[gdal] 05/29: Imported Upstream version 2.0.0~beta1+dfsg

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Sun Jun 14 20:19:39 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch experimental-2.0
in repository gdal.

commit 365d9db531e591cc1a8a242327efa274451aab62
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Sat Jun 13 21:22:09 2015 +0200

    Imported Upstream version 2.0.0~beta1+dfsg
---
 .gitignore                                         |     1 +
 COMMITERS                                          |    11 +-
 Doxyfile                                           |     5 +
 GDALmake.opt.in                                    |    30 +-
 GNUmakefile                                        |    14 +-
 HOWTO-RELEASE                                      |   142 +-
 MIGRATION_GUIDE.TXT                                |   217 +-
 NEWS                                               |  1012 +-
 PROVENANCE.TXT                                     |     4 +-
 VERSION                                            |     2 +-
 Vagrantfile                                        |    24 +-
 alg/GNUmakefile                                    |    13 +-
 alg/gdal_alg.h                                     |    16 +-
 alg/gdal_alg_priv.h                                |    42 +-
 alg/gdal_crs.c                                     |    67 +-
 alg/gdal_rpc.cpp                                   |    82 +-
 alg/gdal_simplesurf.cpp                            |     6 +-
 alg/gdal_tps.cpp                                   |    52 +-
 alg/gdalcutline.cpp                                |    50 +-
 alg/gdaldither.cpp                                 |   415 +-
 alg/gdalgeoloc.cpp                                 |    68 +-
 alg/gdalgrid.cpp                                   |   231 +-
 alg/gdalgrid_priv.h                                |    17 +-
 alg/gdalgridavx.cpp                                |    20 +-
 alg/gdalgridsse.cpp                                |   241 +
 alg/gdalmediancut.cpp                              |   791 +-
 alg/gdalproximity.cpp                              |    51 +-
 alg/gdalrasterize.cpp                              |    14 +-
 alg/gdalrasterpolygonenumerator.cpp                |    16 +-
 alg/gdalsievefilter.cpp                            |     8 +-
 alg/gdaltransformer.cpp                            |   703 +-
 alg/gdaltransformgeolocs.cpp                       |    22 +-
 alg/gdalwarper.cpp                                 |   178 +-
 alg/gdalwarper.h                                   |    70 +-
 alg/gdalwarpkernel.cpp                             |  3315 ++--
 alg/gdalwarpkernel_opencl.c                        |     4 +-
 alg/gdalwarpoperation.cpp                          |   346 +-
 alg/llrasterize.cpp                                |    13 +-
 alg/makefile.vc                                    |     2 +-
 alg/polygonize.cpp                                 |    28 +-
 alg/rasterfill.cpp                                 |    92 +-
 alg/thinplatespline.cpp                            |    28 +-
 apps/GNUmakefile                                   |    27 +-
 apps/commonutils.cpp                               |    48 +-
 apps/gdal_contour.cpp                              |    12 +-
 apps/gdal_grid.cpp                                 |    97 +-
 apps/gdal_rasterize.cpp                            |    55 +-
 apps/gdal_translate.cpp                            |   336 +-
 apps/gdal_utilities.dox                            |   126 +-
 apps/gdaladdo.cpp                                  |    30 +-
 apps/gdalasyncread.cpp                             |    12 +-
 apps/gdalbuildvrt.cpp                              |    96 +-
 apps/gdaldem.cpp                                   |    64 +-
 apps/gdalenhance.cpp                               |    30 +-
 apps/gdalflattenmask.c                             |     2 +-
 apps/gdalinfo.c                                    |   345 +-
 apps/gdallocationinfo.cpp                          |    21 +-
 apps/gdalserver.c                                  |     4 +-
 apps/gdalsrsinfo.cpp                               |   112 +-
 apps/gdaltindex.c                                  |     6 +-
 apps/gdaltransform.cpp                             |    29 +-
 apps/gdalwarp.cpp                                  |   437 +-
 apps/gdalwarpsimple.c                              |    18 +-
 apps/multireadtest.cpp                             |     6 +-
 apps/nearblack.cpp                                 |    12 +-
 apps/ogr2ogr.cpp                                   |  1321 +-
 apps/ogr_utilities.dox                             |    84 +-
 apps/ogrdissolve.cpp                               |    70 +-
 apps/ogrinfo.cpp                                   |   281 +-
 apps/ogrlineref.cpp                                |   246 +-
 apps/ogrtindex.cpp                                 |    44 +-
 apps/test_ogrsf.cpp                                |  1435 +-
 apps/testepsg.cpp                                  |    14 +-
 apps/testreprojmulti.cpp                           |     6 +-
 bridge/gdalbridge.cpp                              |     6 +-
 configure                                          |   565 +-
 configure.in                                       |   252 +-
 data/GDALLogoBW.svg                                |     4 +-
 data/GDALLogoColor.svg                             |     4 +-
 data/GDALLogoGS.svg                                |     4 +-
 data/compdcs.csv                                   |    24 +-
 data/coordinate_axis.csv                           |     1 +
 data/datum_shift.csv                               |  1548 +-
 data/ellipsoid.csv                                 |     8 +-
 data/gcs.csv                                       |    30 +-
 data/gdal_datum.csv                                |   203 +-
 data/gdalvrt.xsd                                   |   362 +
 data/geoccs.csv                                    |     9 +-
 data/gml_registry.xml                              |    13 +-
 data/nitf_spec.xml                                 |     2 +-
 data/ogrvrt.xsd                                    |    75 +-
 data/osmconf.ini                                   |    11 +
 data/pcs.csv                                       |   511 +-
 data/prime_meridian.csv                            |     8 +-
 data/projop_wparm.csv                              |    67 +-
 data/ruian_vf_ob_v1.gfs                            |   177 +-
 data/ruian_vf_st_uvoh_v1.gfs                       |    10 +-
 data/ruian_vf_st_v1.gfs                            |   150 +-
 data/ruian_vf_v1.gfs                               |   257 +-
 data/unit_of_measure.csv                           |    22 +-
 data/vertcs.csv                                    |    17 +-
 doc/credits.dox                                    |   149 +-
 doc/gdal_datamodel.dox                             |    22 +-
 doc/gdal_drivertut.dox                             |   111 +-
 doc/images/foss4g2014.png                          |   Bin 0 -> 10682 bytes
 doc/index.dox                                      |    81 +-
 frmts/aaigrid/GNUmakefile                          |     2 +-
 frmts/aaigrid/aaigriddataset.cpp                   |    40 +-
 frmts/adrg/GNUmakefile                             |     2 +-
 frmts/adrg/adrgdataset.cpp                         |    18 +-
 frmts/adrg/srpdataset.cpp                          |     5 +-
 frmts/aigrid/GNUmakefile                           |     2 +-
 frmts/aigrid/aigccitt.c                            |    15 +-
 frmts/aigrid/aigdataset.cpp                        |     5 +-
 frmts/aigrid/aitest.c                              |    10 +-
 frmts/airsar/GNUmakefile                           |     2 +-
 frmts/airsar/airsardataset.cpp                     |    38 +-
 frmts/arg/GNUmakefile                              |     2 +-
 frmts/arg/argdataset.cpp                           |    11 +-
 frmts/blx/GNUmakefile                              |     2 +-
 frmts/blx/blx.c                                    |     6 +-
 frmts/blx/blxdataset.cpp                           |     9 +-
 frmts/bmp/GNUmakefile                              |     2 +-
 frmts/bmp/bmpdataset.cpp                           |    30 +-
 frmts/bpg/bpgdataset.cpp                           |   361 +
 frmts/bsb/GNUmakefile                              |     2 +-
 frmts/bsb/bsb_read.c                               |    18 +-
 frmts/bsb/bsbdataset.cpp                           |    27 +-
 frmts/ceos/GNUmakefile                             |     2 +-
 frmts/ceos/ceosdataset.cpp                         |    11 +-
 frmts/ceos/ceosopen.c                              |     5 +-
 frmts/ceos2/GNUmakefile                            |     2 +-
 frmts/ceos2/ceosrecipe.c                           |     4 +-
 frmts/ceos2/ceossar.c                              |    20 +-
 frmts/ceos2/sar_ceosdataset.cpp                    |    25 +-
 frmts/coasp/GNUmakefile                            |     2 +-
 frmts/coasp/coasp_dataset.cpp                      |    22 +-
 frmts/cosar/GNUmakefile                            |     2 +-
 frmts/cosar/cosar_dataset.cpp                      |    51 +-
 frmts/ctg/GNUmakefile                              |     2 +-
 frmts/ctg/ctgdataset.cpp                           |    15 +-
 frmts/dds/GNUmakefile                              |     2 +-
 frmts/dds/ddsdataset.cpp                           |    14 +-
 frmts/dimap/GNUmakefile                            |     2 +-
 frmts/dimap/dimapdataset.cpp                       |    32 +-
 frmts/dods/GNUmakefile                             |     2 +-
 frmts/dods/dodsdataset2.cpp                        |    29 +-
 frmts/dted/GNUmakefile                             |     2 +-
 frmts/dted/dted_api.c                              |    45 +-
 frmts/dted/dted_api.h                              |     8 +-
 frmts/dted/dted_create.c                           |     6 +-
 frmts/dted/dted_ptstream.c                         |    13 +-
 frmts/dted/dteddataset.cpp                         |   103 +-
 frmts/e00grid/GNUmakefile                          |     2 +-
 frmts/e00grid/e00griddataset.cpp                   |    36 +-
 frmts/ecw/GNUmakefile                              |     2 +-
 frmts/ecw/ecwcreatecopy.cpp                        |    99 +-
 frmts/ecw/ecwdataset.cpp                           |   371 +-
 frmts/ecw/frmt_ecw.html                            |   188 +-
 frmts/ecw/frmt_jp2ecw.html                         |   180 +-
 frmts/ecw/gdal_ecw.h                               |    35 +-
 frmts/ecw/jp2userbox.cpp                           |     4 +-
 frmts/ecw/lookup.py                                |    25 +-
 frmts/elas/GNUmakefile                             |     2 +-
 frmts/elas/elasdataset.cpp                         |    17 +-
 frmts/envisat/EnvisatFile.c                        |   112 +-
 frmts/envisat/GNUmakefile                          |     2 +-
 frmts/envisat/envisatdataset.cpp                   |     9 +-
 frmts/envisat/records.c                            |    13 +-
 frmts/epsilon/GNUmakefile                          |     2 +-
 frmts/epsilon/epsilondataset.cpp                   |    14 +-
 frmts/ers/GNUmakefile                              |     2 +-
 frmts/ers/ersdataset.cpp                           |    44 +-
 frmts/fit/GNUmakefile                              |     2 +-
 frmts/fit/fitdataset.cpp                           |    13 +-
 frmts/fits/GNUmakefile                             |     2 +-
 frmts/fits/fitsdataset.cpp                         |    11 +-
 frmts/formats_list.html                            |    54 +-
 frmts/frmt_various.html                            |    44 +-
 frmts/gdalallregister.cpp                          |    46 +-
 frmts/georaster/GNUmakefile                        |     2 +-
 frmts/georaster/frmt_georaster.html                |     4 +-
 frmts/georaster/georaster_dataset.cpp              |   286 +-
 frmts/georaster/georaster_priv.h                   |     8 +-
 frmts/georaster/georaster_wrapper.cpp              |     4 +-
 frmts/gff/GNUmakefile                              |     2 +-
 frmts/gff/gff_dataset.cpp                          |    10 +-
 frmts/gif/GNUmakefile                              |     2 +-
 frmts/gif/biggifdataset.cpp                        |   168 +-
 frmts/gif/gifabstractdataset.cpp                   |   189 +-
 frmts/gif/gifabstractdataset.h                     |    35 +-
 frmts/gif/gifdataset.cpp                           |   232 +-
 frmts/grass/GNUmakefile                            |     2 +-
 frmts/grass/grass57dataset.cpp                     |    18 +-
 frmts/grass/grassdataset.cpp                       |     5 +-
 frmts/grass/pkg/Makefile.in                        |    19 +-
 frmts/grass/pkg/README                             |     8 +-
 frmts/grass/pkg/configure                          |  4688 ++---
 frmts/grass/pkg/configure.in                       |    49 +-
 frmts/grib/GNUmakefile                             |    18 +-
 frmts/grib/degrib18/degrib/degrib1.cpp             |    10 +-
 frmts/grib/degrib18/degrib/degrib2.cpp             |     5 +-
 frmts/grib/degrib18/degrib/grib2api.c              |     2 +-
 frmts/grib/degrib18/degrib/inventory.cpp           |     9 +-
 frmts/grib/degrib18/degrib/metaname.cpp            |    46 +-
 frmts/grib/degrib18/degrib/metaparse.cpp           |     5 +-
 frmts/grib/degrib18/degrib/myutil.c                |     4 +-
 frmts/grib/degrib18/degrib/tdlpack.cpp             |    33 +-
 frmts/grib/degrib18/g2clib-1.0.4/dec_jpeg2000.cpp  |     2 +-
 frmts/grib/degrib18/g2clib-1.0.4/enc_jpeg2000.c    |     9 +-
 frmts/grib/degrib18/g2clib-1.0.4/reduce.c          |     4 +-
 frmts/grib/degrib18/g2clib-1.0.4/simpack.c         |     2 +-
 frmts/grib/frmt_grib.html                          |     2 +-
 frmts/grib/gribdataset.cpp                         |    26 +-
 frmts/gsg/GNUmakefile                              |     2 +-
 frmts/gsg/gs7bgdataset.cpp                         |    16 +-
 frmts/gsg/gsagdataset.cpp                          |    12 +-
 frmts/gsg/gsbgdataset.cpp                          |    17 +-
 frmts/gta/GNUmakefile                              |     2 +-
 frmts/gta/gtadataset.cpp                           |     9 +-
 frmts/gtiff/GNUmakefile                            |     4 +-
 frmts/gtiff/frmt_gtiff.html                        |   108 +-
 frmts/gtiff/geotiff.cpp                            |  4142 +++-
 frmts/gtiff/gt_citation.cpp                        |    18 +-
 frmts/gtiff/gt_jpeg_copy.cpp                       |    31 +-
 frmts/gtiff/gt_overview.cpp                        |    30 +-
 frmts/gtiff/gt_wkt_srs.cpp                         |   300 +-
 frmts/gtiff/gt_wkt_srs_for_gdal.h                  |     6 +-
 frmts/gtiff/gt_wkt_srs_priv.h                      |    50 +
 frmts/gtiff/gtiff.h                                |     5 +-
 .../libgeotiff/gdal_libgeotiff_symbol_rename.h     |     2 +
 frmts/gtiff/libgeotiff/geo_config.h                |     5 +
 frmts/gtiff/libgeotiff/geo_names.c                 |     5 +-
 frmts/gtiff/libgeotiff/geo_new.c                   |     3 +-
 frmts/gtiff/libgeotiff/geo_normalize.c             |   476 +-
 frmts/gtiff/libgeotiff/geo_normalize.h             |     9 +-
 frmts/gtiff/libgeotiff/geo_print.c                 |     8 +-
 frmts/gtiff/libgeotiff/geo_set.c                   |     5 +-
 frmts/gtiff/libgeotiff/geo_write.c                 |     2 +-
 frmts/gtiff/libgeotiff/geotiff.h                   |     4 +-
 frmts/gtiff/libgeotiff/geotiff_proj4.c             |    40 +-
 frmts/gtiff/libtiff/GNUmakefile                    |     6 +
 frmts/gtiff/libtiff/tif_jpeg.c                     |    95 +-
 frmts/gtiff/libtiff/tif_vsi.c                      |     2 +-
 frmts/gtiff/libtiff/tiffvers.h                     |     4 +-
 frmts/gtiff/makefile.vc                            |     2 +-
 frmts/gtiff/tifvsi.cpp                             |   200 +-
 frmts/gtiff/tifvsi.h                               |     6 +-
 frmts/gxf/GNUmakefile                              |     2 +-
 frmts/gxf/gxf_ogcwkt.c                             |    15 +-
 frmts/gxf/gxf_proj4.c                              |     8 +-
 frmts/gxf/gxfdataset.cpp                           |    19 +-
 frmts/hdf4/GNUmakefile                             |     2 +-
 frmts/hdf4/hdf-eos/GDapi.c                         |    23 +-
 frmts/hdf4/hdf-eos/GNUmakefile                     |     4 +-
 frmts/hdf4/hdf-eos/SWapi.c                         |    10 +-
 frmts/hdf4/hdf-eos/makefile.vc                     |     4 +
 frmts/hdf4/hdf4dataset.cpp                         |    68 +-
 frmts/hdf4/hdf4dataset.h                           |     5 +-
 frmts/hdf4/hdf4imagedataset.cpp                    |    34 +-
 frmts/hdf4/makefile.vc                             |     6 +-
 frmts/hdf5/GNUmakefile                             |     2 +-
 frmts/hdf5/bagdataset.cpp                          |    15 +-
 frmts/hdf5/hdf5dataset.cpp                         |    30 +-
 frmts/hdf5/hdf5imagedataset.cpp                    |     5 +-
 frmts/hf2/GNUmakefile                              |     2 +-
 frmts/hf2/hf2dataset.cpp                           |    17 +-
 frmts/hfa/GNUmakefile                              |     4 +-
 frmts/hfa/frmt_hfa.html                            |    11 +-
 frmts/hfa/hfa_p.h                                  |    14 +-
 frmts/hfa/hfaband.cpp                              |   101 +-
 frmts/hfa/hfadataset.cpp                           |    91 +-
 frmts/hfa/hfaentry.cpp                             |   112 +-
 frmts/hfa/hfafield.cpp                             |     8 +-
 frmts/hfa/hfaopen.cpp                              |    42 +-
 frmts/hfa/hfatype.cpp                              |     9 +-
 frmts/idrisi/GNUmakefile                           |     2 +-
 frmts/idrisi/IdrisiDataset.cpp                     |    51 +-
 frmts/ilwis/GNUmakefile                            |     2 -
 frmts/ilwis/ilwiscoordinatesystem.cpp              |     2 +-
 frmts/ilwis/ilwisdataset.cpp                       |    39 +-
 frmts/ingr/GNUmakefile                             |     2 +-
 frmts/ingr/IngrTypes.cpp                           |     6 +-
 frmts/ingr/IngrTypes.h                             |     4 +-
 frmts/ingr/IntergraphBand.cpp                      |     4 +-
 frmts/ingr/IntergraphDataset.cpp                   |     7 +-
 frmts/ingr/JpegHelper.cpp                          |     6 +-
 frmts/ingr/makefile.vc                             |     2 +-
 frmts/iris/GNUmakefile                             |     2 +-
 frmts/iris/irisdataset.cpp                         |    23 +-
 frmts/iso8211/8211createfromxml.cpp                |     6 +-
 frmts/iso8211/ddffielddefn.cpp                     |     7 +-
 frmts/iso8211/ddfsubfielddefn.cpp                  |     9 +-
 frmts/jaxapalsar/GNUmakefile                       |     2 +-
 frmts/jaxapalsar/jaxapalsardataset.cpp             |    10 +-
 frmts/jdem/GNUmakefile                             |     2 +-
 frmts/jdem/jdemdataset.cpp                         |    32 +-
 frmts/jp2kak/GNUmakefile                           |     2 +-
 frmts/jp2kak/frmt_jp2kak.html                      |    38 +-
 frmts/jp2kak/jp2kak.lst                            |     6 +
 frmts/jp2kak/jp2kakdataset.cpp                     |   218 +-
 frmts/jp2kak/subfile_source.h                      |     7 +-
 frmts/jpeg/GNUmakefile                             |     2 +-
 frmts/jpeg/frmt_jpeg.html                          |    23 +-
 frmts/jpeg/jpgdataset.cpp                          |   959 +-
 frmts/jpeg/jpgdataset_12.cpp                       |     9 +-
 frmts/jpeg/makefile.vc                             |     4 +-
 frmts/jpeg/vsidataio.cpp                           |     4 +-
 frmts/jpeg2000/GNUmakefile                         |     2 +-
 frmts/jpeg2000/frmt_jpeg2000.html                  |    39 +-
 frmts/jpeg2000/jpeg2000dataset.cpp                 |   231 +-
 frmts/jpegls/GNUmakefile                           |     2 +-
 frmts/jpegls/jpeglsdataset.cpp                     |    11 +-
 frmts/jpipkak/GNUmakefile                          |     2 +-
 frmts/jpipkak/jpipkakdataset.cpp                   |    22 +-
 frmts/jpipkak/jpipkakdataset.h                     |    16 +-
 frmts/kea/GNUmakefile                              |    15 +
 frmts/kea/frmt_kea.html                            |    63 +
 frmts/kea/keaband.cpp                              |   971 +
 frmts/kea/keaband.h                                |   116 +
 frmts/kea/keacopy.cpp                              |   489 +
 frmts/kea/keacopy.h                                |    38 +
 frmts/kea/keadataset.cpp                           |   867 +
 frmts/kea/keadataset.h                             |   112 +
 frmts/kea/keadriver.cpp                            |    93 +
 frmts/kea/keamaskband.cpp                          |   143 +
 frmts/kea/keamaskband.h                            |    53 +
 frmts/kea/keaoverview.cpp                          |   131 +
 frmts/kea/keaoverview.h                            |    61 +
 frmts/kea/kearat.cpp                               |   940 +
 frmts/kea/kearat.h                                 |    84 +
 frmts/kea/makefile.vc                              |    26 +
 frmts/kmlsuperoverlay/GNUmakefile                  |     2 +-
 frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp   |    89 +-
 frmts/kmlsuperoverlay/kmlsuperoverlaydataset.h     |     7 +-
 frmts/l1b/GNUmakefile                              |     2 +-
 frmts/l1b/frmt_l1b.html                            |     9 +
 frmts/l1b/l1bdataset.cpp                           |   450 +-
 frmts/leveller/GNUmakefile                         |     2 +-
 frmts/leveller/levellerdataset.cpp                 |    32 +-
 frmts/makefile.vc                                  |    20 +-
 frmts/map/GNUmakefile                              |     2 +-
 frmts/map/frmt_map.html                            |     2 +-
 frmts/map/mapdataset.cpp                           |     3 +-
 frmts/mbtiles/GNUmakefile                          |     2 +-
 frmts/mbtiles/mbtilesdataset.cpp                   |    73 +-
 frmts/mem/GNUmakefile                              |     2 +-
 frmts/mem/frmt_mem.html                            |     2 +-
 frmts/mem/memdataset.cpp                           |   232 +-
 frmts/mem/memdataset.h                             |    36 +-
 frmts/mrsid/GNUmakefile                            |     2 +-
 frmts/mrsid/mrsiddataset.cpp                       |    56 +-
 frmts/mrsid_lidar/GNUmakefile                      |     2 +-
 frmts/mrsid_lidar/gdal_MG4Lidar.cpp                |    21 +-
 frmts/msg/GNUmakefile                              |     2 +-
 frmts/msg/msgcommand.cpp                           |     2 +-
 frmts/msg/msgdataset.cpp                           |     9 +-
 frmts/msgn/GNUmakefile                             |     2 +-
 frmts/msgn/msg_basic_types.cpp                     |    27 +-
 frmts/msgn/msgndataset.cpp                         |    17 +-
 frmts/netcdf/GNUmakefile                           |     2 +-
 frmts/netcdf/frmt_netcdf.html                      |     1 +
 frmts/netcdf/gmtdataset.cpp                        |    17 +-
 frmts/netcdf/netcdfdataset.cpp                     |   120 +-
 frmts/ngsgeoid/GNUmakefile                         |     2 +-
 frmts/ngsgeoid/ngsgeoiddataset.cpp                 |    11 +-
 frmts/nitf/GNUmakefile                             |     2 +-
 frmts/nitf/ecrgtocdataset.cpp                      |     5 +-
 frmts/nitf/frmt_nitf.html                          |     4 +-
 frmts/nitf/makefile.vc                             |     2 +-
 frmts/nitf/nitfaridpcm.cpp                         |    16 +-
 frmts/nitf/nitfbilevel.cpp                         |    16 +-
 frmts/nitf/nitfdataset.cpp                         |   181 +-
 frmts/nitf/nitfdataset.h                           |    20 +-
 frmts/nitf/nitfdes.c                               |    10 +-
 frmts/nitf/nitffile.c                              |    64 +-
 frmts/nitf/nitfimage.c                             |   182 +-
 frmts/nitf/nitflib.h                               |     3 +-
 frmts/nitf/nitfrasterband.cpp                      |    12 +-
 frmts/nitf/nitfwritejpeg.cpp                       |     4 +-
 frmts/nitf/rpftocdataset.cpp                       |     3 +-
 frmts/northwood/GNUmakefile                        |     2 +-
 frmts/northwood/grcdataset.cpp                     |    64 +-
 frmts/northwood/grddataset.cpp                     |    58 +-
 frmts/northwood/northwood.cpp                      |     2 +-
 frmts/ogdi/GNUmakefile                             |     2 +-
 frmts/ogdi/ogdidataset.cpp                         |    56 +-
 frmts/openjpeg/GNUmakefile                         |     7 +-
 frmts/openjpeg/eoptemplate_pleiades.xml            |    46 +
 frmts/openjpeg/eoptemplate_worldviewgeoeye.xml     |    46 +
 frmts/openjpeg/frmt_jp2openjpeg.html               |   407 +-
 frmts/openjpeg/makefile.vc                         |     2 +-
 frmts/openjpeg/openjpegdataset.cpp                 |  2700 ++-
 frmts/ozi/GNUmakefile                              |     2 +-
 frmts/ozi/ozidataset.cpp                           |    11 +-
 frmts/pcidsk/GNUmakefile                           |     8 +-
 frmts/pcidsk/frmt_pcidsk.html                      |     2 +-
 frmts/pcidsk/gdal_edb.cpp                          |     8 +-
 frmts/pcidsk/makefile.vc                           |     4 +-
 frmts/pcidsk/ogrpcidsklayer.cpp                    |   834 +
 frmts/pcidsk/pcidskdataset.cpp                     |    20 +-
 frmts/pcidsk/pcidskdataset2.cpp                    |   339 +-
 frmts/pcidsk/pcidskdataset2.h                      |   202 +
 .../pcidsk/sdk/channel/cbandinterleavedchannel.cpp |     5 +-
 frmts/pcidsk/sdk/channel/cexternalchannel.cpp      |     4 +-
 frmts/pcidsk/sdk/channel/cpcidskchannel.cpp        |    17 +-
 .../sdk/channel/cpixelinterleavedchannel.cpp       |     3 +-
 frmts/pcidsk/sdk/channel/ctiledchannel.cpp         |     3 +-
 frmts/pcidsk/sdk/core/metadataset_p.cpp            |    14 +-
 frmts/pcidsk/sdk/core/pcidsk_utils.cpp             |     4 +-
 frmts/pcidsk/sdk/core/pcidskbuffer.cpp             |    10 +-
 frmts/pcidsk/sdk/pcidsk_config.h                   |    13 +
 frmts/pcidsk/sdk/segment/cpcidsk_array.cpp         |     4 +-
 frmts/pcidsk/sdk/segment/cpcidskgeoref.cpp         |     2 +-
 frmts/pcidsk/sdk/segment/metadatasegment.h         |     9 +-
 frmts/pcidsk/sdk/segment/metadatasegment_p.cpp     |    14 +-
 frmts/pcidsk/vsi_pcidsk_io.cpp                     |     6 +-
 frmts/pcraster/GNUmakefile                         |     2 +-
 frmts/pcraster/libcsf/AUTHORS                      |    11 +-
 frmts/pcraster/libcsf/COPYING                      |     2 +-
 frmts/pcraster/libcsf/README                       |    14 +-
 frmts/pcraster/libcsf/_getcell.c                   |     3 -
 frmts/pcraster/libcsf/_getrow.c                    |     3 -
 frmts/pcraster/libcsf/_gsomece.c                   |     3 -
 frmts/pcraster/libcsf/_putcell.c                   |     3 -
 frmts/pcraster/libcsf/_rputrow.c                   |     3 -
 frmts/pcraster/libcsf/angle.c                      |    10 -
 frmts/pcraster/libcsf/attravai.c                   |     3 -
 frmts/pcraster/libcsf/attrsize.c                   |     3 -
 frmts/pcraster/libcsf/cellsize.c                   |    37 -
 frmts/pcraster/libcsf/csfglob.c                    |     5 -
 frmts/pcraster/libcsf/csfimpl.h                    |    30 +-
 frmts/pcraster/libcsf/csfsup.c                     |    30 -
 frmts/pcraster/libcsf/csftypes.h                   |    58 +-
 frmts/pcraster/libcsf/delattr.c                    |    37 +-
 frmts/pcraster/libcsf/dumconv.c                    |    45 +-
 frmts/pcraster/libcsf/filename.c                   |    30 -
 frmts/pcraster/libcsf/gattrblk.c                   |    42 +-
 frmts/pcraster/libcsf/gattridx.c                   |    31 -
 frmts/pcraster/libcsf/gdattype.c                   |    34 -
 frmts/pcraster/libcsf/getattr.c                    |    34 -
 frmts/pcraster/libcsf/getx0.c                      |    31 -
 frmts/pcraster/libcsf/gety0.c                      |    30 -
 frmts/pcraster/libcsf/ggisfid.c                    |    34 -
 frmts/pcraster/libcsf/gnrcols.c                    |    30 -
 frmts/pcraster/libcsf/gnrrows.c                    |    30 -
 frmts/pcraster/libcsf/gproj.c                      |    30 -
 frmts/pcraster/libcsf/gputproj.c                   |    30 -
 frmts/pcraster/libcsf/gvalscal.c                   |    31 -
 frmts/pcraster/libcsf/gvartype.c                   |    30 -
 frmts/pcraster/libcsf/gversion.c                   |    30 -
 frmts/pcraster/libcsf/ismv.c                       |    39 -
 frmts/pcraster/libcsf/kernlcsf.c                   |    15 -
 frmts/pcraster/libcsf/legend.c                     |     6 +-
 frmts/pcraster/libcsf/mclose.c                     |     7 -
 frmts/pcraster/libcsf/mopen.c                      |    11 +-
 frmts/pcraster/libcsf/moreattr.c                   |     4 -
 frmts/pcraster/libcsf/mperror.c                    |     3 -
 frmts/pcraster/libcsf/pcrtypes.h                   |    73 +-
 frmts/pcraster/libcsf/pgisfid.c                    |    30 -
 frmts/pcraster/libcsf/pmaxval.c                    |    37 -
 frmts/pcraster/libcsf/pminval.c                    |    37 -
 frmts/pcraster/libcsf/putattr.c                    |    33 +-
 frmts/pcraster/libcsf/putsomec.c                   |     3 -
 frmts/pcraster/libcsf/putx0.c                      |    30 -
 frmts/pcraster/libcsf/puty0.c                      |    30 -
 frmts/pcraster/libcsf/pvalscal.c                   |    33 -
 frmts/pcraster/libcsf/rattrblk.c                   |    39 +-
 frmts/pcraster/libcsf/rcomp.c                      |    11 -
 frmts/pcraster/libcsf/rcoords.c                    |     3 -
 frmts/pcraster/libcsf/rdup2.c                      |     4 -
 frmts/pcraster/libcsf/reseterr.c                   |    30 -
 frmts/pcraster/libcsf/rextend.c                    |     3 -
 frmts/pcraster/libcsf/rmalloc.c                    |     3 -
 frmts/pcraster/libcsf/rrowcol.c                    |     3 -
 frmts/pcraster/libcsf/ruseas.c                     |   170 +-
 frmts/pcraster/libcsf/setangle.c                   |    36 -
 frmts/pcraster/libcsf/setmv.c                      |    31 -
 frmts/pcraster/libcsf/setvtmv.c                    |    27 -
 frmts/pcraster/libcsf/strconst.c                   |     9 -
 frmts/pcraster/libcsf/strpad.c                     |     5 -
 frmts/pcraster/libcsf/swapio.c                     |    10 +-
 frmts/pcraster/libcsf/trackmm.c                    |    37 -
 frmts/pcraster/libcsf/vs2.c                        |     7 -
 frmts/pcraster/libcsf/vsdef.c                      |    40 -
 frmts/pcraster/libcsf/vsis.c                       |    11 -
 frmts/pcraster/libcsf/vsvers.c                     |    10 -
 frmts/pcraster/libcsf/wattrblk.c                   |    45 +-
 frmts/pcraster/pcrasterdataset.cpp                 |   189 +-
 frmts/pcraster/pcrasterdataset.h                   |    24 +-
 frmts/pcraster/pcrastermisc.cpp                    |    38 +-
 frmts/pcraster/pcrasterrasterband.cpp              |   138 +-
 frmts/pcraster/pcrasterrasterband.h                |    32 +-
 frmts/pcraster/pcrasterutil.cpp                    |    31 +-
 frmts/pcraster/pcrasterutil.h                      |    42 +-
 frmts/pdf/GNUmakefile                              |     9 +-
 frmts/pdf/frmt_pdf.html                            |    61 +-
 frmts/pdf/gdal_pdf.h                               |   372 +
 frmts/pdf/makefile.vc                              |    19 +-
 frmts/pdf/ogrpdflayer.cpp                          |   209 +
 frmts/pdf/pdfcreatecopy.cpp                        |    24 +-
 frmts/pdf/pdfdataset.cpp                           |   552 +-
 frmts/pdf/pdfdataset.h                             |    37 -
 frmts/pdf/pdfio.cpp                                |    88 +-
 frmts/pdf/pdfio.h                                  |     6 +-
 frmts/pdf/pdfobject.cpp                            |    12 +-
 frmts/pdf/pdfobject.h                              |     2 +-
 frmts/pdf/pdfreadvectors.cpp                       |  1666 ++
 frmts/pdf/pdfwritabledataset.cpp                   |   334 +
 frmts/pds/GNUmakefile                              |     6 +-
 frmts/pds/isis2dataset.cpp                         |    36 +-
 frmts/pds/isis3dataset.cpp                         |    23 +-
 frmts/pds/makefile.vc                              |     2 +-
 frmts/pds/pdsdataset.cpp                           |   242 +-
 frmts/pds/vicardataset.cpp                         |   835 +
 frmts/pds/vicarkeywordhandler.cpp                  |   355 +
 frmts/pds/vicarkeywordhandler.h                    |    53 +
 frmts/pgchip/GNUmakefile                           |     2 +-
 frmts/pgchip/pgchipdataset.cpp                     |     1 +
 frmts/plmosaic/GNUmakefile                         |    13 +
 frmts/plmosaic/frmt_plmosaic.html                  |   241 +
 frmts/plmosaic/makefile.vc                         |    16 +
 frmts/plmosaic/plmosaicdataset.cpp                 |  1511 ++
 frmts/png/GNUmakefile                              |     4 +-
 frmts/png/libpng/README                            |     2 +-
 frmts/png/libpng/png.c                             |    30 +-
 frmts/png/libpng/png.h                             |    38 +-
 frmts/png/libpng/pngconf.h                         |    18 +-
 frmts/png/libpng/pngerror.c                        |    10 +-
 frmts/png/libpng/pngget.c                          |     8 +-
 frmts/png/libpng/pngread.c                         |    38 +-
 frmts/png/libpng/pngrtran.c                        |    10 +-
 frmts/png/libpng/pngrutil.c                        |    10 +-
 frmts/png/libpng/pngset.c                          |    35 +-
 frmts/png/libpng/pngwrite.c                        |    29 +-
 frmts/png/pngdataset.cpp                           |   246 +-
 frmts/postgisraster/GNUmakefile                    |     2 +-
 frmts/postgisraster/postgisraster.h                |     6 +-
 frmts/postgisraster/postgisrasterdataset.cpp       |    15 +-
 frmts/postgisraster/postgisrasterrasterband.cpp    |    11 +-
 .../postgisraster/postgisrastertilerasterband.cpp  |     1 -
 frmts/r/GNUmakefile                                |     2 +-
 frmts/r/rcreatecopy.cpp                            |    23 +-
 frmts/r/rdataset.cpp                               |    11 +-
 frmts/rasdaman/GNUmakefile                         |     2 +-
 frmts/rasdaman/rasdamandataset.cpp                 |    19 +-
 frmts/rasterlite/GNUmakefile                       |     2 +-
 frmts/rasterlite/frmt_rasterlite.html              |     6 +-
 frmts/rasterlite/rasterlitecreatecopy.cpp          |    33 +-
 frmts/rasterlite/rasterlitedataset.cpp             |    98 +-
 frmts/rasterlite/rasterlitedataset.h               |    13 +-
 frmts/rasterlite/rasterliteoverviews.cpp           |    49 +-
 frmts/raw/GNUmakefile                              |     4 +-
 frmts/raw/ace2dataset.cpp                          |     5 +-
 frmts/raw/btdataset.cpp                            |    21 +-
 frmts/raw/cpgdataset.cpp                           |    40 +-
 frmts/raw/ctable2dataset.cpp                       |     7 +-
 frmts/raw/dipxdataset.cpp                          |     7 +-
 frmts/raw/doq1dataset.cpp                          |     7 +-
 frmts/raw/doq2dataset.cpp                          |    11 +-
 frmts/raw/ehdrdataset.cpp                          |    32 +-
 frmts/raw/eirdataset.cpp                           |     1 +
 frmts/raw/envidataset.cpp                          |   102 +-
 frmts/raw/fastdataset.cpp                          |     5 +-
 frmts/raw/fujibasdataset.cpp                       |     7 +-
 frmts/raw/genbindataset.cpp                        |    11 +-
 frmts/raw/gscdataset.cpp                           |     5 +-
 frmts/raw/gtxdataset.cpp                           |    10 +-
 frmts/raw/hkvdataset.cpp                           |    61 +-
 frmts/raw/idadataset.cpp                           |    35 +-
 frmts/raw/krodataset.cpp                           |     9 +-
 frmts/raw/landataset.cpp                           |    70 +-
 frmts/raw/lcpdataset.cpp                           |    17 +-
 frmts/raw/loslasdataset.cpp                        |     5 +-
 frmts/raw/makefile.vc                              |     2 +-
 frmts/raw/mffdataset.cpp                           |   112 +-
 frmts/raw/ndfdataset.cpp                           |    19 +-
 frmts/raw/ntv2dataset.cpp                          |    18 +-
 frmts/raw/pauxdataset.cpp                          |    50 +-
 frmts/raw/pnmdataset.cpp                           |     5 +-
 frmts/raw/rawdataset.cpp                           |    65 +-
 frmts/raw/rawdataset.h                             |    10 +-
 frmts/raw/roipacdataset.cpp                        |   868 +
 frmts/raw/snodasdataset.cpp                        |     5 +-
 frmts/rik/GNUmakefile                              |     2 +-
 frmts/rik/rikdataset.cpp                           |   154 +-
 frmts/rmf/GNUmakefile                              |     2 +-
 frmts/rmf/rmfdataset.cpp                           |     5 +-
 frmts/rs2/GNUmakefile                              |     2 +-
 frmts/rs2/rs2dataset.cpp                           |    67 +-
 frmts/saga/GNUmakefile                             |     2 -
 frmts/saga/sagadataset.cpp                         |     7 +-
 frmts/sde/GNUmakefile                              |     2 +-
 frmts/sde/sdedataset.cpp                           |     3 +-
 frmts/sdts/GNUmakefile                             |     2 +-
 frmts/sdts/sdts2shp.cpp                            |     6 +-
 frmts/sdts/sdtsdataset.cpp                         |     7 +-
 frmts/sdts/sdtslinereader.cpp                      |     6 +-
 frmts/sdts/sdtsrasterreader.cpp                    |    12 +-
 frmts/sgi/GNUmakefile                              |     2 +-
 frmts/sgi/sgidataset.cpp                           |    24 +-
 frmts/srtmhgt/GNUmakefile                          |     2 +-
 frmts/srtmhgt/srtmhgtdataset.cpp                   |    18 +-
 frmts/terragen/GNUmakefile                         |     2 +-
 frmts/terragen/terragendataset.cpp                 |    23 +-
 frmts/til/GNUmakefile                              |     2 +-
 frmts/til/tildataset.cpp                           |    90 +-
 frmts/tsx/GNUmakefile                              |     2 +-
 frmts/tsx/tsxdataset.cpp                           |    35 +-
 frmts/usgsdem/GNUmakefile                          |     2 +-
 frmts/usgsdem/usgsdem_create.cpp                   |    43 +-
 frmts/usgsdem/usgsdemdataset.cpp                   |     8 +-
 frmts/vrt/GNUmakefile                              |     2 +-
 frmts/vrt/vrt_tutorial.dox                         |    64 +-
 frmts/vrt/vrtdataset.cpp                           |    61 +-
 frmts/vrt/vrtdataset.h                             |    78 +-
 frmts/vrt/vrtderivedrasterband.cpp                 |    15 +-
 frmts/vrt/vrtdriver.cpp                            |    27 +-
 frmts/vrt/vrtfilters.cpp                           |    18 +-
 frmts/vrt/vrtrasterband.cpp                        |    20 +-
 frmts/vrt/vrtrawrasterband.cpp                     |    13 +-
 frmts/vrt/vrtsourcedrasterband.cpp                 |    57 +-
 frmts/vrt/vrtsources.cpp                           |   378 +-
 frmts/vrt/vrtwarped.cpp                            |   356 +-
 frmts/wcs/GNUmakefile                              |     2 +-
 frmts/wcs/httpdriver.cpp                           |    29 +-
 frmts/wcs/wcsdataset.cpp                           |   130 +-
 frmts/webp/GNUmakefile                             |     2 +-
 frmts/webp/webpdataset.cpp                         |    80 +-
 frmts/wms/GNUmakefile                              |     6 +-
 frmts/wms/frmt_ags_arcgisonline.xml                |    15 +
 frmts/wms/frmt_wms.html                            |    80 +-
 frmts/wms/frmt_wms_openstreetmap_tms.xml           |     2 +-
 frmts/wms/gdalwmscache.cpp                         |     2 +-
 frmts/wms/gdalwmsdataset.cpp                       |    27 +-
 frmts/wms/gdalwmsrasterband.cpp                    |    43 +-
 frmts/wms/makefile.vc                              |     2 +-
 frmts/wms/minidriver.cpp                           |     7 +-
 frmts/wms/minidriver_arcgis_server.cpp             |   263 +
 frmts/wms/minidriver_arcgis_server.h               |    74 +
 frmts/wms/minidriver_tiled_wms.cpp                 |    15 +-
 frmts/wms/minidriver_tileservice.cpp               |     2 +-
 frmts/wms/minidriver_tms.cpp                       |     2 +-
 frmts/wms/minidriver_virtualearth.cpp              |     2 +-
 frmts/wms/minidriver_wms.cpp                       |     3 +-
 frmts/wms/minidriver_worldwind.cpp                 |     2 +-
 frmts/wms/wmsdriver.cpp                            |    48 +-
 frmts/wms/wmsdriver.h                              |    17 +-
 frmts/wms/wmsmetadataset.cpp                       |     8 +-
 frmts/xpm/GNUmakefile                              |     2 +-
 frmts/xpm/xpmdataset.cpp                           |    26 +-
 frmts/xyz/GNUmakefile                              |     2 +-
 frmts/xyz/xyzdataset.cpp                           |   187 +-
 frmts/zlib/deflate.h                               |     4 +-
 frmts/zmap/GNUmakefile                             |     2 +-
 frmts/zmap/zmapdataset.cpp                         |    23 +-
 gcore/GNUmakefile                                  |    19 +-
 gcore/gdal.h                                       |   297 +-
 gcore/gdal_frmts.h                                 |     6 +-
 gcore/gdal_mdreader.cpp                            |  1072 ++
 gcore/gdal_mdreader.h                              |   202 +
 gcore/gdal_misc.cpp                                |   311 +-
 gcore/gdal_pam.h                                   |    16 +-
 gcore/gdal_priv.h                                  |   314 +-
 gcore/gdal_proxy.h                                 |    18 +-
 gcore/gdal_rat.cpp                                 |    24 +-
 gcore/gdal_rpcimdio.cpp                            |   644 -
 gcore/gdal_version.h                               |    10 +-
 gcore/gdalallvalidmaskband.cpp                     |     8 +-
 gcore/gdalclientserver.cpp                         |   115 +-
 gcore/gdalcolortable.cpp                           |    23 +-
 gcore/gdaldataset.cpp                              |  3341 +++-
 gcore/gdaldefaultasync.cpp                         |    11 +-
 gcore/gdaldefaultoverviews.cpp                     |    89 +-
 gcore/gdaldllmain.cpp                              |    74 +-
 gcore/gdaldriver.cpp                               |   503 +-
 gcore/gdaldrivermanager.cpp                        |   172 +-
 gcore/gdalexif.cpp                                 |    12 +-
 gcore/gdalgmlcoverage.cpp                          |    12 +-
 gcore/gdaljp2abstractdataset.cpp                   |   402 +-
 gcore/gdaljp2abstractdataset.h                     |    16 +-
 gcore/gdaljp2box.cpp                               |    99 +-
 gcore/gdaljp2metadata.cpp                          |  1987 +-
 gcore/gdaljp2metadata.h                            |    48 +-
 gcore/gdaljp2metadatagenerator.cpp                 |   915 +
 gcore/gdaljp2metadatagenerator.h                   |    40 +
 gcore/gdaljp2structure.cpp                         |  1425 ++
 gcore/gdalmultidomainmetadata.cpp                  |    11 +-
 gcore/gdalnodatamaskband.cpp                       |    14 +-
 gcore/gdalnodatavaluesmaskband.cpp                 |     9 +-
 gcore/gdalopeninfo.cpp                             |   205 +-
 gcore/gdaloverviewdataset.cpp                      |   570 +
 gcore/gdalpamdataset.cpp                           |    61 +-
 gcore/gdalpamproxydb.cpp                           |     6 +-
 gcore/gdalpamrasterband.cpp                        |    74 +-
 gcore/gdalproxydataset.cpp                         |    24 +-
 gcore/gdalproxypool.cpp                            |    40 +-
 gcore/gdalrasterband.cpp                           |   505 +-
 gcore/gdalrasterblock.cpp                          |   305 +-
 gcore/gdalrescaledalphaband.cpp                    |    17 +-
 gcore/gdalsse_priv.h                               |   571 +
 gcore/gdalvirtualmem.cpp                           |    93 +-
 gcore/jp2dump.cpp                                  |     0
 gcore/makefile.vc                                  |    27 +-
 gcore/mdreader/GNUmakefile                         |    26 +
 gcore/mdreader/makefile.vc                         |    12 +
 gcore/mdreader/reader_digital_globe.cpp            |   280 +
 gcore/mdreader/reader_digital_globe.h              |    74 +
 gcore/mdreader/reader_geo_eye.cpp                  |   363 +
 gcore/mdreader/reader_geo_eye.h                    |    67 +
 gcore/mdreader/reader_landsat.cpp                  |   195 +
 gcore/mdreader/reader_landsat.h                    |    65 +
 gcore/mdreader/reader_orb_view.cpp                 |   161 +
 gcore/mdreader/reader_orb_view.h                   |    63 +
 gcore/mdreader/reader_pleiades.cpp                 |   326 +
 gcore/mdreader/reader_pleiades.h                   |    64 +
 gcore/mdreader/reader_rdk1.cpp                     |   210 +
 gcore/mdreader/reader_rdk1.h                       |    65 +
 gcore/overview.cpp                                 |  1730 +-
 gcore/rasterio.cpp                                 |   935 +-
 m4/acinclude.m4                                    |    12 +-
 makefile.vc                                        |    10 -
 man/man1/gdal-config.1                             |     4 +-
 man/man1/gdal2tiles.1                              |     4 +-
 man/man1/gdal_calc.1                               |     6 +-
 man/man1/gdal_contour.1                            |     4 +-
 man/man1/gdal_edit.1                               |    30 +-
 man/man1/gdal_fillnodata.1                         |     6 +-
 man/man1/gdal_grid.1                               |     4 +-
 man/man1/gdal_merge.1                              |     6 +-
 man/man1/gdal_polygonize.1                         |     6 +-
 man/man1/gdal_proximity.1                          |    12 +-
 man/man1/gdal_rasterize.1                          |    22 +-
 man/man1/gdal_retile.1                             |     4 +-
 man/man1/gdal_sieve.1                              |     6 +-
 man/man1/gdal_translate.1                          |    29 +-
 man/man1/gdal_utilities.1                          |     4 +-
 man/man1/gdaladdo.1                                |    14 +-
 man/man1/gdalbuildvrt.1                            |     8 +-
 man/man1/gdalcompare.1                             |     4 +-
 man/man1/gdaldem.1                                 |     4 +-
 man/man1/gdalinfo.1                                |    10 +-
 man/man1/gdallocationinfo.1                        |     9 +-
 man/man1/gdalmanage.1                              |     4 +-
 man/man1/gdalmove.1                                |     4 +-
 man/man1/gdalsrsinfo.1                             |     4 +-
 man/man1/gdaltindex.1                              |     4 +-
 man/man1/gdaltransform.1                           |     8 +-
 man/man1/gdalwarp.1                                |    40 +-
 man/man1/nearblack.1                               |     4 +-
 man/man1/ogr2ogr.1                                 |    41 +-
 man/man1/ogr_utilities.1                           |     4 +-
 man/man1/ogrinfo.1                                 |    22 +-
 man/man1/ogrlineref.1                              |     6 +-
 man/man1/ogrtindex.1                               |     6 +-
 man/man1/pct2rgb.1                                 |     4 +-
 man/man1/rgb2pct.1                                 |     4 +-
 nmake.opt                                          |    50 +-
 ogr/GNUmakefile                                    |    20 +-
 ogr/file.lst                                       |     9 +-
 ogr/gml2ogrgeometry.cpp                            |  1373 +-
 ogr/makefile.vc                                    |    10 +-
 ogr/ogr2gmlgeometry.cpp                            |   256 +-
 ogr/ogr_api.cpp                                    |   483 +-
 ogr/ogr_api.h                                      |    61 +-
 ogr/ogr_apitut.dox                                 |   434 +-
 ogr/ogr_arch.dox                                   |    94 +-
 ogr/ogr_core.h                                     |   184 +-
 ogr/ogr_drivertut.dox                              |   202 +-
 ogr/ogr_expat.cpp                                  |     4 +-
 ogr/ogr_feature.h                                  |   115 +-
 ogr/ogr_fromepsg.cpp                               |    90 +-
 ogr/ogr_geocoding.cpp                              |     8 +-
 ogr/ogr_geometry.h                                 |   754 +-
 ogr/ogr_geos.h                                     |     6 +-
 ogr/ogr_opt.cpp                                    |    12 +-
 ogr/ogr_p.h                                        |    40 +-
 ogr/ogr_spatialref.h                               |     8 +-
 ogr/ogr_sql.dox                                    |    58 +-
 ogr/ogr_sql_sqlite.dox                             |    11 +-
 ogr/ogr_srs_api.h                                  |    24 +-
 ogr/ogr_srs_erm.cpp                                |    10 +-
 ogr/ogr_srs_esri.cpp                               |   781 +-
 ogr/ogr_srs_esri_names.h                           |     4 +
 ogr/ogr_srs_ozi.cpp                                |    65 +-
 ogr/ogr_srs_pci.cpp                                |    53 +-
 ogr/ogr_srs_proj4.cpp                              |   303 +-
 ogr/ogr_srs_usgs.cpp                               |    12 +-
 ogr/ogr_srs_validate.cpp                           |    15 +-
 ogr/ogr_srs_xml.cpp                                |    33 +-
 ogr/ogr_srsnode.cpp                                |    10 +-
 ogr/ograpispy.cpp                                  |  1085 ++
 ogr/ograpispy.h                                    |   173 +
 ogr/ogrcircularstring.cpp                          |   715 +
 ogr/ogrcompoundcurve.cpp                           |   800 +
 ogr/ogrct.cpp                                      |    39 +-
 ogr/ogrcurve.cpp                                   |   274 +-
 ogr/ogrcurvecollection.cpp                         |   599 +
 ogr/ogrcurvepolygon.cpp                            |   717 +
 ogr/ogrfeature.cpp                                 |  1377 +-
 ogr/ogrfeaturedefn.cpp                             |    60 +-
 ogr/ogrfeaturequery.cpp                            |   140 +-
 ogr/ogrfeaturestyle.cpp                            |    10 +-
 ogr/ogrfielddefn.cpp                               |   537 +-
 ogr/ogrgeomediageometry.cpp                        |     5 +-
 ogr/ogrgeometry.cpp                                |  1179 +-
 ogr/ogrgeometrycollection.cpp                      |   542 +-
 ogr/ogrgeometryfactory.cpp                         |  1629 +-
 ogr/ogrgeomfielddefn.cpp                           |   133 +-
 ogr/ogrlinearring.cpp                              |    92 +-
 ogr/ogrlinestring.cpp                              |   583 +-
 ogr/ogrmulticurve.cpp                              |   178 +
 ogr/ogrmultilinestring.cpp                         |   313 +-
 ogr/ogrmultipoint.cpp                              |   185 +-
 ogr/ogrmultipolygon.cpp                            |   404 +-
 ogr/ogrmultisurface.cpp                            |   284 +
 ogr/ogrpgeogeometry.cpp                            |     6 +-
 ogr/ogrpoint.cpp                                   |   195 +-
 ogr/ogrpolygon.cpp                                 |   749 +-
 ogr/ogrsf_frmts/GNUmakefile                        |    16 +-
 ogr/ogrsf_frmts/aeronavfaa/GNUmakefile             |     2 +-
 ogr/ogrsf_frmts/aeronavfaa/ogr_aeronavfaa.h        |    19 +-
 .../aeronavfaa/ograeronavfaadatasource.cpp         |    13 +-
 ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadriver.cpp |    62 +-
 ogr/ogrsf_frmts/aeronavfaa/ograeronavfaalayer.cpp  |    10 +-
 ogr/ogrsf_frmts/arcgen/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/arcgen/ogr_arcgen.h                |    20 +-
 ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp     |    59 +-
 ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp         |   103 +-
 ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp          |    26 +-
 ogr/ogrsf_frmts/arcobjects/GNUmakefile             |     2 +-
 ogr/ogrsf_frmts/arcobjects/aolayer.cpp             |     4 +-
 ogr/ogrsf_frmts/arcobjects/ogr_ao.h                |    12 +-
 ogr/ogrsf_frmts/avc/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/avc/avc_bin.c                      |     3 +-
 ogr/ogrsf_frmts/avc/avc_binwr.c                    |    14 +-
 ogr/ogrsf_frmts/avc/avc_e00gen.c                   |     4 +-
 ogr/ogrsf_frmts/avc/avc_e00parse.c                 |   101 +-
 ogr/ogrsf_frmts/avc/avc_e00write.c                 |     2 +-
 ogr/ogrsf_frmts/avc/avc_misc.c                     |     2 +-
 ogr/ogrsf_frmts/avc/ogr_avc.h                      |    37 +-
 ogr/ogrsf_frmts/avc/ogravcbindatasource.cpp        |     6 +-
 ogr/ogrsf_frmts/avc/ogravcbindriver.cpp            |    88 +-
 ogr/ogrsf_frmts/avc/ogravcbinlayer.cpp             |    13 +-
 ogr/ogrsf_frmts/avc/ogravce00datasource.cpp        |     6 +-
 ogr/ogrsf_frmts/avc/ogravce00driver.cpp            |    61 +-
 ogr/ogrsf_frmts/avc/ogravce00layer.cpp             |    12 +-
 ogr/ogrsf_frmts/avc/ogravclayer.cpp                |    12 +-
 ogr/ogrsf_frmts/bna/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/bna/ogr_bna.h                      |    26 +-
 ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp           |    30 +-
 ogr/ogrsf_frmts/bna/ogrbnadriver.cpp               |   118 +-
 ogr/ogrsf_frmts/bna/ogrbnalayer.cpp                |    23 +-
 ogr/ogrsf_frmts/bna/ogrbnaparser.cpp               |     2 +-
 ogr/ogrsf_frmts/bna/ogrbnaparser.h                 |     2 +-
 ogr/ogrsf_frmts/cartodb/GNUmakefile                |     2 +-
 ogr/ogrsf_frmts/cartodb/drv_cartodb.html           |    49 +-
 ogr/ogrsf_frmts/cartodb/makefile.vc                |     2 +-
 ogr/ogrsf_frmts/cartodb/ogr_cartodb.h              |   103 +-
 ogr/ogrsf_frmts/cartodb/ogrcartodbdatasource.cpp   |   289 +-
 ogr/ogrsf_frmts/cartodb/ogrcartodbdriver.cpp       |    85 +-
 ogr/ogrsf_frmts/cartodb/ogrcartodblayer.cpp        |    97 +-
 ogr/ogrsf_frmts/cartodb/ogrcartodbresultlayer.cpp  |    36 +-
 ogr/ogrsf_frmts/cartodb/ogrcartodbtablelayer.cpp   |   765 +-
 ogr/ogrsf_frmts/cloudant/GNUmakefile               |    14 +
 ogr/ogrsf_frmts/cloudant/drv_cloudant.html         |   113 +
 ogr/ogrsf_frmts/cloudant/makefile.vc               |    15 +
 ogr/ogrsf_frmts/cloudant/ogr_cloudant.h            |   104 +
 ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp |   388 +
 ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp     |   118 +
 ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp |   547 +
 ogr/ogrsf_frmts/couchdb/GNUmakefile                |     2 +-
 ogr/ogrsf_frmts/couchdb/drv_couchdb.html           |     2 +-
 ogr/ogrsf_frmts/couchdb/ogr_couchdb.h              |    62 +-
 ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp   |    73 +-
 ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp       |    17 +-
 ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp        |    26 +-
 ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp    |     6 +-
 ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp   |    47 +-
 ogr/ogrsf_frmts/csv/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/csv/drv_csv.html                   |    43 +-
 ogr/ogrsf_frmts/csv/ogr_csv.h                      |    56 +-
 ogr/ogrsf_frmts/csv/ogrcsvdatasource.cpp           |    59 +-
 ogr/ogrsf_frmts/csv/ogrcsvdriver.cpp               |   190 +-
 ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp                |   741 +-
 ogr/ogrsf_frmts/csw/GNUmakefile                    |    14 +
 ogr/ogrsf_frmts/csw/drv_csw.html                   |    93 +
 ogr/ogrsf_frmts/csw/makefile.vc                    |    15 +
 ogr/ogrsf_frmts/csw/ogrcswdataset.cpp              |  1085 ++
 ogr/ogrsf_frmts/dgn/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/dgn/dgndump.c                      |    12 +-
 ogr/ogrsf_frmts/dgn/dgnhelp.cpp                    |    12 +-
 ogr/ogrsf_frmts/dgn/dgnopen.cpp                    |     6 +-
 ogr/ogrsf_frmts/dgn/dgnread.cpp                    |     5 +-
 ogr/ogrsf_frmts/dgn/dgnstroke.cpp                  |    21 +-
 ogr/ogrsf_frmts/dgn/dgnwrite.cpp                   |    19 +-
 ogr/ogrsf_frmts/dgn/drv_dgn.html                   |     2 +-
 ogr/ogrsf_frmts/dgn/ogr_dgn.h                      |    27 +-
 ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp           |    22 +-
 ogr/ogrsf_frmts/dgn/ogrdgndriver.cpp               |    93 +-
 ogr/ogrsf_frmts/dgn/ogrdgnlayer.cpp                |    25 +-
 ogr/ogrsf_frmts/dods/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/dods/drv_dods.html                 |     2 +-
 ogr/ogrsf_frmts/dods/ogr_dods.h                    |    10 +-
 ogr/ogrsf_frmts/dods/ogrdodsdriver.cpp             |     6 +-
 ogr/ogrsf_frmts/dods/ogrdodsgrid.cpp               |     8 +-
 ogr/ogrsf_frmts/dods/ogrdodslayer.cpp              |    12 +-
 ogr/ogrsf_frmts/dods/ogrdodssequencelayer.cpp      |    10 +-
 ogr/ogrsf_frmts/dwg/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/dwg/ogrdwg_dimension.cpp           |     8 +-
 ogr/ogrsf_frmts/dwg/ogrdwgdriver.cpp               |     8 +-
 ogr/ogrsf_frmts/dwg/ogrdwglayer.cpp                |    11 +-
 ogr/ogrsf_frmts/dxf/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/dxf/drv_dxf.html                   |    28 +-
 ogr/ogrsf_frmts/dxf/ogr_dxf.h                      |    26 +-
 ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp           |    22 +-
 ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp               |     4 +-
 ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp    |     4 +-
 ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp           |     7 +-
 ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp               |    82 +-
 ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp                |    33 +-
 ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp             |    16 +-
 ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp          |    21 +-
 ogr/ogrsf_frmts/edigeo/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/edigeo/drv_edigeo.html             |     4 +-
 ogr/ogrsf_frmts/edigeo/ogr_edigeo.h                |    23 +-
 ogr/ogrsf_frmts/edigeo/ogredigeodatasource.cpp     |    34 +-
 ogr/ogrsf_frmts/edigeo/ogredigeodriver.cpp         |    59 +-
 ogr/ogrsf_frmts/edigeo/ogredigeolayer.cpp          |    11 +-
 ogr/ogrsf_frmts/elastic/GNUmakefile                |     2 +-
 ogr/ogrsf_frmts/elastic/drv_elasticsearch.html     |     7 +-
 ogr/ogrsf_frmts/elastic/ogr_elastic.h              |    23 +-
 ogr/ogrsf_frmts/elastic/ogrelasticdatasource.cpp   |    18 +-
 ogr/ogrsf_frmts/elastic/ogrelasticdriver.cpp       |    76 +-
 ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp        |    13 +-
 ogr/ogrsf_frmts/filegdb/FGdbDatasource.cpp         |    71 +-
 ogr/ogrsf_frmts/filegdb/FGdbDriver.cpp             |   315 +-
 ogr/ogrsf_frmts/filegdb/FGdbLayer.cpp              |   310 +-
 ogr/ogrsf_frmts/filegdb/FGdbResultLayer.cpp        |     3 +-
 ogr/ogrsf_frmts/filegdb/FGdbUtils.cpp              |    54 +-
 ogr/ogrsf_frmts/filegdb/FGdbUtils.h                |     8 +-
 ogr/ogrsf_frmts/filegdb/GNUmakefile                |     2 +-
 ogr/ogrsf_frmts/filegdb/drv_filegdb.html           |    24 +-
 ogr/ogrsf_frmts/filegdb/makefile.vc                |     2 +-
 ogr/ogrsf_frmts/filegdb/ogr_fgdb.h                 |    55 +-
 ogr/ogrsf_frmts/fme/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/fme/fme2ogr.h                      |     6 +-
 ogr/ogrsf_frmts/fme/ogrfmedatasource.cpp           |    10 +-
 ogr/ogrsf_frmts/fme/ogrfmelayer.cpp                |     7 +-
 ogr/ogrsf_frmts/fme/ogrfmelayercached.cpp          |     6 +-
 ogr/ogrsf_frmts/fme/ogrfmelayerdb.cpp              |     6 +-
 ogr/ogrsf_frmts/generic/GNUmakefile                |    30 +-
 ogr/ogrsf_frmts/generic/makefile.vc                |    40 +-
 ogr/ogrsf_frmts/generic/ogr_gensql.cpp             |   435 +-
 ogr/ogrsf_frmts/generic/ogr_gensql.h               |    24 +-
 ogr/ogrsf_frmts/generic/ogr_miattrind.cpp          |    51 +-
 ogr/ogrsf_frmts/generic/ogrdatasource.cpp          |  1711 +-
 ogr/ogrsf_frmts/generic/ogremulatedtransaction.cpp |   556 +
 ogr/ogrsf_frmts/generic/ogremulatedtransaction.h   |   148 +
 ogr/ogrsf_frmts/generic/ogrlayer.cpp               |   312 +-
 ogr/ogrsf_frmts/generic/ogrlayerdecorator.cpp      |    82 +-
 ogr/ogrsf_frmts/generic/ogrlayerdecorator.h        |    28 +-
 ogr/ogrsf_frmts/generic/ogrlayerpool.cpp           |    31 +-
 ogr/ogrsf_frmts/generic/ogrlayerpool.h             |    19 +-
 ogr/ogrsf_frmts/generic/ogrmutexeddatasource.cpp   |   130 +-
 ogr/ogrsf_frmts/generic/ogrmutexeddatasource.h     |    34 +-
 ogr/ogrsf_frmts/generic/ogrmutexedlayer.cpp        |    62 +-
 ogr/ogrsf_frmts/generic/ogrmutexedlayer.h          |    31 +-
 ogr/ogrsf_frmts/generic/ogrregisterall.cpp         |    48 +-
 ogr/ogrsf_frmts/generic/ogrsfdriver.cpp            |   132 +-
 ogr/ogrsf_frmts/generic/ogrsfdriverregistrar.cpp   |   853 +-
 ogr/ogrsf_frmts/generic/ogrunionlayer.cpp          |    40 +-
 ogr/ogrsf_frmts/generic/ogrunionlayer.h            |    14 +-
 ogr/ogrsf_frmts/generic/ogrwarpedlayer.cpp         |    17 +-
 ogr/ogrsf_frmts/generic/ogrwarpedlayer.h           |    10 +-
 ogr/ogrsf_frmts/geoconcept/GNUmakefile             |     2 +-
 ogr/ogrsf_frmts/geoconcept/geoconcept.c            |     6 +-
 ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c   |     2 +-
 .../geoconcept/ogrgeoconceptdatasource.cpp         |    15 +-
 .../geoconcept/ogrgeoconceptdatasource.h           |     2 +-
 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp |    28 +-
 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp  |    17 +-
 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h    |    12 +-
 ogr/ogrsf_frmts/geojson/GNUmakefile                |     4 +-
 ogr/ogrsf_frmts/geojson/drv_geojson.html           |    71 +-
 ogr/ogrsf_frmts/geojson/libjson/json_object.c      |     3 +-
 .../geojson/libjson/json_object_iterator.c         |     2 +-
 ogr/ogrsf_frmts/geojson/libjson/json_util.c        |     4 +-
 ogr/ogrsf_frmts/geojson/ogr_geojson.h              |    52 +-
 ogr/ogrsf_frmts/geojson/ogresrijsonreader.cpp      |    21 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp   |   115 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsondriver.cpp       |   455 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonlayer.cpp        |    16 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonreader.cpp       |   428 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonreader.h         |    23 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonutils.cpp        |   147 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonutils.h          |    15 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp   |     7 +-
 ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp       |    51 +-
 ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp      |   115 +-
 ogr/ogrsf_frmts/geomedia/GNUmakefile               |     2 +-
 ogr/ogrsf_frmts/geomedia/ogr_geomedia.h            |    14 +-
 ogr/ogrsf_frmts/geomedia/ogrgeomediadatasource.cpp |     4 +-
 ogr/ogrsf_frmts/geomedia/ogrgeomediadriver.cpp     |    12 +-
 ogr/ogrsf_frmts/geomedia/ogrgeomedialayer.cpp      |     7 +-
 .../geomedia/ogrgeomediaselectlayer.cpp            |     8 +-
 ogr/ogrsf_frmts/geomedia/ogrgeomediatablelayer.cpp |    10 +-
 ogr/ogrsf_frmts/georss/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/georss/drv_georss.html             |     2 +-
 ogr/ogrsf_frmts/georss/ogr_georss.h                |    38 +-
 ogr/ogrsf_frmts/georss/ogrgeorssdatasource.cpp     |    23 +-
 ogr/ogrsf_frmts/georss/ogrgeorssdriver.cpp         |   117 +-
 ogr/ogrsf_frmts/georss/ogrgeorsslayer.cpp          |   175 +-
 ogr/ogrsf_frmts/gft/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gft/drv_gft.html                   |     2 +-
 ogr/ogrsf_frmts/gft/ogr_gft.h                      |    16 +-
 ogr/ogrsf_frmts/gft/ogrgftdatasource.cpp           |    20 +-
 ogr/ogrsf_frmts/gft/ogrgftdriver.cpp               |    15 +-
 ogr/ogrsf_frmts/gft/ogrgftlayer.cpp                |    28 +-
 ogr/ogrsf_frmts/gft/ogrgftresultlayer.cpp          |     6 +-
 ogr/ogrsf_frmts/gft/ogrgfttablelayer.cpp           |    52 +-
 ogr/ogrsf_frmts/gme/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gme/ogr_gme.h                      |    10 +-
 ogr/ogrsf_frmts/gme/ogrgmedatasource.cpp           |    18 +-
 ogr/ogrsf_frmts/gme/ogrgmedriver.cpp               |    10 +-
 ogr/ogrsf_frmts/gme/ogrgmejson.cpp                 |     8 +-
 ogr/ogrsf_frmts/gme/ogrgmelayer.cpp                |    98 +-
 ogr/ogrsf_frmts/gml/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gml/drv_gml.html                   |   131 +-
 ogr/ogrsf_frmts/gml/gfstemplate.cpp                |     6 +-
 ogr/ogrsf_frmts/gml/gmlfeature.cpp                 |     4 +-
 ogr/ogrsf_frmts/gml/gmlfeatureclass.cpp            |   179 +-
 ogr/ogrsf_frmts/gml/gmlhandler.cpp                 |    80 +-
 ogr/ogrsf_frmts/gml/gmlpropertydefn.cpp            |    63 +-
 ogr/ogrsf_frmts/gml/gmlreader.cpp                  |    96 +-
 ogr/ogrsf_frmts/gml/gmlreader.h                    |    38 +-
 ogr/ogrsf_frmts/gml/gmlreaderp.h                   |    14 +-
 ogr/ogrsf_frmts/gml/gmlutils.cpp                   |     4 +-
 ogr/ogrsf_frmts/gml/hugefileresolver.cpp           |    21 +-
 ogr/ogrsf_frmts/gml/ogr_gml.h                      |    40 +-
 ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp           |   604 +-
 ogr/ogrsf_frmts/gml/ogrgmldriver.cpp               |   152 +-
 ogr/ogrsf_frmts/gml/ogrgmllayer.cpp                |   217 +-
 ogr/ogrsf_frmts/gml/parsexsd.cpp                   |   185 +-
 ogr/ogrsf_frmts/gml/parsexsd.h                     |     5 +-
 ogr/ogrsf_frmts/gmt/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gmt/drv_gmt.html                   |     8 +-
 ogr/ogrsf_frmts/gmt/ogr_gmt.h                      |     4 +-
 ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp           |    12 +-
 ogr/ogrsf_frmts/gmt/ogrgmtdriver.cpp               |    10 +-
 ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp                |     7 +-
 ogr/ogrsf_frmts/gpkg/GNUmakefile                   |    13 +-
 ogr/ogrsf_frmts/gpkg/drv_geopackage.html           |   120 +-
 ogr/ogrsf_frmts/gpkg/drv_geopackage_raster.html    |   375 +
 ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp  |  1935 ++
 ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html      |   182 +
 ogr/ogrsf_frmts/gpkg/geopackage_aspatial.md        |    80 +
 ogr/ogrsf_frmts/gpkg/makefile.vc                   |     9 +-
 ogr/ogrsf_frmts/gpkg/ogr_geopackage.h              |   453 +-
 ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp   |  4449 ++++-
 ogr/ogrsf_frmts/gpkg/ogrgeopackagedriver.cpp       |   210 +-
 ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp        |  1421 +-
 ogr/ogrsf_frmts/gpkg/ogrgeopackageselectlayer.cpp  |   161 +
 ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp   |  2670 +++
 ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.cpp      |   160 +-
 ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.h        |     8 +-
 ogr/ogrsf_frmts/gpsbabel/GNUmakefile               |     2 +-
 ogr/ogrsf_frmts/gpsbabel/ogr_gpsbabel.h            |    33 +-
 ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp |    77 +-
 ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp     |   118 +-
 .../gpsbabel/ogrgpsbabelwritedatasource.cpp        |    16 +-
 ogr/ogrsf_frmts/gpx/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gpx/drv_gpx.html                   |     2 +-
 ogr/ogrsf_frmts/gpx/ogr_gpx.h                      |    24 +-
 ogr/ogrsf_frmts/gpx/ogrgpxdatasource.cpp           |    20 +-
 ogr/ogrsf_frmts/gpx/ogrgpxdriver.cpp               |   114 +-
 ogr/ogrsf_frmts/gpx/ogrgpxlayer.cpp                |    34 +-
 ogr/ogrsf_frmts/grass/GNUmakefile                  |     2 +-
 ogr/ogrsf_frmts/grass/ogrgrass.h                   |    14 +-
 ogr/ogrsf_frmts/grass/ogrgrassdatasource.cpp       |    10 +-
 ogr/ogrsf_frmts/grass/ogrgrassdriver.cpp           |    23 +-
 ogr/ogrsf_frmts/grass/ogrgrasslayer.cpp            |    25 +-
 ogr/ogrsf_frmts/gtm/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/gtm/gtmtracklayer.cpp              |    12 +-
 ogr/ogrsf_frmts/gtm/gtmwaypointlayer.cpp           |    11 +-
 ogr/ogrsf_frmts/gtm/ogr_gtm.h                      |    35 +-
 ogr/ogrsf_frmts/gtm/ogrgtmdatasource.cpp           |    16 +-
 ogr/ogrsf_frmts/gtm/ogrgtmdriver.cpp               |    94 +-
 ogr/ogrsf_frmts/gtm/ogrgtmlayer.cpp                |    10 +-
 ogr/ogrsf_frmts/htf/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/htf/ogr_htf.h                      |    22 +-
 ogr/ogrsf_frmts/htf/ogrhtfdatasource.cpp           |    32 +-
 ogr/ogrsf_frmts/htf/ogrhtfdriver.cpp               |    61 +-
 ogr/ogrsf_frmts/htf/ogrhtflayer.cpp                |    13 +-
 ogr/ogrsf_frmts/idb/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/idb/ogr_idb.h                      |    16 +-
 ogr/ogrsf_frmts/idb/ogridblayer.cpp                |     7 +-
 ogr/ogrsf_frmts/idb/ogridbselectlayer.cpp          |     8 +-
 ogr/ogrsf_frmts/idb/ogridbtablelayer.cpp           |    14 +-
 ogr/ogrsf_frmts/idrisi/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/idrisi/ogr_idrisi.h                |     7 +-
 ogr/ogrsf_frmts/idrisi/ogridrisidatasource.cpp     |    17 +-
 ogr/ogrsf_frmts/idrisi/ogridrisidriver.cpp         |    23 +-
 ogr/ogrsf_frmts/idrisi/ogridrisilayer.cpp          |     9 +-
 ogr/ogrsf_frmts/ili/GNUmakefile                    |     6 +-
 ogr/ogrsf_frmts/ili/drv_ili.html                   |    54 +-
 ogr/ogrsf_frmts/ili/ili1reader.cpp                 |   330 +-
 ogr/ogrsf_frmts/ili/ili1reader.h                   |     3 +-
 ogr/ogrsf_frmts/ili/ili1readerp.h                  |     5 +-
 ogr/ogrsf_frmts/ili/ili2handler.cpp                |     6 +-
 ogr/ogrsf_frmts/ili/ili2reader.cpp                 |   112 +-
 ogr/ogrsf_frmts/ili/ili2reader.h                   |     3 +-
 ogr/ogrsf_frmts/ili/ili2readerp.h                  |     5 +-
 ogr/ogrsf_frmts/ili/ilihelper.cpp                  |   133 -
 ogr/ogrsf_frmts/ili/ilihelper.h                    |    43 -
 ogr/ogrsf_frmts/ili/imdreader.cpp                  |    54 +-
 ogr/ogrsf_frmts/ili/makefile.vc                    |     2 +-
 ogr/ogrsf_frmts/ili/ogr_ili1.h                     |    35 +-
 ogr/ogrsf_frmts/ili/ogr_ili2.h                     |    30 +-
 ogr/ogrsf_frmts/ili/ogrili1datasource.cpp          |    51 +-
 ogr/ogrsf_frmts/ili/ogrili1driver.cpp              |    87 +-
 ogr/ogrsf_frmts/ili/ogrili1layer.cpp               |   160 +-
 ogr/ogrsf_frmts/ili/ogrili2datasource.cpp          |    54 +-
 ogr/ogrsf_frmts/ili/ogrili2driver.cpp              |    89 +-
 ogr/ogrsf_frmts/ili/ogrili2layer.cpp               |    30 +-
 ogr/ogrsf_frmts/ingres/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/ingres/ogr_ingres.h                |    18 +-
 ogr/ogrsf_frmts/ingres/ogringresdatasource.cpp     |     8 +-
 ogr/ogrsf_frmts/ingres/ogringreslayer.cpp          |    10 +-
 ogr/ogrsf_frmts/ingres/ogringresresultlayer.cpp    |     2 +-
 ogr/ogrsf_frmts/ingres/ogringrestablelayer.cpp     |    19 +-
 ogr/ogrsf_frmts/jml/GNUmakefile                    |    19 +
 ogr/ogrsf_frmts/jml/drv_jml.html                   |    79 +
 ogr/ogrsf_frmts/jml/makefile.vc                    |    18 +
 ogr/ogrsf_frmts/jml/ogr_jml.h                      |   212 +
 ogr/ogrsf_frmts/jml/ogrjmldataset.cpp              |   249 +
 ogr/ogrsf_frmts/jml/ogrjmllayer.cpp                |   785 +
 ogr/ogrsf_frmts/jml/ogrjmlwriterlayer.cpp          |   360 +
 ogr/ogrsf_frmts/kml/drv_kml.html                   |    10 +-
 ogr/ogrsf_frmts/kml/kml.cpp                        |     2 +-
 ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp            |    16 +-
 ogr/ogrsf_frmts/kml/ogr_kml.h                      |    26 +-
 ogr/ogrsf_frmts/kml/ogrkmldatasource.cpp           |    14 +-
 ogr/ogrsf_frmts/kml/ogrkmldriver.cpp               |    97 +-
 ogr/ogrsf_frmts/kml/ogrkmllayer.cpp                |    26 +-
 ogr/ogrsf_frmts/libkml/drv_libkml.html             |     4 +-
 ogr/ogrsf_frmts/libkml/ogr_libkml.h                |    34 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmldatasource.cpp     |    20 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmldriver.cpp         |   261 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmlfeature.cpp        |    11 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmlfield.cpp          |   127 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.cpp       |    46 +-
 ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.h         |     2 -
 ogr/ogrsf_frmts/libkml/ogrlibkmllayer.cpp          |    17 +-
 ogr/ogrsf_frmts/makefile.vc                        |    49 +-
 ogr/ogrsf_frmts/mdb/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/mdb/drv_mdb.html                   |     2 +-
 ogr/ogrsf_frmts/mdb/ogr_mdb.h                      |     8 +-
 ogr/ogrsf_frmts/mdb/ogrmdbdatasource.cpp           |     9 +-
 ogr/ogrsf_frmts/mdb/ogrmdbdriver.cpp               |    19 +-
 ogr/ogrsf_frmts/mdb/ogrmdblayer.cpp                |    15 +-
 ogr/ogrsf_frmts/mem/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/mem/ogr_mem.h                      |    27 +-
 ogr/ogrsf_frmts/mem/ogrmemdatasource.cpp           |    19 +-
 ogr/ogrsf_frmts/mem/ogrmemdriver.cpp               |    11 +-
 ogr/ogrsf_frmts/mem/ogrmemlayer.cpp                |   101 +-
 ogr/ogrsf_frmts/mitab/GNUmakefile                  |     4 +-
 ogr/ogrsf_frmts/mitab/drv_mitab.html               |    67 +-
 ogr/ogrsf_frmts/mitab/mitab.h                      |   206 +-
 ogr/ogrsf_frmts/mitab/mitab_bounds.cpp             |  2239 +--
 ogr/ogrsf_frmts/mitab/mitab_coordsys.cpp           |  1242 +-
 ogr/ogrsf_frmts/mitab/mitab_datfile.cpp            |   890 +-
 ogr/ogrsf_frmts/mitab/mitab_feature.cpp            |   123 +-
 ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp        |   141 +-
 ogr/ogrsf_frmts/mitab/mitab_idfile.cpp             |    74 +-
 ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp       |   107 +-
 ogr/ogrsf_frmts/mitab/mitab_indfile.cpp            |    26 +-
 ogr/ogrsf_frmts/mitab/mitab_mapcoordblock.cpp      |    29 +-
 ogr/ogrsf_frmts/mitab/mitab_mapfile.cpp            |   729 +-
 ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp     |   134 +-
 ogr/ogrsf_frmts/mitab/mitab_mapindexblock.cpp      |    58 +-
 ogr/ogrsf_frmts/mitab/mitab_mapobjectblock.cpp     |   112 +-
 ogr/ogrsf_frmts/mitab/mitab_maptoolblock.cpp       |    26 +-
 ogr/ogrsf_frmts/mitab/mitab_middatafile.cpp        |    21 +-
 ogr/ogrsf_frmts/mitab/mitab_miffile.cpp            |   118 +-
 ogr/ogrsf_frmts/mitab/mitab_ogr_datasource.cpp     |   183 +-
 ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp         |   201 +-
 ogr/ogrsf_frmts/mitab/mitab_ogr_driver.h           |    22 +-
 ogr/ogrsf_frmts/mitab/mitab_priv.h                 |   189 +-
 ogr/ogrsf_frmts/mitab/mitab_rawbinblock.cpp        |   219 +-
 ogr/ogrsf_frmts/mitab/mitab_spatialref.cpp         |   664 +-
 ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp            |   727 +-
 ogr/ogrsf_frmts/mitab/mitab_tabseamless.cpp        |   107 +-
 ogr/ogrsf_frmts/mitab/mitab_tabview.cpp            |    56 +-
 ogr/ogrsf_frmts/mitab/mitab_utils.cpp              |    44 +-
 ogr/ogrsf_frmts/mssqlspatial/GNUmakefile           |     2 +-
 ogr/ogrsf_frmts/mssqlspatial/drv_mssqlspatial.html |   162 +-
 ogr/ogrsf_frmts/mssqlspatial/ogr_mssqlspatial.h    |    35 +-
 .../mssqlspatial/ogrmssqlgeometryvalidator.cpp     |     4 +-
 .../mssqlspatial/ogrmssqlspatialdatasource.cpp     |   170 +-
 .../mssqlspatial/ogrmssqlspatialdriver.cpp         |    40 +-
 .../mssqlspatial/ogrmssqlspatiallayer.cpp          |   112 +-
 .../mssqlspatial/ogrmssqlspatialselectlayer.cpp    |     8 +-
 .../mssqlspatial/ogrmssqlspatialtablelayer.cpp     |   361 +-
 ogr/ogrsf_frmts/mysql/GNUmakefile                  |     2 +-
 ogr/ogrsf_frmts/mysql/drv_mysql.html               |    10 +-
 ogr/ogrsf_frmts/mysql/ogr_mysql.h                  |    41 +-
 ogr/ogrsf_frmts/mysql/ogrmysqldatasource.cpp       |    80 +-
 ogr/ogrsf_frmts/mysql/ogrmysqldriver.cpp           |   115 +-
 ogr/ogrsf_frmts/mysql/ogrmysqllayer.cpp            |     8 +-
 ogr/ogrsf_frmts/mysql/ogrmysqlresultlayer.cpp      |     7 +-
 ogr/ogrsf_frmts/mysql/ogrmysqltablelayer.cpp       |   150 +-
 ogr/ogrsf_frmts/nas/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/nas/nashandler.cpp                 |     2 +-
 ogr/ogrsf_frmts/nas/nasreader.cpp                  |    35 +-
 ogr/ogrsf_frmts/nas/nasreaderp.h                   |    11 +-
 ogr/ogrsf_frmts/nas/ogr_nas.h                      |    23 +-
 ogr/ogrsf_frmts/nas/ogrnasdatasource.cpp           |    85 +-
 ogr/ogrsf_frmts/nas/ogrnasdriver.cpp               |    99 +-
 ogr/ogrsf_frmts/nas/ogrnaslayer.cpp                |    30 +-
 ogr/ogrsf_frmts/nas/ogrnasrelationlayer.cpp        |     7 +-
 ogr/ogrsf_frmts/ntf/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/ntf/ntf.h                          |    32 +-
 ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp              |    14 +-
 ogr/ogrsf_frmts/ntf/ntf_generic.cpp                |    26 +-
 ogr/ogrsf_frmts/ntf/ntf_raster.cpp                 |    14 +-
 ogr/ogrsf_frmts/ntf/ntffilereader.cpp              |     6 +-
 ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp               |    79 +-
 ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp    |    12 +-
 ogr/ogrsf_frmts/ntf/ogrntflayer.cpp                |     5 +-
 ogr/ogrsf_frmts/null/ogrnulldriver.cpp             |    15 +-
 ogr/ogrsf_frmts/oci/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/oci/drv_oci.html                   |    34 +-
 ogr/ogrsf_frmts/oci/ogr_oci.h                      |    49 +-
 ogr/ogrsf_frmts/oci/ogrocidatasource.cpp           |   100 +-
 ogr/ogrsf_frmts/oci/ogrocidriver.cpp               |   109 +-
 ogr/ogrsf_frmts/oci/ogrocilayer.cpp                |    34 +-
 ogr/ogrsf_frmts/oci/ogrociloaderlayer.cpp          |    24 +-
 ogr/ogrsf_frmts/oci/ogrociselectlayer.cpp          |    21 +-
 ogr/ogrsf_frmts/oci/ogrocisession.cpp              |    21 +-
 ogr/ogrsf_frmts/oci/ogrocistatement.cpp            |    29 +-
 ogr/ogrsf_frmts/oci/ogrocistringbuf.cpp            |     6 +-
 ogr/ogrsf_frmts/oci/ogrocitablelayer.cpp           |   344 +-
 ogr/ogrsf_frmts/oci/ogrociwritablelayer.cpp        |    48 +-
 ogr/ogrsf_frmts/odbc/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/odbc/ogr_odbc.h                    |    18 +-
 ogr/ogrsf_frmts/odbc/ogrodbcdatasource.cpp         |    82 +-
 ogr/ogrsf_frmts/odbc/ogrodbclayer.cpp              |    12 +-
 ogr/ogrsf_frmts/odbc/ogrodbcselectlayer.cpp        |     8 +-
 ogr/ogrsf_frmts/odbc/ogrodbctablelayer.cpp         |    14 +-
 ogr/ogrsf_frmts/ods/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/ods/ods_formula_node.cpp           |     4 +-
 ogr/ogrsf_frmts/ods/ods_formula_parser.cpp         |    17 +-
 ogr/ogrsf_frmts/ods/ods_formula_parser.y           |     5 +-
 ogr/ogrsf_frmts/ods/ogr_ods.h                      |    18 +-
 ogr/ogrsf_frmts/ods/ogrodsdatasource.cpp           |   152 +-
 ogr/ogrsf_frmts/ods/ogrodsdriver.cpp               |    14 +-
 ogr/ogrsf_frmts/ogdi/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/ogdi/ogrogdi.h                     |     6 +-
 ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp         |     6 +-
 ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp             |    18 +-
 ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp              |     9 +-
 ogr/ogrsf_frmts/ogr_attrind.h                      |    12 +-
 ogr/ogrsf_frmts/ogr_formats.html                   |    52 +-
 ogr/ogrsf_frmts/ogrsf_frmts.dox                    |  1060 +-
 ogr/ogrsf_frmts/ogrsf_frmts.h                      |   196 +-
 ogr/ogrsf_frmts/openair/GNUmakefile                |     2 +-
 ogr/ogrsf_frmts/openair/ogr_openair.h              |    19 +-
 ogr/ogrsf_frmts/openair/ogropenairdatasource.cpp   |    46 +-
 ogr/ogrsf_frmts/openair/ogropenairdriver.cpp       |    68 +-
 ogr/ogrsf_frmts/openair/ogropenairlabellayer.cpp   |     6 +-
 ogr/ogrsf_frmts/openair/ogropenairlayer.cpp        |    13 +-
 ogr/ogrsf_frmts/openfilegdb/GNUmakefile            |     4 +-
 ogr/ogrsf_frmts/openfilegdb/drv_openfilegdb.html   |     1 +
 ogr/ogrsf_frmts/openfilegdb/filegdbindex.cpp       |     6 +-
 ogr/ogrsf_frmts/openfilegdb/filegdbtable.cpp       |   228 +-
 ogr/ogrsf_frmts/openfilegdb/filegdbtable.h         |    22 +-
 ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h      |    28 +-
 .../openfilegdb/ogropenfilegdbdatasource.cpp       |    63 +-
 .../openfilegdb/ogropenfilegdbdriver.cpp           |   102 +-
 .../openfilegdb/ogropenfilegdblayer.cpp            |   300 +-
 ogr/ogrsf_frmts/osm/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/osm/drv_osm.html                   |     8 +-
 ogr/ogrsf_frmts/osm/gpb.h                          |     8 +-
 ogr/ogrsf_frmts/osm/ogr_osm.h                      |    53 +-
 ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp           |   214 +-
 ogr/ogrsf_frmts/osm/ogrosmdriver.cpp               |    78 +-
 ogr/ogrsf_frmts/osm/ogrosmlayer.cpp                |   191 +-
 ogr/ogrsf_frmts/osm/osm_parser.cpp                 |    65 +-
 ogr/ogrsf_frmts/pcidsk/GNUmakefile                 |    18 -
 ogr/ogrsf_frmts/pcidsk/makefile.vc                 |    16 -
 ogr/ogrsf_frmts/pcidsk/ogr_pcidsk.h                |   129 -
 ogr/ogrsf_frmts/pcidsk/ogrpcidskdatasource.cpp     |   272 -
 ogr/ogrsf_frmts/pcidsk/ogrpcidskdriver.cpp         |   135 -
 ogr/ogrsf_frmts/pcidsk/ogrpcidsklayer.cpp          |   833 -
 ogr/ogrsf_frmts/pdf/GNUmakefile                    |    14 -
 ogr/ogrsf_frmts/pdf/drv_pdf.html                   |   135 -
 ogr/ogrsf_frmts/pdf/makefile.vc                    |    16 -
 ogr/ogrsf_frmts/pdf/ogr_pdf.h                      |   170 -
 ogr/ogrsf_frmts/pdf/ogrpdfdatasource.cpp           |  2159 ---
 ogr/ogrsf_frmts/pdf/ogrpdfdriver.cpp               |   158 -
 ogr/ogrsf_frmts/pds/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/pds/ogr_pds.h                      |    26 +-
 ogr/ogrsf_frmts/pds/ogrpdsdatasource.cpp           |    11 +-
 ogr/ogrsf_frmts/pds/ogrpdsdriver.cpp               |    60 +-
 ogr/ogrsf_frmts/pds/ogrpdslayer.cpp                |    15 +-
 ogr/ogrsf_frmts/pg/GNUmakefile                     |     4 +-
 ogr/ogrsf_frmts/pg/drv_pg.html                     |    27 +-
 ogr/ogrsf_frmts/pg/drv_pg_advanced.html            |   139 +-
 ogr/ogrsf_frmts/pg/makefile.vc                     |     2 +-
 ogr/ogrsf_frmts/pg/ogr_pg.h                        |   133 +-
 ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp             |  1333 +-
 ogr/ogrsf_frmts/pg/ogrpgdriver.cpp                 |   122 +-
 ogr/ogrsf_frmts/pg/ogrpglayer.cpp                  |   426 +-
 ogr/ogrsf_frmts/pg/ogrpgresultlayer.cpp            |    70 +-
 ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp             |  1632 +-
 ogr/ogrsf_frmts/pg/ogrpgutility.cpp                |    14 +-
 ogr/ogrsf_frmts/pg/ogrpgutility.h                  |     5 +-
 ogr/ogrsf_frmts/pgdump/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/pgdump/drv_pgdump.html             |    14 +-
 ogr/ogrsf_frmts/pgdump/ogr_pgdump.h                |    81 +-
 ogr/ogrsf_frmts/pgdump/ogrpgdumpdatasource.cpp     |   103 +-
 ogr/ogrsf_frmts/pgdump/ogrpgdumpdriver.cpp         |   139 +-
 ogr/ogrsf_frmts/pgdump/ogrpgdumplayer.cpp          |   620 +-
 ogr/ogrsf_frmts/pgeo/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/pgeo/ogr_pgeo.h                    |    14 +-
 ogr/ogrsf_frmts/pgeo/ogrpgeodatasource.cpp         |    50 +-
 ogr/ogrsf_frmts/pgeo/ogrpgeodriver.cpp             |    12 +-
 ogr/ogrsf_frmts/pgeo/ogrpgeolayer.cpp              |     7 +-
 ogr/ogrsf_frmts/pgeo/ogrpgeoselectlayer.cpp        |     8 +-
 ogr/ogrsf_frmts/pgeo/ogrpgeotablelayer.cpp         |    16 +-
 ogr/ogrsf_frmts/plscenes/GNUmakefile               |    14 +
 ogr/ogrsf_frmts/plscenes/drv_plscenes.html         |   194 +
 ogr/ogrsf_frmts/plscenes/makefile.vc               |    15 +
 ogr/ogrsf_frmts/plscenes/ogr_plscenes.h            |   133 +
 ogr/ogrsf_frmts/plscenes/ogrplscenesdataset.cpp    |   577 +
 ogr/ogrsf_frmts/plscenes/ogrplsceneslayer.cpp      |   676 +
 ogr/ogrsf_frmts/rec/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/rec/ogr_rec.h                      |    17 +-
 ogr/ogrsf_frmts/rec/ogrrecdriver.cpp               |    65 +-
 ogr/ogrsf_frmts/rec/ogrreclayer.cpp                |     6 +-
 ogr/ogrsf_frmts/s57/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/s57/drv_s57.html                   |    40 +-
 ogr/ogrsf_frmts/s57/ogr_s57.h                      |    23 +-
 ogr/ogrsf_frmts/s57/ogrs57datasource.cpp           |   144 +-
 ogr/ogrsf_frmts/s57/ogrs57driver.cpp               |   119 +-
 ogr/ogrsf_frmts/s57/ogrs57layer.cpp                |    17 +-
 ogr/ogrsf_frmts/s57/s57.h                          |    24 +-
 ogr/ogrsf_frmts/s57/s57classregistrar.cpp          |     8 +-
 ogr/ogrsf_frmts/s57/s57featuredefns.cpp            |    10 +-
 ogr/ogrsf_frmts/s57/s57reader.cpp                  |    26 +-
 ogr/ogrsf_frmts/s57/s57writer.cpp                  |    92 +-
 ogr/ogrsf_frmts/sde/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/sde/ogr_sde.h                      |    14 +-
 ogr/ogrsf_frmts/sde/ogrsdedatasource.cpp           |    14 +-
 ogr/ogrsf_frmts/sde/ogrsdelayer.cpp                |    29 +-
 ogr/ogrsf_frmts/sdts/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/sdts/ogr_sdts.h                    |    21 +-
 ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp             |    74 +-
 ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp              |    10 +-
 ogr/ogrsf_frmts/segukooa/GNUmakefile               |     2 +-
 ogr/ogrsf_frmts/segukooa/ogr_segukooa.h            |    20 +-
 ogr/ogrsf_frmts/segukooa/ogrsegukooadatasource.cpp |    11 +-
 ogr/ogrsf_frmts/segukooa/ogrsegukooadriver.cpp     |    64 +-
 ogr/ogrsf_frmts/segukooa/ogrsegukooalayer.cpp      |    38 +-
 ogr/ogrsf_frmts/segy/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/segy/ogr_segy.h                    |    22 +-
 ogr/ogrsf_frmts/segy/ogrsegydatasource.cpp         |   119 +-
 ogr/ogrsf_frmts/segy/ogrsegydriver.cpp             |   149 +-
 ogr/ogrsf_frmts/segy/ogrsegylayer.cpp              |     9 +-
 ogr/ogrsf_frmts/selafin/GNUmakefile                |    15 +
 ogr/ogrsf_frmts/selafin/drv_selafin.html           |   259 +
 ogr/ogrsf_frmts/selafin/io_selafin.cpp             |   666 +
 ogr/ogrsf_frmts/selafin/io_selafin.h               |   358 +
 ogr/ogrsf_frmts/selafin/makefile.vc                |    15 +
 ogr/ogrsf_frmts/selafin/ogr_selafin.h              |   130 +
 ogr/ogrsf_frmts/selafin/ogrselafindatasource.cpp   |   592 +
 ogr/ogrsf_frmts/selafin/ogrselafindriver.cpp       |   201 +
 ogr/ogrsf_frmts/selafin/ogrselafinlayer.cpp        |   719 +
 ogr/ogrsf_frmts/shape/GNUmakefile                  |     2 +-
 ogr/ogrsf_frmts/shape/dbfopen.c                    |    40 +-
 ogr/ogrsf_frmts/shape/drv_shapefile.html           |    48 +-
 ogr/ogrsf_frmts/shape/ogrshape.h                   |    91 +-
 ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp       |    51 +-
 ogr/ogrsf_frmts/shape/ogrshapedriver.cpp           |   150 +-
 ogr/ogrsf_frmts/shape/ogrshapelayer.cpp            |   498 +-
 ogr/ogrsf_frmts/shape/sbnsearch.c                  |    12 +-
 ogr/ogrsf_frmts/shape/shape2ogr.cpp                |   174 +-
 ogr/ogrsf_frmts/shape/shapefil.h                   |     9 +-
 ogr/ogrsf_frmts/shape/shp_vsi.c                    |    14 +-
 ogr/ogrsf_frmts/shape/shp_vsi.h                    |     3 +-
 ogr/ogrsf_frmts/shape/shpopen.c                    |    99 +-
 ogr/ogrsf_frmts/shape/shptree.c                    |     4 +-
 ogr/ogrsf_frmts/sosi/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/sosi/fyba_melding.cpp              |     6 +-
 ogr/ogrsf_frmts/sosi/ogr_sosi.h                    |    25 +-
 ogr/ogrsf_frmts/sosi/ogrsosidatasource.cpp         |     9 +-
 ogr/ogrsf_frmts/sosi/ogrsosidriver.cpp             |    90 +-
 ogr/ogrsf_frmts/sosi/ogrsosilayer.cpp              |     9 +-
 ogr/ogrsf_frmts/sqlite/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/sqlite/drv_sqlite.html             |    72 +-
 ogr/ogrsf_frmts/sqlite/ogr_sqlite.h                |   362 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp     |   994 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitedriver.cpp         |   202 +-
 ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp     |    28 +-
 ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.h       |     4 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitelayer.cpp          |   310 +-
 ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp         |    14 +-
 ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp    |   186 +-
 .../sqlite/ogrsqlitesinglefeaturelayer.cpp         |     5 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitesqlfunctions.cpp   |    41 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp     |  1992 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp            |    90 +-
 ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp      |    64 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.cpp     |   169 +-
 ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.h       |     4 +-
 ogr/ogrsf_frmts/sua/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/sua/ogr_sua.h                      |    20 +-
 ogr/ogrsf_frmts/sua/ogrsuadatasource.cpp           |    38 +-
 ogr/ogrsf_frmts/sua/ogrsuadriver.cpp               |    68 +-
 ogr/ogrsf_frmts/sua/ogrsualayer.cpp                |    10 +-
 ogr/ogrsf_frmts/svg/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/svg/ogr_svg.h                      |    26 +-
 ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp           |    15 +-
 ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp               |    64 +-
 ogr/ogrsf_frmts/svg/ogrsvglayer.cpp                |    10 +-
 ogr/ogrsf_frmts/sxf/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/sxf/ogr_sxf.h                      |    14 +-
 ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp           |    81 +-
 ogr/ogrsf_frmts/sxf/ogrsxfdriver.cpp               |    10 +-
 ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp                |   305 +-
 ogr/ogrsf_frmts/sxf/org_sxf_defs.h                 |     1 +
 ogr/ogrsf_frmts/tiger/GNUmakefile                  |     2 +-
 ogr/ogrsf_frmts/tiger/ogr_tiger.h                  |    31 +-
 ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp       |    20 +-
 ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp           |    98 +-
 ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp            |    18 +-
 ogr/ogrsf_frmts/tiger/tigeraltname.cpp             |     7 +-
 ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp       |     7 +-
 ogr/ogrsf_frmts/tiger/tigercompletechain.cpp       |     9 +-
 ogr/ogrsf_frmts/tiger/tigerentitynames.cpp         |     7 +-
 ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp          |     7 +-
 ogr/ogrsf_frmts/tiger/tigerfilebase.cpp            |     7 +-
 ogr/ogrsf_frmts/tiger/tigeridhistory.cpp           |     7 +-
 ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp         |     8 +-
 ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp           |     4 +-
 ogr/ogrsf_frmts/tiger/tigeroverunder.cpp           |     8 +-
 ogr/ogrsf_frmts/tiger/tigerpip.cpp                 |     7 +-
 ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp       |     8 +-
 ogr/ogrsf_frmts/tiger/tigerpolygon.cpp             |     5 +-
 ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp  |     7 +-
 ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp     |     7 +-
 ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp     |     9 +-
 ogr/ogrsf_frmts/tiger/tigertlidrange.cpp           |     8 +-
 ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp          |     8 +-
 ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp            |     8 +-
 ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp            |     8 +-
 ogr/ogrsf_frmts/vfk/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/vfk/drv_vfk.html                   |    21 +-
 ogr/ogrsf_frmts/vfk/ogr_vfk.h                      |    20 +-
 ogr/ogrsf_frmts/vfk/ogrvfkdriver.cpp               |    66 +-
 ogr/ogrsf_frmts/vfk/ogrvfklayer.cpp                |    52 +-
 ogr/ogrsf_frmts/vfk/vfkdatablock.cpp               |    17 +-
 ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp         |   235 +-
 ogr/ogrsf_frmts/vfk/vfkfeature.cpp                 |   180 +-
 ogr/ogrsf_frmts/vfk/vfkfeaturesqlite.cpp           |    18 +-
 ogr/ogrsf_frmts/vfk/vfkproperty.cpp                |    26 +-
 ogr/ogrsf_frmts/vfk/vfkreader.cpp                  |    29 +-
 ogr/ogrsf_frmts/vfk/vfkreader.h                    |    33 +-
 ogr/ogrsf_frmts/vfk/vfkreadersqlite.cpp            |    67 +-
 ogr/ogrsf_frmts/vrt/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/vrt/drv_vrt.html                   |    52 +-
 ogr/ogrsf_frmts/vrt/ogr_vrt.h                      |    49 +-
 ogr/ogrsf_frmts/vrt/ogrvrtdatasource.cpp           |    89 +-
 ogr/ogrsf_frmts/vrt/ogrvrtdriver.cpp               |   128 +-
 ogr/ogrsf_frmts/vrt/ogrvrtlayer.cpp                |   163 +-
 ogr/ogrsf_frmts/walk/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/walk/ogrwalk.h                     |     6 +-
 ogr/ogrsf_frmts/walk/ogrwalkdatasource.cpp         |     8 +-
 ogr/ogrsf_frmts/walk/ogrwalklayer.cpp              |     6 +
 ogr/ogrsf_frmts/walk/ogrwalktablelayer.cpp         |     8 +-
 ogr/ogrsf_frmts/wasp/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/wasp/drv_wasp.html                 |     8 +-
 ogr/ogrsf_frmts/wasp/ogrwasp.h                     |    25 +-
 ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp         |    73 +-
 ogr/ogrsf_frmts/wasp/ogrwaspdriver.cpp             |    10 +-
 ogr/ogrsf_frmts/wasp/ogrwasplayer.cpp              |   156 +-
 ogr/ogrsf_frmts/wfs/GNUmakefile                    |     6 +-
 ogr/ogrsf_frmts/wfs/drv_wfs.html                   |    67 +-
 ogr/ogrsf_frmts/wfs/makefile.vc                    |     2 +-
 ogr/ogrsf_frmts/wfs/ogr_wfs.h                      |   131 +-
 ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp           |   387 +-
 ogr/ogrsf_frmts/wfs/ogrwfsdriver.cpp               |    75 +-
 ogr/ogrsf_frmts/wfs/ogrwfsfilter.cpp               |  1344 +-
 ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp            |   801 +
 ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp                |   284 +-
 ogr/ogrsf_frmts/xls/GNUmakefile                    |     2 +-
 ogr/ogrsf_frmts/xls/ogr_xls.h                      |     4 +-
 ogr/ogrsf_frmts/xls/ogrxlsdatasource.cpp           |     8 +-
 ogr/ogrsf_frmts/xls/ogrxlsdriver.cpp               |    14 +-
 ogr/ogrsf_frmts/xls/ogrxlslayer.cpp                |    11 +-
 ogr/ogrsf_frmts/xlsx/GNUmakefile                   |     2 +-
 ogr/ogrsf_frmts/xlsx/ogr_xlsx.h                    |    36 +-
 ogr/ogrsf_frmts/xlsx/ogrxlsxdatasource.cpp         |   142 +-
 ogr/ogrsf_frmts/xlsx/ogrxlsxdriver.cpp             |    14 +-
 ogr/ogrsf_frmts/xplane/GNUmakefile                 |     2 +-
 ogr/ogrsf_frmts/xplane/ogr_xplane.h                |     6 +-
 ogr/ogrsf_frmts/xplane/ogr_xplane_apt_reader.cpp   |     2 +-
 ogr/ogrsf_frmts/xplane/ogr_xplane_nav_reader.cpp   |     2 +-
 ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp     |     2 +-
 ogr/ogrsf_frmts/xplane/ogrxplanedriver.cpp         |    15 +-
 ogr/ogrsf_frmts/xplane/ogrxplanelayer.cpp          |     9 +-
 ogr/ogrspatialreference.cpp                        |   141 +-
 ogr/ogrsurface.cpp                                 |    42 +-
 ogr/ogrutils.cpp                                   |   495 +-
 ogr/osr_cs_wkt.c                                   |     5 +-
 ogr/osr_cs_wkt_grammar.y                           |    37 +-
 ogr/osr_cs_wkt_parser.c                            |   309 +-
 ogr/osr_cs_wkt_parser.h                            |     1 -
 ogr/osr_tutorial.dox                               |     6 +-
 ogr/style_pen1.gif                                 |   Bin 0 -> 132 bytes
 ogr/style_pen2.gif                                 |   Bin 0 -> 117 bytes
 ogr/style_pen3.gif                                 |   Bin 0 -> 122 bytes
 ogr/style_textanchor.gif                           |   Bin 0 -> 7401 bytes
 ogr/swq.cpp                                        |   223 +-
 ogr/swq.h                                          |   112 +-
 ogr/swq_expr_node.cpp                              |   319 +-
 ogr/swq_op_general.cpp                             |   366 +-
 ogr/swq_op_registrar.cpp                           |     7 +-
 ogr/swq_parser.cpp                                 |   934 +-
 ogr/swq_parser.hpp                                 |    16 +-
 ogr/swq_parser.y                                   |   203 +-
 ogr/swq_select.cpp                                 |   421 +-
 ogr/wcts/GNUmakefile                               |    29 -
 ogr/wcts/html/client.html                          |   212 -
 ogr/wcts/html/imp_details.html                     |   249 -
 ogr/wcts/html/index.html                           |    78 -
 ogr/wcts/html/install.html                         |   236 -
 ogr/wcts/html/popup.css                            |   177 -
 ogr/wcts/html/user_form.html                       |    52 -
 ogr/wcts/makefile.vc                               |    31 -
 ogr/wcts/ogrwcts.cpp                               |  1020 -
 ogr/wcts/req_getcap.xml                            |     2 -
 ogr/wcts/req_istransformable.xml                   |    20 -
 ogr/wcts/req_nad2783tr.xml                         |    33 -
 ogr/wcts/req_remote.xml                            |    23 -
 ogr/wcts/req_transform.xml                         |    42 -
 ogr/wcts/wcts_capabilities.xml.0.1.0               |   146 -
 ogr/wcts/wctsclient.cpp                            |   520 -
 port/GNUmakefile                                   |     1 -
 port/cpl_atomic_ops.cpp                            |    18 +-
 port/cpl_atomic_ops.h                              |    20 +-
 port/cpl_config.h.in                               |    12 +
 port/cpl_config.h.vc                               |     4 +-
 port/cpl_conv.cpp                                  |   240 +-
 port/cpl_conv.h                                    |     5 +-
 port/cpl_csv.cpp                                   |     6 +-
 port/cpl_error.cpp                                 |    93 +-
 port/cpl_error.h                                   |     3 +-
 port/cpl_findfile.cpp                              |     6 +-
 port/cpl_getexecpath.cpp                           |     4 +-
 port/cpl_google_oauth2.cpp                         |     5 +-
 port/cpl_http.cpp                                  |   273 +-
 port/cpl_minixml.cpp                               |    57 +-
 port/cpl_minixml.h                                 |     5 +-
 port/cpl_minizip_ioapi.cpp                         |     3 +-
 port/cpl_minizip_unzip.cpp                         |     1 -
 port/cpl_minizip_zip.cpp                           |     5 +-
 port/cpl_multiproc.cpp                             |   736 +-
 port/cpl_multiproc.h                               |   112 +-
 port/cpl_odbc.cpp                                  |    65 +-
 port/cpl_odbc.h                                    |     5 +-
 port/cpl_port.h                                    |    24 +-
 port/cpl_progress.cpp                              |    13 +-
 port/cpl_recode_stub.cpp                           |     6 +-
 port/cpl_spawn.cpp                                 |     4 +-
 port/cpl_string.cpp                                |   489 +-
 port/cpl_string.h                                  |    22 +-
 port/cpl_strtod.cpp                                |    50 +-
 port/cpl_virtualmem.cpp                            |    14 +-
 port/cpl_virtualmem.h                              |    36 +-
 port/cpl_vsi.h                                     |     7 +-
 port/cpl_vsi_mem.cpp                               |    77 +-
 port/cpl_vsi_virtual.h                             |    15 +-
 port/cpl_vsil.cpp                                  |    18 +-
 port/cpl_vsil_abstract_archive.cpp                 |    14 +-
 port/cpl_vsil_buffered_reader.cpp                  |   100 +-
 port/cpl_vsil_cache.cpp                            |     4 +-
 port/cpl_vsil_curl.cpp                             |    43 +-
 port/cpl_vsil_curl_streaming.cpp                   |    24 +-
 port/cpl_vsil_gzip.cpp                             |   110 +-
 port/cpl_vsil_sparsefile.cpp                       |     8 +-
 port/cpl_vsil_stdin.cpp                            |     7 +-
 port/cpl_vsil_stdout.cpp                           |    60 +-
 port/cpl_vsil_subfile.cpp                          |     5 +-
 port/cpl_vsil_tar.cpp                              |    10 +-
 port/cpl_vsil_unix_stdio_64.cpp                    |    30 +-
 port/cpl_vsil_win32.cpp                            |     8 +-
 port/cpl_vsisimple.cpp                             |   102 +-
 port/cpl_xml_validate.cpp                          |    10 +-
 port/cplgetsymbol.cpp                              |     4 +-
 port/cplkeywordparser.cpp                          |     4 +-
 port/cplstring.cpp                                 |    23 +-
 port/cplstringlist.cpp                             |    49 +-
 port/vsipreload.cpp                                |   138 +-
 scripts/vagrant/gdal.sh                            |    29 +-
 scripts/vagrant/libkml.sh                          |     6 +
 scripts/vagrant/openjpeg.sh                        |     6 +
 scripts/vagrant/postgis.sh                         |     7 +
 scripts/vagrant/swig-1.3.40.sh                     |    21 +
 scripts/vce2008_wine/prepare-gdal-vce2008.sh       |     2 +-
 swig/GNUmakefile                                   |     3 +-
 swig/csharp/apps/OGRFeatureEdit.cs                 |   141 +
 swig/csharp/const/GdalConst.cs                     |    24 +
 swig/csharp/const/GdalConstPINVOKE.cs              |    72 +
 swig/csharp/const/gdalconst_wrap.c                 |   240 +
 swig/csharp/gdal/Band.cs                           |     7 +
 swig/csharp/gdal/Dataset.cs                        |    18 +
 swig/csharp/gdal/Driver.cs                         |    12 +-
 swig/csharp/gdal/Gdal.cs                           |    19 +-
 swig/csharp/gdal/GdalPINVOKE.cs                    |    21 +
 swig/csharp/gdal/RIOResampleAlg.cs                 |    22 +
 swig/csharp/gdal/RasterAttributeTable.cs           |     5 +
 swig/csharp/gdal/gdal_wrap.cpp                     |   410 +-
 swig/csharp/makefile.vc                            |     3 +-
 swig/csharp/ogr/DataSource.cs                      |    23 +
 swig/csharp/ogr/Feature.cs                         |    46 +-
 swig/csharp/ogr/FieldDefn.cs                       |    39 +
 swig/csharp/ogr/FieldSubType.cs                    |    18 +
 swig/csharp/ogr/FieldType.cs                       |     4 +-
 swig/csharp/ogr/GeomFieldDefn.cs                   |    11 +
 swig/csharp/ogr/Geometry.cs                        |    33 +
 swig/csharp/ogr/Layer.cs                           |    14 +-
 swig/csharp/ogr/Ogr.cs                             |    97 +
 swig/csharp/ogr/OgrPINVOKE.cs                      |   153 +-
 swig/csharp/ogr/Osr.cs                             |     9 +
 swig/csharp/ogr/OsrPINVOKE.cs                      |     2 +-
 swig/csharp/ogr/SpatialReference.cs                |     4 +-
 swig/csharp/ogr/ogr_wrap.cpp                       |  1651 +-
 swig/csharp/ogr/osr_wrap.cpp                       |    30 +-
 swig/csharp/ogr/wkbGeometryType.cs                 |    10 +
 swig/csharp/osr/Osr.cs                             |     9 +
 swig/csharp/osr/OsrPINVOKE.cs                      |     2 +-
 swig/csharp/osr/SpatialReference.cs                |     4 +-
 swig/csharp/osr/osr_wrap.cpp                       |    30 +-
 swig/include/Band.i                                |    89 +-
 swig/include/Dataset.i                             |   150 +-
 swig/include/Driver.i                              |     8 +-
 swig/include/MajorObject.i                         |    17 +-
 swig/include/Operations.i                          |    14 +-
 swig/include/RasterAttributeTable.i                |     6 +-
 swig/include/cpl.i                                 |    20 +-
 swig/include/csharp/ogr_csharp.i                   |     3 +-
 swig/include/csharp/typemaps_csharp.i              |     4 +-
 swig/include/gdal.i                                |   116 +-
 swig/include/gdal_array.i                          |   259 +-
 swig/include/gdalconst.i                           |    41 +-
 swig/include/java/gdal_java.i                      |    60 +-
 swig/include/java/ogr_java.i                       |    70 +-
 swig/include/java/osr_java.i                       |     5 +-
 swig/include/ogr.i                                 |   508 +-
 swig/include/ogr_error_map.i                       |     4 +-
 swig/include/osr.i                                 |    19 +-
 swig/include/perl/callback.i                       |    48 +-
 swig/include/perl/gdal_perl.i                      |  2099 ++-
 swig/include/perl/gdal_perl_rename.i               |     4 +
 swig/include/perl/ogr_perl.i                       |  3040 +--
 swig/include/perl/osr_perl.i                       |   635 +-
 swig/include/perl/typemaps_perl.i                  |   487 +-
 swig/include/php/gdal_php.i                        |     4 +-
 swig/include/php/ogr_php.i                         |     4 +-
 swig/include/python/docs/ogr_datasource_docs.i     |     2 +-
 swig/include/python/gdal_python.i                  |   178 +-
 swig/include/python/ogr_python.i                   |   155 +-
 swig/include/python/osr_python.i                   |     4 +-
 swig/include/python/python_exceptions.i            |     2 +-
 swig/include/python/typemaps_python.i              |   209 +-
 swig/include/ruby/gdal_ruby.i                      |     4 +-
 swig/include/ruby/ogr_ruby.i                       |     4 +-
 swig/include/ruby/typemaps_ruby.i                  |     4 +-
 swig/java/apps/gdalinfo.java                       |     4 +-
 swig/java/apps/ogrtindex.java                      |     4 +-
 swig/java/build.xml                                |    70 +-
 swig/java/javadoc.java                             |    48 +-
 swig/java/make_doc.sh                              |     5 +-
 swig/java/pom.xml                                  |    41 +
 swig/makefile.vc                                   |    16 +-
 swig/perl/Changes-in-the-API-in-2.0                |    45 +
 swig/perl/Doxyfile                                 |  2402 ++-
 swig/perl/GNUmakefile                              |     6 +-
 swig/perl/README                                   |    41 +-
 swig/perl/cr.dox                                   |    53 +-
 swig/perl/cv.dox                                   |    82 +-
 swig/perl/gdal_wrap.cpp                            |  3463 ++--
 swig/perl/gdalconst_wrap.c                         |   120 +
 swig/perl/index.dox                                |   114 +-
 swig/perl/lib/Geo/GDAL.dox                         |  1046 +-
 swig/perl/lib/Geo/GDAL.pm                          |  2109 ++-
 swig/perl/lib/Geo/GDAL/Const.dox                   |   274 -
 swig/perl/lib/Geo/GDAL/Const.pm                    |    24 +
 swig/perl/lib/Geo/OGR.dox                          |  1165 +-
 swig/perl/lib/Geo/OGR.pm                           |  3034 +--
 swig/perl/lib/Geo/OSR.dox                          |    97 +-
 swig/perl/lib/Geo/OSR.pm                           |   642 +-
 swig/perl/ogr_wrap.cpp                             |  7397 +++++---
 swig/perl/osr_wrap.cpp                             |   239 +-
 swig/perl/parse-for-doxygen.pl                     |   297 +
 swig/perl/t/00.t                                   |   200 +
 swig/perl/t/01.t                                   |    77 +
 swig/perl/t/02.t                                   |    71 +
 swig/perl/t/03.t                                   |   247 +
 swig/perl/t/gdal.t                                 |    67 +-
 swig/perl/t/ogr.t                                  |   212 +-
 swig/perl/t/osr.t                                  |    19 +-
 swig/php/osr.php                                   |     2 +
 swig/php/osr_wrap.cpp                              |     1 +
 swig/python/extensions/gdal_array_wrap.cpp         |   572 +-
 swig/python/extensions/gdal_wrap.cpp               |  5562 +++---
 swig/python/extensions/gdalconst_wrap.c            |    24 +
 swig/python/extensions/ogr_wrap.cpp                | 18689 +++++++++++--------
 swig/python/extensions/osr_wrap.cpp                |   115 +-
 swig/python/osgeo/gdal.py                          |   256 +-
 swig/python/osgeo/gdal_array.py                    |   183 +-
 swig/python/osgeo/gdalconst.py                     |    24 +
 swig/python/osgeo/gdalnumeric.py                   |     2 +-
 swig/python/osgeo/ogr.py                           |   462 +-
 swig/python/osgeo/osr.py                           |    11 +-
 swig/python/samples/README                         |     2 +-
 swig/python/samples/assemblepoly.py                |     6 +-
 swig/python/samples/attachpct.py                   |     3 +-
 swig/python/samples/build_jp2_from_xml.py          |   449 +
 swig/python/samples/crs2crs2grid.py                |     2 +-
 swig/python/samples/densify.py                     |     4 +-
 swig/python/samples/dump_jp2.py                    |   203 +
 swig/python/samples/fft.py                         |    36 +-
 swig/python/samples/gdal2grd.py                    |    13 +-
 swig/python/samples/gdal_lut.py                    |     2 -
 swig/python/samples/gdalcopyproj.py                |     3 +-
 swig/python/samples/gdalinfo.py                    |     8 +-
 swig/python/samples/gdalpythonserver.py            |    77 +-
 swig/python/samples/get_soundg.py                  |     5 +-
 swig/python/samples/hsv_merge.py                   |    11 +-
 swig/python/samples/jpeg_in_tiff_extract.py        |   251 +
 swig/python/samples/load2odbc.py                   |     5 +-
 swig/python/samples/loslas2ntv2.py                 |     6 +-
 swig/python/samples/ogr2ogr.py                     |     8 +-
 swig/python/samples/ogr2vrt.py                     |   125 +-
 swig/python/samples/ogr_build_junction_table.py    |     1 -
 swig/python/samples/ogr_dispatch.py                |     5 +-
 swig/python/samples/ogr_layer_algebra.py           |     4 +-
 swig/python/samples/ogrinfo.py                     |    12 +-
 swig/python/samples/ogrupdate.py                   |    10 +-
 swig/python/samples/rel.py                         |    46 +-
 swig/python/samples/tigerpoly.py                   |     3 +-
 swig/python/samples/tolatlong.py                   |    14 +-
 swig/python/samples/val_at_coord.py                |   258 +-
 swig/python/samples/val_repl.py                    |    12 +-
 swig/python/samples/validate_jp2.py                |  1228 ++
 swig/python/samples/vec_tr.py                      |     5 +-
 swig/python/samples/vec_tr_spat.py                 |     5 +-
 swig/python/scripts/epsg_tr.py                     |    18 +-
 swig/python/scripts/gcps2vec.py                    |     4 +-
 swig/python/scripts/gcps2wld.py                    |     3 +-
 swig/python/scripts/gdal2tiles.py                  |    15 +-
 swig/python/scripts/gdal_auth.py                   |     2 -
 swig/python/scripts/gdal_calc.dox                  |     2 +-
 swig/python/scripts/gdal_calc.py                   |    17 +-
 swig/python/scripts/gdal_edit.dox                  |    28 +-
 swig/python/scripts/gdal_edit.py                   |    70 +-
 swig/python/scripts/gdal_fillnodata.dox            |     2 +-
 swig/python/scripts/gdal_fillnodata.py             |    11 +-
 swig/python/scripts/gdal_merge.py                  |     9 +-
 swig/python/scripts/gdal_polygonize.dox            |     2 +-
 swig/python/scripts/gdal_polygonize.py             |     3 +-
 swig/python/scripts/gdal_proximity.dox             |    14 +-
 swig/python/scripts/gdal_proximity.py              |    10 +-
 swig/python/scripts/gdal_retile.py                 |   107 +-
 swig/python/scripts/gdal_sieve.dox                 |     2 +-
 swig/python/scripts/gdal_sieve.py                  |     6 +-
 swig/python/scripts/gdalcompare.py                 |    81 +-
 swig/python/scripts/mkgraticule.py                 |     3 +-
 swig/python/scripts/pct2rgb.py                     |     3 +-
 swig/python/setup.py                               |     7 +-
 1783 files changed, 172301 insertions(+), 75584 deletions(-)

diff --git a/.gitignore b/.gitignore
index 5f7e984..59559d4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ apps/gdalwarp
 apps/nearblack
 apps/ogr2ogr
 apps/ogrinfo
+apps/ogrlineref
 apps/ogrtindex
 apps/testepsg
 apps/gdalserver
diff --git a/COMMITERS b/COMMITERS
index 8de1528..0de6dc2 100644
--- a/COMMITERS
+++ b/COMMITERS
@@ -35,7 +35,7 @@ kmelero	      Ken Melero		   mrsid
               kmelero at sanz.com
 
 ajolma        Ari Jolma                    perl bindings
-              ari.jolma at tkk.fi
+              ari.jolma at gmail.com
 
 shalasz       Steve Halasz                 DebianGIS Packaging
               debian at adkgis.org
@@ -88,10 +88,8 @@ kosta         Dr. Konstantin Baumann       MySQL, SQLite
 rayg          Ray Gardener                 DEM drivers, leveller, terragen
               rayg at daylongraphics.com
 
-rouault       Even Rouault                 NITF/RPFTOC, BNA, GPX, ADRG,
-                                           XPlane, GeoRSS, PostgreSQL,
-                                           swig java bindings
-              even.rouault at mines-paris.org
+rouault       Even Rouault                 all
+              even.rouault at spatialys.com
 
 retsios       Bas Retsios                  ILWIS, GRIB
               retsios at itc.nl
@@ -178,6 +176,9 @@ jef           Juergen Fischer              OGR: NAS
 vmo           Vincent Mora                 wasp
               vincent.mora at oslandia.com
 
+jratike80     Jukka Rahkonen               documentation
+              jukka.rahkonen at latuviitta.fi
+
 ===============
 Past developers
 ===============
diff --git a/Doxyfile b/Doxyfile
index 1b7be94..78db20a 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -385,6 +385,11 @@ INPUT                  = port \
                          frmts/vrt \
                          doc \
 			 apps \
+                         ogr \
+                         ogr/ogrsf_frmts \
+                         ogr/ogrsf_frmts/generic \
+                         ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp \
+                         ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp \
 			 swig/python/scripts
 
 # If the value of the INPUT tag contains directories, you can use the 
diff --git a/GDALmake.opt.in b/GDALmake.opt.in
index 1b7147b..ca02225 100644
--- a/GDALmake.opt.in
+++ b/GDALmake.opt.in
@@ -37,6 +37,8 @@ LIBS	=	$(SDE_LIB) @LIBS@ $(KAK_LIBS) $(DWG_LIBS) $(CURL_LIB) \
 		$(PCIDSK_LIB) $(RASDAMAN_LIB) $(CHARLS_LIB) $(SOSI_LIB) \
 		$(OPENCL_LIB) $(JVM_LIB) $(LIBICONV) $(FGDB_LIB) $(LIBXML2_LIB)
 
+SSEFLAGS = @SSEFLAGS@
+HAVE_SSE_AT_COMPILE_TIME = @HAVE_SSE_AT_COMPILE_TIME@
 AVXFLAGS = @AVXFLAGS@
 HAVE_AVX_AT_COMPILE_TIME = @HAVE_AVX_AT_COMPILE_TIME@
 
@@ -64,7 +66,7 @@ INST_DOCS	=	@exec_prefix@/doc
 INST_MAN	=	@mandir@
 INST_HTML	=	$(HOME)/www/gdal
 
-CPPFLAGS	= @CPPFLAGS@ -I$(GDAL_ROOT)/port @EXTRA_INCLUDES@
+CPPFLAGS	= @CPPFLAGS@ -I$(GDAL_ROOT)/port @EXTRA_INCLUDES@ -DGDAL_COMPILATION
 CFLAGS		= @CFLAGS@ @C_WFLAGS@ $(USER_DEFS)
 CXXFLAGS	= @CXXFLAGS@ @CXX_WFLAGS@ $(USER_DEFS)
 LDFLAGS     = @LDFLAGS@
@@ -86,9 +88,9 @@ GDAL_INCLUDE	=	-I$(GDAL_ROOT)/port -I$(GDAL_ROOT)/gcore \
 
 # libtool targets and help variables
 LIBGDAL	:=		libgdal.la
-LIBGDAL_CURRENT	:=	19
-LIBGDAL_REVISION	:=	2
-LIBGDAL_AGE	:=	18
+LIBGDAL_CURRENT	:=	20
+LIBGDAL_REVISION	:=	0
+LIBGDAL_AGE	:=	0
 
 # native build targets and variables
 GDAL_VER	=	@GDAL_VER@
@@ -133,6 +135,10 @@ LIBS	   +=	$(MYSQL_LIB)
 #
 HAVE_HDF4     = @HAVE_HDF4@
 HDF4_INCLUDE  = @HDF4_INCLUDE@ -I$(GDAL_ROOT)/ogr
+HDF4_HAS_MAXOPENFILES = @HDF4_HAS_MAXOPENFILES@
+ifeq ($(HDF4_HAS_MAXOPENFILES),yes)
+HDF4_FLAGS=-DHDF4_HAS_MAXOPENFILES
+endif
 
 #
 # HDF5 Support.
@@ -141,6 +147,14 @@ HAVE_HDF5     = @HAVE_HDF5@
 HDF5_INCLUDE  = @HDF5_INCLUDE@ 
 
 #
+# KEA Support.
+#
+HAVE_KEA     = @HAVE_KEA@
+KEA_INC      = @KEA_INC@ 
+KEA_LIB      = @KEA_LIB@
+LIBS       +=   $(KEA_LIB)
+
+#
 # NetCDF Support.
 #
 NETCDF_ROOT = @NETCDF_ROOT@
@@ -556,16 +570,16 @@ endif # HAVE_LIBTOOL
 O_OBJ =	$(foreach file,$(OBJ),../o/$(file))
 
 ../o/%.$(OBJ_EXT):	%.c
-	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 ../o/%.$(OBJ_EXT):	%.cpp
-	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 %.$(OBJ_EXT):	%.c
-	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 %.$(OBJ_EXT):	%.cpp
-	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 #
 # default rules for handling subdirectories
diff --git a/GNUmakefile b/GNUmakefile
index 7e8580f..ca8f4dc 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -6,9 +6,7 @@ GDAL_OBJ	=	$(GDAL_ROOT)/frmts/o/*.o \
 			$(GDAL_ROOT)/port/*.o \
 			$(GDAL_ROOT)/alg/*.o
 
-ifeq ($(OGR_ENABLED),yes)
 GDAL_OBJ += $(GDAL_ROOT)/ogr/ogrsf_frmts/o/*.o
-endif
 
 include ./ogr/file.lst
 GDAL_OBJ += $(addprefix ./ogr/,$(OBJ))
@@ -112,7 +110,6 @@ GDALmake.opt:	GDALmake.opt.in config.status
 	./config.status
 
 docs:
-	(cd ogr; $(MAKE) docs)
 	(cd html; rm -f *.*)
 # Generate translated docs. Should go first, because index.html page should
 # be overwritten with the main one later
@@ -127,8 +124,12 @@ docs:
 	cp doc/images/*.* html
 	cp doc/grid/*.png html
 	cp frmts/*.html frmts/*/frmt_*.html html
-	cp frmts/wms/frmt_wms_*.xml html
-	cp frmts/wms/frmt_twms_*.xml html
+	cp frmts/wms/frmt_*.xml html
+	cp ogr/ogrsf_frmts/*/drv_*.html html
+	cp ogr/ogrsf_frmts/ogr_formats.html html
+	cp ogr/ogr_feature_style.html html
+	cp ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html html
+	cp ogr/*.gif html
 
 .PHONY: man
 
@@ -139,7 +140,6 @@ man:
 all:	default ogr-all
 
 install-docs:
-	(cd ogr; $(MAKE) install-docs)
 	$(INSTALL_DIR) $(DESTDIR)$(INST_DOCS)/gdal
 	cp html/*.* $(DESTDIR)$(INST_DOCS)/gdal
 
@@ -148,8 +148,8 @@ install-man:
 	for f in $(wildcard man/man1/*.1) ; do $(INSTALL_DATA) $$f $(DESTDIR)$(INST_MAN)/man1 ; done
 
 web-update:	docs
+	$(INSTALL_DIR) $(INST_HTML)
 	cp html/*.* $(INST_HTML)
-	(cd ogr; make web-update)
 
 install:	default install-actions
 
diff --git a/HOWTO-RELEASE b/HOWTO-RELEASE
index f98a940..bcd270b 100644
--- a/HOWTO-RELEASE
+++ b/HOWTO-RELEASE
@@ -38,7 +38,8 @@ Process :
 
 3) Update the VERSION file. 
 
-3.1) Update ./swig/python/setup.py version information. 
+3.1) Update ./swig/python/setup.py version information.
+     And the version of libgdal in ./swig/python/README.txt
 
 3.2) Update ./swig/include/perl/gdal_perl.i $VERSION and $GDAL_VERSION
 strings to current version. Kick Perl module maintainer to make a CPAN
@@ -107,8 +108,9 @@ release.
 
   % ln -sf X.Y.Z CURRENT
 
-13) Announce release to the gdal-dev at lists.maptools.org, 
-   gdal-announce at lists.osgeo.org, freegis at freegis.org and news_item at osgeo.org. 
+13) Announce release to :
+    - major release: gdal-dev at lists.osgeo.org, gdal-announce at lists.osgeo.org, news_item at osgeo.org. 
+    - bugfix release: gdal-dev at lists.osgeo.org, gdal-announce at lists.osgeo.org
 
 14) Update the freecode.com (previously freshmeat) entry for GDAL.
 
@@ -128,4 +130,138 @@ http://trac.osgeo.org/gdal/wiki/NewsAndStatus .
 19) Update Trac to mark this release milestone as "Completed", and create
     a corresponding version.  Then create a new milestone for the next release.
 
+20) Upload the new Python bindings to Pypi (requires upload rights to
+the GDAL package by one of the current owners : HowardB/FrankW/EvenR)
+( procedure taken from http://peterdowns.com/posts/first-time-with-pypi.html )
+
+a) Create a $HOME/.pypirc file :
+
+[distutils] # this tells distutils what package indexes you can push to
+index-servers = pypi
+                pypitest
+
+[pypi] # authentication details for live PyPI
+repository: https://pypi.python.org/pypi
+username: yourlogin
+password: yourpassword
+
+[pypitest] # authentication details for test PyPI
+repository: https://testpypi.python.org/pypi
+username: yourlogin
+password: yourpassword
+
+b) cd swig/python
+
+c) For trial :
+    python setup.py register -r pypitest
+    python setup.py sdist upload -r pypitest
+
+d) For real :
+    python setup.py register -r pypi
+    python setup.py sdist upload -r pypi
+
+21) Build and bundle the java bindings.
+
+a) cd swig/java
+
+b) Make any updates to java.opt that might be required for the platform. For 
+   example osx and windows users will have to change JAVA_INCLUDE to contain
+   include/darwin and include/win32 respectively. 
+
+c) Build the bindings:
+
+     make
+
+22) Build maven artifacts. NOTE: This step only works on Linux and OSX since it
+    requires a shell script to build javadocs. 
+
+    A quick one-liner for this step is:
+
+      ant maven_sign -Dgpg.key=... -Dgpg.pass=...
+
+    This will build and sign the artifacts with a single command. Read on for 
+    more details.
+
+a)  Build the maven aritfacts:
+
+     ant maven
+
+    Upon success maven artifacts should be located in the build/maven directory.
+
+b)  Sign maven artifacts with GPG. This step is required in order to deploy the
+    maven artifacts to the central Maven repository. Before this step can 
+    proceed you must set up a signing key as described here:
+
+      http://central.sonatype.org/pages/working-with-pgp-signatures.html
+
+    Each developer can use their own signing key although it is usually best to
+    avoid constantly using a different key for releases as users will need to 
+    import the public key in order to verify the artifacts.
+
+    Here are a quick set of steps to generate a signing key key.
+
+       gpg --gen-key
+       gpg --list-keys (and note the key id)
+       gpg --keyserver hkp://pool.sks-keyservers.net --send-keys <key id>
+
+    See the above link for more details.
+
+    Once a key is set up run the "maven_sign" ant target. The target takes two
+    parameters specified as system properties: 
+
+    1. gpg.key - The identifier for the signing key
+    2. gpg.pass - The passphrase for the signing key (optional)
+
+      ant maven_sign -Dgpg.key=... -Dgpg.pass=...
+
+    Upon success you should see maven artifacts along with generated signatures
+    in the build/maven directory. You will also find a file named "bundle.jar"
+    that contains all the maven artifacts with signatures. This file is what
+    will be uploaded to maven central. See the next step.
+
+23) Deploy maven artifacts to Maven central. 
+
+    NOTE: Before you can deploy to maven central you must set up an account
+    in Sonatype JIRA. That can be done here:
+
+        https://issues.sonatype.org/secure/Signup!default.jspa
+
+    Once you have an account set up you must be associated with the gdal 
+    project. Create a ticket here asking to be associated with the project:
+
+        https://issues.sonatype.org/browse/OSSRH
+
+    The entire deployment process is described in detail here:
+
+       http://central.sonatype.org/pages/manual-staging-bundle-creation-and-deployment.html
+       http://central.sonatype.org/pages/releasing-the-deployment.html
+
+    The following steps summarize the process.
+
+a) Log into the Sonatype repository manager at https://oss.sonatype.org. Use the
+   same credentials as your Sonatype JIRA account.
+
+b) Once log in select "Staging Upload" on the left hand side.
+
+c) Select "Artifact Bundle" under "Upload Mode" and then choose the "bundle.jar"
+   created in the previous Step 22. Finally "Upload Bundle" to start the upload.
+
+d) When the upload has been completed you will be notified that a staging 
+   repository has been created. Note the name of the repository. It should look
+   something like "orggdal-100x".
+
+e) From the left hand menu navigate to "Staging Repositories". In the search
+   box look for the staging repository name you noted from the previous section.
+   Or just search for "gdal". It should be obvious which repository is the 
+   current one.
+
+f) Select the staging repository. If all is well You should see the option to 
+   "Release" (Located as a button near the top of the page). If not it means 
+   there was an issue with the bundle. Consult the "Activity" tab at the bottom
+   of the page to find out why. 
+
+e) Click the "Release" button and that is it! The release should be available in
+   Maven Central shortly. You can verify this by going to search.maven.org and 
+   searching for "gdal". 
+
 
diff --git a/MIGRATION_GUIDE.TXT b/MIGRATION_GUIDE.TXT
index 4e317b9..6f7b134 100644
--- a/MIGRATION_GUIDE.TXT
+++ b/MIGRATION_GUIDE.TXT
@@ -1,5 +1,218 @@
-MIGRATION GUIDE FROM GDAL 1.X to GDAL 2.0
------------------------------------------
+MIGRATION GUIDE FROM GDAL 1.11 to GDAL 2.0
+------------------------------------------
+
+This file documents backwards incompatible changes. You are strongly encouraged
+to read the relevant RFCs for details and rationale for those changes.
+
+Changes to the Perl bindings API are listed in swig/perl/Changes-in-the-API-in-2.0.
+
+A) RFC 46: Unification of GDAL and OGR driver models
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc46_gdal_ogr_unification
+
+C++ API:
+
+  * OGRSFDriverRegistrar and OGRSFDriver are now deprecated. Use GDALDriverManager
+    and GDALDriver instead.
+
+  * The following methods from OGRSFDriverRegistrar are removed : Open(),
+    OpenShared(), ReleaseDataSource(), DeregisterDriver(), AutoLoadDrivers()
+    GetDriver() and GetDriverByName() now return a GDALDriver* instance.
+
+  * OGRDataSource::CreateLayer() specialized implementations should be renamed
+    as ICreateLayer() to benefit from layer creation options validation.
+
+  * OGRLayer::GetInfo() has been removed.
+
+  * All methods of OGRDataSource have been transfered to GDALDataset, except
+    SyncToDisk() that should now be implemented as FlushCache() in drivers.
+
+  * GDALOpenInfo::papszSiblingFiles member is now private. Use the new
+    GetSiblingFiles() method instead.
+
+  * GDALOpenInfo::fp member is replaced by fpL member of type VSILFILE*.
+
+  * OGRSFDriver::CopyDataSource() has been removed.
+
+  * GDALDriverManager::GetHome() and SetHome() have been removed.
+
+Out-of-tree drivers :
+
+  * Read RFC 46 for the needed changes. Changes in GDALOpenInfo will impact GDAL
+    drivers. GDAL drivers should also declare SetMetadataItem( GDAL_DCAP_RASTER, "YES" ).
+    OGRDataSource::CreateLayer() and SyncToDisk() changes will affect OGR drivers.
+
+Behaviour changes :
+
+  * GDALDriverManager::GetDriverCount() and GetDriver() return both raster and
+    vector drivers. The nature of a driver can be tested with the GDAL_DCAP_RASTER
+    and GDAL_DCAP_VECTOR driver metadata item.
+
+  * GetRefCount() starts at 1 for OGRDataSource instead of 0.
+
+B) RFC 49: Curve geometries
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc49_curve_geometries
+
+C/C++ API :
+
+  * Use of wkb25DBit macro is strongly discouraged, as not compatible with new
+    geometry types. Use wkbFlatten(), wkbHasZ(), wkbSetZ() instead
+  * OGRwkbGeometryType enumeration has new values.
+
+Behaviour changes :
+
+  * GML, NAS, WFS, PostGIS, VRT, GeoPackage and CSV drivers can return non-linear geometries.
+    Applications that do not wish to get such geometries can call
+    OGRSetNonLinearGeometriesEnabledFlag(FALSE)
+
+Out-of-tree drivers :
+
+  * Read RFC 49 for the needed changes. CreateFeature() and SetFeature() virtual
+    methods must be renamed ICreateFeature() and ISetFeature().
+
+C) RFC 51: RasterIO() improvements : resampling and progress callback
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc51_rasterio_resampling_progress
+
+Out-of-tree drivers :
+
+  * Read RFC 51 for the needed changes. GDALRasterBand and GDALDataset::IRasterIO()
+    take a new GDALRasterIOExtraArg* psExtraArg argument.
+    GDALRasterBand and GDALDataset::RasterIO() take a new
+    GDALRasterIOExtraArg* psExtraArg argument
+
+D) RFC 31: OGR 64bit Integer Fields and FIDs
+
+Link:http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
+
+C++ API:
+  * OGRLayer::GetFeature(), OGRLayer::DeleteFeature(), OGRLayer::SetNextByIndex() take a GIntBig instead of a long
+  * OGRFeature::GetFID() and OGRLayer::GetFeatureCount() now returns a GIntBig
+
+C API:
+  * OGR_L_GetFeature(), OGR_L_DeleteFeature(), OGR_L_SetNextByIndex() take a GIntBig instead of a long
+  * OGR_F_GetFID() and OGR_L_GetFeatureCount() now returns a GIntBig
+
+Behaviour changes :
+  * OFTInteger64 and OFTIntegerList64 can be returned whereas OGRFieldType is returned.
+
+Out-of-tree drivers :
+  * Virtual method signature change: OGRLayer::GetFeature(), OGRLayer::DeleteFeature(),
+    OGRLayer::SetNextByIndex() take a GIntBig argument instead of a long
+  * Virtual method signature change: OGRLayer::GetFeatureCount() now returns a GIntBig
+  * OGRFeature::GetFID() returns a GIntBig
+
+E) RFC 52: Strict OGR SQL quoting
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc52_strict_sql_quoting
+
+No API changes
+
+Behaviour changes:
+  * Identifiers, i.e column names or table names, can no longer be quoted with
+    single quote characters, but must use double quote characters if quoting is
+    needed, conforming with SQL 92 syntax. Failure to do the change will not
+    necessarily need to verbose errors at runtime since an expression like
+    WHERE 'a_column_name' = 'a_value' will now always evaluate to FALSE whereas
+    it would have been interpreted as WHERE "a_column_name" = 'a_value" if
+    a_column_name was indeed a column name.
+
+F) RFC 53: OGR not-null constraints and default values 
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc53_ogr_notnull_default
+
+API changes:
+    * OGRFieldDefn::SetDefault() now takes a const char* as argument.
+      OGRFieldDefn::GetDefaultRef() removed and replaced by GetDefault() that
+      returns a const char*
+
+G) RFC 54: Dataset transactions
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions
+
+Only API additions.
+
+Behaviour changes:
+  * As described in the RFC, subtle behaviour changes can be observed with the PG driver,
+    related to implicit transactions that were flushed before and are no longer now,
+    but this should hopefully be restricted to non-typical use cases. So some cases that "worked" before might
+    no longer work, but the new behaviour should hopefully be more understandable.
+
+  * The PG and SQLite drivers could accept apparently nested calls to StartTransaction()
+    (at the layer level). This is no longer possible since they are now redirected
+    to dataset transactions, that explicitely do not support it.
+
+H) RFC 55: Refined SetFeature() and DeleteFeature() semantics
+
+Link: http://trac.osgeo.org/gdal/wiki/rfc55_refined_setfeature_deletefeature_semantics
+
+Behaviour changes:
+    * Drivers will now return OGRERR_NON_EXISTING_FEATURE when calling SetFeature()
+      or DeleteFeature() with a feature id that does not exist.
+
+I) RFC 56: 
+
+Link: https://trac.osgeo.org/gdal/wiki/rfc56_millisecond_precision
+
+API/ABI changes:
+
+  * OGRField.Date structure has now a Reserved field that must be set to 0 when
+    using the OGRFeature::SetField( int i, OGRField * puValue ) method.
+    The "GByte Second" field is now a "float Second".
+
+  * OGRFeature::SetField( int i, int nYear, int nMonth, int nDay,
+                          int nHour=0, int nMinute=0, float fSecond=0.f, 
+                          int nTZFlag = 0 )
+    and the variant that take a const char* as first argument now accept a
+    floating-point number for seconds.
+
+API additions :
+
+    * OGRFeature::GetFieldAsDateTime( int i, 
+                                     int *pnYear, int *pnMonth, int *pnDay,
+                                     int *pnHour, int *pnMinute, float *pfSecond, 
+                                     int *pnTZFlag );
+
+    * OGR_F_GetFieldAsDateTimeEx() and OGR_F_SetFieldDateTimeEx() are added.
+
+Driver related changes:
+
+    * The following functions, mainly used by driver implementations, have
+      seen their signature change :
+
+        int CPL_DLL OGRParseXMLDateTime( const char* pszXMLDateTime,
+                                        OGRField* psField );
+        int CPL_DLL OGRParseRFC822DateTime( const char* pszRFC822DateTime,
+                                            OGRField* psField );
+        char CPL_DLL * OGRGetRFC822DateTime(const OGRField* psField);
+        char CPL_DLL * OGRGetXMLDateTime(const OGRField* psField);
+
+Behaviour changes:
+
+    * OGRFeature::GetFieldAsString() will now output milliseconds if a DateTime/Time
+      field has such precision.
+    * Drivers will now output milliseconds if a DateTime/Time field has such precision.
+
+J) RFC 57: 64-bit bucket count for histograms
+
+Link: https://trac.osgeo.org/gdal/wiki/rfc57_histogram_64bit_count
+
+C++ API:
+  * GDALRasterBand::GetHistogram() and GDALRasterBand::SetDefaultHistogram() take a GUIntBig* instead of a int* for bucket counts.
+  * GDALRasterBand::GetDefaultHistogram() takes a GUIntBig** instead of a int** for bucket counts.
+  * GDALRasterBand::GetRasterSampleOverview() takes a GUIntBig instead of int.
+
+C API:
+  * GDALGetRasterHistogramEx(), GDALGetDefaultHistogramEx() and GDALSetDefaultHistogramEx() are added
+    and deprecate the old interfaces.
+  * GDALGetRasterSampleOverviewEx() is added.
+
+Out-of-tree drivers :
+  * See the virtual method API changes mentionned above in the C++ API paragraph.
+
+MIGRATION GUIDE FROM GDAL 1.10 to GDAL 1.11
+-------------------------------------------
 
 This file documents backwards incompatible changes.
 
diff --git a/NEWS b/NEWS
index cd88a0c..41c0389 100644
--- a/NEWS
+++ b/NEWS
@@ -1,363 +1,880 @@
-= GDAL/OGR 1.11.2 Release Notes = 
+= GDAL/OGR 2.0 Release Notes (to r29147) =
 
-The 1.11.2 release is a bug fix release.
+***** Work in progress ***** 
 
-== Build ==
-
-  * configure: fix detection of OCI by changing linking order to please modern GCC (#5550)
-  * configure: fix test to accept MariaDB 10.X as valid MySQL (#5722)
-  * More compiler warnings addressed (#5414)
-  * Windows build of PDF: fix compilation issue with Visual Studio 2012 (#5744)
-  * Windows build: Add support for MrSID 9.1 SDK (#5814)
-  * Windows build: when building netCDF, HDF4, HDF5 as plugins, call registration of 'sub-drivers' GMT, HDF4Image and HDF5Image (#5802)
-
-== Port ==
-
- * CSV finder: Stop probing for csv/horiz_cs.csv. (#5698)
- * /vsicurl/: avoid reading after end-of-file and fix failure when reading more than 16MB in a single time (#5786)
- * CPLHexToBinary(): faster implementation (#5812)
-
-== GDAL Core and algorithms ==
-
-  * Make GetMaskBand() work with GDT_UInt16 alpha bands (#5692)
-  * Fix 32bit overflow in GDALRasterBand::IRasterIO() (#5713)
-  * RPC transformer: take into account nodata in RPC DEM (#5680)
-  * RPC transformer: add RPC_DEM_MISSING_VALUE transformer option to avoid failure when there's no DEM at the transformed point (#5730)
-  * Fix GDALSuggestedWarpOutput() wrong extent in some circumstances (e.g. dataset of big dimension with world coordinates) (#5693)
-  * Fix crash when calling GetTiledVirtualMem() on non-Linux platform (#5728)
-  * warp: fix integer overflow when reprojecting into an area with (part of) bounds completely outside of the source projection (#5789)
-  * OpenCL warper: fix OpenCL code compilation with NVIDIA OpenCL (#5772)
-
-== Utilities ==
-
-  * gdalwarp: initialize destination dataset to no_data value when automatically propagating source nodata (#5675)
-  * gdalwarp: only apply INIT_DEST when processing the first input dataset (#5387)
-  * gdaldem: avoid too large files to be produced when using -co COMPRESS=xxxx -co TILED=YES (#5678)
-
-== GDAL drivers ==
-
-GRASS driver:
- * fix compilation issues against GRASS 7 (#2953)
-
-GIF driver:
- * fix crash on images without color table (#5792)
- * validate the size of the graphic control extension block (#5793)
-
-GTiff driver:
- * Internal overviews: for near, average, gauss, and pixel interleaving, make sure to use the same code path for compressed vs uncompressed overviews (#5701)
- * allow lossless copying of CMYK JPEG into JPEG-in-TIFF (#5712)
- * when overriding metadata in update mode, make sure to clear it from PAM file (#5807)
- * fix GTiffRasterBand::DirectIO() to work with TIFF files with multiple directories (overviews, masks) (#5831)
- * Internal libtiff: partial (mostly security related fixes) upgrade to 4.0.4beta (#5830)
-
-ISIS3 driver:
- * fix to recognize IsisCube.Mapping.LatitudeType = Planetocentric (#5717)
-
-JP2OpenJPEG driver:
- * add compatibility with OpenJPEG 2.1 (#5579)
-
-JPEG driver:
- * Report non-fatal libjpeg errors as CE_Warning (or CE_Failure if GDAL_ERROR_ON_LIBJPEG_WARNING = TRUE) (#5667)
-
-KMLSuperOverlay driver:
- * remove useless and unreliable computations on floating point numbers that caused issues (truncated raster) on 32bit (#5683)
-
-USGSDEM driver:
- * take into account horizontal unit = ft in the UTM case (#5819)
-
-VRT driver:
- * fix RasterIO() to be able to fill buffers larger than 2GB (#5700, #5734)
-
-== OGR core ==
-
-  * ogr_core.h: only ignore -Wfloat-equal for IsInit() and not for the rest of the file and files that inc it (#5299)
-  * OGR layer algebra: properly initialize field maps to avoid Valgrind warnings in OGRLayer::Update() (#5778)
-
-== OGR drivers ==
-
-CSV driver:
- * fix segfault when reading allCountries.txt of geonames.org (#5668)
-
-FileGDB:
- * avoid emitting error when opening a FileGDB v9, so that OpenFileGDB can be tried to open it, in the case FileGDB is a plugin (#5674)
-
-GeoJSON driver:
- * ESRIJson: parse correctly rings of esriGeometryPolygon objects to build correct Polygon or MultiPolygon (#5538)
-
-GML driver:
- * Fix incorrect geometry cast when reading GML topogeometries (#5715)
- * Update GFS files for RUIAN (UVOH & OB) (#5770)
-
-LIBKML driver:
- * when skipped, fix segfault on second OGRRegisterAll() call (#5775)
- * do not delete the libkml singleton factory (linked to #5775)
-
-MapInfo File driver:
- * Add GDA94 datum entries to the lookup table (#5671)
- * fix segfault in CreateFeature() if passing an invalid OGR feature style string (#1209)
-
-MSSQL driver:
- * Fix recognizing image columns as geometry columns for the select layers. (#5498)
- * Fix issue when creating non-spatial table (#5696)
- * Fix to read metadata if the tables are specified in the connection string (#5796)
- * Fix invalid use of CSLAddString() in OGR MSSQL (#5810)
- * Fix crash if the tablename is specified in the connection string (#5826)
-
-MySQL driver:
- * don't be dependant on locale when building spatial filter (#5720)
-
-NAS driver:
- * make chevrons configurable by NAS_INDICATOR (#5708)
-
-OCI driver:
- * Initialize member variable to avoid UpdateLayerExtents() to be called randomly on non spatial tables (#5376)
- * fix FID (multi_load=off, OGRNullFID) - start with 1 (not -1) (#5454)
-
-OpenFileGDB driver:
- * fix ResetReading() on SQL layer with ORDER BY on indexed column (#5669)
- * add support for non spatial GDB v9 tables (#5673)
-
-PG driver:
-  * fix GDAL 1.11.0 regression that prevented to retrieve more than 500 features from a connection with tables= parameter and on a SQL result layer (#5837)
-
-SQLite/Spatialite driver:
- * remove 'T' suffix when formatting the content of a Date field (#5672)
- * fix segmentation fault when executing OGR2SQLITE_Register() when compiling against sqlite 3.8.7 (#5725)
- * make GetFIDColumn() work when run as first method call (#5781)
-
-VRT driver:
- * do not propagate ignoring of x and y cols of a PointFromColumns to the source layer (#5777)
-
-XLSX driver:
- * fix column numbering when there are more than 26 columns (#5774)
-
-== SWIG Language Bindings ==
+== In a nutshell... ==
 
-Python bindings:
-  * Fix hang of Python in case of repeated call to gdal/ogr.UseExceptions() and CE_Warning emitted (#5704)
-  * fix processing error of ogr_python.i with SWIG 3 (#5795)
-  * NUMPY driver: avoid returning CE_None in GetGeoTransform() when there's no geotransform set (#5801)
+ * New GDAL drivers:
+    - BPG: read-only driver for Better Portable Graphics format (experimental, no build support)
+    - GPKG: read/write/update capabilities in the unified raster/vector driver
+    - KEA: read/write driver for KEA format
+    - PLMosaic: read-only driver for Planet Labs Mosaics API
+    - ROI_PAC: read/write driver for image formats of JPL's ROI_PAC project (#5776)
+    - VICAR: read-only driver for VICAR format
+ * New OGR drivers:
+    - Cloudant: read/write driver for Cloudant service
+    - CSW: read-only driver for OGC CSW (Catalog Service for the Web) protocol
+    - JML: read/write driver for OpenJUMP .jml format
+    - PLScenes: read-only driver for Planet Labs Scenes API 
+    - Selaphin: read/write driver for the Selaphin/Seraphin format (#5442)
+ * Significantly improved drivers: CSV, GPKG, GTiff, JP2OpenJPEG, MapInfo file, PG, SQLite
+ * RFC 31: OGR 64bit Integer Fields and FIDs (trac.osgeo.org/gdal/wiki/rfc31_ogr_64)
+   In OGR core, OGR SQL, Shapefile, PG, PGDump, GeoJSON, CSV, GPKG, SQLite, MySQL,
+   OCI, MEM, VRT, JML, GML, WFS, CartoDB, XLSX, ODS, MSSQLSpatial, OSM, LIBKML, MITAB
+ * RFC 46: GDAL/OGR unification ( http://trac.osgeo.org/gdal/wiki/rfc46_gdal_ogr_unification)
+     - GDAL and OGR PDF drivers are unified into a single one
+     - GDAL and OGR PCIDSK drivers are unified into a single one
+ * RFC 49: Add support for curve geometries (http://trac.osgeo.org/gdal/wiki/rfc49_curve_geometries)
+   In OGR core, and GML, NAS, PostgreSQL, PGDUMP, GPKG, SQLite, VFK, VRT drivers
+ * RFC 50: Add support for OGR field subtypes (http://trac.osgeo.org/gdal/wiki/rfc50_ogr_field_subtype)
+   In OGR core, OGR SQL, swig bindings, CSV, FileGDB, GeoJSON, GML, GPKG, OpenFileGDB, PG, PGDump, SQLite, VRT
+ * RFC 51: RasterIO() improvements : resampling and progress callback (http://trac.osgeo.org/gdal/wiki/rfc51_rasterio_resampling_progress)
+ * RFC 52: Stricter SQL quoting (http://trac.osgeo.org/gdal/wiki/rfc52_strict_sql_quoting)
+ * RFC 53: OGR not-null constraints and default values (http://trac.osgeo.org/gdal/wiki/rfc53_ogr_notnull_default)
+   In OGR core, OGR SQL, PG, PGDump, CartoDB, GPKG, SQLite, MySQL, OCI, VRT, GML, WFS, FileGDB, OpenFileGDB and MSSQLSpatial
+ * RFC 54: Dataset transactions (https://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions)
+   In PG, GPKG, SQLite, FileGDB and MSSQLSpatial
+ * RFC 55: refined SetFeature() and DeleteFeature() semantics.
+   In GPKG, Shape, MySQL, OCI, SQLite, FileGDB, PG, CartoDB, MITAB and MSSQL
+ * RFC 56: OFTTime/OFTDateTime millisecond accuracy ( https://trac.osgeo.org/gdal/wiki/rfc56_millisecond_precision )
+ * RFC 57: 64bit histogram bucket count ( https://trac.osgeo.org/gdal/wiki/rfc57_histogram_64bit_count )
+ * Upgrade to EPSG v8.5 database
+ * Fix locale related issues when formatting or reading floating point numbers (#5731)
 
+== New installed files ==
+ * data/gdalvrt.xsd: XML schema of the GDAL VRT format
 
-= GDAL/OGR 1.11.1 Release Notes = 
+== Backward compatibility issues ==
 
-The 1.11.1 release is a bug fix release.
+See MIGRATION_GUIDE.TXT
 
-'''Security announcement'''
+== GDAL/OGR 2.0 - General Changes ==
 
-Robert Coup has noticed a security problem with the OGR WCTS service.
-This code is not part of the standard build process, nor usually packaged by binary distributions,
-so most users should not be affected by this problem unless they have compiled it by themselves.
-This code still lies in the ogr/wcts directory from the source distribution of the 1.11 branch.
-For more details, you can read the "Security Concern" paragraph at http://svn.osgeo.org/gdal/spike/wcts/html/index.html
+Build(Unix):
+ * Fix for cpl_recode_iconv.cpp compilation error on freebsd 10 (#5452)
+ * Fix pthread detection for Android
+ * Fix in Armadillo detection test (#5455)
+ * Fix detection of OCI by changing linking order to please modern GCC (#5550)
+ * Fix test to accept MariaDB 10.X as valid MySQL (#5722)
+ * Make sure $(GDAL_INCLUDE) is first to avoid being confused by GDAL headers of a previous version elsewhere in the include path (#5664)
+ * Always use stat rather than stat64 for Mac OSX in AC_UNIX_STDIO_64. (#5780, #5414).
+ * Add support for ECW SDK 5.1 (#5390)
 
-== Build ==
+Build(Windows):
+ * PDF: fix compilation issue with Visual Studio 2012 (#5744)
+ * PDF: Add support to compile the pdf driver as plugin (#5813)
+ * Add support for MrSID 9.1 SDK (#5814)
+ * when building netCDF, HDF4, HDF5 as plugins, call registration of 'sub-drivers' GMT, HDF4Image and HDF5Image (#5802)
 
+Build(all):
+ * Ruby bindings: disable autoconf and makefile support (#5880)
  * Fix compilation errors with json-c 0.12 (#5449)
- * configure: fix for cpl_recode_iconv.cpp compilation error on freebsd 10 (#5452)
  * Fix compilation error in alg/gdalgrid.cpp when AVX is available, but not SSE (#5566)
- * Fix wrong include order in ingr and nitf subdirs w.r.t internal libtiff (#5644)
- * Add CPL_UNUSED for gcc >= 4 (#5414)
 
-== Port ==
+== GDAL 2.0 - Overview of Changes ==
 
+Port:
+ * Introduce a more generic lock API (recursive mutex, adaptive mutex, spinlock)
+ * Add types for CPLMutex, CPLCond and CPLJoinableThread (only enforced in -DDEBUG mode)
+ * Add CPLGetPhysicalRAM() and CPLGetUsablePhysicalRAM()
  * CPLSpawn() on Windows: quote arguments with spaces in them (#5469)
  * /vsigzip/: avoid infinite loop when reading broken .gml.gz file (#5486)
- * /vsizip/: fix bug that caused premature end of file condition with some read patterns (#5530)
- * /vsizip/: on >4GB zips: accept .zip declare 0 disks (#5615)
- * Fix stack corruption upon thread termination with CPLSetThreadLocalConfigOption on Windows 32 bit (#5590, reported by cleo)
- * cpl_http.cpp: truly set CURLOPT_NOSIGNAL if available (#5568)
-
-== GDAL Core ==
+ * /vsizip/ : fix bug that caused premature end of file condition with some read patterns (#5530)
+ * /vsizip/ on >4GB zips: accept .zip declare 0 disks (#5615)
+ * /vsitar/: remove useless validation test that prevents from opening valid .tar files (#5864)
+ * /vsistdout/: add VSIStdoutSetRedirection() for compatibility with MapServer FCGI (https://github.com/mapserver/mapserver/pull/4858)
+ * /vsimem/: update st_mtime and return it with Stat()
+ * /vsimem/: in update mode, when seeking after end of file, only extend it if a write is done
+ * /vsimem/: Make Rename() on a directory also rename filenames under that directory (#5934)
+ * /vsicurl/: avoid reading after end-of-file and fix failure when reading more than 16MB in a single time (#5786)
+ * Allow CPL_VSIL_CURL_ALLOWED_EXTENSIONS to be set to special value {noext}
+ * VSIWin32Handle::Flush(): no-op implementation is sufficient to offer same guarantee as POSIX fflush() (#5556)
+ * Unix VSIL: reset eof in all cases in Seek()
+ * Windows plugins: complementary fix to #5211 to avoid error dialog box when there are dependency problems (#5525)
+ * Fix VSIReadDirRecursive() recursing on the parent or current directory (#5535)
+ * cpl_error: obfuscate password
+ * HTTP: set CURLOPT_NOSIGNAL if available (#5568)
+ * Add COOKIE option to CPLHTTPFetch() (#5824)
+ * CPLHTTPFetch(): add retry logic in case of 502, 503 and 504 errors with the GDAL_HTTP_MAX_RETRY (default: 0)and GDAL_HTTP_RETRY_DELAY (default: 30 s) config options (#5920)
+ * Fix stack corruption upon thread termination with CPLSetThreadLocalConfigOption on Windows 32 bit (#5590)
+ * cpl_csv: Stop probing for csv/horiz_cs.csv. (#5698)
+ * vsipreload: implement clearerr() and readdir64() (#5742)
+ * CPLsetlocale(): return a string that is thread-locale storage to avoid potential race in CPLLocaleC::CPLLocaleC() (#5747)
+ * CPLHexToBinary(): faster implementation (#5812)
 
+Core:
+ * Add imagery (satellite or aerial) metadata support (DigitalGlobe, GeoEye, OrbView, Landsat, Pleiades, Resurs-DK1).
+ * Reduce lock contention on the global cache mutex and make it possible to use spin lock instead with GDAL_RB_LOCK_TYPE=SPIN
+ * EXIF reader: fix memleak in error code path
  * EXIF reader: add missing validation for some data types (#3078)
- * Fix segfault in GDALPamRasterBand::SerializeToXML() when saving an empty RAT (#5451)
- * Windows plugin: complementary fix to #5211 to avoid error dialog box when there are dependency problems (#5525)
- * RPC transformer with DEM: fix near interpolation (patch by liminlu0314, #5553)
+ * Fix crash in GDALPamRasterBand::SerializeToXML() when saving an empty RAT (#5451)
+ * ComputeStatistics(): use Welford algorithm to avoid numerical precision issues when computing standard deviation (#5483)
+ * Fix crashing issue with TLS finalization on Unix (#5509)
+ * GDALJP2Metadata::CreateGMLJP2(): use EPSGTreatsAsLatLong() and EPSGTreatsAsNorthingEasting() to determine if axis swapping is needed (#2131)
+ * GDALJP2AbstractDataset: implement GetFileList() to report .wld/.j2w if used
+ * GMLJP2: be robust when parsing GMLJP2 content that has nul character instead of \n (#5760)
+ * GMLJP2: add missing rangeParameters element to validate against GMLJP2 schema (#5707)
+ * GMLJP2: SRS export as GML: output XML definition of a SRS as a GML 3.1.1 compliant Dictionary (#5697)
+ * GMLJP2: when setting GDAL_JP2K_ALT_OFFSETVECTOR_ORDER=TRUE write it as a XML comment so that we can interpret the OffsetVector elements correctly on reading
+ * GMLJP2: when parsing a GMLJP2 box, accept srsName found on gml:RectifiedGrid if not found on origin.Point, so as to be compatible with the example of DGIWG_Profile_of_JPEG2000_for_Georeferenced_Imagery.pdf (#5697)
+ * GMLJP2: add compatibility with GMLJP2 v2.0 where SRS is expressed as CRS URL
+ * JP2Boxes: add null terminated byte to GDAL XML, XML or XMP boxes
+ * Add GDALGetJPEG2000Structure() (#5697)
+ * GDALMultiDomainMetadata::XMLInit(): when importing XML metadata, erase the existing document to replace it with the new one
+ * Metadata: fix correct sorting of StringList / metadata (#5540, #5557)
+ * Make GetMaskBand() work with GDT_UInt16 alpha bands (#5692)
+ * Fix 32bit overflow in GDALRasterBand::IRasterIO() and  GDALDataset::BlockBasedRasterIO() (#5713)
+ * RasterIO: small optimization in generic RasterIO() implementation to avoid loading partial tiles at right and/or bottom edges of the raster when they are going to be completely written 
+ * Fix crash when calling GetTiledVirtualMem() on non-Linux platform (#5728)
+ * Add GDAL_OF_INTERNAL flag to avoid dataset to be registered in the global list of open datasets
+ * GDALDriver::CreateCopy(): accept _INTERNAL_DATASET=YES as creation option, so as to avoid the returned dataset to be registered in the global list of open datasets
+ * Implement GDALColorTable::IsSame()
+ * GDALPamDataset: do not serialize dataset metadata unless it has been set through GDALDataset::SetMetadata() or GDALDataset::SetMetadataItem()
+ * GDALLoadTabFile: add TAB_APPROX_GEOTRANSFORM=YES/NO configuration option to decide if an approximate geotransform is OK (#5809)
+ * Optimize copy efficiency from tiled JPEG2000 images
+ * Avoid fetching remote non-existing resources for sidecar files, when using /vsicurl/ with a URL that takes arguments (#5923)
+
+Algorithms:
+ * RPC transformer: fix near interpolation in RPC DEM (#5553)
+ * RPC transformer: take into account nodata in RPC DEM (#5680)
+ * RPC transform: add RPC_DEM_MISSING_VALUE transformer option to avoid failure when there's no DEM at the transformed point (#5730)
+ * TPS transformer: fix crash if the forward or backward transform cannot be computed (#5588)
  * OpenCL warper: remove unused variable in bilinear resampling that can cause compilation error (#5518)
- * GDALCreateTPSTransformer(): fix crash if the forward or backward transform cannot be computed (#5588)
+ * OpenCL wraper: fix code compilation with NVIDIA OpenCL (#5772)
+ * Overview: Fix and speed-up cubic resampling in overview computation to take into account scaling factor (#5685)
  * Overview: ignore alpha=0 values when compute an average overview of an alpha band; and also avoid memory errors when calling GetMaskBand()/GetMaskFlags() after overview computation if GetMaskXXX() has been called before (#5640)
+ * Overview: avoid crash when computing overview with a X dimension much smaller than Y dimension (#5794)
+ * GDALRegenerateOverviewsMultiBand(): fix stride calculation error with certain raster dimensions (#5653)
+ * Warper: numerous speed optimizations (SSE2 specific code, more fast code paths, ...)
+ * Warper: fix Cubic and Bilinear resampling to work correctly with downsizing (#3740)
+ * Warper: fix and optimize CubicSpline
+ * Warper: regardless of the warping memory limit, add heuristics to determine if we must split the target window in case the 'fill ratio' of the source dataset is too low (#3120)
+ * Warper: accept warping options METHOD=NO_GEOTRANSFORM and DST_METHOD=NO_GEOTRANSFORM to run gdalwarp on ungeoreferenced images
+ * Warper: fix GDALSuggestedWarpOutput() wrong extent in some circumstances (e.g. dataset of big dimension with world coordinates) (#5693)
+ * Warper: fix integer overflow when reprojecting into an area with (part of) bounds completely outside of the source projection (#5789)
+ * Warper: add min,max,med,q1 and q3 resampling algorithms (#5868)
+ * Warper: add a SRC_COORD_PRECISION warping option to help getting more reproducable output when -wm parameter changes (#5925)
+ * GDALReprojectImage(): takes into account nodata values set on destination dataset
+ * Median cut and dithering: optimizations and enhancements to deal with 8-bit precision (only if using internal interface for now)
+ * rasterfill: add option to specify driver to use for temporary files
+ * Polygonize: speed optimization: do not try to build the polygon for pixels that are masked by the mask band (i.e. alpha, nodata, etc...). Can considerably speed-up processing when the nodata outline forms a very complex polygon
 
-== Utilities ==
-
+Utilities:
+ * gdalinfo: display extra metadata domains attached to band, and refactor code a bit (#5542)
+ * gdalinfo: add -oo option per RFC 46
+ * gdaladdo: add -oo option per RFC 46
+ * gdaladdo: add warning when subsampling factor 1 specified
+ * gdal_translate: add -oo option per RFC 46
+ * gdal_translate: add -r and -tr options per RFC 51
+ * gdal_translate: add a -projwin_srs option to be able to express -projwin coordinates in another SRS than the one of the dataset
+ * gdal_translate: support -'outsize avalue 0' or '-outsize 0 avalue' to preserve aspect ratio
+ * gdal_translate: avoid preserving statistics when changing data type in situations where clamping can occur
+ * gdal_translate: adjust RPC metadata (pixel/line offset/scale) when subsetting/rescaling, instead of just discarding it
+ * gdal_translate: don't recopy band units if rescaling or unscaling is involved (#3085)
+ * gdal_translate: increase GDAL_MAX_DATASET_POOL_SIZE default value to 450. (#5828)
+ * gdalwarp: add -oo option per RFC 46
+ * gdalwarp: add -te_srs option to specify -te in a SRS which isn't the target SRS
+ * gdalwarp: add a -ovr option to select which overview level to use, and default to AUTO. Also add a generic OVERVIEW_LEVEL=level open option, and make it available in standard VRT (#5688)
+ * gdalwarp: initialize destination dataset to no_data value when automatically propagating source nodata (#5675)
+ * gdalwarp: only apply INIT_DEST when processing the first input dataset (#5387)
+ * gdalwarp: increase GDAL_MAX_DATASET_POOL_SIZE default value to 450. (#5828)
+ * gdalwarp: do not preserve NODATA_VALUES metadata item in output dataset if adding an alpha channel with -dstalpha
+ * gdalwarp: fix '-dstnodata none' to avoid read of uninitialized values (#5915)
+ * gdaldem: avoid too large files to be produced when using -co COMPRESS=xxxx -co TILED=YES (#5678)
+ * gdallocationinfo: add -oo option
+ * gdaltransform: add a -output_xy flag to restrict output coordinates to 'x y' only
+ * gdal_grid: use nodata= parameter in the algorithm string to determine the nodata value to set on the band (#5605)
+ * gdalbuildvrt: add a -r option to specify the resampling algorithm
+ * gdal_edit.py: add -unsetstats option (and fix -a_nodata to run on all bands, ant not just first one)
+ * gdal_edit.py: add -stats and -approx_stats flags (patch by mwtoews, #5805)
+ * gdal_edit.py: change -mo add metdata to existing one; add new option -unsetmd to clean existing metadata
+ * gdal_edit.py: add -oo to specify open options
+ * gdal_retile.py: fix to make it work with input images of different resolutions (#5749)
+ * gdal_retile.py: implement progress bar (#5750)
+ * gdal_merge.py: add timing information in verbose output
  * gdal2tiles.py: fix inverted long/lat in BoundingBox and Origin elements of tilemapresource.xml (#5336)
- * pct2rgb.py: make it work (again) with color tables with less than 256 entries (#5555)
+ * pct2rgb.py: make it work with color tables with less than 256 entries (#5555)
+ * gdal_fillnodata.py: FillNodata: copy no data value to destination band when creating a dataset (if available) (#4625)
+ * gdal_proximity.py: add a -use_input_nodata flag
+ * gdalcompare.py: add options to supress selected comparisons
+ * gdalcompare.py: takes into account differences in overview bands
+ * gdalcompare.py: compute difference on float to avoid integer underflow
+ * epsg_tr.py: change to make it possible to export GEOCCS and COMPD_CS to proj.4 epsg and PostGIS spatial_ref_sys.sql files
+
+Python samples:
+ * Added swig/python/samples/jpeg_in_tiff_extract.py
+ * Added dump_jp2.py
+ * Added validate_jp2.py
+ * Added build_jp2.py
+ * tolatlong.py: report error when operating on a non-georeferenced dataset
 
-== GDAL drivers ==
+AAIGRID:
+ * Fix formatting string (#5731)
 
 BAG driver:
- * change nodata value for uncertainty band to 1e6; and do not expose wrong values of minimum and maximum of uncertainty band (#5482)
+ * change nodata value for uncertainty band to 1e6 (#5482)
+
+BMP driver:
+ * backout r17065 change that infered georeferencing based on the resolution information in the BMP header (#3578)
 
 DIMAP driver:
- * DIMAP 2: handle the case where the Raster_Data element is in main file; fix to extract geodetic SRS; fix to extract geotransform from JPEG2000 file if not available in XML (#5018, #4826)
+ * DIMAP 2: handle the case where the Raster_Data element is in main file (#5018, #4826)
+ * DIMAP 2: fix to extract geodetic SRS (#5018, #4826)
+ * DIMAP 2: fix to extract geotransform from JPEG2000 file if not available in XML (#5018, #4826)
+
+DDS driver:
+ * Add ETC1 compression format support
+ * Header correction for worldwind client
+
+ECW driver:
+ * correctly assign color interpretation to bands if order is unusual
 
 ENVI driver:
- * avoid generating potentially corrupted .hdr files when opening in update mode; Write 'Arbitrary' instead of 'Unknown' as the projection name for an undefined SRS; when writing, consider that LOCAL_CS SRS is like ungeoreferenced (#5467)
+ * avoid generating potentially corrupted .hdr files when opening in update mode; Write 'Arbitrary' instead of 'Unknown' as the projection name for an undefined SRS (#5467)
+ * when writing, consider that LOCAL_CS SRS is like ungeoreferenced (#5467)
 
 ERS driver:
  * reset RasterInfo.RegistrationCellX/Y if setting a new geotransform on an updated .ers file (#5493)
+ * fix SetProjection() (#5840)
 
-MBTILES driver:
- * better detection of 4 bands dataset (if sample tile is a paletted PNG with transparency) (#5439)
- * take into account alpha component of color table in RasterIO() (#5439)
- * avoid wrong detection of 3 bands when finding paletted PNG in /vsicurl mode (#5439)
+GeoRaster driver:
+ * fix Oracle SRID authority (#5607)
+ * fix user-defined SRID issue (#5881)
+ * new SRID search (#5911)
 
 GIF driver:
  * add compatibility with giflib 5.1 (#5519)
+ * fix crash on images without color table (#5792)
+ * fix reading of interlaced images with giflib >= 5.0
+ * validate the size of the graphic control extension block (#5793)
 
-GeoRaster driver:
- * fix Oracle SRID authority (#5607)
+GRASS driver:
+ * GRASS 7.0.0 support (#5852)
 
 GRIB driver:
- * avoid divide by zero while setting geotransform on 1xn or nx1 grib file (#5532)
+ * avoid divide by zero while setting geotransform on 1xn or nx1 grib file (#5532à
+ * allow writing PDS template numbers to all bands (#5144)
 
 GTiff driver:
- * Internal libtiff: fix segfault on invalid JPEG-in-TIFF (http://bugzilla.maptools.org/show_bug.cgi?id=2471)
+New capabilities:
+ * for JPEG-in-TIFF, use JPEG capabilities to decompress fast overview levels 2,4 and 8, to generate 'hidden' overviews used by RasterIO()
+ * add DISCARD_LSB creation option (lossy compression) to be best used with PREDICTOR=2 and LZW/DEFLATE compression
+ * when GTIFF_DIRECT_IO=YES is enabled, performance improvements in GTiffRasterBand::DirectIO() with Byte dataset and Byte buffer
+ * implement dataset DirectIO()
+ * add GTIFF_VIRTUAL_MEM_IO=YES/NO/IF_ENOUGH_RAM configuration option so that RasterIO() can rely on memory-mapped file I/O (when possible and supported by the OS)
+ * support reading and created streamable files
+ * for JPEG-compressed TIFF, avoid quantization tables to be emitted in each strip/tile and use optimized Huffman coding by default
+ * avoid SetNoDataValue() to immediately 'cryztalize' the IFD
  * allow unsetting TIFFTAG_SOFTWARE, TIFFTAG_DOCUMENTNAME, etc... by removing them from metadata list or passing None as a value of SetMetadataItem() (#5619)
- * fix to make band.SetMetadata({}) clear band metadata (#5628)
+ * allow lossless copying of CMYK JPEG into JPEG-in-TIFF
+ * set alpha on target by default when translating from Grey+Alpha
+ * Internal overviews: for near, average, gauss and cubic, and pixel interleaving, make sure to use the same code path for compressed vs uncompressed overviews (#5701)
+ * add RPCTXT=YES creation option to write sidecar _RPC.TXT file
+ * internal libtiff updated to upstream libtiff 4.0.4beta
+ * internal libgeotiff updated to upstream libgeotiff SVN head
+ * speed optimization on write (at least in Vagrant) (#5914)
+ * use importFromEPSG() when ProjectedCSTypeGeoKey is available (#5926)
+ * on reading better deal with a few ESRI formulations of WebMercator (#5924)
+Fixes:
+ * when overriding metadata in update mode, make sure to clear it from PAM file (#5807)
+ * fix handling of Mercator_2SP (#5791)
+ * avoid TIFF directory to be written (at end of file) when creating a JPEG-in-TIFF file
+ * for a paletted TIFF with nodata, set the alpha component of the color entry that matches the nodata value to 0, so as gdal_translate -expand rgba works properly
+ * fix to make band SetMetadata(NULL) clear band metadata (#5628)
+ * fix error message when requesting a non existing directory
+ * check data type with PHOTOMETRIC=PALETTE
+ * be robust to out-of-memory conditions with SplitBand and SplitBitmapBand
+ * avoid using optimized JPEG --> JPEG-in-TIFF path if INTERLEAVE=BAND is specified with a 3-band JPEG
+ * to make Python bindings happy, avoid emitting CE_Failure errors due to libtiff errors when we still manage to open the file (#5616)
+ * avoid crash when reading GeoTIFF keys if the stored key type isn't the one expected
+ * make sure to call libgeotiff gtSetCSVFilenameHook() method when linking against external libgeotiff
+ * avoid/limit DoS with huge number of directories
+ * clean spurious spaces when reading values from _RPC.TXT
+ * serialize RPC in PAM .aux.xml file if using PROFILE != GDALGeoTIFF and RPB = NO
+ * fix clearing of GCPs (#5945)
+
+GRASS driver:
+ * fix compilation issues against GRASS 7
+
+HDF4 driver:
+ * Add configuration support to be able to open more files simultaneously
+ * Add class suffix to the parameter name when parsing HDF-EOS objects.
+
+HDF5 driver:
+ * avoid opening BAG files in the case HDF5 and BAG are plugins, and HDF5 is registered before BAG
 
 HFA driver:
  * fix recognition of Hotine Mercator Azimuth Center in Imagine format (and Swisstopo GeoTIFF) (#5551)
+ * fix various hangs on invalid files
+
+HTTP driver/wrapper:
+  * make it work with vector files too
+  * fix handling of non VSI*L file on Windows
+
+IRIS driver:
+ * add support for the SHEAR data type (#5549)
+
+JPEG2000 driver:
+ * do expansion of 1-bit alpha channel to 8-bit by default. Can be controlled with the 1BIT_ALPHA_PROMOTION open option (default to YES)
+ * add GMLJP2 creation option
+ * add GMLJP2V2_DEF creation option to create a GMLJP2 v2 box
+ * Add capability of reading GMLJP2 v2 embedded feature collections and annotations
+ * Add read/write support for RPC in GeoJP2 box (#5948)
+
+JP2ECW driver:
+ * add metadata about JPEG2000 codestream and boxes (#5408)
+ * Add 1BIT_ALPHA_PROMOTION open option (default to YES) to control expansion of 1-bit alpha channel to 8-bit
+ * correctly assign color interpretation to bands if order is unusual
+ * add WRITE_METADATA and MAIN_MD_DOMAIN_ONLY creation options to write GDAL metadata, JP2 XML boxes or XMP box
+ * add GMLJP2V2_DEF creation option to create a GMLJP2 v2 box
+ * Add capability of reading GMLJP2 v2 embedded feature collections and annotations
+ * Add read/write support for RPC in GeoJP2 box (#5948)
 
 JP2KAK driver:
+ * Compatibility with Kakadu v7.5 (#4575, #5344)
+ * Handle Kakadu version 7 allocator.finalize (#4575)
  * fix bug in vsil_target::end_rewrite() that prevented TLM index to be generated (#5585)
+ * Add FLUSH in creation option XML (#5646)
+ * Do expansion of 1-bit alpha channel to 8-bit by default. Can be controlled with the 1BIT_ALPHA_PROMOTION open option (default to YES)
+ * add GMLJP2V2_DEF creation option to create a GMLJP2 v2 box
+ * Add capability of reading GMLJP2 v2 embedded feature collections and annotations
+ * Add read/write support for RPC in GeoJP2 box (#5948)
+
+JP2OpenJPEG driver:
+ * Support writing arbitrary number of bands. (#5697)
+ * Generate cdef box when transparency is needed. Add NBITS, 1BIT_ALPHA and ALPHA creation options (#5697)
+ * add INSPIRE_TG (for conformance with Inspire Technical Guidelines on Orthoimagery), PROFILE, JPX and GEOBOXES_AFTER_JP2C creation option (#5697)
+ * add GMLJP2V2_DEF creation option to create a GMLJP2 v2 box
+ * Add capability of reading GMLJP2 v2 embedded feature collections and annotations
+ * add PRECINCTS creation option (#5697)
+ * allow several quality values to be specified with QUALITY creation option. Add TILEPARTS, CODEBLOCK_WIDTH and CODEBLOCK_HEIGHT options (#5697)
+ * support reading&writing datasets with unusual order of band color interpretation (#5697)
+ * add WRITE_METADATA and MAIN_MD_DOMAIN_ONLY creation options to write GDAL metadata, JP2 XML boxes or XMP box (#5697)
+ * add support for reading/writing/updating IPR box (from/into xml:IPR metadata domain) (#5697)
+ * add YCC creation option to do RGB->YCC MCT, and turn it ON by default (#5634)
+ * add USE_SRC_CODESTREAM=YES experimental creation option, to reuse the codestream of the source dataset unmodified
+ * support reading & writing images with a color table (#5697)
+ * support update mode for editing metadata and georeferencing (#5697)
+ * add compatibility with OpenJPEG 2.1 (#5579)
+ * fix warning when reading a single tile image whose dimensions are not a multiple of 1024 (#5480)
+ * Add 1BIT_ALPHA_PROMOTION open option (default to YES) to control expansion of 1-bit alpha channel to 8-bit
+ * Add read/write support for RPC in GeoJP2 box (#5948)
+ * limit number of file descriptors opened
+
+JPEG driver:
+ * use EXIF overviews if available
+ * add EXIF_THUMBNAIL creation option to generate an EXIF thumbnail
+ * use optimized Huffman coding to reduce file size
+ * add support for reading and writing COMMENT
+ * optimize whole image reading with dataset IRasterIO()
+ * report non-fatal libjpeg errors as CE_Warning (or CE_Failure if GDAL_ERROR_ON_LIBJPEG_WARNING = TRUE) (#5667)
+ * in compressor, increase default val of max_memory_to_use to 500MB
 
 JPIPKAK driver:
- * avoid symbol collision with kdu_cpl_error_message from JP2KAK driver (#4865)
+ * avoid symbol collision with kdu_cpl_error_message from JP2KAK driver
+ * reset the bNeedReinitialize flag after a timeout (#3626)
+
+KMLSuperOverlay driver:
+ * fix truncated raster on 32 bit builds (#5683)
+
+L1B driver:
+ * add support for little-endian LRPT datasets (#5645)
+ * expose band mask when there are missing scanlines (#5645)
+ * expose WGS-84 or GRS-80 datum if read from header record (#5645)
+
+MAP driver:
+ * retrieve the image filename in a case insensitive way (#5593)
+
+MBTiles driver:
+ * better detection of 4 bands dataset and take into account alpha component of color table in RasterIO() (#5439)
+ * avoid wrong detection of 3 bands when finding paletted PNG in /vsicurl mode (#5439)
+ * fix dimension computation when opening a single tile dataset
+ * better computation of extent from min/max of tile coordinates, for a single zoom level
+ * use standard EPSG:3857 origin to fix a ~8m shift (#5785)
+
+MEM driver:
+ * implement optimized versions of raster band and dataset IRasterIO()
 
 MSG driver:
  * fix compilation problem (#5479)
+ * fix memory leaks (#5541)
+
+NetCDF driver:
+ * Force block size to 1 scanline for bottom-up datasets if nBlockYSize != 1 (#5291)
+ * Fix computation of inverse flattening (#5858)
+ * In case the netCDF driver is registered before the GMT driver, avoid opening GMT files
+
+NGSGEOID driver:
+ * make Identify() more restrictive
 
 NITF driver:
+ * deal correctly with JPEG2000 NITF datasets that have a color table inboth Image Subheader and JP2 boxes, and for drivers that don't do color table expension
  * HISTOA TRE: put definition of TRE in conformance with STDI-0002 (App L page 14) and STDI-0006 (Page 57) (#5572)
 
-OpenJPEG driver:
- * fix warning when reading a single tile image whose dimensions are not a multiple of 1024 (#5480)
+OGDI driver:
+ * Remove OGDIDataset::GetInternalHandle (#5779).
 
-OZI Map driver:
- * retrieve the image filename in a case insensitive way (#5593)
+OZI driver:
+ * remove .map header detection from Identify() since this is actually handled by the MAP driver
+
+PCIDSK driver:
+ * close dataset in case of exception in PCIDSK2Dataset::LLOpen() (#5729)
+
+PCRaster driver:
+ * Allign libcsf code with PCRaster raster format code (#5843)
+ * Implement Create() (#5844)
 
 PDF driver:
- * fix compilation problem with Podofo on Windows (#5469)
+ * add compatibility with Poppler 0.31.0
+ * in the OGC Best practice case, switch rotational terms of the geotransform matrix (gt[2] and gt[4])
+ * in the OGC Best practice case, handle rotations of 90 and 270 degrees.
+ * advertize LAYERS metadata domain
+ * deal with OHA- datum (Old Hawaiian)
+ * fix compilation problem with Podofo on Windows (patch by keosak, #5469)
+ * add sanity check on page count
+
+PDS driver:
+ * Added support for SPECTRAL_QUBE objects used e.g. by THEMIS instrument of Mars Odyssey spacecraft.
+
+PNG driver:
+ * add creation options to write metadata in TEXT/iTXt chunks
+ * optimize whole image reading with dataset IRasterIO()
+ * Internal libpng: update to 1.2.52
 
-PostGISRaster driver:
+PostgisRaster driver:
  * Fix read of metadata for tables with multiple raster cols (#5529)
 
+Rasterlite driver:
+ * accept space in filename
+
 VRT driver:
+ * VRT warp: make selection of source overview work (#5688)
+ * VRT warp: expose as many overviews in warped dataset as there are in source dataset, and make warped VRT honour -ovr parameter of gdalwarp (#5688)
  * make sure nodata value set on VRT raster band is taken into account in statistics computation (#5463)
  * fix ComputeStatistics() on VRT that are a sub-window of source dataset (#5468)
  * VRT raw: fix corrupted serialization on Windows (#5531)
- * Implement heuristics to determine if GetMinimum()/GetMaximum() should use the implementation of their sources of not. Can be overriden by setting VRT_MIN_MAX_FROM_SOURCES = YES/NO (#5444)
+ * implement heuristics to determine if GetMinimum()/GetMaximum() should use the implementation of their sources of not. Can be overriden by setting VRT_MIN_MAX_FROM_SOURCES = YES/NO (#5444)
+ * VRT warp: avoid to warp truncated blocks at right/bottom edges, so that scale computation is correct
+ * fix RasterIO() to be able to fill buffers larger than 2GB (#5700)
+ * fix performance problem when serializing into XML a big number of sources
+ * do not output empty <Metadata> node on VRTDataset and VRTRasterBand elements
+ * fix rounding of output window size on VRTSimpleSource (#5874)
+ * add trick to make relativeToVRT works for a VRT-in-VRT
+
+USGSDEM driver:
+ * take into account horizontal unit = ft in the UTM case (#5819)
+
+WEBP driver:
+ * Lazy uncompressed buffer allocation and optimize band-interleaved IRasterIO() for whole image reading
 
 WMS driver:
+ * Add support for ArcGIS server REST API
  * fix to make GDAL_DEFAULT_WMS_CACHE_PATH configuration option work as expected (#4540)
+ * move the WMS layer name encoding to be done before the sub datasets URLs are created.
 
 XYZ driver:
  * fix back line seeking with datasets that have not the same number of values per lines (#5488)
- * report correct values of min/max for GDT_Float32 bands (#5492)
+ * deal with lines that have missing values (but still regularly spaced)
 
-== OGR core ==
+== OGR 2.0 - Overview of Changes ==
 
+Core:
+ * OGRPolygon::importFromWkt(): fix memleak when importing broken 2.5D polygon
  * Fix OGRFeature::SetGeometryDirectly() and SetGeomFieldDirectly() to free the passed geometry even if the method fails (#5623)
- * OGRLayerDecorator: remove return statements from void methods (#5618)
- * OSR proj.4 import: for HOM, make sure +no_off/no_uoff is preserved, and change default value of gamma parameter to be the same as alpha (#5511)
+ * OGR SQL: Add hstore_get_value(hstore, key) function
+ * OGR SQL: sanitize how we deal with field names expressed as table_name.field_name and "fieldname.with_point_inside". By default, use standard quoting rules, and be tolerant when there's no ambiguity
+ * OGR SQL: support arbitrary boolean expression on ON clause of a JOIN
+ * OGR SQL: accept AS keyword in 'FROM table_name AS alias' clause
+ * OGR SQL: don't consider backslash-doublequote as an escape sequence when inside a single-quoted string literal
+ * Add OGR_API_SPY mechanism (http://www.gdal.org/ograpispy_8h.html)
+ * Make OGRParseDate() recognize ISO 8601 format
+ * ogr_core.h: only ignore -Wfloat-equal for IsInit() and not for the rest of the file and files that include it (#5299)
+ * OGR layer algebra: properly initialize field maps to avoid Valgrind warnings in OGRLayer::Update() (#5778)
+ * Make OGR_F_SetFieldBinary() set OFTString fields, mostly for testing purposes
+ * OGR_G_CreateGeometryFromJson(): attach a WGS84 SRS to the returned geometry if the json object has no 'crs' member (#5922)
 
-== OGR utilities ==
+OGRSpatialReference:
+ * Upgrade to EPSG v8.5 database
+ * Proj.4 import: for HOM, make sure +no_off/no_uoff is preserved, and change default value of gamma parameter to be the same as alpha (#5511)
+ * Proj.4 export: export Aitoff, Winkel I, Winkel II, Winkel-Tripel, Craster, Loximuthal, Quartic Authalic
+ * Adding support for Mercator_Auxiliary_Sphere without AUTHORITY SECTIONS (#3962)
+ * Add QSC (Quadrilateralized_Spherical_Cube) projection, compatible with PROJ 4.9
+ * Various fixes to put EXTENSION node before AUTHORITY and make it pass Validate() (#5724)
+ * importFromEPSG()/exportToProj4(): avoid precision loss in TOWGS84 parameters, e.g. on Amersfoort / RD EPSG:4289 (https://trac.osgeo.org/proj/ticket/260)
+ * Add OSRCalcInvFlattening() and OSRCalcSemiMinorFromInvFlattening(), and use them in various places (#5858)
+ * Remove deprecated variant of OGRSpatialReference::importFromOzi() (#5932)
 
- * ogr2ogr: fix problem with SRS when copying layers with multiple geometry columns with different SRS (#5546)
+Utilities:
+ * ogrinfo: add -oo option per RFC 46
+ * ogrinfo: display dataset and layer metadata. Add -nomdd, -listmdd, -mdd all|domain options, like in gdalinfo. OGR VRT: add dataset and layer metadata support
+ * ogrinfo: add -nocount and -noextent options
+ * ogr2ogr: add -oo and -doo options per RFC 46
  * ogr2ogr: turn string value to one element list if destination field is stringlist
+ * ogr2ogr: fix problem with SRS when copying layers with multiple geometry columns with different SRS (#5546)
+ * ogr2ogr: add special case for -update and GPKG and input=output
+ * ogr2ogr: when copying a layer that has a source integer/integer64 field with same name as target FID column, avoid creating it into target layer and use its content as the FID value (#5845)
+ * ogr2ogr: in non-append mode, if target layer has a FID creation option, reuse source FID name and source FIDs, unless -unsetFid is specified (#5845)
+ * ogr2ogr: copy source dataset and layer metadata, unless disabled by -nomd. Additionnal dataset metadata can be set with -mo KEY=VALUE
+ * ogrlineref: fix project if reper lies on first point or last point of line
 
-== OGR drivers ==
+Other:
+ * OGR WCTS removed from tree
+
+Cross driver changes:
+ * MSSQLSpatial and GPKG: use standardized 'GEOMETRY_NAME' option name. Add GEOMETRY_NAME to SQLite (#5816)
+ * FileGDB and MySQL: use standardized 'FID' option name. SQLite: add a FID layer creation option (#5816)
+ * SQLite, GPKG, PG, PGDump: in a newly created table, allow to create a integer field with same name of FID column (#5845)
+
+BNA driver:
+ * fix segfault when calling GetNextFeature() on a write-only layer
+
+CartoDB:
+ * add CARTODBFY layer creation option
+ * launder layer and column names by default (#5904)
+ * enable by default batch insertion of features in update mode
+ * on a newly created layer, send new features created by CreateFeature() by chunks of a maximum size of 15 MB (configurable through CARTODB_MAX_CHUNK_SIZE).
+ * implement deferred field creation
+ * support boolean type
+ * register tables with cdb_cartodbfytable()
+ * fix creation of features with Date/DateTime/Time values
+ * fix for multi-user account, and optimization for SQL layers
+ * implement TestCapability() and CreateDataSource() similarly to PostgreSQL, i.e. redirect to Open() in update mode
+ * accept a user column to have the same name of the FID (cartodb_id)
+ * do automatic polygon->multipolygon promotion at creation time
+ * in authenticated mode, retrieve all column information, including spatial info, default value and primary key in one single statement
+ * use integer primary key of tables, when available, to scroll faster among features instead of using OFFSET/LIMIT (#5906)
 
 CSV driver:
+ * add optional field type detection with AUTODETECT_TYPE=YES open option
+ * add QUOTED_FIELDS_AS_STRING open option that default to NO. So by default, if AUTODETECT_TYPE=YES, the content of quoted fields will be tested for real, integer,... data types
  * fix to avoid truncation of WKT geometries to 8000 characters (#5508)
+ * fix segfault when reading allCountries.txt of geonames.org (#5668)
 
-FileGDB:
- * use LatestWKID when available, and turn importFromEPSG() errors into warning (#5638)
+DXF driver:
+ * improve TestCapability(ODsCCreateLayer)
+
+FileGDB driver:
+ * add layer creation option to set CONFIGURATION_KEYWORD
+ * avoid error message when failing to import SRS from WKID code (might be an ESRI code for example)
+ * do not reject features with null geometry
+ * use LatestWKID when available (#5638)
+ * avoid emitting error when opening a FileGDB v9, so that OpenFileGDB can be tried to open it, in the case FileGDB is a plugin (#5674)
+ * fix CreateFeature() to work when a esriFieldTypeGlobalID field is not set
+ * report width of string fields (#5806)
+ * add compatibility with FileGDB SDK v1.4
 
 GeoJSON driver:
+ * implement Date/Time/DateTime field type detection
+ * expose a 'id' object, of type string, directly on Feature object (not in its properties) as a field
+ * add FLATTEN_NESTED_ATTRIBUTES and NESTED_ATTRIBUTE_SEPARATOR open options
+ * TopoJSON: establish layer schema from objects properties (#5870)
+ * implement automatic scrolling through result sets of ArcGIS GeoServices Feature Service (#5943)
  * accept and skip UTF-8 BOM (#5630)
+ * ESRIJson: parse correctly rings of esriGeometryPolygon objects to build correct Polygon or MultiPolygon (#5538)
+ * avoid truncation of real numbers on reading (#5882)
+ * internal libjson-c: Fix to read floating point numbers in non C locale (#5461)
+ * improve TestCapability(ODsCCreateLayer)
+ * make string comparison for authority name case insensitive so as to recognize lowercase 'epsg' (#4995)
+
+GeoRSS driver:
+ * fix to parse ATOM feed documents with atom: namespace (#5871)
 
 GME driver:
- * Merged SetSpatialFilter fix
+ * Added fixes discovered while using v.in.ogr and v.out.ogr in GRASS
 
 GML driver:
+ * add XSD=filename open option
+ * add a FORCE_SRS_DETECTION open option
  * fix bug that prevented multiple instanciation of the reader with Xerces backend (#5571)
- * update GFS files for RUIAN (#5610)
+ * parse correctly GML geometries whose srsDimension attribue is on top-level geometry element and not on posList (#5606)
+ * add datasource option SRSDIMENSION_LOC=GEOMETRY to be able to write srsDimension attribute on top level geometry element, default on posList unchanged (#5066)
+ * add support for reading layers resulting from a WFS 2.0 join query
+ * read/write top <gml:description> and <gml:name> as DESCRIPTION and NAME metadata items. Also add GML_ID, DESCRIPTION and NAME creation options
+ * support to reader response to CSW GetRecords queries
+ * Fix incorrect geometry cast when reading GML topogeometries (#5715)
+ * VFR: fix ST_Z type (changes) -- list all layers
+ * VFR: include also non-spatial (removed) features (ZaniklePrvky) in type ST_Z (changes)
+ * VFR: use String when 32-bit integer wasn't wide enough
+ * VFR: add support for UVOH file type
+ * VFR: add missing support for OriginalniHraniceOmpv geometry
+ * VFR: update GFS files to RFC31 (OGR 64bit Integer Fields and FIDs)
+ * update RUIAN GFS files: add missing GMLFeatureClasses to OB type (SpravniObvody, Mop, Momc)
+ * add support for parsing .xsd with a <choice> of polygonProperty and multiPolygonProperty
+ * remove wrong case insensitive comparison related to gml_registry.xml use
+ * various fixes to better deal with ArcByCenterPoint() as found in FAA AIXML files
+ * make Expat parser accept trailing nul characters
+ * correctly record path to attribute in case of attribute located on a nested element when .gfs is created with GML_ATTRIBUTES_TO_OGR_FIELDS=YES
 
 GPKG driver:
- * fix crash on ogr2ogr -f GPKG with non-spatial layer (#5445)
- * fix GetExtent() crash on layers without extent set in gpkg_contents (#5471)
+ * add support for non-spatial layers via the gdal_aspatial extension (#5521)
+ * add support for creating spatial index
+ * add layer metadata read/write support
+ * implement ST_GeometryType(), GPKG_IsAsisgnable() and ST_SRID() to be compatible with Geometry Type Triggers and SRS ID Triggers Extensions
+ * on creation, use GEOMCOLLECTION (instead of GEOMETRYCOLLECTION) (#5937)
+ * make SELECT expressions passed to ExecuteSQL() be evaluated by SQLite
+ * make it possible to use spatialite 4.2.0 SQL functions
+ * add a 'INDIRECT_SQLITE' dialect that goes through the VirtualOGR mechanism (e.g. for compat with older Spatialite)
+ * allow table names with dash character (#5472)
+ * emit warning when required extensions are not implemented
+ * disable PRAGRAM integrity_check by default, since it can be expensive on big files
+ * read-only support for tables without integer primary key
+ * fix Date and DateTime support
+ * implement TEXT(maxwidth) type in read and creation
+ * implement deferred table creation
+ * fix reporting of geometry type for 2.5D (previous behaviour had the effect to turn to wkbUnknown)
  * put correct value (1) in gpkg_geometry_columns for 2.5D tables (#5481)
- * fix component geometry type of GPKG 3D MultiGeometries (#5629)
+ * fix component geometry type of 3D MultiGeometries (#5629)
+ * fix GetExtent() crash on layers without extent set in gpkg_contents (#5471)
+ * avoid leak when a table has more than one FID column
+ * accept spatial tables whose geometry field is declared as BLOB
+ * recognize both GeomCollection and GeometryCollection as possible values, until GeoPackage SWG clears what is the official value
+ * escape all column names in SQL (#5520)
+ * accept geometries with Spatialite format, that can be returned with issuing a SQL request using spatialite functions
+
+GTM driver:
+ * declare OLCCreateField and OLCSequentialWrite capabilities
 
 IDRISI driver:
  * fix support for multi-ring polygons (#5544)
 
-VFK driver:
- * change default DB filename
+ILI driver:
+ * Use Ili1TransferElement written by ili2c 4.5.5 and newer
+ * Fix crash in polygon geometry reading
+ * Fix reading SURFACE polygons with multiple rings
+ * Fix reading tables with polygon type
+ * Support curve geometries for ILI1 and ILI2.
+ * Add a MODEL open option
 
-MapInfo File driver:
- * MIF: Remove duplicate OLCSequentialWrite test and report OLCCreateField (#5477)
- * MIF: don't write field width for integer fields in .mif, which is incompatible with MapInfo (#3853)
- * MIF: close polygon rings when reading Region from MIF file (#5614)
+ISIS3 driver:
+ * fix to recognize IsisCube.Mapping.LatitudeType = Planetocentric (#5717)
+
+KML driver:
+ * fix segfault when calling GetNextFeature() on a write-only layer
+
+LIBKML driver:
+ * add support for reading gx:MultiTrack
+ * rework libkml singleton factory management (#5775)
+
+MITAB driver:
+ * add support for append/update/delete operations on .tab files (#5652)
+ * add support for CreateField() on non empty file, AlterFieldDefn() and DeleteField() for .TAB (#5652)
+ * implement SyncToDisk() for TAB layers (#5652)
+ * convert to use of VSI*L FILE API (#5558)
+ * don't write field width for integer fields in .mif, which is incompatible with MapInfo (#3853)
+ * report OLCCreateField for .mif files (#5477)
+ * fix opening .mif file without .mid file (#5570)
+ * swap StdParallel1 and stdParallel2 if necessary on LCC projections (https://github.com/mapgears/mitab/issues/1)
+ * take into account scale/bounds to properly round coordinates (https://github.com/mapgears/mitab/issues/2)
+ * add MITAB_BOUNDS_FILE configuration option to specify a file with projection bounds (https://github.com/mapgears/mitab/issues/3)
+ * add BOUNDS layer creation option (#5642)
+ * refactor import/export of MIF coordsys to use the TAB code; take into account MITAB_BOUNDS_FILE to add Bounds to the CoordSys string
+ * close polygon rings when reading Region from MIF file (#5614)
+ * fix segfault in CreateFeature() if passing an invalid OGR feature style string (#1209)
 
-MSSQL driver:
- * Fix schema handling (#5401)
+MSSQLSpatial driver:
+ * Implement SPATIAL_INDEX layer creation option for MSSQL (#5563)
+ * Implement support for WKB geometry upload (#5682)
+ * Fix schema handling in MSSQL driver (#5401)
  * Fix spatial geometry field handling (#5474)
+ * Bind string fields to unicode string columns in the database (#5239)
+ * Fix recognizing image columns as geometry columns for the select layers. (#5498)
+ * Fix issue when creating non-spatial table (#5696)
+ * Fix to read metadata if the tables are specified in the connection string (#5796)
+ * Fix crash if the tablename is specified in the connection string (#5826)
+ * Include geometry column name in Update statement (#5930)
+ * Implement FID layer creation option (#5816)
 
-MySQL driver:
+MySQL:
  * thread-safe initialization of mysql client library (#5528)
 
 NAS driver:
- * implement wfs:update (adds new context 'update' and fields "endet" and
-  "anlass" to "delete" layer).
- * also assign xlink:href attributes as layer attribute, not only
-   in "alkis_beziehungen" layer; (#5372)
+ * implement wfs:update (adds new context 'update' and fields "endet" and "anlass" to "delete" layer).
+ * also assign xlink:href attributes as layer attribute (not only in "alkis_beziehungen" layer; #5372)
+ * fix filtering on OGR_GEOMETRY special field
+ * make chevrons configurable by NAS_INDICATOR
 
 OCI driver:
- * fix memory leaks (#5599)
- * fix creation of DATE fields (#5600)
- * fix creation of columns whose name length is longer than 30 characters (#5466)
+ * add a ADD_LAYER_GTYPE=YES/NO layer creation option that defaults to YES to enforce a layer geometry type and is used to retrieve the layer geometry type when listing layers (#3754)
+ * Fix FID (multi_load=off, OGRNullFID) - start with 1 (not -1) (#5454)
+ * use VARCHAR2 instead of VARCHAR for unsupported types
+ * Fix "ORA-00972: identifier is too long" error (#5466)
+ * Fix memory leaks (#5599)
+ * Fix creation of date and datetime fields (#5600)
+ * initialize member variable to avoid UpdateLayerExtents() to be called randomly on non spatial tables (#5376)
+ * avoid spatial index to be created each time SyncToDisk() is called
+ * fix memory leak in DeleteLayer(const char*)
+ * fix reading of 2D geometries that were always turned as 3D
+ * in layers returned by ExecuteSQL(), only expose geometry column if there's one
+ * force NLS_NUMERIC_CHARACTERS to ". " (#5709)
+
+ODBC driver:
+ * try alternate DSN template for 64bit ODBC
+ * make ODBC driver honour PGEO_DRIVER_TEMPLATE config. option (and also MDB_DRIVER_TEMPLATE in case PGEO_DRIVER_TEMPLATE isn't defined) (#5594)
+
+ODS driver:
+ * fix export of OFTDate fields that were exported as string
 
 OpenFileGDB driver:
+ * add compatibility with .gdbtable files bigger than 4 GB (#5615)
+ * support opening files with ConfigurationKeyword=MAX_FILE_SIZE_4GB or MAX_FILE_SIZE_256TB (#5615)
  * fix occasionnal write-after-end-of-buffer (#5464)
+ * avoid error message when failing to import SRS from WKID code (might be an ESRI code for example)
  * fix spatial filter with GeneralPolygon shapes (#5591)
- * add compatibility with .gdbtable files bigger than 4 GB (#5615)
- * remove not really justified check in .gdbtablx that prevents legit GDB to be read (#5635)
  * fix for reading GDB with string fields with a default value length > 127 (#5636)
- * support opening files with ConfigurationKeyword=MAX_FILE_SIZE_4GB or MAX_FILE_SIZE_256TB (#5615)
- * use LatestWKID when available, and turn importFromEPSG() errors into warning (#5638)
+ * better handling of certain definitions of raster columns
+ * use LatestWKID when available (#5638)
  * increase accepted size for field description zone up to 10 MB (#5660)
+ * fix ResetReading() on SQL layer with ORDER BY on indexed column (#5669)
+ * add support for non spatial GDB v9 tables (#5673)
+ * improve error reporting when file exists but cannot be opened due to permission problem (#5838)
+ * report width of string fields (#5806)
+ * try to deal more gracefully with inconsistent nValidRecordCount vs nTotalRecordCount values (#5842)
+ * report 25D layer geometry type on FileGDB v9 tables when relevant
 
 OSM driver:
+ * add mechanism to compute fields from other fields/tags with SQL expressions. Apply it for z_order on lines layer
  * fix random crash, particularly on MacOSX (#5465)
 
 PG driver:
- * fix crash when writing a StringList with 0 element (#5655, derived from patch by rtorre)
+ * use COPY mode by default (unless PG_USE_COPY is set to NO) when inserting features in a newly create table (#5460)
+ * add UNLOGGED=YES/NO layer creation option to create unlogged tables (improved version of patch by Javier Santana, #4708)
+ * implement deferred loading of table list, to optimize ExecuteSQL() (#5450)
+ * implement optimization for spatial table listing for PostGIS 2.x
+ * implement deferred creation of tables to capture all attribute and geometry column creations into a single CREATE TABLE statement (#5547)
+ * change "No field definitions found" from fatal error to debug
+ * when creating a table and filling it, avoid re-reading the table definition from PG system tables (#5495)
+ * better handling of SRS authority name different than EPSG (authority code must still be integral)
+ * fix crash when writing a StringList with 0 element (#5655)
+ * emit errors instead of debug messages when postgres issues an error (#5679)
+ * fix to make ExecuteSQL('CREATE DATABASE foo') work
+ * fix regression that prevented to retrieve more than 500 features from a connection with tables= parameter and on a SQL result layer (#5837)
+ * PG/PGDump: fix truncation of fields to work with multi-byte UTF-8 characters (#5854)
 
 PGDump driver:
- * fix crash when writing a StringList with 0 element (#5655, derived from patch by rtorre)
+ * switch to DROP_TABLE=IF_EXISTS by default (#5627)
+ * fix crash when writing a StringList with 0 element (#5655)
+
+PGeo driver:
+ * try alternate DSN template for 64bit ODBC
+
+REC driver:
 
 Shapefile driver:
+ * add SPATIAL_INDEX layer creation option (#5562)
+ * support .prj files with UTF-8 BOM
+ * fill 'date of last update' header with current time instead of dummy date, and add a DBF_DATE_LAST_UPDATE layer creation option to override this with a fixed date (#3919)
+ * fix reading of shapefiles whose .shx is non conformant (#5608)
  * fix writing values up to 2^53 in OFTReal fields with 0 decimal places (#5625)
+ * delete implicit FID field as soon as we CreateField a real one
+ * GetExtent(): don't trust extent in header if it contains Not-A-Number values (#5702)
+ * make REPACK compact .shp if SetFeature() is called and changes one geometry size (#5706)
+ * add check not to cut unicode character while cut the string lengnt for field max length during SetFeature
+ * avoid reading whole .shx at open time for /vsicurl/
+ * add SHAPE_REWIND_ON_WRITE configuration option that can be set to NO to disable correction of ring winding order on write. Usefull when dealing with MultiPolygon that are MultiPatch objects in fact (#5888)
+ * Make ENCODING layer creation option prioritary over SHAPE_ENCODING config. option
 
-TIGER driver:
- * Fix potential buffer underflow when providing /vsistdin/ to Tiger driver (#5567)
+SOSI driver:
+ * remove error noise (#5710)
+
+S57 driver:
+ * various compliance fixes in ISO8211 and S57 writer (#5798)
+ * make it possible to set LNAM_REFS=OFF as advertized in the doc
+
+SQLite/Spatialite driver:
+ * SQLite/Spatialte: add support for multiple geometry colunn tables, accordingly with RFC 41 (#5494)
+ * SQLite SQL dialect: Add hstore_get_value(hstore, key) function
+ * remove 'T' suffix when formatting the content of a Date field (#5672)
+ * optimize CreateFeature() when fields can be null or not null from one feature to another one
+ * Spatialite: improve insertion performance by disabling triggers and doing the job ourselves
+ * Fix segmentation fault when executing OGR2SQLITE_Register() when compiling against sqlite 3.8.7 (#5725)
+ * make GetFIDColumn() work when run as first method call (#5781)
+ * emit warning when reading text values in a integer/real field (possible since SQLite has no strong typing)
+ * support reading date/datetime from Julian day floating point representation
+
+SXF driver:
+ * Fix SXF file version check (#5456)
+ * Fix wrong Miller Cylindrical projection string
+ * Fix encoding issues (#5647)
+ * Fix extract z value to OGRGeometry
+ * Fix case sensitivity of RSC file
 
 VFK driver:
- * recode also header values (#5631)
- * process DKATUZE from header properly (#5633)
+ * recode also header values
+ * process DKATUZE from header properly
+ * handle also duplicated records
+ * check attribute 'parametry_spojeni'
+ * speed-up GetFeatureCount()
+ * fix reading properties. Escape characters for SQL
+ * change SRS from EPSG 2065 to 5514
+ * fix reading SBP datablock (fix mismatch when reading from file and db)
+
+VRT driver:
+ * do not propagate ignoring of x and y cols of a PointFromColumns to the source layer (#5777)
+ * add an optional 'name' attribute on FID element, so as to be able to force the report of a FID column name even if it is not exposed as a regular field (related to #5845)
+ * handle optional <OpenOptions><OOI key='key'>value</OOI></OpenOptions> to specify open options
+
+Tiger driver:
+ * Fix potential buffer underflow when providing /vsistdin/ to Tiger driver (#5567)
+
+WAsP driver:
+ * added options and changed output precision to match WAsP Map Editor
+ * improve TestCapability(ODsCCreateLayer)
+
+WFS driver:
+ * automatically enable paging if WFS 2.0 capabilities report paging support
+ * evaluate SELECT with JOIN on server-side for a Join-capable WFS 2.0 server
+ * add a TRUST_CAPABILITIES_BOUNDS open option, that can be set to YES to trust layer bounds declared in GetCapabilities response, for faster GetExtent() runtime (#4041)
+ * add capability to use spatial functions ST_xxxxx() as server-side filters
+ * add dataset and layer metadata
+ * allow SELECT with several ORDER BY columns
+ * report name of geometry column
+ * Add COOKIE option (#5824)
+ * when parsing a layer schema without geometry from the GML .xsd, do not expose a geometry field at the WFS layer level (#5834)
+
+XLSX driver:
+ * fix column numbering when there are more than 26 columns (#5774)
 
 == SWIG Language Bindings ==
 
+All bindings:
+ * bind GDALGetBandDataset() as Band.GetDataset()
+ * add Feature.GetFieldAsBinary()
+
 Java bindings:
- * Pass eRWFlag to allow both reading or writing (#5506).  Write was broken in DatasetRasterIO().
+ * Pass eRWFlag to allow both reading or writing.  Write was broken in DatasetRasterIO().
+ * updates to generate maven artifacts
 
 Perl bindings:
- * Fix schema corruption when 'Index' is a field (#5662)
+ * The breaking changes are described in more detail in swig/perl/Changes-in-the-API-in-2.0.
+ * More comprehensive use of strings as constants (such as capabilities); they are also taken from bindings, which added new ones, and not hard-coded.
+ * New classes (e.g., VSIF, GeoTransform, GeomFieldDefn) and new methods (e.g., constant lists, Dataset::SpatialReference).
+ * Much improved documentation and switch to Doxygen::Filter::Perl.
+ * New test codes.
+ * Errors are confessed with stack trace and often caught earlier with better messages.
+ * Use of attributes is deprecated and methods have been added to replace them.
+ * Multiple geometry fields have necessitated some changes in schema and field related methods.
+ * More support for named parameters (i.e., hashes as arguments).
+ * NoDataValue: set max float if undef is given.
+ * Unit: set '' if undef is given.
+ * Also other changes that will also remove some "use of uninitialized value in subroutine entry" warnings.
+ * Automatic handling of SQL result layers.
+ * Fix issue with index attribute for field meta data (schema) (#5662)
+ * Warn if attempt to create non-integer column for colors.
+ * Remove prefix GCP from GCP swig made attributes.
 
-= GDAL/OGR 1.11.0 Release Notes (r25919 to r27200) =
+Python bindings:
+ * add optional buf_xsize, buf_ysize and buf_type parameters to Dataset.ReadAsArray() and Dataset.LoadFile(), and use dataset RasterIO for better efficiency
+ * avoid generating Python exception when PyString_FromStringAndSize() fails and GDAL errors as Python exceptions are disabled
+ * Band.ReadRaster() and Dataset.ReadRaster(): clear the buffer in case there are holes in it due to odd spacings specified by the user
+ * Fix hang of Python in case of repeated call to gdal/ogr.UseExceptions() and CE_Warning emitted (#5704)
+ * for Python 2, accept unicode string as argument of Feature.SetField(idx_or_name, value) (#4608)
+ * for Python 2, accept Unicode strings to be passed as key and/or value of the dictionary passed to SetMetadata() (#5833)
+ * fix processing error of ogr_python.i with SWIG 3 (#5795)
+ * NUMPY driver: avoid returning CE_None in GetGeoTransform() when there's no geotransform set (#5801)
+ * Make GetFieldAsBinary() work with OFTString fields
+ * For Python3 compat, make Feature.GetField() use GetFieldAsBinary() if GetFieldAsString() fails (#5811)
+
+= GDAL/OGR 1.11.0 Release Notes =
 
 == In a nutshell... ==
 
@@ -1142,7 +1659,7 @@ Build(Unix):
  * New optional dependencies : libpcre (for regular expressions support in SQLite), libxml2 (validation of GML files)
  * --with-python: make it work with python3, and also accept path to python binary as argument of --with-python (#4725)
  * Use nc-config to detect netcdf compilation and linking parameters (#4424)
- * Add frmts/vrt to CONFIG_CFLAGS for developement version of gdal-config (needed for postgis 2.0 compilation)
+ * Add frmts/vrt to CONFIG_CFLAGS for development version of gdal-config (needed for postgis 2.0 compilation)
  * Fix compilation failure with iconv on FreeBSD (#4525)
  * Make FileGDBAPI detection work with FileGDBAPI v1.1 and v1.2 (#4570)
  * Fix build on Gentoo with its custom zlib 1.2.6 with the OF macro removed
@@ -1451,6 +1968,7 @@ NITF driver:
 
 Northwood driver:
  * Fixes for huge files (>2GB) support (#4565, #4645)
+ * NWT_GRD: don't advertize scale/offset as they are transparently applied in IReadBlock() (#5839).
 
 PDF driver:
  * Add CreateCopy() support
@@ -1603,7 +2121,7 @@ Utilities:
  * ogr_layer_algebra.py: new sample script to use OGR layer algebra operations
 
 Multi driver changes:
- * Fix bad AND priority when spatial and attribute filter are combined in PG, MySQL, SQLite MSSQLSptial and VRT drivers (#4507)
+ * Fix bad AND priority when spatial and attribute filter are combined in PG, MySQL, SQLite MSSQLSpatial and VRT drivers (#4507)
 
 AVCE00 driver:
  * Fix GetFeatureCount() when an attribute or spatial filter is set
@@ -1670,7 +2188,7 @@ GML driver:
  * Allow reading srsDimension attribute when set on LineString element, and not on posList (#4663)
  * Partial support for reading GML 3.3 compat encoding profile, limited to <gmlce:SimplePolygon>, <gmlce:SimpleRectangle>, <gmlce:SimpleTriangle>, <gmlce:SimpleMultiPoint> elements
  * Support WFS GetFeature response document to be piped and opened with /vsistdin/
- * Support specifying connection string as 'filename.gml,xsd=some_filename.xsd' to explicitely provide a XSD
+ * Support specifying connection string as 'filename.gml,xsd=some_filename.xsd' to explicitly provide a XSD
  * Improve detection of extent and srs for WFS 2.0
  * Allow ISO-8859-15 encoded files to be used by Expat parser (#4829)
  * Handle CompositeCurve like MultiCurve (for NAS)
@@ -2053,7 +2571,7 @@ Utilities:
  * gdalwarp: speed-up when using -tps with large number of GCPs
  * gdalwarp: add support for optional use of libarmadillo to speed-up matrix inversion in -tps mode
  * gdalwarp: detect situations where the user will override the source file
- * gdallocationinfo: do not let one off-db pixel cause all the rest to be supressed (#4181)
+ * gdallocationinfo: do not let one off-db pixel cause all the rest to be suppressed (#4181)
  * gdal_rasterize: fix half pixel shift when rasterizing points; make gdal_rasterize utility increase the computed raster extent by a half-pixel for point layers (#3774)
  * gdal_rasterize: when source datasource has a single layer, use it implicitely if none of -l or -sql is specified
  * nearblack: add -color option (#4085)
@@ -2067,7 +2585,7 @@ Utilities:
  * Add gdal_ls.py and gdal_cp.py as Python samples
  * Add new sample utility, gdal_edit.py, to edit in place various information of an existing GDAL dataset (projection, geotransform, nodata, metadata) (#4220)
  * gdalcopyproj.py: make it copy GCPs too
- * Add warning if a target filename extension isn't consistant with the output driver
+ * Add warning if a target filename extension isn't consistent with the output driver
  * Add --pause for convenient debugging, document it and --locale
 
 Multi-driver topics:
@@ -2416,7 +2934,7 @@ USGSDEM driver:
 VRT driver:
  * Implement VRTDataset::IRasterIO() that can delegate to source Dataset::RasterIO() in particular cases
  * Implement GetMinimum() and GetMaximum()
- * GetFileList(): for /vsicurl/ ressources, don't actually test their existence as it can be excruciating slow
+ * GetFileList(): for /vsicurl/ resources, don't actually test their existence as it can be excruciating slow
  * VRTComplexSource: correctly deal with complex data type (#3977)
  * Fix 2 segfaults related to using '<VRTDataset', but with invalid XML, as the target filename of VRTDataset::Create()
  * Fix 'VRTDerivedRasterBand with ComplexSource and nodata value yields potentially uninitialized buffer' (#4045)
@@ -2471,7 +2989,7 @@ Core:
  * OGR SQL: recognize optional ESCAPE escape_char clause
  * OGR SQL: allow NULL to be used as a value, so that 'SELECT *, NULL FROM foo works'
  * OGR SQL: Accept doublequoting of column_name in 'SELECT DISTINCT "column_name" FROM table_name' (#3966)
- * OGR SQL: OGRGenSQLResultsLayer: if the dialect is explicitely set to OGRSQL, don't propagate the WHERE clause of the SELECT to the source layer, but evaluate it instead at the OGRGenSQLResultsLayer level (#4022)
+ * OGR SQL: OGRGenSQLResultsLayer: if the dialect is explicitly set to OGRSQL, don't propagate the WHERE clause of the SELECT to the source layer, but evaluate it instead at the OGRGenSQLResultsLayer level (#4022)
  * OGR SQL: Avoid error emission on requests such as 'SELECT MIN(EAS_ID), COUNT(*) FROM POLY'
  * OGR SQL: Avoid setting width/precision for AVG column
  * OGR SQL: Add a mechanism to delete a layer (DROP TABLE x)
@@ -2525,7 +3043,7 @@ Utilities:
  * ogr2ogr: take into account fields specified in the -where clause in combinations with -select to create the correct list of fields to pass to SetIgnoredFields() (#4015)
  * ogr2ogr: fix -zfield option so that the modified geometry properly reports coordinate dimension = 3. Also avoids it to be in the list of ignored field names
  * ogr2ogr: add -simplify option to simplify geometries
- * ogr2ogr: add a warning if the target filename has an extension or a prefix that isn't consistant with the default output format (i.e. Shapefile), but which matches another driver. Can be made quiet with -q option
+ * ogr2ogr: add a warning if the target filename has an extension or a prefix that isn't consistent with the default output format (i.e. Shapefile), but which matches another driver. Can be made quiet with -q option
  * ogrinfo/ogr2ogr: exit when SetAttributeFilter() fails, instead of silently going on (#4261)
 
 Multi driver topics:
@@ -2920,7 +3438,7 @@ Port:
     - /vsitar/ : to read in .tar or .tgz/.tar.gz files
  * Add C API to create ZIP files
  * Add support for writable /vsizip/
- * Add VSIBufferedReaderHandle class that is usefull to improve performance when
+ * Add VSIBufferedReaderHandle class that is useful to improve performance when
    doing backward seeks by a few bytes on underlying file handles for which
    backwardseeks are very slow, such as GZip handle
  * Add service for base64 decoding
@@ -2938,7 +3456,7 @@ Port:
 Core:
  * RFC 24: progressive/async raster reading
  * On Unix, add capability of opening the target of a symlink through GDALOpen()
-   even if it not a real filename. Usefull for opening ressources expressed as
+   even if it not a real filename. Usefull for opening resources expressed as
    GDAL virtual filenames in software offering only file explorers (#3902)
  * Assume anything less than 100000 for GDAL_CACHEMAX is measured in metabytes.
  * Read cartesian coordinates if applicable in GDALLoadOziMapFile().
@@ -3031,7 +3549,7 @@ Utilities :
    to align on a standard grid (#3772)
 
 AAIGRID driver:
- * Cast nodata value to float to be consistant with precision of pixel data in
+ * Cast nodata value to float to be consistent with precision of pixel data in
    GDT_Float32 case; small optimization to avoid reading the first 100K when
    we know that the datatype is already Float32
  * Allow reading files where decimal separator is comma (#3668)
@@ -3138,7 +3656,7 @@ GTX driver:
  * Read NOAA .gtx vertical datum shift files.
 
 GXF driver:
- * Cast nodata value to float to be consistant with precision of pixel data in
+ * Cast nodata value to float to be consistent with precision of pixel data in
    GDT_Float32 case
  * Introduce a GXF_DATATYPE configuration option that can be set to Float64
  * Use GDALGetScanline() instead of GDALGetRawScanline() so that #SENS
@@ -3358,7 +3876,7 @@ Core:
  * Add OGRLayer::GetName() and OGRLayer::GetGeomType() virtual methods,
    and their C and SWIG mappings (#3719)
  * On Unix, add capability of opening the target of a symlink through OGROpen()
-   even if it not a real filename. Usefull for opening ressources expressed as
+   even if it not a real filename. Usefull for opening resources expressed as
    GDAL virtual filenames in software offering only file explorers (#3902)
  * Expat based XML readers : add support for reading files with Windows-1252
    encoding
@@ -3371,7 +3889,7 @@ Core:
                      OGR_G_SymDifference() and OGR_G_UnionCascaded()
  * Add C function: OGR_F_StealGeometry()
  * Move Centroid() method from OGRPolygon to OGRGeometry base class to be able
-   to operate on various geometry types, and to be consistant with PostGIS
+   to operate on various geometry types, and to be consistent with PostGIS
    ST_Centroid() capabilities and the underlying GEOS method
  * Make the GetStyleTable() SetStyleTable() SetStyleTableDirectly() methods on
    datasources and layers virtual (#2978)
@@ -3628,7 +4146,7 @@ PostgreSQL driver:
    is set to YES
  * If the PG_USE_BASE64 configuration option is set to YES, geometries will be
    requested as BASE64 encoded EWKB instead of canonical HEX encoded EWKB.
-   (usefull when bandwidth is the limiting factor)
+   (useful when bandwidth is the limiting factor)
  * Don't instanciate layer defn at layer creation. This can speed up
    significantly database opening when they are many tables and the user just
    needs to fetch one with GetLayerByName().
@@ -3747,7 +4265,7 @@ Python bindings:
    when used and set to True, None is returned when GDALGetGeoTransform()
    returns CE_Failure (instead of the fake (0,1,0,0,0,1)); backward
    compatibility preserved when the parameter isn't specified
- * Avoid supressing warnings and errors when exceptions are used (#3632)
+ * Avoid suppressing warnings and errors when exceptions are used (#3632)
  * Add gdalinfo.py, ogrinfo.py and ogr2ogr.py as sample scripts, direct ports
    of corresponding C/C++ utilities
  * Allow manipulating buffer > 2 GB on 64bit builds for ReadRaster() and WriteRaster()
@@ -4024,7 +4542,7 @@ GeoTIFF driver :
  * Use official value for inverse flattening of the WGS84 ellipsoid (#2787)
  * Add metadata domain for XML documents (#2786)
  * Make GTiff driver friendly with files with huge number of bands and pixel interleaving (#2838)
- * Avoid precaching other bands if block cache size is not big enough to accomodate them (#2838)
+ * Avoid precaching other bands if block cache size is not big enough to accommodate them (#2838)
  * Internal libtiff (4.0.0beta5) and libgeotiff (1.3.0beta) upgraded
  * use the SetCitationToSRS call for the PCSCitationGeoKey in a similar fashion to the GTCitationGeoKey (#2933)
  * NBITS set for GTiffOddBits.  YCbCr JPEG added as a compression type.
@@ -4462,7 +4980,7 @@ General:
         osr.ImportFromMICoordSys(), osr.ExportToMICoordSys(), SpatialReference.Clone()
         osr.EPSGTreatsAsLatLong(), osr.ImportFromEPSGA()
  * Make resampling an optionnal parameter for gdal.RegenerateOverview(),
-   to be consistant with gdal.RegenerateOverviews()
+   to be consistent with gdal.RegenerateOverviews()
  * NONNULL checks have been added to check various arguments of methods
  * add missing constants : DCAP_VIRTUALIO, color interpretations, OGR constants
 
@@ -4641,7 +5159,7 @@ Utilities:
  * gdalinfo: Display checksums on overviews when -checksum is specified
  * gdalinfo: Display whether the mask band has overviews
  * ogr2ogr: reset -gt to 1 with -skipfailures, document -gt (#2409)
- * ogr2ogr: Output error messages on stderr to be consistant; Make error message about failed reprojection more clearer (hopefully); Advertize the use of -skipfailures in error message (#2588)
+ * ogr2ogr: Output error messages on stderr to be consistent; Make error message about failed reprojection more clearer (hopefully); Advertize the use of -skipfailures in error message (#2588)
  * nearblack: Add support for scanning from top and bottom as well as from the sides.
  * Prevent crash in gdalwarpsimple utility and in GDALSimpleImageWarp() when source dataset has no raster band
  * gdal_rasterize: check that coordinates systems match (Ticket #1937)
@@ -5326,7 +5844,7 @@ Other:
 == GDAL 1.5.0 - Overview of Changes ==
 
 Core: 
- * Enable Persistent Auxilary Metadata (.aux.xml) by default.
+ * Enable Persistent Auxiliary Metadata (.aux.xml) by default.
  * Support for "pam proxies" for files in read-only locations. 
  * Create and !CreateCopy pre-Delete output existing dataset.
  * Added Identify() method on drivers (per RFC 11: Fast Format Identify)
@@ -5900,7 +6418,7 @@ Multithreading:
  - Lots of work done to implement support for multiple threads reading
    from distinct GDALDataset objects at the same time. 
 
-GDALRasterBand / Persistant Auxilary Metadata (PAM):
+GDALRasterBand / Persistant Auxiliary Metadata (PAM):
  - Support for preserving a variety of metadata in a supporting XML file. 
  - GDALRasterBand now supports "remembering" histograms, and has a concept
    of the default histogram. 
diff --git a/PROVENANCE.TXT b/PROVENANCE.TXT
index 056bd03..919c5bc 100644
--- a/PROVENANCE.TXT
+++ b/PROVENANCE.TXT
@@ -69,7 +69,7 @@ Historical and Current:
 In gdal/data we have several coordinate system dictionary files derived in one fashion or another from other source (via translation scripts):
 
 * gdal/data/cubewerx_extra.wkt: derived from definitions distributed by Cubewerx, rights unclear. See http://trac.osgeo.org/gdal/ticket/2165
-* gdal/data/ecw_cs.dat: Derived via much processing from ERMapper GDT definitions, rights unclear.  See http://trac.osgeo.org/gdal/ticket/2162
+* gdal/data/ecw_cs.wkt: Derived via much processing from ERMapper GDT definitions, rights unclear.  See http://trac.osgeo.org/gdal/ticket/2162
 * gdal/data/esri_extra.wkt: Derived with some processing from projections definitions in ArcGIS, rights unclear. See http://trac.osgeo.org/gdal/ticket/2163
 
 == Included Libraries ==
@@ -125,7 +125,7 @@ Note: all the following are build options, not required.
 
 * Contains various data files without copyright messages embedded.
 * cubewerx_extra.wkt: derived from definitions distributed by Cubewerx, rights unclear. See http://trac.osgeo.org/gdal/ticket/2165
-* ecw_cs.dat: Derived via much processing from ERMapper GDT definitions, rights unclear. See http://trac.osgeo.org/gdal/ticket/2162
+* ecw_cs.wkt: Derived via much processing from ERMapper GDT definitions, rights unclear. See http://trac.osgeo.org/gdal/ticket/2162
 * esri_extra.wkt: Derived with some processing from projections definitions in ArcGIS, rights unclear. See http://trac.osgeo.org/gdal/ticket/2163
 * ellipsoid.csv, gcs.csv, gdal_datum.csv, pcs.csv, prime_meridian.csv, projop_wparm.csv, unit_of_measure.csv: Derived from EPSG.  Modifications to EPSG data violate the EPSG use agreement (if we are to still attribute it to EPSG) so I have segregated changes into override files (ie. gcs.override.csv). 
 * seed_2d.dgn, seed_3d.dgn: Exact source of these files is unclear.  The files contain no substantial creative content since all but the header elements were stripped.  Judged to acceptable use. 
diff --git a/VERSION b/VERSION
index ca71766..57d7910 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.11.2
+2.0.0beta1
diff --git a/Vagrantfile b/Vagrantfile
index 6f2201b..793257a 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -7,6 +7,10 @@ require 'socket'
 VAGRANTFILE_API_VERSION = "2"
 
 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+
+  vm_ram = ENV['VAGRANT_VM_RAM'] || 1024
+  vm_cpu = ENV['VAGRANT_VM_CPU'] || 2
+
   config.vm.box = "precise64"
 
   config.vm.hostname = "gdal-vagrant"
@@ -16,14 +20,14 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
   config.vm.network :forwarded_port, guest: 80, host: 8080
 
   config.vm.provider :virtualbox do |vb|
-     vb.customize ["modifyvm", :id, "--memory", "1024"]
-     vb.customize ["modifyvm", :id, "--cpus", "2"]
+     vb.customize ["modifyvm", :id, "--memory", vm_ram]
+     vb.customize ["modifyvm", :id, "--cpus", vm_cpu]
      vb.customize ["modifyvm", :id, "--ioapic", "on"]
      vb.name = "gdal-vagrant"
    end  
 
   ppaRepos = [
-    "ppa:ubuntugis/ppa", "ppa:marlam/gta"
+    "ppa:ubuntugis/ubuntugis-unstable", "ppa:marlam/gta"
   ]
 
   packageList = [
@@ -33,6 +37,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     "postgis",
     "postgresql-server-dev-9.1",
     "postgresql-9.1-postgis",
+    "postgresql-9.1-postgis-scripts",
     "libmysqlclient-dev",
     #"mysql-server",
     "libpq-dev",
@@ -72,9 +77,19 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     "cmake", # for openjpeg
     "bison",
     "flex",
-    "vim"
+    "doxygen",
+    "vim",
+    "ant",
+    "mono-mcs"
   ];
 
+  unless File.exists?(".no_apt_cache")
+    cache_dir = "apt-cache/#{config.vm.box}"
+    FileUtils.mkdir_p(cache_dir) unless Dir.exists?(cache_dir)
+    puts "Using local apt cache, #{cache_dir}"
+    config.vm.synced_folder cache_dir, "/var/cache/apt/archives"
+  end
+
   if Dir.glob("#{File.dirname(__FILE__)}/.vagrant/machines/default/*/id").empty?
 	  pkg_cmd = "sed -i 's#deb http://us.archive.ubuntu.com/ubuntu/#deb mirror://mirrors.ubuntu.com/mirrors.txt#' /etc/apt/sources.list; "
 
@@ -89,6 +104,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
 	  pkg_cmd << "apt-get install -q -y " + packageList.join(" ") << " ; "
 	  config.vm.provision :shell, :inline => pkg_cmd
     scripts = [
+      "swig-1.3.40.sh",
       "libkml.sh",
       "openjpeg.sh",
       "gdal.sh",
diff --git a/alg/GNUmakefile b/alg/GNUmakefile
index 02f7f16..832c6a0 100644
--- a/alg/GNUmakefile
+++ b/alg/GNUmakefile
@@ -16,6 +16,10 @@ ifeq ($(HAVE_AVX_AT_COMPILE_TIME),yes)
 CPPFLAGS 	:=	-DHAVE_AVX_AT_COMPILE_TIME $(CPPFLAGS)
 endif
 
+ifeq ($(HAVE_SSE_AT_COMPILE_TIME),yes)
+CPPFLAGS 	:=	-DHAVE_SSE_AT_COMPILE_TIME $(CPPFLAGS)
+endif
+
 ifeq ($(HAVE_GEOS),yes)
 CPPFLAGS 	:=	-DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS)
 endif
@@ -24,12 +28,15 @@ ifeq ($(HAVE_ARMADILLO),yes)
 CPPFLAGS 	:=	-DHAVE_ARMADILLO $(CPPFLAGS)
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(OPENCL_FLAGS)
+CPPFLAGS	:=	$(CPPFLAGS) $(OPENCL_FLAGS)
 
-default:	$(OBJ:.o=.$(OBJ_EXT)) gdalgridavx.$(OBJ_EXT)
+default:	$(OBJ:.o=.$(OBJ_EXT)) gdalgridavx.$(OBJ_EXT) gdalgridsse.$(OBJ_EXT)
 
 gdalgridavx.$(OBJ_EXT):   gdalgridavx.cpp
-	$(CXX) $(CXXFLAGS) $(AVXFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(AVXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+gdalgridsse.$(OBJ_EXT):   gdalgridsse.cpp
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(SSEFLAGS) $(CPPFLAGS) -c -o $@ $<
 
 clean:
 	$(RM) *.o $(O_OBJ)
diff --git a/alg/gdal_alg.h b/alg/gdal_alg.h
index a22684b..b4734fb 100644
--- a/alg/gdal_alg.h
+++ b/alg/gdal_alg.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_alg.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal_alg.h 27850 2014-10-12 16:58:09Z rouault $
  *
  * Project:  GDAL Image Processing Algorithms
  * Purpose:  Prototypes, and definitions for various GDAL based algorithms.
@@ -115,13 +115,15 @@ typedef int
                         int bDstToSrc, int nPointCount, 
                         double *x, double *y, double *z, int *panSuccess );
 
+#define GDAL_GTI2_SIGNATURE     "GTI2"
+
 typedef struct {
-    char szSignature[4];
+    GByte abySignature[4];
     const char *pszClassName;
     GDALTransformerFunc pfnTransform;
-    void (*pfnCleanup)( void * );
-    CPLXMLNode *(*pfnSerialize)( void * );
-    /* TODO GDAL 2.0 : add a void* (*pfnClone) (void *) member */
+    void (*pfnCleanup)( void * pTransformerArg );
+    CPLXMLNode *(*pfnSerialize)( void * pTransformerArg );
+    void* (*pfnCreateSimilar)( void* pTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
 } GDALTransformerInfo;
 
 void CPL_DLL GDALDestroyTransformer( void *pTransformerArg );
@@ -129,6 +131,8 @@ int  CPL_DLL GDALUseTransformer( void *pTranformerArg,
                                  int bDstToSrc, int nPointCount, 
                                  double *x, double *y, double *z, 
                                  int *panSuccess );
+void* GDALCreateSimilarTransformer( void* psTransformerArg, double dfSrcRatioX, double dfSrcRatioY );
+
 
 /* High level transformer for going from image coordinates on one file
    to image coordiantes on another, potentially doing reprojection, 
@@ -154,6 +158,8 @@ int CPL_DLL GDALGenImgProjTransform(
     void *pTransformArg, int bDstToSrc, int nPointCount,
     double *x, double *y, double *z, int *panSuccess );
 
+void GDALSetTransformerDstGeoTransform( void *, const double * );
+
 /* Geo to geo reprojection transformer. */
 void CPL_DLL *
 GDALCreateReprojectionTransformer( const char *pszSrcWKT, 
diff --git a/alg/gdal_alg_priv.h b/alg/gdal_alg_priv.h
index 53f6586..3015ec0 100644
--- a/alg/gdal_alg_priv.h
+++ b/alg/gdal_alg_priv.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_alg_priv.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal_alg_priv.h 28826 2015-03-30 17:51:14Z rouault $
  *
  * Project:  GDAL Image Processing Algorithms
  * Purpose:  Prototypes and definitions for various GDAL based algorithms:
@@ -94,6 +94,8 @@ CPL_C_END
 /*                          Polygon Enumerator                          */
 /************************************************************************/
 
+#define GP_NODATA_MARKER -51502112
+
 class GDALRasterPolygonEnumerator
 
 {
@@ -172,17 +174,45 @@ void GDALCleanupTransformDeserializerMutex();
 
 /* Transformer cloning */
 
-void* GDALCloneTPSTransformer( void *pTransformArg );
-void* GDALCloneGenImgProjTransformer( void *pTransformArg );
-void* GDALCloneApproxTransformer( void *pTransformArg );
-/* TODO : GDALCloneGeoLocTransformer? , GDALCloneRPCTransformer? */ 
-
 void* GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList, 
                                    int bReversed, char** papszOptions );
 
 void CPL_DLL * GDALCloneTransformer( void *pTranformerArg );
 
 /************************************************************************/
+/*      Color table related                                             */
+/************************************************************************/
+
+int
+GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed, 
+                           GDALRasterBandH hGreen, 
+                           GDALRasterBandH hBlue, 
+                           GByte* pabyRedBand,
+                           GByte* pabyGreenBand,
+                           GByte* pabyBlueBand,
+                           int (*pfnIncludePixel)(int,int,void*),
+                           int nColors, 
+                           int nBits,
+                           int* panHistogram,
+                           GDALColorTableH hColorTable,
+                           GDALProgressFunc pfnProgress, 
+                           void * pProgressArg );
+
+int GDALDitherRGB2PCTInternal( GDALRasterBandH hRed, 
+                               GDALRasterBandH hGreen, 
+                               GDALRasterBandH hBlue, 
+                               GDALRasterBandH hTarget, 
+                               GDALColorTableH hColorTable,
+                               int nBits,
+                               GInt16* pasDynamicColorMap,
+                               int bDither,
+                               GDALProgressFunc pfnProgress, 
+                               void * pProgressArg );
+
+#define PRIME_FOR_65536                                 98317
+#define MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536         (6 * sizeof(int) * PRIME_FOR_65536)
+
+/************************************************************************/
 /*      Float comparison function.                                      */
 /************************************************************************/
 
diff --git a/alg/gdal_crs.c b/alg/gdal_crs.c
index f75a55c..24a8553 100644
--- a/alg/gdal_crs.c
+++ b/alg/gdal_crs.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_crs.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdal_crs.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Mapinfo Image Warper
  * Purpose:  Implemention of the GDALTransformer wrapper around CRS.C functions
@@ -57,8 +57,9 @@
 #include "cpl_conv.h"
 #include "cpl_minixml.h"
 #include "cpl_string.h"
+#include "cpl_atomic_ops.h"
 
-CPL_CVSID("$Id: gdal_crs.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdal_crs.c 27942 2014-11-11 00:57:41Z rouault $");
 
 /* Hum, we cannot include gdal_priv.h from a .c file... */
 CPL_C_START
@@ -105,6 +106,8 @@ typedef struct
     int    nMinimumGcps;
     double dfTolerance;
     
+    volatile int nRefCount;
+    
 } GCPTransformInfo;
 
 CPL_C_START
@@ -127,6 +130,42 @@ static char *CRS_error_message[] = {
     "Failed to compute GCP transform: Internal error"
 };
 
+/************************************************************************/
+/*                   GDALCreateSimilarGCPTransformer()                  */
+/************************************************************************/
+
+static
+void* GDALCreateSimilarGCPTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
+{
+    int i;
+    GDAL_GCP *pasGCPList;
+    GCPTransformInfo *psInfo = (GCPTransformInfo *) hTransformArg;
+
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarGCPTransformer", NULL );
+    
+    if( dfRatioX == 1.0 && dfRatioY == 1.0 )
+    {
+        /* We can just use a ref count, since using the source transformation */
+        /* is thread-safe */
+        CPLAtomicInc(&(psInfo->nRefCount));
+    }
+    else
+    {
+        pasGCPList = GDALDuplicateGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
+        for(i=0;i<psInfo->nGCPCount;i++)
+        {
+            pasGCPList[i].dfGCPPixel /= dfRatioX;
+            pasGCPList[i].dfGCPLine /= dfRatioY;
+        }
+        /* As remove_outliers modifies the provided GCPs we don't need to reapply it */
+        psInfo = (GCPTransformInfo *) GDALCreateGCPTransformer(
+            psInfo->nGCPCount, pasGCPList, psInfo->nOrder, psInfo->bReversed );
+        GDALDeinitGCPs( psInfo->nGCPCount, pasGCPList );
+        CPLFree( pasGCPList );
+    }
+
+    return psInfo;
+}
 
 /************************************************************************/
 /*                      GDALCreateGCPTransformer()                      */
@@ -185,15 +224,18 @@ void *GDALCreateGCPTransformerEx( int nGCPCount, const GDAL_GCP *pasGCPList,
     psInfo->bRefine = bRefine;
     psInfo->dfTolerance = dfTolerance;
     psInfo->nMinimumGcps = nMinimumGcps;
+    
+    psInfo->nRefCount = 1;
 
     psInfo->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
     psInfo->nGCPCount = nGCPCount;
 
-    strcpy( psInfo->sTI.szSignature, "GTI" );
+    memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psInfo->sTI.pszClassName = "GDALGCPTransformer";
     psInfo->sTI.pfnTransform = GDALGCPTransform;
     psInfo->sTI.pfnCleanup = GDALDestroyGCPTransformer;
     psInfo->sTI.pfnSerialize = GDALSerializeGCPTransformer;
+    psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarGCPTransformer;
     
 /* -------------------------------------------------------------------- */
 /*      Compute the forward and reverse polynomials.                    */
@@ -292,11 +334,14 @@ void GDALDestroyGCPTransformer( void *pTransformArg )
     GCPTransformInfo *psInfo = (GCPTransformInfo *) pTransformArg;
 
     VALIDATE_POINTER0( pTransformArg, "GDALDestroyGCPTransformer" );
+    
+    if( CPLAtomicDec(&(psInfo->nRefCount)) == 0 )
+    {
+        GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
+        CPLFree( psInfo->pasGCPList );
 
-    GDALDeinitGCPs( psInfo->nGCPCount, psInfo->pasGCPList );
-    CPLFree( psInfo->pasGCPList );
-
-    CPLFree( pTransformArg );
+        CPLFree( pTransformArg );
+    }
 }
 
 /************************************************************************/
@@ -324,9 +369,9 @@ void GDALDestroyGCPTransformer( void *pTransformArg )
  * @return TRUE.
  */
 
-int GDALGCPTransform( void *pTransformArg, int bDstToSrc, 
-                      int nPointCount, 
-                      double *x, double *y, CPL_UNUSED double *z, 
+int GDALGCPTransform( void *pTransformArg, int bDstToSrc,
+                      int nPointCount,
+                      double *x, double *y, CPL_UNUSED double *z,
                       int *panSuccess )
 
 {
@@ -457,7 +502,7 @@ void *GDALDeserializeGCPTransformer( CPLXMLNode *psTree )
     bReversed = atoi(CPLGetXMLValue(psTree,"Reversed","0"));
     bRefine = atoi(CPLGetXMLValue(psTree,"Refine","0"));
     nMinimumGcps = atoi(CPLGetXMLValue(psTree,"MinimumGcps","6"));
-    dfTolerance = atof(CPLGetXMLValue(psTree,"Tolerance","1.0"));
+    dfTolerance = CPLAtof(CPLGetXMLValue(psTree,"Tolerance","1.0"));
 
 /* -------------------------------------------------------------------- */
 /*      Generate transformation.                                        */
diff --git a/alg/gdal_rpc.cpp b/alg/gdal_rpc.cpp
index 0ff0255..b37ca37 100644
--- a/alg/gdal_rpc.cpp
+++ b/alg/gdal_rpc.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_rpc.cpp 27931 2014-11-07 13:24:50Z rouault $
+ * $Id: gdal_rpc.cpp 29123 2015-05-03 11:05:46Z bishop $
  *
  * Project:  Image Warper
  * Purpose:  Implements a rational polynomail (RPC) based transformer. 
@@ -32,8 +32,9 @@
 #include "gdal_alg.h"
 #include "ogr_spatialref.h"
 #include "cpl_minixml.h"
+#include "gdal_mdreader.h"
 
-CPL_CVSID("$Id: gdal_rpc.cpp 27931 2014-11-07 13:24:50Z rouault $");
+CPL_CVSID("$Id: gdal_rpc.cpp 29123 2015-05-03 11:05:46Z bishop $");
 
 CPL_C_START
 CPLXMLNode *GDALSerializeRPCTransformer( void *pTransformArg );
@@ -54,34 +55,34 @@ char ** RPCInfoToMD( GDALRPCInfo *psRPCInfo )
     int i;
 
     osField.Printf( "%.15g", psRPCInfo->dfLINE_OFF );
-    papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LINE_OFF, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfSAMP_OFF );
-    papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_SAMP_OFF, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfLAT_OFF );
-    papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LAT_OFF, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfLONG_OFF );
-    papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LONG_OFF, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfHEIGHT_OFF );
-    papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_HEIGHT_OFF, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfLINE_SCALE );
-    papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LINE_SCALE, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfSAMP_SCALE );
-    papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_SAMP_SCALE, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfLAT_SCALE );
-    papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LAT_SCALE, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfLONG_SCALE );
-    papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_LONG_SCALE, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfHEIGHT_SCALE );
-    papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
+    papszMD = CSLSetNameValue( papszMD, RPC_HEIGHT_SCALE, osField );
 
     osField.Printf( "%.15g", psRPCInfo->dfMIN_LONG );
     papszMD = CSLSetNameValue( papszMD, "MIN_LONG", osField );
@@ -281,6 +282,49 @@ static const char* GDALSerializeRPCDEMResample(DEMResampleAlg eResampleAlg)
 }
 
 /************************************************************************/
+/*                   GDALCreateSimilarRPCTransformer()                  */
+/************************************************************************/
+
+static
+void* GDALCreateSimilarRPCTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
+{
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarRPCTransformer", NULL );
+
+    GDALRPCTransformInfo *psInfo = (GDALRPCTransformInfo *) hTransformArg;
+    
+    GDALRPCInfo sRPC;
+    memcpy(&sRPC, &(psInfo->sRPC), sizeof(GDALRPCInfo));
+    
+    if( dfRatioX != 1.0 || dfRatioY != 1.0 )
+    {
+        sRPC.dfLINE_OFF /= dfRatioY;
+        sRPC.dfLINE_SCALE /= dfRatioY;
+        sRPC.dfSAMP_OFF /= dfRatioX;
+        sRPC.dfSAMP_SCALE /= dfRatioX;
+    }
+
+    char** papszOptions = NULL;
+    papszOptions = CSLSetNameValue(papszOptions, "RPC_HEIGHT",
+                                   CPLSPrintf("%.18g", psInfo->dfHeightOffset));
+    papszOptions = CSLSetNameValue(papszOptions, "RPC_HEIGHT_SCALE",
+                                   CPLSPrintf("%.18g", psInfo->dfHeightScale));
+    if( psInfo->pszDEMPath != NULL )
+    {
+        papszOptions = CSLSetNameValue(papszOptions, "RPC_DEM", psInfo->pszDEMPath);
+        papszOptions = CSLSetNameValue(papszOptions, "RPC_DEMINTERPOLATION",
+                                       GDALSerializeRPCDEMResample(psInfo->eResampleAlg));
+        if( psInfo->bHasDEMMissingValue )
+            papszOptions = CSLSetNameValue(papszOptions, "RPC_DEM_MISSING_VALUE",
+                                           CPLSPrintf("%.18g", psInfo->dfDEMMissingValue)) ;
+    }
+    psInfo = (GDALRPCTransformInfo*) GDALCreateRPCTransformer( &sRPC,
+           psInfo->bReversed, psInfo->dfPixErrThreshold, papszOptions );
+    CSLDestroy(papszOptions);
+
+    return psInfo;
+}
+
+/************************************************************************/
 /*                      GDALCreateRPCTransformer()                      */
 /************************************************************************/
 
@@ -357,7 +401,7 @@ static const char* GDALSerializeRPCDEMResample(DEMResampleAlg eResampleAlg)
  * an average height above sea level for ground in the target scene. 
  *
  * <li> RPC_HEIGHT_SCALE: a factor used to multiply heights above ground.
- * Usefull when elevation offsets of the DEM are not expressed in meters. (GDAL >= 1.8.0)
+ * Useful when elevation offsets of the DEM are not expressed in meters. (GDAL >= 1.8.0)
  *
  * <li> RPC_DEM: the name of a GDAL dataset (a DEM file typically) used to
  * extract elevation offsets from. In this situation the Z passed into the
@@ -406,11 +450,12 @@ void *GDALCreateRPCTransformer( GDALRPCInfo *psRPCInfo, int bReversed,
     psTransform->dfHeightOffset = 0.0;
     psTransform->dfHeightScale = 1.0;
 
-    strcpy( psTransform->sTI.szSignature, "GTI" );
+    memcpy( psTransform->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psTransform->sTI.pszClassName = "GDALRPCTransformer";
     psTransform->sTI.pfnTransform = GDALRPCTransform;
     psTransform->sTI.pfnCleanup = GDALDestroyRPCTransformer;
     psTransform->sTI.pfnSerialize = GDALSerializeRPCTransformer;
+    psTransform->sTI.pfnCreateSimilar = GDALCreateSimilarRPCTransformer;
    
 /* -------------------------------------------------------------------- */
 /*      Do we have a "average height" that we want to consider all      */
@@ -664,7 +709,8 @@ int GDALRPCGetDEMHeight( GDALRPCTransformInfo *psTransform,
         double adfElevData[16] = {0};
         CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dXNew, dYNew, 4, 4,
                                                     &adfElevData, 4, 4,
-                                                    GDT_Float64, 1, bands, 0, 0, 0);
+                                                    GDT_Float64, 1, bands, 0, 0, 0,
+                                                    NULL);
         if(eErr != CE_None)
         {
             return FALSE;
@@ -709,7 +755,8 @@ int GDALRPCGetDEMHeight( GDALRPCTransformInfo *psTransform,
         double adfElevData[4] = {0,0,0,0};
         CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 2, 2,
                                                     &adfElevData, 2, 2,
-                                                    GDT_Float64, 1, bands, 0, 0, 0);
+                                                    GDT_Float64, 1, bands, 0, 0, 0,
+                                                  NULL);
         if(eErr != CE_None)
         {
             return FALSE;
@@ -744,7 +791,8 @@ int GDALRPCGetDEMHeight( GDALRPCTransformInfo *psTransform,
         }
         CPLErr eErr = psTransform->poDS->RasterIO(GF_Read, dX, dY, 1, 1,
                                                     &dfDEMH, 1, 1,
-                                                    GDT_Float64, 1, bands, 0, 0, 0);
+                                                    GDT_Float64, 1, bands, 0, 0, 0,
+                                                  NULL);
         if(eErr != CE_None ||
             (bGotNoDataValue && ARE_REAL_EQUAL(dfNoDataValue, dfDEMH)) )
         {
diff --git a/alg/gdal_simplesurf.cpp b/alg/gdal_simplesurf.cpp
index 00be375..754c136 100644
--- a/alg/gdal_simplesurf.cpp
+++ b/alg/gdal_simplesurf.cpp
@@ -178,9 +178,9 @@ CPLErr GDALSimpleSURF::ConvertRGBToLuminosity(
     void *paGreenLayer = CPLMalloc(dataGreenSize * nWidth * nHeight);
     void *paBlueLayer = CPLMalloc(dataBlueSize * nWidth * nHeight);
 
-    red->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paRedLayer, nWidth, nHeight, eRedType, 0, 0);
-    green->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paGreenLayer, nWidth, nHeight, eGreenType, 0, 0);
-    blue->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paBlueLayer, nWidth, nHeight, eBlueType, 0, 0);
+    red->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paRedLayer, nWidth, nHeight, eRedType, 0, 0, NULL);
+    green->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paGreenLayer, nWidth, nHeight, eGreenType, 0, 0, NULL);
+    blue->RasterIO(GF_Read, 0, 0, nXSize, nYSize, paBlueLayer, nWidth, nHeight, eBlueType, 0, 0, NULL);
 
     double maxValue = 255.0;
     for (int row = 0; row < nHeight; row++)
diff --git a/alg/gdal_tps.cpp b/alg/gdal_tps.cpp
index c225852..10c4116 100644
--- a/alg/gdal_tps.cpp
+++ b/alg/gdal_tps.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_tps.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdal_tps.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Thin Plate Spline transformer (GDAL wrapper portion)
@@ -37,7 +37,7 @@
 #include "cpl_atomic_ops.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gdal_tps.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdal_tps.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 CPL_C_START
 CPLXMLNode *GDALSerializeTPSTransformer( void *pTransformArg );
@@ -63,19 +63,36 @@ typedef struct
 } TPSTransformInfo;
 
 /************************************************************************/
-/*                       GDALCloneTPSTransformer()                      */
+/*                   GDALCreateSimilarTPSTransformer()                  */
 /************************************************************************/
 
-void* GDALCloneTPSTransformer( void *hTransformArg )
+static
+void* GDALCreateSimilarTPSTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
 {
-    VALIDATE_POINTER1( hTransformArg, "GDALCloneTPSTransformer", NULL );
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarTPSTransformer", NULL );
 
-    TPSTransformInfo *psInfo = 
-        (TPSTransformInfo *) hTransformArg;
-
-    /* We can just use a ref count, since using the source transformation */
-    /* is thread-safe */
-    CPLAtomicInc(&(psInfo->nRefCount));
+    TPSTransformInfo *psInfo = (TPSTransformInfo *) hTransformArg;
+    
+    if( dfRatioX == 1.0 && dfRatioY == 1.0 )
+    {
+        /* We can just use a ref count, since using the source transformation */
+        /* is thread-safe */
+        CPLAtomicInc(&(psInfo->nRefCount));
+    }
+    else
+    {
+        GDAL_GCP *pasGCPList = GDALDuplicateGCPs( psInfo->nGCPCount,
+                                                  psInfo->pasGCPList );
+        for(int i=0;i<psInfo->nGCPCount;i++)
+        {
+            pasGCPList[i].dfGCPPixel /= dfRatioX;
+            pasGCPList[i].dfGCPLine /= dfRatioY;
+        }
+        psInfo = (TPSTransformInfo *) GDALCreateTPSTransformer( psInfo->nGCPCount, pasGCPList,
+                                           psInfo->bReversed );
+        GDALDeinitGCPs( psInfo->nGCPCount, pasGCPList );
+        CPLFree( pasGCPList );
+    }
 
     return psInfo;
 }
@@ -144,11 +161,12 @@ void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
     psInfo->poForward = new VizGeorefSpline2D( 2 );
     psInfo->poReverse = new VizGeorefSpline2D( 2 );
 
-    strcpy( psInfo->sTI.szSignature, "GTI" );
+    memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psInfo->sTI.pszClassName = "GDALTPSTransformer";
     psInfo->sTI.pfnTransform = GDALTPSTransform;
     psInfo->sTI.pfnCleanup = GDALDestroyTPSTransformer;
     psInfo->sTI.pfnSerialize = GDALSerializeTPSTransformer;
+    psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarTPSTransformer;
 
 /* -------------------------------------------------------------------- */
 /*      Attach all the points to the transformation.                    */
@@ -191,7 +209,7 @@ void *GDALCreateTPSTransformerInt( int nGCPCount, const GDAL_GCP *pasGCPList,
     if( nThreads > 1 )
     {
         /* Compute direct and reverse transforms in parallel */
-        void* hThread = CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo);
+        CPLJoinableThread* hThread = CPLCreateJoinableThread(GDALTPSComputeForwardInThread, psInfo);
         psInfo->bReverseSolved = psInfo->poReverse->solve() != 0;
         if( hThread != NULL )
             CPLJoinThread(hThread);
@@ -271,11 +289,11 @@ void GDALDestroyTPSTransformer( void *pTransformArg )
  * @return TRUE.
  */
 
-int GDALTPSTransform( void *pTransformArg, int bDstToSrc, 
-                      int nPointCount, 
-                      double *x, double *y, CPL_UNUSED double *z,
+int GDALTPSTransform( void *pTransformArg, int bDstToSrc,
+                      int nPointCount,
+                      double *x, double *y,
+                      CPL_UNUSED double *z,
                       int *panSuccess )
-
 {
     VALIDATE_POINTER1( pTransformArg, "GDALTPSTransform", 0 );
 
diff --git a/alg/gdalcutline.cpp b/alg/gdalcutline.cpp
index 7984aab..36ff99e 100644
--- a/alg/gdalcutline.cpp
+++ b/alg/gdalcutline.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalcutline.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalcutline.cpp 28223 2014-12-26 11:28:03Z goatbar $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Implement cutline/blend mask generator.
@@ -35,20 +35,30 @@
 #include "ogr_geometry.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdalcutline.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdalcutline.cpp 28223 2014-12-26 11:28:03Z goatbar $");
 
 /************************************************************************/
 /*                         BlendMaskGenerator()                         */
 /************************************************************************/
 
 static CPLErr
-BlendMaskGenerator( int nXOff, int nYOff, int nXSize, int nYSize, 
+BlendMaskGenerator(
+#ifndef HAVE_GEOS
+                    CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
+                    CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
+                    CPL_UNUSED GByte *pabyPolyMask,
+                    CPL_UNUSED float *pafValidityMask,
+                    CPL_UNUSED OGRGeometryH hPolygon,
+                    CPL_UNUSED double dfBlendDist
+#else
+                    int nXOff, int nYOff, int nXSize, int nYSize,
                     GByte *pabyPolyMask, float *pafValidityMask,
-                    OGRGeometryH hPolygon, double dfBlendDist )
-
+                    OGRGeometryH hPolygon, double dfBlendDist
+#endif
+)
 {
-#ifndef HAVE_GEOS 
-    CPLError( CE_Failure, CPLE_AppDefined, 
+#ifndef HAVE_GEOS
+    CPLError( CE_Failure, CPLE_AppDefined,
               "Blend distance support not available without the GEOS library.");
     return CE_Failure;
 
@@ -59,7 +69,7 @@ BlendMaskGenerator( int nXOff, int nYOff, int nXSize, int nYSize,
 /*      measure distance from the edge even on the inside.              */
 /* -------------------------------------------------------------------- */
     OGRGeometry *poLines
-        = OGRGeometryFactory::forceToMultiLineString( 
+        = OGRGeometryFactory::forceToMultiLineString(
             ((OGRGeometry *) hPolygon)->clone() );
 
 /* -------------------------------------------------------------------- */
@@ -227,14 +237,17 @@ BlendMaskGenerator( int nXOff, int nYOff, int nXSize, int nYSize,
 /*      relative to the current chunk.                                  */
 /************************************************************************/
 
-static int CutlineTransformer( void *pTransformArg, int bDstToSrc, 
-                               int nPointCount, 
-                               double *x, double *y, CPL_UNUSED double *z, 
+static int CutlineTransformer( void *pTransformArg,
+                               int bDstToSrc,
+                               int nPointCount,
+                               double *x,
+                               double *y,
+                               CPL_UNUSED double *z,
                                CPL_UNUSED int *panSuccess )
-
 {
     int nXOff = ((int *) pTransformArg)[0];
-    int nYOff = ((int *) pTransformArg)[1];				
+    int nYOff = ((int *) pTransformArg)[1];
+    int i;
 
     if( bDstToSrc )
     {
@@ -242,12 +255,12 @@ static int CutlineTransformer( void *pTransformArg, int bDstToSrc,
         nYOff *= -1;
     }
 
-    for( int i = 0; i < nPointCount; i++ )
+    for( i = 0; i < nPointCount; i++ )
     {
         x[i] -= nXOff;
         y[i] -= nYOff;
     }
-    
+
     return TRUE;
 }
 
@@ -259,8 +272,10 @@ static int CutlineTransformer( void *pTransformArg, int bDstToSrc,
 /*      provided cutline, and optional blend distance.                  */
 /************************************************************************/
 
-CPLErr 
-GDALWarpCutlineMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED GDALDataType eType,
+CPLErr
+GDALWarpCutlineMasker( void *pMaskFuncArg,
+                       CPL_UNUSED int nBandCount,
+                       CPL_UNUSED GDALDataType eType,
                        int nXOff, int nYOff, int nXSize, int nYSize,
                        GByte ** /*ppImageData */,
                        int bMaskIsFloat, void *pValidityMask )
@@ -401,4 +416,3 @@ GDALWarpCutlineMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED
 
     return eErr;
 }
-
diff --git a/alg/gdaldither.cpp b/alg/gdaldither.cpp
index 80b4c04..e7ff8d8 100644
--- a/alg/gdaldither.cpp
+++ b/alg/gdaldither.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldither.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdaldither.cpp 28085 2014-12-07 14:36:00Z rouault $
  *
  * Project:  CIETMap Phase 2
  * Purpose:  Convert RGB (24bit) to a pseudo-colored approximation using
@@ -35,8 +35,8 @@
  *  I should point out that the actual fractions we used were, assuming
  *  you are at X, moving left to right:
  *
- *		    X     7/16
- *	     3/16   5/16  1/16    
+ *                    X     7/16
+ *             3/16   5/16  1/16
  *
  *  Note that the error goes to four neighbors, not three.  I think this
  *  will probably do better (at least for black and white) than the
@@ -50,12 +50,44 @@
 
 #include "gdal_priv.h"
 #include "gdal_alg.h"
+#include "gdal_alg_priv.h"
 
-CPL_CVSID("$Id: gdaldither.cpp 27044 2014-03-16 23:41:27Z rouault $");
+#if defined(__x86_64) || defined(_M_X64)
+#define USE_SSE2
+#endif
 
-#define C_LEVELS	32
+#ifdef USE_SSE2
 
-static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap );
+#include <emmintrin.h>
+#define CAST_PCT(x) ((GByte*)x)
+#define ALIGN_INT_ARRAY_ON_16_BYTE(x) ( (((GPtrDiff_t)(x) % 16) != 0 ) ? (int*)((GByte*)(x) + 16 - ((GPtrDiff_t)(x) % 16)) : (x) )
+
+#else
+
+#define CAST_PCT(x) x
+
+#endif
+
+#define MAKE_COLOR_CODE(r,g,b) ((r)|((g)<<8)|((b)<<16))
+
+CPL_CVSID("$Id: gdaldither.cpp 28085 2014-12-07 14:36:00Z rouault $");
+
+static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
+                              int nCLevels );
+static int FindNearestColor( int nColors, int *panPCT,
+                             int nRedValue, int nGreenValue, int nBlueValue );
+
+/* Structure for a hashmap from a color code to a color index of the color table */
+typedef struct  /* NOTE: if changing the size of this structure, edit MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 */
+{
+    GUInt32 nColorCode;
+    GUInt32 nColorCode2;
+    GUInt32 nColorCode3;
+    GByte   nIndex;
+    GByte   nIndex2;
+    GByte   nIndex3;
+    GByte   nPadding;
+} ColorIndex;
 
 /************************************************************************/
 /*                         GDALDitherRGB2PCT()                          */
@@ -98,6 +130,22 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
                    void * pProgressArg )
 
 {
+    return GDALDitherRGB2PCTInternal( hRed, hGreen, hBlue, hTarget,
+                                hColorTable, 5, NULL, TRUE,
+                                pfnProgress, pProgressArg );
+}
+
+int GDALDitherRGB2PCTInternal( GDALRasterBandH hRed, 
+                         GDALRasterBandH hGreen, 
+                         GDALRasterBandH hBlue, 
+                         GDALRasterBandH hTarget, 
+                         GDALColorTableH hColorTable,
+                         int nBits,
+                         GInt16* pasDynamicColorMap, /* NULL or at least 256 * 256 * 256 * sizeof(GInt16) bytes */
+                         int bDither,
+                         GDALProgressFunc pfnProgress, 
+                         void * pProgressArg )
+{
     VALIDATE_POINTER1( hRed, "GDALDitherRGB2PCT", CE_Failure );
     VALIDATE_POINTER1( hGreen, "GDALDitherRGB2PCT", CE_Failure );
     VALIDATE_POINTER1( hBlue, "GDALDitherRGB2PCT", CE_Failure );
@@ -140,8 +188,13 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
 /* -------------------------------------------------------------------- */
 /*      Setup more direct colormap.                                     */
 /* -------------------------------------------------------------------- */
-    int		nColors, anPCT[768], iColor;
-
+    int		nColors, iColor;
+#ifdef USE_SSE2
+    int anPCTUnaligned[256+4]; /* 4 for alignment on 16-byte boundary */
+    int* anPCT = ALIGN_INT_ARRAY_ON_16_BYTE(anPCTUnaligned);
+#else
+    int anPCT[256*4];
+#endif
     nColors = GDALGetColorEntryCount( hColorTable );
     
     if (nColors == 0 )
@@ -166,27 +219,31 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
         GDALColorEntry	sEntry;
 
         GDALGetColorEntryAsRGB( hColorTable, iColor, &sEntry );
-        
-        anPCT[iColor    ] = sEntry.c1;
-        anPCT[iColor+256] = sEntry.c2;
-        anPCT[iColor+512] = sEntry.c3;
+        CAST_PCT(anPCT)[4*iColor+0] = sEntry.c1;
+        CAST_PCT(anPCT)[4*iColor+1] = sEntry.c2;
+        CAST_PCT(anPCT)[4*iColor+2] = sEntry.c3;
+        CAST_PCT(anPCT)[4*iColor+3] = 0;
     }
-    
-/* -------------------------------------------------------------------- */
-/*      Build a 24bit to 8 bit color mapping.                           */
-/* -------------------------------------------------------------------- */
-    GByte	*pabyColorMap;
-
-    pabyColorMap = (GByte *) CPLMalloc(C_LEVELS * C_LEVELS * C_LEVELS 
-                                       * sizeof(int));
-    
-    FindNearestColor( nColors, anPCT, pabyColorMap );
+#ifdef USE_SSE2
+    /* Pad to multiple of 8 colors */
+    int nColorsMod8 = nColors % 8;
+    if( nColorsMod8 )
+    {
+        for( iColor = 0; iColor < 8 - nColorsMod8; iColor ++)
+        {
+            anPCT[nColors+iColor] = anPCT[nColors-1];
+        }
+    }
+#endif
 
 /* -------------------------------------------------------------------- */
 /*      Setup various variables.                                        */
 /* -------------------------------------------------------------------- */
-    GByte	*pabyRed, *pabyGreen, *pabyBlue, *pabyIndex;
-    int		*panError;
+    GByte   *pabyRed, *pabyGreen, *pabyBlue, *pabyIndex;
+    GByte   *pabyColorMap = NULL;
+    int     *panError;
+    int nCLevels = 1 << nBits;
+    ColorIndex* psColorIndexMap = NULL;
 
     pabyRed = (GByte *) VSIMalloc(nXSize);
     pabyGreen = (GByte *) VSIMalloc(nXSize);
@@ -208,6 +265,41 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
         goto end_and_cleanup;
     }
 
+    if( pasDynamicColorMap == NULL )
+    {
+/* -------------------------------------------------------------------- */
+/*      Build a 24bit to 8 bit color mapping.                           */
+/* -------------------------------------------------------------------- */
+
+        pabyColorMap = (GByte *) VSIMalloc(nCLevels * nCLevels * nCLevels 
+                                        * sizeof(GByte));
+        if( pabyColorMap == NULL )
+        {
+            CPLError( CE_Failure, CPLE_OutOfMemory,
+                  "VSIMalloc(): Out of memory in GDALDitherRGB2PCT" );
+            err = CE_Failure;
+            goto end_and_cleanup;
+        }
+
+        FindNearestColor( nColors, anPCT, pabyColorMap, nCLevels);
+    }
+    else
+    {
+        pabyColorMap = NULL;
+        if( nBits == 8 && (GIntBig)nXSize * nYSize <= 65536 )
+        {
+            /* If the image is small enough, then the number of colors */
+            /* will be limited and using a hashmap, rather than a full table */
+            /* will be more efficient */
+            psColorIndexMap = (ColorIndex*)pasDynamicColorMap;
+            memset(psColorIndexMap, 0xFF, sizeof(ColorIndex) * PRIME_FOR_65536);
+        }
+        else
+        {
+            memset(pasDynamicColorMap, 0xFF, 256 * 256 * 256 * sizeof(GInt16));
+        }
+    }
+
 /* ==================================================================== */
 /*      Loop over all scanlines of data to process.                     */
 /* ==================================================================== */
@@ -240,17 +332,20 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
 /* -------------------------------------------------------------------- */
 /*	Apply the error from the previous line to this one.		*/
 /* -------------------------------------------------------------------- */
-        for( i = 0; i < nXSize; i++ )
+        if( bDither )
         {
+          for( i = 0; i < nXSize; i++ )
+          {
             pabyRed[i] = (GByte)
                 MAX(0,MIN(255,(pabyRed[i]   + panError[i*3+0+3])));
             pabyGreen[i] = (GByte)
                 MAX(0,MIN(255,(pabyGreen[i] + panError[i*3+1+3])));
             pabyBlue[i] =  (GByte)
                 MAX(0,MIN(255,(pabyBlue[i]  + panError[i*3+2+3])));
-        }
+          }
 
-        memset( panError, 0, sizeof(int) * (nXSize+2) * 3 );
+          memset( panError, 0, sizeof(int) * (nXSize+2) * 3 );
+        }
 
 /* -------------------------------------------------------------------- */
 /*	Figure out the nearest color to the RGB value.			*/
@@ -261,26 +356,112 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
 
         for( i = 0; i < nXSize; i++ )
         {
-            int		iIndex, nError, nSixth, iRed, iGreen, iBlue;
+            int		iIndex, nError, nSixth;
             int		nRedValue, nGreenValue, nBlueValue;
 
             nRedValue =   MAX(0,MIN(255, pabyRed[i]   + nLastRedError));
             nGreenValue = MAX(0,MIN(255, pabyGreen[i] + nLastGreenError));
             nBlueValue =  MAX(0,MIN(255, pabyBlue[i]  + nLastBlueError));
 
-            iRed   = nRedValue *   C_LEVELS   / 256;
-            iGreen = nGreenValue * C_LEVELS / 256;
-            iBlue  = nBlueValue *  C_LEVELS  / 256;
-            
-            iIndex = pabyColorMap[iRed + iGreen * C_LEVELS 
-                                 + iBlue * C_LEVELS * C_LEVELS];
-	
+            if( psColorIndexMap )
+            {
+                GUInt32 nColorCode = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
+                GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
+                //int nCollisions = 0;
+                //static int nMaxCollisions = 0;
+                while( TRUE )
+                {
+                    if( psColorIndexMap[nIdx].nColorCode == nColorCode )
+                    {
+                        iIndex = psColorIndexMap[nIdx].nIndex;
+                        break;
+                    }
+                    if( (int)psColorIndexMap[nIdx].nColorCode < 0 )
+                    {
+                        psColorIndexMap[nIdx].nColorCode = nColorCode;
+                        iIndex = FindNearestColor( nColors, anPCT,
+                                                   nRedValue, nGreenValue, nBlueValue );
+                        psColorIndexMap[nIdx].nIndex = (GByte) iIndex;
+                        break;
+                    }
+                    if( psColorIndexMap[nIdx].nColorCode2 == nColorCode )
+                    {
+                        iIndex = psColorIndexMap[nIdx].nIndex2;
+                        break;
+                    }
+                    if( (int)psColorIndexMap[nIdx].nColorCode2 < 0 )
+                    {
+                        psColorIndexMap[nIdx].nColorCode2 = nColorCode;
+                        iIndex = FindNearestColor( nColors, anPCT,
+                                                   nRedValue, nGreenValue, nBlueValue );
+                        psColorIndexMap[nIdx].nIndex2 = (GByte) iIndex;
+                        break;
+                    }
+                    if( psColorIndexMap[nIdx].nColorCode3 == nColorCode )
+                    {
+                        iIndex = psColorIndexMap[nIdx].nIndex3;
+                        break;
+                    }
+                    if( (int)psColorIndexMap[nIdx].nColorCode3 < 0 )
+                    {
+                        psColorIndexMap[nIdx].nColorCode3 = nColorCode;
+                        iIndex = FindNearestColor( nColors, anPCT,
+                                                   nRedValue, nGreenValue, nBlueValue );
+                        psColorIndexMap[nIdx].nIndex3 = (GByte) iIndex;
+                        break;
+                    }
+
+                    do
+                    {
+                        //nCollisions ++;
+                        nIdx+=257;
+                        if( nIdx >= PRIME_FOR_65536 )
+                            nIdx -= PRIME_FOR_65536;
+                    }
+                    while( (int)psColorIndexMap[nIdx].nColorCode >= 0 &&
+                            psColorIndexMap[nIdx].nColorCode != nColorCode &&
+                            (int)psColorIndexMap[nIdx].nColorCode2 >= 0 &&
+                            psColorIndexMap[nIdx].nColorCode2 != nColorCode&&
+                            (int)psColorIndexMap[nIdx].nColorCode3 >= 0 &&
+                            psColorIndexMap[nIdx].nColorCode3 != nColorCode );
+                    /*if( nCollisions > nMaxCollisions )
+                    {
+                        nMaxCollisions = nCollisions;
+                        printf("nCollisions = %d for R=%d,G=%d,B=%d\n",
+                                nCollisions, nRedValue, nGreenValue, nBlueValue);
+                    }*/
+                }
+            }
+            else if( pasDynamicColorMap == NULL )
+            {
+                int iRed   = nRedValue *   nCLevels   / 256;
+                int iGreen = nGreenValue * nCLevels / 256;
+                int iBlue  = nBlueValue *  nCLevels  / 256;
+                
+                iIndex = pabyColorMap[iRed + iGreen * nCLevels 
+                                    + iBlue * nCLevels * nCLevels];
+            }
+            else
+            {
+                GUInt32 nColorCode = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
+                GInt16* psIndex = &pasDynamicColorMap[nColorCode];
+                if( *psIndex < 0 )
+                    iIndex = *psIndex = FindNearestColor( nColors, anPCT,
+                                                          nRedValue,
+                                                          nGreenValue,
+                                                          nBlueValue );
+                else
+                    iIndex = *psIndex;
+            }
+
             pabyIndex[i] = (GByte) iIndex;
+            if( !bDither )
+                continue;
 
 /* -------------------------------------------------------------------- */
 /*      Compute Red error, and carry it on to the next error line.      */
 /* -------------------------------------------------------------------- */
-            nError = nRedValue - anPCT[iIndex    ];
+            nError = nRedValue - CAST_PCT(anPCT)[4*iIndex+0];
             nSixth = nError / 6;
             
             panError[i*3    ] += nSixth;
@@ -292,7 +473,7 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
 /* -------------------------------------------------------------------- */
 /*      Compute Green error, and carry it on to the next error line.    */
 /* -------------------------------------------------------------------- */
-            nError = nGreenValue - anPCT[iIndex+256];
+            nError = nGreenValue - CAST_PCT(anPCT)[4*iIndex+1];
             nSixth = nError / 6;
 
             panError[i*3  +1] += nSixth;
@@ -304,7 +485,7 @@ GDALDitherRGB2PCT( GDALRasterBandH hRed,
 /* -------------------------------------------------------------------- */
 /*      Compute Blue error, and carry it on to the next error line.     */
 /* -------------------------------------------------------------------- */
-            nError = nBlueValue - anPCT[iIndex+512];
+            nError = nBlueValue - CAST_PCT(anPCT)[4*iIndex+2];
             nSixth = nError / 6;
             
             panError[i*3  +2] += nSixth;
@@ -337,53 +518,139 @@ end_and_cleanup:
     return err;
 }
 
+static int FindNearestColor( int nColors, int *panPCT,
+                             int nRedValue, int nGreenValue, int nBlueValue )
+
+{
+#ifdef USE_SSE2
+    int     iColor;
+
+    int nBestDist = 768, nBestIndex = 0;
+
+    int     anDistanceUnaligned[16+4]; /* 4 for alignment on 16-byte boundary */
+    int* anDistance = ALIGN_INT_ARRAY_ON_16_BYTE(anDistanceUnaligned);
+
+    const __m128i ff = _mm_set1_epi32(0xFFFFFFFF);
+    const __m128i mask_low = _mm_srli_epi64(ff, 32);
+    const __m128i mask_high = _mm_slli_epi64(ff, 32);
+
+    unsigned int nColorVal = MAKE_COLOR_CODE(nRedValue, nGreenValue, nBlueValue);
+    const __m128i thisColor = _mm_set1_epi32(nColorVal);
+    const __m128i thisColor_low = _mm_srli_epi64(thisColor, 32);
+    const __m128i thisColor_high = _mm_slli_epi64(thisColor, 32);
+
+    for( iColor = 0; iColor < nColors; iColor+=8 )
+    {
+        __m128i pctColor = _mm_load_si128((__m128i*)&panPCT[iColor]);
+        __m128i pctColor2 = _mm_load_si128((__m128i*)&panPCT[iColor+4]);
+
+        _mm_store_si128((__m128i*)anDistance,
+                        _mm_sad_epu8(_mm_and_si128(pctColor,mask_low),thisColor_low));
+        _mm_store_si128((__m128i*)(anDistance+4),
+                        _mm_sad_epu8(_mm_and_si128(pctColor,mask_high),thisColor_high));
+        _mm_store_si128((__m128i*)(anDistance+8),
+                        _mm_sad_epu8(_mm_and_si128(pctColor2,mask_low),thisColor_low));
+        _mm_store_si128((__m128i*)(anDistance+12),
+                        _mm_sad_epu8(_mm_and_si128(pctColor2,mask_high),thisColor_high));
+
+        if( anDistance[0] < nBestDist )
+        {
+            nBestIndex = iColor;
+            nBestDist = anDistance[0];
+        }
+        if( anDistance[4] < nBestDist )
+        {
+            nBestIndex = iColor+1;
+            nBestDist = anDistance[4];
+        }
+        if( anDistance[2] < nBestDist )
+        {
+            nBestIndex = iColor+2;
+            nBestDist = anDistance[2];
+        }
+        if( anDistance[6] < nBestDist )
+        {
+            nBestIndex = iColor+3;
+            nBestDist = anDistance[6];
+        }
+        if( anDistance[8+0] < nBestDist )
+        {
+            nBestIndex = iColor+4;
+            nBestDist = anDistance[8+0];
+        }
+        if( anDistance[8+4] < nBestDist )
+        {
+            nBestIndex = iColor+4+1;
+            nBestDist = anDistance[8+4];
+        }
+        if( anDistance[8+2] < nBestDist )
+        {
+            nBestIndex = iColor+4+2;
+            nBestDist = anDistance[8+2];
+        }
+        if( anDistance[8+6] < nBestDist )
+        {
+            nBestIndex = iColor+4+3;
+            nBestDist = anDistance[8+6];
+        }
+    }
+    return nBestIndex;
+#else
+    int     iColor;
+
+    int nBestDist = 768, nBestIndex = 0;
+
+    for( iColor = 0; iColor < nColors; iColor++ )
+    {
+        int     nThisDist;
+
+        nThisDist = ABS(nRedValue   - panPCT[4*iColor+0]) 
+                  + ABS(nGreenValue - panPCT[4*iColor+1])
+                  + ABS(nBlueValue  - panPCT[4*iColor+2]);
+
+        if( nThisDist < nBestDist )
+        {
+            nBestIndex = iColor;
+            nBestDist = nThisDist;
+        }
+    }
+    return nBestIndex;
+#endif
+}
+
+
 /************************************************************************/
 /*                          FindNearestColor()                          */
 /*                                                                      */
 /*      Finear near PCT color for any RGB color.                        */
 /************************************************************************/
 
-static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap )
+static void FindNearestColor( int nColors, int *panPCT, GByte *pabyColorMap,
+                              int nCLevels )
 
 {
-    int		iBlue, iGreen, iRed;
-    int		iColor;
+    int     iBlue, iGreen, iRed;
 
 /* -------------------------------------------------------------------- */
-/*	Loop over all the cells in the high density cube.		*/
+/*  Loop over all the cells in the high density cube.       */
 /* -------------------------------------------------------------------- */
-    for( iBlue = 0; iBlue < C_LEVELS; iBlue++ )
+    for( iBlue = 0; iBlue < nCLevels; iBlue++ )
     {
-	for( iGreen = 0; iGreen < C_LEVELS; iGreen++ )
-	{
-	    for( iRed = 0; iRed < C_LEVELS; iRed++ )
-	    {
-		int  	nRedValue, nGreenValue, nBlueValue;
-		int	nBestDist = 768, nBestIndex = 0;
-
-		nRedValue   = (iRed * 255) / (C_LEVELS-1);
-		nGreenValue = (iGreen * 255) / (C_LEVELS-1);
-		nBlueValue  = (iBlue * 255) / (C_LEVELS-1);
-
-		for( iColor = 0; iColor < nColors; iColor++ )
-		{
-		    int		nThisDist;
-
-		    nThisDist = ABS(nRedValue   - panPCT[iColor    ]) 
-		              + ABS(nGreenValue - panPCT[iColor+256])
-		              + ABS(nBlueValue  - panPCT[iColor+512]);
-
-		    if( nThisDist < nBestDist )
-		    {
-			nBestIndex = iColor;
-			nBestDist = nThisDist;
-		    }
-		}
-		
-		pabyColorMap[iRed + iGreen*C_LEVELS 
-                            + iBlue*C_LEVELS*C_LEVELS] = (GByte)nBestIndex;
-	    }
-	}
+        for( iGreen = 0; iGreen < nCLevels; iGreen++ )
+        {
+            for( iRed = 0; iRed < nCLevels; iRed++ )
+            {
+                int     nRedValue, nGreenValue, nBlueValue;
+
+                nRedValue   = (iRed * 255) / (nCLevels-1);
+                nGreenValue = (iGreen * 255) / (nCLevels-1);
+                nBlueValue  = (iBlue * 255) / (nCLevels-1);
+
+                int nBestIndex = FindNearestColor( nColors, panPCT,
+                                        nRedValue, nGreenValue, nBlueValue );
+                pabyColorMap[iRed + iGreen*nCLevels 
+                                    + iBlue*nCLevels*nCLevels] = (GByte)nBestIndex;
+            }
+        }
     }
 }
-
diff --git a/alg/gdalgeoloc.cpp b/alg/gdalgeoloc.cpp
index e5e0c9d..e701da4 100644
--- a/alg/gdalgeoloc.cpp
+++ b/alg/gdalgeoloc.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalgeoloc.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalgeoloc.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implements Geolocation array based transformer.
@@ -38,7 +38,7 @@ SHPHandle hSHP = NULL;
 DBFHandle hDBF = NULL;
 #endif
 
-CPL_CVSID("$Id: gdalgeoloc.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdalgeoloc.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 CPLXMLNode *GDALSerializeGeoLocTransformer( void *pTransformArg );
@@ -706,6 +706,47 @@ static int FindGeoLocPosition( GDALGeoLocTransformInfo *psTransform,
 #endif /* def notdef */
 
 
+/************************************************************************/
+/*                       GDALGeoLocRescale()                            */
+/************************************************************************/
+
+static void GDALGeoLocRescale(char**& papszMD, const char* pszItem,
+                                  double dfRatio, double dfDefaultVal)
+{
+    double dfVal = CPLAtofM(CSLFetchNameValueDef(papszMD, pszItem,
+                                            CPLSPrintf("%.18g", dfDefaultVal)));
+    dfVal *= dfRatio;
+    papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
+}
+
+/************************************************************************/
+/*                 GDALCreateSimilarGeoLocTransformer()                 */
+/************************************************************************/
+
+static
+void* GDALCreateSimilarGeoLocTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
+{
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarGeoLocTransformer", NULL );
+
+    GDALGeoLocTransformInfo *psInfo = (GDALGeoLocTransformInfo *) hTransformArg;
+    
+    char** papszGeolocationInfo = CSLDuplicate(psInfo->papszGeolocationInfo);
+
+    if( dfRatioX != 1.0 || dfRatioY != 1.0 )
+    {
+        GDALGeoLocRescale(papszGeolocationInfo, "PIXEL_OFFSET", dfRatioX, 0.0);
+        GDALGeoLocRescale(papszGeolocationInfo, "LINE_OFFSET", dfRatioY, 0.0);
+        GDALGeoLocRescale(papszGeolocationInfo, "PIXEL_STEP", 1.0 / dfRatioX, 1.0);
+        GDALGeoLocRescale(papszGeolocationInfo, "LINE_STEP", 1.0 / dfRatioY, 1.0);
+    }
+
+    psInfo = (GDALGeoLocTransformInfo*) GDALCreateGeoLocTransformer(
+        NULL, papszGeolocationInfo, psInfo->bReversed );
+    
+    CSLDestroy(papszGeolocationInfo);
+
+    return psInfo;
+}
 
 /************************************************************************/
 /*                    GDALCreateGeoLocTransformer()                     */
@@ -738,23 +779,25 @@ void *GDALCreateGeoLocTransformer( GDALDatasetH hBaseDS,
 
     psTransform->bReversed = bReversed;
 
-    strcpy( psTransform->sTI.szSignature, "GTI" );
+    memcpy( psTransform->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psTransform->sTI.pszClassName = "GDALGeoLocTransformer";
     psTransform->sTI.pfnTransform = GDALGeoLocTransform;
     psTransform->sTI.pfnCleanup = GDALDestroyGeoLocTransformer;
     psTransform->sTI.pfnSerialize = GDALSerializeGeoLocTransformer;
+    psTransform->sTI.pfnCreateSimilar = GDALCreateSimilarGeoLocTransformer;
+    
     psTransform->papszGeolocationInfo = CSLDuplicate( papszGeolocationInfo );
 
 /* -------------------------------------------------------------------- */
 /*      Pull geolocation info from the options/metadata.                */
 /* -------------------------------------------------------------------- */
-    psTransform->dfPIXEL_OFFSET = atof(CSLFetchNameValue( papszGeolocationInfo,
+    psTransform->dfPIXEL_OFFSET = CPLAtof(CSLFetchNameValue( papszGeolocationInfo,
                                                           "PIXEL_OFFSET" ));
-    psTransform->dfLINE_OFFSET = atof(CSLFetchNameValue( papszGeolocationInfo,
+    psTransform->dfLINE_OFFSET = CPLAtof(CSLFetchNameValue( papszGeolocationInfo,
                                                          "LINE_OFFSET" ));
-    psTransform->dfPIXEL_STEP = atof(CSLFetchNameValue( papszGeolocationInfo,
+    psTransform->dfPIXEL_STEP = CPLAtof(CSLFetchNameValue( papszGeolocationInfo,
                                                         "PIXEL_STEP" ));
-    psTransform->dfLINE_STEP = atof(CSLFetchNameValue( papszGeolocationInfo,
+    psTransform->dfLINE_STEP = CPLAtof(CSLFetchNameValue( papszGeolocationInfo,
                                                        "LINE_STEP" ));
 
 /* -------------------------------------------------------------------- */
@@ -894,13 +937,14 @@ void GDALDestroyGeoLocTransformer( void *pTransformAlg )
 /*                        GDALGeoLocTransform()                         */
 /************************************************************************/
 
-int GDALGeoLocTransform( void *pTransformArg, int bDstToSrc, 
-                         int nPointCount, 
-                         double *padfX, double *padfY, CPL_UNUSED double *padfZ,
+int GDALGeoLocTransform( void *pTransformArg,
+                         int bDstToSrc,
+                         int nPointCount,
+                         double *padfX, double *padfY,
+                         CPL_UNUSED double *padfZ,
                          int *panSuccess )
-
 {
-    GDALGeoLocTransformInfo *psTransform = 
+    GDALGeoLocTransformInfo *psTransform =
         (GDALGeoLocTransformInfo *) pTransformArg;
 
     if( psTransform->bReversed )
diff --git a/alg/gdalgrid.cpp b/alg/gdalgrid.cpp
index 0e2642d..c0a8e8b 100644
--- a/alg/gdalgrid.cpp
+++ b/alg/gdalgrid.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalgrid.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalgrid.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  GDAL Gridding API.
  * Purpose:  Implementation of GDAL scattered data gridder.
@@ -36,11 +36,7 @@
 #include "cpl_multiproc.h"
 #include "gdalgrid_priv.h"
 
-#ifdef HAVE_SSE_AT_COMPILE_TIME
-#include <xmmintrin.h>
-#endif
-
-CPL_CVSID("$Id: gdalgrid.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdalgrid.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 #define TO_RADIANS (3.14159265358979323846 / 180.0)
 
@@ -53,74 +49,6 @@ CPL_CVSID("$Id: gdalgrid.cpp 27729 2014-09-24 00:40:16Z goatbar $");
 #endif /* DBL_MAX */
 
 /************************************************************************/
-/*                          CPLHaveRuntimeSSE()                         */
-/************************************************************************/
-
-#ifdef HAVE_SSE_AT_COMPILE_TIME
-
-#define CPUID_SSE_EDX_BIT     25
-
-#if (defined(_M_X64) || defined(__x86_64))
-
-static int CPLHaveRuntimeSSE()
-{
-    return TRUE;
-}
-
-#elif defined(__GNUC__) && defined(__i386__)
-
-static int CPLHaveRuntimeSSE()
-{
-    int cpuinfo[4] = {0,0,0,0};
-    GCC_CPUID(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
-    return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
-}
-
-#elif defined(_MSC_VER) && defined(_M_IX86)
-
-#if _MSC_VER <= 1310
-static void inline __cpuid(int cpuinfo[4], int level)
-{
-    __asm 
-    {
-        push   ebx
-        push   esi
-
-        mov    esi,cpuinfo
-        mov    eax,level  
-        cpuid  
-        mov    dword ptr [esi], eax
-        mov    dword ptr [esi+4],ebx  
-        mov    dword ptr [esi+8],ecx  
-        mov    dword ptr [esi+0Ch],edx 
-
-        pop    esi
-        pop    ebx
-    }
-}
-#else
-#include <intrin.h>
-#endif
-
-static int CPLHaveRuntimeSSE()
-{
-    int cpuinfo[4] = {0,0,0,0};
-    __cpuid(cpuinfo, 1);
-    return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
-}
-
-#else
-
-static int CPLHaveRuntimeSSE()
-{
-    return FALSE;
-}
-
-#endif
-
-#endif // HAVE_SSE_AT_COMPILE_TIME
-
-/************************************************************************/
 /*                        GDALGridGetPointBounds()                      */
 /************************************************************************/
 
@@ -394,148 +322,6 @@ GDALGridInverseDistanceToAPowerNoSearch( const void *poOptions, GUInt32 nPoints,
 }
 
 /************************************************************************/
-/*         GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE()     */
-/************************************************************************/
-
-#ifdef HAVE_SSE_AT_COMPILE_TIME
-
-static CPLErr
-GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
-                                        const void *poOptions,
-                                        GUInt32 nPoints,
-                                        CPL_UNUSED const double *unused_padfX,
-                                        CPL_UNUSED const double *unused_padfY,
-                                        CPL_UNUSED const double *unused_padfZ,
-                                        double dfXPoint, double dfYPoint,
-                                        double *pdfValue,
-                                        void* hExtraParamsIn )
-{
-    size_t i = 0;
-    GDALGridExtraParameters* psExtraParams = (GDALGridExtraParameters*) hExtraParamsIn;
-    const float* pafX = psExtraParams->pafX;
-    const float* pafY = psExtraParams->pafY;
-    const float* pafZ = psExtraParams->pafZ;
-
-    const float fEpsilon = 0.0000000000001f;
-    const float fXPoint = (float)dfXPoint;
-    const float fYPoint = (float)dfYPoint;
-    const __m128 xmm_small = _mm_load1_ps((float*)&fEpsilon);
-    const __m128 xmm_x = _mm_load1_ps((float*)&fXPoint);
-    const __m128 xmm_y = _mm_load1_ps((float*)&fYPoint);
-    __m128 xmm_nominator = _mm_setzero_ps();
-    __m128 xmm_denominator = _mm_setzero_ps();
-    int mask = 0;
-
-#if defined(__x86_64) || defined(_M_X64)
-    /* This would also work in 32bit mode, but there are only 8 XMM registers */
-    /* whereas we have 16 for 64bit */
-#define LOOP_SIZE   8
-    size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
-    for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
-    {
-        __m128 xmm_rx = _mm_sub_ps(_mm_load_ps(pafX + i), xmm_x);            /* rx = pafX[i] - fXPoint */
-        __m128 xmm_rx_4 = _mm_sub_ps(_mm_load_ps(pafX + i + 4), xmm_x);
-        __m128 xmm_ry = _mm_sub_ps(_mm_load_ps(pafY + i), xmm_y);            /* ry = pafY[i] - fYPoint */
-        __m128 xmm_ry_4 = _mm_sub_ps(_mm_load_ps(pafY + i + 4), xmm_y);
-        __m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx),               /* r2 = rx * rx + ry * ry */
-                                   _mm_mul_ps(xmm_ry, xmm_ry));
-        __m128 xmm_r2_4 = _mm_add_ps(_mm_mul_ps(xmm_rx_4, xmm_rx_4),
-                                     _mm_mul_ps(xmm_ry_4, xmm_ry_4));
-        __m128 xmm_invr2 = _mm_rcp_ps(xmm_r2);                               /* invr2 = 1.0f / r2 */
-        __m128 xmm_invr2_4 = _mm_rcp_ps(xmm_r2_4);
-        xmm_nominator = _mm_add_ps(xmm_nominator,                            /* nominator += invr2 * pafZ[i] */
-                            _mm_mul_ps(xmm_invr2, _mm_load_ps(pafZ + i)));
-        xmm_nominator = _mm_add_ps(xmm_nominator,
-                            _mm_mul_ps(xmm_invr2_4, _mm_load_ps(pafZ + i + 4)));
-        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2);           /* denominator += invr2 */
-        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2_4);
-        mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)) |           /* if( r2 < fEpsilon) */
-              (_mm_movemask_ps(_mm_cmplt_ps(xmm_r2_4, xmm_small)) << 4);
-        if( mask )
-            break;
-    }
-#else
-#define LOOP_SIZE   4
-    size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
-    for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
-    {
-        __m128 xmm_rx = _mm_sub_ps(_mm_load_ps((float*)pafX + i), xmm_x);           /* rx = pafX[i] - fXPoint */
-        __m128 xmm_ry = _mm_sub_ps(_mm_load_ps((float*)pafY + i), xmm_y);           /* ry = pafY[i] - fYPoint */
-        __m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx),              /* r2 = rx * rx + ry * ry */
-                                   _mm_mul_ps(xmm_ry, xmm_ry));
-        __m128 xmm_invr2 = _mm_rcp_ps(xmm_r2);                              /* invr2 = 1.0f / r2 */
-        xmm_nominator = _mm_add_ps(xmm_nominator,                           /* nominator += invr2 * pafZ[i] */
-                            _mm_mul_ps(xmm_invr2, _mm_load_ps((float*)pafZ + i)));
-        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2);           /* denominator += invr2 */
-        mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small));            /* if( r2 < fEpsilon) */
-        if( mask )
-            break;
-    }
-#endif
-
-    /* Find which i triggered r2 < fEpsilon */
-    if( mask )
-    {
-        for(int j = 0; j < LOOP_SIZE; j++ )
-        {
-            if( mask & (1 << j) )
-            {
-                (*pdfValue) = (pafZ)[i + j];
-                return CE_None;
-            }
-        }
-    }
-
-    /* Get back nominator and denominator values for XMM registers */
-    float afNominator[4], afDenominator[4];
-    _mm_storeu_ps(afNominator, xmm_nominator);
-    _mm_storeu_ps(afDenominator, xmm_denominator);
-
-    float fNominator = afNominator[0] + afNominator[1] +
-                       afNominator[2] + afNominator[3];
-    float fDenominator = afDenominator[0] + afDenominator[1] +
-                         afDenominator[2] + afDenominator[3];
-
-    /* Do the few remaining loop iterations */
-    for ( ; i < nPoints; i++ )
-    {
-        const float fRX = pafX[i] - fXPoint;
-        const float fRY = pafY[i] - fYPoint;
-        const float fR2 =
-            fRX * fRX + fRY * fRY;
-
-        // If the test point is close to the grid node, use the point
-        // value directly as a node value to avoid singularity.
-        if ( fR2 < 0.0000000000001 )
-        {
-            break;
-        }
-        else
-        {
-            const float fInvR2 = 1.0f / fR2;
-            fNominator += fInvR2 * pafZ[i];
-            fDenominator += fInvR2;
-        }
-    }
-
-    if( i != nPoints )
-    {
-        (*pdfValue) = pafZ[i];
-    }
-    else
-    if ( fDenominator == 0.0 )
-    {
-        (*pdfValue) =
-            ((GDALGridInverseDistanceToAPowerOptions*)poOptions)->dfNoDataValue;
-    }
-    else
-        (*pdfValue) = fNominator / fDenominator;
-
-    return CE_None;
-}
-#endif // HAVE_SSE_AT_COMPILE_TIME
-
-/************************************************************************/
 /*                        GDALGridMovingAverage()                       */
 /************************************************************************/
 
@@ -1507,11 +1293,11 @@ struct _GDALGridJob
     int               (*pfnProgress)(GDALGridJob* psJob);
     GDALDataType        eType;
 
-    void           *hThread;
+    CPLJoinableThread  *hThread;
     volatile int   *pnCounter;
     volatile int   *pbStop;
-    void           *hCond;
-    void           *hCondMutex;
+    CPLCond        *hCond;
+    CPLMutex       *hCondMutex;
 
     GDALProgressFunc pfnRealProgress;
     void *pRealProgressArg;
@@ -2045,17 +1831,17 @@ GDALGridCreate( GDALGridAlgorithm eAlgorithm, const void *poOptions,
 /*      defaults.                                                       */
 /************************************************************************/
 
-CPLErr ParseAlgorithmAndOptions( const char *pszAlgoritm,
+CPLErr ParseAlgorithmAndOptions( const char *pszAlgorithm,
                                  GDALGridAlgorithm *peAlgorithm,
                                  void **ppOptions )
 {
-    CPLAssert( pszAlgoritm );
+    CPLAssert( pszAlgorithm );
     CPLAssert( peAlgorithm );
     CPLAssert( ppOptions );
 
     *ppOptions = NULL;
 
-    char **papszParms = CSLTokenizeString2( pszAlgoritm, ":", FALSE );
+    char **papszParms = CSLTokenizeString2( pszAlgorithm, ":", FALSE );
 
     if ( CSLCount(papszParms) < 1 )
         return CE_Failure;
@@ -2212,4 +1998,3 @@ CPLErr ParseAlgorithmAndOptions( const char *pszAlgoritm,
     CSLDestroy( papszParms );
     return CE_None;
 }
-
diff --git a/alg/gdalgrid_priv.h b/alg/gdalgrid_priv.h
index 61aaa9d..02f3540 100644
--- a/alg/gdalgrid_priv.h
+++ b/alg/gdalgrid_priv.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalgrid_priv.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalgrid_priv.h 28033 2014-11-30 16:37:24Z rouault $
  *
  * Project:  GDAL Gridding API.
  * Purpose:  Prototypes, and definitions for of GDAL scattered data gridder.
@@ -51,6 +51,21 @@ typedef struct
     const float *pafZ;
 } GDALGridExtraParameters;
 
+#ifdef HAVE_SSE_AT_COMPILE_TIME
+int CPLHaveRuntimeSSE();
+
+CPLErr
+GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
+                                        const void *poOptions,
+                                        GUInt32 nPoints,
+                                        const double *unused_padfX,
+                                        const double *unused_padfY,
+                                        const double *unused_padfZ,
+                                        double dfXPoint, double dfYPoint,
+                                        double *pdfValue,
+                                        void* hExtraParamsIn );
+#endif
+
 #ifdef HAVE_AVX_AT_COMPILE_TIME
 int CPLHaveRuntimeAVX();
 
diff --git a/alg/gdalgridavx.cpp b/alg/gdalgridavx.cpp
index d67c685..528388d 100644
--- a/alg/gdalgridavx.cpp
+++ b/alg/gdalgridavx.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalgridavx.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalgridavx.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GDAL Gridding API.
  * Purpose:  Implementation of GDAL scattered data gridder.
@@ -33,7 +33,7 @@
 #ifdef HAVE_AVX_AT_COMPILE_TIME
 #include <immintrin.h>
 
-CPL_CVSID("$Id: gdalgridavx.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdalgridavx.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          CPLHaveRuntimeAVX()                         */
@@ -83,14 +83,14 @@ int CPLHaveRuntimeAVX()
 
 CPLErr
 GDALGridInverseDistanceToAPower2NoSmoothingNoSearchAVX(
-                                        const void *poOptions,
-                                        GUInt32 nPoints,
-                                        CPL_UNUSED const double *unused_padfX,
-                                        CPL_UNUSED const double *unused_padfY,
-                                        CPL_UNUSED const double *unused_padfZ,
-                                        double dfXPoint, double dfYPoint,
-                                        double *pdfValue,
-                                        void* hExtraParamsIn )
+    const void *poOptions,
+    GUInt32 nPoints,
+    CPL_UNUSED const double *unused_padfX,
+    CPL_UNUSED const double *unused_padfY,
+    CPL_UNUSED const double *unused_padfZ,
+    double dfXPoint, double dfYPoint,
+    double *pdfValue,
+    void* hExtraParamsIn )
 {
     size_t i = 0;
     GDALGridExtraParameters* psExtraParams = (GDALGridExtraParameters*) hExtraParamsIn;
diff --git a/alg/gdalgridsse.cpp b/alg/gdalgridsse.cpp
new file mode 100644
index 0000000..e7bb675
--- /dev/null
+++ b/alg/gdalgridsse.cpp
@@ -0,0 +1,241 @@
+/******************************************************************************
+ * $Id: gdalgridsse.cpp 28033 2014-11-30 16:37:24Z rouault $
+ *
+ * Project:  GDAL Gridding API.
+ * Purpose:  Implementation of GDAL scattered data gridder.
+ * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdalgrid.h"
+#include "gdalgrid_priv.h"
+
+#ifdef HAVE_SSE_AT_COMPILE_TIME
+#include <xmmintrin.h>
+
+CPL_CVSID("$Id: gdalgridsse.cpp 28033 2014-11-30 16:37:24Z rouault $");
+
+/************************************************************************/
+/*                          CPLHaveRuntimeSSE()                         */
+/************************************************************************/
+
+#define CPUID_SSE_EDX_BIT     25
+
+#if (defined(_M_X64) || defined(__x86_64))
+
+int CPLHaveRuntimeSSE()
+{
+    return TRUE;
+}
+
+#elif defined(__GNUC__) && defined(__i386__)
+
+int CPLHaveRuntimeSSE()
+{
+    int cpuinfo[4] = {0,0,0,0};
+    GCC_CPUID(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
+    return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
+}
+
+#elif defined(_MSC_VER) && defined(_M_IX86)
+
+#if _MSC_VER <= 1310
+static void inline __cpuid(int cpuinfo[4], int level)
+{
+    __asm 
+    {
+        push   ebx
+        push   esi
+
+        mov    esi,cpuinfo
+        mov    eax,level  
+        cpuid  
+        mov    dword ptr [esi], eax
+        mov    dword ptr [esi+4],ebx  
+        mov    dword ptr [esi+8],ecx  
+        mov    dword ptr [esi+0Ch],edx 
+
+        pop    esi
+        pop    ebx
+    }
+}
+#else
+#include <intrin.h>
+#endif
+
+int CPLHaveRuntimeSSE()
+{
+    int cpuinfo[4] = {0,0,0,0};
+    __cpuid(cpuinfo, 1);
+    return (cpuinfo[3] & (1 << CPUID_SSE_EDX_BIT)) != 0;
+}
+
+#else
+
+int CPLHaveRuntimeSSE()
+{
+    return FALSE;
+}
+#endif
+
+/************************************************************************/
+/*         GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE()     */
+/************************************************************************/
+
+CPLErr
+GDALGridInverseDistanceToAPower2NoSmoothingNoSearchSSE(
+                                        const void *poOptions,
+                                        GUInt32 nPoints,
+                                        CPL_UNUSED const double *unused_padfX,
+                                        CPL_UNUSED const double *unused_padfY,
+                                        CPL_UNUSED const double *unused_padfZ,
+                                        double dfXPoint, double dfYPoint,
+                                        double *pdfValue,
+                                        void* hExtraParamsIn )
+{
+    size_t i = 0;
+    GDALGridExtraParameters* psExtraParams = (GDALGridExtraParameters*) hExtraParamsIn;
+    const float* pafX = psExtraParams->pafX;
+    const float* pafY = psExtraParams->pafY;
+    const float* pafZ = psExtraParams->pafZ;
+
+    const float fEpsilon = 0.0000000000001f;
+    const float fXPoint = (float)dfXPoint;
+    const float fYPoint = (float)dfYPoint;
+    const __m128 xmm_small = _mm_load1_ps((float*)&fEpsilon);
+    const __m128 xmm_x = _mm_load1_ps((float*)&fXPoint);
+    const __m128 xmm_y = _mm_load1_ps((float*)&fYPoint);
+    __m128 xmm_nominator = _mm_setzero_ps();
+    __m128 xmm_denominator = _mm_setzero_ps();
+    int mask = 0;
+
+#if defined(__x86_64) || defined(_M_X64)
+    /* This would also work in 32bit mode, but there are only 8 XMM registers */
+    /* whereas we have 16 for 64bit */
+#define LOOP_SIZE   8
+    size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
+    for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
+    {
+        __m128 xmm_rx = _mm_sub_ps(_mm_load_ps(pafX + i), xmm_x);            /* rx = pafX[i] - fXPoint */
+        __m128 xmm_rx_4 = _mm_sub_ps(_mm_load_ps(pafX + i + 4), xmm_x);
+        __m128 xmm_ry = _mm_sub_ps(_mm_load_ps(pafY + i), xmm_y);            /* ry = pafY[i] - fYPoint */
+        __m128 xmm_ry_4 = _mm_sub_ps(_mm_load_ps(pafY + i + 4), xmm_y);
+        __m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx),               /* r2 = rx * rx + ry * ry */
+                                   _mm_mul_ps(xmm_ry, xmm_ry));
+        __m128 xmm_r2_4 = _mm_add_ps(_mm_mul_ps(xmm_rx_4, xmm_rx_4),
+                                     _mm_mul_ps(xmm_ry_4, xmm_ry_4));
+        __m128 xmm_invr2 = _mm_rcp_ps(xmm_r2);                               /* invr2 = 1.0f / r2 */
+        __m128 xmm_invr2_4 = _mm_rcp_ps(xmm_r2_4);
+        xmm_nominator = _mm_add_ps(xmm_nominator,                            /* nominator += invr2 * pafZ[i] */
+                            _mm_mul_ps(xmm_invr2, _mm_load_ps(pafZ + i)));
+        xmm_nominator = _mm_add_ps(xmm_nominator,
+                            _mm_mul_ps(xmm_invr2_4, _mm_load_ps(pafZ + i + 4)));
+        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2);           /* denominator += invr2 */
+        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2_4);
+        mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small)) |           /* if( r2 < fEpsilon) */
+              (_mm_movemask_ps(_mm_cmplt_ps(xmm_r2_4, xmm_small)) << 4);
+        if( mask )
+            break;
+    }
+#else
+#define LOOP_SIZE   4
+    size_t nPointsRound = (nPoints / LOOP_SIZE) * LOOP_SIZE;
+    for ( i = 0; i < nPointsRound; i += LOOP_SIZE )
+    {
+        __m128 xmm_rx = _mm_sub_ps(_mm_load_ps((float*)pafX + i), xmm_x);           /* rx = pafX[i] - fXPoint */
+        __m128 xmm_ry = _mm_sub_ps(_mm_load_ps((float*)pafY + i), xmm_y);           /* ry = pafY[i] - fYPoint */
+        __m128 xmm_r2 = _mm_add_ps(_mm_mul_ps(xmm_rx, xmm_rx),              /* r2 = rx * rx + ry * ry */
+                                   _mm_mul_ps(xmm_ry, xmm_ry));
+        __m128 xmm_invr2 = _mm_rcp_ps(xmm_r2);                              /* invr2 = 1.0f / r2 */
+        xmm_nominator = _mm_add_ps(xmm_nominator,                           /* nominator += invr2 * pafZ[i] */
+                            _mm_mul_ps(xmm_invr2, _mm_load_ps((float*)pafZ + i)));
+        xmm_denominator = _mm_add_ps(xmm_denominator, xmm_invr2);           /* denominator += invr2 */
+        mask = _mm_movemask_ps(_mm_cmplt_ps(xmm_r2, xmm_small));            /* if( r2 < fEpsilon) */
+        if( mask )
+            break;
+    }
+#endif
+
+    /* Find which i triggered r2 < fEpsilon */
+    if( mask )
+    {
+        for(int j = 0; j < LOOP_SIZE; j++ )
+        {
+            if( mask & (1 << j) )
+            {
+                (*pdfValue) = (pafZ)[i + j];
+                return CE_None;
+            }
+        }
+    }
+
+    /* Get back nominator and denominator values for XMM registers */
+    float afNominator[4], afDenominator[4];
+    _mm_storeu_ps(afNominator, xmm_nominator);
+    _mm_storeu_ps(afDenominator, xmm_denominator);
+
+    float fNominator = afNominator[0] + afNominator[1] +
+                       afNominator[2] + afNominator[3];
+    float fDenominator = afDenominator[0] + afDenominator[1] +
+                         afDenominator[2] + afDenominator[3];
+
+    /* Do the few remaining loop iterations */
+    for ( ; i < nPoints; i++ )
+    {
+        const float fRX = pafX[i] - fXPoint;
+        const float fRY = pafY[i] - fYPoint;
+        const float fR2 =
+            fRX * fRX + fRY * fRY;
+
+        // If the test point is close to the grid node, use the point
+        // value directly as a node value to avoid singularity.
+        if ( fR2 < 0.0000000000001 )
+        {
+            break;
+        }
+        else
+        {
+            const float fInvR2 = 1.0f / fR2;
+            fNominator += fInvR2 * pafZ[i];
+            fDenominator += fInvR2;
+        }
+    }
+
+    if( i != nPoints )
+    {
+        (*pdfValue) = pafZ[i];
+    }
+    else
+    if ( fDenominator == 0.0 )
+    {
+        (*pdfValue) =
+            ((GDALGridInverseDistanceToAPowerOptions*)poOptions)->dfNoDataValue;
+    }
+    else
+        (*pdfValue) = fNominator / fDenominator;
+
+    return CE_None;
+}
+
+
+#endif /* HAVE_SSE_AT_COMPILE_TIME */
diff --git a/alg/gdalmediancut.cpp b/alg/gdalmediancut.cpp
index 735bfda..3e17858 100644
--- a/alg/gdalmediancut.cpp
+++ b/alg/gdalmediancut.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalmediancut.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalmediancut.cpp 28085 2014-12-07 14:36:00Z rouault $
  *
  * Project:  CIETMap Phase 2
  * Purpose:  Use median cut algorithm to generate an near-optimal PCT for a 
@@ -39,18 +39,23 @@
 
 #include "gdal_priv.h"
 #include "gdal_alg.h"
+#include "gdal_alg_priv.h"
 
-CPL_CVSID("$Id: gdalmediancut.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalmediancut.cpp 28085 2014-12-07 14:36:00Z rouault $");
 
-#define	MAX_CMAP_SIZE	256
+#define HISTOGRAM(h,n,r,g,b) h[((r)*(n)+(g))*(n)+(b)]
 
-#define	COLOR_DEPTH	8
-#define	MAX_COLOR	256
+#define MAKE_COLOR_CODE(r,g,b) ((r)+(g)*256+(b)*256*256)
 
-#define	GMC_B_DEPTH		5		/* # bits/pixel to use */
-#define	GMC_B_LEN		(1L<<GMC_B_DEPTH)
-
-#define	COLOR_SHIFT	(COLOR_DEPTH-GMC_B_DEPTH)
+typedef struct /* NOTE: if changing the size of this structure, edit MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536 */
+{
+    GUInt32 nColorCode;
+    int     nCount;
+    GUInt32 nColorCode2;
+    int     nCount2;
+    GUInt32 nColorCode3;
+    int     nCount3;
+} HashHistogram;
 
 typedef	struct colorbox {
 	struct	colorbox *next, *prev;
@@ -60,10 +65,17 @@ typedef	struct colorbox {
 	int	total;
 } Colorbox;
 
-static	void splitbox(Colorbox* ptr, int	(*histogram)[GMC_B_LEN][GMC_B_LEN],
-                      Colorbox **pfreeboxes, Colorbox **pusedboxes);
-static	void shrinkbox(Colorbox* box, int	(*histogram)[GMC_B_LEN][GMC_B_LEN]);
-static	Colorbox* largest_box(Colorbox *usedboxes);
+static void splitbox(Colorbox* ptr, const int* histogram,
+                     const HashHistogram* psHashHistogram,
+                     int nCLevels,
+                     Colorbox **pfreeboxes, Colorbox **pusedboxes,
+                     GByte* pabyRedBand,
+                     GByte* pabyGreenBand,
+                     GByte* pabyBlueBand, int nPixels);
+static void shrinkbox(Colorbox* box,
+                      const int* histogram,
+                      int nCLevels);
+static Colorbox* largest_box(Colorbox *usedboxes);
 
 /************************************************************************/
 /*                      GDALComputeMedianCutPCT()                       */
@@ -116,6 +128,147 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
                          void * pProgressArg )
 
 {
+    return GDALComputeMedianCutPCTInternal(hRed, hGreen, hBlue,
+                                     NULL, NULL, NULL,
+                                     pfnIncludePixel, nColors,
+                                     5,
+                                     NULL,
+                                     hColorTable,
+                                     pfnProgress, pProgressArg);
+}
+
+/*static int nMaxCollisions = 0;*/
+
+static inline int FindColorCount(const HashHistogram* psHashHistogram,
+                                 GUInt32 nColorCode)
+{
+    GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
+    /*int nCollisions = 0; */
+    while( TRUE )
+    {
+        if( (int)psHashHistogram[nIdx].nColorCode < 0 )
+        {
+            return 0;
+        }
+        if( psHashHistogram[nIdx].nColorCode == nColorCode )
+        {
+            return psHashHistogram[nIdx].nCount;
+        }
+        if( (int)psHashHistogram[nIdx].nColorCode2 < 0 )
+        {
+            return 0;
+        }
+        if( psHashHistogram[nIdx].nColorCode2 == nColorCode )
+        {
+            return psHashHistogram[nIdx].nCount2;
+        }
+        if( (int)psHashHistogram[nIdx].nColorCode3 < 0 )
+        {
+            return 0;
+        }
+        if( psHashHistogram[nIdx].nColorCode3 == nColorCode )
+        {
+            return psHashHistogram[nIdx].nCount3;
+        }
+
+        do
+        {
+            /*nCollisions ++;*/
+            nIdx+=257;
+            if( nIdx >= PRIME_FOR_65536 )
+                nIdx -= PRIME_FOR_65536;
+        }
+        while( (int)psHashHistogram[nIdx].nColorCode >= 0 &&
+                psHashHistogram[nIdx].nColorCode != nColorCode &&
+                (int)psHashHistogram[nIdx].nColorCode2 >= 0 &&
+                psHashHistogram[nIdx].nColorCode2 != nColorCode&&
+                (int)psHashHistogram[nIdx].nColorCode3 >= 0 &&
+                psHashHistogram[nIdx].nColorCode3 != nColorCode );
+        /*if( nCollisions > nMaxCollisions )
+        {
+            nMaxCollisions = nCollisions;
+            printf("median cut: nCollisions = %d for R=%d,G=%d,B=%d\n",
+                    nCollisions, nColorCode&0xFF, (nColorCode>>8)&0xFF, (nColorCode>>16)&0xFF);
+        }*/
+    }
+}
+
+static inline int* FindAndInsertColorCount(HashHistogram* psHashHistogram,
+                           GUInt32 nColorCode)
+{
+    GUInt32 nIdx = nColorCode % PRIME_FOR_65536;
+    /*int nCollisions = 0;*/
+    while( TRUE )
+    {
+        if( psHashHistogram[nIdx].nColorCode == nColorCode )
+        {
+            return &(psHashHistogram[nIdx].nCount);
+        }
+        if( (int)psHashHistogram[nIdx].nColorCode < 0 )
+        {
+            psHashHistogram[nIdx].nColorCode = nColorCode;
+            psHashHistogram[nIdx].nCount = 0;
+            return &(psHashHistogram[nIdx].nCount);
+        }
+        if( psHashHistogram[nIdx].nColorCode2 == nColorCode )
+        {
+            return &(psHashHistogram[nIdx].nCount2);
+        }
+        if( (int)psHashHistogram[nIdx].nColorCode2 < 0 )
+        {
+            psHashHistogram[nIdx].nColorCode2 = nColorCode;
+            psHashHistogram[nIdx].nCount2 = 0;
+            return &(psHashHistogram[nIdx].nCount2);
+        }
+        if( psHashHistogram[nIdx].nColorCode3 == nColorCode )
+        {
+            return &(psHashHistogram[nIdx].nCount3);
+        }
+        if( (int)psHashHistogram[nIdx].nColorCode3 < 0 )
+        {
+            psHashHistogram[nIdx].nColorCode3 = nColorCode;
+            psHashHistogram[nIdx].nCount3 = 0;
+            return &(psHashHistogram[nIdx].nCount3);
+        }
+
+        do
+        {
+            /*nCollisions ++;*/
+            nIdx+=257;
+            if( nIdx >= PRIME_FOR_65536 )
+                nIdx -= PRIME_FOR_65536;
+        }
+        while( (int)psHashHistogram[nIdx].nColorCode >= 0 &&
+                psHashHistogram[nIdx].nColorCode != nColorCode &&
+                (int)psHashHistogram[nIdx].nColorCode2 >= 0 &&
+                psHashHistogram[nIdx].nColorCode2 != nColorCode&&
+                (int)psHashHistogram[nIdx].nColorCode3 >= 0 &&
+                psHashHistogram[nIdx].nColorCode3 != nColorCode );
+        /*if( nCollisions > nMaxCollisions )
+        {
+            nMaxCollisions = nCollisions;
+            printf("median cut: nCollisions = %d for R=%d,G=%d,B=%d\n",
+                    nCollisions, nColorCode&0xFF, (nColorCode>>8)&0xFF, (nColorCode>>16)&0xFF);
+        }*/
+    }
+}
+
+int
+GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed, 
+                           GDALRasterBandH hGreen, 
+                           GDALRasterBandH hBlue, 
+                           GByte* pabyRedBand,
+                           GByte* pabyGreenBand,
+                           GByte* pabyBlueBand,
+                           int (*pfnIncludePixel)(int,int,void*),
+                           int nColors, 
+                           int nBits,
+                           int* panHistogram, /* NULL, or at least of size (1<<nBits)^3 * sizeof(int) bytes */
+                           GDALColorTableH hColorTable,
+                           GDALProgressFunc pfnProgress, 
+                           void * pProgressArg )
+
+{
     VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure );
     VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure );
     VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure );
@@ -169,16 +322,53 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
         pfnProgress = GDALDummyProgress;
 
 /* ==================================================================== */
-/*      STEP 1: crate empty boxes.                                      */
+/*      STEP 1: create empty boxes.                                     */
 /* ==================================================================== */
     int	     i;
     Colorbox *box_list, *ptr;
-    int	(*histogram)[GMC_B_LEN][GMC_B_LEN];
+    int* histogram;
     Colorbox *freeboxes;
     Colorbox *usedboxes;
+    int nCLevels = 1 << nBits;
+    int nColorShift = 8 - nBits;
+    int nColorCounter = 0;
+    GByte anRed[256], anGreen[256], anBlue[256];
+    int nPixels = 0;
+    HashHistogram* psHashHistogram = NULL;
+    
+    if( nBits == 8 && pabyRedBand != NULL && pabyGreenBand != NULL &&
+        pabyBlueBand != NULL && nXSize < INT_MAX / nYSize )
+    {
+        nPixels = nXSize * nYSize;
+    }
 
-    histogram = (int (*)[GMC_B_LEN][GMC_B_LEN]) 
-        CPLCalloc(GMC_B_LEN * GMC_B_LEN * GMC_B_LEN,sizeof(int));
+    if( panHistogram )
+    {
+        if( nBits == 8 && (GIntBig)nXSize * nYSize <= 65536 )
+        {
+            /* If the image is small enough, then the number of colors */
+            /* will be limited and using a hashmap, rather than a full table */
+            /* will be more efficient */
+            histogram = NULL;
+            psHashHistogram = (HashHistogram*)panHistogram;
+            memset(psHashHistogram, 0xFF, sizeof(HashHistogram) * PRIME_FOR_65536);
+        }
+        else
+        {
+            histogram = panHistogram;
+            memset(histogram, 0, nCLevels*nCLevels*nCLevels * sizeof(int));
+        }
+    }
+    else
+    {
+        histogram = (int*) VSICalloc(nCLevels*nCLevels*nCLevels,sizeof(int));
+        if( histogram == NULL )
+        {
+            CPLError( CE_Failure, CPLE_OutOfMemory,
+                  "VSICalloc(): Out of memory in GDALComputeMedianCutPCT" );
+            return CE_Failure;
+        }
+    }
     usedboxes = NULL;
     box_list = freeboxes = (Colorbox *)CPLMalloc(nColors*sizeof (Colorbox));
     freeboxes[0].next = &freeboxes[1];
@@ -250,9 +440,9 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
         {
             int	nRed, nGreen, nBlue;
             
-            nRed = pabyRedLine[iPixel] >> COLOR_SHIFT;
-            nGreen = pabyGreenLine[iPixel] >> COLOR_SHIFT;
-            nBlue = pabyBlueLine[iPixel] >> COLOR_SHIFT;
+            nRed = pabyRedLine[iPixel] >> nColorShift;
+            nGreen = pabyGreenLine[iPixel] >> nColorShift;
+            nBlue = pabyBlueLine[iPixel] >> nColorShift;
 
             ptr->rmin = MIN(ptr->rmin, nRed);
             ptr->gmin = MIN(ptr->gmin, nGreen);
@@ -261,7 +451,27 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
             ptr->gmax = MAX(ptr->gmax, nGreen);
             ptr->bmax = MAX(ptr->bmax, nBlue);
 
-            histogram[nRed][nGreen][nBlue]++;
+            int* pnColor;
+            if( psHashHistogram )
+            {
+                pnColor = FindAndInsertColorCount(psHashHistogram,
+                                         MAKE_COLOR_CODE(nRed, nGreen, nBlue));
+            }
+            else
+            {
+                pnColor = &HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue);
+            }
+            if( *pnColor == 0 )
+            {
+                if( nColorShift == 0 && nColorCounter < nColors )
+                {
+                    anRed[nColorCounter] = nRed;
+                    anGreen[nColorCounter] = nGreen;
+                    anBlue[nColorCounter] = nBlue;
+                }
+                nColorCounter++;
+            }
+            (*pnColor) ++;
         }
     }
 
@@ -272,6 +482,21 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
         goto end_and_cleanup;
     }
 
+    if( nColorShift == 0 && nColorCounter <= nColors )
+    {
+        //CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors);
+        for(int iColor = 0;iColor<nColorCounter;iColor++)
+        {
+            GDALColorEntry  sEntry;
+            sEntry.c1 = (GByte) anRed[iColor];
+            sEntry.c2 = (GByte) anGreen[iColor];
+            sEntry.c3 = (GByte) anBlue[iColor];
+            sEntry.c4 = 255;
+            GDALSetColorEntry( hColorTable, iColor, &sEntry );
+        }
+        goto end_and_cleanup;
+    }
+
 /* ==================================================================== */
 /*      STEP 3: continually subdivide boxes until no more free          */
 /*      boxes remain or until all colors assigned.                      */
@@ -279,7 +504,8 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
     while (freeboxes != NULL) {
         ptr = largest_box(usedboxes);
         if (ptr != NULL)
-            splitbox(ptr, histogram, &freeboxes, &usedboxes);
+            splitbox(ptr, histogram, psHashHistogram, nCLevels, &freeboxes, &usedboxes,
+                     pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
         else
             freeboxes = NULL;
     }
@@ -291,9 +517,9 @@ GDALComputeMedianCutPCT( GDALRasterBandH hRed,
     {
         GDALColorEntry	sEntry;
 
-        sEntry.c1 = (GByte) (((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2);
-        sEntry.c2 = (GByte) (((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2);
-        sEntry.c3 = (GByte) (((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2);
+        sEntry.c1 = (GByte) (((ptr->rmin + ptr->rmax) << nColorShift) / 2);
+        sEntry.c2 = (GByte) (((ptr->gmin + ptr->gmax) << nColorShift) / 2);
+        sEntry.c3 = (GByte) (((ptr->bmin + ptr->bmax) << nColorShift) / 2);
         sEntry.c4 = 255;
         GDALSetColorEntry( hColorTable, i, &sEntry );
     }
@@ -307,7 +533,8 @@ end_and_cleanup:
     CPLFree(box_list);
     freeboxes = usedboxes = NULL;
 
-    CPLFree( histogram );
+    if( panHistogram == NULL )
+        CPLFree( histogram );
     
     return err;
 }
@@ -331,17 +558,179 @@ largest_box(Colorbox *usedboxes)
     return (b);
 }
 
+static void shrinkboxFromBand(Colorbox* ptr,
+                              const GByte* pabyRedBand,
+                              const GByte* pabyGreenBand,
+                              const GByte* pabyBlueBand, int nPixels)
+{
+    int rmin_new = 255, rmax_new = 0,
+        gmin_new = 255, gmax_new = 0,
+        bmin_new = 255, bmax_new = 0;
+    for(int i=0;i<nPixels;i++)
+    {
+        int iR = pabyRedBand[i];
+        int iG = pabyGreenBand[i];
+        int iB = pabyBlueBand[i];
+        if( iR >= ptr->rmin && iR <= ptr->rmax &&
+            iG >= ptr->gmin && iG <= ptr->gmax &&
+            iB >= ptr->bmin && iB <= ptr->bmax )
+        {
+            if( iR < rmin_new ) rmin_new = iR;
+            if( iR > rmax_new ) rmax_new = iR;
+            if( iG < gmin_new ) gmin_new = iG;
+            if( iG > gmax_new ) gmax_new = iG;
+            if( iB < bmin_new ) bmin_new = iB;
+            if( iB > bmax_new ) bmax_new = iB;
+        }
+    }
+
+    CPLAssert(rmin_new >= ptr->rmin && rmin_new <= rmax_new && rmax_new <= ptr->rmax);
+    CPLAssert(gmin_new >= ptr->gmin && gmin_new <= gmax_new && gmax_new <= ptr->gmax);
+    CPLAssert(bmin_new >= ptr->bmin && bmin_new <= bmax_new && bmax_new <= ptr->bmax);
+    ptr->rmin = rmin_new;
+    ptr->rmax = rmax_new;
+    ptr->gmin = gmin_new;
+    ptr->gmax = gmax_new;
+    ptr->bmin = bmin_new;
+    ptr->bmax = bmax_new;
+}
+
+static void shrinkboxFromHashHistogram(Colorbox* box,
+                                       const HashHistogram* psHashHistogram)
+{
+    int ir, ig, ib;
+    //int count_iter;
+
+    if (box->rmax > box->rmin) {
+        //count_iter = 0;
+        for (ir = box->rmin; ir <= box->rmax; ++ir) {
+            for (ig = box->gmin; ig <= box->gmax; ++ig) {
+                for (ib = box->bmin; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter rmin=%d\n", count_iter);
+                        box->rmin = ir;
+                        goto have_rmin;
+                    }
+                }
+            }
+        }
+    }
+    have_rmin:
+    if (box->rmax > box->rmin) {
+        //count_iter = 0;
+        for (ir = box->rmax; ir >= box->rmin; --ir) {
+            for (ig = box->gmin; ig <= box->gmax; ++ig) {
+                ib = box->bmin;
+                for (; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter rmax=%d\n", count_iter);
+                        box->rmax = ir;
+                        goto have_rmax;
+                    }
+                }
+            }
+        }
+    }
+
+    have_rmax:
+    if (box->gmax > box->gmin) {
+        //count_iter = 0;
+        for (ig = box->gmin; ig <= box->gmax; ++ig) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                for (ib = box->bmin; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter gmin=%d\n", count_iter);
+                        box->gmin = ig;
+                        goto have_gmin;
+                    }
+                }
+            }
+        }
+    }
+
+    have_gmin:
+    if (box->gmax > box->gmin) {
+        //count_iter = 0;
+        for (ig = box->gmax; ig >= box->gmin; --ig) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                ib = box->bmin;
+                for (; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter gmax=%d\n", count_iter);
+                        box->gmax = ig;
+                        goto have_gmax;
+                    }
+                }
+            }
+        }
+    }
+
+    have_gmax:
+    if (box->bmax > box->bmin) {
+        //count_iter = 0;
+        for (ib = box->bmin; ib <= box->bmax; ++ib) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                for (ig = box->gmin; ig <= box->gmax; ++ig) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter bmin=%d\n", count_iter);
+                        box->bmin = ib;
+                        goto have_bmin;
+                    }
+                }
+            }
+        }
+    }
+    
+    have_bmin:
+    if (box->bmax > box->bmin) {
+        //count_iter = 0;
+        for (ib = box->bmax; ib >= box->bmin; --ib) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                ig = box->gmin;
+                for (; ig <= box->gmax; ++ig) {
+                    //count_iter ++;
+                    if (FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib)) != 0) {
+                        //if( count_iter > 65536 ) printf("iter bmax=%d\n", count_iter);
+                        box->bmax = ib;
+                        goto have_bmax;
+                    }
+                }
+            }
+        }
+    }
+
+    have_bmax:
+    ;
+}
+
 /************************************************************************/
 /*                              splitbox()                              */
 /************************************************************************/
 static void
-splitbox(Colorbox* ptr, int	(*histogram)[GMC_B_LEN][GMC_B_LEN],
-         Colorbox **pfreeboxes, Colorbox **pusedboxes)
+splitbox(Colorbox* ptr, const int* histogram,
+         const HashHistogram* psHashHistogram,
+         int nCLevels,
+         Colorbox **pfreeboxes, Colorbox **pusedboxes,
+         GByte* pabyRedBand,
+         GByte* pabyGreenBand,
+         GByte* pabyBlueBand, int nPixels)
 {
-    int		hist2[GMC_B_LEN];
+    int		hist2[256];
     int		first=0, last=0;
     Colorbox	*new_cb;
-    int	*iptr, *histp;
+    const int	*iptr;
+    int *histp;
     int	i, j;
     int	ir,ig,ib;
     int sum, sum1, sum2;
@@ -360,51 +749,179 @@ splitbox(Colorbox* ptr, int	(*histogram)[GMC_B_LEN][GMC_B_LEN],
     else
         axis = BLUE;
     /* get histogram along longest axis */
+    int nIters = (ptr->rmax - ptr->rmin + 1) * (ptr->gmax - ptr->gmin + 1) *
+                 (ptr->bmax - ptr->bmin + 1);
+    //printf("nIters = %d\n", nIters);
     switch (axis) {
       case RED:
-        histp = &hist2[ptr->rmin];
-        for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
-            *histp = 0;
-            for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
-                iptr = &histogram[ir][ig][ptr->bmin];
-                for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
-                    *histp += *iptr++;
+      {
+        if( nPixels != 0 && nIters > nPixels )
+        {
+            memset(hist2, 0, sizeof(hist2));
+            const int           rmin = ptr->rmin,
+                                rmax = ptr->rmax,
+                                gmin = ptr->gmin,
+                                gmax = ptr->gmax,
+                                bmin = ptr->bmin,
+                                bmax = ptr->bmax;
+            for(int i=0;i<nPixels;i++)
+            {
+                int iR = pabyRedBand[i];
+                int iG = pabyGreenBand[i];
+                int iB = pabyBlueBand[i];
+                if( iR >= rmin && iR <= rmax &&
+                    iG >= gmin && iG <= gmax &&
+                    iB >= bmin && iB <= bmax )
+                {
+                    hist2[iR] ++;
+                }
+            }
+        }
+        else if( psHashHistogram )
+        {
+            histp = &hist2[ptr->rmin];
+            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                *histp = 0;
+                for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+                    {
+                        *histp += FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib));
+                    }
+                }
+                histp++;
+            }
+        }
+        else
+        {
+            histp = &hist2[ptr->rmin];
+            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                *histp = 0;
+                for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ig,ptr->bmin);
+                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+                        *histp += *iptr++;
+                }
+                histp++;
             }
-            histp++;
         }
         first = ptr->rmin;
         last = ptr->rmax;
         break;
+      }
       case GREEN:
-        histp = &hist2[ptr->gmin];
-        for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
-            *histp = 0;
-            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
-                iptr = &histogram[ir][ig][ptr->bmin];
-                for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
-                    *histp += *iptr++;
+      {
+        if( nPixels != 0 && nIters > nPixels )
+        {
+            memset(hist2, 0, sizeof(hist2));
+            const int           rmin = ptr->rmin,
+                                rmax = ptr->rmax,
+                                gmin = ptr->gmin,
+                                gmax = ptr->gmax,
+                                bmin = ptr->bmin,
+                                bmax = ptr->bmax;
+            for(int i=0;i<nPixels;i++)
+            {
+                int iR = pabyRedBand[i];
+                int iG = pabyGreenBand[i];
+                int iB = pabyBlueBand[i];
+                if( iR >= rmin && iR <= rmax &&
+                    iG >= gmin && iG <= gmax &&
+                    iB >= bmin && iB <= bmax )
+                {
+                    hist2[iG] ++;
+                }
+            }
+        }
+        else if( psHashHistogram )
+        {
+            histp = &hist2[ptr->gmin];
+            for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                *histp = 0;
+                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+                    {
+                        *histp += FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib));
+                    }
+                }
+                histp++;
+            }
+        }
+        else
+        {
+            histp = &hist2[ptr->gmin];
+            for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                *histp = 0;
+                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ig,ptr->bmin);
+                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
+                        *histp += *iptr++;
+                }
+                histp++;
             }
-            histp++;
         }
         first = ptr->gmin;
         last = ptr->gmax;
         break;
+      }
       case BLUE:
-        histp = &hist2[ptr->bmin];
-        for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
-            *histp = 0;
-            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
-                iptr = &histogram[ir][ptr->gmin][ib];
-                for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
-                    *histp += *iptr;
-                    iptr += GMC_B_LEN;
+      {
+        if( nPixels != 0 && nIters > nPixels )
+        {
+            memset(hist2, 0, sizeof(hist2));
+            const int           rmin = ptr->rmin,
+                                rmax = ptr->rmax,
+                                gmin = ptr->gmin,
+                                gmax = ptr->gmax,
+                                bmin = ptr->bmin,
+                                bmax = ptr->bmax;
+            for(int i=0;i<nPixels;i++)
+            {
+                int iR = pabyRedBand[i];
+                int iG = pabyGreenBand[i];
+                int iB = pabyBlueBand[i];
+                if( iR >= rmin && iR <= rmax &&
+                    iG >= gmin && iG <= gmax &&
+                    iB >= bmin && iB <= bmax )
+                {
+                    hist2[iB] ++;
+                }
+            }
+        }
+        else if( psHashHistogram )
+        {
+            histp = &hist2[ptr->bmin];
+            for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
+                *histp = 0;
+                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                    for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                        *histp += FindColorCount(psHashHistogram,
+                                       MAKE_COLOR_CODE(ir, ig, ib));
+                    }
                 }
+                histp++;
+            }
+        }
+        else
+        {
+            histp = &hist2[ptr->bmin];
+            for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
+                *histp = 0;
+                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
+                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ptr->gmin,ib);
+                    for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
+                        *histp += *iptr;
+                        iptr += nCLevels;
+                    }
+                }
+                histp++;
             }
-            histp++;
         }
         first = ptr->bmin;
         last = ptr->bmax;
         break;
+      }
     }
     /* find median point */
     sum2 = ptr->total / 2;
@@ -453,93 +970,157 @@ splitbox(Colorbox* ptr, int	(*histogram)[GMC_B_LEN][GMC_B_LEN],
         ptr->bmin = i;
         break;
     }
-    shrinkbox(new_cb, histogram);
-    shrinkbox(ptr, histogram);
+    if( nPixels != 0 &&
+        (new_cb->rmax - new_cb->rmin + 1) * (new_cb->gmax - new_cb->gmin + 1) *
+        (new_cb->bmax - new_cb->bmin + 1) > nPixels )
+    {
+        shrinkboxFromBand(new_cb, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
+    }
+    else if( psHashHistogram != NULL )
+    {
+        shrinkboxFromHashHistogram(new_cb, psHashHistogram);
+    }
+    else
+    {
+        shrinkbox(new_cb, histogram, nCLevels);
+    }
+    if( nPixels != 0 &&
+        (ptr->rmax - ptr->rmin + 1) * (ptr->gmax - ptr->gmin + 1) *
+        (ptr->bmax - ptr->bmin + 1) > nPixels )
+    {
+        shrinkboxFromBand(ptr, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
+    }
+    else if( psHashHistogram != NULL )
+    {
+        shrinkboxFromHashHistogram(ptr, psHashHistogram);
+    }
+    else
+    {
+        shrinkbox(ptr, histogram, nCLevels);
+    }
 }
 
 /************************************************************************/
 /*                             shrinkbox()                              */
 /************************************************************************/
 static void
-shrinkbox(Colorbox* box, int	(*histogram)[GMC_B_LEN][GMC_B_LEN])
+shrinkbox(Colorbox* box, const int* histogram, int nCLevels)
 {
-    int *histp, ir, ig, ib;
+    const int *histp;
+    int ir, ig, ib;
+    //int count_iter;
 
     if (box->rmax > box->rmin) {
-        for (ir = box->rmin; ir <= box->rmax; ++ir)
+        //count_iter = 0;
+        for (ir = box->rmin; ir <= box->rmax; ++ir) {
             for (ig = box->gmin; ig <= box->gmax; ++ig) {
-                histp = &histogram[ir][ig][box->bmin];
-                for (ib = box->bmin; ib <= box->bmax; ++ib)
+                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
+                for (ib = box->bmin; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
                     if (*histp++ != 0) {
+                        //if( count_iter > 65536 ) printf("iter rmin=%d\n", count_iter);
                         box->rmin = ir;
                         goto have_rmin;
                     }
+                }
             }
-      have_rmin:
-        if (box->rmax > box->rmin)
-            for (ir = box->rmax; ir >= box->rmin; --ir)
-                for (ig = box->gmin; ig <= box->gmax; ++ig) {
-                    histp = &histogram[ir][ig][box->bmin];
-                    ib = box->bmin;
-                    for (; ib <= box->bmax; ++ib)
-                        if (*histp++ != 0) {
-                            box->rmax = ir;
-                            goto have_rmax;
-                        }
+        }
+    }
+    have_rmin:
+    if (box->rmax > box->rmin) {
+        //count_iter = 0;
+        for (ir = box->rmax; ir >= box->rmin; --ir) {
+            for (ig = box->gmin; ig <= box->gmax; ++ig) {
+                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
+                ib = box->bmin;
+                for (; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (*histp++ != 0) {
+                        //if( count_iter > 65536 ) printf("iter rmax=%d\n", count_iter);
+                        box->rmax = ir;
+                        goto have_rmax;
+                    }
                 }
+            }
+        }
     }
-  have_rmax:
+
+    have_rmax:
     if (box->gmax > box->gmin) {
-        for (ig = box->gmin; ig <= box->gmax; ++ig)
+        //count_iter = 0;
+        for (ig = box->gmin; ig <= box->gmax; ++ig) {
             for (ir = box->rmin; ir <= box->rmax; ++ir) {
-                histp = &histogram[ir][ig][box->bmin];
-                for (ib = box->bmin; ib <= box->bmax; ++ib)
+                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
+                for (ib = box->bmin; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
                     if (*histp++ != 0) {
+                        //if( count_iter > 65536 ) printf("iter gmin=%d\n", count_iter);
                         box->gmin = ig;
                         goto have_gmin;
                     }
+                }
             }
-      have_gmin:
-        if (box->gmax > box->gmin)
-            for (ig = box->gmax; ig >= box->gmin; --ig)
-                for (ir = box->rmin; ir <= box->rmax; ++ir) {
-                    histp = &histogram[ir][ig][box->bmin];
-                    ib = box->bmin;
-                    for (; ib <= box->bmax; ++ib)
-                        if (*histp++ != 0) {
-                            box->gmax = ig;
-                            goto have_gmax;
-                        }
+        }
+    }
+
+    have_gmin:
+    if (box->gmax > box->gmin) {
+        //count_iter = 0;
+        for (ig = box->gmax; ig >= box->gmin; --ig) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
+                ib = box->bmin;
+                for (; ib <= box->bmax; ++ib) {
+                    //count_iter ++;
+                    if (*histp++ != 0) {
+                        //if( count_iter > 65536 ) printf("iter gmax=%d\n", count_iter);
+                        box->gmax = ig;
+                        goto have_gmax;
+                    }
                 }
+            }
+        }
     }
-  have_gmax:
+
+    have_gmax:
     if (box->bmax > box->bmin) {
-        for (ib = box->bmin; ib <= box->bmax; ++ib)
+        //count_iter = 0;
+        for (ib = box->bmin; ib <= box->bmax; ++ib) {
             for (ir = box->rmin; ir <= box->rmax; ++ir) {
-                histp = &histogram[ir][box->gmin][ib];
+                histp = &HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
                 for (ig = box->gmin; ig <= box->gmax; ++ig) {
+                    //count_iter ++;
                     if (*histp != 0) {
+                        //if( count_iter > 65536 ) printf("iter bmin=%d\n", count_iter);
                         box->bmin = ib;
                         goto have_bmin;
                     }
-                    histp += GMC_B_LEN;
+                    histp += nCLevels;
                 }
             }
-      have_bmin:
-        if (box->bmax > box->bmin)
-            for (ib = box->bmax; ib >= box->bmin; --ib)
-                for (ir = box->rmin; ir <= box->rmax; ++ir) {
-                    histp = &histogram[ir][box->gmin][ib];
-                    ig = box->gmin;
-                    for (; ig <= box->gmax; ++ig) {
-                        if (*histp != 0) {
-                            box->bmax = ib;
-                            goto have_bmax;
-                        }
-                        histp += GMC_B_LEN;
+        }
+    }
+    
+    have_bmin:
+    if (box->bmax > box->bmin) {
+        //count_iter = 0;
+        for (ib = box->bmax; ib >= box->bmin; --ib) {
+            for (ir = box->rmin; ir <= box->rmax; ++ir) {
+                histp = &HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
+                ig = box->gmin;
+                for (; ig <= box->gmax; ++ig) {
+                    //count_iter ++;
+                    if (*histp != 0) {
+                        //if( count_iter > 65536 ) printf("iter bmax=%d\n", count_iter);
+                        box->bmax = ib;
+                        goto have_bmax;
                     }
+                    histp += nCLevels;
                 }
+            }
+        }
     }
-  have_bmax:
+
+    have_bmax:
     ;
 }
diff --git a/alg/gdalproximity.cpp b/alg/gdalproximity.cpp
index 8d0ce5f..af13815 100644
--- a/alg/gdalproximity.cpp
+++ b/alg/gdalproximity.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalproximity.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalproximity.cpp 28882 2015-04-09 15:59:38Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Compute each pixel's proximity to a set of target pixels.
@@ -32,12 +32,12 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdalproximity.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalproximity.cpp 28882 2015-04-09 15:59:38Z rouault $");
 
 static CPLErr
 ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY, 
                       int bForward, int iLine, int nXSize, double nMaxDist,
-                      float *pafProximity,
+                      float *pafProximity, double *pdfSrcNoDataValue,
                       int nTargetValues, int *panTargetValues );
 
 /************************************************************************/
@@ -85,6 +85,12 @@ The NODATA value to use on the output band for pixels that are
 beyond MAXDIST.  If not provided, the hProximityBand will be
 queried for a nodata value.  If one is not found, 65535 will be used.
 
+  USE_INPUT_NODATA=YES/NO
+
+If this option is set, the input data set no-data value will be
+respected. Leaving no data pixels in the input as no data pixels in
+the proximity output.
+
   FIXED_BUF_VAL=n
 
 If this option is set, all pixels within the MAXDIST threadhold are
@@ -146,7 +152,7 @@ GDALComputeProximity( GDALRasterBandH hSrcBand,
 /* -------------------------------------------------------------------- */
     pszOpt = CSLFetchNameValue( papszOptions, "MAXDIST" );
     if( pszOpt )
-        dfMaxDist = atof(pszOpt) / dfDistMult;
+        dfMaxDist = CPLAtof(pszOpt) / dfDistMult;
     else
         dfMaxDist = GDALGetRasterBandXSize(hSrcBand) + GDALGetRasterBandYSize(hSrcBand);
 
@@ -166,12 +172,25 @@ GDALComputeProximity( GDALRasterBandH hSrcBand,
     }
 
 /* -------------------------------------------------------------------- */
+/*      Get input NODATA value.                                         */
+/* -------------------------------------------------------------------- */
+    double dfSrcNoDataValue = 0.0;
+    double *pdfSrcNoData = NULL;
+    if( CSLFetchBoolean( papszOptions, "USE_INPUT_NODATA", FALSE ) )
+    {
+        int bSrcHasNoData = 0;
+        dfSrcNoDataValue = GDALGetRasterNoDataValue( hSrcBand, &bSrcHasNoData );
+        if( bSrcHasNoData )
+            pdfSrcNoData = &dfSrcNoDataValue;
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Get output NODATA value.                                        */
 /* -------------------------------------------------------------------- */
     float fNoDataValue;
     pszOpt = CSLFetchNameValue( papszOptions, "NODATA" );
     if( pszOpt != NULL )
-        fNoDataValue = (float) atof(pszOpt);
+        fNoDataValue = (float) CPLAtof(pszOpt);
     else
     {
         int bSuccess;
@@ -187,7 +206,7 @@ GDALComputeProximity( GDALRasterBandH hSrcBand,
     pszOpt = CSLFetchNameValue( papszOptions, "FIXED_BUF_VAL" );
     if( pszOpt )
     {
-        dfFixedBufVal = atof(pszOpt);
+        dfFixedBufVal = CPLAtof(pszOpt);
         bFixedBufVal = TRUE;
     }
 
@@ -300,13 +319,13 @@ GDALComputeProximity( GDALRasterBandH hSrcBand,
 
         // Left to right
         ProcessProximityLine( panSrcScanline, panNearX, panNearY, 
-                              TRUE, iLine, nXSize, dfMaxDist,
-                              pafProximity, nTargetValues, panTargetValues );
+                              TRUE, iLine, nXSize, dfMaxDist, pafProximity,
+                              pdfSrcNoData, nTargetValues, panTargetValues );
 
         // Right to Left
         ProcessProximityLine( panSrcScanline, panNearX, panNearY, 
-                              FALSE, iLine, nXSize, dfMaxDist,
-                              pafProximity, nTargetValues, panTargetValues );
+                              FALSE, iLine, nXSize, dfMaxDist, pafProximity,
+                              pdfSrcNoData, nTargetValues, panTargetValues );
 
         // Write out results.
         eErr = 
@@ -349,13 +368,13 @@ GDALComputeProximity( GDALRasterBandH hSrcBand,
 
         // Right to left
         ProcessProximityLine( panSrcScanline, panNearX, panNearY, 
-                              FALSE, iLine, nXSize, dfMaxDist,
-                              pafProximity, nTargetValues, panTargetValues );
+                              FALSE, iLine, nXSize, dfMaxDist, pafProximity,
+                              pdfSrcNoData, nTargetValues, panTargetValues );
 
         // Left to right
         ProcessProximityLine( panSrcScanline, panNearX, panNearY, 
-                              TRUE, iLine, nXSize, dfMaxDist,
-                              pafProximity, nTargetValues, panTargetValues );
+                              TRUE, iLine, nXSize, dfMaxDist, pafProximity,
+                              pdfSrcNoData, nTargetValues, panTargetValues );
 
         // Final post processing of distances. 
         for( i = 0; i < nXSize; i++ )
@@ -414,7 +433,7 @@ end:
 static CPLErr
 ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY, 
                       int bForward, int iLine, int nXSize, double dfMaxDist,
-                      float *pafProximity,
+                      float *pafProximity, double *pdfSrcNoDataValue,
                       int nTargetValues, int *panTargetValues )
 
 {
@@ -529,6 +548,8 @@ ProcessProximityLine( GInt32 *panSrcScanline, int *panNearX, int *panNearY,
 /*      Update our proximity value.                                     */
 /* -------------------------------------------------------------------- */
         if( panNearX[iPixel] != -1 
+            && (pdfSrcNoDataValue == NULL
+                || panSrcScanline[iPixel] != *pdfSrcNoDataValue)
             && fNearDistSq <= dfMaxDist * dfMaxDist
             && (pafProximity[iPixel] < 0 
                 || fNearDistSq < pafProximity[iPixel] * pafProximity[iPixel]) )
diff --git a/alg/gdalrasterize.cpp b/alg/gdalrasterize.cpp
index 9b47587..58c98cd 100644
--- a/alg/gdalrasterize.cpp
+++ b/alg/gdalrasterize.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalrasterize.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gdalrasterize.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Vector rasterization.
@@ -679,7 +679,7 @@ CPLErr GDALRasterizeGeometries( GDALDatasetH hDS,
                            0, iY, poDS->GetRasterXSize(), nThisYChunkSize, 
                            pabyChunkBuf,poDS->GetRasterXSize(),nThisYChunkSize,
                            eType, nBandCount, panBandList,
-                           0, 0, 0 );
+                           0, 0, 0, NULL );
         if( eErr != CE_None )
             break;
 
@@ -699,7 +699,7 @@ CPLErr GDALRasterizeGeometries( GDALDatasetH hDS,
                             poDS->GetRasterXSize(), nThisYChunkSize, 
                             pabyChunkBuf,
                             poDS->GetRasterXSize(), nThisYChunkSize, 
-                            eType, nBandCount, panBandList, 0, 0, 0 );
+                            eType, nBandCount, panBandList, 0, 0, 0, NULL);
 
         if( !pfnProgress((iY+nThisYChunkSize)/((double)poDS->GetRasterYSize()),
                          "", pProgressArg ) )
@@ -878,7 +878,7 @@ CPLErr GDALRasterizeLayers( GDALDatasetH hDS,
         if ( poDS->RasterIO( GF_Read, 0, 0, poDS->GetRasterXSize(),
                              nYChunkSize, pabyChunkBuf,
                              poDS->GetRasterXSize(), nYChunkSize,
-                             eType, nBandCount, panBandList, 0, 0, 0 )
+                             eType, nBandCount, panBandList, 0, 0, 0, NULL )
              != CE_None )
         {
             CPLError( CE_Failure, CPLE_OutOfMemory, 
@@ -993,7 +993,7 @@ CPLErr GDALRasterizeLayers( GDALDatasetH hDS,
                                     poDS->GetRasterXSize(), nThisYChunkSize, 
                                     pabyChunkBuf,
                                     poDS->GetRasterXSize(), nThisYChunkSize,
-                                    eType, nBandCount, panBandList, 0, 0, 0 );
+                                    eType, nBandCount, panBandList, 0, 0, 0, NULL );
                 if( eErr != CE_None )
                     break;
             }
@@ -1035,7 +1035,7 @@ CPLErr GDALRasterizeLayers( GDALDatasetH hDS,
                                     poDS->GetRasterXSize(), nThisYChunkSize, 
                                     pabyChunkBuf,
                                     poDS->GetRasterXSize(), nThisYChunkSize, 
-                                    eType, nBandCount, panBandList, 0, 0, 0 );
+                                    eType, nBandCount, panBandList, 0, 0, 0, NULL );
             }
 
             poLayer->ResetReading();
@@ -1066,7 +1066,7 @@ CPLErr GDALRasterizeLayers( GDALDatasetH hDS,
                                 poDS->GetRasterXSize(), nYChunkSize, 
                                 pabyChunkBuf,
                                 poDS->GetRasterXSize(), nYChunkSize, 
-                                eType, nBandCount, panBandList, 0, 0, 0 );
+                                eType, nBandCount, panBandList, 0, 0, 0, NULL );
     }
 
 /* -------------------------------------------------------------------- */
diff --git a/alg/gdalrasterpolygonenumerator.cpp b/alg/gdalrasterpolygonenumerator.cpp
index 83a5015..d09c8e7 100644
--- a/alg/gdalrasterpolygonenumerator.cpp
+++ b/alg/gdalrasterpolygonenumerator.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalrasterpolygonenumerator.cpp 24379 2012-05-04 01:26:19Z warmerdam $
+ * $Id: gdalrasterpolygonenumerator.cpp 28826 2015-03-30 17:51:14Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Raster Polygon Enumerator
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include <vector>
 
-CPL_CVSID("$Id: gdalrasterpolygonenumerator.cpp 24379 2012-05-04 01:26:19Z warmerdam $");
+CPL_CVSID("$Id: gdalrasterpolygonenumerator.cpp 28826 2015-03-30 17:51:14Z rouault $");
 
 /************************************************************************/
 /*                    GDALRasterPolygonEnumerator()                     */
@@ -174,7 +174,11 @@ void GDALRasterPolygonEnumerator::ProcessLine(
     {
         for( i=0; i < nXSize; i++ )
         {
-            if( i == 0 || panThisLineVal[i] != panThisLineVal[i-1] )
+            if( panThisLineVal[i] == GP_NODATA_MARKER )
+            {
+                panThisLineId[i] = -1;
+            }
+            else if( i == 0 || panThisLineVal[i] != panThisLineVal[i-1] )
             {
                 panThisLineId[i] = NewPolygon( panThisLineVal[i] );
             }
@@ -191,7 +195,11 @@ void GDALRasterPolygonEnumerator::ProcessLine(
 /* -------------------------------------------------------------------- */
     for( i = 0; i < nXSize; i++ )
     {
-        if( i > 0 && panThisLineVal[i] == panThisLineVal[i-1] )
+        if( panThisLineVal[i] == GP_NODATA_MARKER )
+        {
+            panThisLineId[i] = -1;
+        }
+        else if( i > 0 && panThisLineVal[i] == panThisLineVal[i-1] )
         {
             panThisLineId[i] = panThisLineId[i-1];        
 
diff --git a/alg/gdalsievefilter.cpp b/alg/gdalsievefilter.cpp
index 97d6a08..abd2377 100644
--- a/alg/gdalsievefilter.cpp
+++ b/alg/gdalsievefilter.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalsievefilter.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalsievefilter.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GDAL
  * Purpose:  Raster to Polygon Converter
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include <vector>
 
-CPL_CVSID("$Id: gdalsievefilter.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gdalsievefilter.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define GP_NODATA_MARKER -51502112
 #define MY_MAX_INT 2147483647
@@ -184,9 +184,8 @@ GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
                  GDALRasterBandH hDstBand,
                  int nSizeThreshold, int nConnectedness,
                  CPL_UNUSED char **papszOptions,
-                 GDALProgressFunc pfnProgress, 
+                 GDALProgressFunc pfnProgress,
                  void * pProgressArg )
-
 {
     VALIDATE_POINTER1( hSrcBand, "GDALSieveFilter", CE_Failure );
     VALIDATE_POINTER1( hDstBand, "GDALSieveFilter", CE_Failure );
@@ -577,4 +576,3 @@ GDALSieveFilter( GDALRasterBandH hSrcBand, GDALRasterBandH hMaskBand,
 
     return eErr;
 }
-
diff --git a/alg/gdaltransformer.cpp b/alg/gdaltransformer.cpp
index 48a104c..ee2b659 100644
--- a/alg/gdaltransformer.cpp
+++ b/alg/gdaltransformer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaltransformer.cpp 27865 2014-10-15 22:44:28Z rouault $
+ * $Id: gdaltransformer.cpp 28916 2015-04-16 14:13:13Z rouault $
  *
  * Project:  Mapinfo Image Warper
  * Purpose:  Implementation of one or more GDALTrasformerFunc types, including
@@ -38,7 +38,7 @@
 #include "cpl_list.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gdaltransformer.cpp 27865 2014-10-15 22:44:28Z rouault $");
+CPL_CVSID("$Id: gdaltransformer.cpp 28916 2015-04-16 14:13:13Z rouault $");
 CPL_C_START
 void *GDALDeserializeGCPTransformer( CPLXMLNode *psTree );
 void *GDALDeserializeTPSTransformer( CPLXMLNode *psTree );
@@ -166,11 +166,13 @@ GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
 }
 
 
- static int GDALSuggestedWarpOutput2_MustAdjustForRightBorder(
-                     GDALTransformerFunc pfnTransformer, void *pTransformArg,
-                     double* padfExtent, CPL_UNUSED int nPixels, int nLines,
-                     double dfPixelSizeX, double dfPixelSizeY)
- {
+static int GDALSuggestedWarpOutput2_MustAdjustForRightBorder(
+    GDALTransformerFunc pfnTransformer, void *pTransformArg,
+    double* padfExtent,
+    CPL_UNUSED int nPixels,
+    int nLines,
+    double dfPixelSizeX, double dfPixelSizeY)
+{
     int nSamplePoints;
     double dfRatio;
     int bErr;
@@ -228,11 +230,12 @@ GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
 }
 
 
- static int GDALSuggestedWarpOutput2_MustAdjustForBottomBorder(
-                     GDALTransformerFunc pfnTransformer, void *pTransformArg,
-                     double* padfExtent, int nPixels, CPL_UNUSED int nLines,
-                     double dfPixelSizeX, double dfPixelSizeY)
- {
+static int GDALSuggestedWarpOutput2_MustAdjustForBottomBorder(
+     GDALTransformerFunc pfnTransformer, void *pTransformArg,
+     double* padfExtent, int nPixels,
+     CPL_UNUSED int nLines,
+     double dfPixelSizeX, double dfPixelSizeY)
+{
     int nSamplePoints;
     double dfRatio;
     int bErr;
@@ -334,13 +337,13 @@ GDALSuggestedWarpOutput( GDALDatasetH hSrcDS,
  */
 
 CPLErr CPL_STDCALL
-GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS, 
-                          GDALTransformerFunc pfnTransformer, 
-                          void *pTransformArg, 
-                          double *padfGeoTransformOut, 
+GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS,
+                          GDALTransformerFunc pfnTransformer,
+                          void *pTransformArg,
+                          double *padfGeoTransformOut,
                           int *pnPixels, int *pnLines,
-                          double *padfExtent, CPL_UNUSED int nOptions )
-
+                          double *padfExtent,
+                          CPL_UNUSED int nOptions )
 {
     VALIDATE_POINTER1( hSrcDS, "GDALSuggestedWarpOutput2", CE_Failure );
 
@@ -348,8 +351,8 @@ GDALSuggestedWarpOutput2( GDALDatasetH hSrcDS,
 /*      Setup sample points all around the edge of the input raster.    */
 /* -------------------------------------------------------------------- */
     int    nSamplePoints = 0;
-    const int    nInXSize = GDALGetRasterXSize( hSrcDS );
-    const int    nInYSize = GDALGetRasterYSize( hSrcDS );
+    int    nInXSize = GDALGetRasterXSize( hSrcDS );
+    int    nInYSize = GDALGetRasterYSize( hSrcDS );
 
     if (pfnTransformer == GDALGenImgProjTransform)
     {
@@ -797,7 +800,7 @@ retry:
     
     
 /* -------------------------------------------------------------------- */
-/*      Recompute some bounds so that all return values are consistant  */
+/*      Recompute some bounds so that all return values are consistent  */
 /* -------------------------------------------------------------------- */
     dfMaxXOut = dfMinXOut + (*pnPixels) * dfPixelSizeX;
     dfMinYOut = dfMaxYOut - (*pnLines) * dfPixelSizeY;
@@ -857,12 +860,12 @@ typedef struct {
 } GDALGenImgProjTransformInfo;
 
 /************************************************************************/
-/*                  GDALCloneGenImgProjTransformer()                    */
+/*                GDALCreateSimilarGenImgProjTransformer()              */
 /************************************************************************/
 
-void* GDALCloneGenImgProjTransformer( void *hTransformArg )
+static void* GDALCreateSimilarGenImgProjTransformer( void *hTransformArg, double dfRatioX, double dfRatioY )
 {
-    VALIDATE_POINTER1( hTransformArg, "GDALCloneGenImgProjTransformer", NULL );
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarGenImgProjTransformer", NULL );
 
     GDALGenImgProjTransformInfo *psInfo = 
         (GDALGenImgProjTransformInfo *) hTransformArg;
@@ -871,23 +874,51 @@ void* GDALCloneGenImgProjTransformer( void *hTransformArg )
         CPLMalloc(sizeof(GDALGenImgProjTransformInfo));
 
     memcpy(psClonedInfo, psInfo, sizeof(GDALGenImgProjTransformInfo));
+    
     if( psClonedInfo->pSrcGCPTransformArg )
-        psClonedInfo->pSrcGCPTransformArg = GDALCloneTransformer( psInfo->pSrcGCPTransformArg );
-    if( psClonedInfo->pSrcRPCTransformArg )
-        psClonedInfo->pSrcRPCTransformArg = GDALCloneTransformer( psInfo->pSrcRPCTransformArg );
-    if( psClonedInfo->pSrcTPSTransformArg )
-        psClonedInfo->pSrcTPSTransformArg = GDALCloneTransformer( psInfo->pSrcTPSTransformArg );
-    if( psClonedInfo->pSrcGeoLocTransformArg )
-        psClonedInfo->pSrcGeoLocTransformArg = GDALCloneTransformer( psInfo->pSrcGeoLocTransformArg );
+        psClonedInfo->pSrcGCPTransformArg = GDALCreateSimilarTransformer( psInfo->pSrcGCPTransformArg, dfRatioX, dfRatioY );
+    else if( psClonedInfo->pSrcRPCTransformArg )
+        psClonedInfo->pSrcRPCTransformArg = GDALCreateSimilarTransformer( psInfo->pSrcRPCTransformArg, dfRatioX, dfRatioY );
+    else if( psClonedInfo->pSrcTPSTransformArg )
+        psClonedInfo->pSrcTPSTransformArg = GDALCreateSimilarTransformer( psInfo->pSrcTPSTransformArg, dfRatioX, dfRatioY );
+    else if( psClonedInfo->pSrcGeoLocTransformArg )
+        psClonedInfo->pSrcGeoLocTransformArg = GDALCreateSimilarTransformer( psInfo->pSrcGeoLocTransformArg, dfRatioX, dfRatioY );
+    else if( dfRatioX != 1.0 || dfRatioY != 1.0 )
+    {
+        if( psClonedInfo->adfSrcGeoTransform[2] == 0.0 && psClonedInfo->adfSrcGeoTransform[4] == 0.0 )
+        {
+            psClonedInfo->adfSrcGeoTransform[1] *= dfRatioX;
+            psClonedInfo->adfSrcGeoTransform[5] *= dfRatioY;
+        }
+        else
+        {
+            /* If the x and y ratios are not equal, then we cannot really */
+            /* compute a geotransform */
+            psClonedInfo->adfSrcGeoTransform[1] *= dfRatioX;
+            psClonedInfo->adfSrcGeoTransform[2] *= dfRatioX;
+            psClonedInfo->adfSrcGeoTransform[4] *= dfRatioX;
+            psClonedInfo->adfSrcGeoTransform[5] *= dfRatioX;
+        }
+        if( !GDALInvGeoTransform( psClonedInfo->adfSrcGeoTransform, 
+                                  psClonedInfo->adfSrcInvGeoTransform ) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot invert geotransform");
+            GDALDestroyGenImgProjTransformer( psClonedInfo );
+            return NULL;
+        }
+    }
+    
     if( psClonedInfo->pReprojectArg )
         psClonedInfo->pReprojectArg = GDALCloneTransformer( psInfo->pReprojectArg );
+    
     if( psClonedInfo->pDstGCPTransformArg )
         psClonedInfo->pDstGCPTransformArg = GDALCloneTransformer( psInfo->pDstGCPTransformArg );
-    if( psClonedInfo->pDstRPCTransformArg )
+    else if( psClonedInfo->pDstRPCTransformArg )
         psClonedInfo->pDstRPCTransformArg = GDALCloneTransformer( psInfo->pDstRPCTransformArg );
-    if( psClonedInfo->pDstTPSTransformArg )
+    else if( psClonedInfo->pDstTPSTransformArg )
         psClonedInfo->pDstTPSTransformArg = GDALCloneTransformer( psInfo->pDstTPSTransformArg );
 
+    
     return psClonedInfo;
 }
 
@@ -942,9 +973,9 @@ void* GDALCloneGenImgProjTransformer( void *hTransformArg )
 void *
 GDALCreateGenImgProjTransformer( GDALDatasetH hSrcDS, const char *pszSrcWKT,
                                  GDALDatasetH hDstDS, const char *pszDstWKT,
-                                 int bGCPUseOK, CPL_UNUSED double dfGCPErrorThreshold,
+                                 int bGCPUseOK,
+                                 CPL_UNUSED double dfGCPErrorThreshold,
                                  int nOrder )
-
 {
     char **papszOptions = NULL;
     void *pRet;
@@ -1048,6 +1079,28 @@ static CPLString InsertCenterLong( GDALDatasetH hDS, CPLString osWKT )
 }
 
 /************************************************************************/
+/*               GDALCreateGenImgProjTransformerInternal()              */
+/************************************************************************/
+
+static GDALGenImgProjTransformInfo* GDALCreateGenImgProjTransformerInternal()
+{
+/* -------------------------------------------------------------------- */
+/*      Initialize the transform info.                                  */
+/* -------------------------------------------------------------------- */
+    GDALGenImgProjTransformInfo* psInfo = (GDALGenImgProjTransformInfo *) 
+        CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
+
+    memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
+    psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
+    psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
+    psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
+    psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
+    psInfo->sTI.pfnCreateSimilar = GDALCreateSimilarGenImgProjTransformer;
+    
+    return psInfo;
+}
+
+/************************************************************************/
 /*                  GDALCreateGenImgProjTransformer2()                  */
 /************************************************************************/
 
@@ -1095,7 +1148,7 @@ static CPLString InsertCenterLong( GDALDatasetH hDS, CPLString osWKT )
  * to georef transformation on the source dataset.
  * <li> DST_METHOD: may have a value which is one of GEOTRANSFORM, 
  * GCP_POLYNOMIAL, GCP_TPS, GEOLOC_ARRAY, RPC to force only one geolocation 
- * method to be considered on the source dataset.  Will be used for pixel/line 
+ * method to be considered on the target dataset.  Will be used for pixel/line 
  * to georef transformation on the destination dataset.
  * <li> RPC_HEIGHT: A fixed height to be used with RPC calculations.
  * <li> RPC_DEM: The name of a DEM file to be used with RPC calculations.
@@ -1147,26 +1200,19 @@ GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
     pszValue = CSLFetchNameValue( papszOptions, "REFINE_TOLERANCE" );
     if( pszValue )
     {
-        dfTolerance = atof(pszValue);
+        dfTolerance = CPLAtof(pszValue);
         bRefine = TRUE;
     }
 
 /* -------------------------------------------------------------------- */
 /*      Initialize the transform info.                                  */
 /* -------------------------------------------------------------------- */
-    psInfo = (GDALGenImgProjTransformInfo *) 
-        CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
-
-    strcpy( psInfo->sTI.szSignature, "GTI" );
-    psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
-    psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
-    psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
-    psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
+    psInfo = GDALCreateGenImgProjTransformerInternal();
 
 /* -------------------------------------------------------------------- */
 /*      Get forward and inverse geotransform for the source image.      */
 /* -------------------------------------------------------------------- */
-    if( hSrcDS == NULL )
+    if( hSrcDS == NULL || (pszMethod != NULL && EQUAL(pszMethod,"NO_GEOTRANSFORM")) )
     {
         psInfo->adfSrcGeoTransform[0] = 0.0;
         psInfo->adfSrcGeoTransform[1] = 1.0;
@@ -1293,7 +1339,8 @@ GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
         CPLError( CE_Failure, CPLE_AppDefined, 
                   "Unable to compute a transformation between pixel/line\n"
                   "and georeferenced coordinates for %s.\n"
-                  "There is no affine transformation and no GCPs.", 
+                  "There is no affine transformation and no GCPs.\n"
+                  "Specify transformation option SRC_METHOD=NO_GEOTRANSFORM to bypass this check.", 
                   GDALGetDescription( hSrcDS ) );
 
         GDALDestroyGenImgProjTransformer( psInfo );
@@ -1306,7 +1353,7 @@ GDALCreateGenImgProjTransformer2( GDALDatasetH hSrcDS, GDALDatasetH hDstDS,
 /* -------------------------------------------------------------------- */
     const char *pszDstMethod = CSLFetchNameValue( papszOptions, "DST_METHOD" );
 
-    if( !hDstDS )
+    if( !hDstDS || (pszDstMethod != NULL && EQUAL(pszDstMethod,"NO_GEOTRANSFORM"))  )
     {
         psInfo->adfDstGeoTransform[0] = 0.0;
         psInfo->adfDstGeoTransform[1] = 1.0;
@@ -1500,15 +1547,8 @@ GDALCreateGenImgProjTransformer3( const char *pszSrcWKT,
 /* -------------------------------------------------------------------- */
 /*      Initialize the transform info.                                  */
 /* -------------------------------------------------------------------- */
-    psInfo = (GDALGenImgProjTransformInfo *) 
-        CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
-
-    strcpy( psInfo->sTI.szSignature, "GTI" );
-    psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
-    psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
-    psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
-    psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
-
+    psInfo = GDALCreateGenImgProjTransformerInternal();
+    
 /* -------------------------------------------------------------------- */
 /*      Get forward and inverse geotransform for the source image.      */
 /* -------------------------------------------------------------------- */
@@ -1681,6 +1721,10 @@ void GDALDestroyGenImgProjTransformer( void *hTransformArg )
  * can be found in that topic. 
  */
 
+#ifdef DEBUG_APPROX_TRANSFORMER
+int countGDALGenImgProjTransform = 0;
+#endif
+
 int GDALGenImgProjTransform( void *pTransformArg, int bDstToSrc, 
                              int nPointCount, 
                              double *padfX, double *padfY, double *padfZ,
@@ -1695,6 +1739,11 @@ int GDALGenImgProjTransform( void *pTransformArg, int bDstToSrc,
     void *pTPSTransformArg;
     void *pGeoLocTransformArg;
 
+#ifdef DEBUG_APPROX_TRANSFORMER
+    CPLAssert(nPointCount > 0);
+    countGDALGenImgProjTransform += nPointCount;
+#endif
+
     for( i = 0; i < nPointCount; i++ )
     {
         panSuccess[i] = ( padfX[i] != HUGE_VAL && padfY[i] != HUGE_VAL );
@@ -1944,7 +1993,7 @@ GDALSerializeGenImgProjTransformer( void *pTransformArg )
 /* -------------------------------------------------------------------- */
     else
     {
-        sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
+        CPLsprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
                  psInfo->adfSrcGeoTransform[0],
                  psInfo->adfSrcGeoTransform[1],
                  psInfo->adfSrcGeoTransform[2],
@@ -1953,7 +2002,7 @@ GDALSerializeGenImgProjTransformer( void *pTransformArg )
                  psInfo->adfSrcGeoTransform[5] );
         CPLCreateXMLElementAndValue( psTree, "SrcGeoTransform", szWork );
         
-        sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
+        CPLsprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
                  psInfo->adfSrcInvGeoTransform[0],
                  psInfo->adfSrcInvGeoTransform[1],
                  psInfo->adfSrcInvGeoTransform[2],
@@ -2019,7 +2068,7 @@ GDALSerializeGenImgProjTransformer( void *pTransformArg )
 /* -------------------------------------------------------------------- */
     else
     {
-        sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
+        CPLsprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
                  psInfo->adfDstGeoTransform[0],
                  psInfo->adfDstGeoTransform[1],
                  psInfo->adfDstGeoTransform[2],
@@ -2028,7 +2077,7 @@ GDALSerializeGenImgProjTransformer( void *pTransformArg )
                  psInfo->adfDstGeoTransform[5] );
         CPLCreateXMLElementAndValue( psTree, "DstGeoTransform", szWork );
         
-        sprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
+        CPLsprintf( szWork, "%.18g,%.18g,%.18g,%.18g,%.18g,%.18g",
                  psInfo->adfDstInvGeoTransform[0],
                  psInfo->adfDstInvGeoTransform[1],
                  psInfo->adfDstInvGeoTransform[2],
@@ -2059,6 +2108,22 @@ GDALSerializeGenImgProjTransformer( void *pTransformArg )
 }
 
 /************************************************************************/
+/*                    GDALDeserializeGeoTransform()                     */
+/************************************************************************/
+
+static void GDALDeserializeGeoTransform(const char* pszGT,
+                                        double adfGeoTransform[6])
+{
+    CPLsscanf( pszGT, "%lf,%lf,%lf,%lf,%lf,%lf", 
+               adfGeoTransform + 0,
+               adfGeoTransform + 1,
+               adfGeoTransform + 2,
+               adfGeoTransform + 3,
+               adfGeoTransform + 4,
+               adfGeoTransform + 5 );
+}
+
+/************************************************************************/
 /*                GDALDeserializeGenImgProjTransformer()                */
 /************************************************************************/
 
@@ -2071,40 +2136,20 @@ void *GDALDeserializeGenImgProjTransformer( CPLXMLNode *psTree )
 /* -------------------------------------------------------------------- */
 /*      Initialize the transform info.                                  */
 /* -------------------------------------------------------------------- */
-    psInfo = (GDALGenImgProjTransformInfo *) 
-        CPLCalloc(sizeof(GDALGenImgProjTransformInfo),1);
-
-    strcpy( psInfo->sTI.szSignature, "GTI" );
-    psInfo->sTI.pszClassName = "GDALGenImgProjTransformer";
-    psInfo->sTI.pfnTransform = GDALGenImgProjTransform;
-    psInfo->sTI.pfnCleanup = GDALDestroyGenImgProjTransformer;
-    psInfo->sTI.pfnSerialize = GDALSerializeGenImgProjTransformer;
+    psInfo = GDALCreateGenImgProjTransformerInternal();
 
 /* -------------------------------------------------------------------- */
 /*      SrcGeotransform                                                 */
 /* -------------------------------------------------------------------- */
     if( CPLGetXMLNode( psTree, "SrcGeoTransform" ) != NULL )
     {
-        sscanf( CPLGetXMLValue( psTree, "SrcGeoTransform", "" ), 
-                "%lg,%lg,%lg,%lg,%lg,%lg", 
-                psInfo->adfSrcGeoTransform + 0,
-                psInfo->adfSrcGeoTransform + 1,
-                psInfo->adfSrcGeoTransform + 2,
-                psInfo->adfSrcGeoTransform + 3,
-                psInfo->adfSrcGeoTransform + 4,
-                psInfo->adfSrcGeoTransform + 5 );
+        GDALDeserializeGeoTransform( CPLGetXMLValue( psTree, "SrcGeoTransform", "" ), 
+                                     psInfo->adfSrcGeoTransform );
 
         if( CPLGetXMLNode( psTree, "SrcInvGeoTransform" ) != NULL )
         {
-            sscanf( CPLGetXMLValue( psTree, "SrcInvGeoTransform", "" ), 
-                    "%lg,%lg,%lg,%lg,%lg,%lg", 
-                    psInfo->adfSrcInvGeoTransform + 0,
-                    psInfo->adfSrcInvGeoTransform + 1,
-                    psInfo->adfSrcInvGeoTransform + 2,
-                    psInfo->adfSrcInvGeoTransform + 3,
-                    psInfo->adfSrcInvGeoTransform + 4,
-                    psInfo->adfSrcInvGeoTransform + 5 );
-            
+            GDALDeserializeGeoTransform( CPLGetXMLValue( psTree, "SrcInvGeoTransform", "" ), 
+                                     psInfo->adfSrcInvGeoTransform );
         }
         else
         {
@@ -2181,26 +2226,13 @@ void *GDALDeserializeGenImgProjTransformer( CPLXMLNode *psTree )
 /* -------------------------------------------------------------------- */
     if( CPLGetXMLNode( psTree, "DstGeoTransform" ) != NULL )
     {
-        sscanf( CPLGetXMLValue( psTree, "DstGeoTransform", "" ), 
-                "%lg,%lg,%lg,%lg,%lg,%lg", 
-                psInfo->adfDstGeoTransform + 0,
-                psInfo->adfDstGeoTransform + 1,
-                psInfo->adfDstGeoTransform + 2,
-                psInfo->adfDstGeoTransform + 3,
-                psInfo->adfDstGeoTransform + 4,
-                psInfo->adfDstGeoTransform + 5 );
+        GDALDeserializeGeoTransform( CPLGetXMLValue( psTree, "DstGeoTransform", "" ), 
+                                     psInfo->adfDstGeoTransform );
 
         if( CPLGetXMLNode( psTree, "DstInvGeoTransform" ) != NULL )
         {
-            sscanf( CPLGetXMLValue( psTree, "DstInvGeoTransform", "" ), 
-                    "%lg,%lg,%lg,%lg,%lg,%lg", 
-                    psInfo->adfDstInvGeoTransform + 0,
-                    psInfo->adfDstInvGeoTransform + 1,
-                    psInfo->adfDstInvGeoTransform + 2,
-                    psInfo->adfDstInvGeoTransform + 3,
-                    psInfo->adfDstInvGeoTransform + 4,
-                    psInfo->adfDstInvGeoTransform + 5 );
-            
+            GDALDeserializeGeoTransform( CPLGetXMLValue( psTree, "DstInvGeoTransform", "" ), 
+                                        psInfo->adfDstInvGeoTransform );
         }
         else
         {
@@ -2309,7 +2341,7 @@ void *GDALCreateReprojectionTransformer( const char *pszSrcWKT,
     psInfo->poReverseTransform = 
         OGRCreateCoordinateTransformation(&oDstSRS,&oSrcSRS);
 
-    strcpy( psInfo->sTI.szSignature, "GTI" );
+    memcpy( psInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psInfo->sTI.pszClassName = "GDALReprojectionTransformer";
     psInfo->sTI.pfnTransform = GDALReprojectionTransform;
     psInfo->sTI.pfnCleanup = GDALDestroyReprojectionTransformer;
@@ -2480,12 +2512,13 @@ typedef struct
 } ApproxTransformInfo;
 
 /************************************************************************/
-/*                    GDALCloneApproxTransformer()                      */
+/*                  GDALCreateSimilarApproxTransformer()                */
 /************************************************************************/
 
-void* GDALCloneApproxTransformer( void *hTransformArg )
+static
+void* GDALCreateSimilarApproxTransformer( void *hTransformArg, double dfSrcRatioX, double dfSrcRatioY )
 {
-    VALIDATE_POINTER1( hTransformArg, "GDALCloneApproxTransformer", NULL );
+    VALIDATE_POINTER1( hTransformArg, "GDALCreateSimilarApproxTransformer", NULL );
 
     ApproxTransformInfo *psInfo = 
         (ApproxTransformInfo *) hTransformArg;
@@ -2496,7 +2529,9 @@ void* GDALCloneApproxTransformer( void *hTransformArg )
     memcpy(psClonedInfo, psInfo, sizeof(ApproxTransformInfo));
     if( psClonedInfo->pBaseCBData )
     {
-        psClonedInfo->pBaseCBData = GDALCloneTransformer( psInfo->pBaseCBData );
+        psClonedInfo->pBaseCBData = GDALCreateSimilarTransformer( psInfo->pBaseCBData,
+                                                                  dfSrcRatioX,
+                                                                  dfSrcRatioY );
         if( psClonedInfo->pBaseCBData == NULL )
         {
             CPLFree(psClonedInfo);
@@ -2598,11 +2633,12 @@ void *GDALCreateApproxTransformer( GDALTransformerFunc pfnBaseTransformer,
     psATInfo->dfMaxError = dfMaxError;
     psATInfo->bOwnSubtransformer = FALSE;
 
-    strcpy( psATInfo->sTI.szSignature, "GTI" );
+    memcpy( psATInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psATInfo->sTI.pszClassName = "GDALApproxTransformer";
     psATInfo->sTI.pfnTransform = GDALApproxTransform;
     psATInfo->sTI.pfnCleanup = GDALDestroyApproxTransformer;
     psATInfo->sTI.pfnSerialize = GDALSerializeApproxTransformer;
+    psATInfo->sTI.pfnCreateSimilar = GDALCreateSimilarApproxTransformer;
 
     return psATInfo;
 }
@@ -2646,6 +2682,249 @@ void GDALDestroyApproxTransformer( void * pCBData )
 }
 
 /************************************************************************/
+/*                      GDALApproxTransformInternal()                   */
+/************************************************************************/
+
+static int GDALApproxTransformInternal( void *pCBData, int bDstToSrc, int nPoints, 
+                                        double *x, double *y, double *z, int *panSuccess,
+                                        const double xSMETransformed[3], /* SME = Start, Middle, End */
+                                        const double ySMETransformed[3],
+                                        const double zSMETransformed[3])
+{
+    ApproxTransformInfo *psATInfo = (ApproxTransformInfo *) pCBData;
+    double dfDeltaX, dfDeltaY, dfError, dfDist, dfDeltaZ;
+    int nMiddle, i, bSuccess;
+
+    nMiddle = (nPoints-1)/2;
+
+#ifdef notdef_sanify_check
+    {
+        double x2[3], y2[3], z2[3];
+        int anSuccess2[3];
+        x2[0] = x[0];
+        y2[0] = y[0];
+        z2[0] = z[0];
+        x2[1] = x[nMiddle];
+        y2[1] = y[nMiddle];
+        z2[1] = z[nMiddle];
+        x2[2] = x[nPoints-1];
+        y2[2] = y[nPoints-1];
+        z2[2] = z[nPoints-1];
+
+        bSuccess = 
+            psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 3, 
+                                        x2, y2, z2, anSuccess2 );
+        CPLAssert(bSuccess);
+        CPLAssert(anSuccess2[0]);
+        CPLAssert(anSuccess2[1]);
+        CPLAssert(anSuccess2[2]);
+        CPLAssert(x2[0] == xSMETransformed[0]);
+        CPLAssert(y2[0] == ySMETransformed[0]);
+        CPLAssert(z2[0] == zSMETransformed[0]);
+        CPLAssert(x2[1] == xSMETransformed[1]);
+        CPLAssert(y2[1] == ySMETransformed[1]);
+        CPLAssert(z2[1] == zSMETransformed[1]);
+        CPLAssert(x2[2] == xSMETransformed[2]);
+        CPLAssert(y2[2] == ySMETransformed[2]);
+        CPLAssert(z2[2] == zSMETransformed[2]);
+    }
+#endif
+
+#ifdef DEBUG_APPROX_TRANSFORMER
+    fprintf(stderr, "start (%.3f,%.3f) -> (%.3f,%.3f)\n",
+            x[0], y[0], xSMETransformed[0], ySMETransformed[0]);
+    fprintf(stderr, "middle (%.3f,%.3f) -> (%.3f,%.3f)\n",
+            x[nMiddle], y[nMiddle], xSMETransformed[1], ySMETransformed[1]);
+    fprintf(stderr, "end (%.3f,%.3f) -> (%.3f,%.3f)\n",
+            x[nPoints-1], y[nPoints-1], xSMETransformed[2], ySMETransformed[2]);
+#endif
+
+/* -------------------------------------------------------------------- */
+/*      Is the error at the middle acceptable relative to an            */
+/*      interpolation of the middle position?                           */
+/* -------------------------------------------------------------------- */
+    dfDeltaX = (xSMETransformed[2] - xSMETransformed[0]) / (x[nPoints-1] - x[0]);
+    dfDeltaY = (ySMETransformed[2] - ySMETransformed[0]) / (x[nPoints-1] - x[0]);
+    dfDeltaZ = (zSMETransformed[2] - zSMETransformed[0]) / (x[nPoints-1] - x[0]);
+
+    dfError = fabs((xSMETransformed[0] + dfDeltaX * (x[nMiddle] - x[0])) - xSMETransformed[1])
+            + fabs((ySMETransformed[0] + dfDeltaY * (x[nMiddle] - x[0])) - ySMETransformed[1]);
+
+    if( dfError > psATInfo->dfMaxError )
+    {
+#ifdef notdef
+        CPLDebug( "GDAL", "ApproxTransformer - "
+                  "error %g over threshold %g, subdivide %d points.",
+                  dfError, psATInfo->dfMaxError, nPoints );
+#endif
+
+        double xMiddle[3], yMiddle[3], zMiddle[3];
+        int  anSuccess2[3];
+        xMiddle[0] = x[ (nMiddle - 1) / 2 ];
+        yMiddle[0] = y[ (nMiddle - 1) / 2 ];
+        zMiddle[0] = z[ (nMiddle - 1) / 2 ];
+        xMiddle[1] = x[ nMiddle - 1 ];
+        yMiddle[1] = y[ nMiddle - 1 ];
+        zMiddle[1] = z[ nMiddle - 1 ];
+        xMiddle[2] = x[ nMiddle + (nPoints - nMiddle - 1) / 2 ];
+        yMiddle[2] = y[ nMiddle + (nPoints - nMiddle - 1) / 2 ];
+        zMiddle[2] = z[ nMiddle + (nPoints - nMiddle - 1) / 2 ];
+
+        int bUseBaseTransformForHalf1 = ( nMiddle <= 5 ||
+                                y[0] != y[nMiddle-1] ||
+                                y[0] != y[(nMiddle - 1) / 2] ||
+                                x[0] == x[nMiddle-1] ||
+                                x[0] == x[(nMiddle - 1) / 2]  );
+        int bUseBaseTransformForHalf2 = ( nPoints - nMiddle <= 5 ||
+                                 y[nMiddle] != y[nPoints-1] ||
+                                 y[nMiddle] != y[nMiddle + (nPoints - nMiddle - 1) / 2] ||
+                                 x[nMiddle] == x[nPoints-1] ||
+                                 x[nMiddle] == x[nMiddle + (nPoints - nMiddle - 1) / 2] );
+
+        if( !bUseBaseTransformForHalf1 && !bUseBaseTransformForHalf2 )
+            bSuccess = 
+                psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 3, 
+                                             xMiddle, yMiddle, zMiddle, anSuccess2 );
+        else if( !bUseBaseTransformForHalf1 )
+        {
+            bSuccess = 
+                psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 2, 
+                                             xMiddle, yMiddle, zMiddle, anSuccess2 );
+            anSuccess2[2] = TRUE;
+        }
+        else if( !bUseBaseTransformForHalf2 )
+        {
+            bSuccess = 
+                psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 1, 
+                                              xMiddle + 2, yMiddle + 2, zMiddle + 2,
+                                              anSuccess2 + 2 );
+            anSuccess2[0] = TRUE;
+            anSuccess2[1] = TRUE;
+        }
+        else
+            bSuccess = FALSE;
+        if( !bSuccess || !anSuccess2[0] || !anSuccess2[1] || !anSuccess2[2] )
+        {
+            bSuccess = psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+                                                     nMiddle - 1,
+                                                     x + 1, y + 1, z + 1,
+                                                     panSuccess + 1 );
+            bSuccess &= psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+                                                      nPoints - nMiddle - 2,
+                                                      x + nMiddle + 1,
+                                                      y + nMiddle + 1,
+                                                      z + nMiddle + 1,
+                                                      panSuccess + nMiddle + 1 );
+
+            x[0] = xSMETransformed[0];
+            y[0] = ySMETransformed[0];
+            z[0] = zSMETransformed[0];
+            panSuccess[0] = TRUE;
+            x[nMiddle] = xSMETransformed[1];
+            y[nMiddle] = ySMETransformed[1];
+            z[nMiddle] = zSMETransformed[1];
+            panSuccess[nMiddle] = TRUE;
+            x[nPoints-1] = xSMETransformed[2];
+            y[nPoints-1] = ySMETransformed[2];
+            z[nPoints-1] = zSMETransformed[2];
+            panSuccess[nPoints-1] = TRUE;
+            return bSuccess;
+        }
+
+        double x2[3], y2[3], z2[3];
+        if( !bUseBaseTransformForHalf1 )
+        {
+            x2[0] = xSMETransformed[0];
+            y2[0] = ySMETransformed[0];
+            z2[0] = zSMETransformed[0];
+            x2[1] = xMiddle[0];
+            y2[1] = yMiddle[0];
+            z2[1] = zMiddle[0];
+            x2[2] = xMiddle[1];
+            y2[2] = yMiddle[1];
+            z2[2] = zMiddle[1];
+
+            bSuccess = 
+                GDALApproxTransformInternal( psATInfo, bDstToSrc, nMiddle, 
+                                            x, y, z, panSuccess,
+                                            x2, y2, z2);
+    
+        }
+        else
+        {
+            bSuccess = psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+                                                     nMiddle - 1, x + 1, y + 1, z + 1,
+                                                     panSuccess + 1 );
+            x[0] = xSMETransformed[0];
+            y[0] = ySMETransformed[0];
+            z[0] = zSMETransformed[0];
+            panSuccess[0] = TRUE;
+        }
+
+        if( !bSuccess )
+            return FALSE;
+
+        if( !bUseBaseTransformForHalf2 )
+        {
+            x2[0] = xSMETransformed[1];
+            y2[0] = ySMETransformed[1];
+            z2[0] = zSMETransformed[1];
+            x2[1] = xMiddle[2];
+            y2[1] = yMiddle[2];
+            z2[1] = zMiddle[2];
+            x2[2] = xSMETransformed[2];
+            y2[2] = ySMETransformed[2];
+            z2[2] = zSMETransformed[2];
+
+            bSuccess = 
+                GDALApproxTransformInternal( psATInfo, bDstToSrc, nPoints - nMiddle,
+                                            x+nMiddle, y+nMiddle, z+nMiddle,
+                                            panSuccess+nMiddle,
+                                            x2, y2, z2);
+        }
+        else
+        {
+            bSuccess = psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+                                                     nPoints - nMiddle - 2,
+                                                     x+nMiddle + 1, y+nMiddle+1, z+nMiddle+1,
+                                                     panSuccess+nMiddle+1 );
+
+            x[nMiddle] = xSMETransformed[1];
+            y[nMiddle] = ySMETransformed[1];
+            z[nMiddle] = zSMETransformed[1];
+            panSuccess[nMiddle] = TRUE;
+            x[nPoints-1] = xSMETransformed[2];
+            y[nPoints-1] = ySMETransformed[2];
+            z[nPoints-1] = zSMETransformed[2];
+            panSuccess[nPoints-1] = TRUE;
+        }
+
+        if( !bSuccess )
+            return FALSE;
+
+        return TRUE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Error is OK since this is just used to compute output bounds    */
+/*      of newly created file for gdalwarper.  So just use affine       */
+/*      approximation of the reverse transform.  Eventually we          */
+/*      should implement iterative searching to find a result within    */
+/*      our error threshold.                                            */
+/* -------------------------------------------------------------------- */
+    for( i = nPoints-1; i >= 0; i-- )
+    {
+        dfDist = (x[i] - x[0]);
+        x[i] = xSMETransformed[0] + dfDeltaX * dfDist;
+        y[i] = ySMETransformed[0] + dfDeltaY * dfDist;
+        z[i] = zSMETransformed[0] + dfDeltaZ * dfDist;
+        panSuccess[i] = TRUE;
+    }
+    
+    return TRUE;
+}
+
+/************************************************************************/
 /*                        GDALApproxTransform()                         */
 /************************************************************************/
 
@@ -2657,14 +2936,14 @@ void GDALDestroyApproxTransformer( void * pCBData )
  * GDALTransformerFunc() signature.  Details of the arguments are described
  * there. 
  */
- 
+
 int GDALApproxTransform( void *pCBData, int bDstToSrc, int nPoints, 
                          double *x, double *y, double *z, int *panSuccess )
 
 {
     ApproxTransformInfo *psATInfo = (ApproxTransformInfo *) pCBData;
-    double x2[3], y2[3], z2[3], dfDeltaX, dfDeltaY, dfError, dfDist, dfDeltaZ;
-    int nMiddle, anSuccess2[3], i, bSuccess;
+    double x2[3], y2[3], z2[3];
+    int nMiddle, anSuccess2[3], bSuccess;
 
     nMiddle = (nPoints-1)/2;
 
@@ -2672,12 +2951,14 @@ int GDALApproxTransform( void *pCBData, int bDstToSrc, int nPoints,
 /*      Bail if our preconditions are not met, or if error is not       */
 /*      acceptable.                                                     */
 /* -------------------------------------------------------------------- */
+    int bRet = FALSE;
     if( y[0] != y[nPoints-1] || y[0] != y[nMiddle]
         || x[0] == x[nPoints-1] || x[0] == x[nMiddle]
         || psATInfo->dfMaxError == 0.0 || nPoints <= 5 )
     {
-        return psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+        bRet = psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
                                              nPoints, x, y, z, panSuccess );
+        goto end;
     }
 
 /* -------------------------------------------------------------------- */
@@ -2697,63 +2978,25 @@ int GDALApproxTransform( void *pCBData, int bDstToSrc, int nPoints,
         psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc, 3, 
                                       x2, y2, z2, anSuccess2 );
     if( !bSuccess || !anSuccess2[0] || !anSuccess2[1] || !anSuccess2[2] )
-        return psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
+    {
+        bRet = psATInfo->pfnBaseTransformer( psATInfo->pBaseCBData, bDstToSrc,
                                              nPoints, x, y, z, panSuccess );
-    
-/* -------------------------------------------------------------------- */
-/*      Is the error at the middle acceptable relative to an            */
-/*      interpolation of the middle position?                           */
-/* -------------------------------------------------------------------- */
-    dfDeltaX = (x2[2] - x2[0]) / (x[nPoints-1] - x[0]);
-    dfDeltaY = (y2[2] - y2[0]) / (x[nPoints-1] - x[0]);
-    dfDeltaZ = (z2[2] - z2[0]) / (x[nPoints-1] - x[0]);
+        goto end;
+    }
 
-    dfError = fabs((x2[0] + dfDeltaX * (x[nMiddle] - x[0])) - x2[1])
-        + fabs((y2[0] + dfDeltaY * (x[nMiddle] - x[0])) - y2[1]);
+    bRet = GDALApproxTransformInternal( pCBData, bDstToSrc, nPoints, 
+                                        x, y, z, panSuccess,
+                                        x2,
+                                        y2,
+                                        z2 );
 
-    if( dfError > psATInfo->dfMaxError )
-    {
-#ifdef notdef
-        CPLDebug( "GDAL", "ApproxTransformer - "
-                  "error %g over threshold %g, subdivide %d points.",
-                  dfError, psATInfo->dfMaxError, nPoints );
+end:
+#ifdef DEBUG_APPROX_TRANSFORMER
+    for(int i=0;i<nPoints;i++ )
+        fprintf(stderr, "[%d] (%.10f,%.10f) %d\n", i, x[i], y[i], panSuccess[i]);
 #endif
 
-        bSuccess = 
-            GDALApproxTransform( psATInfo, bDstToSrc, nMiddle, 
-                                 x, y, z, panSuccess );
-            
-        if( !bSuccess )
-            return FALSE;
-
-        bSuccess = 
-            GDALApproxTransform( psATInfo, bDstToSrc, nPoints - nMiddle,
-                                 x+nMiddle, y+nMiddle, z+nMiddle,
-                                 panSuccess+nMiddle );
-
-        if( !bSuccess )
-            return FALSE;
-
-        return TRUE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Error is OK since this is just used to compute output bounds    */
-/*      of newly created file for gdalwarper.  So just use affine       */
-/*      approximation of the reverse transform.  Eventually we          */
-/*      should implement iterative searching to find a result within    */
-/*      our error threshold.                                            */
-/* -------------------------------------------------------------------- */
-    for( i = nPoints-1; i >= 0; i-- )
-    {
-        dfDist = (x[i] - x[0]);
-        y[i] = y2[0] + dfDeltaY * dfDist;
-        x[i] = x2[0] + dfDeltaX * dfDist;
-        z[i] = z2[0] + dfDeltaZ * dfDist;
-        panSuccess[i] = TRUE;
-    }
-    
-    return TRUE;
+    return bRet;
 }
 
 /************************************************************************/
@@ -2764,7 +3007,7 @@ static void *
 GDALDeserializeApproxTransformer( CPLXMLNode *psTree )
 
 {
-    double dfMaxError = atof(CPLGetXMLValue( psTree, "MaxError",  "0.25" ));
+    double dfMaxError = CPLAtof(CPLGetXMLValue( psTree, "MaxError",  "0.25" ));
     CPLXMLNode *psContainer;
     GDALTransformerFunc pfnBaseTransform = NULL;
     void *pBaseCBData = NULL;
@@ -2900,16 +3143,16 @@ int CPL_STDCALL GDALInvGeoTransform( double *gt_in, double *gt_out )
 
 CPLXMLNode *GDALSerializeTransformer( CPL_UNUSED GDALTransformerFunc pfnFunc,
                                       void *pTransformArg )
-
 {
     VALIDATE_POINTER1( pTransformArg, "GDALSerializeTransformer", NULL );
 
     GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
 
-    if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to serialize non-GTI transformer." );
+                  "Attempt to serialize non-GTI2 transformer." );
         return NULL;
     }
     else if ( psInfo->pfnSerialize == NULL )
@@ -2929,7 +3172,7 @@ CPLXMLNode *GDALSerializeTransformer( CPL_UNUSED GDALTransformerFunc pfnFunc,
 /************************************************************************/
 
 static CPLList* psListDeserializer = NULL;
-static void* hDeserializerMutex = NULL;
+static CPLMutex* hDeserializerMutex = NULL;
 
 typedef struct
 {
@@ -3092,10 +3335,11 @@ void GDALDestroyTransformer( void *pTransformArg )
 {
     GDALTransformerInfo *psInfo = (GDALTransformerInfo *) pTransformArg;
 
-    if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to destroy non-GTI transformer." );
+                  "Attempt to destroy non-GTI2 transformer." );
     }
     else
         psInfo->pfnCleanup( pTransformArg );
@@ -3112,10 +3356,11 @@ int GDALUseTransformer( void *pTransformArg,
 {
     GDALTransformerInfo *psInfo = (GDALTransformerInfo *) pTransformArg;
 
-    if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to use non-GTI transformer." );
+                  "Attempt to use non-GTI2 transformer." );
         return FALSE;
     }
     else
@@ -3127,56 +3372,23 @@ int GDALUseTransformer( void *pTransformArg,
 /*                        GDALCloneTransformer()                        */
 /************************************************************************/
 
-/* TODO GDAL 2.0 : use a void* (*pfnClone) (void *) member */
 void *GDALCloneTransformer( void *pTransformArg )
 {
     VALIDATE_POINTER1( pTransformArg, "GDALCloneTransformer", NULL );
 
     GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
 
-    if( psInfo == NULL || !EQUAL(psInfo->szSignature,"GTI") )
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to clone non-GTI transformer." );
+                  "Attempt to clone non-GTI2 transformer." );
         return NULL;
     }
 
-    void* (*pfnClone)(void*) = NULL;
-    if( EQUAL(psInfo->pszClassName,"GDALTPSTransformer") )
-    {
-        pfnClone = GDALCloneTPSTransformer;
-    }
-    /* TODO
-    else if( EQUAL(psInfo->pszClassName,"GDALGeoLocTransformer") )
-    {
-        pfnClone = GDALCloneGeoLocTransformer;
-    }
-    else if( EQUAL(psInfo->pszClassName,"GDALRPCTransformer") )
-    {
-        pfnClone = GDALCloneRPCTransformer;
-    }
-    */
-    else if( EQUAL(psInfo->pszClassName,"GDALGenImgProjTransformer") )
-    {
-        pfnClone = GDALCloneGenImgProjTransformer;
-    }
-    /* Useless : serialization/deserialization is fine */
-    /*
-    else if( EQUAL(psInfo->pszClassName,"GDALReprojectionTransformer") )
-    {
-        pfnClone = GDALCloneReprojectionTransformer;
-    }
-    */
-    else if( EQUAL(psInfo->pszClassName,"GDALApproxTransformer") )
-    {
-        pfnClone = GDALCloneApproxTransformer;
-    }
-
-    if( pfnClone != NULL )
+    if( psInfo->pfnCreateSimilar != NULL )
     {
-        void* pRet = pfnClone(pTransformArg);
-        if( pRet != NULL )
-            return pRet;
+        return psInfo->pfnCreateSimilar(psInfo, 1.0, 1.0);
     }
 
     if ( psInfo->pfnSerialize == NULL )
@@ -3202,3 +3414,70 @@ void *GDALCloneTransformer( void *pTransformArg )
         return pClonedTransformArg;
     }
 }
+
+/************************************************************************/
+/*                   GDALCreateSimilarTransformer()                     */
+/************************************************************************/
+
+void* GDALCreateSimilarTransformer( void* pTransformArg, double dfRatioX, double dfRatioY )
+{
+    VALIDATE_POINTER1( pTransformArg, "GDALCreateSimilarTransformer", NULL );
+
+    GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
+
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Attempt to call CreateSimilar on a non-GTI2 transformer." );
+        return NULL;
+    }
+
+    if( psInfo->pfnCreateSimilar != NULL )
+    {
+        return psInfo->pfnCreateSimilar(psInfo, dfRatioX, dfRatioY);
+    }
+    
+    CPLError( CE_Failure, CPLE_AppDefined,
+                  "No CreateSimilar function available for this transformer." );
+    return NULL;
+}
+
+/************************************************************************/
+/*                 GDALSetTransformerDstGeoTransform()                  */
+/************************************************************************/
+
+void GDALSetTransformerDstGeoTransform(void *pTransformArg,
+                                       const double *padfGeoTransform )
+{
+    VALIDATE_POINTER0( pTransformArg, "GDALSetTransformerDstGeoTransform" );
+
+    GDALTransformerInfo *psInfo = static_cast<GDALTransformerInfo *>(pTransformArg);
+
+    if( psInfo == NULL ||
+        memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Attempt to call GDALSetTransformerDstGeoTransform on a non-GTI2 transformer." );
+        return;
+    }
+    
+    if( EQUAL(psInfo->pszClassName, "GDALApproxTransformer") )
+    {
+        ApproxTransformInfo   *psATInfo = (ApproxTransformInfo*)pTransformArg;
+        psInfo = (GDALTransformerInfo *)psATInfo->pBaseCBData;
+          
+        if( psInfo == NULL ||
+            memcmp(psInfo->abySignature,GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE)) != 0 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to call GDALSetTransformerDstGeoTransform on a non-GTI2 transformer." );
+            return;
+        }
+    }
+    
+    if( EQUAL(psInfo->pszClassName, "GDALGenImgProjTransformer") )
+    {
+        GDALSetGenImgProjTransformerDstGeoTransform(psInfo, padfGeoTransform);
+    }
+}
diff --git a/alg/gdaltransformgeolocs.cpp b/alg/gdaltransformgeolocs.cpp
index 48179b0..d12b259 100644
--- a/alg/gdaltransformgeolocs.cpp
+++ b/alg/gdaltransformgeolocs.cpp
@@ -60,12 +60,12 @@ CPL_CVSID("$Id$");
  */
 
 CPLErr
-GDALTransformGeolocations( GDALRasterBandH hXBand, 
-                           GDALRasterBandH hYBand, 
+GDALTransformGeolocations( GDALRasterBandH hXBand,
+                           GDALRasterBandH hYBand,
                            GDALRasterBandH hZBand,
-                           GDALTransformerFunc pfnTransformer, 
-                           void *pTransformArg, 
-                           GDALProgressFunc pfnProgress, 
+                           GDALTransformerFunc pfnTransformer,
+                           void *pTransformArg,
+                           GDALProgressFunc pfnProgress,
                            void *pProgressArg,
                            CPL_UNUSED char **papszOptions )
 
@@ -109,13 +109,13 @@ GDALTransformGeolocations( GDALRasterBandH hXBand,
     for( iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ )
     {
         eErr = poXBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
-                                  padfX, nXSize, 1, GDT_Float64, 0, 0 );
+                                  padfX, nXSize, 1, GDT_Float64, 0, 0, NULL );
         if( eErr == CE_None )
             eErr = poYBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
-                                      padfY, nXSize, 1, GDT_Float64, 0, 0 );
+                                      padfY, nXSize, 1, GDT_Float64, 0, 0, NULL );
         if( eErr == CE_None && poZBand != NULL )
             eErr = poZBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
-                                      padfZ, nXSize, 1, GDT_Float64, 0, 0 );
+                                      padfZ, nXSize, 1, GDT_Float64, 0, 0, NULL );
         else
             memset( padfZ, 0, sizeof(double) * nXSize);
         
@@ -127,13 +127,13 @@ GDALTransformGeolocations( GDALRasterBandH hXBand,
 
         if( eErr == CE_None )
             eErr = poXBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
-                                      padfX, nXSize, 1, GDT_Float64, 0, 0 );
+                                      padfX, nXSize, 1, GDT_Float64, 0, 0, NULL );
         if( eErr == CE_None )
             eErr = poYBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
-                                      padfY, nXSize, 1, GDT_Float64, 0, 0 );
+                                      padfY, nXSize, 1, GDT_Float64, 0, 0, NULL );
         if( eErr == CE_None && poZBand != NULL )
             eErr = poZBand->RasterIO( GF_Write, 0, iLine, nXSize, 1,
-                                      padfZ, nXSize, 1, GDT_Float64, 0, 0 );
+                                      padfZ, nXSize, 1, GDT_Float64, 0, 0, NULL );
 
         if( eErr == CE_None )
             pfnProgress( (iLine+1) / (double) nYSize, "", pProgressArg );
diff --git a/alg/gdalwarper.cpp b/alg/gdalwarper.cpp
index 647bff1..ecc8a94 100644
--- a/alg/gdalwarper.cpp
+++ b/alg/gdalwarper.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarper.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gdalwarper.cpp 28919 2015-04-16 18:57:58Z rouault $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Implementation of high level convenience APIs for warper.
@@ -34,7 +34,7 @@
 #include "ogr_api.h"
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalwarper.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gdalwarper.cpp 28919 2015-04-16 18:57:58Z rouault $");
 
 /************************************************************************/
 /*                         GDALReprojectImage()                         */
@@ -52,6 +52,9 @@ CPL_CVSID("$Id: gdalwarper.cpp 27739 2014-09-25 18:49:52Z goatbar $");
  * No metadata, projection info, or color tables are transferred
  * to the output file. 
  *
+ * Starting with GDAL 2.0, nodata values set on destination dataset are taken
+ * into account.
+ *
  * @param hSrcDS the source image file. 
  * @param pszSrcWKT the source projection.  If NULL the source projection
  * is read from from hSrcDS.
@@ -152,7 +155,7 @@ GDALReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
 
 /* -------------------------------------------------------------------- */
 /*      Set source nodata values if the source dataset seems to have    */
-/*      any.                                                            */
+/*      any. Same for target nodata values                              */
 /* -------------------------------------------------------------------- */
     for( iBand = 0; iBand < psWOptions->nBandCount; iBand++ )
     {
@@ -187,11 +190,34 @@ GDALReprojectImage( GDALDatasetH hSrcDS, const char *pszSrcWKT,
             psWOptions->padfSrcNoDataReal[iBand] = dfNoDataValue;
         }
 
+        // Deal with target band
         hBand = GDALGetRasterBand( hDstDS, iBand+1 );
         if (hBand && GDALGetRasterColorInterpretation(hBand) == GCI_AlphaBand)
         {
             psWOptions->nDstAlphaBand = iBand + 1;
         }
+
+        dfNoDataValue = GDALGetRasterNoDataValue( hBand, &bGotNoData );
+        if( bGotNoData )
+        {
+            if( psWOptions->padfDstNoDataReal == NULL )
+            {
+                int  ii;
+
+                psWOptions->padfDstNoDataReal = (double *) 
+                    CPLMalloc(sizeof(double) * psWOptions->nBandCount);
+                psWOptions->padfDstNoDataImag = (double *) 
+                    CPLMalloc(sizeof(double) * psWOptions->nBandCount);
+
+                for( ii = 0; ii < psWOptions->nBandCount; ii++ )
+                {
+                    psWOptions->padfDstNoDataReal[ii] = -1.1e20;
+                    psWOptions->padfDstNoDataImag[ii] = 0.0;
+                }
+            }
+
+            psWOptions->padfDstNoDataReal[iBand] = dfNoDataValue;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -338,12 +364,14 @@ CPLErr
 GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType, 
                       int /* nXOff */, int /* nYOff */, int nXSize, int nYSize,
                       GByte **ppImageData, 
-                      int bMaskIsFloat, void *pValidityMask )
+                      int bMaskIsFloat, void *pValidityMask, int* pbOutAllValid )
 
 {
     double *padfNoData = (double *) pMaskFuncArg;
     GUInt32 *panValidityMask = (GUInt32 *) pValidityMask;
 
+    *pbOutAllValid = FALSE;
+
     if( nBandCount != 1 || bMaskIsFloat )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -362,15 +390,21 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
           // nothing to do if value is out of range.
           if( padfNoData[0] < 0.0 || padfNoData[0] > 255.000001 
               || padfNoData[1] != 0.0 )
+          {
+              *pbOutAllValid = TRUE;
               return CE_None;
+          }
 
+          int bAllValid = TRUE;
           for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
           {
               if( pabyData[iOffset] == nNoData )
               {
+                  bAllValid = FALSE;
                   panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
               }
           }
+          *pbOutAllValid = bAllValid;
       }
       break;
       
@@ -383,15 +417,21 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
           // nothing to do if value is out of range.
           if( padfNoData[0] < -32768 || padfNoData[0] > 32767
               || padfNoData[1] != 0.0 )
+          {
+              *pbOutAllValid = TRUE;
               return CE_None;
+          }
 
+          int bAllValid = TRUE;
           for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
           {
               if( panData[iOffset] == nNoData )
               {
+                  bAllValid = FALSE;
                   panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
               }
           }
+          *pbOutAllValid = bAllValid;
       }
       break;
       
@@ -404,15 +444,21 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
           // nothing to do if value is out of range.
           if( padfNoData[0] < 0 || padfNoData[0] > 65535
               || padfNoData[1] != 0.0 )
+          {
+              *pbOutAllValid = TRUE;
               return CE_None;
+          }
 
+          int bAllValid = TRUE;
           for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
           {
               if( panData[iOffset] == nNoData )
               {
+                  bAllValid = FALSE;
                   panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
               }
           }
+          *pbOutAllValid = bAllValid;
       }
       break;
       
@@ -425,16 +471,22 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
 
           // nothing to do if value is out of range.
           if( padfNoData[1] != 0.0 )
+          {
+              *pbOutAllValid = TRUE;
               return CE_None;
+          }
 
+          int bAllValid = TRUE;
           for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
           {
               float fVal = pafData[iOffset];
               if( (bIsNoDataNan && CPLIsNan(fVal)) || (!bIsNoDataNan && ARE_REAL_EQUAL(fVal, fNoData)) )
               {
+                  bAllValid = FALSE;
                   panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
               }
           }
+          *pbOutAllValid = bAllValid;
       }
       break;
       
@@ -447,16 +499,22 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
 
           // nothing to do if value is out of range.
           if( padfNoData[1] != 0.0 )
+          {
+              *pbOutAllValid = TRUE;
               return CE_None;
+          }
 
+          int bAllValid = TRUE;
           for( iOffset = nXSize*nYSize-1; iOffset >= 0; iOffset-- )
           {
               double dfVal = padfData[iOffset];
               if( (bIsNoDataNan && CPLIsNan(dfVal)) || (!bIsNoDataNan && ARE_REAL_EQUAL(dfVal, dfNoData)) )
               {
+                  bAllValid = FALSE;
                   panValidityMask[iOffset>>5] &= ~(0x01 << (iOffset & 0x1f));
               }
           }
+          *pbOutAllValid = bAllValid;
       }
       break;
       
@@ -470,6 +528,7 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
           int bIsNoDataImagNan = CPLIsNan(padfNoData[1]);
 
           padfWrk = (double *) CPLMalloc(nXSize * sizeof(double) * 2);
+          int bAllValid = TRUE;
           for( iLine = 0; iLine < nYSize; iLine++ )
           {
               GDALCopyWords( ((GByte *) *ppImageData)+nWordSize*iLine*nXSize, 
@@ -485,12 +544,14 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
                   {
                       int iOffset = iPixel + iLine * nXSize;
                       
+                      bAllValid = FALSE;
                       panValidityMask[iOffset>>5] &=
                           ~(0x01 << (iOffset & 0x1f));
                   }
               }
               
           }
+          *pbOutAllValid = bAllValid;
 
           CPLFree( padfWrk );
       }
@@ -509,14 +570,18 @@ GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
 /************************************************************************/
 
 CPLErr 
-GDALWarpSrcAlphaMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED GDALDataType eType, 
+GDALWarpSrcAlphaMasker( void *pMaskFuncArg,
+                        CPL_UNUSED int nBandCount,
+                        CPL_UNUSED GDALDataType eType,
                         int nXOff, int nYOff, int nXSize, int nYSize,
                         GByte ** /*ppImageData */,
-                        int bMaskIsFloat, void *pValidityMask )
+                        int bMaskIsFloat, void *pValidityMask,
+                        int* pbOutAllOpaque )
 
 {
     GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
     float *pafMask = (float *) pValidityMask;
+    *pbOutAllOpaque = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Do some minimal checking.                                       */
@@ -551,11 +616,16 @@ GDALWarpSrcAlphaMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSE
 /* -------------------------------------------------------------------- */
 /*      Rescale from 0-255 to 0.0-1.0.                                  */
 /* -------------------------------------------------------------------- */
+    int bOutAllOpaque = TRUE;
     for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
     {                                    //  (1/255)
         pafMask[iPixel] = (float)( pafMask[iPixel] * 0.00392157 );
-        pafMask[iPixel] = MIN( 1.0F, pafMask[iPixel] );
+        if( pafMask[iPixel] >= 1.0F )
+            pafMask[iPixel] = 1.0F;
+        else
+            bOutAllOpaque = FALSE;
     }
+    *pbOutAllOpaque = bOutAllOpaque;
 
     return CE_None;
 }
@@ -567,8 +637,10 @@ GDALWarpSrcAlphaMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSE
 /*      information and building a one bit validity mask.               */
 /************************************************************************/
 
-CPLErr 
-GDALWarpSrcMaskMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED GDALDataType eType, 
+CPLErr
+GDALWarpSrcMaskMasker( void *pMaskFuncArg,
+                       CPL_UNUSED int nBandCount,
+                       CPL_UNUSED GDALDataType eType,
                        int nXOff, int nYOff, int nXSize, int nYSize,
                        GByte ** /*ppImageData */,
                        int bMaskIsFloat, void *pValidityMask )
@@ -639,7 +711,7 @@ GDALWarpSrcMaskMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED
 /*      Pack into 1 bit per pixel for validity.                         */
 /* -------------------------------------------------------------------- */
     for( int iPixel = nXSize * nYSize - 1; iPixel >= 0; iPixel-- )
-    {                                    
+    {
         if( pabySrcMask[iPixel] == 0 )
             panMask[iPixel>>5] &= ~(0x01 << (iPixel & 0x1f));
     }
@@ -658,12 +730,12 @@ GDALWarpSrcMaskMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED
 /*      negative bandcount.                                             */
 /************************************************************************/
 
-CPLErr 
-GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, CPL_UNUSED GDALDataType eType,
+CPLErr
+GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount,
+                        CPL_UNUSED GDALDataType eType,
                         int nXOff, int nYOff, int nXSize, int nYSize,
                         GByte ** /*ppImageData */,
                         int bMaskIsFloat, void *pValidityMask )
-
 {
     GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg;
     float *pafMask = (float *) pValidityMask;
@@ -842,6 +914,24 @@ GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, CPL_UNUSED GDALDataT
  * - NUM_THREADS: (GDAL >= 1.10) Can be set to a numeric value or ALL_CPUS to
  * set the number of threads to use to parallelize the computation part of the
  * warping. If not set, computation will be done in a single thread.
+ *
+ * - STREAMABLE_OUTPUT: (GDAL >= 2.0) This defaults to FALSE, but may be set to TRUE when
+ * outputing typically to a streamed file. The gdalwarp utility automatically
+ * sets this option when outputing to /vsistdout/ or a named pipe (on Unix).
+ * This option has performance impacts for some reprojections.
+ * Note: band interleaved output is not currently supported by the warping algorithm in
+ * a streamable compabible way.
+ *
+ * - SRC_COORD_PRECISION: (GDAL >= 2.0). Advanced setting. This defaults to 0, to indicate that
+ * no rounding of computing source image coordinates corresponding to the target
+ * image must be done. If greater than 0 (and typically below 1), this value,
+ * expressed in pixel, will be used to round computed source image coordinates. The purpose
+ * of this option is to make the results of warping with the approximated transformer
+ * more reproducible and not sensitive to changes in warping memory size. To achieve
+ * that, SRC_COORD_PRECISION must be at least 10 times greater than the error
+ * threshold. The higher the SRC_COORD_PRECISION/error_threshold ratio, the higher
+ * the performance will be, since exact reprojections must statistically be
+ * done with a frequency of 4*error_threshold/SRC_COORD_PRECISION.
  */
 
 /************************************************************************/
@@ -974,6 +1064,16 @@ GDALSerializeWarpOptions( const GDALWarpOptions *psWO )
         pszAlgName = "Average";
     else if( psWO->eResampleAlg == GRA_Mode )
         pszAlgName = "Mode";
+    else if( psWO->eResampleAlg == GRA_Max )
+        pszAlgName = "Maximum";
+    else if( psWO->eResampleAlg == GRA_Min )
+        pszAlgName = "Minimum";
+    else if( psWO->eResampleAlg == GRA_Med )
+        pszAlgName = "Median";
+    else if( psWO->eResampleAlg == GRA_Q1 )
+        pszAlgName = "Quartile1";
+    else if( psWO->eResampleAlg == GRA_Q3 )
+        pszAlgName = "Quartile3";
     else
         pszAlgName = "Unknown";
 
@@ -999,14 +1099,19 @@ GDALSerializeWarpOptions( const GDALWarpOptions *psWO )
         char *pszName = NULL;
         const char *pszValue = 
             CPLParseNameValue( psWO->papszWarpOptions[iWO], &pszName );
+            
+        /* EXTRA_ELTS is an internal detail that we will recover */
+        /* no need to serialize it */
+        if( !EQUAL(pszName, "EXTRA_ELTS") )
+        {
+            CPLXMLNode *psOption = 
+                CPLCreateXMLElementAndValue( 
+                    psTree, "Option", pszValue );
 
-        CPLXMLNode *psOption = 
-            CPLCreateXMLElementAndValue( 
-                psTree, "Option", pszValue );
-
-        CPLCreateXMLNode( 
-            CPLCreateXMLNode( psOption, CXT_Attribute, "name" ),
-            CXT_Text, pszName );
+            CPLCreateXMLNode( 
+                CPLCreateXMLNode( psOption, CXT_Attribute, "name" ),
+                CXT_Text, pszName );
+        }
 
         CPLFree(pszName);
     }
@@ -1019,6 +1124,9 @@ GDALSerializeWarpOptions( const GDALWarpOptions *psWO )
         CPLCreateXMLElementAndValue( 
             psTree, "SourceDataset", 
             GDALGetDescription( psWO->hSrcDS ) );
+        
+        char** papszOpenOptions = ((GDALDataset*)psWO->hSrcDS)->GetOpenOptions();
+        GDALSerializeOpenOptionsToXML(psTree, papszOpenOptions);
     }
     
     if( psWO->hDstDS != NULL && strlen(GDALGetDescription(psWO->hDstDS)) != 0 )
@@ -1175,7 +1283,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
 /*      Warp memory limit.                                              */
 /* -------------------------------------------------------------------- */
     psWO->dfWarpMemoryLimit = 
-        atof(CPLGetXMLValue(psTree,"WarpMemoryLimit","0.0"));
+        CPLAtof(CPLGetXMLValue(psTree,"WarpMemoryLimit","0.0"));
 
 /* -------------------------------------------------------------------- */
 /*      resample algorithm                                              */
@@ -1197,6 +1305,16 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
         psWO->eResampleAlg = GRA_Average;
     else if( EQUAL(pszValue,"Mode") )
         psWO->eResampleAlg = GRA_Mode;
+    else if( EQUAL(pszValue,"Maximum") )
+        psWO->eResampleAlg = GRA_Max;
+    else if( EQUAL(pszValue,"Minimum") )
+        psWO->eResampleAlg = GRA_Min;
+    else if( EQUAL(pszValue,"Median") )
+        psWO->eResampleAlg = GRA_Med;
+    else if( EQUAL(pszValue,"Quartile1") )
+        psWO->eResampleAlg = GRA_Q1;
+    else if( EQUAL(pszValue,"Quartile3") )
+        psWO->eResampleAlg = GRA_Q3;
     else if( EQUAL(pszValue,"Default") )
         /* leave as is */;
     else
@@ -1241,7 +1359,13 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
     pszValue = CPLGetXMLValue(psTree,"SourceDataset",NULL);
 
     if( pszValue != NULL )
-        psWO->hSrcDS = GDALOpenShared( pszValue, GA_ReadOnly );
+    {
+        char** papszOpenOptions = GDALDeserializeOpenOptionsFromXML(psTree);
+        psWO->hSrcDS = GDALOpenEx(
+                    pszValue, GDAL_OF_SHARED | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
+                    (const char* const* )papszOpenOptions, NULL );
+        CSLDestroy(papszOpenOptions);
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Destination Dataset.                                            */
@@ -1324,7 +1448,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
                 psWO->padfSrcNoDataReal = 
                     (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
 
-            psWO->padfSrcNoDataReal[iBand] = CPLAtofM(pszValue);
+            psWO->padfSrcNoDataReal[iBand] = CPLAtof(pszValue);
         }
         
         pszValue = CPLGetXMLValue(psBand,"SrcNoDataImag",NULL);
@@ -1334,7 +1458,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
                 psWO->padfSrcNoDataImag = 
                     (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
 
-            psWO->padfSrcNoDataImag[iBand] = CPLAtofM(pszValue);
+            psWO->padfSrcNoDataImag[iBand] = CPLAtof(pszValue);
         }
         
 /* -------------------------------------------------------------------- */
@@ -1347,7 +1471,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
                 psWO->padfDstNoDataReal = 
                     (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
 
-            psWO->padfDstNoDataReal[iBand] = CPLAtofM(pszValue);
+            psWO->padfDstNoDataReal[iBand] = CPLAtof(pszValue);
         }
         
         pszValue = CPLGetXMLValue(psBand,"DstNoDataImag",NULL);
@@ -1357,7 +1481,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
                 psWO->padfDstNoDataImag = 
                     (double *) CPLCalloc(sizeof(double),psWO->nBandCount);
 
-            psWO->padfDstNoDataImag[iBand] = CPLAtofM(pszValue);
+            psWO->padfDstNoDataImag[iBand] = CPLAtof(pszValue);
         }
         
         iBand++;
@@ -1382,7 +1506,7 @@ GDALWarpOptions * CPL_STDCALL GDALDeserializeWarpOptions( CPLXMLNode *psTree )
     }
 
     psWO->dfCutlineBlendDist =
-        atof( CPLGetXMLValue( psTree, "CutlineBlendDist", "0" ) );
+        CPLAtof( CPLGetXMLValue( psTree, "CutlineBlendDist", "0" ) );
 
 /* -------------------------------------------------------------------- */
 /*      Transformation.                                                 */
diff --git a/alg/gdalwarper.h b/alg/gdalwarper.h
index 4de0c97..68c3684 100644
--- a/alg/gdalwarper.h
+++ b/alg/gdalwarper.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarper.h 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gdalwarper.h 28876 2015-04-08 22:21:55Z rouault $
  *
  * Project:  GDAL High Performance Warper
  * Purpose:  Prototypes, and definitions for warping related work.
@@ -41,9 +41,11 @@
 
 #include "gdal_alg.h"
 #include "cpl_minixml.h"
+#include "cpl_multiproc.h"
 
 CPL_C_START
 
+/* Note: values are selected to be consistant with GDALRIOResampleAlg of gcore/gdal.h */ 
 /*! Warp Resampling Algorithm */
 typedef enum {
   /*! Nearest neighbour (select on one input pixel) */ GRA_NearestNeighbour=0,
@@ -52,9 +54,25 @@ typedef enum {
   /*! Cubic B-Spline Approximation (4x4 kernel) */     GRA_CubicSpline=3,
   /*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRA_Lanczos=4,
   /*! Average (computes the average of all non-NODATA contributing pixels) */ GRA_Average=5, 
-  /*! Mode (selects the value which appears most often of all the sampled points) */ GRA_Mode=6
+  /*! Mode (selects the value which appears most often of all the sampled points) */ GRA_Mode=6,
+  // GRA_Gauss=7 reserved.
+  /*! Max (selects maximum of all non-NODATA contributing pixels) */ GRA_Max=8,
+  /*! Min (selects minimum of all non-NODATA contributing pixels) */ GRA_Min=9,
+  /*! Med (selects median of all non-NODATA contributing pixels) */ GRA_Med=10,
+  /*! Q1 (selects first quartile of all non-NODATA contributing pixels) */ GRA_Q1=11,
+  /*! Q3 (selects third quartile of all non-NODATA contributing pixels) */ GRA_Q3=12
 } GDALResampleAlg;
 
+/*! GWKAverageOrMode Algorithm */
+typedef enum {
+    /*! Average */ GWKAOM_Average=1,
+    /*! Mode */ GWKAOM_Fmode=2,
+    /*! Mode of GDT_Byte, GDT_UInt16, or GDT_Int16 */ GWKAOM_Imode=3,
+    /*! Maximum */ GWKAOM_Max=4,
+    /*! Minimum */ GWKAOM_Min=5,
+    /*! Quantile */ GWKAOM_Quant=6
+} GWKAverageOrModeAlg;
+
 typedef int 
 (*GDALMaskFunc)( void *pMaskFuncArg,
                  int nBandCount, GDALDataType eType, 
@@ -67,7 +85,7 @@ CPLErr CPL_DLL
 GDALWarpNoDataMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
                       int nXOff, int nYOff, int nXSize, int nYSize,
                       GByte **papabyImageData, int bMaskIsFloat,
-                      void *pValidityMask );
+                      void *pValidityMask, int* pbOutAllValid );
 
 CPLErr CPL_DLL 
 GDALWarpDstAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
@@ -78,7 +96,7 @@ CPLErr CPL_DLL
 GDALWarpSrcAlphaMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
                         int nXOff, int nYOff, int nXSize, int nYSize,
                         GByte ** /*ppImageData */,
-                        int bMaskIsFloat, void *pValidityMask );
+                        int bMaskIsFloat, void *pValidityMask, int* pbOutAllOpaque );
 
 CPLErr CPL_DLL 
 GDALWarpSrcMaskMasker( void *pMaskFuncArg, int nBandCount, GDALDataType eType,
@@ -268,6 +286,8 @@ public:
 
     int                 nSrcXSize;
     int                 nSrcYSize;
+    int                 nSrcXExtraSize; /* extra pixels (included in nSrcXSize) reserved for filter window. Should be ignored in scale computation */
+    int                 nSrcYExtraSize; /* extra pixels (included in nSrcYSize) reserved for filter window. Should be ignored in scale computation */
     GByte               **papabySrcImage; /* each subarray must have WARP_EXTRA_ELTS at the end */
 
     GUInt32           **papanBandSrcValid; /* each subarray must have WARP_EXTRA_ELTS at the end */
@@ -323,6 +343,8 @@ public:
 /*      masks.  Actual resampling is done by the GDALWarpKernel.        */
 /************************************************************************/
 
+typedef struct _GDALWarpChunk GDALWarpChunk;
+
 class CPL_DLL GDALWarpOperation {
 private:
     GDALWarpOptions *psOptions;
@@ -333,20 +355,19 @@ private:
     CPLErr          ComputeSourceWindow( int nDstXOff, int nDstYOff, 
                                          int nDstXSize, int nDstYSize,
                                          int *pnSrcXOff, int *pnSrcYOff, 
-                                         int *pnSrcXSize, int *pnSrcYSize );
+                                         int *pnSrcXSize, int *pnSrcYSize,
+                                         int *pnSrcXExtraSize, int *pnSrcYExtraSize,
+                                         double* pdfSrcFillRatio );
 
     CPLErr          CreateKernelMask( GDALWarpKernel *, int iBand, 
                                       const char *pszType );
 
-    /* Unused kept to preserve binary ABI */
-    /* CPL_UNUSED */ void            *unused1;
-    /* CPL_UNUSED */ void            *unused2;
-    void            *hIOMutex;
-    void            *hWarpMutex;
+    CPLMutex        *hIOMutex;
+    CPLMutex        *hWarpMutex;
 
     int             nChunkListCount;
     int             nChunkListMax;
-    int            *panChunkList;
+    GDALWarpChunk  *pasChunkList;
 
     int             bReportTimings;
     unsigned long   nLastTimeReported;
@@ -373,7 +394,12 @@ public:
                                 int nSrcXOff=0, int nSrcYOff=0,
                                 int nSrcXSize=0, int nSrcYSize=0,
                                 double dfProgressBase=0.0, double dfProgressScale=1.0);
-    
+    CPLErr          WarpRegion( int nDstXOff, int nDstYOff, 
+                                int nDstXSize, int nDstYSize,
+                                int nSrcXOff, int nSrcYOff,
+                                int nSrcXSize, int nSrcYSize,
+                                int nSrcXExtraSize, int nSrcYExtraSize,
+                                double dfProgressBase, double dfProgressScale);
     CPLErr          WarpRegionToBuffer( int nDstXOff, int nDstYOff, 
                                         int nDstXSize, int nDstYSize, 
                                         void *pDataBuf, 
@@ -381,6 +407,14 @@ public:
                                         int nSrcXOff=0, int nSrcYOff=0,
                                         int nSrcXSize=0, int nSrcYSize=0,
                                         double dfProgressBase=0.0, double dfProgressScale=1.0);
+    CPLErr          WarpRegionToBuffer( int nDstXOff, int nDstYOff, 
+                                        int nDstXSize, int nDstYSize, 
+                                        void *pDataBuf, 
+                                        GDALDataType eBufDataType,
+                                        int nSrcXOff, int nSrcYOff,
+                                        int nSrcXSize, int nSrcYSize,
+                                        int nSrcXExtraSize, int nSrcYExtraSize,
+                                        double dfProgressBase, double dfProgressScale);
 };
 
 #endif /* def __cplusplus */
@@ -399,6 +433,18 @@ CPLErr CPL_DLL GDALWarpRegionToBuffer( GDALWarpOperationH, int, int, int, int,
                                        void *, GDALDataType,
                                        int, int, int, int );
 
+/************************************************************************/
+/*      Warping kernel functions                                        */
+/************************************************************************/
+
+int GWKGetFilterRadius(GDALResampleAlg eResampleAlg);
+
+typedef double (*FilterFuncType)(double dfX);
+FilterFuncType GWKGetFilterFunc(GDALResampleAlg eResampleAlg);
+
+typedef double (*FilterFunc4ValuesType)(double* padfVals);
+FilterFunc4ValuesType GWKGetFilterFunc4Values(GDALResampleAlg eResampleAlg);
+
 CPL_C_END
 
 #endif /* ndef GDAL_ALG_H_INCLUDED */
diff --git a/alg/gdalwarpkernel.cpp b/alg/gdalwarpkernel.cpp
index 07bd038..27b7679 100644
--- a/alg/gdalwarpkernel.cpp
+++ b/alg/gdalwarpkernel.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarpkernel.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gdalwarpkernel.cpp 28946 2015-04-18 20:12:47Z rouault $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Implementation of the GDALWarpKernel class.  Implements the actual
@@ -30,50 +30,127 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
+#include <vector>
+#include <algorithm>
+#include <cmath>
+#include <cfloat>
 #include "gdalwarper.h"
 #include "gdal_alg_priv.h"
 #include "cpl_string.h"
 #include "gdalwarpkernel_opencl.h"
 #include "cpl_atomic_ops.h"
 #include "cpl_multiproc.h"
+#include <limits>
 
-CPL_CVSID("$Id: gdalwarpkernel.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gdalwarpkernel.cpp 28946 2015-04-18 20:12:47Z rouault $");
+
+//#define INSTANCIATE_FLOAT64_SSE2_IMPL
 
 static const int anGWKFilterRadius[] =
 {
     0,      // Nearest neighbour
     1,      // Bilinear
-    2,      // Cubic Convolution
+    2,      // Cubic Convolution (Catmull-Rom)
     2,      // Cubic B-Spline
     3,      // Lanczos windowed sinc
     0,      // Average
     0,      // Mode
+    0,      // Reserved GRA_Gauss=7
+    0,      // Max
+    0,      // Min
+    0,      // Med
+    0,      // Q1
+    0,      // Q3
+};
+
+static double GWKBilinear(double dfX);
+static double GWKCubic(double dfX);
+static double GWKBSpline(double dfX);
+static double GWKLanczosSinc(double dfX);
+
+static const FilterFuncType apfGWKFilter[] =
+{
+    NULL,            // Nearest neighbour
+    GWKBilinear,     // Bilinear
+    GWKCubic,        // Cubic Convolution (Catmull-Rom)
+    GWKBSpline,      // Cubic B-Spline
+    GWKLanczosSinc,  // Lanczos windowed sinc
+    NULL,            // Average
+    NULL,            // Mode
+    NULL,      // Reserved GRA_Gauss=7
+    NULL,      // Max
+    NULL,      // Min
+    NULL,      // Med
+    NULL,      // Q1
+    NULL,      // Q3
+};
+
+static double GWKBilinear4Values(double* padfVals);
+static double GWKCubic4Values(double* padfVals);
+static double GWKBSpline4Values(double* padfVals);
+static double GWKLanczosSinc4Values(double* padfVals);
+
+static const FilterFunc4ValuesType apfGWKFilter4Values[] =
+{
+    NULL,            // Nearest neighbour
+    GWKBilinear4Values,     // Bilinear
+    GWKCubic4Values,        // Cubic Convolution (Catmull-Rom)
+    GWKBSpline4Values,      // Cubic B-Spline
+    GWKLanczosSinc4Values,  // Lanczos windowed sinc
+    NULL,            // Average
+    NULL,            // Mode
+    NULL,      // Reserved GRA_Gauss=7
+    NULL,      // Max
+    NULL,      // Min
+    NULL,      // Med
+    NULL,      // Q1
+    NULL,      // Q3
 };
 
-/* Used in gdalwarpoperation.cpp */
 int GWKGetFilterRadius(GDALResampleAlg eResampleAlg)
 {
     return anGWKFilterRadius[eResampleAlg];
 }
 
+FilterFuncType GWKGetFilterFunc(GDALResampleAlg eResampleAlg)
+{
+    return apfGWKFilter[eResampleAlg];
+}
+
+FilterFunc4ValuesType GWKGetFilterFunc4Values(GDALResampleAlg eResampleAlg)
+{
+    return apfGWKFilter4Values[eResampleAlg];
+}
+
 #ifdef HAVE_OPENCL
 static CPLErr GWKOpenCLCase( GDALWarpKernel * );
 #endif
 
 static CPLErr GWKGeneralCase( GDALWarpKernel * );
-static CPLErr GWKNearestNoMasksByte( GDALWarpKernel *poWK );
-static CPLErr GWKBilinearNoMasksByte( GDALWarpKernel *poWK );
-static CPLErr GWKCubicNoMasksByte( GDALWarpKernel *poWK );
-static CPLErr GWKCubicSplineNoMasksByte( GDALWarpKernel *poWK );
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK );
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK );
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK );
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK );
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyDouble( GDALWarpKernel *poWK );
+#endif
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK );
 static CPLErr GWKNearestByte( GDALWarpKernel *poWK );
-static CPLErr GWKNearestNoMasksShort( GDALWarpKernel *poWK );
-static CPLErr GWKBilinearNoMasksShort( GDALWarpKernel *poWK );
-static CPLErr GWKCubicNoMasksShort( GDALWarpKernel *poWK );
-static CPLErr GWKCubicSplineNoMasksShort( GDALWarpKernel *poWK );
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK );
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK );
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK );
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyDouble( GDALWarpKernel *poWK );
+#endif
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK );
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK );
 static CPLErr GWKNearestShort( GDALWarpKernel *poWK );
-static CPLErr GWKNearestNoMasksFloat( GDALWarpKernel *poWK );
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK );
 static CPLErr GWKNearestFloat( GDALWarpKernel *poWK );
 static CPLErr GWKAverageOrMode( GDALWarpKernel * );
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyUShort( GDALWarpKernel * );
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyUShort( GDALWarpKernel * );
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyUShort( GDALWarpKernel * );
 
 /************************************************************************/
 /*                           GWKJobStruct                               */
@@ -83,14 +160,14 @@ typedef struct _GWKJobStruct GWKJobStruct;
 
 struct _GWKJobStruct
 {
-    void           *hThread;
+    CPLJoinableThread *hThread;
     GDALWarpKernel *poWK;
     int             iYMin;
     int             iYMax;
     volatile int   *pnCounter;
     volatile int   *pbStop;
-    void           *hCond;
-    void           *hCondMutex;
+    CPLCond        *hCond;
+    CPLMutex       *hCondMutex;
     int           (*pfnProgress)(GWKJobStruct* psJob);
     void           *pTransformerArg;
 } ;
@@ -236,7 +313,7 @@ static CPLErr GWKRun( GDALWarpKernel *poWK,
             return GWKGenericMonoThread(poWK, pfnFunc);
         }
 
-        void* hCond = CPLCreateCond();
+        CPLCond* hCond = CPLCreateCond();
         if (hCond == NULL)
         {
             for(i=0;i<nThreads;i++)
@@ -253,7 +330,7 @@ static CPLErr GWKRun( GDALWarpKernel *poWK,
 
         CPLDebug("WARP", "Using %d threads", nThreads);
 
-        void* hCondMutex = CPLCreateMutex(); /* and take implicitely the mutex */
+        CPLMutex* hCondMutex = CPLCreateMutex(); /* and take implicitely the mutex */
 
         volatile int bStop = FALSE;
         volatile int nCounter = 0;
@@ -270,7 +347,10 @@ static CPLErr GWKRun( GDALWarpKernel *poWK,
             pasThreadJob[i].pbStop = &bStop;
             pasThreadJob[i].hCond = hCond;
             pasThreadJob[i].hCondMutex = hCondMutex;
-            pasThreadJob[i].pfnProgress = GWKProgressThread;
+            if( poWK->pfnProgress != GDALDummyProgress )
+                pasThreadJob[i].pfnProgress = GWKProgressThread;
+            else
+                pasThreadJob[i].pfnProgress = NULL;
             pasThreadJob[i].hThread = CPLCreateJoinableThread( pfnFunc,
                                                   (void*) &pasThreadJob[i] );
         }
@@ -278,17 +358,20 @@ static CPLErr GWKRun( GDALWarpKernel *poWK,
 /* -------------------------------------------------------------------- */
 /*      Report progress.                                                */
 /* -------------------------------------------------------------------- */
-        while(nCounter < nDstYSize)
+        if( poWK->pfnProgress != GDALDummyProgress )
         {
-            CPLCondWait(hCond, hCondMutex);
-
-            if( !poWK->pfnProgress( poWK->dfProgressBase + poWK->dfProgressScale *
-                                    (nCounter / (double) nDstYSize),
-                                    "", poWK->pProgress ) )
+            while(nCounter < nDstYSize)
             {
-                CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
-                bStop = TRUE;
-                break;
+                CPLCondWait(hCond, hCondMutex);
+
+                if( !poWK->pfnProgress( poWK->dfProgressBase + poWK->dfProgressScale *
+                                        (nCounter / (double) nDstYSize),
+                                        "", poWK->pProgress ) )
+                {
+                    CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+                    bStop = TRUE;
+                    break;
+                }
             }
         }
 
@@ -427,6 +510,24 @@ static CPLErr GWKRun( GDALWarpKernel *poWK,
  */
 
 /**
+ * \var int GDALWarpKernel::nSrcXExtraSize;
+ * 
+ * Number of pixels included in nSrcXSize that are present on the edges of
+ * the area of interest to take into account the width of the kernel.
+ *
+ * This field is required.
+ */
+
+/**
+ * \var int GDALWarpKernel::nSrcYExtraSize;
+ * 
+ * Number of pixels included in nSrcYExtraSize that are present on the edges of
+ * the area of interest to take into account the height of the kernel.
+ *
+ * This field is required.
+ */
+
+/**
  * \var int GDALWarpKernel::papabySrcImage;
  * 
  * Array of source image band data.
@@ -731,6 +832,8 @@ GDALWarpKernel::GDALWarpKernel()
     nSrcYOff = 0;
     nSrcXSize = 0;
     nSrcYSize = 0;
+    nSrcXExtraSize = 0;
+    nSrcYExtraSize = 0;
     dfXScale = 1.0;
     dfYScale = 1.0;
     dfXFilter = 0.0;
@@ -800,12 +903,42 @@ CPLErr GDALWarpKernel::PerformWarp()
 /*      Pre-calculate resampling scales and window sizes for filtering. */
 /* -------------------------------------------------------------------- */
 
-    dfXScale = (double)nDstXSize / nSrcXSize;
-    dfYScale = (double)nDstYSize / nSrcYSize;
-    if( nSrcXSize >= nDstXSize && nSrcXSize <= nDstXSize + 1 + 2 * anGWKFilterRadius[eResample] )
+    dfXScale = (double)nDstXSize / (nSrcXSize - nSrcXExtraSize);
+    dfYScale = (double)nDstYSize / (nSrcYSize - nSrcYExtraSize);
+    if( nSrcXSize >= nDstXSize && nSrcXSize <= nDstXSize + nSrcXExtraSize )
         dfXScale = 1;
-    if( nSrcYSize >= nDstYSize && nSrcYSize <= nDstYSize + 1 + 2 * anGWKFilterRadius[eResample] )
+    if( nSrcYSize >= nDstYSize && nSrcYSize <= nDstYSize + nSrcYExtraSize )
         dfYScale = 1;
+    if( dfXScale < 1 )
+    {
+        double dfXReciprocalScale =  1. / dfXScale;
+        int nXReciprocalScale = (int)(dfXReciprocalScale + 0.5);
+        if( fabs(dfXReciprocalScale-nXReciprocalScale) < 0.05 )
+            dfXScale = 1.0 / nXReciprocalScale;
+    }
+    if( dfYScale < 1 )
+    {
+        double dfYReciprocalScale =  1. / dfYScale;
+        int nYReciprocalScale = (int)(dfYReciprocalScale + 0.5);
+        if( fabs(dfYReciprocalScale-nYReciprocalScale) < 0.05 )
+            dfYScale = 1.0 / nYReciprocalScale;
+    }
+    /*CPLDebug("WARP", "dfXScale = %f, dfYScale = %f", dfXScale, dfYScale);*/
+    
+    int bUse4SamplesFormula = (dfXScale >= 0.95 && dfYScale >= 0.95);
+    
+    // Safety check for callers that would use GDALWarpKernel without using
+    // GDALWarpOperation.
+    if( (eResample == GRA_CubicSpline || eResample == GRA_Lanczos ||
+         ((eResample == GRA_Cubic || eResample == GRA_Bilinear) && !bUse4SamplesFormula)) &&
+         atoi(CSLFetchNameValueDef(papszWarpOptions, "EXTRA_ELTS", "0") ) != WARP_EXTRA_ELTS )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Source arrays must have WARP_EXTRA_ELTS extra elements at their end. "
+                  "See GDALWarpKernel class definition. If this condition is fulfilled, "
+                  "define a EXTRA_ELTS=%d warp options", WARP_EXTRA_ELTS);
+        return CE_Failure;
+    }
 
     dfXFilter = anGWKFilterRadius[eResample];
     dfYFilter = anGWKFilterRadius[eResample];
@@ -847,41 +980,30 @@ CPLErr GDALWarpKernel::PerformWarp()
     }
 #endif /* defined HAVE_OPENCL */
 
-    if( eWorkingDataType == GDT_Byte
-        && eResample == GRA_NearestNeighbour
-        && papanBandSrcValid == NULL
+    int bNoMasksOrDstDensityOnly = (papanBandSrcValid == NULL
         && panUnifiedSrcValid == NULL
         && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKNearestNoMasksByte( this );
+        && panDstValid == NULL );
+
+    if( eWorkingDataType == GDT_Byte
+        && eResample == GRA_NearestNeighbour
+        && bNoMasksOrDstDensityOnly )
+        return GWKNearestNoMasksOrDstDensityOnlyByte( this );
 
     if( eWorkingDataType == GDT_Byte
         && eResample == GRA_Bilinear
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKBilinearNoMasksByte( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKBilinearNoMasksOrDstDensityOnlyByte( this );
 
     if( eWorkingDataType == GDT_Byte
         && eResample == GRA_Cubic
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKCubicNoMasksByte( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicNoMasksOrDstDensityOnlyByte( this );
 
     if( eWorkingDataType == GDT_Byte
         && eResample == GRA_CubicSpline
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKCubicSplineNoMasksByte( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicSplineNoMasksOrDstDensityOnlyByte( this );
 
     if( eWorkingDataType == GDT_Byte
         && eResample == GRA_NearestNeighbour )
@@ -889,39 +1011,38 @@ CPLErr GDALWarpKernel::PerformWarp()
 
     if( (eWorkingDataType == GDT_Int16 || eWorkingDataType == GDT_UInt16)
         && eResample == GRA_NearestNeighbour
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKNearestNoMasksShort( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKNearestNoMasksOrDstDensityOnlyShort( this );
 
     if( (eWorkingDataType == GDT_Int16 )
         && eResample == GRA_Cubic
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKCubicNoMasksShort( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicNoMasksOrDstDensityOnlyShort( this );
 
     if( (eWorkingDataType == GDT_Int16 )
         && eResample == GRA_CubicSpline
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKCubicSplineNoMasksShort( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicSplineNoMasksOrDstDensityOnlyShort( this );
 
     if( (eWorkingDataType == GDT_Int16 )
         && eResample == GRA_Bilinear
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKBilinearNoMasksShort( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKBilinearNoMasksOrDstDensityOnlyShort( this );
+
+    if( (eWorkingDataType == GDT_UInt16 )
+        && eResample == GRA_Cubic
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicNoMasksOrDstDensityOnlyUShort( this );
+
+    if( (eWorkingDataType == GDT_UInt16 )
+        && eResample == GRA_CubicSpline
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicSplineNoMasksOrDstDensityOnlyUShort( this );
+
+    if( (eWorkingDataType == GDT_UInt16 )
+        && eResample == GRA_Bilinear
+        && bNoMasksOrDstDensityOnly )
+        return GWKBilinearNoMasksOrDstDensityOnlyUShort( this );
 
     if( (eWorkingDataType == GDT_Int16 || eWorkingDataType == GDT_UInt16)
         && eResample == GRA_NearestNeighbour )
@@ -929,23 +1050,56 @@ CPLErr GDALWarpKernel::PerformWarp()
 
     if( eWorkingDataType == GDT_Float32
         && eResample == GRA_NearestNeighbour
-        && papanBandSrcValid == NULL
-        && panUnifiedSrcValid == NULL
-        && pafUnifiedSrcDensity == NULL
-        && panDstValid == NULL
-        && pafDstDensity == NULL )
-        return GWKNearestNoMasksFloat( this );
+        && bNoMasksOrDstDensityOnly )
+        return GWKNearestNoMasksOrDstDensityOnlyFloat( this );
 
     if( eWorkingDataType == GDT_Float32
         && eResample == GRA_NearestNeighbour )
         return GWKNearestFloat( this );
 
+    if( eWorkingDataType == GDT_Float32
+        && eResample == GRA_Bilinear
+        && bNoMasksOrDstDensityOnly )
+        return GWKBilinearNoMasksOrDstDensityOnlyFloat( this );
+
+    if( eWorkingDataType == GDT_Float32
+        && eResample == GRA_Cubic
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicNoMasksOrDstDensityOnlyFloat( this );
+
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
+    if( eWorkingDataType == GDT_Float64
+        && eResample == GRA_Bilinear
+        && bNoMasksOrDstDensityOnly )
+        return GWKBilinearNoMasksOrDstDensityOnlyDouble( this );
+
+    if( eWorkingDataType == GDT_Float64
+        && eResample == GRA_Cubic
+        && bNoMasksOrDstDensityOnly )
+        return GWKCubicNoMasksOrDstDensityOnlyDouble( this );
+#endif
+
     if( eResample == GRA_Average )
         return GWKAverageOrMode( this );
 
     if( eResample == GRA_Mode )
         return GWKAverageOrMode( this );
 
+    if( eResample == GRA_Max )
+        return GWKAverageOrMode( this );
+
+    if( eResample == GRA_Min )
+        return GWKAverageOrMode( this );
+
+    if( eResample == GRA_Med )
+        return GWKAverageOrMode( this );
+
+    if( eResample == GRA_Q1 )
+        return GWKAverageOrMode( this );
+
+    if( eResample == GRA_Q3 )
+        return GWKAverageOrMode( this );
+
     return GWKGeneralCase( this );
 }
                                   
@@ -976,18 +1130,6 @@ CPLErr GDALWarpKernel::Validate()
                   "Unsupported resampling method %d.", (int) eResample );
         return CE_Failure;
     }
-    
-    // Safety check for callers that would use GDALWarpKernel without using
-    // GDALWarpOperation.
-    if( (eResample == GRA_CubicSpline || eResample == GRA_Lanczos) &&
-         atoi(CSLFetchNameValueDef(papszWarpOptions, "EXTRA_ELTS", "0") ) != WARP_EXTRA_ELTS )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Source arrays must have WARP_EXTRA_ELTS extra elements at their end. "
-                  "See GDALWarpKernel class definition. If this condition is fulfilled, "
-                  "define a EXTRA_ELTS=%d warp options", WARP_EXTRA_ELTS);
-        return CE_Failure;
-    }
 
     return CE_None;
 }
@@ -1011,6 +1153,124 @@ static void GWKOverlayDensity( GDALWarpKernel *poWK, int iDstOffset,
 }
 
 /************************************************************************/
+/*                          GWKRoundValueT()                           */
+/************************************************************************/
+
+template<class T>
+static CPL_INLINE T GWKRoundValueT(double dfValue)
+{
+    return (std::numeric_limits<T>::min() < 0) ? (T)floor(dfValue + 0.5) :
+                                                 (T)(dfValue + 0.5);
+}
+
+template<> float GWKRoundValueT<float>(double dfValue)
+{
+    return (float)dfValue;
+}
+
+#ifdef notused
+template<> double GWKRoundValueT<double>(double dfValue)
+{
+    return dfValue;
+}
+#endif
+
+/************************************************************************/
+/*                            GWKClampValueT()                          */
+/************************************************************************/
+
+template<class T>
+static CPL_INLINE T GWKClampValueT(double dfValue)
+{
+    if (dfValue < std::numeric_limits<T>::min())
+        return std::numeric_limits<T>::min();
+    else if (dfValue > std::numeric_limits<T>::max())
+        return std::numeric_limits<T>::max();
+    else
+        return GWKRoundValueT<T>(dfValue);
+}
+
+template<> float GWKClampValueT<float>(double dfValue)
+{
+    return (float)dfValue;
+}
+
+#ifdef notused
+template<> double GWKClampValueT<double>(double dfValue)
+{
+    return dfValue;
+}
+#endif
+
+/************************************************************************/
+/*                         GWKSetPixelValueRealT()                      */
+/************************************************************************/
+
+template<class T>
+static int GWKSetPixelValueRealT( GDALWarpKernel *poWK, int iBand, 
+                         int iDstOffset, double dfDensity,
+                         T value)
+{
+    T *pDst = (T*)(poWK->papabyDstImage[iBand]);
+
+/* -------------------------------------------------------------------- */
+/*      If the source density is less than 100% we need to fetch the    */
+/*      existing destination value, and mix it with the source to       */
+/*      get the new "to apply" value.  Also compute composite           */
+/*      density.                                                        */
+/*                                                                      */
+/*      We avoid mixing if density is very near one or risk mixing      */
+/*      in very extreme nodata values and causing odd results (#1610)   */
+/* -------------------------------------------------------------------- */
+    if( dfDensity < 0.9999 )
+    {
+        double dfDstReal, dfDstDensity = 1.0;
+
+        if( dfDensity < 0.0001 )
+            return TRUE;
+
+        if( poWK->pafDstDensity != NULL )
+            dfDstDensity = poWK->pafDstDensity[iDstOffset];
+        else if( poWK->panDstValid != NULL 
+                 && !((poWK->panDstValid[iDstOffset>>5]
+                       & (0x01 << (iDstOffset & 0x1f))) ) )
+            dfDstDensity = 0.0;
+
+        // It seems like we also ought to be testing panDstValid[] here!
+
+        dfDstReal = pDst[iDstOffset];
+
+        // the destination density is really only relative to the portion
+        // not occluded by the overlay.
+        double dfDstInfluence = (1.0 - dfDensity) * dfDstDensity;
+
+        double dfReal = (value * dfDensity + dfDstReal * dfDstInfluence) 
+                            / (dfDensity + dfDstInfluence);
+
+/* -------------------------------------------------------------------- */
+/*      Actually apply the destination value.                           */
+/*                                                                      */
+/*      Avoid using the destination nodata value for integer datatypes  */
+/*      if by chance it is equal to the computed pixel value.           */
+/* -------------------------------------------------------------------- */
+        pDst[iDstOffset] = GWKClampValueT<T>(dfReal);
+    }
+    else
+        pDst[iDstOffset] = value;
+
+    if (poWK->padfDstNoDataReal != NULL &&
+        poWK->padfDstNoDataReal[iBand] == (double)pDst[iDstOffset])
+    {
+        if (pDst[iDstOffset] == std::numeric_limits<T>::min())
+            pDst[iDstOffset] = std::numeric_limits<T>::min() + 1;
+        else
+            pDst[iDstOffset] --;
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
 /*                          GWKSetPixelValue()                          */
 /************************************************************************/
 
@@ -1222,6 +1482,8 @@ static int GWKSetPixelValue( GDALWarpKernel *poWK, int iBand,
 /*                          GWKGetPixelValue()                          */
 /************************************************************************/
 
+/* It is assumed that panUnifiedSrcValid has been checked before */
+
 static int GWKGetPixelValue( GDALWarpKernel *poWK, int iBand, 
                              int iSrcOffset, double *pdfDensity, 
                              double *pdfReal, double *pdfImag )
@@ -1229,14 +1491,6 @@ static int GWKGetPixelValue( GDALWarpKernel *poWK, int iBand,
 {
     GByte *pabySrc = poWK->papabySrcImage[iBand];
 
-    if( poWK->panUnifiedSrcValid != NULL
-        && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
-              & (0x01 << (iSrcOffset & 0x1f))) ) )
-    {
-        *pdfDensity = 0.0;
-        return FALSE;
-    }
-
     if( poWK->papanBandSrcValid != NULL
         && poWK->papanBandSrcValid[iBand] != NULL
         && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
@@ -1589,81 +1843,16 @@ static int GWKGetPixelRow( GDALWarpKernel *poWK, int iBand,
 }
 
 /************************************************************************/
-/*                          GWKGetPixelByte()                           */
-/************************************************************************/
-
-static int GWKGetPixelByte( GDALWarpKernel *poWK, int iBand, 
-                            int iSrcOffset, double *pdfDensity, 
-                            GByte *pbValue )
-
-{
-    GByte *pabySrc = poWK->papabySrcImage[iBand];
-
-    if ( ( poWK->panUnifiedSrcValid != NULL
-           && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
-                 & (0x01 << (iSrcOffset & 0x1f))) ) )
-         || ( poWK->papanBandSrcValid != NULL
-              && poWK->papanBandSrcValid[iBand] != NULL
-              && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
-                    & (0x01 << (iSrcOffset & 0x1f)))) ) )
-    {
-        *pdfDensity = 0.0;
-        return FALSE;
-    }
-
-    *pbValue = pabySrc[iSrcOffset];
-
-    if ( poWK->pafUnifiedSrcDensity == NULL )
-        *pdfDensity = 1.0;
-    else
-        *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
-
-    return *pdfDensity != 0.0;
-}
-
-/************************************************************************/
-/*                          GWKGetPixelShort()                          */
-/************************************************************************/
-
-static int GWKGetPixelShort( GDALWarpKernel *poWK, int iBand, 
-                             int iSrcOffset, double *pdfDensity, 
-                             GInt16 *piValue )
-
-{
-    GInt16 *pabySrc = (GInt16 *)poWK->papabySrcImage[iBand];
-
-    if ( ( poWK->panUnifiedSrcValid != NULL
-           && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
-                 & (0x01 << (iSrcOffset & 0x1f))) ) )
-         || ( poWK->papanBandSrcValid != NULL
-              && poWK->papanBandSrcValid[iBand] != NULL
-              && !((poWK->papanBandSrcValid[iBand][iSrcOffset>>5]
-                    & (0x01 << (iSrcOffset & 0x1f)))) ) )
-    {
-        *pdfDensity = 0.0;
-        return FALSE;
-    }
-
-    *piValue = pabySrc[iSrcOffset];
-
-    if ( poWK->pafUnifiedSrcDensity == NULL )
-        *pdfDensity = 1.0;
-    else
-        *pdfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
-
-    return *pdfDensity != 0.0;
-}
-
-/************************************************************************/
-/*                          GWKGetPixelFloat()                          */
+/*                          GWKGetPixelT()                              */
 /************************************************************************/
 
-static int GWKGetPixelFloat( GDALWarpKernel *poWK, int iBand, 
-                             int iSrcOffset, double *pdfDensity, 
-                             float *pfValue )
+template<class T>
+static int GWKGetPixelT( GDALWarpKernel *poWK, int iBand, 
+                         int iSrcOffset, double *pdfDensity, 
+                         T *pValue )
 
 {
-    float *pabySrc = (float *)poWK->papabySrcImage[iBand];
+    T *pSrc = (T *)poWK->papabySrcImage[iBand];
 
     if ( ( poWK->panUnifiedSrcValid != NULL
            && !((poWK->panUnifiedSrcValid[iSrcOffset>>5]
@@ -1677,7 +1866,7 @@ static int GWKGetPixelFloat( GDALWarpKernel *poWK, int iBand,
         return FALSE;
     }
 
-    *pfValue = pabySrc[iSrcOffset];
+    *pValue = pSrc[iSrcOffset];
 
     if ( poWK->pafUnifiedSrcDensity == NULL )
         *pdfDensity = 1.0;
@@ -1692,7 +1881,7 @@ static int GWKGetPixelFloat( GDALWarpKernel *poWK, int iBand,
 /*     Set of bilinear interpolators                                    */
 /************************************************************************/
 
-static int GWKBilinearResample( GDALWarpKernel *poWK, int iBand, 
+static int GWKBilinearResample4Sample( GDALWarpKernel *poWK, int iBand, 
                                 double dfSrcX, double dfSrcY,
                                 double *pdfDensity, 
                                 double *pdfReal, double *pdfImag )
@@ -1840,11 +2029,13 @@ static int GWKBilinearResample( GDALWarpKernel *poWK, int iBand,
     }
 }
 
-static int GWKBilinearResampleNoMasksByte( GDALWarpKernel *poWK, int iBand, 
-                                           double dfSrcX, double dfSrcY,
-                                           GByte *pbValue )
+template<class T>
+static int GWKBilinearResampleNoMasks4SampleT( GDALWarpKernel *poWK, int iBand, 
+                                        double dfSrcX, double dfSrcY,
+                                        T *pValue )
 
 {
+    double dfMult;
     double  dfAccumulator = 0.0;
     double  dfAccumulatorDivisor = 0.0;
 
@@ -1853,55 +2044,64 @@ static int GWKBilinearResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
     int     iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
     double  dfRatioX = 1.5 - (dfSrcX - iSrcX);
     double  dfRatioY = 1.5 - (dfSrcY - iSrcY);
+    
+    T* pSrc = (T *)poWK->papabySrcImage[iBand];
+    
+    if( iSrcX >= 0 && iSrcX+1 < poWK->nSrcXSize
+        && iSrcY >= 0 && iSrcY+1 < poWK->nSrcYSize )
+    {
+        dfAccumulator = ((double)pSrc[iSrcOffset] * dfRatioX +
+                         (double)pSrc[iSrcOffset+1] * (1.0-dfRatioX)) * dfRatioY +
+                        ((double)pSrc[iSrcOffset+poWK->nSrcXSize] * dfRatioX +
+                         (double)pSrc[iSrcOffset+1+poWK->nSrcXSize] * (1.0-dfRatioX)) * (1.0-dfRatioY);
 
-    // Upper Left Pixel
+        *pValue = GWKRoundValueT<T>(dfAccumulator);
+
+        return TRUE;
+    }
+
+    // Upper Left Pixel
     if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
         && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
     {
-        double dfMult = dfRatioX * dfRatioY;
+        dfMult = dfRatioX * dfRatioY;
 
         dfAccumulatorDivisor += dfMult;
 
-        dfAccumulator +=
-            (double)poWK->papabySrcImage[iBand][iSrcOffset] * dfMult;
+        dfAccumulator += (double)pSrc[iSrcOffset] * dfMult;
     }
         
     // Upper Right Pixel
     if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
         && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
     {
-        double dfMult = (1.0-dfRatioX) * dfRatioY;
+        dfMult = (1.0-dfRatioX) * dfRatioY;
 
         dfAccumulatorDivisor += dfMult;
 
-        dfAccumulator +=
-            (double)poWK->papabySrcImage[iBand][iSrcOffset+1] * dfMult;
+        dfAccumulator += (double)pSrc[iSrcOffset+1] * dfMult;
     }
         
     // Lower Right Pixel
     if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
         && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
     {
-        double dfMult = (1.0-dfRatioX) * (1.0-dfRatioY);
+        dfMult = (1.0-dfRatioX) * (1.0-dfRatioY);
 
         dfAccumulatorDivisor += dfMult;
 
-        dfAccumulator +=
-            (double)poWK->papabySrcImage[iBand][iSrcOffset+1+poWK->nSrcXSize]
-            * dfMult;
+        dfAccumulator += (double)pSrc[iSrcOffset+1+poWK->nSrcXSize] * dfMult;
     }
         
     // Lower Left Pixel
     if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
         && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
     {
-        double dfMult = dfRatioX * (1.0-dfRatioY);
+        dfMult = dfRatioX * (1.0-dfRatioY);
 
         dfAccumulatorDivisor += dfMult;
 
-        dfAccumulator +=
-            (double)poWK->papabySrcImage[iBand][iSrcOffset+poWK->nSrcXSize]
-            * dfMult;
+        dfAccumulator += (double)pSrc[iSrcOffset+poWK->nSrcXSize] * dfMult;
     }
 
 /* -------------------------------------------------------------------- */
@@ -1911,7 +2111,7 @@ static int GWKBilinearResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
 
     if( dfAccumulatorDivisor < 0.00001 )
     {
-        *pbValue = 0;
+        *pValue = 0;
         return FALSE;
     }
     else if( dfAccumulatorDivisor == 1.0 )
@@ -1923,112 +2123,27 @@ static int GWKBilinearResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
         dfValue = dfAccumulator / dfAccumulatorDivisor;
     }
 
-    if ( dfValue < 0.0 )
-        *pbValue = 0;
-    else if ( dfValue > 255.0 )
-        *pbValue = 255;
-    else
-        *pbValue = (GByte)(0.5 + dfValue);
-    
-    return TRUE;
-}
-
-static int GWKBilinearResampleNoMasksShort( GDALWarpKernel *poWK, int iBand, 
-                                            double dfSrcX, double dfSrcY,
-                                            GInt16 *piValue )
-
-{
-    double  dfAccumulator = 0.0;
-    double  dfAccumulatorDivisor = 0.0;
-
-    int     iSrcX = (int) floor(dfSrcX - 0.5);
-    int     iSrcY = (int) floor(dfSrcY - 0.5);
-    int     iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
-    double  dfRatioX = 1.5 - (dfSrcX - iSrcX);
-    double  dfRatioY = 1.5 - (dfSrcY - iSrcY);
-
-    // Upper Left Pixel
-    if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
-        && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
-    {
-        double dfMult = dfRatioX * dfRatioY;
-
-        dfAccumulatorDivisor += dfMult;
-
-        dfAccumulator +=
-            (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset]
-            * dfMult;
-    }
-        
-    // Upper Right Pixel
-    if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
-        && iSrcY >= 0 && iSrcY < poWK->nSrcYSize )
-    {
-        double dfMult = (1.0-dfRatioX) * dfRatioY;
-
-        dfAccumulatorDivisor += dfMult;
-
-        dfAccumulator +=
-            (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+1] * dfMult;
-    }
-        
-    // Lower Right Pixel
-    if( iSrcX+1 >= 0 && iSrcX+1 < poWK->nSrcXSize
-        && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
-    {
-        double dfMult = (1.0-dfRatioX) * (1.0-dfRatioY);
-
-        dfAccumulatorDivisor += dfMult;
-
-        dfAccumulator +=
-            (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+1+poWK->nSrcXSize]
-            * dfMult;
-    }
-        
-    // Lower Left Pixel
-    if( iSrcX >= 0 && iSrcX < poWK->nSrcXSize
-        && iSrcY+1 >= 0 && iSrcY+1 < poWK->nSrcYSize )
-    {
-        double dfMult = dfRatioX * (1.0-dfRatioY);
-
-        dfAccumulatorDivisor += dfMult;
-
-        dfAccumulator +=
-            (double)((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset+poWK->nSrcXSize]
-            * dfMult;
-    }
+    *pValue = GWKRoundValueT<T>(dfValue);
 
-/* -------------------------------------------------------------------- */
-/*      Return result.                                                  */
-/* -------------------------------------------------------------------- */
-    if( dfAccumulatorDivisor == 1.0 )
-    {
-        *piValue = (GInt16)(0.5 + dfAccumulator);
-        return TRUE;
-    }
-    else if( dfAccumulatorDivisor < 0.00001 )
-    {
-        *piValue = 0;
-        return FALSE;
-    }
-    else
-    {
-        *piValue = (GInt16)(0.5 + dfAccumulator / dfAccumulatorDivisor);
-        return TRUE;
-    }
+    return TRUE;
 }
 
 /************************************************************************/
 /*                        GWKCubicResample()                            */
 /*     Set of bicubic interpolators using cubic convolution.            */
 /************************************************************************/
+
+/* http://verona.fi-p.unam.mx/boris/practicas/CubConvInterp.pdf Formula 18
+or http://en.wikipedia.org/wiki/Cubic_Hermite_spline : CINTx(p_1,p0,p1,p2)
+or http://en.wikipedia.org/wiki/Bicubic_interpolation: matrix notation */
+
 #define CubicConvolution(distance1,distance2,distance3,f0,f1,f2,f3) \
      (             f1                                               \
-      + distance1*0.5*(f2 - f0)                                     \
-      + distance2*0.5*(2.0*f0 - 5.0*f1 + 4.0*f2 - f3)               \
-      + distance3*0.5*(3.0*(f1 - f2) + f3 - f0))
+      + 0.5 * (distance1*(f2 - f0)                                  \
+             + distance2*(2.0*f0 - 5.0*f1 + 4.0*f2 - f3)            \
+             + distance3*(3.0*(f1 - f2) + f3 - f0)))
 
-static int GWKCubicResample( GDALWarpKernel *poWK, int iBand,
+static int GWKCubicResample4Sample( GDALWarpKernel *poWK, int iBand,
                              double dfSrcX, double dfSrcY,
                              double *pdfDensity,
                              double *pdfReal, double *pdfImag )
@@ -2050,7 +2165,7 @@ static int GWKCubicResample( GDALWarpKernel *poWK, int iBand,
     // Get the bilinear interpolation at the image borders
     if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
          || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
-        return GWKBilinearResample( poWK, iBand, dfSrcX, dfSrcY,
+        return GWKBilinearResample4Sample( poWK, iBand, dfSrcX, dfSrcY,
                                     pdfDensity, pdfReal, pdfImag );
 
     for ( i = -1; i < 3; i++ )
@@ -2062,7 +2177,7 @@ static int GWKCubicResample( GDALWarpKernel *poWK, int iBand,
              || adfDensity[2] < 0.000000001
              || adfDensity[3] < 0.000000001 )
         {
-            return GWKBilinearResample( poWK, iBand, dfSrcX, dfSrcY,
+            return GWKBilinearResample4Sample( poWK, iBand, dfSrcX, dfSrcY,
                                        pdfDensity, pdfReal, pdfImag );
         }
 
@@ -2094,56 +2209,10 @@ static int GWKCubicResample( GDALWarpKernel *poWK, int iBand,
     return TRUE;
 }
 
-static int GWKCubicResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
-                                        double dfSrcX, double dfSrcY,
-                                        GByte *pbValue )
-
-{
-    int     iSrcX = (int) (dfSrcX - 0.5);
-    int     iSrcY = (int) (dfSrcY - 0.5);
-    int     iSrcOffset = iSrcX + iSrcY * poWK->nSrcXSize;
-    double  dfDeltaX = dfSrcX - 0.5 - iSrcX;
-    double  dfDeltaY = dfSrcY - 0.5 - iSrcY;
-    double  dfDeltaX2 = dfDeltaX * dfDeltaX;
-    double  dfDeltaY2 = dfDeltaY * dfDeltaY;
-    double  dfDeltaX3 = dfDeltaX2 * dfDeltaX;
-    double  dfDeltaY3 = dfDeltaY2 * dfDeltaY;
-    double  adfValue[4];
-    int     i;
-
-    // Get the bilinear interpolation at the image borders
-    if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
-         || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
-        return GWKBilinearResampleNoMasksByte( poWK, iBand, dfSrcX, dfSrcY,
-                                               pbValue);
-
-    for ( i = -1; i < 3; i++ )
-    {
-        int     iOffset = iSrcOffset + i * poWK->nSrcXSize;
-
-        adfValue[i + 1] = CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
-                            (double)poWK->papabySrcImage[iBand][iOffset - 1],
-                            (double)poWK->papabySrcImage[iBand][iOffset],
-                            (double)poWK->papabySrcImage[iBand][iOffset + 1],
-                            (double)poWK->papabySrcImage[iBand][iOffset + 2]);
-    }
-
-    double dfValue = CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
-                        adfValue[0], adfValue[1], adfValue[2], adfValue[3]);
-
-    if ( dfValue < 0.0 )
-        *pbValue = 0;
-    else if ( dfValue > 255.0 )
-        *pbValue = 255;
-    else
-        *pbValue = (GByte)(0.5 + dfValue);
-    
-    return TRUE;
-}
-
-static int GWKCubicResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
-                                         double dfSrcX, double dfSrcY,
-                                         GInt16 *piValue )
+template<class T>
+static int GWKCubicResampleNoMasks4SampleT( GDALWarpKernel *poWK, int iBand,
+                                     double dfSrcX, double dfSrcY,
+                                     T *pValue )
 
 {
     int     iSrcX = (int) (dfSrcX - 0.5);
@@ -2161,31 +2230,26 @@ static int GWKCubicResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
     // Get the bilinear interpolation at the image borders
     if ( iSrcX - 1 < 0 || iSrcX + 2 >= poWK->nSrcXSize
          || iSrcY - 1 < 0 || iSrcY + 2 >= poWK->nSrcYSize )
-        return GWKBilinearResampleNoMasksShort( poWK, iBand, dfSrcX, dfSrcY,
-                                                piValue);
+        return GWKBilinearResampleNoMasks4SampleT ( poWK, iBand, dfSrcX, dfSrcY,
+                                             pValue );
 
     for ( i = -1; i < 3; i++ )
     {
         int     iOffset = iSrcOffset + i * poWK->nSrcXSize;
 
         adfValue[i + 1] =CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
-                (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset - 1],
-                (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset],
-                (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset + 1],
-                (double)((GInt16 *)poWK->papabySrcImage[iBand])[iOffset + 2]);
+                (double)((T *)poWK->papabySrcImage[iBand])[iOffset - 1],
+                (double)((T *)poWK->papabySrcImage[iBand])[iOffset],
+                (double)((T *)poWK->papabySrcImage[iBand])[iOffset + 1],
+                (double)((T *)poWK->papabySrcImage[iBand])[iOffset + 2]);
     }
 
     double dfValue = CubicConvolution(
         dfDeltaY, dfDeltaY2, dfDeltaY3,
         adfValue[0], adfValue[1], adfValue[2], adfValue[3]);
-    
-    if ( dfValue < -32768.0 )
-        *piValue = -32768;
-    else if ( dfValue > 32767.0 )
-        *piValue = 32767;
-    else
-        *piValue = (GInt16)floor(0.5 + dfValue);
-    
+
+    *pValue = GWKClampValueT<T>(dfValue);
+
     return TRUE;
 }
 
@@ -2207,23 +2271,155 @@ static int GWKCubicResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
 
 #define GWK_PI 3.14159265358979323846
 
-static double GWKLanczosSinc( double dfX, double dfR )
+static double GWKLanczosSinc( double dfX )
 {
+    /*if( fabs(dfX) > 3.0 )
+    {
+        printf("%f\n", dfX);
+        return 0;
+    }*/
     if ( dfX == 0.0 )
         return 1.0;
 
     const double dfPIX = GWK_PI * dfX;
-    const double dfPIXoverR = dfPIX / dfR;
+    const double dfPIXoverR = dfPIX / 3;
     const double dfPIX2overR = dfPIX * dfPIXoverR;
     return sin(dfPIX) * sin(dfPIXoverR) / dfPIX2overR;
 }
 
+static double GWKLanczosSinc4Values( double* padfValues )
+{
+    for(int i=0;i<4;i++)
+    {
+        if ( padfValues[i] == 0.0 )
+            padfValues[i] = 1.0;
+        else
+        {
+            const double dfPIX = GWK_PI * padfValues[i];
+            const double dfPIXoverR = dfPIX / 3;
+            const double dfPIX2overR = dfPIX * dfPIXoverR;
+            padfValues[i] = sin(dfPIX) * sin(dfPIXoverR) / dfPIX2overR;
+        }
+    }
+    return padfValues[0] + padfValues[1] + padfValues[2] + padfValues[3];
+}
+
 //#undef GWK_PI
 
 /************************************************************************/
+/*                           GWKBilinear()                              */
+/************************************************************************/
+
+static double GWKBilinear(double dfX)
+{
+    double dfAbsX = fabs(dfX);
+    if( dfAbsX <= 1.0 )
+        return 1 - dfAbsX;
+    else
+        return 0.0;
+}
+
+static double GWKBilinear4Values( double* padfValues )
+{
+    double dfAbsX0 = fabs(padfValues[0]);
+    double dfAbsX1 = fabs(padfValues[1]);
+    double dfAbsX2 = fabs(padfValues[2]);
+    double dfAbsX3 = fabs(padfValues[3]);
+    if( dfAbsX0 <= 1.0 )
+        padfValues[0] = 1 - dfAbsX0;
+    else
+        padfValues[0] = 0.0;
+    if( dfAbsX1 <= 1.0 )
+        padfValues[1] = 1 - dfAbsX1;
+    else
+        padfValues[1] = 0.0;
+    if( dfAbsX2 <= 1.0 )
+        padfValues[2] = 1 - dfAbsX2;
+    else
+        padfValues[2] = 0.0;
+    if( dfAbsX3 <= 1.0 )
+        padfValues[3] = 1 - dfAbsX3;
+    else
+        padfValues[3] = 0.0;
+    return  padfValues[0] +  padfValues[1] + padfValues[2] + padfValues[3];
+}
+
+/************************************************************************/
+/*                            GWKCubic()                                */
+/************************************************************************/
+
+static double GWKCubic(double dfX)
+{
+    /* http://en.wikipedia.org/wiki/Bicubic_interpolation#Bicubic_convolution_algorithm */
+    /* W(x) formula with a = -0.5 (cubic hermite spline ) */
+    /* or http://www.cs.utexas.edu/users/fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf */
+    /* k(x) (formula 8) with (B,C)=(0,0.5) the Catmull-Rom spline */
+    double dfAbsX = fabs(dfX);
+    if( dfAbsX <= 1.0 )
+    {
+        double dfX2 = dfX * dfX;
+        return dfX2 * (1.5 * dfAbsX - 2.5) + 1;
+    }
+    else if( dfAbsX <= 2.0 )
+    {
+        double dfX2 = dfX * dfX;
+        return dfX2 * (-0.5 * dfAbsX + 2.5) - 4 * dfAbsX + 2;
+    }
+    else
+        return 0.0;
+}
+
+static double GWKCubic4Values( double* padfValues )
+{
+    double dfAbsX_0 = fabs(padfValues[0]);
+    double dfX2_0 = padfValues[0] * padfValues[0];
+    double dfAbsX_1 = fabs(padfValues[1]);
+    double dfX2_1 = padfValues[1] * padfValues[1];
+    double dfAbsX_2 = fabs(padfValues[2]);
+    double dfX2_2 = padfValues[2] * padfValues[2];
+    double dfAbsX_3 = fabs(padfValues[3]);
+    double dfX2_3 = padfValues[3] * padfValues[3];
+    double dfVal0, dfVal1, dfVal2, dfVal3;
+    if( dfAbsX_0 <= 1.0 )
+        dfVal0 = dfX2_0 * (1.5 * dfAbsX_0 - 2.5) + 1;
+    else if( dfAbsX_0 <= 2.0 )
+        dfVal0 = dfX2_0 * (-0.5 * dfAbsX_0 + 2.5) - 4 * dfAbsX_0 + 2;
+    else
+        dfVal0 = 0.0;
+    if( dfAbsX_1 <= 1.0 )
+        dfVal1 = dfX2_1 * (1.5 * dfAbsX_1 - 2.5) + 1;
+    else if( dfAbsX_1 <= 2.0 )
+        dfVal1 = dfX2_1 * (-0.5 * dfAbsX_1 + 2.5) - 4 * dfAbsX_1 + 2;
+    else
+        dfVal1 = 0.0;
+    if( dfAbsX_2 <= 1.0 )
+        dfVal2 = dfX2_2 * (1.5 * dfAbsX_2 - 2.5) + 1;
+    else if( dfAbsX_2 <= 2.0 )
+        dfVal2 = dfX2_2 * (-0.5 * dfAbsX_2 + 2.5) - 4 * dfAbsX_2 + 2;
+    else
+        dfVal2 = 0.0;
+    if( dfAbsX_3 <= 1.0 )
+        dfVal3 = dfX2_3 * (1.5 * dfAbsX_3 - 2.5) + 1;
+    else if( dfAbsX_3 <= 2.0 )
+        dfVal3 = dfX2_3 * (-0.5 * dfAbsX_3 + 2.5) - 4 * dfAbsX_3 + 2;
+    else
+        dfVal3 = 0.0;
+
+    padfValues[0] = dfVal0;
+    padfValues[1] = dfVal1;
+    padfValues[2] = dfVal2;
+    padfValues[3] = dfVal3;
+    return dfVal0 + dfVal1 + dfVal2 + dfVal3;
+}
+
+/************************************************************************/
 /*                           GWKBSpline()                               */
 /************************************************************************/
 
+/* http://www.cs.utexas.edu/users/fussell/courses/cs384g/lectures/mitchell/Mitchell.pdf with (B,C)=(1,0) */
+/* 1/6 * ( 3 * |x|^3 -  6 * |x|^2 + 4) |x| < 1
+   1/6 * ( -|x|^3 + 6 |x|^2  - 12|x| + 8) |x| > 1
+*/
 static double GWKBSpline( double x )
 {
     double xp2 = x + 2.0;
@@ -2239,10 +2435,31 @@ static double GWKBSpline( double x )
                                                   -4.0 * xm1*xm1*xm1:0.0) +
                                        6.0 * x*x*x:0.0) +
                           -4.0 * xp1*xp1*xp1:0.0) +
-             xp2c:0.0) ) * 0.166666666666666666666;
+             xp2c:0.0) ) /* * 0.166666666666666666666 */;
 }
 
-
+static double GWKBSpline4Values( double* padfValues )
+{
+    for(int i=0;i<4;i++)
+    {
+        double x = padfValues[i];
+        double xp2 = x + 2.0;
+        double xp1 = x + 1.0;
+        double xm1 = x - 1.0;
+        
+        // This will most likely be used, so we'll compute it ahead of time to
+        // avoid stalling the processor
+        double xp2c = xp2 * xp2 * xp2;
+        
+        // Note that the test is computed only if it is needed
+        padfValues[i] = (((xp2 > 0.0)?((xp1 > 0.0)?((x > 0.0)?((xm1 > 0.0)?
+                                                    -4.0 * xm1*xm1*xm1:0.0) +
+                                        6.0 * x*x*x:0.0) +
+                            -4.0 * xp1*xp1*xp1:0.0) +
+                xp2c:0.0) ) /* * 0.166666666666666666666 */;
+    }
+    return padfValues[0] + padfValues[1] + padfValues[2] + padfValues[3];
+}
 /************************************************************************/
 /*                       GWKResampleWrkStruct                           */
 /************************************************************************/
@@ -2324,9 +2541,7 @@ static GWKResampleWrkStruct* GWKResampleCreateWrkStruct(GDALWarpKernel *poWK)
     psWrkStruct->padfRowReal = (double *)CPLCalloc( nXDist, sizeof(double) );
     psWrkStruct->padfRowImag = (double *)CPLCalloc( nXDist, sizeof(double) );
 
-    if( poWK->eResample == GRA_Lanczos &&
-        poWK->dfXFilter == 3.0 &&
-        poWK->dfYFilter == 3.0 )
+    if( poWK->eResample == GRA_Lanczos )
     {
         psWrkStruct->pfnGWKResample = GWKResampleOptimizedLanczos;
 
@@ -2342,7 +2557,7 @@ static GWKResampleWrkStruct* GWKResampleCreateWrkStruct(GDALWarpKernel *poWK)
             for(int i = iMin; i <= iMax; ++i)
             {
                 psWrkStruct->padfWeightsX[i-poWK->nFiltInitX] =
-                    GWKLanczosSinc(i * dfXScale, poWK->dfXFilter) * dfXScale;
+                    GWKLanczosSinc(i * dfXScale);
             }
         }
 
@@ -2358,7 +2573,7 @@ static GWKResampleWrkStruct* GWKResampleCreateWrkStruct(GDALWarpKernel *poWK)
             for(int j = jMin; j <= jMax; ++j)
             {
                 psWrkStruct->padfWeightsY[j-poWK->nFiltInitY] =
-                    GWKLanczosSinc(j * dfYScale, poWK->dfYFilter) * dfYScale;
+                    GWKLanczosSinc(j * dfYScale);
             }
         }
     }
@@ -2406,10 +2621,8 @@ static int GWKResample( GDALWarpKernel *poWK, int iBand,
     const int     iSrcOffset = iSrcX + iSrcY * nSrcXSize;
     const double  dfDeltaX = dfSrcX - 0.5 - iSrcX;
     const double  dfDeltaY = dfSrcY - 0.5 - iSrcY;
-    const int     eResample = poWK->eResample;
 
     const double  dfXScale = poWK->dfXScale, dfYScale = poWK->dfYScale;
-    const double  dfXFilter = poWK->dfXFilter, dfYFilter = poWK->dfYFilter;
 
     int     i, j;
     const int     nXDist = ( poWK->nXRadius + 1 ) * 2;
@@ -2427,7 +2640,8 @@ static int GWKResample( GDALWarpKernel *poWK, int iBand,
     // because a mask may render it unnecessary)
     memset( panCalcX, FALSE, nXDist * sizeof(char) );
     
-    CPLAssert( eResample == GRA_CubicSpline || eResample == GRA_Lanczos );
+    FilterFuncType pfnGetWeight = apfGWKFilter[poWK->eResample];
+    CPLAssert(pfnGetWeight);
 
     // Skip sampling over edge of image
     j = poWK->nFiltInitY;
@@ -2464,21 +2678,18 @@ static int GWKResample( GDALWarpKernel *poWK, int iBand,
                               padfRowDensity, padfRowReal, padfRowImag ) )
             continue;
 
-        // Select the resampling algorithm
-        if ( eResample == GRA_CubicSpline )
-            // Calculate the Y weight
-            dfWeight1 = ( bYScaleBelow1 ) ?
-                GWKBSpline(((double)j) * dfYScale) * dfYScale :
-                GWKBSpline(((double)j) - dfDeltaY);
-        else /*if ( eResample == GRA_Lanczos )*/
-        {
-            if( bYScaleBelow1 )
-                dfWeight1 = GWKLanczosSinc(j * dfYScale, dfYFilter) * dfYScale;
-            else
-                dfWeight1 = GWKLanczosSinc(j - dfDeltaY, dfYFilter);
-        }
+         // Calculate the Y weight
+        dfWeight1 = ( bYScaleBelow1 ) ?
+                pfnGetWeight((j - dfDeltaY) * dfYScale):
+                pfnGetWeight(j - dfDeltaY);
+
 
         // Iterate over pixels in row
+        double dfAccumulatorRealLocal = 0.0;
+        double dfAccumulatorImagLocal = 0.0;
+        double dfAccumulatorDensityLocal = 0.0;
+        double dfAccumulatorWeightLocal = 0.0;
+
         for (i = iMin; i <= iMax; ++i )
         {
             double dfWeight2;
@@ -2490,38 +2701,32 @@ static int GWKResample( GDALWarpKernel *poWK, int iBand,
 
             // Make or use a cached set of weights for this row
             if ( panCalcX[i-iMin] )
+            {
                 // Use saved weight value instead of recomputing it
-                dfWeight2 = dfWeight1 * padfWeightsX[i-iMin];
+                dfWeight2 = padfWeightsX[i-iMin];
+            }
             else
             {
-                // Choose among possible algorithms
-                if ( eResample == GRA_CubicSpline )
-                    // Calculate & save the X weight
-                    padfWeightsX[i-iMin] = dfWeight2 = ( bXScaleBelow1 ) ?
-                        GWKBSpline((double)i * dfXScale) * dfXScale :
-                        GWKBSpline(dfDeltaX - (double)i);
-                else /*if ( eResample == GRA_Lanczos )*/
-                {
-                    // Calculate & save the X weight
-                    if( bXScaleBelow1 )
-                        padfWeightsX[i-iMin] = dfWeight2 =
-                            GWKLanczosSinc(i * dfXScale, dfXFilter) * dfXScale;
-                    else
-                        padfWeightsX[i-iMin] = dfWeight2 = 
-                            GWKLanczosSinc(i - dfDeltaX, dfXFilter);
-                }
+                // Calculate & save the X weight
+                padfWeightsX[i-iMin] = dfWeight2 = ( bXScaleBelow1 ) ?
+                        pfnGetWeight((i - dfDeltaX) * dfXScale):
+                        pfnGetWeight(i - dfDeltaX);
 
-                dfWeight2 *= dfWeight1;
                 panCalcX[i-iMin] = TRUE;
             }
 
             // Accumulate!
-            dfAccumulatorReal += padfRowReal[i-iMin] * dfWeight2;
-            dfAccumulatorImag += padfRowImag[i-iMin] * dfWeight2;
+            dfAccumulatorRealLocal += padfRowReal[i-iMin] * dfWeight2;
+            dfAccumulatorImagLocal += padfRowImag[i-iMin] * dfWeight2;
             if( padfRowDensity != NULL )
-                dfAccumulatorDensity += padfRowDensity[i-iMin] * dfWeight2;
-            dfAccumulatorWeight += dfWeight2;
+                dfAccumulatorDensityLocal += padfRowDensity[i-iMin] * dfWeight2;
+            dfAccumulatorWeightLocal += dfWeight2;
         }
+        
+        dfAccumulatorReal += dfAccumulatorRealLocal * dfWeight1;
+        dfAccumulatorImag += dfAccumulatorImagLocal * dfWeight1;
+        dfAccumulatorDensity += dfAccumulatorDensityLocal * dfWeight1;
+        dfAccumulatorWeight += dfAccumulatorWeightLocal * dfWeight1;
     }
 
     if ( dfAccumulatorWeight < 0.000001 ||
@@ -2842,9 +3047,14 @@ static int GWKResampleOptimizedLanczos( GDALWarpKernel *poWK, int iBand,
     return TRUE;
 }
 
-static int GWKCubicSplineResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
-                                              double dfSrcX, double dfSrcY,
-                                              GByte *pbValue, double *padfBSpline )
+/************************************************************************/
+/*                        GWKResampleNoMasksT()                         */
+/************************************************************************/
+
+template <class T>
+static int GWKResampleNoMasksT( GDALWarpKernel *poWK, int iBand,
+                                double dfSrcX, double dfSrcY,
+                                T *pValue, double *padfWeight )
 
 {
     // Commonly used; save locally
@@ -2863,79 +3073,113 @@ static int GWKCubicSplineResampleNoMasksByte( GDALWarpKernel *poWK, int iBand,
     int     nXRadius = poWK->nXRadius;
     int     nYRadius = poWK->nYRadius;
 
-    GByte*  pabySrcBand = poWK->papabySrcImage[iBand];
+    T*  pSrcBand = (T*) poWK->papabySrcImage[iBand];
     
     // Politely refusing to process invalid coordinates or obscenely small image
     if ( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize
          || nXRadius > nSrcXSize || nYRadius > nSrcYSize )
-        return GWKBilinearResampleNoMasksByte( poWK, iBand, dfSrcX, dfSrcY, pbValue);
+        return GWKBilinearResampleNoMasks4SampleT( poWK, iBand, dfSrcX, dfSrcY, pValue);
+
+    FilterFuncType pfnGetWeight = apfGWKFilter[poWK->eResample];
+    CPLAssert(pfnGetWeight);
+    FilterFunc4ValuesType pfnGetWeight4Values = apfGWKFilter4Values[poWK->eResample];
+    CPLAssert(pfnGetWeight4Values);
+
+    if( dfXScale > 1.0 ) dfXScale = 1.0;
+    if( dfYScale > 1.0 ) dfYScale = 1.0;
 
     // Loop over all rows in the kernel
-    int     j, jC;
-    for ( jC = 0, j = 1 - nYRadius; j <= nYRadius; ++j, ++jC )
+    double dfAccumulatorWeightHorizontal = 0.0;
+    double dfAccumulatorWeightVertical = 0.0;
+    
+    int iMin = 1 - nXRadius;
+    if( iSrcX + iMin < 0 )
+        iMin = -iSrcX;
+    int iMax = nXRadius;
+    if( iSrcX + iMax >= nSrcXSize-1 )
+        iMax = nSrcXSize-1 - iSrcX;
+    int i, iC;
+    for(iC = 0, i = iMin; i+2 < iMax; i+=4, iC+=4 )
     {
-        int     iSampJ;
-        // Calculate the Y weight
-        double  dfWeight1 = ( dfYScale < 1.0 ) ?
-            GWKBSpline((double)j * dfYScale) * dfYScale :
-            GWKBSpline((double)j - dfDeltaY);
-
-        // Flip sampling over edge of image
-        if ( iSrcY + j < 0 )
-            iSampJ = iSrcOffset - (iSrcY + j) * nSrcXSize;
-        else if ( iSrcY + j >= nSrcYSize )
-            iSampJ = iSrcOffset + (2*nSrcYSize - 2*iSrcY - j - 1) * nSrcXSize;
-        else
-            iSampJ = iSrcOffset + j * nSrcXSize;
-        
+        padfWeight[iC] = (i - dfDeltaX) * dfXScale;
+        padfWeight[iC+1] = padfWeight[iC] + dfXScale;
+        padfWeight[iC+2] = padfWeight[iC+1] + dfXScale;
+        padfWeight[iC+3] = padfWeight[iC+2] + dfXScale;
+        dfAccumulatorWeightHorizontal += pfnGetWeight4Values(padfWeight+iC);
+    }
+    for(; i <= iMax; ++i, ++iC )
+    {
+        double dfWeight = pfnGetWeight((i - dfDeltaX) * dfXScale);
+        padfWeight[iC] = dfWeight;
+        dfAccumulatorWeightHorizontal += dfWeight;
+    }
+
+    int j = 1 - nYRadius;
+    if(  iSrcY + j < 0 )
+        j = -iSrcY;
+    int jMax = nYRadius;
+    if( iSrcY + jMax >= nSrcYSize-1 )
+        jMax = nSrcYSize-1 - iSrcY;
+
+    for ( ; j <= jMax; ++j )
+    {
+        int     iSampJ = iSrcOffset + j * nSrcXSize;
+
         // Loop over all pixels in the row
-        int     i, iC;
-        for ( iC = 0, i = 1 - nXRadius; i <= nXRadius; ++i, ++iC )
+        double dfAccumulatorLocal = 0.0, dfAccumulatorLocal2 = 0.0;
+        iC = 0;
+        i = iMin;
+        /* Process by chunk of 4 cols */
+        for(; i+2 < iMax; i+=4, iC+=4 )
         {
-            int     iSampI;
-            double  dfWeight2;
-            
-            // Flip sampling over edge of image
-            if ( iSrcX + i < 0 )
-                iSampI = -iSrcX - i;
-            else if ( iSrcX + i >= nSrcXSize )
-                iSampI = 2*nSrcXSize - 2*iSrcX - i - 1;
-            else
-                iSampI = i;
-            
-            // Make a cached set of GWKBSpline values
-            if( jC == 0 )
-            {
-                // Calculate & save the X weight
-                dfWeight2 = padfBSpline[iC] = ((dfXScale < 1.0 ) ?
-                    GWKBSpline((double)i * dfXScale) * dfXScale :
-                    GWKBSpline(dfDeltaX - (double)i));
-                dfWeight2 *= dfWeight1;
-            }
-            else
-                dfWeight2 = dfWeight1 * padfBSpline[iC];
-
             // Retrieve the pixel & accumulate
-            dfAccumulator += (double)pabySrcBand[iSampI+iSampJ] * dfWeight2;
+            dfAccumulatorLocal += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+            dfAccumulatorLocal += (double)pSrcBand[i+1+iSampJ] * padfWeight[iC+1];
+            dfAccumulatorLocal2 += (double)pSrcBand[i+2+iSampJ] * padfWeight[iC+2];
+            dfAccumulatorLocal2 += (double)pSrcBand[i+3+iSampJ] * padfWeight[iC+3];
+        }
+        dfAccumulatorLocal += dfAccumulatorLocal2;
+        if( i < iMax )
+        {
+            dfAccumulatorLocal += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+            dfAccumulatorLocal += (double)pSrcBand[i+1+iSampJ] * padfWeight[iC+1];
+            i+=2;
+            iC+=2;
         }
+        if( i == iMax )
+        {
+            dfAccumulatorLocal += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+        }
+
+        // Calculate the Y weight
+        double  dfWeight = pfnGetWeight((j - dfDeltaY) * dfYScale);
+        dfAccumulator += dfWeight * dfAccumulatorLocal;
+        dfAccumulatorWeightVertical += dfWeight;
     }
+    
+    double dfAccumulatorWeight = dfAccumulatorWeightHorizontal * dfAccumulatorWeightVertical;
+    
+    *pValue = GWKClampValueT<T>(dfAccumulator / dfAccumulatorWeight);
 
-    if ( dfAccumulator < 0.0 )
-        *pbValue = 0;
-    else if ( dfAccumulator > 255.0 )
-        *pbValue = 255;
-    else
-        *pbValue = (GByte)(0.5 + dfAccumulator);
-     
     return TRUE;
 }
 
-static int GWKCubicSplineResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
-                                               double dfSrcX, double dfSrcY,
-                                               GInt16 *piValue, double *padfBSpline )
+/* We restrict to 64bit processors because they are guaranteed to have SSE2 */
+/* Could possibly be used too on 32bit, but we would need to check at runtime */
+#if defined(__x86_64) || defined(_M_X64)
+
+#include <gdalsse_priv.h>
 
+/************************************************************************/
+/*                    GWKResampleNoMasks_SSE2_T()                       */
+/************************************************************************/
+
+template<class T>
+static int GWKResampleNoMasks_SSE2_T( GDALWarpKernel *poWK, int iBand,
+                                      double dfSrcX, double dfSrcY,
+                                      T *pValue, double *padfWeight )
 {
-    //Save src size to local var
+    // Commonly used; save locally
     int     nSrcXSize = poWK->nSrcXSize;
     int     nSrcYSize = poWK->nSrcYSize;
     
@@ -2951,79 +3195,302 @@ static int GWKCubicSplineResampleNoMasksShort( GDALWarpKernel *poWK, int iBand,
     int     nXRadius = poWK->nXRadius;
     int     nYRadius = poWK->nYRadius;
 
-    // Save band array pointer to local var; cast here instead of later
-    GInt16* pabySrcBand = ((GInt16 *)poWK->papabySrcImage[iBand]);
-
+    const T*  pSrcBand = (const T*) poWK->papabySrcImage[iBand];
+    
     // Politely refusing to process invalid coordinates or obscenely small image
     if ( iSrcX >= nSrcXSize || iSrcY >= nSrcYSize
          || nXRadius > nSrcXSize || nYRadius > nSrcYSize )
-        return GWKBilinearResampleNoMasksShort( poWK, iBand, dfSrcX, dfSrcY, piValue);
+        return GWKBilinearResampleNoMasks4SampleT( poWK, iBand, dfSrcX, dfSrcY, pValue);
+
+    FilterFuncType pfnGetWeight = apfGWKFilter[poWK->eResample];
+    CPLAssert(pfnGetWeight);
+    FilterFunc4ValuesType pfnGetWeight4Values = apfGWKFilter4Values[poWK->eResample];
+    CPLAssert(pfnGetWeight4Values);
+
+    if( dfXScale > 1.0 ) dfXScale = 1.0;
+    if( dfYScale > 1.0 ) dfYScale = 1.0;
 
-    // Loop over all pixels in the kernel
-    int     j, jC;
-    for ( jC = 0, j = 1 - nYRadius; j <= nYRadius; ++j, ++jC )
+    // Loop over all rows in the kernel
+    double dfAccumulatorWeightHorizontal = 0.0;
+    double dfAccumulatorWeightVertical = 0.0;
+    
+    int iMin = 1 - nXRadius;
+    if( iSrcX + iMin < 0 )
+        iMin = -iSrcX;
+    int iMax = nXRadius;
+    if( iSrcX + iMax >= nSrcXSize-1 )
+        iMax = nSrcXSize-1 - iSrcX;
+    int i, iC;
+    for(iC = 0, i = iMin; i+2 < iMax; i+=4, iC+=4 )
     {
-        int     iSampJ;
-        
-        // Calculate the Y weight
-        double  dfWeight1 = ( dfYScale < 1.0 ) ?
-            GWKBSpline((double)j * dfYScale) * dfYScale :
-            GWKBSpline((double)j - dfDeltaY);
-
-        // Flip sampling over edge of image
-        if ( iSrcY + j < 0 )
-            iSampJ = iSrcOffset - (iSrcY + j) * nSrcXSize;
-        else if ( iSrcY + j >= nSrcYSize )
-            iSampJ = iSrcOffset + (2*nSrcYSize - 2*iSrcY - j - 1) * nSrcXSize;
-        else
-            iSampJ = iSrcOffset + j * nSrcXSize;
-        
-        // Loop over all pixels in row
-        int     i, iC;
-        for ( iC = 0, i = 1 - nXRadius; i <= nXRadius; ++i, ++iC )
+        padfWeight[iC] = (i - dfDeltaX) * dfXScale;
+        padfWeight[iC+1] = padfWeight[iC] + dfXScale;
+        padfWeight[iC+2] = padfWeight[iC+1] + dfXScale;
+        padfWeight[iC+3] = padfWeight[iC+2] + dfXScale;
+        dfAccumulatorWeightHorizontal += pfnGetWeight4Values(padfWeight+iC);
+    }
+    for(; i <= iMax; ++i, ++iC )
+    {
+        double dfWeight = pfnGetWeight((i - dfDeltaX) * dfXScale);
+        padfWeight[iC] = dfWeight;
+        dfAccumulatorWeightHorizontal += dfWeight;
+    }
+
+    int j = 1 - nYRadius;
+    if(  iSrcY + j < 0 )
+        j = -iSrcY;
+    int jMax = nYRadius;
+    if( iSrcY + jMax >= nSrcYSize-1 )
+        jMax = nSrcYSize-1 - iSrcY;
+
+    /* Process by chunk of 4 rows */
+    for ( ; j+2 < jMax; j+=4 )
+    {
+        int     iSampJ = iSrcOffset + j * nSrcXSize;
+
+        // Loop over all pixels in the row
+        iC = 0;
+        i = iMin;
+        /* Process by chunk of 4 cols */
+        XMMReg4Double v_acc_1 = XMMReg4Double::Zero();
+        XMMReg4Double v_acc_2 = XMMReg4Double::Zero();
+        XMMReg4Double v_acc_3 = XMMReg4Double::Zero();
+        XMMReg4Double v_acc_4 = XMMReg4Double::Zero();
+        for(; i+2 < iMax; i+=4, iC+=4 )
         {
-        int     iSampI;
-            double  dfWeight2;
-            
-            // Flip sampling over edge of image
-            if ( iSrcX + i < 0 )
-                iSampI = -iSrcX - i;
-            else if(iSrcX + i >= nSrcXSize)
-                iSampI = 2*nSrcXSize - 2*iSrcX - i - 1;
-            else
-                iSampI = i;
-            
-            // Make a cached set of GWKBSpline values
-            if ( jC == 0 )
-            {
-                // Calculate & save the X weight
-                dfWeight2 = padfBSpline[iC] = ((dfXScale < 1.0 ) ?
-                    GWKBSpline((double)i * dfXScale) * dfXScale :
-                    GWKBSpline(dfDeltaX - (double)i));
-                dfWeight2 *= dfWeight1;
-            } else
-                dfWeight2 = dfWeight1 * padfBSpline[iC];
-
-            dfAccumulator += (double)pabySrcBand[iSampI + iSampJ] * dfWeight2;
+            // Retrieve the pixel & accumulate
+            XMMReg4Double v_pixels_1 = XMMReg4Double::Load4Val(pSrcBand+i+iSampJ);
+            XMMReg4Double v_pixels_2 = XMMReg4Double::Load4Val(pSrcBand+i+iSampJ+nSrcXSize);
+            XMMReg4Double v_pixels_3 = XMMReg4Double::Load4Val(pSrcBand+i+iSampJ+2*nSrcXSize);
+            XMMReg4Double v_pixels_4 = XMMReg4Double::Load4Val(pSrcBand+i+iSampJ+3*nSrcXSize);
+
+            XMMReg4Double v_padfWeight = XMMReg4Double::Load4Val(padfWeight + iC);
+
+            v_acc_1 += v_pixels_1 * v_padfWeight;
+            v_acc_2 += v_pixels_2 * v_padfWeight;
+            v_acc_3 += v_pixels_3 * v_padfWeight;
+            v_acc_4 += v_pixels_4 * v_padfWeight;
         }
-    }
 
-    *piValue = (GInt16)(0.5 + dfAccumulator);
-    
-    return TRUE;
-}
+        if( i < iMax )
+        {
+            XMMReg2Double v_pixels_1 = XMMReg2Double::Load2Val(pSrcBand+i+iSampJ);
+            XMMReg2Double v_pixels_2 = XMMReg2Double::Load2Val(pSrcBand+i+iSampJ+nSrcXSize);
+            XMMReg2Double v_pixels_3 = XMMReg2Double::Load2Val(pSrcBand+i+iSampJ+2*nSrcXSize);
+            XMMReg2Double v_pixels_4 = XMMReg2Double::Load2Val(pSrcBand+i+iSampJ+3*nSrcXSize);
 
-/************************************************************************/
-/*                           GWKOpenCLCase()                            */
-/*                                                                      */
-/*      This is identical to GWKGeneralCase(), but functions via        */
-/*      OpenCL. This means we have vector optimization (SSE) and/or     */
-/*      GPU optimization depending on our prefs. The code itsef is      */
-/*      general and not optimized, but by defining constants we can     */
-/*      make some pretty darn good code on the fly.                     */
-/************************************************************************/
+            XMMReg2Double v_padfWeight = XMMReg2Double::Load2Val(padfWeight + iC);
 
-#if defined(HAVE_OPENCL)
+            v_acc_1.GetLow() += v_pixels_1 * v_padfWeight;
+            v_acc_2.GetLow() += v_pixels_2 * v_padfWeight;
+            v_acc_3.GetLow() += v_pixels_3 * v_padfWeight;
+            v_acc_4.GetLow() += v_pixels_4 * v_padfWeight;
+
+            i+=2;
+            iC+=2;
+        }
+
+        v_acc_1.AddLowAndHigh();
+        v_acc_2.AddLowAndHigh();
+        v_acc_3.AddLowAndHigh();
+        v_acc_4.AddLowAndHigh();
+
+        double dfAccumulatorLocal_1 = (double)v_acc_1.GetLow(),
+               dfAccumulatorLocal_2 = (double)v_acc_2.GetLow(),
+               dfAccumulatorLocal_3 = (double)v_acc_3.GetLow(),
+               dfAccumulatorLocal_4 = (double)v_acc_4.GetLow();
+
+        if( i == iMax )
+        {
+            dfAccumulatorLocal_1 += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+            dfAccumulatorLocal_2 += (double)pSrcBand[i+iSampJ + nSrcXSize] * padfWeight[iC];
+            dfAccumulatorLocal_3 += (double)pSrcBand[i+iSampJ + 2 * nSrcXSize] * padfWeight[iC];
+            dfAccumulatorLocal_4 += (double)pSrcBand[i+iSampJ + 3 * nSrcXSize] * padfWeight[iC];
+        }
+
+        // Calculate the Y weight
+        double adfWeight[4];
+        adfWeight[0] = (j - dfDeltaY) * dfYScale;
+        adfWeight[1] = adfWeight[0] + dfYScale;
+        adfWeight[2] = adfWeight[1] + dfYScale;
+        adfWeight[3] = adfWeight[2] + dfYScale;
+        dfAccumulatorWeightVertical += pfnGetWeight4Values(adfWeight);
+        dfAccumulator += adfWeight[0] * dfAccumulatorLocal_1;
+        dfAccumulator += adfWeight[1] * dfAccumulatorLocal_2;
+        dfAccumulator += adfWeight[2] * dfAccumulatorLocal_3;
+        dfAccumulator += adfWeight[3] * dfAccumulatorLocal_4;
+    }
+    for ( ; j <= jMax; ++j )
+    {
+        int     iSampJ = iSrcOffset + j * nSrcXSize;
+
+        // Loop over all pixels in the row
+        iC = 0;
+        i = iMin;
+        /* Process by chunk of 4 cols */
+        XMMReg4Double v_acc = XMMReg4Double::Zero();
+        for(; i+2 < iMax; i+=4, iC+=4 )
+        {
+            // Retrieve the pixel & accumulate
+            XMMReg4Double v_pixels= XMMReg4Double::Load4Val(pSrcBand+i+iSampJ);
+            XMMReg4Double v_padfWeight = XMMReg4Double::Load4Val(padfWeight + iC);
+
+            v_acc += v_pixels * v_padfWeight;
+        }
+
+        v_acc.AddLowAndHigh();
+
+        double dfAccumulatorLocal = (double)v_acc.GetLow();
+
+        if( i < iMax )
+        {
+            dfAccumulatorLocal += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+            dfAccumulatorLocal += (double)pSrcBand[i+1+iSampJ] * padfWeight[iC+1];
+            i+=2;
+            iC+=2;
+        }
+        if( i == iMax )
+        {
+            dfAccumulatorLocal += (double)pSrcBand[i+iSampJ] * padfWeight[iC];
+        }
+
+        // Calculate the Y weight
+        double  dfWeight = pfnGetWeight((j - dfDeltaY) * dfYScale);
+        dfAccumulator += dfWeight * dfAccumulatorLocal;
+        dfAccumulatorWeightVertical += dfWeight;
+    }
+
+    double dfAccumulatorWeight = dfAccumulatorWeightHorizontal * dfAccumulatorWeightVertical;
+    
+    *pValue = GWKClampValueT<T>(dfAccumulator / dfAccumulatorWeight);
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                     GWKResampleNoMasksT<GByte>()                     */
+/************************************************************************/
+
+template<>
+int GWKResampleNoMasksT<GByte>( GDALWarpKernel *poWK, int iBand,
+                                double dfSrcX, double dfSrcY,
+                                GByte *pValue, double *padfWeight )
+{
+    return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, padfWeight);
+}
+
+/************************************************************************/
+/*                     GWKResampleNoMasksT<GInt16>()                    */
+/************************************************************************/
+
+template<>
+int GWKResampleNoMasksT<GInt16>( GDALWarpKernel *poWK, int iBand,
+                                 double dfSrcX, double dfSrcY,
+                                 GInt16 *pValue, double *padfWeight )
+{
+    return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, padfWeight);
+}
+
+/************************************************************************/
+/*                     GWKResampleNoMasksT<GUInt16>()                   */
+/************************************************************************/
+
+template<>
+int GWKResampleNoMasksT<GUInt16>( GDALWarpKernel *poWK, int iBand,
+                                  double dfSrcX, double dfSrcY,
+                                  GUInt16 *pValue, double *padfWeight )
+{
+    return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, padfWeight);
+}
+
+/************************************************************************/
+/*                     GWKResampleNoMasksT<float>()                     */
+/************************************************************************/
+
+template<>
+int GWKResampleNoMasksT<float>( GDALWarpKernel *poWK, int iBand,
+                                 double dfSrcX, double dfSrcY,
+                                 float *pValue, double *padfWeight )
+{
+    return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, padfWeight);
+}
+
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
+
+/************************************************************************/
+/*                     GWKResampleNoMasksT<double>()                    */
+/************************************************************************/
+
+template<>
+int GWKResampleNoMasksT<double>( GDALWarpKernel *poWK, int iBand,
+                                 double dfSrcX, double dfSrcY,
+                                 double *pValue, double *padfWeight )
+{
+    return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, padfWeight);
+}
+
+#endif /* INSTANCIATE_FLOAT64_SSE2_IMPL */
+
+#endif /* defined(__x86_64) || defined(_M_X64) */
+
+/************************************************************************/
+/*                     GWKRoundSourceCoordinates()                      */
+/************************************************************************/
+
+static void GWKRoundSourceCoordinates(int nDstXSize,
+                                      double* padfX,
+                                      double* padfY,
+                                      double* padfZ,
+                                      int* pabSuccess,
+                                      double dfSrcCoordPrecision,
+                                      double dfErrorThreshold,
+                                      GDALTransformerFunc pfnTransformer,
+                                      void* pTransformerArg,
+                                      double dfDstXOff,
+                                      double dfDstY)
+{
+    double dfPct = 0.8;
+    if( dfErrorThreshold > 0 && dfSrcCoordPrecision / dfErrorThreshold >= 10.0 )
+    {
+        dfPct = 1.0 - 2 * 1.0 / (dfSrcCoordPrecision / dfErrorThreshold);
+    }
+    double dfExactTransformThreshold = 0.5 * dfPct * dfSrcCoordPrecision;
+
+    for( int iDstX = 0; iDstX < nDstXSize; iDstX++ )
+    {
+        double dfXBefore = padfX[iDstX], dfYBefore = padfY[iDstX];
+        padfX[iDstX] = floor(padfX[iDstX] / dfSrcCoordPrecision + 0.5) * dfSrcCoordPrecision;
+        padfY[iDstX] = floor(padfY[iDstX] / dfSrcCoordPrecision + 0.5) * dfSrcCoordPrecision;
+
+        /* If we are in an uncertainty zone, go to non approximated transformation */
+        /* Due to the 80% of half-precision threshold, dfSrcCoordPrecision must */
+        /* be at least 10 times greater than the approximation error */
+        if( fabs(dfXBefore - padfX[iDstX]) > dfExactTransformThreshold ||
+            fabs(dfYBefore - padfY[iDstX]) > dfExactTransformThreshold )
+        {
+            padfX[iDstX] = iDstX + dfDstXOff;
+            padfY[iDstX] = dfDstY;
+            padfZ[iDstX] = 0.0;
+            pfnTransformer( pTransformerArg, TRUE, 1, 
+                            padfX + iDstX, padfY + iDstX,
+                            padfZ + iDstX, pabSuccess + iDstX );
+            padfX[iDstX] = floor(padfX[iDstX] / dfSrcCoordPrecision + 0.5) * dfSrcCoordPrecision;
+            padfY[iDstX] = floor(padfY[iDstX] / dfSrcCoordPrecision + 0.5) * dfSrcCoordPrecision;
+        }
+    }
+}
+
+/************************************************************************/
+/*                           GWKOpenCLCase()                            */
+/*                                                                      */
+/*      This is identical to GWKGeneralCase(), but functions via        */
+/*      OpenCL. This means we have vector optimization (SSE) and/or     */
+/*      GPU optimization depending on our prefs. The code itsef is      */
+/*      general and not optimized, but by defining constants we can     */
+/*      make some pretty darn good code on the fly.                     */
+/************************************************************************/
+
+#if defined(HAVE_OPENCL)
 static CPLErr GWKOpenCLCase( GDALWarpKernel *poWK )
 {
     int iDstY, iBand;
@@ -3156,12 +3623,18 @@ static CPLErr GWKOpenCLCase( GDALWarpKernel *poWK )
     /* -------------------------------------------------------------------- */
     double *padfX, *padfY, *padfZ;
     int    *pabSuccess;
+    double dfSrcCoordPrecision;
+    double dfErrorThreshold;
     
     padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-    
+    dfSrcCoordPrecision = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0"));
+    dfErrorThreshold = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "ERROR_THRESHOLD", "0"));
+
     /* ==================================================================== */
     /*      Loop over output lines.                                         */
     /* ==================================================================== */
@@ -3185,7 +3658,17 @@ static CPLErr GWKOpenCLCase( GDALWarpKernel *poWK )
         /* ---------------------------------------------------------------- */
         poWK->pfnTransformer( poWK->pTransformerArg, TRUE, nDstXSize, 
                               padfX, padfY, padfZ, pabSuccess );
-        
+        if( dfSrcCoordPrecision > 0.0 )
+        {
+            GWKRoundSourceCoordinates(nDstXSize, padfX, padfY, padfZ, pabSuccess,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      poWK->pTransformerArg,
+                                      0.5 + nDstXOff,
+                                      iDstY + 0.5 + nDstYOff);
+        }
+
         err = GDALWarpKernelOpenCL_setCoordRow(warper, padfX, padfY,
                                                nSrcXOff, nSrcYOff,
                                                pabSuccess, iDstY);
@@ -3330,34 +3813,47 @@ free_warper:
 }
 #endif /* defined(HAVE_OPENCL) */
 
+/************************************************************************/
+/*                     GWKCheckAndComputeSrcOffsets()                   */
+/************************************************************************/
+static CPL_INLINE int GWKCheckAndComputeSrcOffsets(const int* _pabSuccess,
+                                         int _iDstX,
+                                         const double* _padfX,
+                                         const double* _padfY,
+                                         const GDALWarpKernel* _poWK,
+                                         int _nSrcXSize,
+                                         int _nSrcYSize,
+                                         int& iSrcOffset)
+{
+    if( !_pabSuccess[_iDstX] )
+        return FALSE;
+
+/* -------------------------------------------------------------------- */
+/*      Figure out what pixel we want in our source raster, and skip    */
+/*      further processing if it is well off the source image.          */
+/* -------------------------------------------------------------------- */
+    /* We test against the value before casting to avoid the */
+    /* problem of asymmetric truncation effects around zero.  That is */
+    /* -0.5 will be 0 when cast to an int. */
+    if( _padfX[_iDstX] < _poWK->nSrcXOff
+        || _padfY[_iDstX] < _poWK->nSrcYOff )
+        return FALSE;
+
+    int iSrcX, iSrcY;
+
+    iSrcX = ((int) (_padfX[_iDstX] + 1e-10)) - _poWK->nSrcXOff;
+    iSrcY = ((int) (_padfY[_iDstX] + 1e-10)) - _poWK->nSrcYOff;
+
+    /* If operating outside natural projection area, padfX/Y can be */
+    /* a very huge positive number, that becomes -2147483648 in the */
+    /* int trucation. So it is necessary to test now for non negativeness. */
+    if( iSrcX < 0 || iSrcX >= _nSrcXSize || iSrcY < 0 || iSrcY >= _nSrcYSize )
+        return FALSE;
+
+    iSrcOffset = iSrcX + iSrcY * _nSrcXSize;
 
-#define COMPUTE_iSrcOffset(_pabSuccess, _iDstX, _padfX, _padfY, _poWK, _nSrcXSize, _nSrcYSize) \
-            if( !_pabSuccess[_iDstX] ) \
-                continue; \
-\
-/* -------------------------------------------------------------------- */ \
-/*      Figure out what pixel we want in our source raster, and skip    */ \
-/*      further processing if it is well off the source image.          */ \
-/* -------------------------------------------------------------------- */ \
-            /* We test against the value before casting to avoid the */ \
-            /* problem of asymmetric truncation effects around zero.  That is */ \
-            /* -0.5 will be 0 when cast to an int. */ \
-            if( _padfX[_iDstX] < _poWK->nSrcXOff \
-                || _padfY[_iDstX] < _poWK->nSrcYOff ) \
-                continue; \
-\
-            int iSrcX, iSrcY, CPL_UNUSED iSrcOffset;\
-\
-            iSrcX = ((int) (_padfX[_iDstX] + 1e-10)) - _poWK->nSrcXOff;\
-            iSrcY = ((int) (_padfY[_iDstX] + 1e-10)) - _poWK->nSrcYOff;\
-\
-            /* If operating outside natural projection area, padfX/Y can be */ \
-            /* a very huge positive number, that becomes -2147483648 in the */ \
-            /* int trucation. So it is necessary to test now for non negativeness. */ \
-            if( iSrcX < 0 || iSrcX >= _nSrcXSize || iSrcY < 0 || iSrcY >= _nSrcYSize )\
-                continue;\
-\
-            iSrcOffset = iSrcX + iSrcY * _nSrcXSize;
+    return TRUE;
+}
 
 /************************************************************************/
 /*                           GWKGeneralCase()                           */
@@ -3397,13 +3893,18 @@ static void GWKGeneralCaseThread( void* pData)
     padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
+    
+    int bUse4SamplesFormula = (poWK->dfXScale >= 0.95 && poWK->dfYScale >= 0.95);
 
     GWKResampleWrkStruct* psWrkStruct = NULL;
-    if (poWK->eResample == GRA_CubicSpline
-        || poWK->eResample == GRA_Lanczos )
+    if (poWK->eResample != GRA_NearestNeighbour)
     {
         psWrkStruct = GWKResampleCreateWrkStruct(poWK);
     }
+    double dfSrcCoordPrecision = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0"));
+    double dfErrorThreshold = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "ERROR_THRESHOLD", "0"));
 
 /* ==================================================================== */
 /*      Loop over output lines.                                         */
@@ -3428,6 +3929,16 @@ static void GWKGeneralCaseThread( void* pData)
 /* -------------------------------------------------------------------- */
         poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
                               padfX, padfY, padfZ, pabSuccess );
+        if( dfSrcCoordPrecision > 0.0 )
+        {
+            GWKRoundSourceCoordinates(nDstXSize, padfX, padfY, padfZ, pabSuccess,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      psJob->pTransformerArg,
+                                      0.5 + poWK->nDstXOff,
+                                      iDstY + 0.5 + poWK->nDstYOff);
+        }
 
 /* ==================================================================== */
 /*      Loop over pixels in output scanline.                            */
@@ -3436,7 +3947,10 @@ static void GWKGeneralCaseThread( void* pData)
         {
             int iDstOffset;
 
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
+            int iSrcOffset;
+            if( !GWKCheckAndComputeSrcOffsets(pabSuccess, iDstX, padfX, padfY,
+                                    poWK, nSrcXSize, nSrcYSize, iSrcOffset) )
+                continue;
 
 /* -------------------------------------------------------------------- */
 /*      Do not try to apply transparent/invalid source pixels to the    */
@@ -3479,24 +3993,25 @@ static void GWKGeneralCaseThread( void* pData)
                     GWKGetPixelValue( poWK, iBand, iSrcOffset,
                                       &dfBandDensity, &dfValueReal, &dfValueImag );
                 }
-                else if ( poWK->eResample == GRA_Bilinear )
+                else if ( poWK->eResample == GRA_Bilinear &&
+                          bUse4SamplesFormula )
                 {
-                    GWKBilinearResample( poWK, iBand, 
+                    GWKBilinearResample4Sample( poWK, iBand, 
                                          padfX[iDstX]-poWK->nSrcXOff,
                                          padfY[iDstX]-poWK->nSrcYOff,
                                          &dfBandDensity, 
                                          &dfValueReal, &dfValueImag );
                 }
-                else if ( poWK->eResample == GRA_Cubic )
+                else if ( poWK->eResample == GRA_Cubic &&
+                          bUse4SamplesFormula )
                 {
-                    GWKCubicResample( poWK, iBand, 
-                                      padfX[iDstX]-poWK->nSrcXOff,
-                                      padfY[iDstX]-poWK->nSrcYOff,
-                                      &dfBandDensity, 
-                                      &dfValueReal, &dfValueImag );
+                    GWKCubicResample4Sample( poWK, iBand, 
+                                        padfX[iDstX]-poWK->nSrcXOff,
+                                        padfY[iDstX]-poWK->nSrcYOff,
+                                        &dfBandDensity, 
+                                        &dfValueReal, &dfValueImag );
                 }
-                else if ( poWK->eResample == GRA_CubicSpline
-                          || poWK->eResample == GRA_Lanczos )
+                else
                 {
                     psWrkStruct->pfnGWKResample( poWK, iBand, 
                                  padfX[iDstX]-poWK->nSrcXOff,
@@ -3541,7 +4056,7 @@ static void GWKGeneralCaseThread( void* pData)
 /* -------------------------------------------------------------------- */
 /*      Report progress to the user, and optionally cancel out.         */
 /* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
+        if (psJob->pfnProgress && psJob->pfnProgress(psJob))
             break;
     }
 
@@ -3557,21 +4072,12 @@ static void GWKGeneralCaseThread( void* pData)
 }
 
 /************************************************************************/
-/*                       GWKNearestNoMasksByte()                        */
-/*                                                                      */
-/*      Case for 8bit input data with nearest neighbour resampling      */
-/*      without concerning about masking. Should be as fast as          */
-/*      possible for this particular transformation type.               */
+/*                GWKResampleNoMasksOrDstDensityOnlyThreadInternal()           */
 /************************************************************************/
 
-static void GWKNearestNoMasksByteThread(void* pData);
-
-static CPLErr GWKNearestNoMasksByte( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKNearestNoMasksByte", GWKNearestNoMasksByteThread );
-}
+template<class T,GDALResampleAlg eResample, int bUse4SamplesFormula>
+static void GWKResampleNoMasksOrDstDensityOnlyThreadInternal( void* pData )
 
-static void GWKNearestNoMasksByteThread(void* pData)
 {
     GWKJobStruct* psJob = (GWKJobStruct*) pData;
     GDALWarpKernel *poWK = psJob->poWK;
@@ -3594,6 +4100,13 @@ static void GWKNearestNoMasksByteThread(void* pData)
     padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
 
+    int     nXRadius = poWK->nXRadius;
+    double  *padfWeight = (double *)CPLCalloc( 1 + nXRadius * 2, sizeof(double) );
+    double dfSrcCoordPrecision = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0"));
+    double dfErrorThreshold = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "ERROR_THRESHOLD", "0"));
+
 /* ==================================================================== */
 /*      Loop over output lines.                                         */
 /* ==================================================================== */
@@ -3617,13 +4130,26 @@ static void GWKNearestNoMasksByteThread(void* pData)
 /* -------------------------------------------------------------------- */
         poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
                               padfX, padfY, padfZ, pabSuccess );
+        if( dfSrcCoordPrecision > 0.0 )
+        {
+            GWKRoundSourceCoordinates(nDstXSize, padfX, padfY, padfZ, pabSuccess,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      psJob->pTransformerArg,
+                                      0.5 + poWK->nDstXOff,
+                                      iDstY + 0.5 + poWK->nDstYOff);
+        }
 
 /* ==================================================================== */
 /*      Loop over pixels in output scanline.                            */
 /* ==================================================================== */
         for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
         {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
+            int iSrcOffset;
+            if( !GWKCheckAndComputeSrcOffsets(pabSuccess, iDstX, padfX, padfY,
+                                        poWK, nSrcXSize, nSrcYSize, iSrcOffset) )
+                continue;
 
 /* ==================================================================== */
 /*      Loop processing each band.                                      */
@@ -3635,15 +4161,41 @@ static void GWKNearestNoMasksByteThread(void* pData)
 
             for( iBand = 0; iBand < poWK->nBands; iBand++ )
             {
-                poWK->papabyDstImage[iBand][iDstOffset] = 
-                    poWK->papabySrcImage[iBand][iSrcOffset];
+                T value = 0;
+                if( eResample == GRA_NearestNeighbour )
+                {
+                    value = ((T *)poWK->papabySrcImage[iBand])[iSrcOffset];
+                }
+                else if( bUse4SamplesFormula )
+                {
+                    if( eResample == GRA_Bilinear )
+                        GWKBilinearResampleNoMasks4SampleT( poWK, iBand,
+                                                padfX[iDstX]-poWK->nSrcXOff,
+                                                padfY[iDstX]-poWK->nSrcYOff,
+                                                &value );
+                    else
+                        GWKCubicResampleNoMasks4SampleT( poWK, iBand,
+                                              padfX[iDstX]-poWK->nSrcXOff,
+                                              padfY[iDstX]-poWK->nSrcYOff,
+                                              &value );
+                }
+                else
+                    GWKResampleNoMasksT( poWK, iBand,
+                                    padfX[iDstX]-poWK->nSrcXOff,
+                                    padfY[iDstX]-poWK->nSrcYOff,
+                                    &value,
+                                    padfWeight);
+                ((T *)poWK->papabyDstImage[iBand])[iDstOffset] = value;
             }
+
+            if( poWK->pafDstDensity )
+                poWK->pafDstDensity[iDstOffset] = 1.0f;
         }
 
 /* -------------------------------------------------------------------- */
 /*      Report progress to the user, and optionally cancel out.         */
 /* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
+        if (psJob->pfnProgress && psJob->pfnProgress(psJob))
             break;
     }
 
@@ -3654,24 +4206,78 @@ static void GWKNearestNoMasksByteThread(void* pData)
     CPLFree( padfY );
     CPLFree( padfZ );
     CPLFree( pabSuccess );
+    CPLFree( padfWeight );
 }
 
-/************************************************************************/
-/*                       GWKBilinearNoMasksByte()                       */
-/*                                                                      */
-/*      Case for 8bit input data with bilinear resampling without       */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
+template<class T,GDALResampleAlg eResample>
+static void GWKResampleNoMasksOrDstDensityOnlyThread( void* pData )
+{
+    GWKResampleNoMasksOrDstDensityOnlyThreadInternal<T,eResample,FALSE>(pData);
+}
+
+template<class T,GDALResampleAlg eResample> void GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread( void* pData )
+
+{
+    GWKJobStruct* psJob = (GWKJobStruct*) pData;
+    GDALWarpKernel *poWK = psJob->poWK;
+    CPLAssert(eResample == GRA_Bilinear || eResample == GRA_Cubic);
+    int bUse4SamplesFormula = (poWK->dfXScale >= 0.95 && poWK->dfYScale >= 0.95);
+    if( bUse4SamplesFormula )
+        GWKResampleNoMasksOrDstDensityOnlyThreadInternal<T,eResample,TRUE>(pData);
+    else
+        GWKResampleNoMasksOrDstDensityOnlyThreadInternal<T,eResample,FALSE>(pData);
+}
+
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestNoMasksOrDstDensityOnlyByte",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<GByte,GRA_NearestNeighbour> );
+}
+
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKBilinearNoMasksOrDstDensityOnlyByte",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GByte,GRA_Bilinear> );
+}
+
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKCubicNoMasksOrDstDensityOnlyByte",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GByte,GRA_Cubic> );
+}
+
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKCubicNoMasksOrDstDensityOnlyFloat",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<float,GRA_Cubic> );
+}
 
-static void GWKBilinearNoMasksByteThread(void* pData);
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
+
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyDouble( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKCubicNoMasksOrDstDensityOnlyDouble",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<double,GRA_Cubic> );
+}
+#endif
 
-static CPLErr GWKBilinearNoMasksByte( GDALWarpKernel *poWK )
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyByte( GDALWarpKernel *poWK )
 {
-    return GWKRun( poWK, "GWKBilinearNoMasksByte", GWKBilinearNoMasksByteThread );
+    return GWKRun( poWK, "GWKCubicSplineNoMasksOrDstDensityOnlyByte",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<GByte,GRA_CubicSpline> );
 }
 
-static void GWKBilinearNoMasksByteThread(void* pData)
+/************************************************************************/
+/*                          GWKNearestByte()                            */
+/*                                                                      */
+/*      Case for 8bit input data with nearest neighbour resampling      */
+/*      using valid flags. Should be as fast as possible for this       */
+/*      particular transformation type.                                 */
+/************************************************************************/
+
+template<class T>
+static void GWKNearestThread( void* pData )
+
 {
     GWKJobStruct* psJob = (GWKJobStruct*) pData;
     GDALWarpKernel *poWK = psJob->poWK;
@@ -3694,6 +4300,11 @@ static void GWKBilinearNoMasksByteThread(void* pData)
     padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
     pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
 
+    double dfSrcCoordPrecision = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0"));
+    double dfErrorThreshold = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "ERROR_THRESHOLD", "0"));
+
 /* ==================================================================== */
 /*      Loop over output lines.                                         */
 /* ==================================================================== */
@@ -3717,35 +4328,99 @@ static void GWKBilinearNoMasksByteThread(void* pData)
 /* -------------------------------------------------------------------- */
         poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
                               padfX, padfY, padfZ, pabSuccess );
-
+        if( dfSrcCoordPrecision > 0.0 )
+        {
+            GWKRoundSourceCoordinates(nDstXSize, padfX, padfY, padfZ, pabSuccess,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      psJob->pTransformerArg,
+                                      0.5 + poWK->nDstXOff,
+                                      iDstY + 0.5 + poWK->nDstYOff);
+        }
 /* ==================================================================== */
 /*      Loop over pixels in output scanline.                            */
 /* ==================================================================== */
         for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
         {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
+            int iDstOffset;
+
+            int iSrcOffset;
+            if( !GWKCheckAndComputeSrcOffsets(pabSuccess, iDstX, padfX, padfY,
+                                    poWK, nSrcXSize, nSrcYSize, iSrcOffset) )
+                continue;
+ 
+/* -------------------------------------------------------------------- */
+/*      Do not try to apply invalid source pixels to the dest.          */
+/* -------------------------------------------------------------------- */
+            if( poWK->panUnifiedSrcValid != NULL
+                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
+                     & (0x01 << (iSrcOffset & 0x1f))) )
+                continue;
+
+/* -------------------------------------------------------------------- */
+/*      Do not try to apply transparent source pixels to the destination.*/
+/* -------------------------------------------------------------------- */
+            double  dfDensity = 1.0;
+
+            if( poWK->pafUnifiedSrcDensity != NULL )
+            {
+                dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
+                if( dfDensity < 0.00001 )
+                    continue;
+            }
 
 /* ==================================================================== */
 /*      Loop processing each band.                                      */
 /* ==================================================================== */
             int iBand;
-            int iDstOffset;
-
+            
             iDstOffset = iDstX + iDstY * nDstXSize;
 
             for( iBand = 0; iBand < poWK->nBands; iBand++ )
             {
-                GWKBilinearResampleNoMasksByte( poWK, iBand,
-                                                padfX[iDstX]-poWK->nSrcXOff,
-                                                padfY[iDstX]-poWK->nSrcYOff,
-                                                &poWK->papabyDstImage[iBand][iDstOffset] );
+                T   value = 0;
+                double dfBandDensity = 0.0;
+
+/* -------------------------------------------------------------------- */
+/*      Collect the source value.                                       */
+/* -------------------------------------------------------------------- */
+                if ( GWKGetPixelT(poWK, iBand, iSrcOffset, &dfBandDensity, &value) )
+                {
+                    if( dfBandDensity < 1.0 )
+                    {
+                        if( dfBandDensity == 0.0 )
+                            /* do nothing */;
+                        else
+                        {
+                            /* let the general code take care of mixing */
+                            GWKSetPixelValueRealT( poWK, iBand, iDstOffset, 
+                                          dfBandDensity, value );
+                        }
+                    }
+                    else
+                    {
+                        ((T *)poWK->papabyDstImage[iBand])[iDstOffset] = value;
+                    }
+                }
             }
-        }
+ 
+/* -------------------------------------------------------------------- */
+/*      Mark this pixel valid/opaque in the output.                     */
+/* -------------------------------------------------------------------- */
+            GWKOverlayDensity( poWK, iDstOffset, dfDensity );
+
+            if( poWK->panDstValid != NULL )
+            {
+                poWK->panDstValid[iDstOffset>>5] |= 
+                    0x01 << (iDstOffset & 0x1f);
+            }
+        } /* Next iDstX */
 
 /* -------------------------------------------------------------------- */
 /*      Report progress to the user, and optionally cancel out.         */
 /* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
+        if (psJob->pfnProgress && psJob->pfnProgress(psJob))
             break;
     }
 
@@ -3758,1214 +4433,85 @@ static void GWKBilinearNoMasksByteThread(void* pData)
     CPLFree( pabSuccess );
 }
 
-/************************************************************************/
-/*                       GWKCubicNoMasksByte()                          */
-/*                                                                      */
-/*      Case for 8bit input data with cubic resampling without          */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
+static CPLErr GWKNearestByte( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestByte", GWKNearestThread<GByte> );
+}
 
-static void GWKCubicNoMasksByteThread(void* pData);
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestNoMasksOrDstDensityOnlyShort",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<GInt16,GRA_NearestNeighbour> );
+}
 
-static CPLErr GWKCubicNoMasksByte( GDALWarpKernel *poWK )
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK )
 {
-    return GWKRun( poWK, "GWKCubicNoMasksByte", GWKCubicNoMasksByteThread );
+    return GWKRun( poWK, "GWKBilinearNoMasksOrDstDensityOnlyShort",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GInt16,GRA_Bilinear> );
 }
 
-static void GWKCubicNoMasksByteThread( void* pData )
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyUShort( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKBilinearNoMasksOrDstDensityOnlyUShort",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GUInt16,GRA_Bilinear> );
+}
 
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK )
 {
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
+    return GWKRun( poWK, "GWKBilinearNoMasksOrDstDensityOnlyFloat",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<float,GRA_Bilinear> );
+}
 
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            int iDstOffset;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GWKCubicResampleNoMasksByte( poWK, iBand,
-                                             padfX[iDstX]-poWK->nSrcXOff,
-                                             padfY[iDstX]-poWK->nSrcYOff,
-                                             &poWK->papabyDstImage[iBand][iDstOffset] );
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                   GWKCubicSplineNoMasksByte()                        */
-/*                                                                      */
-/*      Case for 8bit input data with cubic spline resampling without   */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKCubicSplineNoMasksByteThread(void* pData);
-
-static CPLErr GWKCubicSplineNoMasksByte( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKCubicSplineNoMasksByte", GWKCubicSplineNoMasksByteThread );
-}
-
-static void GWKCubicSplineNoMasksByteThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-    int     nXRadius = poWK->nXRadius;
-    double  *padfBSpline = (double *)CPLCalloc( nXRadius * 2, sizeof(double) );
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            int iDstOffset;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GWKCubicSplineResampleNoMasksByte( poWK, iBand,
-                                                   padfX[iDstX]-poWK->nSrcXOff,
-                                                   padfY[iDstX]-poWK->nSrcYOff,
-                                                   &poWK->papabyDstImage[iBand][iDstOffset],
-                                                   padfBSpline);
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-    CPLFree( padfBSpline );
-}
-
-/************************************************************************/
-/*                          GWKNearestByte()                            */
-/*                                                                      */
-/*      Case for 8bit input data with nearest neighbour resampling      */
-/*      using valid flags. Should be as fast as possible for this       */
-/*      particular transformation type.                                 */
-/************************************************************************/
-
-static void GWKNearestByteThread(void* pData);
-
-static CPLErr GWKNearestByte( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKNearestByte", GWKNearestByteThread );
-}
-
-static void GWKNearestByteThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            int iDstOffset;
-
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* -------------------------------------------------------------------- */
-/*      Do not try to apply invalid source pixels to the dest.          */
-/* -------------------------------------------------------------------- */
-            if( poWK->panUnifiedSrcValid != NULL
-                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
-                     & (0x01 << (iSrcOffset & 0x1f))) )
-                continue;
-
-/* -------------------------------------------------------------------- */
-/*      Do not try to apply transparent source pixels to the destination.*/
-/* -------------------------------------------------------------------- */
-            double  dfDensity = 1.0;
-
-            if( poWK->pafUnifiedSrcDensity != NULL )
-            {
-                dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
-                if( dfDensity < 0.00001 )
-                    continue;
-            }
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GByte   bValue = 0;
-                double dfBandDensity = 0.0;
-
-/* -------------------------------------------------------------------- */
-/*      Collect the source value.                                       */
-/* -------------------------------------------------------------------- */
-                if ( GWKGetPixelByte( poWK, iBand, iSrcOffset, &dfBandDensity,
-                                      &bValue ) )
-                {
-                    if( dfBandDensity < 1.0 )
-                    {
-                        if( dfBandDensity == 0.0 )
-                            /* do nothing */;
-                        else
-                        {
-                            /* let the general code take care of mixing */
-                            GWKSetPixelValue( poWK, iBand, iDstOffset, 
-                                              dfBandDensity, (double) bValue, 
-                                              0.0 );
-                        }
-                    }
-                    else
-                    {
-                        poWK->papabyDstImage[iBand][iDstOffset] = bValue;
-                    }
-                }
-            }
-
-/* -------------------------------------------------------------------- */
-/*      Mark this pixel valid/opaque in the output.                     */
-/* -------------------------------------------------------------------- */
-            GWKOverlayDensity( poWK, iDstOffset, dfDensity );
-
-            if( poWK->panDstValid != NULL )
-            {
-                poWK->panDstValid[iDstOffset>>5] |= 
-                    0x01 << (iDstOffset & 0x1f);
-            }
-        } /* Next iDstX */
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    } /* Next iDstY */
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                    GWKNearestNoMasksShort()                          */
-/*                                                                      */
-/*      Case for 16bit signed and unsigned integer input data with      */
-/*      nearest neighbour resampling without concerning about masking.  */
-/*      Should be as fast as possible for this particular               */
-/*      transformation type.                                            */
-/************************************************************************/
-
-static void GWKNearestNoMasksShortThread(void* pData);
-
-static CPLErr GWKNearestNoMasksShort( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKNearestNoMasksShort", GWKNearestNoMasksShortThread );
-}
-
-static void GWKNearestNoMasksShortThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            int iDstOffset;
-
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = 
-                    ((GInt16 *)poWK->papabySrcImage[iBand])[iSrcOffset];
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                       GWKBilinearNoMasksShort()                      */
-/*                                                                      */
-/*      Case for 16bit input data with cubic resampling without         */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKBilinearNoMasksShortThread(void* pData);
-
-static CPLErr GWKBilinearNoMasksShort( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKBilinearNoMasksShort", GWKBilinearNoMasksShortThread );
-}
-
-static void GWKBilinearNoMasksShortThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            int iDstOffset;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GInt16  iValue = 0;
-                GWKBilinearResampleNoMasksShort( poWK, iBand,
-                                                 padfX[iDstX]-poWK->nSrcXOff,
-                                                 padfY[iDstX]-poWK->nSrcYOff,
-                                                 &iValue );
-                ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                       GWKCubicNoMasksShort()                         */
-/*                                                                      */
-/*      Case for 16bit input data with cubic resampling without         */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKCubicNoMasksShortThread(void* pData);
-
-static CPLErr GWKCubicNoMasksShort( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKCubicNoMasksShort", GWKCubicNoMasksShortThread );
-}
-
-static void GWKCubicNoMasksShortThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            int iDstOffset;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GInt16  iValue = 0;
-                GWKCubicResampleNoMasksShort( poWK, iBand,
-                                              padfX[iDstX]-poWK->nSrcXOff,
-                                              padfY[iDstX]-poWK->nSrcYOff,
-                                              &iValue );
-                ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                    GWKCubicSplineNoMasksShort()                      */
-/*                                                                      */
-/*      Case for 16bit input data with cubic resampling without         */
-/*      concerning about masking. Should be as fast as possible         */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKCubicSplineNoMasksShortThread(void* pData);
-
-static CPLErr GWKCubicSplineNoMasksShort( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKCubicSplineNoMasksShort", GWKCubicSplineNoMasksShortThread );
-}
-
-static void GWKCubicSplineNoMasksShortThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-    int     nXRadius = poWK->nXRadius;
-    // Make space to save weights
-    double  *padfBSpline = (double *)CPLCalloc( nXRadius * 2, sizeof(double) );
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            int iDstOffset;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GInt16  iValue = 0;
-                GWKCubicSplineResampleNoMasksShort( poWK, iBand,
-                                                    padfX[iDstX]-poWK->nSrcXOff,
-                                                    padfY[iDstX]-poWK->nSrcYOff,
-                                                    &iValue,
-                                                    padfBSpline);
-                ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-    CPLFree( padfBSpline );
-}
-
-/************************************************************************/
-/*                          GWKNearestShort()                           */
-/*                                                                      */
-/*      Case for 32bit float input data with nearest neighbour          */
-/*      resampling using valid flags. Should be as fast as possible     */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKNearestShortThread(void* pData);
-
-static CPLErr GWKNearestShort( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKNearestShort", GWKNearestShortThread );
-}
-
-static void GWKNearestShortThread(void* pData)
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            int iDstOffset;
-
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* -------------------------------------------------------------------- */
-/*      Don't generate output pixels for which the source valid         */
-/*      mask exists and is invalid.                                     */
-/* -------------------------------------------------------------------- */
-            if( poWK->panUnifiedSrcValid != NULL
-                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
-                     & (0x01 << (iSrcOffset & 0x1f))) )
-                continue;
-
-/* -------------------------------------------------------------------- */
-/*      Do not try to apply transparent source pixels to the destination.*/
-/* -------------------------------------------------------------------- */
-            double  dfDensity = 1.0;
-
-            if( poWK->pafUnifiedSrcDensity != NULL )
-            {
-                dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
-                if( dfDensity < 0.00001 )
-                    continue;
-            }
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                GInt16  iValue = 0;
-                double dfBandDensity = 0.0;
-
-/* -------------------------------------------------------------------- */
-/*      Collect the source value.                                       */
-/* -------------------------------------------------------------------- */
-                if ( GWKGetPixelShort( poWK, iBand, iSrcOffset, &dfBandDensity,
-                                       &iValue ) )
-                {
-                    if( dfBandDensity < 1.0 )
-                    {
-                        if( dfBandDensity == 0.0 )
-                            /* do nothing */;
-                        else
-                        {
-                            /* let the general code take care of mixing */
-                            GWKSetPixelValue( poWK, iBand, iDstOffset, 
-                                              dfBandDensity, (double) iValue, 
-                                              0.0 );
-                        }
-                    }
-                    else
-                    {
-                        ((GInt16 *)poWK->papabyDstImage[iBand])[iDstOffset] = iValue;
-                    }
-                }
-            }
-
-/* -------------------------------------------------------------------- */
-/*      Mark this pixel valid/opaque in the output.                     */
-/* -------------------------------------------------------------------- */
-            GWKOverlayDensity( poWK, iDstOffset, dfDensity );
-
-            if( poWK->panDstValid != NULL )
-            {
-                poWK->panDstValid[iDstOffset>>5] |= 
-                    0x01 << (iDstOffset & 0x1f);
-            }
-        } /* Next iDstX */
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    } /* Next iDstY */
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
-}
-
-/************************************************************************/
-/*                    GWKNearestNoMasksFloat()                          */
-/*                                                                      */
-/*      Case for 32bit float input data with nearest neighbour          */
-/*      resampling without concerning about masking. Should be as fast  */
-/*      as possible for this particular transformation type.            */
-/************************************************************************/
-
-static void GWKNearestNoMasksFloatThread(void* pData);
-
-static CPLErr GWKNearestNoMasksFloat( GDALWarpKernel *poWK )
-{
-    return GWKRun( poWK, "GWKNearestNoMasksFloat", GWKNearestNoMasksFloatThread );
-}
-
-static void GWKNearestNoMasksFloatThread( void* pData )
-
-{
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            int iDstOffset;
-
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-            
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                ((float *)poWK->papabyDstImage[iBand])[iDstOffset] = 
-                    ((float *)poWK->papabySrcImage[iBand])[iSrcOffset];
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
+#ifdef INSTANCIATE_FLOAT64_SSE2_IMPL
 
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
+static CPLErr GWKBilinearNoMasksOrDstDensityOnlyDouble( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKBilinearNoMasksOrDstDensityOnlyDouble",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<double,GRA_Bilinear> );
 }
+#endif
 
-/************************************************************************/
-/*                          GWKNearestFloat()                           */
-/*                                                                      */
-/*      Case for 32bit float input data with nearest neighbour          */
-/*      resampling using valid flags. Should be as fast as possible     */
-/*      for this particular transformation type.                        */
-/************************************************************************/
-
-static void GWKNearestFloatThread(void* pData);
-
-static CPLErr GWKNearestFloat( GDALWarpKernel *poWK )
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK )
 {
-    return GWKRun( poWK, "GWKNearestFloat", GWKNearestFloatThread );
+    return GWKRun( poWK, "GWKCubicNoMasksOrDstDensityOnlyShort",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GInt16,GRA_Cubic> );
 }
 
-static void GWKNearestFloatThread( void* pData )
-
+static CPLErr GWKCubicNoMasksOrDstDensityOnlyUShort( GDALWarpKernel *poWK )
 {
-    GWKJobStruct* psJob = (GWKJobStruct*) pData;
-    GDALWarpKernel *poWK = psJob->poWK;
-    int iYMin = psJob->iYMin;
-    int iYMax = psJob->iYMax;
-
-    int iDstY;
-    int nDstXSize = poWK->nDstXSize;
-    int nSrcXSize = poWK->nSrcXSize, nSrcYSize = poWK->nSrcYSize;
-
-/* -------------------------------------------------------------------- */
-/*      Allocate x,y,z coordinate arrays for transformation ... one     */
-/*      scanlines worth of positions.                                   */
-/* -------------------------------------------------------------------- */
-    double *padfX, *padfY, *padfZ;
-    int    *pabSuccess;
-
-    padfX = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfY = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    padfZ = (double *) CPLMalloc(sizeof(double) * nDstXSize);
-    pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
-
-/* ==================================================================== */
-/*      Loop over output lines.                                         */
-/* ==================================================================== */
-    for( iDstY = iYMin; iDstY < iYMax; iDstY++ )
-    {
-        int iDstX;
-
-/* -------------------------------------------------------------------- */
-/*      Setup points to transform to source image space.                */
-/* -------------------------------------------------------------------- */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            padfX[iDstX] = iDstX + 0.5 + poWK->nDstXOff;
-            padfY[iDstX] = iDstY + 0.5 + poWK->nDstYOff;
-            padfZ[iDstX] = 0.0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Transform the points from destination pixel/line coordinates    */
-/*      to source pixel/line coordinates.                               */
-/* -------------------------------------------------------------------- */
-        poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
-                              padfX, padfY, padfZ, pabSuccess );
-
-/* ==================================================================== */
-/*      Loop over pixels in output scanline.                            */
-/* ==================================================================== */
-        for( iDstX = 0; iDstX < nDstXSize; iDstX++ )
-        {
-            int iDstOffset;
-
-            COMPUTE_iSrcOffset(pabSuccess, iDstX, padfX, padfY, poWK, nSrcXSize, nSrcYSize);
-
-/* -------------------------------------------------------------------- */
-/*      Do not try to apply invalid source pixels to the dest.          */
-/* -------------------------------------------------------------------- */
-            if( poWK->panUnifiedSrcValid != NULL
-                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
-                     & (0x01 << (iSrcOffset & 0x1f))) )
-                continue;
-
-/* -------------------------------------------------------------------- */
-/*      Do not try to apply transparent source pixels to the destination.*/
-/* -------------------------------------------------------------------- */
-            double  dfDensity = 1.0;
-
-            if( poWK->pafUnifiedSrcDensity != NULL )
-            {
-                dfDensity = poWK->pafUnifiedSrcDensity[iSrcOffset];
-                if( dfDensity < 0.00001 )
-                    continue;
-            }
-
-/* ==================================================================== */
-/*      Loop processing each band.                                      */
-/* ==================================================================== */
-            int iBand;
-
-            iDstOffset = iDstX + iDstY * nDstXSize;
-
-            for( iBand = 0; iBand < poWK->nBands; iBand++ )
-            {
-                float   fValue = 0;
-                double dfBandDensity = 0.0;
+    return GWKRun( poWK, "GWKCubicNoMasksOrDstDensityOnlyUShort",
+                   GWKResampleNoMasksOrDstDensityOnlyHas4SampleThread<GUInt16,GRA_Cubic> );
+}
 
-/* -------------------------------------------------------------------- */
-/*      Collect the source value.                                       */
-/* -------------------------------------------------------------------- */
-                if ( GWKGetPixelFloat( poWK, iBand, iSrcOffset, &dfBandDensity,
-                                       &fValue ) )
-                {
-                    if( dfBandDensity < 1.0 )
-                    {
-                        if( dfBandDensity == 0.0 )
-                            /* do nothing */;
-                        else
-                        {
-                            /* let the general code take care of mixing */
-                            GWKSetPixelValue( poWK, iBand, iDstOffset, 
-                                              dfBandDensity, (double) fValue, 
-                                              0.0 );
-                        }
-                    }
-                    else
-                    {
-                        ((float *)poWK->papabyDstImage[iBand])[iDstOffset] 
-                            = fValue;
-                    }
-                }
-            }
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyShort( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKCubicSplineNoMasksOrDstDensityOnlyShort",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<GInt16,GRA_CubicSpline> );
+}
 
-/* -------------------------------------------------------------------- */
-/*      Mark this pixel valid/opaque in the output.                     */
-/* -------------------------------------------------------------------- */
-            GWKOverlayDensity( poWK, iDstOffset, dfDensity );
+static CPLErr GWKCubicSplineNoMasksOrDstDensityOnlyUShort( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKCubicSplineNoMasksOrDstDensityOnlyUShort",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<GUInt16,GRA_CubicSpline> );
+}
 
-            if( poWK->panDstValid != NULL )
-            {
-                poWK->panDstValid[iDstOffset>>5] |= 
-                    0x01 << (iDstOffset & 0x1f);
-            }
-        }
+static CPLErr GWKNearestShort( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestShort", GWKNearestThread<GInt16> );
+}
 
-/* -------------------------------------------------------------------- */
-/*      Report progress to the user, and optionally cancel out.         */
-/* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
-            break;
-    }
+static CPLErr GWKNearestNoMasksOrDstDensityOnlyFloat( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestNoMasksOrDstDensityOnlyFloat",
+                   GWKResampleNoMasksOrDstDensityOnlyThread<float,GRA_NearestNeighbour> );
+}
 
-/* -------------------------------------------------------------------- */
-/*      Cleanup and return.                                             */
-/* -------------------------------------------------------------------- */
-    CPLFree( padfX );
-    CPLFree( padfY );
-    CPLFree( padfZ );
-    CPLFree( pabSuccess );
+static CPLErr GWKNearestFloat( GDALWarpKernel *poWK )
+{
+    return GWKRun( poWK, "GWKNearestFloat", GWKNearestThread<float> );
 }
 
+
 /************************************************************************/
 /*                           GWKAverageOrMode()                         */
 /*                                                                      */
@@ -5003,9 +4549,12 @@ static void GWKAverageOrModeThread( void* pData)
     float*   pafVals = NULL;
     int*     panSums = NULL;
 
+    // only used with nAlgo = 6
+    float quant = 0.5;
+    
     if ( poWK->eResample == GRA_Average ) 
     {
-        nAlgo = 1;
+        nAlgo = GWKAOM_Average;
     }
     else if( poWK->eResample == GRA_Mode )
     {
@@ -5014,7 +4563,7 @@ static void GWKAverageOrModeThread( void* pData)
              poWK->eWorkingDataType == GDT_UInt16 ||
              poWK->eWorkingDataType == GDT_Int16 )
         {
-            nAlgo = 3;
+            nAlgo = GWKAOM_Imode;
 
             /* In the case of a paletted or non-paletted byte band, */
             /* input values are between 0 and 255 */
@@ -5039,7 +4588,7 @@ static void GWKAverageOrModeThread( void* pData)
         }
         else
         {
-            nAlgo = 2;
+            nAlgo = GWKAOM_Fmode;
 
             if ( nSrcXSize > 0 && nSrcYSize > 0 )
             {
@@ -5054,6 +4603,29 @@ static void GWKAverageOrModeThread( void* pData)
             }
         }
     }
+    else if( poWK->eResample == GRA_Max )
+    {
+        nAlgo = GWKAOM_Max;
+    }
+    else if( poWK->eResample == GRA_Min )
+    {
+        nAlgo = GWKAOM_Min;
+    }
+    else if( poWK->eResample == GRA_Med )
+    {
+        nAlgo = GWKAOM_Quant;
+        quant = 0.5;
+    }
+    else if( poWK->eResample == GRA_Q1 )
+    {
+        nAlgo = GWKAOM_Quant;
+        quant = 0.25;
+    }
+    else if( poWK->eResample == GRA_Q3 )
+    {
+        nAlgo = GWKAOM_Quant;
+        quant = 0.75;
+    }
     else
     {
         // other resample algorithms not permitted here
@@ -5079,6 +4651,11 @@ static void GWKAverageOrModeThread( void* pData)
     pabSuccess = (int *) CPLMalloc(sizeof(int) * nDstXSize);
     pabSuccess2 = (int *) CPLMalloc(sizeof(int) * nDstXSize);
 
+    double dfSrcCoordPrecision = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0"));
+    double dfErrorThreshold = CPLAtof(
+        CSLFetchNameValueDef(poWK->papszWarpOptions, "ERROR_THRESHOLD", "0"));
+
 /* ==================================================================== */
 /*      Loop over output lines.                                         */
 /* ==================================================================== */
@@ -5107,6 +4684,24 @@ static void GWKAverageOrModeThread( void* pData)
         poWK->pfnTransformer( psJob->pTransformerArg, TRUE, nDstXSize,
                               padfX2, padfY2, padfZ2, pabSuccess2 );
 
+        if( dfSrcCoordPrecision > 0.0 )
+        {
+            GWKRoundSourceCoordinates(nDstXSize, padfX, padfY, padfZ, pabSuccess,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      psJob->pTransformerArg,
+                                      poWK->nDstXOff,
+                                      iDstY + poWK->nDstYOff);
+            GWKRoundSourceCoordinates(nDstXSize, padfX2, padfY2, padfZ2, pabSuccess2,
+                                      dfSrcCoordPrecision,
+                                      dfErrorThreshold,
+                                      poWK->pfnTransformer,
+                                      psJob->pTransformerArg,
+                                      1.0 + poWK->nDstXOff,
+                                      iDstY + 1.0 + poWK->nDstYOff);
+        }
+
 /* ==================================================================== */
 /*      Loop over pixels in output scanline.                            */
 /* ==================================================================== */
@@ -5170,7 +4765,7 @@ static void GWKAverageOrModeThread( void* pData)
 
                 // loop over source lines and pixels - 3 possible algorithms
                 
-                if ( nAlgo == 1 ) // poWK->eResample == GRA_Average
+                if ( nAlgo == GWKAOM_Average ) // poWK->eResample == GRA_Average
                 {
                     // this code adapted from GDALDownsampleChunk32R_AverageT() in gcore/overview.cpp
                     for( iSrcY = iSrcYMin; iSrcY < iSrcYMax; iSrcY++ )
@@ -5205,11 +4800,11 @@ static void GWKAverageOrModeThread( void* pData)
                                        
                 } // GRA_Average
                 
-                else if ( nAlgo == 2 || nAlgo == 3 ) // poWK->eResample == GRA_Mode
+                else if ( nAlgo == GWKAOM_Imode || nAlgo == GWKAOM_Fmode ) // poWK->eResample == GRA_Mode
                 {
                     // this code adapted from GDALDownsampleChunk32R_Mode() in gcore/overview.cpp
 
-                    if ( nAlgo == 2 ) // int32 or float
+                    if ( nAlgo == GWKAOM_Fmode ) // int32 or float
                     {
                         /* I'm not sure how much sense it makes to run a majority
                            filter on floating point data, but here it is for the sake
@@ -5234,7 +4829,7 @@ static void GWKAverageOrModeThread( void* pData)
                                 {
                                     nCount++;
 
-                                    float fVal = dfValueRealTmp;
+                                    float fVal = (float)dfValueRealTmp;
                                     
                                     //Check array for existing entry
                                     for( i = 0; i < iMaxInd; ++i )
@@ -5312,6 +4907,122 @@ static void GWKAverageOrModeThread( void* pData)
                     }
                     
                 } // GRA_Mode
+                else if ( nAlgo == GWKAOM_Max ) // poWK->eResample == GRA_Max
+                {
+                    dfTotal = -DBL_MAX;
+                    // this code adapted from nAlgo 1 method, GRA_Average
+                    for( iSrcY = iSrcYMin; iSrcY < iSrcYMax; iSrcY++ )
+                    {
+                        for( iSrcX = iSrcXMin; iSrcX < iSrcXMax; iSrcX++ )
+                        {
+                            iSrcOffset = iSrcX + iSrcY * nSrcXSize;
+
+                            if( poWK->panUnifiedSrcValid != NULL
+                                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
+                                     & (0x01 << (iSrcOffset & 0x1f))) )
+                            {
+                                continue;
+                            }
+
+                            // Returns pixel value if it is not no data
+                            if ( GWKGetPixelValue( poWK, iBand, iSrcOffset,
+                                                   &dfBandDensity, &dfValueRealTmp, &dfValueImagTmp ) && dfBandDensity > 0.0000000001 )
+                            {
+                                nCount++;
+                                if (dfTotal < dfValueRealTmp)
+                                {
+                                    dfTotal = dfValueRealTmp;
+                                }
+                            }
+                        }
+                    }
+
+                    if ( nCount > 0 )
+                    {
+                        dfValueReal = dfTotal;
+                        dfBandDensity = 1;
+                        bHasFoundDensity = TRUE;
+                    }
+
+                } // GRA_Max
+                else if ( nAlgo == GWKAOM_Min ) // poWK->eResample == GRA_Min
+                {
+                    dfTotal = DBL_MAX;
+                    // this code adapted from nAlgo 1 method, GRA_Average
+                    for( iSrcY = iSrcYMin; iSrcY < iSrcYMax; iSrcY++ )
+                    {
+                        for( iSrcX = iSrcXMin; iSrcX < iSrcXMax; iSrcX++ )
+                        {
+                            iSrcOffset = iSrcX + iSrcY * nSrcXSize;
+
+                            if( poWK->panUnifiedSrcValid != NULL
+                                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
+                                     & (0x01 << (iSrcOffset & 0x1f))) )
+                            {
+                                continue;
+                            }
+
+                            // Returns pixel value if it is not no data
+                            if ( GWKGetPixelValue( poWK, iBand, iSrcOffset,
+                                                   &dfBandDensity, &dfValueRealTmp, &dfValueImagTmp ) && dfBandDensity > 0.0000000001 )
+                            {
+                                nCount++;
+                                if (dfTotal > dfValueRealTmp)
+                                {
+                                    dfTotal = dfValueRealTmp;
+                                }
+                            }
+                        }
+                    }
+
+                    if ( nCount > 0 )
+                    {
+                        dfValueReal = dfTotal;
+                        dfBandDensity = 1;
+                        bHasFoundDensity = TRUE;
+                    }
+
+                } // GRA_Min
+                else if ( nAlgo == GWKAOM_Quant ) // poWK->eResample == GRA_Med | GRA_Q1 | GRA_Q3
+                {
+                    std::vector<double> dfValuesTmp;
+                    
+                    // this code adapted from nAlgo 1 method, GRA_Average
+                    for( iSrcY = iSrcYMin; iSrcY < iSrcYMax; iSrcY++ )
+                    {
+                        for( iSrcX = iSrcXMin; iSrcX < iSrcXMax; iSrcX++ )
+                        {
+                            iSrcOffset = iSrcX + iSrcY * nSrcXSize;
+
+                            if( poWK->panUnifiedSrcValid != NULL
+                                && !(poWK->panUnifiedSrcValid[iSrcOffset>>5]
+                                     & (0x01 << (iSrcOffset & 0x1f))) )
+                            {
+                                continue;
+                            }
+
+                            // Returns pixel value if it is not no data
+                            if ( GWKGetPixelValue( poWK, iBand, iSrcOffset,
+                                                   &dfBandDensity, &dfValueRealTmp, &dfValueImagTmp ) && dfBandDensity > 0.0000000001 )
+                            {
+                                nCount++;
+                                dfValuesTmp.push_back(dfValueRealTmp);
+                            }
+                        }
+                    }
+
+                    if ( nCount > 0 )
+                    {
+                        std::sort(dfValuesTmp.begin(), dfValuesTmp.end());
+                        int quantIdx = std::ceil(quant * dfValuesTmp.size() - 1);
+                        dfValueReal = dfValuesTmp[quantIdx];
+
+                        dfBandDensity = 1;
+                        bHasFoundDensity = TRUE;
+                        dfValuesTmp.clear();
+                    }
+
+                } // Quantile
 
 /* -------------------------------------------------------------------- */
 /*      We have a computed value from the source.  Now apply it to      */
@@ -5349,7 +5060,7 @@ static void GWKAverageOrModeThread( void* pData)
 /* -------------------------------------------------------------------- */
 /*      Report progress to the user, and optionally cancel out.         */
 /* -------------------------------------------------------------------- */
-        if (psJob->pfnProgress(psJob))
+        if (psJob->pfnProgress && psJob->pfnProgress(psJob))
             break;
     }
 
diff --git a/alg/gdalwarpkernel_opencl.c b/alg/gdalwarpkernel_opencl.c
index 15edf86..08b9549 100644
--- a/alg/gdalwarpkernel_opencl.c
+++ b/alg/gdalwarpkernel_opencl.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarpkernel_opencl.c 28301 2015-01-07 08:31:04Z rouault $
+ * $Id: gdalwarpkernel_opencl.c 28300 2015-01-07 08:30:07Z rouault $
  *
  * Project:  OpenCL Image Reprojector
  * Purpose:  Implementation of the GDALWarpKernel reprojector in OpenCL.
@@ -41,7 +41,7 @@
 #include "cpl_string.h"
 #include "gdalwarpkernel_opencl.h"
 
-CPL_CVSID("$Id: gdalwarpkernel_opencl.c 28301 2015-01-07 08:31:04Z rouault $");
+CPL_CVSID("$Id: gdalwarpkernel_opencl.c 28300 2015-01-07 08:30:07Z rouault $");
 
 #define handleErr(err) if((err) != CL_SUCCESS) { \
     CPLError(CE_Failure, CPLE_AppDefined, "Error at file %s line %d: %s", __FILE__, __LINE__, getCLErrorString(err)); \
diff --git a/alg/gdalwarpoperation.cpp b/alg/gdalwarpoperation.cpp
index 215ace6..a150d1a 100644
--- a/alg/gdalwarpoperation.cpp
+++ b/alg/gdalwarpoperation.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarpoperation.cpp 28206 2014-12-24 10:32:49Z rouault $
+ * $Id: gdalwarpoperation.cpp 28876 2015-04-08 22:21:55Z rouault $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Implementation of the GDALWarpOperation class.
@@ -33,11 +33,13 @@
 #include "cpl_multiproc.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: gdalwarpoperation.cpp 28206 2014-12-24 10:32:49Z rouault $");
-
-/* Defined in gdalwarpkernel.cpp */
-int GWKGetFilterRadius(GDALResampleAlg eResampleAlg);
+CPL_CVSID("$Id: gdalwarpoperation.cpp 28876 2015-04-08 22:21:55Z rouault $");
 
+struct _GDALWarpChunk { 
+    int dx, dy, dsx, dsy; 
+    int sx, sy, ssx, ssy; 
+    int sExtraSx, sExtraSy;
+}; 
 
 /************************************************************************/
 /* ==================================================================== */
@@ -127,7 +129,7 @@ GDALWarpOperation::GDALWarpOperation()
 
     nChunkListCount = 0;
     nChunkListMax = 0;
-    panChunkList = NULL;
+    pasChunkList = NULL;
 
     bReportTimings = FALSE;
     nLastTimeReported = 0;
@@ -205,7 +207,12 @@ int GDALWarpOperation::ValidateOptions()
         && psOptions->eResampleAlg != GRA_CubicSpline
         && psOptions->eResampleAlg != GRA_Lanczos
         && psOptions->eResampleAlg != GRA_Average
-        && psOptions->eResampleAlg != GRA_Mode )
+        && psOptions->eResampleAlg != GRA_Mode
+        && psOptions->eResampleAlg != GRA_Max 
+        && psOptions->eResampleAlg != GRA_Min
+        && psOptions->eResampleAlg != GRA_Med
+        && psOptions->eResampleAlg != GRA_Q1
+        && psOptions->eResampleAlg != GRA_Q3)
     {
         CPLError( CE_Failure, CPLE_IllegalArg, 
                   "GDALWarpOptions.Validate()\n"
@@ -417,7 +424,7 @@ CPLErr GDALWarpOperation::Initialize( const GDALWarpOptions *psNewOptions )
         WipeOptions();
 
     psOptions = GDALCloneWarpOptions( psNewOptions );
-    psOptions->papszWarpOptions = CSLAddNameValue(psOptions->papszWarpOptions,
+    psOptions->papszWarpOptions = CSLSetNameValue(psOptions->papszWarpOptions,
         "EXTRA_ELTS", CPLSPrintf("%d", WARP_EXTRA_ELTS));
 
 /* -------------------------------------------------------------------- */
@@ -556,7 +563,7 @@ CPLErr GDALWarpOperation::Initialize( const GDALWarpOptions *psNewOptions )
             const char *pszBD = CSLFetchNameValue( psOptions->papszWarpOptions,
                                                    "CUTLINE_BLEND_DIST" );
             if( pszBD )
-                psOptions->dfCutlineBlendDist = atof(pszBD);
+                psOptions->dfCutlineBlendDist = CPLAtof(pszBD);
         }
     }
 
@@ -612,16 +619,11 @@ void GDALDestroyWarpOperation( GDALWarpOperationH hOperation )
 /************************************************************************/
 /*                         ChunkAndWarpImage()                          */
 /************************************************************************/
- 
- struct WarpChunk { 
-    int dx, dy, dsx, dsy; 
-    int sx, sy, ssx, ssy; 
-}; 
- 
+
 static int OrderWarpChunk(const void* _a, const void *_b)
 { 
-    const WarpChunk* a = (const WarpChunk* )_a;
-    const WarpChunk* b = (const WarpChunk* )_b;
+    const GDALWarpChunk* a = (const GDALWarpChunk* )_a;
+    const GDALWarpChunk* b = (const GDALWarpChunk* )_b;
     if (a->dy < b->dy)
         return -1; 
     else if (a->dy > b->dy)
@@ -668,7 +670,7 @@ CPLErr GDALWarpOperation::ChunkAndWarpImage(
     CollectChunkList( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
     
     /* Sort chucks from top to bottom, and for equal y, from left to right */
-    qsort(panChunkList, nChunkListCount, sizeof(WarpChunk), OrderWarpChunk); 
+    qsort(pasChunkList, nChunkListCount, sizeof(GDALWarpChunk), OrderWarpChunk); 
 
 /* -------------------------------------------------------------------- */
 /*      Total up output pixels to process.                              */
@@ -678,8 +680,8 @@ CPLErr GDALWarpOperation::ChunkAndWarpImage(
 
     for( iChunk = 0; iChunk < nChunkListCount; iChunk++ )
     {
-        int *panThisChunk = panChunkList + iChunk*8;
-        double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
+        GDALWarpChunk *pasThisChunk = pasChunkList + iChunk;
+        double dfChunkPixels = pasThisChunk->dsx * (double) pasThisChunk->dsy;
 
         dfTotalPixels += dfChunkPixels;
     }
@@ -692,17 +694,18 @@ CPLErr GDALWarpOperation::ChunkAndWarpImage(
 
     for( iChunk = 0; iChunk < nChunkListCount; iChunk++ )
     {
-        int *panThisChunk = panChunkList + iChunk*8;
-        double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
+        GDALWarpChunk *pasThisChunk = pasChunkList + iChunk;
+        double dfChunkPixels = pasThisChunk->dsx * (double) pasThisChunk->dsy;
         CPLErr eErr;
 
         double dfProgressBase = dfPixelsProcessed / dfTotalPixels;
         double dfProgressScale = dfChunkPixels / dfTotalPixels;
 
-        eErr = WarpRegion( panThisChunk[0], panThisChunk[1], 
-                           panThisChunk[2], panThisChunk[3],
-                           panThisChunk[4], panThisChunk[5],
-                           panThisChunk[6], panThisChunk[7],
+        eErr = WarpRegion( pasThisChunk->dx, pasThisChunk->dy, 
+                           pasThisChunk->dsx, pasThisChunk->dsy,
+                           pasThisChunk->sx, pasThisChunk->sy, 
+                           pasThisChunk->ssx, pasThisChunk->ssy,
+                           pasThisChunk->sExtraSx, pasThisChunk->sExtraSy,
                            dfProgressBase, dfProgressScale);
 
         if( eErr != CE_None )
@@ -742,16 +745,16 @@ CPLErr GDALChunkAndWarpImage( GDALWarpOperationH hOperation,
 typedef struct
 {
     GDALWarpOperation *poOperation;
-    int               *panChunkInfo;
-    void              *hThreadHandle;
+    GDALWarpChunk     *pasChunkInfo;
+    CPLJoinableThread *hThreadHandle;
     CPLErr             eErr;
     double             dfProgressBase;
     double             dfProgressScale;
-    void              *hIOMutex;
+    CPLMutex          *hIOMutex;
 
-    void              *hCondMutex;
+    CPLMutex          *hCondMutex;
     int                bIOMutexTaken;
-    void              *hCond;
+    CPLCond           *hCond;
 } ChunkThreadData;
 
 
@@ -760,7 +763,7 @@ static void ChunkThreadMain( void *pThreadData )
 {
     volatile ChunkThreadData* psData = (volatile ChunkThreadData*) pThreadData;
 
-    int *panChunkInfo = psData->panChunkInfo;
+    GDALWarpChunk *pasChunkInfo = psData->pasChunkInfo;
 
 /* -------------------------------------------------------------------- */
 /*      Acquire IO mutex.                                               */
@@ -782,10 +785,11 @@ static void ChunkThreadMain( void *pThreadData )
         }
 
         psData->eErr = psData->poOperation->WarpRegion(
-                                    panChunkInfo[0], panChunkInfo[1],
-                                    panChunkInfo[2], panChunkInfo[3],
-                                    panChunkInfo[4], panChunkInfo[5],
-                                    panChunkInfo[6], panChunkInfo[7],
+                                    pasChunkInfo->dx, pasChunkInfo->dy, 
+                                    pasChunkInfo->dsx, pasChunkInfo->dsy,
+                                    pasChunkInfo->sx, pasChunkInfo->sy, 
+                                    pasChunkInfo->ssx, pasChunkInfo->ssy,
+                                    pasChunkInfo->sExtraSx, pasChunkInfo->sExtraSy,
                                     psData->dfProgressBase,
                                     psData->dfProgressScale);
 
@@ -830,8 +834,8 @@ CPLErr GDALWarpOperation::ChunkAndWarpMulti(
     CPLReleaseMutex( hIOMutex );
     CPLReleaseMutex( hWarpMutex );
 
-    void* hCond = CPLCreateCond();
-    void* hCondMutex = CPLCreateMutex();
+    CPLCond* hCond = CPLCreateCond();
+    CPLMutex* hCondMutex = CPLCreateMutex();
     CPLReleaseMutex(hCondMutex);
 
 /* -------------------------------------------------------------------- */
@@ -841,7 +845,7 @@ CPLErr GDALWarpOperation::ChunkAndWarpMulti(
     CollectChunkList( nDstXOff, nDstYOff, nDstXSize, nDstYSize );
 
     /* Sort chucks from top to bottom, and for equal y, from left to right */
-    qsort(panChunkList, nChunkListCount, sizeof(WarpChunk), OrderWarpChunk); 
+    qsort(pasChunkList, nChunkListCount, sizeof(GDALWarpChunk), OrderWarpChunk); 
 
 /* -------------------------------------------------------------------- */
 /*      Process them one at a time, updating the progress               */
@@ -867,15 +871,15 @@ CPLErr GDALWarpOperation::ChunkAndWarpMulti(
 /* -------------------------------------------------------------------- */
         if( iChunk < nChunkListCount )
         {
-            int *panThisChunk = panChunkList + iChunk*8;
-            double dfChunkPixels = panThisChunk[2] * (double) panThisChunk[3];
+            GDALWarpChunk *pasThisChunk = pasChunkList + iChunk;
+            double dfChunkPixels = pasThisChunk->dsx * (double) pasThisChunk->dsy;
 
             asThreadData[iThread].dfProgressBase = dfPixelsProcessed / dfTotalPixels;
             asThreadData[iThread].dfProgressScale = dfChunkPixels / dfTotalPixels;
 
             dfPixelsProcessed += dfChunkPixels;
 
-            asThreadData[iThread].panChunkInfo = panThisChunk;
+            asThreadData[iThread].pasChunkInfo = pasThisChunk;
 
             if ( iChunk == 0 )
             {
@@ -974,8 +978,8 @@ CPLErr GDALChunkAndWarpMulti( GDALWarpOperationH hOperation,
 void GDALWarpOperation::WipeChunkList()
 
 {
-    CPLFree( panChunkList );
-    panChunkList = NULL;
+    CPLFree( pasChunkList );
+    pasChunkList = NULL;
     nChunkListCount = 0;
     nChunkListMax = 0;
 }
@@ -993,10 +997,13 @@ CPLErr GDALWarpOperation::CollectChunkList(
 /*      output area.                                                    */
 /* -------------------------------------------------------------------- */
     int nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize;
+    int nSrcXExtraSize, nSrcYExtraSize;
+    double dfSrcFillRatio;
     CPLErr eErr;
 
     eErr = ComputeSourceWindow( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
-                                &nSrcXOff, &nSrcYOff, &nSrcXSize, &nSrcYSize );
+                                &nSrcXOff, &nSrcYOff, &nSrcXSize, &nSrcYSize,
+                                &nSrcXExtraSize, &nSrcYExtraSize, &dfSrcFillRatio );
     
     if( eErr != CE_None )
     {
@@ -1082,26 +1089,41 @@ CPLErr GDALWarpOperation::CollectChunkList(
                          &nBlockXSize, &nBlockYSize);
     }
     
-    if( dfTotalMemoryUse > psOptions->dfWarpMemoryLimit 
-        && (nDstXSize > 2 || nDstYSize > 2) )
-    {
-        CPLErr eErr2;
-
-        int bOptimizeSize =
+    // If size of working buffers need exceed the allow limit, then divide
+    // the target area
+    // Do it also if the "fill ratio" of the source is too low (#3120), but
+    // only if there's at least some source pixel intersecting. The
+    // SRC_FILL_RATIO_HEURISTICS warping option is undocumented and only here
+    // in case the heuristics would cause issues.
+    /*CPLDebug("WARP", "dst=(%d,%d,%d,%d) src=(%d,%d,%d,%d) srcfillratio=%.18g",
+             nDstXOff, nDstYOff, nDstXSize, nDstYSize,
+             nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize, dfSrcFillRatio);*/
+    if( (dfTotalMemoryUse > psOptions->dfWarpMemoryLimit && (nDstXSize > 2 || nDstYSize > 2)) ||
+        (dfSrcFillRatio > 0 && dfSrcFillRatio < 0.5 && (nDstXSize > 100 || nDstYSize > 100) &&
+         CSLFetchBoolean( psOptions->papszWarpOptions, "SRC_FILL_RATIO_HEURISTICS", TRUE )) )
+    {
+        CPLErr eErr2 = CE_None;
+        
+        int bStreamableOutput =
+                CSLFetchBoolean( psOptions->papszWarpOptions, "STREAMABLE_OUTPUT", FALSE );
+        int bOptimizeSize = !bStreamableOutput &&
                 CSLFetchBoolean( psOptions->papszWarpOptions, "OPTIMIZE_SIZE", FALSE );
 
         /* If the region width is greater than the region height, */
         /* cut in half in the width. When we want to optimize the size */
         /* of a compressed output dataset, do this only if each half part */
         /* is at least as wide as the block width */
+        int bHasDivided = FALSE;
         if( nDstXSize > nDstYSize &&
-            (!bOptimizeSize ||
-             (bOptimizeSize && (nDstXSize / 2 >= nBlockXSize || nDstYSize == 1))) )
+            ((!bOptimizeSize && !bStreamableOutput) ||
+             (bOptimizeSize && (nDstXSize / 2 >= nBlockXSize || nDstYSize == 1)) ||
+             (bStreamableOutput && nDstXSize / 2 >= nBlockXSize && nDstYSize == nBlockYSize)) )
         {
+            bHasDivided = TRUE;
             int nChunk1 = nDstXSize / 2;
             
             /* In the optimize size case, try to stick on target block boundaries */
-            if (bOptimizeSize && nChunk1 > nBlockXSize)
+            if ((bOptimizeSize || bStreamableOutput) && nChunk1 > nBlockXSize)
                 nChunk1 = (nChunk1 / nBlockXSize) * nBlockXSize;
             
             int nChunk2 = nDstXSize - nChunk1;
@@ -1112,12 +1134,13 @@ CPLErr GDALWarpOperation::CollectChunkList(
             eErr2 = CollectChunkList( nDstXOff+nChunk1, nDstYOff, 
                                       nChunk2, nDstYSize );
         }
-        else
+        else if( !(bStreamableOutput && nDstYSize / 2 < nBlockYSize) )
         {
+            bHasDivided = TRUE;
             int nChunk1 = nDstYSize / 2;
 
             /* In the optimize size case, try to stick on target block boundaries */
-            if (bOptimizeSize && nChunk1 > nBlockYSize)
+            if ((bOptimizeSize || bStreamableOutput) && nChunk1 > nBlockYSize)
                 nChunk1 = (nChunk1 / nBlockYSize) * nBlockYSize;
 
             int nChunk2 = nDstYSize - nChunk1;
@@ -1129,10 +1152,13 @@ CPLErr GDALWarpOperation::CollectChunkList(
                                       nDstXSize, nChunk2 );
         }
 
-        if( eErr == CE_None )
-            return eErr2;
-        else
-            return eErr;
+        if( bHasDivided )
+        {
+            if( eErr == CE_None )
+                return eErr2;
+            else
+                return eErr;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1141,18 +1167,20 @@ CPLErr GDALWarpOperation::CollectChunkList(
     if( nChunkListCount == nChunkListMax )
     {
         nChunkListMax = nChunkListMax * 2 + 1;
-        panChunkList = (int *) 
-            CPLRealloc(panChunkList,sizeof(int)*nChunkListMax*8 );
+        pasChunkList = (GDALWarpChunk *) 
+            CPLRealloc(pasChunkList,sizeof(GDALWarpChunk)*nChunkListMax );
     }
 
-    panChunkList[nChunkListCount*8+0] = nDstXOff;
-    panChunkList[nChunkListCount*8+1] = nDstYOff;
-    panChunkList[nChunkListCount*8+2] = nDstXSize;
-    panChunkList[nChunkListCount*8+3] = nDstYSize;
-    panChunkList[nChunkListCount*8+4] = nSrcXOff;
-    panChunkList[nChunkListCount*8+5] = nSrcYOff;
-    panChunkList[nChunkListCount*8+6] = nSrcXSize;
-    panChunkList[nChunkListCount*8+7] = nSrcYSize;
+    pasChunkList[nChunkListCount].dx = nDstXOff;
+    pasChunkList[nChunkListCount].dy = nDstYOff;
+    pasChunkList[nChunkListCount].dsx = nDstXSize;
+    pasChunkList[nChunkListCount].dsy = nDstYSize;
+    pasChunkList[nChunkListCount].sx = nSrcXOff;
+    pasChunkList[nChunkListCount].sy = nSrcYOff;
+    pasChunkList[nChunkListCount].ssx = nSrcXSize;
+    pasChunkList[nChunkListCount].ssy = nSrcYSize;
+    pasChunkList[nChunkListCount].sExtraSx = nSrcXExtraSize;
+    pasChunkList[nChunkListCount].sExtraSy = nSrcYExtraSize;
 
     nChunkListCount++;
 
@@ -1206,6 +1234,22 @@ CPLErr GDALWarpOperation::WarpRegion( int nDstXOff, int nDstYOff,
                                       int nSrcXSize, int nSrcYSize,
                                       double dfProgressBase,
                                       double dfProgressScale)
+{
+    return WarpRegion(nDstXOff, nDstYOff, 
+                      nDstXSize, nDstYSize,
+                      nSrcXOff, nSrcYOff,
+                      nSrcXSize, nSrcYSize,
+                      0, 0,
+                      dfProgressBase, dfProgressScale);
+}
+
+CPLErr GDALWarpOperation::WarpRegion( int nDstXOff, int nDstYOff, 
+                                      int nDstXSize, int nDstYSize,
+                                      int nSrcXOff, int nSrcYOff,
+                                      int nSrcXSize, int nSrcYSize,
+                                      int nSrcXExtraSize, int nSrcYExtraSize,
+                                      double dfProgressBase,
+                                      double dfProgressScale)
 
 {
     CPLErr eErr;
@@ -1331,6 +1375,7 @@ CPLErr GDALWarpOperation::WarpRegion( int nDstXOff, int nDstYOff,
     eErr = WarpRegionToBuffer( nDstXOff, nDstYOff, nDstXSize, nDstYSize, 
                                pDstBuffer, psOptions->eWorkingDataType, 
                                nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
+                               nSrcXExtraSize, nSrcYExtraSize,
                                dfProgressBase, dfProgressScale);
 
 /* -------------------------------------------------------------------- */
@@ -1430,11 +1475,24 @@ CPLErr GDALWarpRegion( GDALWarpOperationH hOperation,
  *
  * @return CE_None on success or CE_Failure if an error occurs.
  */
-                                 
+
+CPLErr GDALWarpOperation::WarpRegionToBuffer( 
+    int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize, 
+    void *pDataBuf, GDALDataType eBufDataType,
+    int nSrcXOff, int nSrcYOff, int nSrcXSize, int nSrcYSize,
+    double dfProgressBase, double dfProgressScale)
+{
+    return WarpRegionToBuffer(nDstXOff, nDstYOff, nDstXSize, nDstYSize, 
+                              pDataBuf, eBufDataType,
+                              nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize, 0, 0,
+                              dfProgressBase, dfProgressScale);
+}
+
 CPLErr GDALWarpOperation::WarpRegionToBuffer( 
     int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize, 
     void *pDataBuf, GDALDataType eBufDataType,
     int nSrcXOff, int nSrcYOff, int nSrcXSize, int nSrcYSize,
+    int nSrcXExtraSize, int nSrcYExtraSize,
     double dfProgressBase, double dfProgressScale)
 
 {
@@ -1452,7 +1510,8 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
     {
         eErr = ComputeSourceWindow( nDstXOff, nDstYOff, nDstXSize, nDstYSize,
                                     &nSrcXOff, &nSrcYOff, 
-                                    &nSrcXSize, &nSrcYSize );
+                                    &nSrcXSize, &nSrcYSize,
+                                    &nSrcXExtraSize, &nSrcYExtraSize, NULL );
     
         if( eErr != CE_None )
             return eErr;
@@ -1489,6 +1548,8 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
     oWK.nSrcYOff = nSrcYOff;
     oWK.nSrcXSize = nSrcXSize;
     oWK.nSrcYSize = nSrcYSize;
+    oWK.nSrcXExtraSize = nSrcXExtraSize;
+    oWK.nSrcYExtraSize = nSrcYExtraSize;
 
     if (nSrcXSize != 0 && nSrcYSize != 0 &&
         (nSrcXSize > INT_MAX / nSrcYSize ||
@@ -1558,11 +1619,13 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
     if( eErr == CE_None && psOptions->nSrcAlphaBand > 0 &&
         nSrcXSize > 0 && nSrcYSize > 0 )
     {
-        CPLAssert( oWK.pafDstDensity == NULL );
+        CPLAssert( oWK.pafUnifiedSrcDensity == NULL );
 
         eErr = CreateKernelMask( &oWK, 0, "UnifiedSrcDensity" );
         
         if( eErr == CE_None )
+        {
+            int bOutAllOpaque = FALSE;
             eErr = 
                 GDALWarpSrcAlphaMasker( psOptions, 
                                         psOptions->nBandCount, 
@@ -1570,7 +1633,15 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
                                         oWK.nSrcXOff, oWK.nSrcYOff, 
                                         oWK.nSrcXSize, oWK.nSrcYSize,
                                         oWK.papabySrcImage,
-                                        TRUE, oWK.pafUnifiedSrcDensity );
+                                        TRUE, oWK.pafUnifiedSrcDensity,
+                                        &bOutAllOpaque );
+            if( bOutAllOpaque )
+            {
+                //CPLDebug("WARP", "No need for a source density mask as all values are opaque");
+                CPLFree(oWK.pafUnifiedSrcDensity);
+                oWK.pafUnifiedSrcDensity = NULL;
+            }
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1625,12 +1696,14 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
     }
     
 /* -------------------------------------------------------------------- */
-/*      If we have source nodata values create, or update the           */
-/*      validity mask.                                                  */
+/*      If we have source nodata values create the validity mask.       */
 /* -------------------------------------------------------------------- */
     if( eErr == CE_None && psOptions->padfSrcNoDataReal != NULL &&
         nSrcXSize > 0 && nSrcYSize > 0 )
     {
+        CPLAssert( oWK.papanBandSrcValid == NULL );
+
+        int bAllBandsAllValid = TRUE;
         for( i = 0; i < psOptions->nBandCount && eErr == CE_None; i++ )
         {
             eErr = CreateKernelMask( &oWK, i, "BandSrcValid" );
@@ -1641,15 +1714,30 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
                 adfNoData[0] = psOptions->padfSrcNoDataReal[i];
                 adfNoData[1] = psOptions->padfSrcNoDataImag[i];
 
+                int bAllValid = FALSE;
                 eErr = 
                     GDALWarpNoDataMasker( adfNoData, 1, 
                                           psOptions->eWorkingDataType,
                                           oWK.nSrcXOff, oWK.nSrcYOff, 
                                           oWK.nSrcXSize, oWK.nSrcYSize,
                                           &(oWK.papabySrcImage[i]),
-                                          FALSE, oWK.papanBandSrcValid[i] );
+                                          FALSE, oWK.papanBandSrcValid[i],
+                                          &bAllValid );
+                if( !bAllValid )
+                    bAllBandsAllValid = FALSE;
             }
         }
+
+        /* Optimization: if all pixels in all bands are valid, */
+        /* we don't need a mask */
+        if( bAllBandsAllValid )
+        {
+            //CPLDebug("WARP", "No need for a source nodata mask as all values are valid");
+            for( i = 0; i < oWK.nBands; i++ )
+                CPLFree( oWK.papanBandSrcValid[i] );
+            CPLFree( oWK.papanBandSrcValid );
+            oWK.papanBandSrcValid = NULL;
+        }
         
 /* -------------------------------------------------------------------- */
 /*      If UNIFIED_SRC_NODATA is set, then compute a unified input      */
@@ -1657,7 +1745,8 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
 /*      is, we only treat a pixel as nodata if all bands match their    */
 /*      respective nodata values.                                       */
 /* -------------------------------------------------------------------- */
-        if( CSLFetchBoolean( psOptions->papszWarpOptions, "UNIFIED_SRC_NODATA",
+        if( oWK.papanBandSrcValid != NULL &&
+            CSLFetchBoolean( psOptions->papszWarpOptions, "UNIFIED_SRC_NODATA",
                              FALSE ) 
             && eErr == CE_None )
         {
@@ -1666,19 +1755,22 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
 
             eErr = CreateKernelMask( &oWK, i, "UnifiedSrcValid" );
 
-            memset( oWK.panUnifiedSrcValid, 0, nBytesInMask );
-            
-            for( i = 0; i < psOptions->nBandCount; i++ )
+            if( eErr == CE_None )
             {
-                for( iWord = nBytesInMask/4 - 1; iWord >= 0; iWord-- )
-                    oWK.panUnifiedSrcValid[iWord] |= 
-                        oWK.papanBandSrcValid[i][iWord];
-                CPLFree( oWK.papanBandSrcValid[i] );
-                oWK.papanBandSrcValid[i] = NULL;
+                memset( oWK.panUnifiedSrcValid, 0, nBytesInMask );
+                
+                for( i = 0; i < psOptions->nBandCount; i++ )
+                {
+                    for( iWord = nBytesInMask/4 - 1; iWord >= 0; iWord-- )
+                        oWK.panUnifiedSrcValid[iWord] |= 
+                            oWK.papanBandSrcValid[i][iWord];
+                    CPLFree( oWK.papanBandSrcValid[i] );
+                    oWK.papanBandSrcValid[i] = NULL;
+                }
+                
+                CPLFree( oWK.papanBandSrcValid );
+                oWK.papanBandSrcValid = NULL;
             }
-            
-            CPLFree( oWK.papanBandSrcValid );
-            oWK.papanBandSrcValid = NULL;
         }
     }
 
@@ -1712,8 +1804,8 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
     }
     
 /* -------------------------------------------------------------------- */
-/*      If we have destination nodata values create, or update the      */
-/*      validity mask.  We clear the DstValid for any pixel that we     */
+/*      If we have destination nodata values create the                 */
+/*      validity mask.  We set the DstValid for any pixel that we       */
 /*      do no have valid data in *any* of the source bands.             */
 /*                                                                      */
 /*      Note that we don't support any concept of unified nodata on     */
@@ -1722,14 +1814,15 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
 /* -------------------------------------------------------------------- */
     if( eErr == CE_None && psOptions->padfDstNoDataReal != NULL )
     {
-        GUInt32 *panBandMask = NULL, *panMergedMask = NULL;
+        CPLAssert( oWK.panDstValid == NULL );
+
+        GUInt32 *panBandMask = NULL;
         int     nMaskWords = (oWK.nDstXSize * oWK.nDstYSize + 31)/32;
 
         eErr = CreateKernelMask( &oWK, 0, "DstValid" );
         if( eErr == CE_None )
         {
             panBandMask = (GUInt32 *) CPLMalloc(nMaskWords*4);
-            panMergedMask = (GUInt32 *) CPLCalloc(nMaskWords,4);
         }
 
         if( eErr == CE_None && panBandMask != NULL )
@@ -1745,23 +1838,30 @@ CPLErr GDALWarpOperation::WarpRegionToBuffer(
                 adfNoData[0] = psOptions->padfDstNoDataReal[iBand];
                 adfNoData[1] = psOptions->padfDstNoDataImag[iBand];
             
+                int bAllValid = FALSE;
                 eErr = 
                     GDALWarpNoDataMasker( adfNoData, 1, 
                                           psOptions->eWorkingDataType,
                                           oWK.nDstXOff, oWK.nDstYOff, 
                                           oWK.nDstXSize, oWK.nDstYSize,
                                           oWK.papabyDstImage + iBand,
-                                          FALSE, panBandMask );
+                                          FALSE, panBandMask,
+                                          &bAllValid );
+
+                /* Optimization: if there's a single band and all pixels are */
+                /* valid then we don't need a mask */
+                if( bAllValid && psOptions->nBandCount == 1 )
+                {
+                    //CPLDebug("WARP", "No need for a destination nodata mask as all values are valid");
+                    CPLFree(oWK.panDstValid);
+                    oWK.panDstValid = NULL;
+                    break;
+                }
 
                 for( iWord = nMaskWords - 1; iWord >= 0; iWord-- )
-                    panMergedMask[iWord] |= panBandMask[iWord];
+                    oWK.panDstValid[iWord] |= panBandMask[iWord];
             }
             CPLFree( panBandMask );
-
-            for( iWord = nMaskWords - 1; iWord >= 0; iWord-- )
-                oWK.panDstValid[iWord] &= panMergedMask[iWord];
-
-            CPLFree( panMergedMask );
         }
     }
         
@@ -1931,7 +2031,7 @@ CPLErr GDALWarpOperation::CreateKernelMask( GDALWarpKernel *poKernel,
         nXSize = poKernel->nDstXSize;
         nYSize = poKernel->nDstYSize;
         nBitsPerPixel = 1;
-        nDefault = 0xff;
+        nDefault = 0;
     }
     else if( EQUAL(pszType,"DstDensity") )
     {
@@ -1986,7 +2086,9 @@ CPLErr GDALWarpOperation::CreateKernelMask( GDALWarpKernel *poKernel,
 CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff, 
                                               int nDstXSize, int nDstYSize,
                                               int *pnSrcXOff, int *pnSrcYOff, 
-                                              int *pnSrcXSize, int *pnSrcYSize)
+                                              int *pnSrcXSize, int *pnSrcYSize,
+                                              int *pnSrcXExtraSize, int *pnSrcYExtraSize,
+                                              double *pdfSrcFillRatio)
 
 {
 /* -------------------------------------------------------------------- */
@@ -2190,6 +2292,15 @@ CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff,
 /* -------------------------------------------------------------------- */
     int nResWinSize = GWKGetFilterRadius(psOptions->eResampleAlg);
 
+    /* Take scaling into account */
+    double dfXScale = (double)nDstXSize / (dfMaxXOut - dfMinXOut);
+    double dfYScale = (double)nDstYSize / (dfMaxYOut - dfMinYOut);
+    int nXRadius = ( dfXScale < 1.0 ) ?
+        (int)ceil( nResWinSize / dfXScale ) :nResWinSize;
+    int nYRadius = ( dfYScale < 1.0 ) ?
+        (int)ceil( nResWinSize / dfYScale ) : nResWinSize;
+    nResWinSize = MAX(nXRadius, nYRadius);
+
 /* -------------------------------------------------------------------- */
 /*      Allow addition of extra sample pixels to source window to       */
 /*      avoid missing pixels due to sampling error.  In fact,           */
@@ -2208,8 +2319,12 @@ CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff,
 /* -------------------------------------------------------------------- */
 /*      return bounds.                                                  */
 /* -------------------------------------------------------------------- */
-    *pnSrcXOff = MAX(0,(int) floor( dfMinXOut ) - nResWinSize );
-    *pnSrcYOff = MAX(0,(int) floor( dfMinYOut ) - nResWinSize );
+    /*CPLDebug("WARP", "dst=(%d,%d,%d,%d) raw src=(minx=%.8g,miny=%.8g,maxx=%.8g,maxy=%.8g)",
+             nDstXOff, nDstYOff, nDstXSize, nDstYSize,
+             dfMinXOut, dfMinYOut, dfMaxXOut, dfMaxYOut);
+    */
+    *pnSrcXOff = MAX(0,(int) floor( dfMinXOut ) );
+    *pnSrcYOff = MAX(0,(int) floor( dfMinYOut ) );
     *pnSrcXOff = MIN(*pnSrcXOff,GDALGetRasterXSize(psOptions->hSrcDS));
     *pnSrcYOff = MIN(*pnSrcYOff,GDALGetRasterYSize(psOptions->hSrcDS));
 
@@ -2219,6 +2334,19 @@ CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff,
     double dfCeilMaxYOut = ceil(dfMaxYOut);
     if( dfCeilMaxYOut > INT_MAX )
         dfCeilMaxYOut = INT_MAX;
+
+    int nSrcXSizeRaw = MIN( GDALGetRasterXSize(psOptions->hSrcDS) - *pnSrcXOff,
+                       ((int) dfCeilMaxXOut) - *pnSrcXOff );
+    int nSrcYSizeRaw = MIN( GDALGetRasterYSize(psOptions->hSrcDS) - *pnSrcYOff,
+                       ((int) dfCeilMaxYOut) - *pnSrcYOff );
+    nSrcXSizeRaw = MAX(0,nSrcXSizeRaw);
+    nSrcYSizeRaw = MAX(0,nSrcYSizeRaw);
+    
+    *pnSrcXOff = MAX(0,(int) floor( dfMinXOut ) - nResWinSize );
+    *pnSrcYOff = MAX(0,(int) floor( dfMinYOut ) - nResWinSize );
+    *pnSrcXOff = MIN(*pnSrcXOff,GDALGetRasterXSize(psOptions->hSrcDS));
+    *pnSrcYOff = MIN(*pnSrcYOff,GDALGetRasterYSize(psOptions->hSrcDS));
+
     *pnSrcXSize = MIN( GDALGetRasterXSize(psOptions->hSrcDS) - *pnSrcXOff,
                        ((int) dfCeilMaxXOut) - *pnSrcXOff + nResWinSize );
     *pnSrcYSize = MIN( GDALGetRasterYSize(psOptions->hSrcDS) - *pnSrcYOff,
@@ -2226,6 +2354,16 @@ CPLErr GDALWarpOperation::ComputeSourceWindow(int nDstXOff, int nDstYOff,
     *pnSrcXSize = MAX(0,*pnSrcXSize);
     *pnSrcYSize = MAX(0,*pnSrcYSize);
 
+    if( pnSrcXExtraSize )
+        *pnSrcXExtraSize = *pnSrcXSize - nSrcXSizeRaw;
+    if( pnSrcYExtraSize )
+        *pnSrcYExtraSize = *pnSrcYSize - nSrcYSizeRaw;
+    
+    // Computed the ratio of the clamped source raster window size over
+    // the unclamped source raster window size
+    if( pdfSrcFillRatio )
+        *pdfSrcFillRatio = *pnSrcXSize * *pnSrcYSize / MAX(1.0,
+        (dfMaxXOut - dfMinXOut + 2 * nResWinSize) * (dfMaxYOut - dfMinYOut + 2 * nResWinSize)); 
 
     return CE_None;
 }
diff --git a/alg/llrasterize.cpp b/alg/llrasterize.cpp
index 9dbfe42..8150264 100644
--- a/alg/llrasterize.cpp
+++ b/alg/llrasterize.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: llrasterize.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: llrasterize.cpp 29117 2015-05-02 20:50:05Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Vector polygon rasterization code.
@@ -249,12 +249,15 @@ No known bug
 /*                         GDALdllImagePoint()                          */
 /************************************************************************/
 
-void GDALdllImagePoint( int nRasterXSize, int nRasterYSize, 
-                        int nPartCount, CPL_UNUSED int *panPartSize,
+void GDALdllImagePoint( int nRasterXSize, int nRasterYSize,
+                        int nPartCount,
+                        CPL_UNUSED int *panPartSize,
                         double *padfX, double *padfY, double *padfVariant,
                         llPointFunc pfnPointFunc, void *pCBData )
 {
-    for ( int i = 0; i < nPartCount; i++ )
+    int i;
+
+    for ( i = 0; i < nPartCount; i++ )
     {
         int nX = (int)floor( padfX[i] );
         int nY = (int)floor( padfY[i] );
@@ -553,7 +556,7 @@ GDALdllImageLineAllTouched(int nRasterXSize, int nRasterYSize,
             }
 
             // step from pixel to pixel.
-            while( dfX < dfXEnd )
+            while( dfX >= 0 && dfX < dfXEnd )
             {
                 int iX = (int) floor(dfX);
                 int iY = (int) floor(dfY);
diff --git a/alg/makefile.vc b/alg/makefile.vc
index ce546a0..f1072db 100644
--- a/alg/makefile.vc
+++ b/alg/makefile.vc
@@ -17,7 +17,7 @@ OBJ =	gdaldither.obj gdalmediancut.obj gdal_crs.obj gdaltransformer.obj \
 	gdalsimplewarp.obj gdalwarper.obj gdalwarpkernel.obj \
 	thinplatespline.obj gdal_tps.obj gdalrasterize.obj llrasterize.obj \
 	gdalwarpoperation.obj gdalchecksum.obj gdal_rpc.obj gdalgeoloc.obj \
-	gdalgrid.obj gdalcutline.obj gdalproximity.obj rasterfill.obj \
+	gdalgrid.obj gdalgridsse.obj gdalcutline.obj gdalproximity.obj rasterfill.obj \
 	gdalsievefilter.obj gdalrasterpolygonenumerator.obj polygonize.obj \
 	gdalrasterfpolygonenumerator.obj fpolygonize.obj contour.obj \
 	gdal_octave.obj gdal_simplesurf.obj gdalmatching.obj \
diff --git a/alg/polygonize.cpp b/alg/polygonize.cpp
index 1959f6b..74646f8 100644
--- a/alg/polygonize.cpp
+++ b/alg/polygonize.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: polygonize.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: polygonize.cpp 28826 2015-03-30 17:51:14Z rouault $
  * Project:  GDAL
  * Purpose:  Raster to Polygon Converter
  * Author:   Frank Warmerdam, warmerdam at pobox.com
@@ -32,9 +32,7 @@
 #include "cpl_string.h"
 #include <vector>
 
-CPL_CVSID("$Id: polygonize.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-#define GP_NODATA_MARKER -51502112
+CPL_CVSID("$Id: polygonize.cpp 28826 2015-03-30 17:51:14Z rouault $");
 
 #ifdef OGR_ENABLED
 
@@ -697,13 +695,10 @@ GDALPolygonize( GDALRasterBandH hSrcBand,
             {
                 if( papoPoly[iX] && papoPoly[iX]->nLastLineUpdated < iY-1 )
                 {
-                    if( hMaskBand == NULL
-                        || papoPoly[iX]->nPolyValue != GP_NODATA_MARKER )
-                    {
-                        eErr = 
-                            EmitPolygonToLayer( hOutLayer, iPixValField, 
-                                                papoPoly[iX], adfGeoTransform );
-                    }
+                    eErr = 
+                        EmitPolygonToLayer( hOutLayer, iPixValField, 
+                                            papoPoly[iX], adfGeoTransform );
+
                     delete papoPoly[iX];
                     papoPoly[iX] = NULL;
                 }
@@ -741,13 +736,10 @@ GDALPolygonize( GDALRasterBandH hSrcBand,
     {
         if( papoPoly[iX] )
         {
-            if( hMaskBand == NULL
-                || papoPoly[iX]->nPolyValue != GP_NODATA_MARKER )
-            {
-                eErr = 
-                    EmitPolygonToLayer( hOutLayer, iPixValField, 
-                                        papoPoly[iX], adfGeoTransform );
-            }
+            eErr = 
+                EmitPolygonToLayer( hOutLayer, iPixValField, 
+                                    papoPoly[iX], adfGeoTransform );
+
             delete papoPoly[iX];
             papoPoly[iX] = NULL;
         }
diff --git a/alg/rasterfill.cpp b/alg/rasterfill.cpp
index 951d7ab..e76f103 100644
--- a/alg/rasterfill.cpp
+++ b/alg/rasterfill.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rasterfill.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: rasterfill.cpp 28342 2015-01-22 12:31:07Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Interpolate in nodata areas.
@@ -7,7 +7,7 @@
  *
  ******************************************************************************
  * Copyright (c) 2008, Frank Warmerdam
- * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2015, Sean Gillies <sean at mapbox.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -26,13 +26,13 @@
  * 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.
- ****************************************************************************/
+ ***************************************************************************/
 
 #include "gdal_alg.h"
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: rasterfill.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: rasterfill.cpp 28342 2015-01-22 12:31:07Z rouault $");
 
 /************************************************************************/
 /*                           GDALFilterLine()                           */
@@ -377,8 +377,8 @@ if( quad_value != nNoDataVal ) 						\
  * @param bDeprecatedOption unused argument, should be zero.
  * @param nSmoothingIterations the number of 3x3 smoothing filter passes to 
  * run (0 or more).
- * @param papszOptions additional name=value options in a string list (none 
- * supported at this time - just pass NULL).
+ * @param papszOptions additional name=value options in a string list (the
+ * temporary file driver can be specified like TEMP_FILE_DRIVER=MEM).
  * @param pfnProgress the progress function to report completion.
  * @param pProgressArg callback data for progress function.
  * 
@@ -386,13 +386,13 @@ if( quad_value != nNoDataVal ) 						\
  */
 
 CPLErr CPL_STDCALL
-GDALFillNodata( GDALRasterBandH hTargetBand, 
+GDALFillNodata( GDALRasterBandH hTargetBand,
                 GDALRasterBandH hMaskBand,
-                double dfMaxSearchDist, 
-                CPL_UNUSED int bDeprecatedOption,
+                double dfMaxSearchDist,
+                int bDeprecatedOption,
                 int nSmoothingIterations,
-                CPL_UNUSED char **papszOptions,
-                GDALProgressFunc pfnProgress, 
+                char **papszOptions,
+                GDALProgressFunc pfnProgress,
                 void * pProgressArg )
 
 {
@@ -441,28 +441,52 @@ GDALFillNodata( GDALRasterBandH hTargetBand,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Create a work file to hold the Y "last value" indices.          */
+/*      Determine format driver for temp work files.                    */
 /* -------------------------------------------------------------------- */
-    GDALDriverH  hDriver = GDALGetDriverByName( "GTiff" );
+    CPLString osTmpFileDriver = CSLFetchNameValueDef(
+            papszOptions, "TEMP_FILE_DRIVER", "GTiff");
+    GDALDriverH hDriver = GDALGetDriverByName((const char *) osTmpFileDriver);
+
     if (hDriver == NULL)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
-                 "GDALFillNodata needs GTiff driver");
+                 "Given driver is not registered");
         return CE_Failure;
     }
-    
+
+    if (GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE, NULL) == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Given driver is incapable of creating temp work files");
+        return CE_Failure;
+    }
+
+    char **papszWorkFileOptions = NULL;
+    if (osTmpFileDriver == "GTiff") {
+        papszWorkFileOptions = CSLSetNameValue(
+                papszWorkFileOptions, "COMPRESS", "LZW");
+        papszWorkFileOptions = CSLSetNameValue(
+                papszWorkFileOptions, "BIGTIFF", "IF_SAFER");
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create a work file to hold the Y "last value" indices.          */
+/* -------------------------------------------------------------------- */
     GDALDatasetH hYDS;
     GDALRasterBandH hYBand;
-    static const char *apszOptions[] = { "COMPRESS=LZW", "BIGTIFF=IF_SAFER", 
-                                         NULL };
+
     CPLString osTmpFile = CPLGenerateTempFilename("");
     CPLString osYTmpFile = osTmpFile + "fill_y_work.tif";
-    
-    hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1, 
-                       eType, (char **) apszOptions );
-    
-    if( hYDS == NULL )
+
+    hYDS = GDALCreate( hDriver, osYTmpFile, nXSize, nYSize, 1,
+                       eType, (char **) papszWorkFileOptions );
+
+    if ( hYDS == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+            "Could not create Y index work file. Check driver capabilities.");
         return CE_Failure;
+    }
 
     hYBand = GDALGetRasterBand( hYDS, 1 );
 
@@ -476,10 +500,14 @@ GDALFillNodata( GDALRasterBandH hTargetBand,
 
     hValDS = GDALCreate( hDriver, osValTmpFile, nXSize, nYSize, 1,
                          GDALGetRasterDataType( hTargetBand ), 
-                         (char **) apszOptions );
-    
-    if( hValDS == NULL )
+                         (char **) papszWorkFileOptions );
+
+    if ( hValDS == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+            "Could not create XY value work file. Check driver capabilities.");
         return CE_Failure;
+    }
 
     hValBand = GDALGetRasterBand( hValDS, 1 );
 
@@ -490,13 +518,17 @@ GDALFillNodata( GDALRasterBandH hTargetBand,
     GDALDatasetH hFiltMaskDS;
     GDALRasterBandH hFiltMaskBand;
     CPLString osFiltMaskTmpFile = osTmpFile + "fill_filtmask_work.tif";
-    
+
     hFiltMaskDS = 
         GDALCreate( hDriver, osFiltMaskTmpFile, nXSize, nYSize, 1,
-                    GDT_Byte, (char **) apszOptions );
-    
-    if( hFiltMaskDS == NULL )
+                    GDT_Byte, (char **) papszWorkFileOptions );
+
+    if ( hFiltMaskDS == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+            "Could not create mask work file. Check driver capabilities.");
         return CE_Failure;
+    }
 
     hFiltMaskBand = GDALGetRasterBand( hFiltMaskDS, 1 );
 
@@ -844,6 +876,8 @@ end:
     GDALClose( hValDS );
     GDALClose( hFiltMaskDS );
 
+    CSLDestroy(papszWorkFileOptions);
+
     GDALDeleteDataset( hDriver, osYTmpFile );
     GDALDeleteDataset( hDriver, osValTmpFile );
     GDALDeleteDataset( hDriver, osFiltMaskTmpFile );
diff --git a/alg/thinplatespline.cpp b/alg/thinplatespline.cpp
index 79b7a84..5bbb5ab 100644
--- a/alg/thinplatespline.cpp
+++ b/alg/thinplatespline.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: thinplatespline.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: thinplatespline.cpp 27546 2014-07-22 22:40:02Z rouault $
  *
  * Project:  GDAL Warp API
  * Purpose:  Implemenentation of 2D Thin Plate Spline transformer. 
@@ -471,7 +471,7 @@ int VizGeorefSpline2D::solve(void)
     
     if( _nof_eqs > INT_MAX / _nof_eqs )
     {
-        fprintf(stderr, "Too many coefficients. Computation aborted.\n");
+        CPLError(CE_Failure, CPLE_AppDefined, "Too many coefficients. Computation aborted.");
         return 0;
     }
 	
@@ -480,7 +480,7 @@ int VizGeorefSpline2D::solve(void)
     
     if( _AA == NULL || _Ainv == NULL )
     {
-        fprintf(stderr, "Out-of-memory while allocating temporary arrays. Computation aborted.\n");
+        CPLError(CE_Failure, CPLE_AppDefined, "Out-of-memory while allocating temporary arrays. Computation aborted.");
         VSIFree(_AA);
         VSIFree(_Ainv);
         return 0;
@@ -531,14 +531,22 @@ int VizGeorefSpline2D::solve(void)
         for(row = 0; row < _nof_eqs; row++)
             for(col = 0; col < _nof_vars; col++)
                 matRHS.at(row, col) = rhs[col][row];
-        arma::mat matCoefs(arma::solve(matA, matRHS));
-        for(row = 0; row < _nof_eqs; row++)
-            for(col = 0; col < _nof_vars; col++)
-                coef[col][row] = matCoefs.at(row, col);
+        arma::mat matCoefs(_nof_vars, _nof_eqs);
+        if( !arma::solve(matCoefs, matA, matRHS) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
+            ret = 0;
+        }
+        else
+        {
+            for(row = 0; row < _nof_eqs; row++)
+                for(col = 0; col < _nof_vars; col++)
+                    coef[col][row] = matCoefs.at(row, col);
+        }
     }
     catch(...)
     {
-        fprintf(stderr, "There is a problem to invert the interpolation matrix\n");
+        CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
         ret = 0;
     }
 #else
@@ -547,7 +555,7 @@ int VizGeorefSpline2D::solve(void)
 			
     if ( !status )
     {
-        fprintf(stderr, " There is a problem to invert the interpolation matrix\n");
+        CPLError(CE_Failure, CPLE_AppDefined, "There is a problem to invert the interpolation matrix.");
         ret = 0;
     }
     else
@@ -699,7 +707,7 @@ static int matrixInvert( int N, double input[], double output[] )
 	
     if (temp == 0) {
 		
-        fprintf(stderr, "matrixInvert(): ERROR - memory allocation failed.\n");
+        CPLError(CE_Failure, CPLE_AppDefined, "matrixInvert(): ERROR - memory allocation failed.");
         return false;
     }
 	
diff --git a/apps/GNUmakefile b/apps/GNUmakefile
index f9950df..8eb6387 100644
--- a/apps/GNUmakefile
+++ b/apps/GNUmakefile
@@ -4,13 +4,14 @@
 
 include ../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I$(GDAL_ROOT)/frmts/vrt $(CPPFLAGS)
-LNK_FLAGS   :=  $(LDFLAGS)
-DEP_LIBS	=	$(EXE_DEP_LIBS) $(XTRAOBJ)
-BIN_LIST	=	gdalinfo$(EXE) gdalserver$(EXE) gdal_translate$(EXE) gdaladdo$(EXE) \
-			gdalwarp$(EXE) nearblack$(EXE) gdalmanage$(EXE) \
-			gdalenhance$(EXE) gdaltransform$(EXE) gdaldem$(EXE) \
-			gdallocationinfo$(EXE) gdalsrsinfo$(EXE) 
+CPPFLAGS :=	-I$(GDAL_ROOT)/frmts/vrt $(CPPFLAGS)
+LNK_FLAGS :=	$(LDFLAGS)
+DEP_LIBS =	$(EXE_DEP_LIBS) $(XTRAOBJ)
+
+BIN_LIST =	gdalinfo$(EXE) gdalserver$(EXE) gdal_translate$(EXE) \
+		gdaladdo$(EXE) gdalwarp$(EXE) nearblack$(EXE) gdalmanage$(EXE) \
+		gdalenhance$(EXE) gdaltransform$(EXE) gdaldem$(EXE) \
+		gdallocationinfo$(EXE) gdalsrsinfo$(EXE) 
 
 ifeq ($(OGR_ENABLED),yes)
 BIN_LIST += 	gdal_contour$(EXE) \
@@ -20,19 +21,19 @@ BIN_LIST += 	gdal_contour$(EXE) \
 		ogrinfo$(EXE) \
 		ogr2ogr$(EXE) \
 		ogrtindex$(EXE) \
-        ogrlineref$(EXE) \
+		ogrlineref$(EXE) \
 		testepsg$(EXE) \
 		gdalbuildvrt$(EXE)
 endif
 
 ifeq ($(HAVE_GEOS),yes)
-CPPFLAGS 	:=	-DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS)
+CPPFLAGS 	:=	$(CPPFLAGS) -DHAVE_GEOS=1 $(GEOS_CFLAGS)
 endif
 
-NON_DEFAULT_LIST = 	multireadtest$(EXE) \
-			dumpoverviews$(EXE) gdalwarpsimple$(EXE) gdalflattenmask$(EXE) \
-			gdaltorture$(EXE) gdal2ogr$(EXE) test_ogrsf$(EXE) \
-			gdalasyncread$(EXE) testreprojmulti$(EXE)
+NON_DEFAULT_LIST = 	multireadtest$(EXE) dumpoverviews$(EXE) \
+	gdalwarpsimple$(EXE) gdalflattenmask$(EXE) \
+	gdaltorture$(EXE) gdal2ogr$(EXE) test_ogrsf$(EXE) \
+	gdalasyncread$(EXE) testreprojmulti$(EXE)
 
 default:	gdal-config-inst gdal-config $(BIN_LIST)
 
diff --git a/apps/commonutils.cpp b/apps/commonutils.cpp
index 4644671..3d10e86 100644
--- a/apps/commonutils.cpp
+++ b/apps/commonutils.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: commonutils.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: commonutils.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Common utility routines
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2011-2012, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2011-2012, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include "gdal.h"
 
-CPL_CVSID("$Id: commonutils.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: commonutils.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /* -------------------------------------------------------------------- */
 /*                      CheckExtensionConsistency()                     */
@@ -54,23 +54,32 @@ void CheckExtensionConsistency(const char* pszDestFilename,
         for(int i=0;i<nDriverCount;i++)
         {
             GDALDriverH hDriver = GDALGetDriver(i);
-            const char* pszDriverExtension = 
-                GDALGetMetadataItem( hDriver, GDAL_DMD_EXTENSION, NULL );   
-            if (pszDriverExtension && EQUAL(pszDestExtension, pszDriverExtension))
+            const char* pszDriverExtensions = 
+                GDALGetMetadataItem( hDriver, GDAL_DMD_EXTENSIONS, NULL );
+            if( pszDriverExtensions )
             {
-                if (GDALGetDriverByName(pszDriverName) != hDriver)
+                char** papszTokens = CSLTokenizeString( pszDriverExtensions );
+                for(int j=0; papszTokens[j]; j++)
                 {
-                    if (osConflictingDriverList.size())
-                        osConflictingDriverList += ", ";
-                    osConflictingDriverList += GDALGetDriverShortName(hDriver);
-                }
-                else
-                {
-                    /* If the request driver allows the used extension, then */
-                    /* just stop iterating now */
-                    osConflictingDriverList = "";
-                    break;
+                    const char* pszDriverExtension = papszTokens[j];
+                    if (EQUAL(pszDestExtension, pszDriverExtension))
+                    {
+                        if (GDALGetDriverByName(pszDriverName) != hDriver)
+                        {
+                            if (osConflictingDriverList.size())
+                                osConflictingDriverList += ", ";
+                            osConflictingDriverList += GDALGetDriverShortName(hDriver);
+                        }
+                        else
+                        {
+                            /* If the request driver allows the used extension, then */
+                            /* just stop iterating now */
+                            osConflictingDriverList = "";
+                            break;
+                        }
+                    }
                 }
+                CSLDestroy(papszTokens);
             }
         }
         if (osConflictingDriverList.size())
@@ -109,5 +118,10 @@ void EarlySetConfigOptions( int argc, char ** argv )
 
             i += 2;
         }
+        else if( EQUAL(argv[i],"--debug") && i + 1 < argc )
+        {
+            CPLSetConfigOption( "CPL_DEBUG", argv[i+1] );
+            i += 1;
+        }
     }
 }
diff --git a/apps/gdal_contour.cpp b/apps/gdal_contour.cpp
index e018801..cb47694 100644
--- a/apps/gdal_contour.cpp
+++ b/apps/gdal_contour.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_contour.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: gdal_contour.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Contour Generator
  * Purpose:  Contour Generator mainline.
@@ -35,7 +35,7 @@
 #include "ogr_api.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: gdal_contour.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: gdal_contour.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                            ArgIsNumeric()                            */
@@ -129,12 +129,12 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-off") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            dfOffset = atof(argv[++i]);
+            dfOffset = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i],"-i") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            dfInterval = atof(argv[++i]);
+            dfInterval = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i],"-fl") )
         {
@@ -144,7 +144,7 @@ int main( int argc, char ** argv )
                    && nFixedLevelCount 
                              < (int)(sizeof(adfFixedLevels)/sizeof(double))
                    && ArgIsNumeric(argv[i+1]) )
-                adfFixedLevels[nFixedLevelCount++] = atof(argv[++i]);
+                adfFixedLevels[nFixedLevelCount++] = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i],"-b") )
         {
@@ -174,7 +174,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             bNoDataSet = TRUE;
-            dfNoData = atof(argv[++i]);
+            dfNoData = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i],"-nln") )
         {
diff --git a/apps/gdal_grid.cpp b/apps/gdal_grid.cpp
index c4911ab..06fc474 100644
--- a/apps/gdal_grid.cpp
+++ b/apps/gdal_grid.cpp
@@ -1,5 +1,5 @@
 /* ****************************************************************************
- * $Id: gdal_grid.cpp 27128 2014-04-05 12:59:03Z rouault $
+ * $Id: gdal_grid.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  GDAL scattered data gridding (interpolation) tool
@@ -40,7 +40,7 @@
 #include "gdalgrid.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: gdal_grid.cpp 27128 2014-04-05 12:59:03Z rouault $");
+CPL_CVSID("$Id: gdal_grid.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                               Usage()                                */
@@ -103,7 +103,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
     {
         case GGA_InverseDistanceToAPower:
             printf( "Algorithm name: \"%s\".\n", szAlgNameInvDist );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"power=%f:smoothing=%f:radius1=%f:radius2=%f:angle=%f"
                     ":max_points=%lu:min_points=%lu:nodata=%f\"\n",
                 ((GDALGridInverseDistanceToAPowerOptions *)pOptions)->dfPower,
@@ -117,7 +117,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MovingAverage:
             printf( "Algorithm name: \"%s\".\n", szAlgNameAverage );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridMovingAverageOptions *)pOptions)->dfRadius1,
@@ -128,7 +128,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_NearestNeighbor:
             printf( "Algorithm name: \"%s\".\n", szAlgNameNearest );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:nodata=%f\"\n",
                 ((GDALGridNearestNeighborOptions *)pOptions)->dfRadius1,
                 ((GDALGridNearestNeighborOptions *)pOptions)->dfRadius2,
@@ -137,7 +137,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricMinimum:
             printf( "Algorithm name: \"%s\".\n", szAlgNameMinimum );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -148,7 +148,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricMaximum:
             printf( "Algorithm name: \"%s\".\n", szAlgNameMaximum );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -159,7 +159,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricRange:
             printf( "Algorithm name: \"%s\".\n", szAlgNameRange );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -170,7 +170,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricCount:
             printf( "Algorithm name: \"%s\".\n", szAlgNameCount );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -181,7 +181,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricAverageDistance:
             printf( "Algorithm name: \"%s\".\n", szAlgNameAverageDistance );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -192,7 +192,7 @@ static void PrintAlgorithmAndOptions( GDALGridAlgorithm eAlgorithm,
             break;
         case GGA_MetricAverageDistancePts:
             printf( "Algorithm name: \"%s\".\n", szAlgNameAverageDistancePts );
-            printf( "Options are "
+            CPLprintf( "Options are "
                     "\"radius1=%f:radius2=%f:angle=%f:min_points=%lu"
                     ":nodata=%f\"\n",
                 ((GDALGridDataMetricsOptions *)pOptions)->dfRadius1,
@@ -415,10 +415,10 @@ static CPLErr ProcessLayer( OGRLayerH hSrcLayer, GDALDatasetH hDstDS,
         printf( "Grid data type is \"%s\"\n", GDALGetDataTypeName(eType) );
         printf( "Grid size = (%lu %lu).\n",
                 (unsigned long)nXSize, (unsigned long)nYSize );
-        printf( "Corner coordinates = (%f %f)-(%f %f).\n",
+        CPLprintf( "Corner coordinates = (%f %f)-(%f %f).\n",
                 dfXMin - dfDeltaX / 2, dfYMax + dfDeltaY / 2,
                 dfXMax + dfDeltaX / 2, dfYMin - dfDeltaY / 2 );
-        printf( "Grid cell size = (%f %f).\n", dfDeltaX, dfDeltaY );
+        CPLprintf( "Grid cell size = (%f %f).\n", dfDeltaX, dfDeltaY );
         printf( "Source point count = %lu.\n", (unsigned long)adfX.size() );
         PrintAlgorithmAndOptions( eAlgorithm, pOptions );
         printf("\n");
@@ -524,12 +524,12 @@ static OGRGeometryCollection* LoadGeometry( const char* pszDS,
                                             const char* pszLyr,
                                             const char* pszWhere )
 {
-    OGRDataSource       *poDS;
+    GDALDataset         *poDS;
     OGRLayer            *poLyr;
     OGRFeature          *poFeat;
     OGRGeometryCollection *poGeom = NULL;
         
-    poDS = OGRSFDriverRegistrar::Open( pszDS, FALSE );
+    poDS = (GDALDataset*) GDALOpen( pszDS, GA_ReadOnly );
     if ( poDS == NULL )
         return NULL;
 
@@ -544,7 +544,7 @@ static OGRGeometryCollection* LoadGeometry( const char* pszDS,
     {
         fprintf( stderr,
             "FAILURE: Failed to identify source layer from datasource.\n" );
-        OGRDataSource::DestroyDataSource( poDS );
+        GDALClose( (GDALDatasetH) poDS );
         return NULL;
     }
     
@@ -583,7 +583,7 @@ static OGRGeometryCollection* LoadGeometry( const char* pszDS,
                 OGRFeature::DestroyFeature( poFeat );
                 if ( pszSQL != NULL )
                     poDS->ReleaseResultSet( poLyr );
-                OGRDataSource::DestroyDataSource( poDS );
+                GDALClose( (GDALDatasetH) poDS );
                 return NULL;
             }
         }
@@ -593,7 +593,7 @@ static OGRGeometryCollection* LoadGeometry( const char* pszDS,
     
     if( pszSQL != NULL )
         poDS->ReleaseResultSet( poLyr );
-    OGRDataSource::DestroyDataSource( poDS );
+    GDALClose( (GDALDatasetH) poDS );
     
     return poGeom;
 }
@@ -634,6 +634,8 @@ int main( int argc, char ** argv )
     const char      *pszClipSrcSQL = NULL;
     const char      *pszClipSrcLayer = NULL;
     const char      *pszClipSrcWhere = NULL;
+    int              bNoDataSet = FALSE;
+    double           dfNoDataValue = 0;
 
     /* Check strict compilation and runtime library version as we use C++ API */
     if (! GDAL_CHECK_VERSION(argv[0]))
@@ -698,16 +700,16 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-txe") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2);
-            dfXMin = atof(argv[++i]);
-            dfXMax = atof(argv[++i]);
+            dfXMin = CPLAtof(argv[++i]);
+            dfXMax = CPLAtof(argv[++i]);
             bIsXExtentSet = TRUE;
         }   
 
         else if( EQUAL(argv[i],"-tye") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2);
-            dfYMin = atof(argv[++i]);
-            dfYMax = atof(argv[++i]);
+            dfYMin = CPLAtof(argv[++i]);
+            dfYMax = CPLAtof(argv[++i]);
             bIsYExtentSet = TRUE;
         }   
 
@@ -733,13 +735,13 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-z_increase") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            dfIncreaseBurnValue = atof(argv[++i]);
+            dfIncreaseBurnValue = CPLAtof(argv[++i]);
         }
 
         else if( EQUAL(argv[i],"-z_multiply") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            dfMultiplyBurnValue = atof(argv[++i]);
+            dfMultiplyBurnValue = CPLAtof(argv[++i]);
         }
 
         else if( EQUAL(argv[i],"-where") )
@@ -765,11 +767,11 @@ int main( int argc, char ** argv )
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
             OGRLinearRing  oRing;
 
-            oRing.addPoint( atof(argv[i+1]), atof(argv[i+2]) );
-            oRing.addPoint( atof(argv[i+1]), atof(argv[i+4]) );
-            oRing.addPoint( atof(argv[i+3]), atof(argv[i+4]) );
-            oRing.addPoint( atof(argv[i+3]), atof(argv[i+2]) );
-            oRing.addPoint( atof(argv[i+1]), atof(argv[i+2]) );
+            oRing.addPoint( CPLAtof(argv[i+1]), CPLAtof(argv[i+2]) );
+            oRing.addPoint( CPLAtof(argv[i+1]), CPLAtof(argv[i+4]) );
+            oRing.addPoint( CPLAtof(argv[i+3]), CPLAtof(argv[i+4]) );
+            oRing.addPoint( CPLAtof(argv[i+3]), CPLAtof(argv[i+2]) );
+            oRing.addPoint( CPLAtof(argv[i+1]), CPLAtof(argv[i+2]) );
 
             poSpatialFilter = new OGRPolygon();
             ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
@@ -791,11 +793,11 @@ int main( int argc, char ** argv )
             {
                 OGRLinearRing  oRing;
 
-                oRing.addPoint( atof(argv[i + 1]), atof(argv[i + 2]) );
-                oRing.addPoint( atof(argv[i + 1]), atof(argv[i + 4]) );
-                oRing.addPoint( atof(argv[i + 3]), atof(argv[i + 4]) );
-                oRing.addPoint( atof(argv[i + 3]), atof(argv[i + 2]) );
-                oRing.addPoint( atof(argv[i + 1]), atof(argv[i + 2]) );
+                oRing.addPoint( CPLAtof(argv[i + 1]), CPLAtof(argv[i + 2]) );
+                oRing.addPoint( CPLAtof(argv[i + 1]), CPLAtof(argv[i + 4]) );
+                oRing.addPoint( CPLAtof(argv[i + 3]), CPLAtof(argv[i + 4]) );
+                oRing.addPoint( CPLAtof(argv[i + 3]), CPLAtof(argv[i + 2]) );
+                oRing.addPoint( CPLAtof(argv[i + 1]), CPLAtof(argv[i + 2]) );
 
                 poClipSrc = new OGRPolygon();
                 ((OGRPolygon *) poClipSrc)->addRing( &oRing );
@@ -866,13 +868,23 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-a") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            if ( ParseAlgorithmAndOptions( argv[++i], &eAlgorithm, &pOptions )
+            const char* pszAlgorithm = argv[++i];
+            if ( ParseAlgorithmAndOptions( pszAlgorithm, &eAlgorithm, &pOptions )
                  != CE_None )
             {
                 fprintf( stderr,
                          "Failed to process algorithm name and parameters.\n" );
                 exit( 1 );
             }
+            
+            char **papszParms = CSLTokenizeString2( pszAlgorithm, ":", FALSE );
+            const char* pszNoDataValue = CSLFetchNameValue( papszParms, "nodata" );
+            if( pszNoDataValue != NULL )
+            {
+                bNoDataSet = TRUE;
+                dfNoDataValue = CPLAtofM(pszNoDataValue);
+            }
+            CSLDestroy(papszParms);
         }
 
         else if( argv[i][0] == '-' )
@@ -966,9 +978,9 @@ int main( int argc, char ** argv )
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
 
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
-                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
-                                        NULL ) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                ( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
             {
                 fprintf( stderr, "  %s: %s\n",
                          GDALGetDriverShortName( hDriver  ),
@@ -1021,6 +1033,15 @@ int main( int argc, char ** argv )
         fprintf( stderr, "%s\n", CPLGetLastErrorMsg() );
         exit( 3 );
     }
+    
+    if( bNoDataSet )
+    {
+        for( i = 1; i <= nBands; i++ )
+        {
+            GDALRasterBandH hBand = GDALGetRasterBand( hDstDS, i );
+            GDALSetRasterNoDataValue( hBand, dfNoDataValue );
+        }
+    }
 
 /* -------------------------------------------------------------------- */
 /*      If algorithm was not specified assigh default one.              */
diff --git a/apps/gdal_rasterize.cpp b/apps/gdal_rasterize.cpp
index 263861c..b9c6515 100644
--- a/apps/gdal_rasterize.cpp
+++ b/apps/gdal_rasterize.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_rasterize.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal_rasterize.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Rasterize OGR shapes into a GDAL raster.
@@ -37,7 +37,7 @@
 #include "commonutils.h"
 #include <vector>
 
-CPL_CVSID("$Id: gdal_rasterize.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdal_rasterize.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /*                            ArgIsNumeric()                            */
@@ -58,7 +58,7 @@ static void Usage()
 {
     printf( 
         "Usage: gdal_rasterize [-b band]* [-i] [-at]\n"
-        "       [-burn value]* | [-a attribute_name] [-3d]\n"
+        "       [-burn value]* | [-a attribute_name] [-3d] [-add]\n"
         "       [-l layername]* [-where expression] [-sql select_statement]\n"
         "       [-of format] [-a_srs srs_def] [-co \"NAME=VALUE\"]*\n"
         "       [-a_nodata value] [-init value]*\n"
@@ -341,7 +341,7 @@ GDALDatasetH CreateOutputDataset(std::vector<OGRLayerH> ahLayers,
             }
 
             /* When rasterizing point layers and that the bounds have */
-            /* not been explicitely set, voluntary increase the extent by */
+            /* not been explicitly set, voluntary increase the extent by */
             /* a half-pixel size to avoid missing points on the border */
             if (wkbFlatten(OGR_L_GetGeomType(hLayer)) == wkbPoint &&
                 !bTargetAlignedPixels && dfXRes != 0 && dfYRes != 0)
@@ -479,7 +479,7 @@ int main( int argc, char ** argv )
     double dfXRes = 0, dfYRes = 0;
     int bCreateOutput = FALSE;
     const char* pszFormat = "GTiff";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     char **papszCreateOptions = NULL;
     GDALDriverH hDriver = NULL;
     GDALDataType eOutputType = GDT_Float64;
@@ -560,6 +560,17 @@ int main( int argc, char ** argv )
             papszRasterizeOptions = 
                 CSLSetNameValue( papszRasterizeOptions, "BURN_VALUE_FROM", "Z");
         }
+        else if( EQUAL(argv[i],"-add")  )
+        {
+            papszRasterizeOptions = 
+                CSLSetNameValue( papszRasterizeOptions, "MERGE_ALG", "ADD");
+        }
+        else if( EQUAL(argv[i],"-chunkysize") && i < argc-1 )
+        {
+            papszRasterizeOptions = 
+                CSLSetNameValue( papszRasterizeOptions, "CHUNKYSIZE", 
+                                 argv[++i] );
+        }
         else if( EQUAL(argv[i],"-i")  )
         {
             bInverse = TRUE;
@@ -577,7 +588,7 @@ int main( int argc, char ** argv )
                 char** papszIter = papszTokens;
                 while(papszIter && *papszIter)
                 {
-                    adfBurnValues.push_back(atof(*papszIter));
+                    adfBurnValues.push_back(CPLAtof(*papszIter));
                     papszIter ++;
                 }
                 CSLDestroy(papszTokens);
@@ -587,7 +598,7 @@ int main( int argc, char ** argv )
             {
                 while(i < argc-1 && ArgIsNumeric(argv[i+1]))
                 {
-                    adfBurnValues.push_back(atof(argv[i+1]));
+                    adfBurnValues.push_back(CPLAtof(argv[i+1]));
                     i += 1;
                 }
             }
@@ -607,7 +618,7 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-of") && i < argc-1 )
         {
             pszFormat = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
             bCreateOutput = TRUE;
         }
         else if( EQUAL(argv[i],"-init") && i < argc - 1 )
@@ -618,7 +629,7 @@ int main( int argc, char ** argv )
                 char** papszIter = papszTokens;
                 while(papszIter && *papszIter)
                 {
-                    adfInitVals.push_back(atof(*papszIter));
+                    adfInitVals.push_back(CPLAtof(*papszIter));
                     papszIter ++;
                 }
                 CSLDestroy(papszTokens);
@@ -628,7 +639,7 @@ int main( int argc, char ** argv )
             {
                 while(i < argc-1 && ArgIsNumeric(argv[i+1]))
                 {
-                    adfInitVals.push_back(atof(argv[i+1]));
+                    adfInitVals.push_back(CPLAtof(argv[i+1]));
                     i += 1;
                 }
             }
@@ -636,7 +647,7 @@ int main( int argc, char ** argv )
         }
         else if( EQUAL(argv[i],"-a_nodata") && i < argc - 1 )
         {
-            dfNoData = atof(argv[i+1]);
+            dfNoData = CPLAtof(argv[i+1]);
             bNoDataSet = TRUE;
             i += 1;
             bCreateOutput = TRUE;
@@ -658,19 +669,19 @@ int main( int argc, char ** argv )
 
         else if( EQUAL(argv[i],"-te") && i < argc - 4 )
         {
-            sEnvelop.MinX = atof(argv[++i]);
-            sEnvelop.MinY = atof(argv[++i]);
-            sEnvelop.MaxX = atof(argv[++i]);
-            sEnvelop.MaxY = atof(argv[++i]);
+            sEnvelop.MinX = CPLAtof(argv[++i]);
+            sEnvelop.MinY = CPLAtof(argv[++i]);
+            sEnvelop.MaxX = CPLAtof(argv[++i]);
+            sEnvelop.MaxY = CPLAtof(argv[++i]);
             bGotBounds = TRUE;
             bCreateOutput = TRUE;
         }
         else if( EQUAL(argv[i],"-a_ullr") && i < argc - 4 )
         {
-            sEnvelop.MinX = atof(argv[++i]);
-            sEnvelop.MaxY = atof(argv[++i]);
-            sEnvelop.MaxX = atof(argv[++i]);
-            sEnvelop.MinY = atof(argv[++i]);
+            sEnvelop.MinX = CPLAtof(argv[++i]);
+            sEnvelop.MaxY = CPLAtof(argv[++i]);
+            sEnvelop.MaxX = CPLAtof(argv[++i]);
+            sEnvelop.MinY = CPLAtof(argv[++i]);
             bGotBounds = TRUE;
             bCreateOutput = TRUE;
         }
@@ -714,8 +725,8 @@ int main( int argc, char ** argv )
         }
         else if( EQUAL(argv[i],"-tr") && i < argc-2 )
         {
-            dfXRes = atof(argv[++i]);
-            dfYRes = fabs(atof(argv[++i]));
+            dfXRes = CPLAtof(argv[++i]);
+            dfYRes = fabs(CPLAtof(argv[++i]));
             if( dfXRes == 0 || dfYRes == 0 )
             {
                 printf( "Wrong value for -tr parameters\n");
@@ -859,7 +870,7 @@ int main( int argc, char ** argv )
             exit( 1 );
         }
 
-        if (!bQuiet && !bFormatExplicitelySet)
+        if (!bQuiet && !bFormatExplicitlySet)
             CheckExtensionConsistency(pszDstFilename, pszFormat);
     }
     else
diff --git a/apps/gdal_translate.cpp b/apps/gdal_translate.cpp
index 22747e4..354a701 100644
--- a/apps/gdal_translate.cpp
+++ b/apps/gdal_translate.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_translate.cpp 27994 2014-11-21 20:03:49Z rouault $
+ * $Id: gdal_translate.cpp 29144 2015-05-04 09:22:47Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  GDAL Image Translator Program
@@ -36,7 +36,7 @@
 #include "vrtdataset.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: gdal_translate.cpp 27994 2014-11-21 20:03:49Z rouault $");
+CPL_CVSID("$Id: gdal_translate.cpp 29144 2015-05-04 09:22:47Z rouault $");
 
 static int ArgIsNumeric( const char * );
 static void AttachMetadata( GDALDatasetH, char ** );
@@ -57,13 +57,16 @@ static void Usage(const char* pszErrorMsg = NULL, int bShort = TRUE)
             "       [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/\n"
             "             CInt16/CInt32/CFloat32/CFloat64}] [-strict]\n"
             "       [-of format] [-b band] [-mask band] [-expand {gray|rgb|rgba}]\n"
-            "       [-outsize xsize[%%] ysize[%%]]\n"
+            "       [-outsize xsize[%%]|0 ysize[%%]|0] [-tr xres yres]\n"
+            "       [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]\n"
             "       [-unscale] [-scale[_bn] [src_min src_max [dst_min dst_max]]]* [-exponent[_bn] exp_val]*\n"
-            "       [-srcwin xoff yoff xsize ysize] [-projwin ulx uly lrx lry] [-epo] [-eco]\n"
+            "       [-srcwin xoff yoff xsize ysize] [-epo] [-eco]\n"
+            "       [-projwin ulx uly lrx lry] [-projwin_srs srs_def]\n"
             "       [-a_srs srs_def] [-a_ullr ulx uly lrx lry] [-a_nodata value]\n"
             "       [-gcp pixel line easting northing [elevation]]*\n" 
             "       [-mo \"META-TAG=VALUE\"]* [-q] [-sds]\n"
             "       [-co \"NAME=VALUE\"]* [-stats] [-norat]\n"
+            "       [-oo NAME=VALUE]*\n"
             "       src_dataset dst_dataset\n" );
 
     if( !bShort )
@@ -74,9 +77,9 @@ static void Usage(const char* pszErrorMsg = NULL, int bShort = TRUE)
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
             
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
-                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
-                                        NULL ) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
             {
                 printf( "  %s: %s\n",
                         GDALGetDriverShortName( hDriver ),
@@ -278,7 +281,7 @@ static int ProxyMain( int argc, char ** argv )
     int			i;
     int			nRasterXSize, nRasterYSize;
     const char		*pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     GDALDriverH		hDriver;
     int			*panBandList = NULL; /* negative value of panBandList[i] means mask band of ABS(panBandList[i]) */
     int         nBandCount = 0, bDefBands = TRUE;
@@ -319,7 +322,10 @@ static int ProxyMain( int argc, char ** argv )
     int                 bErrorOnPartiallyOutside = FALSE;
     int                 bErrorOnCompletelyOutside = FALSE;
     int                 bNoRAT = FALSE;
-
+    char              **papszOpenOptions = NULL;
+    const char         *pszResampling = NULL;
+    double              dfXRes = 0.0, dfYRes = 0.0;
+    CPLString           osProjSRS;
 
     anSrcWin[0] = 0;
     anSrcWin[1] = 0;
@@ -344,6 +350,19 @@ static int ProxyMain( int argc, char ** argv )
         exit( -argc );
 
 /* -------------------------------------------------------------------- */
+/*      Set optimal setting for best performance with huge input VRT.   */
+/*      The rationale for 450 is that typical Linux process allow       */
+/*      only 1024 file descriptors per process and we need to keep some */
+/*      spare for shared libraries, etc. so let's go down to 900.       */
+/*      And some datasets may need 2 file descriptors, so divide by 2   */
+/*      for security.                                                   */
+/* -------------------------------------------------------------------- */
+    if( CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", NULL) == NULL )
+    {
+        CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Handle command line arguments.                                  */
 /* -------------------------------------------------------------------- */
     for( i = 1; i < argc; i++ )
@@ -363,7 +382,7 @@ static int ProxyMain( int argc, char ** argv )
         else if( EQUAL(argv[i],"-of") && i < argc-1 )
         {
             pszFormat = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
         }
 
         else if( EQUAL(argv[i],"-q") || EQUAL(argv[i],"-quiet") )
@@ -634,7 +653,18 @@ static int ProxyMain( int argc, char ** argv )
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2);
             pszOXSize = argv[++i];
             pszOYSize = argv[++i];
-        }   
+        }
+        
+        else if( EQUAL(argv[i],"-tr") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(2);
+            dfXRes = CPLAtofM(argv[++i]);
+            dfYRes = fabs(CPLAtofM(argv[++i]));
+            if( dfXRes == 0 || dfYRes == 0 )
+            {
+                Usage("Wrong value for -tr parameters.");
+            }
+        }
 
         else if( EQUAL(argv[i],"-srcwin") )
         {
@@ -653,6 +683,26 @@ static int ProxyMain( int argc, char ** argv )
             dfLRX = CPLAtofM(argv[++i]);
             dfLRY = CPLAtofM(argv[++i]);
         }   
+        
+        else if( EQUAL(argv[i],"-projwin_srs") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            OGRSpatialReference oSRS;
+
+            if( oSRS.SetFromUserInput( argv[i+1] ) != OGRERR_NONE )
+            {
+                fprintf( stderr, "Failed to process SRS definition: %s\n", 
+                         argv[i+1] );
+                GDALDestroyDriverManager();
+                exit( 1 );
+            }
+
+            char* pszSRS = NULL;
+            oSRS.exportToWkt( &pszSRS );
+            if( pszSRS )
+                osProjSRS = pszSRS;
+            i++;
+        }
 
         else if( EQUAL(argv[i],"-epo") )
         {
@@ -713,6 +763,17 @@ static int ProxyMain( int argc, char ** argv )
         {
             bNoRAT = TRUE;
         }
+        else if( EQUAL(argv[i], "-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                argv[++i] );
+        }
+        else if( EQUAL(argv[i],"-r") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszResampling = argv[++i];
+        }  
         else if( argv[i][0] == '-' )
         {
             Usage(CPLSPrintf("Unknown option name '%s'", argv[i]));
@@ -753,14 +814,27 @@ static int ProxyMain( int argc, char ** argv )
         pfnProgress = GDALDummyProgress;
     }
 
-    if (!bQuiet && !bFormatExplicitelySet)
+    if (!bQuiet && !bFormatExplicitlySet)
         CheckExtensionConsistency(pszDest, pszFormat);
+/* -------------------------------------------------------------------- */
+/*      Check that incompatible options are not used                    */
+/* -------------------------------------------------------------------- */
+
+    if( pszOXSize != NULL && (dfXRes != 0 && dfYRes != 0) )
+    {
+        Usage("-outsize and -tr options cannot be used at the same time.");
+    }
+    if( bGotBounds &&  (dfXRes != 0 && dfYRes != 0) )
+    {
+        Usage("-a_ullr and -tr options cannot be used at the same time.");
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Attempt to open source file.                                    */
 /* -------------------------------------------------------------------- */
 
-    hDataset = GDALOpenShared( pszSource, GA_ReadOnly );
+    hDataset = GDALOpenEx( pszSource, GDAL_OF_RASTER, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
     
     if( hDataset == NULL )
     {
@@ -933,6 +1007,39 @@ static int ProxyMain( int argc, char ** argv )
             exit( 1 );
         }
 
+        if( osProjSRS.size() )
+        {
+            pszProjection = GDALGetProjectionRef( hDataset );
+            if( pszProjection != NULL && strlen(pszProjection) > 0 )
+            {
+                OGRSpatialReference oSRSIn;
+                OGRSpatialReference oSRSDS;
+                oSRSIn.SetFromUserInput(osProjSRS);
+                oSRSDS.SetFromUserInput(pszProjection);
+                if( !oSRSIn.IsSame(&oSRSDS) )
+                {
+                    OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(&oSRSIn, &oSRSDS);
+                    if( !(poCT &&
+                        poCT->Transform(1, &dfULX, &dfULY) &&
+                        poCT->Transform(1, &dfLRX, &dfLRY)) )
+                    {
+                        OGRCoordinateTransformation::DestroyCT(poCT);
+
+                        fprintf( stderr, "-projwin_srs ignored since coordinate transformation failed.\n");
+                        GDALClose( hDataset );
+                        CPLFree( panBandList );
+                        GDALDestroyDriverManager();
+                        exit( 1 );
+                    }
+                    delete poCT;
+                }
+            }
+            else
+            {
+                fprintf( stderr, "-projwin_srs ignored since the dataset has no projection.\n");
+            }
+        }
+
         anSrcWin[0] = (int) 
             floor((dfULX - adfGeoTransform[0]) / adfGeoTransform[1] + 0.001);
         anSrcWin[1] = (int) 
@@ -1008,9 +1115,9 @@ static int ProxyMain( int argc, char ** argv )
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
 
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
-                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
-                                        NULL ) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                 || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
             {
                 printf( "  %s: %s\n",
                         GDALGetDriverShortName( hDriver  ),
@@ -1025,6 +1132,7 @@ static int ProxyMain( int argc, char ** argv )
         GDALDestroyDriverManager();
         CSLDestroy( argv );
         CSLDestroy( papszCreateOptions );
+        CSLDestroy( papszOpenOptions );
         exit( 1 );
     }
 
@@ -1040,7 +1148,7 @@ static int ProxyMain( int argc, char ** argv )
            anSrcWin[0] == 0 && anSrcWin[1] == 0
         && anSrcWin[2] == GDALGetRasterXSize(hDataset)
         && anSrcWin[3] == GDALGetRasterYSize(hDataset)
-        && pszOXSize == NULL && pszOYSize == NULL );
+        && pszOXSize == NULL && pszOYSize == NULL && dfXRes == 0.0 );
 
     if( eOutputType == GDT_Unknown 
         && nScaleRepeat == 0 && nExponentRepeat == 0 && !bUnscale
@@ -1071,6 +1179,7 @@ static int ProxyMain( int argc, char ** argv )
 
         CSLDestroy( argv );
         CSLDestroy( papszCreateOptions );
+        CSLDestroy( papszOpenOptions );
 
         return hOutDS == NULL;
     }
@@ -1078,17 +1187,59 @@ static int ProxyMain( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
 /*      Establish some parameters.                                      */
 /* -------------------------------------------------------------------- */
-    if( pszOXSize == NULL )
+    if( dfXRes != 0.0 )
+    {
+        if( !(GDALGetGeoTransform( hDataset, adfGeoTransform ) == CE_None &&
+              nGCPCount == 0 &&
+              adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0) )
+        {
+            fprintf( stderr, 
+                     "The -tr option was used, but there's no geotransform or it is\n"
+                     "rotated.  This configuration is not supported.\n" );
+            GDALClose( hDataset );
+            CPLFree( panBandList );
+            GDALDestroyDriverManager();
+            exit( 1 );
+        }
+        nOXSize = int(anSrcWin[2] / dfXRes * adfGeoTransform[1] + 0.5);
+        nOYSize = int(anSrcWin[3] / dfYRes * fabs(adfGeoTransform[5]) + 0.5);
+    }
+    else if( pszOXSize == NULL )
     {
         nOXSize = anSrcWin[2];
         nOYSize = anSrcWin[3];
     }
     else
     {
-        nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%' 
-                          ? CPLAtofM(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
-        nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%' 
-                          ? CPLAtofM(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
+        int bXAuto = EQUAL(pszOXSize, "auto") || EQUAL(pszOXSize, "0");
+        int bYAuto = EQUAL(pszOYSize, "auto") || EQUAL(pszOYSize, "0");
+        if( bXAuto && bYAuto )
+        {
+            fprintf(stderr, "-outsize %s %s invalid.\n", pszOXSize, pszOYSize);
+            GDALClose( hDataset );
+            CPLFree( panBandList );
+            GDALDestroyDriverManager();
+            exit( 1 );
+        }
+        if( !bXAuto )
+            nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%' 
+                            ? CPLAtofM(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
+        if( !bYAuto )
+            nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%' 
+                            ? CPLAtofM(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
+        if( bXAuto )
+            nOXSize = (int)((double)nOYSize * anSrcWin[2] / anSrcWin[3] + 0.5);
+        else if( bYAuto )
+            nOYSize = (int)((double)nOXSize * anSrcWin[3] / anSrcWin[2] + 0.5);
+    }
+
+    if( nOXSize == 0 || nOYSize == 0 )
+    {
+        fprintf(stderr, "Attempt to create %dx%d dataset is illegal.\n", nOXSize, nOYSize);
+        GDALClose( hDataset );
+        CPLFree( panBandList );
+        GDALDestroyDriverManager();
+        exit( 1 );
     }
 
 /* ==================================================================== */
@@ -1140,6 +1291,12 @@ static int ProxyMain( int argc, char ** argv )
         adfGeoTransform[4] *= anSrcWin[2] / (double) nOXSize;
         adfGeoTransform[5] *= anSrcWin[3] / (double) nOYSize;
         
+        if( dfXRes != 0.0 )
+        {
+            adfGeoTransform[1] = dfXRes;
+            adfGeoTransform[5] = (adfGeoTransform[5] > 0) ? dfYRes : -dfYRes;
+        }
+
         poVDS->SetGeoTransform( adfGeoTransform );
     }
 
@@ -1239,6 +1396,44 @@ static int ProxyMain( int argc, char ** argv )
         if( papszMD != NULL )
             poVDS->SetMetadata( papszMD, "GEOLOCATION" );
     }
+    else
+    {
+        char **papszMD;
+
+        papszMD = ((GDALDataset*)hDataset)->GetMetadata("RPC");
+        if( papszMD != NULL )
+        {
+            papszMD = CSLDuplicate(papszMD);
+ 
+            double dfSAMP_OFF = CPLAtof(CSLFetchNameValueDef(papszMD, "SAMP_OFF", "0"));
+            double dfLINE_OFF = CPLAtof(CSLFetchNameValueDef(papszMD, "LINE_OFF", "0"));
+            double dfSAMP_SCALE = CPLAtof(CSLFetchNameValueDef(papszMD, "SAMP_SCALE", "1"));
+            double dfLINE_SCALE = CPLAtof(CSLFetchNameValueDef(papszMD, "LINE_SCALE", "1"));
+
+            dfSAMP_OFF -= anSrcWin[0];
+            dfLINE_OFF -= anSrcWin[1];
+            dfSAMP_OFF *= (nOXSize / (double) anSrcWin[2] );
+            dfLINE_OFF *= (nOYSize / (double) anSrcWin[3] );
+            dfSAMP_SCALE *= (nOXSize / (double) anSrcWin[2] );
+            dfLINE_SCALE *= (nOYSize / (double) anSrcWin[3] );
+
+            CPLString osField;
+            osField.Printf( "%.15g", dfLINE_OFF );
+            papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
+
+            osField.Printf( "%.15g", dfSAMP_OFF );
+            papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
+
+            osField.Printf( "%.15g", dfLINE_SCALE );
+            papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
+
+            osField.Printf( "%.15g", dfSAMP_SCALE );
+            papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
+
+            poVDS->SetMetadata( papszMD, "RPC" );
+            CSLDestroy(papszMD);
+        }
+    }
 
     int nSrcBandCount = nBandCount;
 
@@ -1258,6 +1453,7 @@ static int ProxyMain( int argc, char ** argv )
             GDALDestroyDriverManager();
             CSLDestroy( argv );
             CSLDestroy( papszCreateOptions );
+            CSLDestroy( papszOpenOptions );
             exit( 1 );
         }
         
@@ -1289,6 +1485,7 @@ static int ProxyMain( int argc, char ** argv )
         }
     }
 
+    // Can be set to TRUE in the band loop too
     int bFilterOutStatsMetadata =
         (nScaleRepeat > 0 || bUnscale || !bSpatialArrangementPreserved || nRGBExpand != 0);
 
@@ -1324,7 +1521,70 @@ static int ProxyMain( int argc, char ** argv )
         if( eOutputType == GDT_Unknown )
             eBandType = poSrcBand->GetRasterDataType();
         else
+        {
             eBandType = eOutputType;
+            
+            // Check that we can copy existing statistics
+            GDALDataType eSrcBandType = poSrcBand->GetRasterDataType();
+            const char* pszMin = poSrcBand->GetMetadataItem("STATISTICS_MINIMUM");
+            const char* pszMax = poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM");
+            if( !bFilterOutStatsMetadata && eBandType != eSrcBandType &&
+                pszMin != NULL && pszMax != NULL )
+            {
+                int bSrcIsInteger = ( eSrcBandType == GDT_Byte ||
+                                      eSrcBandType == GDT_Int16 ||
+                                      eSrcBandType == GDT_UInt16 ||
+                                      eSrcBandType == GDT_Int32 ||
+                                      eSrcBandType == GDT_UInt32 );
+                int bDstIsInteger = ( eBandType == GDT_Byte ||
+                                      eBandType == GDT_Int16 ||
+                                      eBandType == GDT_UInt16 ||
+                                      eBandType == GDT_Int32 ||
+                                      eBandType == GDT_UInt32 );
+                if( bSrcIsInteger && bDstIsInteger )
+                {
+                    GInt32 nDstMin = 0;
+                    GUInt32 nDstMax = 0;
+                    switch( eBandType )
+                    {
+                        case GDT_Byte:
+                            nDstMin = 0;
+                            nDstMax = 255;
+                            break;
+                        case GDT_UInt16:
+                            nDstMin = 0;
+                            nDstMax = 65535;
+                            break;
+                        case GDT_Int16:
+                            nDstMin = -32768;
+                            nDstMax = 32767;
+                            break;
+                        case GDT_UInt32:
+                            nDstMin = 0;
+                            nDstMax = 0xFFFFFFFFU;
+                            break;
+                        case GDT_Int32:
+                            nDstMin = 0x80000000;
+                            nDstMax = 0x7FFFFFFF;
+                            break;
+                        default:
+                            CPLAssert(FALSE);
+                            break;
+                    }
+
+                    GInt32 nMin = atoi(pszMin);
+                    GUInt32 nMax = (GUInt32)strtoul(pszMax, NULL, 10);
+                    if( nMin < nDstMin || nMax > nDstMax )
+                        bFilterOutStatsMetadata = TRUE;
+                }
+                // Float64 is large enough to hold all integer <= 32 bit or float32 values
+                // there might be other OK cases, but ere on safe side for now
+                else if( !((bSrcIsInteger || eSrcBandType == GDT_Float32) && eBandType == GDT_Float64) )
+                {
+                    bFilterOutStatsMetadata = TRUE;
+                }
+            }
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Create this band.                                               */
@@ -1418,16 +1678,10 @@ static int ProxyMain( int argc, char ** argv )
 /*      Create a simple or complex data source depending on the         */
 /*      translation type required.                                      */
 /* -------------------------------------------------------------------- */
+        VRTSimpleSource* poSimpleSource;
         if( bUnscale || bScale || (nRGBExpand != 0 && i < nRGBExpand) )
         {
             VRTComplexSource* poSource = new VRTComplexSource();
-            poVRTBand->ConfigureSource( poSource,
-                                        poSrcBand,
-                                        FALSE,
-                                        anSrcWin[0], anSrcWin[1],
-                                        anSrcWin[2], anSrcWin[3],
-                                        anDstWin[0], anDstWin[1],
-                                        anDstWin[2], anDstWin[3] );
 
         /* -------------------------------------------------------------------- */
         /*      Set complex parameters.                                         */
@@ -1448,14 +1702,21 @@ static int ProxyMain( int argc, char ** argv )
 
             poSource->SetColorTableComponent(nComponent);
 
-            poVRTBand->AddSource( poSource );
+            poSimpleSource = poSource;
         }
         else
-            poVRTBand->AddSimpleSource( poSrcBand,
-                                        anSrcWin[0], anSrcWin[1],
-                                        anSrcWin[2], anSrcWin[3],
-                                        anDstWin[0], anDstWin[1],
-                                        anDstWin[2], anDstWin[3] );
+            poSimpleSource = new VRTSimpleSource();
+
+        poSimpleSource->SetResampling(pszResampling);
+        poVRTBand->ConfigureSource( poSimpleSource,
+                                    poSrcBand,
+                                    FALSE,
+                                    anSrcWin[0], anSrcWin[1],
+                                    anSrcWin[2], anSrcWin[3],
+                                    anDstWin[0], anDstWin[1],
+                                    anDstWin[2], anDstWin[3] );
+
+        poVRTBand->AddSource( poSimpleSource );
 
 /* -------------------------------------------------------------------- */
 /*      In case of color table translate, we only set the color         */
@@ -1638,6 +1899,7 @@ static int ProxyMain( int argc, char ** argv )
 
     CSLDestroy( argv );
     CSLDestroy( papszCreateOptions );
+    CSLDestroy( papszOpenOptions );
     
     return hOutDS == NULL;
 }
@@ -1726,7 +1988,9 @@ static void CopyBandInfo( GDALRasterBand * poSrcBand, GDALRasterBand * poDstBand
     }
 
     poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() );
-    if( !EQUAL(poSrcBand->GetUnitType(),"") )
+
+    // Copy unit only if the range of pixel values is not modified
+    if( bCanCopyStatsMetadata && bCopyScale && !EQUAL(poSrcBand->GetUnitType(),"") )
         poDstBand->SetUnitType( poSrcBand->GetUnitType() );
 }
 
diff --git a/apps/gdal_utilities.dox b/apps/gdal_utilities.dox
index 36d2314..d866b02 100644
--- a/apps/gdal_utilities.dox
+++ b/apps/gdal_utilities.dox
@@ -1,5 +1,5 @@
 #ifndef DOXYGEN_SKIP
-/* $Id: gdal_utilities.dox 27110 2014-03-28 21:29:20Z rouault $ */
+/* $Id: gdal_utilities.dox 29105 2015-05-02 10:13:13Z rouault $ */
 #endif /* DOXYGEN_SKIP */
 
 /*! 
@@ -173,7 +173,7 @@ and exit.
 
 \htmlonly
 <p>
-$Id: gdal_utilities.dox 27110 2014-03-28 21:29:20Z rouault $
+$Id: gdal_utilities.dox 29105 2015-05-02 10:13:13Z rouault $
 </p>
 \endhtmlonly
 */
@@ -189,7 +189,7 @@ lists information about a raster dataset
 gdalinfo [--help-general] [-mm] [-stats] [-hist] [-nogcp] [-nomd]
          [-norat] [-noct] [-nofl] [-checksum] [-proj4]
          [-listmdd] [-mdd domain|`all`]*
-         [-sd subdataset] datasetname
+         [-sd subdataset] [-oo NAME=VALUE]* datasetname
 \endverbatim
 
 \section gdalinfo_description DESCRIPTION
@@ -210,7 +210,7 @@ useful for datasets with huge amount of GCPs, such as L1B AVHRR or HDF4 MODIS
 which contain thousands of them.</dd>
 <dt> <b>-nomd</b></dt><dd> Suppress metadata printing. Some datasets may contain a lot
 of metadata strings.</dd>
-<dt> <b>-nrat</b></dt><dd> Suppress printing of raster attribute table.</dd>
+<dt> <b>-norat</b></dt><dd> Suppress printing of raster attribute table.</dd>
 <dt> <b>-noct</b></dt><dd> Suppress printing of color table.</dd>
 <dt> <b>-checksum</b></dt><dd> Force computation of the checksum for each band in the dataset.</dd>
 <dt> <b>-listmdd</b></dt><dd> (GDAL >= 1.11) List all metadata domains available for the dataset.</dd>
@@ -223,6 +223,7 @@ dataset contains several subdatasets read and display a subdataset with
 specified number (starting from 1). This is an alternative of giving the full
 subdataset name.</dd>
 <dt> <b>-proj4</b></dt><dd> (GDAL >= 1.9.0) Report a PROJ.4 string corresponding to the file's coordinate system.</dd>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
 </dl>
 
 The gdalinfo will report all of the following (if known):
@@ -298,13 +299,16 @@ gdal_translate [--help-general]
        [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/
              CInt16/CInt32/CFloat32/CFloat64}] [-strict]
        [-of format] [-b band] [-mask band] [-expand {gray|rgb|rgba}]
-       [-outsize xsize[%] ysize[%]]
+       [-outsize xsize[%]|0 ysize[%]|0] [-tr xres yres]
+       [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]
        [-unscale] [-scale[_bn] [src_min src_max [dst_min dst_max]]]* [-exponent[_bn] exp_val]*
-       [-srcwin xoff yoff xsize ysize] [-projwin ulx uly lrx lry] [-epo] [-eco]
+       [-srcwin xoff yoff xsize ysize] [-epo] [-eco]
+       [-projwin ulx uly lrx lry] [-projwin_srs srs_def]
        [-a_srs srs_def] [-a_ullr ulx uly lrx lry] [-a_nodata value]
        [-gcp pixel line easting northing [elevation]]*
        [-mo "META-TAG=VALUE"]* [-q] [-sds]
        [-co "NAME=VALUE"]* [-stats] [-norat]
+       [-oo NAME=VALUE]*
        src_dataset dst_dataset
 \endverbatim
 
@@ -339,9 +343,18 @@ output drivers such as JPEG, JPEG2000, MrSID, ECW that don't support color
 indexed datasets. The 'gray' value (from GDAL 1.7.0) enables to expand a
 dataset with a color table that only contains gray levels to a gray indexed
 dataset.</dd>
-<dt> <b>-outsize</b> <i>xsize[%] ysize[%]</i>:</dt><dd> Set the size of the output
+<dt> <b>-outsize</b> <i>xsize[%]|0 ysize[%]|0</i>:</dt><dd> Set the size of the output
 file.  Outsize is in pixels and lines unless '\%' is attached in which case it
-is as a fraction of the input image size.</dd>
+is as a fraction of the input image size. Starting with GDAL 2.0, if one of the
+2 values is set to 0, its value will be determined from the other one,
+while maintaining the aspect ratio of the source dataset.</dd>
+<dt> <b>-tr</b> xres yres :</dt><dd>  (starting with GDAL 2.0)
+set target resolution. The values must be expressed in georeferenced units.
+Both must be positive values. This is exclusive with -outsize and -a_ullr.
+</dd>
+<dt> <b>-r</b>
+<i>{nearest (default),bilinear,cubic,cubicspline,lanczos,average,mode}</i>:</dt><dd>
+(GDAL >= 2.0) Select a resampling algorithm.</dd>
 <dt> <b>-scale</b> <i>[src_min src_max [dst_min dst_max]]</i>:</dt><dd> Rescale the
 input pixels values from the range <i>src_min</i> to <i>src_max</i> to
 the range <i>dst_min</i> to <i>dst_max</i>.  If omitted the output range is
@@ -371,7 +384,13 @@ reset the output datatype with the <b>-ot</b> switch.</dd>
 from the source image for copying based on pixel/line location.  </dd>
 <dt> <b>-projwin</b> <i>ulx uly lrx lry</i>:</dt><dd> Selects a subwindow from
 the source image for copying (like <b>-srcwin</b>) but with the corners given
-in georeferenced coordinates. </dd>
+in georeferenced coordinates (by default expressed in the SRS of the dataset. Can be
+changed with -projwin_srs). </dd>
+<dt> <b>-projwin_srs</b> <i>srs_def</i>:</dt><dd> (GDAL >= 2.0) Specifies the SRS in
+which to interpret the coordinates given with -projwin. The <i>srs_def</i> may
+be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file
+containing the WKT.
+Note that this does not cause reprojection of the dataset to the specified SRS. </dd>
 <dt> <b>-epo</b>: (Error when Partially Outside)</dt><dd>(GDAL >= 1.10) If this
 option is set, <b>-srcwin</b> or <b>-projwin</b> values that falls partially outside the
 source raster extent will be considered as an error. The default behaviour starting
@@ -385,11 +404,13 @@ complete WKT, PROJ.4, EPSG:n or a file containing the WKT. </dd>
 <dt> <b>-a_ullr</b> <i>ulx uly lrx lry</i>:</dt><dd>
 Assign/override the georeferenced bounds of the output file.  This assigns 
 georeferenced bounds to the output file, ignoring what would have been derived 
-from the source file.</dd>
+from the source file. So this does not cause reprojection to the specified SRS. </dd>
 <dt> <b>-a_nodata</b> <i>value</i>:</dt><dd>
 Assign a specified nodata value to output bands. Starting with GDAL 1.8.0, can
 be set to <i>none</i> to avoid setting a nodata value to the output file if
-one exists for the source file</dd>
+one exists for the source file. Note that, if the input dataset has a
+nodata value, this does not cause pixel values that are equal to that nodata
+value to be changed to the value specified with this option.</dd>
 <dt> <b>-mo</b> <i>"META-TAG=VALUE"</i>:</dt><dd> Passes a metadata key and
 value to set on the output dataset if possible.</dd>
 <dt> <b>-co</b> <i>"NAME=VALUE"</i>:</dt><dd> Passes a creation option to the
@@ -406,6 +427,7 @@ output files.  Use with formats like HDF or OGDI that have subdatasets.
 The output file naming scheme has changed in GDAL 1.11 (e.g. ofile_1.tif, ofile_2.tif).</dd>
 <dt> <b>-stats</b>:</dt><dd> (GDAL >= 1.8.0) Force (re)computation of statistics.</dd>
 <dt> <b>-norat</b></dt><dd> (GDAL >= 1.11) Do not copy source RAT into destination dataset.</dd>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
 <dt> <i>src_dataset</i>:</dt><dd>The source dataset name. It can be either
 file name, URL of data source or subdataset name for multi-dataset files.</dd>
 <dt> <i>dst_dataset</i>:</dt><dd> The destination file name.</dd>
@@ -441,9 +463,9 @@ builds or rebuilds overview images
 \section gdaladdo_synopsis SYNOPSIS
 
 \verbatim
-gdaladdo [-r {nearest,average,gauss,cubic,average_mp,average_magphase,mode}]
+gdaladdo [-r {nearest,average,gauss,cubic,cubicspline,lanczos,average_mp,average_magphase,mode}]
          [-b band]
-         [-ro] [-clean] [--help-general] filename levels
+         [-ro] [-clean] [-oo NAME=VALUE]* [--help-general] filename levels
 \endverbatim
 
 \section gdaladdo_description DESCRIPTION
@@ -453,7 +475,7 @@ most supported file formats with one of several downsampling algorithms.
 
 <dl>
 <dt> <b>-r</b>
-<i>{nearest (default),average,gauss,cubic,average_mp,average_magphase,mode}</i>:</dt><dd>
+<i>{nearest (default),average,gauss,cubic,cubicspline,lanczos,average_mp,average_magphase,mode}</i>:</dt><dd>
 Select a resampling algorithm.</dd>
 <dt> <b>-b</b> <i>band</i>:</dt><dd> (available from GDAL 1.10) Select an input band <i>band</i> for
 overview generation. Band numbering starts from 1. Multiple <b>-b</b> switches may be used
@@ -461,6 +483,7 @@ to select a set of input bands to generate overviews.</dd>
 <dt> <b>-ro</b></dt>:<dd> (available from GDAL 1.6.0) open the dataset in read-only mode, in order to generate
 external overview (for GeoTIFF especially). </dd>
 <dt> <b>-clean</b></dt>:<dd> (available from GDAL 1.7.0) remove all overviews. </dd>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
 <dt> <i>filename</i>:</dt><dd> The file to build overviews for (or whose overviews must be removed). </dd>
 <dt> <i>levels</i>:</dt><dd> A list of integral overview levels to build. Ignored with -clean option.</dd>
 </dl>
@@ -471,11 +494,13 @@ external overview (for GeoTIFF especially). </dd>
 <i>Nearest</i> and <i>average</i> are applicable to normal image data.  
 <i>Nearest</i> applies a nearest neighbour (simple sampling) resampler, while
 <i>average</i> computes the average of all non-NODATA contributing pixels.
-<i>Cubic</i> resampling (available from GDAL 1.7.0) applies a 4x4 approximate cubic convolution kernel.
+<i>Cubic</i> resampling (available from GDAL 1.7.0) applies a cubic convolution kernel.
 <i>Gauss</i> resampling (available from GDAL 1.6.0) applies a Gaussian kernel before computing the overview, 
 which can lead to better results than simple averaging in e.g case of sharp edges
 with high contrast or noisy patterns. The advised level values should be 2, 4, 8, ...
 so that a 3x3 resampling Gaussian kernel is selected.
+<i>CubicSpline</i> resampling (available from GDAL 2.0) applies a B-Spline convolution kernel.
+<i>Lanczos</i> resampling (available from GDAL 2.0) applies a Lanczos windowed sinc convolution kernel.
 
 gdaladdo will honour properly NODATA_VALUES tuples (special dataset metadata) so
 that only a given RGB triplet (in case of a RGB image) will be considered as the
@@ -673,6 +698,7 @@ gdalbuildvrt [-tileindex field_name]
              [-addalpha] [-hidenodata]
              [-srcnodata "value [value...]"] [-vrtnodata "value [value...]"] 
              [-a_srs srs_def]
+             [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]
              [-input_file_list my_liste.txt] [-overwrite] output.vrt [gdalfile]*
 \endverbatim
 
@@ -787,6 +813,10 @@ just be ignored.
 Override the projection for the output file.  The <i>srs_def</i> may be any of the usual GDAL/OGR forms,
 complete WKT, PROJ.4, EPSG:n or a file containing the WKT. </dd>
 
+<dt> <b>-r</b>
+<i>{nearest (default),bilinear,cubic,cubicspline,lanczos,average,mode}</i>:</dt><dd>
+(GDAL >= 2.0) Select a resampling algorithm.</dd>
+
 <dt> <b>-input_file_list</b>:</dt><dd> 
 To specify a text file with an input filename on each line
 </dd>
@@ -925,15 +955,15 @@ Usage: gdal_rasterize [-b band]* [-i] [-at]
 
 \section gdal_rasterize_description DESCRIPTION
 
-This program burns vector geometries (points, lines and polygons) into the 
+This program burns vector geometries (points, lines, and polygons) into the
 raster band(s) of a raster image.  Vectors are read from OGR supported vector 
 formats. 
 
-Note that the vector data must in the same coordinate system as the 
+Note that the vector data must be in the same coordinate system as the
 raster data; on the fly reprojection is not provided.
 
-Since GDAL 1.8.0, the target GDAL file can be created by gdal_rasterize. One of -tr or -ts option
-must be used in that case.
+Since GDAL 1.8.0, the target GDAL file can be created by gdal_rasterize. Either
+the -tr or -ts option must be used in that case.
 
 <dl>
 <dt> <b>-b</b> <em>band</em>: </dt><dd> 
@@ -947,7 +977,7 @@ provided a polygon.</dd>
 
 <dt> <b>-at</b>: </dt><dd>
 Enables the ALL_TOUCHED rasterization option so that all pixels touched
-by lines or polygons will be updated not just those one the line render path,
+by lines or polygons will be updated, not just those on the line render path,
 or whose center point is within the polygon.  Defaults to disabled for normal
 rendering rules.</dd>
 
@@ -956,7 +986,7 @@ A fixed value to burn into a band for all objects.  A list of -burn options
 can be supplied, one per band being written to.</dd>
 
 <dt> <b>-a</b> <em>attribute_name</em>: </dt><dd> 
-Identifies an attribute field on the features to be used for a burn in value.
+Identifies an attribute field on the features to be used for a burn-in value.
 The value will be burned into all output bands.</dd>
 
 <dt> <b>-3d</b>: </dt><dd> 
@@ -967,7 +997,8 @@ feature. These values are adjusted by the burn value given by "-burn value" or
 
 <dt> <b>-l</b> <em>layername</em>: </dt><dd> 
 Indicates the layer(s) from the datasource that will be used for input 
-features.  May be specified multiple times, but at least one layer name or a -sql option must be specified.</dd>
+features.  May be specified multiple times, but at least one layer name or a
+-sql option must be specified.</dd>
 
 <dt> <b>-where</b> <em>expression</em>: </dt><dd> 
 An optional SQL WHERE style query expression to be applied to select features 
@@ -977,8 +1008,9 @@ to burn in from the input layer(s). </dd>
 An SQL statement to be evaluated against the datasource to produce a
 virtual layer of features to be burned in.</dd>
 
-<dt> <b>-of</b> <i>format</i>:</dt><dd> (GDAL >= 1.8.0) Select the output format.  The default
-is GeoTIFF (GTiff).  Use the short format name.</dd>
+<dt> <b>-of</b> <i>format</i>:</dt><dd> (GDAL >= 1.8.0)
+Select the output format.  The default is GeoTIFF (GTiff).  Use the short format
+name.</dd>
 
 <dt> <b>-a_nodata</b> <i>value</i>:</dt><dd> (GDAL >= 1.8.0)
 Assign a specified nodata value to output bands.</dd>
@@ -988,38 +1020,41 @@ Pre-initialize the output image bands with these values.  However, it is not
 marked as the nodata value in the output file.  If only one value is given, the
 same value is used in all the bands.</dd>
 
-<dt> <b>-a_srs</b> <i>srs_def</i>:</dt><dd> (GDAL >= 1.8.0) Override the projection for the
-output file. If not specified, the projection of the input vector file will be used if available.
-If incompatible projections between input and output files, no attempt will be made to reproject features.
-The <i>srs_def</i> may be any of the usual GDAL/OGR forms,
-complete WKT, PROJ.4, EPSG:n or a file containing the WKT. </dd>
+<dt> <b>-a_srs</b> <i>srs_def</i>:</dt><dd> (GDAL >= 1.8.0)
+Override the projection for the output file. If not specified, the projection of
+the input vector file will be used if available. If incompatible projections
+between input and output files, no attempt will be made to reproject features.
+The <i>srs_def</i> may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4,
+EPSG:n or a file containing the WKT. </dd>
 
-<dt> <b>-co</b> <i>"NAME=VALUE"</i>:</dt><dd> (GDAL >= 1.8.0) Passes a creation option to the
-output format driver.  Multiple <b>-co</b> options may be listed.  See format 
-specific documentation for legal creation options for each format.</dd>
+<dt> <b>-co</b> <i>"NAME=VALUE"</i>:</dt><dd> (GDAL >= 1.8.0)
+Passes a creation option to the output format driver.  Multiple <b>-co</b>
+options may be listed.  See format specific documentation for legal creation
+options for each format.</dd>
 
 <dt> <b>-te</b> <em>xmin ymin xmax ymax</em> :</dt><dd> (GDAL >= 1.8.0) 
-set georeferenced extents. The values must be expressed in georeferenced units.
-If not specified, the extent of the output file will be the extent of the vector layers.
-</dd>
+Set georeferenced extents. The values must be expressed in georeferenced units.
+If not specified, the extent of the output file will be the extent of the vector
+layers. </dd>
 
 <dt> <b>-tr</b> <em>xres yres</em> :</dt><dd> (GDAL >= 1.8.0) 
-set target resolution. The values must be expressed in georeferenced units.
+Set target resolution. The values must be expressed in georeferenced units.
 Both must be positive values.
 </dd>
 
-<dt> <b>-tap</b>:</dt><dd> (GDAL >= 1.8.0) (target aligned pixels) align
+<dt> <b>-tap</b>:</dt><dd> (GDAL >= 1.8.0) (target aligned pixels) Align
 the coordinates of the extent of the output file to the values of the -tr,
 such that the aligned extent includes the minimum extent.</dd>
 
-<dt> <b>-ts</b> <em>width height</em>:</dt><dd>  (GDAL >= 1.8.0) set output file size in
-pixels and lines. Note that -ts cannot be used with -tr</dd>
+<dt> <b>-ts</b> <em>width height</em>:</dt><dd>  (GDAL >= 1.8.0)
+Set output file size in pixels and lines. Note that -ts cannot be used with
+-tr</dd>
 
-<dt> <b>-ot</b> <i>type</i>:</dt><dd> (GDAL >= 1.8.0) For the output bands to be of the
-indicated data type. Defaults to Float64</dd>
+<dt> <b>-ot</b> <i>type</i>:</dt><dd> (GDAL >= 1.8.0)
+For the output bands to be of the indicated data type. Defaults to Float64</dd>
 
-<dt> <b>-q</b>:</dt><dd> (GDAL >= 1.8.0) Suppress progress monitor and other non-error
-output.</dd>
+<dt> <b>-q</b>:</dt><dd> (GDAL >= 1.8.0) Suppress progress monitor and other
+non-error output.</dd>
 
 <dt> <em>src_datasource</em>: </dt><dd> 
 Any OGR supported readable datasource.</dd>
@@ -1170,7 +1205,7 @@ transforms coordinates
 gdaltransform [--help-general]
     [-i] [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
     [-order n] [-tps] [-rpc] [-geoloc]
-    [-gcp pixel line easting northing [elevation]]*
+    [-gcp pixel line easting northing [elevation]]* [-output_xy]
     [srcfile [dstfile]]
 \endverbatim
 
@@ -1201,6 +1236,7 @@ available GCPs.</dd>
 <dt> <b>-geoloc</b>:</dt><dd>Force use of Geolocation Arrays.</dd>
 <dt> <b>-i</b></dt><dd>Inverse transformation: from destination to source.</dd>
 <dt> <b>-gcp</b><em>pixel line easting northing [elevation]</em>:</dt> <dd>Provide a GCP to be used for transformation (generally three or more are required)</dd>
+<dt> <b>-output_xy</b>:</dt> <dd>(GDAL >= 2.0) Restrict output to "x y" instead of "x y z"</dd>
 <dt> <em>srcfile</em>:</dt><dd> File with source projection definition or GCP's. If
     not given, source projection is read from the command-line -s_srs or -gcp parameters </dd>
 <dt> <em>dstfile</em>:</dt><dd> File with destination projection definition. </dd>
@@ -1416,7 +1452,7 @@ Create an image with the pixels in all bands initialized to 255.
 \endverbatim
 
 Create an RGB image that shows blue in pixels with no data. The first two bands
-will be initialized to 0 and the third band will be initalized to 255.
+will be initialized to 0 and the third band will be initialized to 255.
 
 \verbatim
 % gdal_merge.py -init "0 0 255" -o out.tif in1.tif in2.tif
diff --git a/apps/gdaladdo.cpp b/apps/gdaladdo.cpp
index c804663..357f7ea 100644
--- a/apps/gdaladdo.cpp
+++ b/apps/gdaladdo.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaladdo.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdaladdo.cpp 28083 2014-12-05 18:58:42Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Commandline application to build overviews. 
@@ -31,7 +31,7 @@
 #include "gdal_priv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdaladdo.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdaladdo.cpp 28083 2014-12-05 18:58:42Z rouault $");
 
 /************************************************************************/
 /*                               Usage()                                */
@@ -40,8 +40,8 @@ CPL_CVSID("$Id: gdaladdo.cpp 27044 2014-03-16 23:41:27Z rouault $");
 static void Usage(const char* pszErrorMsg = NULL)
 
 {
-    printf( "Usage: gdaladdo [-r {nearest,average,gauss,cubic,average_mp,average_magphase,mode}]\n"
-            "                [-ro] [-clean] [-q] [--help-general] filename levels\n"
+    printf( "Usage: gdaladdo [-r {nearest,average,gauss,cubic,cubicspline,lanczos,average_mp,average_magphase,mode}]\n"
+            "                [-ro] [-clean] [-q] [-oo NAME=VALUE]* [--help-general] filename levels\n"
             "\n"
             "  -r : choice of resampling method (default: nearest)\n"
             "  -ro : open the dataset in read-only mode, in order to generate\n"
@@ -52,7 +52,7 @@ static void Usage(const char* pszErrorMsg = NULL)
             "  filename: The file to build overviews for (or whose overviews must be removed).\n"
             "  levels: A list of integral overview levels to build. Ignored with -clean option.\n"
             "\n"
-            "Usefull configuration variables :\n"
+            "Useful configuration variables :\n"
             "  --config USE_RRD YES : Use Erdas Imagine format (.aux) as overview format.\n"
             "Below, only for external overviews in GeoTIFF format:\n"
             "  --config COMPRESS_OVERVIEW {JPEG,LZW,PACKBITS,DEFLATE} : TIFF compression\n"
@@ -94,6 +94,7 @@ int main( int nArgc, char ** papszArgv )
     GDALProgressFunc pfnProgress = GDALTermProgress; 
     int             *panBandList = NULL;
     int              nBandCount = 0;
+    char           **papszOpenOptions = NULL;
 
     /* Check that we are running against at least GDAL 1.7 */
     /* Note to developers : if we use newer API, please change the requirement */
@@ -153,12 +154,24 @@ int main( int nArgc, char ** papszArgv )
                 CPLRealloc(panBandList, sizeof(int) * nBandCount);
             panBandList[nBandCount-1] = nBand;
         }
+        else if( EQUAL(papszArgv[iArg], "-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                             papszArgv[++iArg] );
+        }
         else if( papszArgv[iArg][0] == '-' )
             Usage(CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
         else if( pszFilename == NULL )
             pszFilename = papszArgv[iArg];
         else if( atoi(papszArgv[iArg]) > 0 )
+        {
             anLevels[nLevelCount++] = atoi(papszArgv[iArg]);
+            if( anLevels[nLevelCount-1] == 1 )
+            {
+                printf("Warning: Overview with subsampling factor of 1 requested. This will copy the full resolution dataset in the overview !\n");
+            }
+        }
         else
             Usage("Too many command options.");
     }
@@ -177,12 +190,15 @@ int main( int nArgc, char ** papszArgv )
     else
     {
         CPLPushErrorHandler( CPLQuietErrorHandler );
-        hDataset = GDALOpen( pszFilename, GA_Update );
+        hDataset = GDALOpenEx( pszFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE, NULL, papszOpenOptions, NULL );
         CPLPopErrorHandler();
     }
 
     if( hDataset == NULL )
-        hDataset = GDALOpen( pszFilename, GA_ReadOnly );
+        hDataset = GDALOpenEx( pszFilename, GDAL_OF_RASTER, NULL, papszOpenOptions, NULL );
+
+    CSLDestroy(papszOpenOptions);
+    papszOpenOptions = NULL;
 
     if( hDataset == NULL )
         exit( 2 );
diff --git a/apps/gdalasyncread.cpp b/apps/gdalasyncread.cpp
index e1e5739..4f91bd3 100644
--- a/apps/gdalasyncread.cpp
+++ b/apps/gdalasyncread.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalasyncread.cpp 19521 2010-04-24 21:46:11Z rouault $
+ * $Id: gdalasyncread.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  GDAL Async Image Reader, primarily for testing async api.
@@ -33,7 +33,7 @@
 #include "gdal_priv.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: gdalasyncread.cpp 19521 2010-04-24 21:46:11Z rouault $");
+CPL_CVSID("$Id: gdalasyncread.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /* ******************************************************************** */
 /*                               Usage()                                */
@@ -189,7 +189,7 @@ int main( int argc, char ** argv )
 
         else if( EQUAL(argv[i],"-to") && i < argc-1 )
         {
-            dfTimeout = atof(argv[++i] );
+            dfTimeout = CPLAtof(argv[++i] );
         }   
 
         else if( EQUAL(argv[i],"-outsize") && i < argc-2 )
@@ -294,9 +294,9 @@ int main( int argc, char ** argv )
     else
     {
         nOXSize = (int) ((pszOXSize[strlen(pszOXSize)-1]=='%' 
-                          ? atof(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
+                          ? CPLAtof(pszOXSize)/100*anSrcWin[2] : atoi(pszOXSize)));
         nOYSize = (int) ((pszOYSize[strlen(pszOYSize)-1]=='%' 
-                          ? atof(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
+                          ? CPLAtof(pszOYSize)/100*anSrcWin[3] : atoi(pszOYSize)));
     }
 
 /* -------------------------------------------------------------------- */
@@ -521,7 +521,7 @@ int main( int argc, char ** argv )
                                + nUpYOff * nLineSpace, 
                                nUpXSize, nUpYSize, eOutputType,
                                nBandCount, NULL, 
-                               nPixelSpace, nLineSpace, nBandSpace );
+                               nPixelSpace, nLineSpace, nBandSpace, NULL );
         poAsyncReq->UnlockBuffer();
 
 /* -------------------------------------------------------------------- */
diff --git a/apps/gdalbuildvrt.cpp b/apps/gdalbuildvrt.cpp
index 078278f..f8326eb 100644
--- a/apps/gdalbuildvrt.cpp
+++ b/apps/gdalbuildvrt.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalbuildvrt.cpp 27994 2014-11-21 20:03:49Z rouault $
+ * $Id: gdalbuildvrt.cpp 28998 2015-04-24 19:04:46Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Commandline application to build VRT datasets from raster products or content of SHP tile index
@@ -37,7 +37,7 @@
 #endif
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: gdalbuildvrt.cpp 27994 2014-11-21 20:03:49Z rouault $");
+CPL_CVSID("$Id: gdalbuildvrt.cpp 28998 2015-04-24 19:04:46Z rouault $");
 
 #define GEOTRSFRM_TOPLEFT_X            0
 #define GEOTRSFRM_WE_RES               1
@@ -105,6 +105,7 @@ static void Usage(const char* pszErrorMsg = NULL)
             "                    [-addalpha] [-hidenodata]\n"
             "                    [-srcnodata \"value [value...]\"] [-vrtnodata \"value [value...]\"] \n"
             "                    [-a_srs srs_def]\n"
+            "                    [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]\n"
             "                    [-input_file_list my_liste.txt] [-overwrite] output.vrt [gdalfile]*\n"
             "\n"
             "eg.\n"
@@ -226,6 +227,7 @@ class VRTBuilder
     char               *pszSrcNoData;
     char               *pszVRTNoData;
     char               *pszOutputSRS;
+    char               *pszResampling;
 
     /* Internal variables */
     char               *pszProjectionRef;
@@ -262,7 +264,8 @@ class VRTBuilder
                            int bSeparate, int bAllowProjectionDifference,
                            int bAddAlpha, int bHideNoData, int nSubdataset,
                            const char* pszSrcNoData, const char* pszVRTNoData,
-                           const char* pszOutputSRS);
+                           const char* pszOutputSRS,
+                           const char* pszResampling);
 
                ~VRTBuilder();
 
@@ -284,7 +287,8 @@ VRTBuilder::VRTBuilder(const char* pszOutputFilename,
                        int bSeparate, int bAllowProjectionDifference,
                        int bAddAlpha, int bHideNoData, int nSubdataset,
                        const char* pszSrcNoData, const char* pszVRTNoData,
-                       const char* pszOutputSRS)
+                       const char* pszOutputSRS,
+                       const char* pszResampling)
 {
     this->pszOutputFilename = CPLStrdup(pszOutputFilename);
     this->nInputFiles = nInputFiles;
@@ -316,6 +320,7 @@ VRTBuilder::VRTBuilder(const char* pszOutputFilename,
     this->pszSrcNoData = (pszSrcNoData) ? CPLStrdup(pszSrcNoData) : NULL;
     this->pszVRTNoData = (pszVRTNoData) ? CPLStrdup(pszVRTNoData) : NULL;
     this->pszOutputSRS = (pszOutputSRS) ? CPLStrdup(pszOutputSRS) : NULL;
+    this->pszResampling = (pszResampling) ? CPLStrdup(pszResampling) : NULL;
 
     bUserExtent = FALSE;
     pszProjectionRef = NULL;
@@ -378,6 +383,7 @@ VRTBuilder::~VRTBuilder()
     CPLFree(padfSrcNoData);
     CPLFree(padfVRTNoData);
     CPLFree(pszOutputSRS);
+    CPLFree(pszResampling);
 }
 
 /************************************************************************/
@@ -839,20 +845,28 @@ void VRTBuilder::CreateVRTSeparate(VRTDatasetH hVRTDS)
         if (bHideNoData)
             GDALSetMetadataItem(hVRTBand,"HideNoDataValue","1",NULL);
 
+        VRTSourcedRasterBand* poVRTBand = (VRTSourcedRasterBand*)hVRTBand;
+
+        VRTSimpleSource* poSimpleSource;
         if (bAllowSrcNoData && psDatasetProperties->panHasNoData[0])
         {
             GDALSetRasterNoDataValue(hVRTBand, psDatasetProperties->padfNoDataValues[0]);
-            VRTAddComplexSource(hVRTBand, GDALGetRasterBand((GDALDatasetH)hProxyDS, 1),
-                            nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
-                            nDstXOff, nDstYOff, nDstXSize, nDstYSize,
-                            0, 1, psDatasetProperties->padfNoDataValues[0]);
+            poSimpleSource = new VRTComplexSource();
+            poSimpleSource->SetNoDataValue( psDatasetProperties->padfNoDataValues[0] );
         }
         else
-            /* Place the raster band at the right position in the VRT */
-            VRTAddSimpleSource(hVRTBand, GDALGetRasterBand((GDALDatasetH)hProxyDS, 1),
-                            nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
-                            nDstXOff, nDstYOff, nDstXSize, nDstYSize,
-                            "near", VRT_NODATA_UNSET);
+            poSimpleSource = new VRTSimpleSource();
+        if( pszResampling )
+            poSimpleSource->SetResampling(pszResampling);
+        poVRTBand->ConfigureSource( poSimpleSource,
+                                    (GDALRasterBand*)GDALGetRasterBand((GDALDatasetH)hProxyDS, 1),
+                                    FALSE,
+                                    nSrcXOff, nSrcYOff,
+                                    nSrcXSize, nSrcYSize,
+                                    nDstXOff, nDstYOff,
+                                    nDstXSize, nDstYSize );
+
+        poVRTBand->AddSource( poSimpleSource );
 
         GDALDereferenceDataset(hProxyDS);
 
@@ -885,7 +899,7 @@ void VRTBuilder::CreateVRTNonSeparate(VRTDatasetH hVRTDS)
             GDALSetMetadataItem(hBand,"HideNoDataValue","1",NULL);
     }
 
-    VRTSourcedRasterBand* hMaskVRTBand = NULL;
+    VRTSourcedRasterBand* poMaskVRTBand = NULL;
     if (bAddAlpha)
     {
         GDALRasterBandH hBand;
@@ -896,7 +910,7 @@ void VRTBuilder::CreateVRTNonSeparate(VRTDatasetH hVRTDS)
     else if (bHasDatasetMask)
     {
         GDALCreateDatasetMaskBand(hVRTDS, GMF_PER_DATASET);
-        hMaskVRTBand = (VRTSourcedRasterBand*)GDALGetMaskBand(GDALGetRasterBand(hVRTDS, 1));
+        poMaskVRTBand = (VRTSourcedRasterBand*)GDALGetMaskBand(GDALGetRasterBand(hVRTDS, 1));
     }
 
 
@@ -946,16 +960,27 @@ void VRTBuilder::CreateVRTNonSeparate(VRTDatasetH hVRTDS)
 
             /* Place the raster band at the right position in the VRT */
             int nSelBand = panBandList[j] - 1;
+            VRTSourcedRasterBand* poVRTBand = (VRTSourcedRasterBand*)hVRTBand;
+
+            VRTSimpleSource* poSimpleSource;
             if (bAllowSrcNoData && psDatasetProperties->panHasNoData[nSelBand])
-                VRTAddComplexSource(hVRTBand, GDALGetRasterBand((GDALDatasetH)hProxyDS, nSelBand + 1),
-                                nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
-                                nDstXOff, nDstYOff, nDstXSize, nDstYSize,
-                                0, 1, psDatasetProperties->padfNoDataValues[nSelBand]);
+            {
+                poSimpleSource = new VRTComplexSource();
+                poSimpleSource->SetNoDataValue( psDatasetProperties->padfNoDataValues[nSelBand] );
+            }
             else
-                VRTAddSimpleSource(hVRTBand, GDALGetRasterBand((GDALDatasetH)hProxyDS, nSelBand + 1),
-                                nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
-                                nDstXOff, nDstYOff, nDstXSize, nDstYSize,
-                                "near", VRT_NODATA_UNSET);
+                poSimpleSource = new VRTSimpleSource();
+            if( pszResampling )
+                poSimpleSource->SetResampling(pszResampling);
+            poVRTBand->ConfigureSource( poSimpleSource,
+                                        (GDALRasterBand*)GDALGetRasterBand((GDALDatasetH)hProxyDS, nSelBand + 1),
+                                        FALSE,
+                                        nSrcXOff, nSrcYOff,
+                                        nSrcXSize, nSrcYSize,
+                                        nDstXOff, nDstYOff,
+                                        nDstXSize, nDstYSize );
+
+            poVRTBand->AddSource( poSimpleSource );
         }
 
         if (bAddAlpha)
@@ -971,9 +996,18 @@ void VRTBuilder::CreateVRTNonSeparate(VRTDatasetH hVRTDS)
         }
         else if (bHasDatasetMask)
         {
-            hMaskVRTBand->AddMaskBandSource((GDALRasterBand*)GDALGetRasterBand((GDALDatasetH)hProxyDS, 1),
-                                            nSrcXOff, nSrcYOff, nSrcXSize, nSrcYSize,
-                                            nDstXOff, nDstYOff, nDstXSize, nDstYSize);
+            VRTSimpleSource* poSimpleSource = new VRTSimpleSource();
+            if( pszResampling )
+                poSimpleSource->SetResampling(pszResampling);
+            poMaskVRTBand->ConfigureSource( poSimpleSource,
+                                            (GDALRasterBand*)GDALGetRasterBand((GDALDatasetH)hProxyDS, 1),
+                                            TRUE,
+                                            nSrcXOff, nSrcYOff,
+                                            nSrcXSize, nSrcYSize,
+                                            nDstXOff, nDstYOff,
+                                            nDstXSize, nDstYSize );
+
+            poMaskVRTBand->AddSource( poSimpleSource );
         }
 
         GDALDereferenceDataset(hProxyDS);
@@ -1232,7 +1266,7 @@ static void add_file_to_list(const char* filename, const char* tile_index,
         }
     
         /* Load in memory existing file names in SHP */
-        int nTileIndexFiles = OGR_L_GetFeatureCount(hLayer, TRUE);
+        int nTileIndexFiles = (int)OGR_L_GetFeatureCount(hLayer, TRUE);
         if (nTileIndexFiles == 0)
         {
             fprintf( stderr, "Tile index %s is empty. Skipping it.\n", filename);
@@ -1298,6 +1332,7 @@ int main( int nArgc, char ** papszArgv )
     int nBandCount = 0;
     int nMaxBandNo = 0;
     int nRet;
+    const char* pszResampling = NULL;
 
     /* Check strict compilation and runtime library version as we use C++ API */
     if (! GDAL_CHECK_VERSION(papszArgv[0]))
@@ -1453,6 +1488,11 @@ int main( int nArgc, char ** papszArgv )
             OSRDestroySpatialReference( hOutputSRS );
             iArg++;
         }
+        else if( EQUAL(papszArgv[iArg],"-r") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            pszResampling = papszArgv[++iArg];
+        }  
         else if ( papszArgv[iArg][0] == '-' )
         {
             Usage(CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
@@ -1545,7 +1585,7 @@ int main( int nArgc, char ** papszArgv )
                         panBandList, nBandCount, nMaxBandNo,
                         eStrategy, we_res, ns_res, bTargetAlignedPixels, xmin, ymin, xmax, ymax,
                         bSeparate, bAllowProjectionDifference, bAddAlpha, bHideNoData, nSubdataset,
-                        pszSrcNoData, pszVRTNoData, pszOutputSRS);
+                        pszSrcNoData, pszVRTNoData, pszOutputSRS, pszResampling);
 
     nRet = (oBuilder.Build(pfnProgress, NULL) == CE_None) ? 0 : 1;
     
diff --git a/apps/gdaldem.cpp b/apps/gdaldem.cpp
index 513bec2..12f8c14 100644
--- a/apps/gdaldem.cpp
+++ b/apps/gdaldem.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldem.cpp 27781 2014-10-01 17:48:26Z rouault $
+ * $Id: gdaldem.cpp 28496 2015-02-16 10:33:55Z rouault $
  *
  * Project:  GDAL DEM Utilities
  * Purpose:  
@@ -82,6 +82,7 @@
  *  on the continental slope Marine Geodesy, 2007, 30, 3-35
  ****************************************************************************/
 
+#include "cpl_vsi.h"
 #include <stdlib.h>
 #include <math.h>
 
@@ -91,7 +92,7 @@
 #include "gdal_priv.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: gdaldem.cpp 27781 2014-10-01 17:48:26Z rouault $");
+CPL_CVSID("$Id: gdaldem.cpp 28496 2015-02-16 10:33:55Z rouault $");
 
 #ifndef M_PI
 # define M_PI  3.1415926535897932384626433832795
@@ -1048,14 +1049,14 @@ ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
                     (ColorAssociation*)CPLRealloc(pasColorAssociation,
                            (nColorAssociation + 2) * sizeof(ColorAssociation));
 
-            pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
+            pasColorAssociation[nColorAssociation].dfVal = CPLAtof(papszFields[0]);
             pasColorAssociation[nColorAssociation].nR = atoi(papszFields[1]);
             pasColorAssociation[nColorAssociation].nG = atoi(papszFields[2]);
             pasColorAssociation[nColorAssociation].nB = atoi(papszFields[3]);
             pasColorAssociation[nColorAssociation].nA = 255;
             nColorAssociation++;
 
-            pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[4]);
+            pasColorAssociation[nColorAssociation].dfVal = CPLAtof(papszFields[4]);
             pasColorAssociation[nColorAssociation].nR = atoi(papszFields[5]);
             pasColorAssociation[nColorAssociation].nG = atoi(papszFields[6]);
             pasColorAssociation[nColorAssociation].nB = atoi(papszFields[7]);
@@ -1089,7 +1090,7 @@ ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
                 pasColorAssociation[nColorAssociation].dfVal = dfSrcNoDataValue;
             else if (strlen(papszFields[0]) > 1 && papszFields[0][strlen(papszFields[0])-1] == '%')
             {
-                double dfPct = atof(papszFields[0]) / 100.;
+                double dfPct = CPLAtof(papszFields[0]) / 100.;
                 if (dfPct < 0.0 || dfPct > 1.0)
                 {
                     CPLError(CE_Failure, CPLE_AppDefined,
@@ -1104,7 +1105,7 @@ ColorAssociation* GDALColorReliefParseColorFile(GDALRasterBandH hSrcBand,
                         GDALColorReliefGetAbsoluteValFromPct(hSrcBand, dfPct);
             }
             else
-                pasColorAssociation[nColorAssociation].dfVal = atof(papszFields[0]);
+                pasColorAssociation[nColorAssociation].dfVal = CPLAtof(papszFields[0]);
 
             if (nTokens >= 4)
             {
@@ -2237,7 +2238,7 @@ int main( int argc, char ** argv )
     const char *pszDstFilename = NULL;
     const char *pszColorFilename = NULL;
     const char *pszFormat = "GTiff";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     char **papszCreateOptions = NULL;
     
     GDALDatasetH hSrcDataset = NULL;
@@ -2319,7 +2320,7 @@ int main( int argc, char ** argv )
             ++i;
             if( !ArgIsNumeric(argv[i]) )
                 Usage();
-            z = atof(argv[i]);
+            z = CPLAtof(argv[i]);
         }
         else if ( eUtilityMode == SLOPE && EQUAL(argv[i], "-p"))
         {
@@ -2364,7 +2365,7 @@ int main( int argc, char ** argv )
             ++i;
             if( !ArgIsNumeric(argv[i]) )
                 Usage();
-            scale = atof(argv[i]);
+            scale = CPLAtof(argv[i]);
         }
         else if( eUtilityMode == HILL_SHADE &&
             (EQUAL(argv[i], "--az") || 
@@ -2377,7 +2378,7 @@ int main( int argc, char ** argv )
             ++i;
             if( !ArgIsNumeric(argv[i]) )
                 Usage();
-            az = atof(argv[i]);
+            az = CPLAtof(argv[i]);
         }
         else if( eUtilityMode == HILL_SHADE &&
             (EQUAL(argv[i], "--alt") || 
@@ -2390,7 +2391,7 @@ int main( int argc, char ** argv )
             ++i;
             if( !ArgIsNumeric(argv[i]) )
                 Usage();
-            alt = atof(argv[i]);
+            alt = CPLAtof(argv[i]);
         }
         else if( eUtilityMode == HILL_SHADE &&
             (EQUAL(argv[i], "-combined") || 
@@ -2430,7 +2431,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             pszFormat = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
         }
         else if( argv[i][0] == '-' )
         {
@@ -2509,8 +2510,9 @@ int main( int argc, char ** argv )
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
 
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL ||
-                GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL ||
+                 GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
             {
                 printf( "  %s: %s\n",
                         GDALGetDriverShortName( hDriver  ),
@@ -2521,7 +2523,7 @@ int main( int argc, char ** argv )
         exit( 1 );
     }
 
-    if (!bQuiet && !bFormatExplicitelySet)
+    if (!bQuiet && !bFormatExplicitlySet)
         CheckExtensionConsistency(pszDstFilename, pszFormat);
 
     double dfDstNoDataValue = 0;
@@ -2634,15 +2636,35 @@ int main( int argc, char ** argv )
     
     // We might actually want to always go through the intermediate dataset
     int bForceUseIntermediateDataset = FALSE;
-    if( EQUAL(pszFormat, "GTiff") &&
-        !EQUAL(CSLFetchNameValueDef(papszCreateOptions, "COMPRESS", "NONE"), "NONE") &&
-        CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "TILED", "NO")) )
+    if( EQUAL(pszFormat, "GTiff") )
     {
-        bForceUseIntermediateDataset = TRUE;
+        if( !EQUAL(CSLFetchNameValueDef(papszCreateOptions, "COMPRESS", "NONE"), "NONE") &&
+            CSLTestBoolean(CSLFetchNameValueDef(papszCreateOptions, "TILED", "NO")) )
+        {
+            bForceUseIntermediateDataset = TRUE;
+        }
+        else if( strcmp(pszDstFilename, "/vsistdout/") == 0 )
+        {
+            bForceUseIntermediateDataset = TRUE;
+            pfnProgress = GDALDummyProgress;
+            bQuiet = TRUE;
+        }
+#ifdef S_ISFIFO
+        else
+        {
+            VSIStatBufL sStat;
+            if( VSIStatExL(pszDstFilename, &sStat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
+                S_ISFIFO(sStat.st_mode) )
+            {
+                bForceUseIntermediateDataset = TRUE;
+            }
+        }
+#endif
     }
 
-    if( (bForceUseIntermediateDataset || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL) &&
-        GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL)
+    if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+        ((bForceUseIntermediateDataset || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) == NULL) &&
+         GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
     {
         GDALDatasetH hIntermediateDataset;
         
diff --git a/apps/gdalenhance.cpp b/apps/gdalenhance.cpp
index 0bbc0f9..2c357d3 100644
--- a/apps/gdalenhance.cpp
+++ b/apps/gdalenhance.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalenhance.cpp 27994 2014-11-21 20:03:49Z rouault $
+ * $Id: gdalenhance.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Commandline application to do image enhancement. 
@@ -35,7 +35,7 @@
 #include "vrtdataset.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: gdalenhance.cpp 27994 2014-11-21 20:03:49Z rouault $");
+CPL_CVSID("$Id: gdalenhance.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 static int
 ComputeEqualizationLUTs( GDALDatasetH hDataset,  int nLUTBins,
@@ -89,7 +89,7 @@ int main( int argc, char ** argv )
     GDALDatasetH	hDataset, hOutDS;
     int			i;
     const char		*pszSource=NULL, *pszDest=NULL, *pszFormat = "GTiff";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     GDALDriverH		hDriver;
     GDALDataType	eOutputType = GDT_Unknown;
     char                **papszCreateOptions = NULL;
@@ -130,7 +130,7 @@ int main( int argc, char ** argv )
         else if( EQUAL(argv[i],"-of") && i < argc-1 )
         {
             pszFormat = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
         }
 
         else if( EQUAL(argv[i],"-ot") && i < argc-1 )
@@ -252,9 +252,9 @@ int main( int argc, char ** argv )
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
 
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
-                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY,
-                                        NULL ) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                (GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL
+                || GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, NULL ) != NULL) )
             {
                 printf( "  %s: %s\n",
                         GDALGetDriverShortName( hDriver  ),
@@ -265,7 +265,7 @@ int main( int argc, char ** argv )
         Usage();
     }
 
-    if (!bQuiet && pszDest != NULL && !bFormatExplicitelySet)
+    if (!bQuiet && pszDest != NULL && !bFormatExplicitlySet)
         CheckExtensionConsistency(pszDest, pszFormat);
 
 /* -------------------------------------------------------------------- */
@@ -311,8 +311,8 @@ int main( int argc, char ** argv )
 
             // Process scale min/max
 
-            padfScaleMin[iBand] = atof(papszTokens[1]);
-            padfScaleMax[iBand] = atof(papszTokens[2]);
+            padfScaleMin[iBand] = CPLAtof(papszTokens[1]);
+            padfScaleMax[iBand] = CPLAtof(papszTokens[2]);
 
             if( CSLCount(papszTokens) == 3 )
                 continue;
@@ -490,7 +490,7 @@ ComputeEqualizationLUTs( GDALDatasetH hDataset, int nLUTBins,
     int iBand;
     int nBandCount = GDALGetRasterCount(hDataset);
     int nHistSize = 0;
-    int *panHistogram = NULL;
+    GUIntBig *panHistogram = NULL;
 
     // For now we always compute min/max
     *ppadfScaleMin = (double *) CPLCalloc(sizeof(double),nBandCount);
@@ -510,7 +510,7 @@ ComputeEqualizationLUTs( GDALDatasetH hDataset, int nLUTBins,
 /*      Get a reasonable histogram.                                     */
 /* -------------------------------------------------------------------- */
         eErr =
-            GDALGetDefaultHistogram( hBand, 
+            GDALGetDefaultHistogramEx( hBand, 
                                      *ppadfScaleMin + iBand,
                                      *ppadfScaleMax + iBand,
                                      &nHistSize, &panHistogram, 
@@ -527,8 +527,8 @@ ComputeEqualizationLUTs( GDALDatasetH hDataset, int nLUTBins,
 /*      We take care to use big integers as there may be more than 4    */
 /*      Gigapixels.                                                     */
 /* -------------------------------------------------------------------- */
-        GIntBig *panCumHist = (GIntBig *) CPLCalloc(sizeof(GIntBig),nHistSize);
-        GIntBig nTotal = 0;
+        GUIntBig *panCumHist = (GUIntBig *) CPLCalloc(sizeof(GUIntBig),nHistSize);
+        GUIntBig nTotal = 0;
         int iHist;
 
         for( iHist = 0; iHist < nHistSize; iHist++ )
@@ -593,7 +593,7 @@ static CPLErr EnhancerCallback( void *hCBData,
 
     eErr = psEInfo->poSrcBand->
         RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize,
-                  pafSrcImage, nXSize, nYSize, GDT_Float32, 0, 0 );
+                  pafSrcImage, nXSize, nYSize, GDT_Float32, 0, 0, NULL );
 
     if( eErr != CE_None )
     {
diff --git a/apps/gdalflattenmask.c b/apps/gdalflattenmask.c
index 397545e..3323633 100644
--- a/apps/gdalflattenmask.c
+++ b/apps/gdalflattenmask.c
@@ -95,7 +95,7 @@ int main(int argc, char* argv[])
         else if( EQUAL(argv[i],"-a_nodata") && i < argc - 1 )
         {
             bSetNoData = TRUE;
-            dfDstNoData = atof(argv[++i]);
+            dfDstNoData = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i], "-set_alpha"))
         {
diff --git a/apps/gdalinfo.c b/apps/gdalinfo.c
index a4e3f94..b02b911 100644
--- a/apps/gdalinfo.c
+++ b/apps/gdalinfo.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalinfo.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalinfo.c 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Commandline application to list info about a file.
@@ -36,7 +36,7 @@
 #include "cpl_multiproc.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: gdalinfo.c 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalinfo.c 28899 2015-04-14 09:27:00Z rouault $");
 
 static int 
 GDALInfoReportCorner( GDALDatasetH hDataset, 
@@ -44,6 +44,13 @@ GDALInfoReportCorner( GDALDatasetH hDataset,
                       const char * corner_name,
                       double x, double y );
 
+static void
+GDALInfoReportMetadata( GDALMajorObjectH hObject,
+                        int bListMDD,
+                        int bShowMetadata,
+                        char **papszExtraMDDomains,
+                        int bIsBand );
+
 /************************************************************************/
 /*                               Usage()                                */
 /************************************************************************/
@@ -54,7 +61,7 @@ void Usage(const char* pszErrorMsg)
     printf( "Usage: gdalinfo [--help-general] [-mm] [-stats] [-hist] [-nogcp] [-nomd]\n"
             "                [-norat] [-noct] [-nofl] [-checksum] [-proj4]\n"
             "                [-listmdd] [-mdd domain|`all`]*\n"
-            "                [-sd subdataset] datasetname\n" );
+            "                [-sd subdataset] [-oo NAME=VALUE]* datasetname\n" );
 
     if( pszErrorMsg != NULL )
         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
@@ -78,10 +85,9 @@ int main( int argc, char ** argv )
     int			i, iBand;
     double		adfGeoTransform[6];
     GDALDriverH		hDriver;
-    char		**papszMetadata;
     int                 bComputeMinMax = FALSE, bSample = FALSE;
     int                 bShowGCPs = TRUE, bShowMetadata = TRUE, bShowRAT=TRUE;
-    int                 bStats = FALSE, bApproxStats = TRUE, iMDD;
+    int                 bStats = FALSE, bApproxStats = TRUE;
     int                 bShowColorTable = TRUE, bComputeChecksum = FALSE;
     int                 bReportHistograms = FALSE;
     int                 bReportProj4 = FALSE;
@@ -92,6 +98,7 @@ int main( int argc, char ** argv )
     const char  *pszProjection = NULL;
     OGRCoordinateTransformationH hTransform = NULL;
     int             bShowFileList = TRUE;
+    char              **papszOpenOptions = NULL;
 
     /* Check that we are running against at least GDAL 1.5 */
     /* Note to developers : if we use newer API, please change the requirement */
@@ -159,6 +166,12 @@ int main( int argc, char ** argv )
             papszExtraMDDomains = CSLAddString( papszExtraMDDomains,
                                                 argv[++i] );
         }
+        else if( EQUAL(argv[i], "-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                argv[++i] );
+        }
         else if( EQUAL(argv[i], "-nofl") )
             bShowFileList = FALSE;
         else if( EQUAL(argv[i], "-sd") )
@@ -180,7 +193,8 @@ int main( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
 /*      Open dataset.                                                   */
 /* -------------------------------------------------------------------- */
-    hDataset = GDALOpen( pszFilename, GA_ReadOnly );
+    hDataset = GDALOpenEx( pszFilename, GDAL_OF_READONLY | GDAL_OF_RASTER, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
 
     if( hDataset == NULL )
     {
@@ -213,6 +227,7 @@ int main( int argc, char ** argv )
 
         CSLDestroy( argv );
         CSLDestroy( papszExtraMDDomains );
+        CSLDestroy( papszOpenOptions );
     
         GDALDumpOpenDatasets( stderr );
 
@@ -324,14 +339,14 @@ int main( int argc, char ** argv )
     {
         if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 )
         {
-            printf( "Origin = (%.15f,%.15f)\n",
+            CPLprintf( "Origin = (%.15f,%.15f)\n",
                     adfGeoTransform[0], adfGeoTransform[3] );
 
-            printf( "Pixel Size = (%.15f,%.15f)\n",
+            CPLprintf( "Pixel Size = (%.15f,%.15f)\n",
                     adfGeoTransform[1], adfGeoTransform[5] );
         }
         else
-            printf( "GeoTransform =\n"
+            CPLprintf( "GeoTransform =\n"
                     "  %.16g, %.16g, %.16g\n"
                     "  %.16g, %.16g, %.16g\n", 
                     adfGeoTransform[0],
@@ -376,7 +391,7 @@ int main( int argc, char ** argv )
             
             psGCP = GDALGetGCPs( hDataset ) + i;
 
-            printf( "GCP[%3d]: Id=%s, Info=%s\n"
+            CPLprintf( "GCP[%3d]: Id=%s, Info=%s\n"
                     "          (%.15g,%.15g) -> (%.15g,%.15g,%.15g)\n", 
                     i, psGCP->pszId, psGCP->pszInfo, 
                     psGCP->dfGCPPixel, psGCP->dfGCPLine, 
@@ -388,125 +403,8 @@ int main( int argc, char ** argv )
 /*      Report metadata.                                                */
 /* -------------------------------------------------------------------- */
 
-    if( bListMDD )
-    {
-        char** papszMDDList = GDALGetMetadataDomainList( hDataset );
-        char** papszIter = papszMDDList;
-
-        if( papszMDDList != NULL )
-            printf( "Metadata domains:\n" );
-        while( papszIter != NULL && *papszIter != NULL )
-        {
-            if( EQUAL(*papszIter, "") )
-                printf( "  (default)\n");
-            else
-                printf( "  %s\n", *papszIter );
-            papszIter ++;
-        }
-        CSLDestroy(papszMDDList);
-    }
-
-    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, NULL ) : NULL;
-    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-    {
-        printf( "Metadata:\n" );
-        for( i = 0; papszMetadata[i] != NULL; i++ )
-        {
-            printf( "  %s\n", papszMetadata[i] );
-        }
-    }
-
-    if( papszExtraMDDomains != NULL && EQUAL(papszExtraMDDomains[0], "all") &&
-        papszExtraMDDomains[1] == NULL )
-    {
-        char** papszMDDList = GDALGetMetadataDomainList( hDataset );
-        char** papszIter = papszMDDList;
-
-        CSLDestroy(papszExtraMDDomains);
-        papszExtraMDDomains = NULL;
+    GDALInfoReportMetadata( hDataset, bListMDD, bShowMetadata, papszExtraMDDomains, FALSE);
 
-        while( papszIter != NULL && *papszIter != NULL )
-        {
-            if( !EQUAL(*papszIter, "") &&
-                !EQUAL(*papszIter, "IMAGE_STRUCTURE") &&
-                !EQUAL(*papszIter, "SUBDATASETS") &&
-                !EQUAL(*papszIter, "GEOLOCATION") &&
-                !EQUAL(*papszIter, "RPC") )
-            {
-                papszExtraMDDomains = CSLAddString(papszExtraMDDomains, *papszIter);
-            }
-            papszIter ++;
-        }
-        CSLDestroy(papszMDDList);
-    }
-
-    for( iMDD = 0; bShowMetadata && iMDD < CSLCount(papszExtraMDDomains); iMDD++ )
-    {
-        papszMetadata = GDALGetMetadata( hDataset, papszExtraMDDomains[iMDD] );
-        if( CSLCount(papszMetadata) > 0 )
-        {
-            printf( "Metadata (%s):\n", papszExtraMDDomains[iMDD]);
-            for( i = 0; papszMetadata[i] != NULL; i++ )
-            {
-                if (EQUALN(papszExtraMDDomains[iMDD], "xml:", 4))
-                    printf( "%s\n", papszMetadata[i] );
-                else
-                    printf( "  %s\n", papszMetadata[i] );
-            }
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Report "IMAGE_STRUCTURE" metadata.                              */
-/* -------------------------------------------------------------------- */
-    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "IMAGE_STRUCTURE" ) : NULL;
-    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-    {
-        printf( "Image Structure Metadata:\n" );
-        for( i = 0; papszMetadata[i] != NULL; i++ )
-        {
-            printf( "  %s\n", papszMetadata[i] );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Report subdatasets.                                             */
-/* -------------------------------------------------------------------- */
-    papszMetadata = GDALGetMetadata( hDataset, "SUBDATASETS" );
-    if( CSLCount(papszMetadata) > 0 )
-    {
-        printf( "Subdatasets:\n" );
-        for( i = 0; papszMetadata[i] != NULL; i++ )
-        {
-            printf( "  %s\n", papszMetadata[i] );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Report geolocation.                                             */
-/* -------------------------------------------------------------------- */
-    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "GEOLOCATION" ) : NULL;
-    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-    {
-        printf( "Geolocation:\n" );
-        for( i = 0; papszMetadata[i] != NULL; i++ )
-        {
-            printf( "  %s\n", papszMetadata[i] );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Report RPCs                                                     */
-/* -------------------------------------------------------------------- */
-    papszMetadata = (bShowMetadata) ? GDALGetMetadata( hDataset, "RPC" ) : NULL;
-    if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-    {
-        printf( "RPC Metadata:\n" );
-        for( i = 0; papszMetadata[i] != NULL; i++ )
-        {
-            printf( "  %s\n", papszMetadata[i] );
-        }
-    }
 
 /* -------------------------------------------------------------------- */
 /*      Setup projected to lat/long transform if appropriate.           */
@@ -599,9 +497,9 @@ int main( int argc, char ** argv )
         {
             printf( "  " );
             if( bGotMin )
-                printf( "Min=%.3f ", dfMin );
+                CPLprintf( "Min=%.3f ", dfMin );
             if( bGotMax )
-                printf( "Max=%.3f ", dfMax );
+                CPLprintf( "Max=%.3f ", dfMax );
         
             if( bComputeMinMax )
             {
@@ -609,7 +507,7 @@ int main( int argc, char ** argv )
                 GDALComputeRasterMinMax( hBand, FALSE, adfCMinMax );
                 if (CPLGetLastErrorType() == CE_None)
                 {
-                  printf( "  Computed Min/Max=%.3f,%.3f", 
+                  CPLprintf( "  Computed Min/Max=%.3f,%.3f", 
                           adfCMinMax[0], adfCMinMax[1] );
                 }
             }
@@ -621,15 +519,16 @@ int main( int argc, char ** argv )
                                         &dfMin, &dfMax, &dfMean, &dfStdDev );
         if( eErr == CE_None )
         {
-            printf( "  Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f\n",
+            CPLprintf( "  Minimum=%.3f, Maximum=%.3f, Mean=%.3f, StdDev=%.3f\n",
                     dfMin, dfMax, dfMean, dfStdDev );
         }
 
         if( bReportHistograms )
         {
-            int nBucketCount, *panHistogram = NULL;
+            int nBucketCount;
+            GUIntBig *panHistogram = NULL;
 
-            eErr = GDALGetDefaultHistogram( hBand, &dfMin, &dfMax, 
+            eErr = GDALGetDefaultHistogramEx( hBand, &dfMin, &dfMax, 
                                             &nBucketCount, &panHistogram, 
                                             TRUE, GDALTermProgress, NULL );
             if( eErr == CE_None )
@@ -639,7 +538,7 @@ int main( int argc, char ** argv )
                 printf( "  %d buckets from %g to %g:\n  ",
                         nBucketCount, dfMin, dfMax );
                 for( iBucket = 0; iBucket < nBucketCount; iBucket++ )
-                    printf( "%d ", panHistogram[iBucket] );
+                    printf( CPL_FRMT_GUIB " ", panHistogram[iBucket] );
                 printf( "\n" );
                 CPLFree( panHistogram );
             }
@@ -659,7 +558,7 @@ int main( int argc, char ** argv )
             if (CPLIsNan(dfNoData))
                 printf( "  NoData Value=nan\n" );
             else
-                printf( "  NoData Value=%.18g\n", dfNoData );
+                CPLprintf( "  NoData Value=%.18g\n", dfNoData );
         }
 
         if( GDALGetOverviewCount(hBand) > 0 )
@@ -783,46 +682,11 @@ int main( int argc, char ** argv )
 
         if( GDALGetRasterScale( hBand, &bSuccess ) != 1.0 
             || GDALGetRasterOffset( hBand, &bSuccess ) != 0.0 )
-            printf( "  Offset: %.15g,   Scale:%.15g\n",
+            CPLprintf( "  Offset: %.15g,   Scale:%.15g\n",
                     GDALGetRasterOffset( hBand, &bSuccess ),
                     GDALGetRasterScale( hBand, &bSuccess ) );
 
-        if( bListMDD )
-        {
-            char** papszMDDList = GDALGetMetadataDomainList( hBand );
-            char** papszIter = papszMDDList;
-            if( papszMDDList != NULL )
-                printf( "  Metadata domains:\n" );
-            while( papszIter != NULL && *papszIter != NULL )
-            {
-                if( EQUAL(*papszIter, "") )
-                    printf( "    (default)\n");
-                else
-                    printf( "    %s\n", *papszIter );
-                papszIter ++;
-            }
-            CSLDestroy(papszMDDList);
-        }
-
-        papszMetadata = (bShowMetadata) ? GDALGetMetadata( hBand, NULL ) : NULL;
-        if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-        {
-            printf( "  Metadata:\n" );
-            for( i = 0; papszMetadata[i] != NULL; i++ )
-            {
-                printf( "    %s\n", papszMetadata[i] );
-            }
-        }
-
-        papszMetadata = (bShowMetadata) ? GDALGetMetadata( hBand, "IMAGE_STRUCTURE" ) : NULL;
-        if( bShowMetadata && CSLCount(papszMetadata) > 0 )
-        {
-            printf( "  Image Structure Metadata:\n" );
-            for( i = 0; papszMetadata[i] != NULL; i++ )
-            {
-                printf( "    %s\n", papszMetadata[i] );
-            }
-        }
+        GDALInfoReportMetadata( hBand, bListMDD, bShowMetadata, papszExtraMDDomains, TRUE);
 
         if( GDALGetRasterColorInterpretation(hBand) == GCI_PaletteIndex 
             && (hTable = GDALGetRasterColorTable( hBand )) != NULL )
@@ -862,6 +726,7 @@ int main( int argc, char ** argv )
     GDALClose( hDataset );
     
     CSLDestroy( papszExtraMDDomains );
+    CSLDestroy( papszOpenOptions );
     CSLDestroy( argv );
     
     GDALDumpOpenDatasets( stderr );
@@ -903,7 +768,7 @@ GDALInfoReportCorner( GDALDatasetH hDataset,
 
     else
     {
-        printf( "(%7.1f,%7.1f)\n", x, y );
+        CPLprintf( "(%7.1f,%7.1f)\n", x, y );
         return FALSE;
     }
 
@@ -912,11 +777,11 @@ GDALInfoReportCorner( GDALDatasetH hDataset,
 /* -------------------------------------------------------------------- */
     if( ABS(dfGeoX) < 181 && ABS(dfGeoY) < 91 )
     {
-        printf( "(%12.7f,%12.7f) ", dfGeoX, dfGeoY );
+        CPLprintf( "(%12.7f,%12.7f) ", dfGeoX, dfGeoY );
     }
     else
     {
-        printf( "(%12.3f,%12.3f) ", dfGeoX, dfGeoY );
+        CPLprintf( "(%12.3f,%12.3f) ", dfGeoX, dfGeoY );
     }
 
 /* -------------------------------------------------------------------- */
@@ -934,3 +799,131 @@ GDALInfoReportCorner( GDALDatasetH hDataset,
 
     return TRUE;
 }
+
+
+/************************************************************************/
+/*                       GDALInfoPrintMetadata()                        */
+/************************************************************************/
+static void GDALInfoPrintMetadata( GDALMajorObjectH hObject,
+                                   const char *pszDomain,
+                                   const char *pszDisplayedname,
+                                   const char *pszIndent)
+{
+    int i;
+    char **papszMetadata;
+    int bIsxml = FALSE;
+
+    if (pszDomain != NULL && EQUALN(pszDomain, "xml:", 4))
+        bIsxml = TRUE;
+
+    papszMetadata = GDALGetMetadata( hObject, pszDomain );
+    if( CSLCount(papszMetadata) > 0 )
+    {
+        printf( "%s%s:\n", pszIndent, pszDisplayedname );
+        for( i = 0; papszMetadata[i] != NULL; i++ )
+        {
+            if (bIsxml)
+                printf( "%s%s\n", pszIndent, papszMetadata[i] );
+            else
+                printf( "%s  %s\n", pszIndent, papszMetadata[i] );
+        }
+    }
+}
+
+/************************************************************************/
+/*                       GDALInfoReportMetadata()                       */
+/************************************************************************/
+static void GDALInfoReportMetadata( GDALMajorObjectH hObject,
+                                    int bListMDD,
+                                    int bShowMetadata,
+                                    char **papszExtraMDDomains,
+                                    int bIsBand )
+{
+    const char* pszIndent = "";
+    if( bIsBand )
+        pszIndent = "  ";
+
+    /* -------------------------------------------------------------------- */
+    /*      Report list of Metadata domains                                 */
+    /* -------------------------------------------------------------------- */
+    if( bListMDD )
+    {
+        char** papszMDDList = GDALGetMetadataDomainList( hObject );
+        char** papszIter = papszMDDList;
+
+        if( papszMDDList != NULL )
+            printf( "%sMetadata domains:\n", pszIndent );
+        while( papszIter != NULL && *papszIter != NULL )
+        {
+            if( EQUAL(*papszIter, "") )
+                printf( "%s  (default)\n", pszIndent);
+            else
+                printf( "%s  %s\n", pszIndent, *papszIter );
+            papszIter ++;
+        }
+        CSLDestroy(papszMDDList);
+    }
+
+    if (!bShowMetadata)
+        return;
+
+    /* -------------------------------------------------------------------- */
+    /*      Report default Metadata domain.                                 */
+    /* -------------------------------------------------------------------- */
+    GDALInfoPrintMetadata( hObject, NULL, "Metadata", pszIndent );
+
+    /* -------------------------------------------------------------------- */
+    /*      Report extra Metadata domains                                   */
+    /* -------------------------------------------------------------------- */
+    if (papszExtraMDDomains != NULL) {
+        char **papszExtraMDDomainsExpanded = NULL;
+        int iMDD;
+
+        if( EQUAL(papszExtraMDDomains[0], "all") &&
+            papszExtraMDDomains[1] == NULL )
+        {
+            char** papszMDDList = GDALGetMetadataDomainList( hObject );
+            char** papszIter = papszMDDList;
+
+            while( papszIter != NULL && *papszIter != NULL )
+            {
+                if( !EQUAL(*papszIter, "") &&
+                    !EQUAL(*papszIter, "IMAGE_STRUCTURE") &&
+                    !EQUAL(*papszIter, "SUBDATASETS") &&
+                    !EQUAL(*papszIter, "GEOLOCATION") &&
+                    !EQUAL(*papszIter, "RPC") )
+                {
+                    papszExtraMDDomainsExpanded = CSLAddString(papszExtraMDDomainsExpanded, *papszIter);
+                }
+                papszIter ++;
+            }
+            CSLDestroy(papszMDDList);
+        }
+        else
+        {
+            papszExtraMDDomainsExpanded = CSLDuplicate(papszExtraMDDomains);
+        }
+
+        for( iMDD = 0; iMDD < CSLCount(papszExtraMDDomainsExpanded); iMDD++ )
+        {
+            char pszDisplayedname[256];
+            snprintf(pszDisplayedname, 256, "Metadata (%s)", papszExtraMDDomainsExpanded[iMDD]);
+            GDALInfoPrintMetadata( hObject, papszExtraMDDomainsExpanded[iMDD], pszDisplayedname, pszIndent );
+        }
+
+        CSLDestroy(papszExtraMDDomainsExpanded);
+    }
+
+    /* -------------------------------------------------------------------- */
+    /*      Report various named metadata domains.                          */
+    /* -------------------------------------------------------------------- */
+    GDALInfoPrintMetadata( hObject, "IMAGE_STRUCTURE", "Image Structure Metadata", pszIndent );
+
+    if (!bIsBand)
+    {
+        GDALInfoPrintMetadata( hObject, "SUBDATASETS", "Subdatasets", pszIndent );
+        GDALInfoPrintMetadata( hObject, "GEOLOCATION", "Geolocation", pszIndent );
+        GDALInfoPrintMetadata( hObject, "RPC", "RPC Metadata", pszIndent );
+    }
+
+}
diff --git a/apps/gdallocationinfo.cpp b/apps/gdallocationinfo.cpp
index d1ae8be..61ad025 100644
--- a/apps/gdallocationinfo.cpp
+++ b/apps/gdallocationinfo.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdallocationinfo.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdallocationinfo.cpp 28800 2015-03-27 21:03:41Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Commandline raster query tool.
@@ -34,7 +34,7 @@
 #include "cpl_minixml.h"
 #include <vector>
 
-CPL_CVSID("$Id: gdallocationinfo.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdallocationinfo.cpp 28800 2015-03-27 21:03:41Z rouault $");
 
 /******************************************************************************/
 /*! \page gdallocationinfo gdallocationinfo
@@ -51,7 +51,7 @@ Usage:
 Usage: gdallocationinfo [--help-general] [-xml] [-lifonly] [-valonly]
                         [-b band]* [-overview overview_level]
                         [-l_srs srs_def] [-geoloc] [-wgs84]
-                        srcfile [x y]
+                        [-oo NAME=VALUE]* srcfile [x y]
 \endverbatim
 
 \section gdallocationinfo_description DESCRIPTION
@@ -92,6 +92,9 @@ pixel/line) must still be given with respect to the base band.</dd>
 <dt> <b>-wgs84</b>:</dt>
 <dd> Indicates input x,y points are WGS84 long, lat.</dd>
 
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt>
+<dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
+
 <dt> <em>srcfile</em>:</dt><dd> The source GDAL raster datasource name.</dd>
 
 <dt> <em>x</em>:</dt><dd> X location of target pixel.  By default the 
@@ -173,7 +176,7 @@ static void Usage()
     printf( "Usage: gdallocationinfo [--help-general] [-xml] [-lifonly] [-valonly]\n"
             "                        [-b band]* [-overview overview_level]\n"
             "                        [-l_srs srs_def] [-geoloc] [-wgs84]\n"
-            "                        srcfile x y\n" 
+            "                        [-oo NAME=VALUE]* srcfile x y\n" 
             "\n" );
     exit( 1 );
 }
@@ -220,6 +223,7 @@ int main( int argc, char ** argv )
     bool               bAsXML = false, bLIFOnly = false;
     bool               bQuiet = false, bValOnly = false;
     int                nOverview = -1;
+    char             **papszOpenOptions = NULL;
 
     GDALAllRegister();
     argc = GDALGeneralCmdLineProcessor( argc, &argv, 0 );
@@ -276,6 +280,11 @@ int main( int argc, char ** argv )
             bValOnly = true;
             bQuiet = true;
         }
+        else if( EQUAL(argv[i], "-oo") && i < argc-1 )
+        {
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                argv[++i] );
+        }
         else if( argv[i][0] == '-' && !isdigit(argv[i][1]) )
             Usage();
 
@@ -300,7 +309,8 @@ int main( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
     GDALDatasetH hSrcDS = NULL;
 
-    hSrcDS = GDALOpen( pszSrcFilename, GA_ReadOnly );
+    hSrcDS = GDALOpenEx( pszSrcFilename, GDAL_OF_RASTER, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
     if( hSrcDS == NULL )
         exit( 1 );
 
@@ -616,6 +626,7 @@ int main( int argc, char ** argv )
     GDALDumpOpenDatasets( stderr );
     GDALDestroyDriverManager();
     CPLFree(pszSourceSRS);
+    CSLDestroy(papszOpenOptions);
 
     CSLDestroy( argv );
 
diff --git a/apps/gdalserver.c b/apps/gdalserver.c
index b7ce6db..7202e2e 100644
--- a/apps/gdalserver.c
+++ b/apps/gdalserver.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalserver.c 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: gdalserver.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GDAL
  * Purpose:  Server application that is forked by libgdal
@@ -77,7 +77,7 @@ int CPL_DLL GDALServerLoop(CPL_FILE_HANDLE fin, CPL_FILE_HANDLE fout);
 int CPL_DLL GDALServerLoopSocket(CPL_SOCKET nSocket);
 CPL_C_END
 
-CPL_CVSID("$Id: gdalserver.c 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: gdalserver.c 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                               Usage()                                */
diff --git a/apps/gdalsrsinfo.cpp b/apps/gdalsrsinfo.cpp
index 55e17f4..0a2fc08 100644
--- a/apps/gdalsrsinfo.cpp
+++ b/apps/gdalsrsinfo.cpp
@@ -115,68 +115,6 @@ int main( int argc, char ** argv )
 #endif
 
 /* -------------------------------------------------------------------- */
-/*      Process --formats option.                                       */
-/*      Code copied from gcore/gdal_misc.cpp and ogr/ogrutils.cpp.      */
-/*      This is not ideal, but is best for more descriptive output and  */
-/*      we don't want to call OGRGeneralCmdLineProcessor().             */
-/* -------------------------------------------------------------------- */ 
-   for( i = 1; i < argc; i++ )
-    {        
-        if( EQUAL(argv[i], "--formats") )
-        {
-            int iDr;
-            
-            /* GDAL formats */
-            printf( "Supported Raster Formats:\n" );
-            for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
-            {
-                GDALDriverH hDriver = GDALGetDriver(iDr);
-                const char *pszRWFlag, *pszVirtualIO;
-                
-                if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) )
-                    pszRWFlag = "rw+";
-                else if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, 
-                                              NULL ) )
-                    pszRWFlag = "rw";
-                else
-                    pszRWFlag = "ro";
-                
-                if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL) )
-                    pszVirtualIO = "v";
-                else
-                    pszVirtualIO = "";
-                
-                printf( "  %s (%s%s): %s\n",
-                        GDALGetDriverShortName( hDriver ),
-                        pszRWFlag, pszVirtualIO,
-                        GDALGetDriverLongName( hDriver ) );
-            }
-
-            /* OGR formats */
-#ifdef OGR_ENABLED
-            printf( "\nSupported Vector Formats:\n" );
-            
-            OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
-            
-            for( iDr = 0; iDr < poR->GetDriverCount(); iDr++ )
-            {
-                OGRSFDriver *poDriver = poR->GetDriver(iDr);
-                
-                if( poDriver->TestCapability( ODrCCreateDataSource ) )
-                    printf( "  -> \"%s\" (read/write)\n", 
-                            poDriver->GetName() );
-                else
-                    printf( "  -> \"%s\" (readonly)\n", 
-                            poDriver->GetName() );
-            }
-            
-#endif
-            exit(1);
-            
-        }
-    }
-
-/* -------------------------------------------------------------------- */
 /*      Register standard GDAL drivers, and process generic GDAL        */
 /*      command options.                                                */
 /* -------------------------------------------------------------------- */
@@ -326,17 +264,14 @@ int FindSRS( const char *pszInput, OGRSpatialReference &oSRS )
     int            bGotSRS = FALSE;
     VSILFILE      *fp = NULL;
     GDALDataset	  *poGDALDS = NULL; 
-#ifdef OGR_ENABLED
-    OGRDataSource *poOGRDS = NULL;
     OGRLayer      *poLayer = NULL;
-#endif
-    char           *pszProjection = NULL;
+    const char    *pszProjection = NULL;
     CPLErrorHandler oErrorHandler = NULL;
     int bIsFile = FALSE;
     OGRErr eErr = CE_None;
     int bDebug  = FALSE;
 
-    /* temporarily supress error messages we may get from xOpen() */
+    /* temporarily suppress error messages we may get from xOpen() */
     bDebug = CSLTestBoolean(CPLGetConfigOption("CPL_DEBUG", "OFF"));
     if ( ! bDebug )
         oErrorHandler = CPLSetErrorHandler ( CPLQuietErrorHandler );
@@ -354,30 +289,21 @@ int FindSRS( const char *pszInput, OGRSpatialReference &oSRS )
                 strlen("http://spatialreference.org/")) != 0 )
     {
         CPLDebug( "gdalsrsinfo", "trying to open with GDAL" );
-        poGDALDS = (GDALDataset *) GDALOpen( pszInput, GA_ReadOnly );
+        poGDALDS = (GDALDataset *) GDALOpenEx( pszInput, 0, NULL, NULL, NULL );
     }
-    if ( poGDALDS != NULL && poGDALDS->GetProjectionRef( ) != NULL ) {
-        pszProjection = (char *) poGDALDS->GetProjectionRef( );
-        if( oSRS.importFromWkt( &pszProjection ) == CE_None ) {
-            CPLDebug( "gdalsrsinfo", "got SRS from GDAL" );
-            bGotSRS = TRUE;
-        }
-        GDALClose( (GDALDatasetH) poGDALDS );
-        if ( ! bGotSRS ) 
-            CPLDebug( "gdalsrsinfo", "did not open with GDAL" );
-    }    
-    
-#ifdef OGR_ENABLED
-    /* if unsuccessful, try to open with OGR */
-    if ( ! bGotSRS ) {
-        if( strncmp(pszInput, "http://spatialreference.org/",
-                    strlen("http://spatialreference.org/")) != 0 )
+    if ( poGDALDS != NULL ) {
+        pszProjection = poGDALDS->GetProjectionRef( );
+        if( pszProjection != NULL && pszProjection[0] != '\0' )
         {
-            CPLDebug( "gdalsrsinfo", "trying to open with OGR" );
-            poOGRDS = OGRSFDriverRegistrar::Open( pszInput, FALSE, NULL );
+            char* pszProjectionTmp = (char*) pszProjection;
+            if( oSRS.importFromWkt( &pszProjectionTmp ) == CE_None ) {
+                CPLDebug( "gdalsrsinfo", "got SRS from GDAL" );
+                bGotSRS = TRUE;
+            }
         }
-        if( poOGRDS != NULL ) {
-            poLayer = poOGRDS->GetLayer( 0 );
+        else if( poGDALDS->GetLayerCount() > 0 )
+        {
+            poLayer = poGDALDS->GetLayer( 0 );
             if ( poLayer != NULL ) {
                 OGRSpatialReference *poSRS = poLayer->GetSpatialRef( );
                 if ( poSRS != NULL ) {
@@ -388,13 +314,11 @@ int FindSRS( const char *pszInput, OGRSpatialReference &oSRS )
                     OGRSpatialReference::DestroySpatialReference( poSRSClone );
                 }
             }
-            OGRDataSource::DestroyDataSource( poOGRDS );
-            poOGRDS = NULL;
-        } 
+        }
+        GDALClose( (GDALDatasetH) poGDALDS );
         if ( ! bGotSRS ) 
-            CPLDebug( "gdalsrsinfo", "did not open with OGR" );
-    }
-#endif // OGR_ENABLED
+            CPLDebug( "gdalsrsinfo", "did not open with GDAL" );
+    }    
     
     /* Try ESRI file */
     if ( ! bGotSRS && bIsFile && (strstr(pszInput,".prj") != NULL) ) {
diff --git a/apps/gdaltindex.c b/apps/gdaltindex.c
index 1cbb100..1810d59 100644
--- a/apps/gdaltindex.c
+++ b/apps/gdaltindex.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaltindex.c 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: gdaltindex.c 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  MapServer
  * Purpose:  Commandline App to build tile index for raster files.
@@ -35,7 +35,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdaltindex.c 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: gdaltindex.c 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                               Usage()                                */
@@ -352,7 +352,7 @@ int main(int argc, char *argv[])
         i_SrcSRSName = OGR_FD_GetFieldIndex( hFDefn, pszSrcSRSName );
 
     /* Load in memory existing file names in SHP */
-    nExistingFiles = OGR_L_GetFeatureCount(hLayer, FALSE);
+    nExistingFiles = (int)OGR_L_GetFeatureCount(hLayer, FALSE);
     if( nExistingFiles < 0)
         nExistingFiles = 0;
     if (nExistingFiles > 0)
diff --git a/apps/gdaltransform.cpp b/apps/gdaltransform.cpp
index dced22a..b2dfb0a 100644
--- a/apps/gdaltransform.cpp
+++ b/apps/gdaltransform.cpp
@@ -45,7 +45,7 @@ static void Usage(const char* pszErrorMsg = NULL)
         "Usage: gdaltransform [--help-general]\n"
         "    [-i] [-s_srs srs_def] [-t_srs srs_def] [-to \"NAME=VALUE\"]\n"
         "    [-order n] [-tps] [-rpc] [-geoloc] \n"
-        "    [-gcp pixel line easting northing [elevation]]*\n" 
+        "    [-gcp pixel line easting northing [elevation]]* [-output_xy]\n" 
         "    [srcfile [dstfile]]\n" 
         "\n" );
 
@@ -103,6 +103,7 @@ int main( int argc, char ** argv )
     GDAL_GCP            *pasGCPs = NULL;
     int                 bInverse = FALSE;
     char              **papszTO = NULL;
+    int                 bOutputXY = FALSE;
 
     /* Check that we are running against at least GDAL 1.5 */
     /* Note to developers : if we use newer API, please change the requirement */
@@ -186,21 +187,26 @@ int main( int argc, char ** argv )
                 CPLRealloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
             GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
 
-            pasGCPs[nGCPCount-1].dfGCPPixel = atof(argv[++i]);
-            pasGCPs[nGCPCount-1].dfGCPLine = atof(argv[++i]);
-            pasGCPs[nGCPCount-1].dfGCPX = atof(argv[++i]);
-            pasGCPs[nGCPCount-1].dfGCPY = atof(argv[++i]);
+            pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtof(argv[++i]);
+            pasGCPs[nGCPCount-1].dfGCPLine = CPLAtof(argv[++i]);
+            pasGCPs[nGCPCount-1].dfGCPX = CPLAtof(argv[++i]);
+            pasGCPs[nGCPCount-1].dfGCPY = CPLAtof(argv[++i]);
             if( argv[i+1] != NULL 
                 && (CPLStrtod(argv[i+1], &endptr) != 0.0 || argv[i+1][0] == '0') )
             {
                 /* Check that last argument is really a number and not a filename */
                 /* looking like a number (see ticket #863) */
                 if (endptr && *endptr == 0)
-                    pasGCPs[nGCPCount-1].dfGCPZ = atof(argv[++i]);
+                    pasGCPs[nGCPCount-1].dfGCPZ = CPLAtof(argv[++i]);
             }
 
             /* should set id and info? */
         }   
+        
+        else if( EQUAL(argv[i],"-output_xy") )
+        {
+            bOutputXY = TRUE;
+        }
 
         else if( argv[i][0] == '-' )
             Usage(CPLSPrintf("Unknown option name '%s'", argv[i]));
@@ -290,16 +296,19 @@ int main( int argc, char ** argv )
             continue;
         }
 
-        dfX = atof(papszTokens[0]);
-        dfY = atof(papszTokens[1]);
+        dfX = CPLAtof(papszTokens[0]);
+        dfY = CPLAtof(papszTokens[1]);
         if( CSLCount(papszTokens) >= 3 )
-            dfZ = atof(papszTokens[2]);
+            dfZ = CPLAtof(papszTokens[2]);
 
         if( pfnTransformer( hTransformArg, bInverse, 1, 
                             &dfX, &dfY, &dfZ, &bSuccess )
             && bSuccess )
         {
-            printf( "%.15g %.15g %.15g\n", dfX, dfY, dfZ );
+            if( bOutputXY )
+                CPLprintf( "%.15g %.15g\n", dfX, dfY );
+            else
+                CPLprintf( "%.15g %.15g %.15g\n", dfX, dfY, dfZ );
         }
         else
         {
diff --git a/apps/gdalwarp.cpp b/apps/gdalwarp.cpp
index 5b9e34e..3f22127 100644
--- a/apps/gdalwarp.cpp
+++ b/apps/gdalwarp.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarp.cpp 28186 2014-12-20 21:14:58Z rouault $
+ * $Id: gdalwarp.cpp 29144 2015-05-04 09:22:47Z rouault $
  *
  * Project:  High Performance Image Reprojector
  * Purpose:  Test program for high performance warper API.
@@ -34,9 +34,10 @@
 #include "ogr_spatialref.h"
 #include "ogr_api.h"
 #include "commonutils.h"
+#include "gdal_priv.h"
 #include <vector>
 
-CPL_CVSID("$Id: gdalwarp.cpp 28186 2014-12-20 21:14:58Z rouault $");
+CPL_CVSID("$Id: gdalwarp.cpp 29144 2015-05-04 09:22:47Z rouault $");
 
 static void
 LoadCutline( const char *pszCutlineDSName, const char *pszCLayer, 
@@ -52,7 +53,8 @@ GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
                       char ***ppapszCreateOptions, GDALDataType eDT,
                       void ** phTransformArg,
                       GDALDatasetH* phSrcDS,
-                      int bSetColorInterpretation );
+                      int bSetColorInterpretation,
+                      char** papszOpenOptions );
 
 static void 
 RemoveConflictingMetadata( GDALMajorObjectH hObj, char **papszMetadata,
@@ -82,14 +84,15 @@ gdalwarp [--help-general] [--formats]
     [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
     [-order n | -tps | -rpc | -geoloc] [-et err_threshold]
     [-refine_gcps tolerance [minimum_gcps]]
-    [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]
-    [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
+    [-te xmin ymin xmax ymax] [-te_srs srs_def]
+    [-tr xres yres] [-tap] [-ts width height]
+    [-ovr level|AUTO|AUTO-n|NONE] [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
     [-srcnodata "value [value...]"] [-dstnodata "value [value...]"] -dstalpha
     [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]
     [-cutline datasource] [-cl layer] [-cwhere expression]
     [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]
     [-of format] [-co "NAME=VALUE"]* [-overwrite]
-    [-nomd] [-cvmd meta_conflict_value] [-setci]
+    [-nomd] [-cvmd meta_conflict_value] [-setci] [-oo NAME=VALUE]*
     srcfile* dstfile
 \endverbatim
 
@@ -131,7 +134,17 @@ Not that GCP refinement only works with polynomial interpolation.
 The tolerance is in pixel units if no projection is available, otherwise it is in SRS units.
 If minimum_gcps is not provided, the minimum GCPs according to the polynomial model is used.</dd>
 <dt> <b>-te</b> <em>xmin ymin xmax ymax</em>:</dt><dd> set georeferenced
-extents of output file to be created (in target SRS).</dd>
+extents of output file to be created (in target SRS by default, or in the SRS
+specified with -te_srs)
+</dd>
+<dt> <b>-te_srs</b> <i>srs_def</i>:</dt><dd> (GDAL >= 2.0) Specifies the SRS in
+which to interpret the coordinates given with -te. The <i>srs_def</i> may
+be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file
+containing the WKT.
+This must not be confused with -t_srs which is the target SRS of the output
+dataset. -te_srs is a conveniency e.g. when knowing the output coordinates in a
+geodetic long/lat SRS, but still wanting a result in a projected coordinate system.
+</dd>
 <dt> <b>-tr</b> <em>xres yres</em>:</dt><dd> set output file resolution (in
 target georeferenced units)</dd>
 <dt> <b>-tap</b>:</dt><dd> (GDAL >= 1.8.0) (target aligned pixels) align
@@ -140,7 +153,14 @@ such that the aligned extent includes the minimum extent.</dd>
 <dt> <b>-ts</b> <em>width height</em>:</dt><dd> set output file size in
 pixels and lines. If width or height is set to 0, the other dimension will be
 guessed from the computed resolution. Note that -ts cannot be used with -tr</dd>
-<dt> <b>-wo</b> <em>"NAME=VALUE"</em>:</dt><dd> Set a warp options.  The 
+<dt> <b>-ovr</b> <em>level|AUTO|AUTO-n|NONE></em>:</dt><dd>(GDAL >= 2.0) To
+specify which overview level of source files must be used. The default choice,
+AUTO, will select the overview level whose resolution is the closest to the
+target resolution. Specify an integer value (0-based, i.e. 0=1st overview level) 
+to select a particular level. Specify AUTO-n where n is an integer greater or
+equal to 1, to select an overview level below the AUTO one. Or specify NONE to
+force the base resolution to be used.</dd>
+<dt> <b>-wo</b> <em>"NAME=VALUE"</em>:</dt><dd> Set a warp option.  The 
 GDALWarpOptions::papszWarpOptions docs show all options.  Multiple
  <b>-wo</b> options may be listed.</dd>
 <dt> <b>-ot</b> <em>type</em>:</dt><dd> For the output bands to be of the
@@ -157,6 +177,11 @@ algorithm, worst interpolation quality).</dd>
 <dt><b>lanczos</b></dt>: <dd>Lanczos windowed sinc resampling.</dd>
 <dt><b>average</b></dt>: <dd>average resampling, computes the average of all non-NODATA contributing pixels. (GDAL >= 1.10.0)</dd>
 <dt><b>mode</b></dt>: <dd>mode resampling, selects the value which appears most often of all the sampled points. (GDAL >= 1.10.0)</dd>
+<dt><b>max</b></dt>: <dd>maximum resampling, selects the maximum value from all non-NODATA contributing pixels. (GDAL >= 2.0.0)</dd>
+<dt><b>min</b></dt>: <dd>minimum resampling, selects the minimum value from all non-NODATA contributing pixels. (GDAL >= 2.0.0)</dd>
+<dt><b>med</b></dt>: <dd>median resampling, selects the median value of all non-NODATA contributing pixels. (GDAL >= 2.0.0)</dd>
+<dt><b>q1</b></dt>: <dd>first quartile resampling, selects the first quartile value of all non-NODATA contributing pixels. (GDAL >= 2.0.0)</dd>
+<dt><b>q3</b></dt>: <dd>third quartile resampling, selects the third quartile value of all non-NODATA contributing pixels. (GDAL >= 2.0.0)</dd>
 </dl>
 <dt> <b>-srcnodata</b> <em>value [value...]</em>:</dt><dd> Set nodata masking
 values for input bands (different values can be supplied for each band).  If 
@@ -168,8 +193,8 @@ for output bands (different values can be supplied for each band).  If more
 than one value is supplied all values should be quoted to keep them together
 as a single operating system argument.  New files will be initialized to this
 value and if possible the nodata value will be recorded in the output
-file. Use a value of <tt>None</tt> to ensure that nodata is not defined (GDAL>=2.0).
-If this argument is not used then nodata values will be copied from the source dataset (GDAL>=2.0).</dd>
+file. Use a value of <tt>None</tt> to ensure that nodata is not defined (GDAL>=1.11).
+If this argument is not used then nodata values will be copied from the source dataset (GDAL>=1.11).</dd>
 <dt> <b>-dstalpha</b>:</dt><dd> Create an output alpha band to identify 
 nodata (unset/transparent) pixels. </dd>
 <dt> <b>-wm</b> <em>memory_in_mb</em>:</dt><dd> Set the amount of memory (in
@@ -199,6 +224,7 @@ Items that differ between source datasets will be set to * (see -cvmd option).</
 Value to set metadata items that conflict between source datasets (default is "*"). Use "" to remove conflicting items. </dd>
 <dt> <b>-setci</b>:</dt><dd>(GDAL >= 1.10.0) 
 Set the color interpretation of the bands of the target dataset from the source dataset.</dd>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
 
 <dt> <em>srcfile</em>:</dt><dd> The source file name(s). </dd>
 <dt> <em>dstfile</em>:</dt><dd> The destination file name. </dd>
@@ -206,7 +232,7 @@ Set the color interpretation of the bands of the target dataset from the source
 
 Mosaicing into an existing output file is supported if the output file 
 already exists. The spatial extent of the existing file will not
-be modified to accomodate new data, so you may have to remove it in that case, or
+be modified to accommodate new data, so you may have to remove it in that case, or
 use the -overwrite option.
 
 Polygon cutlines may be used as a mask to restrict the area of the destination file
@@ -235,6 +261,20 @@ projection with a command like this:<p>
 gdalwarp HDF4_SDS:ASTER_L1B:"pg-PR1B0000-2002031402_100_001":2 pg-PR1B0000-2002031402_100_001_2.tif
 \endverbatim
 
+<p>
+\section gdalwarp_seealso SEE ALSO
+
+\if man
+http://trac.osgeo.org/gdal/wiki/UserDocs/GdalWarp :
+\else
+<a href="http://trac.osgeo.org/gdal/wiki/UserDocs/GdalWarp">
+\endif
+Wiki page discussing options and behaviours of gdalwarp
+\if man
+\else
+</a>
+\endif
+
 \if man
 \section gdalwarp_author AUTHORS
 Frank Warmerdam <warmerdam at pobox.com>, Silke Reimer <silke at intevation.de>
@@ -278,17 +318,17 @@ static void Usage(const char* pszErrorMsg = NULL)
         "    [-order n | -tps | -rpc | -geoloc] [-et err_threshold]\n"
         "    [-refine_gcps tolerance [minimum_gcps]]\n"
         "    [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]\n"
-        "    [-wo \"NAME=VALUE\"] [-ot Byte/Int16/...] [-wt Byte/Int16]\n"
+        "    [-ovr level|AUTO|AUTO-n|NONE] [-wo \"NAME=VALUE\"] [-ot Byte/Int16/...] [-wt Byte/Int16]\n"
         "    [-srcnodata \"value [value...]\"] [-dstnodata \"value [value...]\"] -dstalpha\n" 
         "    [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]\n"
         "    [-cutline datasource] [-cl layer] [-cwhere expression]\n"
         "    [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]\n"
         "    [-of format] [-co \"NAME=VALUE\"]* [-overwrite]\n"
-        "    [-nomd] [-cvmd meta_conflict_value]\n"
+        "    [-nomd] [-cvmd meta_conflict_value] [-setci] [-oo NAME=VALUE]*\n"
         "    srcfile* dstfile\n"
         "\n"
         "Available resampling methods:\n"
-        "    near (default), bilinear, cubic, cubicspline, lanczos, average, mode.\n" );
+        "    near (default), bilinear, cubic, cubicspline, lanczos, average, mode,  max, min, med, Q1, Q3.\n" );
 
     if( pszErrorMsg != NULL )
         fprintf(stderr, "\nFAILURE: %s\n", pszErrorMsg);
@@ -337,11 +377,11 @@ int main( int argc, char ** argv )
 {
     GDALDatasetH	hDstDS;
     const char         *pszFormat = "GTiff";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     char              **papszSrcFiles = NULL;
     char               *pszDstFilename = NULL;
     int                 bCreateOutput = FALSE, i;
-    void               *hTransformArg, *hGenImgProjArg=NULL, *hApproxArg=NULL;
+    void               *hTransformArg = NULL;
     char               **papszWarpOptions = NULL;
     double             dfErrorThreshold = 0.125;
     double             dfWarpMemoryLimit = 0.0;
@@ -363,6 +403,9 @@ int main( int argc, char ** argv )
     int                  bCopyBandInfo = TRUE;
     const char           *pszMDConflictValue = "*";
     int                  bSetColorInterpretation = FALSE;
+    char               **papszOpenOptions = NULL;
+    int                  nOvLevel = -2;
+    CPLString            osTE_SRS;
 
     /* Check that we are running against at least GDAL 1.6 */
     /* Note to developers : if we use newer API, please change the requirement */
@@ -385,6 +428,19 @@ int main( int argc, char ** argv )
         GDALExit( -argc );
 
 /* -------------------------------------------------------------------- */
+/*      Set optimal setting for best performance with huge input VRT.   */
+/*      The rationale for 450 is that typical Linux process allow       */
+/*      only 1024 file descriptors per process and we need to keep some */
+/*      spare for shared libraries, etc. so let's go down to 900.       */
+/*      And some datasets may need 2 file descriptors, so divide by 2   */
+/*      for security.                                                   */
+/* -------------------------------------------------------------------- */
+    if( CPLGetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", NULL) == NULL )
+    {
+        CPLSetConfigOption("GDAL_MAX_DATASET_POOL_SIZE", "450");
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Parse arguments.                                                */
 /* -------------------------------------------------------------------- */
     for( i = 1; i < argc; i++ )
@@ -440,7 +496,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             pszFormat = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
             bCreateOutput = TRUE;
             if( EQUAL(pszFormat,"VRT") )
                 bVRT = TRUE;
@@ -472,7 +528,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             papszTO = CSLSetNameValue( papszTO, "REFINE_TOLERANCE", argv[++i] );
-            if(atof(argv[i]) < 0)
+            if(CPLAtof(argv[i]) < 0)
             {
                 Usage("The tolerance for -refine_gcps may not be negative.");
             }
@@ -506,6 +562,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             dfErrorThreshold = CPLAtofM(argv[++i]);
+            papszWarpOptions = CSLAddString( papszWarpOptions, CPLSPrintf("ERROR_THRESHOLD=%.16g", dfErrorThreshold) );
         }
         else if( EQUAL(argv[i],"-wm") )
         {
@@ -600,6 +657,14 @@ int main( int argc, char ** argv )
             dfMaxY = CPLAtofM(argv[++i]);
             bCreateOutput = TRUE;
         }
+        else if( EQUAL(argv[i],"-te_srs") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            char *pszSRS = SanitizeSRS(argv[++i]);
+            osTE_SRS = pszSRS;
+            CPLFree(pszSRS);
+            bCreateOutput = TRUE;
+        }
         else if( EQUAL(argv[i],"-rn") )
             eResampleAlg = GRA_NearestNeighbour;
 
@@ -638,6 +703,16 @@ int main( int argc, char ** argv )
                 eResampleAlg = GRA_Average;
             else if ( EQUAL(argv[i], "mode") )
                 eResampleAlg = GRA_Mode;
+            else if ( EQUAL(argv[i], "max") )
+                eResampleAlg = GRA_Max;
+            else if ( EQUAL(argv[i], "min") )
+                eResampleAlg = GRA_Min;
+            else if ( EQUAL(argv[i], "med") )
+                eResampleAlg = GRA_Med;
+            else if ( EQUAL(argv[i], "q1") )
+                eResampleAlg = GRA_Q1;
+            else if ( EQUAL(argv[i], "q3") )
+                eResampleAlg = GRA_Q3;
             else
             {
                 Usage(CPLSPrintf( "Unknown resampling method: \"%s\".", argv[i] ));
@@ -690,7 +765,27 @@ int main( int argc, char ** argv )
         }
         else if( EQUAL(argv[i],"-setci") )
             bSetColorInterpretation = TRUE;
-
+        else if( EQUAL(argv[i], "-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                argv[++i] );
+        }
+        else if( EQUAL(argv[i], "-ovr") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            const char* pszOvLevel = argv[++i];
+            if( EQUAL(pszOvLevel, "AUTO") )
+                nOvLevel = -2;
+            else if( EQUALN(pszOvLevel,"AUTO-",5) )
+                nOvLevel = -2-atoi(pszOvLevel + 5);
+            else if( EQUAL(pszOvLevel, "NONE") )
+                nOvLevel = -1;
+            else if( CPLGetValueType(pszOvLevel) == CPL_VALUE_INTEGER )
+                nOvLevel = atoi(pszOvLevel); 
+            else
+                Usage(CPLSPrintf("Invalid value '%s' for -ov option", pszOvLevel));
+        }
         else if( argv[i][0] == '-' )
             Usage(CPLSPrintf("Unknown option name '%s'", argv[i]));
 
@@ -711,6 +806,14 @@ int main( int argc, char ** argv )
     {
         Usage("-tap option cannot be used without using -tr.");
     }
+    
+    if( !bQuiet && !(dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0)  )
+    {
+        if( dfMinX >= dfMaxX )
+            printf("-ts values have minx >= maxx. This will result in a horizontally flipped image.\n");
+        if( dfMinY >= dfMaxY )
+            printf("-ts values have miny >= maxy. This will result in a vertically flipped image.\n");
+    }
 
 /* -------------------------------------------------------------------- */
 /*      The last filename in the file list is really our destination    */
@@ -747,10 +850,36 @@ int main( int argc, char ** argv )
         fprintf(stderr, "Source and destination datasets must be different.\n");
         GDALExit( 1 );
     }
+    
+    int bOutStreaming = FALSE;
+    if( strcmp(pszDstFilename, "/vsistdout/") == 0 )
+    {
+        bQuiet = TRUE;
+        bOutStreaming = TRUE;
+    }
+#ifdef S_ISFIFO
+    else
+    {
+        VSIStatBufL sStat;
+        if( VSIStatExL(pszDstFilename, &sStat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
+            S_ISFIFO(sStat.st_mode) )
+        {
+            bOutStreaming = TRUE;
+        }
+    }
+#endif
 
-    CPLPushErrorHandler( CPLQuietErrorHandler );
-    hDstDS = GDALOpen( pszDstFilename, GA_Update );
-    CPLPopErrorHandler();
+    if( bOutStreaming )
+    {
+        papszWarpOptions = CSLSetNameValue(papszWarpOptions, "STREAMABLE_OUTPUT", "YES");
+        hDstDS = NULL;
+    }
+    else
+    {
+        CPLPushErrorHandler( CPLQuietErrorHandler );
+        hDstDS = GDALOpen( pszDstFilename, GA_Update );
+        CPLPopErrorHandler();
+    }
 
     if( hDstDS != NULL && bOverwrite )
     {
@@ -770,7 +899,7 @@ int main( int argc, char ** argv )
 
     /* Avoid overwriting an existing destination file that cannot be opened in */
     /* update mode with a new GTiff file */
-    if ( hDstDS == NULL && !bOverwrite )
+    if ( !bOutStreaming && hDstDS == NULL && !bOverwrite )
     {
         CPLPushErrorHandler( CPLQuietErrorHandler );
         hDstDS = GDALOpen( pszDstFilename, GA_ReadOnly );
@@ -787,6 +916,68 @@ int main( int argc, char ** argv )
     }
 
 /* -------------------------------------------------------------------- */
+/*      -te_srs option                                                  */
+/* -------------------------------------------------------------------- */
+    if( osTE_SRS.size() )
+    {
+        if( dfMinX == 0.0 && dfMinY == 0.0 && dfMaxX == 0.0 && dfMaxY == 0.0 )
+        {
+            fprintf( stderr, "-te_srs ignored since -te is not specified.\n");
+        }
+        else
+        {
+            OGRSpatialReference oSRSIn;
+            oSRSIn.SetFromUserInput(osTE_SRS);
+            OGRSpatialReference oSRSDS;
+            int bOK = FALSE;
+            if( CSLFetchNameValue( papszTO, "DST_SRS" ) != NULL )
+            {
+                oSRSDS.SetFromUserInput( CSLFetchNameValue( papszTO, "DST_SRS" ) );
+                bOK = TRUE;
+            }
+            else if( CSLFetchNameValue( papszTO, "SRC_SRS" ) != NULL )
+            {
+                oSRSDS.SetFromUserInput( CSLFetchNameValue( papszTO, "SRC_SRS" ) );
+                bOK = TRUE;
+            }
+            else
+            {
+                if( papszSrcFiles[0] != NULL )
+                {
+                    GDALDatasetH hSrcDS = GDALOpen( papszSrcFiles[0], GA_ReadOnly );
+                    if( hSrcDS && GDALGetProjectionRef(hSrcDS) && GDALGetProjectionRef(hSrcDS)[0] )
+                    {
+                        oSRSDS.SetFromUserInput( GDALGetProjectionRef(hSrcDS) );
+                        bOK = TRUE;
+                    }
+                    GDALClose(hSrcDS);
+                }
+            }
+            if( !bOK )
+            {
+                fprintf( stderr, "-te_srs ignored since none of -t_srs, -s_srs is specified or the input dataset has no projection.\n");
+                GDALClose(hDstDS);
+                GDALExit( 1 );
+            }
+            if( !oSRSIn.IsSame(&oSRSDS) )
+            {
+                OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(&oSRSIn, &oSRSDS);
+                if( !(poCT &&
+                    poCT->Transform(1, &dfMinX, &dfMinY) &&
+                    poCT->Transform(1, &dfMaxX, &dfMaxY)) )
+                {
+                    OGRCoordinateTransformation::DestroyCT(poCT);
+
+                    fprintf( stderr, "-te_srs ignored since coordinate transformation failed.\n");
+                    GDALClose(hDstDS);
+                    GDALExit( 1 );
+                }
+                delete poCT;
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      If we have a cutline datasource read it and attach it in the    */
 /*      warp options.                                                   */
 /* -------------------------------------------------------------------- */
@@ -824,7 +1015,8 @@ int main( int argc, char ** argv )
         {
             if (papszSrcFiles[0] != NULL)
             {
-                GDALDatasetH hSrcDS = GDALOpen(papszSrcFiles[0], GA_ReadOnly);
+                GDALDatasetH hSrcDS = GDALOpenEx( papszSrcFiles[0], GDAL_OF_RASTER, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
                 if (hSrcDS == NULL)
                 {
                     fprintf(stderr, "Cannot compute bounding box of cutline.\n");
@@ -894,17 +1086,21 @@ int main( int argc, char ** argv )
 
     const char* pszWarpThreads = CSLFetchNameValue(papszWarpOptions, "NUM_THREADS");
     if( pszWarpThreads != NULL )
+    {
+        /* Used by TPS transformer to parallelize direct and inverse matrix computation */
         papszTO = CSLSetNameValue(papszTO, "NUM_THREADS", pszWarpThreads);
+    }
 
     if( hDstDS == NULL )
     {
-        if (!bQuiet && !bFormatExplicitelySet)
+        if (!bQuiet && !bFormatExplicitlySet)
             CheckExtensionConsistency(pszDstFilename, pszFormat);
 
         hDstDS = GDALWarpCreateOutput( papszSrcFiles, pszDstFilename,pszFormat,
                                        papszTO, &papszCreateOptions, 
                                        eOutputType, &hUniqueTransformArg,
-                                       &hUniqueSrcDS, bSetColorInterpretation);
+                                       &hUniqueSrcDS, bSetColorInterpretation,
+                                       papszOpenOptions);
         bCreateOutput = TRUE;
 
         if( !bInitDestSetByUser )
@@ -943,7 +1139,8 @@ int main( int argc, char ** argv )
         if (hUniqueSrcDS)
             hSrcDS = hUniqueSrcDS;
         else
-            hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
+            hSrcDS = GDALOpenEx( papszSrcFiles[iSrc], GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
     
         if( hSrcDS == NULL )
             GDALExit( 2 );
@@ -980,11 +1177,28 @@ int main( int argc, char ** argv )
                 CPLDebug("WARP", "Copying metadata from first source to destination dataset");
                 /* copy dataset-level metadata */
                 papszMetadata = GDALGetMetadata( hSrcDS, NULL );
-                if ( CSLCount(papszMetadata) > 0 ) {
-                    if ( GDALSetMetadata( hDstDS, papszMetadata, NULL ) != CE_None )
+
+                char** papszMetadataNew = NULL;
+                for( int i = 0; papszMetadata != NULL && papszMetadata[i] != NULL; i++ )
+                {
+                    // Do not preserve NODATA_VALUES when the output includes an alpha band
+                    if( bEnableDstAlpha &&
+                        EQUALN(papszMetadata[i], "NODATA_VALUES=", strlen("NODATA_VALUES=")) )
+                    {
+                        continue;
+                    }
+
+                    papszMetadataNew = CSLAddString(papszMetadataNew, papszMetadata[i]);
+                }
+
+                if ( CSLCount(papszMetadataNew) > 0 ) {
+                    if ( GDALSetMetadata( hDstDS, papszMetadataNew, NULL ) != CE_None )
                          fprintf( stderr, 
                                   "Warning: error copying metadata to destination dataset.\n" );
                 }
+
+                CSLDestroy(papszMetadataNew);
+
                 /* copy band-level metadata and other info */
                 if ( GDALGetRasterCount( hSrcDS ) == GDALGetRasterCount( hDstDS ) )              
                 {
@@ -1090,26 +1304,101 @@ int main( int argc, char ** argv )
 /*      destination coordinate system.                                  */
 /* -------------------------------------------------------------------- */
         if (hUniqueTransformArg)
-            hTransformArg = hGenImgProjArg = hUniqueTransformArg;
+            hTransformArg = hUniqueTransformArg;
         else
-            hTransformArg = hGenImgProjArg =
+            hTransformArg =
                 GDALCreateGenImgProjTransformer2( hSrcDS, hDstDS, papszTO );
         
         if( hTransformArg == NULL )
             GDALExit( 1 );
-        
+
         pfnTransformer = GDALGenImgProjTransform;
 
 /* -------------------------------------------------------------------- */
+/*      Determine if we must work with the full-resolution source       */
+/*      dataset, or one of its overview level.                          */
+/* -------------------------------------------------------------------- */
+        GDALDataset* poSrcDS = (GDALDataset*) hSrcDS;
+        GDALDataset* poSrcOvrDS = NULL;
+        int nOvCount = poSrcDS->GetRasterBand(1)->GetOverviewCount();
+        if( nOvLevel <= -2 && nOvCount > 0 )
+        {
+            double adfSuggestedGeoTransform[6];
+            double adfExtent[4];
+            int    nPixels, nLines;
+            /* Compute what the "natural" output resolution (in pixels) would be for this */
+            /* input dataset */
+            if( GDALSuggestedWarpOutput2(hSrcDS, pfnTransformer, hTransformArg,
+                                         adfSuggestedGeoTransform, &nPixels, &nLines,
+                                         adfExtent, 0) == CE_None)
+            {
+                double dfTargetRatio = 1.0 / adfSuggestedGeoTransform[1];
+                if( dfTargetRatio > 1.0 )
+                {
+                    int iOvr;
+                    for( iOvr = -1; iOvr < nOvCount-1; iOvr++ )
+                    {
+                        double dfOvrRatio = (iOvr < 0) ? 1.0 : (double)poSrcDS->GetRasterXSize() /
+                            poSrcDS->GetRasterBand(1)->GetOverview(iOvr)->GetXSize();
+                        double dfNextOvrRatio = (double)poSrcDS->GetRasterXSize() /
+                            poSrcDS->GetRasterBand(1)->GetOverview(iOvr+1)->GetXSize();
+                        if( dfOvrRatio < dfTargetRatio && dfNextOvrRatio > dfTargetRatio )
+                            break;
+                        if( fabs(dfOvrRatio - dfTargetRatio) < 1e-1 )
+                            break;
+                    }
+                    iOvr += (nOvLevel+2);
+                    if( iOvr >= 0 )
+                    {
+                        CPLDebug("WARP", "Selecting overview level %d for %s",
+                                 iOvr, papszSrcFiles[iSrc]);
+                        poSrcOvrDS = GDALCreateOverviewDataset( poSrcDS, iOvr, FALSE, FALSE );
+                    }
+                }
+            }
+        }
+        else if( nOvLevel >= 0 )
+        {
+            poSrcOvrDS = GDALCreateOverviewDataset( poSrcDS, nOvLevel, TRUE, FALSE );
+            if( poSrcOvrDS == NULL )
+            {
+                if( !bQuiet )
+                {
+                    fprintf(stderr, "Warning: cannot get overview level %d for "
+                            "dataset %s. Defaulting to level %d\n",
+                            nOvLevel, papszSrcFiles[iSrc], nOvCount - 1);
+                }
+                if( nOvCount > 0 )
+                    poSrcOvrDS = GDALCreateOverviewDataset( poSrcDS, nOvCount - 1, FALSE, FALSE );
+            }
+            else
+            {
+                CPLDebug("WARP", "Selecting overview level %d for %s",
+                         nOvLevel, papszSrcFiles[iSrc]);
+            }
+        }
+
+        GDALDatasetH hWrkSrcDS = (poSrcOvrDS) ? (GDALDatasetH)poSrcOvrDS : hSrcDS;
+
+        /* We need to recreate the transform when operating on an overview */
+        if( poSrcOvrDS != NULL )
+        {
+            GDALDestroyGenImgProjTransformer( hTransformArg );
+            hTransformArg =
+                GDALCreateGenImgProjTransformer2( hWrkSrcDS, hDstDS, papszTO );
+        }
+
+/* -------------------------------------------------------------------- */
 /*      Warp the transformer with a linear approximator unless the      */
 /*      acceptable error is zero.                                       */
 /* -------------------------------------------------------------------- */
         if( dfErrorThreshold != 0.0 )
         {
-            hTransformArg = hApproxArg = 
+            hTransformArg =
                 GDALCreateApproxTransformer( GDALGenImgProjTransform, 
-                                             hGenImgProjArg, dfErrorThreshold);
+                                             hTransformArg, dfErrorThreshold);
             pfnTransformer = GDALApproxTransform;
+            GDALApproxTransformerOwnsSubtransformer(hTransformArg, TRUE);
         }
 
 /* -------------------------------------------------------------------- */
@@ -1128,7 +1417,7 @@ int main( int argc, char ** argv )
         psWO->eWorkingDataType = eWorkingType;
         psWO->eResampleAlg = eResampleAlg;
 
-        psWO->hSrcDS = hSrcDS;
+        psWO->hSrcDS = hWrkSrcDS;
         psWO->hDstDS = hDstDS;
 
         psWO->pfnTransformer = pfnTransformer;
@@ -1144,9 +1433,9 @@ int main( int argc, char ** argv )
 /*      Setup band mapping.                                             */
 /* -------------------------------------------------------------------- */
         if( bEnableSrcAlpha )
-            psWO->nBandCount = GDALGetRasterCount(hSrcDS) - 1;
+            psWO->nBandCount = GDALGetRasterCount(hWrkSrcDS) - 1;
         else
-            psWO->nBandCount = GDALGetRasterCount(hSrcDS);
+            psWO->nBandCount = GDALGetRasterCount(hWrkSrcDS);
 
         psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
         psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
@@ -1161,7 +1450,7 @@ int main( int argc, char ** argv )
 /*      Setup alpha bands used if any.                                  */
 /* -------------------------------------------------------------------- */
         if( bEnableSrcAlpha )
-            psWO->nSrcAlphaBand = GDALGetRasterCount(hSrcDS);
+            psWO->nSrcAlphaBand = GDALGetRasterCount(hWrkSrcDS);
 
         if( !bEnableDstAlpha 
             && GDALGetRasterCount(hDstDS) == psWO->nBandCount+1 
@@ -1224,7 +1513,7 @@ int main( int argc, char ** argv )
 
             for( i = 0; !bHaveNodata && i < psWO->nBandCount; i++ )
             {
-                GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
+                GDALRasterBandH hBand = GDALGetRasterBand( hWrkSrcDS, i+1 );
                 dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
             }
 
@@ -1246,7 +1535,7 @@ int main( int argc, char ** argv )
                 
                 for( i = 0; i < psWO->nBandCount; i++ )
                 {
-                    GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
+                    GDALRasterBandH hBand = GDALGetRasterBand( hWrkSrcDS, i+1 );
 
                     dfReal = GDALGetRasterNoDataValue( hBand, &bHaveNodata );
 
@@ -1268,7 +1557,7 @@ int main( int argc, char ** argv )
 /*      If the output dataset was created, and we have a destination    */
 /*      nodata value, go through marking the bands with the information.*/
 /* -------------------------------------------------------------------- */
-        if( pszDstNodata != NULL )
+        if( pszDstNodata != NULL && !EQUAL(pszDstNodata,"none") )
         {
             char **papszTokens = CSLTokenizeString( pszDstNodata );
             int  nTokenCount = CSLCount(papszTokens);
@@ -1281,6 +1570,9 @@ int main( int argc, char ** argv )
 
             for( i = 0; i < psWO->nBandCount; i++ )
             {
+                psWO->padfDstNoDataReal[i] = -1.1e20;
+                psWO->padfDstNoDataImag[i] = 0.0;
+
                 if( i < nTokenCount )
                 {
                     if ( papszTokens[i] != NULL && EQUAL(papszTokens[i],"none") )
@@ -1375,8 +1667,9 @@ int main( int argc, char ** argv )
 
             CSLDestroy( papszTokens );
         }
+
         /* else try to fill dstNoData from source bands */
-        else if ( psWO->padfSrcNoDataReal != NULL )
+        if ( pszDstNodata == NULL && psWO->padfSrcNoDataReal != NULL )
         {
             psWO->padfDstNoDataReal = (double *) 
                 CPLMalloc(psWO->nBandCount*sizeof(double));
@@ -1391,7 +1684,7 @@ int main( int argc, char ** argv )
             {
                 int bHaveNodata = FALSE;
                 
-                GDALRasterBandH hBand = GDALGetRasterBand( hSrcDS, i+1 );
+                GDALRasterBandH hBand = GDALGetRasterBand( hWrkSrcDS, i+1 );
                 GDALGetRasterNoDataValue( hBand, &bHaveNodata );
 
                 CPLDebug("WARP", "band=%d bHaveNodata=%d", i, bHaveNodata);
@@ -1412,7 +1705,7 @@ int main( int argc, char ** argv )
                 }
             }
 
-            if( !bInitDestSetByUser && iSrc == 0 )
+            if( bCreateOutput && !bInitDestSetByUser && iSrc == 0 )
             {
                 /* As we didn't know at the beginning if there was source nodata */
                 /* we have initialized INIT_DEST=0. Override this with NO_DATA now */
@@ -1427,7 +1720,7 @@ int main( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
         if( hCutline != NULL )
         {
-            TransformCutlineToSource( hSrcDS, hCutline, 
+            TransformCutlineToSource( hWrkSrcDS, hCutline, 
                                       &(psWO->papszWarpOptions), 
                                       papszTO );
         }
@@ -1439,21 +1732,15 @@ int main( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
         if( bVRT )
         {
+            GDALSetMetadataItem(hDstDS, "SrcOvrLevel", CPLSPrintf("%d", nOvLevel), NULL);
             if( GDALInitializeWarpedVRT( hDstDS, psWO ) != CE_None )
                 GDALExit( 1 );
 
             GDALClose( hDstDS );
+            if( poSrcOvrDS )
+                delete poSrcOvrDS;
             GDALClose( hSrcDS );
 
-            /* The warped VRT will clean itself the transformer used */
-            /* So we have only to destroy the hGenImgProjArg if we */
-            /* have wrapped it inside the hApproxArg */
-            if (pfnTransformer == GDALApproxTransform)
-            {
-                if( hGenImgProjArg != NULL )
-                    GDALDestroyGenImgProjTransformer( hGenImgProjArg );
-            }
-
             GDALDestroyWarpOptions( psWO );
 
             CPLFree( pszDstFilename );
@@ -1461,6 +1748,7 @@ int main( int argc, char ** argv )
             CSLDestroy( papszSrcFiles );
             CSLDestroy( papszWarpOptions );
             CSLDestroy( papszTO );
+            CSLDestroy( papszOpenOptions );
     
             GDALDumpOpenDatasets( stderr );
         
@@ -1492,14 +1780,13 @@ int main( int argc, char ** argv )
 /* -------------------------------------------------------------------- */
 /*      Cleanup                                                         */
 /* -------------------------------------------------------------------- */
-        if( hApproxArg != NULL )
-            GDALDestroyApproxTransformer( hApproxArg );
-        
-        if( hGenImgProjArg != NULL )
-            GDALDestroyGenImgProjTransformer( hGenImgProjArg );
+        if( hTransformArg != NULL )
+            GDALDestroyTransformer( hTransformArg );
         
         GDALDestroyWarpOptions( psWO );
 
+        if( poSrcOvrDS )
+            delete poSrcOvrDS;
         GDALClose( hSrcDS );
     }
 
@@ -1517,6 +1804,7 @@ int main( int argc, char ** argv )
     CSLDestroy( papszSrcFiles );
     CSLDestroy( papszWarpOptions );
     CSLDestroy( papszTO );
+    CSLDestroy( papszOpenOptions );
 
     GDALDumpOpenDatasets( stderr );
 
@@ -1548,7 +1836,8 @@ GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
                       char ***ppapszCreateOptions, GDALDataType eDT,
                       void ** phTransformArg,
                       GDALDatasetH* phSrcDS,
-                      int bSetColorInterpretation)
+                      int bSetColorInterpretation,
+                      char** papszOpenOptions)
 
 
 {
@@ -1587,7 +1876,8 @@ GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
         {
             GDALDriverH hDriver = GDALGetDriver(iDr);
 
-            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL) != NULL )
+            if( GDALGetMetadataItem( hDriver, GDAL_DCAP_RASTER, NULL) != NULL &&
+                GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL) != NULL )
             {
                 printf( "  %s: %s\n",
                         GDALGetDriverShortName( hDriver  ),
@@ -1620,7 +1910,8 @@ GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
         GDALDatasetH hSrcDS;
         const char *pszThisSourceSRS = CSLFetchNameValue(papszTO,"SRC_SRS");
 
-        hSrcDS = GDALOpen( papszSrcFiles[iSrc], GA_ReadOnly );
+        hSrcDS = GDALOpenEx( papszSrcFiles[iSrc], GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
+                                (const char* const* )papszOpenOptions, NULL );
         if( hSrcDS == NULL )
             GDALExit( 1 );
 
@@ -1983,8 +2274,22 @@ GDALWarpCreateOutput( char **papszSrcFiles, const char *pszFilename,
 /* -------------------------------------------------------------------- */
 /*      Write out the projection definition.                            */
 /* -------------------------------------------------------------------- */
-    GDALSetProjection( hDstDS, pszThisTargetSRS );
-    GDALSetGeoTransform( hDstDS, adfDstGeoTransform );
+    const char *pszDstMethod = CSLFetchNameValue(papszTO,"DST_METHOD");
+    if( pszDstMethod == NULL || !EQUAL(pszDstMethod, "NO_GEOTRANSFORM") )
+    {
+        if( GDALSetProjection( hDstDS, pszThisTargetSRS ) == CE_Failure ||
+            GDALSetGeoTransform( hDstDS, adfDstGeoTransform ) == CE_Failure )
+        {
+            CPLFree( pszThisTargetSRS );
+            return NULL;
+        }
+    }
+    else
+    {
+        adfDstGeoTransform[0] = 0.0;
+        adfDstGeoTransform[3] = 0.0;
+        adfDstGeoTransform[5] = fabs(adfDstGeoTransform[5]);
+    }
 
     if (*phTransformArg != NULL)
         GDALSetGenImgProjTransformerDstGeoTransform( *phTransformArg, adfDstGeoTransform);
@@ -2094,7 +2399,10 @@ LoadCutline( const char *pszCutlineDSName, const char *pszCLayer,
 
     hSrcDS = OGROpen( pszCutlineDSName, FALSE, NULL );
     if( hSrcDS == NULL )
+    {
+        fprintf( stderr, "Cannot open %s.\n", pszCutlineDSName);
         GDALExit( 1 );
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Get the source layer                                            */
@@ -2332,3 +2640,4 @@ RemoveConflictingMetadata( GDALMajorObjectH hObj, char **papszMetadata,
 
     CSLDestroy( papszMetadataRef );
 }
+
diff --git a/apps/gdalwarpsimple.c b/apps/gdalwarpsimple.c
index 3ea751e..f655476 100644
--- a/apps/gdalwarpsimple.c
+++ b/apps/gdalwarpsimple.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwarpsimple.c 15436 2008-09-24 19:26:31Z rouault $
+ * $Id: gdalwarpsimple.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Mapinfo Image Warper
  * Purpose:  Commandline program for doing a variety of image warps, including
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: gdalwarpsimple.c 15436 2008-09-24 19:26:31Z rouault $");
+CPL_CVSID("$Id: gdalwarpsimple.c 27942 2014-11-11 00:57:41Z rouault $");
 
 static GDALDatasetH 
 GDALWarpCreateOutput( GDALDatasetH hSrcDS, const char *pszFilename, 
@@ -159,12 +159,12 @@ int main( int argc, char ** argv )
         }
         else if( EQUAL(argv[i],"-et") && i < argc-1 )
         {
-            dfErrorThreshold = atof(argv[++i]);
+            dfErrorThreshold = CPLAtof(argv[++i]);
         }
         else if( EQUAL(argv[i],"-tr") && i < argc-2 )
         {
-            dfXRes = atof(argv[++i]);
-            dfYRes = fabs(atof(argv[++i]));
+            dfXRes = CPLAtof(argv[++i]);
+            dfYRes = fabs(CPLAtof(argv[++i]));
             bCreateOutput = TRUE;
         }
         else if( EQUAL(argv[i],"-ts") && i < argc-2 )
@@ -175,10 +175,10 @@ int main( int argc, char ** argv )
         }
         else if( EQUAL(argv[i],"-te") && i < argc-4 )
         {
-            dfMinX = atof(argv[++i]);
-            dfMinY = atof(argv[++i]);
-            dfMaxX = atof(argv[++i]);
-            dfMaxY = atof(argv[++i]);
+            dfMinX = CPLAtof(argv[++i]);
+            dfMinY = CPLAtof(argv[++i]);
+            dfMaxX = CPLAtof(argv[++i]);
+            dfMaxY = CPLAtof(argv[++i]);
             bCreateOutput = TRUE;
         }
         else if( argv[i][0] == '-' )
diff --git a/apps/multireadtest.cpp b/apps/multireadtest.cpp
index ee804ac..d34d61d 100644
--- a/apps/multireadtest.cpp
+++ b/apps/multireadtest.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: multireadtest.cpp 17754 2009-10-04 20:48:03Z rouault $
+ * $Id: multireadtest.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Multithreading test application.
@@ -32,7 +32,7 @@
 #include "cpl_multiproc.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: multireadtest.cpp 17754 2009-10-04 20:48:03Z rouault $");
+CPL_CVSID("$Id: multireadtest.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 static int nThreadCount = 4, nIterations = 1, bLockOnOpen = TRUE;
 static int nOpenIterations = 1;
@@ -40,7 +40,7 @@ static volatile int nPendingThreads = 0;
 static const char *pszFilename = NULL;
 static int nChecksum = 0;
 
-static void *pGlobalMutex = NULL;
+static CPLMutex *pGlobalMutex = NULL;
 
 static void WorkerFunc( void * );
 
diff --git a/apps/nearblack.cpp b/apps/nearblack.cpp
index bcc2b44..a55875c 100644
--- a/apps/nearblack.cpp
+++ b/apps/nearblack.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nearblack.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nearblack.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  GDAL Utilities
  * Purpose:  Convert nearly black or nearly white border to exact black/white.
@@ -34,7 +34,7 @@
 #include <vector>
 #include "commonutils.h"
 
-CPL_CVSID("$Id: nearblack.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: nearblack.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 typedef std::vector<int> Color;
 typedef std::vector< Color > Colors;
@@ -123,7 +123,7 @@ int main( int argc, char ** argv )
     int bSetAlpha = FALSE;
     int bSetMask = FALSE;
     const char* pszDriverName = "HFA";
-    int bFormatExplicitelySet = FALSE;
+    int bFormatExplicitlySet = FALSE;
     char** papszCreationOptions = NULL;
     int bQuiet = FALSE;
 
@@ -148,7 +148,7 @@ int main( int argc, char ** argv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             pszDriverName = argv[++i];
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
         }
         else if( EQUAL(argv[i], "-white") ) {
             bNearWhite = TRUE;
@@ -185,7 +185,7 @@ int main( int argc, char ** argv )
             
             CSLDestroy( papszTokens );
 
-            /***** check if the number of bands is consistant *****/
+            /***** check if the number of bands is consistent *****/
 
             if ( oColors.size() > 0 &&
                  oColors.front().size() != oColor.size() )
@@ -270,7 +270,7 @@ int main( int argc, char ** argv )
         if (hDriver == NULL)
             exit(1);
 
-        if (!bQuiet && !bFormatExplicitelySet)
+        if (!bQuiet && !bFormatExplicitlySet)
             CheckExtensionConsistency(pszOutFile, pszDriverName);
 
         if (bSetAlpha)
diff --git a/apps/ogr2ogr.cpp b/apps/ogr2ogr.cpp
index 01d8ebb..9b0ea8d 100644
--- a/apps/ogr2ogr.cpp
+++ b/apps/ogr2ogr.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr2ogr.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogr2ogr.cpp 29012 2015-04-25 17:27:37Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Simple client for translating between formats.
@@ -39,12 +39,12 @@
 #include <map>
 #include <vector>
 
-CPL_CVSID("$Id: ogr2ogr.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogr2ogr.cpp 29012 2015-04-25 17:27:37Z rouault $");
 
 static int bSkipFailures = FALSE;
+static int bLayerTransaction = -1;
 static int nGroupTransactions = 20000;
-static int bPreserveFID = FALSE;
-static int nFIDToFetch = OGRNullFID;
+static GIntBig nFIDToFetch = OGRNullFID;
 
 #define COORD_DIM_LAYER_DIM -2
 
@@ -60,6 +60,7 @@ typedef enum
 
 typedef struct
 {
+    OGRLayer *   poSrcLayer;
     GIntBig      nFeaturesRead;
     int          bPerFeatureCT;
     OGRLayer    *poDstLayer;
@@ -67,7 +68,9 @@ typedef struct
     char       ***papapszTransformOptions; // size: poDstLayer->GetLayerDefn()->GetFieldCount();
     int         *panMap;
     int          iSrcZField;
+    int          iSrcFIDField;
     int          iRequestedSrcGeomField;
+    int          bPreserveFID;
 } TargetLayerInfo;
 
 typedef struct
@@ -76,51 +79,81 @@ typedef struct
     TargetLayerInfo  *psInfo;
 } AssociatedLayers;
 
-static TargetLayerInfo* SetupTargetLayer( OGRDataSource *poSrcDS,
-                                                OGRLayer * poSrcLayer,
-                                                OGRDataSource *poDstDS,
-                                                char **papszLCO,
-                                                const char *pszNewLayerName,
-                                                OGRSpatialReference *poOutputSRS,
-                                                int bNullifyOutputSRS,
-                                                char **papszSelFields,
-                                                int bAppend, int bAddMissingFields, int eGType,
-                                                int bPromoteToMulti,
-                                                int nCoordDim, int bOverwrite,
-                                                char** papszFieldTypesToString,
-                                                int bUnsetFieldWidth,
-                                                int bExplodeCollections,
-                                                const char* pszZField,
-                                                char **papszFieldMap,
-                                                const char* pszWHERE,
-                                                int bExactFieldNameMatch );
+typedef struct
+{
+    int bPromoteToMulti;
+    int bConvertToLinear;
+    int bConvertToCurve;
+} GeometryConversion;
 
-static void FreeTargetLayerInfo(TargetLayerInfo* psInfo);
+class SetupTargetLayer
+{
+public:
+    GDALDataset *poDstDS;
+    char ** papszLCO;
+    OGRSpatialReference *poOutputSRSIn;
+    int bNullifyOutputSRS;
+    char **papszSelFields;
+    int bAppend;
+    int bAddMissingFields;
+    int eGTypeIn;
+    GeometryConversion sGeomConversion;
+    int nCoordDim;
+    int bOverwrite;
+    char** papszFieldTypesToString;
+    char** papszMapFieldType;
+    int bUnsetFieldWidth;
+    int bExplodeCollections;
+    const char* pszZField;
+    char **papszFieldMap;
+    const char* pszWHERE;
+    int bExactFieldNameMatch;
+    int bQuiet;
+    int bForceNullable;
+    int bUnsetDefault;
+    int bUnsetFid;
+    int bPreserveFID;
+    int bCopyMD;
+
+    TargetLayerInfo*            Setup(OGRLayer * poSrcLayer,
+                                      const char *pszNewLayerName);
+};
+
+class LayerTranslator
+{
+public:
+    GDALDataset *poSrcDS;
+    GDALDataset *poODS;
+    int bTransform;
+    int bWrapDateline;
+    const char* pszDateLineOffset;
+    OGRSpatialReference *poOutputSRSIn;
+    int bNullifyOutputSRS;
+    OGRSpatialReference *poUserSourceSRS;
+    OGRCoordinateTransformation *poGCPCoordTrans;
+    int eGTypeIn;
+    GeometryConversion sGeomConversion;
+    int nCoordDim;
+    GeomOperation eGeomOp;
+    double dfGeomOpParam;
+    OGRGeometry* poClipSrc;
+    OGRGeometry *poClipDst;
+    int bExplodeCollectionsIn;
+    vsi_l_offset nSrcFileSize;
+
+    int                 Translate(TargetLayerInfo* psInfo,
+                                  GIntBig nCountLayerFeatures,
+                                  GIntBig* pnReadFeatureCount,
+                                  GDALProgressFunc pfnProgress,
+                                  void *pProgressArg);
+};
 
-static int TranslateLayer( TargetLayerInfo* psInfo,
-                           OGRDataSource *poSrcDS,
-                           OGRLayer * poSrcLayer,
-                           OGRDataSource *poDstDS,
-                           int bTransform,
-                           int bWrapDateline,
-                           const char* pszDateLineOffset,
-                           OGRSpatialReference *poOutputSRS,
-                           int bNullifyOutputSRS,
-                           OGRSpatialReference *poUserSourceSRS,
-                           OGRCoordinateTransformation *poGCPCoordTrans,
-                           int eGType,
-                           int bPromoteToMulti,
-                           int nCoordDim,
-                           GeomOperation eGeomOp,
-                           double dfGeomOpParam,
-                           long nCountLayerFeatures,
-                           OGRGeometry* poClipSrc,
-                           OGRGeometry *poClipDst,
-                           int bExplodeCollections,
-                           vsi_l_offset nSrcFileSize,
-                           GIntBig* pnReadFeatureCount,
-                           GDALProgressFunc pfnProgress,
-                           void *pProgressArg);
+static OGRLayer* GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
+                                                 const char* pszNewLayerName,
+                                                 int bOverwrite,
+                                                 int* pbErrorOccured);
+
+static void FreeTargetLayerInfo(TargetLayerInfo* psInfo);
 
 /* -------------------------------------------------------------------- */
 /*                  CheckDestDataSourceNameConsistency()                */
@@ -133,30 +166,8 @@ void CheckDestDataSourceNameConsistency(const char* pszDestFilename,
     int i;
     char* pszDestExtension = CPLStrdup(CPLGetExtension(pszDestFilename));
 
-    /* TODO: Would be good to have driver metadata like for GDAL drivers ! */
-    static const char* apszExtensions[][2] = { { "shp"    , "ESRI Shapefile" },
-                                               { "dbf"    , "ESRI Shapefile" },
-                                               { "sqlite" , "SQLite" },
-                                               { "db"     , "SQLite" },
-                                               { "mif"    , "MapInfo File" },
-                                               { "tab"    , "MapInfo File" },
-                                               { "s57"    , "S57" },
-                                               { "bna"    , "BNA" },
-                                               { "csv"    , "CSV" },
-                                               { "gml"    , "GML" },
-                                               { "kml"    , "KML/LIBKML" },
-                                               { "kmz"    , "LIBKML" },
-                                               { "json"   , "GeoJSON" },
-                                               { "geojson", "GeoJSON" },
-                                               { "dxf"    , "DXF" },
-                                               { "gdb"    , "FileGDB" },
-                                               { "pix"    , "PCIDSK" },
-                                               { "sql"    , "PGDump" },
-                                               { "gtm"    , "GPSTrackMaker" },
-                                               { "gmt"    , "GMT" },
-                                               { "pdf"    , "PDF" },
-                                               { NULL, NULL }
-                                              };
+    CheckExtensionConsistency(pszDestFilename, pszDriverName);
+
     static const char* apszBeginName[][2] =  { { "PG:"      , "PG" },
                                                { "MySQL:"   , "MySQL" },
                                                { "CouchDB:" , "CouchDB" },
@@ -169,20 +180,6 @@ void CheckDestDataSourceNameConsistency(const char* pszDestFilename,
                                                { NULL, NULL }
                                              };
 
-    for(i=0; apszExtensions[i][0] != NULL; i++)
-    {
-        if (EQUAL(pszDestExtension, apszExtensions[i][0]) && !EQUAL(pszDriverName, apszExtensions[i][1]))
-        {
-            fprintf(stderr,
-                    "Warning: The target file has a '%s' extension, which is normally used by the %s driver,\n"
-                    "but the requested output driver is %s. Is it really what you want ?\n",
-                    pszDestExtension,
-                    apszExtensions[i][1],
-                    pszDriverName);
-            break;
-        }
-    }
-
     for(i=0; apszBeginName[i][0] != NULL; i++)
     {
         if (EQUALN(pszDestFilename, apszBeginName[i][0], strlen(apszBeginName[i][0])) &&
@@ -222,12 +219,12 @@ static OGRGeometry* LoadGeometry( const char* pszDS,
                                   const char* pszLyr,
                                   const char* pszWhere)
 {
-    OGRDataSource       *poDS;
+    GDALDataset         *poDS;
     OGRLayer            *poLyr;
     OGRFeature          *poFeat;
     OGRGeometry         *poGeom = NULL;
         
-    poDS = OGRSFDriverRegistrar::Open( pszDS, FALSE );
+    poDS = (GDALDataset*) OGROpen( pszDS, FALSE, NULL );
     if (poDS == NULL)
         return NULL;
 
@@ -241,7 +238,7 @@ static OGRGeometry* LoadGeometry( const char* pszDS,
     if (poLyr == NULL)
     {
         fprintf( stderr, "Failed to identify source layer from datasource.\n" );
-        OGRDataSource::DestroyDataSource(poDS);
+        GDALClose(( GDALDatasetH) poDS);
         return NULL;
     }
     
@@ -278,7 +275,7 @@ static OGRGeometry* LoadGeometry( const char* pszDS,
                 OGRFeature::DestroyFeature(poFeat);
                 if( pszSQL != NULL )
                     poDS->ReleaseResultSet( poLyr );
-                OGRDataSource::DestroyDataSource(poDS);
+                GDALClose(( GDALDatasetH) poDS);
                 return NULL;
             }
         }
@@ -288,7 +285,7 @@ static OGRGeometry* LoadGeometry( const char* pszDS,
     
     if( pszSQL != NULL )
         poDS->ReleaseResultSet( poLyr );
-    OGRDataSource::DestroyDataSource(poDS);
+    GDALClose(( GDALDatasetH) poDS);
     
     return poGeom;
 }
@@ -325,13 +322,13 @@ class OGRSplitListFieldLayer : public OGRLayer
                                                 void *pProgressArg);
 
     virtual OGRFeature          *GetNextFeature();
-    virtual OGRFeature          *GetFeature(long nFID);
+    virtual OGRFeature          *GetFeature(GIntBig nFID);
     virtual OGRFeatureDefn      *GetLayerDefn();
 
     virtual void                 ResetReading() { poSrcLayer->ResetReading(); }
     virtual int                  TestCapability(const char*) { return FALSE; }
 
-    virtual int                  GetFeatureCount( int bForce = TRUE )
+    virtual GIntBig              GetFeatureCount( int bForce = TRUE )
     {
         return poSrcLayer->GetFeatureCount(bForce);
     }
@@ -430,6 +427,7 @@ int  OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
     {
         OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
         if (eType == OFTIntegerList ||
+            eType == OFTInteger64List ||
             eType == OFTRealList ||
             eType == OFTStringList)
         {
@@ -451,10 +449,10 @@ int  OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
         poSrcLayer->ResetReading();
         OGRFeature* poSrcFeature;
 
-        int nFeatureCount = 0;
+        GIntBig nFeatureCount = 0;
         if (poSrcLayer->TestCapability(OLCFastFeatureCount))
             nFeatureCount = poSrcLayer->GetFeatureCount();
-        int nFeatureIndex = 0;
+        GIntBig nFeatureIndex = 0;
 
         /* Scan the whole layer to compute the maximum number of */
         /* items for each field of list type */
@@ -522,6 +520,7 @@ int  OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
     {
         OGRFieldType eType = poSrcFieldDefn->GetFieldDefn(i)->GetType();
         if (eType == OFTIntegerList ||
+            eType == OFTInteger64List ||
             eType == OFTRealList ||
             eType == OFTStringList)
         {
@@ -533,6 +532,7 @@ int  OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
             {
                 OGRFieldDefn oFieldDefn(poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(),
                                             (eType == OFTIntegerList) ? OFTInteger :
+                                            (eType == OFTInteger64List) ? OFTInteger64 :
                                             (eType == OFTRealList) ?    OFTReal :
                                                                         OFTString);
                 poFeatureDefn->AddFieldDefn(&oFieldDefn);
@@ -546,6 +546,7 @@ int  OGRSplitListFieldLayer::BuildLayerDefn(GDALProgressFunc pfnProgress,
                         poSrcFieldDefn->GetFieldDefn(i)->GetNameRef(), j+1);
                     OGRFieldDefn oFieldDefn(osFieldName.c_str(),
                                             (eType == OFTIntegerList) ? OFTInteger :
+                                            (eType == OFTInteger64List) ? OFTInteger64 :
                                             (eType == OFTRealList) ?    OFTReal :
                                                                         OFTString);
                     oFieldDefn.SetWidth(nWidth);
@@ -606,6 +607,18 @@ OGRFeature *OGRSplitListFieldLayer::TranslateFeature(OGRFeature* poSrcFeature)
                 iListField++;
                 break;
             }
+            case OFTInteger64List:
+            {
+                int nCount = psField->Integer64List.nCount;
+                if (nCount > nMaxSplitListSubFields)
+                    nCount = nMaxSplitListSubFields;
+                GIntBig* paList = psField->Integer64List.paList;
+                for(j=0;j<nCount;j++)
+                    poFeature->SetField(iDstField + j, paList[j]);
+                iDstField += pasListFields[iListField].nMaxOccurences;
+                iListField++;
+                break;
+            }
             case OFTRealList:
             {
                 int nCount = psField->RealList.nCount;
@@ -655,7 +668,7 @@ OGRFeature *OGRSplitListFieldLayer::GetNextFeature()
 /*                           GetFeature()                               */
 /************************************************************************/
 
-OGRFeature *OGRSplitListFieldLayer::GetFeature(long nFID)
+OGRFeature *OGRSplitListFieldLayer::GetFeature(GIntBig nFID)
 {
     return TranslateFeature(poSrcLayer->GetFeature(nFID));
 }
@@ -841,6 +854,57 @@ void ApplySpatialFilter(OGRLayer* poLayer, OGRGeometry* poSpatialFilter,
             poLayer->SetSpatialFilter( poSpatialFilter );
     }
 }
+             
+/************************************************************************/
+/*                          GetFieldType()                              */
+/************************************************************************/
+
+int GetFieldType(const char* pszArg, int* pnSubFieldType)
+{
+    *pnSubFieldType = OFSTNone;
+    int nLengthBeforeParenthesis = strlen(pszArg);
+    const char* pszOpenParenthesis = strchr(pszArg, '(');
+    if( pszOpenParenthesis )
+        nLengthBeforeParenthesis = pszOpenParenthesis - pszArg;
+    for( int iType = 0; iType <= (int) OFTMaxType; iType++ )
+    {
+         const char* pszFieldTypeName = OGRFieldDefn::GetFieldTypeName(
+                                                       (OGRFieldType)iType);
+         if( EQUALN(pszArg,pszFieldTypeName,nLengthBeforeParenthesis) &&
+             pszFieldTypeName[nLengthBeforeParenthesis] == '\0' )
+         {
+             if( pszOpenParenthesis != NULL )
+             {
+                 *pnSubFieldType = -1;
+                 CPLString osArgSubType = pszOpenParenthesis + 1;
+                 if( osArgSubType.size() && osArgSubType[osArgSubType.size()-1] == ')' )
+                     osArgSubType.resize(osArgSubType.size()-1);
+                 for( int iSubType = 0; iSubType <= (int) OFSTMaxSubType; iSubType++ )
+                 {
+                     const char* pszFieldSubTypeName = OGRFieldDefn::GetFieldSubTypeName(
+                                                       (OGRFieldSubType)iSubType);
+                     if( EQUAL( pszFieldSubTypeName, osArgSubType ) )
+                     {
+                         *pnSubFieldType = iSubType;
+                         break;
+                     }
+                 }
+             }
+             return iType;
+         }
+     }
+     return -1;
+}
+             
+/************************************************************************/
+/*                           IsFieldType()                              */
+/************************************************************************/
+
+static int IsFieldType(const char* pszArg)
+{
+    int iSubType;
+    return GetFieldType(pszArg, &iSubType) >= 0 && iSubType >= 0;
+}
 
 /************************************************************************/
 /*                                main()                                */
@@ -855,7 +919,7 @@ int main( int nArgc, char ** papszArgv )
 {
     int          nRetCode = 0;
     int          bQuiet = FALSE;
-    int          bFormatExplicitelySet = FALSE;
+    int          bFormatExplicitlySet = FALSE;
     const char  *pszFormat = "ESRI Shapefile";
     const char  *pszDataSource = NULL;
     const char  *pszDestDataSource = NULL;
@@ -879,10 +943,14 @@ int main( int nArgc, char ** papszArgv )
     const char  *pszSQLStatement = NULL;
     const char  *pszDialect = NULL;
     int         eGType = -2;
-    int          bPromoteToMulti = FALSE;
+    GeometryConversion sGeomConversion;
+    sGeomConversion.bPromoteToMulti = FALSE;
+    sGeomConversion.bConvertToLinear = FALSE;
+    sGeomConversion.bConvertToCurve = FALSE;
     GeomOperation eGeomOp = NONE;
     double       dfGeomOpParam = 0;
     char        **papszFieldTypesToString = NULL;
+    char        **papszMapFieldType = NULL;
     int          bUnsetFieldWidth = FALSE;
     int          bDisplayProgress = FALSE;
     GDALProgressFunc pfnProgress = NULL;
@@ -907,7 +975,15 @@ int main( int nArgc, char ** papszArgv )
     const char  *pszFieldMap = NULL;
     char        **papszFieldMap = NULL;
     int          nCoordDim = -1;
- 
+    char       **papszOpenOptions = NULL;
+    char       **papszDestOpenOptions = NULL;
+    int          bForceNullable = FALSE;
+    int          bUnsetDefault = FALSE;
+    int          bUnsetFid = FALSE;
+    int          bPreserveFID = FALSE;
+    int          bCopyMD = TRUE;
+    char       **papszMetadataOptions = NULL;
+
     int          nGCPCount = 0;
     GDAL_GCP    *pasGCPs = NULL;
     int          nTransformOrder = 0;  /* Default to 0 for now... let the lib decide */
@@ -953,7 +1029,7 @@ int main( int nArgc, char ** papszArgv )
         else if( EQUAL(papszArgv[iArg],"-f") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            bFormatExplicitelySet = TRUE;
+            bFormatExplicitlySet = TRUE;
             pszFormat = papszArgv[++iArg];
         }
         else if( EQUAL(papszArgv[iArg],"-dsco") )
@@ -966,6 +1042,16 @@ int main( int nArgc, char ** papszArgv )
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             papszLCO = CSLAddString(papszLCO, papszArgv[++iArg] );
         }
+        else if( EQUAL(papszArgv[iArg],"-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString(papszOpenOptions, papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg],"-doo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszDestOpenOptions = CSLAddString(papszDestOpenOptions, papszArgv[++iArg] );
+        }
         else if( EQUAL(papszArgv[iArg],"-preserve_fid") )
         {
             bPreserveFID = TRUE;
@@ -1002,7 +1088,7 @@ int main( int nArgc, char ** papszArgv )
         else if( EQUAL(papszArgv[iArg],"-fid") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            nFIDToFetch = atoi(papszArgv[++iArg]);
+            nFIDToFetch = CPLAtoGIntBig(papszArgv[++iArg]);
         }
         else if( EQUAL(papszArgv[iArg],"-sql") )
         {
@@ -1030,12 +1116,22 @@ int main( int nArgc, char ** papszArgv )
                 bIs3D = TRUE;
                 osGeomName.resize(osGeomName.size() - 3);
             }
+            else if (strlen(papszArgv[iArg+1]) > 1 &&
+                EQUALN(papszArgv[iArg+1] + strlen(papszArgv[iArg+1]) - 1, "Z", 1))
+            {
+                bIs3D = TRUE;
+                osGeomName.resize(osGeomName.size() - 1);
+            }
             if( EQUAL(osGeomName,"NONE") )
                 eGType = wkbNone;
             else if( EQUAL(osGeomName,"GEOMETRY") )
                 eGType = wkbUnknown;
             else if( EQUAL(osGeomName,"PROMOTE_TO_MULTI") )
-                bPromoteToMulti = TRUE;
+                sGeomConversion.bPromoteToMulti = TRUE;
+            else if( EQUAL(osGeomName,"CONVERT_TO_LINEAR") )
+                sGeomConversion.bConvertToLinear = TRUE;
+            else if( EQUAL(osGeomName,"CONVERT_TO_CURVE") )
+                sGeomConversion.bConvertToCurve = TRUE;
             else
             {
                 eGType = OGRFromOGCGeomType(osGeomName);
@@ -1047,7 +1143,7 @@ int main( int nArgc, char ** papszArgv )
                 }
             }
             if (eGType != -2 && eGType != wkbNone && bIs3D)
-                eGType |= wkb25DBit;
+                eGType = wkbSetZ((OGRwkbGeometryType)eGType);
 
             iArg++;
         }
@@ -1072,7 +1168,21 @@ int main( int nArgc, char ** papszArgv )
                  EQUAL(papszArgv[iArg],"-gt") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            nGroupTransactions = atoi(papszArgv[++iArg]);
+            ++iArg;
+            if( EQUAL(papszArgv[iArg], "unlimited") )
+                nGroupTransactions = -1;
+            else
+                nGroupTransactions = atoi(papszArgv[iArg]);
+        }
+        /* Undocumented. Just a provision. Default behaviour should be OK */
+        else if ( EQUAL(papszArgv[iArg],"-ds_transaction") )
+        {
+            bLayerTransaction = FALSE;
+        }
+        /* Undocumented. Just a provision. Default behaviour should be OK */
+        else if ( EQUAL(papszArgv[iArg],"-lyr_transaction") )
+        {
+            bLayerTransaction = TRUE;
         }
         else if( EQUAL(papszArgv[iArg],"-s_srs") )
         {
@@ -1101,11 +1211,11 @@ int main( int nArgc, char ** papszArgv )
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
             OGRLinearRing  oRing;
 
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
 
             poSpatialFilter = OGRGeometryFactory::createGeometry(wkbPolygon);
             ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
@@ -1132,13 +1242,13 @@ int main( int nArgc, char ** papszArgv )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             eGeomOp = SEGMENTIZE;
-            dfGeomOpParam = atof(papszArgv[++iArg]);
+            dfGeomOpParam = CPLAtof(papszArgv[++iArg]);
         }
         else if( EQUAL(papszArgv[iArg],"-simplify") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
             eGeomOp = SIMPLIFY_PRESERVE_TOPOLOGY;
-            dfGeomOpParam = atof(papszArgv[++iArg]);
+            dfGeomOpParam = CPLAtof(papszArgv[++iArg]);
         }
         else if( EQUAL(papszArgv[iArg],"-fieldTypeToString") )
         {
@@ -1149,16 +1259,7 @@ int main( int nArgc, char ** papszArgv )
             char** iter = papszFieldTypesToString;
             while(*iter)
             {
-                if (EQUAL(*iter, "Integer") ||
-                    EQUAL(*iter, "Real") ||
-                    EQUAL(*iter, "String") ||
-                    EQUAL(*iter, "Date") ||
-                    EQUAL(*iter, "Time") ||
-                    EQUAL(*iter, "DateTime") ||
-                    EQUAL(*iter, "Binary") ||
-                    EQUAL(*iter, "IntegerList") ||
-                    EQUAL(*iter, "RealList") ||
-                    EQUAL(*iter, "StringList"))
+                if (IsFieldType(*iter))
                 {
                     /* Do nothing */
                 }
@@ -1171,12 +1272,34 @@ int main( int nArgc, char ** papszArgv )
                 }
                 else
                 {
-                    Usage(CPLSPrintf("Unhandled type for fieldtypeasstring option : %s",
+                    Usage(CPLSPrintf("Unhandled type for fieldTypeToString option : %s",
                             *iter));
                 }
                 iter ++;
             }
         }
+        else if( EQUAL(papszArgv[iArg],"-mapFieldType") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszMapFieldType =
+                    CSLTokenizeStringComplex(papszArgv[++iArg], " ,", 
+                                             FALSE, FALSE );
+            char** iter = papszMapFieldType;
+            while(*iter)
+            {
+                char* pszKey = NULL;
+                const char* pszValue = CPLParseNameValue(*iter, &pszKey);
+                if( pszKey && pszValue)
+                {
+                    if( !((IsFieldType(pszKey) || EQUAL(pszKey, "All")) && IsFieldType(pszValue)) )
+                    {
+                        Usage("Invalid value for -mapFieldType");
+                    }
+                }
+                CPLFree(pszKey);
+                iter ++;
+            }
+        }
         else if( EQUAL(papszArgv[iArg],"-unsetFieldWidth") )
         {
             bUnsetFieldWidth = TRUE;
@@ -1207,11 +1330,11 @@ int main( int nArgc, char ** papszArgv )
             {
                 OGRLinearRing  oRing;
 
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
-                oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
-                oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+4]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+4]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
 
                 poClipSrc = OGRGeometryFactory::createGeometry(wkbPolygon);
                 ((OGRPolygon *) poClipSrc)->addRing( &oRing );
@@ -1270,11 +1393,11 @@ int main( int nArgc, char ** papszArgv )
             {
                 OGRLinearRing  oRing;
 
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
-                oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
-                oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
-                oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+4]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+4]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+2]) );
+                oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
 
                 poClipDst = OGRGeometryFactory::createGeometry(wkbPolygon);
                 ((OGRPolygon *) poClipDst)->addRing( &oRing );
@@ -1354,17 +1477,17 @@ int main( int nArgc, char ** papszArgv )
                 CPLRealloc( pasGCPs, sizeof(GDAL_GCP) * nGCPCount );
             GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 );
 
-            pasGCPs[nGCPCount-1].dfGCPPixel = atof(papszArgv[++iArg]);
-            pasGCPs[nGCPCount-1].dfGCPLine = atof(papszArgv[++iArg]);
-            pasGCPs[nGCPCount-1].dfGCPX = atof(papszArgv[++iArg]);
-            pasGCPs[nGCPCount-1].dfGCPY = atof(papszArgv[++iArg]);
+            pasGCPs[nGCPCount-1].dfGCPPixel = CPLAtof(papszArgv[++iArg]);
+            pasGCPs[nGCPCount-1].dfGCPLine = CPLAtof(papszArgv[++iArg]);
+            pasGCPs[nGCPCount-1].dfGCPX = CPLAtof(papszArgv[++iArg]);
+            pasGCPs[nGCPCount-1].dfGCPY = CPLAtof(papszArgv[++iArg]);
             if( papszArgv[iArg+1] != NULL 
                 && (CPLStrtod(papszArgv[iArg+1], &endptr) != 0.0 || papszArgv[iArg+1][0] == '0') )
             {
                 /* Check that last argument is really a number and not a filename */
                 /* looking like a number (see ticket #863) */
                 if (endptr && *endptr == 0)
-                    pasGCPs[nGCPCount-1].dfGCPZ = atof(papszArgv[++iArg]);
+                    pasGCPs[nGCPCount-1].dfGCPZ = CPLAtof(papszArgv[++iArg]);
             }
 
             /* should set id and info? */
@@ -1385,6 +1508,28 @@ int main( int nArgc, char ** papszArgv )
             papszFieldMap = CSLTokenizeStringComplex(pszFieldMap, ",", 
                                                       FALSE, FALSE );
         }
+        else if( EQUAL(papszArgv[iArg],"-forceNullable") )
+        {
+            bForceNullable = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-unsetDefault") )
+        {
+            bUnsetDefault = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-unsetFid") )
+        {
+            bUnsetFid = TRUE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-nomd") )
+        {
+            bCopyMD = FALSE;
+        }
+        else if( EQUAL(papszArgv[iArg],"-mo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszMetadataOptions = CSLAddString( papszMetadataOptions,
+                                                 papszArgv[++iArg] );
+        }
         else if( papszArgv[iArg][0] == '-' )
         {
             Usage(CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
@@ -1420,6 +1565,11 @@ int main( int nArgc, char ** papszArgv )
         Usage("if -addfields is specified, -fieldmap cannot be used.");
     }
 
+    if( papszFieldTypesToString && papszMapFieldType )
+    {
+        Usage("-fieldTypeToString and -mapFieldType are exclusive.");
+    }
+
     if( pszSourceSRSDef != NULL && pszOutputSRSDef == NULL )
     {
         Usage("if -s_srs is specified, -t_srs must also be specified");
@@ -1456,22 +1606,28 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 /*      Open data source.                                               */
 /* -------------------------------------------------------------------- */
-    OGRDataSource       *poDS;
-    OGRDataSource       *poODS = NULL;
-    OGRSFDriver         *poDriver = NULL;
+    GDALDataset         *poDS;
+    GDALDataset         *poODS = NULL;
+    GDALDriver          *poDriver = NULL;
     int                  bCloseODS = TRUE;
 
     /* Avoid opening twice the same datasource if it is both the input and output */
     /* Known to cause problems with at least FGdb and SQlite drivers. See #4270 */
     if (bUpdate && strcmp(pszDestDataSource, pszDataSource) == 0)
     {
-        poODS = poDS = OGRSFDriverRegistrar::Open( pszDataSource, TRUE, &poDriver );
+        poODS = poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+                GDAL_OF_UPDATE | GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL );
+        if( poDS != NULL )
+            poDriver = poDS->GetDriver();
+
         /* Restrict to those 2 drivers. For example it is known to break with */
         /* the PG driver due to the way it manages transactions... */
-        if (poDS && !(EQUAL(poDriver->GetName(), "FileGDB") ||
-                      EQUAL(poDriver->GetName(), "SQLite")))
+        if (poDS && !(EQUAL(poDriver->GetDescription(), "FileGDB") ||
+                      EQUAL(poDriver->GetDescription(), "SQLite") ||
+                      EQUAL(poDriver->GetDescription(), "GPKG")))
         {
-            poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE );
+            poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+                            GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL );
         }
         else
             bCloseODS = FALSE;
@@ -1500,7 +1656,8 @@ int main( int nArgc, char ** papszArgv )
         }
     }
     else
-        poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE );
+        poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+                            GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL );
 
 /* -------------------------------------------------------------------- */
 /*      Report failure                                                  */
@@ -1515,7 +1672,7 @@ int main( int nArgc, char ** papszArgv )
 
         for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
         {
-            fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+            fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
         }
 
         exit( 1 );
@@ -1527,13 +1684,17 @@ int main( int nArgc, char ** papszArgv )
 
     if( bUpdate && poODS == NULL )
     {
-        poODS = OGRSFDriverRegistrar::Open( pszDestDataSource, TRUE, &poDriver );
+        poODS = (GDALDataset*) GDALOpenEx( pszDestDataSource,
+                GDAL_OF_UPDATE | GDAL_OF_VECTOR, NULL, papszDestOpenOptions, NULL );
+        if( poODS != NULL )
+            poDriver = poODS->GetDriver();
 
         if( poODS == NULL )
         {
             if (bOverwrite || bAppend)
             {
-                poODS = OGRSFDriverRegistrar::Open( pszDestDataSource, FALSE, &poDriver );
+                poODS = (GDALDataset*) GDALOpenEx( pszDestDataSource,
+                            GDAL_OF_VECTOR, NULL, papszDestOpenOptions, NULL );
                 if (poODS == NULL)
                 {
                     /* ok the datasource doesn't exist at all */
@@ -1541,7 +1702,9 @@ int main( int nArgc, char ** papszArgv )
                 }
                 else
                 {
-                    OGRDataSource::DestroyDataSource(poODS);
+                    if( poODS != NULL )
+                        poDriver = poODS->GetDriver();
+                    GDALClose( (GDALDatasetH) poODS );
                     poODS = NULL;
                 }
             }
@@ -1566,7 +1729,7 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
     if( !bUpdate )
     {
-        if (!bQuiet && !bFormatExplicitelySet)
+        if (!bQuiet && !bFormatExplicitlySet)
             CheckDestDataSourceNameConsistency(pszDestDataSource, pszFormat);
 
         OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
@@ -1580,12 +1743,12 @@ int main( int nArgc, char ** papszArgv )
         
             for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription() );
             }
             exit( 1 );
         }
 
-        if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+        if( !CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
         {
             fprintf( stderr,  "%s driver does not support data source creation.\n",
                     pszFormat );
@@ -1601,7 +1764,7 @@ int main( int nArgc, char ** papszArgv )
 /*      a directory instead.                                            */
 /* -------------------------------------------------------------------- */
         VSIStatBufL  sStat;
-        if (EQUAL(poDriver->GetName(), "ESRI Shapefile") &&
+        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
             pszSQLStatement == NULL &&
             (CSLCount(papszLayers) > 1 ||
              (CSLCount(papszLayers) == 0 && poDS->GetLayerCount() > 1)) &&
@@ -1622,15 +1785,41 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 /*      Create the output data source.                                  */
 /* -------------------------------------------------------------------- */
-        poODS = poDriver->CreateDataSource( pszDestDataSource, papszDSCO );
+        poODS = poDriver->Create( pszDestDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
         if( poODS == NULL )
         {
             fprintf( stderr,  "%s driver failed to create %s\n", 
                     pszFormat, pszDestDataSource );
             exit( 1 );
         }
+        
+        if( bCopyMD )
+        {
+            char** papszDomains = poDS->GetMetadataDomainList();
+            for(char** papszIter = papszDomains; papszIter && *papszIter; ++papszIter )
+            {
+                char** papszMD = poDS->GetMetadata(*papszIter);
+                if( papszMD )
+                    poODS->SetMetadata(papszMD, *papszIter);
+            }
+            CSLDestroy(papszDomains);
+        }
+        for(char** papszIter = papszMetadataOptions; papszIter && *papszIter; ++papszIter )
+        {
+            char    *pszKey = NULL;
+            const char *pszValue;
+            pszValue = CPLParseNameValue( *papszIter, &pszKey );
+            if( pszKey )
+            {
+                poODS->SetMetadataItem(pszKey,pszValue);
+                CPLFree( pszKey );
+            }
+        }
     }
 
+    if( bLayerTransaction < 0 )
+        bLayerTransaction = !poODS->TestCapability(ODsCTransactions);
+
 /* -------------------------------------------------------------------- */
 /*      Parse the output SRS definition if possible.                    */
 /* -------------------------------------------------------------------- */
@@ -1679,23 +1868,83 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 /*      For OSM file.                                                   */
 /* -------------------------------------------------------------------- */
-    int         bSrcIsOSM = (poDS->GetDriver() != NULL &&
-                             strcmp(poDS->GetDriver()->GetName(), "OSM") == 0);
+    int         bSrcIsOSM = (strcmp(poDS->GetDriverName(), "OSM") == 0);
     vsi_l_offset nSrcFileSize = 0;
-    if( bSrcIsOSM && strcmp(poDS->GetName(), "/vsistdin/") != 0)
+    if( bSrcIsOSM && strcmp(poDS->GetDescription(), "/vsistdin/") != 0)
     {
         VSIStatBufL sStat;
-        if( VSIStatL(poDS->GetName(), &sStat) == 0 )
+        if( VSIStatL(poDS->GetDescription(), &sStat) == 0 )
             nSrcFileSize = sStat.st_size;
     }
 
 /* -------------------------------------------------------------------- */
+/*      Create layer setup and transformer objects.                     */
+/* -------------------------------------------------------------------- */
+    SetupTargetLayer oSetup;
+    oSetup.poDstDS = poODS;
+    oSetup.papszLCO = papszLCO;
+    oSetup.poOutputSRSIn = poOutputSRS;
+    oSetup.bNullifyOutputSRS = bNullifyOutputSRS;
+    oSetup.papszSelFields = papszSelFields;
+    oSetup.bAppend = bAppend;
+    oSetup.bAddMissingFields = bAddMissingFields;
+    oSetup.eGTypeIn = eGType;
+    oSetup.sGeomConversion = sGeomConversion;
+    oSetup.nCoordDim = nCoordDim;
+    oSetup.bOverwrite = bOverwrite;
+    oSetup.papszFieldTypesToString = papszFieldTypesToString;
+    oSetup.papszMapFieldType = papszMapFieldType;
+    oSetup.bUnsetFieldWidth = bUnsetFieldWidth;
+    oSetup.bExplodeCollections = bExplodeCollections;
+    oSetup.pszZField = pszZField;
+    oSetup.papszFieldMap = papszFieldMap;
+    oSetup.pszWHERE = pszWHERE;
+    oSetup.bExactFieldNameMatch = bExactFieldNameMatch;
+    oSetup.bQuiet = bQuiet;
+    oSetup.bForceNullable = bForceNullable;
+    oSetup.bUnsetDefault = bUnsetDefault;
+    oSetup.bUnsetFid = bUnsetFid;
+    oSetup.bPreserveFID = bPreserveFID;
+    oSetup.bCopyMD = bCopyMD;
+
+    LayerTranslator oTranslator;
+    oTranslator.poSrcDS = poDS;
+    oTranslator.poODS = poODS;
+    oTranslator.bTransform = bTransform;
+    oTranslator.bWrapDateline = bWrapDateline;
+    oTranslator.pszDateLineOffset = pszDateLineOffset;
+    oTranslator.poOutputSRSIn = poOutputSRS;
+    oTranslator.bNullifyOutputSRS = bNullifyOutputSRS;
+    oTranslator.poUserSourceSRS = poSourceSRS;
+    oTranslator.poGCPCoordTrans = poGCPCoordTrans;
+    oTranslator.eGTypeIn = eGType;
+    oTranslator.sGeomConversion = sGeomConversion;
+    oTranslator.nCoordDim = nCoordDim;
+    oTranslator.eGeomOp = eGeomOp;
+    oTranslator.dfGeomOpParam = dfGeomOpParam;
+    oTranslator.poClipSrc = poClipSrc;
+    oTranslator.poClipDst = poClipDst;
+    oTranslator.bExplodeCollectionsIn = bExplodeCollections;
+    oTranslator.nSrcFileSize = nSrcFileSize;
+
+    if( nGroupTransactions )
+    {
+        if( !bLayerTransaction )
+            poODS->StartTransaction();
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Special case for -sql clause.  No source layers required.       */
 /* -------------------------------------------------------------------- */
     if( pszSQLStatement != NULL )
     {
         OGRLayer *poResultSet;
 
+        /* Special case: if output=input, then we must likely destroy the */
+        /* old table before to avoid transaction issues. */
+        if( poDS == poODS && pszNewLayerName != NULL && bOverwrite )
+            GetLayerAndOverwriteIfNecessary(poODS, pszNewLayerName, bOverwrite, NULL);
+
         if( pszWHERE != NULL )
             fprintf( stderr,  "-where clause ignored in combination with -sql.\n" );
         if( CSLCount(papszLayers) > 0 )
@@ -1717,7 +1966,7 @@ int main( int nArgc, char ** papszArgv )
                            pszGeomField);
             }
 
-            long nCountLayerFeatures = 0;
+            GIntBig nCountLayerFeatures = 0;
             if (bDisplayProgress)
             {
                 if (bSrcIsOSM)
@@ -1754,47 +2003,22 @@ int main( int nArgc, char ** papszArgv )
 /*      the layer name isn't specified                                  */
 /* -------------------------------------------------------------------- */
             VSIStatBufL  sStat;
-            if (EQUAL(poDriver->GetName(), "ESRI Shapefile") &&
+            if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
                 pszNewLayerName == NULL &&
                 VSIStatL(pszDestDataSource, &sStat) == 0 && VSI_ISREG(sStat.st_mode))
             {
                 pszNewLayerName = CPLStrdup(CPLGetBasename(pszDestDataSource));
             }
 
-            TargetLayerInfo* psInfo = SetupTargetLayer( poDS,
-                                                poPassedLayer,
-                                                poODS,
-                                                papszLCO,
-                                                pszNewLayerName,
-                                                poOutputSRS,
-                                                bNullifyOutputSRS,
-                                                papszSelFields,
-                                                bAppend, bAddMissingFields, eGType,
-                                                bPromoteToMulti,
-                                                nCoordDim, bOverwrite,
-                                                papszFieldTypesToString,
-                                                bUnsetFieldWidth,
-                                                bExplodeCollections,
-                                                pszZField,
-                                                papszFieldMap,
-                                                pszWHERE,
-                                                bExactFieldNameMatch );
+            TargetLayerInfo* psInfo = oSetup.Setup(poPassedLayer,
+                                                   pszNewLayerName);
 
             poPassedLayer->ResetReading();
 
             if( psInfo == NULL ||
-                !TranslateLayer( psInfo, poDS, poPassedLayer, poODS,
-                                 bTransform, bWrapDateline, pszDateLineOffset,
-                                 poOutputSRS, bNullifyOutputSRS,
-                                 poSourceSRS,
-                                 poGCPCoordTrans,
-                                 eGType, bPromoteToMulti, nCoordDim,
-                                 eGeomOp, dfGeomOpParam,
-                                 nCountLayerFeatures,
-                                 poClipSrc, poClipDst,
-                                 bExplodeCollections,
-                                 nSrcFileSize, NULL,
-                                 pfnProgress, pProgressArg ))
+                !oTranslator.Translate( psInfo,
+                                        nCountLayerFeatures, NULL,
+                                        pfnProgress, pProgressArg ))
             {
                 CPLError( CE_Failure, CPLE_AppDefined, 
                           "Terminating translation prematurely after failed\n"
@@ -1841,7 +2065,7 @@ int main( int nArgc, char ** papszArgv )
 /*      the layer name isn't specified                                  */
 /* -------------------------------------------------------------------- */
         VSIStatBufL  sStat;
-        if (EQUAL(poDriver->GetName(), "ESRI Shapefile") &&
+        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
             (CSLCount(papszLayers) == 1 || nSrcLayerCount == 1) && pszNewLayerName == NULL &&
             VSIStatL(pszDestDataSource, &sStat) == 0 && VSI_ISREG(sStat.st_mode))
         {
@@ -1917,24 +2141,8 @@ int main( int nArgc, char ** papszArgv )
 
                 ApplySpatialFilter(poLayer, poSpatialFilter, pszGeomField);
 
-                TargetLayerInfo* psInfo = SetupTargetLayer( poDS,
-                                                    poLayer,
-                                                    poODS,
-                                                    papszLCO,
-                                                    pszNewLayerName,
-                                                    poOutputSRS,
-                                                    bNullifyOutputSRS,
-                                                    papszSelFields,
-                                                    bAppend, bAddMissingFields, eGType,
-                                                    bPromoteToMulti,
-                                                    nCoordDim, bOverwrite,
-                                                    papszFieldTypesToString,
-                                                    bUnsetFieldWidth,
-                                                    bExplodeCollections,
-                                                    pszZField,
-                                                    papszFieldMap,
-                                                    pszWHERE,
-						    bExactFieldNameMatch );
+                TargetLayerInfo* psInfo = oSetup.Setup(poLayer,
+                                                       pszNewLayerName);
 
                 if( psInfo == NULL && !bSkipFailures )
                     exit(1);
@@ -1963,19 +2171,9 @@ int main( int nArgc, char ** papszArgv )
 
                 if( psInfo )
                 {
-                    if( !TranslateLayer(psInfo, poDS, poLayer, poODS,
-                                        bTransform, bWrapDateline, pszDateLineOffset,
-                                        poOutputSRS, bNullifyOutputSRS,
-                                        poSourceSRS,
-                                        poGCPCoordTrans,
-                                        eGType, bPromoteToMulti, nCoordDim,
-                                        eGeomOp, dfGeomOpParam,
-                                        0,
-                                        poClipSrc, poClipDst,
-                                        bExplodeCollections,
-                                        nSrcFileSize,
-                                        &nReadFeatureCount,
-                                        pfnProgress, pProgressArg )
+                    if( !oTranslator.Translate( psInfo,
+                                                0, &nReadFeatureCount,
+                                                pfnProgress, pProgressArg )
                         && !bSkipFailures )
                     {
                         CPLError( CE_Failure, CPLE_AppDefined,
@@ -2082,16 +2280,16 @@ int main( int nArgc, char ** papszArgv )
 /*      the layer name isn't specified                                  */
 /* -------------------------------------------------------------------- */
         VSIStatBufL  sStat;
-        if (EQUAL(poDriver->GetName(), "ESRI Shapefile") &&
+        if (EQUAL(poDriver->GetDescription(), "ESRI Shapefile") &&
             nLayerCount == 1 && pszNewLayerName == NULL &&
             VSIStatL(pszDestDataSource, &sStat) == 0 && VSI_ISREG(sStat.st_mode))
         {
             pszNewLayerName = CPLStrdup(CPLGetBasename(pszDestDataSource));
         }
 
-        long* panLayerCountFeatures = (long*) CPLCalloc(sizeof(long), nLayerCount);
-        long nCountLayersFeatures = 0;
-        long nAccCountFeatures = 0;
+        GIntBig* panLayerCountFeatures = (GIntBig*) CPLCalloc(sizeof(GIntBig), nLayerCount);
+        GIntBig nCountLayersFeatures = 0;
+        GIntBig nAccCountFeatures = 0;
         int iLayer;
 
         /* First pass to apply filters and count all features if necessary */
@@ -2180,7 +2378,7 @@ int main( int nArgc, char ** papszArgv )
                 else
                 {
                     pfnProgress = GDALScaledProgress;
-                    int nStart = 0;
+                    GIntBig nStart = 0;
                     if (poPassedLayer != poLayer && nMaxSplitListSubFields != 1)
                         nStart = panLayerCountFeatures[iLayer] / 2;
                     pProgressArg =
@@ -2193,40 +2391,15 @@ int main( int nArgc, char ** papszArgv )
 
             nAccCountFeatures += panLayerCountFeatures[iLayer];
 
-            TargetLayerInfo* psInfo = SetupTargetLayer( poDS,
-                                                poPassedLayer,
-                                                poODS,
-                                                papszLCO,
-                                                pszNewLayerName,
-                                                poOutputSRS,
-                                                bNullifyOutputSRS,
-                                                papszSelFields,
-                                                bAppend, bAddMissingFields, eGType,
-                                                bPromoteToMulti,
-                                                nCoordDim, bOverwrite,
-                                                papszFieldTypesToString,
-                                                bUnsetFieldWidth,
-                                                bExplodeCollections,
-                                                pszZField,
-                                                papszFieldMap,
-                                                pszWHERE,
-						bExactFieldNameMatch );
+            TargetLayerInfo* psInfo = oSetup.Setup(poPassedLayer,
+                                                   pszNewLayerName);
 
             poPassedLayer->ResetReading();
 
             if( (psInfo == NULL ||
-                !TranslateLayer( psInfo, poDS, poPassedLayer, poODS,
-                                  bTransform, bWrapDateline, pszDateLineOffset,
-                                  poOutputSRS, bNullifyOutputSRS,
-                                  poSourceSRS,
-                                  poGCPCoordTrans,
-                                  eGType, bPromoteToMulti, nCoordDim,
-                                  eGeomOp, dfGeomOpParam,
-                                  panLayerCountFeatures[iLayer],
-                                  poClipSrc, poClipDst,
-                                  bExplodeCollections,
-                                  nSrcFileSize, NULL,
-                                  pfnProgress, pProgressArg ))
+                !oTranslator.Translate( psInfo,
+                                        panLayerCountFeatures[iLayer], NULL,
+                                        pfnProgress, pProgressArg ))
                 && !bSkipFailures )
             {
                 CPLError( CE_Failure, CPLE_AppDefined, 
@@ -2254,13 +2427,24 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 
     poODS->SetStyleTable( poDS->GetStyleTable () );
-    
+
+    if( nGroupTransactions )
+    {
+        if( !bLayerTransaction )
+        {
+            if( nRetCode != 0 && !bSkipFailures )
+                poODS->RollbackTransaction();
+            else
+                poODS->CommitTransaction();
+        }
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Close down.                                                     */
 /* -------------------------------------------------------------------- */
     if (bCloseODS)
-        OGRDataSource::DestroyDataSource(poODS);
-    OGRDataSource::DestroyDataSource(poDS);
+        GDALClose( (GDALDatasetH)poODS );
+    GDALClose( (GDALDatasetH)poDS );
     OGRGeometryFactory::destroyGeometry(poSpatialFilter);
     OGRGeometryFactory::destroyGeometry(poClipSrc);
     OGRGeometryFactory::destroyGeometry(poClipDst);
@@ -2278,11 +2462,15 @@ int main( int nArgc, char ** papszArgv )
 
     CSLDestroy(papszSelFields);
     CSLDestroy( papszFieldMap );
+    CSLDestroy( papszMapFieldType );
     CSLDestroy( papszArgv );
     CSLDestroy( papszLayers );
     CSLDestroy( papszDSCO );
     CSLDestroy( papszLCO );
+    CSLDestroy( papszOpenOptions );
+    CSLDestroy( papszDestOpenOptions );
     CSLDestroy( papszFieldTypesToString );
+    CSLDestroy( papszMetadataOptions );
     CPLFree( pszNewLayerName );
 
     OGRCleanupAll();
@@ -2317,10 +2505,13 @@ static void Usage(const char* pszAdditionalMsg, int bShort)
             "               [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]\n"
             "               [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]\n"
             "               dst_datasource_name src_datasource_name\n"
-            "               [-lco NAME=VALUE] [-nln name] [-nlt type] [-dim 2|3|layer_dim] [layer [layer ...]]\n"
+            "               [-lco NAME=VALUE] [-nln name] \n"
+            "               [-nlt type|PROMOTE_TO_MULTI|CONVERT_TO_LINEAR]\n"
+            "               [-dim 2|3|layer_dim] [layer [layer ...]]\n"
             "\n"
             "Advanced options :\n"
             "               [-gt n]\n"
+            "               [[-oo NAME=VALUE] ...] [[-doo NAME=VALUE] ...]\n"
             "               [-clipsrc [xmin ymin xmax ymax]|WKT|datasource|spat_extent]\n"
             "               [-clipsrcsql sql_statement] [-clipsrclayer layer]\n"
             "               [-clipsrcwhere expression]\n"
@@ -2329,13 +2520,15 @@ static void Usage(const char* pszAdditionalMsg, int bShort)
             "               [-clipdstwhere expression]\n"
             "               [-wrapdateline][-datelineoffset val]\n"
             "               [[-simplify tolerance] | [-segmentize max_dist]]\n"
-            "               [-addfields]\n"
-            "               [-relaxedFieldNameMatch]\n"
+            "               [-addfields] [-unsetFid]\n"
+            "               [-relaxedFieldNameMatch] [-forceNullable] [-unsetDefault]\n"
             "               [-fieldTypeToString All|(type1[,type2]*)] [-unsetFieldWidth]\n"
+            "               [-mapFieldType srctype|All=dsttype[,srctype2=dsttype2]*]\n"
             "               [-fieldmap identity | index1[,index2]*]\n"
             "               [-splitlistfields] [-maxsubfields val]\n"
             "               [-explodecollections] [-zfield field_name]\n"
-            "               [-gcp pixel line easting northing [elevation]]* [-order n | -tps]\n");
+            "               [-gcp pixel line easting northing [elevation]]* [-order n | -tps]\n"
+            "               [-nomd] [-mo \"META-TAG=VALUE\"]*\n");
 
     if (bShort)
     {
@@ -2349,10 +2542,10 @@ static void Usage(const char* pszAdditionalMsg, int bShort)
 
     for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
     {
-        OGRSFDriver *poDriver = poR->GetDriver(iDriver);
+        GDALDriver *poDriver = poR->GetDriver(iDriver);
 
-        if( poDriver->TestCapability( ODrCCreateDataSource ) )
-            printf( "     -f \"%s\"\n", poDriver->GetName() );
+        if( CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+            printf( "     -f \"%s\"\n", poDriver->GetDescription() );
     }
 
     printf( " -append: Append to existing layer instead of creating new if it exists\n"
@@ -2378,6 +2571,8 @@ static void Usage(const char* pszAdditionalMsg, int bShort)
             "                       Used to create intermediate points\n"
             " -dsco NAME=VALUE: Dataset creation option (format specific)\n"
             " -lco  NAME=VALUE: Layer creation option (format specific)\n"
+            " -oo   NAME=VALUE: Input dataset open option (format specific)\n"
+            " -doo  NAME=VALUE: Destination dataset open 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"
@@ -2386,7 +2581,7 @@ static void Usage(const char* pszAdditionalMsg, int bShort)
             " -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 : Integer,\n"
-            "      Real, String, Date, Time, DateTime, Binary, IntegerList, RealList,\n"
+            "      Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList,\n"
             "      StringList. Special value All will convert all fields to strings.\n"
             " -fieldmap index1,index2,...: Specifies the list of field indexes to be\n"
             "      copied from the source to the destination. The (n)th value specified\n"
@@ -2468,39 +2663,218 @@ static void SetZ (OGRGeometry* poGeom, double dfZ )
 static int ForceCoordDimension(int eGType, int nCoordDim)
 {
     if( nCoordDim == 2 && eGType != wkbNone )
-        return eGType & ~wkb25DBit;
+        return wkbFlatten(eGType);
     else if( nCoordDim == 3 && eGType != wkbNone )
-        return eGType | wkb25DBit;
+        return wkbSetZ((OGRwkbGeometryType)eGType);
     else
         return eGType;
 }
 
 /************************************************************************/
-/*                         SetupTargetLayer()                           */
+/*                   GetLayerAndOverwriteIfNecessary()                  */
+/************************************************************************/
+
+static OGRLayer* GetLayerAndOverwriteIfNecessary(GDALDataset *poDstDS,
+                                                 const char* pszNewLayerName,
+                                                 int bOverwrite,
+                                                 int* pbErrorOccured)
+{
+    if( pbErrorOccured )
+        *pbErrorOccured = FALSE;
+
+    /* 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) */
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    OGRLayer* poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
+    CPLPopErrorHandler();
+    CPLErrorReset();
+
+    int iLayer = -1;
+    if (poDstLayer != NULL)
+    {
+        int nLayerCount = poDstDS->GetLayerCount();
+        for( iLayer = 0; iLayer < nLayerCount; iLayer++ )
+        {
+            OGRLayer        *poLayer = poDstDS->GetLayer(iLayer);
+            if (poLayer == poDstLayer)
+                break;
+        }
+
+        if (iLayer == nLayerCount)
+            /* shouldn't happen with an ideal driver */
+            poDstLayer = NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      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 != NULL && bOverwrite )
+    {
+        if( poDstDS->DeleteLayer( iLayer ) != OGRERR_NONE )
+        {
+            fprintf( stderr,
+                     "DeleteLayer() failed when overwrite requested.\n" );
+            if( pbErrorOccured )
+                *pbErrorOccured = TRUE;
+        }
+        poDstLayer = NULL;
+    }
+
+    return poDstLayer;
+}
+
+/************************************************************************/
+/*                          ConvertType()                               */
+/************************************************************************/
+
+static OGRwkbGeometryType ConvertType(GeometryConversion sGeomConversion,
+                                      OGRwkbGeometryType eGType)
+{
+    OGRwkbGeometryType eRetType = eGType;
+    if ( sGeomConversion.bPromoteToMulti )
+    {
+        if( !OGR_GT_IsSubClassOf(eGType, wkbGeometryCollection) )
+            eRetType = OGR_GT_GetCollection(eGType);
+    }
+    else if ( sGeomConversion.bConvertToLinear )
+        eRetType = OGR_GT_GetLinear(eGType);
+    if ( sGeomConversion.bConvertToCurve )
+        eRetType = OGR_GT_GetCurve(eGType);
+    return eRetType;
+}
+
+/************************************************************************/
+/*                        DoFieldTypeConversion()                       */
+/************************************************************************/
+
+void DoFieldTypeConversion(GDALDataset* poDstDS, OGRFieldDefn& oFieldDefn,
+                           char** papszFieldTypesToString,
+                           char** papszMapFieldType,
+                           int bUnsetFieldWidth,
+                           int bQuiet,
+                           int bForceNullable,
+                           int bUnsetDefault)
+{
+    if (papszFieldTypesToString != NULL )
+    {
+        CPLString osLookupString;
+        osLookupString.Printf("%s(%s)",
+                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
+                        OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
+                                  
+        int iIdx = CSLFindString(papszFieldTypesToString, osLookupString);
+        if( iIdx < 0 )
+            iIdx = CSLFindString(papszFieldTypesToString,
+                                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
+        if( iIdx < 0 )
+            iIdx = CSLFindString(papszFieldTypesToString, "All");
+        if( iIdx >= 0 )
+        {
+            oFieldDefn.SetSubType(OFSTNone);
+            oFieldDefn.SetType(OFTString);
+        }
+    }
+    else if (papszMapFieldType != NULL)
+    {
+        CPLString osLookupString;
+        osLookupString.Printf("%s(%s)",
+                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
+                        OGRFieldDefn::GetFieldSubTypeName(oFieldDefn.GetSubType()));
+                                  
+        const char* pszType = CSLFetchNameValue(papszMapFieldType, osLookupString);
+        if( pszType == NULL )
+            pszType = CSLFetchNameValue(papszMapFieldType,
+                                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()));
+        if( pszType == NULL )
+            pszType = CSLFetchNameValue(papszMapFieldType, "All");
+        if( pszType != NULL )
+        {
+            int iSubType;
+            int iType = GetFieldType(pszType, &iSubType);
+            if( iType >= 0 && iSubType >= 0 )
+            {
+                oFieldDefn.SetSubType(OFSTNone);
+                oFieldDefn.SetType((OGRFieldType)iType);
+                oFieldDefn.SetSubType((OGRFieldSubType)iSubType);
+                if( iType == OFTInteger )
+                    oFieldDefn.SetWidth(0);
+            }
+        }
+    }
+    if( bUnsetFieldWidth )
+    {
+        oFieldDefn.SetWidth(0);
+        oFieldDefn.SetPrecision(0);
+    }
+    if( bForceNullable )
+        oFieldDefn.SetNullable(TRUE);
+    if( bUnsetDefault )
+        oFieldDefn.SetDefault(NULL);
+
+    if( poDstDS->GetDriver() != NULL &&
+        poDstDS->GetDriver()->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES) != NULL &&
+        strstr(poDstDS->GetDriver()->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES),
+                OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType())) == NULL )
+    {
+        if( oFieldDefn.GetType() == OFTInteger64 )
+        {
+            if( !bQuiet )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                        "The output driver does not seem to natively support %s "
+                        "type for field %s. Converting it to Real instead. "
+                        "-mapFieldType can be used to control field type conversion.",
+                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
+                        oFieldDefn.GetNameRef());
+            }
+            oFieldDefn.SetType(OFTReal);
+        }
+        else if( !bQuiet )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                        "The output driver does not natively support %s type for "
+                        "field %s. Misconversion can happen. "
+                        "-mapFieldType can be used to control field type conversion.",
+                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
+                        oFieldDefn.GetNameRef());
+        }
+    }
+    else if( poDstDS->GetDriver() != NULL &&
+             poDstDS->GetDriver()->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES) == NULL )
+    {
+        // All drivers supporting OFTInteger64 should advertize it theoretically
+        if( oFieldDefn.GetType() == OFTInteger64 )
+        {
+            if( !bQuiet )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                        "The output driver does not seem to natively support %s type "
+                        "for field %s. Converting it to Real instead. "
+                        "-mapFieldType can be used to control field type conversion.",
+                        OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()),
+                        oFieldDefn.GetNameRef());
+            }
+            oFieldDefn.SetType(OFTReal);
+        }
+    }
+}
+
+/************************************************************************/
+/*                   SetupTargetLayer::Setup()                          */
 /************************************************************************/
 
-static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
-                                          OGRLayer * poSrcLayer,
-                                          OGRDataSource *poDstDS,
-                                          char **papszLCO,
-                                          const char *pszNewLayerName,
-                                          OGRSpatialReference *poOutputSRSIn,
-                                          int bNullifyOutputSRS,
-                                          char **papszSelFields,
-                                          int bAppend, int bAddMissingFields, int eGType,
-                                          int bPromoteToMulti,
-                                          int nCoordDim, int bOverwrite,
-                                          char** papszFieldTypesToString,
-                                          int bUnsetFieldWidth,
-                                          int bExplodeCollections,
-                                          const char* pszZField,
-                                          char **papszFieldMap,
-                                          const char* pszWHERE,
-                                          int bExactFieldNameMatch )
+TargetLayerInfo* SetupTargetLayer::Setup(OGRLayer* poSrcLayer,
+                                         const char* pszNewLayerName)
 {
     OGRLayer    *poDstLayer;
     OGRFeatureDefn *poSrcFDefn;
     OGRFeatureDefn *poDstFDefn = NULL;
+    int eGType = eGTypeIn;
+    int bPreserveFID = this->bPreserveFID;
 
     if( pszNewLayerName == NULL )
         pszNewLayerName = poSrcLayer->GetName();
@@ -2571,46 +2945,13 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
 /*      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) */
-    CPLPushErrorHandler(CPLQuietErrorHandler);
-    poDstLayer = poDstDS->GetLayerByName(pszNewLayerName);
-    CPLPopErrorHandler();
-    CPLErrorReset();
-
-    int iLayer = -1;
-    if (poDstLayer != NULL)
-    {
-        int nLayerCount = poDstDS->GetLayerCount();
-        for( iLayer = 0; iLayer < nLayerCount; iLayer++ )
-        {
-            OGRLayer        *poLayer = poDstDS->GetLayer(iLayer);
-            if (poLayer == poDstLayer)
-                break;
-        }
-
-        if (iLayer == nLayerCount)
-            /* shouldn't happen with an ideal driver */
-            poDstLayer = NULL;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      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 != NULL && bOverwrite )
-    {
-        if( poDstDS->DeleteLayer( iLayer ) != OGRERR_NONE )
-        {
-            fprintf( stderr,
-                     "DeleteLayer() failed when overwrite requested.\n" );
-            return NULL;
-        }
-        poDstLayer = NULL;
-    }
+    int bErrorOccured;
+    poDstLayer = GetLayerAndOverwriteIfNecessary(poDstDS,
+                                                 pszNewLayerName,
+                                                 bOverwrite,
+                                                 &bErrorOccured);
+    if( bErrorOccured )
+        return NULL;
 
 /* -------------------------------------------------------------------- */
 /*      If the layer does not exist, then create it.                    */
@@ -2626,7 +2967,7 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
         }
 
         int bForceGType = ( eGType != -2 );
-        if( eGType == -2 )
+        if( !bForceGType )
         {
             if( anRequestedGeomFields.size() == 0 )
             {
@@ -2640,43 +2981,42 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
             else
                 eGType = wkbNone;
 
-            int n25DBit = eGType & wkb25DBit;
-            if ( bPromoteToMulti )
-            {
-                if (wkbFlatten(eGType) == wkbLineString)
-                    eGType = wkbMultiLineString | n25DBit;
-                else if (wkbFlatten(eGType) == wkbPolygon)
-                    eGType = wkbMultiPolygon | n25DBit;
-            }
+            int bHasZ = wkbHasZ((OGRwkbGeometryType)eGType);
+            eGType = ConvertType(sGeomConversion, (OGRwkbGeometryType)eGType);
 
             if ( bExplodeCollections )
             {
-                if (wkbFlatten(eGType) == wkbMultiPoint)
+                OGRwkbGeometryType eFGType = wkbFlatten(eGType);
+                if (eFGType == wkbMultiPoint)
                 {
-                    eGType = wkbPoint | n25DBit;
+                    eGType = wkbPoint;
                 }
-                else if (wkbFlatten(eGType) == wkbMultiLineString)
+                else if (eFGType == wkbMultiLineString)
                 {
-                    eGType = wkbLineString | n25DBit;
+                    eGType = wkbLineString;
                 }
-                else if (wkbFlatten(eGType) == wkbMultiPolygon)
+                else if (eFGType == wkbMultiPolygon)
                 {
-                    eGType = wkbPolygon | n25DBit;
+                    eGType = wkbPolygon;
                 }
-                else if (wkbFlatten(eGType) == wkbGeometryCollection)
+                else if (eFGType == wkbGeometryCollection ||
+                         eFGType == wkbMultiCurve ||
+                         eFGType == wkbMultiSurface)
                 {
-                    eGType = wkbUnknown | n25DBit;
+                    eGType = wkbUnknown;
                 }
             }
 
-            if ( pszZField && eGType != wkbNone )
-                eGType |= wkb25DBit;
+            if ( bHasZ || (pszZField && eGType != wkbNone) )
+                eGType = wkbSetZ((OGRwkbGeometryType)eGType);
         }
 
         eGType = ForceCoordDimension(eGType, nCoordDim);
 
         CPLErrorReset();
 
+        char** papszLCOTemp = CSLDuplicate(papszLCO);
+
         int eGCreateLayerType = eGType;
         if( anRequestedGeomFields.size() == 0 &&
             nSrcGeomFieldCount > 1 &&
@@ -2689,13 +3029,83 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
         {
             eGCreateLayerType = wkbNone;
         }
+        // If the source feature has a single geometry column that is not nullable
+        // and that ODsCCreateGeomFieldAfterCreateLayer is available, use it
+        // so as to be able to set the not null constraint (if the driver supports it)
+        else if( anRequestedGeomFields.size() == 0 &&
+                 nSrcGeomFieldCount == 1 &&
+                 poDstDS->TestCapability(ODsCCreateGeomFieldAfterCreateLayer) &&
+                 !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
+                 !bForceNullable)
+        {
+            anRequestedGeomFields.push_back(0);
+            eGCreateLayerType = wkbNone;
+        }
+        // If the source feature first geometry column is not nullable
+        // and that GEOMETRY_NULLABLE creation option is available, use it
+        // so as to be able to set the not null constraint (if the driver supports it)
+        else if( anRequestedGeomFields.size() == 0 &&
+                 nSrcGeomFieldCount >= 1 &&
+                 !poSrcFDefn->GetGeomFieldDefn(0)->IsNullable() &&
+                 poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST) != NULL &&
+                 strstr(poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST), "GEOMETRY_NULLABLE") != NULL &&
+                 CSLFetchNameValue(papszLCO, "GEOMETRY_NULLABLE") == NULL&&
+                 !bForceNullable )
+        {
+            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "GEOMETRY_NULLABLE", "NO");
+            CPLDebug("OGR2OGR", "Using GEOMETRY_NULLABLE=NO");
+        }
+
+        // Force FID column as 64 bit if the source feature has a 64 bit FID,
+        // the target driver supports 64 bit FID and the user didn't set it
+        // manually.
+        if( poSrcLayer->GetMetadataItem(OLMD_FID64) != NULL &&
+            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES") &&
+            poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST) != NULL &&
+            strstr(poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST), "FID64") != NULL &&
+            CSLFetchNameValue(papszLCO, "FID64") == NULL )
+        {
+            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID64", "YES");
+            CPLDebug("OGR2OGR", "Using FID64=YES");
+        }
+
+        // If output driver supports FID layer creation option, set it with
+        // the FID column name of the source layer
+        if( !bUnsetFid && !bAppend &&
+            poSrcLayer->GetFIDColumn() != NULL &&
+            !EQUAL(poSrcLayer->GetFIDColumn(), "") &&
+            poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST) != NULL &&
+            strstr(poDstDS->GetDriver()->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST), "='FID'") != NULL &&
+            CSLFetchNameValue(papszLCO, "FID") == NULL )
+        {
+            papszLCOTemp = CSLSetNameValue(papszLCOTemp, "FID", poSrcLayer->GetFIDColumn());
+            CPLDebug("OGR2OGR", "Using FID=%s and -preserve_fid", poSrcLayer->GetFIDColumn());
+            bPreserveFID = TRUE;
+        }
 
         poDstLayer = poDstDS->CreateLayer( pszNewLayerName, poOutputSRS,
                                            (OGRwkbGeometryType) eGCreateLayerType,
-                                           papszLCO );
+                                           papszLCOTemp );
+        CSLDestroy(papszLCOTemp);
 
         if( poDstLayer == NULL )
             return NULL;
+        
+        if( bCopyMD )
+        {
+            char** papszDomains = poSrcLayer->GetMetadataDomainList();
+            for(char** papszIter = papszDomains; papszIter && *papszIter; ++papszIter )
+            {
+                if( !EQUAL(*papszIter, "IMAGE_STRUCTURE") &&
+                    !EQUAL(*papszIter, "SUBDATASETS") )
+                {
+                    char** papszMD = poSrcLayer->GetMetadata(*papszIter);
+                    if( papszMD )
+                        poDstLayer->SetMetadata(papszMD, *papszIter);
+                }
+            }
+            CSLDestroy(papszDomains);
+        }
 
         if( anRequestedGeomFields.size() == 0 &&
             nSrcGeomFieldCount > 1 &&
@@ -2723,17 +3133,12 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                 else
                 {
                     eGType = oGFldDefn.GetType();
-                    int n25DBit = eGType & wkb25DBit;
-                    if ( bPromoteToMulti )
-                    {
-                        if (wkbFlatten(eGType) == wkbLineString)
-                            eGType = wkbMultiLineString | n25DBit;
-                        else if (wkbFlatten(eGType) == wkbPolygon)
-                            eGType = wkbMultiPolygon | n25DBit;
-                    }
+                    eGType = ConvertType(sGeomConversion, (OGRwkbGeometryType)eGType);
                     eGType = ForceCoordDimension(eGType, nCoordDim);
                     oGFldDefn.SetType((OGRwkbGeometryType) eGType);
                 }
+                if( bForceNullable )
+                    oGFldDefn.SetNullable(TRUE);
                 poDstLayer->CreateGeomField(&oGFldDefn);
             }
         }
@@ -2773,6 +3178,7 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
 /* -------------------------------------------------------------------- */
     int         nSrcFieldCount = poSrcFDefn->GetFieldCount();
     int         iField, *panMap;
+    int         iSrcFIDField = -1;
 
     // Initialize the index-to-index map to -1's
     panMap = (int *) VSIMalloc( sizeof(int) * nSrcFieldCount );
@@ -2821,18 +3227,13 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                 OGRFieldDefn* poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iSrcField);
                 OGRFieldDefn oFieldDefn( poSrcFieldDefn );
 
-                if (papszFieldTypesToString != NULL &&
-                    (CSLFindString(papszFieldTypesToString, "All") != -1 ||
-                     CSLFindString(papszFieldTypesToString,
-                                   OGRFieldDefn::GetFieldTypeName(poSrcFieldDefn->GetType())) != -1))
-                {
-                    oFieldDefn.SetType(OFTString);
-                }
-                if( bUnsetFieldWidth )
-                {
-                    oFieldDefn.SetWidth(0);
-                    oFieldDefn.SetPrecision(0);
-                }
+                DoFieldTypeConversion(poDstDS, oFieldDefn,
+                                      papszFieldTypesToString,
+                                      papszMapFieldType,
+                                      bUnsetFieldWidth,
+                                      bQuiet,
+                                      bForceNullable,
+                                      bUnsetDefault);
 
                 /* The field may have been already created at layer creation */
                 int iDstField = -1;
@@ -2879,7 +3280,7 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
             {
                 /* We must not ignore fields used in the -where expression (#4015) */
                 OGRFeatureQuery oFeatureQuery;
-                if ( oFeatureQuery.Compile( poSrcLayer->GetLayerDefn(), pszWHERE ) == OGRERR_NONE )
+                if ( oFeatureQuery.Compile( poSrcLayer->GetLayerDefn(), pszWHERE, FALSE, NULL ) == OGRERR_NONE )
                 {
                     papszWHEREUsedFields = oFeatureQuery.GetUsedFields();
                 }
@@ -2889,7 +3290,7 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                 }
             }
 
-            for(iSrcField=0;iSrcField<poSrcFDefn->GetFieldCount();iSrcField++)
+            for(iSrcField=0;bUseIgnoredFields && iSrcField<poSrcFDefn->GetFieldCount();iSrcField++)
             {
                 const char* pszFieldName =
                     poSrcFDefn->GetFieldDefn(iSrcField)->GetNameRef();
@@ -2937,24 +3338,29 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                          "adding the fields of the source layer", pszFieldName); */
         }
 
+        const char* pszFIDColumn = poDstLayer->GetFIDColumn();
+
         for( iField = 0; iField < nSrcFieldCount; iField++ )
         {
             OGRFieldDefn* poSrcFieldDefn = poSrcFDefn->GetFieldDefn(iField);
             OGRFieldDefn oFieldDefn( poSrcFieldDefn );
 
-            if (papszFieldTypesToString != NULL &&
-                (CSLFindString(papszFieldTypesToString, "All") != -1 ||
-                 CSLFindString(papszFieldTypesToString,
-                               OGRFieldDefn::GetFieldTypeName(poSrcFieldDefn->GetType())) != -1))
+            // Avoid creating a field with the same name as the FID column
+            if( pszFIDColumn != NULL && EQUAL(pszFIDColumn, oFieldDefn.GetNameRef()) &&
+                (oFieldDefn.GetType() == OFTInteger || oFieldDefn.GetType() == OFTInteger64) )
             {
-                oFieldDefn.SetType(OFTString);
-            }
-            if( bUnsetFieldWidth )
-            {
-                oFieldDefn.SetWidth(0);
-                oFieldDefn.SetPrecision(0);
+                iSrcFIDField = iField;
+                continue;
             }
 
+            DoFieldTypeConversion(poDstDS, oFieldDefn,
+                                  papszFieldTypesToString,
+                                  papszMapFieldType,
+                                  bUnsetFieldWidth,
+                                  bQuiet,
+                                  bForceNullable,
+                                  bUnsetDefault);
+
             /* The field may have been already created at layer creation */
             std::map<CPLString, int>::iterator oIter =
                 oMapExistingFields.find(CPLString(oFieldDefn.GetNameRef()).toupper());
@@ -3052,6 +3458,7 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                                             CPLMalloc(sizeof(TargetLayerInfo));
     psInfo->nFeaturesRead = 0;
     psInfo->bPerFeatureCT = FALSE;
+    psInfo->poSrcLayer = poSrcLayer;
     psInfo->poDstLayer = poDstLayer;
     psInfo->papoCT = (OGRCoordinateTransformation**)
         CPLCalloc(poDstLayer->GetLayerDefn()->GetGeomFieldCount(),
@@ -3061,10 +3468,12 @@ static TargetLayerInfo* SetupTargetLayer( CPL_UNUSED OGRDataSource *poSrcDS,
                   sizeof(char**));
     psInfo->panMap = panMap;
     psInfo->iSrcZField = iSrcZField;
+    psInfo->iSrcFIDField = iSrcFIDField;
     if( anRequestedGeomFields.size() == 1 )
         psInfo->iRequestedSrcGeomField = anRequestedGeomFields[0];
     else
         psInfo->iRequestedSrcGeomField = -1;
+    psInfo->bPreserveFID = bPreserveFID;
 
     return psInfo;
 }
@@ -3246,45 +3655,29 @@ static int SetupCT( TargetLayerInfo* psInfo,
     return TRUE;
 }
 /************************************************************************/
-/*                           TranslateLayer()                           */
+/*                     LayerTranslator::Translate()                     */
 /************************************************************************/
 
-static int TranslateLayer( TargetLayerInfo* psInfo,
-                           OGRDataSource *poSrcDS,
-                           OGRLayer * poSrcLayer,
-                           CPL_UNUSED OGRDataSource *poDstDS,
-                           int bTransform,
-                           int bWrapDateline,
-                           const char* pszDateLineOffset,
-                           OGRSpatialReference *poOutputSRS,
-                           int bNullifyOutputSRS,
-                           OGRSpatialReference *poUserSourceSRS,
-                           OGRCoordinateTransformation *poGCPCoordTrans,
-                           int eGType,
-                           int bPromoteToMulti,
-                           int nCoordDim,
-                           GeomOperation eGeomOp,
-                           double dfGeomOpParam,
-                           long nCountLayerFeatures,
-                           OGRGeometry* poClipSrc,
-                           OGRGeometry *poClipDst,
-                           int bExplodeCollections,
-                           vsi_l_offset nSrcFileSize,
-                           GIntBig* pnReadFeatureCount,
-                           GDALProgressFunc pfnProgress,
-                           void *pProgressArg )
-
+int LayerTranslator::Translate( TargetLayerInfo* psInfo,
+                                GIntBig nCountLayerFeatures,
+                                GIntBig* pnReadFeatureCount,
+                                GDALProgressFunc pfnProgress,
+                                void *pProgressArg )
 {
+    OGRLayer    *poSrcLayer;
     OGRLayer    *poDstLayer;
-    int         bForceToPolygon = FALSE;
-    int         bForceToMultiPolygon = FALSE;
-    int         bForceToMultiLineString = FALSE;
     int         *panMap = NULL;
     int         iSrcZField;
+    int         eGType = eGTypeIn;
+    OGRSpatialReference* poOutputSRS = poOutputSRSIn;
+    int         bExplodeCollections = bExplodeCollectionsIn;
+    int         bPreserveFID;
 
+    poSrcLayer = psInfo->poSrcLayer;
     poDstLayer = psInfo->poDstLayer;
     panMap = psInfo->panMap;
     iSrcZField = psInfo->iSrcZField;
+    bPreserveFID = psInfo->bPreserveFID;
     int nSrcGeomFieldCount = poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
     int nDstGeomFieldCount = poDstLayer->GetLayerDefn()->GetGeomFieldCount();
 
@@ -3301,14 +3694,7 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
         }
 
     }
-    
-    if( wkbFlatten(eGType) == wkbPolygon )
-        bForceToPolygon = TRUE;
-    else if( wkbFlatten(eGType) == wkbMultiPolygon )
-        bForceToMultiPolygon = TRUE;
-    else if( wkbFlatten(eGType) == wkbMultiLineString )
-        bForceToMultiLineString = TRUE;
-    
+
     if( bExplodeCollections && nDstGeomFieldCount > 1 )
     {
         bExplodeCollections = FALSE;
@@ -3323,20 +3709,17 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
     GIntBig      nFeaturesWritten = 0;
 
     if( nGroupTransactions )
-        poDstLayer->StartTransaction();
+    {
+        if( bLayerTransaction )
+            poDstLayer->StartTransaction();
+    }
 
     while( TRUE )
     {
         OGRFeature      *poDstFeature = NULL;
 
         if( nFIDToFetch != OGRNullFID )
-        {
-            // Only fetch feature on first pass.
-            if( nFeaturesInTransaction == 0 )
-                poFeature = poSrcLayer->GetFeature(nFIDToFetch);
-            else
-                poFeature = NULL;
-        }
+            poFeature = poSrcLayer->GetFeature(nFIDToFetch);
         else
             poFeature = poSrcLayer->GetNextFeature();
 
@@ -3388,8 +3771,16 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
         {
             if( ++nFeaturesInTransaction == nGroupTransactions )
             {
-                poDstLayer->CommitTransaction();
-                poDstLayer->StartTransaction();
+                if( bLayerTransaction )
+                {
+                    poDstLayer->CommitTransaction();
+                    poDstLayer->StartTransaction();
+                }
+                else
+                {
+                    poODS->CommitTransaction();
+                    poODS->StartTransaction();
+                }
                 nFeaturesInTransaction = 0;
             }
 
@@ -3414,10 +3805,15 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
             if( poDstFeature->SetFrom( poFeature, panMap, TRUE ) != OGRERR_NONE )
             {
                 if( nGroupTransactions )
-                    poDstLayer->CommitTransaction();
+                {
+                    if( bLayerTransaction )
+                    {
+                        poDstLayer->CommitTransaction();
+                    }
+                }
 
                 CPLError( CE_Failure, CPLE_AppDefined,
-                        "Unable to translate feature %ld from layer %s.\n",
+                        "Unable to translate feature " CPL_FRMT_GIB " from layer %s.\n",
                         poFeature->GetFID(), poSrcLayer->GetName() );
 
                 OGRFeature::DestroyFeature( poFeature );
@@ -3434,6 +3830,9 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
 
             if( bPreserveFID )
                 poDstFeature->SetFID( poFeature->GetFID() );
+            else if( psInfo->iSrcFIDField >= 0 &&
+                     poFeature->IsFieldSet(psInfo->iSrcFIDField))
+                poDstFeature->SetFID( poFeature->GetFieldAsInteger64(psInfo->iSrcFIDField) );
             
             for( int iGeom = 0; iGeom < nDstGeomFieldCount; iGeom ++ )
             {
@@ -3463,7 +3862,7 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
                     poDstGeometry->setCoordinateDimension( nCoordDim );
                 else if ( nCoordDim == COORD_DIM_LAYER_DIM )
                     poDstGeometry->setCoordinateDimension(
-                        (poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom)->GetType() & wkb25DBit) ? 3 : 2 );
+                        wkbHasZ(poDstLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom)->GetType()) ? 3 : 2 );
 
                 if (eGeomOp == SEGMENTIZE)
                 {
@@ -3507,7 +3906,12 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
                     if( poReprojectedGeom == NULL )
                     {
                         if( nGroupTransactions )
-                            poDstLayer->CommitTransaction();
+                        {
+                            if( bLayerTransaction )
+                            {
+                                poDstLayer->CommitTransaction();
+                            }
+                        }
 
                         fprintf( stderr, "Failed to reproject feature %d (geometry probably out of source or destination SRS).\n",
                                 (int) poFeature->GetFID() );
@@ -3540,25 +3944,24 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
                     poDstGeometry = poClipped;
                 }
 
-                if( bForceToPolygon )
+                if( eGType != -2 )
                 {
                     poDstFeature->SetGeomFieldDirectly(iGeom, 
-                        OGRGeometryFactory::forceToPolygon(
-                            poDstFeature->StealGeometry(iGeom) ) );
+                        OGRGeometryFactory::forceTo(
+                            poDstFeature->StealGeometry(iGeom), (OGRwkbGeometryType)eGType) );
                 }
-                else if( bForceToMultiPolygon ||
-                        (bPromoteToMulti && wkbFlatten(poDstGeometry->getGeometryType()) == wkbPolygon) )
+                else if( sGeomConversion.bPromoteToMulti ||
+                         sGeomConversion.bConvertToLinear ||
+                         sGeomConversion.bConvertToCurve )
                 {
-                    poDstFeature->SetGeomFieldDirectly(iGeom, 
-                        OGRGeometryFactory::forceToMultiPolygon(
-                            poDstFeature->StealGeometry(iGeom) ) );
-                }
-                else if ( bForceToMultiLineString ||
-                        (bPromoteToMulti && wkbFlatten(poDstGeometry->getGeometryType()) == wkbLineString) )
-                {
-                    poDstFeature->SetGeomFieldDirectly(iGeom, 
-                        OGRGeometryFactory::forceToMultiLineString(
-                            poDstFeature->StealGeometry(iGeom) ) );
+                    poDstGeometry = poDstFeature->StealGeometry(iGeom);
+                    if( poDstGeometry != NULL )
+                    {
+                        OGRwkbGeometryType eTargetType = poDstGeometry->getGeometryType();
+                        eTargetType = ConvertType(sGeomConversion, eTargetType);
+                        poDstGeometry = OGRGeometryFactory::forceTo(poDstGeometry, eTargetType);
+                        poDstFeature->SetGeomFieldDirectly(iGeom, poDstGeometry);
+                    }
                 }
             }
 
@@ -3566,14 +3969,24 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
             if( poDstLayer->CreateFeature( poDstFeature ) == OGRERR_NONE )
             {
                 nFeaturesWritten ++;
+                if( (bPreserveFID && poDstFeature->GetFID() != poFeature->GetFID()) ||
+                    (!bPreserveFID && psInfo->iSrcFIDField >= 0 && poFeature->IsFieldSet(psInfo->iSrcFIDField) &&
+                     poDstFeature->GetFID() != poFeature->GetFieldAsInteger64(psInfo->iSrcFIDField)) )
+                {
+                    CPLError( CE_Warning, CPLE_AppDefined,
+                              "Feature id not preserved");
+                }
             }
             else if( !bSkipFailures )
             {
                 if( nGroupTransactions )
-                    poDstLayer->RollbackTransaction();
+                {
+                    if( bLayerTransaction )
+                        poDstLayer->RollbackTransaction();
+                }
 
                 CPLError( CE_Failure, CPLE_AppDefined,
-                        "Unable to write feature %ld from layer %s.\n",
+                        "Unable to write feature " CPL_FRMT_GIB " from layer %s.\n",
                         poFeature->GetFID(), poSrcLayer->GetName() );
 
                 OGRFeature::DestroyFeature( poFeature );
@@ -3582,7 +3995,7 @@ static int TranslateLayer( TargetLayerInfo* psInfo,
             }
             else
             {
-                CPLDebug( "OGR2OGR", "Unable to write feature %ld into layer %s.\n",
+                CPLDebug( "OGR2OGR", "Unable to write feature " CPL_FRMT_GIB " into layer %s.\n",
                            poFeature->GetFID(), poSrcLayer->GetName() );
             }
 
@@ -3623,10 +4036,18 @@ end_loop:
 
         if (pnReadFeatureCount)
             *pnReadFeatureCount = nCount;
+        
+        if( nFIDToFetch != OGRNullFID )
+            break;
     }
 
     if( nGroupTransactions )
-        poDstLayer->CommitTransaction();
+    {
+        if( bLayerTransaction )
+        {
+            poDstLayer->CommitTransaction();
+        }
+    }
 
     CPLDebug("OGR2OGR", CPL_FRMT_GIB " features written in layer '%s'",
              nFeaturesWritten, poDstLayer->GetName());
diff --git a/apps/ogr_utilities.dox b/apps/ogr_utilities.dox
index 94b46cc..dadd4cb 100644
--- a/apps/ogr_utilities.dox
+++ b/apps/ogr_utilities.dox
@@ -26,7 +26,9 @@ Usage:
 ogrinfo [--help-general] [-ro] [-q] [-where restricted_where]
         [-spat xmin ymin xmax ymax] [-geomfield field] [-fid fid]
         [-sql statement] [-dialect dialect] [-al] [-so] [-fields={YES/NO}]
-        [-geom={YES/NO/SUMMARY}][--formats]
+        [-geom={YES/NO/SUMMARY}] [-formats] [[-oo NAME=VALUE] ...]
+        [-nomd] [-listmdd] [-mdd domain|`all`]*
+        [-nocount] [-noextent]
         datasource_name [layer [layer ...]]
 
 \endverbatim
@@ -40,7 +42,7 @@ source to stdout (the terminal).
 <dt> <b>-ro</b>:</dt><dd> Open the data source in read-only mode.  </dd>
 <dt> <b>-al</b>:</dt><dd> List all features of all layers (used instead of having to
 give layer names as arguments).</dd>
-<dt> <b>-so</b>:</dt><dd> Summary Only: supress listing of features, show only the 
+<dt> <b>-so</b>:</dt><dd> Summary Only: suppress listing of features, show only the 
 summary information like projection, schema, feature count and
 extents.</dd>
 <dt> <b>-q</b>:</dt><dd> Quiet verbose reporting of various information, including
@@ -67,6 +69,14 @@ the feature dump will not display field values. Default value is YES.</dd>
 the feature dump will not display the geometry. If set to SUMMARY, only a
 summary of the geometry will be displayed. If set to YES, the geometry will be reported in full OGC WKT format.
 Default value is YES.</dd>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Dataset open option (format specific)</dd>
+<dt> <b>-nomd</b></dt><dd>(starting with GDAL 2.0)  Suppress metadata printing. Some datasets may contain a lot
+of metadata strings.</dd>
+<dt> <b>-listmdd</b></dt><dd>(starting with GDAL 2.0)  List all metadata domains available for the dataset.</dd>
+<dt> <b>-mdd domain</b></dt><dd>(starting with GDAL 2.0)  Report metadata for the specified domain.
+"all" can be used to report metadata in all domains</dd>
+<dt> <b>-nocount</b></dt><dd>(starting with GDAL 2.0)  Suppress feature count printing.</dd>
+<dt> <b>-noextent</b></dt><dd>(starting with GDAL 2.0)  Suppress spatial extent printing.</dd>
 <dt> <b>--formats</b>:</dt><dd> List the format drivers that are
 enabled.</dd>
 <dt> <i>datasource_name</i>:</dt><dd> The data source to open.  May be a filename, 
@@ -178,10 +188,13 @@ Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update]
                [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]
                [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]
                dst_datasource_name src_datasource_name
-               [-lco NAME=VALUE] [-nln name] [-nlt type] [-dim 2|3|layer_dim] [layer [layer ...]]
+               [-lco NAME=VALUE] [-nln name]
+               [-nlt type|PROMOTE_TO_MULTI|CONVERT_TO_LINEAR]
+               [-dim 2|3|layer_dim] [layer [layer ...]]
 
 Advanced options :
                [-gt n]
+               [[-oo NAME=VALUE] ...] [[-doo NAME=VALUE] ...]
                [-clipsrc [xmin ymin xmax ymax]|WKT|datasource|spat_extent]
                [-clipsrcsql sql_statement] [-clipsrclayer layer]
                [-clipsrcwhere expression]
@@ -190,12 +203,15 @@ Advanced options :
                [-clipdstwhere expression]
                [-wrapdateline] [-datelineoffset val]
                [[-simplify tolerance] | [-segmentize max_dist]]
-               [-addfields]
+               [-addfields] [-unsetFid]
+               [-relaxedFieldNameMatch] [-forceNullable] [-unsetDefault]
                [-fieldTypeToString All|(type1[,type2]*)] [-unsetFieldWidth]
+               [-mapFieldType type1|All=type2[,type3=type4]*]
                [-fieldmap identity | index1[,index2]*]
                [-splitlistfields] [-maxsubfields val]
                [-explodecollections] [-zfield field_name]
                [-gcp pixel line easting northing [elevation]]* [-order n | -tps]
+               [-nomd] [-mo \"META-TAG=VALUE\"]*
 
 \endverbatim
 
@@ -242,12 +258,16 @@ on which the spatial filter operates on.</dd>
 <dt> <b>-nln</b><em> name</em>:</dt><dd> Assign an alternate name to the new layer</dd>
 <dt> <b>-nlt</b><em> type</em>:</dt><dd> Define the geometry type for the 
 created layer.  One of NONE, GEOMETRY, POINT, LINESTRING, POLYGON, 
-GEOMETRYCOLLECTION, MULTIPOINT, MULTIPOLYGON or MULTILINESTRING. 
+GEOMETRYCOLLECTION, MULTIPOINT, MULTIPOLYGON or MULTILINESTRING. And CIRCULARSTRING,
+COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE and MULTISURFACE for GDAL 2.0 non-linear geometry
+types. 
 Add "25D" to the name to get 2.5D versions.
 Starting with GDAL 1.10, PROMOTE_TO_MULTI can be used to automatically promote layers
 that mix polygon or multipolygons to multipolygons, and layers that mix linestrings or
 multilinestrings to multilinestrings. Can be usefull when converting shapefiles to PostGIS
-(and other target drivers) that implements strict checks for geometry type.</dd>
+(and other target drivers) that implements strict checks for geometry type.
+Starting with GDAL 2.0, CONVERT_TO_LINEAR can be used to to convert non-linear geometries
+types into linear geometries by approximating them.</dd>
 <dt> <b>-dim</b><em> val</em>:</dt><dd>(starting with GDAL 1.10) Force the coordinate dimension to val (valid values are 2 or 3).
 This affects both the layer geometry type, and feature geometries.
 Starting with GDAL 1.11, the value can be set to "layer_dim" to instruct feature geometries to be promoted
@@ -256,7 +276,11 @@ to the coordinate dimension declared by the layer.
 <dt> <b>-a_srs</b><em> srs_def</em>:</dt><dd> Assign an output SRS</dd>
 <dt> <b>-t_srs</b><em> srs_def</em>:</dt><dd> Reproject/transform to this SRS on output</dd>
 <dt> <b>-s_srs</b><em> srs_def</em>:</dt><dd> Override source SRS</dd>
-<dt> <b>-preserve_fid</b>:</dt><dd>Use the FID of the source features instead of letting the output driver to automatically assign a new one.</dd>
+<dt> <b>-preserve_fid</b>:</dt><dd>Use the FID of the source features instead of letting the output driver to automatically assign a new one.
+Note: starting with GDAL 2.0, if not in append mode, this behaviour becomes the default if the output driver
+has a FID layer creation option. In which case the name of the source FID column will
+be used and source feature IDs will be attempted to be preserved. This behaviour
+can be disabled by setting -unsetFid</dd>
 <dt> <b>-fid</b> <i>fid</i>:</dt><dd> If provided, only the feature with this feature
 id will be reported.  Operates exclusive of the spatial or attribute 
 queries.  Note: if you want to select several features based on their feature id, you can
@@ -270,6 +294,8 @@ known definition (ie. EPSG:4326) or a file with a WKT definition.
 Advanced options :
 
 <dl>
+<dt> <b>-oo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Input dataset open option (format specific)</dd>
+<dt> <b>-doo</b> <em>NAME=VALUE</em>:</dt><dd>(starting with GDAL 2.0) Destination dataset open option (format specific), only valid in -update mode</dd>
 <dt> <b>-gt</b> <em>n</em>:</dt><dd> group <em>n</em> features per transaction (default 20000 in OGR 1.11, 200 in previous releases). Increase the value
 for better performance when writing into DBMS drivers that have transaction support.</dd>
 <dt> <b>-clipsrc</b><em> [xmin ymin xmax ymax]|WKT|datasource|spat_extent</em>:
@@ -295,9 +321,18 @@ Note: the algorithm used preserves topology per feature, in particular for polyg
 <dt> <b>-segmentize</b><em> max_dist</em>:</dt><dd> (starting with GDAL 1.6.0) maximum distance between 2 nodes.
 Used to create intermediate points</dd>
 <dt> <b>-fieldTypeToString</b><em> type1, ...</em>:</dt><dd> (starting with GDAL 1.7.0) converts any field of the
-specified type to a field of type string in the destination layer. Valid types are : Integer, Real, String, Date, Time,
-DateTime, Binary, IntegerList, RealList, StringList. Special value <b>All</b> can be used to convert all fields to strings.
-This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query.</dd>
+specified type to a field of type string in the destination layer. Valid types are : Integer, Integer64, Real, String, Date, Time,
+DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Special value <b>All</b> can be used to convert all fields to strings.
+This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query.
+Note that this does not influence the field types used by the source driver, and is only an afterwards conversion.</dd>
+<dt> <b>-mapFieldType</b><em> srctype|All=dsttype, ...</em>:</dt><dd> (starting with GDAL 2.0) converts any field of the
+specified type to another type. Valid types are : Integer, Integer64, Real, String, Date, Time,
+DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Types can also include subtype
+between parenthesis, such as Integer(Boolean), Real(Float32), ...
+Special value <b>All</b> can be used to convert all fields to another type.
+This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query. This is
+a generalization of -fieldTypeToString.
+Note that this does not influence the field types used by the source driver, and is only an afterwards conversion.</dd>
 <dt> <b>-unsetFieldWidth</b>:</dt><dd> (starting with GDAL 1.11) set field width and precision to 0.</dd>
 <dt> <b>-splitlistfields</b>:</dt><dd>(starting with GDAL 1.8.0) split fields of type StringList, RealList or IntegerList into as many fields of type String, Real or Integer as necessary.</dd>
 <dt> <b>-maxsubfields</b> <em>val</em>:</dt><dd>To be combined with -splitlistfields to limit the number of subfields created for each split field.</dd>
@@ -319,9 +354,26 @@ We can use the 'identity' setting to specify that the fields should be transferr
 This setting should be used along with the -append setting.</dd>
 <dt> <b>-addfields</b>:</dt><dd>(starting with GDAL 1.11) This is a specialized version of
 -append. Contrary to -append, -addfields has the effect of adding, to existing target layers,
-the new fields found in source layers. This option is usefull when merging files that have non-strictly
+the new fields found in source layers. This option is useful when merging files that have non-strictly
 identical structures.
 This might not work for output formats that don't support adding fields to existing non-empty layers.</dd>
+<dt> <b>-relaxedFieldNameMatch</b>:</dt><dd>(starting with GDAL 1.11) Do field name matching between
+source and existing target layer in a more relaxed way if the target driver has an implementation for it.</dd>
+[-relaxedFieldNameMatch] [-forceNullable]
+<dt> <b>-forceNullable</b>:</dt><dd>(starting with GDAL 2.0) Do not propagate not-nullable constraints
+to target layer if they exist in source layer..</dd>
+<dt> <b>-unsetDefault</b>:</dt><dd>(starting with GDAL 2.0) Do not propagate default field values
+to target layer if they exist in source layer..</dd>
+<dt> <b>-unsetFid</b>:</dt><dd>(starting with GDAL 2.0) Can be specify to prevent
+the new default behaviour that consists in, if the output driver
+has a FID layer creation option and we are not in append mode, to preserve the
+name of the source FID column and source feature IDs</dd>
+<dt> <b>-nomd</b>:</dt><dd>(starting with GDAL 2.0) To disable copying of metadata
+from source dataset and layers into target dataset and layers, when supported by
+output driver.</dd>
+<dt> <b>-mo</b> <i>"META-TAG=VALUE"</i>:</dt><dd>(starting with GDAL 2.0)  Passes a metadata key and
+value to set on the output dataset, when supported by output driver.</dd>
+
 </dl>
 
 \section ogr2ogr_performance PERFORMANCE HINTS
@@ -396,7 +448,7 @@ to layers using the OGR connection type.
 
 <dl>
 <dt><b>-lnum</b> <em>n</em>:</dt><dd> Add layer number 'n' from each source
-		file in the tile index.</dd>
+        file in the tile index.</dd>
 <dt><b>-lname</b> <em>name</em>:</dt><dd> Add the layer named 'name' from each source file
         in the tile index.</dd>
 <dt><b>-f</b> <em>output_format</em>:</dt><dd> Select an output format name.  The default
@@ -406,6 +458,10 @@ to layers using the OGR connection type.
 <dt><b>-write_absolute_path</b>:</dt><dd> Filenames are written with absolute paths</dd>
 <dt><b>-skip_different_projection</b>:</dt><dd> Only layers with same projection ref
         as layers already inserted in the tileindex will be inserted.</dd>
+<dt><b>-accept_different_schemas</b>:</dt><dd> By default ogrtindex checks that all 
+        layers inserted into the index have the same attribute schemas. If you specify
+        this option, this test will be disabled. Be aware that resulting index may be 
+        incompatible with MapServer!</dd>
 </dl>
 
 If no -lnum or -lname arguments are given it is assumed that
@@ -473,7 +529,7 @@ format. Also some information writed to the stdout.
 <dl>
 <dt><b>--help-general</b>:</dt><dd> Show the usage.</dd>
 <dt><b>-progress</b>:</dt><dd> Show progress.</dd>
-<dt><b>-quiet</b>:</dt><dd> Supress all messages except errors and results.</dd>
+<dt><b>-quiet</b>:</dt><dd> Suppress all messages except errors and results.</dd>
 <dt><b>-f</b> <em>format_name</em>:</dt><dd> Select an output format name.
     The default is to create a shapefile.</dd>
 <dt> <b>-dsco</b> <em>NAME=VALUE</em>:</dt><dd> Dataset creation option 
@@ -527,4 +583,4 @@ Dmitry Baryshnikov <polimax at mail.ru>
 
 \endif
 
-*/
\ No newline at end of file
+*/
diff --git a/apps/ogrdissolve.cpp b/apps/ogrdissolve.cpp
index bdd6556..7895a28 100644
--- a/apps/ogrdissolve.cpp
+++ b/apps/ogrdissolve.cpp
@@ -147,46 +147,36 @@ int main( int nArgc, char ** papszArgv )
         }
         else if( EQUAL(papszArgv[iArg],"-nlt") && iArg < nArgc-1 )
         {
-            if( EQUAL(papszArgv[iArg+1],"NONE") )
+            int bIs3D = FALSE;
+            CPLString osGeomName = papszArgv[iArg+1];
+            if (strlen(papszArgv[iArg+1]) > 3 &&
+                EQUALN(papszArgv[iArg+1] + strlen(papszArgv[iArg+1]) - 3, "25D", 3))
+            {
+                bIs3D = TRUE;
+                osGeomName.resize(osGeomName.size() - 3);
+            }
+            else if (strlen(papszArgv[iArg+1]) > 1 &&
+                EQUALN(papszArgv[iArg+1] + strlen(papszArgv[iArg+1]) - 1, "Z", 1))
+            {
+                bIs3D = TRUE;
+                osGeomName.resize(osGeomName.size() - 1);
+            }
+            if( EQUAL(osGeomName,"NONE") )
                 eGType = wkbNone;
-            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY") )
+            else if( EQUAL(osGeomName,"GEOMETRY") )
                 eGType = wkbUnknown;
-            else if( EQUAL(papszArgv[iArg+1],"POINT") )
-                eGType = wkbPoint;
-            else if( EQUAL(papszArgv[iArg+1],"LINESTRING") )
-                eGType = wkbLineString;
-            else if( EQUAL(papszArgv[iArg+1],"POLYGON") )
-                eGType = wkbPolygon;
-            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION") )
-                eGType = wkbGeometryCollection;
-            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT") )
-                eGType = wkbMultiPoint;
-            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING") )
-                eGType = wkbMultiLineString;
-            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON") )
-                eGType = wkbMultiPolygon;
-            else if( EQUAL(papszArgv[iArg+1],"GEOMETRY25D") )
-                eGType = wkbUnknown | wkb25DBit;
-            else if( EQUAL(papszArgv[iArg+1],"POINT25D") )
-                eGType = wkbPoint25D;
-            else if( EQUAL(papszArgv[iArg+1],"LINESTRING25D") )
-                eGType = wkbLineString25D;
-            else if( EQUAL(papszArgv[iArg+1],"POLYGON25D") )
-                eGType = wkbPolygon25D;
-            else if( EQUAL(papszArgv[iArg+1],"GEOMETRYCOLLECTION25D") )
-                eGType = wkbGeometryCollection25D;
-            else if( EQUAL(papszArgv[iArg+1],"MULTIPOINT25D") )
-                eGType = wkbMultiPoint25D;
-            else if( EQUAL(papszArgv[iArg+1],"MULTILINESTRING25D") )
-                eGType = wkbMultiLineString25D;
-            else if( EQUAL(papszArgv[iArg+1],"MULTIPOLYGON25D") )
-                eGType = wkbMultiPolygon25D;
             else
             {
-                fprintf( stderr, "-nlt %s: type not recognised.\n", 
-                         papszArgv[iArg+1] );
-                exit( 1 );
+                eGType = OGRFromOGCGeomType(osGeomName);
+                if (eGType == wkbUnknown)
+                {
+                    fprintf( stderr, "-nlt %s: type not recognised.\n",
+                            papszArgv[iArg+1] );
+                    exit( 1 );
+                }
             }
+            if (eGType != wkbNone && bIs3D)
+                eGType = wkbSetZ((OGRwkbGeometryType)eGType);
             iArg++;
         }
         else if( EQUAL(papszArgv[iArg],"-tg") && iArg < nArgc-1 )
@@ -214,11 +204,11 @@ int main( int nArgc, char ** papszArgv )
         {
             OGRLinearRing  oRing;
 
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
 
             poSpatialFilter = new OGRPolygon();
             ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
diff --git a/apps/ogrinfo.cpp b/apps/ogrinfo.cpp
index 94b748d..8f21308 100644
--- a/apps/ogrinfo.cpp
+++ b/apps/ogrinfo.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrinfo.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrinfo.cpp 28977 2015-04-22 22:21:03Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Simple client for viewing OGR driver data.
@@ -36,18 +36,27 @@
 #include "cpl_multiproc.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: ogrinfo.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrinfo.cpp 28977 2015-04-22 22:21:03Z rouault $");
 
 int     bReadOnly = FALSE;
 int     bVerbose = TRUE;
 int     bSummaryOnly = FALSE;
-int     nFetchFID = OGRNullFID;
+GIntBig nFetchFID = OGRNullFID;
 char**  papszOptions = NULL;
 
 static void Usage(const char* pszErrorMsg = NULL);
 
 static void ReportOnLayer( OGRLayer *, const char *, const char* pszGeomField, 
-                           OGRGeometry * );
+                           OGRGeometry *,
+                           int bListMDD,
+                           int bShowMetadata,
+                           char** papszExtraMDDomains,
+                           int bFeatureCount,
+                           int bExtent  );
+static void GDALInfoReportMetadata( GDALMajorObjectH hObject,
+                                    int bListMDD,
+                                    int bShowMetadata,
+                                    char **papszExtraMDDomains );
 
 /************************************************************************/
 /*                                main()                                */
@@ -69,6 +78,11 @@ int main( int nArgc, char ** papszArgv )
     const char  *pszDialect = NULL;
     int          nRet = 0;
     const char* pszGeomField = NULL;
+    char      **papszOpenOptions = NULL;
+    char      **papszExtraMDDomains = NULL;
+    int                 bListMDD = FALSE;
+    int                  bShowMetadata = TRUE;
+    int         bFeatureCount = TRUE, bExtent = TRUE;
     
     /* Check strict compilation and runtime library version as we use C++ API */
     if (! GDAL_CHECK_VERSION(papszArgv[0]))
@@ -106,18 +120,18 @@ int main( int nArgc, char ** papszArgv )
         else if( EQUAL(papszArgv[iArg],"-fid") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
-            nFetchFID = atoi(papszArgv[++iArg]);
+            nFetchFID = CPLAtoGIntBig(papszArgv[++iArg]);
         }
         else if( EQUAL(papszArgv[iArg],"-spat") )
         {
             CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(4);
             OGRLinearRing  oRing;
 
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+4]) );
-            oRing.addPoint( atof(papszArgv[iArg+3]), atof(papszArgv[iArg+2]) );
-            oRing.addPoint( atof(papszArgv[iArg+1]), atof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+4]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+3]), CPLAtof(papszArgv[iArg+2]) );
+            oRing.addPoint( CPLAtof(papszArgv[iArg+1]), CPLAtof(papszArgv[iArg+2]) );
 
             poSpatialFilter = new OGRPolygon();
             ((OGRPolygon *) poSpatialFilter)->addRing( &oRing );
@@ -171,6 +185,26 @@ int main( int nArgc, char ** papszArgv )
             papszOptions = CSLAddString(papszOptions, pszTemp);
             CPLFree(pszTemp);
         }
+        else if( EQUAL(papszArgv[iArg], "-oo") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg], "-nomd") )
+            bShowMetadata = FALSE;
+        else if( EQUAL(papszArgv[iArg], "-listmdd") )
+            bListMDD = TRUE;
+        else if( EQUAL(papszArgv[iArg], "-mdd") )
+        {
+            CHECK_HAS_ENOUGH_ADDITIONAL_ARGS(1);
+            papszExtraMDDomains = CSLAddString( papszExtraMDDomains,
+                                                papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg], "-nocount") )
+            bFeatureCount = FALSE;
+        else if( EQUAL(papszArgv[iArg], "-noextent") )
+            bExtent = FALSE;
         else if( papszArgv[iArg][0] == '-' )
         {
             Usage(CPLSPrintf("Unknown option name '%s'", papszArgv[iArg]));
@@ -187,22 +221,30 @@ int main( int nArgc, char ** papszArgv )
     if( pszDataSource == NULL )
         Usage("No datasource specified.");
 
+    if( pszDialect != NULL && pszWHERE != NULL && pszSQLStatement == NULL )
+        printf("Warning: -dialect is ignored with -where. Use -sql instead");
+
 /* -------------------------------------------------------------------- */
 /*      Open data source.                                               */
 /* -------------------------------------------------------------------- */
-    OGRDataSource       *poDS = NULL;
-    OGRSFDriver         *poDriver = NULL;
+    GDALDataset        *poDS = NULL;
+    GDALDriver         *poDriver = NULL;
 
-    poDS = OGRSFDriverRegistrar::Open( pszDataSource, !bReadOnly, &poDriver );
+    poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+            (!bReadOnly ? GDAL_OF_UPDATE : GDAL_OF_READONLY) | GDAL_OF_VECTOR,
+            NULL, papszOpenOptions, NULL );
     if( poDS == NULL && !bReadOnly )
     {
-        poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE, &poDriver );
+        poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+            GDAL_OF_READONLY | GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL );
         if( poDS != NULL && bVerbose )
         {
             printf( "Had to open data source read-only.\n" );
             bReadOnly = TRUE;
         }
     }
+    if( poDS != NULL )
+        poDriver = poDS->GetDriver();
 
 /* -------------------------------------------------------------------- */
 /*      Report failure                                                  */
@@ -217,7 +259,7 @@ int main( int nArgc, char ** papszArgv )
 
         for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
         {
-            printf( "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+            printf( "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
         }
 
         nRet = 1;
@@ -232,15 +274,20 @@ int main( int nArgc, char ** papszArgv )
     if( bVerbose )
         printf( "INFO: Open of `%s'\n"
                 "      using driver `%s' successful.\n",
-                pszDataSource, poDriver->GetName() );
+                pszDataSource, poDriver->GetDescription() );
 
-    if( bVerbose && !EQUAL(pszDataSource,poDS->GetName()) )
+    if( bVerbose && !EQUAL(pszDataSource,poDS->GetDescription()) )
     {
         printf( "INFO: Internal data source name `%s'\n"
                 "      different from user name `%s'.\n",
-                poDS->GetName(), pszDataSource );
+                poDS->GetDescription(), pszDataSource );
     }
 
+    GDALInfoReportMetadata( (GDALMajorObjectH)poDS,
+                            bListMDD,
+                            bShowMetadata,
+                            papszExtraMDDomains );
+
 /* -------------------------------------------------------------------- */
 /*      Special case for -sql clause.  No source layers required.       */
 /* -------------------------------------------------------------------- */
@@ -269,9 +316,13 @@ int main( int nArgc, char ** papszArgv )
             }
 
             if( pszGeomField != NULL )
-                ReportOnLayer( poResultSet, NULL, pszGeomField, poSpatialFilter );
+                ReportOnLayer( poResultSet, NULL, pszGeomField, poSpatialFilter,
+                               bListMDD, bShowMetadata, papszExtraMDDomains,
+                               bFeatureCount, bExtent );
             else
-                ReportOnLayer( poResultSet, NULL, NULL, NULL );
+                ReportOnLayer( poResultSet, NULL, NULL, NULL,
+                               bListMDD, bShowMetadata, papszExtraMDDomains,
+                               bFeatureCount, bExtent );
             poDS->ReleaseResultSet( poResultSet );
         }
     }
@@ -331,7 +382,9 @@ int main( int nArgc, char ** papszArgv )
                     if( iRepeat != 0 )
                         poLayer->ResetReading();
 
-                    ReportOnLayer( poLayer, pszWHERE, pszGeomField, poSpatialFilter );
+                    ReportOnLayer( poLayer, pszWHERE, pszGeomField, poSpatialFilter,
+                                   bListMDD, bShowMetadata, papszExtraMDDomains,
+                                   bFeatureCount, bExtent );
                 }
             }
         }
@@ -355,7 +408,9 @@ int main( int nArgc, char ** papszArgv )
                 if( iRepeat != 0 )
                     poLayer->ResetReading();
 
-                ReportOnLayer( poLayer, pszWHERE, pszGeomField, poSpatialFilter );
+                ReportOnLayer( poLayer, pszWHERE, pszGeomField, poSpatialFilter,
+                               bListMDD, bShowMetadata, papszExtraMDDomains,
+                               bFeatureCount, bExtent );
             }
         }
     }
@@ -367,7 +422,10 @@ end:
     CSLDestroy( papszArgv );
     CSLDestroy( papszLayers );
     CSLDestroy( papszOptions );
-    OGRDataSource::DestroyDataSource( poDS );
+    CSLDestroy( papszOpenOptions );
+    CSLDestroy( papszExtraMDDomains );
+    if( poDS != NULL )
+        GDALClose( (GDALDatasetH)poDS );
     if (poSpatialFilter)
         OGRGeometryFactory::destroyGeometry( poSpatialFilter );
 
@@ -386,7 +444,9 @@ static void Usage(const char* pszErrorMsg)
     printf( "Usage: ogrinfo [--help-general] [-ro] [-q] [-where restricted_where]\n"
             "               [-spat xmin ymin xmax ymax] [-geomfield field] [-fid fid]\n"
             "               [-sql statement] [-dialect sql_dialect] [-al] [-so] [-fields={YES/NO}]\n"
-            "               [-geom={YES/NO/SUMMARY}][--formats]\n"
+            "               [-geom={YES/NO/SUMMARY}] [-formats] [[-oo NAME=VALUE] ...]\n"
+            "               [-nomd] [-listmdd] [-mdd domain|`all`]*\n"
+            "               [-nocount] [-noextent]\n"
             "               datasource_name [layer [layer ...]]\n");
 
     if( pszErrorMsg != NULL )
@@ -401,7 +461,12 @@ static void Usage(const char* pszErrorMsg)
 
 static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
                            const char* pszGeomField, 
-                           OGRGeometry *poSpatialFilter )
+                           OGRGeometry *poSpatialFilter,
+                           int bListMDD,
+                           int bShowMetadata,
+                           char** papszExtraMDDomains,
+                           int bFeatureCount,
+                           int bExtent )
 
 {
     OGRFeatureDefn      *poDefn = poLayer->GetLayerDefn();
@@ -440,6 +505,11 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
     
     printf( "Layer name: %s\n", poLayer->GetName() );
 
+    GDALInfoReportMetadata( (GDALMajorObjectH)poLayer,
+                            bListMDD,
+                            bShowMetadata,
+                            papszExtraMDDomains );
+
     if( bVerbose )
     {
         int nGeomFieldCount =
@@ -460,10 +530,11 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
                     OGRGeometryTypeToName( poLayer->GetGeomType() ) );
         }
         
-        printf( "Feature Count: %d\n", poLayer->GetFeatureCount() );
+        if( bFeatureCount )
+            printf( "Feature Count: " CPL_FRMT_GIB "\n", poLayer->GetFeatureCount() );
         
         OGREnvelope oExt;
-        if( nGeomFieldCount > 1 )
+        if( bExtent && nGeomFieldCount > 1 )
         {
             for(int iGeom = 0;iGeom < nGeomFieldCount; iGeom ++ )
             {
@@ -471,15 +542,15 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
                 {
                     OGRGeomFieldDefn* poGFldDefn =
                         poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
-                    printf("Extent (%s): (%f, %f) - (%f, %f)\n",
+                    CPLprintf("Extent (%s): (%f, %f) - (%f, %f)\n",
                            poGFldDefn->GetNameRef(),
                            oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
                 }
             }
         }
-        else if (poLayer->GetExtent(&oExt, TRUE) == OGRERR_NONE)
+        else if ( bExtent && poLayer->GetExtent(&oExt, TRUE) == OGRERR_NONE)
         {
-            printf("Extent: (%f, %f) - (%f, %f)\n", 
+            CPLprintf("Extent: (%f, %f) - (%f, %f)\n", 
                    oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY);
         }
 
@@ -520,30 +591,40 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
         if( strlen(poLayer->GetFIDColumn()) > 0 )
             printf( "FID Column = %s\n", 
                     poLayer->GetFIDColumn() );
-    
-        if( nGeomFieldCount > 1 )
+
+        for(int iGeom = 0;iGeom < nGeomFieldCount; iGeom ++ )
         {
-            for(int iGeom = 0;iGeom < nGeomFieldCount; iGeom ++ )
-            {
-                OGRGeomFieldDefn* poGFldDefn =
-                    poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
-                printf( "Geometry Column %d = %s\n", iGeom + 1,
-                        poGFldDefn->GetNameRef() );
-            }
+            OGRGeomFieldDefn* poGFldDefn =
+                poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeom);
+            if( nGeomFieldCount == 1 &&
+                EQUAL(poGFldDefn->GetNameRef(), "")  && poGFldDefn->IsNullable() )
+                break;
+            printf( "Geometry Column ");
+            if( nGeomFieldCount > 1 )
+                printf("%d ", iGeom + 1);
+            if( !poGFldDefn->IsNullable() )
+                printf("NOT NULL ");
+            printf("= %s\n", poGFldDefn->GetNameRef() );
         }
-        else if( strlen(poLayer->GetGeometryColumn()) > 0 )
-            printf( "Geometry Column = %s\n", 
-                    poLayer->GetGeometryColumn() );
 
         for( int iAttr = 0; iAttr < poDefn->GetFieldCount(); iAttr++ )
         {
             OGRFieldDefn    *poField = poDefn->GetFieldDefn( iAttr );
-            
-            printf( "%s: %s (%d.%d)\n",
+            const char* pszType = (poField->GetSubType() != OFSTNone) ?
+                CPLSPrintf("%s(%s)",
+                           poField->GetFieldTypeName( poField->GetType() ),
+                           poField->GetFieldSubTypeName(poField->GetSubType())) :
+                poField->GetFieldTypeName( poField->GetType() );
+            printf( "%s: %s (%d.%d)",
                     poField->GetNameRef(),
-                    poField->GetFieldTypeName( poField->GetType() ),
+                    pszType,
                     poField->GetWidth(),
                     poField->GetPrecision() );
+            if( !poField->IsNullable() )
+                printf(" NOT NULL");
+            if( poField->GetDefault() != NULL )
+                printf(" DEFAULT %s", poField->GetDefault() );
+            printf( "\n" );
         }
     }
 
@@ -565,7 +646,7 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
         poFeature = poLayer->GetFeature( nFetchFID );
         if( poFeature == NULL )
         {
-            printf( "Unable to locate feature id %d on this layer.\n", 
+            printf( "Unable to locate feature id " CPL_FRMT_GIB " on this layer.\n", 
                     nFetchFID );
         }
         else
@@ -575,3 +656,111 @@ static void ReportOnLayer( OGRLayer * poLayer, const char *pszWHERE,
         }
     }
 }
+
+/************************************************************************/
+/*                       GDALInfoPrintMetadata()                        */
+/************************************************************************/
+static void GDALInfoPrintMetadata( GDALMajorObjectH hObject,
+                                   const char *pszDomain,
+                                   const char *pszDisplayedname,
+                                   const char *pszIndent)
+{
+    int i;
+    char **papszMetadata;
+    int bIsxml = FALSE;
+
+    if (pszDomain != NULL && EQUALN(pszDomain, "xml:", 4))
+        bIsxml = TRUE;
+
+    papszMetadata = GDALGetMetadata( hObject, pszDomain );
+    if( CSLCount(papszMetadata) > 0 )
+    {
+        printf( "%s%s:\n", pszIndent, pszDisplayedname );
+        for( i = 0; papszMetadata[i] != NULL; i++ )
+        {
+            if (bIsxml)
+                printf( "%s%s\n", pszIndent, papszMetadata[i] );
+            else
+                printf( "%s  %s\n", pszIndent, papszMetadata[i] );
+        }
+    }
+}
+
+/************************************************************************/
+/*                       GDALInfoReportMetadata()                       */
+/************************************************************************/
+static void GDALInfoReportMetadata( GDALMajorObjectH hObject,
+                                    int bListMDD,
+                                    int bShowMetadata,
+                                    char **papszExtraMDDomains )
+{
+    const char* pszIndent = "";
+
+    /* -------------------------------------------------------------------- */
+    /*      Report list of Metadata domains                                 */
+    /* -------------------------------------------------------------------- */
+    if( bListMDD )
+    {
+        char** papszMDDList = GDALGetMetadataDomainList( hObject );
+        char** papszIter = papszMDDList;
+
+        if( papszMDDList != NULL )
+            printf( "%sMetadata domains:\n", pszIndent );
+        while( papszIter != NULL && *papszIter != NULL )
+        {
+            if( EQUAL(*papszIter, "") )
+                printf( "%s  (default)\n", pszIndent);
+            else
+                printf( "%s  %s\n", pszIndent, *papszIter );
+            papszIter ++;
+        }
+        CSLDestroy(papszMDDList);
+    }
+
+    if (!bShowMetadata)
+        return;
+
+    /* -------------------------------------------------------------------- */
+    /*      Report default Metadata domain.                                 */
+    /* -------------------------------------------------------------------- */
+    GDALInfoPrintMetadata( hObject, NULL, "Metadata", pszIndent );
+
+    /* -------------------------------------------------------------------- */
+    /*      Report extra Metadata domains                                   */
+    /* -------------------------------------------------------------------- */
+    if (papszExtraMDDomains != NULL) {
+        char **papszExtraMDDomainsExpanded = NULL;
+        int iMDD;
+
+        if( EQUAL(papszExtraMDDomains[0], "all") &&
+            papszExtraMDDomains[1] == NULL )
+        {
+            char** papszMDDList = GDALGetMetadataDomainList( hObject );
+            char** papszIter = papszMDDList;
+
+            while( papszIter != NULL && *papszIter != NULL )
+            {
+                if( !EQUAL(*papszIter, "") )
+                {
+                    papszExtraMDDomainsExpanded = CSLAddString(papszExtraMDDomainsExpanded, *papszIter);
+                }
+                papszIter ++;
+            }
+            CSLDestroy(papszMDDList);
+        }
+        else
+        {
+            papszExtraMDDomainsExpanded = CSLDuplicate(papszExtraMDDomains);
+        }
+
+        for( iMDD = 0; iMDD < CSLCount(papszExtraMDDomainsExpanded); iMDD++ )
+        {
+            char pszDisplayedname[256];
+            snprintf(pszDisplayedname, 256, "Metadata (%s)", papszExtraMDDomainsExpanded[iMDD]);
+            GDALInfoPrintMetadata( hObject, papszExtraMDDomainsExpanded[iMDD], pszDisplayedname, pszIndent );
+        }
+
+        CSLDestroy(papszExtraMDDomainsExpanded);
+    }
+
+}
diff --git a/apps/ogrlineref.cpp b/apps/ogrlineref.cpp
index 365b347..204c661 100644
--- a/apps/ogrlineref.cpp
+++ b/apps/ogrlineref.cpp
@@ -44,6 +44,7 @@
 #define FIELD_FINISH "end"
 #define FIELD_SCALE_FACTOR "scale"
 #define DELTA 0.00000001 //- delta
+#define TOLLERANCE 0.00008983153
 
 #if defined(HAVE_GEOS)
 #if GEOS_VERSION_MAJOR > 3 || (GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 2)
@@ -98,10 +99,10 @@ static void Usage(const char* pszAdditionalMsg, int bShort = TRUE)
 
     for (int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++)
     {
-        OGRSFDriver *poDriver = poR->GetDriver(iDriver);
+        GDALDriver *poDriver = poR->GetDriver(iDriver);
 
-        if (poDriver->TestCapability(ODrCCreateDataSource))
-            printf("     -f \"%s\"\n", poDriver->GetName());
+        if( CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
+            printf("     -f \"%s\"\n", poDriver->GetDescription());
     }
 
     printf(" -progress: Display progress on terminal. Only works if input layers have the \n"
@@ -138,7 +139,7 @@ static void Usage(int bShort = TRUE)
 /*                         SetupTargetLayer()                           */
 /************************************************************************/
 
-static OGRLayer* SetupTargetLayer(OGRLayer * poSrcLayer, OGRDataSource *poDstDS, char **papszLCO, const char *pszNewLayerName, const char* pszOutputSepFieldName = NULL)
+static OGRLayer* SetupTargetLayer(OGRLayer * poSrcLayer, GDALDataset *poDstDS, char **papszLCO, const char *pszNewLayerName, const char* pszOutputSepFieldName = NULL)
 {
     OGRLayer    *poDstLayer;
     OGRFeatureDefn *poSrcFDefn;
@@ -148,7 +149,7 @@ static OGRLayer* SetupTargetLayer(OGRLayer * poSrcLayer, OGRDataSource *poDstDS,
     
     if (pszNewLayerName == NULL)
     {
-        szLayerName = CPLGetBasename(poDstDS->GetName());
+        szLayerName = CPLGetBasename(poDstDS->GetDescription());
     }
     else
     {
@@ -540,7 +541,23 @@ OGRErr CreateSubline(OGRLayer* const poPkLayer,
     return OGRERR_NONE;
 }
 
-
+//------------------------------------------------------------------------
+// Project
+//------------------------------------------------------------------------
+double Project(OGRLineString* pLine, OGRPoint* pPoint)
+{
+    if(NULL == pLine || NULL == pPoint)
+        return -1;
+    OGRPoint TestPoint;
+    pLine->StartPoint(&TestPoint);
+    if(TestPoint.Equals(pPoint))
+        return 0;
+    pLine->EndPoint(&TestPoint);
+    if(TestPoint.Equals(pPoint))
+        return pLine->get_Length();
+        
+    return pLine->Project(pPoint);    
+}
 
 //------------------------------------------------------------------------
 // CreatePartsFromLineString
@@ -576,9 +593,9 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
                         "The distance %f is already present in repers file!", dfReperPos);
                 }
             }
-            //check if reper incide path
-            dfTestDistance = pPathGeom->Project(pPt);
-            if (dfTestDistance == 0 || dfTestDistance == pPathGeom->get_Length())
+            //check if reper is incide the path
+            dfTestDistance = Project(pPathGeom, pPt);
+            if (dfTestDistance < 0)
             {
                 if (!bQuiet)
                 {
@@ -588,7 +605,9 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
             }
             else
             {
-                moRepers[dfReperPos] = pPt;
+                double dfDist = pPathGeom->Distance(pPt);
+                if (dfDist < TOLLERANCE)
+                    moRepers[dfReperPos] = pPt;
             }           
         }
         OGRFeature::DestroyFeature(pReperFeature);
@@ -616,8 +635,8 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
     ++IT;
     pt2 = IT->second;
 
-    double dfDistance1 = pPathGeom->Project(pt1);
-    double dfDistance2 = pPathGeom->Project(pt2);
+    double dfDistance1 = Project(pPathGeom, pt1);
+    double dfDistance2 = Project(pPathGeom, pt2);
 
     if (dfDistance1 > dfDistance2)
     {
@@ -627,8 +646,8 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
         }
         pPathGeom->reversePoints();
 
-        dfDistance1 = pPathGeom->Project(pt1);
-        dfDistance2 = pPathGeom->Project(pt2);
+        dfDistance1 = Project(pPathGeom, pt1);
+        dfDistance2 = Project(pPathGeom, pt2);
     }
 
     OGRLineString* pPart = NULL;
@@ -699,12 +718,15 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
         }
     }
 
-    pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
-    if (NULL != pPart)
+    if(dfDistance2 - dfDistance1 > DELTA)
     {
-        CURVE_DATA data = { pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition) };
-        astSubLines.push_back(data);
-//        AddFeature(poOutLayer, pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition), bQuiet);
+        pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
+        if (NULL != pPart)
+        {
+            CURVE_DATA data = { pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition) };
+            astSubLines.push_back(data);
+    //        AddFeature(poOutLayer, pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition), bQuiet);
+        }
     }
 
     GDALProgressFunc pfnProgress = NULL;
@@ -733,68 +755,74 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
 
         dfEndPosition = IT->first;
 
-        dfDistance2 = pPathGeom->Project(IT->second);
+        dfDistance2 = Project(pPathGeom, IT->second);
 
-        pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
-        if (NULL != pPart)
+        if(dfDistance2 - dfDistance1 > DELTA)
         {
-            CURVE_DATA data = { pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition) };
-            astSubLines.push_back(data);
-//            AddFeature(poOutLayer, pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition), bQuiet);
-            dfDistance1 = dfDistance2;
-            dfPosition = IT->first;
+            pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
+            if (NULL != pPart)
+            {
+                CURVE_DATA data = { pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition) };
+                astSubLines.push_back(data);
+    //            AddFeature(poOutLayer, pPart, dfPosition, IT->first, pPart->get_Length() / (IT->first - dfPosition), bQuiet);
+                dfDistance1 = dfDistance2;
+                dfPosition = IT->first;
+            }
         }
 
         ++IT;
     }
 
     //get last part
-    pPart = pPathGeom->getSubLine(dfDistance1, pPathGeom->get_Length(), FALSE);
-    if (NULL != pPart)
+    if(pPathGeom->get_Length() - dfDistance1 > DELTA)
     {
-        OGRSpatialReference* pSpaRef = pPathGeom->getSpatialReference();
-        double dfLen = pPart->get_Length();
-        if (pSpaRef->IsGeographic())
-        {
-            //convert to UTM/WGS84
-            OGRPoint pt;
-            pPart->Value(dfLen / 2, &pt);
-            int nZoneEnv = 30 + (pt.getX() + 3.0) / 6.0 + 0.5;
-            int nEPSG;
-            if (pt.getY() > 0)
+        pPart = pPathGeom->getSubLine(dfDistance1, pPathGeom->get_Length(), FALSE);
+        if (NULL != pPart)
+        {
+            OGRSpatialReference* pSpaRef = pPathGeom->getSpatialReference();
+            double dfLen = pPart->get_Length();
+            if (pSpaRef->IsGeographic())
             {
-                nEPSG = 32600 + nZoneEnv;
+                //convert to UTM/WGS84
+                OGRPoint pt;
+                pPart->Value(dfLen / 2, &pt);
+                int nZoneEnv = 30 + (pt.getX() + 3.0) / 6.0 + 0.5;
+                int nEPSG;
+                if (pt.getY() > 0)
+                {
+                    nEPSG = 32600 + nZoneEnv;
+                }
+                else
+                {
+                    nEPSG = 32700 + nZoneEnv;
+                }
+                OGRSpatialReference SpatRef;
+                SpatRef.importFromEPSG(nEPSG);
+                OGRGeometry *pTransformPart = pPart->clone();
+                if (pTransformPart->transformTo(&SpatRef) == OGRERR_NONE)
+                {
+                    OGRLineString* pTransformPartLS = (OGRLineString*)pTransformPart;
+                    dfLen = pTransformPartLS->get_Length();
+                }
+                CURVE_DATA data = { pPart, dfPosition, dfPosition + dfLen, pPart->get_Length() / dfLen };
+                astSubLines.push_back(data);
+                //AddFeature(poOutLayer, pPart, dfPosition, dfPosition + dfLen, pPart->get_Length() / dfLen, bQuiet);
+
+                pPtEnd = new OGRPoint();
+                pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
+                dfPtEndPosition = dfPosition + dfLen;
+
+                delete pTransformPart;
             }
             else
             {
-                nEPSG = 32700 + nZoneEnv;
-            }
-            OGRSpatialReference SpatRef;
-            SpatRef.importFromEPSG(nEPSG);
-            OGRGeometry *pTransformPart = pPart->clone();
-            if (pTransformPart->transformTo(&SpatRef) == OGRERR_NONE)
-            {
-                OGRLineString* pTransformPartLS = (OGRLineString*)pTransformPart;
-                dfLen = pTransformPartLS->get_Length();
+                CURVE_DATA data = { pPart, dfPosition, dfPosition + dfLen, 1.0 };
+                astSubLines.push_back(data);
+                //AddFeature(poOutLayer, pPart, dfPosition - dfLen, dfPosition, 1.0, bQuiet);
+                pPtEnd = new OGRPoint();
+                pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
+                dfPtEndPosition = dfPosition + dfLen;
             }
-            CURVE_DATA data = { pPart, dfPosition, dfPosition + dfLen, pPart->get_Length() / dfLen };
-            astSubLines.push_back(data);
-            //AddFeature(poOutLayer, pPart, dfPosition, dfPosition + dfLen, pPart->get_Length() / dfLen, bQuiet);
-
-            pPtEnd = new OGRPoint();
-            pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
-            dfPtEndPosition = dfPosition + dfLen;
-
-            delete pTransformPart;
-        }
-        else
-        {
-            CURVE_DATA data = { pPart, dfPosition, dfPosition + dfLen, 1.0 };
-            astSubLines.push_back(data);
-            //AddFeature(poOutLayer, pPart, dfPosition - dfLen, dfPosition, 1.0, bQuiet);
-            pPtEnd = new OGRPoint();
-            pPart->getPoint(pPart->getNumPoints() - 1, pPtEnd);
-            dfPtEndPosition = dfPosition + dfLen;
         }
     }
 
@@ -866,9 +894,9 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
             nCount++;
         }
 
-        dfDistance2 = pPathGeom->Project(IT->second);
+        dfDistance2 = Project(pPathGeom, IT->second);
 
-        if (dfDistance1 != dfDistance2)
+        if (dfDistance2 - dfDistance1 > DELTA)
         {
             pPart = pPathGeom->getSubLine(dfDistance1, dfDistance2, FALSE);
             if (NULL != pPart)
@@ -886,7 +914,7 @@ OGRErr CreatePartsFromLineString(OGRLineString* pPathGeom, OGRLayer* const poPkL
     {
         fprintf(stdout, "\nSuccess!\n\n");
     }
-    
+
     if (NULL != pProgressArg)
     {
         GDALDestroyScaledProgress(pProgressArg);
@@ -923,7 +951,7 @@ OGRErr CreateParts(OGRLayer* const poLnLayer, OGRLayer* const poPkLayer, int nMV
         {
             if (!bQuiet)
             {
-                fprintf(stdout, "\nThe geometry %ld is wkbMultiLineString type\n", pPathFeature->GetFID());
+                fprintf(stdout, "\nThe geometry " CPL_FRMT_GIB " is wkbMultiLineString type\n", pPathFeature->GetFID());
             }
 
             OGRGeometryCollection* pGeomColl = (OGRGeometryCollection*)pGeom;
@@ -951,6 +979,8 @@ OGRErr CreateParts(OGRLayer* const poLnLayer, OGRLayer* const poPkLayer, int nMV
         OGRFeature::DestroyFeature(pPathFeature);
     }
 
+    //should never reach
+
     return eRetCode;
 }
 
@@ -1049,16 +1079,16 @@ OGRErr GetPosition(OGRLayer* const poPkLayer,
     }
     //now we have closest part
     //get real distance
-    double dfRealDist = pCloserPart->Project(&pt);
+    double dfRealDist = Project(pCloserPart, &pt);
     //compute reference distance
     double dfRefDist = dfBeg + dfRealDist / dfScale;
     if (bQuiet == TRUE)
     {
-        fprintf(stdout, "%f\n", dfRefDist);
+        fprintf(stdout, "%s", CPLSPrintf("%f\n", dfRefDist));
     }
     else
     {
-        fprintf(stdout, "The position for coordinates lat:%f, long:%f is %f\n", dfY, dfX, dfRefDist);
+        fprintf(stdout, "%s", CPLSPrintf("The position for coordinates lat:%f, long:%f is %f\n", dfY, dfX, dfRefDist));
     }
 
     return OGRERR_NONE;
@@ -1093,11 +1123,11 @@ OGRErr GetCoordinates(OGRLayer* const poPkLayer,
 
         if (bQuiet == TRUE)
         {
-            fprintf(stdout, "%f,%f,%f\n", pt.getX(), pt.getY(), pt.getZ());
+            fprintf(stdout, "%s", CPLSPrintf("%f,%f,%f\n", pt.getX(), pt.getY(), pt.getZ()));
         }
         else
         {
-            fprintf(stdout, "The position for distance %f is lat:%f, long:%f, height:%f\n", dfPos, pt.getY(), pt.getX(), pt.getZ());
+            fprintf(stdout, "%s", CPLSPrintf("The position for distance %f is lat:%f, long:%f, height:%f\n", dfPos, pt.getY(), pt.getX(), pt.getZ()));
         }
         OGRFeature::DestroyFeature(pFeature);
     }
@@ -1340,13 +1370,13 @@ int main( int nArgc, char ** papszArgv )
     /* -------------------------------------------------------------------- */
     /*      Open data source.                                               */
     /* -------------------------------------------------------------------- */
-        OGRDataSource       *poLnDS;
-        OGRDataSource       *poODS = NULL;
-        OGRSFDriver         *poDriver = NULL;
-        OGRDataSource *poPkDS = NULL;
+        GDALDataset       *poLnDS;
+        GDALDataset       *poODS = NULL;
+        GDALDriver         *poDriver = NULL;
+        GDALDataset *poPkDS = NULL;
         OGRLayer *poPkLayer = NULL;
 
-        poLnDS = OGRSFDriverRegistrar::Open( pszLineDataSource, FALSE );
+        poLnDS = (GDALDataset*) OGROpen( pszLineDataSource, FALSE, NULL );
 
     /* -------------------------------------------------------------------- */
     /*      Report failure                                                  */
@@ -1361,13 +1391,13 @@ int main( int nArgc, char ** papszArgv )
 
             for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
             }
 
             exit( 1 );
         }
         
-        poPkDS = OGRSFDriverRegistrar::Open( pszPicketsDataSource, FALSE );
+        poPkDS = (GDALDataset*) OGROpen( pszPicketsDataSource, FALSE, NULL );
     /* -------------------------------------------------------------------- */
     /*      Report failure                                                  */
     /* -------------------------------------------------------------------- */
@@ -1381,7 +1411,7 @@ int main( int nArgc, char ** papszArgv )
 
             for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
             }
 
             exit( 1 );
@@ -1406,12 +1436,12 @@ int main( int nArgc, char ** papszArgv )
         
             for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr,  "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription() );
             }
             exit( 1 );
         }
 
-        if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+        if( !CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
         {
             fprintf( stderr,  "%s driver does not support data source creation.\n",
                     pszFormat );
@@ -1421,7 +1451,7 @@ int main( int nArgc, char ** papszArgv )
     /* -------------------------------------------------------------------- */
     /*      Create the output data source.                                  */
     /* -------------------------------------------------------------------- */
-        poODS = poDriver->CreateDataSource( pszOutputDataSource, papszDSCO );
+        poODS = poDriver->Create( pszOutputDataSource, 0, 0, 0, GDT_Unknown, papszDSCO );
         if( poODS == NULL )
         {
             fprintf( stderr,  "%s driver failed to create %s\n", 
@@ -1490,9 +1520,9 @@ int main( int nArgc, char ** papszArgv )
         }
         
         //clean up        
-        OGRDataSource::DestroyDataSource(poLnDS);
-        OGRDataSource::DestroyDataSource(poPkDS);
-        OGRDataSource::DestroyDataSource(poODS);
+        GDALClose( (GDALDatasetH)poLnDS);
+        GDALClose( (GDALDatasetH)poPkDS);
+        GDALClose( (GDALDatasetH)poODS);
             
         if (NULL != pszOutputLayerName)
             CPLFree(pszOutputLayerName);
@@ -1504,7 +1534,7 @@ int main( int nArgc, char ** papszArgv )
     else if(stOper == op_get_pos)
     {
 #ifdef HAVE_GEOS_PROJECT    
-        OGRDataSource *poPartsDS = NULL;
+        GDALDataset *poPartsDS = NULL;
         OGRLayer *poPartsLayer = NULL;
 
         if (pszPartsDataSource == NULL)
@@ -1512,7 +1542,7 @@ int main( int nArgc, char ** papszArgv )
         else if(dfX == -100000000 || dfY == -100000000)
             Usage("no coordinates provided");
             
-        poPartsDS = OGRSFDriverRegistrar::Open( pszPartsDataSource, FALSE );
+        poPartsDS = (GDALDataset*) OGROpen( pszPartsDataSource, FALSE, NULL );
     /* -------------------------------------------------------------------- */
     /*      Report failure                                                  */
     /* -------------------------------------------------------------------- */
@@ -1526,7 +1556,7 @@ int main( int nArgc, char ** papszArgv )
 
             for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
             }
 
             exit( 1 );
@@ -1551,7 +1581,7 @@ int main( int nArgc, char ** papszArgv )
         eErr = GetPosition(poPartsLayer, dfX, dfY, bDisplayProgress, bQuiet);
 
         //clean up
-        OGRDataSource::DestroyDataSource(poPartsDS);
+        GDALClose( (GDALDatasetH)poPartsDS);
 #else //HAVE_GEOS_PROJECT
         fprintf( stderr, "GEOS support not enabled or incompatible version.\n" );
         exit( 1 );       
@@ -1559,7 +1589,7 @@ int main( int nArgc, char ** papszArgv )
     }
     else if(stOper == op_get_coord)
     {
-        OGRDataSource *poPartsDS = NULL;
+        GDALDataset *poPartsDS = NULL;
         OGRLayer *poPartsLayer = NULL;
 
         if (pszPartsDataSource == NULL)
@@ -1567,7 +1597,7 @@ int main( int nArgc, char ** papszArgv )
         else if(dfPos == -100000000)
             Usage("no position provided");
             
-        poPartsDS = OGRSFDriverRegistrar::Open(pszPartsDataSource, FALSE);
+        poPartsDS = (GDALDataset*) OGROpen(pszPartsDataSource, FALSE, NULL);
     /* -------------------------------------------------------------------- */
     /*      Report failure                                                  */
     /* -------------------------------------------------------------------- */
@@ -1581,7 +1611,7 @@ int main( int nArgc, char ** papszArgv )
 
             for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
             }
 
             exit( 1 );
@@ -1605,7 +1635,7 @@ int main( int nArgc, char ** papszArgv )
         eErr = GetCoordinates(poPartsLayer, dfPos, bDisplayProgress, bQuiet);
 
         //clean up
-        OGRDataSource::DestroyDataSource(poPartsDS);
+        GDALClose( (GDALDatasetH)poPartsDS);
     }
     else if (stOper == op_get_subline)
     {
@@ -1621,11 +1651,11 @@ int main( int nArgc, char ** papszArgv )
         /* -------------------------------------------------------------------- */
         /*      Open data source.                                               */
         /* -------------------------------------------------------------------- */
-        OGRDataSource       *poPartsDS;
-        OGRDataSource       *poODS = NULL;
-        OGRSFDriver         *poDriver = NULL;
+        GDALDataset       *poPartsDS;
+        GDALDataset       *poODS = NULL;
+        GDALDriver         *poDriver = NULL;
 
-        poPartsDS = OGRSFDriverRegistrar::Open(pszPartsDataSource, FALSE);
+        poPartsDS = (GDALDataset*) OGROpen(pszPartsDataSource, FALSE, NULL);
 
         /* -------------------------------------------------------------------- */
         /*      Report failure                                                  */
@@ -1640,7 +1670,7 @@ int main( int nArgc, char ** papszArgv )
 
             for (int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++)
             {
-                fprintf(stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetName());
+                fprintf(stderr, "  -> %s\n", poR->GetDriver(iDriver)->GetDescription());
             }
 
             exit(1);
@@ -1664,12 +1694,12 @@ int main( int nArgc, char ** papszArgv )
 
             for (iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++)
             {
-                fprintf(stderr, "  -> `%s'\n", poR->GetDriver(iDriver)->GetName());
+                fprintf(stderr, "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription());
             }
             exit(1);
         }
 
-        if (!poDriver->TestCapability(ODrCCreateDataSource))
+        if( !CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
         {
             fprintf(stderr, "%s driver does not support data source creation.\n",
                 pszFormat);
@@ -1679,7 +1709,7 @@ int main( int nArgc, char ** papszArgv )
         /* -------------------------------------------------------------------- */
         /*      Create the output data source.                                  */
         /* -------------------------------------------------------------------- */
-        poODS = poDriver->CreateDataSource(pszOutputDataSource, papszDSCO);
+        poODS = poDriver->Create(pszOutputDataSource, 0, 0, 0, GDT_Unknown, papszDSCO);
         if (poODS == NULL)
         {
             fprintf(stderr, "%s driver failed to create %s\n",
@@ -1715,8 +1745,8 @@ int main( int nArgc, char ** papszArgv )
         eErr = CreateSubline(poPartsLayer, dfPosBeg, dfPosEnd, poOutLayer, bDisplayProgress, bQuiet);
 
         //clean up        
-        OGRDataSource::DestroyDataSource(poPartsDS);
-        OGRDataSource::DestroyDataSource(poODS);
+        GDALClose( (GDALDatasetH) poPartsDS);
+        GDALClose( (GDALDatasetH) poODS);
 
         if (NULL != pszOutputLayerName)
             CPLFree(pszOutputLayerName);
diff --git a/apps/ogrtindex.cpp b/apps/ogrtindex.cpp
index 4a9e5b3..334a3ad 100644
--- a/apps/ogrtindex.cpp
+++ b/apps/ogrtindex.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtindex.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrtindex.cpp 28387 2015-01-30 17:10:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Program to generate a UMN MapServer compatible tile index for a
@@ -36,7 +36,7 @@
 
 #include <cassert>
 
-CPL_CVSID("$Id: ogrtindex.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrtindex.cpp 28387 2015-01-30 17:10:41Z rouault $");
 
 static void Usage();
 
@@ -116,10 +116,10 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 /*      Try to open as an existing dataset for update access.           */
 /* -------------------------------------------------------------------- */
-    OGRDataSource *poDstDS;
+    GDALDataset *poDstDS;
     OGRLayer *poDstLayer = NULL;
 
-    poDstDS = OGRSFDriverRegistrar::Open( pszOutputName, TRUE );
+    poDstDS = (GDALDataset*) OGROpen( pszOutputName, TRUE, NULL );
 
 /* -------------------------------------------------------------------- */
 /*      If that failed, find the driver so we can create the tile index.*/
@@ -127,14 +127,14 @@ int main( int nArgc, char ** papszArgv )
     if( poDstDS == NULL )
     {
         OGRSFDriverRegistrar     *poR = OGRSFDriverRegistrar::GetRegistrar();
-        OGRSFDriver              *poDriver = NULL;
+        GDALDriver              *poDriver = NULL;
         int                      iDriver;
 
         for( iDriver = 0;
              iDriver < poR->GetDriverCount() && poDriver == NULL;
              iDriver++ )
         {
-            if( EQUAL(poR->GetDriver(iDriver)->GetName(),pszFormat) )
+            if( EQUAL(poR->GetDriver(iDriver)->GetDescription(),pszFormat) )
             {
                 poDriver = poR->GetDriver(iDriver);
             }
@@ -147,12 +147,12 @@ int main( int nArgc, char ** papszArgv )
         
             for( iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
             {
-                fprintf( stderr, "  -> `%s'\n", poR->GetDriver(iDriver)->GetName() );
+                fprintf( stderr, "  -> `%s'\n", poR->GetDriver(iDriver)->GetDescription() );
             }
             exit( 1 );
         }
 
-        if( !poDriver->TestCapability( ODrCCreateDataSource ) )
+        if( !CSLTestBoolean( CSLFetchNameValueDef(poDriver->GetMetadata(), GDAL_DCAP_CREATE, "FALSE") ) )
         {
             fprintf( stderr, "%s driver does not support data source creation.\n",
                     pszFormat );
@@ -163,7 +163,7 @@ int main( int nArgc, char ** papszArgv )
 /*      Now create it.                                                  */
 /* -------------------------------------------------------------------- */
         
-        poDstDS = poDriver->CreateDataSource( pszOutputName, NULL );
+        poDstDS = poDriver->Create( pszOutputName, 0, 0, 0, GDT_Unknown, NULL );
         if( poDstDS == NULL )
         {
             fprintf( stderr, "%s driver failed to create %s\n", 
@@ -187,9 +187,7 @@ int main( int nArgc, char ** papszArgv )
             /* Fetches the SRS of the first layer and use it when creating the tileindex layer */
             if (nFirstSourceDataset < nArgc)
             {
-                OGRDataSource* poDS = OGRSFDriverRegistrar::Open( papszArgv[nFirstSourceDataset], 
-                                           FALSE );
-                                           
+                GDALDataset* poDS = (GDALDataset*) OGROpen(papszArgv[nFirstSourceDataset], FALSE, NULL);
                 if (poDS)
                 {
                     int iLayer;
@@ -219,7 +217,7 @@ int main( int nArgc, char ** papszArgv )
                     }
                 }
                 
-                OGRDataSource::DestroyDataSource( poDS );
+                GDALClose( (GDALDatasetH)poDS );
             }
 
             poDstLayer = poDstDS->CreateLayer( "tileindex", poSrcSpatialRef );
@@ -257,7 +255,7 @@ int main( int nArgc, char ** papszArgv )
     char** existingLayersTab = NULL;
     OGRSpatialReference* alreadyExistingSpatialRef = NULL;
     int alreadyExistingSpatialRefValid = FALSE;
-    nExistingLayers = poDstLayer->GetFeatureCount();
+    nExistingLayers = (int)poDstLayer->GetFeatureCount();
     if (nExistingLayers)
     {
         int i;
@@ -268,7 +266,7 @@ int main( int nArgc, char ** papszArgv )
             existingLayersTab[i] = CPLStrdup(feature->GetFieldAsString( iTileIndexField));
             if (i == 0)
             {
-                OGRDataSource       *poDS;
+                GDALDataset       *poDS;
                 char* filename = CPLStrdup(existingLayersTab[i]);
                 int j;
                 for(j=strlen(filename)-1;j>=0;j--)
@@ -280,8 +278,7 @@ int main( int nArgc, char ** papszArgv )
                 {
                     int iLayer = atoi(filename + j + 1);
                     filename[j] = 0;
-                    poDS = OGRSFDriverRegistrar::Open(filename, 
-                                                    FALSE );
+                    poDS = (GDALDataset*) OGROpen(filename, FALSE, NULL);
                     if (poDS)
                     {
                         OGRLayer *poLayer = poDS->GetLayer(iLayer);
@@ -294,7 +291,7 @@ int main( int nArgc, char ** papszArgv )
                             if (poFeatureDefn == NULL)
                                 poFeatureDefn = poLayer->GetLayerDefn()->Clone();
                         }
-                        OGRDataSource::DestroyDataSource( poDS );
+                        GDALClose( (GDALDatasetH)poDS );
                     }
                 }
             }
@@ -319,7 +316,7 @@ int main( int nArgc, char ** papszArgv )
 	for(; nFirstSourceDataset < nArgc; nFirstSourceDataset++ )
     {
         int i;
-        OGRDataSource       *poDS;
+        GDALDataset       *poDS;
 
         if( papszArgv[nFirstSourceDataset][0] == '-' )
         {
@@ -340,8 +337,7 @@ int main( int nArgc, char ** papszArgv )
             fileNameToWrite = CPLStrdup(papszArgv[nFirstSourceDataset]);
         }
 
-        poDS = OGRSFDriverRegistrar::Open( papszArgv[nFirstSourceDataset], 
-                                           FALSE );
+        poDS = (GDALDataset*) OGROpen( papszArgv[nFirstSourceDataset], FALSE, NULL );
 
         if( poDS == NULL )
         {
@@ -514,7 +510,7 @@ int main( int nArgc, char ** papszArgv )
             if( poDstLayer->CreateFeature( &oTileFeat ) != OGRERR_NONE )
             {
                 fprintf( stderr, "Failed to create feature on tile index ... terminating." );
-                OGRDataSource::DestroyDataSource( poDstDS );
+                GDALClose( (GDALDatasetH) poDstDS );
                 exit( 1 );
             }
         }
@@ -523,13 +519,13 @@ int main( int nArgc, char ** papszArgv )
 /*      Cleanup this data source.                                       */
 /* -------------------------------------------------------------------- */
         CPLFree(fileNameToWrite);
-        OGRDataSource::DestroyDataSource( poDS );
+        GDALClose( (GDALDatasetH)poDS );
     }
 
 /* -------------------------------------------------------------------- */
 /*      Close tile index and clear buffers.                             */
 /* -------------------------------------------------------------------- */
-    OGRDataSource::DestroyDataSource( poDstDS );
+    GDALClose( (GDALDatasetH) poDstDS );
 	OGRFeatureDefn::DestroyFeatureDefn( poFeatureDefn );
   
     if (alreadyExistingSpatialRef != NULL)
diff --git a/apps/test_ogrsf.cpp b/apps/test_ogrsf.cpp
index f0dd14c..8608775 100644
--- a/apps/test_ogrsf.cpp
+++ b/apps/test_ogrsf.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: test_ogrsf.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: test_ogrsf.cpp 28849 2015-04-05 14:05:18Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Formal test harnass for OGRLayer implementations.
@@ -35,7 +35,7 @@
 #include "ogr_p.h"
 #include "commonutils.h"
 
-CPL_CVSID("$Id: test_ogrsf.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: test_ogrsf.cpp 28849 2015-04-05 14:05:18Z goatbar $");
 
 int     bReadOnly = FALSE;
 int     bVerbose = TRUE;
@@ -44,19 +44,45 @@ char** papszLayers = NULL;
 const char  *pszSQLStatement = NULL;
 const char  *pszDialect = NULL;
 int nLoops = 1;
+int     bFullSpatialFilter = FALSE;
+char  **papszOpenOptions = NULL;
+const char* pszDriver = NULL;
+int bAllDrivers = FALSE;
+const char* pszLogFilename = NULL;
+char** papszDSCO = NULL;
+char** papszLCO = NULL;
 
 typedef struct
 {
-    void* hThread;
+    CPLJoinableThread* hThread;
     int bRet;
 } ThreadContext;
 
 static void Usage();
 static void ThreadFunction( void* user_data );
 static void ThreadFunctionInternal( ThreadContext* psContext );
-static int TestOGRLayer( OGRDataSource * poDS, OGRLayer * poLayer, int bIsSQLLayer );
+static int TestDataset( GDALDriver** ppoDriver );
+static int TestCreate( GDALDriver* poDriver, int bFromAllDrivers );
+static int TestOGRLayer( GDALDataset * poDS, OGRLayer * poLayer, int bIsSQLLayer );
 static int TestInterleavedReading( const char* pszDataSource, char** papszLayers );
-static int TestDSErrorConditions( OGRDataSource * poDS );
+static int TestDSErrorConditions( GDALDataset * poDS );
+static int TestVirtualIO( GDALDataset* poDS );
+static const char* Log(const char* pszMsg, int nLineNumber);
+
+static const char* Log(const char* pszMsg, int nLineNumber)
+{
+    if( pszLogFilename == NULL )
+        return pszMsg;
+    FILE* f = fopen(pszLogFilename, "at");
+    if( f == NULL )
+        return pszMsg;
+    fprintf(f, "%d: %s\n", nLineNumber, pszMsg);
+    fclose(f);
+    return pszMsg;
+}
+
+#define LOG_STR(str) (Log((str), __LINE__))
+#define LOG_ACTION(action) (Log(#action, __LINE__), (action))
 
 /************************************************************************/
 /*                                main()                                */
@@ -112,6 +138,33 @@ int main( int nArgc, char ** papszArgv )
         {
             nLoops = atoi(papszArgv[++iArg]);
         }
+        else if( EQUAL(papszArgv[iArg],"-fsf") )
+            bFullSpatialFilter = TRUE;
+        else if( EQUAL(papszArgv[iArg], "-oo") && iArg + 1 < nArgc)
+        {
+            papszOpenOptions = CSLAddString( papszOpenOptions,
+                                                papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg], "-dsco") && iArg + 1 < nArgc)
+        {
+            papszDSCO = CSLAddString( papszDSCO,
+                                                papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg], "-lco") && iArg + 1 < nArgc)
+        {
+            papszLCO = CSLAddString( papszLCO,
+                                                papszArgv[++iArg] );
+        }
+        else if( EQUAL(papszArgv[iArg], "-log") && iArg + 1 < nArgc)
+        {
+            pszLogFilename = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg], "-driver") && iArg + 1 < nArgc)
+        {
+            pszDriver = papszArgv[++iArg];
+        }
+        else if( EQUAL(papszArgv[iArg],"-all_drivers") )
+            bAllDrivers = TRUE;
         else if( papszArgv[iArg][0] == '-' )
         {
             Usage();
@@ -122,11 +175,11 @@ int main( int nArgc, char ** papszArgv )
             papszLayers = CSLAddString(papszLayers, papszArgv[iArg]);
     }
 
-    if( pszDataSource == NULL )
+    if( pszDataSource == NULL && pszDriver == NULL && !bAllDrivers )
         Usage();
-    if( nThreads > 1 && !bReadOnly )
+    if( nThreads > 1 && !bReadOnly && pszDataSource != NULL )
     {
-        fprintf(stderr, "-theads must be used with -ro option.\n");
+        fprintf(stderr, "-threads must be used with -ro or -driver/-all_drivers option.\n");
         exit(1);
     }
 
@@ -157,6 +210,9 @@ int main( int nArgc, char ** papszArgv )
 
     CSLDestroy(papszLayers);
     CSLDestroy(papszArgv);
+    CSLDestroy(papszOpenOptions);
+    CSLDestroy(papszDSCO);
+    CSLDestroy(papszLCO);
     
 #ifdef DBMALLOC
     malloc_dump(1);
@@ -189,22 +245,66 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
 {
     int bRet = TRUE;
 
+    GDALDriver         *poDriver = NULL;
+
+    if( pszDataSource != NULL )
+        bRet = TestDataset( &poDriver );
+    else if( pszDriver != NULL )
+    {
+        poDriver = (GDALDriver*) GDALGetDriverByName(pszDriver);
+        if( poDriver )
+            bRet &= TestCreate( poDriver, FALSE );
+        else
+        {
+            printf("ERROR: Cannot find driver %s\n", pszDriver);
+            bRet = FALSE;
+        }
+    }
+    else
+    {
+        int nCount = GDALGetDriverCount();
+        for(int i=0;i<nCount;i++)
+        {
+            poDriver = (GDALDriver*) GDALGetDriver(i);
+            if( poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != NULL )
+                bRet &= TestCreate( poDriver, TRUE );
+        }
+    }
+
+    psContext->bRet = bRet;
+}
+
+/************************************************************************/
+/*                            TestDataset()                             */
+/************************************************************************/
+
+static int TestDataset( GDALDriver** ppoDriver )
+{
+    int bRet = TRUE;
+    int bRetLocal;
+
 /* -------------------------------------------------------------------- */
 /*      Open data source.                                               */
 /* -------------------------------------------------------------------- */
-    OGRDataSource       *poDS;
-    OGRSFDriver         *poDriver;
+    GDALDataset        *poDS;
+    GDALDriver         *poDriver = NULL;
 
-    poDS = OGRSFDriverRegistrar::Open( pszDataSource, !bReadOnly, &poDriver );
+    poDS = (GDALDataset*) GDALOpenEx( pszDataSource,
+            (!bReadOnly ? GDAL_OF_UPDATE : GDAL_OF_READONLY) | GDAL_OF_VECTOR,
+            NULL, papszOpenOptions, NULL );
     if( poDS == NULL && !bReadOnly )
     {
-        poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE, &poDriver );
+        poDS = (GDALDataset*) GDALOpenEx( pszDataSource, GDAL_OF_VECTOR,
+                                          NULL, papszOpenOptions, NULL );
         if( poDS != NULL && bVerbose )
         {
             printf( "Had to open data source read-only.\n" );
             bReadOnly = TRUE;
         }
     }
+    if( poDS != NULL )
+        poDriver = poDS->GetDriver();
+    *ppoDriver = poDriver;
 
 /* -------------------------------------------------------------------- */
 /*      Report failure                                                  */
@@ -219,11 +319,10 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
 
         for( int iDriver = 0; iDriver < poR->GetDriverCount(); iDriver++ )
         {
-            printf( "  -> %s\n", poR->GetDriver(iDriver)->GetName() );
+            printf( "  -> %s\n", poR->GetDriver(iDriver)->GetDescription() );
         }
 
-        psContext->bRet = FALSE;
-        return;
+        return FALSE;
     }
 
 /* -------------------------------------------------------------------- */
@@ -231,13 +330,13 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
 /* -------------------------------------------------------------------- */
     if( bVerbose )
         printf( "INFO: Open of `%s' using driver `%s' successful.\n",
-                pszDataSource, poDriver->GetName() );
+                pszDataSource, poDriver->GetDescription() );
 
-    if( bVerbose && !EQUAL(pszDataSource,poDS->GetName()) )
+    if( bVerbose && !EQUAL(pszDataSource,poDS->GetDescription()) )
     {
         printf( "INFO: Internal data source name `%s'\n"
                 "      different from user name `%s'.\n",
-                poDS->GetName(), pszDataSource );
+                poDS->GetDescription(), pszDataSource );
     }
     
 /* -------------------------------------------------------------------- */
@@ -248,9 +347,8 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
         OGRLayer  *poResultSet = poDS->ExecuteSQL(pszSQLStatement, NULL, pszDialect);
         if (poResultSet == NULL)
         {
-            OGRDataSource::DestroyDataSource(poDS);
-            psContext->bRet = FALSE;
-            return;
+            GDALClose( (GDALDatasetH)poDS );
+            return FALSE;
         }
 
         if( bVerbose )
@@ -262,7 +360,11 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
         
         poDS->ReleaseResultSet(poResultSet);
 
+        bRetLocal = TestDSErrorConditions(poDS);
         bRet &= TestDSErrorConditions(poDS);
+
+        bRetLocal = TestVirtualIO(poDS);
+        bRet &= bRetLocal;
     }
 /* -------------------------------------------------------------------- */
 /*      Process each data source layer.                                 */
@@ -277,9 +379,8 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
             {
                 printf( "FAILURE: Couldn't fetch advertised layer %d!\n",
                         iLayer );
-                OGRDataSource::DestroyDataSource(poDS);
-                psContext->bRet = FALSE;
-                return;
+                GDALClose( (GDALDatasetH)poDS );
+                return FALSE;
             }
 
             if( bVerbose )
@@ -290,13 +391,18 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
             bRet &= TestOGRLayer( poDS, poLayer, FALSE );
         }
 
+        bRetLocal = TestDSErrorConditions(poDS);
         bRet &= TestDSErrorConditions(poDS);
 
+        bRetLocal = TestVirtualIO(poDS);
+        bRet &= bRetLocal;
+
         if (poDS->GetLayerCount() >= 2)
         {
-            OGRDataSource::DestroyDataSource(poDS);
+            GDALClose( (GDALDatasetH)poDS );
             poDS = NULL;
-            bRet &= TestInterleavedReading( pszDataSource, NULL );
+            bRetLocal = TestInterleavedReading( pszDataSource, NULL );
+            bRet &= bRetLocal;
         }
     }
     else
@@ -313,9 +419,8 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
             {
                 printf( "FAILURE: Couldn't fetch requested layer %s!\n",
                         *papszLayerIter );
-                OGRDataSource::DestroyDataSource(poDS);
-                psContext->bRet = FALSE;
-                return;
+                GDALClose( (GDALDatasetH)poDS );
+                return FALSE;
             }
             
             if( bVerbose )
@@ -328,22 +433,496 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
             papszLayerIter ++;
         }
 
+        bRetLocal = TestDSErrorConditions(poDS);
         bRet &= TestDSErrorConditions(poDS);
 
+        bRetLocal = TestVirtualIO(poDS);
+        bRet &= bRetLocal;
+
         if (CSLCount(papszLayers) >= 2)
         {
-            OGRDataSource::DestroyDataSource(poDS);
+            GDALClose( (GDALDatasetH)poDS );
             poDS = NULL;
-            bRet &= TestInterleavedReading( pszDataSource, papszLayers );
+            bRetLocal = TestInterleavedReading( pszDataSource, papszLayers );
+            bRet &= bRetLocal;
         }
     }
 
 /* -------------------------------------------------------------------- */
 /*      Close down.                                                     */
 /* -------------------------------------------------------------------- */
-    OGRDataSource::DestroyDataSource(poDS);
+    if( poDS != NULL )
+        GDALClose( (GDALDatasetH)poDS );
 
-    psContext->bRet = bRet;
+    return bRet;
+}
+
+/************************************************************************/
+/*                             GetWKT()                                 */
+/************************************************************************/
+
+static const char* GetWKT(OGRwkbGeometryType eGeomType)
+{
+    const char* pszWKT = NULL;
+    if( eGeomType == wkbUnknown || eGeomType == wkbPoint )
+        pszWKT = "POINT (0 0)";
+    else if( eGeomType == wkbLineString )
+        pszWKT = "LINESTRING (0 0,1 1)";
+    else if( eGeomType == wkbPolygon )
+        pszWKT = "POLYGON ((0 0,0 1,1 1,1 0,0 0))";
+    else if( eGeomType == wkbMultiPoint )
+        pszWKT = "MULTIPOINT (0 0)";
+    else if( eGeomType == wkbMultiLineString )
+        pszWKT = "MULTILINESTRING ((0 0,1 1))";
+    else if( eGeomType == wkbMultiPolygon )
+        pszWKT = "MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))";
+    else if( eGeomType == wkbGeometryCollection )
+        pszWKT = "GEOMETRYCOLLECTION (POINT (0 0),LINESTRING (0 0,1 1),POLYGON ((0 0,0 1,1 1,1 0,0 0)))";
+    else if( eGeomType == wkbPoint25D )
+        pszWKT = "POINT (0 0 10)";
+    else if( eGeomType == wkbLineString25D )
+        pszWKT = "LINESTRING (0 0 10,1 1 10)";
+    else if( eGeomType == wkbPolygon25D )
+        pszWKT = "POLYGON ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10))";
+    else if( eGeomType == wkbMultiPoint25D )
+        pszWKT = "MULTIPOINT (0 0 10)";
+    else if( eGeomType == wkbMultiLineString25D )
+        pszWKT = "MULTILINESTRING ((0 0 10,1 1 10))";
+    else if( eGeomType == wkbMultiPolygon25D )
+        pszWKT = "MULTIPOLYGON (((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10)))";
+    else if( eGeomType == wkbGeometryCollection25D )
+        pszWKT = "GEOMETRYCOLLECTION (POINT (0 0 10),LINESTRING (0 0 10,1 1 10),POLYGON ((0 0 10,0 1 10,1 1 10,1 0 10,0 0 10)))";
+    return pszWKT;
+}
+
+/************************************************************************/
+/*                         TestCreateLayer()                            */
+/************************************************************************/
+
+static int TestCreateLayer( GDALDriver* poDriver, OGRwkbGeometryType eGeomType )
+{
+    int bRet = TRUE;
+    const char* pszExt = poDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
+
+    static int nCounter = 0;
+    CPLString osFilename = CPLFormFilename("/vsimem", CPLSPrintf("test%d", ++nCounter), pszExt);
+    GDALDataset* poDS = LOG_ACTION(poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, papszDSCO));
+    if( poDS == NULL )
+    {
+        if( bVerbose )
+            printf("INFO: %s: Creation of %s failed.\n",
+                   poDriver->GetDescription(), osFilename.c_str());
+        return bRet;
+    }
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    int bCreateLayerCap = LOG_ACTION(poDS->TestCapability(ODsCCreateLayer));
+    OGRLayer* poLayer = LOG_ACTION(poDS->CreateLayer(CPLGetFilename(osFilename), NULL, eGeomType, papszLCO));
+    CPLPopErrorHandler();
+    CPLString osLayerNameToTest;
+    OGRwkbGeometryType eExpectedGeomType = wkbUnknown;
+    if( poLayer != NULL )
+    {
+        if( bCreateLayerCap == FALSE )
+        {
+            printf("ERROR: %s: TestCapability(ODsCCreateLayer) returns FALSE whereas layer creation was successful.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+        
+        if( LOG_ACTION(poLayer->GetLayerDefn()) == NULL )
+        {
+            printf("ERROR: %s: GetLayerDefn() returns NUL just after layer creation.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+        
+        // Create fields of various types
+        int bCreateField = LOG_ACTION(poLayer->TestCapability(OLCCreateField));
+        int iFieldStr = -1, iFieldInt = -1, iFieldReal = -1, iFieldDate = -1, iFieldDateTime = -1;
+
+        OGRFieldDefn oFieldStr("str", OFTString);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bStrFieldOK = (LOG_ACTION(poLayer->CreateField(&oFieldStr)) == OGRERR_NONE);
+        CPLPopErrorHandler();
+        if( bStrFieldOK && (iFieldStr = LOG_ACTION(poLayer->GetLayerDefn())->GetFieldIndex("str")) < 0 )
+        {
+            printf("ERROR: %s: CreateField(str) returned OK but field was not created.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        OGRFieldDefn oFieldInt("int", OFTInteger);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bIntFieldOK = (LOG_ACTION(poLayer->CreateField(&oFieldInt)) == OGRERR_NONE);
+        CPLPopErrorHandler();
+        if( bIntFieldOK && (iFieldInt = poLayer->GetLayerDefn()->GetFieldIndex("int")) < 0 )
+        {
+            printf("ERROR: %s: CreateField(int) returned OK but field was not created.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        OGRFieldDefn oFieldReal("real", OFTReal);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bRealFieldOK = (LOG_ACTION(poLayer->CreateField(&oFieldReal)) == OGRERR_NONE);
+        CPLPopErrorHandler();
+        if( bRealFieldOK && (iFieldReal = poLayer->GetLayerDefn()->GetFieldIndex("real")) < 0 )
+        {
+            printf("ERROR: %s: CreateField(real) returned OK but field was not created.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        OGRFieldDefn oFieldDate("date", OFTDate);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bDateFieldOK = (LOG_ACTION(poLayer->CreateField(&oFieldDate)) == OGRERR_NONE);
+        CPLPopErrorHandler();
+        if( bDateFieldOK && (iFieldDate = poLayer->GetLayerDefn()->GetFieldIndex("date")) < 0 )
+        {
+            printf("ERROR: %s: CreateField(date) returned OK but field was not created.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        OGRFieldDefn oFieldDateTime("datetime", OFTDateTime);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bDateTimeFieldOK = (LOG_ACTION(poLayer->CreateField(&oFieldDateTime)) == OGRERR_NONE);
+        CPLPopErrorHandler();
+        if( bDateTimeFieldOK && (iFieldDateTime = poLayer->GetLayerDefn()->GetFieldIndex("datetime")) < 0 )
+        {
+            printf("ERROR: %s: CreateField(datetime) returned OK but field was not created.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        if( bCreateField == FALSE &&
+            (bStrFieldOK || bIntFieldOK || bRealFieldOK || bDateFieldOK || bDateTimeFieldOK) )
+        {
+            printf("ERROR: %s: TestCapability(OLCCreateField) returns FALSE.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        if( LOG_ACTION(poLayer->TestCapability(OLCSequentialWrite)) == FALSE )
+        {
+            printf("ERROR: %s: TestCapability(OLCSequentialWrite) returns FALSE.\n",
+                   poDriver->GetDescription());
+            bRet = FALSE;
+        }
+
+        OGRFeature* poFeature;
+        OGRErr eErr;
+
+        /* Test creating empty feature */
+        poFeature = new OGRFeature( poLayer->GetLayerDefn() );
+        CPLErrorReset();
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
+        CPLPopErrorHandler();
+        if( eErr != OGRERR_NONE && CPLGetLastErrorType() == 0 )
+        {
+            printf("INFO: %s: CreateFeature() at line %d failed but without explicit error.\n",
+                   poDriver->GetDescription(), __LINE__);
+        }
+        if( eErr == OGRERR_NONE && poFeature->GetFID() < 0 && eGeomType == wkbUnknown )
+        {
+            printf("INFO: %s: CreateFeature() at line %d succeeded but failed to assign FID to feature.\n",
+                   poDriver->GetDescription(), __LINE__);
+        }
+        delete poFeature;
+
+        /* Test creating feature with all fields set */
+        poFeature = new OGRFeature( poLayer->GetLayerDefn() );
+        if( bStrFieldOK )
+            poFeature->SetField(iFieldStr, "foo");
+        if( bIntFieldOK )
+            poFeature->SetField(iFieldInt, 123);
+        if( bRealFieldOK )
+            poFeature->SetField(iFieldReal, 1.23);
+        if( bDateFieldOK )
+            poFeature->SetField(iFieldDate, "2014/10/20");
+        if( bDateTimeFieldOK )
+            poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
+        CPLErrorReset();
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
+        CPLPopErrorHandler();
+        if( eErr != OGRERR_NONE && CPLGetLastErrorType() == 0 )
+        {
+            printf("INFO: %s: CreateFeature() at line %d failed but without explicit error.\n",
+                   poDriver->GetDescription(), __LINE__);
+        }
+        delete poFeature;
+
+        /* Test creating feature with all fields set as well as geometry */
+        poFeature = new OGRFeature( poLayer->GetLayerDefn() );
+        if( bStrFieldOK )
+            poFeature->SetField(iFieldStr, "foo");
+        if( bIntFieldOK )
+            poFeature->SetField(iFieldInt, 123);
+        if( bRealFieldOK )
+            poFeature->SetField(iFieldReal, 1.23);
+        if( bDateFieldOK )
+            poFeature->SetField(iFieldDate, "2014/10/20");
+        if( bDateTimeFieldOK )
+            poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
+
+        const char* pszWKT = GetWKT(eGeomType);
+        if( pszWKT != NULL )
+        {
+            OGRGeometry* poGeom = NULL;
+            OGRGeometryFactory::createFromWkt( (char**) &pszWKT, NULL, &poGeom);
+            poFeature->SetGeometryDirectly(poGeom);
+        }
+
+        CPLErrorReset();
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
+        CPLPopErrorHandler();
+        if( eErr != OGRERR_NONE && CPLGetLastErrorType() == 0 )
+        {
+            printf("INFO: %s: CreateFeature() at line %d failed but without explicit error.\n",
+                   poDriver->GetDescription(), __LINE__);
+        }
+        delete poFeature;
+        
+        /* Test feature with incompatible geometry */
+        poFeature = new OGRFeature( poLayer->GetLayerDefn() );
+        if( bStrFieldOK )
+            poFeature->SetField(iFieldStr, "foo");
+        if( bIntFieldOK )
+            poFeature->SetField(iFieldInt, 123);
+        if( bRealFieldOK )
+            poFeature->SetField(iFieldReal, 1.23);
+        if( bDateFieldOK )
+            poFeature->SetField(iFieldDate, "2014/10/20");
+        if( bDateTimeFieldOK )
+            poFeature->SetField(iFieldDateTime, "2014/10/20 12:34:56");
+
+        OGRwkbGeometryType eOtherGeomType;
+        if (eGeomType == wkbUnknown || eGeomType == wkbNone)
+            eOtherGeomType = wkbLineString;
+        else if( wkbFlatten(eGeomType) == eGeomType )
+            eOtherGeomType = (OGRwkbGeometryType) ( ((int)eGeomType % 7) + 1 );
+        else
+            eOtherGeomType = wkbSetZ((OGRwkbGeometryType) ( (((int)wkbFlatten(eGeomType) % 7) + 1 )));
+        pszWKT = GetWKT(eOtherGeomType);
+        if( pszWKT != NULL )
+        {
+            OGRGeometry* poGeom = NULL;
+            OGRGeometryFactory::createFromWkt( (char**) &pszWKT, NULL, &poGeom);
+            poFeature->SetGeometryDirectly(poGeom);
+        }
+
+        CPLErrorReset();
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
+        CPLPopErrorHandler();
+        if( eErr != OGRERR_NONE && CPLGetLastErrorType() == 0 )
+        {
+            printf("INFO: %s: CreateFeature() at line %d failed but without explicit error.\n",
+                   poDriver->GetDescription(), __LINE__);
+        }
+        delete poFeature;
+
+        /* Test reading a feature: write-only layers might not like this */
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        LOG_ACTION(poLayer->ResetReading());
+        delete LOG_ACTION(poLayer->GetNextFeature());
+        CPLPopErrorHandler();
+        
+        osLayerNameToTest = poLayer->GetName();
+        eExpectedGeomType = poLayer->GetGeomType();
+
+        /* Some drivers don't like more than one layer per dataset */
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        int bCreateLayerCap2 = LOG_ACTION(poDS->TestCapability(ODsCCreateLayer));
+        OGRLayer* poLayer2 = LOG_ACTION(poDS->CreateLayer(CPLSPrintf("%s2",CPLGetFilename(osFilename)), NULL, eGeomType));
+        CPLPopErrorHandler();
+        if( poLayer2 == NULL && bCreateLayerCap2 )
+        {
+            printf("INFO: %s: Creation of second layer failed but TestCapability(ODsCCreateLayer) succeeded.\n",
+                   poDriver->GetDescription());
+        }
+        else if( !EQUAL(poDriver->GetDescription(), "CSV") && poLayer2 != NULL )
+        {
+            OGRFieldDefn oFieldStr("str", OFTString);
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            LOG_ACTION(poLayer2->CreateField(&oFieldStr));
+            CPLPopErrorHandler();
+
+            poFeature = new OGRFeature( poLayer2->GetLayerDefn() );
+            const char* pszWKT = GetWKT(eGeomType);
+            if( pszWKT != NULL )
+            {
+                OGRGeometry* poGeom = NULL;
+                OGRGeometryFactory::createFromWkt( (char**) &pszWKT, NULL, &poGeom);
+                poFeature->SetGeometryDirectly(poGeom);
+            }
+            CPLErrorReset();
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            eErr = LOG_ACTION(poLayer2->CreateFeature(poFeature));
+            CPLPopErrorHandler();
+            delete poFeature;
+
+            if( eErr == OGRERR_NONE )
+            {
+                osLayerNameToTest = poLayer2->GetName();
+                eExpectedGeomType = poLayer2->GetGeomType();
+            }
+        }
+
+        /* Test deleting first layer */
+        int bDeleteLayerCap = LOG_ACTION(poDS->TestCapability(ODsCDeleteLayer));
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        eErr = LOG_ACTION(poDS->DeleteLayer(0));
+        CPLPopErrorHandler();
+        if( eErr == CE_None )
+        {
+            if( !bDeleteLayerCap )
+            {
+                printf("ERROR: %s: TestCapability(ODsCDeleteLayer) returns FALSE but layer deletion worked.\n",
+                   poDriver->GetDescription());
+                bRet = FALSE;
+            }
+            
+            if( LOG_ACTION(poDS->GetLayerByName(CPLGetFilename(osFilename))) != NULL )
+            {
+                printf("ERROR: %s: DeleteLayer() declared success, but layer can still be fetched.\n",
+                   poDriver->GetDescription());
+                bRet = FALSE;
+            }
+        }
+        else
+        {
+            if( bDeleteLayerCap )
+            {
+                printf("ERROR: %s: TestCapability(ODsCDeleteLayer) returns TRUE but layer deletion failed.\n",
+                   poDriver->GetDescription());
+                bRet = FALSE;
+            }
+        }
+    }
+    /*else
+    {
+        if( bVerbose )
+            printf("INFO: %s: Creation of layer with geom_type = %s failed.\n",
+                   poDriver->GetDescription(), OGRGeometryTypeToName(eGeomType));
+    }*/
+    LOG_ACTION(GDALClose(poDS));
+
+    if( eExpectedGeomType != wkbUnknown &&
+        /* Those drivers are expected not to store a layer geometry type */
+        !EQUAL(poDriver->GetDescription(), "KML") &&
+        !EQUAL(poDriver->GetDescription(), "LIBKML") &&
+        !EQUAL(poDriver->GetDescription(), "PDF") )
+    {
+        /* Reopen dataset */
+        poDS = LOG_ACTION((GDALDataset*)GDALOpenEx( osFilename,
+                                                    GDAL_OF_VECTOR,
+                                                    NULL, NULL, NULL ));
+        if( poDS != NULL )
+        {
+            poLayer = LOG_ACTION(poDS->GetLayerByName(osLayerNameToTest));
+            if( poLayer != NULL )
+            {
+                if( poLayer->GetGeomType() != eExpectedGeomType )
+                {
+                    printf("ERROR: %s: GetGeomType() returns %d but %d was expected (and %d originaly set).\n",
+                    poDriver->GetDescription(), poLayer->GetGeomType(), eExpectedGeomType, eGeomType);
+                    bRet = FALSE;
+                }
+            }
+            LOG_ACTION(GDALClose(poDS));
+        }
+    }
+    
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    LOG_ACTION(poDriver->Delete(osFilename));
+    CPLPopErrorHandler();
+    VSIUnlink(osFilename);
+
+    if( poLayer != NULL )
+    {
+        /* Test creating empty layer */
+        osFilename = CPLFormFilename("/vsimem", CPLSPrintf("test%d", ++nCounter), pszExt);
+        poDS = LOG_ACTION(poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, NULL));
+        if( poDS != NULL )
+        {
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            poLayer = LOG_ACTION(poDS->CreateLayer(CPLGetFilename(osFilename), NULL, eGeomType));
+            CPLPopErrorHandler();
+            LOG_ACTION(GDALClose(poDS));
+        
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            LOG_ACTION(poDriver->Delete(osFilename));
+            CPLPopErrorHandler();
+            VSIUnlink(osFilename);
+        }
+    }
+
+    return bRet;
+}
+
+/************************************************************************/
+/*                           TestCreate()                               */
+/************************************************************************/
+
+static int TestCreate( GDALDriver* poDriver, int bFromAllDrivers )
+{
+    int bRet = TRUE;
+    int bVirtualIO =  poDriver->GetMetadataItem(GDAL_DCAP_VIRTUALIO) != NULL;
+    if( poDriver->GetMetadataItem(GDAL_DCAP_CREATE) == NULL || !bVirtualIO)
+    {
+        if( bVerbose && !bFromAllDrivers )
+            printf("INFO: %s: TestCreate skipped.\n", poDriver->GetDescription());
+        return TRUE;
+    }
+
+    printf("%s\n", LOG_STR(CPLSPrintf("INFO: TestCreate(%s).", poDriver->GetDescription())));
+
+    const char* pszExt = poDriver->GetMetadataItem(GDAL_DMD_EXTENSION);
+    CPLString osFilename = CPLFormFilename("/foo", "test", pszExt);
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    GDALDataset* poDS = LOG_ACTION(poDriver->Create(osFilename, 0, 0, 0, GDT_Unknown, NULL));
+    CPLPopErrorHandler();
+    if( poDS != NULL )
+    {
+        /* Sometimes actual file creation is differed */
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        OGRLayer* poLayer = LOG_ACTION(poDS->CreateLayer("test", NULL, wkbPoint));
+        CPLPopErrorHandler();
+
+        /* Or sometimes writing is differed at dataset closing */
+        CPLErrorReset();
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        LOG_ACTION(GDALClose(poDS));
+        CPLPopErrorHandler();
+        if( poLayer != NULL && CPLGetLastErrorType() == 0 )
+        {
+            printf("INFO: %s: Creation of %s should have failed.\n",
+                poDriver->GetDescription(), osFilename.c_str());
+        }
+    }
+
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbUnknown));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbNone));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPoint));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbLineString));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPolygon));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPoint));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiLineString));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPolygon));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbGeometryCollection));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPoint25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbLineString25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbPolygon25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPoint25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiLineString25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbMultiPolygon25D));
+    bRet &= LOG_ACTION(TestCreateLayer(poDriver, wkbGeometryCollection25D));
+
+    return bRet;
 }
 
 /************************************************************************/
@@ -353,8 +932,12 @@ static void ThreadFunctionInternal( ThreadContext* psContext )
 static void Usage()
 
 {
-    printf( "Usage: test_ogrsf [-ro] [-q] [-threads N] [-loops M] datasource_name \n"
-            "                  [[layer1_name, layer2_name, ...] | [-sql statement] [-dialect dialect]]\n" );
+    printf( "Usage: test_ogrsf [-ro] [-q] [-threads N] [-loops M] [-fsf]\n"
+            "                  (datasource_name | [-driver driver_name] [[-dsco NAME=VALUE] ...] [[-lco NAME=VALUE] ...] | -all_drivers) \n"
+            "                  [[layer1_name, layer2_name, ...] | [-sql statement] [-dialect dialect]]\n"
+            "                   [[-oo NAME=VALUE] ...]\n");
+    printf( "\n");
+    printf( "-fsf : full spatial filter testing (slow)\n");
     exit( 1 );
 }
 
@@ -366,20 +949,29 @@ static int TestBasic( OGRLayer *poLayer )
 {
     int bRet = TRUE;
 
-    const char* pszLayerName = poLayer->GetName();
-    OGRwkbGeometryType eGeomType = poLayer->GetGeomType();
-    OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
+    const char* pszLayerName = LOG_ACTION(poLayer->GetName());
+    OGRwkbGeometryType eGeomType = LOG_ACTION(poLayer->GetGeomType());
+    OGRFeatureDefn* poFDefn = LOG_ACTION(poLayer->GetLayerDefn());
 
-    if( strcmp(pszLayerName, poFDefn->GetName()) != 0 )
+    if( strcmp(pszLayerName, LOG_ACTION(poFDefn->GetName())) != 0 )
     {
         bRet = FALSE;
-        printf( "ERROR: poLayer->GetName() and poFDefn>GetName() differ.\n"
+        printf( "ERROR: poLayer->GetName() and poFDefn->GetName() differ.\n"
                 "poLayer->GetName() = %s\n"
                 "poFDefn->GetName() = %s\n",
                     pszLayerName, poFDefn->GetName());
     }
 
-    if( eGeomType != poFDefn->GetGeomType() )
+    if( strcmp(pszLayerName, LOG_ACTION(poLayer->GetDescription())) != 0 )
+    {
+        bRet = FALSE;
+        printf( "ERROR: poLayer->GetName() and poLayer->GetDescription() differ.\n"
+                "poLayer->GetName() = %s\n"
+                "poLayer->GetDescription() = %s\n",
+                    pszLayerName, poLayer->GetDescription());
+    }
+    
+    if( eGeomType != LOG_ACTION(poFDefn->GetGeomType()) )
     {
         bRet = FALSE;
         printf( "ERROR: poLayer->GetGeomType() and poFDefn->GetGeomType() differ.\n"
@@ -388,21 +980,21 @@ static int TestBasic( OGRLayer *poLayer )
                     eGeomType, poFDefn->GetGeomType());
     }
 
-    if( poLayer->GetFIDColumn() == NULL )
+    if( LOG_ACTION(poLayer->GetFIDColumn()) == NULL )
     {
         bRet = FALSE;
         printf( "ERROR: poLayer->GetFIDColumn() returned NULL.\n" );
     }
 
-    if( poLayer->GetGeometryColumn() == NULL )
+    if( LOG_ACTION(poLayer->GetGeometryColumn()) == NULL )
     {
         bRet = FALSE;
         printf( "ERROR: poLayer->GetGeometryColumn() returned NULL.\n" );
     }
 
-    if( poFDefn->GetGeomFieldCount() > 0 )
+    if( LOG_ACTION(poFDefn->GetGeomFieldCount()) > 0 )
     {
-        if( eGeomType != poFDefn->GetGeomFieldDefn(0)->GetType() )
+        if( eGeomType != LOG_ACTION(poFDefn->GetGeomFieldDefn(0))->GetType() )
         {
             bRet = FALSE;
             printf( "ERROR: poLayer->GetGeomType() and poFDefn->GetGeomFieldDefn(0)->GetType() differ.\n"
@@ -411,7 +1003,7 @@ static int TestBasic( OGRLayer *poLayer )
                         eGeomType, poFDefn->GetGeomFieldDefn(0)->GetType());
         }
 
-        if( !EQUAL(poLayer->GetGeometryColumn(),
+        if( !EQUAL(LOG_ACTION(poLayer->GetGeometryColumn()),
                    poFDefn->GetGeomFieldDefn(0)->GetNameRef()) )
         {
             if( poFDefn->GetGeomFieldCount() > 1 )
@@ -424,8 +1016,8 @@ static int TestBasic( OGRLayer *poLayer )
                      poFDefn->GetGeomFieldDefn(0)->GetNameRef());
         }
 
-        if( poLayer->GetSpatialRef() !=
-                   poFDefn->GetGeomFieldDefn(0)->GetSpatialRef() )
+        if( LOG_ACTION(poLayer->GetSpatialRef()) !=
+                   LOG_ACTION(poFDefn->GetGeomFieldDefn(0)->GetSpatialRef()) )
         {
             if( poFDefn->GetGeomFieldCount() > 1 )
                 bRet = FALSE;
@@ -448,33 +1040,53 @@ static int TestBasic( OGRLayer *poLayer )
 static int TestLayerErrorConditions( OGRLayer* poLyr )
 {
     int bRet = TRUE;
+    OGRFeature* poFeat = NULL;
 
     CPLPushErrorHandler(CPLQuietErrorHandler);
 
-    if (poLyr->TestCapability("fake_capability"))
+    if (LOG_ACTION(poLyr->TestCapability("fake_capability")))
     {
         printf( "ERROR: poLyr->TestCapability(\"fake_capability\") should have returned FALSE\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poLyr->GetFeature(-10) != NULL)
+    if (LOG_ACTION(poLyr->GetFeature(-10)) != NULL)
     {
         printf( "ERROR: GetFeature(-10) should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poLyr->GetFeature(2000000000) != NULL)
+    if (LOG_ACTION(poLyr->GetFeature(2000000000)) != NULL)
     {
         printf( "ERROR: GetFeature(2000000000) should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
     }
 
-#if 0
-    /* PG driver doesn't issue errors when the feature doesn't exist */
-    /* So, not sure if emitting error is expected or not */
+    // This should detect int overflow
+    if (LOG_ACTION(poLyr->GetFeature((GIntBig)INT_MAX + 1)) != NULL)
+    {
+        printf( "ERROR: GetFeature((GIntBig)INT_MAX + 1) should have returned NULL\n" );
+        bRet = FALSE;
+        goto bye;
+    }
+
+    poLyr->ResetReading();
+    poFeat = poLyr->GetNextFeature();
+    if( poFeat )
+    {
+        poFeat->SetFID(-10);
+        if (poLyr->SetFeature(poFeat) == OGRERR_NONE)
+        {
+            printf( "ERROR: SetFeature(-10) should have returned an error\n" );
+            delete poFeat;
+            bRet = FALSE;
+            goto bye;
+        }
+        delete poFeat;
+    }
 
     if (poLyr->DeleteFeature(-10) == OGRERR_NONE)
     {
@@ -489,17 +1101,16 @@ static int TestLayerErrorConditions( OGRLayer* poLyr )
         bRet = FALSE;
         goto bye;
     }
-#endif
 
-    if (poLyr->SetNextByIndex(-10) != OGRERR_FAILURE)
+    if (LOG_ACTION(poLyr->SetNextByIndex(-10)) != OGRERR_FAILURE)
     {
         printf( "ERROR: SetNextByIndex(-10) should have returned OGRERR_FAILURE\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poLyr->SetNextByIndex(2000000000) == OGRERR_NONE &&
-        poLyr->GetNextFeature() != NULL)
+    if (LOG_ACTION(poLyr->SetNextByIndex(2000000000)) == OGRERR_NONE &&
+        LOG_ACTION(poLyr->GetNextFeature()) != NULL)
     {
         printf( "ERROR: SetNextByIndex(2000000000) and then GetNextFeature() should have returned NULL\n" );
         bRet = FALSE;
@@ -515,7 +1126,7 @@ bye:
 /*                          GetLayerNameForSQL()                        */
 /************************************************************************/
 
-const char* GetLayerNameForSQL( OGRDataSource* poDS, const char* pszLayerName )
+const char* GetLayerNameForSQL( GDALDataset* poDS, const char* pszLayerName )
 {
     int i;
     char ch;
@@ -533,10 +1144,10 @@ const char* GetLayerNameForSQL( OGRDataSource* poDS, const char* pszLayerName )
     if (ch == 0)
         return pszLayerName;
 
-    if (EQUAL(poDS->GetDriver()->GetName(), "MYSQL"))
+    if (EQUAL(poDS->GetDriverName(), "MYSQL"))
         return CPLSPrintf("`%s`", pszLayerName);
 
-    if (EQUAL(poDS->GetDriver()->GetName(), "PostgreSQL") &&
+    if (EQUAL(poDS->GetDriverName(), "PostgreSQL") &&
                 strchr(pszLayerName, '.'))
     {
         const char* pszRet;
@@ -549,7 +1160,7 @@ const char* GetLayerNameForSQL( OGRDataSource* poDS, const char* pszLayerName )
         return pszRet;
     }
 
-    if (EQUAL(poDS->GetDriver()->GetName(), "SQLAnywhere"))
+    if (EQUAL(poDS->GetDriverName(), "SQLAnywhere"))
         return pszLayerName;
 
     return CPLSPrintf("\"%s\"", pszLayerName);
@@ -562,20 +1173,20 @@ const char* GetLayerNameForSQL( OGRDataSource* poDS, const char* pszLayerName )
 /*      features returned during sequential reading.                    */
 /************************************************************************/
 
-static int TestOGRLayerFeatureCount( OGRDataSource* poDS, OGRLayer *poLayer, int bIsSQLLayer )
+static int TestOGRLayerFeatureCount( GDALDataset* poDS, OGRLayer *poLayer, int bIsSQLLayer )
 
 {
     int bRet = TRUE;
-    int         nFC = 0, nClaimedFC = poLayer->GetFeatureCount();
+    GIntBig         nFC = 0, nClaimedFC = LOG_ACTION(poLayer->GetFeatureCount());
     OGRFeature  *poFeature;
     int         bWarnAboutSRS = FALSE;
-    OGRFeatureDefn* poLayerDefn = poLayer->GetLayerDefn();
-    int nGeomFieldCount = poLayerDefn->GetGeomFieldCount();
+    OGRFeatureDefn* poLayerDefn = LOG_ACTION(poLayer->GetLayerDefn());
+    int nGeomFieldCount = LOG_ACTION(poLayerDefn->GetGeomFieldCount());
 
     poLayer->ResetReading();
     CPLErrorReset();
 
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         nFC++;
 
@@ -642,15 +1253,15 @@ static int TestOGRLayerFeatureCount( OGRDataSource* poDS, OGRLayer *poLayer, int
     if( nFC != nClaimedFC )
     {
         bRet = FALSE;
-        printf( "ERROR: Claimed feature count %d doesn't match actual, %d.\n",
+        printf( "ERROR: Claimed feature count " CPL_FRMT_GIB " doesn't match actual, " CPL_FRMT_GIB ".\n",
                 nClaimedFC, nFC );
     }
-    else if( nFC != poLayer->GetFeatureCount() )
+    else if( nFC != LOG_ACTION(poLayer->GetFeatureCount()) )
     {
         bRet = FALSE;
-        printf( "ERROR: Feature count at end of layer %d differs "
-                "from at start, %d.\n",
-                nFC, poLayer->GetFeatureCount() );
+        printf( "ERROR: Feature count at end of layer, " CPL_FRMT_GIB ", differs "
+                "from at start, " CPL_FRMT_GIB ".\n",
+                poLayer->GetFeatureCount(), nFC );
     }
     else if( bVerbose )
         printf( "INFO: Feature count verified.\n" );
@@ -673,8 +1284,8 @@ static int TestOGRLayerFeatureCount( OGRDataSource* poDS, OGRLayer *poLayer, int
             else if (nClaimedFC != poFeatCount->GetFieldAsInteger(0))
             {
                 bRet = FALSE;
-                printf( "ERROR: Claimed feature count %d doesn't match '%s' one, %d.\n",
-                        nClaimedFC, osSQL.c_str(), poFeatCount->GetFieldAsInteger(0) );
+                printf( "ERROR: Claimed feature count " CPL_FRMT_GIB " doesn't match '%s' one, " CPL_FRMT_GIB ".\n",
+                        nClaimedFC, osSQL.c_str(), poFeatCount->GetFieldAsInteger64(0) );
             }
             OGRFeature::DestroyFeature(poFeatCount);
             poDS->ReleaseResultSet(poSQLLyr);
@@ -704,12 +1315,12 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
     OGRFeature  *papoFeatures[5], *poFeature = NULL;
     int         iFeature;
 
-    poLayer->SetSpatialFilter( NULL );
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
     
-    if( poLayer->GetFeatureCount() < 5 )
+    if( LOG_ACTION(poLayer->GetFeatureCount()) < 5 )
     {
         if( bVerbose )
-            printf( "INFO: Only %d features on layer,"
+            printf( "INFO: Only " CPL_FRMT_GIB " features on layer,"
                     "skipping random read test.\n",
                     poLayer->GetFeatureCount() );
         
@@ -719,7 +1330,7 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Fetch five features.                                            */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
     
     for( iFeature = 0; iFeature < 5; iFeature++ )
     {
@@ -727,7 +1338,7 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
     }
     for( iFeature = 0; iFeature < 5; iFeature++ )
     {
-        papoFeatures[iFeature] = poLayer->GetNextFeature();
+        papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
         if( papoFeatures[iFeature] == NULL )
         {
             if( bVerbose )
@@ -741,10 +1352,10 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Test feature 2.                                                 */
 /* -------------------------------------------------------------------- */
-    poFeature = poLayer->GetFeature( papoFeatures[1]->GetFID() );
+    poFeature = LOG_ACTION(poLayer->GetFeature( papoFeatures[1]->GetFID() ));
     if (poFeature == NULL)
     {
-        printf( "ERROR: Cannot fetch feature %ld.\n",
+        printf( "ERROR: Cannot fetch feature " CPL_FRMT_GIB ".\n",
                  papoFeatures[1]->GetFID() );
         goto end;
     }
@@ -752,7 +1363,7 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
     if( !poFeature->Equal( papoFeatures[1] ) )
     {
         bRet = FALSE;
-        printf( "ERROR: Attempt to randomly read feature %ld appears to\n"
+        printf( "ERROR: Attempt to randomly read feature " CPL_FRMT_GIB " appears to\n"
                 "       have returned a different feature than sequential\n"
                 "       reading indicates should have happened.\n",
                 papoFeatures[1]->GetFID() );
@@ -767,11 +1378,28 @@ static int TestOGRLayerRandomRead( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Test feature 5.                                                 */
 /* -------------------------------------------------------------------- */
-    poFeature = poLayer->GetFeature( papoFeatures[4]->GetFID() );
+    poFeature = LOG_ACTION(poLayer->GetFeature( papoFeatures[4]->GetFID() ));
     if( poFeature == NULL || !poFeature->Equal( papoFeatures[4] ) )
     {
         bRet = FALSE;
-        printf( "ERROR: Attempt to randomly read feature %ld appears to\n"
+        printf( "ERROR: Attempt to randomly read feature " CPL_FRMT_GIB " appears to\n"
+                "       have returned a different feature than sequential\n"
+                "       reading indicates should have happened.\n",
+                papoFeatures[4]->GetFID() );
+
+        goto end;
+    }
+
+    OGRFeature::DestroyFeature(poFeature);
+
+/* -------------------------------------------------------------------- */
+/*      Test feature 2 again                                            */
+/* -------------------------------------------------------------------- */
+    poFeature = LOG_ACTION(poLayer->GetFeature( papoFeatures[2]->GetFID() ));
+    if( poFeature == NULL || !poFeature->Equal( papoFeatures[2] ) )
+    {
+        bRet = FALSE;
+        printf( "ERROR: Attempt to randomly read feature " CPL_FRMT_GIB " appears to\n"
                 "       have returned a different feature than sequential\n"
                 "       reading indicates should have happened.\n",
                 papoFeatures[4]->GetFID() );
@@ -809,12 +1437,12 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 
     memset(papoFeatures, 0, sizeof(papoFeatures));
 
-    poLayer->SetSpatialFilter( NULL );
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
     
-    if( poLayer->GetFeatureCount() < 5 )
+    if( LOG_ACTION(poLayer->GetFeatureCount()) < 5 )
     {
         if( bVerbose )
-            printf( "INFO: Only %d features on layer,"
+            printf( "INFO: Only " CPL_FRMT_GIB " features on layer,"
                     "skipping SetNextByIndex test.\n",
                     poLayer->GetFeatureCount() );
         
@@ -824,11 +1452,11 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Fetch five features.                                            */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
     
     for( iFeature = 0; iFeature < 5; iFeature++ )
     {
-        papoFeatures[iFeature] = poLayer->GetNextFeature();
+        papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
         if( papoFeatures[iFeature] == NULL )
         {
             bRet = FALSE;
@@ -840,14 +1468,14 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Test feature at index 1.                                        */
 /* -------------------------------------------------------------------- */
-    if (poLayer->SetNextByIndex(1) != OGRERR_NONE)
+    if (LOG_ACTION(poLayer->SetNextByIndex(1)) != OGRERR_NONE)
     {
         bRet = FALSE;
         printf( "ERROR: SetNextByIndex(%d) failed.\n", 1 );
         goto end;
     }
     
-    poFeature = poLayer->GetNextFeature();
+    poFeature = LOG_ACTION(poLayer->GetNextFeature());
     if( poFeature == NULL || !poFeature->Equal( papoFeatures[1] ) )
     {
         bRet = FALSE;
@@ -861,7 +1489,7 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 
     OGRFeature::DestroyFeature(poFeature);
     
-    poFeature = poLayer->GetNextFeature();
+    poFeature = LOG_ACTION(poLayer->GetNextFeature());
     if( poFeature == NULL || !poFeature->Equal( papoFeatures[2] ) )
     {
         bRet = FALSE;
@@ -879,14 +1507,14 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Test feature at index 3.                                        */
 /* -------------------------------------------------------------------- */
-    if (poLayer->SetNextByIndex(3) != OGRERR_NONE)
+    if (LOG_ACTION(poLayer->SetNextByIndex(3)) != OGRERR_NONE)
     {
         bRet = FALSE;
         printf( "ERROR: SetNextByIndex(%d) failed.\n", 3 );
         goto end;
     }
     
-    poFeature = poLayer->GetNextFeature();
+    poFeature = LOG_ACTION(poLayer->GetNextFeature());
     if( !poFeature->Equal( papoFeatures[3] ) )
     {
         bRet = FALSE;
@@ -900,7 +1528,7 @@ static int TestOGRLayerSetNextByIndex( OGRLayer *poLayer )
 
     OGRFeature::DestroyFeature(poFeature);
     
-    poFeature = poLayer->GetNextFeature();
+    poFeature = LOG_ACTION(poLayer->GetNextFeature());
     if( !poFeature->Equal( papoFeatures[4] ) )
     {
         bRet = FALSE;
@@ -941,23 +1569,23 @@ static int TestOGRLayerRandomWrite( OGRLayer *poLayer )
     int bRet = TRUE;
     OGRFeature  *papoFeatures[5], *poFeature;
     int         iFeature;
-    long        nFID2, nFID5;
+    GIntBig     nFID2, nFID5;
 
     memset(papoFeatures, 0, sizeof(papoFeatures));
 
-    poLayer->SetSpatialFilter( NULL );
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
 
-    if( poLayer->GetFeatureCount() < 5 )
+    if( LOG_ACTION(poLayer->GetFeatureCount()) < 5 )
     {
         if( bVerbose )
-            printf( "INFO: Only %d features on layer,"
+            printf( "INFO: Only " CPL_FRMT_GIB " features on layer,"
                     "skipping random write test.\n",
                     poLayer->GetFeatureCount() );
         
         return bRet;
     }
 
-    if( !poLayer->TestCapability( OLCRandomRead ) )
+    if( !LOG_ACTION(poLayer->TestCapability( OLCRandomRead )) )
     {
         if( bVerbose )
             printf( "INFO: Skipping random write test since this layer "
@@ -968,11 +1596,11 @@ static int TestOGRLayerRandomWrite( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Fetch five features.                                            */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
     
     for( iFeature = 0; iFeature < 5; iFeature++ )
     {
-        papoFeatures[iFeature] = poLayer->GetNextFeature();
+        papoFeatures[iFeature] = LOG_ACTION(poLayer->GetNextFeature());
         if( papoFeatures[iFeature] == NULL )
         {
             bRet = FALSE;
@@ -993,13 +1621,13 @@ static int TestOGRLayerRandomWrite( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Rewrite them.                                                   */
 /* -------------------------------------------------------------------- */
-    if( poLayer->SetFeature( papoFeatures[1] ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->SetFeature( papoFeatures[1] )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to SetFeature(1) failed.\n" );
         goto end;
     }
-    if( poLayer->SetFeature( papoFeatures[4] ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->SetFeature( papoFeatures[4] )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to SetFeature(4) failed.\n" );
@@ -1009,7 +1637,7 @@ static int TestOGRLayerRandomWrite( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Now re-read feature 2 to verify the effect stuck.               */
 /* -------------------------------------------------------------------- */
-    poFeature = poLayer->GetFeature( nFID5 );
+    poFeature = LOG_ACTION(poLayer->GetFeature( nFID5 ));
     if(poFeature == NULL)
     {
         bRet = FALSE;
@@ -1036,12 +1664,12 @@ static int TestOGRLayerRandomWrite( OGRLayer *poLayer )
     papoFeatures[1]->SetFID( nFID2 );
     papoFeatures[4]->SetFID( nFID5 );
 
-    if( poLayer->SetFeature( papoFeatures[1] ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->SetFeature( papoFeatures[1] )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to restore SetFeature(1) failed.\n" );
     }
-    if( poLayer->SetFeature( papoFeatures[4] ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->SetFeature( papoFeatures[4] )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to restore SetFeature(4) failed.\n" );
@@ -1085,13 +1713,13 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     OGRPolygon  oInclusiveFilter, oExclusiveFilter;
     OGRLinearRing oRing;
     OGREnvelope sEnvelope;
-    int         nInclusiveCount;
+    GIntBig         nInclusiveCount;
 
 /* -------------------------------------------------------------------- */
 /*      Read the target feature.                                        */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
-    poTargetFeature = poLayer->GetNextFeature();
+    LOG_ACTION(poLayer->ResetReading());
+    poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
 
     if( poTargetFeature == NULL )
     {
@@ -1121,8 +1749,8 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
 
     OGREnvelope sLayerExtent;
     double epsilon = 10.0;
-    if( poLayer->TestCapability( OLCFastGetExtent ) &&
-        poLayer->GetExtent(iGeomField, &sLayerExtent) == OGRERR_NONE &&
+    if( LOG_ACTION(poLayer->TestCapability( OLCFastGetExtent )) &&
+        LOG_ACTION(poLayer->GetExtent(iGeomField, &sLayerExtent)) == OGRERR_NONE &&
         sLayerExtent.MinX < sLayerExtent.MaxX &&
         sLayerExtent.MinY < sLayerExtent.MaxY )
     {
@@ -1141,14 +1769,14 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     
     oInclusiveFilter.addRing( &oRing );
 
-    poLayer->SetSpatialFilter( iGeomField, &oInclusiveFilter );
+    LOG_ACTION(poLayer->SetSpatialFilter( iGeomField, &oInclusiveFilter ));
 
 /* -------------------------------------------------------------------- */
 /*      Verify that we can find the target feature.                     */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->Equal(poTargetFeature) )
         {
@@ -1170,7 +1798,7 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
         printf( "INFO: Spatial filter inclusion seems to work.\n" );
     }
 
-    nInclusiveCount = poLayer->GetFeatureCount();
+    nInclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
 
 /* -------------------------------------------------------------------- */
 /*      Construct exclusive filter.                                     */
@@ -1183,14 +1811,14 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     
     oExclusiveFilter.addRing( &oRing );
 
-    poLayer->SetSpatialFilter( iGeomField, &oExclusiveFilter );
+    LOG_ACTION(poLayer->SetSpatialFilter( iGeomField, &oExclusiveFilter ));
 
 /* -------------------------------------------------------------------- */
-/*      Verify that we can find the target feature.                     */
+/*      Verify that we can NOT find the target feature.                 */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->Equal(poTargetFeature) )
         {
@@ -1208,7 +1836,7 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
                 "a feature unexpectedly!\n",
                 iGeomField);
     }
-    else if( poLayer->GetFeatureCount() >= nInclusiveCount )
+    else if( LOG_ACTION(poLayer->GetFeatureCount()) >= nInclusiveCount )
     {
         bRet = FALSE;
         printf( "ERROR: GetFeatureCount() may not be taking spatial "
@@ -1221,7 +1849,7 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     }
 
     // Check that GetFeature() ignores the spatial filter
-    poFeature = poLayer->GetFeature( poTargetFeature->GetFID() );
+    poFeature = LOG_ACTION(poLayer->GetFeature( poTargetFeature->GetFID() ));
     if( poFeature == NULL || !poFeature->Equal(poTargetFeature) )
     {
         bRet = FALSE;
@@ -1236,8 +1864,8 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
 
     if( bRet )
     {
-        poLayer->ResetReading();
-        while( (poFeature = poLayer->GetNextFeature()) != NULL )
+        LOG_ACTION(poLayer->ResetReading());
+        while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
         {
             if( poFeature->Equal(poTargetFeature) )
             {
@@ -1272,10 +1900,10 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     OGRPolygon oInfinityFilter;
     oInfinityFilter.addRing( &oRing );
 
-    poLayer->SetSpatialFilter( iGeomField, &oInfinityFilter );
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->SetSpatialFilter( iGeomField, &oInfinityFilter ));
+    LOG_ACTION(poLayer->ResetReading());
     int nCountInf = 0;
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->GetGeomFieldRef(iGeomField) != NULL )
             nCountInf ++;
@@ -1297,10 +1925,10 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     OGRPolygon oHugeFilter;
     oHugeFilter.addRing( &oRing );
 
-    poLayer->SetSpatialFilter( iGeomField, &oHugeFilter );
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->SetSpatialFilter( iGeomField, &oHugeFilter ));
+    LOG_ACTION(poLayer->ResetReading());
     int nCountHuge = 0;
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->GetGeomFieldRef(iGeomField) != NULL )
             nCountHuge ++;
@@ -1310,17 +1938,17 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
 /* -------------------------------------------------------------------- */
 /*     Reset spatial filter                                             */
 /* -------------------------------------------------------------------- */
-    poLayer->SetSpatialFilter( NULL );
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
 
     int nExpected = 0;
     poLayer->ResetReading();
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->GetGeomFieldRef(iGeomField) != NULL )
             nExpected ++;
         delete poFeature;
     }
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
     if( nCountInf != nExpected )
     {
@@ -1347,13 +1975,113 @@ static int TestSpatialFilter( OGRLayer *poLayer, int iGeomField )
     return bRet;
 }
 
+static int TestFullSpatialFilter( OGRLayer *poLayer, int iGeomField )
+
+{
+    int bRet = TRUE;
+
+    OGREnvelope sLayerExtent;
+    double epsilon = 10.0;
+    if( LOG_ACTION(poLayer->TestCapability( OLCFastGetExtent )) &&
+        LOG_ACTION(poLayer->GetExtent(iGeomField, &sLayerExtent)) == OGRERR_NONE &&
+        sLayerExtent.MinX < sLayerExtent.MaxX &&
+        sLayerExtent.MinY < sLayerExtent.MaxY )
+    {
+        epsilon = MIN( sLayerExtent.MaxX - sLayerExtent.MinX, sLayerExtent.MaxY - sLayerExtent.MinY ) / 10.0;
+    }
+
+    GIntBig nTotalFeatureCount = LOG_ACTION(poLayer->GetFeatureCount());
+    for(GIntBig i=0; i<nTotalFeatureCount;i++ )
+    {
+        OGRFeature  *poFeature, *poTargetFeature;
+        OGRPolygon  oInclusiveFilter;
+        OGRLinearRing oRing;
+        OGREnvelope sEnvelope;
+
+    /* -------------------------------------------------------------------- */
+    /*      Read the target feature.                                        */
+    /* -------------------------------------------------------------------- */
+        LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
+        LOG_ACTION(poLayer->ResetReading());
+        LOG_ACTION(poLayer->SetNextByIndex(i));
+        poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
+
+        if( poTargetFeature == NULL )
+        {
+            continue;
+        }
+
+        OGRGeometry* poGeom = poTargetFeature->GetGeomFieldRef(iGeomField);
+        if( poGeom == NULL || poGeom->IsEmpty() )
+        {
+            OGRFeature::DestroyFeature(poTargetFeature);
+            continue;
+        }
+
+        poGeom->getEnvelope( &sEnvelope );
+
+/* -------------------------------------------------------------------- */
+/*      Construct inclusive filter.                                     */
+/* -------------------------------------------------------------------- */
+
+        oRing.setPoint( 0, sEnvelope.MinX - 2 * epsilon, sEnvelope.MinY - 2 * epsilon );
+        oRing.setPoint( 1, sEnvelope.MinX - 2 * epsilon, sEnvelope.MaxY + 1 * epsilon );
+        oRing.setPoint( 2, sEnvelope.MaxX + 1 * epsilon, sEnvelope.MaxY + 1 * epsilon );
+        oRing.setPoint( 3, sEnvelope.MaxX + 1 * epsilon, sEnvelope.MinY - 2 * epsilon );
+        oRing.setPoint( 4, sEnvelope.MinX - 2 * epsilon, sEnvelope.MinY - 2 * epsilon );
+        
+        oInclusiveFilter.addRing( &oRing );
+
+        LOG_ACTION(poLayer->SetSpatialFilter( iGeomField, &oInclusiveFilter ));
+
+/* -------------------------------------------------------------------- */
+/*      Verify that we can find the target feature.                     */
+/* -------------------------------------------------------------------- */
+        LOG_ACTION(poLayer->ResetReading());
+
+        while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
+        {
+            if( poFeature->Equal(poTargetFeature) )
+            {
+                OGRFeature::DestroyFeature(poFeature);
+                break;
+            }
+            else
+                OGRFeature::DestroyFeature(poFeature);
+        }
+
+        if( poFeature == NULL )
+        {
+            bRet = FALSE;
+            printf( "ERROR: Spatial filter (%d) eliminated feature " CPL_FRMT_GIB " unexpectedly!\n",
+                    iGeomField, poTargetFeature->GetFID());
+            OGRFeature::DestroyFeature(poTargetFeature);
+            break;
+        }
+
+        OGRFeature::DestroyFeature(poTargetFeature);
+    }
+
+/* -------------------------------------------------------------------- */
+/*     Reset spatial filter                                             */
+/* -------------------------------------------------------------------- */
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
+    
+    if( bRet && bVerbose )
+    {
+        printf( "INFO: Full spatial filter succeeded.\n");
+    }
+
+    return bRet;
+}
+
 static int TestSpatialFilter( OGRLayer *poLayer )
 {
 /* -------------------------------------------------------------------- */
 /*      Read the target feature.                                        */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
-    OGRFeature* poTargetFeature = poLayer->GetNextFeature();
+    LOG_ACTION(poLayer->ResetReading());
+    OGRFeature* poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
 
     if( poTargetFeature == NULL )
     {
@@ -1367,7 +2095,8 @@ static int TestSpatialFilter( OGRLayer *poLayer )
     }
     OGRFeature::DestroyFeature(poTargetFeature);
 
-    if( poLayer->GetLayerDefn()->GetGeomFieldCount() == 0 )
+    int nGeomFieldCount = LOG_ACTION(poLayer->GetLayerDefn()->GetGeomFieldCount());
+    if( nGeomFieldCount == 0 )
     {
         if( bVerbose )
         {
@@ -1379,21 +2108,25 @@ static int TestSpatialFilter( OGRLayer *poLayer )
     }
 
     int bRet = TRUE;
-    int nGeomFieldCount = poLayer->GetLayerDefn()->GetGeomFieldCount();
     for( int iGeom = 0; iGeom < nGeomFieldCount; iGeom ++ )
+    {
         bRet &= TestSpatialFilter(poLayer, iGeom);
+        
+        if( bFullSpatialFilter )
+            bRet &= TestFullSpatialFilter( poLayer, iGeom );
+    }
     
     OGRPolygon oPolygon;
     CPLErrorReset();
     CPLPushErrorHandler(CPLQuietErrorHandler);
-    poLayer->SetSpatialFilter(-1, &oPolygon);
+    LOG_ACTION(poLayer->SetSpatialFilter(-1, &oPolygon));
     CPLPopErrorHandler();
     if( CPLGetLastErrorType() == 0 )
         printf( "WARNING: poLayer->SetSpatialFilter(-1) should emit an error.\n" );
 
     CPLErrorReset();
     CPLPushErrorHandler(CPLQuietErrorHandler);
-    poLayer->SetSpatialFilter(nGeomFieldCount, &oPolygon);
+    LOG_ACTION(poLayer->SetSpatialFilter(nGeomFieldCount, &oPolygon));
     CPLPopErrorHandler();
     if( CPLGetLastErrorType() == 0 )
         printf( "WARNING: poLayer->SetSpatialFilter(nGeomFieldCount) should emit an error.\n" );
@@ -1412,19 +2145,19 @@ static int TestSpatialFilter( OGRLayer *poLayer )
 /*      filter that doesn't include this feature, and test again.       */
 /************************************************************************/
 
-static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
+static int TestAttributeFilter( GDALDataset* poDS, OGRLayer *poLayer )
 
 {
     int bRet = TRUE;
     OGRFeature  *poFeature, *poFeature2, *poFeature3, *poTargetFeature;
-    int         nInclusiveCount, nExclusiveCount, nTotalCount;
+    GIntBig        nInclusiveCount, nExclusiveCount, nTotalCount;
     CPLString osAttributeFilter;
 
 /* -------------------------------------------------------------------- */
 /*      Read the target feature.                                        */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
-    poTargetFeature = poLayer->GetNextFeature();
+    LOG_ACTION(poLayer->ResetReading());
+    poTargetFeature = LOG_ACTION(poLayer->GetNextFeature());
 
     if( poTargetFeature == NULL )
     {
@@ -1469,19 +2202,12 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
 /*      Construct inclusive filter.                                     */
 /* -------------------------------------------------------------------- */
 
-    if (EQUAL(poDS->GetDriver()->GetName(), "PostgreSQL") &&
-        (strchr(pszFieldName, '_') || strchr(pszFieldName, ' ')))
+    if( strchr(pszFieldName, '_') || strchr(pszFieldName, ' ') )
     {
         osAttributeFilter = "\"";
         osAttributeFilter += pszFieldName;
         osAttributeFilter += "\"";
     }
-    else if (strchr(pszFieldName, ' ') || pszFieldName[0] == '_')
-    {
-        osAttributeFilter = "'";
-        osAttributeFilter += pszFieldName;
-        osAttributeFilter += "'";
-    }
     else
         osAttributeFilter = pszFieldName;
     osAttributeFilter += " = ";
@@ -1494,14 +2220,14 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
     /* to avoid int underflow/overflow */
     else if (eType == OFTReal && strchr(osValue, '.') == NULL)
         osAttributeFilter += ".";
-    poLayer->SetAttributeFilter( osAttributeFilter );
+    LOG_ACTION(poLayer->SetAttributeFilter( osAttributeFilter ));
 
 /* -------------------------------------------------------------------- */
 /*      Verify that we can find the target feature.                     */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->Equal(poTargetFeature) )
         {
@@ -1522,24 +2248,17 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
         printf( "INFO: Attribute filter inclusion seems to work.\n" );
     }
 
-    nInclusiveCount = poLayer->GetFeatureCount();
+    nInclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
 
 /* -------------------------------------------------------------------- */
 /*      Construct exclusive filter.                                     */
 /* -------------------------------------------------------------------- */
-    if (EQUAL(poDS->GetDriver()->GetName(), "PostgreSQL") &&
-        (strchr(pszFieldName, '_') || strchr(pszFieldName, ' ')))
+    if( strchr(pszFieldName, '_') || strchr(pszFieldName, ' ') )
     {
         osAttributeFilter = "\"";
         osAttributeFilter += pszFieldName;
         osAttributeFilter += "\"";
     }
-    else if (strchr(pszFieldName, ' ') || pszFieldName[0] == '_')
-    {
-        osAttributeFilter = "'";
-        osAttributeFilter += pszFieldName;
-        osAttributeFilter += "'";
-    }
     else
         osAttributeFilter = pszFieldName;
     osAttributeFilter += " <> ";
@@ -1552,15 +2271,15 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
     /* to avoid int underflow/overflow */
     else if (eType == OFTReal && strchr(osValue, '.') == NULL)
         osAttributeFilter += ".";
-    poLayer->SetAttributeFilter( osAttributeFilter );
+    LOG_ACTION(poLayer->SetAttributeFilter( osAttributeFilter ));
 
 /* -------------------------------------------------------------------- */
 /*      Verify that we can find the target feature.                     */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
-    int nExclusiveCountWhileIterating = 0;
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    GIntBig nExclusiveCountWhileIterating = 0;
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature->Equal(poTargetFeature) )
         {
@@ -1572,13 +2291,13 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
         nExclusiveCountWhileIterating ++;
     }
 
-    nExclusiveCount = poLayer->GetFeatureCount();
+    nExclusiveCount = LOG_ACTION(poLayer->GetFeatureCount());
 
     // Check that GetFeature() ignores the attribute filter
-    poFeature2 = poLayer->GetFeature( poTargetFeature->GetFID() );
+    poFeature2 = LOG_ACTION(poLayer->GetFeature( poTargetFeature->GetFID() ));
 
     poLayer->ResetReading();
-    while( (poFeature3 = poLayer->GetNextFeature()) != NULL )
+    while( (poFeature3 = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( poFeature3->Equal(poTargetFeature) )
         {
@@ -1589,9 +2308,9 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
             OGRFeature::DestroyFeature(poFeature3);
     }
 
-    poLayer->SetAttributeFilter( NULL );
+    LOG_ACTION(poLayer->SetAttributeFilter( NULL ));
 
-    nTotalCount = poLayer->GetFeatureCount();
+    nTotalCount = LOG_ACTION(poLayer->GetFeatureCount());
 
     if( poFeature != NULL )
     {
@@ -1606,7 +2325,7 @@ static int TestAttributeFilter( OGRDataSource* poDS, OGRLayer *poLayer )
     {
         bRet = FALSE;
         printf( "ERROR: GetFeatureCount() may not be taking attribute "
-                "filter into account (nInclusiveCount = %d, nExclusiveCount = %d, nExclusiveCountWhileIterating = %d, nTotalCount = %d).\n",
+                "filter into account (nInclusiveCount = " CPL_FRMT_GIB ", nExclusiveCount = " CPL_FRMT_GIB ", nExclusiveCountWhileIterating = " CPL_FRMT_GIB ", nTotalCount = " CPL_FRMT_GIB ").\n",
                  nInclusiveCount, nExclusiveCount, nExclusiveCountWhileIterating, nTotalCount);
     }
     else if( bVerbose )
@@ -1646,19 +2365,19 @@ static int TestOGRLayerUTF8 ( OGRLayer *poLayer )
 {
     int bRet = TRUE;
 
-    poLayer->SetSpatialFilter( NULL );
-    poLayer->SetAttributeFilter( NULL );
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
+    LOG_ACTION(poLayer->SetAttributeFilter( NULL ));
+    LOG_ACTION(poLayer->ResetReading());
 
-    int bIsAdvertizedAsUTF8 = poLayer->TestCapability( OLCStringsAsUTF8 );
-    int nFields = poLayer->GetLayerDefn()->GetFieldCount();
+    int bIsAdvertizedAsUTF8 = LOG_ACTION(poLayer->TestCapability( OLCStringsAsUTF8 ));
+    int nFields = LOG_ACTION(poLayer->GetLayerDefn()->GetFieldCount());
     int bFoundString = FALSE;
     int bFoundNonASCII = FALSE;
     int bFoundUTF8 = FALSE;
     int bCanAdvertizeUTF8 = TRUE;
 
     OGRFeature* poFeature = NULL;
-    while( bRet && (poFeature = poLayer->GetNextFeature()) != NULL )
+    while( bRet && (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         for(int i = 0; i<nFields; i++)
         {
@@ -1689,7 +2408,7 @@ static int TestOGRLayerUTF8 ( OGRLayer *poLayer )
                     {
                         if (!bIsUTF8)
                         {
-                            printf( "ERROR: Found non-UTF8 content at field %d of feature %ld, but layer is advertized as UTF-8.\n",
+                            printf( "ERROR: Found non-UTF8 content at field %d of feature " CPL_FRMT_GIB ", but layer is advertized as UTF-8.\n",
                                     i, poFeature->GetFID() );
                             bRet = FALSE;
                             break;
@@ -1750,15 +2469,15 @@ static int TestGetExtent ( OGRLayer *poLayer, int iGeomField )
 {
     int bRet = TRUE;
 
-    poLayer->SetSpatialFilter( NULL );
-    poLayer->SetAttributeFilter( NULL );
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
+    LOG_ACTION(poLayer->SetAttributeFilter( NULL ));
+    LOG_ACTION(poLayer->ResetReading());
 
     OGREnvelope sExtent;
     OGREnvelope sExtentSlow;
 
-    OGRErr eErr = poLayer->GetExtent(iGeomField, &sExtent, TRUE);
-    OGRErr eErr2 = poLayer->OGRLayer::GetExtent(iGeomField, &sExtentSlow, TRUE);
+    OGRErr eErr = LOG_ACTION(poLayer->GetExtent(iGeomField, &sExtent, TRUE));
+    OGRErr eErr2 = LOG_ACTION(poLayer->OGRLayer::GetExtent(iGeomField, &sExtentSlow, TRUE));
 
     if (eErr != eErr2)
     {
@@ -1819,14 +2538,14 @@ static int TestGetExtent ( OGRLayer *poLayer, int iGeomField )
 static int TestGetExtent ( OGRLayer *poLayer )
 {
     int bRet = TRUE;
-    int nGeomFieldCount = poLayer->GetLayerDefn()->GetGeomFieldCount();
+    int nGeomFieldCount = LOG_ACTION(poLayer->GetLayerDefn()->GetGeomFieldCount());
     for( int iGeom = 0; iGeom < nGeomFieldCount; iGeom ++ )
         bRet &= TestGetExtent(poLayer, iGeom);
 
     OGREnvelope sExtent;
     
     CPLPushErrorHandler(CPLQuietErrorHandler);
-    OGRErr eErr = poLayer->GetExtent(-1, &sExtent, TRUE);
+    OGRErr eErr = LOG_ACTION(poLayer->GetExtent(-1, &sExtent, TRUE));
     CPLPopErrorHandler();
     if( eErr != OGRERR_FAILURE )
     {
@@ -1835,7 +2554,7 @@ static int TestGetExtent ( OGRLayer *poLayer )
     }
     
     CPLPushErrorHandler(CPLQuietErrorHandler);
-    eErr = poLayer->GetExtent(nGeomFieldCount, &sExtent, TRUE);
+    eErr = LOG_ACTION(poLayer->GetExtent(nGeomFieldCount, &sExtent, TRUE));
     CPLPopErrorHandler();
     if( eErr != OGRERR_FAILURE )
     {
@@ -1859,11 +2578,11 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
     int bRet = TRUE;
     OGRFeature  * poFeature = NULL;
     OGRFeature  * poFeatureTest = NULL;
-    long        nFID;
+    GIntBig nFID;
 
-    poLayer->SetSpatialFilter( NULL );
+    LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
     
-    if( !poLayer->TestCapability( OLCRandomRead ) )
+    if( !LOG_ACTION(poLayer->TestCapability( OLCRandomRead )) )
     {
         if( bVerbose )
             printf( "INFO: Skipping delete feature test since this layer "
@@ -1871,7 +2590,7 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
         return bRet;
     }
 
-    if( poLayer->GetFeatureCount() == 0 )
+    if( LOG_ACTION(poLayer->GetFeatureCount()) == 0 )
     {
         if( bVerbose )
             printf( "INFO: No feature available on layer '%s',"
@@ -1883,10 +2602,10 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Fetch the last feature                                          */
 /* -------------------------------------------------------------------- */
-    poLayer->ResetReading();
+    LOG_ACTION(poLayer->ResetReading());
 
-    poLayer->SetNextByIndex(poLayer->GetFeatureCount() - 1);
-    poFeature = poLayer->GetNextFeature();
+    LOG_ACTION(poLayer->SetNextByIndex(poLayer->GetFeatureCount() - 1));
+    poFeature = LOG_ACTION(poLayer->GetNextFeature());
     if (poFeature == NULL)
     {
         bRet = FALSE;
@@ -1902,7 +2621,7 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Delete the feature.                                             */
 /* -------------------------------------------------------------------- */
-    if( poLayer->DeleteFeature( nFID ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->DeleteFeature( nFID )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to DeleteFeature() failed.\n" );
@@ -1913,7 +2632,7 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
 /*      Now re-read the feature to verify the delete effect worked.     */
 /* -------------------------------------------------------------------- */
     CPLPushErrorHandler(CPLQuietErrorHandler); /* silent legitimate error message */
-    poFeatureTest = poLayer->GetFeature( nFID );
+    poFeatureTest = LOG_ACTION(poLayer->GetFeature( nFID ));
     CPLPopErrorHandler();
     if( poFeatureTest != NULL)
     {
@@ -1929,7 +2648,7 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Re-insert the features to restore to original state             */
 /* -------------------------------------------------------------------- */
-    if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
+    if( LOG_ACTION(poLayer->CreateFeature( poFeature )) != OGRERR_NONE )
     {
         bRet = FALSE;
         printf( "ERROR: Attempt to restore feature failed.\n" );
@@ -1949,7 +2668,7 @@ static int TestOGRLayerDeleteAndCreateFeature( OGRLayer *poLayer )
 /* -------------------------------------------------------------------- */
 /*      Now re-read the feature to verify the create effect worked.     */
 /* -------------------------------------------------------------------- */
-    poFeatureTest = poLayer->GetFeature( nFID );
+    poFeatureTest = LOG_ACTION(poLayer->GetFeature( nFID ));
     if( poFeatureTest == NULL)
     {
         bRet = FALSE;
@@ -1979,15 +2698,15 @@ static int TestTransactions( OGRLayer *poLayer )
 
 {
     OGRFeature* poFeature = NULL;
-    int nInitialFeatureCount = poLayer->GetFeatureCount();
+    GIntBig nInitialFeatureCount = LOG_ACTION(poLayer->GetFeatureCount());
 
-    OGRErr eErr = poLayer->StartTransaction();
+    OGRErr eErr = LOG_ACTION(poLayer->StartTransaction());
     if (eErr == OGRERR_NONE)
     {
-        if (poLayer->TestCapability(OLCTransactions) == FALSE)
+        if (LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == FALSE)
         {
-            eErr = poLayer->RollbackTransaction();
-            if (eErr == OGRERR_UNSUPPORTED_OPERATION && poLayer->TestCapability(OLCTransactions) == FALSE)
+            eErr = LOG_ACTION(poLayer->RollbackTransaction());
+            if (eErr == OGRERR_UNSUPPORTED_OPERATION && LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == FALSE)
             {
                 /* The default implementation has a dummy StartTransaction(), but RollbackTransaction() returns */
                 /* OGRERR_UNSUPPORTED_OPERATION */
@@ -2005,7 +2724,7 @@ static int TestTransactions( OGRLayer *poLayer )
     }
     else if (eErr == OGRERR_FAILURE)
     {
-        if (poLayer->TestCapability(OLCTransactions) == TRUE)
+        if (LOG_ACTION(poLayer->TestCapability(OLCTransactions)) == TRUE)
         {
             printf("ERROR: StartTransaction() failed, but TestCapability(OLCTransactions) returns TRUE.\n");
             return FALSE;
@@ -2016,32 +2735,32 @@ static int TestTransactions( OGRLayer *poLayer )
         }
     }
 
-    eErr = poLayer->RollbackTransaction();
+    eErr = LOG_ACTION(poLayer->RollbackTransaction());
     if (eErr != OGRERR_NONE)
     {
-        printf("ERROR: RollbackTransaction() failed after successfull StartTransaction().\n");
+        printf("ERROR: RollbackTransaction() failed after successful StartTransaction().\n");
         return FALSE;
     }
 
     /* ---------------- */
 
-    eErr = poLayer->StartTransaction();
+    eErr = LOG_ACTION(poLayer->StartTransaction());
     if (eErr != OGRERR_NONE)
     {
         printf("ERROR: StartTransaction() failed.\n");
         return FALSE;
     }
 
-    eErr = poLayer->CommitTransaction();
+    eErr = LOG_ACTION(poLayer->CommitTransaction());
     if (eErr != OGRERR_NONE)
     {
-        printf("ERROR: CommitTransaction() failed after successfull StartTransaction().\n");
+        printf("ERROR: CommitTransaction() failed after successful StartTransaction().\n");
         return FALSE;
     }
 
     /* ---------------- */
 
-    eErr = poLayer->StartTransaction();
+    eErr = LOG_ACTION(poLayer->StartTransaction());
     if (eErr != OGRERR_NONE)
     {
         printf("ERROR: StartTransaction() failed.\n");
@@ -2051,7 +2770,7 @@ static int TestTransactions( OGRLayer *poLayer )
     poFeature = new OGRFeature(poLayer->GetLayerDefn());
     if (poLayer->GetLayerDefn()->GetFieldCount() > 0)
         poFeature->SetField(0, "0");
-    eErr = poLayer->CreateFeature(poFeature);
+    eErr = LOG_ACTION(poLayer->CreateFeature(poFeature));
     delete poFeature;
     poFeature = NULL;
 
@@ -2061,29 +2780,28 @@ static int TestTransactions( OGRLayer *poLayer )
         {
             printf("INFO: CreateFeature() failed. Exiting this test now.\n");
         }
-        poLayer->RollbackTransaction();
+        LOG_ACTION(poLayer->RollbackTransaction());
         return TRUE;
     }
 
-    eErr = poLayer->RollbackTransaction();
+    eErr = LOG_ACTION(poLayer->RollbackTransaction());
     if (eErr != OGRERR_NONE)
     {
-        printf("ERROR: RollbackTransaction() failed after successfull StartTransaction().\n");
+        printf("ERROR: RollbackTransaction() failed after successful StartTransaction().\n");
         return FALSE;
     }
 
-    if (poLayer->GetFeatureCount() != nInitialFeatureCount)
+    if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount)
     {
         printf("ERROR: GetFeatureCount() should have returned its initial value after RollbackTransaction().\n");
-        poLayer->RollbackTransaction();
         return FALSE;
     }
 
     /* ---------------- */
 
-    if( poLayer->TestCapability( OLCDeleteFeature ) )
+    if( LOG_ACTION(poLayer->TestCapability( OLCDeleteFeature )) )
     {
-        eErr = poLayer->StartTransaction();
+        eErr = LOG_ACTION(poLayer->StartTransaction());
         if (eErr != OGRERR_NONE)
         {
             printf("ERROR: StartTransaction() failed.\n");
@@ -2094,42 +2812,47 @@ static int TestTransactions( OGRLayer *poLayer )
         if (poLayer->GetLayerDefn()->GetFieldCount() > 0)
             poFeature->SetField(0, "0");
         eErr = poLayer->CreateFeature(poFeature);
-        int nFID = poFeature->GetFID();
+        GIntBig nFID = poFeature->GetFID();
         delete poFeature;
         poFeature = NULL;
 
         if (eErr == OGRERR_FAILURE)
         {
             printf("ERROR: CreateFeature() failed. Exiting this test now.\n");
-            poLayer->RollbackTransaction();
+            LOG_ACTION(poLayer->RollbackTransaction());
             return FALSE;
         }
 
-        eErr = poLayer->CommitTransaction();
+        if( nFID < 0 )
+        {
+            printf("WARNING: CreateFeature() returned featured without FID.\n");
+            LOG_ACTION(poLayer->RollbackTransaction());
+            return FALSE;
+        }
+
+        eErr = LOG_ACTION(poLayer->CommitTransaction());
         if (eErr != OGRERR_NONE)
         {
-            printf("ERROR: CommitTransaction() failed after successfull StartTransaction().\n");
+            printf("ERROR: CommitTransaction() failed after successful StartTransaction().\n");
             return FALSE;
         }
 
-        if (poLayer->GetFeatureCount() != nInitialFeatureCount + 1)
+        if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount + 1)
         {
             printf("ERROR: GetFeatureCount() should have returned its initial value + 1 after CommitTransaction().\n");
-            poLayer->RollbackTransaction();
             return FALSE;
         }
 
-        eErr = poLayer->DeleteFeature(nFID);
+        eErr = LOG_ACTION(poLayer->DeleteFeature(nFID));
         if (eErr != OGRERR_NONE)
         {
             printf("ERROR: DeleteFeature() failed.\n");
             return FALSE;
         }
 
-        if (poLayer->GetFeatureCount() != nInitialFeatureCount)
+        if (LOG_ACTION(poLayer->GetFeatureCount()) != nInitialFeatureCount)
         {
             printf("ERROR: GetFeatureCount() should have returned its initial value after DeleteFeature().\n");
-            poLayer->RollbackTransaction();
             return FALSE;
         }
     }
@@ -2155,8 +2878,8 @@ static int TestOGRLayerIgnoreFields( OGRLayer* poLayer )
     int bGeomNonEmpty = FALSE;
     OGRFeature* poFeature;
 
-    poLayer->ResetReading();
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    LOG_ACTION(poLayer->ResetReading());
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( iFieldNonEmpty < 0 )
         {
@@ -2204,7 +2927,7 @@ static int TestOGRLayerIgnoreFields( OGRLayer* poLayer )
     if( bGeomNonEmpty )
         papszIgnoredFields = CSLAddString(papszIgnoredFields, "OGR_GEOMETRY");
 
-    OGRErr eErr = poLayer->SetIgnoredFields((const char**)papszIgnoredFields);
+    OGRErr eErr = LOG_ACTION(poLayer->SetIgnoredFields((const char**)papszIgnoredFields));
     CSLDestroy(papszIgnoredFields);
 
     if( eErr == OGRERR_FAILURE )
@@ -2216,8 +2939,8 @@ static int TestOGRLayerIgnoreFields( OGRLayer* poLayer )
 
     int bFoundNonEmpty2 = FALSE;
 
-    poLayer->ResetReading();
-    while( (poFeature = poLayer->GetNextFeature()) != NULL )
+    LOG_ACTION(poLayer->ResetReading());
+    while( (poFeature = LOG_ACTION(poLayer->GetNextFeature())) != NULL )
     {
         if( iFieldNonEmpty >= 0 && poFeature->IsFieldSet(iFieldNonEmpty) )
         {
@@ -2248,7 +2971,7 @@ static int TestOGRLayerIgnoreFields( OGRLayer* poLayer )
         return FALSE;
     }
 
-    poLayer->SetIgnoredFields(NULL);
+    LOG_ACTION(poLayer->SetIgnoredFields(NULL));
 
     if( bVerbose )
     {
@@ -2262,30 +2985,39 @@ static int TestOGRLayerIgnoreFields( OGRLayer* poLayer )
 /*                            TestLayerSQL()                            */
 /************************************************************************/
 
-static int TestLayerSQL( OGRDataSource* poDS, OGRLayer * poLayer )
+static int TestLayerSQL( GDALDataset* poDS, OGRLayer * poLayer )
 
 {
     int bRet = TRUE;
     OGRLayer* poSQLLyr = NULL;
     OGRFeature* poLayerFeat = NULL;
     OGRFeature* poSQLFeat = NULL;
+    int bGotFeature = FALSE;
 
     CPLString osSQL;
 
     /* Test consistency between result layer and traditionnal layer */
-    poLayer->ResetReading();
-    poLayerFeat = poLayer->GetNextFeature();
+    LOG_ACTION(poLayer->ResetReading());
+    poLayerFeat = LOG_ACTION(poLayer->GetNextFeature());
+
+    /* Reset to avoid potentially a statement to be active which cause */
+    /* issue in the transaction test of the second layer, when testing */
+    /* multi-tables sqlite and gpkg databases */
+    LOG_ACTION(poLayer->ResetReading());
 
     osSQL.Printf("SELECT * FROM %s", GetLayerNameForSQL(poDS, poLayer->GetName()));
-    poSQLLyr = poDS->ExecuteSQL(osSQL.c_str(), NULL, NULL);
+    poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), NULL, NULL));
     if( poSQLLyr == NULL )
     {
         printf( "ERROR: ExecuteSQL(%s) failed.\n", osSQL.c_str() );
         bRet = FALSE;
+        return bRet;
     }
     else
     {
-        poSQLFeat = poSQLLyr->GetNextFeature();
+        poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
+        if( poSQLFeat != NULL )
+            bGotFeature = TRUE;
         if( poLayerFeat == NULL && poSQLFeat != NULL )
         {
             printf( "ERROR: poLayerFeat == NULL && poSQLFeat != NULL.\n" );
@@ -2373,24 +3105,55 @@ static int TestLayerSQL( OGRDataSource* poDS, OGRLayer * poLayer )
     poSQLFeat = NULL;
     if( poSQLLyr )
     {
-        poDS->ReleaseResultSet(poSQLLyr);
+        LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
+        poSQLLyr = NULL;
+    }
+
+    /* Try ResetReading(), GetNextFeature(), ResetReading(), GetNextFeature() */
+    poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), NULL, NULL));
+
+    LOG_ACTION(poSQLLyr->ResetReading());
+
+    poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
+    if( poSQLFeat == NULL && bGotFeature )
+    {
+        printf( "ERROR: Should have got feature (1)\n" );
+        bRet = FALSE;
+    }
+    OGRFeature::DestroyFeature(poSQLFeat);
+    poSQLFeat = NULL;
+
+    LOG_ACTION(poSQLLyr->ResetReading());
+
+    poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
+    if( poSQLFeat == NULL && bGotFeature )
+    {
+        printf( "ERROR: Should have got feature (2)\n" );
+        bRet = FALSE;
+    }
+    OGRFeature::DestroyFeature(poSQLFeat);
+    poSQLFeat = NULL;
+
+    if( poSQLLyr )
+    {
+        LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
         poSQLLyr = NULL;
     }
 
     /* Return an empty layer */
     osSQL.Printf("SELECT * FROM %s WHERE 0 = 1", GetLayerNameForSQL(poDS, poLayer->GetName()));
 
-    poSQLLyr = poDS->ExecuteSQL(osSQL.c_str(), NULL, NULL);
+    poSQLLyr = LOG_ACTION(poDS->ExecuteSQL(osSQL.c_str(), NULL, NULL));
     if (poSQLLyr)
     {
-        poSQLFeat = poSQLLyr->GetNextFeature();
+        poSQLFeat = LOG_ACTION(poSQLLyr->GetNextFeature());
         if (poSQLFeat != NULL)
         {
             bRet = FALSE;
             printf( "ERROR: ExecuteSQL() should have returned a layer without features.\n" );
         }
         OGRFeature::DestroyFeature(poSQLFeat);
-        poDS->ReleaseResultSet(poSQLLyr);
+        LOG_ACTION(poDS->ReleaseResultSet(poSQLLyr));
     }
     else
     {
@@ -2408,7 +3171,7 @@ static int TestLayerSQL( OGRDataSource* poDS, OGRLayer * poLayer )
 /*                            TestOGRLayer()                            */
 /************************************************************************/
 
-static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLayer )
+static int TestOGRLayer( GDALDataset* poDS, OGRLayer * poLayer, int bIsSQLLayer )
 
 {
     int bRet = TRUE;
@@ -2416,11 +3179,11 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 /* -------------------------------------------------------------------- */
 /*      Verify that there is no spatial filter in place by default.     */
 /* -------------------------------------------------------------------- */
-    if( poLayer->GetSpatialFilter() != NULL )
+    if( LOG_ACTION(poLayer->GetSpatialFilter()) != NULL )
     {
         printf( "WARN: Spatial filter in place by default on layer %s.\n",
                 poLayer->GetName() );
-        poLayer->SetSpatialFilter( NULL );
+        LOG_ACTION(poLayer->SetSpatialFilter( NULL ));
     }
 
 /* -------------------------------------------------------------------- */
@@ -2451,23 +3214,17 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 /* -------------------------------------------------------------------- */
 /*      Test random reading.                                            */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCRandomRead ) )
-    {
-        bRet &= TestOGRLayerRandomRead( poLayer );
-    }
+    bRet &= TestOGRLayerRandomRead( poLayer );
     
 /* -------------------------------------------------------------------- */
 /*      Test SetNextByIndex.                                            */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCFastSetNextByIndex ) )
-    {
-        bRet &= TestOGRLayerSetNextByIndex( poLayer );
-    }
-    
+    bRet &= TestOGRLayerSetNextByIndex( poLayer );
+
 /* -------------------------------------------------------------------- */
 /*      Test delete feature.                                            */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCDeleteFeature ) )
+    if( LOG_ACTION(poLayer->TestCapability( OLCDeleteFeature )) )
     {
         bRet &= TestOGRLayerDeleteAndCreateFeature( poLayer );
     }
@@ -2475,7 +3232,7 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 /* -------------------------------------------------------------------- */
 /*      Test random writing.                                            */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCRandomWrite ) )
+    if( LOG_ACTION(poLayer->TestCapability( OLCRandomWrite )) )
     {
         bRet &= TestOGRLayerRandomWrite( poLayer );
     }
@@ -2483,7 +3240,7 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 /* -------------------------------------------------------------------- */
 /*      Test OLCIgnoreFields.                                           */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCIgnoreFields ) )
+    if( LOG_ACTION(poLayer->TestCapability( OLCIgnoreFields )) )
     {
         bRet &= TestOGRLayerIgnoreFields( poLayer );
     }
@@ -2496,7 +3253,7 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 /* -------------------------------------------------------------------- */
 /*      Test TestTransactions()                                         */
 /* -------------------------------------------------------------------- */
-    if( poLayer->TestCapability( OLCSequentialWrite ) )
+    if( LOG_ACTION(poLayer->TestCapability( OLCSequentialWrite )) )
     {
         bRet &= TestTransactions( poLayer );
     }
@@ -2523,8 +3280,8 @@ static int TestOGRLayer( OGRDataSource* poDS, OGRLayer * poLayer, int bIsSQLLaye
 static int TestInterleavedReading( const char* pszDataSource, char** papszLayers )
 {
     int bRet = TRUE;
-    OGRDataSource* poDS = NULL;
-    OGRDataSource* poDS2 = NULL;
+    GDALDataset* poDS = NULL;
+    GDALDataset* poDS2 = NULL;
     OGRLayer* poLayer1 = NULL;
     OGRLayer* poLayer2 = NULL;
     OGRFeature* poFeature11_Ref = NULL;
@@ -2537,7 +3294,8 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
     OGRFeature* poFeature22 = NULL;
 
     /* Check that we have 2 layers with at least 2 features */
-    poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE, NULL );
+    poDS = LOG_ACTION((GDALDataset*) GDALOpenEx( pszDataSource,
+                            GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL ));
     if (poDS == NULL)
     {
         if( bVerbose )
@@ -2547,10 +3305,10 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
         goto bye;
     }
 
-    poLayer1 = papszLayers ? poDS->GetLayerByName(papszLayers[0]) : poDS->GetLayer(0);
-    poLayer2 = papszLayers ? poDS->GetLayerByName(papszLayers[1]) : poDS->GetLayer(1);
+    poLayer1 = LOG_ACTION(papszLayers ? poDS->GetLayerByName(papszLayers[0]) : poDS->GetLayer(0));
+    poLayer2 = LOG_ACTION(papszLayers ? poDS->GetLayerByName(papszLayers[1]) : poDS->GetLayer(1));
     if (poLayer1 == NULL || poLayer2 == NULL ||
-        poLayer1->GetFeatureCount() < 2 || poLayer2->GetFeatureCount() < 2)
+        LOG_ACTION(poLayer1->GetFeatureCount()) < 2 || LOG_ACTION(poLayer2->GetFeatureCount()) < 2)
     {
         if( bVerbose )
         {
@@ -2560,9 +3318,11 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
     }
 
     /* Test normal reading */
-    OGRDataSource::DestroyDataSource(poDS);
-    poDS = OGRSFDriverRegistrar::Open( pszDataSource, FALSE, NULL );
-    poDS2 = OGRSFDriverRegistrar::Open( pszDataSource, FALSE, NULL );
+    LOG_ACTION(GDALClose( (GDALDatasetH)poDS ));
+    poDS = LOG_ACTION((GDALDataset*) GDALOpenEx( pszDataSource,
+                                GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL ));
+    poDS2 = LOG_ACTION((GDALDataset*) GDALOpenEx( pszDataSource,
+                                GDAL_OF_VECTOR, NULL, papszOpenOptions, NULL ));
     if (poDS == NULL || poDS2 == NULL)
     {
         if( bVerbose )
@@ -2572,8 +3332,8 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
         goto bye;
     }
 
-    poLayer1 = papszLayers ? poDS->GetLayerByName(papszLayers[0]) : poDS->GetLayer(0);
-    poLayer2 = papszLayers ? poDS->GetLayerByName(papszLayers[1]) : poDS->GetLayer(1);
+    poLayer1 = LOG_ACTION(papszLayers ? poDS->GetLayerByName(papszLayers[0]) : poDS->GetLayer(0));
+    poLayer2 = LOG_ACTION(papszLayers ? poDS->GetLayerByName(papszLayers[1]) : poDS->GetLayer(1));
     if (poLayer1 == NULL || poLayer2 == NULL)
     {
         printf( "ERROR: Skipping TestInterleavedReading(). Test conditions are not met\n" );
@@ -2581,10 +3341,10 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
         goto bye;
     }
 
-    poFeature11_Ref = poLayer1->GetNextFeature();
-    poFeature12_Ref = poLayer1->GetNextFeature();
-    poFeature21_Ref = poLayer2->GetNextFeature();
-    poFeature22_Ref = poLayer2->GetNextFeature();
+    poFeature11_Ref = LOG_ACTION(poLayer1->GetNextFeature());
+    poFeature12_Ref = LOG_ACTION(poLayer1->GetNextFeature());
+    poFeature21_Ref = LOG_ACTION(poLayer2->GetNextFeature());
+    poFeature22_Ref = LOG_ACTION(poLayer2->GetNextFeature());
     if (poFeature11_Ref == NULL || poFeature12_Ref == NULL || poFeature21_Ref == NULL || poFeature22_Ref == NULL)
     {
         printf( "ERROR: TestInterleavedReading() failed: poFeature11_Ref=%p, poFeature12_Ref=%p, poFeature21_Ref=%p, poFeature22_Ref=%p\n",
@@ -2594,8 +3354,8 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
     }
 
     /* Test interleaved reading */
-    poLayer1 = papszLayers ? poDS2->GetLayerByName(papszLayers[0]) : poDS2->GetLayer(0);
-    poLayer2 = papszLayers ? poDS2->GetLayerByName(papszLayers[1]) : poDS2->GetLayer(1);
+    poLayer1 = LOG_ACTION(papszLayers ? poDS2->GetLayerByName(papszLayers[0]) : poDS2->GetLayer(0));
+    poLayer2 = LOG_ACTION(papszLayers ? poDS2->GetLayerByName(papszLayers[1]) : poDS2->GetLayer(1));
     if (poLayer1 == NULL || poLayer2 == NULL)
     {
         printf( "ERROR: Skipping TestInterleavedReading(). Test conditions are not met\n" );
@@ -2603,10 +3363,10 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
         goto bye;
     }
 
-    poFeature11 = poLayer1->GetNextFeature();
-    poFeature21 = poLayer2->GetNextFeature();
-    poFeature12 = poLayer1->GetNextFeature();
-    poFeature22 = poLayer2->GetNextFeature();
+    poFeature11 = LOG_ACTION(poLayer1->GetNextFeature());
+    poFeature21 = LOG_ACTION(poLayer2->GetNextFeature());
+    poFeature12 = LOG_ACTION(poLayer1->GetNextFeature());
+    poFeature22 = LOG_ACTION(poLayer2->GetNextFeature());
 
     if (poFeature11 == NULL || poFeature21 == NULL || poFeature12 == NULL || poFeature22 == NULL)
     {
@@ -2636,7 +3396,7 @@ static int TestInterleavedReading( const char* pszDataSource, char** papszLayers
 
     if( bVerbose )
     {
-        printf("INFO: TestInterleavedReading() successfull.\n");
+        printf("INFO: TestInterleavedReading() successful.\n");
     }
 
 bye:
@@ -2648,8 +3408,10 @@ bye:
     OGRFeature::DestroyFeature(poFeature21);
     OGRFeature::DestroyFeature(poFeature12);
     OGRFeature::DestroyFeature(poFeature22);
-    OGRDataSource::DestroyDataSource(poDS);
-    OGRDataSource::DestroyDataSource(poDS2);
+    if( poDS != NULL)
+        LOG_ACTION(GDALClose( (GDALDatasetH)poDS ));
+    if( poDS2 != NULL )
+        LOG_ACTION(GDALClose( (GDALDatasetH)poDS2 ));
     return bRet;
 }
 
@@ -2657,45 +3419,45 @@ bye:
 /*                          TestDSErrorConditions()                     */
 /************************************************************************/
 
-static int TestDSErrorConditions( OGRDataSource * poDS )
+static int TestDSErrorConditions( GDALDataset * poDS )
 {
     int bRet = TRUE;
     OGRLayer* poLyr;
 
     CPLPushErrorHandler(CPLQuietErrorHandler);
 
-    if (poDS->TestCapability("fake_capability"))
+    if (LOG_ACTION(poDS->TestCapability("fake_capability")))
     {
         printf( "ERROR: TestCapability(\"fake_capability\") should have returned FALSE\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poDS->GetLayer(-1) != NULL)
+    if (LOG_ACTION(poDS->GetLayer(-1)) != NULL)
     {
         printf( "ERROR: GetLayer(-1) should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poDS->GetLayer(poDS->GetLayerCount()) != NULL)
+    if (LOG_ACTION(poDS->GetLayer(poDS->GetLayerCount())) != NULL)
     {
         printf( "ERROR: GetLayer(poDS->GetLayerCount()) should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    if (poDS->GetLayerByName("non_existing_layer") != NULL)
+    if (LOG_ACTION(poDS->GetLayerByName("non_existing_layer")) != NULL)
     {
         printf( "ERROR: GetLayerByName(\"non_existing_layer\") should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
     }
 
-    poLyr = poDS->ExecuteSQL("a fake SQL command", NULL, NULL);
+    poLyr = LOG_ACTION(poDS->ExecuteSQL("a fake SQL command", NULL, NULL));
     if (poLyr != NULL)
     {
-        poDS->ReleaseResultSet(poLyr);
+        LOG_ACTION(poDS->ReleaseResultSet(poLyr));
         printf( "ERROR: ExecuteSQL(\"a fake SQL command\") should have returned NULL\n" );
         bRet = FALSE;
         goto bye;
@@ -2705,3 +3467,96 @@ bye:
     CPLPopErrorHandler();
     return bRet;
 }
+
+/************************************************************************/
+/*                              TestVirtualIO()                         */
+/************************************************************************/
+
+static int TestVirtualIO( GDALDataset * poDS )
+{
+    int bRet = TRUE;
+
+    if( strncmp( poDS->GetDescription(), "/vsimem/", strlen("/vsimem/") ) == 0 )
+        return TRUE;
+
+    VSIStatBufL sStat;
+    if( !(VSIStatL( poDS->GetDescription(), &sStat) == 0) )
+        return TRUE;
+
+    char** papszFileList = LOG_ACTION(poDS->GetFileList());
+    char** papszIter = papszFileList;
+    CPLString osPath;
+    int bAllPathIdentical = TRUE;
+    for( ; *papszIter != NULL; papszIter++ )
+    {
+        if( papszIter == papszFileList )
+            osPath = CPLGetPath(*papszIter);
+        else if( strcmp(osPath, CPLGetPath(*papszIter)) != 0 )
+        {
+            bAllPathIdentical = FALSE;
+            break;
+        }
+    }
+    CPLString osVirtPath;
+    if( bAllPathIdentical && CSLCount(papszFileList) > 1 )
+    {
+        osVirtPath = CPLFormFilename("/vsimem", CPLGetFilename(osPath), NULL);
+        VSIMkdir(osVirtPath, 0666);
+    }
+    else
+        osVirtPath = "/vsimem";
+    papszIter = papszFileList;
+    for( ; *papszIter != NULL; papszIter++ )
+    {
+        const char* pszDestFile = CPLFormFilename(osVirtPath, CPLGetFilename(*papszIter), NULL);
+        /* CPLDebug("test_ogrsf", "Copying %s to %s", *papszIter, pszDestFile); */
+        CPLCopyFile( pszDestFile, *papszIter );
+    }
+    
+    const char* pszVirtFile;
+    if( VSI_ISREG(sStat.st_mode) )
+        pszVirtFile = CPLFormFilename(osVirtPath, CPLGetFilename(poDS->GetDescription()), NULL);
+    else
+        pszVirtFile = osVirtPath;
+    CPLDebug("test_ogrsf", "Trying to open %s", pszVirtFile);
+    GDALDataset* poDS2 = LOG_ACTION((GDALDataset*)GDALOpenEx(
+        pszVirtFile, GDAL_OF_VECTOR, NULL, NULL, NULL ));
+    if( poDS2 != NULL )
+    {
+        if( poDS->GetDriver()->GetMetadataItem( GDAL_DCAP_VIRTUALIO ) == NULL )
+        {
+            printf("WARNING: %s driver apparently supports VirtualIO but does not declare it.\n",
+                    poDS->GetDriver()->GetDescription() );
+        }
+        if( poDS2->GetLayerCount() != poDS->GetLayerCount() )
+        {
+            printf("WARNING: /vsimem dataset reports %d layers where as base dataset reports %d layers.\n",
+                    poDS2->GetLayerCount(), poDS->GetLayerCount() );
+        }
+        GDALClose( (GDALDatasetH) poDS2 );
+
+        if( bVerbose && bRet )
+        {
+            printf("INFO: TestVirtualIO successful.\n");
+        }
+    }
+    else
+    {
+        if( poDS->GetDriver()->GetMetadataItem( GDAL_DCAP_VIRTUALIO ) != NULL )
+        {
+            printf("WARNING: %s driver declares supporting VirtualIO but "
+                    "test with /vsimem does not work. It might be a sign that "
+                    "GetFileList() is not properly implemented.\n",
+                    poDS->GetDriver()->GetDescription() );
+        }
+    }
+
+    papszIter = papszFileList;
+    for( ; *papszIter != NULL; papszIter++ )
+    {
+        VSIUnlink( CPLFormFilename(osVirtPath, CPLGetFilename(*papszIter), NULL) );
+    }
+    CSLDestroy(papszFileList);
+
+    return bRet;
+}
diff --git a/apps/testepsg.cpp b/apps/testepsg.cpp
index 30cdd36..14afe82 100644
--- a/apps/testepsg.cpp
+++ b/apps/testepsg.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: testepsg.cpp 18987 2010-03-01 19:44:06Z rouault $
+ * $Id: testepsg.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Test mainline for translating EPSG definitions into WKT.
@@ -89,12 +89,12 @@ int main( int nArgc, char ** papszArgv )
             
             poCT = OGRCreateCoordinateTransformation( &oSourceSRS,
                                                       &oTargetSRS );
-            x = atof( papszArgv[i+3] );
-            y = atof( papszArgv[i+4] );
+            x = CPLAtof( papszArgv[i+3] );
+            y = CPLAtof( papszArgv[i+4] );
             if( i < nArgc - 5 
-                && (atof(papszArgv[i+5]) > 0.0 || papszArgv[i+5][0] == '0') )
+                && (CPLAtof(papszArgv[i+5]) > 0.0 || papszArgv[i+5][0] == '0') )
             {
-                z_orig = z = atof(papszArgv[i+5]);
+                z_orig = z = CPLAtof(papszArgv[i+5]);
                 nArgsUsed++;
             }
             else
@@ -104,8 +104,8 @@ int main( int nArgc, char ** papszArgv )
                 printf( "Transformation failed.\n" );
             else
                 printf( "(%f,%f,%f) -> (%f,%f,%f)\n", 
-                        atof( papszArgv[i+3] ),
-                        atof( papszArgv[i+4] ),
+                        CPLAtof( papszArgv[i+3] ),
+                        CPLAtof( papszArgv[i+4] ),
                         z_orig, 
                         x, y, z );
             
diff --git a/apps/testreprojmulti.cpp b/apps/testreprojmulti.cpp
index 95b7010..62d5d3d 100644
--- a/apps/testreprojmulti.cpp
+++ b/apps/testreprojmulti.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: testreprojmulti.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: testreprojmulti.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Test multi-threaded reprojection
@@ -34,7 +34,7 @@
 #include "cpl_multiproc.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: testreprojmulti.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: testreprojmulti.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 double* padfRefX;
 double* padfRefY;
@@ -65,7 +65,7 @@ void ReprojFunc(void* unused)
         memcpy(padfResultY, padfRefY, 1024 * sizeof(double));
         poCT->TransformEx( 1024, padfResultX, padfResultY, NULL, NULL );
 
-        /* Check that the results are consistant with the reference results */
+        /* Check that the results are consistent with the reference results */
         assert(memcmp(padfResultX, padfRefResultX, 1024 * sizeof(double)) == 0);
         assert(memcmp(padfResultY, padfRefResultY, 1024 * sizeof(double)) == 0);
 
diff --git a/bridge/gdalbridge.cpp b/bridge/gdalbridge.cpp
index 492190a..4f63fdd 100644
--- a/bridge/gdalbridge.cpp
+++ b/bridge/gdalbridge.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalbridge.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: gdalbridge.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  GDAL Bridge 
  * Purpose:  Implementation of GDALBridgeInitialize()
@@ -85,7 +85,7 @@ static void *GBGetSymbolCheck( const char *pszLibrary,
 
         if( i < MAX_SYMBOL-1 )
         {
-            papszErrorList[i] = strdup( pszSymbolName );
+            papszErrorList[i] = CPLStrdup( pszSymbolName );
             papszErrorList[i+1] = NULL;
         }
     }
@@ -512,7 +512,7 @@ int GDALBridgeInitialize( const char * pszTargetDir, FILE *fpReportFailure )
         for( iError = 0; apszFailed[iError] != NULL; iError++ )
         {
             fprintf( fpReportFailure, "  o %s\n", apszFailed[iError] );
-            free( apszFailed[iError] );
+            CPLFree( apszFailed[iError] );
         }
     }
 
diff --git a/configure b/configure
index 095b79f..0b3e9bb 100755
--- a/configure
+++ b/configure
@@ -754,8 +754,13 @@ NETCDF_HAS_NC4
 NETCDF_ROOT
 NETCDF_SETTING
 NETCDF_NCCONFIG
+KEA_LIB
+KEA_INC
+HAVE_KEA
+KEA_CONFIG
 HDF5_INCLUDE
 HAVE_HDF5
+HDF4_HAS_MAXOPENFILES
 HDF4_INCLUDE
 HAVE_HDF4
 SOSI_INC
@@ -798,6 +803,8 @@ RENAME_INTERNAL_LIBTIFF_SYMBOLS
 HAVE_HIDE_INTERNAL_SYMBOLS
 HAVE_AVX_AT_COMPILE_TIME
 AVXFLAGS
+HAVE_SSE_AT_COMPILE_TIME
+SSEFLAGS
 HAVE_GCC_ATOMIC_BUILTINS
 HAVE_LIBTOOL
 SO_EXT
@@ -930,6 +937,7 @@ with_fme
 with_sosi
 with_hdf4
 with_hdf5
+with_kea
 with_netcdf
 with_jasper
 with_openjpeg
@@ -986,7 +994,6 @@ with_gdal_ver
 with_
 with_perl
 with_php
-with_ruby
 with_python
 with_java
 with_mdb
@@ -1670,6 +1677,7 @@ Optional Packages:
   --with-sosi=ARG        Include SOSI support (ARG=SOSI lib Path, yes or no)
   --with-hdf4=ARG       Include HDF4 support (ARG=path)
   --with-hdf5=ARG       Include HDF5 support (ARG=path)
+  --with-kea=ARG      Include kealib (ARG=path to kea-config) [default=yes]
   --with-netcdf=ARG     Include netCDF support (ARG=no or netCDF tree prefix)
   --with-jasper=ARG     Include JPEG-2000 support via JasPer library (ARG=path)
   --with-openjpeg=ARG     Include JPEG-2000 support via OpenJPEG 2.0 library (ARG=path)
@@ -1735,7 +1743,6 @@ Optional Packages:
   --with-macosx-framework         Build and install GDAL as a Mac OS X Framework
   --with-perl           Enable perl bindings
   --with-php            Enable php bindings
-  --with-ruby           Enable Ruby bindings
   --with-python=ARG   Enable python bindings (ARG=yes, no, or path to python binary)
   --with-java       Include Java support (ARG=yes, no or JDK home path)  [default=no]
   --with-mdb       Include MDB driver
@@ -6565,7 +6572,7 @@ linux* | k*bsd*-gnu | kopensolaris*-gnu)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
-netbsd*)
+netbsd* | netbsdelf*-gnu)
   if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
     lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
   else
@@ -9953,6 +9960,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
   openbsd*)
     with_gnu_ld=no
     ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs=no
+    ;;
   esac
 
   ld_shlibs=yes
@@ -10175,7 +10185,7 @@ _LT_EOF
       fi
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
 	wlarc=
@@ -10352,6 +10362,7 @@ _LT_EOF
 	if test "$aix_use_runtimelinking" = yes; then
 	  shared_flag="$shared_flag "'${wl}-G'
 	fi
+	link_all_deplibs=no
       else
 	# not using gcc
 	if test "$host_cpu" = ia64; then
@@ -10808,7 +10819,7 @@ $as_echo "$lt_cv_irix_exported_symbol" >&6; }
       link_all_deplibs=yes
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
       else
@@ -11661,6 +11672,7 @@ gnu*)
   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
   soname_spec='${libname}${release}${shared_ext}$major'
   shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
   ;;
 
@@ -11844,6 +11856,18 @@ fi
   dynamic_linker='GNU/Linux ld.so'
   ;;
 
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
 netbsd*)
   version_type=sunos
   need_lib_prefix=no
@@ -14678,7 +14702,7 @@ lt_prog_compiler_static_CXX=
 	    ;;
 	esac
 	;;
-      netbsd*)
+      netbsd* | netbsdelf*-gnu)
 	;;
       *qnx* | *nto*)
         # QNX uses GNU C++, but need to define -shared option too, otherwise
@@ -15047,6 +15071,9 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie
       ;;
     esac
     ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs_CXX=no
+    ;;
   *)
     export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
     ;;
@@ -15494,6 +15521,7 @@ gnu*)
   library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
   soname_spec='${libname}${release}${shared_ext}$major'
   shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
   hardcode_into_libs=yes
   ;;
 
@@ -15677,6 +15705,18 @@ fi
   dynamic_linker='GNU/Linux ld.so'
   ;;
 
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
 netbsd*)
   version_type=sunos
   need_lib_prefix=no
@@ -16880,13 +16920,21 @@ $as_echo "#define VSI_NEED_LARGEFILE64_SOURCE 1" >>confdefs.h
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
 
-    ac_fn_c_check_func "$LINENO" "stat64" "ac_cv_func_stat64"
+    case "${host_os}" in
+      darwin*)
+        VSI_STAT64=stat
+        VSI_STAT64_T=stat
+        ;;
+      *)
+        ac_fn_c_check_func "$LINENO" "stat64" "ac_cv_func_stat64"
 if test "x$ac_cv_func_stat64" = xyes; then :
   VSI_STAT64=stat64 VSI_STAT64_T=stat64
 else
   VSI_STAT64=stat VSI_STAT64_T=stat
 fi
 
+        ;;
+    esac
     ac_fn_c_check_func "$LINENO" "fopen64" "ac_cv_func_fopen64"
 if test "x$ac_cv_func_fopen64" = xyes; then :
   VSI_FOPEN64=fopen64
@@ -17417,13 +17465,13 @@ if test "$with_sse" = "yes" -o "$with_sse" = ""; then
     if test -z "`${CXX} ${CXXFLAGS} -o detectsse detectsse.cpp 2>&1`" ; then
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-        SSEFLAGS="-DHAVE_SSE_AT_COMPILE_TIME"
+        SSEFLAGS=""
         HAVE_SSE_AT_COMPILE_TIME=yes
     else
         if test -z "`${CXX} ${CXXFLAGS} -msse -o detectsse detectsse.cpp 2>&1`" ; then
             { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-            SSEFLAGS="-msse -DHAVE_SSE_AT_COMPILE_TIME"
+            SSEFLAGS="-msse"
             HAVE_SSE_AT_COMPILE_TIME=yes
         else
             { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
@@ -17457,17 +17505,17 @@ $as_echo "no" >&6; }
        esac
     fi
 
-    if test "$HAVE_SSE_AT_COMPILE_TIME" = "yes"; then
-      CFLAGS="$CFLAGS $SSEFLAGS"
-      CXXFLAGS="$CXXFLAGS $SSEFLAGS"
-    fi
-
     rm -f detectsse*
 else
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
+SSEFLAGS=$SSEFLAGS
+
+HAVE_SSE_AT_COMPILE_TIME=$HAVE_SSE_AT_COMPILE_TIME
+
+
 
 
 # Check whether --with-avx was given.
@@ -17732,6 +17780,49 @@ fi
 
   if test -n "$THREAD_FLAG" ; then
       THREAD_LIB="-lpthread"
+  else
+    # For Android, pthread_create is in Bionic libc
+    unset ac_cv_lib_pthread_pthread_create
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lc" >&5
+$as_echo_n "checking for pthread_create in -lc... " >&6; }
+if ${ac_cv_lib_c_pthread_create+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lc  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_c_pthread_create=yes
+else
+  ac_cv_lib_c_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_pthread_create" >&5
+$as_echo "$ac_cv_lib_c_pthread_create" >&6; }
+if test "x$ac_cv_lib_c_pthread_create" = xyes; then :
+  THREAD_FLAG=CPL_MULTIPROC_PTHREAD
+fi
+
   fi
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_MUTEX_RECURSIVE" >&5
@@ -17771,7 +17862,82 @@ $as_echo "no" >&6; }
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
-  PTHREAD_ENABLED="yes"
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_MUTEX_ADAPTIVE_NP" >&5
+$as_echo_n "checking for PTHREAD_MUTEX_ADAPTIVE_NP... " >&6; }
+
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+
+int
+main ()
+{
+
+    return PTHREAD_MUTEX_ADAPTIVE_NP;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_MUTEX_ADAPTIVE_NP 1
+_ACEOF
+
+
+else
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_spinlock_t" >&5
+$as_echo_n "checking for pthread_spinlock_t... " >&6; }
+
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define _GNU_SOURCE
+#include <pthread.h>
+
+int
+main ()
+{
+
+    pthread_spinlock_t spin;
+    return 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_PTHREAD_SPINLOCK 1
+_ACEOF
+
+
+else
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 elif test "$with_threads" != "no" ; then
 
@@ -17783,8 +17949,6 @@ $as_echo "$as_me: checking whether we should include thread/mutex support......"
   { $as_echo "$as_me:${as_lineno-$LINENO}: result:         using threads with link options \"$THREAD_LIB\"." >&5
 $as_echo "        using threads with link options \"$THREAD_LIB\"." >&6; }
 
-  PTHREAD_ENABLED="yes"
-
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we should include thread/mutex support......" >&5
 $as_echo "$as_me: checking whether we should include thread/mutex support......" >&6;}
@@ -17798,11 +17962,87 @@ cat >>confdefs.h <<_ACEOF
 #define CPL_MULTIPROC_PTHREAD 1
 _ACEOF
 
+  PTHREAD_ENABLED="yes"
 fi
 
 LIBS="$THREAD_LIB $LIBS"
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 5 args mremap()" >&5
+$as_echo_n "checking for 5 args mremap()... " >&6; }
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#define _GNU_SOURCE
+#include <sys/mman.h>
+
+int
+main ()
+{
+
+return (mremap(0,0,0,0,0));
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_5ARGS_MREMAP 1
+_ACEOF
+
+
+else
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for _SC_PHYS_PAGES" >&5
+$as_echo_n "checking for _SC_PHYS_PAGES... " >&6; }
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <unistd.h>
+
+int
+main ()
+{
+
+return (sysconf(_SC_PHYS_PAGES));
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SC_PHYS_PAGES 1
+_ACEOF
+
+
+else
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
 
 # Check whether --with-libz was given.
 if test "${with_libz+set}" = set; then :
@@ -21342,6 +21582,93 @@ fi
       LIBS="$HDF_LIB_NAME $ORIG_LIBS"
     fi
 
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SDget_maxopenfiles in -lmfhdfalt" >&5
+$as_echo_n "checking for SDget_maxopenfiles in -lmfhdfalt... " >&6; }
+if ${ac_cv_lib_mfhdfalt_SDget_maxopenfiles+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmfhdfalt $HDF_LIB_NAME $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SDget_maxopenfiles ();
+int
+main ()
+{
+return SDget_maxopenfiles ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_mfhdfalt_SDget_maxopenfiles=yes
+else
+  ac_cv_lib_mfhdfalt_SDget_maxopenfiles=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mfhdfalt_SDget_maxopenfiles" >&5
+$as_echo "$ac_cv_lib_mfhdfalt_SDget_maxopenfiles" >&6; }
+if test "x$ac_cv_lib_mfhdfalt_SDget_maxopenfiles" = xyes; then :
+  HDF4_HAS_MAXOPENFILES=yes
+else
+  HDF4_HAS_MAXOPENFILES=no
+fi
+
+    if test "$HDF4_HAS_MAXOPENFILES" = "no" ; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SDget_maxopenfiles in -lmfhdf" >&5
+$as_echo_n "checking for SDget_maxopenfiles in -lmfhdf... " >&6; }
+if ${ac_cv_lib_mfhdf_SDget_maxopenfiles+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmfhdf $HDF_LIB_NAME $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char SDget_maxopenfiles ();
+int
+main ()
+{
+return SDget_maxopenfiles ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_mfhdf_SDget_maxopenfiles=yes
+else
+  ac_cv_lib_mfhdf_SDget_maxopenfiles=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mfhdf_SDget_maxopenfiles" >&5
+$as_echo "$ac_cv_lib_mfhdf_SDget_maxopenfiles" >&6; }
+if test "x$ac_cv_lib_mfhdf_SDget_maxopenfiles" = xyes; then :
+  HDF4_HAS_MAXOPENFILES=yes
+else
+  HDF4_HAS_MAXOPENFILES=no
+fi
+
+    fi
+
       if test "$with_hdf4" = "yes" -o "$with_hdf4" = "" -a -r /usr/include/hdf/hdf.h ; then
       HDF4_INCLUDE="-I/usr/include/hdf"
     elif test -r "$with_hdf4/hdf/hdf.h" ; then
@@ -21373,6 +21700,8 @@ HAVE_HDF4=$HAVE_HDF4
 
 HDF4_INCLUDE=$HDF4_INCLUDE
 
+HDF4_HAS_MAXOPENFILES=$HDF4_HAS_MAXOPENFILES
+
 
 if test "$HAVE_HDF4" != "no" ; then
   OPT_GDAL_FORMATS="hdf4 $OPT_GDAL_FORMATS"
@@ -21531,6 +21860,105 @@ if test "$HAVE_HDF5" != "no" ; then
 fi
 
 
+KEA_CONFIG=no
+
+
+# Check whether --with-kea was given.
+if test "${with_kea+set}" = set; then :
+  withval=$with_kea;
+fi
+
+
+if test "$with_kea" = "yes" -o "x$with_kea" = "x" ; then
+  # Extract the first word of "kea-config", so it can be a program name with args.
+set dummy kea-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_KEA_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $KEA_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_KEA_CONFIG="$KEA_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_KEA_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_KEA_CONFIG" && ac_cv_path_KEA_CONFIG="no"
+  ;;
+esac
+fi
+KEA_CONFIG=$ac_cv_path_KEA_CONFIG
+if test -n "$KEA_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $KEA_CONFIG" >&5
+$as_echo "$KEA_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+else
+   KEA_CONFIG=$with_kea
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for kea" >&5
+$as_echo_n "checking for kea... " >&6; }
+
+if test "$KEA_CONFIG" = "no" ; then
+
+  HAVE_KEA=no
+  KEA_LIB=
+  KEA_INC=
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+  if test -d $KEA_CONFIG ; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+      as_fn_error $? "--with-kea argument is a directory.  It should be the path to the kea_config script, often somewhere like /usr/local/bin/kea_config." "$LINENO" 5
+  fi
+
+  if test \! -x $KEA_CONFIG ; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+      as_fn_error $? "--with-kea argument is a not an executable file.  It should be the path to the kea_config script, often somewhere like /usr/local/bin/kea_config." "$LINENO" 5
+  fi
+
+  HAVE_KEA=yes
+  KEA_LIB="`$KEA_CONFIG --libs --hdflibs`"
+  KEA_INC="`$KEA_CONFIG --cflags --hdfcflags`"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+
+HAVE_KEA=$HAVE_KEA
+
+KEA_INC=$KEA_INC
+
+KEA_LIB=$KEA_LIB
+
+
+if test "$HAVE_KEA" != "no" ; then
+  OPT_GDAL_FORMATS="kea $OPT_GDAL_FORMATS"
+fi
+
+
 NETCDF_SETTING=
 NETCDF_ROOT=
 NETCDF_HAS_NC4=
@@ -22528,22 +22956,24 @@ fi
       ECW_LIBS="-lecwj2 $CARBON_FRAMEWORK"
     fi
   fi
-  # ECWJP2 SDK 5.1 style
-  if test "$ECW_SETTING" = "no" ; then
-        if test -r /Intergraph/ERDASEcwJpeg2000SDK5.1/lib/libEcwJp2SDK.a; then
-                ECW_LIBDIR=/Intergraph/ERDASEcwJpeg2000SDK5.1/lib
-                ECW_INCLUDE=-I/Intergraph/ERDASEcwJpeg2000SDK5.1/include
-                ECW_LIBS="-L$ECW_LIBDIR -lEcwJp2SDK -framework Cocoa"
-                ECW_SETTING=yes
-                ECW_FLAGS="-DHAVE_ECW_BUILDNUMBER_H $ECW_FLAGS"
-                { $as_echo "$as_me:${as_lineno-$LINENO}: result: found Intergraph ERDAS EcwJpeg2000 SDK 5.1 in /Intergraph/ERDASEcwJpeg2000SDK5.1/." >&5
-$as_echo "found Intergraph ERDAS EcwJpeg2000 SDK 5.1 in /Intergraph/ERDASEcwJpeg2000SDK5.1/." >&6; }
-        fi
-  fi
 else
 
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libNCSEcw.so or libecwj2" >&5
-$as_echo_n "checking for libNCSEcw.so or libecwj2... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libNCSEcw.a or libecwj2" >&5
+$as_echo_n "checking for libNCSEcw.a or libecwj2... " >&6; }
+  ECW_ARCH=x86
+  ECW_CONF="release"
+  ECW_FLAGS="-DLINUX -DX86 -DPOSIX -DHAVE_COMPRESS -DECW_COMPRESS_RW_SDK_VERSION"
+  ECW_FRAMEWORK_COCOA=""
+  if test "`arch`" = "x86_64" ; then
+    ECW_ARCH="x64"
+  fi
+  if test ! -z "`uname | grep Darwin`" ; then
+    ECW_ARCH=""
+    ECW_CONF=""
+    ECW_FLAGS=""
+    ECW_FRAMEWORK_COCOA=" -framework Cocoa "
+  fi
+
   ECW_SETTING=yes
   if test -r $with_ecw/lib/libNCSCnet.so -o -r $with_ecw/lib/libNCSCnet.dylib ; then
     ECW_LIBS="-L$with_ecw/lib -lNCSEcw -lNCSEcwC -lNCSCnet -lNCSUtil"
@@ -22562,27 +22992,27 @@ $as_echo "found in $with_ecw/bin." >&6; }
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: found libecwj2 in $with_ecw/lib." >&5
 $as_echo "found libecwj2 in $with_ecw/lib." >&6; }
 
-  # ECW SDK 5.0 style
-  elif test -r $with_ecw/lib/x64/release/libNCSEcw.so ; then
-    if test `arch` == "x86_64" ; then
-      ECW_LIBDIR=$with_ecw/lib/x64/release
-    else
-      ECW_LIBDIR=$with_ecw/lib/x86/release
-    fi
-    ECW_FLAGS="-DLINUX -DX86 -DPOSIX -DHAVE_COMPRESS -DECW_COMPRESS_RW_SDK_VERSION"
-    ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw"
+  # ECW SDK 5.0 style and also for the case where license type is included in path i.e. specific license type is requested.
+  elif test -r $with_ecw/lib/$ECW_ARCH/$ECW_CONF/libNCSEcw.a ; then
+    ECW_LIBDIR=$with_ecw/lib/$ECW_ARCH/$ECW_CONF
+    ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw $ECW_FRAMEWORK_COCOA"
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: found Intergraph 5.x+ SDK in ${ECW_LIBDIR}." >&5
 $as_echo "found Intergraph 5.x+ SDK in ${ECW_LIBDIR}." >&6; }
  # ECWJP2 SDK 5.1 style
-  elif test -r $with_ecw/lib/libEcwJp2SDK.a; then
-        ECW_LIBDIR=$with_ecw/lib
-        ECW_INCLUDE=-I$with_ecw/include
-        ECW_LIBS="-L$ECW_LIBDIR -lEcwJp2SDK -framework Cocoa"
-        ECW_FLAGS="-DHAVE_ECW_BUILDNUMBER_H $ECW_FLAGS"
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: found Intergraph 5.1+ SDK in $ {with_ecw}." >&5
-$as_echo "found Intergraph 5.1+ SDK in $ {with_ecw}." >&6; }
+  elif test -d $with_ecw; then
+    for ecw_license_type in "Desktop_Read-Write" "Server_Read-Only_EndUser" "Server_Read-Only" "Server_Read-Write" "Desktop_Read-Only"
+      do
+        ECW_LIBDIR=$with_ecw/$ecw_license_type/lib/$ECW_ARCH/$ECW_CONF
+        if test -r $ECW_LIBDIR/libNCSEcw.a; then
+          ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw $ECW_FRAMEWORK_COCOA"
+          with_ecw=$with_ecw/$ecw_license_type
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: found Intergraph 5.x+ SDK in ${ECW_LIBDIR}." >&5
+$as_echo "found Intergraph 5.x+ SDK in ${ECW_LIBDIR}." >&6; }
+          break
+        fi
+      done
  else
-    as_fn_error $? "not found in $with_ecw/lib or $with_ecw/bin." "$LINENO" 5
+    as_fn_error $? "not found in $with_ecw." "$LINENO" 5
   fi
 
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NCSECWClient.h in $with_ecw/include" >&5
@@ -25094,7 +25524,7 @@ if test "$CURL_SETTING" = "yes" ; then
 
   CURL_INC=`$LIBCURL_CONFIG --cflags`
   CURL_LIB=`$LIBCURL_CONFIG --libs`
-  OPT_GDAL_FORMATS="wcs wms $OPT_GDAL_FORMATS"
+  OPT_GDAL_FORMATS="wcs wms plmosaic $OPT_GDAL_FORMATS"
 
 fi
 
@@ -28433,22 +28863,6 @@ fi
 
 
 
-# Check whether --with-ruby was given.
-if test "${with_ruby+set}" = set; then :
-  withval=$with_ruby;
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ruby bindings" >&5
-$as_echo_n "checking for ruby bindings... " >&6; }
-if test "$with_ruby" = "yes" ; then
-  BINDINGS="ruby $BINDINGS"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: enabled" >&5
-$as_echo "enabled" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-$as_echo "disabled" >&6; }
-fi
 
 
 
@@ -29124,20 +29538,28 @@ if test "$with_armadillo" = "yes" ; then
     rm -f testarmadillo
     echo '#include <armadillo>' > testarmadillo.cpp
     echo 'int main(int argc, char** argv) { arma::mat matInput(2,2); const arma::mat& matInv = arma::inv(matInput); return 0; } ' >> testarmadillo.cpp
-    if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo ${LIBS} 2>&1`" ; then
+    if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo 2>&1`" ; then
         HAVE_ARMADILLO=yes
         LIBS="-larmadillo ${LIBS}"
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
     else
-                if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -llapack ${LIBS} 2>&1`" ; then
+                if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -llapack 2>&1`" ; then
             HAVE_ARMADILLO=yes
             LIBS="-larmadillo -llapack ${LIBS}"
             { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
         else
-            { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+            # clang 3.4 needs linking against libstdc++ (ubuntu 14.04)
+            if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -lstdc++ 2>&1`" ; then
+                HAVE_ARMADILLO=yes
+                LIBS="-larmadillo -lstdc++ ${LIBS}"
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+            else
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
+            fi
         fi
     fi
     rm -f testarmadillo.*
@@ -29149,14 +29571,14 @@ elif test -n "$with_armadillo" -a "$with_armadillo" != "no" ; then
     rm -f testarmadillo
     echo '#include <armadillo>' > testarmadillo.cpp
     echo 'int main(int argc, char** argv) { arma::mat matInput(2,2); const arma::mat& matInv = arma::inv(matInput); return 0; } ' >> testarmadillo.cpp
-    if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo ${LIBS} 2>&1`" ; then
+    if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo 2>&1`" ; then
         HAVE_ARMADILLO=yes
         LIBS="-L$with_armadillo/lib -larmadillo ${LIBS}"
         EXTRA_INCLUDES="-I$with_armadillo/include $EXTRA_INCLUDES"
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
     else
-                if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo -llapack ${LIBS} 2>&1`" ; then
+                if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo -llapack 2>&1`" ; then
             HAVE_ARMADILLO=yes
             LIBS="-L$with_armadillo/lib -larmadillo -llapack ${LIBS}"
             EXTRA_INCLUDES="-I$with_armadillo/include $EXTRA_INCLUDES"
@@ -31652,6 +32074,9 @@ echo "  HDF4 support:              ${HAVE_HDF4}"
 echo "  HDF5 support:              ${HAVE_HDF5}"
 
 
+echo "  Kea support:               ${HAVE_KEA}"
+
+
 echo "  NetCDF support:            ${NETCDF_SETTING}"
 
 
diff --git a/configure.in b/configure.in
index f1e85d2..86919a3 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
 dnl ***************************************************************************
-dnl $Id: configure.in 28317 2015-01-15 22:49:41Z tamas $
+dnl $Id: configure.in 28874 2015-04-08 15:10:44Z dron $
 dnl
 dnl Project:  GDAL
 dnl Purpose:  Configure source file.
@@ -240,12 +240,12 @@ if test "$with_sse" = "yes" -o "$with_sse" = ""; then
     echo '#endif' >> detectsse.cpp
     if test -z "`${CXX} ${CXXFLAGS} -o detectsse detectsse.cpp 2>&1`" ; then
         AC_MSG_RESULT([yes])
-        SSEFLAGS="-DHAVE_SSE_AT_COMPILE_TIME"
+        SSEFLAGS=""
         HAVE_SSE_AT_COMPILE_TIME=yes
     else
         if test -z "`${CXX} ${CXXFLAGS} -msse -o detectsse detectsse.cpp 2>&1`" ; then
             AC_MSG_RESULT([yes])
-            SSEFLAGS="-msse -DHAVE_SSE_AT_COMPILE_TIME"
+            SSEFLAGS="-msse"
             HAVE_SSE_AT_COMPILE_TIME=yes
         else
             AC_MSG_RESULT([no])
@@ -279,16 +279,14 @@ if test "$with_sse" = "yes" -o "$with_sse" = ""; then
        esac
     fi
 
-    if test "$HAVE_SSE_AT_COMPILE_TIME" = "yes"; then
-      CFLAGS="$CFLAGS $SSEFLAGS"
-      CXXFLAGS="$CXXFLAGS $SSEFLAGS"
-    fi
-
     rm -f detectsse*
 else
     AC_MSG_RESULT([no])
 fi
 
+AC_SUBST(SSEFLAGS,$SSEFLAGS)
+AC_SUBST(HAVE_SSE_AT_COMPILE_TIME,$HAVE_SSE_AT_COMPILE_TIME)
+
 dnl ---------------------------------------------------------------------------
 dnl Check AVX availability
 dnl ---------------------------------------------------------------------------
@@ -485,6 +483,10 @@ if test "$with_threads" = "yes" -o "$with_threads" = "" ; then
 
   if test -n "$THREAD_FLAG" ; then
       THREAD_LIB="-lpthread"
+  else
+    # For Android, pthread_create is in Bionic libc
+    unset ac_cv_lib_pthread_pthread_create
+    AC_CHECK_LIB(c,pthread_create,THREAD_FLAG=CPL_MULTIPROC_PTHREAD,,,)
   fi
 
   AC_MSG_CHECKING([for PTHREAD_MUTEX_RECURSIVE])
@@ -504,7 +506,42 @@ if test "$with_threads" = "yes" -o "$with_threads" = "" ; then
     AC_MSG_RESULT([no])
   ])
 
-  PTHREAD_ENABLED="yes"
+
+
+  AC_MSG_CHECKING([for PTHREAD_MUTEX_ADAPTIVE_NP])
+
+  AC_TRY_COMPILE(
+  [
+#define _GNU_SOURCE
+#include <pthread.h>
+  ], [
+    return PTHREAD_MUTEX_ADAPTIVE_NP;
+  ],
+  [
+    AC_MSG_RESULT([yes])
+    AC_DEFINE_UNQUOTED(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP, 1,
+          [Define to 1 if you have the `PTHREAD_MUTEX_ADAPTIVE_NP' constant.])
+  ], [
+    AC_MSG_RESULT([no])
+  ])
+
+  AC_MSG_CHECKING([for pthread_spinlock_t])
+
+  AC_TRY_COMPILE(
+  [
+#define _GNU_SOURCE
+#include <pthread.h>
+  ], [
+    pthread_spinlock_t spin;
+    return 1;
+  ],
+  [
+    AC_MSG_RESULT([yes])
+    AC_DEFINE_UNQUOTED(HAVE_PTHREAD_SPINLOCK, 1,
+          [Define to 1 if you have the `pthread_spinlock_t' type.])
+  ], [
+    AC_MSG_RESULT([no])
+  ])
 
 elif test "$with_threads" != "no" ; then
 
@@ -514,8 +551,6 @@ elif test "$with_threads" != "no" ; then
   AC_CHECKING(whether we should include thread/mutex support...)
   AC_MSG_RESULT([        using threads with link options "$THREAD_LIB".])
 
-  PTHREAD_ENABLED="yes"
-
 else
   AC_CHECKING(whether we should include thread/mutex support...)
   AC_MSG_RESULT([        thread safe support disabled.])
@@ -523,11 +558,53 @@ fi
 
 if test "$THREAD_FLAG" = "CPL_MULTIPROC_PTHREAD" ; then
   AC_DEFINE_UNQUOTED(CPL_MULTIPROC_PTHREAD,1, [Define if you want to use pthreads based multiprocessing support])
+  PTHREAD_ENABLED="yes"
 fi
 
 LIBS="$THREAD_LIB $LIBS" 
 
 dnl ---------------------------------------------------------------------------
+dnl Check if mremap() with 5 args is available
+dnl ---------------------------------------------------------------------------
+
+AC_MSG_CHECKING([for 5 args mremap()])
+
+AC_TRY_COMPILE(
+[
+#define _GNU_SOURCE
+#include <sys/mman.h>
+], [
+return (mremap(0,0,0,0,0));
+],
+[
+AC_MSG_RESULT([yes])
+AC_DEFINE_UNQUOTED(HAVE_5ARGS_MREMAP, 1,
+        [Define to 1 if you have the 5 args `mremap' function.])
+], [
+AC_MSG_RESULT([no])
+])
+
+dnl ---------------------------------------------------------------------------
+dnl Check if _SC_PHYS_PAGES is available
+dnl ---------------------------------------------------------------------------
+
+AC_MSG_CHECKING([for _SC_PHYS_PAGES])
+
+AC_TRY_COMPILE(
+[
+#include <unistd.h>
+], [
+return (sysconf(_SC_PHYS_PAGES));
+],
+[
+AC_MSG_RESULT([yes])
+AC_DEFINE_UNQUOTED(HAVE_SC_PHYS_PAGES, 1,
+        [Define to 1 if you have the _SC_PHYS_PAGES' constant.])
+], [
+AC_MSG_RESULT([no])
+])
+
+dnl ---------------------------------------------------------------------------
 dnl Check if libz is available.
 dnl ---------------------------------------------------------------------------
 
@@ -1593,6 +1670,14 @@ dnl Not found... again, with -lsz.
       LIBS="$HDF_LIB_NAME $ORIG_LIBS"
     fi
 
+    dnl HDF4 library newer than 4.2.5 has a SDreset_maxopenfiles/SDget_maxopenfiles interface
+    dnl which allows to open many HDF files simultaneously (the max number of files was previously
+    dnl hardcoded and too low, smth. like 32). Search for it and use if available.
+    AC_CHECK_LIB(mfhdfalt,SDget_maxopenfiles,HDF4_HAS_MAXOPENFILES=yes,HDF4_HAS_MAXOPENFILES=no,$HDF_LIB_NAME)
+    if test "$HDF4_HAS_MAXOPENFILES" = "no" ; then
+      AC_CHECK_LIB(mfhdf,SDget_maxopenfiles,HDF4_HAS_MAXOPENFILES=yes,HDF4_HAS_MAXOPENFILES=no,$HDF_LIB_NAME)
+    fi
+
   dnl Now search for headers
     if test "$with_hdf4" = "yes" -o "$with_hdf4" = "" -a -r /usr/include/hdf/hdf.h ; then
       HDF4_INCLUDE="-I/usr/include/hdf"
@@ -1623,6 +1708,7 @@ fi
 
 AC_SUBST(HAVE_HDF4,$HAVE_HDF4)
 AC_SUBST(HDF4_INCLUDE,$HDF4_INCLUDE)
+AC_SUBST(HDF4_HAS_MAXOPENFILES,$HDF4_HAS_MAXOPENFILES)
 
 if test "$HAVE_HDF4" != "no" ; then
   OPT_GDAL_FORMATS="hdf4 $OPT_GDAL_FORMATS"
@@ -1697,6 +1783,55 @@ if test "$HAVE_HDF5" != "no" ; then
 fi
 
 dnl ---------------------------------------------------------------------------
+dnl Check if kealib library is available.
+dnl ---------------------------------------------------------------------------
+
+KEA_CONFIG=no
+
+AC_ARG_WITH(kea,[  --with-kea[=ARG]      Include kealib (ARG=path to kea-config) [[default=yes]]],,)
+
+if test "$with_kea" = "yes" -o "x$with_kea" = "x" ; then
+  AC_PATH_PROG(KEA_CONFIG, kea-config, no)
+else
+   KEA_CONFIG=$with_kea
+fi
+
+AC_MSG_CHECKING([for kea])
+
+if test "$KEA_CONFIG" = "no" ; then
+
+  HAVE_KEA=no
+  KEA_LIB=
+  KEA_INC=
+
+  AC_MSG_RESULT([no])
+
+else
+  if test -d $KEA_CONFIG ; then
+      AC_MSG_RESULT([no])
+      AC_MSG_ERROR([--with-kea argument is a directory.  It should be the path to the kea_config script, often somewhere like /usr/local/bin/kea_config.])
+  fi
+
+  if test \! -x $KEA_CONFIG ; then
+      AC_MSG_RESULT([no])
+      AC_MSG_ERROR([--with-kea argument is a not an executable file.  It should be the path to the kea_config script, often somewhere like /usr/local/bin/kea_config.])
+  fi
+
+  HAVE_KEA=yes
+  KEA_LIB="`$KEA_CONFIG --libs --hdflibs`"
+  KEA_INC="`$KEA_CONFIG --cflags --hdfcflags`"
+  AC_MSG_RESULT([yes]) 
+fi
+
+AC_SUBST(HAVE_KEA,$HAVE_KEA)
+AC_SUBST(KEA_INC,$KEA_INC)
+AC_SUBST(KEA_LIB,$KEA_LIB)
+
+if test "$HAVE_KEA" != "no" ; then
+  OPT_GDAL_FORMATS="kea $OPT_GDAL_FORMATS"
+fi
+
+dnl ---------------------------------------------------------------------------
 dnl Check if netcdf library is available.
 dnl ---------------------------------------------------------------------------
 
@@ -2070,20 +2205,23 @@ elif test "$with_ecw" = "yes" -o "$with_ecw" = "" ; then
       ECW_LIBS="-lecwj2 $CARBON_FRAMEWORK"
     fi
   fi
-  # ECWJP2 SDK 5.1 style
-  if test "$ECW_SETTING" = "no" ; then
-        if test -r /Intergraph/ERDASEcwJpeg2000SDK5.1/lib/libEcwJp2SDK.a; then
-                ECW_LIBDIR=/Intergraph/ERDASEcwJpeg2000SDK5.1/lib
-                ECW_INCLUDE=-I/Intergraph/ERDASEcwJpeg2000SDK5.1/include
-                ECW_LIBS="-L$ECW_LIBDIR -lEcwJp2SDK -framework Cocoa"
-                ECW_SETTING=yes
-                ECW_FLAGS="-DHAVE_ECW_BUILDNUMBER_H $ECW_FLAGS"
-                AC_MSG_RESULT([found Intergraph ERDAS EcwJpeg2000 SDK 5.1 in /Intergraph/ERDASEcwJpeg2000SDK5.1/.])
-        fi
-  fi
 else
 
-  AC_MSG_CHECKING([for libNCSEcw.so or libecwj2])
+  AC_MSG_CHECKING([for libNCSEcw.a or libecwj2])
+  ECW_ARCH=x86
+  ECW_CONF="release"
+  ECW_FLAGS="-DLINUX -DX86 -DPOSIX -DHAVE_COMPRESS -DECW_COMPRESS_RW_SDK_VERSION"
+  ECW_FRAMEWORK_COCOA=""
+  if test "`arch`" = "x86_64" ; then 
+    ECW_ARCH="x64"
+  fi
+  if test ! -z "`uname | grep Darwin`" ; then
+    ECW_ARCH=""
+    ECW_CONF=""
+    ECW_FLAGS=""
+    ECW_FRAMEWORK_COCOA=" -framework Cocoa "
+  fi
+  
   ECW_SETTING=yes
   if test -r $with_ecw/lib/libNCSCnet.so -o -r $with_ecw/lib/libNCSCnet.dylib ; then
     ECW_LIBS="-L$with_ecw/lib -lNCSEcw -lNCSEcwC -lNCSCnet -lNCSUtil"
@@ -2098,25 +2236,25 @@ else
     ECW_LIBS="-L$with_ecw/lib -lecwj2 $CARBON_FRAMEWORK"
     AC_MSG_RESULT([found libecwj2 in $with_ecw/lib.])
 
-  # ECW SDK 5.0 style
-  elif test -r $with_ecw/lib/x64/release/libNCSEcw.so ; then
-    if test `arch` == "x86_64" ; then
-      ECW_LIBDIR=$with_ecw/lib/x64/release
-    else
-      ECW_LIBDIR=$with_ecw/lib/x86/release
-    fi
-    ECW_FLAGS="-DLINUX -DX86 -DPOSIX -DHAVE_COMPRESS -DECW_COMPRESS_RW_SDK_VERSION"
-    ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw"
+  # ECW SDK 5.0 style and also for the case where license type is included in path i.e. specific license type is requested.
+  elif test -r $with_ecw/lib/$ECW_ARCH/$ECW_CONF/libNCSEcw.a ; then
+    ECW_LIBDIR=$with_ecw/lib/$ECW_ARCH/$ECW_CONF
+    ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw $ECW_FRAMEWORK_COCOA"
     AC_MSG_RESULT([found Intergraph 5.x+ SDK in ${ECW_LIBDIR}.])
  # ECWJP2 SDK 5.1 style
-  elif test -r $with_ecw/lib/libEcwJp2SDK.a; then
-        ECW_LIBDIR=$with_ecw/lib
-        ECW_INCLUDE=-I$with_ecw/include
-        ECW_LIBS="-L$ECW_LIBDIR -lEcwJp2SDK -framework Cocoa"
-        ECW_FLAGS="-DHAVE_ECW_BUILDNUMBER_H $ECW_FLAGS"
-        AC_MSG_RESULT([found Intergraph 5.1+ SDK in $ {with_ecw}.]) 
+  elif test -d $with_ecw; then
+    for ecw_license_type in "Desktop_Read-Write" "Server_Read-Only_EndUser" "Server_Read-Only" "Server_Read-Write" "Desktop_Read-Only"
+      do
+        ECW_LIBDIR=$with_ecw/$ecw_license_type/lib/$ECW_ARCH/$ECW_CONF
+        if test -r $ECW_LIBDIR/libNCSEcw.a; then
+          ECW_LIBS="-L$ECW_LIBDIR -lNCSEcw $ECW_FRAMEWORK_COCOA"
+          with_ecw=$with_ecw/$ecw_license_type
+          AC_MSG_RESULT([found Intergraph 5.x+ SDK in ${ECW_LIBDIR}.])
+          break
+        fi
+      done
  else
-    AC_MSG_ERROR([not found in $with_ecw/lib or $with_ecw/bin.])
+    AC_MSG_ERROR([not found in $with_ecw.])
   fi
 
   AC_MSG_CHECKING([for NCSECWClient.h in $with_ecw/include])
@@ -2783,7 +2921,7 @@ if test "$CURL_SETTING" = "yes" ; then
   
   CURL_INC=`$LIBCURL_CONFIG --cflags`
   CURL_LIB=`$LIBCURL_CONFIG --libs`
-  OPT_GDAL_FORMATS="wcs wms $OPT_GDAL_FORMATS"
+  OPT_GDAL_FORMATS="wcs wms plmosaic $OPT_GDAL_FORMATS"
 
 fi
 
@@ -3855,15 +3993,15 @@ dnl ---------------------------------------------------------------------------
 dnl Ruby bindings.
 dnl ---------------------------------------------------------------------------
 
-AC_ARG_WITH(ruby,[  --with-ruby           Enable Ruby bindings],,)
+dnl AC_ARG_WITH(ruby,[  --with-ruby           Enable Ruby bindings],,)
 
-AC_MSG_CHECKING([for ruby bindings])
-if test "$with_ruby" = "yes" ; then
-  BINDINGS="ruby $BINDINGS"
-  AC_MSG_RESULT([enabled])
-else
-  AC_MSG_RESULT([disabled])
-fi
+dnl AC_MSG_CHECKING([for ruby bindings])
+dnl if test "$with_ruby" = "yes" ; then
+dnl   BINDINGS="ruby $BINDINGS"
+dnl   AC_MSG_RESULT([enabled])
+dnl else
+dnl   AC_MSG_RESULT([disabled])
+dnl fi
 
 dnl ---------------------------------------------------------------------------
 dnl NG Python bindings.
@@ -4214,18 +4352,25 @@ if test "$with_armadillo" = "yes" ; then
     rm -f testarmadillo
     echo '#include <armadillo>' > testarmadillo.cpp
     echo 'int main(int argc, char** argv) { arma::mat matInput(2,2); const arma::mat& matInv = arma::inv(matInput); return 0; } ' >> testarmadillo.cpp
-    if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo ${LIBS} 2>&1`" ; then
+    if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo 2>&1`" ; then
         HAVE_ARMADILLO=yes
         LIBS="-larmadillo ${LIBS}"
         AC_MSG_RESULT([yes])
     else
         dnl Try adding -llapack (#4923)
-        if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -llapack ${LIBS} 2>&1`" ; then
+        if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -llapack 2>&1`" ; then
             HAVE_ARMADILLO=yes
             LIBS="-larmadillo -llapack ${LIBS}"
             AC_MSG_RESULT([yes])
         else
-            AC_MSG_RESULT([no])
+            # clang 3.4 needs linking against libstdc++ (ubuntu 14.04)
+            if test -z "`${CXX} ${CPPFLAGS} testarmadillo.cpp -o testarmadillo -larmadillo -lstdc++ 2>&1`" ; then
+                HAVE_ARMADILLO=yes
+                LIBS="-larmadillo -lstdc++ ${LIBS}"
+                AC_MSG_RESULT([yes])
+            else
+                AC_MSG_RESULT([no])
+            fi
         fi
     fi
     rm -f testarmadillo.*
@@ -4237,14 +4382,14 @@ elif test -n "$with_armadillo" -a "$with_armadillo" != "no" ; then
     rm -f testarmadillo
     echo '#include <armadillo>' > testarmadillo.cpp
     echo 'int main(int argc, char** argv) { arma::mat matInput(2,2); const arma::mat& matInv = arma::inv(matInput); return 0; } ' >> testarmadillo.cpp
-    if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo ${LIBS} 2>&1`" ; then
+    if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo 2>&1`" ; then
         HAVE_ARMADILLO=yes
         LIBS="-L$with_armadillo/lib -larmadillo ${LIBS}"
         EXTRA_INCLUDES="-I$with_armadillo/include $EXTRA_INCLUDES"
         AC_MSG_RESULT([yes])
     else
         dnl Try adding -llapack (#4923)
-        if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo -llapack ${LIBS} 2>&1`" ; then
+        if test -z "`${CXX} ${CPPFLAGS} -I$with_armadillo/include testarmadillo.cpp -o testarmadillo -L$with_armadillo/lib -larmadillo -llapack 2>&1`" ; then
             HAVE_ARMADILLO=yes
             LIBS="-L$with_armadillo/lib -larmadillo -llapack ${LIBS}"
             EXTRA_INCLUDES="-I$with_armadillo/include $EXTRA_INCLUDES"
@@ -4295,6 +4440,7 @@ LOC_MSG([  LIBGIF support:            ${GIF_SETTING}])
 LOC_MSG([  OGDI support:              ${HAVE_OGDI}])
 LOC_MSG([  HDF4 support:              ${HAVE_HDF4}])
 LOC_MSG([  HDF5 support:              ${HAVE_HDF5}])
+LOC_MSG([  Kea support:               ${HAVE_KEA}])
 LOC_MSG([  NetCDF support:            ${NETCDF_SETTING}])
 LOC_MSG([  Kakadu support:            ${HAVE_KAKADU}])
 if test "x$HAVE_JASPER_UUID" != "x" ; then
diff --git a/data/GDALLogoBW.svg b/data/GDALLogoBW.svg
index b7a16a6..4ac8f6a 100644
--- a/data/GDALLogoBW.svg
+++ b/data/GDALLogoBW.svg
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
-	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
-	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
 ]>
-<svg  version="1.1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="575" height="637.203" viewBox="0 0 575 637.203"
+<svg  version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="575" height="637.203" viewBox="0 0 575 637.203"
 	 overflow="visible" enable-background="new 0 0 575 637.203" xml:space="preserve">
 <g id="Layer_5">
 </g>
diff --git a/data/GDALLogoColor.svg b/data/GDALLogoColor.svg
index 7ae13ef..da311ad 100644
--- a/data/GDALLogoColor.svg
+++ b/data/GDALLogoColor.svg
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
-	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
-	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
 ]>
-<svg  version="1.1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="571.5" height="632.057" viewBox="0 0 571.5 632.057"
+<svg  version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="571.5" height="632.057" viewBox="0 0 571.5 632.057"
 	 overflow="visible" enable-background="new 0 0 571.5 632.057" xml:space="preserve">
 <g id="Layer_5">
 </g>
diff --git a/data/GDALLogoGS.svg b/data/GDALLogoGS.svg
index 8a5cad9..de00b72 100644
--- a/data/GDALLogoGS.svg
+++ b/data/GDALLogoGS.svg
@@ -1,10 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448)  -->
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
-	<!ENTITY ns_svg "http://www.w3.org/2000/svg">
-	<!ENTITY ns_xlink "http://www.w3.org/1999/xlink">
 ]>
-<svg  version="1.1" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="571.5" height="632.057" viewBox="0 0 571.5 632.057"
+<svg  version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="571.5" height="632.057" viewBox="0 0 571.5 632.057"
 	 overflow="visible" enable-background="new 0 0 571.5 632.057" xml:space="preserve">
 <g id="Layer_5">
 </g>
diff --git a/data/compdcs.csv b/data/compdcs.csv
index 7779ec9..0ab7840 100644
--- a/data/compdcs.csv
+++ b/data/compdcs.csv
@@ -103,6 +103,28 @@
 6175,"ETRS89 / UTM zone 35 + NN54 height",25835,5776,1,0
 6176,"ETRS89 / UTM zone 36 + NN54 height",25836,5776,1,0
 6190,"Belge 1972 / Belgian Lambert 72 + Ostend height",31370,5710,1,0
+6349,"NAD83(2011) + NAVD88 height",6318,5703,1,0
+6649,"NAD83(CSRS) + CGVD2013 height",4617,6647,1,0
+6650,"NAD83(CSRS) / UTM zone 7N + CGVD2013 height",3154,6647,1,0
+6651,"NAD83(CSRS) / UTM zone 8N + CGVD2013 height",3155,6647,1,0
+6652,"NAD83(CSRS) / UTM zone 9N + CGVD2013 height",3156,6647,1,0
+6653,"NAD83(CSRS) / UTM zone 10N + CGVD2013 height",3157,6647,1,0
+6654,"NAD83(CSRS) / UTM zone 11N + CGVD2013 height",2955,6647,1,0
+6655,"NAD83(CSRS) / UTM zone 12N + CGVD2013 height",2956,6647,1,0
+6656,"NAD83(CSRS) / UTM zone 13N + CGVD2013 height",2957,6647,1,0
+6657,"NAD83(CSRS) / UTM zone 14N + CGVD2013 height",3158,6647,1,0
+6658,"NAD83(CSRS) / UTM zone 15N + CGVD2013 height",3159,6647,1,0
+6659,"NAD83(CSRS) / UTM zone 16N + CGVD2013 height",3160,6647,1,0
+6660,"NAD83(CSRS) / UTM zone 17N + CGVD2013 height",2958,6647,1,0
+6661,"NAD83(CSRS) / UTM zone 18N + CGVD2013 height",2959,6647,1,0
+6662,"NAD83(CSRS) / UTM zone 19N + CGVD2013 height",2960,6647,1,0
+6663,"NAD83(CSRS) / UTM zone 20N + CGVD2013 height",2961,6647,1,0
+6664,"NAD83(CSRS) / UTM zone 21N + CGVD2013 height",2962,6647,1,0
+6665,"NAD83(CSRS) / UTM zone 22N + CGVD2013 height",3761,6647,1,0
+6696,"JGD2000 + JGD2000 (vertical) height",4612,6694,1,0
+6697,"JGD2011 + JGD2011 (vertical) height",6668,6695,1,0
+6700,"Tokyo + JSLD72 height",4301,6693,1,0
+6871,"WGS 84 / Pseudo-Mercator +  EGM2008 geoid height",3857,3855,1,0
 7400,"NTF (Paris) + NGF IGN69 height",4807,5720,1,0
 7401,"NTF (Paris) / France II + NGF Lallemand",27582,5719,1,1
 7402,"NTF (Paris) / France II + NGF IGN69",27582,5720,1,1
@@ -117,7 +139,7 @@
 7411,"NTF (Paris) / Lambert zone II + NGF Lallemand height",27572,5719,1,0
 7412,"NTF (Paris) / Lambert zone II + NGF IGN69",27572,5719,1,1
 7413,"NTF (Paris) / Lambert zone III + NGF IGN69",27573,5719,1,1
-7414,"Tokyo + JSLD height",4301,5723,1,0
+7414,"Tokyo + JSLD69 height",4301,5723,1,0
 7415,"Amersfoort / RD New + NAP height",28992,5709,1,0
 7416,"ETRS89 / UTM zone 32N + DVR90 height",25832,5799,1,0
 7417,"ETRS89 / UTM zone 33N + DVR90 height",25833,5799,1,0
diff --git a/data/coordinate_axis.csv b/data/coordinate_axis.csv
index be6b073..12ca0ed 100644
--- a/data/coordinate_axis.csv
+++ b/data/coordinate_axis.csv
@@ -31,6 +31,7 @@ coord_sys_code,coord_axis_name_code,coord_axis_orientation,coord_axis_abbreviati
 1038,9907,South along 75°W,Y,9001,2
 1039,9906,east,E,9002,1
 1039,9907,north,N,9002,2
+1043,9905,down,D,9003,1
 4400,9906,east,E,9001,1
 4400,9907,north,N,9001,2
 4401,9906,east,E,9062,1
diff --git a/data/datum_shift.csv b/data/datum_shift.csv
index b903c34..baca1f3 100644
--- a/data/datum_shift.csv
+++ b/data/datum_shift.csv
@@ -1,776 +1,784 @@
 "SEQ_KEY","COORD_OP_CODE","SOURCE_CRS_CODE","TARGET_CRS_CODE","REMARKS","COORD_OP_SCOPE","AREA_OF_USE_CODE","AREA_SOUTH_BOUND_LAT","AREA_NORTH_BOUND_LAT","AREA_WEST_BOUND_LON","AREA_EAST_BOUND_LON","SHOW_OPERATION","DEPRECATED","COORD_OP_METHOD_CODE","DX","DY","DZ","RX","RY","RZ","DS","PREFERRED"
-1,1825,4611,4326,Published 1st March 2002.,Accuracy to 1m level.,1118,22.14,22.57,113.77,114.5,1,0,9606,-162.619,-276.959,-161.764,0.067753,-2.243649,-1.158827,-1.094246,1
-2,1826,4612,4326,,"Approximation at the +/- 1m level.",1129,17.09,46.05,122.38,157.64,1,0,9603,0,0,0,,,,,1
-3,1838,4613,4326,Datum shift derived through ITRF93.,Oil exploration.,1328,-1.24,0,116.73,117.99,1,0,9603,-404.78,685.68,45.47,,,,,0
-4,1897,4613,4326,Accuracy estimate not available.,For military purposes.,1360,-4.23,4.29,114.56,119.06,1,0,9603,-403,684,41,,,,,1
-5,1898,4613,4326,,Oil exploration.,1359,-4.23,0,114.56,117.99,1,0,9603,-387.06,636.53,46.29,,,,,0
-6,1899,4613,4326,,Oil exploration.,2770,-0.07,4.29,116.97,119.06,1,0,9603,-403.4,681.12,46.56,,,,,0
-7,1840,4614,4326,"Transformation defines QND95. May be approximated to 1m throughout Qatar by geocentric translation transformation with dX=-127.78098m, dY=-283.37477m, dZ=+21.24081m.",Parameter values are defined and therefore exact.,1346,24.56,26.2,50.7,51.67,1,0,9606,-119.4248,-303.65872,-11.00061,1.164298,0.174458,1.096259,3.657065,1
-8,1888,4615,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,1314,32.36,33.14,-17.3,-16.23,1,0,9603,-499,-249,314,,,,,1
-9,1889,4616,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,2779,29.98,30.2,-16.1,-15.79,1,1,9603,-289,-124,60,,,,,0
-10,1965,4616,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,2779,29.98,30.2,-16.1,-15.79,1,0,9603,-289,-124,60,,,,,1
-11,1842,4617,4326,"For many purposes NAD83(CSRS) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(CSRS) is equivalent to WGS 84.",1061,40.04,86.45,-141,-47.74,1,0,9603,0,0,0,,,,,1
-12,1946,4617,4326,"Jointly derived by US NGS and Geodetic Survey of Canada - see also code 1901. Strictly between NAD83(CSRS) and ITRF96(1997.0).",Geodesy.,1061,40.04,86.45,-141,-47.74,1,0,9607,-0.991,1.9072,0.5129,-0.0257899075194932,-0.0096500989602704,-0.0116599432323421,0,0
-13,1864,4618,4326,Derived at 84 stations.,"For military purposes only. Accuracy 15m, 6m and 9m in X, Y and Z axes.",4016,-45,12.51,-81.4,-34.74,1,0,9603,-57,1,-41,,,,,1
-14,1865,4618,4326,"Derived at 10 stations. Note: SAD69 not adopted in Argentina: see Campo Inchauspe (CRS code 4221).",For military purposes only. Accuracy 5m in each axis.,3215,-52.43,-21.78,-73.58,-53.65,1,0,9603,-62,-1,-37,,,,,0
-15,1866,4618,4326,"Derived at 4 stations. Note: SAD69 not adopted in Bolivia: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 15m in each axis.,1049,-22.9,-9.68,-69.66,-57.52,1,0,9603,-61,2,-48,,,,,0
-16,1867,4618,4326,Derived at 22 stations.,"For military purposes only. Accuracy 3m, 5m and 5m in X, Y and Z axes.",3887,-33.78,4.43,-60.57,-34.74,1,0,9603,-60,-2,-41,,,,,0
-17,1868,4618,4326,"Derived at 9 stations. Note: SAD69 not adopted in Chile.","For military purposes only. Accuracy 15m, 8m and 11m in X, Y and Z axes.",3227,-45,-17.51,-75.22,-67,1,0,9603,-75,-1,-44,,,,,0
-18,1869,4618,4326,"Derived at 7 stations. Note: SAD69 not adopted in Colombia: see Bogota 1975 (CRS code 4218).","For military purposes only. Accuracy 6m, 6m and 5m in X, Y and Z axes.",3229,-4.24,12.51,-79.1,-66.87,1,0,9603,-44,6,-36,,,,,0
-19,1870,4618,4326,"Derived at 11 stations. Note: SAD69 not adopted in Ecuador: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 3m in each axis.,3241,-5,1.45,-81.03,-75.22,1,0,9603,-48,3,-44,,,,,0
-20,1871,4618,4326,"Derived at 1 station. Note: SAD69 not adopted in Ecuador.",For military purposes. Accuracy 25m in each axis.,2356,-1.41,0.17,-91.71,-89.2,1,0,9603,-47,26,-42,,,,,0
-21,1872,4618,4326,"Derived at 5 stations. Note: SAD69 not adopted in Guyana.","For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",3259,1.19,8.57,-61.39,-56.47,1,0,9603,-53,3,-47,,,,,0
-22,1873,4618,4326,"Derived at 4 stations. Note: SAD69 not adopted in Paraguay.",For military purposes. Accuracy 15m in each axis.,1188,-27.58,-19.3,-62.64,-54.24,1,0,9603,-61,2,-33,,,,,0
-23,1874,4618,4326,"Derived at 6 stations. Note: SAD69 not adopted in Peru: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 5m in each axis.,3292,-18.35,-0.04,-81.4,-68.67,1,0,9603,-58,0,-44,,,,,0
-24,1875,4618,4326,"Derived at 1 station. Note: SAD69 not adopted in Trinidad and Tobago.",For military purposes only. Accuracy 25m in each axis.,3143,9.99,10.89,-61.97,-60.86,1,0,9603,-45,12,-33,,,,,0
-25,1876,4618,4326,"Derived at 5 stations. Note: SAD69 not adopted in Venezuela: see PSAD56 (CRS code 4248).","For military purposes only. Accuracy 3m, 6m and 3m in X, Y and Z axes.",3327,0.65,12.25,-73.38,-59.8,1,0,9603,-45,8,-33,,,,,0
-26,1877,4618,4326,"Derived by Brazilian Institute of Geography and Statistics (IBGE) in 1989 at Chua origin point. In use by Shell throughout Brazil. For use by Petrobras and ANP, replaced by tfm code 5882 from 1994.",Medium and small scale mapping. Valid for transforming GPS observations conducted in the period 1987 to 1993 inclusive.,1053,-35.71,7.04,-74,-25.28,1,0,9603,-66.87,4.37,-38.52,,,,,0
-27,5882,4618,4326,"Parameter values from SAD69 to SIRGAS 2000 (1) (tfm code 15485) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Used by ANP and Petrobras throughout Brazil from 1994, relacing use of tfm code 1877.","Accuracy generally better than 1m except in Amazon basin where it degenerates to 5m. Should be used only to transform data obtained independently of the classical geodetic network (GPS observations conducted after 1994).",1053,-35. [...]
-28,1879,4619,4326,"Parameter values taken from SWEREF to ETRS89 (1) (code 1878) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.",Geographic Information Systems.,1225,54.96,69.06,10.03,24.17,1,0,9603,0,0,0,,,,,1
-29,1880,4620,4326,Derived at one point in each of Burkina Faso and Niger.,For military purposes. Accuracy 25m in each axis.,2791,11.83,14.22,-4.64,4,1,0,9603,-106,-129,165,,,,,1
-30,1903,4621,4326,,"Accuracy +/- 10 metres.",2828,17.83,18.17,-63.2,-62.73,1,0,9603,137,248,-430,,,,,1
-31,1904,4622,4326,,"Accuracy +/- 10 metres.",2829,15.8,16.54,-61.85,-60.97,1,0,9603,-467,-16,-300,,,,,1
-32,1905,4622,4326,,"Accuracy +/- 0.1 metre.",2829,15.8,16.54,-61.85,-60.97,1,0,9606,-472.29,-5.63,-304.12,0.4362,-0.8374,0.2563,1.8984,0
-33,1906,4623,4326,,"Accuracy +/- 10 metres.",3105,3.43,5.81,-54.45,-51.62,1,0,9603,-186,230,110,,,,,1
+1,1825,4611,4326,Published 1st March 2002.,Accuracy to 1m level.,1118,22.13,22.58,113.76,114.51,1,0,9606,-162.619,-276.959,-161.764,0.067753,-2.243649,-1.158827,-1.094246,1
+2,1826,4612,4326,,"Approximation at the +/- 1m level.",1129,17.09,46.05,122.38,157.65,1,0,9603,0,0,0,,,,,1
+3,1838,4613,4326,Datum shift derived through ITRF93.,Oil exploration.,1328,-1.24,0,116.72,117.99,1,0,9603,-404.78,685.68,45.47,,,,,0
+4,1897,4613,4326,Accuracy estimate not available.,For military purposes.,1360,-4.24,4.29,114.55,119.06,1,0,9603,-403,684,41,,,,,1
+5,1898,4613,4326,,Oil exploration.,1359,-4.24,0,114.55,117.99,1,0,9603,-387.06,636.53,46.29,,,,,0
+6,1899,4613,4326,,Oil exploration.,2770,-0.07,4.29,116.96,119.06,1,0,9603,-403.4,681.12,46.56,,,,,0
+7,1840,4614,4326,"Transformation defines QND95. May be approximated to 1m throughout Qatar by geocentric translation transformation with dX=-127.78098m, dY=-283.37477m, dZ=+21.24081m.",Parameter values are defined and therefore exact.,1346,24.55,26.2,50.69,51.68,1,0,9606,-119.4248,-303.65872,-11.00061,1.164298,0.174458,1.096259,3.657065,1
+8,1888,4615,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,1314,32.35,33.15,-17.31,-16.23,1,0,9603,-499,-249,314,,,,,1
+9,1889,4616,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,2779,29.98,30.21,-16.11,-15.79,1,1,9603,-289,-124,60,,,,,0
+10,1965,4616,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,2779,29.98,30.21,-16.11,-15.79,1,0,9603,-289,-124,60,,,,,1
+11,1842,4617,4326,"For many purposes NAD83(CSRS) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(CSRS) is equivalent to WGS 84.",1061,40.04,86.46,-141.01,-47.74,1,0,9603,0,0,0,,,,,1
+12,1946,4617,4326,"Approximation derived from tfm code 6864 ignoring time-dependent parameters and assuming ITRF96(1997.0) and WGS 84 can be considered the same within the accuracy of the transformation.",Geodesy.,1061,40.04,86.46,-141.01,-47.74,1,0,9607,-0.991,1.9072,0.5129,-0.0257899075194932,-0.0096500989602704,-0.0116599432323421,0,0
+13,1864,4618,4326,Derived at 84 stations.,"For military purposes only. Accuracy 15m, 6m and 9m in X, Y and Z axes.",4016,-45,12.52,-81.41,-34.74,1,0,9603,-57,1,-41,,,,,0
+14,1865,4618,4326,"Derived at 10 stations. Note: SAD69 not adopted in Argentina: see Campo Inchauspe (CRS code 4221).",For military purposes only. Accuracy 5m in each axis.,3215,-52.43,-21.78,-73.59,-53.65,1,0,9603,-62,-1,-37,,,,,0
+15,1866,4618,4326,"Derived at 4 stations. Note: SAD69 not adopted in Bolivia: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 15m in each axis.,1049,-22.91,-9.67,-69.66,-57.52,1,0,9603,-61,2,-48,,,,,0
+16,1867,4618,4326,Derived at 22 stations.,"For military purposes only. Accuracy 3m, 5m and 5m in X, Y and Z axes.",3887,-33.78,4.43,-60.58,-34.74,1,0,9603,-60,-2,-41,,,,,0
+17,1868,4618,4326,"Derived at 9 stations. Note: SAD69 not adopted in Chile.","For military purposes only. Accuracy 15m, 8m and 11m in X, Y and Z axes.",3227,-45,-17.5,-75.22,-67,1,0,9603,-75,-1,-44,,,,,0
+18,1869,4618,4326,"Derived at 7 stations. Note: SAD69 not adopted in Colombia: see Bogota 1975 (CRS code 4218).","For military purposes only. Accuracy 6m, 6m and 5m in X, Y and Z axes.",3229,-4.23,12.52,-79.1,-66.87,1,0,9603,-44,6,-36,,,,,0
+19,1870,4618,4326,"Derived at 11 stations. Note: SAD69 not adopted in Ecuador: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 3m in each axis.,3241,-5.01,1.45,-81.03,-75.21,1,0,9603,-48,3,-44,,,,,0
+20,1871,4618,4326,"Derived at 1 station. Note: SAD69 not adopted in Ecuador.",For military purposes. Accuracy 25m in each axis.,2356,-1.41,0.18,-91.72,-89.19,1,0,9603,-47,26,-42,,,,,0
+21,1872,4618,4326,"Derived at 5 stations. Note: SAD69 not adopted in Guyana.","For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",3259,1.18,8.58,-61.39,-56.47,1,0,9603,-53,3,-47,,,,,0
+22,1873,4618,4326,"Derived at 4 stations. Note: SAD69 not adopted in Paraguay.",For military purposes. Accuracy 15m in each axis.,1188,-27.59,-19.29,-62.65,-54.24,1,0,9603,-61,2,-33,,,,,0
+23,1874,4618,4326,"Derived at 6 stations. Note: SAD69 not adopted in Peru: see PSAD56 (CRS code 4248).",For military purposes. Accuracy 5m in each axis.,3292,-18.35,-0.03,-81.41,-68.67,1,0,9603,-58,0,-44,,,,,0
+24,1875,4618,4326,"Derived at 1 station. Note: SAD69 not adopted in Trinidad and Tobago.",For military purposes only. Accuracy 25m in each axis.,3143,9.99,10.9,-61.97,-60.86,1,0,9603,-45,12,-33,,,,,0
+25,1876,4618,4326,"Derived at 5 stations. Note: SAD69 not adopted in Venezuela: see PSAD56 (CRS code 4248).","For military purposes only. Accuracy 3m, 6m and 3m in X, Y and Z axes.",3327,0.64,12.25,-73.38,-59.8,1,0,9603,-45,8,-33,,,,,0
+26,1877,4618,4326,"Derived by Brazilian Institute of Geography and Statistics (IBGE) in 1989 at Chua origin point. In use by Shell throughout Brazil. For use by Petrobras and ANP, replaced by tfm code 5882 from 1994.",Medium and small scale mapping. Valid for transforming GPS observations conducted in the period 1987 to 1993 inclusive.,1053,-35.71,7.04,-74.01,-25.28,1,0,9603,-66.87,4.37,-38.52,,,,,0
+27,5882,4618,4326,"Parameter values from SAD69 to SIRGAS 2000 (1) (tfm code 15485) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Used by ANP and Petrobras throughout Brazil from 1994, relacing use of tfm code 1877.","Accuracy generally better than 1m except in Amazon basin where it degenerates to 5m. Should be used only to transform data obtained independently of the classical geodetic network (GPS observations conducted after 1994).",1053,-35. [...]
+28,1879,4619,4326,"Parameter values taken from SWEREF to ETRS89 (1) (code 1878) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.",Geographic Information Systems.,1225,54.96,69.07,10.03,24.17,1,0,9603,0,0,0,,,,,1
+29,1880,4620,4326,Derived at one point in each of Burkina Faso and Niger.,For military purposes. Accuracy 25m in each axis.,2791,11.83,14.23,-4.64,4,1,0,9603,-106,-129,165,,,,,1
+30,1903,4621,4326,,"Accuracy +/- 10 metres.",2828,17.82,18.17,-63.21,-62.73,1,0,9603,137,248,-430,,,,,1
+31,1904,4622,4326,,"Accuracy +/- 10 metres.",2829,15.8,16.55,-61.85,-60.97,1,0,9603,-467,-16,-300,,,,,1
+32,1905,4622,4326,,"Accuracy +/- 0.1 metre.",2829,15.8,16.55,-61.85,-60.97,1,0,9606,-472.29,-5.63,-304.12,0.4362,-0.8374,0.2563,1.8984,0
+33,1906,4623,4326,,"Accuracy +/- 10 metres.",3105,3.43,5.81,-54.45,-51.61,1,0,9603,-186,230,110,,,,,1
 34,1907,4624,4326,,"Accuracy +/- 2 metres.",1097,2.11,8.88,-54.6,-49.46,1,1,9603,2,2,-2,,,,,0
 35,4840,4624,4326,"Replaces RGFG95 to WGS 84 (1) (code 1907) which was not put into official use but issued in error.","Accuracy +/- 2 metres.",1097,2.11,8.88,-54.6,-49.46,1,0,9603,0,0,0,,,,,1
-36,1909,4625,4326,,"Accuracy +/- 10 metres.",3276,14.35,14.93,-61.28,-60.77,1,0,9603,186,482,151,,,,,1
-37,1910,4625,4326,,"Accuracy +/- 0.1 metre.",3276,14.35,14.93,-61.28,-60.77,1,0,9606,126.93,547.94,130.41,-2.7867,5.1612,-0.8584,13.8227,0
+36,1909,4625,4326,,"Accuracy +/- 10 metres.",3276,14.35,14.93,-61.29,-60.76,1,0,9603,186,482,151,,,,,1
+37,1910,4625,4326,,"Accuracy +/- 0.1 metre.",3276,14.35,14.93,-61.29,-60.76,1,0,9606,126.93,547.94,130.41,-2.7867,5.1612,-0.8584,13.8227,0
 38,1911,4626,4326,Derived at 1 station.,"Accuracy +/- 30 metres.",1196,-25.92,-10.6,37.58,58.27,1,1,9603,94,-948,-1292,,,,,0
-39,15751,4626,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3337,-21.42,-20.81,55.17,55.9,1,0,9603,94,-948,-1262,,,,,1
-40,1912,4627,4326,,"Accuracy +/- 1 metre.",3902,-24.71,-18.29,51.84,58.24,1,0,9603,0,0,0,,,,,1
-41,1924,4628,4326,,"Accuracy +/- 10 metres.",2811,-17.92,-17.42,-149.99,-149.1,1,0,9603,162,117,154,,,,,1
-42,1913,4629,4326,,"Accuracy +/- 10 metres.",2812,-16.95,-16.18,-151.91,-150.9,1,0,9603,65,342,77,,,,,0
-43,15770,4629,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Tahaa 54 to RGPF (1) (tfm code 15758).","Accuracy +/- 1 metre.",2812,-16.95,-16.18,-151.91,-150.9,1,0,9607,72.438,345.918,79.486,-1.6045,-0.8823,-0.5565,1.3746,1
-44,1914,4630,4326,,"Accuracy +/- 10 metres.",3129,-9.56,-8.73,-140.31,-139.45,1,0,9603,84,274,65,,,,,1
-45,15775,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (1) (tfm code 15763).","Accuracy +/- 1 metre.",2810,-9.01,-8.73,-140.31,-139.96,1,0,9607,165.732,216.72,180.505,-0.6434,-0.4512,-0.0791,7.4204,0
-46,15776,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (2) (tfm code 15764).","Accuracy +/- 2 metres.",3127,-8.99,-8.82,-139.65,-139.45,1,0,9607,1363.785,1362.687,398.811,-4.5322,-6.7579,-1.0574,268.361,0
-47,15777,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (2) (tfm code 15765).","Accuracy +/- 1 metre.",3128,-9.56,-9.27,-140.2,-139.96,1,0,9607,259.551,297.612,197.833,1.4866,2.1224,0.4612,27.0249,0
+39,15751,4626,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3337,-21.42,-20.81,55.16,55.91,1,0,9603,94,-948,-1262,,,,,1
+40,1912,4627,4326,,"Accuracy +/- 1 metre.",3902,-24.72,-18.28,51.83,58.24,1,0,9603,0,0,0,,,,,1
+41,1924,4628,4326,,"Accuracy +/- 10 metres.",2811,-17.93,-17.41,-150,-149.11,1,0,9603,162,117,154,,,,,1
+42,1913,4629,4326,,"Accuracy +/- 10 metres.",2812,-16.96,-16.17,-151.91,-150.89,1,0,9603,65,342,77,,,,,0
+43,15770,4629,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Tahaa 54 to RGPF (1) (tfm code 15758).","Accuracy +/- 1 metre.",2812,-16.96,-16.17,-151.91,-150.89,1,0,9607,72.438,345.918,79.486,-1.6045,-0.8823,-0.5565,1.3746,1
+44,1914,4630,4326,,"Accuracy +/- 10 metres.",3129,-9.57,-8.72,-140.31,-139.44,1,0,9603,84,274,65,,,,,1
+45,15775,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (1) (tfm code 15763).","Accuracy +/- 1 metre.",2810,-9.01,-8.72,-140.31,-139.96,1,0,9607,165.732,216.72,180.505,-0.6434,-0.4512,-0.0791,7.4204,0
+46,15776,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (2) (tfm code 15764).","Accuracy +/- 2 metres.",3127,-9,-8.81,-139.66,-139.44,1,0,9607,1363.785,1362.687,398.811,-4.5322,-6.7579,-1.0574,268.361,0
+47,15777,4630,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN72 Nuku Hiva to RGPF (2) (tfm code 15765).","Accuracy +/- 1 metre.",3128,-9.57,-9.27,-140.21,-139.95,1,0,9607,259.551,297.612,197.833,1.4866,2.1224,0.4612,27.0249,0
 48,1915,4631,4326,"Also published in US NIMA/NGA TR8350.2 which gives accuracy of +/-25m in each axis and states that derived at one station.","Accuracy +/- 10 metres.",2816,-49.78,-48.6,68.69,70.62,1,1,9603,145,-187,103,,,,,0
-49,1916,4632,4326,,"Accuracy +/- 10 metres.",3340,-13.04,-12.61,44.99,45.34,1,0,9603,-382,-59,-262,,,,,1
-50,1272,4121,4326,,For applications requiring 1m or better accuracy.,3254,34.88,41.75,19.58,28.3,1,0,9603,-199.87,74.79,246.62,,,,,1
-51,1918,4634,4326,,"Accuracy +/- 10 metres.",1174,-26.44,-14.83,156.26,174.28,1,1,9603,-13,-348,292,,,,,0
-52,1929,4634,4326,,"Accuracy better than +/- 1 metre.",2822,-22.45,-20.04,163.93,167.08,1,1,9606,97.295,-263.247,310.882,-1.5999,0.8386,3.1409,13.3259,0
-53,1639,4123,4326,"Parameter values from KKJ to ETRS89 (1) (code 1638). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by KKJ to WGS 84 (2) (code 10099).",For applications to an accuracy of 1 to 2 metres.,3333,59.76,70.09,19.24,31.58,1,0,9606,-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37,0
-54,10099,4123,4326,"Parameter values from KKJ to ETRS89 (2) (code 10098). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces KKJ to WGS 84 (1) (code 1639).",For applications to an accuracy of 1 to 2 metres.,3333,59.76,70.09,19.24,31.58,1,0,9607,-96.062,-82.428,-121.753,-4.801,-0.345,1.376,1.496,1
-55,1680,4124,4326,"Parameter values from RT90 to ETRS89 (1) (code 1437) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaced by RT90 to WGS 84 (2) (code 1896) from 2001.","Approximation at the +/- 1m level.",1225,54.96,69.06,10.03,24.17,1,0,9607,419.3836,99.3335,591.3451,-0.850389,-1.817277,7.862238,-0.99496,0
-56,1788,4124,4326,"Parameter values from RT90 to ETRS89 (1) (code 1787) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Supersedes RT90 to WGS 84 (1) (code 1680).","Approximation at the +/- 1m level.",1225,54.96,69.06,10.03,24.17,1,1,9607,414.1,41.3,603.1,-0.855,2.141,-7.023,0,0
-57,1896,4124,4326,"Parameter values from RT90 to SWEREF99 (1) (code 1895) assuming that SWEREF99 is equivalent to WGS 84 within the accuracy of the transformation. Replaces RT90 to WGS 84 (1) (code 1680).","Approximation at the +/- 1m level.",1225,54.96,69.06,10.03,24.17,1,0,9607,414.1,41.3,603.1,0.855,-2.141,7.023,0,1
-58,1282,4125,4326,Datum shift derived through ITRF93.,Oil exploration.,1328,-1.24,0,116.73,117.99,1,1,9603,-404.78,685.68,45.47,,,,,0
-59,1923,4638,4326,,"Accuracy +/- 10 metres.",3299,46.7,47.18,-56.47,-56.07,1,0,9603,30,430,368,,,,,1
-60,1683,4127,4326,"Parameter values taken from Tete to Moznet (1) (code 1297) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals as high as 30 metres.,3281,-26.86,-10.43,30.21,40.9,1,0,9607,-115.064,-87.39,-101.716,0.058,-4.001,2.062,9.366,0
-61,1684,4127,4326,"Parameter values taken from Tete to Moznet (2) (code 1298) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 1 metre.,2350,-26.86,-23.91,31.92,34.49,1,0,9607,-82.875,-57.097,-156.768,2.158,-1.524,0.982,-0.359,0
-62,1685,4127,4326,"Parameter values taken from Tete to Moznet (3) (code 1299) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 4 metres.,2351,-24.91,-19.74,31.3,35.65,1,0,9607,-138.527,-91.999,-114.591,0.14,-3.363,2.217,11.748,0
-63,1686,4127,4326,"Parameter values taken from Tete to Moznet (4) (code 1300) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 3 metres.,2352,-19.9,-14.01,30.21,39.18,1,0,9607,-73.472,-51.66,-112.482,-0.953,-4.6,2.368,0.586,1
-64,1687,4127,4326,"Parameter values taken from Tete to Moznet (5) (code 1301) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are 5-10 metres.,2353,-16.94,-10.43,34.37,40.9,1,0,9607,219.315,168.975,-166.145,-0.198,-5.926,2.356,-57.104,0
-65,1934,4640,4326,RRAF 1991 was defined to be WGS84 at a single point in Martinique during the 1988 Tango mission.,"Accuracy +/- 1 metre.",2824,14.08,18.53,-63.66,-57.53,1,1,9603,0,0,0,,,,,0
-66,1928,4641,4326,Withdrawn by information source and replaced by improved information - see tfm code 15901.,"Accuracy better than +/- 1 metre.",2819,-21.71,-21.33,167.76,168.18,1,0,9606,-408.809,366.856,-412.987,1.8842,-0.5308,2.1655,-121.0993,0
-67,15783,4641,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15901.,Accuracy 5 metres.,2819,-21.71,-21.33,167.76,168.18,1,0,9603,287,178,-136,,,,,0
-68,15901,4641,4326,"Parameter values taken from IGN53 Mare to RGNC91-93 (1) ( code 15884) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 2 metres.,2819,-21.71,-21.33,167.76,168.18,1,0,9603,287.58,177.78,-135.41,,,,,1
-69,1302,4130,4326,,For many purposes Moznet can be considered to be coincident with WGS 84. Accuracy better than 1 metre.,1167,-27.7,-10.09,30.21,43.02,1,0,9607,0,0,0,0,0,0,0,1
-70,1542,4131,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,2359,14,18,105.62,109.32,1,0,9603,198,881,317,,,,,1
-71,1543,4131,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2360,8.59,8.82,106.5,106.79,1,0,9603,182,915,344,,,,,0
-72,1513,4132,4326,Derived in 1998 in Kangan district by Geoid for Total. Used for South Pars phases 2 and 3.,Oil exploration.,2362,27.3,28.2,51.8,53,1,0,9603,-241.54,-163.64,396.06,,,,,1
-73,1854,4132,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Oil Exploration,2782,26.22,26.86,52.5,53.43,1,0,9603,-239.1,-170.02,397.5,,,,,0
-74,1855,4132,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Oil Exploration,2781,29.17,29.38,50.23,50.42,1,0,9603,-244.72,-162.773,400.75,,,,,0
-75,1333,4133,4326,,"?",3246,57.52,59.75,21.74,28.19,1,0,9607,0.055,-0.541,-0.185,-0.0183,0.0003,0.007,-0.014,1
-76,1439,4134,4326,"Replaced PSD93 to WGS 84 (2) (code 8581) in 1997.","Oil exploration. Residuals 0.5m at 67% probability level.",3288,16.6,26.57,52,59.9,1,0,9606,-180.624,-225.516,173.919,-0.81,-1.898,8.336,16.71006,1
+49,1916,4632,4326,,"Accuracy +/- 10 metres.",3340,-13.05,-12.61,44.98,45.35,1,0,9603,-382,-59,-262,,,,,1
+50,1272,4121,4326,,For applications requiring 1m or better accuracy.,3254,34.88,41.75,19.57,28.3,1,0,9603,-199.87,74.79,246.62,,,,,1
+51,1918,4634,4326,,"Accuracy +/- 10 metres.",1174,-26.45,-14.83,156.25,174.28,1,1,9603,-13,-348,292,,,,,0
+52,1929,4634,4326,,"Accuracy better than +/- 1 metre.",2822,-22.45,-20.03,163.92,167.09,1,1,9606,97.295,-263.247,310.882,-1.5999,0.8386,3.1409,13.3259,0
+53,1639,4123,4326,"Parameter values from KKJ to ETRS89 (1) (code 1638). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by KKJ to WGS 84 (2) (code 10099).",For applications to an accuracy of 1 to 2 metres.,3333,59.75,70.09,19.24,31.59,1,0,9606,-90.7,-106.1,-119.2,4.09,0.218,-1.05,1.37,0
+54,10099,4123,4326,"Parameter values from KKJ to ETRS89 (2) (code 10098). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces KKJ to WGS 84 (1) (code 1639).",For applications to an accuracy of 1 to 2 metres.,3333,59.75,70.09,19.24,31.59,1,0,9607,-96.062,-82.428,-121.753,-4.801,-0.345,1.376,1.496,1
+55,1680,4124,4326,"Parameter values from RT90 to ETRS89 (1) (code 1437) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaced by RT90 to WGS 84 (2) (code 1896) from 2001.","Approximation at the +/- 1m level.",1225,54.96,69.07,10.03,24.17,1,0,9607,419.3836,99.3335,591.3451,-0.850389,-1.817277,7.862238,-0.99496,0
+56,1788,4124,4326,"Parameter values from RT90 to ETRS89 (1) (code 1787) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Supersedes RT90 to WGS 84 (1) (code 1680).","Approximation at the +/- 1m level.",1225,54.96,69.07,10.03,24.17,1,1,9607,414.1,41.3,603.1,-0.855,2.141,-7.023,0,0
+57,1896,4124,4326,"Parameter values from RT90 to SWEREF99 (1) (code 1895) assuming that SWEREF99 is equivalent to WGS 84 within the accuracy of the transformation. Replaces RT90 to WGS 84 (1) (code 1680).","Approximation at the +/- 1m level.",1225,54.96,69.07,10.03,24.17,1,0,9607,414.1,41.3,603.1,0.855,-2.141,7.023,0,1
+58,1282,4125,4326,Datum shift derived through ITRF93.,Oil exploration.,1328,-1.24,0,116.72,117.99,1,1,9603,-404.78,685.68,45.47,,,,,0
+59,1923,4638,4326,,"Accuracy +/- 10 metres.",3299,46.69,47.19,-56.48,-56.07,1,0,9603,30,430,368,,,,,1
+60,1683,4127,4326,"Parameter values taken from Tete to Moznet (1) (code 1297) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals as high as 30 metres.,3281,-26.87,-10.42,30.21,40.9,1,0,9607,-115.064,-87.39,-101.716,0.058,-4.001,2.062,9.366,0
+61,1684,4127,4326,"Parameter values taken from Tete to Moznet (2) (code 1298) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 1 metre.,2350,-26.87,-23.91,31.91,34.5,1,0,9607,-82.875,-57.097,-156.768,2.158,-1.524,0.982,-0.359,0
+62,1685,4127,4326,"Parameter values taken from Tete to Moznet (3) (code 1299) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 4 metres.,2351,-24.91,-19.74,31.29,35.65,1,0,9607,-138.527,-91.999,-114.591,0.14,-3.363,2.217,11.748,0
+63,1686,4127,4326,"Parameter values taken from Tete to Moznet (4) (code 1300) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are generally under 3 metres.,2352,-19.91,-14.01,30.21,39.18,1,0,9607,-73.472,-51.66,-112.482,-0.953,-4.6,2.368,0.586,1
+64,1687,4127,4326,"Parameter values taken from Tete to Moznet (5) (code 1301) assuming that Moznet is equivalent to WGS 84 within the accuracy of the transformation.",Residuals are 5-10 metres.,2353,-16.94,-10.42,34.36,40.9,1,0,9607,219.315,168.975,-166.145,-0.198,-5.926,2.356,-57.104,0
+65,1934,4640,4326,RRAF 1991 was defined to be WGS84 at a single point in Martinique during the 1988 Tango mission.,"Accuracy +/- 1 metre.",2824,14.08,18.54,-63.66,-57.52,1,1,9603,0,0,0,,,,,0
+66,1928,4641,4326,Withdrawn by information source and replaced by improved information - see tfm code 15901.,"Accuracy better than +/- 1 metre.",2819,-21.71,-21.32,167.75,168.19,1,0,9606,-408.809,366.856,-412.987,1.8842,-0.5308,2.1655,-121.0993,0
+67,15783,4641,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15901.,Accuracy 5 metres.,2819,-21.71,-21.32,167.75,168.19,1,0,9603,287,178,-136,,,,,0
+68,15901,4641,4326,"Parameter values taken from IGN53 Mare to RGNC91-93 (1) ( code 15884) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 2 metres.,2819,-21.71,-21.32,167.75,168.19,1,0,9603,287.58,177.78,-135.41,,,,,1
+69,1302,4130,4326,,For many purposes Moznet can be considered to be coincident with WGS 84. Accuracy better than 1 metre.,1167,-27.71,-10.09,30.21,43.03,1,0,9607,0,0,0,0,0,0,0,1
+70,1542,4131,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,2359,14,18,105.61,109.32,1,0,9603,198,881,317,,,,,1
+71,1543,4131,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2360,8.58,8.83,106.49,106.79,1,0,9603,182,915,344,,,,,0
+72,1513,4132,4326,Derived in 1998 in Kangan district by Geoid for Total. Used for South Pars phases 2 and 3.,Oil exploration.,2362,27.3,28.2,51.8,53.01,1,0,9603,-241.54,-163.64,396.06,,,,,1
+73,1854,4132,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Oil Exploration,2782,26.21,26.87,52.49,53.43,1,0,9603,-239.1,-170.02,397.5,,,,,0
+74,1855,4132,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Oil Exploration,2781,29.16,29.39,50.22,50.42,1,0,9603,-244.72,-162.773,400.75,,,,,0
+75,1333,4133,4326,,"?",3246,57.52,59.75,21.74,28.2,1,0,9607,0.055,-0.541,-0.185,-0.0183,0.0003,0.007,-0.014,1
+76,1439,4134,4326,"Replaced PSD93 to WGS 84 (2) (code 8581) in 1997.","Oil exploration. Residuals 0.5m at 67% probability level.",3288,16.59,26.58,51.99,59.91,1,0,9606,-180.624,-225.516,173.919,-0.81,-1.898,8.336,16.71006,1
 77,1617,4134,4326,Accuracy better than 0.5m in block 4.,Oil exploration.,2404,19.58,21.17,56.5,59.02,1,0,9606,-191.808,-250.512,167.861,-0.792,-1.653,8.558,20.703,0
-78,15824,4135,4326,Derived at 15 satellite stations.,"Military mapping. Accuracy +/- 25m in X axis, +/- 20m in Y and Z axes.",1334,18.88,22.29,-160.3,-154.75,1,0,9603,61,-285,-181,,,,,1
-79,15825,4135,4326,Derived at 2 satellite stations.,"Military mapping. Accuracy +/- 25m in each axis.",1546,18.88,20.33,-156.1,-154.75,1,0,9603,89,-279,-183,,,,,0
-80,15826,4135,4326,Derived at 3 satellite stations.,"Military mapping. Accuracy +/- 20m in each axis.",1549,21.82,22.29,-159.84,-159.24,1,0,9603,45,-290,-172,,,,,0
-81,15827,4135,4326,Derived at 2 satellite stations.,"Military mapping. Accuracy +/- 25m in each axis.",1547,20.46,21.26,-157.35,-155.94,1,0,9603,65,-290,-190,,,,,0
-82,15828,4135,4326,Derived at 8 satellite stations.,"Military mapping only. Accuracy +/- 10m in X axis, +/- 6m in Y and Z axes.",1548,21.21,21.75,-158.32,-157.62,1,0,9603,58,-283,-182,,,,,0
-83,1893,4139,4326,Derived at 11 stations.,For military purposes only. Accuracy 3m in each axis.,1335,17.63,18.77,-67.96,-64.25,1,0,9603,11,72,-101,,,,,1
-84,1473,4140,4326,"For many purposes NAD83(CSRS98) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(CSRS98) is equivalent to WGS 84.",1336,44.61,62.56,-120,-57.1,1,1,9603,0,0,0,,,,,0
-85,1073,4141,4326,For more accurate transformation contact Survey of Israel.,"Accuracy: 2m",2603,29.45,33.27,34.18,35.68,1,0,9603,-48,55,52,,,,,1
-86,1469,4142,4326,,"?",2282,5.16,5.54,-4.22,-3.85,1,0,9603,-125,53,467,,,,,1
-87,1470,4143,4326,"Derived in Abidjan for use in the immediate area, but used by E&P industry more widely onshore and offshore. A similar transformation (dX=-123.1, dY=+53.2, dZ=+465.4, derivation unknown) was used by Western Geophysical for offshore surveys in the 1990s.",Accuracy is submetre in the area around Abidjan but unknown farther afield. There is some evidence of unknown reliability that suggests accuracy of better than 2m throughout offshore.,1075,1.02,10.74,-8.61,-2.49,1,0,96 [...]
-88,1155,4144,4326,Derived at 6 stations.,"For military purposes. Accuracy 10m, 8m and 12m in X, Y and Z axes.",3217,20.52,26.63,88.04,92.67,1,0,9603,282,726,254,,,,,0
-89,1533,4144,4326,,Oil exploration.,2361,9.49,17.87,93.94,99.66,1,0,9603,214,804,268,,,,,1
-90,1247,4145,4326,"Care! DMA ellipsoid is inconsistent with EPSG ellipsoid - transformation parameter values may not be appropriate. No accuracy estimate available.",For military purposes.,3289,23.64,37.06,60.87,77.82,1,0,9603,283,682,231,,,,,1
-91,15494,4145,4326,Derived by Fugro-Geodetic in 2004 at 6 closely-spaced stations. Used by OMV in all blocks in Pakistan where operator.,Oil exploration.,3589,25.88,27.67,68.25,69.3,1,0,9603,274.164,677.282,226.704,,,,,0
-92,15701,4145,4326,Derived at Geodetic Survey office in Karachi in 1997.,Oil exploration.,2985,21.06,25.38,64,68.23,1,0,9603,275.57,676.78,229.6,,,,,0
-93,15702,4145,4326,"Derived at station S0001, an approximate offset to Survey of India primary station Kat Baman, in 1992 from 180 single point Transit passes observed in 1991 by Fugro-Geodetic for UTP.",Oil exploration.,2984,24,25.63,67.75,69.87,1,0,9603,278.9,684.39,226.05,,,,,0
-94,15703,4145,4326,Derived at Chitrawala triangulation station by Fugro-Geodetic for UTP.,Oil exploration.,2982,24.69,25.75,66.83,68,1,0,9603,271.905,669.593,231.495,,,,,0
-95,15704,4145,4326,Derived by Western Geophysical for UTP 1996 East Sind 2D survey.,Oil exploration.,2983,24.17,28.6,68.27,71.1,1,0,9606,230.25,632.76,161.03,-1.114,1.115,1.212,12.584,0
-96,1156,4146,4326,"Care! DMA ellipsoid is inconsistent with EPSG ellipsoid - transformation parameter values may not be appropriate. Also source CRS may not apply to Nepal. Derived at 7 stations.","For military purposes. Accuracy 12m, 10m and 15m in X, Y and Z axes.",2411,8.02,35.51,68.09,97.38,1,0,9603,295,736,257,,,,,1
-97,1544,4147,4326,Derived in Vung Tau area.,Oil exploration.,1494,9.03,11.02,105.5,107.59,1,0,9603,-17.51,-108.32,-62.39,,,,,1
-98,1505,4148,4326,,For many purposes Hartebeesthoek94 datum can be considered to be coincident with WGS 84.,1215,-50.31,-22.14,13.33,42.85,1,0,9603,0,0,0,,,,,1
-99,1508,4149,4326,"Implemented in Bundesamt für Landestopographie programme GRANIT.","?",1286,45.83,47.81,5.97,10.49,1,1,9607,660.077,13.551,369.344,0.804816,0.577692,0.952236,5.66,0
-100,1510,4149,4326,"These parameters are strictly between CH1903+ and CHTRF95 but are used from CH1903 as an approximation which is within the accuracy of the distortions in the CH1903 network.",Accuracy 1.5 metres.,1286,45.83,47.81,5.97,10.49,1,1,9603,674.374,15.056,405.346,,,,,0
-101,1753,4149,4326,"Implemented in Bundesamt für Landestopographie programme GRANIT. Used from 1987 to 1997. Not recommended for current usage - replaced by CH1903 to WGS 84 (2) (code 1766).","?",1286,45.83,47.81,5.97,10.49,1,0,9607,660.077,13.551,369.344,0.804816,0.577692,0.952236,5.66,0
-102,1766,4149,4326,"These parameters are derive from CH1903+ to ETRS89 (code 1647) and are used at lesser precision from CH1903 to WGS 84 as an approximation which is within the accuracy of the distortions in the CH1903 network. Replaces CH1903 to WGS 84 (1) (code 1753).",Accuracy 1.5 metres.,1286,45.83,47.81,5.97,10.49,1,0,9603,674.4,15.1,405.3,,,,,1
-103,1676,4150,4326,"Parameter values are from CH1903+ to CHTRF95 (1) (code 1509) assuming that CHTRF95 is equivalent to WGS 84. That transformation is also given as CH1903+ to ETRS89 (1) (code 1647). CHTRF95 is a realisation of ETRS89.","Approximation at the +/- 1m level.",1286,45.83,47.81,5.97,10.49,1,0,9603,674.374,15.056,405.346,,,,,1
-104,1511,4151,4326,,For many purposes CHTRF95 can be considered to be coincident with WGS 84.,1286,45.83,47.81,5.97,10.49,1,0,9603,0,0,0,,,,,1
-105,1580,4152,4326,"For many purposes NAD83(HARN) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(HARN) is equivalent to WGS 84.",1337,-14.58,49.38,144.58,-64.51,1,0,9603,0,0,0,,,,,1
-106,1900,4152,4326,"Strictly between NAD83(HARN) and ITRF94(1996.0). Replaced by NAD83(HARN) to WGS 84 (3) (code 1901).",Historical record only - superseded - see remarks.,1323,24.41,49.38,-124.79,-66.92,1,0,9607,-0.9738,1.9453,0.5486,-0.0275507901704247,-0.0100492213603585,-0.0113590028800276,0,0
-107,1901,4152,4326,"Jointly derived by US NGS and Geodetic Survey of Canada as transformation to target CRS of ITRF96(1997.0) - see also tfm code 1946. In USA only replaces NAD83 to WGS 84 (2) (code 1900).","Geodesy. Accuracy with respect to CORS at stations adjusted to HARN network is better than 0.05-0.07m. For locations outside a HARN network (i.e. NAD83), accuracy may be only 1m but will usually be better than 0.5m.",1323,24.41,49.38,-124.79,-66.92,1,0,9607,-0.991,1.9072,0.5129,-0.02 [...]
-108,15930,4152,4326,"Accuracy 0.1 to 0.2m in California, 0.05-0.11 in Oregon, elsewhere better than 0.05m.",For applications to an accuracy of 0.2 metre.,1323,24.41,49.38,-124.79,-66.92,1,1,9603,0,0,0,,,,,0
-109,1512,4153,4326,"Derived in 1998 at Assaluyeh (Taheri refinery) by Geoid for Total. Used for South Pars phases 2 and 3.",Oil industry engineering survey. Used only for terminal site.,1338,27.4,27.6,52.5,52.7,1,0,9603,-133.63,-157.5,-158.62,,,,,1
-110,1141,4154,4326,"Given by DMA as from ED50. OGP interpret that as ED50(ED77) in Iran. Derived at 27 stations.","For military purposes. Accuracy 9m, 12m and 11m in X, Y and Z axes.",1123,23.35,39.78,44.03,63.33,1,0,9603,-117,-132,-164,,,,,1
-111,1514,4154,4326,"Used for South Pars phases 6, 7 and 8.","Transformation for whole country: accuracy about 1m.",1123,23.35,39.78,44.03,63.33,1,0,9606,-110.33,-97.73,-119.85,0.3423,1.1634,0.2715,0.063,0
-112,1856,4154,4326,Derived in Kangan district by Geoid for Total in 1998. Used for South Pars phases 2 and 3.,Petroleum Exploration and Production.,2783,26.59,26.71,52.07,52.27,1,0,9603,-122.89,-159.08,-168.74,,,,,0
-113,1857,4154,4326,Derived in 1999 on Lavan island by Geoid for Elf.,Petroleum Exploration and Production.,2782,26.22,26.86,52.5,53.43,1,0,9603,-84.78,-107.55,-137.25,,,,,0
-114,1858,4154,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Petroleum Exploration and Production.,2781,29.17,29.38,50.23,50.42,1,0,9603,-123.92,-155.515,-157.721,,,,,0
-115,15745,4154,4326,Derived in Tombak district in March 2005. Used for South Pars phase 11.,Petroleum Exploration and Production.,3140,26.46,26.63,52.23,52.41,1,0,9603,-123.02,-158.95,-168.47,,,,,0
-116,1518,4155,4326,,Accuracy 25m in each axis.,3257,7.19,12.68,-15.13,-7.65,1,0,9603,-83,37,124,,,,,1
-117,1623,4156,4326,"Parameter values from S-JTSK to ETRS89 (1) (code 1622). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by S-JTSK to WGS 84 (5) (code 5239).",For applications to an accuracy of 1 metre.,1079,48.58,51.05,12.09,18.85,1,0,9606,570.8,85.7,462.8,4.998,1.587,5.261,3.56,0
-118,1625,4156,4326,"Parameter values from S-JTSK to ETRS89 (2) (code 1624). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.74,49.6,16.84,22.56,1,1,9606,559,68.7,451.5,7.92,4.073,4.251,5.71,0
-119,4828,4156,4326,"Parameter values from S-JTSK to ETRS89 (4) (code 4827). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.74,49.6,16.84,22.56,1,1,9606,485,169.5,483.5,7.786,4.398,4.103,0,0
-120,4836,4156,4326,"Parameter values from S-JTSK to ETRS89 (4) (code 4827). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.74,49.6,16.84,22.56,1,0,9606,485,169.5,483.8,7.786,4.398,4.103,0,0
-121,5239,4156,4326,"Parameter values from S-JTSK/05 to WGS 84 (1) (code 5227). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces tfm code 1622.",For applications to an accuracy of 1 metre.,1079,48.58,51.05,12.09,18.85,1,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378,0
-122,15965,4156,4326,Derived at 6 stations.,"For military purposes. Accuracy 4m, 2m and 3m in X, Y and Z axes.",1306,47.74,51.05,12.09,22.56,1,0,9603,589,76,480,,,,,1
-123,1283,4669,4326,,LKS94 is a realisation of ETRS89 coincident to WGS 84 within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1145,53.89,56.45,19.02,26.81,1,0,9603,0,0,0,,,,,1
-124,1099,4670,4326,"Parameter values taken from IGM95 to ETRS89 (1) (code 1098) assuming that ETRS89 is coincident with WGS 84 within the accuracy of the transformation.",Approximation at the 1m level.,3343,34.77,47.09,5.94,18.99,1,0,9603,0,0,0,,,,,1
-125,1859,4159,4326,"Used by Repsol in Murzuq field, and PetroCanada and previous licence holders in NC177 and 72 (En Naga field). Reliability of connection to ELD79 questionned.",Oil Exploration,2785,27.33,27.66,18.37,18.72,1,0,9603,-69.06,-90.71,-142.56,,,,,0
-126,1860,4159,4326,Derived December 2001 by NAGECO. Connected to ITRF via Remsa 2000 data. Used by TotalFinaElf.,Oil Exploration. 3-dimensional SD at 11 points is 0.5m.,2785,27.33,27.66,18.37,18.72,1,0,9603,-113.997,-97.076,-152.312,,,,,0
-127,1861,4159,4326,Derived by GEOID in 1994 from Transit satellite data. Used by TotalFinaElf.,Oil Exploration,2786,29.62,30.06,17.14,17.5,1,0,9603,-114.5,-96.1,-151.9,,,,,0
-128,1862,4159,4326,"Derived by Geoid in 2000 from ITRF connection by NAGECO for TotalFinaElf. For historic compatibility TFE use the 1994 tfm ELD79 to WGS 84 (3) (code 1861) rather than this transformation.",Oil Exploration,2786,29.62,30.06,17.14,17.5,1,0,9606,-194.513,-63.978,-25.759,-3.4027,3.756,-3.352,-0.9175,0
-129,1863,4159,4326,"Derived for the Great Man-made River Authority (GMRA).",Engineering survey and oil exploration,2786,29.62,30.06,17.14,17.5,1,0,9607,-389.691,64.502,210.209,-0.086,-14.314,6.39,0.9264,0
-130,15707,4159,4326,"Used by Petrocanada and previous licence holders in Amal field, concession 12.",Oil exploration and production,2987,29.1,29.8,20.8,21.4,1,0,9603,-118.996,-111.177,-198.687,,,,,0
-131,15778,4159,4326,"Derived by Total at stations SDL 130-03, 04 and 05 in May 2005.",Oil exploration and production.,3142,27.5,28.07,21.25,21.58,1,0,9603,-114.7,-98.5,-150.7,,,,,0
-132,15909,4159,4326,Derived at 29 stations throughout Libya in May 2006.,For applications to an accuracy of 5 metres.,3271,19.5,33.22,9.31,25.21,1,0,9603,-115.8543,-99.0583,-152.4616,,,,,1
-133,15923,4159,4326,"Derived by SDL for Total in Cyrenaica blocks 2 & 4.",Oil and gas exploration.,3477,32,32.79,22.5,23,1,0,9603,-117.7,-100.3,-152.4,,,,,0
-134,1080,4672,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,2889,-44.64,-43.31,-177.24,-175.55,1,0,9603,175,-38,113,,,,,1
-135,1081,4673,4326,Derived at 4 stations using concatenation through WGS72. Parameter vales are also used to transform CI1979 to NZGD2000 - see tfm code 1082.,For applications requiring 2m accuracy.,2889,-44.64,-43.31,-177.24,-175.55,1,0,9607,174.05,-25.49,112.57,0,0,-0.554,0.2263,1
-136,15894,4674,4326,,Accuracy 1m.,3418,-59.86,32.72,-122.18,-25.28,1,0,9603,0,0,0,,,,,1
-137,1070,4675,4326,Derived at 5 stations.,For military purposes only. Accuracy 3m in each axis.,3255,13.19,13.7,144.58,145,1,0,9603,-100,-248,259,,,,,1
-138,1682,4164,4326,"Parameter values taken from South Yemen to Yemen NGN96 (1) (code 1539) assuming that NGN96 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 5m level.",1340,12.55,19,43.37,53.13,1,0,9603,-76,-138,67,,,,,1
-139,1547,4165,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,3258,10.88,12.68,-16.76,-13.64,1,0,9603,-173,253,27,,,,,1
-140,1065,4678,4326,Derived at 25 stations.,Accuracy 5m.,1138,13.93,22.5,100.09,107.7,1,0,9603,44.585,-131.212,-39.544,,,,,1
-141,1565,4167,4326,,Assumes NZGD2000 is coincident to WGS 84 to the 1m accuracy level.,1175,-55.95,-25.89,160.61,-171.2,1,0,9603,0,0,0,,,,,1
-142,1569,4168,4326,Derived at 3 common points.,Military survey,1104,1.4,11.16,-3.79,2.1,1,0,9603,-199,32,322,,,,,1
-143,15495,4168,4326,Derived via WGS 72BE. Found in use within oil industry erroneously concatenated via WGS 72. See tfm code 8571.,Oil industry.,1505,1.4,6.06,-3.79,2.1,1,0,9606,-171.16,17.29,325.21,0,0,0.814,-0.38,0
-144,1577,4169,4326,Transformation based on observations at 2 stations in 1993.,For military purposes. One sigma uncertainty is 25m in each axis.,3109,-14.43,-14.12,-170.87,-169.39,1,0,9603,-115,118,426,,,,,1
-145,1581,4170,4326,,For military purposes. Accuracy 1m in each axis.,3448,-59.86,16.75,-113.2,-26.01,1,0,9603,0,0,0,,,,,1
-146,1671,4171,4326,"Parameter values from RGF93 to ETRS89 (1) (code 1591) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level.",1096,41.15,51.56,-9.86,10.38,1,0,9603,0,0,0,,,,,1
-147,1598,4172,4326,,"?",1033,-58.4,-21.78,-73.58,-52.63,1,1,9603,0,0,0,,,,,0
-148,1678,4173,4326,Assumes that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. IRENET95 is a regional realisation of ETRS89.,"Approximation at the +/- 1m level.",1305,51.4,55.43,-10.56,-5.35,1,0,9603,0,0,0,,,,,1
-149,15738,4686,4326,,MAGNA-SIRGAS is a realisation of WGS 84 coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1070,-4.24,15.5,-84.77,-66.87,1,0,9603,0,0,0,,,,,1
-150,1614,4175,4326,"Determined at 8 stations. Info. source has the source CRS as Sierra Leone 1960. Sierra Leone 1968 is a readjustment of the 1960 network: coordinates changed by less than 3 metres.","Accuracy +/- 15m in each axis.",3306,6.88,10,-13.34,-10.26,1,0,9603,-88,4,101,,,,,1
-151,1890,4176,4326,For many purposes Australian Antarctic can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that Australian Antarctic is equivalent to WGS 84.",1278,-90,-60,45,160,1,0,9603,0,0,0,,,,,1
-152,15773,4689,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN63 Hiva Oa to RGPF (1) (tfm code 15761).","Accuracy +/- 1 metre.",3131,-9.88,-9.65,-139.22,-138.76,1,0,9607,410.721,55.049,80.746,-2.5779,-2.3514,-0.6664,17.3311,1
-153,15774,4689,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN63 Hiva Oa to RGPF (2) (tfm code 15762).","Accuracy +/- 2 metres.",3132,-10.07,-9.87,-139.19,-138.98,1,0,9607,374.716,-58.407,-0.957,-16.2111,-11.4626,-5.5357,-0.5409,0
-154,1675,4178,4326,"Parameter values from Pulkovo 1942(83) to ETRS89 (1) (code 1674) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.",Residuals under 2 m.,1343,50.2,54.73,9.92,15.03,1,0,9607,24,-123,-94,-0.02,0.25,0.13,1.1,0
-155,15996,4178,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1119,45.75,48.58,16.11,22.89,1,0,9603,28,-121,-77,,,,,0
-156,15998,4178,4326,Derived at 6 stations.,"For military purposes only. Accuracy 3m, 3m and 2m in X, Y and Z axes.",1306,47.74,51.05,12.09,22.56,1,0,9603,26,-121,-78,,,,,1
-157,1645,4179,4326,"Parameter values from Pulkovo 1942(58) to ETRS89 (1) (code 1644). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3293,49,54.89,14.15,24.14,1,0,9606,33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84,1
-158,15496,4179,4326,,Oil exploration,1197,43.45,48.26,20.26,31.41,1,0,9603,44.107,-116.147,-54.648,,,,,0
-159,15497,4179,4326,Derived at 4 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.45,48.26,20.26,31.41,1,0,9603,28,-121,-77,,,,,0
-160,15995,4179,4326,"Parameter values taken from Pulkovo 1942(58) to ETRS89 (4) (code 15994) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy of 1.5 to 3 metres horizontal, 3 to 5m vertical.",1197,43.45,48.26,20.26,31.41,1,0,9607,2.329,-147.042,-92.08,0.309,-0.325,-0.497,5.69,0
-161,15997,4179,4326,Derived at 11 stations.,"For military purposes only. Accuracy 4m, 2m and 4m in X, Y and Z axes.",3293,49,54.89,14.15,24.14,1,0,9603,23,-124,-82,,,,,0
-162,15999,4179,4326,Derived at 7 stations.,For military purposes. Accuracy 3m in each axis.,3212,39.64,42.66,19.22,21.05,1,0,9603,24,-130,-92,,,,,0
-163,1649,4180,4326,"Parameter values taken from EST97 to ETRS89 (1) (code 1648). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1090,57.52,59.99,20.37,28.19,1,0,9603,0,0,0,,,,,1
-164,1643,4181,4326,"Parameter values from Luxembourg 1930 to ETRS89 (1) (code 1642). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1146,49.45,50.18,5.73,6.52,1,0,9606,-193,13.7,-39.3,-0.41,-2.933,2.688,0.43,0
-165,5486,4181,4326,"Parameter values from Luxembourg 1930 to ETRS89 (3) (code 5485) assuming ETRS89 and WGS 84 are coincident within the one metre level. Replaces tfm code 1643. For an equivalent transformation using the Molodensky-Badekas method see code 5484.",For applications to an accuracy of 1 metre.,1146,49.45,50.18,5.73,6.52,1,0,9607,-189.6806,18.3463,-42.7695,0.33746,3.09264,-2.53861,0.4598,1
-166,1210,4694,4326,,POSGAR 94 is a local realisation of WGS 84.,1033,-58.4,-21.78,-73.58,-52.63,1,0,9603,0,0,0,,,,,1
-167,1886,4183,4326,Derived at 5 stations.,For military purposes only. Accuracy 3m in each axis.,1301,38.32,39.14,-28.9,-26.97,1,0,9603,-104,167,-38,,,,,1
-168,1885,4184,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,1345,36.88,37.96,-25.91,-24.62,1,0,9603,-203,141,53,,,,,1
-169,15794,4708,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1069,-12.25,-12.08,96.77,96.92,1,0,9603,-491,-22,435,,,,,1
-170,15850,4698,4326,"Also published in US NIMA/NGA TR8350.2 which gives accuracy of +/-25m in each axis and states that derived at one station.","Accuracy +/- 10 metres.",2816,-49.78,-48.6,68.69,70.62,1,0,9603,145,-187,103,,,,,1
-171,15784,4699,4326,Derived at 17 stations in 1994 by University of East London. Residuals less than 2m.,Accuracy 2m.,3209,-20.57,-19.94,57.25,57.85,1,0,9603,-770.1,158.4,-498.2,,,,,1
-172,1955,4188,4326,"Parameter values from TM75 to ETRS89 (2) (code 1953). Assumes each pair of (i) OSNI 1952 and TM75, and (ii) ETRS89 and WGS 84, can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,2530,53.96,55.35,-8.17,-5.35,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
-173,1768,4189,4326,,"Approximation at the +/- 1m level.",1251,0.65,16.75,-73.38,-58.95,1,0,9603,0,0,0,,,,,1
-174,1773,4190,4326,,"Approximation at the +/- 1m level.",1033,-58.4,-21.78,-73.58,-52.63,1,0,9603,0,0,0,,,,,1
-175,15780,4190,4326,,"Approximation at the +/- 1m level.",1033,-58.4,-21.78,-73.58,-52.63,1,1,9603,0,0,0,,,,,0
-176,15873,4192,4326,Derived at Manoca tower assuming the pyramid on the tower and the centre of the tower reservoir are co-located. This assumption carries a few metres uncertainty.,Oil exploration.,2555,2.17,4.98,8.45,10.39,1,0,9603,-206.1,-174.7,-87.7,,,,,1
-177,1796,4193,4326,"Derived at two points, checked at a third by Stolt Comex Seaway and Geoid for Elf.",Oil industry,2555,2.17,4.98,8.45,10.39,1,0,9603,-70.9,-151.8,-41.4,,,,,1
-178,1797,4194,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m, 25m and 32m in X, Y and Z axes.",3362,59.74,79,-73.28,-42.52,1,0,9603,164,138,-189,,,,,1
-179,1798,4194,4326,,Topographic mapping.,3362,59.74,79,-73.28,-42.52,1,0,9606,163.511,127.533,-159.789,0,0,0.814,-0.6,0
-180,1799,4195,4326,,Topographic mapping.,2570,68.66,74.58,-29.68,-19.89,1,0,9606,105,326,-102.5,0,0,0.814,-0.6,1
-181,1800,4196,4326,,Topographic mapping.,2571,65.52,65.9,-38.86,-36.82,1,0,9606,-45,417,-3.5,0,0,0.814,-0.6,1
-182,15796,4709,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,3200,24.68,24.88,141.21,141.42,1,0,9603,145,75,-272,,,,,1
-183,15798,4710,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,3183,-16.07,-15.85,-5.84,-5.6,1,0,9603,-320,550,-494,,,,,1
-184,15799,4711,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1872,24.23,24.35,153.92,154.05,1,0,9603,124,-234,-25,,,,,1
-185,1281,4200,4326,"Derived through concatenation of Pulkovo 1995 to PZ-90 (1) (tfm code 1257) and PZ-90 to WGS 84 (2) (tfm code 1244). Mandated for use in Russia by GOST R 51794-2001, but this has been superseded by GOST R 51794-2008. Replaced by tfm code 5043.",Accuracy 1 metre.,1198,39.88,85.19,18.93,-168.97,1,0,9607,24.82,-131.21,-82.66,0,0,-0.16,-0.12,0
-186,5043,4200,4326,"Derived through concatenation of Pulkovo 1995 to PZ-90.02 to WGS 84. Replaces Pulkovo 1995 to WGS 84 (1), tfm code 1281.",Accuracy 1 metre.,1198,39.88,85.19,18.93,-168.97,1,0,9607,24.47,-130.89,-81.56,0,0,-0.13,-0.22,1
-187,1100,4201,4326,Derived at 22 stations.,For military purposes only. Accuracy 5m in each axis.,1271,3.41,22.23,21.83,47.99,1,0,9603,-166,-15,204,,,,,1
-188,1101,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Burkino Faso.",For military purposes. Accuracy 25m in each axis.,1057,9.4,15.08,-5.52,2.4,1,0,9603,-118,-14,218,,,,,0
-189,1102,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Cameroon.",For military purposes. Accuracy 25m in each axis.,3226,1.65,13.08,8.45,16.21,1,0,9603,-134,-2,210,,,,,0
-190,1103,4201,4326,Derived at 8 stations.,For military purposes. Accuracy 3m in each axis.,1091,3.41,14.88,32.99,47.99,1,0,9603,-165,-11,206,,,,,0
-191,1104,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Mali.",For military purposes. Accuracy 25m in each axis.,1153,10.14,25,-12.24,4.25,1,0,9603,-123,-20,220,,,,,0
-192,1105,4201,4326,"Derived at 2 stations connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Senegal.",For military purposes. Accuracy 25m in each axis.,3304,12.3,16.69,-17.58,-11.37,1,0,9603,-128,-18,224,,,,,0
-193,1106,4201,4326,Derived at 14 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",3311,3.49,22.23,21.83,38.66,1,0,9603,-161,-14,205,,,,,0
-194,1108,4202,4326,Derived at 105 stations.,For military purposes only. Accuracy 3m in each axis.,2575,-43.7,-9.87,112.85,153.68,1,0,9603,-133,-48,148,,,,,0
-195,1665,4202,4326,"Parameter values from AGD66 to GDA94 (2) (code 1458). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in A.C.T. 1m accuracy.,2283,-35.92,-35.13,148.76,149.4,1,0,9607,-129.193,-41.212,130.73,-0.246,-0.374,-0.329,-2.955,0
-196,1666,4202,4326,"Parameter values from AGD66 to GDA94 (4) (code 1460). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in NSW and Victoria. 1m accuracy.,2286,-39.2,-28.16,140.96,153.68,1,0,9607,-119.353,-48.301,139.484,-0.415,-0.26,-0.437,-0.613,0
-197,1667,4202,4326,"Parameter values from AGD66 to GDA94 (8) (code 1594). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in Tasmania. 1m accuracy.,1282,-43.7,-39.52,143.77,148.54,1,0,9607,-120.271,-64.543,161.632,-0.217,0.067,0.129,2.499,0
-198,1668,4202,4326,"Parameter values from AGD66 to GDA94 (9) (code 1595). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in Northern Territory. 1m accuracy.,2284,-26,-10.86,129,138,1,0,9607,-124.133,-42.003,137.4,0.008,-0.557,-0.178,-1.854,0
-199,5841,4202,4326,Derived at 25 stations in 2007.,"Accuracy 2m in 2007. Due to significant tectonic activity in PNG, AGD66 and WGS 84 are separating by approximately 7cm per year.",4013,-8.28,-5.6,142.24,144.74,1,0,9603,-124,-60,154,,,,,0
-200,15788,4202,4326,"Parameter values from AGD66 to GDA94 (1) (code 1278). Derived at 162 stations. Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",5m accuracy.,2575,-43.7,-9.87,112.85,153.68,1,0,9603,-127.8,-52.3,152.9,,,,,0
-201,15980,4202,4326,"Parameter values from AGD66 to GDA94 (12) (code 15979). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation. Use only offshore: onshore tfms 1665-68 for ACT, NSW/Vic, Tas and NT respectively are more accurate.",3m accuracy.,3559,-47.19,-8.88,109.23,163.19,1,0,9607,-117.808,-51.536,137.784,-0.303,-0.446,-0.234,-0.29,1
-202,1109,4203,4326,"Derived at 90 stations. Note: AGD84 officially adopted only in Queensland, South Australia and Western Australia.",For military purposes only. Accuracy 2m in each axis.,2575,-43.7,-9.87,112.85,153.68,1,0,9603,-134,-48,149,,,,,1
-203,1236,4203,4326,"""Higgins parameters"". Replaced by AGD84 to GDA94 (2) (code 1280) and AGD84 to WGS 84 (7) (code 1669). Note: AGD84 officially adopted only in Queensland, South Australia and Western Australia.",Preliminary estimate.,2575,-43.7,-9.87,112.85,153.68,1,0,9607,-116,-50.47,141.69,-0.23,-0.39,-0.344,0.0983,0
-204,1669,4203,4326,"Parameter values from AGD84 to GDA94 (2) (code 1280). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces AGD84 to WGS 84 (2) (code 1236). Note: AGD84 officially adopted only in Qld, SA and WA.",1m accuracy.,2575,-43.7,-9.87,112.85,153.68,1,0,9607,-117.763,-51.51,139.061,-0.292,-0.443,-0.277,-0.191,0
-205,15789,4203,4326,"Parameter values from AGD84 to GDA94 (1) (code 1279). Derived at 327 stations. Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the tfm. AGD84 officially adopted only in Queensland, South Australia and Western Australia.",5m accuracy.,2575,-43.7,-9.87,112.85,153.68,1,0,9603,-128.5,-53,153.4,,,,,0
-206,1055,4204,4326,Derived at station K1.,1 metre accuracy.,3267,28.54,30.08,46.55,48.47,1,0,9603,-145.7,-249.1,1.5,,,,,0
-207,1056,4204,4326,"Derivation is more precise, but no evidence that accuracy is better than Ain el Abd to WGS 84 (3). OGP recommends using Ain el Abd to WGS 84 (3).",1 metre accuracy.,3267,28.54,30.08,46.55,48.47,1,0,9607,-85.645,-273.077,-79.708,-2.289,1.421,-2.532,3.194,0
-208,1057,4204,4326,.,1 metre accuracy.,2956,29.1,30.08,46.55,48.42,1,0,9607,-202.234,-168.351,-63.51,-3.545,-0.659,1.945,2.1,0
-209,1058,4204,4326,,1 metre accuracy.,2957,28.54,29.44,46.55,48.47,1,0,9607,-18.944,-379.364,-24.063,-0.04,0.764,-6.431,3.657,0
-210,1110,4204,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,3943,25.54,26.34,50.4,50.84,1,0,9603,-150,-250,-1,,,,,0
-211,1111,4204,4326,Derived at 9 stations.,For military purposes. Accuracy 10m in each axis.,3303,15.62,32.15,34.52,55.67,1,0,9603,-143,-236,7,,,,,1
-212,1107,4205,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3308,-1.71,12.03,40.99,51.46,1,0,9603,-43,-163,45,,,,,1
-213,15805,4718,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3198,-8.85,-7.52,156.45,158.19,1,0,9603,230,-199,-752,,,,,1
-214,15807,4718,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3197,-9.98,-9.21,159.55,160.88,1,0,9603,252,-209,-751,,,,,0
-215,1656,4207,4326,"Parameter values from Lisbon to ETRS89 (1) (code 1655). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by Lisbon to WGS 84 (4) (code 1988).",For applications to an accuracy of 3 metres.,1294,36.96,42.15,-9.55,-6.19,1,0,9606,-280.9,-89.8,130.2,-1.721,0.355,-0.371,-5.92,0
-216,1944,4207,4326,"Parameter values from Lisbon to ETRS89 (2) (code 1790). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 2 metres.,1294,36.96,42.15,-9.55,-6.19,1,1,9606,-282.1,-72.2,120,-1.592,0.145,-0.89,-4.46,0
-217,1984,4207,4326,,For low resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9603,-304.046,-60.576,103.64,,,,,1
-218,1988,4207,4326,,For medium resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9607,-288.885,-91.744,126.244,1.691,-0.41,0.211,-4.598,0
-219,1549,4208,4326,,Oil exploration.,2307,-28.4,-17.59,-48.79,-35.19,1,1,9603,-158,315,-148,,,,,0
-220,1550,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2308,-9.8,-8.4,-39.03,-37.09,1,0,9603,-139.62,290.53,-150.29,,,,,0
-221,1551,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2309,-10.6,-9.8,-39.13,-38,1,0,9603,-141.15,293.44,-150.56,,,,,0
-222,1552,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2310,-12.26,-10.6,-39.07,-37.99,1,0,9603,-142.48,296.03,-149.74,,,,,0
-223,10089,4208,4326,"Used by ExxonMobil for block BMS1. See WGS 84 (13) (tfm code 5051) which Petrobras now recommends for the area.",Oil exploration.,2962,-28.4,-22.67,-48.79,-40.2,1,0,9603,-163.466,317.396,-147.538,,,,,0
-224,10090,4208,4326,"Used by ExxonMobil for block BC10. Derived from earlier Shell position vector tfm of dX = -181m, dY = +294m, dZ = -144.5m, rX = rY = 0, rZ = +0.554s, dS = +0.219 ppm. See Aratu to WGS 84 (14) (tfm code 5053) which Petrobras now recommends for the area.",Oil exploration.,2963,-25.91,-20.45,-42.03,-37.11,1,0,9603,-170,305,-145,,,,,0
-225,10091,4208,4326,"Used by ExxonMobil for block BMES1. See Aratu to WGS 84 (15) (tfm code 5055) which Petrobras now recommends for the area.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.19,1,0,9603,-162.904,312.531,-137.109,,,,,0
-226,10092,4208,4326,"Used by ExxonMobil for block BP1. Also used by BG as part of a concatenated tfm to SAD69 for offshore regional studies. See WGS 84 (13) (tfm code 5051) for transformation Petrobras now recommends for the area.",Oil exploration.,2965,-35.71,-28.12,-53.37,-44.71,1,0,9603,-158,309,-151,,,,,0
-227,10093,4208,4326,"Used by ExxonMobil for offshore regional studies. See Aratu to WGS 84 (13) through (21) (tfm codes 5051-67 [odd numbers only]) which Petrobras now recommends for various areas.",Oil exploration.,2966,-34,-18,-53.37,-35.2,1,0,9603,-161,308,-142,,,,,0
-228,10094,4208,4326,Derived by IGN in 1992 at 7 stations within Nouakchott city.,Oil exploration.,2972,17.9,18.25,-16.1,-15.83,1,1,9603,124.5,-63.5,-281,,,,,0
-229,5051,4208,4326,"Parameters from Aratu to SIRGAS 2000 (1) (tfm code 5050) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfm codes 15711 and 15734.",Oil exploration.,3700,-35.71,-22.67,-53.37,-40.2,1,0,9603,-157.84,308.54,-146.6,,,,,0
-230,5053,4208,4326,"Parameters from Aratu to SIRGAS 2000 (2) (tfm code 5052) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfm codes 15710 and 15754.",Oil exploration.,2963,-25.91,-20.45,-42.03,-37.11,1,0,9603,-160.31,314.82,-142.25,,,,,0
-231,5055,4208,4326,"Parameters from Aratu to SIRGAS 2000 (3) (tfm code 5054) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfms 15712 and 15754.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.19,1,0,9603,-161.11,310.25,-144.64,,,,,0
-232,5057,4208,4326,"Parameters from Aratu to SIRGAS 2000 (4) (tfm code 5056) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3699,-17.7,-13.02,-39.21,-34.61,1,0,9603,-160.4,302.29,-144.19,,,,,0
-233,5059,4208,4326,"Parameters from Aratu to SIRGAS 2000 (5) (tfm code 5058) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3692,-13.57,-11.19,-39.08,-35.31,1,0,9603,-153.54,302.33,-152.37,,,,,0
-234,5061,4208,4326,"Parameters from Aratu to SIRGAS 2000 (6) (tfm code 5060) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfms 1550-1552.",Oil exploration.,3693,-12.26,-8.4,-39.13,-37.09,1,0,9603,-151.5,300.09,-151.15,,,,,0
-235,5063,4208,4326,"Parameters from Aratu to SIRGAS 2000 (7) (tfm code 5062) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3696,-13.57,-8.73,-37.33,-32.02,1,0,9603,-156.8,298.41,-147.41,,,,,0
-236,5065,4208,4326,"Parameters from Aratu to SIRGAS 2000 (8) (tfm code 5064) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation.Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3697,-10.16,-4.61,-35.09,-29.14,1,0,9603,-157.4,295.05,-150.19,,,,,0
-237,5067,4208,4326,"Parameters from Aratu to SIRGAS 2000 (9) (tfm code 5066) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3698,-6.5,4.25,-44.79,-26.01,1,0,9603,-151.99,287.04,-147.45,,,,,1
-238,15710,4208,4326,"Replaced by Aratu to WGS 84 (14) (tfm code 5053) which Petrobras now recommends for the area.",Oil exploration.,2963,-25.91,-20.45,-42.03,-37.11,1,0,9603,-160,315,-142,,,,,0
-239,15711,4208,4326,"Replaced by Aratu to WGS 84 (13) (tfm code 5051) which Petrobras now recommends for the area.",Oil exploration.,2962,-28.4,-22.67,-48.79,-40.2,1,0,9603,-158,309,-147,,,,,0
-240,15712,4208,4326,"Replaced by Aratu to WGS 84 (15) (tfm code 5055) which Petrobras now recommends for the area.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.19,1,0,9603,-161,310,-145,,,,,0
-241,15754,4208,4326,"Mean for 3 basins. See Aratu to WGS 84 (10) through (12) (codes 15710-12) for transformations for individual basins. Replaced by Aratu to WGS 84 (13) through (15) (tfm codes 5051, 5053 and 5055) which Petrobras now recommends for the areas.",Oil exploration.,2307,-28.4,-17.59,-48.79,-35.19,1,0,9603,-158,315,-148,,,,,0
-242,1113,4209,4326,Derived at 41 stations.,"For military purposes only. Accuracy 20m, 33m and 20m in X, Y and Z axes.",2312,-30.65,-8.19,20,35.92,1,0,9603,-143,-90,-294,,,,,1
-243,1114,4209,4326,Derived at 9 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1051,-26.88,-17.78,20,29.37,1,0,9603,-138,-105,-289,,,,,0
-244,1115,4209,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,1058,-4.45,-2.3,28.98,30.85,1,1,9603,-153,-5,-292,,,,,0
-245,1116,4209,4326,Derived at 5 stations.,"For military purposes. Accuracy 3m, 3m and 8m in X, Y and Z axes.",1141,-30.65,-28.57,27.01,29.46,1,0,9603,-125,-108,-295,,,,,0
-246,1117,4209,4326,Derived at 6 stations.,"For military purposes. Accuracy 9m, 24m and 8m in X, Y and Z axes.",1150,-17.14,-9.38,32.68,35.92,1,0,9603,-161,-73,-317,,,,,0
-247,1118,4209,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1224,-27.32,-25.73,30.8,32.13,1,0,9603,-134,-105,-295,,,,,0
-248,1119,4209,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1259,-13.46,5.38,11.8,31.3,1,1,9603,-169,-19,-278,,,,,0
-249,1120,4209,4326,Derived at 5 stations.,"For military purposes. Accuracy 21m, 21m and 27m in X, Y and Z axes.",1260,-18.07,-8.19,22,33.7,1,0,9603,-147,-74,-283,,,,,0
-250,1121,4209,4326,Derived at 10 stations.,"For military purposes. Accuracy 5m, 8m and 11m in X, Y and Z axes.",1261,-22.41,-15.62,25.24,33.07,1,0,9603,-142,-96,-293,,,,,0
-251,1122,4210,4326,Derived at 25 stations.,For military purposes only. Accuracy 20m in each axis.,2311,-11.74,4.62,29.34,41.91,1,0,9603,-160,-6,-302,,,,,1
-252,1284,4210,4326,Derived at 24 stations.,"For military purposes. Accuracy 4m, 3m and 3m in X, Y and Z axes.",3264,-4.72,4.62,33.91,41.91,1,0,9603,-157,-2,-299,,,,,0
-253,1285,4210,4326,Derived at 12 stations.,"For military purposes. Accuracy 6m, 9m and 10m in X, Y and Z axes.",3316,-11.74,-1,29.34,40.48,1,0,9603,-175,-23,-303,,,,,0
-254,3998,4210,4326,"Derived at 3 stations. From inspection of parameter values and geographic applicability of CRS, OGP believes that the published source CRS (Arc 1950) has been misidentified by information source. Analysis of TR8350.2 contour charts suggest Arc 1960.",For military purposes. Accuracy 20m in each axis.,1058,-4.45,-2.3,28.98,30.85,1,0,9603,-153,-5,-292,,,,,0
-255,1123,4211,4326,"Note: The area of use cited for this transformation (Sumatra) is not consistent with the area of use (Java) for the Batavia (Genuk) coordinate reference system. Derived at 5 stations.",For military purposes. Accuracy 3m in each axis.,1355,-5.98,5.96,95.16,106.13,1,0,9603,-377,681,-50,,,,,1
-256,1813,4211,4326,Used by ARCO offshore NW Java area.,Oil industry operations.,2577,-6.88,-4.08,105.78,110,1,0,9603,-378.873,676.002,-46.255,,,,,0
-257,1814,4211,4326,Used by PT Komaritim for Nippon Steel during East Java Gas Pipeline construction.,Oil industry operations.,2588,-8.46,-6.8,112.81,117,1,0,9603,-377.7,675.1,-52.2,,,,,0
-258,15793,4212,4326,"Derived at 2 stations (S40 and M1, St Annes Tower) in 2004.",Accuracy 2.5m.,3218,13,13.39,-59.71,-59.38,1,0,9603,31.95,300.99,419.19,,,,,1
-259,15809,4725,4326,"Derived at 2 satellite stations. Note: NGA online html files carry a different dZ value - OGP believe this is an erroneous transcription from the TR8350.2 line above.","Military and topographic mapping. Accuracy +/- 25m in each axis.",3201,16.67,16.78,-169.59,-169.47,1,0,9603,189,-79,-202,,,,,1
-260,6143,4726,4326,"Parameter values are taken from SIGD59 to CIGD11 (1) (code 6137) assuming that CIGD11 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1m.,3186,19.64,19.78,-80.13,-79.69,1,0,9607,8.853,-52.644,180.304,0.393,2.323,-2.96,-24.081,1
-261,15814,4726,4326,Determined from 1 satellite station.,"Military mapping. Accuracy +/- 25m in each axis.",3186,19.64,19.78,-80.13,-79.69,1,0,9603,42,124,147,,,,,0
-262,15829,4726,4326,Determined from 2 satellite stations.,"Topographic survey. Accuracy +/- 1m.",3186,19.64,19.78,-80.13,-79.69,1,0,9603,44.4,109,151.7,,,,,0
-263,15800,4713,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1081,10.94,12.71,41.76,44.15,1,0,9603,-79,-129,145,,,,,1
-264,1124,4216,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3221,32.21,32.43,-64.88,-64.62,1,0,9603,-73,213,296,,,,,1
-265,15970,4216,4326,"Parameter values from Bermuda 1957 to BDA2000 (1) (code 15969). Assumes BDA2000 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy +/- 1 metre.",3221,32.21,32.43,-64.88,-64.62,1,0,9607,-292.295,248.758,429.447,-4.9971,-2.99,-6.6906,1.0289,0
-266,15819,4729,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25 m in each axis.",3208,-25.13,-25.01,-130.16,-130.01,1,0,9603,185,165,42,,,,,1
-267,1125,4218,4326,Derived in 1987 at 7 stations.,"For military purposes. Accuracy 6m, 5m and 6m in X, Y and Z axes.",3686,-4.24,13.67,-79.1,-66.87,1,0,9603,307,304,-318,,,,,1
-268,1597,4218,4326,Derived in 1995 by WGC at first order stations Recreo and Mena via multi-day ties to 4 IGS stations. Residuals under 20cm.,Oil exploration.,2315,4.75,5.67,-73,-72.25,1,0,9603,304.5,306.5,-318.1,,,,,0
-269,15715,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (1) (tfm code 15714).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3082,9.8,12.51,-73,-71.06,1,0,9607,-806.413,-263.5,-622.671,12.4142185637707,-2.99084175323096,-39.0346863906349,-20.81616,0
-270,15717,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (2) (tfm code 15716).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3083,9.4,11.59,-76.08,-73,1,0,9607,100.783,187.382,-47,-9.22383004903209,2.42380329967319,-8.30827832824698,-13.56561,0
-271,15719,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (3) (tfm code 15718).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3084,8,9.4,-77.48,-74.4,1,0,9607,336.026,348.565,252.978,-17.2412894390071,-6.30649282215535,1.56204977191825,-5.771909,0
-272,15721,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (4) (tfm code 15720).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3085,5,9.4,-74.4,-72,1,0,9607,963.273,486.386,190.997,-16.4850360280866,-1.66882584284416,21.6928490465265,-13.89914,0
-273,15723,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (5) (tfm code 15722).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3086,5,8,-77.91,-74.4,1,0,9607,-90.29,247.559,-21.989,-8.69688534851263,-4.18803362841004,-12.8082668496251,2.181658,0
-274,15725,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (6) (tfm code 15724).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3087,3,5,-77.67,-74.4,1,0,9607,-0.562,244.299,-456.938,6.8668709851194,-8.25267346177889,-9.2967797230575,3.74656,0
-275,15727,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (7) (tfm code 15726).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3088,-1.12,3,-79.1,-74,1,0,9607,-305.356,222.004,-30.023,-9.69049385992583,1.03196819622539,-19.7573941768278,6.325747,0
-276,15729,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (8) (tfm code 15728).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3089,-4.24,7.1,-74.4,-66.87,1,0,9607,221.899,274.136,-397.554,2.80844591036278,-0.44850858891268,-2.81017234679107,-2.199943,0
-277,1126,4219,4326,Accuracy estimate not available.,For military purposes.,1287,-3.3,-1.44,105.07,108.34,1,0,9603,-384,664,-48,,,,,1
-278,1318,4220,4326,,Used for oil exploration by Conoco.,2316,-8.58,-7.75,12.58,13.39,1,0,9603,-42.01,-332.21,-229.75,,,,,0
-279,1319,4220,4326,,Used for oil exploration by Texaco.,2317,-7,-6.01,12.08,12.83,1,0,9603,-40,-354,-224,,,,,0
-280,1320,4220,4326,"Replaced by Camacupa to WGS 84 (9). Used by Shell prior to 1994.",Oil exploration prior to 1994.,2321,-7.25,-6.03,11.08,12.08,1,0,9606,-37.2,-370.6,-224,0,0,0.554,0.219,0
-281,1321,4220,4326,"Derived as mean of 123 Transit passes at station Cabo Ledo NE base in November 1990. Used by Elf for block 7 up to December 1992 then replaced by Camacupa to WGS 84 (7). Used by Total in block 8, ExxonMobil block 24, Western Geophysical for spec. data.",Oil exploration.,2320,-17.25,-6.01,8.2,13.85,1,0,9603,-41.8,-342.2,-228.2,,,,,0
-282,1322,4220,4326,"Derived at station Djeno during coordination of platform PAL F2 in February 1992. Used by Elf for block 3 up to December 1992 then replaced by Camacupa to WGS 84 (7).",Oil exploration.,2318,-7.33,-6.67,11.75,12.5,1,0,9603,-55.5,-348,-229.2,,,,,0
-283,1323,4220,4326,Derived at Luanda observatory December 1992.,Used for oil exploration by Elf for 1993 block 7 shallow water survey.,2319,-10.08,-9.42,12.66,13.38,1,0,9603,-43,-337,-233,,,,,0
-284,1324,4220,4326,"Derived at platform PAL F2 in December 1992. For use in blocks 3, 7 and 17, replaced by Camacupa to WGS 84 (10) (code 1327).","Used for oil exploration by Elf for blocks 3, 7 and 17 between December 1992 and 1994 then superseded by Camacupa to WGS 84 (10). Used by Exxon for block 15 since 1993.",2322,-10.08,-6.03,10.83,13.38,1,0,9603,-48,-345,-231,,,,,0
-285,1325,4220,4326,"Derived at platform PAL F2 in December 1992. Used by Total for block 2 between December 1992 and 1994 then replaced by Camacupa to WGS 84 (10).",Oil exploration between December 1992 and 1994.,2317,-7,-6.01,12.08,12.83,1,0,9603,-48.6,-345.1,-230.8,,,,,0
-286,1326,4220,4326,"Derived by GPS on two Topnav DGPS reference stations at Djeno and Luanda. Replaces Camacupa to WGS 84 (3). In block 18 replaced by BP from 1999 by Camacupa to WGS 84 (10).",Used by Shell since 1994.,2323,-8.33,-6.03,11.08,12.75,1,0,9606,-41.057,-374.564,-226.287,0,0,0.554,0.219,0
-287,1327,4220,4326,Derived at platform PAL F2 in 1994 by Topnav using Doris.,Used for oil exploration by Elf in blocks 3 and 17 since 1994. Used by Total in block 2 since 1994. Adopted by BP-Amoco Elf and Exxon for blocks 18 and 31-33 in 1999.,2324,-8.58,-6.01,10.41,12.83,1,0,9603,-50.9,-347.6,-231,,,,,1
-288,1127,4221,4326,Derived at 20 stations.,For military purposes. Accuracy 5m in each axis.,3843,-54.92,-21.78,-73.58,-53.65,1,0,9603,-148,136,90,,,,,1
-289,1527,4221,4326,"Derived through ties at 2 stations (Cerro Colorado and Chihuido Sur) to 4 IGS stations in February 1995",Oil exploration.,2325,-37.5,-36.15,-70.5,-70.03,1,0,9603,-154.5,150.7,100.4,,,,,0
-290,1128,4222,4326,Derived at 5 stations.,"For military purposes. Accuracy 3m, 6m and 6m in X, Y and Z axes.",3309,-34.87,-22.14,16.45,32.94,1,0,9603,-136,-108,-292,,,,,1
-291,1129,4222,4326,"Parameter values are from Cape to Hartebeesthoek94 (1) (code 1504) assuming that Hartebeesthoek94 and WGS 84 are equivalent within the accuracy of the transformation. Residuals should not exceed 15 metres.",Accuracy 15m.,3309,-34.87,-22.14,16.45,32.94,1,0,9603,-134.73,-110.92,-292.66,,,,,0
-292,1130,4223,4326,Derived at 5 stations.,"For military purposes. Accuracy 6m, 9m and 8m in X, Y and Z axes.",1236,30.23,38.4,7.49,13.66,1,0,9603,-263,6,431,,,,,1
-293,1538,4223,4326,Derived at station Chaffar January 1995.,Oil exploration.,1489,33.22,38.4,7.82,13.66,1,0,9603,-260.1,5.5,432.2,,,,,0
-294,1131,4224,4326,Derived at 6 stations.,"For military purposes. Accuracy 6m, 9m and 5m in X, Y and Z axes.",3675,-22,-19.3,-62.56,-57.81,1,0,9603,-134,229,-29,,,,,1
-295,3972,4224,4326,"Mandatory for SICAD use until 2005. Replaced by Chua to SIRGAS 2000 (tfm code 4069).","Used by governmental agencies in Distrito Federal until adoption of SIRGAS 2000 by Brazil in 2005. Legally mandated for Cartography System of Distrito Federal (SICAD) until 2005.",3619,-15.94,-15.38,-48.09,-47.1,1,0,9603,-143.87,243.37,-33.52,,,,,0
-296,4834,4224,4326,"Parameter values from Chua to SIRGAS 2000 (1) (tfm code 4069) assuming that within the tfm accuracy SIRGAS 2000 is equivalent to WGS 84.","Cartography System of Distrito Federal (SICAD)",3619,-15.94,-15.38,-48.09,-47.1,1,0,9603,-144.35,242.88,-33.2,,,,,0
-297,1132,4225,4326,Derived at 17 stations.,"For military purposes. Accuracy 5m, 3m and 5m in X, Y and Z axes.",1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-206,172,-6,,,,,1
-298,6192,4225,4326,"Formed by concatenation of tfms codes 6191 and 1877. Used by Petrobras and ANP until February 2005 when replaced by Corrego Alegre 1970-72 to WGS 84 (4) (tfm code 6194).",Medium and small scale mapping.,1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-205.57,168.77,-4.12,,,,,0
-299,6194,4225,4326,"Parameter values from Corrego Alegre to SIRGAS 2000 (2) (tfm code 6193) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Used by ANP and Petrobras from February 2005, replacing use of tfm code 6192.",Medium and small scale mapping.,1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-206.05,168.28,-3.82,,,,,0
-300,1585,4227,4326,,"?",1227,32.31,37.29,34.97,42.38,1,1,9603,-177.5,14.1,237.6,,,,,0
-301,1586,4227,4326,"Derived in 1995 by CGG for Al Furat Petroleum Company. Can be approximated using geocentric translations of dX=-174.3m, dY=+14.1m, dZ=+237.6m.",Oil exploration.,2327,35.33,35.9,39.15,40.4,1,0,9606,-175.09,1.218,238.831,-0.047,0.019,0.808,0.1698,0
-302,1587,4227,4326,Derived at four stations by Topnav in 1997.,Oil exploration.,2328,35.8,36.5,40.5,41.39,1,0,9603,-191.77,15.01,235.07,,,,,0
-303,15741,4227,4326,Derived by Elf in 1991 from tfm code 1584 concatenated with a tfm from WGS72BE to WGS84.,Oil exploration. Accuracy 5m.,2329,34.5,35.9,39.3,40.8,1,0,9603,-187.5,14.1,237.6,,,,,0
-304,15742,4227,4326,Derived for 1998 Omar seismic survey and used in 2000 for El Isba seismic survey.,Oil exploration. Accuracy 5m.,3314,32.31,37.29,35.61,42.38,1,0,9603,-190.421,8.532,238.69,,,,,1
-305,15743,4227,4326,"Derived 2005 at 5 triangulation stations and using (EGM96 geoid model +1.15m). Used by Total/DEZPC for Jafra and Mazraa seismic surveys. Can be approximated using geocentric translations of dX=-190.6m, dY=+8.8m, dZ=+239.6m.",Oil exploration. Accuracy 0.5m.,2329,34.5,35.9,39.3,40.8,1,0,9606,-83.58,-397.54,458.78,-17.595,-2.847,4.256,3.225,0
-306,1244,4740,4326,"Mandated for use in Russia by GosStandard of Russia Decree #327 of August 9, 2001. Republished but with one significant figure less precision to parameter values in GOST R 51794-2008 of December 18 2008.",Geodetic applications. Accuracy better than 0.5 metre.,1198,39.88,85.19,18.93,-168.97,1,0,9607,-1.08,-0.27,-0.9,0,0,-0.16,-0.12,0
-307,15843,4740,4326,"Derived through Glonass and GPS at 30 stations throughout USSR - Former Soviet Union (FSU).",Geodetic applications. Accuracy better than 1.5 metres.,1262,-90,90,-180,180,1,0,9607,0,0,1.5,0,0,-0.076,0,1
-308,1148,4229,4326,Derived at 14 stations.,"For military purposes. Accuracy 3m, 6m and 8m in X, Y and Z axes.",1086,21.9,33.81,24.71,37.91,1,0,9603,-130,110,-13,,,,,1
-309,1546,4229,4326,,Used for oil exploration by GUPCO.,2341,27.2,30,32.34,34.26,1,1,9603,-146.21,112.63,4.05,,,,,0
-310,1075,4230,4326,"Derived in 1987 by Geodetic for TPAO. Used on BP 1991/92 2D seismic surveys in central and eastern Turkish sector of Black Sea. In Turkey, replaced by tfm code 1784. Also adopted for use offshore Israel.",Oil Exploration,2896,31.36,43.45,28.03,41.47,1,0,9603,-89.05,-87.03,-124.56,,,,,0
-311,1087,4230,4326,,Topographic mapping.,1130,29.19,33.38,34.88,39.3,1,0,9603,-112,-110.3,-140.2,,,,,0
-312,1133,4230,4326,Derived at 85 stations. In Germany will be accepted by LBA for minerals management purposes as alternative to tfm 1052 or 1998.,"For military purposes. Accepted for minerals management in Germany. Accuracy 3m, 8m and 5m in X, Y and Z axes.",2420,34.88,71.2,-9.55,31.58,1,0,9603,-87,-98,-121,,,,,1
-313,1134,4230,4326,Derived at 52 stations.,For military purposes only. Accuracy 3m each axis.,2421,42.33,57.8,-4.87,17.17,1,0,9603,-87,-96,-120,,,,,0
-314,1135,4230,4326,Accuracy estimate not available.,For military purposes only.,2345,15.62,37.38,34.18,55.67,1,0,9603,-103,-106,-141,,,,,0
-315,1136,4230,4326,Derived at 4 stations.,For military purposes only. Accuracy 15m in each axis.,1078,32.88,36.21,29.95,35.19,1,0,9603,-104,-101,-140,,,,,0
-316,1137,4230,4326,Derived at 14 stations.,"For military purposes. Accuracy 6m, 8m and 8m in X, Y and Z axes.",2595,25.71,31.67,24.71,30,1,0,9603,-130,-117,-151,,,,,0
-317,1138,4230,4326,Derived at 40 stations.,For military purposes only. Accuracy 3m in each axis.,2343,49.12,60.89,-10.56,1.83,1,0,9603,-86,-96,-120,,,,,0
-318,1139,4230,4326,Derived at 20 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",2344,57.94,71.2,4.69,31.58,1,0,9603,-87,-95,-120,,,,,0
-319,1140,4230,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,3254,34.88,41.75,19.58,28.3,1,0,9603,-84,-95,-130,,,,,0
-320,1142,4230,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,2339,38.83,41.3,8.08,9.89,1,0,9603,-97,-103,-120,,,,,0
-321,1143,4230,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,2340,36.6,38.35,12.37,15.7,1,0,9603,-97,-88,-135,,,,,0
-322,1144,4230,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,3275,35.75,36.04,14.28,14.62,1,0,9603,-107,-88,-149,,,,,0
-323,1145,4230,4326,Derived at 18 stations.,"For military purposes only. Accuracy 5m, 6m and 3m in X, Y and Z axes.",2338,35.26,43.81,-9.55,3.39,1,0,9603,-84,-107,-120,,,,,0
-324,1245,4230,4326,Derived at 4 stations.,For military purposes only. Accuracy 25m in each axis.,1236,30.23,38.4,7.49,13.66,1,0,9603,-112,-77,-145,,,,,0
-325,1275,4230,4326,"These same parameter values are used to transform to ETRS89. See ED50 to ETRS89 (10) (code 1650).",For applications to an accuracy of 2 metres.,1096,41.15,51.56,-9.86,10.38,1,0,9603,-84,-97,-117,,,,,0
-326,1311,4230,4326,"Based on ED50 to WGS72 (precise ephemeris) 6-nations agreement of 1981 to which precise to broadcast and broadcast to WGS 84 transformations have been concatenated.",Recommended transformation for UKCS and IrishCS petroleum purposes.,2342,47.42,63.89,-16.1,10.86,1,0,9606,-89.5,-93.8,-123.1,0,0,-0.156,1.2,0
-327,1440,4230,4326,,Used in oil industry.,3254,34.88,41.75,19.58,28.3,1,0,9603,-86,-92.2,-127.5,,,,,0
-328,1612,4230,4326,"Parameter values are taken from ED50 to ETRS89 (1), code 1588. Adopted for ED50 to WGS84 transformations offshore Norway north of 62N from April 2001 when it replaced code 1590. Included in Statens Kartverk programme wsktrans from v4.0.",Oil industry offshore.,2601,62,84.16,-3.7,39.64,1,0,9606,-116.641,-56.931,-110.559,0.893,0.921,-0.917,-3.52,0
-329,1613,4230,4326,"Approximation to 1 metre of concatenated transformation ED50 to WGS 84 (14), code 8653. 8653 remains the transformation promulgated by Statens Kartverk but 1613 recommended by EPSG for practical oil industry usage.",Approximation to 1 metre for oil industry use.,2334,56.09,62,1.37,11.13,1,0,9606,-90.365,-101.13,-123.384,0.333,0.077,0.894,1.994,0
-330,1627,4230,4326,"Parameter values from ED50 to ETRS89 (4) (code 1626). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3237,54.51,57.8,8,15.24,1,0,9606,-81.1,-89.4,-115.8,0.485,0.024,0.413,-0.54,0
-331,1629,4230,4326,"Parameter values from ED50 to ETRS89 (5) (code 1628). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1105,36.01,36.16,-5.41,-4.89,1,0,9603,-116.8,-106.4,-154.4,,,,,0
-332,1631,4230,4326,"Parameter values from ED50 to ETRS89 (6) (code 1630). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2335,38.59,40.11,1.15,4.38,1,0,9606,-181.5,-90.3,-187.2,0.144,0.492,-0.394,17.57,0
-333,1633,4230,4326,"Parameter values from ED50 to ETRS89 (7) (code 1632). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2336,35.26,43.56,-7.53,3.39,1,0,9606,-131,-100.3,-163.4,-1.244,-0.02,-1.144,9.39,0
-334,1635,4230,4326,"Parameter values from ED50 to ETRS89 (8) (code 1634). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2337,41.5,43.81,-9.36,-4.5,1,0,9606,-178.4,-83.2,-221.3,0.54,-0.532,-0.126,21.2,0
-335,1784,4230,4326,"Parameter values from ED50 to ETRS89 (9) (code 1783). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 2 metres.,1237,34.43,43.45,25.62,44.82,1,0,9606,-84.1,-101.8,-129.7,0,0,0.468,1.05,0
-336,1810,4230,4326,Derived via concatenation through WGS72. The ED50 to WGS72 step is the Sepplin 1974 value for all Europe.,Oil industry exploration and production operations.,2595,25.71,31.67,24.71,30,1,0,9606,-84,-103,-122.5,0,0,0.554,0.2263,0
-337,1853,4230,4326,Derived at a single point in Galway docks.,Used by Enterprise for Corrib.,2961,53.75,55.75,-12.5,-9.5,1,0,9603,-82.31,-95.23,-114.96,,,,,0
-338,1961,4230,4326,"Parameter values taken from ED87 to WGS 84 (2) (tfm code 1960) assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3m.",Used by NAM for offshore operations.,1630,51.43,55.77,2.54,6.4,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.4428,1.218,0
-339,1985,4230,4326,May be taken as a transformation from ED50 to ETRS89 - see tfm code 5040.,For low resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9603,-87.987,-108.639,-121.593,,,,,0
-340,1989,4230,4326,,For medium resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9607,-74.292,-135.889,-104.967,0.524,0.136,-0.61,-3.761,0
-341,1998,4230,4326,"Approximation to better than 0.5m of transformation adopted in June 2003 (see ED50 to WGS 84 (35), code 1052). Acceptable to Landesbergamt for Lower Saxony and Bundesanstalt für Seeschifffahrt und Hydrographie.",Recommended transformation for Germany North Sea petroleum purposes.,2879,53.6,55.92,3.35,8.88,1,0,9606,-157.89,-17.16,-78.41,2.118,2.697,-1.434,-5.38,0
-342,1999,4230,4326,"Parameter values taken from ED87 to WGS 84 (2) (tfm code 1960) assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3m.",Used by NAM for offshore operations.,1630,51.43,55.77,2.54,6.4,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.04428,1.218,0
-343,3904,4230,4326,"Parameter values from ED87 to WGS 84 (32) (tfm code 3905), assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3-5m. Used by NAM for offshore operations until mid 2004, then replaced by tfm code 1311.","E&P operations in the Dutch sector of the North Sea.",1630,51.43,55.77,2.54,6.4,1,0,9606,-83.11,-97.38,-117.22,0.00569290865241986,-0.0446975835137458,0.0442850539012516,0.1218,0
-344,15964,4230,4326,Developed by the Portuguese Hydrographic Institute and used by the Directorate of Energy and Geology.,Hydrography and minerals management offshore Portugal.,3537,34.92,41.87,-13.86,-7.25,1,0,9603,-86.277,-108.879,-120.181,,,,,0
-345,1146,4231,4326,,"?",2330,51.04,62,-5.05,11.13,1,0,9606,-82.981,-99.719,-110.709,-0.104700015651026,0.0310016003789386,0.0804020214751182,-0.3143,0
-346,1960,4231,4326,,Scientific research.,1297,34.88,71.2,-10.56,31.58,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.04428,1.218,0
-347,3905,4231,4326,"Parameter values taken from ED87 to ETRS89 (1) (tfm code 4078) assuming that ETRS89 is coincident with WGS 84 within the accuracy of the transformation. Used as a tfm between ED50 and WGS 84 - see code 3904.",Scientific research.,1297,34.88,71.2,-10.56,31.58,1,0,9606,-83.11,-97.38,-117.22,0.00569290865241986,-0.0446975835137458,0.0442850539012516,0.1218,1
-348,1256,4232,4326,Derived at 7 stations.,"For military purposes. Accuracy 3m, 3m and 9m in X, Y and Z axes.",4009,16.6,26.41,52,59.9,1,0,9603,-346,-1,224,,,,,1
-349,1438,4232,4326,,Oil exploration.,4009,16.6,26.41,52,59.9,1,0,9606,-333.102,-11.02,230.69,0,0,0.554,0.219,0
-350,1894,4233,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1152,-3.47,8.09,69.29,77.08,1,1,9603,-133,-321,50,,,,,0
-351,15817,4727,4326,"Derived at 1 satellite station. Information source states ""provided for historical purposes only. These parameter [values] should not be used"". Replaced by Midway 1961 to WGS 84 (2) (tfm code 15818).","Military and topographic mapping. Accuracy +/- 25m in each axis.",3202,28.13,28.27,-177.45,-177.31,1,0,9603,912,-58,1227,,,,,0
-352,15818,4727,4326,"Derived at 1 satellite station. Replaces Midway 1961 to WGS 84 (1) (tfm code 15817).","Military and topographic mapping. Accuracy +/- 25m in each axis.",3202,28.13,28.27,-177.45,-177.31,1,0,9603,403,-81,277,,,,,1
-353,1152,4236,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,3315,21.88,25.33,119.26,122.05,1,0,9603,-637,-549,-203,,,,,1
-354,1242,4237,4326,"Parameter value error in info source Hungarian text but correct in English summary. Replaces HD72 to WGS 84 (2) (code 1831).",Accuracy at metre level throughout Hungary.,1119,45.75,48.58,16.11,22.89,1,0,9603,52.17,-71.82,-14.9,,,,,1
-355,1448,4237,4326,"Parameter values taken from HD72 to ETRS89 (2) (code 1449) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces HD72 to WGS 84 (1) (code 1830).","Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.",1119,45.75,48.58,16.11,22.89,1,0,9607,52.684,-71.194,-13.975,0.312,0.1063,0.3729,1.0191,0
-356,1677,4237,4326,"Parameter values taken from HD72 to ETRS89 (1) (code 1273) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level.",1119,45.75,48.58,16.11,22.89,1,1,9607,56,75.77,15.31,-0.37,-0.2,-0.21,-1.01,0
-357,1830,4237,4326,"Parameter values taken from HD72 to ETRS89 (1) (code 1829) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. OGP recommends use of newer MSZ 7222 equivalent (tfm code 1448) in preference to this transformation.","Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.",1119,45.75,48.58,16.11,22.89,1,0,9607,56,-75.77,-15.31,0.37,0.2,0.21,1.01,0
-358,1831,4237,4326,"Derived at fundamental point Szolohegy and tested at 99 stations throughout Hungary. OGP recommends use of newer transformation (tfm code 1242) in preference to this transformation.",Accuracy better than 1m in all three dimensions throughout Hungary.,1119,45.75,48.58,16.11,22.89,1,0,9603,57.01,-69.97,-9.29,,,,,0
-359,1248,4238,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,4020,-10.98,5.96,95.16,141.01,1,0,9603,-24,-15,5,,,,,1
-360,1832,4238,4326,"Derived via coordinates of 2 Pulse8 stations. Use of ID74 to WGS 84 (3) (code 1833) is recommended.",For oil industry purposes.,4020,-10.98,5.96,95.16,141.01,1,0,9606,2.691,-14.757,4.724,0,0,0.774,-0.6,0
-361,1833,4238,4326,"Parameter values from ID74 to DGN95 (1) (code 15911) assuming that DGN95 is equivalent to WGS 84 within the accuracy of the transformation.","Standard deviations of translations are 1.3, 1.1 and 3.6m, of rotations 0.11, 0.06 and 0.04 sec and ppm 0.18.",4020,-10.98,5.96,95.16,141.01,1,0,9607,-1.977,-13.06,-9.993,-0.364,-0.254,-0.689,-1.037,0
-362,1153,4239,4326,Derived at 11 stations.,"For military purposes. Accuracy 15m, 6m and 12m in X, Y and Z axes.",3317,5.63,20.45,97.35,105.64,1,0,9603,217,823,299,,,,,1
-363,1154,4240,4326,"Derived at 62 stations. Replaced by Indian 1975 to WGS 84 (2) (code 1304).","For military purposes. Accuracy 3m, 2m and 3m in X, Y and Z axes.",3741,5.63,20.45,97.35,105.64,1,0,9603,209,818,290,,,,,0
-364,1304,4240,4326,"Derived at 62 stations. Replaces Indian 1975 to WGS 84 (1) (code 1154).","For military purposes. Accuracy 3m, 2m and 3m in X, Y and Z axes.",3741,5.63,20.45,97.35,105.64,1,0,9603,210,814,289,,,,,1
-365,1537,4240,4326,Derived in 1995 at point RTSD181.,Oil exploration.,2358,6.75,8.15,102.16,103.04,1,0,9603,204.64,834.74,293.8,,,,,0
-366,1812,4240,4326,,Cadastral survey.,3317,5.63,20.45,97.35,105.64,1,0,9606,293,836,318,0.5,1.6,-2.8,2.1,0
-367,1084,4242,4326,Derived via NAD27 and WGS 72. Preliminary values derived by Survey Department but not officially promulgated.,For applications requiring 5m accuracy.,3342,17.65,18.57,-78.43,-76.17,1,0,9603,70,207,389.5,,,,,1
-368,1085,4242,4326,"Derived at 4 stations, tested at a further 9.",For applications requiring 2m accuracy.,3342,17.65,18.57,-78.43,-76.17,1,0,9603,65.334,212.46,387.63,,,,,0
-369,1086,4242,4326,"Derived at 4 stations, tested at a further 9.",For applications requiring 1m accuracy.,3342,17.65,18.57,-78.43,-76.17,1,1,9607,-33.722,153.789,94.959,8.581,4.478,-4.54,-8.95,0
-370,15927,4242,4326,"Derived at 4 stations, tested at a further 9. Also used as tfm to JAD69 to JAD2001 (see code 15926).
-Note: Info source paper contains an error in sign of dS, subsequently confirmed by primary author and NLA of Jamaica, and corrected in this record.",For applications requiring 1m accuracy.,3342,17.65,18.57,-78.43,-76.17,1,0,9607,-33.722,153.789,94.959,8.581,4.478,-4.54,8.95,0
-371,1930,4642,4326,,"Accuracy better than +/- 1 metre.",2820,-22.72,-22.49,167.37,167.61,1,1,9606,244.416,85.339,168.114,-8.9353,7.7523,12.5953,14.268,0
-372,15848,4642,4326,,"Accuracy +/- 10 metres.",2820,-22.72,-22.49,167.37,167.61,1,0,9603,-13,-348,292,,,,,1
-373,1157,4244,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3310,5.87,9.88,79.65,81.94,1,0,9603,-97,787,86,,,,,1
-374,1158,4245,4326,Derived at 6 stations.,"For military purposes. Accuracy 10m, 8m and 6m in X, Y and Z axes.",1309,1.13,6.71,99.59,104.6,1,0,9603,-11,851,5,,,,,1
-375,1059,4246,4326,,1 metre accuracy.,3267,28.54,30.08,46.55,48.47,1,0,9603,-294.7,-200.1,525.5,,,,,1
-376,1516,4247,4326,Also used for PSAD56 to WGS 84 transformations.,"Parameter values estimated accuracy: ± 2.0m; ± 2.7m; ± 1.3m respectively.",2363,3.56,10.8,-67.49,-59.8,1,0,9603,-273.5,110.6,-357.9,,,,,1
-377,1201,4248,4326,Derived at 63 stations. DMA also lists Colombia as area of applicability but PSAD56 is not used in that country.,"For military purposes only. Accuracy 17m, 27m and 27m in X, Y and Z axes.",2399,-45,12.51,-81.4,-56.47,1,0,9603,-288,175,-376,,,,,1
-378,1202,4248,4326,Derived at 5 stations.,"For military purposes only. Accuracy 5m, 11m and 14m in X, Y and Z axes.",1049,-22.9,-9.68,-69.66,-57.52,1,0,9603,-270,188,-388,,,,,0
-379,1203,4248,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2402,-21.5,-17.51,-70.48,-68.19,1,0,9603,-270,183,-390,,,,,0
-380,1204,4248,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,2403,-45,-39,-75.22,-71.11,1,0,9603,-305,243,-442,,,,,0
-381,1205,4248,4326,"Derived at 4 stations. Note that although the PSAD56 network included Colombia the CRS is not used there: see Bogota 1975 (CRS code 4218).",For military purposes. Accuracy 15m in each axis.,3229,-4.24,12.51,-79.1,-66.87,1,0,9603,-282,169,-371,,,,,0
-382,1206,4248,4326,Derived at 11 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",3241,-5,1.45,-81.03,-75.22,1,0,9603,-278,171,-367,,,,,0
-383,1207,4248,4326,Derived at 9 stations.,"For military purposes. Accuracy 6m, 14m and 5m in X, Y and Z axes.",1114,1.19,10.69,-61.39,-55.78,1,0,9603,-298,159,-369,,,,,0
-384,1208,4248,4326,Derived at 6 stations.,"For military purposes only. Accuracy 6m, 8m and 12m in X, Y and Z axes.",1189,-21.05,-0.04,-84.67,-68.67,1,0,9603,-279,175,-379,,,,,0
-385,1209,4248,4326,Derived at 24 stations.,"For military purposes only. Accuracy 9m, 14m and 15m in X, Y and Z axes.",1251,0.65,16.75,-73.38,-58.95,1,0,9603,-295,173,-371,,,,,0
-386,1582,4248,4326,Derived May 1995 by Geoid for Total. OSU91A geoid model used.,Oil exploration.,2400,-14.43,-13.57,-68.95,-67.79,1,0,9603,-259.73,173.12,-398.27,,,,,0
-387,1583,4248,4326,Derived July 1997 by Geoid from data recorded by UGA for Total. OSU91A geoid model used.,Oil exploration.,2401,-21.7,-21.09,-63.43,-62.95,1,0,9603,-307.7,265.3,-363.5,,,,,0
-388,1811,4248,4326,Used by Petrobras for shelf operations.,Oil industry exploration.,1754,-1.05,5.59,-51.64,-48,1,0,9603,-291.87,106.37,-364.52,,,,,0
-389,3990,4248,4326,"Parameter values from PSAD56 to SIRGAS 1995 (1) (code 3971). Assumes SIRGAS 1995 and WGS 84 can be considered the same to within the accuracy of the transformation.","Suitable for mapping at 1:25,000 scale and smaller.",3241,-5,1.45,-81.03,-75.22,1,0,9607,-60.31,245.935,31.008,-12.324,-3.755,7.37,0.447,0
-390,15967,4761,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84. HTRS96 is a regional realisation of ETRS89.","Accuracy +/- 1 metre.",1076,41.62,46.54,13.01,19.43,1,0,9603,0,0,0,,,,,1
-391,1159,4250,4326,Derived at 8 stations.,"For military purposes. Accuracy 2m, 3m and 2m in X, Y and Z axes.",1104,1.4,11.16,-3.79,2.1,1,0,9603,-130,29,364,,,,,1
-392,1160,4251,4326,Derived at 4 stations.,For military purposes only. Accuracy 15m in each axis.,3270,4.29,8.51,-11.51,-7.37,1,0,9603,-90,40,88,,,,,1
-393,1887,4182,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,1344,39.3,39.76,-31.34,-31.02,1,0,9603,-425,-169,81,,,,,1
-394,1982,4182,4326,Derived at 2 stations in 1999.,For low resolution applications.,1344,39.3,39.76,-31.34,-31.02,1,0,9603,-422.651,-172.995,84.02,,,,,0
-395,1161,4253,4326,Derived at 6 stations.,"For military purposes. Accuracy 8m, 11m and 9m in X, Y and Z axes.",2364,7.76,19.44,116.9,125.87,1,0,9603,-133,-77,-51,,,,,1
-396,1162,4253,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2365,5,10.52,119.77,126.65,1,0,9603,-133,-79,-72,,,,,0
-397,1529,4254,4326,"Derived through ties at 3 stations (RC03, TOTAL11 and MP12) to 3 IGS stations in November 1995",Oil exploration.,2357,-55.1,-52.59,-68.64,-63.73,1,0,9606,18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013,0
-398,1892,4254,4326,Derived at 2 stations. As the source CRS was used for the border survey this transformation is probably also applicable to adjacent areas of Argentina.,Accuracy 25m in each axis.,2805,-55.95,-52.4,-74.82,-66.34,1,0,9603,16,196,93,,,,,1
-399,1246,4255,4326,Accuracy estimate not available.,For military purposes only.,1024,29.41,38.47,60.5,74.92,1,0,9603,-333,-222,114,,,,,1
-400,1164,4256,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2369,-4.84,-4.51,55.33,55.59,1,0,9603,41,-220,-134,,,,,1
-401,1837,4257,4326,,Oil exploration.,1316,-6.53,-1.88,118.71,120.78,1,0,9603,-587.8,519.75,145.76,,,,,1
-402,1149,4258,4326,,ETRS89 and WGS 84 are realisations of ITRS coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1298,32.88,84.16,-16.1,39.64,1,0,9603,0,0,0,,,,,1
-403,1571,4258,4326,"Dutch sources also quote an equivalent transformation with parameter values dX=+593.032 dY=+26.000 dZ=+478.741m, rX rY rZ and dS as this tfm. These values belong to a different transformation method and cannot be used with the Coordinate Frame method.",Accuracy 0.5m,1172,50.75,55.77,2.54,7.21,1,1,9607,565.04,49.91,465.84,0.409394387439237,-0.359705195614311,1.86849100035057,4.0772,0
-404,1330,4259,4326,"Derived at Station Y in April 1989 using 572 transit satellite passes. Computed value for dZ was -96.42 but -96.38 has been utilised. Replaced Malongo 1987 to WGS 84 (3) (code 15791) in 1989. Replaced by Malongo 1987 to WGS 84 (2) (code 1557) in 1990.",Offshore oil exploration and production between April 1989 and June 1990.,3180,-6.03,-5.05,10.53,12.37,1,0,9603,-252.95,-4.11,-96.38,,,,,0
-405,1557,4259,4326,"Derived at station Y in July 1990 through Transit single point positioning using 187 passes by Geodetic Survey Ltd. Replaces Malongo 1987 to WGS 84 (1) (trf code 1330).",Offshore oil exploration and production from June 1990.,3180,-6.03,-5.05,10.53,12.37,1,0,9603,-254.1,-5.36,-100.29,,,,,1
-406,15791,4259,4326,"Derived via WGS 72BE by Geodetic for Chevron in 1987 by single point Transit translocation at 1 station (Malongo Y). Replaced in 1989 by Malongo 1987 to WGS 84 (1) (code 1330).",Oil industry exploration and production between September 1987 and April 1989.,3180,-6.03,-5.05,10.53,12.37,1,0,9603,-259.99,-5.28,-97.09,,,,,0
-407,1316,4260,4326,,"?",1060,1.65,13.08,8.32,16.21,1,1,9603,-70.9,-151.8,-41.4,,,,,0
-408,1166,4261,4326,Derived at 9 stations.,"For military purposes. Accuracy 5m, 3m and 3m in X, Y and Z axes.",3280,27.66,35.97,-13.23,-1.01,1,0,9603,31,146,47,,,,,1
-409,1165,4262,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1089,12.36,18.09,36.44,43.3,1,0,9603,639,405,60,,,,,1
-410,1067,4263,4326,"Used by Statoil for deep water blocks 210, 213, 217 and 218. Parameter values interpolated from Racal Survey geocentric translation contour charts for each of these four blocks and then meaned.",Oil industry exploration and production.,3817,3.25,5.54,4.42,6.28,1,0,9603,-92.1,-89.9,114.9,,,,,0
-411,1167,4263,4326,"Derived at 2 stations. Note: Minna is used in Nigeria, not Cameroon.",For military purposes only. Accuracy 25m in each axis.,3226,1.65,13.08,8.45,16.21,1,0,9603,-81,-84,115,,,,,0
-412,1168,4263,4326,Derived at 6 stations.,"For military purposes. Accuracy 3m, 6m and 5m in X, Y and Z axes.",1178,1.92,13.89,2.67,14.65,1,0,9603,-92,-93,122,,,,,1
-413,1534,4263,4326,,Oil exploration.,2371,4.22,6.95,4.36,9.45,1,1,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
-414,1754,4263,4326,"Derived at 8 stations across the Niger delta. Used by Shell SPDC throughout southern Nigeria onshore, delta and shallow offshore from 1994 and by Total in OPL246. Sometimes given with parameter values to greater resolution; values here are adequate.",Oil exploration.,2371,4.22,6.95,4.36,9.45,1,0,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
-415,1818,4263,4326,Concatenated via WGS 72BE.,Oil industry operations.,1717,1.92,6.14,2.67,7.82,1,0,9606,-89,-112,125.9,0,0,0.814,-0.38,0
-416,1819,4263,4326,Used by Shell in southern Nigeria and Total in OPL246.,Oil industry operations.,2371,4.22,6.95,4.36,9.45,1,1,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
-417,1820,4263,4326,Derived by Nortech at station L40 Minna using NNPC 1989 GPS network tied to 4 ADOS stations. Used by Conoco in OPLs 219-220 to cm precision and ExxonMobil in OPL 209 to dm precision..,Oil industry operations.,3813,3.25,5.54,4.02,6.95,1,0,9603,-93.2,-93.31,121.156,,,,,0
-418,1821,4263,4326,"Derived by Elf Petroleum Nigeria in 1994 at 3 stations (M101 onshore, offshore platforms XSW06 and XSV39) and used in OMLs 99-102 and OPLs 222-223.",Oil industry operations.,3814,3.25,4.5,7.17,8.25,1,0,9603,-88.98,-83.23,113.55,,,,,0
-419,1822,4263,4326,"Used by Shell SNEPCO for OPLs 209-213 and 316. Derived during 1990 Niger Delta control survey at 4 stations (XSU27, 30 31 and 35).",Oil industry exploration and production.,3815,4.22,6.3,3.84,5.16,1,0,9603,-92.726,-90.304,115.735,,,,,0
-420,1823,4263,4326,"Used by Shell SNEPCO for OPLs 217-223. Derived during 1990 Niger Delta control survey at 4 stations (XSU38, 41, 44 and 45).",Oil industry exploration and production.,3816,3.25,3.85,5.58,8,1,0,9603,-93.134,-86.647,114.196,,,,,0
-421,1824,4263,4326,Used by Shell SNEPCO for Gongola basin.,Oil industry exploration and production.,3824,8.78,11.63,9.41,12.12,1,0,9603,-93,-94,124,,,,,0
-422,6196,4263,4326,Used by Addax for OPL 118 and OML 124. Derived in 1999 at 4 stations during  extension into OPL 118 of control in Chevron block OML 53.,Oil industry exploration and production.,4127,5.5,5.8,6.7,7,1,0,9603,-93.179,-87.124,114.338,,,,,0
-423,15493,4263,4326,"Adopted by MPN for all joint venture operations from 1/1/1996.",Oil industry exploration and production.,3590,4,5,6,8,1,0,9603,-94.031,-83.317,116.708,,,,,0
-424,15705,4263,4326,"Derived via WGS 72(BE). Minna to WGS 72(BE) transformation derived in 1981 for Mobil E&P Nigeria (MEPCON) by Geodetic Survey through Transit translocation at six stations in southern Nigeria. Used by MEPCON in blocks OPL 215 and 221.",Oil industry exploration.,3819,3.25,4.22,5.03,7.3,1,0,9606,-83.13,-104.95,114.63,0,0,0.554,0,0
-425,15706,4263,4326,Used by Elf in Blocks OPL 222 and OPL 223 and by Mobil in 1994.,Oil industry exploration.,1717,1.92,6.14,2.67,7.82,1,0,9603,-93.6,-83.7,113.8,,,,,0
-426,15755,4263,4326,Derived in 1995 at unspecified DMA ADOS stations and Racal stations M101 and ZVS3003. Used by Elf in onshore Block OML 58.,Oil industry exploration and production. Accuracy 0.5m.,3113,5.05,5.35,6.54,6.83,1,0,9603,-90.2,-87.32,114.17,,,,,0
-427,1329,4264,4326,"Superseded in 1990 by trf Malongo 1987 to WGS 84 (2), code 1557. Malongo 1987 is an offshore extension of the Mhast cooordinate system.","Used for oil exploration by Chevron until superseded in 1990 by trf Malongo 1987 to WGS 84 (2), code 1557.",1317,-6.03,-5.05,10.53,12.18,1,1,9603,-252.95,-4.11,-96.38,,,,,0
-428,1088,4265,4326,,Oil exploration and production,2882,43.63,45.73,12.23,13.96,1,0,9603,-223.7,-67.38,1.34,,,,,0
-429,1089,4265,4326,,Oil exploration and production,2883,41.95,44.04,13.61,16.13,1,0,9603,-225.4,-67.7,7.85,,,,,0
-430,1090,4265,4326,,Oil exploration and production,2884,40.73,42.28,15.96,18.63,1,0,9603,-227.1,-68.1,14.4,,,,,0
-431,1091,4265,4326,,Marine navigation,2885,39.78,41.02,17.96,18.99,1,0,9603,-231.61,-68.21,13.93,,,,,0
-432,1092,4265,4326,,Marine navigation,2886,37.68,40.47,16.55,18.93,1,0,9603,-225.06,-67.37,14.61,,,,,0
-433,1093,4265,4326,,Marine navigation,2887,35.23,37.48,13,15.16,1,0,9603,-229.08,-65.73,20.21,,,,,0
-434,1094,4265,4326,,Marine navigation,2888,35.29,38.44,10.69,13,1,0,9603,-230.47,-56.08,22.43,,,,,0
-435,1169,4265,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2339,38.83,41.3,8.08,9.89,1,0,9603,-225,-65,9,,,,,0
-436,1660,4265,4326,"Parameter values from Monte Mario to ETRS89 (1) (code 1659). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2372,37.87,47.09,6.62,18.58,1,0,9606,-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68,1
-437,1662,4265,4326,"Parameter values from Monte Mario to ETRS89 (2) (code 1661). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2339,38.83,41.3,8.08,9.89,1,0,9606,-168.6,-34,38.6,-0.374,-0.679,-1.379,-9.48,0
-438,1664,4265,4326,"Parameter values from Monte Mario to ETRS89 (3) (code 1663). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2340,36.6,38.35,12.37,15.7,1,0,9606,-50.2,-50.4,84.8,-0.69,-2.012,0.459,-28.08,0
-439,1163,4266,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1100,-6.37,2.32,7.03,14.52,1,0,9603,-74,-130,42,,,,,1
-440,1532,4266,4326,Derived as mean of Doris determinations at 3 stations in Port Gentil area in 1994.,Oil exploration.,1100,-6.37,2.32,7.03,14.52,1,0,9603,-80.7,-132.5,41.1,,,,,0
-441,1170,4267,4326,Derived at 15 stations.,"For military purposes. Accuracy 3m, 9m and 12m in X, Y and Z axes.",2418,13,23.24,-85.01,-59.38,1,0,9603,-3,142,183,,,,,0
-442,1171,4267,4326,Derived at 19 stations.,"For military purposes only. Accuracy 8m, 3m and 5m in X, Y and Z axes.",2419,7.98,18.49,-92.29,-82.53,1,0,9603,0,125,194,,,,,0
-443,1172,4267,4326,Derived at 112 stations.,"For military purposes only. Accuracy 15m, 11m and 6m in X, Y and Z axes.",1061,40.04,86.45,-141,-47.74,1,0,9603,-10,158,187,,,,,1
-444,1173,4267,4326,Derived at 405 stations.,"For military purposes only. Accuracy 5m, 5m and 6m in X, Y and Z axes.",1323,24.41,49.38,-124.79,-66.92,1,0,9603,-8,160,176,,,,,0
-445,1174,4267,4326,Derived at 129 stations.,"For military purposes only. Accuracy 5m, 5m and 8m in X, Y and Z axes.",2389,24.41,49.38,-97.22,-66.92,1,0,9603,-9,161,179,,,,,0
-446,1175,4267,4326,Derived at 276 stations.,"For military purposes only. Accuracy 5m, 3m and 3m in X, Y and Z axes.",2390,25.84,49.05,-124.79,-89.65,1,0,9603,-8,159,175,,,,,0
-447,1176,4267,4326,Derived at 47 stations.,"For military purposes only. Accuracy 5m, 9m and 5m in X, Y and Z axes.",2412,54.35,71.4,-168.25,-129.99,1,0,9603,-5,135,172,,,,,0
-448,1177,4267,4326,Derived at 11 stations.,"For military purposes. Accuracy 5m, 3m and 5m in X, Y and Z axes.",2413,20.87,27.29,-79.03,-72.69,1,0,9603,-4,154,178,,,,,0
-449,1178,4267,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2414,23.91,24.19,-74.6,-74.37,1,0,9603,1,140,165,,,,,0
-450,1179,4267,4326,Derived at 25 stations.,"For military purposes only. Accuracy 8m, 8m and 6m in X, Y and Z axes.",2384,48.25,60,-139.04,-109.98,1,0,9603,-7,162,188,,,,,0
-451,1180,4267,4326,Derived at 25 stations.,"For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",2415,41.68,60,-102,-74.36,1,0,9603,-9,157,184,,,,,0
-452,1181,4267,4326,Derived at 37 stations.,"For military purposes only. Accuracy 6m, 6m and 3m in X, Y and Z axes.",2416,43.42,62.61,-79.85,-52.54,1,0,9603,-22,160,190,,,,,0
-453,1182,4267,4326,Derived at 17 stations.,"For military purposes only. Accuracy 5m, 5m and 3m in X, Y and Z axes.",2410,49,83.16,-136.45,-60.73,1,0,9603,4,159,188,,,,,0
-454,1183,4267,4326,Derived at 8 stations.,"For military purposes only. Accuracy 5m, 8m and 3m in X, Y and Z axes.",2417,60,69.7,-141,-123.91,1,0,9603,-7,139,181,,,,,0
-455,1184,4267,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,2385,8.82,9.44,-80.06,-79.47,1,0,9603,0,125,201,,,,,0
-456,1185,4267,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3235,19.77,23.24,-85.01,-74.08,1,0,9603,-9,152,178,,,,,0
-457,1186,4267,4326,"Derived at 2 stations. Note: NAD27 is not used in Greenland.",For military purposes. Accuracy 25m in each axis.,2386,75.86,79.19,-73.28,-60.99,1,0,9603,11,114,195,,,,,0
-458,1187,4267,4326,Derived at 22 stations.,"For military purposes only. Accuracy 8m, 6m and 6m in X, Y and Z axes.",3278,14.52,32.72,-118.46,-86.69,1,0,9603,-12,130,190,,,,,0
-459,1249,4267,4326,Derived at 6 stations.,"For military purposes only. Accuracy 6m, 8m and 10m in X, Y and Z axes.",2387,51.54,54.34,-178.3,-164.84,1,0,9603,-2,152,149,,,,,0
-460,1250,4267,4326,Derived at 5 stations.,For military purposes. Accuracy 10m in each axis.,2388,51.3,53.06,172.43,179.85,1,0,9603,2,204,105,,,,,0
-461,1530,4267,4326,,Accuracy 3m.,1077,18.83,25.5,-87.01,-73.57,1,0,9603,-4.2,135.4,181.9,,,,,0
-462,15699,4267,4326,"Developed by John E Chance and Associates at 19°44'N, 92°21'W. Geoid height used =-13.34m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3462,17.85,20.89,-94.79,-89.76,1,0,9603,-2,124.7,196,,,,,0
-463,15852,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3358,23.82,30.25,-87.25,-81.17,1,0,9603,-3,154,177,,,,,0
-464,15853,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3359,25.62,30.23,-95,-87.25,1,0,9603,-7,151,175,,,,,0
-465,15854,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3360,25.98,28.96,-97.21,-95,1,0,9603,-7,151,178,,,,,0
-466,15855,4267,4326,"Developed by John E Chance and Associates at 21°55'N, 97°20'W. Geoid height used =-17m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3361,21.51,22.75,-98.1,-96.89,1,0,9603,-8,125,190,,,,,0
-467,15856,4267,4326,"Developed by EnSoCo Inc. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).",Oil exploration and production. Accuracy 8 metres.,3357,23.82,30.25,-97.21,-81.17,1,0,9603,-7,158,172,,,,,0
-468,15913,4267,4326,"Developed by John E Chance and Associates at 21°33'N, 92°33'W. Geoid height used =-16.7m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3461,20.88,23,-94.32,-88.68,1,0,9603,0,125,196,,,,,0
-469,15978,4267,4326,,Accuracy 1m.,1077,18.83,25.5,-87.01,-73.57,1,0,9607,2.478,149.752,197.726,-0.526,-0.498,0.501,0.685,0
-470,1188,4269,4326,Derived at 354 stations.,Accuracy 2m in each axis.,1325,23.82,86.45,-172.54,-47.74,1,0,9603,0,0,0,,,,,1
-471,1251,4269,4326,Derived at 4 stations.,"For military purposes only. Accuracy 5m, 2m and 5m in X, Y and Z axes.",2157,51.3,54.34,172.43,-164.84,1,0,9603,-2,0,4,,,,,0
-472,1252,4269,4326,Derived at 6 stations.,For military purposes only. Accuracy 2m in each axis.,3883,15.56,25.58,-163.74,-151.28,1,0,9603,1,1,-1,,,,,0
-473,1308,4269,4326,"Strictly between NAD83 and ITRF94(1996.0). Superseded by NAD83 to WGS 84 (5) (code 1515).",Historical record only - superseded - see remarks.,1323,24.41,49.38,-124.79,-66.92,1,1,9607,-0.9738,1.9453,0.5486,-0.0275507901704247,-0.0100492213603585,-0.0113590028800276,0,0
-474,1515,4269,4326,"Strictly between NAD83 and ITRF96(1997.0). Supersedes NAD83 to WGS 84 (4) (code 1308).",Geodesy.,1323,24.41,49.38,-124.79,-66.92,1,1,9607,-0.991,1.9072,0.5129,-0.0257899075194932,-0.0096500989602704,-0.0116599432323421,0,0
-475,1189,4270,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,2391,20.12,20.74,58.58,59,1,0,9603,-247,-148,369,,,,,0
-476,1190,4270,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3968,24.63,28.57,47.96,50.8,1,0,9603,-243,-192,477,,,,,0
-477,1191,4270,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1243,22.63,26.26,51.51,57.13,1,0,9603,-249,-156,381,,,,,0
-478,1531,4270,4326,Parameter values adopted by Total are mean of those derived by Oceonics and Geoid through ties at platform AK1 to 4 IGS stations in March 1995.,Oil exploration.,2392,25.33,25.53,53.03,53.4,1,0,9603,-245,-153.9,382.8,,,,,0
-479,1536,4270,4326,"Derived by Brown & Root in 1992 for Qatar General Petroleum Corporation North Field development. Adopted by QGPC for all offshore Qatar.",Oil exploration.,2406,24.64,27.04,50.56,53.03,1,0,9603,-250.2,-153.09,391.7,,,,,0
-480,15871,4270,4326,Derived by concatenation of parameter values published by IGN Paris from Nahrwan 1967 to WGS 72 at the Nahrwan SE Base trig station near Baghdad with DMA WGS 72 to WGS 84 parameter values.,Oil exploration.,3625,29.06,37.38,38.79,48.61,1,0,9603,-242.2,-144.9,370.3,,,,,1
-481,15937,4270,4326,Parameter values adopted by Total are mean of those derived by Oceonics and Geoid through ties at station TC58 to 4 IGS stations in March 1995.,Oil exploration.,3509,24,25.64,51.51,54.85,1,0,9603,-245.8,-152.2,382.9,,,,,0
-482,15938,4270,4326,Derived via WGS 72BE from Transit observations at station TC58 in 1976 by BP for ADMA.,Oil exploration.,3509,24,25.64,51.51,54.85,1,0,9606,-225.4,-158.7,380.8,0,0,0.814,-0.38,0
-483,15952,4270,4326,"Used by DPC for Al Fateh field. Applying this transformation gives same result as Nahrwan 1967 to WGS 84 (8) (code 15938).",Oil exploration and production.,3530,24.95,25.79,54.07,55.3,1,0,9603,-244.2,-149.8,379.3,,,,,0
-484,15953,4270,4326,Used by Dubai Municipality before 1994.,Municipal operations.,3531,24.85,25.33,54.85,55.55,1,0,9603,-250.7,-157.9,380.4,,,,,0
-485,1192,4271,4326,"CAUTION: OGP believes that these parameter values include a blunder and that if NIMA transformation parameters are to be used the 1987 version (EPSG code 1307) be used.",For military purposes only. Accuracy given by NIMA 15m in each axis. EPSG believes there is an 8-10m blunder in dX.,1322,11.09,11.4,-60.89,-60.47,1,0,9603,-10,375,165,,,,,1
-486,1307,4271,4326,"(1) See remarks for tfm code 1192. (2) Naparima 1972 is an extension to Tobago of the Napaima 1955 geographic CRS of Trindad. In Trinidad this transformation may also be considered to use Napaima 1955 (code 4158) as its source CRS: see tfm code 1556.",For military purposes only. Accuracy 15m in each axis.,1322,11.09,11.4,-60.89,-60.47,1,0,9603,-2,374,172,,,,,0
-487,1151,4272,4326,Derived at 14 stations.,"For military purposes only. Accuracy 5m, 3m and 5m in X, Y and Z axes.",3285,-47.64,-33.9,165.87,179.26,1,0,9603,84,-22,209,,,,,0
-488,1564,4272,4326,"These parameter values are taken from NZGD49 to NZGD2000 (2) (code 1701) and assume that NZGD2000 and WGS 84 are coincident to within the accuracy of the transformation. For improved accuracy use NZGD49 to WGS 84 (4) (code 1670).",Transformation accuracy about 4 metres.,3285,-47.64,-33.9,165.87,179.26,1,0,9607,59.47,-5.04,187.44,-0.47,0.1,-1.024,-4.5993,1
-489,15975,4272,4326,"These parameter values are taken from NZGD49 to NZGD2000 (1) (code 1566) and assume that NZGD2000 and WGS 84 are coincident to within the accuracy of the tfm. For better accuracy use NZGD49 to WGS 84 (2) (code 1564) or NZGD49 to WGS 84 (3) (code 1670).",5m accuracy.,3285,-47.64,-33.9,165.87,179.26,1,0,9603,54.4,-20.1,183.1,,,,,0
-490,1654,4273,4326,"Parameter values from NGO 1948 to ETRS89 (1) (code 1653). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 3 metres.,1352,57.94,71.2,4.69,31.22,1,0,9606,278.3,93,474.5,7.889,0.05,-6.61,6.21,1
-491,1658,4274,4326,"Parameter values from Datum 73 to ETRS89 (1) (code 1657). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by Datum 73 to WGS 84 (4) (tfm code 1987).",For applications to an accuracy of 2 metres.,1294,36.96,42.15,-9.55,-6.19,1,0,9606,-238.2,85.2,29.9,0.166,0.046,1.248,2.03,0
-492,1945,4274,4326,"Parameter values from Datum 73 to ETRS89 (2) (code 1792). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1294,36.96,42.15,-9.55,-6.19,1,1,9606,-231,102.6,29.8,0.615,-0.198,0.881,1.79,0
-493,1983,4274,4326,,For low resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9603,-223.237,110.193,36.649,,,,,1
-494,1987,4274,4326,,For medium resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9607,-239.749,88.181,30.488,-0.263,-0.082,-1.211,2.229,0
-495,1193,4275,4326,"These same parameter values are used to transform to ETRS89. See NTF to ETRS89 (1) (code 1651).",For applications to an accuracy of 2 metres.,3694,41.31,51.14,-4.87,9.63,1,0,9603,-168,-60,320,,,,,1
-496,1195,4277,4326,Derived at 38 stations.,"For military purposes only. Accuracy 10m, 10m and 15m in X, Y and Z axes.",1264,49.81,60.89,-8.73,1.83,1,0,9603,375,-111,431,,,,,0
-497,1196,4277,4326,Derived at 24 stations.,"For military purposes only. Accuracy 5m, 5m and 6m in X, Y and Z axes.",2395,49.81,55.85,-6.49,1.83,1,0,9603,371,-112,434,,,,,0
-498,1197,4277,4326,Derived at 25 stations.,"For military purposes only. Accuracy 10m, 10m and 15m in X, Y and Z axes.",2396,49.81,55.85,-6.49,1.83,1,0,9603,371,-111,434,,,,,0
-499,1198,4277,4326,Derived at 13 stations.,For military purposes only. Accuracy 10m in each axis.,2397,54.58,60.89,-8.73,-0.66,1,0,9603,384,-111,425,,,,,0
-500,1199,4277,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,2398,51.28,53.47,-5.34,-2.66,1,0,9603,370,-108,434,,,,,0
-501,1314,4277,4326,"For a more accurate transformation see OSGB 1936 / British National Grid to ETRS89 (2) (code 1039): contact the Ordnance Survey of Great Britain (http://www.gps.gov.uk/gpssurveying.asp) for details.",Oil exploration. Accuracy better than 4m and generally better than 2m.,1264,49.81,60.89,-8.73,1.83,1,0,9606,446.448,-125.157,542.06,0.15,0.247,0.842,-20.489,1
-502,5622,4277,4326,Derived by CGG for 1994 3D seismic survey.,Oil exploration and production.,3893,50.54,50.8,-2.19,-1.69,1,0,9603,370.396,-108.938,435.682,,,,,0
-503,4560,4558,4326,"Approximation at the +/- 1m level assuming that RRAF91 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",2824,14.08,18.53,-63.66,-57.53,1,0,9603,0,0,0,,,,,1
-504,1074,4281,4326,"Not recognised by Survey of Israel. See Palestine 1923 to WGS 84 (2) (code 8650).","Oil Exploration. Accuracy: 1m to north and 5m to south of east-west line through Beersheba (31°15'N).",2603,29.45,33.27,34.18,35.68,1,0,9606,-275.7224,94.7824,340.8944,-8.001,-4.42,-11.821,1,1
-505,1200,4282,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1072,-6.91,3.71,8.85,18.64,1,0,9603,-148,51,-291,,,,,1
-506,1801,4282,4326,"Derived in 1994 by CGG/Topnav using DORIS system on various stations along the coastline.","?",2574,-6.91,-3.55,8.85,12.34,1,0,9603,-145,52.7,-291.6,,,,,0
-507,1802,4282,4326,Derived by Geoid for Elf in May 1995 using GPS and IGS data by tying 4 geodetic points to ITRF93 epoch 1995.4.,Used by Elf since May 1995 for all offshore Congo operations.,2574,-6.91,-3.55,8.85,12.34,1,0,9606,-178.3,-316.7,-131.5,5.278,6.077,10.979,19.166,0
-508,1150,4283,4326,,GDA94 is a realisation of WGS 84 coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,2575,-43.7,-9.87,112.85,153.68,1,0,9603,0,0,0,,,,,1
-509,1254,4284,4326,Accuracy estimate not available.,For military purposes.,1198,39.88,85.19,18.93,-168.97,1,0,9603,28,-130,-95,,,,,0
-510,1267,4284,4326,"Derived through concatenation of Pulkovo 1942 to PZ-90 (1) (tfm code 15844) and PZ-90 to WGS 84 (2) (tfm code 1244. Mandated for use in Russia by GOST R 51794-2001, but this has been superseded by GOST R 51794-2008. Replaced by tfm code 5044.",Accuracy 4 metres.,1198,39.88,85.19,18.93,-168.97,1,0,9607,23.92,-141.27,-80.9,0,-0.35,-0.82,-0.12,1
-511,1287,4284,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1119,45.75,48.58,16.11,22.89,1,1,9603,28,-121,-77,,,,,0
-512,1288,4284,4326,Derived at 11 stations.,"For military purposes only. Accuracy 4m, 2m and 4m in X, Y and Z axes.",1192,49,55.92,14.15,24.14,1,1,9603,23,-124,-82,,,,,0
-513,1289,4284,4326,Derived at 6 stations.,"For military purposes only. Accuracy 3m, 3m and 2m in X, Y and Z axes.",1306,47.74,51.05,12.09,22.56,1,1,9603,26,-121,-78,,,,,0
-514,1290,4284,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1139,55.67,58.08,19.07,28.24,1,0,9603,24,-124,-82,,,,,0
-515,1291,4284,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1131,40.59,55.44,46.5,87.35,1,0,9603,15,-130,-84,,,,,0
-516,1292,4284,4326,Derived at 7 stations.,For military purposes. Accuracy 3m in each axis.,1025,39.64,42.66,18.46,21.05,1,1,9603,24,-130,-92,,,,,0
-517,1293,4284,4326,Derived at 4 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.45,48.26,20.26,31.41,1,1,9603,28,-121,-77,,,,,0
-518,1303,4284,4326,Mean of 13 stations along entire Kazak coastline.,Residuals under 2 m.,2405,41.16,46.96,48.91,53.15,1,0,9606,43.822,-108.842,-119.585,1.455,-0.761,0.737,0.549,0
-519,1334,4284,4326,,"?",3246,57.52,59.75,21.74,28.19,1,0,9607,21.58719,-97.54127,-60.92546,-1.01378,-0.58117,-0.2348,-4.6121,0
-520,1679,4284,4326,"Parameter values taken from Pulkovo 1942 to LKS94(ETRS89) (1) (code 1274) assuming that LKS94(ETRS89) is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 9m level.",1145,53.89,56.45,19.02,26.81,1,0,9607,-40.595,-18.55,-69.339,-2.508,-1.832,2.611,-4.299,0
-521,1807,4284,4326,"Derived via WGS72 values taken from SOCAR Magnavox 1502 manual. Used by AIOC 1995-1997 then replaced by the AIOC97 values (tfm code 1808).
-Do not confuse with AIOC95 vertical datum as used in southern Caspian Sea and at Sangachal terminal by AIOC.",Oil industry operations by AIOC prior to 1997.,1038,37.9,42.58,44.78,51.73,1,0,9606,27,-135,-84.5,0,0,0.554,0.2263,0
-522,1808,4284,4326,"Mean of 3 stations in western Georgia, 4 stations in eastern Georgia and 4 stations in eastern Azerbaijan. Derived for use on AIOC early oil western export pipeline, but adopted for all AIOC work replacing the 1995 AIOC transformation (code 1807).",Oil industry operations.,2593,37.9,43.58,40,51.73,1,0,9606,686.1,-123.5,-574.4,8.045,-23.366,10.791,-2.926,0
-523,1809,4284,4326,Parameter values calculated by Elf Exploration and Production based on geodetic survey carried out by Azerbaijan State Committee for Geodesy and Cartography.,Oil industry operations.,2594,38.31,40.33,48.93,50.39,1,0,9606,926.4,-715.9,-186.4,-10.364,-20.78,26.452,-7.224,0
-524,5044,4284,4326,"Derived through concatenation of Pulkovo 1942 to PZ-90.02 to WGS 84. Replaces Pulkovo 1942 to WGS 84 (17) (code 1267).",Accuracy 3 metres.,1198,39.88,85.19,18.93,-168.97,1,0,9607,23.57,-140.95,-79.8,0,-0.35,-0.79,-0.22,0
-525,15865,4284,4326,"Derived via PZ-90 at 30 stations throughout USSR (Former Soviet Union, FSU) through concatenation of Pulkovo 1942 to PZ-90 (1) (tfm code 15844) and PZ-90 to WGS 84 (1) (tfm code 15843).",Accuracy 4.5 metres.,2423,35.15,81.9,19.58,-168.98,1,0,9607,25,-141,-78.5,0,-0.35,-0.736,0,0
-526,1561,4285,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,1346,24.56,26.2,50.7,51.67,1,0,9603,-128,-283,22,,,,,0
-527,1562,4285,4326,"Derived by Brown & Root in 1992 for Qatar General Petroleum Corporation.",Oil exploration.,2406,24.64,27.04,50.56,53.03,1,0,9603,-128.16,-282.42,21.93,,,,,1
-528,1563,4285,4326,"Derived by Qatar Centre for GIS. See Qatar 1974 to WGS 84 (2) (code 1562) for transformation used by QGPC for offshore petroleum industry.",Oil exploration.,1346,24.56,26.2,50.7,51.67,1,0,9603,-128.033,-283.697,21.052,,,,,0
-529,1211,4287,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m, 25m and 32m in X, Y and Z axes.",2407,59.75,72,-55,-40,1,1,9603,164,138,-189,,,,,0
-530,1112,4289,4326,"Replaced by Amersfoort to WGS 84 (2) (code 1672).","?",1275,50.75,53.69,3.21,7.21,1,0,9606,593.16,26.15,478.54,-1.30439800822601,-0.103297414968546,-1.14450153042326,4.0775,0
-531,1672,4289,4326,"Parameter values from Amersfoort to ETRS89 (1) (code 1751) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (1) (code 1112). Replaced by Amersfoort to WGS 84 (3) (code 15934).","Approximation at the +/- 1m level.",1275,50.75,53.69,3.21,7.21,1,0,9607,565.04,49.91,465.84,0.409394387439237,-0.359705195614311,1.86849100035057,4.0772,0
-532,4833,4289,4326,"Parameter values from Amersfoort to ETRS89 (5) (tfm code 4830) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (3) (code 15934).","Approximation at the +/- 1m level.",1275,50.75,53.69,3.21,7.21,1,0,9607,565.4171,50.3319,465.5524,0.398957388243134,-0.343987817378283,1.87740163998045,4.0725,1
-533,15934,4289,4326,"Parameter values from Amersfoort to ETRS89 (3) (tfm code 15739) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (2) (code 1672). Replaced by Amersfoort to WGS 84 (4) (tfm code 4833).","Approximation at the +/- 1m level.",1275,50.75,53.69,3.21,7.21,1,0,9607,565.2369,50.0087,465.658,0.406857330322398,-0.350732676542563,1.8703473836068,4.0812,0
-534,1212,4291,4326,Derived at 84 stations.,"For military purposes only. Accuracy 15m, 6m and 9m in X, Y and Z axes.",1341,-56.15,13,-82,-34,1,1,9603,-57,1,-41,,,,,0
-535,1213,4291,4326,Derived at 10 stations.,For military purposes only. Accuracy 5m in each axis.,1033,-58.4,-21.78,-73.58,-52.63,1,1,9603,-62,-1,-37,,,,,0
-536,1214,4291,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1049,-22.9,-9.68,-69.66,-57.52,1,1,9603,-61,2,-48,,,,,0
-537,1215,4291,4326,Derived at 22 stations.,"For military purposes only. Accuracy 3m, 5m and 5m in X, Y and Z axes.",1053,-35.71,7.04,-74,-25.28,1,1,9603,-60,-2,-41,,,,,0
-538,1216,4291,4326,Derived at 9 stations.,"For military purposes only. Accuracy 15m, 8m and 11m in X, Y and Z axes.",1066,-59.86,-17.51,-113.2,-65.73,1,1,9603,-75,-1,-44,,,,,0
-539,1217,4291,4326,Derived at 7 stations.,"For military purposes only. Accuracy 6m, 6m and 5m in X, Y and Z axes.",1070,-4.24,15.5,-84.77,-66.87,1,1,9603,-44,6,-36,,,,,0
-540,1218,4291,4326,Derived at 11 stations.,For military purposes. Accuracy 3m in each axis.,1085,-5,5,-95.35,-75.22,1,1,9603,-48,3,-44,,,,,0
-541,1219,4291,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2356,-1.41,0.17,-91.71,-89.2,1,1,9603,-47,26,-42,,,,,0
-542,1220,4291,4326,Derived at 5 stations.,"For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",1114,1.19,10.69,-61.39,-55.78,1,1,9603,-53,3,-47,,,,,0
-543,1221,4291,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1188,-27.58,-19.3,-62.64,-54.24,1,1,9603,-61,2,-33,,,,,0
-544,1222,4291,4326,Derived at 6 stations.,For military purposes. Accuracy 5m in each axis.,1189,-21.05,-0.04,-84.67,-68.67,1,1,9603,-58,0,-44,,,,,0
-545,1223,4291,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1235,9.83,12.33,-62.08,-57.29,1,1,9603,-45,12,-33,,,,,0
-546,1224,4291,4326,Derived at 5 stations.,"For military purposes only. Accuracy 3m, 6m and 3m in X, Y and Z axes.",1251,0.65,16.75,-73.38,-58.95,1,1,9603,-45,8,-33,,,,,0
-547,1548,4291,4326,"Derived by Brazilean Institute of Geography and Statistics (IGBE) in 1989. Used by ANP.",Medium and small scale mapping.,1053,-35.71,7.04,-74,-25.28,1,1,9603,-66.87,4.37,-38.52,,,,,0
-548,1225,4292,4326,Derived at 5 stations.,For military purposes. Accuracy 1m in each axis.,2355,-52.39,-51.24,-59.8,-57.65,1,0,9603,-355,21,72,,,,,1
-549,1226,4293,4326,"Derived at 3 stations. 
-Beware!  Source CRS uses German legal metres, transformation parameter values are in (International) metres. See tfm code 1271 for example.",For military purposes only. Accuracy 20m in each axis.,1169,-30.64,-16.95,8.24,25.26,1,0,9603,616,97,-251,,,,,1
-550,1271,4293,4326,"Beware!  Source CRS uses GLM, tfm param in m. Example: Schwarzeck ?=19°35'46.952""S ?=20°41'50.649""E h=1185.99m; X=5623409.386 Y=2124618.003 Z=-2125847.632 GLM; X=5623485.84m Y=2124646.89m Z=-2125876.54m; WGS 84 X=5624101.48m Y=2124748.97m Z=-2126132.35m.","?",1169,-30.64,-16.95,8.24,25.26,1,0,9603,615.64,102.08,-255.81,,,,,0
-551,1286,4294,4326,Accuracy estimate not available.,For military purposes.,2354,-4.23,4.37,108.8,119.06,1,1,9603,-403,684,41,,,,,0
-552,1834,4294,4326,Accuracy estimate not available.,For military purposes.,2354,-4.23,4.37,108.8,119.06,1,1,9603,-403,684,41,,,,,0
-553,1835,4294,4326,,Oil exploration.,1360,-4.23,4.29,114.56,119.06,1,1,9603,-387.06,636.53,46.29,,,,,0
-554,1836,4294,4326,,Oil exploration.,2770,-0.07,4.29,116.97,119.06,1,1,9603,-403.4,681.12,46.56,,,,,0
-555,1227,4297,4326,Accuracy estimate not available.,For military purposes.,1149,-26.59,-11.69,42.53,51.03,1,0,9603,-189,-242,-91,,,,,1
-556,1228,4298,4326,Derived at 8 stations.,"For military purposes. Accuracy 10m, 10m and 12m in X, Y and Z axes.",1362,0.85,7.66,109.32,119.61,1,0,9603,-679,669,-48,,,,,1
-557,1592,4298,4326,"Originally used by BSP offshore only, use extended to onshore in 2010.",Oil exploration and production.,1055,4.02,6.3,112.37,115.36,1,0,9603,-678,670,-48,,,,,0
-558,1615,4298,4326,"CARE! Erroneous GPS data was used in the derivation of these parameters. They produce a coordinate difference of 10m horizontally and 50m vertically compared to Timbalai 1948 to WGS 84 (2) (code 1592).",Topographic and engineering survey onshore.,2349,4.02,5.1,114.1,115.36,1,0,9603,-726.282,703.611,-48.999,,,,,0
-559,1852,4298,4326,"Derived by Racal Survey for SSB at 24 coastal stations (including Timbalai fundamental point and 6 other primary triangulation stations) between in Sabah (Kudat southwards) and Sarawak (Sibu northwards).",Oil exploration.,2780,1.57,7.66,109.32,117.3,1,0,9606,-533.4,669.2,-52.5,0,0,4.28,9.4,0
-560,5248,4298,4326,,Oil exploration.,1055,4.02,6.3,112.37,115.36,1,1,9607,-689.5937,623.84046,-65.93566,0.02331,-1.17094,0.80054,5.88536,0
-561,5249,4298,4326,"Parameter values taken from Timbalai 1948 to GDBD2009 (1) (code 5878) assuming that GDBD2009 is equivalent to WGS 84 within the accuracy of the transformation.",Oil exploration.,1055,4.02,6.3,112.37,115.36,1,0,9607,-689.5937,623.84046,-65.93566,0.02331,-1.17094,0.80054,5.88536,0
-562,1229,4299,4326,Derived at 7 stations.,For military purposes only. Accuracy 3m in each axis.,1305,51.4,55.43,-10.56,-5.35,1,1,9603,506,-122,611,,,,,0
-563,1641,4299,4326,"Parameter values from TM75 to ETRS89 (2) (code 1953). Assumes each pair of (i) TM65 and TM75, and (ii) ETRS89 and WGS 84, can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1305,51.4,55.43,-10.56,-5.35,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
-564,1954,4300,4326,"Parameter values taken from TM65 to ETRS89 (2) (code 1953). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1305,51.4,55.43,-10.56,-5.35,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
-565,1956,4300,4326,"Derived at 7 stations. TM75 is based on the geodetic datum of 1965 which should not be confused with the mapping adjustment of 1965 (TM65).",For military purposes only. Accuracy 3m in each axis.,1305,51.4,55.43,-10.56,-5.35,1,0,9603,506,-122,611,,,,,0
-566,1230,4301,4326,Derived at 31 stations.,"For military purposes only. Accuracy 20m, 5m and 20m in X, Y and Z axes.",2409,20.37,45.54,122.84,145.87,1,0,9603,-148,507,685,,,,,0
-567,1231,4301,4326,Derived at 16 stations.,"For military purposes only. Accuracy 8m, 5m and 8m in X, Y and Z axes.",3995,30.19,45.54,128.32,145.87,1,0,9603,-148,507,685,,,,,0
-568,1232,4301,4326,"Derived at 29 stations. Replaced by Tokyo to WGS 84 (5) (code 1305).","For military purposes only. Accuracy 8m, 5m and 8m in X, Y and Z axes.",3266,33.14,38.64,124.54,131,1,0,9603,-146,507,687,,,,,0
-569,1233,4301,4326,Derived at 3 stations.,"For military purposes only. Accuracy 20m, 5m and 20m in X, Y and Z axes.",2408,23.99,26.9,122.84,131.38,1,0,9603,-158,507,676,,,,,0
-570,1305,4301,4326,"Derived at 29 stations. Replaces Tokyo to WGS 84 (3) (code 1232).",For military purposes. Accuracy 2m in each axis.,3266,33.14,38.64,124.54,131,1,0,9603,-147,506,687,,,,,0
-571,15484,4301,4326,"Parameter values from Tokyo to JGD2000 (1) (code 15483). Assumes JGD2000 and WGS 84 can be considered the same to within the accuracy of the transformation.","Surveying, mapping and civil engineering purposes. Accuracy on main islands 9m.",3957,20.37,45.54,122.84,154.05,1,0,9603,-146.414,507.337,680.507,,,,,1
-572,1296,4302,4326,Derived in 1989 by ONI for Amoco.,Oil exploration.,1339,9.83,11.5,-62.08,-60,1,0,9603,-61.702,284.488,472.052,,,,,1
-573,10085,4302,4326,"Parameter values provided to EOG by Trinidad Ministry of Energy and Energy Industries. Used by EOG offshore Trinidad (including Pelican, Kiskadee and Ibis fields) since 1996.",Oil exploration.,1339,9.83,11.5,-62.08,-60,1,0,9603,-61,285.2,471.6,,,,,0
-574,1932,4644,4326,,"Accuracy better than +/- 1 metre.",2823,-22.36,-22.2,166.35,166.53,1,1,9606,-166.207,-154.777,254.831,-37.5444,7.7011,-10.2025,-30.8598,0
-575,15904,4644,4326,"Parameter values taken from NEA74 Noumea to RGNC91-93 (1) ( code 15886) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 1 metre.,2823,-22.36,-22.2,166.35,166.53,1,0,9603,-10.18,-350.43,291.37,,,,,1
-576,1294,4304,4326,Accuracy estimate not available.,For military purposes.,1365,32,37.14,-2.94,9.08,1,0,9603,-73,-247,227,,,,,1
-577,15815,4728,4326,Determined at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3873,27.59,29.29,-18.22,-13.37,1,0,9603,-307,-92,127,,,,,1
-578,1253,4307,4326,Derived at 3 stations.,For military purposes only. Accuracy 25m in each axis.,3213,18.98,37.14,-8.67,11.99,1,0,9603,-186,-93,310,,,,,0
-579,1255,4307,4326,"CAUTION: Source CRS described by DMA as from Voirol 1960. OGP believes that the data used in the derivation of these parameters contains a blunder. We recommend using transformation North Sahara 1959 to WGS84 (1) (code 1253). Derived at 2 stations.",For military purposes only. Accuracy 25m in each axis.,1365,32,37.14,-2.94,9.08,1,0,9603,-123,-206,219,,,,,0
-580,1815,4307,4326,Used by BP in District 3 and In Salah Gas.,Oil industry operations.,2598,25,32,1,3.3,1,0,9606,-152.9,43.8,358.3,2.714,1.386,-2.788,-6.743,0
-581,1816,4307,4326,"Derived at astro station central to concession. Significant and varying differences (>100m) at 4 neighbouring astro stations.",Oil industry operations.,2599,27.5,28.3,8.83,9.91,1,0,9603,-95.7,10.2,158.9,,,,,0
-582,1817,4307,4326,Derived at astro station Guerrara.,Oil industry operations.,2600,31.75,32.42,7.17,8,1,0,9603,-165.914,-70.607,305.009,,,,,0
-583,5630,4307,4326,"Derived at 1 station (L38).",Used by Total in Ahnet licence area.,3917,26.07,27.5,1.25,2.92,1,0,9603,-168.52,-72.05,304.3,,,,,0
-584,5660,4307,4326,Derived in 2006 at 45 points in north and central Algeria.,Accuracy at 75 common points better than 1m..,1026,18.98,38.8,-8.67,11.99,1,0,9606,-209.3622,-87.8162,404.6198,0.0046,3.4784,0.5805,-1.4547,1
-585,15874,4307,4326,"Derived at 11 stations throughout blocks 317b, 319b, 321b and 322b. Network based on station P4 (horizontal) and benchmark RN51 (vertical) using EGM96 geoid height. Used by Statoil in Hassi Mouina.",Oil exploration and production. Accuracy 5m.,3402,29.25,31,0,1.25,1,0,9603,-169.559,-72.34,303.102,,,,,0
-586,1234,4309,4326,Accuracy estimate not available.,For military purposes.,3326,-34.99,-30.1,-58.49,-53.1,1,0,9603,-155,171,37,,,,,1
-587,5386,4309,4326,Derived at 11 stations during 1998 densification of Uruguay control based on SIRGAS 1995.,"Accuracy at stations used for derivation: 0.13 to 1.17m.",3326,-34.99,-30.1,-58.49,-53.1,1,0,9606,-124.45,183.74,44.64,-0.4384,0.5446,-0.9706,-2.1365,0
-588,15816,4734,4326,Determined at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3184,-40.41,-37.01,-12.76,-9.8,1,0,9603,-632,438,-609,,,,,1
-589,1235,4311,4326,Derived at 5 stations.,"For military purposes. Accuracy 5m, 5m and 8m in X, Y and Z axes.",1222,1.84,9.35,-58.07,-52.66,1,0,9603,-265,120,-358,,,,,1
-590,1194,4312,4326,May be taken as approximate transformation MGI to ETRS89 assuming ETRS89 is equivalent to WGS 84 within the accuracy of the transformation - see tfm code 1024. Information source gives scale as -2.388739 ppm.,Provincial GIS and other applications to an accuracy of 0.5 metres.,1543,46.65,47.83,13.58,16.17,1,0,9607,601.705,84.263,485.227,-4.7354,-1.3145,-5.393,-2.3887,0
-591,1306,4312,4326,Accuracy estimate not available.,For military purposes only.,2370,40.86,46.88,13.38,23.03,1,1,9603,682,-203,480,,,,,0
-592,1471,4312,4326,,For applications to an accuracy of 1.5 metres.,1037,46.41,49.02,9.53,17.17,1,1,9606,-577.326,-90.129,-463.919,-5.1365988,-1.4742,-5.2970436,-2.4232,0
-593,1618,4312,4326,"Same transformation parameters used for MGI to ETRS89 (1) (code 1619).",For applications to an accuracy of 1.5 metres.,1037,46.41,49.02,9.53,17.17,1,0,9606,577.326,90.129,463.919,5.137,1.474,5.297,2.4232,1
-594,1621,4312,4326,"Parameter values from MGI to ETRS89 (2) (code 1620). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1076,41.62,46.54,13.01,19.43,1,1,9606,551.7,162.9,467.9,6.04,1.96,-11.38,-4.82,0
-595,1786,4312,4326,"Parameter values from MGI to ETRS89 (3) (code 1785). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.43,46.88,13.38,16.61,1,1,9606,426.9,142.6,460.1,4.91,4.49,-12.42,17.1,0
-596,1794,4312,4326,"For more accurate transformation see MGI to WGS 84 (7) (code 1795).",Oil industry,3536,41.8,43.56,18.45,20.38,1,1,9603,695.5,-216.6,491.1,,,,,0
-597,15982,4312,4326,"Parameter values from MGI to Slovenia 1996 (1) (code 15981). Assumes Slovenia 1996 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.43,46.88,13.38,16.61,1,1,9607,409.545,72.164,486.872,-3.085957,-5.46911,11.020289,17.919665,0
-598,1609,4313,4326,"Scale difference is given by information source as 0.999999. Given in this record in ppm to assist application usage. Very similar parameter values (to slightly less precision) used for BD72 to ETRS89: see code 1652.",For applications to an accuracy of 1 metre.,1347,49.51,51.5,2.51,6.4,1,0,9607,-99.059,53.322,-112.486,-0.419,0.83,-1.885,-1,0
-599,1610,4313,4326,,For applications to an accuracy of 5 metres.,1347,49.51,51.5,2.51,6.4,1,0,9603,-125.8,79.9,-100.5,,,,,0
-600,15749,4313,4326,"Parameter values from BD72 to ETRS89 (2) (code 15748). Scale difference is given by information source as 1.0000012747. Given in this record in ppm to assist application usage.",For applications to an accuracy of 0.5 metre.,1044,49.51,51.87,2.24,6.4,1,1,9607,-106.8686,52.2978,-103.7239,-0.3366,0.457,-1.8422,1.2747,0
-601,15929,4313,4326,"Parameter values from BD72 to ETRS89 (2) (code 15928). Scale difference is given by information source as -1.0000012747. Given in this record in ppm to assist application usage.",For applications to an accuracy of 0.5 metre.,1347,49.51,51.5,2.51,6.4,1,0,9607,-106.8686,52.2978,-103.7239,-0.3366,0.457,-1.8422,-1.2747,1
-602,1673,4314,4326,"Parameter values from DHDN to ETRS89 (1) (code 1309) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaced by DHDN to WGS 84 (2) (tfm code 1777).",For applications with an accuracy at 5 m level.,2326,47.27,55.09,5.87,13.83,1,0,9607,582,105,414,-1.04,-0.35,3.08,8.3,0
-603,1777,4314,4326,"Parameter values from DHDN to ETRS89 (2) (code 1776) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces DHDN to WGS 84 (1) (tfm code 1673).",For applications with an accuracy at 3 m level,2326,47.27,55.09,5.87,13.83,1,0,9606,598.1,73.7,418.2,0.202,0.045,-2.455,6.7,1
-604,15869,4314,4326,"Parameter values taken from RD/83 to ETRS89 (1) (tfm code 15868) assuming that within the accuracy of the transformation ETRS89 is equivalent to WGS 84 and RD/83 is equivalent to DHDN.",For applications with an accuracy at 2m level,1343,50.2,54.73,9.92,15.03,1,0,9606,612.4,77,440.2,-0.054,0.057,-2.797,2.55,0
-605,1517,4315,4326,,"?",3257,7.19,12.68,-15.13,-7.65,1,0,9603,-23,259,-9,,,,,1
-606,1789,4316,4326,"Parameter values taken from Pulkovo 1942 to WGS 84 (9) (code 1293) assuming that","?",1197,43.45,48.26,20.26,31.41,1,1,9603,103.25,-100.4,-307.19,,,,,0
-607,1995,4316,4326,,Oil exploration,3295,43.62,48.26,20.26,29.73,1,0,9603,103.25,-100.4,-307.19,,,,,1
-608,1097,4317,4326,"Parameter values taken from Pulkovo 1942 to WGS 84 (9) (code 1293) assuming that Pulkovo 1942 in Romania is equivalent to Dealul Piscului 1970.","Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.45,48.26,20.26,31.41,1,1,9603,28,-121,-77,,,,,0
-609,1996,4317,4326,,Oil exploration,1197,43.45,48.26,20.26,31.41,1,1,9603,44.107,-116.147,-54.648,,,,,0
-610,1060,4318,4326,,1 metre accuracy.,3267,28.54,30.08,46.55,48.47,1,0,9603,-3.2,-5.7,2.8,,,,,1
-611,1061,4319,4326,,For applications requiring an accuracy of better than 1 metre.,1310,29.17,29.44,47.78,48.16,1,0,9603,-20.8,11.3,2.4,,,,,1
-612,1062,4319,4326,,For applications requiring an accuracy of better than 1 metre.,1310,29.17,29.44,47.78,48.16,1,0,9607,226.702,-193.337,-35.371,2.229,4.391,-9.238,0.9798,0
-613,1237,4322,4326,,For scientific purposes.,1262,-90,90,-180,180,1,0,9606,0,0,4.5,0,0,0.554,0.2263,1
-614,1238,4322,4326,,For scientific purposes.,1262,-90,90,-180,180,1,0,9606,0,0,4.5,0,0,0.554,0.219,0
-615,15821,4731,4326,Derived at 1 satellite station.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3195,-18.32,-17.25,177.2,178.74,1,1,9603,51,391,-36,,,,,0
-616,1240,4324,4326,,Geodesy.,2346,-90,90,-180,180,1,0,9606,0,0,1.9,0,0,0.814,-0.38,1
-617,5521,4646,4326,,For military purposes. Accuracy unknown.,2807,-11.98,-11.32,43.16,43.55,1,0,9603,-963,510,-359,,,,,1
-618,15822,4732,4326,Derived at 10 satellite stations.,"For military and topographic mapping. Accuracy +/-3 m in each axis.",3191,8.67,19.37,162.27,167.81,1,0,9603,102,52,-38,,,,,1
-619,5327,5324,4326,For many purposes ISN2004 can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that ISN2004 is equivalent to WGS 84.",1120,59.96,69.58,-30.86,-5.56,1,0,9603,0,0,0,,,,,1
-620,3817,3819,4326,Horizontal coordinates of 66 points of the National Geodetic Network were used to compute this transformation.,GIS and topographic survey.,1119,45.75,48.58,16.11,22.89,1,0,9607,595.48,121.69,515.35,-4.115,2.9383,-0.853,-3.408,1
-621,1920,4645,4326,,"Accuracy +/- 1 metre.",1174,-26.44,-14.83,156.26,174.28,1,1,9603,0,0,0,,,,,0
-622,15823,4733,4326,Derived at 2 satellite stations.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3190,19.23,19.37,166.56,166.71,1,0,9603,276,-57,149,,,,,1
-623,3830,3824,4326,"Approximation at the +/- 1m level assuming that TWD97 is equivalent to WGS 84.","Accuracy +/- 1m.",1228,17.37,26.95,114.32,123.61,1,0,9603,0,0,0,,,,,1
-624,5376,5365,4326,,Accuracy 1m.,1074,2.15,11.77,-90.44,-81.43,1,0,9603,0,0,0,,,,,1
-625,15808,4724,4326,Derived at 2 satellite stations.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3189,-7.48,-7.19,72.31,72.54,1,0,9603,208,-435,-229,,,,,1
-626,5377,5371,4326,,Accuracy 1m.,1186,5,12.5,-84.32,-77.05,1,0,9603,0,0,0,,,,,1
-627,5378,5373,4326,,Accuracy 1m.,1189,-21.05,-0.04,-84.67,-68.67,1,0,9603,0,0,0,,,,,1
-628,15812,4736,4326,,"Scientific mapping. Accuracy +/- 20m in each axis.",3204,-63.08,-62.83,-60.88,-60.35,1,0,9603,260,12,-147,,,,,1
-629,15795,4707,4326,Derived at 1 satellite station. Same transformation parameter values related to same datum area given in original 1987 DMA TR8350.2 edition for Sorol Atoll.,For military purposes only. Accuracy 25m in each axis.,3181,23.69,23.93,-166.36,-166.03,1,0,9603,114,-116,-333,,,,,1
-630,5384,5381,4326,,Accuracy 1m.,1247,-37.77,-30.1,-58.49,-50.01,1,0,9603,0,0,0,,,,,1
-631,15813,4722,4326,Determined from 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3529,-54.94,-53.94,-38.07,-35.74,1,0,9603,-794,119,-298,,,,,1
-632,5227,5228,4326,"Parameter values from S-JTSK/05 to ETRS89 (1) (code 5226). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces tfm code 1622.",For applications to an accuracy of 1 metre.,1079,48.58,51.05,12.09,18.85,1,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378,1
-633,15771,4692,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Maupiti 83 to RGPF (1) (tfm code 15759).","Accuracy +/- 1 metre.",3126,-16.56,-16.35,-152.38,-152.14,1,0,9603,217.037,86.959,23.956,,,,,1
-634,15973,4055,4326,"Executes change of sphere/ellipsoid",Web mapping. Accuracy may be no better than 800 metres.,1262,-90,90,-180,180,1,1,9603,0,0,0,,,,,0
-635,5395,5393,4326,,Accuracy 1m.,1087,9.97,14.43,-91.42,-87.65,1,0,9603,0,0,0,,,,,1
-636,15842,4739,4326,"Derived at 2 satellite stations. Care: does not use Hong Kong 1963 (code 4838) as the source CRS.","Military mapping. Accuracy +/- 1m.",1118,22.14,22.57,113.77,114.5,1,0,9603,-156,-271,-189,,,,,1
-637,5261,5252,4326,,"Approximation at the +/- 1m level as both TUREF and WGS 84 are realisations of ITRS.",1237,34.43,43.45,25.62,44.82,1,0,9603,0,0,0,,,,,1
-638,1925,4639,4326,,"Accuracy +/- 10 metres.",2815,-13.4,-13.16,-176.24,-176.07,1,1,9603,252,-132,-125,,,,,0
-639,15847,4639,4326,"Replaces information from 2001 (tfm code 1925).","Accuracy +/- 10 metres.",2815,-13.4,-13.16,-176.24,-176.07,1,0,9603,253,-132,-127,,,,,1
-640,15801,4714,4326,Derived at 3 satellite stations.,"Military and topographic mapping; Accuracy +/- 20 m in each axis",3193,-20.3,-17.37,168.1,169.95,1,0,9603,-127,-769,472,,,,,1
-641,15802,4715,4326,No accuracy estimate available.,Military and scientific mapping.,3205,-77.94,-77.18,165.74,167.43,1,0,9603,-104,-129,239,,,,,1
-642,1994,4657,4326,,Low accuracy applications.,3262,63.35,66.58,-24.66,-13.38,1,0,9603,-28,199,5,,,,,1
-643,5351,5340,4326,,Approximation at the sub meter level.,1033,-58.4,-21.78,-73.58,-52.63,1,0,9603,0,0,0,,,,,1
-644,5078,4743,4326,"Parameter values from Karbala 1979 to IGRS (1) (tfm code 5077) assuming that IGRS is equivalent to WGS 84 within the accuracy of the transformation. Replaces Karbala 1979 to WGS 84 (1) (tfm code 15872).",Accuracy 1m.,3625,29.06,37.38,38.79,48.61,1,0,9603,70.995,-335.916,262.898,,,,,1
-645,15872,4743,4326,"Derived from shifts in UTM rectangular coordinates for one point in Basra area provided by Iraq National Oil Exploration Company. Replaced by Karbala 1979 to WGS 84 (2) (tfm code 5078).",Oil exploration.,3397,29.88,31.08,46.47,48.61,1,0,9603,84.1,-320.1,218.7,,,,,0
-646,1951,4658,4326,Derived at 6 stations.,"Accuracy 3m, 3m and 5m in X, Y and Z axes.",3262,63.35,66.58,-24.66,-13.38,1,0,9603,-73,46,-86,,,,,1
-647,3894,3889,4326,"Approximation at the +/- 1m level assuming that IGRS is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1m.,1124,29.06,37.38,38.79,48.75,1,0,9603,0,0,0,,,,,1
-648,1952,4659,4326,For many purposes ISN93 can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that ISN93 is equivalent to WGS 84.",1120,59.96,69.58,-30.86,-5.56,1,0,9603,0,0,0,,,,,1
-649,1957,4660,4326,Derived at 3 stations. Residuals under 1m.,For applications to an accuracy of 1 metre.,2869,70.75,71.23,-9.17,-7.88,1,0,9606,982.6087,552.753,-540.873,6.68162662527694,-31.6114924086422,-19.8481610048168,16.805,1
-650,1958,4661,4326,,LKS92 is a realisation of ETRS89 coincident to WGS84 within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1139,55.67,58.08,19.07,28.24,1,0,9603,0,0,0,,,,,1
-651,15849,4213,4326,"Used by Elf / CGG between December 1991 and March 1992. Probably derived from results of concatenated tfm Beduaram to WGS 84 (1) (code 8634).",Oil exploration.,2771,12.8,16.69,7.82,14.9,1,0,9603,-106,-87,188,,,,,1
-652,15803,4716,4326,Derived at 4 satellite stations.,"Military and topographic mapping. Accuracy +/- 15 m in each axis.",3196,-4.76,-2.69,-174.6,-170.67,1,0,9603,298,-304,-375,,,,,1
-653,3915,3906,4326,"Parameter values from MGI 1901 to ETRS89 (3) (code 3914). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.43,46.88,13.38,16.61,1,0,9606,426.9,142.6,460.1,4.91,4.49,-12.42,17.1,0
-654,3917,3906,4326,"Parameter values from MGI 1901 to Slovenia 1996 (1) (code 3916). Assumes Slovenia 1996 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.43,46.88,13.38,16.61,1,0,9607,409.545,72.164,486.872,-3.085957,-5.46911,11.020289,17.919665,0
-655,3962,3906,4326,Accuracy estimate not available from information source but established empirically by OGP.,For military purposes only.,2370,40.86,46.88,13.38,23.03,1,0,9603,682,-203,480,,,,,1
-656,3964,3906,4326,"Parameter values from MGI 1901 to ETRS89 (2) (code 3963). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3234,42.35,46.54,13.43,19.43,1,0,9606,551.7,162.9,467.9,6.04,1.96,-11.38,-4.82,0
-657,3965,3906,4326,,Oil industry,3536,41.8,43.56,18.45,20.38,1,0,9603,695.5,-216.6,491.1,,,,,0
-658,15879,4747,4326,"Approximation at the +/- 1m level assuming that GR96 is equivalent to WGS 84 within the accuracy of the transformation.","For applications with an accuracy of +/- 1m.",1107,56.38,87.02,-75,8.12,1,0,9603,0,0,0,,,,,1
-659,1962,4662,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15903.,"Accuracy +/- 10 metres.",2822,-22.45,-20.04,163.93,167.08,1,0,9603,-13,-348,292,,,,,0
-660,1963,4662,4326,Withdrawn by information source and replaced by improved information - see tfm code 15903.,"Accuracy better than +/- 1 metre.",2822,-22.45,-20.04,163.93,167.08,1,0,9606,97.295,-263.247,310.882,-1.5999,0.8386,3.1409,13.3259,0
-661,15903,4662,4326,"Parameter values taken from IGN72 Grande Terre to RGNC91-93 (1) ( code 15882) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.","Accuracy +/- 2 metres.",2822,-22.45,-20.04,163.93,167.08,1,0,9603,-11.64,-348.6,291.98,,,,,1
-662,15878,4748,4326,"Parameter values taken from Viti Levu 1912 to WGS 84 (1) (tfm code 15897). Approximation at the +/- 50m level assuming that CRS 4748 is equivalent to CRS 4752 within the transformation accuracy. Source CRSs 4748 and 4752 are independent but connected.","For applications with an accuracy of +/-50m.",3401,-17.06,-16.1,178.43,-179.77,1,0,9603,51,391,-36,,,,,1
-663,1966,4663,4326,Derived at Forte de Sao Tiago.,For low resolution applications.,2870,32.59,33.14,-17.3,-16.23,1,0,9603,-502.862,-247.438,312.724,,,,,1
-664,1967,4663,4326,,For medium resolution applications.,2870,32.59,33.14,-17.3,-16.23,1,0,9607,-210.502,-66.902,-48.476,-2.094,15.067,5.817,0.485,0
-665,15880,4749,4326,,"Accuracy +/- 1 metre.",1174,-26.44,-14.83,156.26,174.28,1,0,9603,0,0,0,,,,,1
-666,1968,4664,4326,Calculated in 2001.,For low resolution applications.,2871,37.66,37.96,-25.91,-25.08,1,0,9603,-204.633,140.216,55.199,,,,,0
-667,1969,4664,4326,Calculated in 2001.,For medium resolution applications.,2871,37.66,37.96,-25.91,-25.08,1,0,9607,-211.939,137.626,58.3,0.089,-0.251,-0.079,0.384,0
-668,1970,4664,4326,Mean for all islands in group.,For low resolution applications.,1345,36.88,37.96,-25.91,-24.62,1,0,9603,-204.619,140.176,55.226,,,,,1
-669,1971,4664,4326,Mean for all islands in group.,For medium resolution applications.,1345,36.88,37.96,-25.91,-24.62,1,0,9607,-208.719,129.685,52.092,0.195,0.014,-0.327,0.198,0
-670,15881,4750,4326,"Parameter values taken from ST87 Ouvea to RGNC91-93 (1) ( code 15885) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.","Accuracy better than +/- 1 metre.",2813,-20.77,-20.34,166.45,166.7,1,0,9603,-56.263,16.136,-22.856,,,,,1
-671,1972,4665,4326,,For low resolution applications.,2872,38.58,38.85,-27.44,-26.97,1,0,9603,-106.301,166.27,-37.916,,,,,0
-672,1973,4665,4326,,For medium resolution applications.,2872,38.58,38.85,-27.44,-26.97,1,0,9607,-105.854,165.589,-38.312,0.003,0.026,-0.024,-0.048,0
-673,1974,4665,4326,,For low resolution applications.,2873,38.46,38.69,-28.9,-28.55,1,0,9603,-106.248,166.244,-37.845,,,,,0
-674,1975,4665,4326,,For medium resolution applications.,2873,38.46,38.69,-28.9,-28.55,1,0,9607,-104,162.924,-38.882,0.075,0.071,-0.051,-0.338,0
-675,1976,4665,4326,,For low resolution applications.,2874,38.32,38.61,-28.61,-27.99,1,0,9603,-106.044,166.655,-37.876,,,,,0
-676,1977,4665,4326,,For medium resolution applications.,2874,38.32,38.61,-28.61,-27.99,1,0,9607,-95.323,166.098,-69.942,0.215,1.031,-0.047,1.922,0
-677,1978,4665,4326,,For low resolution applications.,2875,38.49,38.8,-28.37,-27.71,1,0,9603,-106.253,166.239,-37.854,,,,,0
-678,1979,4665,4326,,For medium resolution applications.,2875,38.49,38.8,-28.37,-27.71,1,0,9607,-100.306,161.246,-48.761,0.192,0.385,-0.076,0.131,0
-679,1980,4665,4326,Mean for all islands in group.,For low resolution applications.,1301,38.32,39.14,-28.9,-26.97,1,0,9603,-106.226,166.366,-37.893,,,,,1
-680,1981,4665,4326,Mean for all islands in group.,For medium resolution applications.,1301,38.32,39.14,-28.9,-26.97,1,0,9607,-103.088,162.481,-28.276,-0.167,-0.082,-0.168,-1.504,0
-681,1986,4666,4326,May be taken as a transformation from Lisbon 1890 to ETRS89 - see tfm code 5039.,For low resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9603,508.088,-191.042,565.223,,,,,1
-682,1990,4666,4326,,For medium resolution applications.,1294,36.96,42.15,-9.55,-6.19,1,0,9607,631.392,-66.551,481.442,-1.09,4.445,4.487,-4.43,0
-683,15804,4717,4326,Derived at 19 satellite stations.,"US space and military operations. Accuracy +/- 3 m in each axis.",3206,20.87,30.83,-82.33,-72.69,1,0,9603,-2,151,181,,,,,1
-684,5267,5264,4326,DRUKREF 03 and WGS 84 are both realisations of ITRS.,For applications to an accuracy of 1 metre.,1048,26.7,28.32,88.75,92.11,1,0,9603,0,0,0,,,,,1
-685,15708,4683,4326,Derived during GPS campaign which established PRS92 coordinates at 330 first order stations.,"Accuracy: 1-10 parts per million.",1190,3,22.18,116.04,129.94,1,0,9607,-127.62,-67.24,-47.04,3.068,-4.903,-1.578,-1.06,1
-686,1993,4667,4326,For all practical purposes this transformation is exact.,Boundary demarcation.,2876,29.06,30.31,46.36,48.61,1,0,9603,0,0,0,,,,,1
-687,15897,4752,4326,Derived at 1 satellite station.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3195,-18.32,-17.25,177.2,178.74,1,0,9603,51,391,-36,,,,,1
-688,15752,4668,4326,Derived at 22 stations.,For military purposes. Accuracy 3m in each axis.,1297,34.88,71.2,-10.56,31.58,1,0,9603,-86,-98,-119,,,,,1
-689,15810,4735,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3192,5.21,5.42,162.86,163.09,1,0,9603,647,1777,-1124,,,,,1
-690,15908,4754,4326,Derived at 5 stations throughout Libya used to define LGD2006 in May 2006.,For applications to an accuracy of 0.1 metre.,1143,19.5,35.23,9.31,26.21,1,0,9603,-208.4058,-109.8777,-2.5764,,,,,1
-691,4477,4463,4326,"Approximation at the +/- 1m level assuming that RGSPM06 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1220,43.42,47.37,-57.1,-55.9,1,0,9603,0,0,0,,,,,1
-692,5501,5489,4326,"Approximation at the +/- 1m level assuming that RGAF09 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",2824,14.08,18.53,-63.66,-57.53,1,0,9603,0,0,0,,,,,1
-693,15912,4755,4326,"Approximation at the +/- 1m level assuming that DGN95 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1 metre.,1122,-13.25,7.78,92.02,141.46,1,0,9603,0,0,0,,,,,1
-694,1555,4158,4326,Derived in 1989 by ONI for Amoco.,Oil exploration.,3143,9.99,10.89,-61.97,-60.86,1,0,9603,-0.465,372.095,171.736,,,,,1
-695,1556,4158,4326,Described by NIMA as Naparima to WGS 84. In Trinidad the source CRS is better known as Naparima 1955. EPSG has duplicated the tfm using the alternative source CRSs. See also tfm code 1307.,For military purposes only. Accuracy given by NIMA 15m in each axis. EPSG believes there is an 8-10m blunder in dX.,3143,9.99,10.89,-61.97,-60.86,1,0,9603,-2,374,172,,,,,0
-696,4476,4470,4326,"Approximation at the +/- 1m level assuming that RGM04 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1159,-14.49,-11.34,43.68,46.69,1,0,9603,0,0,0,,,,,1
-697,5194,4756,4326,Used by Total in Mekong delta.,Academic research not officially adopted.,3770,9.35,11.02,104.25,107.1,1,0,9607,-192.873,-39.382,-111.202,0.00205,0.0005,-0.00335,0.0188,1
-698,1931,4643,4326,,"Accuracy better than +/- 1 metre.",2821,-19.84,-19.51,163.54,163.75,1,0,9606,-480.26,-438.32,-643.429,16.3119,20.1721,-4.0349,-111.7002,1
-699,4290,4475,4326,"Parameter values taken from Cadastre 1997 to RGM04 (1) (transformation code 4478) assuming that RGM04 is coincident with WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",3340,-13.04,-12.61,44.99,45.34,1,0,9603,-381.788,-57.501,-256.673,,,,,1
-700,5374,5354,4326,,Accuracy 1m.,1049,-22.9,-9.68,-69.66,-57.52,1,0,9603,0,0,0,,,,,1
-701,15787,4701,4326,Derived by Topnav in 1991 at station TSH 85.,Oil exploration. Accuracy 5m.,3171,-6.04,-4.28,12.17,16.28,1,0,9603,-79.9,-158,-168.9,,,,,1
-702,4832,4483,4326,,Accuracy 1m.,1160,12.1,32.72,-122.18,-84.64,1,0,9603,0,0,0,,,,,1
-703,1917,4633,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15902.,"Accuracy +/- 10 metres.",2814,-21.23,-20.63,166.99,167.52,1,0,9603,336,223,-231,,,,,0
-704,1927,4633,4326,Withdrawn by information source and replaced by improved information - see tfm code 15902.,"Accuracy better than +/- 1 metre.",2814,-21.23,-20.63,166.99,167.52,1,0,9606,137.092,131.66,91.475,-1.9436,-11.5993,-4.3321,-7.4824,0
-705,15902,4633,4326,"Parameter values taken from IGN56 Lifou to RGNC91-93 (1) ( code 15883) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 1 metre.,2814,-21.23,-20.63,166.99,167.52,1,0,9603,335.47,222.58,-230.94,,,,,1
-706,15925,4758,4326,,For all practical purposes JAD2001 can be considered to be coincident with WGS 84.,1128,14.08,19.36,-80.59,-74.51,1,0,9603,0,0,0,,,,,1
-707,15845,4161,4326,Transformation parameter precision given to millimetres in information source but due to accuracy rounded to nearest decimetre for EPSG database.,Geodetic surveying within the oil industry. Accuracy 25 m.,1265,-46.7,-45.2,-69.5,-67.1,1,0,9603,27.5,14,186.4,,,,,1
-708,15931,4759,4326,"Approximation at the +/- 1m level assuming that NAD83(NSRS2007) is equivalent to WGS 84 within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1511,14.93,74.71,167.65,-63.89,1,0,9603,0,0,0,,,,,1
-709,1540,4163,4326,,Accuracy better than 1 metre.,1257,8.96,19,41.08,57.96,1,0,9603,0,0,0,,,,,1
-710,4905,5013,4326,,PTRA08 and WGS 84 are realisations of ITRS coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,3670,29.25,43.07,-35.58,-12.48,1,0,9603,0,0,0,,,,,1
-711,6195,5527,4326,"Parameter values from SAD69(96) to SIRGAS 2000 (2)) (tfm code 5881) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation, based on SAD69 to SIRGAS 2000 (1)) (tfm code 15485). Used by Petrobras and ANP from 1994.","Accuracy generally better than 1m except in Amazon basin where it degenerates to 5m. Should be used only to transform data obtained independently of the classical geodetic network (GPS observations conducted after 1994).", [...]
-712,15806,4719,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis",3188,-27.25,-27.02,-109.5,-109.16,1,0,9603,211,147,111,,,,,1
-713,15860,4702,4326,Mauritania 1999 can be considered to be the same as WGS 84 within the accuracy of this transformation.,Minerals management. Accuracy 1m.,1157,14.73,27.29,-20.04,-4.81,1,0,9603,0,0,0,,,,,1
-714,15971,4762,4326,"Approximation at the +/- 1m level assuming that BDA2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1047,28.91,35.72,-68.83,-60.71,1,0,9603,0,0,0,,,,,1
-715,5375,5360,4326,,Accuracy 1m.,1066,-59.86,-17.51,-113.2,-65.73,1,0,9603,0,0,0,,,,,1
-716,15972,4763,4326,"Approximation at the +/- 1m level assuming that Pitcairn 2006 is equivalent to WGS 84.","Accuracy +/- 1 metre.",3208,-25.13,-25.01,-130.16,-130.01,1,0,9603,0,0,0,,,,,1
-717,1558,4166,4326,Derived at 5 stations.,For military purposes. Accuracy 1m in each axis.,3266,33.14,38.64,124.54,131,1,0,9603,0,0,0,,,,,1
-718,4084,4081,4326,"Approximation at the +/- 1m level assuming that REGCAN95 is equivalent to WGS 84.","Accuracy +/- 1m.",3199,24.6,32.75,-21.93,-11.75,1,0,9603,0,0,0,,,,,1
-719,15974,4764,4326,"Approximation at the +/- 1m level assuming that RSRGD2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",3558,-90,-60,145,-150,1,0,9603,0,0,0,,,,,1
-720,5553,5546,4326,"Exact in 1994 but due to significant and variable tectonic activity in PNG, in 2011 PNG94 and WGS 84 differ generally by 2m but in areas of significant tectonic activity differences can exceed 9m.",Approximation at the 2-10m level.,1187,-14.75,2.57,139.2,162.8,1,0,9603,0,0,0,,,,,1
-721,15870,4679,4326,Derived at 5 points in 2002.,Hydrographic survey,2967,19.37,21.34,-17.08,-15.89,1,0,9603,-80.01,253.26,291.19,,,,,1
-722,15976,4765,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1212,45.43,46.88,13.38,16.61,1,0,9603,0,0,0,,,,,1
-723,15820,4730,4326,Derived at 1 satellite station.,For military and topographic mapping. Accuracy 25m in each axis.,3194,-17.32,-14.58,166.47,168.71,1,0,9603,170,42,84,,,,,1
-724,15709,4680,4326,Derived by IGN in 1992 at 7 stations within Nouakchott city.,Oil exploration.,2972,17.9,18.25,-16.1,-15.83,1,0,9603,124.5,-63.5,-281,,,,,1
-725,5585,4023,4326,"Parameter values from MOLDREF99 to ETRS89 (1) (code 5584). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications with an accuracy of 1m.,1162,45.45,48.47,26.63,30.13,1,0,9603,0,0,0,,,,,1
-726,15831,4737,4326,"Approximation at the +/- 1m level assuming that ITRF2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1135,28.6,40.27,122.71,134.27,1,0,9603,0,0,0,,,,,1
-727,5590,5561,4326,"Derived through concatenation of UCS-2000 to S-42 (1) (tfm code 5586 reversed) [an approximation] and S-42 to WGS 84 (16) (tfm code 15865) [derived for whole FSU rather than Ukraine]. Replaced by UCS-2000 to WGS 84 (2) (tfm code 5840).",Accuracy 5 metres.,1242,43.19,52.38,22.15,40.18,1,0,9607,25,-141,-78.5,0,-0.35,-0.736,0,1
-728,5823,5561,4326,"Parameter values taken from Ukraine 2000 to ITRF2005 (1) (code 5822) assuming that ITRS2005 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level assuming that ITRS2005 is equivalent to WGS 84.",1242,43.19,52.38,22.15,40.18,1,1,9603,24,-121,-76,,,,,0
-729,5840,5561,4326,"Parameter values taken from UCS-2000 to ITRF2005 (1) (code 5822) assuming that WGS 84 is equivalent to ITRS2005 within the accuracy of the transformation. Replaces UCS-2000 to WGS 84 (1) (tfm code 5590).","Approximation at the +/- 1m level assuming that WGS 84 is equivalent to ITRS2005.",1242,43.19,52.38,22.15,40.18,1,0,9603,24,-121,-76,,,,,0
-730,15700,4682,4326,Derived at origin station in Dhaka.,Oil exploration.,1041,18.57,26.63,88.04,92.67,1,1,9603,283.8,735.9,261.1,,,,,0
-731,15779,4682,4326,Derived at origin station in Dhaka. Source information given to 3 decimal places but rounded by OGP to be commensurate with stated accuracy.,Oil exploration.,1041,18.57,26.63,88.04,92.67,1,0,9603,283.7,735.9,261.1,,,,,1
-732,1919,4635,4326,,"Accuracy better than +/- 1 metre.",2813,-20.77,-20.34,166.45,166.7,1,1,9606,-122.383,-188.696,103.344,3.5107,-4.9668,-5.7047,4.4798,0
-733,5470,5451,4326,,Topographic mapping.,3876,7.98,17.82,-92.29,-82.53,1,0,9603,213.11,9.37,-74.95,,,,,1
-734,5473,5451,4326,"Rotations in original source given in radians are equivalent to Rx = 2.35"", Ry = -0.06"", Rz = 6.39"".",Topographic mapping.,3232,7.98,11.21,-85.96,-82.53,1,0,9607,213.116,9.358,-74.946,2.3514187912169,-0.0614669122616347,6.39420899365999,-5.22,0
-735,5474,5451,4326,,Topographic mapping.,3876,7.98,17.82,-92.29,-82.53,1,0,9603,205.435,-29.099,292.202,,,,,0
-736,15713,4684,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,3274,-0.69,7.08,72.81,73.69,1,0,9603,-133,-321,50,,,,,1
-737,6177,6135,4326,"Approximation at the +/- 1m level assuming that CIGD11 is equivalent to WGS 84.","Accuracy +/- 1m.",1063,17.58,20.67,-83.6,-78.72,1,0,9603,0,0,0,,,,,1
-738,4064,4046,4326,"Approximation at the +/- 1m level assuming that RGRDC 2005 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1m.,3613,-13.46,-3.42,11.8,29.81,1,0,9603,0,0,0,,,,,1
-739,15846,4706,4326,"Sometime referred to as ""Egypt 1907 to WGS 84"". However, application to WGS 84 coordinates of the reverse of this tfm results in Gulf of Suez S-650 TL, not Egypt 1907, position. Gulf of Suez S-650 TL and Egypt 1907 CRSs differ by some 20 metres.",Used for oil exploration by GUPCO.,2341,27.2,30,32.34,34.26,1,0,9603,-146.21,112.63,4.05,,,,,1
-740,15918,4214,4326,Provided by BGP to TOTAL in June 2006.,Geophysical exploration in Ordos basin. Accuracy stated as 1m within basin.,3466,35,39,107,110.01,1,0,9603,12.646,-155.176,-80.863,,,,,0
-741,15919,4214,4326,Derived via WGS 72BE. Original transformation derived in 1979 at 4 stations on Yellow Sea coast.,Geophysical exploration in Yellow Sea.,3469,31.23,37.39,119.24,125.06,1,0,9606,15.53,-113.82,-41.38,0,0,0.814,-0.38,0
-742,15920,4214,4326,"Derived via WGS 72BE. Original transformation derived by GSI in 1980-81. The GSI memo incorrectly gave the parameters as from WGS 72 to Beijing 1954, but it has been determined by the OGP that the memo should have stated from Beijing 1954 to WGS 72BE.",Geophysical exploration in South China Sea.,3470,18.32,22.89,110.14,116.75,1,0,9606,31.4,-144.3,-74.8,0,0,0.814,-0.38,0
-743,15921,4214,4326,Provided by BGP to ELF in 1994.,Geophysical exploration in Tarim basin. Accuracy stated as 1m within basin.,3507,37,41.99,77.46,88,1,0,9603,15.8,-154.4,-82.3,,,,,1
-744,15935,4214,4326,Concatenated via WGS 72BE. Recomputation by Shelltech in 1981 of SSB 1980 observation.,Geophysical exploration in Bei Bu basin. Accuracy stated as 1m within basin.,3561,17.82,21.68,107.16,110.17,1,0,9606,18,-136.8,-73.7,0,0,0.814,-0.38,0
-745,15936,4214,4326,Provided by Sinopec to TOTAL in January 2007.,Geophysical exploration in Ordos basin. Accuracy stated as 1m within basin.,3466,35,39,107,110.01,1,0,9603,11.911,-154.833,-80.079,,,,,0
-746,15875,4721,4326,Derived at 20 stations.,"For military purposes. Accuracy 5m, 3m and 2m in X, Y and Z axes.",3398,-19.21,-16.1,176.82,-179.77,1,0,9603,265.025,384.929,-194.046,,,,,1
-747,15876,4720,4326,"Approximation at the +/- 2m level assuming that Fiji 1986 is equivalent to WGS 72. Parameter values taken from WGS 72 to WGS 84 (1) (tfm code 1237).",tbc,1094,-20.8,-12.43,176.82,-178.15,1,0,9606,0,0,4.5,0,0,0.554,0.2263,1
-748,15877,4720,4326,"Suitable for GIS mapping purposes but not rigorous surveying. Very similar results may be obtained through Fiji 1986 to WGS 84 (1) (tfm code 15876).","Horizontal accuracy 2m, vertical accuracy approximately 40 metres..",3398,-19.21,-16.1,176.82,-179.77,1,0,9607,-35.173,136.571,-36.964,1.37,-0.842,-4.718,-1.537,0
-749,5599,5593,4326,,Approximation at the 1m level.,3889,54.33,54.83,10.67,12,1,0,9603,0,0,0,,,,,1
-750,15832,4687,4326,"Transformation is to original definition of WGS 84. It is consistent with later WGS 84 realisations G730, G873 and G1150 to no better than 1m.","Accuracy +/- 0.5 metre (to original definition of WGS 84 - see remarks).",1098,-31.24,-4.53,-158.13,-131.98,1,0,9607,0.072,-0.507,-0.245,0.0183,-0.0003,0.007,-0.0093,1
-751,15833,4687,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84.","Accuracy +/- 1 metre.",1098,-31.24,-4.53,-158.13,-131.98,1,0,9603,0,0,0,,,,,0
-752,1921,4636,4326,,"Accuracy +/- 10 metres.",2817,-66.78,-66.11,139.45,141.5,1,0,9603,365,194,166,,,,,1
-753,15772,4688,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Fatu Iva 72 to RGPF (1) (tfm code 15760).","Accuracy +/- 2 metres.",3133,-10.6,-10.36,-138.75,-138.54,1,0,9607,347.103,1078.125,2623.922,33.8875,-70.6773,9.3943,186.074,1
-754,5236,5233,4326,Derived at 58 stations.,Accuracy 14m.,3310,5.87,9.88,79.65,81.94,1,0,9607,-0.293,766.95,87.713,-0.195704,-1.695068,-3.473016,-0.039338,1
-755,4077,4075,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84. SREF98 is a regional realisation of ETRS89.","Accuracy +/- 1 metre.",3534,41.86,46.18,18.82,23.01,1,0,9603,0,0,0,,,,,1
-756,4835,4690,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Tahiti 79 to RGPF (1) (tfm code 15756).","Accuracy +/- 1 metre.",3124,-17.92,-17.44,-149.69,-149.1,1,0,9607,221.525,152.948,176.768,2.3847,1.3896,0.877,11.4741,1
-757,1922,4637,4326,,"Accuracy +/- 10 metres.",2818,-67.13,-65.62,136,142,1,0,9603,325,154,172,,,,,1
-758,15797,4712,4326,Derived at 2 satellite stations.,For military purposes only. Accuracy 25m in each axis.,3182,-8.03,-7.84,-14.46,-14.25,1,0,9603,-205,107,53,,,,,1
-759,15769,4691,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Moorea 87 to RGPF (1) (tfm code 15757).","Accuracy +/- 1 metre.",3125,-17.62,-17.42,-149.99,-149.73,1,0,9607,215.525,149.593,176.229,3.2624,1.692,1.1571,10.4773,1
-760,6142,4723,4326,"Parameter values are taken from GCGD59 to CIGD11 (1) (code 6136) assuming that CIGD11 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1m.,3185,19.22,19.4,-81.45,-81.04,1,0,9607,-179.483,-69.379,-27.584,7.862,-8.163,-6.042,-13.925,1
-761,15830,4723,4326,Determined from 6 satellite stations.,"Topographic survey. Accuracy +/- 1m.",3185,19.22,19.4,-81.45,-81.04,1,0,9603,67.8,106.1,138.8,,,,,0
-762,4066,4695,4326,"Parameter values taken from Katanga 1955 to RGRDC 2005 (1) (code 4065) assuming that RGRDC 2005 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1.5m.,3614,-12,-11.14,26.38,27.75,1,0,9603,-103.746,-9.614,-255.95,,,,,1
-763,15746,4693,4326,Derived in Tombak district in March 2005. Used for South Pars phase 11 and Pars LNG plants.,Petroleum Exploration and Production.,3141,27.63,27.8,52.1,52.25,1,0,9603,0,-0.15,0.68,,,,,1
-764,1441,4601,4326,,"?",1273,16.94,17.21,-61.94,-61.62,1,0,9603,-255,-15,71,,,,,1
-765,15811,4601,4326,Determined from 1 satellite station.,"Military mapping. Accuracy +/- 25m in each axis.",1273,16.94,17.21,-61.94,-61.62,1,0,9603,-270,13,62,,,,,0
-766,1442,4602,4326,,"?",3239,15.15,15.68,-61.54,-61.2,1,0,9603,725,685,536,,,,,1
-767,1443,4603,4326,,"?",3118,11.95,12.29,-61.83,-61.55,1,0,9603,72,213.7,93,,,,,1
-768,1444,4604,4326,Derived at 1 satellite station.,Accuracy 25m in each axis.,3279,16.62,16.86,-62.29,-62.09,1,0,9603,174,359,365,,,,,1
-769,1445,4605,4326,,"?",3297,17.07,17.46,-62.91,-62.5,1,0,9603,9,183,236,,,,,1
-770,15750,4605,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m in each of X, Y and Z axes.",3297,17.07,17.46,-62.91,-62.5,1,0,9603,-7,215,225,,,,,0
-771,1446,4606,4326,,"?",3298,13.66,14.16,-61.13,-60.83,1,0,9603,-149,128,296,,,,,1
-772,1959,4607,4326,Derived at 4 points.,1m accuracy.,3300,12.55,13.43,-61.51,-61.07,1,0,9603,195.671,332.517,274.607,,,,,1
+78,15824,4135,4326,Derived at 15 satellite stations.,"Military mapping. Accuracy +/- 25m in X axis, +/- 20m in Y and Z axes.",1334,18.87,22.29,-160.3,-154.74,1,0,9603,61,-285,-181,,,,,1
+79,15825,4135,4326,Derived at 2 satellite stations.,"Military mapping. Accuracy +/- 25m in each axis.",1546,18.87,20.33,-156.1,-154.74,1,0,9603,89,-279,-183,,,,,0
+80,15826,4135,4326,Derived at 3 satellite stations.,"Military mapping. Accuracy +/- 20m in each axis.",1549,21.81,22.29,-159.85,-159.23,1,0,9603,45,-290,-172,,,,,0
+81,15827,4135,4326,Derived at 2 satellite stations.,"Military mapping. Accuracy +/- 25m in each axis.",1547,20.45,21.26,-157.36,-155.93,1,0,9603,65,-290,-190,,,,,0
+82,15828,4135,4326,Derived at 8 satellite stations.,"Military mapping only. Accuracy +/- 10m in X axis, +/- 6m in Y and Z axes.",1548,21.2,21.75,-158.33,-157.61,1,0,9603,58,-283,-182,,,,,0
+83,6208,6207,4326,Derived at 11 points.,"Topographic mapping. Accuracy 0.26m (1-sigma).",1171,26.36,30.43,80.05,88.2,1,0,9603,293.17,726.18,245.36,,,,,1
+84,1893,4139,4326,Derived at 11 stations.,For military purposes only. Accuracy 3m in each axis.,1335,17.62,18.78,-67.97,-64.25,1,0,9603,11,72,-101,,,,,1
+85,1473,4140,4326,"For many purposes NAD83(CSRS98) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(CSRS98) is equivalent to WGS 84.",1336,44.61,62.56,-120,-57.1,1,1,9603,0,0,0,,,,,0
+86,1073,4141,4326,For more accurate transformation contact Survey of Israel.,"Accuracy: 2m",2603,29.45,33.28,34.17,35.69,1,0,9603,-48,55,52,,,,,1
+87,1469,4142,4326,,"?",2282,5.15,5.54,-4.22,-3.85,1,0,9603,-125,53,467,,,,,1
+88,1470,4143,4326,"Derived in Abidjan for use in the immediate area, but used by E&P industry more widely onshore and offshore. A similar transformation (tfm code 6872) was used by Western Geophysical for offshore surveys in the 1990s.",Accuracy is submetre in the area around Abidjan but unknown farther afield. There is some evidence of unknown reliability that suggests accuracy of better than 2m throughout offshore.,1075,1.02,10.74,-8.61,-2.48,1,0,9603,-124.76,53,466.79,,,,,1
+89,6872,4143,4326,"Derived and used by Western Geophysical for offshore surveys in the 1990s, but exact provenance uncertain. Used by OMV.",Accuracy uncertain but there is some evidence of unknown reliability that suggests accuracy of better than 2m throughout offshore.,2296,1.02,5.19,-7.55,-3.11,1,0,9603,-123.1,53.2,465.4,,,,,0
+90,1155,4144,4326,Derived at 6 stations.,"For military purposes. Accuracy 10m, 8m and 12m in X, Y and Z axes.",3217,20.52,26.63,88.04,92.67,1,0,9603,282,726,254,,,,,0
+91,1533,4144,4326,,Oil exploration.,2361,9.48,17.87,93.94,99.66,1,0,9603,214,804,268,,,,,1
+92,1247,4145,4326,"Care! DMA ellipsoid is inconsistent with EPSG ellipsoid - transformation parameter values may not be appropriate. No accuracy estimate available.",For military purposes.,3289,23.64,37.07,60.86,77.83,1,0,9603,283,682,231,,,,,1
+93,15494,4145,4326,Derived by Fugro-Geodetic in 2004 at 6 closely-spaced stations. Used by OMV in all blocks in Pakistan where operator.,Oil exploration.,3589,25.88,27.67,68.24,69.3,1,0,9603,274.164,677.282,226.704,,,,,0
+94,15701,4145,4326,Derived at Geodetic Survey office in Karachi in 1997.,Oil exploration.,2985,21.05,25.39,64,68.24,1,0,9603,275.57,676.78,229.6,,,,,0
+95,15702,4145,4326,"Derived at station S0001, an approximate offset to Survey of India primary station Kat Baman, in 1992 from 180 single point Transit passes observed in 1991 by Fugro-Geodetic for UTP.",Oil exploration.,2984,24,25.64,67.74,69.87,1,0,9603,278.9,684.39,226.05,,,,,0
+96,15703,4145,4326,Derived at Chitrawala triangulation station by Fugro-Geodetic for UTP.,Oil exploration.,2982,24.69,25.76,66.83,68,1,0,9603,271.905,669.593,231.495,,,,,0
+97,15704,4145,4326,Derived by Western Geophysical for UTP 1996 East Sind 2D survey.,Oil exploration.,2983,24.16,28.61,68.27,71.11,1,0,9606,230.25,632.76,161.03,-1.114,1.115,1.212,12.584,0
+98,1156,4146,4326,"Care! DMA ellipsoid is inconsistent with EPSG ellipsoid - transformation parameter values may not be appropriate. Also source CRS may not apply to Nepal. Derived at 7 stations.","For military purposes. Accuracy 12m, 10m and 15m in X, Y and Z axes.",2411,8.02,35.51,68.08,97.39,1,0,9603,295,736,257,,,,,1
+99,1544,4147,4326,Derived in Vung Tau area.,Oil exploration.,1494,9.02,11.03,105.49,107.59,1,0,9603,-17.51,-108.32,-62.39,,,,,1
+100,1505,4148,4326,,For many purposes Hartebeesthoek94 datum can be considered to be coincident with WGS 84.,1215,-50.32,-22.13,13.33,42.85,1,0,9603,0,0,0,,,,,1
+101,1508,4149,4326,"Implemented in Bundesamt für Landestopographie programme GRANIT.","?",1286,45.82,47.81,5.96,10.49,1,1,9607,660.077,13.551,369.344,0.804816,0.577692,0.952236,5.66,0
+102,1510,4149,4326,"These parameters are strictly between CH1903+ and CHTRF95 but are used from CH1903 as an approximation which is within the accuracy of the distortions in the CH1903 network.",Accuracy 1.5 metres.,1286,45.82,47.81,5.96,10.49,1,1,9603,674.374,15.056,405.346,,,,,0
+103,1753,4149,4326,"Implemented in Bundesamt für Landestopographie programme GRANIT. Used from 1987 to 1997. Not recommended for current usage - replaced by CH1903 to WGS 84 (2) (code 1766).","?",1286,45.82,47.81,5.96,10.49,1,0,9607,660.077,13.551,369.344,0.804816,0.577692,0.952236,5.66,0
+104,1766,4149,4326,"These parameters are derive from CH1903+ to ETRS89 (code 1647) and are used at lesser precision from CH1903 to WGS 84 as an approximation which is within the accuracy of the distortions in the CH1903 network. Replaces CH1903 to WGS 84 (1) (code 1753).",Accuracy 1.5 metres.,1286,45.82,47.81,5.96,10.49,1,0,9603,674.4,15.1,405.3,,,,,1
+105,1676,4150,4326,"Parameter values are from CH1903+ to CHTRF95 (1) (code 1509) assuming that CHTRF95 is equivalent to WGS 84. That transformation is also given as CH1903+ to ETRS89 (1) (code 1647). CHTRF95 is a realisation of ETRS89.","Approximation at the +/- 1m level.",1286,45.82,47.81,5.96,10.49,1,0,9603,674.374,15.056,405.346,,,,,1
+106,1511,4151,4326,,For many purposes CHTRF95 can be considered to be coincident with WGS 84.,1286,45.82,47.81,5.96,10.49,1,0,9603,0,0,0,,,,,1
+107,1580,4152,4326,"For many purposes NAD83(HARN) can be considered to be coincident with WGS 84.","Approximation at the +/- 1m level assuming that NAD83(HARN) is equivalent to WGS 84.",1337,-14.59,49.38,144.58,-64.51,1,0,9603,0,0,0,,,,,1
+108,1900,4152,4326,"Approximation derived ignoring time-dependent parameters and assuming ITRF94(1996.0) and WGS 84, plus NAD83(CORS94) and NAD83(HARN), can be considered the same within the accuracy of the transformation. Replaced by NAD83(HARN) to WGS 84 (3) (code 1901).",Historical record only - superseded - see remarks.,1323,24.41,49.38,-124.79,-66.91,1,0,9607,-0.9738,1.9453,0.5486,-0.0275507901704247,-0.0100492213603585,-0.0113590028800276,0,0
+109,1901,4152,4326,"Approximation derived from tfm code 6864 ignoring time-dependent parameters and assuming ITRF96(1997.0) and WGS 84, plus NAD83(CORS96) and NAD83(HARN), can be considered the same within the accuracy of the tfm. In USA only replaces tfm code 1900.","Geodesy. Accuracy with respect to CORS at stations adjusted to HARN network is better than 0.05-0.07m. For locations outside a HARN network (i.e. NAD83), accuracy may be only 1m but will usually be better than 0.5m.",1323,2 [...]
+110,15930,4152,4326,"Accuracy 0.1 to 0.2m in California, 0.05-0.11 in Oregon, elsewhere better than 0.05m.",For applications to an accuracy of 0.2 metre.,1323,24.41,49.38,-124.79,-66.91,1,1,9603,0,0,0,,,,,0
+111,1512,4153,4326,"Derived in 1998 at Assaluyeh (Taheri refinery) by Geoid for Total. Used for South Pars phases 2 and 3.",Oil industry engineering survey. Used only for terminal site.,1338,27.39,27.61,52.5,52.71,1,0,9603,-133.63,-157.5,-158.62,,,,,1
+112,1141,4154,4326,"Given by DMA as from ED50. OGP interpret that as ED50(ED77) in Iran. Derived at 27 stations.","For military purposes. Accuracy 9m, 12m and 11m in X, Y and Z axes.",1123,23.34,39.78,44.03,63.34,1,0,9603,-117,-132,-164,,,,,1
+113,1514,4154,4326,"Used for South Pars phases 6, 7 and 8.","Transformation for whole country: accuracy about 1m.",1123,23.34,39.78,44.03,63.34,1,0,9606,-110.33,-97.73,-119.85,0.3423,1.1634,0.2715,0.063,0
+114,1856,4154,4326,Derived in Kangan district by Geoid for Total in 1998. Used for South Pars phases 2 and 3.,Petroleum Exploration and Production.,2783,26.58,26.71,52.07,52.28,1,0,9603,-122.89,-159.08,-168.74,,,,,0
+115,1857,4154,4326,Derived in 1999 on Lavan island by Geoid for Elf.,Petroleum Exploration and Production.,2782,26.21,26.87,52.49,53.43,1,0,9603,-84.78,-107.55,-137.25,,,,,0
+116,1858,4154,4326,Derived by Geoid for Elf in 1999. EGM96 geoid used.,Petroleum Exploration and Production.,2781,29.16,29.39,50.22,50.42,1,0,9603,-123.92,-155.515,-157.721,,,,,0
+117,15745,4154,4326,Derived in Tombak district in March 2005. Used for South Pars phase 11.,Petroleum Exploration and Production.,3140,26.46,26.64,52.22,52.41,1,0,9603,-123.02,-158.95,-168.47,,,,,0
+118,1518,4155,4326,,Accuracy 25m in each axis.,3257,7.19,12.68,-15.13,-7.65,1,0,9603,-83,37,124,,,,,1
+119,1623,4156,4326,"Parameter values from S-JTSK to ETRS89 (1) (code 1622). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by S-JTSK to WGS 84 (5) (code 5239).",For applications to an accuracy of 1 metre.,1079,48.58,51.06,12.09,18.86,1,0,9606,570.8,85.7,462.8,4.998,1.587,5.261,3.56,0
+120,1625,4156,4326,"Parameter values from S-JTSK to ETRS89 (2) (code 1624). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.73,49.61,16.84,22.56,1,1,9606,559,68.7,451.5,7.92,4.073,4.251,5.71,0
+121,4828,4156,4326,"Parameter values from S-JTSK to ETRS89 (4) (code 4827). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.73,49.61,16.84,22.56,1,1,9606,485,169.5,483.5,7.786,4.398,4.103,0,0
+122,4836,4156,4326,"Parameter values from S-JTSK to ETRS89 (4) (code 4827). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1211,47.73,49.61,16.84,22.56,1,0,9606,485,169.5,483.8,7.786,4.398,4.103,0,0
+123,5239,4156,4326,"Parameter values from S-JTSK/05 to WGS 84 (1) (code 5227). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces tfm code 1622.",For applications to an accuracy of 1 metre.,1079,48.58,51.06,12.09,18.86,1,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378,0
+124,15965,4156,4326,Derived at 6 stations.,"For military purposes. Accuracy 4m, 2m and 3m in X, Y and Z axes.",1306,47.73,51.06,12.09,22.56,1,0,9603,589,76,480,,,,,1
+125,1283,4669,4326,,LKS94 is a realisation of ETRS89 coincident to WGS 84 within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1145,53.89,56.45,19.02,26.82,1,0,9603,0,0,0,,,,,1
+126,1099,4670,4326,"Parameter values taken from IGM95 to ETRS89 (1) (code 1098) assuming that ETRS89 is coincident with WGS 84 within the accuracy of the transformation.",Approximation at the 1m level.,3343,34.76,47.1,5.93,18.99,1,0,9603,0,0,0,,,,,1
+127,1859,4159,4326,"Used by Repsol in Murzuq field, and PetroCanada and previous licence holders in NC177 and 72 (En Naga field). Reliability of connection to ELD79 questionned.",Oil Exploration,2785,27.32,27.67,18.37,18.72,1,0,9603,-69.06,-90.71,-142.56,,,,,0
+128,1860,4159,4326,Derived December 2001 by NAGECO. Connected to ITRF via Remsa 2000 data. Used by TotalFinaElf.,Oil Exploration. 3-dimensional SD at 11 points is 0.5m.,2785,27.32,27.67,18.37,18.72,1,0,9603,-113.997,-97.076,-152.312,,,,,0
+129,1861,4159,4326,Derived by GEOID in 1994 from Transit satellite data. Used by TotalFinaElf.,Oil Exploration,2786,29.61,30.07,17.13,17.51,1,0,9603,-114.5,-96.1,-151.9,,,,,0
+130,1862,4159,4326,"Derived by Geoid in 2000 from ITRF connection by NAGECO for TotalFinaElf. For historic compatibility TFE use the 1994 tfm ELD79 to WGS 84 (3) (code 1861) rather than this transformation.",Oil Exploration,2786,29.61,30.07,17.13,17.51,1,0,9606,-194.513,-63.978,-25.759,-3.4027,3.756,-3.352,-0.9175,0
+131,1863,4159,4326,"Derived for the Great Man-made River Authority (GMRA).",Engineering survey and oil exploration,2786,29.61,30.07,17.13,17.51,1,0,9607,-389.691,64.502,210.209,-0.086,-14.314,6.39,0.9264,0
+132,15707,4159,4326,"Used by Petrocanada and previous licence holders in Amal field, concession 12.",Oil exploration and production,2987,29.1,29.8,20.8,21.4,1,0,9603,-118.996,-111.177,-198.687,,,,,0
+133,15778,4159,4326,"Derived by Total at stations SDL 130-03, 04 and 05 in May 2005.",Oil exploration and production.,3142,27.5,28.07,21.25,21.59,1,0,9603,-114.7,-98.5,-150.7,,,,,0
+134,15909,4159,4326,Derived at 29 stations throughout Libya in May 2006.,For applications to an accuracy of 5 metres.,3271,19.49,33.23,9.31,25.21,1,0,9603,-115.8543,-99.0583,-152.4616,,,,,1
+135,15923,4159,4326,"Derived by SDL for Total in Cyrenaica blocks 2 & 4.",Oil and gas exploration.,3477,32,32.8,22.49,23,1,0,9603,-117.7,-100.3,-152.4,,,,,0
+136,1080,4672,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,2889,-44.64,-43.3,-177.25,-175.54,1,0,9603,175,-38,113,,,,,1
+137,1081,4673,4326,Derived at 4 stations using concatenation through WGS72. Parameter vales are also used to transform CI1979 to NZGD2000 - see tfm code 1082.,For applications requiring 2m accuracy.,2889,-44.64,-43.3,-177.25,-175.54,1,0,9607,174.05,-25.49,112.57,0,0,-0.554,0.2263,1
+138,15894,4674,4326,,Accuracy 1m.,3418,-59.87,32.72,-122.19,-25.28,1,0,9603,0,0,0,,,,,1
+139,1070,4675,4326,Derived at 5 stations.,For military purposes only. Accuracy 3m in each axis.,3255,13.18,13.7,144.58,145.01,1,0,9603,-100,-248,259,,,,,1
+140,1682,4164,4326,"Parameter values taken from South Yemen to Yemen NGN96 (1) (code 1539) assuming that NGN96 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 5m level.",1340,12.54,19,43.37,53.14,1,0,9603,-76,-138,67,,,,,1
+141,1547,4165,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,3258,10.87,12.69,-16.77,-13.64,1,0,9603,-173,253,27,,,,,1
+142,1065,4678,4326,Derived at 25 stations.,Accuracy 5m.,1138,13.92,22.5,100.09,107.7,1,0,9603,44.585,-131.212,-39.544,,,,,1
+143,1565,4167,4326,,Assumes NZGD2000 is coincident to WGS 84 to the 1m accuracy level.,1175,-55.95,-25.88,160.6,-171.2,1,0,9603,0,0,0,,,,,1
+144,1569,4168,4326,Derived at 3 common points.,Military survey,1104,1.4,11.16,-3.79,2.1,1,0,9603,-199,32,322,,,,,1
+145,15495,4168,4326,Derived via WGS 72BE. Found in use within oil industry erroneously concatenated via WGS 72. See tfm code 8571.,Oil industry.,1505,1.4,6.06,-3.79,2.1,1,0,9606,-171.16,17.29,325.21,0,0,0.814,-0.38,0
+146,1577,4169,4326,Transformation based on observations at 2 stations in 1993.,For military purposes. One sigma uncertainty is 25m in each axis.,3109,-14.43,-14.11,-170.88,-169.38,1,0,9603,-115,118,426,,,,,1
+147,1581,4170,4326,,For military purposes. Accuracy 1m in each axis.,3448,-59.87,16.75,-113.21,-26,1,0,9603,0,0,0,,,,,1
+148,1671,4171,4326,"Parameter values from RGF93 to ETRS89 (1) (code 1591) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level.",1096,41.15,51.56,-9.86,10.38,1,0,9603,0,0,0,,,,,1
+149,1598,4172,4326,,"?",1033,-58.41,-21.78,-73.59,-52.63,1,1,9603,0,0,0,,,,,0
+150,1678,4173,4326,Assumes that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. IRENET95 is a regional realisation of ETRS89.,"Approximation at the +/- 1m level.",1305,51.39,55.43,-10.56,-5.34,1,0,9603,0,0,0,,,,,1
+151,15738,4686,4326,,MAGNA-SIRGAS is a realisation of WGS 84 coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1070,-4.23,15.51,-84.77,-66.87,1,0,9603,0,0,0,,,,,1
+152,1614,4175,4326,"Determined at 8 stations. Info. source has the source CRS as Sierra Leone 1960. Sierra Leone 1968 is a readjustment of the 1960 network: coordinates changed by less than 3 metres.","Accuracy +/- 15m in each axis.",3306,6.88,10,-13.35,-10.26,1,0,9603,-88,4,101,,,,,1
+153,1890,4176,4326,For many purposes Australian Antarctic can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that Australian Antarctic is equivalent to WGS 84.",1278,-90,-60,45,160,1,0,9603,0,0,0,,,,,1
+154,15773,4689,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN63 Hiva Oa to RGPF (1) (tfm code 15761).","Accuracy +/- 1 metre.",3131,-9.89,-9.64,-139.23,-138.75,1,0,9607,410.721,55.049,80.746,-2.5779,-2.3514,-0.6664,17.3311,1
+155,15774,4689,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from IGN63 Hiva Oa to RGPF (2) (tfm code 15762).","Accuracy +/- 2 metres.",3132,-10.08,-9.86,-139.19,-138.98,1,0,9607,374.716,-58.407,-0.957,-16.2111,-11.4626,-5.5357,-0.5409,0
+156,1675,4178,4326,"Parameter values from Pulkovo 1942(83) to ETRS89 (1) (code 1674) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.",Residuals under 2 m.,1343,50.2,54.74,9.92,15.04,1,0,9607,24,-123,-94,-0.02,0.25,0.13,1.1,0
+157,15996,4178,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1119,45.74,48.58,16.11,22.9,1,0,9603,28,-121,-77,,,,,0
+158,15998,4178,4326,Derived at 6 stations.,"For military purposes only. Accuracy 3m, 3m and 2m in X, Y and Z axes.",1306,47.73,51.06,12.09,22.56,1,0,9603,26,-121,-78,,,,,1
+159,1645,4179,4326,"Parameter values from Pulkovo 1942(58) to ETRS89 (1) (code 1644). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3293,49,54.89,14.14,24.15,1,0,9606,33.4,-146.6,-76.3,-0.359,-0.053,0.844,-0.84,1
+160,15496,4179,4326,,Oil exploration,1197,43.44,48.27,20.26,31.41,1,0,9603,44.107,-116.147,-54.648,,,,,0
+161,15497,4179,4326,Derived at 4 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.44,48.27,20.26,31.41,1,0,9603,28,-121,-77,,,,,0
+162,15995,4179,4326,"Parameter values taken from Pulkovo 1942(58) to ETRS89 (4) (code 15994) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy of 1.5 to 3 metres horizontal, 3 to 5m vertical.",1197,43.44,48.27,20.26,31.41,1,0,9607,2.329,-147.042,-92.08,0.309,-0.325,-0.497,5.69,0
+163,15997,4179,4326,Derived at 11 stations.,"For military purposes only. Accuracy 4m, 2m and 4m in X, Y and Z axes.",3293,49,54.89,14.14,24.15,1,0,9603,23,-124,-82,,,,,0
+164,15999,4179,4326,Derived at 7 stations.,For military purposes. Accuracy 3m in each axis.,3212,39.64,42.67,19.22,21.06,1,0,9603,24,-130,-92,,,,,0
+165,1649,4180,4326,"Parameter values taken from EST97 to ETRS89 (1) (code 1648). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1090,57.52,60,20.37,28.2,1,0,9603,0,0,0,,,,,1
+166,1643,4181,4326,"Parameter values from Luxembourg 1930 to ETRS89 (1) (code 1642). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1146,49.44,50.19,5.73,6.53,1,0,9606,-193,13.7,-39.3,-0.41,-2.933,2.688,0.43,0
+167,5486,4181,4326,"Parameter values from Luxembourg 1930 to ETRS89 (3) (code 5485) assuming ETRS89 and WGS 84 are coincident within the one metre level. Replaces tfm code 1643. For an equivalent transformation using the Molodensky-Badekas method see code 5484.",For applications to an accuracy of 1 metre.,1146,49.44,50.19,5.73,6.53,1,0,9607,-189.6806,18.3463,-42.7695,0.33746,3.09264,-2.53861,0.4598,1
+168,1210,4694,4326,,POSGAR 94 is a local realisation of WGS 84.,1033,-58.41,-21.78,-73.59,-52.63,1,0,9603,0,0,0,,,,,1
+169,1886,4183,4326,Derived at 5 stations.,For military purposes only. Accuracy 3m in each axis.,1301,38.32,39.14,-28.9,-26.97,1,0,9603,-104,167,-38,,,,,1
+170,1885,4184,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,1345,36.87,37.96,-25.92,-24.62,1,0,9603,-203,141,53,,,,,1
+171,15794,4708,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1069,-12.25,-12.08,96.76,96.92,1,0,9603,-491,-22,435,,,,,1
+172,15850,4698,4326,"Also published in US NIMA/NGA TR8350.2 which gives accuracy of +/-25m in each axis and states that derived at one station.","Accuracy +/- 10 metres.",2816,-49.78,-48.6,68.69,70.62,1,0,9603,145,-187,103,,,,,1
+173,15784,4699,4326,Derived at 17 stations in 1994 by University of East London. Residuals less than 2m.,Accuracy 2m.,3209,-20.57,-19.94,57.25,57.85,1,0,9603,-770.1,158.4,-498.2,,,,,1
+174,1955,4188,4326,"Parameter values from TM75 to ETRS89 (2) (code 1953). Assumes each pair of (i) OSNI 1952 and TM75, and (ii) ETRS89 and WGS 84, can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,2530,53.96,55.36,-8.18,-5.34,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
+175,1768,4189,4326,,"Approximation at the +/- 1m level.",1251,0.64,16.75,-73.38,-58.95,1,0,9603,0,0,0,,,,,1
+176,1773,4190,4326,,"Approximation at the +/- 1m level.",1033,-58.41,-21.78,-73.59,-52.63,1,0,9603,0,0,0,,,,,1
+177,15780,4190,4326,,"Approximation at the +/- 1m level.",1033,-58.41,-21.78,-73.59,-52.63,1,1,9603,0,0,0,,,,,0
+178,15873,4192,4326,Derived at Manoca tower assuming the pyramid on the tower and the centre of the tower reservoir are co-located. This assumption carries a few metres uncertainty.,Oil exploration.,2555,2.16,4.99,8.45,10.4,1,0,9603,-206.1,-174.7,-87.7,,,,,1
+179,1796,4193,4326,"Derived at two points, checked at a third by Stolt Comex Seaway and Geoid for Elf.",Oil industry,2555,2.16,4.99,8.45,10.4,1,0,9603,-70.9,-151.8,-41.4,,,,,1
+180,1797,4194,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m, 25m and 32m in X, Y and Z axes.",3362,59.74,79,-73.29,-42.52,1,0,9603,164,138,-189,,,,,1
+181,1798,4194,4326,,Topographic mapping.,3362,59.74,79,-73.29,-42.52,1,0,9606,163.511,127.533,-159.789,0,0,0.814,-0.6,0
+182,1799,4195,4326,,Topographic mapping.,2570,68.66,74.58,-29.69,-19.89,1,0,9606,105,326,-102.5,0,0,0.814,-0.6,1
+183,1800,4196,4326,,Topographic mapping.,2571,65.52,65.91,-38.86,-36.81,1,0,9606,-45,417,-3.5,0,0,0.814,-0.6,1
+184,15796,4709,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,3200,24.67,24.89,141.2,141.42,1,0,9603,145,75,-272,,,,,1
+185,15798,4710,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,3183,-16.08,-15.85,-5.85,-5.58,1,0,9603,-320,550,-494,,,,,1
+186,15799,4711,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1872,24.22,24.35,153.91,154.05,1,0,9603,124,-234,-25,,,,,1
+187,1281,4200,4326,"Derived through concatenation of Pulkovo 1995 to PZ-90 (1) (tfm code 1257) and PZ-90 to WGS 84 (2) (tfm code 1244). Mandated for use in Russia by GOST R 51794-2001, but this has been superseded by GOST R 51794-2008. Replaced by tfm code 5043.",Accuracy 1 metre.,1198,39.87,85.2,18.92,-168.97,1,0,9607,24.82,-131.21,-82.66,0,0,-0.16,-0.12,0
+188,5043,4200,4326,"Derived through concatenation of Pulkovo 1995 to PZ-90.02 to WGS 84. Replaces Pulkovo 1995 to WGS 84 (1), tfm code 1281.",Accuracy 1 metre.,1198,39.87,85.2,18.92,-168.97,1,0,9607,24.47,-130.89,-81.56,0,0,-0.13,-0.22,1
+189,1100,4201,4326,Derived at 22 stations.,For military purposes only. Accuracy 5m in each axis.,1271,3.4,22.24,21.82,47.99,1,0,9603,-166,-15,204,,,,,1
+190,1101,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Burkino Faso.",For military purposes. Accuracy 25m in each axis.,1057,9.39,15.09,-5.53,2.4,1,0,9603,-118,-14,218,,,,,0
+191,1102,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Cameroon.",For military purposes. Accuracy 25m in each axis.,3226,1.65,13.09,8.45,16.21,1,0,9603,-134,-2,210,,,,,0
+192,1103,4201,4326,Derived at 8 stations.,For military purposes. Accuracy 3m in each axis.,1091,3.4,14.89,32.99,47.99,1,0,9603,-165,-11,206,,,,,0
+193,1104,4201,4326,"Derived at 1 station connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Mali.",For military purposes. Accuracy 25m in each axis.,1153,10.14,25.01,-12.25,4.26,1,0,9603,-123,-20,220,,,,,0
+194,1105,4201,4326,"Derived at 2 stations connected to the Adindan network through the 1968-69 12th parallel traverse. Note: Adindan datum is used in Ethiopia and Sudan, not Senegal.",For military purposes. Accuracy 25m in each axis.,3304,12.29,16.7,-17.59,-11.36,1,0,9603,-128,-18,224,,,,,0
+195,1106,4201,4326,Derived at 14 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",3311,3.49,22.24,21.82,38.66,1,0,9603,-161,-14,205,,,,,0
+196,1108,4202,4326,Derived at 105 stations.,For military purposes only. Accuracy 3m in each axis.,2575,-43.7,-9.86,112.85,153.69,1,0,9603,-133,-48,148,,,,,0
+197,1665,4202,4326,"Parameter values from AGD66 to GDA94 (2) (code 1458). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in A.C.T. 1m accuracy.,2283,-35.93,-35.12,148.76,149.4,1,0,9607,-129.193,-41.212,130.73,-0.246,-0.374,-0.329,-2.955,0
+198,1666,4202,4326,"Parameter values from AGD66 to GDA94 (4) (code 1460). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in NSW and Victoria. 1m accuracy.,2286,-39.2,-28.15,140.96,153.69,1,0,9607,-119.353,-48.301,139.484,-0.415,-0.26,-0.437,-0.613,0
+199,1667,4202,4326,"Parameter values from AGD66 to GDA94 (8) (code 1594). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in Tasmania. 1m accuracy.,1282,-43.7,-39.52,143.77,148.55,1,0,9607,-120.271,-64.543,161.632,-0.217,0.067,0.129,2.499,0
+200,1668,4202,4326,"Parameter values from AGD66 to GDA94 (9) (code 1595). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",Recommended for mid-accuracy use in Northern Territory. 1m accuracy.,2284,-26.01,-10.86,128.99,138,1,0,9607,-124.133,-42.003,137.4,0.008,-0.557,-0.178,-1.854,0
+201,5841,4202,4326,Derived at 25 stations in 2007.,"Accuracy 2m in 2007. Due to significant tectonic activity in PNG, AGD66 and WGS 84 are separating by approximately 7cm per year.",4013,-8.28,-5.59,142.24,144.75,1,0,9603,-124,-60,154,,,,,0
+202,15788,4202,4326,"Parameter values from AGD66 to GDA94 (1) (code 1278). Derived at 162 stations. Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation.",5m accuracy.,2575,-43.7,-9.86,112.85,153.69,1,0,9603,-127.8,-52.3,152.9,,,,,0
+203,15980,4202,4326,"Parameter values from AGD66 to GDA94 (12) (code 15979). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation. Use only offshore: onshore tfms 1665-68 for ACT, NSW/Vic, Tas and NT respectively are more accurate.",3m accuracy.,3559,-47.2,-8.88,109.23,163.2,1,0,9607,-117.808,-51.536,137.784,-0.303,-0.446,-0.234,-0.29,1
+204,1109,4203,4326,"Derived at 90 stations. Note: AGD84 officially adopted only in Queensland, South Australia and Western Australia.",For military purposes only. Accuracy 2m in each axis.,2575,-43.7,-9.86,112.85,153.69,1,0,9603,-134,-48,149,,,,,1
+205,1236,4203,4326,"""Higgins parameters"". Replaced by AGD84 to GDA94 (2) (code 1280) and AGD84 to WGS 84 (7) (code 1669). Note: AGD84 officially adopted only in Queensland, South Australia and Western Australia.",Preliminary estimate.,2575,-43.7,-9.86,112.85,153.69,1,0,9607,-116,-50.47,141.69,-0.23,-0.39,-0.344,0.0983,0
+206,1669,4203,4326,"Parameter values from AGD84 to GDA94 (2) (code 1280). Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces AGD84 to WGS 84 (2) (code 1236). Note: AGD84 officially adopted only in Qld, SA and WA.",1m accuracy.,2575,-43.7,-9.86,112.85,153.69,1,0,9607,-117.763,-51.51,139.061,-0.292,-0.443,-0.277,-0.191,0
+207,15789,4203,4326,"Parameter values from AGD84 to GDA94 (1) (code 1279). Derived at 327 stations. Assumes GDA94 and WGS 84 can be considered the same to within the accuracy of the tfm. AGD84 officially adopted only in Queensland, South Australia and Western Australia.",5m accuracy.,2575,-43.7,-9.86,112.85,153.69,1,0,9603,-128.5,-53,153.4,,,,,0
+208,1055,4204,4326,Derived at station K1.,1 metre accuracy.,3267,28.53,30.09,46.54,48.48,1,0,9603,-145.7,-249.1,1.5,,,,,0
+209,1056,4204,4326,"Derivation is more precise, but no evidence that accuracy is better than Ain el Abd to WGS 84 (3). OGP recommends using Ain el Abd to WGS 84 (3).",1 metre accuracy.,3267,28.53,30.09,46.54,48.48,1,0,9607,-85.645,-273.077,-79.708,-2.289,1.421,-2.532,3.194,0
+210,1057,4204,4326,.,1 metre accuracy.,2956,29.1,30.09,46.54,48.42,1,0,9607,-202.234,-168.351,-63.51,-3.545,-0.659,1.945,2.1,0
+211,1058,4204,4326,,1 metre accuracy.,2957,28.53,29.45,46.54,48.48,1,0,9607,-18.944,-379.364,-24.063,-0.04,0.764,-6.431,3.657,0
+212,1110,4204,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,3943,25.53,26.34,50.39,50.85,1,0,9603,-150,-250,-1,,,,,0
+213,1111,4204,4326,Derived at 9 stations.,For military purposes. Accuracy 10m in each axis.,3303,15.61,32.16,34.51,55.67,1,0,9603,-143,-236,7,,,,,1
+214,1107,4205,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3308,-1.71,12.03,40.99,51.47,1,0,9603,-43,-163,45,,,,,1
+215,15805,4718,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3198,-8.86,-7.52,156.44,158.2,1,0,9603,230,-199,-752,,,,,1
+216,15807,4718,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3197,-9.98,-9.2,159.55,160.88,1,0,9603,252,-209,-751,,,,,0
+217,1656,4207,4326,"Parameter values from Lisbon to ETRS89 (1) (code 1655). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by Lisbon to WGS 84 (4) (code 1988).",For applications to an accuracy of 3 metres.,1294,36.95,42.16,-9.56,-6.19,1,0,9606,-280.9,-89.8,130.2,-1.721,0.355,-0.371,-5.92,0
+218,1944,4207,4326,"Parameter values from Lisbon to ETRS89 (2) (code 1790). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 2 metres.,1294,36.95,42.16,-9.56,-6.19,1,1,9606,-282.1,-72.2,120,-1.592,0.145,-0.89,-4.46,0
+219,1984,4207,4326,,For low resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9603,-304.046,-60.576,103.64,,,,,1
+220,1988,4207,4326,,For medium resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9607,-288.885,-91.744,126.244,1.691,-0.41,0.211,-4.598,0
+221,1549,4208,4326,,Oil exploration.,2307,-28.41,-17.59,-48.8,-35.18,1,1,9603,-158,315,-148,,,,,0
+222,1550,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2308,-9.8,-8.39,-39.04,-37.09,1,0,9603,-139.62,290.53,-150.29,,,,,0
+223,1551,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2309,-10.61,-9.79,-39.14,-37.99,1,0,9603,-141.15,293.44,-150.56,,,,,0
+224,1552,4208,4326,"Replaced by Aratu to WGS 84 (18) (tfm code 5061) which Petrobras now recommends for the area.",Oil exploration.,2310,-12.27,-10.6,-39.07,-37.98,1,0,9603,-142.48,296.03,-149.74,,,,,0
+225,10089,4208,4326,"Used by ExxonMobil for block BMS1. See WGS 84 (13) (tfm code 5051) which Petrobras now recommends for the area.",Oil exploration.,2962,-28.41,-22.66,-48.8,-40.2,1,0,9603,-163.466,317.396,-147.538,,,,,0
+226,10090,4208,4326,"Used by ExxonMobil for block BC10. Derived from earlier Shell position vector tfm of dX = -181m, dY = +294m, dZ = -144.5m, rX = rY = 0, rZ = +0.554s, dS = +0.219 ppm. See Aratu to WGS 84 (14) (tfm code 5053) which Petrobras now recommends for the area.",Oil exploration.,2963,-25.91,-20.45,-42.04,-37.11,1,0,9603,-170,305,-145,,,,,0
+227,10091,4208,4326,"Used by ExxonMobil for block BMES1. See Aratu to WGS 84 (15) (tfm code 5055) which Petrobras now recommends for the area.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.18,1,0,9603,-162.904,312.531,-137.109,,,,,0
+228,10092,4208,4326,"Used by ExxonMobil for block BP1. Also used by BG as part of a concatenated tfm to SAD69 for offshore regional studies. See WGS 84 (13) (tfm code 5051) for transformation Petrobras now recommends for the area.",Oil exploration.,2965,-35.71,-28.11,-53.38,-44.71,1,0,9603,-158,309,-151,,,,,0
+229,10093,4208,4326,"Used by ExxonMobil for offshore regional studies. See Aratu to WGS 84 (13) through (21) (tfm codes 5051-67 [odd numbers only]) which Petrobras now recommends for various areas.",Oil exploration.,2966,-34,-18,-53.38,-35.19,1,0,9603,-161,308,-142,,,,,0
+230,10094,4208,4326,Derived by IGN in 1992 at 7 stations within Nouakchott city.,Oil exploration.,2972,17.89,18.25,-16.11,-15.83,1,1,9603,124.5,-63.5,-281,,,,,0
+231,5051,4208,4326,"Parameters from Aratu to SIRGAS 2000 (1) (tfm code 5050) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfm codes 15711 and 15734.",Oil exploration.,3700,-35.71,-22.66,-53.38,-40.2,1,0,9603,-157.84,308.54,-146.6,,,,,0
+232,5053,4208,4326,"Parameters from Aratu to SIRGAS 2000 (2) (tfm code 5052) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfm codes 15710 and 15754.",Oil exploration.,2963,-25.91,-20.45,-42.04,-37.11,1,0,9603,-160.31,314.82,-142.25,,,,,0
+233,5055,4208,4326,"Parameters from Aratu to SIRGAS 2000 (3) (tfm code 5054) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfms 15712 and 15754.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.18,1,0,9603,-161.11,310.25,-144.64,,,,,0
+234,5057,4208,4326,"Parameters from Aratu to SIRGAS 2000 (4) (tfm code 5056) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3699,-17.7,-13.01,-39.22,-34.6,1,0,9603,-160.4,302.29,-144.19,,,,,0
+235,5059,4208,4326,"Parameters from Aratu to SIRGAS 2000 (5) (tfm code 5058) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3692,-13.57,-11.18,-39.09,-35.31,1,0,9603,-153.54,302.33,-152.37,,,,,0
+236,5061,4208,4326,"Parameters from Aratu to SIRGAS 2000 (6) (tfm code 5060) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area. Replaces tfms 1550-1552.",Oil exploration.,3693,-12.27,-8.39,-39.14,-37.09,1,0,9603,-151.5,300.09,-151.15,,,,,0
+237,5063,4208,4326,"Parameters from Aratu to SIRGAS 2000 (7) (tfm code 5062) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3696,-13.58,-8.73,-37.34,-32.01,1,0,9603,-156.8,298.41,-147.41,,,,,0
+238,5065,4208,4326,"Parameters from Aratu to SIRGAS 2000 (8) (tfm code 5064) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation.Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3697,-10.17,-4.6,-35.1,-29.13,1,0,9603,-157.4,295.05,-150.19,,,,,0
+239,5067,4208,4326,"Parameters from Aratu to SIRGAS 2000 (9) (tfm code 5066) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Petrobras preferred parameters for all purposes in the area.",Oil exploration.,3698,-6.5,4.26,-44.79,-26,1,0,9603,-151.99,287.04,-147.45,,,,,1
+240,15710,4208,4326,"Replaced by Aratu to WGS 84 (14) (tfm code 5053) which Petrobras now recommends for the area.",Oil exploration.,2963,-25.91,-20.45,-42.04,-37.11,1,0,9603,-160,315,-142,,,,,0
+241,15711,4208,4326,"Replaced by Aratu to WGS 84 (13) (tfm code 5051) which Petrobras now recommends for the area.",Oil exploration.,2962,-28.41,-22.66,-48.8,-40.2,1,0,9603,-158,309,-147,,,,,0
+242,15712,4208,4326,"Replaced by Aratu to WGS 84 (15) (tfm code 5055) which Petrobras now recommends for the area.",Oil exploration.,2964,-22.04,-17.59,-40.37,-35.18,1,0,9603,-161,310,-145,,,,,0
+243,15754,4208,4326,"Mean for 3 basins. See Aratu to WGS 84 (10) through (12) (codes 15710-12) for transformations for individual basins. Replaced by Aratu to WGS 84 (13) through (15) (tfm codes 5051, 5053 and 5055) which Petrobras now recommends for the areas.",Oil exploration.,2307,-28.41,-17.59,-48.8,-35.18,1,0,9603,-158,315,-148,,,,,0
+244,1113,4209,4326,Derived at 41 stations.,"For military purposes only. Accuracy 20m, 33m and 20m in X, Y and Z axes.",2312,-30.66,-8.19,19.99,35.93,1,0,9603,-143,-90,-294,,,,,1
+245,1114,4209,4326,Derived at 9 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1051,-26.88,-17.78,19.99,29.38,1,0,9603,-138,-105,-289,,,,,0
+246,1115,4209,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,1058,-4.45,-2.3,28.98,30.86,1,1,9603,-153,-5,-292,,,,,0
+247,1116,4209,4326,Derived at 5 stations.,"For military purposes. Accuracy 3m, 3m and 8m in X, Y and Z axes.",1141,-30.66,-28.57,27.01,29.46,1,0,9603,-125,-108,-295,,,,,0
+248,1117,4209,4326,Derived at 6 stations.,"For military purposes. Accuracy 9m, 24m and 8m in X, Y and Z axes.",1150,-17.14,-9.37,32.68,35.93,1,0,9603,-161,-73,-317,,,,,0
+249,1118,4209,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1224,-27.32,-25.72,30.79,32.14,1,0,9603,-134,-105,-295,,,,,0
+250,1119,4209,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1259,-13.46,5.39,11.79,31.31,1,1,9603,-169,-19,-278,,,,,0
+251,1120,4209,4326,Derived at 5 stations.,"For military purposes. Accuracy 21m, 21m and 27m in X, Y and Z axes.",1260,-18.08,-8.19,21.99,33.71,1,0,9603,-147,-74,-283,,,,,0
+252,1121,4209,4326,Derived at 10 stations.,"For military purposes. Accuracy 5m, 8m and 11m in X, Y and Z axes.",1261,-22.42,-15.61,25.23,33.08,1,0,9603,-142,-96,-293,,,,,0
+253,1122,4210,4326,Derived at 25 stations.,For military purposes only. Accuracy 20m in each axis.,2311,-11.75,4.63,29.34,41.91,1,0,9603,-160,-6,-302,,,,,1
+254,1284,4210,4326,Derived at 24 stations.,"For military purposes. Accuracy 4m, 3m and 3m in X, Y and Z axes.",3264,-4.72,4.63,33.9,41.91,1,0,9603,-157,-2,-299,,,,,0
+255,1285,4210,4326,Derived at 12 stations.,"For military purposes. Accuracy 6m, 9m and 10m in X, Y and Z axes.",3316,-11.75,-0.99,29.34,40.48,1,0,9603,-175,-23,-303,,,,,0
+256,3998,4210,4326,"Derived at 3 stations. From inspection of parameter values and geographic applicability of CRS, OGP believes that the published source CRS (Arc 1950) has been misidentified by information source. Analysis of TR8350.2 contour charts suggest Arc 1960.",For military purposes. Accuracy 20m in each axis.,1058,-4.45,-2.3,28.98,30.86,1,0,9603,-153,-5,-292,,,,,0
+257,1123,4211,4326,"Note: The area of use cited for this transformation (Sumatra) is not consistent with the area of use (Java) for the Batavia (Genuk) coordinate reference system. Derived at 5 stations.",For military purposes. Accuracy 3m in each axis.,1355,-5.99,5.97,95.16,106.13,1,0,9603,-377,681,-50,,,,,1
+258,1813,4211,4326,Used by ARCO offshore NW Java area.,Oil industry operations.,2577,-6.89,-4.07,105.77,110.01,1,0,9603,-378.873,676.002,-46.255,,,,,0
+259,1814,4211,4326,Used by PT Komaritim for Nippon Steel during East Java Gas Pipeline construction.,Oil industry operations.,2588,-8.46,-6.8,112.8,117.01,1,0,9603,-377.7,675.1,-52.2,,,,,0
+260,15793,4212,4326,"Derived at 2 stations (S40 and M1, St Annes Tower) in 2004.",Accuracy 2.5m.,3218,13,13.39,-59.71,-59.37,1,0,9603,31.95,300.99,419.19,,,,,1
+261,15809,4725,4326,"Derived at 2 satellite stations. Note: NGA online html files carry a different dZ value - OGP believe this is an erroneous transcription from the TR8350.2 line above.","Military and topographic mapping. Accuracy +/- 25m in each axis.",3201,16.67,16.79,-169.59,-169.47,1,0,9603,189,-79,-202,,,,,1
+262,6143,4726,4326,"Parameter values are taken from SIGD59 to CIGD11 (1) (code 6137) assuming that CIGD11 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1m.,3186,19.63,19.78,-80.14,-79.69,1,0,9607,8.853,-52.644,180.304,0.393,2.323,-2.96,-24.081,1
+263,15814,4726,4326,Determined from 1 satellite station.,"Military mapping. Accuracy +/- 25m in each axis.",3186,19.63,19.78,-80.14,-79.69,1,0,9603,42,124,147,,,,,0
+264,15829,4726,4326,Determined from 2 satellite stations.,"Topographic survey. Accuracy +/- 1m.",3186,19.63,19.78,-80.14,-79.69,1,0,9603,44.4,109,151.7,,,,,0
+265,15800,4713,4326,Derived at 1 satellite station.,For military purposes only. Accuracy 25m in each axis.,1081,10.94,12.72,41.75,44.15,1,0,9603,-79,-129,145,,,,,1
+266,1124,4216,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3221,32.21,32.43,-64.89,-64.61,1,0,9603,-73,213,296,,,,,1
+267,15970,4216,4326,"Parameter values from Bermuda 1957 to BDA2000 (1) (code 15969). Assumes BDA2000 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy +/- 1 metre.",3221,32.21,32.43,-64.89,-64.61,1,0,9607,-292.295,248.758,429.447,-4.9971,-2.99,-6.6906,1.0289,0
+268,15819,4729,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25 m in each axis.",3208,-25.14,-25,-130.16,-130.01,1,0,9603,185,165,42,,,,,1
+269,1125,4218,4326,Derived in 1987 at 7 stations.,"For military purposes. Accuracy 6m, 5m and 6m in X, Y and Z axes.",3686,-4.23,13.68,-79.1,-66.87,1,0,9603,307,304,-318,,,,,1
+270,1597,4218,4326,Derived in 1995 by WGC at first order stations Recreo and Mena via multi-day ties to 4 IGS stations. Residuals under 20cm.,Oil exploration.,2315,4.75,5.68,-73,-72.25,1,0,9603,304.5,306.5,-318.1,,,,,0
+271,15715,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (1) (tfm code 15714).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3082,9.8,12.52,-73,-71.06,1,0,9607,-806.413,-263.5,-622.671,12.4142185637707,-2.99084175323096,-39.0346863906349,-20.81616,0
+272,15717,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (2) (tfm code 15716).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3083,9.39,11.59,-76.08,-73,1,0,9607,100.783,187.382,-47,-9.22383004903209,2.42380329967319,-8.30827832824698,-13.56561,0
+273,15719,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (3) (tfm code 15718).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3084,8,9.4,-77.48,-74.39,1,0,9607,336.026,348.565,252.978,-17.2412894390071,-6.30649282215535,1.56204977191825,-5.771909,0
+274,15721,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (4) (tfm code 15720).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3085,5,9.4,-74.4,-71.99,1,0,9607,963.273,486.386,190.997,-16.4850360280866,-1.66882584284416,21.6928490465265,-13.89914,0
+275,15723,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (5) (tfm code 15722).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3086,5,8.01,-77.92,-74.39,1,0,9607,-90.29,247.559,-21.989,-8.69688534851263,-4.18803362841004,-12.8082668496251,2.181658,0
+276,15725,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (6) (tfm code 15724).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3087,3,5.01,-77.68,-74.39,1,0,9607,-0.562,244.299,-456.938,6.8668709851194,-8.25267346177889,-9.2967797230575,3.74656,0
+277,15727,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (7) (tfm code 15726).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3088,-1.13,3.01,-79.1,-74,1,0,9607,-305.356,222.004,-30.023,-9.69049385992583,1.03196819622539,-19.7573941768278,6.325747,0
+278,15729,4218,4326,"Approximation at the +/- 1m level assuming that MAGNA-SIRGAS is equivalent to WGS 84. Parameter values taken from Bogota 1975 to MAGNA-SIRGAS (8) (tfm code 15728).","Accuracy about 1 part in 10^5 of distance between points, depending on relative tectonic motion.",3089,-4.23,7.1,-74.4,-66.87,1,0,9607,221.899,274.136,-397.554,2.80844591036278,-0.44850858891268,-2.81017234679107,-2.199943,0
+279,1126,4219,4326,Accuracy estimate not available.,For military purposes.,1287,-3.3,-1.44,105.07,108.35,1,0,9603,-384,664,-48,,,,,1
+280,1318,4220,4326,,Used for oil exploration by Conoco.,2316,-8.59,-7.75,12.58,13.4,1,0,9603,-42.01,-332.21,-229.75,,,,,0
+281,1319,4220,4326,,Used for oil exploration by Texaco.,2317,-7.01,-6.01,12.08,12.84,1,0,9603,-40,-354,-224,,,,,0
+282,1320,4220,4326,"Replaced by Camacupa to WGS 84 (9). Used by Shell prior to 1994.",Oil exploration prior to 1994.,2321,-7.26,-6.03,11.08,12.09,1,0,9606,-37.2,-370.6,-224,0,0,0.554,0.219,0
+283,1321,4220,4326,"Derived as mean of 123 Transit passes at station Cabo Ledo NE base in November 1990. Used by Elf for block 7 up to December 1992 then replaced by Camacupa to WGS 84 (7). Used by Total in block 8, ExxonMobil block 24, Western Geophysical for spec. data.",Oil exploration.,2320,-17.26,-6.01,8.2,13.86,1,0,9603,-41.8,-342.2,-228.2,,,,,0
+284,1322,4220,4326,"Derived at station Djeno during coordination of platform PAL F2 in February 1992. Used by Elf for block 3 up to December 1992 then replaced by Camacupa to WGS 84 (7).",Oil exploration.,2318,-7.34,-6.66,11.74,12.5,1,0,9603,-55.5,-348,-229.2,,,,,0
+285,1323,4220,4326,Derived at Luanda observatory December 1992.,Used for oil exploration by Elf for 1993 block 7 shallow water survey.,2319,-10.09,-9.41,12.66,13.39,1,0,9603,-43,-337,-233,,,,,0
+286,1324,4220,4326,"Derived at platform PAL F2 in December 1992. For use in blocks 3, 7 and 17, replaced by Camacupa to WGS 84 (10) (code 1327).","Used for oil exploration by Elf for blocks 3, 7 and 17 between December 1992 and 1994 then superseded by Camacupa to WGS 84 (10). Used by Exxon for block 15 since 1993.",2322,-10.09,-6.03,10.83,13.39,1,0,9603,-48,-345,-231,,,,,0
+287,1325,4220,4326,"Derived at platform PAL F2 in December 1992. Used by Total for block 2 between December 1992 and 1994 then replaced by Camacupa to WGS 84 (10).",Oil exploration between December 1992 and 1994.,2317,-7.01,-6.01,12.08,12.84,1,0,9603,-48.6,-345.1,-230.8,,,,,0
+288,1326,4220,4326,"Derived by GPS on two Topnav DGPS reference stations at Djeno and Luanda. Replaces Camacupa to WGS 84 (3). In block 18 replaced by BP from 1999 by Camacupa to WGS 84 (10).",Used by Shell since 1994.,2323,-8.34,-6.03,11.08,12.75,1,0,9606,-41.057,-374.564,-226.287,0,0,0.554,0.219,0
+289,1327,4220,4326,Derived at platform PAL F2 in 1994 by Topnav using Doris.,Used for oil exploration by Elf in blocks 3 and 17 since 1994. Used by Total in block 2 since 1994. Adopted by BP-Amoco Elf and Exxon for blocks 18 and 31-33 in 1999.,2324,-8.59,-6.01,10.41,12.84,1,0,9603,-50.9,-347.6,-231,,,,,1
+290,1127,4221,4326,Derived at 20 stations.,For military purposes. Accuracy 5m in each axis.,3843,-54.93,-21.78,-73.59,-53.65,1,0,9603,-148,136,90,,,,,1
+291,1527,4221,4326,"Derived through ties at 2 stations (Cerro Colorado and Chihuido Sur) to 4 IGS stations in February 1995",Oil exploration.,2325,-37.5,-36.14,-70.5,-70.03,1,0,9603,-154.5,150.7,100.4,,,,,0
+292,1128,4222,4326,Derived at 5 stations.,"For military purposes. Accuracy 3m, 6m and 6m in X, Y and Z axes.",3309,-34.88,-22.13,16.45,32.95,1,0,9603,-136,-108,-292,,,,,1
+293,1129,4222,4326,"Parameter values are from Cape to Hartebeesthoek94 (1) (code 1504) assuming that Hartebeesthoek94 and WGS 84 are equivalent within the accuracy of the transformation. Residuals should not exceed 15 metres.",Accuracy 15m.,3309,-34.88,-22.13,16.45,32.95,1,0,9603,-134.73,-110.92,-292.66,,,,,0
+294,1130,4223,4326,Derived at 5 stations.,"For military purposes. Accuracy 6m, 9m and 8m in X, Y and Z axes.",1236,30.23,38.41,7.49,13.67,1,0,9603,-263,6,431,,,,,1
+295,1538,4223,4326,Derived at station Chaffar January 1995.,Oil exploration.,1489,33.22,38.41,7.81,13.67,1,0,9603,-260.1,5.5,432.2,,,,,0
+296,1131,4224,4326,Derived at 6 stations.,"For military purposes. Accuracy 6m, 9m and 5m in X, Y and Z axes.",3675,-22,-19.29,-62.57,-57.81,1,0,9603,-134,229,-29,,,,,0
+297,3972,4224,4326,"Mandatory for SICAD use until 2005. Replaced by Chua to SIRGAS 2000 (tfm code 4069).","Used by governmental agencies in Distrito Federal until adoption of SIRGAS 2000 by Brazil in 2005. Legally mandated for Cartography System of Distrito Federal (SICAD) until 2005.",3619,-15.94,-15.37,-48.1,-47.1,1,0,9603,-143.87,243.37,-33.52,,,,,1
+298,4834,4224,4326,"Parameter values from Chua to SIRGAS 2000 (1) (tfm code 4069) assuming that within the tfm accuracy SIRGAS 2000 is equivalent to WGS 84.","Cartography System of Distrito Federal (SICAD)",3619,-15.94,-15.37,-48.1,-47.1,1,0,9603,-144.35,242.88,-33.2,,,,,0
+299,1132,4225,4326,Derived at 17 stations.,"For military purposes. Accuracy 5m, 3m and 5m in X, Y and Z axes.",1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-206,172,-6,,,,,0
+300,6192,4225,4326,"Formed by concatenation of tfms codes 6191 and 1877. Used by Petrobras and ANP until February 2005 when replaced by Corrego Alegre 1970-72 to WGS 84 (4) (tfm code 6194).",Medium and small scale mapping.,1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-205.57,168.77,-4.12,,,,,1
+301,6194,4225,4326,"Parameter values from Corrego Alegre to SIRGAS 2000 (2) (tfm code 6193) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation. Used by ANP and Petrobras from February 2005, replacing use of tfm code 6192.",Medium and small scale mapping.,1293,-33.78,-2.68,-58.16,-34.74,1,0,9603,-206.05,168.28,-3.82,,,,,0
+302,1585,4227,4326,,"?",1227,32.31,37.3,34.96,42.38,1,1,9603,-177.5,14.1,237.6,,,,,0
+303,1586,4227,4326,"Derived in 1995 by CGG for Al Furat Petroleum Company. Can be approximated using geocentric translations of dX=-174.3m, dY=+14.1m, dZ=+237.6m.",Oil exploration.,2327,35.33,35.9,39.15,40.41,1,0,9606,-175.09,1.218,238.831,-0.047,0.019,0.808,0.1698,0
+304,1587,4227,4326,Derived at four stations by Topnav in 1997.,Oil exploration.,2328,35.79,36.5,40.5,41.39,1,0,9603,-191.77,15.01,235.07,,,,,0
+305,15741,4227,4326,Derived by Elf in 1991 from tfm code 1584 concatenated with a tfm from WGS72BE to WGS84.,Oil exploration. Accuracy 5m.,2329,34.49,35.9,39.3,40.81,1,0,9603,-187.5,14.1,237.6,,,,,0
+306,15742,4227,4326,Derived for 1998 Omar seismic survey and used in 2000 for El Isba seismic survey.,Oil exploration. Accuracy 5m.,3314,32.31,37.3,35.61,42.38,1,0,9603,-190.421,8.532,238.69,,,,,1
+307,15743,4227,4326,"Derived 2005 at 5 triangulation stations and using (EGM96 geoid model +1.15m). Used by Total/DEZPC for Jafra and Mazraa seismic surveys. Can be approximated using geocentric translations of dX=-190.6m, dY=+8.8m, dZ=+239.6m.",Oil exploration. Accuracy 0.5m.,2329,34.49,35.9,39.3,40.81,1,0,9606,-83.58,-397.54,458.78,-17.595,-2.847,4.256,3.225,0
+308,1244,4740,4326,"Mandated for use in Russia by GosStandard of Russia Decree #327 of August 9, 2001. Republished but with one significant figure less precision to parameter values in GOST R 51794-2008 of December 18 2008.",Geodetic applications. Accuracy better than 0.5 metre.,1198,39.87,85.2,18.92,-168.97,1,0,9607,-1.08,-0.27,-0.9,0,0,-0.16,-0.12,0
+309,15843,4740,4326,"Derived through Glonass and GPS at 30 stations throughout USSR - Former Soviet Union (FSU).",Geodetic applications. Accuracy better than 1.5 metres.,1262,-90,90,-180,180,1,0,9607,0,0,1.5,0,0,-0.076,0,1
+310,1148,4229,4326,Derived at 14 stations.,"For military purposes. Accuracy 3m, 6m and 8m in X, Y and Z axes.",1086,21.89,33.82,24.7,37.91,1,0,9603,-130,110,-13,,,,,1
+311,1546,4229,4326,,Used for oil exploration by GUPCO.,2341,27.19,30.01,32.34,34.27,1,1,9603,-146.21,112.63,4.05,,,,,0
+312,1075,4230,4326,"Derived in 1987 by Geodetic for TPAO. Used on BP 1991/92 2D seismic surveys in central and eastern Turkish sector of Black Sea. In Turkey, replaced by tfm code 1784. Also adopted for use offshore Israel.",Oil Exploration,2896,31.35,43.45,28.03,41.47,1,0,9603,-89.05,-87.03,-124.56,,,,,0
+313,1087,4230,4326,,Topographic mapping.,1130,29.18,33.38,34.88,39.31,1,0,9603,-112,-110.3,-140.2,,,,,0
+314,1133,4230,4326,Derived at 85 stations. In Germany will be accepted by LBA for minerals management purposes as alternative to tfm 1052 or 1998.,"For military purposes. Accepted for minerals management in Germany. Accuracy 3m, 8m and 5m in X, Y and Z axes.",2420,34.88,71.21,-9.56,31.59,1,0,9603,-87,-98,-121,,,,,1
+315,1134,4230,4326,Derived at 52 stations.,For military purposes only. Accuracy 3m each axis.,2421,42.33,57.8,-4.87,17.17,1,0,9603,-87,-96,-120,,,,,0
+316,1135,4230,4326,Accuracy estimate not available.,For military purposes only.,2345,15.61,37.39,34.17,55.67,1,0,9603,-103,-106,-141,,,,,0
+317,1136,4230,4326,Derived at 4 stations.,For military purposes only. Accuracy 15m in each axis.,1078,32.88,36.21,29.95,35.2,1,0,9603,-104,-101,-140,,,,,0
+318,1137,4230,4326,Derived at 14 stations.,"For military purposes. Accuracy 6m, 8m and 8m in X, Y and Z axes.",2595,25.71,31.68,24.7,30,1,0,9603,-130,-117,-151,,,,,0
+319,1138,4230,4326,Derived at 40 stations.,For military purposes only. Accuracy 3m in each axis.,2343,49.11,60.9,-10.56,1.84,1,0,9603,-86,-96,-120,,,,,0
+320,1139,4230,4326,Derived at 20 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",2344,57.93,71.21,4.68,31.59,1,0,9603,-87,-95,-120,,,,,0
+321,1140,4230,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,3254,34.88,41.75,19.57,28.3,1,0,9603,-84,-95,-130,,,,,0
+322,1142,4230,4326,Derived at 2 stations.,For military purposes only. Accuracy 25m in each axis.,2339,38.82,41.31,8.08,9.89,1,0,9603,-97,-103,-120,,,,,0
+323,1143,4230,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,2340,36.59,38.35,12.36,15.71,1,0,9603,-97,-88,-135,,,,,0
+324,1144,4230,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,3275,35.74,36.05,14.27,14.63,1,0,9603,-107,-88,-149,,,,,0
+325,1145,4230,4326,Derived at 18 stations.,"For military purposes only. Accuracy 5m, 6m and 3m in X, Y and Z axes.",2338,35.26,43.82,-9.56,3.39,1,0,9603,-84,-107,-120,,,,,0
+326,1245,4230,4326,Derived at 4 stations.,For military purposes only. Accuracy 25m in each axis.,1236,30.23,38.41,7.49,13.67,1,0,9603,-112,-77,-145,,,,,0
+327,1275,4230,4326,"These same parameter values are used to transform to ETRS89. See ED50 to ETRS89 (10) (code 1650).",For applications to an accuracy of 2 metres.,1096,41.15,51.56,-9.86,10.38,1,0,9603,-84,-97,-117,,,,,0
+328,1311,4230,4326,"Based on ED50 to WGS72 (precise ephemeris) 6-nations agreement of 1981 to which precise to broadcast and broadcast to WGS 84 transformations have been concatenated.",Recommended transformation for UKCS and IrishCS petroleum purposes.,2342,47.42,63.89,-16.1,10.86,1,0,9606,-89.5,-93.8,-123.1,0,0,-0.156,1.2,0
+329,1440,4230,4326,,Used in oil industry.,3254,34.88,41.75,19.57,28.3,1,0,9603,-86,-92.2,-127.5,,,,,0
+330,1612,4230,4326,"Parameter values are taken from ED50 to ETRS89 (1), code 1588. Adopted for ED50 to WGS84 transformations offshore Norway north of 62N from April 2001 when it replaced code 1590. Included in Statens Kartverk programme wsktrans from v4.0.",Oil industry offshore.,2601,62,84.17,-3.7,39.65,1,0,9606,-116.641,-56.931,-110.559,0.893,0.921,-0.917,-3.52,0
+331,1613,4230,4326,"Approximation to 1 metre of concatenated transformation ED50 to WGS 84 (14), code 8653. 8653 remains the transformation promulgated by Statens Kartverk but 1613 recommended by EPSG for practical oil industry usage.",Approximation to 1 metre for oil industry use.,2334,56.08,62,1.37,11.14,1,0,9606,-90.365,-101.13,-123.384,0.333,0.077,0.894,1.994,0
+332,1627,4230,4326,"Parameter values from ED50 to ETRS89 (4) (code 1626). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3237,54.51,57.8,8,15.24,1,0,9606,-81.1,-89.4,-115.8,0.485,0.024,0.413,-0.54,0
+333,1629,4230,4326,"Parameter values from ED50 to ETRS89 (5) (code 1628). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1105,36,36.16,-5.42,-4.89,1,0,9603,-116.8,-106.4,-154.4,,,,,0
+334,1631,4230,4326,"Parameter values from ED50 to ETRS89 (6) (code 1630). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2335,38.59,40.11,1.14,4.39,1,0,9606,-181.5,-90.3,-187.2,0.144,0.492,-0.394,17.57,0
+335,1633,4230,4326,"Parameter values from ED50 to ETRS89 (7) (code 1632). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2336,35.26,43.56,-7.54,3.39,1,0,9606,-131,-100.3,-163.4,-1.244,-0.02,-1.144,9.39,0
+336,1635,4230,4326,"Parameter values from ED50 to ETRS89 (8) (code 1634). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1.5 metres.,2337,41.5,43.82,-9.37,-4.5,1,0,9606,-178.4,-83.2,-221.3,0.54,-0.532,-0.126,21.2,0
+337,1784,4230,4326,"Parameter values from ED50 to ETRS89 (9) (code 1783). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 2 metres.,1237,34.42,43.45,25.62,44.83,1,0,9606,-84.1,-101.8,-129.7,0,0,0.468,1.05,0
+338,1810,4230,4326,Derived via concatenation through WGS72. The ED50 to WGS72 step is the Sepplin 1974 value for all Europe.,Oil industry exploration and production operations.,2595,25.71,31.68,24.7,30,1,0,9606,-84,-103,-122.5,0,0,0.554,0.2263,0
+339,1853,4230,4326,Derived at a single point in Galway docks.,Used by Enterprise for Corrib.,2961,53.75,55.76,-12.5,-9.49,1,0,9603,-82.31,-95.23,-114.96,,,,,0
+340,1961,4230,4326,"Parameter values taken from ED87 to WGS 84 (2) (tfm code 1960) assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3m.",Used by NAM for offshore operations.,1630,51.45,55.77,2.53,6.41,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.4428,1.218,0
+341,1985,4230,4326,May be taken as a transformation from ED50 to ETRS89 - see tfm code 5040.,For low resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9603,-87.987,-108.639,-121.593,,,,,0
+342,1989,4230,4326,,For medium resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9607,-74.292,-135.889,-104.967,0.524,0.136,-0.61,-3.761,0
+343,1998,4230,4326,"Approximation to better than 0.5m of transformation adopted in June 2003 (see ED50 to WGS 84 (35), code 1052). Acceptable to Landesbergamt for Lower Saxony and Bundesanstalt für Seeschifffahrt und Hydrographie.",Recommended transformation for Germany North Sea petroleum purposes.,2879,53.6,55.92,3.34,8.88,1,0,9606,-157.89,-17.16,-78.41,2.118,2.697,-1.434,-5.38,0
+344,1999,4230,4326,"Parameter values taken from ED87 to WGS 84 (2) (tfm code 1960) assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3m.",Used by NAM for offshore operations.,1630,51.45,55.77,2.53,6.41,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.04428,1.218,0
+345,3904,4230,4326,"Parameter values from ED87 to WGS 84 (32) (tfm code 3905), assuming that ED87 is identical to ED50. Errors caused by this assumption can reach 3-5m. Used by NAM for offshore operations until mid 2004, then replaced by tfm code 1311.","E&P operations in the Dutch sector of the North Sea.",1630,51.45,55.77,2.53,6.41,1,0,9606,-83.11,-97.38,-117.22,0.00569290865241986,-0.0446975835137458,0.0442850539012516,0.1218,0
+346,15964,4230,4326,Developed by the Portuguese Hydrographic Institute and used by the Directorate of Energy and Geology.,Hydrography and minerals management offshore Portugal.,3537,34.91,41.88,-13.87,-7.24,1,0,9603,-86.277,-108.879,-120.181,,,,,0
+347,1146,4231,4326,,"?",2330,51.03,62.01,-5.05,11.14,1,0,9606,-82.981,-99.719,-110.709,-0.104700015651026,0.0310016003789386,0.0804020214751182,-0.3143,0
+348,1960,4231,4326,,Scientific research.,1297,34.88,71.21,-10.56,31.59,1,1,9606,-83.11,-97.38,-117.22,0.005693,-0.04469,0.04428,1.218,0
+349,3905,4231,4326,"Parameter values taken from ED87 to ETRS89 (1) (tfm code 4078) assuming that ETRS89 is coincident with WGS 84 within the accuracy of the transformation. Used as a tfm between ED50 and WGS 84 - see code 3904.",Scientific research.,1297,34.88,71.21,-10.56,31.59,1,0,9606,-83.11,-97.38,-117.22,0.00569290865241986,-0.0446975835137458,0.0442850539012516,0.1218,1
+350,1256,4232,4326,Derived at 7 stations.,"For military purposes. Accuracy 3m, 3m and 9m in X, Y and Z axes.",4009,16.59,26.42,51.99,59.91,1,0,9603,-346,-1,224,,,,,1
+351,1438,4232,4326,,Oil exploration.,4009,16.59,26.42,51.99,59.91,1,0,9606,-333.102,-11.02,230.69,0,0,0.554,0.219,0
+352,1894,4233,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1152,-3.47,8.1,69.29,77.08,1,1,9603,-133,-321,50,,,,,0
+353,15817,4727,4326,"Derived at 1 satellite station. Information source states ""provided for historical purposes only. These parameter [values] should not be used"". Replaced by Midway 1961 to WGS 84 (2) (tfm code 15818).","Military and topographic mapping. Accuracy +/- 25m in each axis.",3202,28.13,28.28,-177.45,-177.31,1,0,9603,912,-58,1227,,,,,0
+354,15818,4727,4326,"Derived at 1 satellite station. Replaces Midway 1961 to WGS 84 (1) (tfm code 15817).","Military and topographic mapping. Accuracy +/- 25m in each axis.",3202,28.13,28.28,-177.45,-177.31,1,0,9603,403,-81,277,,,,,1
+355,1152,4236,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,3315,21.87,25.34,119.25,122.06,1,0,9603,-637,-549,-203,,,,,1
+356,1242,4237,4326,"Parameter value error in info source Hungarian text but correct in English summary. Replaces HD72 to WGS 84 (2) (code 1831).",Accuracy at metre level throughout Hungary.,1119,45.74,48.58,16.11,22.9,1,0,9603,52.17,-71.82,-14.9,,,,,1
+357,1448,4237,4326,"Parameter values taken from HD72 to ETRS89 (2) (code 1449) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces HD72 to WGS 84 (1) (code 1830).","Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.",1119,45.74,48.58,16.11,22.9,1,0,9607,52.684,-71.194,-13.975,0.312,0.1063,0.3729,1.0191,0
+358,1677,4237,4326,"Parameter values taken from HD72 to ETRS89 (1) (code 1273) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level.",1119,45.74,48.58,16.11,22.9,1,1,9607,56,75.77,15.31,-0.37,-0.2,-0.21,-1.01,0
+359,1830,4237,4326,"Parameter values taken from HD72 to ETRS89 (1) (code 1829) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. OGP recommends use of newer MSZ 7222 equivalent (tfm code 1448) in preference to this transformation.","Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.",1119,45.74,48.58,16.11,22.9,1,0,9607,56,-75.77,-15.31,0.37,0.2,0.21,1.01,0
+360,1831,4237,4326,"Derived at fundamental point Szolohegy and tested at 99 stations throughout Hungary. OGP recommends use of newer transformation (tfm code 1242) in preference to this transformation.",Accuracy better than 1m in all three dimensions throughout Hungary.,1119,45.74,48.58,16.11,22.9,1,0,9603,57.01,-69.97,-9.29,,,,,0
+361,1248,4238,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,4020,-10.98,5.97,95.16,141.01,1,0,9603,-24,-15,5,,,,,1
+362,1832,4238,4326,"Derived via coordinates of 2 Pulse8 stations. Use of ID74 to WGS 84 (3) (code 1833) is recommended.",For oil industry purposes.,4020,-10.98,5.97,95.16,141.01,1,0,9606,2.691,-14.757,4.724,0,0,0.774,-0.6,0
+363,1833,4238,4326,"Parameter values from ID74 to DGN95 (1) (code 15911) assuming that DGN95 is equivalent to WGS 84 within the accuracy of the transformation.","Standard deviations of translations are 1.3, 1.1 and 3.6m, of rotations 0.11, 0.06 and 0.04 sec and ppm 0.18.",4020,-10.98,5.97,95.16,141.01,1,0,9607,-1.977,-13.06,-9.993,-0.364,-0.254,-0.689,-1.037,0
+364,1153,4239,4326,Derived at 11 stations.,"For military purposes. Accuracy 15m, 6m and 12m in X, Y and Z axes.",3317,5.63,20.46,97.34,105.64,1,0,9603,217,823,299,,,,,1
+365,1154,4240,4326,"Derived at 62 stations. Replaced by Indian 1975 to WGS 84 (2) (code 1304).","For military purposes. Accuracy 3m, 2m and 3m in X, Y and Z axes.",3741,5.63,20.46,97.34,105.64,1,0,9603,209,818,290,,,,,0
+366,1304,4240,4326,"Derived at 62 stations. Replaces Indian 1975 to WGS 84 (1) (code 1154).","For military purposes. Accuracy 3m, 2m and 3m in X, Y and Z axes.",3741,5.63,20.46,97.34,105.64,1,0,9603,210,814,289,,,,,1
+367,1537,4240,4326,Derived in 1995 at point RTSD181.,Oil exploration.,2358,6.74,8.16,102.16,103.05,1,0,9603,204.64,834.74,293.8,,,,,0
+368,1812,4240,4326,,Cadastral survey.,3317,5.63,20.46,97.34,105.64,1,0,9606,293,836,318,0.5,1.6,-2.8,2.1,0
+369,1084,4242,4326,Derived via NAD27 and WGS 72. Preliminary values derived by Survey Department but not officially promulgated.,For applications requiring 5m accuracy.,3342,17.64,18.58,-78.43,-76.17,1,0,9603,70,207,389.5,,,,,1
+370,1085,4242,4326,"Derived at 4 stations, tested at a further 9.",For applications requiring 2m accuracy.,3342,17.64,18.58,-78.43,-76.17,1,0,9603,65.334,212.46,387.63,,,,,0
+371,1086,4242,4326,"Derived at 4 stations, tested at a further 9.",For applications requiring 1m accuracy.,3342,17.64,18.58,-78.43,-76.17,1,1,9607,-33.722,153.789,94.959,8.581,4.478,-4.54,-8.95,0
+372,15927,4242,4326,"Derived at 4 stations, tested at a further 9. Also used as tfm to JAD69 to JAD2001 (see code 15926).
+Note: Info source paper contains an error in sign of dS, subsequently confirmed by primary author and NLA of Jamaica, and corrected in this record.",For applications requiring 1m accuracy.,3342,17.64,18.58,-78.43,-76.17,1,0,9607,-33.722,153.789,94.959,8.581,4.478,-4.54,8.95,0
+373,1930,4642,4326,,"Accuracy better than +/- 1 metre.",2820,-22.73,-22.49,167.36,167.61,1,1,9606,244.416,85.339,168.114,-8.9353,7.7523,12.5953,14.268,0
+374,15848,4642,4326,,"Accuracy +/- 10 metres.",2820,-22.73,-22.49,167.36,167.61,1,0,9603,-13,-348,292,,,,,1
+375,1157,4244,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3310,5.86,9.88,79.64,81.95,1,0,9603,-97,787,86,,,,,1
+376,1158,4245,4326,Derived at 6 stations.,"For military purposes. Accuracy 10m, 8m and 6m in X, Y and Z axes.",1309,1.13,6.72,99.59,104.6,1,0,9603,-11,851,5,,,,,1
+377,1059,4246,4326,,1 metre accuracy.,3267,28.53,30.09,46.54,48.48,1,0,9603,-294.7,-200.1,525.5,,,,,1
+378,1516,4247,4326,Also used for PSAD56 to WGS 84 transformations.,"Parameter values estimated accuracy: ± 2.0m; ± 2.7m; ± 1.3m respectively.",2363,3.56,10.8,-67.49,-59.8,1,0,9603,-273.5,110.6,-357.9,,,,,1
+379,1201,4248,4326,Derived at 63 stations. DMA also lists Colombia as area of applicability but PSAD56 is not used in that country.,"For military purposes only. Accuracy 17m, 27m and 27m in X, Y and Z axes.",2399,-45,12.52,-81.41,-56.47,1,0,9603,-288,175,-376,,,,,1
+380,1202,4248,4326,Derived at 5 stations.,"For military purposes only. Accuracy 5m, 11m and 14m in X, Y and Z axes.",1049,-22.91,-9.67,-69.66,-57.52,1,0,9603,-270,188,-388,,,,,0
+381,1203,4248,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2402,-21.51,-17.5,-70.49,-68.18,1,0,9603,-270,183,-390,,,,,0
+382,1204,4248,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,2403,-45,-38.99,-75.22,-71.1,1,0,9603,-305,243,-442,,,,,0
+383,1205,4248,4326,"Derived at 4 stations. Note that although the PSAD56 network included Colombia the CRS is not used there: see Bogota 1975 (CRS code 4218).",For military purposes. Accuracy 15m in each axis.,3229,-4.23,12.52,-79.1,-66.87,1,0,9603,-282,169,-371,,,,,0
+384,1206,4248,4326,Derived at 11 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",3241,-5.01,1.45,-81.03,-75.21,1,0,9603,-278,171,-367,,,,,0
+385,1207,4248,4326,Derived at 9 stations.,"For military purposes. Accuracy 6m, 14m and 5m in X, Y and Z axes.",1114,1.18,10.7,-61.39,-55.77,1,0,9603,-298,159,-369,,,,,0
+386,1208,4248,4326,Derived at 6 stations.,"For military purposes only. Accuracy 6m, 8m and 12m in X, Y and Z axes.",1189,-21.05,-0.03,-84.68,-68.67,1,0,9603,-279,175,-379,,,,,0
+387,1209,4248,4326,Derived at 24 stations.,"For military purposes only. Accuracy 9m, 14m and 15m in X, Y and Z axes.",1251,0.64,16.75,-73.38,-58.95,1,0,9603,-295,173,-371,,,,,0
+388,1582,4248,4326,Derived May 1995 by Geoid for Total. OSU91A geoid model used.,Oil exploration.,2400,-14.43,-13.56,-68.96,-67.79,1,0,9603,-259.73,173.12,-398.27,,,,,0
+389,1583,4248,4326,Derived July 1997 by Geoid from data recorded by UGA for Total. OSU91A geoid model used.,Oil exploration.,2401,-21.71,-21.09,-63.44,-62.95,1,0,9603,-307.7,265.3,-363.5,,,,,0
+390,1811,4248,4326,Used by Petrobras for shelf operations.,Oil industry exploration.,1754,-1.05,5.6,-51.64,-48,1,0,9603,-291.87,106.37,-364.52,,,,,0
+391,3990,4248,4326,"Parameter values from PSAD56 to SIRGAS 1995 (1) (code 3971). Assumes SIRGAS 1995 and WGS 84 can be considered the same to within the accuracy of the transformation.","Suitable for mapping at 1:25,000 scale and smaller.",3241,-5.01,1.45,-81.03,-75.21,1,0,9607,-60.31,245.935,31.008,-12.324,-3.755,7.37,0.447,0
+392,15967,4761,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84. HTRS96 is a regional realisation of ETRS89.","Accuracy +/- 1 metre.",1076,41.62,46.54,13,19.43,1,0,9603,0,0,0,,,,,1
+393,1159,4250,4326,Derived at 8 stations.,"For military purposes. Accuracy 2m, 3m and 2m in X, Y and Z axes.",1104,1.4,11.16,-3.79,2.1,1,0,9603,-130,29,364,,,,,1
+394,1160,4251,4326,Derived at 4 stations.,For military purposes only. Accuracy 15m in each axis.,3270,4.29,8.52,-11.52,-7.36,1,0,9603,-90,40,88,,,,,1
+395,1887,4182,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,1344,39.3,39.77,-31.34,-31.02,1,0,9603,-425,-169,81,,,,,1
+396,1982,4182,4326,Derived at 2 stations in 1999.,For low resolution applications.,1344,39.3,39.77,-31.34,-31.02,1,0,9603,-422.651,-172.995,84.02,,,,,0
+397,1161,4253,4326,Derived at 6 stations.,"For military purposes. Accuracy 8m, 11m and 9m in X, Y and Z axes.",2364,7.75,19.45,116.89,125.88,1,0,9603,-133,-77,-51,,,,,1
+398,1162,4253,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2365,4.99,10.52,119.76,126.65,1,0,9603,-133,-79,-72,,,,,0
+399,1529,4254,4326,"Derived through ties at 3 stations (RC03, TOTAL11 and MP12) to 3 IGS stations in November 1995",Oil exploration.,2357,-55.11,-52.59,-68.64,-63.73,1,0,9606,18.38,192.45,96.82,0.056,-0.142,-0.2,-0.0013,0
+400,1892,4254,4326,Derived at 2 stations. As the source CRS was used for the border survey this transformation is probably also applicable to adjacent areas of Argentina.,Accuracy 25m in each axis.,2805,-55.96,-52.4,-74.83,-66.33,1,0,9603,16,196,93,,,,,1
+401,1246,4255,4326,Accuracy estimate not available.,For military purposes only.,1024,29.4,38.48,60.5,74.92,1,0,9603,-333,-222,114,,,,,1
+402,1164,4256,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2369,-4.84,-4.5,55.32,55.6,1,0,9603,41,-220,-134,,,,,1
+403,1837,4257,4326,,Oil exploration.,1316,-6.54,-1.88,118.71,120.78,1,0,9603,-587.8,519.75,145.76,,,,,1
+404,1149,4258,4326,,ETRS89 and WGS 84 are realisations of ITRS coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1298,32.88,84.17,-16.1,39.65,1,0,9603,0,0,0,,,,,1
+405,1571,4258,4326,"Dutch sources also quote an equivalent transformation with parameter values dX=+593.032 dY=+26.000 dZ=+478.741m, rX rY rZ and dS as this tfm. These values belong to a different transformation method and cannot be used with the Coordinate Frame method.",Accuracy 0.5m,1172,50.75,55.77,2.53,7.22,1,1,9607,565.04,49.91,465.84,0.409394387439237,-0.359705195614311,1.86849100035057,4.0772,0
+406,1330,4259,4326,"Derived at Station Y in April 1989 using 572 transit satellite passes. Computed value for dZ was -96.42 but -96.38 has been utilised. Replaced Malongo 1987 to WGS 84 (3) (code 15791) in 1989. Replaced by Malongo 1987 to WGS 84 (2) (code 1557) in 1990.",Offshore oil exploration and production between April 1989 and June 1990.,3180,-6.04,-5.05,10.53,12.37,1,0,9603,-252.95,-4.11,-96.38,,,,,0
+407,1557,4259,4326,"Derived at station Y in July 1990 through Transit single point positioning using 187 passes by Geodetic Survey Ltd. Replaces Malongo 1987 to WGS 84 (1) (trf code 1330).",Offshore oil exploration and production from June 1990.,3180,-6.04,-5.05,10.53,12.37,1,0,9603,-254.1,-5.36,-100.29,,,,,1
+408,15791,4259,4326,"Derived via WGS 72BE by Geodetic for Chevron in 1987 by single point Transit translocation at 1 station (Malongo Y). Replaced in 1989 by Malongo 1987 to WGS 84 (1) (code 1330).",Oil industry exploration and production between September 1987 and April 1989.,3180,-6.04,-5.05,10.53,12.37,1,0,9603,-259.99,-5.28,-97.09,,,,,0
+409,1316,4260,4326,,"?",1060,1.65,13.09,8.32,16.21,1,1,9603,-70.9,-151.8,-41.4,,,,,0
+410,1166,4261,4326,Derived at 9 stations.,"For military purposes. Accuracy 5m, 3m and 3m in X, Y and Z axes.",3280,27.66,35.97,-13.24,-1.01,1,0,9603,31,146,47,,,,,1
+411,1165,4262,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1089,12.36,18.1,36.44,43.31,1,0,9603,639,405,60,,,,,1
+412,1067,4263,4326,"Used by Statoil for deep water blocks 210, 213, 217 and 218. Parameter values interpolated from Racal Survey geocentric translation contour charts for each of these four blocks and then meaned.",Oil industry exploration and production.,3817,3.24,5.54,4.41,6.29,1,0,9603,-92.1,-89.9,114.9,,,,,0
+413,1167,4263,4326,"Derived at 2 stations. Note: Minna is used in Nigeria, not Cameroon.",For military purposes only. Accuracy 25m in each axis.,3226,1.65,13.09,8.45,16.21,1,0,9603,-81,-84,115,,,,,0
+414,1168,4263,4326,Derived at 6 stations.,"For military purposes. Accuracy 3m, 6m and 5m in X, Y and Z axes.",1178,1.92,13.9,2.66,14.65,1,0,9603,-92,-93,122,,,,,1
+415,1534,4263,4326,,Oil exploration.,2371,4.22,6.95,4.35,9.45,1,1,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
+416,1754,4263,4326,"Derived at 8 stations across the Niger delta. Used by Shell SPDC throughout southern Nigeria onshore, delta and shallow offshore from 1994 and by Total in OPL246. Sometimes given with parameter values to greater resolution; values here are adequate.",Oil exploration.,2371,4.22,6.95,4.35,9.45,1,0,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
+417,1818,4263,4326,Concatenated via WGS 72BE.,Oil industry operations.,1717,1.92,6.14,2.66,7.82,1,0,9606,-89,-112,125.9,0,0,0.814,-0.38,0
+418,1819,4263,4326,Used by Shell in southern Nigeria and Total in OPL246.,Oil industry operations.,2371,4.22,6.95,4.35,9.45,1,1,9606,-111.92,-87.85,114.5,1.875,0.202,0.219,0.032,0
+419,1820,4263,4326,Derived by Nortech at station L40 Minna using NNPC 1989 GPS network tied to 4 ADOS stations. Used by Conoco in OPLs 219-220 to cm precision and ExxonMobil in OPL 209 to dm precision..,Oil industry operations.,3813,3.25,5.54,4.01,6.96,1,0,9603,-93.2,-93.31,121.156,,,,,0
+420,1821,4263,4326,"Derived by Elf Petroleum Nigeria in 1994 at 3 stations (M101 onshore, offshore platforms XSW06 and XSV39) and used in OMLs 99-102 and OPLs 222-223.",Oil industry operations.,3814,3.25,4.51,7.16,8.25,1,0,9603,-88.98,-83.23,113.55,,,,,0
+421,1822,4263,4326,"Used by Shell SNEPCO for OPLs 209-213 and 316. Derived during 1990 Niger Delta control survey at 4 stations (XSU27, 30 31 and 35).",Oil industry exploration and production.,3815,4.22,6.31,3.83,5.17,1,0,9603,-92.726,-90.304,115.735,,,,,0
+422,1823,4263,4326,"Used by Shell SNEPCO for OPLs 217-223. Derived during 1990 Niger Delta control survey at 4 stations (XSU38, 41, 44 and 45).",Oil industry exploration and production.,3816,3.24,3.86,5.58,8,1,0,9603,-93.134,-86.647,114.196,,,,,0
+423,1824,4263,4326,Used by Shell SNEPCO for Gongola basin.,Oil industry exploration and production.,3824,8.78,11.63,9.41,12.13,1,0,9603,-93,-94,124,,,,,0
+424,6196,4263,4326,Used by Addax for OPL 118 and OML 124. Derived in 1999 at 4 stations during  extension into OPL 118 of control in Chevron block OML 53.,Oil industry exploration and production.,4127,5.56,5.74,6.72,6.97,1,0,9603,-93.179,-87.124,114.338,,,,,0
+425,15493,4263,4326,"Adopted by MPN for all joint venture operations from 1/1/1996.",Oil industry exploration and production.,3590,3.99,5.01,5.99,8.01,1,0,9603,-94.031,-83.317,116.708,,,,,0
+426,15705,4263,4326,"Derived via WGS 72(BE). Minna to WGS 72(BE) transformation derived in 1981 for Mobil E&P Nigeria (MEPCON) by Geodetic Survey through Transit translocation at six stations in southern Nigeria. Used by MEPCON in blocks OPL 215 and 221.",Oil industry exploration.,3819,3.25,4.23,5.02,7.31,1,0,9606,-83.13,-104.95,114.63,0,0,0.554,0,0
+427,15706,4263,4326,Used by Elf in Blocks OPL 222 and OPL 223 and by Mobil in 1994.,Oil industry exploration.,1717,1.92,6.14,2.66,7.82,1,0,9603,-93.6,-83.7,113.8,,,,,0
+428,15755,4263,4326,Derived in 1995 at unspecified DMA ADOS stations and Racal stations M101 and ZVS3003. Used by Elf in onshore Block OML 58.,Oil industry exploration and production. Accuracy 0.5m.,3113,5.05,5.36,6.53,6.84,1,0,9603,-90.2,-87.32,114.17,,,,,0
+429,1329,4264,4326,"Superseded in 1990 by trf Malongo 1987 to WGS 84 (2), code 1557. Malongo 1987 is an offshore extension of the Mhast cooordinate system.","Used for oil exploration by Chevron until superseded in 1990 by trf Malongo 1987 to WGS 84 (2), code 1557.",1317,-6.04,-5.05,10.53,12.18,1,1,9603,-252.95,-4.11,-96.38,,,,,0
+430,1088,4265,4326,,Oil exploration and production,2882,43.62,45.73,12.22,13.96,1,0,9603,-223.7,-67.38,1.34,,,,,0
+431,1089,4265,4326,,Oil exploration and production,2883,41.95,44.04,13.61,16.14,1,0,9603,-225.4,-67.7,7.85,,,,,0
+432,1090,4265,4326,,Oil exploration and production,2884,40.72,42.28,15.95,18.63,1,0,9603,-227.1,-68.1,14.4,,,,,0
+433,1091,4265,4326,,Marine navigation,2885,39.77,41.03,17.95,18.99,1,0,9603,-231.61,-68.21,13.93,,,,,0
+434,1092,4265,4326,,Marine navigation,2886,37.67,40.47,16.55,18.93,1,0,9603,-225.06,-67.37,14.61,,,,,0
+435,1093,4265,4326,,Marine navigation,2887,35.22,37.48,13,15.16,1,0,9603,-229.08,-65.73,20.21,,,,,0
+436,1094,4265,4326,,Marine navigation,2888,35.28,38.45,10.68,13.01,1,0,9603,-230.47,-56.08,22.43,,,,,0
+437,1169,4265,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2339,38.82,41.31,8.08,9.89,1,0,9603,-225,-65,9,,,,,0
+438,1660,4265,4326,"Parameter values from Monte Mario to ETRS89 (1) (code 1659). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2372,37.86,47.1,6.62,18.58,1,0,9606,-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68,1
+439,1662,4265,4326,"Parameter values from Monte Mario to ETRS89 (2) (code 1661). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2339,38.82,41.31,8.08,9.89,1,0,9606,-168.6,-34,38.6,-0.374,-0.679,-1.379,-9.48,0
+440,1664,4265,4326,"Parameter values from Monte Mario to ETRS89 (3) (code 1663). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.","Accuracy: 4 metres",2340,36.59,38.35,12.36,15.71,1,0,9606,-50.2,-50.4,84.8,-0.69,-2.012,0.459,-28.08,0
+441,1163,4266,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1100,-6.37,2.32,7.03,14.52,1,0,9603,-74,-130,42,,,,,1
+442,1532,4266,4326,Derived as mean of Doris determinations at 3 stations in Port Gentil area in 1994.,Oil exploration.,1100,-6.37,2.32,7.03,14.52,1,0,9603,-80.7,-132.5,41.1,,,,,0
+443,1170,4267,4326,Derived at 15 stations.,"For military purposes. Accuracy 3m, 9m and 12m in X, Y and Z axes.",2418,13,23.25,-85.01,-59.37,1,0,9603,-3,142,183,,,,,0
+444,1171,4267,4326,Derived at 19 stations.,"For military purposes only. Accuracy 8m, 3m and 5m in X, Y and Z axes.",2419,7.98,18.49,-92.29,-82.53,1,0,9603,0,125,194,,,,,0
+445,1172,4267,4326,Derived at 112 stations.,"For military purposes only. Accuracy 15m, 11m and 6m in X, Y and Z axes.",1061,40.04,86.46,-141.01,-47.74,1,0,9603,-10,158,187,,,,,1
+446,1173,4267,4326,Derived at 405 stations.,"For military purposes only. Accuracy 5m, 5m and 6m in X, Y and Z axes.",1323,24.41,49.38,-124.79,-66.91,1,0,9603,-8,160,176,,,,,0
+447,1174,4267,4326,Derived at 129 stations.,"For military purposes only. Accuracy 5m, 5m and 8m in X, Y and Z axes.",2389,24.41,49.38,-97.22,-66.91,1,0,9603,-9,161,179,,,,,0
+448,1175,4267,4326,Derived at 276 stations.,"For military purposes only. Accuracy 5m, 3m and 3m in X, Y and Z axes.",2390,25.83,49.05,-124.79,-89.64,1,0,9603,-8,159,175,,,,,0
+449,1176,4267,4326,Derived at 47 stations.,"For military purposes only. Accuracy 5m, 9m and 5m in X, Y and Z axes.",2412,54.34,71.4,-168.26,-129.99,1,0,9603,-5,135,172,,,,,0
+450,1177,4267,4326,Derived at 11 stations.,"For military purposes. Accuracy 5m, 3m and 5m in X, Y and Z axes.",2413,20.86,27.29,-79.04,-72.68,1,0,9603,-4,154,178,,,,,0
+451,1178,4267,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2414,23.9,24.19,-74.6,-74.37,1,0,9603,1,140,165,,,,,0
+452,1179,4267,4326,Derived at 25 stations.,"For military purposes only. Accuracy 8m, 8m and 6m in X, Y and Z axes.",2384,48.25,60.01,-139.04,-109.98,1,0,9603,-7,162,188,,,,,0
+453,1180,4267,4326,Derived at 25 stations.,"For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",2415,41.67,60.01,-102,-74.35,1,0,9603,-9,157,184,,,,,0
+454,1181,4267,4326,Derived at 37 stations.,"For military purposes only. Accuracy 6m, 6m and 3m in X, Y and Z axes.",2416,43.41,62.62,-79.85,-52.54,1,0,9603,-22,160,190,,,,,0
+455,1182,4267,4326,Derived at 17 stations.,"For military purposes only. Accuracy 5m, 5m and 3m in X, Y and Z axes.",2410,49,83.17,-136.46,-60.72,1,0,9603,4,159,188,,,,,0
+456,1183,4267,4326,Derived at 8 stations.,"For military purposes only. Accuracy 5m, 8m and 3m in X, Y and Z axes.",2417,59.99,69.7,-141.01,-123.91,1,0,9603,-7,139,181,,,,,0
+457,1184,4267,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,2385,8.82,9.45,-80.07,-79.46,1,0,9603,0,125,201,,,,,0
+458,1185,4267,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,3235,19.77,23.25,-85.01,-74.07,1,0,9603,-9,152,178,,,,,0
+459,1186,4267,4326,"Derived at 2 stations. Note: NAD27 is not used in Greenland.",For military purposes. Accuracy 25m in each axis.,2386,75.86,79.2,-73.29,-60.98,1,0,9603,11,114,195,,,,,0
+460,1187,4267,4326,Derived at 22 stations.,"For military purposes only. Accuracy 8m, 6m and 6m in X, Y and Z axes.",3278,14.51,32.72,-118.47,-86.68,1,0,9603,-12,130,190,,,,,0
+461,1249,4267,4326,Derived at 6 stations.,"For military purposes only. Accuracy 6m, 8m and 10m in X, Y and Z axes.",2387,51.54,54.34,-178.3,-164.84,1,0,9603,-2,152,149,,,,,0
+462,1250,4267,4326,Derived at 5 stations.,For military purposes. Accuracy 10m in each axis.,2388,51.3,53.07,172.42,179.86,1,0,9603,2,204,105,,,,,0
+463,1530,4267,4326,,Accuracy 3m.,1077,18.83,25.51,-87.01,-73.57,1,0,9603,-4.2,135.4,181.9,,,,,0
+464,15699,4267,4326,"Developed by John E Chance and Associates at 19°44'N, 92°21'W. Geoid height used =-13.34m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3462,17.85,20.89,-94.79,-89.75,1,0,9603,-2,124.7,196,,,,,0
+465,15852,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3358,23.82,30.25,-87.25,-81.17,1,0,9603,-3,154,177,,,,,0
+466,15853,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3359,25.61,30.23,-95,-87.25,1,0,9603,-7,151,175,,,,,0
+467,15854,4267,4326,"Developed by John E Chance and Associates. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3360,25.97,28.97,-97.22,-95,1,0,9603,-7,151,178,,,,,0
+468,15855,4267,4326,"Developed by John E Chance and Associates at 21°55'N, 97°20'W. Geoid height used =-17m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3361,21.51,22.75,-98.1,-96.89,1,0,9603,-8,125,190,,,,,0
+469,15856,4267,4326,"Developed by EnSoCo Inc. Replaced by NAD27 to WGS 84 (79) (tfm code 15851).",Oil exploration and production. Accuracy 8 metres.,3357,23.82,30.25,-97.22,-81.17,1,0,9603,-7,158,172,,,,,0
+470,15913,4267,4326,"Developed by John E Chance and Associates at 21°33'N, 92°33'W. Geoid height used =-16.7m.","Oil exploration and production. Horizontal transformation accuracy (1 sigma) is considered to be at the +/- 5 meter level.",3461,20.87,23.01,-94.33,-88.67,1,0,9603,0,125,196,,,,,0
+471,15978,4267,4326,,Accuracy 1m.,1077,18.83,25.51,-87.01,-73.57,1,0,9607,2.478,149.752,197.726,-0.526,-0.498,0.501,0.685,0
+472,1188,4269,4326,Derived at 354 stations.,Accuracy 2m in each axis.,1325,23.81,86.46,-172.54,-47.74,1,0,9603,0,0,0,,,,,1
+473,1251,4269,4326,Derived at 4 stations.,"For military purposes only. Accuracy 5m, 2m and 5m in X, Y and Z axes.",2157,51.3,54.34,172.42,-164.84,1,0,9603,-2,0,4,,,,,0
+474,1252,4269,4326,Derived at 6 stations.,For military purposes only. Accuracy 2m in each axis.,3883,15.56,25.58,-163.74,-151.27,1,0,9603,1,1,-1,,,,,0
+475,1308,4269,4326,"Strictly between NAD83 and ITRF94(1996.0). Superseded by NAD83 to WGS 84 (5) (code 1515).",Historical record only - superseded - see remarks.,1323,24.41,49.38,-124.79,-66.91,1,1,9607,-0.9738,1.9453,0.5486,-0.0275507901704247,-0.0100492213603585,-0.0113590028800276,0,0
+476,1515,4269,4326,"Strictly between NAD83 and ITRF96(1997.0). Supersedes NAD83 to WGS 84 (4) (code 1308).",Geodesy.,1323,24.41,49.38,-124.79,-66.91,1,1,9607,-0.991,1.9072,0.5129,-0.0257899075194932,-0.0096500989602704,-0.0116599432323421,0,0
+477,1189,4270,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,2391,20.12,20.74,58.58,59.01,1,0,9603,-247,-148,369,,,,,0
+478,1190,4270,4326,Derived at 3 stations.,For military purposes. Accuracy 20m in each axis.,3968,24.63,28.57,47.95,50.81,1,0,9603,-243,-192,477,,,,,0
+479,1191,4270,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1243,22.63,26.27,51.5,57.13,1,0,9603,-249,-156,381,,,,,0
+480,1531,4270,4326,Parameter values adopted by Total are mean of those derived by Oceonics and Geoid through ties at platform AK1 to 4 IGS stations in March 1995.,Oil exploration.,2392,25.33,25.54,53.03,53.4,1,0,9603,-245,-153.9,382.8,,,,,0
+481,1536,4270,4326,"Derived by Brown & Root in 1992 for Qatar General Petroleum Corporation North Field development. Adopted by QGPC for all offshore Qatar.",Oil exploration.,2406,24.64,27.05,50.55,53.04,1,0,9603,-250.2,-153.09,391.7,,,,,0
+482,15871,4270,4326,Derived by concatenation of parameter values published by IGN Paris from Nahrwan 1967 to WGS 72 at the Nahrwan SE Base trig station near Baghdad with DMA WGS 72 to WGS 84 parameter values.,Oil exploration.,3625,29.06,37.39,38.79,48.61,1,0,9603,-242.2,-144.9,370.3,,,,,1
+483,15937,4270,4326,Parameter values adopted by Total are mean of those derived by Oceonics and Geoid through ties at station TC58 to 4 IGS stations in March 1995.,Oil exploration.,3509,24,25.64,51.5,54.85,1,0,9603,-245.8,-152.2,382.9,,,,,0
+484,15938,4270,4326,Derived via WGS 72BE from Transit observations at station TC58 in 1976 by BP for ADMA.,Oil exploration.,3509,24,25.64,51.5,54.85,1,0,9606,-225.4,-158.7,380.8,0,0,0.814,-0.38,0
+485,15952,4270,4326,"Used by DPC for Al Fateh field. Applying this transformation gives same result as Nahrwan 1967 to WGS 84 (8) (code 15938).",Oil exploration and production.,3530,24.94,25.8,54.06,55.3,1,0,9603,-244.2,-149.8,379.3,,,,,0
+486,15953,4270,4326,Used by Dubai Municipality before 1994.,Municipal operations.,3531,24.85,25.34,54.84,55.55,1,0,9603,-250.7,-157.9,380.4,,,,,0
+487,1192,4271,4326,"CAUTION: OGP believes that these parameter values include a blunder and that if NIMA transformation parameters are to be used the 1987 version (EPSG code 1307) be used.",For military purposes only. Accuracy given by NIMA 15m in each axis. EPSG believes there is an 8-10m blunder in dX.,1322,11.09,11.4,-60.9,-60.47,1,0,9603,-10,375,165,,,,,1
+488,1307,4271,4326,"(1) See remarks for tfm code 1192. (2) Naparima 1972 is an extension to Tobago of the Napaima 1955 geographic CRS of Trindad. In Trinidad this transformation may also be considered to use Napaima 1955 (code 4158) as its source CRS: see tfm code 1556.",For military purposes only. Accuracy 15m in each axis.,1322,11.09,11.4,-60.9,-60.47,1,0,9603,-2,374,172,,,,,0
+489,1151,4272,4326,Derived at 14 stations.,"For military purposes only. Accuracy 5m, 3m and 5m in X, Y and Z axes.",3285,-47.65,-33.89,165.87,179.27,1,0,9603,84,-22,209,,,,,0
+490,1564,4272,4326,"These parameter values are taken from NZGD49 to NZGD2000 (2) (code 1701) and assume that NZGD2000 and WGS 84 are coincident to within the accuracy of the transformation. For improved accuracy use NZGD49 to WGS 84 (4) (code 1670).",Transformation accuracy about 4 metres.,3285,-47.65,-33.89,165.87,179.27,1,0,9607,59.47,-5.04,187.44,-0.47,0.1,-1.024,-4.5993,1
+491,15975,4272,4326,"These parameter values are taken from NZGD49 to NZGD2000 (1) (code 1566) and assume that NZGD2000 and WGS 84 are coincident to within the accuracy of the tfm. For better accuracy use NZGD49 to WGS 84 (2) (code 1564) or NZGD49 to WGS 84 (3) (code 1670).",5m accuracy.,3285,-47.65,-33.89,165.87,179.27,1,0,9603,54.4,-20.1,183.1,,,,,0
+492,1654,4273,4326,"Parameter values from NGO 1948 to ETRS89 (1) (code 1653). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 3 metres.,1352,57.93,71.21,4.68,31.22,1,0,9606,278.3,93,474.5,7.889,0.05,-6.61,6.21,1
+493,1658,4274,4326,"Parameter values from Datum 73 to ETRS89 (1) (code 1657). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaced by Datum 73 to WGS 84 (4) (tfm code 1987).",For applications to an accuracy of 2 metres.,1294,36.95,42.16,-9.56,-6.19,1,0,9606,-238.2,85.2,29.9,0.166,0.046,1.248,2.03,0
+494,1945,4274,4326,"Parameter values from Datum 73 to ETRS89 (2) (code 1792). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1294,36.95,42.16,-9.56,-6.19,1,1,9606,-231,102.6,29.8,0.615,-0.198,0.881,1.79,0
+495,1983,4274,4326,,For low resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9603,-223.237,110.193,36.649,,,,,1
+496,1987,4274,4326,,For medium resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9607,-239.749,88.181,30.488,-0.263,-0.082,-1.211,2.229,0
+497,1193,4275,4326,"These same parameter values are used to transform to ETRS89. See NTF to ETRS89 (1) (code 1651).",For applications to an accuracy of 2 metres.,3694,41.31,51.14,-4.87,9.63,1,0,9603,-168,-60,320,,,,,1
+498,1195,4277,4326,Derived at 38 stations.,"For military purposes only. Accuracy 10m, 10m and 15m in X, Y and Z axes.",1264,49.81,60.9,-8.74,1.84,1,0,9603,375,-111,431,,,,,0
+499,1196,4277,4326,Derived at 24 stations.,"For military purposes only. Accuracy 5m, 5m and 6m in X, Y and Z axes.",2395,49.81,55.85,-6.5,1.84,1,0,9603,371,-112,434,,,,,0
+500,1197,4277,4326,Derived at 25 stations.,"For military purposes only. Accuracy 10m, 10m and 15m in X, Y and Z axes.",2396,49.81,55.85,-6.5,1.84,1,0,9603,371,-111,434,,,,,0
+501,1198,4277,4326,Derived at 13 stations.,For military purposes only. Accuracy 10m in each axis.,2397,54.57,60.9,-8.74,-0.65,1,0,9603,384,-111,425,,,,,0
+502,1199,4277,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,2398,51.28,53.48,-5.34,-2.65,1,0,9603,370,-108,434,,,,,0
+503,1314,4277,4326,"For a more accurate transformation see OSGB 1936 / British National Grid to ETRS89 (2) (code 1039): contact the Ordnance Survey of Great Britain (http://www.gps.gov.uk/gpssurveying.asp) for details.",Oil exploration. Accuracy better than 4m and generally better than 2m.,1264,49.81,60.9,-8.74,1.84,1,0,9606,446.448,-125.157,542.06,0.15,0.247,0.842,-20.489,1
+504,5622,4277,4326,Derived by CGG for 1994 3D seismic survey.,Oil exploration and production.,3893,50.53,50.8,-2.2,-1.68,1,0,9603,370.396,-108.938,435.682,,,,,0
+505,4560,4558,4326,"Approximation at the +/- 1m level assuming that RRAF91 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",2824,14.08,18.54,-63.66,-57.52,1,0,9603,0,0,0,,,,,1
+506,1074,4281,4326,"Not recognised by Survey of Israel. See Palestine 1923 to WGS 84 (2) (code 8650).","Oil Exploration. Accuracy: 1m to north and 5m to south of east-west line through Beersheba (31°15'N).",2603,29.45,33.28,34.17,35.69,1,0,9606,-275.7224,94.7824,340.8944,-8.001,-4.42,-11.821,1,1
+507,1200,4282,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1072,-6.91,3.72,8.84,18.65,1,0,9603,-148,51,-291,,,,,1
+508,1801,4282,4326,"Derived in 1994 by CGG/Topnav using DORIS system on various stations along the coastline.","?",2574,-6.91,-3.55,8.84,12.34,1,0,9603,-145,52.7,-291.6,,,,,0
+509,1802,4282,4326,Derived by Geoid for Elf in May 1995 using GPS and IGS data by tying 4 geodetic points to ITRF93 epoch 1995.4.,Used by Elf since May 1995 for all offshore Congo operations.,2574,-6.91,-3.55,8.84,12.34,1,0,9606,-178.3,-316.7,-131.5,5.278,6.077,10.979,19.166,0
+510,1150,4283,4326,,GDA94 is a realisation of WGS 84 coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,2575,-43.7,-9.86,112.85,153.69,1,0,9603,0,0,0,,,,,1
+511,1254,4284,4326,Accuracy estimate not available.,For military purposes.,1198,39.87,85.2,18.92,-168.97,1,0,9603,28,-130,-95,,,,,0
+512,1267,4284,4326,"Derived through concatenation of Pulkovo 1942 to PZ-90 (1) (tfm code 15844) and PZ-90 to WGS 84 (2) (tfm code 1244. Mandated for use in Russia by GOST R 51794-2001, but this has been superseded by GOST R 51794-2008. Replaced by tfm code 5044.",Accuracy 4 metres.,1198,39.87,85.2,18.92,-168.97,1,0,9607,23.92,-141.27,-80.9,0,-0.35,-0.82,-0.12,1
+513,1287,4284,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1119,45.74,48.58,16.11,22.9,1,1,9603,28,-121,-77,,,,,0
+514,1288,4284,4326,Derived at 11 stations.,"For military purposes only. Accuracy 4m, 2m and 4m in X, Y and Z axes.",1192,49,55.93,14.14,24.15,1,1,9603,23,-124,-82,,,,,0
+515,1289,4284,4326,Derived at 6 stations.,"For military purposes only. Accuracy 3m, 3m and 2m in X, Y and Z axes.",1306,47.73,51.06,12.09,22.56,1,1,9603,26,-121,-78,,,,,0
+516,1290,4284,4326,Derived at 5 stations.,For military purposes. Accuracy 2m in each axis.,1139,55.67,58.09,19.06,28.24,1,0,9603,24,-124,-82,,,,,0
+517,1291,4284,4326,Derived at 2 stations.,For military purposes. Accuracy 25m in each axis.,1131,40.59,55.45,46.49,87.35,1,0,9603,15,-130,-84,,,,,0
+518,1292,4284,4326,Derived at 7 stations.,For military purposes. Accuracy 3m in each axis.,1025,39.63,42.67,18.46,21.06,1,1,9603,24,-130,-92,,,,,0
+519,1293,4284,4326,Derived at 4 stations.,"For military purposes. Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.44,48.27,20.26,31.41,1,1,9603,28,-121,-77,,,,,0
+520,1303,4284,4326,Mean of 13 stations along entire Kazak coastline.,Residuals under 2 m.,2405,41.15,46.97,48.9,53.15,1,0,9606,43.822,-108.842,-119.585,1.455,-0.761,0.737,0.549,0
+521,1334,4284,4326,,"?",3246,57.52,59.75,21.74,28.2,1,0,9607,21.58719,-97.54127,-60.92546,-1.01378,-0.58117,-0.2348,-4.6121,0
+522,1679,4284,4326,"Parameter values taken from Pulkovo 1942 to LKS94(ETRS89) (1) (code 1274) assuming that LKS94(ETRS89) is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 9m level.",1145,53.89,56.45,19.02,26.82,1,0,9607,-40.595,-18.55,-69.339,-2.508,-1.832,2.611,-4.299,0
+523,1807,4284,4326,"Derived via WGS72 values taken from SOCAR Magnavox 1502 manual. Used by AIOC 1995-1997 then replaced by the AIOC97 values (tfm code 1808).
+Do not confuse with AIOC95 vertical datum as used in southern Caspian Sea and at Sangachal terminal by AIOC.",Oil industry operations by AIOC prior to 1997.,1038,37.89,42.59,44.77,51.73,1,0,9606,27,-135,-84.5,0,0,0.554,0.2263,0
+524,1808,4284,4326,"Mean of 3 stations in western Georgia, 4 stations in eastern Georgia and 4 stations in eastern Azerbaijan. Derived for use on AIOC early oil western export pipeline, but adopted for all AIOC work replacing the 1995 AIOC transformation (code 1807).",Oil industry operations.,2593,37.89,43.59,39.99,51.73,1,0,9606,686.1,-123.5,-574.4,8.045,-23.366,10.791,-2.926,0
+525,1809,4284,4326,Parameter values calculated by Elf Exploration and Production based on geodetic survey carried out by Azerbaijan State Committee for Geodesy and Cartography.,Oil industry operations.,2594,38.31,40.33,48.93,50.4,1,0,9606,926.4,-715.9,-186.4,-10.364,-20.78,26.452,-7.224,0
+526,5044,4284,4326,"Derived through concatenation of Pulkovo 1942 to PZ-90.02 to WGS 84. Replaces Pulkovo 1942 to WGS 84 (17) (code 1267).",Accuracy 3 metres.,1198,39.87,85.2,18.92,-168.97,1,0,9607,23.57,-140.95,-79.8,0,-0.35,-0.79,-0.22,0
+527,15865,4284,4326,"Derived via PZ-90 at 30 stations throughout USSR (Former Soviet Union, FSU) through concatenation of Pulkovo 1942 to PZ-90 (1) (tfm code 15844) and PZ-90 to WGS 84 (1) (tfm code 15843).",Accuracy 4.5 metres.,2423,35.14,81.91,19.57,-168.97,1,0,9607,25,-141,-78.5,0,-0.35,-0.736,0,0
+528,1561,4285,4326,Derived at 3 stations.,For military purposes only. Accuracy 20m in each axis.,1346,24.55,26.2,50.69,51.68,1,0,9603,-128,-283,22,,,,,0
+529,1562,4285,4326,"Derived by Brown & Root in 1992 for Qatar General Petroleum Corporation.",Oil exploration.,2406,24.64,27.05,50.55,53.04,1,0,9603,-128.16,-282.42,21.93,,,,,1
+530,1563,4285,4326,"Derived by Qatar Centre for GIS. See Qatar 1974 to WGS 84 (2) (code 1562) for transformation used by QGPC for offshore petroleum industry.",Oil exploration.,1346,24.55,26.2,50.69,51.68,1,0,9603,-128.033,-283.697,21.052,,,,,0
+531,1211,4287,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m, 25m and 32m in X, Y and Z axes.",2407,59.75,72,-55,-40,1,1,9603,164,138,-189,,,,,0
+532,1112,4289,4326,"Replaced by Amersfoort to WGS 84 (2) (code 1672).","?",1275,50.75,53.7,3.2,7.22,1,0,9606,593.16,26.15,478.54,-1.30439800822601,-0.103297414968546,-1.14450153042326,4.0775,0
+533,1672,4289,4326,"Parameter values from Amersfoort to ETRS89 (1) (code 1751) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (1) (code 1112). Replaced by Amersfoort to WGS 84 (3) (code 15934).","Approximation at the +/- 1m level.",1275,50.75,53.7,3.2,7.22,1,0,9607,565.04,49.91,465.84,0.409394387439237,-0.359705195614311,1.86849100035057,4.0772,0
+534,4833,4289,4326,"Parameter values from Amersfoort to ETRS89 (5) (tfm code 4830) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (3) (code 15934).","Approximation at the +/- 1m level.",1275,50.75,53.7,3.2,7.22,1,0,9607,565.4171,50.3319,465.5524,0.398957388243134,-0.343987817378283,1.87740163998045,4.0725,1
+535,15934,4289,4326,"Parameter values from Amersfoort to ETRS89 (3) (tfm code 15739) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces Amersfoort to WGS 84 (2) (code 1672). Replaced by Amersfoort to WGS 84 (4) (tfm code 4833).","Approximation at the +/- 1m level.",1275,50.75,53.7,3.2,7.22,1,0,9607,565.2369,50.0087,465.658,0.406857330322398,-0.350732676542563,1.8703473836068,4.0812,0
+536,1212,4291,4326,Derived at 84 stations.,"For military purposes only. Accuracy 15m, 6m and 9m in X, Y and Z axes.",1341,-56.15,13,-82,-34,1,1,9603,-57,1,-41,,,,,0
+537,1213,4291,4326,Derived at 10 stations.,For military purposes only. Accuracy 5m in each axis.,1033,-58.41,-21.78,-73.59,-52.63,1,1,9603,-62,-1,-37,,,,,0
+538,1214,4291,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1049,-22.91,-9.67,-69.66,-57.52,1,1,9603,-61,2,-48,,,,,0
+539,1215,4291,4326,Derived at 22 stations.,"For military purposes only. Accuracy 3m, 5m and 5m in X, Y and Z axes.",1053,-35.71,7.04,-74.01,-25.28,1,1,9603,-60,-2,-41,,,,,0
+540,1216,4291,4326,Derived at 9 stations.,"For military purposes only. Accuracy 15m, 8m and 11m in X, Y and Z axes.",1066,-59.87,-17.5,-113.21,-65.72,1,1,9603,-75,-1,-44,,,,,0
+541,1217,4291,4326,Derived at 7 stations.,"For military purposes only. Accuracy 6m, 6m and 5m in X, Y and Z axes.",1070,-4.23,15.51,-84.77,-66.87,1,1,9603,-44,6,-36,,,,,0
+542,1218,4291,4326,Derived at 11 stations.,For military purposes. Accuracy 3m in each axis.,1085,-5.01,5,-95.35,-75.21,1,1,9603,-48,3,-44,,,,,0
+543,1219,4291,4326,Derived at 1 station.,For military purposes. Accuracy 25m in each axis.,2356,-1.41,0.18,-91.72,-89.19,1,1,9603,-47,26,-42,,,,,0
+544,1220,4291,4326,Derived at 5 stations.,"For military purposes only. Accuracy 9m, 5m and 5m in X, Y and Z axes.",1114,1.18,10.7,-61.39,-55.77,1,1,9603,-53,3,-47,,,,,0
+545,1221,4291,4326,Derived at 4 stations.,For military purposes. Accuracy 15m in each axis.,1188,-27.59,-19.29,-62.65,-54.24,1,1,9603,-61,2,-33,,,,,0
+546,1222,4291,4326,Derived at 6 stations.,For military purposes. Accuracy 5m in each axis.,1189,-21.05,-0.03,-84.68,-68.67,1,1,9603,-58,0,-44,,,,,0
+547,1223,4291,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,1235,9.83,12.34,-62.09,-57.28,1,1,9603,-45,12,-33,,,,,0
+548,1224,4291,4326,Derived at 5 stations.,"For military purposes only. Accuracy 3m, 6m and 3m in X, Y and Z axes.",1251,0.64,16.75,-73.38,-58.95,1,1,9603,-45,8,-33,,,,,0
+549,1548,4291,4326,"Derived by Brazilean Institute of Geography and Statistics (IGBE) in 1989. Used by ANP.",Medium and small scale mapping.,1053,-35.71,7.04,-74.01,-25.28,1,1,9603,-66.87,4.37,-38.52,,,,,0
+550,1225,4292,4326,Derived at 5 stations.,For military purposes. Accuracy 1m in each axis.,2355,-52.51,-51.16,-59.98,-57.61,1,0,9603,-355,21,72,,,,,1
+551,1226,4293,4326,"Derived at 3 stations. 
+Beware!  Source CRS uses German legal metres, transformation parameter values are in (International) metres. See tfm code 1271 for example.",For military purposes only. Accuracy 20m in each axis.,1169,-30.64,-16.95,8.24,25.27,1,0,9603,616,97,-251,,,,,1
+552,1271,4293,4326,"Beware!  Source CRS uses GLM, tfm param in m. Example: Schwarzeck ?=19°35'46.952""S ?=20°41'50.649""E h=1185.99m; X=5623409.386 Y=2124618.003 Z=-2125847.632 GLM; X=5623485.84m Y=2124646.89m Z=-2125876.54m; WGS 84 X=5624101.48m Y=2124748.97m Z=-2126132.35m.","?",1169,-30.64,-16.95,8.24,25.27,1,0,9603,615.64,102.08,-255.81,,,,,0
+553,1286,4294,4326,Accuracy estimate not available.,For military purposes.,2354,-4.24,4.37,108.79,119.06,1,1,9603,-403,684,41,,,,,0
+554,1834,4294,4326,Accuracy estimate not available.,For military purposes.,2354,-4.24,4.37,108.79,119.06,1,1,9603,-403,684,41,,,,,0
+555,1835,4294,4326,,Oil exploration.,1360,-4.24,4.29,114.55,119.06,1,1,9603,-387.06,636.53,46.29,,,,,0
+556,1836,4294,4326,,Oil exploration.,2770,-0.07,4.29,116.96,119.06,1,1,9603,-403.4,681.12,46.56,,,,,0
+557,1227,4297,4326,Accuracy estimate not available.,For military purposes.,1149,-26.59,-11.69,42.53,51.03,1,0,9603,-189,-242,-91,,,,,1
+558,6873,4297,4326,Derived at 9 points throughout Madagascar. Adopted by OMV.,For applications with an accuracy of 3m.,1149,-26.59,-11.69,42.53,51.03,1,0,9603,-198.383,-240.517,-107.909,,,,,0
+559,1228,4298,4326,Derived at 8 stations.,"For military purposes. Accuracy 10m, 10m and 12m in X, Y and Z axes.",1362,0.85,7.67,109.31,119.61,1,0,9603,-679,669,-48,,,,,1
+560,1592,4298,4326,"Originally used by BSP offshore only, use extended to onshore in 2010.",Oil exploration and production.,1055,4.01,6.31,112.37,115.37,1,0,9603,-678,670,-48,,,,,0
+561,1615,4298,4326,"CARE! Erroneous GPS data was used in the derivation of these parameters. They produce a coordinate difference of 10m horizontally and 50m vertically compared to Timbalai 1948 to WGS 84 (2) (code 1592).",Topographic and engineering survey onshore.,2349,4.01,5.11,114.09,115.37,1,0,9603,-726.282,703.611,-48.999,,,,,0
+562,1852,4298,4326,"Derived by Racal Survey for SSB at 24 coastal stations (including Timbalai fundamental point and 6 other primary triangulation stations) between in Sabah (Kudat southwards) and Sarawak (Sibu northwards).",Oil exploration.,2780,1.56,7.67,109.31,117.31,1,0,9606,-533.4,669.2,-52.5,0,0,4.28,9.4,0
+563,5248,4298,4326,,Oil exploration.,1055,4.01,6.31,112.37,115.37,1,1,9607,-689.5937,623.84046,-65.93566,0.02331,-1.17094,0.80054,5.88536,0
+564,5249,4298,4326,"Parameter values taken from Timbalai 1948 to GDBD2009 (1) (code 5878) assuming that GDBD2009 is equivalent to WGS 84 within the accuracy of the transformation.",Oil exploration.,1055,4.01,6.31,112.37,115.37,1,0,9607,-689.5937,623.84046,-65.93566,0.02331,-1.17094,0.80054,5.88536,0
+565,1229,4299,4326,Derived at 7 stations.,For military purposes only. Accuracy 3m in each axis.,1305,51.39,55.43,-10.56,-5.34,1,1,9603,506,-122,611,,,,,0
+566,1641,4299,4326,"Parameter values from TM75 to ETRS89 (2) (code 1953). Assumes each pair of (i) TM65 and TM75, and (ii) ETRS89 and WGS 84, can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1305,51.39,55.43,-10.56,-5.34,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
+567,1954,4300,4326,"Parameter values taken from TM65 to ETRS89 (2) (code 1953). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1305,51.39,55.43,-10.56,-5.34,1,0,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15,1
+568,1956,4300,4326,"Derived at 7 stations. TM75 is based on the geodetic datum of 1965 which should not be confused with the mapping adjustment of 1965 (TM65).",For military purposes only. Accuracy 3m in each axis.,1305,51.39,55.43,-10.56,-5.34,1,0,9603,506,-122,611,,,,,0
+569,1230,4301,4326,Derived at 31 stations.,"For military purposes only. Accuracy 20m, 5m and 20m in X, Y and Z axes.",2409,20.37,45.54,122.83,145.87,1,0,9603,-148,507,685,,,,,0
+570,1231,4301,4326,Derived at 16 stations.,"For military purposes only. Accuracy 8m, 5m and 8m in X, Y and Z axes.",3995,30.18,45.54,128.31,145.87,1,0,9603,-148,507,685,,,,,0
+571,1232,4301,4326,"Derived at 29 stations. Replaced by Tokyo to WGS 84 (5) (code 1305).","For military purposes only. Accuracy 8m, 5m and 8m in X, Y and Z axes.",3266,33.14,38.64,124.53,131.01,1,0,9603,-146,507,687,,,,,0
+572,1233,4301,4326,Derived at 3 stations.,"For military purposes only. Accuracy 20m, 5m and 20m in X, Y and Z axes.",2408,23.98,26.91,122.83,131.38,1,0,9603,-158,507,676,,,,,0
+573,1305,4301,4326,"Derived at 29 stations. Replaces Tokyo to WGS 84 (3) (code 1232).",For military purposes. Accuracy 2m in each axis.,3266,33.14,38.64,124.53,131.01,1,0,9603,-147,506,687,,,,,0
+574,15484,4301,4326,"Parameter values from Tokyo to JGD2000 (1) (code 15483). Assumes JGD2000 and WGS 84 can be considered the same to within the accuracy of the transformation.","Surveying, mapping and civil engineering purposes. Accuracy on main islands 9m.",3957,20.37,45.54,122.83,154.05,1,0,9603,-146.414,507.337,680.507,,,,,1
+575,1296,4302,4326,Derived in 1989 by ONI for Amoco.,Oil exploration.,1339,9.83,11.51,-62.09,-60,1,0,9603,-61.702,284.488,472.052,,,,,1
+576,10085,4302,4326,"Parameter values provided to EOG by Trinidad Ministry of Energy and Energy Industries. Used by EOG offshore Trinidad (including Pelican, Kiskadee and Ibis fields) since 1996.",Oil exploration.,1339,9.83,11.51,-62.09,-60,1,0,9603,-61,285.2,471.6,,,,,0
+577,1932,4644,4326,,"Accuracy better than +/- 1 metre.",2823,-22.37,-22.19,166.35,166.54,1,1,9606,-166.207,-154.777,254.831,-37.5444,7.7011,-10.2025,-30.8598,0
+578,15904,4644,4326,"Parameter values taken from NEA74 Noumea to RGNC91-93 (1) ( code 15886) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 1 metre.,2823,-22.37,-22.19,166.35,166.54,1,0,9603,-10.18,-350.43,291.37,,,,,1
+579,1294,4304,4326,Accuracy estimate not available.,For military purposes.,1365,31.99,37.14,-2.95,9.09,1,0,9603,-73,-247,227,,,,,1
+580,15815,4728,4326,Determined at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3873,27.58,29.3,-18.22,-13.37,1,0,9603,-307,-92,127,,,,,1
+581,1253,4307,4326,Derived at 3 stations.,For military purposes only. Accuracy 25m in each axis.,3213,18.97,37.14,-8.67,11.99,1,0,9603,-186,-93,310,,,,,0
+582,1255,4307,4326,"CAUTION: Source CRS described by DMA as from Voirol 1960. OGP believes that the data used in the derivation of these parameters contains a blunder. We recommend using transformation North Sahara 1959 to WGS84 (1) (code 1253). Derived at 2 stations.",For military purposes only. Accuracy 25m in each axis.,1365,31.99,37.14,-2.95,9.09,1,0,9603,-123,-206,219,,,,,0
+583,1815,4307,4326,Used by BP in District 3 and In Salah Gas.,Oil industry operations.,2598,25,32,1,3.3,1,0,9606,-152.9,43.8,358.3,2.714,1.386,-2.788,-6.743,0
+584,1816,4307,4326,"Derived at astro station central to concession. Significant and varying differences (>100m) at 4 neighbouring astro stations.",Oil industry operations.,2599,27.5,28.3,8.83,9.92,1,0,9603,-95.7,10.2,158.9,,,,,0
+585,1817,4307,4326,Derived at astro station Guerrara.,Oil industry operations.,2600,31.75,32.42,7.16,8,1,0,9603,-165.914,-70.607,305.009,,,,,0
+586,5630,4307,4326,"Derived at 1 station (L38).",Used by Total in Ahnet licence area.,3917,26.06,27.51,1.26,2.92,1,0,9603,-168.52,-72.05,304.3,,,,,0
+587,5660,4307,4326,Derived in 2006 at 45 points in north and central Algeria.,Accuracy at 75 common points better than 1m..,1026,18.97,38.8,-8.67,11.99,1,0,9606,-209.3622,-87.8162,404.6198,0.0046,3.4784,0.5805,-1.4547,1
+588,15874,4307,4326,"Derived at 11 stations throughout blocks 317b, 319b, 321b and 322b. Network based on station P4 (horizontal) and benchmark RN51 (vertical) using EGM96 geoid height. Used by Statoil in Hassi Mouina.",Oil exploration and production. Accuracy 5m.,3402,29.25,31,0,1.25,1,0,9603,-169.559,-72.34,303.102,,,,,0
+589,1234,4309,4326,Accuracy estimate not available.,For military purposes.,3326,-35,-30.09,-58.49,-53.09,1,0,9603,-155,171,37,,,,,1
+590,5386,4309,4326,Derived at 11 stations during 1998 densification of Uruguay control based on SIRGAS 1995.,"Accuracy at stations used for derivation: 0.13 to 1.17m.",3326,-35,-30.09,-58.49,-53.09,1,0,9606,-124.45,183.74,44.64,-0.4384,0.5446,-0.9706,-2.1365,0
+591,15816,4734,4326,Determined at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3184,-40.42,-37,-12.76,-9.8,1,0,9603,-632,438,-609,,,,,1
+592,1235,4311,4326,Derived at 5 stations.,"For military purposes. Accuracy 5m, 5m and 8m in X, Y and Z axes.",1222,1.83,9.35,-58.08,-52.66,1,0,9603,-265,120,-358,,,,,1
+593,1194,4312,4326,May be taken as approximate transformation MGI to ETRS89 assuming ETRS89 is equivalent to WGS 84 within the accuracy of the transformation - see tfm code 1024. Information source gives scale as -2.388739 ppm.,Provincial GIS and other applications to an accuracy of 0.5 metres.,1543,46.64,47.84,13.58,16.17,1,0,9607,601.705,84.263,485.227,-4.7354,-1.3145,-5.393,-2.3887,0
+594,1306,4312,4326,Accuracy estimate not available.,For military purposes only.,2370,40.85,46.88,13.38,23.04,1,1,9603,682,-203,480,,,,,0
+595,1471,4312,4326,,For applications to an accuracy of 1.5 metres.,1037,46.4,49.02,9.53,17.17,1,1,9606,-577.326,-90.129,-463.919,-5.1365988,-1.4742,-5.2970436,-2.4232,0
+596,1618,4312,4326,"Same transformation parameters used for MGI to ETRS89 (1) (code 1619).",For applications to an accuracy of 1.5 metres.,1037,46.4,49.02,9.53,17.17,1,0,9606,577.326,90.129,463.919,5.137,1.474,5.297,2.4232,1
+597,1621,4312,4326,"Parameter values from MGI to ETRS89 (2) (code 1620). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1076,41.62,46.54,13,19.43,1,1,9606,551.7,162.9,467.9,6.04,1.96,-11.38,-4.82,0
+598,1786,4312,4326,"Parameter values from MGI to ETRS89 (3) (code 1785). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.42,46.88,13.38,16.61,1,1,9606,426.9,142.6,460.1,4.91,4.49,-12.42,17.1,0
+599,1794,4312,4326,"For more accurate transformation see MGI to WGS 84 (7) (code 1795).",Oil industry,3536,41.79,43.56,18.45,20.38,1,1,9603,695.5,-216.6,491.1,,,,,0
+600,15982,4312,4326,"Parameter values from MGI to Slovenia 1996 (1) (code 15981). Assumes Slovenia 1996 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.42,46.88,13.38,16.61,1,1,9607,409.545,72.164,486.872,-3.085957,-5.46911,11.020289,17.919665,0
+601,1609,4313,4326,"Scale difference is given by information source as 0.999999. Given in this record in ppm to assist application usage. Very similar parameter values (to slightly less precision) used for BD72 to ETRS89: see code 1652.",For applications to an accuracy of 1 metre.,1347,49.5,51.51,2.5,6.4,1,0,9607,-99.059,53.322,-112.486,-0.419,0.83,-1.885,-1,0
+602,1610,4313,4326,,For applications to an accuracy of 5 metres.,1347,49.5,51.51,2.5,6.4,1,0,9603,-125.8,79.9,-100.5,,,,,0
+603,15749,4313,4326,"Parameter values from BD72 to ETRS89 (2) (code 15748). Scale difference is given by information source as 1.0000012747. Given in this record in ppm to assist application usage.",For applications to an accuracy of 0.5 metre.,1044,49.5,51.88,2.23,6.4,1,1,9607,-106.8686,52.2978,-103.7239,-0.3366,0.457,-1.8422,1.2747,0
+604,15929,4313,4326,"Parameter values from BD72 to ETRS89 (2) (code 15928). Scale difference is given by information source as -1.0000012747. Given in this record in ppm to assist application usage.",For applications to an accuracy of 0.5 metre.,1347,49.5,51.51,2.5,6.4,1,0,9607,-106.8686,52.2978,-103.7239,-0.3366,0.457,-1.8422,-1.2747,1
+605,1673,4314,4326,"Parameter values from DHDN to ETRS89 (1) (code 1309) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaced by DHDN to WGS 84 (2) (tfm code 1777).",For applications with an accuracy at 5 m level.,2326,47.27,55.09,5.87,13.84,1,0,9607,582,105,414,-1.04,-0.35,3.08,8.3,0
+606,1777,4314,4326,"Parameter values from DHDN to ETRS89 (2) (code 1776) assuming that ETRS89 is equivalent to WGS 84 within the accuracy of the transformation. Replaces DHDN to WGS 84 (1) (tfm code 1673).",For applications with an accuracy at 3 m level,2326,47.27,55.09,5.87,13.84,1,0,9606,598.1,73.7,418.2,0.202,0.045,-2.455,6.7,1
+607,15869,4314,4326,"Parameter values taken from RD/83 to ETRS89 (1) (tfm code 15868) assuming that within the accuracy of the transformation ETRS89 is equivalent to WGS 84 and RD/83 is equivalent to DHDN.",For applications with an accuracy at 2m level,1343,50.2,54.74,9.92,15.04,1,0,9606,612.4,77,440.2,-0.054,0.057,-2.797,2.55,0
+608,1517,4315,4326,,"?",3257,7.19,12.68,-15.13,-7.65,1,0,9603,-23,259,-9,,,,,1
+609,1789,4316,4326,"Parameter values taken from Pulkovo 1942 to WGS 84 (9) (code 1293) assuming that","?",1197,43.44,48.27,20.26,31.41,1,1,9603,103.25,-100.4,-307.19,,,,,0
+610,1995,4316,4326,,Oil exploration,3295,43.62,48.27,20.26,29.74,1,0,9603,103.25,-100.4,-307.19,,,,,1
+611,1097,4317,4326,"Parameter values taken from Pulkovo 1942 to WGS 84 (9) (code 1293) assuming that Pulkovo 1942 in Romania is equivalent to Dealul Piscului 1970.","Accuracy 3m, 5m and 3m in X, Y and Z axes.",1197,43.44,48.27,20.26,31.41,1,1,9603,28,-121,-77,,,,,0
+612,1996,4317,4326,,Oil exploration,1197,43.44,48.27,20.26,31.41,1,1,9603,44.107,-116.147,-54.648,,,,,0
+613,1060,4318,4326,,1 metre accuracy.,3267,28.53,30.09,46.54,48.48,1,0,9603,-3.2,-5.7,2.8,,,,,1
+614,1061,4319,4326,,For applications requiring an accuracy of better than 1 metre.,1310,29.17,29.45,47.78,48.16,1,0,9603,-20.8,11.3,2.4,,,,,1
+615,1062,4319,4326,,For applications requiring an accuracy of better than 1 metre.,1310,29.17,29.45,47.78,48.16,1,0,9607,226.702,-193.337,-35.371,2.229,4.391,-9.238,0.9798,0
+616,1237,4322,4326,,For scientific purposes.,1262,-90,90,-180,180,1,0,9606,0,0,4.5,0,0,0.554,0.2263,1
+617,1238,4322,4326,,For scientific purposes.,1262,-90,90,-180,180,1,0,9606,0,0,4.5,0,0,0.554,0.219,0
+618,15821,4731,4326,Derived at 1 satellite station.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3195,-18.32,-17.25,177.19,178.75,1,1,9603,51,391,-36,,,,,0
+619,1240,4324,4326,,Geodesy.,2346,-90,90,-180,180,1,0,9606,0,0,1.9,0,0,0.814,-0.38,1
+620,5521,4646,4326,,For military purposes. Accuracy unknown.,2807,-11.99,-11.31,43.16,43.55,1,0,9603,-963,510,-359,,,,,1
+621,15822,4732,4326,Derived at 10 satellite stations.,"For military and topographic mapping. Accuracy +/-3 m in each axis.",3191,8.66,19.38,162.27,167.82,1,0,9603,102,52,-38,,,,,1
+622,5327,5324,4326,For many purposes ISN2004 can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that ISN2004 is equivalent to WGS 84.",1120,59.96,69.59,-30.87,-5.55,1,0,9603,0,0,0,,,,,1
+623,3817,3819,4326,Horizontal coordinates of 66 points of the National Geodetic Network were used to compute this transformation.,GIS and topographic survey.,1119,45.74,48.58,16.11,22.9,1,0,9607,595.48,121.69,515.35,-4.115,2.9383,-0.853,-3.408,1
+624,1920,4645,4326,,"Accuracy +/- 1 metre.",1174,-26.45,-14.83,156.25,174.28,1,1,9603,0,0,0,,,,,0
+625,15823,4733,4326,Derived at 2 satellite stations.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3190,19.22,19.38,166.55,166.72,1,0,9603,276,-57,149,,,,,1
+626,3830,3824,4326,"Approximation at the +/- 1m level assuming that TWD97 is equivalent to WGS 84.","Accuracy +/- 1m.",1228,17.36,26.96,114.32,123.61,1,0,9603,0,0,0,,,,,1
+627,5376,5365,4326,,Accuracy 1m.,1074,2.15,11.77,-90.45,-81.43,1,0,9603,0,0,0,,,,,1
+628,15808,4724,4326,Derived at 2 satellite stations.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3189,-7.49,-7.18,72.3,72.55,1,0,9603,208,-435,-229,,,,,1
+629,5377,5371,4326,,Accuracy 1m.,1186,5,12.51,-84.32,-77.04,1,0,9603,0,0,0,,,,,1
+630,5378,5373,4326,,Accuracy 1m.,1189,-21.05,-0.03,-84.68,-68.67,1,0,9603,0,0,0,,,,,1
+631,15812,4736,4326,,"Scientific mapping. Accuracy +/- 20m in each axis.",3204,-63.08,-62.82,-60.89,-60.35,1,0,9603,260,12,-147,,,,,1
+632,15795,4707,4326,Derived at 1 satellite station. Same transformation parameter values related to same datum area given in original 1987 DMA TR8350.2 edition for Sorol Atoll.,For military purposes only. Accuracy 25m in each axis.,3181,23.69,23.93,-166.36,-166.03,1,0,9603,114,-116,-333,,,,,1
+633,5384,5381,4326,,Accuracy 1m.,1247,-37.77,-30.09,-58.49,-50.01,1,0,9603,0,0,0,,,,,1
+634,15813,4722,4326,Determined from 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3529,-54.95,-53.93,-38.08,-35.74,1,0,9603,-794,119,-298,,,,,1
+635,5227,5228,4326,"Parameter values from S-JTSK/05 to ETRS89 (1) (code 5226). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation. Replaces tfm code 1622.",For applications to an accuracy of 1 metre.,1079,48.58,51.06,12.09,18.86,1,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378,1
+636,15771,4692,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Maupiti 83 to RGPF (1) (tfm code 15759).","Accuracy +/- 1 metre.",3126,-16.57,-16.34,-152.39,-152.14,1,0,9603,217.037,86.959,23.956,,,,,1
+637,15973,4055,4326,"Executes change of sphere/ellipsoid",Web mapping. Accuracy may be no better than 800 metres.,1262,-90,90,-180,180,1,1,9603,0,0,0,,,,,0
+638,5395,5393,4326,,Accuracy 1m.,1087,9.97,14.44,-91.43,-87.65,1,0,9603,0,0,0,,,,,1
+639,15842,4739,4326,"Derived at 2 satellite stations. Care: does not use Hong Kong 1963 (code 4838) as the source CRS.","Military mapping. Accuracy +/- 1m.",1118,22.13,22.58,113.76,114.51,1,0,9603,-156,-271,-189,,,,,1
+640,5261,5252,4326,,"Approximation at the +/- 1m level as both TUREF and WGS 84 are realisations of ITRS.",1237,34.42,43.45,25.62,44.83,1,0,9603,0,0,0,,,,,1
+641,1925,4639,4326,,"Accuracy +/- 10 metres.",2815,-13.41,-13.16,-176.25,-176.07,1,1,9603,252,-132,-125,,,,,0
+642,15847,4639,4326,"Replaces information from 2001 (tfm code 1925).","Accuracy +/- 10 metres.",2815,-13.41,-13.16,-176.25,-176.07,1,0,9603,253,-132,-127,,,,,1
+643,15801,4714,4326,Derived at 3 satellite stations.,"Military and topographic mapping; Accuracy +/- 20 m in each axis",3193,-20.31,-17.37,168.09,169.95,1,0,9603,-127,-769,472,,,,,1
+644,15802,4715,4326,No accuracy estimate available.,Military and scientific mapping.,3205,-77.94,-77.17,165.73,167.43,1,0,9603,-104,-129,239,,,,,1
+645,1994,4657,4326,,Low accuracy applications.,3262,63.34,66.59,-24.66,-13.38,1,0,9603,-28,199,5,,,,,1
+646,5351,5340,4326,,Approximation at the sub meter level.,1033,-58.41,-21.78,-73.59,-52.63,1,0,9603,0,0,0,,,,,1
+647,5078,4743,4326,"Parameter values from Karbala 1979 to IGRS (1) (tfm code 5077) assuming that IGRS is equivalent to WGS 84 within the accuracy of the transformation. Replaces Karbala 1979 to WGS 84 (1) (tfm code 15872).",Accuracy 1m.,3625,29.06,37.39,38.79,48.61,1,0,9603,70.995,-335.916,262.898,,,,,1
+648,15872,4743,4326,"Derived from shifts in UTM rectangular coordinates for one point in Basra area provided by Iraq National Oil Exploration Company. Replaced by Karbala 1979 to WGS 84 (2) (tfm code 5078).",Oil exploration.,3397,29.87,31.09,46.46,48.61,1,0,9603,84.1,-320.1,218.7,,,,,0
+649,1951,4658,4326,Derived at 6 stations.,"Accuracy 3m, 3m and 5m in X, Y and Z axes.",3262,63.34,66.59,-24.66,-13.38,1,0,9603,-73,46,-86,,,,,1
+650,6373,6365,4326,,Accuracy 1m.,1160,12.1,32.72,-122.19,-84.64,1,0,9603,0,0,0,,,,,1
+651,3894,3889,4326,"Approximation at the +/- 1m level assuming that IGRS is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1m.,1124,29.06,37.39,38.79,48.75,1,0,9603,0,0,0,,,,,1
+652,1952,4659,4326,For many purposes ISN93 can be considered to be coincident with WGS 84.,"Approximation at the +/- 1m level assuming that ISN93 is equivalent to WGS 84.",1120,59.96,69.59,-30.87,-5.55,1,0,9603,0,0,0,,,,,1
+653,1957,4660,4326,Derived at 3 stations. Residuals under 1m.,For applications to an accuracy of 1 metre.,2869,70.75,71.24,-9.17,-7.87,1,0,9606,982.6087,552.753,-540.873,6.68162662527694,-31.6114924086422,-19.8481610048168,16.805,1
+654,1958,4661,4326,,LKS92 is a realisation of ETRS89 coincident to WGS84 within 1 metre. This transformation has an accuracy equal to the coincidence figure.,1139,55.67,58.09,19.06,28.24,1,0,9603,0,0,0,,,,,1
+655,15849,4213,4326,"Used by Elf / CGG between December 1991 and March 1992. Probably derived from results of concatenated tfm Beduaram to WGS 84 (1) (code 8634).",Oil exploration.,2771,12.8,16.7,7.81,14.9,1,0,9603,-106,-87,188,,,,,1
+656,15803,4716,4326,Derived at 4 satellite stations.,"Military and topographic mapping. Accuracy +/- 15 m in each axis.",3196,-4.76,-2.68,-174.6,-170.66,1,0,9603,298,-304,-375,,,,,1
+657,3915,3906,4326,"Parameter values from MGI 1901 to ETRS89 (3) (code 3914). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.42,46.88,13.38,16.61,1,0,9606,426.9,142.6,460.1,4.91,4.49,-12.42,17.1,0
+658,3917,3906,4326,"Parameter values from MGI 1901 to Slovenia 1996 (1) (code 3916). Assumes Slovenia 1996 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1212,45.42,46.88,13.38,16.61,1,0,9607,409.545,72.164,486.872,-3.085957,-5.46911,11.020289,17.919665,0
+659,3962,3906,4326,Accuracy estimate not available from information source but established empirically by OGP.,For military purposes only.,2370,40.85,46.88,13.38,23.04,1,0,9603,682,-203,480,,,,,1
+660,3964,3906,4326,"Parameter values from MGI 1901 to ETRS89 (2) (code 3963). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,3234,42.34,46.54,13.43,19.43,1,0,9606,551.7,162.9,467.9,6.04,1.96,-11.38,-4.82,0
+661,3965,3906,4326,,Oil industry,3536,41.79,43.56,18.45,20.38,1,0,9603,695.5,-216.6,491.1,,,,,0
+662,6206,3906,4326,Derived at 13 stations.,"1m accuracy. Residuals generally less than +/- 1m horizontally and vertically.",1148,40.85,42.36,20.45,23.04,1,0,9607,521.748,229.489,590.921,-4.029,-4.488,15.521,-9.78,0
+663,15879,4747,4326,"Approximation at the +/- 1m level assuming that GR96 is equivalent to WGS 84 within the accuracy of the transformation.","For applications with an accuracy of +/- 1m.",1107,56.38,87.03,-75,8.12,1,0,9603,0,0,0,,,,,1
+664,1962,4662,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15903.,"Accuracy +/- 10 metres.",2822,-22.45,-20.03,163.92,167.09,1,0,9603,-13,-348,292,,,,,0
+665,1963,4662,4326,Withdrawn by information source and replaced by improved information - see tfm code 15903.,"Accuracy better than +/- 1 metre.",2822,-22.45,-20.03,163.92,167.09,1,0,9606,97.295,-263.247,310.882,-1.5999,0.8386,3.1409,13.3259,0
+666,15903,4662,4326,"Parameter values taken from IGN72 Grande Terre to RGNC91-93 (1) ( code 15882) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.","Accuracy +/- 2 metres.",2822,-22.45,-20.03,163.92,167.09,1,0,9603,-11.64,-348.6,291.98,,,,,1
+667,15878,4748,4326,"Parameter values taken from Viti Levu 1912 to WGS 84 (1) (tfm code 15897). Approximation at the +/- 50m level assuming that CRS 4748 is equivalent to CRS 4752 within the transformation accuracy. Source CRSs 4748 and 4752 are independent but connected.","For applications with an accuracy of +/-50m.",3401,-17.07,-16.1,178.42,-179.77,1,0,9603,51,391,-36,,,,,1
+668,1966,4663,4326,Derived at Forte de Sao Tiago.,For low resolution applications.,2870,32.58,33.15,-17.31,-16.23,1,0,9603,-502.862,-247.438,312.724,,,,,1
+669,1967,4663,4326,,For medium resolution applications.,2870,32.58,33.15,-17.31,-16.23,1,0,9607,-210.502,-66.902,-48.476,-2.094,15.067,5.817,0.485,0
+670,15880,4749,4326,,"Accuracy +/- 1 metre.",1174,-26.45,-14.83,156.25,174.28,1,0,9603,0,0,0,,,,,1
+671,1968,4664,4326,Calculated in 2001.,For low resolution applications.,2871,37.65,37.96,-25.92,-25.08,1,0,9603,-204.633,140.216,55.199,,,,,0
+672,1969,4664,4326,Calculated in 2001.,For medium resolution applications.,2871,37.65,37.96,-25.92,-25.08,1,0,9607,-211.939,137.626,58.3,0.089,-0.251,-0.079,0.384,0
+673,1970,4664,4326,Mean for all islands in group.,For low resolution applications.,1345,36.87,37.96,-25.92,-24.62,1,0,9603,-204.619,140.176,55.226,,,,,1
+674,1971,4664,4326,Mean for all islands in group.,For medium resolution applications.,1345,36.87,37.96,-25.92,-24.62,1,0,9607,-208.719,129.685,52.092,0.195,0.014,-0.327,0.198,0
+675,15881,4750,4326,"Parameter values taken from ST87 Ouvea to RGNC91-93 (1) ( code 15885) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.","Accuracy better than +/- 1 metre.",2813,-20.77,-20.34,166.44,166.71,1,0,9603,-56.263,16.136,-22.856,,,,,1
+676,1972,4665,4326,,For low resolution applications.,2872,38.57,38.86,-27.44,-26.97,1,0,9603,-106.301,166.27,-37.916,,,,,0
+677,1973,4665,4326,,For medium resolution applications.,2872,38.57,38.86,-27.44,-26.97,1,0,9607,-105.854,165.589,-38.312,0.003,0.026,-0.024,-0.048,0
+678,1974,4665,4326,,For low resolution applications.,2873,38.46,38.7,-28.9,-28.54,1,0,9603,-106.248,166.244,-37.845,,,,,0
+679,1975,4665,4326,,For medium resolution applications.,2873,38.46,38.7,-28.9,-28.54,1,0,9607,-104,162.924,-38.882,0.075,0.071,-0.051,-0.338,0
+680,1976,4665,4326,,For low resolution applications.,2874,38.32,38.61,-28.61,-27.98,1,0,9603,-106.044,166.655,-37.876,,,,,0
+681,1977,4665,4326,,For medium resolution applications.,2874,38.32,38.61,-28.61,-27.98,1,0,9607,-95.323,166.098,-69.942,0.215,1.031,-0.047,1.922,0
+682,1978,4665,4326,,For low resolution applications.,2875,38.48,38.8,-28.37,-27.71,1,0,9603,-106.253,166.239,-37.854,,,,,0
+683,1979,4665,4326,,For medium resolution applications.,2875,38.48,38.8,-28.37,-27.71,1,0,9607,-100.306,161.246,-48.761,0.192,0.385,-0.076,0.131,0
+684,1980,4665,4326,Mean for all islands in group.,For low resolution applications.,1301,38.32,39.14,-28.9,-26.97,1,0,9603,-106.226,166.366,-37.893,,,,,1
+685,1981,4665,4326,Mean for all islands in group.,For medium resolution applications.,1301,38.32,39.14,-28.9,-26.97,1,0,9607,-103.088,162.481,-28.276,-0.167,-0.082,-0.168,-1.504,0
+686,1986,4666,4326,May be taken as a transformation from Lisbon 1890 to ETRS89 - see tfm code 5039.,For low resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9603,508.088,-191.042,565.223,,,,,1
+687,1990,4666,4326,,For medium resolution applications.,1294,36.95,42.16,-9.56,-6.19,1,0,9607,631.392,-66.551,481.442,-1.09,4.445,4.487,-4.43,0
+688,15804,4717,4326,Derived at 19 satellite stations.,"US space and military operations. Accuracy +/- 3 m in each axis.",3206,20.86,30.83,-82.33,-72.68,1,0,9603,-2,151,181,,,,,1
+689,5267,5264,4326,DRUKREF 03 and WGS 84 are both realisations of ITRS.,For applications to an accuracy of 1 metre.,1048,26.7,28.33,88.75,92.12,1,0,9603,0,0,0,,,,,1
+690,15708,4683,4326,Derived during GPS campaign which established PRS92 coordinates at 330 first order stations.,"Accuracy: 1-10 parts per million.",1190,3,22.18,116.04,129.95,1,0,9607,-127.62,-67.24,-47.04,3.068,-4.903,-1.578,-1.06,1
+691,1993,4667,4326,For all practical purposes this transformation is exact.,Boundary demarcation.,2876,29.06,30.32,46.36,48.61,1,0,9603,0,0,0,,,,,1
+692,15897,4752,4326,Derived at 1 satellite station.,"For military and topographic mapping. Accuracy +/-25m in each axis.",3195,-18.32,-17.25,177.19,178.75,1,0,9603,51,391,-36,,,,,1
+693,15752,4668,4326,Derived at 22 stations.,For military purposes. Accuracy 3m in each axis.,1297,34.88,71.21,-10.56,31.59,1,0,9603,-86,-98,-119,,,,,1
+694,15810,4735,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis.",3192,5.21,5.43,162.85,163.1,1,0,9603,647,1777,-1124,,,,,1
+695,6701,5246,4326,"Approximation at the +/- 1m level assuming that GDBD2009 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1m.,1055,4.01,6.31,112.37,115.37,1,0,9603,0,0,0,,,,,1
+696,4477,4463,4326,"Approximation at the +/- 1m level assuming that RGSPM06 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1220,43.41,47.37,-57.1,-55.9,1,0,9603,0,0,0,,,,,1
+697,5501,5489,4326,"Approximation at the +/- 1m level assuming that RGAF09 is equivalent to WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",2824,14.08,18.54,-63.66,-57.52,1,0,9603,0,0,0,,,,,1
+698,15912,4755,4326,"Approximation at the +/- 1m level assuming that DGN95 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1 metre.,1122,-13.25,7.79,92.01,141.46,1,0,9603,0,0,0,,,,,1
+699,1555,4158,4326,Derived in 1989 by ONI for Amoco.,Oil exploration.,3143,9.99,10.9,-61.97,-60.86,1,0,9603,-0.465,372.095,171.736,,,,,1
+700,1556,4158,4326,Described by NIMA as Naparima to WGS 84. In Trinidad the source CRS is better known as Naparima 1955. EPSG has duplicated the tfm using the alternative source CRSs. See also tfm code 1307.,For military purposes only. Accuracy given by NIMA 15m in each axis. EPSG believes there is an 8-10m blunder in dX.,3143,9.99,10.9,-61.97,-60.86,1,0,9603,-2,374,172,,,,,0
+701,4476,4470,4326,"Approximation at the +/- 1m level assuming that RGM04 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1159,-14.49,-11.33,43.68,46.7,1,0,9603,0,0,0,,,,,1
+702,5194,4756,4326,Used by Total in Mekong delta.,Academic research not officially adopted.,3770,9.34,11.03,104.25,107.11,1,0,9607,-192.873,-39.382,-111.202,0.00205,0.0005,-0.00335,0.0188,1
+703,1931,4643,4326,,"Accuracy better than +/- 1 metre.",2821,-19.85,-19.5,163.54,163.75,1,0,9606,-480.26,-438.32,-643.429,16.3119,20.1721,-4.0349,-111.7002,1
+704,4290,4475,4326,"Parameter values taken from Cadastre 1997 to RGM04 (1) (transformation code 4478) assuming that RGM04 is coincident with WGS 84 within the accuracy of the transformation.","Accuracy +/- 1 metre.",3340,-13.05,-12.61,44.98,45.35,1,0,9603,-381.788,-57.501,-256.673,,,,,1
+705,5374,5354,4326,,Accuracy 1m.,1049,-22.91,-9.67,-69.66,-57.52,1,0,9603,0,0,0,,,,,1
+706,15787,4701,4326,Derived by Topnav in 1991 at station TSH 85.,Oil exploration. Accuracy 5m.,3171,-6.04,-4.28,12.17,16.28,1,0,9603,-79.9,-158,-168.9,,,,,1
+707,4832,4483,4326,,Accuracy 1m.,1160,12.1,32.72,-122.19,-84.64,1,0,9603,0,0,0,,,,,1
+708,1917,4633,4326,Withdrawn by information source and replaced by improved information from local authority - see tfm code 15902.,"Accuracy +/- 10 metres.",2814,-21.24,-20.62,166.98,167.52,1,0,9603,336,223,-231,,,,,0
+709,1927,4633,4326,Withdrawn by information source and replaced by improved information - see tfm code 15902.,"Accuracy better than +/- 1 metre.",2814,-21.24,-20.62,166.98,167.52,1,0,9606,137.092,131.66,91.475,-1.9436,-11.5993,-4.3321,-7.4824,0
+710,15902,4633,4326,"Parameter values taken from IGN56 Lifou to RGNC91-93 (1) ( code 15883) assuming that RGNC91-93 is equivalent to WGS 84 to within the accuracy of the transformation.",Accuracy 1 metre.,2814,-21.24,-20.62,166.98,167.52,1,0,9603,335.47,222.58,-230.94,,,,,1
+711,15925,4758,4326,,For all practical purposes JAD2001 can be considered to be coincident with WGS 84.,1128,14.08,19.36,-80.6,-74.51,1,0,9603,0,0,0,,,,,1
+712,6711,6706,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84. RDN2008 is a regional realisation of ETRS89.","Accuracy +/- 1 metre.",1127,34.76,47.1,5.93,18.99,1,0,9603,0,0,0,,,,,1
+713,15845,4161,4326,Transformation parameter precision given to millimetres in information source but due to accuracy rounded to nearest decimetre for EPSG database.,Geodetic surveying within the oil industry. Accuracy 25 m.,1265,-46.7,-45.19,-69.5,-67.1,1,0,9603,27.5,14,186.4,,,,,1
+714,15931,4759,4326,"Approximation at the +/- 1m level assuming that NAD83(NSRS2007) is equivalent to WGS 84 within the accuracy of the transformation.",For applications to an accuracy of 1 metre.,1511,14.92,74.71,167.65,-63.88,1,0,9603,0,0,0,,,,,1
+715,1540,4163,4326,,Accuracy better than 1 metre.,1257,8.95,19,41.08,57.96,1,0,9603,0,0,0,,,,,1
+716,4905,5013,4326,,PTRA08 and WGS 84 are realisations of ITRS coincident to within 1 metre. This transformation has an accuracy equal to the coincidence figure.,3670,29.24,43.07,-35.58,-12.48,1,0,9603,0,0,0,,,,,1
+717,6195,5527,4326,"Parameter values from SAD69(96) to SIRGAS 2000 (2)) (tfm code 5881) assuming that SIRGAS 2000 and WGS 84 are equal within the accuracy of the transformation, based on SAD69 to SIRGAS 2000 (1)) (tfm code 15485). Used by Petrobras and ANP from 1994.","Accuracy generally better than 1m except in Amazon basin where it degenerates to 5m. Should be used only to transform data obtained independently of the classical geodetic network (GPS observations conducted after 1994).", [...]
+718,15806,4719,4326,Derived at 1 satellite station.,"Military and topographic mapping. Accuracy +/- 25m in each axis",3188,-27.25,-27.01,-109.51,-109.16,1,0,9603,211,147,111,,,,,1
+719,15860,4702,4326,Mauritania 1999 can be considered to be the same as WGS 84 within the accuracy of this transformation.,Minerals management. Accuracy 1m.,1157,14.72,27.3,-20.04,-4.8,1,0,9603,0,0,0,,,,,1
+720,15971,4762,4326,"Approximation at the +/- 1m level assuming that BDA2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1047,28.91,35.73,-68.83,-60.7,1,0,9603,0,0,0,,,,,1
+721,5375,5360,4326,,Accuracy 1m.,1066,-59.87,-17.5,-113.21,-65.72,1,0,9603,0,0,0,,,,,1
+722,15972,4763,4326,"Approximation at the +/- 1m level assuming that Pitcairn 2006 is equivalent to WGS 84.","Accuracy +/- 1 metre.",3208,-25.14,-25,-130.16,-130.01,1,0,9603,0,0,0,,,,,1
+723,1558,4166,4326,Derived at 5 stations.,For military purposes. Accuracy 1m in each axis.,3266,33.14,38.64,124.53,131.01,1,0,9603,0,0,0,,,,,1
+724,4084,4081,4326,"Approximation at the +/- 1m level assuming that REGCAN95 is equivalent to WGS 84.","Accuracy +/- 1m.",3199,24.6,32.76,-21.93,-11.75,1,0,9603,0,0,0,,,,,1
+725,15974,4764,4326,"Approximation at the +/- 1m level assuming that RSRGD2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",3558,-90,-59.99,144.99,-144.99,1,0,9603,0,0,0,,,,,1
+726,5553,5546,4326,"Exact in 1994 but due to significant and variable tectonic activity in PNG, in 2011 PNG94 and WGS 84 differ generally by 2m but in areas of significant tectonic activity differences can exceed 9m.",Approximation at the 2-10m level.,1187,-14.75,2.58,139.2,162.81,1,0,9603,0,0,0,,,,,1
+727,15870,4679,4326,Derived at 5 points in 2002.,Hydrographic survey,2967,19.37,21.34,-17.08,-15.88,1,0,9603,-80.01,253.26,291.19,,,,,1
+728,15976,4765,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1212,45.42,46.88,13.38,16.61,1,0,9603,0,0,0,,,,,1
+729,15820,4730,4326,Derived at 1 satellite station.,For military and topographic mapping. Accuracy 25m in each axis.,3194,-17.32,-14.57,166.47,168.71,1,0,9603,170,42,84,,,,,1
+730,15709,4680,4326,Derived by IGN in 1992 at 7 stations within Nouakchott city.,Oil exploration.,2972,17.89,18.25,-16.11,-15.83,1,0,9603,124.5,-63.5,-281,,,,,1
+731,15908,4754,4326,Derived at 5 stations throughout Libya used to define LGD2006 in May 2006.,For applications to an accuracy of 0.1 metre.,1143,19.5,35.23,9.31,26.21,1,0,9603,-208.4058,-109.8777,-2.5764,,,,,1
+732,5585,4023,4326,"Parameter values from MOLDREF99 to ETRS89 (1) (code 5584). Assumes ETRS89 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications with an accuracy of 1m.,1162,45.44,48.47,26.63,30.13,1,0,9603,0,0,0,,,,,1
+733,15831,4737,4326,"Approximation at the +/- 1m level assuming that ITRF2000 is equivalent to WGS 84.","Accuracy +/- 1 metre.",1135,28.6,40.27,122.71,134.28,1,0,9603,0,0,0,,,,,1
+734,5590,5561,4326,"Derived through concatenation of UCS-2000 to S-42 (1) (tfm code 5586 reversed) [an approximation] and S-42 to WGS 84 (16) (tfm code 15865) [derived for whole FSU rather than Ukraine]. Replaced by UCS-2000 to WGS 84 (2) (tfm code 5840).",Accuracy 5 metres.,1242,43.18,52.38,22.15,40.18,1,0,9607,25,-141,-78.5,0,-0.35,-0.736,0,1
+735,5823,5561,4326,"Parameter values taken from Ukraine 2000 to ITRF2005 (1) (code 5822) assuming that ITRS2005 is equivalent to WGS 84 within the accuracy of the transformation.","Approximation at the +/- 1m level assuming that ITRS2005 is equivalent to WGS 84.",1242,43.18,52.38,22.15,40.18,1,1,9603,24,-121,-76,,,,,0
+736,5840,5561,4326,"Parameter values taken from UCS-2000 to ITRF2005 (1) (code 5822) assuming that WGS 84 is equivalent to ITRS2005 within the accuracy of the transformation. Replaces UCS-2000 to WGS 84 (1) (tfm code 5590).","Approximation at the +/- 1m level assuming that WGS 84 is equivalent to ITRS2005.",1242,43.18,52.38,22.15,40.18,1,0,9603,24,-121,-76,,,,,0
+737,15700,4682,4326,Derived at origin station in Dhaka.,Oil exploration.,1041,18.56,26.63,88.04,92.67,1,1,9603,283.8,735.9,261.1,,,,,0
+738,15779,4682,4326,Derived at origin station in Dhaka. Source information given to 3 decimal places but rounded by OGP to be commensurate with stated accuracy.,Oil exploration.,1041,18.56,26.63,88.04,92.67,1,0,9603,283.7,735.9,261.1,,,,,1
+739,1919,4635,4326,,"Accuracy better than +/- 1 metre.",2813,-20.77,-20.34,166.44,166.71,1,1,9606,-122.383,-188.696,103.344,3.5107,-4.9668,-5.7047,4.4798,0
+740,5470,5451,4326,"Parameter values taken from Ocotepeque to CR05 (1) (tfm code 6890) assuming that CR05 is equivalent to WGS 84 within the accuracy of the transformation.",Topographic mapping.,3232,7.98,11.22,-85.97,-82.53,1,0,9603,213.11,9.37,-74.95,,,,,0
+741,5473,5451,4326,"Rotations in original source given in radians are equivalent to Rx = 2.35"", Ry = -0.06"", Rz = 6.39"".",Topographic mapping.,3232,7.98,11.22,-85.97,-82.53,1,1,9607,213.116,9.358,-74.946,2.3514187912169,-0.0614669122616347,6.39420899365999,-5.22,0
+742,5474,5451,4326,,Topographic mapping.,3876,7.98,17.83,-92.29,-82.53,1,1,9603,205.435,-29.099,292.202,,,,,0
+743,6891,5451,4326,"Concatenation (via NAD27) of transformations 6888 and 1171. Accuracy not given, but accuracy of constituent transformations given as 9m and 10m respectively.",For military purposes.,3876,7.98,17.83,-92.29,-82.53,1,0,9603,205,96,-98,,,,,1
+744,15713,4684,4326,Derived at 1 station.,For military purposes only. Accuracy 25m in each axis.,3274,-0.69,7.08,72.81,73.69,1,0,9603,-133,-321,50,,,,,1
+745,6177,6135,4326,"Approximation at the +/- 1m level assuming that CIGD11 is equivalent to WGS 84.","Accuracy +/- 1m.",1063,17.58,20.68,-83.6,-78.72,1,0,9603,0,0,0,,,,,1
+746,4064,4046,4326,"Approximation at the +/- 1m level assuming that RGRDC 2005 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1m.,3613,-13.46,-3.41,11.79,29.81,1,0,9603,0,0,0,,,,,1
+747,15846,4706,4326,"Sometime referred to as ""Egypt 1907 to WGS 84"". However, application to WGS 84 coordinates of the reverse of this tfm results in Gulf of Suez S-650 TL, not Egypt 1907, position. Gulf of Suez S-650 TL and Egypt 1907 CRSs differ by some 20 metres.",Used for oil exploration by GUPCO.,2341,27.19,30.01,32.34,34.27,1,0,9603,-146.21,112.63,4.05,,,,,1
+748,15918,4214,4326,Provided by BGP to TOTAL in June 2006.,Geophysical exploration in Ordos basin. Accuracy stated as 1m within basin.,3466,35,39,107,110.01,1,0,9603,12.646,-155.176,-80.863,,,,,0
+749,15919,4214,4326,Derived via WGS 72BE. Original transformation derived in 1979 at 4 stations on Yellow Sea coast.,Geophysical exploration in Yellow Sea.,3469,31.23,37.4,119.23,125.06,1,0,9606,15.53,-113.82,-41.38,0,0,0.814,-0.38,0
+750,15920,4214,4326,"Derived via WGS 72BE. Original transformation derived by GSI in 1980-81. The GSI memo incorrectly gave the parameters as from WGS 72 to Beijing 1954, but it has been determined by the OGP that the memo should have stated from Beijing 1954 to WGS 72BE.",Geophysical exploration in South China Sea.,3470,18.31,22.89,110.13,116.76,1,0,9606,31.4,-144.3,-74.8,0,0,0.814,-0.38,0
+751,15921,4214,4326,Provided by BGP to ELF in 1994.,Geophysical exploration in Tarim basin. Accuracy stated as 1m within basin.,3507,37,41.99,77.45,88,1,0,9603,15.8,-154.4,-82.3,,,,,1
+752,15935,4214,4326,Concatenated via WGS 72BE. Recomputation by Shelltech in 1981 of SSB 1980 observation.,Geophysical exploration in Bei Bu basin. Accuracy stated as 1m within basin.,3561,17.81,21.69,107.15,110.17,1,0,9606,18,-136.8,-73.7,0,0,0.814,-0.38,0
+753,15936,4214,4326,Provided by Sinopec to TOTAL in January 2007.,Geophysical exploration in Ordos basin. Accuracy stated as 1m within basin.,3466,35,39,107,110.01,1,0,9603,11.911,-154.833,-80.079,,,,,0
+754,15875,4721,4326,Derived at 20 stations.,"For military purposes. Accuracy 5m, 3m and 2m in X, Y and Z axes.",3398,-19.22,-16.1,176.81,-179.77,1,0,9603,265.025,384.929,-194.046,,,,,1
+755,15876,4720,4326,"Approximation at the +/- 2m level assuming that Fiji 1986 is equivalent to WGS 72. Parameter values taken from WGS 72 to WGS 84 (1) (tfm code 1237).",tbc,1094,-20.81,-12.42,176.81,-178.15,1,0,9606,0,0,4.5,0,0,0.554,0.2263,1
+756,15877,4720,4326,"Suitable for GIS mapping purposes but not rigorous surveying. Very similar results may be obtained through Fiji 1986 to WGS 84 (1) (tfm code 15876).","Horizontal accuracy 2m, vertical accuracy approximately 40 metres..",3398,-19.22,-16.1,176.81,-179.77,1,0,9607,-35.173,136.571,-36.964,1.37,-0.842,-4.718,-1.537,0
+757,5599,5593,4326,,Approximation at the 1m level.,3889,54.33,54.83,10.66,12.01,1,0,9603,0,0,0,,,,,1
+758,15832,4687,4326,"Transformation is to original definition of WGS 84. It is consistent with later WGS 84 realisations G730, G873 and G1150 to no better than 1m.","Accuracy +/- 0.5 metre (to original definition of WGS 84 - see remarks).",1098,-31.24,-4.52,-158.13,-131.97,1,0,9607,0.072,-0.507,-0.245,0.0183,-0.0003,0.007,-0.0093,1
+759,15833,4687,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84.","Accuracy +/- 1 metre.",1098,-31.24,-4.52,-158.13,-131.97,1,0,9603,0,0,0,,,,,0
+760,1921,4636,4326,,"Accuracy +/- 10 metres.",2817,-66.78,-66.1,139.44,141.5,1,0,9603,365,194,166,,,,,1
+761,15772,4688,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Fatu Iva 72 to RGPF (1) (tfm code 15760).","Accuracy +/- 2 metres.",3133,-10.6,-10.36,-138.75,-138.54,1,0,9607,347.103,1078.125,2623.922,33.8875,-70.6773,9.3943,186.074,1
+762,5236,5233,4326,Derived at 58 stations.,Accuracy 14m.,3310,5.86,9.88,79.64,81.95,1,0,9607,-0.293,766.95,87.713,-0.195704,-1.695068,-3.473016,-0.039338,1
+763,4077,4075,4326,"Approximation at the +/- 1m level assuming that ETRS89 is equivalent to WGS 84. SREF98 is a regional realisation of ETRS89.","Accuracy +/- 1 metre.",3534,41.85,46.19,18.81,23.01,1,0,9603,0,0,0,,,,,1
+764,4835,4690,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Tahiti 79 to RGPF (1) (tfm code 15756).","Accuracy +/- 1 metre.",3124,-17.93,-17.44,-149.7,-149.09,1,0,9607,221.525,152.948,176.768,2.3847,1.3896,0.877,11.4741,1
+765,1922,4637,4326,,"Accuracy +/- 10 metres.",2818,-67.13,-65.61,136,142,1,0,9603,325,154,172,,,,,1
+766,15797,4712,4326,Derived at 2 satellite stations.,For military purposes only. Accuracy 25m in each axis.,3182,-8.03,-7.83,-14.46,-14.24,1,0,9603,-205,107,53,,,,,1
+767,15769,4691,4326,"Approximation at the +/- 1m level assuming that RGPF is equivalent to WGS 84. Parameter values taken from Moorea 87 to RGPF (1) (tfm code 15757).","Accuracy +/- 1 metre.",3125,-17.63,-17.41,-150,-149.73,1,0,9607,215.525,149.593,176.229,3.2624,1.692,1.1571,10.4773,1
+768,6142,4723,4326,"Parameter values are taken from GCGD59 to CIGD11 (1) (code 6136) assuming that CIGD11 and WGS 84 can be considered the same to within the accuracy of the transformation.",For applications to an accuracy of 1m.,3185,19.21,19.41,-81.46,-81.04,1,0,9607,-179.483,-69.379,-27.584,7.862,-8.163,-6.042,-13.925,1
+769,15830,4723,4326,Determined from 6 satellite stations.,"Topographic survey. Accuracy +/- 1m.",3185,19.21,19.41,-81.46,-81.04,1,0,9603,67.8,106.1,138.8,,,,,0
+770,4066,4695,4326,"Parameter values taken from Katanga 1955 to RGRDC 2005 (1) (code 4065) assuming that RGRDC 2005 is equivalent to WGS 84 within the accuracy of the transformation.",Accuracy 1.5m.,3614,-12.01,-11.13,26.38,27.75,1,0,9603,-103.746,-9.614,-255.95,,,,,1
+771,15746,4693,4326,Derived in Tombak district in March 2005. Used for South Pars phase 11 and Pars LNG plants.,Petroleum Exploration and Production.,3141,27.63,27.81,52.09,52.26,1,0,9603,0,-0.15,0.68,,,,,1
+772,1441,4601,4326,,"?",1273,16.94,17.22,-61.95,-61.61,1,0,9603,-255,-15,71,,,,,1
+773,15811,4601,4326,Determined from 1 satellite station.,"Military mapping. Accuracy +/- 25m in each axis.",1273,16.94,17.22,-61.95,-61.61,1,0,9603,-270,13,62,,,,,0
+774,1442,4602,4326,,"?",3239,15.14,15.69,-61.55,-61.2,1,0,9603,725,685,536,,,,,1
+775,1443,4603,4326,,"?",3118,11.94,12.29,-61.84,-61.54,1,0,9603,72,213.7,93,,,,,1
+776,1444,4604,4326,Derived at 1 satellite station.,Accuracy 25m in each axis.,3279,16.62,16.87,-62.29,-62.08,1,0,9603,174,359,365,,,,,1
+777,1445,4605,4326,,"?",3297,17.06,17.46,-62.92,-62.5,1,0,9603,9,183,236,,,,,1
+778,15750,4605,4326,Derived at 2 stations.,"For military purposes. Accuracy 25m in each of X, Y and Z axes.",3297,17.06,17.46,-62.92,-62.5,1,0,9603,-7,215,225,,,,,0
+779,1446,4606,4326,,"?",3298,13.66,14.16,-61.13,-60.82,1,0,9603,-149,128,296,,,,,1
+780,1959,4607,4326,Derived at 4 points.,1m accuracy.,3300,12.54,13.44,-61.52,-61.07,1,0,9603,195.671,332.517,274.607,,,,,1
diff --git a/data/ellipsoid.csv b/data/ellipsoid.csv
index d58aa6c..f5aea43 100644
--- a/data/ellipsoid.csv
+++ b/data/ellipsoid.csv
@@ -6,9 +6,9 @@ ellipsoid_code,ellipsoid_name,semi_major_axis,uom_code,inv_flattening,semi_minor
 7004,Bessel 1841,6377397.155,9001,299.1528128,,1,"Original Bessel definition is a=3272077.14 and b=3261139.33 toise. This used a weighted mean of values from several authors but did not account for differences in the length of the various toise: the ""Bessel toise"" is therefore of uncertain length.","US Army Map Service Technical Manual; 1943.",OGP,1999/04/22,1998.321 1998.340,0
 7005,Bessel Modified,6377492.018,9001,299.1528128,,1,Used in Norway and also in Sweden with a 1mm increase in semi-major axis.,,OGP,1999/04/22,1998.321,0
 7006,Bessel Namibia,6377483.865,9001,299.1528128,,1,a = 6377397.155 German legal metres. This is the same value as the Bessel 1841 figure (code 7004) but in different units.  Used in Namibia.,"Chief Directorate: Surveys and Mapping, Mowbray, South Africa.",OGP,1999/04/22,1997.160,1
-7007,Clarke 1858,20926348,9005,,20855233,1,"Clarke's 1858/II solution. Derived parameters: a = 6378293.645m using his 1865 ratio of 0.3047972654 feet per metre; 1/f = 294.26068Â…  In Australia and Amoco Trinidad 1/f taken to two decimal places (294.26 exactly); elsewhere a and b used to derive 1/f.","""Ellipsoidisch Parameter der Erdfigur (1800-1950)"" by Georg Strasser.",OGP,2005/08/14,1999.700 2005.370,0
+7007,Clarke 1858,20926348,9005,,20855233,1,"Clarke's 1858/II solution. Derived parameters: a = 6378293.645m using his 1865 ratio of 0.3047972654 feet per metre; 1/f = 294.26068…  In Australia and Amoco Trinidad 1/f taken to two decimal places (294.26 exactly); elsewhere a and b used to derive 1/f.","""Ellipsoidisch Parameter der Erdfigur (1800-1950)"" by Georg Strasser.",OGP,2005/08/14,1999.700 2005.370,0
 7008,Clarke 1866,6378206.4,9001,,6356583.8,1,Original definition a=20926062 and b=20855121 (British) feet. Uses Clarke's 1865 inch-metre ratio of 39.370432 to obtain metres. (Metric value then converted to US survey feet for use in the US and international feet for use in Cayman Islands).,"US Army Map Service Technical Manual No. 7; 1943.",OGP,2013/01/17,1998.340 2012.095,0
-7009,Clarke 1866 Michigan,20926631.531,9003,,20855688.674,1,"Used for Michigan NAD27 State Plane zones.  Radius = ellipsoid radius + 800 feet; this approximates the average elevation of the state.   Derived parameter: 1/f = 294.97870",USGS Professional Paper #1395.,OGP,1995/06/02,1998.220,0
+7009,Clarke 1866 Michigan,20926631.531,9003,,20855688.674,1,"Used for Michigan NAD27 State Plane zones.  Radius = ellipsoid radius + 800 feet; this approximates the average elevation of the state.   Derived parameter: 1/f = 294.97870",USGS Professional Paper #1395.,OGP,1995/06/02,1998.220 2013.020,1
 7010,Clarke 1880 (Benoit),6378300.789,9001,,6356566.435,1,Adopts Clarke's values for a and b.  Uses Benoit's 1895 ratio of 0.9143992 metres per yard to convert to metres.,,OGP,1995/06/02,,0
 7011,Clarke 1880 (IGN),6378249.2,9001,,6356515,1,Adopts Clarke's values for a and b using his 1865 ratio of 39.370432 inches per metre to convert axes to metres.,,OGP,1998/04/16,1998.120,0
 7012,Clarke 1880 (RGS),6378249.145,9001,293.465,,1,Adopts Clarke's values for a and 1/f.  Adopts his 1865 ratio of 39.370432 inches per metre to convert semi-major axis to metres. Also known as Clarke Modified 1880.,"Empire Survey Review #32; 1939.",OGP,1995/06/02,,0
@@ -17,7 +17,7 @@ ellipsoid_code,ellipsoid_name,semi_major_axis,uom_code,inv_flattening,semi_minor
 7015,Everest 1830 (1937 Adjustment),6377276.345,9001,300.8017,,1,Used for the 1937 readjustment of Indian triangulation.  Clarke's 1865 Indian-British foot ratio (0.99999566) and Benoit's 1898 British inch-metre ratio (39.370113) rounded as 0.30479841 exactly and applied to Everest's 1830 definition taken as a and 1/f,"Survey of India professional paper #28; 1939",OGP,1996/10/18,1996.200,0
 7016,Everest 1830 (1967 Definition),6377298.556,9001,300.8017,,1,Adopted 1967 for use in East Malaysia.  Applies Sears 1922 inch-metre ratio of 39.370147 to Everest 1830 original definition of a and 1/f but with a taken to be in British rather than Indian feet.,,OGP,1995/06/02,,0
 7018,Everest 1830 Modified,6377304.063,9001,300.8017,,1,Adopted 1967 for use in West Malaysia.  Applies Benoit 1898 inch-metre ratio of 39.370113 to Everest 1830 original definition of a and 1/f but with a taken to be in British rather than Indian feet.,,OGP,1995/06/02,,0
-7019,GRS 1980,6378137,9001,298.257222101,,1,"Adopted by IUGG 1979 Canberra.  Inverse flattening is derived from geocentric gravitational constant GM = 3986005e8 m*m*m/s/s; dynamic form factor J2 = 108263e8 and Earth's angular velocity = 7292115e-11 rad/s.","""Geodetic Reference System 1980"" by H. Moritz; Bulletin Geodesique",OGP,1998/11/11,1998.110 1998.320,0
+7019,GRS 1980,6378137,9001,298.257222101,,1,"Adopted by IUGG 1979 Canberra.  Inverse flattening is derived from geocentric gravitational constant GM = 3986005e8 m*m*m/s/s; dynamic form factor J2 = 108263e-8 and Earth's angular velocity = 7292115e-11 rad/s.","""Geodetic Reference System 1980"" by H. Moritz; Bulletin Geodesique",OGP,2013/08/23,1998.110 1998.320 2013.043,0
 7020,Helmert 1906,6378200,9001,298.3,,1,Helmert 1906/III solution.,"""Ellipsoidisch Parameter der Erdfigur (1800-1950)"" by Georg Strasser",OGP,1995/06/02,,0
 7021,Indonesian National Spheroid,6378160,9001,298.247,,1,Based on the GRS 1967 figure but with 1/f taken to 3 decimal places exactly.,Rais paper.,OGP,1995/06/02,,0
 7022,International 1924,6378388,9001,297,,1,Adopted by IUGG 1924 in Madrid. Based on Hayford 1909/1910 figures. ,,OGP,1995/06/02,,0
@@ -47,7 +47,7 @@ ellipsoid_code,ellipsoid_name,semi_major_axis,uom_code,inv_flattening,semi_minor
 7052,Clarke 1866 Authalic Sphere,6370997,9001,,6370997,0,Authalic sphere derived from Clarke 1866 ellipsoid (code 7008).,OGP,OGP,2004/04/27,,0
 7053,Hough 1960,6378270,9001,297,,1,,DMA / NIMA / NGA TR8350.2,OGP,2006/01/26,,0
 7054,PZ-90,6378136,9001,298.257839303,,1,,"Geodeziya i Katografiya, 1993.",OGP,2006/02/03,,0
-7055,Clarke 1880 (international foot),20926202,9002,,20854895,1,Clark'es 1880 definition in feet assumed for the purposes of metric conversion to be international foot. a = 6378306.370Â…metres. 1/f derived from a and b = 293.4663077Â… Used in Fiji.,"Department of Lands and Survey, Fiji.",OGP,2006/07/14,,0
+7055,Clarke 1880 (international foot),20926202,9002,,20854895,1,Clark'es 1880 definition in feet assumed for the purposes of metric conversion to be international foot. a = 6378306.370…metres. 1/f derived from a and b = 293.4663077… Used in Fiji.,"Department of Lands and Survey, Fiji.",OGP,2006/07/14,,0
 7056,Everest 1830 (RSO 1969),6377295.664,9001,300.8017,,1,Adopted for 1969 metrication of peninsula Malaysia RSO grid.  Uses Sears 1922 yard-metre ratio truncated to 6 significant figures applied to Everest 1830 original definition of a and 1/f but with a taken to be in British rather than Indian feet.,Defence Geographic Centre,OGP,2006/07/24,,0
 7057,International 1924 Authalic Sphere,6371228,9001,,6371228,0,Authalic sphere derived from International 1924 ellipsoid (code 7022).,OGP,OGP,2006/09/22,,0
 7058,Hughes 1980,6378273,9001,,6356889.449,1,Used in US DMSP SSM/I microwave sensor processing software. Semi-minor axis derived from eccentricity=0.081816153. Semi-major axis (a) sometimes given as 3443.992nm which OGP suspects is a derived approximation. OGP conversion assumes 1nm=1852m exactly.,US National Snow and Ice Data Center,OGP,2006/09/22,,0
diff --git a/data/gcs.csv b/data/gcs.csv
index a9a254d..77ef80c 100644
--- a/data/gcs.csv
+++ b/data/gcs.csv
@@ -12,7 +12,7 @@
 4006,Unknown datum based upon the Bessel Namibia ellipsoid,6006,"Not specified (based on Bessel Namibia ellipsoid)",6006,9122,7046,8901,0,0,6422,,0,,,,,,,,
 4007,Unknown datum based upon the Clarke 1858 ellipsoid,6007,"Not specified (based on Clarke 1858 ellipsoid)",6007,9122,7007,8901,0,0,6422,,0,,,,,,,,
 4008,Unknown datum based upon the Clarke 1866 ellipsoid,6008,"Not specified (based on Clarke 1866 ellipsoid)",6008,9122,7008,8901,0,0,6422,,0,,,,,,,,
-4009,Unknown datum based upon the Clarke 1866 Michigan ellipsoid,6009,"Not specified (based on Clarke 1866 Michigan ellipsoid)",6009,9122,7009,8901,0,0,6422,,0,,,,,,,,
+4009,Unknown datum based upon the Clarke 1866 Michigan ellipsoid,6009,"Not specified (based on Clarke 1866 Michigan ellipsoid)",6009,9122,7009,8901,0,1,6422,,0,,,,,,,,
 4010,"Unknown datum based upon the Clarke 1880 (Benoit) ellipsoid",6010,"Not specified (based on Clarke 1880 (Benoit) ellipsoid)",6010,9122,7010,8901,0,0,6422,,0,,,,,,,,
 4011,"Unknown datum based upon the Clarke 1880 (IGN) ellipsoid",6011,"Not specified (based on Clarke 1880 (IGN) ellipsoid)",6011,9122,7011,8901,0,0,6422,,0,,,,,,,,
 4012,"Unknown datum based upon the Clarke 1880 (RGS) ellipsoid",6012,"Not specified (based on Clarke 1880 (RGS) ellipsoid)",6012,9122,7012,8901,0,0,6422,,0,,,,,,,,
@@ -74,7 +74,7 @@
 4140,"NAD83(CSRS98)",6140,NAD83 Canadian Spatial Reference System,6140,9108,7019,8901,1,1,6402,1473,0,9603,0,0,0,,,,
 4141,Israel,6141,Israel,6141,9122,7019,8901,1,0,6422,1073,0,9603,-48,55,52,,,,
 4142,Locodjo 1965,6142,Locodjo 1965,6142,9122,7012,8901,1,0,6422,1469,0,9603,-125,53,467,,,,
-4143,Abidjan 1987,6143,Abidjan 1987,6143,9122,7012,8901,1,0,6422,1470,0,9603,-124.76,53,466.79,,,,
+4143,Abidjan 1987,6143,Abidjan 1987,6143,9122,7012,8901,1,0,6422,1470,1,9603,-124.76,53,466.79,,,,
 4144,Kalianpur 1937,6144,Kalianpur 1937,6144,9122,7015,8901,1,0,6422,1533,1,9603,214,804,268,,,,
 4145,Kalianpur 1962,6145,Kalianpur 1962,6145,9122,7044,8901,1,0,6422,1247,1,9603,283,682,231,,,,
 4146,Kalianpur 1975,6146,Kalianpur 1975,6146,9122,7045,8901,1,0,6422,1156,0,9603,295,736,257,,,,
@@ -151,8 +151,8 @@
 4221,Campo Inchauspe,6221,Campo Inchauspe,6221,9122,7022,8901,1,0,6422,1127,1,9603,-148,136,90,,,,
 4222,Cape,6222,Cape,6222,9122,7013,8901,1,0,6422,1128,1,9603,-136,-108,-292,,,,
 4223,Carthage,6223,Carthage,6223,9122,7011,8901,1,0,6422,1130,1,9603,-263,6,431,,,,
-4224,Chua,6224,Chua,6224,9122,7022,8901,1,0,6422,1131,1,9603,-134,229,-29,,,,
-4225,Corrego Alegre 1970-72,6225,Corrego Alegre 1970-72,6225,9122,7022,8901,1,0,6422,1132,1,9603,-206,172,-6,,,,
+4224,Chua,6224,Chua,6224,9122,7022,8901,1,0,6422,3972,1,9603,-143.87,243.37,-33.52,,,,
+4225,Corrego Alegre 1970-72,6225,Corrego Alegre 1970-72,6225,9122,7022,8901,1,0,6422,6192,1,9603,-205.57,168.77,-4.12,,,,
 4226,"Cote d'Ivoire",6226,"Cote d'Ivoire",6226,9108,7011,8901,1,1,6402,,0,,,,,,,,
 4227,Deir ez Zor,6227,Deir ez Zor,6227,9122,7011,8901,1,0,6422,15742,1,9603,-190.421,8.532,238.69,,,,
 4228,Douala,6228,Douala,6228,9108,7011,8901,1,1,6402,,0,,,,,,,,
@@ -195,7 +195,7 @@
 4265,Monte Mario,6265,Monte Mario,6265,9122,7022,8901,1,0,6422,1660,1,9606,-104.1,-49.1,-9.9,0.971,-2.917,0.714,-11.68
 4266,"M'poraloko",6266,"M'poraloko",6266,9122,7011,8901,1,0,6422,1163,1,9603,-74,-130,42,,,,
 4267,NAD27,6267,North American Datum 1927,6267,9122,7008,8901,1,0,6422,,0,,,,,,,,
-4268,NAD27 Michigan,6268,NAD27 Michigan,6268,9122,7009,8901,1,0,6422,,0,,,,,,,,
+4268,NAD27 Michigan,6268,NAD27 Michigan,6268,9122,7009,8901,1,1,6422,,0,,,,,,,,
 4269,NAD83,6269,North American Datum 1983,6269,9122,7019,8901,1,0,6422,1188,1,9603,0,0,0,,,,
 4270,Nahrwan 1967,6270,Nahrwan 1967,6270,9122,7012,8901,1,0,6422,15871,1,9603,-242.2,-144.9,370.3,,,,
 4271,Naparima 1972,6271,Naparima 1972,6271,9122,7022,8901,1,0,6422,1192,1,9603,-10,375,165,,,,
@@ -223,7 +223,7 @@
 4294,Segora,6294,Segora,6294,9108,7004,8901,1,1,6402,1286,1,9603,-403,684,41,,,,
 4295,Serindung,6295,Serindung,6295,9122,7004,8901,1,0,6422,,0,,,,,,,,
 4296,Sudan,6296,Sudan,6296,9108,7011,8901,1,1,6402,,0,,,,,,,,
-4297,Tananarive,6297,Tananarive 1925,6297,9122,7022,8901,1,0,6422,1227,0,9603,-189,-242,-91,,,,
+4297,Tananarive,6297,Tananarive 1925,6297,9122,7022,8901,1,0,6422,1227,1,9603,-189,-242,-91,,,,
 4298,Timbalai 1948,6298,Timbalai 1948,6298,9122,7016,8901,1,0,6422,1228,1,9603,-679,669,-48,,,,
 4299,TM65,6299,TM65,6299,9122,7002,8901,1,0,6422,1641,1,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15
 4300,TM75,6300,Geodetic Datum of 1965,6300,9122,7002,8901,1,0,6422,1954,1,9606,482.5,-130.6,564.6,-1.042,-0.214,-0.631,8.15
@@ -251,7 +251,7 @@
 4463,RGSPM06,1038,Reseau Geodesique de Saint Pierre et Miquelon 2006,1038,9122,7019,8901,1,0,6422,4477,0,9603,0,0,0,,,,
 4470,RGM04,1036,Reseau Geodesique de Mayotte 2004,1036,9122,7019,8901,1,0,6422,4476,0,9603,0,0,0,,,,
 4475,Cadastre 1997,1037,Cadastre 1997,1037,9122,7022,8901,1,0,6422,4290,0,9603,-381.788,-57.501,-256.673,,,,
-4483,Mexican Datum of 1993,1042,Mexican Datum of 1993,1042,9122,7019,8901,1,0,6422,4832,0,9603,0,0,0,,,,
+4483,Mexico ITRF92,1042,Mexico ITRF92,1042,9122,7019,8901,1,0,6422,4832,0,9603,0,0,0,,,,
 4490,China Geodetic Coordinate System 2000,1043,China 2000,1043,9122,1024,8901,1,0,6422,,0,,,,,,,,
 4555,New Beijing,1045,New Beijing,1045,9122,7024,8901,1,0,6422,,0,,,,,,,,
 4558,RRAF 1991,1047,Reseau de Reference des Antilles Francaises 1991,1047,9122,7019,8901,1,0,6422,4560,0,9603,0,0,0,,,,
@@ -273,7 +273,7 @@
 4615,Porto Santo,6615,Porto Santo 1936,6615,9122,7022,8901,1,0,6422,1888,0,9603,-499,-249,314,,,,
 4616,Selvagem Grande,6616,Selvagem Grande,6616,9122,7022,8901,1,0,6422,1965,1,9603,-289,-124,60,,,,
 4617,"NAD83(CSRS)",6140,NAD83 Canadian Spatial Reference System,6140,9122,7019,8901,1,0,6422,1842,1,9603,0,0,0,,,,
-4618,SAD69,6618,South American Datum 1969,6618,9122,7050,8901,1,0,6422,1864,1,9603,-57,1,-41,,,,
+4618,SAD69,6618,South American Datum 1969,6618,9122,7050,8901,1,0,6422,1877,1,9603,-66.87,4.37,-38.52,,,,
 4619,SWEREF99,6619,SWEREF99,6619,9122,7019,8901,1,0,6422,1879,0,9603,0,0,0,,,,
 4620,Point 58,6620,Point 58,6620,9122,7012,8901,1,0,6422,1880,0,9603,-106,-129,165,,,,
 4621,Fort Marigot,6621,Fort Marigot,6621,9122,7022,8901,1,0,6422,1903,0,9603,137,248,-430,,,,
@@ -420,7 +420,7 @@
 4807,"NTF (Paris)",6807,"Nouvelle Triangulation Francaise (Paris)",6275,9105,7011,8903,1,0,6403,1193,0,9603,-168,-60,320,,,,
 4808,"Padang (Jakarta)",6808,"Padang 1884 (Jakarta)",6280,9122,7004,8908,1,0,6422,,0,,,,,,,,
 4809,"Belge 1950 (Brussels)",6809,"Reseau National Belge 1950 (Brussels)",6215,9122,7022,8910,1,0,6422,,0,,,,,,,,
-4810,"Tananarive (Paris)",6810,"Tananarive 1925 (Paris)",6297,9105,7022,8903,1,0,6403,1227,0,9603,-189,-242,-91,,,,
+4810,"Tananarive (Paris)",6810,"Tananarive 1925 (Paris)",6297,9105,7022,8903,1,0,6403,1227,1,9603,-189,-242,-91,,,,
 4811,"Voirol 1875 (Paris)",6811,"Voirol 1875 (Paris)",6304,9105,7011,8903,1,0,6403,1294,0,9603,-73,-247,227,,,,
 4813,"Batavia (Jakarta)",6813,"Batavia (Jakarta)",6211,9122,7004,8908,1,0,6422,1123,1,9603,-377,681,-50,,,,
 4814,"RT38 (Stockholm)",6814,"Stockholm 1938 (Stockholm)",6308,9122,7004,8911,1,0,6422,,0,,,,,,,,
@@ -442,7 +442,7 @@
 5228,"S-JTSK/05",1052,"System Jednotne Trigonometricke Site Katastralni/05",1052,9122,7004,8901,1,0,6422,5227,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378
 5229,"S-JTSK/05 (Ferro)",1055,"System Jednotne Trigonometricke Site Katastralni/05 (Ferro)",1052,9122,7004,8909,1,0,6422,5227,0,9607,572.213,85.334,461.94,-4.9732,-1.529,-5.2484,3.5378
 5233,SLD99,1053,Sri Lanka Datum 1999,1053,9122,7015,8901,1,0,6422,5236,0,9607,-0.293,766.95,87.713,-0.195704,-1.695068,-3.473016,-0.039338
-5246,GDBD2009,1056,Geocentric Datum Brunei Darussalam 2009,1056,9122,7019,8901,1,0,6422,,0,,,,,,,,
+5246,GDBD2009,1056,Geocentric Datum Brunei Darussalam 2009,1056,9122,7019,8901,1,0,6422,6701,0,9603,0,0,0,,,,
 5252,TUREF,1057,Turkish National Reference Frame,1057,9122,7019,8901,1,0,6422,5261,0,9603,0,0,0,,,,
 5264,DRUKREF 03,1058,Bhutan National Geodetic Datum,1058,9122,7019,8901,1,0,6422,5267,0,9603,0,0,0,,,,
 5324,ISN2004,1060,Islands Net 2004,1060,9122,7019,8901,1,0,6422,5327,0,9603,0,0,0,,,,
@@ -454,7 +454,7 @@
 5373,Peru96,1067,Peru96,1067,9122,7019,8901,1,0,6422,5378,0,9603,0,0,0,,,,
 5381,SIRGAS-ROU98,1068,SIRGAS-ROU98,1068,9122,7030,8901,1,0,6422,5384,0,9603,0,0,0,,,,
 5393,"SIRGAS_ES2007.8",1069,"SIRGAS_ES2007.8",1069,9122,7019,8901,1,0,6422,5395,0,9603,0,0,0,,,,
-5451,Ocotepeque 1935,1070,Ocotepeque 1935,1070,9122,7008,8901,1,0,6422,5470,1,9603,213.11,9.37,-74.95,,,,
+5451,Ocotepeque 1935,1070,Ocotepeque 1935,1070,9122,7008,8901,1,0,6422,6891,1,9603,205,96,-98,,,,
 5464,Sibun Gorge 1922,1071,Sibun Gorge 1922,1071,9122,7007,8901,1,0,6422,,0,,,,,,,,
 5467,Panama-Colon 1911,1072,Panama-Colon 1911,1072,9122,7008,8901,1,0,6422,,0,,,,,,,,
 5489,RGAF09,1073,Reseau Geodesique des Antilles Francaises 2009,1073,9122,7019,8901,1,0,6422,5501,0,9603,0,0,0,,,,
@@ -466,3 +466,11 @@
 5681,"DB_REF",1081,Deutsche Bahn Reference System,1081,9122,7004,8901,1,0,6422,,0,,,,,,,,
 5886,TGD2005,1095,Tonga Geodetic Datum 2005,1095,9122,7019,8901,1,0,6422,,0,,,,,,,,
 6135,CIGD11,1100,Cayman Islands Geodetic Datum 2011,1100,9122,7019,8901,1,0,6422,6177,0,9603,0,0,0,,,,
+6207,Nepal 1981,1111,Nepal 1981,1111,9122,7015,8901,1,0,6422,6208,0,9603,293.17,726.18,245.36,,,,
+6318,"NAD83(2011)",1116,"NAD83 (National Spatial Reference System 2011)",1116,9122,7019,8901,1,0,6422,,0,,,,,,,,
+6322,"NAD83(PA11)",1117,"NAD83 (National Spatial Reference System PA11)",1117,9122,7019,8901,1,0,6422,,0,,,,,,,,
+6325,"NAD83(MA11)",1118,"NAD83 (National Spatial Reference System MA11)",1118,9122,7019,8901,1,0,6422,,0,,,,,,,,
+6365,Mexico ITRF2008,1120,Mexico ITRF2008,1120,9122,7019,8901,1,0,6422,6373,0,9603,0,0,0,,,,
+6668,JGD2011,1128,Japanese Geodetic Datum 2011,1128,9122,7019,8901,1,0,6422,,0,,,,,,,,
+6706,RDN2008,1132,Rete Dinamica Nazionale 2008,1132,9122,7019,8901,1,0,6422,6711,0,9603,0,0,0,,,,
+6783,"NAD83(CORS96)",1133,"NAD83 (Continuously Operating Reference Station 1996)",1133,9122,7019,8901,1,0,6422,,0,,,,,,,,
diff --git a/data/gdal_datum.csv b/data/gdal_datum.csv
index 6ac5c10..6f58645 100644
--- a/data/gdal_datum.csv
+++ b/data/gdal_datum.csv
@@ -1,63 +1,63 @@
 "DATUM_CODE","DATUM_NAME","DATUM_TYPE","ORIGIN_DESCRIPTION","REALIZATION_EPOCH","ELLIPSOID_CODE","PRIME_MERIDIAN_CODE","AREA_OF_USE_CODE","DATUM_SCOPE","REMARKS","INFORMATION_SOURCE","DATA_SOURCE","REVISION_DATE","CHANGE_ID","DEPRECATED","ESRI_DATUM_NAME"
-1024,Hungarian Datum 1909,geodetic,"Fundamental point not given in information source, but presumably Szolohegy which is origin of later HD72.",1909,7004,8901,1119,Topographic mapping.,"Replaced earlier HD1863 adjustment also on Bessel ellipsoid. Both HD1863 and HD1909 were originally on Ferro Prime Meridian but subsequently converted to Greenwich. Replaced by HD72 (datum code 6237).","Timár, Molnár and Márta in Geodezia es Kartografia 55(3) pp16-21. www.fomi.hu/internet/magyar/szaklap/g [...]
-1025,Taiwan Datum 1967,geodetic,"Fundamental point: Hu Tzu Shan. Latitude: 23°58'32.34""N, longitude: 120°58'25.975""E (of Greenwich).",1967,7050,8901,3315,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Adopted in 1980. TWD67 uses the GRS 1967 ellipsoid but with 1/f to exactly 2 decimal places.","National Land Surveying and Mapping Center (NLSC), http://www.nlsc.gov.tw",OGP,"2008/08/11",,0,
-1026,Taiwan Datum 1997,geodetic,ITRF94 at epoch 1997.0,1997,7019,8901,1228,"Geodetic survey, GIS, topographic mapping, engineering survey.",Adopted in 1998.,"National Land Surveying and Mapping Center (NLSC), http://www.nlsc.gov.tw",OGP,"2008/08/11",,0,
+1024,Hungarian Datum 1909,geodetic,"Fundamental point not given in information source, but presumably Szolohegy which is origin of later HD72.",1909,7004,8901,1119,Topographic mapping.,"Replaced earlier HD1863 adjustment also on Bessel ellipsoid. Both HD1863 and HD1909 were originally on Ferro Prime Meridian but subsequently converted to Greenwich. Replaced by HD72 (datum code 6237).","Timár, Molnár and Márta in Geodezia es Kartografia 55(3) pp16-21. www.fomi.hu/internet/magyar/szaklap/g [...]
+1025,Taiwan Datum 1967,geodetic,"Fundamental point: Hu Tzu Shan. Latitude: 23°58'32.34""N, longitude: 120°58'25.975""E (of Greenwich).",1967,7050,8901,3315,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Adopted in 1980. TWD67 uses the GRS 1967 ellipsoid but with 1/f to exactly 2 decimal places.","National Land Surveying and Mapping Center (NLSC), http://www.nlsc.gov.tw",OGP,"2008/08/11",,0,"D_TWD_1967"
+1026,Taiwan Datum 1997,geodetic,ITRF94 at epoch 1997.0,1997,7019,8901,1228,"Geodetic survey, GIS, topographic mapping, engineering survey.",Adopted in 1998.,"National Land Surveying and Mapping Center (NLSC), http://www.nlsc.gov.tw",OGP,"2008/08/11",,0,"D_TWD_1997"
 1027,EGM2008 geoid,vertical,WGS 84 ellipsoid.,2008,,,1262,Geodesy.,,"http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/egm08_wgs84.html",OGP,"2009/01/30",2008.097,0,
 1028,Fao 1979,vertical,"Average sea level at Fao during two-year period in mid/late 1970s.",1979,,,3625,"Topographic mapping, geodetic survey.","Levelling network established by Polservice consortium.  Replaces Fao (datum code 5149) in Iraq.","Survey Division, Ministry of Water Resources (MoWR).",OGP,"2010/03/01",2009.003 2010.014,0,
-1029,Iraqi Geospatial Reference System,geodetic,ITRF2000 at epoch 1997.0,2000,7019,8901,1124,Geodetic survey.,,"Survey Division, Ministry of Water Resources (MoWR).",OGP,"2009/02/03",2009.003,0,
+1029,Iraqi Geospatial Reference System,geodetic,ITRF2000 at epoch 1997.0,2000,7019,8901,1124,Geodetic survey.,,"Survey Division, Ministry of Water Resources (MoWR).",OGP,"2009/02/03",2009.003,0,"D_Iraqi_Geospatial_Reference_System"
 1030,N2000,vertical,"Height at Metsaahovi (latitude 60.21762°N, longitude 24.39517°E) of 54.4233m related to EVRF2000 origin through Baltic Levelling Ring adjustment at epoch 2000.0.",2000,,,3333,"Topographic mapping, geodetic survey.","Realised through the third precise levelling network. Uses normal heights. Replaces N60 (datum code 5116). To account for isostatic land uplift use NKG2005 model.","National Land Survey of Finland;
 http://www.maanmittauslaitos.fi",OGP,"2009/02/21",2008.112,0,
-1031,MGI 1901,geodetic,"Fundamental point: Hermannskogel. Latitude: 48°16'15.29""N, longitude: 16°17'55.04""E (of Greenwich).",1901,7004,8901,2370,Geodetic survey.,"The longitude of the datum origin equates to the Albrecht 1902 value for the Ferro meridian of 17°39'46.02"" west of Greenwich. Densified in 1948.","The Ferro prime meridian, Gabor Timar (2007), Geodezia es Kartografia vol 59 issue 12 pages 3-7.",OGP,"2009/05/10",2009.015,0,
-1032,MOLDREF99,geodetic,Densification of ETRS89.,1999,7019,8901,1162,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"State Agency for Land Relations & Cadastre.",OGP,"2009/05/11",2009.026,0,"D_International_1967"
-1033,Reseau Geodesique de la RDC 2005,geodetic,ITRF2000 at epoch 2005.4.,2005,7019,8901,3613,Geodetic survey.,,"""Revision du Tiers Meridional du Reseau Geodesique de la RDC"", COPIREP Reclus project report, 2005.",OGP,"2009/04/16",2009.011,0,
-1034,Serbian Reference Network 1998,geodetic,"Densification of ETRS89 in Serbia at epoch 1998.7 based on coordinates of 6 stations in Serbia of Yugoslav Reference Frame (YUREF) 1998 campaign.",1998,7019,8901,3534,Geodesy.,Observed 1998-2003.,"Delcev et al, FIG Working Week May 2009; http://www.gig.net/pub",OGP,"2009/05/11",2009.015,0,
-1035,Red Geodesica de Canarias 1995,geodetic,ITRF93 at epoch 1994.9 at VLBI station Maspalomas on Grand Canary.,1995,7019,8901,3199,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Pico de las Nieves 1984 (PN84).","IGN Madrid. http://www.fomento.es.",OGP,"2009/05/15",2009.033,0,
-1036,Reseau Geodesique de Mayotte 2004,geodetic,ITRF2000 at epoch 2004.0,2004,7019,8901,1159,"Geodetic survey, topographic mapping, engineering survey.","Replaces Combani 1950 (datum code 6632) except for cadastral purposes. (Cadastre 1997 (datum code 1037) used for cadastral purposes).",IGN Paris.,OGP,"2009/10/02",2009.072,0,
-1037,Cadastre 1997,geodetic,Coordinates of 1 station of Combani 1950 adjustment held fixed.,1997,7022,8901,3340,Cadastral survey.,Derived by adjustment of GPS-observed network which was constrained to Combani 1950 coordinates of one station.,CERTU.,OGP,"2009/10/02",2009.072,0,
-1038,Reseau Geodesique de Saint Pierre et Miquelon 2006,geodetic,ITRF2000 at epoch 2006.0,2006,7019,8901,1220,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Saint Pierre et Miquelon 1950 (datum code 6638).",IGN Paris.,OGP,"2009/10/02",2009.072,0,
+1031,MGI 1901,geodetic,"Fundamental point: Hermannskogel. Latitude: 48°16'15.29""N, longitude: 16°17'55.04""E (of Greenwich).",1901,7004,8901,2370,Geodetic survey.,"The longitude of the datum origin equates to the Albrecht 1902 value for the Ferro meridian of 17°39'46.02"" west of Greenwich. Densified in 1948.","The Ferro prime meridian, Gabor Timar (2007), Geodezia es Kartografia vol 59 issue 12 pages 3-7.",OGP,"2009/05/10",2009.015,0,"D_MGI_1901"
+1032,MOLDREF99,geodetic,Densification of ETRS89.,1999,7019,8901,1162,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"State Agency for Land Relations & Cadastre.",OGP,"2009/05/11",2009.026,0,"D_MOLDREF99"
+1033,Reseau Geodesique de la RDC 2005,geodetic,ITRF2000 at epoch 2005.4.,2005,7019,8901,3613,Geodetic survey.,,"""Revision du Tiers Meridional du Reseau Geodesique de la RDC"", COPIREP Reclus project report, 2005.",OGP,"2009/04/16",2009.011,0,"D_Reseau_Geodesique_de_la_RDC_2005"
+1034,Serbian Reference Network 1998,geodetic,"Densification of ETRS89 in Serbia at epoch 1998.7 based on coordinates of 6 stations in Serbia of Yugoslav Reference Frame (YUREF) 1998 campaign.",1998,7019,8901,3534,Geodesy.,Observed 1998-2003.,"Delcev et al, FIG Working Week May 2009; http://www.gig.net/pub",OGP,"2009/05/11",2009.015,0,"D_Serbian_Reference_Network_1998"
+1035,Red Geodesica de Canarias 1995,geodetic,ITRF93 at epoch 1994.9 at VLBI station Maspalomas on Grand Canary.,1995,7019,8901,3199,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Pico de las Nieves 1984 (PN84).","IGN Madrid. http://www.fomento.es.",OGP,"2009/05/15",2009.033,0,"D_Red_Geodesica_de_Canarias_1995"
+1036,Reseau Geodesique de Mayotte 2004,geodetic,ITRF2000 at epoch 2004.0,2004,7019,8901,1159,"Geodetic survey, topographic mapping, engineering survey.","Replaces Combani 1950 (datum code 6632) except for cadastral purposes. (Cadastre 1997 (datum code 1037) used for cadastral purposes).",IGN Paris.,OGP,"2009/10/02",2009.072,0,"D_Reseau_Geodesique_de_Mayotte_2004"
+1037,Cadastre 1997,geodetic,Coordinates of 1 station of Combani 1950 adjustment held fixed.,1997,7022,8901,3340,Cadastral survey.,Derived by adjustment of GPS-observed network which was constrained to Combani 1950 coordinates of one station.,CERTU.,OGP,"2009/10/02",2009.072,0,"D_Cadastre_1997"
+1038,Reseau Geodesique de Saint Pierre et Miquelon 2006,geodetic,ITRF2000 at epoch 2006.0,2006,7019,8901,1220,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Saint Pierre et Miquelon 1950 (datum code 6638).",IGN Paris.,OGP,"2009/10/02",2009.072,0,"D_Reseau_Geodesique_de_St_Pierre_et_Miquelon_2006"
 1039,New Zealand Vertical Datum 2009,vertical,New Zealand Quasigeoid 2009 which is defined by the application of the NZ geoid 2009 grid to NZGD2000 ellipsoidal heights. See transformation code 4459.,2009,,,1175,"Geodetic survey, topographic mapping, engineering survey.",,"Land Information New Zealand (LINZ) standard S25004.",OGP,"2012/01/21",2009.081 2011.004 2012.007,0,
 1040,Dunedin-Bluff 1960,vertical,Common adjustment of Dunedin 1958 and Bluff 1955 networks.,1960,,,3806,"Geodetic survey, topographic mapping, engineering survey.",,"Land Information New Zealand (LINZ) standard S25004.",OGP,"2011/01/25",2009.081 2011.005,0,
-1041,Autonomous Regions of Portugal 2008,geodetic,"ITRF93 as derived from the 1994 TransAtlantic Network for Geodynamics and Oceanography (TANGO) project.",1994,7019,8901,3670,Geodetic survey.,Replaces older classical datums for Azores and Madeira archipelagos.,"Instituto Geografico Portugues; http://www.igeo.pt",OGP,"2010/03/30",2010.006,0,
-1042,Mexican Datum of 1993,geodetic,ITRF1992 at epoch 1988.00.,1993,7019,8901,1160,Geodetic survey.,"Realised by a frame of 15 active GPS stations observed and adjusted in the ITRF1992. Includes ties to tide gauges. Replaces NAD27 (code 6267).","National Densifications per http://www.sirgas.org. See also www.fig.net/pub/cairo/papers/ts_13/ts13_03_hansen.pdf.",OGP,"2010/11/02",2009.087 2010.090,0,
-1043,China 2000,geodetic,ITRF97 at epoch 2000.0,2000,1024,8901,1067,"Geodetic survey, topographic and engineering survey.",Combined adjustment of astro-geodetic observations as used for Xian 1980 and GPS control network observed 2000-2003. Adopted July 2008.,Chinese Academy of Surveying and Mapping.,OGP,"2012/01/05",2009.084 2011.103,0,
-1044,Sao Tome,geodetic,"Fundamental point: Fortaleza. Latitude: 0°20'49.02""N, longitude: 6°44'41.85""E (of Greenwich).",,7022,8901,3645,"Topographic mapping, geodetic survey.",,"US Department of State Bureau of Intelligence and Research ""Limits in the Sea"" series #98.",OGP,"2009/11/24",2009.098,0,
-1045,New Beijing,geodetic,Derived by conformal transformation of Xian 1980 adjustment onto Krassowsky ellipsoid.,1982,7024,8901,3228,Topographic mapping.,From 1982 replaces Beijing 1954.,"Chinese Science Bulletin, 2009, 54:2714-2721.",OGP,"2010/03/01",2009.092 2010.014,0,
-1046,Principe,geodetic,"Fundamental point: Morro do Papagaio. Latitude: 1°36'46.87""N, longitude: 7°23'39.65""E (of Greenwich).",,7022,8901,3646,"Topographic mapping, geodetic survey.",,"US Department of State Bureau of Intelligence and Research ""Limits in the Sea"" series #98.",OGP,"2009/11/24",2009.098,0,
-1047,Reseau de Reference des Antilles Francaises 1991,geodetic,WGS 84 coordinates of a single station determined during the 1988 Tango mission.,1991,7019,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Fort Marigot and Sainte Anne (datum codes 6621-22) in Guadeloupe and Fort Desaix (datum code 6625) in Martinique. Replaced by Reseau Geodesique des Antilles Francaises 2009 (datum code 1073).",IGN Paris.,OGP,"2011/05/09",2009.073 2011.030,0,
+1041,Autonomous Regions of Portugal 2008,geodetic,"ITRF93 as derived from the 1994 TransAtlantic Network for Geodynamics and Oceanography (TANGO) project.",1994,7019,8901,3670,Geodetic survey.,Replaces older classical datums for Azores and Madeira archipelagos.,"Instituto Geografico Portugues; http://www.igeo.pt",OGP,"2010/03/30",2010.006,0,"D_PTRA08"
+1042,Mexico ITRF92,geodetic,ITRF1992 at epoch 1988.00.,1993,7019,8901,1160,Geodetic survey.,"Realised by a frame of 15 active GPS stations observed and adjusted in the ITRF1992. Includes ties to tide gauges. Replaces NAD27 (datum code 6267). Replaced by Mexico ITRF2008 (datum code 1120) from December 2010.","National Densifications per http://www.sirgas.org. See also www.fig.net/pub/cairo/papers/ts_13/ts13_03_hansen.pdf.",OGP,"2013/08/23",2009.087 2010.090 2013.032,0,"D_Mexican_Datum_of_1993"
+1043,China 2000,geodetic,ITRF97 at epoch 2000.0,2000,1024,8901,1067,"Geodetic survey, topographic and engineering survey.",Combined adjustment of astro-geodetic observations as used for Xian 1980 and GPS control network observed 2000-2003. Adopted July 2008.,Chinese Academy of Surveying and Mapping.,OGP,"2012/01/05",2009.084 2011.103,0,"D_China_2000"
+1044,Sao Tome,geodetic,"Fundamental point: Fortaleza. Latitude: 0°20'49.02""N, longitude: 6°44'41.85""E (of Greenwich).",,7022,8901,3645,"Topographic mapping, geodetic survey.",,"US Department of State Bureau of Intelligence and Research ""Limits in the Sea"" series #98.",OGP,"2009/11/24",2009.098,0,"D_Sao_Tome"
+1045,New Beijing,geodetic,Derived by conformal transformation of Xian 1980 adjustment onto Krassowsky ellipsoid.,1982,7024,8901,3228,Topographic mapping.,From 1982 replaces Beijing 1954.,"Chinese Science Bulletin, 2009, 54:2714-2721.",OGP,"2010/03/01",2009.092 2010.014,0,"D_New_Beijing"
+1046,Principe,geodetic,"Fundamental point: Morro do Papagaio. Latitude: 1°36'46.87""N, longitude: 7°23'39.65""E (of Greenwich).",,7022,8901,3646,"Topographic mapping, geodetic survey.",,"US Department of State Bureau of Intelligence and Research ""Limits in the Sea"" series #98.",OGP,"2009/11/24",2009.098,0,"D_Principe"
+1047,Reseau de Reference des Antilles Francaises 1991,geodetic,WGS 84 coordinates of a single station determined during the 1988 Tango mission.,1991,7019,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Fort Marigot and Sainte Anne (datum codes 6621-22) in Guadeloupe and Fort Desaix (datum code 6625) in Martinique. Replaced by Reseau Geodesique des Antilles Francaises 2009 (datum code 1073).",IGN Paris.,OGP,"2011/05/09",2009.073 2011.030,0,"D_RRAF_1991"
 1048,Tokyo 1892,geodetic,"Fundamental point: Nikon-Keido-Genten. Latitude: 35°39'17.5148""N, longitude: 139°44'30.0970""E (of Greenwich). Longitude derived in 1892.",1892,7004,8901,1364,"Cadastre, topographic mapping, engineering survey.","Extended from Japan to Korea in 1898. In Japan replaced by Tokyo 1918 (datum code 6301). In South Korea replaced by Tokyo 1918 (code 6301) only for geodetic purposes; for all other purposes replaced by Korean 1985 (code 6162).",Korean Association of Su [...]
 1049,Incheon,vertical,MSL 1913-1916 at Incheon Bay.,1963,,,3739,"Topographic mapping, geodetic survey.",,"National Geographic Information Institute (NGII).",OGP,"2010/06/30",2010.050,0,
 1050,Trieste,vertical,"Reference point HM1(BV1)-Trieste defined relative to mean sea level at Trieste in 1875.",1875,,,2370,"Geodetic survey, topographic mapping, engineering survey.","Normal-orthometric heights. In Croatia replaced by HVRS71 (datum code 5207).","Eurogeographics, http://www.crs-geo.eu",OGP,"2010/07/12",2010.064,0,
 1051,Genoa,vertical,,1942,,,3736,"Geodetic survey, topographic mapping, engineering survey.",Orthometric heights.,"Eurogeographics, http://www.crs-geo.eu",OGP,"2010/07/12",2010.064,0,
-1052,"System Jednotne Trigonometricke Site Katastralni/05",geodetic,Constrained to S-JTSK but realised through readjustment in projected CRS domain. Related to ETRS89 R05 realisation through transformation code 5226.,2009,7004,8901,1079,"Geodetic survey, cadastre, topographic mapping, engineering survey.","S-JTSK = System of the Unified Trigonometrical Cadastral Network.","Land Survey Office (ZU), Prague. www.cuzk.cz/zu",OGP,"2010/10/29",2010.071,0,
-1053,Sri Lanka Datum 1999,geodetic,"Fundamental point: ISM Diyatalawa. Latitude: 6°49'02.687""N, longitude: 80°57'40.880""E.",1999,7015,8901,3310,Topographic mapping.,Introduced in 2000.,"Abeyratne, Featherstone and Tantrigoda in Survey Review vol. 42 no. 317 (July 2010).",OGP,"2010/08/07",2010.080,0,
+1052,"System Jednotne Trigonometricke Site Katastralni/05",geodetic,Constrained to S-JTSK but realised through readjustment in projected CRS domain. Related to ETRS89 R05 realisation through transformation code 5226.,2009,7004,8901,1079,"Geodetic survey, cadastre, topographic mapping, engineering survey.","S-JTSK = System of the Unified Trigonometrical Cadastral Network.","Land Survey Office (ZU), Prague. www.cuzk.cz/zu",OGP,"2010/10/29",2010.071,0,"D_S_JTSK_05"
+1053,Sri Lanka Datum 1999,geodetic,"Fundamental point: ISM Diyatalawa. Latitude: 6°49'02.687""N, longitude: 80°57'40.880""E.",1999,7015,8901,3310,Topographic mapping.,Introduced in 2000.,"Abeyratne, Featherstone and Tantrigoda in Survey Review vol. 42 no. 317 (July 2010).",OGP,"2010/08/07",2010.080,0,"D_Sri_Lanka_Datum_1999"
 1054,Sri Lanka Vertical Datum,vertical,MSL at Colombo 1884-1889.,1932,,,3310,"Geodetic survey, topographic mapping, engineering survey.","Normal-orthometric heights, but often referred to as ""orthometric"".","Abeyratne, Featherstone and Tantrigoda in Survey Review vol. 42 no. 317 (July 2010).",OGP,"2010/08/07",2010.080,0,
-1055,"System Jednotne Trigonometricke Site Katastralni/05 (Ferro)",geodetic,Constrained to S-JTSK but realised through readjustment in projected CRS domain.,2009,7004,8909,1079,"Geodetic survey, cadastre, topographic mapping, engineering survey.","S-JTSK = System of the Unified Trigonometrical Cadastral Network.","Land Survey Office (ZU), Prague. www.cuzk.cz/zu",OGP,"2010/10/29",2010.071,0,
-1056,Geocentric Datum Brunei Darussalam 2009,geodetic,ITRF2005 at epoch 2009.45,2009,7019,8901,1055,Geodetic survey.,Replaces use of Timbalai from July 2009.,"Survey Department, Brunei.",OGP,"2010/09/22",2010.057,0,
-1057,Turkish National Reference Frame,geodetic,ITRF96 at epoch 2005.0,2005,7019,8901,1237,Geodetic survey.,,"General Command of Mapping via EuroGeographics; http://www.crs-geo.eu/",OGP,"2010/09/06",2010.085,0,
-1058,Bhutan National Geodetic Datum,geodetic,ITRF2000 at epoch 2003.87,2000,7019,8901,1048,Geodetic survey.,,"Department of Survey and Land Records (DSLR), National Land Commission of Bhutan (NLC) via Lantmäteriet Sweden.",OGP,"2010/09/06",2010.086,0,
+1055,"System Jednotne Trigonometricke Site Katastralni/05 (Ferro)",geodetic,Constrained to S-JTSK but realised through readjustment in projected CRS domain.,2009,7004,8909,1079,"Geodetic survey, cadastre, topographic mapping, engineering survey.","S-JTSK = System of the Unified Trigonometrical Cadastral Network.","Land Survey Office (ZU), Prague. www.cuzk.cz/zu",OGP,"2010/10/29",2010.071,0,"D_S_JTSK_05"
+1056,Geocentric Datum Brunei Darussalam 2009,geodetic,ITRF2005 at epoch 2009.45,2009,7019,8901,1055,Geodetic survey.,Replaces use of Timbalai from July 2009.,"Survey Department, Brunei.",OGP,"2010/09/22",2010.057,0,"D_GDBD2009"
+1057,Turkish National Reference Frame,geodetic,ITRF96 at epoch 2005.0,2005,7019,8901,1237,Geodetic survey.,,"General Command of Mapping via EuroGeographics; http://www.crs-geo.eu/",OGP,"2010/09/06",2010.085,0,"D_Turkish_National_Reference_Frame"
+1058,Bhutan National Geodetic Datum,geodetic,ITRF2000 at epoch 2003.87,2000,7019,8901,1048,Geodetic survey.,,"Department of Survey and Land Records (DSLR), National Land Commission of Bhutan (NLC) via Lantmäteriet Sweden.",OGP,"2010/09/06",2010.086,0,"D_Bhutan_National_Geodetic_Datum"
 1059,Faroe Islands Vertical Reference 2009,vertical,,2009,,,3248,Topographic mapping and engineering survey,Mean Tidal Height System.,"Kort & Matrikelstyrelsen (KMS), Copenhagen.",OGP,"2010/10/27",2010.092,0,
-1060,Islands Net 2004,geodetic,ITRF2000 at epoch 2004.6.,2004,7019,8901,1120,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces ISN93 (datum code 6659).","Landmaelingar Islands (National Land Survey of Iceland). http://www.lmi.is",OGP,"2010/11/12",2010.101,0,
+1060,Islands Net 2004,geodetic,ITRF2000 at epoch 2004.6.,2004,7019,8901,1120,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces ISN93 (datum code 6659).","Landmaelingar Islands (National Land Survey of Iceland). http://www.lmi.is",OGP,"2010/11/12",2010.101,0,"D_Islands_Network_2004"
 1061,International Terrestrial Reference Frame 2008,geodetic,Origin at geocentre. The ITRF2008 origin is defined in such a way that there are null translation parameters at epoch 2005.0 and null translation rates between the ITRF2008 and the ILRS SLR time series.,2008,7019,8901,1262,Geodesy.,"Realisation of the IERS Terrestrial Reference System (ITRS) at epoch 2008.0. Replaces ITRF2005 (code 6896).","IGN Paris http://itrf.ensg.ign.fr/itrs_itrf.php",OGP,"2011/01/13",2011.002,0,
-1062,Posiciones Geodesicas Argentinas 2007,geodetic,"A geodetic network of 211 high accuracy surveyed points (178 passive and 33 continuous operating) based on ITRF2005, Epoch 2006.6, that define the National Geodetic System (Sistema Geodésico Nacional) effective 15 May 2009.",2009,7019,8901,1033,"Topographic mapping, geodetic survey.","POSGAR 07 has been adopted by order of the Director of the National Geographic Institute on May 15, 2009, as the new National Geodetic Reference Frame an [...]
-1063,Marco Geodesico Nacional,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Bolivia, consisting of 125 passive geodetic stations and 8 continuous recording GPS stations.",2007,7019,8901,1049,Geodetic survey.,"Densification of SIRGAS 1995 within Bolivia. Replaces PSAD56 (datum code 6248) in Bolivia.","Sistema de Referencia Geocentrico para las Americas (SIRGAS) Boletin Informativo No 12, Aug 2007 and www.sirgas.org/fileadmin/docs/Boletines/Bol12/09_Actividades_SI [...]
-1064,SIRGAS-Chile,geodetic,"ITRF2000 at epoch 2002.0.  Densification of SIRGAS 2000 network in Chile, consisting of 650 monumented stations.",2007,7019,8901,1066,Geodetic survey.,"Densification of SIRGAS 2000 within Chile. Replaces PSAD56 (datum code 6248) in Chile, replaces HITO XVIII (datum code 6254) in Chilean Tierra del Fuego and replaces Easter Island 1967 (datum code 6719)  in Easter Island.","IGM Chile Report: 31_Parra_Baez_Chilean_part_of_SIRGAS.pdf on sirgas.org website (www.si [...]
-1065,Costa Rica 2005,geodetic,"ITRF2000 at epoch 2005.8.  Network of 34 GPS stations throughout the country, five of which were connected to four Caribbean area ITRF stations.",2005,7030,8901,1074,Geodetic survey.,"Replaces Ocotepeque (datum code 1070) in Costa Rica from March 2007.","Instituto Geografico Nacional Costa Rica report: El Sistema de Referencia CR05 y la Proyeccion Transversal de Mercator para Costa Rica CRTM05. (Report available through www.sirgas.org website in national ne [...]
-1066,Sistema Geodesico Nacional de Panama MACARIO SOLIS,geodetic,"ITRF2000 at epoch 2000.0. Densification of SIRGAS 2000 network in Panama, consisting of 20 GPS stations throughout the country.",,7019,8901,1186,Geodetic survey.,,Details taken from summary on national networks list on www.sirgas.org website.,OGP,"2011/03/20",2011.018,0,
-1067,Peru96,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Peru, consisting of 47 passive geodetic stations and 3 continuous recording GPS stations.",1996,7019,8901,1189,Geodetic survey.,"Densification of SIRGAS 1995 within Peru. Replaces PSAD56 (datum code 6248) in Peru.","Details taken from national realizations page of WWW.SIRGAS.ORG, confirmed by reports from IGN Peru.",OGP,"2011/03/20",2011.018,0,
-1068,SIRGAS-ROU98,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Uruguay, consisting of 17 passive geodetic stations and 3 continuous recording GPS stations.",1998,7030,8901,1247,Geodetic survey.,"Densification of SIRGAS 1995 within Uruguay. Replaces Yacare (datum code 6309) in Uruguay. Uruguay documentation clearly states use of WGS 84 reference ellipsoid.","Sistema de Referencia Geocentrico para las Americas: SIRGAS, Boletin Informativo No 12, Aug 2007; www.sir [...]
-1069,"SIRGAS_ES2007.8",geodetic,"ITRF2005 at epoch 2007.8.  Densification of SIRGAS-CON network in El Salvador, consisting of 38 monumented stations.",2007,7019,8901,1087,Geodetic survey.,SIRGAS-ES2007.8 is the national SIRGAS densification.,"Integration of the reference frame of El Salvador into SIRGAS (SIRGAS-ES2007.8) report by GG-IGCN (El Salvador) & DGFI (Germany) available from www.sirgas.org.  (Information also summarised on www.sirgas.org website national networks list).",OGP,"20 [...]
-1070,Ocotepeque 1935,geodetic,"Fundamental point: Base Norte. Latitude: 14°26'20.168""N, longitude: 89°11'33.964""W.",1935,7008,8901,3876,Topographic mapping and engineering survey.,"Replaced in Costa Rica by Costa Rica 2005 (CR05) from March 2007 and replaced in El Salvador by SIRGAS_ES2007 from August 2007.","Clifford Mugnier's PE&RS articles on Belize, Costa Rica, El Salvador, Guatemala, Honduras, Nicaragua, Panama (www.asprs.org/resources/grids/) also substantiated in IGN Costa Rica  [...]
-1071,Sibun Gorge 1922,geodetic,"Latitude: 17º03'40.471""N, longitude: 88º37'54.687""W.",1922,7007,8901,3219,Topographic mapping and engineering survey.,,"Clifford Mugnier's March 2009 PE&RS ""Grids and Datums"" article on Belize (www.asprs.org/resources/grids/).",OGP,"2011/03/26",2011.026,0,
-1072,Panama-Colon 1911,geodetic,"Fundamental point: Balboa Hill. Latitude: 09°04'57.637""N, longtitude: 79°43'50.313""W.",1911,7008,8901,3290,Topographic mapping and engineering survey.,"Reports of the existence of an Ancon datum are probably erroneous, considering that the origin of the Panamá-Colón Datum of 1911 is at Balboa Hill and the access road up the hill is from the town of Ancon, Canal Zone.","Clifford Mugnier's PE&RS July 1999 Grids and Datums article on The Republic of Panama [...]
-1073,Reseau Geodesique des Antilles Francaises 2009,geodetic,ITRF2005 at epoch 2009.0,2009,7019,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.",Replaces RRAF91 in Martinique and Guadeloupe.,IGN Paris.,OGP,"2011/03/23",2011.030,0,
-1074,Corrego Alegre 1961,geodetic,"Fundamental point: Corrego Alegre. Latitude: 19°50'14.91""S, longitude: 48°57'41.98""W (of Greenwich).",1961,7022,8901,3874,"Topographic mapping, geodetic survey.","Replaced by Corrego Alegre 1970-72 (datum code 6225). NIMA gives coordinates of origin as latitude: 19°50'15.14""S, longitude: 48°57'42.75""W.",IBGE,OGP,"2011/07/10",2011.053,0,
-1075,"South American Datum 1969(96)",geodetic,"Fundamental point: Chua. Geodetic latitude: 19°45'41.6527""S; geodetic longitude: 48°06'04.0639""W (of Greenwich). (Astronomic coordinates: Latitude 19°45'41.34""S +/- 0.05"", longitude 48°06'07.80""W +/- 0.08"").",1996,7050,8901,1053,Topographic mapping.,"SAD69 uses GRS 1967 ellipsoid but with 1/f to exactly 2 decimal places. Replaces original 1969 adjustment (datum code 6618) in Brazil.",IBGE.,OGP,"2012/11/26",2011.053 2012.070,0,
-1076,Papua New Guinea Geodetic Datum 1994,geodetic,ITRF92 at epoch 1994.0.,1994,7019,8901,1187,"Topographic mapping, geodetic, engineering and cadastral survey.",Adopted 1996. Coincident with WGS 84 in 1994 but rapidly divergent due to significant tectonic motion in PNG.,"Quickclose Geomatics and http://www.aspng.org/techinfopng94.htm",OGP,"2011/07/15",2011.059,0,
-1077,Ukraine 2000,geodetic,Orientation and scale constrained to be same as ITRF2000 at epoch 2005.0. Position is minimised deviation between reference ellipsoid and quasigeoid in territory of Ukraine.,2005,7024,8901,1242,Geodesy.,,"Berlin 2008 GNSS Symposium paper 4-7 (""Creation of ZAKPOS active Network Reference Stations for Transcarpathian Region of Ukraine"") by Savchuk et al.",OGP,"2012/12/17",2011.044 2012.087,0,
-1078,Fehmarnbelt Datum 2010,geodetic,ITRF2005 at epoch 2010.14.,2010,7019,8901,3889,Engineering survey and construction of Fehmarnbelt tunnel.,Defined through coordinates of four permanant GNSS stations.,"Femern A/S.",OGP,"2011/09/23",2011.083,0,
+1062,Posiciones Geodesicas Argentinas 2007,geodetic,"A geodetic network of 211 high accuracy surveyed points (178 passive and 33 continuous operating) based on ITRF2005, Epoch 2006.6, that define the National Geodetic System (Sistema Geodésico Nacional) effective 15 May 2009.",2009,7019,8901,1033,"Topographic mapping, geodetic survey.","POSGAR 07 has been adopted by order of the Director of the National Geographic Institute on May 15, 2009, as the new National Geodetic Reference Frame an [...]
+1063,Marco Geodesico Nacional,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Bolivia, consisting of 125 passive geodetic stations and 8 continuous recording GPS stations.",2007,7019,8901,1049,Geodetic survey.,"Densification of SIRGAS 1995 within Bolivia. Replaces PSAD56 (datum code 6248) in Bolivia.","Sistema de Referencia Geocentrico para las Americas (SIRGAS) Boletin Informativo No 12, Aug 2007 and www.sirgas.org/fileadmin/docs/Boletines/Bol12/09_Actividades_SI [...]
+1064,SIRGAS-Chile,geodetic,"ITRF2000 at epoch 2002.0.  Densification of SIRGAS 2000 network in Chile, consisting of 650 monumented stations.",2007,7019,8901,1066,Geodetic survey.,"Densification of SIRGAS 2000 within Chile. Replaces PSAD56 (datum code 6248) in Chile, replaces HITO XVIII (datum code 6254) in Chilean Tierra del Fuego and replaces Easter Island 1967 (datum code 6719)  in Easter Island.","IGM Chile Report: 31_Parra_Baez_Chilean_part_of_SIRGAS.pdf on sirgas.org website (www.si [...]
+1065,Costa Rica 2005,geodetic,"ITRF2000 at epoch 2005.8.  Network of 34 GPS stations throughout the country, five of which were connected to four Caribbean area ITRF stations.",2005,7030,8901,1074,Geodetic survey.,"Replaces Ocotepeque (datum code 1070) in Costa Rica from March 2007.","Instituto Geografico Nacional Costa Rica report: El Sistema de Referencia CR05 y la Proyeccion Transversal de Mercator para Costa Rica CRTM05. (Report available through www.sirgas.org website in national ne [...]
+1066,Sistema Geodesico Nacional de Panama MACARIO SOLIS,geodetic,"ITRF2000 at epoch 2000.0. Densification of SIRGAS 2000 network in Panama, consisting of 20 GPS stations throughout the country.",,7019,8901,1186,Geodetic survey.,,Details taken from summary on national networks list on www.sirgas.org website.,OGP,"2011/03/20",2011.018,0,"D_SGNP_MARCARIO_SOLIS"
+1067,Peru96,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Peru, consisting of 47 passive geodetic stations and 3 continuous recording GPS stations.",1996,7019,8901,1189,Geodetic survey.,"Densification of SIRGAS 1995 within Peru. Replaces PSAD56 (datum code 6248) in Peru.","Details taken from national realizations page of WWW.SIRGAS.ORG, confirmed by reports from IGN Peru.",OGP,"2011/03/20",2011.018,0,"D_Peru96"
+1068,SIRGAS-ROU98,geodetic,"ITRF94 at epoch 1995.4.  Densification of SIRGAS95 network in Uruguay, consisting of 17 passive geodetic stations and 3 continuous recording GPS stations.",1998,7030,8901,1247,Geodetic survey.,"Densification of SIRGAS 1995 within Uruguay. Replaces Yacare (datum code 6309) in Uruguay. Uruguay documentation clearly states use of WGS 84 reference ellipsoid.","Sistema de Referencia Geocentrico para las Americas: SIRGAS, Boletin Informativo No 12, Aug 2007; www.sir [...]
+1069,"SIRGAS_ES2007.8",geodetic,"ITRF2005 at epoch 2007.8.  Densification of SIRGAS-CON network in El Salvador, consisting of 38 monumented stations.",2007,7019,8901,1087,Geodetic survey.,SIRGAS-ES2007.8 is the national SIRGAS densification.,"Integration of the reference frame of El Salvador into SIRGAS (SIRGAS-ES2007.8) report by GG-IGCN (El Salvador) & DGFI (Germany) available from www.sirgas.org.  (Information also summarised on www.sirgas.org website national networks list).",OGP,"20 [...]
+1070,Ocotepeque 1935,geodetic,"Fundamental point: Base Norte. Latitude: 14°26'20.168""N, longitude: 89°11'33.964""W.",1935,7008,8901,3876,Topographic mapping and engineering survey.,"Replaced in Costa Rica by Costa Rica 2005 (CR05) from March 2007 and replaced in El Salvador by SIRGAS_ES2007 from August 2007.","Clifford Mugnier's PE&RS articles on Belize, Costa Rica, El Salvador, Guatemala, Honduras, Nicaragua, Panama (www.asprs.org/resources/grids/) also substantiated in IGN Costa Rica  [...]
+1071,Sibun Gorge 1922,geodetic,"Latitude: 17º03'40.471""N, longitude: 88º37'54.687""W.",1922,7007,8901,3219,Topographic mapping and engineering survey.,,"Clifford Mugnier's March 2009 PE&RS ""Grids and Datums"" article on Belize (www.asprs.org/resources/grids/).",OGP,"2011/03/26",2011.026,0,"D_Sibun_Gorge_1922"
+1072,Panama-Colon 1911,geodetic,"Fundamental point: Balboa Hill. Latitude: 09°04'57.637""N, longtitude: 79°43'50.313""W.",1911,7008,8901,3290,Topographic mapping and engineering survey.,"Reports of the existence of an Ancon datum are probably erroneous, considering that the origin of the Panamá-Colón Datum of 1911 is at Balboa Hill and the access road up the hill is from the town of Ancon, Canal Zone.","Clifford Mugnier's PE&RS July 1999 Grids and Datums article on The Republic of Panama [...]
+1073,Reseau Geodesique des Antilles Francaises 2009,geodetic,ITRF2005 at epoch 2009.0,2009,7019,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.",Replaces RRAF91 in Martinique and Guadeloupe.,IGN Paris.,OGP,"2011/03/23",2011.030,0,"Reseau_Geodesique_des_Antilles_Francaises_2009"
+1074,Corrego Alegre 1961,geodetic,"Fundamental point: Corrego Alegre. Latitude: 19°50'14.91""S, longitude: 48°57'41.98""W (of Greenwich).",1961,7022,8901,3874,"Topographic mapping, geodetic survey.","Replaced by Corrego Alegre 1970-72 (datum code 6225). NIMA gives coordinates of origin as latitude: 19°50'15.14""S, longitude: 48°57'42.75""W.",IBGE,OGP,"2011/07/10",2011.053,0,"D_Corrego_Alegre_1961"
+1075,"South American Datum 1969(96)",geodetic,"Fundamental point: Chua. Geodetic latitude: 19°45'41.6527""S; geodetic longitude: 48°06'04.0639""W (of Greenwich). (Astronomic coordinates: Latitude 19°45'41.34""S +/- 0.05"", longitude 48°06'07.80""W +/- 0.08"").",1996,7050,8901,1053,Topographic mapping.,"SAD69 uses GRS 1967 ellipsoid but with 1/f to exactly 2 decimal places. Replaces original 1969 adjustment (datum code 6618) in Brazil.",IBGE.,OGP,"2012/11/26",2011.053 2012.070,0,"D_South_ [...]
+1076,Papua New Guinea Geodetic Datum 1994,geodetic,ITRF92 at epoch 1994.0.,1994,7019,8901,1187,"Topographic mapping, geodetic, engineering and cadastral survey.",Adopted 1996. Coincident with WGS 84 in 1994 but rapidly divergent due to significant tectonic motion in PNG.,"Quickclose Geomatics and http://www.aspng.org/techinfopng94.htm",OGP,"2011/07/15",2011.059,0,"D_Papua_New_Guinea_Geodetic_Datum_1994"
+1077,Ukraine 2000,geodetic,Orientation and scale constrained to be same as ITRF2000 at epoch 2005.0. Position is minimised deviation between reference ellipsoid and quasigeoid in territory of Ukraine.,2005,7024,8901,1242,Geodesy.,,"Berlin 2008 GNSS Symposium paper 4-7 (""Creation of ZAKPOS active Network Reference Stations for Transcarpathian Region of Ukraine"") by Savchuk et al.",OGP,"2012/12/17",2011.044 2012.087,0,"D_Ukraine_2000"
+1078,Fehmarnbelt Datum 2010,geodetic,ITRF2005 at epoch 2010.14.,2010,7019,8901,3889,Engineering survey and construction of Fehmarnbelt tunnel.,Defined through coordinates of four permanant GNSS stations.,"Femern A/S.",OGP,"2011/09/23",2011.083,0,"D_Fehmarnbelt_Datum_2010"
 1079,Fehmarnbelt Vertical Reference 2010,vertical,"Realised by precise levelling between tide gauges at Marienleuchte (Germany), Rodbyhavn (Denmark) and four Fehmarnbelt project GNSS stations.",2010,,,3890,Engineering survey and construction of Fehmarnbelt tunnel.,,"Femern A/S",OGP,"2011/09/24",2011.083,0,
 1080,Lowest Astronomic Tide,vertical,The lowest tide level which can be predicted to occur under average meterological conditions and under any combination of astronomical conditions.,,,,1262,Hydrography and Nautical Charting.,"Users are advised to not use this generic vertical datum but to define explicit realisations of LAT by specifying location and epoch, for instance ""LAT at xxx during yyyy-yyyy"".","IHO Dictionary, S-32, 5th Edition, 2936.",OGP,"2012/08/10",2011.047,0,
-1081,Deutsche Bahn Reference System,geodetic,"Defined by transformation from ETRS89 (transformation code 5826) to be an average of DHDN across all states of Germany.",,7004,8901,3339,Engineering survey for railway applications.,,"Deutsche Bahn AG via Geo++, www.geopp.de",OGP,"2012/03/25",2011.101 2012.034,0,
+1081,Deutsche Bahn Reference System,geodetic,"Defined by transformation from ETRS89 (transformation code 5826) to be an average of DHDN across all states of Germany.",,7004,8901,3339,Engineering survey for railway applications.,,"Deutsche Bahn AG via Geo++, www.geopp.de",OGP,"2012/03/25",2011.101 2012.034,0,"D_Deutsche_Bahn_Reference_System"
 1082,Highest Astronomic Tide,vertical,The highest tide level which can be predicted to occur under average meterological conditions and under any combination of astronomical conditions.,,,,1262,Hydrography and Nautical Charting.,"Users are advised to not use this generic vertical datum but to define explicit realisations of HAT by specifying location and epoch, for instance ""HAT at xxx during yyyy-yyyy"".","IHO Dictionary, S-32, 5th Edition, 2244.",OGP,"2012/08/10",2011.047,0,
 1083,Lower Low Water Large Tide,vertical,"The average of the lowest low waters, one from each of 19 years of observations.",,,,1262,Hydrography and Nautical Charting.,"Users are advised to not use this generic vertical datum but to define explicit realisations of LLWLT by specifying location and epoch, for instance ""LLWLT at xxx during yyyy-yyyy"".",UK Hydrographic Office.,OGP,"2012/08/10",2011.047,0,
 1084,Higher High Water Large Tide,vertical,"The average of the highest high waters, one from each of 19 years of observations.",,,,1262,Hydrography and Nautical Charting.,"Users are advised to not use this generic vertical datum but to define explicit realisations of HHWLT by specifying location and epoch, for instance ""HHWLT at xxx during yyyy-yyyy"".",UK Hydrographic Office.,OGP,"2012/08/10",2011.047,0,
@@ -87,10 +87,29 @@ http://www.maanmittauslaitos.fi",OGP,"2009/02/21",2008.112,0,
 1108,Santa Cruz das Flores,vertical,Mean Sea Level during 1965 at Santa Cruz das Flores.,1965,,,1344,"Geodetic survey, topographic mapping, engineering survey.",Orthometric heights.,"General Directorate of Land, http://www.dgterritorio.pt/",OGP,"2013/04/10",2013.010,0,
 1109,Cais da Vila do Porto,vertical,"Mean Sea Level during 1965 at Cais da Vila, Porto.",1965,,,4126,"Geodetic survey, topographic mapping, engineering survey.",Orthometric heights.,"General Directorate of Land, http://www.dgterritorio.pt/",OGP,"2013/04/10",2013.010,0,
 1110,Ponta Delgada,vertical,Mean Sea Level during 1991 at Ponta Delgada.,1991,,,2871,"Geodetic survey, topographic mapping, engineering survey.",Orthometric heights.,"General Directorate of Land, http://www.dgterritorio.pt/",OGP,"2013/04/10",2013.010,0,
+1111,Nepal 1981,geodetic,"Fundamental point: Station 12/157 Nagarkot. Latitude: 27°41'31.04""N, longitude: 85°31'20.23""E (of Greenwich).",1981,7015,8901,1171,"Geodetic survey, topographic mapping.",,Nepal Survey Department www.dos.gov.np and Nepalese Journal on Geoinformatics June 2011.,OGP,"2013/06/26",2013.018,0,
+1116,"NAD83 (National Spatial Reference System 2011)",geodetic,"Coordinates of a nationwide adjustment of 79,546 NGS ""passive"" control stations in CONUS and Alaska, constrained to 1,171 current CORS station coordinates at epoch 2010.0.",2012,7019,8901,1511,Geodetic survey.,"Replaces NAD83(NSRS2007). ITRF2008 is understood to underlay the latest CORS station coordinates.","U.S. National Geodetic Survey, http://www.ngs.noaa.gov/",OGP,"2013/06/07",2013.022,0,
+1117,"NAD83 (National Spatial Reference System PA11)",geodetic,"Coordinates of a nationwide adjustment including 345 NGS ""passive"" control stations constrained to 24 current Pacific CORS station coordinates at epoch 2010.0.",2012,7019,8901,4162,Geodetic survey.,"Replaces NAD83(HARN) in American Samoa and Hawaii. ITRF2008 is understood to underlay the latest CORS station coordinates.","U.S. National Geodetic Survey, http://www.ngs.noaa.gov/",OGP,"2013/06/07",2013.022,0,
+1118,"NAD83 (National Spatial Reference System MA11)",geodetic,"Coordinates of a nationwide adjustment including 171 NGS ""passive"" control stations constrained to 24 current Pacific CORS station coordinates at epoch 2010.0.",2012,7019,8901,4167,Geodetic survey.,"Replaces NAD83(HARN) (GGN93) code 6152 in Guam. ITRF2008 is understood to underlay the latest CORS station coordinates.","U.S. National Geodetic Survey, http://www.ngs.noaa.gov/",OGP,"2013/06/08",2013.022,0,
+1119,Northern Marianas Vertical Datum of 2003,vertical,"Mean sea level at Tanapag harbor, Saipan. Benchmark 1633227 TIDAL UH-2C = 1.657m relative to National Tidal Datum Epoch 1983-2001. Transferred to Rota (East Harbor, BM TIDAL 3 = 1.482m) and Tinian (Harbor BM TIDAL 1 = 2.361m).",2003,,,4171,"Topographic mapping, geodetic survey.",Replaces all earlier vertical datums on these islands.,"National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/18",2013.044,0,
+1120,Mexico ITRF2008,geodetic,ITRF2008 at epoch 2010.00.,2010,7019,8901,1160,Geodetic survey.,"Realised by a frame of 15 active GPS stations observed and adjusted in the ITRF2008. Includes ties to tide gauges. Replaces Mexico ITRF92 (datum code 1042).","INEGI, http://www.inegi.org.mx",OGP,"2013/08/04",2013.032,0,
+1121,Tutuila Vertical Datum of 1962,vertical,"Mean sea level at Pago Pago harbor, Tutuila, over 10 years 1949-1955 and 1957-1959. Benchmark NO 2 1948 = 7.67ftUS.",1962,,,2288,"Topographic mapping, geodetic survey.","Replaced by American Samoa Vertical Datum of 2002 (datum code 1125).","National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/25",2013.044,0,
+1122,Guam Vertical Datum of 1963,vertical,"Mean sea level at Apra harbor, Guam, 1949-1962. Benchmark NO 5 1949 = 0.599m.",1963,,,3255,"Topographic mapping, geodetic survey.","Replaced by Guam vertical datum of 2004 (datum code 1126).","National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/25",2013.044,0,
+1123,Puerto Rico Vertical Datum of 2002,vertical,"Mean sea level at San Juan. Benchmark 9756371 A TIDAL = 1.334m relative to National Tidal Datum Epoch 1960-1978.",2002,,,3294,"Topographic mapping, geodetic survey.",Replaces all earlier vertical datums for Puerto Rico.,"National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/26",2013.044,0,
+1124,Virgin Islands Vertical Datum of 2009,vertical,"Mean sea level for National Tidal Datum Epoch 1983–2001 at (i) Lime Tree Bay, St. Croix (BM 9751401 M = 3.111m) , (ii) Lameshur Bay, St. John (BM 9751381 TIDAL A = 1.077m) , and (iii) Charlotte Amalie, St. Thomas (BM 9751639 F = 1.552m).",2009,,,3330,"Topographic mapping, geodetic survey.",Replaces all earlier vertical datums on these islands.,"National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/25",2013.044,0,
+1125,American Samoa Vertical Datum of 2002,vertical,"Mean sea level at Pago Pago harbor, Tutuila. Benchmark 1770000 S TIDAL = 1.364m relative to National Tidal Datum Epoch 1983-2001.",2002,,,2288,"Topographic mapping, geodetic survey.","Replaces Tutuila vertical datum of 1962 (datum code 1121).","National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/25",2013.044,0,
+1126,Guam Vertical Datum of 2004,vertical,"Mean sea level at Apra harbor, Guam. Benchmark 1630000 TIDAL 4 = 2.170m relative to US National Tidal Datum Epoch 1983-2001. MSL is 0.419m above MLLW and the BM is 2.589m above MLLW.",2004,,,3255,"Topographic mapping, geodetic survey.","Replaces Guam Vertical Datum of 1963 (datum code 1122).","National Geodetic Survey; http://www.ngs.noaa.gov",OGP,"2013/10/25",2013.044,0,
+1127,Canadian Geodetic Vertical Datum of 2013,vertical,"Defined by the equipotential surface W0 = 62,636,856.0 m^2s^-2, which by convention represents the coastal mean sea level for North America.",2013,,,1061,"Topographic mapping, geodetic survey.","Replaces CGVD28 (datum code 5114) from November 2013.","Geodetic Survey Division, Natural Resources Canada.",OGP,"2013/12/13",2013.064,0,
+1128,Japanese Geodetic Datum 2011,geodetic,"ITRF94 at epoch 1997.0 except for northern Honshu area impacted by 2011 Tohoku earthquake which is ITRF2008 at epoch 2011.395. Fundamental point: Tokyo-Taisho, latitude: 35°39'29.1572""N, longitude: 139°44'28.8869""E (of Greenwich).",2011,7019,8901,1129,"Geodetic survey, topographic and engineering survey.","Instigated under amendment to the Japanese Surveying Law with effect from 21st October 2011. Replaces JGD2000 (datum code 6612).","Geodeti [...]
+1129,Japanese Standard Levelling Datum 1972,vertical,Mean sea level Oshoro 1963-72.,1972,,,4168,"Topographic mapping, geodetic survey.","Normal-orthometric heights. Replaced by JGD2000 (vertical) (datum code 1130) with effect from April 2002.","Geospatial Information Authority of Japan (GSI) bulletin volume 51 of March 2004.",OGP,"2013/12/16",2013.063,0,
+1130,"Japanese Geodetic Datum 2000 (vertical)",vertical,24.4140 metres above mean sea level Tokyo Bay.,2002,,,3263,"Topographic mapping, geodetic survey.","Orthometric heights. Replaces JSLD69 and JSLD72 with effect from April 2002. Replaced by JGD2011 (vertical) (datum code 1131) with effect from 21st October 2011.","Geospatial Information Authority of Japan (GSI) bulletin volume 51 of March 2004.",OGP,"2013/12/15",2013.063,0,
+1131,"Japanese Geodetic Datum 2011 (vertical)",vertical,24.3900 metres above mean sea level Tokyo Bay.,2011,,,3263,"Topographic mapping, geodetic survey.","Orthometric heights. Replaces JGD2000 (vertical) (datum code 1130) with effect from 21st October 2011.","Geodetic Department, Geospatial Information Authority of Japan (GSI).",OGP,"2013/12/15",2013.063,0,
+1132,Rete Dinamica Nazionale 2008,geodetic,"Italian densification of ETRS89 realised through network of 99 permanent reference stations in ETRF2000 at 2008.0.",2008,7019,8901,3343,"Geodetic survey, topographic mapping.","Adopted as official Italian reference datum 10/11/2011. Replaces IGM95 (datum code 6670).",IGM Italy,OGP,"2014/01/21",2014.002,0,
+1134,Christmas Island Datum 1985,engineering,"WGS 72 / UTM zone 48S coordinates 570000mE, 8840000mN; local grid orientated parallel to UTM grid at this point.",1985,,,4169,"GIS, topographic survey, cadastre, engineering survey.",Replaced by GDA94 geodetic datum.,"Landgate (Government of Western Australia), Christmas Island Geographic Information System documentation, www.ga.gov.au/christmas.",OGP,"2014/02/08",2014.005,0,
 5100,Mean Sea Level,vertical,"The average height of the surface of the sea at a tide station for all stages of the tide over a 19-year period, usually determined from hourly height readings measured from a fixed predetermined reference level.",,,,1262,Hydrography.,"Approximates geoid. Users are advised to not use this generic vertical datum but to define explicit realisations of MSL by specifying location and epoch, for instance ""MSL at xxx during yyyy-yyyy"".","IHO Dictionary, S-32, 5t [...]
 5101,Ordnance Datum Newlyn,vertical,Mean Sea Level at Newlyn between 1915 and 1921.,,,,2792,"Topographic mapping, geodetic survey.",Orthometric heights.,Ordnance Survey of Great Britain,OGP,"2004/06/16",2004.100,0,"D_Ordnance_Datum_Newlyn"
 5102,National Geodetic Vertical Datum 1929,vertical,26 tide gauges in the US and Canada.,1929,,,1323,"Topographic mapping, geodetic survey.",Normal orthometric heights.,,OGP,"1996/09/12",,0,
-5103,North American Vertical Datum 1988,vertical,"Mean water level 1970-1988 at Pointe-au-Pierre (Father's Point) and Rimouski, Quebec. Benchmark 1250-G = 6.273m.",1988,,,3664,"Topographic mapping, geodetic survey.",Helmert orthometric heights.,,OGP,"2012/08/10",2005.880 2009.108 2011.047,0,
+5103,North American Vertical Datum 1988,vertical,"Mean water level 1970-1988 at Pointe-au-Pierre (Father's Point) and Rimouski, Quebec. Benchmark 1250-G = 6.273m.",1988,,,4161,"Topographic mapping, geodetic survey.",Helmert orthometric heights.,,OGP,"2013/09/02",2005.880 2009.108 2011.047 2013.028,0,
 5104,Yellow Sea 1956,vertical,2 years tide readings at Qingdao.,1956,,,3228,"Topographic mapping, geodetic survey.",Replaced by Yellow Sea 1985 datum.,,OGP,"2002/06/22",2002.160,0,
 5105,Baltic Sea,vertical,"Datum: average water level at Kronstadt 1833. Network adjusted in 1977.",1977,,,1284,"Topographic mapping, geodetic survey.",Uses Normal heights.,,OGP,"2005/05/27",2004.100 2005.180,0,
 5106,Caspian Sea,vertical,Defined as -28.0m Baltic datum,,,,1291,Hydrography.,,,OGP,"1996/09/12",,0,
@@ -100,7 +119,7 @@ http://www.maanmittauslaitos.fi",OGP,"2009/02/21",2008.112,0,
 5111,Australian Height Datum,vertical,MSL 1966-68 at 30 gauges around coast.,1968,,,1281,"Topographic mapping, geodetic survey.",,Australian Land Information Group  www.auslig.gov.au,OGP,"2005/09/06",2005.460,0,
 5112,"Australian Height Datum (Tasmania)",vertical,MSL 1972 at Hobart and Burnie.,1972,,,2947,"Topographic mapping, geodetic survey.",,,OGP,"2012/01/21",2012.007,0,
 5113,Instantaneous Water Level,vertical,Instantaneous water level uncorrected for tide.,,,,1262,Hydrography.,Not specific to any location or epoch.,OGP,OGP,"2012/08/10",2011.047,0,
-5114,Canadian Geodetic Vertical Datum of 1928,vertical,Based on the mean sea level determined from several tidal gauges located in strategic areas of the country,1928,,,1289,"Topographic mapping, geodetic survey.",,"Geodetic Survey Division, Natural Resources Canada. http://maps.nrcan.gc.ca/asdb/asdb_datum.html and http://www.geod.nrcan.gc.ca/index_e/help_e/acron_e.html",OGP,"2004/11/26",2004.723,0,
+5114,Canadian Geodetic Vertical Datum of 1928,vertical,Based on the mean sea level determined from several tidal gauges located in strategic areas of the country.,1928,,,1289,"Topographic mapping, geodetic survey.","From November 2013 replaced by CGVD2013 (datum code 1127).","Geodetic Survey Division, Natural Resources Canada. http://maps.nrcan.gc.ca/asdb/asdb_datum.html and http://www.geod.nrcan.gc.ca/index_e/help_e/acron_e.html",OGP,"2014/01/27",2004.723 2013.064,0,
 5115,Piraeus Harbour 1986,vertical,MSL determined during 1986.,1986,,,3254,"Topographic mapping, geodetic survey.",,"Geodesy Department; Public Pertoleum Corporation of Greece",OGP,"1997/06/16",,0,
 5116,Helsinki 1960,vertical,MSL at Helsinki during 1960.,1960,,,3333,"Topographic mapping, geodetic survey.","Uses orthometric heights. Replaced by N2000 (datum code 1030).","National Land Survey of Finland;
 http://www.maanmittauslaitos.fi",OGP,"2010/05/02",2008.112,0,
@@ -109,7 +128,7 @@ http://www.maanmittauslaitos.fi",OGP,"2010/05/02",2008.112,0,
 5119,Nivellement General de la France - IGN69,vertical,"Rivet number M.ac O-VIII on the Marseille tide gauge site, with the height fixed in 1897 at 1.661 metre above mean sea level between February 2nd 1885 and January 1st 1897.",1969,,,1326,"Geodetic survey, topographic mapping, engineering survey.",Uses Normal heights.,"Conseil National de l'Information Geographique groupe de travail ""Reseaux de Nivellement"" recommendations v5.1 April 1994.",OGP,"2012/01/21",2001.470 2012.010,0,
 5120,Nivellement General de la France - IGN78,vertical,Marker MM3 situated on the tide gauge site of Ajaccio. Height is 3.640 metre above mean sea level.,1978,,,1327,"Geodetic survey, topographic mapping, engineering survey.","Uses Normal heights. Replaces NGC (datum code 5189).","Conseil National de l'Information Geographique groupe de travail ""Reseaux de Nivellement"" recommendations v5.1 April 1994.",OGP,"2012/01/21",2001.470 2004.060 2004.564 2012.010,0,
 5121,Maputo,vertical,Mean sea level at Maputo.,,,,3281,Topographic mapping.,,"Direcção Nacional de Geografia e Cadastral (DINAGECA).",OGP,"1998/04/16",,0,
-5122,Japanese Standard Levelling Datum 1949,vertical,24.4140 metres above mean sea level Tokyo Bay.,1949,,,3263,"Topographic mapping, geodetic survey.",,"Ministry of Construction; Japan.  http://vldb.gsi.go.jp/sokuchi/datum/tokyodatum.html",OGP,"2004/05/09",2002.080 2004.380,0,
+5122,Japanese Standard Levelling Datum 1969,vertical,24.4140 metres above mean sea level Tokyo Bay.,1969,,,4166,"Topographic mapping, geodetic survey.","Normal-orthometric heights. Replaces JSLD49. Replaced by JGD2000 (vertical) (datum code 1130) from April 2002.","Geospatial Information Authority of Japan (GSI) bulletin volume 51 of March 2004.",OGP,"2014/05/01",2002.080 2004.380 2013.063,0,
 5123,PDO Height Datum 1993,vertical,,1993,,,3288,Oil industry mapping.,"Misclosure between Muscat and Salalah less than .5 meters with differences from of up to 5 meters from old Fahud Datum.  The PHD93 adjustment was initially known as the Spine.  Replaces Fahud Vertical Datum (code 5124) from 1993.",Petroleum Development Oman,OGP,"1999/04/22",,0,
 5124,Fahud Height Datum,vertical,Single MSL determination at Mina Al Fahal.,,,,4009,Oil industry mapping.,"Based on reciprocal trigonometric heighting. Replaced by PHD93 Datum (code 5123) in 1993.",Petroleum Development Oman,OGP,"2012/02/13",2004.212 2011.042,0,
 5125,Ha Tien 1960,vertical,,1960,,,1302,"Topographic mapping, geodetic survey.",In Vietnam replaced by Hon Dau in 1992.,,OGP,"1999/10/20",,0,
@@ -211,13 +230,13 @@ http://www.maanmittauslaitos.fi",OGP,"2010/05/02",2008.112,0,
 6006,"Not specified (based on Bessel Namibia ellipsoid)",geodetic,,,7046,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2001/01/21",1996.080 2000.420 2001.150,0,"D_Bessel_Namibia"
 6007,"Not specified (based on Clarke 1858 ellipsoid)",geodetic,,,7007,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1858"
 6008,"Not specified (based on Clarke 1866 ellipsoid)",geodetic,,,7008,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1866"
-6009,"Not specified (based on Clarke 1866 Michigan ellipsoid)",geodetic,,,7009,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1866_Michigan"
+6009,"Not specified (based on Clarke 1866 Michigan ellipsoid)",geodetic,,,7009,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420 2013.020,1,"D_Clarke_1866_Michigan"
 6010,"Not specified (based on Clarke 1880 (Benoit) ellipsoid)",geodetic,,,7010,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1880_Benoit"
 6011,"Not specified (based on Clarke 1880 (IGN) ellipsoid)",geodetic,,,7011,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1880_IGN"
 6012,"Not specified (based on Clarke 1880 (RGS) ellipsoid)",geodetic,,,7012,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1880_RGS"
 6013,"Not specified (based on Clarke 1880 (Arc) ellipsoid)",geodetic,,,7013,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1880_Arc"
 6014,"Not specified (based on Clarke 1880 (SGA 1922) ellipsoid)",geodetic,,,7014,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Clarke_1880_SGA"
-6015,"Not specified (based on Everest 1830 (1937 Adjustment) ellipsoid)",geodetic,,,7015,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,
+6015,"Not specified (based on Everest 1830 (1937 Adjustment) ellipsoid)",geodetic,,,7015,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Everest_Adj_1937"
 6016,"Not specified (based on Everest 1830 (1967 Definition) ellipsoid)",geodetic,,,7016,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Everest_Def_1967"
 6018,"Not specified (based on Everest 1830 Modified ellipsoid)",geodetic,,,7018,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_Everest_Modified"
 6019,"Not specified (based on GRS 1980 ellipsoid)",geodetic,,,7019,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",1996.080 2000.420,0,"D_GRS_1980"
@@ -241,10 +260,10 @@ http://www.maanmittauslaitos.fi",OGP,"2010/05/02",2008.112,0,
 6043,"Not specified (based on WGS 72 ellipsoid)",geodetic,,,7043,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",2000.420,0,
 6044,"Not specified (based on Everest 1830 (1962 Definition) ellipsoid)",geodetic,,,7044,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",2000.420,0,"D_Everest_Def_1962"
 6045,"Not specified (based on Everest 1830 (1975 Definition) ellipsoid)",geodetic,,,7045,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2000/05/03",2000.420,0,"D_Everest_Def_1975"
-6047,"Not specified (based on GRS 1980 Authalic Sphere)",geodetic,,,7048,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2004/04/27",2001.190 2003.330,0,
+6047,"Not specified (based on GRS 1980 Authalic Sphere)",geodetic,,,7048,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2004/04/27",2001.190 2003.330,0,"D_Sphere_GRS_1980_Authalic"
 6052,"Not specified (based on Clarke 1866 Authalic Sphere)",geodetic,,,7052,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2004/04/27",,0,"D_Sphere_Clarke_1866_Authalic"
-6053,"Not specified (based on International 1924 Authalic Sphere)",geodetic,,,7057,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2006/09/22",,0,
-6054,"Not specified (based on Hughes 1980 ellipsoid)",geodetic,,,7058,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2006/09/22",,0,
+6053,"Not specified (based on International 1924 Authalic Sphere)",geodetic,,,7057,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2006/09/22",,0,"D_Sphere_International_1924_Authalic"
+6054,"Not specified (based on Hughes 1980 ellipsoid)",geodetic,,,7058,8901,1263,Not a valid datum.,Included for coordinate reference systems where datum is unknown.,OGP,OGP,"2006/09/22",,0,"D_Hughes_1980"
 6055,Popular Visualisation Datum,geodetic,Not specified in the classical sense of defining a geodetic datum.,,7059,8901,1262,Used by certain popular Web mapping and visualisation applications.,Not recognised by geodetic authorities.,Microsoft.,OGP,"2008/03/13",2008.114,1,
 6120,Greek,geodetic,"Fundamental point: Athens Observatory. Latitude 37°58'20.132""N, longitude 23°42'58.815""E (of Greenwich)",,7004,8901,3254,Topographic mapping.,"See geodetic datum alias 6404.  Used as basis of topographic mapping based on Hatt projection. Replaced by GGRS87 (code 6121).","Topography Department; National Technical University of Athens",OGP,"2011/07/20",2004.183 2008.045 2011.062,0,"D_Greek"
 6121,Greek Geodetic Reference System 1987,geodetic,"Fundamental point: Dionysos. Latitude 38°04'33.8""N, longitude 23°55'51.0""E of Greenwich; geoid height 7.0 m.",1987,7019,8901,3254,Topographic mapping.,"Replaced (old) Greek datum.  Oil industry work based on ED50.","L. Portokalakis; Public Petroleum Corporation of Greece",OGP,"2011/07/20",2008.045 2011.062,0,"D_GGRS_1987"
@@ -267,7 +286,7 @@ http://www.maanmittauslaitos.fi",OGP,"2011/06/30",2006.270 2011.055,0,"D_KKJ"
 6137,St. Paul Island,geodetic,"Fundamental point latitude: 57°07'16.86""N, longitude: 170°16'24.00""W (of Greenwich).",,7008,8901,1333,Topographic mapping.,"Many Alaskan islands were never on NAD27 but rather on independent datums.  NADCON conversion program provides transformation from St. Paul Island Datum to NAD83 (original 1986 realization) - making the transformation appear to user as if from NAD27.","http://www.ngs.noaa.gov/ (NADCON readme file)",OGP,"2008/06/24",2008.045,0,"D_St_P [...]
 6138,St. George Island,geodetic,"Fundamental point latitude: 56°36'11.31""N, longitude: 169°32'36.00""W (of Greenwich).",,7008,8901,1331,Topographic mapping.,"Many Alaskan islands were never on NAD27 but rather on independent datums.  NADCON conversion program provides transformation from St. George Island Datum to NAD83 (original 1986 realization) - making the transformation appear to user as if from NAD27.","http://www.ngs.noaa.gov/ (NADCON readme file)",OGP,"2008/06/24",2003.362 2008. [...]
 6139,Puerto Rico,geodetic,"Fundamental point: Cardona Island Lighthouse. Latitude:17°57'31.40""N, longitude: 66°38'07.53""W (of Greenwich).",1901,7008,8901,1335,Topographic mapping.,"NADCON conversion program provides transformation from Puerto Rico Datum to NAD83 (original 1986 realization) but making the transformation appear to user as if from NAD27.","Ordnance Survey of Great Britain and http://www.ngs.noaa.gov/ (NADCON readme file).",OGP,"2008/06/24",2003.362 2008.045,0,"D_Puerto_Rico"
-6140,NAD83 Canadian Spatial Reference System,geodetic,,1998,7019,8901,1061,Geodetic survey.,,"Natural Resources of Canada, CSRS website.  http://www.geod.nrcan.gc.ca",OGP,"2007/09/25",2005.880 2006.461 2007.026 2007.092,0,"D_North_American_1983_CSRS98"
+6140,NAD83 Canadian Spatial Reference System,geodetic,,1998,7019,8901,1061,Geodetic survey.,,"Natural Resources of Canada, CSRS website.  http://www.geod.nrcan.gc.ca",OGP,"2007/09/25",2005.880 2006.461 2007.026 2007.092,0,"D_North_American_1983_CSRS"
 6141,Israel,geodetic,"Fundamental point:  Latitude: 31°44'03.817""N, longitude: 35°12'16.261""E (of Greenwich).",,7019,8901,2603,Topographic mapping.,,Survey of Israel.,OGP,"2008/06/24",2002.340 2004.150 2008.045,0,"D_Israel"
 6142,Locodjo 1965,geodetic,"Fundamental point: T5 Banco. Latitude: 5°18'50.5""N, longitude: 4°02'05.1""W (of Greenwich).",1965,7012,8901,1075,Topographic mapping.,,IGN Paris.,OGP,"2008/06/24",2008.045,0,"D_Locodjo_1965"
 6143,Abidjan 1987,geodetic,"Fundamental point: Abidjan I. Latitude: 5°18'51.01""N, longitude: 4°02'06.04""W (of Greenwich).",1987,7012,8901,1075,Topographic mapping.,,IGN Paris.,OGP,"2008/06/24",2008.045,0,"D_Abidjan_1987"
@@ -279,7 +298,7 @@ http://www.maanmittauslaitos.fi",OGP,"2011/06/30",2006.270 2011.055,0,"D_KKJ"
 6149,CH1903,geodetic,"Fundamental point: Old Bern observatory. Latitude: 46°57'08.660""N, longitude: 7°26'22.500""E (of Greenwich).",1903,7004,8901,1286,Topographic mapping.,,"Bundesamt für Landestopographie",OGP,"2008/06/24",2008.045,0,"D_CH1903"
 6150,"CH1903+",geodetic,"Fundamental point: Zimmerwald observatory.",,7004,8901,1286,"Geodetic survey, topographic mapping.",,"Bundesamt für Landestopographie.  Aufbau der Landesvermessung der Schweiz 'LV95' Teil 3: Terrestrische Bezugssysteme und Bezugsrahmen. L+T 1999.",OGP,"2001/11/06",2001.520,0,"D_CH1903+"
 6151,Swiss Terrestrial Reference Frame 1995,geodetic,ETRF89 at epoch 1993.0,1995,7019,8901,1286,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Bundesamt für Landestopographie.  Aufbau der Landesvermessung der Schweiz 'LV95' Teil 3: Terrestrische Bezugssysteme und Bezugsrahmen. L+T 1999.",OGP,"2006/08/18",2006.770,0,"D_Swiss_TRF_1995"
-6152,"NAD83 (High Accuracy Reference Network)",geodetic,,,7019,8901,1337,Geodetic survey.,,National Geodetic Survey,OGP,"2011/02/04",2009.044 2010.061 2011.009,0,"D_North_American_1983_HARN"
+6152,"NAD83 (High Accuracy Reference Network)",geodetic,,,7019,8901,1337,Geodetic survey.,"In CONUS, Puerto Rico and US Virgin Islands replaced by NAD83(NSRS2007). In American Samoa and Hawaii replaced by NAD83(PA11). In Guam replaced by NAD83(MA11).",National Geodetic Survey,OGP,"2013/06/12",2009.044 2010.061 2011.009 2013.022,0,"D_North_American_1983_HARN"
 6153,Rassadiran,geodetic,"Fundamental point: Total1. Latitude: 27°31'07.784""N, longitude: 52°36'12.741""E (of Greenwich).",1998,7022,8901,1338,Oil industry mapping.,,Total-Fina,OGP,"2008/06/24",2008.045,0,"D_Rassadiran"
 6154,"European Datum 1950(1977)",geodetic,Extension of ED50 over Iran.,1977,7022,8901,1123,Topographic mapping.,Sometimes referred to as ED50-ED77.,National Cartographic Centre of Iran,OGP,"1999/11/20",,0,"D_European_1950_ED77"
 6155,Dabola 1981,geodetic,,1981,7011,8901,3257,Topographic mapping.,,IGN Paris,OGP,"1999/12/09",,0,"D_Dabola_1981"
@@ -357,7 +376,7 @@ en el terreno que definen el Sistema Geodésico Nacional.  [A geodetic network o
 6230,European Datum 1950,geodetic,"Fundamental point: Potsdam (Helmert Tower). Latitude: 52°22'51.4456""N, longitude: 13°03'58.9283""E (of Greenwich).",1950,7022,8901,1296,"Topographic mapping, geodetic survey.",,"EuroGeographics; http://crs.bkg.bund.de/crs-eu/",OGP,"2008/06/24",2003.361 2008.045,0,"D_European_1950"
 6231,European Datum 1987,geodetic,"Fundamental point: Potsdam (Helmert Tower). Latitude: 52°22'51.4456""N, longitude: 13°03'58.9283""E (of Greenwich).",1987,7022,8901,1297,Scientific network.,,,OGP,"2008/06/24",2003.362 2008.045,0,"D_European_1987"
 6232,Fahud,geodetic,"Fundamental point: Station NO68-024 Fahud. Latitude: 22°17'31.182""N, longitude: 56°29'18.820""E (of Greenwich).",,7012,8901,4009,Oil industry mapping.,"Replaced by PSD93 (code 6134).",Petroleum Development Oman.,OGP,"2012/02/13",2008.045 2011.042,0,"D_Fahud"
-6233,Gandajika 1970,geodetic,,1970,7022,8901,1152,Topographic mapping.,,,OGP,"1995/06/02",,1,"D_Gandajika_1970"
+6233,Gandajika 1970,geodetic,,1970,7022,8901,1152,Topographic mapping.,,,OGP,"1995/06/02",,1,
 6234,Garoua,geodetic,,,7011,8901,1060,Topographic mapping.,"The intent of the Bukavu 1953 conference was to adopt the Clarke 1880 (RGS) ellipsoid (code 7012) but in practice this datum has used the IGN version.",,OGP,"1995/06/02",,1,"D_Garoua"
 6235,Guyane Francaise,geodetic,,,7022,8901,1097,Topographic mapping.,,,OGP,"1995/06/02",,1,"D_Guyane_Francaise"
 6236,Hu Tzu Shan 1950,geodetic,"Fundamental point: Hu Tzu Shan. Latitude: 23°58'32.34""N, longitude: 120°58'25.975""E (of Greenwich).",1950,7022,8901,3315,Topographic mapping.,,"NIMA 
@@ -389,11 +408,11 @@ US NGA, http://earth-info.nga.mil/GandG/index.html",OGP,"2008/08/12",2003.362 20
 6261,Merchich,geodetic,"Fundamental point: Merchich. Latitude: 33°26'59.672""N, longitude: 7°33'27.295""W (of Greenwich).",1922,7011,8901,3280,Topographic mapping.,,,OGP,"2008/06/24",2003.361 2008.045,0,"D_Merchich"
 6262,Massawa,geodetic,,,7004,8901,1089,Topographic mapping.,,,OGP,"1995/06/02",,0,"D_Massawa"
 6263,Minna,geodetic,"Fundamental point: Minna base station L40. Latitude: 9°38'08.87""N, longitude: 6°30'58.76""E (of Greenwich).",,7012,8901,1178,Topographic mapping.,,"NIMA http://earth-info.nima.mil/",OGP,"2008/06/24",2003.361 2005.460 2008.045,0,"D_Minna"
-6264,Mhast,geodetic,,,7022,8901,1318,Coastal hydrography.,,,OGP,"1995/06/02",,1,"D_Mhast"
+6264,Mhast,geodetic,,,7022,8901,1318,Coastal hydrography.,,,OGP,"1995/06/02",,1,
 6265,Monte Mario,geodetic,"Fundamental point: Monte Mario. Latitude: 41°55'25.51""N, longitude: 12°27'08.4""E (of Greenwich).",1940,7022,8901,3343,Topographic mapping.,"Replaced Genova datum, Bessel 1841 ellipsoid, from 1940.",,OGP,"2008/06/24",2003.360 2008.045,0,"D_Monte_Mario"
 6266,"M'poraloko",geodetic,,,7011,8901,1100,Topographic mapping.,,,OGP,"1995/06/02",,0,"D_Mporaloko"
 6267,North American Datum 1927,geodetic,"Fundamental point: Meade's Ranch. Latitude: 39°13'26.686""N, longitude: 98°32'30.506""W (of Greenwich).",1927,7008,8901,1349,Topographic mapping.,"In United States (USA) and Canada, replaced by North American Datum 1983 (NAD83) (code 6269) ; in Mexico, replaced by Mexican Datum of 1993 (code 1042).",,OGP,"2009/11/24",2008.024 2008.045 2009.087,0,"D_North_American_1927"
-6268,NAD27 Michigan,geodetic,"Fundamental point: Meade's Ranch. Latitude: 39°13'26.686""N, longitude: 98°32'30.506""W (of Greenwich).",,7009,8901,1391,Topographic mapping.,Ellipsoid taken to be 800ft above the NAD27 reference ellipsoid.,"USGS Professional Paper #1395.",OGP,"2011/02/25",2008.045 2011.013,0,"D_North_American_Michigan"
+6268,NAD27 Michigan,geodetic,"Fundamental point: Meade's Ranch. Latitude: 39°13'26.686""N, longitude: 98°32'30.506""W (of Greenwich).",,7009,8901,1391,Topographic mapping.,Ellipsoid taken to be 800ft above the NAD27 reference ellipsoid.,"USGS Professional Paper #1395.",OGP,"2011/02/25",2008.045 2011.013 2013.020,1,
 6269,North American Datum 1983,geodetic,Origin at geocentre.,1986,7019,8901,1350,Topographic mapping.,"Although the 1986 adjustment included connections to Greenland and Mexico, it has not been adopted there. In Canada and US, replaced NAD27.",,OGP,"2008/04/11",2006.464 2008.024,0,"D_North_American_1983"
 6270,Nahrwan 1967,geodetic,"Fundamental point: Nahrwan south base.  Latitude: 33°19'10.87""N, longitude: 44°43'25.54""E (of Greenwich).",1967,7012,8901,1351,Topographic mapping.,"In Iraq, replaces Nahrwan 1934.",,OGP,"2008/06/24",2006.340 2008.045,0,"D_Nahrwan_1967"
 6271,Naparima 1972,geodetic,"Fundamental point: Naparima. Latitude: 10°16'44.860""N, longitude: 61°27'34.620""W (of Greenwich).",1972,7022,8901,1322,Topographic mapping.,Naparima 1972 is an extension of the Naparima 1955 network of Trinidad to include Tobago.,Ordnance Survey International.,OGP,"2008/06/24",2008.045,0,"D_Naparima_1972"
@@ -408,14 +427,14 @@ US NGA, http://earth-info.nga.mil/GandG/index.html",OGP,"2008/08/12",2003.362 20
 6280,Padang 1884,geodetic,"Fundamental point: Padang.",1884,7004,8901,1355,Topographic mapping.,,,OGP,"1995/06/02",,0,"D_Padang_1884"
 6281,Palestine 1923,geodetic,"Fundamental point: Point 82'M  Jerusalem. Latitude: 31°44' 2.749""N, longitude: 35°12'43.490""E (of Greenwich).",1923,7010,8901,1356,Topographic mapping.,,,OGP,"2008/06/24",2004.150 2008.045,0,"D_Palestine_1923"
 6282,Congo 1960 Pointe Noire,geodetic,"Fundamental point: Point Noire Astro. Latitude: 4°47'00.10""S, longitude: 11°51'01.55""E (of Greenwich).",1960,7011,8901,1072,Topographic mapping.,,Elf,OGP,"2008/06/24",2002.050 2003.361 2008.045,0,"D_Pointe_Noire"
-6283,Geocentric Datum of Australia 1994,geodetic,ITRF92 at epoch 1994.0.,1994,7019,8901,1036,"Topographic mapping, geodetic survey.",Coincident with WGS84 to within 1 metre.,"Australian Surveying and Land Information Group Internet WWW page. http://www.auslig.gov.au/geodesy/datums/gda.htm#specs",OGP,"2011/01/25",2011.004,0,"D_GDA_1994"
+6283,Geocentric Datum of Australia 1994,geodetic,ITRF92 at epoch 1994.0.,1994,7019,8901,4177,"Topographic mapping, geodetic survey.",Coincident with WGS84 to within 1 metre.,"Australian Surveying and Land Information Group Internet WWW page. http://www.auslig.gov.au/geodesy/datums/gda.htm#specs",OGP,"2014/02/15",2011.004 2014.005,0,"D_GDA_1994"
 6284,Pulkovo 1942,geodetic,"Fundamental point: Pulkovo observatory. Latitude: 59°46'18.550""N, longitude: 30°19'42.090""E (of Greenwich).",1942,7024,8901,2423,Topographic mapping.,,,OGP,"2008/09/24",2008.011 2008.045,0,"D_Pulkovo_1942"
 6285,Qatar 1974,geodetic,"Fundamental point: Station G3.",1974,7022,8901,1346,Topographic mapping.,,,OGP,"2001/08/28",2001.270,0,"D_Qatar"
 6286,Qatar 1948,geodetic,"Fundamental point: Sokey 0 M. Latitude: 25°22'56.500""N, longitude: 50°45'41.000""E (of Greenwich).",1948,7020,8901,1346,Topographic mapping.,,,OGP,"2008/06/24",2008.045,0,"D_Qatar_1948"
-6287,Qornoq,geodetic,,1927,7022,8901,1107,Topographic mapping.,,,OGP,"1995/06/02",,1,"D_Qornoq"
+6287,Qornoq,geodetic,,1927,7022,8901,1107,Topographic mapping.,,,OGP,"1995/06/02",,1,
 6288,Loma Quintana,geodetic,"Fundamental point: Loma Quintana.",,7022,8901,1313,Topographic mapping.,"Replaced by La Canoa (code 6247).",,OGP,"1995/06/02",,0,"D_Loma_Quintana"
 6289,Amersfoort,geodetic,"Fundamental point: Amersfoort. Latitude: 52°09'22.178""N, longitude: 5°23'15.478""E (of Greenwich).",,7004,8901,1275,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"http://www.rdnap.nl/",OGP,"2008/06/24",2000.560 2003.361 2005.460 2008.045,0,"D_Amersfoort"
-6291,South American Datum 1969,geodetic,,1969,7036,8901,1358,Topographic mapping.,"SAD69 uses GRS67 ellipsoid with 1/f to exactly 2 decimal places.  Precision of ellipsoid entry increased from 2 to 5 dp with change id 97.252.  Error introduced if not using the truncated precision is 0 to 31mm.",,OGP,"1996/10/18",1996.090 1997.252,1,"D_South_American_1969"
+6291,South American Datum 1969,geodetic,,1969,7036,8901,1358,Topographic mapping.,"SAD69 uses GRS67 ellipsoid with 1/f to exactly 2 decimal places.  Precision of ellipsoid entry increased from 2 to 5 dp with change id 97.252.  Error introduced if not using the truncated precision is 0 to 31mm.",,OGP,"1996/10/18",1996.090 1997.252,1,
 6292,Sapper Hill 1943,geodetic,,1943,7022,8901,3247,Topographic mapping.,,,OGP,"1995/06/02",,0,"D_Sapper_Hill_1943"
 6293,Schwarzeck,geodetic,"Fundamental point: Schwarzeck. Latitude: 22°45'35.820""S, longitude: 18°40'34.549""E (of Greenwich). Fixed during German South West Africa-British Bechuanaland boundary survey of 1898-1903.",,7046,8901,1169,Topographic mapping.,,"Private Communication, Directorate of Surveys and Land Information, Cape Town.",OGP,"2008/06/24",2001.150 2003.362 2008.045,0,"D_Schwarzeck"
 6294,Segora,geodetic,,,7004,8901,1359,Topographic mapping.,,,OGP,"1995/06/02",,1,"D_Segora"
@@ -446,8 +465,8 @@ Trinidad 1903 / Trinidad Grid coordinates (Clarke's links): 333604.30 E, 436366.
 6319,Kuwait Utility,geodetic,,,7019,8901,1310,"Cadastre, engineering survey.",,,OGP,"1996/04/12",,0,"D_Kuwait_Utility"
 6322,World Geodetic System 1972,geodetic,Developed from a worldwide distribution of terrestrial and geodetic satellite observations and defined through a set of station coordinates.,1972,7043,8901,1262,Satellite navigation.,Used by GPS before 1987. For Transit satellite positioning see also WGS 72BE.,"NIMA http://earth-info.nima.mil/",OGP,"2006/08/24",1999.030 2003.362 2005.460 2006.820,0,"D_WGS_1972"
 6324,WGS 72 Transit Broadcast Ephemeris,geodetic,,1972,7043,8901,1262,Satellite navigation.,Alleged datum for use with Transit broadcast ephemeris prior to 1989. Relationship to WGS 72 has changed over time.,,OGP,"2006/08/24",1999.030 2006.820,0,"D_WGS_1972_BE"
-6326,World Geodetic System 1984,geodetic,"Defined through a consistent set of station coordinates. These have changed with time: by 0.7m on 29/6/1994 [WGS 84 (G730)], a further 0.2m on 29/1/1997 [WGS 84 (G873)] and a further 0.06m on 20/1/2002 [WGS 84 (G1150)].",1984,7030,8901,1262,Satellite navigation.,"EPSG's WGS 84 datum has been the then current realisation. No distinction is made between the original WGS 84 frame, WGS 84 (G730), WGS 84 (G873) and WGS 84 (G1150). Since 1997, WGS 84 h [...]
-http://gis-lab.info/docs/nima-tr8350.2-addendum.pdf",OGP,"2006/08/25",2002.151 2002.890 2003.270 2005.460 2005.550 2006.810,0,"D_WGS_1984"
+6326,World Geodetic System 1984,geodetic,"Defined through a consistent set of station coordinates. These have changed with time: by 0.7m on 29/06/1994 (G730), a further 0.2m on 29/01/1997 (G873) and a further 0.06m on 20/01/2002 (G1150) and on 8/02/2012 (G1674).",1984,7030,8901,1262,Satellite navigation.,"EPSG::6326 has been the then current realisation. No distinction is made between the original and subsequent (G730, G873, G1150 and G1674) WGS 84 frames. Since 1997, WGS 84 has been mai [...]
+http://gis-lab.info/docs/nima-tr8350.2-addendum.pdf",OGP,"2013/06/15",2002.151 2002.890 2003.270 2005.460 2005.550 2006.810 2012.097,0,
 6600,Anguilla 1957,geodetic,"Fundamental point: station A4, Police.",1957,7012,8901,3214,Topographic mapping.,,Ordnance Survey of Great Britain.,OGP,"1999/04/22",,0,"D_Anguilla_1957"
 6601,Antigua 1943,geodetic,"Fundamental point: station A14.",1943,7012,8901,1273,Topographic mapping.,,Ordnance Survey of Great Britain.,OGP,"1999/04/22",,0,"D_Antigua_1943"
 6602,Dominica 1945,geodetic,"Fundamental point: station M12.",1945,7012,8901,3239,Topographic mapping.,,Ordnance Survey of Great Britain.,OGP,"1999/04/22",,0,"D_Dominica_1945"
@@ -460,11 +479,11 @@ http://gis-lab.info/docs/nima-tr8350.2-addendum.pdf",OGP,"2006/08/25",2002.151 2
 6609,"North American Datum 1927 (CGQ77)",geodetic,"Fundamental point: Meade's Ranch. Latitude: 39°13'26.686""N, longitude: 98°32'30.506""W (of Greenwich).",1977,7008,8901,1368,"Geodetic survey, cadastre, topographic mapping, engineering survey.","NAD27 (CGQ77) used in Quebec for all maps at scale 1/20 000 and larger; generally for maps issued by the Quebec cartography office whose reference system is CGQ77.","Geodetic Service of Quebec.  Contact alain.bernard at mrn.gouv.qc.ca",OGP,"2008/06 [...]
 6610,Xian 1980,geodetic,Xian observatory.,1980,7049,8901,3228,"Geodetic survey, topographic and engineering survey.",,"Chinese Science Bulletin, 2009, 54:2714-2721.",OGP,"2009/11/24",2009.084,0,"D_Xian_1980"
 6611,Hong Kong 1980,geodetic,"Fundamental point: Trig ""Zero"", 38.4 feet south along the transit circle of the Kowloon Observatory. Latitude 22°18'12.82"", longitude 114°10'18.75""E (of Greenwich).",1980,7022,8901,1118,"Geodetic survey, topgraphic and engineering survey, cadastre.","Replaces Hong Kong 1963 and Hong Kong 1963(67).","Survey and Mapping Office, Lands Department. http://www.info.gov.hk/landsd/mapping/tindex.htm",OGP,"2008/06/24",2005.260 2008.045,0,"D_Hong_Kong_1980"
-6612,Japanese Geodetic Datum 2000,geodetic,ITRF94 at epoch 1997.0,2000,7019,8901,1129,"Geodetic survey, topographic and engineering survey.","Instigated under amendment to the Japanese Surveying Law with effect from April 2002. Replaces Tokyo datum (code 6301).","Japanese Survey Federation and Geographical Survey Institute http://www.gsi.go.jp/ENGLISH/RESEARCH/BULLETIN/vol-45/45abst1.htm",OGP,"2002/06/22",,0,"D_JGD_2000"
+6612,Japanese Geodetic Datum 2000,geodetic,"ITRF94 at epoch 1997.0. Fundamental point: Tokyo-Taisho, latitude: 35°39'29.1572""N, longitude: 139°44'28.8759""E (of Greenwich).",2000,7019,8901,1129,"Geodetic survey, topographic and engineering survey.","Instigated under amendment to the Japanese Surveying Law with effect from April 2002. Replaces Tokyo datum (code 6301). Replaced by JGD2011 (datum code 1128) with effect from 21st October 2011.","Japanese Survey Federation and Geographical S [...]
 6613,Gunung Segara,geodetic,"Station P5 (Gunung Segara). Latitude 0°32'12.83""S, longitude 117°08'48.47""E (of Greenwich).",,7004,8901,1360,Topographic mapping.,,TotalFinaElf.,OGP,"2008/06/24",2008.045,0,"D_Gunung_Segara"
 6614,Qatar National Datum 1995,geodetic,Defined by transformation from WGS 84 - see coordinate operation code 1840.,1995,7022,8901,1346,Topographic mapping.,,Qatar Centre for Geographic Information.,OGP,"2002/06/28",,0,"D_QND_1995"
 6615,Porto Santo 1936,geodetic,SE Base on Porto Santo island.,1936,7022,8901,1314,Topographic mapping.,"Replaced by 1995 adjustment (datum code 6663). For Selvagens see Selvagem Grande (code 6616).","Instituto Geografico e Cadastral Lisbon http://www.igeo.pt",OGP,"2003/08/14",2003.231 2003.232,0,"D_Porto_Santo_1936"
-6616,Selvagem Grande,geodetic,,,7022,8901,2779,Topographic mapping.,,"Instituto Geografico e Cadastral Lisbon http://www.igeo.pt",OGP,"2003/08/14",2003.232,0,
+6616,Selvagem Grande,geodetic,,,7022,8901,2779,Topographic mapping.,,"Instituto Geografico e Cadastral Lisbon http://www.igeo.pt",OGP,"2003/08/14",2003.232,0,"D_Selvagem_Grande_1938"
 6618,South American Datum 1969,geodetic,"Fundamental point: Chua. Geodetic latitude: 19°45'41.6527""S; geodetic longitude: 48°06'04.0639""W (of Greenwich). (Astronomic coordinates: Latitude 19°45'41.34""S +/- 0.05"", longitude 48°06'07.80""W +/- 0.08"").",1969,7050,8901,1358,Topographic mapping.,"SAD69 uses GRS 1967 ellipsoid but with 1/f to exactly 2 decimal places. In Brazil only, replaced by SAD69(96) (datum code 1075).",DMA 1974.,OGP,"2011/07/27",2003.362 2008.045 2011.053,0,"D_South [...]
 6619,SWEREF99,geodetic,Densification of ETRS89.,1999,7019,8901,1225,"Geodetic survey, cadastre, topographic mapping, engineering survey.","The solution was calculated in ITRF 97 epoch 1999.5, and has subsequently been corrected to ETRS 89 in accordance with guidelines given by EUREF.","National Land Survey of Sweden http://www.lantmateriet.se",OGP,"2010/03/01",2009.024,0,"D_SWEREF99"
 6620,Point 58,geodetic,"Fundamental point: Point 58. Latitude: 12°52'44.045""N, longitude: 3°58'37.040""E (of Greenwich).",1969,7012,8901,2790,Geodetic survey,Used as the basis for computation of the 12th Parallel traverse conducted 1966-70 from Senegal to Chad and connecting to the Adindan triangulation in Sudan.,IGN Paris.,OGP,"2012/01/05",2008.045 2011.090,0,"D_Point_58"
@@ -472,22 +491,22 @@ http://gis-lab.info/docs/nima-tr8350.2-addendum.pdf",OGP,"2006/08/25",2002.151 2
 6622,Guadeloupe 1948,geodetic,,1948,7022,8901,2829,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RRAF 1991 (datum code 1047).",IGN Paris.,OGP,"2009/11/24",2004.561 2009.073,0,"D_Sainte_Anne"
 6623,Centre Spatial Guyanais 1967,geodetic,"Fundamental point: Kourou-Diane. Latitude: 5°15'53.699""N, longitude: 52°48'09.149""W (of Greenwich).",1967,7022,8901,3105,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGFG95 (code 6624).",IGN Paris.,OGP,"2008/06/24",2004.562 2008.045,0,"D_CSG_1967"
 6624,Reseau Geodesique Francais Guyane 1995,geodetic,ITRF93 at epoch 1995.0,1995,7019,8901,1097,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces CSG67 (datum code 6623).",IGN Paris.,OGP,"2002/11/29",,0,"D_RGFG_1995"
-6625,Martinique 1938,geodetic,"Fundamental point: Fort Desaix. Latitude: 14°36'54.090""N, longitude: 61°04'04.030""W (of Greenwich).",1938,7022,8901,3276,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RRAF 1991 (datum code 1047).",IGN Paris.,OGP,"2009/11/24",2004.561 2008.045 2009.073,0,"D_Fort_Desaix"
+6625,Martinique 1938,geodetic,"Fundamental point: Fort Desaix. Latitude: 14°36'54.090""N, longitude: 61°04'04.030""W (of Greenwich).",1938,7022,8901,3276,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RRAF 1991 (datum code 1047).",IGN Paris.,OGP,"2009/11/24",2004.561 2008.045 2009.073,0,"D_Fort_Desaix"
 6626,Reunion 1947,geodetic,"Fundamental point: Piton des Neiges (Borne). Latitude: 21°05'13.119""S, longitude: 55°29'09.193""E (of Greenwich).",1947,7022,8901,3337,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGR92 (datum code 6627).",IGN Paris.,OGP,"2008/06/24",2004.561 2008.045,0,"D_Reunion_1947"
 6627,Reseau Geodesique de la Reunion 1992,geodetic,ITRF91 at epoch 1993.0,1992,7019,8901,3902,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Piton des Neiges (code 6626).",IGN Paris.,OGP,"2012/01/05",2006.770 2011.109,0,"D_RGR_1992"
 6628,Tahiti 52,geodetic,"Fundamental point: Tahiti North Base. Latitude: 17°38'10.0""S, longitude: 149°36'57.8""W (of Greenwich).",1952,7022,8901,2811,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by Tahiti 79 (datum code 6690) in Tahiti and Moorea 87 (code 6691) in Moorea.","Gouvernement de la Polynésie Française, Service  de l'Urbanisme, Section topographie.",OGP,"2008/06/24",2005.380 2008.045,0,"D_Tahiti_1952"
 6629,Tahaa 54,geodetic,"Fundamental point: Tahaa East Base. Latitude: 16°33'20.97""S, longitude: 151°29'06.25""W (of Greenwich).",1954,7022,8901,2812,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGPF (datum code 6687).","Gouvernement de la Polynésie Française, Service  de l'Urbanisme, Section topographie.",OGP,"2008/06/24",2005.380 2008.045,0,"D_Tahaa_1954"
 6630,IGN72 Nuku Hiva,geodetic,"Fundamental point: Taiohae. Latitude: 8°55'03.97""S, longitude: 140°05'36.24""W (of Greenwich).",1972,7022,8901,3129,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGPF (datum code 6687).","Gouvernement de la Polynésie Française, Service  de l'Urbanisme, Section topographie.",OGP,"2008/06/24",2005.380 2008.045,0,"D_IGN72_Nuku_Hiva"
-6631,K0 1949,geodetic,,1949,7022,8901,2816,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,IGN Paris.,OGP,"2002/11/29",,1,"D_K0_1949"
+6631,K0 1949,geodetic,,1949,7022,8901,2816,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,IGN Paris.,OGP,"2002/11/29",,1,
 6632,Combani 1950,geodetic,Combani South Base.,1950,7022,8901,3340,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGM04 and Cadastre 1997 (datum codes 1036-37).",IGN Paris.,OGP,"2009/10/29",2009.072,0,"D_Combani_1950"
 6633,IGN56 Lifou,geodetic,South end of the Goume base.,1956,7022,8901,2814,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",2006.620,0,"D_IGN56_Lifou"
 6634,IGN72 Grande Terre,geodetic,North end of Gomen base.,1972,7022,8901,2822,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",2006.620,0,"D_IGN72_Grande_Terre"
-6635,ST87 Ouvea,geodetic,,1987,7022,8901,2813,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,Service Topographique de la Nouvelle Caledonie.,OGP,"2002/11/29",,1,"D_ST87_Ouvea"
+6635,ST87 Ouvea,geodetic,,1987,7022,8901,2813,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,Service Topographique de la Nouvelle Caledonie.,OGP,"2002/11/29",,1,
 6636,Petrels 1972,geodetic,"Fundamental point: Astro station DZ on Ile de Petrels. Latitude: 66°40'00""S, longitude: 140°00'46""E (of Greenwich).",1972,7022,8901,2817,"Geodetic survey,  topographic mapping.",,IGN Paris.,OGP,"2008/06/24",2008.045,0,"D_Petrels_1972"
 6637,Pointe Geologie Perroud 1950,geodetic,"Fundamental point: Astro station G.0 on Pointe Geologie. Latitude: 66°39'30""S, longitude: 140°01'00""E (of Greenwich).",1950,7022,8901,2818,"Geodetic survey,  topographic mapping.",,IGN Paris.,OGP,"2008/06/24",2008.045,0,"D_Pointe_Geologie_Perroud_1950"
 6638,Saint Pierre et Miquelon 1950,geodetic,,1950,7008,8901,3299,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by RGSPM06 (datum code 1038).",IGN Paris.,OGP,"2011/01/25",2006.060 2009.072 2011.004,0,"D_Saint_Pierre_et_Miquelon_1950"
 6639,MOP78,geodetic,,1978,7022,8901,2815,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,IGN Paris.,OGP,"2002/11/29",,0,"D_MOP78"
-6640,Reseau de Reference des Antilles Francaises 1991,geodetic,WGS 84 coordinates of a single station determined during the 1988 Tango mission.,1991,7030,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Fort Marigot and Sainte Anne (datum codes 6621-22) in Guadeloupe and Fort Desaix (datum code 6625) in Martinique.",IGN Paris.,OGP,"2004/03/26",2004.200 2009.073,1,"D_RRAF_1991"
+6640,Reseau de Reference des Antilles Francaises 1991,geodetic,WGS 84 coordinates of a single station determined during the 1988 Tango mission.,1991,7030,8901,2824,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Fort Marigot and Sainte Anne (datum codes 6621-22) in Guadeloupe and Fort Desaix (datum code 6625) in Martinique.",IGN Paris.,OGP,"2004/03/26",2004.200 2009.073,1,
 6641,IGN53 Mare,geodetic,South-east end of the La Roche base.,1953,7022,8901,2819,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",2006.620,0,"D_IGN53_Mare"
 6642,ST84 Ile des Pins,geodetic,"Fundamental point: Pic Nga.",1984,7022,8901,2820,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",2006.620,0,"D_ST84_Ile_des_Pins"
 6643,ST71 Belep,geodetic,,1971,7022,8901,2821,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,Service Topographique de la Nouvelle Caledonie.,OGP,"2002/11/29",,0,"D_ST71_Belep"
@@ -516,7 +535,7 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6666,Lisbon 1890,geodetic,"Fundamental point: Castelo Sao Jorge, Lisbon. Latitude: 38°42'43.631""N, longitude: 9°07'54.862""W of Greenwich.",1937,7004,8901,1294,Topographic mapping.,"Replaced by Lisbon 1937 adjustment (which uses International 1924 ellipsoid).","Instituto Geografico e Cadastral Lisbon http://www.igeo.pt",OGP,"2008/06/24",2003.361 2008.045,0,"D_Lisbon_1890"
 6667,Iraq-Kuwait Boundary Datum 1992,geodetic,Four stations established between September and December 1991 determined by GPS and Doppler observations.,1992,7030,8901,2876,International boundary demarcation,,"United Nations Iraq-Kuwait Boundary Demarcation Commission, Final Report, May 1993.",OGP,"2003/09/01",,0,"D_Iraq_Kuwait_Boundary_1992"
 6668,European Datum 1979,geodetic,"Fundamental point: Potsdam (Helmert Tower). Latitude: 52°22'51.4456""N, longitude: 13°03'58.9283""E (of Greenwich).",1979,7022,8901,1297,Scientific network.,Replaced by 1987 adjustment.,,OGP,"2008/06/24",2008.045,0,"D_European_1979"
-6670,Istituto Geografico Militaire 1995,geodetic,Network of 1296 points observed 1992-1995 and adjusted in 1996 constrained to 9 ETRS89 points. Densification of ETRS89 in Italy.,1995,7030,8901,3343,Geodetic survey and scientific study.,,ENI,OGP,"2011/01/25",2011.004,0,"D_IGM_1995"
+6670,Istituto Geografico Militaire 1995,geodetic,Network of 1296 points observed 1992-1995 and adjusted in 1996 constrained to 9 ETRS89 points. Densification of ETRS89 in Italy.,1995,7030,8901,3343,Geodetic survey and scientific study.,"Replaced by RDN2008 (datum code 1132) from 2011-11-10.",ENI,OGP,"2014/01/27",2011.004 2014.002,0,"D_IGM_1995"
 6671,Voirol 1879,geodetic,"Fundamental point: Voirol. Latitude: 36°45'08.199""N, longitude: 3°02'49.435""E (of Greenwich). Uses RGS (and old IGN) value of 2°20'13.95""for Greenwich-Paris meridian difference.",1879,7011,8901,1365,Topographic mapping.,"Replaces Voirol 1875 (code 6304).",IGN Paris,OGP,"2008/06/24",2008.045,0,"D_Voirol_1879"
 6672,Chatham Islands Datum 1971,geodetic,,1971,7022,8901,2889,"Geodetic survey, topographic mapping, engineering survey.","Replaced by Chatham Islands Datum 1979 (code 6673).","Office of Surveyor General (OSG) Technical Report 14, June 2001.",OGP,"2004/02/17",,0,"D_Chatham_Island_1971"
 6673,Chatham Islands Datum 1979,geodetic,"Fundamental point: station Astro. Latitude: 43°57'23.60""S, longitude: 176°34'28.65""W (of Greenwich).",1979,7022,8901,2889,"Geodetic survey, topographic mapping, engineering survey.","Replaces Chatham Islands Datum 1971 (code 6672). Replaced by New Zealand Geodetic Datum 2000 (code 6167) from March 2000.","Office of Surveyor General (OSG) Technical Report 14, June 2001.",OGP,"2008/06/24",2008.045,0,"D_Chatham_Islands_1979"
@@ -529,7 +548,7 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6680,Nouakchott 1965,geodetic,Nouakchott astronomical point.,1965,7012,8901,2968,Topographic survey.,"Triangulation limited to environs of Nouakchott. Extended in 1982 by satellite translocation from a single station ""Ruines"" to support Syledis chain for offshore operations. Replaced by Mauritania 1999 (datum code 6602).",IGN Paris and various industry sources.,OGP,"2006/06/12",2006.440,0,"D_Nouakchott_1965"
 6681,Mauritania 1999,geodetic,,1999,7012,8901,1157,"Minerals management, topographic mapping.","A network of 36 GPS stations tied to ITRF96, 8 of which are IGN astronomic points.",Woodside,OGP,"2004/10/14",,1,"D_Mauritania_1999"
 6682,Gulshan 303,geodetic,"Gulshan garden, Dhaka.",1995,7015,8901,1041,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Network of more than 140 control points observed and adjusted in 1995 by Japan International Cooperation Agency (JICA).",Survey of Bangladesh via IGN Paris and Tullow Oil.,OGP,"2006/06/22",2006.470,0,"D_Gulshan_303"
-6683,Philippine Reference System 1992,geodetic,"Fundamental point: Balacan. Latitude: 13°33'41.000""N, longitude: 121°52'03.000""E (of Greenwich), geoid-ellipsoid separation 0.34m.",1992,7008,8901,1190,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Luzon 1911 datum (code 6253).","National Mapping and Resource Information Authority, Coast and Geodetic Survey Department.",OGP,"2008/06/24",2008.045,0,"D_Phillipine_Reference_System_1992"
+6683,Philippine Reference System 1992,geodetic,"Fundamental point: Balacan. Latitude: 13°33'41.000""N, longitude: 121°52'03.000""E (of Greenwich), geoid-ellipsoid separation 0.34m.",1992,7008,8901,1190,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Luzon 1911 datum (code 6253).","National Mapping and Resource Information Authority, Coast and Geodetic Survey Department.",OGP,"2008/06/24",2008.045,0,"D_Philippine_Reference_System_1992"
 6684,Gan 1970,geodetic,,1970,7022,8901,3274,Topographic mapping.,"In some references incorrectly named ""Gandajika 1970"". See datum code 6685.",Various industry sources.,OGP,"2005/04/14",,0,"D_Gan_1970"
 6685,Gandajika,geodetic,Gandajika base.,1953,7022,8901,1259,Topographic mapping.,In some references incorrectly attributed to the Maldives. See datum code 6684.,Various industry sources.,OGP,"2005/04/14",,1,
 6686,Marco Geocentrico Nacional de Referencia,geodetic,"ITRF94 at epoch 1995.4.  Bogota observatory coordinates: Latitude: 4°35'46.3215""N, longitude: 74°04'39.0285""W (of Greenwich).",2004,7019,8901,1070,Geodetic survey.,"Densification of SIRGAS 1995 within Colombia. Replaces Bogota 1975 (datum code 6218).","Instituto Geografico Agustin Codazzi (IGAC) publication ""Aspectos prácticos de la adopción del Marco Geocéntrico Nacional de Referencia MAGNA-SIRGAS como datum oficial de Colombia" [...]
@@ -542,7 +561,7 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6693,Nakhl-e Ghanem,geodetic,"Coordinates of two stations determined with respect to ITRF 2000 at epoch 2005.2: BMT1 latitude 27°42'09.8417""N, longitude 52°12'11.0362""E (of Greenwich); Total1 latitude 27°31'03.8896""N, longitude 52°36'13.1312""E (of Greenwich).",2005,7030,8901,2362,Engineering survey for onshore facilities for South Pars phase 11 and Pars LNG.,,Total,OGP,"2008/06/24",2006.770 2008.045,0,"D_Nakhl-e_Ghanem"
 6694,Posiciones Geodesicas Argentinas 1994,geodetic,"A geodetic network of 127 high accuracy surveyed points based on WGS 84 that define the National Geodetic System (Sistema Geodésico Nacional).",1994,7030,8901,1033,"Topographic mapping, geodetic survey.","Technically, but not legally, replaced by POSGAR 98 (code 6190) until May 2009, when POSGAR 2007 was officially accepted and officially replaced POSGAR 94.","Instituto Geográfico Militar de la República Argentina, http://www.igm.gov.a [...]
 6695,Katanga 1955,geodetic,"Fundamental point: Tshinsenda A. Latitude: 12°30'31.568""S, longitude: 28°01'02.971""E (of Greenwich).",1955,7008,8901,3147,"Cadastre, topographic mapping, engineering survey.",Replaces earlier adjustments.,"Clifford J. Mugnier, in Photogrammetric Engineering and Remote Sensing, June 2005.",OGP,"2009/06/02",2008.045 2009.011,0,"D_Katanga_1955"
-6696,Kasai 1953,geodetic,"Two stations of the Katanga triangulation with ellipsoid change applied: Kabila, latitude 6°58'34.023""S, longitude 23°50'24.028""E (of Greenwich); and Gandajika NW base, latitude 6°45'01.057""S, longitude 23°57'03.038""E (of Greenwich).",1955,7012,8901,3148,"Cadastre, topographic mapping, engineering survey.",Replaced by IGC 1962 Arc of the 6th Parallel South.,Institute Geographique du Congo,OGP,"2008/06/24",2008.045,0,"D_Kasai_1955"
+6696,Kasai 1953,geodetic,"Two stations of the Katanga triangulation with ellipsoid change applied: Kabila, latitude 6°58'34.023""S, longitude 23°50'24.028""E (of Greenwich); and Gandajika NW base, latitude 6°45'01.057""S, longitude 23°57'03.038""E (of Greenwich).",1955,7012,8901,3148,"Cadastre, topographic mapping, engineering survey.",Replaced by IGC 1962 Arc of the 6th Parallel South.,Institute Geographique du Congo,OGP,"2008/06/24",2008.045,0,"D_Kasai_1953"
 6697,IGC 1962 Arc of the 6th Parallel South,geodetic,"Coordinates of 3 stations determined with respect to Arc 1950: Mulungu 4°47'39.2325""S, 29°59'37.5864""E; Nyakawembe 4°14'57.3618""S, 29°42'52.8032""E; Kavula 4°35'15.8634""S, 29°41'14.2693""E (all longitude w.r.t. Greenwich).",1962,7012,8901,3149,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,Institute Geographique du Congo,OGP,"2008/06/24",2006.721 2008.045,0,"D_IGC_1962_Arc_of_the_6th_Parallel_South"
 6698,IGN 1962 Kerguelen,geodetic,K0 1949.,1949,7022,8901,2816,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,IGN Paris.,OGP,"2005/11/23",,0,"D_Kerguelen_Island_1949"
 6699,Le Pouce 1934,geodetic,"Fundamental point: Le Pouce. Latitude: 20°11'42.25""S, longitude: 57°31'18.58""E (of Greenwich).",1934,7012,8901,3209,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Cartography Section, Ministry of Housing and Land.",OGP,"2008/06/24",2008.045,0,"D_Le_Pouce_1934"
@@ -554,23 +573,23 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6705,"Mhast (offshore)",geodetic,"Fundamental point: Station Y at Malongo base camp. Latitude: 5°23'30.810""S, longitude: 12°12'01.590""E (of Greenwich).",1979,7022,8901,3180,Oil industry offshore exploration and production between 1979 and 1987.,"Origin coordinates determined by Transit single point position using 32 passes and transformed from WGS72BE using transformation code 15790. Differs from Mhast (onshore) by approximately 10m. Replaced in 1987 by Malongo 1987 (code 6259).",Chevr [...]
 6706,Egypt Gulf of Suez S-650 TL,geodetic,"Fundamental point: Station S-650 DMX. Adopted coordinates: latitude: 28°19'02.1907""N, longitude: 33°06'36.6344""E (of Greenwich). The proper Egypt 1907 coordinates for S-650 differ from these by about 20m.",1980,7020,8901,2341,Oil industry offshore exploration and production in Gulf of Suez after 1980.,"A coherent set of stations bordering the Gulf of Suez coordinated by Transit translocation (""TL"") between 1980 and 1984. Based on incorrect E [...]
 6707,Tern Island 1961,geodetic,"Fundamental point: station FRIG on tern island, station B4 on Sorol Atoll.",1961,7022,8901,3181,Military and topographic mapping,"Two independent astronomic determinations considered to be consistent through adoption of common transformation to WGS 84 (see tfm code 15795).","DMA / NIMA / NGA TR8350.2 (original 1987 first edition and 3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Tern_Island_1961"
-6708,Cocos Islands 1965,geodetic,"Fundamental point: Anna 1.",1965,7003,8901,1069,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
-6709,Iwo Jima 1945,geodetic,"Fundamental point: Beacon ""E"".",1945,7022,8901,3200,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
-6710,St. Helena 1971,geodetic,"Fundamental point: DOS 71/4.",1971,7022,8901,3183,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
-6711,Marcus Island 1952,geodetic,Marcus Island Astronomic Station.,1952,7022,8901,1872,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2012/03/25",2012.032,0,
+6708,Cocos Islands 1965,geodetic,"Fundamental point: Anna 1.",1965,7003,8901,1069,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Anna_1_1965"
+6709,Iwo Jima 1945,geodetic,"Fundamental point: Beacon ""E"".",1945,7022,8901,3200,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Beacon_E_1945"
+6710,St. Helena 1971,geodetic,"Fundamental point: DOS 71/4.",1971,7022,8901,3183,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_DOS_71_4"
+6711,Marcus Island 1952,geodetic,Marcus Island Astronomic Station.,1952,7022,8901,1872,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2012/03/25",2012.032,0,"D_Astro_1952"
 6712,Ascension Island 1958,geodetic,,1958,7022,8901,3182,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Ascension_Island_1958"
 6713,Ayabelle Lighthouse,geodetic,"Fundamental point: Ayabelle Lighthouse.",,7012,8901,1081,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Ayabelle"
 6714,Bellevue,geodetic,,1960,7022,8901,3193,Military and topographic mapping,"Datum covers all the major islands of Vanuatu in two different adjustment blocks, but practical usage is as given in the area of use.","DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/07/29",2006.510,0,"D_Bellevue_IGN"
 6715,Camp Area Astro,geodetic,,,7022,8901,3205,Geodetic and topographic survey,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Camp_Area"
-6716,Phoenix Islands 1966,geodetic,,1966,7022,8901,3196,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
+6716,Phoenix Islands 1966,geodetic,,1966,7022,8901,3196,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Canton_1966"
 6717,Cape Canaveral,geodetic,"Fundamental point: Central 1950.  Latitude: 28°29'32.36555""N, longitude 80°34'38.77362""W (of Greenwich)",1963,7008,8901,3206,US space and military operations.,,"US NGS and DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2008/06/24",2006.870 2008.045,0,"D_Cape_Canaveral"
 6718,Solomon 1968,geodetic,"Fundamental point: GUX 1.",1968,7022,8901,1213,"Military and topographic mapping, +/- 25 meters in each component",,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Solomon_1968"
 6719,Easter Island 1967,geodetic,,1967,7022,8901,3188,"Military and topographic mapping, +/- 25 meters in each component",,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Easter_Island_1967"
 6720,Fiji Geodetic Datum 1986,geodetic,NWL 9D coordinates of 6 stations on Vitu Levu and Vanua Levu.,1986,7043,8901,1094,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Viti Levu 1912, Vanua Levu 1915 and Fiji 1956.","Survey Review 30,231 (January 1989).",OGP,"2006/07/19",2006.500,0,"D_Fiji_1986"
 6721,Fiji 1956,geodetic,"Latitude origin was obtained astronomically at station Rasusuva = 17°49'03.13""S,  longitude origin was obtained astronomically at station Suva = 178°25'35.835""E (of Greenwich).",1956,7022,8901,3398,Military and topographic mapping,For topographic mapping replaces Viti Levu 1912 and Vanua Levu 1915. Replaced by Fiji Geodetic Datum 1986.,"SOPAC, www.sopac.org, and Clifford J. Mugnier in Photogrammetric Engineering and Remote Sensing, October 2000, www.asprs.org." [...]
-6722,South Georgia 1968,geodetic,"Fundamental point: ISTS 061.",1968,7022,8901,3529,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2012/02/13",2012.023,0,
+6722,South Georgia 1968,geodetic,"Fundamental point: ISTS 061.",1968,7022,8901,3529,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2012/02/13",2012.023,0,"D_ISTS_061_1968"
 6723,Grand Cayman Geodetic Datum 1959,geodetic,"Fundamental point: GC1. Latitude: 19°17'54.43""N, longitude: 81°22'37.17""W (of Greenwich).",1959,7008,8901,3185,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by CIGD11 (datum code 1100).","Lands and Survey Department, Cayman Islands Government.",OGP,"2013/01/17",2008.045 2012.095,0,"D_Grand_Cayman_1959"
-6724,Diego Garcia 1969,geodetic,"Fundamental point: ISTS 073.",1969,7022,8901,3189,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
+6724,Diego Garcia 1969,geodetic,"Fundamental point: ISTS 073.",1969,7022,8901,3189,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_ISTS_073_1969"
 6725,Johnston Island 1961,geodetic,,1961,7022,8901,3201,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Johnston_Island_1961"
 6726,Sister Islands Geodetic Datum 1961,geodetic,"Fundamental point: LC5. Latitude: 19°39'46.324""N, longitude: 80°03'47.910""W (of Greenwich).",1961,7008,8901,3186,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaced by CIGD11 (datum code 1100).","Lands and Survey Department, Cayman Islands Government.",OGP,"2013/01/17",2008.045 2012.095,0,"D_Little_Cayman_1961"
 6727,Midway 1961,geodetic,,1961,7022,8901,3202,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Midway_1961"
@@ -578,7 +597,7 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6729,Pitcairn 1967,geodetic,"Fundamental point: Pitcairn Astro. Latitude: 25°04'06.87""S, longitude: 130°06'47.83""W (of Greenwich).",1967,7022,8901,3208,Military and topographic mapping,Replaced by Pitcairn 2006.,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2008/06/24",2008.004 2008.045,0,"D_Pitcairn_1967"
 6730,Santo 1965,geodetic,,1965,7022,8901,3194,Military and topographic mapping,"Datum covers all the major islands of Vanuatu in two different adjustment blocks, but practical usage is as given in the area of use.","DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/07/29",2006.510,0,"D_Santo_DOS_1965"
 6731,Viti Levu 1916,geodetic,,1916,7012,8901,3195,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,1,"D_Viti_Levu_1916"
-6732,Marshall Islands 1960,geodetic,,1960,7053,8901,3191,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,
+6732,Marshall Islands 1960,geodetic,,1960,7053,8901,3191,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Wake_Eniwetok_1960"
 6733,Wake Island 1952,geodetic,,1952,7022,8901,3190,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Wake_Island_1952"
 6734,Tristan 1968,geodetic,,1968,7022,8901,3184,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Tristan_1968"
 6735,Kusaie 1951,geodetic,,1951,7022,8901,3192,Military and topographic mapping,,"DMA / NIMA / NGA TR8350.2 (3rd edition, Amendment 1, 3 January 2000).",OGP,"2006/01/26",,0,"D_Kusaie_1951"
@@ -591,27 +610,27 @@ For Selvagens see Selvagem Grande (datum code 6616).","Instituto Geografico e Ca
 6742,Geodetic Datum of Malaysia 2000,geodetic,"ITRF2000, epoch 2000.0.",2000,7019,8901,1151,"Geodetic survey, topographic mapping, engineering and cadastrral survey.",Replaces all older Malaysian datums.,"GDM2000 Technical Manual; Department of Survey and Mapping Malaysia. www.jupem.gov.my",OGP,"2006/03/16",,0,"D_GDM_2000"
 6743,Karbala 1979,geodetic,"Fundamental point: Karbala. Latitude: 32°34'14.4941""N, longitude: 44°00'49.6379""E.",1979,7012,8901,3625,Geodetic survey.,National geodetic network established by Polservice consortium.,Various industry sources.,OGP,"2011/01/25",2009.003 2011.004,0,"D_Karbala_1979_Polservice"
 6744,Nahrwan 1934,geodetic,"Fundamental point: Nahrwan south base.  Latitude: 33°19'10.87""N, longitude: 44°43'25.54""E (of Greenwich).",1934,7012,8901,3390,Oil exploration and production.,"This adjustment later discovered to have a significant orientation error. In Iran replaced by FD58. In Iraq, replaced by Nahrwan 1967.",Various industry sources.,OGP,"2008/06/24",2008.045,0,"D_Nahrwan_1934"
-6745,"Rauenberg Datum/83",geodetic,"Fundamental point: Rauenberg. Latitude: 52°27'12.021""N, longitude: 13°22'04.928""E (of Greenwich). This station was destroyed in 1910 and the station at Potsdam substituted as the fundamental point.",1990,7004,8901,2545,"Geodetic survey, cadastre, topographic mapping, engineering survey.","RD/83 is the realisation of DHDN in Saxony. It is the resultant of applying a transformation derived at 106 points throughout former East Germany to Pulkovo 1942/83 [...]
-6746,"Potsdam Datum/83",geodetic,"Fundamental point: Rauenberg. Latitude: 52°27'12.021""N, longitude: 13°22'04.928""E (of Greenwich). This station was destroyed in 1910 and the station at Potsdam substituted as the fundamental point.",1990,7004,8901,2544,"Geodetic survey, cadastre, topographic mapping, engineering survey.","PD/83 is the realisation of DHDN in Thuringen. It is the resultant of applying a transformation derived at 13 points on the border between East and West Germany to Pu [...]
+6745,"Rauenberg Datum/83",geodetic,"Fundamental point: Rauenberg. Latitude: 52°27'12.021""N, longitude: 13°22'04.928""E (of Greenwich). This station was destroyed in 1910 and the station at Potsdam substituted as the fundamental point.",1990,7004,8901,2545,"Geodetic survey, cadastre, topographic mapping, engineering survey.","RD/83 is the realisation of DHDN in Saxony. It is the resultant of applying a transformation derived at 106 points throughout former East Germany to Pulkovo 1942/83 [...]
+6746,"Potsdam Datum/83",geodetic,"Fundamental point: Rauenberg. Latitude: 52°27'12.021""N, longitude: 13°22'04.928""E (of Greenwich). This station was destroyed in 1910 and the station at Potsdam substituted as the fundamental point.",1990,7004,8901,2544,"Geodetic survey, cadastre, topographic mapping, engineering survey.","PD/83 is the realisation of DHDN in Thuringen. It is the resultant of applying a transformation derived at 13 points on the border between East and West Germany to Pu [...]
 6747,Greenland 1996,geodetic,ITRF94 at epoch 1996.62,1996,7019,8901,1107,"Geodetic survey, cadastre, topographic mapping, engineering survey.","Replaces Ammassalik 1958, Qornoq 1927 and Scoresbysund 1952.","Kort & Matrikelstyrelsen (KMS), Copenhagen.",OGP,"2006/08/18",2006.770,0,"D_Greenland_1996"
 6748,Vanua Levu 1915,geodetic,"Latitude origin was obtained astronomically at station Numuiloa = 16°23'38.36""S, longitude origin was obtained astronomically at station Suva = 178°25'35.835""E.",1915,7055,8901,3401,"Geodetic survey, cadastre, topographic mapping, engineering survey.","For topographic mapping, replaced by Fiji 1956. For other purposes, replaced by Fiji 1986.","Clifford J. Mugnier in Photogrammetric Engineering and Remote Sensing, October 2000, www.asprs.org.",OGP,"2008/06 [...]
-6749,Reseau Geodesique de Nouvelle Caledonie 91-93,geodetic,ITRF90 at epoch 1989.0.,1989,7019,8901,1174,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/08/18",2006.770,0,
-6750,ST87 Ouvea,geodetic,Ouloup.,1987,7030,8901,2813,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",,0,
-6751,"Kertau (RSO)",geodetic,,1969,7056,8901,1309,Metrication of RSO grid.,Adopts metric conversion of 0.914398 metres per yard exactly. This is a truncation of the Sears 1922 ratio.,Defence Geographic Centre.,OGP,"2006/07/24",,0,
-6752,Viti Levu 1912,geodetic,"Latitude origin was obtained astronomically at station Monavatu = 17°53'28.285""S, longitude origin was obtained astronomically at station Suva = 178°25'35.835""E.",1912,7055,8901,3195,"Geodetic survey, cadastre, topographic mapping, engineering survey.","For topographic mapping, replaced by Fiji 1956. For other purposes, replaced by Fiji 1986.","Clifford J. Mugnier in Photogrammetric Engineering and Remote Sensing, October 2000, www.asprs.org.",OGP,"2008/06 [...]
+6749,Reseau Geodesique de Nouvelle Caledonie 91-93,geodetic,ITRF90 at epoch 1989.0.,1989,7019,8901,1174,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/08/18",2006.770,0,"D_Reseau_Geodesique_de_Nouvelle_Caledonie_1991-93"
+6750,ST87 Ouvea,geodetic,Ouloup.,1987,7030,8901,2813,"Geodetic survey, cadastre, topographic mapping, engineering survey.",,"Service Topographique de la Nouvelle Caledonie, Direction des Infrastructures, de la Topografie et des Transports Terrestres. www.dittt.gouv.nc",OGP,"2006/07/21",,0,"D_ST87_Ouvea"
+6751,"Kertau (RSO)",geodetic,,1969,7056,8901,1309,Metrication of RSO grid.,Adopts metric conversion of 0.914398 metres per yard exactly. This is a truncation of the Sears 1922 ratio.,Defence Geographic Centre.,OGP,"2006/07/24",,0,"D_Kertau_RSO"
+6752,Viti Levu 1912,geodetic,"Latitude origin was obtained astronomically at station Monavatu = 17°53'28.285""S, longitude origin was obtained astronomically at station Suva = 178°25'35.835""E.",1912,7055,8901,3195,"Geodetic survey, cadastre, topographic mapping, engineering survey.","For topographic mapping, replaced by Fiji 1956. For other purposes, replaced by Fiji 1986.","Clifford J. Mugnier in Photogrammetric Engineering and Remote Sensing, October 2000, www.asprs.org.",OGP,"2008/06 [...]
 6753,fk89,geodetic,,1989,7022,8901,3248,Cadastre,Replaces FD54 for cadastre.,"Kort & Matrikelstyrelsen (KMS), Copenhagen.",OGP,"2006/08/04",,0,"D_fk89"
 6754,Libyan Geodetic Datum 2006,geodetic,5 stations tied to ITRF2000 through 8 days of continuous observations in May 2006.,2006,7022,8901,1143,"Geodetic survey, topographic mapping, engineering survey.",Replaces ELD79.,Survey Department of Libya.,OGP,"2006/08/25",,0,"D_Libyan_Geodetic_Datum_2006"
 6755,Datum Geodesi Nasional 1995,geodetic,ITRF91at epoch 1992.0.,1995,7030,8901,1122,"Geodetic survey, topographic mapping, engineering survey.",Replaces ID74 and all older datums.,Bakosurtanal.,OGP,"2006/08/25",,0,"D_Datum_Geodesi_Nasional_1995"
 6756,Vietnam 2000,geodetic,"Point N00, located in the premises of the Land Administration Research Institute, Hoang Quoc Viet Street, Hanoi.",2000,7030,8901,3328,"Geodetic survey, topographic mapping, engineering survey.",Replaces Hanoi 1972.,General Director of Land Administration.,OGP,"2011/01/25",2011.004,0,"D_Vietnam_2000"
 6757,SVY21,geodetic,"Fundamental point: Base 7 at Pierce Resevoir. Latitude: 1°22'02.9154""N, longitude: 103°49'31.9752""E (of Greenwich).",2004,7030,8901,1210,Cadastre.,Replaces Kertau 1968 for cadastral purposes from August 2004.,Singapore Land Authority,OGP,"2008/06/24",2008.045,0,"D_SVY21"
 6758,Jamaica 2001,geodetic,Aligned to WGS 84.,2001,7030,8901,1128,"Geodetic survey, cadastre, topographic mapping, hydrographic charting, engineering survey.",,National Land Agency.,OGP,"2007/01/19",,0,"D_Jamaica_2001"
-6759,"NAD83 (National Spatial Reference System 2007)",geodetic,"Coordinates of 486 national continually operating reference system (CORS) and 195 collaborative GPS (CGPS) sites constrained to their CORS96 values, ITRF2000 at epoch 2002.0.",2007,7019,8901,1511,Geodetic survey.,,"U.S. National Geodetic Survey, http://www.ngs.noaa.gov/",OGP,"2007/03/13",,0,
-6760,World Geodetic System 1966,geodetic,Developed from a worldwide distribution of terrestrial and geodetic satellite observations and defined through a set of station coordinates.,1966,7025,8901,1262,Geodesy.,"A worldwide 5° × 5° mean free air gravity anomaly field provided the basic data for producing the WGS 66 gravimetric geoid. Replaced by WGS 72.","US DMA/NIMA/NGA",OGP,"2007/03/25",,0,
-6761,Croatian Terrestrial Reference System,geodetic,Densification of ETRS89 in Croatia at epoch 1995.55.,1996,7019,8901,1076,Geodesy.,Based on 78 control points with coordinates determined in ETRS89.,State Geodetic Administration of the Republic of Croatia.,OGP,"2007/09/25",,0,
-6762,Bermuda 2000,geodetic,ITRF96 at epoch 2000.0.,2000,7030,8901,1047,"Topographic mapping, cadastral and engineering survey.",,Department of Lands Buildings and Surveys,OGP,"2007/12/12",,0,
-6763,Pitcairn 2006,geodetic,"Fundamental point: Pitcairn Astro. Latitude: 25°04'06.7894""S, longitude: 130°06'46.6816""W (of Greenwich), derived by single point GPS oberservations.",2006,7030,8901,3208,"Cadastre, topographic mapping and engineering survey",Replaces Pitcairn 1967.,Pitcairn Island Government.,OGP,"2008/06/24",2008.045,0,
-6764,Ross Sea Region Geodetic Datum 2000,geodetic,Based on ITRF96 at epoch 2000.0,2000,7019,8901,3558,"Geodetic survey, topographic mapping.",,"Land Information New Zealand: LINZS25001 Standard for Ross Sea Region Geodetic Datum 2000; 16 November 2007.",OGP,"2008/04/04",,0,
-6765,Slovenia Geodetic Datum 1996,geodetic,"Densification of ETRS89, based on ITRS89 at epoch 1995.55.",1996,7019,8901,1212,"Geodetic survey, topographic mapping.",,Surveying and Mapping Authority of Slovenia,OGP,"2008/04/04",,0,
+6759,"NAD83 (National Spatial Reference System 2007)",geodetic,"Coordinates of 486 national continually operating reference system (CORS) and 195 collaborative GPS (CGPS) sites constrained to their CORS96 values, ITRF2000 at epoch 2002.0.",2007,7019,8901,1511,Geodetic survey.,"Replaced by NAD83 (National Spatial Reference System 2011), datum code 1116.","U.S. National Geodetic Survey, http://www.ngs.noaa.gov/",OGP,"2013/06/12",2013.022,0,"D_NAD_1983_NSRS2007"
+6760,World Geodetic System 1966,geodetic,Developed from a worldwide distribution of terrestrial and geodetic satellite observations and defined through a set of station coordinates.,1966,7025,8901,1262,Geodesy.,"A worldwide 5° × 5° mean free air gravity anomaly field provided the basic data for producing the WGS 66 gravimetric geoid. Replaced by WGS 72.","US DMA/NIMA/NGA",OGP,"2007/03/25",,0,"D_WGS_1966"
+6761,Croatian Terrestrial Reference System,geodetic,Densification of ETRS89 in Croatia at epoch 1995.55.,1996,7019,8901,1076,Geodesy.,Based on 78 control points with coordinates determined in ETRS89.,State Geodetic Administration of the Republic of Croatia.,OGP,"2007/09/25",,0,"D_Croatian_Terrestrial_Reference_System"
+6762,Bermuda 2000,geodetic,ITRF96 at epoch 2000.0.,2000,7030,8901,1047,"Topographic mapping, cadastral and engineering survey.",,Department of Lands Buildings and Surveys,OGP,"2007/12/12",,0,"D_Bermuda_2000"
+6763,Pitcairn 2006,geodetic,"Fundamental point: Pitcairn Astro. Latitude: 25°04'06.7894""S, longitude: 130°06'46.6816""W (of Greenwich), derived by single point GPS oberservations.",2006,7030,8901,3208,"Cadastre, topographic mapping and engineering survey",Replaces Pitcairn 1967.,Pitcairn Island Government.,OGP,"2008/06/24",2008.045,0,"D_Pitcairn_2006"
+6764,Ross Sea Region Geodetic Datum 2000,geodetic,Based on ITRF96 at epoch 2000.0,2000,7019,8901,3558,"Geodetic survey, topographic mapping.",,"Land Information New Zealand: LINZS25001 Standard for Ross Sea Region Geodetic Datum 2000; 16 November 2007.",OGP,"2008/04/04",,0,"D_Ross_Sea_Region_Geodetic_Datum_2000"
+6765,Slovenia Geodetic Datum 1996,geodetic,"Densification of ETRS89, based on ITRS89 at epoch 1995.55.",1996,7019,8901,1212,"Geodetic survey, topographic mapping.",,Surveying and Mapping Authority of Slovenia,OGP,"2008/04/04",,0,"D_Slovenia_Geodetic_Datum_1996"
 6801,"CH1903 (Bern)",geodetic,"Fundamental point: Old Bern observatory. Latitude: 46°57'08.660""N, longitude: 0°E (of Bern).",1903,7004,8907,1286,Topographic mapping.,,"Bundesamt für Landestopographie",OGP,"2008/06/24",2003.361 2008.045,0,"D_Bern_1898"
 6802,"Bogota 1975 (Bogota)",geodetic,"Fundamental point: Bogota observatory. Latitude: 4°35'56.570""N, longitude: 0°E (of Bogota).",1975,7022,8904,3229,Topographic mapping.,,,OGP,"2008/06/24",2000.200 2003.361 2008.045,0,"D_Bogota"
 6803,"Lisbon 1937 (Lisbon)",geodetic,"Fundamental point: Castelo Sao Jorge, Lisbon. Latitude: 38°42'43.631""N, longitude: 0°E (of Lisbon).",1937,7022,8902,1294,Topographic mapping.,"Replaces Lisbon 1890 adjustment (which used Bessel 1841 ellipsoid).","Instituto Geografico e Cadastral; Lisbon",OGP,"2008/06/24",2001.551 2008.045,0,"D_Lisbon"
diff --git a/data/gdalvrt.xsd b/data/gdalvrt.xsd
new file mode 100644
index 0000000..bd83a55
--- /dev/null
+++ b/data/gdalvrt.xsd
@@ -0,0 +1,362 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/******************************************************************************
+ * $Id: gdalvrt.xsd 28847 2015-04-04 14:14:39Z rouault $
+ *
+ * Project:  GDAL/OGR
+ * Purpose:  XML Schema for GDAL VRT files.
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ **********************************************************************
+ * Copyright (c) 2015, Even Rouault
+ *
+ * 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.
+ ****************************************************************************/
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="1.0">
+    <xs:element name="VRTDataset">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:choice minOccurs="0" maxOccurs="unbounded">
+                    <xs:element name="SRS" type="xs:string"/>
+                    <xs:element name="GeoTransform" type="xs:string"/>
+                    <xs:element name="GCPList" type="GCPListType"/>
+                    <xs:element name="BlockXSize" type="nonNegativeInteger32"/>
+                    <xs:element name="BlockYSize" type="nonNegativeInteger32"/>
+                    <xs:element name="Metadata" type="MetadataType"/> <!-- may be repeated -->
+                    <xs:element name="VRTRasterBand" type="VRTRasterBandType"/> <!-- may be repeated -->
+                    <xs:element name="MaskBand" type="MaskBandType"/>
+                    <xs:element name="GDALWarpOptions" type="GDALWarpOptionsType"/> <!-- only if subClass="VRTWarpedDataset" -->
+                </xs:choice>
+            </xs:sequence>
+            <xs:attribute name="subClass" type="xs:string"/>
+            <xs:attribute name="rasterXSize" type="nonNegativeInteger32" use="required"/>
+            <xs:attribute name="rasterYSize" type="nonNegativeInteger32" use="required"/>
+        </xs:complexType>
+    </xs:element>
+
+    <xs:simpleType name="nonNegativeInteger32">
+        <xs:restriction base="xs:nonNegativeInteger">
+            <xs:maxInclusive value="2147483647"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="GCPListType">
+        <xs:sequence>
+            <xs:element name="GCP" type="GCPType" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="Projection" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="GCPType">
+        <xs:attribute name="Id" type="xs:string"/>
+        <xs:attribute name="Info" type="xs:string"/>
+        <xs:attribute name="Pixel" type="xs:double" use="required"/>
+        <xs:attribute name="Line" type="xs:double" use="required"/>
+        <xs:attribute name="X" type="xs:double" use="required"/>
+        <xs:attribute name="Y" type="xs:double" use="required"/>
+        <xs:attribute name="Z" type="xs:double"/>
+        <xs:attribute name="GCPZ" type="xs:double"/> <!-- deprecated -->
+    </xs:complexType>
+
+    <xs:complexType name="MetadataType">
+        <xs:sequence>
+            <!--<xs:choice>-->
+                <!--<xs:element name="MDI" type="MDIType" minOccurs="0" maxOccurs="unbounded"/>-->
+                <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+            <!--</xs:choice>-->
+        </xs:sequence>
+        <xs:attribute name="domain" type="xs:string"/>
+        <xs:attribute name="format" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="GDALWarpOptionsType">
+        <xs:sequence>
+            <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="MDIType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="key" type="xs:string" use="required"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="VRTRasterBandType">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="Description" type="xs:string"/>
+                <xs:element name="UnitType" type="xs:string"/>
+                <xs:element name="Offset" type="xs:double"/>
+                <xs:element name="Scale" type="xs:double"/>
+                <xs:element name="CategoryNames" type="CategoryNamesType"/>
+                <xs:element name="ColorTable" type="ColorTableType"/>
+                <xs:element name="NoDataValue" type="DoubleOrNanType"/>
+                <xs:element name="NodataValue" type="xs:double"/> <!-- typo: deprecated -->
+                <xs:element name="HideNoDataValue" type="ZeroOrOne"/>
+                <xs:element name="Metadata" type="MetadataType"/>
+                <xs:element name="ColorInterp" type="ColorInterpType"/>
+                <xs:element name="Overview" type="OverviewType"/>
+                <xs:element name="MaskBand" type="MaskBandType"/>
+                <xs:element name="Histograms" type="HistogramsType"/>
+
+                <!-- for a VRTSourcedRasterBand. Each element may be repeated -->
+                <xs:element name="SimpleSource" type="SimpleSourceType"/> 
+                <xs:element name="ComplexSource" type="ComplexSourceType"/>
+                <xs:element name="AveragedSource" type="SimpleSourceType"/>
+                <xs:element name="KernelFilteredSource" type="KernelFilteredSourceType"/>
+
+                <!-- for a VRTDerivedRasterBand -->
+                <xs:element name="PixelFunctionType" type="xs:string"/>
+                <xs:element name="SourceTransferType" type="DataTypeType"/>
+
+                <!-- for a VRTRawRasterBand -->
+                <xs:element name="SourceFilename" type="SourceFilenameType"/>
+                <xs:element name="ImageOffset" type="xs:integer"/>
+                <xs:element name="PixelOffset" type="xs:integer"/>
+                <xs:element name="LineOffset" type="xs:integer"/>
+                <xs:element name="ByteOrder" type="xs:string"/>
+            </xs:choice>
+        </xs:sequence>
+        <xs:attribute name="dataType" type="DataTypeType"/>
+        <xs:attribute name="band" type="xs:unsignedInt"/>
+        <xs:attribute name="subClass" type="VRTRasterBandSubClassType"/>
+
+        <xs:attribute name="BlockXSize" type="xs:unsignedInt"/> <!-- ignored -->
+        <xs:attribute name="BlockYSize" type="xs:unsignedInt"/> <!-- ignored -->
+    </xs:complexType>
+
+    <xs:simpleType name="ZeroOrOne">
+        <xs:restriction base="xs:integer">
+            <xs:enumeration value="0"/>
+            <xs:enumeration value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="VRTRasterBandSubClassType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="VRTWarpedRasterBand"/>
+            <xs:enumeration value="VRTDerivedRasterBand"/>
+            <xs:enumeration value="VRTRawRasterBand"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="MaskBandType">
+        <xs:sequence minOccurs="1" maxOccurs="1">
+            <xs:element name="VRTRasterBand" type="VRTRasterBandType"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="HistogramsType">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="HistItem" type="HistItemType"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="HistItemType">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="HistMin" type="xs:double"/>
+                <xs:element name="HistMax" type="xs:double"/>
+                <xs:element name="BucketCount" type="xs:integer"/>
+                <xs:element name="IncludeOutOfRange" type="ZeroOrOne"/>
+                <xs:element name="Approximate" type="ZeroOrOne"/>
+                <xs:element name="HistCounts" type="xs:string"/>
+            </xs:choice>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="CategoryNamesType">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Category" type="xs:string"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="ColorTableType">
+        <xs:sequence minOccurs="0" maxOccurs="unbounded">
+            <xs:element name="Entry" type="ColorTableEntryType"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="OverviewType">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="SourceFilename" type="SourceFilenameType"/>
+                <xs:element name="SourceBand" type="xs:string"/>  <!-- should be refined into xs:nonNegativeInteger or mask,xs:nonNegativeInteger -->
+            </xs:choice>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="ColorTableEntryType">
+        <xs:attribute name="c1" type="xs:unsignedInt" use="required"/>
+        <xs:attribute name="c2" type="xs:unsignedInt" use="required" />
+        <xs:attribute name="c3" type="xs:unsignedInt" use="required" />
+        <xs:attribute name="c4" type="xs:unsignedInt" />
+    </xs:complexType>
+
+    <xs:simpleType name="DataTypeType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="Byte"/>
+            <xs:enumeration value="UInt16"/>
+            <xs:enumeration value="Int16"/>
+            <xs:enumeration value="UInt32"/>
+            <xs:enumeration value="Int32"/>
+            <xs:enumeration value="Float32"/>
+            <xs:enumeration value="Float64"/>
+            <xs:enumeration value="CInt16"/>
+            <xs:enumeration value="CInt32"/>
+            <xs:enumeration value="CFloat32"/>
+            <xs:enumeration value="CFloat64"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:simpleType name="ColorInterpType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="Gray"/>
+            <xs:enumeration value="Palette"/>
+            <xs:enumeration value="Red"/>
+            <xs:enumeration value="Green"/>
+            <xs:enumeration value="Blue"/>
+            <xs:enumeration value="Alpha"/>
+            <xs:enumeration value="Hue"/>
+            <xs:enumeration value="Saturation"/>
+            <xs:enumeration value="Lightness"/>
+            <xs:enumeration value="Cyan"/>
+            <xs:enumeration value="Magenta"/>
+            <xs:enumeration value="Yellow"/>
+            <xs:enumeration value="Black"/>
+            <xs:enumeration value="YCbCr_Y"/>
+            <xs:enumeration value="YCbCr_Cb"/>
+            <xs:enumeration value="YCbCr_Cr"/>
+            <xs:enumeration value="Undefined"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:group name="SimpleSourceElementsGroup">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="SourceFilename" type="SourceFilenameType"/>
+                <xs:element name="OpenOptions" type="OpenOptionsType"/>
+                <xs:element name="SourceBand" type="xs:string"/>  <!-- should be refined into xs:nonNegativeInteger or mask,xs:nonNegativeInteger -->
+                <xs:element name="SourceProperties" type="SourcePropertiesType"/>
+                <xs:element name="SrcRect" type="RectType"/>
+                <xs:element name="DstRect" type="RectType"/>
+            </xs:choice>
+        </xs:sequence>
+    </xs:group>
+
+    <xs:complexType name="OpenOptionsType">
+        <xs:sequence>
+            <xs:element name="OOI" type="OOIType" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="OOIType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="key" type="xs:string" use="required"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="SimpleSourceType">
+        <xs:group ref="SimpleSourceElementsGroup"/>
+        <xs:attribute name="resampling" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:group name="ComplexSourceElementsGroup">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:group ref="SimpleSourceElementsGroup"/>
+                <xs:element name="ScaleOffset" type="xs:double"/>
+                <xs:element name="ScaleRatio" type="xs:double"/>
+                <xs:element name="ColorTableComponent" type="xs:nonNegativeInteger"/>
+                <xs:element name="Exponent" type="xs:double"/>
+                <xs:element name="SrcMin" type="xs:double"/>
+                <xs:element name="SrcMax" type="xs:double"/>
+                <xs:element name="DstMin" type="xs:double"/>
+                <xs:element name="DstMax" type="xs:double"/>
+                <xs:element name="NODATA" type="DoubleOrNanType"/>
+                <xs:element name="LUT" type="xs:string"/>
+            </xs:choice>
+        </xs:sequence>
+    </xs:group>
+
+    <xs:complexType name="ComplexSourceType">
+        <xs:group ref="ComplexSourceElementsGroup"/>
+        <xs:attribute name="resampling" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="KernelFilteredSourceType">
+        <xs:sequence>
+            <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:group ref="ComplexSourceElementsGroup"/>
+                <xs:element name="Kernel" type="KernelType"/>
+            </xs:choice>
+        </xs:sequence>
+        <xs:attribute name="resampling" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="KernelType">
+        <xs:all>
+            <xs:element name="Size" type="xs:nonNegativeInteger"/>
+            <xs:element name="Coefs" type="xs:string"/>
+        </xs:all>
+
+        <xs:attribute name="normalized" type="ZeroOrOne"/>
+    </xs:complexType>
+
+    <xs:simpleType name="DoubleOrNanType">
+        <xs:union memberTypes="xs:double NANType" />
+    </xs:simpleType>
+
+    <xs:simpleType name="NANType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="nan"/>
+            <xs:enumeration value="NAN"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="SourceFilenameType">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="relativeToVRT" type="ZeroOrOne" />
+                <xs:attribute name="relativetoVRT" type="ZeroOrOne" /> <!-- typo: deprecated -->
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="SourcePropertiesType">
+        <xs:attribute name="RasterXSize" type="nonNegativeInteger32" />
+        <xs:attribute name="RasterYSize" type="nonNegativeInteger32" />
+        <xs:attribute name="DataType" type="DataTypeType" />
+        <xs:attribute name="BlockXSize" type="nonNegativeInteger32" />
+        <xs:attribute name="BlockYSize" type="nonNegativeInteger32" />
+    </xs:complexType>
+
+    <xs:complexType name="RectType">
+        <xs:attribute name="xOff" type="xs:int" />
+        <xs:attribute name="yOff" type="xs:int" />
+        <xs:attribute name="xSize" type="xs:unsignedInt" />
+        <xs:attribute name="ySize" type="xs:unsignedInt" />
+    </xs:complexType>
+
+</xs:schema>
diff --git a/data/geoccs.csv b/data/geoccs.csv
index e8168da..3ad6cb9 100644
--- a/data/geoccs.csv
+++ b/data/geoccs.csv
@@ -45,7 +45,7 @@
 4468,RGM04,1036,Reseau Geodesique de Mayotte 2004,1036,9001,7019,8901,1,0,6500
 4473,Cadastre 1997,1037,Cadastre 1997,1037,9001,7022,8901,1,0,6500
 4479,China Geodetic Coordinate System 2000,1043,China 2000,1043,9001,1024,8901,1,0,6500
-4481,Mexican Datum of 1993,1042,Mexican Datum of 1993,1042,9001,7019,8901,1,0,6500
+4481,Mexico ITRF92,1042,Mexico ITRF92,1042,9001,7019,8901,1,0,6500
 4556,RRAF 1991,1047,Reseau de Reference des Antilles Francaises 1991,1047,9001,7019,8901,1,0,6500
 4882,Slovenia 1996,6765,Slovenia Geodetic Datum 1996,6765,9001,7019,8901,1,0,6500
 4884,RSRGD2000,6764,Ross Sea Region Geodetic Datum 2000,6764,9001,7019,8901,1,0,6500
@@ -130,3 +130,10 @@
 5828,"DB_REF",1081,Deutsche Bahn Reference System,1081,9001,7004,8901,1,0,6500
 5884,TGD2005,1095,Tonga Geodetic Datum 2005,1095,9001,7019,8901,1,0,6500
 6133,CIGD11,1100,Cayman Islands Geodetic Datum 2011,1100,9001,7019,8901,1,0,6500
+6317,"NAD83(2011)",1116,"NAD83 (National Spatial Reference System 2011)",1116,9001,7019,8901,1,0,6500
+6320,"NAD83(PA11)",1117,"NAD83 (National Spatial Reference System PA11)",1117,9001,7019,8901,1,0,6500
+6323,"NAD83(MA11)",1118,"NAD83 (National Spatial Reference System MA11)",1118,9001,7019,8901,1,0,6500
+6363,Mexico ITRF2008,1120,Mexico ITRF2008,1120,9001,7019,8901,1,0,6500
+6666,JGD2011,1128,Japanese Geodetic Datum 2011,1128,9001,7019,8901,1,0,6500
+6704,RDN2008,1132,Rete Dinamica Nazionale 2008,1132,9001,7019,8901,1,0,6500
+6781,"NAD83(CORS96)",1133,"NAD83 (Continuously Operating Reference Station 1996)",1133,9001,7019,8901,1,0,6500
diff --git a/data/gml_registry.xml b/data/gml_registry.xml
index 545326f..0efa105 100644
--- a/data/gml_registry.xml
+++ b/data/gml_registry.xml
@@ -22,6 +22,17 @@
         <featureType elementName="CadastralZoning"
                      gfsSchemaLocation="inspire_cp_CadastralZoning.gfs"/>
     </namespace>
+    <!-- sometimes with upper case namespace prefix -->
+    <namespace prefix="CP" uri="urn:x-inspire:specification:gmlas:CadastralParcels:3.0" useGlobalSRSName="true">
+        <featureType elementName="BasicPropertyUnit"
+                     gfsSchemaLocation="inspire_cp_BasicPropertyUnit.gfs"/>
+        <featureType elementName="CadastralBoundary"
+                     gfsSchemaLocation="inspire_cp_CadastralBoundary.gfs"/>
+        <featureType elementName="CadastralParcel"
+                     gfsSchemaLocation="inspire_cp_CadastralParcel.gfs"/>
+        <featureType elementName="CadastralZoning"
+                     gfsSchemaLocation="inspire_cp_CadastralZoning.gfs"/>
+    </namespace>
 
     <!-- Czech RUIAN (VFR) schema -->
     <namespace prefix="vf"
@@ -32,7 +43,7 @@
                      gfsSchemaLocation="ruian_vf_ob_v1.gfs" />
         <featureType elementName="TypSouboru"
                      elementValue="ST_Z"
-                     gfsSchemaLocation="ruian_vf_ob_v1.gfs" />
+                     gfsSchemaLocation="ruian_vf_v1.gfs" />
         <featureType elementName="TypSouboru"
                      elementValue="ST"
                      gfsSchemaLocation="ruian_vf_st_v1.gfs" />
diff --git a/data/nitf_spec.xml b/data/nitf_spec.xml
index 5f7d129..a201c62 100644
--- a/data/nitf_spec.xml
+++ b/data/nitf_spec.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 /******************************************************************************
- * $Id: nitf_spec.xml 27536 2014-07-16 08:01:29Z rouault $
+ * $Id: nitf_spec.xml 27535 2014-07-16 08:01:05Z rouault $
  *
  * Project:  NITF Library
  * Purpose:  Description of NITF TREs
diff --git a/data/ogrvrt.xsd b/data/ogrvrt.xsd
index 7e9aae4..0b0ebaa 100644
--- a/data/ogrvrt.xsd
+++ b/data/ogrvrt.xsd
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
 /******************************************************************************
- * $Id: ogrvrt.xsd 27000 2014-03-01 14:41:36Z rouault $
+ * $Id: ogrvrt.xsd 28950 2015-04-18 23:24:49Z rouault $
  *
  * Project:  GDAL/OGR
  * Purpose:  XML Schema for OGR VRT files.
@@ -34,6 +34,7 @@
         <xs:complexType>
             <xs:sequence>
                 <xs:choice minOccurs="0" maxOccurs="unbounded">
+                    <xs:element name="Metadata" type="MetadataType"/> <!-- may be repeated -->
                     <xs:element name="OGRVRTLayer" type="OGRVRTLayerType"/>
                     <xs:element name="OGRVRTWarpedLayer" type="OGRVRTWarpedLayerType"/>
                     <xs:element name="OGRVRTUnionLayer" type="OGRVRTUnionLayerType"/>
@@ -42,14 +43,31 @@
         </xs:complexType>
     </xs:element>
 
+    <xs:complexType name="MetadataType">
+        <xs:sequence>
+            <!--<xs:choice>-->
+                <!--<xs:element name="MDI" type="MDIType" minOccurs="0" maxOccurs="unbounded"/>-->
+                <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+            <!--</xs:choice>-->
+        </xs:sequence>
+        <xs:attribute name="domain" type="xs:string"/>
+        <xs:attribute name="format" type="xs:string"/>
+    </xs:complexType>
+
     <xs:complexType name="OGRVRTLayerType">
         <xs:sequence>
             <xs:choice minOccurs="0" maxOccurs="unbounded">
+                <xs:element name="Metadata" type="MetadataType"/> <!-- may be repeated -->
                 <xs:element name="SrcDataSource" type="SrcDataSourceType">
                     <xs:annotation>
                         <xs:documentation>Required element</xs:documentation>
                     </xs:annotation>
                 </xs:element>
+                <xs:element name="OpenOptions" type="OpenOptionsType">
+                    <xs:annotation>
+                        <xs:documentation>Optional element</xs:documentation>
+                    </xs:annotation>
+                </xs:element>
                 <xs:element name="SrcLayer" type="nonEmptyStringType">
                     <xs:annotation>
                         <xs:documentation>SrcLayer or(eclusive) SrcSQL are required elements</xs:documentation>
@@ -64,7 +82,7 @@
                         </xs:simpleContent>
                     </xs:complexType>
                 </xs:element>
-                <xs:element name="FID" type="nonEmptyStringType"/>
+                <xs:element name="FID" type="FIDType"/>
                 <xs:element name="Style" type="nonEmptyStringType"/>
                 <xs:element name="GeometryType" type="GeometryTypeType">
                     <xs:annotation>
@@ -107,6 +125,32 @@
         <xs:attribute name="name" type="nonEmptyStringType" use="required"/>
     </xs:complexType>
 
+    <xs:complexType name="OpenOptionsType">
+        <xs:sequence>
+            <xs:element name="OOI" type="OOIType" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="OOIType">
+        <xs:simpleContent>
+            <xs:extension base="nonEmptyStringType">
+                <xs:attribute name="key" type="xs:string"/>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:complexType name="FIDType">
+        <xs:simpleContent>
+            <xs:extension base="nonEmptyStringType">
+                <xs:attribute name="name" type="xs:string">
+                    <xs:annotation>
+                        <xs:documentation>A user-facing name can be specified here so that a FID column name is reported even if it is not reported as a regular field.</xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
     <xs:group name="ExtentType">
         <xs:sequence>
             <xs:element name="ExtentXMin" type="xs:double" minOccurs="1" maxOccurs="1"/>
@@ -152,6 +196,11 @@
             <xs:enumeration value="wkbMultiLineString"/>
             <xs:enumeration value="wkbMultiPolygon"/>
             <xs:enumeration value="wkbGeometryCollection"/>
+            <xs:enumeration value="wkbCircularString"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbCompoundCurve"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbCurvePolygon"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbMultiCurve"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbMultiSurface"/> <!-- new in GDAL 2.0 -->
             <xs:enumeration value="wkbPoint25D"/>
             <xs:enumeration value="wkbLineString25D"/>
             <xs:enumeration value="wkbPolygon25D"/>
@@ -159,14 +208,22 @@
             <xs:enumeration value="wkbMultiLineString25D"/>
             <xs:enumeration value="wkbMultiPolygon25D"/>
             <xs:enumeration value="wkbGeometryCollection25D"/>
+            <xs:enumeration value="wkbCircularStringZ"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbCompoundCurveZ"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbCurvePolygonZ"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbMultiCurveZ"/> <!-- new in GDAL 2.0 -->
+            <xs:enumeration value="wkbMultiSurfaceZ"/> <!-- new in GDAL 2.0 -->
         </xs:restriction>
     </xs:simpleType>
 
     <xs:complexType name="FieldTypeWithoutSrc">
         <xs:attribute name="name" type="nonEmptyStringType" use="required"/>
         <xs:attribute name="type" type="OGRFieldTypeType" default="String"/>
+        <xs:attribute name="subtype" type="OGRFieldSubTypeType" default="None"/>  <!-- new in GDAL 2.0 -->
         <xs:attribute name="width" type="xs:nonNegativeInteger"/>
         <xs:attribute name="precision" type="xs:nonNegativeInteger"/>
+        <xs:attribute name="nullable" type="OGRBooleanType" default="true"/>  <!-- new in GDAL 2.0 -->
+        <xs:attribute name="default" type="xs:string"/>  <!-- new in GDAL 2.0 -->
     </xs:complexType>
 
     <xs:complexType name="FieldType">
@@ -185,12 +242,16 @@
         <xs:restriction base="xs:string">
             <xs:enumeration value="Integer"/>
             <xs:enumeration value="integer"/>
+            <xs:enumeration value="Integer64"/>
+            <xs:enumeration value="integer64"/>
             <xs:enumeration value="Real"/>
             <xs:enumeration value="real"/>
             <xs:enumeration value="String"/>
             <xs:enumeration value="string"/>
             <xs:enumeration value="IntegerList"/>
             <xs:enumeration value="integerlist"/>
+            <xs:enumeration value="Integer64List"/>
+            <xs:enumeration value="integer64list"/>
             <xs:enumeration value="RealList"/>
             <xs:enumeration value="reallist"/>
             <xs:enumeration value="StringList"/>
@@ -206,6 +267,15 @@
         </xs:restriction>
     </xs:simpleType>
 
+    <xs:simpleType name="OGRFieldSubTypeType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="None"/>
+            <xs:enumeration value="Boolean"/>
+            <xs:enumeration value="Int16"/>
+            <xs:enumeration value="Float32"/>
+        </xs:restriction>
+    </xs:simpleType>
+
     <xs:simpleType name="EncodingType">
         <xs:restriction base="xs:string">
             <xs:enumeration value="Direct"/>
@@ -254,6 +324,7 @@
                 <xs:documentation>Only used if no Field element is found at the OGRVRTLayer level</xs:documentation>
             </xs:annotation>
         </xs:attribute>
+        <xs:attribute name="nullable" type="OGRBooleanType" default="true"/>  <!-- new in GDAL 2.0 -->
     </xs:attributeGroup>
 
     <xs:complexType name="GeometryFieldTypeWithoutSrc">
diff --git a/data/osmconf.ini b/data/osmconf.ini
index 81e0df7..998cb8b 100644
--- a/data/osmconf.ini
+++ b/data/osmconf.ini
@@ -46,6 +46,10 @@ osm_changeset=no
 
 # keys to report as OGR fields
 attributes=name,highway,waterway,aerialway,barrier,man_made
+
+# type of attribute 'foo' can be changed with something like
+#foo_type=Integer/Real/String/DateTime
+
 # keys that should NOT be reported in the "other_tags" field
 ignore=created_by,converted_by,source,time,ele,note,openGeoDB:,fixme,FIXME
 # uncomment to avoid creation of "other_tags" field
@@ -53,6 +57,13 @@ ignore=created_by,converted_by,source,time,ele,note,openGeoDB:,fixme,FIXME
 # uncomment to create "all_tags" field. "all_tags" and "other_tags" are exclusive
 #all_tags=yes
 
+#computed_attributes must appear before the keywords _type and _sql
+computed_attributes=z_order
+z_order_type=Integer
+# Formula based on https://github.com/openstreetmap/osm2pgsql/blob/master/style.lua#L13
+# [foo] is substituted by value of tag foo. When substitution is not wished, the [ character can be escaped with \[ in literals
+z_order_sql="SELECT (CASE [highway] WHEN 'minor' THEN 3 WHEN 'road' THEN 3 WHEN 'unclassified' THEN 3 WHEN 'residential' THEN 3 WHEN 'tertiary_link' THEN 4 WHEN 'tertiary' THEN 4 WHEN 'secondary_link' THEN 6 WHEN 'secondary' THEN 6 WHEN 'primary_link' THEN 7 WHEN 'primary' THEN 7 WHEN 'trunk_link' THEN 8 WHEN 'trunk' THEN 8 WHEN 'motorway_link' THEN 9 WHEN 'motorway' THEN 9 ELSE 0 END) + (CASE WHEN [bridge] IN ('yes', 'true', '1') THEN 10 ELSE 0 END) + (CASE WHEN [tunnel] IN ('yes', 'tru [...]
+
 [multipolygons]
 # common attributes
 # note: for multipolygons, osm_id=yes instanciates a osm_id field for the id of relations
diff --git a/data/pcs.csv b/data/pcs.csv
index 4ed4af0..b24a793 100644
--- a/data/pcs.csv
+++ b/data/pcs.csv
@@ -99,7 +99,7 @@
 2097,"Korean 1985 / Central Belt",9001,4162,18252,9807,1,0,4530,8801,38,9102,8802,127,9102,8805,1,9201,8806,200000,9001,8807,500000,9001,,,,,,
 2098,"Korean 1985 / West Belt",9001,4162,18253,9807,1,0,4530,8801,38,9102,8802,125,9102,8805,1,9201,8806,200000,9001,8807,500000,9001,,,,,,
 2099,"Qatar 1948 / Qatar Grid",9001,4286,19953,9806,1,0,4400,8801,25.22565,9110,8802,50.4541,9110,8806,100000,9001,8807,100000,9001,,,,,,,,,
-2100,"GGRS87 / Greek Grid",9001,4121,19930,9807,1,0,4400,8801,0,9102,8802,24,9110,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+2100,"GGRS87 / Greek Grid",9001,4121,19930,9807,1,0,4400,8801,0,9102,8802,24,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 2101,"Lake / Maracaibo Grid M1",9001,4249,18260,9801,1,0,4499,8801,10.1,9110,8802,-71.3620224,9110,8805,1,9201,8806,0,9001,8807,-52684.972,9001,,,,,,
 2102,"Lake / Maracaibo Grid",9001,4249,18261,9801,1,0,4499,8801,10.1,9110,8802,-71.3620224,9110,8805,1,9201,8806,200000,9001,8807,147315.028,9001,,,,,,
 2103,"Lake / Maracaibo Grid M3",9001,4249,18262,9801,1,0,4499,8801,10.1,9110,8802,-71.3620224,9110,8805,1,9201,8806,500000,9001,8807,447315.028,9001,,,,,,
@@ -981,10 +981,10 @@
 2988,"MOP78 / UTM zone 1S",9001,4639,16101,9807,1,0,4400,8801,0,9102,8802,-177,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 2989,"RRAF 1991 / UTM zone 20N",9001,4640,16020,9807,1,1,4400,8801,0,9102,8802,-63,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 2990,"Reunion 1947 / TM Reunion",9001,4626,19982,9807,1,1,4499,8801,-21.07,9110,8802,55.32,9110,8805,1,9201,8806,50000,9001,8807,160000,9001,,,,,,
-2991,"NAD83 / Oregon Lambert",9001,4269,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
-2992,"NAD83 / Oregon Lambert (ft)",9002,4269,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
-2993,"NAD83(HARN) / Oregon Lambert",9001,4152,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
-2994,"NAD83(HARN) / Oregon Lambert (ft)",9002,4152,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
+2991,"NAD83 / Oregon LCC (m)",9001,4269,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+2992,"NAD83 / Oregon GIC Lambert (ft)",9002,4269,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
+2993,"NAD83(HARN) / Oregon LCC (m)",9001,4152,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+2994,"NAD83(HARN) / Oregon GIC Lambert (ft)",9002,4152,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
 2995,"IGN53 Mare / UTM zone 58S",9001,4641,16158,9807,1,0,4400,8801,0,9102,8802,165,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 2996,"ST84 Ile des Pins / UTM zone 58S",9001,4642,16158,9807,1,0,4400,8801,0,9102,8802,165,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 2997,"ST71 Belep / UTM zone 58S",9001,4643,16158,9807,1,0,4400,8801,0,9102,8802,165,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
@@ -1407,22 +1407,22 @@
 3414,"SVY21 / Singapore TM",9001,4757,19864,9807,1,0,4500,8801,1.22,9110,8802,103.5,9110,8805,1,9201,8806,28001.642,9001,8807,38744.572,9001,,,,,,
 3415,"WGS 72BE / South China Sea Lambert",9001,4324,19863,9802,1,0,4400,8821,21,9102,8822,114,9102,8823,18,9102,8824,24,9102,8826,500000,9001,8827,500000,9001,,,
 3416,"ETRS89 / Austria Lambert",9001,4258,19947,9802,1,0,4530,8821,47.3,9110,8822,13.2,9110,8823,49,9110,8824,46,9110,8826,400000,9001,8827,400000,9001,,,
-3417,"NAD83 / Iowa North (ft US)",9003,4269,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
-3418,"NAD83 / Iowa South (ft US)",9003,4269,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
-3419,"NAD83 / Kansas North (ft US)",9003,4269,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
-3420,"NAD83 / Kansas South (ft US)",9003,4269,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
-3421,"NAD83 / Nevada East (ft US)",9003,4269,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
-3422,"NAD83 / Nevada Central (ft US)",9003,4269,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
-3423,"NAD83 / Nevada West (ft US)",9003,4269,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
-3424,"NAD83 / New Jersey (ft US)",9003,4269,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
-3425,"NAD83(HARN) / Iowa North (ft US)",9003,4152,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
-3426,"NAD83(HARN) / Iowa South (ft US)",9003,4152,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
-3427,"NAD83(HARN) / Kansas North (ft US)",9003,4152,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
-3428,"NAD83(HARN) / Kansas South (ft US)",9003,4152,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
-3429,"NAD83(HARN) / Nevada East (ft US)",9003,4152,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
-3430,"NAD83(HARN) / Nevada Central (ft US)",9003,4152,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
-3431,"NAD83(HARN) / Nevada West (ft US)",9003,4152,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
-3432,"NAD83(HARN) / New Jersey (ft US)",9003,4152,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
+3417,"NAD83 / Iowa North (ftUS)",9003,4269,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
+3418,"NAD83 / Iowa South (ftUS)",9003,4269,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
+3419,"NAD83 / Kansas North (ftUS)",9003,4269,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
+3420,"NAD83 / Kansas South (ftUS)",9003,4269,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
+3421,"NAD83 / Nevada East (ftUS)",9003,4269,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
+3422,"NAD83 / Nevada Central (ftUS)",9003,4269,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
+3423,"NAD83 / Nevada West (ftUS)",9003,4269,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
+3424,"NAD83 / New Jersey (ftUS)",9003,4269,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
+3425,"NAD83(HARN) / Iowa North (ftUS)",9003,4152,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
+3426,"NAD83(HARN) / Iowa South (ftUS)",9003,4152,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
+3427,"NAD83(HARN) / Kansas North (ftUS)",9003,4152,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
+3428,"NAD83(HARN) / Kansas South (ftUS)",9003,4152,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
+3429,"NAD83(HARN) / Nevada East (ftUS)",9003,4152,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
+3430,"NAD83(HARN) / Nevada Central (ftUS)",9003,4152,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
+3431,"NAD83(HARN) / Nevada West (ftUS)",9003,4152,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
+3432,"NAD83(HARN) / New Jersey (ftUS)",9003,4152,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
 3433,"NAD83 / Arkansas North (ftUS)",9003,4269,15385,9802,1,0,4497,8821,34.2,9110,8822,-92,9110,8823,36.14,9110,8824,34.56,9110,8826,1312333.3333,9003,8827,0,9003,,,
 3434,"NAD83 / Arkansas South (ftUS)",9003,4269,15386,9802,1,0,4497,8821,32.4,9110,8822,-92,9110,8823,34.46,9110,8824,33.18,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
 3435,"NAD83 / Illinois East (ftUS)",9003,4269,15387,9807,1,0,4497,8801,36.4,9110,8802,-88.2,9110,8805,0.999975,9201,8806,984250,9003,8807,0,9003,,,,,,
@@ -1527,13 +1527,13 @@
 3534,"NAD83(NSRS2007) / Indiana West",9001,4759,11332,9807,1,0,4499,8801,37.3,9110,8802,-87.05,9110,8805,0.999966667,9201,8806,900000,9001,8807,250000,9001,,,,,,
 3535,"NAD83(NSRS2007) / Indiana West (ftUS)",9003,4759,15373,9807,1,0,4497,8801,37.3,9110,8802,-87.05,9110,8805,0.999966667,9201,8806,2952750,9003,8807,820208.333,9003,,,,,,
 3536,"NAD83(NSRS2007) / Iowa North",9001,4759,11431,9802,1,0,4499,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,1500000,9001,8827,1000000,9001,,,
-3537,"NAD83(NSRS2007) / Iowa North (ft US)",9003,4759,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
+3537,"NAD83(NSRS2007) / Iowa North (ftUS)",9003,4759,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
 3538,"NAD83(NSRS2007) / Iowa South",9001,4759,11432,9802,1,0,4499,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,500000,9001,8827,0,9001,,,
-3539,"NAD83(NSRS2007) / Iowa South (ft US)",9003,4759,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
+3539,"NAD83(NSRS2007) / Iowa South (ftUS)",9003,4759,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
 3540,"NAD83(NSRS2007) / Kansas North",9001,4759,11531,9802,1,0,4499,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,400000,9001,8827,0,9001,,,
-3541,"NAD83(NSRS2007) / Kansas North (ft US)",9003,4759,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
+3541,"NAD83(NSRS2007) / Kansas North (ftUS)",9003,4759,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
 3542,"NAD83(NSRS2007) / Kansas South",9001,4759,11532,9802,1,0,4499,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,400000,9001,8827,400000,9001,,,
-3543,"NAD83(NSRS2007) / Kansas South (ft US)",9003,4759,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
+3543,"NAD83(NSRS2007) / Kansas South (ftUS)",9003,4759,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
 3544,"NAD83(NSRS2007) / Kentucky North",9001,4759,15303,9802,1,0,4499,8821,37.3,9110,8822,-84.15,9110,8823,37.58,9110,8824,38.58,9110,8826,500000,9001,8827,0,9001,,,
 3545,"NAD83(NSRS2007) / Kentucky North (ftUS)",9003,4759,15328,9802,1,0,4497,8821,37.3,9110,8822,-84.15,9110,8823,37.58,9110,8824,38.58,9110,8826,1640416.667,9003,8827,0,9003,,,
 3546,"NAD83(NSRS2007) / Kentucky Single Zone",9001,4759,11630,9802,1,0,4499,8821,36.2,9110,8822,-85.45,9110,8823,37.05,9110,8824,38.4,9110,8826,1500000,9001,8827,1000000,9001,,,
@@ -1550,17 +1550,17 @@
 3557,"NAD83(NSRS2007) / Maine East",9001,4759,11831,9807,1,0,4499,8801,43.4,9110,8802,-68.3,9110,8805,0.9999,9201,8806,300000,9001,8807,0,9001,,,,,,
 3558,"NAD83(NSRS2007) / Maine West",9001,4759,11832,9807,1,0,4499,8801,42.5,9110,8802,-70.1,9110,8805,0.999966667,9201,8806,900000,9001,8807,0,9001,,,,,,
 3559,"NAD83(NSRS2007) / Maryland",9001,4759,11930,9802,1,0,4499,8821,37.4,9110,8822,-77,9110,8823,39.27,9110,8824,38.18,9110,8826,400000,9001,8827,0,9001,,,
-3560,"NAD83 / Utah North (ftUS)",9003,4269,15297,9802,0,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
+3560,"NAD83 / Utah North (ftUS)",9003,4269,15297,9802,1,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
 3561,"Old Hawaiian / Hawaii zone 1",9003,4135,15101,9807,1,0,4497,8801,18.5,9110,8802,-155.3,9110,8805,0.999966667,9201,8806,500000,9003,8807,0,9003,,,,,,
 3562,"Old Hawaiian / Hawaii zone 2",9003,4135,15102,9807,1,0,4497,8801,20.2,9110,8802,-156.4,9110,8805,0.999966667,9201,8806,500000,9003,8807,0,9003,,,,,,
 3563,"Old Hawaiian / Hawaii zone 3",9003,4135,15103,9807,1,0,4497,8801,21.1,9110,8802,-158,9110,8805,0.99999,9201,8806,500000,9003,8807,0,9003,,,,,,
 3564,"Old Hawaiian / Hawaii zone 4",9003,4135,15104,9807,1,0,4497,8801,21.5,9110,8802,-159.3,9110,8805,0.99999,9201,8806,500000,9003,8807,0,9003,,,,,,
 3565,"Old Hawaiian / Hawaii zone 5",9003,4135,15105,9807,1,0,4497,8801,21.4,9110,8802,-160.1,9110,8805,1,9201,8806,500000,9003,8807,0,9003,,,,,,
-3566,"NAD83 / Utah Central (ftUS)",9003,4269,15298,9802,0,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
-3567,"NAD83 / Utah South (ftUS)",9003,4269,15299,9802,0,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
-3568,"NAD83(HARN) / Utah North (ftUS)",9003,4152,15297,9802,0,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
-3569,"NAD83(HARN) / Utah Central (ftUS)",9003,4152,15298,9802,0,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
-3570,"NAD83(HARN) / Utah South (ftUS)",9003,4152,15299,9802,0,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
+3566,"NAD83 / Utah Central (ftUS)",9003,4269,15298,9802,1,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
+3567,"NAD83 / Utah South (ftUS)",9003,4269,15299,9802,1,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
+3568,"NAD83(HARN) / Utah North (ftUS)",9003,4152,15297,9802,1,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
+3569,"NAD83(HARN) / Utah Central (ftUS)",9003,4152,15298,9802,1,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
+3570,"NAD83(HARN) / Utah South (ftUS)",9003,4152,15299,9802,1,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
 3571,"WGS 84 / North Pole LAEA Bering Sea",9001,4326,17295,9820,1,0,4464,8801,90,9102,8802,180,9102,8806,0,9001,8807,0,9001,,,,,,,,,
 3572,"WGS 84 / North Pole LAEA Alaska",9001,4326,17296,9820,1,0,4467,8801,90,9102,8802,-150,9102,8806,0,9001,8807,0,9001,,,,,,,,,
 3573,"WGS 84 / North Pole LAEA Canada",9001,4326,17297,9820,1,0,4466,8801,90,9102,8802,-100,9102,8806,0,9001,8807,0,9001,,,,,,,,,
@@ -1598,15 +1598,15 @@
 3605,"NAD83(NSRS2007) / Montana (ft)",9002,4759,15338,9802,1,0,4495,8821,44.15,9110,8822,-109.3,9110,8823,49,9110,8824,45,9110,8826,1968503.937,9002,8827,0,9002,,,
 3606,"NAD83(NSRS2007) / Nebraska",9001,4759,12630,9802,1,0,4499,8821,39.5,9110,8822,-100,9110,8823,43,9110,8824,40,9110,8826,500000,9001,8827,0,9001,,,
 3607,"NAD83(NSRS2007) / Nevada Central",9001,4759,12732,9807,1,0,4499,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,500000,9001,8807,6000000,9001,,,,,,
-3608,"NAD83(NSRS2007) / Nevada Central (ft US)",9003,4759,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
+3608,"NAD83(NSRS2007) / Nevada Central (ftUS)",9003,4759,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
 3609,"NAD83(NSRS2007) / Nevada East",9001,4759,12731,9807,1,0,4499,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,200000,9001,8807,8000000,9001,,,,,,
-3610,"NAD83(NSRS2007) / Nevada East (ft US)",9003,4759,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
+3610,"NAD83(NSRS2007) / Nevada East (ftUS)",9003,4759,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
 3611,"NAD83(NSRS2007) / Nevada West",9001,4759,12733,9807,1,0,4499,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,800000,9001,8807,4000000,9001,,,,,,
-3612,"NAD83(NSRS2007) / Nevada West (ft US)",9003,4759,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
+3612,"NAD83(NSRS2007) / Nevada West (ftUS)",9003,4759,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
 3613,"NAD83(NSRS2007) / New Hampshire",9001,4759,12830,9807,1,0,4499,8801,42.3,9110,8802,-71.4,9110,8805,0.999966667,9201,8806,300000,9001,8807,0,9001,,,,,,
 3614,"NAD83(NSRS2007) / New Hampshire (ftUS)",9003,4759,15389,9807,1,0,4497,8801,42.3,9110,8802,-71.4,9110,8805,0.999966667,9201,8806,984250,9003,8807,0,9003,,,,,,
 3615,"NAD83(NSRS2007) / New Jersey",9001,4759,12930,9807,1,0,4499,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,150000,9001,8807,0,9001,,,,,,
-3616,"NAD83(NSRS2007) / New Jersey (ft US)",9003,4759,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
+3616,"NAD83(NSRS2007) / New Jersey (ftUS)",9003,4759,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
 3617,"NAD83(NSRS2007) / New Mexico Central",9001,4759,13032,9807,1,0,4499,8801,31,9110,8802,-106.15,9110,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
 3618,"NAD83(NSRS2007) / New Mexico Central (ftUS)",9003,4759,15340,9807,1,0,4497,8801,31,9110,8802,-106.15,9110,8805,0.9999,9201,8806,1640416.667,9003,8807,0,9003,,,,,,
 3619,"NAD83(NSRS2007) / New Mexico East",9001,4759,13031,9807,1,0,4499,8801,31,9110,8802,-104.2,9110,8805,0.999909091,9201,8806,165000,9001,8807,0,9001,,,,,,
@@ -1633,8 +1633,8 @@
 3640,"NAD83(NSRS2007) / Oklahoma North (ftUS)",9003,4759,15349,9802,1,0,4497,8821,35,9110,8822,-98,9110,8823,36.46,9110,8824,35.34,9110,8826,1968500,9003,8827,0,9003,,,
 3641,"NAD83(NSRS2007) / Oklahoma South",9001,4759,13532,9802,1,0,4499,8821,33.2,9110,8822,-98,9110,8823,35.14,9110,8824,33.56,9110,8826,600000,9001,8827,0,9001,,,
 3642,"NAD83(NSRS2007) / Oklahoma South (ftUS)",9003,4759,15350,9802,1,0,4497,8821,33.2,9110,8822,-98,9110,8823,35.14,9110,8824,33.56,9110,8826,1968500,9003,8827,0,9003,,,
-3643,"NAD83(NSRS2007) / Oregon Lambert",9001,4759,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
-3644,"NAD83(NSRS2007) / Oregon Lambert (ft)",9002,4759,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
+3643,"NAD83(NSRS2007) / Oregon LCC (m)",9001,4759,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+3644,"NAD83(NSRS2007) / Oregon GIC Lambert (ft)",9002,4759,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
 3645,"NAD83(NSRS2007) / Oregon North",9001,4759,13631,9802,1,0,4499,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,2500000,9001,8827,0,9001,,,
 3646,"NAD83(NSRS2007) / Oregon North (ft)",9002,4759,15351,9802,1,0,4495,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,8202099.738,9002,8827,0,9002,,,
 3647,"NAD83(NSRS2007) / Oregon South",9001,4759,13632,9802,1,0,4499,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,1500000,9001,8827,0,9001,,,
@@ -1667,13 +1667,13 @@
 3674,"NAD83(NSRS2007) / Texas South Central (ftUS)",9003,4759,15360,9802,1,0,4497,8821,27.5,9110,8822,-99,9110,8823,30.17,9110,8824,28.23,9110,8826,1968500,9003,8827,13123333.333,9003,,,
 3675,"NAD83(NSRS2007) / Utah Central",9001,4759,14332,9802,1,0,4499,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,500000,9001,8827,2000000,9001,,,
 3676,"NAD83(NSRS2007) / Utah Central (ft)",9002,4759,15363,9802,0,0,4495,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640419.948,9002,8827,6561679.79,9002,,,
-3677,"NAD83(NSRS2007) / Utah Central (ftUS)",9003,4759,15298,9802,0,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
+3677,"NAD83(NSRS2007) / Utah Central (ftUS)",9003,4759,15298,9802,1,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
 3678,"NAD83(NSRS2007) / Utah North",9001,4759,14331,9802,1,0,4499,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,500000,9001,8827,1000000,9001,,,
 3679,"NAD83(NSRS2007) / Utah North (ft)",9002,4759,15362,9802,0,0,4495,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640419.948,9002,8827,3280839.895,9002,,,
-3680,"NAD83(NSRS2007) / Utah North (ftUS)",9003,4759,15297,9802,0,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
+3680,"NAD83(NSRS2007) / Utah North (ftUS)",9003,4759,15297,9802,1,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
 3681,"NAD83(NSRS2007) / Utah South",9001,4759,14333,9802,1,0,4499,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,500000,9001,8827,3000000,9001,,,
 3682,"NAD83(NSRS2007) / Utah South (ft)",9002,4759,15364,9802,0,0,4495,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640419.948,9002,8827,9842519.685,9002,,,
-3683,"NAD83(NSRS2007) / Utah South (ftUS)",9003,4759,15299,9802,0,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
+3683,"NAD83(NSRS2007) / Utah South (ftUS)",9003,4759,15299,9802,1,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
 3684,"NAD83(NSRS2007) / Vermont",9001,4759,14430,9807,1,0,4499,8801,42.3,9110,8802,-72.3,9110,8805,0.999964286,9201,8806,500000,9001,8807,0,9001,,,,,,
 3685,"NAD83(NSRS2007) / Virginia North",9001,4759,14531,9802,1,0,4499,8821,37.4,9110,8822,-78.3,9110,8823,39.12,9110,8824,38.02,9110,8826,3500000,9001,8827,2000000,9001,,,
 3686,"NAD83(NSRS2007) / Virginia North (ftUS)",9003,4759,15365,9802,1,0,4497,8821,37.4,9110,8822,-78.3,9110,8823,39.12,9110,8824,38.02,9110,8826,11482916.667,9003,8827,6561666.667,9003,,,
@@ -1948,12 +1948,12 @@
 4467,"RGSPM06 / UTM zone 21N",9001,4463,16021,9807,1,0,4400,8801,0,9102,8802,-57,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 4471,"RGM04 / UTM zone 38S",9001,4470,16138,9807,1,0,4400,8801,0,9102,8802,45,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 4474,"Cadastre 1997 / UTM zone 38S",9001,4632,16138,9807,1,1,4400,8801,0,9102,8802,45,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
-4484,"Mexican Datum of 1993 / UTM zone 11N",9001,4483,16011,9807,1,0,4400,8801,0,9102,8802,-117,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
-4485,"Mexican Datum of 1993 / UTM zone 12N",9001,4483,16012,9807,1,0,4400,8801,0,9102,8802,-111,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
-4486,"Mexican Datum of 1993 / UTM zone 13N",9001,4483,16013,9807,1,0,4400,8801,0,9102,8802,-105,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
-4487,"Mexican Datum of 1993 / UTM zone 14N",9001,4483,16014,9807,1,0,4400,8801,0,9102,8802,-99,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
-4488,"Mexican Datum of 1993 / UTM zone 15N",9001,4483,16015,9807,1,0,4400,8801,0,9102,8802,-93,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
-4489,"Mexican Datum of 1993 / UTM zone 16N",9001,4483,16016,9807,1,0,4400,8801,0,9102,8802,-87,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4484,"Mexico ITRF92 / UTM zone 11N",9001,4483,16011,9807,1,0,4400,8801,0,9102,8802,-117,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4485,"Mexico ITRF92 / UTM zone 12N",9001,4483,16012,9807,1,0,4400,8801,0,9102,8802,-111,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4486,"Mexico ITRF92 / UTM zone 13N",9001,4483,16013,9807,1,0,4400,8801,0,9102,8802,-105,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4487,"Mexico ITRF92 / UTM zone 14N",9001,4483,16014,9807,1,0,4400,8801,0,9102,8802,-99,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4488,"Mexico ITRF92 / UTM zone 15N",9001,4483,16015,9807,1,0,4400,8801,0,9102,8802,-93,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+4489,"Mexico ITRF92 / UTM zone 16N",9001,4483,16016,9807,1,0,4400,8801,0,9102,8802,-87,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 4491,"CGCS2000 / Gauss-Kruger zone 13",9001,4490,16213,9807,1,0,4530,8801,0,9102,8802,75,9102,8805,1,9201,8806,13500000,9001,8807,0,9001,,,,,,
 4492,"CGCS2000 / Gauss-Kruger zone 14",9001,4490,16214,9807,1,0,4530,8801,0,9102,8802,81,9102,8805,1,9201,8806,14500000,9001,8807,0,9001,,,,,,
 4493,"CGCS2000 / Gauss-Kruger zone 15",9001,4490,16215,9807,1,0,4530,8801,0,9102,8802,87,9102,8805,1,9201,8806,15500000,9001,8807,0,9001,,,,,,
@@ -2288,20 +2288,20 @@
 5567,"UCS-2000 / Gauss-Kruger CM 27E",9001,5561,16305,9807,1,0,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
 5568,"UCS-2000 / Gauss-Kruger CM 33E",9001,5561,16306,9807,1,0,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
 5569,"UCS-2000 / Gauss-Kruger CM 39E",9001,5561,16307,9807,1,0,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5570,"UCS-2000 / 3-degree Gauss-Kruger zone 7",9001,5561,16267,9807,1,0,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,7500000,9001,8807,0,9001,,,,,,
-5571,"UCS-2000 / 3-degree Gauss-Kruger zone 8",9001,5561,16268,9807,1,0,4530,8801,0,9102,8802,24,9102,8805,1,9201,8806,8500000,9001,8807,0,9001,,,,,,
-5572,"UCS-2000 / 3-degree Gauss-Kruger zone 9",9001,5561,16269,9807,1,0,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,9500000,9001,8807,0,9001,,,,,,
-5573,"UCS-2000 / 3-degree Gauss-Kruger zone 10",9001,5561,16270,9807,1,0,4530,8801,0,9102,8802,30,9102,8805,1,9201,8806,10500000,9001,8807,0,9001,,,,,,
-5574,"UCS-2000 / 3-degree Gauss-Kruger zone 11",9001,5561,16271,9807,1,0,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,11500000,9001,8807,0,9001,,,,,,
-5575,"UCS-2000 / 3-degree Gauss-Kruger zone 12",9001,5561,16272,9807,1,0,4530,8801,0,9102,8802,36,9102,8805,1,9201,8806,12500000,9001,8807,0,9001,,,,,,
-5576,"UCS-2000 / 3-degree Gauss-Kruger zone 13",9001,5561,16273,9807,1,0,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,13500000,9001,8807,0,9001,,,,,,
-5577,"UCS-2000 / 3-degree Gauss-Kruger CM 21E",9001,5561,16304,9807,1,0,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5578,"UCS-2000 / 3-degree Gauss-Kruger CM 24E",9001,5561,16368,9807,1,0,4530,8801,0,9102,8802,24,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5579,"UCS-2000 / 3-degree Gauss-Kruger CM 27E",9001,5561,16305,9807,1,0,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5580,"UCS-2000 / 3-degree Gauss-Kruger CM 30E",9001,5561,16370,9807,1,0,4530,8801,0,9102,8802,30,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5581,"UCS-2000 / 3-degree Gauss-Kruger CM 33E",9001,5561,16306,9807,1,0,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5582,"UCS-2000 / 3-degree Gauss-Kruger CM 36E",9001,5561,16372,9807,1,0,4530,8801,0,9102,8802,36,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
-5583,"UCS-2000 / 3-degree Gauss-Kruger CM 39E",9001,5561,16307,9807,1,0,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5570,"UCS-2000 / 3-degree Gauss-Kruger zone 7",9001,5561,16267,9807,1,1,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,7500000,9001,8807,0,9001,,,,,,
+5571,"UCS-2000 / 3-degree Gauss-Kruger zone 8",9001,5561,16268,9807,1,1,4530,8801,0,9102,8802,24,9102,8805,1,9201,8806,8500000,9001,8807,0,9001,,,,,,
+5572,"UCS-2000 / 3-degree Gauss-Kruger zone 9",9001,5561,16269,9807,1,1,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,9500000,9001,8807,0,9001,,,,,,
+5573,"UCS-2000 / 3-degree Gauss-Kruger zone 10",9001,5561,16270,9807,1,1,4530,8801,0,9102,8802,30,9102,8805,1,9201,8806,10500000,9001,8807,0,9001,,,,,,
+5574,"UCS-2000 / 3-degree Gauss-Kruger zone 11",9001,5561,16271,9807,1,1,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,11500000,9001,8807,0,9001,,,,,,
+5575,"UCS-2000 / 3-degree Gauss-Kruger zone 12",9001,5561,16272,9807,1,1,4530,8801,0,9102,8802,36,9102,8805,1,9201,8806,12500000,9001,8807,0,9001,,,,,,
+5576,"UCS-2000 / 3-degree Gauss-Kruger zone 13",9001,5561,16273,9807,1,1,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,13500000,9001,8807,0,9001,,,,,,
+5577,"UCS-2000 / 3-degree Gauss-Kruger CM 21E",9001,5561,16304,9807,1,1,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5578,"UCS-2000 / 3-degree Gauss-Kruger CM 24E",9001,5561,16368,9807,1,1,4530,8801,0,9102,8802,24,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5579,"UCS-2000 / 3-degree Gauss-Kruger CM 27E",9001,5561,16305,9807,1,1,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5580,"UCS-2000 / 3-degree Gauss-Kruger CM 30E",9001,5561,16370,9807,1,1,4530,8801,0,9102,8802,30,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5581,"UCS-2000 / 3-degree Gauss-Kruger CM 33E",9001,5561,16306,9807,1,1,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5582,"UCS-2000 / 3-degree Gauss-Kruger CM 36E",9001,5561,16372,9807,1,1,4530,8801,0,9102,8802,36,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+5583,"UCS-2000 / 3-degree Gauss-Kruger CM 39E",9001,5561,16307,9807,1,1,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
 5588,"NAD27 / New Brunswick Stereographic (NAD27)",9002,4267,5587,9809,1,0,1029,8801,46.3,9110,8802,-66.3,9110,8805,0.999912,9201,8806,1000000,9002,8807,1000000,9002,,,,,,
 5589,"Sibun Gorge 1922 / Colony Grid",9005,5464,5465,9807,1,0,4403,8801,17.0340471,9110,8802,-88.3754687,9110,8805,1,9201,8806,217259.26,9005,8807,445474.83,9005,,,,,,
 5596,"FEH2010 / Fehmarnbelt TM",9001,5593,5595,9807,1,0,4400,8801,0,9110,8802,11.2,9110,8805,1,9201,8806,1000000,9001,8807,0,9001,,,,,,
@@ -2469,7 +2469,386 @@
 6125,"ETRS89 / EPSG Arctic zone 5-47",9001,4258,6038,9802,1,0,4400,8821,72.01300331,9110,8822,-5,9110,8823,73.4,9110,8824,70.2,9110,8826,47500000,9001,8827,5500000,9001,,,
 6128,Grand Cayman National Grid 1959,9002,4723,6127,9807,1,0,1039,8801,0,9102,8802,-81,9102,8805,0.9996,9201,8806,1640419.9475,9002,8807,0,9002,,,,,,
 6129,Sister Islands National Grid 1961,9002,4726,6127,9807,1,0,1039,8801,0,9102,8802,-81,9102,8805,0.9996,9201,8806,1640419.9475,9002,8807,0,9002,,,,,,
-6141,Cayman Islands National Grid 2011,9002,6135,6126,9802,1,0,1039,8821,19.2,9110,8822,80.34,9110,8823,19.2,9110,8824,19.42,9110,8826,2950000,9002,8827,1900000,9002,,,
+6141,Cayman Islands National Grid 2011,9002,6135,6126,9802,1,1,1039,8821,19.2,9110,8822,80.34,9110,8823,19.2,9110,8824,19.42,9110,8826,2950000,9002,8827,1900000,9002,,,
+6200,"NAD27 / Michigan North",9003,4267,6197,1051,1,0,4497,1038,1.0000382,9201,8821,44.87,9110,8822,-87,9110,8823,45.29,9110,8824,47.05,9110,8826,2000000,9003,8827,0,9003
+6201,"NAD27 / Michigan Central",9003,4267,6198,1051,1,0,4497,1038,1.0000382,9201,8821,43.19,9110,8822,-84.2,9110,8823,44.11,9110,8824,45.42,9110,8826,2000000,9003,8827,0,9003
+6202,"NAD27 / Michigan South",9003,4267,6199,1051,1,0,4497,1038,1.0000382,9201,8821,41.3,9110,8822,-84.2,9110,8823,42.06,9110,8824,43.4,9110,8826,2000000,9003,8827,0,9003
+6204,Macedonian State Coordinate System,9001,3906,6203,9807,1,0,4498,8801,0,9102,8802,21,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6210,"SIRGAS 2000 / UTM zone 23N",9001,4674,16023,9807,1,0,4400,8801,0,9102,8802,-45,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6211,"SIRGAS 2000 / UTM zone 24N",9001,4674,16024,9807,1,0,4400,8801,0,9102,8802,-39,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6244,"MAGNA-SIRGAS / Arauca urban grid",9001,4686,6212,1052,1,0,4500,1039,100,9001,8801,7.051538301,9110,8802,-70.452991476,9110,8806,1035263.443,9001,8807,1275526.621,9001,,,,,,
+6245,"MAGNA-SIRGAS / Armenia urban grid",9001,4686,6213,1052,1,0,4500,1039,1470,9001,8801,4.315637,9110,8802,-75.4024561,9110,8806,1155824.666,9001,8807,993087.465,9001,,,,,,
+6246,"MAGNA-SIRGAS / Barranquilla urban grid",9001,4686,6214,1052,1,0,4500,1039,100,9001,8801,10.55234591,9110,8802,-74.50035928,9110,8806,917264.406,9001,8807,1699839.935,9001,,,,,,
+6247,"MAGNA-SIRGAS / Bogota urban grid",9001,4686,6215,1052,1,0,4500,1039,2550,9001,8801,4.404975,9110,8802,-74.084773,9110,8806,92334.879,9001,8807,109320.965,9001,,,,,,
+6248,"MAGNA-SIRGAS / Bucaramanga urban grid",9001,4686,6216,1052,1,0,4500,1039,931,9001,8801,7.044399371,9110,8802,-73.11504356,9110,8806,1097241.305,9001,8807,1274642.278,9001,,,,,,
+6249,"MAGNA-SIRGAS / Cali urban grid",9001,4686,6217,1052,1,0,4500,1039,1000,9001,8801,3.263078,9110,8802,-76.3114025,9110,8806,1061900.18,9001,8807,872364.63,9001,,,,,,
+6250,"MAGNA-SIRGAS / Cartagena urban grid",9001,4686,6218,1052,1,0,4500,1039,0,9001,8801,10.2349371,9110,8802,-75.3040345,9110,8806,842981.41,9001,8807,1641887.09,9001,,,,,,
+6251,"MAGNA-SIRGAS / Cucuta urban grid",9001,4686,6219,1052,1,0,4500,1039,308,9001,8801,7.532017225,9110,8802,-72.301033542,9110,8806,842805.406,9001,8807,1364404.57,9001,,,,,,
+6252,"MAGNA-SIRGAS / Florencia urban grid",9001,4686,6220,1052,1,0,4500,1039,300,9001,8801,1.371564426,9110,8802,-75.370882337,9110,8806,1162300.348,9001,8807,671068.716,9001,,,,,,
+6253,"MAGNA-SIRGAS / Ibague urban grid",9001,4686,6221,1052,1,0,4500,1039,1100,9001,8801,4.250988618,9110,8802,-75.104773336,9110,8806,877634.33,9001,8807,980541.348,9001,,,,,,
+6254,"MAGNA-SIRGAS / Inirida urban grid",9001,4686,6222,1052,1,0,4500,1039,96,9001,8801,3.504357746,9110,8802,-67.541883552,9110,8806,1019177.687,9001,8807,491791.326,9001,,,,,,
+6255,"MAGNA-SIRGAS / Leticia urban grid",9001,4686,6223,1052,1,0,4500,1039,89.7,9001,8801,-4.115166257,9110,8802,-69.563411981,9110,8806,25978.217,9001,8807,27501.365,9001,,,,,,
+6256,"MAGNA-SIRGAS / Manizales urban grid",9001,4686,6224,1052,1,0,4500,1039,2100,9001,8801,5.0405354,9110,8802,-75.3039941,9110,8806,1173727.04,9001,8807,1052391.13,9001,,,,,,
+6257,"MAGNA-SIRGAS / Medellin urban grid",9001,4686,6225,1052,1,0,4500,1039,1510,9001,8801,6.1345152,9110,8802,-75.3353593,9110,8806,835378.647,9001,8807,1180816.875,9001,,,,,,
+6258,"MAGNA-SIRGAS / Mitu urban grid",9001,4686,6226,1052,1,0,4500,1039,170,9001,8801,1.145988972,9110,8802,-70.140766196,9110,8806,1093717.398,9001,8807,629997.236,9001,,,,,,
+6259,"MAGNA-SIRGAS / Mocoa urban grid",9001,4686,6227,1052,1,0,4500,1039,655.2,9001,8801,1.082408409,9110,8802,-76.390367639,9110,8806,1047467.388,9001,8807,617828.474,9001,,,,,,
+6260,"MAGNA-SIRGAS / Monteria urban grid",9001,4686,6228,1052,1,0,4500,1039,15,9001,8801,8.462310872,9110,8802,-75.524639199,9110,8806,1131814.934,9001,8807,1462131.119,9001,,,,,,
+6261,"MAGNA-SIRGAS / Neiva urban grid",9001,4686,6229,1052,1,0,4500,1039,430,9001,8801,2.56326942,9110,8802,-75.17471722,9110,8806,864476.923,9001,8807,817199.827,9001,,,,,,
+6262,"MAGNA-SIRGAS / Pasto urban grid",9001,4686,6230,1052,1,0,4500,1039,2530,9001,8801,1.120356225,9110,8802,-77.151125228,9110,8806,980469.695,9001,8807,624555.332,9001,,,,,,
+6263,"MAGNA-SIRGAS / Pereira urban grid",9001,4686,6231,1052,1,0,4500,1039,1500,9001,8801,4.4848937,9110,8802,-75.4138225,9110,8806,1153492.012,9001,8807,1024195.255,9001,,,,,,
+6264,"MAGNA-SIRGAS / Popayan urban grid",9001,4686,6232,1052,1,0,4500,1039,1740,9001,8801,2.272217558,9110,8802,-76.362192989,9110,8806,1052430.525,9001,8807,763366.548,9001,,,,,,
+6265,"MAGNA-SIRGAS / Puerto Carreno urban grid",9001,4686,6233,1052,1,0,4500,1039,51.58,9001,8801,6.105059709,9110,8802,-67.300270089,9110,8806,1063834.703,9001,8807,1175257.481,9001,,,,,,
+6266,"MAGNA-SIRGAS / Quibdo urban grid",9001,4686,6234,1052,1,0,4500,1039,44,9001,8801,5.413929158,9110,8802,-76.390271389,9110,8806,1047273.617,9001,8807,1121443.09,9001,,,,,,
+6267,"MAGNA-SIRGAS / Riohacha urban grid",9001,4686,6235,1052,1,0,4500,1039,6,9001,8801,11.321288798,9110,8802,-72.540996793,9110,8806,1128154.73,9001,8807,1767887.914,9001,,,,,,
+6268,"MAGNA-SIRGAS / San Andres urban grid",9001,4686,6236,1052,1,0,4500,1039,6,9001,8801,12.312565957,9110,8802,-81.434575342,9110,8806,820439.298,9001,8807,1877357.828,9001,,,,,,
+6269,"MAGNA-SIRGAS / San Jose del Guaviare urban grid",9001,4686,6237,1052,1,0,4500,1039,185,9001,8801,2.335068419,9110,8802,-72.382411997,9110,8806,1159876.62,9001,8807,775380.342,9001,,,,,,
+6270,"MAGNA-SIRGAS / Santa Marta urban grid",9001,4686,6238,1052,1,0,4500,1039,29,9001,8801,11.1310715,9110,8802,-74.1330019,9110,8806,983892.409,9001,8807,1732533.518,9001,,,,,,
+6271,"MAGNA-SIRGAS / Sucre urban grid",9001,4686,6239,1052,1,0,4500,1039,20,9001,8801,8.483798132,9110,8802,-74.432088057,9110,8806,929043.607,9001,8807,1466125.658,9001,,,,,,
+6272,"MAGNA-SIRGAS / Tunja urban grid",9001,4686,6240,1052,1,0,4500,1039,2800,9001,8801,5.320310106,9110,8802,-73.210698004,9110,8806,1080514.91,9001,8807,1103772.028,9001,,,,,,
+6273,"MAGNA-SIRGAS / Valledupar urban grid",9001,4686,6241,1052,1,0,4500,1039,200,9001,8801,10.265014,9110,8802,-73.1447657,9110,8806,1090979.66,9001,8807,1647208.93,9001,,,,,,
+6274,"MAGNA-SIRGAS / Villavicencio urban grid",9001,4686,6242,1052,1,0,4500,1039,427.19,9001,8801,4.091935036,9110,8802,-73.372814955,9110,8806,1050678.757,9001,8807,950952.124,9001,,,,,,
+6275,"MAGNA-SIRGAS / Yopal urban grid",9001,4686,6243,1052,1,0,4500,1039,300,9001,8801,5.2114138,9110,8802,-72.2512145,9110,8806,851184.177,9001,8807,1083954.137,9001,,,,,,
+6316,Macedonia State Coordinate System zone 7,9001,3906,18277,9807,1,0,4498,8801,0,9102,8802,21,9102,8805,0.9999,9201,8806,7500000,9001,8807,0,9001,,,,,,
+6328,"NAD83(2011) / UTM zone 59N",9001,6318,16059,9807,1,0,4400,8801,0,9102,8802,171,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6329,"NAD83(2011) / UTM zone 60N",9001,6318,16060,9807,1,0,4400,8801,0,9102,8802,177,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6330,"NAD83(2011) / UTM zone 1N",9001,6318,16001,9807,1,0,4400,8801,0,9102,8802,-177,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6331,"NAD83(2011) / UTM zone 2N",9001,6318,16002,9807,1,0,4400,8801,0,9102,8802,-171,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6332,"NAD83(2011) / UTM zone 3N",9001,6318,16003,9807,1,0,4400,8801,0,9102,8802,-165,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6333,"NAD83(2011) / UTM zone 4N",9001,6318,16004,9807,1,0,4400,8801,0,9102,8802,-159,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6334,"NAD83(2011) / UTM zone 5N",9001,6318,16005,9807,1,0,4400,8801,0,9102,8802,-153,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6335,"NAD83(2011) / UTM zone 6N",9001,6318,16006,9807,1,0,4400,8801,0,9102,8802,-147,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6336,"NAD83(2011) / UTM zone 7N",9001,6318,16007,9807,1,0,4400,8801,0,9102,8802,-141,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6337,"NAD83(2011) / UTM zone 8N",9001,6318,16008,9807,1,0,4400,8801,0,9102,8802,-135,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6338,"NAD83(2011) / UTM zone 9N",9001,6318,16009,9807,1,0,4400,8801,0,9102,8802,-129,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6339,"NAD83(2011) / UTM zone 10N",9001,6318,16010,9807,1,0,4400,8801,0,9102,8802,-123,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6340,"NAD83(2011) / UTM zone 11N",9001,6318,16011,9807,1,0,4400,8801,0,9102,8802,-117,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6341,"NAD83(2011) / UTM zone 12N",9001,6318,16012,9807,1,0,4400,8801,0,9102,8802,-111,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6342,"NAD83(2011) / UTM zone 13N",9001,6318,16013,9807,1,0,4400,8801,0,9102,8802,-105,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6343,"NAD83(2011) / UTM zone 14N",9001,6318,16014,9807,1,0,4400,8801,0,9102,8802,-99,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6344,"NAD83(2011) / UTM zone 15N",9001,6318,16015,9807,1,0,4400,8801,0,9102,8802,-93,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6345,"NAD83(2011) / UTM zone 16N",9001,6318,16016,9807,1,0,4400,8801,0,9102,8802,-87,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6346,"NAD83(2011) / UTM zone 17N",9001,6318,16017,9807,1,0,4400,8801,0,9102,8802,-81,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6347,"NAD83(2011) / UTM zone 18N",9001,6318,16018,9807,1,0,4400,8801,0,9102,8802,-75,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6348,"NAD83(2011) / UTM zone 19N",9001,6318,16019,9807,1,0,4400,8801,0,9102,8802,-69,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6350,"NAD83(2011) / Conus Albers",9001,6318,5068,9822,1,0,4499,8821,23,9102,8822,-96,9102,8823,29.3,9110,8824,45.3,9110,8826,0,9001,8827,0,9001,,,
+6351,"NAD83(2011) / EPSG Arctic zone 5-29",9001,6318,6029,9802,1,0,4400,8821,72.01300331,9110,8822,-163,9110,8823,73.4,9110,8824,70.2,9110,8826,29500000,9001,8827,5500000,9001,,,
+6352,"NAD83(2011) / EPSG Arctic zone 5-31",9001,6318,6030,9802,1,0,4400,8821,72.01300331,9110,8822,-147,9110,8823,73.4,9110,8824,70.2,9110,8826,31500000,9001,8827,5500000,9001,,,
+6353,"NAD83(2011) / EPSG Arctic zone 6-14",9001,6318,6039,9802,1,0,4400,8821,68.4114912,9110,8822,-165,9110,8823,70.2,9110,8824,67,9110,8826,14500000,9001,8827,6500000,9001,,,
+6354,"NAD83(2011) / EPSG Arctic zone 6-16",9001,6318,6040,9802,1,0,4400,8821,68.4114912,9110,8822,-147,9110,8823,70.2,9110,8824,67,9110,8826,16500000,9001,8827,6500000,9001,,,
+6355,"NAD83(2011) / Alabama East",9001,6318,10131,9807,1,0,4499,8801,30.3,9110,8802,-85.5,9110,8805,0.99996,9201,8806,200000,9001,8807,0,9001,,,,,,
+6356,"NAD83(2011) / Alabama West",9001,6318,10132,9807,1,0,4499,8801,30,9110,8802,-87.3,9110,8805,0.999933333,9201,8806,600000,9001,8807,0,9001,,,,,,
+6362,"Mexico ITRF92 / LCC",9001,4483,6361,9802,1,0,4500,8821,12,9102,8822,-102,9102,8823,17.5,9102,8824,29.5,9102,8826,2500000,9001,8827,0,9001,,,
+6366,"Mexico ITRF2008 / UTM zone 11N",9001,6365,16011,9807,1,0,4400,8801,0,9102,8802,-117,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6367,"Mexico ITRF2008 / UTM zone 12N",9001,6365,16012,9807,1,0,4400,8801,0,9102,8802,-111,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6368,"Mexico ITRF2008 / UTM zone 13N",9001,6365,16013,9807,1,0,4400,8801,0,9102,8802,-105,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6369,"Mexico ITRF2008 / UTM zone 14N",9001,6365,16014,9807,1,0,4400,8801,0,9102,8802,-99,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6370,"Mexico ITRF2008 / UTM zone 15N",9001,6365,16015,9807,1,0,4400,8801,0,9102,8802,-93,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6371,"Mexico ITRF2008 / UTM zone 16N",9001,6365,16016,9807,1,0,4400,8801,0,9102,8802,-87,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6372,"Mexico ITRF2008 / LCC",9001,6365,6361,9802,1,0,4500,8821,12,9102,8822,-102,9102,8823,17.5,9102,8824,29.5,9102,8826,2500000,9001,8827,0,9001,,,
+6381,"UCS-2000 / Ukraine TM zone 7",9001,5561,6374,9807,1,0,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6382,"UCS-2000 / Ukraine TM zone 8",9001,5561,6375,9807,1,0,4530,8801,0,9102,8802,24,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6383,"UCS-2000 / Ukraine TM zone 9",9001,5561,6376,9807,1,0,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6384,"UCS-2000 / Ukraine TM zone 10",9001,5561,6377,9807,1,0,4530,8801,0,9102,8802,30,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6385,"UCS-2000 / Ukraine TM zone 11",9001,5561,6378,9807,1,0,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6386,"UCS-2000 / Ukraine TM zone 12",9001,5561,6379,9807,1,0,4530,8801,0,9102,8802,36,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6387,"UCS-2000 / Ukraine TM zone 13",9001,5561,6380,9807,1,0,4530,8801,0,9102,8802,39,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6391,Cayman Islands National Grid 2011,9002,6135,6390,9802,1,0,1039,8821,19.2,9110,8822,-80.34,9110,8823,19.2,9110,8824,19.42,9110,8826,2950000,9002,8827,1900000,9002,,,
+6393,"NAD83(2011) / Alaska Albers",9001,6318,15021,9822,1,0,4499,8821,50,9102,8822,-154,9102,8823,55,9102,8824,65,9102,8826,0,9001,8827,0,9001,,,
+6394,"NAD83(2011) / Alaska zone 1",9001,6318,15031,9812,1,0,4499,8806,5000000,9001,8807,-5000000,9001,8811,57,9110,8812,-133.4,9110,8813,323.07483685,9110,8814,323.07483685,9110,8815,0.9999,9201
+6395,"NAD83(2011) / Alaska zone 2",9001,6318,15032,9807,1,0,4499,8801,54,9102,8802,-142,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6396,"NAD83(2011) / Alaska zone 3",9001,6318,15033,9807,1,0,4499,8801,54,9102,8802,-146,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6397,"NAD83(2011) / Alaska zone 4",9001,6318,15034,9807,1,0,4499,8801,54,9102,8802,-150,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6398,"NAD83(2011) / Alaska zone 5",9001,6318,15035,9807,1,0,4499,8801,54,9102,8802,-154,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6399,"NAD83(2011) / Alaska zone 6",9001,6318,15036,9807,1,0,4499,8801,54,9102,8802,-158,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6400,"NAD83(2011) / Alaska zone 7",9001,6318,15037,9807,1,0,4499,8801,54,9102,8802,-162,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6401,"NAD83(2011) / Alaska zone 8",9001,6318,15038,9807,1,0,4499,8801,54,9102,8802,-166,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6402,"NAD83(2011) / Alaska zone 9",9001,6318,15039,9807,1,0,4499,8801,54,9102,8802,-170,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6403,"NAD83(2011) / Alaska zone 10",9001,6318,15040,9802,1,0,4499,8821,51,9110,8822,-176,9110,8823,53.5,9110,8824,51.5,9110,8826,1000000,9001,8827,0,9001,,,
+6404,"NAD83(2011) / Arizona Central",9001,6318,10232,9807,1,0,4499,8801,31,9110,8802,-111.55,9110,8805,0.9999,9201,8806,213360,9001,8807,0,9001,,,,,,
+6405,"NAD83(2011) / Arizona Central (ft)",9002,6318,15305,9807,1,0,4495,8801,31,9110,8802,-111.55,9110,8805,0.9999,9201,8806,700000,9002,8807,0,9002,,,,,,
+6406,"NAD83(2011) / Arizona East",9001,6318,10231,9807,1,0,4499,8801,31,9110,8802,-110.1,9110,8805,0.9999,9201,8806,213360,9001,8807,0,9001,,,,,,
+6407,"NAD83(2011) / Arizona East (ft)",9002,6318,15304,9807,1,0,4495,8801,31,9110,8802,-110.1,9110,8805,0.9999,9201,8806,700000,9002,8807,0,9002,,,,,,
+6408,"NAD83(2011) / Arizona West",9001,6318,10233,9807,1,0,4499,8801,31,9110,8802,-113.45,9110,8805,0.999933333,9201,8806,213360,9001,8807,0,9001,,,,,,
+6409,"NAD83(2011) / Arizona West (ft)",9002,6318,15306,9807,1,0,4495,8801,31,9110,8802,-113.45,9110,8805,0.999933333,9201,8806,700000,9002,8807,0,9002,,,,,,
+6410,"NAD83(2011) / Arkansas North",9001,6318,10331,9802,1,0,4499,8821,34.2,9110,8822,-92,9110,8823,36.14,9110,8824,34.56,9110,8826,400000,9001,8827,0,9001,,,
+6411,"NAD83(2011) / Arkansas North (ftUS)",9003,6318,15385,9802,1,0,4497,8821,34.2,9110,8822,-92,9110,8823,36.14,9110,8824,34.56,9110,8826,1312333.3333,9003,8827,0,9003,,,
+6412,"NAD83(2011) / Arkansas South",9001,6318,10332,9802,1,0,4499,8821,32.4,9110,8822,-92,9110,8823,34.46,9110,8824,33.18,9110,8826,400000,9001,8827,400000,9001,,,
+6413,"NAD83(2011) / Arkansas South (ftUS)",9003,6318,15386,9802,1,0,4497,8821,32.4,9110,8822,-92,9110,8823,34.46,9110,8824,33.18,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
+6414,"NAD83(2011) / California Albers",9001,6318,10420,9822,1,0,4499,8821,0,9102,8822,-120,9102,8823,34,9102,8824,40.5,9102,8826,0,9001,8827,-4000000,9001,,,
+6415,"NAD83(2011) / California zone 1",9001,6318,10431,9802,1,0,4499,8821,39.2,9110,8822,-122,9110,8823,41.4,9110,8824,40,9110,8826,2000000,9001,8827,500000,9001,,,
+6416,"NAD83(2011) / California zone 1 (ftUS)",9003,6318,15307,9802,1,0,4497,8821,39.2,9110,8822,-122,9110,8823,41.4,9110,8824,40,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6417,"NAD83(2011) / California zone 2",9001,6318,10432,9802,1,0,4499,8821,37.4,9110,8822,-122,9110,8823,39.5,9110,8824,38.2,9110,8826,2000000,9001,8827,500000,9001,,,
+6418,"NAD83(2011) / California zone 2 (ftUS)",9003,6318,15308,9802,1,0,4497,8821,37.4,9110,8822,-122,9110,8823,39.5,9110,8824,38.2,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6419,"NAD83(2011) / California zone 3",9001,6318,10433,9802,1,0,4499,8821,36.3,9110,8822,-120.3,9110,8823,38.26,9110,8824,37.04,9110,8826,2000000,9001,8827,500000,9001,,,
+6420,"NAD83(2011) / California zone 3 (ftUS)",9003,6318,15309,9802,1,0,4497,8821,36.3,9110,8822,-120.3,9110,8823,38.26,9110,8824,37.04,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6421,"NAD83(2011) / California zone 4",9001,6318,10434,9802,1,0,4499,8821,35.2,9110,8822,-119,9110,8823,37.15,9110,8824,36,9110,8826,2000000,9001,8827,500000,9001,,,
+6422,"NAD83(2011) / California zone 4 (ftUS)",9003,6318,15310,9802,1,0,4497,8821,35.2,9110,8822,-119,9110,8823,37.15,9110,8824,36,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6423,"NAD83(2011) / California zone 5",9001,6318,10435,9802,1,0,4499,8821,33.3,9110,8822,-118,9110,8823,35.28,9110,8824,34.02,9110,8826,2000000,9001,8827,500000,9001,,,
+6424,"NAD83(2011) / California zone 5 (ftUS)",9003,6318,15311,9802,1,0,4497,8821,33.3,9110,8822,-118,9110,8823,35.28,9110,8824,34.02,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6425,"NAD83(2011) / California zone 6",9001,6318,10436,9802,1,0,4499,8821,32.1,9110,8822,-116.15,9110,8823,33.53,9110,8824,32.47,9110,8826,2000000,9001,8827,500000,9001,,,
+6426,"NAD83(2011) / California zone 6 (ftUS)",9003,6318,15312,9802,1,0,4497,8821,32.1,9110,8822,-116.15,9110,8823,33.53,9110,8824,32.47,9110,8826,6561666.667,9003,8827,1640416.667,9003,,,
+6427,"NAD83(2011) / Colorado Central",9001,6318,10532,9802,1,0,4499,8821,37.5,9110,8822,-105.3,9110,8823,39.45,9110,8824,38.27,9110,8826,914401.8289,9001,8827,304800.6096,9001,,,
+6428,"NAD83(2011) / Colorado Central (ftUS)",9003,6318,15314,9802,1,0,4497,8821,37.5,9110,8822,-105.3,9110,8823,39.45,9110,8824,38.27,9110,8826,3000000,9003,8827,1000000,9003,,,
+6429,"NAD83(2011) / Colorado North",9001,6318,10531,9802,1,0,4499,8821,39.2,9110,8822,-105.3,9110,8823,40.47,9110,8824,39.43,9110,8826,914401.8289,9001,8827,304800.6096,9001,,,
+6430,"NAD83(2011) / Colorado North (ftUS)",9003,6318,15313,9802,1,0,4497,8821,39.2,9110,8822,-105.3,9110,8823,40.47,9110,8824,39.43,9110,8826,3000000,9003,8827,1000000,9003,,,
+6431,"NAD83(2011) / Colorado South",9001,6318,10533,9802,1,0,4499,8821,36.4,9110,8822,-105.3,9110,8823,38.26,9110,8824,37.14,9110,8826,914401.8289,9001,8827,304800.6096,9001,,,
+6432,"NAD83(2011) / Colorado South (ftUS)",9003,6318,15315,9802,1,0,4497,8821,36.4,9110,8822,-105.3,9110,8823,38.26,9110,8824,37.14,9110,8826,3000000,9003,8827,1000000,9003,,,
+6433,"NAD83(2011) / Connecticut",9001,6318,10630,9802,1,0,4499,8821,40.5,9110,8822,-72.45,9110,8823,41.52,9110,8824,41.12,9110,8826,304800.6096,9001,8827,152400.3048,9001,,,
+6434,"NAD83(2011) / Connecticut (ftUS)",9003,6318,15316,9802,1,0,4497,8821,40.5,9110,8822,-72.45,9110,8823,41.52,9110,8824,41.12,9110,8826,1000000,9003,8827,500000,9003,,,
+6435,"NAD83(2011) / Delaware",9001,6318,10730,9807,1,0,4499,8801,38,9110,8802,-75.25,9110,8805,0.999995,9201,8806,200000,9001,8807,0,9001,,,,,,
+6436,"NAD83(2011) / Delaware (ftUS)",9003,6318,15317,9807,1,0,4497,8801,38,9110,8802,-75.25,9110,8805,0.999995,9201,8806,656166.667,9003,8807,0,9003,,,,,,
+6437,"NAD83(2011) / Florida East",9001,6318,10931,9807,1,0,4499,8801,24.2,9110,8802,-81,9110,8805,0.999941177,9201,8806,200000,9001,8807,0,9001,,,,,,
+6438,"NAD83(2011) / Florida East (ftUS)",9003,6318,15318,9807,1,0,4497,8801,24.2,9110,8802,-81,9110,8805,0.999941177,9201,8806,656166.667,9003,8807,0,9003,,,,,,
+6439,"NAD83(2011) / Florida GDL Albers",9001,6318,10934,9822,1,0,4499,8821,24,9110,8822,-84,9110,8823,24,9110,8824,31.3,9110,8826,400000,9001,8827,0,9001,,,
+6440,"NAD83(2011) / Florida North",9001,6318,10933,9802,1,0,4499,8821,29,9110,8822,-84.3,9110,8823,30.45,9110,8824,29.35,9110,8826,600000,9001,8827,0,9001,,,
+6441,"NAD83(2011) / Florida North (ftUS)",9003,6318,15320,9802,1,0,4497,8821,29,9110,8822,-84.3,9110,8823,30.45,9110,8824,29.35,9110,8826,1968500,9003,8827,0,9003,,,
+6442,"NAD83(2011) / Florida West",9001,6318,10932,9807,1,0,4499,8801,24.2,9110,8802,-82,9110,8805,0.999941177,9201,8806,200000,9001,8807,0,9001,,,,,,
+6443,"NAD83(2011) / Florida West (ftUS)",9003,6318,15319,9807,1,0,4497,8801,24.2,9110,8802,-82,9110,8805,0.999941177,9201,8806,656166.667,9003,8807,0,9003,,,,,,
+6444,"NAD83(2011) / Georgia East",9001,6318,11031,9807,1,0,4499,8801,30,9110,8802,-82.1,9110,8805,0.9999,9201,8806,200000,9001,8807,0,9001,,,,,,
+6445,"NAD83(2011) / Georgia East (ftUS)",9003,6318,15321,9807,1,0,4497,8801,30,9110,8802,-82.1,9110,8805,0.9999,9201,8806,656166.667,9003,8807,0,9003,,,,,,
+6446,"NAD83(2011) / Georgia West",9001,6318,11032,9807,1,0,4499,8801,30,9110,8802,-84.1,9110,8805,0.9999,9201,8806,700000,9001,8807,0,9001,,,,,,
+6447,"NAD83(2011) / Georgia West (ftUS)",9003,6318,15322,9807,1,0,4497,8801,30,9110,8802,-84.1,9110,8805,0.9999,9201,8806,2296583.333,9003,8807,0,9003,,,,,,
+6448,"NAD83(2011) / Idaho Central",9001,6318,11132,9807,1,0,4499,8801,41.4,9110,8802,-114,9110,8805,0.999947368,9201,8806,500000,9001,8807,0,9001,,,,,,
+6449,"NAD83(2011) / Idaho Central (ftUS)",9003,6318,15324,9807,1,0,4497,8801,41.4,9110,8802,-114,9110,8805,0.999947368,9201,8806,1640416.667,9003,8807,0,9003,,,,,,
+6450,"NAD83(2011) / Idaho East",9001,6318,11131,9807,1,0,4499,8801,41.4,9110,8802,-112.1,9110,8805,0.999947368,9201,8806,200000,9001,8807,0,9001,,,,,,
+6451,"NAD83(2011) / Idaho East (ftUS)",9003,6318,15323,9807,1,0,4497,8801,41.4,9110,8802,-112.1,9110,8805,0.999947368,9201,8806,656166.667,9003,8807,0,9003,,,,,,
+6452,"NAD83(2011) / Idaho West",9001,6318,11133,9807,1,0,4499,8801,41.4,9110,8802,-115.45,9110,8805,0.999933333,9201,8806,800000,9001,8807,0,9001,,,,,,
+6453,"NAD83(2011) / Idaho West (ftUS)",9003,6318,15325,9807,1,0,4497,8801,41.4,9110,8802,-115.45,9110,8805,0.999933333,9201,8806,2624666.667,9003,8807,0,9003,,,,,,
+6454,"NAD83(2011) / Illinois East",9001,6318,11231,9807,1,0,4499,8801,36.4,9110,8802,-88.2,9110,8805,0.999975,9201,8806,300000,9001,8807,0,9001,,,,,,
+6455,"NAD83(2011) / Illinois East (ftUS)",9003,6318,15387,9807,1,0,4497,8801,36.4,9110,8802,-88.2,9110,8805,0.999975,9201,8806,984250,9003,8807,0,9003,,,,,,
+6456,"NAD83(2011) / Illinois West",9001,6318,11232,9807,1,0,4499,8801,36.4,9110,8802,-90.1,9110,8805,0.999941177,9201,8806,700000,9001,8807,0,9001,,,,,,
+6457,"NAD83(2011) / Illinois West (ftUS)",9003,6318,15388,9807,1,0,4497,8801,36.4,9110,8802,-90.1,9110,8805,0.999941177,9201,8806,2296583.3333,9003,8807,0,9003,,,,,,
+6458,"NAD83(2011) / Indiana East",9001,6318,11331,9807,1,0,4499,8801,37.3,9110,8802,-85.4,9110,8805,0.999966667,9201,8806,100000,9001,8807,250000,9001,,,,,,
+6459,"NAD83(2011) / Indiana East (ftUS)",9003,6318,15372,9807,1,0,4497,8801,37.3,9110,8802,-85.4,9110,8805,0.999966667,9201,8806,328083.333,9003,8807,820208.333,9003,,,,,,
+6460,"NAD83(2011) / Indiana West",9001,6318,11332,9807,1,0,4499,8801,37.3,9110,8802,-87.05,9110,8805,0.999966667,9201,8806,900000,9001,8807,250000,9001,,,,,,
+6461,"NAD83(2011) / Indiana West (ftUS)",9003,6318,15373,9807,1,0,4497,8801,37.3,9110,8802,-87.05,9110,8805,0.999966667,9201,8806,2952750,9003,8807,820208.333,9003,,,,,,
+6462,"NAD83(2011) / Iowa North",9001,6318,11431,9802,1,0,4499,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,1500000,9001,8827,1000000,9001,,,
+6463,"NAD83(2011) / Iowa North (ftUS)",9003,6318,15377,9802,1,0,4497,8821,41.3,9110,8822,-93.3,9110,8823,43.16,9110,8824,42.04,9110,8826,4921250,9003,8827,3280833.3333,9003,,,
+6464,"NAD83(2011) / Iowa South",9001,6318,11432,9802,1,0,4499,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,500000,9001,8827,0,9001,,,
+6465,"NAD83(2011) / Iowa South (ftUS)",9003,6318,15378,9802,1,0,4497,8821,40,9110,8822,-93.3,9110,8823,41.47,9110,8824,40.37,9110,8826,1640416.6667,9003,8827,0,9003,,,
+6466,"NAD83(2011) / Kansas North",9001,6318,11531,9802,1,0,4499,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,400000,9001,8827,0,9001,,,
+6467,"NAD83(2011) / Kansas North (ftUS)",9003,6318,15379,9802,1,0,4497,8821,38.2,9110,8822,-98,9110,8823,39.47,9110,8824,38.43,9110,8826,1312333.3333,9003,8827,0,9003,,,
+6468,"NAD83(2011) / Kansas South",9001,6318,11532,9802,1,0,4499,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,400000,9001,8827,400000,9001,,,
+6469,"NAD83(2011) / Kansas South (ftUS)",9003,6318,15380,9802,1,0,4497,8821,36.4,9110,8822,-98.3,9110,8823,38.34,9110,8824,37.16,9110,8826,1312333.3333,9003,8827,1312333.3333,9003,,,
+6470,"NAD83(2011) / Kentucky North",9001,6318,15303,9802,1,0,4499,8821,37.3,9110,8822,-84.15,9110,8823,37.58,9110,8824,38.58,9110,8826,500000,9001,8827,0,9001,,,
+6471,"NAD83(2011) / Kentucky North (ftUS)",9003,6318,15328,9802,1,0,4497,8821,37.3,9110,8822,-84.15,9110,8823,37.58,9110,8824,38.58,9110,8826,1640416.667,9003,8827,0,9003,,,
+6472,"NAD83(2011) / Kentucky Single Zone",9001,6318,11630,9802,1,0,4499,8821,36.2,9110,8822,-85.45,9110,8823,37.05,9110,8824,38.4,9110,8826,1500000,9001,8827,1000000,9001,,,
+6473,"NAD83(2011) / Kentucky Single Zone (ftUS)",9003,6318,15375,9802,1,0,4497,8821,36.2,9110,8822,-85.45,9110,8823,37.05,9110,8824,38.4,9110,8826,4921250,9003,8827,3280833.333,9003,,,
+6474,"NAD83(2011) / Kentucky South",9001,6318,11632,9802,1,0,4499,8821,36.2,9110,8822,-85.45,9110,8823,37.56,9110,8824,36.44,9110,8826,500000,9001,8827,500000,9001,,,
+6475,"NAD83(2011) / Kentucky South (ftUS)",9003,6318,15329,9802,1,0,4497,8821,36.2,9110,8822,-85.45,9110,8823,37.56,9110,8824,36.44,9110,8826,1640416.667,9003,8827,1640416.667,9003,,,
+6476,"NAD83(2011) / Louisiana North",9001,6318,11731,9802,1,0,4499,8821,30.3,9110,8822,-92.3,9110,8823,32.4,9110,8824,31.1,9110,8826,1000000,9001,8827,0,9001,,,
+6477,"NAD83(2011) / Louisiana North (ftUS)",9003,6318,15391,9802,1,0,4497,8821,30.3,9110,8822,-92.3,9110,8823,32.4,9110,8824,31.1,9110,8826,3280833.3333,9003,8827,0,9003,,,
+6478,"NAD83(2011) / Louisiana South",9001,6318,11732,9802,1,0,4499,8821,28.3,9110,8822,-91.2,9110,8823,30.42,9110,8824,29.18,9110,8826,1000000,9001,8827,0,9001,,,
+6479,"NAD83(2011) / Louisiana South (ftUS)",9003,6318,15392,9802,1,0,4497,8821,28.3,9110,8822,-91.2,9110,8823,30.42,9110,8824,29.18,9110,8826,3280833.3333,9003,8827,0,9003,,,
+6480,"NAD83(2011) / Maine CS2000 Central",9001,6318,11854,9807,1,0,4499,8801,43.3,9110,8802,-69.073,9110,8805,0.99998,9201,8806,500000,9001,8807,0,9001,,,,,,
+6481,"NAD83(2011) / Maine CS2000 East",9001,6318,11851,9807,1,0,4499,8801,43.5,9110,8802,-67.523,9110,8805,0.99998,9201,8806,700000,9001,8807,0,9001,,,,,,
+6482,"NAD83(2011) / Maine CS2000 West",9001,6318,11853,9807,1,0,4499,8801,42.5,9110,8802,-70.223,9110,8805,0.99998,9201,8806,300000,9001,8807,0,9001,,,,,,
+6483,"NAD83(2011) / Maine East",9001,6318,11831,9807,1,0,4499,8801,43.4,9110,8802,-68.3,9110,8805,0.9999,9201,8806,300000,9001,8807,0,9001,,,,,,
+6484,"NAD83(2011) / Maine East (ftUS)",9003,6318,11833,9807,1,0,4497,8801,43.4,9110,8802,-68.3,9110,8805,0.9999,9201,8806,984250,9003,8807,0,9003,,,,,,
+6485,"NAD83(2011) / Maine West",9001,6318,11832,9807,1,0,4499,8801,42.5,9110,8802,-70.1,9110,8805,0.999966667,9201,8806,900000,9001,8807,0,9001,,,,,,
+6486,"NAD83(2011) / Maine West (ftUS)",9003,6318,11834,9807,1,0,4497,8801,42.5,9110,8802,-70.1,9110,8805,0.999966667,9201,8806,2952750,9003,8807,0,9003,,,,,,
+6487,"NAD83(2011) / Maryland",9001,6318,11930,9802,1,0,4499,8821,37.4,9110,8822,-77,9110,8823,39.27,9110,8824,38.18,9110,8826,400000,9001,8827,0,9001,,,
+6488,"NAD83(2011) / Maryland (ftUS)",9003,6318,15330,9802,1,0,4497,8821,37.4,9110,8822,-77,9110,8823,39.27,9110,8824,38.18,9110,8826,1312333.333,9003,8827,0,9003,,,
+6489,"NAD83(2011) / Massachusetts Island",9001,6318,12032,9802,1,0,4499,8821,41,9110,8822,-70.3,9110,8823,41.29,9110,8824,41.17,9110,8826,500000,9001,8827,0,9001,,,
+6490,"NAD83(2011) / Massachusetts Island (ftUS)",9003,6318,15332,9802,1,0,4497,8821,41,9110,8822,-70.3,9110,8823,41.29,9110,8824,41.17,9110,8826,1640416.667,9003,8827,0,9003,,,
+6491,"NAD83(2011) / Massachusetts Mainland",9001,6318,12031,9802,1,0,4499,8821,41,9110,8822,-71.3,9110,8823,42.41,9110,8824,41.43,9110,8826,200000,9001,8827,750000,9001,,,
+6492,"NAD83(2011) / Massachusetts Mainland (ftUS)",9003,6318,15331,9802,1,0,4497,8821,41,9110,8822,-71.3,9110,8823,42.41,9110,8824,41.43,9110,8826,656166.667,9003,8827,2460625,9003,,,
+6493,"NAD83(2011) / Michigan Central",9001,6318,12142,9802,1,0,4499,8821,43.19,9110,8822,-84.22,9110,8823,45.42,9110,8824,44.11,9110,8826,6000000,9001,8827,0,9001,,,
+6494,"NAD83(2011) / Michigan Central (ft)",9002,6318,15334,9802,1,0,4495,8821,43.19,9110,8822,-84.22,9110,8823,45.42,9110,8824,44.11,9110,8826,19685039.37,9002,8827,0,9002,,,
+6495,"NAD83(2011) / Michigan North",9001,6318,12141,9802,1,0,4499,8821,44.47,9110,8822,-87,9110,8823,47.05,9110,8824,45.29,9110,8826,8000000,9001,8827,0,9001,,,
+6496,"NAD83(2011) / Michigan North (ft)",9002,6318,15333,9802,1,0,4495,8821,44.47,9110,8822,-87,9110,8823,47.05,9110,8824,45.29,9110,8826,26246719.16,9002,8827,0,9002,,,
+6497,"NAD83(2011) / Michigan Oblique Mercator",9001,6318,12150,9812,1,0,4499,8806,2546731.496,9001,8807,-4354009.816,9001,8811,45.1833,9110,8812,-86,9110,8813,337.25556,9102,8814,337.25556,9102,8815,0.9996,9201
+6498,"NAD83(2011) / Michigan South",9001,6318,12143,9802,1,0,4499,8821,41.3,9110,8822,-84.22,9110,8823,43.4,9110,8824,42.06,9110,8826,4000000,9001,8827,0,9001,,,
+6499,"NAD83(2011) / Michigan South (ft)",9002,6318,15335,9802,1,0,4495,8821,41.3,9110,8822,-84.22,9110,8823,43.4,9110,8824,42.06,9110,8826,13123359.58,9002,8827,0,9002,,,
+6500,"NAD83(2011) / Minnesota Central",9001,6318,12232,9802,1,0,4499,8821,45,9110,8822,-94.15,9110,8823,47.03,9110,8824,45.37,9110,8826,800000,9001,8827,100000,9001,,,
+6501,"NAD83(2011) / Minnesota Central (ftUS)",9003,6318,12235,9802,1,0,4497,8821,45,9110,8822,-94.15,9110,8823,47.03,9110,8824,45.37,9110,8826,2624666.6667,9003,8827,328083.3333,9003,,,
+6502,"NAD83(2011) / Minnesota North",9001,6318,12231,9802,1,0,4499,8821,46.3,9110,8822,-93.06,9110,8823,48.38,9110,8824,47.02,9110,8826,800000,9001,8827,100000,9001,,,
+6503,"NAD83(2011) / Minnesota North (ftUS)",9003,6318,12234,9802,1,0,4497,8821,46.3,9110,8822,-93.06,9110,8823,48.38,9110,8824,47.02,9110,8826,2624666.6667,9003,8827,328083.3333,9003,,,
+6504,"NAD83(2011) / Minnesota South",9001,6318,12233,9802,1,0,4499,8821,43,9110,8822,-94,9110,8823,45.13,9110,8824,43.47,9110,8826,800000,9001,8827,100000,9001,,,
+6505,"NAD83(2011) / Minnesota South (ftUS)",9003,6318,12236,9802,1,0,4497,8821,43,9110,8822,-94,9110,8823,45.13,9110,8824,43.47,9110,8826,2624666.6667,9003,8827,328083.3333,9003,,,
+6506,"NAD83(2011) / Mississippi East",9001,6318,12331,9807,1,0,4499,8801,29.3,9110,8802,-88.5,9110,8805,0.99995,9201,8806,300000,9001,8807,0,9001,,,,,,
+6507,"NAD83(2011) / Mississippi East (ftUS)",9003,6318,15336,9807,1,0,4497,8801,29.3,9110,8802,-88.5,9110,8805,0.99995,9201,8806,984250,9003,8807,0,9003,,,,,,
+6508,"NAD83(2011) / Mississippi TM",9001,6318,3813,9807,1,0,4499,8801,32.3,9110,8802,-89.45,9110,8805,0.9998335,9201,8806,500000,9001,8807,1300000,9001,,,,,,
+6509,"NAD83(2011) / Mississippi West",9001,6318,12332,9807,1,0,4499,8801,29.3,9110,8802,-90.2,9110,8805,0.99995,9201,8806,700000,9001,8807,0,9001,,,,,,
+6510,"NAD83(2011) / Mississippi West (ftUS)",9003,6318,15337,9807,1,0,4497,8801,29.3,9110,8802,-90.2,9110,8805,0.99995,9201,8806,2296583.333,9003,8807,0,9003,,,,,,
+6511,"NAD83(2011) / Missouri Central",9001,6318,12432,9807,1,0,4499,8801,35.5,9110,8802,-92.3,9110,8805,0.999933333,9201,8806,500000,9001,8807,0,9001,,,,,,
+6512,"NAD83(2011) / Missouri East",9001,6318,12431,9807,1,0,4499,8801,35.5,9110,8802,-90.3,9110,8805,0.999933333,9201,8806,250000,9001,8807,0,9001,,,,,,
+6513,"NAD83(2011) / Missouri West",9001,6318,12433,9807,1,0,4499,8801,36.1,9110,8802,-94.3,9110,8805,0.999941177,9201,8806,850000,9001,8807,0,9001,,,,,,
+6514,"NAD83(2011) / Montana",9001,6318,12530,9802,1,0,4499,8821,44.15,9110,8822,-109.3,9110,8823,49,9110,8824,45,9110,8826,600000,9001,8827,0,9001,,,
+6515,"NAD83(2011) / Montana (ft)",9002,6318,15338,9802,1,0,4495,8821,44.15,9110,8822,-109.3,9110,8823,49,9110,8824,45,9110,8826,1968503.937,9002,8827,0,9002,,,
+6516,"NAD83(2011) / Nebraska",9001,6318,12630,9802,1,0,4499,8821,39.5,9110,8822,-100,9110,8823,43,9110,8824,40,9110,8826,500000,9001,8827,0,9001,,,
+6517,"NAD83(2011) / Nebraska (ftUS)",9003,4759,15396,9802,1,1,4497,8821,39.5,9110,8822,-100,9110,8823,43,9110,8824,40,9110,8826,1640416.6667,9003,8827,0,9003,,,
+6518,"NAD83(2011) / Nevada Central",9001,6318,12732,9807,1,0,4499,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,500000,9001,8807,6000000,9001,,,,,,
+6519,"NAD83(2011) / Nevada Central (ftUS)",9003,6318,15382,9807,1,0,4497,8801,34.45,9110,8802,-116.4,9110,8805,0.9999,9201,8806,1640416.6667,9003,8807,19685000,9003,,,,,,
+6520,"NAD83(2011) / Nevada East",9001,6318,12731,9807,1,0,4499,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,200000,9001,8807,8000000,9001,,,,,,
+6521,"NAD83(2011) / Nevada East (ftUS)",9003,6318,15381,9807,1,0,4497,8801,34.45,9110,8802,-115.35,9110,8805,0.9999,9201,8806,656166.6667,9003,8807,26246666.6667,9003,,,,,,
+6522,"NAD83(2011) / Nevada West",9001,6318,12733,9807,1,0,4499,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,800000,9001,8807,4000000,9001,,,,,,
+6523,"NAD83(2011) / Nevada West (ftUS)",9003,6318,15383,9807,1,0,4497,8801,34.45,9110,8802,-118.35,9110,8805,0.9999,9201,8806,2624666.6667,9003,8807,13123333.3333,9003,,,,,,
+6524,"NAD83(2011) / New Hampshire",9001,6318,12830,9807,1,0,4499,8801,42.3,9110,8802,-71.4,9110,8805,0.999966667,9201,8806,300000,9001,8807,0,9001,,,,,,
+6525,"NAD83(2011) / New Hampshire (ftUS)",9003,6318,15389,9807,1,0,4497,8801,42.3,9110,8802,-71.4,9110,8805,0.999966667,9201,8806,984250,9003,8807,0,9003,,,,,,
+6526,"NAD83(2011) / New Jersey",9001,6318,12930,9807,1,0,4499,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,150000,9001,8807,0,9001,,,,,,
+6527,"NAD83(2011) / New Jersey (ftUS)",9003,6318,15384,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
+6528,"NAD83(2011) / New Mexico Central",9001,6318,13032,9807,1,0,4499,8801,31,9110,8802,-106.15,9110,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6529,"NAD83(2011) / New Mexico Central (ftUS)",9003,6318,15340,9807,1,0,4497,8801,31,9110,8802,-106.15,9110,8805,0.9999,9201,8806,1640416.667,9003,8807,0,9003,,,,,,
+6530,"NAD83(2011) / New Mexico East",9001,6318,13031,9807,1,0,4499,8801,31,9110,8802,-104.2,9110,8805,0.999909091,9201,8806,165000,9001,8807,0,9001,,,,,,
+6531,"NAD83(2011) / New Mexico East (ftUS)",9003,6318,15339,9807,1,0,4497,8801,31,9110,8802,-104.2,9110,8805,0.999909091,9201,8806,541337.5,9003,8807,0,9003,,,,,,
+6532,"NAD83(2011) / New Mexico West",9001,6318,13033,9807,1,0,4499,8801,31,9110,8802,-107.5,9110,8805,0.999916667,9201,8806,830000,9001,8807,0,9001,,,,,,
+6533,"NAD83(2011) / New Mexico West (ftUS)",9003,6318,15341,9807,1,0,4497,8801,31,9110,8802,-107.5,9110,8805,0.999916667,9201,8806,2723091.667,9003,8807,0,9003,,,,,,
+6534,"NAD83(2011) / New York Central",9001,6318,13132,9807,1,0,4499,8801,40,9110,8802,-76.35,9110,8805,0.9999375,9201,8806,250000,9001,8807,0,9001,,,,,,
+6535,"NAD83(2011) / New York Central (ftUS)",9003,6318,15343,9807,1,0,4497,8801,40,9110,8802,-76.35,9110,8805,0.9999375,9201,8806,820208.333,9003,8807,0,9003,,,,,,
+6536,"NAD83(2011) / New York East",9001,6318,13131,9807,1,0,4499,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,150000,9001,8807,0,9001,,,,,,
+6537,"NAD83(2011) / New York East (ftUS)",9003,6318,15342,9807,1,0,4497,8801,38.5,9110,8802,-74.3,9110,8805,0.9999,9201,8806,492125,9003,8807,0,9003,,,,,,
+6538,"NAD83(2011) / New York Long Island",9001,6318,13134,9802,1,0,4499,8821,40.1,9110,8822,-74,9110,8823,41.02,9110,8824,40.4,9110,8826,300000,9001,8827,0,9001,,,
+6539,"NAD83(2011) / New York Long Island (ftUS)",9003,6318,15345,9802,1,0,4497,8821,40.1,9110,8822,-74,9110,8823,41.02,9110,8824,40.4,9110,8826,984250,9003,8827,0,9003,,,
+6540,"NAD83(2011) / New York West",9001,6318,13133,9807,1,0,4499,8801,40,9110,8802,-78.35,9110,8805,0.9999375,9201,8806,350000,9001,8807,0,9001,,,,,,
+6541,"NAD83(2011) / New York West (ftUS)",9003,6318,15344,9807,1,0,4497,8801,40,9110,8802,-78.35,9110,8805,0.9999375,9201,8806,1148291.667,9003,8807,0,9003,,,,,,
+6542,"NAD83(2011) / North Carolina",9001,6318,13230,9802,1,0,4499,8821,33.45,9110,8822,-79,9110,8823,36.1,9110,8824,34.2,9110,8826,609601.22,9001,8827,0,9001,,,
+6543,"NAD83(2011) / North Carolina (ftUS)",9003,6318,15346,9802,1,0,4497,8821,33.45,9110,8822,-79,9110,8823,36.1,9110,8824,34.2,9110,8826,2000000,9003,8827,0,9003,,,
+6544,"NAD83(2011) / North Dakota North",9001,6318,13331,9802,1,0,4499,8821,47,9110,8822,-100.3,9110,8823,48.44,9110,8824,47.26,9110,8826,600000,9001,8827,0,9001,,,
+6545,"NAD83(2011) / North Dakota North (ft)",9002,6318,15347,9802,1,0,4495,8821,47,9110,8822,-100.3,9110,8823,48.44,9110,8824,47.26,9110,8826,1968503.937,9002,8827,0,9002,,,
+6546,"NAD83(2011) / North Dakota South",9001,6318,13332,9802,1,0,4499,8821,45.4,9110,8822,-100.3,9110,8823,47.29,9110,8824,46.11,9110,8826,600000,9001,8827,0,9001,,,
+6547,"NAD83(2011) / North Dakota South (ft)",9002,6318,15348,9802,1,0,4495,8821,45.4,9110,8822,-100.3,9110,8823,47.29,9110,8824,46.11,9110,8826,1968503.937,9002,8827,0,9002,,,
+6548,"NAD83(2011) / Ohio North",9001,6318,13431,9802,1,0,4499,8821,39.4,9110,8822,-82.3,9110,8823,41.42,9110,8824,40.26,9110,8826,600000,9001,8827,0,9001,,,
+6549,"NAD83(2011) / Ohio North (ftUS)",9003,6318,13433,9802,1,0,4497,8821,39.4,9110,8822,-82.3,9110,8823,41.42,9110,8824,40.26,9110,8826,1968500,9003,8827,0,9003,,,
+6550,"NAD83(2011) / Ohio South",9001,6318,13432,9802,1,0,4499,8821,38,9110,8822,-82.3,9110,8823,40.02,9110,8824,38.44,9110,8826,600000,9001,8827,0,9001,,,
+6551,"NAD83(2011) / Ohio South (ftUS)",9003,6318,13434,9802,1,0,4497,8821,38,9110,8822,-82.3,9110,8823,40.02,9110,8824,38.44,9110,8826,1968500,9003,8827,0,9003,,,
+6552,"NAD83(2011) / Oklahoma North",9001,6318,13531,9802,1,0,4499,8821,35,9110,8822,-98,9110,8823,36.46,9110,8824,35.34,9110,8826,600000,9001,8827,0,9001,,,
+6553,"NAD83(2011) / Oklahoma North (ftUS)",9003,6318,15349,9802,1,0,4497,8821,35,9110,8822,-98,9110,8823,36.46,9110,8824,35.34,9110,8826,1968500,9003,8827,0,9003,,,
+6554,"NAD83(2011) / Oklahoma South",9001,6318,13532,9802,1,0,4499,8821,33.2,9110,8822,-98,9110,8823,35.14,9110,8824,33.56,9110,8826,600000,9001,8827,0,9001,,,
+6555,"NAD83(2011) / Oklahoma South (ftUS)",9003,6318,15350,9802,1,0,4497,8821,33.2,9110,8822,-98,9110,8823,35.14,9110,8824,33.56,9110,8826,1968500,9003,8827,0,9003,,,
+6556,"NAD83(2011) / Oregon LCC (m)",9001,6318,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+6557,"NAD83(2011) / Oregon GIC Lambert (ft)",9002,6318,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
+6558,"NAD83(2011) / Oregon North",9001,6318,13631,9802,1,0,4499,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,2500000,9001,8827,0,9001,,,
+6559,"NAD83(2011) / Oregon North (ft)",9002,6318,15351,9802,1,0,4495,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,8202099.738,9002,8827,0,9002,,,
+6560,"NAD83(2011) / Oregon South",9001,6318,13632,9802,1,0,4499,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,1500000,9001,8827,0,9001,,,
+6561,"NAD83(2011) / Oregon South (ft)",9002,6318,15352,9802,1,0,4495,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,4921259.843,9002,8827,0,9002,,,
+6562,"NAD83(2011) / Pennsylvania North",9001,6318,13731,9802,1,0,4499,8821,40.1,9110,8822,-77.45,9110,8823,41.57,9110,8824,40.53,9110,8826,600000,9001,8827,0,9001,,,
+6563,"NAD83(2011) / Pennsylvania North (ftUS)",9003,6318,15353,9802,1,0,4497,8821,40.1,9110,8822,-77.45,9110,8823,41.57,9110,8824,40.53,9110,8826,1968500,9003,8827,0,9003,,,
+6564,"NAD83(2011) / Pennsylvania South",9001,6318,13732,9802,1,0,4499,8821,39.2,9110,8822,-77.45,9110,8823,40.58,9110,8824,39.56,9110,8826,600000,9001,8827,0,9001,,,
+6565,"NAD83(2011) / Pennsylvania South (ftUS)",9003,6318,15354,9802,1,0,4497,8821,39.2,9110,8822,-77.45,9110,8823,40.58,9110,8824,39.56,9110,8826,1968500,9003,8827,0,9003,,,
+6566,"NAD83(2011) / Puerto Rico and Virgin Is.",9001,6318,15230,9802,1,0,4499,8821,17.5,9110,8822,-66.26,9110,8823,18.26,9110,8824,18.02,9110,8826,200000,9001,8827,200000,9001,,,
+6567,"NAD83(2011) / Rhode Island",9001,6318,13830,9807,1,0,4499,8801,41.05,9110,8802,-71.3,9110,8805,0.99999375,9201,8806,100000,9001,8807,0,9001,,,,,,
+6568,"NAD83(2011) / Rhode Island (ftUS)",9003,6318,15390,9807,1,0,4497,8801,41.05,9110,8802,-71.3,9110,8805,0.99999375,9201,8806,328083.3333,9003,8807,0,9003,,,,,,
+6569,"NAD83(2011) / South Carolina",9001,6318,13930,9802,1,0,4499,8821,31.5,9110,8822,-81,9110,8823,34.5,9110,8824,32.3,9110,8826,609600,9001,8827,0,9001,,,
+6570,"NAD83(2011) / South Carolina (ft)",9002,6318,15355,9802,1,0,4495,8821,31.5,9110,8822,-81,9110,8823,34.5,9110,8824,32.3,9110,8826,2000000,9002,8827,0,9002,,,
+6571,"NAD83(2011) / South Dakota North",9001,6318,14031,9802,1,0,4499,8821,43.5,9110,8822,-100,9110,8823,45.41,9110,8824,44.25,9110,8826,600000,9001,8827,0,9001,,,
+6572,"NAD83(2011) / South Dakota North (ftUS)",9003,6318,15394,9802,1,0,4497,8821,43.5,9110,8822,-100,9110,8823,45.41,9110,8824,44.25,9110,8826,1968500,9003,8827,0,9003,,,
+6573,"NAD83(2011) / South Dakota South",9001,6318,14032,9802,1,0,4499,8821,42.2,9110,8822,-100.2,9110,8823,44.24,9110,8824,42.5,9110,8826,600000,9001,8827,0,9001,,,
+6574,"NAD83(2011) / South Dakota South (ftUS)",9003,6318,15395,9802,1,0,4497,8821,42.2,9110,8822,-100.2,9110,8823,44.24,9110,8824,42.5,9110,8826,1968500,9003,8827,0,9003,,,
+6575,"NAD83(2011) / Tennessee",9001,6318,14130,9802,1,0,4499,8821,34.2,9110,8822,-86,9110,8823,36.25,9110,8824,35.15,9110,8826,600000,9001,8827,0,9001,,,
+6576,"NAD83(2011) / Tennessee (ftUS)",9003,6318,15356,9802,1,0,4497,8821,34.2,9110,8822,-86,9110,8823,36.25,9110,8824,35.15,9110,8826,1968500,9003,8827,0,9003,,,
+6577,"NAD83(2011) / Texas Central",9001,6318,14233,9802,1,0,4499,8821,29.4,9110,8822,-100.2,9110,8823,31.53,9110,8824,30.07,9110,8826,700000,9001,8827,3000000,9001,,,
+6578,"NAD83(2011) / Texas Central (ftUS)",9003,6318,15359,9802,1,0,4497,8821,29.4,9110,8822,-100.2,9110,8823,31.53,9110,8824,30.07,9110,8826,2296583.333,9003,8827,9842500,9003,,,
+6579,"NAD83(2011) / Texas Centric Albers Equal Area",9001,6318,14254,9822,1,0,4499,8821,18,9110,8822,-100,9110,8823,27.3,9110,8824,35,9110,8826,1500000,9001,8827,6000000,9001,,,
+6580,"NAD83(2011) / Texas Centric Lambert Conformal",9001,6318,14253,9802,1,0,4499,8821,18,9110,8822,-100,9110,8823,27.3,9110,8824,35,9110,8826,1500000,9001,8827,5000000,9001,,,
+6581,"NAD83(2011) / Texas North",9001,6318,14231,9802,1,0,4499,8821,34,9110,8822,-101.3,9110,8823,36.11,9110,8824,34.39,9110,8826,200000,9001,8827,1000000,9001,,,
+6582,"NAD83(2011) / Texas North (ftUS)",9003,6318,15357,9802,1,0,4497,8821,34,9110,8822,-101.3,9110,8823,36.11,9110,8824,34.39,9110,8826,656166.667,9003,8827,3280833.333,9003,,,
+6583,"NAD83(2011) / Texas North Central",9001,6318,14232,9802,1,0,4499,8821,31.4,9110,8822,-98.3,9110,8823,33.58,9110,8824,32.08,9110,8826,600000,9001,8827,2000000,9001,,,
+6584,"NAD83(2011) / Texas North Central (ftUS)",9003,6318,15358,9802,1,0,4497,8821,31.4,9110,8822,-98.3,9110,8823,33.58,9110,8824,32.08,9110,8826,1968500,9003,8827,6561666.667,9003,,,
+6585,"NAD83(2011) / Texas South",9001,6318,14235,9802,1,0,4499,8821,25.4,9110,8822,-98.3,9110,8823,27.5,9110,8824,26.1,9110,8826,300000,9001,8827,5000000,9001,,,
+6586,"NAD83(2011) / Texas South (ftUS)",9003,6318,15361,9802,1,0,4497,8821,25.4,9110,8822,-98.3,9110,8823,27.5,9110,8824,26.1,9110,8826,984250,9003,8827,16404166.667,9003,,,
+6587,"NAD83(2011) / Texas South Central",9001,6318,14234,9802,1,0,4499,8821,27.5,9110,8822,-99,9110,8823,30.17,9110,8824,28.23,9110,8826,600000,9001,8827,4000000,9001,,,
+6588,"NAD83(2011) / Texas South Central (ftUS)",9003,6318,15360,9802,1,0,4497,8821,27.5,9110,8822,-99,9110,8823,30.17,9110,8824,28.23,9110,8826,1968500,9003,8827,13123333.333,9003,,,
+6589,"NAD83(2011) / Vermont",9001,6318,14430,9807,1,0,4499,8801,42.3,9110,8802,-72.3,9110,8805,0.999964286,9201,8806,500000,9001,8807,0,9001,,,,,,
+6590,"NAD83(2011) / Vermont (ftUS)",9003,6318,5645,9807,1,0,4497,8801,42.3,9110,8802,-72.3,9110,8805,0.999964286,9201,8806,1640416.6667,9003,8807,0,9003,,,,,,
+6591,"NAD83(2011) / Virginia Lambert",9001,6318,3967,9802,1,0,4499,8821,36,9102,8822,-79.5,9102,8823,37,9102,8824,39.5,9102,8826,0,9001,8827,0,9001,,,
+6592,"NAD83(2011) / Virginia North",9001,6318,14531,9802,1,0,4499,8821,37.4,9110,8822,-78.3,9110,8823,39.12,9110,8824,38.02,9110,8826,3500000,9001,8827,2000000,9001,,,
+6593,"NAD83(2011) / Virginia North (ftUS)",9003,6318,15365,9802,1,0,4497,8821,37.4,9110,8822,-78.3,9110,8823,39.12,9110,8824,38.02,9110,8826,11482916.667,9003,8827,6561666.667,9003,,,
+6594,"NAD83(2011) / Virginia South",9001,6318,14532,9802,1,0,4499,8821,36.2,9110,8822,-78.3,9110,8823,37.58,9110,8824,36.46,9110,8826,3500000,9001,8827,1000000,9001,,,
+6595,"NAD83(2011) / Virginia South (ftUS)",9003,6318,15366,9802,1,0,4497,8821,36.2,9110,8822,-78.3,9110,8823,37.58,9110,8824,36.46,9110,8826,11482916.667,9003,8827,3280833.333,9003,,,
+6596,"NAD83(2011) / Washington North",9001,6318,14631,9802,1,0,4499,8821,47,9110,8822,-120.5,9110,8823,48.44,9110,8824,47.3,9110,8826,500000,9001,8827,0,9001,,,
+6597,"NAD83(2011) / Washington North (ftUS)",9003,6318,15367,9802,1,0,4497,8821,47,9110,8822,-120.5,9110,8823,48.44,9110,8824,47.3,9110,8826,1640416.667,9003,8827,0,9003,,,
+6598,"NAD83(2011) / Washington South",9001,6318,14632,9802,1,0,4499,8821,45.2,9110,8822,-120.3,9110,8823,47.2,9110,8824,45.5,9110,8826,500000,9001,8827,0,9001,,,
+6599,"NAD83(2011) / Washington South (ftUS)",9003,6318,15368,9802,1,0,4497,8821,45.2,9110,8822,-120.3,9110,8823,47.2,9110,8824,45.5,9110,8826,1640416.667,9003,8827,0,9003,,,
+6600,"NAD83(2011) / West Virginia North",9001,6318,14731,9802,1,0,4499,8821,38.3,9110,8822,-79.3,9110,8823,40.15,9110,8824,39,9110,8826,600000,9001,8827,0,9001,,,
+6601,"NAD83(2011) / West Virginia North (ftUS)",9003,6318,14735,9802,1,0,4497,8821,38.3,9110,8822,-79.3,9110,8823,40.15,9110,8824,39,9110,8826,1968500,9003,8827,0,9003,,,
+6602,"NAD83(2011) / West Virginia South",9001,6318,14732,9802,1,0,4499,8821,37,9110,8822,-81,9110,8823,38.53,9110,8824,37.29,9110,8826,600000,9001,8827,0,9001,,,
+6603,"NAD83(2011) / West Virginia South (ftUS)",9003,6318,14736,9802,1,0,4497,8821,37,9110,8822,-81,9110,8823,38.53,9110,8824,37.29,9110,8826,1968500,9003,8827,0,9003,,,
+6604,"NAD83(2011) / Wisconsin Central",9001,4759,14832,9802,1,1,4499,8821,43.5,9110,8822,-90,9110,8823,45.3,9110,8824,44.15,9110,8826,600000,9001,8827,0,9001,,,
+6605,"NAD83(2011) / Wisconsin Central (ftUS)",9003,6318,15370,9802,1,0,4497,8821,43.5,9110,8822,-90,9110,8823,45.3,9110,8824,44.15,9110,8826,1968500,9003,8827,0,9003,,,
+6606,"NAD83(2011) / Wisconsin North",9001,6318,14831,9802,1,0,4499,8821,45.1,9110,8822,-90,9110,8823,46.46,9110,8824,45.34,9110,8826,600000,9001,8827,0,9001,,,
+6607,"NAD83(2011) / Wisconsin North (ftUS)",9003,6318,15369,9802,1,0,4497,8821,45.1,9110,8822,-90,9110,8823,46.46,9110,8824,45.34,9110,8826,1968500,9003,8827,0,9003,,,
+6608,"NAD83(2011) / Wisconsin South",9001,6318,14833,9802,1,0,4499,8821,42,9110,8822,-90,9110,8823,44.04,9110,8824,42.44,9110,8826,600000,9001,8827,0,9001,,,
+6609,"NAD83(2011) / Wisconsin South (ftUS)",9003,6318,15371,9802,1,0,4497,8821,42,9110,8822,-90,9110,8823,44.04,9110,8824,42.44,9110,8826,1968500,9003,8827,0,9003,,,
+6610,"NAD83(2011) / Wisconsin Transverse Mercator",9001,6318,14841,9807,1,0,4499,8801,0,9102,8802,-90,9102,8805,0.9996,9201,8806,520000,9001,8807,-4480000,9001,,,,,,
+6611,"NAD83(2011) / Wyoming East",9001,6318,14931,9807,1,0,4499,8801,40.3,9110,8802,-105.1,9110,8805,0.9999375,9201,8806,200000,9001,8807,0,9001,,,,,,
+6612,"NAD83(2011) / Wyoming East (ftUS)",9003,6318,14935,9807,1,0,4497,8801,40.3,9110,8802,-105.1,9110,8805,0.9999375,9201,8806,656166.6667,9003,8807,0,9003,,,,,,
+6613,"NAD83(2011) / Wyoming East Central",9001,6318,14932,9807,1,0,4499,8801,40.3,9110,8802,-107.2,9110,8805,0.9999375,9201,8806,400000,9001,8807,100000,9001,,,,,,
+6614,"NAD83(2011) / Wyoming East Central (ftUS)",9003,6318,14936,9807,1,0,4497,8801,40.3,9110,8802,-107.2,9110,8805,0.9999375,9201,8806,1312333.3333,9003,8807,328083.3333,9003,,,,,,
+6615,"NAD83(2011) / Wyoming West",9001,6318,14934,9807,1,0,4499,8801,40.3,9110,8802,-110.05,9110,8805,0.9999375,9201,8806,800000,9001,8807,100000,9001,,,,,,
+6616,"NAD83(2011) / Wyoming West (ftUS)",9003,6318,14938,9807,1,0,4497,8801,40.3,9110,8802,-110.05,9110,8805,0.9999375,9201,8806,2624666.6667,9003,8807,328083.3333,9003,,,,,,
+6617,"NAD83(2011) / Wyoming West Central",9001,6318,14933,9807,1,0,4499,8801,40.3,9110,8802,-108.45,9110,8805,0.9999375,9201,8806,600000,9001,8807,0,9001,,,,,,
+6618,"NAD83(2011) / Wyoming West Central (ftUS)",9003,6318,14937,9807,1,0,4497,8801,40.3,9110,8802,-108.45,9110,8805,0.9999375,9201,8806,1968500,9003,8807,0,9003,,,,,,
+6619,"NAD83(2011) / Utah Central",9001,6318,14332,9802,1,0,4499,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,500000,9001,8827,2000000,9001,,,
+6620,"NAD83(2011) / Utah North",9001,6318,14331,9802,1,0,4499,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,500000,9001,8827,1000000,9001,,,
+6621,"NAD83(2011) / Utah South",9001,6318,14333,9802,1,0,4499,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,500000,9001,8827,3000000,9001,,,
+6622,"NAD83(CSRS) / Quebec Lambert",9001,4617,19944,9802,1,0,4499,8821,44,9110,8822,-68.3,9110,8823,60,9110,8824,46,9110,8826,0,9001,8827,0,9001,,,
+6623,"NAD83 / Quebec Albers",9001,4269,6645,9822,1,0,4499,8821,44,9110,8822,-68.3,9110,8823,60,9110,8824,46,9110,8826,0,9001,8827,0,9001,,,
+6624,"NAD83(CSRS) / Quebec Albers",9001,4617,6645,9822,1,0,4499,8821,44,9110,8822,-68.3,9110,8823,60,9110,8824,46,9110,8826,0,9001,8827,0,9001,,,
+6625,"NAD83(2011) / Utah Central (ftUS)",9003,6318,15298,9802,1,0,4497,8821,38.2,9110,8822,-111.3,9110,8823,40.39,9110,8824,39.01,9110,8826,1640416.6667,9003,8827,6561666.6667,9003,,,
+6626,"NAD83(2011) / Utah North (ftUS)",9003,6318,15297,9802,1,0,4497,8821,40.2,9110,8822,-111.3,9110,8823,41.47,9110,8824,40.43,9110,8826,1640416.6667,9003,8827,3280833.3333,9003,,,
+6627,"NAD83(2011) / Utah South (ftUS)",9003,6318,15299,9802,1,0,4497,8821,36.4,9110,8822,-111.3,9110,8823,38.21,9110,8824,37.13,9110,8826,1640416.6667,9003,8827,9842500,9003,,,
+6628,"NAD83(PA11) / Hawaii zone 1",9001,6322,15131,9807,1,0,4499,8801,18.5,9110,8802,-155.3,9110,8805,0.999966667,9201,8806,500000,9001,8807,0,9001,,,,,,
+6629,"NAD83(PA11) / Hawaii zone 2",9001,6322,15132,9807,1,0,4499,8801,20.2,9110,8802,-156.4,9110,8805,0.999966667,9201,8806,500000,9001,8807,0,9001,,,,,,
+6630,"NAD83(PA11) / Hawaii zone 3",9001,6322,15133,9807,1,0,4499,8801,21.1,9110,8802,-158,9110,8805,0.99999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6631,"NAD83(PA11) / Hawaii zone 4",9001,6322,15134,9807,1,0,4499,8801,21.5,9110,8802,-159.3,9110,8805,0.99999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6632,"NAD83(PA11) / Hawaii zone 5",9001,6322,15135,9807,1,0,4499,8801,21.4,9110,8802,-160.1,9110,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+6633,"NAD83(PA11) / Hawaii zone 3 (ftUS)",9003,6322,15138,9807,1,0,4497,8801,21.1,9110,8802,-158,9110,8805,0.99999,9201,8806,1640416.6667,9003,8807,0,9003,,,,,,
+6634,"NAD83(PA11) / UTM zone 4N",9001,6322,16004,9807,1,0,4400,8801,0,9102,8802,-159,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6635,"NAD83(PA11) / UTM zone 5N",9001,6322,16005,9807,1,0,4400,8801,0,9102,8802,-153,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6636,"NAD83(PA11) / UTM zone 2S",9001,6322,16102,9807,1,0,4400,8801,0,9102,8802,-171,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6637,"NAD83(MA11) / Guam Map Grid",9001,6325,4325,9807,1,0,4499,8801,13.3,9110,8802,144.45,9110,8805,1,9201,8806,100000,9001,8807,200000,9001,,,,,,
+6646,"Karbala 1979 / Iraq National Grid",9001,4743,19907,9807,1,0,4400,8801,29.0134566,9110,8802,46.3,9110,8805,0.9994,9201,8806,800000,9001,8807,0,9001,,,,,,
+6669,"JGD2011 / Japan Plane Rectangular CS I",9001,6668,17801,9807,1,0,4530,8801,33,9110,8802,129.3,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6670,"JGD2011 / Japan Plane Rectangular CS II",9001,6668,17802,9807,1,0,4530,8801,33,9110,8802,131,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6671,"JGD2011 / Japan Plane Rectangular CS III",9001,6668,17803,9807,1,0,4530,8801,36,9110,8802,132.1,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6672,"JGD2011 / Japan Plane Rectangular CS IV",9001,6668,17804,9807,1,0,4530,8801,33,9110,8802,133.3,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6673,"JGD2011 / Japan Plane Rectangular CS V",9001,6668,17805,9807,1,0,4530,8801,36,9110,8802,134.2,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6674,"JGD2011 / Japan Plane Rectangular CS VI",9001,6668,17806,9807,1,0,4530,8801,36,9110,8802,136,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6675,"JGD2011 / Japan Plane Rectangular CS VII",9001,6668,17807,9807,1,0,4530,8801,36,9110,8802,137.1,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6676,"JGD2011 / Japan Plane Rectangular CS VIII",9001,6668,17808,9807,1,0,4530,8801,36,9110,8802,138.3,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6677,"JGD2011 / Japan Plane Rectangular CS IX",9001,6668,17809,9807,1,0,4530,8801,36,9110,8802,139.5,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6678,"JGD2011 / Japan Plane Rectangular CS X",9001,6668,17810,9807,1,0,4530,8801,40,9110,8802,140.5,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6679,"JGD2011 / Japan Plane Rectangular CS XI",9001,6668,17811,9807,1,0,4530,8801,44,9110,8802,140.15,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6680,"JGD2011 / Japan Plane Rectangular CS XII",9001,6668,17812,9807,1,0,4530,8801,44,9110,8802,142.15,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6681,"JGD2011 / Japan Plane Rectangular CS XIII",9001,6668,17813,9807,1,0,4530,8801,44,9110,8802,144.15,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6682,"JGD2011 / Japan Plane Rectangular CS XIV",9001,6668,17814,9807,1,0,4530,8801,26,9110,8802,142,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6683,"JGD2011 / Japan Plane Rectangular CS XV",9001,6668,17815,9807,1,0,4530,8801,26,9110,8802,127.3,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6684,"JGD2011 / Japan Plane Rectangular CS XVI",9001,6668,17816,9807,1,0,4530,8801,26,9110,8802,124,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6685,"JGD2011 / Japan Plane Rectangular CS XVII",9001,6668,17817,9807,1,0,4530,8801,26,9110,8802,131,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6686,"JGD2011 / Japan Plane Rectangular CS XVIII",9001,6668,17818,9807,1,0,4530,8801,20,9110,8802,136,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6687,"JGD2011 / Japan Plane Rectangular CS XIX",9001,6668,17819,9807,1,0,4530,8801,26,9110,8802,154,9110,8805,0.9999,9201,8806,0,9001,8807,0,9001,,,,,,
+6688,"JGD2011 / UTM zone 51N",9001,6668,16051,9807,1,0,4400,8801,0,9102,8802,123,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6689,"JGD2011 / UTM zone 52N",9001,6668,16052,9807,1,0,4400,8801,0,9102,8802,129,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6690,"JGD2011 / UTM zone 53N",9001,6668,16053,9807,1,0,4400,8801,0,9102,8802,135,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6691,"JGD2011 / UTM zone 54N",9001,6668,16054,9807,1,0,4400,8801,0,9102,8802,141,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6692,"JGD2011 / UTM zone 55N",9001,6668,16055,9807,1,0,4400,8801,0,9102,8802,147,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6703,"WGS 84 / TM 60 SW",9001,4326,6702,9807,1,0,4400,8801,0,9102,8802,-60,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6707,"RDN2008 / TM32",9001,6706,16032,9807,1,0,4500,8801,0,9102,8802,9,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6708,"RDN2008 / TM33",9001,6706,16033,9807,1,0,4500,8801,0,9102,8802,15,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6709,"RDN2008 / TM34",9001,6706,16034,9807,1,0,4500,8801,0,9102,8802,21,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+6720,"WGS 84 / CIG92",9001,4326,6716,9807,1,0,4400,8801,0,9110,8802,105.373,9110,8805,1.000024,9201,8806,50000,9001,8807,1300000,9001,,,,,,
+6721,"GDA94 / CIG94",9001,4283,6717,9807,1,0,4400,8801,0,9110,8802,105.373,9110,8805,1.00002514,9201,8806,50000,9001,8807,1300000,9001,,,,,,
+6722,"WGS 84 / CKIG92",9001,4326,6718,9807,1,0,4400,8801,0,9110,8802,96.523,9110,8805,1,9201,8806,50000,9001,8807,1400000,9001,,,,,,
+6723,"GDA94 / CKIG94",9001,4283,6719,9807,1,0,4400,8801,0,9110,8802,96.523,9110,8805,0.99999387,9201,8806,50000,9001,8807,1500000,9001,,,,,,
+6732,"GDA94 / MGA zone 41",9001,4283,6725,9807,1,0,4400,8801,0,9102,8802,63,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6733,"GDA94 / MGA zone 42",9001,4283,6726,9807,1,0,4400,8801,0,9102,8802,69,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6734,"GDA94 / MGA zone 43",9001,4283,6727,9807,1,0,4400,8801,0,9102,8802,75,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6735,"GDA94 / MGA zone 44",9001,4283,6728,9807,1,0,4400,8801,0,9102,8802,81,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6736,"GDA94 / MGA zone 46",9001,4283,6729,9807,1,0,4400,8801,0,9102,8802,93,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6737,"GDA94 / MGA zone 47",9001,4283,6730,9807,1,0,4400,8801,0,9102,8802,99,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6738,"GDA94 / MGA zone 59",9001,4283,6731,9807,1,0,4400,8801,0,9102,8802,171,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6867,"NAD83(CORS96) / Oregon LCC (m)",9001,6783,13633,9802,1,0,4499,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+6868,"NAD83(CORS96) / Oregon GIC Lambert (ft)",9002,6783,15374,9802,1,0,4495,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,1312335.958,9002,8827,0,9002,,,
+6870,"ETRS89 / Albania 2010",9001,4258,6869,9807,1,0,4530,8801,0,9102,8802,20,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+6875,"RDN2008 / Italy zone",9001,6706,6877,9807,1,0,4500,8801,0,9102,8802,12,9102,8805,0.9985,9201,8806,7000000,9001,8807,0,9001,,,,,,
+6876,"RDN2008 / Zone 12",9001,6706,6878,9807,1,0,4500,8801,0,9102,8802,12,9102,8805,1,9201,8806,3000000,9001,8807,0,9001,,,,,,
+6879,"NAD83(2011) / Wisconsin Central",9001,6318,14832,9802,1,0,4499,8821,43.5,9110,8822,-90,9110,8823,45.3,9110,8824,44.15,9110,8826,600000,9001,8827,0,9001,,,
+6880,"NAD83(2011) / Nebraska (ftUS)",9003,6318,15396,9802,1,0,4497,8821,39.5,9110,8822,-100,9110,8823,43,9110,8824,40,9110,8826,1640416.6667,9003,8827,0,9003,,,
+6884,"NAD83(CORS96) / Oregon North",9001,6783,13631,9802,1,0,4499,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,2500000,9001,8827,0,9001,,,
+6885,"NAD83(CORS96) / Oregon North (ft)",9002,6783,15351,9802,1,0,4495,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,8202099.738,9002,8827,0,9002,,,
+6886,"NAD83(CORS96) / Oregon South",9001,6783,13632,9802,1,0,4499,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,1500000,9001,8827,0,9001,,,
+6887,"NAD83(CORS96) / Oregon South (ft)",9002,6783,15352,9802,1,0,4495,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,4921259.843,9002,8827,0,9002,,,
 20004,"Pulkovo 1995 / Gauss-Kruger zone 4",9001,4200,16204,9807,1,0,4530,8801,0,9102,8802,21,9102,8805,1,9201,8806,4500000,9001,8807,0,9001,,,,,,
 20005,"Pulkovo 1995 / Gauss-Kruger zone 5",9001,4200,16205,9807,1,0,4530,8801,0,9102,8802,27,9102,8805,1,9201,8806,5500000,9001,8807,0,9001,,,,,,
 20006,"Pulkovo 1995 / Gauss-Kruger zone 6",9001,4200,16206,9807,1,0,4530,8801,0,9102,8802,33,9102,8805,1,9201,8806,6500000,9001,8807,0,9001,,,,,,
@@ -2667,7 +3046,7 @@
 22289,"Cape / Lo29",9001,4222,17529,9808,1,0,6503,8801,0,9102,8802,29,9102,8805,1,9201,8806,0,9001,8807,0,9001,,,,,,
 22291,"Cape / Lo31",9001,4222,17531,9808,1,0,6503,8801,0,9102,8802,31,9102,8805,1,9201,8806,0,9001,8807,0,9001,,,,,,
 22293,"Cape / Lo33",9001,4222,17533,9808,1,0,6503,8801,0,9102,8802,33,9102,8805,1,9201,8806,0,9001,8807,0,9001,,,,,,
-22300,"Carthage (Paris) / Tunisia Mining Grid",9036,4816,19937,9816,1,0,4406,8821,38.81973,9105,8822,7.83445,9105,8826,270,9036,8827,582,9036,,,,,,,,,
+22300,"Carthage (Paris) / Tunisia Mining Grid",9036,4816,19937,9816,1,0,4406,8821,36.5964,9105,8822,7.83445,9105,8826,270,9036,8827,360,9036,,,,,,,,,
 22332,"Carthage / UTM zone 32N",9001,4223,16032,9807,1,0,4400,8801,0,9102,8802,9,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 22391,"Carthage / Nord Tunisie",9001,4223,18181,9801,1,0,4499,8801,40,9105,8802,11,9105,8805,0.999625544,9201,8806,500000,9001,8807,300000,9001,,,,,,
 22392,"Carthage / Sud Tunisie",9001,4223,18182,9801,1,0,4499,8801,37,9105,8802,11,9105,8805,0.999625769,9201,8806,500000,9001,8807,300000,9001,,,,,,
@@ -2928,9 +3307,9 @@
 26801,"NAD Michigan / Michigan East",9003,4268,12101,9807,1,1,4497,8801,41.3,9110,8802,-83.4,9110,8805,0.999942857,9201,8806,500000,9003,8807,0,9003,,,,,,
 26802,"NAD Michigan / Michigan Old Central",9003,4268,12102,9807,1,1,4497,8801,41.3,9110,8802,-85.45,9110,8805,0.999909091,9201,8806,500000,9003,8807,0,9003,,,,,,
 26803,"NAD Michigan / Michigan West",9003,4268,12103,9807,1,1,4497,8801,41.3,9110,8802,-88.45,9110,8805,0.999909091,9201,8806,500000,9003,8807,0,9003,,,,,,
-26811,"NAD Michigan / Michigan North",9003,4268,12111,9802,1,0,4497,8821,44.47,9110,8822,-87,9110,8823,45.29,9110,8824,47.05,9110,8826,2000000,9003,8827,0,9003,,,
-26812,"NAD Michigan / Michigan Central",9003,4268,12112,9802,1,0,4497,8821,43.19,9110,8822,-84.2,9110,8823,44.11,9110,8824,45.42,9110,8826,2000000,9003,8827,0,9003,,,
-26813,"NAD Michigan / Michigan South",9003,4268,12113,9802,1,0,4497,8821,41.3,9110,8822,-84.2,9110,8823,42.06,9110,8824,43.4,9110,8826,2000000,9003,8827,0,9003,,,
+26811,"NAD Michigan / Michigan North",9003,4268,12111,9802,1,1,4497,8821,44.47,9110,8822,-87,9110,8823,45.29,9110,8824,47.05,9110,8826,2000000,9003,8827,0,9003,,,
+26812,"NAD Michigan / Michigan Central",9003,4268,12112,9802,1,1,4497,8821,43.19,9110,8822,-84.2,9110,8823,44.11,9110,8824,45.42,9110,8826,2000000,9003,8827,0,9003,,,
+26813,"NAD Michigan / Michigan South",9003,4268,12113,9802,1,1,4497,8821,41.3,9110,8822,-84.2,9110,8823,42.06,9110,8824,43.4,9110,8826,2000000,9003,8827,0,9003,,,
 26814,"NAD83 / Maine East (ftUS)",9001,4269,11833,9807,1,1,4499,8801,43.4,9110,8802,-68.3,9110,8805,0.9999,9201,8806,984250,9003,8807,0,9003,,,,,,
 26815,"NAD83 / Maine West (ftUS)",9001,4269,11834,9807,1,1,4499,8801,42.5,9110,8802,-70.1,9110,8805,0.999966667,9201,8806,2952750,9003,8807,0,9003,,,,,,
 26819,"NAD83 / Minnesota North (ftUS)",9001,4269,12234,9802,1,1,4499,8821,46.3,9110,8822,-93.06,9110,8823,48.38,9110,8824,47.02,9110,8826,2624666.6667,9003,8827,328083.3333,9003,,,
@@ -3152,7 +3531,7 @@
 28192,"Palestine 1923 / Palestine Belt",9001,4281,18202,9807,1,0,4400,8801,31.4402749,9110,8802,35.124349,9110,8805,1,9201,8806,170251.555,9001,8807,1126867.909,9001,,,,,,
 28193,"Palestine 1923 / Israeli CS Grid",9001,4281,18203,9806,1,0,4400,8801,31.4402749,9110,8802,35.124349,9110,8806,170251.555,9001,8807,1126867.909,9001,,,,,,,,,
 28232,"Pointe Noire / UTM zone 32S",9001,4282,16132,9807,1,0,4400,8801,0,9102,8802,9,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
-28348,"GDA94 / MGA zone 48",9001,4283,17348,9807,1,1,4400,8801,0,9102,8802,105,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+28348,"GDA94 / MGA zone 48",9001,4283,17348,9807,1,0,4400,8801,0,9102,8802,105,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 28349,"GDA94 / MGA zone 49",9001,4283,17349,9807,1,0,4400,8801,0,9102,8802,111,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 28350,"GDA94 / MGA zone 50",9001,4283,17350,9807,1,0,4400,8801,0,9102,8802,117,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
 28351,"GDA94 / MGA zone 51",9001,4283,17351,9807,1,0,4400,8801,0,9102,8802,123,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
diff --git a/data/prime_meridian.csv b/data/prime_meridian.csv
index 94dcf3b..dbcc804 100644
--- a/data/prime_meridian.csv
+++ b/data/prime_meridian.csv
@@ -1,13 +1,13 @@
 prime_meridian_code,prime_meridian_name,greenwich_longitude,uom_code,remarks,information_source,data_source,revision_date,change_id,deprecated
 8901,Greenwich,0,9102,,,OGP,1995/06/02,1996.290,0
-8902,Lisbon,-9.0754862,9110,,"Instituto Geografico e Cadastral; Lisbon",OGP,1995/06/02,1996.290,0
+8902,Lisbon,-9.0754862,9110,,"Instituto Geografico e Cadastral; Lisbon",OGP,2014/06/27,1996.290 2014.040,0
 8903,Paris,2.5969213,9105,"Value adopted by IGN (Paris) in 1936. Equivalent to 2°20'14.025"". Preferred by EPSG to earlier value of 2°20'13.95"" (2.596898 grads) used by RGS London.","Institut Geographique National (IGN); Paris",OGP,2008/06/24,2008.045,0
-8904,Bogota,-74.04513,9110,,"Instituto Geografico ""Augustin Cadazzi"" (IGAC); Bogota",OGP,1995/06/02,1996.290,0
-8905,Madrid,-3.411658,9110,,,OGP,1995/06/02,1996.290,0
+8904,Bogota,-74.04513,9110,,"Instituto Geografico ""Augustin Cadazzi"" (IGAC); Bogota",OGP,2014/06/27,1996.290 2014.040,0
+8905,Madrid,-3.411658,9110,,,OGP,2014/06/27,1996.290 2014.040,0
 8906,Rome,12.27084,9110,,,OGP,1995/06/02,1996.290,0
 8907,Bern,7.26225,9110,"1895 value.  Newer value of 7°26'22.335"" determined in 1938.",Bundesamt für Landestopographie,OGP,2008/06/24,1996.290 2008.045,0
 8908,Jakarta,106.482779,9110,,,OGP,1995/06/02,1996.290,0
-8909,Ferro,-17.4,9110,Used in Austria and former Czechoslovakia.,,OGP,1995/06/02,1996.290,0
+8909,Ferro,-17.4,9110,Used in Austria and former Czechoslovakia.,,OGP,2014/06/27,1996.290 2014.040,0
 8910,Brussels,4.220471,9110,,,OGP,1995/06/02,1996.290,0
 8911,Stockholm,18.03298,9110,,,OGP,1995/06/02,1996.290,0
 8912,Athens,23.4258815,9110,Used in Greece for older mapping based on Hatt projection.,"Topography Department; National Technical University of Athens.",OGP,1997/06/16,,0
diff --git a/data/projop_wparm.csv b/data/projop_wparm.csv
index 4d2cbe5..6d1979e 100644
--- a/data/projop_wparm.csv
+++ b/data/projop_wparm.csv
@@ -299,6 +299,67 @@
 6049,EPSG Arctic LCC zone 7-13,9802,8821,65.21037415,9110,8822,-34,9110,8823,67,9110,8824,63.4,9110,8826,13500000,9001,8827,7500000,9001,,,
 6126,"Cayman Islands LCC (ft)",9802,8821,19.2,9110,8822,80.34,9110,8823,19.2,9110,8824,19.42,9110,8826,2950000,9002,8827,1900000,9002,,,
 6127,"Cayman Islands TM (ft)",9807,8801,0,9102,8802,-81,9102,8805,0.9996,9201,8806,1640419.9475,9002,8807,0,9002,,,,,,
+6197,Michigan CS27 North zone,1051,1038,1.0000382,9201,8821,44.87,9110,8822,-87,9110,8823,45.29,9110,8824,47.05,9110,8826,2000000,9003,8827,0,9003
+6198,Michigan CS27 Central zone,1051,1038,1.0000382,9201,8821,43.19,9110,8822,-84.2,9110,8823,44.11,9110,8824,45.42,9110,8826,2000000,9003,8827,0,9003
+6199,Michigan CS27 South zone,1051,1038,1.0000382,9201,8821,41.3,9110,8822,-84.2,9110,8823,42.06,9110,8824,43.4,9110,8826,2000000,9003,8827,0,9003
+6203,Macedonia Gauss-Kruger,9807,8801,0,9102,8802,21,9102,8805,0.9999,9201,8806,500000,9001,8807,0,9001,,,,,,
+6212,Arauca urban grid,1052,1039,100,9001,8801,7.051538301,9110,8802,-70.452991476,9110,8806,1035263.443,9001,8807,1275526.621,9001,,,,,,
+6213,Armenia urban grid,1052,1039,1470,9001,8801,4.315637,9110,8802,-75.4024561,9110,8806,1155824.666,9001,8807,993087.465,9001,,,,,,
+6214,Barranquilla urban grid,1052,1039,100,9001,8801,10.55234591,9110,8802,-74.50035928,9110,8806,917264.406,9001,8807,1699839.935,9001,,,,,,
+6215,Bogota urban grid,1052,1039,2550,9001,8801,4.404975,9110,8802,-74.084773,9110,8806,92334.879,9001,8807,109320.965,9001,,,,,,
+6216,Bucaramanga urban grid,1052,1039,931,9001,8801,7.044399371,9110,8802,-73.11504356,9110,8806,1097241.305,9001,8807,1274642.278,9001,,,,,,
+6217,Cali urban grid,1052,1039,1000,9001,8801,3.263078,9110,8802,-76.3114025,9110,8806,1061900.18,9001,8807,872364.63,9001,,,,,,
+6218,Cartagena urban grid,1052,1039,0,9001,8801,10.2349371,9110,8802,-75.3040345,9110,8806,842981.41,9001,8807,1641887.09,9001,,,,,,
+6219,Cucuta urban grid,1052,1039,308,9001,8801,7.532017225,9110,8802,-72.301033542,9110,8806,842805.406,9001,8807,1364404.57,9001,,,,,,
+6220,Florencia urban grid,1052,1039,300,9001,8801,1.371564426,9110,8802,-75.370882337,9110,8806,1162300.348,9001,8807,671068.716,9001,,,,,,
+6221,Ibague urban grid,1052,1039,1100,9001,8801,4.250988618,9110,8802,-75.104773336,9110,8806,877634.33,9001,8807,980541.348,9001,,,,,,
+6222,Inirida urban grid,1052,1039,96,9001,8801,3.504357746,9110,8802,-67.541883552,9110,8806,1019177.687,9001,8807,491791.326,9001,,,,,,
+6223,Leticia urban grid,1052,1039,89.7,9001,8801,-4.115166257,9110,8802,-69.563411981,9110,8806,25978.217,9001,8807,27501.365,9001,,,,,,
+6224,Manizales urban grid,1052,1039,2100,9001,8801,5.0405354,9110,8802,-75.3039941,9110,8806,1173727.04,9001,8807,1052391.13,9001,,,,,,
+6225,Medellin urban grid,1052,1039,1510,9001,8801,6.1345152,9110,8802,-75.3353593,9110,8806,835378.647,9001,8807,1180816.875,9001,,,,,,
+6226,Mitu urban grid,1052,1039,170,9001,8801,1.145988972,9110,8802,-70.140766196,9110,8806,1093717.398,9001,8807,629997.236,9001,,,,,,
+6227,Mocoa urban grid,1052,1039,655.2,9001,8801,1.082408409,9110,8802,-76.390367639,9110,8806,1047467.388,9001,8807,617828.474,9001,,,,,,
+6228,Monteria urban grid,1052,1039,15,9001,8801,8.462310872,9110,8802,-75.524639199,9110,8806,1131814.934,9001,8807,1462131.119,9001,,,,,,
+6229,Neiva urban grid,1052,1039,430,9001,8801,2.56326942,9110,8802,-75.17471722,9110,8806,864476.923,9001,8807,817199.827,9001,,,,,,
+6230,Pasto urban grid,1052,1039,2530,9001,8801,1.120356225,9110,8802,-77.151125228,9110,8806,980469.695,9001,8807,624555.332,9001,,,,,,
+6231,Pereira urban grid,1052,1039,1500,9001,8801,4.4848937,9110,8802,-75.4138225,9110,8806,1153492.012,9001,8807,1024195.255,9001,,,,,,
+6232,Popayan urban grid,1052,1039,1740,9001,8801,2.272217558,9110,8802,-76.362192989,9110,8806,1052430.525,9001,8807,763366.548,9001,,,,,,
+6233,Puerto Carreno urban grid,1052,1039,51.58,9001,8801,6.105059709,9110,8802,-67.300270089,9110,8806,1063834.703,9001,8807,1175257.481,9001,,,,,,
+6234,Quibdo urban grid,1052,1039,44,9001,8801,5.413929158,9110,8802,-76.390271389,9110,8806,1047273.617,9001,8807,1121443.09,9001,,,,,,
+6235,Riohacha urban grid,1052,1039,6,9001,8801,11.321288798,9110,8802,-72.540996793,9110,8806,1128154.73,9001,8807,1767887.914,9001,,,,,,
+6236,San Andres urban grid,1052,1039,6,9001,8801,12.312565957,9110,8802,-81.434575342,9110,8806,820439.298,9001,8807,1877357.828,9001,,,,,,
+6237,San Jose del Guaviare urban grid,1052,1039,185,9001,8801,2.335068419,9110,8802,-72.382411997,9110,8806,1159876.62,9001,8807,775380.342,9001,,,,,,
+6238,Santa Marta urban grid,1052,1039,29,9001,8801,11.1310715,9110,8802,-74.1330019,9110,8806,983892.409,9001,8807,1732533.518,9001,,,,,,
+6239,Sucre urban grid,1052,1039,20,9001,8801,8.483798132,9110,8802,-74.432088057,9110,8806,929043.607,9001,8807,1466125.658,9001,,,,,,
+6240,Tunja urban grid,1052,1039,2800,9001,8801,5.320310106,9110,8802,-73.210698004,9110,8806,1080514.91,9001,8807,1103772.028,9001,,,,,,
+6241,Valledupar urban grid,1052,1039,200,9001,8801,10.265014,9110,8802,-73.1447657,9110,8806,1090979.66,9001,8807,1647208.93,9001,,,,,,
+6242,Villavicencio urban grid,1052,1039,427.19,9001,8801,4.091935036,9110,8802,-73.372814955,9110,8806,1050678.757,9001,8807,950952.124,9001,,,,,,
+6243,Yopal urban grid,1052,1039,300,9001,8801,5.2114138,9110,8802,-72.2512145,9110,8806,851184.177,9001,8807,1083954.137,9001,,,,,,
+6361,Mexico LCC,9802,8821,12,9102,8822,-102,9102,8823,17.5,9102,8824,29.5,9102,8826,2500000,9001,8827,0,9001,,,
+6374,Ukraine TM zone 7,9807,8801,0,9102,8802,21,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6375,Ukraine TM zone 8,9807,8801,0,9102,8802,24,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6376,Ukraine TM zone 9,9807,8801,0,9102,8802,27,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6377,Ukraine TM zone 10,9807,8801,0,9102,8802,30,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6378,Ukraine TM zone 11,9807,8801,0,9102,8802,33,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6379,Ukraine TM zone 12,9807,8801,0,9102,8802,36,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6380,Ukraine TM zone 13,9807,8801,0,9102,8802,39,9102,8805,1,9201,8806,300000,9001,8807,0,9001,,,,,,
+6390,"Cayman Islands LCC (ft)",9802,8821,19.2,9110,8822,-80.34,9110,8823,19.2,9110,8824,19.42,9110,8826,2950000,9002,8827,1900000,9002,,,
+6645,Quebec Albers Projection,9822,8821,44,9110,8822,-68.3,9110,8823,60,9110,8824,46,9110,8826,0,9001,8827,0,9001,,,
+6702,TM 60 SW,9807,8801,0,9102,8802,-60,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6716,Christmas Island Grid 1992,9807,8801,0,9110,8802,105.373,9110,8805,1.000024,9201,8806,50000,9001,8807,1300000,9001,,,,,,
+6717,Christmas Island Grid 1994,9807,8801,0,9110,8802,105.373,9110,8805,1.00002514,9201,8806,50000,9001,8807,1300000,9001,,,,,,
+6718,Cocos Island Grid 1992,9807,8801,0,9110,8802,96.523,9110,8805,1,9201,8806,50000,9001,8807,1400000,9001,,,,,,
+6719,Cocos Island Grid 1994,9807,8801,0,9110,8802,96.523,9110,8805,0.99999387,9201,8806,50000,9001,8807,1500000,9001,,,,,,
+6725,Map Grid of Australia zone 41,9807,8801,0,9102,8802,63,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6726,Map Grid of Australia zone 42,9807,8801,0,9102,8802,69,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6727,Map Grid of Australia zone 43,9807,8801,0,9102,8802,75,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6728,Map Grid of Australia zone 44,9807,8801,0,9102,8802,81,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6729,Map Grid of Australia zone 46,9807,8801,0,9102,8802,93,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6730,Map Grid of Australia zone 47,9807,8801,0,9102,8802,99,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6731,Map Grid of Australia zone 59,9807,8801,0,9102,8802,171,9102,8805,0.9996,9201,8806,500000,9001,8807,10000000,9001,,,,,,
+6869,Albania 2010,9807,8801,0,9102,8802,20,9102,8805,1,9201,8806,500000,9001,8807,0,9001,,,,,,
+6877,Italy zone,9807,8801,0,9102,8802,12,9102,8805,0.9985,9201,8806,7000000,9001,8807,0,9001,,,,,,
+6878,Italy zone 12,9807,8801,0,9102,8802,12,9102,8805,1,9201,8806,3000000,9001,8807,0,9001,,,,,,
 10101,Alabama CS27 East zone,9807,8801,30.3,9110,8802,-85.5,9110,8805,0.99996,9201,8806,500000,9003,8807,0,9003,,,,,,
 10102,Alabama CS27 West zone,9807,8801,30,9110,8802,-87.3,9110,8805,0.999933333,9201,8806,500000,9003,8807,0,9003,,,,,,
 10131,"SPCS83 Alabama East zone (meters)",9807,8801,30.3,9110,8802,-85.5,9110,8805,0.99996,9201,8806,200000,9001,8807,0,9001,,,,,,
@@ -478,7 +539,7 @@
 13602,Oregon CS27 South zone,9802,8821,41.4,9110,8822,-120.3,9110,8823,42.2,9110,8824,44,9110,8826,2000000,9003,8827,0,9003,,,
 13631,"SPCS83 Oregon North zone (meters)",9802,8821,43.4,9110,8822,-120.3,9110,8823,46,9110,8824,44.2,9110,8826,2500000,9001,8827,0,9001,,,
 13632,"SPCS83 Oregon South zone (meters)",9802,8821,41.4,9110,8822,-120.3,9110,8823,44,9110,8824,42.2,9110,8826,1500000,9001,8827,0,9001,,,
-13633,"Oregon GIC Lambert (meters)",9802,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
+13633,"Oregon Lambert (meters)",9802,8821,41.45,9110,8822,-120.3,9110,8823,43,9110,8824,45.3,9110,8826,400000,9001,8827,0,9001,,,
 13701,Pennsylvania CS27 North zone,9802,8821,40.1,9110,8822,-77.45,9110,8823,40.53,9110,8824,41.57,9110,8826,2000000,9003,8827,0,9003,,,
 13702,Pennsylvania CS27 South zone,9802,8821,39.2,9110,8822,-77.45,9110,8823,39.56,9110,8824,40.48,9110,8826,2000000,9003,8827,0,9003,,,
 13731,"SPCS83 Pennsylvania North zone (meters)",9802,8821,40.1,9110,8822,-77.45,9110,8823,41.57,9110,8824,40.53,9110,8826,600000,9001,8827,0,9001,,,
@@ -1792,13 +1853,13 @@
 19927,Stereo 33,9809,8801,45.54,9110,8802,25.23328772,9110,8805,0.9996667,9201,8806,500000,9001,8807,500000,9001,,,,,,
 19928,Kuwait TM,9807,8801,0,9102,8802,48,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 19929,Sweden zone 2.5 gon V,9807,8801,0,9110,8802,15.48298,9110,8805,1,9201,8806,1500000,9001,8807,0,9001,,,,,,
-19930,Greek Grid,9807,8801,0,9102,8802,24,9110,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
+19930,Greek Grid,9807,8801,0,9102,8802,24,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 19931,Egyseges Orszagos Vetuleti,9815,8811,47.08398174,9110,8812,19.02548584,9110,8813,90,9110,8814,90,9110,8815,0.99993,9201,8816,650000,9001,8817,200000,9001
 19933,"Prince Edward Island Stereographic (ATS77)",9809,8801,47.15,9110,8802,-63,9110,8805,0.999912,9201,8806,700000,9001,8807,400000,9001,,,,,,
 19934,Lithuania 1994,9807,8801,0,9102,8802,24,9102,8805,0.9998,9201,8806,500000,9001,8807,0,9001,,,,,,
 19935,Rectified Skew Orthomorphic Malaya Grid,9812,8806,40000,9062,8807,0,9062,8811,4,9110,8812,102.15,9110,8813,323.01328458,9110,8814,323.07483685,9110,8815,0.99984,9201
 19936,Portuguese National Grid,9807,8801,39.4,9110,8802,1,9110,8805,1,9201,8806,200000,9001,8807,300000,9001,,,,,,
-19937,Tunisia Mining Grid,9816,8821,38.81973,9105,8822,7.83445,9105,8826,270,9036,8827,582,9036,,,,,,,,,
+19937,Tunisia Mining Grid,9816,8821,36.5964,9105,8822,7.83445,9105,8826,270,9036,8827,360,9036,,,,,,,,,
 19938,Estonian National Grid,9802,8821,57.310319415,9110,8822,24,9110,8823,59.2,9110,8824,58,9110,8826,500000,9001,8827,6375000,9001,,,
 19939,TM Baltic 93,9807,8801,0,9102,8802,24,9102,8805,0.9996,9201,8806,500000,9001,8807,0,9001,,,,,,
 19940,Levant Zone,9817,8801,34.39,9110,8802,37.21,9110,8805,0.9996256,9201,8806,300000,9001,8807,300000,9001,,,,,,
diff --git a/data/ruian_vf_ob_v1.gfs b/data/ruian_vf_ob_v1.gfs
index 5bd2e0d..a64bf86 100644
--- a/data/ruian_vf_ob_v1.gfs
+++ b/data/ruian_vf_ob_v1.gfs
@@ -78,21 +78,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -238,21 +232,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOP -->
@@ -316,21 +304,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOMC -->
@@ -406,21 +388,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Text popisující vlajku MOMC -->
     <PropertyDefn>
@@ -535,21 +511,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -657,31 +627,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID řízení v ISKN -->
     <PropertyDefn>
       <Name>RizeniId</Name>
       <ElementPath>RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -776,21 +737,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -827,11 +782,8 @@
     <PropertyDefn>
       <Name>Vymera</Name>
       <ElementPath>Vymera</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Převažující charakter využití ZSJ -->
     <PropertyDefn>
@@ -895,21 +847,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Parcely -->
@@ -929,15 +875,18 @@
       <ElementPath>Geometrie|OriginalniHranice</ElementPath> 
       <Type>Polygon</Type>
     </GeomPropertyDefn>
+    <!-- Originální geometrie hranice parcely (Ompv) -->
+    <GeomPropertyDefn>
+      <Name>OriginalniHraniceOmpv</Name>
+      <ElementPath>Geometrie|OriginalniHraniceOmpv</ElementPath>
+      <Type>MultiPolygon</Type>
+    </GeomPropertyDefn>
     <!-- Jednoznační identifikátor parcely -->
     <PropertyDefn>
       <Name>Id</Name>
       <ElementPath>Id</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Identifikátor nesprávnosti na prvku -->
     <PropertyDefn>
@@ -962,11 +911,8 @@
     <PropertyDefn>
       <Name>VymeraParcely</Name>
       <ElementPath>VymeraParcely</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Způsob využití pozemku -->
     <PropertyDefn>
@@ -1010,21 +956,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID řízení v ISKN -->
     <PropertyDefn>
       <Name>RizeniId</Name>
       <ElementPath>RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Bonitované díly parcely - výměra v metrech čtverečných -->
     <PropertyDefn>
@@ -1042,21 +982,15 @@
     <PropertyDefn>
       <Name>BonitovanyDilIdTranskace</Name>
       <ElementPath>BonitovaneDily|BonitovanyDil|IdTranskace</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>IntegerList</Type>
-      -->
-      <Type>StringList</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Bonitované díly parcely - ID řízení v ISKN -->
     <PropertyDefn>
       <Name>BonitovaneDilRizeniId</Name>
       <ElementPath>BonitovaneDily|BonitovanyDil|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>IntegerList</Type>
-      -->
-      <Type>StringList</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Způsob ochrany pozemku - kód ochrany -->
     <PropertyDefn>
@@ -1080,11 +1014,8 @@
     <PropertyDefn>
       <Name>ZpusobOchranyRizeniId</Name>
       <ElementPath>ZpusobyOchranyPozemku|ZpusobOchrany|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Stavební objekty -->
@@ -1104,6 +1035,12 @@
       <ElementPath>Geometrie|OriginalniHranice</ElementPath> 
       <Type>MultiPolygon</Type>
     </GeomPropertyDefn>
+    <!-- Originální geometrie hranice stavebního objektu (Ompv) -->
+    <GeomPropertyDefn>
+      <Name>OriginalniHraniceOmpv</Name>
+      <ElementPath>Geometrie|OriginalniHraniceOmpv</ElementPath>
+      <Type>MultiPolygon</Type>
+    </GeomPropertyDefn>
     <!-- Kód stavebního objektu -->
     <PropertyDefn>
       <Name>Kod</Name>
@@ -1128,11 +1065,8 @@
     <PropertyDefn>
       <Name>IdentifikacniParcelaId</Name>
       <ElementPath>IdentifikacniParcela|Id</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Typ stavebního objektu -->
     <PropertyDefn>
@@ -1176,31 +1110,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID budovy v ISKN -->
     <PropertyDefn>
       <Name>IsknBudovaId</Name>
       <ElementPath>IsknBudovaId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Datum dokončení stavebního objektu -->
     <PropertyDefn>
@@ -1297,11 +1222,8 @@
     <PropertyDefn>
       <Name>ZpusobOchranyRizeniId</Name>
       <ElementPath>ZpusobyOchrany|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Detailní tecnicko-ekonomické atributy (TEA) -->
     <PropertyDefn>
@@ -1401,31 +1323,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID budovy v ISKN -->
     <PropertyDefn>
       <Name>IsknBudovaId</Name>
       <ElementPath>IsknBudovaId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
 </GMLFeatureClassList>
diff --git a/data/ruian_vf_st_uvoh_v1.gfs b/data/ruian_vf_st_uvoh_v1.gfs
index e5ac150..1113438 100644
--- a/data/ruian_vf_st_uvoh_v1.gfs
+++ b/data/ruian_vf_st_uvoh_v1.gfs
@@ -72,21 +72,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změny v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
 </GMLFeatureClassList>
diff --git a/data/ruian_vf_st_v1.gfs b/data/ruian_vf_st_v1.gfs
index 59e0b16..84d7121 100644
--- a/data/ruian_vf_st_v1.gfs
+++ b/data/ruian_vf_st_v1.gfs
@@ -60,21 +60,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změny v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -151,21 +145,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -242,21 +230,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -334,21 +316,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!--  ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -431,21 +407,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -528,21 +498,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- POU -->
@@ -620,21 +584,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Obce -->
@@ -716,21 +674,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -876,21 +828,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOP -->
@@ -954,21 +900,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOMC -->
@@ -1044,21 +984,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Text popisující vlajku MOMC -->
     <PropertyDefn>
@@ -1173,21 +1107,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1295,31 +1223,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID řízení v ISKN -->
     <PropertyDefn>
       <Name>RizeniId</Name>
       <ElementPath>RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1414,21 +1333,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1465,11 +1378,8 @@
     <PropertyDefn>
       <Name>Vymera</Name>
       <ElementPath>Vymera</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Převažující charakter využití ZSJ -->
     <PropertyDefn>
diff --git a/data/ruian_vf_v1.gfs b/data/ruian_vf_v1.gfs
index 00da809..49c36cd 100644
--- a/data/ruian_vf_v1.gfs
+++ b/data/ruian_vf_v1.gfs
@@ -60,21 +60,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změny v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -151,21 +145,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -242,21 +230,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -334,21 +316,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!--  ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -431,21 +407,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Kód územního celku v NUTS / LAU -->
     <PropertyDefn>
@@ -528,21 +498,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- POU -->
@@ -620,21 +584,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Obce -->
@@ -716,21 +674,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -876,21 +828,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOP -->
@@ -954,21 +900,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- MOMC -->
@@ -1044,21 +984,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Text popisující vlajku MOMC -->
     <PropertyDefn>
@@ -1173,21 +1107,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1295,31 +1223,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID řízení v ISKN -->
     <PropertyDefn>
       <Name>RizeniId</Name>
       <ElementPath>RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1414,21 +1333,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Mluvnické charakteristiky 2 až 7 pád -->
     <PropertyDefn>
@@ -1465,11 +1378,8 @@
     <PropertyDefn>
       <Name>Vymera</Name>
       <ElementPath>Vymera</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Převažující charakter využití ZSJ -->
     <PropertyDefn>
@@ -1533,21 +1443,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Parcely -->
@@ -1567,15 +1471,18 @@
       <ElementPath>Geometrie|OriginalniHranice</ElementPath> 
       <Type>Polygon</Type>
     </GeomPropertyDefn>
+    <!-- Originální geometrie hranice parcely (Ompv) -->
+    <GeomPropertyDefn>
+      <Name>OriginalniHraniceOmpv</Name>
+      <ElementPath>Geometrie|OriginalniHraniceOmpv</ElementPath>
+      <Type>MultiPolygon</Type>
+    </GeomPropertyDefn>
     <!-- Jednoznační identifikátor parcely -->
     <PropertyDefn>
       <Name>Id</Name>
       <ElementPath>Id</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Identifikátor nesprávnosti na prvku -->
     <PropertyDefn>
@@ -1600,11 +1507,8 @@
     <PropertyDefn>
       <Name>VymeraParcely</Name>
       <ElementPath>VymeraParcely</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Způsob využití pozemku -->
     <PropertyDefn>
@@ -1648,21 +1552,15 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID řízení v ISKN -->
     <PropertyDefn>
       <Name>RizeniId</Name>
       <ElementPath>RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Bonitované díly parcely - výměra v metrech čtverečných -->
     <PropertyDefn>
@@ -1680,21 +1578,15 @@
     <PropertyDefn>
       <Name>BonitovanyDilIdTranskace</Name>
       <ElementPath>BonitovaneDily|BonitovanyDil|IdTranskace</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>IntegerList</Type>
-      -->
-      <Type>StringList</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Bonitované díly parcely - ID řízení v ISKN -->
     <PropertyDefn>
       <Name>BonitovaneDilRizeniId</Name>
       <ElementPath>BonitovaneDily|BonitovanyDil|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>IntegerList</Type>
-      -->
-      <Type>StringList</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Způsob ochrany pozemku - kód ochrany -->
     <PropertyDefn>
@@ -1718,11 +1610,8 @@
     <PropertyDefn>
       <Name>ZpusobOchranyRizeniId</Name>
       <ElementPath>ZpusobyOchranyPozemku|ZpusobOchrany|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Stavební objekty -->
@@ -1742,6 +1631,12 @@
       <ElementPath>Geometrie|OriginalniHranice</ElementPath> 
       <Type>MultiPolygon</Type>
     </GeomPropertyDefn>
+    <!-- Originální geometrie hranice stavebního objektu (Ompv) -->
+    <GeomPropertyDefn>
+      <Name>OriginalniHraniceOmpv</Name>
+      <ElementPath>Geometrie|OriginalniHraniceOmpv</ElementPath>
+      <Type>MultiPolygon</Type>
+    </GeomPropertyDefn>
     <!-- Kód stavebního objektu -->
     <PropertyDefn>
       <Name>Kod</Name>
@@ -1766,11 +1661,8 @@
     <PropertyDefn>
       <Name>IdentifikacniParcelaId</Name>
       <ElementPath>IdentifikacniParcela|Id</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Typ stavebního objektu -->
     <PropertyDefn>
@@ -1814,31 +1706,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID budovy v ISKN -->
     <PropertyDefn>
       <Name>IsknBudovaId</Name>
       <ElementPath>IsknBudovaId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Datum dokončení stavebního objektu -->
     <PropertyDefn>
@@ -1935,11 +1818,8 @@
     <PropertyDefn>
       <Name>ZpusobOchranyRizeniId</Name>
       <ElementPath>ZpusobyOchrany|RizeniId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- Detailní tecnicko-ekonomické atributy (TEA) -->
     <PropertyDefn>
@@ -2039,31 +1919,22 @@
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID návrhu změn v ISUI -->
     <PropertyDefn>
       <Name>GlobalniIdNavrhuZmeny</Name>
       <ElementPath>GlobalniIdNavrhuZmeny</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID budovy v ISKN -->
     <PropertyDefn>
       <Name>IsknBudovaId</Name>
       <ElementPath>IsknBudovaId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
   <!-- Zaniklé prvky -->
@@ -2081,21 +1952,15 @@
     <PropertyDefn>
       <Name>PrvekId</Name>
       <ElementPath>PrvekId</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
     <!-- ID transakce v RUIAN -->
     <PropertyDefn>
       <Name>IdTransakce</Name>
       <ElementPath>IdTransakce</ElementPath>
-      <!-- OGR integers are only 32 bit wide for now, see http://trac.osgeo.org/gdal/wiki/rfc31_ogr_64
       <Type>Integer</Type>
-      -->
-      <Type>String</Type>
-      <Width>18</Width>
+      <SubType>Integer64</SubType>
     </PropertyDefn>
   </GMLFeatureClass>
 </GMLFeatureClassList>
diff --git a/data/unit_of_measure.csv b/data/unit_of_measure.csv
index 1f55224..8dbf2cf 100644
--- a/data/unit_of_measure.csv
+++ b/data/unit_of_measure.csv
@@ -1,5 +1,23 @@
 uom_code,unit_of_meas_name,unit_of_meas_type,target_uom_code,factor_b,factor_c,remarks,information_source,data_source,revision_date,change_id,deprecated
 1024,bin,scale,9201,1,1,,OGP,OGP,2012/07/14,2011.106,0
+1025,millimetre,length,9001,1,1000,,ISO 1000.,OGP,2013/05/29,2013.021,0
+1026,metres per second,length,1026,1,1,Length rate.,OGP,OGP,2013/05/29,2013.021,0
+1027,millimetres per year,length,1026,1,31556925445,"Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",ISO 1000.,OGP,2013/09/02,2013.021 2013.042,0
+1028,parts per billion,scale,9201,1,1000000000,"Billion is internationally ambiguous, in different languages being 1E+9 and 1E+12. One billion taken here to be 1E+9.",OGP,OGP,2013/05/29,2013.021,0
+1029,year,time,1040,31556925.445,1,,"International Union of Geological Sciences (IUGS) and International Union of Pure and Applied Chemistry (IUPAC). Pure Appl. Chem., Vol. 83, No. 5, pp. 1159–1162, 2011.",OGP,2013/05/28,2013.021,0
+1030,parts per billion per year,scale,1036,1,3.1556925445e+16,"Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029. Billion
+    is internationally ambiguous, in different languages being 1E+9 and 1E+12. One billion taken
+    here to be 1E+9.",ISO 1000.,OGP,2013/12/13,2013.021 2013.042 2013.067,0
+1031,milliarc-second,angle,9101,3.14159265358979,648000000,= ((pi/180) / 3600 / 1000) radians,,OGP,2013/05/29,2013.021,0
+1032,milliarc-seconds per year,angle,1035,3.14159265358979,2.044888768836e+16,"= ((pi/180) / 3600 / 1000) radians per year. Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",,OGP,2013/09/02,2013.021 2013.042,0
+1033,centimetre,length,9001,1,100,,ISO 1000.,OGP,2013/05/29,2013.021,0
+1034,centimetres per year,length,1026,1,3155692544.5,"Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",ISO 1000.,OGP,2013/09/02,2013.021 2013.042,0
+1035,radians per second,angle,1035,1,1,Angle rate.,OGP,OGP,2013/05/29,2013.021,0
+1036,unity per second,scale,1036,1,1,Scale rate.,OGP,OGP,2013/05/29,2013.021,0
+1040,second,time,1040,1,1,Not to be confused with the angle unit arc-second.,ISO 1000.,OGP,2013/05/28,2013.021,0
+1041,parts per million per year,scale,1036,1,31556925445000,"Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",,OGP,2013/09/02,2013.021 2013.037 2013.042,0
+1042,metres per year,length,1026,1,31556925.445,"Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",OGP,OGP,2013/09/02,2013.021 2013.042,0
+1043,arc-seconds per year,angle,1035,3.14159265358979,20448887688360,"=((pi/180) / 3600) radians per year. Year taken to be IUGS definition of 31556925.445 seconds; see UoM code 1029.",,OGP,2013/09/02,2013.021 2013.042,0
 9001,metre,length,9001,1,1,Also known as International metre. SI standard unit.,ISO 1000.,OGP,1995/06/02,,0
 9002,foot,length,9001,0.3048,1,,"ISO 1000; 1958",OGP,1995/06/02,,0
 9003,US survey foot,length,9001,12,39.37,Used in USA.,OGP,OGP,2000/05/07,1999.990,0
@@ -37,7 +55,7 @@ uom_code,unit_of_meas_name,unit_of_meas_type,target_uom_code,factor_b,factor_c,r
 9087,Indian yard (1975),length,9001,0.9143985,1,Indian Foot = 0.99999566 British feet (A.R.Clarke 1865).  British yard (3 feet) taken to be J.S. Clark's 1865 value of 0.9144025m. Rounded to 7 significant figures as 1 Ind ft=0.3047995m.  Used in India since metrication.,"G. Bomford; ""Geodesy""; 3rd edition 1975",OGP,2007/01/25,1997.231 1999.990 2007.011,0
 9093,Statute mile,length,9001,1609.344,1,=5280 feet,OGP,OGP,2000/03/07,,0
 9094,Gold Coast foot,length,9001,6378300,20926201,"Used in Ghana and some adjacent parts of British west Africa prior to metrication, except for the metrication of projection defining parameters when British foot (Sears 1922) used.",Ordnance Survey International,OGP,2001/01/21,2000.861,0
-9095,British foot (1936),length,9001,0.3048007491,1,For the 1936 retriangulation OSGB defines the relationship of 10 feet of 1796 to the International metre through the logarithmic relationship (10^0.48401603 exactly). 1 ft = 0.3048007491Â…m. Also used for metric conversions in Ireland.,"1. ""The Retriangulation of Great Britain"", Ordnance Survey of Great Britain.
+9095,British foot (1936),length,9001,0.3048007491,1,For the 1936 retriangulation OSGB defines the relationship of 10 feet of 1796 to the International metre through the logarithmic relationship (10^0.48401603 exactly). 1 ft = 0.3048007491…m. Also used for metric conversions in Ireland.,"1. ""The Retriangulation of Great Britain"", Ordnance Survey of Great Britain.
 2. ""The Irish Grid - A Description of the Co-ordinate Reference System"" published by Ordnance Survey of Ireland, Dublin and Ordnance Survey of Northern Ireland, Belfast.",OGP,2006/11/27,2002.621 2006.932,0
 9096,yard,length,9001,0.9144,1,=3 international feet.,OGP,OGP,2006/07/14,,0
 9097,chain,length,9001,20.1168,1,=22 international yards or 66 international feet.,OGP,OGP,2006/07/14,,0
@@ -66,7 +84,7 @@ uom_code,unit_of_meas_name,unit_of_meas_type,target_uom_code,factor_b,factor_c,r
 9121,sexagesimal DMS.s,angle,9102,,,"Pseudo unit. Format: signed degrees - minutes (two digits) - seconds (real, any precision). Must include leading zero in minutes and seconds where value is under 10 and include decimal separator for seconds. Convert to degree using algorithm.",ISO 6709:1983.,OGP,2002/11/22,,0
 9122,degree (supplier to define representation),angle,9101,3.14159265358979,180,"= pi/180 radians. The degree representation (e.g. decimal, DMSH, etc.) must be clarified by suppliers of data associated with this code.",OGP,OGP,2004/01/05,,0
 9201,unity,scale,9201,1,1,,,OGP,1996/09/12,,0
-9202,parts per million,scale,9201,1,1000000,,,OGP,1996/09/12,,0
+9202,parts per million,scale,9201,1,1000000,,,OGP,2013/07/26,2013.021 2013.037,0
 9203,coefficient,scale,9201,1,1,Used when parameters are coefficients.  They inherently take the units which depend upon the term to which the coefficient applies.,OGP,OGP,2004/09/14,2004.530,0
 9204,Bin width 330 US survey feet,length,9001,3960,39.37,,OGP,OGP,2000/10/19,2000.590 2011.106,1
 9205,Bin width 165 US survey feet,length,9001,1980,39.37,,OGP,OGP,2000/10/19,2000.590 2011.106,1
diff --git a/data/vertcs.csv b/data/vertcs.csv
index f9e3080..0c95b96 100644
--- a/data/vertcs.csv
+++ b/data/vertcs.csv
@@ -53,7 +53,7 @@
 5720,NGF-IGN69 height,5119,Nivellement General de la France - IGN69,9001,1,0,6499,,
 5721,NGF-IGN78 height,5120,Nivellement General de la France - IGN78,9001,1,0,6499,,
 5722,Maputo height,5121,Maputo,9001,1,0,6499,,
-5723,JSLD height,5122,Japanese Standard Levelling Datum 1949,9001,1,0,6499,,
+5723,JSLD69 height,5122,Japanese Standard Levelling Datum 1969,9001,1,0,6499,,
 5724,PHD93 height,5123,PDO Height Datum 1993,9001,1,0,6499,,
 5725,Fahud HD height,5124,Fahud Height Datum,9001,1,0,6499,,
 5726,Ha Tien 1960 height,5125,Ha Tien 1960,9001,1,0,6499,,
@@ -160,3 +160,18 @@
 6185,Santa Cruz das Flores height,1108,Santa Cruz das Flores,9001,1,0,6499,,
 6186,Cais da Vila do Porto height,1109,Cais da Vila do Porto,9001,1,0,6499,,
 6187,Ponta Delgada height,1110,Ponta Delgada,9001,1,0,6499,,
+6357,NAVD88 depth,5103,North American Vertical Datum 1988,9001,1,0,6498,,
+6358,"NAVD88 depth (ftUS)",5103,North American Vertical Datum 1988,9003,1,0,1043,,
+6359,NGVD29 depth,5102,National Geodetic Vertical Datum 1929,9003,1,0,1043,,
+6360,"NAVD88 height (ftUS)",5103,North American Vertical Datum 1988,9003,1,0,6497,,
+6638,Tutuila 1962 height,1121,Tutuila Vertical Datum of 1962,9001,1,0,6499,,
+6639,Guam 1963 height,1122,Guam Vertical Datum of 1963,9001,1,0,6499,,
+6640,NMVD03 height,1119,Northern Marianas Vertical Datum of 2003,9001,1,0,6499,,
+6641,PRVD02 height,1123,Puerto Rico Vertical Datum of 2002,9001,1,0,6499,,
+6642,VIVD09 height,1124,Virgin Islands Vertical Datum of 2009,9001,1,0,6499,,
+6643,ASVD02 height,1125,American Samoa Vertical Datum of 2002,9001,1,0,6499,,
+6644,GUVD04 height,1126,Guam Vertical Datum of 2004,9001,1,0,6499,,
+6647,CGVD2013 height,1127,Canadian Geodetic Vertical Datum of 2013,9001,1,0,6499,,
+6693,JSLD72 height,1129,Japanese Standard Levelling Datum 1972,9001,1,0,6499,,
+6694,"JGD2000 (vertical) height",1130,"Japanese Geodetic Datum 2000 (vertical)",9001,1,0,6499,,
+6695,"JGD2011 (vertical) height",1131,"Japanese Geodetic Datum 2011 (vertical)",9001,1,0,6499,,
diff --git a/doc/credits.dox b/doc/credits.dox
index 0d6bb49..9dc5886 100644
--- a/doc/credits.dox
+++ b/doc/credits.dox
@@ -1,9 +1,9 @@
 #ifndef DOXYGEN_SKIP
-/* $Id: credits.dox 17875 2009-10-22 16:53:57Z warmerdam $ */
+/* $Id: credits.dox 27425 2014-05-30 21:02:09Z rouault $ */
 #endif /* DOXYGEN_SKIP */
 
 /*!
-\page credits Sponsors, Acknowledgements and Credits
+\page credits Acknowledgements and Credits
 
 There are too many people who have helped since GDAL/OGR was launched in 
 late 1998 for me to thank them all.  I have received moral support, 
@@ -14,117 +14,6 @@ years.  Forgive me for all those I left out.<p>
 
 <i>Frank Warmerdam</i><p>
 
-\section credits_sponsorship Sponsorship
-
-Sponsors help fund maintenance, development and promotion of GDAL/OGR. 
-If your organization depends on GDAL/OGR consider 
-<a href="sponsorship.html">becoming a sponsor</a>.
-
-\subsection silver_sponsors Silver Sponsors
-
-\htmlonly
-<table border="0" cellspacing="4" cellpadding="4">
-
-<tr><td><a href="http://www.cadcorp.com/"><center>
-<img src="cadcorp_logo.jpg" alt="" border="0" width="195" height="55">
-</center></a></td>
-
-<td><a href="http://www.cadcorp.com/">Cadcorp</a> 
-is a leading UK developer of digital mapping and GIS software.
-With offices in the UK and the USA, Cadcorp's distribution and VAR
-network stretches worldwide. Cadcorp also plays a pivotal technical role
-in the Open Geospatial Consortium, Inc.(r) (OGC(r)), and the Cadcorp SIS
-- Spatial Information System product family is OGC certified compliant
-for several specifications.</td></tr>
-
-<tr><td>
-
-<a href="http://www.safe.com/"><center>
-<img src="safe-logo.png" alt="" border="0" width="132" height="54">
-</center></a></td>
-
-<td><a href="http://www.safe.com/">Safe Software</a> is the leading developer of Spatial ETL (Extract, Transform, and Load) technology, providing spatial data transformation solutions and professional services. Safe's FME software delivers seamless translation of 160 GIS, CAD, raster, and database formats, and allows users to easily manage feature geometry and attribute restructuring, database loading, merging multiple data sources, web-based data distribution, and coordinate system conversion.
-</td></tr>
-
-<tr><td>
-<a href="http://www.extendthereach.com/"><center>
-<img src="src-logo.png" alt="" border="0" width="189" height="62">
-</center></a></td>
-
-<td><a href="http://www.extendthereach.com/">SRC</a>  
-delivers geographic business intelligence solutions that free
-organizations from limitations. Solving strategic to tactical business
-problems, SRC solutions are deployed by 190,000 global users. SRC is the
-only company to open source its geocoding tool, Explorer Geocoder. SRC
-promotes interoperability by providing solutions that are data, country,
-geography, and mapping independent to be deployed on the desktop or Web.
-</td></tr>
-
-<tr><td>
-<a href="http://www.actgate.com/"><center>
-<img src="act-logo.png" alt="" border="0" width="99" height="124">
-</center></a></td>
-
-<td>
-<a href="http://www.actgate.com/">Applied Coherent Technology Corporation</a> specializes in the automatic ingestion, processing, management, and analysis of geo-spatial data (satellite data streams or model data) in support of NASA planetary missions and Earth environmental satellites.   We have a suite of Network Centric tools to provide different levels of interactive access to the data, i.e. WIPE/PIPE/REACT.  
-</td></tr>
-
-<tr><td>
-<a href="http://www.i3.com/"><center>
-<img src="i3-logo.jpg" alt="" border="0" width="172" height="70">
-</center></a></td>
-
-<td>
-<a href="http://www.i3.com/">i-cubed</a> offers enterprise geospatial information solutions for commercial /
-government customers. Solutions leverage imagery of the Earth for
-visualization / engineering applications including, internet portals,
-wireless telecom and military planning. We offer a full range of products
-and services including imagery itself, image processing, analysis and
-distribution. Also provide image archive management and dissemination
-systems for customers with existing collections.
-</td></tr>
-
-<tr><td>
-<a href="http://www.waypointinfo.com/"><center>
-<img src="waypoint_logo.png" alt="" border="0" width="267" height="47">
-</center></a></td>
-
-<td>
-The <a href="http://www.waypointinfo.com/">Waypoint</a> 
-Panorama(tm) mapping platform delivers powerful online mapping 
-services for business and government organizations, including spatial 
-analysis, mobile asset tracking, web publishing, and Web Mapping Services.  
-Geospatial information can be easily managed, updated, and shared.  Waypoint 
-provides the IT hardware and software infrastructure, the extensive geographic 
-data, and the application software needed by our customers to meet their 
-objectives. 
-</td></tr>
-
-<tr><td>
-<a href="http://www.ingres.com/"><center>
-<img src="ingres-logo.png" alt="" border="0" width="255" height="48">
-</center></a></td>
-
-<td>
-<a href="http://www.ingres.com/">Ingres Corporation</a>
- is the premier provider of open source information
-management services to the enterprise with operations in 58 countries.
-Built on more than 25 years of relational database technology
-investment, Ingres provides the enterprise with proven mission-critical
-reliability coupled with the value and flexibility of open source.  
-</td></tr>
-
-
-
-</table>
-\endhtmlonly
-
-\subsection other_sponsors Other Sponsors
-
-<ul>
-<li> <a href="http://www.microimages.com/">MicroImages Inc.</a>
-</ul>
-
 \section credits_personal Personal
 
 <ul>
@@ -166,7 +55,8 @@ the earlier version by Martin Daly).<p>
 
 <li> <b><a href="http://www.actgate.com/">Applied Coherent 
 Technologies</a></b>: Supported implementation of the GDAL contour generator, 
-as well as various improvements to HDF drivers.
+as well as various improvements to HDF drivers. Has been a Silver sponsor
+of GDAL.
 <p>
 
 <li> <b><a href="http://www.atlantis-scientific.com/">Atlantis 
@@ -185,7 +75,8 @@ in GDAL.
 <p>
 
 <li> <b><a href="http://www.cadcorp.com">Cadcorp</a></b>: Supported 
-development of the Virtual Warped Raster capability.
+development of the Virtual Warped Raster capability. Has been a silver sponsor
+of GDAL.
 <p>
 
 <li> <b><a href="http://www.dmsolutions.ca/">DM Solutions Group</a></b>:
@@ -222,9 +113,16 @@ OGR Memory driver, Virtual Raster Filtering, and NITF RPC capabilities.
 <p>
 
 <li> <b><a href="http://www.i3.com">i-cubed</a></b>: Supported the MrSID 
-driver.
+driver. Has been a Silver sponsor of GDAL.
 <p>
 
+<li> <b><a href="http://www.ingres.com/">Ingres Corporation</a></b> :
+ is the premier provider of open source information
+management services to the enterprise with operations in 58 countries. Has
+been a Silver sponsor of GDAL.
+</td></tr>
+
+
 <li> <b><a href="http://www.intergraph.com">Intergraph</a></b>: Supported
 development of the Erdas Imagine driver.
 <p>
@@ -233,6 +131,10 @@ development of the Erdas Imagine driver.
 of Erdas Imagine driver, and the GDAL Warp API.
 <p>
 
+<li> <b><a href="http://www.microimages.com/">MicroImages Inc.</a></b> : Has been
+a Silver sponsor of GDAL.
+<p>
+
 <li> <b><a href="http://www.opendap.org">OPeNDAP</a></b>: Supported development
 of the OGR OPeNDAP Driver.
 <p>
@@ -253,12 +155,14 @@ initial development of OGR as well as the OGR MapInfo integration.
 <p>
 
 <li> <b><a href="http://www.extendthereach.com/">SRC</a></b>: Supported
-development of the OGR OCI (Oracle Spatial) driver.
+development of the OGR OCI (Oracle Spatial) driver. Has been a Silver sponsor
+of GDAL.
 <p>
 
 <li> <b><a href="http://www.safe.com/">Safe Software</a></b>: Supported
 development of the OGR OLE DB provider, TIGER/Line driver, S-57 driver, 
-DTED driver, FMEObjects driver, SDTS driver and NTF driver. 
+DTED driver, FMEObjects driver, SDTS driver and NTF driver.  Has been a
+Silver sponsor of GDAL.
 <p>
 
 <li> <b><a href="http://www.environmentyukon.gov.yk.ca/">
@@ -266,11 +170,18 @@ Yukon Department of the Environment</a></b>: Supported development of
 CDED / USGS DEM Writer.
 <p>
 
+<li> <b><a href="http://www.waypointinfo.com/">Waypoint</a></b>:
+Panorama(tm) mapping platform delivers powerful online mapping 
+services for business and government organizations, including spatial 
+analysis, mobile asset tracking, web publishing, and Web Mapping Services. Has
+been a Silver sponsor of GDAL.
+</td></tr>
+
 </ul>
 
 \htmlonly
 <p>
-$Id: credits.dox 17875 2009-10-22 16:53:57Z warmerdam $
+$Id: credits.dox 27425 2014-05-30 21:02:09Z rouault $
 </p>
 \endhtmlonly
 
diff --git a/doc/gdal_datamodel.dox b/doc/gdal_datamodel.dox
index 141c5e8..0064d4c 100644
--- a/doc/gdal_datamodel.dox
+++ b/doc/gdal_datamodel.dox
@@ -1,4 +1,4 @@
-/* $Id: gdal_datamodel.dox 25494 2013-01-13 12:55:17Z etourigny $ */
+/* $Id: gdal_datamodel.dox 29123 2015-05-03 11:05:46Z bishop $ */
 
 /*!
 \page gdal_datamodel GDAL Data Model
@@ -168,6 +168,15 @@ honoured by GDAL drivers, algorithms or utilities at this time.
     <li>SYMMETRIZED_KENNAUGH
     </ul>
 <li> POLARIMETRIC_INTERP: This metadata item is defined for Raster Bands for polarimetric SAR data. This indicates which entry in the specified matrix representation of the data this band represents. For a dataset provided as a scattering matrix, for example, acceptable values for this metadata item are HH, HV, VH, VV. When the dataset is a covariance matrix, for example, this metadata item will be one of Covariance_11, Covariance_22, Covariance_33, Covariance_12, Covariance_13, Covarian [...]
+<li> METADATATYPE: If IMAGERY Domain present, the item consist the reader which processed the metadata. Now present such readers:
+    <ul>
+    <li>  DG: DigitalGlobe imagery metadata
+    <li>  GE: GeoEye (or formally SpaceImaging) imagery metadata
+    <li>  OV: OrbView imagery metadata
+    <li>  DIMAP: Pleiades imagery metadata
+    <li>  MSP: Resurs DK-1 imagery metadata
+    <li>  ODL: Landsat imagery metadata
+    </ul>
 </ul>
 
 \subsubsection gdal_datamodel_subdatasets SUBDATASETS Domain
@@ -246,6 +255,17 @@ items defining the model are:
 
 These fields are directly derived from the document prospective GeoTIFF RPC document (http://geotiff.maptools.org/rpc_prop.html) which in turn is closely modelled on the NITF RPC00B definition.
 
+\subsubsection gdal_datamodel_subdatasets IMAGERY Domain
+
+For satellite or aerial imagery the IMAGERY Domain may be present. It depends on exist special metadata files near the image file. The files at the same directory with image file tested by the set of metadata readers, if files can be processed by the metadata reader, it fill the IMAGERY Domain with the following items:
+   
+<ul>
+<li>  SATELLITEID: A satellite or scanner name
+<li>  CLOUDCOVER: Cloud coverage. The value between 0 - 100 or 999 if not available
+<li>  ACQUISITIONDATETIME: The image acquisition date time in UTC
+</ul>  
+
+
 \subsubsection gdal_datamodel_xml xml: Domains
 
 Any domain name prefixed with "xml:" is not normal name/value metadata. 
diff --git a/doc/gdal_drivertut.dox b/doc/gdal_drivertut.dox
index 8cd0eb8..9db3d7f 100644
--- a/doc/gdal_drivertut.dox
+++ b/doc/gdal_drivertut.dox
@@ -1,5 +1,5 @@
 #ifndef DOXYGEN_SKIP
-/* $Id: gdal_drivertut.dox 25410 2012-12-31 11:56:53Z rouault $ */
+/* $Id: gdal_drivertut.dox 28785 2015-03-26 20:46:45Z goatbar $ */
 #endif /* DOXYGEN_SKIP */
 
 /*!
@@ -55,6 +55,7 @@ class JDEMDataset : public GDALPamDataset
 		~JDEMDataset();
     
     static GDALDataset *Open( GDALOpenInfo * );
+    static int          Identify( GDALOpenInfo * );
 
     CPLErr 	GetGeoTransform( double * padfTransform );
     const char *GetProjectionRef();
@@ -75,22 +76,10 @@ GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
 // -------------------------------------------------------------------- //
-//      Confirm that the header has what appears to be dates in the     //
-//      expected locations.  Sadly this is a relatively weak test.      //
+//      Confirm that the header is compatible with a JDEM dataset.      //
 // -------------------------------------------------------------------- //
-    if( poOpenInfo->nHeaderBytes < 50 )
-        return NULL;
-
-    // check if century values seem reasonable //
-    if( (!EQUALN((char *)poOpenInfo->pabyHeader+11,"19",2)
-          && !EQUALN((char *)poOpenInfo->pabyHeader+11,"20",2))
-        || (!EQUALN((char *)poOpenInfo->pabyHeader+15,"19",2)
-             && !EQUALN((char *)poOpenInfo->pabyHeader+15,"20",2))
-        || (!EQUALN((char *)poOpenInfo->pabyHeader+19,"19",2)
-             && !EQUALN((char *)poOpenInfo->pabyHeader+19,"20",2)) )
-    {
+    if (!Identify(poOpenInfo))
         return NULL;
-    }
     
 // -------------------------------------------------------------------- //
 //      Confirm the requested access is supported.                      //
@@ -103,6 +92,11 @@ GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
         return NULL;
     }
 
+    /* Check that the file pointer from GDALOpenInfo* is available */
+    if( poOpenInfo->fpL == NULL )
+    {
+        return NULL;
+    }
 // -------------------------------------------------------------------- //
 //      Create a corresponding GDALDataset.                             //
 // -------------------------------------------------------------------- //
@@ -110,7 +104,9 @@ GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
 
     poDS = new JDEMDataset();
 
-    poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
+    /* Borrow the file pointer from GDALOpenInfo* */
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
     
 // -------------------------------------------------------------------- //
 //      Read the header.                                                //
@@ -159,18 +155,19 @@ GDALOpenInfo object.  The GDALOpenInfo includes the following public
 data members:
 
 \code
-    char	*pszFilename;
-    char        **papszSiblingFiles;
+    char        *pszFilename;
+    char**      papszOpenOptions;
 
-    GDALAccess	eAccess; // GA_ReadOnly or GA_Update
+    GDALAccess  eAccess;  // GA_ReadOnly or GA_Update
+    int         nOpenFlags;
 
-    int 	bStatOK;
+    int         bStatOK;
     int         bIsDirectory;
-    
-    FILE	*fp;
 
-    int		nHeaderBytes;
-    GByte	*pabyHeader;
+    VSILFILE   *fpL;
+
+    int         nHeaderBytes;
+    GByte       *pabyHeader;
 \endcode
 
 The driver can inspect these to establish if the file is supported.  If the
@@ -187,9 +184,22 @@ various date fields to ensure they have reasonable century values.  If the
 test fails, we quietly return NULL indicating this file isn't of our supported
 format. 
 
-\code
+The identification is in fact delegated to a Identify() static function :
+
+\verbatim
+/************************************************************************/
+/*                              Identify()                              */
+/************************************************************************/
+
+int JDEMDataset::Identify( GDALOpenInfo * poOpenInfo )
+
+{
+/* -------------------------------------------------------------------- */
+/*      Confirm that the header has what appears to be dates in the     */
+/*      expected locations.  Sadly this is a relatively weak test.      */
+/* -------------------------------------------------------------------- */
     if( poOpenInfo->nHeaderBytes < 50 )
-        return NULL;
+        return FALSE;
 
     /* check if century values seem reasonable */
     if( (!EQUALN((char *)poOpenInfo->pabyHeader+11,"19",2)
@@ -199,9 +209,12 @@ format.
         || (!EQUALN((char *)poOpenInfo->pabyHeader+19,"19",2)
              && !EQUALN((char *)poOpenInfo->pabyHeader+19,"20",2)) )
     {
-        return NULL;
+        return FALSE;
     }
-\endcode
+
+    return TRUE;
+}
+\endverbatim
 
 It is important to make the <i>is this my format</i> test as stringent as
 possible.  In this particular case the test is weak, and a file that happened
@@ -226,15 +239,23 @@ Next we need to create an instance of the database class in which we will
 set various information of interest.
 
 \code
+    /* Check that the file pointer from GDALOpenInfo* is available */
+    if( poOpenInfo->fpL == NULL )
+    {
+        return NULL;
+    }
+
     JDEMDataset 	*poDS;
 
     poDS = new JDEMDataset();
 
-    poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
+    /* Borrow the file pointer from GDALOpenInfo* */
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
 \endcode
 
-At this point we open the file, to acquire a file handle
-for the dataset.  Whenever possible, we try to use the VSI*L GDAL API to
+At this point we "borrow" the file handle that was held by GDALOpenInfo*.
+This file pointer uses the VSI*L GDAL API to
 access files on disk.  This virtualized POSIX-style API allows some 
 special capabilities like supporting large files, in-memory files 
 and zipped files. 
@@ -432,13 +453,16 @@ void GDALRegister_JDEM()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JDEM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Japanese DEM (.mem)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_various.html#JDEM" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mem" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
         poDriver->pfnOpen = JDEMDataset::Open;
+        poDriver->pfnIdentify = JDEMDataset::Identify;
 
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
@@ -447,7 +471,7 @@ void GDALRegister_JDEM()
 
 Note the use of GDAL_CHECK_VERSION macro (starting with GDAL 1.5.0).
 This is an optional macro for drivers inside GDAL tree that don't depend on external libraries,
-but that can be very usefull if you compile your driver as a plugin (that is to say, an out-of-tree
+but that can be very useful if you compile your driver as a plugin (that is to say, an out-of-tree
 driver). As the GDAL C++ ABI may, and will, change between GDAL releases (for example from GDAL 1.5.0 to 1.6.0),
 it may be necessary to recompile your driver against the header files of the GDAL version with
 which you want to make it work. The GDAL_CHECK_VERSION macro will check that the GDAL version
@@ -464,6 +488,9 @@ name for this format, often used to identity the driver in scripts and
 commandline programs.  Normally 3-5 characters in length, and matching the 
 prefix of the format classes. (mandatory)
 
+<li> GDAL_DCAP_RASTER: set to YES to indicate that this driver handles
+raster data. (mandatory)
+
 <li> GDAL_DMD_LONGNAME: A longer descriptive name for the file format,
 but still no longer than 50-60 characters. (mandatory)
 
@@ -490,9 +517,19 @@ with a CreateCopy() method, and that always writes Float32 might also list
 Byte, Int16, and UInt16 since they can losslessly translated to Float32.  An
 example value might be "Byte Int16 UInt16". (required - if creation supported)
 
+<li> GDAL_DCAP_VIRTUALIO: set to YES to indicate that this driver can deal
+with files opened with the VSI*L GDAL API. Otherwise this metadata item should
+not be defined. (optional)
+
 <li> pfnOpen: The function to call to try opening files of this format. 
 (optional) 
 
+<li> pfnIdentify: The function to call to try identifying files of this format.
+A driver should return 1 if it recognizes the file as being of its format,
+0 if it recognizes the file as being NOT of its format, or -1 if it cannot
+reach to a firm conclusion by just examining the header bytes.
+(optional) 
+
 <li> pfnCreate: The function to call to create new updatable datasets of this
 format. (optional)
 
@@ -754,9 +791,9 @@ JPEGCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 // -------------------------------------------------------------------- 
 //      Create the dataset.                                             
 // -------------------------------------------------------------------- 
-    FILE	*fpImage;
+    VSILFILE	*fpImage;
 
-    fpImage = VSIFOpen( pszFilename, "wb" );
+    fpImage = VSIFOpenL( pszFilename, "wb" );
     if( fpImage == NULL )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -827,7 +864,7 @@ JPEGCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     jpeg_finish_compress( &sCInfo );
     jpeg_destroy_compress( &sCInfo );
 
-    VSIFClose( fpImage );
+    VSIFCloseL( fpImage );
 
     return (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly );
 }
@@ -922,7 +959,7 @@ GDALDataset *PAuxDataset::Create( const char * pszFilename,
     
 // -------------------------------------------------------------------- 
 //      We need to write out the original filename but without any      
-//      path components in the AuxilaryTarget line.  Do so now.         
+//      path components in the AuxiliaryTarget line.  Do so now.         
 // -------------------------------------------------------------------- 
     int		iStart;
 
@@ -1092,7 +1129,7 @@ implement this.
 
 \htmlonly
 <p>
-$Id: gdal_drivertut.dox 25410 2012-12-31 11:56:53Z rouault $
+$Id: gdal_drivertut.dox 28785 2015-03-26 20:46:45Z goatbar $
 </p>
 \endhtmlonly
 
diff --git a/doc/images/foss4g2014.png b/doc/images/foss4g2014.png
new file mode 100644
index 0000000..0265d43
Binary files /dev/null and b/doc/images/foss4g2014.png differ
diff --git a/doc/index.dox b/doc/index.dox
index 0b04f84..c8bc598 100644
--- a/doc/index.dox
+++ b/doc/index.dox
@@ -1,26 +1,29 @@
 #ifndef DOXYGEN_SKIP                                                            
-/* $Id: index.dox 26546 2013-10-22 22:22:36Z warmerdam $ */               
+/* $Id: index.dox 29079 2015-04-30 14:50:02Z rouault $ */               
 #endif /* DOXYGEN_SKIP */                                                       
 
 /*! \mainpage GDAL - Geospatial Data Abstraction Library
 
 <center><b>Select language</b>: [English]<a href="index_ru.html">[Russian]</a><a href="index_br.html">[Portuguese]</a><a href="http://gdal.gloobe.org/">[French/Francais]</a></center>
 
-\htmlonly<img src="gdalicon.png" alt="GDAL">\endhtmlonly \latexonly GDAL \endlatexonly
-is a translator library for raster geospatial data formats
+\htmlonly<img src="gdalicon.png" alt="GDAL">\endhtmlonly \latexonly GDAL/OGR \endlatexonly
+is a translator library for raster and vector geospatial data formats
 that is released under an <a href="http://trac.osgeo.org/gdal/wiki/FAQGeneral#WhatlicensedoesGDALOGRuse">X/MIT</a> style 
 <a href="http://www.opensource.org/">
 Open Source</a> license by the <a href="http://www.osgeo.org/">Open Source
 Geospatial Foundation</a>.  As a library, it presents a
-\link gdal_datamodel.html single abstract data model\endlink 
+\link gdal_datamodel.html single raster abstract data model\endlink and
+\link ogr_arch.html vector abstract data model\endlink  
 to the calling application for all supported formats.  It also comes with a variety
-of useful \link gdal_utilities.html commandline utilities\endlink
+of useful commandline utilities
 for data translation and processing.  The 
-<a href="http://trac.osgeo.org/gdal/wiki/Release/1.10.1-News">NEWS</a>
-page describes the August 2013 GDAL/OGR 1.10.1 release.
+<a href="http://trac.osgeo.org/gdal/wiki/Release/1.11.2-News">NEWS</a>
+page describes the February 2015 GDAL/OGR 1.11.2 release.
 
-The related <a href="ogr/index.html">OGR</a> library (which lives within the GDAL source tree) 
-provides a similar capability for simple features vector data.
+Traditionally GDAL used to design the raster part of the library, and OGR the
+vector part for Simple Features. Starting with GDAL 2.0, both sides have been
+more tightly integrated. You can still refer to the <a href="http://gdal.org/1.11/index.html">documentation of GDAL 1.X</a>
+if needed.
 
 Master: http://www.gdal.org<br>
 Download: 
@@ -32,13 +35,15 @@ Download:
 <ul>
 <li> <a href="http://trac.osgeo.org/gdal/">Wiki</a> - Various user and developer contributed documentation and hints
 <li> <a href="http://trac.osgeo.org/gdal/wiki/DownloadingGdalBinaries">Downloads</a> - Ready to use binaries (executables)
-<li> <a href="formats_list.html">Supported Formats</a> : GeoTIFF, Erdas Imagine, SDTS, ECW, MrSID, JPEG2000, DTED, NITF, ...
-<li> <a href="gdal_utilities.html">GDAL Utility Programs</a> : gdalinfo, gdal_translate, gdaladdo, gdalwarp, ...
+<li> <a href="formats_list.html">Supported raster formats</a> (139 drivers) : <a href="frmt_gtiff.html">GeoTIFF</a>, <a href="frmt_hfa.html">Erdas Imagine</a>, <a href="frmt_ecw.html">ECW</a>, <a href="frmt_mrsid.html">MrSID</a>, <a href="frmt_jp2openjpeg.html">JPEG2000</a>, <a href="frmt_dted.html">DTED</a>, <a href="frmt_nitf.html">NITF</a>, <a href="drv_geopackage_raster.html">GeoPackage</a>, ...
+<li> <a href="ogr_formats.html">Supported vector formats</a> (83 drivers): <a href="drv_shapefile.html">ESRI Shapefile</a>, <a href="drv_sde.html">ESRI ArcSDE</a>, <a href="drv_openfilegdb.html">ESRI FileGDB</a>, <a href="drv_mitab.html">MapInfo (tab and mid/mif)</a>, <a href="drv_gml.html">GML</a>, <a href="drv_libkml.html">KML</a>, <a href="drv_pg.html">PostGIS</a>, <a href="drv_oci.html">Oracle Spatial</a>, <a href="drv_geopackage.html">GeoPackage</a>, ...
+<li> <a href="gdal_utilities.html">Raster utility programs</a> : <a href="gdalinfo.html">gdalinfo</a>, <a href="gdal_translate.html">gdal_translate</a>, <a href="gdaladdo.html">gdaladdo</a>, <a href="gdalwarp.html">gdalwarp</a>, ...
+<li> <a href="ogr_utilities.html">Vector utility programs</a> : <a href="ogrinfo.html">ogrinfo</a>, <a href="ogr2ogr.html">ogr2ogr</a>, <a href="ogrtindex.html">ogrtindex</a>, ...
 <li> <a href="http://trac.osgeo.org/gdal/wiki/FAQ">GDAL FAQ</a>
-<li> <a href="gdal_datamodel.html">GDAL Data Model</a>
+<li> <a href="gdal_datamodel.html">Raster</a> and <a href="ogr_arch.html">Vector</a> data models and architecture
 <li> <a href="http://trac.osgeo.org/gdal/wiki/GovernanceAndCommunity">GDAL/OGR Governance and Community Participation</a>
 <li> <a href="http://www.osgeo.org/search_profile?SET=1&MUL_TECH[0]=00013">GDAL Service Provider Listings</a> (not vetted)
-<li> <a href="credits.html">Sponsors, Acknowledgements and Credits</a>
+<li> <a href="credits.html">Acknowledgements and Credits</a>
 <li> <a href="http://trac.osgeo.org/gdal/wiki/SoftwareUsingGdal">Software Using GDAL</a>
 </ul>
 
@@ -47,33 +52,59 @@ Download:
 <ul>
 <li> <a href="http://trac.osgeo.org/gdal/wiki/BuildHints">Building GDAL From Source</a>
 <li> <a href="http://trac.osgeo.org/gdal/wiki/DownloadSource">Downloads</a> - source code
-<li> <a href="hierarchy.html">API Reference Documentation</a>
-<li> <a href="gdal_tutorial.html">GDAL API Tutorial</a>
-<li> <a href="gdal_drivertut.html">GDAL Driver Implementation Tutorial</a>
-<li> <a href="warptut.html">GDAL Warp API Tutorial</a>
-<li> <a href="ogr/osr_tutorial.html">OGRSpatialReference Tutorial</a>
-<li> <a href="gdal_8h.html">GDAL C API</a>
-<li> <a href="gdal__alg_8h.html">GDAL Algorithms C API</a>
+<li> <a href="wince.html">GDAL for Windows CE (unmaintained)</a>
+</ul>
+
+\subsection index_devdocs_tutorials Tutorials
+
+<ul>
+<li> <a href="gdal_tutorial.html">Raster API tutorial</a>
+<li> <a href="ogr_apitut.html">Vector API tutorial</a>
+<li> <a href="gdal_drivertut.html">Raster driver implementation</a>
+<li> <a href="ogr_drivertut.html">Vector driver implementation</a>
+<li> <a href="warptut.html">GDAL Warp API tutorial</a> (Reprojection, ...)
+<li> <a href="osr_tutorial.html">Projections and Spatial Reference Systems tutorial</a> (OSR - OGRSpatialReference)
+<li> <a href="ogr_feature_style.html">OGR - Feature Style Specification</a>
+</ul>
+
+\subsection index_devdocs_api API documentation
+
+<ul>
+<li> <a href="hierarchy.html">API Reference</a>
+<li> <a href="gdal_8h.html">gdal.h: Raster C API</a>
+<li> <a href="ogr__api_8h.html">ogr_api.h: Vector C API</a>
+<li> <a href="gdal__alg_8h.html">gdal_alg.h: GDAL Algorithms C API</a>
 <li> <a href="classGDALDataset.html">GDALDataset C++ API</a>
 <li> <a href="classGDALRasterBand.html">GDALRasterBand C++ API</a>
-<li> <a href="wince.html">GDAL for Windows CE</a>
+<li> <a href="classOGRLayer.html">OGRLayer C++ API</a>
+<li> <a href="ogr_sql.html">OGR SQL</a> dialect and <a href="ogr_sql_sqlite.html">SQLITE SQL</a> dialect
+</ul>
+
+<!--
+\subsection index_devdocs_specs Specifications
+
+<ul>
+<li> <a href="http://home.gdal.org/projects/opengis/twohalfdsf.html">Adam's 2.5 D Simple Features Proposal (OGC 99-402r2)</a>
+<li> Adam's SRS WKT Clarification Proposal in <a href="http://home.gdal.org/projects/opengis/wkt_prop.html">html</a>
+or <a href="http://home.gdal.org/projects/opengis/wkt_prop.doc">doc</a> format.
 </ul>
+-->
 
 \section foss4g Conference 
  
 \htmlonly 
 <table border="0" cellspacing="4" cellpadding="4"> 
 
-<tr><td><a href="http://2013.foss4g.org/"> 
-<img src="foss4g2013.png" alt="FOSS4G 2013" border="0" width="200" height="117"> 
+<tr><td><a href="http://2015.foss4g.org/"> 
+<img src="foss4g2015.png" alt="FOSS4G 2015" border="0" width="150" height="75"> 
 </a></td> 
  
-<td><a href="http://2013.foss4g.org">FOSS4G 2013</a> is the leading annual  
+<td><a href="http://2015.foss4g.org">FOSS4G 2015</a> is the leading annual  
 conference for free and open source geospatial software.  It will include  
 presentations related to GDAL/OGR, and some of the GDAL/OGR  
 development community will be attending.  It is <i>the</i> event for those  
 interested in GDAL/OGR, other FOSS geospatial technologies and the community  
-around them.</td> 
+around them. The conference will be held in Seoul, South Korea <strong>September 14th - 19th, 2015</strong>.</td>
 </table> 
 \endhtmlonly
 
diff --git a/frmts/aaigrid/GNUmakefile b/frmts/aaigrid/GNUmakefile
index 259fb1c..9f08766 100644
--- a/frmts/aaigrid/GNUmakefile
+++ b/frmts/aaigrid/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	aaigriddataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/aaigrid/aaigriddataset.cpp b/frmts/aaigrid/aaigriddataset.cpp
index d44ebee..bb67c57 100644
--- a/frmts/aaigrid/aaigriddataset.cpp
+++ b/frmts/aaigrid/aaigriddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: aaigriddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: aaigriddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  GDAL
  * Purpose:  Implements Arc/Info ASCII Grid Format.
@@ -35,7 +35,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: aaigriddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: aaigriddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 void    GDALRegister_AAIGrid(void);
@@ -741,6 +741,8 @@ GDALDataset *AAIGDataset::CommonOpen( GDALOpenInfo * poOpenInfo,
     const char* pszDataTypeOption = (eFormat == FORMAT_AAIG) ? "AAIGRID_DATATYPE":
                                                                "GRASSASCIIGRID_DATATYPE";
     const char* pszDataType = CPLGetConfigOption(pszDataTypeOption, NULL);
+    if( pszDataType == NULL )
+        pszDataType = CSLFetchNameValue( poOpenInfo->papszOpenOptions, "DATATYPE" );
     if (pszDataType != NULL)
     {
         poDS->eDataType = GDALGetDataTypeByName(pszDataType);
@@ -920,7 +922,7 @@ GDALDataset *AAIGDataset::CommonOpen( GDALOpenInfo * poOpenInfo,
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -951,10 +953,10 @@ const char *AAIGDataset::GetProjectionRef()
 /************************************************************************/
 
 GDALDataset * AAIGDataset::CreateCopy(
-                const char * pszFilename, GDALDataset *poSrcDS,
-                CPL_UNUSED int bStrict, char ** papszOptions, 
-                GDALProgressFunc pfnProgress, void * pProgressData )
-
+    const char * pszFilename, GDALDataset *poSrcDS,
+    CPL_UNUSED int bStrict,
+    char ** papszOptions,
+    GDALProgressFunc pfnProgress, void * pProgressData )
 {
     int  nBands = poSrcDS->GetRasterCount();
     int  nXSize = poSrcDS->GetRasterXSize();
@@ -1002,7 +1004,7 @@ GDALDataset * AAIGDataset::CreateCopy(
     if( ABS(adfGeoTransform[1]+adfGeoTransform[5]) < 0.0000001 
         || ABS(adfGeoTransform[1]-adfGeoTransform[5]) < 0.0000001 
         || (pszForceCellsize && CSLTestBoolean(pszForceCellsize)) )
-        sprintf( szHeader, 
+        CPLsprintf( szHeader, 
                  "ncols        %d\n" 
                  "nrows        %d\n"
                  "xllcorner    %.12f\n"
@@ -1021,7 +1023,7 @@ GDALDataset * AAIGDataset::CreateCopy(
                       "FORCE_CELLSIZE=TRUE creation option to force use of DX for\n"
                       "even though this will be distorted.  Most ASCII Grid readers\n"
                       "(ArcGIS included) do not support the DX and DY parameters.\n" );
-        sprintf( szHeader, 
+        CPLsprintf( szHeader, 
                  "ncols        %d\n" 
                  "nrows        %d\n"
                  "xllcorner    %.12f\n"
@@ -1063,7 +1065,7 @@ GDALDataset * AAIGDataset::CreateCopy(
     {
         nPrecision = atoi( pszDecimalPrecision );
         if ( nPrecision >= 0 )
-            sprintf( szFormatFloat, " %%.%dlf", nPrecision );
+            sprintf( szFormatFloat, " %%.%df", nPrecision );
         CPLDebug( "AAIGrid", "Setting precision format: %s", szFormatFloat );
     }
 
@@ -1087,7 +1089,7 @@ GDALDataset * AAIGDataset::CreateCopy(
         if( bReadAsInt )
             sprintf( szHeader+strlen( szHeader ), "%d", (int)dfNoData );
         else
-            sprintf( szHeader+strlen( szHeader ), szFormatFloat, dfNoData );
+            CPLsprintf( szHeader+strlen( szHeader ), szFormatFloat, dfNoData );
         sprintf( szHeader+strlen( szHeader ), "\n" );
     }
 
@@ -1115,7 +1117,7 @@ GDALDataset * AAIGDataset::CreateCopy(
         eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                  (bReadAsInt) ? (void*)panScanline : (void*)padfScanline,
                                  nXSize, 1, (bReadAsInt) ? GDT_Int32 : GDT_Float64,
-                                 0, 0 );
+                                 0, 0, NULL );
 
         if( bReadAsInt )
         {
@@ -1140,7 +1142,7 @@ GDALDataset * AAIGDataset::CreateCopy(
         {
             for ( iPixel = 0; iPixel < nXSize; iPixel++ )
             {
-                sprintf( szHeader, szFormatFloat, padfScanline[iPixel] );
+                CPLsprintf( szHeader, szFormatFloat, padfScanline[iPixel] );
                 osBuf += szHeader;
                 if( (iPixel & 1023) == 0 || iPixel == nXSize - 1 )
                 {
@@ -1213,7 +1215,7 @@ GDALDataset * AAIGDataset::CreateCopy(
     }
     
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     /* If outputing to stdout, we can't reopen it, so we'll return */
@@ -1288,6 +1290,7 @@ void GDALRegister_AAIGrid()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "AAIGrid" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Arc/Info ASCII Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -1303,6 +1306,14 @@ void GDALRegister_AAIGrid()
 "   <Option name='DECIMAL_PRECISION' type='int' description='Number of decimal when writing floating-point numbers(%f).'/>\n"
 "   <Option name='SIGNIFICANT_DIGITS' type='int' description='Number of significant digits when writing floating-point numbers(%g).'/>\n"
 "</CreationOptionList>\n" );
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionLists>\n"
+"   <Option name='DATATYPE' type='string-select' description='Data type to be used.'>\n"
+"       <Value>Int32</Value>\n"
+"       <Value>Float32</Value>\n"
+"       <Value>Float64</Value>\n"
+"   </Option>\n"
+"</OpenOptionLists>\n" );
 
         poDriver->pfnOpen = AAIGDataset::Open;
         poDriver->pfnIdentify = AAIGDataset::Identify;
@@ -1326,6 +1337,7 @@ void GDALRegister_GRASSASCIIGrid()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "GRASSASCIIGrid" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "GRASS ASCII Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/adrg/GNUmakefile b/frmts/adrg/GNUmakefile
index afa8b0b..1005bfe 100644
--- a/frmts/adrg/GNUmakefile
+++ b/frmts/adrg/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	adrgdataset.o srpdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) -I../iso8211
+CPPFLAGS	:=	 $(CPPFLAGS) -I../iso8211
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/adrg/adrgdataset.cpp b/frmts/adrg/adrgdataset.cpp
index 39608bf..14d78c6 100644
--- a/frmts/adrg/adrgdataset.cpp
+++ b/frmts/adrg/adrgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: adrgdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: adrgdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Purpose:  ADRG reader
  * Author:   Even Rouault, even.rouault at mines-paris.org
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include "iso8211.h"
 
-CPL_CVSID("$Id: adrgdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: adrgdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 #define N_ELEMENTS(x)  (sizeof(x)/sizeof(x[0]))
 
@@ -761,7 +761,7 @@ double ADRGDataset::GetLongitudeFromString(const char* str)
     strncpy(mm, str, 2);
     str+=2;
     strncpy(ssdotss, str, 5);
-    return sign * (atof(ddd) + atof(mm) / 60 + atof(ssdotss) / 3600);
+    return sign * (CPLAtof(ddd) + CPLAtof(mm) / 60 + CPLAtof(ssdotss) / 3600);
 }
 
 /************************************************************************/
@@ -780,7 +780,7 @@ double ADRGDataset::GetLatitudeFromString(const char* str)
     strncpy(mm, str, 2);
     str+=2;
     strncpy(ssdotss, str, 5);
-    return sign * (atof(ddd) + atof(mm) / 60 + atof(ssdotss) / 3600);
+    return sign * (CPLAtof(ddd) + CPLAtof(mm) / 60 + CPLAtof(ssdotss) / 3600);
 }
 
 /************************************************************************/
@@ -1568,8 +1568,12 @@ GDALDataset *ADRGDataset::Open( GDALOpenInfo * poOpenInfo )
 /*                               Create()                               */
 /************************************************************************/
 
-GDALDataset *ADRGDataset::Create(const char* pszFilename, int nXSize, int nYSize,
-                                 int nBands, GDALDataType eType, CPL_UNUSED char **papszOptions)
+GDALDataset *ADRGDataset::Create(const char* pszFilename,
+                                 int nXSize,
+                                 int nYSize,
+                                 int nBands,
+                                 GDALDataType eType,
+                                 CPL_UNUSED char **papszOptions)
 {
     int i;
 
@@ -2246,6 +2250,7 @@ void GDALRegister_ADRG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ADRG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ARC Digitized Raster Graphics" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -2262,4 +2267,3 @@ void GDALRegister_ADRG()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/adrg/srpdataset.cpp b/frmts/adrg/srpdataset.cpp
index 47119f2..cb6c48f 100644
--- a/frmts/adrg/srpdataset.cpp
+++ b/frmts/adrg/srpdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: srpdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: srpdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  * Purpose:  ASRP/USRP Reader
  * Author:   Frank Warmerdam (warmerdam at pobox.com)
  *
@@ -36,7 +36,7 @@
 // Uncomment to recognize also .gen files in addition to .img files
 // #define OPEN_GEN
 
-CPL_CVSID("$Id: srpdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: srpdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 class SRPDataset : public GDALPamDataset
 {
@@ -1613,6 +1613,7 @@ void GDALRegister_SRP()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "SRP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Standard Raster Product (ASRP/USRP)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/aigrid/GNUmakefile b/frmts/aigrid/GNUmakefile
index 7dfdd2c..4d48b5b 100644
--- a/frmts/aigrid/GNUmakefile
+++ b/frmts/aigrid/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 AIGOBJ  =	gridlib.o aigopen.o aigccitt.o
 OBJ	=	aigdataset.o $(AIGOBJ)
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) -I../../ogr/ogrsf_frmts/avc
+CPPFLAGS	:=	 $(CPPFLAGS) -I../../ogr/ogrsf_frmts/avc
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/aigrid/aigccitt.c b/frmts/aigrid/aigccitt.c
index fc57659..431bf45 100644
--- a/frmts/aigrid/aigccitt.c
+++ b/frmts/aigrid/aigccitt.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: aigccitt.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: aigccitt.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Arc/Info Binary Grid Translator
  * Purpose:  Code for decoding CCITT RLE (G1) compressed data.
@@ -1852,10 +1852,10 @@ Fax3DecodeRLE(Fax3BaseState* tif, unsigned char *buf, int occ,
 /*                       DecompressCCITTRLETile()                       */
 /************************************************************************/
 
-CPLErr DecompressCCITTRLETile( unsigned char *pabySrcData, int nSrcBytes, 
+CPLErr DecompressCCITTRLETile( unsigned char *pabySrcData, int nSrcBytes,
                                unsigned char *pabyDstData, int nDstBytes,
-                               int nBlockXSize, CPL_UNUSED int nBlockYSize )
-
+                               int nBlockXSize,
+                               CPL_UNUSED int nBlockYSize )
 {
     Fax3DecodeState  sDecoderState;
     Fax3BaseState* sp = (Fax3BaseState *) &sDecoderState;
@@ -1863,15 +1863,14 @@ CPLErr DecompressCCITTRLETile( unsigned char *pabySrcData, int nSrcBytes,
     long rowbytes, rowpixels;
 
     memset( &sDecoderState, 0, sizeof(sDecoderState) );
-    
-    sp->groupoptions = 0;	
+
+    sp->groupoptions = 0;
     sp->recvparams = 0;
     sp->subaddress = NULL;
-    
+
     DecoderState(sp)->runs = NULL;
     DecoderState(sp)->fill = aig_TIFFFax3fillruns;
 
-    /* TODO: Verify that the cast is safe. */
     if( sizeof(runs_buf) < (size_t)(nBlockXSize * 2 + 3) )
     {
         CPLError(CE_Failure, CPLE_AppDefined, "Run buffer too small");
diff --git a/frmts/aigrid/aigdataset.cpp b/frmts/aigrid/aigdataset.cpp
index ab52ce6..584bd46 100644
--- a/frmts/aigrid/aigdataset.cpp
+++ b/frmts/aigrid/aigdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: aigdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: aigdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Arc/Info Binary Grid Driver
  * Purpose:  Implements GDAL interface to underlying library.
@@ -36,7 +36,7 @@
 #include "avc.h"
 #include <vector>
 
-CPL_CVSID("$Id: aigdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: aigdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_AIGrid(void);
@@ -1083,6 +1083,7 @@ void GDALRegister_AIGrid()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "AIG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Arc/Info Binary Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/aigrid/aitest.c b/frmts/aigrid/aitest.c
index 1f36a6f..a966ddc 100644
--- a/frmts/aigrid/aitest.c
+++ b/frmts/aigrid/aitest.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: aitest.c 22159 2011-04-14 18:18:54Z warmerdam $
+ * $Id: aitest.c 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  Arc/Info Binary Grid Translator
  * Purpose:  Test mainline for examining AIGrid files.
@@ -29,7 +29,7 @@
 
 #include "aigrid.h"
 
-CPL_CVSID("$Id: aitest.c 22159 2011-04-14 18:18:54Z warmerdam $");
+CPL_CVSID("$Id: aitest.c 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /*                             DumpMagic()                              */
@@ -115,7 +115,7 @@ int main( int argc, char ** argv )
     AIGInfo_t	*psInfo;
     GInt32 	*panRaster;
     int		i, j;
-    int		bMagic = FALSE, bSupressMagic = FALSE;
+    int		bMagic = FALSE, bSuppressMagic = FALSE;
     int         iTestTileX = 0, iTestTileY = 0;
 
 /* -------------------------------------------------------------------- */
@@ -127,7 +127,7 @@ int main( int argc, char ** argv )
             bMagic = TRUE;
 
         else if( EQUAL(argv[1],"-nomagic") )
-            bSupressMagic = TRUE;
+            bSuppressMagic = TRUE;
 
         else if( EQUAL(argv[1],"-t") && argc > 2 )
         {
@@ -184,7 +184,7 @@ int main( int argc, char ** argv )
 /*      Do we want a dump of all the ``magic'' numbers for              */
 /*      instantated blocks?                                             */
 /* -------------------------------------------------------------------- */
-    if( !bSupressMagic )
+    if( !bSuppressMagic )
         DumpMagic( psInfo, bMagic );
     
 /* -------------------------------------------------------------------- */
diff --git a/frmts/airsar/GNUmakefile b/frmts/airsar/GNUmakefile
index 615f4f9..7db8f8b 100644
--- a/frmts/airsar/GNUmakefile
+++ b/frmts/airsar/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	airsardataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/airsar/airsardataset.cpp b/frmts/airsar/airsardataset.cpp
index fa2880d..c16a56e 100644
--- a/frmts/airsar/airsardataset.cpp
+++ b/frmts/airsar/airsardataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: airsardataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: airsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  AirSAR Reader
  * Purpose:  Implements read support for AirSAR Polarimetric data.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_vsi.h"
 
-CPL_CVSID("$Id: airsardataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: airsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_AirSAR(void);
@@ -51,7 +51,7 @@ class AirSARDataset : public GDALPamDataset
 {
     friend class AirSARRasterBand;
 
-    FILE	*fp;
+    VSILFILE	*fp;
 
     int         nLoadedLine;
     GByte       *pabyCompressedLine;
@@ -62,7 +62,7 @@ class AirSARDataset : public GDALPamDataset
 
     CPLErr      LoadLine(int iLine);
 
-    static char  **ReadHeader( FILE * fp, int nFileOffset, 
+    static char  **ReadHeader( VSILFILE * fp, int nFileOffset, 
                                const char *pszPrefix, int nMaxLines );
 
   public:
@@ -173,9 +173,9 @@ AirSARRasterBand::~AirSARRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr AirSARRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                      void * pImage )
-
+CPLErr AirSARRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                     int nBlockYOff,
+                                     void * pImage )
 {
     CPLErr eErr;
     float *pafLine = (float *) pImage;
@@ -299,7 +299,7 @@ AirSARDataset::~AirSARDataset()
 
     if( fp != NULL )
     {
-        VSIFClose( fp );
+        VSIFCloseL( fp );
         fp = NULL;
     }
 }
@@ -340,8 +340,8 @@ CPLErr AirSARDataset::LoadLine( int iLine )
 /* -------------------------------------------------------------------- */
 /*      Load raw compressed data.                                       */
 /* -------------------------------------------------------------------- */
-    if( VSIFSeek( fp, nDataStart + iLine * nRecordLength, SEEK_SET ) != 0 
-        || ((int) VSIFRead( pabyCompressedLine, 10, nRasterXSize, fp ))
+    if( VSIFSeekL( fp, nDataStart + iLine * nRecordLength, SEEK_SET ) != 0 
+        || ((int) VSIFReadL( pabyCompressedLine, 10, nRasterXSize, fp ))
                  != nRasterXSize )
     {
         CPLError( CE_Failure, CPLE_FileIO, 
@@ -387,7 +387,7 @@ CPLErr AirSARDataset::LoadLine( int iLine )
 /*      blank record or some zero bytes.                                */
 /************************************************************************/
 
-char ** AirSARDataset::ReadHeader( FILE * fp, int nFileOffset, 
+char ** AirSARDataset::ReadHeader( VSILFILE * fp, int nFileOffset, 
                                    const char *pszPrefix, int nMaxLines )
 
 {
@@ -395,7 +395,7 @@ char ** AirSARDataset::ReadHeader( FILE * fp, int nFileOffset,
     char szLine[51];
     int  iLine;
 
-    VSIFSeek( fp, nFileOffset, SEEK_SET );
+    VSIFSeekL( fp, nFileOffset, SEEK_SET );
 
 /* ==================================================================== */
 /*      Loop collecting one line at a time.                             */
@@ -405,7 +405,7 @@ char ** AirSARDataset::ReadHeader( FILE * fp, int nFileOffset,
 /* -------------------------------------------------------------------- */
 /*      Read a 50 byte header record.                                   */
 /* -------------------------------------------------------------------- */
-        if( VSIFRead( szLine, 1, 50, fp ) != 50 )
+        if( VSIFReadL( szLine, 1, 50, fp ) != 50 )
         {
             CPLError( CE_Failure, CPLE_FileIO,
                       "Read error collecting AirSAR header." );
@@ -522,7 +522,7 @@ char ** AirSARDataset::ReadHeader( FILE * fp, int nFileOffset,
 GDALDataset *AirSARDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 800 )
+    if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 800 )
         return NULL;
 
 /* -------------------------------------------------------------------- */
@@ -540,7 +540,7 @@ GDALDataset *AirSARDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      keywords by converting spaces to underscores so they will be    */
 /*      "well behaved" as metadata keywords.                            */
 /* -------------------------------------------------------------------- */
-    char **papszMD = ReadHeader( poOpenInfo->fp, 0, "MH", 20 );
+    char **papszMD = ReadHeader( poOpenInfo->fpL, 0, "MH", 20 );
     
     if( papszMD == NULL )
         return NULL;
@@ -580,8 +580,8 @@ GDALDataset *AirSARDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Adopt the openinfo file pointer.                                */
 /* -------------------------------------------------------------------- */
-    poDS->fp = poOpenInfo->fp;
-    poOpenInfo->fp = NULL;
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Read and merge parameter header into metadata.  Prefix          */
@@ -659,9 +659,13 @@ void GDALRegister_AirSAR()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "AirSAR" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "AirSAR Polarimetric Image" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_airsar.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
         poDriver->pfnOpen = AirSARDataset::Open;
 
         GetGDALDriverManager()->RegisterDriver( poDriver );
diff --git a/frmts/arg/GNUmakefile b/frmts/arg/GNUmakefile
index 08af072..1e22ece 100644
--- a/frmts/arg/GNUmakefile
+++ b/frmts/arg/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	argdataset.o
 
-CPPFLAGS :=	$(JSON_INCLUDE) -I../raw $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS :=	$(JSON_INCLUDE) -I../raw  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/arg/argdataset.cpp b/frmts/arg/argdataset.cpp
index 5a7e646..af4a550 100644
--- a/frmts/arg/argdataset.cpp
+++ b/frmts/arg/argdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: argdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Azavea Raster Grid format driver.
  * Purpose:  Implements support for reading and writing Azavea Raster Grid
@@ -34,7 +34,7 @@
 #include <json.h>
 #include <ogr_spatialref.h>
 
-CPL_CVSID("$Id: argdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: argdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 #define MAX_FILENAME_LEN 4096
 
@@ -139,7 +139,7 @@ json_object * GetJsonObject(CPLString pszFilename)
     CPLString osJSONFilename = GetJsonFilename(pszFilename);
 
     pJSONObject = json_object_from_file((char *)osJSONFilename.c_str());
-    if (pJSONObject == (struct json_object*)error_ptr(-1) || pJSONObject == NULL) {
+    if (pJSONObject == NULL) {
         CPLDebug("ARGDataset", "GetJsonObject(): "
             "Could not parse JSON file.");
         return NULL;
@@ -785,7 +785,7 @@ GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
 
                 eErr = poSrcBand->RasterIO(GF_Read, nXBlock * nXBlockSize, 
                     nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize, 
-                    1, eType, 0, 0);
+                    1, eType, 0, 0, NULL);
 
                 if (eErr != CE_None) {
                     CPLError(CE_Failure, CPLE_AppDefined, "Error reading.");
@@ -799,7 +799,7 @@ GDALDataset * ARGDataset::CreateCopy( const char * pszFilename,
 
                 eErr = poDstBand->RasterIO(GF_Write, nXBlock * nXBlockSize, 
                     nYBlock * nYBlockSize + nYScanline, nXValid, 1, pabyData, nXBlockSize, 
-                    1, eType, 0, 0);
+                    1, eType, 0, 0, NULL);
 
                 if (eErr != CE_None) {
                     CPLError(CE_Failure, CPLE_AppDefined, "Error writing.");
@@ -834,6 +834,7 @@ void GDALRegister_ARG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ARG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Azavea Raster Grid format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/blx/GNUmakefile b/frmts/blx/GNUmakefile
index a63f74d..ebe9f1e 100644
--- a/frmts/blx/GNUmakefile
+++ b/frmts/blx/GNUmakefile
@@ -5,7 +5,7 @@ XTRA_OPT =	-I. -DGDALDRIVER
 
 OBJ	=	blxdataset.o blx.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS)
 
 default:        $(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/blx/blx.c b/frmts/blx/blx.c
index a3a8f99..9c6bec8 100644
--- a/frmts/blx/blx.c
+++ b/frmts/blx/blx.c
@@ -534,7 +534,11 @@ int lutcmp(const void *aa, const void *bb) {
 }
 
 
-int blx_encode_celldata(blxcontext_t *ctx, blxdata *indata, int side, unsigned char *outbuf, CPL_UNUSED int outbufsize) {
+int blx_encode_celldata(blxcontext_t *ctx,
+                        blxdata *indata,
+                        int side,
+                        unsigned char *outbuf,
+                        CPL_UNUSED int outbufsize) {
     unsigned char *p=outbuf, *tmpdata, *coutstart, *cout=NULL;
     int level, cn, coutsize, zeros;
     blxdata *vdec=NULL, *vdiff=NULL, *c[4], *tc1, *clut, *indata_scaled;
diff --git a/frmts/blx/blxdataset.cpp b/frmts/blx/blxdataset.cpp
index 16632af..9075c22 100644
--- a/frmts/blx/blxdataset.cpp
+++ b/frmts/blx/blxdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: blxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  BLX Driver
  * Purpose:  GDAL BLX support.
@@ -33,7 +33,7 @@
 #include "gdal_pam.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: blxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: blxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 #include <blx.h>
@@ -83,7 +83,7 @@ GDALDataset *BLXDataset::Open( GDALOpenInfo * poOpenInfo )
     // -------------------------------------------------------------------- 
     //      First that the header looks like a BLX header
     // -------------------------------------------------------------------- 
-    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 102 )
+    if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 102 )
         return NULL;
 
     if(!blx_checkheader((char *)poOpenInfo->pabyHeader))
@@ -387,7 +387,7 @@ BLXCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 	    eErr = poBand->RasterIO( GF_Read, j*ctx->cell_xsize, i*ctx->cell_ysize, 
 				     ctx->cell_xsize, ctx->cell_ysize, 
 				     pabyTile, ctx->cell_xsize, ctx->cell_ysize, GDT_Int16,
-				     0, 0 );
+				     0, 0, NULL );
 	    if(eErr >= CE_Failure) 
 	       break;
 	    celldata = pabyTile;
@@ -437,6 +437,7 @@ void GDALRegister_BLX()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "BLX" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Magellan topo (.blx)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/bmp/GNUmakefile b/frmts/bmp/GNUmakefile
index 34f4aad..756ed58 100644
--- a/frmts/bmp/GNUmakefile
+++ b/frmts/bmp/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	bmpdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/bmp/bmpdataset.cpp b/frmts/bmp/bmpdataset.cpp
index 9ca9bfa..ed8be04 100644
--- a/frmts/bmp/bmpdataset.cpp
+++ b/frmts/bmp/bmpdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: bmpdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: bmpdataset.cpp 28234 2014-12-27 14:22:54Z rouault $
  *
  * Project:  Microsoft Windows Bitmap
  * Purpose:  Read/write MS Windows Device Independent Bitmap (DIB) files
@@ -32,7 +32,7 @@
 #include "gdal_pam.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: bmpdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: bmpdataset.cpp 28234 2014-12-27 14:22:54Z rouault $");
 
 CPL_C_START
 void    GDALRegister_BMP(void);
@@ -230,7 +230,10 @@ class BMPDataset : public GDALPamDataset
   protected:
     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
                                    void *, int, int, GDALDataType,
-                                   int, int *, int, int, int );
+                                   int, int *,
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GSpacing nBandSpace,
+                                   GDALRasterIOExtraArg* psExtraArg );
 
   public:
                 BMPDataset();
@@ -321,7 +324,8 @@ BMPRasterBand::~BMPRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr BMPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr BMPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
 {
     BMPDataset  *poGDS = (BMPDataset *) poDS;
@@ -860,8 +864,9 @@ BMPComprRasterBand::~BMPComprRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr BMPComprRasterBand::
-    IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, void * pImage )
+CPLErr BMPComprRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
+                                       void * pImage )
 {
     memcpy( pImage, pabyUncomprBuf +
             (poDS->GetRasterYSize() - nBlockYOff - 1) * poDS->GetRasterXSize(),
@@ -924,6 +929,8 @@ CPLErr BMPDataset::GetGeoTransform( double * padfTransform )
     if( GDALPamDataset::GetGeoTransform( padfTransform ) == CE_None)
         return CE_None;
 
+#ifdef notdef
+    // See http://trac.osgeo.org/gdal/ticket/3578
     if (sInfoHeader.iXPelsPerMeter > 0 && sInfoHeader.iYPelsPerMeter > 0)
     {
         padfTransform[1] = sInfoHeader.iXPelsPerMeter;
@@ -932,6 +939,7 @@ CPLErr BMPDataset::GetGeoTransform( double * padfTransform )
         padfTransform[3] = -0.5*padfTransform[5];
         return CE_None;
     }
+#endif
 
     return CE_Failure;
 }
@@ -974,20 +982,22 @@ CPLErr BMPDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType,
                               int nBandCount, int *panBandMap, 
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     if( nBandCount > 1 )
         return GDALDataset::BlockBasedRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else
         return 
             GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                     pData, nBufXSize, nBufYSize, eBufType, 
                                     nBandCount, panBandMap, 
-                                    nPixelSpace, nLineSpace, nBandSpace );
+                                    nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -1520,6 +1530,7 @@ void GDALRegister_BMP()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "BMP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "MS Windows Device Independent Bitmap" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -1540,4 +1551,3 @@ void GDALRegister_BMP()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/bpg/bpgdataset.cpp b/frmts/bpg/bpgdataset.cpp
new file mode 100644
index 0000000..4aefc49
--- /dev/null
+++ b/frmts/bpg/bpgdataset.cpp
@@ -0,0 +1,361 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  GDAL BPG Driver
+ * Purpose:  Implement GDAL BPG Support based on libbpg
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include <stdint.h>
+#include "gdal_pam.h"
+#include "cpl_string.h"
+
+// NOTE: build instructions
+// bpg Makefile needs to be modified to have -fPIC on CFLAGS:= at line 49 and LDFLAGS at line 54 before building bpg
+// g++ -fPIC -g -Wall -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -I/home/even/libbpg-0.9.4 frmts/bpg/bpgdataset.cpp -shared -o gdal_BPG.so -L. -lgdal -L/home/even/libbpg-0.9.4/ -lbpg
+
+CPL_C_START
+#include "libbpg.h"
+CPL_C_END
+
+CPL_CVSID("$Id$");
+
+CPL_C_START
+void    GDALRegister_BPG(void);
+CPL_C_END
+
+/************************************************************************/
+/* ==================================================================== */
+/*                               BPGDataset                             */
+/* ==================================================================== */
+/************************************************************************/
+
+class BPGRasterBand;
+
+class BPGDataset : public GDALPamDataset
+{
+    friend class BPGRasterBand;
+
+    VSILFILE*   fpImage;
+    GByte* pabyUncompressed;
+    int    bHasBeenUncompressed;
+    CPLErr eUncompressErrRet;
+    CPLErr Uncompress();
+
+  public:
+                 BPGDataset();
+                 ~BPGDataset();
+
+    static GDALDataset *Open( GDALOpenInfo * );
+    static int          Identify( GDALOpenInfo * );
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                            BPGRasterBand                             */
+/* ==================================================================== */
+/************************************************************************/
+
+class BPGRasterBand : public GDALPamRasterBand
+{
+    friend class BPGDataset;
+
+  public:
+
+                   BPGRasterBand( BPGDataset *, int nbits );
+
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual GDALColorInterp GetColorInterpretation();
+};
+
+/************************************************************************/
+/*                          BPGRasterBand()                            */
+/************************************************************************/
+
+BPGRasterBand::BPGRasterBand( BPGDataset *poDS, int nbits )
+{
+    this->poDS = poDS;
+
+    eDataType = (nbits > 8) ? GDT_UInt16 : GDT_Byte;
+
+    nBlockXSize = poDS->nRasterXSize;
+    nBlockYSize = 1;
+}
+
+/************************************************************************/
+/*                             IReadBlock()                             */
+/************************************************************************/
+
+CPLErr BPGRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+                                   void * pImage )
+{
+    BPGDataset* poGDS = (BPGDataset*) poDS;
+
+    if( poGDS->Uncompress() != CE_None )
+        return CE_Failure;
+
+    int i;
+    int iBand = nBand;
+    if( poGDS->nBands == 2 )
+        iBand = 4;
+    if( eDataType == GDT_Byte )
+    {
+        GByte* pabyUncompressed =
+            &poGDS->pabyUncompressed[nBlockYOff * nRasterXSize  * poGDS->nBands + iBand - 1];
+        for(i=0;i<nRasterXSize;i++)
+            ((GByte*)pImage)[i] = pabyUncompressed[poGDS->nBands * i];
+    }
+    else
+    {
+        GUInt16* pasUncompressed = (GUInt16*)
+            &poGDS->pabyUncompressed[(nBlockYOff * nRasterXSize  * poGDS->nBands + iBand - 1) * 2];
+        for(i=0;i<nRasterXSize;i++)
+            ((GUInt16*)pImage)[i] = pasUncompressed[poGDS->nBands * i];
+    }
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                       GetColorInterpretation()                       */
+/************************************************************************/
+
+GDALColorInterp BPGRasterBand::GetColorInterpretation()
+
+{
+    BPGDataset* poGDS = (BPGDataset*) poDS;
+    if( poGDS->nBands >= 3 )
+        return (GDALColorInterp) (GCI_RedBand + (nBand - 1));
+    else if( nBand == 1 )
+        return GCI_GrayIndex;
+    else
+        return GCI_AlphaBand;
+}
+
+/************************************************************************/
+/* ==================================================================== */
+/*                             BPGDataset                               */
+/* ==================================================================== */
+/************************************************************************/
+
+
+/************************************************************************/
+/*                            BPGDataset()                              */
+/************************************************************************/
+
+BPGDataset::BPGDataset()
+
+{
+    fpImage = NULL;
+    pabyUncompressed = NULL;
+    bHasBeenUncompressed = FALSE;
+    eUncompressErrRet = CE_None;
+}
+
+/************************************************************************/
+/*                           ~BPGDataset()                              */
+/************************************************************************/
+
+BPGDataset::~BPGDataset()
+
+{
+    FlushCache();
+    if (fpImage)
+        VSIFCloseL(fpImage);
+    VSIFree(pabyUncompressed);
+}
+
+/************************************************************************/
+/*                            Uncompress()                              */
+/************************************************************************/
+
+CPLErr BPGDataset::Uncompress()
+{
+    if (bHasBeenUncompressed)
+        return eUncompressErrRet;
+    bHasBeenUncompressed = TRUE;
+    eUncompressErrRet = CE_Failure;
+
+    int nOutBands = (nBands < 3) ? nBands + 2 : nBands;
+    int nDTSize = ( GetRasterBand(1)->GetRasterDataType() == GDT_Byte ) ? 1 : 2;
+    pabyUncompressed = (GByte*)VSIMalloc3(nRasterXSize, nRasterYSize,
+                                          nOutBands * nDTSize);
+    if (pabyUncompressed == NULL)
+        return CE_Failure;
+
+    VSIFSeekL(fpImage, 0, SEEK_END);
+    vsi_l_offset nSize = VSIFTellL(fpImage);
+    if (nSize != (vsi_l_offset)(int)nSize)
+        return CE_Failure;
+    VSIFSeekL(fpImage, 0, SEEK_SET);
+    uint8_t* pabyCompressed = (uint8_t*)VSIMalloc(nSize);
+    if (pabyCompressed == NULL)
+        return CE_Failure;
+    VSIFReadL(pabyCompressed, 1, nSize, fpImage);
+
+    BPGDecoderContext* ctxt = bpg_decoder_open();
+    if( ctxt == NULL )
+    {
+        VSIFree(pabyCompressed);
+        return CE_Failure;
+    }
+    BPGDecoderOutputFormat eOutputFormat;
+    
+    if( GetRasterBand(1)->GetRasterDataType() == GDT_Byte )
+        eOutputFormat = (nBands == 1 || nBands == 3) ? BPG_OUTPUT_FORMAT_RGB24 :
+                                                       BPG_OUTPUT_FORMAT_RGBA32;
+    else
+        eOutputFormat = (nBands == 1 || nBands == 3) ? BPG_OUTPUT_FORMAT_RGB48 :
+                                                       BPG_OUTPUT_FORMAT_RGBA64;
+    if( bpg_decoder_decode(ctxt, pabyCompressed, (int)nSize) < 0 ||
+        bpg_decoder_start(ctxt, eOutputFormat) < 0 )
+    {
+        bpg_decoder_close(ctxt);
+        VSIFree(pabyCompressed);
+        return CE_Failure;
+    }
+
+    for(int i=0;i<nRasterYSize;i++)
+    {
+        void* pRow = pabyUncompressed + i * nBands * nRasterXSize * nDTSize;
+        if( bpg_decoder_get_line(ctxt, pRow) < 0 )
+        {
+            bpg_decoder_close(ctxt);
+            VSIFree(pabyCompressed);
+            return CE_Failure;
+        }
+    }
+
+    bpg_decoder_close(ctxt);
+    VSIFree(pabyCompressed);
+
+    eUncompressErrRet = CE_None;
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                              Identify()                              */
+/************************************************************************/
+
+int BPGDataset::Identify( GDALOpenInfo * poOpenInfo )
+
+{
+    if( poOpenInfo->nHeaderBytes < BPG_DECODER_INFO_BUF_SIZE )
+        return FALSE;
+
+    return memcmp(poOpenInfo->pabyHeader, "BPG\xfb", 4) == 0;
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset *BPGDataset::Open( GDALOpenInfo * poOpenInfo )
+
+{
+    if( !Identify( poOpenInfo ) || poOpenInfo->fpL == NULL )
+        return NULL;
+
+    BPGImageInfo imageInfo;
+    if( bpg_decoder_get_info_from_buf(&imageInfo, NULL,
+                                      poOpenInfo->pabyHeader,
+                                      poOpenInfo->nHeaderBytes) < 0 )
+        return NULL;
+
+    if( poOpenInfo->eAccess == GA_Update )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "The BPG driver does not support update access to existing"
+                  " datasets.\n" );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create a corresponding GDALDataset.                             */
+/* -------------------------------------------------------------------- */
+    BPGDataset  *poDS;
+
+    poDS = new BPGDataset();
+    poDS->nRasterXSize = imageInfo.width;
+    poDS->nRasterYSize = imageInfo.height;
+    poDS->fpImage = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Create band information objects.                                */
+/* -------------------------------------------------------------------- */
+    int nBands = ( imageInfo.format == BPG_FORMAT_GRAY ) ? 1 : 3;
+    if( imageInfo.has_alpha )
+        nBands ++;
+
+    for( int iBand = 0; iBand < nBands; iBand++ )
+        poDS->SetBand( iBand+1, new BPGRasterBand( poDS, imageInfo.bit_depth ) );
+
+/* -------------------------------------------------------------------- */
+/*      Initialize any PAM information.                                 */
+/* -------------------------------------------------------------------- */
+    poDS->SetDescription( poOpenInfo->pszFilename );
+
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
+
+/* -------------------------------------------------------------------- */
+/*      Open overviews.                                                 */
+/* -------------------------------------------------------------------- */
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
+                                 poOpenInfo->GetSiblingFiles() );
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                         GDALRegister_BPG()                           */
+/************************************************************************/
+
+void GDALRegister_BPG()
+
+{
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "BPG" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "BPG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Better Portable Graphics" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "frmt_bpg.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "bpg" );
+        //poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/bpg" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnIdentify = BPGDataset::Identify;
+        poDriver->pfnOpen = BPGDataset::Open;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/frmts/bsb/GNUmakefile b/frmts/bsb/GNUmakefile
index a2796af..971e9ce 100644
--- a/frmts/bsb/GNUmakefile
+++ b/frmts/bsb/GNUmakefile
@@ -8,7 +8,7 @@ OBJ	=	bsb_read.o bsbdataset.o
 
 DISTDIR =	bsb-$(VERSION)
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/bsb/bsb_read.c b/frmts/bsb/bsb_read.c
index e7df644..f3f3f4e 100644
--- a/frmts/bsb/bsb_read.c
+++ b/frmts/bsb/bsb_read.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: bsb_read.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: bsb_read.c 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  BSB Reader
  * Purpose:  Low level BSB Access API Implementation (non-GDAL).
@@ -37,7 +37,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: bsb_read.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: bsb_read.c 28039 2014-11-30 18:24:59Z rouault $");
 
 static int BSBReadHeaderLine( BSBInfo *psInfo, char* pszLine, int nLineMaxLen, int bNO1 );
 static int BSBSeekAndCheckScanlineNumber ( BSBInfo *psInfo, int nScanline,
@@ -359,7 +359,7 @@ BSBInfo *BSBOpen( const char *pszFilename )
         }
         else if( EQUALN(szLine,"VER/",4) && nCount >= 1 )
         {
-            psInfo->nVersion = (int) (100 * atof(papszTokens[0]) + 0.5);
+            psInfo->nVersion = (int) (100 * CPLAtof(papszTokens[0]) + 0.5);
         }
 
         CSLDestroy( papszTokens );
@@ -644,7 +644,7 @@ static int BSBReadHeaderLine( BSBInfo *psInfo, char* pszLine, int nLineMaxLen, i
 /*                  BSBSeekAndCheckScanlineNumber()                     */
 /*                                                                      */
 /*       Seek to the beginning of the scanline and check that the       */
-/*       scanline number in file is consistant with what we expect      */
+/*       scanline number in file is consistent with what we expect      */
 /*                                                                      */
 /* @param nScanline zero based line number                              */
 /************************************************************************/
@@ -769,7 +769,7 @@ int BSBReadScanline( BSBInfo *psInfo, int nScanline,
 
 /* -------------------------------------------------------------------- */
 /*       Seek to the beginning of the scanline and check that the       */
-/*       scanline number in file is consistant with what we expect      */
+/*       scanline number in file is consistent with what we expect      */
 /* -------------------------------------------------------------------- */
     if ( !BSBSeekAndCheckScanlineNumber(psInfo, nScanline, TRUE) )
     {
@@ -882,8 +882,7 @@ int BSBReadScanline( BSBInfo *psInfo, int nScanline,
     while ( iPixel < psInfo->nXSize &&
             (nScanline == psInfo->nYSize-1 ||
              psInfo->panLineOffset[nScanline+1] == -1 ||
-             /* TODO: Will this work for large files? */
-             (int)(VSIFTellL( fp ) - psInfo->nBufferSize + psInfo->nBufferOffset) < psInfo->panLineOffset[nScanline+1]) );
+             VSIFTellL( fp ) - psInfo->nBufferSize + psInfo->nBufferOffset < (vsi_l_offset)psInfo->panLineOffset[nScanline+1]) );
 
 /* -------------------------------------------------------------------- */
 /*      If the line buffer is not filled after reading the line in the  */
@@ -929,9 +928,10 @@ void BSBClose( BSBInfo *psInfo )
 /*                             BSBCreate()                              */
 /************************************************************************/
 
-BSBInfo *BSBCreate( const char *pszFilename, CPL_UNUSED int nCreationFlags, int nVersion, 
+BSBInfo *BSBCreate( const char *pszFilename,
+                    CPL_UNUSED int nCreationFlags,
+                    int nVersion,
                     int nXSize, int nYSize )
-
 {
     VSILFILE	*fp;
     BSBInfo     *psInfo;
diff --git a/frmts/bsb/bsbdataset.cpp b/frmts/bsb/bsbdataset.cpp
index 5c4048d..ddcd566 100644
--- a/frmts/bsb/bsbdataset.cpp
+++ b/frmts/bsb/bsbdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: bsbdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: bsbdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  BSB Reader
  * Purpose:  BSBDataset implementation for BSB format.
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: bsbdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: bsbdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_BSB(void);
@@ -135,9 +135,9 @@ BSBRasterBand::BSBRasterBand( BSBDataset *poDS )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr BSBRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                      void * pImage )
-
+CPLErr BSBRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
+                                  void * pImage )
 {
     BSBDataset *poGDS = (BSBDataset *) poDS;
     GByte *pabyScanline = (GByte*) pImage;
@@ -616,10 +616,10 @@ void BSBDataset::ScanForGCPsNos( const char *pszFilename )
             if (CSLCount(Tokens) >= 5)
             {
                 GDALInitGCPs( 1, pasGCPList + nGCPCount );
-                pasGCPList[nGCPCount].dfGCPX = atof(Tokens[1]);
-                pasGCPList[nGCPCount].dfGCPY = atof(Tokens[2]);
-                pasGCPList[nGCPCount].dfGCPPixel = atof(Tokens[4]);
-                pasGCPList[nGCPCount].dfGCPLine = atof(Tokens[3]);
+                pasGCPList[nGCPCount].dfGCPX = CPLAtof(Tokens[1]);
+                pasGCPList[nGCPCount].dfGCPY = CPLAtof(Tokens[2]);
+                pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(Tokens[4]);
+                pasGCPList[nGCPCount].dfGCPLine = CPLAtof(Tokens[3]);
 
                 CPLFree( pasGCPList[nGCPCount].pszId );
                 char	szName[50];
@@ -676,10 +676,10 @@ void BSBDataset::ScanForGCPsBSB()
         {
             GDALInitGCPs( 1, pasGCPList + nGCPCount );
 
-            pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[4]);
-            pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[3]);
-            pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[1]);
-            pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[2]);
+            pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[4]);
+            pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
+            pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[1]);
+            pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[2]);
 
             CPLFree( pasGCPList[nGCPCount].pszId );
             if( CSLCount(papszTokens) > 5 )
@@ -1187,6 +1187,7 @@ void GDALRegister_BSB()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "BSB" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Maptech BSB Nautical Charts" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/ceos/GNUmakefile b/frmts/ceos/GNUmakefile
index 4309140..9730a2f 100644
--- a/frmts/ceos/GNUmakefile
+++ b/frmts/ceos/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	ceosopen.o ceosdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ceos/ceosdataset.cpp b/frmts/ceos/ceosdataset.cpp
index 080812c..b786c7a 100644
--- a/frmts/ceos/ceosdataset.cpp
+++ b/frmts/ceos/ceosdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ceosdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ceosdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CEOS Translator
  * Purpose:  GDALDataset driver for CEOS translator.
@@ -31,7 +31,7 @@
 #include "ceosopen.h"
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: ceosdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ceosdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_CEOS(void);
@@ -95,9 +95,9 @@ CEOSRasterBand::CEOSRasterBand( CEOSDataset *poDS, int nBand )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr CEOSRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void * pImage )
-
+CPLErr CEOSRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
+                                   void * pImage )
 {
     CEOSDataset	*poCEOS_DS = (CEOSDataset *) poDS;
 
@@ -243,6 +243,7 @@ void GDALRegister_CEOS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "CEOS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "CEOS Image" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/ceos/ceosopen.c b/frmts/ceos/ceosopen.c
index 9fc099b..0c0ae13 100644
--- a/frmts/ceos/ceosopen.c
+++ b/frmts/ceos/ceosopen.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ceosopen.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ceosopen.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CEOS Translator
  * Purpose:  Implementation of non-GDAL dependent CEOS support.
@@ -30,7 +30,7 @@
 
 #include "ceosopen.h"
 
-CPL_CVSID("$Id: ceosopen.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ceosopen.c 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                            CEOSScanInt()                             */
@@ -377,4 +377,3 @@ void CEOSClose( CEOSImage * psCEOS )
     VSIFCloseL( psCEOS->fpImage );
     CPLFree( psCEOS );
 }
-
diff --git a/frmts/ceos2/GNUmakefile b/frmts/ceos2/GNUmakefile
index c7e8111..3771a74 100644
--- a/frmts/ceos2/GNUmakefile
+++ b/frmts/ceos2/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	sar_ceosdataset.o \
 include ../../GDALmake.opt
 
 
-CPPFLAGS	:=	-I../raw $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../raw  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ceos2/ceosrecipe.c b/frmts/ceos2/ceosrecipe.c
index d98b97e..33e0610 100644
--- a/frmts/ceos2/ceosrecipe.c
+++ b/frmts/ceos2/ceosrecipe.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ceosrecipe.c 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: ceosrecipe.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  ASI CEOS Translator
  * Purpose:  CEOS field layout recipes.
@@ -29,7 +29,7 @@
 
 #include "ceos.h"
 
-CPL_CVSID("$Id: ceosrecipe.c 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: ceosrecipe.c 27745 2014-09-27 16:38:57Z goatbar $");
 
 /* Array of Datatypes and their names/values */
 
diff --git a/frmts/ceos2/ceossar.c b/frmts/ceos2/ceossar.c
index d87be7a..a11a39a 100644
--- a/frmts/ceos2/ceossar.c
+++ b/frmts/ceos2/ceossar.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ceossar.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ceossar.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  ASI CEOS Translator
  * Purpose:  Functions related to CeosSARVolume_t.
@@ -29,7 +29,7 @@
 
 #include "ceos.h"
 
-CPL_CVSID("$Id: ceossar.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ceossar.c 27745 2014-09-27 16:38:57Z goatbar $");
 
 extern Link_t *RecipeFunctions;
 
@@ -96,18 +96,23 @@ void CalcCeosSARImageFilePosition(CeosSARVolume_t *volume, int channel, int line
 
 int32 GetCeosSARImageData(CPL_UNUSED CeosSARVolume_t *volume,
                           CPL_UNUSED CeosRecord_t *processed_data_record,
-                          CPL_UNUSED int channel, CPL_UNUSED int xoff, CPL_UNUSED int xsize,
-                          CPL_UNUSED int bufsize, CPL_UNUSED uchar *buffer)
+                          CPL_UNUSED int channel,
+                          CPL_UNUSED int xoff,
+                          CPL_UNUSED int xsize,
+                          CPL_UNUSED int bufsize,
+                          CPL_UNUSED uchar *buffer)
 {
     return 0;
 }
 
-void DetermineCeosSARPixelOrder( CPL_UNUSED CeosSARVolume_t *volume, CPL_UNUSED CeosRecord_t *record )
+void DetermineCeosSARPixelOrder( CPL_UNUSED CeosSARVolume_t *volume,
+                                 CPL_UNUSED CeosRecord_t *record )
 {
-
 }
 
-void GetCeosSAREmbeddedInfo(CPL_UNUSED CeosSARVolume_t *volume, CPL_UNUSED CeosRecord_t *processed_data_record, CPL_UNUSED CeosSAREmbeddedInfo_t *info)
+void GetCeosSAREmbeddedInfo(CPL_UNUSED CeosSARVolume_t *volume,
+                            CPL_UNUSED CeosRecord_t *processed_data_record,
+                            CPL_UNUSED CeosSAREmbeddedInfo_t *info)
 {
 }
 
@@ -132,4 +137,3 @@ void DeleteCeosSARVolume(CeosSARVolume_t *volume)
 	HFree( volume );
     }
 }
-
diff --git a/frmts/ceos2/sar_ceosdataset.cpp b/frmts/ceos2/sar_ceosdataset.cpp
index 5ca07fa..24c76bd 100644
--- a/frmts/ceos2/sar_ceosdataset.cpp
+++ b/frmts/ceos2/sar_ceosdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sar_ceosdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: sar_ceosdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  ASI CEOS Translator
  * Purpose:  GDALDataset driver for CEOS translator.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: sar_ceosdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: sar_ceosdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_SAR_CEOS(void);
@@ -237,9 +237,9 @@ SAR_CEOSRasterBand::SAR_CEOSRasterBand( SAR_CEOSDataset *poGDS, int nBand,
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr SAR_CEOSRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr SAR_CEOSRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
                                        void * pImage )
-
 {
     struct CeosSARImageDesc *ImageDesc;
     int	   offset;
@@ -371,9 +371,9 @@ Im(SVV) = byte(10) ysca/127
 
 */
 
-CPLErr CCPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr CCPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
-
 {
     struct CeosSARImageDesc *ImageDesc;
     int	   offset;
@@ -517,9 +517,9 @@ PALSARRasterBand::PALSARRasterBand( SAR_CEOSDataset *poGDS, int nBand )
 /*      Based on ERSDAC-VX-CEOS-004                                     */
 /************************************************************************/
 
-CPLErr PALSARRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr PALSARRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                     int nBlockYOff,
                                      void * pImage )
-
 {
     struct CeosSARImageDesc *ImageDesc;
     int	   offset;
@@ -1530,9 +1530,9 @@ int SAR_CEOSDataset::ScanForMapProjection()
         pasGCPList[i].pszId = CPLStrdup( szId );
     
         GetCeosField( record, 1073+32*i, "A16", szField );
-        pasGCPList[i].dfGCPY = atof(szField);
+        pasGCPList[i].dfGCPY = CPLAtof(szField);
         GetCeosField( record, 1089+32*i, "A16", szField );
-        pasGCPList[i].dfGCPX = atof(szField);
+        pasGCPList[i].dfGCPX = CPLAtof(szField);
         pasGCPList[i].dfGCPZ = 0.0;
     }
     
@@ -2161,8 +2161,7 @@ ProcessData( VSILFILE *fp, int fileid, CeosSARVolume_t *sar, int max_records,
             max_records--;
         if(max_bytes > 0)
         {
-            // TODO: Make sure that this cast is safe.
-            if( (vsi_l_offset)record->Length <= max_bytes )
+          if( (vsi_l_offset)record->Length <= max_bytes )
                 max_bytes -= record->Length;
             else {
                 CPLDebug( "SAR_CEOS", "Partial record found.  %d > " CPL_FRMT_GUIB,
@@ -2191,6 +2190,7 @@ void GDALRegister_SAR_CEOS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "SAR_CEOS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "CEOS SAR Image" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -2202,4 +2202,3 @@ void GDALRegister_SAR_CEOS()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/coasp/GNUmakefile b/frmts/coasp/GNUmakefile
index 5d0596a..44655c2 100644
--- a/frmts/coasp/GNUmakefile
+++ b/frmts/coasp/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	coasp_dataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) 
+CPPFLAGS	:=	 $(CPPFLAGS) 
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/coasp/coasp_dataset.cpp b/frmts/coasp/coasp_dataset.cpp
index d8bd220..fa2db50 100644
--- a/frmts/coasp/coasp_dataset.cpp
+++ b/frmts/coasp/coasp_dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: coasp_dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: coasp_dataset.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  DRDC Configurable Airborne SAR Processor (COASP) data reader
  * Purpose:  Support in GDAL for the DRDC COASP format data, both Metadata
@@ -39,7 +39,7 @@
 #include "cpl_vsi.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: coasp_dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: coasp_dataset.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 CPL_C_START
 void    GDALRegister_COASP(void);
@@ -192,7 +192,7 @@ COASPMetadataItem *COASPMetadataReader::GetNextItem()
 	}
 	else {
 		int nCount = CSLCount(papszMDTokens);
-		pszItemValue = strdup(papszMDTokens[1]); 
+		pszItemValue = CPLStrdup(papszMDTokens[1]); 
 		for (int i = 2; i < nCount; i++) {
 			int nSize = strlen(papszMDTokens[i]);
 			pszItemValue = (char *)CPLRealloc(pszItemValue, 
@@ -204,9 +204,9 @@ COASPMetadataItem *COASPMetadataReader::GetNextItem()
 		poMetadata = new COASPMetadataItem(pszItemName,
 			pszItemValue);
 
-		free(pszItemValue);
+		CPLFree(pszItemValue);
 	}
-	free(pszItemName);
+	CSLDestroy(papszMDTokens);
 	nCurrentItem++;
 	return poMetadata;
 }
@@ -249,7 +249,7 @@ class COASPRasterBand;
 class COASPDataset : public GDALDataset
 {
 	friend class COASPRasterBand;
-	FILE *fpHdr; /* File pointer for the header file */
+	VSILFILE *fpHdr; /* File pointer for the header file */
 	VSILFILE *fpBinHH; /* File pointer for the binary matrix */
 	VSILFILE *fpBinHV;
 	VSILFILE *fpBinVH;
@@ -292,7 +292,8 @@ COASPRasterBand::COASPRasterBand( COASPDataset *poDS, GDALDataType eDataType,
 	this->nBlockYSize = 1;
 }
 
-CPLErr COASPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, 
+CPLErr COASPRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                    int nBlockYOff,
                                     void *pImage )
 {
 	if (this->fp == NULL) {
@@ -349,7 +350,7 @@ const GDAL_GCP *COASPDataset::GetGCPs()
 
 int COASPDataset::Identify( GDALOpenInfo *poOpenInfo ) 
 {
-	if(poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 256)
+	if(poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 256)
 		return 0;
 
 	/* With a COASP .hdr file, the first line or so is:
@@ -388,8 +389,8 @@ GDALDataset *COASPDataset::Open( GDALOpenInfo *poOpenInfo )
 		return NULL;
 
 	/* Steal the file pointer for the header */
-	poDS->fpHdr = poOpenInfo->fp;
-	poOpenInfo->fp = NULL;
+	poDS->fpHdr = poOpenInfo->fpL;
+	poOpenInfo->fpL = NULL;
 	
 	/* Set the binary matrix file pointers to NULL, for now */
 	poDS->fpBinHH = NULL;
@@ -539,6 +540,7 @@ void GDALRegister_COASP(void)
 	if ( GDALGetDriverByName( "COASP" ) == NULL ) {
 		poDriver = new GDALDriver();
 		poDriver->SetDescription( "COASP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
 		poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
 			"DRDC COASP SAR Processor Raster" );
 		poDriver->SetMetadataItem( GDAL_DMD_EXTENSION,
diff --git a/frmts/cosar/GNUmakefile b/frmts/cosar/GNUmakefile
index 076287f..0f4e20f 100644
--- a/frmts/cosar/GNUmakefile
+++ b/frmts/cosar/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	cosar_dataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/cosar/cosar_dataset.cpp b/frmts/cosar/cosar_dataset.cpp
index cd53ac2..1cfc069 100644
--- a/frmts/cosar/cosar_dataset.cpp
+++ b/frmts/cosar/cosar_dataset.cpp
@@ -50,7 +50,7 @@ class COSARDataset : public GDALDataset
 {
 	long nSize;
 public:
-	FILE *fp;
+	VSILFILE *fp;
 /*	~COSARDataset(); */
 	
 	static GDALDataset *Open( GDALOpenInfo * );
@@ -78,8 +78,10 @@ COSARRasterBand::COSARRasterBand(COSARDataset *pDS, unsigned long nRTNB) {
 	eDataType = GDT_CInt16;
 }
 
-CPLErr COSARRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, 
+CPLErr COSARRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void *pImage) {
+
     unsigned long nRSFV = 0;
     unsigned long nRSLV = 0;
     COSARDataset *pCDS = (COSARDataset *) poDS;
@@ -91,12 +93,12 @@ CPLErr COSARRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
      *    of file
      */
 
-    VSIFSeek(pCDS->fp,(this->nRTNB * (nBlockYOff + 4)), SEEK_SET);
+    VSIFSeekL(pCDS->fp,(this->nRTNB * (nBlockYOff + 4)), SEEK_SET);
 
 
     /* Read RSFV and RSLV (TX-GS-DD-3307) */
-    VSIFRead(&nRSFV,1,4,pCDS->fp);
-    VSIFRead(&nRSLV,1,4,pCDS->fp);
+    VSIFReadL(&nRSFV,1,4,pCDS->fp);
+    VSIFReadL(&nRSLV,1,4,pCDS->fp);
 
 #ifdef CPL_LSB
     nRSFV = CPL_SWAP32(nRSFV);
@@ -124,11 +126,11 @@ CPLErr COSARRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
     /* properly account for validity mask */ 
     if (nRSFV > 1)
     {
-        VSIFSeek(pCDS->fp,(this->nRTNB*(nBlockYOff+4)+(nRSFV+1)*4), SEEK_SET);
+        VSIFSeekL(pCDS->fp,(this->nRTNB*(nBlockYOff+4)+(nRSFV+1)*4), SEEK_SET);
     }
 
     /* Read the valid samples: */
-    VSIFRead(((char *)pImage)+((nRSFV - 1)*4),1,((nRSLV-1)*4)-((nRSFV-1)*4),pCDS->fp);
+    VSIFReadL(((char *)pImage)+((nRSFV - 1)*4),1,((nRSLV-1)*4)-((nRSFV-1)*4),pCDS->fp);
 
 #ifdef CPL_LSB
     // GDALSwapWords( pImage, 4, nBlockXSize * nBlockYSize, 4 );
@@ -169,27 +171,27 @@ GDALDataset *COSARDataset::Open( GDALOpenInfo * pOpenInfo ) {
     pDS = new COSARDataset();
 	
     /* steal fp */
-    pDS->fp = pOpenInfo->fp;
-    pOpenInfo->fp = NULL;
+    pDS->fp = pOpenInfo->fpL;
+    pOpenInfo->fpL = NULL;
 
     /* Calculate the file size */
-    VSIFSeek(pDS->fp,0,SEEK_END);
-    pDS->nSize = VSIFTell(pDS->fp);
+    VSIFSeekL(pDS->fp,0,SEEK_END);
+    pDS->nSize = VSIFTellL(pDS->fp);
 
-    VSIFSeek(pDS->fp, RS_OFFSET, SEEK_SET);
-    VSIFRead(&pDS->nRasterXSize, 1, 4, pDS->fp);  
+    VSIFSeekL(pDS->fp, RS_OFFSET, SEEK_SET);
+    VSIFReadL(&pDS->nRasterXSize, 1, 4, pDS->fp);  
 #ifdef CPL_LSB
     pDS->nRasterXSize = CPL_SWAP32(pDS->nRasterXSize);
 #endif
 	
 	
-    VSIFRead(&pDS->nRasterYSize, 1, 4, pDS->fp);
+    VSIFReadL(&pDS->nRasterYSize, 1, 4, pDS->fp);
 #ifdef CPL_LSB
     pDS->nRasterYSize = CPL_SWAP32(pDS->nRasterYSize);
 #endif
 
-    VSIFSeek(pDS->fp, RTNB_OFFSET, SEEK_SET);
-    VSIFRead(&nRTNB, 1, 4, pDS->fp);
+    VSIFSeekL(pDS->fp, RTNB_OFFSET, SEEK_SET);
+    VSIFReadL(&nRTNB, 1, 4, pDS->fp);
 #ifdef CPL_LSB
     nRTNB = CPL_SWAP32(nRTNB);
 #endif
@@ -202,16 +204,17 @@ GDALDataset *COSARDataset::Open( GDALOpenInfo * pOpenInfo ) {
 
 /* register the driver with GDAL */
 void GDALRegister_COSAR() {
-	GDALDriver *pDriver;
+	GDALDriver *poDriver;
 	if (GDALGetDriverByName("cosar") == NULL) {
-		pDriver = new GDALDriver();
-		pDriver->SetDescription("COSAR");
-		pDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+		poDriver = new GDALDriver();
+		poDriver->SetDescription("COSAR");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+		poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
 			"COSAR Annotated Binary Matrix (TerraSAR-X)");
-		pDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+		poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
 			"frmt_cosar.html");
-		pDriver->pfnOpen = COSARDataset::Open;
-		GetGDALDriverManager()->RegisterDriver(pDriver);
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+		poDriver->pfnOpen = COSARDataset::Open;
+		GetGDALDriverManager()->RegisterDriver(poDriver);
 	}
 }
-
diff --git a/frmts/ctg/GNUmakefile b/frmts/ctg/GNUmakefile
index f30a1e9..8f9185c 100644
--- a/frmts/ctg/GNUmakefile
+++ b/frmts/ctg/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	ctgdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ctg/ctgdataset.cpp b/frmts/ctg/ctgdataset.cpp
index bf9260a..b13d26f 100644
--- a/frmts/ctg/ctgdataset.cpp
+++ b/frmts/ctg/ctgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ctgdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ctgdataset.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  CTG driver
  * Purpose:  GDALDataset driver for CTG dataset.
@@ -30,7 +30,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: ctgdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ctgdataset.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 CPL_C_START
 void    GDALRegister_CTG(void);
@@ -194,7 +194,8 @@ CTGRasterBand::~CTGRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr CTGRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, CPL_UNUSED int nBlockYOff,
+CPLErr CTGRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  CPL_UNUSED int nBlockYOff,
                                   void * pImage )
 {
     CTGDataset* poGDS = (CTGDataset* ) poDS;
@@ -360,7 +361,7 @@ int CTGDataset::Identify( GDALOpenInfo * poOpenInfo )
 
     GDALOpenInfo* poOpenInfoToDelete = NULL;
     /*  GZipped grid_cell.gz files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     const char* pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
     if ((EQUAL(pszFilename, "grid_cell.gz") ||
          EQUAL(pszFilename, "grid_cell1.gz") ||
@@ -371,7 +372,7 @@ int CTGDataset::Identify( GDALOpenInfo * poOpenInfo )
         osFilename += poOpenInfo->pszFilename;
         poOpenInfo = poOpenInfoToDelete =
                 new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
-                                 poOpenInfo->papszSiblingFiles);
+                                 poOpenInfo->GetSiblingFiles());
     }
 
     if (poOpenInfo->nHeaderBytes < HEADER_LINE_COUNT * 80)
@@ -431,7 +432,7 @@ GDALDataset *CTGDataset::Open( GDALOpenInfo * poOpenInfo )
     CPLString osFilename(poOpenInfo->pszFilename);
 
     /*  GZipped grid_cell.gz files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     const char* pszFilename = CPLGetFilename(poOpenInfo->pszFilename);
     if ((EQUAL(pszFilename, "grid_cell.gz") ||
          EQUAL(pszFilename, "grid_cell1.gz") ||
@@ -591,6 +592,7 @@ void GDALRegister_CTG()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "CTG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "USGS LULC Composite Theme Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -604,4 +606,3 @@ void GDALRegister_CTG()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/dds/GNUmakefile b/frmts/dds/GNUmakefile
index c472995..c432a21 100644
--- a/frmts/dds/GNUmakefile
+++ b/frmts/dds/GNUmakefile
@@ -9,7 +9,7 @@ OBJ	=	ddsdataset.o
 
 CRUNCHINC = -I$(CRUNCHDIR)/include/crunch
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CRUNCHINC) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CRUNCHINC) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/dds/ddsdataset.cpp b/frmts/dds/ddsdataset.cpp
index 635240e..5ea452b 100644
--- a/frmts/dds/ddsdataset.cpp
+++ b/frmts/dds/ddsdataset.cpp
@@ -139,6 +139,7 @@ DDSDataset::CreateCopy(const char * pszFilename, GDALDataset *poSrcDS,
     crn_dxt_quality dxt_quality = cCRNDXTQualityNormal;
     bool srgb_colorspace = true;    
     bool dxt1a_transparency = true;
+    //bool generate_mipmaps = true;
     
     /* Check the texture format */
     const char *pszFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
@@ -153,10 +154,12 @@ DDSDataset::CreateCopy(const char * pszFilename, GDALDataset *poSrcDS,
             fmt = cCRNFmtDXT3;
         else if (EQUAL(pszFormat, "dxt5"))
             fmt = cCRNFmtDXT5;
+	else if (EQUAL(pszFormat, "etc1"))
+            fmt = cCRNFmtETC1;
         else
         {
             CPLError( CE_Failure, CPLE_AppDefined,
-                      "Illegal FORMAT value '%s', should be DXT1, DXT1A, DXT3 or DXT5.",
+                      "Illegal FORMAT value '%s', should be DXT1, DXT1A, DXT3, DXT5 or ETC1",
                       pszFormat );
             return NULL;
         }
@@ -211,9 +214,10 @@ DDSDataset::CreateCopy(const char * pszFilename, GDALDataset *poSrcDS,
     crnlib::DDSURFACEDESC2 ddsDesc;
     memset(&ddsDesc, 0, sizeof(ddsDesc));
     ddsDesc.dwSize = sizeof(ddsDesc);
-    ddsDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;
+    ddsDesc.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_MIPMAPCOUNT | DDSD_PIXELFORMAT | DDSD_DEPTH ;
     ddsDesc.dwWidth = nXSize;
     ddsDesc.dwHeight = nYSize;
+    ddsDesc.dwMipMapCount = 1;
     
     ddsDesc.ddpfPixelFormat.dwSize = sizeof(crnlib::DDPIXELFORMAT);
     ddsDesc.ddpfPixelFormat.dwFlags = DDPF_FOURCC;
@@ -254,7 +258,7 @@ DDSDataset::CreateCopy(const char * pszFilename, GDALDataset *poSrcDS,
                                  pabyScanlines, nXSize, size_y, GDT_Byte,
                                  nBands, NULL,
                                  nBands, 
-                                 nBands * nXSize, 1);
+                                 nBands * nXSize, 1, NULL);
 
         if (eErr != CE_None)
             break;
@@ -338,6 +342,7 @@ void GDALRegister_DDS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription("DDS");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 
                                   "DirectDraw Surface");
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_various.html#DDS" );        
@@ -350,7 +355,8 @@ void GDALRegister_DDS()
                                   "     <Value>DXT1</Value>\n"
                                   "     <Value>DXT1A</Value>\n"
                                   "     <Value>DXT3</Value>\n"
-                                  "     <Value>DXT5</Value>\n"                                                                    
+                                  "     <Value>DXT5</Value>\n" 
+                                  "     <Value>ETC1</Value>\n"                                                                     
                                   "   </Option>\n"
                                   "   <Option name='QUALITY' type='string-select' description='Compression Quality' default='NORMAL'>\n"
                                   "     <Value>SUPERFAST</Value>\n"
diff --git a/frmts/dimap/GNUmakefile b/frmts/dimap/GNUmakefile
index 7e11abf..80bfbfe 100644
--- a/frmts/dimap/GNUmakefile
+++ b/frmts/dimap/GNUmakefile
@@ -2,7 +2,7 @@ include ../../GDALmake.opt
 
 OBJ	=	dimapdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/dimap/dimapdataset.cpp b/frmts/dimap/dimapdataset.cpp
index 425c238..1c5f936 100644
--- a/frmts/dimap/dimapdataset.cpp
+++ b/frmts/dimap/dimapdataset.cpp
@@ -35,7 +35,7 @@
 #include "ogr_spatialref.h"
 #include "gdal_proxy.h"
 
-CPL_CVSID("$Id: dimapdataset.cpp 27222 2014-04-19 18:09:01Z rouault $");
+CPL_CVSID("$Id: dimapdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void    GDALRegister_DIMAP(void);
@@ -398,7 +398,7 @@ GDALDataset *DIMAPDataset::Open( GDALOpenInfo * poOpenInfo )
 
     /* We check the for the tag Metadata_Identification.METADATA_FORMAT.
     *  The metadata will be set to 2.0 for DIMAP2 */
-    nMetadataFormatVersion = atof( CPLGetXMLValue(CPLGetXMLNode(psDoc, "Metadata_Identification.METADATA_FORMAT"), 
+    nMetadataFormatVersion = CPLAtof( CPLGetXMLValue(CPLGetXMLNode(psDoc, "Metadata_Identification.METADATA_FORMAT"), 
                         "version", "1") );
     if( nMetadataFormatVersion >= 2.0 )
     {
@@ -609,12 +609,12 @@ int DIMAPDataset::ReadImageInformation()
     if( psGeoLoc != NULL )
     {
         bHaveGeoTransform = TRUE;
-        adfGeoTransform[0] = atof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
-        adfGeoTransform[1] = atof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
+        adfGeoTransform[0] = CPLAtof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
+        adfGeoTransform[1] = CPLAtof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
         adfGeoTransform[2] = 0.0;
-        adfGeoTransform[3] = atof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
+        adfGeoTransform[3] = CPLAtof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
         adfGeoTransform[4] = 0.0;
-        adfGeoTransform[5] = -atof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
+        adfGeoTransform[5] = -CPLAtof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
     }
     else
     {
@@ -661,15 +661,15 @@ int DIMAPDataset::ReadImageInformation()
             psGCP->pszId = CPLStrdup( szID );
             psGCP->pszInfo = CPLStrdup("");
             psGCP->dfGCPPixel = 
-                atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_X","0"))-0.5;
+                CPLAtof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_X","0"))-0.5;
             psGCP->dfGCPLine = 
-                atof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_Y","0"))-0.5;
+                CPLAtof(CPLGetXMLValue(psNode,"TIE_POINT_DATA_Y","0"))-0.5;
             psGCP->dfGCPX = 
-                atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_X",""));
+                CPLAtof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_X",""));
             psGCP->dfGCPY = 
-                atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Y",""));
+                CPLAtof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Y",""));
             psGCP->dfGCPZ = 
-                atof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Z",""));
+                CPLAtof(CPLGetXMLValue(psNode,"TIE_POINT_CRS_Z",""));
         }
     }
 
@@ -869,12 +869,12 @@ int DIMAPDataset::ReadImageInformation2()
     if( psGeoLoc != NULL )
     {
         bHaveGeoTransform = TRUE;
-        adfGeoTransform[0] = atof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
-        adfGeoTransform[1] = atof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
+        adfGeoTransform[0] = CPLAtof(CPLGetXMLValue(psGeoLoc,"ULXMAP","0"));
+        adfGeoTransform[1] = CPLAtof(CPLGetXMLValue(psGeoLoc,"XDIM","0"));
         adfGeoTransform[2] = 0.0;
-        adfGeoTransform[3] = atof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
+        adfGeoTransform[3] = CPLAtof(CPLGetXMLValue(psGeoLoc,"ULYMAP","0"));
         adfGeoTransform[4] = 0.0;
-        adfGeoTransform[5] = -atof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
+        adfGeoTransform[5] = -CPLAtof(CPLGetXMLValue(psGeoLoc,"YDIM","0"));
     }
     else
     {
@@ -883,7 +883,6 @@ int DIMAPDataset::ReadImageInformation2()
             bHaveGeoTransform = TRUE; 
     }
 
-
 /* -------------------------------------------------------------------- */
 /*      Collect the CRS.  For now we look only for EPSG codes.          */
 /* -------------------------------------------------------------------- */
@@ -1157,6 +1156,7 @@ void GDALRegister_DIMAP()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DIMAP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "SPOT DIMAP" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/dods/GNUmakefile b/frmts/dods/GNUmakefile
index fd8c13a..af987c1 100644
--- a/frmts/dods/GNUmakefile
+++ b/frmts/dods/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	dodsdataset2.o 
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(DODS_INC)
+CPPFLAGS	:=	 $(CPPFLAGS) $(DODS_INC)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/dods/dodsdataset2.cpp b/frmts/dods/dodsdataset2.cpp
index af0ff6c..4100081 100644
--- a/frmts/dods/dodsdataset2.cpp
+++ b/frmts/dods/dodsdataset2.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dodsdataset2.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: dodsdataset2.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OPeNDAP Raster Driver
  * Purpose:  Implements DODSDataset and DODSRasterBand classes.
@@ -71,7 +71,7 @@
 
 using namespace libdap;
 
-CPL_CVSID("$Id: dodsdataset2.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: dodsdataset2.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void GDALRegister_DODS(void);
@@ -753,14 +753,14 @@ void DODSDataset::HarvestDAS()
 
     if( oNorth != "" && oSouth != "" && oEast != "" && oWest != "" )
     {
-        adfGeoTransform[0] = atof(oWest.c_str());
+        adfGeoTransform[0] = CPLAtof(oWest.c_str());
         adfGeoTransform[1] = 
-            (atof(oEast.c_str()) - atof(oWest.c_str())) / nRasterXSize;
+            (CPLAtof(oEast.c_str()) - CPLAtof(oWest.c_str())) / nRasterXSize;
         adfGeoTransform[2] = 0.0;
-        adfGeoTransform[3] = atof(oNorth.c_str());
+        adfGeoTransform[3] = CPLAtof(oNorth.c_str());
         adfGeoTransform[4] = 0.0;
         adfGeoTransform[5] = 
-            (atof(oSouth.c_str()) - atof(oNorth.c_str())) / nRasterYSize;
+            (CPLAtof(oSouth.c_str()) - CPLAtof(oNorth.c_str())) / nRasterYSize;
 
         bGotGeoTransform = TRUE;
     }
@@ -778,12 +778,12 @@ void DODSDataset::HarvestDAS()
         char **papszItems = CSLTokenizeString( oValue.c_str() );
         if( CSLCount(papszItems) == 6 )
         {
-            adfGeoTransform[0] = atof(papszItems[0]);
-            adfGeoTransform[1] = atof(papszItems[1]);
-            adfGeoTransform[2] = atof(papszItems[2]);
-            adfGeoTransform[3] = atof(papszItems[3]);
-            adfGeoTransform[4] = atof(papszItems[4]);
-            adfGeoTransform[5] = atof(papszItems[5]);
+            adfGeoTransform[0] = CPLAtof(papszItems[0]);
+            adfGeoTransform[1] = CPLAtof(papszItems[1]);
+            adfGeoTransform[2] = CPLAtof(papszItems[2]);
+            adfGeoTransform[3] = CPLAtof(papszItems[3]);
+            adfGeoTransform[4] = CPLAtof(papszItems[4]);
+            adfGeoTransform[5] = CPLAtof(papszItems[5]);
             bGotGeoTransform = TRUE;
         }
         else
@@ -1364,7 +1364,7 @@ void DODSRasterBand::HarvestDAS()
     oValue = poBandInfo->get_attr( "missing_value" );
     bNoDataSet=FALSE;
     if( oValue != "" ) {
-        SetNoDataValue( atof(oValue.c_str()) );
+        SetNoDataValue( CPLAtof(oValue.c_str()) );
     } else {
 
 /* -------------------------------------------------------------------- */
@@ -1372,7 +1372,7 @@ void DODSRasterBand::HarvestDAS()
 /* -------------------------------------------------------------------- */
 	oValue = poBandInfo->get_attr( "_FillValue" );
 	if( oValue != "" ) {
-	    SetNoDataValue( atof(oValue.c_str()) );
+	    SetNoDataValue( CPLAtof(oValue.c_str()) );
 	}
     }
 
@@ -1731,6 +1731,7 @@ GDALRegister_DODS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DODS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "DAP 3.x servers" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_various.html#DODS" );
diff --git a/frmts/dted/GNUmakefile b/frmts/dted/GNUmakefile
index ed5fe69..dc7242a 100644
--- a/frmts/dted/GNUmakefile
+++ b/frmts/dted/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	dted_api.o dteddataset.o dted_create.o dted_ptstream.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/dted/dted_api.c b/frmts/dted/dted_api.c
index 20a7935..5573946 100644
--- a/frmts/dted/dted_api.c
+++ b/frmts/dted/dted_api.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dted_api.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: dted_api.c 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  DTED Translator
  * Purpose:  Implementation of DTED/CDED access functions.
@@ -31,7 +31,7 @@
 #include "dted_api.h"
 
 #ifndef AVOID_CPL
-CPL_CVSID("$Id: dted_api.c 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: dted_api.c 28831 2015-04-01 16:46:05Z rouault $");
 #endif
 
 static int bWarnedTwoComplement = FALSE;
@@ -88,17 +88,8 @@ DTEDInfo * DTEDOpen( const char * pszFilename,
                      int bTestOpen )
 
 {
-    VSILFILE   *fp;
-    char        achRecord[DTED_UHL_SIZE];
-    DTEDInfo    *psDInfo = NULL;
-    double      dfLLOriginX, dfLLOriginY;
-    int deg = 0;
-    int min = 0;
-    int sec = 0;
-    int bSwapLatLong = FALSE;
-    char szResult[81];
-    int bIsWeirdDTED;
-    char chHemisphere;
+    VSILFILE* fp;
+
 /* -------------------------------------------------------------------- */
 /*      Open the physical file.                                         */
 /* -------------------------------------------------------------------- */
@@ -125,6 +116,30 @@ DTEDInfo * DTEDOpen( const char * pszFilename,
         return NULL;
     }
 
+    return DTEDOpenEx( fp, pszFilename, pszAccess, bTestOpen );
+}
+
+/************************************************************************/
+/*                             DTEDOpenEx()                             */
+/************************************************************************/
+
+DTEDInfo * DTEDOpenEx( VSILFILE   *fp,
+                       const char * pszFilename,
+                       const char * pszAccess,
+                       int bTestOpen )
+
+{
+    char        achRecord[DTED_UHL_SIZE];
+    DTEDInfo    *psDInfo = NULL;
+    double      dfLLOriginX, dfLLOriginY;
+    int deg = 0;
+    int min = 0;
+    int sec = 0;
+    int bSwapLatLong = FALSE;
+    char szResult[81];
+    int bIsWeirdDTED;
+    char chHemisphere;
+
 /* -------------------------------------------------------------------- */
 /*      Read, trying to find the UHL record.  Skip VOL or HDR           */
 /*      records if they are encountered.                                */
@@ -983,9 +998,9 @@ char *DTEDGetMetadata( DTEDInfo *psDInfo, DTEDMetaDataCode eCode )
 
     DTEDGetMetadataLocation( psDInfo, eCode, &pszFieldSrc, &nFieldLen );
     if( pszFieldSrc == NULL )
-        return strdup( "" );
+        return CPLStrdup( "" );
 
-    pszResult = (char *) malloc(nFieldLen+1);
+    pszResult = (char *) CPLMalloc(nFieldLen+1);
     strncpy( pszResult, pszFieldSrc, nFieldLen );
     pszResult[nFieldLen] = '\0';
 
diff --git a/frmts/dted/dted_api.h b/frmts/dted/dted_api.h
index ea76a65..cb78bc3 100644
--- a/frmts/dted/dted_api.h
+++ b/frmts/dted/dted_api.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dted_api.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: dted_api.h 28575 2015-02-28 09:41:10Z rouault $
  *
  * Project:  DTED Translator
  * Purpose:  Public (C callable) interface for DTED/CDED reading.
@@ -133,6 +133,8 @@ typedef struct {
 /* -------------------------------------------------------------------- */
 DTEDInfo *DTEDOpen( const char * pszFilename, const char * pszAccess,
                     int bTestOpen );
+DTEDInfo *DTEDOpenEx( VSILFILE* fp, const char * pszFilename,
+                      const char * pszAccess, int bTestOpen );
 
 /**     Read one single sample. The coordinates are given from the
         top-left corner of the file (contrary to the internal
@@ -146,8 +148,8 @@ int DTEDReadPoint( DTEDInfo * psDInfo, int nXOff, int nYOff, GInt16* panVal);
 int DTEDReadProfile( DTEDInfo * psDInfo, int nColumnOffset,
                      GInt16 * panData );
 
-/* Extented version of DTEDReadProfile that enable the user to specify */
-/* whether he wants the checksums to be verified */
+/* Extended version of DTEDReadProfile that enables the user to specify */
+/* whether the checksums should be verified */
 int DTEDReadProfileEx( DTEDInfo * psDInfo, int nColumnOffset,
                        GInt16 * panData, int bVerifyChecksum );
 
diff --git a/frmts/dted/dted_create.c b/frmts/dted/dted_create.c
index 8093af8..ab76fbd 100644
--- a/frmts/dted/dted_create.c
+++ b/frmts/dted/dted_create.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dted_create.c 20996 2010-10-28 18:38:15Z rouault $
+ * $Id: dted_create.c 28433 2015-02-06 21:18:50Z rouault $
  *
  * Project:  DTED Translator
  * Purpose:  Implementation of DTEDCreate() portion of DTED API.
@@ -30,7 +30,7 @@
 #include "dted_api.h"
 #include <assert.h>
 
-CPL_CVSID("$Id: dted_create.c 20996 2010-10-28 18:38:15Z rouault $");
+CPL_CVSID("$Id: dted_create.c 28433 2015-02-06 21:18:50Z rouault $");
 
 #define DTED_ABS_VERT_ACC "NA  "
 #define DTED_SECURITY     "U"
@@ -87,6 +87,8 @@ static void DTEDFormatDMS( unsigned char *achField, double dfAngle,
 /*                             DTEDFormat()                             */
 /************************************************************************/
 
+static void DTEDFormat( unsigned char *pszTarget, const char *pszFormat, ... ) CPL_PRINT_FUNC_FORMAT (2, 3);
+
 static void DTEDFormat( unsigned char *pszTarget, const char *pszFormat, ... )
 
 {
diff --git a/frmts/dted/dted_ptstream.c b/frmts/dted/dted_ptstream.c
index 14dbcd3..85ced28 100644
--- a/frmts/dted/dted_ptstream.c
+++ b/frmts/dted/dted_ptstream.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dted_ptstream.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: dted_ptstream.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  DTED Translator
  * Purpose:  DTED Point Stream Writer.
@@ -29,7 +29,7 @@
 
 #include "dted_api.h"
 
-CPL_CVSID("$Id: dted_ptstream.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: dted_ptstream.c 27745 2014-09-27 16:38:57Z goatbar $");
 
 typedef struct {
     char     *pszFilename;
@@ -187,10 +187,11 @@ static int DTEDPtStreamNewTile( DTEDPtStream *psStream,
 /*                           DTEDWritePtLL()                            */
 /************************************************************************/
 
-static int DTEDWritePtLL( CPL_UNUSED DTEDPtStream *psStream, 
-                          DTEDCachedFile *psCF, 
-                          double dfLong, double dfLat, double dfElev )
-
+static int DTEDWritePtLL( CPL_UNUSED DTEDPtStream *psStream,
+                          DTEDCachedFile *psCF,
+                          double dfLong,
+                          double dfLat,
+                          double dfElev )
 {
 /* -------------------------------------------------------------------- */
 /*      Determine what profile this belongs in, and initialize the      */
diff --git a/frmts/dted/dteddataset.cpp b/frmts/dted/dteddataset.cpp
index c1f3b96..f80173c 100644
--- a/frmts/dted/dteddataset.cpp
+++ b/frmts/dted/dteddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dteddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: dteddataset.cpp 29017 2015-04-25 19:32:11Z rouault $
  *
  * Project:  DTED Translator
  * Purpose:  GDALDataset driver for DTED translator.
@@ -33,7 +33,7 @@
 #include "ogr_spatialref.h"
 #include <algorithm>
 
-CPL_CVSID("$Id: dteddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: dteddataset.cpp 29017 2015-04-25 19:32:11Z rouault $");
 
 CPL_C_START
 void    GDALRegister_DTED(void);
@@ -125,9 +125,9 @@ DTEDRasterBand::DTEDRasterBand( DTEDDataset *poDS, int nBand )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr DTEDRasterBand::IReadBlock( int nBlockXOff, CPL_UNUSED int nBlockYOff,
-                                  void * pImage )
-
+CPLErr DTEDRasterBand::IReadBlock( int nBlockXOff,
+                                   CPL_UNUSED int nBlockYOff,
+                                   void * pImage )
 {
     DTEDDataset *poDTED_DS = (DTEDDataset *) poDS;
     int         nYSize = poDTED_DS->psDTED->nYSize;
@@ -187,9 +187,9 @@ CPLErr DTEDRasterBand::IReadBlock( int nBlockXOff, CPL_UNUSED int nBlockYOff,
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr DTEDRasterBand::IWriteBlock( int nBlockXOff, CPL_UNUSED int nBlockYOff,
-                                  void * pImage )
-
+CPLErr DTEDRasterBand::IWriteBlock( int nBlockXOff,
+                                    CPL_UNUSED int nBlockYOff,
+                                    void * pImage )
 {
     DTEDDataset *poDTED_DS = (DTEDDataset *) poDS;
     GInt16      *panData;
@@ -326,13 +326,16 @@ GDALDataset *DTEDDataset::Open( GDALOpenInfo * poOpenInfo )
     int         i;
     DTEDInfo    *psDTED;
 
-    if (!Identify(poOpenInfo))
+    if (!Identify(poOpenInfo) || poOpenInfo->fpL == NULL )
         return NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Try opening the dataset.                                        */
 /* -------------------------------------------------------------------- */
-    psDTED = DTEDOpen( poOpenInfo->pszFilename, (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb", TRUE );
+    VSILFILE* fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+    psDTED = DTEDOpenEx( fp, poOpenInfo->pszFilename, 
+                         (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb", TRUE );
 
     if( psDTED == NULL )
         return( NULL );
@@ -374,95 +377,95 @@ GDALDataset *DTEDDataset::Open( GDALOpenInfo * poOpenInfo )
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTACCURACY_UHL );
     poDS->SetMetadataItem( "DTED_VerticalAccuracy_UHL", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTACCURACY_ACC );
     poDS->SetMetadataItem( "DTED_VerticalAccuracy_ACC", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_SECURITYCODE_UHL );
     poDS->SetMetadataItem( "DTED_SecurityCode_UHL", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_SECURITYCODE_DSI );
     poDS->SetMetadataItem( "DTED_SecurityCode_DSI", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_UNIQUEREF_UHL );
     poDS->SetMetadataItem( "DTED_UniqueRef_UHL", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_UNIQUEREF_DSI );
     poDS->SetMetadataItem( "DTED_UniqueRef_DSI", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_DATA_EDITION );
     poDS->SetMetadataItem( "DTED_DataEdition", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_MATCHMERGE_VERSION );
     poDS->SetMetadataItem( "DTED_MatchMergeVersion", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_MAINT_DATE );
     poDS->SetMetadataItem( "DTED_MaintenanceDate", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_MATCHMERGE_DATE );
     poDS->SetMetadataItem( "DTED_MatchMergeDate", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_MAINT_DESCRIPTION );
     poDS->SetMetadataItem( "DTED_MaintenanceDescription", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_PRODUCER );
     poDS->SetMetadataItem( "DTED_Producer", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_VERTDATUM );
     poDS->SetMetadataItem( "DTED_VerticalDatum", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_HORIZDATUM );
     poDS->SetMetadataItem( "DTED_HorizontalDatum", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_DIGITIZING_SYS );
     poDS->SetMetadataItem( "DTED_DigitizingSystem", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_COMPILATION_DATE );
     poDS->SetMetadataItem( "DTED_CompilationDate", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_HORIZACCURACY );
     poDS->SetMetadataItem( "DTED_HorizontalAccuracy", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_REL_HORIZACCURACY );
     poDS->SetMetadataItem( "DTED_RelHorizontalAccuracy", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_REL_VERTACCURACY );
     poDS->SetMetadataItem( "DTED_RelVerticalAccuracy", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
     
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_ORIGINLAT );
     poDS->SetMetadataItem( "DTED_OriginLatitude", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
     
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_ORIGINLONG );
     poDS->SetMetadataItem( "DTED_OriginLongitude", pszValue );
-    free( pszValue );
+    CPLFree( pszValue );
     
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_NIMA_DESIGNATOR ); 
     poDS->SetMetadataItem( "DTED_NimaDesignator", pszValue ); 
-    free( pszValue );
+    CPLFree( pszValue );
 
     pszValue = DTEDGetMetadata( psDTED, DTEDMD_PARTIALCELL_DSI );
     poDS->SetMetadataItem( "DTED_PartialCellIndicator", pszValue );
-    free( pszValue ); 
+    CPLFree( pszValue );
 
     poDS->SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
 
@@ -470,30 +473,39 @@ GDALDataset *DTEDDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
-    poDS->TryLoadXML();
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
 
     // if no SR in xml, try aux
     const char* pszPrj = poDS->GDALPamDataset::GetProjectionRef();
     if( !pszPrj || strlen(pszPrj) == 0 )
     {
-        GDALDataset* poAuxDS = GDALFindAssociatedAuxFile( poOpenInfo->pszFilename, GA_ReadOnly, poDS );
-        if( poAuxDS )
+        int bTryAux = TRUE;
+        if( poOpenInfo->GetSiblingFiles() != NULL &&
+            CSLFindString(poOpenInfo->GetSiblingFiles(), CPLResetExtension(CPLGetFilename(poOpenInfo->pszFilename), "aux")) < 0 &&
+            CSLFindString(poOpenInfo->GetSiblingFiles(), CPLSPrintf("%s.aux", CPLGetFilename(poOpenInfo->pszFilename))) < 0 )
+            bTryAux = FALSE;
+        if( bTryAux )
         {
-            pszPrj = poAuxDS->GetProjectionRef();
-            if( pszPrj && strlen(pszPrj) > 0 )
+            GDALDataset* poAuxDS = GDALFindAssociatedAuxFile( poOpenInfo->pszFilename, GA_ReadOnly, poDS );
+            if( poAuxDS )
             {
-                CPLFree( poDS->pszProjection );
-                poDS->pszProjection = CPLStrdup(pszPrj);
-            }
+                pszPrj = poAuxDS->GetProjectionRef();
+                if( pszPrj && strlen(pszPrj) > 0 )
+                {
+                    CPLFree( poDS->pszProjection );
+                    poDS->pszProjection = CPLStrdup(pszPrj);
+                }
 
-            GDALClose( poAuxDS );
+                GDALClose( poAuxDS );
+            }
         }
     }
 
 /* -------------------------------------------------------------------- */
 /*      Support overviews.                                              */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
+                                 poOpenInfo->GetSiblingFiles() );
     return( poDS );
 }
 
@@ -728,7 +740,7 @@ DTEDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     {
         poSrcBand->RasterIO( GF_Read, 0, iY, psDTED->nXSize, 1, 
                             (void *) (panData + iY * psDTED->nXSize), psDTED->nXSize, 1, 
-                            GDT_Int16, 0, 0 );
+                            GDT_Int16, 0, 0, NULL );
 
         if( pfnProgress && !pfnProgress(0.5 * (iY+1) / (double) psDTED->nYSize, NULL, pProgressData ) )
         {
@@ -905,8 +917,10 @@ void GDALRegister_DTED()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DTED" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "DTED Elevation Raster" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "dt0 dt1 dt2" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_various.html#DTED" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
@@ -921,4 +935,3 @@ void GDALRegister_DTED()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/e00grid/GNUmakefile b/frmts/e00grid/GNUmakefile
index f417687..056bd46 100644
--- a/frmts/e00grid/GNUmakefile
+++ b/frmts/e00grid/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	e00griddataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/e00grid/e00griddataset.cpp b/frmts/e00grid/e00griddataset.cpp
index ba87472..abd9bf7 100644
--- a/frmts/e00grid/e00griddataset.cpp
+++ b/frmts/e00grid/e00griddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: e00griddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: e00griddataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  E00 grid driver
  * Purpose:  GDALDataset driver for E00 grid dataset.
@@ -46,7 +46,7 @@
 #define E00_DOUBLE_SIZE 21
 #define VALS_PER_LINE   5
 
-CPL_CVSID("$Id: e00griddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: e00griddataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void    GDALRegister_E00GRID(void);
@@ -164,9 +164,9 @@ E00GRIDRasterBand::E00GRIDRasterBand( E00GRIDDataset *poDS, int nBand,
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr E00GRIDRasterBand::IReadBlock( int CPL_UNUSED nBlockXOff, int nBlockYOff,
+CPLErr E00GRIDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                      int nBlockYOff,
                                       void * pImage )
-
 {
     E00GRIDDataset *poGDS = (E00GRIDDataset *) poDS;
 
@@ -229,7 +229,7 @@ CPLErr E00GRIDRasterBand::IReadBlock( int CPL_UNUSED nBlockXOff, int nBlockYOff,
             }
             if (eDataType == GDT_Float32)
             {
-                pafImage[i] = (float) atof(pszLine + (i%VALS_PER_LINE) * E00_FLOAT_SIZE);
+                pafImage[i] = (float) CPLAtof(pszLine + (i%VALS_PER_LINE) * E00_FLOAT_SIZE);
                 /* Workaround single vs double precision problems */
                 if (fNoData != 0 && fabs((pafImage[i] - fNoData)/fNoData) < 1e-6)
                     pafImage[i] = fNoData;
@@ -258,7 +258,7 @@ CPLErr E00GRIDRasterBand::IReadBlock( int CPL_UNUSED nBlockXOff, int nBlockYOff,
 
         if (eDataType == GDT_Float32)
         {
-            pafImage[i] = (float) atof(szVal);
+            pafImage[i] = (float) CPLAtof(szVal);
             /* Workaround single vs double precision problems */
             if (fNoData != 0 && fabs((pafImage[i] - fNoData)/fNoData) < 1e-6)
                 pafImage[i] = fNoData;
@@ -601,7 +601,7 @@ GDALDataset *E00GRIDDataset::Open( GDALOpenInfo * poOpenInfo )
         CPLDebug("E00GRID", "Unknown data type : %s", pszLine);
     }
 
-    double dfNoData = atof(pszLine + E00_INT_SIZE + E00_INT_SIZE + 2);
+    double dfNoData = CPLAtof(pszLine + E00_INT_SIZE + E00_INT_SIZE + 2);
 
     /* read pixel size */
     if (e00ReadPtr)
@@ -615,8 +615,8 @@ GDALDataset *E00GRIDDataset::Open( GDALOpenInfo * poOpenInfo )
         return NULL;
     }
 /*
-    double dfPixelX = atof(pszLine);
-    double dfPixelY = atof(pszLine + E00_DOUBLE_SIZE);
+    double dfPixelX = CPLAtof(pszLine);
+    double dfPixelY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
 */
 
     /* read xmin, ymin */
@@ -630,8 +630,8 @@ GDALDataset *E00GRIDDataset::Open( GDALOpenInfo * poOpenInfo )
         delete poDS;
         return NULL;
     }
-    double dfMinX = atof(pszLine);
-    double dfMinY = atof(pszLine + E00_DOUBLE_SIZE);
+    double dfMinX = CPLAtof(pszLine);
+    double dfMinY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
 
     /* read xmax, ymax */
     if (e00ReadPtr)
@@ -644,8 +644,8 @@ GDALDataset *E00GRIDDataset::Open( GDALOpenInfo * poOpenInfo )
         delete poDS;
         return NULL;
     }
-    double dfMaxX = atof(pszLine);
-    double dfMaxY = atof(pszLine + E00_DOUBLE_SIZE);
+    double dfMaxX = CPLAtof(pszLine);
+    double dfMaxY = CPLAtof(pszLine + E00_DOUBLE_SIZE);
 
     poDS->nRasterXSize = nRasterXSize;
     poDS->nRasterYSize = nRasterYSize;
@@ -877,10 +877,10 @@ void E00GRIDDataset::ReadMetadata()
                     char** papszTokens = CSLTokenizeString(osStats);
                     if (CSLCount(papszTokens) == 4)
                     {
-                        dfMin = atof(papszTokens[0]);
-                        dfMax = atof(papszTokens[1]);
-                        dfMean = atof(papszTokens[2]);
-                        dfStddev = atof(papszTokens[3]);
+                        dfMin = CPLAtof(papszTokens[0]);
+                        dfMax = CPLAtof(papszTokens[1]);
+                        dfMean = CPLAtof(papszTokens[2]);
+                        dfStddev = CPLAtof(papszTokens[3]);
                         bHasStats = TRUE;
                     }
                     CSLDestroy(papszTokens);
@@ -906,6 +906,7 @@ void GDALRegister_E00GRID()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "E00GRID" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Arc/Info Export E00 GRID" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -921,4 +922,3 @@ void GDALRegister_E00GRID()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/ecw/GNUmakefile b/frmts/ecw/GNUmakefile
index 1609d7d..0a723d7 100644
--- a/frmts/ecw/GNUmakefile
+++ b/frmts/ecw/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	ecwdataset.o ecwcreatecopy.o jp2userbox.o ecwasyncreader.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -DFRMT_ecw $(CPPFLAGS) \
+CPPFLAGS	:=	 -DFRMT_ecw $(CPPFLAGS) \
 	$(ECW_FLAGS) $(ECW_INCLUDE) $(EXTRA_CFLAGS)
 PLUGIN_SO =	gdal_ECW_JP2ECW.so
 
diff --git a/frmts/ecw/ecwcreatecopy.cpp b/frmts/ecw/ecwcreatecopy.cpp
index 4546a98..0c62adf 100644
--- a/frmts/ecw/ecwcreatecopy.cpp
+++ b/frmts/ecw/ecwcreatecopy.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ecwcreatecopy.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: ecwcreatecopy.cpp 29054 2015-04-29 19:31:41Z rouault $
  *
  * Project:  GDAL ECW Driver
  * Purpose:  ECW CreateCopy method implementation.
@@ -32,7 +32,7 @@
 #include "gdaljp2metadata.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: ecwcreatecopy.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: ecwcreatecopy.cpp 29054 2015-04-29 19:31:41Z rouault $");
 
 #if defined(FRMT_ecw) && defined(HAVE_COMPRESS)
 
@@ -92,11 +92,13 @@ public:
                         GDALDataType eType, 
                         const char *pszWKT, double *padfGeoTransform,
                         int nGCPCount, const GDAL_GCP *pasGCPList,
-                        int bIsJPEG2000, int bPixelIsPoint );
+                        int bIsJPEG2000, int bPixelIsPoint, char** papszRPCMD,
+                        GDALDataset* poSrcDS = NULL );
     CPLErr  CloseDown();
 
     CPLErr  PrepareCoverageBox( const char *pszWKT, double *padfGeoTransform );
     CPLErr  WriteJP2Box( GDALJP2Box * );
+    void    WriteXMLBoxes();
     CPLErr  WriteLineBIL(UINT16 nBands, void **ppOutputLine, UINT32 *pLineSteps = NULL);
     virtual NCSEcwCellType WriteReadLineGetCellType() {
         return sFileInfo.eCellType;
@@ -212,7 +214,7 @@ CNCSError GDALECWCompressor::WriteReadLine( UINT32 nNextLine,
                                 pabyLineBuf, sFileInfo.nSizeX, 1, 
                                 eWorkDT, 
                                 sFileInfo.nBands, panBandMap,
-                                nWordSize, 0, nWordSize * sFileInfo.nSizeX );
+                                nWordSize, 0, nWordSize * sFileInfo.nSizeX, NULL );
 
     for( iBand = 0; iBand < (int) sFileInfo.nBands; iBand++ )
     {
@@ -323,7 +325,7 @@ CPLErr  GDALECWCompressor::PrepareCoverageBox(
 /* -------------------------------------------------------------------- */
     char szDoc[4000];
 
-    sprintf( szDoc, 
+    CPLsprintf( szDoc, 
 "<gml:FeatureCollection\n"
 "   xmlns:gml=\"http://www.opengis.net/gml\"\n"
 "   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
@@ -496,6 +498,21 @@ CPLErr GDALECWCompressor::WriteJP2Box( GDALJP2Box * poBox )
 }
 
 /************************************************************************/
+/*                         WriteXMLBoxes()                              */
+/************************************************************************/
+
+void GDALECWCompressor::WriteXMLBoxes()
+{
+    int nBoxes = 0;
+    GDALJP2Box** papoBoxes = GDALJP2Metadata::CreateXMLBoxes(m_poSrcDS, &nBoxes);
+    for(int i=0;i<nBoxes;i++)
+    {
+        WriteJP2Box(papoBoxes[i]);
+    }
+    CPLFree(papoBoxes);
+}
+
+/************************************************************************/
 /*                            WriteLineBIL()                            */
 /************************************************************************/
 
@@ -522,7 +539,8 @@ CPLErr GDALECWCompressor::Initialize(
     GDALDataType eType, 
     const char *pszWKT, double *padfGeoTransform,
     int nGCPCount, const GDAL_GCP *pasGCPList,
-    int bIsJPEG2000, int bPixelIsPoint )
+    int bIsJPEG2000, int bPixelIsPoint, char** papszRPCMD,
+    GDALDataset* poSrcDS )
 
 {
      const char *pszOption;
@@ -582,7 +600,7 @@ CPLErr GDALECWCompressor::Initialize(
     if( CSLFetchNameValue(papszOptions, "TARGET") != NULL )
     {
         fTargetCompression = (float) 
-            atof(CSLFetchNameValue(papszOptions, "TARGET"));
+            CPLAtof(CSLFetchNameValue(papszOptions, "TARGET"));
 
         /* The max allowed value should be 100 - 100 / 65535 = 99.9984740978 */
         /* so that nCompressionRate fits on a uint16 (see below) */
@@ -817,7 +835,7 @@ CPLErr GDALECWCompressor::Initialize(
 
         pszOption = CSLFetchNameValue(papszOptions, "GEODATA_USAGE");
         if( pszOption == NULL )
-            // Default to supressing ECW SDK geodata, just use our own stuff.
+            // Default to suppressing ECW SDK geodata, just use our own stuff.
             SetGeodataUsage( JP2_GEODATA_USE_NONE );
         else if( EQUAL(pszOption,"NONE") )
             SetGeodataUsage( JP2_GEODATA_USE_NONE );
@@ -843,7 +861,7 @@ CPLErr GDALECWCompressor::Initialize(
         if( pszOption != NULL )
             SetParameter( 
                 CNCSJP2FileView::JPC_DECOMPRESS_RECONSTRUCTION_PARAMETER, 
-                (IEEE4) atof(pszOption) );
+                (IEEE4) CPLAtof(pszOption) );
     }
                                   
 /* -------------------------------------------------------------------- */
@@ -928,7 +946,7 @@ CPLErr GDALECWCompressor::Initialize(
           padfGeoTransform[3] == 0.0 &&
           padfGeoTransform[4] == 0.0 &&
           padfGeoTransform[5] == 1.0) ||
-         nGCPCount > 0 )
+         nGCPCount > 0  || papszRPCMD != NULL )
     {
         GDALJP2Metadata oJP2MD;
 
@@ -936,14 +954,33 @@ CPLErr GDALECWCompressor::Initialize(
         oJP2MD.SetGeoTransform( padfGeoTransform );
         oJP2MD.SetGCPs( nGCPCount, pasGCPList );
         oJP2MD.bPixelIsPoint = bPixelIsPoint;
+        oJP2MD.SetRPCMD( papszRPCMD );
 
         if (bIsJPEG2000) {
-
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+            {
+                if( !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+                {
+                    WriteXMLBoxes();
+                }
+                WriteJP2Box(GDALJP2Metadata::CreateGDALMultiDomainMetadataXMLBox(
+                        m_poSrcDS, CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE)));
+            }
             if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) )
-                WriteJP2Box( oJP2MD.CreateGMLJP2(nXSize,nYSize) );
+            {
+                const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
+                if( pszGMLJP2V2Def != NULL )
+                    WriteJP2Box( oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS) );
+                else
+                    WriteJP2Box( oJP2MD.CreateGMLJP2(nXSize,nYSize) );
+            }
             if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) )
                 WriteJP2Box( oJP2MD.CreateJP2GeoTIFF() );
-
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) &&
+                !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+            {
+                WriteJP2Box(GDALJP2Metadata::CreateXMPBox(m_poSrcDS));
+            }
         }
     }
 /* -------------------------------------------------------------------- */
@@ -1216,7 +1253,9 @@ ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                 eType, pszWKT, adfGeoTransform, 
                                 poSrcDS->GetGCPCount(), 
                                 poSrcDS->GetGCPs(),
-                                bIsJPEG2000, bPixelIsPoint )
+                                bIsJPEG2000, bPixelIsPoint,
+                                poSrcDS->GetMetadata("RPC"),
+                                poSrcDS )
         != CE_None )
     {
         for (i=0;i<nBands;i++)
@@ -1246,7 +1285,7 @@ ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     pfnProgress( 1.001, NULL, pProgressData );
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     GDALPamDataset *poDS;
@@ -1266,7 +1305,7 @@ ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             }
             double dHistMin, dHistMax;
             int nBuckets;
-            int *pHistogram;
+            GUIntBig *pHistogram;
             if (poSrcDS->GetRasterBand(i)->GetDefaultHistogram(&dHistMin, &dHistMax,&nBuckets,&pHistogram, FALSE, NULL, NULL) == CE_None){
                 poDS->GetRasterBand(i)->SetDefaultHistogram(dHistMin, dHistMax, nBuckets, pHistogram);
                 VSIFree(pHistogram);
@@ -1275,7 +1314,11 @@ ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 #endif
 
         ((ECWDataset *)poDS)->SetPreventCopyingSomeMetadata(TRUE);
-        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
+        int nFlags = GCIF_PAM_DEFAULT;
+        if( bIsJPEG2000 &&
+            !CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+            nFlags &= ~GCIF_METADATA;
+        poDS->CloneInfo( poSrcDS, nFlags );
         ((ECWDataset *)poDS)->SetPreventCopyingSomeMetadata(FALSE);
     }
 
@@ -1475,7 +1518,7 @@ class IRasterIORequest
                           int nXOff, int nYOff, int nXSize, int nYSize,
                           void * pData, int nBufXSize, int nBufYSize,
                           GDALDataType eBufType, 
-                          int nPixelSpace, int nLineSpace ) :
+                          GSpacing nPixelSpace, GSpacing nLineSpace ) :
                             poBand(poBand),
                             nXOff(nXOff),
                             nYOff(nYOff),
@@ -1547,7 +1590,9 @@ class CPL_DLL ECWWriteDataset : public GDALDataset
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace);
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 #endif
 };
 
@@ -1592,7 +1637,8 @@ class ECWWriteRasterBand : public GDALRasterBand
                               int nXOff, int nYOff, int nXSize, int nYSize,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace);
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 #endif
 };
 
@@ -1750,7 +1796,7 @@ CPLErr ECWWriteDataset::Crystalize()
                                    eDataType, 
                                    pszProjection, adfGeoTransform, 
                                    0, NULL,
-                                   bIsJPEG2000, FALSE );
+                                   bIsJPEG2000, FALSE, NULL );
 
     if( eErr == CE_None )
         bCrystalized = TRUE;
@@ -1824,7 +1870,9 @@ CPLErr ECWWriteDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace)
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
 {
     ECWWriteRasterBand* po4thBand = NULL;
     IRasterIORequest* poIORequest = NULL;
@@ -1888,7 +1936,7 @@ CPLErr ECWWriteDataset::IRasterIO( GDALRWFlag eRWFlag,
                               pData, nBufXSize, nBufYSize,
                               eBufType, 
                               nBandCount, panBandMap,
-                              nPixelSpace, nLineSpace, nBandSpace);
+                              nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
 }
 #endif
 
@@ -1957,7 +2005,8 @@ CPLErr ECWWriteRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                               int nXOff, int nYOff, int nXSize, int nYSize,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace)
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
 {
     if( eRWFlag == GF_Write && nBand == 4 && poGDS->nBands == 4 &&
         poGDS->nPrevIRasterIOBand < 0 )
@@ -1979,7 +2028,7 @@ CPLErr ECWWriteRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                               nXOff, nYOff, nXSize, nYSize,
                               pData, nBufXSize, nBufYSize,
                               eBufType, 
-                              nPixelSpace, nLineSpace );
+                              nPixelSpace, nLineSpace, psExtraArg );
 }
 #endif
 
diff --git a/frmts/ecw/ecwdataset.cpp b/frmts/ecw/ecwdataset.cpp
index e317448..43d10df 100644
--- a/frmts/ecw/ecwdataset.cpp
+++ b/frmts/ecw/ecwdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ecwdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: ecwdataset.cpp 29075 2015-04-30 12:51:21Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  ECW (ERDAS Wavelet Compression Format) Driver
@@ -34,7 +34,7 @@
 #include "ogr_api.h"
 #include "ogr_geometry.h"
 
-CPL_CVSID("$Id: ecwdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: ecwdataset.cpp 29075 2015-04-30 12:51:21Z rouault $");
 
 #undef NOISY_DEBUG
 
@@ -44,7 +44,7 @@ static const unsigned char jpc_header[] = {0xff,0x4f};
 static const unsigned char jp2_header[] = 
     {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
 
-static void *hECWDatasetMutex = NULL;
+static CPLMutex *hECWDatasetMutex = NULL;
 static int    bNCSInitialized = FALSE;
 
 void ECWInitialize( void );
@@ -76,7 +76,8 @@ void ECWReportError(CNCSError& oErr, const char* pszMsg)
 /*                           ECWRasterBand()                            */
 /************************************************************************/
 
-ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
+ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview,
+                              char** papszOpenOptions )
 
 {
     this->poDS = poDS;
@@ -108,22 +109,26 @@ ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
     }else if (poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND ){
         eBandInterp = ECWGetColorInterpretationByName(poDS->psFileInfo->pBands[nBand-1].szDesc);
     }else if (poDS->psFileInfo->eColorSpace == NCSCS_sRGB){
-        if( nBand == 1 )
-            eBandInterp = GCI_RedBand;
-        else if( nBand == 2 )
-            eBandInterp = GCI_GreenBand;
-        else if( nBand == 3 )
-            eBandInterp = GCI_BlueBand;
-        else if (nBand == 4 )
+        eBandInterp = ECWGetColorInterpretationByName(poDS->psFileInfo->pBands[nBand-1].szDesc);
+        if( eBandInterp == GCI_Undefined )
         {
-            if (strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_AllOpacity) == 0)
-                eBandInterp = GCI_AlphaBand;
+            if( nBand == 1 )
+                eBandInterp = GCI_RedBand;
+            else if( nBand == 2 )
+                eBandInterp = GCI_GreenBand;
+            else if( nBand == 3 )
+                eBandInterp = GCI_BlueBand;
+            else if (nBand == 4 )
+            {
+                if (strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_AllOpacity) == 0)
+                    eBandInterp = GCI_AlphaBand;
+                else
+                    eBandInterp = GCI_Undefined;
+            }
             else
+            {
                 eBandInterp = GCI_Undefined;
-        }
-        else
-        {
-            eBandInterp = GCI_Undefined;
+            }
         }
     }
     else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
@@ -165,7 +170,7 @@ ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
                  && nRasterYSize / (1 << (i+1)) > 128;
              i++ )
         {
-            apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
+            apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i, papszOpenOptions ) );
         }
     }
 
@@ -176,7 +181,8 @@ ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
         poDS->psFileInfo->pBands[2].nBits == 8 &&
         poDS->psFileInfo->pBands[3].nBits == 1 &&
         eBandInterp == GCI_AlphaBand && 
-        CSLTestBoolean(CPLGetConfigOption("GDAL_ECW_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES"));
+        CSLFetchBoolean(papszOpenOptions, "1BIT_ALPHA_PROMOTION",
+            CSLTestBoolean(CPLGetConfigOption("GDAL_ECW_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES")));
     if( bPromoteTo8Bit )
         CPLDebug("ECW", "Fourth (alpha) band is promoted from 1 bit to 8 bit");
 
@@ -271,7 +277,7 @@ CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
 /************************************************************************/
 
 CPLErr ECWRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
-    int *pnBuckets, int ** ppanHistogram,
+    int *pnBuckets, GUIntBig ** ppanHistogram,
     int bForce,
     GDALProgressFunc f, void *pProgressData)
 {
@@ -299,9 +305,9 @@ CPLErr ECWRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
         NCSBandStats& bandStats = poGDS->pStatistics->BandsStats[nStatsBandIndex];
         if ( bandStats.Histogram != NULL && bandStats.nHistBucketCount > 0 ){
             *pnBuckets = bandStats.nHistBucketCount;
-            *ppanHistogram = (int *)VSIMalloc(bandStats.nHistBucketCount *sizeof(int));
+            *ppanHistogram = (GUIntBig *)VSIMalloc(bandStats.nHistBucketCount *sizeof(GUIntBig));
             for (size_t i = 0; i < bandStats.nHistBucketCount; i++){
-                (*ppanHistogram)[i] = (int) bandStats.Histogram[i];
+                (*ppanHistogram)[i] = (GUIntBig) bandStats.Histogram[i];
             }
             //JTO: this is not perfect as You can't tell who wrote the histogram !!! 
             //It will offset it unnecesarilly for files with hists not modified by GDAL. 
@@ -351,7 +357,7 @@ CPLErr ECWRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
 /************************************************************************/
 
 CPLErr ECWRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
-                                           int nBuckets, int *panHistogram )
+                                           int nBuckets, GUIntBig *panHistogram )
 {
     //Only version 3 supports saving statistics. 
     if (poGDS->psFileInfo->nFormatVersion < 3 || eBandInterp == GCI_AlphaBand){
@@ -361,7 +367,7 @@ CPLErr ECWRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
     //determine if there are statistics in PAM file. 
     double dummy;
     int dummy_i;
-    int *dummy_histogram;
+    GUIntBig *dummy_histogram;
     bool hasPAMDefaultHistogram = GDALPamRasterBand::GetDefaultHistogram(&dummy, &dummy, &dummy_i, &dummy_histogram, FALSE, NULL, NULL) == CE_None;
     if (hasPAMDefaultHistogram){
         VSIFree(dummy_histogram);
@@ -666,7 +672,8 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
     
 {
     int          iBand, bDirect;
@@ -681,13 +688,16 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
 /* -------------------------------------------------------------------- */
 /*      Try to do it based on existing "advised" access.                */
 /* -------------------------------------------------------------------- */
-    if( poGDS->TryWinRasterIO( eRWFlag, 
+    int nRet = poGDS->TryWinRasterIO( eRWFlag, 
                                nXOff, nYOff, 
                                nXSize, nYSize, 
                                (GByte *) pData, nBufXSize, nBufYSize, 
                                eBufType, 1, &nBand, 
-                               nPixelSpace, nLineSpace, 0 ) )
+                               nPixelSpace, nLineSpace, 0 , psExtraArg);
+    if( nRet == TRUE )
         return CE_None;
+    else if( nRet < 0 )
+        return CE_Failure;
 
 /* -------------------------------------------------------------------- */
 /*      The ECW SDK doesn't supersample, so adjust for this case.       */
@@ -741,11 +751,12 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
     double  dfSrcYInc = (double)nNewYSize / nBufYSize;
     double  dfSrcXInc = (double)nNewXSize / nBufXSize;
     int         iSrcLine, iDstLine;
+    CPLErr eErr = CE_None;
 
     for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
     {
         NCSEcwReadStatus eRStatus;
-        int         iDstLineOff = iDstLine * nLineSpace;
+        GPtrDiff_t       iDstLineOff = iDstLine * (GPtrDiff_t)nLineSpace;
         unsigned char   *pabySrcBuf;
 
         if( bDirect )
@@ -760,11 +771,11 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
 
             if( eRStatus != NCSECW_READ_OK )
             {
-                CPLFree( pabyWorkBuffer );
                 CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
                 CPLError( CE_Failure, CPLE_AppDefined,
                          "NCScbmReadViewLineBIL failed." );
-                return CE_Failure;
+                eErr = CE_Failure;
+                break;
             }
 
             if( bPromoteTo8Bit )
@@ -782,7 +793,7 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
                     GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType, 
                                 nRawPixelSize, 
                                 ((GByte *)pData) + iDstLine * nLineSpace, 
-                                eBufType, nPixelSpace, nBufXSize );
+                                eBufType, (int)nPixelSpace, nBufXSize );
                 }
                 else
                 {
@@ -795,7 +806,7 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
                                     poGDS->eRasterDataType, nRawPixelSize,
                                     (GByte *)pData + iDstLineOff
                                     + iPixel * nPixelSpace,
-                                                    eBufType, nPixelSpace, 1 );
+                                                    eBufType, (int)nPixelSpace, 1 );
                     }
                 }
             }
@@ -806,15 +817,23 @@ CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
         {
             // Just copy the previous line in this case
             GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
-                            eBufType, nPixelSpace,
+                            eBufType, (int)nPixelSpace,
                             (GByte *)pData + iDstLineOff,
-                            eBufType, nPixelSpace, nBufXSize );
+                            eBufType, (int)nPixelSpace, nBufXSize );
+        }
+
+        if( psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * (iDstLine + 1) / nBufYSize, "",
+                                             psExtraArg->pProgressData) )
+        {
+            eErr = CE_Failure;
+            break;
         }
     }
 
     CPLFree( pabyWorkBuffer );
 
-    return CE_None;
+    return eErr;
 }
 //#endif !defined(SDK_CAN_DO_SUPERSAMPLING)
 
@@ -826,7 +845,8 @@ CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
 {
     if( eRWFlag == GF_Write )
         return CE_Failure;
@@ -850,7 +870,7 @@ CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return OldIRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                             pData, nBufXSize, nBufYSize,
                             eBufType,
-                            nPixelSpace, nLineSpace );
+                            nPixelSpace, nLineSpace, psExtraArg );
     }
 
 #endif
@@ -864,7 +884,7 @@ CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                             (nYSize == nRasterYSize) ? poGDS->nRasterYSize : nYSize * nResFactor,
                             pData, nBufXSize, nBufYSize,
                             eBufType, 1, &nBand,
-                            nPixelSpace, nLineSpace, nLineSpace*nBufYSize);
+                            nPixelSpace, nLineSpace, nLineSpace*nBufYSize, psExtraArg);
 }
 
 /************************************************************************/
@@ -886,10 +906,14 @@ CPLErr ECWRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage
 
     int nPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
     int nLineSpace = nPixelSpace * nBlockXSize;
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     return IRasterIO( GF_Read,
                       nXOff, nYOff, nXSize, nYSize,
                       pImage, nXSize, nYSize,
-                      eDataType, nPixelSpace, nLineSpace );
+                      eDataType, nPixelSpace, nLineSpace, &sExtraArg );
 }
 
 /************************************************************************/
@@ -981,7 +1005,7 @@ ECWDataset::~ECWDataset()
 
     // bInGDALGlobalDestructor is set to TRUE by gdaldllmain.cpp/GDALDestroy() so as
     // to avoid an issue with the ECW SDK 3.3 where the destructor of CNCSJP2File::CNCSJP2FileVector CNCSJP2File::sm_Files;
-    // static ressource allocated in NCJP2File.cpp can be called before GDALDestroy(), causing
+    // static resource allocated in NCJP2File.cpp can be called before GDALDestroy(), causing
     // ECW SDK resources ( CNCSJP2File files ) to be closed before we get here.
     //
     // We also have an issue with ECW SDK 5.0 and ECW files on Linux when
@@ -1589,8 +1613,9 @@ int ECWDataset::TryWinRasterIO( CPL_UNUSED GDALRWFlag eFlag,
                                 GByte *pabyData, int nBufXSize, int nBufYSize,
                                 GDALDataType eDT,
                                 int nBandCount, int *panBandList,
-                                int nPixelSpace, int nLineSpace,
-                                int nBandSpace )
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GSpacing nBandSpace,
+                                GDALRasterIOExtraArg* psExtraArg )
 {
     int iBand, i;
 
@@ -1686,9 +1711,16 @@ int ECWDataset::TryWinRasterIO( CPL_UNUSED GDALRWFlag eFlag,
             GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
                            GDALGetDataTypeSize( eRasterDataType ) / 8, 
                            pabyData + nBandSpace * iBand 
-                           + iBufLine * nLineSpace, eDT, nPixelSpace,
+                           + iBufLine * nLineSpace, eDT, (int)nPixelSpace,
                            nBufXSize );
         }
+
+        if( psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * (iBufLine + 1) / nBufYSize, "",
+                                             psExtraArg->pProgressData) )
+        {
+            return -1;
+        }
     }
 
     return TRUE;
@@ -1759,7 +1791,9 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace)
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
     
 {
     if( eRWFlag == GF_Write )
@@ -1807,7 +1841,7 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     pData, nBufXSize, nBufYSize,
                                     eBufType, 
                                     nBandCount, panBandMap,
-                                    nPixelSpace, nLineSpace, nBandSpace);
+                                    nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
         }
     }
 #endif
@@ -1838,7 +1872,7 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     (*panBandMap - 1) * nBufXSize * nBufYSize * nDataTypeSize +
                                     j * nBufXSize * nDataTypeSize,
                             eBufType, nDataTypeSize,
-                            ((GByte*)pData) + j * nLineSpace, eBufType, nPixelSpace,
+                            ((GByte*)pData) + j * nLineSpace, eBufType, (int)nPixelSpace,
                             nBufXSize);
             }
             return CE_None;
@@ -1856,11 +1890,14 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
 /* -------------------------------------------------------------------- */
 /*      Try to do it based on existing "advised" access.                */
 /* -------------------------------------------------------------------- */
-    if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+    int nRet = TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                         (GByte *) pData, nBufXSize, nBufYSize, 
                         eBufType, nBandCount, panBandMap,
-                        nPixelSpace, nLineSpace, nBandSpace ) )
+                        nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
+    if( nRet == TRUE )
         return CE_None;
+    else if( nRet < 0 )
+        return CE_Failure;
 
 /* -------------------------------------------------------------------- */
 /*      If we are requesting a single line at 1:1, we do a multi-band   */
@@ -1887,7 +1924,7 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     pData, nBufXSize, nBufYSize,
                                     eBufType, 
                                     nBandCount, panBandMap,
-                                    nPixelSpace, nLineSpace, nBandSpace);
+                                    nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
         bUseOldBandRasterIOImplementation = FALSE;
         return eErr;
     }
@@ -1908,7 +1945,7 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
             && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                (GByte *) pData, nBufXSize, nBufYSize, 
                                eBufType, nBandCount, panBandMap,
-                               nPixelSpace, nLineSpace, nBandSpace ) )
+                               nPixelSpace, nLineSpace, nBandSpace, psExtraArg ) )
             return CE_None;
     }
 
@@ -1992,7 +2029,8 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     nBands,
                                     nDataTypeSize,
                                     nBufXSize * nDataTypeSize,
-                                    nBufXSize * nBufYSize * nDataTypeSize);
+                                    nBufXSize * nBufYSize * nDataTypeSize,
+                                    psExtraArg);
             if( eErr != CE_None )
                 return eErr;
 
@@ -2002,7 +2040,7 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
                 GDALCopyWords(sCachedMultiBandIO.pabyData +
                                     j * nBufXSize * nDataTypeSize,
                               eBufType, nDataTypeSize,
-                              ((GByte*)pData) + j * nLineSpace, eBufType, nPixelSpace,
+                              ((GByte*)pData) + j * nLineSpace, eBufType, (int)nPixelSpace,
                               nBufXSize);
             }
             return CE_None;
@@ -2031,7 +2069,8 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
     }
 
     return ReadBands(pData, nBufXSize, nBufYSize, eBufType,
-                     nBandCount, nPixelSpace, nLineSpace, nBandSpace);
+                     nBandCount, nPixelSpace, nLineSpace, nBandSpace,
+                     psExtraArg);
 }
 
 /************************************************************************/
@@ -2041,7 +2080,10 @@ CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
 CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
                                      CPL_UNUSED GDALDataType eBufType,
                                      int nBandCount,
-                                     CPL_UNUSED int nPixelSpace, int nLineSpace, int nBandSpace)
+                                     CPL_UNUSED GSpacing nPixelSpace,
+                                     GSpacing nLineSpace,
+                                     GSpacing nBandSpace,
+                                     GDALRasterIOExtraArg* psExtraArg)
 {
     CPLDebug( "ECW",
               "ReadBandsDirectly(-> %dx%d) - reading lines directly.",
@@ -2054,15 +2096,13 @@ CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
         pBIL[nB] = ((UINT8*)pData) + (nBandSpace*nB);//for any bit depth
     }
 
+    CPLErr eErr = CE_None;
     for(int nR = 0; nR < nBufYSize; nR++) 
     {
         if (poFileView->ReadLineBIL(eNCSRequestDataType,(UINT16) nBandCount, (void**)pBIL) != NCSECW_READ_OK)
         {
-            if(pBIL) {
-                NCSFree(pBIL);
-            }
-        
-            return CE_Failure;
+            eErr = CE_Failure;
+            break;
         }
         for(int nB = 0; nB < nBandCount; nB++) 
         {
@@ -2075,12 +2115,20 @@ CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
             }
             pBIL[nB] += nLineSpace;
         }
+
+        if( psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * (nR + 1) / nBufYSize, "",
+                                             psExtraArg->pProgressData) )
+        {
+            eErr = CE_Failure;
+            break;
+        }
     }
     if(pBIL)
     {
         NCSFree(pBIL);
     }
-    return CE_None;
+    return eErr;
 }
 
 /************************************************************************/
@@ -2088,9 +2136,10 @@ CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
 /************************************************************************/
 
 CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
-                            GDALDataType eBufType, 
-                            int nBandCount, 
-                            int nPixelSpace, int nLineSpace, int nBandSpace)
+                             GDALDataType eBufType, 
+                             int nBandCount, 
+                             GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                             GDALRasterIOExtraArg* psExtraArg)
 {
     int i;
 /* -------------------------------------------------------------------- */
@@ -2102,7 +2151,7 @@ CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
     if (bDirect)
     {
         return ReadBandsDirectly(pData, nBufXSize, nBufYSize,eBufType, 
-            nBandCount, nPixelSpace, nLineSpace, nBandSpace);
+            nBandCount, nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
     }
      CPLDebug( "ECW", 
               "ReadBands(-> %dx%d) - reading lines using GDALCopyWords.", 
@@ -2147,9 +2196,17 @@ CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
                 pabyBILScanline + i * nDataTypeSize * nBufXSize,
                 eRasterDataType, nDataTypeSize, 
                 ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i, 
-                eBufType, nPixelSpace, 
+                eBufType, (int)nPixelSpace, 
                 nBufXSize );
         }
+
+        if( psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * (iScanline + 1) / nBufYSize, "",
+                                             psExtraArg->pProgressData) )
+        {
+            eErr = CE_Failure;
+            break;
+        }
     }
 
     CPLFree( pabyBILScanline );
@@ -2254,7 +2311,16 @@ CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
     bUsingCustomStream = FALSE;
     poFileView = new CNCSFile();
     //we always open in read only mode. This should be improved in the future.
-    oErr = poFileView->Open( (char *) pszDatasetName, bProgressive, false );
+    try
+    {
+        oErr = poFileView->Open( (char *) pszDatasetName, bProgressive, false );
+    }
+    catch(...)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Unexpected exception occured in ECW SDK");
+        delete poFileView;
+        return NULL;
+    }
     eErr = oErr.GetErrorNumber();
 
 /* -------------------------------------------------------------------- */
@@ -2494,7 +2560,7 @@ GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
 /*      Create band information objects.                                */
 /* -------------------------------------------------------------------- */
     for( i=0; i < poDS->psFileInfo->nBands; i++ )
-        poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
+        poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1, -1, poOpenInfo->papszOpenOptions ) );
 
 /* -------------------------------------------------------------------- */
 /*      Look for supporting coordinate system information.              */
@@ -2515,18 +2581,140 @@ GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
             poDS->bGeoTransformValid |= 
                 GDALReadWorldFile2( osFilename, NULL,
                                     poDS->adfGeoTransform,
-                                    poOpenInfo->papszSiblingFiles, NULL )
+                                    poOpenInfo->GetSiblingFiles(), NULL )
                 || GDALReadWorldFile2( osFilename, ".wld",
                                     poDS->adfGeoTransform,
-                                    poOpenInfo->papszSiblingFiles, NULL );
+                                    poOpenInfo->GetSiblingFiles(), NULL );
         }
     }
 
-	poDS->SetMetadataItem("COMPRESSION_RATE_TARGET", CPLString().Printf("%d", poDS->psFileInfo->nCompressionRate));
-	poDS->SetMetadataItem("COLORSPACE", ECWGetColorSpaceName(poDS->psFileInfo->eColorSpace));
+    poDS->SetMetadataItem("COMPRESSION_RATE_TARGET", CPLString().Printf("%d", poDS->psFileInfo->nCompressionRate));
+    poDS->SetMetadataItem("COLORSPACE", ECWGetColorSpaceName(poDS->psFileInfo->eColorSpace));
 #if ECWSDK_VERSION>=50
-    poDS->SetMetadataItem("VERSION", CPLString().Printf("%d", poDS->psFileInfo->nFormatVersion));
-    if ( poDS->psFileInfo->nFormatVersion >=3 ){
+    if( !bIsJPEG2000 )
+         poDS->SetMetadataItem("VERSION", CPLString().Printf("%d", poDS->psFileInfo->nFormatVersion));
+#if ECWSDK_VERSION>=51
+    // output jp2 header info
+    if( bIsJPEG2000 && poDS->poFileView ) {
+        // comments
+        char *csComments = NULL;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:COMMENTS", &csComments);
+        if (csComments) {
+            poDS->SetMetadataItem("ALL_COMMENTS", CPLString().Printf("%s", csComments));
+            NCSFree(csComments);
+        }
+
+        // Profile
+        UINT32 nProfile = 2;
+        UINT32 nRsiz = 0;
+        poDS->poFileView->GetParameter((char*)"JP2:COMPLIANCE:PROFILE:TYPE", &nRsiz);
+        if (nRsiz == 0)
+            nProfile = 2; // Profile 2 (no restrictions)
+        else if (nRsiz == 1)
+            nProfile = 0; // Profile 0
+        else if (nRsiz == 2)
+            nProfile = 1; // Profile 1, NITF_BIIF_NPJE, NITF_BIIF_EPJE
+        poDS->SetMetadataItem("PROFILE", CPLString().Printf("%d", nProfile), JPEG2000_DOMAIN_NAME);
+
+        // number of tiles on X axis
+        UINT32 nTileNrX = 1;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:TILENR:X", &nTileNrX);
+        poDS->SetMetadataItem("TILES_X", CPLString().Printf("%d", nTileNrX), JPEG2000_DOMAIN_NAME);
+
+        // number of tiles on X axis
+        UINT32 nTileNrY = 1;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:TILENR:Y", &nTileNrY);
+        poDS->SetMetadataItem("TILES_Y", CPLString().Printf("%d", nTileNrY), JPEG2000_DOMAIN_NAME);
+
+        // Tile Width
+        UINT32 nTileSizeX = 0;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:TILESIZE:X", &nTileSizeX);
+        poDS->SetMetadataItem("TILE_WIDTH", CPLString().Printf("%d", nTileSizeX), JPEG2000_DOMAIN_NAME);
+
+        // Tile Height
+        UINT32 nTileSizeY = 0;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:TILESIZE:Y", &nTileSizeY);
+        poDS->SetMetadataItem("TILE_HEIGHT", CPLString().Printf("%d", nTileSizeY), JPEG2000_DOMAIN_NAME);
+
+        // Precinct Sizes on X axis
+        char *csPreSizeX = NULL;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:PRECINCTSIZE:X", &csPreSizeX);
+        if (csPreSizeX) {
+                poDS->SetMetadataItem("PRECINCT_SIZE_X", csPreSizeX, JPEG2000_DOMAIN_NAME);
+            NCSFree(csPreSizeX);
+        }
+
+        // Precinct Sizes on Y axis
+        char *csPreSizeY = NULL;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:PRECINCTSIZE:Y", &csPreSizeY);
+        if (csPreSizeY) {
+            poDS->SetMetadataItem("PRECINCT_SIZE_Y", csPreSizeY, JPEG2000_DOMAIN_NAME);
+            NCSFree(csPreSizeY);
+        }
+
+        // Code Block Size on X axis
+        UINT32 nCodeBlockSizeX = 0;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:CODEBLOCK:X", &nCodeBlockSizeX);
+        poDS->SetMetadataItem("CODE_BLOCK_SIZE_X", CPLString().Printf("%d", nCodeBlockSizeX), JPEG2000_DOMAIN_NAME);
+
+        // Code Block Size on Y axis
+        UINT32 nCodeBlockSizeY = 0;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:CODEBLOCK:Y", &nCodeBlockSizeY);
+        poDS->SetMetadataItem("CODE_BLOCK_SIZE_Y", CPLString().Printf("%d", nCodeBlockSizeY), JPEG2000_DOMAIN_NAME);
+
+        // Bitdepth
+        char *csBitdepth = NULL;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:BITDEPTH", &csBitdepth);
+        if (csBitdepth) {
+            poDS->SetMetadataItem("PRECISION", csBitdepth, JPEG2000_DOMAIN_NAME);
+            NCSFree(csBitdepth);
+        }
+
+        // Resolution Levels
+        UINT32 nLevels = 0;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:RESOLUTION:LEVELS", &nLevels);
+        poDS->SetMetadataItem("RESOLUTION_LEVELS", CPLString().Printf("%d", nLevels), JPEG2000_DOMAIN_NAME);
+
+        // Qualaity Layers
+        UINT32 nLayers = 0;
+        poDS->poFileView->GetParameter((char*)"JP2:DECOMPRESS:LAYERS", &nLayers);
+        poDS->SetMetadataItem("QUALITY_LAYERS", CPLString().Printf("%d", nLayers), JPEG2000_DOMAIN_NAME);
+
+        // Progression Order
+        char *csOrder = NULL;
+        poDS->poFileView->GetParameter((char*)"JPC:DECOMPRESS:PROGRESSION:ORDER", &csOrder);	
+        if (csOrder) {
+            poDS->SetMetadataItem("PROGRESSION_ORDER", csOrder, JPEG2000_DOMAIN_NAME);
+            NCSFree(csOrder);
+        }
+
+        // DWT Filter
+        const char *csFilter = NULL;
+        UINT32 nFilter;
+        poDS->poFileView->GetParameter((char*)"JP2:TRANSFORMATION:TYPE", &nFilter);
+        if (nFilter)
+            csFilter = "5x3";
+        else
+            csFilter = "9x7";
+        poDS->SetMetadataItem("TRANSFORMATION_TYPE", csFilter, JPEG2000_DOMAIN_NAME);
+
+        // SOP used?
+        bool bSOP = 0;
+        poDS->poFileView->GetParameter((char*)"JP2:DECOMPRESS:SOP:EXISTS", &bSOP);
+        poDS->SetMetadataItem("USE_SOP", (bSOP) ? "TRUE" : "FALSE", JPEG2000_DOMAIN_NAME);
+
+        // EPH used?
+        bool bEPH = 0;
+        poDS->poFileView->GetParameter((char*)"JP2:DECOMPRESS:EPH:EXISTS", &bEPH);
+        poDS->SetMetadataItem("USE_EPH", (bEPH) ? "TRUE" : "FALSE", JPEG2000_DOMAIN_NAME);
+
+        // GML JP2 data contained?
+        bool bGML = 0;
+        poDS->poFileView->GetParameter((char*)"JP2:GML:JP2:BOX:EXISTS", &bGML);
+        poDS->SetMetadataItem("GML_JP2_DATA", (bGML) ? "TRUE" : "FALSE", JPEG2000_DOMAIN_NAME);
+    }
+    #endif //ECWSDK_VERSION>=51
+    if ( !bIsJPEG2000 && poDS->psFileInfo->nFormatVersion >=3 ){
         poDS->SetMetadataItem("COMPRESSION_RATE_ACTUAL", CPLString().Printf("%f", poDS->psFileInfo->fActualCompressionRate));
         poDS->SetMetadataItem("CLOCKWISE_ROTATION_DEG", CPLString().Printf("%f", poDS->psFileInfo->fCWRotationDegrees));
         poDS->SetMetadataItem("COMPRESSION_DATE", poDS->psFileInfo->sCompressionDate);
@@ -2542,7 +2730,25 @@ GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( osFilename );
     poDS->TryLoadXML();
-    
+
+/* -------------------------------------------------------------------- */
+/*      Vector layers                                                   */
+/* -------------------------------------------------------------------- */
+    if( bIsJPEG2000 && poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
+    {
+        poDS->LoadVectorLayers(
+            CSLFetchBoolean(poOpenInfo->papszOpenOptions, "OPEN_REMOTE_GML", FALSE));
+
+        // If file opened in vector-only mode and there's no vector,
+        // return
+        if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+            poDS->GetLayerCount() == 0 )
+        {
+            delete poDS;
+            return NULL;
+        }
+    }
+
     return( poDS );
 }
 
@@ -2674,12 +2880,12 @@ void ECWDataset::WriteFileMetaData(NCSFileMetaData* pFileMetaDataCopy)
 /*                                                                      */
 /*      Set the dataset pszProjection string in OGC WKT format by       */
 /*      looking up the ECW (GDT) coordinate system info in              */
-/*      ecw_cs.dat support data file.                                   */
+/*      ecw_cs.wkt support data file.                                   */
 /*                                                                      */
 /*      This code is likely still broken in some circumstances.  For    */
 /*      instance, I haven't been careful about changing the linear      */
 /*      projection parameters (false easting/northing) if the units     */
-/*      is feet.  Lots of cases missing here, and in ecw_cs.dat.        */
+/*      is feet.  Lots of cases missing here, and in ecw_cs.wkt.        */
 /************************************************************************/
 
 void ECWDataset::ECW2WKTProjection()
@@ -3133,6 +3339,7 @@ void GDALRegister_ECW()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ECW" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
 
         CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
 
@@ -3232,6 +3439,8 @@ void GDALRegister_JP2ECW()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JP2ECW" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
 
         CPLString osLongName = "ERDAS JPEG2000 (SDK ";
 
@@ -3250,6 +3459,13 @@ void GDALRegister_JP2ECW()
         
         poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
         poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionList>"
+"   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' description='Whether a 1-bit alpha channel should be promoted to 8-bit' default='YES'/>"
+"   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether to load remote vector layers referenced by a link in a GMLJP2 v2 box' default='NO'/>"
+"</OpenOptionList>" );
+
 #ifdef HAVE_COMPRESS
         poDriver->pfnCreate = ECWCreateJPEG2000;
         poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
@@ -3274,6 +3490,7 @@ void GDALRegister_JP2ECW()
 
 "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
 "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
+"   <Option name='GMLJP2V2_DEF' type='string' description='Definition file to describe how a GMLJP2 v2 box should be generated. If set to YES, a minimal instance will be created'/>"
 "   <Option name='PROFILE' type='string-select'>"
 "       <Value>BASELINE_0</Value>"
 "       <Value>BASELINE_1</Value>"
@@ -3297,6 +3514,8 @@ void GDALRegister_JP2ECW()
 "   <Option name='INCLUDE_EPH' type='boolean'/>"
 "   <Option name='DECOMPRESS_LAYERS' type='int'/>"
 "   <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
+"   <Option name='WRITE_METADATA' type='boolean' description='Whether metadata should be written, in a dedicated JP2 XML box' default='NO'/>"
+"   <Option name='MAIN_MD_DOMAIN_ONLY' type='boolean' description='(Only if WRITE_METADATA=YES) Whether only metadata from the main domain should be written' default='NO'/>"
 "</CreationOptionList>" );
 #endif
 
diff --git a/frmts/ecw/frmt_ecw.html b/frmts/ecw/frmt_ecw.html
index 028a4a8..cc7ffd8 100644
--- a/frmts/ecw/frmt_ecw.html
+++ b/frmts/ecw/frmt_ecw.html
@@ -1,88 +1,33 @@
 <html>
 <head>
-<title>ECW -- ERDAS Compress Wavelets (.ecw)</title>
+<title>ECW -- Enhanced Compressed Wavelets (.ecw)</title>
 </head>
 
 <body bgcolor="#ffffff">
 
-<h1>ECW -- ERDAS Compress Wavelets (.ecw)</h1>
+<h1>ECW -- Enhanced Compressed Wavelets (.ecw)</h1>
 
-GDAL supports .ecw format for read access and write.  The current 
-implementation reads any number of bands but returns only as eight bit
-image data.  Coordinate system and georeferencing transformations are read,
-but in some cases coordinate systems may not translate.<p>
+GDAL supports reading and writing ECW files using the ERDAS ECW/JP2 SDK developed by 
+Hexagon Geospatial (formerly Intergraph, ERDAS, ERMapper). Support is optional and 
+requires linking in the libraries available from the ECW/JP2 SDK Download page.<p>
 
-Support for the ECW driver in GDAL is optional, and requires linking
-in external ECW SDK libraries provided by Intergraph (previously ERDAS).<p>
+<h3>Licensing</h3>
 
-In addition to ECW files, this driver also supports access to network
-image services using the "ECWP" protocol.  Use the full ecwp:// url of 
-the service as the dataset name.  When built with SDK 4.1 or newer it
-is also possible to take advantage of 
-<a href="http://trac.osgeo.org/gdal/wiki/rfc24_progressive_data_support">
-RFC 24</a> style asynchronous access to ECWP services.<p>
-
-Starting with GDAL 1.9.0, XMP metadata can be extracted from JPEG2000 files, and will be
-stored as XML raw content in the xml:XMP metadata domain.<p>
-
-<h2>ECW metadata domain / Georeferencing update</h2>
-
-(Starting with GDAL 1.9.0)<p>
-
-The PROJ, DATUM and UNITS found in the ECW header are
-reported in the ECW metadata domain. They can also be set with the SetMetadataItem()
-method, in order to update the header information of an existing ECW file,
-opened in update mode, without modifying the imagery.<p>
-
-The geotransform and projection can also be modified with the SetGeoTransform()
-and SetProjection() methods. If the projection is set with SetProjection() and
-the PROJ, DATUM or UNITS with SetMetadataItem(), the later values will override the values
-built from the projection string.<p>
-
-<h2>ECW Version 3 Files</h2>
-(Starting with GDAL 1.10.0)<p>
-
-ECW 5.x SDK provides amended file format which allows to store data statistics, histograms,
-metadata, rpc metadata and supports UInt16 as band data type.
-
-Currently not everything is implemented: 
-<ul>
-
-<li><B>Statistics and Histograms</B> - full implementation for writing and reading. No ECW_OEM_KEY neccessary.
-<li><B>File Metadata</B> - read only support. Statistics will also be preserved/updated during CreateCopy.
-<li><B>RPC Metadata</B> - supported by file format, not supported by driver. 
-<li><B>Header Metadata</B> - written by SDK itself. Reported by gdalinfo. 
-</ul>
+The ERDAS ECW/JP2 SDK v5.x is available under multiple license types. For Desktop usage, decoding
+any sized ECW/JP2 image is made available free of charge. To compress, deploy on a Server platform, or decode 
+unlimited sized files on Mobile platforms a license must be purchased from Hexagon Geospatial.<p>
 
 
-<h3>File Metadata Keys: </h3>
-
+<h3>History</h3>
 <ul>
-<li>FILE_METADATA_ACQUISITION_DATE
-<li>FILE_METADATA_ACQUISITION_SENSOR_NAME
-<li>FILE_METADATA_ADDRESS
-<li>FILE_METADATA_AUTHOR
-<li>FILE_METADATA_CLASSIFICATION
-<li>FILE_METADATA_COMPANY - should be set to ECW_OEM_KEY
-<li>FILE_METADATA_COMPRESSION_SOFTWARE - updated during recompression
-<li>FILE_METADATA_COPYRIGHT
-<li>FILE_METADATA_EMAIL
-<li>FILE_METADATA_TELEPHONE
+<li>v3.x - Last release, 2006</li>
+<li>v4.x - Last release, 2012</li>
+<li>v5.x - Active development, 2013 - current</li>
 </ul>
 
-<h3>Following Header Metadata will be reported: </h3>
-<ul>
-<li>CLOCKWISE_ROTATION_DEG
-<li>COLORSPACE (reported for V2 files as well)
-<li>COMPRESSION_DATE
-<li>COMPRESSION_RATE_ACTUAL
-<li>COMPRESSION_RATE_TARGET (reported for V2 files as well)
-<li>VERSION (reported for V2 files as well)
-</ul>
-
-<h2>Creation Issues</h2>
+<h2>Creation Options</h2>
 
-The ECW 4.x SDK from ERDAS is only free for image decompression.  To 
+The ERDAS ECW/JP2 v4.x and v5.x SDK is only free for image decompression.  To 
 compress images it is necessary to build with the read/write SDK and to 
 provide an OEM licensing key at runtime which may be purchased from ERDAS.<p>
 
@@ -100,10 +45,23 @@ common coordinate systems are not mapped properly.  If you know the
 ECW name for the coordinate system you can force it to be set at
 creation time with the PROJ and DATUM creation options. <p>
 
-Creation Options:<p>
+ECW format does not support creation of overviews since the ECW format 
+is already considered to be optimized for "arbitrary overviews". <P>
+
+<h2>Creation Options:</h2>
 
 <ul>
 
+<li> <b>LARGE_OK=YES</b>: <i>(v3.x SDK only)</i> Allow compressing files larger than 500MB in accordance with EULA terms. Deprecated since v4.x and 
+replaced by ECW_ENCODE_KEY & ECW_ENCODE_COMPANY.<p>
+
+<li> <b>ECW_ENCODE_KEY=key</b>: <i>(v4.x SDK or higher)</i> Provide the OEM encoding key to unlock encoding capability
+up to the licensed gigapixel limit.  The key is is approximately 129 hex digits long. The Company and Key must match and must be re-generated with each minor release of the SDK.  It may also be provided globally as a configuration option.<p>
+
+<li> <b>ECW_ENCODE_COMPANY=name</b>: <i>(v4.x SDK or higher)</i> Provide the name of the company in the issued
+OEM key (see ECW_ENCODE_KEY).  The Company and Key must match and must be re-generated with each minor release of the SDK.  It may also be provided 
+globally as a configuration option.<p>
+
 <li> <b>TARGET=percent</b>: Set the target size reduction as a percentage of 
 the original.  If not provided defaults to 90% for greyscale images, and 95%
 for RGB images.<p>
@@ -117,29 +75,11 @@ Common examples are WGS84 or NAD83.<p>
 <li> <b>UNITS=name</b>: (GDAL >= 1.9.0) Name of the ECW projection units to use :
 METERS (default) or FEET (us-foot).<p>
 
-<li> <b>LARGE_OK=YES</b>: When built with the ECW 3.x SDK this option can be 
-set to allow compressing files larger than 500MB.  It is the users 
-responsibility to ensure that the licensing requirments for large file 
-compression are being adhered to.<p>
-
-<li> <b>ECW_ENCODE_KEY=key</b>: Provide the OEM encoding key purchased from 
-Erdas which permits encoding images.  The key is is approximately 129 hex 
-digits long.  It may also be provided globally as a configuration option.<p>
-
-<li> <b>ECW_ENCODE_COMPANY=name</b>: Provide the name of the company ERDAS
-issued the OEM encoding key (see ECW_ENCODE_KEY) to.  This must exactly match
-the name used by ERDAS in issuing the OEM key.  It may also be provided 
-globally as a configuration option.<p>
-
 <li> <b>ECW_FORMAT_VERSION=2/3</b>: (GDAL >= 1.10.0) When build with the ECW 5.x SDK this option can be set to  
-allow ECW Version 3 files to be created. This would allow to write UInt16 data type
-rasters (new feature of ECW Version 3 files) . Default is 2 which will write ECW Version 2 files.<p>
+allow ECW Version 3 files to be created. Default, 2 to retain widest compatibility.<p>
 
 </ul>
 
-ECW format does not support creation of overviews since the ECW format 
-is already considered to be optimized for "arbitrary overviews". <P>
-
 <h2> Configuration Options </h2>
 
 The ERDAS ECW SDK supports a variety of 
@@ -184,21 +124,73 @@ should be forgiving of errors in a file, trying to return as much data as is
 available.  Defaults to TRUE.  If set to FALSE an invalid file will result
 in an error.<p>
 
-<li> <b>ECW_ENCODE_KEY, ECW_ENCODE_COMPANY</b>: These values, as described
-in the creation options, may also be set as configuration options. See above.
-<p>
-
 </ul>
 
-<h2>See Also:</h2>
+<h3>ECW Version 3 Files</h3>
+(Starting with GDAL 1.10.0)<p>
+
+ECW 5.x SDK introduces a new file format version which,
+<ol>
+<li>Storage of data statistics, histograms, metadata, RPC information within the file header</li>
+<li>Support for UInt16 data type</li>
+<li>Ability to update regions within an existing ECW v3 file</li>
+<li>Introduces other space saving optimizations</li>
+</ol>
+
+Note: This version is not backward compatible and will fail to decode in v3.x or v4.x ECW/JP2 SDK's. The File VERSION Metadata will advertise whether the file is ECW v2 or ECW v3.
+
+<h3>ECWP</h3>
+In addition to local files, this driver also supports access to streaming network
+imagery services using the proprietary "ECWP" protocol from the ERDAS APOLLO product.  Use the full ecwp:// prefixed dataset url
+as input.  When built with ECW/JP2 SDK v4.1 or newer it
+is also possible to take advantage of 
+<a href="http://trac.osgeo.org/gdal/wiki/rfc24_progressive_data_support">
+RFC 24</a> for asynchronous / progressive streaming access to ECWP services.<p>
+
+<h3>Metadata / Georeferencing</h3>
+
+(Starting with GDAL 1.9.0)<p>
+
+The PROJ, DATUM and UNITS found in the ECW header are
+reported in the ECW metadata domain. They can also be set with the SetMetadataItem()
+method, in order to update the header information of an existing ECW file,
+opened in update mode, without modifying the imagery.<p>
+
+The geotransform and projection can also be modified with the SetGeoTransform()
+and SetProjection() methods. If the projection is set with SetProjection() and
+the PROJ, DATUM or UNITS with SetMetadataItem(), the later values will override the values
+built from the projection string.<p>
+
+<h3>File Metadata Keys: </h3>
 
 <ul>
-<li> Implemented in <tt>gdal/frmts/ecw</tt>.
+<li>FILE_METADATA_ACQUISITION_DATE
+<li>FILE_METADATA_ACQUISITION_SENSOR_NAME
+<li>FILE_METADATA_ADDRESS
+<li>FILE_METADATA_AUTHOR
+<li>FILE_METADATA_CLASSIFICATION
+<li>FILE_METADATA_COMPANY - should be set to ECW_ENCODE_COMPANY
+<li>FILE_METADATA_COMPRESSION_SOFTWARE - updated during recompression
+<li>FILE_METADATA_COPYRIGHT
+<li>FILE_METADATA_EMAIL
+<li>FILE_METADATA_TELEPHONE
+<li>CLOCKWISE_ROTATION_DEG
+<li>COLORSPACE 
+<li>COMPRESSION_DATE
+<li>COMPRESSION_RATE_ACTUAL
+<li>COMPRESSION_RATE_TARGET
+<li>VERSION 
+</ul>
 
-<li> ECW SDK available at <a href="http://geospatial.intergraph.com/products/other/ecw/ERDASECWJPEG2000SDK/Details.aspx">geospatial.intergraph.com</a>.
+<h2>See Also</h2>
 
-<li> <a href="http://trac.osgeo.org/gdal/wiki/ECW">GDAL ECW Build Hints</a>
+<ul>
+<li> Implemented as <tt>gdal/frmts/ecw/ecwdataset.cpp</tt>.<p>
 
+<li> ECW/JP2 SDK available at <a href="http://hexagongeospatial.com/products/data-management-compression/ecw/erdas-ecw-jp2-sdk">www.hexagongeospatial.com</a>
+<li> Further product information available in the <a href="http://hexagongeospatial.com/products/data-management-compression/ecw/erdas-ecw-jp2-sdk/literature">User Guide</a>
+<li> Support for non-GDAL specific issues should be directed to the <a href="https://sgisupport.intergraph.com/infocenter/index?page=forums&forum=507301383c17ef4e013d8dfa30c2007ef1">Hexagon Geospatial public forum</a>
+<li> <a href="http://trac.osgeo.org/gdal/wiki/ECW">GDAL ECW Build Hints</a>
 </ul>
 
 </body>
diff --git a/frmts/ecw/frmt_jp2ecw.html b/frmts/ecw/frmt_jp2ecw.html
index 2d0d08a..c4bd5a0 100644
--- a/frmts/ecw/frmt_jp2ecw.html
+++ b/frmts/ecw/frmt_jp2ecw.html
@@ -7,31 +7,56 @@
 
 <h1>JP2ECW -- ERDAS JPEG2000 (.jp2)</h1>
 
-GDAL supports reading and writing JPEG2000 files using the ECW SDK from 
-ERDAS.<p>
+GDAL supports reading and writing JPEG2000 files using the ERDAS ECW/JP2 SDK developed by 
+Hexagon Geospatial (formerly Intergraph, ERDAS, ERMapper). Support is optional and 
+requires linking in the libraries available from the ECW/JP2 SDK Download page.<p>
 
 Coordinate system and georeferencing transformations are read, and 
 some degree of support is included for GeoJP2 (tm) (GeoTIFF-in-JPEG2000), 
 ERDAS GML-in-JPEG2000, and the new GML-in-JPEG2000 specification developed
 at OGC. <p>
 
-Support for the JP2ECW driver in GDAL is optional, and requires linking
-in external ECW SDK libraries provided by ERDAS.<p>
+<h3>Licensing</h3>
 
-<h2>Creation Issues</h2>
+The ERDAS ECW/JP2 SDK v5.x is available under multiple license types. For Desktop usage, decoding
+any sized ECW/JP2 image is made available free of charge. To compress, deploy on a Server platform, or decode 
+unlimited sized files on Mobile platforms a license must be purchased from Hexagon Geospatial.<p>
 
-The ECW 4.x SDK from ERDAS is only free for image decompression.  To 
-compress images it is necessary to build with the read/write SDK and to 
-provide an OEM licensing key at runtime which may be purchased from ERDAS.<p>
 
-For those still using the ECW 3.3 SDK, images less than 500MB may be 
-compressed for free, while larger images require licensing from ERDAS.  See
-the licensing agreement and the LARGE_OK option.<p>
+<h3>History</h3>
+<ul>
+<li>v3.x - Last release, 2006</li>
+<li>v4.x - Last release, 2012</li>
+<li>v5.x - Active development, 2013 - current</li>
+</ul>
+
+<h2>Option Options</h2>
+
+(GDAL >= 2.0 )
+
+The following open option is available:
+<ul>
+<li><p><b>1BIT_ALPHA_PROMOTION=YES/NO</b>: Whether a 1-bit alpha channel should be promoted to 8-bit.
+Defaults to YES.</li>
+</ul>
+
+<h2>Creation Options:</h2>
 
-Creation Options:<p>
+Note: Only Licensing and compression target need to be specified. The ECW/JP2 SDK will default all other options to recommended settings based on the input characteristics.
+Changing other options can <i>substantially</i> impact decoding speed and compatibility with other JPEG2000 toolkits.
 
 <ul>
 
+<li> <b>LARGE_OK=YES</b>: <i>(v3.x SDK only)</i> Allow compressing files larger than 500MB in accordance with EULA terms. Deprecated since v4.x and 
+replaced by ECW_ENCODE_KEY & ECW_ENCODE_COMPANY.<p>
+
+<li> <b>ECW_ENCODE_KEY=key</b>: <i>(v4.x SDK or higher)</i> Provide the OEM encoding key to unlock encoding capability
+up to the licensed gigapixel limit.  The key is is approximately 129 hex digits long. The Company and Key must match and must be re-generated with each minor release of the SDK.  It may also be provided globally as a configuration option.<p>
+
+<li> <b>ECW_ENCODE_COMPANY=name</b>: <i>(v4.x SDK or higher)</i> Provide the name of the company in the issued
+OEM key (see ECW_ENCODE_KEY).  The Company and Key must match and must be re-generated with each minor release of the SDK.  It may also be provided 
+globally as a configuration option.<p>
+
 <li> <b>TARGET=percent</b>: Set the target size reduction as a percentage of 
 the original.  If not provided defaults to 75 for an 75% reduction.  TARGET=0 
 uses lossless compression.<p>
@@ -42,21 +67,20 @@ Common examples are NUTM11, or GEODETIC.<p>
 <li> <b>DATUM=name</b>: Name of the ECW datum string to use. 
 Common examples are WGS84 or NAD83.<p>
 
-<li> <b>LARGE_OK=YES</b>: When built with the ECW 3.x SDK this option can be 
-set to allow compressing files larger than 500MB.  It is the users 
-responsibility to ensure that the licensing requirments for large file 
-compression are being adhered to.<p>
-
-<li> <b>ECW_ENCODE_KEY=key</b>: Provide the OEM encoding key purchased from 
-Erdas which permits encoding images.  The key is is approximately 129 hex 
-digits long.  It may also be provided globally as a configuration option.<p>
-
-<li> <b>ECW_ENCODE_COMPANY=name</b>: Provide the name of the company ERDAS
-issued the OEM encoding key (see ECW_ENCODE_KEY) to.  This must exactly match
-the name used by ERDAS in issuing the OEM key.  It may also be provided 
-globally as a configuration option.<p>
-
-<li> <b>GMLJP2=YES/NO</b>: Indicates whether a GML box conforming to the OGC GML in JPEG2000 specification should be included in the file.  Defaults to YES.<p>
+<li> <b>GMLJP2=YES/NO</b>: Indicates whether a GML box
+conforming to the OGC GML in JPEG2000 specification should be included in the
+file. Unless GMLJP2V2_DEF is used, the version of the GMLJP2 box will be
+version 1. Defaults to YES.<p>
+
+<li> <b>GMLJP2V2_DEF=filename</b>: (Starting with GDAL 2.0) Indicates whether a GML box
+conforming to the <a href="http://docs.opengeospatial.org/is/08-085r4/08-085r4.html">
+OGC GML in JPEG2000, version 2</a> specification should be included in the
+file. <i>filename</i> must point to a file with a JSon content that defines how
+the GMLJP2 v2 box should be built. See <a href="frmt_jp2openjpeg.html#GMLJP2v2Def">
+GMLJP2v2 definition file section</a> in documentation of the JP2OpenJPEG driver
+for the syntax of the JSon configuration file.
+It is also possible to directly pass the JSon content inlined as a string.
+If filename is just set to YES, a minimal instance will be built.<p>
 
 <li> <b>GeoJP2=YES/NO</b>: Indicates whether a UUID/GeoTIFF box conforming to the GeoJP2 (GeoTIFF in JPEG2000) specification should be included in the file.  Defaults to YES.<p>
 
@@ -65,35 +89,67 @@ NPJE or EPJE.  Review the ECW SDK documentation for details on profile
 meanings.<p>
 
 <li> <b>PROGRESSION=LRCP/RLCP/RPCL</b>: Set the progression order with
-which the JPEG2000 codestream is written.<p>
+which the JPEG2000 codestream is written. (Default, RPCL)<p>
 
 <li> <b>CODESTREAM_ONLY=YES/NO</b>: If set to YES, only the compressed
-imagery code stream will be written.  If NO (the default) a JP2 package
+imagery code stream will be written.  If NO a JP2 package
 will be written around the code stream including a variety of meta
-information.<p>
-
-<li> <b>LEVELS=n</b>: See ECW SDK for details.<p>
-<li> <b>LAYERS=n</b>: See ECW SDK for details.<p>
-<li> <b>PRECINCT_WIDTH=n</b>: See ECW SDK for details.<p>
-<li> <b>PRECINCT_HEIGHT=n</b>: See ECW SDK for details.<p>
-<li> <b>TILE_WIDTH=n</b>: See ECW SDK for details.<p>
-<li> <b>TILE_HEIGHT=n</b>: See ECW SDK for details.<p>
-<li> <b>INCLUDE_SOP=YES/NO</b>: See ECW SDK for details.<p>
-<li> <b>INCLUDE_EPH=YES/NO</b>: See ECW SDK for details.<p>
-<li> <b>DECOMPRESS_LAYERS=n</b>: See ECW SDK for details.<p>
-<li> <b>DECOMPRESS_RECONSTRUCTION_PARAMETER=n</b>: See ECW SDK for details.<p>
+information. (Default, NO)<p>
+
+    
+<li> <b>LEVELS=n</b>: Resolution levels in pyramid (by default so many that the size of the smallest thumbnail image is 64x64 pixels at maximum)<p>
+<li> <b>LAYERS=n</b>: Quality layers (default, 1)<p>
+<li> <b>PRECINCT_WIDTH=n</b>: Precinct Width (default, 64)<p>
+<li> <b>PRECINCT_HEIGHT=n</b>: Precinct Height (default 64)<p>
+<li> <b>TILE_WIDTH=n</b>: Tile Width (default, image width eg. 1 tile). Apart from GeoTIFF, in JPEG2000 tiling is not critical for speed if precincts are used. The minimum tile size allowed by the standard is 1024x1024 pixels.<p>
+<li> <b>TILE_HEIGHT=n</b>: Tile Height (default, image height eg. 1 tile)<p>
+<li> <b>INCLUDE_SOP=YES/NO</b>: Output Start of Packet Marker (default false)<p>
+<li> <b>INCLUDE_EPH=YES/NO</b>: Output End of Packet Header Marker (default true)<p>
+<li> <b>DECOMPRESS_LAYERS=n</b>: The number of quality layers to decode<p>
+<li> <b>DECOMPRESS_RECONSTRUCTION_PARAMETER=n</b>: IRREVERSIBLE_9x7 or REVERSIBLE_5x3<p>
+
+<li><p><b>WRITE_METADATA=YES/NO</b>: (GDAL >= 2.0) Whether metadata should be
+written, in a dedicated JP2 XML box. Defaults to NO.
+The content of the XML box will be like:
+<pre>
+<GDALMultiDomainMetadata>
+  <Metadata>
+    <MDI key="foo">bar</MDI>
+  </Metadata>
+  <Metadata domain='aux_domain'>
+    <MDI key="foo">bar</MDI>
+  </Metadata>
+  <Metadata domain='a_xml_domain' format='xml'>
+    <arbitrary_xml_content>
+    </arbitrary_xml_content>
+  </Metadata>
+</GDALMultiDomainMetadata>
+</pre>
+If there are metadata domain whose name starts with "xml:BOX_", they will be
+written each as separate JP2 XML box.<p>
+If there is a metadata domain whose name is "xml:XMP", its content will be
+written as a JP2 UUID XMP box.
+</p></li>
+
+<li><p><b>MAIN_MD_DOMAIN_ONLY=YES/NO</b>: (GDAL >= 2.0)
+(Only if WRITE_METADATA=YES) Whether only metadata from the main domain should
+be written. Defaults to NO.
+</p></li>
 
 </ul>
 
-JPEG2000 format does not support creation of overviews since the format 
-is already considered to be optimized for "arbitrary overviews". <P>
+"JPEG2000 format does not support creation of GDAL overviews since the format 
+is already considered to be optimized for "arbitrary overviews". 
+JP2ECW driver also arranges JP2 codestream to allow optimal access to power of two overviews. 
+This is controlled with the creation option LEVELS." 
+<P>
 
 <h2> Configuration Options </h2>
 
-The ERDAS ECW SDK supports a variety of 
+The ERDAS ECW/JP2 SDK supports a variety of 
 <a href="http://trac.osgeo.org/gdal/wiki/ConfigOptions">runtime configuration 
 options</a> to control various features.  Most of these are exposed as GDAL 
-configuration options.  See the ECW SDK documentation for full details on the
+configuration options.  See the ECW/JP2 SDK documentation for full details on the
 meaning of these options. 
 
 <ul>
@@ -119,11 +175,34 @@ should be forgiving of errors in a file, trying to return as much data as is
 available.  Defaults to TRUE.  If set to FALSE an invalid file will result
 in an error.<p>
 
-<li> <b>ECW_ENCODE_KEY, ECW_ENCODE_COMPANY</b>: These values, as described
-in the creation options, may also be set as configuration options. See above.
-<p>
+</ul>
+
+<h2>Metadata</h2>
 
+Starting with GDAL 1.11.0, XMP metadata can be extracted from JPEG2000 files, and will be
+stored as XML raw content in the xml:XMP metadata domain.<p>
 
+ECW/JP2 SDK v5.1+ also advertises JPEG2000 structural information as generic File Metadata reported under "JPEG2000" metadata domain (-mdd): </p>
+<ul>
+<li><b>ALL_COMMENTS</b>: Generic comment text field</li><p>
+<li><b>PROFILE</b>: Profile type (0,1,2). Refer to ECW/JP2 SDK documentation for more info</li><p>
+<li><b>TILES_X</b>: Number of tiles on X (horizontal) Axis</li><p>
+<li><b>TILES_Y</b>: Number of tiles on Y (vertical) Axis</li><p>
+<li><b>TILE_WIDTH</b>: Tile size on X Axis</li><p>
+<li><b>TILE_HEIGHT</b>: Tile size on Y Axis</li><p>
+<li><b>PRECINCT_SIZE_X</b>: Precinct size for each resolution level (smallest to largest) on X Axis</li><p>
+<li><b>PRECINCT_SIZE_Y</b>: Precinct size for each resolution level (smallest to largest) on Y Axis</li><p>
+<li><b>CODE_BLOCK_SIZE_X</b>: Code block size on X Axis</li><p>
+<li><b>CODE_BLOCK_SIZE_Y</b>: Code block size on Y Axis</li><p>
+<li><b>PRECISION</b>: Precision / Bit-depth of each component eg. 8,8,8 for 8bit 3 band imagery.</li><p>
+<li><b>RESOLUTION_LEVELS</b>: Number of resolution levels</li><p>
+<li><b>QUALITY_LAYERS</b>: Number of quality layers</li><p>
+<li><b>PROGRESSION_ORDER</b>: Progression order (RPCL, LRCP, CPRL, RLCP)</li><p>
+<li><b>TRANSFORMATION_TYPE</b>: Filter transformation used (9x7, 5x3)</li><p>
+<li><b>USE_SOP</b>: Start of Packet marker detected (TRUE/FALSE)</li><p>
+<li><b>USE_EPH</b>: End of Packet header marker detected (TRUE/FALSE)</li><p>
+<li><b>GML_JP2_DATA</b>: OGC GML GeoReferencing box detected (TRUE/FALSE)</li><p>
+<li><b>COMPRESSION_RATE_TARGET</b>: Target compression rate used on encoding</li><p>
 </ul>
 
 <h2>See Also</h2>
@@ -131,8 +210,9 @@ in the creation options, may also be set as configuration options. See above.
 <ul>
 <li> Implemented as <tt>gdal/frmts/ecw/ecwdataset.cpp</tt>.<p>
 
-<li> ECW SDK available at <a href="http://www.erdas.com/products/ERDASECWJPEG2000SDK/Details.aspx">erdas.com</a>.
-
+<li> ECW/JP2 SDK available at <a href="http://hexagongeospatial.com/products/data-management-compression/ecw/erdas-ecw-jp2-sdk">www.hexagongeospatial.com</a>
+<li> Further product information available in the <a href="http://hexagongeospatial.com/products/data-management-compression/ecw/erdas-ecw-jp2-sdk/literature">User Guide</a>
+<li> Support for non-GDAL specific issues should be directed to the <a href="https://sgisupport.intergraph.com/infocenter/index?page=forums&forum=507301383c17ef4e013d8dfa30c2007ef1">Hexagon Geospatial public forum</a>
 <li> <a href="http://trac.osgeo.org/gdal/wiki/ECW">GDAL ECW Build Hints</a>
 </ul>
 
diff --git a/frmts/ecw/gdal_ecw.h b/frmts/ecw/gdal_ecw.h
index 4a90c11..99c3b18 100644
--- a/frmts/ecw/gdal_ecw.h
+++ b/frmts/ecw/gdal_ecw.h
@@ -73,12 +73,15 @@
 
 #if ECWSDK_VERSION < 40
 
-#if !defined(NO_COMPRESS)
+#if !defined(NO_COMPRESS) && !defined(HAVE_COMPRESS)
 #  define HAVE_COMPRESS
 #endif
 
 #else
     #if ECWSDK_VERSION>=50
+		#if ECWSDK_VERSION>=51
+			#define JPEG2000_DOMAIN_NAME "JPEG2000"
+		#endif
         #include <NCSECWHeaderEditor.h>
         #include "NCSEcw/SDK/Box.h"
     #else 
@@ -411,7 +414,7 @@ class ECWAsyncReader : public GDALAsyncReader
 {
 private:
     CNCSJP2FileView *poFileView;
-    void            *hMutex;
+    CPLMutex        *hMutex;
     int              bUsingCustomStream;
 
     int              bUpdateReady;
@@ -489,7 +492,10 @@ class CPL_DLL ECWDataset : public GDALJP2AbstractDataset
     void        CleanupWindow();
     int         TryWinRasterIO( GDALRWFlag, int, int, int, int,
                                 GByte *, int, int, GDALDataType,
-                                int, int *, int, int, int );
+                                int, int *,
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GSpacing nBandSpace,
+                                GDALRasterIOExtraArg* psExtraArg );
     CPLErr      LoadNextLine();
 
 #if ECWSDK_VERSION>=50
@@ -533,11 +539,13 @@ class CPL_DLL ECWDataset : public GDALJP2AbstractDataset
     CPLErr ReadBands(void * pData, int nBufXSize, int nBufYSize,
                     GDALDataType eBufType, 
                     int nBandCount,
-                    int nPixelSpace, int nLineSpace, int nBandSpace);
+                    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                    GDALRasterIOExtraArg* psExtraArg);
     CPLErr ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
                     GDALDataType eBufType, 
                     int nBandCount,
-                    int nPixelSpace, int nLineSpace, int nBandSpace);
+                    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                    GDALRasterIOExtraArg* psExtraArg);
   public:
         ECWDataset(int bIsJPEG2000);
         ~ECWDataset();
@@ -552,7 +560,10 @@ class CPL_DLL ECWDataset : public GDALJP2AbstractDataset
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     virtual char      **GetMetadataDomainList();
     virtual const char *GetMetadataItem( const char * pszName,
@@ -625,16 +636,18 @@ class ECWRasterBand : public GDALPamRasterBand
 //#if !defined(SDK_CAN_DO_SUPERSAMPLING)
     CPLErr OldIRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 //#endif
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
   public:
 
-                   ECWRasterBand( ECWDataset *, int, int = -1 );
+                   ECWRasterBand( ECWDataset *, int, int iOverview, char** papszOpenOptions );
                    ~ECWRasterBand();
 
     virtual CPLErr IReadBlock( int, int, void * );
@@ -651,11 +664,11 @@ class ECWRasterBand : public GDALPamRasterBand
 #if ECWSDK_VERSION >= 50
     void GetBandIndexAndCountForStatistics(int &bandIndex, int &bandCount);
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                    int *pnBuckets, int ** ppanHistogram,
+                                    int *pnBuckets, GUIntBig ** ppanHistogram,
                                     int bForce,
                                     GDALProgressFunc, void *pProgressData);
     virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int *panHistogram );
+                                        int nBuckets, GUIntBig *panHistogram );
     virtual double GetMinimum( int* pbSuccess );
     virtual double GetMaximum( int* pbSuccess );
     virtual CPLErr GetStatistics( int bApproxOK, int bForce,
diff --git a/frmts/ecw/jp2userbox.cpp b/frmts/ecw/jp2userbox.cpp
index c24651e..913164b 100644
--- a/frmts/ecw/jp2userbox.cpp
+++ b/frmts/ecw/jp2userbox.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jp2userbox.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: jp2userbox.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GDAL ECW Driver
  * Purpose:  JP2UserBox implementation - arbitrary box read/write.
@@ -29,7 +29,7 @@
 
 #include "gdal_ecw.h"
 
-CPL_CVSID("$Id: jp2userbox.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: jp2userbox.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #if defined(HAVE_COMPRESS)
 
diff --git a/frmts/ecw/lookup.py b/frmts/ecw/lookup.py
index fab16e9..69f6c5b 100644
--- a/frmts/ecw/lookup.py
+++ b/frmts/ecw/lookup.py
@@ -1,24 +1,24 @@
 #******************************************************************************
-#  $Id: lookup.py 10957 2007-03-13 18:59:03Z warmerdam $
-# 
+#  $Id: lookup.py 27632 2014-09-04 17:56:16Z goatbar $
+#
 #  Project:  GDAL ECW Driver
 #  Purpose:  Script to lookup ECW (GDT) coordinate systems and translate
-#            into OGC WKT for storage in $GDAL_HOME/data/ecw_cs.dat.
+#            into OGC WKT for storage in $GDAL_HOME/data/ecw_cs.wkt.
 #  Author:   Frank Warmerdam, warmerdam at pobox.com
-# 
+#
 #******************************************************************************
 #  Copyright (c) 2003, 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
@@ -27,17 +27,6 @@
 #  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 #  DEALINGS IN THE SOFTWARE.
 #******************************************************************************
-# 
-# $Log$
-# Revision 1.3  2006/09/05 01:23:38  fwarmerdam
-# do not alter linear projection parameter units (bug 1280)
-#
-# Revision 1.2  2006/04/03 01:46:18  fwarmerdam
-# Added somenew projections
-#
-# Revision 1.1  2003/06/19 17:53:34  warmerda
-# New
-#
 
 import string
 import sys
diff --git a/frmts/elas/GNUmakefile b/frmts/elas/GNUmakefile
index a60e044..5aa7258 100644
--- a/frmts/elas/GNUmakefile
+++ b/frmts/elas/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	elasdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/elas/elasdataset.cpp b/frmts/elas/elasdataset.cpp
index e622fcd..38a10ec 100644
--- a/frmts/elas/elasdataset.cpp
+++ b/frmts/elas/elasdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: elasdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: elasdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  ELAS Translator
  * Purpose:  Complete implementation of ELAS translator module for GDAL.
@@ -30,7 +30,7 @@
 
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: elasdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: elasdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_ELAS(void);
@@ -153,9 +153,9 @@ ELASRasterBand::ELASRasterBand( ELASDataset *poDS, int nBand )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr ELASRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr ELASRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void * pImage )
-
 {
     ELASDataset	*poGDS = (ELASDataset *) poDS;
     CPLErr		eErr = CE_None;
@@ -188,9 +188,9 @@ CPLErr ELASRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 /*                            IWriteBlock()                             */
 /************************************************************************/
 
-CPLErr ELASRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                     void * pImage )
-
+CPLErr ELASRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,
+                                    int nBlockYOff,
+                                    void * pImage )
 {
     ELASDataset	*poGDS = (ELASDataset *) poDS;
     CPLErr		eErr = CE_None;
@@ -453,7 +453,7 @@ GDALDataset *ELASDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -672,6 +672,7 @@ void GDALRegister_ELAS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ELAS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ELAS" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
diff --git a/frmts/envisat/EnvisatFile.c b/frmts/envisat/EnvisatFile.c
index 3b8a93c..a1d064d 100644
--- a/frmts/envisat/EnvisatFile.c
+++ b/frmts/envisat/EnvisatFile.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: EnvisatFile.c 27731 2014-09-24 07:58:14Z rouault $
+ * $Id: EnvisatFile.c 28843 2015-04-02 21:13:08Z kyle $
  *
  * Project:  APP ENVISAT Support
  * Purpose:  Low Level Envisat file access (read/write) API.
@@ -28,12 +28,14 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
+#include "cpl_string.h"
+
 #ifndef APP_BUILD
 #  define GDAL_BUILD
 #  include "cpl_conv.h"
 #  include "EnvisatFile.h"
 
-CPL_CVSID("$Id: EnvisatFile.c 27731 2014-09-24 07:58:14Z rouault $");
+CPL_CVSID("$Id: EnvisatFile.c 28843 2015-04-02 21:13:08Z kyle $");
 
 #else
 #  include "APP/app.h"
@@ -76,7 +78,6 @@ struct EnvisatFile_tag
 
     int		ds_count;
     EnvisatDatasetInfo **ds_info;
-    
 };
 
 #ifdef GDAL_BUILD
@@ -145,7 +146,7 @@ static int EnvisatFile_SetupLevel0( EnvisatFile *self )
     self->dsd_offset = 0;
     self->ds_count = 1;
     self->ds_info = (EnvisatDatasetInfo **) 
-        calloc(sizeof(EnvisatDatasetInfo*),self->ds_count);
+        CPLCalloc(sizeof(EnvisatDatasetInfo*),self->ds_count);
 
     if( self->ds_info == NULL )
         return FAILURE;
@@ -174,11 +175,11 @@ static int EnvisatFile_SetupLevel0( EnvisatFile *self )
     /* 
      * Then build the dataset into structure from that. 
      */
-    ds_info = (EnvisatDatasetInfo *) calloc(sizeof(EnvisatDatasetInfo),1);
+    ds_info = (EnvisatDatasetInfo *) CPLCalloc(sizeof(EnvisatDatasetInfo),1);
     
-    ds_info->ds_name = strdup( "ASAR SOURCE PACKETS         " );
-    ds_info->ds_type = strdup( "M" );
-    ds_info->filename = strdup( "                                                              " );
+    ds_info->ds_name = CPLStrdup( "ASAR SOURCE PACKETS         " );
+    ds_info->ds_type = CPLStrdup("M");
+    ds_info->filename = CPLStrdup("                                                              ");
     ds_info->ds_offset = 3203;
     ds_info->dsr_size = -1;
     ds_info->num_dsr = 0;
@@ -260,12 +261,12 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
     /*
      * Create, and initialize the EnvisatFile structure. 
      */
-    self = (EnvisatFile *) calloc(sizeof(EnvisatFile),1);
+    self = (EnvisatFile *) CPLCalloc(sizeof(EnvisatFile),1);
     if( self == NULL )
         return FAILURE;
 
     self->fp = fp;
-    self->filename = strdup( filename );
+    self->filename = CPLStrdup(filename);
     self->header_dirty = 0;
     self->updatable = (strcmp(mode,"rb+") == 0);
 
@@ -275,7 +276,7 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
 
     if( VSIFReadL( mph_data, 1, MPH_SIZE, fp ) != MPH_SIZE )
     {
-        free( self );
+        CPLFree( self );
         SendError( "VSIFReadL() for mph failed." );
         return FAILURE;
     }
@@ -318,13 +319,13 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
         return FAILURE;
     }
 
-    sph_data = (char *) malloc(sph_size + 1 );
+    sph_data = (char *) CPLMalloc(sph_size + 1 );
     if( sph_data == NULL )
         return FAILURE;
 
     if( (int) VSIFReadL( sph_data, 1, sph_size, fp ) != sph_size )
     {
-        free( self );
+        CPLFree( self );
         SendError( "VSIFReadL() for sph failed." );
         return FAILURE;
     }
@@ -355,7 +356,7 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
     }
 
     self->ds_info = (EnvisatDatasetInfo **) 
-        calloc(sizeof(EnvisatDatasetInfo*),num_dsd);
+        CPLCalloc(sizeof(EnvisatDatasetInfo*),num_dsd);
     if( self->ds_info == NULL )
         return FAILURE;
 
@@ -379,15 +380,15 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
         /* 
          * Then build the dataset into structure from that. 
          */
-        ds_info = (EnvisatDatasetInfo *) calloc(sizeof(EnvisatDatasetInfo),1);
+        ds_info = (EnvisatDatasetInfo *) CPLCalloc(sizeof(EnvisatDatasetInfo),1);
 
-        ds_info->ds_name = strdup( 
+        ds_info->ds_name = CPLStrdup(
             S_NameValueList_FindValue( "DS_NAME", 
                                        dsdh_count, dsdh_entries, "" ));
-        ds_info->ds_type = strdup( 
+        ds_info->ds_type = CPLStrdup(
             S_NameValueList_FindValue( "DS_TYPE", 
                                        dsdh_count, dsdh_entries, "" ));
-        ds_info->filename = strdup( 
+        ds_info->filename = CPLStrdup(
             S_NameValueList_FindValue( "FILENAME", 
                                        dsdh_count, dsdh_entries, "" ));
         ds_info->ds_offset = atoi(
@@ -409,7 +410,7 @@ int EnvisatFile_Open( EnvisatFile **self_ptr,
         self->ds_count++;
     }
     
-    free( sph_data );
+    CPLFree( sph_data );
 
     /*
      * Return successfully.
@@ -471,7 +472,7 @@ int EnvisatFile_Create( EnvisatFile **self_ptr,
     VSIFSeekL( fp, 0, SEEK_END );
     template_size = (int) VSIFTellL( fp );
 
-    template_data = (char *) malloc(template_size);
+    template_data = (char *) CPLMalloc(template_size);
     
     VSIFSeekL( fp, 0, SEEK_SET );
     VSIFReadL( template_data, template_size, 1, fp );
@@ -497,7 +498,7 @@ int EnvisatFile_Create( EnvisatFile **self_ptr,
     VSIFWriteL( template_data, template_size, 1, fp );
     VSIFCloseL( fp );
 
-    free( template_data );
+    CPLFree( template_data );
 
     /*
      * Now just open the file normally. 
@@ -602,7 +603,7 @@ static int EnvisatFile_RewriteHeader( EnvisatFile *self )
         int	dsdh_count = 0, key_index;
         EnvisatNameValue **dsdh_entries = NULL;
 
-        dsd_text = (char *) calloc(1,dsd_size+1);
+        dsd_text = (char *) CPLCalloc(1,dsd_size+1);
         if( VSIFSeekL( self->fp, self->dsd_offset + dsd * dsd_size, 
                    SEEK_SET ) != 0 )
         {
@@ -620,7 +621,7 @@ static int EnvisatFile_RewriteHeader( EnvisatFile *self )
                                    &dsdh_count, &dsdh_entries ) == FAILURE )
             return FAILURE;
 
-        free( dsd_text );
+        CPLFree( dsd_text );
 
         key_index = S_NameValueList_FindKey( "DS_OFFSET", 
                                              dsdh_count, dsdh_entries );
@@ -704,18 +705,18 @@ void EnvisatFile_Close( EnvisatFile *self )
     {
         if( self->ds_info != NULL && self->ds_info[i] != NULL )
         {
-            free( self->ds_info[i]->ds_name );
-            free( self->ds_info[i]->ds_type );
-            free( self->ds_info[i]->filename );
-            free( self->ds_info[i] );
+            CPLFree( self->ds_info[i]->ds_name );
+            CPLFree( self->ds_info[i]->ds_type );
+            CPLFree( self->ds_info[i]->filename );
+            CPLFree( self->ds_info[i] );
         }
     }
     if( self->ds_info != NULL )
-        free( self->ds_info );
+        CPLFree( self->ds_info );
     if( self->filename != NULL )
-        free( self->filename );
+        CPLFree( self->filename );
 
-    free( self );
+    CPLFree( self );
 }
 
 /*-----------------------------------------------------------------------------
@@ -1171,7 +1172,7 @@ int EnvisatFile_SetKeyValueAsDouble( EnvisatFile *self,
         }
 
         sprintf( format, "%%+0%d.%df", length, decimals );
-        sprintf( string_value, format, value );
+        CPLsprintf( string_value, format, value );
 
         if( (int)strlen(string_value) > length )
             string_value[length] = '\0';
@@ -1204,33 +1205,33 @@ Returns:
 -----------------------------------------------------------------------------*/
 
 int EnvisatFile_GetDatasetIndex( EnvisatFile *self, const char *ds_name )
+
 {
+    int		i;
     char	padded_ds_name[100];
-    size_t i;
-    int ii;
 
-    /* 
+    /*
      * Padd the name.  While the normal product spec says the DS_NAME will
      * be 28 characters, I try to pad more than this incase the specification
-     * is changed. 
+     * is changed.
      */
     strncpy( padded_ds_name, ds_name, sizeof(padded_ds_name) );
     padded_ds_name[sizeof(padded_ds_name)-1] = 0;
-    for( i = strlen(padded_ds_name); i < sizeof(padded_ds_name)-1; i++ )
+    for( i = strlen(padded_ds_name); (size_t)i < sizeof(padded_ds_name)-1; i++ )
     {
         padded_ds_name[i] = ' ';
     }
     padded_ds_name[i] = '\0';
 
-    /* 
+    /*
      * Compare only for the full length of DS_NAME we have saved.
      */
-    for( ii = 0; ii < self->ds_count; ii++ )
+    for( i = 0; i < self->ds_count; i++ )
     {
-        if( strncmp( padded_ds_name, self->ds_info[ii]->ds_name, 
-                     strlen(self->ds_info[ii]->ds_name) ) == 0 )
+        if( strncmp( padded_ds_name, self->ds_info[i]->ds_name, 
+                     strlen(self->ds_info[i]->ds_name) ) == 0 )
         {
-            return ii;
+            return i;
         }
     }
 
@@ -1739,7 +1740,7 @@ int S_NameValueList_Parse( const char *text, int text_offset,
         line_offset = (int) (next_text - text) + text_offset;
         while( *next_text != '\0' && *next_text != '\n' )
         {
-          if( (size_t)line_len > sizeof(line)-1 )
+          if( line_len > ((int)sizeof(line) - 1) )
             {
                 SendError( "S_NameValueList_Parse(): "
                            "Corrupt line, longer than 1024 characters." );
@@ -1764,8 +1765,8 @@ int S_NameValueList_Parse( const char *text, int text_offset,
         /*
          * Create the name/value info structure. 
          */
-        entry = (EnvisatNameValue *) calloc(sizeof(EnvisatNameValue),1);
-        entry->literal_line = strdup(line);
+        entry = (EnvisatNameValue *) CPLCalloc(sizeof(EnvisatNameValue),1);
+        entry->literal_line = CPLStrdup(line);
 
         /*
          * Capture the key.  We take everything up to the equal sign.  There
@@ -1773,7 +1774,7 @@ int S_NameValueList_Parse( const char *text, int text_offset,
          * key.
          */
         equal_index = strstr(line, "=") - line;
-        entry->key = (char *) malloc(equal_index+1);
+        entry->key = (char *) CPLMalloc(equal_index+1);
         strncpy( entry->key, line, equal_index );
         entry->key[equal_index] = '\0';
         entry->value_offset = line_offset + equal_index + 1;
@@ -1789,7 +1790,7 @@ int S_NameValueList_Parse( const char *text, int text_offset,
                  src_char++ ) {}
 
             line[src_char] = '\0';
-            entry->value = strdup( line + equal_index + 2 );
+            entry->value = CPLStrdup(line + equal_index + 2);
             entry->value_offset += 1;
         }
 
@@ -1813,11 +1814,11 @@ int S_NameValueList_Parse( const char *text, int text_offset,
                      dst_char++ ) {}
 
                 line[dst_char] = '\0';
-                entry->units = strdup( line + src_char + 1 );
+                entry->units = CPLStrdup( line + src_char + 1 );
             }
 
             line[src_char] = '\0';
-            entry->value = strdup( line + equal_index + 1 );
+            entry->value = CPLStrdup( line + equal_index + 1 );
         }
 
         /*
@@ -1825,7 +1826,7 @@ int S_NameValueList_Parse( const char *text, int text_offset,
          */
         (*entry_count)++;
         *entries = (EnvisatNameValue **)
-            realloc( *entries, *entry_count * sizeof(EnvisatNameValue*) );
+            CPLRealloc( *entries, *entry_count * sizeof(EnvisatNameValue*) );
 
         if( *entries == NULL )
         {
@@ -1921,18 +1922,17 @@ void S_NameValueList_Destroy( int *entry_count,
 
     for( i = 0; i < *entry_count; i++ )
     {
-        free( (*entries)[i]->key );
-        free( (*entries)[i]->value );
-        free( (*entries)[i]->units );
-        free( (*entries)[i]->literal_line );
-        free( (*entries)[i] );
+        CPLFree( (*entries)[i]->key );
+        CPLFree( (*entries)[i]->value );
+        CPLFree( (*entries)[i]->units );
+        CPLFree( (*entries)[i]->literal_line );
+        CPLFree( (*entries)[i] );
     }
 
-    free( *entries );
+    CPLFree( *entries );
     
     *entry_count = 0;
     *entries = NULL;
 }
 
 /* EOF */
-
diff --git a/frmts/envisat/GNUmakefile b/frmts/envisat/GNUmakefile
index 5006bbc..a073bea 100644
--- a/frmts/envisat/GNUmakefile
+++ b/frmts/envisat/GNUmakefile
@@ -5,7 +5,7 @@ include ../../GDALmake.opt
 
 XTRA_OPT =	-I../raw
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(XTRA_OPT) $(CPPFLAGS)
+CPPFLAGS	:=	 $(XTRA_OPT) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/envisat/envisatdataset.cpp b/frmts/envisat/envisatdataset.cpp
index f38dcd2..d9caec6 100644
--- a/frmts/envisat/envisatdataset.cpp
+++ b/frmts/envisat/envisatdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: envisatdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: envisatdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  APP ENVISAT Support
  * Purpose:  Reader for ENVISAT format image data.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: envisatdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: envisatdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 #include "EnvisatFile.h"
@@ -105,7 +105,8 @@ MerisL2FlagBand::~MerisL2FlagBand()
 /************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
-CPLErr MerisL2FlagBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr MerisL2FlagBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                    int nBlockYOff,
                                     void * pImage )
 {
     CPLAssert( nBlockXOff == 0 );
@@ -1181,6 +1182,7 @@ void GDALRegister_Envisat()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "ESAT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Envisat Image Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -1194,4 +1196,3 @@ void GDALRegister_Envisat()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/envisat/records.c b/frmts/envisat/records.c
index 9187834..f8a9263 100644
--- a/frmts/envisat/records.c
+++ b/frmts/envisat/records.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: records.c 27705 2014-09-21 14:13:36Z goatbar $
+ * $Id: records.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  APP ENVISAT Support
  * Purpose:  Low Level Envisat file access (read/write) API.
@@ -27,9 +27,10 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
+#include "cpl_string.h"
 #include "records.h"
 
-CPL_CVSID("$Id: records.c 27705 2014-09-21 14:13:36Z goatbar $");
+CPL_CVSID("$Id: records.c 27942 2014-11-11 00:57:41Z rouault $");
 
 /* --- ASAR record descriptors --------------------------------------------- */
 static const EnvisatFieldDescr ASAR_ANTENNA_ELEV_PATT_ADSR[] = {
@@ -1323,7 +1324,7 @@ CPLErr EnvisatFile_GetFieldAsString(const void *pRecord, int nRecLen,
 
                 if (i > 0)
                     szBuf[nOffset++] = ' ';
-                nOffset += sprintf(szBuf + nOffset, "%f", fValue);
+                nOffset += CPLsprintf(szBuf + nOffset, "%f", fValue);
             }
             break;
         case EDT_Float64:
@@ -1335,7 +1336,7 @@ CPLErr EnvisatFile_GetFieldAsString(const void *pRecord, int nRecLen,
 #endif
                 if (i > 0)
                     szBuf[nOffset++] = ' ';
-                nOffset += sprintf(szBuf + nOffset, "%f", dfValue);
+                nOffset += CPLsprintf(szBuf + nOffset, "%f", dfValue);
             }
             break;
 /*
@@ -1370,7 +1371,7 @@ CPLErr EnvisatFile_GetFieldAsString(const void *pRecord, int nRecLen,
 #endif
                 if (i > 0)
                     szBuf[nOffset++] = ' ';
-                nOffset += sprintf(szBuf + nOffset, "(%f, %f)", fReal, fImag);
+                nOffset += CPLsprintf(szBuf + nOffset, "(%f, %f)", fReal, fImag);
             }
             break;
         case EDT_CFloat64:
@@ -1384,7 +1385,7 @@ CPLErr EnvisatFile_GetFieldAsString(const void *pRecord, int nRecLen,
 #endif
                 if (i > 0)
                     szBuf[nOffset++] = ' ';
-                nOffset += sprintf(szBuf + nOffset, "(%f, %f)", dfReal, dfImag);
+                nOffset += CPLsprintf(szBuf + nOffset, "(%f, %f)", dfReal, dfImag);
             }
             break;
 */
diff --git a/frmts/epsilon/GNUmakefile b/frmts/epsilon/GNUmakefile
index 7657c1f..2bc8853 100644
--- a/frmts/epsilon/GNUmakefile
+++ b/frmts/epsilon/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	epsilondataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(EPSILON_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(EPSILON_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/epsilon/epsilondataset.cpp b/frmts/epsilon/epsilondataset.cpp
index 99fc6f2..4e58529 100644
--- a/frmts/epsilon/epsilondataset.cpp
+++ b/frmts/epsilon/epsilondataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: epsilondataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: epsilondataset.cpp 28738 2015-03-16 17:20:21Z rouault $
  *
  * Project:  GDAL Epsilon driver
  * Purpose:  Implement GDAL Epsilon support using Epsilon library
@@ -30,7 +30,7 @@
 #include "epsilon.h"
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: epsilondataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: epsilondataset.cpp 28738 2015-03-16 17:20:21Z rouault $");
 
 #define RASTERLITE_WAVELET_HEADER "StartWaveletsImage$$"
 #define RASTERLITE_WAVELET_FOOTER "$$EndWaveletsImage"
@@ -683,7 +683,7 @@ GDALDataset* EpsilonDataset::Open(GDALOpenInfo* poOpenInfo)
 
 GDALDataset *
 EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                       int bStrict, char ** papszOptions, 
+                       CPL_UNUSED int bStrict, char ** papszOptions, 
                        GDALProgressFunc pfnProgress, void * pProgressData )
 {
     int nBands = poSrcDS->GetRasterCount();
@@ -777,7 +777,7 @@ EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         eResample = EPS_RESAMPLE_444;
     
     const char* pszTarget = CSLFetchNameValueDef(papszOptions, "TARGET", "96");
-    double dfReductionFactor = 1 - atof(pszTarget) / 100;
+    double dfReductionFactor = 1 - CPLAtof(pszTarget) / 100;
     if (dfReductionFactor > 1)
         dfReductionFactor = 1;
     else if (dfReductionFactor < 0)
@@ -789,7 +789,10 @@ EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     VSILFILE* fp = VSIFOpenL(pszFilename, "wb");
     if (fp == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s", pszFilename);
         return NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Compute number of blocks, block size, etc...                    */
@@ -886,7 +889,7 @@ EpsilonDatasetCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                               GDT_Byte, nBands, NULL,
                               1,
                               nBlockXSize,
-                              nBlockXSize * nBlockYSize);
+                              nBlockXSize * nBlockYSize, NULL);
             
             int nOutBufSize = nTargetBlockSize;
             if (eErr == CE_None && nBands == 1)
@@ -992,6 +995,7 @@ void GDALRegister_EPSILON()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "EPSILON" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Epsilon wavelets" );
diff --git a/frmts/ers/GNUmakefile b/frmts/ers/GNUmakefile
index ec0c4d3..7b6dbfb 100644
--- a/frmts/ers/GNUmakefile
+++ b/frmts/ers/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	ersdataset.o ershdrnode.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I../raw $(CPPFLAGS)
+CPPFLAGS	:=	 -I../raw $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ers/ersdataset.cpp b/frmts/ers/ersdataset.cpp
index 5738ffc..1da4234 100644
--- a/frmts/ers/ersdataset.cpp
+++ b/frmts/ers/ersdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ersdataset.cpp 27433 2014-06-04 19:21:16Z rouault $
+ * $Id: ersdataset.cpp 28474 2015-02-13 11:42:37Z rouault $
  *
  * Project:  ERMapper .ers Driver
  * Purpose:  Implementation of .ers driver.
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ershdrnode.h"
 
-CPL_CVSID("$Id: ersdataset.cpp 27433 2014-06-04 19:21:16Z rouault $");
+CPL_CVSID("$Id: ersdataset.cpp 28474 2015-02-13 11:42:37Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -70,9 +70,9 @@ class ERSDataset : public RawDataset
     int         bHasNoDataValue;
     double      dfNoDataValue;
 
-    CPLString      osProj;
-    CPLString      osDatum;
-    CPLString      osUnits;
+    CPLString      osProj, osProjForced;
+    CPLString      osDatum, osDatumForced;
+    CPLString      osUnits, osUnitsForced;
     void           WriteProjectionInfo(const char* pszProj,
                                        const char* pszDatum,
                                        const char* pszUnits);
@@ -437,9 +437,20 @@ CPLErr ERSDataset::SetProjection( const char *pszSRS )
 
     /* Write the above computed values, unless they have been overriden by */
     /* the creation options PROJ, DATUM or UNITS */
-    WriteProjectionInfo( (osProj.size()) ? osProj.c_str() : szERSProj,
-                         (osDatum.size()) ? osDatum.c_str() : szERSDatum,
-                         (osUnits.size()) ? osUnits.c_str() : szERSUnits );
+    if( osProjForced.size() )
+        osProj = osProjForced;
+    else
+        osProj = szERSProj;
+    if( osDatumForced.size() )
+        osDatum = osDatumForced;
+    else
+        osDatum = szERSDatum;
+    if( osUnitsForced.size() )
+        osUnits = osUnitsForced;
+    else
+        osUnits = szERSUnits;
+
+    WriteProjectionInfo( osProj, osDatum, osUnits );
 
     return CE_None;
 }
@@ -689,12 +700,12 @@ void ERSDataset::ReadGCPs()
 
         CPLFree( psGCP->pszId );
         psGCP->pszId = CPLStrdup(papszTokens[iGCP*nItemsPerLine+0]);
-        psGCP->dfGCPPixel = atof(papszTokens[iGCP*nItemsPerLine+3]);
-        psGCP->dfGCPLine  = atof(papszTokens[iGCP*nItemsPerLine+4]);
-        psGCP->dfGCPX     = atof(papszTokens[iGCP*nItemsPerLine+5]);
-        psGCP->dfGCPY     = atof(papszTokens[iGCP*nItemsPerLine+6]);
+        psGCP->dfGCPPixel = CPLAtof(papszTokens[iGCP*nItemsPerLine+3]);
+        psGCP->dfGCPLine  = CPLAtof(papszTokens[iGCP*nItemsPerLine+4]);
+        psGCP->dfGCPX     = CPLAtof(papszTokens[iGCP*nItemsPerLine+5]);
+        psGCP->dfGCPY     = CPLAtof(papszTokens[iGCP*nItemsPerLine+6]);
         if( nItemsPerLine == 8 )
-            psGCP->dfGCPZ = atof(papszTokens[iGCP*nItemsPerLine+7]);
+            psGCP->dfGCPZ = CPLAtof(papszTokens[iGCP*nItemsPerLine+7]);
     }
     
     CSLDestroy( papszTokens );
@@ -1410,13 +1421,13 @@ GDALDataset *ERSDataset::Create( const char * pszFilename,
 /* -------------------------------------------------------------------- */
     const char *pszDatum = CSLFetchNameValue( papszOptions, "DATUM" );
     if (pszDatum)
-        poDS->osDatum = pszDatum;
+        poDS->osDatumForced = poDS->osDatum = pszDatum;
     const char *pszProj = CSLFetchNameValue( papszOptions, "PROJ" );
     if (pszProj)
-        poDS->osProj = pszProj;
+        poDS->osProjForced = poDS->osProj = pszProj;
     const char *pszUnits = CSLFetchNameValue( papszOptions, "UNITS" );
     if (pszUnits)
-        poDS->osUnits = pszUnits;
+        poDS->osUnitsForced = poDS->osUnits = pszUnits;
 
     if (pszDatum || pszProj || pszUnits)
     {
@@ -1442,6 +1453,7 @@ void GDALRegister_ERS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ERS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ERMapper .ers Labelled" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/fit/GNUmakefile b/frmts/fit/GNUmakefile
index 5376160..d0055e5 100644
--- a/frmts/fit/GNUmakefile
+++ b/frmts/fit/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	fitdataset.o fit.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(XTRA_OPT) $(CPPFLAGS)
+CPPFLAGS	:=	 $(XTRA_OPT) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/fit/fitdataset.cpp b/frmts/fit/fitdataset.cpp
index feb78f2..9d9f4b6 100644
--- a/frmts/fit/fitdataset.cpp
+++ b/frmts/fit/fitdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fitdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: fitdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  FIT Driver
  * Purpose:  Implement FIT Support - not using the SGI iflFIT library.
@@ -33,7 +33,7 @@
 #include "gdal_pam.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: fitdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: fitdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
  
@@ -1069,7 +1069,7 @@ GDALDataset *FITDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return guard.take();
 }
@@ -1266,7 +1266,7 @@ static GDALDataset *FITCreateCopy(const char * pszFilename,
                                       firstBand->GetRasterDataType(),
                                       // eBufType
                                       bytesPerPixel, // nPixelSpace
-                                      bytesPerPixel * blockX); // nLineSpace
+                                      bytesPerPixel * blockX, NULL); // nLineSpace
                 if (eErr != CE_None)
                     CPLError(CE_Failure, CPLE_FileIO, 
                              "FIT write - CreateCopy got read error %i", eErr);
@@ -1319,9 +1319,9 @@ static GDALDataset *FITCreateCopy(const char * pszFilename,
     pfnProgress( 1.0, NULL, pProgressData );
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = (GDALPamDataset *) 
+    GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
@@ -1356,6 +1356,7 @@ void GDALRegister_FIT()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "FIT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "FIT Image" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/fits/GNUmakefile b/frmts/fits/GNUmakefile
index 93f2cc2..d14fce7 100644
--- a/frmts/fits/GNUmakefile
+++ b/frmts/fits/GNUmakefile
@@ -5,7 +5,7 @@ OBJ	=	fitsdataset.o
 
 FITS_OPTS	=	
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(FITS_OPTS) $(CPPFLAGS)
+CPPFLAGS	:=	 $(FITS_OPTS) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/fits/fitsdataset.cpp b/frmts/fits/fitsdataset.cpp
index 5f0e878..124e519 100644
--- a/frmts/fits/fitsdataset.cpp
+++ b/frmts/fits/fitsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fitsdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: fitsdataset.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  FITS Driver
  * Purpose:  Implement FITS raster read/write support
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include <string.h>
 
-CPL_CVSID("$Id: fitsdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: fitsdataset.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 CPL_C_START
 #include <fitsio.h>
@@ -281,9 +281,9 @@ FITSDataset::~FITSDataset() {
 	    // if you want finer control, use the underlying FITS
 	    // handle. Note: to avoid a compiler warning we copy the
 	    // const value string to a non const one...
-	    char* valueCpy = strdup(value);
+            char* valueCpy = CPLStrdup(value);
 	    fits_update_key_longstr(hFITS, key, valueCpy, 0, &status);
-	    free(valueCpy);
+	    CPLFree(valueCpy);
 
 	    // Check for errors
 	    if (status) {
@@ -510,7 +510,7 @@ GDALDataset* FITSDataset::Open(GDALOpenInfo* poOpenInfo) {
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-      dataset->oOvManager.Initialize( dataset, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+      dataset->oOvManager.Initialize( dataset, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
       return dataset;
   }
@@ -609,6 +609,7 @@ void GDALRegister_FITS() {
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "FITS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Flexible Image Transport System" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/formats_list.html b/frmts/formats_list.html
index b208c81..ac88c98 100644
--- a/frmts/formats_list.html
+++ b/frmts/formats_list.html
@@ -59,7 +59,7 @@
 </td><td> Yes
 </td></tr>
 
-<tr><td> <!--<a href="frmt_various.html#ARG"> -->Azavea Raster Grid<!-- </a> -->
+<tr><td> <a href="frmt_various.html#ARG">Azavea Raster Grid</a>
 </td><td> ARG
 </td><td> Yes
 </td><td> Yes
@@ -91,6 +91,14 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> BPG (Better Portable Graphics)</a>
+</td><td> BPG
+</td><td> No
+</td><td> No
+</td><td> ---
+</td><td> No, needs libbpg (manual build required for now)
+</td></tr>
+
 <tr><td> <a href="frmt_various.html#BSB">BSB Nautical Chart Format (.kap)</a>
 </td><td> BSB
 </td><td> No
@@ -323,6 +331,14 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> <a href="drv_geopackage_raster.html">GeoPackage</a>
+</td><td> GPKG
+</td><td> Yes
+</td><td> Yes
+</td><td> No limits
+</td><td> No, needs libsqlite3 (and any or all of PNG, JPEG, WEBP drivers)
+</td></tr>
+
 <tr><td> <a href="frmt_georaster.html">Oracle Spatial GeoRaster</a>
 </td><td> GEORASTER
 </td><td> Yes
@@ -603,6 +619,14 @@
 </td><td> No, needs Kakadu library
 </td></tr>
 
+<tr><td> <a href="frmt_kea.html">KEA</a>
+</td><td> KEA
+</td><td> Yes
+</td><td> Yes
+</td><td> --
+</td><td> No, needs libkea and libhdf5 libraries
+</td></tr>
+
 <tr><td> KMLSUPEROVERLAY
 </td><td> KMLSUPEROVERLAY
 </td><td> Yes
@@ -843,6 +867,14 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> <a href="frmt_plmosaic.html">Planet Labs Mosaics API</a>
+</td><td> PLMosaic
+</td><td> No
+</td><td> Yes
+</td><td> --
+</td><td> No, needs libcurl
+</td></tr>
+
 <tr><td> <a href="frmt_various.html#PNG">Portable Network Graphics (.png)</a>
 </td><td> PNG
 </td><td> Yes
@@ -907,6 +939,14 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> <a href="frmt_various.html#ROI_PAC">ROI_PAC Raster</a>
+</td><td> ROI_PAC
+</td><td> Yes
+</td><td> Yes
+</td><td> --
+</td><td> Yes
+</td></tr>
+
 <tr><td> <a href="frmt_various.html#RPFTOC">Raster Product Format/RPF (CADRG, CIB)</a>
 </td><td> RPFTOC
 </td><td> No
@@ -1027,7 +1067,15 @@
 </td><td> Yes
 </td></tr>
 
-<tr><td> <a href="http://www.gdal.org/gdal_vrttut.html">GDAL Virtual (.vrt)</a>
+<tr><td> <a href="http://www-mipl.jpl.nasa.gov/external/vicar.html">VICAR</a>
+</td><td> VICAR
+</td><td> No
+</td><td> Yes
+</td><td> --
+</td><td> Yes
+</td></tr>
+
+<tr><td> <a href="gdal_vrttut.html">GDAL Virtual (.vrt)</a>
 </td><td> VRT
 </td><td> Yes
 </td><td> Yes
@@ -1099,7 +1147,7 @@
 </p>
 
 <p>
-$Id: formats_list.html 26905 2014-01-30 21:08:06Z rouault $
+$Id: formats_list.html 28859 2015-04-07 08:40:10Z rouault $
 </p>
 
 </body>
diff --git a/frmts/frmt_various.html b/frmts/frmt_various.html
index 963506c..759091b 100644
--- a/frmts/frmt_various.html
+++ b/frmts/frmt_various.html
@@ -112,6 +112,17 @@ limited.  Additional sample prj.adf files may be sent to the maintainer,
 
 <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 
+<h2><a name="ARG">ARG -- Azavea Raster Grid</a></h2>
+
+<p>Driver implementation for a raw format that is used in 
+<a href="http://geotrellis.io/">GeoTrellis</a> and called ARG. 
+<a href="http://geotrellis.io/documentation/0.9.0/geotrellis/io/arg/">ARG format 
+specification</a>. Format is essentially a raw format, with a companion .JSON file.</p>
+
+<p>NOTE: Implemented as <tt>gdal/frmts/arg/argdataset.cpp</tt>.</p>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
 <h2><a name="BSB">BSB -- Maptech/NOAA BSB Nautical Chart Format</a></h2>
 
 <p>BSB Nautical Chart format is supported for read access, including reading 
@@ -287,7 +298,7 @@ unlabelled DOQ (Digital Ortho Quad) format from the USGS.</p>
 <h2><a name="DOQ2">DOQ2 -- New Labelled USGS DOQ</a></h2>
 
 <p>Support for read access, including reading of an affine georeferencing 
-transform, capture of the projection string and reading of other auxilary
+transform, capture of the projection string and reading of other auxiliary
 fields as metadata.   This format is the new,
 labelled DOQ (Digital Ortho Quad) format from the USGS.</p>
 
@@ -815,7 +826,7 @@ Description</a></p>
 <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 
 <h2><a name="PCRaster">PCRaster raster file format</a></h2>
-<p>GDAL includes support for reading and writing PCRaster raster files. PCRaster is a dynamic modelling system for distributed simulation models. The main applications of PCRaster are found in environmental modelling: geography, hydrology, ecology to name a few. Examples include rainfall-runoff models, vegetation competition models and slope stability models.</p>
+<p>GDAL includes support for reading and writing PCRaster raster files. PCRaster is a dynamic modelling system for distributed simulation models. The main applications of PCRaster are found in environmental modelling: geography, hydrology, ecology to name a few. Examples include models for research on global hydrology, vegetation competition models, slope stability models and land use change models.</p>
 
 <p>The driver reads all types of PCRaster maps: booleans, nominal, ordinals, scalar, directional and ldd. The same cell representation used to store values in the file is used to store the values in memory.</p>
 
@@ -914,7 +925,7 @@ Description</a></p>
 
 <p>NOTE: Implemented as <tt>gdal/frmts/pcraster/pcrasterdataset.cpp</tt>.</p>
 
-<p>See also: <a href="http://pcraster.geog.uu.nl">PCRaster website at Utrecht University</a> and <a href="http://www.pcraster.nl">PCRaster Environmental Software company website</a>.</p>
+<p>See also: <a href="http://pcraster.geo.uu.nl">PCRaster website at Utrecht University</a>.</p>
 
 <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 
@@ -972,6 +983,12 @@ details.</li>
 The default is 6.  A value of 1 is fast but does no compression, and a value
 of 9 is slow but does the best compression.</li>
 
+<li> <b>TITLE=value</b>: Title, written in a TEXT or iTXt chunk (GDAL >= 2.0 )</li>
+<li> <b>DESCRIPTION=value</b>: Description, written in a TEXT or iTXt chunk (GDAL >= 2.0 )</li>
+<li> <b>COPYRIGHT=value</b>: Copyright, written in a TEXT or iTXt chunk (GDAL >= 2.0 )</li>
+<li> <b>COMMENT=value</b>: Comment, written in a TEXT or iTXt chunk (GDAL >= 2.0 )</li>
+<li> <b>WRITE_METADATA_AS_TEXT=YES/NO</b>: Whether to write source dataset metadata in TEXT chunks (GDAL >= 2.0 )</li>
+
 </ul>
 
 <p>NOTE: Implemented as <tt>gdal/frmts/png/pngdataset.cpp</tt>.</p> 
@@ -1003,6 +1020,25 @@ software which is not liberal to this value.</li>
 
 <!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
 
+<h2><a name="ROI_PAC">ROI_PAC</a></h2>
+
+<p>Driver for the image formats used in the JPL's ROI_PAC 
+project (<a href="https://aws.roipac.org/">https://aws.roipac.org/</a>).
+All image type are supported excepted .raw images.</p>
+
+<p>Metadata are stored in the ROI_PAC domain.</p>
+
+<p>Georeferencing is supported, but expect problems when using the UTM 
+projection, as ROI_PAC format do not store any hemisphere field.</p>
+
+<p>When creating files, you have to be able to specify the right data type
+corresponding to the file type (slc, int, etc), else the driver will output
+an error.</p>
+
+<p>NOTE: Implemented as <tt>gdal/frmts/raw/roipacdataset.cpp</tt>.</p>
+
+<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
+
 <h2><a name="RPFTOC">Raster Product Format/RPF (a.toc)</a></h2>
 
 <p>This is a read-only reader for RPF products, like CADRG or CIB, that uses the table of
@@ -1325,7 +1361,7 @@ as reported by GDAL will be a half-pixel at the top and left of the values that
 </p>
 
 <p>
-$Id: frmt_various.html 27110 2014-03-28 21:29:20Z rouault $
+$Id: frmt_various.html 28861 2015-04-07 09:41:29Z kdejong $
 </p>
 
 </body>
diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp
index c01300e..e03cad0 100644
--- a/frmts/gdalallregister.cpp
+++ b/frmts/gdalallregister.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalallregister.cpp 27196 2014-04-16 11:41:24Z rouault $
+ * $Id: gdalallregister.cpp 28859 2015-04-07 08:40:10Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALAllRegister(), primary format registration.
@@ -30,8 +30,9 @@
 
 #include "gdal_priv.h"
 #include "gdal_frmts.h"
+#include "ogrsf_frmts.h"
 
-CPL_CVSID("$Id: gdalallregister.cpp 27196 2014-04-16 11:41:24Z rouault $");
+CPL_CVSID("$Id: gdalallregister.cpp 28859 2015-04-07 08:40:10Z rouault $");
 
 #ifdef notdef
 // we may have a use for this some day
@@ -48,25 +49,8 @@ static char *szConfiguredFormats = "GDAL_FORMATS";
  * Register all known configured GDAL drivers.
  *
  * This function will drive any of the following that are configured into
- * GDAL.  Many others as well haven't been updated in this
- * documentation (see <a href="http://gdal.org/formats_list.html">full list</a>):
- *
- * <ul>
- * <li> GeoTIFF (GTiff)
- * <li> Geosoft GXF (GXF)
- * <li> Erdas Imagine (HFA)
- * <li> CEOS (CEOS)
- * <li> ELAS (ELAS)
- * <li> Arc/Info Binary Grid (AIGrid)
- * <li> SDTS Raster DEM (SDTS)
- * <li> OGDI (OGDI)
- * <li> ESRI Labelled BIL (EHdr)
- * <li> PCI .aux Labelled Raw Raster (PAux)
- * <li> HDF4 Hierachal Data Format Release 4
- * <li> HDF5 Hierachal Data Format Release 5
- * <li> GSAG Golden Software ASCII Grid
- * <li> GSBG Golden Software Binary Grid
- * </ul>
+ * GDAL.  See <a href="http://gdal.org/formats_list.html">raster list</a> and
+ * <a href="http://gdal.org/ogr/ogr_formats.html">vector full list</a>
  *
  * This function should generally be called once at the beginning of the application.
  */
@@ -247,6 +231,7 @@ void CPL_STDCALL GDALAllRegister()
     GDALRegister_ISIS3();
     GDALRegister_ISIS2();
     GDALRegister_PDS();
+    GDALRegister_VICAR();
 #endif
 
 #ifdef FRMT_til
@@ -401,6 +386,7 @@ void CPL_STDCALL GDALAllRegister()
     GDALRegister_ACE2();
     GDALRegister_SNODAS();
     GDALRegister_KRO();
+    GDALRegister_ROIPAC();
 #endif
 
 #ifdef FRMT_arg
@@ -432,8 +418,9 @@ void CPL_STDCALL GDALAllRegister()
     GDALRegister_DODS();
 #endif
 
-#ifdef FRMT_wcs
-    GDALRegister_HTTP();
+/* Register KEA before HDF5 */
+#ifdef FRMT_kea
+    GDALRegister_KEA();
 #endif
 
 #ifdef FRMT_hdf5
@@ -531,8 +518,19 @@ void CPL_STDCALL GDALAllRegister()
 #ifdef FRMT_iris
     GDALRegister_IRIS();
 #endif
+
+#ifdef FRMT_plmosaic
+    GDALRegister_PLMOSAIC();
+#endif
+
+    OGRRegisterAllInternal();
+
+#ifdef FRMT_wcs
+    GDALRegister_HTTP();
+#endif
+    
 /* -------------------------------------------------------------------- */
-/*      Deregister any drivers explicitly marked as supressed by the    */
+/*      Deregister any drivers explicitly marked as suppressed by the   */
 /*      GDAL_SKIP environment variable.                                 */
 /* -------------------------------------------------------------------- */
     GetGDALDriverManager()->AutoSkipDrivers();
diff --git a/frmts/georaster/GNUmakefile b/frmts/georaster/GNUmakefile
index c65fa69..78d5d31 100644
--- a/frmts/georaster/GNUmakefile
+++ b/frmts/georaster/GNUmakefile
@@ -11,7 +11,7 @@ OBJ		=	georaster_dataset.o \
 			oci_wrapper.o \
 			georaster_wrapper.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(OCI_INCLUDE) $(CPPFLAGS) -fPIC
+CPPFLAGS	:=	$(GDAL_INCLUDE) $(XTRA_OPT)  $(OCI_INCLUDE) $(CPPFLAGS) -fPIC
 
 PLUGIN_SO	= gdal_GEOR.so
 
diff --git a/frmts/georaster/frmt_georaster.html b/frmts/georaster/frmt_georaster.html
index 21f715a..6f95498 100644
--- a/frmts/georaster/frmt_georaster.html
+++ b/frmts/georaster/frmt_georaster.html
@@ -117,7 +117,7 @@ the table, e.g.:</li>
 <span style="font-family: Courier New,Courier,monospace;">%
 gdal_translate -of georaster landsat_825.tif
 geor:scott/tiger at orcl,landsat,raster \<br>
-  -co INSERT="ID, RASTER VALUES (2,</span><span style="font-family: Courier New,Courier,monospace;"></span><span style="font-family: Courier New,Courier,monospace;">SDO_GEOR.INIT()</span><span style="font-family: Courier New,Courier,monospace;"></span><span style="font-family: Courier New,Courier,monospace;">)"</span><br>
+  -co INSERT="(ID, RASTER) VALUES (2,</span><span style="font-family: Courier New,Courier,monospace;"></span><span style="font-family: Courier New,Courier,monospace;">SDO_GEOR.INIT()</span><span style="font-family: Courier New,Courier,monospace;"></span><span style="font-family: Courier New,Courier,monospace;">)"</span><br>
 <ul>
   <li><strong>COMPRESS</strong>: Compression options, JPEG-F,
 DEFLATE or NONE. The two JPEG options are lossy, meaning that the
@@ -278,4 +278,4 @@ geor:scott/tiger at dbdemo,landsat,scene,id=54 view_54.vrt<br>
 <h3></h3>
 
 
-</body></html>
\ No newline at end of file
+</body></html>
diff --git a/frmts/georaster/georaster_dataset.cpp b/frmts/georaster/georaster_dataset.cpp
index 495ce2c..21ca864 100644
--- a/frmts/georaster/georaster_dataset.cpp
+++ b/frmts/georaster/georaster_dataset.cpp
@@ -7,7 +7,7 @@
  * Author:   Ivan Lucena [ivan.lucena at oracle.com]
  *
  ******************************************************************************
- * Copyright (c) 2008, Ivan Lucena
+ * Copyright (c) 2008, Ivan Lucena <ivan dot lucena at oracle dot com>
  * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -120,7 +120,7 @@ GDALDataset* GeoRasterDataset::Open( GDALOpenInfo* poOpenInfo )
     //  It shouldn't have an open file pointer
     //  -------------------------------------------------------------------
 
-    if( poOpenInfo->fp != NULL )
+    if( poOpenInfo->fpL != NULL )
     {
         return NULL;
     }
@@ -785,7 +785,6 @@ GDALDataset *GeoRasterDataset::Create( const char *pszFilename,
         poGRD->poGeoRaster->nCompressQuality = nQuality;
     }
 
-
     pszFetched = CSLFetchNameValue( papszOptions, "GENPYRAMID" );
 
     if( pszFetched != NULL )
@@ -1065,7 +1064,7 @@ GDALDataset *GeoRasterDataset::CreateCopy( const char* pszFilename,
                         nBlockCols, nBlockRows, pData,
                         nBlockCols, nBlockRows, eType,
                         nPixelSize,
-                        nPixelSize * nBlockXSize );
+                        nPixelSize * nBlockXSize, NULL );
 
                     if( eErr != CE_None )
                     {
@@ -1123,7 +1122,7 @@ GDALDataset *GeoRasterDataset::CreateCopy( const char* pszFilename,
                         nBlockCols, nBlockRows, pData,
                         nBlockCols, nBlockRows, eType,
                         nPixelSize,
-                        nPixelSize * nBlockXSize );
+                        nPixelSize * nBlockXSize, NULL );
 
                     if( eErr != CE_None )
                     {
@@ -1184,7 +1183,9 @@ CPLErr GeoRasterDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     void *pData, int nBufXSize, int nBufYSize,
                                     GDALDataType eBufType,
                                     int nBandCount, int *panBandMap,
-                                    int nPixelSpace, int nLineSpace, int nBandSpace )
+                                    GSpacing nPixelSpace, GSpacing nLineSpace,
+                                    GSpacing nBandSpace,
+                                    GDALRasterIOExtraArg* psExtraArg )
 
 {
     if( poGeoRaster->nBandBlockSize > 1 )
@@ -1193,7 +1194,7 @@ CPLErr GeoRasterDataset::IRasterIO( GDALRWFlag eRWFlag,
             nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType,
             nBandCount, panBandMap, nPixelSpace,
-            nLineSpace, nBandSpace );
+            nLineSpace, nBandSpace, psExtraArg );
     }
     else
     {
@@ -1201,7 +1202,7 @@ CPLErr GeoRasterDataset::IRasterIO( GDALRWFlag eRWFlag,
             nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType,
             nBandCount, panBandMap,
-            nPixelSpace, nLineSpace, nBandSpace );
+            nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     }
 }
 
@@ -1386,7 +1387,6 @@ const char* GeoRasterDataset::GetProjectionRef( void )
         else if ( EQUAL( pszProjName, "Lambert Conformal Conic" ) )
         {
             oSRS.SetProjection( SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP );
-            //?? One ot two parameters?
         }
         else if ( EQUAL( pszProjName, "Lambert Azimuthal Equal Area" ) )
         {
@@ -1507,47 +1507,286 @@ CPLErr GeoRasterDataset::SetProjection( const char *pszProjString )
         return CE_Failure;
     }
     
+    const char *pszProjName = poSRS2->GetAttrValue( "PROJECTION" );
+
+    if( pszProjName )
+    {
+        // ----------------------------------------------------------------
+        // Translate projection names to Oracle's standards
+        // ----------------------------------------------------------------
+
+        if ( EQUAL( pszProjName, SRS_PT_TRANSVERSE_MERCATOR ) )
+        {
+            poSRS2->SetProjection( "Transverse Mercator" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_ALBERS_CONIC_EQUAL_AREA ) )
+        {
+            poSRS2->SetProjection( "Albers Conical Equal Area" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_AZIMUTHAL_EQUIDISTANT ) )
+        {
+            poSRS2->SetProjection( "Azimuthal Equidistant" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_MILLER_CYLINDRICAL ) )
+        {
+            poSRS2->SetProjection( "Miller Cylindrical" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_HOTINE_OBLIQUE_MERCATOR ) )
+        {
+            poSRS2->SetProjection( "Hotine Oblique Mercator" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_WAGNER_IV ) )
+        {
+            poSRS2->SetProjection( "Wagner IV" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_WAGNER_VII ) )
+        {
+            poSRS2->SetProjection( "Wagner VII" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_ECKERT_IV ) )
+        {
+            poSRS2->SetProjection( "Eckert IV" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_ECKERT_VI ) )
+        {
+            poSRS2->SetProjection( "Eckert VI" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_NEW_ZEALAND_MAP_GRID ) )
+        {
+            poSRS2->SetProjection( "New Zealand Map Grid" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP ) )
+        {
+            poSRS2->SetProjection( "Lambert Conformal Conic" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA ) )
+        {
+            poSRS2->SetProjection( "Lambert Azimuthal Equal Area" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_VANDERGRINTEN ) )
+        {
+            poSRS2->SetProjection( "Van der Grinten" );
+        }
+        else if ( EQUAL(
+            pszProjName, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM ) )
+        {
+            poSRS2->SetProjection( "Lambert Conformal Conic (Belgium 1972)" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_CYLINDRICAL_EQUAL_AREA ) )
+        {
+            poSRS2->SetProjection( "Cylindrical Equal Area" );
+        }
+        else if ( EQUAL( pszProjName, SRS_PT_GOODE_HOMOLOSINE ) )
+        {
+            poSRS2->SetProjection( "Interrupted Goode Homolosine" );
+        }
+        
+        // ----------------------------------------------------------------
+        // Translate projection's parameters to Oracle's standards
+        // ----------------------------------------------------------------
+
+        char* pszStart = NULL;
+        
+        CPLFree( pszCloneWKT );       
+
+        if( poSRS2->exportToWkt( &pszCloneWKT ) != OGRERR_NONE )
+        {
+            delete poSRS2;
+            return CE_Failure;
+        }
+        
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_AZIMUTH) ) )
+        {
+            strncpy( pszStart, "Azimuth", strlen(SRS_PP_AZIMUTH) );
+        }
+
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_CENTRAL_MERIDIAN) ) )
+        {
+            strncpy( pszStart, "Central_Meridian", 
+                                        strlen(SRS_PP_CENTRAL_MERIDIAN) );
+        }
+
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_EASTING) ) )
+        {
+            strncpy( pszStart, "False_Easting", strlen(SRS_PP_FALSE_EASTING) );
+        }
+
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_FALSE_NORTHING) ) )
+        {
+            strncpy( pszStart, "False_Northing", 
+                                        strlen(SRS_PP_FALSE_NORTHING) );
+        }
+
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_CENTER) ) )
+        {
+            strncpy( pszStart, "Latitude_Of_Center", 
+                                        strlen(SRS_PP_LATITUDE_OF_CENTER) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LATITUDE_OF_ORIGIN) ) )
+        {
+            strncpy( pszStart, "Latitude_Of_Origin", 
+                                        strlen(SRS_PP_LATITUDE_OF_ORIGIN) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_LONGITUDE_OF_CENTER) ) )
+        {
+            strncpy( pszStart, "Longitude_Of_Center", 
+                                        strlen(SRS_PP_LONGITUDE_OF_CENTER) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_PSEUDO_STD_PARALLEL_1) ) )
+        {
+            strncpy( pszStart, "Pseudo_Standard_Parallel_1", 
+                                        strlen(SRS_PP_PSEUDO_STD_PARALLEL_1) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_SCALE_FACTOR) ) )
+        {
+            strncpy( pszStart, "Scale_Factor", strlen(SRS_PP_SCALE_FACTOR) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_1) ) )
+        {
+            strncpy( pszStart, "Standard_Parallel_1", 
+                                        strlen(SRS_PP_STANDARD_PARALLEL_1) );
+        }
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) )
+        {
+            strncpy( pszStart, "Standard_Parallel_2", 
+                                        strlen(SRS_PP_STANDARD_PARALLEL_2) );
+        }                
+                
+        if( ( pszStart = strstr(pszCloneWKT, SRS_PP_STANDARD_PARALLEL_2) ) )
+        {
+            strncpy( pszStart, "Standard_Parallel_2", 
+                                        strlen(SRS_PP_STANDARD_PARALLEL_2) );
+        }                
+        
+        // ----------------------------------------------------------------
+        // Fix Unit name
+        // ----------------------------------------------------------------
+        
+        if( ( pszStart = strstr(pszCloneWKT, "metre") ) )
+        {
+            strncpy( pszStart, SRS_UL_METER, strlen(SRS_UL_METER) );
+        }
+    }
+
     // --------------------------------------------------------------------
-    // Search by simplified WKT or insert it as a user defined
+    // Tries to find a SRID compatible with the WKT
     // --------------------------------------------------------------------
 
     OWConnection* poConnection  = poGeoRaster->poConnection;
     OWStatement* poStmt = NULL;
-    int nMaxSRID = 0;
+    
+    int nNewSRID = 0;    
+   
+    char *pszFuncName = "FIND_GEOG_CRS";
+  
+    if( poSRS2->IsProjected() )
+    {
+        pszFuncName = "FIND_PROJ_CRS";
+    }
+    
+    poStmt = poConnection->CreateStatement( CPLSPrintf(
+        "DECLARE\n"
+        "  LIST SDO_SRID_LIST;"
+        "BEGIN\n"
+        "  SELECT SDO_CS.%s('%s', null) into LIST FROM DUAL;\n"
+        "  IF LIST.COUNT() > 0 then\n"
+        "    SELECT LIST(1) into :out from dual;\n"
+        "  ELSE\n"
+        "    SELECT 0 into :out from dual;\n"
+        "  END IF;\n"
+        "END;",
+            pszFuncName,
+            pszCloneWKT ) );
+        
+    poStmt->BindName( ":out", &nNewSRID );
+
+    CPLPushErrorHandler( CPLQuietErrorHandler );
+
+    if( poStmt->Execute() )
+    {
+        CPLPopErrorHandler();
+
+        if ( nNewSRID > 0 )
+        {
+            poGeoRaster->SetGeoReference( nNewSRID );
+            CPLFree( pszCloneWKT );       
+            return CE_None;
+        }
+    }   
+
+    // --------------------------------------------------------------------
+    // Search by simplified WKT or insert it as a user defined SRS
+    // --------------------------------------------------------------------
+    
+    int nCounter = 0;
 
     poStmt = poConnection->CreateStatement( CPLSPrintf(
+        "SELECT COUNT(*) FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
+    
+    poStmt->Define( &nCounter );
+            
+    CPLPushErrorHandler( CPLQuietErrorHandler );
+
+    if( poStmt->Execute() && nCounter > 0 )
+    {    
+        poStmt = poConnection->CreateStatement( CPLSPrintf(
+            "SELECT SRID FROM MDSYS.CS_SRS WHERE WKTEXT = '%s'", pszCloneWKT));
+
+        poStmt->Define( &nNewSRID );
+
+        if( poStmt->Execute() )
+        {
+            CPLPopErrorHandler();
+            
+            poGeoRaster->SetGeoReference( nNewSRID );
+            CPLFree( pszCloneWKT );
+            return CE_None;
+        }    
+    }
+
+    CPLPopErrorHandler();
+    
+    poStmt = poConnection->CreateStatement( CPLSPrintf(
         "DECLARE\n"
         "  MAX_SRID NUMBER := 0;\n"
         "BEGIN\n"
-        "  SELECT SRID INTO MAX_SRID FROM MDSYS.CS_SRS WHERE WKTEXT = '%s';\n"
-        "  EXCEPTION\n"
-        "    WHEN no_data_found THEN\n"
-        "      SELECT MAX(SRID) INTO MAX_SRID FROM MDSYS.CS_SRS;\n"
-        "      MAX_SRID := MAX_SRID + 1;\n"
-        "      INSERT INTO MDSYS.CS_SRS (SRID, WKTEXT, CS_NAME)\n"
+        "  SELECT MAX(SRID) INTO MAX_SRID FROM MDSYS.CS_SRS;\n"
+        "  MAX_SRID := MAX_SRID + 1;\n"
+        "  INSERT INTO MDSYS.CS_SRS (SRID, WKTEXT, CS_NAME)\n"
         "        VALUES (MAX_SRID, '%s', '%s');\n"
+        "  SELECT MAX_SRID INTO :out FROM DUAL;\n"
         "END;",
             pszCloneWKT,
-            pszCloneWKT,
             oSRS.GetRoot()->GetChild(0)->GetValue() ) );
 
-    poStmt->Define( &nMaxSRID );
+    poStmt->BindName( ":out", &nNewSRID );
 
     CPLErr eError = CE_None;
 
+    CPLPushErrorHandler( CPLQuietErrorHandler );
+
     if( poStmt->Execute() )
     {
-        poGeoRaster->SetGeoReference( nMaxSRID ); //TODO change that method
-        poGeoRaster->sWKText = pszCloneWKT;
+        CPLPopErrorHandler();
+            
+        poGeoRaster->SetGeoReference( nNewSRID );
     }
     else
     {
+        CPLPopErrorHandler();
+            
         poGeoRaster->SetGeoReference( UNKNOWN_CRS );
-        poGeoRaster->sWKText = "";
 
         CPLError( CE_Warning, CPLE_UserInterrupt,
             "Insufficient privileges to insert reference system to "
-            "MDSYS.CS_SRS table." );
+            "table MDSYS.CS_SRS." );
+        
         eError = CE_Warning;
     }
 
@@ -2047,6 +2286,7 @@ void CPL_DLL GDALRegister_GEOR()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription(  "GeoRaster" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Oracle Spatial GeoRaster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_georaster.html" );
diff --git a/frmts/georaster/georaster_priv.h b/frmts/georaster/georaster_priv.h
index 41dd5a6..c74a64d 100644
--- a/frmts/georaster/georaster_priv.h
+++ b/frmts/georaster/georaster_priv.h
@@ -177,7 +177,9 @@ public:
                             void *pData, int nBufXSize, int nBufYSize, 
                             GDALDataType eBufType,
                             int nBandCount, int *panBandMap, 
-                            int nPixelSpace, int nLineSpace, int nBandSpace );
+                            GSpacing nPixelSpace, GSpacing nLineSpace,
+                            GSpacing nBandSpace,
+                            GDALRasterIOExtraArg* psExtraArg );
     virtual int         GetGCPCount() { return nGCPCount; }
     virtual const char* GetGCPProjection();
     virtual const GDAL_GCP*
@@ -195,6 +197,10 @@ public:
                             GDALProgressFunc pfnProgress,
                             void* pProgresoversData );
     virtual CPLErr      CreateMaskBand( int nFlags );
+    virtual OGRErr      StartTransaction(int bForce=FALSE) {return CE_None;};
+    virtual OGRErr      CommitTransaction() {return CE_None;};
+    virtual OGRErr      RollbackTransaction() {return CE_None;};
+    
     void                AssignGeoRaster( GeoRasterWrapper* poGRW );
 };
 
diff --git a/frmts/georaster/georaster_wrapper.cpp b/frmts/georaster/georaster_wrapper.cpp
index 8b8fece..9669f96 100644
--- a/frmts/georaster/georaster_wrapper.cpp
+++ b/frmts/georaster/georaster_wrapper.cpp
@@ -718,7 +718,7 @@ bool GeoRasterWrapper::Create( char* pszDescription,
     nBandBlockSize   = nBandBlockSize   == 0 ? 1 : nBandBlockSize;
 
     //  -----------------------------------------------------------
-    //  Blocking storage paramters
+    //  Blocking storage parameters
     //  -----------------------------------------------------------
 
     CPLString sBlocking;
@@ -789,7 +789,7 @@ bool GeoRasterWrapper::Create( char* pszDescription,
     }
 
     //  -----------------------------------------------------------
-    //  Complete format paramters
+    //  Complete format parameters
     //  -----------------------------------------------------------
 
     if( poConnection->GetVersion() > 10 )
diff --git a/frmts/gff/GNUmakefile b/frmts/gff/GNUmakefile
index ce24d30..2e4a360 100644
--- a/frmts/gff/GNUmakefile
+++ b/frmts/gff/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	gff_dataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/gff/gff_dataset.cpp b/frmts/gff/gff_dataset.cpp
index ec050b8..da0a520 100644
--- a/frmts/gff/gff_dataset.cpp
+++ b/frmts/gff/gff_dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gff_dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gff_dataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Ground-based SAR Applitcations Testbed File Format driver
  * Purpose:  Support in GDAL for Sandia National Laboratory's GFF format
@@ -36,7 +36,7 @@
 #include "cpl_vsi.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gff_dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gff_dataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /*******************************************************************
  * Declaration of the GFFDataset class                             *
@@ -137,8 +137,9 @@ GFFRasterBand::GFFRasterBand( GFFDataset *poDS, int nBand,
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GFFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void *pImage ) 
+CPLErr GFFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
+                                  void *pImage )
 {
     GFFDataset *poGDS = (GFFDataset *)poDS;
     long nOffset = poGDS->nLength;
@@ -338,6 +339,7 @@ void GDALRegister_GFF(void)
     if ( GDALGetDriverByName("GFF") == NULL ) {
         poDriver = new GDALDriver();
         poDriver->SetDescription("GFF");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 
                                   "Ground-based SAR Applications Testbed File Format (.gff)");
         poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_various.html#GFF");
diff --git a/frmts/gif/GNUmakefile b/frmts/gif/GNUmakefile
index d073ff5..d625298 100644
--- a/frmts/gif/GNUmakefile
+++ b/frmts/gif/GNUmakefile
@@ -10,7 +10,7 @@ else
 OBJ	=	gifdataset.o biggifdataset.o gifabstractdataset.o
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/gif/biggifdataset.cpp b/frmts/gif/biggifdataset.cpp
index aca3924..7f95a80 100644
--- a/frmts/gif/biggifdataset.cpp
+++ b/frmts/gif/biggifdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: biggifdataset.cpp 28278 2015-01-03 14:00:06Z rouault $
+ * $Id: biggifdataset.cpp 28279 2015-01-03 14:37:52Z rouault $
  *
  * Project:  BIGGIF Driver
  * Purpose:  Implement GDAL support for reading large GIF files in a 
@@ -34,17 +34,12 @@
 #include "cpl_string.h"
 #include "gifabstractdataset.h"
 
-CPL_CVSID("$Id: biggifdataset.cpp 28278 2015-01-03 14:00:06Z rouault $");
+CPL_CVSID("$Id: biggifdataset.cpp 28279 2015-01-03 14:37:52Z rouault $");
 
 CPL_C_START
 void	GDALRegister_BIGGIF(void);
 CPL_C_END
 
-static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
-static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
-
-static int VSIGIFReadFunc( GifFileType *, GifByteType *, int);
-
 /************************************************************************/
 /* ==================================================================== */
 /*                          BIGGIFDataset                               */
@@ -79,120 +74,34 @@ class BIGGIFDataset : public GIFAbstractDataset
 /* ==================================================================== */
 /************************************************************************/
 
-class BIGGifRasterBand : public GDALPamRasterBand
+class BIGGifRasterBand : public GIFAbstractRasterBand
 {
     friend class BIGGIFDataset;
 
-    int		*panInterlaceMap;
-    
-    GDALColorTable *poColorTable;
-
   public:
 
                    BIGGifRasterBand( BIGGIFDataset *, int );
-    virtual       ~BIGGifRasterBand();
 
     virtual CPLErr IReadBlock( int, int, void * );
-
-    virtual GDALColorInterp GetColorInterpretation();
-    virtual GDALColorTable *GetColorTable();
 };
 
 /************************************************************************/
 /*                          BIGGifRasterBand()                          */
 /************************************************************************/
 
-BIGGifRasterBand::BIGGifRasterBand( BIGGIFDataset *poDS, int nBackground )
+BIGGifRasterBand::BIGGifRasterBand( BIGGIFDataset *poDS, int nBackground ) :
+    GIFAbstractRasterBand(poDS, 1, poDS->hGifFile->SavedImages, nBackground, TRUE)
 
 {
-    SavedImage *psImage = poDS->hGifFile->SavedImages + 0;
-
-    this->poDS = poDS;
-    this->nBand = 1;
-
-    eDataType = GDT_Byte;
-
-    nBlockXSize = poDS->nRasterXSize;
-    nBlockYSize = 1;
-
-/* -------------------------------------------------------------------- */
-/*      Setup interlacing map if required.                              */
-/* -------------------------------------------------------------------- */
-    panInterlaceMap = NULL;
-    if( psImage->ImageDesc.Interlace )
-    {
-        int	i, j, iLine = 0;
-
-        poDS->SetMetadataItem( "INTERLACED", "YES", "IMAGE_STRUCTURE" );
-
-        panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
-
-	for (i = 0; i < 4; i++)
-        {
-	    for (j = InterlacedOffset[i]; 
-                 j < poDS->nRasterYSize;
-                 j += InterlacedJumps[i]) 
-                panInterlaceMap[j] = iLine++;
-        }
-    }
-    else
-        poDS->SetMetadataItem( "INTERLACED", "NO", "IMAGE_STRUCTURE" );
-
-/* -------------------------------------------------------------------- */
-/*      Setup colormap.                                                 */
-/* -------------------------------------------------------------------- */
-    ColorMapObject 	*psGifCT = psImage->ImageDesc.ColorMap;
-    if( psGifCT == NULL )
-        psGifCT = poDS->hGifFile->SColorMap;
-
-    poColorTable = new GDALColorTable();
-    for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
-    {
-        GDALColorEntry	oEntry;
-
-        oEntry.c1 = psGifCT->Colors[iColor].Red;
-        oEntry.c2 = psGifCT->Colors[iColor].Green;
-        oEntry.c3 = psGifCT->Colors[iColor].Blue;
-        oEntry.c4 = 255;
-
-        poColorTable->SetColorEntry( iColor, &oEntry );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      If we have a background value, return it here.  Some            */
-/*      applications might want to treat this as transparent, but in    */
-/*      many uses this is inappropriate so we don't return it as        */
-/*      nodata or transparent.                                          */
-/* -------------------------------------------------------------------- */
-    if( nBackground != 255 )
-    {
-        char szBackground[10];
-        
-        sprintf( szBackground, "%d", nBackground );
-        SetMetadataItem( "GIF_BACKGROUND", szBackground );
-    }
-}
-
-/************************************************************************/
-/*                           ~BIGGifRasterBand()                           */
-/************************************************************************/
-
-BIGGifRasterBand::~BIGGifRasterBand()
-
-{
-    if( poColorTable != NULL )
-        delete poColorTable;
-
-    CPLFree( panInterlaceMap );
 }
 
 /************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr BIGGifRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void * pImage )
-
+CPLErr BIGGifRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                     int nBlockYOff,
+                                     void * pImage )
 {
     BIGGIFDataset *poGDS = (BIGGIFDataset *) poDS;
 
@@ -209,7 +118,7 @@ CPLErr BIGGifRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
         return poGDS->poWorkDS->
             RasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1, 
                       pImage, nBlockXSize, 1, GDT_Byte, 
-                      1, NULL, 0, 0, 0 );
+                      1, NULL, 0, 0, 0, NULL );
     }
 
 /* -------------------------------------------------------------------- */
@@ -241,7 +150,7 @@ CPLErr BIGGifRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
             poGDS->poWorkDS->RasterIO( GF_Write, 
                                        0, poGDS->nLastLineRead, nBlockXSize, 1, 
                                        pImage, nBlockXSize, 1, GDT_Byte, 
-                                       1, NULL, 0, 0, 0 );
+                                       1, NULL, 0, 0, 0, NULL );
         }
     }
 
@@ -249,26 +158,6 @@ CPLErr BIGGifRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 }
 
 /************************************************************************/
-/*                       GetColorInterpretation()                       */
-/************************************************************************/
-
-GDALColorInterp BIGGifRasterBand::GetColorInterpretation()
-
-{
-    return GCI_PaletteIndex;
-}
-
-/************************************************************************/
-/*                           GetColorTable()                            */
-/************************************************************************/
-
-GDALColorTable *BIGGifRasterBand::GetColorTable()
-
-{
-    return poColorTable;
-}
-
-/************************************************************************/
 /* ==================================================================== */
 /*                             BIGGIFDataset                            */
 /* ==================================================================== */
@@ -373,7 +262,7 @@ CPLErr BIGGIFDataset::ReOpen()
     VSIFSeekL( fp, 0, SEEK_SET );
 
     nLastLineRead = -1;
-    hGifFile = GIFAbstractDataset::myDGifOpen( fp, VSIGIFReadFunc );
+    hGifFile = GIFAbstractDataset::myDGifOpen( fp, GIFAbstractDataset::ReadFunc );
     if( hGifFile == NULL )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -437,7 +326,7 @@ CPLErr BIGGIFDataset::ReOpen()
 GDALDataset *BIGGIFDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if( !Identify( poOpenInfo ) )
+    if( !Identify( poOpenInfo ) || poOpenInfo->fpL == NULL )
         return NULL;
 
     if( poOpenInfo->eAccess == GA_Update )
@@ -449,22 +338,14 @@ GDALDataset *BIGGIFDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
-/*      Open the file.                                                  */
-/* -------------------------------------------------------------------- */
-    VSILFILE                *fp;
-
-    fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
-    if( fp == NULL )
-        return NULL;
-
-/* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
 /* -------------------------------------------------------------------- */
     BIGGIFDataset 	*poDS;
 
     poDS = new BIGGIFDataset();
 
-    poDS->fp = fp;
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
     poDS->eAccess = GA_ReadOnly;
     if( poDS->ReOpen() == CE_Failure )
     {
@@ -502,31 +383,18 @@ GDALDataset *BIGGIFDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
-    poDS->TryLoadXML();
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Support overviews.                                              */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
+                                 poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
 
 /************************************************************************/
-/*                           VSIGIFReadFunc()                           */
-/*                                                                      */
-/*      Proxy function for reading from GIF file.                       */
-/************************************************************************/
-
-static int VSIGIFReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
-                           int nBytesToRead )
-
-{
-    return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
-                      (VSILFILE *) psGFile->UserData );
-}
-
-/************************************************************************/
 /*                        GDALRegister_BIGGIF()                         */
 /************************************************************************/
 
@@ -540,6 +408,7 @@ void GDALRegister_BIGGIF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "BIGGIF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Graphics Interchange Format (.gif)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -554,4 +423,3 @@ void GDALRegister_BIGGIF()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/gif/gifabstractdataset.cpp b/frmts/gif/gifabstractdataset.cpp
index 7fc4978..00723b0 100644
--- a/frmts/gif/gifabstractdataset.cpp
+++ b/frmts/gif/gifabstractdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gifabstractdataset.cpp 27459 2014-06-15 11:30:36Z rouault $
+ * $Id: gifabstractdataset.cpp 28283 2015-01-03 20:08:00Z rouault $
  *
  * Project:  GIF Driver
  * Purpose:  GIF Abstract Dataset
@@ -29,7 +29,10 @@
 
 #include "gifabstractdataset.h"
 
-CPL_CVSID("$Id: gifabstractdataset.cpp 27459 2014-06-15 11:30:36Z rouault $");
+CPL_CVSID("$Id: gifabstractdataset.cpp 28283 2015-01-03 20:08:00Z rouault $");
+
+static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
+static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
 
 /************************************************************************/
 /* ==================================================================== */
@@ -327,13 +330,13 @@ int GIFAbstractDataset::Identify( GDALOpenInfo * poOpenInfo )
 void GIFAbstractDataset::DetectGeoreferencing( GDALOpenInfo * poOpenInfo )
 {
     bGeoTransformValid =
-        GDALReadWorldFile( poOpenInfo->pszFilename, NULL,
-                           adfGeoTransform );
+        GDALReadWorldFile2( poOpenInfo->pszFilename, NULL,
+                           adfGeoTransform, poOpenInfo->GetSiblingFiles(), NULL );
     if ( !bGeoTransformValid )
     {
         bGeoTransformValid =
-            GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
-                               adfGeoTransform );
+            GDALReadWorldFile2( poOpenInfo->pszFilename, ".wld",
+                               adfGeoTransform, poOpenInfo->GetSiblingFiles(), NULL );
     }
 }
 
@@ -378,3 +381,177 @@ int GIFAbstractDataset::myEGifCloseFile( GifFileType *hGifFile )
     return EGifCloseFile( hGifFile );
 #endif
 }
+
+/************************************************************************/
+/*                           VSIGIFReadFunc()                           */
+/*                                                                      */
+/*      Proxy function for reading from GIF file.                       */
+/************************************************************************/
+
+int GIFAbstractDataset::ReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
+                                        int nBytesToRead )
+
+{
+    return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
+                      (VSILFILE *) psGFile->UserData );
+}
+
+/************************************************************************/
+/*                        GIFAbstractRasterBand()                       */
+/************************************************************************/
+
+GIFAbstractRasterBand::GIFAbstractRasterBand(
+                              GIFAbstractDataset *poDS, int nBand, 
+                              SavedImage *psSavedImage, int nBackground,
+                              int bAdvertizeInterlacedMDI )
+
+{
+    this->poDS = poDS;
+    this->nBand = nBand;
+
+    eDataType = GDT_Byte;
+
+    nBlockXSize = poDS->GetRasterXSize();
+    nBlockYSize = 1;
+
+    psImage = psSavedImage;
+
+    poColorTable = NULL;
+    panInterlaceMap = NULL;
+    nTransparentColor = 0;
+
+    if (psImage == NULL)
+        return;
+
+/* -------------------------------------------------------------------- */
+/*      Setup interlacing map if required.                              */
+/* -------------------------------------------------------------------- */
+    panInterlaceMap = NULL;
+    if( psImage->ImageDesc.Interlace )
+    {
+        int     i, j, iLine = 0;
+        
+        if( bAdvertizeInterlacedMDI )
+            poDS->SetMetadataItem( "INTERLACED", "YES", "IMAGE_STRUCTURE" );
+
+        panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
+
+        for (i = 0; i < 4; i++)
+        {
+            for (j = InterlacedOffset[i]; 
+                 j < poDS->nRasterYSize;
+                 j += InterlacedJumps[i]) 
+                panInterlaceMap[j] = iLine++;
+        }
+    }
+    else if( bAdvertizeInterlacedMDI )
+        poDS->SetMetadataItem( "INTERLACED", "NO", "IMAGE_STRUCTURE" );
+
+/* -------------------------------------------------------------------- */
+/*      Check for transparency.  We just take the first graphic         */
+/*      control extension block we find, if any.                        */
+/* -------------------------------------------------------------------- */
+    int iExtBlock;
+
+    nTransparentColor = -1;
+    for( iExtBlock = 0; iExtBlock < psImage->ExtensionBlockCount; iExtBlock++ )
+    {
+        unsigned char *pExtData;
+
+        if( psImage->ExtensionBlocks[iExtBlock].Function != 0xf9 ||
+            psImage->ExtensionBlocks[iExtBlock].ByteCount < 4 )
+            continue;
+
+        pExtData = (unsigned char *) psImage->ExtensionBlocks[iExtBlock].Bytes;
+
+        /* check if transparent color flag is set */
+        if( !(pExtData[0] & 0x1) )
+            continue;
+
+        nTransparentColor = pExtData[3];
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Setup colormap.                                                 */
+/* -------------------------------------------------------------------- */
+    ColorMapObject      *psGifCT = psImage->ImageDesc.ColorMap;
+    if( psGifCT == NULL )
+        psGifCT = poDS->hGifFile->SColorMap;
+
+    poColorTable = new GDALColorTable();
+    for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
+    {
+        GDALColorEntry  oEntry;
+
+        oEntry.c1 = psGifCT->Colors[iColor].Red;
+        oEntry.c2 = psGifCT->Colors[iColor].Green;
+        oEntry.c3 = psGifCT->Colors[iColor].Blue;
+
+        if( iColor == nTransparentColor )
+            oEntry.c4 = 0;
+        else
+            oEntry.c4 = 255;
+
+        poColorTable->SetColorEntry( iColor, &oEntry );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If we have a background value, return it here.  Some            */
+/*      applications might want to treat this as transparent, but in    */
+/*      many uses this is inappropriate so we don't return it as        */
+/*      nodata or transparent.                                          */
+/* -------------------------------------------------------------------- */
+    if( nBackground != 255 )
+    {
+        char szBackground[10];
+        
+        sprintf( szBackground, "%d", nBackground );
+        SetMetadataItem( "GIF_BACKGROUND", szBackground );
+    }
+}
+
+/************************************************************************/
+/*                       ~GIFAbstractRasterBand()                       */
+/************************************************************************/
+
+GIFAbstractRasterBand::~GIFAbstractRasterBand()
+
+{
+    if( poColorTable != NULL )
+        delete poColorTable;
+
+    CPLFree( panInterlaceMap );
+}
+
+/************************************************************************/
+/*                       GetColorInterpretation()                       */
+/************************************************************************/
+
+GDALColorInterp GIFAbstractRasterBand::GetColorInterpretation()
+
+{
+    return GCI_PaletteIndex;
+}
+
+/************************************************************************/
+/*                           GetColorTable()                            */
+/************************************************************************/
+
+GDALColorTable *GIFAbstractRasterBand::GetColorTable()
+
+{
+    return poColorTable;
+}
+
+/************************************************************************/
+/*                           GetNoDataValue()                           */
+/************************************************************************/
+
+double GIFAbstractRasterBand::GetNoDataValue( int *pbSuccess )
+
+{
+    if( pbSuccess != NULL )
+        *pbSuccess = nTransparentColor != -1;
+
+    return nTransparentColor;
+}
diff --git a/frmts/gif/gifabstractdataset.h b/frmts/gif/gifabstractdataset.h
index 30ad489..fe19512 100644
--- a/frmts/gif/gifabstractdataset.h
+++ b/frmts/gif/gifabstractdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gifabstractdataset.h 27459 2014-06-15 11:30:36Z rouault $
+ * $Id: gifabstractdataset.h 28279 2015-01-03 14:37:52Z rouault $
  *
  * Project:  GIF Driver
  * Purpose:  GIF Abstract Dataset
@@ -45,6 +45,8 @@ CPL_C_END
 class GIFAbstractDataset : public GDALPamDataset
 {
   protected:
+    friend class    GIFAbstractRasterBand;
+
     VSILFILE        *fp;
 
     GifFileType *hGifFile;
@@ -79,6 +81,37 @@ class GIFAbstractDataset : public GDALPamDataset
     static GifFileType* myDGifOpen( void *userPtr, InputFunc readFunc );
     static int          myDGifCloseFile( GifFileType *hGifFile );
     static int          myEGifCloseFile( GifFileType *hGifFile );
+    static int          ReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
+                                  int nBytesToRead );
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                        GIFAbstractRasterBand                         */
+/* ==================================================================== */
+/************************************************************************/
+
+class GIFAbstractRasterBand : public GDALPamRasterBand
+{
+  protected:
+    SavedImage  *psImage;
+
+    int         *panInterlaceMap;
+    
+    GDALColorTable *poColorTable;
+
+    int         nTransparentColor;
+
+  public:
+
+                   GIFAbstractRasterBand(GIFAbstractDataset *poDS, int nBand, 
+                                         SavedImage *psSavedImage, int nBackground,
+                                         int bAdvertizeInterlacedMDI );
+    virtual       ~GIFAbstractRasterBand();
+
+    virtual double GetNoDataValue( int *pbSuccess = NULL );
+    virtual GDALColorInterp GetColorInterpretation();
+    virtual GDALColorTable *GetColorTable();
 };
 
 
diff --git a/frmts/gif/gifdataset.cpp b/frmts/gif/gifdataset.cpp
index 4772cee..1483b2f 100644
--- a/frmts/gif/gifdataset.cpp
+++ b/frmts/gif/gifdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gifdataset.cpp 28284 2015-01-03 20:08:36Z rouault $
+ * $Id: gifdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  GIF Driver
  * Purpose:  Implement GDAL GIF Support using libungif code.  
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "gifabstractdataset.h"
 
-CPL_CVSID("$Id: gifdataset.cpp 28284 2015-01-03 20:08:36Z rouault $");
+CPL_CVSID("$Id: gifdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_GIF(void);
@@ -53,7 +53,6 @@ CPL_C_END
 static const int InterlacedOffset[] = { 0, 4, 2, 1 }; 
 static const int InterlacedJumps[] = { 8, 8, 4, 2 };  
 
-static int VSIGIFReadFunc( GifFileType *, GifByteType *, int);
 static int VSIGIFWriteFunc( GifFileType *, const GifByteType *, int );
 
 /************************************************************************/
@@ -87,28 +86,12 @@ class GIFDataset : public GIFAbstractDataset
 /* ==================================================================== */
 /************************************************************************/
 
-class GIFRasterBand : public GDALPamRasterBand
+class GIFRasterBand : public GIFAbstractRasterBand
 {
-    friend class GIFDataset;
-
-    SavedImage	*psImage;
-
-    int		*panInterlaceMap;
-    
-    GDALColorTable *poColorTable;
-
-    int		nTransparentColor;
-
   public:
 
                    GIFRasterBand( GIFDataset *, int, SavedImage *, int );
-    virtual       ~GIFRasterBand();
-
     virtual CPLErr IReadBlock( int, int, void * );
-
-    virtual double GetNoDataValue( int *pbSuccess = NULL );
-    virtual GDALColorInterp GetColorInterpretation();
-    virtual GDALColorTable *GetColorTable();
 };
 
 /************************************************************************/
@@ -116,128 +99,19 @@ class GIFRasterBand : public GDALPamRasterBand
 /************************************************************************/
 
 GIFRasterBand::GIFRasterBand( GIFDataset *poDS, int nBand, 
-                              SavedImage *psSavedImage, int nBackground )
+                              SavedImage *psSavedImage, int nBackground ) :
+                GIFAbstractRasterBand(poDS, nBand, psSavedImage, nBackground, FALSE)
 
 {
-    this->poDS = poDS;
-    this->nBand = nBand;
-
-    eDataType = GDT_Byte;
-
-    nBlockXSize = poDS->nRasterXSize;
-    nBlockYSize = 1;
-
-    psImage = psSavedImage;
-
-    poColorTable = NULL;
-    panInterlaceMap = NULL;
-    nTransparentColor = 0;
-
-    if (psImage == NULL)
-        return;
-
-/* -------------------------------------------------------------------- */
-/*      Setup interlacing map if required.                              */
-/* -------------------------------------------------------------------- */
-    panInterlaceMap = NULL;
-    if( psImage->ImageDesc.Interlace )
-    {
-        int	i, j, iLine = 0;
-
-        panInterlaceMap = (int *) CPLCalloc(poDS->nRasterYSize,sizeof(int));
-
-	for (i = 0; i < 4; i++)
-        {
-	    for (j = InterlacedOffset[i]; 
-                 j < poDS->nRasterYSize;
-                 j += InterlacedJumps[i]) 
-                panInterlaceMap[j] = iLine++;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for transparency.  We just take the first graphic         */
-/*      control extension block we find, if any.                        */
-/* -------------------------------------------------------------------- */
-    int	iExtBlock;
-
-    nTransparentColor = -1;
-    for( iExtBlock = 0; iExtBlock < psImage->ExtensionBlockCount; iExtBlock++ )
-    {
-        unsigned char *pExtData;
-
-        if( psImage->ExtensionBlocks[iExtBlock].Function != 0xf9 ||
-            psImage->ExtensionBlocks[iExtBlock].ByteCount < 4  )
-            continue;
-
-        pExtData = (unsigned char *) psImage->ExtensionBlocks[iExtBlock].Bytes;
-
-        /* check if transparent color flag is set */
-        if( !(pExtData[0] & 0x1) )
-            continue;
-
-        nTransparentColor = pExtData[3];
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Setup colormap.                                                 */
-/* -------------------------------------------------------------------- */
-    ColorMapObject 	*psGifCT = psImage->ImageDesc.ColorMap;
-    if( psGifCT == NULL )
-        psGifCT = poDS->hGifFile->SColorMap;
-
-    poColorTable = new GDALColorTable();
-    for( int iColor = 0; iColor < psGifCT->ColorCount; iColor++ )
-    {
-        GDALColorEntry	oEntry;
-
-        oEntry.c1 = psGifCT->Colors[iColor].Red;
-        oEntry.c2 = psGifCT->Colors[iColor].Green;
-        oEntry.c3 = psGifCT->Colors[iColor].Blue;
-
-        if( iColor == nTransparentColor )
-            oEntry.c4 = 0;
-        else
-            oEntry.c4 = 255;
-
-        poColorTable->SetColorEntry( iColor, &oEntry );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      If we have a background value, return it here.  Some            */
-/*      applications might want to treat this as transparent, but in    */
-/*      many uses this is inappropriate so we don't return it as        */
-/*      nodata or transparent.                                          */
-/* -------------------------------------------------------------------- */
-    if( nBackground != 255 )
-    {
-        char szBackground[10];
-        
-        sprintf( szBackground, "%d", nBackground );
-        SetMetadataItem( "GIF_BACKGROUND", szBackground );
-    }
-}
-
-/************************************************************************/
-/*                           ~GIFRasterBand()                           */
-/************************************************************************/
-
-GIFRasterBand::~GIFRasterBand()
-
-{
-    if( poColorTable != NULL )
-        delete poColorTable;
-
-    CPLFree( panInterlaceMap );
 }
 
 /************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GIFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr GIFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
-
 {
     CPLAssert( nBlockXOff == 0 );
 
@@ -257,39 +131,6 @@ CPLErr GIFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 }
 
 /************************************************************************/
-/*                       GetColorInterpretation()                       */
-/************************************************************************/
-
-GDALColorInterp GIFRasterBand::GetColorInterpretation()
-
-{
-    return GCI_PaletteIndex;
-}
-
-/************************************************************************/
-/*                           GetColorTable()                            */
-/************************************************************************/
-
-GDALColorTable *GIFRasterBand::GetColorTable()
-
-{
-    return poColorTable;
-}
-
-/************************************************************************/
-/*                           GetNoDataValue()                           */
-/************************************************************************/
-
-double GIFRasterBand::GetNoDataValue( int *pbSuccess )
-
-{
-    if( pbSuccess != NULL )
-        *pbSuccess = nTransparentColor != -1;
-
-    return nTransparentColor;
-}
-
-/************************************************************************/
 /* ==================================================================== */
 /*                             GIFDataset                               */
 /* ==================================================================== */
@@ -311,7 +152,7 @@ GIFDataset::GIFDataset()
 GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if( !Identify( poOpenInfo ) )
+    if( !Identify( poOpenInfo ) || poOpenInfo->fpL == NULL )
         return NULL;
 
     if( poOpenInfo->eAccess == GA_Update )
@@ -323,17 +164,16 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
-/*      Open the file and ingest.                                       */
+/*      Ingest.                                                         */
 /* -------------------------------------------------------------------- */
     GifFileType 	*hGifFile;
     VSILFILE                *fp;
     int                  nGifErr;
 
-    fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
-    if( fp == NULL )
-        return NULL;
+    fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
 
-    hGifFile = GIFAbstractDataset::myDGifOpen( fp, VSIGIFReadFunc );
+    hGifFile = GIFAbstractDataset::myDGifOpen( fp, GIFAbstractDataset::ReadFunc );
     if( hGifFile == NULL )
     {
         VSIFCloseL( fp );
@@ -383,7 +223,9 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
                       "Due to limitations of the GDAL GIF driver we deliberately avoid\n"
                       "opening large GIF files (larger than 100 megapixels).");
             GIFAbstractDataset::myDGifCloseFile( hGifFile );
-            VSIFCloseL( fp );
+            /* Reset poOpenInfo->fpL since BIGGIF may need it */
+            poOpenInfo->fpL = fp;
+            VSIFSeekL(fp, 0, SEEK_SET);
             return NULL;
         }
     }
@@ -392,7 +234,7 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
 
     VSIFSeekL( fp, 0, SEEK_SET);
 
-    hGifFile = GIFAbstractDataset::myDGifOpen( fp, VSIGIFReadFunc );
+    hGifFile = GIFAbstractDataset::myDGifOpen( fp, GIFAbstractDataset::ReadFunc );
     if( hGifFile == NULL )
     {
         VSIFCloseL( fp );
@@ -463,7 +305,10 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
             CPLDebug("GIF", "Skipping image without color table");
             continue;
         }
-
+#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5
+        /* Since giflib 5, de-interlacing is done by DGifSlurp() */
+        psImage->ImageDesc.Interlace = 0;
+#endif
         poDS->SetBand( poDS->nBands+1, 
                        new GIFRasterBand( poDS, poDS->nBands+1, psImage,
                                           hGifFile->SBackGroundColor ));
@@ -483,12 +328,13 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
-    poDS->TryLoadXML();
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Support overviews.                                              */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
+                                 poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -497,11 +343,7 @@ GDALDataset *GIFDataset::Open( GDALOpenInfo * poOpenInfo )
 /*                        GDALPrintGifError()                           */
 /************************************************************************/
 
-static void GDALPrintGifError(
-#if GIFLIB_MAJOR < 5
-CPL_UNUSED 
-#endif
-GifFileType *hGifFile, const char* pszMsg)
+static void GDALPrintGifError(CPL_UNUSED GifFileType *hGifFile, const char* pszMsg)
 {
 /* GIFLIB_MAJOR is only defined in libgif >= 4.2.0 */
 /* libgif 4.2.0 has retired PrintGifError() and added GifErrorString() */
@@ -653,7 +495,9 @@ GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 /*      Setup parameters.                                               */
 /* -------------------------------------------------------------------- */
     if (EGifPutScreenDesc(hGifFile, nXSize, nYSize, 
-                          psGifCT->ColorCount, 255, psGifCT) == GIF_ERROR)
+                          8, /* ColorRes */
+                          255, /* Background */
+                          psGifCT) == GIF_ERROR)
     {
         GifFreeMapObject(psGifCT);
         GDALPrintGifError(hGifFile, "Error writing gif file.");
@@ -704,7 +548,7 @@ GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         {
             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                      pabyScanline, nXSize, 1, GDT_Byte,
-                                     nBands, nBands * nXSize );
+                                     nBands, nBands * nXSize, NULL );
 
             if( eErr != CE_None || EGifPutLine( hGifFile, pabyScanline, nXSize ) == GIF_ERROR )
             {
@@ -740,7 +584,7 @@ GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             {
                 eErr= poBand->RasterIO( GF_Read, 0, j, nXSize, 1, 
                                         pabyScanline, nXSize, 1, GDT_Byte,
-                                        1, nXSize );
+                                        1, nXSize, NULL );
 
                 if (eErr != CE_None || EGifPutLine(hGifFile, pabyScanline, nXSize) == GIF_ERROR)
                 {
@@ -788,7 +632,7 @@ GIFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     /* If outputing to stdout, we can't reopen it, so we'll return */
@@ -824,20 +668,6 @@ error:
 }
 
 /************************************************************************/
-/*                           VSIGIFReadFunc()                           */
-/*                                                                      */
-/*      Proxy function for reading from GIF file.                       */
-/************************************************************************/
-
-static int VSIGIFReadFunc( GifFileType *psGFile, GifByteType *pabyBuffer, 
-                           int nBytesToRead )
-
-{
-    return VSIFReadL( pabyBuffer, 1, nBytesToRead, 
-                      (VSILFILE *) psGFile->UserData );
-}
-
-/************************************************************************/
 /*                          VSIGIFWriteFunc()                           */
 /*                                                                      */
 /*      Proxy write function.                                           */
@@ -882,6 +712,7 @@ void GDALRegister_GIF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GIF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Graphics Interchange Format (.gif)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -906,4 +737,3 @@ void GDALRegister_GIF()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/grass/GNUmakefile b/frmts/grass/GNUmakefile
index c75ac54..4863db4 100644
--- a/frmts/grass/GNUmakefile
+++ b/frmts/grass/GNUmakefile
@@ -10,7 +10,7 @@ else
 OBJ	=	grass57dataset.o
 endif
 
-CPPFLAGS	:=	 -DGRASS_GISBASE=\"$(GRASS_GISBASE)\" $(GRASS_INCLUDE) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 -DGRASS_GISBASE=\"$(GRASS_GISBASE)\" $(GRASS_INCLUDE)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/grass/grass57dataset.cpp b/frmts/grass/grass57dataset.cpp
index 0e1d620..0b97887 100644
--- a/frmts/grass/grass57dataset.cpp
+++ b/frmts/grass/grass57dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: grass57dataset.cpp 28291 2015-01-05 14:45:07Z martinl $
+ * $Id: grass57dataset.cpp 28534 2015-02-21 14:34:39Z rouault $
  *
  * Project:  GRASS Driver
  * Purpose:  Implement GRASS raster read/write support
@@ -63,7 +63,7 @@ char *GPJ_grass_to_wkt(struct Key_Value *,
 
 #define GRASS_MAX_COLORS 100000  // what is the right value
 
-CPL_CVSID("$Id: grass57dataset.cpp 28291 2015-01-05 14:45:07Z martinl $");
+CPL_CVSID("$Id: grass57dataset.cpp 28534 2015-02-21 14:34:39Z rouault $");
 
 CPL_C_START
 void	GDALRegister_GRASS(void);
@@ -182,7 +182,10 @@ class GRASSRasterBand : public GDALRasterBand
     virtual        ~GRASSRasterBand();
 
     virtual CPLErr IReadBlock( int, int, void * );
-    virtual CPLErr IRasterIO ( GDALRWFlag, int, int, int, int, void *, int, int, GDALDataType, int, int );
+    virtual CPLErr IRasterIO ( GDALRWFlag, int, int, int, int, void *, int, int, GDALDataType,
+                               GSpacing nPixelSpace,
+                               GSpacing nLineSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
     virtual GDALColorInterp GetColorInterpretation();
     virtual GDALColorTable *GetColorTable();
     virtual double GetMinimum( int *pbSuccess = NULL );
@@ -528,7 +531,9 @@ CPLErr GRASSRasterBand::IRasterIO ( GDALRWFlag eRWFlag,
 	                           int nXOff, int nYOff, int nXSize, int nYSize,
 				   void * pData, int nBufXSize, int nBufYSize,
 				   GDALDataType eBufType,
-				   int nPixelSpace, int nLineSpace )
+				   GSpacing nPixelSpace,
+                   GSpacing nLineSpace,
+                   GDALRasterIOExtraArg* psExtraArg )
 {
     /* GRASS library does that, we have only calculate and reset the region in map units
      * and if the region has changed, reopen the raster */
@@ -866,7 +871,7 @@ GDALDataset *GRASSDataset::Open( GDALOpenInfo * poOpenInfo )
         static char* gisbaseEnv = NULL;
         const char *gisbase = GRASS_GISBASE;
         CPLError( CE_Warning, CPLE_AppDefined, "GRASS warning: GISBASE "
-                "enviroment variable was not set, using:\n%s", gisbase );
+                "environment variable was not set, using:\n%s", gisbase );
         char buf[2000];
         snprintf ( buf, sizeof(buf), "GISBASE=%s", gisbase );
         buf[sizeof(buf)-1] = '\0';
@@ -1042,8 +1047,9 @@ void GDALRegister_GRASS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GRASS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
-                                   "GRASS Database Rasters (5.7+)" );
+                                   "GRASS Rasters (5.7+)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_grass.html" );
         
diff --git a/frmts/grass/grassdataset.cpp b/frmts/grass/grassdataset.cpp
index 95e9d1f..f413298 100644
--- a/frmts/grass/grassdataset.cpp
+++ b/frmts/grass/grassdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: grassdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: grassdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  GRASS Driver
  * Purpose:  Implement GRASS raster read/write support
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: grassdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: grassdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_GRASS(void);
@@ -596,6 +596,7 @@ void GDALRegister_GRASS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GRASS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "GRASS Database Rasters" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/grass/pkg/Makefile.in b/frmts/grass/pkg/Makefile.in
index ca97c29..007df6d 100644
--- a/frmts/grass/pkg/Makefile.in
+++ b/frmts/grass/pkg/Makefile.in
@@ -1,11 +1,12 @@
-                                                                                                                                                                                                                                                               
 CC	=	@CC@
 CXX	=	@CXX@
 LD	=	@CXX@
 
 CPPFLAGS = -DUSE_CPL -DGRASS_GISBASE=\"@GRASS_GISBASE@\" \
-	  @GDAL_INC@ @GRASS_INCLUDE@ @CPPFLAGS@ 
+	  @GDAL_INC@ @GRASS_INCLUDE@ @PQ_INCLUDE@ @CPPFLAGS@
 CXXFLAGS = @CXX_WFLAGS@ @CXX_PIC@ 
+CFLAGS   = @CFLAGS@ 
+LDFLAGS  = @LDFLAGS@ 
 
 RANLIB		=	@RANLIB@
 SO_EXT		=	@SO_EXT@
@@ -28,8 +29,12 @@ install:	default
 	cp $(OLIBNAME) $(AUTOLOAD_DIR)
 	test -d ${GRASSTABLES_DIR} || mkdir ${GRASSTABLES_DIR}
 	test -d ${GRASSTABLES_DIR}/etc || mkdir ${GRASSTABLES_DIR}/etc
-	cp @GRASS_GISBASE@/etc/ellipse.table ${GRASSTABLES_DIR}/etc
-	cp @GRASS_GISBASE@/etc/datum.table @GRASS_GISBASE@/etc/datumtransform.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/ellipse.table || cp @GRASS_GISBASE@/etc/ellipse.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/datum.table || cp @GRASS_GISBASE@/etc/datum.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/datumtransform.table || cp @GRASS_GISBASE@/etc/datumtransform.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/proj/ellipse.table || cp @GRASS_GISBASE@/etc/proj/ellipse.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/proj/datum.table || cp @GRASS_GISBASE@/etc/proj/datum.table ${GRASSTABLES_DIR}/etc
+	test ! -e @GRASS_GISBASE@/etc/proj/datumtransform.table || cp @GRASS_GISBASE@/etc/proj/datumtransform.table ${GRASSTABLES_DIR}/etc
 	test -d ${GRASSTABLES_DIR}/driver || mkdir ${GRASSTABLES_DIR}/driver
 	test -d ${GRASSTABLES_DIR}/driver/db || mkdir ${GRASSTABLES_DIR}/driver/db
 	cp -r @GRASS_GISBASE@/driver/db/* ${GRASSTABLES_DIR}/driver/db/
@@ -42,11 +47,11 @@ distclean: clean
 
 
 $(GLIBNAME):	grass57dataset.o
-	$(LD_SHARED) grass57dataset.o $(LIBS) -o $(GLIBNAME)
+	$(LD_SHARED) $(LDFLAGS) grass57dataset.o $(LIBS) -o $(GLIBNAME)
 
 $(OLIBNAME):	ogrgrassdriver.o ogrgrassdatasource.o ogrgrasslayer.o 
-	$(LD_SHARED) ogrgrassdriver.o ogrgrassdatasource.o ogrgrasslayer.o $(LIBS) -o $(OLIBNAME)
+	$(LD_SHARED) $(LDFLAGS) ogrgrassdriver.o ogrgrassdatasource.o ogrgrasslayer.o $(LIBS) -o $(OLIBNAME)
 
 %.o:	%.cpp
-	$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
 
diff --git a/frmts/grass/pkg/README b/frmts/grass/pkg/README
index c3a9c4a..cd545cd 100644
--- a/frmts/grass/pkg/README
+++ b/frmts/grass/pkg/README
@@ -1,5 +1,5 @@
-	Standalone GRASS 6 Drivers for GDAL and OGR
-	===========================================
+Standalone GRASS Drivers for GDAL and OGR
+=========================================
 
 This package contains standalone drivers for GRASS raster and vector
 files that can be built after GDAL has been built and installed as an 
@@ -13,14 +13,14 @@ build and install GRASS normally and finally build and install this driver.
 To build this driver it is necessary for it to find GDAL and GRASS support
 files.  Typically the configure and build process would look something like:
 
-./configure --with-gdal=/usr/local/bin/gdal-config --with-grass=/usr/local/grass-6.0.0
+./configure --with-gdal=/usr/local/bin/gdal-config --with-grass=/usr/local/grass-7.0.0
 make
 sudo make install
 
 See also:
 
   http://www.gdal.org/
-  http://grass.itc.it/
+  http://grass.osgeo.org
 
 
 ---
diff --git a/frmts/grass/pkg/configure b/frmts/grass/pkg/configure
index cdd9df2..ae5e319 100755
--- a/frmts/grass/pkg/configure
+++ b/frmts/grass/pkg/configure
@@ -1,81 +1,458 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59.
+# Generated by GNU Autoconf 2.69.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
 #
-# Copyright (C) 2003 Free Software Foundation, Inc.
 # This configure script is free software; the Free Software Foundation
 # gives unlimited permission to copy, distribute and modify it.
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
 
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
   # is contrary to our usage.  Disable this feature.
   alias -g '${1+"$@"}'='"$@"'
-elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
-  set -o posix
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
 fi
-DUALCASE=1; export DUALCASE # for MKS sh
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
 else
-  as_unset=false
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
 fi
 
 
-# Work around bugs in pre-3.0 UWIN ksh.
-$as_unset ENV MAIL MAILPATH
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
 PS1='$ '
 PS2='> '
 PS4='+ '
 
 # NLS nuisances.
-for as_var in \
-  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
-  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
-  LC_TELEPHONE LC_TIME
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
 do
-  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
-    eval $as_var=C; export $as_var
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
   else
-    $as_unset $as_var
+    $as_echo "$0: Please tell bug-autoconf at gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
   fi
-done
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
 
-# Required to use basename.
-if expr a : '\(a\)' >/dev/null 2>&1; then
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
 else
   as_expr=false
 fi
 
-if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
   as_basename=basename
 else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
-as_me=`$as_basename "$0" ||
+as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
 	 X"$0" : 'X\(//\)$' \| \
-	 X"$0" : 'X\(/\)$' \| \
-	 .     : '\(.\)' 2>/dev/null ||
-echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
-  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
-  	  /^X\/\(\/\).*/{ s//\1/; q; }
-  	  s/.*/./; q'`
-
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
 
-# PATH needs CR, and LINENO needs CR and PATH.
 # Avoid depending upon Character Ranges.
 as_cr_letters='abcdefghijklmnopqrstuvwxyz'
 as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -83,146 +460,91 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
 as_cr_digits='0123456789'
 as_cr_alnum=$as_cr_Letters$as_cr_digits
 
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  echo "#! /bin/sh" >conf$$.sh
-  echo  "exit 0"   >>conf$$.sh
-  chmod +x conf$$.sh
-  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
-    PATH_SEPARATOR=';'
-  else
-    PATH_SEPARATOR=:
-  fi
-  rm -f conf$$.sh
-fi
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
-  # Find who we are.  Look in the path if we contain no path at all
-  # relative or not.
-  case $0 in
-    *[\\/]* ) as_myself=$0 ;;
-    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
-
-       ;;
-  esac
-  # We did not find ourselves, most probably we were run as `sh COMMAND'
-  # in which case we are not to be found in the path.
-  if test "x$as_myself" = x; then
-    as_myself=$0
-  fi
-  if test ! -f "$as_myself"; then
-    { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
-   { (exit 1); exit 1; }; }
-  fi
-  case $CONFIG_SHELL in
-  '')
-    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for as_base in sh bash ksh sh5; do
-	 case $as_dir in
-	 /*)
-	   if ("$as_dir/$as_base" -c '
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
-	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
-	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
-	     CONFIG_SHELL=$as_dir/$as_base
-	     export CONFIG_SHELL
-	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
-	   fi;;
-	 esac
-       done
-done
-;;
-  esac
 
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line before each line; the second 'sed' does the real
-  # work.  The second script uses 'N' to pair each line-number line
-  # with the numbered line, and appends trailing '-' during
-  # substitution so that $LINENO is not a special case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
-  sed '=' <$as_myself |
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
     sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
       N
-      s,$,-,
-      : loop
-      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
       t loop
-      s,-$,,
-      s,^['$as_cr_digits']*\n,,
+      s/-\n.*//
     ' >$as_me.lineno &&
-  chmod +x $as_me.lineno ||
-    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
-   { (exit 1); exit 1; }; }
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
 
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
   # Don't try to exec as it changes $[0], causing all sort of problems
   # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensible to this).
-  . ./$as_me.lineno
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
   # Exit status is that of the last command.
   exit
 }
 
-
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
-  *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T='	' ;;
-  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
-  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
 esac
 
-if expr a : '\(a\)' >/dev/null 2>&1; then
-  as_expr=expr
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
 else
-  as_expr=false
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
 fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-echo >conf$$.file
-if ln -s conf$$.file conf$$ 2>/dev/null; then
-  # We could just check for DJGPP; but this test a) works b) is more generic
-  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
-  if test -f conf$$.exe; then
-    # Don't use ln at all; we don't have any links
-    as_ln_s='cp -p'
-  else
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
     as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
   fi
-elif ln conf$$.file conf$$ 2>/dev/null; then
-  as_ln_s=ln
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
-rm -f conf$$ conf$$.exe conf$$.file
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
 
 if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
+  as_mkdir_p='mkdir -p "$as_dir"'
 else
   test -d ./-p && rmdir ./-p
   as_mkdir_p=false
 fi
 
-as_executable_p="test -f"
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -231,38 +553,25 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
 as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
-# IFS
-# We need space, tab and new line, in precisely that order.
-as_nl='
-'
-IFS=" 	$as_nl"
-
-# CDPATH.
-$as_unset CDPATH
-
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
 
 # Name of the host.
-# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
 # so uname gets run too.
 ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
 
-exec 6>&1
-
 #
 # Initializations.
 #
 ac_default_prefix=/usr/local
+ac_clean_files=
 ac_config_libobj_dir=.
+LIBOBJS=
 cross_compiling=no
 subdirs=
 MFLAGS=
 MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-
-# Maximum number of lines to put in a shell here document.
-# This variable seems obsolete.  It should probably be removed, and
-# only ac_max_sed_lines should be used.
-: ${ac_max_here_lines=38}
 
 # Identity of this package.
 PACKAGE_NAME=
@@ -270,14 +579,99 @@ PACKAGE_TARNAME=
 PACKAGE_VERSION=
 PACKAGE_STRING=
 PACKAGE_BUGREPORT=
+PACKAGE_URL=
 
 ac_unique_file="Makefile.in"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX RANLIB ac_ct_RANLIB CXX_PIC C_PIC LD_SHARED SO_EXT CXX_WFLAGS C_WFLAGS GDAL [...]
+ac_subst_vars='LTLIBOBJS
+LIBOBJS
+PQ_INCLUDE
+GRASS_GISBASE
+GRASS_INCLUDE
+AUTOLOAD_DIR
+GDAL_INC
+GDAL_CONFIG
+C_WFLAGS
+CXX_WFLAGS
+SO_EXT
+LD_SHARED
+C_PIC
+CXX_PIC
+RANLIB
+ac_ct_CXX
+CXXFLAGS
+CXX
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
 ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+with_ld_shared
+with_gdal
+with_autoload
+with_grass
+with_postgres_includes
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC'
+
 
 # Initialize some variables set by options.
 ac_init_help=
 ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
 # The variables have the same names as the options, with
 # dashes changed to underlines.
 cache_file=/dev/null
@@ -300,34 +694,49 @@ x_libraries=NONE
 # and all the variables that are supposed to be based on exec_prefix
 # by default will actually change.
 # Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
 bindir='${exec_prefix}/bin'
 sbindir='${exec_prefix}/sbin'
 libexecdir='${exec_prefix}/libexec'
-datadir='${prefix}/share'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
-libdir='${exec_prefix}/lib'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
-infodir='${prefix}/info'
-mandir='${prefix}/man'
+docdir='${datarootdir}/doc/${PACKAGE}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
 
 ac_prev=
+ac_dashdash=
 for ac_option
 do
   # If the previous option needs an argument, assign it.
   if test -n "$ac_prev"; then
-    eval "$ac_prev=\$ac_option"
+    eval $ac_prev=\$ac_option
     ac_prev=
     continue
   fi
 
-  ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
 
   # Accept the important Cygnus configure options, so we can diagnose typos.
 
-  case $ac_option in
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
 
   -bindir | --bindir | --bindi | --bind | --bin | --bi)
     ac_prev=bindir ;;
@@ -349,33 +758,59 @@ do
   --config-cache | -C)
     cache_file=config.cache ;;
 
-  -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+  -datadir | --datadir | --datadi | --datad)
     ac_prev=datadir ;;
-  -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
-  | --da=*)
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
     datadir=$ac_optarg ;;
 
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
   -disable-* | --disable-*)
-    ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
-      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
-   { (exit 1); exit 1; }; }
-    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
-    eval "enable_$ac_feature=no" ;;
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
 
   -enable-* | --enable-*)
-    ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
-      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
-   { (exit 1); exit 1; }; }
-    ac_feature=`echo $ac_feature | sed 's/-/_/g'`
-    case $ac_option in
-      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
-      *) ac_optarg=yes ;;
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
     esac
-    eval "enable_$ac_feature='$ac_optarg'" ;;
+    eval enable_$ac_useropt=\$ac_optarg ;;
 
   -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
   | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
@@ -402,6 +837,12 @@ do
   -host=* | --host=* | --hos=* | --ho=*)
     host_alias=$ac_optarg ;;
 
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
   -includedir | --includedir | --includedi | --included | --include \
   | --includ | --inclu | --incl | --inc)
     ac_prev=includedir ;;
@@ -426,13 +867,16 @@ do
   | --libexe=* | --libex=* | --libe=*)
     libexecdir=$ac_optarg ;;
 
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
   -localstatedir | --localstatedir | --localstatedi | --localstated \
-  | --localstate | --localstat | --localsta | --localst \
-  | --locals | --local | --loca | --loc | --lo)
+  | --localstate | --localstat | --localsta | --localst | --locals)
     ac_prev=localstatedir ;;
   -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
-  | --localstate=* | --localstat=* | --localsta=* | --localst=* \
-  | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
     localstatedir=$ac_optarg ;;
 
   -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
@@ -497,6 +941,16 @@ do
   | --progr-tra=* | --program-tr=* | --program-t=*)
     program_transform_name=$ac_optarg ;;
 
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
   -q | -quiet | --quiet | --quie | --qui | --qu | --q \
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
@@ -547,26 +1001,36 @@ do
     ac_init_version=: ;;
 
   -with-* | --with-*)
-    ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
-      { echo "$as_me: error: invalid package name: $ac_package" >&2
-   { (exit 1); exit 1; }; }
-    ac_package=`echo $ac_package| sed 's/-/_/g'`
-    case $ac_option in
-      *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
-      *) ac_optarg=yes ;;
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
     esac
-    eval "with_$ac_package='$ac_optarg'" ;;
+    eval with_$ac_useropt=\$ac_optarg ;;
 
   -without-* | --without-*)
-    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
-      { echo "$as_me: error: invalid package name: $ac_package" >&2
-   { (exit 1); exit 1; }; }
-    ac_package=`echo $ac_package | sed 's/-/_/g'`
-    eval "with_$ac_package=no" ;;
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
 
   --x)
     # Obsolete; use --with-x.
@@ -586,27 +1050,26 @@ do
   | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
     x_libraries=$ac_optarg ;;
 
-  -*) { echo "$as_me: error: unrecognized option: $ac_option
-Try \`$0 --help' for more information." >&2
-   { (exit 1); exit 1; }; }
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
     ;;
 
   *=*)
     ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
     # Reject names that are not valid shell variable names.
-    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
-      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
-   { (exit 1); exit 1; }; }
-    ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
-    eval "$ac_envvar='$ac_optarg'"
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
     export $ac_envvar ;;
 
   *)
     # FIXME: should be removed in autoconf 3.0.
-    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
     expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
-      echo "$as_me: WARNING: invalid host type: $ac_option" >&2
-    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
     ;;
 
   esac
@@ -614,31 +1077,36 @@ done
 
 if test -n "$ac_prev"; then
   ac_option=--`echo $ac_prev | sed 's/_/-/g'`
-  { echo "$as_me: error: missing argument to $ac_option" >&2
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "missing argument to $ac_option"
 fi
 
-# Be sure to have absolute paths.
-for ac_var in exec_prefix prefix
-do
-  eval ac_val=$`echo $ac_var`
-  case $ac_val in
-    [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
-    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
-   { (exit 1); exit 1; }; };;
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
   esac
-done
+fi
 
-# Be sure to have absolute paths.
-for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
-	      localstatedir libdir includedir oldincludedir infodir mandir
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
 do
-  eval ac_val=$`echo $ac_var`
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
   case $ac_val in
-    [\\/$]* | ?:[\\/]* ) ;;
-    *)  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
-   { (exit 1); exit 1; }; };;
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
   esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
 done
 
 # There might be people who depend on the old broken behavior: `$host'
@@ -652,8 +1120,6 @@ target=$target_alias
 if test "x$host_alias" != x; then
   if test "x$build_alias" = x; then
     cross_compiling=maybe
-    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
-    If a cross compiler is detected then cross compile mode will be used." >&2
   elif test "x$build_alias" != "x$host_alias"; then
     cross_compiling=yes
   fi
@@ -665,78 +1131,72 @@ test -n "$host_alias" && ac_tool_prefix=$host_alias-
 test "$silent" = yes && exec 6>/dev/null
 
 
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
 # Find the source files, if location was not specified.
 if test -z "$srcdir"; then
   ac_srcdir_defaulted=yes
-  # Try the directory containing this script, then its parent.
-  ac_confdir=`(dirname "$0") 2>/dev/null ||
-$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$0" : 'X\(//\)[^/]' \| \
-	 X"$0" : 'X\(//\)$' \| \
-	 X"$0" : 'X\(/\)' \| \
-	 .     : '\(.\)' 2>/dev/null ||
-echo X"$0" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
-  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
-  	  /^X\(\/\/\)$/{ s//\1/; q; }
-  	  /^X\(\/\).*/{ s//\1/; q; }
-  	  s/.*/./; q'`
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
   srcdir=$ac_confdir
-  if test ! -r $srcdir/$ac_unique_file; then
+  if test ! -r "$srcdir/$ac_unique_file"; then
     srcdir=..
   fi
 else
   ac_srcdir_defaulted=no
 fi
-if test ! -r $srcdir/$ac_unique_file; then
-  if test "$ac_srcdir_defaulted" = yes; then
-    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
-   { (exit 1); exit 1; }; }
-  else
-    { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
-   { (exit 1); exit 1; }; }
-  fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
 fi
-(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null ||
-  { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2
-   { (exit 1); exit 1; }; }
-srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
-ac_env_build_alias_set=${build_alias+set}
-ac_env_build_alias_value=$build_alias
-ac_cv_env_build_alias_set=${build_alias+set}
-ac_cv_env_build_alias_value=$build_alias
-ac_env_host_alias_set=${host_alias+set}
-ac_env_host_alias_value=$host_alias
-ac_cv_env_host_alias_set=${host_alias+set}
-ac_cv_env_host_alias_value=$host_alias
-ac_env_target_alias_set=${target_alias+set}
-ac_env_target_alias_value=$target_alias
-ac_cv_env_target_alias_set=${target_alias+set}
-ac_cv_env_target_alias_value=$target_alias
-ac_env_CC_set=${CC+set}
-ac_env_CC_value=$CC
-ac_cv_env_CC_set=${CC+set}
-ac_cv_env_CC_value=$CC
-ac_env_CFLAGS_set=${CFLAGS+set}
-ac_env_CFLAGS_value=$CFLAGS
-ac_cv_env_CFLAGS_set=${CFLAGS+set}
-ac_cv_env_CFLAGS_value=$CFLAGS
-ac_env_LDFLAGS_set=${LDFLAGS+set}
-ac_env_LDFLAGS_value=$LDFLAGS
-ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
-ac_cv_env_LDFLAGS_value=$LDFLAGS
-ac_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_env_CPPFLAGS_value=$CPPFLAGS
-ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
-ac_cv_env_CPPFLAGS_value=$CPPFLAGS
-ac_env_CXX_set=${CXX+set}
-ac_env_CXX_value=$CXX
-ac_cv_env_CXX_set=${CXX+set}
-ac_cv_env_CXX_value=$CXX
-ac_env_CXXFLAGS_set=${CXXFLAGS+set}
-ac_env_CXXFLAGS_value=$CXXFLAGS
-ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set}
-ac_cv_env_CXXFLAGS_value=$CXXFLAGS
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
 
 #
 # Report the --help message.
@@ -759,20 +1219,17 @@ Configuration:
       --help=short        display options specific to this package
       --help=recursive    display the short help of all the included packages
   -V, --version           display version information and exit
-  -q, --quiet, --silent   do not print \`checking...' messages
+  -q, --quiet, --silent   do not print \`checking ...' messages
       --cache-file=FILE   cache test results in FILE [disabled]
   -C, --config-cache      alias for \`--cache-file=config.cache'
   -n, --no-create         do not create output files
       --srcdir=DIR        find the sources in DIR [configure dir or \`..']
 
-_ACEOF
-
-  cat <<_ACEOF
 Installation directories:
   --prefix=PREFIX         install architecture-independent files in PREFIX
-			  [$ac_default_prefix]
+                          [$ac_default_prefix]
   --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
-			  [PREFIX]
+                          [PREFIX]
 
 By default, \`make install' will install all the files in
 \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
@@ -782,18 +1239,25 @@ for instance \`--prefix=\$HOME'.
 For better control, use the options below.
 
 Fine tuning of the installation directories:
-  --bindir=DIR           user executables [EPREFIX/bin]
-  --sbindir=DIR          system admin executables [EPREFIX/sbin]
-  --libexecdir=DIR       program executables [EPREFIX/libexec]
-  --datadir=DIR          read-only architecture-independent data [PREFIX/share]
-  --sysconfdir=DIR       read-only single-machine data [PREFIX/etc]
-  --sharedstatedir=DIR   modifiable architecture-independent data [PREFIX/com]
-  --localstatedir=DIR    modifiable single-machine data [PREFIX/var]
-  --libdir=DIR           object code libraries [EPREFIX/lib]
-  --includedir=DIR       C header files [PREFIX/include]
-  --oldincludedir=DIR    C header files for non-gcc [/usr/include]
-  --infodir=DIR          info documentation [PREFIX/info]
-  --mandir=DIR           man documentation [PREFIX/man]
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/PACKAGE]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
 _ACEOF
 
   cat <<\_ACEOF
@@ -809,135 +1273,233 @@ Optional Packages:
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
   --with-ld-shared=cmd    provide shared library link
   --with-gdal=PATH        GDAL (PATH is path to gdal-config)
-  --with-autoload=DIR      Directory for autoload drivers
+  --with-autoload=DIR     Directory for autoload drivers
   --with-grass=ARG        Include GRASS support (ARG=GRASS install tree dir)
+  --with-postgres-includes=DIR     use PostgreSQL includes in DIR
 
 Some influential environment variables:
   CC          C compiler command
   CFLAGS      C compiler flags
   LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
               nonstandard directory <lib dir>
-  CPPFLAGS    C/C++ preprocessor flags, e.g. -I<include dir> if you have
-              headers in a nonstandard directory <include dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
 
+Report bugs to the package provider.
 _ACEOF
+ac_status=$?
 fi
 
 if test "$ac_init_help" = "recursive"; then
   # If there are subdirs, report their specific --help.
-  ac_popdir=`pwd`
   for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
-    test -d $ac_dir || continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
     ac_builddir=.
 
-if test "$ac_dir" != .; then
-  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
-  # A "../" for each directory in $ac_dir_suffix.
-  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
-else
-  ac_dir_suffix= ac_top_builddir=
-fi
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
 
 case $srcdir in
-  .)  # No --srcdir option.  We are building in place.
+  .)  # We are building in place.
     ac_srcdir=.
-    if test -z "$ac_top_builddir"; then
-       ac_top_srcdir=.
-    else
-       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
-    fi ;;
-  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
     ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir ;;
-  *) # Relative path.
-    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_builddir$srcdir ;;
-esac
-
-# Do not use `cd foo && pwd` to compute absolute paths, because
-# the directories may not exist.
-case `pwd` in
-.) ac_abs_builddir="$ac_dir";;
-*)
-  case "$ac_dir" in
-  .) ac_abs_builddir=`pwd`;;
-  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
-  *) ac_abs_builddir=`pwd`/"$ac_dir";;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_top_builddir=${ac_top_builddir}.;;
-*)
-  case ${ac_top_builddir}. in
-  .) ac_abs_top_builddir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
-  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_srcdir=$ac_srcdir;;
-*)
-  case $ac_srcdir in
-  .) ac_abs_srcdir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
-  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_top_srcdir=$ac_top_srcdir;;
-*)
-  case $ac_top_srcdir in
-  .) ac_abs_top_srcdir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
-  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
-  esac;;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
 esac
-
-    cd $ac_dir
-    # Check for guested configure; otherwise get Cygnus style configure.
-    if test -f $ac_srcdir/configure.gnu; then
-      echo
-      $SHELL $ac_srcdir/configure.gnu  --help=recursive
-    elif test -f $ac_srcdir/configure; then
-      echo
-      $SHELL $ac_srcdir/configure  --help=recursive
-    elif test -f $ac_srcdir/configure.ac ||
-	   test -f $ac_srcdir/configure.in; then
-      echo
-      $ac_configure --help
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
     else
-      echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
-    fi
-    cd $ac_popdir
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
   done
 fi
 
-test -n "$ac_init_help" && exit 0
+test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
+configure
+generated by GNU Autoconf 2.69
 
-Copyright (C) 2003 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This configure script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it.
 _ACEOF
-  exit 0
+  exit
 fi
-exec 5>config.log
-cat >&5 <<_ACEOF
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
 It was created by $as_me, which was
-generated by GNU Autoconf 2.59.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
 
 _ACEOF
+exec 5>>config.log
 {
 cat <<_ASUNAME
 ## --------- ##
@@ -956,7 +1518,7 @@ uname -v = `(uname -v) 2>/dev/null || echo unknown`
 /bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
 /usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
 /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
-hostinfo               = `(hostinfo) 2>/dev/null               || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
 /bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
 /usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
 /bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
@@ -968,8 +1530,9 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  echo "PATH: $as_dir"
-done
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
 
 } >&5
 
@@ -991,7 +1554,6 @@ _ACEOF
 ac_configure_args=
 ac_configure_args0=
 ac_configure_args1=
-ac_sep=
 ac_must_keep_next=false
 for ac_pass in 1 2
 do
@@ -1002,13 +1564,13 @@ do
     -q | -quiet | --quiet | --quie | --qui | --qu | --q \
     | -silent | --silent | --silen | --sile | --sil)
       continue ;;
-    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
-      ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
     esac
     case $ac_pass in
-    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
     2)
-      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      as_fn_append ac_configure_args1 " '$ac_arg'"
       if test $ac_must_keep_next = true; then
 	ac_must_keep_next=false # Got value, back to normal.
       else
@@ -1024,104 +1586,115 @@ do
 	  -* ) ac_must_keep_next=true ;;
 	esac
       fi
-      ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
-      # Get rid of the leading space.
-      ac_sep=" "
+      as_fn_append ac_configure_args " '$ac_arg'"
       ;;
     esac
   done
 done
-$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
-$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
 
 # When interrupted or exit'd, cleanup temporary files, and complete
 # config.log.  We remove comments because anyway the quotes in there
 # would cause problems or look ugly.
-# WARNING: Be sure not to use single quotes in there, as some shells,
-# such as our DU 5.0 friend, will then `close' the trap.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
 trap 'exit_status=$?
   # Save into config.log some information that might help in debugging.
   {
     echo
 
-    cat <<\_ASBOX
-## ---------------- ##
+    $as_echo "## ---------------- ##
 ## Cache variables. ##
-## ---------------- ##
-_ASBOX
+## ---------------- ##"
     echo
     # The following way of writing the cache mishandles newlines in values,
-{
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
   (set) 2>&1 |
-    case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
-    *ac_space=\ *)
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
       sed -n \
-	"s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
-	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
-      ;;
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
     *)
-      sed -n \
-	"s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
       ;;
-    esac;
-}
+    esac |
+    sort
+)
     echo
 
-    cat <<\_ASBOX
-## ----------------- ##
+    $as_echo "## ----------------- ##
 ## Output variables. ##
-## ----------------- ##
-_ASBOX
+## ----------------- ##"
     echo
     for ac_var in $ac_subst_vars
     do
-      eval ac_val=$`echo $ac_var`
-      echo "$ac_var='"'"'$ac_val'"'"'"
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
     done | sort
     echo
 
     if test -n "$ac_subst_files"; then
-      cat <<\_ASBOX
-## ------------- ##
-## Output files. ##
-## ------------- ##
-_ASBOX
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
       echo
       for ac_var in $ac_subst_files
       do
-	eval ac_val=$`echo $ac_var`
-	echo "$ac_var='"'"'$ac_val'"'"'"
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
       done | sort
       echo
     fi
 
     if test -s confdefs.h; then
-      cat <<\_ASBOX
-## ----------- ##
+      $as_echo "## ----------- ##
 ## confdefs.h. ##
-## ----------- ##
-_ASBOX
+## ----------- ##"
       echo
-      sed "/^$/d" confdefs.h | sort
+      cat confdefs.h
       echo
     fi
     test "$ac_signal" != 0 &&
-      echo "$as_me: caught signal $ac_signal"
-    echo "$as_me: exit $exit_status"
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
   } >&5
-  rm -f core *.core &&
-  rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
     exit $exit_status
-     ' 0
+' 0
 for ac_signal in 1 2 13 15; do
-  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
 done
 ac_signal=0
 
 # confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo >confdefs.h
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
 
 # Predefined preprocessor variables.
 
@@ -1129,42 +1702,57 @@ cat >>confdefs.h <<_ACEOF
 #define PACKAGE_NAME "$PACKAGE_NAME"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_TARNAME "$PACKAGE_TARNAME"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_VERSION "$PACKAGE_VERSION"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_STRING "$PACKAGE_STRING"
 _ACEOF
 
-
 cat >>confdefs.h <<_ACEOF
 #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
 _ACEOF
 
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
 
 # Let the site file select an alternate cache file if it wants to.
-# Prefer explicitly selected file to automatically selected ones.
-if test -z "$CONFIG_SITE"; then
-  if test "x$prefix" != xNONE; then
-    CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
-  else
-    CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
-  fi
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
 fi
-for ac_site_file in $CONFIG_SITE; do
-  if test -r "$ac_site_file"; then
-    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
-echo "$as_me: loading site script $ac_site_file" >&6;}
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
     sed 's/^/| /' "$ac_site_file" >&5
-    . "$ac_site_file"
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
   fi
 done
 
@@ -1172,53 +1760,63 @@ done
 # Check that the precious variables saved in the cache have kept the same
 # value.
 ac_cache_corrupted=false
-for ac_var in `(set) 2>&1 |
-	       sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+for ac_var in $ac_precious_vars; do
   eval ac_old_set=\$ac_cv_env_${ac_var}_set
   eval ac_new_set=\$ac_env_${ac_var}_set
-  eval ac_old_val="\$ac_cv_env_${ac_var}_value"
-  eval ac_new_val="\$ac_env_${ac_var}_value"
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
   case $ac_old_set,$ac_new_set in
     set,)
-      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
       ac_cache_corrupted=: ;;
     ,set)
-      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
-echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
       ac_cache_corrupted=: ;;
     ,);;
     *)
       if test "x$ac_old_val" != "x$ac_new_val"; then
-	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
-echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
-	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
-echo "$as_me:   former value:  $ac_old_val" >&2;}
-	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
-echo "$as_me:   current value: $ac_new_val" >&2;}
-	ac_cache_corrupted=:
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
       fi;;
   esac
   # Pass precious variables to config.status.
   if test "$ac_new_set" = set; then
     case $ac_new_val in
-    *" "*|*"	"*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
-      ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
     *) ac_arg=$ac_var=$ac_new_val ;;
     esac
     case " $ac_configure_args " in
       *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
-      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
     esac
   fi
 done
 if $ac_cache_corrupted; then
-  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
-echo "$as_me: error: changes in the environment can compromise the build" >&2;}
-  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
-echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
-   { (exit 1); exit 1; }; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
 fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -1230,23 +1828,6 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -1255,10 +1836,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}gcc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
@@ -1268,35 +1849,37 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}gcc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
 fi
 if test -z "$ac_cv_prog_CC"; then
   ac_ct_CC=$CC
   # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
   ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
@@ -1306,39 +1889,50 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="gcc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-  CC=$ac_ct_CC
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
 else
   CC="$ac_cv_prog_CC"
 fi
 
 if test -z "$CC"; then
-  if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
 set dummy ${ac_tool_prefix}cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
@@ -1348,77 +1942,37 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="${ac_tool_prefix}cc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
-else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
-fi
-
-fi
-if test -z "$ac_cv_prog_CC"; then
-  ac_ct_CC=$CC
-  # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  if test -n "$ac_ct_CC"; then
-  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_CC="cc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-done
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
-  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-  CC=$ac_ct_CC
-else
-  CC="$ac_cv_prog_CC"
-fi
 
+  fi
 fi
 if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
@@ -1429,18 +1983,19 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
        ac_prog_rejected=yes
        continue
      fi
     ac_cv_prog_CC="cc"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 if test $ac_prog_rejected = yes; then
   # We found a bogon in the path, so make sure we never use it.
@@ -1458,24 +2013,25 @@ fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
 fi
 if test -z "$CC"; then
   if test -n "$ac_tool_prefix"; then
-  for ac_prog in cl
+  for ac_prog in cl.exe
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$CC"; then
   ac_cv_prog_CC="$CC" # Let the user override the test.
@@ -1485,39 +2041,41 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 CC=$ac_cv_prog_CC
 if test -n "$CC"; then
-  echo "$as_me:$LINENO: result: $CC" >&5
-echo "${ECHO_T}$CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
     test -n "$CC" && break
   done
 fi
 if test -z "$CC"; then
   ac_ct_CC=$CC
-  for ac_prog in cl
+  for ac_prog in cl.exe
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CC"; then
   ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
@@ -1527,66 +2085,78 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CC="$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CC=$ac_cv_prog_ac_ct_CC
 if test -n "$ac_ct_CC"; then
-  echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
-echo "${ECHO_T}$ac_ct_CC" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
   test -n "$ac_ct_CC" && break
 done
 
-  CC=$ac_ct_CC
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
 fi
 
 fi
 
 
-test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&5
-echo "$as_me: error: no acceptable C compiler found in \$PATH
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
 
 # Provide some information about the compiler.
-echo "$as_me:$LINENO:" \
-     "checking for C compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
-  (eval $ac_compiler --version </dev/null >&5) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
-  (eval $ac_compiler -v </dev/null >&5) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
-  (eval $ac_compiler -V </dev/null >&5) 2>&5
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -1598,112 +2168,108 @@ main ()
 }
 _ACEOF
 ac_clean_files_save=$ac_clean_files
-ac_clean_files="$ac_clean_files a.out a.exe b.out"
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
 # Try to create an executable without -o first, disregard a.out.
 # It will help us diagnose broken compilers, and finding out an intuition
 # of exeext.
-echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
-echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6
-ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
-if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
-  (eval $ac_link_default) 2>&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
   ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  # Find the output, starting from the most likely.  This scheme is
-# not robust to junk in `.', hence go to wildcards (a.*) only as a last
-# resort.
-
-# Be careful to initialize this variable, since it used to be cached.
-# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
-ac_cv_exeext=
-# b.out is created by i960 compilers.
-for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
 do
   test -f "$ac_file" || continue
   case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj )
-	;;
-    conftest.$ac_ext )
-	# This is the source file.
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
 	;;
     [ab].out )
 	# We found the default executable, but exeext='' is most
 	# certainly right.
 	break;;
     *.* )
-	ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-	# FIXME: I believe we export ac_cv_exeext for Libtool,
-	# but it would be cool to find out if it's true.  Does anybody
-	# maintain Libtool? --akim.
-	export ac_cv_exeext
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
 	break;;
     * )
 	break;;
   esac
 done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
 else
-  echo "$as_me: failed program was:" >&5
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
-See \`config.log' for more details." >&5
-echo "$as_me: error: C compiler cannot create executables
-See \`config.log' for more details." >&2;}
-   { (exit 77); exit 77; }; }
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 fi
-
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
 ac_exeext=$ac_cv_exeext
-echo "$as_me:$LINENO: result: $ac_file" >&5
-echo "${ECHO_T}$ac_file" >&6
-
-# Check the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-echo "$as_me:$LINENO: checking whether the C compiler works" >&5
-echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
-# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
-# If not cross compiling, check that we can run a simple program.
-if test "$cross_compiling" != yes; then
-  if { ac_try='./$ac_file'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-    cross_compiling=no
-  else
-    if test "$cross_compiling" = maybe; then
-	cross_compiling=yes
-    else
-	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&5
-echo "$as_me: error: cannot run C compiled programs.
-If you meant to cross compile, use \`--host'.
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
-    fi
-  fi
-fi
-echo "$as_me:$LINENO: result: yes" >&5
-echo "${ECHO_T}yes" >&6
 
-rm -f a.out a.exe conftest$ac_cv_exeext b.out
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
 ac_clean_files=$ac_clean_files_save
-# Check the compiler produces executables we can run.  If not, either
-# the compiler is broken, or we cross compile.
-echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
-echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
-echo "$as_me:$LINENO: result: $cross_compiling" >&5
-echo "${ECHO_T}$cross_compiling" >&6
-
-echo "$as_me:$LINENO: checking for suffix of executables" >&5
-echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>&5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
   ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
   # If both `conftest.exe' and `conftest' are `present' (well, observable)
 # catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
 # work properly (i.e., refer to `conftest.exe'), while it won't with
@@ -1711,38 +2277,90 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
 for ac_file in conftest.exe conftest conftest.*; do
   test -f "$ac_file" || continue
   case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;;
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
     *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
-	  export ac_cv_exeext
 	  break;;
     * ) break;;
   esac
 done
 else
-  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&5
-echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
 fi
-
-rm -f conftest$ac_cv_exeext
-echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
-echo "${ECHO_T}$ac_cv_exeext" >&6
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
 
 rm -f conftest.$ac_ext
 EXEEXT=$ac_cv_exeext
 ac_exeext=$EXEEXT
-echo "$as_me:$LINENO: checking for suffix of object files" >&5
-echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
-if test "${ac_cv_objext+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
 _ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -1754,45 +2372,46 @@ main ()
 }
 _ACEOF
 rm -f conftest.o conftest.obj
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>&5
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
   ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; then
-  for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
   case $ac_file in
-    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;;
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
     *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
        break;;
   esac
 done
 else
-  echo "$as_me: failed program was:" >&5
+  $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&5
-echo "$as_me: error: cannot compute suffix of object files: cannot compile
-See \`config.log' for more details." >&2;}
-   { (exit 1); exit 1; }; }
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
 fi
-
 rm -f conftest.$ac_cv_objext conftest.$ac_ext
 fi
-echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
-echo "${ECHO_T}$ac_cv_objext" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
 OBJEXT=$ac_cv_objext
 ac_objext=$OBJEXT
-echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
-if test "${ac_cv_c_compiler_gnu+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -1806,55 +2425,34 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_c_compiler_gnu=$ac_compiler_gnu
 
 fi
-echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
-GCC=`test $ac_compiler_gnu = yes && echo yes`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
 ac_test_CFLAGS=${CFLAGS+set}
 ac_save_CFLAGS=$CFLAGS
-CFLAGS="-g"
-echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
-echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
-if test "${ac_cv_prog_cc_g+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -1865,39 +2463,49 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+if ac_fn_c_try_compile "$LINENO"; then :
   ac_cv_prog_cc_g=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
-ac_cv_prog_cc_g=no
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
 if test "$ac_test_CFLAGS" = set; then
   CFLAGS=$ac_save_CFLAGS
 elif test $ac_cv_prog_cc_g = yes; then
@@ -1913,23 +2521,18 @@ else
     CFLAGS=
   fi
 fi
-echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
-echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
-if test "${ac_cv_prog_cc_stdc+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  ac_cv_prog_cc_stdc=no
+  ac_cv_prog_cc_c89=no
 ac_save_CC=$CC
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <stdarg.h>
 #include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+struct stat;
 /* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
 struct buf { int x; };
 FILE * (*rcsopen) (struct buf *, struct stat *, int);
@@ -1952,12 +2555,17 @@ static char *f (char * (*g) (char **, int), char **p, ...)
 /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
    function prototypes and stuff, but not '\xHH' hex character constants.
    These don't provoke an error unfortunately, instead are silently treated
-   as 'x'.  The following induces an error, until -std1 is added to get
+   as 'x'.  The following induces an error, until -std is added to get
    proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
    array size at least.  It's necessary to write '\x00'==0 to get something
-   that's true only with -std1.  */
+   that's true only with -std.  */
 int osf4_cc_array ['\x00' == 0 ? 1 : -1];
 
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
 int test (int i, double x);
 struct s1 {int (*f) (int a);};
 struct s2 {int (*f) (double a);};
@@ -1972,225 +2580,61 @@ return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
   return 0;
 }
 _ACEOF
-# Don't try gcc -ansi; that turns off useful extensions and
-# breaks some systems' header files.
-# AIX			-qlanglvl=ansi
-# Ultrix and OSF/1	-std1
-# HP-UX 10.20 and later	-Ae
-# HP-UX older versions	-Aa -D_HPUX_SOURCE
-# SVR4			-Xc -D__EXTENSIONS__
-for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
 do
   CC="$ac_save_CC $ac_arg"
-  rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_prog_cc_stdc=$ac_arg
-break
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
 fi
-rm -f conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
 done
-rm -f conftest.$ac_ext conftest.$ac_objext
+rm -f conftest.$ac_ext
 CC=$ac_save_CC
 
 fi
-
-case "x$ac_cv_prog_cc_stdc" in
-  x|xno)
-    echo "$as_me:$LINENO: result: none needed" >&5
-echo "${ECHO_T}none needed" >&6 ;;
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
   *)
-    echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
-echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
-    CC="$CC $ac_cv_prog_cc_stdc" ;;
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
 esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
 
-# Some people use a C++ compiler to compile C.  Since we use `exit',
-# in C++ we need to declare it.  In case someone uses the same compiler
-# for both compiling C and C++ we need to have the C++ compiler decide
-# the declaration of exit, since it's the most demanding environment.
-cat >conftest.$ac_ext <<_ACEOF
-#ifndef __cplusplus
-  choke me
-#endif
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  for ac_declaration in \
-   '' \
-   'extern "C" void std::exit (int) throw (); using std::exit;' \
-   'extern "C" void std::exit (int); using std::exit;' \
-   'extern "C" void exit (int) throw ();' \
-   'extern "C" void exit (int);' \
-   'void exit (int);'
-do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_declaration
-#include <stdlib.h>
-int
-main ()
-{
-exit (42);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  :
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-continue
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-$ac_declaration
-int
-main ()
-{
-exit (42);
-  ;
-  return 0;
-}
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  break
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
-  echo '#ifdef __cplusplus' >>confdefs.h
-  echo $ac_declaration      >>confdefs.h
-  echo '#endif'             >>confdefs.h
 fi
 
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
-ac_ext=cc
+ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-if test -n "$ac_tool_prefix"; then
-  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_CXX+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$CXX"; then
   ac_cv_prog_CXX="$CXX" # Let the user override the test.
@@ -2200,39 +2644,41 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 CXX=$ac_cv_prog_CXX
 if test -n "$CXX"; then
-  echo "$as_me:$LINENO: result: $CXX" >&5
-echo "${ECHO_T}$CXX" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
     test -n "$CXX" && break
   done
 fi
 if test -z "$CXX"; then
   ac_ct_CXX=$CXX
-  for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_CXX"; then
   ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
@@ -2242,64 +2688,77 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_CXX="$ac_prog"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
 if test -n "$ac_ct_CXX"; then
-  echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
-echo "${ECHO_T}$ac_ct_CXX" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
   test -n "$ac_ct_CXX" && break
 done
-test -n "$ac_ct_CXX" || ac_ct_CXX="g++"
 
-  CXX=$ac_ct_CXX
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
 fi
 
-
-# Provide some information about the compiler.
-echo "$as_me:$LINENO:" \
-     "checking for C++ compiler version" >&5
-ac_compiler=`set X $ac_compile; echo $2`
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
-  (eval $ac_compiler --version </dev/null >&5) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
-  (eval $ac_compiler -v </dev/null >&5) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
-{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
-  (eval $ac_compiler -V </dev/null >&5) 2>&5
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
   ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
 
-echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
-echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6
-if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -2313,55 +2772,34 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_cxx_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+if ac_fn_cxx_try_compile "$LINENO"; then :
   ac_compiler_gnu=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_compiler_gnu=no
+  ac_compiler_gnu=no
 fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
 
 fi
-echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
-echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6
-GXX=`test $ac_compiler_gnu = yes && echo yes`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
 ac_test_CXXFLAGS=${CXXFLAGS+set}
 ac_save_CXXFLAGS=$CXXFLAGS
-CXXFLAGS="-g"
-echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
-echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6
-if test "${ac_cv_prog_cxx_g+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
 int
@@ -2372,160 +2810,64 @@ main ()
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_cxx_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
+if ac_fn_cxx_try_compile "$LINENO"; then :
   ac_cv_prog_cxx_g=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_prog_cxx_g=no
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
-echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6
-if test "$ac_test_CXXFLAGS" = set; then
-  CXXFLAGS=$ac_save_CXXFLAGS
-elif test $ac_cv_prog_cxx_g = yes; then
-  if test "$GXX" = yes; then
-    CXXFLAGS="-g -O2"
-  else
-    CXXFLAGS="-g"
-  fi
-else
-  if test "$GXX" = yes; then
-    CXXFLAGS="-O2"
-  else
-    CXXFLAGS=
-  fi
-fi
-for ac_declaration in \
-   '' \
-   'extern "C" void std::exit (int) throw (); using std::exit;' \
-   'extern "C" void std::exit (int); using std::exit;' \
-   'extern "C" void exit (int) throw ();' \
-   'extern "C" void exit (int);' \
-   'void exit (int);'
-do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+  CXXFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_declaration
-#include <stdlib.h>
+
 int
 main ()
 {
-exit (42);
+
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_cxx_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  :
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
+if ac_fn_cxx_try_compile "$LINENO"; then :
 
-continue
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+else
+  ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-$ac_declaration
+
 int
 main ()
 {
-exit (42);
+
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_cxx_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  break
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ac_cv_prog_cxx_g=yes
 fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-done
-rm -f conftest*
-if test -n "$ac_declaration"; then
-  echo '#ifdef __cplusplus' >>confdefs.h
-  echo $ac_declaration      >>confdefs.h
-  echo '#endif'             >>confdefs.h
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
 fi
-
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -2536,10 +2878,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_RANLIB+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$RANLIB"; then
   ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
@@ -2549,35 +2891,37 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
 fi
 fi
 RANLIB=$ac_cv_prog_RANLIB
 if test -n "$RANLIB"; then
-  echo "$as_me:$LINENO: result: $RANLIB" >&5
-echo "${ECHO_T}$RANLIB" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
 fi
 if test -z "$ac_cv_prog_RANLIB"; then
   ac_ct_RANLIB=$RANLIB
   # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   if test -n "$ac_ct_RANLIB"; then
   ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
@@ -2587,28 +2931,38 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_prog_ac_ct_RANLIB="ranlib"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
-  test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
 fi
 fi
 ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
 if test -n "$ac_ct_RANLIB"; then
-  echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
-echo "${ECHO_T}$ac_ct_RANLIB" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-  RANLIB=$ac_ct_RANLIB
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
 else
   RANLIB="$ac_cv_prog_RANLIB"
 fi
@@ -2649,11 +3003,11 @@ fi
   fi
 
 
-# Check whether --with-ld-shared or --without-ld-shared was given.
-if test "${with_ld_shared+set}" = set; then
-  withval="$with_ld_shared"
+# Check whether --with-ld-shared was given.
+if test "${with_ld_shared+set}" = set; then :
+  withval=$with_ld_shared;
+fi
 
-fi;
 
   if test "$with_ld_shared" != "" ; then
     if test "$with_ld_shared" = "no" ; then
@@ -2783,17 +3137,13 @@ fi;
 	if test "$GCC" = "yes"; then
 		C_WFLAGS="-Wall"
 
-cat >>confdefs.h <<\_ACEOF
-#define USE_GNUCC 1
-_ACEOF
+$as_echo "#define USE_GNUCC 1" >>confdefs.h
 
 	fi
 	if test "$GXX" = "yes"; then
 		CXX_WFLAGS="-Wall"
 
-cat >>confdefs.h <<\_ACEOF
-#define USE_GNUCC 1
-_ACEOF
+$as_echo "#define USE_GNUCC 1" >>confdefs.h
 
 	fi
 	CXX_WFLAGS=$CXX_WFLAGS
@@ -2804,11 +3154,11 @@ _ACEOF
 
 
 
-# Check whether --with-gdal or --without-gdal was given.
-if test "${with_gdal+set}" = set; then
-  withval="$with_gdal"
+# Check whether --with-gdal was given.
+if test "${with_gdal+set}" = set; then :
+  withval=$with_gdal;
+fi
 
-fi;
 
 if test "$with_gdal" = "yes" -o "$with_gdal" = "" ; then
 
@@ -2819,10 +3169,10 @@ if test "$with_gdal" = "yes" -o "$with_gdal" = "" ; then
   if test -z "$GDAL_CONFIG" ; then
     # Extract the first word of "gdal-config", so it can be a program name with args.
 set dummy gdal-config; ac_word=$2
-echo "$as_me:$LINENO: checking for $ac_word" >&5
-echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
-if test "${ac_cv_path_GDAL_CONFIG+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_GDAL_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   case $GDAL_CONFIG in
   [\\/]* | ?:[\\/]*)
@@ -2834,35 +3184,34 @@ for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-  for ac_exec_ext in '' $ac_executable_extensions; do
-  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
     ac_cv_path_GDAL_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
-done
+  done
+IFS=$as_save_IFS
 
   test -z "$ac_cv_path_GDAL_CONFIG" && ac_cv_path_GDAL_CONFIG="no"
   ;;
 esac
 fi
 GDAL_CONFIG=$ac_cv_path_GDAL_CONFIG
-
 if test -n "$GDAL_CONFIG"; then
-  echo "$as_me:$LINENO: result: $GDAL_CONFIG" >&5
-echo "${ECHO_T}$GDAL_CONFIG" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDAL_CONFIG" >&5
+$as_echo "$GDAL_CONFIG" >&6; }
 else
-  echo "$as_me:$LINENO: result: no" >&5
-echo "${ECHO_T}no" >&6
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
+
   fi
 
   if test "$GDAL_CONFIG" = "no" ; then
-    { { echo "$as_me:$LINENO: error: couldn't find gdal-config" >&5
-echo "$as_me: error: couldn't find gdal-config" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error $? "couldn't find gdal-config" "$LINENO" 5
   fi
 
 elif test -n "$with_gdal" -a "$with_gdal" != "no" ; then
@@ -2870,19 +3219,15 @@ elif test -n "$with_gdal" -a "$with_gdal" != "no" ; then
   GDAL_CONFIG=$with_gdal
 
   if test -f "$GDAL_CONFIG" -a -x "$GDAL_CONFIG" ; then
-    echo "$as_me:$LINENO: result: user supplied gdal-config ($GDAL_CONFIG)" >&5
-echo "${ECHO_T}user supplied gdal-config ($GDAL_CONFIG)" >&6
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: user supplied gdal-config ($GDAL_CONFIG)" >&5
+$as_echo "user supplied gdal-config ($GDAL_CONFIG)" >&6; }
   else
-    { { echo "$as_me:$LINENO: error: '$GDAL_CONFIG' is not an executable.  Make sure you use --with-gdal=/path/to/gdal-config" >&5
-echo "$as_me: error: '$GDAL_CONFIG' is not an executable.  Make sure you use --with-gdal=/path/to/gdal-config" >&2;}
-   { (exit 1); exit 1; }; }
+    as_fn_error $? "'$GDAL_CONFIG' is not an executable.  Make sure you use --with-gdal=/path/to/gdal-config" "$LINENO" 5
   fi
 
 else
 
-  { { echo "$as_me:$LINENO: error: gdal required to build GDAL GRASS driver" >&5
-echo "$as_me: error: gdal required to build GDAL GRASS driver" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "gdal required to build GDAL GRASS driver" "$LINENO" 5
 
 fi
 
@@ -2893,11 +3238,11 @@ GDAL_INC=$GDAL_INC
 
 
 
-# Check whether --with-autoload or --without-autoload was given.
-if test "${with_autoload+set}" = set; then
-  withval="$with_autoload"
+# Check whether --with-autoload was given.
+if test "${with_autoload+set}" = set; then :
+  withval=$with_autoload;
+fi
 
-fi;
 
 if test "$with_autoload" != "" ; then
   AUTOLOAD_DIR=$with_autoload
@@ -2909,8 +3254,8 @@ else
   fi
 fi
 
-echo "$as_me:$LINENO: result: using $AUTOLOAD_DIR as GDAL shared library autoload directory" >&5
-echo "${ECHO_T}using $AUTOLOAD_DIR as GDAL shared library autoload directory" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using $AUTOLOAD_DIR as GDAL shared library autoload directory" >&5
+$as_echo "using $AUTOLOAD_DIR as GDAL shared library autoload directory" >&6; }
 AUTOLOAD_DIR=$AUTOLOAD_DIR
 
 
@@ -2921,178 +3266,121 @@ GRASS_GISBASE=
 export GRASS_INCLUDE GRASS_SETTING GRASS_GISBASE
 
 
-# Check whether --with-grass or --without-grass was given.
-if test "${with_grass+set}" = set; then
-  withval="$with_grass"
+# Check whether --with-grass was given.
+if test "${with_grass+set}" = set; then :
+  withval=$with_grass;
+fi
 
-fi;
 
 if test "$with_grass" = "no" ; then
-  { { echo "$as_me:$LINENO: error: grass required for this driver, please install GRASS 5.7 or later and rebuild" >&5
-echo "$as_me: error: grass required for this driver, please install GRASS 5.7 or later and rebuild" >&2;}
-   { (exit 1); exit 1; }; }
+  as_fn_error $? "grass required for this driver, please install GRASS 5.7 or later and rebuild" "$LINENO" 5
 fi
 
 if test "$with_grass" != "yes" ; then
 
 
-echo "$as_me:$LINENO: checking for G_asprintf in -lgrass_gis" >&5
-echo $ECHO_N "checking for G_asprintf in -lgrass_gis... $ECHO_C" >&6
-if test "${ac_cv_lib_grass_gis_G_asprintf+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for G_is_initialized in -lgrass_gis" >&5
+$as_echo_n "checking for G_is_initialized in -lgrass_gis... " >&6; }
+if ${ac_cv_lib_grass_gis_G_is_initialized+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lgrass_gis -L$with_grass/lib -lgrass_I -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime -lgrass_gproj -lgrass_vect -lgrass_dbmibase -lgrass_dbmiclient -lgrass_dgl -lgrass_dig2 -lgrass_rtree -lgrass_linkm $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+LIBS="-lgrass_gis -L$with_grass/lib -lgrass_datetime $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
-/* Override any gcc2 internal prototype to avoid an error.  */
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
 #ifdef __cplusplus
 extern "C"
 #endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char G_asprintf ();
+char G_is_initialized ();
 int
 main ()
 {
-G_asprintf ();
+return G_is_initialized ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest$ac_exeext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_lib_grass_gis_G_asprintf=yes
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_grass_gis_G_is_initialized=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_grass_gis_G_asprintf=no
+  ac_cv_lib_grass_gis_G_is_initialized=no
 fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_grass_gis_G_asprintf" >&5
-echo "${ECHO_T}$ac_cv_lib_grass_gis_G_asprintf" >&6
-if test $ac_cv_lib_grass_gis_G_asprintf = yes; then
-  GRASS_SETTING=grass57+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_grass_gis_G_is_initialized" >&5
+$as_echo "$ac_cv_lib_grass_gis_G_is_initialized" >&6; }
+if test "x$ac_cv_lib_grass_gis_G_is_initialized" = xyes; then :
+  GRASS_SETTING=grass70+
 else
   GRASS_SETTING=no
 fi
 
-
-  if test "$GRASS_SETTING" = "grass57+" ; then
-    LIBS="-L$with_grass/lib -lgrass_I -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime -lgrass_gproj -lgrass_vect -lgrass_dbmibase -lgrass_dbmiclient -lgrass_dgl -lgrass_dig2 -lgrass_rtree -lgrass_linkm $LIBS"
-    GRASS_INCLUDE="-I$with_grass/include"
-    GRASS_GISBASE="$with_grass"
-  else
-
-    # Check for GRASS >= 7.0
-    echo "$as_me:$LINENO: checking for G_putenv in -lgrass_gis.7.0.svn" >&5
-echo $ECHO_N "checking for G_putenv in -lgrass_gis.7.0.svn... $ECHO_C" >&6
-if test "${ac_cv_lib_grass_gis_7_0_svn_G_putenv+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
+  if test "$GRASS_SETTING" = "no" ; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for G_asprintf in -lgrass_gis" >&5
+$as_echo_n "checking for G_asprintf in -lgrass_gis... " >&6; }
+if ${ac_cv_lib_grass_gis_G_asprintf+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lgrass_gis.7.0.svn -L$with_grass/lib -lgrass_raster.7.0.svn -lgrass_gmath.7.0.svn -lgrass_gis.7.0.svn -lgrass_datetime.7.0.svn -lgrass_gproj.7.0.svn -lgrass_vector.7.0.svn -lgrass_dbmibase.7.0.svn -lgrass_dbmiclient.7.0.svn -lgrass_dgl.7.0.svn -lgrass_dig2.7.0.svn -lgrass_rtree.7.0.svn -lgrass_linkm.7.0.svn -lgrass_btree2.7.0.svn -lgrass_ccmath.7.0.svn $LIBS"
-cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
+LIBS="-lgrass_gis -L$with_grass/lib -lgrass_datetime $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
-/* Override any gcc2 internal prototype to avoid an error.  */
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
 #ifdef __cplusplus
 extern "C"
 #endif
-/* We use char because int might match the return type of a gcc2
-   builtin and then its argument prototype would still apply.  */
-char G_putenv ();
+char G_asprintf ();
 int
 main ()
 {
-G_putenv ();
+return G_asprintf ();
   ;
   return 0;
 }
 _ACEOF
-rm -f conftest.$ac_objext conftest$ac_exeext
-if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
-  (eval $ac_link) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-	 { ac_try='test -z "$ac_c_werror_flag"
-			 || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-	 { ac_try='test -s conftest$ac_exeext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_lib_grass_gis_7_0_svn_G_putenv=yes
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_grass_gis_G_asprintf=yes
 else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-ac_cv_lib_grass_gis_7_0_svn_G_putenv=no
+  ac_cv_lib_grass_gis_G_asprintf=no
 fi
-rm -f conftest.err conftest.$ac_objext \
-      conftest$ac_exeext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-echo "$as_me:$LINENO: result: $ac_cv_lib_grass_gis_7_0_svn_G_putenv" >&5
-echo "${ECHO_T}$ac_cv_lib_grass_gis_7_0_svn_G_putenv" >&6
-if test $ac_cv_lib_grass_gis_7_0_svn_G_putenv = yes; then
-  GRASS_SETTING=grass7+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_grass_gis_G_asprintf" >&5
+$as_echo "$ac_cv_lib_grass_gis_G_asprintf" >&6; }
+if test "x$ac_cv_lib_grass_gis_G_asprintf" = xyes; then :
+  GRASS_SETTING=grass57+
 else
   GRASS_SETTING=no
 fi
 
-    if test "$GRASS_SETTING" = "grass7+" ; then
-        LIBS="-L$with_grass/lib -lgrass_raster.7.0.svn -lgrass_gmath.7.0.svn -lgrass_gis.7.0.svn -lgrass_datetime.7.0.svn -lgrass_gproj.7.0.svn -lgrass_vector.7.0.svn -lgrass_dbmibase.7.0.svn -lgrass_dbmiclient.7.0.svn -lgrass_dgl.7.0.svn -lgrass_dig2.7.0.svn -lgrass_rtree.7.0.svn -lgrass_linkm.7.0.svn -lgrass_btree2.7.0.svn -lgrass_ccmath.7.0.svn $LIBS"
-        GRASS_INCLUDE="-I$with_grass/include"
-        GRASS_GISBASE="$with_grass"
+  fi
+
+  if test "$GRASS_SETTING" != "no" ; then
+    if test "$GRASS_SETTING" = "grass70+" ; then
+      G_RASTLIBS="-lgrass_raster -lgrass_imagery"
+      G_VECTLIBS="-lgrass_vector -lgrass_dig2 -lgrass_dgl -lgrass_rtree -lgrass_linkm -lgrass_dbmiclient -lgrass_dbmibase"
+      LIBS="-L$with_grass/lib $G_VECTLIBS $G_RASTLIBS -lgrass_gproj -lgrass_gmath -lgrass_gis -lgrass_datetime $LIBS"
     else
-        { { echo "$as_me:$LINENO: error: --with-grass=$with_grass requested, but libraries not found!  Perhaps you need to set LD_LIBRARY_PATH to include $with_grass/lib?" >&5
-echo "$as_me: error: --with-grass=$with_grass requested, but libraries not found!  Perhaps you need to set LD_LIBRARY_PATH to include $with_grass/lib?" >&2;}
-   { (exit 1); exit 1; }; }
+      G_RASTLIBS="-lgrass_I"
+      G_VECTLIBS="-lgrass_vect -lgrass_dig2 -lgrass_dgl -lgrass_rtree -lgrass_linkm -lgrass_dbmiclient -lgrass_dbmibase"
+      LIBS="-L$with_grass/lib $G_VECTLIBS $G_RASTLIBS -lgrass_gproj -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime $LIBS"
     fi
+    GRASS_INCLUDE="-I$with_grass/include"
+    GRASS_GISBASE="$with_grass"
+    HAVE_GRASS=yes
+  else
+    as_fn_error $? "--with-grass=$with_grass requested, but libraries not found!" "$LINENO" 5
   fi
 fi
 
@@ -3102,72 +3390,84 @@ GRASS_GISBASE=$GRASS_GISBASE
 
 
 
+
+
+# Check whether --with-postgres_includes was given.
+if test "${with_postgres_includes+set}" = set; then :
+  withval=$with_postgres_includes; postgres_includes="$withval"
+else
+  postgres_includes=no
+fi
+
+
+PQ_INCLUDE=
+if test "x$postgres_includes" != "xno"; then
+# With PostgreSQL includes directory
+PQ_INCLUDE="-I$postgres_includes"
+fi
+
+
+
+
 rm -f conftest*
 
-          ac_config_files="$ac_config_files Makefile"
+ac_config_files="$ac_config_files Makefile"
+
 
 
 test "x$prefix" = xNONE && prefix=$ac_default_prefix
 # Let make expand exec_prefix.
 test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
 
-# VPATH may cause trouble with some makes, so we remove $(srcdir),
-# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
-# trailing colons and then remove the whole line if VPATH becomes empty
-# (actually we leave an empty line to preserve line numbers).
-if test "x$srcdir" = x.; then
-  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
-s/:*\$(srcdir):*/:/;
-s/:*\${srcdir}:*/:/;
-s/:*@srcdir@:*/:/;
-s/^\([^=]*=[	 ]*\):*/\1/;
-s/:*$//;
-s/^[^=]*=[	 ]*$//;
-}'
-fi
-
 # Transform confdefs.h into DEFS.
 # Protect against shell expansion while executing Makefile rules.
 # Protect against Makefile macro expansion.
 #
 # If the first sed substitution is executed (which looks for macros that
-# take arguments), then we branch to the quote section.  Otherwise,
+# take arguments), then branch to the quote section.  Otherwise,
 # look for a macro that doesn't take arguments.
-cat >confdef2opt.sed <<\_ACEOF
+ac_script='
+:mline
+/\\$/{
+ N
+ s,\\\n,,
+ b mline
+}
 t clear
-: clear
-s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\),-D\1=\2,g
+:clear
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 (][^	 (]*([^)]*)\)[	 ]*\(.*\)/-D\1=\2/g
 t quote
-s,^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\),-D\1=\2,g
+s/^[	 ]*#[	 ]*define[	 ][	 ]*\([^	 ][^	 ]*\)[	 ]*\(.*\)/-D\1=\2/g
 t quote
-d
-: quote
-s,[	 `~#$^&*(){}\\|;'"<>?],\\&,g
-s,\[,\\&,g
-s,\],\\&,g
-s,\$,$$,g
-p
-_ACEOF
-# We use echo to avoid assuming a particular line-breaking character.
-# The extra dot is to prevent the shell from consuming trailing
-# line-breaks from the sub-command output.  A line-break within
-# single-quotes doesn't work because, if this script is created in a
-# platform that uses two characters for line-breaks (e.g., DOS), tr
-# would break.
-ac_LF_and_DOT=`echo; echo .`
-DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
-rm -f confdef2opt.sed
+b any
+:quote
+s/[	 `~#$^&*(){}\\|;'\''"<>?]/\\&/g
+s/\[/\\&/g
+s/\]/\\&/g
+s/\$/$$/g
+H
+:any
+${
+	g
+	s/^\n//
+	s/\n/ /g
+	p
+}
+'
+DEFS=`sed -n "$ac_script" confdefs.h`
 
 
 ac_libobjs=
 ac_ltlibobjs=
+U=
 for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
   # 1. Remove the extension, and $U if already installed.
-  ac_i=`echo "$ac_i" |
-	 sed 's/\$U\././;s/\.o$//;s/\.obj$//'`
-  # 2. Add them.
-  ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext"
-  ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo'
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
 done
 LIBOBJS=$ac_libobjs
 
@@ -3175,12 +3475,14 @@ LTLIBOBJS=$ac_ltlibobjs
 
 
 
-: ${CONFIG_STATUS=./config.status}
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
 ac_clean_files_save=$ac_clean_files
 ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
-echo "$as_me: creating $CONFIG_STATUS" >&6;}
-cat >$CONFIG_STATUS <<_ACEOF
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
 #! $SHELL
 # Generated by $as_me.
 # Run this file to recreate the current configuration.
@@ -3190,81 +3492,253 @@ cat >$CONFIG_STATUS <<_ACEOF
 debug=false
 ac_cs_recheck=false
 ac_cs_silent=false
-SHELL=\${CONFIG_SHELL-$SHELL}
-_ACEOF
-
-cat >>$CONFIG_STATUS <<\_ACEOF
-## --------------------- ##
-## M4sh Initialization.  ##
-## --------------------- ##
 
-# Be Bourne compatible
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
   emulate sh
   NULLCMD=:
-  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
   # is contrary to our usage.  Disable this feature.
   alias -g '${1+"$@"}'='"$@"'
-elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
-  set -o posix
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
 fi
-DUALCASE=1; export DUALCASE # for MKS sh
 
-# Support unset when possible.
-if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
-  as_unset=unset
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
 else
-  as_unset=false
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
 fi
 
 
-# Work around bugs in pre-3.0 UWIN ksh.
-$as_unset ENV MAIL MAILPATH
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
 PS1='$ '
 PS2='> '
 PS4='+ '
 
 # NLS nuisances.
-for as_var in \
-  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
-  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
-  LC_TELEPHONE LC_TIME
-do
-  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
-    eval $as_var=C; export $as_var
-  else
-    $as_unset $as_var
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
   fi
-done
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
 
-# Required to use basename.
-if expr a : '\(a\)' >/dev/null 2>&1; then
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
   as_expr=expr
 else
   as_expr=false
 fi
 
-if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
   as_basename=basename
 else
   as_basename=false
 fi
 
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
 
-# Name of the executable.
-as_me=`$as_basename "$0" ||
+as_me=`$as_basename -- "$0" ||
 $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
 	 X"$0" : 'X\(//\)$' \| \
-	 X"$0" : 'X\(/\)$' \| \
-	 .     : '\(.\)' 2>/dev/null ||
-echo X/"$0" |
-    sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
-  	  /^X\/\(\/\/\)$/{ s//\1/; q; }
-  	  /^X\/\(\/\).*/{ s//\1/; q; }
-  	  s/.*/./; q'`
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
 
-
-# PATH needs CR, and LINENO needs CR and PATH.
 # Avoid depending upon Character Ranges.
 as_cr_letters='abcdefghijklmnopqrstuvwxyz'
 as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -3272,148 +3746,111 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
 as_cr_digits='0123456789'
 as_cr_alnum=$as_cr_Letters$as_cr_digits
 
-# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
-  echo "#! /bin/sh" >conf$$.sh
-  echo  "exit 0"   >>conf$$.sh
-  chmod +x conf$$.sh
-  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
-    PATH_SEPARATOR=';'
-  else
-    PATH_SEPARATOR=:
-  fi
-  rm -f conf$$.sh
-fi
-
-
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x$as_lineno_3"  = "x$as_lineno_2"  || {
-  # Find who we are.  Look in the path if we contain no path at all
-  # relative or not.
-  case $0 in
-    *[\\/]* ) as_myself=$0 ;;
-    *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
-done
-
-       ;;
-  esac
-  # We did not find ourselves, most probably we were run as `sh COMMAND'
-  # in which case we are not to be found in the path.
-  if test "x$as_myself" = x; then
-    as_myself=$0
-  fi
-  if test ! -f "$as_myself"; then
-    { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
-echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
-   { (exit 1); exit 1; }; }
-  fi
-  case $CONFIG_SHELL in
-  '')
-    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-  for as_base in sh bash ksh sh5; do
-	 case $as_dir in
-	 /*)
-	   if ("$as_dir/$as_base" -c '
-  as_lineno_1=$LINENO
-  as_lineno_2=$LINENO
-  as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
-  test "x$as_lineno_1" != "x$as_lineno_2" &&
-  test "x$as_lineno_3"  = "x$as_lineno_2" ') 2>/dev/null; then
-	     $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
-	     $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
-	     CONFIG_SHELL=$as_dir/$as_base
-	     export CONFIG_SHELL
-	     exec "$CONFIG_SHELL" "$0" ${1+"$@"}
-	   fi;;
-	 esac
-       done
-done
-;;
-  esac
-
-  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
-  # uniformly replaced by the line number.  The first 'sed' inserts a
-  # line-number line before each line; the second 'sed' does the real
-  # work.  The second script uses 'N' to pair each line-number line
-  # with the numbered line, and appends trailing '-' during
-  # substitution so that $LINENO is not a special case at line end.
-  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
-  # second 'sed' script.  Blame Lee E. McMahon for sed's syntax.  :-)
-  sed '=' <$as_myself |
-    sed '
-      N
-      s,$,-,
-      : loop
-      s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
-      t loop
-      s,-$,,
-      s,^['$as_cr_digits']*\n,,
-    ' >$as_me.lineno &&
-  chmod +x $as_me.lineno ||
-    { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
-echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
-   { (exit 1); exit 1; }; }
-
-  # Don't try to exec as it changes $[0], causing all sort of problems
-  # (the dirname of $[0] is not the place where we might find the
-  # original and so on.  Autoconf is especially sensible to this).
-  . ./$as_me.lineno
-  # Exit status is that of the last command.
-  exit
-}
-
-
-case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
-  *c*,-n*) ECHO_N= ECHO_C='
-' ECHO_T='	' ;;
-  *c*,*  ) ECHO_N=-n ECHO_C= ECHO_T= ;;
-  *)       ECHO_N= ECHO_C='\c' ECHO_T= ;;
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
 esac
 
-if expr a : '\(a\)' >/dev/null 2>&1; then
-  as_expr=expr
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
 else
-  as_expr=false
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
 fi
-
-rm -f conf$$ conf$$.exe conf$$.file
-echo >conf$$.file
-if ln -s conf$$.file conf$$ 2>/dev/null; then
-  # We could just check for DJGPP; but this test a) works b) is more generic
-  # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
-  if test -f conf$$.exe; then
-    # Don't use ln at all; we don't have any links
-    as_ln_s='cp -p'
-  else
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
     as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
   fi
-elif ln conf$$.file conf$$ 2>/dev/null; then
-  as_ln_s=ln
 else
-  as_ln_s='cp -p'
+  as_ln_s='cp -pR'
 fi
-rm -f conf$$ conf$$.exe conf$$.file
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
 
+} # as_fn_mkdir_p
 if mkdir -p . 2>/dev/null; then
-  as_mkdir_p=:
+  as_mkdir_p='mkdir -p "$as_dir"'
 else
   test -d ./-p && rmdir ./-p
   as_mkdir_p=false
 fi
 
-as_executable_p="test -f"
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
 
 # Sed expression to map a string onto a valid CPP name.
 as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
@@ -3422,31 +3859,20 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
 as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
 
 
-# IFS
-# We need space, tab and new line, in precisely that order.
-as_nl='
-'
-IFS=" 	$as_nl"
-
-# CDPATH.
-$as_unset CDPATH
-
 exec 6>&1
-
-# Open the log real soon, to keep \$[0] and so on meaningful, and to
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
 # report actual input values of CONFIG_FILES etc. instead of their
-# values after options handling.  Logging --version etc. is OK.
-exec 5>>config.log
-{
-  echo
-  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
-## Running $as_me. ##
-_ASBOX
-} >&5
-cat >&5 <<_CSEOF
-
+# values after options handling.
+ac_log="
 This file was extended by $as_me, which was
-generated by GNU Autoconf 2.59.  Invocation command line was
+generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_HEADERS  = $CONFIG_HEADERS
@@ -3454,124 +3880,116 @@ generated by GNU Autoconf 2.59.  Invocation command line was
   CONFIG_COMMANDS = $CONFIG_COMMANDS
   $ $0 $@
 
-_CSEOF
-echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
-echo >&5
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
 _ACEOF
 
-# Files that config.status was made for.
-if test -n "$ac_config_files"; then
-  echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
-fi
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
 
-if test -n "$ac_config_headers"; then
-  echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
-fi
 
-if test -n "$ac_config_links"; then
-  echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
-fi
 
-if test -n "$ac_config_commands"; then
-  echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
-fi
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
 
-cat >>$CONFIG_STATUS <<\_ACEOF
+_ACEOF
 
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 ac_cs_usage="\
-\`$as_me' instantiates files from templates according to the
-current configuration.
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
 
-Usage: $0 [OPTIONS] [FILE]...
+Usage: $0 [OPTION]... [TAG]...
 
   -h, --help       print this help, then exit
-  -V, --version    print version number, then exit
-  -q, --quiet      do not print progress messages
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
   -d, --debug      don't remove temporary files
       --recheck    update $as_me by reconfiguring in the same conditions
-  --file=FILE[:TEMPLATE]
-		   instantiate the configuration file FILE
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
 
 Configuration files:
 $config_files
 
-Report bugs to <bug-autoconf at gnu.org>."
-_ACEOF
+Report bugs to the package provider."
 
-cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
 config.status
-configured by $0, generated by GNU Autoconf 2.59,
-  with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
 
-Copyright (C) 2003 Free Software Foundation, Inc.
+Copyright (C) 2012 Free Software Foundation, Inc.
 This config.status script is free software; the Free Software Foundation
 gives unlimited permission to copy, distribute and modify it."
-srcdir=$srcdir
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+test -n "\$AWK" || AWK=awk
 _ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
-# If no file are specified by the user, then we need to provide default
-# value.  By we need to know if files were specified by the user.
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
 ac_need_defaults=:
 while test $# != 0
 do
   case $1 in
-  --*=*)
-    ac_option=`expr "x$1" : 'x\([^=]*\)='`
-    ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
     ac_shift=:
     ;;
-  -*)
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
     ac_option=$1
     ac_optarg=$2
     ac_shift=shift
     ;;
-  *) # This is not an option, so the user has probably given explicit
-     # arguments.
-     ac_option=$1
-     ac_need_defaults=false;;
   esac
 
   case $ac_option in
   # Handling of the options.
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
   -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
     ac_cs_recheck=: ;;
-  --version | --vers* | -V )
-    echo "$ac_cs_version"; exit 0 ;;
-  --he | --h)
-    # Conflict between --help and --header
-    { { echo "$as_me:$LINENO: error: ambiguous option: $1
-Try \`$0 --help' for more information." >&5
-echo "$as_me: error: ambiguous option: $1
-Try \`$0 --help' for more information." >&2;}
-   { (exit 1); exit 1; }; };;
-  --help | --hel | -h )
-    echo "$ac_cs_usage"; exit 0 ;;
-  --debug | --d* | -d )
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
     debug=: ;;
   --file | --fil | --fi | --f )
     $ac_shift
-    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
-    ac_need_defaults=false;;
-  --header | --heade | --head | --hea )
-    $ac_shift
-    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
     ac_need_defaults=false;;
+  --he | --h |  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
   -q | -quiet | --quiet | --quie | --qui | --qu | --q \
   | -silent | --silent | --silen | --sile | --sil | --si | --s)
     ac_cs_silent=: ;;
 
   # This is an error.
-  -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&5
-echo "$as_me: error: unrecognized option: $1
-Try \`$0 --help' for more information." >&2;}
-   { (exit 1); exit 1; }; } ;;
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
 
-  *) ac_config_targets="$ac_config_targets $1" ;;
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
 
   esac
   shift
@@ -3585,30 +4003,44 @@ if $ac_cs_silent; then
 fi
 
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 if \$ac_cs_recheck; then
-  echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
-  exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
 fi
 
 _ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
 
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACEOF
 
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 
-
-
-cat >>$CONFIG_STATUS <<\_ACEOF
+# Handling of arguments.
 for ac_config_target in $ac_config_targets
 do
-  case "$ac_config_target" in
-  # Handling of arguments.
-  "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
-echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
-   { (exit 1); exit 1; }; };;
+  case $ac_config_target in
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
 done
 
+
 # If the user did not use the arguments to specify the items to instantiate,
 # then the envvar interface is used.  Set only those that are not.
 # We use the long form for the default assignment because of an extremely
@@ -3618,340 +4050,414 @@ if $ac_need_defaults; then
 fi
 
 # Have a temporary directory for convenience.  Make it in the build tree
-# simply because there is no reason to put it here, and in addition,
+# simply because there is no reason against having it here, and in addition,
 # creating and moving files from /tmp can sometimes cause problems.
-# Create a temporary directory, and hook for its removal unless debugging.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
 $debug ||
 {
-  trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
-  trap '{ (exit 1); exit 1; }' 1 2 13 15
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
 }
-
 # Create a (secure) tmp directory for tmp files.
 
 {
-  tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
-  test -n "$tmp" && test -d "$tmp"
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
 }  ||
 {
-  tmp=./confstat$$-$RANDOM
-  (umask 077 && mkdir $tmp)
-} ||
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
 {
-   echo "$me: cannot create a temporary directory in ." >&2
-   { (exit 1); exit 1; }
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
 }
 
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
 _ACEOF
 
-cat >>$CONFIG_STATUS <<_ACEOF
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
 
-#
-# CONFIG_FILES section.
-#
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
 
-# No need to generate the scripts if there are no CONFIG_FILES.
-# This happens for instance when ./config.status config.h
-if test -n "\$CONFIG_FILES"; then
-  # Protect against being on the right side of a sed subst in config.status.
-  sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
-   s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
-s, at SHELL@,$SHELL,;t t
-s, at PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
-s, at PACKAGE_NAME@,$PACKAGE_NAME,;t t
-s, at PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
-s, at PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
-s, at PACKAGE_STRING@,$PACKAGE_STRING,;t t
-s, at PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
-s, at exec_prefix@,$exec_prefix,;t t
-s, at prefix@,$prefix,;t t
-s, at program_transform_name@,$program_transform_name,;t t
-s, at bindir@,$bindir,;t t
-s, at sbindir@,$sbindir,;t t
-s, at libexecdir@,$libexecdir,;t t
-s, at datadir@,$datadir,;t t
-s, at sysconfdir@,$sysconfdir,;t t
-s, at sharedstatedir@,$sharedstatedir,;t t
-s, at localstatedir@,$localstatedir,;t t
-s, at libdir@,$libdir,;t t
-s, at includedir@,$includedir,;t t
-s, at oldincludedir@,$oldincludedir,;t t
-s, at infodir@,$infodir,;t t
-s, at mandir@,$mandir,;t t
-s, at build_alias@,$build_alias,;t t
-s, at host_alias@,$host_alias,;t t
-s, at target_alias@,$target_alias,;t t
-s, at DEFS@,$DEFS,;t t
-s, at ECHO_C@,$ECHO_C,;t t
-s, at ECHO_N@,$ECHO_N,;t t
-s, at ECHO_T@,$ECHO_T,;t t
-s, at LIBS@,$LIBS,;t t
-s, at CC@,$CC,;t t
-s, at CFLAGS@,$CFLAGS,;t t
-s, at LDFLAGS@,$LDFLAGS,;t t
-s, at CPPFLAGS@,$CPPFLAGS,;t t
-s, at ac_ct_CC@,$ac_ct_CC,;t t
-s, at EXEEXT@,$EXEEXT,;t t
-s, at OBJEXT@,$OBJEXT,;t t
-s, at CXX@,$CXX,;t t
-s, at CXXFLAGS@,$CXXFLAGS,;t t
-s, at ac_ct_CXX@,$ac_ct_CXX,;t t
-s, at RANLIB@,$RANLIB,;t t
-s, at ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
-s, at CXX_PIC@,$CXX_PIC,;t t
-s, at C_PIC@,$C_PIC,;t t
-s, at LD_SHARED@,$LD_SHARED,;t t
-s, at SO_EXT@,$SO_EXT,;t t
-s, at CXX_WFLAGS@,$CXX_WFLAGS,;t t
-s, at C_WFLAGS@,$C_WFLAGS,;t t
-s, at GDAL_CONFIG@,$GDAL_CONFIG,;t t
-s, at GDAL_INC@,$GDAL_INC,;t t
-s, at AUTOLOAD_DIR@,$AUTOLOAD_DIR,;t t
-s, at GRASS_INCLUDE@,$GRASS_INCLUDE,;t t
-s, at GRASS_GISBASE@,$GRASS_GISBASE,;t t
-s, at LIBOBJS@,$LIBOBJS,;t t
-s, at LTLIBOBJS@,$LTLIBOBJS,;t t
-CEOF
 
-_ACEOF
+eval set X "  :F $CONFIG_FILES      "
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
 
-  cat >>$CONFIG_STATUS <<\_ACEOF
-  # Split the substitutions into bite-sized pieces for seds with
-  # small command number limits, like on Digital OSF/1 and HP-UX.
-  ac_max_sed_lines=48
-  ac_sed_frag=1 # Number of current file.
-  ac_beg=1 # First line for current file.
-  ac_end=$ac_max_sed_lines # Line after last line for current file.
-  ac_more_lines=:
-  ac_sed_cmds=
-  while $ac_more_lines; do
-    if test $ac_beg -gt 1; then
-      sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
-    else
-      sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
-    fi
-    if test ! -s $tmp/subs.frag; then
-      ac_more_lines=false
-    else
-      # The purpose of the label and of the branching condition is to
-      # speed up the sed processing (if there are no `@' at all, there
-      # is no need to browse any of the substitutions).
-      # These are the two extra sed commands mentioned above.
-      (echo ':t
-  /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
-      if test -z "$ac_sed_cmds"; then
-	ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
-      else
-	ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
-      fi
-      ac_sed_frag=`expr $ac_sed_frag + 1`
-      ac_beg=$ac_end
-      ac_end=`expr $ac_end + $ac_max_sed_lines`
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
     fi
-  done
-  if test -z "$ac_sed_cmds"; then
-    ac_sed_cmds=cat
-  fi
-fi # test -n "$CONFIG_FILES"
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
 
-_ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
-for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
-  # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
-  case $ac_file in
-  - | *:- | *:-:* ) # input from stdin
-	cat >$tmp/stdin
-	ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
-	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
-  *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
-	ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
-  * )   ac_file_in=$ac_file.in ;;
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
   esac
 
-  # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
-  ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+  ac_dir=`$as_dirname -- "$ac_file" ||
 $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
 	 X"$ac_file" : 'X\(//\)[^/]' \| \
 	 X"$ac_file" : 'X\(//\)$' \| \
-	 X"$ac_file" : 'X\(/\)' \| \
-	 .     : '\(.\)' 2>/dev/null ||
-echo X"$ac_file" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
-  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
-  	  /^X\(\/\/\)$/{ s//\1/; q; }
-  	  /^X\(\/\).*/{ s//\1/; q; }
-  	  s/.*/./; q'`
-  { if $as_mkdir_p; then
-    mkdir -p "$ac_dir"
-  else
-    as_dir="$ac_dir"
-    as_dirs=
-    while test ! -d "$as_dir"; do
-      as_dirs="$as_dir $as_dirs"
-      as_dir=`(dirname "$as_dir") 2>/dev/null ||
-$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
-	 X"$as_dir" : 'X\(//\)[^/]' \| \
-	 X"$as_dir" : 'X\(//\)$' \| \
-	 X"$as_dir" : 'X\(/\)' \| \
-	 .     : '\(.\)' 2>/dev/null ||
-echo X"$as_dir" |
-    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
-  	  /^X\(\/\/\)[^/].*/{ s//\1/; q; }
-  	  /^X\(\/\/\)$/{ s//\1/; q; }
-  	  /^X\(\/\).*/{ s//\1/; q; }
-  	  s/.*/./; q'`
-    done
-    test ! -n "$as_dirs" || mkdir $as_dirs
-  fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5
-echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
-   { (exit 1); exit 1; }; }; }
-
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
   ac_builddir=.
 
-if test "$ac_dir" != .; then
-  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
-  # A "../" for each directory in $ac_dir_suffix.
-  ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
-else
-  ac_dir_suffix= ac_top_builddir=
-fi
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
 
 case $srcdir in
-  .)  # No --srcdir option.  We are building in place.
+  .)  # We are building in place.
     ac_srcdir=.
-    if test -z "$ac_top_builddir"; then
-       ac_top_srcdir=.
-    else
-       ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
-    fi ;;
-  [\\/]* | ?:[\\/]* )  # Absolute path.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
     ac_srcdir=$srcdir$ac_dir_suffix;
-    ac_top_srcdir=$srcdir ;;
-  *) # Relative path.
-    ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
-    ac_top_srcdir=$ac_top_builddir$srcdir ;;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
 esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
 
-# Do not use `cd foo && pwd` to compute absolute paths, because
-# the directories may not exist.
-case `pwd` in
-.) ac_abs_builddir="$ac_dir";;
-*)
-  case "$ac_dir" in
-  .) ac_abs_builddir=`pwd`;;
-  [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
-  *) ac_abs_builddir=`pwd`/"$ac_dir";;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_top_builddir=${ac_top_builddir}.;;
-*)
-  case ${ac_top_builddir}. in
-  .) ac_abs_top_builddir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
-  *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_srcdir=$ac_srcdir;;
-*)
-  case $ac_srcdir in
-  .) ac_abs_srcdir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
-  *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
-  esac;;
-esac
-case $ac_abs_builddir in
-.) ac_abs_top_srcdir=$ac_top_srcdir;;
-*)
-  case $ac_top_srcdir in
-  .) ac_abs_top_srcdir=$ac_abs_builddir;;
-  [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
-  *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
-  esac;;
-esac
 
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
 
+_ACEOF
 
-  if test x"$ac_file" != x-; then
-    { echo "$as_me:$LINENO: creating $ac_file" >&5
-echo "$as_me: creating $ac_file" >&6;}
-    rm -f "$ac_file"
-  fi
-  # Let's still pretend it is `configure' which instantiates (i.e., don't
-  # use $as_me), people would be surprised to read:
-  #    /* config.h.  Generated by config.status.  */
-  if test x"$ac_file" = x-; then
-    configure_input=
-  else
-    configure_input="$ac_file.  "
-  fi
-  configure_input=$configure_input"Generated from `echo $ac_file_in |
-				     sed 's,.*/,,'` by configure."
-
-  # First look for the input files in the build tree, otherwise in the
-  # src tree.
-  ac_file_inputs=`IFS=:
-    for f in $ac_file_in; do
-      case $f in
-      -) echo $tmp/stdin ;;
-      [\\/$]*)
-	 # Absolute (can't be DOS-style, as IFS=:)
-	 test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
-echo "$as_me: error: cannot find input file: $f" >&2;}
-   { (exit 1); exit 1; }; }
-	 echo "$f";;
-      *) # Relative
-	 if test -f "$f"; then
-	   # Build tree
-	   echo "$f"
-	 elif test -f "$srcdir/$f"; then
-	   # Source tree
-	   echo "$srcdir/$f"
-	 else
-	   # /dev/null tree
-	   { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
-echo "$as_me: error: cannot find input file: $f" >&2;}
-   { (exit 1); exit 1; }; }
-	 fi;;
-      esac
-    done` || { (exit 1); exit 1; }
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
 _ACEOF
-cat >>$CONFIG_STATUS <<_ACEOF
-  sed "$ac_vpsub
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
 $extrasub
 _ACEOF
-cat >>$CONFIG_STATUS <<\_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 :t
 /@[a-zA-Z_][a-zA-Z_0-9]*@/!b
-s, at configure_input@,$configure_input,;t t
-s, at srcdir@,$ac_srcdir,;t t
-s, at abs_srcdir@,$ac_abs_srcdir,;t t
-s, at top_srcdir@,$ac_top_srcdir,;t t
-s, at abs_top_srcdir@,$ac_abs_top_srcdir,;t t
-s, at builddir@,$ac_builddir,;t t
-s, at abs_builddir@,$ac_abs_builddir,;t t
-s, at top_builddir@,$ac_top_builddir,;t t
-s, at abs_top_builddir@,$ac_abs_top_builddir,;t t
-" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
-  rm -f $tmp/stdin
-  if test x"$ac_file" != x-; then
-    mv $tmp/out $ac_file
-  else
-    cat $tmp/out
-    rm -f $tmp/out
-  fi
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
 
-done
-_ACEOF
 
-cat >>$CONFIG_STATUS <<\_ACEOF
 
-{ (exit 0); exit 0; }
+  esac
+
+done # for ac_tag
+
+
+as_fn_exit 0
 _ACEOF
-chmod +x $CONFIG_STATUS
 ac_clean_files=$ac_clean_files_save
 
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
 
 # configure is writing to config.log, and then calls config.status.
 # config.status does its own redirection, appending to config.log.
@@ -3971,7 +4477,11 @@ if test "$no_create" != yes; then
   exec 5>>config.log
   # Use ||, not &&, to avoid exiting from the if with $? = 1, which
   # would make configure fail if this is the last instruction.
-  $ac_cs_success || { (exit 1); exit 1; }
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
 fi
 
 
diff --git a/frmts/grass/pkg/configure.in b/frmts/grass/pkg/configure.in
index 099a9e1..0ac90cb 100644
--- a/frmts/grass/pkg/configure.in
+++ b/frmts/grass/pkg/configure.in
@@ -1,5 +1,5 @@
 dnl ***************************************************************************
-dnl $Id: configure.in 20157 2010-07-28 19:32:04Z rouault $
+dnl $Id: configure.in 28598 2015-03-03 07:34:28Z martinl $
 dnl
 dnl Project:  GDAL GRASS Plugin
 dnl Purpose:  Configure source file.
@@ -91,7 +91,7 @@ AC_SUBST(GDAL_INC,    $GDAL_INC)
 dnl ---------------------------------------------------------------------------
 dnl Where to put driver?
 dnl ---------------------------------------------------------------------------
-AC_ARG_WITH(autoload,[  --with-autoload[=DIR]      Directory for autoload drivers],,)
+AC_ARG_WITH(autoload,[  --with-autoload[=DIR]     Directory for autoload drivers],,)
 
 if test "$with_autoload" != "" ; then
   AUTOLOAD_DIR=$with_autoload
@@ -123,23 +123,26 @@ fi
 
 if test "$with_grass" != "yes" ; then
 
-  AC_CHECK_LIB(grass_gis,G_asprintf,GRASS_SETTING=grass57+,GRASS_SETTING=no,-L$with_grass/lib -lgrass_I -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime -lgrass_gproj -lgrass_vect -lgrass_dbmibase -lgrass_dbmiclient -lgrass_dgl -lgrass_dig2 -lgrass_rtree -lgrass_linkm)
+  AC_CHECK_LIB(grass_gis,G_is_initialized,GRASS_SETTING=grass70+,GRASS_SETTING=no,-L$with_grass/lib -lgrass_datetime)
+  if test "$GRASS_SETTING" = "no" ; then
+    AC_CHECK_LIB(grass_gis,G_asprintf,GRASS_SETTING=grass57+,GRASS_SETTING=no,-L$with_grass/lib -lgrass_datetime)
+  fi
    
-  if test "$GRASS_SETTING" = "grass57+" ; then   
-    LIBS="-L$with_grass/lib -lgrass_I -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime -lgrass_gproj -lgrass_vect -lgrass_dbmibase -lgrass_dbmiclient -lgrass_dgl -lgrass_dig2 -lgrass_rtree -lgrass_linkm $LIBS"
+  if test "$GRASS_SETTING" != "no" ; then   
+    if test "$GRASS_SETTING" = "grass70+" ; then   
+      G_RASTLIBS="-lgrass_raster -lgrass_imagery"
+      G_VECTLIBS="-lgrass_vector -lgrass_dig2 -lgrass_dgl -lgrass_rtree -lgrass_linkm -lgrass_dbmiclient -lgrass_dbmibase"
+      LIBS="-L$with_grass/lib $G_VECTLIBS $G_RASTLIBS -lgrass_gproj -lgrass_gmath -lgrass_gis -lgrass_datetime $LIBS"
+    else
+      G_RASTLIBS="-lgrass_I"
+      G_VECTLIBS="-lgrass_vect -lgrass_dig2 -lgrass_dgl -lgrass_rtree -lgrass_linkm -lgrass_dbmiclient -lgrass_dbmibase"
+      LIBS="-L$with_grass/lib $G_VECTLIBS $G_RASTLIBS -lgrass_gproj -lgrass_vask -lgrass_gmath -lgrass_gis -lgrass_datetime $LIBS"
+    fi
     GRASS_INCLUDE="-I$with_grass/include"
     GRASS_GISBASE="$with_grass"
+    HAVE_GRASS=yes
   else
-
-    # Check for GRASS >= 7.0
-    AC_CHECK_LIB(grass_gis.7.0.svn,G_putenv,GRASS_SETTING=grass7+,GRASS_SETTING=no,-L$with_grass/lib -lgrass_raster.7.0.svn -lgrass_gmath.7.0.svn -lgrass_gis.7.0.svn -lgrass_datetime.7.0.svn -lgrass_gproj.7.0.svn -lgrass_vector.7.0.svn -lgrass_dbmibase.7.0.svn -lgrass_dbmiclient.7.0.svn -lgrass_dgl.7.0.svn -lgrass_dig2.7.0.svn -lgrass_rtree.7.0.svn -lgrass_linkm.7.0.svn -lgrass_btree2.7.0.svn -lgrass_ccmath.7.0.svn)
-    if test "$GRASS_SETTING" = "grass7+" ; then
-        LIBS="-L$with_grass/lib -lgrass_raster.7.0.svn -lgrass_gmath.7.0.svn -lgrass_gis.7.0.svn -lgrass_datetime.7.0.svn -lgrass_gproj.7.0.svn -lgrass_vector.7.0.svn -lgrass_dbmibase.7.0.svn -lgrass_dbmiclient.7.0.svn -lgrass_dgl.7.0.svn -lgrass_dig2.7.0.svn -lgrass_rtree.7.0.svn -lgrass_linkm.7.0.svn -lgrass_btree2.7.0.svn -lgrass_ccmath.7.0.svn $LIBS"
-        GRASS_INCLUDE="-I$with_grass/include"
-        GRASS_GISBASE="$with_grass"
-    else
-        AC_MSG_ERROR([--with-grass=$with_grass requested, but libraries not found!  Perhaps you need to set LD_LIBRARY_PATH to include $with_grass/lib?])
-    fi
+    AC_MSG_ERROR([--with-grass=$with_grass requested, but libraries not found!])
   fi
 fi
 
@@ -148,6 +151,22 @@ AC_SUBST(GRASS_GISBASE,$GRASS_GISBASE)
 
 dnl ---------------------------------------------------------------------------
 
+dnl ---------------------------------------------------------------------------
+dnl Find PostgreSQL (GRASS optional dependency)
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(postgres_includes,[  --with-postgres-includes=DIR     use PostgreSQL includes in DIR], postgres_includes="$withval", postgres_includes=no)
+
+PQ_INCLUDE=
+if test "x$postgres_includes" != "xno"; then
+# With PostgreSQL includes directory
+PQ_INCLUDE="-I$postgres_includes"
+fi
+
+AC_SUBST(PQ_INCLUDE)
+
+dnl ---------------------------------------------------------------------------
+
 rm -f conftest*
 
 AC_OUTPUT(Makefile)
diff --git a/frmts/grib/GNUmakefile b/frmts/grib/GNUmakefile
index a560894..65fec6a 100644
--- a/frmts/grib/GNUmakefile
+++ b/frmts/grib/GNUmakefile
@@ -14,33 +14,33 @@ ifeq ($(HAVE_JASPER),yes)
 EXTRAFLAGS	:= 	$(EXTRAFLAGS) -DHAVE_JASPER
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(EXTRAFLAGS)
+CPPFLAGS	:=	 $(CPPFLAGS) $(EXTRAFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
 ../o/%.$(OBJ_EXT):	degrib18/degrib/%.c
-	$(CC) -c $(CPPFLAGS) $(CFLAGS) -Idegrib18/g2clib-1.0.4 $< -o $@
+	$(CC) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CFLAGS) -Idegrib18/g2clib-1.0.4 $< -o $@
 
 ../o/%.$(OBJ_EXT):	degrib18/degrib/%.cpp
-	$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+	$(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
 
 ../o/%.$(OBJ_EXT):	degrib18/g2clib-1.0.4/%.c
-	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+	$(CC) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CFLAGS) $< -o $@
 
 ../o/%.$(OBJ_EXT):	degrib18/g2clib-1.0.4/%.cpp
-	$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+	$(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
 
 %.$(OBJ_EXT):	degrib18/degrib/%.c
-	$(CC) -c $(CPPFLAGS) $(CFLAGS) -Idegrib18/g2clib-1.0.4 $< -o $@
+	$(CC) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CFLAGS) -Idegrib18/g2clib-1.0.4 $< -o $@
 
 %.$(OBJ_EXT):	degrib18/degrib/%.cpp
-	$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+	$(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
 
 %.$(OBJ_EXT):	degrib18/g2clib-1.0.4/%.c
-	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+	$(CC) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CFLAGS) $< -o $@
 
 %.$(OBJ_EXT):	degrib18/g2clib-1.0.4/%.cpp
-	$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
+	$(CXX) -c $(GDAL_INCLUDE) $(CPPFLAGS) $(CXXFLAGS) $< -o $@
 
 defaultold:	$(OBJ:.o=.$(OBJ_EXT))
 	(cd degrib18/degrib; $(MAKE)); cd ../..
diff --git a/frmts/grib/degrib18/degrib/degrib1.cpp b/frmts/grib/degrib18/degrib/degrib1.cpp
index 9e411c6..195344c 100644
--- a/frmts/grib/degrib18/degrib/degrib1.cpp
+++ b/frmts/grib/degrib18/degrib/degrib1.cpp
@@ -285,7 +285,7 @@ static void GRIB1_Table2LookUp (pdsG1Type *pdsMeta, const char **name,
                                 unsigned short int center,
                                 unsigned short int subcenter)
 {
-   GRIB1ParmTable *table; /* The paramter table choosen by the pdsMeta data */
+   GRIB1ParmTable *table; /* The parameter table choosen by the pdsMeta data */
 
    table = Choose_ParmTable (pdsMeta, center, subcenter);
    if ((center == NMC) && (pdsMeta->mstrVersion == 129)
@@ -366,11 +366,7 @@ static void GRIB1_Table3LookUp (pdsG1Type *pdsMeta, char **shortLevelName,
  */
 static double fval_360 (uInt4 aval)
 {
-   double pow16;
-/*   short int *ptr = (short int *) (&pow16);*/
-   void *voidPtr = &pow16;
-   short int *ptr = (short int *) voidPtr;
-
+   short int ptr[4];
 #ifdef LITTLE_ENDIAN
    ptr[3] = ((((aval >> 24) & 0x7f) << 2) + (0x3ff - 0x100)) << 4;
    ptr[2] = 0;
@@ -382,6 +378,8 @@ static double fval_360 (uInt4 aval)
    ptr[2] = 0;
    ptr[3] = 0;
 #endif
+   double pow16;
+   memcpy(&pow16, ptr, 8);
    return ((aval & 0x80000000) ? -pow16 : pow16) *
          (aval & 0xffffff) / ((double) 0x1000000);
 }
diff --git a/frmts/grib/degrib18/degrib/degrib2.cpp b/frmts/grib/degrib18/degrib/degrib2.cpp
index 49567fc..2caf42a 100644
--- a/frmts/grib/degrib18/degrib/degrib2.cpp
+++ b/frmts/grib/degrib18/degrib/degrib2.cpp
@@ -31,8 +31,6 @@
 //#include "mymapf.h"
 #include "clock.h"
 
-#include "cpl_port.h"
-
 #define GRIB_UNSIGN_INT3(a,b,c) ((a<<16)+(b<<8)+c)
 
 /*****************************************************************************
@@ -817,7 +815,8 @@ int ReadGrib2Record (DataSource &fp, sChar f_unit, double **Grib_Data,
                      uInt4 *grib_DataLen, grib_MetaData *meta,
                      IS_dataType *IS, int subgNum, double majEarth,
                      double minEarth, int simpVer, sInt4 *f_endMsg,
-                     CPL_UNUSED LatLon *lwlf, CPL_UNUSED LatLon *uprt)
+                     CPL_UNUSED LatLon *lwlf,
+                     CPL_UNUSED LatLon *uprt)
 {
    sInt4 l3264b;        /* Number of bits in a sInt4.  Needed by FORTRAN
                          * unpack library to determine if system has a 4
diff --git a/frmts/grib/degrib18/degrib/grib2api.c b/frmts/grib/degrib18/degrib/grib2api.c
index fc2a7b8..48a69c4 100644
--- a/frmts/grib/degrib18/degrib/grib2api.c
+++ b/frmts/grib/degrib18/degrib/grib2api.c
@@ -1083,7 +1083,7 @@ void unpk_g2ncep (CPL_UNUSED sInt4 * kfildo, float * ain, sInt4 * iain, sInt4 *
       *ibitmap = 0;
    }
 
-   /* Check type of original field, before transfering the memory. */
+   /* Check type of original field, before transferring the memory. */
    myAssert (*ns5 > 20);
    /* Check if NCEP had problems expanding the data.  If so we currently
     * abort.  May need to revisit this behavior. */
diff --git a/frmts/grib/degrib18/degrib/inventory.cpp b/frmts/grib/degrib18/degrib/inventory.cpp
index 8788fc1..950c639 100644
--- a/frmts/grib/degrib18/degrib/inventory.cpp
+++ b/frmts/grib/degrib18/degrib/inventory.cpp
@@ -31,8 +31,6 @@
 #include "metaname.h"
 #include "filedatasource.h"
 
-#include "cpl_port.h"
-
 #define SECT0LEN_BYTE 16
 
 typedef union {
@@ -244,7 +242,9 @@ static int InventoryParseTime (char *is, double *AnsTime)
  *   May want to put this in degrib2.c
  *****************************************************************************
  */
-static int GRIB2SectToBuffer (DataSource &fp, CPL_UNUSED uInt4 gribLen, sChar *sect,
+static int GRIB2SectToBuffer (DataSource &fp,
+                              CPL_UNUSED uInt4 gribLen,
+                              sChar *sect,
                               uInt4 *secLen, uInt4 *buffLen, char **buff)
 {
    char *buffer = *buff; /* Local ptr to buff to reduce ptr confusion. */
@@ -316,7 +316,8 @@ static int GRIB2SectToBuffer (DataSource &fp, CPL_UNUSED uInt4 gribLen, sChar *s
  *   May want to put this in degrib2.c
  *****************************************************************************
  */
-static int GRIB2SectJump (DataSource &fp, CPL_UNUSED sInt4 gribLen, sChar *sect, uInt4 *secLen)
+static int GRIB2SectJump (DataSource &fp,
+                          CPL_UNUSED sInt4 gribLen, sChar *sect, uInt4 *secLen)
 {
    char sectNum;        /* Validates that we are on the correct section. */
    int c;               /* Check that the fseek is still inside the file. */
diff --git a/frmts/grib/degrib18/degrib/metaname.cpp b/frmts/grib/degrib18/degrib/metaname.cpp
index f34c74a..3586383 100644
--- a/frmts/grib/degrib18/degrib/metaname.cpp
+++ b/frmts/grib/degrib18/degrib/metaname.cpp
@@ -61,7 +61,7 @@ const char *centerLookup (unsigned short int center)
       {22, "ACMAD"},
       {23, "Mozambique"},
       {24, "Pretoria"},
-      {25, "La R�union"},
+      {25, "La R\xE9" "union"},
       {26, "Khabarovsk"},
       {27, ") Khabarovsk"},
       {28, "New Delhi"},
@@ -118,8 +118,8 @@ const char *centerLookup (unsigned short int center)
       {79, ") Offenbach"},
       {80, "Rome"},
       {81, ") Rome"},
-      {82, "Norrk�ping"},
-      {83, ") Norrk�ping"},
+      {82, "Norrk\xF6" "ping"},
+      {83, ") Norrk\xF6" "ping"},
       {84, "Toulouse"},
       {85, "Toulouse"},
       {86, "Helsinki"},
@@ -251,7 +251,7 @@ const char *centerLookup (unsigned short int center)
       {212, "Lisboa"},
       {213, "Reykiavik"},
       {214, "Madrid"},
-      {215, "Z�rich"},
+      {215, "Z\xFC" "rich"},
       {216, "Service ARGOS Toulouse"},
       {217, "Bratislava"},
       {218, "Budapest"},
@@ -384,7 +384,7 @@ const char *subCenterLookup(unsigned short int center,
       {74, 27, "Nordic Commission of Geodesy (Norway)"},
       {74, 28, "Nordic Commission of Geodesy (Sweden)"},
       {74, 29, "Institute de Geodesie National (France)"},
-      {74, 30, "Bundesamt f�r Kartographie und Geod�sie (Germany)"},
+      {74, 30, "Bundesamt f\xFC" "r Kartographie und Geod\xE4" "sie (Germany)"},
       {74, 31, "Institute of Engineering Satellite Surveying and Geodesy (U.K.)"},
       {254, 10, "Tromso (Norway)"}, {254, 10, "Maspalomas (Spain)"},
       {254, 30, "Kangerlussuaq (Greenland)"}, {254, 40, "Edmonton (Canada)"},
@@ -840,7 +840,7 @@ GRIB2ParmTable MeteoAtmos[] = {
 /* 18 */    {"SNFALB", "Snow free albedo", "%", UC_NONE},
 };
 
-/* GRIB2 Code table 4.2 : 0.253 or 0.190 (Document is inconsistant.) */
+/* GRIB2 Code table 4.2 : 0.253 or 0.190 (Document is inconsistent.) */
 GRIB2ParmTable MeteoText[] = {
    /* 0 */ {"", "Arbitrary text string", "CCITTIA5", UC_NONE},
 };
@@ -1202,9 +1202,9 @@ GRIB2LocalTable NDFD_LclTable[] = {
    /* grandfather'ed in a NDFD choice for POP. */
    /* 4 */ {0, 10, 8, "PoP12", "Prob of 0.01 In. of Precip", "%", UC_NONE},
            {0, 13, 194, "smokes", "Surface level smoke from fires",
-            "log10(�g/m^3)", UC_LOG10},
+            "log10(\xB5" "g/m^3)", UC_LOG10},
            {0, 13, 195, "smokec", "Average vertical column smoke from fires",
-            "log10(�g/m^3)", UC_LOG10},
+            "log10(\xB5" "g/m^3)", UC_LOG10},
    /* Arthur Added this to both NDFD and NCEP local tables. (5/1/2006) */
            {10, 3, 192, "Surge", "Hurricane Storm Surge", "m", UC_M2Feet},
            {10, 3, 193, "ETSurge", "Extra Tropical Storm Surge", "m", UC_M2Feet},
@@ -1288,12 +1288,12 @@ GRIB2LocalTable NCEP_LclTable[] = {
    /* 40 */ {0, 7, 193, "4LFTX", "Best (4 layer) Lifted Index", "K", UC_NONE},
    /* 41 */ {0, 7, 194, "RI", "Richardson Number", "-", UC_NONE},
 
-            {0, 13, 192, "PMTC", "Particulate matter (coarse)", "�g/m^3", UC_NONE},
-            {0, 13, 193, "PMTF", "Particulate matter (fine)", "�g/m^3", UC_NONE},
+            {0, 13, 192, "PMTC", "Particulate matter (coarse)", "\xB5" "g/m^3", UC_NONE},
+            {0, 13, 193, "PMTF", "Particulate matter (fine)", "\xB5" "g/m^3", UC_NONE},
             {0, 13, 194, "LPMTF", "Particulate matter (fine)",
-             "log10(�g/m^3)", UC_LOG10},
+             "log10(\xB5" "g/m^3)", UC_LOG10},
             {0, 13, 195, "LIPMF", "Integrated column particulate matter "
-             "(fine)", "log10(�g/m^3)", UC_LOG10},
+             "(fine)", "log10(\xB5" "g/m^3)", UC_LOG10},
 
    /* 42 */ {0, 14, 192, "O3MR", "Ozone Mixing Ratio", "kg/kg", UC_NONE},
    /* 43 */ {0, 14, 193, "OZCON", "Ozone Concentration", "PPB", UC_NONE},
@@ -1485,8 +1485,11 @@ static GRIB2LocalTable *Choose_LocalParmTable (unsigned short int center,
  */
 /* Deal with probability templates 2/16/2006 */
 static void ElemNameProb (uShort2 center, uShort2 subcenter, int prodType,
-                          CPL_UNUSED int templat, uChar cat, uChar subcat, sInt4 lenTime,
-                          uChar timeIncrType, CPL_UNUSED uChar genID, uChar probType,
+                          CPL_UNUSED int templat,
+                          uChar cat, uChar subcat, sInt4 lenTime,
+                          uChar timeIncrType,
+                          CPL_UNUSED uChar genID,
+                          uChar probType,
                           double lowerProb, double upperProb, char **name,
                           char **comment, char **unit, int *convert)
 {
@@ -1660,7 +1663,8 @@ static void ElemNameProb (uShort2 center, uShort2 subcenter, int prodType,
 
 /* Deal with percentile templates 5/1/2006 */
 static void ElemNamePerc (uShort2 center, uShort2 subcenter, int prodType,
-                          CPL_UNUSED int templat, uChar cat, uChar subcat, sInt4 lenTime,
+                          CPL_UNUSED int templat,
+                          uChar cat, uChar subcat, sInt4 lenTime,
                           sChar percentile, char **name, char **comment,
                           char **unit, int *convert)
 {
@@ -1748,8 +1752,12 @@ static void ElemNamePerc (uShort2 center, uShort2 subcenter, int prodType,
 /* Deal with non-prob templates 2/16/2006 */
 static void ElemNameNorm (uShort2 center, uShort2 subcenter, int prodType,
                           int templat, uChar cat, uChar subcat, sInt4 lenTime,
-                          CPL_UNUSED uChar timeIncrType, CPL_UNUSED uChar genID, CPL_UNUSED uChar probType,
-                          CPL_UNUSED double lowerProb, CPL_UNUSED double upperProb, char **name,
+                          CPL_UNUSED uChar timeIncrType,
+                          CPL_UNUSED uChar genID,
+                          CPL_UNUSED uChar probType,
+                          CPL_UNUSED double lowerProb,
+                          CPL_UNUSED double upperProb,
+                          char **name,
                           char **comment, char **unit, int *convert)
 {
    GRIB2ParmTable *table;
@@ -2390,7 +2398,9 @@ GRIB2LocalSurface NCEP_Surface[] = {
  * NOTES
  *****************************************************************************
  */
-GRIB2SurfTable Table45Index (int i, int *f_reserved, uShort2 center,
+GRIB2SurfTable Table45Index (int i,
+                             int *f_reserved,
+                             uShort2 center,
                              CPL_UNUSED uShort2 subcenter)
 {
    size_t j;
diff --git a/frmts/grib/degrib18/degrib/metaparse.cpp b/frmts/grib/degrib18/degrib/metaparse.cpp
index ffb0b3a..4b3adee 100644
--- a/frmts/grib/degrib18/degrib/metaparse.cpp
+++ b/frmts/grib/degrib18/degrib/metaparse.cpp
@@ -28,8 +28,6 @@
 #include "memendian.h"
 #include "myutil.h"
 
-#include "cpl_port.h"
-
 /*****************************************************************************
  * MetaInit() --
  *
@@ -2370,7 +2368,8 @@ void ParseGrid (gridAttribType *attrib, double **Grib_Data,
                 uInt4 *grib_DataLen, uInt4 Nx, uInt4 Ny, int scan,
                 sInt4 *iain, sInt4 ibitmap, sInt4 *ib, double unitM,
                 double unitB, uChar f_wxType, sect2_WxType *WxType,
-                CPL_UNUSED uChar f_subGrid, int startX, int startY, int stopX, int stopY)
+                CPL_UNUSED uChar f_subGrid,
+                int startX, int startY, int stopX, int stopY)
 {
    double xmissp;       /* computed missing value needed for ibitmap = 1,
                          * Also used if unit conversion causes confusion
diff --git a/frmts/grib/degrib18/degrib/myutil.c b/frmts/grib/degrib18/degrib/myutil.c
index d0914f8..ec2290d 100644
--- a/frmts/grib/degrib18/degrib/myutil.c
+++ b/frmts/grib/degrib18/degrib/myutil.c
@@ -458,7 +458,9 @@ static int FileMatch (const char *filename, const char *filter)
 }
 **/
 
-int myGlob (CPL_UNUSED const char *dirName, CPL_UNUSED const char *filter, CPL_UNUSED size_t *Argc,
+int myGlob (CPL_UNUSED const char *dirName,
+            CPL_UNUSED const char *filter,
+            CPL_UNUSED size_t *Argc,
             CPL_UNUSED char ***Argv)
 {
 return 0; // TODO: reimplement for Win32
diff --git a/frmts/grib/degrib18/degrib/tdlpack.cpp b/frmts/grib/degrib18/degrib/tdlpack.cpp
index 32ace53..ba6a43c 100644
--- a/frmts/grib/degrib18/degrib/tdlpack.cpp
+++ b/frmts/grib/degrib18/degrib/tdlpack.cpp
@@ -175,7 +175,7 @@ static int ReadTDLPSect1 (uChar *pds, sInt4 tdlpLen, sInt4 *curLoc,
    t_hour = li_temp - t_day * 100;
    if ((t_year != year) || (t_month != month) || (t_day != day) ||
        (t_hour != hour)) {
-      errSprintf ("Error Inconsistant Times in ReadTDLPSect1.\n");
+      errSprintf ("Error Inconsistent Times in ReadTDLPSect1.\n");
       return -1;
    }
    if (ParseTime (&(pdsMeta->refTime), year, month, day, hour, min, 0) != 0) {
@@ -232,10 +232,10 @@ static int ReadTDLPSect1 (uChar *pds, sInt4 tdlpLen, sInt4 *curLoc,
    project_hr = GRIB_UNSIGN_INT2 (*pds, pds[1]);
    tau = pdsMeta->ID3 - ((pdsMeta->ID3 / 1000) * 1000);
    if (tau != project_hr) {
-      printf ("Warning: Inconsistant Projections in hours in "
+      printf ("Warning: Inconsistent Projections in hours in "
               "ReadTDLPSect1 (%d vs %d)\n", tau, project_hr);
 /*
-      errSprintf ("Warning: Inconsistant Projections in hours in "
+      errSprintf ("Warning: Inconsistent Projections in hours in "
                   "ReadTDLPSect1 (%ld vs %d)\n", tau, project_hr);
 */
       project_hr = tau;
@@ -634,7 +634,7 @@ int TDLP_RefTime (DataSource &fp, sInt4 tdlpLen, double *refTime)
 
    if ((t_year != year) || (t_month != month) || (t_day != day) ||
        (t_hour != hour)) {
-      errSprintf ("Error Inconsistant Times in TDLP_RefTime.\n");
+      errSprintf ("Error Inconsistent Times in TDLP_RefTime.\n");
       return -1;
    }
    if (ParseTime (refTime, year, month, day, hour, min, 0) != 0) {
@@ -796,8 +796,11 @@ static int ReadTDLPSect2 (uChar *gds, sInt4 tdlpLen, sInt4 *curLoc,
  * NOTES
  *****************************************************************************
  */
-static int ReadTDLPSect3 (CPL_UNUSED uChar *bms, CPL_UNUSED sInt4 tdlpLen, CPL_UNUSED sInt4 *curLoc,
-                          CPL_UNUSED uChar *bitmap, CPL_UNUSED sInt4 NxNy)
+static int ReadTDLPSect3 (CPL_UNUSED uChar *bms,
+                          CPL_UNUSED sInt4 tdlpLen,
+                          CPL_UNUSED sInt4 *curLoc,
+                          CPL_UNUSED uChar *bitmap,
+                          CPL_UNUSED sInt4 NxNy)
 {
    errSprintf ("Bitmap data is Not Supported\n");
    return -1;
@@ -847,7 +850,9 @@ static int ReadTDLPSect3 (CPL_UNUSED uChar *bms, CPL_UNUSED sInt4 tdlpLen, CPL_U
  */
 static int ReadTDLPSect4 (uChar *bds, sInt4 tdlpLen, sInt4 *curLoc,
                           short int DSF, short int BSF, double *data,
-                          grib_MetaData *meta, CPL_UNUSED double unitM, CPL_UNUSED double unitB)
+                          grib_MetaData *meta,
+                          CPL_UNUSED double unitM,
+                          CPL_UNUSED double unitB)
 {
    uInt4 sectLen;       /* Length in bytes of the current section. */
    uChar f_notGridPnt;  /* Not Grid point data? */
@@ -2862,7 +2867,9 @@ static void shiftGroup0 (sInt4 *Data, int start1, int start2, int bit,
  * NOTES
  *****************************************************************************
  */
-static void doSplit (sInt4 *Data, CPL_UNUSED int numData, TDLGroupType * G,
+static void doSplit (sInt4 *Data,
+                     CPL_UNUSED int numData,
+                     TDLGroupType * G,
                      TDLGroupType ** lclGroup, int *numLclGroup,
                      char f_primMiss, sInt4 li_primMiss,
                      char f_secMiss, sInt4 li_secMiss, int xFactor)
@@ -3001,7 +3008,9 @@ static void doSplit (sInt4 *Data, CPL_UNUSED int numData, TDLGroupType * G,
  * NOTES
  *****************************************************************************
  */
-static void doSplitRight (sInt4 *Data, CPL_UNUSED int numData, TDLGroupType * G,
+static void doSplitRight (sInt4 *Data,
+                          CPL_UNUSED int numData,
+                          TDLGroupType * G,
                           TDLGroupType * G1, TDLGroupType * G2,
                           char f_primMiss, sInt4 li_primMiss,
                           char f_secMiss, sInt4 li_secMiss)
@@ -3355,7 +3364,9 @@ static int splitGroup (sInt4 *Data, int numData, TDLGroupType * group,
  * NOTES
  *****************************************************************************
  */
-static void shiftGroup (sInt4 *Data, CPL_UNUSED int numData, TDLGroupType ** Group,
+static void shiftGroup (sInt4 *Data,
+                        CPL_UNUSED int numData,
+                        TDLGroupType ** Group,
                         size_t *NumGroup, char f_primMiss, sInt4 li_primMiss,
                         char f_secMiss, sInt4 li_secMiss, int xFactor)
 {
@@ -3858,7 +3869,7 @@ static int GroupPack (double *Src, sInt4 **Dst, sInt4 numData,
                            * requested. */
    sInt4 *Data;         /* The scaled data. */
    char f_min;          /* Flag saying overallMin is valid. */
-   sInt4 overallMin;    /* The overall min of the scaled data. */
+   sInt4 overallMin = 0;    /* The overall min of the scaled data. */
    sInt4 secMin;        /* The overall min of the 2nd order differences */
    sInt4 li_primMiss = 0; /* The scaled primary missing value */
    sInt4 li_secMiss = 0; /* The scaled secondary missing value */
diff --git a/frmts/grib/degrib18/g2clib-1.0.4/dec_jpeg2000.cpp b/frmts/grib/degrib18/g2clib-1.0.4/dec_jpeg2000.cpp
index 6cdd095..67e13f5 100644
--- a/frmts/grib/degrib18/g2clib-1.0.4/dec_jpeg2000.cpp
+++ b/frmts/grib/degrib18/g2clib-1.0.4/dec_jpeg2000.cpp
@@ -120,7 +120,7 @@ int dec_jpeg2000(char *injpc,g2int bufsize,g2int *outfld)
     poJ2KDataset->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize,
                             outfld, nBufXSize, nBufYSize, eBufType,
                             nBandCount, panBandMap, 
-                            nPixelSpace, nLineSpace, nBandSpace );
+                            nPixelSpace, nLineSpace, nBandSpace, NULL );
 
     // close source file, and "unlink" it.
     GDALClose( poJ2KDataset );
diff --git a/frmts/grib/degrib18/g2clib-1.0.4/enc_jpeg2000.c b/frmts/grib/degrib18/g2clib-1.0.4/enc_jpeg2000.c
index 9b99f26..c6076cf 100644
--- a/frmts/grib/degrib18/g2clib-1.0.4/enc_jpeg2000.c
+++ b/frmts/grib/degrib18/g2clib-1.0.4/enc_jpeg2000.c
@@ -1,8 +1,8 @@
 #include "grib2.h"
-#ifndef USE_JPEG2000
 
 #include "cpl_port.h"
 
+#ifndef USE_JPEG2000
 int enc_jpeg2000(CPL_UNUSED unsigned char *cin,
                  CPL_UNUSED g2int width,
                  CPL_UNUSED g2int height,
@@ -10,10 +10,9 @@ int enc_jpeg2000(CPL_UNUSED unsigned char *cin,
                  CPL_UNUSED g2int ltype,
                  CPL_UNUSED g2int ratio,
                  CPL_UNUSED g2int retry,
-                 CPL_UNUSED char *outjpc, 
-                 CPL_UNUSED g2int jpclen) {
-    return 0;
-}
+                 CPL_UNUSED char *outjpc,
+                 CPL_UNUSED g2int jpclen) { return 0; }
+
 #else   /* USE_JPEG2000 */
 
 #include <stdio.h>
diff --git a/frmts/grib/degrib18/g2clib-1.0.4/reduce.c b/frmts/grib/degrib18/g2clib-1.0.4/reduce.c
index 50bdaa2..044138b 100644
--- a/frmts/grib/degrib18/g2clib-1.0.4/reduce.c
+++ b/frmts/grib/degrib18/g2clib-1.0.4/reduce.c
@@ -19,9 +19,9 @@
 typedef g2int integer;
 typedef g2float real;
 
-/* Subroutine */ int reduce(CPL_UNUSED integer *kfildo, integer *jmin, integer *jmax, 
+/* Subroutine */ int reduce(CPL_UNUSED integer *kfildo, integer *jmin, integer *jmax,
 	integer *lbit, integer *nov, integer *lx, integer *ndg, integer *ibit,
-	 integer *jbit, integer *kbit, integer *novref, integer *ibxx2, 
+	 integer *jbit, integer *kbit, integer *novref, integer *ibxx2,
 	integer *ier)
 {
     /* Initialized data */
diff --git a/frmts/grib/degrib18/g2clib-1.0.4/simpack.c b/frmts/grib/degrib18/g2clib-1.0.4/simpack.c
index 043b506..1e19af9 100644
--- a/frmts/grib/degrib18/g2clib-1.0.4/simpack.c
+++ b/frmts/grib/degrib18/g2clib-1.0.4/simpack.c
@@ -112,7 +112,7 @@ void simpack(g2float *fld,g2int ndpts,g2int *idrstmpl,unsigned char *cpack,g2int
         else if (nbits!=0 && idrstmpl[1]==0) {
            //
            //  Use minimum number of bits specified by user and
-           //  adjust binary scaling factor to accomodate data.
+           //  adjust binary scaling factor to accommodate data.
            //
            rmin=rmin*dscale;
            rmax=rmax*dscale;
diff --git a/frmts/grib/frmt_grib.html b/frmts/grib/frmt_grib.html
index 28ec9c3..773d5b4 100644
--- a/frmts/grib/frmt_grib.html
+++ b/frmts/grib/frmt_grib.html
@@ -71,7 +71,7 @@ reading or writing several GRIB datasets at the same time from different threads
 
 <li> <a href="http://www.weather.gov/mdl/NDFD_GRIB2Decoder/">NOAA NWS NDFD "degrib" GRIB2 Decoder</a>
 <li> <a href="http://www.nco.ncep.noaa.gov/pmb/codes/GRIB2/">NOAA NWS NCEP g2clib grib decoding library</a>
-<li> <a href="http://www.wmo.int/pages/prog/www/WMOCodes/GRIB.html">WMS GRIB Format Documents</a>
+<li> <a href="http://www.wmo.int/pages/prog/www/WDM/Guides/Guide-binary-2.html">WMO GRIB Format Documents</a>
 </ul>
 
 </body>
diff --git a/frmts/grib/gribdataset.cpp b/frmts/grib/gribdataset.cpp
index ead99fb..7384922 100644
--- a/frmts/grib/gribdataset.cpp
+++ b/frmts/grib/gribdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gribdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gribdataset.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  GRIB Driver
  * Purpose:  GDALDataset driver for GRIB translator for read support
@@ -41,13 +41,13 @@
 
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: gribdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gribdataset.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 CPL_C_START
 void	GDALRegister_GRIB(void);
 CPL_C_END
 
-static void *hGRIBMutex = NULL;
+static CPLMutex *hGRIBMutex = NULL;
 
 /************************************************************************/
 /* ==================================================================== */
@@ -339,7 +339,8 @@ CPLErr GRIBRasterBand::LoadData()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GRIBRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr GRIBRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void * pImage )
 
 {
@@ -671,6 +672,7 @@ GDALDataset *GRIBDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Create band objects.                                            */
 /* -------------------------------------------------------------------- */
+    GRIBRasterBand *gribBand;
     for (uInt4 i = 0; i < LenInv; ++i)
     {
         uInt4 bandNr = i+1;
@@ -692,17 +694,24 @@ GDALDataset *GRIBDataset::Open( GDALOpenInfo * poOpenInfo )
             }
 
             poDS->SetGribMetaData(metaData); // set the DataSet's x,y size, georeference and projection from the first GRIB band
-            GRIBRasterBand* gribBand = new GRIBRasterBand( poDS, bandNr, Inv+i);
+            gribBand = new GRIBRasterBand( poDS, bandNr, Inv+i);
 
             if( Inv->GribVersion == 2 )
                 gribBand->FindPDSTemplate();
 
             gribBand->m_Grib_Data = data;
             gribBand->m_Grib_MetaData = metaData;
-            poDS->SetBand( bandNr, gribBand);
         }
         else
-            poDS->SetBand( bandNr, new GRIBRasterBand( poDS, bandNr, Inv+i ));
+        {
+            gribBand = new GRIBRasterBand( poDS, bandNr, Inv+i );
+            if( CSLTestBoolean( CPLGetConfigOption( "GRIB_PDS_ALL_BANDS", "ON" ) ) )
+            {
+                if( Inv->GribVersion == 2 )
+                    gribBand->FindPDSTemplate();
+            }
+        }
+        poDS->SetBand( bandNr, gribBand);
         GRIB2InventoryFree (Inv + i);
     }
     free (Inv);
@@ -718,7 +727,7 @@ GDALDataset *GRIBDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
     CPLAcquireMutex(hGRIBMutex, 1000.0);
 
     return( poDS );
@@ -923,6 +932,7 @@ void GDALRegister_GRIB()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GRIB" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "GRIdded Binary (.grb)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/gsg/GNUmakefile b/frmts/gsg/GNUmakefile
index 7535e03..e21476c 100644
--- a/frmts/gsg/GNUmakefile
+++ b/frmts/gsg/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	gsagdataset.o gsbgdataset.o gs7bgdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/gsg/gs7bgdataset.cpp b/frmts/gsg/gs7bgdataset.cpp
index e741522..ee8d8d2 100644
--- a/frmts/gsg/gs7bgdataset.cpp
+++ b/frmts/gsg/gs7bgdataset.cpp
@@ -1,5 +1,5 @@
 /****************************************************************************
- * $Id: gs7bgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gs7bgdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implements the Golden Software Surfer 7 Binary Grid Format.
@@ -61,7 +61,7 @@
 # define SHRT_MAX 32767
 #endif /* SHRT_MAX */
 
-CPL_CVSID("$Id: gs7bgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gs7bgdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_GS7BG(void);
@@ -836,7 +836,7 @@ GDALDataset *GS7BGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -1107,7 +1107,9 @@ CPLErr GS7BGDataset::WriteHeader( VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
 /************************************************************************/
 
 GDALDataset *GS7BGDataset::Create( const char * pszFilename,
-                                   int nXSize, int nYSize, int nBands,
+                                   int nXSize,
+                                   int nYSize,
+                                   int nBands,
                                    GDALDataType eType,
                                    CPL_UNUSED char **papszParmList )
 
@@ -1185,7 +1187,8 @@ GDALDataset *GS7BGDataset::Create( const char * pszFilename,
 
 GDALDataset *GS7BGDataset::CreateCopy( const char *pszFilename,
                                        GDALDataset *poSrcDS,
-                                       int bStrict, CPL_UNUSED char **papszOptions,
+                                       int bStrict,
+                                       CPL_UNUSED char **papszOptions,
                                        GDALProgressFunc pfnProgress,
                                        void *pProgressData )
 {
@@ -1271,7 +1274,7 @@ GDALDataset *GS7BGDataset::CreateCopy( const char *pszFilename,
     {
         eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
                     nXSize, 1, pfData,
-                    nXSize, 1, GDT_Float64, 0, 0 );
+                    nXSize, 1, GDT_Float64, 0, 0, NULL );
 
         if( eErr != CE_None )
         {
@@ -1355,6 +1358,7 @@ void GDALRegister_GS7BG()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "GS7BG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Golden Software 7 Binary Grid (.grd)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/gsg/gsagdataset.cpp b/frmts/gsg/gsagdataset.cpp
index f572a0e..1790276 100644
--- a/frmts/gsg/gsagdataset.cpp
+++ b/frmts/gsg/gsagdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gsagdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gsagdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implements the Golden Software ASCII Grid Format.
@@ -50,7 +50,7 @@
 # define INT_MAX 2147483647
 #endif /* INT_MAX */
 
-CPL_CVSID("$Id: gsagdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gsagdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_GSAG(void);
@@ -1067,7 +1067,7 @@ GDALDataset *GSAGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 
@@ -1505,7 +1505,8 @@ CPLErr GSAGDataset::UpdateHeader()
 
 GDALDataset *GSAGDataset::CreateCopy( const char *pszFilename,
 				      GDALDataset *poSrcDS,
-				      int bStrict, CPL_UNUSED char **papszOptions,
+				      int bStrict,
+                                      CPL_UNUSED char **papszOptions,
 				      GDALProgressFunc pfnProgress,
 				      void *pProgressData )
 {
@@ -1615,7 +1616,7 @@ GDALDataset *GSAGDataset::CreateCopy( const char *pszFilename,
     {
 	CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, nYSize-iRow-1,
 					   nXSize, 1, pdfData,
-					   nXSize, 1, GDT_Float64, 0, 0 );
+					   nXSize, 1, GDT_Float64, 0, 0, NULL );
 
 	if( eErr != CE_None )
 	{
@@ -1753,6 +1754,7 @@ void GDALRegister_GSAG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GSAG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Golden Software ASCII Grid (.grd)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/gsg/gsbgdataset.cpp b/frmts/gsg/gsbgdataset.cpp
index f0b9270..fc30544 100644
--- a/frmts/gsg/gsbgdataset.cpp
+++ b/frmts/gsg/gsbgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gsbgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gsbgdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implements the Golden Software Binary Grid Format.
@@ -61,7 +61,7 @@
 # define SHRT_MAX 32767
 #endif /* SHRT_MAX */
 
-CPL_CVSID("$Id: gsbgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gsbgdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_GSBG(void);
@@ -679,7 +679,7 @@ GDALDataset *GSBGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -882,10 +882,11 @@ CPLErr GSBGDataset::WriteHeader( VSILFILE *fp, GInt16 nXSize, GInt16 nYSize,
 /************************************************************************/
 
 GDALDataset *GSBGDataset::Create( const char * pszFilename,
-				  int nXSize, int nYSize, CPL_UNUSED int nBands,
+				  int nXSize,
+                                  int nYSize,
+                                  CPL_UNUSED int nBands,
 				  GDALDataType eType,
 				  CPL_UNUSED char **papszParmList )
-
 {
     if( nXSize <= 0 || nYSize <= 0 )
     {
@@ -962,7 +963,8 @@ GDALDataset *GSBGDataset::Create( const char * pszFilename,
 
 GDALDataset *GSBGDataset::CreateCopy( const char *pszFilename,
 				      GDALDataset *poSrcDS,
-				      int bStrict, CPL_UNUSED char **papszOptions,
+				      int bStrict,
+                                      CPL_UNUSED char **papszOptions,
 				      GDALProgressFunc pfnProgress,
 				      void *pProgressData )
 {
@@ -1059,7 +1061,7 @@ GDALDataset *GSBGDataset::CreateCopy( const char *pszFilename,
     {
 	eErr = poSrcBand->RasterIO( GF_Read, 0, iRow,
 				    nXSize, 1, pfData,
-				    nXSize, 1, GDT_Float32, 0, 0 );
+				    nXSize, 1, GDT_Float32, 0, 0, NULL );
 
 	if( eErr != CE_None )
 	{
@@ -1143,6 +1145,7 @@ void GDALRegister_GSBG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GSBG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Golden Software Binary Grid (.grd)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/gta/GNUmakefile b/frmts/gta/GNUmakefile
index cb16a5d..148615b 100644
--- a/frmts/gta/GNUmakefile
+++ b/frmts/gta/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	gtadataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/gta/gtadataset.cpp b/frmts/gta/gtadataset.cpp
index 891842e..f9df795 100644
--- a/frmts/gta/gtadataset.cpp
+++ b/frmts/gta/gtadataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gtadataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gtadataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  GTA read/write Driver
  * Purpose:  GDAL bindings over GTA library.
@@ -91,7 +91,7 @@
 #include <gta/gta.hpp>
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: gtadataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gtadataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 void    GDALRegister_GTA(void);
@@ -1641,7 +1641,7 @@ GTACreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                 CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, iLine,
                         poSrcDS->GetRasterXSize(), 1,
                         pDst, poSrcDS->GetRasterXSize(), 1, eDT,
-                        oHeader.element_size(), 0 );
+                        oHeader.element_size(), 0, NULL );
                 if( eErr != CE_None )
                 {
                     CPLError( CE_Failure, CPLE_FileIO, "Cannot read source data set.\n" );
@@ -1671,7 +1671,7 @@ GTACreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     oGTAIO.close();
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     GTADataset *poDS = (GTADataset *) GDALOpen( pszFilename,
@@ -1697,6 +1697,7 @@ void GDALRegister_GTA()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "GTA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                 "Generic Tagged Arrays (.gta)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/gtiff/GNUmakefile b/frmts/gtiff/GNUmakefile
index 441632c..6a8bf9c 100644
--- a/frmts/gtiff/GNUmakefile
+++ b/frmts/gtiff/GNUmakefile
@@ -16,7 +16,7 @@ endif
 
 ifeq ($(GEOTIFF_SETTING),internal)
 SUBLIBS	:= lib-geotiff $(SUBLIBS) 
-TIFF_OPTS	:=	-Ilibgeotiff $(TIFF_OPTS)
+TIFF_OPTS	:=	-DINTERNAL_LIBGEOTIFF -Ilibgeotiff $(TIFF_OPTS)
 ifeq ($(RENAME_INTERNAL_LIBGEOTIFF_SYMBOLS),yes)
 TIFF_OPTS	:=	-DRENAME_INTERNAL_LIBGEOTIFF_SYMBOLS $(TIFF_OPTS)
 endif
@@ -32,7 +32,7 @@ ifeq ($(JPEG_SETTING),internal)
 JPEG_FLAGS 	:=	$(JPEG_FLAGS) -I../jpeg/libjpeg
 endif
 
-CPPFLAGS	:=	 -I.. $(JPEG_FLAGS) $(GDAL_INCLUDE) $(GEOTIFF_INCLUDE) $(TIFF_OPTS) $(CPPFLAGS)
+CPPFLAGS	:=	 -I.. $(JPEG_FLAGS)  $(GEOTIFF_INCLUDE) $(TIFF_OPTS) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT)) $(SUBLIBS)
 
diff --git a/frmts/gtiff/frmt_gtiff.html b/frmts/gtiff/frmt_gtiff.html
index 45e34d7..16eb6b5 100644
--- a/frmts/gtiff/frmt_gtiff.html
+++ b/frmts/gtiff/frmt_gtiff.html
@@ -179,6 +179,15 @@ so TOWGS84 parameters in coordinate systems are lost in GeoTIFF format.</p>
 file (.tfw).See a <a href="frmt_various.html#WLD">World Files</a> section
 for details.</p></li>
 
+<li><p><b>RPB=YES</b>: Force the generation of an associated .RPB file to
+describe RPC (Rational Polynomial Coefficients), if RPC information is available.
+If not specified, this file is automatically generated if there's RPC information
+and that the PROFILE is not the default GDALGeoTIFF.</p></li>
+
+<li><p><b>RPCTXT=YES</b>: (GDAL >=2.0) Force the generation of an associated
+_RPC.TXT file to describe RPC (Rational Polynomial Coefficients),
+if RPC information is available.</p></li>
+
 <li><p><b>INTERLEAVE=[BAND,PIXEL]</b>: By default TIFF files with pixel
 interleaving (PLANARCONFIG_CONTIG in TIFF terminology) are created.  These
 are slightly less efficient than BAND interleaving for some purposes, but 
@@ -199,15 +208,32 @@ Set the compression to use.  JPEG should generally only be used with Byte data (
 But starting with GDAL 1.7.0 and provided that GDAL is built with internal libtiff and libjpeg,
 it is possible to read and write TIFF files with 12bit JPEG compressed TIFF files (seen as UInt16 bands with NBITS=12).
 See the <a href="http://trac.osgeo.org/gdal/wiki/TIFF12BitJPEG">"8 and 12 bit JPEG in TIFF"</a> wiki page for more details.
-The CCITT compression should only be used with 1bit (NBITS=1) data.  None is the 
-default.</p></li>
+The CCITT compression should only be used with 1bit (NBITS=1) data.
+LZW and DEFLATE compressions can be used with the PREDICTOR creation option.
+None is the default.</p></li>
 
 <li><p><b>PREDICTOR=[1/2/3]</b>: Set the predictor for LZW or DEFLATE compression. The default is 1 (no predictor), 2 is horizontal differencing and 3 is floating point prediction.</p></li>
 
+<li><p><b>DISCARD_LSB=nbits or nbits_band1,nbits_band2,...nbits_bandN</b>: (GDAL >= 2.0)
+Set the number of least-significant bits to clear, possibly different per band.
+Lossy compression scheme to be best used with PREDICTOR=2 and LZW/DEFLATE compression.</p></li>
+
 <li><p><b>SPARSE_OK=TRUE/FALSE</b> (From GDAL 1.6.0): Should newly created files be allowed to be sparse?  Sparse files have 0 tile/strip offsets for blocks never written and save space; however, most non-GDAL packages cannot read such files.  The default is FALSE.</p></li>
 
 <li><p><b>JPEG_QUALITY=[1-100]</b>:  Set the JPEG quality when using JPEG compression.  A value of 100 is best quality (least compression), and 1 is worst quality (best compression).  The default is 75.</p></li>
 
+<li><p><b>JPEGTABLESMODE=0/1/2/3</b>:  (From GDAL 2.0) Configure how and where JPEG quantization and Huffman tables are written in the TIFF JpegTables tag and strip/tile. Default to 1.</p>
+<ul>
+<li>0: JpegTables is not written. Each strip/tile contains its own quantization tables and use optimized Huffman coding.</li>
+<li>1: JpegTables is written with only the quantization tables. Each strip/tile refers to those quantized tables and use optimized Huffman coding.
+This is generally the optimal choice for smallest file size, and consequently is the default.</li>
+<li>2: JpegTables is written with only the default Huffman tables. Each strip/tile refers to those Huffman tables
+    (thus no optimized Huffman coding) and contains its own quantization tables (identical). This option has no anticipated practical value.</li>
+<li>3: JpegTables is written with the quantization and default Huffman tables. Each strip/tile refers to those tables
+    (thus no optimized Huffman coding). This option could perhaps with some data be more efficient than 1, but this should only occur in rare circumstances.</li>
+</ul>
+</li>
+
 <li><p><b>ZLEVEL=[1-9]</b>:  Set the level of compression when using DEFLATE compression. A value of 9 is best, and 1 is least compression. The default is 6.</p></li>
 
 <li><p><b>PHOTOMETRIC=[MINISBLACK/MINISWHITE/RGB/CMYK/YCBCR/CIELAB/ICCLAB/ITULAB]</b>: 
@@ -246,7 +272,7 @@ size of the resulting file. If that computed file size is over 4GiB, GDAL will a
 decide to create a BigTIFF file. However, when compression is used, it is not possible in
 advance to known the final size of the file, so classical TIFF will be chosen. In
 that case, the user must explicitly require the creation of a BigTIFF with BIGTIFF=YES
-if he anticipates the final file to be too big for classical TIFF format.
+if the final file is anticipated to be too big for classical TIFF format.
 If BigTIFF creation is not explicitly asked or guessed and the resulting file is too big for classical TIFF,
 libtiff will fail with an error message like "TIFFAppendToStrip:Maximum TIFF file size exceeded".</p></li>
 
@@ -276,6 +302,64 @@ otherwise libtiff will fail to compress the data.</p>
 <p>
 Note also that the dimensions of the tiles or strips must be a multiple of 8 for PHOTOMETRIC=RGB or 16 for PHOTOMETRIC=YCBCR</p>
 
+<h3>Streaming operations</h3>
+
+Starting with GDAL 2.0, the GeoTIFF driver can support reading or writing TIFF
+files (with some restrictions detailed below) in a streaming compatible way.<p>
+
+When reading a file from /vsistdin/, a named pipe (on Unix), or if forcing streamed
+reading by setting the TIFF_READ_STREAMING configuration option to YES, the GeoTIFF driver
+will assume that the TIFF Image File Directory (IFD) is at the beginning of the file,
+i.e. at offset 8 for a classical TIFF file or at offset 16 for a BigTIFF file.
+The values of the tags of array type must be contained at the beginning of file, after the
+end of the IFD and before the first image strip/tile. The reader must read the
+strips/tiles in the order they are written in the file. For a pixel interleaved file (PlanarConfiguration=Contig),
+the recommended order for a writer, and thus for a reader, is from top to bottom
+for a strip-organized file or from top to bottom, which a chunk of a block height,
+and left to right for a tile-organized file. For a band organized file (PlanarConfiguration=Separate),
+the above order is recommended with the content of the first band, then the
+content of the second band, etc... Technically this order corresponds to increasing
+offsets in the TileOffsets/StripOffsets tag. This is the order that the GDAL raster
+copy routine will assume.
+<p>
+If the order is not the one described above, the UNORDERED_BLOCKS=YES dataset metadata item
+will be set in the TIFF metadata domain. Each block offset can be determined
+by querying the "BLOCK_OFFSET_[xblock]_[yblock]" band metadata items in the TIFF metadata
+domain (where xblock, yblock is the coordinate of the block), and a reader could use
+that information to determine the appropriate reading order for image blocks.
+<p>
+The files that are streamed into the GeoTIFF driver may be compressed, even if the
+GeoTIFF driver cannot produce such files in streamable output mode (regular creation
+of TIFF files will produce such compatible files for streamed reading).
+<p>
+When writing a file to /vsistdout/, a named pipe (on Unix), or when definiting
+the STREAMABLE_OUTPUT=YES creation option, the CreateCopy() method of the GeoTIFF driver
+will generate a file with the above defined constraints (related to position of IFD and
+block order), and this
+is only supported for a uncompressed file. The Create() method also supports creating streamable
+compatible files, but the writer must be careful to set the projection, geotransform
+or metadata before writting image blocks (so that the IFD is written at the beginning
+of the file). And when writing image blocks, the order
+of blocks must be the one of the above paragraph, otherwise errors will be reported.
+
+<p>
+Some examples :
+<pre>
+gdal_translate in.tif /vsistdout/ -co TILED=YES | gzip | gunzip | gdal_translate /vsistdin/ out.tif -co TILED=YES -co COMPRESS=DEFLATE
+</pre>
+or
+<pre>
+mkfifo my_fifo
+gdalwarp in.tif my_fifo -t_srs EPSG:3857
+gdal_translate my_fifo out.png -of PNG
+</pre>
+
+<p>
+Note: not all utilities are compatible with such input or output streaming operations,
+and even those which may deal with such files may not manage to deal with them in
+all circumstances, for example if the reading driver drived by the output file is
+not compatible with the block order of the streamed input.
+
 <h3>Configuration options</h3>
 
 <p>
@@ -301,9 +385,25 @@ RFC 33: GTiff - Fixing PixelIsPoint Interpretation</a> for more details. Default
 <!-- not sure it is wise to advertize this one. I doubt it works correctly if set to NO. CONVERT_YCBCR_TO_RGB -->
 <!-- debug/autotest option : GTIFF_DELETE_ON_ERROR -->
 <li>GDAL_TIFF_OVR_BLOCKSIZE : See <a href="#overviews"><i>Overviews</i> section</a>.
-<li> GTIFF_LINEAR_UNITS: Can be set to BROKEN to read GeoTIFF files that 
+<li>GTIFF_LINEAR_UNITS: Can be set to BROKEN to read GeoTIFF files that 
 have false easting/northing improperly set in meters when it ought to be in
 coordinate system linear units.  (<a href="http://trac.osgeo.org/gdal/ticket/3901">Ticket #3901</a>). 
+<li>TAB_APPROX_GEOTRANSFORM=YES/NO: (GDAL >= 2.0) To decide if an approximate geotransform is acceptable when reading a .tab file. Default value: NO
+<li>GTIFF_DIRECT_IO=YES/NO: (GDAL >= 2.0) Can be set to YES to use specialized
+RasterIO() implementations when reading un-tiled un-compressed TIFF files to
+avoid using the block cache. Setting it to YES even when the optimized cases do
+not apply should be safe (generic implementation will be used). Default value:NO
+<li>GTIFF_VIRTUAL_MEM_IO=YES/NO/IF_ENOUGH_RAM: (GDAL >= 2.0) Can be set to YES
+to use specialized RasterIO() implementations when reading un-compressed TIFF
+files to avoid using the block cache.
+This implementation relies on memory-mapped file I/O,
+and is currently only supported on Linux (64-bit build strongly recommended).
+Setting it to YES even when the optimized cases do not apply should be safe
+(generic implementation will be used), but if the file exceeds RAM, disk swapping
+might occur if the whole file is read. Setting it to IF_ENOUGH_RAM will first
+check if the uncompressed file size is no bigger than the physical memory. Default value:NO.
+If both GTIFF_VIRTUAL_MEM_IO and GTIFF_DIRECT_IO are enabled, the former is used
+in priority, and if not possible, the later is tried.
 </ul>
 </p>
 
diff --git a/frmts/gtiff/geotiff.cpp b/frmts/gtiff/geotiff.cpp
index 48111e1..d0d6294 100644
--- a/frmts/gtiff/geotiff.cpp
+++ b/frmts/gtiff/geotiff.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: geotiff.cpp 28419 2015-02-06 00:28:50Z rouault $
+ * $Id: geotiff.cpp 29129 2015-05-03 13:24:20Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  GDAL GeoTIFF support.
@@ -7,7 +7,7 @@
  *
  ******************************************************************************
  * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam at pobox.com>
- * Copyright (c) 2007-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -50,17 +50,20 @@
 #include "gtiff.h"
 #include "gdal_csv.h"
 #include "gt_wkt_srs.h"
+#include "gt_wkt_srs_priv.h"
 #include "tifvsi.h"
 #include "cpl_multiproc.h"
 #include "cplkeywordparser.h"
 #include "gt_jpeg_copy.h"
+#include "cpl_vsi_virtual.h"
 #include <set>
+#include "gdal_mdreader.h"
 
 #ifdef INTERNAL_LIBTIFF
 #include "tiffiop.h"
 #endif
 
-CPL_CVSID("$Id: geotiff.cpp 28419 2015-02-06 00:28:50Z rouault $");
+CPL_CVSID("$Id: geotiff.cpp 29129 2015-05-03 13:24:20Z rouault $");
 
 #if SIZEOF_VOIDP == 4
 static int bGlobalStripIntegerOverflow = FALSE;
@@ -97,107 +100,6 @@ static const GTIFFTags asTIFFTags[] =
 };
 
 /************************************************************************/
-/* ==================================================================== */
-/*                                GDALOverviewDS                        */
-/* ==================================================================== */
-/************************************************************************/
-
-/* GDALOverviewDS is not specific to GTiff and could probably be moved */
-/* in gcore. It is currently used to generate a fake */
-/* dataset from the overview levels of the source dataset that is taken */
-/* by CreateCopy() */
-
-#include "gdal_proxy.h"
-
-class GDALOverviewBand;
-
-class GDALOverviewDS : public GDALDataset
-{
-    private:
-
-        friend class GDALOverviewBand;
-
-        GDALDataset* poDS;
-        GDALDataset* poOvrDS;
-        int          nOvrLevel;
-
-    public:
-                        GDALOverviewDS(GDALDataset* poDS, int nOvrLevel);
-        virtual        ~GDALOverviewDS();
-
-        virtual char  **GetMetadata( const char * pszDomain = "" );
-        virtual const char *GetMetadataItem( const char * pszName,
-                                             const char * pszDomain = "" );
-};
-
-class GDALOverviewBand : public GDALProxyRasterBand
-{
-    protected:
-        GDALRasterBand*         poUnderlyingBand;
-        virtual GDALRasterBand* RefUnderlyingRasterBand();
-
-    public:
-                    GDALOverviewBand(GDALOverviewDS* poDS, int nBand);
-        virtual    ~GDALOverviewBand();
-};
-
-GDALOverviewDS::GDALOverviewDS(GDALDataset* poDS, int nOvrLevel)
-{
-    this->poDS = poDS;
-    this->nOvrLevel = nOvrLevel;
-    eAccess = poDS->GetAccess();
-    nRasterXSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize();
-    nRasterYSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize();
-    poOvrDS = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetDataset();
-    nBands = poDS->GetRasterCount();
-    int i;
-    for(i=0;i<nBands;i++)
-        SetBand(i+1, new GDALOverviewBand(this, i+1));
-}
-
-GDALOverviewDS::~GDALOverviewDS()
-{
-    FlushCache();
-}
-
-char  **GDALOverviewDS::GetMetadata( const char * pszDomain )
-{
-    if (poOvrDS != NULL)
-        return poOvrDS->GetMetadata(pszDomain);
-
-    return poDS->GetMetadata(pszDomain);
-}
-
-const char *GDALOverviewDS::GetMetadataItem( const char * pszName, const char * pszDomain )
-{
-    if (poOvrDS != NULL)
-        return poOvrDS->GetMetadataItem(pszName, pszDomain);
-
-    return poDS->GetMetadataItem(pszName, pszDomain);
-}
-
-GDALOverviewBand::GDALOverviewBand(GDALOverviewDS* poDS, int nBand)
-{
-    this->poDS = poDS;
-    this->nBand = nBand;
-    poUnderlyingBand = poDS->poDS->GetRasterBand(nBand)->GetOverview(poDS->nOvrLevel);
-    nRasterXSize = poDS->nRasterXSize;
-    nRasterYSize = poDS->nRasterYSize;
-    eDataType = poUnderlyingBand->GetRasterDataType();
-    poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
-}
-
-GDALOverviewBand::~GDALOverviewBand()
-{
-    FlushCache();
-}
-
-GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
-{
-    return poUnderlyingBand;
-}
-
-/************************************************************************/
 /*                            IsPowerOfTwo()                            */
 /************************************************************************/
 
@@ -256,6 +158,15 @@ enum
 class GTiffRasterBand;
 class GTiffRGBABand;
 class GTiffBitmapBand;
+class GTiffJPEGOverviewDS;
+class GTiffJPEGOverviewBand;
+
+typedef enum
+{
+    VIRTUAL_MEM_IO_NO,
+    VIRTUAL_MEM_IO_YES,
+    VIRTUAL_MEM_IO_IF_ENOUGH_RAM
+} VirtualMemIOEnum;
 
 class GTiffDataset : public GDALPamDataset
 {
@@ -265,10 +176,20 @@ class GTiffDataset : public GDALPamDataset
     friend class GTiffBitmapBand;
     friend class GTiffSplitBitmapBand;
     friend class GTiffOddBitsBand;
+    friend class GTiffJPEGOverviewDS;
+    friend class GTiffJPEGOverviewBand;
 
     friend void    GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality);
     
     TIFF	*hTIFF;
+    VSILFILE *fpL;
+    int         bStreamingIn;
+
+    int         bStreamingOut;
+    CPLString   osTmpFilename;
+    VSILFILE*   fpToWrite;
+    int         nLastWrittenBlockId;
+
     GTiffDataset **ppoActiveDSRef;
     GTiffDataset *poActiveDS; /* only used in actual base */
 
@@ -277,7 +198,7 @@ class GTiffDataset : public GDALPamDataset
 
     toff_t      nDirOffset;
     int		bBase;
-    int         bCloseTIFFHandle; /* usefull for closing TIFF handle opened by GTIFF_DIR: */
+    int         bCloseTIFFHandle; /* useful for closing TIFF handle opened by GTIFF_DIR: */
 
     uint16	nPlanarConfig;
     uint16	nSamplesPerPixel;
@@ -326,14 +247,22 @@ class GTiffDataset : public GDALPamDataset
     int		nOverviewCount;
     GTiffDataset **papoOverviewDS;
 
+    int         nJPEGOverviewVisibilityFlag; /* if > 0, the implicit JPEG overviews are visible through GetOverviewCount() */
+    int         nJPEGOverviewCount; /* currently visible overviews. Generally == nJPEGOverviewCountOri */
+    int         nJPEGOverviewCountOri; /* size of papoJPEGOverviewDS */
+    GTiffJPEGOverviewDS **papoJPEGOverviewDS;
+    int         GetJPEGOverviewCount();
+
     int		nGCPCount;
     GDAL_GCP	*pasGCPList;
 
     int         IsBlockAvailable( int nBlockId );
 
     int         bGeoTIFFInfoChanged;
-    int         bForceUnsetGT;
+    int         bForceUnsetGTOrGCPs;
     int         bForceUnsetProjection;
+
+    int         bNoDataChanged;
     int         bNoDataSet;
     double      dfNoDataValue;
 
@@ -352,9 +281,6 @@ class GTiffDataset : public GDALPamDataset
 
     int         bLoadingOtherBands;
 
-    static void WriteRPCTag( TIFF *, char ** );
-    void        ReadRPCTag();
-
     void*        pabyTempWriteBuffer;
     int          nTempWriteBufferSize;
     int          WriteEncodedTile(uint32 tile, GByte* pabyData, int bPreserveDataBuffer);
@@ -379,19 +305,9 @@ class GTiffDataset : public GDALPamDataset
 
     int           bClipWarn;
 
-    CPLString     osRPBFile;
-    int           FindRPBFile();
-    CPLString     osRPCFile;
-    int           FindRPCFile();
-    CPLString     osIMDFile;
-    int           FindIMDFile();
-    CPLString     osPVLFile;
-    int           FindPVLFile();
-    int           bHasSearchedRPC;
-    void          LoadRPCRPB();
-    int           bHasSearchedIMD;
-    int           bHasSearchedPVL;
-    void          LoadIMDPVL();
+    int           bIMDRPCMetadataLoaded;
+    char**        papszMetadataFiles;
+    void          LoadMetadata();
 
     int           bEXIFMetadataLoaded;
     void          LoadEXIFMetadata();
@@ -406,6 +322,7 @@ class GTiffDataset : public GDALPamDataset
     int           nZLevel;
     int           nLZMAPreset;
     int           nJpegQuality;
+    int           nJpegTablesMode;
     
     int           bPromoteTo8Bits;
 
@@ -424,12 +341,40 @@ class GTiffDataset : public GDALPamDataset
     CPLString     osGeorefFilename;
 
     int           bDirectIO;
-    
+
+    VirtualMemIOEnum eVirtualMemIOUsage;
+    CPLVirtualMem* psVirtualMemIOMapping;
+
     int           nSetPhotometricFromBandColorInterp;
 
     CPLVirtualMem *pBaseMapping;
     int            nRefBaseMapping;
-
+    
+    int            bHasDiscardedLsb;
+    std::vector<int> anMaskLsb, anOffsetLsb;
+    void           DiscardLsb(GByte* pabyBuffer, int nBytes, int iBand);
+    void           GetDiscardLsbOption(char** papszOptions);
+
+    int            GuessJPEGQuality(int& bOutHasQuantizationTable,
+                                    int& bOutHasHuffmanTable);
+
+    CPLErr         DirectIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg );
+
+    int            VirtualMemIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg );
   protected:
     virtual int         CloseDependentDatasets();
 
@@ -447,6 +392,14 @@ class GTiffDataset : public GDALPamDataset
     virtual const GDAL_GCP *GetGCPs();
     CPLErr         SetGCPs( int, const GDAL_GCP *, const char * );
 
+    virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
     virtual char **GetFileList(void);
 
     virtual CPLErr IBuildOverviews( const char *, int, int *, int, int *, 
@@ -482,6 +435,8 @@ class GTiffDataset : public GDALPamDataset
     virtual CPLErr          CreateMaskBand( int nFlags );
 
     // only needed by createcopy and close code.
+    static void     WriteRPC( GDALDataset *, TIFF *, int, const char *,
+                                   const char *, char **, int bWriteOnlyInPAMIfNeeded = FALSE );
     static int	    WriteMetadata( GDALDataset *, TIFF *, int, const char *,
                                    const char *, char **, int bExcludeRPBandIMGFileWriting = FALSE );
     static void	    WriteNoDataValue( TIFF *, double );
@@ -490,13 +445,386 @@ class GTiffDataset : public GDALPamDataset
                               int nXSize, int nYSize, int nBands,
                               GDALDataType eType,
                               double dfExtraSpaceForOverviews,
-                              char **papszParmList );
+                              char **papszParmList,
+                              VSILFILE** pfpL,
+                              CPLString& osTmpFilename);
 
     CPLErr   WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data, int bPreserveDataBuffer);
 
     static void SaveICCProfile(GTiffDataset *pDS, TIFF *hTIFF, char **papszParmList, uint32 nBitsPerSample);
 };
 
+
+/************************************************************************/
+/* ==================================================================== */
+/*                        GTiffJPEGOverviewDS                           */
+/* ==================================================================== */
+/************************************************************************/
+
+class GTiffJPEGOverviewDS : public GDALDataset
+{
+        friend class GTiffJPEGOverviewBand;
+        GTiffDataset* poParentDS;
+        int nOverviewLevel;
+
+        int        nJPEGTableSize;
+        GByte     *pabyJPEGTable;
+        CPLString  osTmpFilenameJPEGTable;
+
+        CPLString    osTmpFilename;
+        GDALDataset* poJPEGDS;
+        int          nBlockId; /* valid block id of the parent DS that match poJPEGDS */
+
+    public:
+        GTiffJPEGOverviewDS(GTiffDataset* poParentDS, int nOverviewLevel,
+                            const void* pJPEGTable, int nJPEGTableSize);
+       ~GTiffJPEGOverviewDS();
+
+       virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
+};
+
+class GTiffJPEGOverviewBand : public GDALRasterBand
+{
+    public:
+        GTiffJPEGOverviewBand(GTiffJPEGOverviewDS* poDS, int nBand);
+
+        virtual CPLErr IReadBlock( int, int, void * );
+};
+
+/************************************************************************/
+/*                        GTiffJPEGOverviewDS()                         */
+/************************************************************************/
+
+GTiffJPEGOverviewDS::GTiffJPEGOverviewDS(GTiffDataset* poParentDS, int nOverviewLevel,
+                                         const void* pJPEGTable, int nJPEGTableSizeIn)
+{
+    this->poParentDS = poParentDS;
+    this->nOverviewLevel = nOverviewLevel;
+    poJPEGDS = NULL;
+    nBlockId = -1;
+
+    osTmpFilenameJPEGTable.Printf("/vsimem/jpegtable_%p", this);
+    nJPEGTableSize = nJPEGTableSizeIn;
+
+    const GByte abyAdobeAPP14RGB[] = {
+        0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00,
+        0x64, 0x00, 0x00, 0x00, 0x00, 0x00 };
+    int bAddAdobe = ( poParentDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
+                      poParentDS->nPhotometric != PHOTOMETRIC_YCBCR && poParentDS->nBands == 3 );
+    pabyJPEGTable = (GByte*) CPLMalloc(nJPEGTableSize + ((bAddAdobe) ? sizeof(abyAdobeAPP14RGB) : 0));
+    memcpy(pabyJPEGTable, pJPEGTable, nJPEGTableSize);
+    if( bAddAdobe )
+    {
+        memcpy(pabyJPEGTable + nJPEGTableSize, abyAdobeAPP14RGB, sizeof(abyAdobeAPP14RGB));
+        nJPEGTableSize += sizeof(abyAdobeAPP14RGB);
+    }
+    VSIFCloseL(VSIFileFromMemBuffer( osTmpFilenameJPEGTable, pabyJPEGTable, nJPEGTableSize, TRUE ));
+
+    int nScaleFactor = 1 << nOverviewLevel;
+    nRasterXSize = (poParentDS->nRasterXSize + nScaleFactor - 1) / nScaleFactor; 
+    nRasterYSize = (poParentDS->nRasterYSize + nScaleFactor - 1) / nScaleFactor; 
+
+    int i;
+    for(i=1;i<=poParentDS->nBands;i++)
+        SetBand(i, new GTiffJPEGOverviewBand(this, i));
+
+    SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
+    if ( poParentDS->nPhotometric == PHOTOMETRIC_YCBCR )
+        SetMetadataItem( "COMPRESSION", "YCbCr JPEG", "IMAGE_STRUCTURE" );
+    else
+        SetMetadataItem( "COMPRESSION", "JPEG", "IMAGE_STRUCTURE" );
+}
+
+/************************************************************************/
+/*                       ~GTiffJPEGOverviewDS()                         */
+/************************************************************************/
+
+GTiffJPEGOverviewDS::~GTiffJPEGOverviewDS()
+{
+    if( poJPEGDS != NULL )
+        GDALClose( (GDALDatasetH) poJPEGDS );
+    VSIUnlink(osTmpFilenameJPEGTable);
+    if( osTmpFilename.size() )
+        VSIUnlink(osTmpFilename);
+}
+
+/************************************************************************/
+/*                            IRasterIO()                               */
+/************************************************************************/
+
+CPLErr GTiffJPEGOverviewDS::IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
+
+{
+    /* For non-single strip JPEG-IN-TIFF, the block based strategy will */
+    /* be the most efficient one, to avoid decompressing the JPEG content */
+    /* for each requested band */
+    if( nBandCount > 1 && poParentDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
+        ((int)poParentDS->nBlockXSize < poParentDS->nRasterXSize ||
+        poParentDS->nBlockYSize > 1) )
+    {
+        return BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+                                   pData, nBufXSize, nBufYSize,
+                                   eBufType, nBandCount, panBandMap,
+                                   nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
+    }
+    else
+    {
+        return GDALDataset::IRasterIO(
+                eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
+    }
+
+}
+
+/************************************************************************/
+/*                        GTiffJPEGOverviewBand()                       */
+/************************************************************************/
+
+GTiffJPEGOverviewBand::GTiffJPEGOverviewBand(GTiffJPEGOverviewDS* poDS, int nBand)
+{
+    this->poDS = poDS;
+    this->nBand = nBand;
+    eDataType = poDS->poParentDS->GetRasterBand(nBand)->GetRasterDataType();
+    poDS->poParentDS->GetRasterBand(nBand)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+    int nScaleFactor = 1 << poDS->nOverviewLevel;
+    nBlockXSize = (nBlockXSize + nScaleFactor - 1) / nScaleFactor; 
+    if( nBlockYSize == 1 )
+        nBlockYSize = 1;
+    else
+        nBlockYSize = (nBlockYSize + nScaleFactor - 1) / nScaleFactor; 
+}
+
+/************************************************************************/
+/*                          IReadBlock()                                */
+/************************************************************************/
+
+CPLErr GTiffJPEGOverviewBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pImage )
+{
+    GTiffJPEGOverviewDS* poGDS = (GTiffJPEGOverviewDS*)poDS;
+
+    /* Compute the source block ID */
+    int nBlockId;
+    if( nBlockYSize == 1 )
+    {
+        nBlockId = 0;
+    }
+    else
+    {
+        int nBlocksPerRow = DIV_ROUND_UP(poGDS->poParentDS->nRasterXSize, poGDS->poParentDS->nBlockXSize);
+        nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
+    }
+    if( poGDS->poParentDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+    {
+        nBlockId += (nBand-1) * poGDS->poParentDS->nBlocksPerBand;
+    }
+
+    if( !poGDS->poParentDS->SetDirectory() )
+        return CE_Failure;
+
+    /* Make sure it is available */
+    int nDataTypeSize = GDALGetDataTypeSize(eDataType)/8;
+    if( !poGDS->poParentDS->IsBlockAvailable(nBlockId) )
+    {
+        memset(pImage, 0, nBlockXSize * nBlockYSize * nDataTypeSize );
+        return CE_None;
+    }
+
+    int nScaleFactor = 1 << poGDS->nOverviewLevel;
+    if( poGDS->poJPEGDS == NULL || nBlockId != poGDS->nBlockId )
+    {
+        toff_t *panByteCounts = NULL;
+        toff_t *panOffsets = NULL;
+        vsi_l_offset nOffset = 0;
+        vsi_l_offset nByteCount = 0;
+
+        /* Find offset and size of the JPEG tile/strip */
+        TIFF* hTIFF = poGDS->poParentDS->hTIFF;
+        if( (( TIFFIsTiled( hTIFF ) 
+            && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts )
+            && TIFFGetField( hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets ) )
+            || ( !TIFFIsTiled( hTIFF ) 
+            && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts )
+            && TIFFGetField( hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets ) )) &&
+            panByteCounts != NULL && panOffsets != NULL )
+        {
+            if( panByteCounts[nBlockId] < 2 )
+                return CE_Failure;
+            nOffset = panOffsets[nBlockId] + 2; /* skip leading 0xFF 0xF8 */
+            nByteCount = panByteCounts[nBlockId] - 2;
+        }
+        else
+        {
+            return CE_Failure;
+        }
+
+        /* Special case for last strip that might be smaller than other strips */
+        /* In which case we must invalidate the dataset */
+        if( !TIFFIsTiled( hTIFF ) && poGDS->poParentDS->nBlockYSize > 1 &&
+            (nBlockYOff + 1 == (int)DIV_ROUND_UP(poGDS->poParentDS->nRasterYSize, poGDS->poParentDS->nBlockYSize) ||
+             (poGDS->poJPEGDS != NULL && poGDS->poJPEGDS->GetRasterYSize() != nBlockYSize * nScaleFactor)) )
+        {
+            if( poGDS->poJPEGDS != NULL )
+                GDALClose( (GDALDatasetH) poGDS->poJPEGDS );
+            poGDS->poJPEGDS = NULL;
+        }
+
+        CPLString osFileToOpen;
+        poGDS->osTmpFilename.Printf("/vsimem/sparse_%p", poGDS);
+        VSILFILE* fp = VSIFOpenL(poGDS->osTmpFilename, "wb+");
+
+        /* If the size of the JPEG strip/tile is small enough, we will */
+        /* read it from the TIFF file and forge a in-memory JPEG file with */
+        /* the JPEG table followed by the JPEG data. */
+        int bInMemoryJPEGFile = ( nByteCount < 256 * 256 );
+        if( bInMemoryJPEGFile )
+        {
+            /* If the previous file was opened as a /vsisparse/, we have to re-open */
+            if( poGDS->poJPEGDS != NULL &&
+                strncmp(poGDS->poJPEGDS->GetDescription(), "/vsisparse/", strlen("/vsisparse/")) == 0 )
+            {
+                GDALClose( (GDALDatasetH) poGDS->poJPEGDS );
+                poGDS->poJPEGDS = NULL;
+            }
+            osFileToOpen = poGDS->osTmpFilename;
+
+            VSIFSeekL(fp, poGDS->nJPEGTableSize + nByteCount - 1, SEEK_SET);
+            char ch = 0;
+            VSIFWriteL(&ch, 1, 1, fp);
+            GByte* pabyBuffer = VSIGetMemFileBuffer( poGDS->osTmpFilename, NULL, FALSE);
+            memcpy(pabyBuffer, poGDS->pabyJPEGTable, poGDS->nJPEGTableSize);
+            VSILFILE* fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata( hTIFF ));
+            VSIFSeekL(fpTIF, nOffset, SEEK_SET);
+            VSIFReadL(pabyBuffer + poGDS->nJPEGTableSize, 1, (size_t)nByteCount, fpTIF);
+        }
+        else
+        {
+            /* If the JPEG strip/tile is too big (e.g. a single-strip JPEG-in-TIFF) */
+            /* we will use /vsisparse mechanism to make a fake JPEG file */
+
+            /* If the previous file was NOT opened as a /vsisparse/, we have to re-open */
+            if( poGDS->poJPEGDS != NULL &&
+                strncmp(GDALGetDescription(poGDS->poJPEGDS), "/vsisparse/", strlen("/vsisparse/")) != 0  )
+            {
+                GDALClose( (GDALDatasetH) poGDS->poJPEGDS );
+                poGDS->poJPEGDS = NULL;
+            }
+            osFileToOpen = CPLSPrintf("/vsisparse/%s", poGDS->osTmpFilename.c_str());
+
+            VSIFPrintfL(fp, "<VSISparseFile><SubfileRegion><Filename relative='0'>%s</Filename>"
+                        "<DestinationOffset>0</DestinationOffset>"
+                        "<SourceOffset>0</SourceOffset>"
+                        "<RegionLength>%d</RegionLength>"
+                        "</SubfileRegion>"
+                        "<SubfileRegion>"
+                        "<Filename relative='0'>%s</Filename>"
+                        "<DestinationOffset>%d</DestinationOffset>"
+                        "<SourceOffset>" CPL_FRMT_GUIB "</SourceOffset>"
+                        "<RegionLength>" CPL_FRMT_GUIB "</RegionLength>"
+                        "</SubfileRegion></VSISparseFile>",
+                        poGDS->osTmpFilenameJPEGTable.c_str(),
+                        (int)poGDS->nJPEGTableSize,
+                        poGDS->poParentDS->GetDescription(),
+                        (int)poGDS->nJPEGTableSize,
+                        nOffset,
+                        nByteCount);
+        }
+        VSIFCloseL(fp);
+
+        if( poGDS->poJPEGDS == NULL )
+        {
+            const char* apszDrivers[] = { "JPEG", NULL };
+            poGDS->poJPEGDS = (GDALDataset*) GDALOpenEx(osFileToOpen,
+                                                        GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                                                apszDrivers,
+                                                                NULL, NULL);
+            if( poGDS->poJPEGDS != NULL )
+            {
+                /* Force all implicit overviews to be available, even for small tiles */
+                CPLSetThreadLocalConfigOption("JPEG_FORCE_INTERNAL_OVERVIEWS", "YES");
+                GDALGetOverviewCount(GDALGetRasterBand(poGDS->poJPEGDS, 1));
+                CPLSetThreadLocalConfigOption("JPEG_FORCE_INTERNAL_OVERVIEWS", NULL);
+
+                poGDS->nBlockId = nBlockId;
+            }
+        }
+        else
+        {
+            /* Trick: we invalidate the JPEG dataset to force a reload */
+            /* of the new content */
+            CPLErrorReset();
+            poGDS->poJPEGDS->FlushCache();
+            if( CPLGetLastErrorNo() != 0 )
+            {
+                GDALClose( (GDALDatasetH) poGDS->poJPEGDS );
+                poGDS->poJPEGDS = NULL;
+                return CE_Failure;
+            }
+            poGDS->nBlockId = nBlockId;
+        }
+    }
+
+    CPLErr eErr = CE_Failure;
+    if( poGDS->poJPEGDS )
+    {
+        GDALDataset* poDS = poGDS->poJPEGDS;
+
+        int nReqXOff = 0, nReqYOff, nReqXSize, nReqYSize;
+        if( nBlockYSize == 1 )
+        {
+            nReqYOff = nBlockYOff * nScaleFactor;
+            nReqXSize = poDS->GetRasterXSize();
+            nReqYSize = nScaleFactor;
+        }
+        else
+        {
+            nReqYOff = 0;
+            nReqXSize = nBlockXSize * nScaleFactor;
+            nReqYSize = nBlockYSize * nScaleFactor;
+        }
+        int nBufXSize = nBlockXSize;
+        int nBufYSize = nBlockYSize;
+        if( nReqXOff + nReqXSize > poDS->GetRasterXSize() )
+        {
+            nReqXSize = poDS->GetRasterXSize() - nReqXOff;
+            nBufXSize = nReqXSize / nScaleFactor;
+            if( nBufXSize == 0 ) nBufXSize = 1;
+        }
+        if( nReqYOff + nReqYSize > poDS->GetRasterYSize() )
+        {
+            nReqYSize = poDS->GetRasterYSize() - nReqYOff;
+            nBufYSize = nReqYSize / nScaleFactor;
+            if( nBufYSize == 0 ) nBufYSize = 1;
+        }
+
+        int nSrcBand = ( poGDS->poParentDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) ? 1 : nBand;
+        if( nSrcBand <= poDS->GetRasterCount() )
+        {
+            eErr = poDS->GetRasterBand(nSrcBand)->RasterIO(GF_Read,
+                                 nReqXOff, nReqYOff, nReqXSize, nReqYSize,
+                                 pImage,
+                                 nBufXSize, nBufYSize, eDataType,
+                                 0, nBlockXSize * nDataTypeSize, NULL );
+        }
+    }
+
+    return eErr;
+}
+
 /************************************************************************/
 /*                        GTIFFSetJpegQuality()                         */
 /* Called by GTIFFBuildOverviews() to set the jpeg quality on the IFD   */
@@ -539,7 +867,8 @@ class GTiffRasterBand : public GDALPamRasterBand
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace );
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg );
 
     std::set<GTiffRasterBand **> aSetPSelf;
     static void     DropReferenceVirtualMem(void* pUserData);
@@ -568,7 +897,8 @@ public:
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace );
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg );
 
     virtual const char *GetDescription() const;
     virtual void        SetDescription( const char * );
@@ -776,14 +1106,15 @@ GTiffRasterBand::~GTiffRasterBand()
 
 /* Reads directly bytes from the file using ReadMultiRange(), and by-pass */
 /* block reading. Restricted to simple TIFF configurations (un-tiled, */
-/* uncompressed data, standard data types). Particularly usefull to extract */
+/* uncompressed data, standard data types). Particularly useful to extract */
 /* sub-windows of data on a large /vsicurl dataset). */
 
 CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace )
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg )
 {
     if( !(eRWFlag == GF_Read &&
           poGDS->nCompression == COMPRESSION_NONE &&
@@ -799,37 +1130,24 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
         return CE_Failure;
     }
 
+    /* we only know how to deal with nearest neighbour in this optimized routine */
+    if( (nXSize != nBufXSize || nYSize != nBufYSize) &&
+        psExtraArg != NULL &&
+        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour )
+    {
+        return CE_Failure;
+    }
+
     /*CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)",
              nXOff, nYOff, nXSize, nYSize,
              nBufXSize, nBufYSize);*/
 
-/* ==================================================================== */
-/*      Do we have overviews that would be appropriate to satisfy       */
-/*      this request?                                                   */
-/* ==================================================================== */
-    if( (nBufXSize < nXSize || nBufYSize < nYSize)
-        && GetOverviewCount() > 0 && eRWFlag == GF_Read )
-    {
-        int         nOverview;
-
-        nOverview =
-            GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
-                                        nBufXSize, nBufYSize);
-        if (nOverview >= 0)
-        {
-            GDALRasterBand* poOverviewBand = GetOverview(nOverview);
-            if (poOverviewBand == NULL)
-                return CE_Failure;
-
-            return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
-                                            pData, nBufXSize, nBufYSize, eBufType,
-                                            nPixelSpace, nLineSpace );
-        }
-    }
-
     /* Make sure that TIFFTAG_STRIPOFFSETS is up-to-date */
     if (poGDS->GetAccess() == GA_Update)
+    {
         poGDS->FlushCache();
+        VSI_TIFFFlushBufferedWrite( TIFFClientdata( poGDS->hTIFF ) );
+    }
 
     /* Get strip offsets */
     toff_t *panTIFFOffsets = NULL;
@@ -846,11 +1164,11 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
     vsi_l_offset* panOffsets = (vsi_l_offset*)
                             VSIMalloc(nReqYSize * sizeof(vsi_l_offset));
     size_t* panSizes = (size_t*) VSIMalloc(nReqYSize * sizeof(size_t));
-    int eDTSize = GDALGetDataTypeSize(eDataType) / 8;
+    int nDTSize = GDALGetDataTypeSize(eDataType) / 8;
     void* pTmpBuffer = NULL;
     CPLErr eErr = CE_None;
     int nContigBands = ((poGDS->nPlanarConfig == PLANARCONFIG_CONTIG) ? poGDS->nBands : 1);
-    int ePixelSize = eDTSize * nContigBands;
+    int ePixelSize = nDTSize * nContigBands;
 
     if (ppData == NULL || panOffsets == NULL || panSizes == NULL)
         eErr = CE_Failure;
@@ -900,7 +1218,7 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
     /* Extract data from the file */
     if (eErr == CE_None)
     {
-        VSILFILE* fp = (VSILFILE*) TIFFClientdata( poGDS->hTIFF );
+        VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( poGDS->hTIFF ));
         int nRet = VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
         if (nRet != 0)
             eErr = CE_Failure;
@@ -911,7 +1229,7 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
     {
         for(iLine=0;iLine<nReqYSize;iLine++)
         {
-            GDALSwapWords( ppData[iLine], eDTSize, nReqXSize * nContigBands, eDTSize);
+            GDALSwapWords( ppData[iLine], nDTSize, nReqXSize * nContigBands, nDTSize);
         }
     }
 
@@ -924,7 +1242,7 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
                             (int)((iY + 0.5) * nYSize / nBufYSize);
             if (nBufXSize == nXSize && nContigBands == 1)
             {
-                GDALCopyWords( ppData[iSrcY], eDataType, eDTSize,
+                GDALCopyWords( ppData[iSrcY], eDataType, nDTSize,
                                 ((GByte*)pData) + iY * nLineSpace,
                                 eBufType, nPixelSpace,
                                 nReqXSize);
@@ -932,16 +1250,26 @@ CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
             else
             {
                 GByte* pabySrcData = ((GByte*)ppData[iSrcY]) +
-                            ((nContigBands > 1) ? (nBand-1) : 0) * eDTSize;
+                            ((nContigBands > 1) ? (nBand-1) : 0) * nDTSize;
                 GByte* pabyDstData = ((GByte*)pData) + iY * nLineSpace;
-                for(int iX=0;iX<nBufXSize;iX++)
+                if( nBufXSize == nXSize && nDTSize == 1 && eBufType == GDT_Byte )
+                {
+                    for(int iX=0;iX<nBufXSize;iX++)
+                    {
+                        pabyDstData[iX * nPixelSpace] = pabySrcData[iX * ePixelSize];
+                    }
+                }
+                else
                 {
-                    int iSrcX = (nBufXSize == nXSize) ? iX :
-                                    (int)((iX+0.5) * nXSize / nBufXSize);
-                    GDALCopyWords( pabySrcData + iSrcX * ePixelSize,
-                                   eDataType, 0,
-                                   pabyDstData + iX * nPixelSpace,
-                                   eBufType, 0, 1);
+                    for(int iX=0;iX<nBufXSize;iX++)
+                    {
+                        int iSrcX = (nBufXSize == nXSize) ? iX :
+                                        (int)((iX+0.5) * nXSize / nBufXSize);
+                        GDALCopyWords( pabySrcData + iSrcX * ePixelSize,
+                                    eDataType, 0,
+                                    pabyDstData + iX * nPixelSpace,
+                                    eBufType, 0, 1);
+                    }
                 }
             }
         }
@@ -1056,7 +1384,9 @@ CPLVirtualMem* GTiffRasterBand::GetVirtualMemAutoInternal( GDALRWFlag eRWFlag,
         }
     }
 
-    VSILFILE* fp = (VSILFILE*) TIFFClientdata( poGDS->hTIFF );
+    if( !poGDS->SetDirectory() ) /* very important to make hTIFF up-to-date */
+        return NULL;
+    VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( poGDS->hTIFF ));
 
     vsi_l_offset nLength = (vsi_l_offset)nRasterYSize * nLineSize;
 
@@ -1064,6 +1394,9 @@ CPLVirtualMem* GTiffRasterBand::GetVirtualMemAutoInternal( GDALRWFlag eRWFlag,
           VSIFGetNativeFileDescriptorL(fp) != NULL &&
           nLength == (size_t)nLength &&
           poGDS->nCompression == COMPRESSION_NONE &&
+          (poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK ||
+           poGDS->nPhotometric == PHOTOMETRIC_RGB ||
+           poGDS->nPhotometric == PHOTOMETRIC_PALETTE) &&
           (poGDS->nBitsPerSample == 8 || poGDS->nBitsPerSample == 16 ||
            poGDS->nBitsPerSample == 32 || poGDS->nBitsPerSample == 64) &&
           poGDS->nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
@@ -1072,12 +1405,12 @@ CPLVirtualMem* GTiffRasterBand::GetVirtualMemAutoInternal( GDALRWFlag eRWFlag,
         return NULL;
     }
 
-    if (!poGDS->SetDirectory())
-        return NULL;
-
     /* Make sure that TIFFTAG_STRIPOFFSETS is up-to-date */
     if (poGDS->GetAccess() == GA_Update)
+    {
         poGDS->FlushCache();
+        VSI_TIFFFlushBufferedWrite( TIFFClientdata( poGDS->hTIFF ) );
+    }
 
     /* Get strip offsets */
     toff_t *panTIFFOffsets = NULL;
@@ -1125,6 +1458,7 @@ CPLVirtualMem* GTiffRasterBand::GetVirtualMemAutoInternal( GDALRWFlag eRWFlag,
                 return NULL;
             }
             int ret = TIFFWriteEncodedStrip(poGDS->hTIFF, 0, pabyData, nBlockSize);
+            VSI_TIFFFlushBufferedWrite( TIFFClientdata( poGDS->hTIFF ) );
             VSIFree(pabyData);
             if( ret != nBlockSize )
             {
@@ -1155,90 +1489,929 @@ CPLVirtualMem* GTiffRasterBand::GetVirtualMemAutoInternal( GDALRWFlag eRWFlag,
         }
     }
 
-    GIntBig nBlockSpacing = 0;
-    int bCompatibleSpacing = TRUE;
-    toff_t nPrevOffset = 0;
-    for(i = 0; i < poGDS->nBlocksPerBand; i ++)
+    GIntBig nBlockSpacing = 0;
+    int bCompatibleSpacing = TRUE;
+    toff_t nPrevOffset = 0;
+    for(i = 0; i < poGDS->nBlocksPerBand; i ++)
+    {
+        toff_t nCurOffset;
+        if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+            nCurOffset = panTIFFOffsets[poGDS->nBlocksPerBand * (nBand - 1) + i];
+        else
+            nCurOffset = panTIFFOffsets[i];
+        if( nCurOffset == 0 )
+        {
+            bCompatibleSpacing = FALSE;
+            break;
+        }
+        if( i > 0 )
+        {
+            GIntBig nCurSpacing = nCurOffset - nPrevOffset;
+            if( i == 1 )
+            {
+                if( nCurSpacing != (GIntBig)nBlockYSize * nLineSize )
+                {
+                    bCompatibleSpacing = FALSE;
+                    break;
+                }
+                nBlockSpacing = nCurSpacing;
+            }
+            else if( nBlockSpacing != nCurSpacing )
+            {
+                bCompatibleSpacing = FALSE;
+                break;
+            }
+        }
+        nPrevOffset = nCurOffset;
+    }
+
+    if( !bCompatibleSpacing )
+    {
+        return NULL;
+    }
+    else
+    {
+        vsi_l_offset nOffset;
+        if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
+        {
+            CPLAssert( poGDS->pBaseMapping == NULL );
+            nOffset = panTIFFOffsets[0];
+        }
+        else
+            nOffset = panTIFFOffsets[poGDS->nBlocksPerBand * (nBand - 1)];
+        CPLVirtualMem* pVMem = CPLVirtualMemFileMapNew(
+            fp, nOffset, nLength,
+            (eRWFlag == GF_Write) ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
+            NULL, NULL);
+        if( pVMem == NULL )
+        {
+            return NULL;
+        }
+        else
+        {
+            if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
+            {
+                poGDS->pBaseMapping = pVMem;
+                pVMem = GetVirtualMemAutoInternal( eRWFlag,
+                                                   pnPixelSpace,
+                                                   pnLineSpace,
+                                                   papszOptions );
+                /* drop ref on base mapping */
+                CPLVirtualMemFree(poGDS->pBaseMapping);
+                if( pVMem == NULL )
+                    poGDS->pBaseMapping = NULL;
+            }
+            else
+            {
+                *pnPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
+                if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
+                    *pnPixelSpace *= poGDS->nBands;
+                *pnLineSpace = nLineSize;
+            }
+            return pVMem;
+        }
+    }
+}
+
+/************************************************************************/
+/*                            IRasterIO()                               */
+/************************************************************************/
+
+CPLErr GTiffDataset::IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
+
+{
+    CPLErr eErr;
+    /* Try to pass the request to the most appropriate overview dataset */
+    if( nBufXSize < nXSize && nBufYSize < nYSize )
+    {
+        int nXOffMod = nXOff, nYOffMod = nYOff, nXSizeMod = nXSize, nYSizeMod = nYSize;
+        GDALRasterIOExtraArg sExtraArg;
+    
+        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
+        
+        nJPEGOverviewVisibilityFlag ++;
+        int iOvrLevel = GDALBandGetBestOverviewLevel2(papoBands[0],
+                                                     nXOffMod, nYOffMod,
+                                                     nXSizeMod, nYSizeMod,
+                                                     nBufXSize, nBufYSize,
+                                                     &sExtraArg);
+        nJPEGOverviewVisibilityFlag --;
+
+        if( iOvrLevel >= 0 && papoBands[0]->GetOverview(iOvrLevel) != NULL &&
+            papoBands[0]->GetOverview(iOvrLevel)->GetDataset() != NULL )
+        {
+            nJPEGOverviewVisibilityFlag ++;
+            eErr = papoBands[0]->GetOverview(iOvrLevel)->GetDataset()->RasterIO(
+                eRWFlag, nXOffMod, nYOffMod, nXSizeMod, nYSizeMod,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, &sExtraArg);
+            nJPEGOverviewVisibilityFlag --;
+            return eErr;
+        }
+    }
+
+    if( eVirtualMemIOUsage != VIRTUAL_MEM_IO_NO )
+    {
+        int nErr = VirtualMemIO(
+                eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
+        if (nErr >= 0)
+            return (CPLErr)nErr;
+    }
+    if (bDirectIO)
+    {
+        eErr = DirectIO(
+                eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
+        if (eErr == CE_None)
+            return eErr;
+    }
+
+    nJPEGOverviewVisibilityFlag ++;
+    eErr =  GDALPamDataset::IRasterIO(
+                eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
+    nJPEGOverviewVisibilityFlag --;
+    return eErr;
+}
+
+/************************************************************************/
+/*                         VirtualMemIO()                               */
+/************************************************************************/
+
+//#define DEBUG_REACHED_VIRTUAL_MEM_IO
+#ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
+static int anReachedVirtualMemIO[32] = { 0 };
+#define REACHED(x)  anReachedVirtualMemIO[x] = 1
+#else
+#define REACHED(x)
+#endif
+
+int GTiffDataset::VirtualMemIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg )
+{
+    GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
+    if( eAccess == GA_Update || eRWFlag == GF_Write || bStreamingIn )
+        return -1;
+
+    /* we only know how to deal with nearest neighbour in this optimized routine */
+    if( (nXSize != nBufXSize || nYSize != nBufYSize) &&
+        psExtraArg != NULL &&
+        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour )
+    {
+        return -1;
+    }
+
+    if( !SetDirectory() )
+        return CE_Failure;
+
+    size_t nMappingSize = 0;
+    GByte* pabySrcData = NULL;
+    if( strncmp(GetDescription(), "/vsimem/", strlen("/vsimem/")) == 0 )
+    {
+        vsi_l_offset nDataLength = 0;
+        pabySrcData = VSIGetMemFileBuffer(GetDescription(), &nDataLength, FALSE);
+        nMappingSize = (size_t)nDataLength;
+        if( pabySrcData == NULL )
+            return -1;
+    }
+    else if( psVirtualMemIOMapping == NULL )
+    {
+        if( !(nCompression == COMPRESSION_NONE &&
+              (nPhotometric == PHOTOMETRIC_MINISBLACK ||
+              nPhotometric == PHOTOMETRIC_RGB ||
+              nPhotometric == PHOTOMETRIC_PALETTE) &&
+              (nBitsPerSample == 8 || (nBitsPerSample == 16) ||
+              nBitsPerSample == 32 || nBitsPerSample == 64) &&
+              nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
+              !TIFFIsByteSwapped(hTIFF) ) )
+        {
+            eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+            return -1;
+        }
+        VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( hTIFF ));
+        if( !CPLIsVirtualMemFileMapAvailable() ||
+            VSIFGetNativeFileDescriptorL(fp) == NULL )
+        {
+            eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+            return -1;
+        }
+        VSIFSeekL(fp, 0, SEEK_END);
+        vsi_l_offset nLength = VSIFTellL(fp);
+        if( (size_t)nLength != nLength )
+        {
+            eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+            return -1;
+        }
+        if( eVirtualMemIOUsage == VIRTUAL_MEM_IO_IF_ENOUGH_RAM )
+        {
+            GIntBig nRAM = CPLGetUsablePhysicalRAM();
+            if( (GIntBig)nLength > nRAM )
+            {
+                CPLDebug("GTiff", "Not enough RAM to map whole file into memory.");
+                eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+                return -1;
+            }
+        }
+        psVirtualMemIOMapping = CPLVirtualMemFileMapNew(
+            fp, 0, nLength, VIRTUALMEM_READONLY, NULL, NULL);
+        if( psVirtualMemIOMapping == NULL )
+        {
+            eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+            return -1;
+        }
+        eVirtualMemIOUsage = VIRTUAL_MEM_IO_YES;
+    }
+
+    /* Get strip offsets */
+    toff_t *panOffsets = NULL;
+    if ( !TIFFGetField( hTIFF, (TIFFIsTiled( hTIFF )) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS, &panOffsets ) ||
+         panOffsets == NULL )
+    {
+        eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+        return CE_Failure;
+    }
+
+    int nDTSize = GDALGetDataTypeSize(eDataType) / 8;
+    int nBufDTSize = GDALGetDataTypeSize(eBufType) / 8;
+
+    int iBand;
+    int bUseContigImplementation =
+        ( nPlanarConfig == PLANARCONFIG_CONTIG ) && (nBandCount > 1) && (nBandSpace == nBufDTSize);
+    for(iBand = 0; iBand < nBandCount; iBand ++ )
+    {
+        int nBand = panBandMap[iBand];
+        if( nBand != iBand + 1 )
+        {
+            bUseContigImplementation = FALSE;
+            break;
+        }
+    }
+
+    if( psVirtualMemIOMapping )
+    {
+        nMappingSize = CPLVirtualMemGetSize(psVirtualMemIOMapping);
+        pabySrcData = (GByte*)CPLVirtualMemGetAddr(psVirtualMemIOMapping);
+    }
+    const int nBandsPerBlock = ( nPlanarConfig == PLANARCONFIG_SEPARATE ) ? 1 : nBands;
+    const int nBandsPerBlockDTSize = nBandsPerBlock * nDTSize;
+    const int nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
+    const int bByteOnly = (eDataType == eBufType && nDTSize == 1 );
+    const int bByteNoXResampling = ( bByteOnly && nXSize == nBufXSize );
+    const int nBlockSize = nBlockXSize * nBlockYSize * nBandsPerBlockDTSize;
+
+    int bNoDataSet;
+    double dfNoData = GetRasterBand(1)->GetNoDataValue( &bNoDataSet );
+    GByte abyNoData = 0;
+    if( !bNoDataSet )
+        dfNoData = 0;
+    else if( dfNoData >= 0 && dfNoData <= 255 )
+        abyNoData = (GByte) (dfNoData + 0.5);
+
+    if( bUseContigImplementation )
+    {
+        if( TIFFIsTiled( hTIFF ) )
+        {
+            GByte* pabyData = (GByte*)pData;
+            for(int y=0;y<nBufYSize;y++)
+            {
+                int nSrcLine = nYOff + (int)((y + 0.5) * nYSize / nBufYSize);
+                int nBlockYOff = nSrcLine / nBlockYSize;
+                int nYOffsetInBlock = nSrcLine % nBlockYSize;
+                int nBaseByteOffsetInBlock = nYOffsetInBlock * nBlockXSize * nBandsPerBlockDTSize;
+
+                if( bByteNoXResampling )
+                {
+                    GByte* pabyLocalSrcData = NULL;
+                    GByte* pabyLocalData = pabyData + y * nLineSpace;
+                    int nLastPixelBlock = 0;
+                    int nBlockXOff = nXOff / nBlockXSize;
+                    int nXOffsetInBlock = nXOff % nBlockXSize;
+                    int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
+                    int nByteOffsetInBlock = nBaseByteOffsetInBlock + nXOffsetInBlock * nBandsPerBlockDTSize;
+
+                    for(int x=0;x<nBufXSize;x++)
+                    {
+                        int nSrcPixel = nXOff + x;
+                        if( nSrcPixel >= nLastPixelBlock )
+                        {
+                            REACHED(0);
+                            nLastPixelBlock = (nBlockXOff + 1) * nBlockXSize;
+                            toff_t nCurOffset = panOffsets[nBlockId];
+                            if( nCurOffset )
+                            {
+                                if( nCurOffset + nBlockSize > nMappingSize )
+                                {
+                                    REACHED(24);
+                                    CPLError(CE_Failure, CPLE_FileIO,
+                                            "Missing data for block %d", nBlockId);
+                                    return CE_Failure;
+                                }
+                                pabyLocalSrcData = pabySrcData + nCurOffset + nByteOffsetInBlock;
+                            }
+                            else
+                                pabyLocalSrcData = NULL;
+                            nByteOffsetInBlock = nBaseByteOffsetInBlock;
+                            nBlockXOff ++;
+                            nBlockId ++; 
+                        }
+                        else
+                        {
+                            REACHED(1);
+                        }
+
+                        if( pabyLocalSrcData == NULL )
+                        {
+                            REACHED(2);
+                            for(int iBand=0;iBand<nBandCount;iBand++)
+                                pabyLocalData[iBand] = abyNoData;
+                        }
+                        else
+                        {
+                            REACHED(3);
+                            for(int iBand=0;iBand<nBandCount;iBand++)
+                                pabyLocalData[iBand] = pabyLocalSrcData[iBand];
+                            pabyLocalSrcData += nBandsPerBlockDTSize;
+                        }
+                        pabyLocalData += nPixelSpace;
+                    }
+                }
+                else
+                {
+                    for(int x=0;x<nBufXSize;x++)
+                    {
+                        int nSrcPixel = nXOff + (int)((x + 0.5) * nXSize / nBufXSize);
+                        int nBlockXOff = nSrcPixel / nBlockXSize;
+                        int nXOffsetInBlock = nSrcPixel % nBlockXSize;
+                        int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
+                        int nByteOffsetInBlock = nBaseByteOffsetInBlock + nXOffsetInBlock * nBandsPerBlockDTSize;
+                        toff_t nCurOffset = panOffsets[nBlockId];
+                        if( nCurOffset == 0 )
+                        {
+                            REACHED(4);
+                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
+                                          pabyData + y * nLineSpace + x * nPixelSpace,
+                                          eBufType, nBandSpace,
+                                          nBandCount);
+                        }
+                        else
+                        {
+                            if( nCurOffset + nBlockSize > nMappingSize )
+                            {
+                                REACHED(25);
+                                CPLError(CE_Failure, CPLE_FileIO,
+                                            "Missing data for block %d", nBlockId);
+                                return CE_Failure;
+                            }
+                            REACHED(5);
+                            GDALCopyWords(pabySrcData + nCurOffset + nByteOffsetInBlock,
+                                            eDataType, nDTSize,
+                                            pabyData + y * nLineSpace + x * nPixelSpace,
+                                            eBufType, nBandSpace,
+                                            nBandCount);
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            GByte* pabyData = (GByte*)pData;
+            for(int y=0;y<nBufYSize;y++)
+            {
+                int nSrcLine = nYOff + (int)((y + 0.5) * nYSize / nBufYSize);
+                int nBlockYOff = nSrcLine / nBlockYSize;
+                int nYOffsetInBlock = nSrcLine % nBlockYSize;
+                int nBlockId = nBlockYOff;
+                toff_t nCurOffset = panOffsets[nBlockId];
+                if( nCurOffset == 0 )
+                {
+                    REACHED(6);
+                    for(int x=0;x<nBufXSize;x++)
+                    {
+                        GDALCopyWords(&dfNoData, GDT_Float64, 0,
+                                      pabyData + y * nLineSpace + x * nPixelSpace,
+                                      eBufType, nBandSpace,
+                                      nBandCount);
+                    }
+                }
+                else
+                {
+                    if( nCurOffset + (nYOffsetInBlock + 1) * nBlockXSize * nBandsPerBlockDTSize > nMappingSize )
+                    {
+                        REACHED(26);
+                        CPLError(CE_Failure, CPLE_FileIO,
+                                    "Missing data for block %d", nBlockId);
+                        return CE_Failure;
+                    }
+                    int nBaseByteOffsetInBlock = (nYOffsetInBlock * nBlockXSize + nXOff) * nBandsPerBlockDTSize;
+                    GByte* pabyLocalData = pabyData + y * nLineSpace;
+                    GByte* pabyLocalSrcData = pabySrcData + nCurOffset + nBaseByteOffsetInBlock;
+                    if( bByteNoXResampling )
+                    {
+                        if( nPixelSpace == nBandCount && nBandsPerBlockDTSize == nBandCount )
+                        {
+                            REACHED(7);
+                            memcpy(pabyLocalData, pabyLocalSrcData, nBufXSize * nBandCount);
+                        }
+                        else
+                        {
+                            REACHED(23);
+                            for(int x=0;x<nBufXSize;x++)
+                            {
+                                for(int iBand=0;iBand<nBandCount;iBand++)
+                                    pabyLocalData[iBand] = pabyLocalSrcData[iBand];
+                                pabyLocalSrcData += nBandsPerBlockDTSize;
+                                pabyLocalData += nPixelSpace;
+                            }
+                        }
+                    }
+                    else if( bByteOnly )
+                    {
+                        REACHED(31);
+                        for(int x=0;x<nBufXSize;x++)
+                        {
+                            int nSrcPixelMinusXOff = (int)((x + 0.5) * nXSize / nBufXSize);
+                            for(int iBand=0;iBand<nBandCount;iBand++)
+                                pabyLocalData[x * nPixelSpace + iBand /* * nBandSpace*/] = pabyLocalSrcData[nSrcPixelMinusXOff * nBandsPerBlockDTSize + iBand];
+                        }
+                    }
+                    else
+                    {
+                        REACHED(8);
+                        for(int x=0;x<nBufXSize;x++)
+                        {
+                            int nSrcPixelMinusXOff = (int)((x + 0.5) * nXSize / nBufXSize);
+                            GDALCopyWords(pabyLocalSrcData + nSrcPixelMinusXOff * nBandsPerBlockDTSize,
+                                          eDataType, nDTSize,
+                                          pabyLocalData + x * nPixelSpace,
+                                          eBufType, nBandSpace,
+                                          nBandCount);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else
+    {
+        if( TIFFIsTiled( hTIFF ) )
+        {
+            for(iBand = 0; iBand < nBandCount; iBand ++ )
+            {
+                int nBand = panBandMap[iBand];
+                GByte* pabyData = (GByte*)pData + iBand * nBandSpace;
+                for(int y=0;y<nBufYSize;y++)
+                {
+                    int nSrcLine = nYOff + (int)((y + 0.5) * nYSize / nBufYSize);
+                    int nBlockYOff = nSrcLine / nBlockYSize;
+                    int nYOffsetInBlock = nSrcLine % nBlockYSize;
+
+                    int nBaseByteOffsetInBlock = nYOffsetInBlock * nBlockXSize * nBandsPerBlockDTSize;
+                    if ( nPlanarConfig == PLANARCONFIG_CONTIG )
+                    {
+                        REACHED(9);
+                        nBaseByteOffsetInBlock += (nBand-1) * nDTSize;
+                    }
+                    else
+                    {
+                        REACHED(10);
+                    }
+
+                    if( bByteNoXResampling )
+                    {
+                        GByte* pabyLocalData = pabyData + y * nLineSpace;
+                        int nLastPixelBlock = 0;
+                        int nByteOffsetInBlock = 0;
+                        toff_t nCurOffset = 0;
+                        int nBlockXOff = nXOff / nBlockXSize;
+                        int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
+                        if ( nPlanarConfig == PLANARCONFIG_SEPARATE )
+                            nBlockId += nBlocksPerBand * (nBand - 1);
+                        int nXOffsetInBlock = nXOff % nBlockXSize;
+                        for(int x=0;x<nBufXSize;x++)
+                        {
+                            int nSrcPixel = nXOff + x;
+                            if( nSrcPixel >= nLastPixelBlock )
+                            {
+                                REACHED(11);
+                                nLastPixelBlock = (nBlockXOff + 1) * nBlockXSize;
+                                nByteOffsetInBlock = nBaseByteOffsetInBlock + nXOffsetInBlock * nBandsPerBlockDTSize;
+                                nCurOffset = panOffsets[nBlockId];
+                                if( nCurOffset != 0 &&
+                                    nCurOffset + nBlockSize > nMappingSize )
+                                {
+                                    REACHED(27);
+                                    CPLError(CE_Failure, CPLE_FileIO,
+                                                "Missing data for block %d", nBlockId);
+                                    return CE_Failure;
+                                }
+                                nXOffsetInBlock = 0;
+                                nBlockXOff ++;
+                                nBlockId ++; 
+                            }
+                            else
+                            {
+                                REACHED(12);
+                                nByteOffsetInBlock += nBandsPerBlockDTSize;
+                            }
+
+                            if( nCurOffset == 0 )
+                            {
+                                REACHED(13);
+                                *pabyLocalData = abyNoData;
+                            }
+                            else
+                            {
+                                REACHED(14);
+                                *pabyLocalData = pabySrcData[nCurOffset + nByteOffsetInBlock];
+                            }
+                            pabyLocalData += nPixelSpace;
+                        }
+                    }
+                    else
+                    {
+                        for(int x=0;x<nBufXSize;x++)
+                        {
+                            int nSrcPixel = nXOff + (int)((x + 0.5) * nXSize / nBufXSize);
+                            int nBlockXOff = nSrcPixel / nBlockXSize;
+                            int nXOffsetInBlock = nSrcPixel % nBlockXSize;
+                            int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
+                            if ( nPlanarConfig == PLANARCONFIG_SEPARATE )
+                                nBlockId += nBlocksPerBand * (nBand - 1);
+                            int nByteOffsetInBlock = nBaseByteOffsetInBlock + nXOffsetInBlock * nBandsPerBlockDTSize;
+                            toff_t nCurOffset = panOffsets[nBlockId];
+                            if( nCurOffset == 0 )
+                            {
+                                REACHED(15);
+                                GDALCopyWords(&dfNoData, GDT_Float64, 0,
+                                              pabyData + y * nLineSpace + x * nPixelSpace,
+                                              eBufType, nPixelSpace,
+                                              1);
+                            }
+                            else
+                            {
+                                if( nCurOffset + nBlockSize > nMappingSize)
+                                {
+                                    REACHED(28);
+                                    CPLError(CE_Failure, CPLE_FileIO,
+                                                "Missing data for block %d", nBlockId);
+                                    return CE_Failure;
+                                }
+                                REACHED(16);
+                                GDALCopyWords(pabySrcData + nCurOffset + nByteOffsetInBlock,
+                                            eDataType, nDTSize,
+                                            pabyData + y * nLineSpace + x * nPixelSpace,
+                                            eBufType, nPixelSpace,
+                                            1);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        else
+        {
+            for(iBand = 0; iBand < nBandCount; iBand ++ )
+            {
+                int nBand = panBandMap[iBand];
+                GByte* pabyData = (GByte*)pData + iBand * nBandSpace;
+                for(int y=0;y<nBufYSize;y++)
+                {
+                    int nSrcLine = nYOff + (int)((y + 0.5) * nYSize / nBufYSize);
+                    int nBlockYOff = nSrcLine / nBlockYSize;
+                    int nYOffsetInBlock = nSrcLine % nBlockYSize;
+                    int nBlockId = nBlockYOff;
+                    if ( nPlanarConfig == PLANARCONFIG_SEPARATE )
+                    {
+                        REACHED(17);
+                        nBlockId += nBlocksPerBand * (nBand - 1);
+                    }
+                    else
+                    {
+                        REACHED(18);
+                    }
+                    toff_t nCurOffset = panOffsets[nBlockId];
+                    if( nCurOffset == 0 )
+                    {
+                        REACHED(19);
+                        GDALCopyWords(&dfNoData, GDT_Float64, 0,
+                                      pabyData + y * nLineSpace, eBufType, nPixelSpace,
+                                      nBufXSize);
+                    }
+                    else
+                    {
+                        if( nCurOffset + (nYOffsetInBlock + 1) * nBlockXSize * nBandsPerBlockDTSize > nMappingSize )
+                        {
+                            REACHED(29);
+                            CPLError(CE_Failure, CPLE_FileIO,
+                                     "Missing data for block %d", nBlockId);
+                            return CE_Failure;
+                        }
+                        int nBaseByteOffsetInBlock = (nYOffsetInBlock * nBlockXSize + nXOff) * nBandsPerBlockDTSize;
+                        if ( nPlanarConfig == PLANARCONFIG_CONTIG )
+                            nBaseByteOffsetInBlock += (nBand-1) * nDTSize;
+
+                        if( bByteNoXResampling )
+                        {
+                            GByte* pabyLocalData = pabyData + y * nLineSpace;
+                            GByte* pabyLocalSrcData = pabySrcData + nCurOffset + nBaseByteOffsetInBlock;
+                            if( nPixelSpace == 1 && nBandsPerBlockDTSize == 1 )
+                            {
+                                REACHED(20);
+                                memcpy(pabyLocalData, pabyLocalSrcData, nBufXSize);
+                            }
+                            else
+                            {
+                                REACHED(21);
+                                for(int x=0;x<nBufXSize;x++)
+                                {
+                                    *pabyLocalData = *pabyLocalSrcData,
+                                    pabyLocalData += nPixelSpace;
+                                    pabyLocalSrcData += nBandsPerBlockDTSize;
+                                }
+                            }
+                        }
+                        else if( bByteOnly )
+                        {
+                            REACHED(30);
+                            GByte* pabyLocalData = pabyData + y * nLineSpace;
+                            GByte* pabyLocalSrcData = pabySrcData + nCurOffset + nBaseByteOffsetInBlock;
+                            for(int x=0;x<nBufXSize;x++)
+                            {
+                                int nSrcPixelMinusXOff = (int)((x + 0.5) * nXSize / nBufXSize);
+                                pabyLocalData[x * nPixelSpace] = pabyLocalSrcData[nSrcPixelMinusXOff * nBandsPerBlockDTSize];
+                            }
+                        }
+                        else
+                        {
+                            REACHED(22);
+                            for(int x=0;x<nBufXSize;x++)
+                            {
+                                int nSrcPixelMinusXOff = (int)((x + 0.5) * nXSize / nBufXSize);
+                                int nByteOffsetInBlock = nBaseByteOffsetInBlock + nSrcPixelMinusXOff * nBandsPerBlockDTSize;
+                                GDALCopyWords(pabySrcData + nCurOffset + nByteOffsetInBlock,
+                                            eDataType, nDTSize,
+                                            pabyData + y * nLineSpace + x * nPixelSpace, eBufType, nPixelSpace,
+                                            1);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                           DirectIO()                                 */
+/************************************************************************/
+
+/* Reads directly bytes from the file using ReadMultiRange(), and by-pass */
+/* block reading. Restricted to simple TIFF configurations (un-tiled, */
+/* uncompressed data, standard data types). Particularly useful to extract */
+/* sub-windows of data on a large /vsicurl dataset). */
+
+CPLErr GTiffDataset::DirectIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg )
+{
+    GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
+    if( !(eRWFlag == GF_Read &&
+          nCompression == COMPRESSION_NONE &&
+          (nPhotometric == PHOTOMETRIC_MINISBLACK ||
+           nPhotometric == PHOTOMETRIC_RGB ||
+           nPhotometric == PHOTOMETRIC_PALETTE) &&
+          (nBitsPerSample == 8 || (nBitsPerSample == 16) ||
+           nBitsPerSample == 32 || nBitsPerSample == 64) &&
+          nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
+          SetDirectory() && /* very important to make hTIFF uptodate! */
+          !TIFFIsTiled( hTIFF )) )
+    {
+        return CE_Failure;
+    }
+
+    /* we only know how to deal with nearest neighbour in this optimized routine */
+    if( (nXSize != nBufXSize || nYSize != nBufYSize) &&
+        psExtraArg != NULL &&
+        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour )
+    {
+        return CE_Failure;
+    }
+
+    /* if the file is band interleave or only one band is requested, then */
+    /* fallback to band DirectIO */
+    int bUseBandRasterIO = FALSE;
+    if( nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1 )
+    {
+        bUseBandRasterIO = TRUE;
+    }
+    else
+    {
+        /* For the sake of simplicity, only deals with "naturally ordered" bands */
+        for(int iBand = 0; iBand < nBandCount; iBand ++ )
+        {
+            if( panBandMap[iBand] != iBand + 1)
+            {
+                bUseBandRasterIO = TRUE;
+                break;
+            }
+        }
+    }
+    if( bUseBandRasterIO )
+    {
+        CPLErr eErr = CE_None;
+        for(int iBand = 0; eErr == CE_None && iBand < nBandCount; iBand ++ )
+        {
+            eErr = GetRasterBand(panBandMap[iBand])->RasterIO(
+                                       eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                                       (GByte*)pData + iBand * nBandSpace,
+                                       nBufXSize, nBufYSize,
+                                       eBufType,
+                                       nPixelSpace, nLineSpace,
+                                       psExtraArg);
+        }
+        return eErr;
+    }
+
+    /*CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)",
+             nXOff, nYOff, nXSize, nYSize,
+             nBufXSize, nBufYSize);*/
+
+    /* No need to look if overviews can satisfy the request as it has already */
+    /* been done in GTiffDataset::IRasterIO() */
+
+    /* Make sure that TIFFTAG_STRIPOFFSETS is up-to-date */
+    if (GetAccess() == GA_Update)
+        FlushCache();
+
+    /* Get strip offsets */
+    toff_t *panTIFFOffsets = NULL;
+    if ( !TIFFGetField( hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets ) ||
+         panTIFFOffsets == NULL )
+    {
+        return CE_Failure;
+    }
+
+    int iLine;
+    int nReqXSize = nXSize; /* sub-sampling or over-sampling can only be done at last stage */
+    int nReqYSize = MIN(nBufYSize, nYSize); /* we can do sub-sampling at the extraction stage */
+    void** ppData = (void**) VSIMalloc(nReqYSize * sizeof(void*));
+    vsi_l_offset* panOffsets = (vsi_l_offset*)
+                            VSIMalloc(nReqYSize * sizeof(vsi_l_offset));
+    size_t* panSizes = (size_t*) VSIMalloc(nReqYSize * sizeof(size_t));
+    int nDTSize = GDALGetDataTypeSize(eDataType) / 8;
+    void* pTmpBuffer = NULL;
+    CPLErr eErr = CE_None;
+    int nContigBands = nBands;
+    int ePixelSize = nDTSize * nContigBands;
+
+    if (ppData == NULL || panOffsets == NULL || panSizes == NULL)
+        eErr = CE_Failure;
+    /* For now we always allocate a temp buffer as it's easier */
+    else /*if (nXSize != nBufXSize || nYSize != nBufYSize ||
+             eBufType != eDataType ||
+             nPixelSpace != GDALGetDataTypeSize(eBufType) / 8 ||
+             check if the user buffer is large enough)*/
+    {
+        /* We need a temporary buffer for over-sampling/sub-sampling */
+        /* and/or data type conversion */
+        pTmpBuffer = VSIMalloc(nReqXSize * nReqYSize * ePixelSize);
+        if (pTmpBuffer == NULL)
+            eErr = CE_Failure;
+    }
+
+    /* Prepare data extraction */
+    for(iLine=0;eErr == CE_None && iLine<nReqYSize;iLine++)
+    {
+        /*if (pTmpBuffer == NULL)
+            ppData[iLine] = ((GByte*)pData) + iLine * nLineSpace;
+        else*/
+            ppData[iLine] = ((GByte*)pTmpBuffer) + iLine * nReqXSize * ePixelSize;
+        int nSrcLine;
+        if (nBufYSize < nYSize) /* Sub-sampling in y */
+            nSrcLine = nYOff + (int)((iLine + 0.5) * nYSize / nBufYSize);
+        else
+            nSrcLine = nYOff + iLine;
+
+        int nBlockXOff = 0;
+        int nBlockYOff = nSrcLine / nBlockYSize;
+        int nYOffsetInBlock = nSrcLine % nBlockYSize;
+        int nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
+        int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
+
+        panOffsets[iLine] = panTIFFOffsets[nBlockId];
+        if (panOffsets[iLine] == 0) /* We don't support sparse files */
+            eErr = CE_Failure;
+
+        panOffsets[iLine] += (nXOff + nYOffsetInBlock * nBlockXSize) * ePixelSize;
+        panSizes[iLine] = nReqXSize * ePixelSize;
+    }
+
+    /* Extract data from the file */
+    if (eErr == CE_None)
     {
-        toff_t nCurOffset;
-        if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
-            nCurOffset = panTIFFOffsets[poGDS->nBlocksPerBand * (nBand - 1) + i];
-        else
-            nCurOffset = panTIFFOffsets[i];
-        if( nCurOffset == 0 )
-        {
-            bCompatibleSpacing = FALSE;
-            break;
-        }
-        if( i > 0 )
-        {
-            GIntBig nCurSpacing = nCurOffset - nPrevOffset;
-            if( i == 1 )
-            {
-                if( nCurSpacing != (GIntBig)nBlockYSize * nLineSize )
-                {
-                    bCompatibleSpacing = FALSE;
-                    break;
-                }
-                nBlockSpacing = nCurSpacing;
-            }
-            else if( nBlockSpacing != nCurSpacing )
-            {
-                bCompatibleSpacing = FALSE;
-                break;
-            }
-        }
-        nPrevOffset = nCurOffset;
+        VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( hTIFF ));
+        int nRet = VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
+        if (nRet != 0)
+            eErr = CE_Failure;
     }
 
-    if( !bCompatibleSpacing )
-    {
-        return NULL;
-    }
-    else
+    /* Byte-swap if necessary */
+    if (eErr == CE_None && TIFFIsByteSwapped(hTIFF))
     {
-        vsi_l_offset nOffset;
-        if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
-        {
-            CPLAssert( poGDS->pBaseMapping == NULL );
-            nOffset = panTIFFOffsets[0];
-        }
-        else
-            nOffset = panTIFFOffsets[poGDS->nBlocksPerBand * (nBand - 1)];
-        CPLVirtualMem* pVMem = CPLVirtualMemFileMapNew(
-            fp, nOffset, nLength,
-            (eRWFlag == GF_Write) ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
-            NULL, NULL);
-        if( pVMem == NULL )
+        for(iLine=0;iLine<nReqYSize;iLine++)
         {
-            return NULL;
+            GDALSwapWords( ppData[iLine], nDTSize, nReqXSize * nContigBands, nDTSize);
         }
-        else
+    }
+
+    /* Over-sampling/sub-sampling and/or data type conversion */
+    if (eErr == CE_None && pTmpBuffer != NULL)
+    {
+        for(int iY=0;iY<nBufYSize;iY++)
         {
-            if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
-            {
-                poGDS->pBaseMapping = pVMem;
-                pVMem = GetVirtualMemAutoInternal( eRWFlag,
-                                                   pnPixelSpace,
-                                                   pnLineSpace,
-                                                   papszOptions );
-                /* drop ref on base mapping */
-                CPLVirtualMemFree(poGDS->pBaseMapping);
-                if( pVMem == NULL )
-                    poGDS->pBaseMapping = NULL;
+            int iSrcY = (nBufYSize <= nYSize) ? iY :
+                            (int)((iY + 0.5) * nYSize / nBufYSize);
+            /* Optimization: no resampling, no data type change, number of bands requested == number of bands */
+            /* and buffer is packed pixel-interleaved */
+            if (nBufXSize == nXSize && nContigBands == nBandCount &&
+                eDataType == eBufType &&
+                nBandSpace == nDTSize && nPixelSpace == nBandCount * nBandSpace )
+            {
+                memcpy( ((GByte*)pData) + iY * nLineSpace, ppData[iSrcY],
+                        nReqXSize * nPixelSpace );
+            }
+            /* Other optimization: no resampling, no data type change, */
+            /* data type is Byte and buffer is pixel-interleaved (with some stridding between pixels) */
+            else if (nBufXSize == nXSize &&
+                     eDataType == eBufType && eDataType == GDT_Byte &&
+                     nBandSpace == 1 && nPixelSpace > nBandCount )
+            {
+                GByte* pabySrcData = ((GByte*)ppData[iSrcY]);
+                GByte* pabyDstData = ((GByte*)pData) + iY * nLineSpace;
+                for(int iX=0;iX<nBufXSize;iX++)
+                {
+                    for(int iBand = 0; iBand < nBandCount; iBand ++ )
+                    {
+                        pabyDstData[iX * nPixelSpace + iBand] = pabySrcData[iX * ePixelSize + iBand];
+                    }
+                }
             }
+            /* General case */
             else
             {
-                *pnPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
-                if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
-                    *pnPixelSpace *= poGDS->nBands;
-                *pnLineSpace = nLineSize;
+                for(int iBand = 0; iBand < nBandCount; iBand ++ )
+                {
+                    GByte* pabySrcData = ((GByte*)ppData[iSrcY]) + iBand * nDTSize;
+                    GByte* pabyDstData = ((GByte*)pData) + iBand * nBandSpace + iY * nLineSpace;
+                    for(int iX=0;iX<nBufXSize;iX++)
+                    {
+                        int iSrcX = (nBufXSize == nXSize) ? iX :
+                                        (int)((iX+0.5) * nXSize / nBufXSize);
+                        GDALCopyWords( pabySrcData + iSrcX * ePixelSize,
+                                    eDataType, 0,
+                                    pabyDstData + iX * nPixelSpace,
+                                    eBufType, 0, 1);
+                    }
+                }
             }
-            return pVMem;
         }
     }
+
+    /* Cleanup */
+    CPLFree(pTmpBuffer);
+    CPLFree(ppData);
+    CPLFree(panOffsets);
+    CPLFree(panSizes);
+
+    return eErr;
 }
 
+
 /************************************************************************/
 /*                            IRasterIO()                               */
 /************************************************************************/
@@ -1247,19 +2420,58 @@ CPLErr GTiffRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace )
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg )
 {
     CPLErr eErr;
 
     //CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)",
     //         nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
 
+    /* Try to pass the request to the most appropriate overview dataset */
+    if( nBufXSize < nXSize && nBufYSize < nYSize )
+    {
+        int nXOffMod = nXOff, nYOffMod = nYOff, nXSizeMod = nXSize, nYSizeMod = nYSize;
+        GDALRasterIOExtraArg sExtraArg;
+    
+        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
+        
+        poGDS->nJPEGOverviewVisibilityFlag ++;
+        int iOvrLevel = GDALBandGetBestOverviewLevel2(this,
+                                                     nXOffMod, nYOffMod,
+                                                     nXSizeMod, nYSizeMod,
+                                                     nBufXSize, nBufYSize,
+                                                     &sExtraArg);
+        poGDS->nJPEGOverviewVisibilityFlag --;
+
+        if( iOvrLevel >= 0 && GetOverview(iOvrLevel) != NULL &&
+            GetOverview(iOvrLevel)->GetDataset() != NULL )
+        {
+            poGDS->nJPEGOverviewVisibilityFlag ++;
+            eErr = GetOverview(iOvrLevel)->RasterIO(
+                eRWFlag, nXOffMod, nYOffMod, nXSizeMod, nYSizeMod,
+                pData, nBufXSize, nBufYSize, eBufType,
+                nPixelSpace, nLineSpace, &sExtraArg);
+            poGDS->nJPEGOverviewVisibilityFlag --;
+            return eErr;
+        }
+    }
+
+
+    if( poGDS->eVirtualMemIOUsage != VIRTUAL_MEM_IO_NO )
+    {
+        int nErr = poGDS->VirtualMemIO(
+                eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                pData, nBufXSize, nBufYSize, eBufType,
+                1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg);
+        if (nErr >= 0)
+            return (CPLErr)nErr;
+    }
     if (poGDS->bDirectIO)
     {
         eErr = DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                         pData, nBufXSize, nBufYSize, eBufType,
-                        nPixelSpace, nLineSpace);
-
+                        nPixelSpace, nLineSpace, psExtraArg);
         if (eErr == CE_None)
             return eErr;
     }
@@ -1290,9 +2502,11 @@ CPLErr GTiffRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         }
     }
 
+    poGDS->nJPEGOverviewVisibilityFlag ++;
     eErr = GDALPamRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                         pData, nBufXSize, nBufYSize, eBufType,
-                                        nPixelSpace, nLineSpace);
+                                        nPixelSpace, nLineSpace, psExtraArg);
+    poGDS->nJPEGOverviewVisibilityFlag --;
 
     poGDS->bLoadingOtherBands = FALSE;
 
@@ -1350,6 +2564,24 @@ CPLErr GTiffRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         NullBlock( pImage );
         return CE_None;
     }
+    
+    if( poGDS->bStreamingIn &&
+        !(poGDS->nBands > 1 && poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && nBlockId == poGDS->nLoadedBlock) )
+    {
+        toff_t* panOffsets = NULL;
+        TIFFGetField( poGDS->hTIFF, (TIFFIsTiled( poGDS->hTIFF )) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS , &panOffsets );
+        if( panOffsets == NULL )
+            return CE_Failure;
+        if( panOffsets[nBlockId] < VSIFTellL(poGDS->fpL) )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Trying to load block %d at offset " CPL_FRMT_GUIB
+                     " whereas current pos is " CPL_FRMT_GUIB " (backward read not supported)",
+                     nBlockId, (GUIntBig)panOffsets[nBlockId],
+                     (GUIntBig)VSIFTellL(poGDS->fpL) );
+            return CE_Failure;
+        }
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Handle simple case (separate, onesampleperpixel)		*/
@@ -1555,7 +2787,7 @@ CPLErr GTiffRasterBand::FillCacheForOtherBands( int nBlockXOff, int nBlockYOff )
 /*      and O(nBands^2) performance !                                   */
 /*                                                                      */
 /*      If there are many bands and the block cache size is not big     */
-/*      enough to accomodate the size of all the blocks, don't enter    */
+/*      enough to accommodate the size of all the blocks, don't enter   */
 /* -------------------------------------------------------------------- */
     if( poGDS->nBands != 1 && !poGDS->bLoadingOtherBands &&
         nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) < GDALGetCacheMax64() / poGDS->nBands)
@@ -1881,6 +3113,13 @@ char **GTiffRasterBand::GetMetadata( const char * pszDomain )
 CPLErr GTiffRasterBand::SetMetadata( char ** papszMD, const char *pszDomain )
 
 {
+    if( poGDS->bStreamingOut && poGDS->bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify metadata at that point in a streamed output file");
+        return CE_Failure;
+    }
+
     if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
     {
         if( papszMD != NULL || GetMetadata(pszDomain) != NULL )
@@ -1904,6 +3143,102 @@ const char *GTiffRasterBand::GetMetadataItem( const char * pszName,
                                               const char * pszDomain )
 
 {
+    if( pszName != NULL && pszDomain != NULL && EQUAL(pszDomain, "TIFF") )
+    {
+        int nBlockXOff, nBlockYOff;
+
+        if( EQUAL(pszName, "JPEGTABLES") )
+        {
+            if( !poGDS->SetDirectory() )
+                return NULL;
+
+            uint32 nJPEGTableSize = 0;
+            void* pJPEGTable = NULL;
+            if( TIFFGetField(poGDS->hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable) != 1 ||
+                pJPEGTable == NULL || (int)nJPEGTableSize <= 0 )
+            {
+                return NULL;
+            }
+            char* pszHex = CPLBinaryToHex( nJPEGTableSize, (const GByte*)pJPEGTable );
+            const char* pszReturn = CPLSPrintf("%s", pszHex);
+            CPLFree(pszHex);
+            return pszReturn;
+        }
+        else if( sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) == 2 )
+        {
+            if( !poGDS->SetDirectory() )
+                return NULL;
+
+            int nBlocksPerRow = DIV_ROUND_UP(poGDS->nRasterXSize, poGDS->nBlockXSize);
+            int nBlocksPerColumn = DIV_ROUND_UP(poGDS->nRasterYSize, poGDS->nBlockYSize);
+            if( nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
+                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn )
+                return NULL;
+
+            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
+            if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+            {
+                nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
+            }
+
+            if( !poGDS->IsBlockAvailable(nBlockId) )
+            {
+                return NULL;
+            }
+
+            toff_t *panOffsets = NULL;
+            TIFF* hTIFF = poGDS->hTIFF;
+            if( (( TIFFIsTiled( hTIFF ) 
+                && TIFFGetField( hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets ) )
+                || ( !TIFFIsTiled( hTIFF ) 
+                && TIFFGetField( hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets ) )) &&
+                panOffsets != NULL )
+            {
+                return CPLSPrintf(CPL_FRMT_GUIB, (GUIntBig)panOffsets[nBlockId]);
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+        else if( sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2 )
+        {
+            if( !poGDS->SetDirectory() )
+                return NULL;
+
+            int nBlocksPerRow = DIV_ROUND_UP(poGDS->nRasterXSize, poGDS->nBlockXSize);
+            int nBlocksPerColumn = DIV_ROUND_UP(poGDS->nRasterYSize, poGDS->nBlockYSize);
+            if( nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
+                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn )
+                return NULL;
+
+            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
+            if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+            {
+                nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
+            }
+
+            if( !poGDS->IsBlockAvailable(nBlockId) )
+            {
+                return NULL;
+            }
+
+            toff_t *panByteCounts = NULL;
+            TIFF* hTIFF = poGDS->hTIFF;
+            if( (( TIFFIsTiled( hTIFF ) 
+                && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts ) )
+                || ( !TIFFIsTiled( hTIFF ) 
+                && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts ) )) &&
+                panByteCounts != NULL )
+            {
+                return CPLSPrintf(CPL_FRMT_GUIB, (GUIntBig)panByteCounts[nBlockId]);
+            }
+            else
+            {
+                return NULL;
+            }
+        }
+    }
     return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
 }
 
@@ -1916,6 +3251,13 @@ CPLErr GTiffRasterBand::SetMetadataItem( const char *pszName,
                                          const char *pszDomain )
 
 {
+    if( poGDS->bStreamingOut && poGDS->bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify metadata at that point in a streamed output file");
+        return CE_Failure;
+    }
+
     if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
     {
         poGDS->bMetadataChanged = TRUE;
@@ -1945,7 +3287,7 @@ GDALColorInterp GTiffRasterBand::GetColorInterpretation()
  /* Note: was EXTRASAMPLE_ASSOCALPHA in GDAL < 1.10 */
 #define DEFAULT_ALPHA_TYPE              EXTRASAMPLE_UNASSALPHA
 
-static int GTiffGetAlphaValue(const char* pszValue, int nDefault)
+static uint16 GTiffGetAlphaValue(const char* pszValue, uint16 nDefault)
 {
     if (pszValue == NULL)
         return nDefault;
@@ -2238,15 +3580,17 @@ CPLErr GTiffRasterBand::SetNoDataValue( double dfNoData )
 {
     if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
         return CE_None;
-
-    if (!poGDS->SetDirectory())  // needed to call TIFFSetField().
+    if( poGDS->bStreamingOut && poGDS->bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify nodata at that point in a streamed output file");
         return CE_Failure;
+    }
 
     poGDS->bNoDataSet = TRUE;
     poGDS->dfNoDataValue = dfNoData;
 
-    poGDS->WriteNoDataValue( poGDS->hTIFF, dfNoData );
-    poGDS->bNeedsRewrite = TRUE;
+    poGDS->bNoDataChanged = TRUE;
 
     bNoDataSet = TRUE;
     dfNoDataValue = dfNoData;
@@ -2297,9 +3641,22 @@ int GTiffRasterBand::GetOverviewCount()
     poGDS->ScanDirectories();
 
     if( poGDS->nOverviewCount > 0 )
+    {
         return poGDS->nOverviewCount;
+    }
     else
-        return GDALRasterBand::GetOverviewCount();
+    {
+        int nOverviewCount = GDALRasterBand::GetOverviewCount();
+        if( nOverviewCount > 0 )
+            return nOverviewCount;
+
+        /* Implict JPEG overviews are normally hidden, except when doing */
+        /* IRasterIO() operations */
+        if( poGDS->nJPEGOverviewVisibilityFlag )
+            return poGDS->GetJPEGOverviewCount();
+        else
+            return 0;
+    }
 }
 
 /************************************************************************/
@@ -2313,13 +3670,26 @@ GDALRasterBand *GTiffRasterBand::GetOverview( int i )
 
     if( poGDS->nOverviewCount > 0 )
     {
+        /* Do we have internal overviews ? */
         if( i < 0 || i >= poGDS->nOverviewCount )
             return NULL;
         else
             return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
     }
     else
-        return GDALRasterBand::GetOverview( i );
+    {
+        GDALRasterBand* poOvrBand = GDALRasterBand::GetOverview( i );
+        if( poOvrBand != NULL )
+            return poOvrBand;
+
+        /* For consistency with GetOverviewCount(), we should also test */
+        /* nJPEGOverviewVisibilityFlag, but it is also convenient to be able */
+        /* to query them for testing purposes. */
+        if( i >= 0 && i < poGDS->GetJPEGOverviewCount() )
+            return poGDS->papoJPEGOverviewDS[i]->GetRasterBand(nBand);
+        else
+            return NULL;
+    }
 }
 
 /************************************************************************/
@@ -2427,7 +3797,15 @@ CPLErr GTiffSplitBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         poGDS->nBands > 1)
     {
         if (poGDS->pabyBlockBuf == NULL)
-            poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
+        {
+            poGDS->pabyBlockBuf = (GByte *) VSIMalloc(TIFFScanlineSize(poGDS->hTIFF));
+            if( poGDS->pabyBlockBuf == NULL )
+            {
+                CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate " CPL_FRMT_GUIB " bytes.",
+                         (GUIntBig)TIFFScanlineSize(poGDS->hTIFF));
+                return CE_Failure;
+            }
+        }
     }
     else
     {
@@ -3417,7 +4795,15 @@ CPLErr GTiffSplitBitmapBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         return CE_Failure;
         
     if (poGDS->pabyBlockBuf == NULL)
-        poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
+    {
+        poGDS->pabyBlockBuf = (GByte *) VSIMalloc(TIFFScanlineSize(poGDS->hTIFF));
+        if( poGDS->pabyBlockBuf == NULL )
+        {
+            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate " CPL_FRMT_GUIB " bytes.",
+                         (GUIntBig)TIFFScanlineSize(poGDS->hTIFF));
+            return CE_Failure;
+        }
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Read through to target scanline.                                */
@@ -3488,14 +4874,20 @@ GTiffDataset::GTiffDataset()
     pabyBlockBuf = NULL;
     bWriteErrorInFlushBlockBuf = FALSE;
     hTIFF = NULL;
+    fpL = NULL;
+    bStreamingIn = FALSE;
+    bStreamingOut = FALSE;
+    fpToWrite = NULL;
+    nLastWrittenBlockId = -1;
     bNeedsRewrite = FALSE;
     bMetadataChanged = FALSE;
     bColorProfileMetadataChanged = FALSE;
     bGeoTIFFInfoChanged = FALSE;
-    bForceUnsetGT = FALSE;
+    bForceUnsetGTOrGCPs = FALSE;
     bForceUnsetProjection = FALSE;
     bCrystalized = TRUE;
     poColorTable = NULL;
+    bNoDataChanged = FALSE;
     bNoDataSet = FALSE;
     dfNoDataValue = -9999.0;
     pszProjection = CPLStrdup("");
@@ -3506,6 +4898,12 @@ GTiffDataset::GTiffDataset()
     bTreatAsRGBA = FALSE;
     nOverviewCount = 0;
     papoOverviewDS = NULL;
+
+    nJPEGOverviewVisibilityFlag = FALSE;
+    nJPEGOverviewCount = -1;
+    nJPEGOverviewCountOri = 0;
+    papoJPEGOverviewDS = NULL;
+
     nDirOffset = 0;
     poActiveDS = NULL;
     ppoActiveDSRef = NULL;
@@ -3544,6 +4942,7 @@ GTiffDataset::GTiffDataset()
     nZLevel = -1;
     nLZMAPreset = -1;
     nJpegQuality = -1;
+    nJpegTablesMode = -1;
     
     bPromoteTo8Bits = FALSE;
 
@@ -3552,19 +4951,30 @@ GTiffDataset::GTiffDataset()
     bIsFinalized = FALSE;
     bIgnoreReadErrors = CSLTestBoolean(CPLGetConfigOption("GTIFF_IGNORE_READ_ERRORS", "NO"));
 
-    bHasSearchedRPC = FALSE;
-    bHasSearchedIMD = FALSE;
-    bHasSearchedPVL = FALSE;
     bEXIFMetadataLoaded = FALSE;
     bICCMetadataLoaded = FALSE;
 
     bScanDeferred = TRUE;
 
     bDirectIO = CSLTestBoolean(CPLGetConfigOption("GTIFF_DIRECT_IO", "NO"));
+    const char* pszVirtualMemIO = CPLGetConfigOption("GTIFF_VIRTUAL_MEM_IO", "NO");
+    if( EQUAL(pszVirtualMemIO, "IF_ENOUGH_RAM") )
+        eVirtualMemIOUsage = VIRTUAL_MEM_IO_IF_ENOUGH_RAM;
+    else if( CSLTestBoolean(pszVirtualMemIO) )
+        eVirtualMemIOUsage = VIRTUAL_MEM_IO_YES;
+    else
+        eVirtualMemIOUsage = VIRTUAL_MEM_IO_NO;
+    psVirtualMemIOMapping = NULL;
+    
     nSetPhotometricFromBandColorInterp = 0;
 
     pBaseMapping = NULL;
     nRefBaseMapping = 0;
+    
+    bHasDiscardedLsb = FALSE;
+
+    bIMDRPCMetadataLoaded = FALSE;
+    papszMetadataFiles = NULL;
 }
 
 /************************************************************************/
@@ -3608,6 +5018,10 @@ int GTiffDataset::Finalize()
         }
     }
 
+    if( psVirtualMemIOMapping )
+        CPLVirtualMemFree( psVirtualMemIOMapping );
+    psVirtualMemIOMapping = NULL;
+
 /* -------------------------------------------------------------------- */
 /*      Ensure any blocks write cached by GDAL gets pushed through libtiff.*/
 /* -------------------------------------------------------------------- */
@@ -3650,6 +5064,16 @@ int GTiffDataset::Finalize()
             bHasDroppedRef = TRUE;
         }
         nOverviewCount = 0;
+
+        for( int i = 0; i < nJPEGOverviewCountOri; i++ )
+        {
+            delete papoJPEGOverviewDS[i];
+            bHasDroppedRef = TRUE;
+        }
+        nJPEGOverviewCount = 0;
+        nJPEGOverviewCountOri = 0;
+        CPLFree( papoJPEGOverviewDS );
+        papoJPEGOverviewDS = NULL;
     }
 
     /* If we are a mask dataset, we can have overviews, but we don't */
@@ -3675,6 +5099,17 @@ int GTiffDataset::Finalize()
     {
         XTIFFClose( hTIFF );
         hTIFF = NULL;
+        if( fpL != NULL )
+        {
+            VSIFCloseL( fpL );
+            fpL = NULL;
+        }
+    }
+    
+    if( fpToWrite != NULL )
+    {
+        VSIFCloseL( fpToWrite );
+        fpToWrite = NULL;
     }
 
     if( nGCPCount > 0 )
@@ -3694,10 +5129,14 @@ int GTiffDataset::Finalize()
     CPLFree(pabyTempWriteBuffer);
     pabyTempWriteBuffer = NULL;
 
-    if( *ppoActiveDSRef == this )
+    if( ppoActiveDSRef != NULL && *ppoActiveDSRef == this )
         *ppoActiveDSRef = NULL;
     ppoActiveDSRef = NULL;
 
+    bIMDRPCMetadataLoaded = FALSE;
+    CSLDestroy(papszMetadataFiles);
+    papszMetadataFiles = NULL;
+
     bIsFinalized = TRUE;
 
     return bHasDroppedRef;
@@ -3720,6 +5159,73 @@ int GTiffDataset::CloseDependentDatasets()
 }
 
 /************************************************************************/
+/*                        GetJPEGOverviewCount()                        */
+/************************************************************************/
+
+int GTiffDataset::GetJPEGOverviewCount()
+{
+    if( nJPEGOverviewCount >= 0 )
+        return nJPEGOverviewCount;
+
+    nJPEGOverviewCount = 0;
+    if( eAccess != GA_ReadOnly || nCompression != COMPRESSION_JPEG ||
+        (nRasterXSize < 256 && nRasterYSize < 256) ||
+        !CSLTestBoolean(CPLGetConfigOption("GTIFF_IMPLICIT_JPEG_OVR", "YES")) ||
+        GDALGetDriverByName("JPEG") == NULL )
+    {
+        return 0;
+    }
+
+    /* libjpeg-6b only suppports 2, 4 and 8 scale denominators */
+    /* TODO: Later versions support more */
+    int i;
+    for(i = 2; i >= 0; i--)
+    {
+        if( nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i) )
+        {
+            nJPEGOverviewCount = i + 1;
+            break;
+        }
+    }
+    if( nJPEGOverviewCount == 0 )
+        return 0;
+    
+    if( !SetDirectory() )
+        return 0;
+
+    /* Get JPEG tables */
+    uint32 nJPEGTableSize = 0;
+    void* pJPEGTable = NULL;
+    GByte abyFFD8[] = { 0xFF, 0xD8 };
+    if( TIFFGetField(hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable) )
+    {
+        if( pJPEGTable == NULL || (int)nJPEGTableSize <= 0 ||
+            ((GByte*)pJPEGTable)[nJPEGTableSize-1] != 0xD9 )
+        {
+            return 0;
+        }
+        nJPEGTableSize --; /* remove final 0xD9 */
+    }
+    else
+    {
+        pJPEGTable = abyFFD8;
+        nJPEGTableSize = 2;
+    }
+
+    papoJPEGOverviewDS = (GTiffJPEGOverviewDS**) CPLMalloc(
+                        sizeof(GTiffJPEGOverviewDS*) * nJPEGOverviewCount );
+    for(i = 0; i < nJPEGOverviewCount; i++)
+    {
+        papoJPEGOverviewDS[i] = new GTiffJPEGOverviewDS(this, i+1,
+                                            pJPEGTable, (int)nJPEGTableSize);
+    }
+
+    nJPEGOverviewCountOri = nJPEGOverviewCount;
+
+    return nJPEGOverviewCount;
+}
+
+/************************************************************************/
 /*                           FillEmptyTiles()                           */
 /************************************************************************/
 
@@ -3830,7 +5336,7 @@ int GTiffDataset::WriteEncodedTile(uint32 tile, GByte *pabyData,
     ** working buffer.  If not, we can just do a direct write. 
     */
     if (bPreserveDataBuffer 
-        && (TIFFIsByteSwapped(hTIFF) || bNeedTileFill) )
+        && (TIFFIsByteSwapped(hTIFF) || bNeedTileFill || bHasDiscardedLsb) )
     {
         if (cc != nTempWriteBufferSize)
         {
@@ -3882,6 +5388,31 @@ int GTiffDataset::WriteEncodedTile(uint32 tile, GByte *pabyData,
         }
     }
 
+    if( bHasDiscardedLsb != 0 )
+    {
+        int iBand = (nPlanarConfig == PLANARCONFIG_SEPARATE ) ? tile / nBlocksPerBand : -1;
+        DiscardLsb(pabyData, cc, iBand);
+    }
+
+    if( bStreamingOut )
+    {
+        if( tile != (uint32)(nLastWrittenBlockId + 1) )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Attempt to write block %d whereas %d was expected",
+                     tile,  nLastWrittenBlockId + 1);
+            return -1;
+        }
+        if( (int)VSIFWriteL(pabyData, 1, cc, fpToWrite) != cc )
+        {
+            CPLError(CE_Failure, CPLE_FileIO, "Could not write %d bytes",
+                     cc);
+            return -1;
+        }
+        nLastWrittenBlockId = tile;
+        return 0;
+    }
+
     return TIFFWriteEncodedTile(hTIFF, tile, pabyData, cc);
 }
 
@@ -3914,7 +5445,7 @@ int  GTiffDataset::WriteEncodedStrip(uint32 strip, GByte* pabyData,
 /*      byte-swapping is necessary so we use a temporary buffer         */
 /*      before calling it.                                              */
 /* -------------------------------------------------------------------- */
-    if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
+    if (bPreserveDataBuffer && (TIFFIsByteSwapped(hTIFF) || bHasDiscardedLsb))
     {
         if (cc != nTempWriteBufferSize)
         {
@@ -3922,10 +5453,114 @@ int  GTiffDataset::WriteEncodedStrip(uint32 strip, GByte* pabyData,
             nTempWriteBufferSize = cc;
         }
         memcpy(pabyTempWriteBuffer, pabyData, cc);
-        return TIFFWriteEncodedStrip(hTIFF, strip, pabyTempWriteBuffer, cc);
+        pabyData = (GByte *) pabyTempWriteBuffer;
+    }
+
+    if( bHasDiscardedLsb != 0 )
+    {
+        int iBand = (nPlanarConfig == PLANARCONFIG_SEPARATE ) ? strip / nBlocksPerBand : -1;
+        DiscardLsb(pabyData, cc, iBand);
+    }
+
+    if( bStreamingOut )
+    {
+        if( strip != (uint32)(nLastWrittenBlockId + 1) )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Attempt to write block %d whereas %d was expected",
+                     strip,  nLastWrittenBlockId + 1);
+            return -1;
+        }
+        if( (int)VSIFWriteL(pabyData, 1, cc, fpToWrite) != cc )
+        {
+            CPLError(CE_Failure, CPLE_FileIO, "Could not write %d bytes",
+                     cc);
+            return -1;
+        }
+        nLastWrittenBlockId = strip;
+        return 0;
+    }
+
+    return TIFFWriteEncodedStrip(hTIFF, strip, pabyData, cc);
+}
+
+/************************************************************************/
+/*                          DiscardLsb()                               */
+/************************************************************************/
+
+void GTiffDataset::DiscardLsb(GByte* pabyBuffer, int nBytes, int iBand)
+{
+    if( nBitsPerSample == 8 )
+    {
+        if( nPlanarConfig == PLANARCONFIG_SEPARATE )
+        {
+            int nMask = anMaskLsb[iBand];
+            int nOffset = anOffsetLsb[iBand];
+            for( int i = 0; i < nBytes; i ++ )
+            {
+                if( pabyBuffer[i] != 255 ) /* we want to keep 255 in case it is alpha */
+                    pabyBuffer[i] = (pabyBuffer[i] & nMask) | nOffset;
+            }
+        }
+        else
+        {
+            for( int i = 0; i < nBytes; i += nBands )
+            {
+                for( int j = 0; j < nBands; j ++ )
+                {
+                    if( pabyBuffer[i + j] != 255 ) /* we want to keep 255 in case it is alpha */
+                        pabyBuffer[i + j] = (pabyBuffer[i + j] &
+                                    anMaskLsb[j]) | anOffsetLsb[j];
+                }
+            }
+        }
+    }
+    else if( nBitsPerSample == 16 )
+    {
+        if( nPlanarConfig == PLANARCONFIG_SEPARATE )
+        {
+            int nMask = anMaskLsb[iBand];
+            int nOffset = anOffsetLsb[iBand];
+            for( int i = 0; i < nBytes/2; i ++ )
+            {
+                ((GUInt16*)pabyBuffer)[i] = (((GUInt16*)pabyBuffer)[i] & nMask) | nOffset;
+            }
+        }
+        else
+        {
+            for( int i = 0; i < nBytes/2; i += nBands )
+            {
+                for( int j = 0; j < nBands; j ++ )
+                {
+                    ((GUInt16*)pabyBuffer)[i + j] = (((GUInt16*)pabyBuffer)[i + j] &
+                                    anMaskLsb[j]) | anOffsetLsb[j];
+                }
+            }
+        }
+    }
+    else if( nBitsPerSample == 32 )
+    {
+        if( nPlanarConfig == PLANARCONFIG_SEPARATE )
+        {
+            int nMask = anMaskLsb[iBand];
+            int nOffset = anOffsetLsb[iBand];
+            for( int i = 0; i < nBytes/4; i ++ )
+            {
+                ((GUInt32*)pabyBuffer)[i] = (((GUInt32*)pabyBuffer)[i] & nMask) | nOffset;
+            }
+        }
+        else
+        {
+            for( int i = 0; i < nBytes/4; i += nBands )
+            {
+                for( int j = 0; j < nBands; j ++ )
+                {
+                    ((GUInt32*)pabyBuffer)[i + j] = (((GUInt32*)pabyBuffer)[i + j] &
+                                    anMaskLsb[j]) | anOffsetLsb[j];
+                }
+            }
+        }
     }
-    else
-        return TIFFWriteEncodedStrip(hTIFF, strip, pabyData, cc);
 }
 
 /************************************************************************/
@@ -4047,7 +5682,7 @@ CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
 /*  geotiffs), the ::IWriteBlock will override the content of the buffer*/
 /*  with pImage, so we don't need to read data from disk                */
 /* -------------------------------------------------------------------- */
-    if( !bReadFromDisk )
+    if( !bReadFromDisk || bStreamingOut )
     {
         nLoadedBlock = nBlockId;
         return CE_None;
@@ -4132,6 +5767,51 @@ CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
     return eErr;
 }
 
+/************************************************************************/
+/*                   GTiffFillStreamableOffsetAndCount()                */
+/************************************************************************/
+
+static void GTiffFillStreamableOffsetAndCount(TIFF* hTIFF, int nSize)
+{
+    uint32  nXSize, nYSize;
+    TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
+    TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
+    toff_t* panOffset = NULL, *panSize = NULL;
+    int nBlockCount = ( TIFFIsTiled(hTIFF) ) ? TIFFNumberOfTiles(hTIFF) : TIFFNumberOfStrips(hTIFF);
+    TIFFGetField( hTIFF, TIFFIsTiled(hTIFF) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS, &panOffset );
+    TIFFGetField( hTIFF, TIFFIsTiled(hTIFF) ? TIFFTAG_TILEBYTECOUNTS : TIFFTAG_STRIPBYTECOUNTS, &panSize );
+    toff_t nOffset = nSize;
+    int nBlocksPerBand = 0;
+    uint32 nRowsPerStrip = 0;
+    if( !TIFFIsTiled(hTIFF)  )
+    {
+        TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &nRowsPerStrip);
+        if( nRowsPerStrip > (uint32)nYSize )
+            nRowsPerStrip = nYSize;
+        nBlocksPerBand = DIV_ROUND_UP(nYSize, nRowsPerStrip);
+    }
+    for(int i=0;i<nBlockCount;i++)
+    {
+        int cc = TIFFIsTiled(hTIFF) ? TIFFTileSize(hTIFF) : TIFFStripSize(hTIFF);
+        if( !TIFFIsTiled(hTIFF)  )
+        {
+/* -------------------------------------------------------------------- */
+/*      If this is the last strip in the image, and is partial, then    */
+/*      we need to trim the number of scanlines written to the          */
+/*      amount of valid data we have. (#2748)                           */
+/* -------------------------------------------------------------------- */
+            int nStripWithinBand = i % nBlocksPerBand;
+            if( (int) ((nStripWithinBand+1) * nRowsPerStrip) > (int) nYSize )
+            {
+                cc = (cc / nRowsPerStrip)
+                    * (nYSize - nStripWithinBand * nRowsPerStrip);
+            }
+        }
+        panOffset[i] = nOffset;
+        panSize[i] = cc;
+        nOffset += cc;
+    }
+}
 
 /************************************************************************/
 /*                             Crystalize()                             */
@@ -4145,12 +5825,17 @@ void GTiffDataset::Crystalize()
 {
     if( !bCrystalized )
     {
+        // FIXME? libtiff writes extended tags in the order they are specified
+        // and not in increasing order
         WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
                        papszCreationOptions );
         WriteGeoTIFFInfo();
+        if( bNoDataSet )
+            WriteNoDataValue( hTIFF, dfNoDataValue );
 
         bMetadataChanged = FALSE;
         bGeoTIFFInfoChanged = FALSE;
+        bNoDataChanged = FALSE;
         bNeedsRewrite = FALSE;
 
         bCrystalized = TRUE;
@@ -4159,13 +5844,43 @@ void GTiffDataset::Crystalize()
 
         // Keep zip and tiff quality, and jpegcolormode which get reset when we call 
         // TIFFWriteDirectory 
-        int jquality = -1, zquality = -1, nColorMode = -1; 
+        int jquality = -1, zquality = -1, nColorMode = -1, nJpegTablesMode = -1; 
         TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality); 
         TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality); 
         TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
+        TIFFGetField( hTIFF, TIFFTAG_JPEGTABLESMODE, &nJpegTablesMode );
 
         TIFFWriteDirectory( hTIFF );
-        TIFFSetDirectory( hTIFF, 0 );
+        if( bStreamingOut )
+        {
+            /* We need to write twice the directory to be sure that custom */
+            /* TIFF tags are correctly sorted and that padding bytes have been */
+            /* added */
+            TIFFSetDirectory( hTIFF, 0 );
+            TIFFWriteDirectory( hTIFF );
+
+            VSIFSeekL( fpL, 0, SEEK_END );
+            int nSize = (int) VSIFTellL(fpL);
+
+            TIFFSetDirectory( hTIFF, 0 );
+            GTiffFillStreamableOffsetAndCount( hTIFF, nSize );
+            TIFFWriteDirectory( hTIFF );
+
+            vsi_l_offset nDataLength;
+            void* pabyBuffer = VSIGetMemFileBuffer( osTmpFilename, &nDataLength, FALSE);
+            if( (int)VSIFWriteL( pabyBuffer, 1, (int)nDataLength, fpToWrite ) != (int)nDataLength )
+            {
+                CPLError(CE_Failure, CPLE_FileIO, "Could not write %d bytes",
+                        (int)nDataLength);
+            }
+            /* In case of single strip file, there's a libtiff check that would */
+            /* issue a warning since the file hasn't the required size */
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            TIFFSetDirectory( hTIFF, 0 );
+            CPLPopErrorHandler();
+        }
+        else
+            TIFFSetDirectory( hTIFF, 0 );
 
 
         // Now, reset zip and tiff quality and jpegcolormode. 
@@ -4175,6 +5890,8 @@ void GTiffDataset::Crystalize()
             TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
         if (nColorMode >= 0)
             TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, nColorMode);
+        if (nJpegTablesMode >= 0 )
+            TIFFSetField(hTIFF, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode);
 
         nDirOffset = TIFFCurrentDirOffset( hTIFF );
     }
@@ -4185,73 +5902,68 @@ void GTiffDataset::Crystalize()
 #define IO_CACHE_PAGE_SIZE      4096
 
 static
-void GTiffCacheOffsetOrCount4(VSILFILE* fp,
-                              vsi_l_offset nBaseOffset,
-                              int nBlockId,
-                              uint32 nstrips,
-                              uint64* panVals)
+void GTiffCacheOffsetOrCount(VSILFILE* fp,
+                             vsi_l_offset nBaseOffset,
+                             int nBlockId,
+                             uint32 nstrips,
+                             uint64* panVals,
+                             size_t sizeofval)
 {
-    uint32 val;
     int i, iStartBefore;
     vsi_l_offset nOffset, nOffsetStartPage, nOffsetEndPage;
     GByte buffer[2 * IO_CACHE_PAGE_SIZE];
 
-    nOffset = nBaseOffset + sizeof(val) * nBlockId;
+    nOffset = nBaseOffset + sizeofval * nBlockId;
     nOffsetStartPage = (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE;
     nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE;
 
-    if( nOffset + sizeof(val) > nOffsetEndPage )
+    if( nOffset + sizeofval > nOffsetEndPage )
         nOffsetEndPage += IO_CACHE_PAGE_SIZE;
+    vsi_l_offset nLastStripOffset = nBaseOffset + nstrips * sizeofval;
+    if( nLastStripOffset < nOffsetEndPage )
+        nOffsetEndPage  = nLastStripOffset;
+    if( nOffsetStartPage >= nOffsetEndPage )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, 
+                 "Cannot read offset/size for strile %d", nBlockId);
+        panVals[nBlockId] = 0;
+        return;
+    }
     VSIFSeekL(fp, nOffsetStartPage, SEEK_SET);
-    VSIFReadL(buffer, 1, nOffsetEndPage - nOffsetStartPage, fp);
-    iStartBefore = - ((nOffset - nOffsetStartPage) / sizeof(val));
-    if( nBlockId + iStartBefore < 0 )
-        iStartBefore = -nBlockId;
-    for(i=iStartBefore; (uint32)(nBlockId + i) < nstrips &&
-        (GIntBig)nOffset + (i+1) * (int)sizeof(val) <= (GIntBig)nOffsetEndPage; i++)
+    size_t nToRead = (size_t)(nOffsetEndPage - nOffsetStartPage);
+    size_t nRead = VSIFReadL(buffer, 1, nToRead, fp);
+    if( nRead < nToRead )
     {
-        memcpy(&val,
-            buffer + (nOffset - nOffsetStartPage) + i * sizeof(val),
-            sizeof(val));
-        panVals[nBlockId + i] = val;
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot read offset/size for strile around ~%d", nBlockId);
+        memset(buffer + nRead, 0, nToRead - nRead);
     }
-}
-
-/* Same code as GTiffCacheOffsetOrCount4 except the 'val' declaration */
-static
-void GTiffCacheOffsetOrCount8(VSILFILE* fp,
-                              vsi_l_offset nBaseOffset,
-                              int nBlockId,
-                              uint32 nstrips,
-                              uint64* panVals)
-{
-    uint64 val;
-    int i, iStartBefore;
-    vsi_l_offset nOffset, nOffsetStartPage, nOffsetEndPage;
-    GByte buffer[2 * IO_CACHE_PAGE_SIZE];
-
-    nOffset = nBaseOffset + sizeof(val) * nBlockId;
-    nOffsetStartPage = (nOffset / IO_CACHE_PAGE_SIZE) * IO_CACHE_PAGE_SIZE;
-    nOffsetEndPage = nOffsetStartPage + IO_CACHE_PAGE_SIZE;
-
-    if( nOffset + sizeof(val) > nOffsetEndPage )
-        nOffsetEndPage += IO_CACHE_PAGE_SIZE;
-    VSIFSeekL(fp, nOffsetStartPage, SEEK_SET);
-    VSIFReadL(buffer, 1, nOffsetEndPage - nOffsetStartPage, fp);
-    iStartBefore = - ((nOffset - nOffsetStartPage) / sizeof(val));
+    iStartBefore = - (int)((nOffset - nOffsetStartPage) / sizeofval);
     if( nBlockId + iStartBefore < 0 )
         iStartBefore = -nBlockId;
     for(i=iStartBefore; (uint32)(nBlockId + i) < nstrips &&
-        (GIntBig)nOffset + (i+1) * (int)sizeof(val) <= (GIntBig)nOffsetEndPage; i++)
+        (GIntBig)nOffset + (i+1) * (int)sizeofval <= (GIntBig)nOffsetEndPage; i++)
     {
-        memcpy(&val,
-            buffer + (nOffset - nOffsetStartPage) + i * sizeof(val),
-            sizeof(val));
-        panVals[nBlockId + i] = val;
+        if( sizeofval == 4 )
+        {
+            uint32 val;
+            memcpy(&val,
+                   buffer + (nOffset - nOffsetStartPage) + i * sizeof(val),
+                   sizeof(val));
+            panVals[nBlockId + i] = val;
+        }
+        else
+        {
+            uint64 val;
+            memcpy(&val,
+                   buffer + (nOffset - nOffsetStartPage) + i * sizeof(val),
+                   sizeof(val));
+            panVals[nBlockId + i] = val;
+        }
     }
 }
 
-#endif
+#endif /* INTERNAL_LIBTIFF */
 
 /************************************************************************/
 /*                          IsBlockAvailable()                          */
@@ -4274,7 +5986,7 @@ int GTiffDataset::IsBlockAvailable( int nBlockId )
          hTIFF->tif_dir.td_stripoffset_entry.tdir_type == TIFF_LONG8) &&
         (hTIFF->tif_dir.td_stripbytecount_entry.tdir_type == TIFF_LONG ||
          hTIFF->tif_dir.td_stripbytecount_entry.tdir_type == TIFF_LONG8) &&
-        strcmp(GetDescription(), "/vsistdin/") != 0 )
+        !bStreamingIn )
     {
         if( hTIFF->tif_dir.td_stripoffset == NULL )
         {
@@ -4302,25 +6014,27 @@ int GTiffDataset::IsBlockAvailable( int nBlockId )
         if( ~(hTIFF->tif_dir.td_stripoffset[nBlockId]) == 0 ||
             ~(hTIFF->tif_dir.td_stripbytecount[nBlockId]) == 0 )
         {
-            VSILFILE* fp = (VSILFILE*)hTIFF->tif_clientdata;
+            VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( hTIFF ));
             vsi_l_offset nCurOffset = VSIFTellL(fp);
             if( ~(hTIFF->tif_dir.td_stripoffset[nBlockId]) == 0 )
             {
                 if( hTIFF->tif_dir.td_stripoffset_entry.tdir_type == TIFF_LONG )
                 {
-                    GTiffCacheOffsetOrCount4(fp,
-                                             hTIFF->tif_dir.td_stripoffset_entry.tdir_offset.toff_long,
-                                             nBlockId,
-                                             hTIFF->tif_dir.td_nstrips,
-                                             hTIFF->tif_dir.td_stripoffset);
+                    GTiffCacheOffsetOrCount(fp,
+                                            hTIFF->tif_dir.td_stripoffset_entry.tdir_offset.toff_long,
+                                            nBlockId,
+                                            hTIFF->tif_dir.td_nstrips,
+                                            hTIFF->tif_dir.td_stripoffset,
+                                            sizeof(uint32));
                 }
                 else
                 {
-                    GTiffCacheOffsetOrCount8(fp,
-                                             hTIFF->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8,
-                                             nBlockId,
-                                             hTIFF->tif_dir.td_nstrips,
-                                             hTIFF->tif_dir.td_stripoffset);
+                    GTiffCacheOffsetOrCount(fp,
+                                            hTIFF->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8,
+                                            nBlockId,
+                                            hTIFF->tif_dir.td_nstrips,
+                                            hTIFF->tif_dir.td_stripoffset,
+                                            sizeof(uint64));
                 }
             }
 
@@ -4328,26 +6042,28 @@ int GTiffDataset::IsBlockAvailable( int nBlockId )
             {
                 if( hTIFF->tif_dir.td_stripbytecount_entry.tdir_type == TIFF_LONG )
                 {
-                    GTiffCacheOffsetOrCount4(fp,
-                                             hTIFF->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long,
-                                             nBlockId,
-                                             hTIFF->tif_dir.td_nstrips,
-                                             hTIFF->tif_dir.td_stripbytecount);
+                    GTiffCacheOffsetOrCount(fp,
+                                            hTIFF->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long,
+                                            nBlockId,
+                                            hTIFF->tif_dir.td_nstrips,
+                                            hTIFF->tif_dir.td_stripbytecount,
+                                            sizeof(uint32));
                 }
                 else
                 {
-                    GTiffCacheOffsetOrCount8(fp,
-                                             hTIFF->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8,
-                                             nBlockId,
-                                             hTIFF->tif_dir.td_nstrips,
-                                             hTIFF->tif_dir.td_stripbytecount);
+                    GTiffCacheOffsetOrCount(fp,
+                                            hTIFF->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8,
+                                            nBlockId,
+                                            hTIFF->tif_dir.td_nstrips,
+                                            hTIFF->tif_dir.td_stripbytecount,
+                                            sizeof(uint64));
                 }
             }
             VSIFSeekL(fp, nCurOffset, SEEK_SET);
         }
         return hTIFF->tif_dir.td_stripbytecount[nBlockId] != 0;
     }
-#endif
+#endif /* INTERNAL_LIBTIFF */
     toff_t *panByteCounts = NULL;
 
     if( ( TIFFIsTiled( hTIFF ) 
@@ -4374,7 +6090,7 @@ int GTiffDataset::IsBlockAvailable( int nBlockId )
 void GTiffDataset::FlushCache()
 
 {
-    if (bIsFinalized)
+    if (bIsFinalized || ppoActiveDSRef == NULL)
         return;
 
     GDALPamDataset::FlushCache();
@@ -4417,6 +6133,18 @@ void GTiffDataset::FlushDirectory()
                 return;
             WriteGeoTIFFInfo();
         }
+        
+        if( bNoDataChanged )
+        {
+            if (!SetDirectory())
+                return;
+            if( bNoDataSet )
+            {
+                WriteNoDataValue( hTIFF, dfNoDataValue );
+                bNeedsRewrite = TRUE;
+                bNoDataChanged = FALSE;
+            }
+        }
 
         if( bNeedsRewrite )
         {
@@ -4474,32 +6202,6 @@ void GTiffDataset::FlushDirectory()
 }
 
 /************************************************************************/
-/*                         TIFF_OvLevelAdjust()                         */
-/*                                                                      */
-/*      Some overview levels cannot be achieved closely enough to be    */
-/*      recognised as the desired overview level.  This function        */
-/*      will adjust an overview level to one that is achievable on      */
-/*      the given raster size.                                          */
-/*                                                                      */
-/*      For instance a 1200x1200 image on which a 256 level overview    */
-/*      is request will end up generating a 5x5 overview.  However,     */
-/*      this will appear to the system be a level 240 overview.         */
-/*      This function will adjust 256 to 240 based on knowledge of      */
-/*      the image size.                                                 */
-/*                                                                      */
-/*      This is a copy of the GDALOvLevelAdjust() function in           */
-/*      gdaldefaultoverviews.cpp.                                       */
-/************************************************************************/
-
-static int TIFF_OvLevelAdjust( int nOvLevel, int nXSize )
-
-{
-    int	nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
-    
-    return (int) (0.5 + nXSize / (double) nOXSize);
-}
-
-/************************************************************************/
 /*                           CleanOverviews()                           */
 /************************************************************************/
 
@@ -4850,6 +6552,11 @@ CPLErr GTiffDataset::IBuildOverviews(
 
     ScanDirectories();
 
+    /* Make implicit JPEG overviews invisible, but do not destroy */
+    /* them in case they are already used (not sure that the client */
+    /* has the right to do that. behaviour undefined in GDAL API I think) */
+    nJPEGOverviewCount = 0;
+
 /* -------------------------------------------------------------------- */
 /*      If RRD or external OVR overviews requested, then invoke         */
 /*      generic handling.                                               */
@@ -5078,12 +6785,15 @@ CPLErr GTiffDataset::IBuildOverviews(
 
             poODS = papoOverviewDS[j];
 
-            nOvFactor = (int) 
-                (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
+            nOvFactor = GDALComputeOvFactor(poODS->GetRasterXSize(),
+                                             GetRasterXSize(),
+                                             poODS->GetRasterYSize(),
+                                             GetRasterYSize());
 
             if( nOvFactor == panOverviewList[i] 
-                || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
-                                                    GetRasterXSize() ) )
+                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
+                                                    GetRasterXSize(),
+                                                    GetRasterYSize() ) )
                 panOverviewList[i] *= -1;
         }
 
@@ -5162,7 +6872,10 @@ CPLErr GTiffDataset::IBuildOverviews(
     if (nPlanarConfig == PLANARCONFIG_CONTIG &&
         GDALDataTypeIsComplex(GetRasterBand( panBandList[0] )->GetRasterDataType()) == FALSE &&
         GetRasterBand( panBandList[0] )->GetColorTable() == NULL &&
-        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
+        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") ||
+         EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
+         EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") ||
+         EQUAL(pszResampling, "BILINEAR")))
     {
         /* In the case of pixel interleaved compressed overviews, we want to generate */
         /* the overviews for all the bands block by block, and not band after band, */
@@ -5196,8 +6909,10 @@ CPLErr GTiffDataset::IBuildOverviews(
                     int    nOvFactor;
                     GDALRasterBand * poOverview = poBand->GetOverview( j );
 
-                    nOvFactor = (int) 
-                    (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+                    nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                                     poBand->GetXSize(),
+                                                     poOverview->GetYSize(),
+                                                     poBand->GetYSize());
 
                     int bHasNoData;
                     double noDataValue = poBand->GetNoDataValue(&bHasNoData);
@@ -5206,8 +6921,9 @@ CPLErr GTiffDataset::IBuildOverviews(
                         poOverview->SetNoDataValue(noDataValue);
 
                     if( nOvFactor == panOverviewList[i] 
-                        || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
-                                                            poBand->GetXSize() ) )
+                        || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
+                                                            poBand->GetXSize(),
+                                                            poBand->GetYSize() ) )
                     {
                         papapoOverviewBands[iBand][iCurOverview] = poOverview;
                         iCurOverview++ ;
@@ -5266,12 +6982,15 @@ CPLErr GTiffDataset::IBuildOverviews(
                     if (bHasNoData)
                         poOverview->SetNoDataValue(noDataValue);
 
-                    nOvFactor = (int) 
-                    (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+                    nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                                     poBand->GetXSize(),
+                                                     poOverview->GetYSize(),
+                                                     poBand->GetYSize());
 
                     if( nOvFactor == panOverviewList[i] 
-                        || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
-                                                            poBand->GetXSize() ) )
+                        || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
+                                                            poBand->GetXSize(),
+                                                            poBand->GetYSize() ) )
                     {
                         papoOverviewBands[nNewOverviews++] = poOverview;
                         break;
@@ -5352,10 +7071,10 @@ void GTiffDataset::WriteGeoTIFFInfo()
                                                "FALSE") );
     }
 
-    if( bForceUnsetGT )
+    if( bForceUnsetGTOrGCPs )
     {
         bNeedsRewrite = TRUE;
-        bForceUnsetGT = FALSE;
+        bForceUnsetGTOrGCPs = FALSE;
 
 #ifdef HAVE_UNSETFIELD
         TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
@@ -5607,7 +7326,7 @@ static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
             continue; // ignored
         if( EQUAL(papszDomainList[iDomain], "COLOR_PROFILE") )
             continue; // ignored
-        if( EQUAL(papszDomainList[iDomain], "RPC") )
+        if( EQUAL(papszDomainList[iDomain], MD_DOMAIN_RPC) )
             continue; // handled elsewhere
         if( EQUAL(papszDomainList[iDomain], "xml:ESRI") 
             && CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
@@ -5721,6 +7440,59 @@ static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
 }
 
 /************************************************************************/
+/*                           WriteRPC()                                 */
+/************************************************************************/
+
+void GTiffDataset::WriteRPC( GDALDataset *poSrcDS, TIFF *hTIFF,
+                             int bSrcIsGeoTIFF,
+                             const char *pszProfile,
+                             const char *pszTIFFFilename,
+                             char **papszCreationOptions,
+                             int bWriteOnlyInPAMIfNeeded )
+{
+
+/* -------------------------------------------------------------------- */
+/*      Handle RPC data written to an RPB file.                         */
+/* -------------------------------------------------------------------- */
+    char **papszRPCMD = poSrcDS->GetMetadata(MD_DOMAIN_RPC);
+    if( papszRPCMD != NULL )
+    {
+        int bRPCSerializedOtherWay = FALSE;
+
+        if( EQUAL(pszProfile,"GDALGeoTIFF") )
+        {
+            if( !bWriteOnlyInPAMIfNeeded )
+                GTiffDatasetWriteRPCTag( hTIFF, papszRPCMD );
+            bRPCSerializedOtherWay = TRUE;
+        }
+
+        /* Write RPB file if explicitely asked, or if a non GDAL specific */
+        /* profile is selected and RPCTXT is not asked */
+        int bRPBExplicitelyAsked = CSLFetchBoolean( papszCreationOptions, "RPB", FALSE );
+        int bRPBExplicitelyDenied = !CSLFetchBoolean( papszCreationOptions, "RPB", TRUE );
+        if( (!EQUAL(pszProfile,"GDALGeoTIFF") && 
+             !CSLFetchBoolean( papszCreationOptions, "RPCTXT", FALSE ) &&
+             !bRPBExplicitelyDenied )
+            || bRPBExplicitelyAsked )
+        {
+            if( !bWriteOnlyInPAMIfNeeded )
+                GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
+            bRPCSerializedOtherWay = TRUE;
+        }
+
+        if( CSLFetchBoolean( papszCreationOptions, "RPCTXT", FALSE ) )
+        {
+            if( !bWriteOnlyInPAMIfNeeded )
+                GDALWriteRPCTXTFile( pszTIFFFilename, papszRPCMD );
+            bRPCSerializedOtherWay = TRUE;
+        }
+
+        if( !bRPCSerializedOtherWay && bWriteOnlyInPAMIfNeeded && bSrcIsGeoTIFF )
+            ((GTiffDataset*)poSrcDS)->GDALPamDataset::SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
+    }
+}
+
+/************************************************************************/
 /*                           WriteMetadata()                            */
 /************************************************************************/
 
@@ -5756,31 +7528,21 @@ int  GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
         }
     }
 
-/* -------------------------------------------------------------------- */
-/*      Handle RPC data written to an RPB file.                         */
-/* -------------------------------------------------------------------- */
-    char **papszRPCMD = poSrcDS->GetMetadata("RPC");
-    if( papszRPCMD != NULL && !bExcludeRPBandIMGFileWriting )
+    if( !bExcludeRPBandIMGFileWriting )
     {
-        if( EQUAL(pszProfile,"GDALGeoTIFF") )
-            WriteRPCTag( hTIFF, papszRPCMD );
-
-        if( !EQUAL(pszProfile,"GDALGeoTIFF") 
-            || CSLFetchBoolean( papszCreationOptions, "RPB", FALSE ) )
-        {
-            GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
-        }
-    }
+        WriteRPC(poSrcDS, hTIFF, bSrcIsGeoTIFF,
+                 pszProfile, pszTIFFFilename,
+                 papszCreationOptions);
 
 /* -------------------------------------------------------------------- */
 /*      Handle metadata data written to an IMD file.                    */
 /* -------------------------------------------------------------------- */
-    char **papszIMDMD = poSrcDS->GetMetadata("IMD");
-    if( papszIMDMD != NULL && !bExcludeRPBandIMGFileWriting)
-    {
-        GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
+        char **papszIMDMD = poSrcDS->GetMetadata(MD_DOMAIN_IMD);
+        if( papszIMDMD != NULL )
+        {
+            GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
+        }
     }
-
 /* -------------------------------------------------------------------- */
 /*      We also need to address band specific metadata, and special     */
 /*      "role" metadata.                                                */
@@ -5816,10 +7578,10 @@ int  GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
         {
             char szValue[128];
 
-            sprintf( szValue, "%.18g", dfOffset );
+            CPLsprintf( szValue, "%.18g", dfOffset );
             AppendMetadataItem( &psRoot, &psTail, "OFFSET", szValue, nBand, 
                                 "offset", "" );
-            sprintf( szValue, "%.18g", dfScale );
+            CPLsprintf( szValue, "%.18g", dfScale );
             AppendMetadataItem( &psRoot, &psTail, "SCALE", szValue, nBand, 
                                 "scale", "" );
         }
@@ -5936,8 +7698,8 @@ void GTiffDataset::PushMetadataToPam()
         {
             char **papszMD = poSrcMDMD->GetMetadata( papszDomainList[iDomain] );
 
-            if( EQUAL(papszDomainList[iDomain],"RPC")
-                || EQUAL(papszDomainList[iDomain],"IMD") 
+            if( EQUAL(papszDomainList[iDomain],MD_DOMAIN_RPC)
+                || EQUAL(papszDomainList[iDomain],MD_DOMAIN_IMD)
                 || EQUAL(papszDomainList[iDomain],"_temporary_")
                 || EQUAL(papszDomainList[iDomain],"IMAGE_STRUCTURE")
                 || EQUAL(papszDomainList[iDomain],"COLOR_PROFILE") )
@@ -5975,15 +7737,14 @@ void GTiffDataset::PushMetadataToPam()
 }
 
 /************************************************************************/
-/*                            WriteRPCTag()                             */
+/*                     GTiffDatasetWriteRPCTag()                        */
 /*                                                                      */
 /*      Format a TAG according to:                                      */
 /*                                                                      */
 /*      http://geotiff.maptools.org/rpc_prop.html                       */
 /************************************************************************/
 
-/* static */
-void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
+void GTiffDatasetWriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
 
 {
     double adfRPCTag[92];
@@ -6022,7 +7783,7 @@ void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
 /*      http://geotiff.maptools.org/rpc_prop.html                       */
 /************************************************************************/
 
-void GTiffDataset::ReadRPCTag()
+char** GTiffDatasetReadRPCTag(TIFF* hTIFF)
 
 {
     double *padfRPCTag;
@@ -6034,18 +7795,18 @@ void GTiffDataset::ReadRPCTag()
 
     if( !TIFFGetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag ) 
         || nCount != 92 )
-        return;
+        return NULL;
 
-    asMD.SetNameValue("LINE_OFF", CPLOPrintf("%.15g", padfRPCTag[2]));
-    asMD.SetNameValue("SAMP_OFF", CPLOPrintf("%.15g", padfRPCTag[3]));
-    asMD.SetNameValue("LAT_OFF", CPLOPrintf("%.15g", padfRPCTag[4]));
-    asMD.SetNameValue("LONG_OFF", CPLOPrintf("%.15g", padfRPCTag[5]));
-    asMD.SetNameValue("HEIGHT_OFF", CPLOPrintf("%.15g", padfRPCTag[6]));
-    asMD.SetNameValue("LINE_SCALE", CPLOPrintf("%.15g", padfRPCTag[7]));
-    asMD.SetNameValue("SAMP_SCALE", CPLOPrintf("%.15g", padfRPCTag[8]));
-    asMD.SetNameValue("LAT_SCALE", CPLOPrintf("%.15g", padfRPCTag[9]));
-    asMD.SetNameValue("LONG_SCALE", CPLOPrintf("%.15g", padfRPCTag[10]));
-    asMD.SetNameValue("HEIGHT_SCALE", CPLOPrintf("%.15g", padfRPCTag[11]));
+    asMD.SetNameValue(RPC_LINE_OFF, CPLOPrintf("%.15g", padfRPCTag[2]));
+    asMD.SetNameValue(RPC_SAMP_OFF, CPLOPrintf("%.15g", padfRPCTag[3]));
+    asMD.SetNameValue(RPC_LAT_OFF, CPLOPrintf("%.15g", padfRPCTag[4]));
+    asMD.SetNameValue(RPC_LONG_OFF, CPLOPrintf("%.15g", padfRPCTag[5]));
+    asMD.SetNameValue(RPC_HEIGHT_OFF, CPLOPrintf("%.15g", padfRPCTag[6]));
+    asMD.SetNameValue(RPC_LINE_SCALE, CPLOPrintf("%.15g", padfRPCTag[7]));
+    asMD.SetNameValue(RPC_SAMP_SCALE, CPLOPrintf("%.15g", padfRPCTag[8]));
+    asMD.SetNameValue(RPC_LAT_SCALE, CPLOPrintf("%.15g", padfRPCTag[9]));
+    asMD.SetNameValue(RPC_LONG_SCALE, CPLOPrintf("%.15g", padfRPCTag[10]));
+    asMD.SetNameValue(RPC_HEIGHT_SCALE, CPLOPrintf("%.15g", padfRPCTag[11]));
 
     for( i = 0; i < 20; i++ )
     {
@@ -6056,7 +7817,7 @@ void GTiffDataset::ReadRPCTag()
             osMultiField = "";
         osMultiField += osField;
     }
-    asMD.SetNameValue("LINE_NUM_COEFF", osMultiField );
+    asMD.SetNameValue(RPC_LINE_NUM_COEFF, osMultiField );
 
     for( i = 0; i < 20; i++ )
     {
@@ -6067,7 +7828,7 @@ void GTiffDataset::ReadRPCTag()
             osMultiField = "";
         osMultiField += osField;
     }
-    asMD.SetNameValue( "LINE_DEN_COEFF", osMultiField );
+    asMD.SetNameValue( RPC_LINE_DEN_COEFF, osMultiField );
 
     for( i = 0; i < 20; i++ )
     {
@@ -6078,7 +7839,7 @@ void GTiffDataset::ReadRPCTag()
             osMultiField = "";
         osMultiField += osField;
     }
-    asMD.SetNameValue( "SAMP_NUM_COEFF", osMultiField );
+    asMD.SetNameValue( RPC_SAMP_NUM_COEFF, osMultiField );
 
     for( i = 0; i < 20; i++ )
     {
@@ -6089,9 +7850,9 @@ void GTiffDataset::ReadRPCTag()
             osMultiField = "";
         osMultiField += osField;
     }
-    asMD.SetNameValue( "SAMP_DEN_COEFF", osMultiField );
+    asMD.SetNameValue( RPC_SAMP_DEN_COEFF, osMultiField );
 
-    oGTiffMDMD.SetMetadata( asMD, "RPC" );
+    return asMD.StealList();
 }
 
 /************************************************************************/
@@ -6105,7 +7866,7 @@ void GTiffDataset::WriteNoDataValue( TIFF *hTIFF, double dfNoData )
     if (CPLIsNan(dfNoData))
         strcpy(szVal, "nan");
 	else
-        snprintf(szVal, sizeof(szVal), "%.18g", dfNoData);
+        CPLsnprintf(szVal, sizeof(szVal), "%.18g", dfNoData);
     TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, szVal );
 }
 
@@ -6176,10 +7937,12 @@ int GTiffDataset::SetDirectory( toff_t nNewOffset )
         // Now, reset zip and jpeg quality.
         if(nJpegQuality > 0 && nCompression == COMPRESSION_JPEG)
         {
-            CPLDebug( "GTiff", "Propgate JPEG_QUALITY(%d) in SetDirectory()",
+            CPLDebug( "GTiff", "Propagate JPEG_QUALITY(%d) in SetDirectory()",
                       nJpegQuality );
             TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality); 
         }
+        if(nJpegTablesMode >= 0 && nCompression == COMPRESSION_JPEG)
+            TIFFSetField(hTIFF, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode); 
         if(nZLevel > 0 && nCompression == COMPRESSION_ADOBE_DEFLATE)
             TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, nZLevel);
         if(nLZMAPreset > 0 && nCompression == COMPRESSION_LZMA)
@@ -6215,7 +7978,7 @@ int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
 /*	First we check to see if the file has the expected header	*/
 /*	bytes.								*/    
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->nHeaderBytes < 2 )
+    if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 2 )
         return FALSE;
 
     if( (poOpenInfo->pabyHeader[0] != 'I' || poOpenInfo->pabyHeader[1] != 'I')
@@ -6243,6 +8006,246 @@ int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
 }
 
 /************************************************************************/
+/*                            GTIFFErrorHandler()                       */
+/************************************************************************/
+
+class GTIFFErrorStruct
+{
+public:
+    CPLErr type;
+    int    no;
+    CPLString msg;
+    
+        GTIFFErrorStruct() {}
+        GTIFFErrorStruct(CPLErr eErr, int no, const char* msg) :
+            type(eErr), no(no), msg(msg) {}
+};
+
+static void CPL_STDCALL GTIFFErrorHandler(CPLErr eErr, int no, const char* msg)
+{
+    std::vector<GTIFFErrorStruct>* paoErrors =
+        (std::vector<GTIFFErrorStruct>*) CPLGetErrorHandlerUserData();
+    paoErrors->push_back(GTIFFErrorStruct(eErr, no, msg));
+}
+
+/************************************************************************/
+/*                          GTIFFExtendMemoryFile()                     */
+/************************************************************************/
+
+static int GTIFFExtendMemoryFile(const CPLString& osTmpFilename,
+                                 VSILFILE* fpTemp,
+                                 VSILFILE* fpL,
+                                 int nNewLength,
+                                 GByte*& pabyBuffer,
+                                 vsi_l_offset& nDataLength)
+{
+    if( nNewLength <= (int)nDataLength )
+        return TRUE;
+    VSIFSeekL(fpTemp, nNewLength - 1, SEEK_SET);
+    char ch = 0;
+    VSIFWriteL(&ch, 1, 1, fpTemp);
+    int nOldDataLength = nDataLength;
+    pabyBuffer = (GByte*)VSIGetMemFileBuffer( osTmpFilename, &nDataLength, FALSE);
+    int nToRead = nNewLength - nOldDataLength;
+    int nRead = (int)VSIFReadL( pabyBuffer + nOldDataLength, 1, nToRead, fpL);
+    if( nRead != nToRead )
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Needed to read %d bytes. Only %d got", nToRead, nRead);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                         GTIFFMakeBufferedStream()                    */
+/************************************************************************/
+
+static int GTIFFMakeBufferedStream(GDALOpenInfo* poOpenInfo)
+{
+    CPLString osTmpFilename;
+    static int nCounter = 0;
+    osTmpFilename.Printf("/vsimem/stream_%d.tif", ++nCounter);
+    VSILFILE* fpTemp = VSIFOpenL(osTmpFilename, "wb+");
+    if( fpTemp == NULL )
+        return FALSE;
+    /* The seek is needed for /vsistdin/ that has some rewind capabilities */
+    VSIFSeekL(poOpenInfo->fpL, poOpenInfo->nHeaderBytes, SEEK_SET);
+    CPLAssert( (int)VSIFTellL(poOpenInfo->fpL) == poOpenInfo->nHeaderBytes );
+    VSIFWriteL(poOpenInfo->pabyHeader, 1, poOpenInfo->nHeaderBytes, fpTemp);
+    vsi_l_offset nDataLength;
+    GByte* pabyBuffer = (GByte*)VSIGetMemFileBuffer( osTmpFilename, &nDataLength, FALSE);
+    int bLittleEndian = (pabyBuffer[0] == 'I');
+    int bSwap = (bLittleEndian && !CPL_IS_LSB) || (!bLittleEndian && CPL_IS_LSB);
+    int bBigTIFF = ( pabyBuffer[2] == 43 || pabyBuffer[3] == 43 );
+    vsi_l_offset nMaxOffset = 0;
+    if( bBigTIFF )
+    {
+        GUIntBig nTmp;
+        memcpy(&nTmp, pabyBuffer + 8, 8);
+        if( bSwap ) CPL_SWAP64PTR(&nTmp);
+        if( nTmp != 16 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "IFD start should be at offset 16 for a streamed BigTIFF");
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        memcpy(&nTmp, pabyBuffer + 16, 8);
+        if( bSwap ) CPL_SWAP64PTR(&nTmp);
+        if( nTmp > 1024 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Too many tags : " CPL_FRMT_GIB, nTmp);
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        int nTags = nTmp;
+        int nSpaceForTags = nTags * 20;
+        if( !GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
+                                    24 + nSpaceForTags,
+                                    pabyBuffer, nDataLength) )
+        {
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        nMaxOffset = 24 + nSpaceForTags + 8;
+        for(int i=0;i<nTags;i++)
+        {
+            GUInt16 nTmp16;
+            memcpy(&nTmp16, pabyBuffer + 24 + i * 20, 2);
+            if( bSwap ) CPL_SWAP16PTR(&nTmp16);
+            int nTag = nTmp16;
+            memcpy(&nTmp16, pabyBuffer + 24 + i * 20 + 2, 2);
+            if( bSwap ) CPL_SWAP16PTR(&nTmp16);
+            int nDataType = nTmp16;
+            memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 4, 8);
+            if( bSwap ) CPL_SWAP64PTR(&nTmp);
+            if( nTmp >= 16 * 1024 * 1024 )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Too many elements for tag %d : " CPL_FRMT_GUIB, nTag, nTmp);
+                VSIFCloseL(fpTemp);
+                VSIUnlink(osTmpFilename);
+                return FALSE;
+            }
+            GUInt32 nCount = (GUInt32)nTmp;
+            GUInt32 nTagSize = TIFFDataWidth((TIFFDataType)nDataType) * nCount;
+            if( nTagSize > 8 )
+            {
+                memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 12, 8);
+                if( bSwap ) CPL_SWAP64PTR(&nTmp);
+                if( nTmp > (GUIntBig)((((GIntBig)INT_MAX) << 32) - nTagSize) )
+                {
+                    CPLError(CE_Failure, CPLE_NotSupported,
+                             "Overflow with tag %d", nTag);
+                    VSIFCloseL(fpTemp);
+                    VSIUnlink(osTmpFilename);
+                    return FALSE;
+                }
+                if( (vsi_l_offset)(nTmp + nTagSize) > nMaxOffset )
+                    nMaxOffset = nTmp + nTagSize;
+            }
+        }
+    }
+    else
+    {
+        GUInt32 nTmp;
+        memcpy(&nTmp, pabyBuffer + 4, 4);
+        if( bSwap ) CPL_SWAP32PTR(&nTmp);
+        if( nTmp != 8 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "IFD start should be at offset 8 for a streamed TIFF");
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        GUInt16 nTmp16;
+        memcpy(&nTmp16, pabyBuffer + 8, 2);
+        if( bSwap ) CPL_SWAP16PTR(&nTmp16);
+        if( nTmp16 > 1024 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Too many tags : %d", nTmp16);
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        int nTags = nTmp16;
+        int nSpaceForTags = nTags * 12;
+        if( !GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
+                                    10 + nSpaceForTags,
+                                    pabyBuffer, nDataLength) )
+        {
+            VSIFCloseL(fpTemp);
+            VSIUnlink(osTmpFilename);
+            return FALSE;
+        }
+        nMaxOffset = 10 + nSpaceForTags + 4;
+        for(int i=0;i<nTags;i++)
+        {
+            memcpy(&nTmp16, pabyBuffer + 10 + i * 12, 2);
+            if( bSwap ) CPL_SWAP16PTR(&nTmp16);
+            int nTag = nTmp16;
+            memcpy(&nTmp16, pabyBuffer + 10 + i * 12 + 2, 2);
+            if( bSwap ) CPL_SWAP16PTR(&nTmp16);
+            int nDataType = nTmp16;
+            memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 4, 4);
+            if( bSwap ) CPL_SWAP32PTR(&nTmp);
+            if( nTmp >= 16 * 1024 * 1024 )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Too many elements for tag %d : %u", nTag, nTmp);
+                VSIFCloseL(fpTemp);
+                VSIUnlink(osTmpFilename);
+                return FALSE;
+            }
+            GUInt32 nCount = nTmp;
+            GUInt32 nTagSize = TIFFDataWidth((TIFFDataType)nDataType) * nCount;
+            if( nTagSize > 4 )
+            {
+                memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 8, 4);
+                if( bSwap ) CPL_SWAP32PTR(&nTmp);
+                if( nTmp > (GUInt32)(0xFFFFFFFFU - nTagSize) )
+                {
+                    CPLError(CE_Failure, CPLE_NotSupported,
+                             "Overflow with tag %d", nTag);
+                    VSIFCloseL(fpTemp);
+                    VSIUnlink(osTmpFilename);
+                    return FALSE;
+                }
+                if( nTmp + nTagSize > nMaxOffset )
+                    nMaxOffset = nTmp + nTagSize;
+            }
+        }
+    }
+    if( nMaxOffset > 10 * 1024 * 1024 )
+    {
+        VSIFCloseL(fpTemp);
+        VSIUnlink(osTmpFilename);
+        return FALSE;
+    }
+    if( !GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
+                                nMaxOffset, pabyBuffer, nDataLength) )
+    {
+        VSIFCloseL(fpTemp);
+        VSIUnlink(osTmpFilename);
+        return FALSE;
+    }
+    CPLAssert(nDataLength == VSIFTellL(poOpenInfo->fpL));
+    poOpenInfo->fpL = (VSILFILE*)VSICreateBufferedReaderHandle(
+        (VSIVirtualHandle*)poOpenInfo->fpL, pabyBuffer, ((vsi_l_offset)INT_MAX) << 32 );
+    VSIFCloseL(fpTemp);
+    VSIUnlink(osTmpFilename);
+
+    return TRUE;
+}
+
+/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
@@ -6280,33 +8283,63 @@ GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 
     /* Disable strip chop for now */
-    hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "rc" : "r+c" );
+    int bStreaming = FALSE;
+    const char* pszReadStreaming = CPLGetConfigOption("TIFF_READ_STREAMING", NULL);
+    if( poOpenInfo->fpL == NULL )
+    {
+        poOpenInfo->fpL = VSIFOpenL( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "rb" : "r+b" );
+        if( poOpenInfo->fpL == NULL )
+            return NULL;
+    }
+    else if( !(pszReadStreaming && !CSLTestBoolean(pszReadStreaming)) &&
+             poOpenInfo->nHeaderBytes >= 24 &&
+             ((int)VSIFTellL(poOpenInfo->fpL) == poOpenInfo->nHeaderBytes || /* A pipe has no seeking capability, so its position is 0 despite having read bytes */
+              strcmp(pszFilename, "/vsistdin/") == 0 ||
+              //strncmp(pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")) == 0 ||
+              (pszReadStreaming && CSLTestBoolean(pszReadStreaming))) )
+    {
+        bStreaming = TRUE;
+        if( !GTIFFMakeBufferedStream(poOpenInfo) )
+            return NULL;
+    }
+
+    /* Store errors/warnings and emit them later */
+    std::vector<GTIFFErrorStruct> aoErrors;
+    CPLPushErrorHandlerEx(GTIFFErrorHandler, &aoErrors);
+    hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "rc" : "r+c",
+                          poOpenInfo->fpL );
+    CPLPopErrorHandler();
 #if SIZEOF_VOIDP == 4
     if( hTIFF == NULL )
     {
         /* Case of one-strip file where the strip size is > 2GB (#5403) */
         if( bGlobalStripIntegerOverflow )
         {
-            hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "r" : "r+" );
+            hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "r" : "r+",
+                                  poOpenInfo->fpL );
             bGlobalStripIntegerOverflow = FALSE;
-            if( hTIFF == NULL )
-            {
-                return( NULL );
-            }
-        }
-        else
-        {
-            return( NULL );
         }
     }
     else
     {
         bGlobalStripIntegerOverflow = FALSE;
     }
-#else
+#endif
+
+    /* Now emit errors and change their criticality if needed */
+    /* We only emit failures if we didn't manage to open the file */
+    /* Otherwise it make Python bindings unhappy (#5616) */
+    for(size_t iError=0;iError<aoErrors.size();iError++)
+    {
+        CPLError( (hTIFF == NULL && aoErrors[iError].type == CE_Failure) ? CE_Failure : CE_Warning,
+                  aoErrors[iError].no,
+                  "%s",
+                  aoErrors[iError].msg.c_str() );
+    }
+    aoErrors.resize(0);
+
     if( hTIFF == NULL )
         return( NULL );
-#endif
 
     uint32  nXSize, nYSize;
     uint16  nPlanarConfig;
@@ -6370,7 +8403,8 @@ GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
         {
             CPLDebug("GTiff", "Reopen with strip chop enabled");
             XTIFFClose(hTIFF);
-            hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "r" : "r+" );
+            hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "r" : "r+",
+                                  poOpenInfo->fpL );
             if( hTIFF == NULL )
                 return( NULL );
         }
@@ -6385,21 +8419,111 @@ GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
     poDS->SetDescription( pszFilename );
     poDS->osFilename = pszFilename;
     poDS->poActiveDS = poDS;
+    poDS->fpL = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+    poDS->bStreamingIn = bStreaming;
 
     if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
                           TIFFCurrentDirOffset(hTIFF), TRUE,
                           poOpenInfo->eAccess, 
                           bAllowRGBAInterface, TRUE,
-                          poOpenInfo->papszSiblingFiles) != CE_None )
+                          poOpenInfo->GetSiblingFiles()) != CE_None )
     {
         delete poDS;
         return NULL;
     }
 
+    if( nCompression == COMPRESSION_JPEG && poOpenInfo->eAccess == GA_Update )
+    {
+        int bHasQuantizationTable = FALSE, bHasHuffmanTable = FALSE;
+        int nQuality = poDS->GuessJPEGQuality(bHasQuantizationTable,
+                                              bHasHuffmanTable);
+        if( nQuality > 0 )
+        {
+            CPLDebug("GTiff", "Guessed JPEG quality to be %d", nQuality);
+            poDS->nJpegQuality = nQuality;
+            TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nQuality );
+
+            /* This means we will use the quantization tables from the JpegTables */
+            /* tag */
+            poDS->nJpegTablesMode = JPEGTABLESMODE_QUANT;
+        }
+        else
+        {
+            uint32 nJPEGTableSize = 0;
+            void* pJPEGTable = NULL;
+            if( !TIFFGetField(hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable) )
+            {
+                int bFoundNonEmptyBlock = FALSE;
+                toff_t *panByteCounts = NULL;
+                int nBlockCount;
+                if( poDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+                    nBlockCount = poDS->nBlocksPerBand * poDS->nBands;
+                else
+                    nBlockCount = poDS->nBlocksPerBand;
+                if( TIFFIsTiled( hTIFF ) )
+                    TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts );
+                else
+                    TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
+                if( panByteCounts != NULL )
+                {
+                    for( int iBlock = 0; iBlock < nBlockCount; iBlock++ )
+                    {
+                        if( panByteCounts[iBlock] != 0 )
+                        {
+                            bFoundNonEmptyBlock = TRUE;
+                            break;
+                        }
+                    }
+                }
+                if( bFoundNonEmptyBlock )
+                {
+                    CPLDebug("GTiff", "Could not guess JPEG quality. "
+                             "JPEG tables are missing, so going in "
+                             "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
+                    /* Write quantization tables in each strile */
+                    poDS->nJpegTablesMode = 0;
+                }
+            }
+            else
+            {
+                if( bHasQuantizationTable )
+                {
+                    // FIXME in libtiff: this is likely going to cause issues since
+                    // libtiff will reuse in each strile the number of the global
+                    // quantization table, which is invalid.
+
+                    CPLDebug("GTiff", "Could not guess JPEG quality although JPEG "
+                            "quantization tables are present, so going in "
+                            "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
+                }
+                else
+                {
+                    CPLDebug("GTiff", "Could not guess JPEG quality since JPEG "
+                            "quantization tables are not present, so going in "
+                            "TIFFTAG_JPEGTABLESMODE = 0/2 mode");
+                }
+
+                /* Write quantization tables in each strile */
+                poDS->nJpegTablesMode = 0;
+            }
+        }
+        if( bHasHuffmanTable )
+        {
+            /* If there are Huffman tables in header use them, otherwise */
+            /* if we use optimized tables, libtiff will currently reuse */
+            /* the number of the Huffman tables of the header for the */
+            /* optimized version of each strile, which is illegal */
+            poDS->nJpegTablesMode |= JPEGTABLESMODE_HUFF;
+        }
+        if( poDS->nJpegTablesMode >= 0 )
+            TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE, poDS->nJpegTablesMode);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
-    poDS->TryLoadXML( poOpenInfo->papszSiblingFiles);
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
     poDS->ApplyPamInfo();
 
     int i;
@@ -6428,18 +8552,39 @@ GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
     poDS->bColorProfileMetadataChanged = FALSE;
     poDS->bMetadataChanged = FALSE;
     poDS->bGeoTIFFInfoChanged = FALSE;
-    poDS->bForceUnsetGT = FALSE;
+    poDS->bNoDataChanged = FALSE;
+    poDS->bForceUnsetGTOrGCPs = FALSE;
     poDS->bForceUnsetProjection = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, pszFilename, poOpenInfo->GetSiblingFiles() );
     
     return poDS;
 }
 
 /************************************************************************/
+/*                      GTiffDatasetSetAreaOrPointMD()                  */
+/************************************************************************/
+
+static void GTiffDatasetSetAreaOrPointMD(GTIF* hGTIF,
+                                         GDALMultiDomainMetadata& oGTiffMDMD)
+{
+    // Is this a pixel-is-point dataset?
+    short nRasterType;
+
+    if( GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType,
+                    0, 1 ) == 1 )
+    {
+        if( nRasterType == (short) RasterPixelIsPoint )
+            oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
+        else
+            oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
+    }
+}
+
+/************************************************************************/
 /*                         LoadMDAreaOrPoint()                          */
 /************************************************************************/
 
@@ -6467,17 +8612,7 @@ void GTiffDataset::LoadMDAreaOrPoint()
     }
     else
     {
-        // Is this a pixel-is-point dataset?
-        short nRasterType;
-
-        if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
-                       0, 1 ) == 1 )
-        {
-            if( nRasterType == (short) RasterPixelIsPoint )
-                oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
-            else
-                oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
-        }
+        GTiffDatasetSetAreaOrPointMD( hGTIF, oGTiffMDMD );
 
         GTIFFree( hGTIF );
     }
@@ -6543,9 +8678,6 @@ void GTiffDataset::LookForProjection()
             }
         }
 
-        // Is this a pixel-is-point dataset?
-        short nRasterType;
-
         // check the tif linear unit and the CS linear unit 
 #ifdef ESRI_BUILD
         AdjustLinearUnit(psGTIFDefn.UOMLength); 
@@ -6557,14 +8689,7 @@ void GTiffDataset::LookForProjection()
         CPLFree(psGTIFDefn);
 #endif
 
-        if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType, 
-                       0, 1 ) == 1 )
-        {
-            if( nRasterType == (short) RasterPixelIsPoint )
-                oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
-            else
-                oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
-        }
+        GTiffDatasetSetAreaOrPointMD( hGTIF, oGTiffMDMD );
 
         GTIFFree( hGTIF );
     }
@@ -6575,7 +8700,7 @@ void GTiffDataset::LookForProjection()
     }
 
     bGeoTIFFInfoChanged = FALSE;
-    bForceUnsetGT = FALSE;
+    bForceUnsetGTOrGCPs = FALSE;
     bForceUnsetProjection = FALSE;
 }
 
@@ -6766,22 +8891,30 @@ GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
     if (!GTiffOneTimeInit())
         return NULL;
 
-    hTIFF = VSI_TIFFOpen( pszFilename, "r" );
+    VSILFILE* fpL = VSIFOpenL(pszFilename, "r");
+    if( fpL == NULL )
+        return NULL;
+    hTIFF = VSI_TIFFOpen( pszFilename, "r", fpL );
     if( hTIFF == NULL )
+    {
+        VSIFCloseL(fpL);
         return( NULL );
+    }
 
 /* -------------------------------------------------------------------- */
 /*      If a directory was requested by index, advance to it now.       */
 /* -------------------------------------------------------------------- */
     if( !bAbsolute )
     {
+        toff_t nOffsetRequested = nOffset;
         while( nOffset > 1 )
         {
             if( TIFFReadDirectory( hTIFF ) == 0 )
             {
                 XTIFFClose( hTIFF );
                 CPLError( CE_Failure, CPLE_OpenFailed, 
-                          "Requested directory %lu not found.", (long unsigned int)nOffset );
+                          "Requested directory %lu not found.", (long unsigned int)nOffsetRequested );
+                VSIFCloseL(fpL);
                 return NULL;
             }
             nOffset--;
@@ -6799,6 +8932,7 @@ GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
     poDS->SetDescription( poOpenInfo->pszFilename );
     poDS->osFilename = poOpenInfo->pszFilename;
     poDS->poActiveDS = poDS;
+    poDS->fpL = fpL;
 
     if( !EQUAL(pszFilename,poOpenInfo->pszFilename) 
         && !EQUALN(poOpenInfo->pszFilename,"GTIFF_RAW:",10) )
@@ -6817,7 +8951,7 @@ GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
     if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
                           nOffset, FALSE, GA_ReadOnly,
                           bAllowRGBAInterface, TRUE,
-                          poOpenInfo->papszSiblingFiles ) != CE_None )
+                          poOpenInfo->GetSiblingFiles() ) != CE_None )
     {
         delete poDS;
         return NULL;
@@ -7029,7 +9163,7 @@ void GTiffDataset::SaveICCProfile(GTiffDataset *pDS, TIFF *hTIFF, char **papszPa
             int j;
             for( j = 0; j < 3; j++ )
             {
-                float v = (float)atof(papszTokens[j]);
+                float v = (float)CPLAtof(papszTokens[j]);
 
                 if (j == 2)
                 {
@@ -7074,7 +9208,7 @@ void GTiffDataset::SaveICCProfile(GTiffDataset *pDS, TIFF *hTIFF, char **papszPa
                 int j;
                 for( j = 0; j < 3; j++ )
                 {
-                    float v = (float)atof(papszTokens[j]);
+                    float v = (float)CPLAtof(papszTokens[j]);
 
                     if (j == 2)
                     {
@@ -7428,6 +9562,17 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
     int bMinIsWhite = nPhotometric == PHOTOMETRIC_MINISWHITE;
 
 /* -------------------------------------------------------------------- */
+/*      Check for NODATA                                                */
+/* -------------------------------------------------------------------- */
+    char    *pszText;
+    if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) &&
+        !EQUAL(pszText, "") )
+    {
+        bNoDataSet = TRUE;
+        dfNoDataValue = CPLAtofM( pszText );
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Capture the color table if there is one.                        */
 /* -------------------------------------------------------------------- */
     unsigned short	*panRed, *panGreen, *panBlue;
@@ -7436,29 +9581,29 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
         || TIFFGetField( hTIFF, TIFFTAG_COLORMAP, 
                          &panRed, &panGreen, &panBlue) == 0 )
     {
-	// Build inverted palette if we have inverted photometric.
-	// Pixel values remains unchanged.  Avoid doing this for *deep*
-        // data types (per #1882)
-	if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
-	{
-	    GDALColorEntry  oEntry;
-	    int		    iColor, nColorCount;
-	    
-	    poColorTable = new GDALColorTable();
-	    nColorCount = 1 << nBitsPerSample;
-
-	    for ( iColor = 0; iColor < nColorCount; iColor++ )
-	    {
-		oEntry.c1 = oEntry.c2 = oEntry.c3 = (short) 
-                    ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
-		oEntry.c4 = 255;
-		poColorTable->SetColorEntry( iColor, &oEntry );
-	    }
-
-	    nPhotometric = PHOTOMETRIC_PALETTE;
-	}
-	else
-	    poColorTable = NULL;
+        // Build inverted palette if we have inverted photometric.
+        // Pixel values remains unchanged.  Avoid doing this for *deep*
+            // data types (per #1882)
+        if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
+        {
+            GDALColorEntry  oEntry;
+            int		    iColor, nColorCount;
+            
+            poColorTable = new GDALColorTable();
+            nColorCount = 1 << nBitsPerSample;
+
+            for ( iColor = 0; iColor < nColorCount; iColor++ )
+            {
+            oEntry.c1 = oEntry.c2 = oEntry.c3 = (short) 
+                        ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
+            oEntry.c4 = 255;
+            poColorTable->SetColorEntry( iColor, &oEntry );
+            }
+
+            nPhotometric = PHOTOMETRIC_PALETTE;
+        }
+        else
+            poColorTable = NULL;
     }
     else
     {
@@ -7474,7 +9619,7 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
             oEntry.c1 = panRed[iColor] / 256;
             oEntry.c2 = panGreen[iColor] / 256;
             oEntry.c3 = panBlue[iColor] / 256;
-            oEntry.c4 = 255;
+            oEntry.c4 = (bNoDataSet && (int)dfNoDataValue == iColor) ? 0 : 255;
 
             poColorTable->SetColorEntry( iColor, &oEntry );
 
@@ -7495,7 +9640,7 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
                 oEntry.c1 = panRed[iColor];
                 oEntry.c2 = panGreen[iColor];
                 oEntry.c3 = panBlue[iColor];
-                oEntry.c4 = 255;
+                oEntry.c4 = (bNoDataSet && (int)dfNoDataValue == iColor) ? 0 : 255;
                 
                 poColorTable->SetColorEntry( iColor, &oEntry );
             }
@@ -7545,7 +9690,7 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
 
         if( psGTIF )
         {
-            if( GTIFKeyGet(psGTIF, GTRasterTypeGeoKey, &nRasterType,
+            if( GDALGTIFKeyGetSHORT(psGTIF, GTRasterTypeGeoKey, &nRasterType,
                         0, 1 ) == 1
                 && nRasterType == (short) RasterPixelIsPoint )
             {
@@ -7697,14 +9842,14 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
         
         CPLFree( pszTabWKT );
         bGeoTIFFInfoChanged = FALSE;
-        bForceUnsetGT = FALSE;
+        bForceUnsetGTOrGCPs = FALSE;
         bForceUnsetProjection = FALSE;
     }
 
 /* -------------------------------------------------------------------- */
 /*      Capture some other potentially interesting information.         */
 /* -------------------------------------------------------------------- */
-    char	*pszText, szWorkMDI[200];
+    char	szWorkMDI[200];
     uint16  nShort;
 
     size_t iTag;
@@ -7720,7 +9865,7 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
             float   fVal;
             if( TIFFGetField( hTIFF, asTIFFTags[iTag].nTagVal, &fVal ) )
             {
-                sprintf( szWorkMDI, "%.8g", fVal );
+                CPLsprintf( szWorkMDI, "%.8g", fVal );
                 SetMetadataItem( asTIFFTags[iTag].pszTagName, szWorkMDI );
             }
         }
@@ -7914,18 +10059,30 @@ CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
 
         CPLDestroyXMLNode( psRoot );
     }
-
-    bMetadataChanged = FALSE;
-
-/* -------------------------------------------------------------------- */
-/*      Check for NODATA                                                */
-/* -------------------------------------------------------------------- */
-    if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) )
+    
+    if( bStreamingIn )
     {
-        bNoDataSet = TRUE;
-        dfNoDataValue = CPLAtofM( pszText );
+        toff_t* panOffsets = NULL;
+        TIFFGetField( hTIFF, (TIFFIsTiled( hTIFF )) ? TIFFTAG_TILEOFFSETS : TIFFTAG_STRIPOFFSETS , &panOffsets );
+        if( panOffsets )
+        {
+            int nBlockCount = ( TIFFIsTiled(hTIFF) ) ? TIFFNumberOfTiles(hTIFF) : TIFFNumberOfStrips(hTIFF);
+            for(int i=1;i<nBlockCount;i++)
+            {
+                if( panOffsets[i] < panOffsets[i-1] )
+                {
+                    SetMetadataItem("UNORDERED_BLOCKS", "YES", "TIFF");
+                    CPLDebug("GTIFF",
+                             "Offset of block %d is lower than previous block. Reader must be careful",
+                             i);
+                    break;
+                }
+            }
+        }
     }
 
+    bMetadataChanged = FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      If this is a "base" raster, we should scan for any              */
 /*      associated overviews, internal mask bands and subdatasets.      */
@@ -7967,13 +10124,18 @@ void GTiffDataset::ScanDirectories()
 /* ==================================================================== */
 /*      Scan all directories.                                           */
 /* ==================================================================== */
-    char **papszSubdatasets = NULL;
+    CPLStringList aosSubdatasets;
     int  iDirIndex = 0;
 
     FlushDirectory();  
     while( !TIFFLastDirectory( hTIFF ) 
            && (iDirIndex == 0 || TIFFReadDirectory( hTIFF ) != 0) )
     {
+        /* Only libtiff 4.0.4 can handle between 32768 and 65535 directories */
+#if !defined(INTERNAL_LIBTIFF) && (!defined(TIFFLIB_VERSION) || (TIFFLIB_VERSION < 20120922))
+        if( iDirIndex == 32768 )
+            break;
+#endif
         toff_t	nThisDir = TIFFCurrentDirOffset(hTIFF);
         uint32	nSubType = 0;
 
@@ -7987,7 +10149,8 @@ void GTiffDataset::ScanDirectories()
         /* Embedded overview of the main image */
         if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
             (nSubType & FILETYPE_MASK) == 0 &&
-            iDirIndex != 1 )
+            iDirIndex != 1 &&
+            nOverviewCount < 30 /* to avoid DoS */ )
         {
             GTiffDataset	*poODS;
                 
@@ -8100,10 +10263,8 @@ void GTiffDataset::ScanDirectories()
                            iDirIndex, iDirIndex, 
                            (int)nXSize, (int)nYSize, nSPP );
 
-            papszSubdatasets = 
-                CSLAddString( papszSubdatasets, osName );
-            papszSubdatasets = 
-                CSLAddString( papszSubdatasets, osDesc );
+            aosSubdatasets.AddString(osName);
+            aosSubdatasets.AddString(osDesc);
         }
 
         // Make sure we are stepping from the expected directory regardless
@@ -8136,12 +10297,10 @@ void GTiffDataset::ScanDirectories()
 /*      Only keep track of subdatasets if we have more than one         */
 /*      subdataset (pair).                                              */
 /* -------------------------------------------------------------------- */
-    if( CSLCount(papszSubdatasets) > 2 )
+    if( aosSubdatasets.size() > 2 )
     {
-        oGTiffMDMD.SetMetadata( papszSubdatasets, "SUBDATASETS" );
+        oGTiffMDMD.SetMetadata( aosSubdatasets.StealList(), "SUBDATASETS" );
     }
-    CSLDestroy( papszSubdatasets );
-    
 }
 
 
@@ -8200,6 +10359,70 @@ static int GTiffGetJpegQuality(char** papszOptions)
     return nJpegQuality;
 }
 
+static int GTiffGetJpegTablesMode(char** papszOptions)
+{
+    return atoi(CSLFetchNameValueDef( papszOptions, "JPEGTABLESMODE",
+                                   "1" /* JPEGTABLESMODE_QUANT */));
+}
+
+/************************************************************************/
+/*                        GetDiscardLsbOption()                         */
+/************************************************************************/
+
+void GTiffDataset::GetDiscardLsbOption(char** papszOptions)
+{
+    const char* pszBits = CSLFetchNameValue( papszOptions, "DISCARD_LSB" );
+    if( pszBits == NULL)
+        return;
+    
+    if( nPhotometric == PHOTOMETRIC_PALETTE )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "DISCARD_LSB ignored on a paletted image");
+        return;
+    }
+    if( !(nBitsPerSample == 8 || nBitsPerSample == 16 || nBitsPerSample == 32) )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "DISCARD_LSB ignored on non 8, 16 or 32 bits integer images");
+        return;
+    }
+
+    char** papszTokens = CSLTokenizeString2( pszBits, ",", 0 );
+    if( CSLCount(papszTokens) == 1 )
+    {
+        bHasDiscardedLsb = TRUE;
+        for(int i=0;i<nBands;i++)
+        {
+            int nBits = atoi(papszTokens[0]);
+            anMaskLsb.push_back(~((1 << nBits)-1));
+            if( nBits > 1 )
+                anOffsetLsb.push_back(1 << (nBits-1));
+            else
+                anOffsetLsb.push_back(0);
+        }
+    }
+    else if( CSLCount(papszTokens) == nBands )
+    {
+        bHasDiscardedLsb = TRUE;
+        for(int i=0;i<nBands;i++)
+        {
+            int nBits = atoi(papszTokens[i]);
+            anMaskLsb.push_back(~((1 << nBits)-1));
+            if( nBits > 1 )
+                anOffsetLsb.push_back(1 << (nBits-1));
+            else
+                anOffsetLsb.push_back(0);
+        }
+    }
+    else
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "DISCARD_LSB ignored: wrong number of components");
+    }
+    CSLDestroy(papszTokens);
+}
+
 /************************************************************************/
 /*                            GTiffCreate()                             */
 /*                                                                      */
@@ -8212,7 +10435,9 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
                               int nXSize, int nYSize, int nBands,
                               GDALDataType eType,
                               double dfExtraSpaceForOverviews,
-                              char **papszParmList )
+                              char **papszParmList,
+                              VSILFILE** pfpL,
+                              CPLString& osTmpFilename )
 
 {
     TIFF		*hTIFF;
@@ -8220,7 +10445,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
     int                 bTiled = FALSE;
     int                 nCompression = COMPRESSION_NONE;
     int                 nPredictor = PREDICTOR_NONE, nJpegQuality = -1, nZLevel = -1,
-                        nLZMAPreset = -1;
+                        nLZMAPreset = -1, nJpegTablesMode = -1;
     uint16              nSampleFormat;
     int			nPlanar;
     const char          *pszValue;
@@ -8306,6 +10531,48 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
     nZLevel = GTiffGetZLevel(papszParmList);
     nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
     nJpegQuality = GTiffGetJpegQuality(papszParmList);
+    nJpegTablesMode = GTiffGetJpegTablesMode(papszParmList);
+
+/* -------------------------------------------------------------------- */
+/*      Streaming related code                                          */
+/* -------------------------------------------------------------------- */
+    int bStreaming = ( strcmp(pszFilename, "/vsistdout/") == 0 ||
+                       CSLFetchBoolean(papszParmList, "STREAMABLE_OUTPUT", FALSE) );
+#ifdef S_ISFIFO
+    if( !bStreaming )
+    {
+        VSIStatBufL sStat;
+        if( VSIStatExL(pszFilename, &sStat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0 &&
+             S_ISFIFO(sStat.st_mode) )
+        {
+            bStreaming = TRUE;
+        }
+    }
+#endif
+    if( bStreaming &&
+        !EQUAL("NONE", CSLFetchNameValueDef(papszParmList, "COMPRESS", "NONE")) )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Streaming only supported to uncompressed TIFF");
+        return NULL;
+    }
+    if( bStreaming &&
+        CSLFetchBoolean(papszParmList, "SPARSE_OK", FALSE) )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Streaming not supported with SPARSE_OK");
+        return NULL;
+    }
+    if( bStreaming &&
+        CSLFetchBoolean(papszParmList, "COPY_SRC_OVERVIEWS", FALSE) )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Streaming not supported with COPY_SRC_OVERVIEWS");
+        return NULL;
+    }
+    if( bStreaming )
+    {
+        static int nCounter = 0;
+        osTmpFilename = CPLSPrintf("/vsimem/vsistdout_%d.tif",  ++nCounter);
+        pszFilename = osTmpFilename.c_str();
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Compute the uncompressed size.                                  */
@@ -8416,7 +10683,16 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
         strcat(szOpeningFlag, "b");
     else if (eEndianness == ENDIANNESS_LITTLE)
         strcat(szOpeningFlag, "l");
-    hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag );
+
+    VSILFILE* fpL = VSIFOpenL( pszFilename, "w+b" );
+    if( fpL == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create new tiff file `%s' failed: %s",
+                  pszFilename, VSIStrerror(errno) );
+        return NULL;
+    }
+    hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag, fpL );
     if( hTIFF == NULL )
     {
         if( CPLGetLastErrorNo() == 0 )
@@ -8424,6 +10700,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
                       "Attempt to create new tiff file `%s'\n"
                       "failed in XTIFFOpen().\n",
                       pszFilename );
+        VSIFCloseL(fpL);
         return NULL;
     }
 
@@ -8524,9 +10801,17 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
             TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE );
         else if( EQUAL( pszValue, "PALETTE" ))
         {
-            TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
-            nSamplesAccountedFor = 1;
-            bForceColorTable = TRUE;
+            if( eType == GDT_Byte || eType == GDT_UInt16 )
+            {
+                TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
+                nSamplesAccountedFor = 1;
+                bForceColorTable = TRUE;
+            }
+            else
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "PHOTOMETRIC=PALETTE only compatible with Byte or UInt16");
+            }
         }
         else if( EQUAL( pszValue, "RGB" ))
         {
@@ -8549,6 +10834,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
                 CPLError(CE_Failure, CPLE_NotSupported,
                          "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
                 XTIFFClose(hTIFF);
+                VSIFCloseL(fpL);
                 return NULL;
             }
 
@@ -8557,6 +10843,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
                 CPLError(CE_Failure, CPLE_NotSupported,
                          "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
                 XTIFFClose(hTIFF);
+                VSIFCloseL(fpL);
                 return NULL;
             }
 
@@ -8568,6 +10855,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
                 CPLError(CE_Failure, CPLE_NotSupported,
                          "PHOTOMETRIC=YCBCR requires a source raster with only 3 bands (RGB)");
                 XTIFFClose(hTIFF);
+                VSIFCloseL(fpL);
                 return NULL;
             }
 
@@ -8667,7 +10955,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
     }
 
     /* Set the compression method before asking the default strip size */
-    /* This is usefull when translating to a JPEG-In-TIFF file where */
+    /* This is useful when translating to a JPEG-In-TIFF file where */
     /* the default strip size is 8 or 16 depending on the photometric value */
     TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompression );
 
@@ -8686,6 +10974,7 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
             !TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ))
         {
             XTIFFClose(hTIFF);
+            VSIFCloseL(fpL);
             return NULL;
         }
     }
@@ -8716,6 +11005,9 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
     else if( nCompression == COMPRESSION_LZMA && nLZMAPreset != -1)
         TIFFSetField( hTIFF, TIFFTAG_LZMAPRESET, nLZMAPreset );
 
+    if( nCompression == COMPRESSION_JPEG )
+        TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode );
+
 /* -------------------------------------------------------------------- */
 /*      If we forced production of a file with photometric=palette,     */
 /*      we need to push out a default color table.                      */
@@ -8727,39 +11019,277 @@ TIFF *GTiffDataset::CreateLL( const char * pszFilename,
         if( eType == GDT_Byte )
             nColors = 256;
         else
-            nColors = 65536;
-        
-        unsigned short *panTRed, *panTGreen, *panTBlue;
+            nColors = 65536;
+        
+        unsigned short *panTRed, *panTGreen, *panTBlue;
+
+        panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
+        panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
+        panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
+
+        for( int iColor = 0; iColor < nColors; iColor++ )
+        {
+            if( eType == GDT_Byte )
+            {                
+                panTRed[iColor] = (unsigned short) (257 * iColor);
+                panTGreen[iColor] = (unsigned short) (257 * iColor);
+                panTBlue[iColor] = (unsigned short) (257 * iColor);
+            }
+            else
+            {
+                panTRed[iColor] = (unsigned short) iColor;
+                panTGreen[iColor] = (unsigned short) iColor;
+                panTBlue[iColor] = (unsigned short) iColor;
+            }
+        }
+        
+        TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
+                      panTRed, panTGreen, panTBlue );
+        
+        CPLFree( panTRed );
+        CPLFree( panTGreen );
+        CPLFree( panTBlue );
+    }
+
+    /* Would perhaps works with libtiff 3.X but didn't bother trying */
+    /* This trick creates a temporary in-memory file and fetches its JPEG tables */
+    /* so that we can directly set them, before tif_jpeg.c compute them at */
+    /* the first strip/tile writing, which is too late, since we have already */
+    /* crystalized the directory. This way we avoid a directory rewriting */
+#if defined(BIGTIFF_SUPPORT)
+    if( nCompression == COMPRESSION_JPEG &&
+        strncmp(pszFilename, "/vsimem/gtiffdataset_jpg_tmp_",
+                strlen("/vsimem/gtiffdataset_jpg_tmp_")) != 0 &&
+        CSLTestBoolean(CSLFetchNameValueDef(papszParmList, "WRITE_JPEGTABLE_TAG", "YES")) )
+    {
+        CPLString osTmpFilename;
+        osTmpFilename.Printf("/vsimem/gtiffdataset_jpg_tmp_%p", hTIFF);
+        VSILFILE* fpTmp = NULL;
+        CPLString osTmp;
+        char** papszLocalParameters = NULL;
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                               "COMPRESS", "JPEG");
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                "JPEG_QUALITY", CSLFetchNameValue(papszParmList, "JPEG_QUALITY"));
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                "PHOTOMETRIC", CSLFetchNameValue(papszParmList, "PHOTOMETRIC"));
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                               "BLOCKYSIZE", "16");
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                "NBITS", CSLFetchNameValue(papszParmList, "NBITS"));
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                "JPEGTABLESMODE", CSLFetchNameValue(papszParmList, "JPEGTABLESMODE"));
+        TIFF* hTIFFTmp = CreateLL( osTmpFilename, 16, 16, (nBands <= 4) ? nBands : 1,
+                                   eType, 0.0, papszLocalParameters, &fpTmp, osTmp );
+        CSLDestroy(papszLocalParameters);
+        if( hTIFFTmp )
+        {
+            uint16 nPhotometric;
+            int nJpegTablesMode;
+            TIFFGetField( hTIFFTmp, TIFFTAG_PHOTOMETRIC, &(nPhotometric) );
+            TIFFGetField( hTIFFTmp, TIFFTAG_JPEGTABLESMODE, &nJpegTablesMode );
+            TIFFWriteCheck( hTIFFTmp, FALSE, "CreateLL" );
+            TIFFWriteDirectory( hTIFFTmp );
+            TIFFSetDirectory( hTIFFTmp, 0 );
+            // Now, reset quality and jpegcolormode. 
+            if(nJpegQuality > 0) 
+                TIFFSetField(hTIFFTmp, TIFFTAG_JPEGQUALITY, nJpegQuality); 
+            if( nPhotometric == PHOTOMETRIC_YCBCR 
+                && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
+                                                    "YES") ) )
+            {
+                TIFFSetField(hTIFFTmp, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+            }
+            if (nJpegTablesMode >= 0 )
+                TIFFSetField(hTIFFTmp, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode);
+
+            GByte abyZeroData[(16*16*4*3)/2];
+            memset(abyZeroData, 0, (16*16*4*3)/2);
+            int nBlockSize = 16 * 16 * ((nBands <= 4) ? nBands : 1);
+            if( nBitsPerSample == 12 )
+               nBlockSize = (nBlockSize * 3) / 2;
+            TIFFWriteEncodedStrip( hTIFFTmp, 0, abyZeroData, nBlockSize);
+
+            uint32 nJPEGTableSize = 0;
+            void* pJPEGTable = NULL;
+            if( TIFFGetField(hTIFFTmp, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable) )
+                TIFFSetField(hTIFF, TIFFTAG_JPEGTABLES, nJPEGTableSize, pJPEGTable);
+
+            float *ref;
+            if( TIFFGetField(hTIFFTmp, TIFFTAG_REFERENCEBLACKWHITE, &ref) )
+                TIFFSetField(hTIFF, TIFFTAG_REFERENCEBLACKWHITE, ref);
+
+            XTIFFClose(hTIFFTmp);
+            VSIFCloseL(fpTmp);
+        }
+        VSIUnlink(osTmpFilename);
+    }
+#endif
+
+    *pfpL = fpL;
+
+    return( hTIFF );
+}
+
+/************************************************************************/
+/*                              GuessJPEGQuality()                      */
+/*                                                                      */
+/*      Guess JPEG quality from JPEGTABLES tag.                         */
+/************************************************************************/
+
+static const GByte* GTIFFFindNextTable(const GByte* paby, GByte byMarker,
+                                       int nLen, int* pnLenTable)
+{
+    for(int i = 0; i+1 < nLen; )
+    {
+        if( paby[i] != 0xFF )
+            return NULL;
+        i ++;
+        if( paby[i] == 0xD8 )
+        {
+            i ++;
+            continue;
+        }
+        if( i+2 >= nLen )
+            return NULL;
+        int nMarkerLen = paby[i+1] * 256 + paby[i+2];
+        if( i+1+nMarkerLen >= nLen )
+            return NULL;
+        if( paby[i] == byMarker )
+        {
+            if( pnLenTable ) *pnLenTable = nMarkerLen;
+            return paby + i + 1;
+        }
+        i += 1 + nMarkerLen;
+    }
+    return NULL;
+}
+
+/* We assume that if there are several quantization tables, they are */
+/* in the same order. Which is a reasonable assumption for updating */
+/* a file generated by ourselves */
+static int GTIFFQuantizationTablesEqual(const GByte* paby1, int nLen1,
+                                        const GByte* paby2, int nLen2)
+{
+    int bFound = FALSE;
+    while(TRUE)
+    {
+        int nLenTable1 = 0;
+        int nLenTable2 = 0;
+        const GByte* paby1New = GTIFFFindNextTable(paby1, 0xDB, nLen1, &nLenTable1);
+        const GByte* paby2New = GTIFFFindNextTable(paby2, 0xDB, nLen2, &nLenTable2);
+        if( paby1New == NULL && paby2New == NULL )
+            return bFound;
+        if( paby1New == NULL && paby2New != NULL )
+            return FALSE;
+        if( paby1New != NULL && paby2New == NULL )
+            return FALSE;
+        if( nLenTable1 != nLenTable2 )
+            return FALSE;
+        if( memcmp(paby1New, paby2New, nLenTable1) != 0 )
+            return FALSE;
+        paby1New += nLenTable1;
+        paby2New += nLenTable2;
+        nLen1 -= (paby1New - paby1);
+        nLen2 -= (paby2New - paby2);
+        paby1 = paby1New;
+        paby2 = paby2New;
+        bFound = TRUE;
+    }
+}
+
+int GTiffDataset::GuessJPEGQuality(int& bOutHasQuantizationTable,
+                                   int& bOutHasHuffmanTable)
+{
+    CPLAssert( nCompression == COMPRESSION_JPEG );
+    uint32 nJPEGTableSize = 0;
+    void* pJPEGTable = NULL;
+    bOutHasQuantizationTable = FALSE;
+    bOutHasHuffmanTable = FALSE;
+    if( !TIFFGetField(hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable) )
+        return -1;
+
+    bOutHasQuantizationTable = GTIFFFindNextTable((const GByte*)pJPEGTable, 0xDB, nJPEGTableSize, NULL) != NULL;
+    bOutHasHuffmanTable = GTIFFFindNextTable((const GByte*)pJPEGTable, 0xC4, nJPEGTableSize, NULL) != NULL;
+    if( !bOutHasQuantizationTable )
+        return -1;
+
+    char** papszLocalParameters = NULL;
+    papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                            "COMPRESS", "JPEG");
+    if( nPhotometric == PHOTOMETRIC_YCBCR )
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                            "PHOTOMETRIC", "YCBCR");
+    else if( nPhotometric == PHOTOMETRIC_SEPARATED )
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                            "PHOTOMETRIC", "CMYK");
+    papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                            "BLOCKYSIZE", "16");
+    if( nBitsPerSample == 12 )
+        papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                                "NBITS", "12");
+
+    CPLString osTmpFilename;
+    osTmpFilename.Printf("/vsimem/gtiffdataset_guess_jpeg_quality_tmp_%p", this);
+
+    int nRet = -1;
+    for(int nQuality=0;nQuality<=100 && nRet < 0;nQuality++)
+    {
+        VSILFILE* fpTmp = NULL;
+        if( nQuality == 0 )
+            papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                                   "JPEG_QUALITY", "75");
+        else
+            papszLocalParameters = CSLSetNameValue(papszLocalParameters,
+                                "JPEG_QUALITY", CPLSPrintf("%d", nQuality));
 
-        panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
-        panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
-        panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        CPLString osTmp;
+        TIFF* hTIFFTmp = CreateLL( osTmpFilename, 16, 16, (nBands <= 4) ? nBands : 1,
+                                   GetRasterBand(1)->GetRasterDataType(), 0.0,
+                                   papszLocalParameters, &fpTmp, osTmp );
+        CPLPopErrorHandler();
+        if( !hTIFFTmp )
+        {
+            break;
+        }
 
-        for( int iColor = 0; iColor < nColors; iColor++ )
+        TIFFWriteCheck( hTIFFTmp, FALSE, "CreateLL" );
+        TIFFWriteDirectory( hTIFFTmp );
+        TIFFSetDirectory( hTIFFTmp, 0 );
+        // Now reset jpegcolormode. 
+        if( nPhotometric == PHOTOMETRIC_YCBCR 
+            && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
+                                                "YES") ) )
         {
-            if( eType == GDT_Byte )
-            {                
-                panTRed[iColor] = (unsigned short) (257 * iColor);
-                panTGreen[iColor] = (unsigned short) (257 * iColor);
-                panTBlue[iColor] = (unsigned short) (257 * iColor);
-            }
-            else
+            TIFFSetField(hTIFFTmp, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
+        }
+
+        GByte abyZeroData[(16*16*4*3)/2];
+        memset(abyZeroData, 0, (16*16*4*3)/2);
+        int nBlockSize = (16 * 16 * ((nBands <= 4) ? nBands : 1) * nBitsPerSample) / 8;
+        TIFFWriteEncodedStrip( hTIFFTmp, 0, abyZeroData, nBlockSize);
+
+        uint32 nJPEGTableSizeTry = 0;
+        void* pJPEGTableTry = NULL;
+        if( TIFFGetField(hTIFFTmp, TIFFTAG_JPEGTABLES,
+                         &nJPEGTableSizeTry, &pJPEGTableTry) )
+        {
+            if( GTIFFQuantizationTablesEqual((GByte*)pJPEGTable, nJPEGTableSize,
+                                             (GByte*)pJPEGTableTry, nJPEGTableSizeTry) )
             {
-                panTRed[iColor] = (unsigned short) iColor;
-                panTGreen[iColor] = (unsigned short) iColor;
-                panTBlue[iColor] = (unsigned short) iColor;
+                nRet = (nQuality == 0 ) ? 75 : nQuality;
             }
         }
-        
-        TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
-                      panTRed, panTGreen, panTBlue );
-        
-        CPLFree( panTRed );
-        CPLFree( panTGreen );
-        CPLFree( panTBlue );
+
+        XTIFFClose(hTIFFTmp);
+        VSIFCloseL(fpTmp);
     }
 
-    return( hTIFF );
+    CSLDestroy(papszLocalParameters);
+    VSIUnlink(osTmpFilename);
+
+    return nRet;
 }
 
 /************************************************************************/
@@ -8776,12 +11306,16 @@ GDALDataset *GTiffDataset::Create( const char * pszFilename,
 {
     GTiffDataset *	poDS;
     TIFF		*hTIFF;
+    VSILFILE* fpL = NULL;
+    CPLString           osTmpFilename;
 
 /* -------------------------------------------------------------------- */
 /*      Create the underlying TIFF file.                                */
 /* -------------------------------------------------------------------- */
-    hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands, 
-                      eType, 0, papszParmList );
+    hTIFF = CreateLL( pszFilename,
+                      nXSize, nYSize, nBands, 
+                      eType, 0, papszParmList, &fpL, osTmpFilename );
+    int bStreaming = (osTmpFilename.size() != 0);
 
     if( hTIFF == NULL )
         return NULL;
@@ -8791,6 +11325,19 @@ GDALDataset *GTiffDataset::Create( const char * pszFilename,
 /* -------------------------------------------------------------------- */
     poDS = new GTiffDataset();
     poDS->hTIFF = hTIFF;
+    poDS->fpL = fpL;
+    if( bStreaming )
+    {
+        poDS->bStreamingOut = TRUE;
+        poDS->osTmpFilename = osTmpFilename;
+        poDS->fpToWrite = VSIFOpenL( pszFilename, "wb" );
+        if( poDS->fpToWrite == NULL )
+        {
+            VSIUnlink(osTmpFilename);
+            delete poDS;
+            return NULL;
+        }
+    }
     poDS->poActiveDS = poDS;
     poDS->ppoActiveDSRef = &(poDS->poActiveDS);
 
@@ -8807,7 +11354,9 @@ GDALDataset *GTiffDataset::Create( const char * pszFilename,
 
     TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->nSampleFormat) );
     TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->nPlanarConfig) );
-    TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) );
+    // Weird that we need this, but otherwise we get a Valgrind warning on tiff_write_124
+    if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) ) )
+        poDS->nPhotometric = PHOTOMETRIC_MINISBLACK;
     TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->nBitsPerSample) );
     TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(poDS->nCompression) );
 
@@ -8894,6 +11443,7 @@ GDALDataset *GTiffDataset::Create( const char * pszFilename,
     poDS->nZLevel = GTiffGetZLevel(papszParmList);
     poDS->nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
     poDS->nJpegQuality = GTiffGetJpegQuality(papszParmList);
+    poDS->nJpegTablesMode = GTiffGetJpegTablesMode(papszParmList);
 
 #if !defined(BIGTIFF_SUPPORT)
 /* -------------------------------------------------------------------- */
@@ -8947,6 +11497,13 @@ GDALDataset *GTiffDataset::Create( const char * pszFilename,
         }
     }
 
+    poDS->GetDiscardLsbOption(papszParmList);
+
+    if( poDS->nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1 )
+        poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
+    else
+        poDS->SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
+
     poDS->oOvManager.Initialize( poDS, pszFilename );
 
     return( poDS );
@@ -9155,7 +11712,7 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 #endif
 
     /* Note: JPEG_DIRECT_COPY is not defined by default, because it is mainly */
-    /* usefull for debugging purposes */
+    /* useful for debugging purposes */
 #ifdef JPEG_DIRECT_COPY
     if (CSLFetchBoolean(papszCreateOptions, "JPEG_DIRECT_COPY", FALSE) &&
         GTIFF_CanDirectCopyFromJPEG(poSrcDS, papszCreateOptions))
@@ -9182,13 +11739,21 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 /* -------------------------------------------------------------------- */
 /*      Create the file.                                                */
 /* -------------------------------------------------------------------- */
+    VSILFILE* fpL = NULL;
+    CPLString osTmpFilename;
+
     hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
-                      eType, dfExtraSpaceForOverviews, papszCreateOptions );
+                      eType, dfExtraSpaceForOverviews, papszCreateOptions, &fpL, osTmpFilename );
+    int bStreaming = (osTmpFilename.size() != 0);
 
     CSLDestroy( papszCreateOptions );
+    papszCreateOptions = NULL;
 
     if( hTIFF == NULL )
+    {
+        if( bStreaming ) VSIUnlink(osTmpFilename);
         return NULL;
+    }
 
     TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
     TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample );
@@ -9214,6 +11779,23 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
+/*      Are we really producing a Grey+Alpha image?  If so, set the     */
+/*      associated alpha information.                                   */
+/* -------------------------------------------------------------------- */
+    else if( nBands == 2 && !bForcePhotometric &&
+             nCompression != COMPRESSION_JPEG &&
+             poSrcDS->GetRasterBand(1)->GetColorInterpretation()==GCI_GrayIndex &&
+             poSrcDS->GetRasterBand(2)->GetColorInterpretation()==GCI_AlphaBand)
+    {
+        uint16 v[1];
+
+        v[0] = GTiffGetAlphaValue(CSLFetchNameValue(papszOptions, "ALPHA"),
+                                  DEFAULT_ALPHA_TYPE);
+
+        TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
+        TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
+    }
+/* -------------------------------------------------------------------- */
 /*      Are we really producing an RGBA image?  If so, set the          */
 /*      associated alpha information.                                   */
 /* -------------------------------------------------------------------- */
@@ -9351,6 +11933,9 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v );
     }
 
+    // FIXME? libtiff writes extended tags in the order they are specified
+    // and not in increasing order
+
 /* -------------------------------------------------------------------- */
 /*      Transfer some TIFF specific metadata, if available.             */
 /*      The return value will tell us if we need to try again later with*/
@@ -9581,16 +12166,55 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     
     TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffCreateCopy()");
     TIFFWriteDirectory( hTIFF );
+    if( bStreaming )
+    {
+        /* We need to write twice the directory to be sure that custom */
+        /* TIFF tags are correctly sorted and that padding bytes have been */
+        /* added */
+        TIFFSetDirectory( hTIFF, 0 );
+        TIFFWriteDirectory( hTIFF );
+
+        VSIFSeekL( fpL, 0, SEEK_END );
+        int nSize = (int) VSIFTellL(fpL);
+
+        vsi_l_offset nDataLength;
+        VSIGetMemFileBuffer( osTmpFilename, &nDataLength, FALSE);
+        TIFFSetDirectory( hTIFF, 0 );
+        GTiffFillStreamableOffsetAndCount( hTIFF, nSize );
+        TIFFWriteDirectory( hTIFF );
+    }
     TIFFFlush( hTIFF );
     XTIFFClose( hTIFF );
     hTIFF = NULL;
+    VSIFCloseL(fpL);
+    fpL = NULL;
 
     if( eErr != CE_None )
     {
-        VSIUnlink( pszFilename );
+        VSIUnlink( bStreaming ? osTmpFilename.c_str() : pszFilename );
         return NULL;
     }
 
+    if( bStreaming )
+    {
+        vsi_l_offset nDataLength;
+        void* pabyBuffer = VSIGetMemFileBuffer( osTmpFilename, &nDataLength, FALSE);
+        fpL = VSIFOpenL( pszFilename, "wb" );
+        if( fpL == NULL )
+        {
+            VSIUnlink(osTmpFilename);
+            return NULL;
+        }
+        if( (int)VSIFWriteL( pabyBuffer, 1, (int)nDataLength, fpL ) != (int)nDataLength )
+        {
+            CPLError(CE_Failure, CPLE_FileIO, "Could not write %d bytes",
+                     (int)nDataLength);
+            VSIFCloseL( fpL );
+            VSIUnlink(osTmpFilename);
+            return NULL;
+        }
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Re-open as a dataset and copy over missing metadata using       */
 /*      PAM facilities.                                                 */
@@ -9598,10 +12222,18 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     GTiffDataset *poDS;
     CPLString osFileName("GTIFF_RAW:");
 
-    osFileName += pszFilename;
+    osFileName += bStreaming ? osTmpFilename.c_str() : pszFilename;
 
     GDALOpenInfo oOpenInfo( osFileName, GA_Update );
+    if( bStreaming )
+    {
+        /* In case of single strip file, there's a libtiff check that would */
+        /* issue a warning since the file hasn't the required size */
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+    }
     poDS = (GTiffDataset *) Open(&oOpenInfo);
+    if( bStreaming )
+        CPLPopErrorHandler();
     if( poDS == NULL )
     {
         oOpenInfo.eAccess = GA_ReadOnly;
@@ -9610,10 +12242,15 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     if ( poDS == NULL )
     {
-        VSIUnlink( pszFilename );
+        VSIUnlink( bStreaming ? osTmpFilename.c_str() : pszFilename );
         return NULL;
     }
 
+    if( bStreaming )
+    {
+        VSIUnlink(osTmpFilename);
+        poDS->fpToWrite = fpL;
+    }
     poDS->osProfile = pszProfile;
     poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & ~GCIF_MASK );
     poDS->papszCreationOptions = CSLDuplicate( papszOptions );
@@ -9672,15 +12309,21 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 /*      Second chance : now that we have a PAM dataset, it is possible  */
 /*      to write metadata that we couldn't be writen as TIFF tag        */
 /* -------------------------------------------------------------------- */
-    if (!bHasWrittenMDInGeotiffTAG)
+    if (!bHasWrittenMDInGeotiffTAG && !bStreaming)
         GTiffDataset::WriteMetadata( poDS, hTIFF, TRUE, pszProfile,
                                      pszFilename, papszOptions, TRUE /* don't write RPC and IMD file again */);
 
+    if( !bStreaming )
+        GTiffDataset::WriteRPC( poDS, hTIFF, TRUE, pszProfile,
+                                     pszFilename, papszOptions, TRUE /* write only in PAM AND if needed */ );
+
     /* To avoid unnecessary directory rewriting */
     poDS->bMetadataChanged = FALSE;
     poDS->bGeoTIFFInfoChanged = FALSE;
-    poDS->bForceUnsetGT = FALSE;
+    poDS->bNoDataChanged = FALSE;
+    poDS->bForceUnsetGTOrGCPs = FALSE;
     poDS->bForceUnsetProjection = FALSE;
+    poDS->bStreamingOut = bStreaming;
 
     /* We must re-set the compression level at this point, since it has */
     /* been lost a few lines above when closing the newly create TIFF file */
@@ -9690,6 +12333,8 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     poDS->nZLevel = GTiffGetZLevel(papszOptions);
     poDS->nLZMAPreset = GTiffGetLZMAPreset(papszOptions);
     poDS->nJpegQuality = GTiffGetJpegQuality(papszOptions);
+    poDS->nJpegTablesMode = GTiffGetJpegTablesMode(papszOptions);
+    poDS->GetDiscardLsbOption(papszOptions);
 
     if (nCompression == COMPRESSION_ADOBE_DEFLATE)
     {
@@ -9704,6 +12349,7 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         {
             TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, poDS->nJpegQuality );
         }
+        TIFFSetField( hTIFF, TIFFTAG_JPEGTABLESMODE, poDS->nJpegTablesMode );
     }
     else if( nCompression == COMPRESSION_LZMA)
     {
@@ -9768,7 +12414,7 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             
             /* Create a fake dataset with the source overview level so that */
             /* GDALDatasetCopyWholeRaster can cope with it */
-            GDALDataset* poSrcOvrDS = new GDALOverviewDS(poSrcDS, iOvrLevel);
+            GDALDataset* poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS, iOvrLevel, TRUE, FALSE);
             
             GDALRasterBand* poOvrBand =
                     poSrcDS->GetRasterBand(1)->GetOverview(iOvrLevel);
@@ -9850,7 +12496,8 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             {
                 eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1,
                                          pabyScanline, nXSize, 1,
-                                         GDT_Byte, nBands, NULL, poDS->nBands, 0, 1);
+                                         GDT_Byte, nBands, NULL, poDS->nBands, 0, 1,
+                                         NULL);
                 if (eErr == CE_None &&
                     TIFFWriteScanline( hTIFF, pabyScanline, j, 0) == -1)
                 {
@@ -9875,7 +12522,7 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                     eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
                                                     GF_Read, 0, j, nXSize, 1,
                                                     pabyScanline, nXSize, 1,
-                                                    GDT_Byte, 0, 0);
+                                                    GDT_Byte, 0, 0, NULL);
                     if (poDS->bTreatAsSplitBitmap)
                     {
                         for(int i=0;i<nXSize;i++)
@@ -9928,6 +12575,10 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
         if (nCompression != COMPRESSION_NONE)
             papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
+        /* For streaming with separate, we really want that bands are written */
+        /* after each other, even if the source is pixel interleaved */
+        else if( bStreaming && poDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
+            papszCopyWholeRasterOptions[0] = (char*) "INTERLEAVE=BAND";
         eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
                                             (GDALDatasetH) poDS,
                                             papszCopyWholeRasterOptions,
@@ -9936,7 +12587,7 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     
     GDALDestroyScaledProgress(pScaledData);
 
-    if (eErr == CE_None)
+    if (eErr == CE_None && !bStreaming)
     {
         if (poDS->poMaskDS)
         {
@@ -9957,7 +12608,10 @@ GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         poDS = NULL;
 
         if (CSLTestBoolean(CPLGetConfigOption("GTIFF_DELETE_ON_ERROR", "YES")))
-            VSIUnlink( pszFilename ); // should really delete more carefully.
+        {
+            if( !bStreaming )
+                VSIUnlink( pszFilename ); // should really delete more carefully.
+        }
     }
 
     return poDS;
@@ -9990,6 +12644,13 @@ const char *GTiffDataset::GetProjectionRef()
 CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
 
 {
+    if( bStreamingOut && bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify projection at that point in a streamed output file");
+        return CE_Failure;
+    }
+    
     LookForProjection();
 
     if( !EQUALN(pszNewProjection,"GEOGCS",6)
@@ -10007,10 +12668,12 @@ CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
         return CE_Failure;
     }
 
-    bForceUnsetProjection = (
-         EQUAL(pszNewProjection, "") &&
+    if ( EQUAL(pszNewProjection, "") &&
          pszProjection != NULL &&
-         !EQUAL(pszProjection, "") );
+         !EQUAL(pszProjection, "") )
+    {
+        bForceUnsetProjection = TRUE;
+    }
 
     CPLFree( pszProjection );
     pszProjection = CPLStrdup( pszNewProjection );
@@ -10042,9 +12705,16 @@ CPLErr GTiffDataset::GetGeoTransform( double * padfTransform )
 CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
 
 {
+    if( bStreamingOut && bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify geotransform at that point in a streamed output file");
+        return CE_Failure;
+    }
+
     if( GetAccess() == GA_Update )
     {
-        bForceUnsetGT = (
+        if (
             padfTransform[0] == 0.0 &&
             padfTransform[1] == 1.0 &&
             padfTransform[2] == 0.0 &&
@@ -10056,7 +12726,10 @@ CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
             adfGeoTransform[2] == 0.0 &&
             adfGeoTransform[3] == 0.0 &&
             adfGeoTransform[4] == 0.0 &&
-            adfGeoTransform[5] == 1.0) );
+            adfGeoTransform[5] == 1.0) )
+        {
+            bForceUnsetGTOrGCPs = TRUE;
+        }
 
         memcpy( adfGeoTransform, padfTransform, sizeof(double)*6 );
         bGeoTransformValid = TRUE;
@@ -10118,8 +12791,14 @@ CPLErr GTiffDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
 {
     if( GetAccess() == GA_Update )
     {
-        LoadMDAreaOrPoint();
-        bLookedForProjection = TRUE;
+        LookForProjection();
+
+        if (this->nGCPCount > 0 && nGCPCount == 0)
+            bForceUnsetGTOrGCPs = TRUE;
+        if( !EQUAL(this->pszProjection, "") &&
+                   (pszGCPProjection == NULL ||
+                   pszGCPProjection[0] == '\0') )
+            bForceUnsetProjection = TRUE;
 
         if( this->nGCPCount > 0 )
         {
@@ -10152,7 +12831,7 @@ char **GTiffDataset::GetMetadataDomainList()
 {
     return BuildMetadataDomainList(CSLDuplicate(oGTiffMDMD.GetDomainList()),
                                    TRUE,
-                                   "", "ProxyOverviewRequest", "RPC", "IMD", "SUBDATASETS", "EXIF",
+                                   "", "ProxyOverviewRequest", MD_DOMAIN_RPC, MD_DOMAIN_IMD, "SUBDATASETS", "EXIF",
                                    "xml:XMP", "COLOR_PROFILE", NULL);
 }
 
@@ -10166,11 +12845,10 @@ char **GTiffDataset::GetMetadata( const char * pszDomain )
     if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
         return GDALPamDataset::GetMetadata( pszDomain );
 
-    else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
-        LoadRPCRPB();
-
-    else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
-        LoadIMDPVL();
+    else if( pszDomain != NULL && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
+                                   EQUAL(pszDomain, MD_DOMAIN_IMD) ||
+                                   EQUAL(pszDomain, MD_DOMAIN_IMAGERY)) )
+        LoadMetadata();
     
     else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
         ScanDirectories();
@@ -10193,6 +12871,13 @@ char **GTiffDataset::GetMetadata( const char * pszDomain )
 CPLErr GTiffDataset::SetMetadata( char ** papszMD, const char *pszDomain )
 
 {
+    if( bStreamingOut && bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify metadata at that point in a streamed output file");
+        return CE_Failure;
+    }
+
     if ((papszMD != NULL) && (pszDomain != NULL) && EQUAL(pszDomain, "COLOR_PROFILE"))
         bColorProfileMetadataChanged = TRUE;
     else if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
@@ -10233,11 +12918,10 @@ const char *GTiffDataset::GetMetadataItem( const char * pszName,
     if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
         return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
 
-    else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
-        LoadRPCRPB();
-
-    else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
-        LoadIMDPVL();
+    else if( pszDomain != NULL && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
+                                   EQUAL(pszDomain, MD_DOMAIN_IMD) ||
+                                   EQUAL(pszDomain, MD_DOMAIN_IMAGERY)) )
+        LoadMetadata();
 
     else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
         ScanDirectories();
@@ -10254,6 +12938,23 @@ const char *GTiffDataset::GetMetadataItem( const char * pszName,
         LoadMDAreaOrPoint(); /* to set GDALMD_AREA_OR_POINT */
     }
 
+#ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
+    else if( pszDomain != NULL && EQUAL(pszDomain, "_DEBUG_") &&
+             pszName != NULL && EQUAL(pszName, "UNREACHED_VIRTUALMEMIO_CODE_PATH") )
+    {
+        CPLString osMissing;
+        for(int i=0;i<(int)(sizeof(anReachedVirtualMemIO)/sizeof(anReachedVirtualMemIO[0]));i++)
+        {
+            if( !anReachedVirtualMemIO[i] )
+            {
+                if( osMissing.size() ) osMissing += ",";
+                osMissing += CPLSPrintf("%d", i);
+            }
+        }
+        return (osMissing.size()) ? CPLSPrintf("%s", osMissing.c_str()) : NULL;
+    }
+#endif
+
     return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
 }
 
@@ -10266,6 +12967,13 @@ CPLErr GTiffDataset::SetMetadataItem( const char *pszName,
                                       const char *pszDomain )
 
 {
+    if( bStreamingOut && bCrystalized )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify metadata at that point in a streamed output file");
+        return CE_Failure;
+    }
+
     if ((pszDomain != NULL) && EQUAL(pszDomain, "COLOR_PROFILE"))
         bColorProfileMetadataChanged = TRUE;
     else if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
@@ -10297,190 +13005,6 @@ void *GTiffDataset::GetInternalHandle( const char * /* pszHandleName */ )
     return hTIFF;
 }
 
-
-/************************************************************************/
-/*                           FindRPBFile()                             */
-/************************************************************************/
-
-int GTiffDataset::FindRPBFile()
-{
-    osRPBFile = GDALFindAssociatedFile( osFilename, "RPB", 
-                                        oOvManager.GetSiblingFiles(), 0 );
-
-    return osRPBFile != "";
-}
-
-/************************************************************************/
-/*                           FindIMDFile()                             */
-/************************************************************************/
-
-int GTiffDataset::FindIMDFile()
-{
-    osIMDFile = GDALFindAssociatedFile( osFilename, "IMD", 
-                                        oOvManager.GetSiblingFiles(), 0 );
-
-    return osIMDFile != "";
-}
-
-/************************************************************************/
-/*                           FindPVLFile()                             */
-/************************************************************************/
-
-int GTiffDataset::FindPVLFile()
-{
-    osPVLFile = GDALFindAssociatedFile( osFilename, "PVL", 
-                                        oOvManager.GetSiblingFiles(), 0 );
-
-    return osPVLFile != "";
-}
-
-/************************************************************************/
-/*                           FindRPCFile()                             */
-/************************************************************************/
-
-int GTiffDataset::FindRPCFile()
-{
-    CPLString osSrcPath = osFilename;
-    CPLString soPt(".");
-    size_t found = osSrcPath.rfind(soPt);
-    if (found == CPLString::npos)
-        return FALSE;
-    osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
-    CPLString osTarget = osSrcPath; 
-
-    char** papszSiblingFiles = oOvManager.GetSiblingFiles();
-    if( papszSiblingFiles == NULL )
-    {
-        VSIStatBufL sStatBuf;
-
-        if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
-        {
-            osSrcPath = osFilename;
-            osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
-            osTarget = osSrcPath; 
-
-            if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
-            {
-                osSrcPath = osFilename;
-                osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
-                osTarget = osSrcPath; 
-
-                if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
-                {
-                    return FALSE;
-                }
-            }
-        }
-    }
-    else
-    {
-        int iSibling = CSLFindString( papszSiblingFiles, 
-                                    CPLGetFilename(osTarget) );
-        if( iSibling < 0 )
-            return FALSE;
-
-        osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
-        osTarget += papszSiblingFiles[iSibling];
-    }
-
-    osRPCFile = osTarget;
-    return TRUE;
-}
-
-/************************************************************************/
-/*                            LoadRPCRPB()                              */
-/************************************************************************/
-
-void GTiffDataset::LoadRPCRPB()
-{
-    if (bHasSearchedRPC)
-        return;
-
-    bHasSearchedRPC = TRUE;
-
-    char **papszRPCMD = NULL;
-    /* Read Digital Globe .RPB file */
-    if (FindRPBFile())
-        papszRPCMD = GDALLoadRPBFile( osRPBFile.c_str(), NULL );
-
-    /* Read GeoEye _rpc.txt file */
-    if(papszRPCMD == NULL && FindRPCFile())
-        papszRPCMD = GDALLoadRPCFile( osRPCFile.c_str(), NULL );
-
-    if( papszRPCMD != NULL )
-    {
-        oGTiffMDMD.SetMetadata( papszRPCMD, "RPC" );
-        CSLDestroy( papszRPCMD );
-    }
-    else
-        ReadRPCTag();
-}
-
-/************************************************************************/
-/*                            LoadIMDPVL()                              */
-/************************************************************************/
-
-void GTiffDataset::LoadIMDPVL()
-{
-    if (!bHasSearchedIMD)
-    {
-        bHasSearchedIMD = TRUE;
-
-        if (FindIMDFile())
-        {
-            char **papszIMDMD = GDALLoadIMDFile( osIMDFile.c_str(), NULL );
-
-            if( papszIMDMD != NULL )
-            {
-                papszIMDMD = CSLSetNameValue( papszIMDMD, 
-                                                "md_type", "imd" );
-                oGTiffMDMD.SetMetadata( papszIMDMD, "IMD" );
-                CSLDestroy( papszIMDMD );
-            }
-        }
-    }
-    //the imd has priority
-    if (!bHasSearchedPVL && osIMDFile.empty())
-    {
-        bHasSearchedPVL = TRUE;
-
-        if (FindPVLFile())
-        {
-            /* -------------------------------------------------------------------- */
-            /*      Read file and parse.                                            */
-            /* -------------------------------------------------------------------- */
-            CPLKeywordParser oParser;
-
-            VSILFILE *fp = VSIFOpenL( osPVLFile.c_str(), "r" );
-
-            if( fp == NULL )
-                return;
-    
-            if( !oParser.Ingest( fp ) )
-            {
-                VSIFCloseL( fp );
-                return;
-            }
-
-            VSIFCloseL( fp );
-
-            /* -------------------------------------------------------------------- */
-            /*      Consider version changing.                                      */
-            /* -------------------------------------------------------------------- */
-            char **papszPVLMD = CSLDuplicate( oParser.GetAllKeywords() );
- 
-            if( papszPVLMD != NULL )
-            {
-                papszPVLMD = CSLSetNameValue( papszPVLMD, 
-                                                "md_type", "pvl" );
-                
-                oGTiffMDMD.SetMetadata( papszPVLMD, "IMD" );
-                CSLDestroy( papszPVLMD );
-            }
-        }
-    }
-}
-
 /************************************************************************/
 /*                         LoadEXIFMetadata()                           */
 /************************************************************************/
@@ -10494,7 +13018,7 @@ void GTiffDataset::LoadEXIFMetadata()
     if (!SetDirectory())
         return;
 
-    VSILFILE* fp = (VSILFILE*) TIFFClientdata( hTIFF );
+    VSILFILE* fp = VSI_TIFFGetVSILFile(TIFFClientdata( hTIFF ));
 
     GByte          abyHeader[2];
     VSIFSeekL(fp, 0, SEEK_SET);
@@ -10529,6 +13053,46 @@ void GTiffDataset::LoadEXIFMetadata()
 }
 
 /************************************************************************/
+/*                           LoadMetadata()                             */
+/************************************************************************/
+void GTiffDataset::LoadMetadata()
+{
+    if(TRUE == bIMDRPCMetadataLoaded)
+        return;
+    bIMDRPCMetadataLoaded = TRUE;
+
+    GDALMDReaderManager mdreadermanager;
+    GDALMDReaderBase* mdreader = mdreadermanager.GetReader(osFilename,
+                                         oOvManager.GetSiblingFiles(), MDR_ANY);
+
+    if(NULL != mdreader)
+    {
+        mdreader->FillMetadata(&oGTiffMDMD);
+
+        if(mdreader->GetMetadataDomain(MD_DOMAIN_RPC) == NULL)
+        {
+            char** papszRPCMD = GTiffDatasetReadRPCTag(hTIFF);
+            if( papszRPCMD )
+            {
+                oGTiffMDMD.SetMetadata( papszRPCMD, MD_DOMAIN_RPC );
+                CSLDestroy( papszRPCMD );
+            }
+        }
+
+        papszMetadataFiles = mdreader->GetMetadataFiles();
+    }
+    else
+    {
+        char** papszRPCMD = GTiffDatasetReadRPCTag(hTIFF);
+        if( papszRPCMD )
+        {
+            oGTiffMDMD.SetMetadata( papszRPCMD, MD_DOMAIN_RPC );
+            CSLDestroy( papszRPCMD );
+        }
+    }
+}
+
+/************************************************************************/
 /*                            GetFileList()                             */
 /************************************************************************/
 
@@ -10537,17 +13101,14 @@ char **GTiffDataset::GetFileList()
 {
     char **papszFileList = GDALPamDataset::GetFileList();
 
-    LoadRPCRPB();
-    LoadIMDPVL();
-
-    if (osIMDFile.size() != 0)
-        papszFileList = CSLAddString( papszFileList, osIMDFile );
-    if (osPVLFile.size() != 0)
-        papszFileList = CSLAddString( papszFileList, osPVLFile );
-    if (osRPBFile.size() != 0)
-        papszFileList = CSLAddString( papszFileList, osRPBFile );
-    if (osRPCFile.size() != 0)
-        papszFileList = CSLAddString( papszFileList, osRPCFile );
+    LoadMetadata();
+    if(NULL != papszMetadataFiles)
+    {
+        for( int i = 0; papszMetadataFiles[i] != NULL; i++ )
+        {
+            papszFileList = CSLAddString( papszFileList, papszMetadataFiles[i] );
+        }
+    }
 
     if (osGeorefFilename.size() != 0 &&
         CSLFindString(papszFileList, osGeorefFilename) == -1)
@@ -10813,7 +13374,7 @@ static void GTiffTagExtender(TIFF *tif)
 #include <dlfcn.h>
 #endif
 
-static void* hGTiffOneTimeInitMutex = NULL;
+static CPLMutex* hGTiffOneTimeInitMutex = NULL;
 
 int GTiffOneTimeInit()
 
@@ -10938,7 +13499,7 @@ void GDALRegister_GTiff()
     if( GDALGetDriverByName( "GTiff" ) == NULL )
     {
         GDALDriver	*poDriver;
-        char szCreateOptions[4556];
+        char szCreateOptions[5000];
         char szOptionalCompressItems[500];
         int bHasJPEG = FALSE, bHasLZW = FALSE, bHasDEFLATE = FALSE, bHasLZMA = FALSE;
 
@@ -11014,11 +13575,14 @@ void GDALRegister_GTiff()
 "   </Option>");
         if (bHasLZW || bHasDEFLATE)
             strcat( szCreateOptions, ""        
-"   <Option name='PREDICTOR' type='int' description='Predictor Type'/>");
+"   <Option name='PREDICTOR' type='int' description='Predictor Type (1=default, 2=horizontal differencing, 3=floating point prediction)'/>");
+        strcat( szCreateOptions, ""
+"   <Option name='DISCARD_LSB' type='string' description='Number of least-significant bits to set to clear as a single value or comma-separated list of values for per-band values'/>" );
         if (bHasJPEG)
         {
             strcat( szCreateOptions, ""
-"   <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>" );
+"   <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>"
+"   <Option name='JPEGTABLESMODE' type='int' description='Content of JPEGTABLES tag. 0=no JPEGTABLES tag, 1=Quantization tables only, 2=Huffman tables only, 3=Both' default='1'/>" );
 #ifdef JPEG_DIRECT_COPY
             strcat( szCreateOptions, ""
 "   <Option name='JPEG_DIRECT_COPY' type='boolean' description='To copy without any decompression/recompression a JPEG source file' default='NO'/>");
@@ -11039,6 +13603,7 @@ void GDALRegister_GTiff()
 "   <Option name='TILED' type='boolean' description='Switch to tiled format'/>"
 "   <Option name='TFW' type='boolean' description='Write out world file'/>"
 "   <Option name='RPB' type='boolean' description='Write out .RPB (RPC) file'/>"
+"   <Option name='RPCTXT' type='boolean' description='Write out _RPC.TXT file'/>"
 "   <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
 "   <Option name='BLOCKYSIZE' type='int' description='Tile/Strip Height'/>"
 "   <Option name='PHOTOMETRIC' type='string-select'>"
@@ -11094,16 +13659,19 @@ void GDALRegister_GTiff()
 "   <Option name='TIFFTAG_TRANSFERFUNCTION_BLUE' type='string' description='Transfer function for blue'/>"
 "   <Option name='TIFFTAG_TRANSFERRANGE_BLACK' type='string' description='Transfer range for black'/>"
 "   <Option name='TIFFTAG_TRANSFERRANGE_WHITE' type='string' description='Transfer range for white'/>"
+"   <Option name='STREAMABLE_OUTPUT' type='boolean' default='NO' description='Enforce a mode compatible with a streamable file'/>"
 "</CreationOptionList>" );
                  
 /* -------------------------------------------------------------------- */
 /*      Set the driver details.                                         */
 /* -------------------------------------------------------------------- */
         poDriver->SetDescription( "GTiff" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoTIFF" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_gtiff.html" );
         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/tiff" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "tif" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "tif tiff" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
                                    "Byte UInt16 Int16 UInt32 Int32 Float32 "
                                    "Float64 CInt16 CInt32 CFloat32 CFloat64" );
@@ -11112,6 +13680,12 @@ void GDALRegister_GTiff()
         poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
+#ifdef INTERNAL_LIBTIFF
+        poDriver->SetMetadataItem( "LIBTIFF", "INTERNAL" );
+#else
+        poDriver->SetMetadataItem( "LIBTIFF", TIFFLIB_VERSION_STR );
+#endif
+
         poDriver->pfnOpen = GTiffDataset::Open;
         poDriver->pfnCreate = GTiffDataset::Create;
         poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
diff --git a/frmts/gtiff/gt_citation.cpp b/frmts/gtiff/gt_citation.cpp
index fc937a5..80470cf 100644
--- a/frmts/gtiff/gt_citation.cpp
+++ b/frmts/gtiff/gt_citation.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gt_citation.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gt_citation.cpp 28263 2014-12-29 22:00:08Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Implements special parsing of Imagine citation strings, and
@@ -34,8 +34,9 @@
 
 #include "geovalues.h"
 #include "gt_citation.h"
+#include "gt_wkt_srs_priv.h"
 
-CPL_CVSID("$Id: gt_citation.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gt_citation.cpp 28263 2014-12-29 22:00:08Z rouault $");
 
 static const char *apszUnitMap[] = {
     "meters", "1.0",
@@ -317,7 +318,7 @@ void SetLinearUnitCitation(GTIF* psGTIF, char* pszLinearUOMName)
     char szName[512];
     CPLString osCitation;
     int n = 0;
-    if( GTIFKeyGet( psGTIF, PCSCitationGeoKey, szName, 0, sizeof(szName) ) )
+    if( GDALGTIFKeyGetASCII( psGTIF, PCSCitationGeoKey, szName, 0, sizeof(szName) ) )
         n = strlen(szName);
     if(n>0)
     {
@@ -348,7 +349,7 @@ void SetGeogCSCitation(GTIF * psGTIF, OGRSpatialReference *poSRS, char* angUnitN
     char szName[256];
     CPLString osCitation;
     size_t n = 0;
-    if( GTIFKeyGet( psGTIF, GeogCitationGeoKey, szName, 0, sizeof(szName) ) )
+    if( GDALGTIFKeyGetASCII( psGTIF, GeogCitationGeoKey, szName, 0, sizeof(szName) ) )
         n = strlen(szName);
     if (n == 0)
         return;
@@ -463,13 +464,12 @@ OGRBoolean SetCitationToSRS(GTIF* hGTIF, char* szCTString, int nCTStringLen,
             {
                 if( EQUALN(apszUnitMap[i], ctNames[CitLUnitsName], size) )
                 {
-                    unitSize = atof(apszUnitMap[i+1]);
+                    unitSize = CPLAtof(apszUnitMap[i+1]);
                     break;
                 }
             }
             if( unitSize == 0.0 )
-                GTIFKeyGet(hGTIF, ProjLinearUnitSizeGeoKey, &unitSize, 0,
-                           sizeof(unitSize) );
+                GDALGTIFKeyGetDOUBLE(hGTIF, ProjLinearUnitSizeGeoKey, &unitSize, 0, 1 );
             poSRS->SetLinearUnits( ctNames[CitLUnitsName], unitSize);
             *linearUnitIsSet = TRUE;
         }
@@ -571,7 +571,7 @@ OGRBoolean CheckCitationKeyForStatePlaneUTM(GTIF* hGTIF, GTIFDefn* psDefn, OGRSp
     units[0] = '\0';
 
     OGRBoolean hasUnits = FALSE;
-    if( GTIFKeyGet( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) ) )
+    if( GDALGTIFKeyGetASCII( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) ) )
     {
         CPLString osLCCT = szCTString;
 
@@ -658,7 +658,7 @@ OGRBoolean CheckCitationKeyForStatePlaneUTM(GTIF* hGTIF, GTIFDefn* psDefn, OGRSp
 
     /* check PCSCitationGeoKey if it exists */
     szCTString[0] = '\0';
-    if( hGTIF && GTIFKeyGet( hGTIF, PCSCitationGeoKey, szCTString, 0, sizeof(szCTString)) )  
+    if( hGTIF && GDALGTIFKeyGetASCII( hGTIF, PCSCitationGeoKey, szCTString, 0, sizeof(szCTString)) )  
     {
         /* For tif created by LEICA(ERDAS), ESRI state plane pe string was used and */
         /* the state plane zone is given in PCSCitation. Therefore try Esri pe string first. */
diff --git a/frmts/gtiff/gt_jpeg_copy.cpp b/frmts/gtiff/gt_jpeg_copy.cpp
index aa684f3..97b98dc 100644
--- a/frmts/gtiff/gt_jpeg_copy.cpp
+++ b/frmts/gtiff/gt_jpeg_copy.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gt_jpeg_copy.cpp 27899 2014-10-23 13:36:59Z rouault $
+ * $Id: gt_jpeg_copy.cpp 28213 2014-12-25 00:42:13Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Specialized copy of JPEG content into TIFF.
@@ -31,9 +31,9 @@
 #include "gt_jpeg_copy.h"
 
 /* Note: JPEG_DIRECT_COPY is not defined by default, because it is mainly */
-/* usefull for debugging purposes */
+/* useful for debugging purposes */
 
-CPL_CVSID("$Id: gt_jpeg_copy.cpp 27899 2014-10-23 13:36:59Z rouault $");
+CPL_CVSID("$Id: gt_jpeg_copy.cpp 28213 2014-12-25 00:42:13Z rouault $");
 
 #if defined(JPEG_DIRECT_COPY) || defined(HAVE_LIBJPEG)
 
@@ -339,6 +339,7 @@ static void GTIFF_ErrorExitJPEG(j_common_ptr cinfo)
 /*                      GTIFF_Set_TIFFTAG_JPEGTABLES()                  */
 /************************************************************************/
 
+static
 void GTIFF_Set_TIFFTAG_JPEGTABLES(TIFF* hTIFF,
                                   jpeg_decompress_struct& sDInfo,
                                   jpeg_compress_struct& sCInfo)
@@ -346,8 +347,27 @@ void GTIFF_Set_TIFFTAG_JPEGTABLES(TIFF* hTIFF,
     char szTmpFilename[128];
     sprintf(szTmpFilename, "/vsimem/tables_%p", &sDInfo);
     VSILFILE* fpTABLES = VSIFOpenL(szTmpFilename, "wb+");
+    
+    uint16  nPhotometric;
+    TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric );
 
     jpeg_vsiio_dest( &sCInfo, fpTABLES );
+
+    // Avoid unnecessary tables to be emitted
+    if( nPhotometric != PHOTOMETRIC_YCBCR )
+    {
+        JQUANT_TBL* qtbl;
+        JHUFF_TBL* htbl;
+        qtbl = sCInfo.quant_tbl_ptrs[1];
+        if (qtbl != NULL)
+            qtbl->sent_table = TRUE;
+        htbl = sCInfo.dc_huff_tbl_ptrs[1];
+        if (htbl != NULL)
+            htbl->sent_table = TRUE;
+        htbl = sCInfo.ac_huff_tbl_ptrs[1];
+        if (htbl != NULL)
+            htbl->sent_table = TRUE;
+    }
     jpeg_write_tables( &sCInfo );
 
     VSIFCloseL(fpTABLES);
@@ -486,7 +506,8 @@ CPLErr GTIFF_CopyFromJPEG_WriteAdditionalTags(TIFF* hTIFF,
 static CPLErr GTIFF_CopyBlockFromJPEG(TIFF* hTIFF,
                                       jpeg_decompress_struct& sDInfo,
                                       int iX, int iY,
-                                      int nXBlocks, CPL_UNUSED int nYBlocks,
+                                      int nXBlocks,
+                                      CPL_UNUSED int nYBlocks,
                                       int nXSize, int nYSize,
                                       int nBlockXSize, int nBlockYSize,
                                       int iMCU_sample_width, int iMCU_sample_height,
@@ -724,10 +745,12 @@ CPLErr GTIFF_CopyFromJPEG(GDALDataset* poDS, GDALDataset* poSrcDS,
 /* -------------------------------------------------------------------- */
     struct jpeg_error_mgr sJErr;
     struct jpeg_decompress_struct sDInfo;
+    memset(&sDInfo, 0, sizeof(sDInfo));
     jmp_buf setjmp_buffer;
     if (setjmp(setjmp_buffer))
     {
         VSIFCloseL(fpJPEG);
+        jpeg_destroy_decompress(&sDInfo);
         return CE_Failure;
     }
 
diff --git a/frmts/gtiff/gt_overview.cpp b/frmts/gtiff/gt_overview.cpp
index df75ecb..fc845bf 100644
--- a/frmts/gtiff/gt_overview.cpp
+++ b/frmts/gtiff/gt_overview.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gt_overview.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gt_overview.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Code to build overviews of external databases as a TIFF file. 
@@ -37,7 +37,7 @@
 #include "gt_overview.h"
 #include "gtiff.h"
 
-CPL_CVSID("$Id: gt_overview.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gt_overview.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                         GTIFFWriteDirectory()                        */
@@ -476,6 +476,7 @@ GTIFFBuildOverviews( const char * pszFilename,
 /*      Create the file, if it does not already exist.                  */
 /* -------------------------------------------------------------------- */
     VSIStatBufL  sStatBuf;
+    VSILFILE* fpL = NULL;
 
     if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
     {
@@ -562,7 +563,11 @@ GTIFFBuildOverviews( const char * pszFilename,
         if( bCreateBigTIFF )
             CPLDebug( "GTiff", "File being created as a BigTIFF." );
 
-        hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+" );
+        fpL = VSIFOpenL( pszFilename, "w+" );
+        if( fpL == NULL )
+            hOTIFF = NULL;
+        else
+            hOTIFF = VSI_TIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+", fpL );
         if( hOTIFF == NULL )
         {
             if( CPLGetLastErrorNo() == 0 )
@@ -570,7 +575,8 @@ GTIFFBuildOverviews( const char * pszFilename,
                           "Attempt to create new tiff file `%s'\n"
                           "failed in VSI_TIFFOpen().\n",
                           pszFilename );
-
+            if( fpL != NULL )
+                VSIFCloseL(fpL);
             return CE_Failure;
         }
     }
@@ -579,7 +585,11 @@ GTIFFBuildOverviews( const char * pszFilename,
 /* -------------------------------------------------------------------- */
     else 
     {
-        hOTIFF = VSI_TIFFOpen( pszFilename, "r+" );
+        fpL = VSIFOpenL( pszFilename, "r+" );
+        if( fpL == NULL )
+            hOTIFF = NULL;
+        else
+            hOTIFF = VSI_TIFFOpen( pszFilename, "r+", fpL );
         if( hOTIFF == NULL )
         {
             if( CPLGetLastErrorNo() == 0 )
@@ -587,7 +597,8 @@ GTIFFBuildOverviews( const char * pszFilename,
                           "Attempt to create new tiff file `%s'\n"
                           "failed in VSI_TIFFOpen().\n",
                           pszFilename );
-
+            if( fpL != NULL )
+                VSIFCloseL(fpL);
             return CE_Failure;
         }
     }
@@ -668,6 +679,8 @@ GTIFFBuildOverviews( const char * pszFilename,
     }
 
     XTIFFClose( hOTIFF );
+    VSIFCloseL(fpL);
+    fpL = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Open the overview dataset so that we can get at the overview    */
@@ -702,7 +715,10 @@ GTIFFBuildOverviews( const char * pszFilename,
         nPlanarConfig == PLANARCONFIG_CONTIG &&
         GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
         papoBandList[0]->GetColorTable() == NULL &&
-        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
+        (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") ||
+         EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
+         EQUAL(pszResampling, "CUBICSPLINE") || EQUAL(pszResampling, "LANCZOS") ||
+         EQUAL(pszResampling, "BILINEAR")))
     {
         /* In the case of pixel interleaved compressed overviews, we want to generate */
         /* the overviews for all the bands block by block, and not band after band, */
diff --git a/frmts/gtiff/gt_wkt_srs.cpp b/frmts/gtiff/gt_wkt_srs.cpp
index 4f6e8bd..209625b 100644
--- a/frmts/gtiff/gt_wkt_srs.cpp
+++ b/frmts/gtiff/gt_wkt_srs.cpp
@@ -1,10 +1,9 @@
 /******************************************************************************
- * $Id: gt_wkt_srs.cpp 27182 2014-04-14 20:03:08Z rouault $
+ * $Id: gt_wkt_srs.cpp 29049 2015-04-29 15:54:12Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Implements translation between GeoTIFF normalized projection
- *           definitions and OpenGIS WKT SRS format.  This code is intended to
- *           be moved into libgeotiff someday if possible.
+ *           definitions and OpenGIS WKT SRS format.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -44,8 +43,10 @@
 #include "gt_wkt_srs.h"
 #include "gt_wkt_srs_for_gdal.h"
 #include "gt_citation.h"
+#include "gt_wkt_srs_priv.h"
+#include "gtiff.h"
 
-CPL_CVSID("$Id: gt_wkt_srs.cpp 27182 2014-04-14 20:03:08Z rouault $")
+CPL_CVSID("$Id: gt_wkt_srs.cpp 29049 2015-04-29 15:54:12Z rouault $")
 
 #define ProjLinearUnitsInterpCorrectGeoKey   3059
 
@@ -58,9 +59,10 @@ CPL_CVSID("$Id: gt_wkt_srs.cpp 27182 2014-04-14 20:03:08Z rouault $")
 #endif
 
 CPL_C_START
-void CPL_DLL LibgeotiffOneTimeInit();
-void    LibgeotiffOneTimeCleanupMutex();
-
+#ifndef INTERNAL_LIBGEOTIFF
+void CPL_DLL gtSetCSVFilenameHook( const char *(*)(const char *) );
+#define SetCSVFilenameHook gtSetCSVFilenameHook
+#endif
 CPL_C_END
 
 // To remind myself not to use CPLString in this file!
@@ -90,7 +92,7 @@ static const char *papszDatumEquiv[] =
 /*                       LibgeotiffOneTimeInit()                        */
 /************************************************************************/
 
-static void* hMutex = NULL;
+static CPLMutex* hMutex = NULL;
 
 void LibgeotiffOneTimeInit() 
 {
@@ -209,11 +211,11 @@ static void WKTMassageDatum( char ** ppszDatum )
 /************************************************************************/
 
 /* For example:
-   GTCitationGeoKey (Ascii,215): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 27182 $ $Date: 2014-04-14 13:03:08 -0700 (Mon, 14 Apr 2014) $\nProjection Name = UTM\nUnits = meters\nGeoTIFF Units = meters"
+   GTCitationGeoKey (Ascii,215): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 29049 $ $Date: 2015-04-29 08:54:12 -0700 (Wed, 29 Apr 2015) $\nProjection Name = UTM\nUnits = meters\nGeoTIFF Units = meters"
 
-   GeogCitationGeoKey (Ascii,267): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 27182 $ $Date: 2014-04-14 13:03:08 -0700 (Mon, 14 Apr 2014) $\nUnable to match Ellipsoid (Datum) to a GeographicTypeGeoKey value\nEllipsoid = Clarke 1866\nDatum = NAD27 (CONUS)"
+   GeogCitationGeoKey (Ascii,267): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 29049 $ $Date: 2015-04-29 08:54:12 -0700 (Wed, 29 Apr 2015) $\nUnable to match Ellipsoid (Datum) to a GeographicTypeGeoKey value\nEllipsoid = Clarke 1866\nDatum = NAD27 (CONUS)"
 
-   PCSCitationGeoKey (Ascii,214): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 27182 $ $Date: 2014-04-14 13:03:08 -0700 (Mon, 14 Apr 2014) $\nUTM Zone 10N\nEllipsoid = Clarke 1866\nDatum = NAD27 (CONUS)"
+   PCSCitationGeoKey (Ascii,214): "IMAGINE GeoTIFF Support\nCopyright 1991 - 2001 by ERDAS, Inc. All Rights Reserved\n@(#)$RCSfile$ $Revision: 29049 $ $Date: 2015-04-29 08:54:12 -0700 (Wed, 29 Apr 2015) $\nUTM Zone 10N\nEllipsoid = Clarke 1866\nDatum = NAD27 (CONUS)"
  
 */
 
@@ -252,6 +254,66 @@ static void GTIFCleanupImagineNames( char *pszCitation )
 }
 
 /************************************************************************/
+/*                       GDALGTIFKeyGet()                               */
+/************************************************************************/
+
+static int GDALGTIFKeyGet( GTIF *hGTIF, geokey_t key,
+                           void* pData,
+                           int nIndex,
+                           int nCount,
+                           tagtype_t expected_tagtype )
+{
+    tagtype_t tagtype;
+    if( !GTIFKeyInfo(hGTIF, key, NULL, &tagtype) )
+        return 0;
+    if( tagtype != expected_tagtype )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Expected key %s to be of type %s. Got %s",
+                 GTIFKeyName(key), GTIFTypeName(expected_tagtype), GTIFTypeName(tagtype));
+        return 0;
+    }
+    return GTIFKeyGet( hGTIF, key, pData, nIndex, nCount );
+}
+
+/************************************************************************/
+/*                       GDALGTIFKeyGetASCII()                          */
+/************************************************************************/
+
+int GDALGTIFKeyGetASCII( GTIF *hGTIF, geokey_t key,
+                                char* szStr,
+                                int nIndex,
+                                int szStrMaxLen )
+{
+    CPLAssert(nIndex == 0);
+    return GDALGTIFKeyGet(hGTIF, key, szStr, nIndex, szStrMaxLen, TYPE_ASCII);
+}
+
+/************************************************************************/
+/*                       GDALGTIFKeyGetSHORT()                          */
+/************************************************************************/
+
+int GDALGTIFKeyGetSHORT( GTIF *hGTIF, geokey_t key,
+                                short* pnVal,
+                                int nIndex,
+                                int nCount )
+{
+    return GDALGTIFKeyGet(hGTIF, key, pnVal, nIndex, nCount, TYPE_SHORT);
+}
+
+/************************************************************************/
+/*                        GDALGTIFKeyGetDOUBLE()                        */
+/************************************************************************/
+
+int GDALGTIFKeyGetDOUBLE( GTIF *hGTIF, geokey_t key,
+                                 double* pdfVal,
+                                 int nIndex,
+                                 int nCount )
+{
+    return GDALGTIFKeyGet(hGTIF, key, pdfVal, nIndex, nCount, TYPE_DOUBLE);
+}
+
+/************************************************************************/
 /*                          GTIFGetOGISDefn()                           */
 /************************************************************************/
 
@@ -285,10 +347,22 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
         char    szPeStr[2400];
 
         /** check if there is a pe string citation key **/
-        if( GTIFKeyGet( hGTIF, PCSCitationGeoKey, szPeStr, 0, sizeof(szPeStr) ) &&
+        if( GDALGTIFKeyGetASCII( hGTIF, PCSCitationGeoKey, szPeStr, 0, sizeof(szPeStr) ) &&
             strstr(szPeStr, "ESRI PE String = " ) )
         {
             pszWKT = CPLStrdup( szPeStr + strlen("ESRI PE String = ") );
+
+            if( strstr(pszWKT, "PROJCS[\"WGS_1984_Web_Mercator_Auxiliary_Sphere\"") )
+            {
+                oSRS.SetFromUserInput(pszWKT);
+                oSRS.SetExtension( "PROJCS", "PROJ4",  
+                                   "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs" ); 
+                oSRS.FixupOrdering();
+                CPLFree(pszWKT);
+                pszWKT = NULL;
+                oSRS.exportToWkt(&pszWKT);
+            }
+
             return pszWKT;
         }
         else
@@ -305,9 +379,9 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
             {
                 // Handle citation.
                 strcpy( szPCSName, "unnamed" );
-                if( !GTIFKeyGet( hGTIF, GTCitationGeoKey, szPCSName, 
+                if( !GDALGTIFKeyGetASCII( hGTIF, GTCitationGeoKey, szPCSName, 
                                  0, sizeof(szPCSName) ) )
-                    GTIFKeyGet( hGTIF, GeogCitationGeoKey, szPCSName, 
+                    GDALGTIFKeyGetASCII( hGTIF, GeogCitationGeoKey, szPCSName, 
                                 0, sizeof(szPCSName) );
 
                 GTIFCleanupImagineNames( szPCSName );
@@ -340,9 +414,9 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
         char    szName[300];
 
         strcpy( szName, "unnamed" );
-        if( !GTIFKeyGet( hGTIF, GTCitationGeoKey, szName, 
+        if( !GDALGTIFKeyGetASCII( hGTIF, GTCitationGeoKey, szName, 
                          0, sizeof(szName) ) )
-            GTIFKeyGet( hGTIF, GeogCitationGeoKey, szName, 
+            GDALGTIFKeyGetASCII( hGTIF, GeogCitationGeoKey, szName, 
                         0, sizeof(szName) );
 
         oSRS.SetGeocCS( szName );
@@ -412,7 +486,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
     short bLinearUnitsMarkedCorrect = FALSE;
     
-    GTIFKeyGet(hGTIF, (geokey_t) ProjLinearUnitsInterpCorrectGeoKey, 
+    GDALGTIFKeyGetSHORT(hGTIF, (geokey_t) ProjLinearUnitsInterpCorrectGeoKey, 
                &bLinearUnitsMarkedCorrect, 0, 1);
 
     if( EQUAL(pszLinearUnits,"BROKEN") 
@@ -433,7 +507,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
                     && psDefn->UOMLengthInMeters != 1.0 )
                 {
                     psDefn->ProjParm[iParm] /= psDefn->UOMLengthInMeters;
-                    CPLDebug( "GTIFF", "converting geokey to accomodate old broken file due to GTIFF_LINEAR_UNITS=BROKEN setting." );
+                    CPLDebug( "GTIFF", "converting geokey to accommodate old broken file due to GTIFF_LINEAR_UNITS=BROKEN setting." );
                 }
                 break;
 
@@ -464,7 +538,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
 
             oSRS.SetAuthority( "PROJCS", "EPSG", psDefn->PCS );
         }
-        else if(hGTIF && GTIFKeyGet( hGTIF, PCSCitationGeoKey, szCTString, 0, 
+        else if(hGTIF && GDALGTIFKeyGetASCII( hGTIF, PCSCitationGeoKey, szCTString, 0, 
                                      sizeof(szCTString)) )  
         {
             if (!SetCitationToSRS(hGTIF, szCTString, sizeof(szCTString),
@@ -475,7 +549,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
         {
             if( hGTIF )
             {
-                GTIFKeyGet( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) );
+                GDALGTIFKeyGetASCII( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) );
                 if(!SetCitationToSRS(hGTIF, szCTString, sizeof(szCTString),
                                      GTCitationGeoKey, &oSRS, &linearUnitIsSet))
                     oSRS.SetNode( "PROJCS", szCTString );
@@ -496,7 +570,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
 
         /* Handle ESRI PE string in citation */
         szCTString[0] = '\0';
-        if( hGTIF && GTIFKeyGet( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) ) )
+        if( hGTIF && GDALGTIFKeyGetASCII( hGTIF, GTCitationGeoKey, szCTString, 0, sizeof(szCTString) ) )
             SetCitationToSRS(hGTIF, szCTString, sizeof(szCTString), GTCitationGeoKey, &oSRS, &linearUnitIsSet);
     }
     
@@ -514,7 +588,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
     
     if( !GTIFGetGCSInfo( psDefn->GCS, &pszGeogName, NULL, NULL, NULL )
         && hGTIF != NULL 
-        && GTIFKeyGet( hGTIF, GeogCitationGeoKey, szGCSName, 0, 
+        && GDALGTIFKeyGetASCII( hGTIF, GeogCitationGeoKey, szGCSName, 0, 
                        sizeof(szGCSName)) )
     {
         GetGeogCSFromCitation(szGCSName, sizeof(szGCSName),
@@ -538,8 +612,8 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
     }
     else
     {
-        GTIFKeyGet(hGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 );
-        GTIFKeyGet(hGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening, 0, 1 );
+        GDALGTIFKeyGetDOUBLE(hGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 );
+        GDALGTIFKeyGetDOUBLE(hGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening, 0, 1 );
     }
     if( !pszPMName )
     {
@@ -547,7 +621,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
         GTIFToCPLRecycleString( &pszPMName );
     }
     else
-        GTIFKeyGet(hGTIF, GeogPrimeMeridianLongGeoKey, &(psDefn->PMLongToGreenwich), 0, 1 );
+        GDALGTIFKeyGetDOUBLE(hGTIF, GeogPrimeMeridianLongGeoKey, &(psDefn->PMLongToGreenwich), 0, 1 );
     
     if( !pszAngularUnits )
     {
@@ -559,7 +633,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
     }
     else
     {
-        GTIFKeyGet(hGTIF, GeogAngularUnitSizeGeoKey, &(psDefn->UOMAngleInDegrees), 0, 1 );
+        GDALGTIFKeyGetDOUBLE(hGTIF, GeogAngularUnitSizeGeoKey, &(psDefn->UOMAngleInDegrees), 0, 1 );
         aUnitGot = TRUE;
     }
 
@@ -577,7 +651,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
     else if( dfInvFlattening == 0.0 && ((psDefn->SemiMinor / psDefn->SemiMajor) < 0.99999999999999999
                                         || (psDefn->SemiMinor / psDefn->SemiMajor) > 1.00000000000000001 ) )
     {
-        dfInvFlattening = -1.0 / (psDefn->SemiMinor/psDefn->SemiMajor - 1.0);
+        dfInvFlattening = OSRCalcInvFlattening(psDefn->SemiMajor,psDefn->SemiMinor);
 
         /* Take official inverse flattening definition in the WGS84 case */
         if (fabs(dfSemiMajor-SRS_WGS84_SEMIMAJOR) < 1e-10 &&
@@ -632,9 +706,40 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
 #endif
         
 /* ==================================================================== */
+/*      Try to import PROJCS from ProjectedCSTypeGeoKey if we           */
+/*      have essentially only it. We could relax a bit the constraints  */
+/*      but that should do for now. This may mask shortcomings in the   */
+/*      libgeotiff GTIFGetDefn() function.                              */
+/* ==================================================================== */
+    short tmp;
+    int bGotFromEPSG = FALSE;
+    if( psDefn->Model == ModelTypeProjected &&
+        psDefn->PCS != KvUserDefined &&
+        GDALGTIFKeyGetSHORT(hGTIF, ProjectionGeoKey, &tmp, 0, 1  ) == 0 &&
+        GDALGTIFKeyGetSHORT(hGTIF, ProjCoordTransGeoKey, &tmp, 0, 1  ) == 0 &&
+        GDALGTIFKeyGetSHORT(hGTIF, GeographicTypeGeoKey, &tmp, 0, 1  ) == 0 &&
+        GDALGTIFKeyGetSHORT(hGTIF, GeogGeodeticDatumGeoKey, &tmp, 0, 1  ) == 0 &&
+        GDALGTIFKeyGetSHORT(hGTIF, GeogEllipsoidGeoKey, &tmp, 0, 1  ) == 0 &&
+        CSLTestBoolean(CPLGetConfigOption("GTIFF_IMPORT_FROM_EPSG", "YES")) )
+    {
+        // Save error state as importFromEPSGA() will call CPLReset()
+        int errNo = CPLGetLastErrorNo();
+        CPLErr eErr = CPLGetLastErrorType();
+        const char* pszTmp = CPLGetLastErrorMsg();
+        char* pszLastErrorMsg = CPLStrdup(pszTmp ? pszTmp : "");
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        OGRErr eImportErr = oSRS.importFromEPSG(psDefn->PCS);
+        CPLPopErrorHandler();
+        // Restore error state
+        CPLErrorSetState( eErr, errNo, pszLastErrorMsg);
+        CPLFree(pszLastErrorMsg);
+        bGotFromEPSG = (eImportErr == OGRERR_NONE);
+    }
+        
+/* ==================================================================== */
 /*      Handle projection parameters.                                   */
 /* ==================================================================== */
-    if( psDefn->Model == ModelTypeProjected )
+    if( psDefn->Model == ModelTypeProjected && !bGotFromEPSG )
     {
 /* -------------------------------------------------------------------- */
 /*      Make a local copy of parms, and convert back into the           */
@@ -657,8 +762,8 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
             adfParm[2] *= psDefn->UOMAngleInDegrees;
             adfParm[3] *= psDefn->UOMAngleInDegrees; 
         }
-        int unitCode = 0;
-        GTIFKeyGet(hGTIF, ProjLinearUnitsGeoKey, &unitCode, 0, 1  );
+        short unitCode = 0;
+        GDALGTIFKeyGetSHORT(hGTIF, ProjLinearUnitsGeoKey, &unitCode, 0, 1  );
         if(unitCode != KvUserDefined)
         {
             adfParm[5] /= psDefn->UOMLengthInMeters;
@@ -683,10 +788,22 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
             break;
 
           case CT_Mercator:
-            oSRS.SetMercator( adfParm[0], adfParm[1],
-                              adfParm[4],
-                              adfParm[5], adfParm[6] );
-                              
+            /* If a lat_ts was specified use 2SP, otherwise use 1SP */
+            if (psDefn->ProjParmId[2] == ProjStdParallel1GeoKey)
+            {
+                if (psDefn->ProjParmId[4] == ProjScaleAtNatOriginGeoKey)
+                    CPLError( CE_Warning, CPLE_AppDefined,
+                              "Mercator projection should not define both StdParallel1 and ScaleAtNatOrigin.\n"
+                              "Using StdParallel1 and ignoring ScaleAtNatOrigin.\n" );
+                oSRS.SetMercator2SP( adfParm[2],
+                                     adfParm[0], adfParm[1],
+                                     adfParm[5], adfParm[6]);
+            }
+            else
+                oSRS.SetMercator( adfParm[0], adfParm[1],
+                                  adfParm[4],
+                                  adfParm[5], adfParm[6] );
+
             if (psDefn->Projection == 1024 || psDefn->Projection == 9841) // override hack for google mercator. 
             {
                 oSRS.SetExtension( "PROJCS", "PROJ4",  
@@ -841,6 +958,16 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
             GTIFFreeMemory( pszUnitsName );
         }
     }
+    
+    if( oSRS.IsProjected())
+    {
+        // Hack to be able to read properly what we have written for EPSG:102113 (ESRI ancient WebMercator)
+        if( EQUAL(oSRS.GetAttrValue("PROJCS"), "WGS_1984_Web_Mercator") )
+            oSRS.importFromEPSG(102113);
+        // And for EPSG:900913
+        else if( EQUAL(oSRS.GetAttrValue("PROJCS"), "Google Maps Global Mercator") )
+            oSRS.importFromEPSG(900913);
+    }
 
 /* ==================================================================== */
 /*      Handle vertical coordinate system information if we have it.    */
@@ -855,14 +982,14 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
     char citation[2048];
 
     // Don't do anything if there is no apparent vertical information.
-    GTIFKeyGet( hGTIF, VerticalCSTypeGeoKey, &verticalCSType, 0, 1 );
-    GTIFKeyGet( hGTIF, VerticalDatumGeoKey, &verticalDatum, 0, 1 );
-    GTIFKeyGet( hGTIF, VerticalUnitsGeoKey, &verticalUnits, 0, 1 );
+    GDALGTIFKeyGetSHORT( hGTIF, VerticalCSTypeGeoKey, &verticalCSType, 0, 1 );
+    GDALGTIFKeyGetSHORT( hGTIF, VerticalDatumGeoKey, &verticalDatum, 0, 1 );
+    GDALGTIFKeyGetSHORT( hGTIF, VerticalUnitsGeoKey, &verticalUnits, 0, 1 );
 
     if( (verticalCSType != -1 || verticalDatum != -1 || verticalUnits != -1)
         && (oSRS.IsGeographic() || oSRS.IsProjected() || oSRS.IsLocal()) )
     {
-        if( !GTIFKeyGet( hGTIF, VerticalCitationGeoKey, &citation, 
+        if( !GDALGTIFKeyGetASCII( hGTIF, VerticalCitationGeoKey, citation, 
                          0, sizeof(citation) ) )
             strcpy( citation, "unknown" );
 
@@ -1055,7 +1182,7 @@ char *GTIFGetOGISDefn( GTIF *hGTIF, GTIFDefn * psDefn )
                              "uom_code", szSearchKey, CC_Integer,
                              "factor_c" ));
             if( dfFactorB != 0.0 && dfFactorC != 0.0 )
-                sprintf( szInMeters, "%.16g", dfFactorB / dfFactorC );
+                CPLsprintf( szInMeters, "%.16g", dfFactorB / dfFactorC );
             else
                 strcpy( szInMeters, "1" );
 
@@ -1455,10 +1582,14 @@ int GTIFSetFromOGISDefn( GTIF * psGTIF, const char *pszOGCWKT )
 
         GTIFKeySet(psGTIF, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1,
                    poSRS->GetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, 0.0 ) );
-        
-        GTIFKeySet(psGTIF, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetNormProjParm( SRS_PP_SCALE_FACTOR, 1.0 ) );
-        
+
+        if( EQUAL(pszProjection,SRS_PT_MERCATOR_2SP) )
+            GTIFKeySet(psGTIF, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1,
+                       poSRS->GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 ) );
+        else
+            GTIFKeySet(psGTIF, ProjScaleAtNatOriginGeoKey, TYPE_DOUBLE, 1,
+                       poSRS->GetNormProjParm( SRS_PP_SCALE_FACTOR, 1.0 ) );
+
         GTIFKeySet(psGTIF, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1,
                    poSRS->GetProjParm( SRS_PP_FALSE_EASTING, 0.0 ) );
         
@@ -1946,37 +2077,6 @@ int GTIFSetFromOGISDefn( GTIF * psGTIF, const char *pszOGCWKT )
                    poSRS->GetProjParm( SRS_PP_FALSE_NORTHING, 0.0 ) );
     }
     
-    else if( EQUAL(pszProjection,SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
-    {
-        GTIFKeySet(psGTIF, GTModelTypeGeoKey, TYPE_SHORT, 1,
-                   ModelTypeProjected);
-        GTIFKeySet(psGTIF, ProjectedCSTypeGeoKey, TYPE_SHORT, 1,
-                   KvUserDefined );
-        GTIFKeySet(psGTIF, ProjectionGeoKey, TYPE_SHORT, 1,
-                   KvUserDefined );
-
-        GTIFKeySet(psGTIF, ProjCoordTransGeoKey, TYPE_SHORT, 1, 
-                   CT_AlbersEqualArea );
-
-        GTIFKeySet(psGTIF, ProjNatOriginLatGeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetNormProjParm( SRS_PP_LATITUDE_OF_CENTER, 0.0 ) );
-
-        GTIFKeySet(psGTIF, ProjNatOriginLongGeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetNormProjParm( SRS_PP_LONGITUDE_OF_CENTER, 0.0 ) );
-        
-        GTIFKeySet(psGTIF, ProjStdParallel1GeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetNormProjParm( SRS_PP_STANDARD_PARALLEL_1, 0.0 ) );
-        
-        GTIFKeySet(psGTIF, ProjStdParallel2GeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetNormProjParm( SRS_PP_STANDARD_PARALLEL_2, 0.0 ) );
-        
-        GTIFKeySet(psGTIF, ProjFalseEastingGeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetProjParm( SRS_PP_FALSE_EASTING, 0.0 ) );
-        
-        GTIFKeySet(psGTIF, ProjFalseNorthingGeoKey, TYPE_DOUBLE, 1,
-                   poSRS->GetProjParm( SRS_PP_FALSE_NORTHING, 0.0 ) );
-    }
-    
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) )
     {
         GTIFKeySet(psGTIF, GTModelTypeGeoKey, TYPE_SHORT, 1,
@@ -2101,10 +2201,10 @@ int GTIFSetFromOGISDefn( GTIF * psGTIF, const char *pszOGCWKT )
 /* -------------------------------------------------------------------- */
     double dfFE = 0.0, dfFN = 0.0;
 
-    if( (GTIFKeyGet(psGTIF, ProjFalseEastingGeoKey, &dfFE, 0, 1)
-         || GTIFKeyGet(psGTIF, ProjFalseNorthingGeoKey, &dfFN, 0, 1)
-         || GTIFKeyGet(psGTIF, ProjFalseOriginEastingGeoKey, &dfFE, 0, 1)
-         || GTIFKeyGet(psGTIF, ProjFalseOriginNorthingGeoKey, &dfFN, 0, 1))
+    if( (GDALGTIFKeyGetDOUBLE(psGTIF, ProjFalseEastingGeoKey, &dfFE, 0, 1)
+         || GDALGTIFKeyGetDOUBLE(psGTIF, ProjFalseNorthingGeoKey, &dfFN, 0, 1)
+         || GDALGTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginEastingGeoKey, &dfFE, 0, 1)
+         || GDALGTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginNorthingGeoKey, &dfFN, 0, 1))
         && (dfFE != 0.0 || dfFN != 0.0) 
         && nUOMLengthCode != 9001 )
     {
@@ -2333,13 +2433,13 @@ CPLErr GTIFWktFromMemBuf( int nSize, unsigned char *pabyBuffer,
                           int *pnGCPCount, GDAL_GCP **ppasGCPList )
 {
     return GTIFWktFromMemBufEx(nSize, pabyBuffer, ppszWKT, padfGeoTransform,
-                               pnGCPCount, ppasGCPList, NULL);
+                               pnGCPCount, ppasGCPList, NULL, NULL);
 }
 
 CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer, 
                             char **ppszWKT, double *padfGeoTransform,
                             int *pnGCPCount, GDAL_GCP **ppasGCPList,
-                            int *pbPixelIsPoint )
+                            int *pbPixelIsPoint, char*** ppapszRPCMD )
 
 {
     bool    bPixelIsPoint = false;
@@ -2353,6 +2453,7 @@ CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer,
 /* -------------------------------------------------------------------- */
 /*      Make sure we have hooked CSVFilename().                         */
 /* -------------------------------------------------------------------- */
+    GTiffOneTimeInit(); /* for RPC tag */
     LibgeotiffOneTimeInit();
 
 /* -------------------------------------------------------------------- */
@@ -2361,19 +2462,20 @@ CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer,
     VSILFILE *fp = VSIFileFromMemBuffer( szFilename, pabyBuffer, nSize, FALSE );
     if( fp == NULL )
         return CE_Failure;
-    VSIFCloseL( fp );
 
 /* -------------------------------------------------------------------- */
 /*      Initialize access to the memory geotiff structure.              */
 /* -------------------------------------------------------------------- */
     TIFF        *hTIFF;
-    hTIFF = VSI_TIFFOpen( szFilename, "rc" );
+
+    hTIFF = VSI_TIFFOpen( szFilename, "rc", fp );
 
     if( hTIFF == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "TIFF/GeoTIFF structure is corrupt." );
         VSIUnlink( szFilename );
+        VSIFCloseL( fp );
         return CE_Failure;
     }
     
@@ -2385,7 +2487,7 @@ CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer,
 
     hGTIF = GTIFNew(hTIFF);
 
-    if( hGTIF != NULL && GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
+    if( hGTIF != NULL && GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType,
                 0, 1 ) == 1
         && nRasterType == (short) RasterPixelIsPoint )
     {
@@ -2396,6 +2498,8 @@ CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer,
     }
     if( pbPixelIsPoint )
         *pbPixelIsPoint = bPixelIsPoint;
+    if( ppapszRPCMD )
+        *ppapszRPCMD = NULL;
 
 #if LIBGEOTIFF_VERSION >= 1410
     psGTIFDefn = GTIFAllocDefn();
@@ -2491,9 +2595,18 @@ CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer,
     }
 
 /* -------------------------------------------------------------------- */
+/*      Read RPC                                                        */
+/* -------------------------------------------------------------------- */
+    if( ppapszRPCMD != NULL )
+    {
+        *ppapszRPCMD =  GTiffDatasetReadRPCTag( hTIFF );
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Cleanup.                                                        */
 /* -------------------------------------------------------------------- */
     XTIFFClose( hTIFF );
+    VSIFCloseL( fp );
 
     VSIUnlink( szFilename );
 
@@ -2513,13 +2626,13 @@ CPLErr GTIFMemBufFromWkt( const char *pszWKT, const double *padfGeoTransform,
 {
     return GTIFMemBufFromWktEx(pszWKT, padfGeoTransform,
                                nGCPCount,pasGCPList,
-                               pnSize, ppabyBuffer, FALSE);
+                               pnSize, ppabyBuffer, FALSE, NULL);
 }
 
 CPLErr GTIFMemBufFromWktEx( const char *pszWKT, const double *padfGeoTransform,
                             int nGCPCount, const GDAL_GCP *pasGCPList,
                             int *pnSize, unsigned char **ppabyBuffer,
-                            int bPixelIsPoint )
+                            int bPixelIsPoint, char** papszRPCMD )
 
 {
     TIFF        *hTIFF;
@@ -2532,17 +2645,23 @@ CPLErr GTIFMemBufFromWktEx( const char *pszWKT, const double *padfGeoTransform,
 /* -------------------------------------------------------------------- */
 /*      Make sure we have hooked CSVFilename().                         */
 /* -------------------------------------------------------------------- */
+    GTiffOneTimeInit(); /* for RPC tag */
     LibgeotiffOneTimeInit();
 
 /* -------------------------------------------------------------------- */
 /*      Initialize access to the memory geotiff structure.              */
 /* -------------------------------------------------------------------- */
-    hTIFF = VSI_TIFFOpen( szFilename, "w" );
+    VSILFILE* fpL = VSIFOpenL( szFilename, "w" );
+    if( fpL == NULL )
+        return CE_Failure;
+
+    hTIFF = VSI_TIFFOpen( szFilename, "w", fpL );
 
     if( hTIFF == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "TIFF/GeoTIFF structure is corrupt." );
+        VSIFCloseL(fpL);
         return CE_Failure;
     }
 
@@ -2668,6 +2787,14 @@ CPLErr GTIFMemBufFromWktEx( const char *pszWKT, const double *padfGeoTransform,
     } 
 
 /* -------------------------------------------------------------------- */
+/*      Write RPC                                                       */
+/* -------------------------------------------------------------------- */
+    if( papszRPCMD != NULL )
+    {
+        GTiffDatasetWriteRPCTag( hTIFF, papszRPCMD );
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Cleanup and return the created memory buffer.                   */
 /* -------------------------------------------------------------------- */
     GByte bySmallImage = 0;
@@ -2677,6 +2804,7 @@ CPLErr GTIFMemBufFromWktEx( const char *pszWKT, const double *padfGeoTransform,
     TIFFWriteDirectory( hTIFF );
 
     XTIFFClose( hTIFF );
+    VSIFCloseL(fpL);
 
 /* -------------------------------------------------------------------- */
 /*      Read back from the memory buffer.  It would be preferrable      */
diff --git a/frmts/gtiff/gt_wkt_srs_for_gdal.h b/frmts/gtiff/gt_wkt_srs_for_gdal.h
index 9f54cf6..8f69103 100644
--- a/frmts/gtiff/gt_wkt_srs_for_gdal.h
+++ b/frmts/gtiff/gt_wkt_srs_for_gdal.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gt_wkt_srs_for_gdal.h 27182 2014-04-14 20:03:08Z rouault $
+ * $Id: gt_wkt_srs_for_gdal.h 29049 2015-04-29 15:54:12Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Read/Write in-memory GeoTIFF file
@@ -44,7 +44,7 @@ CPLErr GTIFMemBufFromWktEx( const char *pszWKT,
                             const double *padfGeoTransform,
                             int nGCPCount, const GDAL_GCP *pasGCPList,
                             int *pnSize, unsigned char **ppabyBuffer,
-                            int bPixelIsPoint );
+                            int bPixelIsPoint, char** papszRPCMD );
 
 CPLErr CPL_DLL GTIFWktFromMemBuf( int nSize, unsigned char *pabyBuffer,
                           char **ppszWKT, double *padfGeoTransform,
@@ -53,7 +53,7 @@ CPLErr CPL_DLL GTIFWktFromMemBuf( int nSize, unsigned char *pabyBuffer,
 CPLErr GTIFWktFromMemBufEx( int nSize, unsigned char *pabyBuffer, 
                             char **ppszWKT, double *padfGeoTransform,
                             int *pnGCPCount, GDAL_GCP **ppasGCPList,
-                            int *pbPixelIsPoint );
+                            int *pbPixelIsPoint, char*** ppapszRPCMD );
 
 CPL_C_END;
 
diff --git a/frmts/gtiff/gt_wkt_srs_priv.h b/frmts/gtiff/gt_wkt_srs_priv.h
new file mode 100644
index 0000000..8660715
--- /dev/null
+++ b/frmts/gtiff/gt_wkt_srs_priv.h
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * $Id: gt_wkt_srs_priv.h 28263 2014-12-29 22:00:08Z rouault $
+ *
+ * Project:  GeoTIFF Driver
+ * Purpose:  Internal methods of gt_wkt_srs.cpp shared with gt_citation.cpp
+ * Author:   Even Rouault
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef GT_WKT_SRS_PRIV_H_INCLUDED
+#define GT_WKT_SRS_PRIV_H_INCLUDED
+
+#include "geotiff.h"
+
+int GDALGTIFKeyGetASCII( GTIF *hGTIF, geokey_t key,
+                                char* szStr,
+                                int nIndex,
+                                int szStrMaxLen );
+
+int GDALGTIFKeyGetSHORT( GTIF *hGTIF, geokey_t key,
+                                short* pnVal,
+                                int nIndex,
+                                int nCount );
+
+int GDALGTIFKeyGetDOUBLE( GTIF *hGTIF, geokey_t key,
+                                 double* pdfVal,
+                                 int nIndex,
+                                 int nCount );
+
+#endif // GT_WKT_SRS_PRIV_H_INCLUDED
diff --git a/frmts/gtiff/gtiff.h b/frmts/gtiff/gtiff.h
index cb2a8da..4347bc4 100644
--- a/frmts/gtiff/gtiff.h
+++ b/frmts/gtiff/gtiff.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gtiff.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gtiff.h 29049 2015-04-29 15:54:12Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  GDAL GeoTIFF support.
@@ -46,6 +46,9 @@ void    GTIFFGetOverviewBlockSize(int* pnBlockXSize, int* pnBlockYSize);
 void    GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality);
 int     GTIFFGetCompressionMethod(const char* pszValue, const char* pszVariableName);
 
+void GTiffDatasetWriteRPCTag( TIFF *hTIFF, char **papszRPCMD );
+char** GTiffDatasetReadRPCTag( TIFF *hTIFF );
+
 #define TIFFTAG_GDAL_METADATA  42112
 #define TIFFTAG_GDAL_NODATA    42113
 #define TIFFTAG_RPCCOEFFICIENT 50844
diff --git a/frmts/gtiff/libgeotiff/gdal_libgeotiff_symbol_rename.h b/frmts/gtiff/libgeotiff/gdal_libgeotiff_symbol_rename.h
index e8dbb2c..1f63ab3 100644
--- a/frmts/gtiff/libgeotiff/gdal_libgeotiff_symbol_rename.h
+++ b/frmts/gtiff/libgeotiff/gdal_libgeotiff_symbol_rename.h
@@ -6,6 +6,7 @@
 #define FindCode gdal_FindCode
 #define FindName gdal_FindName
 #define frame_dummy gdal_frame_dummy
+#define GTIFAllocDefn gdal_GTIFAllocDefn
 #define GTIFAngleStringToDD gdal_GTIFAngleStringToDD
 #define GTIFAngleToDD gdal_GTIFAngleToDD
 #define _GTIFcalloc gdal__GTIFcalloc
@@ -15,6 +16,7 @@
 #define GTIFFetchProjParms gdal_GTIFFetchProjParms
 #define GTIFFree gdal_GTIFFree
 #define _GTIFFree gdal__GTIFFree
+#define GTIFFreeDefn gdal_GTIFFreeDefn
 #define GTIFFreeMemory gdal_GTIFFreeMemory
 #define GTIFGetDatumInfo gdal_GTIFGetDatumInfo
 #define GTIFGetDefn gdal_GTIFGetDefn
diff --git a/frmts/gtiff/libgeotiff/geo_config.h b/frmts/gtiff/libgeotiff/geo_config.h
index a749082..d773b71 100644
--- a/frmts/gtiff/libgeotiff/geo_config.h
+++ b/frmts/gtiff/libgeotiff/geo_config.h
@@ -3,6 +3,11 @@
 #define GEO_CONFIG_H
 
 #include "cpl_config.h"
+#include "cpl_string.h"
+#ifdef sprintf
+#undef sprintf
+#endif
+#define sprintf CPLsprintf
 
 #ifdef RENAME_INTERNAL_LIBTIFF_SYMBOLS
 #include "gdal_libtiff_symbol_rename.h"
diff --git a/frmts/gtiff/libgeotiff/geo_names.c b/frmts/gtiff/libgeotiff/geo_names.c
index c5779a4..4c73f49 100644
--- a/frmts/gtiff/libgeotiff/geo_names.c
+++ b/frmts/gtiff/libgeotiff/geo_names.c
@@ -81,7 +81,7 @@ char *GTIFValueName(geokey_t key, int value)
 	case ProjLinearUnitsGeoKey: 
 	case GeogAngularUnitsGeoKey: 
 	case GeogAzimuthUnitsGeoKey: 
-        case VerticalUnitsGeoKey:
+    case VerticalUnitsGeoKey:
 		                      info=_geounitsValue; break;
 
    	/* put other key-dependent lists here */
@@ -157,7 +157,8 @@ int GTIFValueCode(geokey_t key, char *name)
 	case GeogLinearUnitsGeoKey: 
 	case ProjLinearUnitsGeoKey: 
 	case GeogAngularUnitsGeoKey: 
-	case GeogAzimuthUnitsGeoKey: 
+	case GeogAzimuthUnitsGeoKey:
+    case VerticalUnitsGeoKey: 
 		                      info=_geounitsValue; break;
 
    	/* put other key-dependent lists here */
diff --git a/frmts/gtiff/libgeotiff/geo_new.c b/frmts/gtiff/libgeotiff/geo_new.c
index bcd1a8e..af02bee 100644
--- a/frmts/gtiff/libgeotiff/geo_new.c
+++ b/frmts/gtiff/libgeotiff/geo_new.c
@@ -232,8 +232,7 @@ static int ReadKey(GTIF* gt, TempKeyData* tempData,
     {
         case GTIFF_LOCAL:
             /* store value into data value */
-            /* TODO: Fix strict-aliasing issue. */
-            *(pinfo_t *)(&keyptr->gk_data) = entptr->ent_val_offset;
+            memcpy(&keyptr->gk_data, &(entptr->ent_val_offset), sizeof(pinfo_t));
             break;
         case GTIFF_GEOKEYDIRECTORY:
             keyptr->gk_data = (char *)(gt->gt_short+offset);
diff --git a/frmts/gtiff/libgeotiff/geo_normalize.c b/frmts/gtiff/libgeotiff/geo_normalize.c
index 4761ea0..f88b5af 100644
--- a/frmts/gtiff/libgeotiff/geo_normalize.c
+++ b/frmts/gtiff/libgeotiff/geo_normalize.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: geo_normalize.c 2210 2012-05-16 00:18:02Z warmerdam $
+ * $Id: geo_normalize.c 2595 2014-12-27 22:59:32Z rouault $
  *
  * Project:  libgeotiff
  * Purpose:  Code to normalize PCS and other composite codes in a GeoTIFF file.
@@ -73,6 +73,8 @@
 #define EPSGTopocentricOriginLong 8835
 #define EPSGTopocentricOriginHeight 8836
 
+#define CT_Ext_Mercator_2SP     -CT_Mercator
+
 /************************************************************************/
 /*                           GTIFGetPCSInfo()                           */
 /************************************************************************/
@@ -146,7 +148,19 @@ int GTIFGetPCSInfo( int nPCSCode, char **ppszEPSGName,
                                          szSearchKey, CC_Integer );
 
         if( papszRecord == NULL )
+        {
+            static int bWarnedOrTried = FALSE;
+            if( !bWarnedOrTried )
+            {
+                FILE* f = VSIFOpen(CSVFilename( "pcs.csv" ), "rb");
+                if( f == NULL )
+                    CPLError(CE_Warning, CPLE_AppDefined, "Cannot find pcs.csv");
+                else
+                    VSIFClose(f);
+                bWarnedOrTried = TRUE;
+            }
             return FALSE;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -398,6 +412,16 @@ int GTIFGetGCSInfo( int nGCSCode, char ** ppszName,
 
     if( nDatum < 1 )
     {
+        static int bWarnedOrTried = FALSE;
+        if( !bWarnedOrTried )
+        {
+            FILE* f = VSIFOpen(CSVFilename( "gcs.csv" ), "rb");
+            if( f == NULL )
+                CPLError(CE_Warning, CPLE_AppDefined, "Cannot find gcs.csv");
+            else
+                VSIFClose(f);
+            bWarnedOrTried = TRUE;
+        }
         return FALSE;
     }
 
@@ -459,7 +483,6 @@ int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
     char	szSearchKey[24];
     double	dfSemiMajor=0.0, dfToMeters = 1.0;
     int		nUOMLength;
-    const char* pszFilename;
 
 /* -------------------------------------------------------------------- */
 /*      Try some well known ellipsoids.                                 */
@@ -515,22 +538,30 @@ int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
 /*      Get the semi major axis.                                        */
 /* -------------------------------------------------------------------- */
     sprintf( szSearchKey, "%d", nEllipseCode );
-    pszFilename = CSVFilename("ellipsoid.csv" );
-
     dfSemiMajor =
-        GTIFAtof(CSVGetField( pszFilename,
+        GTIFAtof(CSVGetField( CSVFilename("ellipsoid.csv"),
                           "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                           "SEMI_MAJOR_AXIS" ) );
 
     if( dfSemiMajor == 0.0 )
     {
+        static int bWarnedOrTried = FALSE;
+        if( !bWarnedOrTried )
+        {
+            FILE* f = VSIFOpen(CSVFilename( "ellipsoid.csv" ), "rb");
+            if( f == NULL )
+                CPLError(CE_Warning, CPLE_AppDefined, "Cannot find ellipsoid.csv");
+            else
+                VSIFClose(f);
+            bWarnedOrTried = TRUE;
+        }
         return FALSE;
     }
 
 /* -------------------------------------------------------------------- */
 /*	Get the translation factor into meters.				*/
 /* -------------------------------------------------------------------- */
-    nUOMLength = atoi(CSVGetField( pszFilename,
+    nUOMLength = atoi(CSVGetField( CSVFilename("ellipsoid.csv"),
                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                                    "UOM_CODE" ));
     GTIFGetUOMLengthInfo( nUOMLength, NULL, &dfToMeters );
@@ -547,7 +578,7 @@ int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
     if( pdfSemiMinor != NULL )
     {
         *pdfSemiMinor =
-            GTIFAtof(CSVGetField( pszFilename,
+            GTIFAtof(CSVGetField( CSVFilename("ellipsoid.csv"),
                               "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                               "SEMI_MINOR_AXIS" )) * dfToMeters;
 
@@ -556,7 +587,7 @@ int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
             double	dfInvFlattening;
             
             dfInvFlattening = 
-                GTIFAtof(CSVGetField( pszFilename,
+                GTIFAtof(CSVGetField( CSVFilename("ellipsoid.csv"),
                                   "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                                   "INV_FLATTENING" ));
             *pdfSemiMinor = dfSemiMajor * (1 - 1.0/dfInvFlattening);
@@ -568,7 +599,7 @@ int GTIFGetEllipsoidInfo( int nEllipseCode, char ** ppszName,
 /* -------------------------------------------------------------------- */
     if( ppszName != NULL )
         *ppszName =
-            CPLStrdup(CSVGetField( pszFilename,
+            CPLStrdup(CSVGetField( CSVFilename("ellipsoid.csv"),
                                    "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                                    "ELLIPSOID_NAME" ));
     
@@ -612,7 +643,19 @@ int GTIFGetPMInfo( int nPMCode, char ** ppszName, double *pdfOffset )
                           "PRIME_MERIDIAN_CODE", szSearchKey, CC_Integer,
                           "UOM_CODE" ) );
     if( nUOMAngle < 1 )
+    {
+        static int bWarnedOrTried = FALSE;
+        if( !bWarnedOrTried )
+        {
+            FILE* f = VSIFOpen(CSVFilename( "prime_meridian.csv" ), "rb");
+            if( f == NULL )
+                CPLError(CE_Warning, CPLE_AppDefined, "Cannot find prime_meridian.csv");
+            else
+                VSIFClose(f);
+            bWarnedOrTried = TRUE;
+        }
         return FALSE;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Get the PM offset.                                              */
@@ -720,6 +763,18 @@ int GTIFGetDatumInfo( int nDatumCode, char ** ppszName, short * pnEllipsoid )
 
     if( nEllipsoid < 1 )
     {
+        static int bWarnedOrTried = FALSE;
+        if( !bWarnedOrTried )
+        {
+            FILE* f = VSIFOpen(CSVFilename( "datum.csv" ), "rb");
+            if( f == NULL )
+                f = VSIFOpen(CSVFilename( "gdal_datum.csv" ), "rb");
+            if( f == NULL )
+                CPLError(CE_Warning, CPLE_AppDefined, "Cannot find datum.csv or gdal_datum.csv");
+            else
+                VSIFClose(f);
+            bWarnedOrTried = TRUE;
+        }
         return FALSE;
     }
 
@@ -968,7 +1023,7 @@ int GTIFGetUOMAngleInfo( int nUOMAngleCode,
 /*      and the GeoTIFF CT codes.                                       */
 /************************************************************************/
 
-static int EPSGProjMethodToCTProjMethod( int nEPSG )
+static int EPSGProjMethodToCTProjMethod( int nEPSG, int bReturnExtendedCTCode )
 
 {
     /* see trf_method.csv for list of EPSG codes */
@@ -988,7 +1043,10 @@ static int EPSGProjMethodToCTProjMethod( int nEPSG )
         return( CT_Mercator );  /* 1SP and 2SP not differentiated */
 
       case 9805:
-        return( CT_Mercator );  /* 1SP and 2SP not differentiated */
+        if( bReturnExtendedCTCode )
+            return( CT_Ext_Mercator_2SP );
+        else
+            return( CT_Mercator );  /* 1SP and 2SP not differentiated */
         
       /* Mercator 1SP (Spherical) For EPSG:3785 */
       case 9841:
@@ -1032,6 +1090,9 @@ static int EPSGProjMethodToCTProjMethod( int nEPSG )
       case 9816: /* tunesia mining grid has no counterpart */
         return( KvUserDefined );
 
+      case 9818:
+        return( CT_Polyconic );
+
       case 9820:
       case 1027:
         return( CT_LambertAzimEqualArea );
@@ -1041,6 +1102,12 @@ static int EPSGProjMethodToCTProjMethod( int nEPSG )
 
       case 9834:
         return( CT_CylindricalEqualArea );
+        
+      case 1028:
+      case 1029:
+      case 9823: /* spherical */
+      case 9842: /* elliptical */
+        return( CT_Equirectangular );
 
       default: /* use the EPSG code for other methods */
         return nEPSG;
@@ -1078,6 +1145,7 @@ static int SetGTParmIds( int nCTProjection,
     {
       case CT_CassiniSoldner:
       case CT_NewZealandMapGrid:
+      case CT_Polyconic:
         panProjParmId[0] = ProjNatOriginLatGeoKey;
         panProjParmId[1] = ProjNatOriginLongGeoKey;
         panProjParmId[5] = ProjFalseEastingGeoKey;
@@ -1208,6 +1276,34 @@ static int SetGTParmIds( int nCTProjection,
         panEPSGCodes[6] = EPSGFalseOriginNorthing;
         return TRUE;
 
+      case CT_Equirectangular:
+        panProjParmId[0] = ProjCenterLatGeoKey;
+        panProjParmId[1] = ProjCenterLongGeoKey;
+        panProjParmId[2] = ProjStdParallel1GeoKey;
+        panProjParmId[5] = ProjFalseEastingGeoKey;
+        panProjParmId[6] = ProjFalseNorthingGeoKey;
+
+        panEPSGCodes[0] = EPSGNatOriginLat;
+        panEPSGCodes[1] = EPSGNatOriginLong;
+        panEPSGCodes[2] = EPSGStdParallel1Lat;
+        panEPSGCodes[5] = EPSGFalseEasting;
+        panEPSGCodes[6] = EPSGFalseNorthing;
+        return TRUE;
+
+      case CT_Ext_Mercator_2SP:
+        panProjParmId[0] = ProjNatOriginLatGeoKey;
+        panProjParmId[1] = ProjNatOriginLongGeoKey;
+        panProjParmId[2] = ProjStdParallel1GeoKey;
+        panProjParmId[5] = ProjFalseEastingGeoKey;
+        panProjParmId[6] = ProjFalseNorthingGeoKey;
+
+        panEPSGCodes[0] = EPSGNatOriginLat;
+        panEPSGCodes[1] = EPSGNatOriginLong;
+        panEPSGCodes[2] = EPSGStdParallel1Lat;
+        panEPSGCodes[5] = EPSGFalseEasting;
+        panEPSGCodes[6] = EPSGFalseNorthing;
+        return TRUE;
+
       default:
         return( FALSE );
     }
@@ -1296,7 +1392,7 @@ int GTIFGetProjTRFInfo( /* COORD_OP_CODE from coordinate_operation.csv */
 /*      Initialize a definition of what EPSG codes need to be loaded    */
 /*      into what fields in adfProjParms.                               */
 /* -------------------------------------------------------------------- */
-    nCTProjMethod = EPSGProjMethodToCTProjMethod( nProjMethod );
+    nCTProjMethod = EPSGProjMethodToCTProjMethod( nProjMethod, TRUE );
     SetGTParmIds( nCTProjMethod, NULL, anEPSGCodes );
 
 /* -------------------------------------------------------------------- */
@@ -1349,6 +1445,13 @@ int GTIFGetProjTRFInfo( /* COORD_OP_CODE from coordinate_operation.csv */
                 nEPSGCode = EPSGFalseEasting;
             else if ( nCTProjMethod == CT_ObliqueMercator && nEPSGCode == EPSGProjCenterNorthing )
                 nEPSGCode = EPSGFalseNorthing;
+            /* for CT_PolarStereographic try alternate parameter codes first */
+            /* because EPSG proj method 9829 uses EPSGLatOfStdParallel instead of EPSGNatOriginLat */
+            /* and EPSGOriginLong instead of EPSGNatOriginLong */
+            else if( nCTProjMethod == CT_PolarStereographic && nEPSGCode == EPSGNatOriginLat )
+                nEPSGCode = EPSGLatOfStdParallel;
+            else if( nCTProjMethod == CT_PolarStereographic && nEPSGCode == EPSGNatOriginLong )
+                nEPSGCode = EPSGOriginLong;
             else
                 continue;
                 
@@ -1421,6 +1524,58 @@ int GTIFGetProjTRFInfo( /* COORD_OP_CODE from coordinate_operation.csv */
 }
 
 /************************************************************************/
+/*                       GTIFKeyGetInternal()                           */
+/************************************************************************/
+
+static int GTIFKeyGetInternal( GTIF *psGTIF, geokey_t key,
+                           void* pData,
+                           int nIndex,
+                           int nCount,
+                           tagtype_t expected_tagtype )
+{
+    tagtype_t tagtype;
+    if( !GTIFKeyInfo(psGTIF, key, NULL, &tagtype) )
+        return 0;
+    if( tagtype != expected_tagtype )
+    {
+        static int nErrorCount = 0;
+        if( ++nErrorCount < 100 )
+        {
+            fprintf(stderr,
+                    "Expected key %s to be of type %s. Got %s\n",
+                    GTIFKeyName(key), GTIFTypeName(expected_tagtype),
+                    GTIFTypeName(tagtype));
+        }
+        return 0;
+    }
+    return GTIFKeyGet( psGTIF, key, pData, nIndex, nCount );
+}
+
+/************************************************************************/
+/*                          GTIFKeyGetSHORT()                           */
+/************************************************************************/
+
+static int GTIFKeyGetSHORT( GTIF *psGTIF, geokey_t key,
+                                 short* pnVal,
+                                 int nIndex,
+                                 int nCount )
+{
+    return GTIFKeyGetInternal(psGTIF, key, pnVal, nIndex, nCount, TYPE_SHORT);
+}
+
+/************************************************************************/
+/*                        GDALGTIFKeyGetDOUBLE()                        */
+/************************************************************************/
+
+static int GTIFKeyGetDOUBLE( GTIF *psGTIF, geokey_t key,
+                                 double* pdfVal,
+                                 int nIndex,
+                                 int nCount )
+{
+    return GTIFKeyGetInternal(psGTIF, key, pdfVal, nIndex, nCount, TYPE_DOUBLE);
+}
+
+/************************************************************************/
 /*                         GTIFFetchProjParms()                         */
 /*                                                                      */
 /*      Fetch the projection parameters for a particular projection     */
@@ -1435,21 +1590,22 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
     double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
     double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
     int iParm;
+    int bHaveSP1, bHaveNOS;
 
 /* -------------------------------------------------------------------- */
 /*      Get the false easting, and northing if available.               */
 /* -------------------------------------------------------------------- */
-    if( !GTIFKeyGet(psGTIF, ProjFalseEastingGeoKey, &dfFalseEasting, 0, 1)
-        && !GTIFKeyGet(psGTIF, ProjCenterEastingGeoKey,
+    if( !GTIFKeyGetDOUBLE(psGTIF, ProjFalseEastingGeoKey, &dfFalseEasting, 0, 1)
+        && !GTIFKeyGetDOUBLE(psGTIF, ProjCenterEastingGeoKey,
                        &dfFalseEasting, 0, 1) 
-        && !GTIFKeyGet(psGTIF, ProjFalseOriginEastingGeoKey,
+        && !GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginEastingGeoKey,
                        &dfFalseEasting, 0, 1) )
         dfFalseEasting = 0.0;
         
-    if( !GTIFKeyGet(psGTIF, ProjFalseNorthingGeoKey, &dfFalseNorthing,0,1)
-        && !GTIFKeyGet(psGTIF, ProjCenterNorthingGeoKey,
+    if( !GTIFKeyGetDOUBLE(psGTIF, ProjFalseNorthingGeoKey, &dfFalseNorthing,0,1)
+        && !GTIFKeyGetDOUBLE(psGTIF, ProjCenterNorthingGeoKey,
                        &dfFalseNorthing, 0, 1)
-        && !GTIFKeyGet(psGTIF, ProjFalseOriginNorthingGeoKey,
+        && !GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginNorthingGeoKey,
                        &dfFalseNorthing, 0, 1) )
         dfFalseNorthing = 0.0;
         
@@ -1458,23 +1614,23 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
       case CT_Stereographic:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
                        &dfNatOriginScale, 0, 1 ) == 0 )
             dfNatOriginScale = 1.0;
             
@@ -1495,29 +1651,85 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
         break;
 
 /* -------------------------------------------------------------------- */
-      case CT_LambertConfConic_1SP:
       case CT_Mercator:
+/* -------------------------------------------------------------------- */
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey,
+                       &dfNatOriginLong, 0, 1 ) == 0
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey,
+                          &dfNatOriginLong, 0, 1 ) == 0
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey,
+                          &dfNatOriginLong, 0, 1 ) == 0 )
+            dfNatOriginLong = 0.0;
+
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey,
+                       &dfNatOriginLat, 0, 1 ) == 0
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey,
+                          &dfNatOriginLat, 0, 1 ) == 0
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey,
+                          &dfNatOriginLat, 0, 1 ) == 0 )
+            dfNatOriginLat = 0.0;
+
+
+        bHaveSP1 = GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey,
+                              &dfStdParallel1, 0, 1 );
+
+        bHaveNOS = GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
+                              &dfNatOriginScale, 0, 1 );
+
+        /* Default scale only if dfStdParallel1 isn't defined either */
+        if( !bHaveNOS && !bHaveSP1)
+        {
+            bHaveNOS = TRUE;
+            dfNatOriginScale = 1.0;
+        }
+
+        /* notdef: should transform to decimal degrees at this point */
+
+        psDefn->ProjParm[0] = dfNatOriginLat;
+        psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
+        psDefn->ProjParm[1] = dfNatOriginLong;
+        psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
+        if( bHaveSP1 )
+        {
+            psDefn->ProjParm[2] = dfStdParallel1;
+            psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
+        }
+        if( bHaveNOS )
+        {
+            psDefn->ProjParm[4] = dfNatOriginScale;
+            psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
+        }
+        psDefn->ProjParm[5] = dfFalseEasting;
+        psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
+        psDefn->ProjParm[6] = dfFalseNorthing;
+        psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
+
+        psDefn->nParms = 7;
+        break;
+
+/* -------------------------------------------------------------------- */
+      case CT_LambertConfConic_1SP:
       case CT_ObliqueStereographic:
       case CT_TransverseMercator:
       case CT_TransvMercator_SouthOriented:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
                        &dfNatOriginScale, 0, 1 ) == 0 )
             dfNatOriginScale = 1.0;
             
@@ -1541,33 +1753,33 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
       case CT_ObliqueMercator: /* hotine */
       case CT_HotineObliqueMercatorAzimuthCenter: 
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjAzimuthAngleGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjAzimuthAngleGeoKey, 
                        &dfAzimuth, 0, 1 ) == 0 )
             dfAzimuth = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjRectifiedGridAngleGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjRectifiedGridAngleGeoKey,
                        &dfRectGridAngle, 0, 1 ) == 0 )
             dfRectGridAngle = 90.0;
 
-        if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
                        &dfNatOriginScale, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
+            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
                           &dfNatOriginScale, 0, 1 ) == 0 )
             dfNatOriginScale = 1.0;
             
@@ -1595,25 +1807,25 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
       case CT_CassiniSoldner:
       case CT_Polyconic:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
                        &dfNatOriginScale, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
+            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
                           &dfNatOriginScale, 0, 1 ) == 0 )
             dfNatOriginScale = 1.0;
             
@@ -1641,19 +1853,19 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
       case CT_Orthographic:
       case CT_NewZealandMapGrid:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
@@ -1674,23 +1886,23 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
       case CT_Equirectangular:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey, 
                        &dfStdParallel1, 0, 1 ) == 0 )
             dfStdParallel1 = 0.0;
 
@@ -1715,11 +1927,11 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
       case CT_Sinusoidal:
       case CT_VanDerGrinten:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
@@ -1738,27 +1950,27 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
       case CT_PolarStereographic:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjStraightVertPoleLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStraightVertPoleLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjScaleAtNatOriginGeoKey,
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtNatOriginGeoKey,
                        &dfNatOriginScale, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjScaleAtCenterGeoKey,
+            && GTIFKeyGetDOUBLE(psGTIF, ProjScaleAtCenterGeoKey,
                           &dfNatOriginScale, 0, 1 ) == 0 )
             dfNatOriginScale = 1.0;
             
@@ -1781,27 +1993,27 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
       case CT_LambertConfConic_2SP:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey, 
                        &dfStdParallel1, 0, 1 ) == 0 )
             dfStdParallel1 = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjStdParallel2GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel2GeoKey, 
                        &dfStdParallel2, 0, 1 ) == 0 )
             dfStdParallel1 = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
@@ -1827,27 +2039,27 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
       case CT_AlbersEqualArea:
       case CT_EquidistantConic:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey, 
                        &dfStdParallel1, 0, 1 ) == 0 )
             dfStdParallel1 = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjStdParallel2GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel2GeoKey, 
                        &dfStdParallel2, 0, 1 ) == 0 )
             dfStdParallel2 = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLatGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLatGeoKey, 
                        &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLatGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLatGeoKey, 
                           &dfNatOriginLat, 0, 1 ) == 0 )
             dfNatOriginLat = 0.0;
 
@@ -1872,15 +2084,15 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
       case CT_CylindricalEqualArea:
 /* -------------------------------------------------------------------- */
-        if( GTIFKeyGet(psGTIF, ProjStdParallel1GeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjStdParallel1GeoKey, 
                        &dfStdParallel1, 0, 1 ) == 0 )
             dfStdParallel1 = 0.0;
 
-        if( GTIFKeyGet(psGTIF, ProjNatOriginLongGeoKey, 
+        if( GTIFKeyGetDOUBLE(psGTIF, ProjNatOriginLongGeoKey, 
                        &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjFalseOriginLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjFalseOriginLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0
-            && GTIFKeyGet(psGTIF, ProjCenterLongGeoKey, 
+            && GTIFKeyGetDOUBLE(psGTIF, ProjCenterLongGeoKey, 
                           &dfNatOriginLong, 0, 1 ) == 0 )
             dfNatOriginLong = 0.0;
 
@@ -1933,8 +2145,7 @@ static void GTIFFetchProjParms( GTIF * psGTIF, GTIFDefn * psDefn )
 
 /**
 @param psGTIF GeoTIFF information handle as returned by GTIFNew.
- at param psDefn Pointer to an existing GTIFDefn structure.  This structure
-does not need to have been pre-initialized at all.
+ at param psDefn Pointer to an existing GTIFDefn structure allocated by GTIFAllocDefn().
 
 @return TRUE if the function has been successful, otherwise FALSE.
 
@@ -2071,8 +2282,10 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
     psDefn->SemiMinor = 0.0;
     psDefn->PM = KvUserDefined;
     psDefn->PMLongToGreenwich = 0.0;
+#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
     psDefn->TOWGS84Count = 0;
     memset( psDefn->TOWGS84, 0, sizeof(psDefn->TOWGS84) );
+#endif
 
     psDefn->ProjCode = KvUserDefined;
     psDefn->Projection = KvUserDefined;
@@ -2106,18 +2319,18 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
 /*	Try to get the overall model type.				*/
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF,GTModelTypeGeoKey,&(psDefn->Model),0,1);
+    GTIFKeyGetSHORT(psGTIF,GTModelTypeGeoKey,&(psDefn->Model),0,1);
 
 /* -------------------------------------------------------------------- */
 /*	Extract the Geog units.  					*/
 /* -------------------------------------------------------------------- */
     nGeogUOMLinear = 9001; /* Linear_Meter */
-    GTIFKeyGet(psGTIF, GeogLinearUnitsGeoKey, &nGeogUOMLinear, 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeogLinearUnitsGeoKey, &nGeogUOMLinear, 0, 1 );
 
 /* -------------------------------------------------------------------- */
 /*      Try to get a PCS.                                               */
 /* -------------------------------------------------------------------- */
-    if( GTIFKeyGet(psGTIF,ProjectedCSTypeGeoKey, &(psDefn->PCS),0,1) == 1
+    if( GTIFKeyGetSHORT(psGTIF,ProjectedCSTypeGeoKey, &(psDefn->PCS),0,1) == 1
         && psDefn->PCS != KvUserDefined )
     {
         /*
@@ -2149,7 +2362,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      If the Proj_ code is specified directly, use that.              */
 /* -------------------------------------------------------------------- */
     if( psDefn->ProjCode == KvUserDefined )
-        GTIFKeyGet(psGTIF, ProjectionGeoKey, &(psDefn->ProjCode), 0, 1 );
+        GTIFKeyGetSHORT(psGTIF, ProjectionGeoKey, &(psDefn->ProjCode), 0, 1 );
     
     if( psDefn->ProjCode != KvUserDefined )
     {
@@ -2167,9 +2380,10 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
          * Set the GeoTIFF identity of the parameters.
          */
         psDefn->CTProjection = (short) 
-            EPSGProjMethodToCTProjMethod( psDefn->Projection );
+            EPSGProjMethodToCTProjMethod( psDefn->Projection, FALSE );
 
-        SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
+        SetGTParmIds( EPSGProjMethodToCTProjMethod(psDefn->Projection, TRUE),
+                      psDefn->ProjParmId, NULL);
         psDefn->nParms = 7;
     }
 
@@ -2177,7 +2391,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      Try to get a GCS.  If found, it will override any implied by    */
 /*      the PCS.                                                        */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeographicTypeGeoKey, &(psDefn->GCS), 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeographicTypeGeoKey, &(psDefn->GCS), 0, 1 );
     if( psDefn->GCS < 1 || psDefn->GCS >= KvUserDefined )
         psDefn->GCS = KvUserDefined;
 
@@ -2194,7 +2408,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      Handle the GCS angular units.  GeogAngularUnitsGeoKey           */
 /*      overrides the GCS or PCS setting.                               */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeogAngularUnitsGeoKey, &(psDefn->UOMAngle), 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeogAngularUnitsGeoKey, &(psDefn->UOMAngle), 0, 1 );
     if( psDefn->UOMAngle != KvUserDefined )
     {
         GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
@@ -2205,7 +2419,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      Check for a datum setting, and then use the datum to derive     */
 /*      an ellipsoid.                                                   */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeogGeodeticDatumGeoKey, &(psDefn->Datum), 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeogGeodeticDatumGeoKey, &(psDefn->Datum), 0, 1 );
 
     if( psDefn->Datum != KvUserDefined )
     {
@@ -2216,7 +2430,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      Check for an explicit ellipsoid.  Use the ellipsoid to          */
 /*      derive the ellipsoid characteristics, if possible.              */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeogEllipsoidGeoKey, &(psDefn->Ellipsoid), 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeogEllipsoidGeoKey, &(psDefn->Ellipsoid), 0, 1 );
 
     if( psDefn->Ellipsoid != KvUserDefined )
     {
@@ -2229,10 +2443,10 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      to warn if they conflict with provided information, but for     */
 /*      now we just override.                                           */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 );
-    GTIFKeyGet(psGTIF, GeogSemiMinorAxisGeoKey, &(psDefn->SemiMinor), 0, 1 );
+    GTIFKeyGetDOUBLE(psGTIF, GeogSemiMajorAxisGeoKey, &(psDefn->SemiMajor), 0, 1 );
+    GTIFKeyGetDOUBLE(psGTIF, GeogSemiMinorAxisGeoKey, &(psDefn->SemiMinor), 0, 1 );
     
-    if( GTIFKeyGet(psGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening, 
+    if( GTIFKeyGetDOUBLE(psGTIF, GeogInvFlatteningGeoKey, &dfInvFlattening, 
                    0, 1 ) == 1 )
     {
         if( dfInvFlattening != 0.0 )
@@ -2245,7 +2459,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
 /*      Get the prime meridian info.                                    */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF, GeogPrimeMeridianGeoKey, &(psDefn->PM), 0, 1 );
+    GTIFKeyGetSHORT(psGTIF, GeogPrimeMeridianGeoKey, &(psDefn->PM), 0, 1 );
 
     if( psDefn->PM != KvUserDefined )
     {
@@ -2253,7 +2467,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
     }
     else
     {
-        GTIFKeyGet(psGTIF, GeogPrimeMeridianLongGeoKey,
+        GTIFKeyGetDOUBLE(psGTIF, GeogPrimeMeridianLongGeoKey,
                    &(psDefn->PMLongToGreenwich), 0, 1 );
 
         psDefn->PMLongToGreenwich =
@@ -2264,8 +2478,10 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
 /*      Get the TOWGS84 parameters.                                     */
 /* -------------------------------------------------------------------- */
+#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
     psDefn->TOWGS84Count = 
-        GTIFKeyGet(psGTIF, GeogTOWGS84GeoKey, &(psDefn->TOWGS84), 0, 7 );
+        GTIFKeyGetDOUBLE(psGTIF, GeogTOWGS84GeoKey, psDefn->TOWGS84, 0, 7 );
+#endif
 
 /* -------------------------------------------------------------------- */
 /*      Have the projection units of measure been overridden?  We       */
@@ -2273,7 +2489,7 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
 /*      but these are very rarely not decimal degrees for actual        */
 /*      file coordinates.                                               */
 /* -------------------------------------------------------------------- */
-    GTIFKeyGet(psGTIF,ProjLinearUnitsGeoKey,&(psDefn->UOMLength),0,1);
+    GTIFKeyGetSHORT(psGTIF,ProjLinearUnitsGeoKey,&(psDefn->UOMLength),0,1);
 
     if( psDefn->UOMLength != KvUserDefined )
     {
@@ -2282,13 +2498,13 @@ int GTIFGetDefn( GTIF * psGTIF, GTIFDefn * psDefn )
     }
     else
     {
-        GTIFKeyGet(psGTIF,ProjLinearUnitSizeGeoKey,&(psDefn->UOMLengthInMeters),0,1);
+        GTIFKeyGetDOUBLE(psGTIF,ProjLinearUnitSizeGeoKey,&(psDefn->UOMLengthInMeters),0,1);
     }
 
 /* -------------------------------------------------------------------- */
 /*      Handle a variety of user defined transform types.               */
 /* -------------------------------------------------------------------- */
-    if( GTIFKeyGet(psGTIF,ProjCoordTransGeoKey,
+    if( GTIFKeyGetSHORT(psGTIF,ProjCoordTransGeoKey,
                    &(psDefn->CTProjection),0,1) == 1)
     {
         GTIFFetchProjParms( psGTIF, psDefn );
@@ -2541,6 +2757,7 @@ void GTIFPrintDefn( GTIFDefn * psDefn, FILE * fp )
 /* -------------------------------------------------------------------- */
 /*      Report TOWGS84 parameters.                                      */
 /* -------------------------------------------------------------------- */
+#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
     if( psDefn->TOWGS84Count > 0 )
     {
         int i;
@@ -2556,6 +2773,7 @@ void GTIFPrintDefn( GTIFDefn * psDefn, FILE * fp )
 
         fprintf( fp, "\n" );
     }
+#endif
 
 /* -------------------------------------------------------------------- */
 /*      Report the projection units of measure (currently just          */
@@ -2605,3 +2823,27 @@ void GTIFDeaccessCSV()
 {
     CSVDeaccess( NULL );
 }
+
+/************************************************************************/
+/*                           GTIFAllocDefn()                            */
+/*                                                                      */
+/*      This allocates a GTIF structure in such a way that the          */
+/*      calling application doesn't need to know the size and           */
+/*      initializes it appropriately.                                   */
+/************************************************************************/
+
+GTIFDefn *GTIFAllocDefn()
+{
+    return (GTIFDefn *) CPLCalloc(sizeof(GTIFDefn),1);
+}
+
+/************************************************************************/
+/*                            GTIFFreeDefn()                            */
+/*                                                                      */
+/*      Free a GTIF structure allocated by GTIFAllocDefn().             */
+/************************************************************************/
+
+void GTIFFreeDefn( GTIFDefn *defn ) 
+{
+    VSIFree( defn );
+}
diff --git a/frmts/gtiff/libgeotiff/geo_normalize.h b/frmts/gtiff/libgeotiff/geo_normalize.h
index bfaf983..60a4095 100644
--- a/frmts/gtiff/libgeotiff/geo_normalize.h
+++ b/frmts/gtiff/libgeotiff/geo_normalize.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: geo_normalize.h 1983 2011-03-10 02:10:00Z warmerdam $
+ * $Id: geo_normalize.h 2233 2012-10-09 01:33:11Z warmerdam $
  *
  * Project:  libgeotiff
  * Purpose:  Include file related to geo_normalize.c containing Code to
@@ -95,11 +95,15 @@ typedef struct {
     /** The length of the semi minor ellipse axis in meters. */
     double	SemiMinor;
 
+  /* this #if is primary intended to maintain binary compatability with older
+     versions of libgeotiff for MrSID binaries (for example) */
+#if !defined(GEO_NORMALIZE_DISABLE_TOWGS84)
     /** TOWGS84 transformation values (0/3/7) */
     short       TOWGS84Count;
 
     /** TOWGS84 transformation values */
     double      TOWGS84[7];
+#endif /* !defined(GEO_NORMALIZE_DISABLE_TOWGS84) */
 
     /** Projection id from ProjectionGeoKey.  For example Proj_UTM_11S. */
     short	ProjCode;
@@ -172,7 +176,8 @@ void CPL_DLL GTIFDeaccessCSV( void );
 
 int CPL_DLL GTIFGetDefn( GTIF *psGTIF, GTIFDefn * psDefn );
 void CPL_DLL GTIFPrintDefn( GTIFDefn *, FILE * );
-void CPL_DLL GTIFFreeDefn( GTIF * );
+GTIFDefn CPL_DLL *GTIFAllocDefn( void );
+void CPL_DLL GTIFFreeDefn( GTIFDefn * );
 
 void CPL_DLL SetCSVFilenameHook( const char *(*CSVFileOverride)(const char *) );
 
diff --git a/frmts/gtiff/libgeotiff/geo_print.c b/frmts/gtiff/libgeotiff/geo_print.c
index 0a00fc4..bc9d164 100644
--- a/frmts/gtiff/libgeotiff/geo_print.c
+++ b/frmts/gtiff/libgeotiff/geo_print.c
@@ -215,7 +215,10 @@ static void PrintKey(GeoKey *key, GTIFPrintMethod print, void *aux)
             print( GTIFValueName(keyid,*sptr), aux );
             print( "\n", aux );
         }
+        else if( sptr == NULL && count > 0 )
+            print( "****Corrupted data****\n", aux );
         else
+        {
             for (; count > 0; count-= vals_now)
             {
                 vals_now = count > 3? 3: count;
@@ -226,6 +229,7 @@ static void PrintKey(GeoKey *key, GTIFPrintMethod print, void *aux)
                 }
                 print("\n",aux);
             }
+        }
         break;
         
       default: 
@@ -455,7 +459,9 @@ static int ReadKey(GTIF *gt, GTIFReadMethod scan, void *aux)
         }
         else  /* multi-valued short - no such thing yet */
         {
-            sptr = (short *)data;
+            char* cdata;
+            memcpy(&cdata, &data, sizeof(void*));
+            sptr = (short *)cdata;
             outcount = count;
             for (; count > 0; count-= vals_now)
             {
diff --git a/frmts/gtiff/libgeotiff/geo_set.c b/frmts/gtiff/libgeotiff/geo_set.c
index 3b2066e..19adf71 100644
--- a/frmts/gtiff/libgeotiff/geo_set.c
+++ b/frmts/gtiff/libgeotiff/geo_set.c
@@ -160,9 +160,8 @@ int GTIFKeySet(GTIF *gtif, geokey_t keyID, tagtype_t type, int count,...)
         key->gk_type = type;
         key->gk_count = count;
         key->gk_size = _gtiff_size[ type ];
-        /* TODO: Make sure that the following two casts are safe. */
-        if ((geokey_t)gtif->gt_keymin > keyID) gtif->gt_keymin=keyID;
-        if ((geokey_t)gtif->gt_keymax < keyID) gtif->gt_keymax=keyID;
+        if ((geokey_t)gtif->gt_keymin > keyID)  gtif->gt_keymin=keyID;
+        if ((geokey_t)gtif->gt_keymax < keyID)  gtif->gt_keymax=keyID;
         newvalues = 1;
     }
 
diff --git a/frmts/gtiff/libgeotiff/geo_write.c b/frmts/gtiff/libgeotiff/geo_write.c
index 3fc813b..344d4bd 100644
--- a/frmts/gtiff/libgeotiff/geo_write.c
+++ b/frmts/gtiff/libgeotiff/geo_write.c
@@ -132,7 +132,7 @@ static int WriteKey(GTIF* gt, TempKeyData* tempData,
     if (count==1 && keyptr->gk_type==TYPE_SHORT)
     {
         entptr->ent_location = GTIFF_LOCAL;
-        entptr->ent_val_offset = *(pinfo_t*)&keyptr->gk_data;
+        memcpy(&(entptr->ent_val_offset), &keyptr->gk_data, sizeof(pinfo_t));
         return 1;
     }
 		  
diff --git a/frmts/gtiff/libgeotiff/geotiff.h b/frmts/gtiff/libgeotiff/geotiff.h
index 6c51d41..6bf9ba2 100644
--- a/frmts/gtiff/libgeotiff/geotiff.h
+++ b/frmts/gtiff/libgeotiff/geotiff.h
@@ -30,7 +30,7 @@
  */
 #define GvCurrentVersion   1
 
-#define LIBGEOTIFF_VERSION 1400
+#define LIBGEOTIFF_VERSION 1410
 
 #include "geo_config.h"
 #include "geokeys.h"
@@ -61,7 +61,7 @@ typedef struct _TIFFMethod TIFFMethod;
 typedef unsigned short tifftag_t;
 typedef unsigned short geocode_t;
 typedef int (*GTIFPrintMethod)(char *string, void *aux);
-typedef int (*GTIFReadMethod)(char *string, void *aux);
+typedef int (*GTIFReadMethod)(char *string, void *aux); // string 1024+ in size
 
 typedef enum {
    TYPE_BYTE=1,
diff --git a/frmts/gtiff/libgeotiff/geotiff_proj4.c b/frmts/gtiff/libgeotiff/geotiff_proj4.c
index 47e4597..129f687 100644
--- a/frmts/gtiff/libgeotiff/geotiff_proj4.c
+++ b/frmts/gtiff/libgeotiff/geotiff_proj4.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: geotiff_proj4.c 1979 2011-02-24 22:17:39Z warmerdam $
+ * $Id: geotiff_proj4.c 2594 2014-12-27 16:46:35Z rouault $
  *
  * Project:  libgeotiff
  * Purpose:  Code to convert a normalized GeoTIFF definition into a PROJ.4
@@ -57,7 +57,7 @@ static char **OSRProj4Tokenize( const char *pszFull )
 
     papszTokens = (char **) calloc(sizeof(char*),nMaxTokens);
 
-    pszFullWrk = strdup( pszFull );
+    pszFullWrk = CPLStrdup(pszFull);
 
     for( i=0; pszFullWrk[i] != '\0' && nTokens != nMaxTokens-1; i++ )
     {
@@ -70,7 +70,7 @@ static char **OSRProj4Tokenize( const char *pszFull )
                 {
                     if( strstr(pszStart,"=") != NULL )
                     {
-                        papszTokens[nTokens++] = strdup(pszStart);
+                        papszTokens[nTokens++] = CPLStrdup(pszStart);
                     }
                     else
                     {
@@ -78,7 +78,7 @@ static char **OSRProj4Tokenize( const char *pszFull )
                         strncpy( szAsBoolean,pszStart, sizeof(szAsBoolean)-1-4);
                         szAsBoolean[sizeof(szAsBoolean)-1-4] = '\0';
                         strcat( szAsBoolean,"=yes" );
-                        papszTokens[nTokens++] = strdup(szAsBoolean);
+                        papszTokens[nTokens++] = CPLStrdup(szAsBoolean);
                     }
                 }
                 pszStart = pszFullWrk + i + 1;
@@ -99,10 +99,10 @@ static char **OSRProj4Tokenize( const char *pszFull )
     if( pszStart != NULL && strlen(pszStart) > 0 )
     {
         if (nTokens != 199)
-            papszTokens[nTokens++] = strdup( pszStart );
+            papszTokens[nTokens++] = CPLStrdup(pszStart);
     }
 
-    free( pszFullWrk );
+    CPLFree( pszFullWrk );
 
     return papszTokens;
 }
@@ -848,7 +848,7 @@ char * GTIFGetProj4Defn( GTIFDefn * psDefn )
     double      dfFalseEasting, dfFalseNorthing;
 
     if( psDefn == NULL || !psDefn->DefnSet )
-        return strdup("");
+        return CPLStrdup("");
 
     szProjection[0] = '\0';
     
@@ -946,13 +946,21 @@ char * GTIFGetProj4Defn( GTIFDefn * psDefn )
 /* -------------------------------------------------------------------- */
     else if( psDefn->CTProjection == CT_Mercator )
     {
-        sprintf( szProjection+strlen(szProjection),
-           "+proj=merc +lat_ts=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f ",
-                 psDefn->ProjParm[0],
-                 psDefn->ProjParm[1],
-                 psDefn->ProjParm[4],
-                 dfFalseEasting,
-                 dfFalseNorthing );
+        if( psDefn->ProjParm[2] != 0.0 ) /* Mercator 2SP: FIXME we need a better way of detecting it */
+            sprintf( szProjection+strlen(szProjection),
+                    "+proj=merc +lat_ts=%.9f +lon_0=%.9f +x_0=%.3f +y_0=%.3f ",
+                    psDefn->ProjParm[2],
+                    psDefn->ProjParm[1],
+                    dfFalseEasting,
+                    dfFalseNorthing );
+        else
+            sprintf( szProjection+strlen(szProjection),
+                    "+proj=merc +lat_ts=%.9f +lon_0=%.9f +k=%f +x_0=%.3f +y_0=%.3f ",
+                    psDefn->ProjParm[0],
+                    psDefn->ProjParm[1],
+                    psDefn->ProjParm[4],
+                    dfFalseEasting,
+                    dfFalseNorthing );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1294,9 +1302,9 @@ char * GTIFGetProj4Defn( GTIFDefn * psDefn )
     strcat( szProjection, szUnits );
     
     /* If we don't have anything, reset */
-    if (strstr(szProjection,"+proj=") == NULL) { return strdup(""); }
+    if (strstr(szProjection, "+proj=") == NULL) { return CPLStrdup(""); }
 
-    return( strdup( szProjection ) );
+    return( CPLStrdup( szProjection ) );
 }
 
 #if !defined(HAVE_LIBPROJ)
diff --git a/frmts/gtiff/libtiff/GNUmakefile b/frmts/gtiff/libtiff/GNUmakefile
index 2ac520b..db77c07 100644
--- a/frmts/gtiff/libtiff/GNUmakefile
+++ b/frmts/gtiff/libtiff/GNUmakefile
@@ -61,6 +61,7 @@ endif
 
 ifneq ($(JPEG_SETTING),no)
 ALL_C_FLAGS 	:=	$(ALL_C_FLAGS) -DJPEG_SUPPORT -DOJPEG_SUPPORT
+# jpeg9: -DHAVE_BOOLEAN -Dboolean=int
 endif
 
 ifeq ($(JPEG_SETTING),internal)
@@ -105,6 +106,11 @@ ifeq ($(RENAME_INTERNAL_LIBTIFF_SYMBOLS),yes)
 	sed "s/defined(TIFFInitJPEG)/0/" < tif_jpeg.c > tmp_tif_jpeg.c
 	$(CC) -c -I../../port $(ALL_C_FLAGS) tmp_tif_jpeg.c -o $@
 	rm tmp_tif_jpeg.c
+
+../../o/tif_jpeg_12.$(OBJ_EXT) : tif_jpeg_12.c t4.h tif_config.h tif_dir.h tif_fax3.h tif_predict.h tiff.h tiffconf.h tiffio.h tiffiop.h tiffvers.h uvcode.h
+	sed "s/#  define TIFFInitJPEG/#undef TIFFInitJPEG\n#  define TIFFInitJPEG/" < tif_jpeg_12.c > tmp_tif_jpeg_12.c
+	$(CC) -c -I../../port $(ALL_C_FLAGS) tmp_tif_jpeg_12.c -o $@
+	rm tmp_tif_jpeg_12.c
 endif
 
 ../../o/%.$(OBJ_EXT):	%.c t4.h tif_config.h tif_dir.h tif_fax3.h tif_predict.h tiff.h tiffconf.h tiffio.h tiffiop.h tiffvers.h uvcode.h
diff --git a/frmts/gtiff/libtiff/tif_jpeg.c b/frmts/gtiff/libtiff/tif_jpeg.c
index a454597..dc77f55 100644
--- a/frmts/gtiff/libtiff/tif_jpeg.c
+++ b/frmts/gtiff/libtiff/tif_jpeg.c
@@ -1,4 +1,4 @@
-/* $Id: tif_jpeg.c,v 1.111 2012-07-06 18:48:04 bfriesen Exp $ */
+/* $Id: tif_jpeg.c,v 1.114 2014-12-30 16:37:22 erouault Exp $ */
 
 /*
  * Copyright (c) 1994-1997 Sam Leffler
@@ -658,7 +658,9 @@ alloc_downsampled_buffers(TIFF* tif, jpeg_component_info* comp_info,
 
 #define JPEG_MARKER_SOF0 0xC0
 #define JPEG_MARKER_SOF1 0xC1
-#define JPEG_MARKER_SOF3 0xC3
+#define JPEG_MARKER_SOF2 0xC2
+#define JPEG_MARKER_SOF9 0xC9
+#define JPEG_MARKER_SOF10 0xCA
 #define JPEG_MARKER_DHT 0xC4
 #define JPEG_MARKER_SOI 0xD8
 #define JPEG_MARKER_SOS 0xDA
@@ -817,8 +819,11 @@ JPEGFixupTagsSubsamplingSec(struct JPEGFixupTagsSubsamplingData* data)
 						JPEGFixupTagsSubsamplingSkip(data,n);
 				}
 				break;
-			case JPEG_MARKER_SOF0:
-			case JPEG_MARKER_SOF1:
+			case JPEG_MARKER_SOF0: /* Baseline sequential Huffman */
+			case JPEG_MARKER_SOF1: /* Extended sequential Huffman */
+			case JPEG_MARKER_SOF2: /* Progressive Huffman: normally not allowed by TechNote, but that doesn't hurt supporting it */
+			case JPEG_MARKER_SOF9: /* Extended sequential arithmetic */
+			case JPEG_MARKER_SOF10: /* Progressive arithmetic: normally not allowed by TechNote, but that doesn't hurt supporting it */
 				/* this marker contains the subsampling factors we're scanning for */
 				{
 					uint16 n;
@@ -1452,6 +1457,15 @@ unsuppress_quant_table (JPEGState* sp, int tblno)
 }
 
 static void
+suppress_quant_table (JPEGState* sp, int tblno)
+{
+	JQUANT_TBL* qtbl;
+
+	if ((qtbl = sp->cinfo.c.quant_tbl_ptrs[tblno]) != NULL)
+		qtbl->sent_table = TRUE;
+}
+
+static void
 unsuppress_huff_table (JPEGState* sp, int tblno)
 {
 	JHUFF_TBL* htbl;
@@ -1462,6 +1476,17 @@ unsuppress_huff_table (JPEGState* sp, int tblno)
 		htbl->sent_table = FALSE;
 }
 
+static void
+suppress_huff_table (JPEGState* sp, int tblno)
+{
+	JHUFF_TBL* htbl;
+
+	if ((htbl = sp->cinfo.c.dc_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = TRUE;
+	if ((htbl = sp->cinfo.c.ac_huff_tbl_ptrs[tblno]) != NULL)
+		htbl->sent_table = TRUE;
+}
+
 static int
 prepare_JPEGTables(TIFF* tif)
 {
@@ -1511,17 +1536,38 @@ JPEGSetupEncode(TIFF* tif)
 	assert(sp != NULL);
 	assert(!sp->cinfo.comm.is_decompressor);
 
+	sp->photometric = td->td_photometric;
+
 	/*
 	 * Initialize all JPEG parameters to default values.
 	 * Note that jpeg_set_defaults needs legal values for
 	 * in_color_space and input_components.
 	 */
-	sp->cinfo.c.in_color_space = JCS_UNKNOWN;
-	sp->cinfo.c.input_components = 1;
+	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
+		sp->cinfo.c.input_components = td->td_samplesperpixel;
+		if (sp->photometric == PHOTOMETRIC_YCBCR) {
+			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			} else {
+				sp->cinfo.c.in_color_space = JCS_YCbCr;
+			}
+		} else {
+			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
+				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
+			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
+				sp->cinfo.c.in_color_space = JCS_RGB;
+			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
+				sp->cinfo.c.in_color_space = JCS_CMYK;
+			else
+				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+		}
+	} else {
+		sp->cinfo.c.input_components = 1;
+		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
+	}
 	if (!TIFFjpeg_set_defaults(sp))
 		return (0);
 	/* Set per-file parameters */
-	sp->photometric = td->td_photometric;
 	switch (sp->photometric) {
 	case PHOTOMETRIC_YCBCR:
 		sp->h_sampling = td->td_ycbcrsubsampling[0];
@@ -1681,10 +1727,7 @@ JPEGPreEncode(TIFF* tif, uint16 s)
 	if (td->td_planarconfig == PLANARCONFIG_CONTIG) {
 		sp->cinfo.c.input_components = td->td_samplesperpixel;
 		if (sp->photometric == PHOTOMETRIC_YCBCR) {
-			if (sp->jpegcolormode == JPEGCOLORMODE_RGB) {
-				sp->cinfo.c.in_color_space = JCS_RGB;
-			} else {
-				sp->cinfo.c.in_color_space = JCS_YCbCr;
+			if (sp->jpegcolormode != JPEGCOLORMODE_RGB) {
 				if (sp->h_sampling != 1 || sp->v_sampling != 1)
 					downsampled_input = TRUE;
 			}
@@ -1697,21 +1740,11 @@ JPEGPreEncode(TIFF* tif, uint16 s)
 			sp->cinfo.c.comp_info[0].h_samp_factor = sp->h_sampling;
 			sp->cinfo.c.comp_info[0].v_samp_factor = sp->v_sampling;
 		} else {
-			if ((td->td_photometric == PHOTOMETRIC_MINISWHITE || td->td_photometric == PHOTOMETRIC_MINISBLACK) && td->td_samplesperpixel == 1)
-				sp->cinfo.c.in_color_space = JCS_GRAYSCALE;
-			else if (td->td_photometric == PHOTOMETRIC_RGB && td->td_samplesperpixel == 3)
-				sp->cinfo.c.in_color_space = JCS_RGB;
-			else if (td->td_photometric == PHOTOMETRIC_SEPARATED && td->td_samplesperpixel == 4)
-				sp->cinfo.c.in_color_space = JCS_CMYK;
-			else
-				sp->cinfo.c.in_color_space = JCS_UNKNOWN;
 			if (!TIFFjpeg_set_colorspace(sp, sp->cinfo.c.in_color_space))
 				return (0);
 			/* jpeg_set_colorspace set all sampling factors to 1 */
 		}
 	} else {
-		sp->cinfo.c.input_components = 1;
-		sp->cinfo.c.in_color_space = JCS_UNKNOWN;
 		if (!TIFFjpeg_set_colorspace(sp, JCS_UNKNOWN))
 			return (0);
 		sp->cinfo.c.comp_info[0].component_id = s;
@@ -1726,14 +1759,30 @@ JPEGPreEncode(TIFF* tif, uint16 s)
 	sp->cinfo.c.write_JFIF_header = FALSE;
 	sp->cinfo.c.write_Adobe_marker = FALSE;
 	/* set up table handling correctly */
-        if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
+	/* calling TIFFjpeg_set_quality() causes quantization tables to be flagged */
+	/* as being to be emitted, which we don't want in the JPEGTABLESMODE_QUANT */
+	/* mode, so we must manually suppress them. However TIFFjpeg_set_quality() */
+	/* should really be called when dealing with files with directories with */
+	/* mixed qualities. see http://trac.osgeo.org/gdal/ticket/3539 */
+	if (!TIFFjpeg_set_quality(sp, sp->jpegquality, FALSE))
 		return (0);
-	if (! (sp->jpegtablesmode & JPEGTABLESMODE_QUANT)) {
+	if (sp->jpegtablesmode & JPEGTABLESMODE_QUANT) {
+		suppress_quant_table(sp, 0);
+		suppress_quant_table(sp, 1);
+	}
+	else {
 		unsuppress_quant_table(sp, 0);
 		unsuppress_quant_table(sp, 1);
 	}
 	if (sp->jpegtablesmode & JPEGTABLESMODE_HUFF)
+	{
+		/* Explicit suppression is only needed if we did not go through the */
+		/* prepare_JPEGTables() code path, which may be the case if updating */
+		/* an existing file */
+		suppress_huff_table(sp, 0);
+		suppress_huff_table(sp, 1);
 		sp->cinfo.c.optimize_coding = FALSE;
+	}
 	else
 		sp->cinfo.c.optimize_coding = TRUE;
 	if (downsampled_input) {
diff --git a/frmts/gtiff/libtiff/tif_vsi.c b/frmts/gtiff/libtiff/tif_vsi.c
index b7f9da5..459502e 100644
--- a/frmts/gtiff/libtiff/tif_vsi.c
+++ b/frmts/gtiff/libtiff/tif_vsi.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tif_vsi.c 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: tif_vsi.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Implement system hook functions for libtiff on top of CPL/VSI,
diff --git a/frmts/gtiff/libtiff/tiffvers.h b/frmts/gtiff/libtiff/tiffvers.h
index 4326145..74f769c 100644
--- a/frmts/gtiff/libtiff/tiffvers.h
+++ b/frmts/gtiff/libtiff/tiffvers.h
@@ -1,4 +1,4 @@
-#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.3patched\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
+#define TIFFLIB_VERSION_STR "LIBTIFF, Version 4.0.4beta\nCopyright (c) 1988-1996 Sam Leffler\nCopyright (c) 1991-1996 Silicon Graphics, Inc."
 /*
  * This define can be used in code that requires
  * compilation-related definitions specific to a
@@ -6,4 +6,4 @@
  * version checking should be done based on the
  * string returned by TIFFGetVersion.
  */
-#define TIFFLIB_VERSION 20120922
+#define TIFFLIB_VERSION 20150126
diff --git a/frmts/gtiff/makefile.vc b/frmts/gtiff/makefile.vc
index a274be3..a5223ec 100644
--- a/frmts/gtiff/makefile.vc
+++ b/frmts/gtiff/makefile.vc
@@ -18,7 +18,7 @@ SUB_TIFF_TARGET =	tiff
 !IFDEF GEOTIFF_INC
 SUB_GEOTIFF_TARGET =	
 !ELSE
-GEOTIFF_INC   =	-Ilibgeotiff
+GEOTIFF_INC   =	-Ilibgeotiff -DINTERNAL_LIBGEOTIFF
 SUB_GEOTIFF_TARGET =	geotiff
 !ENDIF
 
diff --git a/frmts/gtiff/tifvsi.cpp b/frmts/gtiff/tifvsi.cpp
index 3618da0..70b6454 100644
--- a/frmts/gtiff/tifvsi.cpp
+++ b/frmts/gtiff/tifvsi.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tifvsi.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: tifvsi.cpp 28873 2015-04-08 14:32:00Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Implement system hook functions for libtiff on top of CPL/VSI,
@@ -34,6 +34,7 @@
  * TIFF Library UNIX-specific Routines.
  */
 #include "cpl_vsi.h"
+#include "cpl_conv.h"
 #include "tifvsi.h"
 
 #include <errno.h>
@@ -54,79 +55,197 @@ extern TIFF CPL_DLL * XTIFFClientOpen(const char* name, const char* mode,
                                       TIFFMapFileProc, TIFFUnmapFileProc);
 CPL_C_END
 
+#define BUFFER_SIZE     (65536)
+
+typedef struct
+{
+    VSILFILE*   fpL;
+    int         bAtEndOfFile;
+    vsi_l_offset nExpectedPos;
+    GByte      *abyWriteBuffer;
+    int         nWriteBufferSize;
+} GDALTiffHandle;
+
 static tsize_t
-_tiffReadProc(thandle_t fd, tdata_t buf, tsize_t size)
+_tiffReadProc(thandle_t th, tdata_t buf, tsize_t size)
+{
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    return VSIFReadL( buf, 1, size, psGTH->fpL );
+}
+
+static int GTHFlushBuffer(thandle_t th)
 {
-    return VSIFReadL( buf, 1, size, (VSILFILE *) fd );
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    int bRet = TRUE;
+    if( psGTH->abyWriteBuffer && psGTH->nWriteBufferSize )
+    {
+        tsize_t nRet = VSIFWriteL( psGTH->abyWriteBuffer, 1, psGTH->nWriteBufferSize, psGTH->fpL );
+        bRet = (nRet == psGTH->nWriteBufferSize);
+        if( !bRet )
+        {
+            TIFFErrorExt( th, "_tiffWriteProc", "%s", VSIStrerror( errno ) );
+        }
+        psGTH->nWriteBufferSize = 0;
+    }
+    return bRet;
 }
 
+
 static tsize_t
-_tiffWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
+_tiffWriteProc(thandle_t th, tdata_t buf, tsize_t size)
 {
-    tsize_t nRet = VSIFWriteL( buf, 1, size, (VSILFILE *) fd );
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    
+    // If we have a write buffer and are at end of file, then accumulate
+    // the bytes until the buffer is full
+    if( psGTH->bAtEndOfFile && psGTH->abyWriteBuffer )
+    {
+        const GByte* pabyData = (const GByte*) buf;
+        tsize_t nRemainingBytes = size;
+        while( TRUE )
+        {
+            if( psGTH->nWriteBufferSize + nRemainingBytes <= BUFFER_SIZE )
+            {
+                memcpy( psGTH->abyWriteBuffer + psGTH->nWriteBufferSize,
+                        pabyData, nRemainingBytes );
+                psGTH->nWriteBufferSize += nRemainingBytes;
+                psGTH->nExpectedPos += size;
+                return size;
+            }
+
+            int nAppendable = BUFFER_SIZE - psGTH->nWriteBufferSize;
+            memcpy( psGTH->abyWriteBuffer + psGTH->nWriteBufferSize, pabyData,
+                    nAppendable );
+            tsize_t nRet = VSIFWriteL( psGTH->abyWriteBuffer, 1, BUFFER_SIZE, psGTH->fpL );
+            psGTH->nWriteBufferSize = 0;
+            if( nRet != BUFFER_SIZE )
+            {
+                TIFFErrorExt( th, "_tiffWriteProc", "%s", VSIStrerror( errno ) );
+                return 0;
+            }
+
+            pabyData += nAppendable;
+            nRemainingBytes -= nAppendable;
+        }
+    }
+    
+    tsize_t nRet = VSIFWriteL( buf, 1, size, psGTH->fpL );
     if (nRet < size)
     {
-        TIFFErrorExt( fd, "_tiffWriteProc", "%s", VSIStrerror( errno ) );
+        TIFFErrorExt( th, "_tiffWriteProc", "%s", VSIStrerror( errno ) );
+    }
+    if( psGTH->bAtEndOfFile )
+    {
+        psGTH->nExpectedPos += nRet;
     }
     return nRet;
 }
 
 static toff_t
-_tiffSeekProc(thandle_t fd, toff_t off, int whence)
+_tiffSeekProc(thandle_t th, toff_t off, int whence)
 {
-    if( VSIFSeekL( (VSILFILE *) fd, off, whence ) == 0 )
-        return (toff_t) VSIFTellL( (VSILFILE *) fd );
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+
+    /* Optimization: if we are already at end, then no need to */
+    /* issue a VSIFSeekL() */
+    if( whence == SEEK_END )
+    {
+        if( psGTH->bAtEndOfFile )
+        {
+            return (toff_t) psGTH->nExpectedPos;
+        }
+
+        if( VSIFSeekL( psGTH->fpL, off, whence ) != 0 )
+        {
+            TIFFErrorExt( th, "_tiffSeekProc", "%s", VSIStrerror( errno ) );
+            return (toff_t) -1;
+        }
+        psGTH->bAtEndOfFile = TRUE;
+        psGTH->nExpectedPos = VSIFTellL( psGTH->fpL );
+        return (toff_t) (psGTH->nExpectedPos);
+    }
+
+    GTHFlushBuffer(th);
+    psGTH->bAtEndOfFile = FALSE;
+    psGTH->nExpectedPos = 0;
+    
+    if( VSIFSeekL( psGTH->fpL, off, whence ) == 0 )
+        return (toff_t) VSIFTellL( psGTH->fpL );
     else
     {
-        TIFFErrorExt( fd, "_tiffSeekProc", "%s", VSIStrerror( errno ) );
+        TIFFErrorExt( th, "_tiffSeekProc", "%s", VSIStrerror( errno ) );
         return (toff_t) -1;
     }
 }
 
 static int
-_tiffCloseProc(thandle_t fd)
+_tiffCloseProc(thandle_t th)
 {
-    return VSIFCloseL( (VSILFILE *) fd );
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    GTHFlushBuffer(th);
+    CPLFree(psGTH->abyWriteBuffer);
+    CPLFree(psGTH);
+    return 0;
 }
 
 static toff_t
-_tiffSizeProc(thandle_t fd)
+_tiffSizeProc(thandle_t th)
 {
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
     vsi_l_offset  old_off;
     toff_t        file_size;
+    
+    if( psGTH->bAtEndOfFile )
+    {
+        return (toff_t) psGTH->nExpectedPos;
+    }
 
-    old_off = VSIFTellL( (VSILFILE *) fd );
-    VSIFSeekL( (VSILFILE *) fd, 0, SEEK_END );
+    old_off = VSIFTellL( psGTH->fpL );
+    VSIFSeekL( psGTH->fpL, 0, SEEK_END );
     
-    file_size = (toff_t) VSIFTellL( (VSILFILE *) fd );
-    VSIFSeekL( (VSILFILE *) fd, old_off, SEEK_SET );
+    file_size = (toff_t) VSIFTellL( psGTH->fpL );
+    VSIFSeekL( psGTH->fpL, old_off, SEEK_SET );
 
     return file_size;
 }
 
 static int
-_tiffMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+_tiffMapProc(thandle_t th, tdata_t* pbase, toff_t* psize)
 {
-	(void) fd; (void) pbase; (void) psize;
+	(void) th; (void) pbase; (void) psize;
 	return (0);
 }
 
 static void
-_tiffUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+_tiffUnmapProc(thandle_t th, tdata_t base, toff_t size)
+{
+	(void) th; (void) base; (void) size;
+}
+
+VSILFILE* VSI_TIFFGetVSILFile(thandle_t th)
+{
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    VSI_TIFFFlushBufferedWrite(th);
+    return psGTH->fpL;
+}
+
+int VSI_TIFFFlushBufferedWrite(thandle_t th)
 {
-	(void) fd; (void) base; (void) size;
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) th;
+    psGTH->bAtEndOfFile = FALSE;
+    return GTHFlushBuffer(th);
 }
 
 /*
  * Open a TIFF file for read/writing.
  */
-TIFF* VSI_TIFFOpen(const char* name, const char* mode)
+TIFF* VSI_TIFFOpen(const char* name, const char* mode,
+                   VSILFILE* fpL)
 {
-    static const char module[] = "TIFFOpen";
     int           i, a_out;
     char          access[32];
-    VSILFILE      *fp;
     TIFF          *tif;
+    int           bAllocBuffer = FALSE;
 
     a_out = 0;
     access[0] = '\0';
@@ -140,27 +259,34 @@ TIFF* VSI_TIFFOpen(const char* name, const char* mode)
             access[a_out++] = mode[i];
             access[a_out] = '\0';
         }
+        if( mode[i] == 'w'
+            || mode[i] == '+'
+            || mode[i] == 'a' )
+            bAllocBuffer = TRUE;
     }
 
+    // No need to buffer on /vsimem/
+    if( strncmp(name, "/vsimem/", strlen("/vsimem/")) == 0 )
+        bAllocBuffer = FALSE;
+
     strcat( access, "b" );
-                    
-    fp = VSIFOpenL( name, access );
-    if (fp == NULL) {
-        if( errno >= 0 )
-            TIFFError(module,"%s: %s", name, VSIStrerror( errno ) );
-        else
-            TIFFError(module, "%s: Cannot open", name);
-        return ((TIFF *)0);
-    }
+
+    VSIFSeekL(fpL, 0, SEEK_SET);
+    
+    GDALTiffHandle* psGTH = (GDALTiffHandle*) CPLMalloc(sizeof(GDALTiffHandle));
+    psGTH->fpL = fpL;
+    psGTH->nExpectedPos = 0;
+    psGTH->bAtEndOfFile = FALSE;
+    psGTH->abyWriteBuffer = (bAllocBuffer) ? (GByte*)VSIMalloc(BUFFER_SIZE) : NULL;
+    psGTH->nWriteBufferSize = 0;
 
     tif = XTIFFClientOpen(name, mode,
-                          (thandle_t) fp,
+                          (thandle_t) psGTH,
                           _tiffReadProc, _tiffWriteProc,
                           _tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
                           _tiffMapProc, _tiffUnmapProc);
-
     if( tif == NULL )
-        VSIFCloseL( fp );
-        
+        CPLFree(psGTH);
+
     return tif;
 }
diff --git a/frmts/gtiff/tifvsi.h b/frmts/gtiff/tifvsi.h
index 17a30c5..de7befc 100644
--- a/frmts/gtiff/tifvsi.h
+++ b/frmts/gtiff/tifvsi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tifvsi.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: tifvsi.h 28872 2015-04-08 14:25:20Z rouault $
  *
  * Project:  GeoTIFF Driver
  * Purpose:  Implement system hook functions for libtiff on top of CPL/VSI,
@@ -35,6 +35,8 @@
 
 #include "tiffio.h"
 
-TIFF* VSI_TIFFOpen(const char* name, const char* mode);
+TIFF* VSI_TIFFOpen(const char* name, const char* mode, VSILFILE* fp);
+VSILFILE* VSI_TIFFGetVSILFile(thandle_t th);
+int VSI_TIFFFlushBufferedWrite(thandle_t th);
 
 #endif // TIFVSI_H_INCLUDED
diff --git a/frmts/gxf/GNUmakefile b/frmts/gxf/GNUmakefile
index 7116936..4bdf883 100644
--- a/frmts/gxf/GNUmakefile
+++ b/frmts/gxf/GNUmakefile
@@ -9,7 +9,7 @@ include ../../GDALmake.opt
 GXFOBJ	=	gxfopen.o gxf_proj4.o gxf_ogcwkt.o
 OBJ	=	gxfdataset.o $(GXFOBJ)
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/gxf/gxf_ogcwkt.c b/frmts/gxf/gxf_ogcwkt.c
index 57e33bb..8ab0f4a 100644
--- a/frmts/gxf/gxf_ogcwkt.c
+++ b/frmts/gxf/gxf_ogcwkt.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gxf_ogcwkt.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gxf_ogcwkt.c 28565 2015-02-27 10:26:21Z rouault $
  *
  * Project:  GXF Reader
  * Purpose:  Handle GXF to OGC WKT projection transformation.
@@ -29,8 +29,9 @@
  ****************************************************************************/
 
 #include "gxfopen.h"
+#include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: gxf_ogcwkt.c 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gxf_ogcwkt.c 28565 2015-02-27 10:26:21Z rouault $");
 
 /* -------------------------------------------------------------------- */
 /* the following #defines come from ogr_spatialref.h in the GDAL/OGR	*/
@@ -549,7 +550,7 @@ char *GXFGetMapProjectionAsOGCWKT( GXFHandle hGXF )
         if( strlen(psGXF->pszUnitName) > 80 )
             return CPLStrdup("");
 
-        sprintf( szProjection+strlen(szProjection),
+        CPLsprintf( szProjection+strlen(szProjection),
                  ",UNIT[\"%s\",%.15g]",
                  psGXF->pszUnitName, psGXF->dfUnitToMeter );
     }
@@ -572,8 +573,8 @@ char *GXFGetMapProjectionAsOGCWKT( GXFHandle hGXF )
 
         if( CSLCount(papszTokens) > 2 )
         {
-            double	dfMajor = atof(papszTokens[1]);
-            double	dfEccentricity = atof(papszTokens[2]);
+            double	dfMajor = CPLAtof(papszTokens[1]);
+            double	dfEccentricity = CPLAtof(papszTokens[2]);
             double	dfInvFlattening, dfMinor;
             char	*pszOGCDatum;
 
@@ -583,13 +584,13 @@ char *GXFGetMapProjectionAsOGCWKT( GXFHandle hGXF )
             else
             {
                 dfMinor = dfMajor * pow(1.0-dfEccentricity*dfEccentricity,0.5);
-                dfInvFlattening = 1.0 / (1 - dfMinor/dfMajor);
+                dfInvFlattening = OSRCalcInvFlattening(dfMajor, dfMinor);
             }
 
             pszOGCDatum = CPLStrdup(papszTokens[0]);
             WKTMassageDatum( &pszOGCDatum );
             
-            sprintf( szGCS,
+            CPLsprintf( szGCS,
                      "GEOGCS[\"%s\","
                        "DATUM[\"%s\","
                        "SPHEROID[\"%s\",%s,%.15g]],",
diff --git a/frmts/gxf/gxf_proj4.c b/frmts/gxf/gxf_proj4.c
index 1c1bd59..8e356c9 100644
--- a/frmts/gxf/gxf_proj4.c
+++ b/frmts/gxf/gxf_proj4.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gxf_proj4.c 25164 2012-10-20 13:42:32Z rouault $
+ * $Id: gxf_proj4.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GXF Reader
  * Purpose:  Handle GXF to PROJ.4 projection transformation.
@@ -30,7 +30,7 @@
 
 #include "gxfopen.h"
 
-CPL_CVSID("$Id: gxf_proj4.c 25164 2012-10-20 13:42:32Z rouault $");
+CPL_CVSID("$Id: gxf_proj4.c 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                     GXFGetMapProjectionAsPROJ4()                     */
@@ -237,14 +237,14 @@ char *GXFGetMapProjectionAsPROJ4( GXFHandle hGXF )
         strcat( szPROJ4, " +alpha=" );
         strcat( szPROJ4, papszMethods[3] );
 
-        if( atof(papszMethods[4]) < 0.00001 )
+        if( CPLAtof(papszMethods[4]) < 0.00001 )
         {
             strcat( szPROJ4, " +not_rot" );
         }
         else
         {
 #ifdef notdef            
-            if( atof(papszMethods[4]) + atof(papszMethods[3]) < 0.00001 )
+            if( CPLAtof(papszMethods[4]) + CPLAtof(papszMethods[3]) < 0.00001 )
                 /* ok */;
             else
                 /* notdef: no way to specify arbitrary angles! */;
diff --git a/frmts/gxf/gxfdataset.cpp b/frmts/gxf/gxfdataset.cpp
index 823d8fa..47e420b 100644
--- a/frmts/gxf/gxfdataset.cpp
+++ b/frmts/gxf/gxfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gxfdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gxfdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GXF Reader
  * Purpose:  GDAL binding for GXF reader.
@@ -31,7 +31,7 @@
 #include "gxfopen.h"
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: gxfdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gxfdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #ifndef PI
 #  define PI 3.14159265358979323846
@@ -124,9 +124,9 @@ double GXFRasterBand::GetNoDataValue(int* bGotNoDataValue)
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GXFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr GXFRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
-
 {
     GXFDataset	*poGXF_DS = (GXFDataset *) poDS;
     double	*padfBuffer;
@@ -245,7 +245,7 @@ GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      least one "\n#keyword" type signature in the first chunk of     */
 /*      the file.                                                       */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )
+    if( poOpenInfo->nHeaderBytes < 50 )
         return NULL;
 
     bFoundKeyword = FALSE;
@@ -256,6 +256,12 @@ GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo )
              || poOpenInfo->pabyHeader[i] == 13)
             && poOpenInfo->pabyHeader[i+1] == '#' )
         {
+            if( strncmp((const char*)poOpenInfo->pabyHeader + i + 2, "include", strlen("include")) == 0 )
+                return NULL;
+            if( strncmp((const char*)poOpenInfo->pabyHeader + i + 2, "define", strlen("define")) == 0 )
+                return NULL;
+            if( strncmp((const char*)poOpenInfo->pabyHeader + i + 2, "ifdef", strlen("ifdef")) == 0 )
+                return NULL;
             bFoundKeyword = TRUE;
         }
         if( poOpenInfo->pabyHeader[i] == 0 )
@@ -372,7 +378,7 @@ GDALDataset *GXFDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -391,6 +397,7 @@ void GDALRegister_GXF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GXF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "GeoSoft Grid Exchange Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/hdf4/GNUmakefile b/frmts/hdf4/GNUmakefile
index c49e0af..409e002 100644
--- a/frmts/hdf4/GNUmakefile
+++ b/frmts/hdf4/GNUmakefile
@@ -5,7 +5,7 @@ OBJ	=	hdf4dataset.o hdf4imagedataset.o
 
 SUBLIBS 	= lib-hdfeos
 
-CPPFLAGS	:=	-I../pds -Ihdf-eos $(GDAL_INCLUDE) $(HDF4_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../pds -Ihdf-eos  $(HDF4_INCLUDE) $(HDF4_FLAGS) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT)) $(SUBLIBS)
 
diff --git a/frmts/hdf4/hdf-eos/GDapi.c b/frmts/hdf4/hdf-eos/GDapi.c
index f969aa6..50c43df 100644
--- a/frmts/hdf4/hdf-eos/GDapi.c
+++ b/frmts/hdf4/hdf-eos/GDapi.c
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: GDapi.c 15522 2008-10-13 06:17:52Z dron $
+ * $Id: GDapi.c 28436 2015-02-07 15:36:06Z rouault $
  *
  * This module has a number of additions and improvements over the original
  * implementation to be suitable for usage in GDAL HDF driver.
@@ -85,6 +85,7 @@ Jun  05, 2003 Bruce Beaumont / Abe Taaheri
                                 end of GDll2mm_cea
                              Added return statement to GDll2mm_cea
 ******************************************************************************/
+#include "cpl_string.h"
 #include "stdio.h"
 #include "mfhdf.h"
 #include "hcomp.h"
@@ -494,10 +495,10 @@ GDcreate(int32 fid, char *gridname, int32 xdimsize, int32 ydimsize,
 		}
 		else
 		{
-		    sprintf(refstr1, "%s%f%s%f%s",
+		    CPLsprintf(refstr1, "%s%f%s%f%s",
 			    "(", upleftpt[0], ",", upleftpt[1], ")");
 
-		    sprintf(refstr2, "%s%f%s%f%s",
+		    CPLsprintf(refstr2, "%s%f%s%f%s",
 			    "(", lowrightpt[0], ",", lowrightpt[1], ")");
 		}
 
@@ -1067,7 +1068,7 @@ GDdefproj(int32 gridID, int32 projcode, int32 zonecode, int32 spherecode,
 		    /* else projparm[i] is non-zero floating point ... */
 		    else
 		    {
-			sprintf(utlbuf, "%f%s",	projparm[i], ",");
+			CPLsprintf(utlbuf, "%f%s",	projparm[i], ",");
 		    }
 		}
 		strcat(projparmbuf, utlbuf);
@@ -6318,7 +6319,7 @@ GDll2ij(int32 projcode, int32 zonecode, float64 projparm[],
     float64         xMtr;	/* X value in meters from GCTP */
     float64         yMtr;	/* Y value in meters from GCTP */
     float64         lonrad0;	/* Longitude in radians of upleft point */
-    float64         latrad0;	/* Latitude in radians of upleft point */
+    float64         latrad0 = 0;	/* Latitude in radians of upleft point */
     float64         lonrad;	/* Longitude in radians of point */
     float64         latrad;	/* Latitude in radians of point */
     float64         scaleX;	/* X scale factor */
@@ -6595,8 +6596,8 @@ GDrs2ll(int32 projcode, float64 projparm[],
     float64         yMtr;	    /* Y value in meters from GCTP */
     float64         epsilon;
     float64         beta;
-    float64         qp_cea;
-    float64         kz_cea;
+    float64         qp_cea = 0;
+    float64         kz_cea = 0;
     float64         eccen, eccen_sq;
     float64         phi1, sinphi1, cosphi1;
     float64         scaleX, scaleY;
@@ -7619,10 +7620,10 @@ GDdefboxregion(int32 gridID, float64 cornerlon[], float64 cornerlat[])
     int32           spherecode;	    /* Sphere code */
     int32           row[32];	    /* Row array */
     int32           col[32];	    /* Column array */
-    int32           minCol;	    /* Minimun column value */
-    int32           minRow;	    /* Minimun row value */
-    int32           maxCol;	    /* Maximun column value */
-    int32           maxRow;	    /* Maximun row value */
+    int32           minCol = 0;	    /* Minimun column value */
+    int32           minRow = 0;	    /* Minimun row value */
+    int32           maxCol = 0;	    /* Maximun column value */
+    int32           maxRow = 0;	    /* Maximun row value */
     int32           npnts;	    /* Number of boundary
                                        (edge & tangent) pnts */
 
diff --git a/frmts/hdf4/hdf-eos/GNUmakefile b/frmts/hdf4/hdf-eos/GNUmakefile
index 51684e4..75b010c 100644
--- a/frmts/hdf4/hdf-eos/GNUmakefile
+++ b/frmts/hdf4/hdf-eos/GNUmakefile
@@ -9,7 +9,7 @@ OBJ	= \
 
 O_OBJ	=	$(foreach file,$(OBJ),../../o/$(file))
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(HDF4_INCLUDE) -I. -I.. $(CPPFLAGS) 
+CPPFLAGS	:=	 $(HDF4_INCLUDE) -I. -I.. $(HDF4_FLAGS) $(CPPFLAGS) 
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
@@ -19,4 +19,4 @@ clean:
 install-obj:    $(SUBLIBS) $(O_OBJ:.o=.$(OBJ_EXT))
 
 ../../o/%.$(OBJ_EXT):	%.c
-	$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+	$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
diff --git a/frmts/hdf4/hdf-eos/SWapi.c b/frmts/hdf4/hdf-eos/SWapi.c
index d0acc74..9cef80a 100644
--- a/frmts/hdf4/hdf-eos/SWapi.c
+++ b/frmts/hdf4/hdf-eos/SWapi.c
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: SWapi.c 18599 2010-01-19 21:10:50Z rouault $
+ * $Id: SWapi.c 28435 2015-02-07 14:35:34Z rouault $
  *
  * This module has a number of additions and improvements over the original
  * implementation to be suitable for usage in GDAL HDF driver.
@@ -5906,7 +5906,7 @@ SWregionindex(int32 swathID, float64 cornerlon[], float64 cornerlat[],
     intn            k;		/* Loop index */
 
     intn            l=0;	/* Loop index */
-    intn            tmpVal;     /* temp value for start region Delyth Jones*/
+    intn            tmpVal = 0;     /* temp value for start region Delyth Jones*/
   /*intn            j1;  */     /* Loop index */
     intn            status;	/* routine return status variable */
     intn	    mapstatus;	/* status for type of mapping */
@@ -6542,7 +6542,7 @@ SWdeftimeperiod(int32 swathID, float64 starttime, float64 stoptime,
 
     intn            i;		    /* Loop index */
     intn            j;		    /* Loop index */
-    intn            k;		    /* Loop index */
+    intn            k = 0;		    /* Loop index */
     intn            status;	    /* routine return status variable */
     intn            statTime;	    /* Status from SWfieldinfo for time */
 
@@ -9443,8 +9443,8 @@ SWdefscanregion(int32 swathID, char *fieldname, float64 range[], int32 mode)
 
     int32           regionID = -1;	/* Region ID (return) */
 
-    float64	    scan[2];
-    float64	    original_scan[2];
+    float64	    scan[2] = {0,0};
+    float64	    original_scan[2] = {0,0};
 
     char            dimlist[256];	/* Dimension list */
     char	    swathname[80];
diff --git a/frmts/hdf4/hdf-eos/makefile.vc b/frmts/hdf4/hdf-eos/makefile.vc
index 1487ff7..5dfe538 100644
--- a/frmts/hdf4/hdf-eos/makefile.vc
+++ b/frmts/hdf4/hdf-eos/makefile.vc
@@ -8,6 +8,10 @@ GDAL_ROOT	=	..\..\..
 
 EXTRAFLAGS = 	-I$(HDF4_DIR)\include -I.\ -I..\ -DFRMT_hdf4 -DWIN32
 
+!IF "$(HDF4_HAS_MAXOPENFILES)" == "YES"
+EXTRAFLAGS = $(EXTRAFLAGS) -DHDF4_HAS_MAXOPENFILES
+!ENDIF
+
 default:	$(OBJ)
 	xcopy /D  /Y *.obj ..\..\o
 
diff --git a/frmts/hdf4/hdf4dataset.cpp b/frmts/hdf4/hdf4dataset.cpp
index b6bc1a6..a15edcc 100644
--- a/frmts/hdf4/hdf4dataset.cpp
+++ b/frmts/hdf4/hdf4dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hdf4dataset.cpp 28365 2015-01-27 10:39:30Z rouault $
+ * $Id: hdf4dataset.cpp 28901 2015-04-14 10:10:32Z rouault $
  *
  * Project:  Hierarchical Data Format Release 4 (HDF4)
  * Purpose:  HDF4 Datasets. Open HDF4 file, fetch metadata and list of
@@ -42,7 +42,7 @@
 #include "hdf4compat.h"
 #include "hdf4dataset.h"
 
-CPL_CVSID("$Id: hdf4dataset.cpp 28365 2015-01-27 10:39:30Z rouault $");
+CPL_CVSID("$Id: hdf4dataset.cpp 28901 2015-04-14 10:10:32Z rouault $");
 
 CPL_C_START
 void	GDALRegister_HDF4(void);
@@ -50,7 +50,7 @@ CPL_C_END
 
 extern const char *pszGDALSignature;
 
-void *hHDF4Mutex = NULL;
+CPLMutex *hHDF4Mutex = NULL;
 
 /************************************************************************/
 /* ==================================================================== */
@@ -65,7 +65,6 @@ void *hHDF4Mutex = NULL;
 HDF4Dataset::HDF4Dataset()
 
 {
-    fp = NULL;
     hSD = 0;
     hGR = 0;
     nImages = 0;
@@ -93,8 +92,6 @@ HDF4Dataset::~HDF4Dataset()
 	CSLDestroy( papszSubDatasets );
     if ( papszGlobalMetadata )
 	CSLDestroy( papszGlobalMetadata );
-    if( fp != NULL )
-        VSIFClose( fp );
 }
 
 /************************************************************************/
@@ -167,11 +164,11 @@ char *SPrintArray( GDALDataType eDataType, const void *paDataArray,
                      (i < nValues - 1)?pszDelimiter:"" );
                 break;
             case GDT_Float32:
-                sprintf( pszField, "%.10g%s", ((float *)paDataArray)[i],
+                CPLsprintf( pszField, "%.10g%s", ((float *)paDataArray)[i],
                      (i < nValues - 1)?pszDelimiter:"" );
                 break;
             case GDT_Float64:
-                sprintf( pszField, "%.15g%s", ((double *)paDataArray)[i],
+                CPLsprintf( pszField, "%.15g%s", ((double *)paDataArray)[i],
                      (i < nValues - 1)?pszDelimiter:"" );
                 break;
         }
@@ -414,16 +411,19 @@ char **HDF4Dataset::HDF4EOSTokenizeAttrs( const char * pszString )
 }
 
 /************************************************************************/
-/*     Find object name and its value in HDF-EOS attributes.            */
+/*     Find object name, class value in HDF-EOS attributes.             */
 /*     Function returns pointer to the string in list next behind       */
 /*     recognized object.                                               */
 /************************************************************************/
 
-char **HDF4Dataset::HDF4EOSGetObject( char **papszAttrList, char **ppszAttrName,
+char **HDF4Dataset::HDF4EOSGetObject( char **papszAttrList,
+                                      char **ppszAttrName,
+                                      char **ppszAttrClass,
                                       char **ppszAttrValue )
 {
     int	    iCount, i, j;
     *ppszAttrName = NULL;
+    *ppszAttrClass = NULL;
     *ppszAttrValue = NULL;
 
     iCount = CSLCount( papszAttrList );
@@ -437,12 +437,16 @@ char **HDF4Dataset::HDF4EOSGetObject( char **papszAttrList, char **ppszAttrName,
 	        if ( EQUAL( papszAttrList[i + j], "END_OBJECT" ) ||
 		     EQUAL( papszAttrList[i + j], "OBJECT" ) )
 	            return &papszAttrList[i + j];
+	        else if ( EQUAL( papszAttrList[i + j], "CLASS" ) )
+	        {
+		    *ppszAttrClass = papszAttrList[i + j + 2];
+                    continue;
+	        }
 	        else if ( EQUAL( papszAttrList[i + j], "VALUE" ) )
 	        {
 		    *ppszAttrName = papszAttrList[i];
 	            *ppszAttrValue = papszAttrList[i + j + 2];
-
-		    return &papszAttrList[i + j + 2];
+                    continue;
 	        }
 	    }
 	}
@@ -498,14 +502,25 @@ char** HDF4Dataset::TranslateHDF4EOSAttributes( int32 iHandle,
     // or
     // (<number>,<number>,...)
     //
-    // Records within objects may follows in any order, objects may contains
-    // other objects (and lacks VALUE record), groups contains other groups
+    // Records within objects could come in any order, objects could contain
+    // other objects (and lack VALUE record), groups could contain other groups
     // and objects. Names of groups and objects are not unique and may repeat.
     // Objects may contains other types of records.
     //
-    // We are interested in OBJECTS structures only.
+    // We are interested in OBJECTS structures only. To avoid multiple items
+    // with the same name, names will be suffixed with the class values, e.g.
+    //
+    //  OBJECT                 = PARAMETERNAME
+    //    CLASS                = "9"
+    //    NUM_VAL              = 1
+    //    VALUE                = "Spectral IR Surf Bidirect Reflectivity"
+    //  END_OBJECT             = PARAMETERNAME
+    //
+    //  will be translated into metadata record:
+    //
+    //  PARAMETERNAME.9 = "Spectral IR Surf Bidirect Reflectivity"
 
-    char *pszAttrName, *pszAttrValue;
+    char *pszAttrName, *pszAttrClass, *pszAttrValue;
     char *pszAddAttrName = NULL;
     char **papszAttrList, **papszAttrs;
     
@@ -513,8 +528,8 @@ char** HDF4Dataset::TranslateHDF4EOSAttributes( int32 iHandle,
     papszAttrs = papszAttrList;
     while ( papszAttrs )
     {
-	papszAttrs =
-	    HDF4EOSGetObject( papszAttrs, &pszAttrName, &pszAttrValue );
+	papszAttrs = HDF4EOSGetObject( papszAttrs, &pszAttrName,
+                                       &pszAttrClass, &pszAttrValue );
 	if ( pszAttrName && pszAttrValue )
 	{
 	    // Now we should recognize special type of HDF EOS metastructures:
@@ -530,8 +545,11 @@ char** HDF4Dataset::TranslateHDF4EOSAttributes( int32 iHandle,
 	    }
 	    else
 	    {
-		papszMetadata =
-		    CSLAddNameValue( papszMetadata, pszAttrName, pszAttrValue );
+                // Add class suffix to the key name if applicable
+		papszMetadata = CSLAddNameValue( papszMetadata,
+                    pszAttrClass ?
+                    CPLSPrintf("%s.%s", pszAttrName, pszAttrClass) : pszAttrName,
+                    pszAttrValue );
 	    }
 	}
     }
@@ -706,8 +724,11 @@ GDALDataset *HDF4Dataset::Open( GDALOpenInfo * poOpenInfo )
     poDS = new HDF4Dataset();
     CPLAcquireMutex(hHDF4Mutex, 1000.0);
 
-    poDS->fp = poOpenInfo->fp;
-    poOpenInfo->fp = NULL;
+    if( poOpenInfo->fpL != NULL )
+    {
+        VSIFCloseL(poOpenInfo->fpL);
+        poOpenInfo->fpL = NULL;
+    }
     
 /* -------------------------------------------------------------------- */
 /*          Open HDF SDS Interface.                                     */
@@ -1208,7 +1229,7 @@ GDALDataset *HDF4Dataset::Open( GDALOpenInfo * poOpenInfo )
 /*                           HDF4UnloadDriver()                         */
 /************************************************************************/
 
-static void HDF4UnloadDriver(GDALDriver* poDriver)
+static void HDF4UnloadDriver(CPL_UNUSED GDALDriver* poDriver)
 {
     if( hHDF4Mutex != NULL )
         CPLDestroyMutex(hHDF4Mutex);
@@ -1232,6 +1253,7 @@ void GDALRegister_HDF4()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "HDF4" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Hierarchical Data Format Release 4" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/hdf4/hdf4dataset.h b/frmts/hdf4/hdf4dataset.h
index 0353e03..98e60d0 100644
--- a/frmts/hdf4/hdf4dataset.h
+++ b/frmts/hdf4/hdf4dataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hdf4dataset.h 26569 2013-10-29 23:51:12Z rouault $
+ * $Id: hdf4dataset.h 28879 2015-04-09 11:05:49Z dron $
  *
  * Project:  Hierarchical Data Format Release 4 (HDF4)
  * Purpose:  Header file for HDF4 datasets reader.
@@ -69,11 +69,10 @@ class HDF4Dataset : public GDALPamDataset
 
     static char **HDF4EOSTokenizeAttrs( const char *pszString );
     static char **HDF4EOSGetObject( char **papszAttrList, char **ppszAttrName,
-                                    char **ppszAttrValue );
+                                    char **ppszAttrClass, char **ppszAttrValue );
      
   protected:
 
-    FILE	*fp;
     int32	hGR, hSD;
     int32	nImages;
     HDF4SubdatasetType iSubdatasetType;
diff --git a/frmts/hdf4/hdf4imagedataset.cpp b/frmts/hdf4/hdf4imagedataset.cpp
index 2433971..92ce1e1 100644
--- a/frmts/hdf4/hdf4imagedataset.cpp
+++ b/frmts/hdf4/hdf4imagedataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hdf4imagedataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: hdf4imagedataset.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  Hierarchical Data Format Release 4 (HDF4)
  * Purpose:  Read subdatasets of HDF4 file.
@@ -47,7 +47,7 @@
 
 #include "nasakeywordhandler.h"
 
-CPL_CVSID("$Id: hdf4imagedataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: hdf4imagedataset.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 CPL_C_START
 void    GDALRegister_HDF4(void);
@@ -59,7 +59,7 @@ CPL_C_END
 const char      *pszGDALSignature =
         "Created with GDAL (http://www.remotesensing.org/gdal/)";
 
-extern void *hHDF4Mutex;
+extern CPLMutex *hHDF4Mutex;
 
 /************************************************************************/
 /* ==================================================================== */
@@ -1219,14 +1219,14 @@ void HDF4ImageDataset::CaptureL1GMTLInfo()
     else
         return;
 
-    dfULX = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LON").c_str(), "0" ));
-    dfULY = atof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LAT").c_str(), "0" ));
-    dfLRX = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LON").c_str(), "0" ));
-    dfLRY = atof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LAT").c_str(), "0" ));
-    dfLLX = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LON").c_str(), "0" ));
-    dfLLY = atof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LAT").c_str(), "0" ));
-    dfURX = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LON").c_str(), "0" ));
-    dfURY = atof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LAT").c_str(), "0" ));
+    dfULX = CPLAtof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LON").c_str(), "0" ));
+    dfULY = CPLAtof(oMTL.GetKeyword((osPrefix+"UL_CORNER_LAT").c_str(), "0" ));
+    dfLRX = CPLAtof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LON").c_str(), "0" ));
+    dfLRY = CPLAtof(oMTL.GetKeyword((osPrefix+"LR_CORNER_LAT").c_str(), "0" ));
+    dfLLX = CPLAtof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LON").c_str(), "0" ));
+    dfLLY = CPLAtof(oMTL.GetKeyword((osPrefix+"LL_CORNER_LAT").c_str(), "0" ));
+    dfURX = CPLAtof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LON").c_str(), "0" ));
+    dfURY = CPLAtof(oMTL.GetKeyword((osPrefix+"UR_CORNER_LAT").c_str(), "0" ));
 
     CPLFree( pszGCPProjection );
     pszGCPProjection = CPLStrdup( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9108\"]],AXIS[\"Lat\",NORTH],AXIS[\"Long\",EAST],AUTHORITY[\"EPSG\",\"4326\"]]" );
@@ -2602,8 +2602,11 @@ GDALDataset *HDF4ImageDataset::Open( GDALOpenInfo * poOpenInfo )
     HDF4ImageDataset    *poDS;
 
     poDS = new HDF4ImageDataset( );
-    poDS->fp = poOpenInfo->fp;
-    poOpenInfo->fp = NULL;
+    if( poOpenInfo->fpL != NULL )
+    {
+        VSIFCloseL(poOpenInfo->fpL);
+        poOpenInfo->fpL = NULL;
+    }
     
     CPLMutexHolderD(&hHDF4Mutex);
 
@@ -2695,7 +2698,7 @@ GDALDataset *HDF4ImageDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Try opening the dataset.                                        */
 /* -------------------------------------------------------------------- */
     int32       iAttribute, nValues, iAttrNumType;
-    double      dfNoData, dfScale, dfOffset;
+    double      dfNoData = 0, dfScale = 1, dfOffset = 0;
     int         bNoDataSet = FALSE, bHaveScale = FALSE, bHaveOffset = FALSE;
     const char  *pszUnits = NULL, *pszDescription = NULL;
 
@@ -3451,7 +3454,7 @@ GDALDataset *HDF4ImageDataset::Open( GDALOpenInfo * poOpenInfo )
               char *pszString = (char *) pszValue;
               while ( *pszValue && i < 6 )
               {
-                  poDS->adfGeoTransform[i++] = strtod(pszString, &pszString);
+                  poDS->adfGeoTransform[i++] = CPLStrtod(pszString, &pszString);
                   pszString++;
               }
               poDS->bHasGeoTransform = TRUE;
@@ -3807,6 +3810,7 @@ void GDALRegister_HDF4Image()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "HDF4Image" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "HDF4 Dataset" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/hdf4/makefile.vc b/frmts/hdf4/makefile.vc
index 7d6a2cd..4e2f3f4 100644
--- a/frmts/hdf4/makefile.vc
+++ b/frmts/hdf4/makefile.vc
@@ -12,6 +12,10 @@ EXTRAFLAGS = 	-I..\pds -I$(HDF4_DIR)\include -Ihdf-eos -DFRMT_hdf4
 EXTRAFLAGS = $(EXTRAFLAGS) -DHDF4_PLUGIN
 !ENDIF
 
+!IF "$(HDF4_HAS_MAXOPENFILES)" == "YES"
+EXTRAFLAGS = $(EXTRAFLAGS) -DHDF4_HAS_MAXOPENFILES
+!ENDIF
+
 
 default:	$(OBJ)
 	xcopy /D  /Y *.obj ..\o
@@ -32,4 +36,4 @@ $(PLUGIN_DLL): $(OBJ)
 
 plugin-install:
 	-mkdir $(PLUGINDIR)
-	$(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR)
\ No newline at end of file
+	$(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR)
diff --git a/frmts/hdf5/GNUmakefile b/frmts/hdf5/GNUmakefile
index 5ca9a10..bd87b66 100644
--- a/frmts/hdf5/GNUmakefile
+++ b/frmts/hdf5/GNUmakefile
@@ -7,7 +7,7 @@ OBJ	=	hdf5dataset.o hdf5imagedataset.o \
 HDFEOS_OPTS	=	
 SUBLIBS 	=
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(HDF5_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(HDF5_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT)) $(SUBLIBS)
 
diff --git a/frmts/hdf5/bagdataset.cpp b/frmts/hdf5/bagdataset.cpp
index 8e6839c..b18e3d2 100644
--- a/frmts/hdf5/bagdataset.cpp
+++ b/frmts/hdf5/bagdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: bagdataset.cpp 27394 2014-05-24 16:37:41Z rouault $
+ * $Id: bagdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Hierarchical Data Format Release 5 (HDF5)
  * Purpose:  Read BAG datasets.
@@ -35,7 +35,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: bagdataset.cpp 27394 2014-05-24 16:37:41Z rouault $");
+CPL_CVSID("$Id: bagdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void    GDALRegister_BAG(void);
@@ -224,7 +224,7 @@ bool BAGRasterBand::Initialize( hid_t hDatasetID, const char *pszName )
         && GH5_FetchAttribute( hDatasetID, "Minimum Elevation Value", 
                                dfMinimum ) )
         bMinMaxSet = true;
-    else if( EQUAL(pszName,"uncertainty") 
+    else if( EQUAL(pszName,"uncertainty")
              && GH5_FetchAttribute( hDatasetID, "Maximum Uncertainty Value", 
                                     dfMaximum ) 
              && GH5_FetchAttribute( hDatasetID, "Minimum Uncertainty Value", 
@@ -652,10 +652,10 @@ void BAGDataset::LoadMetadata()
 
         if( CSLCount(papszCornerTokens ) == 4 )
         {
-            double dfLLX = atof( papszCornerTokens[0] );
-            double dfLLY = atof( papszCornerTokens[1] );
-            double dfURX = atof( papszCornerTokens[2] );
-            double dfURY = atof( papszCornerTokens[3] );
+            double dfLLX = CPLAtof( papszCornerTokens[0] );
+            double dfLLY = CPLAtof( papszCornerTokens[1] );
+            double dfURX = CPLAtof( papszCornerTokens[2] );
+            double dfURY = CPLAtof( papszCornerTokens[3] );
 
             adfGeoTransform[0] = dfLLX;
             adfGeoTransform[1] = (dfURX - dfLLX) / (GetRasterXSize()-1);
@@ -872,6 +872,7 @@ void GDALRegister_BAG( )
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "BAG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Bathymetry Attributed Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/hdf5/hdf5dataset.cpp b/frmts/hdf5/hdf5dataset.cpp
index d7e0b15..abd7910 100644
--- a/frmts/hdf5/hdf5dataset.cpp
+++ b/frmts/hdf5/hdf5dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hdf5dataset.cpp 28365 2015-01-27 10:39:30Z rouault $
+ * $Id: hdf5dataset.cpp 28822 2015-03-30 13:56:19Z rouault $
  *
  * Project:  Hierarchical Data Format Release 5 (HDF5)
  * Purpose:  HDF5 Datasets. Open HDF5 file, fetch metadata and list of
@@ -40,7 +40,7 @@
 #include "cpl_string.h"
 #include "hdf5dataset.h"
 
-CPL_CVSID("$Id: hdf5dataset.cpp 28365 2015-01-27 10:39:30Z rouault $");
+CPL_CVSID("$Id: hdf5dataset.cpp 28822 2015-03-30 13:56:19Z rouault $");
 
 CPL_C_START
 void GDALRegister_HDF5(void);
@@ -65,6 +65,7 @@ void GDALRegister_HDF5()
     {
         poDriver = new GDALDriver();
         poDriver->SetDescription("HDF5");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
                                   "Hierarchical Data Format Release 5");
         poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
@@ -221,7 +222,28 @@ int HDF5Dataset::Identify( GDALOpenInfo * poOpenInfo )
     if( poOpenInfo->pabyHeader )
     {
         if( memcmp(poOpenInfo->pabyHeader,achSignature,8) == 0 )
+        {
+            /* The tests to avoid opening KEA and BAG drivers are not */
+            /* necessary when drivers are built in the core lib, as they */
+            /* are registered after HDF5, but in the case of plugins, we */
+            /* cannot do assumptions about the registration order */
+
+            /* Avoid opening kea files if the kea driver is available */
+            if( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "KEA") &&
+                GDALGetDriverByName("KEA") != NULL )
+            {
+                return FALSE;
+            }
+
+            /* Avoid opening kea files if the bag driver is available */
+            if( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "BAG") &&
+                GDALGetDriverByName("BAG") != NULL )
+            {
+                return FALSE;
+            }
+
             return TRUE;
+        }
 
         if( memcmp(poOpenInfo->pabyHeader,"<HDF_UserBlock>",15) == 0)
         {
@@ -788,7 +810,7 @@ herr_t HDF5AttrIterate( hid_t hH5ObjID,
         }
         else if( H5Tequal( H5T_NATIVE_FLOAT,  hAttrNativeType ) ) {
             for( i=0; i < nAttrElmts; i++ ) {
-                sprintf( szData, "%.8g ",  ((float *)buf)[i] );
+                CPLsprintf( szData, "%.8g ",  ((float *)buf)[i] );
                 if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
                                                             MAX_METADATA_LEN )
                     CPLError( CE_Warning, CPLE_OutOfMemory,
@@ -797,7 +819,7 @@ herr_t HDF5AttrIterate( hid_t hH5ObjID,
         }
         else if( H5Tequal( H5T_NATIVE_DOUBLE, hAttrNativeType ) ) {
             for( i=0; i < nAttrElmts; i++ ) {
-                sprintf( szData, "%.15g ",  ((double *)buf)[i] );
+                CPLsprintf( szData, "%.15g ",  ((double *)buf)[i] );
                 if( CPLStrlcat(szValue, szData, MAX_METADATA_LEN) >=
                                                             MAX_METADATA_LEN )
                     CPLError( CE_Warning, CPLE_OutOfMemory,
diff --git a/frmts/hdf5/hdf5imagedataset.cpp b/frmts/hdf5/hdf5imagedataset.cpp
index 132cc7e..257ad28 100644
--- a/frmts/hdf5/hdf5imagedataset.cpp
+++ b/frmts/hdf5/hdf5imagedataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hdf5imagedataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: hdf5imagedataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Hierarchical Data Format Release 5 (HDF5)
  * Purpose:  Read subdatasets of HDF5 file.
@@ -38,7 +38,7 @@
 #include "hdf5dataset.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: hdf5imagedataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: hdf5imagedataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void GDALRegister_HDF5Image(void);
@@ -648,6 +648,7 @@ void GDALRegister_HDF5Image( )
         poDriver = new GDALDriver( );
 
         poDriver->SetDescription( "HDF5Image" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "HDF5 Dataset" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/hf2/GNUmakefile b/frmts/hf2/GNUmakefile
index 9183eaa..bc4d2b1 100644
--- a/frmts/hf2/GNUmakefile
+++ b/frmts/hf2/GNUmakefile
@@ -3,7 +3,7 @@ OBJ	=	hf2dataset.o
 
 include ../../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/hf2/hf2dataset.cpp b/frmts/hf2/hf2dataset.cpp
index 3b4c414..6d27834 100644
--- a/frmts/hf2/hf2dataset.cpp
+++ b/frmts/hf2/hf2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hf2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: hf2dataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  HF2 driver
  * Purpose:  GDALDataset driver for HF2/HFZ dataset.
@@ -31,7 +31,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: hf2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: hf2dataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_HF2(void);
@@ -330,7 +330,7 @@ int HF2Dataset::Identify( GDALOpenInfo * poOpenInfo)
 
     GDALOpenInfo* poOpenInfoToDelete = NULL;
     /*  GZipped .hf2 files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     CPLString osFilename(poOpenInfo->pszFilename);
     if ((EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "hfz") ||
         (strlen(poOpenInfo->pszFilename) > 6 &&
@@ -341,7 +341,7 @@ int HF2Dataset::Identify( GDALOpenInfo * poOpenInfo)
         osFilename += poOpenInfo->pszFilename;
         poOpenInfo = poOpenInfoToDelete =
                 new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
-                                 poOpenInfo->papszSiblingFiles);
+                                 poOpenInfo->GetSiblingFiles());
     }
 
     if (poOpenInfo->nHeaderBytes < 28)
@@ -374,7 +374,7 @@ GDALDataset *HF2Dataset::Open( GDALOpenInfo * poOpenInfo )
 
     GDALOpenInfo* poOpenInfoToDelete = NULL;
     /*  GZipped .hf2 files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     CPLString osFilename(poOpenInfo->pszFilename);
     if ((EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "hfz") ||
         (strlen(poOpenInfo->pszFilename) > 6 &&
@@ -385,7 +385,7 @@ GDALDataset *HF2Dataset::Open( GDALOpenInfo * poOpenInfo )
         osFilename += poOpenInfo->pszFilename;
         poOpenInfo = poOpenInfoToDelete =
                 new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
-                                 poOpenInfo->papszSiblingFiles);
+                                 poOpenInfo->GetSiblingFiles());
     }
 
 /* -------------------------------------------------------------------- */
@@ -805,7 +805,7 @@ GDALDataset* HF2Dataset::CreateCopy( const char * pszFilename,
 
             if( ABS(dfLinear - 0.3048) < 0.0000001 )
                 nExtentUnits = 2;
-            else if( ABS(dfLinear - atof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
+            else if( ABS(dfLinear - CPLAtof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
                 nExtentUnits = 3;
             else
                 nExtentUnits = 1;
@@ -924,7 +924,7 @@ GDALDataset* HF2Dataset::CreateCopy( const char * pszFilename,
                                                 i * nTileSize, MAX(0, nYSize - (j + 1) * nTileSize),
                                                 nReqXSize, nReqYSize,
                                                 pTileBuffer, nReqXSize, nReqYSize,
-                                                eReqDT, 0, 0);
+                                                eReqDT, 0, 0, NULL);
             if (eErr != CE_None)
                 break;
 
@@ -1081,6 +1081,7 @@ void GDALRegister_HF2()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "HF2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "HF2/HFZ heightfield raster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/hfa/GNUmakefile b/frmts/hfa/GNUmakefile
index 1c05827..27d6dee 100644
--- a/frmts/hfa/GNUmakefile
+++ b/frmts/hfa/GNUmakefile
@@ -6,9 +6,9 @@ HFAOBJ  =	hfaopen.o hfaentry.o hfadictionary.o hfafield.o hfatype.o \
 		hfaband.o hfacompress.o
 OBJ	=	$(HFAOBJ) hfadataset.o hfa_overviews.o
 
-ALL_C_FLAGS	=	$(GDAL_INCLUDE) $(CFLAGS)
+ALL_C_FLAGS	=	 $(CFLAGS)
+
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/hfa/frmt_hfa.html b/frmts/hfa/frmt_hfa.html
index c2b3477..0e28b46 100644
--- a/frmts/hfa/frmt_hfa.html
+++ b/frmts/hfa/frmt_hfa.html
@@ -55,14 +55,19 @@ the original .img) set the global config option HFA_USE_RRD=YES).<p>
 Layer names can be set and retrieved with the GDALSetDescription/GDALGetDescription calls on the Raster Band objects. <p>
 
 <h2>Configuration Options</h2> 
-Currently only one <a href="http://trac.osgeo.org/gdal/wiki/ConfigOptions">runtime configuration option</a> is supported by the HFA driver: 
+Currently two <a href="http://trac.osgeo.org/gdal/wiki/ConfigOptions">runtime configuration options</a> are supported by the HFA driver: 
 
 <ul> 
+<li> <b>HFA_USE_RRD=YES/NO</b> : Whether to force creation of external overviews in Erdas rrd format and with .rrd file name extension (gdaladdo with combination -ro --config USE_RRD YES creates overview file with .aux extension). <p> 
 <li> <b>HFA_COMPRESS_OVR=YES/NO</b> : (GDAL >= 1.11) Whether to create compressed overviews.
 Default is to only create compressed overviews when the file is compressed. <p> 
-This configuration option can be used when building .aux external overviews for a base image not in Erdas Imagine format.
+This configuration option can be used when building external overviews for a base image that is not in Erdas Imagine format. Resulting overview file will use the rrd structure and have .aux extension.
 <pre>
-gdaladdo out.tif --config USE_RRD YES 2 --config HFA_COMPRESS_OVR YES 
+gdaladdo out.tif --config USE_RRD YES --config HFA_COMPRESS_OVR YES 2 4 8
+</pre>
+Erdas Imagine and older ArcGIS versions may recognize overviews for some image formats only if they have .rrd extension. In this case use:
+<pre>
+gdaladdo out.tif --config USE_RRD YES --config HFA_USE_RRD YES --config HFA_COMPRESS_OVR YES 2 4 8
 </pre>
 
 </li>
diff --git a/frmts/hfa/hfa_p.h b/frmts/hfa/hfa_p.h
index c15db95..f330c89 100644
--- a/frmts/hfa/hfa_p.h
+++ b/frmts/hfa/hfa_p.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfa_p.h 23495 2011-12-08 00:16:33Z rouault $
+ * $Id: hfa_p.h 28275 2015-01-02 18:45:58Z rouault $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Private class declarations for the HFA classes used to read
@@ -234,18 +234,23 @@ class HFAEntry
 
     int         bIsMIFObject;
 
+                HFAEntry();
                 HFAEntry( HFAEntry *poContainer,
                           const char *pszMIFObjectPath,
                           const char * pszDictionnary, 
                           const char * pszTypeName,
                           int nDataSizeIn,
                           GByte* pabyDataIn );
+    std::vector<HFAEntry*> FindChildren( const char *pszName, 
+                                         const char *pszType,
+                                         int nRecLevel,
+                                         int* pbErrorDetected);
 
 public:
-    		HFAEntry( HFAInfo_t * psHFA, GUInt32 nPos,
+    static HFAEntry* New( HFAInfo_t * psHFA, GUInt32 nPos,
                           HFAEntry * poParent, HFAEntry *poPrev);
 
-                HFAEntry( HFAInfo_t *psHFA, 
+                 HFAEntry( HFAInfo_t *psHFA, 
                           const char *pszNodeName,
                           const char *pszTypeName,
                           HFAEntry *poParent );
@@ -273,8 +278,7 @@ public:
     HFAEntry	*GetNext();
     HFAEntry    *GetNamedChild( const char * );
     std::vector<HFAEntry*> FindChildren( const char *pszName, 
-                                         const char *pszType,
-                                         int nRecLevel = 0);
+                                         const char *pszType);
 
     GInt32	GetIntField( const char *, CPLErr * = NULL );
     double	GetDoubleField( const char *, CPLErr * = NULL );
diff --git a/frmts/hfa/hfaband.cpp b/frmts/hfa/hfaband.cpp
index b6db31d..1f2d433 100644
--- a/frmts/hfa/hfaband.cpp
+++ b/frmts/hfa/hfaband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfaband.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: hfaband.cpp 28435 2015-02-07 14:35:34Z rouault $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Implementation of the HFABand, for accessing one Eimg_Layer.
@@ -33,7 +33,7 @@
 
 /* include the compression code */
 
-CPL_CVSID("$Id: hfaband.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: hfaband.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 /************************************************************************/
 /*                              HFABand()                               */
@@ -360,20 +360,41 @@ CPLErr	HFABand::LoadBlockInfo()
 
     for( iBlock = 0; iBlock < nBlocks; iBlock++ )
     {
+        CPLErr  eErr = CE_None;
         char	szVarName[64];
         int	nLogvalid, nCompressType;
 
         sprintf( szVarName, "blockinfo[%d].offset", iBlock );
-        panBlockStart[iBlock] = (GUInt32)poDMS->GetIntField( szVarName );
+        panBlockStart[iBlock] = (GUInt32)poDMS->GetIntField( szVarName, &eErr);
+        if( eErr == CE_Failure )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
+            return eErr;
+        }
         
         sprintf( szVarName, "blockinfo[%d].size", iBlock );
-        panBlockSize[iBlock] = poDMS->GetIntField( szVarName );
+        panBlockSize[iBlock] = poDMS->GetIntField( szVarName, &eErr );
+        if( eErr == CE_Failure )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
+            return eErr;
+        }
         
         sprintf( szVarName, "blockinfo[%d].logvalid", iBlock );
-        nLogvalid = poDMS->GetIntField( szVarName );
+        nLogvalid = poDMS->GetIntField( szVarName, &eErr );
+        if( eErr == CE_Failure )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
+            return eErr;
+        }
         
         sprintf( szVarName, "blockinfo[%d].compressionType", iBlock );
-        nCompressType = poDMS->GetIntField( szVarName );
+        nCompressType = poDMS->GetIntField( szVarName, &eErr );
+        if( eErr == CE_Failure )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot read %s", szVarName);
+            return eErr;
+        }
 
         panBlockFlag[iBlock] = 0;
         if( nLogvalid )
@@ -683,7 +704,9 @@ static CPLErr UncompressBlock( GByte *pabyCData, int nSrcBytes,
 /*      Note, floating point values are handled as if they were signed  */
 /*      32-bit integers (bug #1000).                                    */
 /* -------------------------------------------------------------------- */
-                ((float *) pabyDest)[nPixelsOutput] = *((float*)( &nDataValue ));
+                memcpy(&(((float *) pabyDest)[nPixelsOutput]),
+                       &nDataValue,
+                       sizeof(float));
             }
             else
             {
@@ -997,7 +1020,7 @@ void HFABand::NullBlock( void *pData )
     }
     else
     {
-        double adfND[2];
+        GByte abyTmp[16];
         int i;
 
         switch( nDataType )
@@ -1006,9 +1029,9 @@ void HFABand::NullBlock( void *pData )
           {
               nWords = (nWords + 7)/8;
               if( dfNoData != 0.0 )
-                  ((unsigned char *) &adfND)[0] = 0xff;
+                  ((unsigned char *) abyTmp)[0] = 0xff;
               else
-                  ((unsigned char *) &adfND)[0] = 0x00;
+                  ((unsigned char *) abyTmp)[0] = 0x00;
           }
           break;
 
@@ -1016,13 +1039,13 @@ void HFABand::NullBlock( void *pData )
           {
               nWords = (nWords + 3)/4;
               if( dfNoData == 0.0 )
-                  ((unsigned char *) &adfND)[0] = 0x00;
+                  ((unsigned char *) abyTmp)[0] = 0x00;
               else if( dfNoData == 1.0 )
-                  ((unsigned char *) &adfND)[0] = 0x55;
+                  ((unsigned char *) abyTmp)[0] = 0x55;
               else if( dfNoData == 2.0 )
-                  ((unsigned char *) &adfND)[0] = 0xaa;
+                  ((unsigned char *) abyTmp)[0] = 0xaa;
               else
-                  ((unsigned char *) &adfND)[0] = 0xff;
+                  ((unsigned char *) abyTmp)[0] = 0xff;
           }
           break;
 
@@ -1033,58 +1056,80 @@ void HFABand::NullBlock( void *pData )
 
               nWords = (nWords + 1)/2;
                   
-              ((unsigned char *) &adfND)[0] = byVal + (byVal << 4);
+              ((unsigned char *) abyTmp)[0] = byVal + (byVal << 4);
           }
           break;
 
           case EPT_u8:
-            ((unsigned char *) &adfND)[0] = 
+            ((unsigned char *) abyTmp)[0] = 
                 (unsigned char) MAX(0,MIN(255,(int)dfNoData));
             break;
 
           case EPT_s8:
-            ((signed char *) &adfND)[0] = 
+            ((signed char *) abyTmp)[0] = 
                 (signed char) MAX(-128,MIN(127,(int)dfNoData));
             break;
 
           case EPT_u16:
-            ((GUInt16 *) &adfND)[0] = (GUInt16) dfNoData;
+          {
+            GUInt16 nTmp = (GUInt16) dfNoData;
+            memcpy(abyTmp, &nTmp, sizeof(nTmp));
             break;
+          }
 
           case EPT_s16:
-            ((GInt16 *) &adfND)[0] = (GInt16) dfNoData;
+          {
+            GInt16 nTmp = (GInt16) dfNoData;
+            memcpy(abyTmp, &nTmp, sizeof(nTmp));
             break;
+          }
 
           case EPT_u32:
-            ((GUInt32 *) &adfND)[0] = (GUInt32) dfNoData;
+          {
+            GUInt32 nTmp = (GUInt32) dfNoData;
+            memcpy(abyTmp, &nTmp, sizeof(nTmp));
             break;
+          }
 
           case EPT_s32:
-            ((GInt32 *) &adfND)[0] = (GInt32) dfNoData;
+          {
+            GInt32 nTmp = (GInt32) dfNoData;
+            memcpy(abyTmp, &nTmp, sizeof(nTmp));
             break;
+          }
 
           case EPT_f32:
-            ((float *) &adfND)[0] = (float) dfNoData;
+          {
+            float fTmp = (float) dfNoData;
+            memcpy(abyTmp, &fTmp, sizeof(fTmp));
             break;
+          }
 
           case EPT_f64:
-            ((double *) &adfND)[0] = dfNoData;
+          {
+            memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
             break;
+          }
 
           case EPT_c64:
-            ((float *) &adfND)[0] = (float) dfNoData;
-            ((float *) &adfND)[1] = 0;
+          {
+            float fTmp = (float) dfNoData;
+            memcpy(abyTmp, &fTmp, sizeof(fTmp));
+            memset(abyTmp+4, 0, sizeof(float));
             break;
+          }
 
           case EPT_c128:
-            ((double *) &adfND)[0] = dfNoData;
-            ((double *) &adfND)[1] = 0;
+          {
+            memcpy(abyTmp, &dfNoData, sizeof(dfNoData));
+            memset(abyTmp+8, 0, sizeof(double));
             break;
+          }
         }
             
         for( i = 0; i < nWords; i++ )
             memcpy( ((GByte *) pData) + nChunkSize * i, 
-                    &adfND[0], nChunkSize );
+                    abyTmp, nChunkSize );
     }
 
 }
diff --git a/frmts/hfa/hfadataset.cpp b/frmts/hfa/hfadataset.cpp
index 245e53f..d9b302e 100644
--- a/frmts/hfa/hfadataset.cpp
+++ b/frmts/hfa/hfadataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfadataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: hfadataset.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Name:     hfadataset.cpp
  * Project:  Erdas Imagine Driver
@@ -33,8 +33,9 @@
 #include "gdal_rat.h"
 #include "hfa_p.h"
 #include "ogr_spatialref.h"
+#include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: hfadataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: hfadataset.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 CPL_C_START
 void	GDALRegister_HFA(void);
@@ -287,7 +288,10 @@ class CPL_DLL HFADataset : public GDALPamDataset
   protected:
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
   public:
                 HFADataset();
@@ -391,7 +395,7 @@ class HFARasterBand : public GDALPamRasterBand
                                    GDALProgressFunc, void * );
 
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                        int *pnBuckets, int ** ppanHistogram,
+                                        int *pnBuckets, GUIntBig ** ppanHistogram,
                                         int bForce,
                                         GDALProgressFunc, void *pProgressData);
 
@@ -1072,7 +1076,7 @@ CPLErr HFARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iSt
             {
                 // copy them back to doubles
                 for( int i = 0; i < iLength; i++ )
-                    pdfData[i] = atof(papszColData[i]);
+                    pdfData[i] = CPLAtof(papszColData[i]);
             }
 
             // either we allocated them for write, or they were allocated
@@ -1383,7 +1387,7 @@ CPLErr HFARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iSt
             {
                 // convert user supplied strings to doubles
                 for( int i = 0; i < iLength; i++ )
-                    padfColData[i] = atof(papszStrList[i]);
+                    padfColData[i] = CPLAtof(papszStrList[i]);
             }
 
             // call value IO to read/write doubles
@@ -2154,7 +2158,7 @@ void HFARasterBand::ReadAuxMetadata()
                       break;
 
                   char szValueAsString[100];
-                  sprintf( szValueAsString, "%.14g", dfValue );
+                  CPLsprintf( szValueAsString, "%.14g", dfValue );
 
                   if( iValue > 0 )
                       osValueList += ",";
@@ -2239,7 +2243,7 @@ void HFARasterBand::ReadHistogramMetadata()
     if( pszType != NULL && EQUALN( "real", pszType, 4 ) )
         nBinSize = 8;
 
-    int *panHistValues = (int *) VSIMalloc2(sizeof(int), nNumBins);
+    GUIntBig *panHistValues = (GUIntBig *) VSIMalloc2(sizeof(GUIntBig), nNumBins);
     GByte  *pabyWorkBuf = (GByte *) VSIMalloc2(nBinSize, nNumBins);
     
     if (panHistValues == NULL || pabyWorkBuf == NULL)
@@ -2268,11 +2272,12 @@ void HFARasterBand::ReadHistogramMetadata()
     if( nBinSize == 8 ) // source is doubles
     {
         for( i = 0; i < nNumBins; i++ )
-            panHistValues[i] = (int) ((double *) pabyWorkBuf)[i];
+            panHistValues[i] = (GUIntBig) ((double *) pabyWorkBuf)[i];
     }
     else // source is 32bit integers
     {
-        memcpy( panHistValues, pabyWorkBuf, 4 * nNumBins );
+        for( i = 0; i < nNumBins; i++ )
+            panHistValues[i] = (GUIntBig) ((int *) pabyWorkBuf)[i];
     }
 
     CPLFree( pabyWorkBuf );
@@ -2314,7 +2319,7 @@ void HFARasterBand::ReadHistogramMetadata()
         }
 
         int nNewBins = nMaxValue + 1;
-        int *panNewHistValues = (int *) CPLCalloc(sizeof(int),nNewBins);
+        GUIntBig *panNewHistValues = (GUIntBig *) CPLCalloc(sizeof(GUIntBig),nNewBins);
 
         for( i = 0; i < nNumBins; i++ )
             panNewHistValues[(int) padfBinValues[i]] = panHistValues[i];
@@ -2344,7 +2349,7 @@ void HFARasterBand::ReadHistogramMetadata()
     for ( int nBin = 0; nBin < nNumBins; ++nBin )
     {
         char szBuf[32];
-        snprintf( szBuf, 31, "%d", panHistValues[nBin] );
+        snprintf( szBuf, 31, CPL_FRMT_GUIB, panHistValues[nBin] );
         if ( ( nBinValuesLen + strlen( szBuf ) + 2 ) > nBufSize )
         {
             nBufSize *= 2;
@@ -2894,7 +2899,7 @@ CPLErr HFARasterBand::BuildOverviews( const char *pszResampling,
         int i, iResult = -1, nReqOvLevel;
 
         nReqOvLevel = 
-            GDALOvLevelAdjust(panOverviewList[iOverview],nRasterXSize);
+            GDALOvLevelAdjust2(panOverviewList[iOverview],nRasterXSize,nRasterYSize);
 
         for( i = 0; i < nOverviews && papoOvBands[iOverview] == NULL; i++ )
         {
@@ -2906,8 +2911,10 @@ CPLErr HFARasterBand::BuildOverviews( const char *pszResampling,
                 continue;
             }
 
-            nThisOvLevel = (int) (0.5 + GetXSize() 
-                    / (double) papoOverviewBands[i]->GetXSize());
+            nThisOvLevel = GDALComputeOvFactor(papoOverviewBands[i]->GetXSize(),
+                                               GetXSize(),
+                                               papoOverviewBands[i]->GetYSize(),
+                                               GetYSize());
 
             if( nReqOvLevel == nThisOvLevel )
                 papoOvBands[iOverview] = papoOverviewBands[i];
@@ -2965,7 +2972,7 @@ CPLErr HFARasterBand::BuildOverviews( const char *pszResampling,
 
 CPLErr 
 HFARasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                    int *pnBuckets, int ** ppanHistogram,
+                                    int *pnBuckets, GUIntBig ** ppanHistogram,
                                     int bForce,
                                     GDALProgressFunc pfnProgress, 
                                     void *pProgressData)
@@ -2980,8 +2987,8 @@ HFARasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
         const char *pszBinValues = 
             GetMetadataItem( "STATISTICS_HISTOBINVALUES" );
 
-        *pdfMin = atof(GetMetadataItem("STATISTICS_HISTOMIN"));
-        *pdfMax = atof(GetMetadataItem("STATISTICS_HISTOMAX"));
+        *pdfMin = CPLAtof(GetMetadataItem("STATISTICS_HISTOMIN"));
+        *pdfMax = CPLAtof(GetMetadataItem("STATISTICS_HISTOMAX"));
 
         *pnBuckets = 0;
         for( i = 0; pszBinValues[i] != '\0'; i++ )
@@ -2990,12 +2997,12 @@ HFARasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
                 (*pnBuckets)++;
         }
 
-        *ppanHistogram = (int *) CPLCalloc(sizeof(int),*pnBuckets);
+        *ppanHistogram = (GUIntBig *) CPLCalloc(sizeof(GUIntBig),*pnBuckets);
 
         pszNextBin = pszBinValues;
         for( i = 0; i < *pnBuckets; i++ )
         {
-            (*ppanHistogram)[i] = atoi(pszNextBin);
+            (*ppanHistogram)[i] = (GUIntBig) CPLAtoGIntBig(pszNextBin);
 
             while( *pszNextBin != '|' && *pszNextBin != '\0' )
                 pszNextBin++;
@@ -3040,26 +3047,26 @@ GDALRasterAttributeTable *HFARasterBand::GetDefaultRAT()
 {		
     if( poDefaultRAT == NULL )
         poDefaultRAT = new HFARasterAttributeTable(this, "Descriptor_Table" );
- 
+
     return poDefaultRAT;
 }
 
 /************************************************************************/
 /*                            WriteNamedRAT()                            */
 /************************************************************************/
- 
-CPLErr HFARasterBand::WriteNamedRAT( CPL_UNUSED const char *pszName, const GDALRasterAttributeTable *poRAT )
+
+CPLErr HFARasterBand::WriteNamedRAT( CPL_UNUSED const char *pszName,
+                                     CPL_UNUSED const GDALRasterAttributeTable *poRAT )
 {
 /* -------------------------------------------------------------------- */
 /*      Find the requested table.                                       */
 /* -------------------------------------------------------------------- */
     HFAEntry * poDT = hHFA->papoBand[nBand-1]->poNode->GetNamedChild( "Descriptor_Table" );
     if( poDT == NULL || !EQUAL(poDT->GetType(),"Edsc_Table") )
-        poDT = new HFAEntry( hHFA->papoBand[nBand-1]->psInfo, 
+        poDT = new HFAEntry( hHFA->papoBand[nBand-1]->psInfo,
                              "Descriptor_Table", "Edsc_Table",
                              hHFA->papoBand[nBand-1]->poNode );
-   
-  
+
     int nRowCount = poRAT->GetRowCount();
 
     poDT->SetIntField( "numrows", nRowCount );
@@ -4029,10 +4036,10 @@ CPLErr HFADataset::WriteProjection()
 
         for( iUnit = 0; apszUnitMap[iUnit] != NULL; iUnit += 2 )
         {
-            if( fabs(atof(apszUnitMap[iUnit+1]) - dfActualSize) < dfClosestDiff )
+            if( fabs(CPLAtof(apszUnitMap[iUnit+1]) - dfActualSize) < dfClosestDiff )
             {
                 iClosest = iUnit;
-                dfClosestDiff = fabs(atof(apszUnitMap[iUnit+1])-dfActualSize);
+                dfClosestDiff = fabs(CPLAtof(apszUnitMap[iUnit+1])-dfActualSize);
             }
         }
         
@@ -4347,7 +4354,7 @@ HFAPCSStructToWKT( const Eprj_Datum *psDatum,
                 iUnitIndex = 0;
             
             oSRS.SetLinearUnits( pszUnits, 
-                                 atof(apszUnitMap[iUnitIndex+1]) );
+                                 CPLAtof(apszUnitMap[iUnitIndex+1]) );
         }
         else
             oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
@@ -4398,10 +4405,7 @@ HFAPCSStructToWKT( const Eprj_Datum *psDatum,
     if( psPro->proSpheroid.b == 0.0 )
         ((Eprj_ProParameters *) psPro)->proSpheroid.b = 6356752.3;
 
-    if( fabs(psPro->proSpheroid.b - psPro->proSpheroid.a) < 0.001 )
-        dfInvFlattening = 0.0; /* special value for sphere. */
-    else
-        dfInvFlattening = 1.0/(1.0-psPro->proSpheroid.b/psPro->proSpheroid.a);
+    dfInvFlattening = OSRCalcInvFlattening(psPro->proSpheroid.a, psPro->proSpheroid.b);
 
 /* -------------------------------------------------------------------- */
 /*      Handle different projection methods.                            */
@@ -5382,7 +5386,9 @@ CPLErr HFADataset::IRasterIO( GDALRWFlag eRWFlag,
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType,
                               int nBandCount, int *panBandMap, 
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     if( hHFA->papoBand[panBandMap[0]-1]->fpExternal != NULL 
@@ -5390,13 +5396,13 @@ CPLErr HFADataset::IRasterIO( GDALRWFlag eRWFlag,
         return GDALDataset::BlockBasedRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else
         return 
             GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                     pData, nBufXSize, nBufYSize, eBufType, 
                                     nBandCount, panBandMap, 
-                                    nPixelSpace, nLineSpace, nBandSpace );
+                                    nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -5815,9 +5821,9 @@ CPLErr HFADataset::CopyFiles( const char *pszNewName, const char *pszOldName )
 
 GDALDataset *
 HFADataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
-                        CPL_UNUSED int bStrict, char ** papszOptions,
+                        CPL_UNUSED int bStrict,
+                        char ** papszOptions,
                         GDALProgressFunc pfnProgress, void * pProgressData )
-
 {
     HFADataset	*poDS;
     GDALDataType eType = GDT_Byte;
@@ -5988,7 +5994,8 @@ HFADataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             // Histogram
             // -----------------------------------------------------------
 
-            int nBuckets, *panHistogram = NULL;
+            int nBuckets;
+            GUIntBig *panHistogram = NULL;
 
             if( poSrcBand->GetDefaultHistogram( &dfMin, &dfMax, 
                                                 &nBuckets, &panHistogram, 
@@ -5997,7 +6004,7 @@ HFADataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                 == CE_None )
             {
                 CPLString osValue;
-                char *pszBinValues = (char *) CPLCalloc(12,nBuckets+1);
+                char *pszBinValues = (char *) CPLCalloc(20,nBuckets+1);
                 int iBin, nBinValuesLen = 0;
                 double dfBinWidth = (dfMax - dfMin) / nBuckets;
                 
@@ -6015,7 +6022,7 @@ HFADataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                 {
                     
                     strcat( pszBinValues+nBinValuesLen, 
-                            osValue.Printf( "%d", panHistogram[iBin]) );
+                            osValue.Printf( CPL_FRMT_GUIB, panHistogram[iBin]) );
                     strcat( pszBinValues+nBinValuesLen, "|" );
                     nBinValuesLen += strlen(pszBinValues+nBinValuesLen);
                 }
@@ -6068,6 +6075,7 @@ void GDALRegister_HFA()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "HFA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Erdas Imagine Images (.img)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -6103,4 +6111,3 @@ void GDALRegister_HFA()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/hfa/hfaentry.cpp b/frmts/hfa/hfaentry.cpp
index 4a535fd..8d36c46 100644
--- a/frmts/hfa/hfaentry.cpp
+++ b/frmts/hfa/hfaentry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfaentry.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: hfaentry.cpp 28275 2015-01-02 18:45:58Z rouault $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Implementation of the HFAEntry class for reading and relating
@@ -38,31 +38,23 @@
 #include "hfa_p.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: hfaentry.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: hfaentry.cpp 28275 2015-01-02 18:45:58Z rouault $");
 
 /************************************************************************/
 /*                              HFAEntry()                              */
-/*                                                                      */
-/*      Construct an HFAEntry from the source file.                     */
 /************************************************************************/
 
-HFAEntry::HFAEntry( HFAInfo_t * psHFAIn, GUInt32 nPos,
-                    HFAEntry * poParentIn, HFAEntry * poPrevIn )
-
+HFAEntry::HFAEntry()
 {
-    psHFA = psHFAIn;
-    
-    nFilePos = nPos;
+    psHFA = NULL;
+
+    nFilePos = 0;
     bDirty = FALSE;
     bIsMIFObject = FALSE;
 
-    poParent = poParentIn;
-    poPrev = poPrevIn;
+    poParent = NULL;
+    poPrev = NULL;
 
-/* -------------------------------------------------------------------- */
-/*      Initialize fields to null values in case there is a read        */
-/*      error, so the entry will be in a harmless state.                */
-/* -------------------------------------------------------------------- */
     poNext = poChild = NULL;
 
     nDataPos = nDataSize = 0;
@@ -73,6 +65,24 @@ HFAEntry::HFAEntry( HFAInfo_t * psHFAIn, GUInt32 nPos,
     pabyData = NULL;
 
     poType = NULL;
+}
+
+/************************************************************************/
+/*                              HFAEntry()                              */
+/*                                                                      */
+/*      Construct an HFAEntry from the source file.                     */
+/************************************************************************/
+
+HFAEntry* HFAEntry::New( HFAInfo_t * psHFAIn, GUInt32 nPos,
+                         HFAEntry * poParentIn, HFAEntry * poPrevIn )
+
+{
+    HFAEntry* poEntry = new HFAEntry;
+    poEntry->psHFA = psHFAIn;
+    
+    poEntry->nFilePos = nPos;
+    poEntry->poParent = poParentIn;
+    poEntry->poPrev = poPrevIn;
 
 /* -------------------------------------------------------------------- */
 /*      Read the entry information from the file.                       */
@@ -80,37 +90,40 @@ HFAEntry::HFAEntry( HFAInfo_t * psHFAIn, GUInt32 nPos,
     GInt32	anEntryNums[6];
     int		i;
 
-    if( VSIFSeekL( psHFA->fp, nFilePos, SEEK_SET ) == -1
-        || VSIFReadL( anEntryNums, sizeof(GInt32), 6, psHFA->fp ) < 1 )
+    if( VSIFSeekL( poEntry->psHFA->fp, poEntry->nFilePos, SEEK_SET ) == -1
+        || VSIFReadL( anEntryNums, sizeof(GInt32), 6, poEntry->psHFA->fp ) < 1 )
     {
         CPLError( CE_Failure, CPLE_FileIO,
                   "VSIFReadL(%p,6*4) @ %d failed in HFAEntry().\n%s",
-                  psHFA->fp, nFilePos, VSIStrerror( errno ) );
-        return;
+                  poEntry->psHFA->fp, poEntry->nFilePos, VSIStrerror( errno ) );
+        delete poEntry;
+        return NULL;
     }
 
     for( i = 0; i < 6; i++ )
         HFAStandard( 4, anEntryNums + i );
 
-    nNextPos = anEntryNums[0];
-    nChildPos = anEntryNums[3];
-    nDataPos = anEntryNums[4];
-    nDataSize = anEntryNums[5];
+    poEntry->nNextPos = anEntryNums[0];
+    poEntry->nChildPos = anEntryNums[3];
+    poEntry->nDataPos = anEntryNums[4];
+    poEntry->nDataSize = anEntryNums[5];
 
 /* -------------------------------------------------------------------- */
 /*      Read the name, and type.                                        */
 /* -------------------------------------------------------------------- */
-    if( VSIFReadL( szName, 1, 64, psHFA->fp ) < 1
-        || VSIFReadL( szType, 1, 32, psHFA->fp ) < 1 )
+    if( VSIFReadL( poEntry->szName, 1, 64, poEntry->psHFA->fp ) < 1
+        || VSIFReadL( poEntry->szType, 1, 32, poEntry->psHFA->fp ) < 1 )
     {
-        szName[sizeof(szName)-1] = '\0';
-        szType[sizeof(szType)-1] = '\0';
+        poEntry->szName[sizeof(poEntry->szName)-1] = '\0';
+        poEntry->szType[sizeof(poEntry->szType)-1] = '\0';
         CPLError( CE_Failure, CPLE_FileIO,
                   "VSIFReadL() failed in HFAEntry()." );
-        return;
+        delete poEntry;
+        return NULL;
     }
-    szName[sizeof(szName)-1] = '\0';
-    szType[sizeof(szType)-1] = '\0';
+    poEntry->szName[sizeof(poEntry->szName)-1] = '\0';
+    poEntry->szType[sizeof(poEntry->szType)-1] = '\0';
+    return poEntry;
 }
 
 /************************************************************************/
@@ -254,11 +267,10 @@ HFAEntry* HFAEntry::BuildEntryFromMIFObject( HFAEntry *poContainer, const char *
 
 HFAEntry::HFAEntry( CPL_UNUSED HFAEntry * poContainer,
                     CPL_UNUSED const char *pszMIFObjectPath,
-                    const char * pszDictionnary, 
+                    const char * pszDictionnary,
                     const char * pszTypeName,
                     int nDataSizeIn,
                     GByte* pabyDataIn )
-
 {
 /* -------------------------------------------------------------------- */
 /*      Initialize Entry                                                */
@@ -395,7 +407,9 @@ HFAEntry *HFAEntry::GetChild()
 /* -------------------------------------------------------------------- */
     if( poChild == NULL && nChildPos != 0 )
     {
-        poChild = new HFAEntry( psHFA, nChildPos, this, NULL );
+        poChild = HFAEntry::New( psHFA, nChildPos, this, NULL );
+        if( poChild == NULL )
+            nChildPos = 0;
     }
 
     return( poChild );
@@ -430,7 +444,9 @@ HFAEntry *HFAEntry::GetNext()
             return NULL;
         }
              
-        poNext = new HFAEntry( psHFA, nNextPos, poParent, this );
+        poNext = HFAEntry::New( psHFA, nNextPos, poParent, this );
+        if( poNext == NULL )
+            nNextPos = 0;
     }
 
     return( poNext );
@@ -584,22 +600,23 @@ void HFAEntry::DumpFieldValues( FILE * fp, const char * pszPrefix )
 
 std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
                                                const char *pszType,
-                                               int nRecLevel )
+                                               int nRecLevel,
+                                               int* pbErrorDetected )
 
 {
     std::vector<HFAEntry*> apoChildren;
     HFAEntry *poEntry;
 
+    if( *pbErrorDetected )
+        return apoChildren;
     if( nRecLevel == 50 )
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "Bad entry structure: recursion detected !");
+        *pbErrorDetected = TRUE;
         return apoChildren;
     }
 
-    if( this == NULL )
-        return apoChildren;
-    
     for( poEntry = GetChild(); poEntry != NULL; poEntry = poEntry->GetNext() )
     {
         std::vector<HFAEntry*> apoEntryChildren;
@@ -609,7 +626,10 @@ std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
             && (pszType == NULL || EQUAL(poEntry->GetType(),pszType)) )
             apoChildren.push_back( poEntry );
 
-        apoEntryChildren = poEntry->FindChildren( pszName, pszType, nRecLevel + 1 );
+        apoEntryChildren = poEntry->FindChildren( pszName, pszType, nRecLevel + 1,
+                                                  pbErrorDetected);
+        if( *pbErrorDetected )
+            return apoChildren;
 
         for( i = 0; i < apoEntryChildren.size(); i++ )
             apoChildren.push_back( apoEntryChildren[i] );
@@ -618,6 +638,14 @@ std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
     return apoChildren;
 }
 
+std::vector<HFAEntry*> HFAEntry::FindChildren( const char *pszName,
+                                               const char *pszType)
+
+{
+    int bErrorDetected = FALSE;
+    return FindChildren(pszName, pszType, 0, &bErrorDetected);
+}
+
 /************************************************************************/
 /*                           GetNamedChild()                            */
 /************************************************************************/
@@ -711,10 +739,9 @@ int HFAEntry::GetFieldValue( const char * pszFieldPath,
 /************************************************************************/
 
 int HFAEntry::GetFieldCount( const char * pszFieldPath, CPL_UNUSED CPLErr *peErr )
-
 {
     HFAEntry	*poEntry = this;
-    
+
 /* -------------------------------------------------------------------- */
 /*      Is there a node path in this string?                            */
 /* -------------------------------------------------------------------- */
@@ -1102,4 +1129,3 @@ void HFAEntry::MarkDirty()
     bDirty = TRUE;
     psHFA->bTreeDirty = TRUE;
 }
-
diff --git a/frmts/hfa/hfafield.cpp b/frmts/hfa/hfafield.cpp
index 5c1417e..26b1f48 100644
--- a/frmts/hfa/hfafield.cpp
+++ b/frmts/hfa/hfafield.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfafield.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: hfafield.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Implementation of the HFAField class for managing information
@@ -31,7 +31,7 @@
 
 #include "hfa_p.h"
 
-CPL_CVSID("$Id: hfafield.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: hfafield.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 #define MAX_ENTRY_REPORT   16
                            
@@ -493,7 +493,7 @@ HFAField::SetInstValue( const char * pszField, int nIndexValue,
     if( chReqType == 's' )
     {
         nIntValue = atoi((char *) pValue);
-        dfDoubleValue = atof((char *) pValue);
+        dfDoubleValue = CPLAtof((char *) pValue);
     }
     else if( chReqType == 'd' )
     {
@@ -1261,7 +1261,7 @@ HFAField::ExtractInstValue( const char * pszField, int nIndexValue,
             /* not go here, but that can happen if the file is corrupted */
             /* so reserve the first 8 bytes before the string to contain null bytes */
             memset(szNumberString, 0, 8);
-            sprintf( szNumberString + 8, "%.14g", dfDoubleRet );
+            CPLsprintf( szNumberString + 8, "%.14g", dfDoubleRet );
             pszStringRet = szNumberString + 8;
         }
         
diff --git a/frmts/hfa/hfaopen.cpp b/frmts/hfa/hfaopen.cpp
index 86a9fd1..0026775 100644
--- a/frmts/hfa/hfaopen.cpp
+++ b/frmts/hfa/hfaopen.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfaopen.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: hfaopen.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Supporting functions for HFA (.img) ... main (C callable) API
@@ -42,7 +42,7 @@
 #include <limits.h>
 #include <vector>
 
-CPL_CVSID("$Id: hfaopen.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: hfaopen.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 
 static const char *apszAuxMetadataItems[] = {
@@ -208,7 +208,12 @@ HFAHandle HFAOpen( const char * pszFilename, const char * pszAccess )
 /* -------------------------------------------------------------------- */
 /*      Instantiate the root entry.                                     */
 /* -------------------------------------------------------------------- */
-    psInfo->poRoot = new HFAEntry( psInfo, psInfo->nRootPos, NULL, NULL );
+    psInfo->poRoot = HFAEntry::New( psInfo, psInfo->nRootPos, NULL, NULL );
+    if( psInfo->poRoot == NULL )
+    {
+        CPLFree(psInfo);
+        return NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Read the dictionary                                             */
@@ -2034,17 +2039,17 @@ CPLErr HFAFlush( HFAHandle hHFA )
 /*      Suitable for use with primary layers, and overviews.            */
 /************************************************************************/
 
-int 
+int
 HFACreateLayer( HFAHandle psInfo, HFAEntry *poParent,
                 const char *pszLayerName,
-                int bOverview, int nBlockSize, 
-                int bCreateCompressed, int bCreateLargeRaster, 
+                int bOverview, int nBlockSize,
+                int bCreateCompressed, int bCreateLargeRaster,
                 int bDependentLayer,
-                int nXSize, int nYSize, int nDataType, 
+                int nXSize, int nYSize, int nDataType,
                 CPL_UNUSED char **papszOptions,
-                
+
                 // these are only related to external (large) files
-                GIntBig nStackValidFlagsOffset, 
+                GIntBig nStackValidFlagsOffset,
                 GIntBig nStackDataOffset,
                 int nStackCount, int nStackIndex )
 
@@ -2313,7 +2318,8 @@ HFAHandle HFACreate( const char * pszFilename,
     {
         nBlockSize = atoi( pszValue );
         // check for sane values
-        if ( ( nBlockSize < 32 ) || (nBlockSize > 2048) )
+        if ( (( nBlockSize < 32 ) || (nBlockSize > 2048))
+            && !CSLTestBoolean(CPLGetConfigOption("FORCE_BLOCKSIZE", "NO")) )
         {
             nBlockSize = 64;
         }
@@ -2368,11 +2374,11 @@ HFAHandle HFACreate( const char * pszFilename,
 /* -------------------------------------------------------------------- */
 /*      Check whether we should create external large file with         */
 /*      image.  We create a spill file if the amount of imagery is      */
-/*      close to 2GB.  We don't check the amount of auxilary            */
+/*      close to 2GB.  We don't check the amount of auxiliary            */
 /*      information, so in theory if there were an awful lot of         */
 /*      non-imagery data our approximate size could be smaller than     */
 /*      the file will actually we be.  We leave room for 10MB of        */
-/*      auxilary data.                                                  */
+/*      auxiliary data.                                                  */
 /*      We can also force spill file creation using option              */
 /*      SPILL_FILE=YES.                                                 */
 /* -------------------------------------------------------------------- */
@@ -2758,7 +2764,7 @@ CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
             {
               case 'd':
               {
-                  double dfValue = atof( pszValue );
+                  double dfValue = CPLAtof( pszValue );
                   poEntry->SetDoubleField( pszFieldName, dfValue );
               }
               break;
@@ -2781,8 +2787,8 @@ CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
         }
         else if ( EQUALN( "STATISTICS_HISTOBINVALUES", pszKey, strlen(pszKey) ) )
         {
-            pszBinValues = strdup( pszValue );
-	}
+            pszBinValues = CPLStrdup( pszValue );
+        }
         else
             papszGDALMD = CSLAddString( papszGDALMD, papszMD[iColumn] );
 
@@ -2847,7 +2853,7 @@ CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
                 {
                     *pszEnd = 0;
                     VSIFSeekL( hHFA->fp, nOffset + 8*nBin, SEEK_SET );
-                    double nValue = atof( pszWork );
+                    double nValue = CPLAtof( pszWork );
                     HFAStandard( 8, &nValue );
 
                     VSIFWriteL( (void *)&nValue, 1, 8, hHFA->fp );
@@ -2898,7 +2904,7 @@ CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
                         } else {
                             // Histogram were written as doubles, as is now the default behaviour
                             VSIFSeekL( hHFA->fp, nOffset + 8*nBin, SEEK_SET );
-                            double nValue = atof( pszWork );
+                            double nValue = CPLAtof( pszWork );
                             HFAStandard( 8, &nValue );
                             VSIFWriteL( (void *)&nValue, 1, 8, hHFA->fp );
                         }
@@ -2907,7 +2913,7 @@ CPLErr HFASetMetadata( HFAHandle hHFA, int nBand, char **papszMD )
                 }
             }
         }
-        free( pszBinValues );
+        CPLFree( pszBinValues );
     }
 
 /* -------------------------------------------------------------------- */
diff --git a/frmts/hfa/hfatype.cpp b/frmts/hfa/hfatype.cpp
index 172f3b4..da95e36 100644
--- a/frmts/hfa/hfatype.cpp
+++ b/frmts/hfa/hfatype.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hfatype.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: hfatype.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Erdas Imagine (.img) Translator
  * Purpose:  Implementation of the HFAType class, for managing one type
@@ -31,7 +31,7 @@
 
 #include "hfa_p.h"
 
-CPL_CVSID("$Id: hfatype.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: hfatype.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -285,8 +285,9 @@ HFAType::SetInstValue( const char * pszFieldPath,
 
 int
 HFAType::GetInstCount( const char * pszFieldPath,
-                       GByte *pabyData, CPL_UNUSED GUInt32 nDataOffset, int nDataSize )
-
+                       GByte *pabyData,
+                       CPL_UNUSED GUInt32 nDataOffset,
+                       int nDataSize )
 {
     /* int		nArrayIndex = 0; */
     int		nNameLen, iField, nByteOffset;
diff --git a/frmts/idrisi/GNUmakefile b/frmts/idrisi/GNUmakefile
index 936f7e9..3258dec 100644
--- a/frmts/idrisi/GNUmakefile
+++ b/frmts/idrisi/GNUmakefile
@@ -4,7 +4,7 @@ include $(GDAL_ROOT)/GDALmake.opt
 
 OBJ	=	IdrisiDataset.o 
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/idrisi/IdrisiDataset.cpp b/frmts/idrisi/IdrisiDataset.cpp
index 682917f..ac56d28 100644
--- a/frmts/idrisi/IdrisiDataset.cpp
+++ b/frmts/idrisi/IdrisiDataset.cpp
@@ -1,5 +1,5 @@
 /*****************************************************************************
-* $Id: IdrisiDataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+* $Id: IdrisiDataset.cpp 27942 2014-11-11 00:57:41Z rouault $
 *
 * Project:  Idrisi Raster Image File Driver
 * Purpose:  Read/write Idrisi Raster Image Format RST
@@ -42,7 +42,7 @@
 #include "gdal_rat.h"
 #include "idrisi.h"
 
-CPL_CVSID( "$Id: IdrisiDataset.cpp 27044 2014-03-16 23:41:27Z rouault $" );
+CPL_CVSID( "$Id: IdrisiDataset.cpp 27942 2014-11-11 00:57:41Z rouault $" );
 
 CPL_C_START
 void GDALRegister_IDRISI( void);
@@ -56,7 +56,7 @@ CPL_C_END
 
 //----- Safe numeric conversion, NULL as zero
 #define atoi_nz(s) (s == NULL ? (int)      0 : atoi(s))
-#define atof_nz(s) (s == NULL ? (double) 0.0 : atof(s))
+#define CPLAtof_nz(s) (s == NULL ? (double) 0.0 : CPLAtof(s))
 
 //----- file extensions:
 #define extRST          "rst"
@@ -617,7 +617,7 @@ IdrisiDataset::~IdrisiDataset()
 
 GDALDataset *IdrisiDataset::Open( GDALOpenInfo *poOpenInfo )
 {
-    if(  ( poOpenInfo->fp == NULL ) || (EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), extRST ) == FALSE ))//modified
+    if(  ( poOpenInfo->fpL == NULL ) || (EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), extRST ) == FALSE ))//modified
         return NULL;
 
     // --------------------------------------------------------------------
@@ -755,11 +755,11 @@ GDALDataset *IdrisiDataset::Open( GDALOpenInfo *poOpenInfo )
     {
         double dfMinX, dfMaxX, dfMinY, dfMaxY, dfUnit, dfXPixSz, dfYPixSz;
 
-        dfMinX = atof_nz( pszMinX );
-        dfMaxX = atof_nz( pszMaxX );
-        dfMinY = atof_nz( pszMinY );
-        dfMaxY = atof_nz( pszMaxY );
-        dfUnit = atof_nz( pszUnit );
+        dfMinX = CPLAtof_nz( pszMinX );
+        dfMaxX = CPLAtof_nz( pszMaxX );
+        dfMinY = CPLAtof_nz( pszMinY );
+        dfMaxY = CPLAtof_nz( pszMaxY );
+        dfUnit = CPLAtof_nz( pszUnit );
 
         dfMinX = dfMinX * dfUnit; 
         dfMaxX = dfMaxX * dfUnit; 
@@ -1712,7 +1712,7 @@ double IdrisiRasterBand::GetMinimum( int *pbSuccess )
         return GDALPamRasterBand::GetMinimum(pbSuccess);
 
     double adfMinValue[3];
-    sscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMIN_VALUE ), "%lf %lf %lf", 
+    CPLsscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMIN_VALUE ), "%lf %lf %lf", 
         &adfMinValue[0], &adfMinValue[1], &adfMinValue[2] );
 
     if( pbSuccess )
@@ -1735,7 +1735,7 @@ double IdrisiRasterBand::GetMaximum( int *pbSuccess )
         return GDALPamRasterBand::GetMaximum(pbSuccess);
 
     double adfMaxValue[3];
-    sscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMAX_VALUE ), "%lf %lf %lf", 
+    CPLsscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMAX_VALUE ), "%lf %lf %lf", 
         &adfMaxValue[0], &adfMaxValue[1], &adfMaxValue[2] );
 
     if( pbSuccess )
@@ -1771,7 +1771,7 @@ double IdrisiRasterBand::GetNoDataValue( int *pbSuccess )
 
     if( ! EQUAL( pszFlagDefn, "none" ) )
     {
-        dfNoData = atof_nz( CSLFetchNameValue( poGDS->papszRDC, rdcFLAG_VALUE ) );
+        dfNoData = CPLAtof_nz( CSLFetchNameValue( poGDS->papszRDC, rdcFLAG_VALUE ) );
         if( pbSuccess )
             *pbSuccess = TRUE;
     }
@@ -2020,9 +2020,9 @@ CPLErr IdrisiRasterBand::SetMinMax( double dfMin, double dfMax )
     double adfMax[3] = {0.0, 0.0, 0.0};
 
     if (CSLFetchNameValue( poGDS->papszRDC, rdcMIN_VALUE ) != NULL)
-        sscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMIN_VALUE ), "%lf %lf %lf", &adfMin[0], &adfMin[1], &adfMin[2] );
+        CPLsscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMIN_VALUE ), "%lf %lf %lf", &adfMin[0], &adfMin[1], &adfMin[2] );
     if (CSLFetchNameValue( poGDS->papszRDC, rdcMAX_VALUE ) != NULL)
-        sscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMAX_VALUE ), "%lf %lf %lf", &adfMax[0], &adfMax[1], &adfMax[2] );
+        CPLsscanf( CSLFetchNameValue( poGDS->papszRDC, rdcMAX_VALUE ), "%lf %lf %lf", &adfMax[0], &adfMax[1], &adfMax[2] );
 
     adfMin[nBand - 1] = dfMin;
     adfMax[nBand - 1] = dfMax;
@@ -2543,27 +2543,27 @@ CPLErr IdrisiGeoReference2Wkt( const char* pszFilename,
     char *pszProjName           = CPLStrdup( CSLFetchNameValue( papszRef, refPROJECTION ) );
     char *pszDatum              = CPLStrdup( CSLFetchNameValue( papszRef, refDATUM ) );
     char *pszEllipsoid          = CPLStrdup( CSLFetchNameValue( papszRef, refELLIPSOID ) );
-    double dfCenterLat          = atof_nz( CSLFetchNameValue( papszRef, refORIGIN_LAT ) );
-    double dfCenterLong         = atof_nz( CSLFetchNameValue( papszRef, refORIGIN_LONG ) );
-    double dfSemiMajor          = atof_nz( CSLFetchNameValue( papszRef, refMAJOR_SAX ) );
-    double dfSemiMinor          = atof_nz( CSLFetchNameValue( papszRef, refMINOR_SAX ) );
-    double dfFalseEasting       = atof_nz( CSLFetchNameValue( papszRef, refORIGIN_X ) );
-    double dfFalseNorthing      = atof_nz( CSLFetchNameValue( papszRef, refORIGIN_Y ) );
-    double dfStdP1              = atof_nz( CSLFetchNameValue( papszRef, refSTANDL_1 ) );
-    double dfStdP2              = atof_nz( CSLFetchNameValue( papszRef, refSTANDL_2 ) );
+    double dfCenterLat          = CPLAtof_nz( CSLFetchNameValue( papszRef, refORIGIN_LAT ) );
+    double dfCenterLong         = CPLAtof_nz( CSLFetchNameValue( papszRef, refORIGIN_LONG ) );
+    double dfSemiMajor          = CPLAtof_nz( CSLFetchNameValue( papszRef, refMAJOR_SAX ) );
+    double dfSemiMinor          = CPLAtof_nz( CSLFetchNameValue( papszRef, refMINOR_SAX ) );
+    double dfFalseEasting       = CPLAtof_nz( CSLFetchNameValue( papszRef, refORIGIN_X ) );
+    double dfFalseNorthing      = CPLAtof_nz( CSLFetchNameValue( papszRef, refORIGIN_Y ) );
+    double dfStdP1              = CPLAtof_nz( CSLFetchNameValue( papszRef, refSTANDL_1 ) );
+    double dfStdP2              = CPLAtof_nz( CSLFetchNameValue( papszRef, refSTANDL_2 ) );
     double dfScale;
     double adfToWGS84[3] = { 0.0, 0.0, 0.0 };
 
     const char* pszToWGS84 = CSLFetchNameValue( papszRef, refDELTA_WGS84 );
     if (pszToWGS84)
-        sscanf( pszToWGS84, "%lf %lf %lf",
+        CPLsscanf( pszToWGS84, "%lf %lf %lf",
             &adfToWGS84[0], &adfToWGS84[1], &adfToWGS84[2] );
 
     const char* pszSCALE_FAC = CSLFetchNameValue( papszRef, refSCALE_FAC );
     if( pszSCALE_FAC == NULL || EQUAL( pszSCALE_FAC, "na" ) )
         dfScale = 1.0;
     else
-        dfScale = atof_nz( pszSCALE_FAC );
+        dfScale = CPLAtof_nz( pszSCALE_FAC );
 
     CSLDestroy( papszRef );
 
@@ -3244,7 +3244,7 @@ int GetUnitIndex( const char *pszUnitName )
 
 int GetToMeterIndex( const char *pszToMeter )
 {
-    double dfToMeter = atof_nz(pszToMeter);
+    double dfToMeter = CPLAtof_nz(pszToMeter);
 
     if( dfToMeter != 0.0 )
     {
@@ -3343,6 +3343,7 @@ void GDALRegister_IDRISI()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "RST" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, rstVERSION );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_Idrisi.html" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, extRST );
diff --git a/frmts/ilwis/GNUmakefile b/frmts/ilwis/GNUmakefile
index 0b070bd..4d30288 100644
--- a/frmts/ilwis/GNUmakefile
+++ b/frmts/ilwis/GNUmakefile
@@ -3,8 +3,6 @@ include ../../GDALmake.opt
 
 OBJ	=	ilwisdataset.o ilwiscoordinatesystem.o
 
-CPPFLAGS	=	$(GDAL_INCLUDE)
-
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
 clean:
diff --git a/frmts/ilwis/ilwiscoordinatesystem.cpp b/frmts/ilwis/ilwiscoordinatesystem.cpp
index 3f6696b..d94eca7 100644
--- a/frmts/ilwis/ilwiscoordinatesystem.cpp
+++ b/frmts/ilwis/ilwiscoordinatesystem.cpp
@@ -262,7 +262,7 @@ double ReadPrjParms(string section, string entry, string filename)
     string str = ReadElement(section, entry, filename);
     //string str="";
     if (str.length() != 0)
-        return atof(str.c_str());
+        return CPLAtof(str.c_str());
     else
         return 0;
 }
diff --git a/frmts/ilwis/ilwisdataset.cpp b/frmts/ilwis/ilwisdataset.cpp
index ac9ebee..b0ba8aa 100644
--- a/frmts/ilwis/ilwisdataset.cpp
+++ b/frmts/ilwis/ilwisdataset.cpp
@@ -301,7 +301,7 @@ bool WriteElement(string sSection, string sEntry,
         return false;
 
     char strdouble[45];
-    sprintf(strdouble, "%.6f", dValue);
+    CPLsprintf(strdouble, "%.6f", dValue);
     string sValue = string(strdouble);
     return WriteElement(sSection, sEntry, fn, sValue) != 0;
 }
@@ -503,21 +503,21 @@ void ILWISDataset::CollectTransformCoef(string &pszRefName)
             string sMaxY = ReadElement("GeoRefCorners", "MaxY", pszRefName);
 				
             //Calculate pixel size in X and Y direction from the extent
-            double deltaX = atof(sMaxX.c_str()) - atof(sMinX.c_str());
-            double deltaY = atof(sMaxY.c_str()) - atof(sMinY.c_str());
+            double deltaX = CPLAtof(sMaxX.c_str()) - CPLAtof(sMinX.c_str());
+            double deltaY = CPLAtof(sMaxY.c_str()) - CPLAtof(sMinY.c_str());
 
             double PixelSizeX = deltaX / (double)nRasterXSize;
             double PixelSizeY = deltaY / (double)nRasterYSize;
 				
             if (EQUAL(IsCorner.c_str(),"Yes"))
             {
-                adfGeoTransform[0] = atof(sMinX.c_str());
-                adfGeoTransform[3] = atof(sMaxY.c_str());
+                adfGeoTransform[0] = CPLAtof(sMinX.c_str());
+                adfGeoTransform[3] = CPLAtof(sMaxY.c_str());
             }
             else
             {
-                adfGeoTransform[0] = atof(sMinX.c_str()) - PixelSizeX/2.0;
-                adfGeoTransform[3] = atof(sMaxY.c_str()) + PixelSizeY/2.0;
+                adfGeoTransform[0] = CPLAtof(sMinX.c_str()) - PixelSizeX/2.0;
+                adfGeoTransform[3] = CPLAtof(sMaxY.c_str()) + PixelSizeY/2.0;
             }
 
             adfGeoTransform[1] = PixelSizeX;
@@ -816,7 +816,7 @@ GDALDataset *ILWISDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -941,7 +941,7 @@ GDALDataset *ILWISDataset::Create(const char* pszFilename,
         adfMinMax[0] = -9999999.9;
         adfMinMax[1] = 9999999.9;
         char strdouble[45];
-        sprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
+        CPLsprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
         string range = string(strdouble);
         WriteElement("BaseMap", "Range", pszODFName, range);
 
@@ -1116,7 +1116,7 @@ ILWISDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         {
             // only write a range if we got a correct one from the source dataset (otherwise ILWIS can't show the map properly)
             char strdouble[45];
-            sprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
+            CPLsprintf(strdouble, "%.3f:%.3f:%3f:offset=0", adfMinMax[0], adfMinMax[1],stepsize);
             string range = string(strdouble);
             WriteElement("BaseMap", "Range", pszODFName, range);
         }
@@ -1143,7 +1143,7 @@ ILWISDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         {
             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                      pData, nXSize, 1, eType, 
-                                     0, 0 );
+                                     0, 0, NULL );
 
             if( eErr == CE_None )
             {
@@ -1369,7 +1369,7 @@ CPLErr ILWISRasterBand::GetILWISInfo(string pszFileName)
     psInfo.stDomain = "";
 
     // ILWIS has several (currently 22) predefined "system-domains", that influence the data-type
-    // The user can also create his own domains. The possible types for these are "class", "identifier", "bool" and "value"
+    // The user can also create domains. The possible types for these are "class", "identifier", "bool" and "value"
     // The last one has Type=DomainValue
     // Here we make an effort to determine the most-compact gdal-type (eDataType) that is suitable
     // for the data in the current ILWIS band.
@@ -1833,7 +1833,7 @@ static double doubleConv(const char* s)
 
     if (strlen(begin) == 0) return rUNDEF;
     errno = 0;
-    double r = strtod(begin, &endptr);
+    double r = CPLStrtod(begin, &endptr);
     if ((0 == *endptr) && (errno==0))
         return r;
     while (*endptr != 0) { // check trailing spaces
@@ -1873,11 +1873,11 @@ ValueRange::ValueRange(string sRng)
     p2 = strchr(sRange, ':');
     if (p2 != 0) {
         *p2 = 0;
-        _rLo = atof(sRange);
-        _rHi = atof(p2+1);
+        _rLo = CPLAtof(sRange);
+        _rHi = CPLAtof(p2+1);
     }
     else {
-        _rLo = atof(sRange);
+        _rLo = CPLAtof(sRange);
         _rHi = _rLo;
     }  
     init(_r0);
@@ -1990,11 +1990,11 @@ string ValueRange::ToString()
 {
     char buffer[200];
     if (fabs(get_rLo()) > 1.0e20 || fabs(get_rHi()) > 1.0e20)
-        sprintf(buffer, "%g:%g:%f:offset=%g", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
+        CPLsprintf(buffer, "%g:%g:%f:offset=%g", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
     else if (get_iDec() >= 0)
-        sprintf(buffer, "%.*f:%.*f:%.*f:offset=%.0f", get_iDec(), get_rLo(), get_iDec(), get_rHi(), get_iDec(), get_rStep(), get_rRaw0());
+        CPLsprintf(buffer, "%.*f:%.*f:%.*f:offset=%.0f", get_iDec(), get_rLo(), get_iDec(), get_rHi(), get_iDec(), get_rStep(), get_rRaw0());
     else
-        sprintf(buffer, "%f:%f:%f:offset=%.0f", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
+        CPLsprintf(buffer, "%f:%f:%f:offset=%.0f", get_rLo(), get_rHi(), get_rStep(), get_rRaw0());
     return string(buffer);
 }
 
@@ -2045,6 +2045,7 @@ void GDALRegister_ILWIS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ILWIS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ILWIS Raster Map" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mpr/mpl" );
diff --git a/frmts/ingr/GNUmakefile b/frmts/ingr/GNUmakefile
index 0f3f061..ef5649c 100644
--- a/frmts/ingr/GNUmakefile
+++ b/frmts/ingr/GNUmakefile
@@ -4,7 +4,7 @@ include $(GDAL_ROOT)/GDALmake.opt
 
 OBJ	=	IntergraphDataset.o IntergraphBand.o IngrTypes.o JpegHelper.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 -I../gtiff $(CPPFLAGS)
 
 ifeq ($(TIFF_SETTING),internal)
 ifeq ($(RENAME_INTERNAL_LIBTIFF_SYMBOLS),yes)
diff --git a/frmts/ingr/IngrTypes.cpp b/frmts/ingr/IngrTypes.cpp
index 8f45bf6..b828201 100644
--- a/frmts/ingr/IngrTypes.cpp
+++ b/frmts/ingr/IngrTypes.cpp
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: IngrTypes.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: IngrTypes.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Intergraph Raster Format support
  * Purpose:  Types support function
@@ -817,7 +817,8 @@ INGR_VirtualFile CPL_STDCALL INGR_CreateVirtualFile( const char *pszFilename,
     case CCITTGroup4:
         {
             REVERSEBITSBUFFER( pabyBuffer, nBufferSize );
-            TIFF *hTIFF = VSI_TIFFOpen( hVirtual.pszFileName, "w+" );
+            VSILFILE *fpL = VSIFOpenL( hVirtual.pszFileName, "w+" );
+            TIFF *hTIFF = VSI_TIFFOpen( hVirtual.pszFileName, "w+", fpL );
             TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH,      nXSize );
             TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH,     nYSize );
             TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE,   1 );
@@ -831,6 +832,7 @@ INGR_VirtualFile CPL_STDCALL INGR_CreateVirtualFile( const char *pszFilename,
             TIFFWriteRawStrip( hTIFF, 0, pabyBuffer, nBufferSize );
             TIFFWriteDirectory( hTIFF );
             TIFFClose( hTIFF );
+            VSIFCloseL(fpL);
             break;
         }
     default:
diff --git a/frmts/ingr/IngrTypes.h b/frmts/ingr/IngrTypes.h
index 24b2906..70c9ffb 100644
--- a/frmts/ingr/IngrTypes.h
+++ b/frmts/ingr/IngrTypes.h
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: IngrTypes.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: IngrTypes.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Intergraph Raster Format support
  * Purpose:  Types, constants and functions definition
@@ -505,7 +505,7 @@ INGR_DecodeRunLengthPaletted( GByte *pabySrcData, GByte *pabyDstData,
 //    GeoTiff in memory helper
 //  ------------------------------------------------------------------
 
-TIFF* VSI_TIFFOpen(const char* name, const char* mode);
+#include "tifvsi.h"
 
 INGR_VirtualFile CPL_STDCALL INGR_CreateVirtualFile( const char *pszFilename,
                                                      INGR_Format eFormat,
diff --git a/frmts/ingr/IntergraphBand.cpp b/frmts/ingr/IntergraphBand.cpp
index 415bfd3..3cb1422 100644
--- a/frmts/ingr/IntergraphBand.cpp
+++ b/frmts/ingr/IntergraphBand.cpp
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: IntergraphBand.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: IntergraphBand.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Intergraph Raster Format support
  * Purpose:  Read/Write Intergraph Raster Format, band support
@@ -952,7 +952,7 @@ CPLErr IntergraphBitmapBand::IReadBlock( int nBlockXOff,
 
     poGDS->hVirtual.poBand->RasterIO( GF_Read, 0, 0, 
         nVirtualXSize, nVirtualYSize, pImage, 
-        nVirtualXSize, nVirtualYSize, GDT_Byte, 0, 0 );
+        nVirtualXSize, nVirtualYSize, GDT_Byte, 0, 0, NULL );
 
     // --------------------------------------------------------------------
     // Reshape blocks if needed
diff --git a/frmts/ingr/IntergraphDataset.cpp b/frmts/ingr/IntergraphDataset.cpp
index 5235721..4cea75a 100644
--- a/frmts/ingr/IntergraphDataset.cpp
+++ b/frmts/ingr/IntergraphDataset.cpp
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * $Id: IntergraphDataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: IntergraphDataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Intergraph Raster Format support
  * Purpose:  Read/Write Intergraph Raster Format, dataset support
@@ -804,7 +804,7 @@ GDALDataset *IntergraphDataset::CreateCopy( const char *pszFilename,
                     iXOffset, iYOffset, 
                     nBlockXSize, nBlockYSize,
                     pData, nBlockXSize, nBlockYSize,
-                    eType, 0, 0 );
+                    eType, 0, 0, NULL );
                 if( eErr != CE_None )
                 {
                     return NULL;
@@ -813,7 +813,7 @@ GDALDataset *IntergraphDataset::CreateCopy( const char *pszFilename,
                     iXOffset, iYOffset, 
                     nBlockXSize, nBlockYSize,
                     pData, nBlockXSize, nBlockYSize,
-                    eType, 0, 0 );
+                    eType, 0, 0, NULL );
                 if( eErr != CE_None )
                 {
                     return NULL;
@@ -892,6 +892,7 @@ void GDALRegister_INGR()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "INGR" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Intergraph Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_IntergraphRaster.html" );
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
diff --git a/frmts/ingr/JpegHelper.cpp b/frmts/ingr/JpegHelper.cpp
index 218321a..79fdd69 100644
--- a/frmts/ingr/JpegHelper.cpp
+++ b/frmts/ingr/JpegHelper.cpp
@@ -142,9 +142,9 @@ static const GByte ZIGZAG[64] = {
   { int i; for( i = 0; i < 64; i++ ) tb[i] = (GByte) (tb[i] op vl); }
 
 int JPGHLP_HeaderMaker( GByte *pabyBuffer,
-                        const int nCols, 
-                        const int nRows, 
-                        const int nComponents, 
+                        const int nCols,
+                        const int nRows,
+                        const int nComponents,
                         CPL_UNUSED const int nRestart,
                         const int nQuality )
 {
diff --git a/frmts/ingr/makefile.vc b/frmts/ingr/makefile.vc
index 2bf1a21..8f03724 100644
--- a/frmts/ingr/makefile.vc
+++ b/frmts/ingr/makefile.vc
@@ -4,7 +4,7 @@ GDAL_ROOT = ..\..
 
 OBJ	= intergraphdataset.obj intergraphband.obj ingrtypes.obj jpeghelper.obj
 
-EXTRAFLAGS = -D_USE_MATH_DEFINES -I..\gtiff\libtiff
+EXTRAFLAGS = -D_USE_MATH_DEFINES -I..\gtiff -I..\gtiff\libtiff
 
 default:	$(OBJ)
 	xcopy /D  /Y *.obj ..\o
diff --git a/frmts/iris/GNUmakefile b/frmts/iris/GNUmakefile
index 9bdbc3e..a5f8217 100644
--- a/frmts/iris/GNUmakefile
+++ b/frmts/iris/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	irisdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/iris/irisdataset.cpp b/frmts/iris/irisdataset.cpp
index bb1ba38..cb7d0f7 100644
--- a/frmts/iris/irisdataset.cpp
+++ b/frmts/iris/irisdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: irisdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: irisdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  IRIS Reader
  * Purpose:  All code for IRIS format Reader
@@ -43,7 +43,7 @@
 #include <sstream>
 
 
-CPL_CVSID("$Id: irisdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: irisdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_IRIS(void);
@@ -189,7 +189,8 @@ IRISRasterBand::~IRISRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr IRISRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr IRISRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void * pImage )
 
 {
@@ -308,6 +309,21 @@ CPLErr IRISRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
                 fVal = poGDS->fNyquistVelocity * (fVal - 128)/127;
             ((float *) pImage)[i] = fVal;     
         }       
+    //SHEAR (1-Byte Shear)
+    //See point 3.3.23 at page 3.39 of the manual
+    } else if(poGDS->nDataTypeCode == 35){
+        float fVal;
+        for (i=0;i<nBlockXSize;i++){
+            fVal = (float) *(pszRecord+i*nDataLength);
+            if (fVal == 0.0)
+                fVal = -9998;
+            else if (fVal == 255.0)
+                fVal = -9999;
+            else
+                fVal = (fVal - 128) * 0.2;
+            ((float *) pImage)[i] = fVal;
+        }
+
     }
 
     return CE_None;
@@ -960,6 +976,7 @@ void GDALRegister_IRIS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "IRIS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "IRIS data (.PPI, .CAPPi etc)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/iso8211/8211createfromxml.cpp b/frmts/iso8211/8211createfromxml.cpp
index 989b06d..012988f 100644
--- a/frmts/iso8211/8211createfromxml.cpp
+++ b/frmts/iso8211/8211createfromxml.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: 8211createfromxml.cpp 25842 2013-04-02 22:21:06Z rouault $
+ * $Id: 8211createfromxml.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  ISO8211 library
  * Purpose:  Create a 8211 file from a XML dump file generated by "8211dump -xml"
@@ -32,7 +32,7 @@
 #include <map>
 #include <string>
 
-CPL_CVSID("$Id: 8211createfromxml.cpp 25842 2013-04-02 22:21:06Z rouault $");
+CPL_CVSID("$Id: 8211createfromxml.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 int main(int nArgc, char* papszArgv[])
 {
@@ -245,7 +245,7 @@ int main(int nArgc, char* papszArgv[])
                                 if( strcmp(pszSubfieldType, "float") == 0 )
                                 {
                                     poRec->SetFloatSubfield( pszFieldName, nFieldOcc, pszSubfieldName, nOcc,
-                                                           atof(pszSubfieldValue) );
+                                                           CPLAtof(pszSubfieldValue) );
                                 }
                                 else if( strcmp(pszSubfieldType, "integer") == 0 )
                                 {
diff --git a/frmts/iso8211/ddffielddefn.cpp b/frmts/iso8211/ddffielddefn.cpp
index 57e4aab..725a657 100644
--- a/frmts/iso8211/ddffielddefn.cpp
+++ b/frmts/iso8211/ddffielddefn.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ddffielddefn.cpp 25820 2013-03-30 20:07:35Z rouault $
+ * $Id: ddffielddefn.cpp 28348 2015-01-23 15:27:13Z rouault $
  *
  * Project:  ISO 8211 Access
  * Purpose:  Implements the DDFFieldDefn class.
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include <ctype.h>
 
-CPL_CVSID("$Id: ddffielddefn.cpp 25820 2013-03-30 20:07:35Z rouault $");
+CPL_CVSID("$Id: ddffielddefn.cpp 28348 2015-01-23 15:27:13Z rouault $");
 
 #define CPLE_DiscardedFormat   1301
 
@@ -138,7 +138,8 @@ void DDFFieldDefn::AddSubfield( DDFSubfieldDefn *poNewSFDefn,
     _arrayDescr = (char *) 
         CPLRealloc(_arrayDescr, 
                    strlen(_arrayDescr)+strlen(poNewSFDefn->GetName())+2);
-    if( strlen(_arrayDescr) > 0 )
+    if( strlen(_arrayDescr) > 0 && 
+       (_arrayDescr[0] != '*' || strlen(_arrayDescr) > 1) )
         strcat( _arrayDescr, "!" );
     strcat( _arrayDescr, poNewSFDefn->GetName() );
 }
diff --git a/frmts/iso8211/ddfsubfielddefn.cpp b/frmts/iso8211/ddfsubfielddefn.cpp
index 7f75a34..341b31d 100644
--- a/frmts/iso8211/ddfsubfielddefn.cpp
+++ b/frmts/iso8211/ddfsubfielddefn.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ddfsubfielddefn.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ddfsubfielddefn.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  ISO 8211 Access
  * Purpose:  Implements the DDFSubfieldDefn class.
@@ -30,8 +30,9 @@
 
 #include "iso8211.h"
 #include "cpl_conv.h"
+#include "cpl_string.h"
 
-CPL_CVSID("$Id: ddfsubfielddefn.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ddfsubfielddefn.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                          DDFSubfieldDefn()                           */
@@ -442,7 +443,7 @@ DDFSubfieldDefn::ExtractFloatData( const char * pachSourceData,
       case 'R':
       case 'S':
       case 'C':
-        return atof(ExtractStringData(pachSourceData, nMaxBytes,
+        return CPLAtof(ExtractStringData(pachSourceData, nMaxBytes,
                                       pnConsumedBytes));
 
       case 'B':
@@ -954,7 +955,7 @@ int DDFSubfieldDefn::FormatFloatValue( char *pachData, int nBytesAvailable,
     int nSize;
     char szWork[120];
 
-    sprintf( szWork, "%.16g", dfNewValue );
+    CPLsprintf( szWork, "%.16g", dfNewValue );
 
     if( bIsVariable )
     {
diff --git a/frmts/jaxapalsar/GNUmakefile b/frmts/jaxapalsar/GNUmakefile
index e9828e8..2d89b12 100644
--- a/frmts/jaxapalsar/GNUmakefile
+++ b/frmts/jaxapalsar/GNUmakefile
@@ -1,7 +1,7 @@
 include ../../GDALmake.opt
 
 OBJ	=	jaxapalsardataset.o
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 clean:
diff --git a/frmts/jaxapalsar/jaxapalsardataset.cpp b/frmts/jaxapalsar/jaxapalsardataset.cpp
index 9a3aaec..a6717a8 100644
--- a/frmts/jaxapalsar/jaxapalsardataset.cpp
+++ b/frmts/jaxapalsar/jaxapalsardataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jaxapalsardataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: jaxapalsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  PALSAR JAXA imagery reader
  * Purpose:  Support for PALSAR L1.1/1.5 imagery and appropriate metadata from
@@ -32,7 +32,7 @@
 
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: jaxapalsardataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: jaxapalsardataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_PALSARJaxa(void);
@@ -298,8 +298,9 @@ PALSARJaxaRasterBand::~PALSARJaxaRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr PALSARJaxaRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-	void *pImage )
+CPLErr PALSARJaxaRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                         int nBlockYOff,
+                                         void *pImage )
 {
     int nNumBytes = 0;
     if (nFileType == level_11) {
@@ -647,6 +648,7 @@ void GDALRegister_PALSARJaxa() {
     if( GDALGetDriverByName( "JAXAPALSAR" ) == NULL ) {
         poDriver = new GDALDriver();
         poDriver->SetDescription( "JAXAPALSAR" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JAXA PALSAR Product Reader (Level 1.1/1.5)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/jdem/GNUmakefile b/frmts/jdem/GNUmakefile
index ebd785c..8a7c5e2 100644
--- a/frmts/jdem/GNUmakefile
+++ b/frmts/jdem/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	jdemdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/jdem/jdemdataset.cpp b/frmts/jdem/jdemdataset.cpp
index dd38799..5bd7a92 100644
--- a/frmts/jdem/jdemdataset.cpp
+++ b/frmts/jdem/jdemdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jdemdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: jdemdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  JDEM Reader
  * Purpose:  All code for Japanese DEM Reader
@@ -30,7 +30,7 @@
 
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: jdemdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: jdemdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_JDEM(void);
@@ -157,10 +157,13 @@ JDEMRasterBand::~JDEMRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr JDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void * pImage )
+CPLErr JDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
+                                   void * pImage )
+
 {
     JDEMDataset *poGDS = (JDEMDataset *) poDS;
+    int		i;
     
     if (pszRecord == NULL)
     {
@@ -197,7 +200,7 @@ CPLErr JDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
         return CE_Failure;
     }
 
-    for( int i = 0; i < nBlockXSize; i++ )
+    for( i = 0; i < nBlockXSize; i++ )
         ((float *) pImage)[i] = (float)
             (JDEMGetField( pszRecord + 9 + 5 * i, 5) * 0.1);
 
@@ -303,6 +306,9 @@ int JDEMDataset::Identify( GDALOpenInfo * poOpenInfo )
 GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
+/* -------------------------------------------------------------------- */
+/*      Confirm that the header is compatible with a JDEM dataset.      */
+/* -------------------------------------------------------------------- */
     if (!Identify(poOpenInfo))
         return NULL;
 
@@ -316,6 +322,12 @@ GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
                   " datasets.\n" );
         return NULL;
     }
+    
+    /* Check that the file pointer from GDALOpenInfo* is available */
+    if( poOpenInfo->fpL == NULL )
+    {
+        return NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
@@ -324,12 +336,9 @@ GDALDataset *JDEMDataset::Open( GDALOpenInfo * poOpenInfo )
 
     poDS = new JDEMDataset();
 
-    poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
-    if (poDS->fp == NULL)
-    {
-        delete poDS;
-        return NULL;
-    }
+    /* Borrow the file pointer from GDALOpenInfo* */
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
     
 /* -------------------------------------------------------------------- */
 /*      Read the header.                                                */
@@ -380,6 +389,7 @@ void GDALRegister_JDEM()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JDEM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Japanese DEM (.mem)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/jp2kak/GNUmakefile b/frmts/jp2kak/GNUmakefile
index cac2509..5a3e7c0 100644
--- a/frmts/jp2kak/GNUmakefile
+++ b/frmts/jp2kak/GNUmakefile
@@ -19,7 +19,7 @@ INSTOBJ = $(foreach d,$(APPOBJ),../o/$(notdir $(d)))
 
 #CXXFLAGS :=	$(CXXFLAGS) -DFILEIO_DEBUG
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(KAKINC) -I. $(CPPFLAGS)
+CPPFLAGS	:=	 $(KAKINC) -I. $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/jp2kak/frmt_jp2kak.html b/frmts/jp2kak/frmt_jp2kak.html
index 0efd505..5c09aa3 100644
--- a/frmts/jp2kak/frmt_jp2kak.html
+++ b/frmts/jp2kak/frmt_jp2kak.html
@@ -21,7 +21,7 @@ format.  They are distinct compression mechanisms produced by the same
 group.  JPEG2000 is based on wavelet compression.<p>
 
 The JPEG2000 driver documented on this page (the JP2KAK driver) is implemented
-on top of the commercial <a href="http://www.kakadusoftware.com/">Kakadu</a>
+on top of the proprietary <a href="http://www.kakadusoftware.com/">Kakadu</a>
 library.  This is a high quality and high performance JPEG2000 library in wide
 used in the geospatial and general imaging community.  However, it is not free,
 and so normally builds of GDAL from source will not include support for this
@@ -62,6 +62,16 @@ on.  Defaults to NO.<p>
 
 </ul>
 
+<h2>Option Options</h2>
+
+(GDAL >= 2.0 )
+
+The following open option is available:
+<ul>
+<li><p><b>1BIT_ALPHA_PROMOTION=YES/NO</b>: Whether a 1-bit alpha channel should be promoted to 8-bit.
+Defaults to YES.</li>
+</ul>
+
 <h2>Creation Issues</h2>
 
 JPEG2000 files can only be created using the CreateCopy mechanism to
@@ -91,7 +101,23 @@ produce better compression than lossy compression. <P>
 <li> <b>BLOCKYSIZE=n</b>: Set the tile height to use.  Defaults to image height.
 <p>
 
-<li> <b>GMLJP2=YES/NO</b>: Indicates whether a GML box conforming to the OGC GML in JPEG2000 specification should be included in the file.  Defaults to YES.<p>
+<li> <b>FLUSH=TRUE/FALSE</b>: Enable/Disable incremental flushing when writing files.  Required to be FALSE for RLPC and LRPC Corder.  May use a lot of memory when FALSE while writing large images.  Defaults to TRUE.
+<p>
+
+<li> <b>GMLJP2=YES/NO</b>: Indicates whether a GML box
+conforming to the OGC GML in JPEG2000 specification should be included in the
+file. Unless GMLJP2V2_DEF is used, the version of the GMLJP2 box will be
+version 1. Defaults to YES.<p>
+
+<li> <b>GMLJP2V2_DEF=filename</b>: (Starting with GDAL 2.0) Indicates whether a GML box
+conforming to the <a href="http://docs.opengeospatial.org/is/08-085r4/08-085r4.html">
+OGC GML in JPEG2000, version 2</a> specification should be included in the
+file. <i>filename</i> must point to a file with a JSon content that defines how
+the GMLJP2 v2 box should be built. See <a href="frmt_jp2openjpeg.html#GMLJP2v2Def">
+GMLJP2v2 definition file section</a> in documentation of the JP2OpenJPEG driver
+for the syntax of the JSon configuration file.
+It is also possible to directly pass the JSon content inlined as a string.
+If filename is just set to YES, a minimal instance will be built.<p>
 
 <li> <b>GeoJP2=YES/NO</b>: Indicates whether a UUID/GeoTIFF box conforming to the GeoJP2 (GeoTIFF in JPEG2000) specification should be included in the file.  Defaults to YES.<p>
 
@@ -127,12 +153,14 @@ See Also:<p>
 
 <ul>
 
-<li> Implemented as <tt>gdal/frmts/jp2kak/jp2kakdataset.cpp</tt>.<p>
+<li> Implemented as <tt>gdal/frmts/jp2kak/jp2kakdataset.cpp</tt>. </li>
+
+<li> If you're using a Kakadu release before v7.5, configure & compile GDAL with eg. <code>CXXFLAGS="-DKDU_MAJOR_VERSION=7 -DKDU_MINOR_VERSION=3 -DKDU_PATCH_VERSION=2"</code> for Kakadu version 7.3.2.</li>
 
 <li> <a href="http://www.remotesensing.org/jpeg2000/">JPEG2000 for Geospatial
-Applications</a> page, includes GeoJP2(tm) discussion.<p>
+Applications</a> page, includes GeoJP2(tm) discussion.</li>
 
-<li> Alternate <a href="frmt_jpeg2000.html">JPEG200 driver</a>.<p>
+<li> Alternate <a href="frmt_jpeg2000.html">JPEG2000 driver</a>.</li>
 
 </ul>
 
diff --git a/frmts/jp2kak/jp2kak.lst b/frmts/jp2kak/jp2kak.lst
index 652e772..005b509 100644
--- a/frmts/jp2kak/jp2kak.lst
+++ b/frmts/jp2kak/jp2kak.lst
@@ -19,3 +19,9 @@ ifneq ($(wildcard $(KAKDIR)/apps/make/ssse3_stripe_transfe?.o),)
 KAK_OBJ +=	\
     $(KAKDIR)/apps/make/ssse3_stripe_transfer.o
 endif
+
+# The following are for Kakadu 7.5 and later.
+ifneq ($(wildcard $(KAKDIR)/apps/make/ssse3_region_decompressor.o),)
+KAK_OBJ +=	\
+    $(KAKDIR)/apps/make/ssse3_region_decompressor.o
+endif
diff --git a/frmts/jp2kak/jp2kakdataset.cpp b/frmts/jp2kak/jp2kakdataset.cpp
index 468df43..74ddb0d 100644
--- a/frmts/jp2kak/jp2kakdataset.cpp
+++ b/frmts/jp2kak/jp2kakdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jp2kakdataset.cpp 27182 2014-04-14 20:03:08Z rouault $
+ * $Id: jp2kakdataset.cpp 29075 2015-04-30 12:51:21Z rouault $
  *
  * Project:  JPEG-2000
  * Purpose:  Implementation of the ISO/IEC 15444-1 standard based on Kakadu.
@@ -65,16 +65,18 @@
 #  define kdu_client void
 #endif
 
-CPL_CVSID("$Id: jp2kakdataset.cpp 27182 2014-04-14 20:03:08Z rouault $");
+CPL_CVSID("$Id: jp2kakdataset.cpp 29075 2015-04-30 12:51:21Z rouault $");
 
-// Generally Kakadu does not advertise its version well, so we look for a
-// clue to V6 vs V7, the main difference in api.
-#ifndef KAKADU_VERSION
-#  ifdef KDU_TARGET_CAP_SEQUENTIAL
-#    define KAKADU_VERSION 700
-#  else
-#    define KAKADU_VERSION 600
-#  endif
+// Before v7.5 Kakadu does not advertise its version well
+// After v7.5 Kakadu has KDU_{MAJOR,MINOR,PATCH}_VERSION defines so it's easier
+// For older releases compile with them manually specified
+#ifndef KDU_MAJOR_VERSION
+#  error Compile with eg. -DKDU_MAJOR_VERSION=7 -DKDU_MINOR_VERSION=3 -DKDU_PATCH_VERSION=2 to specify Kakadu library version
+#endif
+
+#if KDU_MAJOR_VERSION > 7 || (KDU_MAJOR_VERSION == 7 && KDU_MINOR_VERSION >= 5)
+    using namespace kdu_core;
+    using namespace kdu_supp;
 #endif
 
 // #define KAKADU_JPX	1
@@ -117,16 +119,24 @@ class JP2KAKDataset : public GDALJP2AbstractDataset
     int            bResilient;
     int            bFussy;
     bool           bUseYCC;
+    
+    bool           bPromoteTo8Bit;
 
     int         TestUseBlockIO( int, int, int, int, int, int,
                                 GDALDataType, int, int * );
     CPLErr      DirectRasterIO( GDALRWFlag, int, int, int, int,
                                 void *, int, int, GDALDataType,
-                                int, int *, int, int, int );
+                                int, int *,
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GSpacing nBandSpace,
+                                GDALRasterIOExtraArg* psExtraArg);
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
 
   public:
@@ -172,7 +182,8 @@ class JP2KAKRasterBand : public GDALPamRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     int            HasExternalOverviews() 
                    { return GDALPamRasterBand::GetOverviewCount() != 0; }
@@ -246,7 +257,7 @@ public: // Member classes
 
         if( end_of_message && m_eErrClass == CE_Failure )
         {
-            throw new JP2KAKException();
+            throw JP2KAKException();
         }
     }
 
@@ -302,9 +313,8 @@ JP2KAKRasterBand::JP2KAKRasterBand( int nBand, int nDiscardLevels,
 /* -------------------------------------------------------------------- */
 /*      Capture some useful metadata.                                   */
 /* -------------------------------------------------------------------- */
-    if( oCodeStream.get_bit_depth(nBand-1) % 8 != 0 )
+    if( oCodeStream.get_bit_depth(nBand-1) % 8 != 0 && !poBaseDSIn->bPromoteTo8Bit )
     {
-        
         SetMetadataItem( "NBITS", 
                          CPLString().Printf("%d",oCodeStream.get_bit_depth(nBand-1)), 
                          "IMAGE_STRUCTURE" );
@@ -538,12 +548,17 @@ CPLErr JP2KAKRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
 /*      By default we invoke just for the requested band, directly      */
 /*      into the target buffer.                                         */
 /* -------------------------------------------------------------------- */
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     if( !poBaseDS->bUseYCC )
+    {
         return poBaseDS->DirectRasterIO( GF_Read, 
                                          nWXOff, nWYOff, nWXSize, nWYSize,
                                          pImage, nXSize, nYSize,
                                          eDataType, 1, &nBand, 
-                                         nWordSize, nWordSize*nBlockXSize, 0 );
+                                         nWordSize, nWordSize*nBlockXSize, 0, &sExtraArg );
+    }
 
 /* -------------------------------------------------------------------- */
 /*      But for YCC or possible other effectively pixel interleaved     */
@@ -572,7 +587,8 @@ CPLErr JP2KAKRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                      pabyWrkBuffer, nXSize, nYSize,
                                      eDataType, anBands.size(), &anBands[0],
                                      nWordSize, nWordSize*nBlockXSize, 
-                                     nWordSize*nBlockXSize*nBlockYSize );
+                                     nWordSize*nBlockXSize*nBlockYSize,
+                                     &sExtraArg );
 
     if( eErr == CE_None )
     {
@@ -641,7 +657,8 @@ JP2KAKRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                              int nXOff, int nYOff, int nXSize, int nYSize,
                              void * pData, int nBufXSize, int nBufYSize,
                              GDALDataType eBufType, 
-                             int nPixelSpace,int nLineSpace )
+                             GSpacing nPixelSpace, GSpacing nLineSpace,
+                             GDALRasterIOExtraArg* psExtraArg)
 
 {
 /* -------------------------------------------------------------------- */
@@ -653,7 +670,7 @@ JP2KAKRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamRasterBand::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nPixelSpace, nLineSpace );
+            nPixelSpace, nLineSpace, psExtraArg );
     else
     {
         int nOverviewDiscard = nDiscardLevels;
@@ -671,7 +688,7 @@ JP2KAKRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return poBaseDS->DirectRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            1, &nBand, nPixelSpace, nLineSpace, 0 );
+            1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg );
     }
 }
 
@@ -714,7 +731,7 @@ void JP2KAKRasterBand::ApplyPalette( jp2_palette oJP2Palette )
 
     if( oJP2Palette.get_num_luts() == 4 )
     {
-        oJP2Palette.get_lut( 2, pafLUT + nCount*3 );
+        oJP2Palette.get_lut( 3, pafLUT + nCount*3 );
     }
     else
     {
@@ -788,6 +805,7 @@ JP2KAKDataset::JP2KAKDataset()
 
     bCached = 0;
     bPreferNPReads = false;
+    bPromoteTo8Bit = false;
 
     poDriver = (GDALDriver*) GDALGetDriverByName( "JP2KAK" );
 }
@@ -1026,9 +1044,10 @@ GDALDataset *JP2KAKDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      subfile_source.  We do this if it does not seem to open normally*/
 /*      or if we want to operate in resilient (sequential) mode.        */
 /* -------------------------------------------------------------------- */
+    VSIStatBuf sStat;
     if( poRawInput == NULL
         && !bIsJPIP
-        && (bBuffered || bResilient || poOpenInfo->fp == NULL) )
+        && (bBuffered || bResilient || VSIStat(poOpenInfo->pszFilename, &sStat) != 0) )
     {
         try
         {
@@ -1336,6 +1355,19 @@ GDALDataset *JP2KAKDataset::Open( GDALOpenInfo * poOpenInfo )
 
         CPLDebug( "JP2KAK", "nResCount=%d", poDS->nResCount );
 
+
+/* -------------------------------------------------------------------- */
+/*      Should we promote alpha channel to 8 bits ?                     */
+/* -------------------------------------------------------------------- */
+        poDS->bPromoteTo8Bit = (poDS->nBands == 4 &&
+                                poDS->oCodeStream.get_bit_depth(0) == 8 &&
+                                poDS->oCodeStream.get_bit_depth(1) == 8 &&
+                                poDS->oCodeStream.get_bit_depth(2) == 8 &&
+                                poDS->oCodeStream.get_bit_depth(3) == 1 &&
+                                CSLFetchBoolean(poOpenInfo->papszOpenOptions, "1BIT_ALPHA_PROMOTION", TRUE));
+        if( poDS->bPromoteTo8Bit )
+            CPLDebug( "JP2KAK",  "Fourth (alpha) band is promoted from 1 bit to 8 bit");
+
 /* -------------------------------------------------------------------- */
 /*      Create band information objects.                                */
 /* -------------------------------------------------------------------- */
@@ -1397,7 +1429,25 @@ GDALDataset *JP2KAKDataset::Open( GDALOpenInfo * poOpenInfo )
                       " datasets.\n" );
             return NULL;
         }
-    
+
+/* -------------------------------------------------------------------- */
+/*      Vector layers                                                   */
+/* -------------------------------------------------------------------- */
+        if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
+        {
+            poDS->LoadVectorLayers(
+                CSLFetchBoolean(poOpenInfo->papszOpenOptions, "OPEN_REMOTE_GML", FALSE));
+
+            // If file opened in vector-only mode and there's no vector,
+            // return
+            if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+                poDS->GetLayerCount() == 0 )
+            {
+                delete poDS;
+                return NULL;
+            }
+        }
+
         return( poDS );
     }
 
@@ -1419,12 +1469,14 @@ GDALDataset *JP2KAKDataset::Open( GDALOpenInfo * poOpenInfo )
 /************************************************************************/
 
 CPLErr 
-JP2KAKDataset::DirectRasterIO( GDALRWFlag eRWFlag,
+JP2KAKDataset::DirectRasterIO( CPL_UNUSED GDALRWFlag eRWFlag,
                                int nXOff, int nYOff, int nXSize, int nYSize,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace,int nLineSpace,int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
     
 {
     kdu_codestream *poCodeStream = &oCodeStream;
@@ -1691,6 +1743,19 @@ JP2KAKDataset::DirectRasterIO( GDALRWFlag eRWFlag,
     }
 
 /* -------------------------------------------------------------------- */
+/*      1-bit alpha promotion.                                          */
+/* -------------------------------------------------------------------- */
+    if( nBandCount == 4 && bPromoteTo8Bit )
+    {
+        for(int j=0;j<nBufYSize;j++)
+        {
+            for(i=0;i<nBufXSize;i++)
+            {
+                ((GByte*)pData)[j*nLineSpace+i*nPixelSpace+3*nBandSpace] *= 255;
+            }
+        }
+    }
+/* -------------------------------------------------------------------- */
 /*      Cleanup                                                         */
 /* -------------------------------------------------------------------- */
     if( poCodeStream == &oWCodeStream )
@@ -1760,9 +1825,9 @@ JP2KAKDataset::TestUseBlockIO( int nXOff, int nYOff, int nXSize, int nYSize,
         int    nXOff2=nXOff, nYOff2=nYOff, nXSize2=nXSize, nYSize2=nYSize;
 
         nOverview =
-            GDALBandGetBestOverviewLevel( poWrkBand, 
+            GDALBandGetBestOverviewLevel2( poWrkBand, 
                                           nXOff2, nYOff2, nXSize2, nYSize2,
-                                          nBufXSize, nBufYSize);
+                                          nBufXSize, nBufYSize, NULL);
         if (nOverview >= 0 )
             return TRUE;
     }
@@ -1795,7 +1860,9 @@ CPLErr JP2KAKDataset::IRasterIO( GDALRWFlag eRWFlag,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType, 
                                  int nBandCount, int *panBandMap,
-                                 int nPixelSpace,int nLineSpace,int nBandSpace)
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GSpacing nBandSpace,
+                                 GDALRasterIOExtraArg* psExtraArg)
 
 {
 /* -------------------------------------------------------------------- */
@@ -1806,12 +1873,12 @@ CPLErr JP2KAKDataset::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamDataset::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else
         return DirectRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -1886,7 +1953,7 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
             res.get_dims(dims);
             roi_node = poROIImage->acquire_node(c,dims);
         }
-#if KAKADU_VERSION >= 700
+#if KDU_MAJOR_VERSION >= 7
         lines[c].pre_create(&allocator,nXSize,bReversible,bUseShorts,0,0);
 #else
         lines[c].pre_create(&allocator,nXSize,bReversible,bUseShorts);
@@ -1896,7 +1963,11 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
 
     try
     {
+#if KDU_MAJOR_VERSION > 7 || (KDU_MAJOR_VERSION == 7 && (KDU_MINOR_VERSION > 3 || KDU_MINOR_VERSION == 3 && KDU_PATCH_VERSION >= 1))
+        allocator.finalize(oCodeStream);
+#else
         allocator.finalize();
+#endif
 
         for (c=0; c < num_components; c++)
             lines[c].create();
@@ -1920,9 +1991,10 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
 
     CPLAssert( !oTile.get_ycc() );
 
-    for( iLine = 0; iLine < nYSize; iLine += TILE_CHUNK_SIZE )
+    int bRet = TRUE;
+    for( iLine = 0; iLine < nYSize && bRet; iLine += TILE_CHUNK_SIZE )
     {
-        for (c=0; c < num_components; c++)
+        for (c=0; c < num_components && bRet; c++)
         {
             GDALRasterBand *poBand = poSrcDS->GetRasterBand( c+1 );
             int iSubline = 0;
@@ -1934,8 +2006,11 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
                 if( poBand->RasterIO( GF_Read, 
                                       nXOff, nYOff+iSubline, nXSize, 1, 
                                       (void *) pabyBuffer, nXSize, 1, eType,
-                                      0, 0 ) == CE_Failure )
-                    return FALSE;
+                                      0, 0, NULL ) == CE_Failure )
+                {
+                    bRet = FALSE;
+                    break;
+                }
 
                 if( bReversible && eType == GDT_Byte )
                 {
@@ -2003,7 +2078,7 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
                         dest->fval = *sp;  /* scale it? */
                 }
 
-#if KAKADU_VERSION >= 700
+#if KDU_MAJOR_VERSION >= 7
                 engines[c].push(lines[c]);
 #else
                 engines[c].push(lines[c],true);
@@ -2015,19 +2090,28 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
                                   / (double) (num_components * nYSize),
                                   NULL, pProgressData ) )
                 {
-                    return FALSE;
+                    bRet = FALSE;
+                    break;
                 }
             }
         }
+        if( !bRet )
+            break;
 
         if( oCodeStream.ready_for_flush() && bFlushEnabled )
         {
             CPLDebug( "JP2KAK", 
                       "Calling oCodeStream.flush() at line %d",
                       MIN(nYSize,iLine+TILE_CHUNK_SIZE) );
-            
-            oCodeStream.flush( layer_bytes, layer_count, NULL,
-                               true, bComseg );
+            try
+            {
+                oCodeStream.flush( layer_bytes, layer_count, NULL,
+                                   true, bComseg );
+            }
+            catch(...)
+            {
+                bRet = FALSE;
+            }
         }
         else if( bFlushEnabled )
             CPLDebug( "JP2KAK", 
@@ -2049,7 +2133,7 @@ JP2KAKCreateCopy_WriteTile( GDALDataset *poSrcDS, kdu_tile &oTile,
     if( poROIImage != NULL )
         delete poROIImage;
 
-    return TRUE;
+    return bRet;
 }
 
 /************************************************************************/
@@ -2146,7 +2230,7 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     if( CSLFetchNameValue(papszOptions,"QUALITY") != NULL )
     {
-        dfQuality = atof(CSLFetchNameValue(papszOptions,"QUALITY"));
+        dfQuality = CPLAtof(CSLFetchNameValue(papszOptions,"QUALITY"));
     }
 
     if( dfQuality < 0.01 || dfQuality > 100.0 )
@@ -2154,6 +2238,7 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         CPLError( CE_Failure, CPLE_IllegalArg,
                   "QUALITY=%s is not a legal value in the range 0.01-100.",
                   CSLFetchNameValue(papszOptions,"QUALITY") );
+        CPLFree(layer_bytes);
         return NULL;
     }
 
@@ -2356,6 +2441,7 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
         poROIImage = new kdu_roi_rect(oCodeStream,region);
     }
+    CSLDestroy(papszROIDefs);
 
 /* -------------------------------------------------------------------- */
 /*      Set some particular parameters.                                 */
@@ -2403,7 +2489,24 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             CPLString osOpt;
 
             osOpt.Printf( "%s=%s", apszParms[iParm], pszValue );
-            oCodeStream.access_siz()->parse_string( osOpt );
+            try
+            {
+                oCodeStream.access_siz()->parse_string( osOpt );
+            }
+            catch( ... )
+            {
+                CPLFree(layer_bytes);
+                if( bIsJP2 )
+                {
+                    jp2_out.close();
+                    family.close();
+                }
+                else
+                {
+                    poOutputFile->close();
+                }
+                return NULL;
+            }
 
             CPLDebug( "JP2KAK", "parse_string(%s)", osOpt.c_str() );
         }
@@ -2539,7 +2642,8 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                  || adfGeoTransform[3] != 0.0 
                  || adfGeoTransform[4] != 0.0 
                  || ABS(adfGeoTransform[5]) != 1.0))
-            || poSrcDS->GetGCPCount() > 0) )
+            || poSrcDS->GetGCPCount() > 0
+            || poSrcDS->GetMetadata("RPC") != NULL) )
     {
         GDALJP2Metadata oJP2MD;
 
@@ -2554,11 +2658,19 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
             oJP2MD.SetGeoTransform( adfGeoTransform );
         }
 
+        oJP2MD.SetRPCMD( poSrcDS->GetMetadata("RPC") );
+
         const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
         oJP2MD.bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
 
         if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) )
-            JP2KAKWriteBox( &jp2_out, oJP2MD.CreateGMLJP2(nXSize,nYSize) );
+        {
+            const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
+            if( pszGMLJP2V2Def != NULL )
+                JP2KAKWriteBox( &jp2_out, oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS) );
+            else
+                JP2KAKWriteBox( &jp2_out, oJP2MD.CreateGMLJP2(nXSize,nYSize) );
+        }
         if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) )
             JP2KAKWriteBox( &jp2_out, oJP2MD.CreateJP2GeoTIFF() );
     }
@@ -2680,7 +2792,7 @@ JP2KAKCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         return NULL;
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     GDALPamDataset *poDS = (GDALPamDataset*) JP2KAKDataset::Open(&oOpenInfo);
@@ -2708,6 +2820,8 @@ void GDALRegister_JP2KAK()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JP2KAK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JPEG-2000 (based on Kakadu " 
                                    KDU_CORE_VERSION ")" );
@@ -2719,6 +2833,12 @@ void GDALRegister_JP2KAK()
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
 
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionList>"
+"   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' description='Whether a 1-bit alpha channel should be promoted to 8-bit' default='YES'/>"
+"   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether to load remote vector layers referenced by a link in a GMLJP2 v2 box' default='NO'/>"
+"</OpenOptionList>" );
 
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
 "<CreationOptionList>"
@@ -2727,9 +2847,11 @@ void GDALRegister_JP2KAK()
 "   <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
 "   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
 "   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
+"   <Option name='GMLJP2V2_DEF' type='string' description='Definition file to describe how a GMLJP2 v2 box should be generated. If set to YES, a minimal instance will be created'/>"
 "   <Option name='LAYERS' type='integer'/>"
 "   <Option name='ROI' type='string'/>"
 "   <Option name='COMSEG' type='boolean' />"
+"   <Option name='FLUSH' type='boolean' />"
 "   <Option name='NBITS' type='int' description='BITS (precision) for sub-byte files (1-7), sub-uint16 (9-15)'/>"
 "   <Option name='Corder' type='string'/>"
 "   <Option name='Cprecincts' type='string'/>"
@@ -2738,7 +2860,7 @@ void GDALRegister_JP2KAK()
 "   <Option name='ORGgen_plt' type='string'/>"
 "   <Option name='ORGgen_tlm' type='string'/>"
 "   <Option name='Qguard' type='integer'/>"
-"   <Option name='Sprofile' type='integer'/>"
+"   <Option name='Sprofile' type='string'/>"
 "   <Option name='Rshift' type='string'/>"
 "   <Option name='Rlevels' type='string'/>"
 "   <Option name='Rweight' type='string'/>"
diff --git a/frmts/jp2kak/subfile_source.h b/frmts/jp2kak/subfile_source.h
index b0d78bc..731e226 100644
--- a/frmts/jp2kak/subfile_source.h
+++ b/frmts/jp2kak/subfile_source.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: subfile_source.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: subfile_source.h 27787 2014-10-03 01:08:03Z rcoup $
  *
  * Project:  JPEG-2000
  * Purpose:  Implements read-only virtual io on a subregion of a file.
@@ -32,6 +32,11 @@
 #include "cpl_error.h"
 #include "cpl_vsi_virtual.h"
 
+#if KDU_MAJOR_VERSION > 7 || (KDU_MAJOR_VERSION == 7 && KDU_MINOR_VERSION >= 5)
+    using namespace kdu_core;
+    using namespace kdu_supp;
+#endif
+
 #define IO_CHUNK_SIZE 65536L
 #define IO_BUFFER_SIZE 1048576L
 /************************************************************************/
diff --git a/frmts/jpeg/GNUmakefile b/frmts/jpeg/GNUmakefile
index 7c7b82e..7a40ade 100644
--- a/frmts/jpeg/GNUmakefile
+++ b/frmts/jpeg/GNUmakefile
@@ -33,7 +33,7 @@ OBJ :=	jcapimin12.o jcapistd12.o jccoefct12.o jccolor12.o jcdctmgr12.o jchuff12.
 	$(OBJ) jpgdataset_12.o 
 endif
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS) -I../mem
 
 default:	install-obj
 
diff --git a/frmts/jpeg/frmt_jpeg.html b/frmts/jpeg/frmt_jpeg.html
index 627cf4d..fe8d546 100644
--- a/frmts/jpeg/frmt_jpeg.html
+++ b/frmts/jpeg/frmt_jpeg.html
@@ -40,7 +40,7 @@ compressed tiles.<p>
 
 To be able to read and write JPEG images with 12-bit sample, you can build GDAL
 with its internal libjpeg (based on IJG libjpeg-6b, with additional changes for 12-bit
-sample support), or explicitely pass --with-jpeg12=yes to configure script when building
+sample support), or explicitly pass --with-jpeg12=yes to configure script when building
 with external libjpeg. See <a href="http://trac.osgeo.org/gdal/wiki/TIFF12BitJPEG">
 "8 and 12 bit JPEG in TIFF"</a> wiki page for more details.<p>
 
@@ -51,6 +51,9 @@ and SSE2 SIMD instructions to accelerate baseline JPEG compression/decompression
 Starting with GDAL 1.9.0, XMP metadata can be extracted from the file, and will be
 stored as XML raw content in the xml:XMP metadata domain.<p>
 
+Starting with GDAL 2.0, embedded EXIF thumbnails (with JPEG compression) can be
+used as overviews, and generated by GDAL.<p>
+
 <h2>Color Profile Metadata</h2>
 
 <p>Starting with GDAL 1.11, GDAL can deal with the following color profile metadata in the COLOR_PROFILE domain:</p>
@@ -112,6 +115,24 @@ than 8 will produce files incompatible with versions prior to libjpeg 8c.<p>
 Set to RGB1 for lossless RGB. Note: this will produce files incompatible with
 versions prior to libjpeg 9.<p>
 
+<li> <b>SOURCE_ICC_PROFILE=value</b>: (Starting with GDAL 1.11).
+ICC profile encoded in Base64.<p>
+
+<li> <b>COMMENT=string</b>: (Starting with GDAL 2.0). String to embed in a
+comment JPEG marker. When reading, such strings are exposed in the COMMENT
+metadata item.<p>
+
+<li> <b>EXIF_THUMBNAIL=YES/NO</b>: (Starting with GDAL 2.0). Whether to generate
+an EXIF thumbnail(overview), itself JPEG compressed. Defaults to NO. If enabled,
+the maximum dimension of the thumbnail will be 128, if neither THUMBNAIL_WIDTH nor
+THUMBNAIL_HEIGHT are specified.<p>
+
+<li> <b>THUMBNAIL_WIDTH=n</b>: (Starting with GDAL 2.0). Width of thumbnail. Only
+taken into account if EXIF_THUMBNAIL=YES.<p>
+
+<li> <b>THUMBNAIL_HEIGHT=n</b>: (Starting with GDAL 2.0). Height of thumbnail. Only
+taken into account if EXIF_THUMBNAIL=YES.<p>
+
 </ul>
 
 <h3>See Also:</h3>
diff --git a/frmts/jpeg/jpgdataset.cpp b/frmts/jpeg/jpgdataset.cpp
index 26943f5..19fff42 100644
--- a/frmts/jpeg/jpgdataset.cpp
+++ b/frmts/jpeg/jpgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jpgdataset.cpp 27743 2014-09-26 21:56:05Z rouault $
+ * $Id: jpgdataset.cpp 29017 2015-04-25 19:32:11Z rouault $
  *
  * Project:  JPEG JFIF Driver
  * Purpose:  Implement GDAL JPEG Support based on IJG libjpeg.
@@ -33,6 +33,8 @@
 
 #include "gdal_pam.h"
 #include "cpl_string.h"
+#include "gdalexif.h"
+#include "memdataset.h"
 
 #include <setjmp.h>
 
@@ -41,6 +43,11 @@
 #define TIFF_BIGENDIAN          0x4d4d
 #define TIFF_LITTLEENDIAN       0x4949
 
+#define JPEG_TIFF_IMAGEWIDTH        0x100
+#define JPEG_TIFF_IMAGEHEIGHT       0x101
+#define JPEG_TIFF_COMPRESSION       0x103
+#define JPEG_EXIF_JPEGIFOFSET       0x201
+#define JPEG_EXIF_JPEGIFBYTECOUNT   0x202
 /*
  * TIFF header.
  */
@@ -50,7 +57,7 @@ typedef struct {
         GUInt32  tiff_diroff;    /* byte offset to first directory */
 } TIFFHeader;
 
-CPL_CVSID("$Id: jpgdataset.cpp 27743 2014-09-26 21:56:05Z rouault $");
+CPL_CVSID("$Id: jpgdataset.cpp 29017 2015-04-25 19:32:11Z rouault $");
 
 CPL_C_START
 #ifdef LIBJPEG_12_PATH 
@@ -67,8 +74,10 @@ CPL_C_END
 
 #if defined(JPEG_DUAL_MODE_8_12) && !defined(JPGDataset)
 GDALDataset* JPEGDataset12Open(const char* pszFilename,
+                               VSILFILE* fpLin,
                                char** papszSiblingFiles,
-                               int nScaleFactor);
+                               int nScaleFactor,
+                               int bDoPAMInitialize);
 GDALDataset* JPEGDataset12CreateCopy( const char * pszFilename,
                                     GDALDataset *poSrcDS,
                                     int bStrict, char ** papszOptions,
@@ -92,31 +101,24 @@ CPL_C_END
 #  define JPEG_LIB_MK1_OR_12BIT 1
 #endif
 
-#define Q1table GDALJPEG_Q1table
-#define Q2table GDALJPEG_Q2table
-#define Q3table GDALJPEG_Q3table
-#define Q4table GDALJPEG_Q4table
-#define Q5table GDALJPEG_Q5table
-#define AC_BITS GDALJPEG_AC_BITS
-#define AC_HUFFVAL GDALJPEG_AC_HUFFVAL
-#define DC_BITS GDALJPEG_DC_BITS
-#define DC_HUFFVAL GDALJPEG_DC_HUFFVAL
-
-extern const GByte Q1table[64];
-extern const GByte Q2table[64];
-extern const GByte Q3table[64];
-extern const GByte Q4table[64];
-extern const GByte Q5table[64];
-extern const GByte AC_BITS[16];
-extern const GByte AC_HUFFVAL[256];
-extern const GByte DC_BITS[16];
-extern const GByte DC_HUFFVAL[256];
-
 class JPGDatasetCommon;
 GDALRasterBand* JPGCreateBand(JPGDatasetCommon* poDS, int nBand);
 
 CPLErr JPGAppendMask( const char *pszJPGFilename, GDALRasterBand *poMask,
                       GDALProgressFunc pfnProgress, void * pProgressData );
+void   JPGAddEXIFOverview( GDALDataType eWorkDT,
+                           GDALDataset* poSrcDS, char** papszOptions,
+                           j_compress_ptr cinfo,
+                           void (*p_jpeg_write_m_header) (j_compress_ptr cinfo, int marker, unsigned int datalen),
+                           void (*p_jpeg_write_m_byte) (j_compress_ptr cinfo, int val),
+                           GDALDataset *(pCreateCopy)( const char *, GDALDataset *, 
+                                     int, char **,
+                                     GDALProgressFunc pfnProgress, 
+                                     void * pProgressData ) );
+void JPGAddICCProfile( struct jpeg_compress_struct *pInfo,
+                       const char *pszICCProfile,
+                       void (*p_jpeg_write_m_header) (j_compress_ptr cinfo, int marker, unsigned int datalen),
+                       void (*p_jpeg_write_m_byte) (j_compress_ptr cinfo, int val));
 
 typedef struct
 {
@@ -149,6 +151,7 @@ protected:
     int           nInternalOverviewsToFree;
     GDALDataset** papoInternalOverviews;
     void          InitInternalOverviews();
+    GDALDataset*  InitEXIFOverview();
 
     char   *pszProjection;
     int	   bGeoTransformValid;
@@ -178,7 +181,7 @@ protected:
     int    bHasDoneJpegStartDecompress;
 
     virtual CPLErr LoadScanline(int) = 0;
-    virtual void   Restart() = 0;
+    virtual CPLErr Restart() = 0;
 
     virtual int GetDataPrecision() = 0;
     virtual int GetOutColorSpace() = 0;
@@ -186,8 +189,6 @@ protected:
     int    EXIFInit(VSILFILE *);
     void   ReadICCProfile();
 
-    int    nQLevel;
-
     void   CheckForMask();
     void   DecompressMask();
 
@@ -221,7 +222,10 @@ protected:
 
     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
                                    void *, int, int, GDALDataType,
-                                   int, int *, int, int, int );
+                                   int, int *,
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GSpacing nBandSpace,
+                                   GDALRasterIOExtraArg* psExtraArg );
 
     virtual CPLErr GetGeoTransform( double * );
 
@@ -236,8 +240,12 @@ protected:
 
     virtual char **GetFileList(void);
 
+    virtual void FlushCache(void);
+
     static int          Identify( GDALOpenInfo * );
     static GDALDataset *Open( GDALOpenInfo * );
+
+    static void EmitMessage(j_common_ptr cinfo, int msg_level);
 };
 
 /************************************************************************/
@@ -252,11 +260,14 @@ class JPGDataset : public JPGDatasetCommon
     struct jpeg_error_mgr sJErr;
 
     virtual CPLErr LoadScanline(int);
-    virtual void   Restart();
+    virtual CPLErr Restart();
     virtual int GetDataPrecision() { return sDInfo.data_precision; }
     virtual int GetOutColorSpace() { return sDInfo.out_color_space; }
 
+    int    nQLevel;
+#if !defined(JPGDataset)
     void   LoadDefaultTables(int);
+#endif
     void   SetScaleNumAndDenom();
 
   public:
@@ -264,8 +275,10 @@ class JPGDataset : public JPGDatasetCommon
                  ~JPGDataset();
 
     static GDALDataset *Open( const char* pszFilename,
-                              char** papszSiblingFiles = NULL,
-                              int nScaleFactor = 1 );
+                              VSILFILE* fpLin,
+                              char** papszSiblingFiles,
+                              int nScaleFactor,
+                              int bDoPAMInitialize );
     static GDALDataset* CreateCopy( const char * pszFilename,
                                     GDALDataset *poSrcDS,
                                     int bStrict, char ** papszOptions,
@@ -273,7 +286,6 @@ class JPGDataset : public JPGDatasetCommon
                                     void * pProgressData );
 
     static void ErrorExit(j_common_ptr cinfo);
-    static void EmitMessage(j_common_ptr cinfo, int msg_level);
 };
 
 /************************************************************************/
@@ -408,6 +420,11 @@ void JPGDatasetCommon::ReadXMPMetadata()
         if( VSIFReadL( abyChunkHeader, sizeof(abyChunkHeader), 1, fpImage ) != 1 )
             break;
 
+        nChunkLoc += 2 + abyChunkHeader[2] * 256 + abyChunkHeader[3];
+        // COM marker
+        if( abyChunkHeader[0] == 0xFF && abyChunkHeader[1] == 0xFE )
+            continue;
+
         if( abyChunkHeader[0] != 0xFF
             || (abyChunkHeader[1] & 0xf0) != 0xe0 )
             break; // Not an APP chunk.
@@ -418,8 +435,6 @@ void JPGDatasetCommon::ReadXMPMetadata()
             bFoundXMP = TRUE;
             break; // APP1 - XMP
         }
-
-        nChunkLoc += 2 + abyChunkHeader[2] * 256 + abyChunkHeader[3];
     }
 
     if (bFoundXMP)
@@ -494,7 +509,8 @@ const char *JPGDatasetCommon::GetMetadataItem( const char * pszName,
         return NULL;
     if (eAccess == GA_ReadOnly && !bHasReadEXIFMetadata &&
         (pszDomain == NULL || EQUAL(pszDomain, "")) &&
-        pszName != NULL && EQUALN(pszName, "EXIF_", 5))
+        pszName != NULL &&
+        (EQUAL(pszName, "COMMENT") || EQUALN(pszName, "EXIF_", 5)))
         ReadEXIFMetadata();
     if (eAccess == GA_ReadOnly && !bHasReadICCMetadata &&
         pszDomain != NULL && EQUAL(pszDomain, "COLOR_PROFILE"))
@@ -602,7 +618,7 @@ void JPGDatasetCommon::ReadICCProfile()
             }
         }
 
-        nChunkLoc += 2 + abyChunkHeader[2] * 256 + abyChunkHeader[3];
+        nChunkLoc += 2 + nChunkLength;
     }
 
     /* Get total size and verify that there are no missing segments */
@@ -666,6 +682,12 @@ int JPGDatasetCommon::EXIFInit(VSILFILE *fp)
 {
     int           one = 1;
     TIFFHeader    hdr;
+    
+    if( nTiffDirStart == 0 )
+        return FALSE;
+    else if( nTiffDirStart > 0 )
+        return TRUE;
+    nTiffDirStart = 0;
   
     bigendian = (*(char *)&one == 0);
 
@@ -682,34 +704,64 @@ int JPGDatasetCommon::EXIFInit(VSILFILE *fp)
 
         if( VSIFReadL( abyChunkHeader, sizeof(abyChunkHeader), 1, fp ) != 1 )
             return FALSE;
-
-        if( abyChunkHeader[0] != 0xFF 
-            || (abyChunkHeader[1] & 0xf0) != 0xe0 )
-            return FALSE; // Not an APP chunk.
-
-        if( abyChunkHeader[1] == 0xe1
-            && strncmp((const char *) abyChunkHeader + 4,"Exif",4) == 0 )
+        
+        int nChunkLength = abyChunkHeader[2] * 256 + abyChunkHeader[3];
+        // COM marker
+        if( abyChunkHeader[0] == 0xFF && abyChunkHeader[1] == 0xFE &&
+            nChunkLength >= 2 )
         {
-            nTIFFHEADER = nChunkLoc + 10;
-            break; // APP1 - Exif
+            char* pszComment = (char*)CPLMalloc(nChunkLength - 2 + 1);
+            if( nChunkLength > 2 &&
+                VSIFSeekL( fp, nChunkLoc + 4, SEEK_SET ) == 0 &&
+                VSIFReadL(pszComment, nChunkLength - 2, 1, fp) == 1 )
+            {
+                pszComment[nChunkLength-2] = 0;
+                /* Avoid setting the PAM dirty bit just for that */
+                int nOldPamFlags = nPamFlags;
+                /* Set ICC profile metadata */
+                SetMetadataItem( "COMMENT", pszComment );
+                nPamFlags = nOldPamFlags;
+            }
+            CPLFree(pszComment);
         }
+        else
+        {
+            if( abyChunkHeader[0] != 0xFF 
+                || (abyChunkHeader[1] & 0xf0) != 0xe0 )
+                break; // Not an APP chunk.
 
-        nChunkLoc += 2 + abyChunkHeader[2] * 256 + abyChunkHeader[3];
+            if( abyChunkHeader[1] == 0xe1
+                && strncmp((const char *) abyChunkHeader + 4,"Exif",4) == 0 )
+            {
+                nTIFFHEADER = nChunkLoc + 10;
+            }
+        }
+
+        nChunkLoc += 2 + nChunkLength;
     }
+    
+    if( nTIFFHEADER < 0 )
+        return FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Read TIFF header                                                */
 /* -------------------------------------------------------------------- */
     VSIFSeekL(fp, nTIFFHEADER, SEEK_SET);
     if(VSIFReadL(&hdr,1,sizeof(hdr),fp) != sizeof(hdr)) 
+    {
         CPLError( CE_Failure, CPLE_FileIO,
                   "Failed to read %d byte from image header.",
                   (int) sizeof(hdr));
+                  return FALSE;
+    }
 
     if (hdr.tiff_magic != TIFF_BIGENDIAN && hdr.tiff_magic != TIFF_LITTLEENDIAN)
+    {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "Not a TIFF file, bad magic number %u (%#x)",
                   hdr.tiff_magic, hdr.tiff_magic);
+        return FALSE;
+    }
 
     if (hdr.tiff_magic == TIFF_BIGENDIAN)    bSwabflag = !bigendian;
     if (hdr.tiff_magic == TIFF_LITTLEENDIAN) bSwabflag = bigendian;
@@ -722,9 +774,12 @@ int JPGDatasetCommon::EXIFInit(VSILFILE *fp)
 
 
     if (hdr.tiff_version != TIFF_VERSION)
+    {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "Not a TIFF file, bad version number %u (%#x)",
                  hdr.tiff_version, hdr.tiff_version); 
+        return FALSE;
+    }
     nTiffDirStart = hdr.tiff_diroff;
 
     CPLDebug( "JPEG", "Magic: %#x <%s-endian> Version: %#x\n",
@@ -1108,6 +1163,8 @@ JPGDatasetCommon::JPGDatasetCommon()
     nExifOffset     = -1;
     nInterOffset    = -1;
     nGPSOffset      = -1;
+    nTiffDirStart   = -1;
+    nTIFFHEADER     = -1;
 
     pszProjection = NULL;
     bGeoTransformValid = FALSE;
@@ -1191,6 +1248,134 @@ int JPGDatasetCommon::CloseDependentDatasets()
 }
 
 /************************************************************************/
+/*                          InitEXIFOverview()                          */
+/************************************************************************/
+
+GDALDataset* JPGDatasetCommon::InitEXIFOverview()
+{
+    if( !EXIFInit(fpImage) )
+        return NULL;
+
+    GUInt16 nEntryCount;
+/* -------------------------------------------------------------------- */
+/*      Read number of entry in directory                               */
+/* -------------------------------------------------------------------- */
+    if( VSIFSeekL(fpImage, nTiffDirStart+nTIFFHEADER, SEEK_SET) != 0
+        || VSIFReadL(&nEntryCount,1,sizeof(GUInt16),fpImage) != sizeof(GUInt16) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Error reading EXIF Directory count at %d.",
+                nTiffDirStart + nTIFFHEADER );
+        return NULL;
+    }
+
+    if (bSwabflag)
+        TIFFSwabShort(&nEntryCount);
+
+    // Some files are corrupt, a large entry count is a sign of this.
+    if( nEntryCount > 125 )
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                  "Ignoring EXIF directory with unlikely entry count (%d).",
+                  nEntryCount );
+        return NULL;
+    }
+
+    // Skip EXIF entries
+    VSIFSeekL(fpImage, nEntryCount * sizeof(TIFFDirEntry), SEEK_CUR );
+
+    // Read offset of next directory (IFD1)
+    GUInt32 nNextDirOff;
+    if( VSIFReadL(&nNextDirOff, 1, sizeof(GUInt32), fpImage) != sizeof(GUInt32) )
+        return NULL;
+    if( bSwabflag )
+        CPL_SWAP32PTR(&nNextDirOff);
+    if( nNextDirOff == 0 || nNextDirOff > 0xFFFFFFFFU - nTIFFHEADER )
+        return NULL;
+
+    // Seek to IFD1
+    if( VSIFSeekL(fpImage, nTIFFHEADER+nNextDirOff, SEEK_SET) != 0
+        || VSIFReadL(&nEntryCount,1,sizeof(GUInt16),fpImage) != sizeof(GUInt16) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Error reading IFD1 Directory count at %d.",
+                nTIFFHEADER + nNextDirOff );
+        return NULL;
+    }
+    
+    if (bSwabflag)
+        TIFFSwabShort(&nEntryCount);
+    if( nEntryCount > 125 )
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                  "Ignoring IFD1 directory with unlikely entry count (%d).",
+                  nEntryCount );
+        return NULL;
+    }
+    /* CPLDebug("JPEG", "IFD1 entry count = %d", nEntryCount); */
+
+    int nImageWidth = 0, nImageHeight = 0, nCompression = 6;
+    GUInt32 nJpegIFOffset = 0, nJpegIFByteCount = 0;
+    for( int i = 0; i < nEntryCount; i ++ )
+    {
+        TIFFDirEntry sEntry;
+        if( VSIFReadL(&sEntry,1,sizeof(sEntry),fpImage) != sizeof(sEntry) )
+        {
+            CPLError( CE_Warning, CPLE_AppDefined, "Cannot read entry %d of IFD1",
+                      i );
+            return NULL;
+        }
+        if (bSwabflag)
+        {
+            TIFFSwabShort(&sEntry.tdir_tag);
+            TIFFSwabShort(&sEntry.tdir_type);
+            TIFFSwabLong (&sEntry.tdir_count);
+            TIFFSwabLong (&sEntry.tdir_offset);
+        }
+        /*CPLDebug("JPEG", "tag = %d (0x%4X), type = %d, count = %d, offset = %d",
+                 sEntry.tdir_tag, sEntry.tdir_tag, sEntry.tdir_type, sEntry.tdir_count, sEntry.tdir_offset );*/
+
+        if( (sEntry.tdir_type == TIFF_SHORT || sEntry.tdir_type == TIFF_LONG) &&
+            sEntry.tdir_count == 1 )
+        {
+            switch( sEntry.tdir_tag )
+            {
+                case JPEG_TIFF_IMAGEWIDTH:
+                    nImageWidth = sEntry.tdir_offset;
+                    break;
+                case JPEG_TIFF_IMAGEHEIGHT:
+                    nImageHeight = sEntry.tdir_offset;
+                    break;
+                case JPEG_TIFF_COMPRESSION:
+                    nCompression = sEntry.tdir_offset;
+                    break;
+                case JPEG_EXIF_JPEGIFOFSET:
+                    nJpegIFOffset = sEntry.tdir_offset;
+                    break;
+                case JPEG_EXIF_JPEGIFBYTECOUNT:
+                    nJpegIFByteCount = sEntry.tdir_offset;
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+    if( nCompression != 6 ||
+        nImageWidth >= nRasterXSize ||
+        nImageHeight >= nRasterYSize ||
+        nJpegIFOffset == 0 ||
+        nJpegIFOffset > 0xFFFFFFFFU - nTIFFHEADER ||
+        (int)nJpegIFByteCount <= 0 )
+    {
+        return NULL;
+    }
+
+    const char* pszSubfile = CPLSPrintf("JPEG_SUBFILE:%u,%d,%s",
+                            nTIFFHEADER + nJpegIFOffset, nJpegIFByteCount, GetDescription());
+    return JPGDataset::Open(pszSubfile, NULL, NULL, 1, FALSE);
+}
+
+/************************************************************************/
 /*                       InitInternalOverviews()                        */
 /************************************************************************/
 
@@ -1205,37 +1390,84 @@ void JPGDatasetCommon::InitInternalOverviews()
 /* -------------------------------------------------------------------- */
     if( nScaleFactor == 1 && GetRasterBand(1)->GetOverviewCount() == 0 )
     {
+        /* EXIF overview */
+        GDALDataset* poEXIFOverview = NULL;
+        if( nRasterXSize > 512 || nRasterYSize > 512 )
+        {
+            vsi_l_offset nCurOffset = VSIFTellL(fpImage);
+            poEXIFOverview = InitEXIFOverview();
+            if( poEXIFOverview != NULL )
+            {
+                if( poEXIFOverview->GetRasterCount() != nBands ||
+                    poEXIFOverview->GetRasterXSize() >= nRasterXSize ||
+                    poEXIFOverview->GetRasterYSize() >= nRasterYSize )
+                {
+                    GDALClose(poEXIFOverview);
+                    poEXIFOverview = NULL;
+                }
+                else
+                {
+                    CPLDebug("JPEG", "EXIF overview (%d x %d) detected",
+                            poEXIFOverview->GetRasterXSize(),
+                            poEXIFOverview->GetRasterYSize());
+                }
+            }
+            VSIFSeekL( fpImage, nCurOffset, SEEK_SET );
+        }
+
         /* libjpeg-6b only suppports 2, 4 and 8 scale denominators */
         /* TODO: Later versions support more */
 
         int i;
-        int nInternalOverviews = 0;
+        int nImplicitOverviews = 0;
 
-        for(i = 2; i >= 0; i--)
+        /* For the needs of the implicit JPEG-in-TIFF overview mechanism */
+        if( CSLTestBoolean(CPLGetConfigOption("JPEG_FORCE_INTERNAL_OVERVIEWS", "NO")) )
+            nImplicitOverviews = 3;
+        else
         {
-            if( nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i) )
+            for(i = 2; i >= 0; i--)
             {
-                nInternalOverviews = i + 1;
-                break;
+                if( nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i) )
+                {
+                    nImplicitOverviews = i + 1;
+                    break;
+                }
             }
         }
 
-        if( nInternalOverviews > 0 )
+        if( nImplicitOverviews > 0 )
         {
             papoInternalOverviews = (GDALDataset**)
-                    CPLMalloc(nInternalOverviews * sizeof(GDALDataset*));
-            for(i = 0; i < nInternalOverviews; i++ )
+                    CPLMalloc((nImplicitOverviews + (poEXIFOverview ? 1 : 0)) * sizeof(GDALDataset*));
+            for(i = 0; i < nImplicitOverviews; i++ )
             {
-                papoInternalOverviews[i] =
-                    JPGDataset::Open(GetDescription(), NULL, 1 << (i + 1));
-                if( papoInternalOverviews[i] == NULL )
+                if( poEXIFOverview != NULL &&
+                    poEXIFOverview->GetRasterXSize() >= nRasterXSize >> (i + 1) )
                 {
-                    nInternalOverviews = i;
                     break;
                 }
+                GDALDataset* poImplicitOverview =
+                    JPGDataset::Open(GetDescription(), NULL, NULL, 1 << (i + 1), FALSE);
+                if( poImplicitOverview == NULL )
+                    break;
+                papoInternalOverviews[nInternalOverviewsCurrent] = poImplicitOverview;
+                nInternalOverviewsCurrent ++;
+                nInternalOverviewsToFree ++;
+            }
+            if( poEXIFOverview != NULL )
+            {
+                papoInternalOverviews[nInternalOverviewsCurrent] = poEXIFOverview;
+                nInternalOverviewsCurrent ++;
+                nInternalOverviewsToFree ++;
             }
-
-            nInternalOverviewsCurrent = nInternalOverviewsToFree = nInternalOverviews;
+        }
+        else if( poEXIFOverview )
+        {
+            papoInternalOverviews = (GDALDataset**) CPLMalloc(sizeof(GDALDataset*));
+            papoInternalOverviews[0] = poEXIFOverview;
+            nInternalOverviewsCurrent ++;
+            nInternalOverviewsToFree ++;
         }
     }
 }
@@ -1280,6 +1512,25 @@ int JPGDatasetCommon::ErrorOutOnNonFatalError()
 }
 
 
+/************************************************************************/
+/*                           FlushCache()                               */
+/************************************************************************/
+
+void JPGDatasetCommon::FlushCache()
+
+{
+    GDALPamDataset::FlushCache();
+
+    if (bHasDoneJpegStartDecompress)
+    {
+        Restart();
+    }
+
+    /* For the needs of the implicit JPEG-in-TIFF overview mechanism */
+    for(int i = 0; i < nInternalOverviewsCurrent; i++)
+        papoInternalOverviews[i]->FlushCache();
+}
+
 #endif // !defined(JPGDataset)
 
 /************************************************************************/
@@ -1299,7 +1550,7 @@ JPGDataset::JPGDataset()
 JPGDataset::~JPGDataset()
 
 {
-    FlushCache();
+    GDALPamDataset::FlushCache();
 
     if (bHasDoneJpegStartDecompress)
     {
@@ -1357,7 +1608,10 @@ CPLErr JPGDataset::LoadScanline( int iLine )
     }
 
     if( iLine < nLoadedScanline )
-        Restart();
+    {
+        if( Restart() != CE_None )
+            return CE_Failure;
+    }
         
     while( nLoadedScanline < iLine )
     {
@@ -1379,7 +1633,17 @@ CPLErr JPGDataset::LoadScanline( int iLine )
 
 #if !defined(JPGDataset)
 
-const GByte Q1table[64] =
+#define Q1table GDALJPEG_Q1table
+#define Q2table GDALJPEG_Q2table
+#define Q3table GDALJPEG_Q3table
+#define Q4table GDALJPEG_Q4table
+#define Q5table GDALJPEG_Q5table
+#define AC_BITS GDALJPEG_AC_BITS
+#define AC_HUFFVAL GDALJPEG_AC_HUFFVAL
+#define DC_BITS GDALJPEG_DC_BITS
+#define DC_HUFFVAL GDALJPEG_DC_HUFFVAL
+
+static const GByte Q1table[64] =
 {
    8,    72,  72,  72,  72,  72,  72,  72, // 0 - 7
     72,   72,  78,  74,  76,  74,  78,  89, // 8 - 15
@@ -1391,7 +1655,7 @@ const GByte Q1table[64] =
     255, 255, 255, 255, 255, 255, 255, 255  // 56 - 63
 };
 
-const GByte Q2table[64] =
+static const GByte Q2table[64] =
 {
     8, 36, 36, 36,
     36, 36, 36, 36, 36, 36, 39, 37, 38, 37, 39, 45, 41, 42, 42, 41, 45, 53,
@@ -1400,7 +1664,7 @@ const GByte Q2table[64] =
     178,190,178,243,243,255
 };
 
-const GByte Q3table[64] =
+static const GByte Q3table[64] =
 {
      8, 10, 10, 10,
     10, 10, 10, 10, 10, 10, 11, 10, 11, 10, 11, 13, 11, 12, 12, 11, 13, 15, 
@@ -1409,7 +1673,7 @@ const GByte Q3table[64] =
     50, 53, 50, 68, 68, 91 
 }; 
 
-const GByte Q4table[64] =
+static const GByte Q4table[64] =
 {
     8, 7, 7, 7,
     7, 7, 7, 7, 7, 7, 8, 7, 8, 7, 8, 9, 8, 8, 8, 8, 9, 11, 
@@ -1418,7 +1682,7 @@ const GByte Q4table[64] =
     36, 38, 36, 49, 49, 65
 };
 
-const GByte Q5table[64] =
+static const GByte Q5table[64] =
 {
     4, 4, 4, 4, 
     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6,
@@ -1427,10 +1691,10 @@ const GByte Q5table[64] =
     20, 21, 20, 27, 27, 36
 };
 
-const GByte AC_BITS[16] =
+static const GByte AC_BITS[16] =
 { 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125 };
 
-const GByte AC_HUFFVAL[256] = {
+static const GByte AC_HUFFVAL[256] = {
     0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,          
     0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
     0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
@@ -1462,15 +1726,13 @@ const GByte AC_HUFFVAL[256] = {
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
-const GByte DC_BITS[16] =
+static const GByte DC_BITS[16] =
 { 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
 
-const GByte DC_HUFFVAL[256] = {
+static const GByte DC_HUFFVAL[256] = {
     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
     0x08, 0x09, 0x0A, 0x0B };
 
-#endif // !defined(JPGDataset)
-
 void JPGDataset::LoadDefaultTables( int n )
 {
     if( nQLevel < 1 )
@@ -1547,6 +1809,7 @@ void JPGDataset::LoadDefaultTables( int n )
     }
 
 }
+#endif // !defined(JPGDataset)
 
 /************************************************************************/
 /*                       SetScaleNumAndDenom()                          */
@@ -1569,19 +1832,27 @@ void JPGDataset::SetScaleNumAndDenom()
 /*      Restart compressor at the beginning of the file.                */
 /************************************************************************/
 
-void JPGDataset::Restart()
+CPLErr JPGDataset::Restart()
 
 {
+    // setup to trap a fatal error.
+    if (setjmp(sErrorStruct.setjmp_buffer)) 
+        return CE_Failure;
+
     J_COLOR_SPACE colorSpace = sDInfo.out_color_space;
+    J_COLOR_SPACE jpegColorSpace = sDInfo.jpeg_color_space;
 
     jpeg_abort_decompress( &sDInfo );
     jpeg_destroy_decompress( &sDInfo );
     jpeg_create_decompress( &sDInfo );
 
+
+#if !defined(JPGDataset)
     LoadDefaultTables( 0 );
     LoadDefaultTables( 1 );
     LoadDefaultTables( 2 );
     LoadDefaultTables( 3 );
+#endif // !defined(JPGDataset)
 
 /* -------------------------------------------------------------------- */
 /*      restart io.                                                     */
@@ -1594,8 +1865,34 @@ void JPGDataset::Restart()
     sDInfo.out_color_space = colorSpace;
     nLoadedScanline = -1;
     SetScaleNumAndDenom();
-    jpeg_start_decompress( &sDInfo );
-    bHasDoneJpegStartDecompress = TRUE;
+
+    /* The following errors could happen when "recycling" an existing dataset */
+    /* particularly when triggered by the implicit overviews of JPEG-in-TIFF */
+    /* with a corrupted TIFF file */
+    if( nRasterXSize != (int)(sDInfo.image_width + nScaleFactor - 1) / nScaleFactor ||
+        nRasterYSize != (int)(sDInfo.image_height + nScaleFactor - 1) / nScaleFactor )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Unexpected image dimension (%d x %d), where as (%d x %d) was expected",
+                 (int)(sDInfo.image_width + nScaleFactor - 1) / nScaleFactor,
+                 (int)(sDInfo.image_height + nScaleFactor - 1) / nScaleFactor,
+                 nRasterXSize, nRasterYSize);
+        bHasDoneJpegStartDecompress = FALSE;
+    }
+    else if( jpegColorSpace != sDInfo.jpeg_color_space )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Unexpected jpeg color space : %d",
+                 sDInfo.jpeg_color_space);
+        bHasDoneJpegStartDecompress = FALSE;
+    }
+    else
+    {
+        jpeg_start_decompress( &sDInfo );
+        bHasDoneJpegStartDecompress = TRUE;
+    }
+
+    return CE_None;
 }
 
 #if !defined(JPGDataset)
@@ -1678,7 +1975,7 @@ const GDAL_GCP *JPGDatasetCommon::GetGCPs()
 /*                             IRasterIO()                              */
 /*                                                                      */
 /*      Checks for what might be the most common read case              */
-/*      (reading an entire interleaved, 8bit, RGB JPEG), and            */
+/*      (reading an entire 8bit, RGB JPEG), and                         */
 /*      optimizes for that case                                         */
 /************************************************************************/
 
@@ -1687,19 +1984,18 @@ CPLErr JPGDatasetCommon::IRasterIO( GDALRWFlag eRWFlag,
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType,
                               int nBandCount, int *panBandMap, 
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     if((eRWFlag == GF_Read) &&
        (nBandCount == 3) &&
        (nBands == 3) &&
-       (nXOff == 0) && (nXOff == 0) &&
+       (nXOff == 0) && (nYOff == 0) &&
        (nXSize == nBufXSize) && (nXSize == nRasterXSize) &&
        (nYSize == nBufYSize) && (nYSize == nRasterYSize) &&
        (eBufType == GDT_Byte) && (GetDataPrecision() != 12) &&
-       /*(nPixelSpace >= 3)*/(nPixelSpace > 3) &&
-       (nLineSpace == (nPixelSpace*nXSize)) &&
-       (nBandSpace == 1) &&
        (pData != NULL) &&
        (panBandMap != NULL) &&
        (panBandMap[0] == 1) && (panBandMap[1] == 2) && (panBandMap[2] == 3))
@@ -1709,18 +2005,41 @@ CPLErr JPGDatasetCommon::IRasterIO( GDALRWFlag eRWFlag,
         CPLErr tmpError;
         int x;
 
-        // handles copy with padding case
-        for(y = 0; y < nYSize; ++y)
+        // Pixel interleaved case
+        if( nBandSpace == 1 )
         {
-            tmpError = LoadScanline(y);
-            if(tmpError != CE_None) return tmpError;
+            for(y = 0; y < nYSize; ++y)
+            {
+                tmpError = LoadScanline(y);
+                if(tmpError != CE_None) return tmpError;
 
-            for(x = 0; x < nXSize; ++x)
+                if( nPixelSpace == 3 )
+                {
+                    memcpy(&(((GByte*)pData)[(y*nLineSpace)]),
+                           pabyScanline, 3 * nXSize);
+                }
+                else
+                {
+                    for(x = 0; x < nXSize; ++x)
+                    {
+                        memcpy(&(((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace)]), 
+                               (const GByte*)&(pabyScanline[x*3]), 3);
+                    }
+                }
+            }
+        }
+        else
+        {
+            for(y = 0; y < nYSize; ++y)
             {
                 tmpError = LoadScanline(y);
                 if(tmpError != CE_None) return tmpError;
-                memcpy(&(((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace)]), 
-                       (const GByte*)&(pabyScanline[x*3]), 3);
+                for(x = 0; x < nXSize; ++x)
+                {
+                    ((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace)] = pabyScanline[x*3];
+                    ((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace) + nBandSpace] = pabyScanline[x*3+1];
+                    ((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace) + 2 * nBandSpace] = pabyScanline[x*3+2];
+                }
             }
         }
 
@@ -1730,7 +2049,8 @@ CPLErr JPGDatasetCommon::IRasterIO( GDALRWFlag eRWFlag,
     return GDALPamDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                      pData, nBufXSize, nBufYSize, eBufType, 
                                      nBandCount, panBandMap, 
-                                     nPixelSpace, nLineSpace, nBandSpace);
+                                     nPixelSpace, nLineSpace, nBandSpace,
+                                     psExtraArg);
 }
 
 #if JPEG_LIB_VERSION_MAJOR < 9
@@ -1836,7 +2156,13 @@ GDALDataset *JPGDatasetCommon::Open( GDALOpenInfo * poOpenInfo )
         return NULL;
     }
 
-    return JPGDataset::Open(poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles);
+    VSILFILE* fpL = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+
+    return JPGDataset::Open(poOpenInfo->pszFilename,
+                            fpL,
+                            poOpenInfo->GetSiblingFiles(),
+                            1, TRUE);
 }
 
 #endif // !defined(JPGDataset)
@@ -1845,8 +2171,11 @@ GDALDataset *JPGDatasetCommon::Open( GDALOpenInfo * poOpenInfo )
 /*                                Open()                                */
 /************************************************************************/
 
-GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles,
-                               int nScaleFactor )
+GDALDataset *JPGDataset::Open( const char* pszFilename,
+                               VSILFILE* fpLin,
+                               char** papszSiblingFiles,
+                               int nScaleFactor,
+                               int bDoPAMInitialize )
 
 {
 /* -------------------------------------------------------------------- */
@@ -1917,19 +2246,24 @@ GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles
     }
 
 /* -------------------------------------------------------------------- */
-/*      Open the file using the large file api.                         */
+/*      Open the file using the large file api if necessary.            */
 /* -------------------------------------------------------------------- */
     VSILFILE* fpImage;
 
-    fpImage = VSIFOpenL( real_filename, "rb" );
-
-    if( fpImage == NULL )
+    if( fpLin == NULL )
     {
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                "VSIFOpenL(%s) failed unexpectedly in jpgdataset.cpp",
-                real_filename );
-        return NULL;
+        fpImage = VSIFOpenL( real_filename, "rb" );
+
+        if( fpImage == NULL )
+        {
+            CPLError( CE_Failure, CPLE_OpenFailed,
+                    "VSIFOpenL(%s) failed unexpectedly in jpgdataset.cpp",
+                    real_filename );
+            return NULL;
+        }
     }
+    else
+        fpImage = fpLin;
 
 /* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
@@ -1958,7 +2292,7 @@ GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles
     poDS->sDInfo.err = jpeg_std_error( &(poDS->sJErr) );
     poDS->sJErr.error_exit = JPGDataset::ErrorExit;
     poDS->sErrorStruct.p_previous_emit_message = poDS->sJErr.emit_message;
-    poDS->sJErr.emit_message = JPGDataset::EmitMessage;
+    poDS->sJErr.emit_message = JPGDatasetCommon::EmitMessage;
     poDS->sDInfo.client_data = (void *) &(poDS->sErrorStruct);
 
     jpeg_create_decompress( &(poDS->sDInfo) );
@@ -1976,10 +2310,13 @@ GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles
 /* -------------------------------------------------------------------- */
 /*      Preload default NITF JPEG quantization tables.                  */
 /* -------------------------------------------------------------------- */
+
+#if !defined(JPGDataset)
     poDS->LoadDefaultTables( 0 );
     poDS->LoadDefaultTables( 1 );
     poDS->LoadDefaultTables( 2 );
     poDS->LoadDefaultTables( 3 );
+#endif // !defined(JPGDataset)
 
 /* -------------------------------------------------------------------- */
 /*      If a fatal error occurs after this, we will return NULL         */
@@ -1989,9 +2326,11 @@ GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles
 #if defined(JPEG_DUAL_MODE_8_12) && !defined(JPGDataset)
         if (poDS->sDInfo.data_precision == 12)
         {
+            fpImage = poDS->fpImage;
+            poDS->fpImage = NULL;
             delete poDS;
-            return JPEGDataset12Open(pszFilename, papszSiblingFiles,
-                                     nScaleFactor);
+            return JPEGDataset12Open(pszFilename, fpImage, papszSiblingFiles,
+                                     nScaleFactor, bDoPAMInitialize);
         }
 #endif
         delete poDS;
@@ -2105,7 +2444,7 @@ GDALDataset *JPGDataset::Open( const char* pszFilename, char** papszSiblingFiles
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( pszFilename );
 
-    if( nScaleFactor == 1 )
+    if( nScaleFactor == 1 && bDoPAMInitialize )
     {
         if( !bIsSubfile )
             poDS->TryLoadXML( papszSiblingFiles );
@@ -2392,11 +2731,13 @@ void JPGDataset::ErrorExit(j_common_ptr cinfo)
     longjmp(psErrorStruct->setjmp_buffer, 1);
 }
 
+#if !defined(JPGDataset)
+
 /************************************************************************/
 /*                             EmitMessage()                            */
 /************************************************************************/
 
-void JPGDataset::EmitMessage(j_common_ptr cinfo, int msg_level)
+void JPGDatasetCommon::EmitMessage(j_common_ptr cinfo, int msg_level)
 {
     GDALJPEGErrorStruct* psErrorStruct = (GDALJPEGErrorStruct* ) cinfo->client_data;
     if( msg_level >= 0 ) /* Trace message */
@@ -2440,7 +2781,10 @@ void JPGDataset::EmitMessage(j_common_ptr cinfo, int msg_level)
 /*      This function adds an ICC profile to a JPEG file.               */
 /************************************************************************/
 
-static void JPGAddICCProfile( struct jpeg_compress_struct *pInfo, const char *pszICCProfile )
+void JPGAddICCProfile( struct jpeg_compress_struct *pInfo,
+                       const char *pszICCProfile,
+                       void (*p_jpeg_write_m_header) (j_compress_ptr cinfo, int marker, unsigned int datalen),
+                       void (*p_jpeg_write_m_byte) (j_compress_ptr cinfo, int val))
 {
     if( pszICCProfile == NULL )
         return;
@@ -2460,20 +2804,20 @@ static void JPGAddICCProfile( struct jpeg_compress_struct *pInfo, const char *ps
         nEmbedLen -= nChunkLen;
 
         /* write marker and length. */
-        jpeg_write_m_header(pInfo, JPEG_APP0 + 2,
+        p_jpeg_write_m_header(pInfo, JPEG_APP0 + 2,
 			        (unsigned int) (nChunkLen + 14));
 
         /* Write identifier */
         for(int i = 0; i < 12; i++)
-            jpeg_write_m_byte(pInfo, paHeader[i]);
+            p_jpeg_write_m_byte(pInfo, paHeader[i]);
 
         /* Write ID and max ID */
-        jpeg_write_m_byte(pInfo, nSegmentID);
-        jpeg_write_m_byte(pInfo, nSegments);
+        p_jpeg_write_m_byte(pInfo, nSegmentID);
+        p_jpeg_write_m_byte(pInfo, nSegments);
 
         /* Write ICC Profile */
         for(int i = 0; i < nChunkLen; i++)
-            jpeg_write_m_byte(pInfo, pEmbedPtr[i]);
+            p_jpeg_write_m_byte(pInfo, pEmbedPtr[i]);
 
         nSegmentID++;
 
@@ -2483,8 +2827,6 @@ static void JPGAddICCProfile( struct jpeg_compress_struct *pInfo, const char *ps
     CPLFree(pEmbedBuffer);        
 }
 
-#if !defined(JPGDataset)
-
 /************************************************************************/
 /*                           JPGAppendMask()                            */
 /*                                                                      */
@@ -2532,7 +2874,7 @@ CPLErr JPGAppendMask( const char *pszJPGFilename, GDALRasterBand *poMask,
     for( iY = 0; eErr == CE_None && iY < nYSize; iY++ )
     {
         eErr = poMask->RasterIO( GF_Read, 0, iY, nXSize, 1,
-                                 pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0 );
+                                 pabyMaskLine, nXSize, 1, GDT_Byte, 0, 0, NULL );
         if( eErr != CE_None )
             break;
 
@@ -2639,6 +2981,239 @@ CPLErr JPGAppendMask( const char *pszJPGFilename, GDALRasterBand *poMask,
     return eErr;
 }
 
+/************************************************************************/
+/*                          JPGAddEXIFOverview()                        */
+/************************************************************************/
+
+void   JPGAddEXIFOverview( GDALDataType eWorkDT,
+                           GDALDataset* poSrcDS, char** papszOptions,
+                           j_compress_ptr cinfo,
+                           void (*p_jpeg_write_m_header) (j_compress_ptr cinfo, int marker, unsigned int datalen),
+                           void (*p_jpeg_write_m_byte) (j_compress_ptr cinfo, int val),
+                           GDALDataset *(pCreateCopy)( const char *, GDALDataset *, 
+                                     int, char **,
+                                     GDALProgressFunc pfnProgress, 
+                                     void * pProgressData ))
+{
+    int  nBands = poSrcDS->GetRasterCount();
+    int  nXSize = poSrcDS->GetRasterXSize();
+    int  nYSize = poSrcDS->GetRasterYSize();
+
+    int bGenerateEXIFThumbnail =
+        CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "EXIF_THUMBNAIL", "NO"));
+    const char* pszThumbnailWidth = CSLFetchNameValue(papszOptions, "THUMBNAIL_WIDTH");
+    const char* pszThumbnailHeight = CSLFetchNameValue(papszOptions, "THUMBNAIL_HEIGHT");
+    int nOvrWidth = 0, nOvrHeight = 0;
+    if( pszThumbnailWidth == NULL && pszThumbnailHeight == NULL )
+    {
+        if( nXSize >= nYSize )
+        {
+            nOvrWidth = 128;
+        }
+        else
+        {
+            nOvrHeight = 128;
+        }
+    }
+    if( pszThumbnailWidth != NULL )
+    {
+        nOvrWidth = atoi(pszThumbnailWidth);
+        if( nOvrWidth < 32 )
+            nOvrWidth = 32;
+        if( nOvrWidth > 1024 )
+            nOvrWidth = 1024;
+    }
+    if( pszThumbnailHeight != NULL )
+    {
+        nOvrHeight = atoi(pszThumbnailHeight);
+        if( nOvrHeight < 32 )
+            nOvrHeight = 32;
+        if( nOvrHeight > 1024 )
+            nOvrHeight = 1024;
+    }
+    if( nOvrWidth == 0 )
+    {
+        nOvrWidth = (int)((GIntBig)nOvrHeight * nXSize / nYSize);
+        if( nOvrWidth == 0 ) nOvrWidth = 1;
+    }
+    else if( nOvrHeight == 0 )
+    {
+        nOvrHeight = (int)((GIntBig)nOvrWidth * nYSize / nXSize);
+        if( nOvrHeight == 0 ) nOvrHeight = 1;
+    }
+
+    if( bGenerateEXIFThumbnail && nXSize > nOvrWidth && nYSize > nOvrHeight )
+    {
+        GDALDataset* poMemDS = MEMDataset::Create("", nOvrWidth, nOvrHeight, nBands, eWorkDT, NULL);
+        GDALRasterBand** papoSrcBands = (GDALRasterBand**)CPLMalloc(nBands * sizeof(GDALRasterBand*));
+        GDALRasterBand*** papapoOverviewBands= (GDALRasterBand***)CPLMalloc(nBands * sizeof(GDALRasterBand**));
+        int i;
+        for(i=0;i<nBands;i++)
+        {
+            papoSrcBands[i] = poSrcDS->GetRasterBand(i+1);
+            papapoOverviewBands[i] = (GDALRasterBand**)CPLMalloc(sizeof(GDALRasterBand*));
+            papapoOverviewBands[i][0] = poMemDS->GetRasterBand(i+1);
+        }
+        CPLErr eErr = GDALRegenerateOverviewsMultiBand(nBands, papoSrcBands,
+                                        1, papapoOverviewBands,
+                                        "AVERAGE", NULL, NULL);
+        CPLFree(papoSrcBands);
+        for(i=0;i<nBands;i++)
+        {
+            CPLFree(papapoOverviewBands[i]);
+        }
+        CPLFree(papapoOverviewBands);
+
+        if( eErr != CE_None )
+        {
+            GDALClose(poMemDS);
+            return;
+        }
+
+        CPLString osTmpFile(CPLSPrintf("/vsimem/ovrjpg%p",poMemDS));
+        GDALDataset* poOutDS = pCreateCopy(osTmpFile, poMemDS, 0, NULL, GDALDummyProgress, NULL);
+        delete poOutDS;
+        GDALClose(poMemDS);
+        vsi_l_offset nJPEGIfByteCount = 0;
+        GByte* pabyOvr = NULL;
+        if( poOutDS != NULL )
+            pabyOvr = VSIGetMemFileBuffer( osTmpFile, &nJPEGIfByteCount, TRUE );
+        VSIUnlink(osTmpFile);
+
+        unsigned int nMarkerSize = 6 + 16 + 5 * 12 + 4 + nJPEGIfByteCount;
+        if( pabyOvr == NULL )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined, "Could not generate EXIF overview");
+        }
+        else if( nMarkerSize < 65536 )
+        {
+            p_jpeg_write_m_header( cinfo, JPEG_APP0 + 1, nMarkerSize );
+            p_jpeg_write_m_byte( cinfo, 'E' ); /* EXIF signature */
+            p_jpeg_write_m_byte( cinfo, 'x' );
+            p_jpeg_write_m_byte( cinfo, 'i' );
+            p_jpeg_write_m_byte( cinfo, 'f' );
+            p_jpeg_write_m_byte( cinfo, '\0' );
+            p_jpeg_write_m_byte( cinfo, '\0' );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_LITTLEENDIAN & 0xff ); /* TIFF little-endian signature */
+            p_jpeg_write_m_byte( cinfo, TIFF_LITTLEENDIAN >> 8 );
+            p_jpeg_write_m_byte( cinfo, TIFF_VERSION );
+            p_jpeg_write_m_byte( cinfo, 0x00 );
+
+            p_jpeg_write_m_byte( cinfo, 8 ); /* Offset of IFD0 */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 0 ); /* Number of entries of IFD0 */
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 14 ); /* Offset of IFD1 */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 5 ); /* Number of entries of IFD1 */
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, JPEG_TIFF_IMAGEWIDTH & 0xff );
+            p_jpeg_write_m_byte( cinfo, (JPEG_TIFF_IMAGEWIDTH >> 8) & 0xff );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_LONG );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 1 ); /* 1 value */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, nOvrWidth & 0xff );
+            p_jpeg_write_m_byte( cinfo, nOvrWidth >> 8 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, JPEG_TIFF_IMAGEHEIGHT & 0xff );
+            p_jpeg_write_m_byte( cinfo, JPEG_TIFF_IMAGEHEIGHT >> 8 );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_LONG );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 1 ); /* 1 value */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, nOvrHeight & 0xff );
+            p_jpeg_write_m_byte( cinfo, nOvrHeight >> 8 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, JPEG_TIFF_COMPRESSION & 0xff );
+            p_jpeg_write_m_byte( cinfo, JPEG_TIFF_COMPRESSION >> 8 );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_SHORT );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 1 ); /* 1 value */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 6 ); /* JPEG compression */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, JPEG_EXIF_JPEGIFOFSET & 0xff );
+            p_jpeg_write_m_byte( cinfo, JPEG_EXIF_JPEGIFOFSET >> 8 );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_LONG );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 1 ); /* 1 value */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            const unsigned int nJPEGIfOffset = 16 + 5 * 12 + 4;
+            p_jpeg_write_m_byte( cinfo, nJPEGIfOffset & 0xff );
+            p_jpeg_write_m_byte( cinfo, nJPEGIfOffset >> 8 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, JPEG_EXIF_JPEGIFBYTECOUNT & 0xff );
+            p_jpeg_write_m_byte( cinfo, JPEG_EXIF_JPEGIFBYTECOUNT >> 8 );
+
+            p_jpeg_write_m_byte( cinfo, TIFF_LONG );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 1 ); /* 1 value */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, nJPEGIfByteCount & 0xff );
+            p_jpeg_write_m_byte( cinfo, nJPEGIfByteCount >> 8 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            p_jpeg_write_m_byte( cinfo, 0 ); /* Offset of IFD2 == 0 ==> end of TIFF directory */
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+            p_jpeg_write_m_byte( cinfo, 0 );
+
+            for(int i=0; i<(int)nJPEGIfByteCount; i++)
+                p_jpeg_write_m_byte( cinfo, pabyOvr[i] );
+        }
+        else
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "Cannot write EXIF thumbnail. The size of the EXIF segment exceeds 65536 bytes");
+        }
+        CPLFree(pabyOvr);
+    }
+}
+
 #endif // !defined(JPGDataset)
 
 /************************************************************************/
@@ -2777,7 +3352,7 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     sCInfo.err = jpeg_std_error( &sJErr );
     sJErr.error_exit = JPGDataset::ErrorExit;
     sErrorStruct.p_previous_emit_message = sJErr.emit_message;
-    sJErr.emit_message = JPGDataset::EmitMessage;
+    sJErr.emit_message = JPGDatasetCommon::EmitMessage;
     sCInfo.client_data = (void *) &(sErrorStruct);
 
     jpeg_create_compress( &sCInfo );
@@ -2796,7 +3371,16 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         sCInfo.in_color_space = JCS_UNKNOWN;
 
     jpeg_set_defaults( &sCInfo );
-    
+
+    /* This is to address bug related in ticket #1795 */
+    if (CPLGetConfigOption("JPEGMEM", NULL) == NULL)
+    {
+        /* If the user doesn't provide a value for JPEGMEM, we want to be sure */
+        /* that at least 500 MB will be used before creating the temporary file */
+        sCInfo.mem->max_memory_to_use =
+                MAX(sCInfo.mem->max_memory_to_use, 500 * 1024 * 1024);
+    }
+
     if( eDT == GDT_UInt16 )
     {
         sCInfo.data_precision = 12;
@@ -2810,6 +3394,11 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     if( pszVal )
         sCInfo.arith_code = CSLTestBoolean(pszVal);
 
+    /* Optimized Huffman coding. Supposedly slower according to libjpeg doc */
+    /* but no longer significant with today computer standards */
+    if( !sCInfo.arith_code )
+        sCInfo.optimize_coding = TRUE;
+
 #if JPEG_LIB_VERSION_MAJOR >= 8 && \
       (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
     pszVal = CSLFetchNameValue(papszOptions, "BLOCK");
@@ -2848,6 +3437,18 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     jpeg_start_compress( &sCInfo, TRUE );
 
+    JPGAddEXIFOverview( eWorkDT, poSrcDS, papszOptions, 
+                        &sCInfo, jpeg_write_m_header, jpeg_write_m_byte,
+                        CreateCopy ); 
+
+/* -------------------------------------------------------------------- */
+/*      Add comment if available                                        */
+/* -------------------------------------------------------------------- */
+    const char *pszComment = CSLFetchNameValue(papszOptions, "COMMENT");
+    if( pszComment )
+        jpeg_write_marker(&sCInfo, JPEG_COM, (const JOCTET*)pszComment,
+                          (unsigned int)strlen(pszComment));
+
 /* -------------------------------------------------------------------- */
 /*      Save ICC profile if available                                   */
 /* -------------------------------------------------------------------- */
@@ -2856,7 +3457,8 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         pszICCProfile = poSrcDS->GetMetadataItem( "SOURCE_ICC_PROFILE", "COLOR_PROFILE" );
 
     if (pszICCProfile != NULL)
-        JPGAddICCProfile( &sCInfo, pszICCProfile );
+        JPGAddICCProfile( &sCInfo, pszICCProfile,
+                          jpeg_write_m_header, jpeg_write_m_byte );
 
 /* -------------------------------------------------------------------- */
 /*      Does the source have a mask?  If so, we will append it to the   */
@@ -2886,7 +3488,7 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                   pabyScanline, nXSize, 1, eWorkDT,
                                   nBands, NULL,
                                   nBands*nWorkDTSize, 
-                                  nBands * nXSize * nWorkDTSize, nWorkDTSize );
+                                  nBands * nXSize * nWorkDTSize, nWorkDTSize, NULL );
 
         // clamp 16bit values to 12bit.
         if( nWorkDTSize == 2 )
@@ -2973,7 +3575,7 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     /* If outputing to stdout, we can't reopen it, so we'll return */
@@ -2981,7 +3583,7 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     if( CSLTestBoolean(CPLGetConfigOption("GDAL_OPEN_AFTER_COPY", "YES")) )
     {
         CPLPushErrorHandler(CPLQuietErrorHandler);
-        JPGDataset *poDS = (JPGDataset*) Open( pszFilename );
+        JPGDataset *poDS = (JPGDataset*) Open( pszFilename, NULL, NULL, 1, TRUE );
         CPLPopErrorHandler();
         if( poDS )
         {
@@ -3005,6 +3607,99 @@ JPGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 /************************************************************************/
 
 #if !defined(JPGDataset)
+
+class GDALJPGDriver: public GDALDriver
+{
+    public:
+        GDALJPGDriver() {}
+
+        char      **GetMetadata( const char * pszDomain = "" );
+        const char *GetMetadataItem( const char * pszName,
+                                      const char * pszDomain = "" );
+
+};
+
+char** GDALJPGDriver::GetMetadata( const char * pszDomain )
+{
+    GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST);
+    return GDALDriver::GetMetadata(pszDomain);
+}
+
+static void GDALJPEGIsArithmeticCodingAvailableErrorExit(j_common_ptr cinfo)
+{
+    jmp_buf* p_setjmp_buffer = (jmp_buf* ) cinfo->client_data;
+    /* Return control to the setjmp point */
+    longjmp(*p_setjmp_buffer, 1);
+}
+
+/* Runtime check if arithmetic coding is available */
+static int GDALJPEGIsArithmeticCodingAvailable()
+{
+    struct jpeg_compress_struct sCInfo;
+    struct jpeg_error_mgr sJErr;
+    jmp_buf     setjmp_buffer;
+    if (setjmp(setjmp_buffer)) 
+    {
+        jpeg_destroy_compress( &sCInfo );
+        return FALSE;
+    }
+    sCInfo.err = jpeg_std_error( &sJErr );
+    sJErr.error_exit = GDALJPEGIsArithmeticCodingAvailableErrorExit;
+    sCInfo.client_data = (void *) &(setjmp_buffer);
+    jpeg_create_compress( &sCInfo );
+    /* Hopefully nothing will be written */
+    jpeg_stdio_dest(&sCInfo, stderr);
+    sCInfo.image_width = 1;
+    sCInfo.image_height = 1;
+    sCInfo.input_components = 1;
+    sCInfo.in_color_space = JCS_UNKNOWN;
+    jpeg_set_defaults( &sCInfo );
+    sCInfo.arith_code = TRUE;
+    jpeg_start_compress( &sCInfo, FALSE );
+    jpeg_abort_compress( &sCInfo );
+    jpeg_destroy_compress( &sCInfo );
+    
+    return TRUE;
+}
+
+const char *GDALJPGDriver::GetMetadataItem( const char * pszName,
+                                            const char * pszDomain )
+{
+    if( pszName != NULL && EQUAL(pszName, GDAL_DMD_CREATIONOPTIONLIST) &&
+        (pszDomain == NULL || EQUAL(pszDomain, "")) &&
+        GDALDriver::GetMetadataItem(pszName, pszDomain) == NULL )
+    {
+        CPLString osCreationOptions =
+"<CreationOptionList>\n"
+"   <Option name='PROGRESSIVE' type='boolean' description='whether to generate a progressive JPEG' default='NO'/>\n"
+"   <Option name='QUALITY' type='int' description='good=100, bad=0, default=75'/>\n"
+"   <Option name='WORLDFILE' type='boolean' description='whether to geneate a worldfile' default='NO'/>\n"
+"   <Option name='INTERNAL_MASK' type='boolean' description='whether to generate a validity mask' default='YES'/>\n";
+        if( GDALJPEGIsArithmeticCodingAvailable() )
+            osCreationOptions +=
+"   <Option name='ARITHMETIC' type='boolean' description='whether to use arithmetic encoding' default='NO'/>\n";
+    osCreationOptions +=
+#if JPEG_LIB_VERSION_MAJOR >= 8 && \
+      (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
+"   <Option name='BLOCK' type='int' description='between 1 and 16'/>\n"
+#endif
+#if JPEG_LIB_VERSION_MAJOR >= 9
+"   <Option name='COLOR_TRANSFORM' type='string-select'>\n"
+"       <Value>RGB</Value>"
+"       <Value>RGB1</Value>"
+"   </Option>"
+#endif
+"   <Option name='COMMENT' description='Comment' type='string'/>\n"
+"   <Option name='SOURCE_ICC_PROFILE' description='ICC profile encoded in Base64' type='string'/>\n"
+"   <Option name='EXIF_THUMBNAIL' type='boolean' description='whether to generate an EXIF thumbnail(overview). By default its max dimension will be 128' default='NO'/>\n"
+"   <Option name='THUMBNAIL_WIDTH' type='int' description='Forced thumbnail width' min='32' max='512'/>\n"
+"   <Option name='THUMBNAIL_HEIGHT' type='int' description='Forced thumbnail height' min='32' max='512'/>\n"
+"</CreationOptionList>\n";
+        SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, osCreationOptions );
+    }
+    return GDALDriver::GetMetadataItem(pszName, pszDomain);
+}
+
 void GDALRegister_JPEG()
 
 {
@@ -3012,14 +3707,16 @@ void GDALRegister_JPEG()
 
     if( GDALGetDriverByName( "JPEG" ) == NULL )
     {
-        poDriver = new GDALDriver();
+        poDriver = new GDALJPGDriver();
         
         poDriver->SetDescription( "JPEG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JPEG JFIF" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_jpeg.html" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jpg" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "jpg jpeg" );
         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jpeg" );
 
 #if defined(JPEG_LIB_MK1_OR_12BIT) || defined(JPEG_DUAL_MODE_8_12)
@@ -3029,26 +3726,6 @@ void GDALRegister_JPEG()
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
                                    "Byte" );
 #endif
-        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
-"<CreationOptionList>\n"
-"   <Option name='PROGRESSIVE' type='boolean' default='NO'/>\n"
-"   <Option name='QUALITY' type='int' description='good=100, bad=0, default=75'/>\n"
-"   <Option name='WORLDFILE' type='boolean' default='NO'/>\n"
-"   <Option name='INTERNAL_MASK' type='boolean' default='YES'/>\n"
-"   <Option name='ARITHMETIC' type='boolean' default='NO'/>\n"
-#if JPEG_LIB_VERSION_MAJOR >= 8 && \
-      (JPEG_LIB_VERSION_MAJOR > 8 || JPEG_LIB_VERSION_MINOR >= 3)
-"   <Option name='BLOCK' type='int' description='between 1 and 16'/>\n"
-#endif
-#if JPEG_LIB_VERSION_MAJOR >= 9
-"   <Option name='COLOR_TRANSFORM' type='string-select'>\n"
-"       <Value>RGB</Value>"
-"       <Value>RGB1</Value>"
-"   </Option>"
-#endif
-"   <Option name='SOURCE_ICC_PROFILE' type='string'/>\n"
-"</CreationOptionList>\n" );
-
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
         poDriver->pfnIdentify = JPGDatasetCommon::Identify;
diff --git a/frmts/jpeg/jpgdataset_12.cpp b/frmts/jpeg/jpgdataset_12.cpp
index da8ec78..6115370 100644
--- a/frmts/jpeg/jpgdataset_12.cpp
+++ b/frmts/jpeg/jpgdataset_12.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jpgdataset_12.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: jpgdataset_12.cpp 28028 2014-11-30 11:46:11Z rouault $
  *
  * Project:  JPEG JFIF Driver
  * Purpose:  Implement GDAL JPEG Support based on IJG libjpeg.
@@ -33,10 +33,13 @@
 #include "jpgdataset.cpp"
 
 GDALDataset* JPEGDataset12Open(const char* pszFilename,
+                               VSILFILE* fpLin,
                                char** papszSiblingFiles,
-                               int nScaleFactor)
+                               int nScaleFactor,
+                               int bDoPAMInitialize)
 {
-    return JPGDataset12::Open(pszFilename, papszSiblingFiles, nScaleFactor);
+    return JPGDataset12::Open(pszFilename, fpLin, papszSiblingFiles, nScaleFactor,
+                              bDoPAMInitialize);
 }
 
 GDALDataset* JPEGDataset12CreateCopy( const char * pszFilename,
diff --git a/frmts/jpeg/makefile.vc b/frmts/jpeg/makefile.vc
index b168a4d..85c8b14 100644
--- a/frmts/jpeg/makefile.vc
+++ b/frmts/jpeg/makefile.vc
@@ -6,9 +6,9 @@ OBJ	=    jpgdataset.obj jpgdataset_12.obj vsidataio.obj
 
 
 !IFDEF JPEG_EXTERNAL_LIB
-EXTRAFLAGS      = -I$(JPEGDIR)
+EXTRAFLAGS      = -I$(JPEGDIR) -I..\mem
 !ELSE
-EXTRAFLAGS = 	-Ilibjpeg $(JPEG12_FLAGS)
+EXTRAFLAGS = 	-Ilibjpeg $(JPEG12_FLAGS) -I..\mem
 !ENDIF
 
 !IFDEF JPEG12_SUPPORTED
diff --git a/frmts/jpeg/vsidataio.cpp b/frmts/jpeg/vsidataio.cpp
index c95e1e2..f03d5e7 100644
--- a/frmts/jpeg/vsidataio.cpp
+++ b/frmts/jpeg/vsidataio.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vsidataio.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: vsidataio.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  JPEG JFIF Driver
  * Purpose:  Implement JPEG read/write io indirection through VSI.
@@ -30,7 +30,7 @@
 
 #include "vsidataio.h"
 
-CPL_CVSID("$Id: vsidataio.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: vsidataio.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 #include "jerror.h"
diff --git a/frmts/jpeg2000/GNUmakefile b/frmts/jpeg2000/GNUmakefile
index e2665fe..a67b3ab 100644
--- a/frmts/jpeg2000/GNUmakefile
+++ b/frmts/jpeg2000/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	jpeg2000dataset.o jpeg2000_vsil_io.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(JASPER_FLAGS) $(CPPFLAGS)
+CPPFLAGS	:=	 $(JASPER_FLAGS) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/jpeg2000/frmt_jpeg2000.html b/frmts/jpeg2000/frmt_jpeg2000.html
index 8e70e87..b994964 100644
--- a/frmts/jpeg2000/frmt_jpeg2000.html
+++ b/frmts/jpeg2000/frmt_jpeg2000.html
@@ -13,6 +13,16 @@ This implementation based on JasPer software (see below).<p>
 Starting with GDAL 1.9.0, XMP metadata can be extracted from JPEG2000 files, and will be
 stored as XML raw content in the xml:XMP metadata domain.<p>
 
+<h2>Option Options</h2>
+
+(GDAL >= 2.0 )
+
+The following open option is available:
+<ul>
+<li><p><b>1BIT_ALPHA_PROMOTION=YES/NO</b>: Whether a 1-bit alpha channel should be promoted to 8-bit.
+Defaults to YES.</li>
+</ul>
+
 <h2>Creation Options</h2>
 <ul>
 	<li> <b>WORLDFILE=ON</b>: Force the generation of an associated
@@ -20,6 +30,29 @@ stored as XML raw content in the xml:XMP metadata domain.<p>
 
 	<li> <b>FORMAT=JP2|JPC</b>: Specify output file format.<p>
 
+<li> <b>GMLJP2=YES/NO</b>: (Starting with GDAL 2.0) Indicates whether a GML box
+conforming to the OGC GML in JPEG2000 specification should be included in the
+file. Unless GMLJP2V2_DEF is used, the version of the GMLJP2 box will be
+version 1. As implemented currently, the GMLJP2 box will be written after the
+codestream. Defaults to YES.<p>
+
+<li> <b>GMLJP2V2_DEF=filename</b>: (Starting with GDAL 2.0) Indicates whether a GML box
+conforming to the <a href="http://docs.opengeospatial.org/is/08-085r4/08-085r4.html">
+OGC GML in JPEG2000, version 2</a> specification should be included in the
+file. <i>filename</i> must point to a file with a JSon content that defines how
+the GMLJP2 v2 box should be built. See <a href="frmt_jp2openjpeg.html#GMLJP2v2Def">
+GMLJP2v2 definition file section</a> in documentation of the JP2OpenJPEG driver
+for the syntax of the JSon configuration file.
+It is also possible to directly pass the JSon content inlined as a string.
+If filename is just set to YES, a minimal instance will be built.
+As implemented currently, the GMLJP2 box will be written after the codestream.<p>
+
+<li> <b>GeoJP2=YES/NO</b>: (Option starting with GDAL 2.0, but already enabled in
+previous versions. Require a modified Jasper with GeoJP2 support enabled)
+Indicates whether a UUID/GeoTIFF
+box conforming to the GeoJP2 (GeoTIFF in JPEG2000) specification should be
+included in the file.  Defaults to YES.<p>
+
 	<li> Encoding parameters, directly delivered to the JasPer library
 	described in the JasPer documentation. Quoted from the docs:<p>
 
@@ -254,9 +287,9 @@ The JasPer Project Home Page
 Other JPEG2000 GDAL drivers :
 <ul>
 <li><p> <a href="frmt_jp2openjpeg.html">JP2OpenJPEG: based on OpenJPEG library (open source)</a></p></li>
-<li><p> <a href="frmt_jp2ecw.html">JP2ECW: based on Erdas ECW library (commercial)</a></p></li>
-<li><p> <a href="frmt_jp2mrsid.html">JP2MRSID: based on LizardTech MrSID library (commercial)</a></p></li>
-<li><p> <a href="frmt_jp2kak.html">JP2KAK: based on Kakadu library (commercial)</a></p></li>
+<li><p> <a href="frmt_jp2ecw.html">JP2ECW: based on Erdas ECW library (proprietary)</a></p></li>
+<li><p> <a href="frmt_jp2mrsid.html">JP2MRSID: based on LizardTech MrSID library (proprietary)</a></p></li>
+<li><p> <a href="frmt_jp2kak.html">JP2KAK: based on Kakadu library (proprietary)</a></p></li>
 </ul>
 
 </body>
diff --git a/frmts/jpeg2000/jpeg2000dataset.cpp b/frmts/jpeg2000/jpeg2000dataset.cpp
index cccb82e..430a25e 100644
--- a/frmts/jpeg2000/jpeg2000dataset.cpp
+++ b/frmts/jpeg2000/jpeg2000dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jpeg2000dataset.cpp 27182 2014-04-14 20:03:08Z rouault $
+ * $Id: jpeg2000dataset.cpp 29075 2015-04-30 12:51:21Z rouault $
  *
  * Project:  JPEG-2000
  * Purpose:  Partial implementation of the ISO/IEC 15444-1 standard
@@ -35,7 +35,7 @@
 #include <jasper/jasper.h>
 #include "jpeg2000_vsil_io.h"
 
-CPL_CVSID("$Id: jpeg2000dataset.cpp 27182 2014-04-14 20:03:08Z rouault $");
+CPL_CVSID("$Id: jpeg2000dataset.cpp 29075 2015-04-30 12:51:21Z rouault $");
 
 CPL_C_START
 void    GDALRegister_JPEG2000(void);
@@ -175,6 +175,7 @@ class JPEG2000Dataset : public GDALJP2AbstractDataset
     jas_stream_t *psStream;
     jas_image_t *psImage;
     int         iFormat;
+    int         bPromoteTo8Bit;
 
     int         bAlreadyDecoded;
     int         DecodeImage();
@@ -258,6 +259,14 @@ JPEG2000RasterBand::JPEG2000RasterBand( JPEG2000Dataset *poDS, int nBand,
     nBlockXSize = MIN(256, poDS->nRasterXSize);
     nBlockYSize = MIN(256, poDS->nRasterYSize);
     psMatrix = jas_matrix_create(nBlockYSize, nBlockXSize);
+
+    if( iDepth % 8 != 0 && !poDS->bPromoteTo8Bit )
+    {
+        SetMetadataItem( "NBITS", 
+                         CPLString().Printf("%d",iDepth), 
+                         "IMAGE_STRUCTURE" );
+    }
+    SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
 }
 
 /************************************************************************/
@@ -345,6 +354,18 @@ CPLErr JPEG2000RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         }
     }
 
+    if( poGDS->bPromoteTo8Bit && nBand == 4 )
+    {
+        ptr = (GByte*)pImage;
+        for( i = 0; i < nHeightToRead; i++, ptr += nLineSize )
+        {
+            for( j = 0; j < nWidthToRead; j++ )
+            {
+                ((GByte*)ptr)[j] *= 255;
+            }
+        }
+    }
+
     return CE_None;
 }
 
@@ -400,6 +421,7 @@ JPEG2000Dataset::JPEG2000Dataset()
     psImage = NULL;
     nBands = 0;
     bAlreadyDecoded = FALSE;
+    bPromoteTo8Bit = FALSE;
     
     poDriver = (GDALDriver *)GDALGetDriverByName("JPEG2000");
 }
@@ -728,9 +750,23 @@ GDALDataset *JPEG2000Dataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
+/*      Should we promote alpha channel to 8 bits ?                     */
+/* -------------------------------------------------------------------- */
+    poDS->bPromoteTo8Bit = (poDS->nBands == 4 &&
+                            paiDepth[0] == 8 &&
+                            paiDepth[1] == 8 &&
+                            paiDepth[2] == 8 &&
+                            paiDepth[3] == 1 &&
+                            CSLFetchBoolean(poOpenInfo->papszOpenOptions, "1BIT_ALPHA_PROMOTION", TRUE));
+    if( poDS->bPromoteTo8Bit )
+        CPLDebug( "JPEG2000",  "Fourth (alpha) band is promoted from 1 bit to 8 bit");
+
+/* -------------------------------------------------------------------- */
 
 /*      Create band information objects.                                */
 /* -------------------------------------------------------------------- */
+
+
     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
     {
         poDS->SetBand( iBand, new JPEG2000RasterBand( poDS, iBand,
@@ -755,7 +791,25 @@ GDALDataset *JPEG2000Dataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Check for overviews.                                            */
 /* -------------------------------------------------------------------- */
     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
-    
+
+/* -------------------------------------------------------------------- */
+/*      Vector layers                                                   */
+/* -------------------------------------------------------------------- */
+    if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
+    {
+        poDS->LoadVectorLayers(
+            CSLFetchBoolean(poOpenInfo->papszOpenOptions, "OPEN_REMOTE_GML", FALSE));
+
+        // If file opened in vector-only mode and there's no vector,
+        // return
+        if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+            poDS->GetLayerCount() == 0 )
+        {
+            delete poDS;
+            return NULL;
+        }
+    }
+
     return( poDS );
 }
 
@@ -894,7 +948,7 @@ JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         {
             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                               paiScanline, nXSize, 1, GDT_UInt32,
-                              sizeof(GUInt32), sizeof(GUInt32) * nXSize );
+                              sizeof(GUInt32), sizeof(GUInt32) * nXSize, NULL );
             for ( iPixel = 0; iPixel < nXSize; iPixel++ )
                 jas_matrix_setv( psMatrix, iPixel, paiScanline[iPixel] );
             
@@ -1049,14 +1103,16 @@ JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     {
 #ifdef HAVE_JASPER_UUID
         double  adfGeoTransform[6];
-        if( ((poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None
+        if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) &&
+            ((poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None
                  && (adfGeoTransform[0] != 0.0 
                      || adfGeoTransform[1] != 1.0 
                      || adfGeoTransform[2] != 0.0 
                      || adfGeoTransform[3] != 0.0 
                      || adfGeoTransform[4] != 0.0 
                      || ABS(adfGeoTransform[5]) != 1.0))
-                || poSrcDS->GetGCPCount() > 0) )
+                || poSrcDS->GetGCPCount() > 0
+                || poSrcDS->GetMetadata("RPC") != NULL ) )
         {
             GDALJP2Metadata oJP2Geo;
 
@@ -1071,6 +1127,8 @@ JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                 oJP2Geo.SetGeoTransform( adfGeoTransform );
             }
 
+            oJP2Geo.SetRPCMD(  poSrcDS->GetMetadata("RPC") );
+
             const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
             oJP2Geo.bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
 
@@ -1143,6 +1201,89 @@ JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
+/*      Add GMLJP2 box at end of file.                                  */
+/* -------------------------------------------------------------------- */
+    if ( EQUALN( pszFormatName, "jp2", 3 ) )
+    {
+        double  adfGeoTransform[6];
+        if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) &&
+            poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None &&
+            poSrcDS->GetProjectionRef() != NULL &&
+            poSrcDS->GetProjectionRef()[0] != '\0' )
+        {
+            VSILFILE* fp = VSIFOpenL(pszFilename, "rb+");
+            if( fp )
+            {
+                // Look for jp2c box and patch its LBox to be the real box size
+                // instead of zero
+                int bOK = FALSE;
+                GUInt32   nLBox;
+                GUInt32   nTBox;
+
+                while(TRUE)
+                {
+                    if( VSIFReadL(&nLBox, 4, 1, fp) != 1 ||
+                        VSIFReadL(&nTBox, 4, 1, fp) != 1 )
+                        break;
+                    nLBox = CPL_MSBWORD32( nLBox );
+                    if( memcmp(&nTBox, "jp2c", 4) == 0 )
+                    {
+                        if( nLBox >= 8 )
+                        {
+                            bOK = TRUE;
+                            break;
+                        }
+                        if( nLBox == 0 )
+                        {
+                            vsi_l_offset nPos = VSIFTellL(fp);
+                            VSIFSeekL(fp, 0, SEEK_END);
+                            vsi_l_offset nEnd = VSIFTellL(fp);
+                            VSIFSeekL(fp, nPos - 8, SEEK_SET);
+                            nLBox = (GUInt32)(8 + nEnd - nPos);
+                            if( nLBox == (vsi_l_offset)8 + nEnd - nPos )
+                            {
+                                nLBox = CPL_MSBWORD32( nLBox );
+                                VSIFWriteL(&nLBox, 1, 4, fp);
+                                bOK = TRUE;
+                            }
+                        }
+                        break;
+                    }
+                    if( nLBox < 8 )
+                        break;
+                    VSIFSeekL(fp, nLBox - 8, SEEK_CUR);
+                }
+
+                // Can write GMLJP2 box
+                if( bOK )
+                {
+                    GDALJP2Metadata oJP2MD;
+                    oJP2MD.SetProjection( poSrcDS->GetProjectionRef() );
+                    oJP2MD.SetGeoTransform( adfGeoTransform );
+                    GDALJP2Box *poBox;
+                    const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
+                    if( pszGMLJP2V2Def != NULL )
+                        poBox = oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS);
+                    else
+                        poBox = oJP2MD.CreateGMLJP2(nXSize,nYSize);
+
+                    nLBox = (int) poBox->GetDataLength() + 8;
+                    nLBox = CPL_MSBWORD32( nLBox );
+                    memcpy(&nTBox, poBox->GetType(), 4);
+
+                    VSIFSeekL(fp, 0, SEEK_END);
+                    VSIFWriteL( &nLBox, 4, 1, fp );
+                    VSIFWriteL( &nTBox, 4, 1, fp );
+                    VSIFWriteL(poBox->GetWritableData(), 1, (int) poBox->GetDataLength(), fp);
+                    VSIFCloseL(fp);
+
+                    delete poBox;
+                }
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Do we need a world file?                                        */
 /* -------------------------------------------------------------------- */
     if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
@@ -1154,13 +1295,43 @@ JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     GDALPamDataset *poDS = (GDALPamDataset*) JPEG2000Dataset::Open(&oOpenInfo);
 
     if( poDS )
-        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
+    {
+        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & (~GCIF_METADATA) );
+
+        /* Only write relevant metadata to PAM, and if needed */
+        char** papszSrcMD = CSLDuplicate(poSrcDS->GetMetadata());
+        papszSrcMD = CSLSetNameValue(papszSrcMD, GDALMD_AREA_OR_POINT, NULL);
+        papszSrcMD = CSLSetNameValue(papszSrcMD, "Corder", NULL);
+        for(char** papszSrcMDIter = papszSrcMD;
+                papszSrcMDIter && *papszSrcMDIter; )
+        {
+            /* Remove entries like KEY= (without value) */
+            if( (*papszSrcMDIter)[0] &&
+                (*papszSrcMDIter)[strlen((*papszSrcMDIter))-1] == '=' )
+            {
+                CPLFree(*papszSrcMDIter);
+                memmove(papszSrcMDIter, papszSrcMDIter + 1,
+                        sizeof(char*) * (CSLCount(papszSrcMDIter + 1) + 1));
+            }
+            else
+                ++papszSrcMDIter;
+        }
+        char** papszMD = CSLDuplicate(poDS->GetMetadata());
+        papszMD = CSLSetNameValue(papszMD, GDALMD_AREA_OR_POINT, NULL);
+        if( papszSrcMD && papszSrcMD[0] != NULL &&
+            CSLCount(papszSrcMD) != CSLCount(papszMD) )
+        {
+            poDS->SetMetadata(papszSrcMD);
+        }
+        CSLDestroy(papszSrcMD);
+        CSLDestroy(papszMD);
+    }
 
     return poDS;
 }
@@ -1182,6 +1353,8 @@ void GDALRegister_JPEG2000()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JPEG2000" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JPEG-2000 part 1 (ISO/IEC 15444-1)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -1193,6 +1366,48 @@ void GDALRegister_JPEG2000()
         
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionList>"
+"   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' description='Whether a 1-bit alpha channel should be promoted to 8-bit' default='YES'/>"
+"   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether to load remote vector layers referenced by a link in a GMLJP2 v2 box' default='NO'/>"
+"</OpenOptionList>" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"   <Option name='FORMAT' type='string-select' default='according to file extension. If unknown, default to J2K'>"
+"       <Value>JP2</Value>"
+"       <Value>JPC</Value>"
+"   </Option>"
+"   <Option name='GeoJP2' type='boolean' description='Whether to emit a GeoJP2 box' default='YES'/>"
+"   <Option name='GMLJP2' type='boolean' description='Whether to emit a GMLJP2 v1 box' default='YES'/>"
+"   <Option name='GMLJP2V2_DEF' type='string' description='Definition file to describe how a GMLJP2 v2 box should be generated. If set to YES, a minimal instance will be created'/>"
+"   <Option name='WORLDFILE' type='boolean' description='Whether to write a worldfile .wld' default='NO'/>"
+"   <Option name='imgareatlx' type='string' />"
+"   <Option name='imgareatly' type='string' />"
+"   <Option name='tilegrdtlx' type='string' />"
+"   <Option name='tilegrdtly' type='string' />"
+"   <Option name='tilewidth' type='string' />"
+"   <Option name='tileheight' type='string' />"
+"   <Option name='prcwidth' type='string' />"
+"   <Option name='prcheight' type='string' />"
+"   <Option name='cblkwidth' type='string' />"
+"   <Option name='cblkheight' type='string' />"
+"   <Option name='mode' type='string' />"
+"   <Option name='rate' type='string' />"
+"   <Option name='ilyrrates' type='string' />"
+"   <Option name='prg' type='string' />"
+"   <Option name='numrlvls' type='string' />"
+"   <Option name='sop' type='string' />"
+"   <Option name='eph' type='string' />"
+"   <Option name='lazy' type='string' />"
+"   <Option name='termall' type='string' />"
+"   <Option name='segsym' type='string' />"
+"   <Option name='vcausal' type='string' />"
+"   <Option name='pterm' type='string' />"
+"   <Option name='resetprob' type='string' />"
+"   <Option name='numgbits' type='string' />"
+"</CreationOptionList>"  );
+
         poDriver->pfnIdentify = JPEG2000Dataset::Identify;
         poDriver->pfnOpen = JPEG2000Dataset::Open;
         poDriver->pfnCreateCopy = JPEG2000CreateCopy;
diff --git a/frmts/jpegls/GNUmakefile b/frmts/jpegls/GNUmakefile
index b4528fa..6c7ff47 100644
--- a/frmts/jpegls/GNUmakefile
+++ b/frmts/jpegls/GNUmakefile
@@ -3,7 +3,7 @@ OBJ	=	jpeglsdataset.o
 
 include ../../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(CHARLS_INC)
+CPPFLAGS	:=	 $(CPPFLAGS) $(CHARLS_INC)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/jpegls/jpeglsdataset.cpp b/frmts/jpegls/jpeglsdataset.cpp
index 6a4c6fe..d13807d 100644
--- a/frmts/jpegls/jpeglsdataset.cpp
+++ b/frmts/jpegls/jpeglsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: jpeglsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: jpeglsdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  JPEGLS driver based on CharLS library
  * Purpose:  JPEGLS driver based on CharLS library
@@ -37,7 +37,7 @@ extern "C" void GDALRegister_JPEGLS();
 
 /* g++ -Wall -g fmrts/jpegls/jpeglsdataset.cpp -shared -fPIC -o gdal_JPEGLS.so -Iport -Igcore -L. -lgdal -I/home/even/charls-1.0 -L/home/even/charls-1.0/build -lCharLS */
 
-CPL_CVSID("$Id: jpeglsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: jpeglsdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -553,10 +553,10 @@ JPEGLSDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
     CPLErr eErr;
-    eErr = poSrcDS->RasterIO(GF_Read, 0, 0, nXSize, nYSize,
+    eErr = poSrcDS->s(GF_Read, 0, 0, nXSize, nYSize,
                       pabyDataUncompressed, nXSize, nYSize,
                       eDT, nBands, NULL,
-                      nBands * nWordSize, nBands * nWordSize * nXSize, nWordSize);
+                      nBands * nWordSize, nBands * nWordSize * nXSize, nWordSize, NULL);
     if (eErr != CE_None)
     {
         VSIFree(pabyDataCompressed);
@@ -637,7 +637,7 @@ JPEGLSDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     VSIFCloseL(fp);
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     JPEGLSDataset *poDS = (JPEGLSDataset *) GDALOpen( pszFilename, GA_ReadOnly );
 
@@ -664,6 +664,7 @@ void GDALRegister_JPEGLS()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "JPEGLS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "JPEGLS" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/jpipkak/GNUmakefile b/frmts/jpipkak/GNUmakefile
index 8fe0d83..0144e02 100644
--- a/frmts/jpipkak/GNUmakefile
+++ b/frmts/jpipkak/GNUmakefile
@@ -14,7 +14,7 @@ INSTOBJ = $(foreach d,$(APPOBJ),../o/$(notdir $(d)))
 
 #CXXFLAGS :=	$(CXXFLAGS) -DFILEIO_DEBUG
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(KAKINC) -I. $(CPPFLAGS)
+CPPFLAGS	:=	 $(KAKINC) -I. $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/jpipkak/jpipkakdataset.cpp b/frmts/jpipkak/jpipkakdataset.cpp
index 2cce54d..a0253cf 100644
--- a/frmts/jpipkak/jpipkakdataset.cpp
+++ b/frmts/jpipkak/jpipkakdataset.cpp
@@ -322,7 +322,8 @@ JPIPKAKRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                               int nXOff, int nYOff, int nXSize, int nYSize,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
-                              int nPixelSpace,int nLineSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
     
 {
 /* -------------------------------------------------------------------- */
@@ -334,7 +335,7 @@ JPIPKAKRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamRasterBand::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nPixelSpace, nLineSpace );
+            nPixelSpace, nLineSpace, psExtraArg );
 
 /* -------------------------------------------------------------------- */
 /*      Otherwise do this as a single uncached async rasterio.          */
@@ -390,6 +391,8 @@ JPIPKAKDataset::JPIPKAKDataset()
     bWindowDone = FALSE;
     bGeoTransformValid = FALSE;
 
+    bNeedReinitialize = FALSE;
+
     adfGeoTransform[0] = 0.0;
     adfGeoTransform[1] = 1.0;
     adfGeoTransform[2] = 0.0;
@@ -629,7 +632,10 @@ int JPIPKAKDataset::Initialize(const char* pszDatasetName, int bReinitializing )
 /*      hopefully the configuration is unchanged.                       */
 /* -------------------------------------------------------------------- */
         if( bReinitializing )
+        {
+            bNeedReinitialize = FALSE;
             return TRUE;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Collect GDAL raster configuration information.                  */
@@ -1141,7 +1147,9 @@ CPLErr JPIPKAKDataset::IRasterIO( GDALRWFlag eRWFlag,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType, 
                                   int nBandCount, int *panBandMap,
-                                  int nPixelSpace,int nLineSpace,int nBandSpace)
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GSpacing nBandSpace,
+                                  GDALRasterIOExtraArg* psExtraArg)
 
 {
 /* -------------------------------------------------------------------- */
@@ -1152,7 +1160,7 @@ CPLErr JPIPKAKDataset::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamDataset::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 
 /* -------------------------------------------------------------------- */
 /*      Otherwise do this as a single uncached async rasterio.          */
@@ -1190,9 +1198,10 @@ CPLErr JPIPKAKDataset::IRasterIO( GDALRWFlag eRWFlag,
 /************************************************************************/
 
 int 
-JPIPKAKDataset::TestUseBlockIO( int nXOff, int nYOff, int nXSize, int nYSize,
+JPIPKAKDataset::TestUseBlockIO( CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
+                                int nXSize, int nYSize,
                                 int nBufXSize, int nBufYSize,
-                                GDALDataType eDataType, 
+                                CPL_UNUSED GDALDataType eDataType, 
                                 int nBandCount, int *panBandList )
 
 {
@@ -1459,6 +1468,7 @@ void GDALRegister_JPIPKAK()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JPIPKAK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JPIP (based on Kakadu)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/jpipkak/jpipkakdataset.h b/frmts/jpipkak/jpipkakdataset.h
index c4e16dc..45117a6 100644
--- a/frmts/jpipkak/jpipkakdataset.h
+++ b/frmts/jpipkak/jpipkakdataset.h
@@ -42,6 +42,13 @@
 
 #include <time.h>
 
+
+#if KDU_MAJOR_VERSION > 7 || (KDU_MAJOR_VERSION == 7 && KDU_MINOR_VERSION >= 5)
+    using namespace kdu_core;
+    using namespace kdu_supp;
+#endif
+
+
 static void JPIPWorkerFunc(void *);
 
 /************************************************************************/
@@ -133,7 +140,7 @@ private:
     void Deinitialize();
     int KakaduClassId(int nClassId);
 
-    void *pGlobalMutex;
+    CPLMutex *pGlobalMutex;
  
     // support two communication threads to the server, a main and an overview thread
     volatile int bHighThreadRunning;
@@ -182,7 +189,9 @@ public:
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace,int nLineSpace,int nBandSpace);
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     static GDALDataset *Open(GDALOpenInfo *);
     static const GByte JPIP_EOR_IMAGE_DONE = 1;
@@ -231,7 +240,8 @@ public:
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual int    GetOverviewCount();
     virtual GDALRasterBand *GetOverview( int );
diff --git a/frmts/kea/GNUmakefile b/frmts/kea/GNUmakefile
new file mode 100644
index 0000000..e63bc98
--- /dev/null
+++ b/frmts/kea/GNUmakefile
@@ -0,0 +1,15 @@
+
+include ../../GDALmake.opt
+
+OBJ	=	keaband.o keacopy.o keadataset.o keadriver.o keamaskband.o keaoverview.o kearat.o
+
+CPPFLAGS	:=	 $(KEA_INC) $(CPPFLAGS)
+
+default:	$(OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(OBJ) $(O_OBJ):	keaband.h keacopy.h keadataset.h keamaskband.h keaoverview.h kearat.h
+
+install-obj:	$(O_OBJ:.o=.$(OBJ_EXT))
diff --git a/frmts/kea/frmt_kea.html b/frmts/kea/frmt_kea.html
new file mode 100644
index 0000000..287a86c
--- /dev/null
+++ b/frmts/kea/frmt_kea.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>KEA</title>
+</head>
+
+<body>
+
+<h1>KEA</h1>
+
+<p>Starting with GDAL 2.0, GDAL can read, create and update files in the KEA format, through the libkea library.</p>
+
+<p>KEA is an image file format, named after the New Zealand bird, that provides a full implementation
+of the GDAL data model and is implemented within a HDF5 file. A software library, likea, is used
+to access the file format. The format has comparable performance with existing formats while
+producing smaller file sizes and is already within active use for a number of projects within
+Landcare Research, New Zealand, and the wider community.<p>
+
+<p>The KEA format supports the following features of the GDAL data model:
+<ul>
+<li>Multiple-band support, with possible different datatypes. Bands can be added to an existing dataset with AddBand() API</li>
+<li>Image blocking support</li>
+<li>Reading, creation and update of data of image blocks</li>
+<li>Affine geotransform, WKT projection, GCP</li>
+<li>Metadata at dataset and band level</li>
+<li>Per-band description</li>
+<li>Per-band nodata and color interpration</li>
+<li>Per-band color table</li>
+<li>Per-band RAT (Raster Attribute Table) of arbitrary size</li>
+<li>Internal overviews and mask bands</li>
+</ul>
+</li>
+
+<h2>Creation options</h2>
+
+<p>The following creation options are available. Some are rather esoteric and
+should rarely be specified, unless the user has good knowledge of the working
+of the underlying HDF5 format.</p>
+
+<ul>
+<li><p><b>IMAGEBLOCKSIZE</b>=integer_value: The size of each block for image data. Defaults to 256</li>
+<li><p><b>ATTBLOCKSIZE</b>=integer_value: The size of each block for attribute data. Defaults to 1000</li>
+<li><p><b>MDC_NELMTS</b>=integer_value: Number of elements in the meta data cache. Defaults to 0. See the <a href="http://www.hdfgroup.org/HDF5/doc/H5.user/Caching.html">Data caching</a> page of HDF5 documentation.</li>
+<li><p><b>RDCC_NELMTS</b>=integer_value: Number of elements in the raw data chunk cache. Defaults to 512. See the <a href="http://www.hdfgroup.org/HDF5/doc/H5.user/Caching.html">Data caching</a> page of HDF5 documentation.</li>
+<li><p><b>RDCC_NBYTES</b>=integer_value: Total size of the raw data chunk cache, in bytes. Defaults to 1048576. See the <a href="http://www.hdfgroup.org/HDF5/doc/H5.user/Caching.html">Data caching</a> page of HDF5 documentation.</li>
+<li><p><b>RDCC_W0</b>=floating_point_value between 0 and 1: Preemption policy. Defaults to 0.75. See the <a href="http://www.hdfgroup.org/HDF5/doc/H5.user/Caching.html">Data caching</a> page of HDF5 documentation.</li>
+<li><p><b>SIEVE_BUF</b>=integer_value: Sets the maximum size of the data sieve buffer. Defaults to 65536.  See <a href="http://www.hdfgroup.org/HDF5/doc/RM/RM_H5P.html#Property-SetSieveBufSize">H5Pset_sieve_buf_size()</a> documentation</li>
+<li><p><b>META_BLOCKSIZE</b>=integer_value: Sets the minimum size of metadata block allocations. Defaults to 2048. See <a href="http://www.hdfgroup.org/HDF5/doc/RM/RM_H5P.html#Property-SetMetaBlockSize">H5Pset_meta_block_size()</a> documentation</li>
+<li><p><b>DEFLATE</b>=integer_value: Compression level between 0 (no compression) to 9 (max compression). Defaults to 1</li>
+<li><p><b>THEMATIC</b>=YES/NO: If YES then all bands are set to thematic. Defaults to NO</li>
+</ul>
+
+<h2>See Also:</h2>
+
+<ul>
+<li><a href="https://bitbucket.org/chchrsc/kealib">libkea bitbucket repository</a></li>
+<li><a href="http://www.sciencedirect.com/science/article/pii/S0098300413001015">The KEAimage file format, by Peter Bunting and Sam Gillingham, published in Computers&Geosciences</a></li>
+<li><a href="frmt_hdf5">HDF5 driver page</a></li>
+</ul>
+
+</body>
+</html>
diff --git a/frmts/kea/keaband.cpp b/frmts/kea/keaband.cpp
new file mode 100644
index 0000000..287b2ca
--- /dev/null
+++ b/frmts/kea/keaband.cpp
@@ -0,0 +1,971 @@
+/*
+ * $Id: keaband.cpp 28011 2014-11-26 13:47:09Z rouault $
+ *  keaband.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "keaband.h"
+#include "keaoverview.h"
+#include "keamaskband.h"
+#include "kearat.h"
+
+#include "gdal_rat.h"
+#include "libkea/KEAAttributeTable.h"
+
+#include <map>
+#include <vector>
+
+#include <limits.h>
+
+// constructor
+KEARasterBand::KEARasterBand( KEADataset *pDataset, int nSrcBand, GDALAccess eAccess, kealib::KEAImageIO *pImageIO, int *pRefCount )
+{
+    this->poDS = pDataset; // our pointer onto the dataset
+    this->nBand = nSrcBand; // this is the band we are
+    this->m_eKEADataType = pImageIO->getImageBandDataType(nSrcBand); // get the data type as KEA enum
+    this->eDataType = KEA_to_GDAL_Type( m_eKEADataType );       // convert to GDAL enum
+    this->nBlockXSize = pImageIO->getImageBlockSize(nSrcBand);  // get the native blocksize
+    this->nBlockYSize = pImageIO->getImageBlockSize(nSrcBand);
+    this->nRasterXSize = this->poDS->GetRasterXSize();          // ask the dataset for the total image size
+    this->nRasterYSize = this->poDS->GetRasterYSize();
+    this->eAccess = eAccess;
+
+    if( pImageIO->attributeTablePresent(nSrcBand) )
+    {
+        this->m_nAttributeChunkSize = pImageIO->getAttributeTableChunkSize(nSrcBand);
+    }
+    else
+    {
+        this->m_nAttributeChunkSize = -1; // don't report
+    }
+
+    // grab the imageio class and its refcount
+    this->m_pImageIO = pImageIO;
+    this->m_pnRefCount = pRefCount;
+    // increment the refcount as we now have a reference to imageio
+    (*this->m_pnRefCount)++;
+
+    // initialise overview variables
+    m_nOverviews = 0;
+    m_panOverviewBands = NULL;
+
+    // mask band
+    m_pMaskBand = NULL;
+    m_bMaskBandOwned = false;
+
+    // grab the description here
+    this->sDescription = pImageIO->getImageBandDescription(nSrcBand);
+
+    this->m_pAttributeTable = NULL;  // no RAT yet
+    this->m_pColorTable = NULL;     // no color table yet
+
+    // initialise the metadata as a CPLStringList
+    m_papszMetadataList = NULL;
+    this->UpdateMetadataList();
+}
+
+// destructor
+KEARasterBand::~KEARasterBand()
+{
+    // destroy RAT if any
+    delete this->m_pAttributeTable;
+    // destroy color table if any
+    delete this->m_pColorTable;
+    // destroy the metadata
+    CSLDestroy(this->m_papszMetadataList);
+    // delete any overview bands
+    this->deleteOverviewObjects();
+
+    // if GDAL created the mask it will delete it
+    if( m_bMaskBandOwned )
+    {
+        delete m_pMaskBand;
+    }
+
+    // according to the docs, this is required
+    this->FlushCache();
+
+    // decrement the recount and delete if needed
+    (*m_pnRefCount)--;
+    if( *m_pnRefCount == 0 )
+    {
+        try
+        {
+            m_pImageIO->close();
+        }
+        catch (kealib::KEAIOException &e)
+        {
+        }
+        delete m_pImageIO;
+        delete m_pnRefCount;
+    }
+}
+
+// internal method that updates the metadata into m_papszMetadataList
+void KEARasterBand::UpdateMetadataList()
+{
+    std::vector< std::pair<std::string, std::string> > data;
+
+    // get all the metadata and iterate through
+    data = this->m_pImageIO->getImageBandMetaData(this->nBand);
+    for(std::vector< std::pair<std::string, std::string> >::iterator iterMetaData = data.begin(); iterMetaData != data.end(); ++iterMetaData)
+    {
+        // add to our list
+        m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(), iterMetaData->second.c_str());
+    }
+    // we have a pseudo metadata item that tells if we are thematic 
+    // or continuous like the HFA driver
+    if( this->m_pImageIO->getImageBandLayerType(this->nBand) == kealib::kea_continuous )
+    {
+        m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "athematic" );
+    }
+    else
+    {
+        m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "LAYER_TYPE", "thematic" );
+    }
+    // attribute table chunksize
+    if( this->m_nAttributeChunkSize != -1 )
+    {
+        char szTemp[100];
+        snprintf(szTemp, 100, "%d", this->m_nAttributeChunkSize );
+        m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, "ATTRIBUTETABLE_CHUNKSIZE", szTemp );
+    }
+}
+
+// internal method to create the overviews
+void KEARasterBand::CreateOverviews(int nOverviews, int *panOverviewList)
+{
+    // delete any existing overview bands
+    this->deleteOverviewObjects();
+
+    // allocate space
+    m_panOverviewBands = (KEAOverview**)CPLMalloc(sizeof(KEAOverview*) * nOverviews);
+    m_nOverviews = nOverviews;
+
+    // loop through and create the overviews
+    int nFactor, nXSize, nYSize;
+    for( int nCount = 0; nCount < m_nOverviews; nCount++ )
+    {
+        nFactor = panOverviewList[nCount];
+        // divide by the factor to get the new size
+        nXSize = this->nRasterXSize / nFactor;
+        nYSize = this->nRasterYSize / nFactor;
+
+        // tell image io to create a new overview
+        this->m_pImageIO->createOverview(this->nBand, nCount + 1, nXSize, nYSize);
+
+        // create one of our objects to represent it
+        m_panOverviewBands[nCount] = new KEAOverview((KEADataset*)this->poDS, this->nBand, GA_Update,
+                                        this->m_pImageIO, this->m_pnRefCount, nCount + 1, nXSize, nYSize);
+    }
+}
+
+// virtual method to read a block
+CPLErr KEARasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount read so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+        this->m_pImageIO->readImageBlock2Band( this->nBand, pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize, 
+                                            this->m_eKEADataType );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to read file: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// virtual method to write a block
+CPLErr KEARasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount written so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+
+        this->m_pImageIO->writeImageBlock2Band( this->nBand, pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize,
+                                            this->m_eKEADataType );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to write file: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+void KEARasterBand::SetDescription(const char *pszDescription)
+{
+    try
+    {
+        this->m_pImageIO->setImageBandDescription(this->nBand, pszDescription);
+        GDALPamRasterBand::SetDescription(pszDescription);
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        // ignore?
+    }
+}
+
+// set a metadata item
+CPLErr KEARasterBand::SetMetadataItem(const char *pszName, const char *pszValue, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return CE_Failure;
+    try
+    {
+        // if it is LAYER_TYPE handle it seperately
+        if( EQUAL( pszName, "LAYER_TYPE" ) )
+        {
+            if( EQUAL( pszValue, "athematic" ) )
+            {
+                this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_continuous );
+            }
+            else
+            {
+                this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_thematic );
+            }
+        }
+        else
+        {
+            // otherwise set it as normal
+            this->m_pImageIO->setImageBandMetaData(this->nBand, pszName, pszValue );
+        }
+        // CSLSetNameValue will update if already there
+        m_papszMetadataList = CSLSetNameValue( m_papszMetadataList, pszName, pszValue );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        return CE_Failure;
+    }
+}
+
+// get a single metdata item
+const char *KEARasterBand::GetMetadataItem (const char *pszName, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return NULL;
+    // get it out of the CSLStringList so we can be sure it is persistant
+    return CSLFetchNameValue(m_papszMetadataList, pszName);
+}
+
+// get all the metadata as a CSLStringList
+char **KEARasterBand::GetMetadata(const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return NULL;
+    // conveniently we already have it in this format
+    return m_papszMetadataList; 
+}
+
+// set the metdata as a CSLStringList
+CPLErr KEARasterBand::SetMetadata(char **papszMetadata, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return CE_Failure;
+    int nIndex = 0;
+    char *pszName;
+    const char *pszValue;
+    try
+    {
+        // iterate through each one
+        while( papszMetadata[nIndex] != NULL )
+        {
+            pszName = NULL;
+            pszValue = CPLParseNameValue( papszMetadata[nIndex], &pszName );
+            if( pszValue == NULL )
+                pszValue = "";
+            if( pszName != NULL )
+            {
+                // it is LAYER_TYPE? if so handle seperately
+                if( EQUAL( pszName, "LAYER_TYPE" ) )
+                {
+                    if( EQUAL( pszValue, "athematic" ) )
+                    {
+                        this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_continuous );
+                    }
+                    else
+                    {
+                        this->m_pImageIO->setImageBandLayerType(this->nBand, kealib::kea_thematic );
+                    }
+                }
+                else
+                {
+                    // write it into the image
+                    this->m_pImageIO->setImageBandMetaData(this->nBand, pszName, pszValue );
+                }
+                CPLFree(pszName);
+            }
+            nIndex++;
+        }
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        return CE_Failure;
+    }
+    // destroy our list and duplicate the one passed in
+    // and use that as our list from now on
+    CSLDestroy(m_papszMetadataList);
+    m_papszMetadataList = CSLDuplicate(papszMetadata);
+    return CE_None;
+}
+
+// get the no data value
+double KEARasterBand::GetNoDataValue(int *pbSuccess)
+{
+    try
+    {
+        double dVal;
+        this->m_pImageIO->getNoDataValue(this->nBand, &dVal, kealib::kea_64float);
+        if( pbSuccess != NULL )
+            *pbSuccess = 1;
+
+        return dVal;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        if( pbSuccess != NULL )
+            *pbSuccess = 0;
+        return -1;
+    }
+}
+
+// set the no data value
+CPLErr KEARasterBand::SetNoDataValue(double dfNoData)
+{
+    // need to check for out of range values
+    bool bSet = true;
+    GDALDataType dtype = this->GetRasterDataType();
+    switch( dtype )
+    {
+        case GDT_Byte:
+            bSet = (dfNoData >= 0) && (dfNoData <= UCHAR_MAX);
+            break;
+        case GDT_UInt16:
+            bSet = (dfNoData >= 0) && (dfNoData <= USHRT_MAX);
+            break;
+        case GDT_Int16:
+            bSet = (dfNoData >= SHRT_MIN) && (dfNoData <= SHRT_MAX);
+            break;
+        case GDT_UInt32:
+            bSet = (dfNoData >= 0) && (dfNoData <= UINT_MAX);
+            break;
+        case GDT_Int32:
+            bSet = (dfNoData >= INT_MIN) && (dfNoData <= INT_MAX);
+            break;
+        default:
+            // for other types we can't really tell if outside the range
+            break;
+    }
+
+    try
+    {
+        if( bSet )
+        {
+            this->m_pImageIO->setNoDataValue(this->nBand, &dfNoData, kealib::kea_64float);
+        }
+        else
+        {
+            this->m_pImageIO->undefineNoDataValue(this->nBand);
+        }
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        return CE_Failure;
+    }
+}
+
+GDALRasterAttributeTable *KEARasterBand::GetDefaultRAT()
+{
+    if( this->m_pAttributeTable == NULL )
+    {
+        try
+        {
+            // we assume this is never NULL - creates a new one if none exists
+            kealib::KEAAttributeTable *pKEATable = this->m_pImageIO->getAttributeTable(kealib::kea_att_file, this->nBand);
+            this->m_pAttributeTable = new KEARasterAttributeTable(pKEATable);
+        }
+        catch(kealib::KEAException &e)
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, "Failed to read attributes: %s", e.what() );
+        }
+    }
+    return this->m_pAttributeTable;
+}
+
+CPLErr KEARasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT)
+{
+    if( poRAT == NULL )
+        return CE_Failure;
+
+    try
+    {
+        KEARasterAttributeTable *pKEATable = (KEARasterAttributeTable*)this->GetDefaultRAT();
+
+        int numRows = poRAT->GetRowCount();
+        pKEATable->SetRowCount(numRows);
+
+        for( int nGDALColumnIndex = 0; nGDALColumnIndex < poRAT->GetColumnCount(); nGDALColumnIndex++ )
+        {
+            const char *pszColumnName = poRAT->GetNameOfCol(nGDALColumnIndex);
+            GDALRATFieldType eFieldType = poRAT->GetTypeOfCol(nGDALColumnIndex);
+
+            // do we have it?
+            bool bExists = false;
+            int nKEAColumnIndex;
+            for( nKEAColumnIndex = 0; nKEAColumnIndex < pKEATable->GetColumnCount(); nKEAColumnIndex++ )
+            {
+                if( EQUAL(pszColumnName, pKEATable->GetNameOfCol(nKEAColumnIndex) ))
+                {
+                    bExists = true;
+                    break;
+                }
+            }
+
+            if( !bExists )
+            {
+                if( pKEATable->CreateColumn(pszColumnName, eFieldType,
+                                            poRAT->GetUsageOfCol(nGDALColumnIndex) ) != CE_None )
+                {
+                    CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column");
+                    return CE_Failure;
+                }
+                nKEAColumnIndex = pKEATable->GetColumnCount() - 1;
+            }
+
+            if( numRows == 0 )
+                continue;
+
+            // ok now copy data
+            if( eFieldType == GFT_Integer )
+            {
+                int *panIntData = (int*)VSIMalloc2(numRows, sizeof(int));
+                if( panIntData == NULL )
+                {
+                    CPLError( CE_Failure, CPLE_OutOfMemory,
+                        "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
+                    return CE_Failure;
+                }
+
+                if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, panIntData ) == CE_None )
+                {
+                    pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, panIntData);
+                }
+                CPLFree(panIntData);
+            }
+            else if( eFieldType == GFT_Real )
+            {
+                double *padfFloatData = (double*)VSIMalloc2(numRows, sizeof(double));
+                if( padfFloatData == NULL )
+                {
+                    CPLError( CE_Failure, CPLE_OutOfMemory,
+                        "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
+                    return CE_Failure;
+                }
+
+                if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, padfFloatData ) == CE_None )
+                {
+                    pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, padfFloatData);
+                }
+                CPLFree(padfFloatData);
+            }
+            else
+            {
+                char **papszStringData = (char**)VSIMalloc2(numRows, sizeof(char*));
+                if( papszStringData == NULL )
+                {
+                    CPLError( CE_Failure, CPLE_OutOfMemory,
+                        "Memory Allocation failed in KEARasterAttributeTable::SetDefaultRAT");
+                    return CE_Failure;
+                }
+
+                if( ((GDALRasterAttributeTable*)poRAT)->ValuesIO(GF_Read, nGDALColumnIndex, 0, numRows, papszStringData ) == CE_None )
+                {
+                    pKEATable->ValuesIO(GF_Write, nKEAColumnIndex, 0, numRows, papszStringData);
+                    for( int n = 0; n < numRows; n++ )
+                        CPLFree(papszStringData[n]);
+                }
+                CPLFree(papszStringData);
+
+            }
+        }
+    }
+    catch(kealib::KEAException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Failed to write attributes: %s", e.what() );
+        return CE_Failure;
+    }
+    return CE_None;
+}
+
+GDALColorTable *KEARasterBand::GetColorTable()
+{
+    if( this->m_pColorTable == NULL )
+    {
+        try
+        {
+            GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
+            int nRedIdx = -1;
+            int nGreenIdx = -1;
+            int nBlueIdx = -1;
+            int nAlphaIdx = -1;
+
+            for( int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++ )
+            {
+                if( pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer )
+                {
+                    GDALRATFieldUsage eFieldUsage = pKEATable->GetUsageOfCol(nColIdx);
+                    if( eFieldUsage == GFU_Red )
+                        nRedIdx = nColIdx;
+                    else if( eFieldUsage == GFU_Green )
+                        nGreenIdx = nColIdx;
+                    else if( eFieldUsage == GFU_Blue )
+                        nBlueIdx = nColIdx;
+                    else if( eFieldUsage == GFU_Alpha )
+                        nAlphaIdx = nColIdx;
+                }
+            }
+
+            if( ( nRedIdx != -1 ) && ( nGreenIdx != -1 ) && ( nBlueIdx != -1 ) && ( nAlphaIdx != -1 ) )
+            {
+                // we need to create one - only do RGB palettes
+                this->m_pColorTable = new GDALColorTable(GPI_RGB);
+
+                // OK go through each row and fill in the fields
+                for( int nRowIndex = 0; nRowIndex < pKEATable->GetRowCount(); nRowIndex++ )
+                {
+                    // maybe could be more efficient using ValuesIO
+                    GDALColorEntry colorEntry;
+                    colorEntry.c1 = pKEATable->GetValueAsInt(nRowIndex, nRedIdx);
+                    colorEntry.c2 = pKEATable->GetValueAsInt(nRowIndex, nGreenIdx);
+                    colorEntry.c3 = pKEATable->GetValueAsInt(nRowIndex, nBlueIdx);
+                    colorEntry.c4 = pKEATable->GetValueAsInt(nRowIndex, nAlphaIdx);
+                    this->m_pColorTable->SetColorEntry(nRowIndex, &colorEntry);
+                }
+            }
+        }
+        catch(kealib::KEAException &e)
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, "Failed to read color table: %s", e.what() );
+            delete this->m_pColorTable;
+            this->m_pColorTable = NULL;
+        }
+    }
+    return this->m_pColorTable;
+}
+
+CPLErr KEARasterBand::SetColorTable(GDALColorTable *poCT)
+{
+    if( poCT == NULL )
+        return CE_Failure;
+
+    try
+    {
+        GDALRasterAttributeTable *pKEATable = this->GetDefaultRAT();
+        int nRedIdx = -1;
+        int nGreenIdx = -1;
+        int nBlueIdx = -1;
+        int nAlphaIdx = -1;
+
+        if( poCT->GetColorEntryCount() > pKEATable->GetRowCount() )
+        {
+            pKEATable->SetRowCount(poCT->GetColorEntryCount());
+        }
+
+        for( int nColIdx = 0; nColIdx < pKEATable->GetColumnCount(); nColIdx++ )
+        {
+            if( pKEATable->GetTypeOfCol(nColIdx) == GFT_Integer )
+            {
+                GDALRATFieldUsage eFieldUsage = pKEATable->GetUsageOfCol(nColIdx);
+                if( eFieldUsage == GFU_Red )
+                    nRedIdx = nColIdx;
+                else if( eFieldUsage == GFU_Green )
+                    nGreenIdx = nColIdx;
+                else if( eFieldUsage == GFU_Blue )
+                    nBlueIdx = nColIdx;
+                else if( eFieldUsage == GFU_Alpha )
+                    nAlphaIdx = nColIdx;
+            }
+        }
+
+        // create if needed
+        if( nRedIdx == -1 )
+        {
+            if( pKEATable->CreateColumn("Red", GFT_Integer, GFU_Red ) != CE_None )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
+                return CE_Failure;
+            }
+            nRedIdx = pKEATable->GetColumnCount() - 1;
+        }
+        if( nGreenIdx == -1 )
+        {
+            if( pKEATable->CreateColumn("Green", GFT_Integer, GFU_Green ) != CE_None )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
+                return CE_Failure;
+            }
+            nGreenIdx = pKEATable->GetColumnCount() - 1;
+        }
+        if( nBlueIdx == -1 )
+        {
+            if( pKEATable->CreateColumn("Blue", GFT_Integer, GFU_Blue ) != CE_None )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
+                return CE_Failure;
+            }
+            nBlueIdx = pKEATable->GetColumnCount() - 1;
+        }
+        if( nAlphaIdx == -1 )
+        {
+            if( pKEATable->CreateColumn("Alpha", GFT_Integer, GFU_Alpha ) != CE_None )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to create column" );
+                return CE_Failure;
+            }
+            nAlphaIdx = pKEATable->GetColumnCount() - 1;
+        }
+
+        // OK go through each row and fill in the fields
+        for( int nRowIndex = 0; nRowIndex < poCT->GetColorEntryCount(); nRowIndex++ )
+        {
+            // maybe could be more efficient using ValuesIO
+            GDALColorEntry colorEntry;
+            poCT->GetColorEntryAsRGB(nRowIndex, &colorEntry);
+            pKEATable->SetValue(nRowIndex, nRedIdx, colorEntry.c1);
+            pKEATable->SetValue(nRowIndex, nGreenIdx, colorEntry.c2);
+            pKEATable->SetValue(nRowIndex, nBlueIdx, colorEntry.c3);
+            pKEATable->SetValue(nRowIndex, nAlphaIdx, colorEntry.c4);
+        }
+
+        // out of date
+        delete this->m_pColorTable;
+        this->m_pColorTable = NULL;
+    }
+    catch(kealib::KEAException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Failed to write color table: %s", e.what() );
+        return CE_Failure;
+    }
+    return CE_None;
+}
+
+GDALColorInterp KEARasterBand::GetColorInterpretation()
+{
+    kealib::KEABandClrInterp ekeainterp;
+    try
+    {
+        ekeainterp = this->m_pImageIO->getImageBandClrInterp(this->nBand);
+    }
+    catch(kealib::KEAException &e)
+    {
+        return GCI_GrayIndex;
+    }
+        
+    GDALColorInterp egdalinterp;
+    switch(ekeainterp)
+    {
+        case kealib::kea_generic:
+        case kealib::kea_greyindex:
+            egdalinterp = GCI_GrayIndex;
+            break;
+        case kealib::kea_paletteindex:
+            egdalinterp = GCI_PaletteIndex;
+            break;
+        case kealib::kea_redband:
+            egdalinterp = GCI_RedBand;
+            break;
+        case kealib::kea_greenband:
+            egdalinterp = GCI_GreenBand;
+            break;
+        case kealib::kea_blueband:
+            egdalinterp = GCI_BlueBand;
+            break;
+        case kealib::kea_alphaband:
+            egdalinterp = GCI_AlphaBand;
+            break;
+        case kealib::kea_hueband:
+            egdalinterp = GCI_HueBand;
+            break;
+        case kealib::kea_saturationband:
+            egdalinterp = GCI_SaturationBand;
+            break;
+        case kealib::kea_lightnessband:
+            egdalinterp = GCI_LightnessBand;
+            break;
+        case kealib::kea_cyanband:
+            egdalinterp = GCI_CyanBand;
+            break;
+        case kealib::kea_magentaband:
+            egdalinterp = GCI_MagentaBand;
+            break;
+        case kealib::kea_yellowband:
+            egdalinterp = GCI_YellowBand;
+            break;
+        case kealib::kea_blackband:
+            egdalinterp = GCI_BlackBand;
+            break;
+        case kealib::kea_ycbcr_yband:
+            egdalinterp = GCI_YCbCr_YBand;
+            break;
+        case kealib::kea_ycbcr_cbband:
+            egdalinterp = GCI_YCbCr_CbBand;
+            break;
+        case kealib::kea_ycbcr_crband:
+            egdalinterp = GCI_YCbCr_CrBand;
+            break;
+        default:
+            egdalinterp = GCI_GrayIndex;
+            break;
+    }
+        
+    return egdalinterp;
+}
+
+CPLErr KEARasterBand::SetColorInterpretation(GDALColorInterp egdalinterp)
+{
+    kealib::KEABandClrInterp ekeainterp;
+    switch(egdalinterp)
+    {
+        case GCI_GrayIndex:
+            ekeainterp = kealib::kea_greyindex;
+            break;
+        case GCI_PaletteIndex:
+            ekeainterp = kealib::kea_paletteindex;
+            break;
+        case GCI_RedBand:
+            ekeainterp = kealib::kea_redband;
+            break;
+        case GCI_GreenBand:
+            ekeainterp = kealib::kea_greenband;
+            break;
+        case GCI_BlueBand:
+            ekeainterp = kealib::kea_blueband;
+            break;
+        case GCI_AlphaBand:
+            ekeainterp = kealib::kea_alphaband;
+            break;
+        case GCI_HueBand:
+            ekeainterp = kealib::kea_hueband;
+            break;
+        case GCI_SaturationBand:
+            ekeainterp = kealib::kea_saturationband;
+            break;
+        case GCI_LightnessBand:
+            ekeainterp = kealib::kea_lightnessband;
+            break;
+        case GCI_CyanBand:
+            ekeainterp = kealib::kea_cyanband;
+            break;
+        case GCI_MagentaBand:
+            ekeainterp = kealib::kea_magentaband;
+            break;
+        case GCI_YellowBand:
+            ekeainterp = kealib::kea_yellowband;
+            break;
+        case GCI_BlackBand:
+            ekeainterp = kealib::kea_blackband;
+            break;
+        case GCI_YCbCr_YBand:
+            ekeainterp = kealib::kea_ycbcr_yband;
+            break;
+        case GCI_YCbCr_CbBand:
+            ekeainterp = kealib::kea_ycbcr_cbband;
+            break;
+        case GCI_YCbCr_CrBand:
+            ekeainterp = kealib::kea_ycbcr_crband;
+            break;
+        default:
+            ekeainterp = kealib::kea_greyindex;
+            break;
+    }
+
+    try
+    {
+        this->m_pImageIO->setImageBandClrInterp(this->nBand, ekeainterp);
+    }
+    catch(kealib::KEAException &e)
+    {
+        // do nothing? The docs say CE_Failure only if unsupporte by format
+    }
+    return CE_None;
+}
+
+// clean up our overview objects
+void KEARasterBand::deleteOverviewObjects()
+{
+    // deletes the objects - not the overviews themselves
+    int nCount;
+    for( nCount = 0; nCount < m_nOverviews; nCount++ )
+    {
+        delete m_panOverviewBands[nCount];
+    }
+    CPLFree(m_panOverviewBands);
+    m_panOverviewBands = NULL;
+    m_nOverviews = 0;
+}
+
+// read in any overviews in the file into our array of objects
+void KEARasterBand::readExistingOverviews()
+{
+    // delete any existing overview bands
+    this->deleteOverviewObjects();
+
+    m_nOverviews = this->m_pImageIO->getNumOfOverviews(this->nBand);
+    m_panOverviewBands = (KEAOverview**)CPLMalloc(sizeof(KEAOverview*) * m_nOverviews);
+
+    uint64_t nXSize, nYSize;    
+    for( int nCount = 0; nCount < m_nOverviews; nCount++ )
+    {
+        this->m_pImageIO->getOverviewSize(this->nBand, nCount + 1, &nXSize, &nYSize);
+        m_panOverviewBands[nCount] = new KEAOverview((KEADataset*)this->poDS, this->nBand, GA_ReadOnly,
+                                        this->m_pImageIO, this->m_pnRefCount, nCount + 1, nXSize, nYSize);
+    }
+}
+
+// number of overviews
+int KEARasterBand::GetOverviewCount()
+{
+    return m_nOverviews;
+}
+
+// get a given overview
+GDALRasterBand* KEARasterBand::GetOverview(int nOverview)
+{
+    if( nOverview < 0 || nOverview >= m_nOverviews )
+    {
+        return NULL;
+    }
+    else
+    {
+        return m_panOverviewBands[nOverview];
+    }
+}
+
+CPLErr KEARasterBand::CreateMaskBand(CPL_UNUSED int nFlags)
+{
+    if( m_bMaskBandOwned )
+        delete m_pMaskBand;
+    m_pMaskBand = NULL;
+    try
+    {
+        this->m_pImageIO->createMask(this->nBand);
+    }
+    catch(kealib::KEAException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Failed to create mask band: %s", e.what());
+        return CE_Failure;
+    }
+    return CE_None;
+}
+
+GDALRasterBand* KEARasterBand::GetMaskBand()
+{
+    if( m_pMaskBand == NULL )
+    {
+        try
+        {
+            if( this->m_pImageIO->maskCreated(this->nBand) )
+            {
+                m_pMaskBand = new KEAMaskBand(this, this->m_pImageIO, this->m_pnRefCount);
+                m_bMaskBandOwned = true;
+            }
+            else
+            {
+                // use the base class implementation - GDAL will delete
+                //fprintf( stderr, "returning base GetMaskBand()\n" );
+                m_pMaskBand = GDALPamRasterBand::GetMaskBand();
+            }
+        }
+        catch(kealib::KEAException &e)
+        {
+            // do nothing?
+        }
+    }
+    return m_pMaskBand;
+}
+
+int KEARasterBand::GetMaskFlags()
+{
+    try
+    {
+        if( ! this->m_pImageIO->maskCreated(this->nBand) )
+        {
+            // need to return the base class one since we are using
+            // the base class implementation of GetMaskBand()
+            //fprintf( stderr, "returning base GetMaskFlags()\n" );
+            return GDALPamRasterBand::GetMaskFlags();
+        }
+    }
+    catch(kealib::KEAException &e)
+    {
+        // do nothing?
+    }
+
+    // none of the other flags seem to make sense...
+    return 0;
+}
+
diff --git a/frmts/kea/keaband.h b/frmts/kea/keaband.h
new file mode 100644
index 0000000..2931e2d
--- /dev/null
+++ b/frmts/kea/keaband.h
@@ -0,0 +1,116 @@
+/*
+ * $Id: keaband.h 28011 2014-11-26 13:47:09Z rouault $
+ *  keaband.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEABAND_H
+#define KEABAND_H
+
+#include "gdal_pam.h"
+#include "keadataset.h"
+
+class KEAOverview;
+class KEAMaskBand;
+
+// Provides the implementation of a GDAL raster band
+class KEARasterBand : public GDALPamRasterBand
+{
+private:
+    int                 *m_pnRefCount; // reference count of m_pImageIO
+
+    int                  m_nOverviews; // number of overviews
+    KEAOverview        **m_panOverviewBands; // array of overview objects
+    GDALRasterBand      *m_pMaskBand;   // pointer to mask band if one exists (and been requested)
+    bool                 m_bMaskBandOwned; // do we delete it or not?
+
+    GDALRasterAttributeTable  *m_pAttributeTable; // pointer to the attribute table
+                                                 // created on first call to GetDefaultRAT()
+    GDALColorTable      *m_pColorTable;     // pointer to the color table
+                                            // created on first call to GetColorTable()
+
+    int                  m_nAttributeChunkSize; // for reporting via the metadata
+public:
+    // constructor/destructor
+    KEARasterBand( KEADataset *pDataset, int nSrcBand, GDALAccess eAccess, kealib::KEAImageIO *pImageIO, int *pRefCount );
+    ~KEARasterBand();
+
+    // virtual methods for overview support
+    int GetOverviewCount();
+    GDALRasterBand* GetOverview(int nOverview);
+
+    // virtual methods for band names (aka description)
+    void SetDescription(const char *);
+
+    // virtual methods for handling the metadata
+    CPLErr SetMetadataItem (const char *pszName, const char *pszValue, const char *pszDomain="");
+    const char *GetMetadataItem (const char *pszName, const char *pszDomain="");
+    char **GetMetadata(const char *pszDomain="");
+    CPLErr SetMetadata(char **papszMetadata, const char *pszDomain="");
+
+    // virtual methods for the no data value
+    double GetNoDataValue(int *pbSuccess=NULL);
+    CPLErr SetNoDataValue(double dfNoData);
+
+    // virtual methods for RATs
+    GDALRasterAttributeTable *GetDefaultRAT();
+    CPLErr SetDefaultRAT(const GDALRasterAttributeTable *poRAT);
+
+    // virtual methods for color tables
+    GDALColorTable *GetColorTable();
+    CPLErr SetColorTable(GDALColorTable *poCT);
+
+    // virtual methods for color interpretation
+    GDALColorInterp GetColorInterpretation();
+    CPLErr SetColorInterpretation(GDALColorInterp gdalinterp);
+
+    // virtual mthods for band masks
+    CPLErr CreateMaskBand(int nFlags);
+    GDALRasterBand* GetMaskBand();
+    int GetMaskFlags();
+
+    // internal methods for overviews
+    void readExistingOverviews();
+    void deleteOverviewObjects();
+    void CreateOverviews(int nOverviews, int *panOverviewList);
+    KEAOverview** GetOverviewList() { return m_panOverviewBands; }
+
+protected:
+    // methods for accessing data as blocks
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual CPLErr IWriteBlock( int, int, void * );
+
+    // updates m_papszMetadataList
+    void UpdateMetadataList();
+
+    kealib::KEAImageIO  *m_pImageIO; // our image access pointer - refcounted
+    char               **m_papszMetadataList; // CPLStringList of metadata
+    kealib::KEADataType  m_eKEADataType; // data type as KEA enum
+};
+
+
+#endif //KEABAND_H
diff --git a/frmts/kea/keacopy.cpp b/frmts/kea/keacopy.cpp
new file mode 100644
index 0000000..8301765
--- /dev/null
+++ b/frmts/kea/keacopy.cpp
@@ -0,0 +1,489 @@
+/*
+ * $Id: keacopy.cpp 28437 2015-02-07 15:50:57Z rouault $
+ *  keacopy.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include <cmath>
+#include "gdal_priv.h"
+#include "gdal_rat.h"
+#include "libkea/KEAImageIO.h"
+#include "libkea/KEAAttributeTable.h"
+#include "libkea/KEAAttributeTableInMem.h"
+
+// Support functions for CreateCopy()
+
+// Copies GDAL Band to KEA Band if nOverview == -1
+// Otherwise it is assumed we are writing to the specified overview
+static
+bool KEACopyRasterData( GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand, int nOverview, int nTotalBands, GDALProgressFunc pfnProgress, void *pProgressData)
+{
+    // get some info
+    kealib::KEADataType eKeaType = pImageIO->getImageBandDataType(nBand);
+    unsigned int nBlockSize;
+    if( nOverview == -1 )
+        nBlockSize = pImageIO->getImageBlockSize( nBand );
+    else
+        nBlockSize = pImageIO->getOverviewBlockSize(nBand, nOverview);
+
+    GDALDataType eGDALType = pBand->GetRasterDataType();
+    unsigned int nXSize = pBand->GetXSize();
+    unsigned int nYSize = pBand->GetYSize();
+
+    // allocate some space
+    int nPixelSize = GDALGetDataTypeSize( eGDALType ) / 8;
+    void *pData = VSIMalloc3( nPixelSize, nBlockSize, nBlockSize);
+    if( pData == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Unable to allocate memory" );        
+        return false;
+    }
+    // for progress
+    int nTotalBlocks = std::ceil( (double)nXSize / (double)nBlockSize ) * std::ceil( (double)nYSize / (double)nBlockSize );
+    int nBlocksComplete = 0;
+    double dLastFraction = -1;
+    // go through the image
+    for( unsigned int nY = 0; nY < nYSize; nY += nBlockSize )
+    {
+        // adjust for edge blocks
+        unsigned int nysize = nBlockSize;
+        unsigned int nytotalsize = nY + nBlockSize;
+        if( nytotalsize > nYSize )
+            nysize -= (nytotalsize - nYSize);
+        for( unsigned int nX = 0; nX < nXSize; nX += nBlockSize )
+        {
+            // adjust for edge blocks
+            unsigned int nxsize = nBlockSize;
+            unsigned int nxtotalsize = nX + nBlockSize;
+            if( nxtotalsize > nXSize )
+                nxsize -= (nxtotalsize - nXSize);
+
+            // read in from GDAL
+            if( pBand->RasterIO( GF_Read, nX, nY, nxsize, nysize, pData, nxsize, nysize, eGDALType, nPixelSize, nPixelSize * nBlockSize, NULL) != CE_None )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Unable to read blcok at %d %d\n", nX, nY );
+                return false;
+            }
+            // write out to KEA
+            if( nOverview == -1 )
+                pImageIO->writeImageBlock2Band( nBand, pData, nX, nY, nxsize, nysize, nBlockSize, nBlockSize, eKeaType);
+            else
+                pImageIO->writeToOverview( nBand, nOverview, pData,  nX, nY, nxsize, nysize, nBlockSize, nBlockSize, eKeaType);
+
+            // progress
+            nBlocksComplete++;
+            if( nOverview == -1 )
+            {
+                double dFraction = (((double)nBlocksComplete / (double)nTotalBlocks) / (double)nTotalBands) + ((double)(nBand-1) * (1.0 / (double)nTotalBands));
+                if( dFraction != dLastFraction )
+                {
+                    if( !pfnProgress( dFraction, NULL, pProgressData ) )
+                    {
+                        CPLFree( pData );
+                        return false;
+                    }
+                    dLastFraction = dFraction;
+                }
+            }
+        }
+    }
+    
+    CPLFree( pData );
+    return true;
+}
+
+static const int RAT_CHUNKSIZE = 1000;
+// copies the raster attribute table
+static void KEACopyRAT(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
+{
+    const GDALRasterAttributeTable *gdalAtt = pBand->GetDefaultRAT();
+    if((gdalAtt != NULL) && (gdalAtt->GetRowCount() > 0))
+    {
+        // some operations depend on whether the input dataset is HFA
+        int bInputHFA = pBand->GetDataset()->GetDriver() != NULL &&
+                EQUAL(pBand->GetDataset()->GetDriver()->GetDescription(), "HFA");
+
+        kealib::KEAAttributeTable *keaAtt = pImageIO->getAttributeTable(kealib::kea_att_file, nBand);
+
+        /*bool redDef = false;
+        int redIdx = -1;
+        bool greenDef = false;
+        int greenIdx = -1;
+        bool blueDef = false;
+        int blueIdx = -1;
+        bool alphaDef = false;
+        int alphaIdx = -1;*/
+        
+        int numCols = gdalAtt->GetColumnCount();
+        std::vector<kealib::KEAATTField*> *fields = new std::vector<kealib::KEAATTField*>();
+        kealib::KEAATTField *field;
+        for(int ni = 0; ni < numCols; ++ni)
+        {
+            field = new kealib::KEAATTField();
+            field->name = gdalAtt->GetNameOfCol(ni);
+            
+            field->dataType = kealib::kea_att_string;
+            switch(gdalAtt->GetTypeOfCol(ni))
+            {
+                case GFT_Integer:
+                    field->dataType = kealib::kea_att_int;
+                    break;
+                case GFT_Real:
+                    field->dataType = kealib::kea_att_float;
+                    break;
+                case GFT_String:
+                    field->dataType = kealib::kea_att_string;
+                    break;
+                default:
+                    // leave as "kea_att_string"
+                    break;
+            }
+            
+            if(bInputHFA && (field->name == "Histogram"))
+            {
+                field->usage = "PixelCount";
+                field->dataType = kealib::kea_att_int;
+            }
+            else if(bInputHFA && (field->name == "Opacity"))
+            {
+                field->name = "Alpha";
+                field->usage = "Alpha";
+                field->dataType = kealib::kea_att_int;
+                /*alphaDef = true;
+                alphaIdx = ni;*/
+            }
+            else
+            {
+                field->usage = "Generic";
+                switch(gdalAtt->GetUsageOfCol(ni))
+                {
+                    case GFU_PixelCount:
+                        field->usage = "PixelCount";
+                        break;
+                    case GFU_Name:
+                        field->usage = "Name";
+                        break;
+                    case GFU_Red:
+                        field->usage = "Red";
+                        if( bInputHFA )
+                        {
+                            field->dataType = kealib::kea_att_int;
+                            /*redDef = true;
+                            redIdx = ni;*/
+                        }
+                        break;
+                    case GFU_Green:
+                        field->usage = "Green";
+                        if( bInputHFA )
+                        {
+                            field->dataType = kealib::kea_att_int;
+                            /*greenDef = true;
+                            greenIdx = ni;*/
+                        }
+                        break;
+                    case GFU_Blue:
+                        field->usage = "Blue";
+                        if( bInputHFA )
+                        {
+                            field->dataType = kealib::kea_att_int;
+                            /*blueDef = true;
+                            blueIdx = ni;*/
+                        }
+                        break;
+                    case GFU_Alpha:
+                        field->usage = "Alpha";
+                        break;
+                    default:
+                        // leave as "Generic"
+                        break;
+                }
+            }
+            
+            fields->push_back(field);
+        }
+        
+        keaAtt->addFields(fields); // This function will populate the field indexs used within the KEA RAT.
+        
+        int numRows = gdalAtt->GetRowCount();
+        keaAtt->addRows(numRows);
+
+        int *pnIntBuffer = new int[RAT_CHUNKSIZE];
+        int64_t *pnInt64Buffer = new int64_t[RAT_CHUNKSIZE];
+        double *pfDoubleBuffer = new double[RAT_CHUNKSIZE];
+        for(int ni = 0; ni < numRows; ni += RAT_CHUNKSIZE )
+        {
+            int nLength = RAT_CHUNKSIZE;
+            if( ( ni + nLength ) > numRows )
+            {
+                nLength = numRows - ni;
+            }
+            for(int nj = 0; nj < numCols; ++nj)
+            {
+                field = fields->at(nj);
+
+                switch(field->dataType)
+                {
+                    case kealib::kea_att_int:
+                        ((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, pnIntBuffer);
+                        for( int i = 0; i < nLength; i++ )
+                        {
+                            pnInt64Buffer[i] = pnIntBuffer[i];
+                        }
+                        keaAtt->setIntFields(ni, nLength, field->idx, pnInt64Buffer);
+                        break;
+                    case kealib::kea_att_float:
+                        ((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, pfDoubleBuffer);
+                        keaAtt->setFloatFields(ni, nLength, field->idx, pfDoubleBuffer);
+                        break;
+                    case kealib::kea_att_string:
+                        {   
+                            char **papszColData = (char**)VSIMalloc2(nLength, sizeof(char*));
+                            ((GDALRasterAttributeTable*)gdalAtt)->ValuesIO(GF_Read, nj, ni, nLength, papszColData);
+                     
+                            std::vector<std::string> aStringBuffer;
+                            for( int i = 0; i < nLength; i++ )
+                            {
+                                aStringBuffer.push_back(papszColData[i]);
+                            }
+
+                            for( int i = 0; i < nLength; i++ )
+                                CPLFree(papszColData[i]);
+                            CPLFree(papszColData);
+
+                            keaAtt->setStringFields(ni, nLength, field->idx, &aStringBuffer);
+                        }
+                        break;
+                    default:
+                        // Ignore as data type is not known or available from a HFA/GDAL RAT."
+                        break;
+                }
+            }
+        }
+
+        delete[] pnIntBuffer;
+        delete[] pnInt64Buffer;
+        delete[] pfDoubleBuffer;
+
+        delete keaAtt;
+        for(std::vector<kealib::KEAATTField*>::iterator iterField = fields->begin(); iterField != fields->end(); ++iterField)
+        {
+            delete *iterField;
+        }
+        delete fields;
+    }
+}
+
+// copies the metadata
+// pass nBand == -1 to copy a dataset's metadata
+// or band index to copy a band's metadata
+static void KEACopyMetadata( GDALMajorObject *pObject, kealib::KEAImageIO *pImageIO, int nBand)
+{
+    char **ppszMetadata = pObject->GetMetadata();
+    if( ppszMetadata != NULL )
+    {
+        char *pszName;
+        const char *pszValue;
+        int nCount = 0;
+        while( ppszMetadata[nCount] != NULL )
+        {
+            pszName = NULL;
+            pszValue = CPLParseNameValue( ppszMetadata[nCount], &pszName );
+            if( pszValue == NULL )
+                pszValue = "";
+            if( pszName != NULL )
+            {
+                // it is LAYER_TYPE and a Band? if so handle seperately
+                if( ( nBand != -1 ) && EQUAL( pszName, "LAYER_TYPE" ) )
+                {
+                    if( EQUAL( pszValue, "athematic" ) )
+                    {
+                        pImageIO->setImageBandLayerType(nBand, kealib::kea_continuous );
+                    }
+                    else
+                    {
+                        pImageIO->setImageBandLayerType(nBand, kealib::kea_thematic );
+                    }
+                }
+                else if( ( nBand != -1 ) && EQUAL( pszName, "STATISTICS_HISTOBINVALUES") )
+                {
+                    // this gets copied accross as part of the attributes
+                    // so ignore for now
+                }
+                else
+                {
+                    // write it into the image
+                    if( nBand != -1 )
+                        pImageIO->setImageBandMetaData(nBand, pszName, pszValue );
+                    else
+                        pImageIO->setImageMetaData(pszName, pszValue );
+                }
+                CPLFree(pszName);
+            }
+            nCount++;
+        }
+    }
+}
+
+// copies the description over
+static void KEACopyDescription(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
+{
+    const char *pszDesc = pBand->GetDescription();
+    pImageIO->setImageBandDescription(nBand, pszDesc);
+}
+
+// copies the no data value accross
+static void KEACopyNoData(GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand)
+{
+    int bSuccess = 0;
+    double dNoData = pBand->GetNoDataValue(&bSuccess);
+    if( bSuccess )
+    {
+        pImageIO->setNoDataValue(nBand, &dNoData, kealib::kea_64float);
+    }
+}
+
+static bool KEACopyBand( GDALRasterBand *pBand, kealib::KEAImageIO *pImageIO, int nBand, int nTotalbands, GDALProgressFunc pfnProgress, void *pProgressData)
+{
+    // first copy the raster data over
+    if( !KEACopyRasterData( pBand, pImageIO, nBand, -1, nTotalbands, pfnProgress, pProgressData) )
+        return false;
+
+    // are there any overviews?
+    int nOverviews = pBand->GetOverviewCount();
+    for( int nOverviewCount = 0; nOverviewCount < nOverviews; nOverviewCount++ )
+    {
+        GDALRasterBand *pOverview = pBand->GetOverview(nOverviewCount);
+        int nOverviewXSize = pOverview->GetXSize();
+        int nOverviewYSize = pOverview->GetYSize();
+        pImageIO->createOverview( nBand, nOverviewCount + 1, nOverviewXSize, nOverviewYSize);
+        if( !KEACopyRasterData( pOverview, pImageIO, nBand, nOverviewCount + 1, nTotalbands, pfnProgress, pProgressData) )
+            return false;
+    }
+
+    // now metadata 
+    KEACopyMetadata(pBand, pImageIO, nBand);
+
+    // and attributes
+    KEACopyRAT(pBand, pImageIO, nBand);
+
+    // and description
+    KEACopyDescription(pBand, pImageIO, nBand);
+
+    // and no data
+    KEACopyNoData(pBand, pImageIO, nBand);
+
+    return true;
+}
+
+static void KEACopySpatialInfo(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
+{
+    kealib::KEAImageSpatialInfo *pSpatialInfo = pImageIO->getSpatialInfo();
+
+    double padfTransform[6];
+    if( pDataset->GetGeoTransform(padfTransform) == CE_None )
+    {
+        // convert back from GDAL's array format
+        pSpatialInfo->tlX = padfTransform[0];
+        pSpatialInfo->xRes = padfTransform[1];
+        pSpatialInfo->xRot = padfTransform[2];
+        pSpatialInfo->tlY = padfTransform[3];
+        pSpatialInfo->yRot = padfTransform[4];
+        pSpatialInfo->yRes = padfTransform[5];
+    }
+
+    const char *pszProjection = pDataset->GetProjectionRef();
+    pSpatialInfo->wktString = pszProjection;
+
+    pImageIO->setSpatialInfo( pSpatialInfo );
+}
+
+// copies the GCP's accross
+static void KEACopyGCPs(GDALDataset *pDataset, kealib::KEAImageIO *pImageIO)
+{
+    int nGCPs = pDataset->GetGCPCount();
+
+    if( nGCPs > 0 )
+    {
+        std::vector<kealib::KEAImageGCP*> KEAGCPs;
+        const GDAL_GCP *pGDALGCPs = pDataset->GetGCPs();
+
+        for( int n = 0; n < nGCPs; n++ )
+        {
+            kealib::KEAImageGCP *pGCP = new kealib::KEAImageGCP;
+            pGCP->pszId = pGDALGCPs[n].pszId;
+            pGCP->pszInfo = pGDALGCPs[n].pszInfo;
+            pGCP->dfGCPPixel = pGDALGCPs[n].dfGCPPixel;
+            pGCP->dfGCPLine = pGDALGCPs[n].dfGCPLine;
+            pGCP->dfGCPX = pGDALGCPs[n].dfGCPX;
+            pGCP->dfGCPY = pGDALGCPs[n].dfGCPY;
+            pGCP->dfGCPZ = pGDALGCPs[n].dfGCPZ;
+            KEAGCPs.push_back(pGCP);
+        }
+
+        const char *pszGCPProj = pDataset->GetGCPProjection();
+        try
+        {
+            pImageIO->setGCPs(&KEAGCPs, pszGCPProj);
+        }
+        catch(kealib::KEAException &e)
+        {
+        }
+
+        for( std::vector<kealib::KEAImageGCP*>::iterator itr = KEAGCPs.begin(); itr != KEAGCPs.end(); itr++)
+        {
+            delete (*itr);
+        }
+    }
+}
+
+
+
+bool KEACopyFile( GDALDataset *pDataset, kealib::KEAImageIO *pImageIO, GDALProgressFunc pfnProgress, void *pProgressData )
+{
+    // Main function - copies pDataset to pImageIO
+
+    // copy accross the spatial info
+    KEACopySpatialInfo( pDataset, pImageIO);
+
+    // dataset metadata
+    KEACopyMetadata(pDataset, pImageIO, -1);
+
+    // GCPs
+    KEACopyGCPs(pDataset, pImageIO);
+    
+    // now copy all the bands over
+    int nBands = pDataset->GetRasterCount();
+    for( int nBand = 0; nBand < nBands; nBand++ )
+    {
+        GDALRasterBand *pBand = pDataset->GetRasterBand(nBand + 1);
+        if( !KEACopyBand( pBand, pImageIO, nBand +1, nBands, pfnProgress, pProgressData ) )
+            return false;
+    }
+
+    pfnProgress( 1.0, NULL, pProgressData );
+    return true;
+}
diff --git a/frmts/kea/keacopy.h b/frmts/kea/keacopy.h
new file mode 100644
index 0000000..24f9cd7
--- /dev/null
+++ b/frmts/kea/keacopy.h
@@ -0,0 +1,38 @@
+/*
+ * $Id: keacopy.h 28011 2014-11-26 13:47:09Z rouault $
+ *  keacopy.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEACOPY_H
+#define KEACOPY_H
+
+#include "libkea/KEAImageIO.h"
+
+bool KEACopyFile( GDALDataset *pDataset, kealib::KEAImageIO *pImageIO, GDALProgressFunc pfnProgress, void *pProgressData );
+
+#endif
diff --git a/frmts/kea/keadataset.cpp b/frmts/kea/keadataset.cpp
new file mode 100644
index 0000000..4826e0d
--- /dev/null
+++ b/frmts/kea/keadataset.cpp
@@ -0,0 +1,867 @@
+/*
+ * $Id: keadataset.cpp 28825 2015-03-30 14:48:50Z rouault $
+ *  keadataset.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "keadataset.h"
+#include "keaband.h"
+#include "keacopy.h"
+
+#include "libkea/KEACommon.h"
+
+// Function for converting a libkea type into a GDAL type
+GDALDataType KEA_to_GDAL_Type( kealib::KEADataType ekeaType )
+{
+    GDALDataType egdalType = GDT_Unknown;
+    switch( ekeaType )
+    {
+        case kealib::kea_8int:
+        case kealib::kea_8uint:
+            egdalType = GDT_Byte;
+            break;
+        case kealib::kea_16int:
+            egdalType = GDT_Int16;
+            break;
+        case kealib::kea_32int:
+            egdalType = GDT_Int32;
+            break;
+        case kealib::kea_16uint:
+            egdalType = GDT_UInt16;
+            break;
+        case kealib::kea_32uint:
+            egdalType = GDT_UInt32;
+            break;
+        case kealib::kea_32float:
+            egdalType = GDT_Float32;
+            break;
+        case kealib::kea_64float:
+            egdalType = GDT_Float64;
+            break;
+        default:
+            egdalType = GDT_Unknown;
+            break;
+    }
+    return egdalType;
+}
+
+// function for converting a GDAL type to a kealib type
+kealib::KEADataType GDAL_to_KEA_Type( GDALDataType egdalType )
+{
+    kealib::KEADataType ekeaType = kealib::kea_undefined;
+    switch( egdalType )
+    {
+        case GDT_Byte:
+            ekeaType = kealib::kea_8uint;
+            break;
+        case GDT_Int16:
+            ekeaType = kealib::kea_16int;
+            break;
+        case GDT_Int32:
+            ekeaType = kealib::kea_32int;
+            break;
+        case GDT_UInt16:
+            ekeaType = kealib::kea_16uint;
+            break;
+        case GDT_UInt32:
+            ekeaType = kealib::kea_32uint;
+            break;
+        case GDT_Float32:
+            ekeaType = kealib::kea_32float;
+            break;
+        case GDT_Float64:
+            ekeaType = kealib::kea_64float;
+            break;
+        default:
+            ekeaType = kealib::kea_undefined;
+            break;
+    }
+    return ekeaType;
+}
+
+// static function - pointer set in driver 
+GDALDataset *KEADataset::Open( GDALOpenInfo * poOpenInfo )
+{
+    if( Identify( poOpenInfo ) )
+    {
+        try
+        {
+            // try and open it in the appropriate mode
+            H5::H5File *pH5File;
+            if( poOpenInfo->eAccess == GA_ReadOnly )
+            {
+                pH5File = kealib::KEAImageIO::openKeaH5RDOnly( poOpenInfo->pszFilename );
+            }
+            else
+            {
+                pH5File = kealib::KEAImageIO::openKeaH5RW( poOpenInfo->pszFilename );
+            }
+            // create the KEADataset object
+            KEADataset *pDataset = new KEADataset( pH5File, poOpenInfo->eAccess );
+
+            // set the description as the name
+            pDataset->SetDescription( poOpenInfo->pszFilename );
+
+            return pDataset;
+        }
+        catch (kealib::KEAIOException &e)
+        {
+            // was a problem - can't be a valid file
+            return NULL;
+        }
+    }
+    else
+    {
+        // not a KEA file
+        return NULL;
+    }
+}
+
+// static function- pointer set in driver
+// this function is called in preference to Open
+// 
+int KEADataset::Identify( GDALOpenInfo * poOpenInfo )
+{
+    bool bisKEA = false;
+
+/* -------------------------------------------------------------------- */
+/*      Is it an HDF5 file?                                             */
+/* -------------------------------------------------------------------- */
+    static const char achSignature[] = "\211HDF\r\n\032\n";
+
+    if( poOpenInfo->pabyHeader == NULL ||
+        memcmp(poOpenInfo->pabyHeader,achSignature,8) != 0 )
+    {
+        return false;
+    }
+
+    try
+    {
+        // is this a KEA file?
+        bisKEA = kealib::KEAImageIO::isKEAImage( poOpenInfo->pszFilename );
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        bisKEA = false;
+    }
+    if( bisKEA )
+        return 1;
+    else
+        return 0;
+}
+
+
+// static function
+H5::H5File *KEADataset::CreateLL( const char * pszFilename,
+                                  int nXSize, int nYSize, int nBands,
+                                  GDALDataType eType,
+                                  char ** papszParmList  )
+{
+    GDALDriverH hDriver = GDALGetDriverByName( "KEA" );
+    if( ( hDriver == NULL ) || !GDALValidateCreationOptions( hDriver, papszParmList ) )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed. Invalid creation option(s)\n", pszFilename);
+        return NULL;
+    }
+    // process any creation options in papszParmList
+    // default value
+    unsigned int nimageblockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
+    // see if they have provided a different value
+    const char *pszValue = CSLFetchNameValue( papszParmList, "IMAGEBLOCKSIZE" );
+    if( pszValue != NULL )
+        nimageblockSize = (unsigned int) atol( pszValue );
+
+    unsigned int nattblockSize = kealib::KEA_ATT_CHUNK_SIZE;
+    pszValue = CSLFetchNameValue( papszParmList, "ATTBLOCKSIZE" );
+    if( pszValue != NULL )
+        nattblockSize = (unsigned int) atol( pszValue );
+
+    unsigned int nmdcElmts = kealib::KEA_MDC_NELMTS;
+    pszValue = CSLFetchNameValue( papszParmList, "MDC_NELMTS" );
+    if( pszValue != NULL )
+        nmdcElmts = (unsigned int) atol( pszValue );
+
+    hsize_t nrdccNElmts = kealib::KEA_RDCC_NELMTS;
+    pszValue = CSLFetchNameValue( papszParmList, "RDCC_NELMTS" );
+    if( pszValue != NULL )
+        nrdccNElmts = (unsigned int) atol( pszValue );
+
+    hsize_t nrdccNBytes = kealib::KEA_RDCC_NBYTES;
+    pszValue = CSLFetchNameValue( papszParmList, "RDCC_NBYTES" );
+    if( pszValue != NULL )
+        nrdccNBytes = (unsigned int) atol( pszValue );
+
+    double nrdccW0 = kealib::KEA_RDCC_W0;
+    pszValue = CSLFetchNameValue( papszParmList, "RDCC_W0" );
+    if( pszValue != NULL )
+        nrdccW0 = CPLAtof( pszValue );
+
+    hsize_t nsieveBuf = kealib::KEA_SIEVE_BUF;
+    pszValue = CSLFetchNameValue( papszParmList, "SIEVE_BUF" );
+    if( pszValue != NULL )
+        nsieveBuf = (unsigned int) atol( pszValue );
+
+    hsize_t nmetaBlockSize = kealib::KEA_META_BLOCKSIZE;
+    pszValue = CSLFetchNameValue( papszParmList, "META_BLOCKSIZE" );
+    if( pszValue != NULL )
+        nmetaBlockSize = (unsigned int) atol( pszValue );
+
+    unsigned int ndeflate = kealib::KEA_DEFLATE;
+    pszValue = CSLFetchNameValue( papszParmList, "DEFLATE" );
+    if( pszValue != NULL )
+        ndeflate = (unsigned int) atol( pszValue );
+
+    kealib::KEADataType keaDataType = GDAL_to_KEA_Type( eType );
+    if( nBands > 0 && keaDataType == kealib::kea_undefined )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Data type %s not supported in KEA",
+                  GDALGetDataTypeName(eType) );
+        return NULL;
+    }
+    
+    try
+    {
+        // now create it
+        H5::H5File *keaImgH5File = kealib::KEAImageIO::createKEAImage( pszFilename,
+                                                    keaDataType,
+                                                    nXSize, nYSize, nBands,
+                                                    NULL, NULL, nimageblockSize, 
+                                                    nattblockSize, nmdcElmts, nrdccNElmts,
+                                                    nrdccNBytes, nrdccW0, nsieveBuf, 
+                                                    nmetaBlockSize, ndeflate );
+        return keaImgH5File;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed. Error: %s\n",
+                  pszFilename, e.what() );
+        return NULL;
+    }
+}
+
+// static function- pointer set in driver
+GDALDataset *KEADataset::Create( const char * pszFilename,
+                                  int nXSize, int nYSize, int nBands,
+                                  GDALDataType eType,
+                                  char ** papszParmList  )
+{
+    H5::H5File *keaImgH5File = CreateLL( pszFilename, nXSize, nYSize, nBands,
+                                         eType, papszParmList  );
+    if( keaImgH5File == NULL )
+        return NULL;
+
+    bool bThematic = CSLTestBoolean(CSLFetchNameValueDef( papszParmList, "THEMATIC", "FALSE" ));
+
+    try
+    {
+        // create our dataset object                            
+        KEADataset *pDataset = new KEADataset( keaImgH5File, GA_Update );
+
+        pDataset->SetDescription( pszFilename );
+
+        // set all to thematic if asked
+        if( bThematic )
+        {
+            for( int nCount = 0; nCount < nBands; nCount++ )
+            {
+                GDALRasterBand *pBand = pDataset->GetRasterBand(nCount+1);
+                pBand->SetMetadataItem("LAYER_TYPE", "thematic");
+            }
+        }
+
+        return pDataset;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed. Error: %s\n",
+                  pszFilename, e.what() );
+        return NULL;
+    }
+}
+
+GDALDataset *KEADataset::CreateCopy( const char * pszFilename, GDALDataset *pSrcDs,
+                                CPL_UNUSED int bStrict, char **  papszParmList, 
+                                GDALProgressFunc pfnProgress, void *pProgressData )
+{
+    // get the data out of the input dataset
+    int nXSize = pSrcDs->GetRasterXSize();
+    int nYSize = pSrcDs->GetRasterYSize();
+    int nBands = pSrcDs->GetRasterCount();
+
+    GDALDataType eType = (nBands == 0) ? GDT_Unknown : pSrcDs->GetRasterBand(1)->GetRasterDataType();
+    H5::H5File *keaImgH5File = CreateLL( pszFilename, nXSize, nYSize, nBands,
+                                         eType, papszParmList  );
+    if( keaImgH5File == NULL )
+        return NULL;
+
+    bool bThematic = CSLTestBoolean(CSLFetchNameValueDef( papszParmList, "THEMATIC", "FALSE" ));
+
+    try
+    {
+        // create the imageio
+        kealib::KEAImageIO *pImageIO = new kealib::KEAImageIO();
+        
+        // open the file
+        pImageIO->openKEAImageHeader( keaImgH5File );
+
+        // copy file
+        if( !KEACopyFile( pSrcDs, pImageIO, pfnProgress, pProgressData) )
+        {
+            delete pImageIO;
+            return NULL;
+        }
+
+        // close it
+        try
+        {
+            pImageIO->close();
+        }
+        catch (kealib::KEAIOException &e)
+        {
+        }
+        delete pImageIO;
+
+        // now open it again - because the constructor loads all the info
+        // in we need to copy the data first....
+        keaImgH5File = kealib::KEAImageIO::openKeaH5RW( pszFilename );
+
+        // and wrap it in a dataset
+        KEADataset *pDataset = new KEADataset( keaImgH5File, GA_Update );
+        pDataset->SetDescription( pszFilename );
+
+        // set all to thematic if asked - overrides whatever set by CopyFile
+        if( bThematic )
+        {
+            for( int nCount = 0; nCount < nBands; nCount++ )
+            {
+                GDALRasterBand *pBand = pDataset->GetRasterBand(nCount+1);
+                pBand->SetMetadataItem("LAYER_TYPE", "thematic");
+            }
+        }
+
+        for( int nCount = 0; nCount < nBands; nCount++ )
+        {
+            pDataset->GetRasterBand(nCount+1)->SetColorInterpretation(
+                pSrcDs->GetRasterBand(nCount+1)->GetColorInterpretation());
+        }
+        
+        // KEA has no concept of per-dataset mask band for now.
+        for( int nCount = 0; nCount < nBands; nCount++ )
+        {
+            if( pSrcDs->GetRasterBand(nCount+1)->GetMaskFlags() == 0 ) // Per-band mask
+            {
+                pDataset->GetRasterBand(nCount+1)->CreateMaskBand(0);
+                GDALRasterBandCopyWholeRaster(
+                    (GDALRasterBandH)pSrcDs->GetRasterBand(nCount+1)->GetMaskBand(),
+                    (GDALRasterBandH)pDataset->GetRasterBand(nCount+1)->GetMaskBand(),
+                    NULL, NULL, NULL);
+            }
+        }
+
+        return pDataset;
+    }
+    catch (kealib::KEAException &e)
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed. Error: %s\n",
+                  pszFilename, e.what() );
+        return NULL;
+    }
+
+}
+
+// constructor
+KEADataset::KEADataset( H5::H5File *keaImgH5File, GDALAccess eAccess )
+{
+    try
+    {
+        // create the image IO and initilize the refcount
+        m_pImageIO = new kealib::KEAImageIO();
+        m_pnRefcount = new int(1);
+
+        // NULL until we read them in 
+        m_papszMetadataList = NULL;
+        m_pGCPs = NULL;
+        m_pszGCPProjection = NULL;
+
+        // open the file
+        m_pImageIO->openKEAImageHeader( keaImgH5File );
+        kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
+
+        // get the dimensions
+        this->nBands = m_pImageIO->getNumOfImageBands();
+        this->nRasterXSize = pSpatialInfo->xSize;
+        this->nRasterYSize = pSpatialInfo->ySize;
+        this->eAccess = eAccess;
+
+        // create all the bands
+        for( int nCount = 0; nCount < nBands; nCount++ )
+        {
+            // note GDAL uses indices starting at 1 and so does kealib
+            // create band object
+            KEARasterBand *pBand = new KEARasterBand( this, nCount + 1, eAccess, m_pImageIO, m_pnRefcount );
+            // read in overviews
+            pBand->readExistingOverviews();
+            // set the band into this dataset
+            this->SetBand( nCount + 1, pBand );            
+        }
+
+        // read in the metadata
+        this->UpdateMetadataList();
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        // ignore?
+        CPLError( CE_Warning, CPLE_AppDefined,
+                "Caught exception in KEADataset constructor %s", e.what() );
+    }
+}
+
+KEADataset::~KEADataset()
+{
+    // destroy the metadata
+    CSLDestroy(m_papszMetadataList);
+    // decrement the refcount and delete if needed
+    (*m_pnRefcount)--;
+    if( *m_pnRefcount == 0 )
+    {
+        try
+        {
+            m_pImageIO->close();
+        }
+        catch (kealib::KEAIOException &e)
+        {
+        }
+        delete m_pImageIO;
+        delete m_pnRefcount;
+    }
+    this->DestroyGCPs();
+    CPLFree( m_pszGCPProjection );
+}
+
+// read in the metadata into our CSLStringList
+void KEADataset::UpdateMetadataList()
+{
+    std::vector< std::pair<std::string, std::string> > odata;
+    // get all the metadata
+    odata = this->m_pImageIO->getImageMetaData();
+    for(std::vector< std::pair<std::string, std::string> >::iterator iterMetaData = odata.begin(); iterMetaData != odata.end(); ++iterMetaData)
+    {
+        m_papszMetadataList = CSLSetNameValue(m_papszMetadataList, iterMetaData->first.c_str(), iterMetaData->second.c_str());
+    }
+}
+
+// read in the geotransform
+CPLErr KEADataset::GetGeoTransform( double * padfTransform )
+{
+    try
+    {
+        kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
+        // GDAL uses an array format
+        padfTransform[0] = pSpatialInfo->tlX;
+        padfTransform[1] = pSpatialInfo->xRes;
+        padfTransform[2] = pSpatialInfo->xRot;
+        padfTransform[3] = pSpatialInfo->tlY;
+        padfTransform[4] = pSpatialInfo->yRot;
+        padfTransform[5] = pSpatialInfo->yRes;
+    
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                "Unable to read geotransform: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// read in the projection ref
+const char *KEADataset::GetProjectionRef()
+{
+    try
+    {
+        kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
+        // should be safe since pSpatialInfo should be around a while...
+        return pSpatialInfo->wktString.c_str();
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        return NULL;
+    }
+}
+
+// set the geotransform
+CPLErr KEADataset::SetGeoTransform (double *padfTransform )
+{
+    try
+    {
+        // get the spatial info and update it
+        kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
+        // convert back from GDAL's array format
+        pSpatialInfo->tlX = padfTransform[0];
+        pSpatialInfo->xRes = padfTransform[1];
+        pSpatialInfo->xRot = padfTransform[2];
+        pSpatialInfo->tlY = padfTransform[3];
+        pSpatialInfo->yRot = padfTransform[4];
+        pSpatialInfo->yRes = padfTransform[5];
+
+        m_pImageIO->setSpatialInfo( pSpatialInfo );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                "Unable to write geotransform: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// set the projection
+CPLErr KEADataset::SetProjection( const char *pszWKT )
+{
+    try
+    {
+        // get the spatial info and update it
+        kealib::KEAImageSpatialInfo *pSpatialInfo = m_pImageIO->getSpatialInfo();
+
+        pSpatialInfo->wktString = pszWKT;
+
+        m_pImageIO->setSpatialInfo( pSpatialInfo );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                "Unable to write projection: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// Thought this might be handy to pass back to the application
+void * KEADataset::GetInternalHandle(const char *)
+{
+    return m_pImageIO;
+}
+
+// this is called by GDALDataset::BuildOverviews. we implement this function to support
+// building of overviews
+CPLErr KEADataset::IBuildOverviews(const char *pszResampling, int nOverviews, int *panOverviewList, 
+                                    int nListBands, int *panBandList, GDALProgressFunc pfnProgress, 
+                                    void *pProgressData)
+{
+    // go through the list of bands that have been passed in
+    int nCurrentBand, nOK = 1;
+    for( int nBandCount = 0; (nBandCount < nListBands) && nOK; nBandCount++ )
+    {
+        // get the band number
+        nCurrentBand = panBandList[nBandCount];
+        // get the band
+        KEARasterBand *pBand = (KEARasterBand*)this->GetRasterBand(nCurrentBand);
+        // create the overview object
+        pBand->CreateOverviews( nOverviews, panOverviewList );
+
+        // get GDAL to do the hard work. It will calculate the overviews and write them
+        // back into the objects
+        if( GDALRegenerateOverviews( (GDALRasterBandH)pBand, nOverviews, (GDALRasterBandH*)pBand->GetOverviewList(),
+                                    pszResampling, pfnProgress, pProgressData ) != CE_None )
+        {
+            nOK = 0;
+        }
+    }
+    if( !nOK )
+    {
+        return CE_Failure;
+    }
+    else
+    {
+        return CE_None;
+    }
+}
+
+// set a single metadata item
+CPLErr KEADataset::SetMetadataItem(const char *pszName, const char *pszValue, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return CE_Failure;
+
+    try
+    {
+        this->m_pImageIO->setImageMetaData(pszName, pszValue );
+        // CSLSetNameValue will update if already there
+        m_papszMetadataList = CSLSetNameValue( m_papszMetadataList, pszName, pszValue );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Unable to write metadata: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// get a single metadata item
+const char *KEADataset::GetMetadataItem (const char *pszName, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return NULL;
+    // string returned from CSLFetchNameValue should be persistant
+    return CSLFetchNameValue(m_papszMetadataList, pszName);
+}
+
+// get the whole metadata as CSLStringList
+char **KEADataset::GetMetadata(const char *pszDomain)
+{ 
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return NULL;
+    // this is what we store it as anyway
+    return m_papszMetadataList; 
+}
+
+// set the whole metadata as a CSLStringList
+CPLErr KEADataset::SetMetadata(char **papszMetadata, const char *pszDomain)
+{
+    // only deal with 'default' domain - no geolocation etc
+    if( ( pszDomain != NULL ) && ( *pszDomain != '\0' ) )
+        return CE_Failure;
+
+    int nIndex = 0;
+    char *pszName;
+    const char *pszValue;
+    try
+    {
+        // go through each item
+        while( papszMetadata[nIndex] != NULL )
+        {
+            // get the value/name
+            pszName = NULL;
+            pszValue = CPLParseNameValue( papszMetadata[nIndex], &pszName );
+            if( pszValue == NULL )
+                pszValue = "";
+            if( pszName != NULL )
+            {
+                // set it with imageio
+                this->m_pImageIO->setImageMetaData(pszName, pszValue );
+                CPLFree(pszName);
+            }
+            nIndex++;
+        }
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Unable to write metadata: %s", e.what() );
+        return CE_Failure;
+    }
+
+    // destroy our one and replace it
+    CSLDestroy(m_papszMetadataList);
+    m_papszMetadataList = CSLDuplicate(papszMetadata);
+    return CE_None;
+}
+
+CPLErr KEADataset::AddBand(GDALDataType eType, char **papszOptions)
+{
+    // process any creation options in papszOptions
+    unsigned int nimageBlockSize = kealib::KEA_IMAGE_CHUNK_SIZE;
+    unsigned int nattBlockSize = kealib::KEA_ATT_CHUNK_SIZE;
+    unsigned int ndeflate = kealib::KEA_DEFLATE;
+    if (papszOptions != NULL) {
+        const char *pszValue = CSLFetchNameValue(papszOptions,"IMAGEBLOCKSIZE");
+        if ( pszValue != NULL ) {
+            nimageBlockSize = atol(pszValue);
+        }
+
+        pszValue = CSLFetchNameValue(papszOptions, "ATTBLOCKSIZE");
+        if (pszValue != NULL) {
+            nattBlockSize = atol(pszValue);
+        }
+
+        pszValue = CSLFetchNameValue(papszOptions, "DEFLATE");
+        if (pszValue != NULL) {
+            ndeflate = atol(pszValue);
+        }
+    }
+    
+    kealib::KEADataType keaDataType = GDAL_to_KEA_Type( eType );
+    if( keaDataType == kealib::kea_undefined )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Data type %s not supported in KEA",
+                  GDALGetDataTypeName(eType) );
+        return CE_Failure;
+    }
+    
+    try {
+        m_pImageIO->addImageBand(keaDataType, "", nimageBlockSize,
+                nattBlockSize, ndeflate);
+    } catch (kealib::KEAIOException &e) {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Unable to create band: %s", e.what() );
+        return CE_Failure;
+    }
+
+    // create a new band and add it to the dataset
+    // note GDAL uses indices starting at 1 and so does kealib
+    KEARasterBand *pBand = new KEARasterBand(this, this->nBands+1, this->eAccess,
+            m_pImageIO, m_pnRefcount);
+    this->SetBand(this->nBands+1, pBand);            
+
+    return CE_None;
+}
+
+
+int KEADataset::GetGCPCount()
+{
+    try
+    {
+        return m_pImageIO->getGCPCount();
+    }
+    catch (kealib::KEAIOException &e) 
+    {
+        return 0;
+    }
+
+}
+
+const char* KEADataset::GetGCPProjection()
+{
+    if( m_pszGCPProjection == NULL )
+    {
+        try
+        {
+            std::string sProj = m_pImageIO->getGCPProjection();
+            m_pszGCPProjection = CPLStrdup( sProj.c_str() );
+        }
+        catch (kealib::KEAIOException &e) 
+        {
+            return NULL;
+        }
+    }
+    return m_pszGCPProjection;
+}
+
+const GDAL_GCP* KEADataset::GetGCPs()
+{
+    if( m_pGCPs == NULL )
+    {
+        // convert to GDAL data structures
+        try
+        {
+            unsigned int nCount = m_pImageIO->getGCPCount();
+            std::vector<kealib::KEAImageGCP*> *pKEAGCPs = m_pImageIO->getGCPs();
+
+            m_pGCPs = (GDAL_GCP*)CPLCalloc(nCount, sizeof(GDAL_GCP));
+            for( unsigned int nIndex = 0; nIndex < nCount; nIndex++)
+            {
+                GDAL_GCP *pGCP = &m_pGCPs[nIndex];
+                kealib::KEAImageGCP *pKEAGCP = pKEAGCPs->at(nIndex);
+                pGCP->pszId = CPLStrdup( pKEAGCP->pszId.c_str() );
+                pGCP->pszInfo = CPLStrdup( pKEAGCP->pszInfo.c_str() );
+                pGCP->dfGCPPixel = pKEAGCP->dfGCPPixel;
+                pGCP->dfGCPLine = pKEAGCP->dfGCPLine;
+                pGCP->dfGCPX = pKEAGCP->dfGCPX;
+                pGCP->dfGCPY = pKEAGCP->dfGCPY;
+                pGCP->dfGCPZ = pKEAGCP->dfGCPZ;
+
+                delete pKEAGCP;
+            }
+
+            delete pKEAGCPs;
+        }
+        catch (kealib::KEAIOException &e) 
+        {
+            return NULL;
+        }
+    }
+    return m_pGCPs;
+}
+
+CPLErr KEADataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection)
+{
+    this->DestroyGCPs();
+    CPLFree( m_pszGCPProjection );
+    m_pszGCPProjection = NULL;
+    CPLErr result = CE_None;
+
+    std::vector<kealib::KEAImageGCP*> *pKEAGCPs = new std::vector<kealib::KEAImageGCP*>(nGCPCount);
+    for( int nIndex = 0; nIndex < nGCPCount; nIndex++ )
+    {
+        const GDAL_GCP *pGCP = &pasGCPList[nIndex];
+        kealib::KEAImageGCP *pKEA = new kealib::KEAImageGCP;
+        pKEA->pszId = pGCP->pszId;
+        pKEA->pszInfo = pGCP->pszInfo;
+        pKEA->dfGCPPixel = pGCP->dfGCPPixel;
+        pKEA->dfGCPLine = pGCP->dfGCPLine;
+        pKEA->dfGCPX = pGCP->dfGCPX;
+        pKEA->dfGCPY = pGCP->dfGCPY;
+        pKEA->dfGCPZ = pGCP->dfGCPZ;
+        pKEAGCPs->at(nIndex) = pKEA;
+    }
+    try
+    {
+        m_pImageIO->setGCPs(pKEAGCPs, pszGCPProjection);
+    }
+    catch (kealib::KEAIOException &e) 
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                "Unable to write GCPs: %s", e.what() );
+        result = CE_Failure;
+    }
+
+    for( std::vector<kealib::KEAImageGCP*>::iterator itr = pKEAGCPs->begin(); itr != pKEAGCPs->end(); itr++)
+    {
+        kealib::KEAImageGCP *pKEA = (*itr);
+        delete pKEA;
+    }
+    delete pKEAGCPs;
+
+    return result;
+}
+
+void KEADataset::DestroyGCPs()
+{
+    if( m_pGCPs != NULL )
+    {
+        // we assume this is always the same as the internal list...
+        int nCount = this->GetGCPCount();
+        for( int nIndex = 0; nIndex < nCount; nIndex++ )
+        {
+            GDAL_GCP *pGCP = &m_pGCPs[nIndex];
+            CPLFree( pGCP->pszId );
+            CPLFree( pGCP->pszInfo );
+        }
+        CPLFree( m_pGCPs );
+        m_pGCPs = NULL;
+    }
+}
diff --git a/frmts/kea/keadataset.h b/frmts/kea/keadataset.h
new file mode 100644
index 0000000..b46d466
--- /dev/null
+++ b/frmts/kea/keadataset.h
@@ -0,0 +1,112 @@
+/*
+ * $Id: keadataset.h 28011 2014-11-26 13:47:09Z rouault $
+ *  keadataset.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEADATASET_H
+#define KEADATASET_H
+
+#include "gdal_pam.h"
+#include "libkea/KEAImageIO.h"
+
+// class that implements a GDAL dataset
+class KEADataset : public GDALPamDataset
+{
+    static H5::H5File *CreateLL( const char * pszFilename,
+                                  int nXSize, int nYSize, int nBands,
+                                  GDALDataType eType,
+                                  char ** papszParmList  );
+
+public:
+    // constructor/destructor
+    KEADataset( H5::H5File *keaImgH5File, GDALAccess eAccess );
+    ~KEADataset();
+    
+    // static methods that handle open and creation
+    // the driver class has pointers to these
+    static GDALDataset *Open( GDALOpenInfo * );
+    static int Identify( GDALOpenInfo * poOpenInfo );
+    static GDALDataset *Create( const char * pszFilename,
+                                  int nXSize, int nYSize, int nBands,
+                                  GDALDataType eType,
+                                  char **  papszParmList );
+    static GDALDataset *CreateCopy( const char * pszFilename, GDALDataset *pSrcDs,
+                                int bStrict, char **  papszParmList, 
+                                GDALProgressFunc pfnProgress, void *pProgressData );
+
+    // virtual methods for dealing with transform and projection
+    CPLErr      GetGeoTransform( double * padfTransform );
+    const char *GetProjectionRef();
+
+    CPLErr  SetGeoTransform (double *padfTransform );
+    CPLErr SetProjection( const char *pszWKT );
+
+    // method to get a pointer to the imageio class
+    void *GetInternalHandle (const char *);
+
+    // virtual methods for dealing with metadata
+    CPLErr SetMetadataItem (const char *pszName, const char *pszValue, const char *pszDomain="");
+    const char *GetMetadataItem (const char *pszName, const char *pszDomain="");
+
+    char **GetMetadata(const char *pszDomain="");
+    CPLErr SetMetadata(char **papszMetadata, const char *pszDomain="");
+
+    // virtual method for adding new image bands
+    CPLErr AddBand(GDALDataType eType, char **papszOptions = NULL);
+
+    // GCPs
+    int GetGCPCount();
+    const char* GetGCPProjection();
+    const GDAL_GCP* GetGCPs();
+    CPLErr SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList, const char *pszGCPProjection);
+
+protected:
+    // this method builds overviews for the specified bands. 
+    virtual CPLErr IBuildOverviews(const char *pszResampling, int nOverviews, int *panOverviewList, 
+                                    int nListBands, int *panBandList, GDALProgressFunc pfnProgress, 
+                                    void *pProgressData);
+
+    // internal method to update m_papszMetadataList
+    void UpdateMetadataList();
+
+    void DestroyGCPs();
+
+private:
+    // pointer to KEAImageIO class and the refcount for it
+    kealib::KEAImageIO  *m_pImageIO;
+    int                 *m_pnRefcount;
+    char               **m_papszMetadataList; // CSLStringList for metadata
+    GDAL_GCP            *m_pGCPs;
+    char                *m_pszGCPProjection;
+};
+
+// conversion functions
+GDALDataType KEA_to_GDAL_Type( kealib::KEADataType ekeaType );
+kealib::KEADataType GDAL_to_KEA_Type( GDALDataType egdalType );
+
+#endif //KEADATASET_H
diff --git a/frmts/kea/keadriver.cpp b/frmts/kea/keadriver.cpp
new file mode 100644
index 0000000..46c1f36
--- /dev/null
+++ b/frmts/kea/keadriver.cpp
@@ -0,0 +1,93 @@
+/*
+ * $Id: keadriver.cpp 28041 2014-12-01 11:33:47Z rouault $
+ *  keadriver.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "keadataset.h"
+
+CPL_C_START
+void CPL_DLL GDALRegister_KEA(void);
+CPL_C_END
+
+// method to register this driver
+void GDALRegister_KEA()
+{
+    GDALDriver  *poDriver;
+
+    if (! GDAL_CHECK_VERSION("KEA"))
+        return;
+
+    if( GDALGetDriverByName( "KEA" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+        
+        poDriver->SetDescription( "KEA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
+                                   "KEA Image Format (.kea)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "kea" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "frmt_kea.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
+                            "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+CPLSPrintf("\
+<CreationOptionList> \
+<Option name='IMAGEBLOCKSIZE' type='int' description='The size of each block for image data' default='%d'/> \
+<Option name='ATTBLOCKSIZE' type='int' description='The size of each block for attribute data' default='%d'/> \
+<Option name='MDC_NELMTS' type='int' description='Number of elements in the meta data cache' default='%d'/> \
+<Option name='RDCC_NELMTS' type='int' description='Number of elements in the raw data chunk cache' default='%d'/> \
+<Option name='RDCC_NBYTES' type='int' description='Total size of the raw data chunk cache, in bytes' default='%d'/> \
+<Option name='RDCC_W0' type='float' min='0' max='1' description='Preemption policy' default='%.2f'/> \
+<Option name='SIEVE_BUF' type='int' description='Sets the maximum size of the data sieve buffer' default='%d'/> \
+<Option name='META_BLOCKSIZE' type='int' description='Sets the minimum size of metadata block allocations' default='%d'/> \
+<Option name='DEFLATE' type='int' description='0 (no compression) to 9 (max compression)' default='%d'/> \
+<Option name='THEMATIC' type='boolean' description='If YES then all bands are set to thematic' default='NO'/> \
+</CreationOptionList>",
+           (int)kealib::KEA_IMAGE_CHUNK_SIZE,
+           (int)kealib::KEA_ATT_CHUNK_SIZE,
+           (int)kealib::KEA_MDC_NELMTS,
+           (int)kealib::KEA_RDCC_NELMTS,
+           (int)kealib::KEA_RDCC_NBYTES,
+           kealib::KEA_RDCC_W0,
+           (int)kealib::KEA_SIEVE_BUF,
+           (int)kealib::KEA_META_BLOCKSIZE,
+           kealib::KEA_DEFLATE));
+
+        // pointer to open function
+        poDriver->pfnOpen = KEADataset::Open;
+        // pointer to identify function
+        poDriver->pfnIdentify = KEADataset::Identify;
+        // pointer to create function
+        poDriver->pfnCreate = KEADataset::Create;
+        // pointer to create copy function
+        poDriver->pfnCreateCopy = KEADataset::CreateCopy;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/frmts/kea/keamaskband.cpp b/frmts/kea/keamaskband.cpp
new file mode 100644
index 0000000..9f7ac2a
--- /dev/null
+++ b/frmts/kea/keamaskband.cpp
@@ -0,0 +1,143 @@
+/*
+ * $Id: keamaskband.cpp 28011 2014-11-26 13:47:09Z rouault $
+ *  keamaskband.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "keamaskband.h"
+
+// constructor
+KEAMaskBand::KEAMaskBand(GDALRasterBand *pParent, 
+                kealib::KEAImageIO *pImageIO, int *pRefCount)
+{
+    m_nSrcBand = pParent->GetBand();
+    poDS = NULL;
+    nBand = 0;
+
+    nRasterXSize = pParent->GetXSize();
+    nRasterYSize = pParent->GetYSize();
+
+    eDataType = GDT_Byte;
+    pParent->GetBlockSize( &nBlockXSize, &nBlockYSize );
+    eAccess = pParent->GetAccess();
+
+    // grab the imageio class and its refcount
+    this->m_pImageIO = pImageIO;
+    this->m_pnRefCount = pRefCount;
+    // increment the refcount as we now have a reference to imageio
+    (*this->m_pnRefCount)++;
+}
+
+KEAMaskBand::~KEAMaskBand()
+{
+    // according to the docs, this is required
+    this->FlushCache();
+
+    // decrement the recount and delete if needed
+    (*m_pnRefCount)--;
+    if( *m_pnRefCount == 0 )
+    {
+        try
+        {
+            m_pImageIO->close();
+        }
+        catch (kealib::KEAIOException &e)
+        {
+        }
+        delete m_pImageIO;
+        delete m_pnRefCount;
+    }
+}
+
+// overridden implementation - calls readImageBlock2BandMask instead
+CPLErr KEAMaskBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount read so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+        this->m_pImageIO->readImageBlock2BandMask( this->m_nSrcBand,
+                                            pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize, 
+                                            kealib::kea_8uint );
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to read file: %s", e.what() );
+        return CE_Failure;
+    }
+    return CE_None;
+}
+
+// overridden implementation - calls writeImageBlock2BandMask instead
+CPLErr KEAMaskBand::IWriteBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount written so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+
+        this->m_pImageIO-> writeImageBlock2BandMask( this->m_nSrcBand, 
+                                            pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize,
+                                            kealib::kea_8uint );
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to write file: %s", e.what() );
+        return CE_Failure;
+    }
+    return CE_None;
+}
diff --git a/frmts/kea/keamaskband.h b/frmts/kea/keamaskband.h
new file mode 100644
index 0000000..20db9ed
--- /dev/null
+++ b/frmts/kea/keamaskband.h
@@ -0,0 +1,53 @@
+/*
+ * $Id: keamaskband.h 28011 2014-11-26 13:47:09Z rouault $
+ *  keamaskband.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEAMASKBAND_H
+#define KEAMASKBAND_H
+
+#include "gdal_priv.h"
+#include "libkea/KEAImageIO.h"
+
+class KEAMaskBand : public GDALRasterBand
+{
+    int m_nSrcBand;
+    kealib::KEAImageIO  *m_pImageIO; // our image access pointer - refcounted
+    int                 *m_pnRefCount; // reference count of m_pImageIO
+public:
+    KEAMaskBand(GDALRasterBand *pParent, kealib::KEAImageIO *pImageIO, int *pRefCount );
+    ~KEAMaskBand();
+
+protected:
+    // we just override these functions from GDALRasterBand
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual CPLErr IWriteBlock( int, int, void * );
+
+};
+
+#endif //KEAMASKBAND_H
diff --git a/frmts/kea/keaoverview.cpp b/frmts/kea/keaoverview.cpp
new file mode 100644
index 0000000..df6d3b0
--- /dev/null
+++ b/frmts/kea/keaoverview.cpp
@@ -0,0 +1,131 @@
+/*
+ * $Id: keaoverview.cpp 28011 2014-11-26 13:47:09Z rouault $
+ *  keaoverview.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "keaoverview.h"
+
+// constructor
+KEAOverview::KEAOverview(KEADataset *pDataset, int nSrcBand, GDALAccess eAccess,
+                kealib::KEAImageIO *pImageIO, int *pRefCount,
+                int nOverviewIndex, uint64_t nXSize, uint64_t nYSize)
+ : KEARasterBand( pDataset, nSrcBand, eAccess, pImageIO, pRefCount )
+{
+    this->m_nOverviewIndex = nOverviewIndex;
+    // overridden from the band - not the same size as the band obviously
+    this->nBlockXSize = pImageIO->getOverviewBlockSize(nSrcBand, nOverviewIndex);
+    this->nBlockYSize = pImageIO->getOverviewBlockSize(nSrcBand, nOverviewIndex);
+    this->nRasterXSize = nXSize;
+    this->nRasterYSize = nYSize;
+}
+
+KEAOverview::~KEAOverview()
+{
+
+}
+
+// overridden implementation - calls readFromOverview instead
+CPLErr KEAOverview::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount read so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+        this->m_pImageIO->readFromOverview( this->nBand, this->m_nOverviewIndex,
+                                            pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize, 
+                                            this->m_eKEADataType );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to read file: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+// overridden implementation - calls writeToOverview instead
+CPLErr KEAOverview::IWriteBlock( int nBlockXOff, int nBlockYOff, void * pImage )
+{
+    try
+    {
+        // GDAL deals in blocks - if we are at the end of a row
+        // we need to adjust the amount written so we don't go over the edge
+        int nxsize = this->nBlockXSize;
+        int nxtotalsize = this->nBlockXSize * (nBlockXOff + 1);
+        if( nxtotalsize > this->nRasterXSize )
+        {
+            nxsize -= (nxtotalsize - this->nRasterXSize);
+        }
+        int nysize = this->nBlockYSize;
+        int nytotalsize = this->nBlockYSize * (nBlockYOff + 1);
+        if( nytotalsize > this->nRasterYSize )
+        {
+            nysize -= (nytotalsize - this->nRasterYSize);
+        }
+
+        this->m_pImageIO->writeToOverview( this->nBand, this->m_nOverviewIndex,
+                                            pImage, this->nBlockXSize * nBlockXOff,
+                                            this->nBlockYSize * nBlockYOff,
+                                            nxsize, nysize, this->nBlockXSize, this->nBlockYSize,
+                                            this->m_eKEADataType );
+        return CE_None;
+    }
+    catch (kealib::KEAIOException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "Failed to write file: %s", e.what() );
+        return CE_Failure;
+    }
+}
+
+GDALRasterAttributeTable *KEAOverview::GetDefaultRAT()
+{
+    // KEARasterBand implements this, but we don't want to
+    return NULL;
+}
+
+CPLErr KEAOverview::SetDefaultRAT(CPL_UNUSED const GDALRasterAttributeTable *poRAT)
+{
+    // KEARasterBand implements this, but we don't want to
+    return CE_Failure;    
+}
diff --git a/frmts/kea/keaoverview.h b/frmts/kea/keaoverview.h
new file mode 100644
index 0000000..70428e8
--- /dev/null
+++ b/frmts/kea/keaoverview.h
@@ -0,0 +1,61 @@
+/*
+ * $Id: keaoverview.h 28011 2014-11-26 13:47:09Z rouault $
+ *  keaoverview.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEAOVERVIEW_H
+#define KEAOVERVIEW_H
+
+#include "keaband.h"
+
+// overview class. Derives from our band class
+// and just overrited and read/write block functions
+class KEAOverview : public KEARasterBand
+{
+    int         m_nOverviewIndex; // the index of this overview
+public:
+    KEAOverview(KEADataset *pDataset, int nSrcBand, GDALAccess eAccess, 
+                kealib::KEAImageIO *pImageIO, int *pRefCount,
+                int nOverviewIndex, uint64_t nXSize, uint64_t nYSize );
+    ~KEAOverview();
+
+    // virtual methods for RATs - not implemented for overviews
+    GDALRasterAttributeTable *GetDefaultRAT();
+
+    CPLErr SetDefaultRAT(const GDALRasterAttributeTable *poRAT);
+
+    // note that Color Table stuff implemented in base class
+    // so could be some duplication if overview asked for color table
+
+protected:
+    // we just override these functions from KEARasterBand
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual CPLErr IWriteBlock( int, int, void * );
+};
+
+#endif //KEAOVERVIEW_H
diff --git a/frmts/kea/kearat.cpp b/frmts/kea/kearat.cpp
new file mode 100644
index 0000000..886e406
--- /dev/null
+++ b/frmts/kea/kearat.cpp
@@ -0,0 +1,940 @@
+/*
+ * $Id: kearat.cpp 28014 2014-11-26 14:43:45Z rouault $
+ *  kearat.cpp
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#include "kearat.h"
+
+KEARasterAttributeTable::KEARasterAttributeTable(kealib::KEAAttributeTable *poKEATable)
+{
+    for( size_t nColumnIndex = 0; nColumnIndex < poKEATable->getMaxGlobalColIdx(); nColumnIndex++ )
+    {
+        kealib::KEAATTField sKEAField;
+        try
+        {
+            sKEAField = poKEATable->getField(nColumnIndex);
+        }
+        catch(kealib::KEAATTException &e)
+        {
+            // pKEATable->getField raised exception because we have a missing column
+            continue;
+        }
+        m_aoFields.push_back(sKEAField);
+    }
+    m_poKEATable = poKEATable;
+}
+
+KEARasterAttributeTable::~KEARasterAttributeTable()
+{
+    // can't just delete thanks to Windows
+    kealib::KEAAttributeTable::destroyAttributeTable(m_poKEATable);
+}
+
+GDALDefaultRasterAttributeTable *KEARasterAttributeTable::Clone() const
+{
+    if( ( GetRowCount() * GetColumnCount() ) > RAT_MAX_ELEM_FOR_CLONE )
+        return NULL;
+
+    GDALDefaultRasterAttributeTable *poRAT = new GDALDefaultRasterAttributeTable();
+
+    for( int iCol = 0; iCol < (int)m_aoFields.size(); iCol++)
+    {
+        CPLString sName = m_aoFields[iCol].name;
+        CPLString sUsage = m_aoFields[iCol].usage;
+        GDALRATFieldUsage eGDALUsage;
+        if( sUsage == "PixelCount" )
+            eGDALUsage = GFU_PixelCount;
+        else if( sUsage == "Name" )
+            eGDALUsage = GFU_Name;
+        else if( sUsage == "Red" )
+            eGDALUsage = GFU_Red;
+        else if( sUsage == "Green" )
+            eGDALUsage = GFU_Green;
+        else if( sUsage == "Blue" )
+            eGDALUsage = GFU_Blue;
+        else if( sUsage == "Alpha" )
+            eGDALUsage = GFU_Alpha;
+        else
+        {
+            // don't recognise any other special names - generic column
+            eGDALUsage = GFU_Generic;
+        }
+
+        GDALRATFieldType eGDALType;
+        switch( m_aoFields[iCol].dataType )
+        {
+            case kealib::kea_att_bool:
+            case kealib::kea_att_int:
+                eGDALType = GFT_Integer;
+                break;
+            case kealib::kea_att_float:
+                eGDALType = GFT_Real;
+                break;
+            case kealib::kea_att_string:
+                eGDALType = GFT_String;
+                break;
+            default:
+                eGDALType = GFT_Integer;
+                break;
+        }
+        poRAT->CreateColumn(sName, eGDALType, eGDALUsage);
+        poRAT->SetRowCount(m_poKEATable->getSize());
+        
+        if( m_poKEATable->getSize() == 0 )
+            continue;
+
+        if( eGDALType == GFT_Integer )
+        {
+            int *panColData = (int*)VSIMalloc2(sizeof(int), m_poKEATable->getSize());
+            if( panColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::Clone");
+                delete poRAT;
+                return NULL;
+            }
+
+            if( (const_cast<KEARasterAttributeTable*>(this))->
+                        ValuesIO(GF_Read, iCol, 0, m_poKEATable->getSize(), panColData ) != CE_None )
+            {
+                CPLFree(panColData);
+                delete poRAT;
+                return NULL;
+            }           
+
+            for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
+            {
+                poRAT->SetValue(iRow, iCol, panColData[iRow]);            
+            }
+            CPLFree(panColData);
+        }
+        if( eGDALType == GFT_Real )
+        {
+            double *padfColData = (double*)VSIMalloc2(sizeof(double), m_poKEATable->getSize());
+            if( padfColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::Clone");
+                delete poRAT;
+                return NULL;
+            }
+            if( (const_cast<KEARasterAttributeTable*>(this))->
+                        ValuesIO(GF_Read, iCol, 0, m_poKEATable->getSize(), padfColData ) != CE_None )
+            {
+                CPLFree(padfColData);
+                delete poRAT;
+                return NULL;
+            }           
+
+            for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
+            {
+                poRAT->SetValue(iRow, iCol, padfColData[iRow]);            
+            }
+            CPLFree(padfColData);
+        }
+        if( eGDALType == GFT_String )
+        {
+            char **papszColData = (char**)VSIMalloc2(sizeof(char*), m_poKEATable->getSize());
+            if( papszColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::Clone");
+                delete poRAT;
+                return NULL;
+            }
+
+            if( (const_cast<KEARasterAttributeTable*>(this))->
+                    ValuesIO(GF_Read, iCol, 0, m_poKEATable->getSize(), papszColData ) != CE_None )
+            {
+                CPLFree(papszColData);
+                delete poRAT;
+                return NULL;
+            }           
+
+            for( int iRow = 0; iRow < (int)m_poKEATable->getSize(); iRow++ )
+            {
+                poRAT->SetValue(iRow, iCol, papszColData[iRow]);
+                CPLFree(papszColData[iRow]);
+            }
+            CPLFree(papszColData);
+        }
+    }
+    return poRAT;
+}
+
+
+int KEARasterAttributeTable::GetColumnCount() const
+{
+    return (int)m_aoFields.size();
+}
+
+
+const char *KEARasterAttributeTable::GetNameOfCol(int nCol) const
+{
+     if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
+        return NULL;
+
+    return m_aoFields[nCol].name.c_str();
+}
+
+GDALRATFieldUsage KEARasterAttributeTable::GetUsageOfCol( int nCol ) const
+{
+    if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
+        return GFU_Generic;
+
+    GDALRATFieldUsage eGDALUsage;
+    std::string keausage = m_aoFields[nCol].usage;    
+
+    if( keausage == "PixelCount" )
+        eGDALUsage = GFU_PixelCount;
+    else if( keausage == "Name" )
+        eGDALUsage = GFU_Name;
+    else if( keausage == "Red" )
+        eGDALUsage = GFU_Red;
+    else if( keausage == "Green" )
+        eGDALUsage = GFU_Green;
+    else if( keausage == "Blue" )
+        eGDALUsage = GFU_Blue;
+    else if( keausage == "Alpha" )
+        eGDALUsage = GFU_Alpha;
+    else
+    {
+        // don't recognise any other special names - generic column
+        eGDALUsage = GFU_Generic;
+    }
+
+    return eGDALUsage;
+}
+
+GDALRATFieldType KEARasterAttributeTable::GetTypeOfCol( int nCol ) const
+{
+    if( ( nCol < 0 ) || ( nCol >= (int)m_aoFields.size() ) )
+        return GFT_Integer;
+
+    GDALRATFieldType eGDALType;
+    switch( m_aoFields[nCol].dataType )
+    {
+        case kealib::kea_att_bool:
+        case kealib::kea_att_int:
+            eGDALType = GFT_Integer;
+            break;
+        case kealib::kea_att_float:
+            eGDALType = GFT_Real;
+            break;
+        case kealib::kea_att_string:
+            eGDALType = GFT_String;
+            break;
+        default:
+            eGDALType = GFT_Integer;
+            break;
+    }
+    return eGDALType;
+}
+
+
+int KEARasterAttributeTable::GetColOfUsage( GDALRATFieldUsage eUsage ) const
+{
+    unsigned int i;
+
+    std::string keausage;
+    switch(eUsage)
+    {
+    case GFU_PixelCount:
+        keausage = "PixelCount";
+        break;
+    case GFU_Name:
+        keausage = "Name";
+        break;
+    case GFU_Red:
+        keausage = "Red";
+        break;
+    case GFU_Green:
+        keausage = "Green";
+        break;
+    case GFU_Blue:
+        keausage = "Blue";
+        break;
+    case GFU_Alpha:
+        keausage = "Alpha";
+        break;
+    default:
+        keausage = "Generic";
+        break;
+    }
+
+    for( i = 0; i < m_aoFields.size(); i++ )
+    {
+        if( m_aoFields[i].usage == keausage )
+            return i;
+    }
+    return -1;
+}
+
+int KEARasterAttributeTable::GetRowCount() const
+{
+    return (int)m_poKEATable->getSize();
+}
+
+const char *KEARasterAttributeTable::GetValueAsString( int iRow, int iField ) const
+{
+    // Get ValuesIO do do the work
+    char *apszStrList[1];
+    if( (const_cast<KEARasterAttributeTable*>(this))->
+                ValuesIO(GF_Read, iField, iRow, 1, apszStrList ) != CPLE_None )
+    {
+        return "";
+    }
+
+    const_cast<KEARasterAttributeTable*>(this)->osWorkingResult = apszStrList[0];
+    CPLFree(apszStrList[0]);
+
+    return osWorkingResult;
+}
+
+int KEARasterAttributeTable::GetValueAsInt( int iRow, int iField ) const
+{
+    // Get ValuesIO do do the work
+    int nValue;
+    if( (const_cast<KEARasterAttributeTable*>(this))->
+                ValuesIO(GF_Read, iField, iRow, 1, &nValue ) != CE_None )
+    {
+        return 0;
+    }
+
+    return nValue;
+}
+
+double KEARasterAttributeTable::GetValueAsDouble( int iRow, int iField ) const
+{
+    // Get ValuesIO do do the work
+    double dfValue;
+    if( (const_cast<KEARasterAttributeTable*>(this))->
+                ValuesIO(GF_Read, iField, iRow, 1, &dfValue ) != CE_None )
+    {
+        return 0;
+    }
+
+    return dfValue;
+}
+
+void KEARasterAttributeTable::SetValue( int iRow, int iField, const char *pszValue )
+{
+    // Get ValuesIO do do the work
+    ValuesIO(GF_Write, iField, iRow, 1, const_cast<char**>(&pszValue) );
+}
+
+void KEARasterAttributeTable::SetValue( int iRow, int iField, double dfValue)
+{
+    // Get ValuesIO do do the work
+    ValuesIO(GF_Write, iField, iRow, 1, &dfValue );
+}
+
+void KEARasterAttributeTable::SetValue( int iRow, int iField, int nValue )
+{
+    // Get ValuesIO do do the work
+    ValuesIO(GF_Write, iField, iRow, 1, &nValue );
+}
+
+CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, double *pdfData)
+{
+    /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+            "Dataset not open in update mode");
+        return CE_Failure;
+    }*/
+
+    if( iField < 0 || iField >= (int) m_aoFields.size() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iField (%d) out of range.", iField );
+
+        return CE_Failure;
+    }
+
+    if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
+
+        return CE_Failure;
+    }
+
+    switch( m_aoFields[iField].dataType )
+    {
+        case kealib::kea_att_bool:
+        case kealib::kea_att_int:
+        {
+            // allocate space for ints
+            int *panColData = (int*)VSIMalloc2(iLength, sizeof(int) );
+            if( panColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied doubles to ints
+                for( int i = 0; i < iLength; i++ )
+                    panColData[i] = pdfData[i];
+            }
+
+            // do the ValuesIO as ints
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, panColData );
+            if( eVal != CE_None )
+            {
+                CPLFree(panColData);
+                return eVal;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to doubles
+                for( int i = 0; i < iLength; i++ )
+                    pdfData[i] = panColData[i];
+            }
+
+            CPLFree(panColData);
+        }
+        break;
+        case kealib::kea_att_float:
+        {
+            try
+            {
+                if( eRWFlag == GF_Read )
+                    m_poKEATable->getFloatFields(iStartRow, iLength, m_aoFields[iField].idx, pdfData);
+                else
+                    m_poKEATable->setFloatFields(iStartRow, iLength, m_aoFields[iField].idx, pdfData);
+            }
+            catch(kealib::KEAException &e)
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
+                return CE_Failure;
+            }
+        }
+        break;
+        case kealib::kea_att_string:
+        {
+            // allocate space for string pointers
+            char **papszColData = (char**)VSIMalloc2(iLength, sizeof(char*));
+            if( papszColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied doubles to strings
+                for( int i = 0; i < iLength; i++ )
+                {
+                    osWorkingResult.Printf( "%.16g", pdfData[i] );
+                    papszColData[i] = CPLStrdup(osWorkingResult);
+                }
+            }
+
+            // do the ValuesIO as strings
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, papszColData );
+            if( eVal != CE_None )
+            {
+                if( eRWFlag == GF_Write )
+                {
+                    for( int i = 0; i < iLength; i++ )
+                        CPLFree(papszColData[i]);
+                }
+                CPLFree(papszColData);
+                return eVal;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to doubles
+                for( int i = 0; i < iLength; i++ )
+                    pdfData[i] = CPLAtof(papszColData[i]);
+            }
+
+            // either we allocated them for write, or they were allocated
+            // by ValuesIO on read
+            for( int i = 0; i < iLength; i++ )
+                CPLFree(papszColData[i]);
+
+            CPLFree(papszColData);
+        }
+        break;
+        default:
+            break;
+    }
+    return CE_None;
+}
+
+CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, int *pnData)
+{
+    /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+            "Dataset not open in update mode");
+        return CE_Failure;
+    }*/
+
+    if( iField < 0 || iField >= (int) m_aoFields.size() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iField (%d) out of range.", iField );
+
+        return CE_Failure;
+    }
+
+    if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
+
+        return CE_Failure;
+    }
+
+    switch( m_aoFields[iField].dataType )
+    {
+        case kealib::kea_att_bool:
+        {
+            // need to convert to/from bools
+            bool *panColData = (bool*)VSIMalloc2(iLength, sizeof(bool) );
+            if( panColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied ints to bools
+                for( int i = 0; i < iLength; i++ )
+                {
+                    panColData[i] = (pnData[i] != 0);
+                }
+            }
+
+            try
+            {
+                if( eRWFlag == GF_Read )
+                    m_poKEATable->getBoolFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
+                else
+                    m_poKEATable->setBoolFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
+            }
+            catch(kealib::KEAException &e)
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to ints
+                for( int i = 0; i < iLength; i++ )
+                    pnData[i] = panColData[i]? 1 : 0;
+            }
+            CPLFree(panColData);
+        }
+        break;
+        case kealib::kea_att_int:
+        {
+            // need to convert to/from int64_t
+            int64_t *panColData = (int64_t*)VSIMalloc2(iLength, sizeof(int64_t) );
+            if( panColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied ints to int64t
+                for( int i = 0; i < iLength; i++ )
+                    panColData[i] = pnData[i];
+            }
+
+            try
+            {
+                if( eRWFlag == GF_Read )
+                    m_poKEATable->getIntFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
+                else
+                    m_poKEATable->setIntFields(iStartRow, iLength, m_aoFields[iField].idx, panColData);
+            }
+            catch(kealib::KEAException &e)
+            {
+                fprintf(stderr,"Failed to read/write attribute table: %s %d %d %ld\n", e.what(), iStartRow, iLength, m_poKEATable->getSize() );
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to ints
+                for( int i = 0; i < iLength; i++ )
+                    pnData[i] = panColData[i];
+            }
+            CPLFree(panColData);
+        }
+        break;
+        case kealib::kea_att_float:
+        {
+            // allocate space for doubles
+            double *padfColData = (double*)VSIMalloc2(iLength, sizeof(double) );
+            if( padfColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied ints to doubles
+                for( int i = 0; i < iLength; i++ )
+                    padfColData[i] = pnData[i];
+            }
+
+            // do the ValuesIO as doubles
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, padfColData );
+            if( eVal != CE_None )
+            {
+                CPLFree(padfColData);
+                return eVal;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to ints
+                for( int i = 0; i < iLength; i++ )
+                    pnData[i] = padfColData[i];
+            }
+
+            CPLFree(padfColData);
+        }
+        break;
+        case kealib::kea_att_string:
+        {
+            // allocate space for string pointers
+            char **papszColData = (char**)VSIMalloc2(iLength, sizeof(char*));
+            if( papszColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+
+            if( eRWFlag == GF_Write )
+            {
+                // copy the application supplied ints to strings
+                for( int i = 0; i < iLength; i++ )
+                {
+                    osWorkingResult.Printf( "%d", pnData[i] );
+                    papszColData[i] = CPLStrdup(osWorkingResult);
+                }
+            }
+
+            // do the ValuesIO as strings
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, papszColData );
+            if( eVal != CE_None )
+            {
+                if( eRWFlag == GF_Write )
+                {
+                    for( int i = 0; i < iLength; i++ )
+                        CPLFree(papszColData[i]);
+                }
+                CPLFree(papszColData);
+                return eVal;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // copy them back to ints
+                for( int i = 0; i < iLength; i++ )
+                    pnData[i] = atol(papszColData[i]);
+            }
+
+            // either we allocated them for write, or they were allocated
+            // by ValuesIO on read
+            for( int i = 0; i < iLength; i++ )
+                CPLFree(papszColData[i]);
+
+            CPLFree(papszColData);
+        }
+        break;
+        default:
+            break;
+    }
+    return CE_None;
+}
+
+CPLErr KEARasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, char **papszStrList)
+{
+    /*if( ( eRWFlag == GF_Write ) && ( this->eAccess == GA_ReadOnly ) )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+            "Dataset not open in update mode");
+        return CE_Failure;
+    }*/
+
+    if( iField < 0 || iField >= (int) m_aoFields.size() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iField (%d) out of range.", iField );
+
+        return CE_Failure;
+    }
+
+    if( iStartRow < 0 || (iStartRow+iLength) > (int)m_poKEATable->getSize() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "iStartRow (%d) + iLength(%d) out of range.", iStartRow, iLength );
+
+        return CE_Failure;
+    }
+
+    switch( m_aoFields[iField].dataType )
+    {
+        case kealib::kea_att_bool:
+        case kealib::kea_att_int:
+        {
+            // allocate space for ints
+            int *panColData = (int*)VSIMalloc2(iLength, sizeof(int) );
+            if( panColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+            if( eRWFlag == GF_Write )
+            {
+                // convert user supplied strings to ints
+                for( int i = 0; i < iLength; i++ )
+                    panColData[i] = atol(papszStrList[i]);
+            }
+
+            // call values IO to read/write ints
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, panColData);
+            if( eVal != CE_None )
+            {
+                CPLFree(panColData);
+                return eVal;
+            }
+
+
+            if( eRWFlag == GF_Read )
+            {
+                // convert ints back to strings
+                for( int i = 0; i < iLength; i++ )
+                {
+                    osWorkingResult.Printf( "%d", panColData[i]);
+                    papszStrList[i] = CPLStrdup(osWorkingResult);
+                }
+            }
+            CPLFree(panColData);
+        }
+        break;
+        case kealib::kea_att_float:
+        {
+            // allocate space for doubles
+            double *padfColData = (double*)VSIMalloc2(iLength, sizeof(double) );
+            if( padfColData == NULL )
+            {
+                CPLError( CE_Failure, CPLE_OutOfMemory,
+                    "Memory Allocation failed in KEARasterAttributeTable::ValuesIO");
+                return CE_Failure;
+            }
+            
+            if( eRWFlag == GF_Write )
+            {
+                // convert user supplied strings to doubles
+                for( int i = 0; i < iLength; i++ )
+                    padfColData[i] = CPLAtof(papszStrList[i]);
+            }
+
+            // call value IO to read/write doubles
+            CPLErr eVal = ValuesIO(eRWFlag, iField, iStartRow, iLength, padfColData);
+            if( eVal != CE_None )
+            {
+                CPLFree(padfColData);
+                return eVal;
+            }
+
+            if( eRWFlag == GF_Read )
+            {
+                // convert doubles back to strings
+                for( int i = 0; i < iLength; i++ )
+                {
+                    osWorkingResult.Printf( "%.16g", padfColData[i]);
+                    papszStrList[i] = CPLStrdup(osWorkingResult);
+                }
+            }
+            CPLFree(padfColData);
+
+        }
+        break;
+        case kealib::kea_att_string:
+        {
+            try
+            {
+                if( eRWFlag == GF_Read )
+                {
+                    std::vector<std::string> aStrings;
+                    m_poKEATable->getStringFields(iStartRow, iLength, m_aoFields[iField].idx, &aStrings);
+                    for( std::vector<std::string>::size_type i = 0; i < aStrings.size(); i++ )
+                    {
+                        // Copy using CPLStrdup so user can call CPLFree
+                        papszStrList[i] = CPLStrdup(aStrings[i].c_str());
+                    }
+                }
+                else
+                {
+                    // need to convert to a vector first
+                    std::vector<std::string> aStrings;
+                    for( int i = 0; i < iLength; i++ )
+                    {
+                        aStrings.push_back(papszStrList[i]);
+                    }
+                    m_poKEATable->setStringFields(iStartRow, iLength, m_aoFields[iField].idx, &aStrings);
+                }
+            }
+            catch(kealib::KEAException &e)
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "Failed to read/write attribute table: %s", e.what() );
+                return CE_Failure;
+            }
+        }
+        break;
+        default:
+            break;
+    }
+    return CE_None;
+}
+
+int KEARasterAttributeTable::ChangesAreWrittenToFile()
+{
+    return TRUE;
+}
+
+void KEARasterAttributeTable::SetRowCount( int iCount )
+{
+    /*if( this->eAccess == GA_ReadOnly )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+            "Dataset not open in update mode");
+        return;
+    }*/
+
+    if( iCount > (int)m_poKEATable->getSize() )
+    {
+        m_poKEATable->addRows(iCount - m_poKEATable->getSize());
+    }
+    // can't shrink
+}
+
+CPLErr KEARasterAttributeTable::CreateColumn( const char *pszFieldName, 
+                                GDALRATFieldType eFieldType, 
+                                GDALRATFieldUsage eFieldUsage )
+{
+    /*if( this->eAccess == GA_ReadOnly )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+            "Dataset not open in update mode");
+        return CE_Failure;
+    }*/
+
+    std::string strUsage = "Generic";
+    switch(eFieldUsage)
+    {
+        case GFU_PixelCount:
+            strUsage = "PixelCount";
+            eFieldType = GFT_Real;
+            break;
+        case GFU_Name:
+            strUsage = "Name";
+            eFieldType = GFT_String;
+            break;
+        case GFU_Red:
+            strUsage = "Red";
+            eFieldType = GFT_Integer;
+            break;
+        case GFU_Green:
+            strUsage = "Green";
+            eFieldType = GFT_Integer;
+            break;
+        case GFU_Blue:
+            strUsage = "Blue";
+            eFieldType = GFT_Integer;
+            break;
+        case GFU_Alpha:
+            strUsage = "Alpha";
+            eFieldType = GFT_Integer;
+            break;
+        default:
+            // leave as "Generic"
+            break;
+    }
+
+    try
+    {
+        if(eFieldType == GFT_Integer)
+        {
+            m_poKEATable->addAttIntField(pszFieldName, 0, strUsage);
+        }
+        else if(eFieldType == GFT_Real)
+        {
+            m_poKEATable->addAttFloatField(pszFieldName, 0, strUsage);
+        }
+        else
+        {
+            m_poKEATable->addAttStringField(pszFieldName, "", strUsage);
+        }
+
+        // assume we can just grab this now
+        kealib::KEAATTField sKEAField = m_poKEATable->getField(pszFieldName);
+        m_aoFields.push_back(sKEAField);
+    }
+    catch(kealib::KEAException &e)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Failed to add column: %s", e.what() );
+        return CE_Failure;
+    }
+
+    return CE_None;
+}
+
+CPLXMLNode *KEARasterAttributeTable::Serialize() const
+{
+    if( ( GetRowCount() * GetColumnCount() ) > RAT_MAX_ELEM_FOR_CLONE )
+        return NULL;
+
+    return GDALRasterAttributeTable::Serialize();
+}
diff --git a/frmts/kea/kearat.h b/frmts/kea/kearat.h
new file mode 100644
index 0000000..47e5d8e
--- /dev/null
+++ b/frmts/kea/kearat.h
@@ -0,0 +1,84 @@
+/*
+ * $Id: kearat.h 28011 2014-11-26 13:47:09Z rouault $
+ *  kearat.h
+ *
+ *  Created by Pete Bunting on 01/08/2012.
+ *  Copyright 2012 LibKEA. All rights reserved.
+ *
+ *  This file is part of LibKEA.
+ *
+ *  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.
+ *
+ */
+
+#ifndef KEARAT_H
+#define KEARAT_H
+
+#include "gdal_priv.h"
+#include "gdal_rat.h"
+#include "keaband.h"
+
+class KEARasterAttributeTable : public GDALRasterAttributeTable
+{
+private:
+    kealib::KEAAttributeTable *m_poKEATable;
+    std::vector<kealib::KEAATTField> m_aoFields;
+    CPLString osWorkingResult;
+
+public:
+    KEARasterAttributeTable(kealib::KEAAttributeTable *poKEATable);
+    ~KEARasterAttributeTable();
+
+    GDALDefaultRasterAttributeTable *Clone() const;
+
+    virtual int           GetColumnCount() const;
+
+    virtual const char   *GetNameOfCol( int ) const;
+    virtual GDALRATFieldUsage GetUsageOfCol( int ) const;
+    virtual GDALRATFieldType GetTypeOfCol( int ) const;
+    
+    virtual int           GetColOfUsage( GDALRATFieldUsage ) const;
+
+    virtual int           GetRowCount() const;
+
+    virtual const char   *GetValueAsString( int iRow, int iField ) const;
+    virtual int           GetValueAsInt( int iRow, int iField ) const;
+    virtual double        GetValueAsDouble( int iRow, int iField ) const;
+
+    virtual void          SetValue( int iRow, int iField, const char *pszValue );
+    virtual void          SetValue( int iRow, int iField, double dfValue);
+    virtual void          SetValue( int iRow, int iField, int nValue );
+
+    virtual CPLErr        ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, double *pdfData);
+    virtual CPLErr        ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, int *pnData);
+    virtual CPLErr        ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, char **papszStrList);
+
+    virtual int           ChangesAreWrittenToFile();
+    virtual void          SetRowCount( int iCount );
+
+    virtual CPLErr        CreateColumn( const char *pszFieldName, 
+                                GDALRATFieldType eFieldType, 
+                                GDALRATFieldUsage eFieldUsage );
+
+    virtual CPLXMLNode   *Serialize() const;
+
+};
+
+#endif //KEARAT_H
diff --git a/frmts/kea/makefile.vc b/frmts/kea/makefile.vc
new file mode 100644
index 0000000..1a1ec45
--- /dev/null
+++ b/frmts/kea/makefile.vc
@@ -0,0 +1,26 @@
+
+OBJ	=	keaband.obj keacopy.obj keadataset.obj keadriver.obj keamaskband.obj keaoverview.obj kearat.obj
+
+EXTRAFLAGS 	= 	$(KEA_CFLAGS) 
+
+GDAL_ROOT	=	..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+default:	$(OBJ)
+	xcopy /D  /Y *.obj ..\o
+
+clean:
+	-del *.obj
+
+PLUGIN_DLL      =       gdal_KEA.dll
+
+plugin: $(PLUGIN_DLL)
+
+$(PLUGIN_DLL): $(OBJ)
+        link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) $(GDALLIB) $(KEA_LIB)
+        if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2
+
+plugin-install:
+        -mkdir $(PLUGINDIR)
+        $(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR)
diff --git a/frmts/kmlsuperoverlay/GNUmakefile b/frmts/kmlsuperoverlay/GNUmakefile
index 33a9fd5..8cccabd 100644
--- a/frmts/kmlsuperoverlay/GNUmakefile
+++ b/frmts/kmlsuperoverlay/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	kmlsuperoverlaydataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp
index 248b01d..c13ca09 100644
--- a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp
+++ b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.cpp
@@ -51,19 +51,22 @@ using namespace std;
 /************************************************************************/
 /*                           GenerateTiles()                            */
 /************************************************************************/
-void GenerateTiles(std::string filename, 
-                   CPL_UNUSED int zoom, int rxsize, 
-                   int rysize, CPL_UNUSED int ix, CPL_UNUSED int iy, 
-                   int rx, int ry, int dxsize, 
+void GenerateTiles(std::string filename,
+                   CPL_UNUSED int zoom,
+                   int rxsize,
+                   int rysize,
+                   CPL_UNUSED int ix,
+                   CPL_UNUSED int iy,
+                   int rx, int ry, int dxsize,
                    int dysize, int bands,
                    GDALDataset* poSrcDs,
-                   GDALDriver* poOutputTileDriver, 
+                   GDALDriver* poOutputTileDriver,
                    GDALDriver* poMemDriver,
                    bool isJpegDriver)
 {
     GDALDataset* poTmpDataset = NULL;
     GDALRasterBand* alphaBand = NULL;
-   
+
     GByte* pafScanline = new GByte[dxsize];
     bool* hadnoData = new bool[dxsize];
 
@@ -109,18 +112,12 @@ void GenerateTiles(std::string filename,
                 }
             }
 
-            GDALRasterBand* poBandtmp = NULL;
-            if (poTmpDataset)
-            {
-                poBandtmp = poTmpDataset->GetRasterBand(band);
-            }
-
             int yOffset = ry + row * rowOffset;
             bool bReadFailed = false;
             if (poBand)
             {
                 CPLErr errTest = 
-                    poBand->RasterIO( GF_Read, rx, yOffset, rxsize, rowOffset, pafScanline, dxsize, 1, GDT_Byte, 0, 0);
+                    poBand->RasterIO( GF_Read, rx, yOffset, rxsize, rowOffset, pafScanline, dxsize, 1, GDT_Byte, 0, 0, NULL);
 
                 if ( errTest == CE_Failure )
                 {
@@ -151,10 +148,11 @@ void GenerateTiles(std::string filename,
                 }
             }
 
-            if (poBandtmp && bReadFailed == false)
+            if (bReadFailed == false)
             {
+                GDALRasterBand* poBandtmp = poTmpDataset->GetRasterBand(band);
                 poBandtmp->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte, 
-                                    0, 0);
+                                    0, 0, NULL);
             }
         } 
 
@@ -176,7 +174,7 @@ void GenerateTiles(std::string filename,
                 }    
 
                 alphaBand->RasterIO(GF_Write, 0, row, dxsize, 1, pafScanline, dxsize, 1, GDT_Byte, 
-                                    0, 0);
+                                    0, 0, NULL);
             }
         }
     }
@@ -507,12 +505,15 @@ class KmlSuperOverlayDummyDataset: public GDALDataset
 };
 
 static
-GDALDataset *KmlSuperOverlayCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                                        CPL_UNUSED int bStrict, char ** papszOptions,
-                                        GDALProgressFunc pfnProgress, void * pProgressData)
+GDALDataset *KmlSuperOverlayCreateCopy( const char * pszFilename,
+                                        GDALDataset *poSrcDS,
+                                        CPL_UNUSED int bStrict,
+                                        char ** papszOptions,
+                                        GDALProgressFunc pfnProgress,
+                                        void * pProgressData)
 {
     bool isKmz = false;
-    
+
     if( pfnProgress == NULL )
         pfnProgress = GDALDummyProgress;
 
@@ -991,7 +992,8 @@ CPLErr KmlSuperOverlayReadDataset::GetGeoTransform( double * padfGeoTransform )
 /*                        KmlSuperOverlayRasterBand()                   */
 /************************************************************************/
 
-KmlSuperOverlayRasterBand::KmlSuperOverlayRasterBand(KmlSuperOverlayReadDataset* poDS, CPL_UNUSED int nBand)
+KmlSuperOverlayRasterBand::KmlSuperOverlayRasterBand(KmlSuperOverlayReadDataset* poDS,
+                                                     CPL_UNUSED int nBand)
 {
     nRasterXSize = poDS->nRasterXSize;
     nRasterYSize = poDS->nRasterYSize;
@@ -1014,6 +1016,10 @@ CPLErr KmlSuperOverlayRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, vo
         nXSize = nRasterXSize - nXOff;
     if( nYOff + nYSize > nRasterYSize )
         nYSize = nRasterYSize - nYOff;
+    
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     return IRasterIO( GF_Read,
                       nXOff,
                       nYOff,
@@ -1024,7 +1030,7 @@ CPLErr KmlSuperOverlayRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, vo
                       nYSize,
                       eDataType,
                       1,
-                      nBlockXSize );
+                      nBlockXSize, &sExtraArg );
 }
 
 /************************************************************************/
@@ -1044,14 +1050,16 @@ CPLErr KmlSuperOverlayRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                              int nXOff, int nYOff, int nXSize, int nYSize,
                                              void * pData, int nBufXSize, int nBufYSize,
                                              GDALDataType eBufType,
-                                             int nPixelSpace, int nLineSpace )
+                                             GSpacing nPixelSpace,
+                                             GSpacing nLineSpace,
+                                             GDALRasterIOExtraArg* psExtraArg )
 {
     KmlSuperOverlayReadDataset* poGDS = (KmlSuperOverlayReadDataset* )poDS;
 
     return poGDS->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                             pData, nBufXSize, nBufYSize, eBufType,
                             1, &nBand,
-                            nPixelSpace, nLineSpace, 0 );
+                            nPixelSpace, nLineSpace, 0, psExtraArg );
 }
 
 /************************************************************************/
@@ -1122,7 +1130,9 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
 {
     if( eRWFlag == GF_Write )
         return CE_Failure;
@@ -1136,7 +1146,7 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
                                     pData, nBufXSize, nBufYSize,
                                     eBufType, 
                                     nBandCount, panBandMap,
-                                    nPixelSpace, nLineSpace, nBandSpace);
+                                    nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
     
     double dfXOff = 1.0 * nXOff / nFactor;
     double dfYOff = 1.0 * nYOff / nFactor;
@@ -1383,7 +1393,8 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
                                              nReqYSize,
                                              pData, nBufXSize, nBufYSize, eBufType,
                                              nBandCount, panBandMap,
-                                             nPixelSpace, nLineSpace, nBandSpace );
+                                             nPixelSpace, nLineSpace, nBandSpace,
+                                             psExtraArg);
 
             for(i=0; i < (int)aosImages.size(); i++)
             {
@@ -1396,6 +1407,9 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
         }
     }
 
+    GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+    void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
     for(int iBandIdx = 0; iBandIdx < nBandCount; iBandIdx++ )
     {
         int nBand = panBandMap[iBandIdx];
@@ -1423,6 +1437,13 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
         if( nReqYOff + nReqYSize > poDSIcon->GetRasterYSize() )
             nReqYSize = poDSIcon->GetRasterYSize() - nReqYOff;
 
+        psExtraArg->pfnProgress = GDALScaledProgress;
+        psExtraArg->pProgressData = 
+            GDALCreateScaledProgress( 1.0 * iBandIdx / nBandCount,
+                                      1.0 * (iBandIdx + 1) / nBandCount,
+                                      pfnProgressGlobal,
+                                      pProgressDataGlobal );
+
         poDSIcon->GetRasterBand(nIconBand)->RasterIO( eRWFlag,
                                                       nReqXOff,
                                                       nReqYOff,
@@ -1430,9 +1451,15 @@ CPLErr KmlSuperOverlayReadDataset::IRasterIO( GDALRWFlag eRWFlag,
                                                       nReqYSize,
                                                       ((GByte*) pData) + nBandSpace * iBandIdx,
                                                       nBufXSize, nBufYSize, eBufType,
-                                                      nPixelSpace, nLineSpace );
+                                                      nPixelSpace, nLineSpace,
+                                                      psExtraArg);
+
+        GDALDestroyScaledProgress( psExtraArg->pProgressData );
     }
 
+    psExtraArg->pfnProgress = pfnProgressGlobal;
+    psExtraArg->pProgressData = pProgressDataGlobal;
+
     return CE_None;
 
 }
@@ -1955,7 +1982,7 @@ CPLErr KmlSingleDocRasterRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                                     0, 0, nXSize, nYSize,
                                                     pImage,
                                                     nXSize, nYSize,
-                                                    GDT_Byte, 1, nBlockXSize);
+                                                    GDT_Byte, 1, nBlockXSize, NULL);
 
             /* Expand color table */
             if( eErr == CE_None && poColorTable != NULL )
@@ -1989,7 +2016,7 @@ CPLErr KmlSingleDocRasterRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                                 0, 0, nXSize, nYSize,
                                                 pImage,
                                                 nXSize, nYSize,
-                                                GDT_Byte, 1, nBlockXSize);
+                                                GDT_Byte, 1, nBlockXSize, NULL);
     }
     else if( nBand == 4 && poImageDS->GetRasterCount() == 3 )
     {
@@ -2447,6 +2474,7 @@ void GDALRegister_KMLSUPEROVERLAY()
         poDriver = new GDALDriver();
       
         poDriver->SetDescription( "KMLSUPEROVERLAY" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Kml Super Overlay" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
@@ -2480,4 +2508,3 @@ void GDALRegister_KMLSUPEROVERLAY()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.h b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.h
index 48b1ef3..724c8b8 100644
--- a/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.h
+++ b/frmts/kmlsuperoverlay/kmlsuperoverlaydataset.h
@@ -96,7 +96,9 @@ class KmlSuperOverlayReadDataset : public GDALDataset
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace);
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
 };
 
 /************************************************************************/
@@ -112,7 +114,8 @@ class KmlSuperOverlayRasterBand: public GDALRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
     virtual GDALColorInterp GetColorInterpretation();
 
     virtual int GetOverviewCount();
diff --git a/frmts/l1b/GNUmakefile b/frmts/l1b/GNUmakefile
index 8db27cb..df52ea6 100644
--- a/frmts/l1b/GNUmakefile
+++ b/frmts/l1b/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	l1bdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/l1b/frmt_l1b.html b/frmts/l1b/frmt_l1b.html
index ae201db..95da65d 100644
--- a/frmts/l1b/frmt_l1b.html
+++ b/frmts/l1b/frmt_l1b.html
@@ -122,6 +122,15 @@ NOAA >=15 datasets advertize a L1B_CLOUDS:"l1b_dataset_name"
 subdataset that contains a band of same dimensions as bands of the main L1B
 dataset. The values of each pixel are 0 = unknown; 1 = clear; 2 = cloudy; 3 = partly cloudy.<p>
 
+<h2>Nodata mask</h2>
+
+(Starting with GDAL 2.0)<p>
+
+NOAA >=15 datasets that report in their header to have missing scan lines
+will expose a per-dataset mask band (following
+<a href="https://trac.osgeo.org/gdal/wiki/rfc15_nodatabitmask">RFC 15: Band Masks</a>)
+to indicate such scan lines. 
+
 <h2>See Also:</h2>
 
 <ul>
diff --git a/frmts/l1b/l1bdataset.cpp b/frmts/l1b/l1bdataset.cpp
index 1633e04..326b7c7 100644
--- a/frmts/l1b/l1bdataset.cpp
+++ b/frmts/l1b/l1bdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: l1bdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: l1bdataset.cpp 28925 2015-04-16 21:51:54Z rouault $
  *
  * Project:  NOAA Polar Orbiter Level 1b Dataset Reader (AVHRR)
  * Purpose:  Can read NOAA-9(F)-NOAA-17(M) AVHRR datasets
@@ -36,8 +36,9 @@
 
 #include "gdal_pam.h"
 #include "cpl_string.h"
+#include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: l1bdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: l1bdataset.cpp 28925 2015-04-16 21:51:54Z rouault $");
 
 CPL_C_START
 void    GDALRegister_L1B(void);
@@ -57,6 +58,7 @@ typedef enum {          // Spacecrafts:
     NOAAB,      // NOAA-B
     NOAA7,      // NOAA-7(C)
     NOAA8,      // NOAA-8(E)
+    NOAA9_UNKNOWN, // Some NOAA-18 and NOAA-19 HRPT are recognized like that...
     NOAA9,      // NOAA-9(F)
     NOAA10,     // NOAA-10(G)
     NOAA11,     // NOAA-11(H)
@@ -156,14 +158,25 @@ static const char *apszBandDesc[] =
 #define L1B_NOAA9_HDR_REC_PROD_OFF  1   // Data type offset
 #define L1B_NOAA9_HDR_REC_DSTAT_OFF 34  // DACS status offset
 
+/* See http://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/html/c8/sec83132-2.htm */
 #define L1B_NOAA15_HDR_REC_SIZE     992 // Length of header record
                                         // filled with the data
 #define L1B_NOAA15_HDR_REC_SITE_OFF 0   // Dataset creation site ID offset
+#define L1B_NOAA15_HDR_REC_FORMAT_VERSION_OFF      4  // NOAA Level 1b Format Version Number
+#define L1B_NOAA15_HDR_REC_FORMAT_VERSION_YEAR_OFF 6  // Level 1b Format Version Year (e.g., 1999)
+#define L1B_NOAA15_HDR_REC_FORMAT_VERSION_DAY_OFF  8  // Level 1b Format Version Day of Year (e.g., 365)
+#define L1B_NOAA15_HDR_REC_LOGICAL_REC_LENGTH_OFF  10 // Logical Record Length of source Level 1b data set prior to processing
+#define L1B_NOAA15_HDR_REC_BLOCK_SIZE_OFF          12 // Block Size of source Level 1b data set prior to processing
+#define L1B_NOAA15_HDR_REC_HDR_REC_COUNT_OFF       14 // Count of Header Records in this Data Set
 #define L1B_NOAA15_HDR_REC_NAME_OFF 22  // Dataset name
 #define L1B_NOAA15_HDR_REC_ID_OFF   72  // Spacecraft ID offset
 #define L1B_NOAA15_HDR_REC_PROD_OFF 76  // Data type offset
 #define L1B_NOAA15_HDR_REC_STAT_OFF 116 // Instrument status offset
+#define L1B_NOAA15_HDR_REC_DATA_RECORD_COUNT_OFF 128
+#define L1B_NOAA15_HDR_REC_CALIBRATED_SCANLINE_COUNT_OFF 130
+#define L1B_NOAA15_HDR_REC_MISSING_SCANLINE_COUNT_OFF 132
 #define L1B_NOAA15_HDR_REC_SRC_OFF  154 // Receiving station name offset
+#define L1B_NOAA15_HDR_REC_ELLIPSOID_OFF 328
 
 /* This only apply if L1B_HIGH_GCP_DENSITY is explicitely set to NO */
 /* otherwise we will report more GCPs */
@@ -230,6 +243,7 @@ class L1BCloudsRasterBand;
 class L1BDataset : public GDALPamDataset
 {
     friend class L1BRasterBand;
+    friend class L1BMaskBand;
     friend class L1BGeolocDataset;
     friend class L1BGeolocRasterBand;
     friend class L1BSolarZenithAnglesDataset;
@@ -263,6 +277,7 @@ class L1BDataset : public GDALPamDataset
     int         nRecordDataEnd;
     int         nDataStartOffset;
     int         nRecordSize;
+    int         nRecordSizeFromHeader;
     GUInt32     iInstrumentStatus;
     GUInt32     iChannelsMask;
 
@@ -273,10 +288,15 @@ class L1BDataset : public GDALPamDataset
     int         bFetchGeolocation;
     int         bGuessDataFormat;
 
+    int         bByteSwap;
+    
+    int             bExposeMaskBand;
+    GDALRasterBand* poMaskBand;
+
     void        ProcessRecordHeaders();
     int         FetchGCPs( GDAL_GCP *, GByte *, int );
     void        FetchNOAA9TimeCode(TimeCode *, const GByte *, int *);
-    void        FetchNOAA15TimeCode(TimeCode *, const GUInt16 *, int *);
+    void        FetchNOAA15TimeCode(TimeCode *, const GByte *, int *);
     void        FetchTimeCode( TimeCode *psTime, const void *pRecordHeader,
                                int *peLocationIndicator );
     CPLErr      ProcessDatasetHeader(const char* pszFilename);
@@ -284,7 +304,14 @@ class L1BDataset : public GDALPamDataset
     
     void        FetchMetadata();
     void        FetchMetadataNOAA15();
-    
+
+    vsi_l_offset GetLineOffset(int nBlockYOff);
+
+    GUInt16     GetUInt16(const void* pabyData);
+    GInt16      GetInt16(const void* pabyData);
+    GUInt32     GetUInt32(const void* pabyData);
+    GInt32      GetInt32(const void* pabyData);
+
     static L1BFileFormat  DetectFormat( const char* pszFilename,
                               const GByte* pabyHeader, int nHeaderBytes );
 
@@ -317,8 +344,68 @@ class L1BRasterBand : public GDALPamRasterBand
     
 //    virtual double GetNoDataValue( int *pbSuccess = NULL );
     virtual CPLErr IReadBlock( int, int, void * );
+    virtual GDALRasterBand *GetMaskBand();
+    virtual int             GetMaskFlags();
 };
 
+/************************************************************************/
+/* ==================================================================== */
+/*                            L1BMaskBand                               */
+/* ==================================================================== */
+/************************************************************************/
+
+class L1BMaskBand: public GDALPamRasterBand
+{
+    friend class L1BDataset;
+
+  public:
+
+                L1BMaskBand( L1BDataset * );
+    
+    virtual CPLErr IReadBlock( int, int, void * );
+};
+
+/************************************************************************/
+/*                            L1BMaskBand()                             */
+/************************************************************************/
+
+L1BMaskBand::L1BMaskBand( L1BDataset *poDS )
+{
+    CPLAssert(poDS->eL1BFormat == L1B_NOAA15 ||
+              poDS->eL1BFormat == L1B_NOAA15_NOHDR);
+
+    this->poDS = poDS;
+    eDataType = GDT_Byte;
+
+    nRasterXSize = poDS->GetRasterXSize();
+    nRasterYSize = poDS->GetRasterYSize();
+    nBlockXSize = poDS->GetRasterXSize();
+    nBlockYSize = 1;
+}
+
+/************************************************************************/
+/*                             IReadBlock()                             */
+/************************************************************************/
+
+CPLErr L1BMaskBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                int nBlockYOff,
+                                void * pImage )
+{
+    L1BDataset  *poGDS = (L1BDataset *) poDS;
+
+    VSIFSeekL( poGDS->fp, poGDS->GetLineOffset(nBlockYOff) + 24, SEEK_SET );
+
+    GByte abyData[4];
+    VSIFReadL( abyData, 1, 4, poGDS->fp );
+    GUInt32 n32 = poGDS->GetUInt32(abyData);
+
+    if( (n32 >> 31) != 0 ) /* fatal flag */
+        memset(pImage, 0, nBlockXSize);
+    else
+        memset(pImage, 255, nBlockXSize);
+
+    return CE_None;
+}
 
 /************************************************************************/
 /*                           L1BRasterBand()                            */
@@ -336,10 +423,35 @@ L1BRasterBand::L1BRasterBand( L1BDataset *poDS, int nBand )
 }
 
 /************************************************************************/
+/*                           GetMaskBand()                              */
+/************************************************************************/
+
+GDALRasterBand *L1BRasterBand::GetMaskBand()
+{
+    L1BDataset  *poGDS = (L1BDataset *) poDS;
+    if( poGDS->poMaskBand )
+        return poGDS->poMaskBand;
+    return GDALPamRasterBand::GetMaskBand();
+}
+
+/************************************************************************/
+/*                           GetMaskFlags()                             */
+/************************************************************************/
+
+int L1BRasterBand::GetMaskFlags()
+{
+    L1BDataset  *poGDS = (L1BDataset *) poDS;
+    if( poGDS->poMaskBand )
+        return GMF_PER_DATASET;
+    return GDALPamRasterBand::GetMaskFlags();
+}
+
+/************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr L1BRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr L1BRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
 {
     L1BDataset  *poGDS = (L1BDataset *) poDS;
@@ -347,11 +459,7 @@ CPLErr L1BRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-    int iDataOffset = (poGDS->eLocationIndicator == DESCEND) ?
-        poGDS->nDataStartOffset + nBlockYOff * poGDS->nRecordSize :
-        poGDS->nDataStartOffset +
-            (nRasterYSize - nBlockYOff - 1) * poGDS->nRecordSize;
-    VSIFSeekL( poGDS->fp, iDataOffset, SEEK_SET );
+    VSIFSeekL( poGDS->fp, poGDS->GetLineOffset(nBlockYOff), SEEK_SET );
 
 /* -------------------------------------------------------------------- */
 /*      Read data into the buffer.                                      */
@@ -372,7 +480,7 @@ CPLErr L1BRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
                 for(i = poGDS->nRecordDataStart / (int)sizeof(iRawScan[0]);
                     i < poGDS->nRecordDataEnd / (int)sizeof(iRawScan[0]); i++)
                 {
-                    GUInt32 iWord1 = CPL_MSBWORD32( iRawScan[i] );
+                    GUInt32 iWord1 = poGDS->GetUInt32( &iRawScan[i] );
                     GUInt32 iWord2 = iWord1 & 0x3FF00000;
 
                     iScan[j++] = (GUInt16) (iWord2 >> 20);
@@ -393,7 +501,7 @@ CPLErr L1BRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
                                              * poGDS->nBands * sizeof(GUInt16));
                 for (i = 0; i < poGDS->GetRasterXSize() * poGDS->nBands; i++)
                 {
-                    iScan[i] = CPL_MSBWORD16( iRawScan[poGDS->nRecordDataStart
+                    iScan[i] = poGDS->GetUInt16( &iRawScan[poGDS->nRecordDataStart
                         / (int)sizeof(iRawScan[0]) + i] );
                 }
                 CPLFree(iRawScan);
@@ -469,12 +577,16 @@ L1BDataset::L1BDataset( L1BFileFormat eL1BFormat )
     nRecordDataEnd = 0;
     nDataStartOffset = 0;
     nRecordSize = 0;
+    nRecordSizeFromHeader = 0;
     iInstrumentStatus = 0;
     iChannelsMask = 0;
     pszGCPProjection = CPLStrdup( "GEOGCS[\"WGS 72\",DATUM[\"WGS_1972\",SPHEROID[\"WGS 72\",6378135,298.26,AUTHORITY[\"EPSG\",7043]],TOWGS84[0,0,4.5,0,0,0.554,0.2263],AUTHORITY[\"EPSG\",6322]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",8901]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",9108]],AUTHORITY[\"EPSG\",4322]]" );
     fp = NULL;
     bFetchGeolocation = FALSE;
     bGuessDataFormat = FALSE;
+    bByteSwap = CPL_IS_LSB; /* L1B is normally big-endian ordered, so byte-swap on little-endian CPU */
+    bExposeMaskBand = FALSE;
+    poMaskBand = NULL;
 }
 
 /************************************************************************/
@@ -495,6 +607,19 @@ L1BDataset::~L1BDataset()
         CPLFree( pszGCPProjection );
     if( fp != NULL )
         VSIFCloseL( fp );
+    delete poMaskBand;
+}
+
+/************************************************************************/
+/*                          GetLineOffset()                             */
+/************************************************************************/
+
+vsi_l_offset L1BDataset::GetLineOffset(int nBlockYOff)
+{
+    return (eLocationIndicator == DESCEND) ?
+        nDataStartOffset + (vsi_l_offset)nBlockYOff * nRecordSize :
+        nDataStartOffset +
+            (vsi_l_offset)(nRasterYSize - nBlockYOff - 1) * nRecordSize;
 }
 
 /************************************************************************/
@@ -530,6 +655,47 @@ const GDAL_GCP *L1BDataset::GetGCPs()
 }
 
 /************************************************************************/
+/*      Byte swapping helpers                                           */
+/************************************************************************/
+
+GUInt16 L1BDataset::GetUInt16(const void* pabyData)
+{
+    GUInt16 iTemp;
+    memcpy(&iTemp, pabyData, 2);
+    if( bByteSwap )
+        return CPL_SWAP16(iTemp);
+    return iTemp;
+}
+
+GInt16 L1BDataset::GetInt16(const void* pabyData)
+{
+    GInt16 iTemp;
+    memcpy(&iTemp, pabyData, 2);
+    if( bByteSwap )
+        return CPL_SWAP16(iTemp);
+    return iTemp;
+}
+
+GUInt32 L1BDataset::GetUInt32(const void* pabyData)
+{
+    GUInt32 lTemp;
+    memcpy(&lTemp, pabyData, 4);
+    if( bByteSwap )
+        return CPL_SWAP32(lTemp);
+    return lTemp;
+}
+
+GInt32 L1BDataset::GetInt32(const void* pabyData)
+{
+    GInt32 lTemp;
+    memcpy(&lTemp, pabyData, 4);
+    if( bByteSwap )
+        return CPL_SWAP32(lTemp);
+    return lTemp;
+
+}
+
+/************************************************************************/
 /*      Fetch timecode from the record header (NOAA9-NOAA14 version)    */
 /************************************************************************/
 
@@ -560,24 +726,17 @@ void L1BDataset::FetchNOAA9TimeCode( TimeCode *psTime,
 /************************************************************************/
 
 void L1BDataset::FetchNOAA15TimeCode( TimeCode *psTime,
-                                      const GUInt16 *piRecordHeader,
+                                      const GByte *pabyRecordHeader,
                                       int *peLocationIndicator )
 {
-    GUInt16 iTemp;
-    GUInt32 lTemp;
-
-    iTemp = piRecordHeader[1];
-    psTime->SetYear(CPL_MSBWORD16(iTemp));
-    iTemp = piRecordHeader[2];
-    psTime->SetDay(CPL_MSBWORD16(iTemp));
-    lTemp = (GUInt32)CPL_MSBWORD16(piRecordHeader[4]) << 16 |
-        (GUInt32)CPL_MSBWORD16(piRecordHeader[5]);
-    psTime->SetMillisecond(lTemp);
+    psTime->SetYear(GetUInt16(pabyRecordHeader + 2));
+    psTime->SetDay(GetUInt16(pabyRecordHeader + 4));
+    psTime->SetMillisecond(GetUInt32(pabyRecordHeader+8));
     if ( peLocationIndicator )
     {
         // FIXME: hemisphere
         *peLocationIndicator =
-            ((CPL_MSBWORD16(piRecordHeader[6]) & 0x8000) == 0) ? ASCEND : DESCEND;
+            ((GetUInt16(pabyRecordHeader + 12) & 0x8000) == 0) ? ASCEND : DESCEND;
     }
 }
 /************************************************************************/
@@ -595,7 +754,7 @@ void L1BDataset::FetchTimeCode( TimeCode *psTime,
     }
     else
     {
-        FetchNOAA15TimeCode( psTime, (const GUInt16 *) pRecordHeader,
+        FetchNOAA15TimeCode( psTime, (const GByte *) pRecordHeader,
                              peLocationIndicator );
     }
 }
@@ -620,7 +779,7 @@ int L1BDataset::FetchGCPs( GDAL_GCP *pasGCPListRow,
         // Number of good GCPs may be smaller than the total amount of points.
         nGCPs = (*(pabyRecordHeader + iGCPCodeOffset) < nGCPsPerLine) ?
             *(pabyRecordHeader + iGCPCodeOffset) : nGCPsPerLine;
-#ifdef DEBUG
+#ifdef DEBUG_VERBOSE
         CPLDebug( "L1B", "iGCPCodeOffset=%d, nGCPsPerLine=%d, nGoodGCPs=%d",
                   iGCPCodeOffset, nGCPsPerLine, nGCPs );
 #endif
@@ -635,9 +794,9 @@ int L1BDataset::FetchGCPs( GDAL_GCP *pasGCPListRow,
     {
         if ( eSpacecraftID <= NOAA14 )
         {
-            GInt16  nRawY = CPL_MSBWORD16( *(GInt16*)pabyRecordHeader );
+            GInt16  nRawY = GetInt16( pabyRecordHeader );
             pabyRecordHeader += sizeof(GInt16);
-            GInt16  nRawX = CPL_MSBWORD16( *(GInt16*)pabyRecordHeader );
+            GInt16  nRawX = GetInt16( pabyRecordHeader );
             pabyRecordHeader += sizeof(GInt16);
 
             pasGCPListRow[nGCPCountRow].dfGCPY = nRawY / L1B_NOAA9_GCP_SCALE;
@@ -645,9 +804,9 @@ int L1BDataset::FetchGCPs( GDAL_GCP *pasGCPListRow,
         }
         else
         {
-            GInt32  nRawY = CPL_MSBWORD32( *(GInt32*)pabyRecordHeader );
+            GInt32  nRawY = GetInt32( pabyRecordHeader );
             pabyRecordHeader += sizeof(GInt32);
-            GInt32  nRawX = CPL_MSBWORD32( *(GInt32*)pabyRecordHeader );
+            GInt32  nRawX = GetInt32( pabyRecordHeader );
             pabyRecordHeader += sizeof(GInt32);
 
             pasGCPListRow[nGCPCountRow].dfGCPY = nRawY / L1B_NOAA15_GCP_SCALE;
@@ -876,17 +1035,11 @@ void L1BDataset::FetchMetadata()
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-        int iDataOffset = (eLocationIndicator == DESCEND) ?
-            nDataStartOffset + nBlockYOff * nRecordSize :
-            nDataStartOffset +
-                (nRasterYSize - nBlockYOff - 1) * nRecordSize;
-        VSIFSeekL( fp, iDataOffset, SEEK_SET );
+        VSIFSeekL( fp, GetLineOffset(nBlockYOff), SEEK_SET );
 
         VSIFReadL( pabyRecordHeader, 1, nRecordDataStart, fp );
 
-        GUInt16 nScanlineNumber;
-        memcpy(&nScanlineNumber, pabyRecordHeader, 2);
-        CPL_MSBPTR16(&nScanlineNumber);
+        GUInt16 nScanlineNumber = GetUInt16(pabyRecordHeader);
 
         TimeCode timeCode;
         FetchTimeCode( &timeCode, pabyRecordHeader, NULL );
@@ -929,8 +1082,7 @@ void L1BDataset::FetchMetadata()
         GInt32 i32;
         for(int i=0;i<10;i++)
         {
-            memcpy(&i32, pabyRecordHeader + 12 + 4 *i, 4);
-            CPL_MSBPTR32(&i32);
+            i32 = GetInt32(pabyRecordHeader + 12 + 4 *i);
             /* Scales : http://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/podug/html/c3/sec3-3.htm */
             if( (i % 2) == 0 )
                 VSIFPrintfL(fpCSV, "%f,", i32 / pow(2.0, 30.0));
@@ -1030,24 +1182,19 @@ void L1BDataset::FetchMetadataNOAA15()
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-        int iDataOffset = (eLocationIndicator == DESCEND) ?
-            nDataStartOffset + nBlockYOff * nRecordSize :
-            nDataStartOffset +
-                (nRasterYSize - nBlockYOff - 1) * nRecordSize;
-        VSIFSeekL( fp, iDataOffset, SEEK_SET );
+        VSIFSeekL( fp, GetLineOffset(nBlockYOff), SEEK_SET );
 
         VSIFReadL( pabyRecordHeader, 1, nRecordDataStart, fp );
 
-        GUInt16 nScanlineNumber;
-        memcpy(&nScanlineNumber, pabyRecordHeader, 2);
-        CPL_MSBPTR16(&nScanlineNumber);
+        GUInt16 nScanlineNumber = GetUInt16(pabyRecordHeader);
 
         TimeCode timeCode;
         FetchTimeCode( &timeCode, pabyRecordHeader, NULL );
 
         /* Clock drift delta */
-        memcpy(&i16, pabyRecordHeader + 6, 2);
-        CPL_MSBPTR16(&i16);
+        i16 = GetInt16(pabyRecordHeader + 6);
+        /* Scanline bit field */
+        n16 = GetInt16(pabyRecordHeader + 12);
 
         VSIFPrintfL(fpCSV,
                     "%d,%d,%d,%d,%d,%d,%d,%d,%d,",
@@ -1057,12 +1204,11 @@ void L1BDataset::FetchMetadataNOAA15()
                     (int)timeCode.GetDay(),
                     (int)timeCode.GetMillisecond(),
                     i16,
-                    (pabyRecordHeader[12] >> 7) & 1,
-                    (pabyRecordHeader[12] >> 6) & 1,
-                    (pabyRecordHeader[12] >> 0) & 3);
+                    (n16 >> 15) & 1,
+                    (n16 >> 14) & 1,
+                    (n16) & 3);
 
-        memcpy(&n32, pabyRecordHeader + 24, 4);
-        CPL_MSBPTR32(&n32);
+        n32 = GetUInt32(pabyRecordHeader + 24);
         VSIFPrintfL(fpCSV,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,",
                     (n32 >> 31) & 1,
                     (n32 >> 30) & 1,
@@ -1083,8 +1229,7 @@ void L1BDataset::FetchMetadataNOAA15()
                     (n32 >> 1) & 1,
                     (n32 >> 0) & 1);
 
-        memcpy(&n32, pabyRecordHeader + 28, 4);
-        CPL_MSBPTR32(&n32);
+        n32 = GetUInt32(pabyRecordHeader + 28);
         VSIFPrintfL(fpCSV,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,",
                     (n32 >> 23) & 1,
                     (n32 >> 22) & 1,
@@ -1102,8 +1247,7 @@ void L1BDataset::FetchMetadataNOAA15()
 
         for(i=0;i<3;i++)
         {
-            memcpy(&n16, pabyRecordHeader + 32 + 2 * i, 2);
-            CPL_MSBPTR16(&n16);
+            n16 = GetUInt16(pabyRecordHeader + 32 + 2 * i);
             VSIFPrintfL(fpCSV,"%d,%d,%d,%d,%d,%d,",
                     (n32 >> 7) & 1,
                     (n32 >> 6) & 1,
@@ -1114,8 +1258,7 @@ void L1BDataset::FetchMetadataNOAA15()
         }
 
         /* Bit errors */
-        memcpy(&n16, pabyRecordHeader + 38, 2);
-        CPL_MSBPTR16(&n16);
+        n16 = GetUInt16(pabyRecordHeader + 38);
         VSIFPrintfL(fpCSV, "%d,", n16);
 
         int nOffset = 48;
@@ -1123,38 +1266,31 @@ void L1BDataset::FetchMetadataNOAA15()
         {
             for(j=0;j<3;j++)
             {
-                memcpy(&i32, pabyRecordHeader + nOffset, 4);
-                CPL_MSBPTR32(&i32);
+                i32 = GetInt32(pabyRecordHeader + nOffset);
                 nOffset += 4;
                 VSIFPrintfL(fpCSV, "%f,", i32 / pow(10.0, 7.0));
-                memcpy(&i32, pabyRecordHeader + nOffset, 4);
-                CPL_MSBPTR32(&i32);
+                i32 = GetInt32(pabyRecordHeader + nOffset);
                 nOffset += 4;
                 VSIFPrintfL(fpCSV, "%f,", i32 / pow(10.0, 6.0));
-                memcpy(&i32, pabyRecordHeader + nOffset, 4);
-                CPL_MSBPTR32(&i32);
+                i32 = GetInt32(pabyRecordHeader + nOffset);
                 nOffset += 4;
                 VSIFPrintfL(fpCSV, "%f,", i32 / pow(10.0, 7.0));
-                memcpy(&i32, pabyRecordHeader + nOffset, 4);
-                CPL_MSBPTR32(&i32);
+                i32 = GetInt32(pabyRecordHeader + nOffset);
                 nOffset += 4;
                 VSIFPrintfL(fpCSV, "%f,", i32 / pow(10.0, 6.0));
-                memcpy(&i32, pabyRecordHeader + nOffset, 4);
-                CPL_MSBPTR32(&i32);
+                i32 = GetInt32(pabyRecordHeader + nOffset);
                 nOffset += 4;
                 VSIFPrintfL(fpCSV, "%d,", i32);
             }
         }
         for(i=0;i<18;i++)
         {
-            memcpy(&i32, pabyRecordHeader + nOffset, 4);
-            CPL_MSBPTR32(&i32);
+            i32 = GetInt32(pabyRecordHeader + nOffset);
             nOffset += 4;
             VSIFPrintfL(fpCSV, "%f,", i32 / pow(10.0, 6.0));
         }
 
-        memcpy(&n32, pabyRecordHeader + 312, 4);
-        CPL_MSBPTR32(&n32);
+        n32 = GetUInt32(pabyRecordHeader + 312);
         VSIFPrintfL(fpCSV,"%d,%d,%d,%d,%d,",
                     (n32 >> 16) & 1,
                     (n32 >> 12) & 15,
@@ -1162,19 +1298,16 @@ void L1BDataset::FetchMetadataNOAA15()
                     (n32 >> 4) & 15,
                     (n32 >> 0) & 15);
 
-        memcpy(&n32, pabyRecordHeader + 316, 4);
-        CPL_MSBPTR32(&n32);
+        n32 = GetUInt32(pabyRecordHeader + 316);
         VSIFPrintfL(fpCSV,"%d,",n32);
 
         for(i=0;i<3;i++)
         {
-            memcpy(&i16, pabyRecordHeader + 320 + 2 * i, 2);
-            CPL_MSBPTR16(&i16);
+            i16 = GetUInt16(pabyRecordHeader + 320 + 2 * i);
             VSIFPrintfL(fpCSV,"%f,",i16 / pow(10.0,3.0));
         }
 
-        memcpy(&n16, pabyRecordHeader + 326, 2);
-        CPL_MSBPTR16(&n16);
+        n16 = GetUInt16(pabyRecordHeader + 326);
         VSIFPrintfL(fpCSV,"%f",n16 / pow(10.0,1.0));
 
         VSIFPrintfL(fpCSV, "\n");
@@ -1367,11 +1500,12 @@ CPLErr L1BDataset::ProcessDatasetHeader(const char* pszFilename)
                 eSpacecraftID = NOAA14;
                 break;
             default:
-#ifdef DEBUG
-                CPLDebug( "L1B", "Unknown spacecraft ID \"%d\".",
+                CPLError( CE_Warning, CPLE_AppDefined,
+                          "Unknown spacecraft ID \"%d\".",
                           abyRecHeader[L1B_NOAA9_HDR_REC_ID_OFF] );
-#endif
-                return CE_Failure;
+
+                eSpacecraftID = NOAA9_UNKNOWN;
+                break;
         }
 
         // Determine the product data type
@@ -1503,10 +1637,69 @@ CPLErr L1BDataset::ProcessDatasetHeader(const char* pszFilename)
         else
              eProcCenter = UNKNOWN_CENTER;
 
+        int nFormatVersionYear, nFormatVersionDayOfYear, nHeaderRecCount;
+
+        /* Some products from NOAA-18 and NOAA-19 coming from 'ess' processing station */
+        /* have little-endian ordering. Try to detect it with some consistency checks */
+        for(int i=0;i<=2;i++)
+        {
+            nFormatVersionYear = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_FORMAT_VERSION_YEAR_OFF);
+            nFormatVersionDayOfYear = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_FORMAT_VERSION_DAY_OFF);
+            nHeaderRecCount = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_HDR_REC_COUNT_OFF);
+            if( i == 2 )
+                break;
+            if( !(nFormatVersionYear >= 1980 && nFormatVersionYear <= 2100) &&
+                !(nFormatVersionDayOfYear <= 366) &&
+                !(nHeaderRecCount == 1) )
+            {
+                if( i == 0 )
+                    CPLDebug("L1B", "Trying little-endian ordering");
+                else
+                    CPLDebug("L1B", "Not completely convincing... Returning to big-endian order");
+                bByteSwap = !bByteSwap;
+            }
+            else
+                break;
+        }
+        nRecordSizeFromHeader = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_LOGICAL_REC_LENGTH_OFF);
+        int nFormatVersion = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_FORMAT_VERSION_OFF);
+        CPLDebug("L1B", "NOAA Level 1b Format Version Number = %d", nFormatVersion);
+        CPLDebug("L1B", "Level 1b Format Version Year = %d", nFormatVersionYear);
+        CPLDebug("L1B", "Level 1b Format Version Day of Year = %d", nFormatVersionDayOfYear);
+        CPLDebug("L1B", "Logical Record Length of source Level 1b data set prior to processing = %d", nRecordSizeFromHeader);
+        int nBlockSize = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_BLOCK_SIZE_OFF);
+        CPLDebug("L1B", "Block Size of source Level 1b data set prior to processing = %d", nBlockSize);
+        CPLDebug("L1B", "Count of Header Records in this Data Set = %d", nHeaderRecCount);
+        
+        int nDataRecordCount = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_DATA_RECORD_COUNT_OFF);
+        CPLDebug("L1B", "Count of Data Records = %d", nDataRecordCount);
+        
+        int nCalibratedScanlineCount = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_CALIBRATED_SCANLINE_COUNT_OFF);
+        CPLDebug("L1B", "Count of Calibrated, Earth Located Scan Lines = %d", nCalibratedScanlineCount);
+        
+        int nMissingScanlineCount = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_MISSING_SCANLINE_COUNT_OFF);
+        CPLDebug("L1B", "Count of Missing Scan Lines = %d", nMissingScanlineCount);
+        if( nMissingScanlineCount != 0 )
+            bExposeMaskBand = TRUE;
+
+        char szEllipsoid[8+1];
+        memcpy(szEllipsoid, abyRecHeader + L1B_NOAA15_HDR_REC_ELLIPSOID_OFF, 8);
+        szEllipsoid[8] = '\0';
+        CPLDebug("L1B", "Reference Ellipsoid Model ID = '%s'", szEllipsoid);
+        if( EQUAL(szEllipsoid, "WGS-84  ") )
+        {
+            CPLFree(pszGCPProjection);
+            pszGCPProjection = CPLStrdup(SRS_WKT_WGS84);
+        }
+        else if( EQUAL(szEllipsoid, "  GRS 80") )
+        {
+            CPLFree(pszGCPProjection);
+            pszGCPProjection = CPLStrdup("GEOGCS[\"GRS 1980(IUGG, 1980)\",DATUM[\"unknown\",SPHEROID[\"GRS80\",6378137,298.257222101],TOWGS84[0,0,0,0,0,0,0]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]");
+        }
+
         // Determine the spacecraft name
 		// See http://www.ncdc.noaa.gov/oa/pod-guide/ncdc/docs/klm/html/c8/sec83132-2.htm
-        int iWord = CPL_MSBWORD16( *(GUInt16 *)
-            (abyRecHeader + L1B_NOAA15_HDR_REC_ID_OFF) );
+        int iWord = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_ID_OFF);
         switch ( iWord )
         {
             case 2:
@@ -1545,8 +1738,7 @@ CPLErr L1BDataset::ProcessDatasetHeader(const char* pszFilename)
         }
 
         // Determine the product data type
-        iWord = CPL_MSBWORD16( *(GUInt16 *)
-            (abyRecHeader + L1B_NOAA15_HDR_REC_PROD_OFF) );
+        iWord = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_PROD_OFF);
         switch ( iWord )
         {
             case 1:
@@ -1571,12 +1763,10 @@ CPLErr L1BDataset::ProcessDatasetHeader(const char* pszFilename)
 
         // Fetch hinstrument status. Helps to determine whether we have
         // 3A or 3B channel in the dataset.
-        iInstrumentStatus = CPL_MSBWORD32( *(GUInt32 *)
-            (abyRecHeader + L1B_NOAA15_HDR_REC_STAT_OFF) );
+        iInstrumentStatus = GetUInt32(abyRecHeader + L1B_NOAA15_HDR_REC_STAT_OFF);
 
         // Determine receiving station name
-        iWord = CPL_MSBWORD16( *(GUInt16 *)
-            (abyRecHeader + L1B_NOAA15_HDR_REC_SRC_OFF) );
+        iWord = GetUInt16(abyRecHeader + L1B_NOAA15_HDR_REC_SRC_OFF);
         switch( iWord )
         {
             case 1:
@@ -1626,6 +1816,9 @@ CPLErr L1BDataset::ProcessDatasetHeader(const char* pszFilename)
         case NOAA8:
             pszText = "NOAA-8(E)";
             break;
+        case NOAA9_UNKNOWN:
+            pszText = "UNKNOWN";
+            break;
         case NOAA9:
             pszText = "NOAA-9(F)";
             break;
@@ -2268,7 +2461,9 @@ L1BInterpol(double vals[],
 /*                         IReadBlock()                                 */
 /************************************************************************/
 
-CPLErr L1BGeolocRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, void* pData)
+CPLErr L1BGeolocRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
+                                       void* pData)
 {
     L1BGeolocDataset* poGDS = (L1BGeolocDataset*)poDS;
     L1BDataset* poL1BDS = poGDS->poL1BDS;
@@ -2282,11 +2477,7 @@ CPLErr L1BGeolocRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-    int iDataOffset = (poL1BDS->eLocationIndicator == DESCEND) ?
-        poL1BDS->nDataStartOffset + nBlockYOff * poL1BDS->nRecordSize :
-        poL1BDS->nDataStartOffset +
-            (nRasterYSize - nBlockYOff - 1) * poL1BDS->nRecordSize;
-    VSIFSeekL( poL1BDS->fp, iDataOffset, SEEK_SET );
+    VSIFSeekL( poL1BDS->fp, poL1BDS->GetLineOffset(nBlockYOff), SEEK_SET );
 
     VSIFReadL( pabyRecordHeader, 1, poL1BDS->nRecordDataStart, poL1BDS->fp );
 
@@ -2447,7 +2638,9 @@ L1BSolarZenithAnglesRasterBand::L1BSolarZenithAnglesRasterBand(L1BSolarZenithAng
 /*                         IReadBlock()                                 */
 /************************************************************************/
 
-CPLErr L1BSolarZenithAnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, void* pData)
+CPLErr L1BSolarZenithAnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                                  int nBlockYOff,
+                                                  void* pData)
 {
     L1BSolarZenithAnglesDataset* poGDS = (L1BSolarZenithAnglesDataset*)poDS;
     L1BDataset* poL1BDS = poGDS->poL1BDS;
@@ -2458,11 +2651,7 @@ CPLErr L1BSolarZenithAnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-    int iDataOffset = (poL1BDS->eLocationIndicator == DESCEND) ?
-        poL1BDS->nDataStartOffset + nBlockYOff * poL1BDS->nRecordSize :
-        poL1BDS->nDataStartOffset +
-            (nRasterYSize - nBlockYOff - 1) * poL1BDS->nRecordSize;
-    VSIFSeekL( poL1BDS->fp, iDataOffset, SEEK_SET );
+    VSIFSeekL( poL1BDS->fp, poL1BDS->GetLineOffset(nBlockYOff), SEEK_SET );
 
     VSIFReadL( pabyRecordHeader, 1, poL1BDS->nRecordSize, poL1BDS->fp );
 
@@ -2640,7 +2829,9 @@ L1BNOAA15AnglesRasterBand::L1BNOAA15AnglesRasterBand(L1BNOAA15AnglesDataset* poD
 /*                         IReadBlock()                                 */
 /************************************************************************/
 
-CPLErr L1BNOAA15AnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, void* pData)
+CPLErr L1BNOAA15AnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                             int nBlockYOff,
+                                             void* pData)
 {
     L1BNOAA15AnglesDataset* poGDS = (L1BNOAA15AnglesDataset*)poDS;
     L1BDataset* poL1BDS = poGDS->poL1BDS;
@@ -2651,11 +2842,7 @@ CPLErr L1BNOAA15AnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlo
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-    int iDataOffset = (poL1BDS->eLocationIndicator == DESCEND) ?
-        poL1BDS->nDataStartOffset + nBlockYOff * poL1BDS->nRecordSize :
-        poL1BDS->nDataStartOffset +
-            (nRasterYSize - nBlockYOff - 1) * poL1BDS->nRecordSize;
-    VSIFSeekL( poL1BDS->fp, iDataOffset, SEEK_SET );
+    VSIFSeekL( poL1BDS->fp, poL1BDS->GetLineOffset(nBlockYOff), SEEK_SET );
 
     VSIFReadL( pabyRecordHeader, 1, poL1BDS->nRecordSize, poL1BDS->fp );
 
@@ -2663,9 +2850,7 @@ CPLErr L1BNOAA15AnglesRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlo
 
     for(i=0;i<nRasterXSize;i++)
     {
-        GInt16 i16;
-        memcpy(&i16, pabyRecordHeader + 328 + 6 * i + 2 * (nBand - 1), 2);
-        CPL_MSBPTR16(&i16);
+        GInt16 i16 = poL1BDS->GetInt16(pabyRecordHeader + 328 + 6 * i + 2 * (nBand - 1));
         pafData[i] = i16 / 100.0;
     }
 
@@ -2766,7 +2951,9 @@ L1BCloudsRasterBand::L1BCloudsRasterBand(L1BCloudsDataset* poDS, int nBand)
 /*                         IReadBlock()                                 */
 /************************************************************************/
 
-CPLErr L1BCloudsRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, void* pData)
+CPLErr L1BCloudsRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
+                                       void* pData)
 {
     L1BCloudsDataset* poGDS = (L1BCloudsDataset*)poDS;
     L1BDataset* poL1BDS = poGDS->poL1BDS;
@@ -2777,11 +2964,7 @@ CPLErr L1BCloudsRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff
 /* -------------------------------------------------------------------- */
 /*      Seek to data.                                                   */
 /* -------------------------------------------------------------------- */
-    int iDataOffset = (poL1BDS->eLocationIndicator == DESCEND) ?
-        poL1BDS->nDataStartOffset + nBlockYOff * poL1BDS->nRecordSize :
-        poL1BDS->nDataStartOffset +
-            (nRasterYSize - nBlockYOff - 1) * poL1BDS->nRecordSize;
-    VSIFSeekL( poL1BDS->fp, iDataOffset, SEEK_SET );
+    VSIFSeekL( poL1BDS->fp, poL1BDS->GetLineOffset(nBlockYOff), SEEK_SET );
 
     VSIFReadL( pabyRecordHeader, 1, poL1BDS->nRecordSize, poL1BDS->fp );
 
@@ -3040,7 +3223,17 @@ GDALDataset *L1BDataset::Open( GDALOpenInfo * poOpenInfo )
 
     VSIStatL(osFilename, &sStat);
 
-    if ( poDS->bGuessDataFormat )
+    if( poDS->eL1BFormat == L1B_NOAA15_NOHDR &&
+        poDS->nRecordSizeFromHeader == 22016 &&
+        (sStat.st_size % poDS->nRecordSizeFromHeader) == 0 )
+    {
+        poDS->iDataFormat = UNPACKED16BIT;
+        poDS->ComputeFileOffsets();
+        poDS->nDataStartOffset = poDS->nRecordSizeFromHeader;
+        poDS->nRecordSize = poDS->nRecordSizeFromHeader;
+        poDS->iCLAVRStart = 0;
+    }
+    else if ( poDS->bGuessDataFormat )
     {
         int nTempYSize;
         GUInt16 nScanlineNumber;
@@ -3069,7 +3262,7 @@ GDALDataset *L1BDataset::Open( GDALOpenInfo * poOpenInfo )
 
                 VSIFSeekL(poDS->fp, poDS->nDataStartOffset + i * poDS->nRecordSize, SEEK_SET);
                 VSIFReadL(&nScanlineNumber, 1, 2, poDS->fp);
-                CPL_MSBPTR16( &nScanlineNumber );
+                nScanlineNumber = poDS->GetUInt16(&nScanlineNumber);
 
                 if (i == 1)
                 {
@@ -3107,6 +3300,12 @@ GDALDataset *L1BDataset::Open( GDALOpenInfo * poOpenInfo )
             goto bad;
     }
 
+    CPLDebug("L1B", "nRecordDataStart = %d", poDS->nRecordDataStart);
+    CPLDebug("L1B", "nRecordDataEnd = %d", poDS->nRecordDataEnd);
+    CPLDebug("L1B", "nDataStartOffset = %d", poDS->nDataStartOffset);
+    CPLDebug("L1B", "iCLAVRStart = %d", poDS->iCLAVRStart);
+    CPLDebug("L1B", "nRecordSize = %d", poDS->nRecordSize);
+
     // Compute number of lines dinamycally, so we can read partially
     // downloaded files
     poDS->nRasterYSize =
@@ -3279,6 +3478,9 @@ GDALDataset *L1BDataset::Open( GDALOpenInfo * poOpenInfo )
             }
         }
     }
+    
+    if( poDS->bExposeMaskBand )
+        poDS->poMaskBand = new L1BMaskBand(poDS);
 
 /* -------------------------------------------------------------------- */
 /*      Initialize any PAM information.                                 */
@@ -3289,7 +3491,7 @@ GDALDataset *L1BDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Fetch metadata in CSV file                                      */
@@ -3320,6 +3522,7 @@ void GDALRegister_L1B()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "L1B" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NOAA Polar Orbiter Level 1b Data Set" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -3334,4 +3537,3 @@ void GDALRegister_L1B()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/leveller/GNUmakefile b/frmts/leveller/GNUmakefile
index e5012a7..50cc6ae 100644
--- a/frmts/leveller/GNUmakefile
+++ b/frmts/leveller/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	levellerdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/leveller/levellerdataset.cpp b/frmts/leveller/levellerdataset.cpp
index f959429..98cbd30 100644
--- a/frmts/leveller/levellerdataset.cpp
+++ b/frmts/leveller/levellerdataset.cpp
@@ -35,7 +35,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: levellerdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: levellerdataset.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 CPL_C_START
 void	GDALRegister_Leveller(void);
@@ -454,10 +454,11 @@ LevellerRasterBand::~LevellerRasterBand()
 /*                             IWriteBlock()                            */
 /************************************************************************/
 
-CPLErr LevellerRasterBand::IWriteBlock ( 
-	CPL_UNUSED int nBlockXOff, 
-	int nBlockYOff,
-        void* pImage
+CPLErr LevellerRasterBand::IWriteBlock
+(
+    CPL_UNUSED int nBlockXOff,
+    int nBlockYOff,
+    void* pImage
 )
 {
     CPLAssert( nBlockXOff == 0  );
@@ -520,7 +521,8 @@ CPLErr LevellerRasterBand::SetUnitType( const char* psz )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr LevellerRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr LevellerRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
                                        void* pImage )
 
 {
@@ -920,7 +922,7 @@ GDALDataset* LevellerDataset::Create
     const char* pszValue = CSLFetchNameValue( 
 		papszOptions,"MINUSERPIXELVALUE");
     if( pszValue != NULL )
-        poDS->m_dLogSpan[0] = atof( pszValue );
+        poDS->m_dLogSpan[0] = CPLAtof( pszValue );
 	else
 	{
 		delete poDS;
@@ -932,7 +934,7 @@ GDALDataset* LevellerDataset::Create
     pszValue = CSLFetchNameValue( 
 		papszOptions,"MAXUSERPIXELVALUE");
     if( pszValue != NULL )
-        poDS->m_dLogSpan[1] = atof( pszValue );
+        poDS->m_dLogSpan[1] = CPLAtof( pszValue );
 
 	if(poDS->m_dLogSpan[1] < poDS->m_dLogSpan[0])
 	{
@@ -1345,9 +1347,10 @@ bool LevellerDataset::load_from_file(VSILFILE* file, const char* pszFilename)
 			{
 				UNITLABEL unitcode;
 				//char szLocalUnits[8];
-                                // TODO: Fix strict aliasing issue.
-				if(!this->get((int&)unitcode, file, "coordsys_units"))
-					unitcode = UNITLABEL_M;
+                                int unitcode_int;
+				if(!this->get(unitcode_int, file, "coordsys_units"))
+					unitcode_int = UNITLABEL_M;
+                                unitcode = (UNITLABEL) unitcode_int;
 
 				if(!this->make_local_coordsys("Leveller", unitcode))
 				{
@@ -1396,8 +1399,10 @@ bool LevellerDataset::load_from_file(VSILFILE* file, const char* pszFilename)
 			this->get(m_dElevScale, file, "coordsys_em_scale");
 			this->get(m_dElevBase, file, "coordsys_em_base");
 			UNITLABEL unitcode;
-			if(this->get((int&)unitcode, file, "coordsys_em_units"))
+                        int unitcode_int;
+			if(this->get(unitcode_int, file, "coordsys_em_units"))
 			{
+                                unitcode = (UNITLABEL) unitcode_int;
 				const char* pszUnitID = this->code_to_id(unitcode);
 				if(pszUnitID != NULL)
 					strcpy(m_szElevUnits, pszUnitID);
@@ -1571,7 +1576,7 @@ GDALDataset *LevellerDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -1599,6 +1604,7 @@ void GDALRegister_Leveller()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "Leveller" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, 
                                    "ter" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
diff --git a/frmts/makefile.vc b/frmts/makefile.vc
index 7fc563c..8d35038 100644
--- a/frmts/makefile.vc
+++ b/frmts/makefile.vc
@@ -14,7 +14,7 @@ EXTRAFLAGS =	-DFRMT_ceos -DFRMT_aigrid -DFRMT_elas -DFRMT_hfa -DFRMT_gtiff\
 		-DFRMT_adrg -DFRMT_coasp -DFRMT_tsx -DFRMT_blx -DFRMT_til \
 		-DFRMT_r -DFRMT_northwood -DFRMT_saga -DFRMT_xyz -DFRMT_hf2 \
 		-DFRMT_kmlsuperoverlay -DFRMT_ozi -DFRMT_ctg -DFRMT_e00grid \
-		-DFRMT_zmap -DFRMT_ngsgeoid -DFRMT_pdf -DFRMT_iris -DFRMT_map
+		-DFRMT_zmap -DFRMT_ngsgeoid -DFRMT_iris -DFRMT_map
 
 MOREEXTRA 	=	
 
@@ -106,6 +106,14 @@ PLUGINFLAGS	=	$(PLUGINFLAGS) -DFRMT_fits
 !ENDIF
 !ENDIF
 
+!IF DEFINED(POPPLER_LIBS) || DEFINED(PODOFO_LIBS)
+!IF "$(PDF_PLUGIN)" != "YES"
+EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_pdf
+!ELSE
+PLUGINFLAGS	=	$(PLUGINFLAGS) -DFRMT_pdf
+!ENDIF
+!ENDIF
+
 !IFDEF DODS_DIR
 EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_dods
 !ENDIF
@@ -123,7 +131,7 @@ EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_grib
 !ENDIF
 
 !IFDEF CURL_LIB
-EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_wcs -DFRMT_wms
+EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_wcs -DFRMT_wms -DFRMT_plmosaic
 !ENDIF
 
 !IFDEF SDE_ENABLED
@@ -164,6 +172,14 @@ EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_gta
 EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_arg
 !ENDIF
 
+!IFDEF KEA_CFLAGS
+!IF "$(KEA_PLUGIN)" != "YES"
+EXTRAFLAGS	=	$(EXTRAFLAGS) -DFRMT_kea
+!ELSE
+PLUGINFLAGS	=	$(PLUGINFLAGS) -DFRMT_kea
+!ENDIF
+!ENDIF
+
 default:	o\gdalallregister.obj subdirs
 
 list:
diff --git a/frmts/map/GNUmakefile b/frmts/map/GNUmakefile
index c4b5a18..e85bf23 100644
--- a/frmts/map/GNUmakefile
+++ b/frmts/map/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	mapdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/map/frmt_map.html b/frmts/map/frmt_map.html
index b2e4619..b2e829b 100644
--- a/frmts/map/frmt_map.html
+++ b/frmts/map/frmt_map.html
@@ -18,7 +18,7 @@ This driver does not support file creation.
 <ul>
 <li> Implemented as <tt>gdal/frmts/map/mapdataset.cpp</tt>.<p>
 
-<li> <a href="http://www.rus-roads.ru/gps/help_ozi/map_file_format.html">
+<li> <a href="http://www.oziexplorer3.com/eng/help/map_file_format.html">
 OziExplorer Map File Format
 </a><p>
 
diff --git a/frmts/map/mapdataset.cpp b/frmts/map/mapdataset.cpp
index f7e2045..726f444 100644
--- a/frmts/map/mapdataset.cpp
+++ b/frmts/map/mapdataset.cpp
@@ -32,7 +32,7 @@
 #include "ogr_spatialref.h"
 #include "ogr_geometry.h"
 
-CPL_CVSID("$Id: mapdataset.cpp 27560 2014-08-04 17:52:58Z rouault $");
+CPL_CVSID("$Id: mapdataset.cpp 27559 2014-08-04 17:52:19Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -493,6 +493,7 @@ void GDALRegister_MAP()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "MAP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "OziExplorer .MAP" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/mbtiles/GNUmakefile b/frmts/mbtiles/GNUmakefile
index 72bf33b..338acea 100644
--- a/frmts/mbtiles/GNUmakefile
+++ b/frmts/mbtiles/GNUmakefile
@@ -7,7 +7,7 @@ ifeq ($(LIBZ_SETTING),internal)
   XTRA_OPT :=   $(XTRA_OPT) -I../zlib
 endif
 
-CPPFLAGS	:=	$(JSON_INCLUDE) $(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS) -I../../ogr
+CPPFLAGS	:=	$(JSON_INCLUDE) $(XTRA_OPT)  $(CPPFLAGS) -I../../ogr
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/mbtiles/mbtilesdataset.cpp b/frmts/mbtiles/mbtilesdataset.cpp
index 4f82f2c..75cac22 100644
--- a/frmts/mbtiles/mbtilesdataset.cpp
+++ b/frmts/mbtiles/mbtilesdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: mbtilesdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: mbtilesdataset.cpp 28884 2015-04-12 20:48:02Z rouault $
  *
  * Project:  GDAL MBTiles driver
  * Purpose:  Implement GDAL MBTiles support using OGR SQLite driver
@@ -39,13 +39,27 @@
 
 extern "C" void GDALRegister_MBTiles();
 
-CPL_CVSID("$Id: mbtilesdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: mbtilesdataset.cpp 28884 2015-04-12 20:48:02Z rouault $");
 
 static const char * const apszAllowedDrivers[] = {"JPEG", "PNG", NULL};
 
 class MBTilesBand;
 
 /************************************************************************/
+/*                         MBTILESOpenSQLiteDB()                        */
+/************************************************************************/
+
+OGRDataSourceH MBTILESOpenSQLiteDB(const char* pszFilename,
+                                      GDALAccess eAccess)
+{
+    const char* apszAllowedDrivers[] = { "SQLITE", NULL };
+    return (OGRDataSourceH)GDALOpenEx(pszFilename,
+                                      GDAL_OF_VECTOR |
+                                      ((eAccess == GA_Update) ? GDAL_OF_UPDATE : 0),
+                                      apszAllowedDrivers, NULL, NULL);
+}
+
+/************************************************************************/
 /* ==================================================================== */
 /*                              MBTilesDataset                          */
 /* ==================================================================== */
@@ -183,7 +197,9 @@ CPLErr MBTilesBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage)
                                             nDataSize, FALSE);
         VSIFCloseL(fp);
 
-        GDALDatasetH hDSTile = GDALOpenInternal(osMemFileName.c_str(), GA_ReadOnly, apszAllowedDrivers);
+        GDALDatasetH hDSTile = GDALOpenEx(osMemFileName.c_str(),
+                                          GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                          apszAllowedDrivers, NULL, NULL);
         if (hDSTile != NULL)
         {
             int nTileBands = GDALGetRasterCount(hDSTile);
@@ -772,8 +788,11 @@ const char *MBTilesBand::GetMetadataItem( const char * pszName,
             double adfInvGeoTransform[6];
             double dfGeoX, dfGeoY;
 
-            if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
+            dfGeoX = CPLAtof(pszName + 9);
+            const char* pszUnderscore = strchr(pszName + 9, '_');
+            if( !pszUnderscore )
                 return NULL;
+            dfGeoY = CPLAtof(pszUnderscore + 1);
 
             if( GetDataset() == NULL )
                 return NULL;
@@ -1030,8 +1049,7 @@ int MBTilesDataset::CloseDependentDatasets()
 /*                          GetGeoTransform()                           */
 /************************************************************************/
 
-//#define MAX_GM 20037508.3427892
-#define MAX_GM 20037500.
+#define MAX_GM 20037508.34
 
 CPLErr MBTilesDataset::GetGeoTransform(double* padfGeoTransform)
 {
@@ -1275,7 +1293,9 @@ int MBTilesGetMinMaxZoomLevel(OGRDataSourceH hDS, int bHasMap,
 /************************************************************************/
 
 static
-int MBTilesGetBounds(OGRDataSourceH hDS, CPL_UNUSED int nMinLevel, int nMaxLevel,
+int MBTilesGetBounds(OGRDataSourceH hDS,
+                     CPL_UNUSED int nMinLevel,
+                     int nMaxLevel,
                      int& nMinTileRow, int& nMaxTileRow,
                      int& nMinTileCol, int &nMaxTileCol)
 {
@@ -1295,12 +1315,12 @@ int MBTilesGetBounds(OGRDataSourceH hDS, CPL_UNUSED int nMinLevel, int nMaxLevel
             const char* pszBounds = OGR_F_GetFieldAsString(hFeat, 0);
             char** papszTokens = CSLTokenizeString2(pszBounds, ",", 0);
             if (CSLCount(papszTokens) != 4 ||
-                fabs(atof(papszTokens[0])) > 180 ||
-                fabs(atof(papszTokens[1])) > 86 ||
-                fabs(atof(papszTokens[2])) > 180 ||
-                fabs(atof(papszTokens[3])) > 86 ||
-                atof(papszTokens[0]) > atof(papszTokens[2]) ||
-                atof(papszTokens[1]) > atof(papszTokens[3]))
+                fabs(CPLAtof(papszTokens[0])) > 180 ||
+                fabs(CPLAtof(papszTokens[1])) > 86 ||
+                fabs(CPLAtof(papszTokens[2])) > 180 ||
+                fabs(CPLAtof(papszTokens[3])) > 86 ||
+                CPLAtof(papszTokens[0]) > CPLAtof(papszTokens[2]) ||
+                CPLAtof(papszTokens[1]) > CPLAtof(papszTokens[3]))
             {
                 CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for 'bounds' metadata");
                 CSLDestroy(papszTokens);
@@ -1314,10 +1334,10 @@ int MBTilesGetBounds(OGRDataSourceH hDS, CPL_UNUSED int nMinLevel, int nMaxLevel
             #define LAT_TO_NORTHING(lat) \
                 6378137 * log(tan(FORTPI + .5 * (lat) / 180 * (4 * FORTPI)))
 
-            nMinTileCol = (int)(((atof(papszTokens[0]) + 180) / 360) * (1 << nMaxLevel));
-            nMaxTileCol = (int)(((atof(papszTokens[2]) + 180) / 360) * (1 << nMaxLevel));
-            nMinTileRow = (int)(0.5 + ((LAT_TO_NORTHING(atof(papszTokens[1])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
-            nMaxTileRow = (int)(0.5 + ((LAT_TO_NORTHING(atof(papszTokens[3])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
+            nMinTileCol = (int)(((CPLAtof(papszTokens[0]) + 180) / 360) * (1 << nMaxLevel));
+            nMaxTileCol = (int)(((CPLAtof(papszTokens[2]) + 180) / 360) * (1 << nMaxLevel));
+            nMinTileRow = (int)(0.5 + ((LAT_TO_NORTHING(CPLAtof(papszTokens[1])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
+            nMaxTileRow = (int)(0.5 + ((LAT_TO_NORTHING(CPLAtof(papszTokens[3])) + MAX_GM) / (2* MAX_GM)) * (1 << nMaxLevel));
 
             bHasBounds = TRUE;
 
@@ -1353,9 +1373,9 @@ int MBTilesGetBounds(OGRDataSourceH hDS, CPL_UNUSED int nMinLevel, int nMaxLevel
             OGR_F_IsFieldSet(hFeat, 3))
         {
             nMinTileCol = OGR_F_GetFieldAsInteger(hFeat, 0);
-            nMaxTileCol = OGR_F_GetFieldAsInteger(hFeat, 1);
+            nMaxTileCol = OGR_F_GetFieldAsInteger(hFeat, 1) + 1;
             nMinTileRow = OGR_F_GetFieldAsInteger(hFeat, 2);
-            nMaxTileRow = OGR_F_GetFieldAsInteger(hFeat, 3);
+            nMaxTileRow = OGR_F_GetFieldAsInteger(hFeat, 3) + 1;
             bHasBounds = TRUE;
         }
 
@@ -1480,7 +1500,9 @@ static int MBTilesCurlReadCbk(CPL_UNUSED VSILFILE* fp,
 /************************************************************************/
 
 static
-int MBTilesGetBandCount(OGRDataSourceH &hDS, CPL_UNUSED int nMinLevel, int nMaxLevel,
+int MBTilesGetBandCount(OGRDataSourceH &hDS,
+                        CPL_UNUSED int nMinLevel,
+                        int nMaxLevel,
                         int nMinTileRow, int nMaxTileRow,
                         int nMinTileCol, int nMaxTileCol)
 {
@@ -1553,7 +1575,7 @@ int MBTilesGetBandCount(OGRDataSourceH &hDS, CPL_UNUSED int nMinLevel, int nMaxL
             /* No worry ! This will be fast because the /vsicurl/ cache has cached the already */
             /* read blocks */
             OGRReleaseDataSource(hDS);
-            hDS = OGROpen(osDSName.c_str(), FALSE, NULL);
+            hDS = MBTILESOpenSQLiteDB(osDSName.c_str(), GA_ReadOnly);
             if (hDS == NULL)
                 return -1;
 
@@ -1607,8 +1629,8 @@ int MBTilesGetBandCount(OGRDataSourceH &hDS, CPL_UNUSED int nMinLevel, int nMaxL
     VSIFCloseL(VSIFileFromMemBuffer( osMemFileName.c_str(), pabyData,
                                     nDataSize, FALSE));
 
-    GDALDatasetH hDSTile =
-        GDALOpenInternal(osMemFileName.c_str(), GA_ReadOnly, apszAllowedDrivers);
+    GDALDatasetH hDSTile = GDALOpenEx(osMemFileName.c_str(), GDAL_OF_RASTER,
+                                          apszAllowedDrivers, NULL, NULL);
     if (hDSTile == NULL)
     {
         VSIUnlink(osMemFileName.c_str());
@@ -1672,7 +1694,7 @@ GDALDataset* MBTilesDataset::Open(GDALOpenInfo* poOpenInfo)
 /*      Open underlying OGR DB                                          */
 /* -------------------------------------------------------------------- */
 
-    OGRDataSourceH hDS = OGROpen(poOpenInfo->pszFilename, FALSE, NULL);
+    OGRDataSourceH hDS = MBTILESOpenSQLiteDB(poOpenInfo->pszFilename, GA_ReadOnly);
 
     MBTilesDataset* poDS = NULL;
 
@@ -1746,7 +1768,7 @@ GDALDataset* MBTilesDataset::Open(GDALOpenInfo* poOpenInfo)
         if (bHasMinMaxLevel && (nMinLevel < 0 || nMinLevel > nMaxLevel))
         {
             CPLError(CE_Failure, CPLE_AppDefined,
-                     "Inconsistant values : min(zoom_level) = %d, max(zoom_level) = %d",
+                     "Inconsistent values : min(zoom_level) = %d, max(zoom_level) = %d",
                      nMinLevel, nMaxLevel);
             goto end;
         }
@@ -1899,6 +1921,7 @@ void GDALRegister_MBTiles()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "MBTiles" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "MBTiles" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/mem/GNUmakefile b/frmts/mem/GNUmakefile
index 54200cd..6a31191 100644
--- a/frmts/mem/GNUmakefile
+++ b/frmts/mem/GNUmakefile
@@ -4,7 +4,7 @@ include ../../GDALmake.opt
 
 OBJ	=	memdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/mem/frmt_mem.html b/frmts/mem/frmt_mem.html
index 78e74e4..65f10d0 100644
--- a/frmts/mem/frmt_mem.html
+++ b/frmts/mem/frmt_mem.html
@@ -11,7 +11,7 @@ GDAL supports the ability to hold rasters in a temporary in-memory format.
 This is primarily useful for temporary datasets in scripts or internal
 to applications.  It is not generally of any use to application end-users.<p>
 
-Memory datasets should support for most kinds of auxilary information
+Memory datasets should support for most kinds of auxiliary information
 including metadata, coordinate systems, georeferencing, GCPs,
 color interpretation, nodata, color tables and all pixel data types.<p>
 
diff --git a/frmts/mem/memdataset.cpp b/frmts/mem/memdataset.cpp
index 9b2d74e..06bd387 100644
--- a/frmts/mem/memdataset.cpp
+++ b/frmts/mem/memdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: memdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: memdataset.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  Memory Array Translator
  * Purpose:  Complete implementation.
@@ -31,7 +31,7 @@
 #include "memdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: memdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: memdataset.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /************************************************************************/
 /*                        MEMCreateRasterBand()                         */
@@ -54,7 +54,7 @@ GDALRasterBandH MEMCreateRasterBand( GDALDataset *poDS, int nBand,
 
 MEMRasterBand::MEMRasterBand( GDALDataset *poDS, int nBand,
                               GByte *pabyDataIn, GDALDataType eTypeIn, 
-                              int nPixelOffsetIn, int nLineOffsetIn,
+                              GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
                               int bAssumeOwnership, const char * pszPixelType)
 
 {
@@ -74,7 +74,7 @@ MEMRasterBand::MEMRasterBand( GDALDataset *poDS, int nBand,
         nPixelOffsetIn = GDALGetDataTypeSize(eTypeIn) / 8;
 
     if( nLineOffsetIn == 0 )
-        nLineOffsetIn = nPixelOffsetIn * nBlockXSize;
+        nLineOffsetIn = nPixelOffsetIn * (size_t)nBlockXSize;
 
     nPixelOffset = nPixelOffsetIn;
     nLineOffset = nLineOffsetIn;
@@ -127,9 +127,9 @@ MEMRasterBand::~MEMRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr MEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                   void * pImage )
-
+CPLErr MEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
+                                  void * pImage )
 {
     int     nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
     CPLAssert( nBlockXOff == 0 );
@@ -159,9 +159,9 @@ CPLErr MEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 /*                            IWriteBlock()                             */
 /************************************************************************/
 
-CPLErr MEMRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                     void * pImage )
-
+CPLErr MEMRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
+                                   void * pImage )
 {
     int     nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
     CPLAssert( nBlockXOff == 0 );
@@ -188,6 +188,183 @@ CPLErr MEMRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 }
 
 /************************************************************************/
+/*                             IRasterIO()                              */
+/************************************************************************/
+
+CPLErr MEMRasterBand::IRasterIO( GDALRWFlag eRWFlag,
+                                 int nXOff, int nYOff, int nXSize, int nYSize,
+                                 void * pData, int nBufXSize, int nBufYSize,
+                                 GDALDataType eBufType,
+                                 GSpacing nPixelSpaceBuf,
+                                 GSpacing nLineSpaceBuf,
+                                 GDALRasterIOExtraArg* psExtraArg )
+{
+    if( nXSize != nBufXSize || nYSize != nBufYSize )
+    {
+        return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                                         pData, nBufXSize, nBufYSize,
+                                         eBufType,
+                                         nPixelSpaceBuf, nLineSpaceBuf,
+                                         psExtraArg);
+    }
+
+    // In case block based I/O has been done before
+    FlushCache();
+
+    if( eRWFlag == GF_Read )
+    {
+        for(int iLine=0;iLine<nYSize;iLine++)
+        {
+            GDALCopyWords( pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
+                           eDataType,
+                           nPixelOffset,
+                           ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
+                           eBufType,
+                           nPixelSpaceBuf,
+                           nXSize);
+        }
+    }
+    else
+    {
+        for(int iLine=0;iLine<nYSize;iLine++)
+        {
+            GDALCopyWords( ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
+                           eBufType,
+                           nPixelSpaceBuf,
+                           pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
+                           eDataType,
+                           nPixelOffset,
+                           nXSize);
+        }
+    }
+    return CE_None;
+}
+
+/************************************************************************/
+/*                             IRasterIO()                              */
+/************************************************************************/
+
+CPLErr MEMDataset::IRasterIO( GDALRWFlag eRWFlag,
+                              int nXOff, int nYOff, int nXSize, int nYSize,
+                              void * pData, int nBufXSize, int nBufYSize,
+                              GDALDataType eBufType, 
+                              int nBandCount, int *panBandMap,
+                              GSpacing nPixelSpaceBuf,
+                              GSpacing nLineSpaceBuf,
+                              GSpacing nBandSpaceBuf,
+                              GDALRasterIOExtraArg* psExtraArg)
+{
+    int eBufTypeSize = GDALGetDataTypeSize(eBufType) / 8;
+
+    /* Detect if we have a pixel-interleaved buffer and a pixel-interleaved dataset */
+    if( nXSize == nBufXSize && nYSize == nBufYSize &&
+        nBandCount == nBands && nBands > 1 &&
+        nBandSpaceBuf == eBufTypeSize &&
+        nPixelSpaceBuf == nBandSpaceBuf * nBands )
+    {
+        GDALDataType eDT = GDT_Unknown;
+        GByte* pabyData = NULL;
+        GSpacing nPixelOffset = 0;
+        GSpacing nLineOffset = 0;
+        int eDTSize = 0;
+        int iBandIndex;
+        for( iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++ )
+        {
+            if( panBandMap[iBandIndex] != iBandIndex + 1 )
+                break;
+            MEMRasterBand *poBand = (MEMRasterBand*) GetRasterBand(iBandIndex + 1);
+            if( iBandIndex == 0 )
+            {
+                eDT = poBand->GetRasterDataType();
+                pabyData = poBand->pabyData;
+                nPixelOffset = poBand->nPixelOffset;
+                nLineOffset = poBand->nLineOffset;
+                eDTSize = GDALGetDataTypeSize(eDT) / 8;
+                if( nPixelOffset != nBands * eDTSize )
+                    break;
+            }
+            else if( poBand->GetRasterDataType() != eDT ||
+                     nPixelOffset != poBand->nPixelOffset ||
+                     nLineOffset != poBand->nLineOffset ||
+                     poBand->pabyData != pabyData + iBandIndex * eDTSize )
+            {
+                break;
+            }
+        }
+        if( iBandIndex == nBandCount )
+        {
+            FlushCache();
+            if( eRWFlag == GF_Read )
+            {
+                for(int iLine=0;iLine<nYSize;iLine++)
+                {
+                    GDALCopyWords( pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
+                                   eDT,
+                                   eDTSize,
+                                   ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
+                                   eBufType,
+                                   eBufTypeSize,
+                                   nXSize * nBands);
+                }
+            }
+            else
+            {
+                for(int iLine=0;iLine<nYSize;iLine++)
+                {
+                    GDALCopyWords( ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
+                                   eBufType,
+                                   eBufTypeSize,
+                                   pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
+                                   eDT,
+                                   eDTSize,
+                                   nXSize * nBands);
+                }
+            }
+            return CE_None;
+        }
+    }
+    
+    GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+    void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
+    CPLErr eErr = CE_None;
+    for( int iBandIndex = 0; 
+         iBandIndex < nBandCount && eErr == CE_None; 
+         iBandIndex++ )
+    {
+        GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
+        GByte *pabyBandData;
+
+        if (poBand == NULL)
+        {
+            eErr = CE_Failure;
+            break;
+        }
+
+        pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpaceBuf;
+
+        psExtraArg->pfnProgress = GDALScaledProgress;
+        psExtraArg->pProgressData = 
+            GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
+                                      1.0 * (iBandIndex + 1) / nBandCount,
+                                      pfnProgressGlobal,
+                                      pProgressDataGlobal );
+
+        eErr = poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+                                  (void *) pabyBandData, nBufXSize, nBufYSize,
+                                  eBufType, nPixelSpaceBuf, nLineSpaceBuf,
+                                 psExtraArg);
+
+        GDALDestroyScaledProgress( psExtraArg->pProgressData );
+    }
+    
+    psExtraArg->pfnProgress = pfnProgressGlobal;
+    psExtraArg->pProgressData = pProgressDataGlobal;
+
+    return eErr;
+}
+
+/************************************************************************/
 /*                            GetNoDataValue()                          */
 /************************************************************************/
 double MEMRasterBand::GetNoDataValue( int *pbSuccess )
@@ -372,7 +549,7 @@ CPLErr MEMRasterBand::SetCategoryNames( char ** papszNewNames )
 /************************************************************************/
 
 CPLErr MEMRasterBand::SetDefaultHistogram( double dfMin, double dfMax, 
-                                           int nBuckets, int *panHistogram)
+                                           int nBuckets, GUIntBig *panHistogram)
 
 {
     CPLXMLNode *psNode;
@@ -420,7 +597,7 @@ CPLErr MEMRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
 
 CPLErr 
 MEMRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax, 
-                                    int *pnBuckets, int **ppanHistogram, 
+                                    int *pnBuckets, GUIntBig **ppanHistogram, 
                                     int bForce,
                                     GDALProgressFunc pfnProgress, 
                                     void *pProgressData )
@@ -671,7 +848,7 @@ CPLErr MEMDataset::AddBand( GDALDataType eType, char **papszOptions )
 /*      Get layout of memory and other flags.                           */
 /* -------------------------------------------------------------------- */
     const char *pszOption;
-    int nPixelOffset, nLineOffset;
+    GSpacing nPixelOffset, nLineOffset;
     const char *pszDataPointer;
 
     pszDataPointer = CSLFetchNameValue(papszOptions,"DATAPOINTER");
@@ -682,13 +859,13 @@ CPLErr MEMDataset::AddBand( GDALDataType eType, char **papszOptions )
     if( pszOption == NULL )
         nPixelOffset = nPixelSize;
     else
-        nPixelOffset = atoi(pszOption);
+        nPixelOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
 
     pszOption = CSLFetchNameValue(papszOptions,"LINEOFFSET");
     if( pszOption == NULL )
-        nLineOffset = GetRasterXSize() * nPixelOffset;
+        nLineOffset = GetRasterXSize() * (size_t)nPixelOffset;
     else
-        nLineOffset = atoi(pszOption);
+        nLineOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
 
     SetBand( nBandId,
              new MEMRasterBand( this, nBandId, pData, eType, 
@@ -711,7 +888,7 @@ GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      description strings?                                            */
 /* -------------------------------------------------------------------- */
     if( !EQUALN(poOpenInfo->pszFilename,"MEM:::",6) 
-        || poOpenInfo->fp != NULL )
+        || poOpenInfo->fpL != NULL )
         return NULL;
 
     papszOptions = CSLTokenizeStringComplex(poOpenInfo->pszFilename+6, ",",
@@ -748,8 +925,8 @@ GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     const char *pszOption;
     GDALDataType eType;
-    int nBands, nPixelOffset, nLineOffset;
-    size_t nBandOffset;
+    int nBands;
+    GSpacing nPixelOffset, nLineOffset, nBandOffset;
     const char *pszDataPointer;
     GByte *pabyData;
 
@@ -807,19 +984,19 @@ GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
     if( pszOption == NULL )
         nPixelOffset = GDALGetDataTypeSize(eType) / 8;
     else
-        nPixelOffset = atoi(pszOption);
+        nPixelOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
 
     pszOption = CSLFetchNameValue(papszOptions,"LINEOFFSET");
     if( pszOption == NULL )
-        nLineOffset = poDS->nRasterXSize * nPixelOffset;
+        nLineOffset = poDS->nRasterXSize * (size_t) nPixelOffset;
     else
-        nLineOffset = atoi(pszOption);
+        nLineOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
 
     pszOption = CSLFetchNameValue(papszOptions,"BANDOFFSET");
     if( pszOption == NULL )
         nBandOffset = nLineOffset * (size_t) poDS->nRasterYSize;
     else
-        nBandOffset = atoi(pszOption);
+        nBandOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
 
     pszDataPointer = CSLFetchNameValue(papszOptions,"DATAPOINTER");
     pabyData = (GByte *) CPLScanPointer( pszDataPointer, 
@@ -849,10 +1026,11 @@ GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
 /************************************************************************/
 
 GDALDataset *MEMDataset::Create( CPL_UNUSED const char * pszFilename,
-                                 int nXSize, int nYSize, int nBands,
+                                 int nXSize,
+                                 int nYSize,
+                                 int nBands,
                                  GDALDataType eType,
                                  char **papszOptions )
-
 {
 
 /* -------------------------------------------------------------------- */
@@ -975,7 +1153,7 @@ GDALDataset *MEMDataset::Create( CPL_UNUSED const char * pszFilename,
 static int MEMDatasetIdentify( GDALOpenInfo * poOpenInfo )
 {
     return (strncmp(poOpenInfo->pszFilename, "MEM:::", 6) == 0 &&
-            poOpenInfo->fp == NULL);
+            poOpenInfo->fpL == NULL);
 }
 
 /************************************************************************/
@@ -1002,6 +1180,7 @@ void GDALRegister_MEM()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "MEM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "In Memory Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
@@ -1029,4 +1208,3 @@ void GDALRegister_MEM()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/mem/memdataset.h b/frmts/mem/memdataset.h
index 3edffe8..54b6301 100644
--- a/frmts/mem/memdataset.h
+++ b/frmts/mem/memdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: memdataset.h 21803 2011-02-22 22:12:22Z warmerdam $
+ * $Id: memdataset.h 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  Memory Array Translator
  * Purpose:  Declaration of MEMDataset, and MEMRasterBand.
@@ -35,6 +35,8 @@
 
 CPL_C_START
 void	GDALRegister_MEM(void);
+/* Caution: if changing this prototype, also change in swig/include/gdal_python.i
+   where it is redefined */
 GDALRasterBandH CPL_DLL MEMCreateRasterBand( GDALDataset *, int, GByte *,
                                              GDALDataType, int, int, int );
 CPL_C_END
@@ -76,7 +78,16 @@ class CPL_DLL MEMDataset : public GDALDataset
 
     virtual CPLErr        AddBand( GDALDataType eType, 
                                    char **papszOptions=NULL );
-
+    virtual CPLErr  IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpaceBuf,
+                               GSpacing nLineSpaceBuf,
+                               GSpacing nBandSpaceBuf,
+                               GDALRasterIOExtraArg* psExtraArg);
+    
     static GDALDataset *Open( GDALOpenInfo * );
     static GDALDataset *Create( const char * pszFilename,
                                 int nXSize, int nYSize, int nBands,
@@ -90,10 +101,11 @@ class CPL_DLL MEMDataset : public GDALDataset
 class CPL_DLL MEMRasterBand : public GDALPamRasterBand
 {
   protected:
+    friend      class MEMDataset;
 
     GByte      *pabyData;
-    int         nPixelOffset;
-    int         nLineOffset;
+    GSpacing    nPixelOffset;
+    GSpacing    nLineOffset;
     int         bOwnData;
 
     int         bNoDataSet;
@@ -113,15 +125,19 @@ class CPL_DLL MEMRasterBand : public GDALPamRasterBand
 
                    MEMRasterBand( GDALDataset *poDS, int nBand,
                                   GByte *pabyData, GDALDataType eType,
-                                  int nPixelOffset, int nLineOffset,
+                                  GSpacing nPixelOffset, GSpacing nLineOffset,
                                   int bAssumeOwnership,  const char * pszPixelType = NULL);
     virtual        ~MEMRasterBand();
 
-    // should override RasterIO eventually.
-
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IWriteBlock( int, int, void * );
-
+    virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
+                                  int nXOff, int nYOff, int nXSize, int nYSize,
+                                  void * pData, int nBufXSize, int nBufYSize,
+                                  GDALDataType eBufType,
+                                  GSpacing nPixelSpaceBuf,
+                                  GSpacing nLineSpaceBuf,
+                                  GDALRasterIOExtraArg* psExtraArg );
     virtual double GetNoDataValue( int *pbSuccess = NULL );
     virtual CPLErr SetNoDataValue( double );
 
@@ -143,9 +159,9 @@ class CPL_DLL MEMRasterBand : public GDALPamRasterBand
     CPLErr SetScale( double );
 
     virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int *panHistogram );
+                                        int nBuckets, GUIntBig *panHistogram );
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                        int *pnBuckets, int ** ppanHistogram,
+                                        int *pnBuckets, GUIntBig ** ppanHistogram,
                                         int bForce,
                                         GDALProgressFunc, void *pProgressData);
 
diff --git a/frmts/mrsid/GNUmakefile b/frmts/mrsid/GNUmakefile
index 022800a..69cfe88 100644
--- a/frmts/mrsid/GNUmakefile
+++ b/frmts/mrsid/GNUmakefile
@@ -12,7 +12,7 @@ CPPFLAGS	:=	-DRENAME_INTERNAL_LIBGEOTIFF_SYMBOLS $(CPPFLAGS)
 endif
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(MRSID_FLAGS) $(MRSID_INCLUDE) $(GEOTIFF_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(MRSID_FLAGS) $(MRSID_INCLUDE) $(GEOTIFF_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/mrsid/mrsiddataset.cpp b/frmts/mrsid/mrsiddataset.cpp
index 2d0e4e4..2c5caa7 100644
--- a/frmts/mrsid/mrsiddataset.cpp
+++ b/frmts/mrsid/mrsiddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: mrsiddataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: mrsiddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  Multi-resolution Seamless Image Database (MrSID)
  * Purpose:  Read/write LizardTech's MrSID file format - Version 4+ SDK.
@@ -39,7 +39,7 @@
 #include <geo_normalize.h>
 #include <geovalues.h>
 
-CPL_CVSID("$Id: mrsiddataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: mrsiddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 double GTIFAngleToDD( double dfAngle, int nUOMAngle );
@@ -259,8 +259,10 @@ class MrSIDDataset : public GDALJP2AbstractDataset
     char                *GetOGISDefn( GTIFDefn * );
 
     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int, void *,
-                                   int, int, GDALDataType, int, int *,int,
-                                   int, int );
+                                   int, int, GDALDataType, int, int *,
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GSpacing nBandSpace,
+                                   GDALRasterIOExtraArg* psExtraArg);
 
   protected:
     virtual int         CloseDependentDatasets();
@@ -312,7 +314,8 @@ class MrSIDRasterBand : public GDALPamRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     virtual CPLErr          IReadBlock( int, int, void * );
     virtual GDALColorInterp GetColorInterpretation();
@@ -610,7 +613,8 @@ CPLErr MrSIDRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                    int nXOff, int nYOff, int nXSize, int nYSize,
                                    void * pData, int nBufXSize, int nBufYSize,
                                    GDALDataType eBufType,
-                                   int nPixelSpace, int nLineSpace )
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GDALRasterIOExtraArg* psExtraArg)
     
 {
 /* -------------------------------------------------------------------- */
@@ -624,7 +628,7 @@ CPLErr MrSIDRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff,
                                           nXSize, nYSize, pData,
                                           nBufXSize, nBufYSize, eBufType,
-                                          nPixelSpace, nLineSpace );
+                                          nPixelSpace, nLineSpace, psExtraArg );
     }
 
 /* -------------------------------------------------------------------- */
@@ -632,7 +636,7 @@ CPLErr MrSIDRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 /* -------------------------------------------------------------------- */
     return poGDS->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, 
                              nBufXSize, nBufYSize, eBufType, 
-                             1, &nBand, nPixelSpace, nLineSpace, 0 );
+                             1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg );
 }
 
 /************************************************************************/
@@ -823,7 +827,9 @@ CPLErr MrSIDDataset::IRasterIO( GDALRWFlag eRWFlag,
                                 void * pData, int nBufXSize, int nBufYSize,
                                 GDALDataType eBufType, 
                                 int nBandCount, int *panBandMap,
-                                int nPixelSpace, int nLineSpace, int nBandSpace )
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GSpacing nBandSpace,
+                                GDALRasterIOExtraArg* psExtraArg )
 
 {
 /* -------------------------------------------------------------------- */
@@ -844,7 +850,7 @@ CPLErr MrSIDDataset::IRasterIO( GDALRWFlag eRWFlag,
         return GDALDataset::BlockBasedRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     CPLDebug( "MrSID", "RasterIO() - using optimized dataset level IO." );
     
 /* -------------------------------------------------------------------- */
@@ -1446,10 +1452,10 @@ static GDALDataset* JP2Open( GDALOpenInfo *poOpenInfo )
 
 GDALDataset *MrSIDDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJP2 )
 {
-    if(poOpenInfo->fp)
+    if(poOpenInfo->fpL)
     {
-        VSIFClose( poOpenInfo->fp );
-        poOpenInfo->fp = NULL;
+        VSIFCloseL( poOpenInfo->fpL );
+        poOpenInfo->fpL = NULL;
     }
 
 /* -------------------------------------------------------------------- */
@@ -2551,8 +2557,7 @@ void MrSIDDataset::GetGTIFDefn()
                             &dfInvFlattening ) == 1 )
     {
         if( dfInvFlattening != 0.0 )
-            psDefn->SemiMinor = 
-                psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
+            psDefn->SemiMinor = OSRCalcSemiMinorFromInvFlattening(psDefn->SemiMajor, dfInvFlattening);
     }
 
 /* -------------------------------------------------------------------- */
@@ -2744,11 +2749,8 @@ char *MrSIDDataset::GetOGISDefn( GTIFDefn *psDefn )
         dfSemiMajor = SRS_WGS84_SEMIMAJOR;
         dfInvFlattening = SRS_WGS84_INVFLATTENING;
     }
-    else if( (psDefn->SemiMinor / psDefn->SemiMajor) < 0.99999999999999999
-             || (psDefn->SemiMinor / psDefn->SemiMajor) > 1.00000000000000001 )
-        dfInvFlattening = -1.0 / (psDefn->SemiMinor/psDefn->SemiMajor - 1.0);
     else
-        dfInvFlattening = 0.0; /* special flag for infinity */
+        dfInvFlattening = OSRCalcInvFlattening(psDefn->SemiMajor,psDefn->SemiMinor);
 
     oSRS.SetGeogCS( pszGeogName, pszDatumName, 
                     pszSpheroidName, dfSemiMajor, dfInvFlattening,
@@ -3146,7 +3148,7 @@ LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer& stripData,
 
     poDS->RasterIO( GF_Read, nXOff, nYOff, nBufXSize, nBufYSize, 
                     pData, nBufXSize, nBufYSize, eDataType, nBands, NULL, 
-                    0, 0, 0 );
+                    0, 0, 0, NULL );
 
     stripData.importDataBSQ( pData );
     CPLFree( pData );
@@ -3259,7 +3261,7 @@ MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         // check for compression option
         const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
         if( pszValue != NULL )
-            poMG2ImageWriter->params().setCompressionRatio( (float)atof(pszValue) );
+            poMG2ImageWriter->params().setCompressionRatio( (float)CPLAtof(pszValue) );
 
         poImageWriter = poMG2ImageWriter;
 
@@ -3394,9 +3396,9 @@ MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     delete poImageWriter;
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = (GDALPamDataset *) 
+    GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
@@ -3497,7 +3499,7 @@ JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     // check for compression option
     const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
     if( pszValue != NULL )
-        oImageWriter.params().setCompressionRatio( (float)atof(pszValue) );
+        oImageWriter.params().setCompressionRatio( (float)CPLAtof(pszValue) );
         
     pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
     if( pszValue != NULL )
@@ -3523,9 +3525,9 @@ JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                   getLastStatusString( eStat ) );
         return NULL;
     }
-  
+
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     GDALPamDataset *poDS = (GDALPamDataset*) JP2Open(&oOpenInfo);
@@ -3558,6 +3560,7 @@ void GDALRegister_MrSID()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "MrSID" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                         "Multi-resolution Seamless Image Database (MrSID)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_mrsid.html" );
@@ -3601,6 +3604,7 @@ void GDALRegister_MrSID()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "JP2MrSID" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                         "MrSID JPEG2000" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_jp2mrsid.html" );
diff --git a/frmts/mrsid_lidar/GNUmakefile b/frmts/mrsid_lidar/GNUmakefile
index eee7b86..26a6fd9 100644
--- a/frmts/mrsid_lidar/GNUmakefile
+++ b/frmts/mrsid_lidar/GNUmakefile
@@ -2,7 +2,7 @@ include ../../GDALmake.opt
 
 OBJ		=	gdal_MG4Lidar.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(MRSID_LIDAR_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(MRSID_LIDAR_INCLUDE) $(CPPFLAGS)
 
 PLUGIN_SO	=	gdal_MG4Lidar.so
 
diff --git a/frmts/mrsid_lidar/gdal_MG4Lidar.cpp b/frmts/mrsid_lidar/gdal_MG4Lidar.cpp
index 4e88df0..6b3f5db 100644
--- a/frmts/mrsid_lidar/gdal_MG4Lidar.cpp
+++ b/frmts/mrsid_lidar/gdal_MG4Lidar.cpp
@@ -214,7 +214,7 @@ default:
       {
          papszParams = CSLTokenizeString(poxmlMethod->psChild->pszValue);
          if (!EQUAL(papszParams[0], "MAX"))
-            nodatavalue = atof(papszParams[0]);
+            nodatavalue = CPLAtof(papszParams[0]);
       }
       // else if .... Add support for other interpolation methods here.
       CSLDestroy(papszParams);
@@ -695,7 +695,7 @@ GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )
    CPLSetConfigOption( "CPL_LOG", "C:\\ArcGIS_GDAL\\jdem\\cpl.log" );
 #endif
 
-   if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 32 )
+   if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 32 )
       return NULL;
 
    CPLXMLNode *pxmlPCView;
@@ -747,7 +747,7 @@ GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )
    /*      Check that particular fields in the header are valid looking    */
    /*      dates.                                                          */
    /* -------------------------------------------------------------------- */
-   if( openinfo.fp == NULL || openinfo.nHeaderBytes < 50 )
+   if( openinfo.fpL == NULL || openinfo.nHeaderBytes < 50 )
    {
       CPLDestroyXMLNode(pxmlPCView);
       return NULL;
@@ -817,19 +817,19 @@ GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )
          return NULL;
       }
       if (!EQUAL(papszClipExtent[0], "NOFILTER"))
-         bounds.x.min = atof(papszClipExtent[0]);
+         bounds.x.min = CPLAtof(papszClipExtent[0]);
       if (!EQUAL(papszClipExtent[1], "NOFILTER"))
-         bounds.x.max = atof(papszClipExtent[1]);
+         bounds.x.max = CPLAtof(papszClipExtent[1]);
       if (!EQUAL(papszClipExtent[2], "NOFILTER"))
-         bounds.y.min = atof(papszClipExtent[2]);
+         bounds.y.min = CPLAtof(papszClipExtent[2]);
       if (!EQUAL(papszClipExtent[3], "NOFILTER"))
-         bounds.y.max = atof(papszClipExtent[3]);
+         bounds.y.max = CPLAtof(papszClipExtent[3]);
       if (cslcount == 6)
       {
          if (!EQUAL(papszClipExtent[4], "NOFILTER"))
-            bounds.z.min = atof(papszClipExtent[4]);
+            bounds.z.min = CPLAtof(papszClipExtent[4]);
          if (!EQUAL(papszClipExtent[5], "NOFILTER"))
-            bounds.z.max = atof(papszClipExtent[5]);
+            bounds.z.max = CPLAtof(papszClipExtent[5]);
       }
       CSLDestroy(papszClipExtent);
    }
@@ -854,7 +854,7 @@ GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo )
    double cell_side = average_pt_spacing;
    const char * pszCellSize = CPLGetXMLValue(pxmlPCView, "CellSize", NULL);
    if (pszCellSize)
-      cell_side = atof(pszCellSize);
+      cell_side = CPLAtof(pszCellSize);
    MaxRasterSize = MAX(poDS->reader->getBounds().x.length()/cell_side, poDS->reader->getBounds().y.length()/cell_side);
 
    RELEASE(r);
@@ -924,6 +924,7 @@ void GDALRegister_MG4Lidar()
       poDriver = new GDALDriver();
 
       poDriver->SetDescription( "MG4Lidar" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
       poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
          "MrSID Generation 4 / Lidar (.sid)" );
       // To do:  update this help file in gdal.org
diff --git a/frmts/msg/GNUmakefile b/frmts/msg/GNUmakefile
index 6878c66..fef39bc 100644
--- a/frmts/msg/GNUmakefile
+++ b/frmts/msg/GNUmakefile
@@ -10,7 +10,7 @@ WTOBJ=$(subst PublicDecompWT/COMP/WT/Src/, ,$(OBJ1)) $(subst PublicDecompWT/COMP
 
 OBJ	=	msgdataset.o xritheaderparser.o prologue.o msgcommand.o reflectancecalculator.o $(WTOBJ)
 
-CPPFLAGS	=	$(GDAL_INCLUDE) -I PublicDecompWT/DISE -I PublicDecompWT/COMP/WT/Inc -I PublicDecompWT/COMP/Inc -I.
+CPPFLAGS	=	 -I PublicDecompWT/DISE -I PublicDecompWT/COMP/WT/Inc -I PublicDecompWT/COMP/Inc -I.
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/msg/msgcommand.cpp b/frmts/msg/msgcommand.cpp
index 020aaee..84640a9 100644
--- a/frmts/msg/msgcommand.cpp
+++ b/frmts/msg/msgcommand.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: msgcommand.cpp 27371 2014-05-21 09:35:42Z rouault $
+ * $Id: msgcommand.cpp 27370 2014-05-21 09:34:50Z rouault $
  *
  * Purpose:  Implementation of MSGCommand class. Parse the src_dataset
  *           string that is meant for the MSG driver.
diff --git a/frmts/msg/msgdataset.cpp b/frmts/msg/msgdataset.cpp
index 6125b6a..0f0271e 100644
--- a/frmts/msg/msgdataset.cpp
+++ b/frmts/msg/msgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: msgdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: msgdataset.cpp 27477 2014-06-28 15:23:40Z rouault $
  *
  * Project:  MSG Driver
  * Purpose:  GDALDataset driver for MSG translator for read support.
@@ -248,6 +248,7 @@ GDALDataset *MSGDataset::Open( GDALOpenInfo * poOpenInfo )
 
     poDS->oSRS.SetGEOS(  0, 35785831, 0, 0 );
     poDS->oSRS.SetWellKnownGeogCS( "WGS84" ); // Temporary line to satisfy ERDAS (otherwise the ellips is "unnamed"). Eventually this should become the custom a and b ellips (CGMS).
+    CPLFree( poDS->pszProjection );
     poDS->oSRS.exportToWkt( &(poDS->pszProjection) );
 
     // The following are 3 different try-outs for also setting the ellips a and b parameters.
@@ -276,8 +277,13 @@ GDALDataset *MSGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 
     char *pszLLTemp;
+    char *pszLLTemp_bak;
+
     (poDS->oSRS.GetAttrNode("GEOGCS"))->exportToWkt(&pszLLTemp);
+    pszLLTemp_bak = pszLLTemp; // importFromWkt() changes the pointer
     poDS->oLL.importFromWkt(&pszLLTemp);
+    CPLFree( pszLLTemp_bak );
+
     poDS->poTransform = OGRCreateCoordinateTransformation( &(poDS->oSRS), &(poDS->oLL) );
 
 /* -------------------------------------------------------------------- */
@@ -744,6 +750,7 @@ void GDALRegister_MSG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "MSG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "MSG HRIT Data" );
 
diff --git a/frmts/msgn/GNUmakefile b/frmts/msgn/GNUmakefile
index 99d309a..9118d2e 100644
--- a/frmts/msgn/GNUmakefile
+++ b/frmts/msgn/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ    =       msgndataset.o msg_basic_types.o msg_reader_core.o
 
-CPPFLAGS :=	$(GDAL_INCLUDE) $(CPPFLAGS) -I. -DGDAL_SUPPORT
+CPPFLAGS :=	 $(CPPFLAGS) -I. -DGDAL_SUPPORT
 
 default:       $(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/msgn/msg_basic_types.cpp b/frmts/msgn/msg_basic_types.cpp
index 2873530..93e15ad 100644
--- a/frmts/msgn/msg_basic_types.cpp
+++ b/frmts/msgn/msg_basic_types.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: msg_basic_types.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: msg_basic_types.cpp 28435 2015-02-07 14:35:34Z rouault $
  *
  * Project:  MSG Native Reader
  * Purpose:  Basic types implementation.
@@ -30,7 +30,7 @@
 #include "msg_basic_types.h"
 #include "cpl_port.h"
 
-CPL_CVSID("$Id: msg_basic_types.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: msg_basic_types.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 #include <stdio.h>
 
@@ -75,18 +75,17 @@ void to_native(IMAGE_DESCRIPTION_RECORD& r) {
     r.referencegrid_visir.numberOfLines = CPL_MSBWORD32(r.referencegrid_visir.numberOfLines);
     r.referencegrid_visir.numberOfColumns = CPL_MSBWORD32(r.referencegrid_visir.numberOfColumns);
     // should floats be swapped too?
-    unsigned int t;
-
-    // convert float using CPL_MSBWORD32
-    // TODO: Fix strict aliasing issue
-    t = *(unsigned int *)&r.referencegrid_visir.lineDirGridStep;
-    t = CPL_MSBWORD32(t);
-    r.referencegrid_visir.lineDirGridStep = *(float *)&t;
-
-    // convert float using CPL_MSBWORD32
-    t = *(unsigned int *)&r.referencegrid_visir.columnDirGridStep;
-    t = CPL_MSBWORD32(t);
-    r.referencegrid_visir.columnDirGridStep = *(float *)&t;
+    float f;
+
+    // convert float using CPL_MSBPTR32
+    memcpy(&f, &r.referencegrid_visir.lineDirGridStep, sizeof(f));
+    CPL_MSBPTR32(&f);
+    r.referencegrid_visir.lineDirGridStep = f;
+
+    // convert float using CPL_MSBPTR32
+    memcpy(&f, &r.referencegrid_visir.columnDirGridStep, sizeof(f));
+    CPL_MSBPTR32(&f);
+    r.referencegrid_visir.columnDirGridStep = f;
 }
 
 void to_string(PH_DATA& d) {
diff --git a/frmts/msgn/msgndataset.cpp b/frmts/msgn/msgndataset.cpp
index 2f7b731..2446525 100644
--- a/frmts/msgn/msgndataset.cpp
+++ b/frmts/msgn/msgndataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: msgndataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: msgndataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  MSG Native Reader
  * Purpose:  All code for EUMETSAT Archive format reader
@@ -34,7 +34,7 @@
 #include "msg_reader_core.h"
 using namespace msg_native_format;
 
-CPL_CVSID("$Id: msgndataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: msgndataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void   GDALRegister_MSGN(void);
@@ -155,8 +155,10 @@ MSGNRasterBand::MSGNRasterBand( MSGNDataset *poDS, int nBand , open_mode_type mo
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr MSGNRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr MSGNRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void * pImage )
+
 {
     MSGNDataset *poGDS = (MSGNDataset *) poDS;
 
@@ -356,7 +358,7 @@ GDALDataset *MSGNDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      least one "\n#keyword" type signature in the first chunk of     */
 /*      the file.                                                       */
 /* -------------------------------------------------------------------- */
-    if( open_info->fp == NULL || open_info->nHeaderBytes < 50 )
+    if( open_info->fpL == NULL || open_info->nHeaderBytes < 50 )
         return NULL;
 
     /* check if this is a "NATIVE" MSG format image */
@@ -381,11 +383,13 @@ GDALDataset *MSGNDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Create a corresponding GDALDataset.                             */
 /* -------------------------------------------------------------------- */
     MSGNDataset        *poDS;
+    FILE* fp = VSIFOpen( open_info->pszFilename, "rb" );
+    if( fp == NULL )
+        return NULL;
 
     poDS = new MSGNDataset();
 
-    poDS->fp = open_info->fp;
-    open_info->fp = NULL;
+    poDS->fp = fp;
 
 /* -------------------------------------------------------------------- */
 /*      Read the header.                                                */
@@ -528,6 +532,7 @@ void GDALRegister_MSGN()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "MSGN" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "EUMETSAT Archive native (.nat)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/netcdf/GNUmakefile b/frmts/netcdf/GNUmakefile
index 42c56a7..e069067 100644
--- a/frmts/netcdf/GNUmakefile
+++ b/frmts/netcdf/GNUmakefile
@@ -17,7 +17,7 @@ ifeq ($(HAVE_HDF5),yes)
 XTRA_OPT := -DHAVE_HDF5 $(XTRA_OPT)
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT) 
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT) 
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/netcdf/frmt_netcdf.html b/frmts/netcdf/frmt_netcdf.html
index bc4d479..b595e6a 100644
--- a/frmts/netcdf/frmt_netcdf.html
+++ b/frmts/netcdf/frmt_netcdf.html
@@ -305,6 +305,7 @@ The driver has undergone significant changes in GDAL 1.9.0, see NEWS file and <a
 <li><p>Added support for valid_range/valid_min/valid_max</p></li>
 <li><p>Proper handling of signed/unsigned byte data</p></li>
 <li><p>Added support for Create() function - enables to use netcdf directly with gdalwarp</p></li>
+<li><p>Added support for CF two-dimensional coordinate variables (see <a href="http://cfconventions.org/1.6.html#idp5559280">CF Conventions</a>) via GDAL GEOLOCATION arrays (see <a href="https://trac.osgeo.org/gdal/wiki/rfc4_geolocate">RFC 4: Geolocation Arrays</a>) (GDAL >= 1.10)</p></li>
 </ul>
 
 <h3>Creation Options</h3>
diff --git a/frmts/netcdf/gmtdataset.cpp b/frmts/netcdf/gmtdataset.cpp
index b09e205..0148456 100644
--- a/frmts/netcdf/gmtdataset.cpp
+++ b/frmts/netcdf/gmtdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gmtdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gmtdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  netCDF read/write Driver
  * Purpose:  GDAL bindings over netCDF library for GMT Grids.
@@ -33,9 +33,9 @@
 #include "netcdf.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gmtdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gmtdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
-extern void *hNCMutex; /* shared with netcdf. See netcdfdataset.cpp */
+extern CPLMutex *hNCMutex; /* shared with netcdf. See netcdfdataset.cpp */
 
 /************************************************************************/
 /* ==================================================================== */
@@ -211,7 +211,7 @@ GDALDataset *GMTDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Does this file have the GMT magic number?                    */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )
+    if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 50 )
         return NULL;
 
     if( poOpenInfo->pabyHeader[0] != 'C' 
@@ -372,7 +372,7 @@ GDALDataset *GMTDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
     CPLAcquireMutex(hNCMutex, 1000.0);
 
     return( poDS );
@@ -557,7 +557,7 @@ GMTCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     {
         start[0] = iLine * nXSize;
         poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
-                          padfData, nXSize, 1, GDT_Float64, 0, 0 );
+                          padfData, nXSize, 1, GDT_Float64, 0, 0, NULL );
         err = nc_put_vara_double( cdfid, z_id, start, edge, padfData );
         if( err != NC_NOERR )
         {
@@ -577,9 +577,9 @@ GMTCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     nc_close (cdfid);
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = (GDALPamDataset *) 
+    GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
@@ -605,6 +605,7 @@ void GDALRegister_GMT()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GMT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "GMT NetCDF Grid Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/netcdf/netcdfdataset.cpp b/frmts/netcdf/netcdfdataset.cpp
index 5c7d7a8..40d1cc3 100644
--- a/frmts/netcdf/netcdfdataset.cpp
+++ b/frmts/netcdf/netcdfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: netcdfdataset.cpp 28365 2015-01-27 10:39:30Z rouault $
+ * $Id: netcdfdataset.cpp 28823 2015-03-30 14:18:13Z rouault $
  *
  * Project:  netCDF read/write Driver
  * Purpose:  GDAL bindings over netCDF library.
@@ -33,7 +33,7 @@
 #include "cpl_error.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: netcdfdataset.cpp 28365 2015-01-27 10:39:30Z rouault $");
+CPL_CVSID("$Id: netcdfdataset.cpp 28823 2015-03-30 14:18:13Z rouault $");
 
 #include <map> //for NCDFWriteProjAttribs()
 
@@ -83,7 +83,7 @@ void CopyMetadata( void  *poDS, int fpImage, int CDFVarID,
 // uncomment this for more debug ouput
 // #define NCDF_DEBUG 1
 
-void *hNCMutex = NULL;
+CPLMutex *hNCMutex = NULL;
 
 /************************************************************************/
 /* ==================================================================== */
@@ -447,6 +447,15 @@ netCDFRasterBand::netCDFRasterBand( netCDFDataset *poNCDFDS,
         }
 	} 		
 #endif
+
+/* -------------------------------------------------------------------- */
+/*      Force block size to 1 scanline for bottom-up datasets if        */
+/*      nBlockYSize != 1                                                */
+/* -------------------------------------------------------------------- */
+    if( poNCDFDS->bBottomUp && nBlockYSize != 1 ) {
+        nBlockXSize = nRasterXSize;
+        nBlockYSize = 1;
+    }
 }
 
 /* constructor in create mode */
@@ -1004,14 +1013,14 @@ CPLErr netCDFRasterBand::CreateBandMetadata( int *paDimIds )
                     status =  nc_get_vara_float( cdfid, nVarID, 
                                                  start,
                                                  count, &fData );
-                    sprintf( szMetaTemp,"%.8g", fData );
+                    CPLsprintf( szMetaTemp,"%.8g", fData );
                     break;
                 case NC_DOUBLE:
                     double dfData;
                     status =  nc_get_vara_double( cdfid, nVarID, 
                                                   start,
                                                   count, &dfData);
-                    sprintf( szMetaTemp,"%.16g", dfData );
+                    CPLsprintf( szMetaTemp,"%.16g", dfData );
                     break;
                 default: 
                     CPLDebug( "GDAL_netCDF", "invalid dim %s, type=%d", 
@@ -1990,8 +1999,8 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                         if( dfSemiMajorAxis < 0.0 )
                             dfSemiMajorAxis = dfEarthRadius;
                         //set inv_flat using semi_minor/major
-                        dfInverseFlattening = 
-                            1.0 / ( dfSemiMajorAxis - dfSemiMinorAxis ) / dfSemiMajorAxis;
+                        dfInverseFlattening = OSRCalcInvFlattening(dfSemiMajorAxis, dfSemiMinorAxis);
+
                         oSRS.SetGeogCS( "unknown", 
                                         NULL, 
                                         "Spheroid", 
@@ -2892,12 +2901,12 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                     papszGeoTransform = CSLTokenizeString2( pszGeoTransform,
                                                             " ", 
                                                             CSLT_HONOURSTRINGS );
-                    adfTempGeoTransform[0] = atof( papszGeoTransform[0] );
-                    adfTempGeoTransform[1] = atof( papszGeoTransform[1] );
-                    adfTempGeoTransform[2] = atof( papszGeoTransform[2] );
-                    adfTempGeoTransform[3] = atof( papszGeoTransform[3] );
-                    adfTempGeoTransform[4] = atof( papszGeoTransform[4] );
-                    adfTempGeoTransform[5] = atof( papszGeoTransform[5] );
+                    adfTempGeoTransform[0] = CPLAtof( papszGeoTransform[0] );
+                    adfTempGeoTransform[1] = CPLAtof( papszGeoTransform[1] );
+                    adfTempGeoTransform[2] = CPLAtof( papszGeoTransform[2] );
+                    adfTempGeoTransform[3] = CPLAtof( papszGeoTransform[3] );
+                    adfTempGeoTransform[4] = CPLAtof( papszGeoTransform[4] );
+                    adfTempGeoTransform[5] = CPLAtof( papszGeoTransform[5] );
                     
 /* -------------------------------------------------------------------- */
 /*      Look for corner array values                                    */
@@ -2912,7 +2921,7 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                     strcat( szTemp, "Northernmost_Northing");
                     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);                    
                     if( pszValue != NULL ) {
-                        dfNN = atof( pszValue );
+                        dfNN = CPLAtof( pszValue );
                         bGotNN = TRUE;
                     }
 
@@ -2921,7 +2930,7 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                     strcat( szTemp, "Southernmost_Northing");
                     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);                    
                     if( pszValue != NULL ) {
-                        dfSN = atof( pszValue );
+                        dfSN = CPLAtof( pszValue );
                         bGotSN = TRUE;
                     }
                     
@@ -2930,7 +2939,7 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                     strcat( szTemp, "Easternmost_Easting");
                     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);                    
                     if( pszValue != NULL ) {
-                        dfEE = atof( pszValue );
+                        dfEE = CPLAtof( pszValue );
                         bGotEE = TRUE;
                     }
                     
@@ -2939,7 +2948,7 @@ void netCDFDataset::SetProjectionFromVar( int nVarId )
                     strcat( szTemp, "Westernmost_Easting");
                     pszValue = CSLFetchNameValue(poDS->papszMetadata, szTemp);                    
                     if( pszValue != NULL ) {
-                        dfWE = atof( pszValue ); 
+                        dfWE = CPLAtof( pszValue ); 
                         bGotWE = TRUE;
                     }
                     
@@ -3138,7 +3147,7 @@ double *netCDFDataset::Get1DGeolocation( CPL_UNUSED const char *szDimName, int &
     for(int i=0, j=0; i < nVarLen; i++) { 
         if ( ! bBottomUp ) j=nVarLen - 1 - i;
         else j=i; /* invert latitude values */
-        pdfVarValues[j] = strtod( papszValues[i], &pszTemp );
+        pdfVarValues[j] = CPLStrtod( papszValues[i], &pszTemp );
     }
     CSLDestroy( papszValues );
 
@@ -3540,7 +3549,7 @@ CPLErr netCDFDataset::AddProjectionVars( GDALProgressFunc pfnProgress,
             
             *szGeoTransform = '\0';
             for( int i=0; i<6; i++ ) {
-                sprintf( szTemp, "%.16g ",
+                CPLsprintf( szTemp, "%.16g ",
                          adfGeoTransform[i] );
                 strcat( szGeoTransform, szTemp );
             }
@@ -4230,8 +4239,11 @@ void netCDFDataset::CreateSubDatasetList( )
 /*                              IdentifyFormat()                      */
 /************************************************************************/
 
-int netCDFDataset::IdentifyFormat( GDALOpenInfo * poOpenInfo, bool bCheckExt = TRUE )
-
+int netCDFDataset::IdentifyFormat( GDALOpenInfo * poOpenInfo, 
+#ifndef HAVE_HDF5
+CPL_UNUSED
+#endif
+                                   bool bCheckExt = TRUE )
 {
 /* -------------------------------------------------------------------- */
 /*      Does this appear to be a netcdf file? If so, which format?      */
@@ -4243,7 +4255,29 @@ int netCDFDataset::IdentifyFormat( GDALOpenInfo * poOpenInfo, bool bCheckExt = T
     if ( poOpenInfo->nHeaderBytes < 4 )
         return NCDF_FORMAT_NONE;
     if ( EQUALN((char*)poOpenInfo->pabyHeader,"CDF\001",4) )
+    {
+        /* In case the netCDF driver is registered before the GMT driver, */
+        /* avoid opening GMT files */
+        if( GDALGetDriverByName("GMT") != NULL )
+        {
+            int bFoundZ = FALSE, bFoundDimension = FALSE;
+            for(int i=0;i<poOpenInfo->nHeaderBytes - 11;i++)
+            {
+                if( poOpenInfo->pabyHeader[i] == 1 &&
+                    poOpenInfo->pabyHeader[i+1] == 'z' &&
+                    poOpenInfo->pabyHeader[i+2] == 0  )
+                    bFoundZ = TRUE;
+                else if( poOpenInfo->pabyHeader[i] == 9 &&
+                        memcmp((const char*)poOpenInfo->pabyHeader + i + 1, "dimension", 9) == 0 &&
+                        poOpenInfo->pabyHeader[i+10] == 0 )
+                    bFoundDimension = TRUE;
+            }
+            if( bFoundZ && bFoundDimension )
+                return NCDF_FORMAT_UNKNOWN;
+        }
+
         return NCDF_FORMAT_NC;
+    }
     else if ( EQUALN((char*)poOpenInfo->pabyHeader,"CDF\002",4) )
         return NCDF_FORMAT_NC2;
     else if ( EQUALN((char*)poOpenInfo->pabyHeader,"\211HDF\r\n\032\n",8) ) {
@@ -4654,6 +4688,7 @@ GDALDataset *netCDFDataset::Open( GDALOpenInfo * poOpenInfo )
     if( !bTreatAsSubdataset ) // nCount must be 1!
     {
         char szVarName[NC_MAX_NAME];
+        szVarName[0] = '\0';
         nc_inq_varname( cdfid, nVarID, szVarName);
         osSubdatasetName = szVarName;
     }
@@ -5223,7 +5258,7 @@ CPLErr  NCDFCopyBand( GDALRasterBand *poSrcBand, GDALRasterBand *poDstBand,
     for( int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++ )  {                
         eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                     patScanline, nXSize, 1, eDT,
-                                    0,0);
+                                    0,0, NULL);
         if ( eErr != CE_None )
             CPLDebug( "GDAL_netCDF", 
                       "NCDFCopyBand(), poSrcBand->RasterIO() returned error code %d",
@@ -5231,7 +5266,7 @@ CPLErr  NCDFCopyBand( GDALRasterBand *poSrcBand, GDALRasterBand *poDstBand,
         else { 
             eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1, 
                                         patScanline, nXSize, 1, eDT,
-                                        0,0);
+                                        0,0, NULL);
             if ( eErr != CE_None )
                 CPLDebug( "GDAL_netCDF", 
                           "NCDFCopyBand(), poDstBand->RasterIO() returned error code %d",
@@ -5753,7 +5788,13 @@ netCDFDataset::ProcessCreationOptions( )
 
 }
 
-int netCDFDataset::DefVarDeflate( int nVarId, int bChunkingArg )
+int netCDFDataset::DefVarDeflate(
+#ifdef NETCDF_HAS_NC4
+            int nVarId, int bChunkingArg
+#else
+            CPL_UNUSED int nVarId, CPL_UNUSED int bChunkingArg
+#endif
+            )
 {
 #ifdef NETCDF_HAS_NC4
     if ( nCompress == NCDF_COMPRESS_DEFLATE ) {                         
@@ -5876,6 +5917,7 @@ void GDALRegister_netCDF()
 /*      Set the driver details.                                         */
 /* -------------------------------------------------------------------- */
         poDriver->SetDescription( "netCDF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Network Common Data Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -6133,7 +6175,7 @@ void NCDFWriteProjAttribs( const OGR_SRSNode *poPROJCS,
         pszParamStr = poNode->GetChild(0)->GetValue();
         pszParamVal = poNode->GetChild(1)->GetValue();
 
-        oValMap[pszParamStr] = atof(pszParamVal);
+        oValMap[pszParamStr] = CPLAtof(pszParamVal);
     }
 
     /* Lookup mappings and fill output vector */
@@ -6393,10 +6435,10 @@ CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,
             nc_get_att_float( nCdfId, nVarId, pszAttrName, pfTemp );
             dfValue = (double)pfTemp[0];
             for(m=0; m < nAttrLen-1; m++) {
-                sprintf( szTemp, "%.8g,", pfTemp[m] );
+                CPLsprintf( szTemp, "%.8g,", pfTemp[m] );
                 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
             }
-            sprintf( szTemp, "%.8g", pfTemp[m] );
+            CPLsprintf( szTemp, "%.8g", pfTemp[m] );
             NCDFSafeStrcat(&pszAttrValue,szTemp, &nAttrValueSize);
             CPLFree(pfTemp);
             break;
@@ -6406,10 +6448,10 @@ CPLErr NCDFGetAttr1( int nCdfId, int nVarId, const char *pszAttrName,
             nc_get_att_double( nCdfId, nVarId, pszAttrName, pdfTemp );
             dfValue = pdfTemp[0];
             for(m=0; m < nAttrLen-1; m++) {
-                sprintf( szTemp, "%.16g,", pdfTemp[m] );
+                CPLsprintf( szTemp, "%.16g,", pdfTemp[m] );
                 NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
             }
-            sprintf( szTemp, "%.16g", pdfTemp[m] );
+            CPLsprintf( szTemp, "%.16g", pdfTemp[m] );
             NCDFSafeStrcat(&pszAttrValue, szTemp, &nAttrValueSize);
             CPLFree(pdfTemp);
             break;
@@ -6488,13 +6530,13 @@ CPLErr NCDFPutAttr( int nCdfId, int nVarId,
         else {
             /* test for double */
             errno = 0;
-            dfValue = strtod( papszValues[i], &pszTemp );
+            dfValue = CPLStrtod( papszValues[i], &pszTemp );
             if ( (errno == 0) && (papszValues[i] != pszTemp) && (*pszTemp == 0) ) {
                 /* test for float instead of double */
                 /* strtof() is C89, which is not available in MSVC */
                 /* see if we loose precision if we cast to float and write to char* */
                 fValue = (float)dfValue; 
-                sprintf( szTemp,"%.8g",fValue); 
+                CPLsprintf( szTemp,"%.8g",fValue); 
                 if ( EQUAL(szTemp, papszValues[i] ) )
                     nTmpAttrType = NC_FLOAT;
                 else
@@ -6529,7 +6571,7 @@ CPLErr NCDFPutAttr( int nCdfId, int nVarId,
                 float *pfTemp;
                 pfTemp = (float *) CPLCalloc( nAttrLen, sizeof( float ) );
                 for(i=0; i < nAttrLen; i++) {
-                    pfTemp[i] = (float)strtod( papszValues[i], &pszTemp );
+                    pfTemp[i] = (float)CPLStrtod( papszValues[i], &pszTemp );
                 }
                 status = nc_put_att_float( nCdfId, nVarId, pszAttrName, 
                                            NC_FLOAT, nAttrLen, pfTemp );  
@@ -6540,7 +6582,7 @@ CPLErr NCDFPutAttr( int nCdfId, int nVarId,
                 double *pdfTemp;
                 pdfTemp = (double *) CPLCalloc( nAttrLen, sizeof( double ) );
                 for(i=0; i < nAttrLen; i++) {
-                    pdfTemp[i] = strtod( papszValues[i], &pszTemp );
+                    pdfTemp[i] = CPLStrtod( papszValues[i], &pszTemp );
                 }
                 status = nc_put_att_double( nCdfId, nVarId, pszAttrName, 
                                             NC_DOUBLE, nAttrLen, pdfTemp );
@@ -6642,10 +6684,10 @@ CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )
             pfTemp = (float *) CPLCalloc( nVarLen, sizeof( float ) );
             nc_get_vara_float( nCdfId, nVarId, start, count, pfTemp );
             for(m=0; m < nVarLen-1; m++) {
-                sprintf( szTemp, "%.8g,", pfTemp[m] );
+                CPLsprintf( szTemp, "%.8g,", pfTemp[m] );
                 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
             }
-            sprintf( szTemp, "%.8g", pfTemp[m] );
+            CPLsprintf( szTemp, "%.8g", pfTemp[m] );
             NCDFSafeStrcat(&pszVarValue,szTemp, &nVarValueSize);
             CPLFree(pfTemp);
             break;
@@ -6654,10 +6696,10 @@ CPLErr NCDFGet1DVar( int nCdfId, int nVarId, char **pszValue )
             pdfTemp = (double *) CPLCalloc(nVarLen, sizeof(double));
             nc_get_vara_double( nCdfId, nVarId, start, count, pdfTemp );
             for(m=0; m < nVarLen-1; m++) {
-                sprintf( szTemp, "%.16g,", pdfTemp[m] );
+                CPLsprintf( szTemp, "%.16g,", pdfTemp[m] );
                 NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
             }
-            sprintf( szTemp, "%.16g", pdfTemp[m] );
+            CPLsprintf( szTemp, "%.16g", pdfTemp[m] );
             NCDFSafeStrcat(&pszVarValue, szTemp, &nVarValueSize);
             CPLFree(pdfTemp);
             break;
@@ -6740,7 +6782,7 @@ CPLErr NCDFPut1DVar( int nCdfId, int nVarId, const char *pszValue )
                 float *pfTemp;
                 pfTemp = (float *) CPLCalloc( nVarLen, sizeof( float ) );
                 for(i=0; i < nVarLen; i++) {
-                    pfTemp[i] = (float)strtod( papszValues[i], &pszTemp );
+                    pfTemp[i] = (float)CPLStrtod( papszValues[i], &pszTemp );
                 }
                 status = nc_put_vara_float( nCdfId, nVarId, start, count, 
                                             pfTemp );  
@@ -6751,7 +6793,7 @@ CPLErr NCDFPut1DVar( int nCdfId, int nVarId, const char *pszValue )
                 double *pdfTemp;
                 pdfTemp = (double *) CPLCalloc( nVarLen, sizeof( double ) );
                 for(i=0; i < nVarLen; i++) {
-                    pdfTemp[i] = strtod( papszValues[i], &pszTemp );
+                    pdfTemp[i] = CPLStrtod( papszValues[i], &pszTemp );
                 }
                 status = nc_put_vara_double( nCdfId, nVarId, start, count, 
                                              pdfTemp );
diff --git a/frmts/ngsgeoid/GNUmakefile b/frmts/ngsgeoid/GNUmakefile
index 227eff8..c0273bf 100644
--- a/frmts/ngsgeoid/GNUmakefile
+++ b/frmts/ngsgeoid/GNUmakefile
@@ -3,7 +3,7 @@ OBJ	=	ngsgeoiddataset.o
 
 include ../../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ngsgeoid/ngsgeoiddataset.cpp b/frmts/ngsgeoid/ngsgeoiddataset.cpp
index 406eef0..2ca4d68 100644
--- a/frmts/ngsgeoid/ngsgeoiddataset.cpp
+++ b/frmts/ngsgeoid/ngsgeoiddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ngsgeoiddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ngsgeoiddataset.cpp 28202 2014-12-23 20:12:45Z rouault $
  *
  * Project:  NGSGEOID driver
  * Purpose:  GDALDataset driver for NGSGEOID dataset.
@@ -32,7 +32,7 @@
 #include "gdal_pam.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ngsgeoiddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ngsgeoiddataset.cpp 28202 2014-12-23 20:12:45Z rouault $");
 
 CPL_C_START
 void    GDALRegister_NGSGEOID(void);
@@ -113,7 +113,8 @@ NGSGEOIDRasterBand::NGSGEOIDRasterBand( NGSGEOIDDataset *poDS )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr NGSGEOIDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr NGSGEOIDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
                                        void * pImage )
 
 {
@@ -276,7 +277,7 @@ int NGSGEOIDDataset::GetHeaderInfo( const GByte* pBuffer,
     /*CPLDebug("NGSGEOID", "SLAT=%f, WLON=%f, DLAT=%f, DLON=%f, NLAT=%d, NLON=%d, IKIND=%d",
              dfSLAT, dfWLON, dfDLAT, dfDLON, nNLAT, nNLON, nIKIND);*/
 
-    if (nNLAT <= 0 || nNLON <= 0 || dfDLAT <= 0.0 || dfDLON <= 0.0)
+    if (nNLAT <= 0 || nNLON <= 0 || dfDLAT <= 1e-15 || dfDLON <= 1e-15)
         return FALSE;
 
     /* Grids go over +180 in longitude */
@@ -411,6 +412,7 @@ void GDALRegister_NGSGEOID()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "NGSGEOID" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "NOAA NGS Geoid Height Grids" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -425,4 +427,3 @@ void GDALRegister_NGSGEOID()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/nitf/GNUmakefile b/frmts/nitf/GNUmakefile
index bfcb993..411f933 100644
--- a/frmts/nitf/GNUmakefile
+++ b/frmts/nitf/GNUmakefile
@@ -7,7 +7,7 @@ GDAL_OBJ =	nitfdataset.o rpftocdataset.o nitfwritejpeg.o \
 NITFLIB_OBJ =	nitffile.o nitfimage.o mgrs.o nitfaridpcm.o \
 		nitfbilevel.o rpftocfile.o nitfdes.o nitf_gcprpc.o
 
-CPPFLAGS	:=	-I../vrt -I../gtiff $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../vrt -I../gtiff  $(CPPFLAGS)
 
 ifeq ($(TIFF_SETTING),internal)
 ifeq ($(RENAME_INTERNAL_LIBTIFF_SYMBOLS),yes)
diff --git a/frmts/nitf/ecrgtocdataset.cpp b/frmts/nitf/ecrgtocdataset.cpp
index 3b7f455..01c1de8 100644
--- a/frmts/nitf/ecrgtocdataset.cpp
+++ b/frmts/nitf/ecrgtocdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ecrgtocdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ecrgtocdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  ECRG TOC read Translator
  * Purpose:  Implementation of ECRGTOCDataset and ECRGTOCSubDataset.
@@ -35,7 +35,7 @@
 #include "cpl_minixml.h"
 #include <vector>
 
-CPL_CVSID("$Id: ecrgtocdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ecrgtocdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /** Overview of used classes :
    - ECRGTOCDataset : lists the different subdatasets, listed in the .xml,
@@ -1039,6 +1039,7 @@ void GDALRegister_ECRGTOC()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ECRGTOC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ECRG TOC format" );
         
diff --git a/frmts/nitf/frmt_nitf.html b/frmts/nitf/frmt_nitf.html
index 495146b..45af366 100644
--- a/frmts/nitf/frmt_nitf.html
+++ b/frmts/nitf/frmt_nitf.html
@@ -20,7 +20,7 @@ may be identified.<p>
 
 Lat/Long extents are read from the IGEOLO information in 
 the image header if available.  If high precision lat/long georeferencing 
-information is available in RPF auxilary data it will be used in preference 
+information is available in RPF auxiliary data it will be used in preference 
 to the low precision IGEOLO information.  In case a BLOCKA instance is found, 
 the higher precision coordinates of BLOCKA are used if the block data covers 
 the complete image - that is the L_LINES field with the row count for that 
@@ -35,7 +35,7 @@ metadata.<p>
 <h2>Creation Issues</h2>
 
 On export NITF files are always written as NITF 2.1 with one image
-and no other auxilary layers. Images are uncompressed by default, but JPEG
+and no other auxiliary layers. Images are uncompressed by default, but JPEG
 and JPEG2000 compression are also available. Georeferencing can only be written for 
 images using a geographic coordinate system or a UTM WGS84 projection.  Coordinates are implicitly 
 treated as WGS84 even if they are actually in a different geographic coordinate
diff --git a/frmts/nitf/makefile.vc b/frmts/nitf/makefile.vc
index 5a7da50..90da63d 100644
--- a/frmts/nitf/makefile.vc
+++ b/frmts/nitf/makefile.vc
@@ -23,7 +23,7 @@ JPEG_FLAGS =	-I..\jpeg\libjpeg -DJPEG_SUPPORTED
 JPEG12_FLAGS =  -DJPEG_DUAL_MODE_8_12
 !ENDIF
  	
-EXTRAFLAGS = -I..\gtiff\libtiff -I..\vrt $(JPEG_FLAGS) $(JPEG12_FLAGS)
+EXTRAFLAGS = -I..\gtiff -I..\gtiff\libtiff -I..\vrt $(JPEG_FLAGS) $(JPEG12_FLAGS)
 
 default:	$(OBJ)
 	xcopy /D  /Y *.obj ..\o
diff --git a/frmts/nitf/nitfaridpcm.cpp b/frmts/nitf/nitfaridpcm.cpp
index f0d5894..eea2f16 100644
--- a/frmts/nitf/nitfaridpcm.cpp
+++ b/frmts/nitf/nitfaridpcm.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfaridpcm.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: nitfaridpcm.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  ARIDPCM reading code.
@@ -32,7 +32,7 @@
 #include "nitflib.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: nitfaridpcm.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: nitfaridpcm.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static const int neighbourhood_size_75[4] = { 23, 47, 74, 173 };
 static const int bits_per_level_by_busycode_75[4/*busy code*/][4/*level*/] = { 
@@ -199,11 +199,15 @@ get_bits( unsigned char *buffer, int first_bit, int num_bits )
 /*      Compute the delta value for a particular (i,j) location.        */
 /************************************************************************/
 static int
-get_delta( unsigned char *srcdata, 
+get_delta( unsigned char *srcdata,
            int nInputBytes,
-           int busy_code, CPL_UNUSED int comrat,
-           int block_offset, CPL_UNUSED int block_size, 
-           int i, int j, int *pbError )
+           int busy_code,
+           CPL_UNUSED int comrat,
+           int block_offset,
+           CPL_UNUSED int block_size,
+           int i,
+           int j,
+           int *pbError )
 
 {
     CPLAssert( comrat == CR075 );
diff --git a/frmts/nitf/nitfbilevel.cpp b/frmts/nitf/nitfbilevel.cpp
index ea879e5..115e764 100644
--- a/frmts/nitf/nitfbilevel.cpp
+++ b/frmts/nitf/nitfbilevel.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfbilevel.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nitfbilevel.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  Module implement BILEVEL (C1) compressed image reading.
@@ -38,9 +38,9 @@ CPL_C_START
 #include "tiffio.h"
 CPL_C_END
 
-TIFF* VSI_TIFFOpen(const char* name, const char* mode);
+#include "tifvsi.h"
 
-CPL_CVSID("$Id: nitfbilevel.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: nitfbilevel.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                       NITFUncompressBILEVEL()                        */
@@ -60,9 +60,13 @@ int NITFUncompressBILEVEL( NITFImage *psImage,
 
     osFilename.Printf( "/vsimem/nitf-wrk-%ld.tif", (long) CPLGetPID() );
 
-    TIFF *hTIFF = VSI_TIFFOpen( osFilename, "w+" );
+    VSILFILE* fpL = VSIFOpenL(osFilename, "w+");
+    if( fpL == NULL )
+        return FALSE;
+    TIFF *hTIFF = VSI_TIFFOpen( osFilename, "w+", fpL );
     if (hTIFF == NULL)
     {
+        VSIFCloseL(fpL);
         return FALSE;
     }
 
@@ -91,9 +95,10 @@ int NITFUncompressBILEVEL( NITFImage *psImage,
 /* -------------------------------------------------------------------- */
     int bResult = TRUE;
 
-    hTIFF = VSI_TIFFOpen( osFilename, "r" );
+    hTIFF = VSI_TIFFOpen( osFilename, "r", fpL );
     if (hTIFF == NULL)
     {
+        VSIFCloseL(fpL);
         return FALSE;
     }
 
@@ -105,6 +110,7 @@ int NITFUncompressBILEVEL( NITFImage *psImage,
     }
 
     TIFFClose( hTIFF );
+    VSIFCloseL(fpL);
 
     VSIUnlink( osFilename );
 
diff --git a/frmts/nitf/nitfdataset.cpp b/frmts/nitf/nitfdataset.cpp
index b1ef961..3e3a0f5 100644
--- a/frmts/nitf/nitfdataset.cpp
+++ b/frmts/nitf/nitfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nitfdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  NITF Read/Write Translator
  * Purpose:  NITFDataset and driver related implementations.
@@ -35,7 +35,7 @@
 #include "cpl_string.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: nitfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: nitfdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 static void NITFPatchImageLength( const char *pszFilename,
                                   GUIntBig nImageOffset, 
@@ -494,7 +494,14 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
 /* -------------------------------------------------------------------- */
     NITFFile *psFile;
 
-    psFile = NITFOpen( pszFilename, poOpenInfo->eAccess == GA_Update );
+    if( poOpenInfo->fpL )
+    {
+        VSILFILE* fpL = poOpenInfo->fpL;
+        poOpenInfo->fpL = NULL;
+        psFile = NITFOpenEx( fpL, pszFilename );
+    }
+    else
+        psFile = NITFOpen( pszFilename, poOpenInfo->eAccess == GA_Update );
     if( psFile == NULL )
     {
         return NULL;
@@ -606,13 +613,13 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
         }
         else
         {
-            /* We explicitely list the allowed drivers to avoid hostile content */
+            /* We explicitly list the allowed drivers to avoid hostile content */
             /* to be opened by a random driver, and also to make sure that */
             /* a future new JPEG2000 compatible driver derives from GDALPamDataset */
             static const char * const apszDrivers[] = { "JP2KAK", "JP2ECW", "JP2MRSID",
                                                         "JPEG2000", "JP2OPENJPEG", NULL };
             poDS->poJ2KDataset = (GDALPamDataset *)
-                GDALOpenInternal( osDSName, GA_ReadOnly, apszDrivers);
+                GDALOpenEx( osDSName, GDAL_OF_RASTER, apszDrivers, NULL, NULL);
 
             if( poDS->poJ2KDataset == NULL )
             {
@@ -660,13 +667,13 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
                     bSetColorInterpretation = FALSE;
                 }
                 else if (poDS->poJ2KDataset->GetRasterCount() == 1 &&
-                         psImage->pasBandInfo[0].nSignificantLUTEntries > 0 &&
-                         poDS->poJ2KDataset->GetRasterBand(1)->GetColorTable() == NULL)
+                         psImage->pasBandInfo[0].nSignificantLUTEntries > 0)
                 {
 /* Test case : http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9_j2c.ntf */
 /* 256-entry/LUT in Image Subheader, JP2 header completely removed */
 /* The JPEG2000 driver will decode it as a grey band */
 /* So we must set the color table on the wrapper band */
+/* or for file9_jp2_2places.ntf as well if the J2K driver does do RGB expension */
                     bSetColorTable = TRUE;
                 }
             }
@@ -896,8 +903,8 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
 /*      Try looking for a .nfw file.                                    */
 /* -------------------------------------------------------------------- */
     if( psImage
-        && GDALReadWorldFile( pszFilename, "nfw", 
-                              poDS->adfGeoTransform ) )
+        && GDALReadWorldFile2( pszFilename, "nfw", 
+                              poDS->adfGeoTransform, poOpenInfo->GetSiblingFiles(), NULL ) )
     {
         const char *pszHDR;
         VSILFILE *fpHDR;
@@ -1342,73 +1349,73 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
         char szValue[1280];
         int  i;
 
-        sprintf( szValue, "%.16g", sRPCInfo.LINE_OFF );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LINE_OFF );
         poDS->SetMetadataItem( "LINE_OFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.LINE_SCALE );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LINE_SCALE );
         poDS->SetMetadataItem( "LINE_SCALE", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.SAMP_OFF );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.SAMP_OFF );
         poDS->SetMetadataItem( "SAMP_OFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.SAMP_SCALE );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.SAMP_SCALE );
         poDS->SetMetadataItem( "SAMP_SCALE", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.LONG_OFF );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LONG_OFF );
         poDS->SetMetadataItem( "LONG_OFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.LONG_SCALE );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LONG_SCALE );
         poDS->SetMetadataItem( "LONG_SCALE", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.LAT_OFF );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LAT_OFF );
         poDS->SetMetadataItem( "LAT_OFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.LAT_SCALE );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.LAT_SCALE );
         poDS->SetMetadataItem( "LAT_SCALE", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_OFF );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.HEIGHT_OFF );
         poDS->SetMetadataItem( "HEIGHT_OFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", sRPCInfo.HEIGHT_SCALE );
+        CPLsprintf( szValue, "%.16g", sRPCInfo.HEIGHT_SCALE );
         poDS->SetMetadataItem( "HEIGHT_SCALE", szValue, "RPC" );
 
         szValue[0] = '\0'; 
         for( i = 0; i < 20; i++ )
-            sprintf( szValue+strlen(szValue), "%.16g ",  
+            CPLsprintf( szValue+strlen(szValue), "%.16g ",  
                      sRPCInfo.LINE_NUM_COEFF[i] );
         poDS->SetMetadataItem( "LINE_NUM_COEFF", szValue, "RPC" );
 
         szValue[0] = '\0'; 
         for( i = 0; i < 20; i++ )
-            sprintf( szValue+strlen(szValue), "%.16g ",  
+            CPLsprintf( szValue+strlen(szValue), "%.16g ",  
                      sRPCInfo.LINE_DEN_COEFF[i] );
         poDS->SetMetadataItem( "LINE_DEN_COEFF", szValue, "RPC" );
         
         szValue[0] = '\0'; 
         for( i = 0; i < 20; i++ )
-            sprintf( szValue+strlen(szValue), "%.16g ",  
+            CPLsprintf( szValue+strlen(szValue), "%.16g ",  
                      sRPCInfo.SAMP_NUM_COEFF[i] );
         poDS->SetMetadataItem( "SAMP_NUM_COEFF", szValue, "RPC" );
         
         szValue[0] = '\0'; 
         for( i = 0; i < 20; i++ )
-            sprintf( szValue+strlen(szValue), "%.16g ",  
+            CPLsprintf( szValue+strlen(szValue), "%.16g ",  
                      sRPCInfo.SAMP_DEN_COEFF[i] );
         poDS->SetMetadataItem( "SAMP_DEN_COEFF", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", 
+        CPLsprintf( szValue, "%.16g", 
                  sRPCInfo.LONG_OFF - ( sRPCInfo.LONG_SCALE / 2.0 ) );
         poDS->SetMetadataItem( "MIN_LONG", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g",
+        CPLsprintf( szValue, "%.16g",
                  sRPCInfo.LONG_OFF + ( sRPCInfo.LONG_SCALE / 2.0 ) );
         poDS->SetMetadataItem( "MAX_LONG", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", 
+        CPLsprintf( szValue, "%.16g", 
                  sRPCInfo.LAT_OFF - ( sRPCInfo.LAT_SCALE / 2.0 ) );
         poDS->SetMetadataItem( "MIN_LAT", szValue, "RPC" );
 
-        sprintf( szValue, "%.16g", 
+        CPLsprintf( szValue, "%.16g", 
                  sRPCInfo.LAT_OFF + ( sRPCInfo.LAT_SCALE / 2.0 ) );
         poDS->SetMetadataItem( "MAX_LAT", szValue, "RPC" );
     }
@@ -1423,7 +1430,7 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
     {
         char szValue[1280];
 
-        sprintf( szValue, "%.16g", sChipInfo.SCALE_FACTOR );
+        CPLsprintf( szValue, "%.16g", sChipInfo.SCALE_FACTOR );
         poDS->SetMetadataItem( "ICHIP_SCALE_FACTOR", szValue );
 
         sprintf( szValue, "%d", sChipInfo.ANAMORPH_CORR );
@@ -1432,52 +1439,52 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
         sprintf( szValue, "%d", sChipInfo.SCANBLK_NUM );
         poDS->SetMetadataItem( "ICHIP_SCANBLK_NUM", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_ROW_11 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_ROW_11 );
         poDS->SetMetadataItem( "ICHIP_OP_ROW_11", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_COL_11 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_COL_11 );
         poDS->SetMetadataItem( "ICHIP_OP_COL_11", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_ROW_12 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_ROW_12 );
         poDS->SetMetadataItem( "ICHIP_OP_ROW_12", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_COL_12 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_COL_12 );
         poDS->SetMetadataItem( "ICHIP_OP_COL_12", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_ROW_21 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_ROW_21 );
         poDS->SetMetadataItem( "ICHIP_OP_ROW_21", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_COL_21 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_COL_21 );
         poDS->SetMetadataItem( "ICHIP_OP_COL_21", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_ROW_22 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_ROW_22 );
         poDS->SetMetadataItem( "ICHIP_OP_ROW_22", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.OP_COL_22 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.OP_COL_22 );
         poDS->SetMetadataItem( "ICHIP_OP_COL_22", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_ROW_11 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_ROW_11 );
         poDS->SetMetadataItem( "ICHIP_FI_ROW_11", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_COL_11 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_COL_11 );
         poDS->SetMetadataItem( "ICHIP_FI_COL_11", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_ROW_12 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_ROW_12 );
         poDS->SetMetadataItem( "ICHIP_FI_ROW_12", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_COL_12 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_COL_12 );
         poDS->SetMetadataItem( "ICHIP_FI_COL_12", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_ROW_21 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_ROW_21 );
         poDS->SetMetadataItem( "ICHIP_FI_ROW_21", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_COL_21 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_COL_21 );
         poDS->SetMetadataItem( "ICHIP_FI_COL_21", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_ROW_22 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_ROW_22 );
         poDS->SetMetadataItem( "ICHIP_FI_ROW_22", szValue );
 
-        sprintf( szValue, "%.16g", sChipInfo.FI_COL_22 );
+        CPLsprintf( szValue, "%.16g", sChipInfo.FI_COL_22 );
         poDS->SetMetadataItem( "ICHIP_FI_COL_22", szValue );
 
         sprintf( szValue, "%d", sChipInfo.FI_ROW );
@@ -1552,7 +1559,7 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
     }
 
     poDS->bInLoadXML = TRUE;
-    poDS->TryLoadXML();
+    poDS->TryLoadXML(poOpenInfo->GetSiblingFiles());
     poDS->bInLoadXML = FALSE;
 
 /* -------------------------------------------------------------------- */
@@ -1564,7 +1571,7 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
 
     if( pszOverviewFile == NULL )
     {
-        if( poDS->CheckForRSets(pszFilename) )
+        if( poDS->CheckForRSets(pszFilename, poOpenInfo->GetSiblingFiles()) )
             pszOverviewFile = poDS->osRSetVRT;
     }        
 
@@ -1600,7 +1607,7 @@ GDALDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo,
     if( !EQUAL(poOpenInfo->pszFilename,pszFilename) )
         poDS->oOvManager.Initialize( poDS, ":::VIRTUAL:::" );
     else
-        poDS->oOvManager.Initialize( poDS, pszFilename );
+        poDS->oOvManager.Initialize( poDS, pszFilename, poOpenInfo->GetSiblingFiles() );
 
     /* If there are PAM overviews, don't expose the underlying JPEG dataset */
     /* overviews (in case of monoblock C3) */
@@ -1750,10 +1757,10 @@ void NITFDataset::CheckGeoSDEInfo()
         return;
     }
     for( i = 0; i < nParmCount; i++ )
-        adfParm[i] = atof(NITFGetField(szParm,pszPRJPSB,83+15*i,15));
+        adfParm[i] = CPLAtof(NITFGetField(szParm,pszPRJPSB,83+15*i,15));
 
-    dfFE = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount,15));
-    dfFN = atof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount+15,15));
+    dfFE = CPLAtof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount,15));
+    dfFN = CPLAtof(NITFGetField(szParm,pszPRJPSB,83+15*nParmCount+15,15));
 
 /* -------------------------------------------------------------------- */
 /*      Try to handle the projection.                                   */
@@ -1882,12 +1889,12 @@ void NITFDataset::CheckGeoSDEInfo()
                   pszMAPLOB+0 );
     }
     
-    adfGT[0] = atof(NITFGetField(szParm,pszMAPLOB,13,15));
-    adfGT[1] = atof(NITFGetField(szParm,pszMAPLOB,3,5)) * dfMeterPerUnit;
+    adfGT[0] = CPLAtof(NITFGetField(szParm,pszMAPLOB,13,15));
+    adfGT[1] = CPLAtof(NITFGetField(szParm,pszMAPLOB,3,5)) * dfMeterPerUnit;
     adfGT[2] = 0.0;
-    adfGT[3] = atof(NITFGetField(szParm,pszMAPLOB,28,15));
+    adfGT[3] = CPLAtof(NITFGetField(szParm,pszMAPLOB,28,15));
     adfGT[4] = 0.0;
-    adfGT[5] = -atof(NITFGetField(szParm,pszMAPLOB,8,5)) * dfMeterPerUnit;
+    adfGT[5] = -CPLAtof(NITFGetField(szParm,pszMAPLOB,8,5)) * dfMeterPerUnit;
 
 /* -------------------------------------------------------------------- */
 /*      Apply back to dataset.                                          */
@@ -1938,24 +1945,26 @@ CPLErr NITFDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
     
 {
     if( poJ2KDataset != NULL )
         return poJ2KDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                        pData, nBufXSize, nBufYSize, eBufType,
                                        nBandCount, panBandMap, 
-                                       nPixelSpace, nLineSpace, nBandSpace );
+                                       nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else if( poJPEGDataset != NULL )
         return poJPEGDataset->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                         pData, nBufXSize, nBufYSize, eBufType,
                                         nBandCount, panBandMap, 
-                                        nPixelSpace, nLineSpace, nBandSpace );
+                                        nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else 
         return GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                        pData, nBufXSize, nBufYSize, eBufType,
                                        nBandCount, panBandMap, 
-                                       nPixelSpace, nLineSpace, nBandSpace );
+                                       nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 
@@ -3145,7 +3154,8 @@ const GDAL_GCP *NITFDataset::GetGCPs()
 /*      overview file. (#3457)                                          */
 /************************************************************************/
 
-int NITFDataset::CheckForRSets( const char *pszNITFFilename )
+int NITFDataset::CheckForRSets( const char *pszNITFFilename,
+                                char** papszSiblingFiles )
 
 {
     bool isR0File = EQUAL(CPLGetExtension(pszNITFFilename),"r0");
@@ -3169,8 +3179,17 @@ int NITFDataset::CheckForRSets( const char *pszNITFFilename )
         else
           osTarget.Printf( "%s.r%d", pszNITFFilename, i );
 
-        if( VSIStatL( osTarget, &sStat ) != 0 )
-            break;
+        if( papszSiblingFiles == NULL )
+        {
+            if( VSIStatL( osTarget, &sStat ) != 0 )
+                break;
+        }
+        else
+        {
+            if( CSLFindStringCaseSensitive(papszSiblingFiles,
+                                           CPLGetFilename( osTarget )) < 0 )
+                break;
+        }
 
         aosRSetFilenames.push_back( osTarget );
     }
@@ -3577,7 +3596,7 @@ CPLErr NITFDataset::ReadJPEGBlock( int iBlockX, int iBlockY )
     if( poDS->GetRasterBand(1)->GetRasterDataType() != GetRasterBand(1)->GetRasterDataType())
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "JPEG block %d data type (%s) not consistant with band data type (%s).", 
+                  "JPEG block %d data type (%s) not consistent with band data type (%s).",
                   iBlock, GDALGetDataTypeName(poDS->GetRasterBand(1)->GetRasterDataType()),
                   GDALGetDataTypeName(GetRasterBand(1)->GetRasterDataType()) );
         delete poDS;
@@ -3589,7 +3608,8 @@ CPLErr NITFDataset::ReadJPEGBlock( int iBlockX, int iBlockY )
                            psImage->nBlockWidth, psImage->nBlockHeight,
                            pabyJPEGBlock, 
                            psImage->nBlockWidth, psImage->nBlockHeight,
-                           GetRasterBand(1)->GetRasterDataType(), psImage->nBands, anBands, 0, 0, 0 );
+                           GetRasterBand(1)->GetRasterDataType(), psImage->nBands, anBands,
+                           0, 0, 0, NULL );
 
     delete poDS;
 
@@ -3635,13 +3655,29 @@ char **NITFDataset::AddFile(char **papszFileList, const char* EXTENSION, const c
 {
     VSIStatBufL sStatBuf;
     CPLString osTarget = CPLResetExtension( osNITFFilename, EXTENSION );
-    if( VSIStatL( osTarget, &sStatBuf ) == 0 )
-        papszFileList = CSLAddString( papszFileList, osTarget );
+    if( oOvManager.GetSiblingFiles() != NULL )
+    {
+        if( CSLFindStringCaseSensitive( oOvManager.GetSiblingFiles(), 
+                           CPLGetFilename(osTarget) ) >= 0 )
+            papszFileList = CSLAddString( papszFileList, osTarget );
+        else
+        {
+            osTarget = CPLResetExtension( osNITFFilename, extension );
+            if( CSLFindStringCaseSensitive( oOvManager.GetSiblingFiles(), 
+                           CPLGetFilename(osTarget) ) >= 0 )
+                papszFileList = CSLAddString( papszFileList, osTarget );
+        }
+    }
     else
     {
-        osTarget = CPLResetExtension( osNITFFilename, extension );
         if( VSIStatL( osTarget, &sStatBuf ) == 0 )
             papszFileList = CSLAddString( papszFileList, osTarget );
+        else
+        {
+            osTarget = CPLResetExtension( osNITFFilename, extension );
+            if( VSIStatL( osTarget, &sStatBuf ) == 0 )
+                papszFileList = CSLAddString( papszFileList, osTarget );
+        }
     }
 
     return papszFileList;
@@ -4225,7 +4261,7 @@ NITFDataset::NITFCreateCopy(
 
                 if (CSLPartialFindString(papszFullOptions, "TRE=GEOLOB=") != - 1)
                 {
-                    CPLDebug("NITF", "GEOLOB TRE was explicitely defined before. "
+                    CPLDebug("NITF", "GEOLOB TRE was explicitly defined before. "
                              "Overriding it with current georefencing info.");
                 }
 
@@ -4252,7 +4288,7 @@ NITFDataset::NITFCreateCopy(
                 papszFullOptions = CSLAddString( papszFullOptions, osGEOLOB ) ;
 
 /* -------------------------------------------------------------------- */
-/*      Write GEOPSB TRE if not already explicitely provided            */
+/*      Write GEOPSB TRE if not already explicitly provided            */
 /* -------------------------------------------------------------------- */
                 if (CSLPartialFindString(papszFullOptions, "FILE_TRE=GEOPSB=") == -1 &&
                     CSLPartialFindString(papszFullOptions, "TRE=GEOPSB=") == -1)
@@ -4284,7 +4320,7 @@ NITFDataset::NITFCreateCopy(
                 }
                 else
                 {
-                    CPLDebug("NITF", "GEOPSB TRE was explicitely defined before. Keeping it.");
+                    CPLDebug("NITF", "GEOPSB TRE was explicitly defined before. Keeping it.");
                 }
 
             }
@@ -4317,7 +4353,7 @@ NITFDataset::NITFCreateCopy(
             else
             {
                 CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
-                    "Inconsistant ICORDS value with SRS : %s%s.\n", pszICORDS,
+                    "Inconsistent ICORDS value with SRS : %s%s.\n", pszICORDS,
                     (!bStrict) ? ". Setting it to G instead" : "");
                 if (bStrict)
                 {
@@ -4565,12 +4601,12 @@ NITFDataset::NITFCreateCopy(
             for( int iLine = 0; iLine < nYSize; iLine++ )
             {
                 eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
-                                            pData, nXSize, 1, eType, 0, 0 );
+                                            pData, nXSize, 1, eType, 0, 0, NULL );
                 if( eErr != CE_None )
                     break;   
                     
                 eErr = poDstBand->RasterIO( GF_Write, 0, iLine, nXSize, 1, 
-                                            pData, nXSize, 1, eType, 0, 0 );
+                                            pData, nXSize, 1, eType, 0, 0, NULL );
 
                 if( eErr != CE_None )
                     break;   
@@ -5699,6 +5735,7 @@ void GDALRegister_NITF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "NITF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "National Imagery Transmission Format" );
         
diff --git a/frmts/nitf/nitfdataset.h b/frmts/nitf/nitfdataset.h
index 09b6414..c868da2 100644
--- a/frmts/nitf/nitfdataset.h
+++ b/frmts/nitf/nitfdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfdataset.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nitfdataset.h 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  NITF Read/Write Translator
  * Purpose:  GDALDataset/GDALRasterBand declarations.
@@ -110,7 +110,7 @@ class NITFDataset : public GDALPamDataset
     CPLString    osNITFFilename;
 
     CPLString    osRSetVRT;
-    int          CheckForRSets( const char *pszFilename );
+    int          CheckForRSets( const char *pszFilename, char** papszSiblingFiles );
 
     char       **papszTextMDToWrite;
     char       **papszCgmMDToWrite;
@@ -135,7 +135,10 @@ class NITFDataset : public GDALPamDataset
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual const char *GetProjectionRef(void);
     virtual CPLErr SetProjection( const char * );
@@ -230,7 +233,8 @@ class NITFProxyPamRasterBand : public GDALPamRasterBand
         virtual CPLErr IWriteBlock( int, int, void * );
         virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                                 void *, int, int, GDALDataType,
-                                int, int );
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GDALRasterIOExtraArg* psExtraArg);
 
     public:
                          ~NITFProxyPamRasterBand();
@@ -279,7 +283,7 @@ class NITFProxyPamRasterBand : public GDALPamRasterBand
         virtual int HasArbitraryOverviews();
         virtual int GetOverviewCount();
         virtual GDALRasterBand *GetOverview(int);
-        virtual GDALRasterBand *GetRasterSampleOverview( int );
+        virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig );
         virtual CPLErr BuildOverviews( const char *, int, int *,
                                     GDALProgressFunc, void * );
 
@@ -288,16 +292,16 @@ class NITFProxyPamRasterBand : public GDALPamRasterBand
                                 GDALDataType eDT, char **papszOptions );
 
         /*virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                            int nBuckets, int * panHistogram,
+                            int nBuckets, GUIntBig * panHistogram,
                             int bIncludeOutOfRange, int bApproxOK,
                             GDALProgressFunc, void *pProgressData );
 
         virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                            int *pnBuckets, int ** ppanHistogram,
+                                            int *pnBuckets, GUIntBig ** ppanHistogram,
                                             int bForce,
                                             GDALProgressFunc, void *pProgressData);
         virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                            int nBuckets, int *panHistogram );*/
+                                            int nBuckets, GUIntBig *panHistogram );*/
 
         /*virtual const GDALRasterAttributeTable *GetDefaultRAT();
         virtual CPLErr SetDefaultRAT( const GDALRasterAttributeTable * );*/
diff --git a/frmts/nitf/nitfdes.c b/frmts/nitf/nitfdes.c
index a0e64f2..4049063 100644
--- a/frmts/nitf/nitfdes.c
+++ b/frmts/nitf/nitfdes.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfdes.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: nitfdes.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  Module responsible for implementation of DE segments.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: nitfdes.c 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: nitfdes.c 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                          NITFDESAccess()                             */
@@ -350,7 +350,7 @@ retry:
                             memcpy(&dfVal, pachDataIter, 8);
                             CPL_MSBPTR64(&dfVal);
                             pachDataIter += 8;
-                            sprintf(szAttrNameValue, "NITF_ATT_Q%d_%d=%.16g", j+1, i, dfVal);
+                            CPLsprintf(szAttrNameValue, "NITF_ATT_Q%d_%d=%.16g", j+1, i, dfVal);
                             papszMD[nMDSize + i * 4 + j] = CPLStrdup(szAttrNameValue);
                         }
                     }
@@ -429,7 +429,7 @@ int   NITFDESGetTRE( NITFDES* psDES,
     psSegInfo = psDES->psFile->pasSegmentInfo + psDES->iSegment;
     fp = psDES->psFile->fp;
 
-    if ((GUIntBig)nOffset >= psSegInfo->nSegmentSize)
+    if ((size_t)nOffset >= psSegInfo->nSegmentSize)
         return FALSE;
 
     VSIFSeekL(fp, psSegInfo->nSegmentStart + nOffset, SEEK_SET);
@@ -460,7 +460,7 @@ int   NITFDESGetTRE( NITFDES* psDES,
                  nTRESize, szTRETempName);
         return FALSE;
     }
-    if ((GUIntBig)(nOffset + 11 + nTRESize) > psSegInfo->nSegmentSize)
+    if ((size_t)(nOffset + 11 + nTRESize) > psSegInfo->nSegmentSize)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "Cannot read %s TRE. Not enough bytes : remaining %d, expected %d",
diff --git a/frmts/nitf/nitffile.c b/frmts/nitf/nitffile.c
index ed7bce0..3f59b29 100644
--- a/frmts/nitf/nitffile.c
+++ b/frmts/nitf/nitffile.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitffile.c 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: nitffile.c 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  Module responsible for opening NITF file, populating NITFFile
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: nitffile.c 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: nitffile.c 28039 2014-11-30 18:24:59Z rouault $");
 
 static int NITFWriteBLOCKA( VSILFILE* fp, vsi_l_offset nOffsetUDIDL,
                             int *pnOffset,
@@ -60,13 +60,6 @@ NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
 
 {
     VSILFILE	*fp;
-    char        *pachHeader;
-    NITFFile    *psFile;
-    int         nHeaderLen, nOffset, nHeaderLenOffset;
-    GUIntBig    nNextData;
-    char        szTemp[128], achFSDWNG[6];
-    GIntBig     currentPos;
-    int         bTriedStreamingFileHeader = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Open the file.                                                  */
@@ -84,9 +77,28 @@ NITFFile *NITFOpen( const char *pszFilename, int bUpdatable )
         return NULL;
     }
 
+    return NITFOpenEx(fp, pszFilename);
+}
+
+/************************************************************************/
+/*                             NITFOpenEx()                             */
+/************************************************************************/
+
+NITFFile *NITFOpenEx(VSILFILE *fp, const char *pszFilename)
+
+{
+    char        *pachHeader;
+    NITFFile    *psFile;
+    int         nHeaderLen, nOffset, nHeaderLenOffset;
+    GUIntBig    nNextData;
+    char        szTemp[128], achFSDWNG[6];
+    GIntBig     currentPos;
+    int         bTriedStreamingFileHeader = FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      Check file type.                                                */
 /* -------------------------------------------------------------------- */
+    VSIFSeekL( fp, 0, SEEK_SET );
     VSIFReadL( szTemp, 1, 9, fp );
 
     if( !EQUALN(szTemp,"NITF",4) && !EQUALN(szTemp,"NSIF",4) )
@@ -275,7 +287,7 @@ retry_read_header:
             abyDELIM2_L2[2] == 0x14 && abyDELIM2_L2[3] == 0xBF)
         {
             int SFHL2 = atoi((const char*)(abyDELIM2_L2 + 4));
-            if (SFHL2 > 0 && nFileSize > (GUIntBig)(11 + SFHL2 + 11) )
+            if (SFHL2 > 0 && (nFileSize > (size_t)(11 + SFHL2 + 11)) )
             {
                 VSIFSeekL( fp, nFileSize - 11 - SFHL2 - 11 , SEEK_SET );
 
@@ -475,11 +487,11 @@ void NITFClose( NITFFile *psFile )
 
 static void NITFGotoOffset(VSILFILE* fp, GUIntBig nLocation)
 {
-    GUIntBig iFill;
     GUIntBig nCurrentLocation = VSIFTellL(fp);
     if (nLocation > nCurrentLocation)
     {
         GUIntBig nFileSize;
+        size_t iFill;
         char cSpace = ' ';
 
         VSIFSeekL(fp, 0, SEEK_END);
@@ -1645,7 +1657,7 @@ void NITFExtractMetadata( char ***ppapszMetadata, const char *pachHeader,
     char szWork[400];
     char* pszWork;
 
-    if ((size_t)nLength >= sizeof(szWork) - 1)
+    if (nLength >= (int)(sizeof(szWork) - 1))
         pszWork = (char*)CPLMalloc(nLength + 1);
     else
         pszWork = szWork;
@@ -1908,7 +1920,7 @@ const NITFSeries* NITFGetSeriesInfo(const char* pszFilename)
             {
                 seriesCode[0] = pszFilename[i+1];
                 seriesCode[1] = pszFilename[i+2];
-                for(i=0;(size_t)i<sizeof(nitfSeries) / sizeof(nitfSeries[0]); i++)
+                for(i=0;i < (int)(sizeof(nitfSeries) / sizeof(nitfSeries[0])); i++)
                 {
                     if (EQUAL(seriesCode, nitfSeries[i].code))
                     {
@@ -2205,7 +2217,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
             {
                 *pbError = TRUE;
                 CPLError( CE_Warning, CPLE_AppDefined,
-                          "Invalid item construct in %s TRE in XML ressource",
+                          "Invalid item construct in %s TRE in XML resource",
                           pszTREName );
                 break;
             }
@@ -2229,7 +2241,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (nIterations < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, pszCounter );
                     *pbError = TRUE;
@@ -2250,7 +2262,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NPART < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NPART" );
                     *pbError = TRUE;
@@ -2268,7 +2280,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NUMOPG < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NUMOPG" );
                     *pbError = TRUE;
@@ -2290,7 +2302,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NPAR < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NPAR" );
                     *pbError = TRUE;
@@ -2299,7 +2311,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NPARO < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NPAR0" );
                     *pbError = TRUE;
@@ -2317,7 +2329,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NPLN < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NPLN" );
                     *pbError = TRUE;
@@ -2339,7 +2351,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NXPTS < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NXPTS" );
                     *pbError = TRUE;
@@ -2348,7 +2360,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
                 if (NYPTS < 0)
                 {
                     CPLError( CE_Warning, CPLE_AppDefined,
-                            "Invalid loop construct in %s TRE in XML ressource : "
+                            "Invalid loop construct in %s TRE in XML resource : "
                             "invalid 'counter' %s",
                             pszTREName, "NYPTS" );
                     *pbError = TRUE;
@@ -2359,7 +2371,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
             else
             {
                 CPLError( CE_Warning, CPLE_AppDefined,
-                          "Invalid loop construct in %s TRE in XML ressource : "
+                          "Invalid loop construct in %s TRE in XML resource : "
                           "missing or invalid 'counter' or 'iterations' or 'formula'",
                           pszTREName );
                 *pbError = TRUE;
@@ -2544,7 +2556,7 @@ static char** NITFGenericMetadataReadTREInternal(char **papszMD,
             else
             {
                 CPLError( CE_Warning, CPLE_AppDefined,
-                          "Invalid if construct in %s TRE in XML ressource : "
+                          "Invalid if construct in %s TRE in XML resource : "
                           "missing or invalid 'cond' attribute",
                           pszTREName );
                 *pbError = TRUE;
@@ -2626,7 +2638,7 @@ char **NITFGenericMetadataReadTRE(char **papszMD,
     if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
     {
         CPLError( CE_Warning, CPLE_AppDefined,
-                  "Inconsistant declaration of %s TRE",
+                  "Inconsistent declaration of %s TRE",
                   pszTREName );
     }
     if (nTreOffset < nTRESize)
@@ -2762,7 +2774,7 @@ CPLXMLNode* NITFCreateXMLTre(NITFFile* psFile,
     if (bError == FALSE && nTreLength > 0 && nTreOffset != nTreLength)
     {
         CPLError( CE_Warning, CPLE_AppDefined,
-                  "Inconsistant declaration of %s TRE",
+                  "Inconsistent declaration of %s TRE",
                   pszTREName );
     }
     if (nTreOffset < nTRESize)
diff --git a/frmts/nitf/nitfimage.c b/frmts/nitf/nitfimage.c
index 854f7e9..6ba1efa 100644
--- a/frmts/nitf/nitfimage.c
+++ b/frmts/nitf/nitfimage.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfimage.c 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: nitfimage.c 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  Module responsible for implementation of most NITFImage 
@@ -36,7 +36,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: nitfimage.c 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: nitfimage.c 28039 2014-11-30 18:24:59Z rouault $");
 
 static int NITFReadIMRFCA( NITFImage *psImage, NITFRPC00BInfo *psRPC );
 static char *NITFTrimWhite( char * );
@@ -277,30 +277,30 @@ NITFImage *NITFImageAccess( NITFFile *psFile, int iSegment )
                 psImage->nZone = 
                     atoi(NITFGetField( szTemp, pszCoordPair, 0, 2 ));
 
-                pdfXY[0] = atof(NITFGetField( szTemp, pszCoordPair, 2, 6 ));
-                pdfXY[1] = atof(NITFGetField( szTemp, pszCoordPair, 8, 7 ));
+                pdfXY[0] = CPLAtof(NITFGetField( szTemp, pszCoordPair, 2, 6 ));
+                pdfXY[1] = CPLAtof(NITFGetField( szTemp, pszCoordPair, 8, 7 ));
             }
             else if( psImage->chICORDS == 'G' || psImage->chICORDS == 'C' )
             {
                 pdfXY[1] =
-                    atof(NITFGetField( szTemp, pszCoordPair, 0, 2 ))
-                  + atof(NITFGetField( szTemp, pszCoordPair, 2, 2 )) / 60.0
-                  + atof(NITFGetField( szTemp, pszCoordPair, 4, 2 )) / 3600.0;
+                    CPLAtof(NITFGetField( szTemp, pszCoordPair, 0, 2 ))
+                  + CPLAtof(NITFGetField( szTemp, pszCoordPair, 2, 2 )) / 60.0
+                  + CPLAtof(NITFGetField( szTemp, pszCoordPair, 4, 2 )) / 3600.0;
                 if( pszCoordPair[6] == 's' || pszCoordPair[6] == 'S' )
                     pdfXY[1] *= -1;
 
                 pdfXY[0] =
-                    atof(NITFGetField( szTemp, pszCoordPair, 7, 3 ))
-                  + atof(NITFGetField( szTemp, pszCoordPair,10, 2 )) / 60.0
-                  + atof(NITFGetField( szTemp, pszCoordPair,12, 2 )) / 3600.0;
+                    CPLAtof(NITFGetField( szTemp, pszCoordPair, 7, 3 ))
+                  + CPLAtof(NITFGetField( szTemp, pszCoordPair,10, 2 )) / 60.0
+                  + CPLAtof(NITFGetField( szTemp, pszCoordPair,12, 2 )) / 3600.0;
 
                 if( pszCoordPair[14] == 'w' || pszCoordPair[14] == 'W' )
                     pdfXY[0] *= -1;
             }
             else if( psImage->chICORDS == 'D' )
             {  /* 'D' is Decimal Degrees */
-                pdfXY[1] = atof(NITFGetField( szTemp, pszCoordPair, 0, 7 ));
-                pdfXY[0] = atof(NITFGetField( szTemp, pszCoordPair, 7, 8 ));
+                pdfXY[1] = CPLAtof(NITFGetField( szTemp, pszCoordPair, 0, 7 ));
+                pdfXY[0] = CPLAtof(NITFGetField( szTemp, pszCoordPair, 7, 8 ));
             }
             else if( psImage->chICORDS == 'U' )
             {
@@ -1255,9 +1255,9 @@ int NITFReadImageBlock( NITFImage *psImage, int nBlockX, int nBlockY,
 /* -------------------------------------------------------------------- */
 /*      Can we do a direct read into our buffer?                        */
 /* -------------------------------------------------------------------- */
-    if( (GUIntBig)psImage->nWordSize == psImage->nPixelOffset
-        && (GUIntBig)((psImage->nBitsPerSample * psImage->nBlockWidth + 7) / 8)
-           == psImage->nLineOffset 
+    if( (size_t)psImage->nWordSize == psImage->nPixelOffset
+        && (size_t)((psImage->nBitsPerSample * psImage->nBlockWidth + 7) / 8)
+           == psImage->nLineOffset
         && psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M'
         && psImage->chIMODE != 'P' )
     {
@@ -1558,8 +1558,8 @@ int NITFWriteImageBlock( NITFImage *psImage, int nBlockX, int nBlockY,
 /* -------------------------------------------------------------------- */
 /*      Can we do a direct read into our buffer?                        */
 /* -------------------------------------------------------------------- */
-    if( (GUIntBig)psImage->nWordSize == psImage->nPixelOffset
-        && (GUIntBig)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset 
+    if( (size_t)psImage->nWordSize == psImage->nPixelOffset
+        && (size_t)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset
         && psImage->szIC[0] != 'C' && psImage->szIC[0] != 'M' )
     {
 #ifdef CPL_LSB
@@ -1653,8 +1653,8 @@ int NITFReadImageLine( NITFImage *psImage, int nLine, int nBand, void *pData )
 /*      Can we do a direct read into our buffer.                        */
 /* -------------------------------------------------------------------- */
     if( (psImage->nBitsPerSample % 8) != 0 ||
-        ((GUIntBig)psImage->nWordSize == psImage->nPixelOffset
-         && (GUIntBig)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset) )
+        ((size_t)psImage->nWordSize == psImage->nPixelOffset
+         && (size_t)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset) )
     {
         if( VSIFReadL( pData, 1, nLineSize, psImage->psFile->fp ) !=  
             nLineSize )
@@ -1769,8 +1769,8 @@ int NITFWriteImageLine( NITFImage *psImage, int nLine, int nBand, void *pData )
 /* -------------------------------------------------------------------- */
 /*      Can we do a direct write into our buffer.                       */
 /* -------------------------------------------------------------------- */
-    if( (GUIntBig)psImage->nWordSize == psImage->nPixelOffset
-        && (GUIntBig)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset )
+    if( (size_t)psImage->nWordSize == psImage->nPixelOffset
+        && (size_t)(psImage->nWordSize * psImage->nBlockWidth) == psImage->nLineOffset )
     {
 #ifdef CPL_LSB
         NITFSwapWords( psImage, pData, psImage->nBlockWidth );
@@ -1982,10 +1982,10 @@ int NITFWriteIGEOLO( NITFImage *psImage, char chICORDS,
             return FALSE;
         }
 
-        sprintf(szIGEOLO + 0, "%+#07.3f%+#08.3f", dfULY, dfULX);
-        sprintf(szIGEOLO + 15, "%+#07.3f%+#08.3f", dfURY, dfURX);
-        sprintf(szIGEOLO + 30, "%+#07.3f%+#08.3f", dfLRY, dfLRX);
-        sprintf(szIGEOLO + 45, "%+#07.3f%+#08.3f", dfLLY, dfLLX);
+        CPLsprintf(szIGEOLO + 0, "%+#07.3f%+#08.3f", dfULY, dfULX);
+        CPLsprintf(szIGEOLO + 15, "%+#07.3f%+#08.3f", dfURY, dfURX);
+        CPLsprintf(szIGEOLO + 30, "%+#07.3f%+#08.3f", dfLRY, dfLRX);
+        CPLsprintf(szIGEOLO + 45, "%+#07.3f%+#08.3f", dfLLY, dfLLX);
     }
 
 /* -------------------------------------------------------------------- */
@@ -2001,13 +2001,13 @@ int NITFWriteIGEOLO( NITFImage *psImage, char chICORDS,
         CHECK_IGEOLO_UTM_Y("dfLRY", dfLRY);
         CHECK_IGEOLO_UTM_X("dfLLX", dfLLX);
         CHECK_IGEOLO_UTM_Y("dfLLY", dfLLY);
-        sprintf( szIGEOLO + 0, "%02d%06d%07d",
+        CPLsprintf( szIGEOLO + 0, "%02d%06d%07d",
                  nZone, (int) floor(dfULX+0.5), (int) floor(dfULY+0.5) );
-        sprintf( szIGEOLO + 15, "%02d%06d%07d",
+        CPLsprintf( szIGEOLO + 15, "%02d%06d%07d",
                  nZone, (int) floor(dfURX+0.5), (int) floor(dfURY+0.5) );
-        sprintf( szIGEOLO + 30, "%02d%06d%07d",
+        CPLsprintf( szIGEOLO + 30, "%02d%06d%07d",
                  nZone, (int) floor(dfLRX+0.5), (int) floor(dfLRY+0.5) );
-        sprintf( szIGEOLO + 45, "%02d%06d%07d",
+        CPLsprintf( szIGEOLO + 45, "%02d%06d%07d",
                  nZone, (int) floor(dfLLX+0.5), (int) floor(dfLLY+0.5) );
     }
 
@@ -2274,20 +2274,20 @@ int NITFReadRPC00B( NITFImage *psImage, NITFRPC00BInfo *psRPC )
     if ( !psRPC->SUCCESS )
 	fprintf( stdout, "RPC Extension not Populated!\n");
 
-    psRPC->ERR_BIAS = atof(NITFGetField(szTemp, pachTRE, 1, 7 ));
-    psRPC->ERR_RAND = atof(NITFGetField(szTemp, pachTRE, 8, 7 ));
+    psRPC->ERR_BIAS = CPLAtof(NITFGetField(szTemp, pachTRE, 1, 7 ));
+    psRPC->ERR_RAND = CPLAtof(NITFGetField(szTemp, pachTRE, 8, 7 ));
 
-    psRPC->LINE_OFF = atof(NITFGetField(szTemp, pachTRE, 15, 6 ));
-    psRPC->SAMP_OFF = atof(NITFGetField(szTemp, pachTRE, 21, 5 ));
-    psRPC->LAT_OFF = atof(NITFGetField(szTemp, pachTRE, 26, 8 ));
-    psRPC->LONG_OFF = atof(NITFGetField(szTemp, pachTRE, 34, 9 ));
-    psRPC->HEIGHT_OFF = atof(NITFGetField(szTemp, pachTRE, 43, 5 ));
+    psRPC->LINE_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 15, 6 ));
+    psRPC->SAMP_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 21, 5 ));
+    psRPC->LAT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 26, 8 ));
+    psRPC->LONG_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 34, 9 ));
+    psRPC->HEIGHT_OFF = CPLAtof(NITFGetField(szTemp, pachTRE, 43, 5 ));
 
-    psRPC->LINE_SCALE = atof(NITFGetField(szTemp, pachTRE, 48, 6 ));
-    psRPC->SAMP_SCALE = atof(NITFGetField(szTemp, pachTRE, 54, 5 ));
-    psRPC->LAT_SCALE = atof(NITFGetField(szTemp, pachTRE, 59, 8 ));
-    psRPC->LONG_SCALE = atof(NITFGetField(szTemp, pachTRE, 67, 9 ));
-    psRPC->HEIGHT_SCALE = atof(NITFGetField(szTemp, pachTRE, 76, 5 ));
+    psRPC->LINE_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 48, 6 ));
+    psRPC->SAMP_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 54, 5 ));
+    psRPC->LAT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 59, 8 ));
+    psRPC->LONG_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 67, 9 ));
+    psRPC->HEIGHT_SCALE = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 5 ));
 
 /* -------------------------------------------------------------------- */
 /*      Parse out coefficients.                                         */
@@ -2300,13 +2300,13 @@ int NITFReadRPC00B( NITFImage *psImage, NITFRPC00BInfo *psRPC )
             iSrcCoef = anRPC00AMap[i];
 
         psRPC->LINE_NUM_COEFF[i] = 
-            atof(NITFGetField(szTemp, pachTRE, 81+iSrcCoef*12, 12));
+            CPLAtof(NITFGetField(szTemp, pachTRE, 81+iSrcCoef*12, 12));
         psRPC->LINE_DEN_COEFF[i] = 
-            atof(NITFGetField(szTemp, pachTRE, 321+iSrcCoef*12, 12));
+            CPLAtof(NITFGetField(szTemp, pachTRE, 321+iSrcCoef*12, 12));
         psRPC->SAMP_NUM_COEFF[i] = 
-            atof(NITFGetField(szTemp, pachTRE, 561+iSrcCoef*12, 12));
+            CPLAtof(NITFGetField(szTemp, pachTRE, 561+iSrcCoef*12, 12));
         psRPC->SAMP_DEN_COEFF[i] = 
-            atof(NITFGetField(szTemp, pachTRE, 801+iSrcCoef*12, 12));
+            CPLAtof(NITFGetField(szTemp, pachTRE, 801+iSrcCoef*12, 12));
     }
 
     return TRUE;
@@ -2362,33 +2362,33 @@ int NITFReadICHIPB( NITFImage *psImage, NITFICHIPBInfo *psICHIP )
             return FALSE;
         }
 
-        psICHIP->SCALE_FACTOR = atof(NITFGetField(szTemp, pachTRE, 2, 10 ));
+        psICHIP->SCALE_FACTOR = CPLAtof(NITFGetField(szTemp, pachTRE, 2, 10 ));
         psICHIP->ANAMORPH_CORR = atoi(NITFGetField(szTemp, pachTRE, 12, 2 ));
         psICHIP->SCANBLK_NUM = atoi(NITFGetField(szTemp, pachTRE, 14, 2 ));
 
-        psICHIP->OP_ROW_11 = atof(NITFGetField(szTemp, pachTRE, 16, 12 ));
-        psICHIP->OP_COL_11 = atof(NITFGetField(szTemp, pachTRE, 28, 12 ));
+        psICHIP->OP_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 16, 12 ));
+        psICHIP->OP_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 28, 12 ));
 
-        psICHIP->OP_ROW_12 = atof(NITFGetField(szTemp, pachTRE, 40, 12 ));
-        psICHIP->OP_COL_12 = atof(NITFGetField(szTemp, pachTRE, 52, 12 ));
+        psICHIP->OP_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 40, 12 ));
+        psICHIP->OP_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 52, 12 ));
 
-        psICHIP->OP_ROW_21 = atof(NITFGetField(szTemp, pachTRE, 64, 12 ));
-        psICHIP->OP_COL_21 = atof(NITFGetField(szTemp, pachTRE, 76, 12 ));
+        psICHIP->OP_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 64, 12 ));
+        psICHIP->OP_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 76, 12 ));
 
-        psICHIP->OP_ROW_22 = atof(NITFGetField(szTemp, pachTRE, 88, 12 ));
-        psICHIP->OP_COL_22 = atof(NITFGetField(szTemp, pachTRE, 100, 12 ));
+        psICHIP->OP_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 88, 12 ));
+        psICHIP->OP_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 100, 12 ));
 
-        psICHIP->FI_ROW_11 = atof(NITFGetField(szTemp, pachTRE, 112, 12 ));
-        psICHIP->FI_COL_11 = atof(NITFGetField(szTemp, pachTRE, 124, 12 ));
+        psICHIP->FI_ROW_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 112, 12 ));
+        psICHIP->FI_COL_11 = CPLAtof(NITFGetField(szTemp, pachTRE, 124, 12 ));
 
-        psICHIP->FI_ROW_12 = atof(NITFGetField(szTemp, pachTRE, 136, 12 ));
-        psICHIP->FI_COL_12 = atof(NITFGetField(szTemp, pachTRE, 148, 12 ));
+        psICHIP->FI_ROW_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 136, 12 ));
+        psICHIP->FI_COL_12 = CPLAtof(NITFGetField(szTemp, pachTRE, 148, 12 ));
 
-        psICHIP->FI_ROW_21 = atof(NITFGetField(szTemp, pachTRE, 160, 12 ));
-        psICHIP->FI_COL_21 = atof(NITFGetField(szTemp, pachTRE, 172, 12 ));
+        psICHIP->FI_ROW_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 160, 12 ));
+        psICHIP->FI_COL_21 = CPLAtof(NITFGetField(szTemp, pachTRE, 172, 12 ));
 
-        psICHIP->FI_ROW_22 = atof(NITFGetField(szTemp, pachTRE, 184, 12 ));
-        psICHIP->FI_COL_22 = atof(NITFGetField(szTemp, pachTRE, 196, 12 ));
+        psICHIP->FI_ROW_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 184, 12 ));
+        psICHIP->FI_COL_22 = CPLAtof(NITFGetField(szTemp, pachTRE, 196, 12 ));
 
         psICHIP->FI_ROW = atoi(NITFGetField(szTemp, pachTRE, 208, 8 ));
         psICHIP->FI_COL = atoi(NITFGetField(szTemp, pachTRE, 216, 8 ));
@@ -2513,17 +2513,17 @@ void NITFGetGCP ( const char* pachCoord, double *pdfXYs, int iCoord )
         /* ------------------------------------------------------------ */
 
         pdfXYs[1] = 
-            atof(NITFGetField( szTemp, pachCoord, 1, 2 )) 
-          + atof(NITFGetField( szTemp, pachCoord, 3, 2 )) / 60.0
-          + atof(NITFGetField( szTemp, pachCoord, 5, 5 )) / 3600.0;
+            CPLAtof(NITFGetField( szTemp, pachCoord, 1, 2 )) 
+          + CPLAtof(NITFGetField( szTemp, pachCoord, 3, 2 )) / 60.0
+          + CPLAtof(NITFGetField( szTemp, pachCoord, 5, 5 )) / 3600.0;
 
         if( pachCoord[0] == 's' || pachCoord[0] == 'S' )
             pdfXYs[1] *= -1;
 
         pdfXYs[0] = 
-            atof(NITFGetField( szTemp, pachCoord,11, 3 )) 
-          + atof(NITFGetField( szTemp, pachCoord,14, 2 )) / 60.0
-          + atof(NITFGetField( szTemp, pachCoord,16, 5 )) / 3600.0;
+            CPLAtof(NITFGetField( szTemp, pachCoord,11, 3 )) 
+          + CPLAtof(NITFGetField( szTemp, pachCoord,14, 2 )) / 60.0
+          + CPLAtof(NITFGetField( szTemp, pachCoord,16, 5 )) / 3600.0;
 
         if( pachCoord[10] == 'w' || pachCoord[10] == 'W' )
             pdfXYs[0] *= -1;
@@ -2538,8 +2538,8 @@ void NITFGetGCP ( const char* pachCoord, double *pdfXYs, int iCoord )
         /* longitude (east is positive).                                */
         /* ------------------------------------------------------------ */
 
-        pdfXYs[1] = atof(NITFGetField( szTemp, pachCoord, 0, 10 ));
-        pdfXYs[0] = atof(NITFGetField( szTemp, pachCoord,10, 11 ));
+        pdfXYs[1] = CPLAtof(NITFGetField( szTemp, pachCoord, 0, 10 ));
+        pdfXYs[0] = CPLAtof(NITFGetField( szTemp, pachCoord,10, 11 ));
     }
 }
 
@@ -2669,8 +2669,8 @@ static int NITFReadGEOLOB( NITFImage *psImage )
         double dfARV = atoi(NITFGetField( szTemp, pachTRE, 0, 9 ));
         double dfBRV = atoi(NITFGetField( szTemp, pachTRE, 9, 9 ));
         
-        double dfLSO = atof(NITFGetField( szTemp, pachTRE, 18, 15 ));
-        double dfPSO = atof(NITFGetField( szTemp, pachTRE, 33, 15 ));
+        double dfLSO = CPLAtof(NITFGetField( szTemp, pachTRE, 18, 15 ));
+        double dfPSO = CPLAtof(NITFGetField( szTemp, pachTRE, 33, 15 ));
         
         double dfPixelWidth  = 360.0 / dfARV;
         double dfPixelHeight = 360.0 / dfBRV;
@@ -2818,7 +2818,7 @@ static void NITFLoadAttributeSection( NITFImage *psImage )
 /*      hold the offset table (otherwise NITFFetchAttribute coud        */
 /*      read out of the buffer)                                         */
 /* -------------------------------------------------------------------- */
-    if (nASSSize < (GUIntBig)(8 * nAttrCount))
+    if (nASSSize < (size_t)(8 * nAttrCount))
     {
         CPLError( CE_Warning, CPLE_AppDefined,
                   "Attribute subsection not large enough (%d bytes) to contain %d attributes.",
@@ -3298,7 +3298,7 @@ static void NITFLoadLocationTable( NITFImage *psImage )
                     }
                     else
                     {
-                        CPLDebug("NITF", "The CoverageSectionSubheader content isn't consistant");
+                        CPLDebug("NITF", "The CoverageSectionSubheader content isn't consistent");
                         bFoundValidLocation = FALSE;
                         break;
                     }
@@ -3311,7 +3311,7 @@ static void NITFLoadLocationTable( NITFImage *psImage )
                     }
                     else
                     {
-                        CPLDebug("NITF", "The VQ tables content aren't consistant");
+                        CPLDebug("NITF", "The VQ tables content aren't consistent");
                         bFoundValidLocation = FALSE;
                         break;
                     }
@@ -3390,8 +3390,8 @@ static int NITFLoadVQTables( NITFImage *psImage, int bTryGuessingOffset )
             if( memcmp(abyTestChunk+i,abySignature,sizeof(abySignature)) == 0 )
             {
                 bFoundSignature = TRUE;
-                nVQOffset += i; 
-                CPLDebug( "NITF", 
+                nVQOffset += i;
+                CPLDebug( "NITF",
                           "VQ CompressionLookupSubsection offsets off by %d bytes, adjusting accordingly.",
                           i );
                 break;
@@ -3831,16 +3831,16 @@ int NITFReadIMRFCA( NITFImage *psImage, NITFRPC00BInfo *psRPC )
     psRPC->ERR_BIAS = 0.0;
     psRPC->ERR_RAND = 0.0;
     
-    psRPC->LONG_OFF     = atof( NITFGetField(szTemp, pachTreIMASDA, 0,   22) );
-    psRPC->LAT_OFF      = atof( NITFGetField(szTemp, pachTreIMASDA, 22,  22) );
-    psRPC->HEIGHT_OFF   = atof( NITFGetField(szTemp, pachTreIMASDA, 44,  22) );
-    psRPC->LONG_SCALE   = atof( NITFGetField(szTemp, pachTreIMASDA, 66,  22) );
-    psRPC->LAT_SCALE    = atof( NITFGetField(szTemp, pachTreIMASDA, 88,  22) );
-    psRPC->HEIGHT_SCALE = atof( NITFGetField(szTemp, pachTreIMASDA, 110, 22) );
-    psRPC->SAMP_OFF     = atof( NITFGetField(szTemp, pachTreIMASDA, 132, 22) );
-    psRPC->LINE_OFF     = atof( NITFGetField(szTemp, pachTreIMASDA, 154, 22) );
-    psRPC->SAMP_SCALE   = atof( NITFGetField(szTemp, pachTreIMASDA, 176, 22) );
-    psRPC->LINE_SCALE   = atof( NITFGetField(szTemp, pachTreIMASDA, 198, 22) );
+    psRPC->LONG_OFF     = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 0,   22) );
+    psRPC->LAT_OFF      = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 22,  22) );
+    psRPC->HEIGHT_OFF   = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 44,  22) );
+    psRPC->LONG_SCALE   = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 66,  22) );
+    psRPC->LAT_SCALE    = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 88,  22) );
+    psRPC->HEIGHT_SCALE = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 110, 22) );
+    psRPC->SAMP_OFF     = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 132, 22) );
+    psRPC->LINE_OFF     = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 154, 22) );
+    psRPC->SAMP_SCALE   = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 176, 22) );
+    psRPC->LINE_SCALE   = CPLAtof( NITFGetField(szTemp, pachTreIMASDA, 198, 22) );
 
     if (psRPC->HEIGHT_SCALE == 0.0 ) psRPC->HEIGHT_SCALE = dfTolerance;
     if (psRPC->LAT_SCALE    == 0.0 ) psRPC->LAT_SCALE    = dfTolerance;
@@ -3858,11 +3858,11 @@ int NITFReadIMRFCA( NITFImage *psImage, NITFRPC00BInfo *psRPC )
 
     for( count = 0; count < 20; ++count )
     {
-        psRPC->LINE_NUM_COEFF[count] = atof( NITFGetField(szTemp, pachTreIMRFCA, count*22,     22) );
-        psRPC->LINE_DEN_COEFF[count] = atof( NITFGetField(szTemp, pachTreIMRFCA, 440+count*22, 22) );
+        psRPC->LINE_NUM_COEFF[count] = CPLAtof( NITFGetField(szTemp, pachTreIMRFCA, count*22,     22) );
+        psRPC->LINE_DEN_COEFF[count] = CPLAtof( NITFGetField(szTemp, pachTreIMRFCA, 440+count*22, 22) );
 
-        psRPC->SAMP_NUM_COEFF[count] = atof( NITFGetField(szTemp, pachTreIMRFCA, 880+count*22,  22) );
-        psRPC->SAMP_DEN_COEFF[count] = atof( NITFGetField(szTemp, pachTreIMRFCA, 1320+count*22, 22) );
+        psRPC->SAMP_NUM_COEFF[count] = CPLAtof( NITFGetField(szTemp, pachTreIMRFCA, 880+count*22,  22) );
+        psRPC->SAMP_DEN_COEFF[count] = CPLAtof( NITFGetField(szTemp, pachTreIMRFCA, 1320+count*22, 22) );
     }
 
     psRPC->SUCCESS = 1;
diff --git a/frmts/nitf/nitflib.h b/frmts/nitf/nitflib.h
index 8b4e6d1..d30c56e 100644
--- a/frmts/nitf/nitflib.h
+++ b/frmts/nitf/nitflib.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitflib.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nitflib.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  NITF Read/Write Library
  * Purpose:  Main GDAL independent include file for NITF support.  
@@ -80,6 +80,7 @@ typedef struct {
 /*      File level prototypes.                                          */
 /* -------------------------------------------------------------------- */
 NITFFile CPL_DLL *NITFOpen( const char *pszFilename, int bUpdatable );
+NITFFile *NITFOpenEx( VSILFILE *fp, const char *pszFilename );
 void     CPL_DLL  NITFClose( NITFFile * );
 
 int      CPL_DLL  NITFCreate( const char *pszFilename, 
diff --git a/frmts/nitf/nitfrasterband.cpp b/frmts/nitf/nitfrasterband.cpp
index b580826..63fa7c4 100644
--- a/frmts/nitf/nitfrasterband.cpp
+++ b/frmts/nitf/nitfrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfrasterband.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: nitfrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  NITF Read/Write Translator
  * Purpose:  NITFRasterBand (and related proxy band) implementations.
@@ -35,7 +35,7 @@
 #include "cpl_string.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: nitfrasterband.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: nitfrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /************************************************************************/
 /*                       NITFMakeColorTable()                           */
@@ -309,11 +309,11 @@ RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IRasterIO, Ra
                                 int nXOff, int nYOff, int nXSize, int nYSize,
                                 void * pData, int nBufXSize, int nBufYSize,
                                 GDALDataType eBufType,
-                                int nPixelSpace,
-                                int nLineSpace ),
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GDALRasterIOExtraArg* psExtraArg ),
                         (eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                 pData, nBufXSize, nBufYSize, eBufType,
-                                nPixelSpace, nLineSpace ) )
+                                nPixelSpace, nLineSpace, psExtraArg ) )
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, FlushCache, (), ())
 
@@ -330,7 +330,7 @@ RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
 RB_PROXY_METHOD_WITH_RET(int, 0,  GetOverviewCount, (), ())
 RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetOverview, (int arg1), (arg1))
 RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetRasterSampleOverview,
-                        (int arg1), (arg1))
+                        (GUIntBig arg1), (arg1))
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
                         (const char * arg1, int arg2, int *arg3,
diff --git a/frmts/nitf/nitfwritejpeg.cpp b/frmts/nitf/nitfwritejpeg.cpp
index 473c4e5..a7a5035 100644
--- a/frmts/nitf/nitfwritejpeg.cpp
+++ b/frmts/nitf/nitfwritejpeg.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nitfwritejpeg.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: nitfwritejpeg.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  NITF Read/Write Translator
  * Purpose:  GDALDataset/GDALRasterBand implementation on top of "nitflib".
@@ -204,7 +204,7 @@ NITFWriteJPEGBlock( GDALDataset *poSrcDS, VSILFILE *fp,
             eErr = poSrcDS->RasterIO( GF_Read, nBlockXSize * nBlockXOff, iLine + nBlockYSize * nBlockYOff, nBlockXSizeToRead, 1, 
                                     pabyScanline, nBlockXSizeToRead, 1, eWorkDT,
                                     nBands, anBandList, 
-                                    nBands*nWorkDTSize, nBands * nBlockXSize * nWorkDTSize, nWorkDTSize );
+                                    nBands*nWorkDTSize, nBands * nBlockXSize * nWorkDTSize, nWorkDTSize, NULL );
 
 #if !defined(JPEG_LIB_MK1_OR_12BIT)
             /* Repeat the last pixel till the end of the line */
diff --git a/frmts/nitf/rpftocdataset.cpp b/frmts/nitf/rpftocdataset.cpp
index 83078e7..72d2c6d 100644
--- a/frmts/nitf/rpftocdataset.cpp
+++ b/frmts/nitf/rpftocdataset.cpp
@@ -42,7 +42,7 @@
 #define GEOTRSFRM_ROTATION_PARAM2      4
 #define GEOTRSFRM_NS_RES               5
 
-CPL_CVSID("$Id: rpftocdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rpftocdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 
 /** Overview of used classes :
@@ -1270,6 +1270,7 @@ void GDALRegister_RPFTOC()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "RPFTOC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Raster Product Format TOC format" );
         
diff --git a/frmts/northwood/GNUmakefile b/frmts/northwood/GNUmakefile
index eb5af8f..d272a86 100644
--- a/frmts/northwood/GNUmakefile
+++ b/frmts/northwood/GNUmakefile
@@ -4,7 +4,7 @@ include $(GDAL_ROOT)/GDALmake.opt
 
 OBJ    =    grddataset.o grcdataset.o northwood.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/northwood/grcdataset.cpp b/frmts/northwood/grcdataset.cpp
index e012e37..868e7f7 100644
--- a/frmts/northwood/grcdataset.cpp
+++ b/frmts/northwood/grcdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: grcdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: grcdataset.cpp 28502 2015-02-16 16:55:20Z rouault $
  *
  * Project:  GRC Reader
  * Purpose:  GDAL driver for Northwood Classified Format
@@ -83,9 +83,6 @@ class NWT_GRCDataset : public GDALPamDataset
 class NWT_GRCRasterBand : public GDALPamRasterBand
 {
   friend class NWT_GRCDataset;
-    int bHaveOffsetScale;
-    double dfOffset;
-    double dfScale;
 
   public:
 
@@ -95,11 +92,6 @@ class NWT_GRCRasterBand : public GDALPamRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual double GetNoDataValue( int *pbSuccess );
 
-    virtual double GetOffset( int *pbSuccess = NULL );
-    virtual CPLErr SetOffset( double dfNewValue );
-    virtual double GetScale( int *pbSuccess = NULL );
-    virtual CPLErr SetScale( double dfNewValue );
-
     virtual GDALColorInterp GetColorInterpretation();
     virtual char **GetCategoryNames();
     virtual GDALColorTable *GetColorTable();
@@ -116,9 +108,6 @@ NWT_GRCRasterBand::NWT_GRCRasterBand( NWT_GRCDataset * poDS, int nBand )
     this->nBand = nBand;
     NWT_GRCDataset *poGDS =( NWT_GRCDataset * ) poDS;
 
-    bHaveOffsetScale = FALSE;
-    dfOffset = 0;
-    dfScale = 1.0;
     if( poGDS->pGrd->nBitsPerPixel == 8 )
         eDataType = GDT_Byte;
     else if( poGDS->pGrd->nBitsPerPixel == 16 )
@@ -228,8 +217,9 @@ GDALColorInterp NWT_GRCRasterBand::GetColorInterpretation()
 /************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
-CPLErr NWT_GRCRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                        void *pImage )
+CPLErr NWT_GRCRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                      int nBlockYOff,
+                                      void *pImage )
 {
     NWT_GRCDataset *poGDS =(NWT_GRCDataset *) poDS;
     int nRecordSize = nBlockXSize *( poGDS->pGrd->nBitsPerPixel / 8 );
@@ -249,49 +239,6 @@ CPLErr NWT_GRCRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
     return CE_None;
 }
 
-
-/************************************************************************/
-/*                             GetOffset()                              */
-/************************************************************************/
-double NWT_GRCRasterBand::GetOffset( int *pbSuccess )
-{
-    if( pbSuccess )
-        *pbSuccess = bHaveOffsetScale;
-    return dfOffset;
-}
-
-/************************************************************************/
-/*                             SetOffset()                              */
-/************************************************************************/
-CPLErr NWT_GRCRasterBand::SetOffset( double dfNewValue )
-{
-    //poGDS->bMetadataChanged = TRUE;
-
-    bHaveOffsetScale = TRUE;
-    dfOffset = dfNewValue;
-    return CE_None;
-}
-
-/************************************************************************/
-/*                              GetScale()                              */
-/************************************************************************/
-double NWT_GRCRasterBand::GetScale( int *pbSuccess )
-{
-    if( pbSuccess )
-        *pbSuccess = bHaveOffsetScale;
-    return dfScale;
-}
-
-/************************************************************************/
-/*                              SetScale()                              */
-/************************************************************************/
-CPLErr NWT_GRCRasterBand::SetScale( double dfNewValue )
-{
-    bHaveOffsetScale = TRUE;
-    dfScale = dfNewValue;
-    return CE_None;
-}
-
 /************************************************************************/
 /* ==================================================================== */
 /*                          NWT_GRCDataset                              */
@@ -438,7 +385,7 @@ GDALDataset *NWT_GRCDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return (poDS);
 }
@@ -458,6 +405,7 @@ GDALRegister_NWT_GRC()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "NWT_GRC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                  "Northwood Classified Grid Format .grc/.tab");
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/northwood/grddataset.cpp b/frmts/northwood/grddataset.cpp
index 6ba9d88..95b0873 100644
--- a/frmts/northwood/grddataset.cpp
+++ b/frmts/northwood/grddataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: grddataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: grddataset.cpp 28502 2015-02-16 16:55:20Z rouault $
  *
  * Project:  GRD Reader
  * Purpose:  GDAL driver for Northwood Grid Format
@@ -91,13 +91,6 @@ class NWT_GRDRasterBand:public GDALPamRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual double GetNoDataValue( int *pbSuccess );
 
-    /* FIXME. I don't believe it is correct to advertize offset and */
-    /* scale because IReadBlock() already apply them. */
-    virtual double GetOffset( int *pbSuccess = NULL );
-    virtual CPLErr SetOffset( double dfNewValue );
-    virtual double GetScale( int *pbSuccess = NULL );
-    virtual CPLErr SetScale( double dfNewValue );
-
     virtual GDALColorInterp GetColorInterpretation();
 };
 
@@ -173,7 +166,9 @@ GDALColorInterp NWT_GRDRasterBand::GetColorInterpretation()
 /************************************************************************/
 /*                             IReadBlock()                             */
 /************************************************************************/
-CPLErr NWT_GRDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff, void *pImage )
+CPLErr NWT_GRDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                      int nBlockYOff,
+                                      void *pImage )
 {
     NWT_GRDDataset *poGDS = (NWT_GRDDataset *) poDS;
     char *pszRecord;
@@ -246,48 +241,6 @@ CPLErr NWT_GRDRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 }
 
 /************************************************************************/
-/*                             GetOffset()                              */
-/************************************************************************/
-double NWT_GRDRasterBand::GetOffset( int *pbSuccess )
-{
-    if( pbSuccess )
-        *pbSuccess = bHaveOffsetScale;
-    return dfOffset;
-}
-
-/************************************************************************/
-/*                             SetOffset()                              */
-/************************************************************************/
-CPLErr NWT_GRDRasterBand::SetOffset( double dfNewValue )
-{
-    //poGDS->bMetadataChanged = TRUE;
-
-    bHaveOffsetScale = TRUE;
-    dfOffset = dfNewValue;
-    return CE_None;
-}
-
-/************************************************************************/
-/*                              GetScale()                              */
-/************************************************************************/
-double NWT_GRDRasterBand::GetScale( int *pbSuccess )
-{
-    if( pbSuccess )
-        *pbSuccess = bHaveOffsetScale;
-    return dfScale;
-}
-
-/************************************************************************/
-/*                              SetScale()                              */
-/************************************************************************/
-CPLErr NWT_GRDRasterBand::SetScale( double dfNewValue )
-{
-    bHaveOffsetScale = TRUE;
-    dfScale = dfNewValue;
-    return CE_None;
-}
-
-/************************************************************************/
 /* ==================================================================== */
 /*                             NWT_GRDDataset                           */
 /* ==================================================================== */
@@ -440,7 +393,7 @@ GDALDataset *NWT_GRDDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return (poDS);
 }
@@ -458,6 +411,7 @@ void GDALRegister_NWT_GRD()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "NWT_GRD" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                  "Northwood Numeric Grid Format .grd/.tab" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_various.html#grd");
diff --git a/frmts/northwood/northwood.cpp b/frmts/northwood/northwood.cpp
index c72806b..feeddc1 100644
--- a/frmts/northwood/northwood.cpp
+++ b/frmts/northwood/northwood.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: northwood.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: northwood.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GRC/GRD Reader
  * Purpose:  Northwood Format basic implementation
diff --git a/frmts/ogdi/GNUmakefile b/frmts/ogdi/GNUmakefile
index 4d18e11..e7a997d 100644
--- a/frmts/ogdi/GNUmakefile
+++ b/frmts/ogdi/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	ogdidataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(OGDI_INCLUDE) $(PROJ_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(OGDI_INCLUDE) $(PROJ_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ogdi/ogdidataset.cpp b/frmts/ogdi/ogdidataset.cpp
index 61744a0..ae0590f 100644
--- a/frmts/ogdi/ogdidataset.cpp
+++ b/frmts/ogdi/ogdidataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogdidataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogdidataset.cpp 28216 2014-12-25 18:02:53Z goatbar $
  *
  * Name:     ogdidataset.cpp
  * Project:  OGDI Bridge
@@ -35,7 +35,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: ogdidataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogdidataset.cpp 28216 2014-12-25 18:02:53Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_OGDI(void);
@@ -69,19 +69,17 @@ class CPL_DLL OGDIDataset : public GDALDataset
     char	**papszSubDatasets;
 
   public:
-    		OGDIDataset();
-    		~OGDIDataset();
-                
+    OGDIDataset();
+    ~OGDIDataset();
+
     static GDALDataset *Open( GDALOpenInfo * );
 
-    int		GetClientID() { return nClientID; }
+    int GetClientID() { return nClientID; }
 
     virtual const char *GetProjectionRef(void);
     virtual CPLErr GetGeoTransform( double * );
 
-    virtual void *GetInternalHandle( const char * );
-
-    virtual char      **GetMetadataDomainList();
+    virtual char **GetMetadataDomainList();
     virtual char **GetMetadata( const char * pszDomain = "" );
 };
 
@@ -106,7 +104,9 @@ class OGDIRasterBand : public GDALRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace,
+                              GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     CPLErr         EstablishAccess( int nXOff, int nYOff, 
                                     int nXSize, int nYSize,
@@ -232,27 +232,31 @@ OGDIRasterBand::~OGDIRasterBand()
 CPLErr OGDIRasterBand::IReadBlock( int, int nBlockYOff, void * pImage )
 
 {
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     return IRasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1, 
                       pImage, nBlockXSize, 1, eDataType, 
-                      GDALGetDataTypeSize(eDataType)/8, 0 );
+                      GDALGetDataTypeSize(eDataType)/8, 0, &sExtraArg );
 }
 
 /************************************************************************/
 /*                             IRasterIO()                              */
 /************************************************************************/
 
-CPLErr OGDIRasterBand::IRasterIO( GDALRWFlag eRWFlag,
+CPLErr OGDIRasterBand::IRasterIO( CPL_UNUSED GDALRWFlag eRWFlag,
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace )
-
+                                  GSpacing nPixelSpace,
+                                  GSpacing nLineSpace,
+                                  CPL_UNUSED GDALRasterIOExtraArg* psExtraArg )
 {
     OGDIDataset	*poODS = (OGDIDataset *) poDS;
     CPLErr    eErr;
 #ifdef notdef
-    CPLDebug( "OGDIRasterBand", 
-              "RasterIO(%d,%d,%d,%d -> %dx%d)", 
+    CPLDebug( "OGDIRasterBand",
+              "RasterIO(%d,%d,%d,%d -> %dx%d)",
               nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
 #endif
 
@@ -495,7 +499,8 @@ GDALColorTable *OGDIRasterBand::GetColorTable()
 CPLErr OGDIRasterBand::AdviseRead( int nXOff, int nYOff, 
                                    int nXSize, int nYSize,
                                    int nBufXSize, int nBufYSize, 
-                                   GDALDataType eDT, char **papszOptions )
+                                   CPL_UNUSED GDALDataType eDT,
+                                   CPL_UNUSED char **papszOptions )
 
 {
     return EstablishAccess( nXOff, nYOff, nXSize, nYSize, 
@@ -685,7 +690,7 @@ GDALDataset *OGDIDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     psResult = cln_GetVersion(nClientID);
     
-    if( (ECSERROR(psResult) || atof(ECSTEXT(psResult)) >= 3.1)
+    if( (ECSERROR(psResult) || CPLAtof(ECSTEXT(psResult)) >= 3.1)
         && CSLCount(papszMatrices) == 0 
         && CSLCount(papszImages) == 0 )
     {
@@ -946,19 +951,6 @@ CPLErr OGDIDataset::GetGeoTransform( double * padfTransform )
 }
 
 /************************************************************************/
-/*                         GetInternalHandle()                          */
-/************************************************************************/
-
-void *OGDIDataset::GetInternalHandle( const char * pszRequest )
-
-{
-    if( EQUAL(pszRequest,"ClientID") )
-        return (void *) nClientID;
-    else
-        return NULL;
-}
-
-/************************************************************************/
 /*                          GDALRegister_OGDI()                        */
 /************************************************************************/
 
@@ -975,6 +967,7 @@ void GDALRegister_OGDI()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "OGDI" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "OGDI Bridge" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -986,4 +979,3 @@ void GDALRegister_OGDI()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/openjpeg/GNUmakefile b/frmts/openjpeg/GNUmakefile
index 9f90b1c..76f7e26 100644
--- a/frmts/openjpeg/GNUmakefile
+++ b/frmts/openjpeg/GNUmakefile
@@ -3,12 +3,15 @@ include ../../GDALmake.opt
 
 OBJ	=	openjpegdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 ifneq ($(OPENJPEG_VERSION),)
-CPPFLAGS        :=      $(CPPFLAGS) -DOPENJPEG_VERSION=$(OPENJPEG_VERSION)
+CPPFLAGS 	:=	$(CPPFLAGS) -DOPENJPEG_VERSION=$(OPENJPEG_VERSION)
 endif
 
+CPPFLAGS        :=       -I.. $(CPPFLAGS)
+
+
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
 clean:
diff --git a/frmts/openjpeg/eoptemplate_pleiades.xml b/frmts/openjpeg/eoptemplate_pleiades.xml
new file mode 100644
index 0000000..75ce8c9
--- /dev/null
+++ b/frmts/openjpeg/eoptemplate_pleiades.xml
@@ -0,0 +1,46 @@
+<eop:EarthObservation
+    gml:id="GMLID_{{{XPATH(uuid())}}}"
+    xmlns:eop="http://www.opengis.net/eop/2.0"
+    xmlns:gml="http://www.opengis.net/gml/3.2"
+    xmlns:om="http://www.opengis.net/om/2.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.opengis.net/eop/2.0 http://schemas.opengis.net/omeo/1.0/eop.xsd http://www.opengis.net/om/2.0 http://schemas.opengis.net/om/2.0/observation.xsd">
+    <om:phenomenonTime>
+        <gml:TimeInstant gml:id="GMLID_{{{XPATH(uuid())}}}">
+            <gml:timePosition>{{{XPATH(//PRODUCTION_DATE/text())}}}</gml:timePosition>
+        </gml:TimeInstant>
+    </om:phenomenonTime>
+    <om:resultTime />
+    <om:procedure>
+        <eop:EarthObservationEquipment gml:id="GMLID_{{{XPATH(uuid())}}}">
+            <eop:platform>
+                <eop:Platform>
+                    <eop:shortName>{{{XPATH(//PRODUCT_CODE/text())}}}</eop:shortName>
+                </eop:Platform>
+            </eop:platform>
+            <eop:instrument>
+                <eop:Instrument>
+                    <eop:shortName>{{{XPATH(//PRODUCT_CODE/text())}}}</eop:shortName>
+                </eop:Instrument>
+            </eop:instrument>
+            <eop:sensor>
+                <eop:Sensor>
+                    <eop:sensorType>{{{XPATH(//DATASET_TYPE/text())}}}</eop:sensorType>
+                    <eop:operationalMode>{{{XPATH(if(//PAN_RESTORATION/text() = 'true','P',if(//MS_RESTORATION/text() = 'true','Multi','Unknown')))}}}</eop:operationalMode>
+                    <eop:resolution uom="{{{XPATH(string(//RESAMPLING_SPACING/@unit))}}}">{{{XPATH(//RESAMPLING_SPACING/text())}}}</eop:resolution>
+                </eop:Sensor>
+        </eop:sensor>
+        </eop:EarthObservationEquipment>
+    </om:procedure>
+    <om:observedProperty />
+    <om:featureOfInterest />
+    <om:result />
+    <eop:metaDataProperty>
+        <eop:EarthObservationMetaData>
+            <eop:identifier>{{{XPATH(uuid())}}}</eop:identifier>
+            <eop:acquisitionType>NOMINAL</eop:acquisitionType>
+            <eop:status>ACQUIRED</eop:status>
+        </eop:EarthObservationMetaData>
+    </eop:metaDataProperty>
+</eop:EarthObservation>
+
diff --git a/frmts/openjpeg/eoptemplate_worldviewgeoeye.xml b/frmts/openjpeg/eoptemplate_worldviewgeoeye.xml
new file mode 100644
index 0000000..19ecfc2
--- /dev/null
+++ b/frmts/openjpeg/eoptemplate_worldviewgeoeye.xml
@@ -0,0 +1,46 @@
+<eop:EarthObservation
+    gml:id="GMLID_{{{XPATH(uuid())}}}"
+    xmlns:eop="http://www.opengis.net/eop/2.0"
+    xmlns:gml="http://www.opengis.net/gml/3.2"
+    xmlns:om="http://www.opengis.net/om/2.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.opengis.net/eop/2.0 http://schemas.opengis.net/omeo/1.0/eop.xsd http://www.opengis.net/om/2.0 http://schemas.opengis.net/om/2.0/observation.xsd">
+    <om:phenomenonTime>
+        <gml:TimeInstant gml:id="GMLID_{{{XPATH(uuid())}}}">
+            <gml:timePosition>{{{XPATH(//GENERATIONTIME/text())}}}</gml:timePosition>
+        </gml:TimeInstant>
+    </om:phenomenonTime>
+    <om:resultTime />
+    <om:procedure>
+        <eop:EarthObservationEquipment gml:id="GMLID_{{{XPATH(uuid())}}}">
+            <eop:platform>
+                <eop:Platform>
+                    <eop:shortName>{{{XPATH(//SATID/text())}}}</eop:shortName>
+                </eop:Platform>
+            </eop:platform>
+            <eop:instrument>
+                <eop:Instrument>
+                    <eop:shortName>{{{XPATH(//SATID/text())}}}</eop:shortName>
+                </eop:Instrument>
+            </eop:instrument>
+            <eop:sensor>
+                <eop:Sensor>
+                    <eop:sensorType>OPTICAL</eop:sensorType>
+                    <eop:operationalMode>{{{XPATH((//BANDID/text())[1])}}}</eop:operationalMode>
+                    <eop:resolution uom="{{{XPATH(//PRODUCTUNITS/text())}}}">{{{XPATH(//PRODUCTGSD/text())}}}</eop:resolution>
+                </eop:Sensor>
+            </eop:sensor>
+        </eop:EarthObservationEquipment>
+    </om:procedure>
+    <om:observedProperty />
+    <om:featureOfInterest />
+    <om:result />
+    <eop:metaDataProperty>
+        <eop:EarthObservationMetaData>
+            <eop:identifier>{{{XPATH(uuid())}}}</eop:identifier>
+            <eop:acquisitionType>NOMINAL</eop:acquisitionType>
+            <eop:status>ACQUIRED</eop:status>
+        </eop:EarthObservationMetaData>
+    </eop:metaDataProperty>
+</eop:EarthObservation>
+
diff --git a/frmts/openjpeg/frmt_jp2openjpeg.html b/frmts/openjpeg/frmt_jp2openjpeg.html
index a5dd68d..89d2d02 100644
--- a/frmts/openjpeg/frmt_jp2openjpeg.html
+++ b/frmts/openjpeg/frmt_jp2openjpeg.html
@@ -11,7 +11,7 @@
 
 <p>This driver is an implementation of a JPEG2000 reader/writer based on OpenJPEG library <b>v2</b>.</p>
 
-<p>For GDAL 1.10 or later, use openjpeg 2.0.</p>
+<p>For GDAL 1.10 or later, use openjpeg 2.X.</p>
 <p>For GDAL 1.9.x or before, use the v2 branch from its Subversion repository : http://openjpeg.googlecode.com/svn/branches/v2 (before r2230 when it was deleted).</p>
 
 <p>The driver uses the VSI Virtual File API, so it can read JPEG2000 compressed NITF files.</p>
@@ -21,40 +21,413 @@ stored as XML raw content in the xml:XMP metadata domain.</p>
 
 <p>Starting with GDAL 1.10, the driver supports writing georeferencing information as GeoJP2 and GMLJP2 boxes.</p>
 
+<p>Starting with GDAL 2.0, the driver supports creating files with transparency,
+arbitrary band count, and adding/reading metadata. Update of georeferencing or
+metadata of existing file is also supported. Optional intellectual property
+metdata can be read/written in the xml:IPR box.</p>
+
+<h2>Option Options</h2>
+
+(GDAL >= 2.0 )
+
+The following open option is available:
+<ul>
+<li><p><b>1BIT_ALPHA_PROMOTION=YES/NO</b>: Whether a 1-bit alpha channel should be promoted to 8-bit.
+Defaults to YES.</li>
+</ul>
+
 <h2>Creation Options</h2>
 
 <ul>
-<li><p><b>CODEC=JP2/J2K</b> : JP2 will add JP2 boxes around the codestream data. The value is determined
-automatically from the file extension. If it's neither JP2 nor J2K, J2K codec is used.</p></li>
+<li><p><b>CODEC=JP2/J2K</b> : JP2 will add JP2 boxes around the codestream data.
+The value is determined automatically from the file extension. If it's neither
+JP2 nor J2K, J2K codec is used.</p></li>
+
+<li> <b>GMLJP2=YES/NO</b>: (Starting with GDAL 1.10) Indicates whether a GML box
+ conforming to the OGC GML in JPEG2000 specification should be included in the
+file. Unless GMLJP2V2_DEF is used, the version of the GMLJP2 box will be
+version 1. Defaults to YES.<p>
+
+<li> <b>GMLJP2V2_DEF=filename</b>: (Starting with GDAL 2.0) Indicates whether a GML box
+conforming to the <a href="http://docs.opengeospatial.org/is/08-085r4/08-085r4.html">
+OGC GML in JPEG2000, version 2</a> specification should be included in the
+file. <i>filename</i> must point to a file with a JSon content that defines how
+the GMLJP2 v2 box should be built. See below section for the syntax of the JSon configuration file.
+It is also possible to directly pass the JSon content inlined as a string.
+If filename is just set to YES, a minimal instance will be built.<p>
+
+<li> <b>GeoJP2=YES/NO</b>: (Starting with GDAL 1.10) Indicates whether a
+UUID/GeoTIFF box conforming to the GeoJP2 (GeoTIFF in JPEG2000) specification
+should be included in the file.  Defaults to YES.<p>
+
+<li><p><b>QUALITY=float_value,float_value,...</b> : Percentage between 0 and 100.
+A value of 50 means the file will be half-size in comparison to uncompressed data,
+33 means 1/3, etc.. Defaults to 25 (unless the dataset is made of a single band
+with color table, in which case the default quality is 100).
+Starting with GDAL 2.0, it is possible to specify several quality values
+(comma separated) to ask for several quality layers. Quality values should be
+increasing.
+</li>
+
+<li><p><b>REVERSIBLE=YES/NO</b> : YES means use of reversible 5x3 integer-only
+filter, NO use of the irreversible DWT 9-7. Defaults to NO  (unless the dataset
+is made of a single band with color table, in which case reversible filter is
+used).</p></li>
+
+<li><p><b>RESOLUTIONS=int_value</b> : Number of resolution levels. Default value
+is selected such the smallest overview of a tile is no bigger than 128x128.</p></li>
+
+<li><p><b>BLOCKXSIZE=int_value</b> : Tile width. Defaults to 1024.</p></li>
+
+<li><p><b>BLOCKYSIZE=int_value</b> : Tile height. Defaults to 1024.</p></li>
+
+<li><p><b>PROGRESSION=LRCP/RLCP/RPCL/PCRL/CPRL</b> : Progession order. Defaults
+to LRCP.</p></li>
+
+<li><p><b>SOP=YES/NO</b> : YES means generate SOP (Start Of Packet) marker
+segments. Defaults to NO.</p></li>
+
+<li><p><b>EPH=YES/NO</b> : YES means generate EPH (End of Packet Header) marker
+segments. Defaults to NO.</p></li>
+
+<li><p><b>YCBCR420=YES/NO</b> : (GDAL >= 1.11) YES if RGB must be resampled
+to YCbCr 4:2:0. Defaults to NO.</p></li>
+
+<li><p><b>YCC=YES/NO</b> : (GDAL >= 2.0) YES if RGB must be transformed to
+YCC color space ("MCT transform", i.e. internal transform, without visual
+degration). Defaults to YES.</p></li>
 
-<li> <b>GMLJP2=YES/NO</b>: (Starting with GDAL 1.10) Indicates whether a GML box conforming to the OGC GML in JPEG2000 specification should be included in the file.  Defaults to YES.<p>
+<li><p><b>NBITS=int_value</b> : (GDAL >= 2.0) Bits (precision) for sub-byte
+files (1-7), sub-uint16 (9-15), sub-uint32 (17-31).</p></li>
 
-<li> <b>GeoJP2=YES/NO</b>: (Starting with GDAL 1.10) Indicates whether a UUID/GeoTIFF box conforming to the GeoJP2 (GeoTIFF in JPEG2000) specification should be included in the file.  Defaults to YES.<p>
+<li><p><b>1BIT_ALPHA=YES/NO</b>: (GDAL >= 2.0) Whether to encode the alpha
+channel as a 1-bit channel (when there's an alpha channel). Defaults to NO,
+unless INSPIRE_TG=YES. Enabling this option might cause compatibility problems
+with some readers. At the time of writing, those based on the MrSID JPEG2000 SDK
+are unable to open such files. And regarding the ECW JPEG2000 SDK, decoding of
+1-bit alpha channel with lossy/irreversible compression gives visual artifacts
+(OK with lossless encoding).
+</p></li>
+
+<li><p><b>ALPHA=YES/NO</b>: (GDAL >= 2.0) Whether to force encoding last
+channel as alpha channel. Only usefull if the color interpretation of that channel
+is not already Alpha. Defaults to NO.</p></li>
+
+<li><p><b>PROFILE=AUTO/UNRESTRICTED/PROFILE_1</b>: (GDAL >= 2.0) Determine
+which codestream profile to use. UNRESTRICTED corresponds to the
+"Unrestricted JPEG 2000 Part 1 codestream" (RSIZ=0). PROFILE_1 corresponds
+to the "JPEG 2000 Part 1 Profile 1 codestream" (RSIZ=2), which add constraints
+on tile dimensions and number of resolutions. In AUTO mode, the driver
+will determine if the BLOCKXSIZE, BLOCKYSIZE, RESOLUTIONS, CODEBLOCK_WIDTH and
+CODEBLOCK_HEIGHT values are compatible with PROFILE_1 and advertize it in the
+relevant case. Note that the default values of those options are compatible with
+PROFILE_1. Otherwise UNRESTRICTED is advertized. Defaults to AUTO.</p></li>
+
+<li><p><b>INSPIRE_TG=YES/NO</b>: (GDAL >= 2.0) Whether to use JPEG2000 features that
+comply with <a href="http://inspire.ec.europa.eu/documents/Data_Specifications/INSPIRE_DataSpecification_OI_v3.0.pdf">
+Inspire Orthoimagery Technical Guidelines</a>. Defaults to NO.
+When set to YES, implies PROFILE=PROFILE_1, 1BIT_ALPHA=YES, GEOBOXES_AFTER_JP2C=YES.
+The CODEC, BLOCKXSIZE, BLOCKYSIZE, RESOLUTIONS, NBITS, PROFILE, CODEBLOCK_WIDTH
+and CODEBLOCK_HEIGHT options will be checked against the requirements and recommendations of the
+Technical Guidelines.
+</p></li>
+
+<li><p><b>JPX=YES/NO</b>: (GDAL >= 2.0) Whether to advertize JPX features, and
+add a Reader requirement box, when a GMLJP2 box is written. Defaults to YES.
+This option should not be used unless compatibility problems with a reader
+occur.</p></li>
+
+<li><p><b>GEOBOXES_AFTER_JP2C=YES/NO</b>: (GDAL >= 2.0) Whether to place
+GeoJP2/GMLJP2 boxes after the code-stream. Defaults to NO, unless INSPIRE_TG=YES.
+This option should not be used unless compatibility problems with a reader occur.
+</p></li>
+
+<li><p><b>PRECINCTS={prec_w,prec_h},{prec_w,prec_h},...</b>: (GDAL >= 2.0)
+A list of {precincts width,precincts height} tuples to specify precincts size.
+Each value should be a multiple of 2. The maximum number of tuples used will be
+the number of resolutions. The first tuple corresponds to the higher resolution
+level, and the following ones to the lower resolution levels.
+If less tuples are specified, the last one is used by
+dividing its values by 2 for each extra lower resolution level.
+The default value used is {512,512},{256,512},{128,512},{64,512},{32,512},{16,512},{8,512},{4,512},{2,512}.
+An empty string may be used to disable precincts (
+i.e. the default {32767,32767},{32767,32767}, ... will then be used).
+</p></li>
+
+<li><p><b>TILEPARTS=DISABLED/RESOLUTIONS/LAYERS/COMPONENTS</b>: (GDAL >= 2.0)
+Whether to generate tile-parts and according to which criterion. Defaults to
+DISABLED.
+</p></li>
+
+<li><p><b>CODEBLOCK_WIDTH=int_value</b>: (GDAL >= 2.0)
+Codeblock width: power of two value between 4 and 1024. Defaults to 64.
+Note that CODEBLOCK_WIDTH * CODEBLOCK_HEIGHT must not be greater than 4096.
+For PROFILE_1 compatibility, CODEBLOCK_WIDTH must not be greater than 64.
+</p></li>
+
+<li><p><b>CODEBLOCK_HEIGHT=int_value</b>: (GDAL >= 2.0)
+Codeblock height: power of two value between 4 and 1024. Defaults to 64.
+Note that CODEBLOCK_WIDTH * CODEBLOCK_HEIGHT must not be greater than 4096.
+For PROFILE_1 compatibility, CODEBLOCK_HEIGHT must not be greater than 64.
+</p></li>
+
+<li><p><b>WRITE_METADATA=YES/NO</b>: (GDAL >= 2.0) Whether metadata should be
+written, in a dedicated JP2 'xml ' box. Defaults to NO.
+The content of the 'xml ' box will be like:
+<pre>
+<GDALMultiDomainMetadata>
+  <Metadata>
+    <MDI key="foo">bar</MDI>
+  </Metadata>
+  <Metadata domain='aux_domain'>
+    <MDI key="foo">bar</MDI>
+  </Metadata>
+  <Metadata domain='a_xml_domain' format='xml'>
+    <arbitrary_xml_content>
+    </arbitrary_xml_content>
+  </Metadata>
+</GDALMultiDomainMetadata>
+</pre>
+If there are metadata domain whose name starts with "xml:BOX_", they will be
+written each as separate JP2 'xml ' box.<p>
+If there is a metadata domain whose name is "xml:XMP", its content will be
+written as a JP2 'uuid' XMP box.<p>
+If there is a metadata domain whose name is "xml:IPR", its content will be
+written as a JP2 'jp2i' box.
+</p></li>
+
+<li><p><b>MAIN_MD_DOMAIN_ONLY=YES/NO</b>: (GDAL >= 2.0)
+(Only if WRITE_METADATA=YES) Whether only metadata from the main domain should
+be written. Defaults to NO.
+</p></li>
+
+<li><p><b>USE_SRC_CODESTREAM=YES/NO</b>: (GDAL >= 2.0)
+(EXPERIMENTAL!) When source dataset is JPEG2000, whether to reuse the codestream
+of the source dataset unmodified. Defaults to NO. Note that enabling that feature might result
+in inconsistant content of the JP2 boxes w.r.t. to the content of the source codestream.
+Most other creation options will be ignored in that mode. Can be usefull in some
+use cases when adding/correcting georeferencing, metadata, ... INSPIRE_TG and
+PROFILE options will be ignored, and the profile of the codestream will be overriden
+with the one specified/implied by the options (which may be inconsistant with
+the characteristics of the codestream).
+</p></li>
 
-<li><p><b>QUALITY</b> : Percentage between 0 and 100. A value of 50 means the file will be half-size in comparison to uncompressed data, 33 means 1/3, etc.. Defaults to 25</li>
-<li><p><b>REVERSIBLE=YES/NO</b> : YES means lossless compression. Defaults to NO.</p></li>
-<li><p><b>RESOLUTIONS</b> : Number of resolution levels. Between 1 and 7. Defaults to 6.</p></li>
-<li><p><b>BLOCKXSIZE</b> : Tile width. Defaults to 1024.</p></li>
-<li><p><b>BLOCKYSIZE</b> : Tile height. Defaults to 1024.</p></li>
-<li><p><b>PROGRESSION</b> : Progession order : LRCP, RLCP, RPCL, PCRL or CPRL. Defaults to LRCP.</p></li>
-<li><p><b>SOP=YES/NO</b> : YES means generate SOP marker segments. Defaults to NO.</p></li>
-<li><p><b>EPH=YES/NO</b> : YES means generate EPH marker segments. Defaults to NO.</p></li>
 </ul>
 
+<h3>Lossless compression</h3>
+
+Lossless compression can be achieved if ALL the following creation options are defined :
+<ul>
+<li>QUALITY=100</li>
+<li>REVERSIBLE=YES</li>
+<li>YCBCR420=NO (which is the default)</li>
+</ul>
+
+<h3><a name="GMLJP2v2Def">GMLJP2v2 definition file</a></h3>
+
+A GMLJP2v2 box typically contains a GMLJP2RectifiedGridCoverage with the 
+SRS information and geotransformation matrix. It is also possible to add metadata,
+vector features (GML feature collections), annotations (KML), styles (typically
+SLD, or other XML format) or any XML content as an extension.
+
+The value of the GMLJP2V2_DEF creation option should be a file that conforms with
+the below syntax (elements starting with "#" are documentation, and can be omitted):
+
+<pre>
+{
+    "#doc" : "Unless otherwise specified, all elements are optional",
+
+    "#root_instance_doc": "Describe content of the GMLJP2CoverageCollection",
+    "root_instance": {
+        "#gml_id_doc": "Specify GMLJP2CoverageCollection gml:id. Default is ID_GMLJP2_0",
+        "gml_id": "some_gml_id",
+
+        "#grid_coverage_file_doc": [
+            "External XML file, whose root might be a GMLJP2GridCoverage, ",
+            "GMLJP2RectifiedGridCoverage or a GMLJP2ReferenceableGridCoverage.",
+            "If not specified, GDAL will auto-generate a GMLJP2RectifiedGridCoverage" ],
+        "grid_coverage_file": "gmljp2gridcoverage.xml",
+
+        "#crs_url_doc": [
+            "true for http://www.opengis.net/def/crs/EPSG/0/XXXX CRS URL.",
+            "If false, use CRS URN. Default value is true",
+            "Only taken into account for a auto-generated GMLJP2RectifiedGridCoverage"],
+        "crs_url": true,
+
+        "#metadata_doc": [ "An array of metadata items. Can be either strings, with ",
+                           "a filename or directly inline XML content, or either ",
+                           "a more complete description." ],
+        "metadata": [
+
+            "dcmetadata.xml",
+
+            {
+                "#file_doc": "Can use relative or absolute paths. Exclusive of content, gdal_metadata and generated_metadata.",
+                "file": "dcmetadata.xml",
+
+                "#gdal_metadata_doc": "Whether to serialize GDAL metadata as GDALMultiDomainMetadata",
+                "gdal_metadata": false,
+
+                "#dynamic_metadata_doc":
+                    [ "The metadata file will be generated from a template and a source file.",
+                      "The template is a valid GMLJP2 metadata XML tree with placeholders like",
+                      "{{{XPATH(some_xpath_expression)}}}",
+                      "that are evalated from the source XML file. Typical use case",
+                      "is to generate a gmljp2:eopMetadata from the XML metadata",
+                      "provided by the image provider in their own particular format." ],
+                "dynamic_metadata" :
+                {
+                    "template": "my_template.xml",
+                    "source": "my_source.xml"
+                },
+
+                "#content": "Exclusive of file. Inline XML metadata content",
+                "content": "<gmljp2:metadata>Some simple textual metadata</gmljp2:metadata>",
+
+                "#parent_node": ["Where to put the metadata.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ],
+
+        "#annotations_doc": [ "An array of filenames, either directly KML files",
+                              "or other vector files recognized by GDAL that ",
+                              "will be translated on-the-fly as KML" ],
+        "annotations": [
+            "my.kml"
+        ],
+
+        "#gml_filelist_doc" :[
+            "An array of GML files. Can be either GML filenames, ",
+            "or a more complete description" ],
+        "gml_filelist": [
+
+            "my.gml",
+
+            {
+                "#file_doc": "Can use relative or absolute paths. Exclusive of remote_resource",
+                "file": "converted/test_0.gml",
+
+                "#remote_resource_doc": "URL of a feature collection that must be referenced through a xlink:href",
+                "remote_resource": "http://svn.osgeo.org/gdal/trunk/autotest/ogr/data/expected_gml_gml32.gml",
+
+                "#namespace_doc": ["The namespace in schemaLocation for which to substitute",
+                                  "its original schemaLocation with the one provided below.",
+                                  "Ignored for a remote_resource"],
+                "namespace": "http://example.com",
+
+                "#schema_location_doc": ["Value of the substitued schemaLocation. ",
+                                         "Typically a schema box label (link)",
+                                         "Ignored for a remote_resource"],
+                "schema_location": "gmljp2://xml/schema_0.xsd",
+
+                "#inline_doc": [
+                    "Whether to inline the content, or put it in a separate xml box. Default is true",
+                    "Ignored for a remote_resource." ],
+                "inline": true,
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ],
+
+
+        "#styles_doc: [ "An array of styles. For example SLD files" ],
+        "styles" : [
+            {
+                "#file_doc": "Can use relative or absolute paths.",
+                "file": "my.sld",
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ],
+
+        "#extensions_doc: [ "An array of extensions." ],
+        "extensions" : [
+            {
+                "#file_doc": "Can use relative or absolute paths.",
+                "file": "my.xml",
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ]
+    },
+
+    "#boxes_doc": "An array to describe the content of XML asoc boxes",
+    "boxes": [
+        {
+            "#file_doc": "can use relative or absolute paths. Required",
+            "file": "converted/test_0.xsd",
+
+            "#label_doc": ["the label of the XML box. If not specified, will be the ",
+                          "filename without the directory part." ],
+            "label": "schema_0.xsd"
+        }
+    ]
+}
+</pre>
+
+<p>
+Metadata can be dynamically generated from a template file (in that context,
+with a XML structure) and a XML source file. The template file is processed
+by searching for patterns like {{{XPATH(xpath_expr)}}} and replacing them by their evaluation
+against the content of the source file. xpath_expr must be a XPath 1.0 compatible
+expression, with the addition of the following functions :
+
+<ul>
+<li><b>if(cond_expr,expr_if_true,expr_if_false)</b>: if cond_expr evalutes to
+true, returns expr_if_true. Otherwise returns expr_if_false</li>
+<li><b>uuid()</b>: evaluates to a random UUID</b></li>
+</ul>
+</p>
+
+<p>A template file to process XML metadata of Pleiades imagery can be found
+<a href="eoptemplate_pleiades.xml">here</a>, and
+a template file to process XML metadata of GeoEye/WorldView imagery can be found
+<a href="eoptemplate_worldviewgeoeye.xml">here</a>.</p>
+
+<h2>Vector information</h2>
+
+Starting with GDAL 2.0, a JPEG2000 file containing a GMLJP2 v2 box with GML feature
+collections and/or KML annotations embedded can be opened as a vector file with
+the OGR API.
+
+For example:
+<pre>
+ogrinfo -ro my.jp2 
+
+INFO: Open of my.jp2'
+      using driver `JP2OpenJPEG' successful.
+1: FC_GridCoverage_1_rivers (LineString)
+2: FC_GridCoverage_1_borders (LineString)
+3: Annotation_1_poly
+</pre>
+
+<p>Feature collections can be linked from the GMLJP2 v2 box to a remote location.
+By default, the link is not followed. It will be followed if the open option
+OPEN_REMOTE_GML is set to YES.</p>
+
 <h2>See Also:</h2>
 
 <ul>
 <li><p> Implemented as <tt>gdal/frmts/openjpeg/openjpegdataset.cpp</tt>.</p></li>
-<li><p> <a href="http://www.jpeg.org/JPEG2000.html">Official JPEG-2000 page<a></p></li>
+<li><p> <a href="http://www.jpeg.org/jpeg2000/index.html">Official JPEG-2000 page<a></p></li>
 <li><p> <a href="http://code.google.com/p/openjpeg/">The OpenJPEG library home page</a></p></li>
+<li><p> <a href="http://inspire.ec.europa.eu/documents/Data_Specifications/INSPIRE_DataSpecification_OI_v3.0.pdf">
+Inspire Data Specification on Orthoimagery - Technical Guidelines</a></p></li>
 </ul>
 
 Other JPEG2000 GDAL drivers :
 <ul>
 <li><p> <a href="frmt_jpeg2000.html">JPEG2000: based on Jasper library (open source)</a></p></li>
-<li><p> <a href="frmt_jp2ecw.html">JP2ECW: based on Erdas ECW library (commercial)</a></p></li>
-<li><p> <a href="frmt_jp2mrsid.html">JP2MRSID: based on LizardTech MrSID library (commercial)</a></p></li>
-<li><p> <a href="frmt_jp2kak.html">JP2KAK: based on Kakadu library (commercial)</a></p></li>
+<li><p> <a href="frmt_jp2ecw.html">JP2ECW: based on Erdas ECW library (proprietary)</a></p></li>
+<li><p> <a href="frmt_jp2mrsid.html">JP2MRSID: based on LizardTech MrSID library (proprietary)</a></p></li>
+<li><p> <a href="frmt_jp2kak.html">JP2KAK: based on Kakadu library (proprietary)</a></p></li>
 </ul>
 
 </body>
diff --git a/frmts/openjpeg/makefile.vc b/frmts/openjpeg/makefile.vc
index 2ad929e..e591b25 100644
--- a/frmts/openjpeg/makefile.vc
+++ b/frmts/openjpeg/makefile.vc
@@ -5,7 +5,7 @@ GDAL_ROOT	=	..\..
 
 !INCLUDE $(GDAL_ROOT)\nmake.opt
 
-EXTRAFLAGS = $(OPENJPEG_CFLAGS) $(OPENJPEG_VERSION_CFLAGS)
+EXTRAFLAGS = -I.. $(OPENJPEG_CFLAGS) $(OPENJPEG_VERSION_CFLAGS)
 
 !IFDEF OPENJPEG_VERSION
 OPENJPEG_VERSION_CFLAGS = -DOPENJPEG_VERSION=$(OPENJPEG_VERSION)
diff --git a/frmts/openjpeg/openjpegdataset.cpp b/frmts/openjpeg/openjpegdataset.cpp
index 1fd4f4f..e978e53 100644
--- a/frmts/openjpeg/openjpegdataset.cpp
+++ b/frmts/openjpeg/openjpegdataset.cpp
@@ -1,12 +1,13 @@
 /******************************************************************************
- * $Id: openjpegdataset.cpp 28317 2015-01-15 22:49:41Z tamas $
+ * $Id: openjpegdataset.cpp 29131 2015-05-03 14:47:58Z rouault $
  *
  * Project:  JPEG2000 driver based on OpenJPEG library
  * Purpose:  JPEG2000 driver based on OpenJPEG library
- * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2014, Even Rouault <even dot rouault at spatialys dot com>
+ * Copyright (c) 2015, European Union (European Environment Agency)
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -42,14 +43,15 @@
 #include "gdaljp2metadata.h"
 #include "cpl_multiproc.h"
 #include "cpl_atomic_ops.h"
+#include "vrt/vrtdataset.h"
 
-CPL_CVSID("$Id: openjpegdataset.cpp 28317 2015-01-15 22:49:41Z tamas $");
+CPL_CVSID("$Id: openjpegdataset.cpp 29131 2015-05-03 14:47:58Z rouault $");
 
 /************************************************************************/
 /*                  JP2OpenJPEGDataset_ErrorCallback()                  */
 /************************************************************************/
 
-static void JP2OpenJPEGDataset_ErrorCallback(const char *pszMsg, void *unused)
+static void JP2OpenJPEGDataset_ErrorCallback(const char *pszMsg, CPL_UNUSED void *unused)
 {
     CPLError(CE_Failure, CPLE_AppDefined, "%s", pszMsg);
 }
@@ -58,7 +60,7 @@ static void JP2OpenJPEGDataset_ErrorCallback(const char *pszMsg, void *unused)
 /*               JP2OpenJPEGDataset_WarningCallback()                   */
 /************************************************************************/
 
-static void JP2OpenJPEGDataset_WarningCallback(const char *pszMsg, void *unused)
+static void JP2OpenJPEGDataset_WarningCallback(const char *pszMsg, CPL_UNUSED void *unused)
 {
     if( strcmp(pszMsg, "Empty SOT marker detected: Psot=12.\n") == 0 )
     {
@@ -75,7 +77,7 @@ static void JP2OpenJPEGDataset_WarningCallback(const char *pszMsg, void *unused)
 /*                 JP2OpenJPEGDataset_InfoCallback()                    */
 /************************************************************************/
 
-static void JP2OpenJPEGDataset_InfoCallback(const char *pszMsg, void *unused)
+static void JP2OpenJPEGDataset_InfoCallback(const char *pszMsg, CPL_UNUSED void *unused)
 {
     char* pszMsgTmp = CPLStrdup(pszMsg);
     int nLen = (int)strlen(pszMsgTmp);
@@ -88,6 +90,12 @@ static void JP2OpenJPEGDataset_InfoCallback(const char *pszMsg, void *unused)
     CPLFree(pszMsgTmp);
 }
 
+typedef struct
+{
+    VSILFILE*    fp;
+    vsi_l_offset nBaseOffset;
+} JP2OpenJPEGFile;
+
 /************************************************************************/
 /*                      JP2OpenJPEGDataset_Read()                       */
 /************************************************************************/
@@ -95,12 +103,14 @@ static void JP2OpenJPEGDataset_InfoCallback(const char *pszMsg, void *unused)
 static OPJ_SIZE_T JP2OpenJPEGDataset_Read(void* pBuffer, OPJ_SIZE_T nBytes,
                                        void *pUserData)
 {
-    int nRet = VSIFReadL(pBuffer, 1, nBytes, (VSILFILE*)pUserData);
+    JP2OpenJPEGFile* psJP2OpenJPEGFile = (JP2OpenJPEGFile* )pUserData;
+    int nRet = VSIFReadL(pBuffer, 1, nBytes, psJP2OpenJPEGFile->fp);
 #ifdef DEBUG_IO
     CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Read(%d) = %d", (int)nBytes, nRet);
 #endif
     if (nRet == 0)
         nRet = -1;
+
     return nRet;
 }
 
@@ -111,7 +121,8 @@ static OPJ_SIZE_T JP2OpenJPEGDataset_Read(void* pBuffer, OPJ_SIZE_T nBytes,
 static OPJ_SIZE_T JP2OpenJPEGDataset_Write(void* pBuffer, OPJ_SIZE_T nBytes,
                                        void *pUserData)
 {
-    int nRet = VSIFWriteL(pBuffer, 1, nBytes, (VSILFILE*)pUserData);
+    JP2OpenJPEGFile* psJP2OpenJPEGFile = (JP2OpenJPEGFile* )pUserData;
+    int nRet = VSIFWriteL(pBuffer, 1, nBytes, psJP2OpenJPEGFile->fp);
 #ifdef DEBUG_IO
     CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Write(%d) = %d", (int)nBytes, nRet);
 #endif
@@ -124,10 +135,12 @@ static OPJ_SIZE_T JP2OpenJPEGDataset_Write(void* pBuffer, OPJ_SIZE_T nBytes,
 
 static OPJ_BOOL JP2OpenJPEGDataset_Seek(OPJ_OFF_T nBytes, void * pUserData)
 {
+    JP2OpenJPEGFile* psJP2OpenJPEGFile = (JP2OpenJPEGFile* )pUserData;
 #ifdef DEBUG_IO
     CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Seek(%d)", (int)nBytes);
 #endif
-    return VSIFSeekL((VSILFILE*)pUserData, nBytes, SEEK_SET) == 0;
+    return VSIFSeekL(psJP2OpenJPEGFile->fp, psJP2OpenJPEGFile->nBaseOffset +nBytes,
+                     SEEK_SET) == 0;
 }
 
 /************************************************************************/
@@ -136,13 +149,14 @@ static OPJ_BOOL JP2OpenJPEGDataset_Seek(OPJ_OFF_T nBytes, void * pUserData)
 
 static OPJ_OFF_T JP2OpenJPEGDataset_Skip(OPJ_OFF_T nBytes, void * pUserData)
 {
-    vsi_l_offset nOffset = VSIFTellL((VSILFILE*)pUserData);
+    JP2OpenJPEGFile* psJP2OpenJPEGFile = (JP2OpenJPEGFile* )pUserData;
+    vsi_l_offset nOffset = VSIFTellL(psJP2OpenJPEGFile->fp);
     nOffset += nBytes;
 #ifdef DEBUG_IO
     CPLDebug("OPENJPEG", "JP2OpenJPEGDataset_Skip(%d -> " CPL_FRMT_GUIB ")",
              (int)nBytes, (GUIntBig)nOffset);
 #endif
-    VSIFSeekL((VSILFILE*)pUserData, nOffset, SEEK_SET);
+    VSIFSeekL(psJP2OpenJPEGFile->fp, nOffset, SEEK_SET);
     return nBytes;
 }
 
@@ -159,9 +173,14 @@ class JP2OpenJPEGDataset : public GDALJP2AbstractDataset
     friend class JP2OpenJPEGRasterBand;
 
     VSILFILE   *fp; /* Large FILE API */
+    vsi_l_offset nCodeStreamStart;
+    vsi_l_offset nCodeStreamLength;
 
-    OPJ_CODEC_FORMAT eCodecFormat;
     OPJ_COLOR_SPACE eColorSpace;
+    int         nRedIndex;
+    int         nGreenIndex;
+    int         nBlueIndex;
+    int         nAlphaIndex;
 
     int         bIs420;
 
@@ -173,6 +192,8 @@ class JP2OpenJPEGDataset : public GDALJP2AbstractDataset
     int         nThreads;
     int         GetNumThreads();
     int         bEnoughMemoryToLoadOtherBands;
+    int         bRewrite;
+    int         bHasGeoreferencingAtOpening;
 
   protected:
     virtual int         CloseDependentDatasets();
@@ -189,14 +210,34 @@ class JP2OpenJPEGDataset : public GDALJP2AbstractDataset
                                            GDALProgressFunc pfnProgress,
                                            void * pProgressData );
 
+    virtual CPLErr SetProjection( const char * );
+    virtual CPLErr SetGeoTransform( double* );
+    virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
+                            const char *pszGCPProjection );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                             const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                 const char * pszValue,
+                                 const char * pszDomain = "" );
+
     virtual CPLErr  IRasterIO( GDALRWFlag eRWFlag,
                                int nXOff, int nYOff, int nXSize, int nYSize,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace);
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
 
     static void         WriteBox(VSILFILE* fp, GDALJP2Box* poBox);
+    static void         WriteGDALMetadataBox( VSILFILE* fp, GDALDataset* poSrcDS,
+                                       char** papszOptions );
+    static void         WriteXMLBoxes( VSILFILE* fp, GDALDataset* poSrcDS,
+                                       char** papszOptions );
+    static void         WriteXMPBox( VSILFILE* fp, GDALDataset* poSrcDS,
+                                     char** papszOptions );
+    static void         WriteIPRBox( VSILFILE* fp, GDALDataset* poSrcDS,
+                                     char** papszOptions );
 
     CPLErr      ReadBlock( int nBand, VSILFILE* fp,
                            int nBlockXOff, int nBlockYOff, void * pImage,
@@ -216,7 +257,8 @@ class JP2OpenJPEGDataset : public GDALJP2AbstractDataset
 class JP2OpenJPEGRasterBand : public GDALPamRasterBand
 {
     friend class JP2OpenJPEGDataset;
-    int bPromoteTo8Bit;
+    int             bPromoteTo8Bit;
+    GDALColorTable* poCT;
 
   public:
 
@@ -231,14 +273,16 @@ class JP2OpenJPEGRasterBand : public GDALPamRasterBand
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace );
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg);
 
     virtual GDALColorInterp GetColorInterpretation();
+    virtual GDALColorTable* GetColorTable() { return poCT; }
 
     virtual int             GetOverviewCount();
     virtual GDALRasterBand* GetOverview(int iOvrLevel);
     
-    virtual int HasArbitraryOverviews() { return TRUE; }
+    virtual int HasArbitraryOverviews() { return poCT == NULL; }
 };
 
 
@@ -252,17 +296,20 @@ JP2OpenJPEGRasterBand::JP2OpenJPEGRasterBand( JP2OpenJPEGDataset *poDS, int nBan
                                               int nBlockXSize, int nBlockYSize )
 
 {
-    this->poDS = poDS;
-    this->nBand = nBand;
     this->eDataType = eDataType;
     this->nBlockXSize = nBlockXSize;
     this->nBlockYSize = nBlockYSize;
     this->bPromoteTo8Bit = bPromoteTo8Bit;
+    poCT = NULL;
 
     if( (nBits % 8) != 0 )
-        SetMetadataItem("NBITS",
+        GDALRasterBand::SetMetadataItem("NBITS",
                         CPLString().Printf("%d",nBits),
                         "IMAGE_STRUCTURE" );
+    GDALRasterBand::SetMetadataItem("COMPRESSION", "JPEG2000",
+                    "IMAGE_STRUCTURE" );
+    this->poDS = poDS;
+    this->nBand = nBand;
 }
 
 /************************************************************************/
@@ -271,6 +318,7 @@ JP2OpenJPEGRasterBand::JP2OpenJPEGRasterBand( JP2OpenJPEGDataset *poDS, int nBan
 
 JP2OpenJPEGRasterBand::~JP2OpenJPEGRasterBand()
 {
+    delete poCT;
 }
 
 /************************************************************************/
@@ -311,7 +359,8 @@ CPLErr JP2OpenJPEGRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                          int nXOff, int nYOff, int nXSize, int nYSize,
                                          void * pData, int nBufXSize, int nBufYSize,
                                          GDALDataType eBufType,
-                                         int nPixelSpace, int nLineSpace )
+                                         GSpacing nPixelSpace, GSpacing nLineSpace,
+                                         GDALRasterIOExtraArg* psExtraArg )
 {
     JP2OpenJPEGDataset *poGDS = (JP2OpenJPEGDataset *) poDS;
 
@@ -326,10 +375,13 @@ CPLErr JP2OpenJPEGRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         && GetOverviewCount() > 0 && eRWFlag == GF_Read )
     {
         int         nOverview;
+        GDALRasterIOExtraArg sExtraArg;
+    
+        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
 
         nOverview =
-            GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
-                                        nBufXSize, nBufYSize);
+            GDALBandGetBestOverviewLevel2(this, nXOff, nYOff, nXSize, nYSize,
+                                        nBufXSize, nBufYSize, &sExtraArg);
         if (nOverview >= 0)
         {
             GDALRasterBand* poOverviewBand = GetOverview(nOverview);
@@ -338,7 +390,7 @@ CPLErr JP2OpenJPEGRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
             return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                             pData, nBufXSize, nBufYSize, eBufType,
-                                            nPixelSpace, nLineSpace );
+                                            nPixelSpace, nLineSpace, &sExtraArg );
         }
     }
 
@@ -346,7 +398,7 @@ CPLErr JP2OpenJPEGRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
     CPLErr eErr = GDALPamRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                          pData, nBufXSize, nBufYSize, eBufType,
-                                         nPixelSpace, nLineSpace );
+                                         nPixelSpace, nLineSpace, psExtraArg );
 
     poGDS->bEnoughMemoryToLoadOtherBands = TRUE;
     return eErr;
@@ -472,7 +524,7 @@ int JP2OpenJPEGDataset::PreloadBlocks(JP2OpenJPEGRasterBand* poBand,
         if( nBlocksToLoad > 1 )
         {
             int nThreads = MIN(nBlocksToLoad, nMaxThreads);
-            void** pahThreads = (void**) CPLMalloc( sizeof(void*) * nThreads );
+            CPLJoinableThread** pahThreads = (CPLJoinableThread**) CPLMalloc( sizeof(CPLJoinableThread*) * nThreads );
             int i;
 
             CPLDebug("OPENJPEG", "%d blocks to load", nBlocksToLoad);
@@ -502,6 +554,12 @@ int JP2OpenJPEGDataset::PreloadBlocks(JP2OpenJPEGRasterBand* poBand,
                 }
             }
 
+            /* Flushes all dirty blocks from cache to disk to avoid them */
+            /* to be flushed randomly, and simultaneously, from our worker threads, */
+            /* which might cause races in the output driver. */
+            /* This is a workaround to a design defect of the block cache */
+            GDALRasterBlock::FlushDirtyBlocks();
+
             for(i=0;i<nThreads;i++)
                 pahThreads[i] = CPLCreateJoinableThread(JP2OpenJPEGReadBlockInThread, &oJob);
             for(i=0;i<nThreads;i++)
@@ -522,7 +580,9 @@ CPLErr  JP2OpenJPEGDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
 {
     if( eRWFlag != GF_Read )
         return CE_Failure;
@@ -541,16 +601,20 @@ CPLErr  JP2OpenJPEGDataset::IRasterIO( GDALRWFlag eRWFlag,
         && poBand->GetOverviewCount() > 0 && eRWFlag == GF_Read )
     {
         int         nOverview;
+        GDALRasterIOExtraArg sExtraArg;
+    
+        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
 
         nOverview =
-            GDALBandGetBestOverviewLevel(poBand, nXOff, nYOff, nXSize, nYSize,
-                                        nBufXSize, nBufYSize);
+            GDALBandGetBestOverviewLevel2(poBand, nXOff, nYOff, nXSize, nYSize,
+                                          nBufXSize, nBufYSize, &sExtraArg);
         if (nOverview >= 0)
         {
             return papoOverviewDS[nOverview]->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                                         pData, nBufXSize, nBufYSize, eBufType,
                                                         nBandCount, panBandMap,
-                                                        nPixelSpace, nLineSpace, nBandSpace );
+                                                        nPixelSpace, nLineSpace, nBandSpace,
+                                                        &sExtraArg);
         }
     }
 
@@ -561,13 +625,38 @@ CPLErr  JP2OpenJPEGDataset::IRasterIO( GDALRWFlag eRWFlag,
                                         pData, nBufXSize, nBufYSize,
                                         eBufType, 
                                         nBandCount, panBandMap,
-                                        nPixelSpace, nLineSpace, nBandSpace );
+                                        nPixelSpace, nLineSpace, nBandSpace,
+                                        psExtraArg );
 
     bEnoughMemoryToLoadOtherBands = TRUE;
     return eErr;
 }
 
 /************************************************************************/
+/*                    JP2OpenJPEGCreateReadStream()                     */
+/************************************************************************/
+
+static opj_stream_t* JP2OpenJPEGCreateReadStream(JP2OpenJPEGFile* psJP2OpenJPEGFile,
+                                                 vsi_l_offset nSize)
+{
+    opj_stream_t *pStream = opj_stream_create(1024, TRUE); // Default 1MB is way too big for some datasets
+
+    VSIFSeekL(psJP2OpenJPEGFile->fp, psJP2OpenJPEGFile->nBaseOffset, SEEK_SET);
+    opj_stream_set_user_data_length(pStream, nSize);
+
+    opj_stream_set_read_function(pStream, JP2OpenJPEGDataset_Read);
+    opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
+    opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
+#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
+    opj_stream_set_user_data(pStream, psJP2OpenJPEGFile, NULL);
+#else
+    opj_stream_set_user_data(pStream, psJP2OpenJPEGFile);
+#endif
+
+    return pStream;
+}
+
+/************************************************************************/
 /*                             ReadBlock()                              */
 /************************************************************************/
 
@@ -591,7 +680,7 @@ CPLErr JP2OpenJPEGDataset::ReadBlock( int nBand, VSILFILE* fp,
     int nWidthToRead = MIN(nBlockXSize, nRasterXSize - nBlockXOff * nBlockXSize);
     int nHeightToRead = MIN(nBlockYSize, nRasterYSize - nBlockYOff * nBlockYSize);
 
-    pCodec = opj_create_decompress(eCodecFormat);
+    pCodec = opj_create_decompress(OPJ_CODEC_J2K);
 
     opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
     opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback, NULL);
@@ -606,21 +695,10 @@ CPLErr JP2OpenJPEGDataset::ReadBlock( int nBand, VSILFILE* fp,
         return CE_Failure;
     }
 
-    pStream = opj_stream_create(1024, TRUE); // Default 1MB is way too big for some datasets
-
-    VSIFSeekL(fp, 0, SEEK_END);
-    opj_stream_set_user_data_length(pStream, VSIFTellL(fp));
-    /* Reseek to file beginning */
-    VSIFSeekL(fp, 0, SEEK_SET);
-
-    opj_stream_set_read_function(pStream, JP2OpenJPEGDataset_Read);
-    opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
-    opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
-#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
-    opj_stream_set_user_data(pStream, fp, NULL);
-#else
-    opj_stream_set_user_data(pStream, fp);
-#endif
+    JP2OpenJPEGFile sJP2OpenJPEGFile;
+    sJP2OpenJPEGFile.fp = fp;
+    sJP2OpenJPEGFile.nBaseOffset = nCodeStreamStart;
+    pStream = JP2OpenJPEGCreateReadStream(&sJP2OpenJPEGFile, nCodeStreamLength);
 
     if(!opj_read_header(pStream,pCodec,&psImage))
     {
@@ -706,10 +784,16 @@ CPLErr JP2OpenJPEGDataset::ReadBlock( int nBand, VSILFILE* fp,
             CPLAssert(psImage->comps[1].h == (psImage->comps[0].h + 1) / 2);
             CPLAssert(psImage->comps[2].w == (psImage->comps[0].w + 1) / 2);
             CPLAssert(psImage->comps[2].h == (psImage->comps[0].h + 1) / 2);
+            if( nBands == 4 )
+            {
+                CPLAssert((int)psImage->comps[3].w >= nWidthToRead);
+                CPLAssert((int)psImage->comps[3].h >= nHeightToRead);
+            }
 
             OPJ_INT32* pSrcY = psImage->comps[0].data;
             OPJ_INT32* pSrcCb = psImage->comps[1].data;
             OPJ_INT32* pSrcCr = psImage->comps[2].data;
+            OPJ_INT32* pSrcA = (nBands == 4) ? psImage->comps[3].data : NULL;
             GByte* pDst = (GByte*)pDstBuffer;
             for(int j=0;j<nHeightToRead;j++)
             {
@@ -722,8 +806,21 @@ CPLErr JP2OpenJPEGDataset::ReadBlock( int nBand, VSILFILE* fp,
                         pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y + 1.402 * (Cr - 128)));
                     else if (iBand == 2)
                         pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)));
-                    else
+                    else if (iBand == 3)
                         pDst[j * nBlockXSize + i] = CLAMP_0_255((int)(Y + 1.772 * (Cb - 128)));
+                    else if (iBand == 4)
+                        pDst[j * nBlockXSize + i] = pSrcA[j * psImage->comps[0].w + i];
+                }
+            }
+            
+            if( bPromoteTo8Bit )
+            {
+                for(int j=0;j<nHeightToRead;j++)
+                {
+                    for(int i=0;i<nWidthToRead;i++)
+                    {
+                        pDst[j * nBlockXSize + i] *= 255;
+                    }
                 }
             }
         }
@@ -805,23 +902,23 @@ GDALColorInterp JP2OpenJPEGRasterBand::GetColorInterpretation()
 {
     JP2OpenJPEGDataset *poGDS = (JP2OpenJPEGDataset *) poDS;
 
-    if (poGDS->eColorSpace == OPJ_CLRSPC_GRAY)
+    if( poCT )
+        return GCI_PaletteIndex;
+
+    if( nBand == poGDS->nAlphaIndex + 1 )
+        return GCI_AlphaBand;
+
+    if (poGDS->nBands <= 2 && poGDS->eColorSpace == OPJ_CLRSPC_GRAY)
         return GCI_GrayIndex;
-    else if (poGDS->nBands == 3 || poGDS->nBands == 4)
+    else if (poGDS->eColorSpace == OPJ_CLRSPC_SRGB ||
+             poGDS->eColorSpace == OPJ_CLRSPC_SYCC)
     {
-        switch(nBand)
-        {
-            case 1:
-                return GCI_RedBand;
-            case 2:
-                return GCI_GreenBand;
-            case 3:
-                return GCI_BlueBand;
-            case 4:
-                return GCI_AlphaBand;
-            default:
-                return GCI_Undefined;
-        }
+        if( nBand == poGDS->nRedIndex + 1 )
+            return GCI_RedBand;
+        if( nBand == poGDS->nGreenIndex + 1 )
+            return GCI_GreenBand;
+        if( nBand == poGDS->nBlueIndex + 1 )
+            return GCI_BlueBand;
     }
 
     return GCI_Undefined;
@@ -840,9 +937,14 @@ GDALColorInterp JP2OpenJPEGRasterBand::GetColorInterpretation()
 JP2OpenJPEGDataset::JP2OpenJPEGDataset()
 {
     fp = NULL;
+    nCodeStreamStart = 0;
+    nCodeStreamLength = 0;
     nBands = 0;
-    eCodecFormat = OPJ_CODEC_UNKNOWN;
     eColorSpace = OPJ_CLRSPC_UNKNOWN;
+    nRedIndex = 0;
+    nGreenIndex = 1;
+    nBlueIndex = 2;
+    nAlphaIndex = -1;
     bIs420 = FALSE;
     iLevel = 0;
     nOverviewCount = 0;
@@ -850,6 +952,8 @@ JP2OpenJPEGDataset::JP2OpenJPEGDataset()
     bUseSetDecodeArea = FALSE;
     nThreads = -1;
     bEnoughMemoryToLoadOtherBands = TRUE;
+    bRewrite = FALSE;
+    bHasGeoreferencingAtOpening = FALSE;
 }
 
 /************************************************************************/
@@ -861,8 +965,233 @@ JP2OpenJPEGDataset::~JP2OpenJPEGDataset()
 {
     FlushCache();
 
-    if( fp != NULL )
-        VSIFCloseL( fp );
+    if( iLevel == 0 && fp != NULL )
+    {
+        if( bRewrite )
+        {
+            GDALJP2Box oBox( fp );
+            vsi_l_offset nOffsetJP2C = 0, nLengthJP2C = 0,
+                         nOffsetXML = 0, nOffsetASOC = 0, nOffsetUUID = 0,
+                         nOffsetIHDR = 0, nLengthIHDR = 0;
+            int bMSIBox = FALSE, bGMLData = FALSE;
+            int bUnsupportedConfiguration = FALSE;
+            if( oBox.ReadFirst() )
+            {
+                while( strlen(oBox.GetType()) > 0 )
+                {
+                    if( EQUAL(oBox.GetType(),"jp2c") )
+                    {
+                        if( nOffsetJP2C == 0 )
+                        {
+                            nOffsetJP2C = VSIFTellL(fp);
+                            nLengthJP2C = oBox.GetDataLength();
+                        }
+                        else
+                            bUnsupportedConfiguration = TRUE;
+                    }
+                    else if( EQUAL(oBox.GetType(),"jp2h") )
+                    {
+                        GDALJP2Box oSubBox( fp );
+                        if( oSubBox.ReadFirstChild( &oBox ) &&
+                            EQUAL(oSubBox.GetType(),"ihdr") )
+                        {
+                            nOffsetIHDR = VSIFTellL(fp);
+                            nLengthIHDR = oSubBox.GetDataLength();
+                        }
+                    }
+                    else if( EQUAL(oBox.GetType(),"xml ") )
+                    {
+                        if( nOffsetXML == 0 )
+                            nOffsetXML = VSIFTellL(fp);
+                    }
+                    else if( EQUAL(oBox.GetType(),"asoc") )
+                    {
+                        if( nOffsetASOC == 0 )
+                            nOffsetASOC = VSIFTellL(fp);
+
+                        GDALJP2Box oSubBox( fp );
+                        if( oSubBox.ReadFirstChild( &oBox ) &&
+                            EQUAL(oSubBox.GetType(),"lbl ") )
+                        {
+                            char *pszLabel = (char *) oSubBox.ReadBoxData();
+                            if( pszLabel != NULL && EQUAL(pszLabel,"gml.data") )
+                            {
+                                bGMLData = TRUE;
+                            }
+                            else
+                                bUnsupportedConfiguration = TRUE;
+                            CPLFree( pszLabel );
+                        }
+                        else
+                            bUnsupportedConfiguration = TRUE;
+                    }
+                    else if( EQUAL(oBox.GetType(),"uuid") )
+                    {
+                        if( nOffsetUUID == 0 )
+                            nOffsetUUID = VSIFTellL(fp);
+                        if( GDALJP2Metadata::IsUUID_MSI(oBox.GetUUID()) )
+                            bMSIBox = TRUE;
+                        else if( !GDALJP2Metadata::IsUUID_XMP(oBox.GetUUID()) )
+                            bUnsupportedConfiguration = TRUE;
+                    }
+                    else if( !EQUAL(oBox.GetType(),"jP  ") &&
+                             !EQUAL(oBox.GetType(),"ftyp") &&
+                             !EQUAL(oBox.GetType(),"rreq") &&
+                             !EQUAL(oBox.GetType(),"jp2h") &&
+                             !EQUAL(oBox.GetType(),"jp2i") )
+                    {
+                        bUnsupportedConfiguration = TRUE;
+                    }
+
+                    if (bUnsupportedConfiguration || !oBox.ReadNext())
+                        break;
+                }
+            }
+
+            const char* pszGMLJP2;
+            int bGeoreferencingCompatOfGMLJP2 =
+                       ((pszProjection != NULL && pszProjection[0] != '\0' ) &&
+                        bGeoTransformValid && nGCPCount == 0);
+            if( bGeoreferencingCompatOfGMLJP2 &&
+                ((bHasGeoreferencingAtOpening && bGMLData) ||
+                 (!bHasGeoreferencingAtOpening)) )
+                pszGMLJP2 = "GMLJP2=YES";
+            else
+                pszGMLJP2 = "GMLJP2=NO";
+
+            const char* pszGeoJP2;
+            int bGeoreferencingCompatOfGeoJP2 = 
+                    ((pszProjection != NULL && pszProjection[0] != '\0' ) ||
+                    nGCPCount != 0 || bGeoTransformValid);
+            if( bGeoreferencingCompatOfGeoJP2 &&
+                ((bHasGeoreferencingAtOpening && bMSIBox) ||
+                 (!bHasGeoreferencingAtOpening) || nGCPCount > 0) )
+                pszGeoJP2 = "GeoJP2=YES";
+            else
+                pszGeoJP2 = "GeoJP2=NO";
+
+            /* Test that the length of the JP2C box is not 0 */
+            int bJP2CBoxOKForRewriteInPlace = TRUE;
+            if( nOffsetJP2C > 16 && !bUnsupportedConfiguration )
+            {
+                VSIFSeekL(fp, nOffsetJP2C - 8, SEEK_SET);
+                GByte abyBuffer[8];
+                VSIFReadL(abyBuffer, 1, 8, fp);
+                if( EQUALN((const char*)abyBuffer + 4, "jp2c", 4) &&
+                    abyBuffer[0] == 0 && abyBuffer[1] == 0 &&
+                    abyBuffer[2] == 0 && abyBuffer[3] == 0 )
+                {
+                    if( (vsi_l_offset)(GUInt32)(nLengthJP2C + 8) == (nLengthJP2C + 8) )
+                    {
+                        CPLDebug("OPENJPEG", "Patching length of JP2C box with real length");
+                        VSIFSeekL(fp, nOffsetJP2C - 8, SEEK_SET);
+                        GUInt32 nLength = (GUInt32)nLengthJP2C + 8;
+                        CPL_MSBPTR32(&nLength);
+                        VSIFWriteL(&nLength, 1, 4, fp);
+                    }
+                    else
+                        bJP2CBoxOKForRewriteInPlace = FALSE;
+                }
+            }
+
+            if( nOffsetJP2C == 0 || bUnsupportedConfiguration )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                         "Cannot rewrite file due to unsupported JP2 box configuration");
+                VSIFCloseL( fp );
+            }
+            else if( bJP2CBoxOKForRewriteInPlace &&
+                     (nOffsetXML == 0 || nOffsetXML > nOffsetJP2C) &&
+                     (nOffsetASOC == 0 || nOffsetASOC > nOffsetJP2C) &&
+                     (nOffsetUUID == 0 || nOffsetUUID > nOffsetJP2C) )
+            {
+                CPLDebug("OPENJPEG", "Rewriting boxes after codestream");
+
+                /* Update IPR flag */
+                if( nLengthIHDR == 14 )
+                {
+                    VSIFSeekL( fp, nOffsetIHDR + nLengthIHDR - 1, SEEK_SET );
+                    GByte bIPR = GetMetadata("xml:IPR") != NULL;
+                    VSIFWriteL( &bIPR, 1, 1, fp );
+                }
+
+                VSIFSeekL( fp, nOffsetJP2C + nLengthJP2C, SEEK_SET );
+
+                GDALJP2Metadata oJP2MD;
+                if( GetGCPCount() > 0 )
+                {
+                    oJP2MD.SetGCPs( GetGCPCount(),
+                                    GetGCPs() );
+                    oJP2MD.SetProjection( GetGCPProjection() );
+                }
+                else
+                {
+                    const char* pszWKT = GetProjectionRef();
+                    if( pszWKT != NULL && pszWKT[0] != '\0' )
+                    {
+                        oJP2MD.SetProjection( pszWKT );
+                    }
+                    if( bGeoTransformValid )
+                    {
+                        oJP2MD.SetGeoTransform( adfGeoTransform );
+                    }
+                }
+
+                const char* pszAreaOrPoint = GetMetadataItem(GDALMD_AREA_OR_POINT);
+                oJP2MD.bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
+
+                WriteIPRBox(fp, this, NULL);
+
+                if( bGeoreferencingCompatOfGMLJP2 && EQUAL(pszGMLJP2, "GMLJP2=YES") )
+                {
+                    GDALJP2Box* poBox = oJP2MD.CreateGMLJP2(nRasterXSize,nRasterYSize);
+                    WriteBox(fp, poBox);
+                    delete poBox;
+                }
+
+                WriteXMLBoxes(fp, this, NULL);
+                WriteGDALMetadataBox(fp, this, NULL);
+
+                if( bGeoreferencingCompatOfGeoJP2 && EQUAL(pszGeoJP2, "GeoJP2=YES") )
+                {
+                    GDALJP2Box* poBox = oJP2MD.CreateJP2GeoTIFF();
+                    WriteBox(fp, poBox);
+                    delete poBox;
+                }
+
+                WriteXMPBox(fp, this, NULL);
+                
+                VSIFTruncateL( fp, VSIFTellL(fp) );
+
+                VSIFCloseL( fp );
+            }
+            else
+            {
+                VSIFCloseL( fp );
+                
+                CPLDebug("OPENJPEG", "Rewriting whole file");
+
+                const char* apszOptions[] = {
+                    "USE_SRC_CODESTREAM=YES", "CODEC=JP2", "WRITE_METADATA=YES",
+                    NULL, NULL, NULL };
+                apszOptions[3] = pszGMLJP2;
+                apszOptions[4] = pszGeoJP2;
+                CPLString osTmpFilename(CPLSPrintf("%s.tmp", GetDescription()));
+                GDALDataset* poOutDS = CreateCopy( osTmpFilename, this, FALSE,
+                                                (char**)apszOptions, GDALDummyProgress, NULL );
+                if( poOutDS )
+                {
+                    GDALClose(poOutDS);
+                    VSIRename(osTmpFilename, GetDescription());
+                }
+                else
+                    VSIUnlink(osTmpFilename);
+                VSIUnlink(CPLSPrintf("%s.tmp.aux.xml", GetDescription()));
+            }
+        }
+        else
+            VSIFCloseL( fp );
+    }
 
     CloseDependentDatasets();
 }
@@ -873,7 +1202,7 @@ JP2OpenJPEGDataset::~JP2OpenJPEGDataset()
 
 int JP2OpenJPEGDataset::CloseDependentDatasets()
 {
-    int bRet = GDALPamDataset::CloseDependentDatasets();
+    int bRet = GDALJP2AbstractDataset::CloseDependentDatasets();
     if ( papoOverviewDS )
     {
         for( int i = 0; i < nOverviewCount; i++ )
@@ -886,15 +1215,111 @@ int JP2OpenJPEGDataset::CloseDependentDatasets()
 }
 
 /************************************************************************/
+/*                           SetProjection()                            */
+/************************************************************************/
+
+CPLErr JP2OpenJPEGDataset::SetProjection( const char * pszProjectionIn )
+{
+    if( eAccess == GA_Update )
+    {
+        bRewrite = TRUE;
+        CPLFree(pszProjection);
+        pszProjection = (pszProjectionIn) ? CPLStrdup(pszProjectionIn) : CPLStrdup("");
+        return CE_None;
+    }
+    else
+        return GDALJP2AbstractDataset::SetProjection(pszProjectionIn);
+}
+
+/************************************************************************/
+/*                           SetGeoTransform()                          */
+/************************************************************************/
+
+CPLErr JP2OpenJPEGDataset::SetGeoTransform( double *padfGeoTransform )
+{
+    if( eAccess == GA_Update )
+    {
+        bRewrite = TRUE;
+        memcpy(adfGeoTransform, padfGeoTransform, 6* sizeof(double));
+        bGeoTransformValid = !(
+            adfGeoTransform[0] == 0.0 && adfGeoTransform[1] == 1.0 &&
+            adfGeoTransform[2] == 0.0 && adfGeoTransform[3] == 0.0 &&
+            adfGeoTransform[4] == 0.0 && adfGeoTransform[5] == 1.0);
+        return CE_None;
+    }
+    else
+        return GDALJP2AbstractDataset::SetGeoTransform(padfGeoTransform);
+}
+
+/************************************************************************/
+/*                           SetGCPs()                                  */
+/************************************************************************/
+
+CPLErr JP2OpenJPEGDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
+                                    const char *pszGCPProjectionIn )
+{
+    if( eAccess == GA_Update )
+    {
+        bRewrite = TRUE;
+        CPLFree( pszProjection );
+        if( nGCPCount > 0 )
+        {
+            GDALDeinitGCPs( nGCPCount, pasGCPList );
+            CPLFree( pasGCPList );
+        }
+
+        pszProjection = (pszGCPProjectionIn) ? CPLStrdup(pszGCPProjectionIn) : CPLStrdup("");
+        nGCPCount = nGCPCountIn;
+        pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPListIn );
+
+        return CE_None;
+    }
+    else
+        return GDALJP2AbstractDataset::SetGCPs(nGCPCountIn, pasGCPListIn,
+                                               pszGCPProjectionIn);
+}
+
+/************************************************************************/
+/*                            SetMetadata()                             */
+/************************************************************************/
+
+CPLErr JP2OpenJPEGDataset::SetMetadata( char ** papszMetadata,
+                                        const char * pszDomain )
+{
+    if( eAccess == GA_Update )
+    {
+        bRewrite = TRUE;
+        return GDALDataset::SetMetadata(papszMetadata, pszDomain);
+    }
+    return GDALJP2AbstractDataset::SetMetadata(papszMetadata, pszDomain);
+}
+
+/************************************************************************/
+/*                            SetMetadata()                             */
+/************************************************************************/
+
+CPLErr JP2OpenJPEGDataset::SetMetadataItem( const char * pszName,
+                                            const char * pszValue,
+                                            const char * pszDomain )
+{
+    if( eAccess == GA_Update )
+    {
+        bRewrite = TRUE;
+        return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
+    }
+    return GDALJP2AbstractDataset::SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+/************************************************************************/
 /*                            Identify()                                */
 /************************************************************************/
 
+static const unsigned char jpc_header[] = {0xff,0x4f};
+static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP  ' */
+
 int JP2OpenJPEGDataset::Identify( GDALOpenInfo * poOpenInfo )
 
 {
-    static const unsigned char jpc_header[] = {0xff,0x4f};
-    static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP  ' */
-        
     if( poOpenInfo->nHeaderBytes >= 16 
         && (memcmp( poOpenInfo->pabyHeader, jpc_header, 
                     sizeof(jpc_header) ) == 0
@@ -906,6 +1331,50 @@ int JP2OpenJPEGDataset::Identify( GDALOpenInfo * poOpenInfo )
     else
         return FALSE;
 }
+
+/************************************************************************/
+/*                        JP2OpenJPEGFindCodeStream()                   */
+/************************************************************************/
+
+static vsi_l_offset JP2OpenJPEGFindCodeStream( VSILFILE* fp,
+                                               vsi_l_offset* pnLength )
+{
+    vsi_l_offset nCodeStreamStart = 0;
+    vsi_l_offset nCodeStreamLength = 0;
+
+    VSIFSeekL(fp, 0, SEEK_SET);
+    GByte abyHeader[16];
+    VSIFReadL(abyHeader, 1, 16, fp);
+
+    if (memcmp( abyHeader, jpc_header, sizeof(jpc_header) ) == 0)
+    {
+        VSIFSeekL(fp, 0, SEEK_END);
+        nCodeStreamLength = VSIFTellL(fp);
+    }
+    else if (memcmp( abyHeader + 4, jp2_box_jp, sizeof(jp2_box_jp) ) == 0)
+    {
+        /* Find offset of first jp2c box */
+        GDALJP2Box oBox( fp );
+        if( oBox.ReadFirst() )
+        {
+            while( strlen(oBox.GetType()) > 0 )
+            {
+                if( EQUAL(oBox.GetType(),"jp2c") )
+                {
+                    nCodeStreamStart = VSIFTellL(fp);
+                    nCodeStreamLength = oBox.GetDataLength();
+                    break;
+                }
+
+                if (!oBox.ReadNext())
+                    break;
+            }
+        }
+    }
+    *pnLength = nCodeStreamLength;
+    return nCodeStreamStart;
+}
+
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
@@ -913,26 +1382,26 @@ int JP2OpenJPEGDataset::Identify( GDALOpenInfo * poOpenInfo )
 GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if (!Identify(poOpenInfo))
+    if (!Identify(poOpenInfo) || poOpenInfo->fpL == NULL)
         return NULL;
 
-    VSILFILE* fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
-    if (!fp)
+    /* Detect which codec to use : J2K or JP2 ? */
+    vsi_l_offset nCodeStreamLength = 0;
+    vsi_l_offset nCodeStreamStart = JP2OpenJPEGFindCodeStream(poOpenInfo->fpL,
+                                                              &nCodeStreamLength);
+
+    if( nCodeStreamStart == 0 && nCodeStreamLength == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "No code-stream in JP2 file");
         return NULL;
+    }
 
-    OPJ_CODEC_FORMAT eCodecFormat;
+    OPJ_CODEC_FORMAT eCodecFormat = (nCodeStreamStart == 0) ? OPJ_CODEC_J2K : OPJ_CODEC_JP2;
 
-    /* Detect which codec to use : J2K or JP2 ? */
-    static const unsigned char jpc_header[] = {0xff,0x4f};
-    if (memcmp( poOpenInfo->pabyHeader, jpc_header, 
-                    sizeof(jpc_header) ) == 0)
-        eCodecFormat = OPJ_CODEC_J2K;
-    else
-        eCodecFormat = OPJ_CODEC_JP2;
 
     opj_codec_t* pCodec;
 
-    pCodec = opj_create_decompress(eCodecFormat);
+    pCodec = opj_create_decompress(OPJ_CODEC_J2K);
 
     opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
     opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback, NULL);
@@ -943,47 +1412,39 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
 
     if (! opj_setup_decoder(pCodec,&parameters))
     {
-        VSIFCloseL(fp);
         return NULL;
     }
 
-    opj_stream_t * pStream;
-    pStream = opj_stream_create(1024, TRUE); // Default 1MB is way too big for some datasets
-
-    VSIFSeekL(fp, 0, SEEK_END);
-    opj_stream_set_user_data_length(pStream, VSIFTellL(fp));
-    /* Reseek to file beginning */
-    VSIFSeekL(fp, 0, SEEK_SET);
-
-    opj_stream_set_read_function(pStream, JP2OpenJPEGDataset_Read);
-    opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
-    opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
-#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
-    opj_stream_set_user_data(pStream, fp, NULL);
-#else
-    opj_stream_set_user_data(pStream, fp);
-#endif
+    JP2OpenJPEGFile sJP2OpenJPEGFile;
+    sJP2OpenJPEGFile.fp = poOpenInfo->fpL;
+    sJP2OpenJPEGFile.nBaseOffset = nCodeStreamStart;
+    opj_stream_t * pStream = JP2OpenJPEGCreateReadStream(&sJP2OpenJPEGFile,
+                                                         nCodeStreamLength);
 
     opj_image_t * psImage = NULL;
-    OPJ_INT32  nX0,nY0;
-    OPJ_UINT32 nTileW,nTileH,nTilesX,nTilesY;
+
     if(!opj_read_header(pStream,pCodec,&psImage))
     {
         CPLError(CE_Failure, CPLE_AppDefined, "opj_read_header() failed");
         opj_destroy_codec(pCodec);
         opj_stream_destroy(pStream);
         opj_image_destroy(psImage);
-        VSIFCloseL(fp);
         return NULL;
     }
 
     opj_codestream_info_v2_t* pCodeStreamInfo = opj_get_cstr_info(pCodec);
-    nX0 = pCodeStreamInfo->tx0;
-    nY0 = pCodeStreamInfo->ty0;
+    OPJ_UINT32 nTileW,nTileH;
     nTileW = pCodeStreamInfo->tdx;
     nTileH = pCodeStreamInfo->tdy;
+#ifdef DEBUG
+    OPJ_UINT32  nX0,nY0;
+    OPJ_UINT32 nTilesX,nTilesY;
+    nX0 = pCodeStreamInfo->tx0;
+    nY0 = pCodeStreamInfo->ty0;
     nTilesX = pCodeStreamInfo->tw;
     nTilesY = pCodeStreamInfo->th;
+    int mct = pCodeStreamInfo->m_default_tile_info.mct;
+#endif
     int numResolutions = pCodeStreamInfo->m_default_tile_info.tccp_info[0].numresolutions;
     opj_destroy_cstr_info(&pCodeStreamInfo);
 
@@ -992,31 +1453,33 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
         opj_destroy_codec(pCodec);
         opj_stream_destroy(pStream);
         opj_image_destroy(psImage);
-        VSIFCloseL(fp);
         return NULL;
     }
 
 #ifdef DEBUG
     int i;
-    CPLDebug("OPENJPEG", "nX0 = %d", nX0);
-    CPLDebug("OPENJPEG", "nY0 = %d", nY0);
-    CPLDebug("OPENJPEG", "nTileW = %d", nTileW);
-    CPLDebug("OPENJPEG", "nTileH = %d", nTileH);
-    CPLDebug("OPENJPEG", "psImage->x0 = %d", psImage->x0);
-    CPLDebug("OPENJPEG", "psImage->y0 = %d", psImage->y0);
-    CPLDebug("OPENJPEG", "psImage->x1 = %d", psImage->x1);
-    CPLDebug("OPENJPEG", "psImage->y1 = %d", psImage->y1);
+    CPLDebug("OPENJPEG", "nX0 = %u", nX0);
+    CPLDebug("OPENJPEG", "nY0 = %u", nY0);
+    CPLDebug("OPENJPEG", "nTileW = %u", nTileW);
+    CPLDebug("OPENJPEG", "nTileH = %u", nTileH);
+    CPLDebug("OPENJPEG", "nTilesX = %u", nTilesX);
+    CPLDebug("OPENJPEG", "nTilesY = %u", nTilesY);
+    CPLDebug("OPENJPEG", "mct = %d", mct);
+    CPLDebug("OPENJPEG", "psImage->x0 = %u", psImage->x0);
+    CPLDebug("OPENJPEG", "psImage->y0 = %u", psImage->y0);
+    CPLDebug("OPENJPEG", "psImage->x1 = %u", psImage->x1);
+    CPLDebug("OPENJPEG", "psImage->y1 = %u", psImage->y1);
     CPLDebug("OPENJPEG", "psImage->numcomps = %d", psImage->numcomps);
-    CPLDebug("OPENJPEG", "psImage->color_space = %d", psImage->color_space);
+    //CPLDebug("OPENJPEG", "psImage->color_space = %d", psImage->color_space);
     CPLDebug("OPENJPEG", "numResolutions = %d", numResolutions);
     for(i=0;i<(int)psImage->numcomps;i++)
     {
-        CPLDebug("OPENJPEG", "psImage->comps[%d].dx = %d", i, psImage->comps[i].dx);
-        CPLDebug("OPENJPEG", "psImage->comps[%d].dy = %d", i, psImage->comps[i].dy);
-        CPLDebug("OPENJPEG", "psImage->comps[%d].x0 = %d", i, psImage->comps[i].x0);
-        CPLDebug("OPENJPEG", "psImage->comps[%d].y0 = %d", i, psImage->comps[i].y0);
-        CPLDebug("OPENJPEG", "psImage->comps[%d].w = %d", i, psImage->comps[i].w);
-        CPLDebug("OPENJPEG", "psImage->comps[%d].h = %d", i, psImage->comps[i].h);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].dx = %u", i, psImage->comps[i].dx);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].dy = %u", i, psImage->comps[i].dy);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].x0 = %u", i, psImage->comps[i].x0);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].y0 = %u", i, psImage->comps[i].y0);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].w = %u", i, psImage->comps[i].w);
+        CPLDebug("OPENJPEG", "psImage->comps[%d].h = %u", i, psImage->comps[i].h);
         CPLDebug("OPENJPEG", "psImage->comps[%d].resno_decoded = %d", i, psImage->comps[i].resno_decoded);
         CPLDebug("OPENJPEG", "psImage->comps[%d].factor = %d", i, psImage->comps[i].factor);
         CPLDebug("OPENJPEG", "psImage->comps[%d].prec = %d", i, psImage->comps[i].prec);
@@ -1027,6 +1490,10 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
     if (psImage->x1 <= psImage->x0 ||
         psImage->y1 <= psImage->y0 ||
         psImage->numcomps == 0 ||
+        (psImage->comps[0].w >> 31) != 0 ||
+        (psImage->comps[0].h >> 31) != 0 ||
+        (nTileW >> 31) != 0 ||
+        (nTileH >> 31) != 0 ||
         psImage->comps[0].w != psImage->x1 - psImage->x0 ||
         psImage->comps[0].h != psImage->y1 - psImage->y0)
     {
@@ -1034,7 +1501,6 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
         opj_destroy_codec(pCodec);
         opj_stream_destroy(pStream);
         opj_image_destroy(psImage);
-        VSIFCloseL(fp);
         return NULL;
     }
 
@@ -1056,11 +1522,15 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
 
     int bIs420  =  (psImage->color_space != OPJ_CLRSPC_SRGB &&
                     eDataType == GDT_Byte &&
-                    psImage->numcomps == 3 &&
+                    (psImage->numcomps == 3 || psImage->numcomps == 4) &&
                     psImage->comps[1].w == psImage->comps[0].w / 2 &&
                     psImage->comps[1].h == psImage->comps[0].h / 2 &&
                     psImage->comps[2].w == psImage->comps[0].w / 2 &&
-                    psImage->comps[2].h == psImage->comps[0].h / 2);
+                    psImage->comps[2].h == psImage->comps[0].h / 2) &&
+                    (psImage->numcomps == 3 || 
+                     (psImage->numcomps == 4 &&
+                      psImage->comps[3].w == psImage->comps[0].w &&
+                      psImage->comps[3].h == psImage->comps[0].h));
 
     if (bIs420)
     {
@@ -1078,7 +1548,6 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
                 opj_destroy_codec(pCodec);
                 opj_stream_destroy(pStream);
                 opj_image_destroy(psImage);
-                VSIFCloseL(fp);
                 return NULL;
             }
         }
@@ -1092,12 +1561,16 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
     int                 iBand;
 
     poDS = new JP2OpenJPEGDataset();
-    poDS->eCodecFormat = eCodecFormat;
+    if( eCodecFormat == OPJ_CODEC_JP2 )
+        poDS->eAccess = poOpenInfo->eAccess;
     poDS->eColorSpace = psImage->color_space;
     poDS->nRasterXSize = psImage->x1 - psImage->x0;
     poDS->nRasterYSize = psImage->y1 - psImage->y0;
     poDS->nBands = psImage->numcomps;
-    poDS->fp = fp;
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+    poDS->nCodeStreamStart = nCodeStreamStart;
+    poDS->nCodeStreamLength = nCodeStreamLength;
     poDS->bIs420 = bIs420;
 
     poDS->bUseSetDecodeArea = 
@@ -1112,23 +1585,212 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
         if (nTileH > 1024) nTileH = 1024;
     }
 
+    GDALColorTable* poCT = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Look for color table or cdef box                                */
+/* -------------------------------------------------------------------- */
+    if( eCodecFormat == OPJ_CODEC_JP2 )
+    {
+        GDALJP2Box oBox( poDS->fp );
+        if( oBox.ReadFirst() )
+        {
+            while( strlen(oBox.GetType()) > 0 )
+            {
+                if( EQUAL(oBox.GetType(),"jp2h") )
+                {
+                    GDALJP2Box oSubBox( poDS->fp );
+
+                    for( oSubBox.ReadFirstChild( &oBox );
+                         strlen(oSubBox.GetType()) > 0;
+                         oSubBox.ReadNextChild( &oBox ) )
+                    {
+                        GIntBig nDataLength = oSubBox.GetDataLength();
+                        if( poCT == NULL &&
+                            EQUAL(oSubBox.GetType(),"pclr") &&
+                            nDataLength >= 3 &&
+                            nDataLength <= 2 + 1 + 4 + 4 * 256 )
+                        {
+                            GByte* pabyCT = oSubBox.ReadBoxData();
+                            if( pabyCT != NULL )
+                            {
+                                int nEntries = (pabyCT[0] << 8) | pabyCT[1];
+                                int nComponents = pabyCT[2];
+                                /* CPLDebug("OPENJPEG", "Color table found"); */
+                                if( nEntries <= 256 && nComponents == 3 )
+                                {
+                                    /*CPLDebug("OPENJPEG", "resol[0] = %d", pabyCT[3]);
+                                    CPLDebug("OPENJPEG", "resol[1] = %d", pabyCT[4]);
+                                    CPLDebug("OPENJPEG", "resol[2] = %d", pabyCT[5]);*/
+                                    if( pabyCT[3] == 7 && pabyCT[4] == 7 && pabyCT[5] == 7 &&
+                                        nDataLength == 2 + 1 + 3 + 3 * nEntries )
+                                    {
+                                        poCT = new GDALColorTable();
+                                        for(int i=0;i<nEntries;i++)
+                                        {
+                                            GDALColorEntry sEntry;
+                                            sEntry.c1 = pabyCT[6 + 3 * i];
+                                            sEntry.c2 = pabyCT[6 + 3 * i + 1];
+                                            sEntry.c3 = pabyCT[6 + 3 * i + 2];
+                                            sEntry.c4 = 255;
+                                            poCT->SetColorEntry(i, &sEntry);
+                                        }
+                                    }
+                                }
+                                else if ( nEntries <= 256 && nComponents == 4 )
+                                {
+                                    if( pabyCT[3] == 7 && pabyCT[4] == 7 &&
+                                        pabyCT[5] == 7 && pabyCT[6] == 7 &&
+                                        nDataLength == 2 + 1 + 4 + 4 * nEntries )
+                                    {
+                                        poCT = new GDALColorTable();
+                                        for(int i=0;i<nEntries;i++)
+                                        {
+                                            GDALColorEntry sEntry;
+                                            sEntry.c1 = pabyCT[7 + 4 * i];
+                                            sEntry.c2 = pabyCT[7 + 4 * i + 1];
+                                            sEntry.c3 = pabyCT[7 + 4 * i + 2];
+                                            sEntry.c4 = pabyCT[7 + 4 * i + 3];
+                                            poCT->SetColorEntry(i, &sEntry);
+                                        }
+                                    }
+                                }
+                                CPLFree(pabyCT);
+                            }
+                        }
+                        /* There's a bug/misfeature in openjpeg: the color_space
+                           only gets set at read tile time */
+                        else if( EQUAL(oSubBox.GetType(),"colr") &&
+                                 nDataLength == 7 )
+                        {
+                            GByte* pabyContent = oSubBox.ReadBoxData();
+                            if( pabyContent != NULL )
+                            {
+                                if( pabyContent[0] == 1 /* enumerated colourspace */ )
+                                {
+                                    GUInt32 enumcs = (pabyContent[3] << 24) |
+                                                     (pabyContent[4] << 16) |
+                                                     (pabyContent[5] << 8) |
+                                                     (pabyContent[6]);
+                                    if( enumcs == 16 )
+                                    {
+                                        poDS->eColorSpace = OPJ_CLRSPC_SRGB;
+                                        CPLDebug("OPENJPEG", "SRGB color space");
+                                    }
+                                    else if( enumcs == 17 )
+                                    {
+                                        poDS->eColorSpace = OPJ_CLRSPC_GRAY;
+                                        CPLDebug("OPENJPEG", "Grayscale color space");
+                                    }
+                                    else if( enumcs == 18 )
+                                    {
+                                        poDS->eColorSpace = OPJ_CLRSPC_SYCC;
+                                        CPLDebug("OPENJPEG", "SYCC color space");
+                                    }
+                                    else if( enumcs == 20 )
+                                    {
+                                        /* Used by J2KP4files/testfiles_jp2/file7.jp2 */
+                                        poDS->eColorSpace = OPJ_CLRSPC_SRGB;
+                                        CPLDebug("OPENJPEG", "e-sRGB color space");
+                                    }
+                                    else if( enumcs == 21 )
+                                    {
+                                        /* Used by J2KP4files/testfiles_jp2/file5.jp2 */
+                                        poDS->eColorSpace = OPJ_CLRSPC_SRGB;
+                                        CPLDebug("OPENJPEG", "ROMM-RGB color space");
+                                    }
+                                    else
+                                    {
+                                        poDS->eColorSpace = OPJ_CLRSPC_UNKNOWN;
+                                        CPLDebug("OPENJPEG", "Unknown color space");
+                                    }
+                                }
+                                CPLFree(pabyContent);
+                            }
+                        }
+                        /* Check if there's an alpha channel or odd channel attribution */
+                        else if( EQUAL(oSubBox.GetType(),"cdef") &&
+                                 nDataLength == 2 + poDS->nBands * 6 )
+                        {
+                            GByte* pabyContent = oSubBox.ReadBoxData();
+                            if( pabyContent != NULL )
+                            {
+                                int nEntries = (pabyContent[0] << 8) | pabyContent[1];
+                                if( nEntries == poDS->nBands )
+                                {
+                                    poDS->nRedIndex = -1;
+                                    poDS->nGreenIndex = -1;
+                                    poDS->nBlueIndex = -1;
+                                    for(int i=0;i<poDS->nBands;i++)
+                                    {
+                                        int CNi = (pabyContent[2+6*i] << 8) | pabyContent[2+6*i+1];
+                                        int Typi = (pabyContent[2+6*i+2] << 8) | pabyContent[2+6*i+3];
+                                        int Asoci = (pabyContent[2+6*i+4] << 8) | pabyContent[2+6*i+5];
+                                        if( CNi < 0 || CNi >= poDS->nBands )
+                                        {
+                                            CPLError(CE_Failure, CPLE_AppDefined,
+                                                     "Wrong value of CN%d=%d", i, CNi);
+                                            break;
+                                        }
+                                        if( Typi == 0 )
+                                        {
+                                            if( Asoci == 1 )
+                                                poDS->nRedIndex = CNi;
+                                            else if( Asoci == 2 )
+                                                poDS->nGreenIndex = CNi;
+                                            else if( Asoci == 3 )
+                                                poDS->nBlueIndex = CNi;
+                                            else if( Asoci < 0 || (Asoci > poDS->nBands && Asoci != 65535) )
+                                            {
+                                                CPLError(CE_Failure, CPLE_AppDefined,
+                                                     "Wrong value of Asoc%d=%d", i, Asoci);
+                                                break;
+                                            }
+                                        }
+                                        else if( Typi == 1 )
+                                        {
+                                            poDS->nAlphaIndex = CNi;
+                                        }
+                                    }
+                                }
+                                else
+                                {
+                                    CPLDebug("OPENJPEG", "Unsupported cdef content");
+                                }
+                                CPLFree(pabyContent);
+                            }
+                        }
+                    }
+                }
+
+                if (!oBox.ReadNext())
+                    break;
+            }
+        }
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Create band information objects.                                */
 /* -------------------------------------------------------------------- */
     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
     {
         int bPromoteTo8Bit = (
-            iBand == 4 && poDS->nBands == 4 &&
-            psImage->comps[0].prec == 8 &&
-            psImage->comps[1].prec == 8 &&
-            psImage->comps[2].prec == 8 &&
-            psImage->comps[3].prec == 1 && 
-            CSLTestBoolean(CPLGetConfigOption("JP2OPENJPEG_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES")) );
-
-        poDS->SetBand( iBand, new JP2OpenJPEGRasterBand( poDS, iBand, eDataType,
-                                                         bPromoteTo8Bit ? 8: psImage->comps[iBand-1].prec,
-                                                         bPromoteTo8Bit,
-                                                         nTileW, nTileH) );
+            iBand == poDS->nAlphaIndex + 1 &&
+            psImage->comps[(poDS->nAlphaIndex==0 && poDS->nBands > 1) ? 1 : 0].prec == 8 &&
+            psImage->comps[poDS->nAlphaIndex ].prec == 1 && 
+            CSLFetchBoolean(poOpenInfo->papszOpenOptions, "1BIT_ALPHA_PROMOTION",
+                    CSLTestBoolean(CPLGetConfigOption("JP2OPENJPEG_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES"))) );
+        if( bPromoteTo8Bit )
+            CPLDebug("JP2OpenJPEG", "Alpha band is promoted from 1 bit to 8 bit");
+
+        JP2OpenJPEGRasterBand* poBand =
+            new JP2OpenJPEGRasterBand( poDS, iBand, eDataType,
+                                        bPromoteTo8Bit ? 8: psImage->comps[iBand-1].prec,
+                                        bPromoteTo8Bit,
+                                        nTileW, nTileH);
+        if( iBand == 1 && poCT != NULL )
+            poBand->poCT = poCT;
+        poDS->SetBand( iBand, poBand );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1136,17 +1798,18 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     int nW = poDS->nRasterXSize;
     int nH = poDS->nRasterYSize;
+
+    /* Lower resolutions are not compatible with a color-table */
+    if( poCT != NULL )
+        numResolutions = 0;
+
     while (poDS->nOverviewCount+1 < numResolutions &&
-           (nW > 256 || nH > 256) &&
+           (nW > 128 || nH > 128) &&
            (poDS->bUseSetDecodeArea || ((nTileW % 2) == 0 && (nTileH % 2) == 0)))
     {
         nW /= 2;
         nH /= 2;
 
-        VSILFILE* fpOvr = VSIFOpenL(poOpenInfo->pszFilename, "rb");
-        if (!fpOvr)
-            break;
-
         poDS->papoOverviewDS = (JP2OpenJPEGDataset**) CPLRealloc(
                     poDS->papoOverviewDS,
                     (poDS->nOverviewCount + 1) * sizeof(JP2OpenJPEGDataset*));
@@ -1154,6 +1817,10 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
         poODS->SetDescription( poOpenInfo->pszFilename );
         poODS->iLevel = poDS->nOverviewCount + 1;
         poODS->bUseSetDecodeArea = poDS->bUseSetDecodeArea;
+        poODS->nRedIndex = poDS->nRedIndex;
+        poODS->nGreenIndex = poDS->nGreenIndex;
+        poODS->nBlueIndex = poDS->nBlueIndex;
+        poODS->nAlphaIndex = poDS->nAlphaIndex;
         if (!poDS->bUseSetDecodeArea)
         {
             nTileW /= 2;
@@ -1169,22 +1836,22 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
             }
         }
 
-        poODS->eCodecFormat = poDS->eCodecFormat;
         poODS->eColorSpace = poDS->eColorSpace;
         poODS->nRasterXSize = nW;
         poODS->nRasterYSize = nH;
         poODS->nBands = poDS->nBands;
-        poODS->fp = fpOvr;
+        poODS->fp = poDS->fp;
+        poODS->nCodeStreamStart = nCodeStreamStart;
+        poODS->nCodeStreamLength = nCodeStreamLength;
         poODS->bIs420 = bIs420;
         for( iBand = 1; iBand <= poDS->nBands; iBand++ )
         {
             int bPromoteTo8Bit = (
-                iBand == 4 && poDS->nBands == 4 &&
-                psImage->comps[0].prec == 8 &&
-                psImage->comps[1].prec == 8 &&
-                psImage->comps[2].prec == 8 &&
-                psImage->comps[3].prec == 1 && 
-                CSLTestBoolean(CPLGetConfigOption("JP2OPENJPEG_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES")) );
+                iBand == poDS->nAlphaIndex + 1 &&
+                psImage->comps[(poDS->nAlphaIndex==0 && poDS->nBands > 1) ? 1 : 0].prec == 8 &&
+                psImage->comps[poDS->nAlphaIndex].prec == 1 && 
+                CSLFetchBoolean(poOpenInfo->papszOpenOptions, "1BIT_ALPHA_PROMOTION",
+                        CSLTestBoolean(CPLGetConfigOption("JP2OPENJPEG_PROMOTE_1BIT_ALPHA_AS_8BIT", "YES"))) );
 
             poODS->SetBand( iBand, new JP2OpenJPEGRasterBand( poODS, iBand, eDataType,
                                                               bPromoteTo8Bit ? 8: psImage->comps[iBand-1].prec,
@@ -1208,21 +1875,45 @@ GDALDataset *JP2OpenJPEGDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     if( poDS->nBands > 1 )
     {
-        poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
+        poDS->GDALDataset::SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
     }
 
+    poOpenInfo->fpL = poDS->fp;
     poDS->LoadJP2Metadata(poOpenInfo);
+    poOpenInfo->fpL = NULL;
 
-/* -------------------------------------------------------------------- */
-/*      Initialize any PAM information.                                 */
-/* -------------------------------------------------------------------- */
-    poDS->SetDescription( poOpenInfo->pszFilename );
-    poDS->TryLoadXML();
+    poDS->bHasGeoreferencingAtOpening = 
+        ((poDS->pszProjection != NULL && poDS->pszProjection[0] != '\0' )||
+         poDS->nGCPCount != 0 || poDS->bGeoTransformValid);
 
 /* -------------------------------------------------------------------- */
-/*      Check for overviews.                                            */
+/*      Vector layers                                                   */
 /* -------------------------------------------------------------------- */
-    //poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+    if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
+    {
+        poDS->LoadVectorLayers(
+            CSLFetchBoolean(poOpenInfo->papszOpenOptions, "OPEN_REMOTE_GML", FALSE));
+
+        // If file opened in vector-only mode and there's no vector,
+        // return
+        if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+            poDS->GetLayerCount() == 0 )
+        {
+            delete poDS;
+            return NULL;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Initialize any PAM information.                                 */
+/* -------------------------------------------------------------------- */
+    poDS->SetDescription( poOpenInfo->pszFilename );
+    poDS->TryLoadXML();
+
+/* -------------------------------------------------------------------- */
+/*      Check for overviews.                                            */
+/* -------------------------------------------------------------------- */
+    //poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
 
     return( poDS );
 }
@@ -1250,6 +1941,78 @@ void JP2OpenJPEGDataset::WriteBox(VSILFILE* fp, GDALJP2Box* poBox)
 }
 
 /************************************************************************/
+/*                         WriteGDALMetadataBox()                       */
+/************************************************************************/
+
+void JP2OpenJPEGDataset::WriteGDALMetadataBox( VSILFILE* fp,
+                                               GDALDataset* poSrcDS,
+                                               char** papszOptions )
+{
+    GDALJP2Box* poBox = GDALJP2Metadata::CreateGDALMultiDomainMetadataXMLBox(
+        poSrcDS, CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE));
+    if( poBox )
+        WriteBox(fp, poBox);
+    delete poBox;
+}
+
+/************************************************************************/
+/*                         WriteXMLBoxes()                              */
+/************************************************************************/
+
+void JP2OpenJPEGDataset::WriteXMLBoxes( VSILFILE* fp, GDALDataset* poSrcDS,
+                                         CPL_UNUSED char** papszOptions )
+{
+    int nBoxes = 0;
+    GDALJP2Box** papoBoxes = GDALJP2Metadata::CreateXMLBoxes(poSrcDS, &nBoxes);
+    for(int i=0;i<nBoxes;i++)
+    {
+        WriteBox(fp, papoBoxes[i]);
+        delete papoBoxes[i];
+    }
+    CPLFree(papoBoxes);
+}
+
+/************************************************************************/
+/*                           WriteXMPBox()                              */
+/************************************************************************/
+
+void JP2OpenJPEGDataset::WriteXMPBox ( VSILFILE* fp, GDALDataset* poSrcDS,
+                                       CPL_UNUSED char** papszOptions )
+{
+    GDALJP2Box* poBox = GDALJP2Metadata::CreateXMPBox(poSrcDS);
+    if( poBox )
+        WriteBox(fp, poBox);
+    delete poBox;
+}
+
+/************************************************************************/
+/*                           WriteIPRBox()                              */
+/************************************************************************/
+
+void JP2OpenJPEGDataset::WriteIPRBox ( VSILFILE* fp, GDALDataset* poSrcDS,
+                                       CPL_UNUSED char** papszOptions )
+{
+    GDALJP2Box* poBox = GDALJP2Metadata::CreateIPRBox(poSrcDS);
+    if( poBox )
+        WriteBox(fp, poBox);
+    delete poBox;
+}
+/************************************************************************/
+/*                         FloorPowerOfTwo()                            */
+/************************************************************************/
+
+static int FloorPowerOfTwo(int nVal)
+{
+    int nBits = 0;
+    while( nVal > 1 )
+    {
+        nBits ++;
+        nVal >>= 1;
+    }
+    return 1 << nBits;
+}
+
+/************************************************************************/
 /*                          CreateCopy()                                */
 /************************************************************************/
 
@@ -1264,21 +2027,19 @@ GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
     int  nXSize = poSrcDS->GetRasterXSize();
     int  nYSize = poSrcDS->GetRasterYSize();
 
-    if( nBands != 1 && nBands != 3 )
+    if( nBands == 0 || nBands > 16384 )
     {
         CPLError( CE_Failure, CPLE_NotSupported,
-                  "Unable to export files with %d bands.", nBands );
+                  "Unable to export files with %d bands. Must be >= 1 and <= 16384", nBands );
         return NULL;
     }
 
-    if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
+    GDALColorTable* poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
+    if (poCT != NULL && nBands != 1)
     {
-        CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, 
-                  "JP2OpenJPEG driver ignores color table. "
-                  "The source raster band will be considered as grey level.\n"
-                  "Consider using color table expansion (-expand option in gdal_translate)\n");
-        if (bStrict)
-            return NULL;
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "JP2OpenJPEG driver only supports a color table for a single-band dataset");
+        return NULL;
     }
 
     GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
@@ -1291,6 +2052,8 @@ GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
         return NULL;
     }
 
+    int bInspireTG = CSLFetchBoolean(papszOptions, "INSPIRE_TG", FALSE);
+
 /* -------------------------------------------------------------------- */
 /*      Analyze creation options.                                       */
 /* -------------------------------------------------------------------- */
@@ -1317,6 +2080,12 @@ GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
             eCodecFormat = OPJ_CODEC_JP2;
         }
     }
+    if( eCodecFormat != OPJ_CODEC_JP2 && bInspireTG )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                  "INSPIRE_TG=YES mandates CODEC=JP2 (TG requirement 21)");
+        return NULL;
+    }
 
     int nBlockXSize =
         atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "1024"));
@@ -1354,224 +2123,328 @@ GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
     }
 
     int bIsIrreversible =
-            ! (CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "REVERSIBLE", "NO")));
+            ! (CSLFetchBoolean(papszOptions, "REVERSIBLE", poCT != NULL));
 
-    double dfRate = 100. / 25;
+    std::vector<double> adfRates;
     const char* pszQuality = CSLFetchNameValueDef(papszOptions, "QUALITY", NULL);
+    double dfDefaultQuality = ( poCT != NULL ) ? 100.0 : 25.0;
     if (pszQuality)
     {
-        double dfQuality = atof(pszQuality);
-        if (dfQuality > 0 && dfQuality <= 100)
+        char **papszTokens = CSLTokenizeStringComplex( pszQuality, ",", FALSE, FALSE );
+        for(int i=0; papszTokens[i] != NULL; i++ )
         {
-            dfRate = 100 / dfQuality;
+            double dfQuality = CPLAtof(papszTokens[i]);
+            if (dfQuality > 0 && dfQuality <= 100)
+            {
+                double dfRate = 100 / dfQuality;
+                adfRates.push_back(dfRate);
+            }
+            else
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                         "Unsupported value for QUALITY: %s. Defaulting to single-layer, with quality=%.0f",
+                         papszTokens[i], dfDefaultQuality);
+                adfRates.resize(0);
+                break;
+            }
         }
-        else
+        if( papszTokens[0] == NULL )
         {
             CPLError(CE_Warning, CPLE_NotSupported,
-                 "Unsupported value for QUALITY : %s. Defaulting to 25",
-                 pszQuality);
+                     "Unsupported value for QUALITY: %s. Defaulting to single-layer, with quality=%.0f",
+                     pszQuality, dfDefaultQuality);
         }
+        CSLDestroy(papszTokens);
+    }
+    if( adfRates.size() == 0 )
+    {
+        adfRates.push_back(100. / dfDefaultQuality);
+    }
+
+    if( poCT != NULL && (bIsIrreversible || adfRates[adfRates.size()-1] != 100.0 / 100.0) )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Encoding a dataset with a color table with REVERSIBLE != YES "
+                 "or QUALITY != 100 will likely lead to bad visual results");
     }
 
-    int nNumResolutions = 6;
+    int nMaxTileDim = MAX(nBlockXSize, nBlockYSize);
+    int nNumResolutions = 1;
+    /* Pickup a reasonable value compatible with PROFILE_1 requirements */
+    while( (nMaxTileDim >> (nNumResolutions-1)) > 128 )
+        nNumResolutions ++;
+    int nMinProfile1Resolutions = nNumResolutions;
     const char* pszResolutions = CSLFetchNameValueDef(papszOptions, "RESOLUTIONS", NULL);
     if (pszResolutions)
     {
         nNumResolutions = atoi(pszResolutions);
-        if (nNumResolutions < 1 || nNumResolutions > 7)
+        if (nNumResolutions <= 0 || nNumResolutions >= 32 ||
+            (nMaxTileDim >> nNumResolutions) == 0 )
         {
-            nNumResolutions = 6;
             CPLError(CE_Warning, CPLE_NotSupported,
-                 "Unsupported value for RESOLUTIONS : %s. Defaulting to 6",
-                 pszResolutions);
+                 "Unsupported value for RESOLUTIONS : %s. Defaulting to %d",
+                 pszResolutions, nMinProfile1Resolutions);
+            nNumResolutions = nMinProfile1Resolutions;
         }
     }
-    
+
     int bSOP = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SOP", "FALSE"));
     int bEPH = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "EPH", "FALSE"));
-    
-    int bResample = nBands == 3 && eDataType == GDT_Byte &&
-            CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "YCBCR420", "FALSE"));
-    if (bResample && !((nXSize % 2) == 0 && (nYSize % 2) == 0 && (nBlockXSize % 2) == 0 && (nBlockYSize % 2) == 0))
+
+    int nRedBandIndex = -1, nGreenBandIndex = -1, nBlueBandIndex = -1;
+    int nAlphaBandIndex = -1;
+    for(int i=0;i<nBands;i++)
     {
-        CPLError(CE_Warning, CPLE_NotSupported,
-                 "YCBCR420 unsupported when image size and/or tile size are not multiple of 2");
-        bResample = FALSE;
+        GDALColorInterp eInterp = poSrcDS->GetRasterBand(i+1)->GetColorInterpretation();
+        if( eInterp == GCI_RedBand )
+            nRedBandIndex = i;
+        else if( eInterp == GCI_GreenBand )
+            nGreenBandIndex = i;
+        else if( eInterp == GCI_BlueBand )
+            nBlueBandIndex = i;
+        else if( eInterp == GCI_AlphaBand )
+            nAlphaBandIndex = i;
+    }
+    const char* pszAlpha = CSLFetchNameValue(papszOptions, "ALPHA");
+    if( nAlphaBandIndex < 0 && nBands > 1 && pszAlpha != NULL && CSLTestBoolean(pszAlpha) )
+    {
+        nAlphaBandIndex = nBands - 1;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Setup encoder                                                  */
-/* -------------------------------------------------------------------- */
-
-    opj_cparameters_t parameters;
-    opj_set_default_encoder_parameters(&parameters);
-    if (bSOP)
-        parameters.csty |= 0x02;
-    if (bEPH)
-        parameters.csty |= 0x04;
-    parameters.cp_disto_alloc = 1;
-    parameters.tcp_numlayers = 1;
-    parameters.tcp_rates[0] = (float) dfRate;
-    parameters.cp_tx0 = 0;
-    parameters.cp_ty0 = 0;
-    parameters.tile_size_on = TRUE;
-    parameters.cp_tdx = nBlockXSize;
-    parameters.cp_tdy = nBlockYSize;
-    parameters.irreversible = bIsIrreversible;
-    parameters.numresolution = nNumResolutions;
-    parameters.prog_order = eProgOrder;
-
-    opj_image_cmptparm_t* pasBandParams =
-            (opj_image_cmptparm_t*)CPLMalloc(nBands * sizeof(opj_image_cmptparm_t));
-    int iBand;
-    for(iBand=0;iBand<nBands;iBand++)
+    const char* pszYCBCR420 = CSLFetchNameValue(papszOptions, "YCBCR420");
+    int bYCBCR420 = FALSE;
+    if( pszYCBCR420 && CSLTestBoolean(pszYCBCR420) )
     {
-        pasBandParams[iBand].x0 = 0;
-        pasBandParams[iBand].y0 = 0;
-        if (bResample && iBand > 0)
+        if ((nBands == 3 || nBands == 4) && eDataType == GDT_Byte &&
+            nRedBandIndex == 0 && nGreenBandIndex == 1 && nBlueBandIndex == 2)
         {
-            pasBandParams[iBand].dx = 2;
-            pasBandParams[iBand].dy = 2;
-            pasBandParams[iBand].w = nXSize / 2;
-            pasBandParams[iBand].h = nYSize / 2;
+            if( ((nXSize % 2) == 0 && (nYSize % 2) == 0 && (nBlockXSize % 2) == 0 && (nBlockYSize % 2) == 0) )
+            {
+                bYCBCR420 = TRUE;
+            }
+            else
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                    "YCBCR420 unsupported when image size and/or tile size are not multiple of 2");
+            }
         }
         else
         {
-            pasBandParams[iBand].dx = 1;
-            pasBandParams[iBand].dy = 1;
-            pasBandParams[iBand].w = nXSize;
-            pasBandParams[iBand].h = nYSize;
+            CPLError(CE_Warning, CPLE_NotSupported,
+                    "YCBCR420 unsupported with this image band count and/or data byte");
         }
-        pasBandParams[iBand].sgnd = (eDataType == GDT_Int16 || eDataType == GDT_Int32);
-        pasBandParams[iBand].prec = 8 * nDataTypeSize;
     }
 
-    opj_codec_t* pCodec = opj_create_compress(eCodecFormat);
-    if (pCodec == NULL)
+    const char* pszYCC = CSLFetchNameValue(papszOptions, "YCC");
+    int bYCC = ((nBands == 3 || nBands == 4) && eDataType == GDT_Byte &&
+            CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "YCC", "TRUE")));
+    
+    /* TODO: when OpenJPEG 2.2 is released, make this conditional */
+    /* Depending on the way OpenJPEG <= r2950 is built, YCC with 4 bands might work on
+     * Debug mode, but this relies on unreliable stack buffer overflows, so
+     * better err on the safe side */
+    if( bYCC && nBands > 3 )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "opj_create_compress() failed");
-        CPLFree(pasBandParams);
-        return NULL;
+        if( pszYCC != NULL )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "OpenJPEG r2950 and below can generate invalid output with "
+                     "MCT YCC transform and more than 3 bands. Disabling YCC");
+        }
+        bYCC = FALSE;
     }
-
-    opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
-    opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback,NULL);
-    opj_set_error_handler(pCodec, JP2OpenJPEGDataset_ErrorCallback,NULL);
-
-    OPJ_COLOR_SPACE eColorSpace = (bResample) ? OPJ_CLRSPC_SYCC : (nBands == 3) ? OPJ_CLRSPC_SRGB : OPJ_CLRSPC_GRAY;
-
-    opj_image_t* psImage = opj_image_tile_create(nBands,pasBandParams,
-                                                 eColorSpace);
-
-
-    CPLFree(pasBandParams);
-    pasBandParams = NULL;
-    if (psImage == NULL)
+    
+    if( bYCBCR420 && bYCC )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "opj_image_tile_create() failed");
-        opj_destroy_codec(pCodec);
-        return NULL;
+        if( pszYCC != NULL )
+        {
+            CPLError(CE_Warning, CPLE_NotSupported,
+                    "YCC unsupported when YCbCr requesting");
+        }
+        bYCC = FALSE;
     }
+    
+/* -------------------------------------------------------------------- */
+/*      Deal with codeblocks size                                       */
+/* -------------------------------------------------------------------- */
 
-    psImage->x0 = 0;
-    psImage->y0 = 0;
-    psImage->x1 = nXSize;
-    psImage->y1 = nYSize;
-    psImage->color_space = eColorSpace;
-    psImage->numcomps = nBands;
-
-    if (!opj_setup_encoder(pCodec,&parameters,psImage))
+    int nCblockW = atoi(CSLFetchNameValueDef( papszOptions, "CODEBLOCK_WIDTH", "64" ));
+    int nCblockH = atoi(CSLFetchNameValueDef( papszOptions, "CODEBLOCK_HEIGHT", "64" ));
+    if( nCblockW < 4 || nCblockW > 1024 || nCblockH < 4 || nCblockH > 1024 )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "opj_setup_encoder() failed");
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        return NULL;
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Invalid values for codeblock size. Defaulting to 64x64");
+        nCblockW = 64;
+        nCblockH = 64;
+    }
+    else if( nCblockW * nCblockH > 4096 )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Invalid values for codeblock size. "
+                 "CODEBLOCK_WIDTH * CODEBLOCK_HEIGHT should be <= 4096. "
+                 "Defaulting to 64x64");
+        nCblockW = 64;
+        nCblockH = 64;
+    }
+    int nCblockW_po2 = FloorPowerOfTwo(nCblockW);
+    int nCblockH_po2 = FloorPowerOfTwo(nCblockH);
+    if( nCblockW_po2 != nCblockW || nCblockH_po2 != nCblockH )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Non power of two values used for codeblock size. "
+                 "Using to %dx%d",
+                 nCblockW_po2, nCblockH_po2);
     }
+    nCblockW = nCblockW_po2;
+    nCblockH = nCblockH_po2;
 
 /* -------------------------------------------------------------------- */
-/*      Create the dataset.                                             */
+/*      Deal with codestream PROFILE                                    */
 /* -------------------------------------------------------------------- */
-
-    const char* pszAccess = EQUALN(pszFilename, "/vsisubfile/", 12) ? "r+b" : "w+b";
-    VSILFILE* fp = VSIFOpenL(pszFilename, pszAccess);
-    if (fp == NULL)
+    const char* pszProfile = CSLFetchNameValueDef( papszOptions, "PROFILE", "AUTO" );
+    int bProfile1 = FALSE;
+    if( EQUAL(pszProfile, "UNRESTRICTED") )
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Cannot create file");
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        return NULL;
+        bProfile1 = FALSE;
+        if( bInspireTG )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                    "INSPIRE_TG=YES mandates PROFILE=PROFILE_1 (TG requirement 21)");
+            return NULL;
+        }
+    }
+    else if( EQUAL(pszProfile, "UNRESTRICTED_FORCED") )
+    {
+        bProfile1 = FALSE;
+    }
+    else if( EQUAL(pszProfile, "PROFILE_1_FORCED") ) /* For debug only: can produce inconsistent codestream */
+    {
+        bProfile1 = TRUE;
     }
+    else
+    {
+        if( !(EQUAL(pszProfile, "PROFILE_1") || EQUAL(pszProfile, "AUTO")) )
+        {
+            CPLError(CE_Warning, CPLE_NotSupported,
+                     "Unsupported value for PROFILE : %s. Defaulting to AUTO",
+                     pszProfile);
+            pszProfile = "AUTO";
+        }
 
-    opj_stream_t * pStream;
-    pStream = opj_stream_create(1024*1024, FALSE);
-    opj_stream_set_write_function(pStream, JP2OpenJPEGDataset_Write);
-    opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
-    opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
-#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
-    opj_stream_set_user_data(pStream, fp, NULL);
-#else
-    opj_stream_set_user_data(pStream, fp);
-#endif
+        bProfile1 = TRUE;
+        const char* pszReq21OrEmpty = (bInspireTG) ? " (TG requirement 21)" : "";
+        if( (nBlockXSize != nXSize || nBlockYSize != nYSize) &&
+            (nBlockXSize != nBlockYSize || nBlockXSize > 1024 || nBlockYSize > 1024 ) )
+        {
+            bProfile1 = FALSE;
+            if( bInspireTG || EQUAL(pszProfile, "PROFILE_1") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Tile dimensions incompatible with PROFILE_1%s. "
+                         "Should be whole image or square with dimension <= 1024.",
+                         pszReq21OrEmpty);
+                return NULL;
+            }
+        }
+        if( (nMaxTileDim >> (nNumResolutions-1)) > 128 )
+        {
+            bProfile1 = FALSE;
+            if( bInspireTG || EQUAL(pszProfile, "PROFILE_1") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Number of resolutions incompatible with PROFILE_1%s. "
+                         "Should be at least %d.",
+                         pszReq21OrEmpty,
+                         nMinProfile1Resolutions);
+                return NULL;
+            }
+        }
+        if( nCblockW > 64 || nCblockH > 64 )
+        {
+            bProfile1 = FALSE;
+            if( bInspireTG || EQUAL(pszProfile, "PROFILE_1") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Codeblock width incompatible with PROFILE_1%s. "
+                         "Codeblock width or height should be <= 64.",
+                         pszReq21OrEmpty);
+                return NULL;
+            }
+        }
+    }
 
-    if (!opj_start_compress(pCodec,psImage,pStream))
+/* -------------------------------------------------------------------- */
+/*      Work out the precision.                                         */
+/* -------------------------------------------------------------------- */
+    int nBits;
+    if( CSLFetchNameValue( papszOptions, "NBITS" ) != NULL )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "opj_start_compress() failed");
-        opj_stream_destroy(pStream);
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        VSIFCloseL(fp);
-        return NULL;
+        nBits = atoi(CSLFetchNameValue(papszOptions,"NBITS"));
+        if( bInspireTG &&
+            !(nBits == 1 || nBits == 8 || nBits == 16 || nBits == 32) )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                    "INSPIRE_TG=YES mandates NBITS=1,8,16 or 32 (TG requirement 24)");
+            return NULL;
+        }
+    }
+    else if( poSrcDS->GetRasterBand(1)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) 
+             != NULL )
+    {
+        nBits = atoi(poSrcDS->GetRasterBand(1)->GetMetadataItem( "NBITS", 
+                                                       "IMAGE_STRUCTURE" ));
+        if( bInspireTG && 
+            !(nBits == 1 || nBits == 8 || nBits == 16 || nBits == 32) )
+        {
+            /* Implements "NOTE If the original data do not satisfy this "
+               "requirement, they will be converted in a representation using "
+               "the next higher power of 2" */
+            nBits = GDALGetDataTypeSize(eDataType);
+        }
+    }
+    else
+    {
+        nBits = GDALGetDataTypeSize(eDataType);
     }
 
-    int nTilesX = (nXSize + nBlockXSize - 1) / nBlockXSize;
-    int nTilesY = (nYSize + nBlockYSize - 1) / nBlockYSize;
-
-    GByte* pTempBuffer =(GByte*)VSIMalloc(nBlockXSize * nBlockYSize *
-                                          nBands * nDataTypeSize);
-    if (pTempBuffer == NULL)
+    if( (GDALGetDataTypeSize(eDataType) == 8 && nBits > 8) ||
+        (GDALGetDataTypeSize(eDataType) == 16 && (nBits <= 8 || nBits > 16)) ||
+        (GDALGetDataTypeSize(eDataType) == 32 && (nBits <= 16 || nBits > 32)) )
     {
-        opj_stream_destroy(pStream);
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        VSIFCloseL(fp);
-        return NULL;
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Inconsistant NBITS value with data type. Using %d",
+                 GDALGetDataTypeSize(eDataType));
     }
 
-    GByte* pYUV420Buffer = NULL;
-    if (bResample)
+/* -------------------------------------------------------------------- */
+/*      Georeferencing options                                          */
+/* -------------------------------------------------------------------- */
+
+    int bGMLJP2Option = CSLFetchBoolean( papszOptions, "GMLJP2", TRUE );
+    int nGMLJP2Version = 1;
+    const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
+    if( pszGMLJP2V2Def != NULL )
     {
-        pYUV420Buffer =(GByte*)VSIMalloc(3 * nBlockXSize * nBlockYSize / 2);
-        if (pYUV420Buffer == NULL)
+        bGMLJP2Option = TRUE;
+        nGMLJP2Version = 2;
+        if( bInspireTG )
         {
-            opj_stream_destroy(pStream);
-            opj_image_destroy(psImage);
-            opj_destroy_codec(pCodec);
-            CPLFree(pTempBuffer);
-            VSIFCloseL(fp);
+            CPLError(CE_Warning, CPLE_NotSupported,
+                    "INSPIRE_TG=YES is only compatible with GMLJP2 v1");
             return NULL;
         }
     }
+    int bGeoJP2Option = CSLFetchBoolean( papszOptions, "GeoJP2", TRUE );
 
-/* -------------------------------------------------------------------- */
-/*      Setup GML and GeoTIFF information.                              */
-/* -------------------------------------------------------------------- */
     GDALJP2Metadata oJP2MD;
 
-    int bWriteExtraBoxes = FALSE;
-    int bHasGeoreferencing = FALSE;
+    int bGeoreferencingCompatOfGeoJP2 = FALSE;
     int bGeoreferencingCompatOfGMLJP2 = FALSE;
-    if( eCodecFormat == OPJ_CODEC_JP2 &&
-        (CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) ||
-         CSLFetchBoolean( papszOptions, "GeoJP2", TRUE )) )
+    if( eCodecFormat == OPJ_CODEC_JP2 && (bGMLJP2Option || bGeoJP2Option) )
     {
         if( poSrcDS->GetGCPCount() > 0 )
         {
-            bWriteExtraBoxes = TRUE;
-            bHasGeoreferencing = TRUE;
+            bGeoreferencingCompatOfGeoJP2 = TRUE;
             oJP2MD.SetGCPs( poSrcDS->GetGCPCount(),
                             poSrcDS->GetGCPs() );
             oJP2MD.SetProjection( poSrcDS->GetGCPProjection() );
@@ -1581,291 +2454,1030 @@ GDALDataset * JP2OpenJPEGDataset::CreateCopy( const char * pszFilename,
             const char* pszWKT = poSrcDS->GetProjectionRef();
             if( pszWKT != NULL && pszWKT[0] != '\0' )
             {
-                bGeoreferencingCompatOfGMLJP2 = TRUE;
-                bHasGeoreferencing = TRUE;
-                bWriteExtraBoxes = TRUE;
+                bGeoreferencingCompatOfGeoJP2 = TRUE;
                 oJP2MD.SetProjection( pszWKT );
             }
             double adfGeoTransform[6];
             if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
             {
-                bGeoreferencingCompatOfGMLJP2 = TRUE;
-                bHasGeoreferencing = TRUE;
-                bWriteExtraBoxes = TRUE;
+                bGeoreferencingCompatOfGeoJP2 = TRUE;
                 oJP2MD.SetGeoTransform( adfGeoTransform );
             }
+            bGeoreferencingCompatOfGMLJP2 =
+                        ( pszWKT != NULL && pszWKT[0] != '\0' ) && 
+                          poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None;
+        }
+        if( poSrcDS->GetMetadata("RPC") != NULL )
+        {
+            oJP2MD.SetRPCMD(  poSrcDS->GetMetadata("RPC") );
+            bGeoreferencingCompatOfGeoJP2 = TRUE;
         }
 
         const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
         oJP2MD.bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
-    }
 
-#define PIXELS_PER_INCH 2
-#define PIXELS_PER_CM   3
+        if( bGMLJP2Option && CPLGetConfigOption("GMLJP2OVERRIDE", NULL) != NULL )
+            bGeoreferencingCompatOfGMLJP2 = TRUE;
+    }
 
-    // Resolution
-    double dfXRes = 0, dfYRes = 0;
-    int nResUnit = 0;
-    if( eCodecFormat == OPJ_CODEC_JP2
-        && poSrcDS->GetMetadataItem("TIFFTAG_XRESOLUTION") != NULL
-        && poSrcDS->GetMetadataItem("TIFFTAG_YRESOLUTION") != NULL
-        && poSrcDS->GetMetadataItem("TIFFTAG_RESOLUTIONUNIT") != NULL )
+    if( CSLFetchNameValue( papszOptions, "GMLJP2" ) != NULL && bGMLJP2Option &&
+        !bGeoreferencingCompatOfGMLJP2 && nGMLJP2Version == 1 )
     {
-        dfXRes =
-            CPLAtof(poSrcDS->GetMetadataItem("TIFFTAG_XRESOLUTION"));
-        dfYRes =
-            CPLAtof(poSrcDS->GetMetadataItem("TIFFTAG_YRESOLUTION"));
-        nResUnit = atoi(poSrcDS->GetMetadataItem("TIFFTAG_RESOLUTIONUNIT"));
-
-        if( nResUnit == PIXELS_PER_INCH )
-        {
-            // convert pixels per inch to pixels per cm.
-            dfXRes = dfXRes * 39.37 / 100.0;
-            dfYRes = dfYRes * 39.37 / 100.0;
-            nResUnit = PIXELS_PER_CM;
-        }
-
-        if( nResUnit == PIXELS_PER_CM &&
-            dfXRes > 0 && dfYRes > 0 &&
-            dfXRes < 65535 && dfYRes < 65535 )
-        {
-            bWriteExtraBoxes = TRUE;
-        }
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "GMLJP2 box was explicitely required but cannot be written due "
+                 "to lack of georeferencing and/or unsupported georeferencing for GMLJP2");
     }
 
-    /* The file pointer should have been set 8 bytes after the */
-    /* last written bytes, because openjpeg has reserved it */
-    /* for the jp2c header, but still not written. */
-    vsi_l_offset nPosOriginalJP2C = 0;
-    vsi_l_offset nPosRealJP2C = 0;
-    GByte abyBackupWhatShouldHaveBeenTheJP2CBoxHeader[8];
-
-    if( bWriteExtraBoxes )
+    if( CSLFetchNameValue( papszOptions, "GeoJP2" ) != NULL && bGeoJP2Option &&
+        !bGeoreferencingCompatOfGeoJP2 )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "GeoJP2 box was explicitely required but cannot be written due "
+                 "to lack of georeferencing");
+    }
+    int bGeoBoxesAfter = CSLFetchBoolean(papszOptions, "GEOBOXES_AFTER_JP2C",
+                                         bInspireTG);
+    GDALJP2Box* poGMLJP2Box = NULL;
+    if( eCodecFormat == OPJ_CODEC_JP2 && bGMLJP2Option && bGeoreferencingCompatOfGMLJP2 )
     {
-        nPosOriginalJP2C = VSIFTellL(fp) - 8;
+        if( nGMLJP2Version == 1)
+            poGMLJP2Box = oJP2MD.CreateGMLJP2(nXSize,nYSize);
+        else
+            poGMLJP2Box = oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS);
+        if( poGMLJP2Box == NULL )
+            return NULL;
+    }
 
-        char szBoxName[4+1];
-        int nLBoxJP2H = 0;
+/* -------------------------------------------------------------------- */
+/*      Setup encoder                                                  */
+/* -------------------------------------------------------------------- */
 
-        /* If we must write a Res/Resd box, */
-        /* read the box header at offset 32 */
-        if ( nResUnit == PIXELS_PER_CM )
+    opj_cparameters_t parameters;
+    opj_set_default_encoder_parameters(&parameters);
+    if (bSOP)
+        parameters.csty |= 0x02;
+    if (bEPH)
+        parameters.csty |= 0x04;
+    parameters.cp_disto_alloc = 1;
+    parameters.tcp_numlayers = (int)adfRates.size();
+    for(int i=0;i<(int)adfRates.size();i++)
+        parameters.tcp_rates[i] = (float) adfRates[i];
+    parameters.cp_tx0 = 0;
+    parameters.cp_ty0 = 0;
+    parameters.tile_size_on = TRUE;
+    parameters.cp_tdx = nBlockXSize;
+    parameters.cp_tdy = nBlockYSize;
+    parameters.irreversible = bIsIrreversible;
+    parameters.numresolution = nNumResolutions;
+    parameters.prog_order = eProgOrder;
+    parameters.tcp_mct = bYCC;
+    parameters.cblockw_init = nCblockW;
+    parameters.cblockh_init = nCblockH;
+
+    /* Add precincts */
+    const char* pszPrecincts = CSLFetchNameValueDef(papszOptions, "PRECINCTS",
+        "{512,512},{256,512},{128,512},{64,512},{32,512},{16,512},{8,512},{4,512},{2,512}");
+    char **papszTokens = CSLTokenizeStringComplex( pszPrecincts, "{},", FALSE, FALSE );
+    int nPrecincts = CSLCount(papszTokens) / 2;
+    for(int i=0;i<nPrecincts && i < OPJ_J2K_MAXRLVLS;i++)
+    {
+        int nPCRW = atoi(papszTokens[2*i]);
+        int nPCRH = atoi(papszTokens[2*i+1]);
+        if( nPCRW < 1 || nPCRH < 1 )
+            break;
+        parameters.csty |= 0x01;
+        parameters.res_spec ++;
+        parameters.prcw_init[i] = nPCRW;
+        parameters.prch_init[i] = nPCRH;
+    }
+    CSLDestroy(papszTokens);
+
+    /* Add tileparts setting */
+    const char* pszTileParts = CSLFetchNameValueDef(papszOptions, "TILEPARTS", "DISABLED");
+    if( EQUAL(pszTileParts, "RESOLUTIONS") )
+    {
+        parameters.tp_on = 1;
+        parameters.tp_flag = 'R';
+    }
+    else if( EQUAL(pszTileParts, "LAYERS") )
+    {
+        if( parameters.tcp_numlayers == 1 )
         {
-            VSIFSeekL(fp, 32, SEEK_SET);
-            VSIFReadL(&nLBoxJP2H, 1, 4, fp);
-            nLBoxJP2H = CPL_MSBWORD32( nLBoxJP2H );
-            VSIFReadL(szBoxName, 1, 4, fp);
-            szBoxName[4] = '\0';
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "TILEPARTS=LAYERS has no real interest with single-layer codestream");
         }
+        parameters.tp_on = 1;
+        parameters.tp_flag = 'L';
+    }
+    else if( EQUAL(pszTileParts, "COMPONENTS") )
+    {
+        parameters.tp_on = 1;
+        parameters.tp_flag = 'C';
+    }
+    else if( !EQUAL(pszTileParts, "DISABLED") )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Invalid value for TILEPARTS");
+    }
 
-        VSIFSeekL(fp, nPosOriginalJP2C, SEEK_SET);
+    if( bProfile1 )
+    {
+#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
+        parameters.rsiz = OPJ_PROFILE_1;
+#else
+        /* This is a hack but this works */
+        parameters.cp_rsiz = (OPJ_RSIZ_CAPABILITIES) 2; /* Profile 1 */
+#endif
+    }
 
-        /* And check that it is the jp2h box before */
-        /* writing the res box */
-        if ( nResUnit == PIXELS_PER_CM && EQUAL(szBoxName, "jp2h") )
+    opj_image_cmptparm_t* pasBandParams =
+            (opj_image_cmptparm_t*)CPLMalloc(nBands * sizeof(opj_image_cmptparm_t));
+    int iBand;
+    int bSamePrecision = TRUE;
+    int b1BitAlpha = FALSE;
+    for(iBand=0;iBand<nBands;iBand++)
+    {
+        pasBandParams[iBand].x0 = 0;
+        pasBandParams[iBand].y0 = 0;
+        if (bYCBCR420 && (iBand == 1 || iBand == 2))
         {
-            /* Format a resd box and embed it inside a res box */
-            GDALJP2Box oResd;
-            oResd.SetType("resd");
-            GByte aby[10];
+            pasBandParams[iBand].dx = 2;
+            pasBandParams[iBand].dy = 2;
+            pasBandParams[iBand].w = nXSize / 2;
+            pasBandParams[iBand].h = nYSize / 2;
+        }
+        else
+        {
+            pasBandParams[iBand].dx = 1;
+            pasBandParams[iBand].dy = 1;
+            pasBandParams[iBand].w = nXSize;
+            pasBandParams[iBand].h = nYSize;
+        }
 
-            int nYDenom = 1;
-            while (nYDenom < 32767 && dfYRes < 32767)
+        pasBandParams[iBand].sgnd = (eDataType == GDT_Int16 || eDataType == GDT_Int32);
+        pasBandParams[iBand].prec = nBits;
+
+        const char* pszNBits = poSrcDS->GetRasterBand(iBand+1)->GetMetadataItem(
+            "NBITS", "IMAGE_STRUCTURE");
+        /* Recommendation 38 In the case of an opacity channel, the bit depth should be 1-bit. */
+        if( iBand == nAlphaBandIndex &&
+            ((pszNBits != NULL && EQUAL(pszNBits, "1")) ||
+              CSLFetchBoolean(papszOptions, "1BIT_ALPHA", bInspireTG)) )
+        {
+            if( iBand != nBands - 1 && nBits != 1 )
             {
-                dfYRes *= 2;
-                nYDenom *= 2;
+                /* Might be a bug in openjpeg, but it seems that if the alpha */
+                /* band is the first one, it would select 1-bit for all channels... */
+                CPLError(CE_Warning, CPLE_NotSupported,
+                         "Cannot output 1-bit alpha channel if it is not the last one");
             }
-            int nXDenom = 1;
-            while (nXDenom < 32767 && dfXRes < 32767)
+            else
             {
-                dfXRes *= 2;
-                nXDenom *= 2;
+                CPLDebug("OPENJPEG", "Using 1-bit alpha channel");
+                pasBandParams[iBand].sgnd = 0;
+                pasBandParams[iBand].prec = 1;
+                bSamePrecision = FALSE;
+                b1BitAlpha = TRUE;
             }
+        }
+    }
+
+    if( bInspireTG && nAlphaBandIndex >= 0 && !b1BitAlpha )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                  "INSPIRE_TG=YES recommends 1BIT_ALPHA=YES (Recommendation 38)");
+    }
+
+    /* Always ask OpenJPEG to do codestream only. We will take care */
+    /* of JP2 boxes */
+    opj_codec_t* pCodec = opj_create_compress(OPJ_CODEC_J2K);
+    if (pCodec == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "opj_create_compress() failed");
+        CPLFree(pasBandParams);
+        delete poGMLJP2Box;
+        return NULL;
+    }
+
+    opj_set_info_handler(pCodec, JP2OpenJPEGDataset_InfoCallback,NULL);
+    opj_set_warning_handler(pCodec, JP2OpenJPEGDataset_WarningCallback,NULL);
+    opj_set_error_handler(pCodec, JP2OpenJPEGDataset_ErrorCallback,NULL);
 
-            aby[0] = (GByte) (((int)dfYRes) / 256);
-            aby[1] = ((int)dfYRes) % 256;
-            aby[2] = (GByte) (nYDenom / 256);
-            aby[3] = nYDenom % 256;
-            aby[4] = (GByte) (((int)dfXRes) / 256);
-            aby[5] = ((int)dfXRes) % 256;
-            aby[6] = (GByte) (nXDenom / 256);
-            aby[7] = nXDenom % 256;
-            aby[8] = 2;
-            aby[9] = 2;
-            oResd.SetWritableData(10, aby);
-            GDALJP2Box* poResd = &oResd;
-            GDALJP2Box* poRes = GDALJP2Box::CreateAsocBox( 1, &poResd );
-            poRes->SetType("res ");
+    OPJ_COLOR_SPACE eColorSpace = OPJ_CLRSPC_GRAY;
 
-            /* Now let's extend the jp2c box header so that the */
-            /* res box becomes a sub-box of it */
-            nLBoxJP2H += (int)poRes->GetDataLength() + 8;
-            nLBoxJP2H = CPL_MSBWORD32( nLBoxJP2H );
-            VSIFSeekL(fp, 32, SEEK_SET);
-            VSIFWriteL(&nLBoxJP2H, 1, 4, fp);
+    if( bYCBCR420 )
+    {
+        eColorSpace = OPJ_CLRSPC_SYCC;
+    }
+    else if( (nBands == 3 || nBands == 4) &&
+             nRedBandIndex >= 0 && nGreenBandIndex >= 0 && nBlueBandIndex >= 0 )
+    {
+        eColorSpace = OPJ_CLRSPC_SRGB;
+    }
+    else if (poCT != NULL)
+    {
+        eColorSpace = OPJ_CLRSPC_SRGB;
+    }
 
-            /* Write the box at the end of the file */
-            VSIFSeekL(fp, nPosOriginalJP2C, SEEK_SET);
-            WriteBox(fp, poRes);
+    opj_image_t* psImage = opj_image_tile_create(nBands,pasBandParams,
+                                                 eColorSpace);
 
-            delete poRes;
-        }
+    if (psImage == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "opj_image_tile_create() failed");
+        opj_destroy_codec(pCodec);
+        CPLFree(pasBandParams);
+        pasBandParams = NULL;
+        delete poGMLJP2Box;
+        return NULL;
+    }
 
-        if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) &&
-            bGeoreferencingCompatOfGMLJP2 )
+    psImage->x0 = 0;
+    psImage->y0 = 0;
+    psImage->x1 = nXSize;
+    psImage->y1 = nYSize;
+    psImage->color_space = eColorSpace;
+    psImage->numcomps = nBands;
+
+    if (!opj_setup_encoder(pCodec,&parameters,psImage))
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "opj_setup_encoder() failed");
+        opj_image_destroy(psImage);
+        opj_destroy_codec(pCodec);
+        CPLFree(pasBandParams);
+        pasBandParams = NULL;
+        delete poGMLJP2Box;
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create the dataset.                                             */
+/* -------------------------------------------------------------------- */
+
+    const char* pszAccess = EQUALN(pszFilename, "/vsisubfile/", 12) ? "r+b" : "w+b";
+    VSILFILE* fp = VSIFOpenL(pszFilename, pszAccess);
+    if (fp == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot create file");
+        opj_image_destroy(psImage);
+        opj_destroy_codec(pCodec);
+        CPLFree(pasBandParams);
+        pasBandParams = NULL;
+        delete poGMLJP2Box;
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Add JP2 boxes.                                                  */
+/* -------------------------------------------------------------------- */
+    vsi_l_offset nStartJP2C = 0;
+    int bUseXLBoxes = FALSE;
+
+    if( eCodecFormat == OPJ_CODEC_JP2  )
+    {
+        GDALJP2Box jPBox(fp);
+        jPBox.SetType("jP  ");
+        jPBox.AppendWritableData(4, "\x0D\x0A\x87\x0A");
+        WriteBox(fp, &jPBox);
+
+        GDALJP2Box ftypBox(fp);
+        ftypBox.SetType("ftyp");
+        ftypBox.AppendWritableData(4, "jp2 "); /* Branding */
+        ftypBox.AppendUInt32(0); /* minimum version */
+        ftypBox.AppendWritableData(4, "jp2 "); /* Compatibility list: first value */
+
+        int bJPXOption = CSLFetchBoolean( papszOptions, "JPX", TRUE );
+        if( bInspireTG && poGMLJP2Box != NULL && !bJPXOption )
         {
-            GDALJP2Box* poBox = oJP2MD.CreateGMLJP2(nXSize,nYSize);
-            WriteBox(fp, poBox);
-            delete poBox;
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "INSPIRE_TG=YES implies following GMLJP2 specification which "
+                     "recommends advertize reader requirement 67 feature, and thus JPX capability");
         }
-        if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) &&
-            bHasGeoreferencing )
+        else if( poGMLJP2Box != NULL && bJPXOption )
         {
-            GDALJP2Box* poBox = oJP2MD.CreateJP2GeoTIFF();
-            WriteBox(fp, poBox);
-            delete poBox;
+            /* GMLJP2 uses lbl and asoc boxes, which are JPEG2000 Part II spec */
+            /* advertizing jpx is required per 8.1 of 05-047r3 GMLJP2 */
+            ftypBox.AppendWritableData(4, "jpx "); /* Compatibility list: second value */
         }
+        WriteBox(fp, &ftypBox);
 
-        nPosRealJP2C = VSIFTellL(fp);
+        int bIPR = poSrcDS->GetMetadata("xml:IPR") != NULL &&
+                   CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE);
 
-        /* Backup the res, GMLJP2 or GeoJP2 box header */
-        /* that will be overwritten by opj_end_compress() */
-        VSIFSeekL(fp, nPosOriginalJP2C, SEEK_SET);
-        VSIFReadL(abyBackupWhatShouldHaveBeenTheJP2CBoxHeader, 1, 8, fp);
+        /* Reader requirement box */
+        if( poGMLJP2Box != NULL && bJPXOption )
+        {
+            GDALJP2Box rreqBox(fp);
+            rreqBox.SetType("rreq");
+            rreqBox.AppendUInt8(1); /* ML = 1 byte for mask length */
 
-        VSIFSeekL(fp, nPosRealJP2C + 8, SEEK_SET);
-    }
+            rreqBox.AppendUInt8(0x80 | 0x40 | (bIPR ? 0x20 : 0)); /* FUAM */
+            rreqBox.AppendUInt8(0x80); /* DCM */
 
-/* -------------------------------------------------------------------- */
-/*      Iterate over the tiles                                          */
-/* -------------------------------------------------------------------- */
-    pfnProgress( 0.0, NULL, pProgressData );
-
-    CPLErr eErr = CE_None;
-    int nBlockXOff, nBlockYOff;
-    int iTile = 0;
-    for(nBlockYOff=0;eErr == CE_None && nBlockYOff<nTilesY;nBlockYOff++)
-    {
-        for(nBlockXOff=0;eErr == CE_None && nBlockXOff<nTilesX;nBlockXOff++)
-        {
-            int nWidthToRead = MIN(nBlockXSize, nXSize - nBlockXOff * nBlockXSize);
-            int nHeightToRead = MIN(nBlockYSize, nYSize - nBlockYOff * nBlockYSize);
-            eErr = poSrcDS->RasterIO(GF_Read,
-                                     nBlockXOff * nBlockXSize,
-                                     nBlockYOff * nBlockYSize,
-                                     nWidthToRead, nHeightToRead,
-                                     pTempBuffer, nWidthToRead, nHeightToRead,
-                                     eDataType,
-                                     nBands, NULL,
-                                     0,0,0);
-            if (eErr == CE_None)
+            rreqBox.AppendUInt16(2 + bIPR); /* NSF: Number of standard features */
+
+            rreqBox.AppendUInt16((bProfile1) ? 4 : 5); /* SF0 : PROFILE 1 or PROFILE 2 */
+            rreqBox.AppendUInt8(0x80); /* SM0 */
+
+            rreqBox.AppendUInt16(67); /* SF1 : GMLJP2 box */
+            rreqBox.AppendUInt8(0x40); /* SM1 */
+
+            if( bIPR )
             {
-                if (bResample)
+                rreqBox.AppendUInt16(35); /* SF2 : IPR metadata */
+                rreqBox.AppendUInt8(0x20); /* SM2 */
+            }
+            rreqBox.AppendUInt16(0); /* NVF */
+            WriteBox(fp, &rreqBox);
+        }
+
+        GDALJP2Box ihdrBox(fp);
+        ihdrBox.SetType("ihdr");
+        ihdrBox.AppendUInt32(nYSize);
+        ihdrBox.AppendUInt32(nXSize);
+        ihdrBox.AppendUInt16(nBands);
+        GByte BPC;
+        if( bSamePrecision )
+            BPC = (pasBandParams[0].prec-1) | (pasBandParams[0].sgnd << 7);
+        else
+            BPC = 255;
+        ihdrBox.AppendUInt8(BPC);
+        ihdrBox.AppendUInt8(7); /* C=Compression type: fixed value */
+        ihdrBox.AppendUInt8(0); /* UnkC: 0= colourspace of the image is known */
+                                /*and correctly specified in the Colourspace Specification boxes within the file */
+        ihdrBox.AppendUInt8(bIPR); /* IPR: 0=no intellectual property, 1=IPR box */
+
+        GDALJP2Box bpccBox(fp);
+        if( !bSamePrecision )
+        {
+            bpccBox.SetType("bpcc");
+            for(int i=0;i<nBands;i++)
+                bpccBox.AppendUInt8((pasBandParams[i].prec-1) | (pasBandParams[i].sgnd << 7));
+        }
+
+        GDALJP2Box colrBox(fp);
+        colrBox.SetType("colr");
+        colrBox.AppendUInt8(1); /* METHOD: 1=Enumerated Colourspace */
+        colrBox.AppendUInt8(0); /* PREC: Precedence. 0=(field reserved for ISO use) */
+        colrBox.AppendUInt8(0); /* APPROX: Colourspace approximation. */
+        GUInt32 enumcs = 16;
+        if( eColorSpace == OPJ_CLRSPC_SRGB )
+            enumcs = 16;
+        else if(  eColorSpace == OPJ_CLRSPC_GRAY )
+            enumcs = 17;
+        else if(  eColorSpace == OPJ_CLRSPC_SYCC )
+            enumcs = 18;
+        colrBox.AppendUInt32(enumcs); /* EnumCS: Enumerated colourspace */
+
+        GDALJP2Box pclrBox(fp);
+        GDALJP2Box cmapBox(fp);
+        int nCTComponentCount = 0;
+        if (poCT != NULL)
+        {
+            pclrBox.SetType("pclr");
+            int nEntries = MIN(256, poCT->GetColorEntryCount());
+            nCTComponentCount = atoi(CSLFetchNameValueDef(papszOptions, "CT_COMPONENTS", "0"));
+            if( bInspireTG )
+            {
+                if( nCTComponentCount != 0 && nCTComponentCount != 3 )
+                    CPLError(CE_Warning, CPLE_AppDefined, "Inspire TG mandates 3 components for color table");
+                else
+                    nCTComponentCount = 3;
+            }
+            else if( nCTComponentCount != 3 && nCTComponentCount != 4 )
+            {
+                nCTComponentCount = 3;
+                for(int i=0;i<nEntries;i++)
                 {
-                    int j, i;
-                    for(j=0;j<nHeightToRead;j++)
+                    const GDALColorEntry* psEntry = poCT->GetColorEntry(i);
+                    if( psEntry->c4 != 255 )
                     {
-                        for(i=0;i<nWidthToRead;i++)
-                        {
-                            int R = pTempBuffer[j*nWidthToRead+i];
-                            int G = pTempBuffer[nHeightToRead*nWidthToRead + j*nWidthToRead+i];
-                            int B = pTempBuffer[2*nHeightToRead*nWidthToRead + j*nWidthToRead+i];
-                            int Y = (int) (0.299 * R + 0.587 * G + 0.114 * B);
-                            int Cb = CLAMP_0_255((int) (-0.1687 * R - 0.3313 * G + 0.5 * B  + 128));
-                            int Cr = CLAMP_0_255((int) (0.5 * R - 0.4187 * G - 0.0813 * B  + 128));
-                            pYUV420Buffer[j*nWidthToRead+i] = (GByte) Y;
-                            pYUV420Buffer[nHeightToRead * nWidthToRead + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cb;
-                            pYUV420Buffer[5 * nHeightToRead * nWidthToRead / 4 + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cr;
-                        }
+                        CPLDebug("OPENJPEG", "Color table has at least one non-opaque value. "
+                                "This may cause compatibility problems with some readers. "
+                                "In which case use CT_COMPONENTS=3 creation option");
+                        nCTComponentCount = 4;
+                        break;
                     }
+                }
+            }
+            nRedBandIndex = 0;
+            nGreenBandIndex = 1;
+            nBlueBandIndex = 2;
+            nAlphaBandIndex = (nCTComponentCount == 4) ? 3 : -1;
+
+            pclrBox.AppendUInt16(nEntries);
+            pclrBox.AppendUInt8(nCTComponentCount); /* NPC: Number of components */
+            for(int i=0;i<nCTComponentCount;i++)
+            {
+                pclrBox.AppendUInt8(7); /* Bi: unsigned 8 bits */
+            }
+            for(int i=0;i<nEntries;i++)
+            {
+                const GDALColorEntry* psEntry = poCT->GetColorEntry(i);
+                pclrBox.AppendUInt8((GByte)psEntry->c1);
+                pclrBox.AppendUInt8((GByte)psEntry->c2);
+                pclrBox.AppendUInt8((GByte)psEntry->c3);
+                if( nCTComponentCount == 4 )
+                    pclrBox.AppendUInt8((GByte)psEntry->c4);
+            }
+            
+            cmapBox.SetType("cmap");
+            for(int i=0;i<nCTComponentCount;i++)
+            {
+                cmapBox.AppendUInt16(0); /* CMPi: code stream component index */
+                cmapBox.AppendUInt8(1); /* MYTPi: 1=palette mapping */
+                cmapBox.AppendUInt8(i); /* PCOLi: index component from the map */
+            }
+        }
 
-                    if (!opj_write_tile(pCodec,
-                                        iTile,
-                                        pYUV420Buffer,
-                                        3 * nWidthToRead * nHeightToRead / 2,
-                                        pStream))
+        GDALJP2Box cdefBox(fp);
+        if( ((nBands == 3 || nBands == 4) &&
+             (eColorSpace == OPJ_CLRSPC_SRGB || eColorSpace == OPJ_CLRSPC_SYCC) &&
+             (nRedBandIndex != 0 || nGreenBandIndex != 1 || nBlueBandIndex != 2)) ||
+            nAlphaBandIndex >= 0)
+        {
+            cdefBox.SetType("cdef");
+            int nComponents = (nCTComponentCount == 4) ? 4 : nBands;
+            cdefBox.AppendUInt16(nComponents);
+            for(int i=0;i<nComponents;i++)
+            {
+                cdefBox.AppendUInt16(i);   /* Component number */
+                if( i != nAlphaBandIndex )
+                {
+                    cdefBox.AppendUInt16(0);   /* Signification: This channel is the colour image data for the associated colour */
+                    if( eColorSpace == OPJ_CLRSPC_GRAY && nComponents == 2)
+                        cdefBox.AppendUInt16(1); /* Colour of the component: associated with a particular colour */
+                    else if ((eColorSpace == OPJ_CLRSPC_SRGB ||
+                            eColorSpace == OPJ_CLRSPC_SYCC) &&
+                            (nComponents == 3 || nComponents == 4) )
                     {
-                        CPLError(CE_Failure, CPLE_AppDefined,
-                                "opj_write_tile() failed");
-                        eErr = CE_Failure;
+                        if( i == nRedBandIndex )
+                            cdefBox.AppendUInt16(1);
+                        else if( i == nGreenBandIndex )
+                            cdefBox.AppendUInt16(2);
+                        else if( i == nBlueBandIndex )
+                            cdefBox.AppendUInt16(3);
+                        else
+                        {
+                            CPLError(CE_Warning, CPLE_AppDefined,
+                                    "Could not associate band %d with a red/green/blue channel",
+                                    i+1);
+                            cdefBox.AppendUInt16(65535);
+                        }
                     }
+                    else
+                        cdefBox.AppendUInt16(65535); /* Colour of the component: not associated with any particular colour */
                 }
                 else
                 {
-                    if (!opj_write_tile(pCodec,
-                                        iTile,
-                                        pTempBuffer,
-                                        nWidthToRead * nHeightToRead * nBands * nDataTypeSize,
-                                        pStream))
-                    {
-                        CPLError(CE_Failure, CPLE_AppDefined,
-                                "opj_write_tile() failed");
-                        eErr = CE_Failure;
-                    }
+                    cdefBox.AppendUInt16(1);        /* Signification: Non pre-multiplied alpha */
+                    cdefBox.AppendUInt16(0);        /* Colour of the component: This channel is associated as the image as a whole */
+                }
+            }
+        }
+
+        // Add res box if needed
+        double dfXRes = 0, dfYRes = 0;
+        int nResUnit = 0;
+        GDALJP2Box* poRes = NULL;
+        if( poSrcDS->GetMetadataItem("TIFFTAG_XRESOLUTION") != NULL
+            && poSrcDS->GetMetadataItem("TIFFTAG_YRESOLUTION") != NULL
+            && poSrcDS->GetMetadataItem("TIFFTAG_RESOLUTIONUNIT") != NULL )
+        {
+            dfXRes =
+                CPLAtof(poSrcDS->GetMetadataItem("TIFFTAG_XRESOLUTION"));
+            dfYRes =
+                CPLAtof(poSrcDS->GetMetadataItem("TIFFTAG_YRESOLUTION"));
+            nResUnit = atoi(poSrcDS->GetMetadataItem("TIFFTAG_RESOLUTIONUNIT"));
+#define PIXELS_PER_INCH 2
+#define PIXELS_PER_CM   3
+
+            if( nResUnit == PIXELS_PER_INCH )
+            {
+                // convert pixels per inch to pixels per cm.
+                dfXRes = dfXRes * 39.37 / 100.0;
+                dfYRes = dfYRes * 39.37 / 100.0;
+                nResUnit = PIXELS_PER_CM;
+            }
+
+            if( nResUnit == PIXELS_PER_CM &&
+                dfXRes > 0 && dfYRes > 0 &&
+                dfXRes < 65535 && dfYRes < 65535 )
+            {
+                /* Format a resd box and embed it inside a res box */
+                GDALJP2Box oResd;
+                oResd.SetType("resd");
+
+                int nYDenom = 1;
+                while (nYDenom < 32767 && dfYRes < 32767)
+                {
+                    dfYRes *= 2;
+                    nYDenom *= 2;
+                }
+                int nXDenom = 1;
+                while (nXDenom < 32767 && dfXRes < 32767)
+                {
+                    dfXRes *= 2;
+                    nXDenom *= 2;
                 }
+
+                oResd.AppendUInt16((GUInt16)dfYRes);
+                oResd.AppendUInt16((GUInt16)nYDenom);
+                oResd.AppendUInt16((GUInt16)dfXRes);
+                oResd.AppendUInt16((GUInt16)nXDenom);
+                oResd.AppendUInt8(2); /* vertical exponent */
+                oResd.AppendUInt8(2); /* horizontal exponent */
+
+                GDALJP2Box* poResd = &oResd;
+                poRes = GDALJP2Box::CreateAsocBox( 1, &poResd );
+                poRes->SetType("res ");
+            }
+        }
+
+        /* Build and write jp2h super box now */
+        GDALJP2Box* apoBoxes[7];
+        int nBoxes = 1;
+        apoBoxes[0] = &ihdrBox;
+        if( bpccBox.GetDataLength() )
+            apoBoxes[nBoxes++] = &bpccBox;
+        apoBoxes[nBoxes++] = &colrBox;
+        if( pclrBox.GetDataLength() )
+            apoBoxes[nBoxes++] = &pclrBox;
+        if( cmapBox.GetDataLength() )
+            apoBoxes[nBoxes++] = &cmapBox;
+        if( cdefBox.GetDataLength() )
+            apoBoxes[nBoxes++] = &cdefBox;
+        if( poRes )
+            apoBoxes[nBoxes++] = poRes;
+        GDALJP2Box* psJP2HBox = GDALJP2Box::CreateSuperBox( "jp2h",
+                                                            nBoxes,
+                                                            apoBoxes );
+        WriteBox(fp, psJP2HBox);
+        delete psJP2HBox;
+        delete poRes;
+
+        if( !bGeoBoxesAfter )
+        {
+            if( bGeoJP2Option && bGeoreferencingCompatOfGeoJP2 )
+            {
+                GDALJP2Box* poBox = oJP2MD.CreateJP2GeoTIFF();
+                WriteBox(fp, poBox);
+                delete poBox;
             }
 
-            if( !pfnProgress( (iTile + 1) * 1.0 / (nTilesX * nTilesY), NULL, pProgressData ) )
-                eErr = CE_Failure;
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) &&
+                !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+            {
+                WriteXMPBox(fp, poSrcDS, papszOptions);
+            }
 
-            iTile ++;
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+            {
+                if( !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+                    WriteXMLBoxes(fp, poSrcDS, papszOptions);
+                WriteGDALMetadataBox(fp, poSrcDS, papszOptions);
+            }
+
+            if( poGMLJP2Box != NULL )
+            {
+                WriteBox(fp, poGMLJP2Box);
+            }
         }
     }
+    CPLFree(pasBandParams);
+    pasBandParams = NULL;
 
-    VSIFree(pTempBuffer);
-    VSIFree(pYUV420Buffer);
+/* -------------------------------------------------------------------- */
+/*      Try lossless reuse of an existing JPEG2000 codestream           */
+/* -------------------------------------------------------------------- */
+    vsi_l_offset nCodeStreamLength = 0;
+    vsi_l_offset nCodeStreamStart = 0;
+    VSILFILE* fpSrc = NULL;
+    if( CSLFetchBoolean(papszOptions, "USE_SRC_CODESTREAM", FALSE) )
+    {
+        CPLString osSrcFilename( poSrcDS->GetDescription() );
+        if( poSrcDS->GetDriver() != NULL &&
+            poSrcDS->GetDriver() == GDALGetDriverByName("VRT") )
+        {
+            VRTDataset* poVRTDS = (VRTDataset* )poSrcDS;
+            GDALDataset* poSimpleSourceDS = poVRTDS->GetSingleSimpleSource();
+            if( poSimpleSourceDS )
+                osSrcFilename = poSimpleSourceDS->GetDescription();
+        }
+
+        fpSrc = VSIFOpenL( osSrcFilename, "rb" );
+        if( fpSrc )
+        {
+            nCodeStreamStart = JP2OpenJPEGFindCodeStream(fpSrc,
+                                                         &nCodeStreamLength);
+        }
+        if( nCodeStreamLength == 0 )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "USE_SRC_CODESTREAM=YES specified, but no codestream found");
+        }
+    }
 
-    if (eErr != CE_None)
+    if( eCodecFormat == OPJ_CODEC_JP2  )
     {
-        opj_stream_destroy(pStream);
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        VSIFCloseL(fp);
-        return NULL;
+        // Start codestream box
+        nStartJP2C = VSIFTellL(fp);
+        if( nCodeStreamLength )
+            bUseXLBoxes = ((vsi_l_offset)(GUInt32)nCodeStreamLength != nCodeStreamLength);
+        else
+            bUseXLBoxes = CSLFetchBoolean(papszOptions, "JP2C_XLBOX", FALSE) || /* For debugging */
+                (GIntBig)nXSize * nYSize * nBands * nDataTypeSize / adfRates[adfRates.size()-1] > 4e9;
+        GUInt32 nLBox = (bUseXLBoxes) ? 1 : 0;
+        CPL_MSBPTR32(&nLBox);
+        VSIFWriteL(&nLBox, 1, 4, fp);
+        VSIFWriteL("jp2c", 1, 4, fp);
+        if( bUseXLBoxes )
+        {
+            GUIntBig nXLBox = 0;
+            VSIFWriteL(&nXLBox, 1, 8, fp);
+        }
     }
 
-    if (!opj_end_compress(pCodec,pStream))
+/* -------------------------------------------------------------------- */
+/*      Do lossless reuse of an existing JPEG2000 codestream            */
+/* -------------------------------------------------------------------- */
+    if( fpSrc )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "opj_end_compress() failed");
+        const char* apszIgnoredOptions[] = {
+            "BLOCKXSIZE", "BLOCKYSIZE", "QUALITY", "REVERSIBLE",
+            "RESOLUTIONS", "PROGRESSION", "SOP", "EPH",
+            "YCBCR420", "YCC", "NBITS", "1BIT_ALPHA", "PRECINCTS",
+            "TILEPARTS", "CODEBLOCK_WIDTH", "CODEBLOCK_HEIGHT", NULL };
+        for( int i = 0; apszIgnoredOptions[i]; i ++)
+        {
+            if( CSLFetchNameValue(papszOptions, apszIgnoredOptions[i]) )
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                            "Option %s ignored when USE_SRC_CODESTREAM=YES",
+                            apszIgnoredOptions[i]);
+            }
+        }
+        GByte abyBuffer[4096];
+        VSIFSeekL( fpSrc, nCodeStreamStart, SEEK_SET );
+        vsi_l_offset nRead = 0;
+        while( nRead < nCodeStreamLength )
+        {
+            int nToRead = ( nCodeStreamLength-nRead > 4096 ) ? 4049 :
+                                        (int)(nCodeStreamLength-nRead);
+            if( (int)VSIFReadL(abyBuffer, 1, nToRead, fpSrc) != nToRead )
+            {
+                VSIFCloseL(fp);
+                VSIFCloseL(fpSrc);
+                opj_image_destroy(psImage);
+                opj_destroy_codec(pCodec);
+                delete poGMLJP2Box;
+                return NULL;
+            }
+            if( nRead == 0 && (pszProfile || bInspireTG) &&
+                abyBuffer[2] == 0xFF && abyBuffer[3] == 0x51 )
+            {
+                if( EQUAL(pszProfile, "UNRESTRICTED") )
+                {
+                    abyBuffer[6] = 0;
+                    abyBuffer[7] = 0;
+                }
+                else if( EQUAL(pszProfile, "PROFILE_1") || bInspireTG )
+                {
+                    // TODO: ultimately we should check that we can really set Profile 1
+                    abyBuffer[6] = 0;
+                    abyBuffer[7] = 2;
+                }
+            }
+            if( (int)VSIFWriteL(abyBuffer, 1, nToRead, fp) != nToRead ||
+                !pfnProgress( (nRead + nToRead) * 1.0 / nCodeStreamLength,
+                                NULL, pProgressData ) )
+            {
+                VSIFCloseL(fp);
+                VSIFCloseL(fpSrc);
+                opj_image_destroy(psImage);
+                opj_destroy_codec(pCodec);
+                delete poGMLJP2Box;
+                return NULL;
+            }
+            nRead += nToRead;
+        }
+
+        VSIFCloseL(fpSrc);
+    }
+    else
+    {
+        opj_stream_t * pStream;
+        JP2OpenJPEGFile sJP2OpenJPEGFile;
+        sJP2OpenJPEGFile.fp = fp;
+        sJP2OpenJPEGFile.nBaseOffset = VSIFTellL(fp);
+        pStream = opj_stream_create(1024*1024, FALSE);
+        opj_stream_set_write_function(pStream, JP2OpenJPEGDataset_Write);
+        opj_stream_set_seek_function(pStream, JP2OpenJPEGDataset_Seek);
+        opj_stream_set_skip_function(pStream, JP2OpenJPEGDataset_Skip);
+#if defined(OPENJPEG_VERSION) && OPENJPEG_VERSION >= 20100
+        opj_stream_set_user_data(pStream, &sJP2OpenJPEGFile, NULL);
+#else
+        opj_stream_set_user_data(pStream, &sJP2OpenJPEGFile);
+#endif
+
+        if (!opj_start_compress(pCodec,psImage,pStream))
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                    "opj_start_compress() failed");
+            opj_stream_destroy(pStream);
+            opj_image_destroy(psImage);
+            opj_destroy_codec(pCodec);
+            VSIFCloseL(fp);
+            delete poGMLJP2Box;
+            return NULL;
+        }
+
+        int nTilesX = (nXSize + nBlockXSize - 1) / nBlockXSize;
+        int nTilesY = (nYSize + nBlockYSize - 1) / nBlockYSize;
+
+        GUIntBig nTileSize = (GUIntBig)nBlockXSize * nBlockYSize * nBands * nDataTypeSize;
+        GByte* pTempBuffer;
+        if( nTileSize != (GUIntBig)(GUInt32)nTileSize )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported, "Tile size exceeds 4GB");
+            pTempBuffer = NULL;
+        }
+        else
+        {
+            pTempBuffer = (GByte*)VSIMalloc((size_t)nTileSize);
+        }
+        if (pTempBuffer == NULL)
+        {
+            opj_stream_destroy(pStream);
+            opj_image_destroy(psImage);
+            opj_destroy_codec(pCodec);
+            VSIFCloseL(fp);
+            delete poGMLJP2Box;
+            return NULL;
+        }
+
+        GByte* pYUV420Buffer = NULL;
+        if (bYCBCR420)
+        {
+            pYUV420Buffer =(GByte*)VSIMalloc(3 * nBlockXSize * nBlockYSize / 2 +
+                                            ((nBands == 4) ? nBlockXSize * nBlockYSize : 0));
+            if (pYUV420Buffer == NULL)
+            {
+                opj_stream_destroy(pStream);
+                opj_image_destroy(psImage);
+                opj_destroy_codec(pCodec);
+                CPLFree(pTempBuffer);
+                VSIFCloseL(fp);
+                delete poGMLJP2Box;
+                return NULL;
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Iterate over the tiles                                          */
+/* -------------------------------------------------------------------- */
+        pfnProgress( 0.0, NULL, pProgressData );
+
+        CPLErr eErr = CE_None;
+        int nBlockXOff, nBlockYOff;
+        int iTile = 0;
+        for(nBlockYOff=0;eErr == CE_None && nBlockYOff<nTilesY;nBlockYOff++)
+        {
+            for(nBlockXOff=0;eErr == CE_None && nBlockXOff<nTilesX;nBlockXOff++)
+            {
+                int nWidthToRead = MIN(nBlockXSize, nXSize - nBlockXOff * nBlockXSize);
+                int nHeightToRead = MIN(nBlockYSize, nYSize - nBlockYOff * nBlockYSize);
+                eErr = poSrcDS->RasterIO(GF_Read,
+                                        nBlockXOff * nBlockXSize,
+                                        nBlockYOff * nBlockYSize,
+                                        nWidthToRead, nHeightToRead,
+                                        pTempBuffer, nWidthToRead, nHeightToRead,
+                                        eDataType,
+                                        nBands, NULL,
+                                        0,0,0,NULL);
+                if( b1BitAlpha )
+                {
+                    for(int i=0;i<nWidthToRead*nHeightToRead;i++)
+                    {
+                        if( pTempBuffer[nAlphaBandIndex*nWidthToRead*nHeightToRead+i] )
+                            pTempBuffer[nAlphaBandIndex*nWidthToRead*nHeightToRead+i] = 1;
+                        else
+                            pTempBuffer[nAlphaBandIndex*nWidthToRead*nHeightToRead+i] = 0;
+                    }
+                }
+                if (eErr == CE_None)
+                {
+                    if (bYCBCR420)
+                    {
+                        int j, i;
+                        for(j=0;j<nHeightToRead;j++)
+                        {
+                            for(i=0;i<nWidthToRead;i++)
+                            {
+                                int R = pTempBuffer[j*nWidthToRead+i];
+                                int G = pTempBuffer[nHeightToRead*nWidthToRead + j*nWidthToRead+i];
+                                int B = pTempBuffer[2*nHeightToRead*nWidthToRead + j*nWidthToRead+i];
+                                int Y = (int) (0.299 * R + 0.587 * G + 0.114 * B);
+                                int Cb = CLAMP_0_255((int) (-0.1687 * R - 0.3313 * G + 0.5 * B  + 128));
+                                int Cr = CLAMP_0_255((int) (0.5 * R - 0.4187 * G - 0.0813 * B  + 128));
+                                pYUV420Buffer[j*nWidthToRead+i] = (GByte) Y;
+                                pYUV420Buffer[nHeightToRead * nWidthToRead + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cb;
+                                pYUV420Buffer[5 * nHeightToRead * nWidthToRead / 4 + ((j/2) * ((nWidthToRead)/2) + i/2) ] = (GByte) Cr;
+                                if( nBands == 4 )
+                                {
+                                    pYUV420Buffer[3 * nHeightToRead * nWidthToRead / 2 + j*nWidthToRead+i ] =
+                                        (GByte) pTempBuffer[3*nHeightToRead*nWidthToRead + j*nWidthToRead+i];
+                                }
+                            }
+                        }
+
+                        int nBytesToWrite = 3 * nWidthToRead * nHeightToRead / 2;
+                        if (nBands == 4)
+                            nBytesToWrite += nBlockXSize * nBlockYSize;
+
+                        if (!opj_write_tile(pCodec,
+                                            iTile,
+                                            pYUV420Buffer,
+                                            nBytesToWrite,
+                                            pStream))
+                        {
+                            CPLError(CE_Failure, CPLE_AppDefined,
+                                    "opj_write_tile() failed");
+                            eErr = CE_Failure;
+                        }
+                    }
+                    else
+                    {
+                        if (!opj_write_tile(pCodec,
+                                            iTile,
+                                            pTempBuffer,
+                                            nWidthToRead * nHeightToRead * nBands * nDataTypeSize,
+                                            pStream))
+                        {
+                            CPLError(CE_Failure, CPLE_AppDefined,
+                                    "opj_write_tile() failed");
+                            eErr = CE_Failure;
+                        }
+                    }
+                }
+
+                if( !pfnProgress( (iTile + 1) * 1.0 / (nTilesX * nTilesY), NULL, pProgressData ) )
+                    eErr = CE_Failure;
+
+                iTile ++;
+            }
+        }
+
+        VSIFree(pTempBuffer);
+        VSIFree(pYUV420Buffer);
+
+        if (eErr != CE_None)
+        {
+            opj_stream_destroy(pStream);
+            opj_image_destroy(psImage);
+            opj_destroy_codec(pCodec);
+            VSIFCloseL(fp);
+            delete poGMLJP2Box;
+            return NULL;
+        }
+
+        if (!opj_end_compress(pCodec,pStream))
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                    "opj_end_compress() failed");
+            opj_stream_destroy(pStream);
+            opj_image_destroy(psImage);
+            opj_destroy_codec(pCodec);
+            VSIFCloseL(fp);
+            delete poGMLJP2Box;
+            return NULL;
+        }
         opj_stream_destroy(pStream);
-        opj_image_destroy(psImage);
-        opj_destroy_codec(pCodec);
-        VSIFCloseL(fp);
-        return NULL;
     }
 
-    opj_stream_destroy(pStream);
     opj_image_destroy(psImage);
     opj_destroy_codec(pCodec);
 
-    /* Move the jp2c box header at its real position */
-    /* and restore the res, GMLJP2 or GeoJP2 box header that */
-    /* has been overwritten */
-    if( bWriteExtraBoxes )
+/* -------------------------------------------------------------------- */
+/*      Patch JP2C box length and add trailing JP2 boxes                */
+/* -------------------------------------------------------------------- */
+    if( eCodecFormat == OPJ_CODEC_JP2 &&
+        !CSLFetchBoolean(papszOptions, "JP2C_LENGTH_ZERO", FALSE) /* debug option */ )
     {
-        GByte abyJP2CHeader[8];
+        vsi_l_offset nEndJP2C = VSIFTellL(fp);
+        GUIntBig nBoxSize = nEndJP2C -nStartJP2C;
+        if( bUseXLBoxes )
+        {
+            VSIFSeekL(fp, nStartJP2C + 8, SEEK_SET);
+            CPL_MSBPTR64(&nBoxSize);
+            VSIFWriteL(&nBoxSize, 8, 1, fp);
+        }
+        else
+        {
+            GUInt32 nBoxSize32 = (GUInt32)nBoxSize;
+            if( (vsi_l_offset)nBoxSize32 != nBoxSize )
+            {
+                /*  Shouldn't happen hopefully */
+                if( (bGeoreferencingCompatOfGeoJP2 || poGMLJP2Box) && bGeoBoxesAfter )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Cannot write GMLJP2/GeoJP2 boxes as codestream is unexpectedly > 4GB");
+                    bGeoreferencingCompatOfGeoJP2 = FALSE;
+                    delete poGMLJP2Box;
+                    poGMLJP2Box = NULL;
+                }
+            }
+            else
+            {
+                VSIFSeekL(fp, nStartJP2C, SEEK_SET);
+                CPL_MSBPTR32(&nBoxSize32);
+                VSIFWriteL(&nBoxSize32, 4, 1, fp);
+            }
+        }
+        VSIFSeekL(fp, 0, SEEK_END);
+
+        if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+        {
+            WriteIPRBox(fp, poSrcDS, papszOptions);
+        }
+
+        if( bGeoBoxesAfter )
+        {
+            if( poGMLJP2Box != NULL )
+            {
+                WriteBox(fp, poGMLJP2Box);
+            }
 
-        VSIFSeekL(fp, nPosOriginalJP2C, SEEK_SET);
-        VSIFReadL(abyJP2CHeader, 1, 8, fp);
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+            {
+                if( !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+                    WriteXMLBoxes(fp, poSrcDS, papszOptions);
+                WriteGDALMetadataBox(fp, poSrcDS, papszOptions);
+            }
 
-        VSIFSeekL(fp, nPosOriginalJP2C, SEEK_SET);
-        VSIFWriteL(abyBackupWhatShouldHaveBeenTheJP2CBoxHeader, 1, 8, fp);
+            if( bGeoJP2Option && bGeoreferencingCompatOfGeoJP2 )
+            {
+                GDALJP2Box* poBox = oJP2MD.CreateJP2GeoTIFF();
+                WriteBox(fp, poBox);
+                delete poBox;
+            }
 
-        VSIFSeekL(fp, nPosRealJP2C, SEEK_SET);
-        VSIFWriteL(abyJP2CHeader, 1, 8, fp);
+            if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) &&
+                !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
+            {
+                WriteXMPBox(fp, poSrcDS, papszOptions);
+            }
+        }
     }
 
     VSIFCloseL(fp);
+    delete poGMLJP2Box;
+
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
     JP2OpenJPEGDataset *poDS = (JP2OpenJPEGDataset*) JP2OpenJPEGDataset::Open(&oOpenInfo);
 
     if( poDS )
-        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
+    {
+        poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & (~GCIF_METADATA) );
+
+        /* Only write relevant metadata to PAM, and if needed */
+        if( !CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
+        {
+            char** papszSrcMD = CSLDuplicate(poSrcDS->GetMetadata());
+            papszSrcMD = CSLSetNameValue(papszSrcMD, GDALMD_AREA_OR_POINT, NULL);
+            papszSrcMD = CSLSetNameValue(papszSrcMD, "Corder", NULL);
+            for(char** papszSrcMDIter = papszSrcMD;
+                    papszSrcMDIter && *papszSrcMDIter; )
+            {
+                /* Remove entries like KEY= (without value) */
+                if( (*papszSrcMDIter)[0] &&
+                    (*papszSrcMDIter)[strlen((*papszSrcMDIter))-1] == '=' )
+                {
+                    CPLFree(*papszSrcMDIter);
+                    memmove(papszSrcMDIter, papszSrcMDIter + 1,
+                            sizeof(char*) * (CSLCount(papszSrcMDIter + 1) + 1));
+                }
+                else
+                    ++papszSrcMDIter;
+            }
+            char** papszMD = CSLDuplicate(poDS->GetMetadata());
+            papszMD = CSLSetNameValue(papszMD, GDALMD_AREA_OR_POINT, NULL);
+            if( papszSrcMD && papszSrcMD[0] != NULL &&
+                CSLCount(papszSrcMD) != CSLCount(papszMD) )
+            {
+                poDS->SetMetadata(papszSrcMD);
+            }
+            CSLDestroy(papszSrcMD);
+            CSLDestroy(papszMD);
+        }
+    }
 
     return poDS;
 }
@@ -1887,26 +3499,36 @@ void GDALRegister_JP2OpenJPEG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "JP2OpenJPEG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "JPEG-2000 driver based on OpenJPEG library" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_jp2openjpeg.html" );
         poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jp2" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "jp2 j2k" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
                                    "Byte Int16 UInt16 Int32 UInt32" );
 
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionList>"
+"   <Option name='1BIT_ALPHA_PROMOTION' type='boolean' description='Whether a 1-bit alpha channel should be promoted to 8-bit' default='YES'/>"
+"   <Option name='OPEN_REMOTE_GML' type='boolean' description='Whether to load remote vector layers referenced by a link in a GMLJP2 v2 box' default='NO'/>"
+"</OpenOptionList>" );
+
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
 "<CreationOptionList>"
 "   <Option name='CODEC' type='string-select' default='according to file extension. If unknown, default to J2K'>"
 "       <Value>JP2</Value>"
 "       <Value>J2K</Value>"
 "   </Option>"
-"   <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
-"   <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
-"   <Option name='QUALITY' type='float' description='Quality. 0-100' default='25'/>"
+"   <Option name='GeoJP2' type='boolean' description='Whether to emit a GeoJP2 box' default='YES'/>"
+"   <Option name='GMLJP2' type='boolean' description='Whether to emit a GMLJP2 v1 box' default='YES'/>"
+"   <Option name='GMLJP2V2_DEF' type='string' description='Definition file to describe how a GMLJP2 v2 box should be generated. If set to YES, a minimal instance will be created'/>"
+"   <Option name='QUALITY' type='string' description='Single quality value or comma separated list of increasing quality values for several layers, each in the 0-100 range' default='25'/>"
 "   <Option name='REVERSIBLE' type='boolean' description='True if the compression is reversible' default='false'/>"
-"   <Option name='RESOLUTIONS' type='int' description='Number of resolutions. 1-7' default='6'/>"
+"   <Option name='RESOLUTIONS' type='int' description='Number of resolutions.' min='1' max='30'/>"
 "   <Option name='BLOCKXSIZE' type='int' description='Tile Width' default='1024'/>"
 "   <Option name='BLOCKYSIZE' type='int' description='Tile Height' default='1024'/>"
 "   <Option name='PROGRESSION' type='string-select' default='LRCP'>"
@@ -1919,6 +3541,31 @@ void GDALRegister_JP2OpenJPEG()
 "   <Option name='SOP' type='boolean' description='True to insert SOP markers' default='false'/>"
 "   <Option name='EPH' type='boolean' description='True to insert EPH markers' default='false'/>"
 "   <Option name='YCBCR420' type='boolean' description='if RGB must be resampled to YCbCr 4:2:0' default='false'/>"
+"   <Option name='YCC' type='boolean' description='if RGB must be transformed to YCC color space (lossless MCT transform)' default='YES'/>"
+"   <Option name='NBITS' type='int' description='Bits (precision) for sub-byte files (1-7), sub-uint16 (9-15), sub-uint32 (17-31)'/>"
+"   <Option name='1BIT_ALPHA' type='boolean' description='Whether to encode the alpha channel as a 1-bit channel' default='NO'/>"
+"   <Option name='ALPHA' type='boolean' description='Whether to force encoding last channel as alpha channel' default='NO'/>"
+"   <Option name='PROFILE' type='string-select' description='Which codestream profile to use' default='AUTO'>"
+"       <Value>AUTO</Value>"
+"       <Value>UNRESTRICTED</Value>"
+"       <Value>PROFILE_1</Value>"
+"   </Option>"
+"   <Option name='INSPIRE_TG' type='boolean' description='Whether to use features that comply with Inspire Orthoimagery Technical Guidelines' default='NO'/>"
+"   <Option name='JPX' type='boolean' description='Whether to advertize JPX features when a GMLJP2 box is written' default='YES'/>"
+"   <Option name='GEOBOXES_AFTER_JP2C' type='boolean' description='Whether to place GeoJP2/GMLJP2 boxes after the code-stream' default='NO'/>"
+"   <Option name='PRECINCTS' type='string' description='Precincts size as a string of the form {w,h},{w,h},... with power-of-two values'/>"
+"   <Option name='TILEPARTS' type='string-select' description='Whether to generate tile-parts and according to which criterion' default='DISABLED'>"
+"       <Value>DISABLED</Value>"
+"       <Value>RESOLUTIONS</Value>"
+"       <Value>LAYERS</Value>"
+"       <Value>COMPONENTS</Value>"
+"   </Option>"
+"   <Option name='CODEBLOCK_WIDTH' type='int' description='Codeblock width' default='64' min='4' max='1024'/>"
+"   <Option name='CODEBLOCK_HEIGHT' type='int' description='Codeblock height' default='64' min='4' max='1024'/>"
+"   <Option name='CT_COMPONENTS' type='int' min='3' max='4' description='If there is one color table, number of color table components to write. Autodetected if not specified.'/>"
+"   <Option name='WRITE_METADATA' type='boolean' description='Whether metadata should be written, in a dedicated JP2 XML box' default='NO'/>"
+"   <Option name='MAIN_MD_DOMAIN_ONLY' type='boolean' description='(Only if WRITE_METADATA=YES) Whether only metadata from the main domain should be written' default='NO'/>"
+"   <Option name='USE_SRC_CODESTREAM' type='boolean' description='When source dataset is JPEG2000, whether to reuse the codestream of the source dataset unmodified' default='NO'/>"
 "</CreationOptionList>"  );
 
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
@@ -1930,4 +3577,3 @@ void GDALRegister_JP2OpenJPEG()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/ozi/GNUmakefile b/frmts/ozi/GNUmakefile
index d4b867d..f773ebf 100644
--- a/frmts/ozi/GNUmakefile
+++ b/frmts/ozi/GNUmakefile
@@ -9,7 +9,7 @@ else
 XTRA_OPT =
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(XTRA_OPT)
+CPPFLAGS	:=	 $(CPPFLAGS) $(XTRA_OPT)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/ozi/ozidataset.cpp b/frmts/ozi/ozidataset.cpp
index f2cb46a..f85be77 100644
--- a/frmts/ozi/ozidataset.cpp
+++ b/frmts/ozi/ozidataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ozidataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ozidataset.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:   OZF2 and OZFx3 binary files driver
  * Purpose:  GDALDataset driver for OZF2 and OZFx3 binary files.
@@ -32,7 +32,7 @@
 
 /* g++ -fPIC -g -Wall frmts/ozi/ozidataset.cpp -shared -o gdal_OZI.so -Iport -Igcore -Iogr -L. -lgdal  */
 
-CPL_CVSID("$Id: ozidataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ozidataset.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 CPL_C_START
 void    GDALRegister_OZI(void);
@@ -378,10 +378,6 @@ int OZIDataset::Identify( GDALOpenInfo * poOpenInfo )
     if (poOpenInfo->nHeaderBytes < 14)
         return FALSE;
 
-    if (EQUALN((const char*)poOpenInfo->pabyHeader,
-        "OziExplorer Map Data File Version ", 34) )
-        return TRUE;
-
     if (poOpenInfo->pabyHeader[0] == 0x80 &&
         poOpenInfo->pabyHeader[1] == 0x77)
         return TRUE;
@@ -601,7 +597,7 @@ GDALDataset *OZIDataset::Open( GDALOpenInfo * poOpenInfo )
         short nTileY = ReadShort(fp, bOzi3, nKeyInit);
         if (i == 0 && (nW != poDS->nRasterXSize || nH != poDS->nRasterYSize))
         {
-            CPLDebug("OZI", "zoom[%d] inconsistant dimensions for zoom level 0 : nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, nRasterYSize=%d",
+            CPLDebug("OZI", "zoom[%d] inconsistent dimensions for zoom level 0 : nW=%d, nH=%d, nTileX=%d, nTileY=%d, nRasterXSize=%d, nRasterYSize=%d",
                      i, nW, nH, nTileX, nTileY, poDS->nRasterXSize, poDS->nRasterYSize);
             delete poDS;
             return NULL;
@@ -683,6 +679,7 @@ void GDALRegister_OZI()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "OZI" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "OziExplorer Image File" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/pcidsk/GNUmakefile b/frmts/pcidsk/GNUmakefile
index ea255d3..644f54d 100644
--- a/frmts/pcidsk/GNUmakefile
+++ b/frmts/pcidsk/GNUmakefile
@@ -11,13 +11,13 @@ endif
 
 ifeq ($(PCIDSK_SETTING),old)
 OBJ	=	pcidskdataset.o pcidsktiledrasterband.o
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I../raw $(CPPFLAGS)
+CPPFLAGS	:=	 -I../raw $(CPPFLAGS)
 $(O_OBJ):	../raw/rawdataset.h gdal_pcidsk.h
 else
-OBJ	=	pcidskdataset2.o vsi_pcidsk_io.o gdal_edb.o $(SDKOBJ)
+OBJ	=	pcidskdataset2.o ogrpcidsklayer.o vsi_pcidsk_io.o gdal_edb.o $(SDKOBJ)
 ifeq ($(PCIDSK_SETTING),internal)
 CPPFLAGS	:=	$(JPEG_FLAGS) $(JPEG_INCLUDE) -DPCIDSK_INTERNAL \
-	-Isdk $(GDAL_INCLUDE) $(CPPFLAGS)
+	-Isdk  $(CPPFLAGS)
 
 SDKOBJ 	=	\
 	cbandinterleavedchannel.o \
@@ -59,7 +59,7 @@ SDKOBJ 	=	\
 	cpcidskads40model.o 
 
 else
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(PCIDSK_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(PCIDSK_INCLUDE) $(CPPFLAGS)
 endif
 endif
 
diff --git a/frmts/pcidsk/frmt_pcidsk.html b/frmts/pcidsk/frmt_pcidsk.html
index 311d177..9f87d17 100644
--- a/frmts/pcidsk/frmt_pcidsk.html
+++ b/frmts/pcidsk/frmt_pcidsk.html
@@ -23,7 +23,7 @@ RPC segments will be returned as GDAL style RPC metadata.<p>
 Internal overview (pyramid) images will also be correctly read though newly
 requested overviews will be built externally as an .ovr file.<p>
 
-Vector segments are supported by the OGR PCIDSK driver.<p>
+Starting with GDAL 2.0, vector segments are also supported by the driver.<p>
 
 <h2>Creation Options</h2>
 
diff --git a/frmts/pcidsk/gdal_edb.cpp b/frmts/pcidsk/gdal_edb.cpp
index 63cd6c9..214b0ec 100644
--- a/frmts/pcidsk/gdal_edb.cpp
+++ b/frmts/pcidsk/gdal_edb.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_edb.cpp 20632 2010-09-16 19:49:24Z rouault $
+ * $Id: gdal_edb.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  PCIDSK Database File
  * Purpose:  External Database access interface implementation (EDBFile).
@@ -32,7 +32,7 @@
 #include "gdal_priv.h"
 #include "pcidsk.h"
 
-CPL_CVSID("$Id: gdal_edb.cpp 20632 2010-09-16 19:49:24Z rouault $");
+CPL_CVSID("$Id: gdal_edb.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 using namespace PCIDSK;
 
@@ -236,7 +236,7 @@ int GDAL_EDBFile::ReadBlock( int channel,
                                     win_xsize, win_ysize, 
                                     buffer, win_xsize, win_ysize, 
                                     poBand->GetRasterDataType(),
-                                    nPixelOffset, nLineOffset );
+                                    nPixelOffset, nLineOffset, NULL );
 
     if( eErr != CE_None )
     {
@@ -291,7 +291,7 @@ int GDAL_EDBFile::WriteBlock( int channel, int block_index, void *buffer)
                                     nBlockY * nBlockYSize,
                                     nWinXSize, nWinYSize,
                                     buffer, nWinXSize, nWinYSize,
-                                    poBand->GetRasterDataType(), 0, 0 );
+                                    poBand->GetRasterDataType(), 0, 0, NULL );
 
     if( eErr != CE_None )
     {
diff --git a/frmts/pcidsk/makefile.vc b/frmts/pcidsk/makefile.vc
index c5cd3d9..1035661 100644
--- a/frmts/pcidsk/makefile.vc
+++ b/frmts/pcidsk/makefile.vc
@@ -10,13 +10,13 @@ OBJ		=	pcidskdataset.obj pcidsktiledrasterband.obj
 
 !IF "$(PCIDSK_SETTING)" == "EXTERNAL"
 PCIDSKFLAGS	=	$(PCIDSK_INCLUDE) 
-OBJ		=	pcidskdataset2.obj vsi_pcidsk_io.obj gdal_edb.obj
+OBJ		=	pcidskdataset2.obj ogrpcidsklayer.obj vsi_pcidsk_io.obj gdal_edb.obj
 !ENDIF
 
 !IF "$(PCIDSK_SETTING)" == "INTERNAL"
 PCIDSKFLAGS	=	-Isdk -DPCIDSK_INTERNAL -DHAVE_LIBJPEG 
 
-OBJ	=	pcidskdataset2.obj vsi_pcidsk_io.obj gdal_edb.obj \
+OBJ	=	pcidskdataset2.obj ogrpcidsklayer.obj vsi_pcidsk_io.obj gdal_edb.obj \
 	sdk\channel\cbandinterleavedchannel.obj \
 	sdk\channel\cpcidskchannel.obj \
 	sdk\channel\cpixelinterleavedchannel.obj \
diff --git a/frmts/pcidsk/ogrpcidsklayer.cpp b/frmts/pcidsk/ogrpcidsklayer.cpp
new file mode 100644
index 0000000..16a090f
--- /dev/null
+++ b/frmts/pcidsk/ogrpcidsklayer.cpp
@@ -0,0 +1,834 @@
+/******************************************************************************
+ * $Id: ogrcsvlayer.cpp 17496 2009-08-02 11:54:23Z rouault $
+ *
+ * Project:  PCIDSK Translator
+ * Purpose:  Implements OGRPCIDSKLayer class.
+ * Author:   Frank Warmerdam <warmerdam at pobox.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2009, Frank Warmerdam <warmerdam at pobox.com>
+ * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "pcidskdataset2.h"
+
+CPL_CVSID("$Id$");
+
+/************************************************************************/
+/*                           OGRPCIDSKLayer()                           */
+/************************************************************************/
+
+OGRPCIDSKLayer::OGRPCIDSKLayer( PCIDSK::PCIDSKSegment *poSegIn,
+                                bool bUpdate )
+
+{
+    poSRS = NULL;
+    bUpdateAccess = bUpdate;
+    poSeg = poSegIn;
+    poVecSeg = dynamic_cast<PCIDSK::PCIDSKVectorSegment*>( poSeg );
+
+    poFeatureDefn = new OGRFeatureDefn( poSeg->GetName().c_str() );
+    SetDescription( poFeatureDefn->GetName() );
+    poFeatureDefn->Reference();
+
+    hLastShapeId = PCIDSK::NullShapeId;
+
+/* -------------------------------------------------------------------- */
+/*      Attempt to assign a geometry type.                              */
+/* -------------------------------------------------------------------- */
+    try {
+        std::string osLayerType = poSeg->GetMetadataValue( "LAYER_TYPE" );
+        
+        if( osLayerType == "WHOLE_POLYGONS" )
+            poFeatureDefn->SetGeomType( wkbPolygon25D );
+        else if( osLayerType == "ARCS" || osLayerType == "TOPO_ARCS" )
+            poFeatureDefn->SetGeomType( wkbLineString25D );
+        else if( osLayerType == "POINTS" || osLayerType == "TOPO_NODES" )
+            poFeatureDefn->SetGeomType( wkbPoint25D );
+        else if( osLayerType == "TABLE" )
+            poFeatureDefn->SetGeomType( wkbNone );
+    } catch(...) {}
+
+
+/* -------------------------------------------------------------------- */
+/*      Build field definitions.                                        */
+/* -------------------------------------------------------------------- */
+    try
+    {
+        iRingStartField = -1;
+
+        for( int iField = 0; iField < poVecSeg->GetFieldCount(); iField++ )
+        {
+            OGRFieldDefn oField( poVecSeg->GetFieldName(iField).c_str(), OFTString);
+            
+            switch( poVecSeg->GetFieldType(iField) )
+            {
+              case PCIDSK::FieldTypeFloat:
+              case PCIDSK::FieldTypeDouble:
+                oField.SetType( OFTReal );
+                break;
+                
+              case PCIDSK::FieldTypeInteger:
+                oField.SetType( OFTInteger );
+                break;
+                
+              case PCIDSK::FieldTypeString:
+                oField.SetType( OFTString );
+                break;
+                
+              case PCIDSK::FieldTypeCountedInt:
+                oField.SetType( OFTIntegerList );
+                break;
+                
+              default:
+                CPLAssert( FALSE );
+                break;
+            }
+            
+            // we ought to try and extract some width/precision information
+            // from the format string at some point.
+            
+            // If the last field is named RingStart we treat it specially.
+            if( EQUAL(oField.GetNameRef(),"RingStart")
+                && oField.GetType() == OFTIntegerList 
+                && iField == poVecSeg->GetFieldCount()-1 )
+                iRingStartField = iField;
+            else
+                poFeatureDefn->AddFieldDefn( &oField );
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Look for a coordinate system.                                   */
+/* -------------------------------------------------------------------- */
+        CPLString osGeosys;
+        const char *pszUnits = NULL;
+        std::vector<double> adfParameters;
+
+        adfParameters = poVecSeg->GetProjection( osGeosys );
+
+        if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
+            == PCIDSK::UNIT_DEGREE )
+            pszUnits = "DEGREE";
+        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
+                 == PCIDSK::UNIT_METER )
+            pszUnits = "METER";
+        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
+                 == PCIDSK::UNIT_US_FOOT )
+            pszUnits = "FOOT";
+        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
+                 == PCIDSK::UNIT_INTL_FOOT )
+            pszUnits = "INTL FOOT";
+
+        poSRS = new OGRSpatialReference();
+
+        if( poSRS->importFromPCI( osGeosys, pszUnits, 
+                                  &(adfParameters[0]) ) != OGRERR_NONE )
+        {
+            delete poSRS;
+            poSRS = NULL;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Trap pcidsk exceptions.                                         */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() );
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." );
+    }
+    
+    if( poFeatureDefn->GetGeomFieldCount() > 0 )
+        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+}
+
+/************************************************************************/
+/*                          ~OGRPCIDSKLayer()                           */
+/************************************************************************/
+
+OGRPCIDSKLayer::~OGRPCIDSKLayer()
+
+{
+    if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
+    {
+        CPLDebug( "PCIDSK", "%d features read on layer '%s'.",
+                  (int) m_nFeaturesRead, 
+                  poFeatureDefn->GetName() );
+    }
+
+    poFeatureDefn->Release();
+
+    if (poSRS)
+        poSRS->Release();
+}
+
+/************************************************************************/
+/*                            ResetReading()                            */
+/************************************************************************/
+
+void OGRPCIDSKLayer::ResetReading()
+
+{
+    hLastShapeId = PCIDSK::NullShapeId;
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature *OGRPCIDSKLayer::GetNextFeature()
+
+{
+    OGRFeature  *poFeature = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Read features till we find one that satisfies our current       */
+/*      spatial criteria.                                               */
+/* -------------------------------------------------------------------- */
+    while( TRUE )
+    {
+        poFeature = GetNextUnfilteredFeature();
+        if( poFeature == NULL )
+            break;
+
+        if( (m_poFilterGeom == NULL
+            || FilterGeometry( poFeature->GetGeometryRef() ) )
+            && (m_poAttrQuery == NULL
+                || m_poAttrQuery->Evaluate( poFeature )) )
+            break;
+
+        delete poFeature;
+    }
+
+    return poFeature;
+}
+
+/************************************************************************/
+/*                      GetNextUnfilteredFeature()                      */
+/************************************************************************/
+
+OGRFeature * OGRPCIDSKLayer::GetNextUnfilteredFeature()
+
+{
+/* -------------------------------------------------------------------- */
+/*      Get the next shapeid.                                           */
+/* -------------------------------------------------------------------- */
+    if( hLastShapeId == PCIDSK::NullShapeId )
+        hLastShapeId = poVecSeg->FindFirst();
+    else
+        hLastShapeId = poVecSeg->FindNext( hLastShapeId );
+
+    if( hLastShapeId == PCIDSK::NullShapeId )
+        return NULL;
+
+    return GetFeature( hLastShapeId );
+}
+
+/************************************************************************/
+/*                             GetFeature()                             */
+/************************************************************************/
+
+OGRFeature *OGRPCIDSKLayer::GetFeature( GIntBig nFID )
+
+{
+/* -------------------------------------------------------------------- */
+/*      Create the OGR feature.                                         */
+/* -------------------------------------------------------------------- */
+    OGRFeature *poFeature;
+
+    poFeature = new OGRFeature( poFeatureDefn );
+    poFeature->SetFID( (int) nFID );
+
+/* -------------------------------------------------------------------- */
+/*      Set attributes for any indicated attribute records.             */
+/* -------------------------------------------------------------------- */
+    try {
+        std::vector<PCIDSK::ShapeField> aoFields;
+        unsigned int i;
+
+        poVecSeg->GetFields( (int) nFID, aoFields );
+        for( i=0; i < aoFields.size(); i++ )
+        {
+            if( (int) i == iRingStartField )
+                continue;
+
+            switch( aoFields[i].GetType() )
+            {
+              case PCIDSK::FieldTypeNone:
+                // null field value.
+                break;
+
+              case PCIDSK::FieldTypeInteger:
+                poFeature->SetField( i, aoFields[i].GetValueInteger() );
+                break;
+                                 
+              case PCIDSK::FieldTypeFloat:
+                poFeature->SetField( i, aoFields[i].GetValueFloat() );
+                break;
+                                 
+              case PCIDSK::FieldTypeDouble:
+                poFeature->SetField( i, aoFields[i].GetValueDouble() );
+                break;
+                                 
+              case PCIDSK::FieldTypeString:
+                poFeature->SetField( i, aoFields[i].GetValueString().c_str() );
+                break;
+                                 
+              case PCIDSK::FieldTypeCountedInt:
+                std::vector<PCIDSK::int32> list = aoFields[i].GetValueCountedInt();
+            
+                poFeature->SetField( i, list.size(), &(list[0]) );
+                break;
+            }
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Translate the geometry.                                         */
+/* -------------------------------------------------------------------- */
+        std::vector<PCIDSK::ShapeVertex> aoVertices;
+
+        poVecSeg->GetVertices( (int) nFID, aoVertices );
+
+/* -------------------------------------------------------------------- */
+/*      Point                                                           */
+/* -------------------------------------------------------------------- */
+        if( poFeatureDefn->GetGeomType() == wkbPoint25D 
+            || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown 
+                && aoVertices.size() == 1) )
+        {
+            if( aoVertices.size() == 1 )
+            {
+                OGRPoint* poPoint =
+                    new OGRPoint( aoVertices[0].x,
+                                  aoVertices[0].y, 
+                                  aoVertices[0].z );
+                if (poSRS)
+                    poPoint->assignSpatialReference(poSRS);
+                poFeature->SetGeometryDirectly(poPoint);
+            }
+            else
+            {
+                // report issue?
+            }
+        }    
+
+/* -------------------------------------------------------------------- */
+/*      LineString                                                      */
+/* -------------------------------------------------------------------- */
+        else if( poFeatureDefn->GetGeomType() == wkbLineString25D 
+                 || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown 
+                     && aoVertices.size() > 1) )
+        {
+            // We should likely be applying ringstart to break things into 
+            // a multilinestring in some cases.
+            if( aoVertices.size() > 1 )
+            {
+                OGRLineString *poLS = new OGRLineString();
+
+                poLS->setNumPoints( aoVertices.size() );
+            
+                for( i = 0; i < aoVertices.size(); i++ )
+                    poLS->setPoint( i,
+                                    aoVertices[i].x, 
+                                    aoVertices[i].y, 
+                                    aoVertices[i].z );
+                if (poSRS)
+                    poLS->assignSpatialReference(poSRS);
+
+                poFeature->SetGeometryDirectly( poLS );
+            }
+            else
+            {
+                // report issue?
+            }
+        }    
+
+/* -------------------------------------------------------------------- */
+/*      Polygon - Currently we have no way to recognise if we are       */
+/*      dealing with a multipolygon when we have more than one          */
+/*      ring.  Also, PCIDSK allows the rings to be in arbitrary         */
+/*      order, not necessarily outside first which we are not yet       */
+/*      ready to address in the following code.                         */
+/* -------------------------------------------------------------------- */
+        else if( poFeatureDefn->GetGeomType() == wkbPolygon25D )
+        {
+            std::vector<PCIDSK::int32> anRingStart;
+            OGRPolygon *poPoly = new OGRPolygon();
+            unsigned int iRing;
+
+            if( iRingStartField != -1 )
+                anRingStart = aoFields[iRingStartField].GetValueCountedInt();
+
+            for( iRing = 0; iRing < anRingStart.size()+1; iRing++ )
+            {
+                int iStartVertex, iEndVertex, iVertex;
+                OGRLinearRing *poRing = new OGRLinearRing();
+
+                if( iRing == 0 )
+                    iStartVertex = 0;
+                else
+                    iStartVertex = anRingStart[iRing-1];
+
+                if( iRing == anRingStart.size() )
+                    iEndVertex = aoVertices.size() - 1;
+                else
+                    iEndVertex = anRingStart[iRing] - 1;
+
+                poRing->setNumPoints( iEndVertex - iStartVertex + 1 );
+                for( iVertex = iStartVertex; iVertex <= iEndVertex; iVertex++ )
+                {
+                    poRing->setPoint( iVertex - iStartVertex,
+                                      aoVertices[iVertex].x, 
+                                      aoVertices[iVertex].y, 
+                                      aoVertices[iVertex].z );
+                }
+
+                poPoly->addRingDirectly( poRing );
+            }
+
+            if (poSRS)
+                poPoly->assignSpatialReference(poSRS);
+
+            poFeature->SetGeometryDirectly( poPoly );
+        }    
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Trap exceptions and report as CPL errors.                       */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        delete poFeature;
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "%s", ex.what() );
+        return NULL;
+    }
+    catch(...)
+    {
+        delete poFeature;
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped." );
+        return NULL;
+    }
+
+    m_nFeaturesRead++;
+
+    return poFeature;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRPCIDSKLayer::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,OLCRandomRead) )
+        return TRUE;
+
+    else if( EQUAL(pszCap,OLCFastFeatureCount) )
+        return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
+
+    else if( EQUAL(pszCap,OLCSequentialWrite) 
+             || EQUAL(pszCap,OLCRandomWrite) )
+        return bUpdateAccess;
+
+    else if( EQUAL(pszCap,OLCDeleteFeature) )
+        return bUpdateAccess;
+
+    else if( EQUAL(pszCap,OLCCreateField) )
+        return bUpdateAccess;
+
+    else 
+        return FALSE;
+}
+
+/************************************************************************/
+/*                         GetFeatureCount()                          */
+/************************************************************************/
+
+GIntBig OGRPCIDSKLayer::GetFeatureCount( int bForce )
+
+{
+    if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
+        return OGRLayer::GetFeatureCount( bForce );
+    else
+    {
+        try {
+            return poVecSeg->GetShapeCount();
+        } catch(...) {
+            return 0;
+        }
+    }
+}
+
+/************************************************************************/
+/*                             GetExtent()                              */
+/************************************************************************/
+
+OGRErr OGRPCIDSKLayer::GetExtent (OGREnvelope *psExtent, int bForce)
+
+{
+    if( !bForce )
+        return OGRERR_FAILURE;
+    
+/* -------------------------------------------------------------------- */
+/*      Loop over all features, but just read the geometry.  This is    */
+/*      a fair amount quicker than actually processing all the          */
+/*      attributes, forming features and then exaimining the            */
+/*      geometries as the default implemntation would do.               */
+/* -------------------------------------------------------------------- */
+    try
+    {
+        bool bHaveExtent = FALSE;
+
+        std::vector<PCIDSK::ShapeVertex> asVertices;
+
+        for( PCIDSK::ShapeIterator oIt = poVecSeg->begin(); 
+             oIt != poVecSeg->end();
+             oIt++ )
+        {
+            unsigned int i;
+
+            poVecSeg->GetVertices( *oIt, asVertices );
+
+            for( i = 0; i < asVertices.size(); i++ )
+            {
+                if( !bHaveExtent )
+                {
+                    psExtent->MinX = psExtent->MaxX = asVertices[i].x;
+                    psExtent->MinY = psExtent->MaxY = asVertices[i].y;
+                    bHaveExtent = true;
+                }
+                else
+                {
+                    psExtent->MinX = MIN(psExtent->MinX,asVertices[i].x);
+                    psExtent->MaxX = MAX(psExtent->MaxX,asVertices[i].x);
+                    psExtent->MinY = MIN(psExtent->MinY,asVertices[i].y);
+                    psExtent->MaxY = MAX(psExtent->MaxY,asVertices[i].y);
+                }
+            }
+        }
+
+        if( bHaveExtent )
+            return OGRERR_NONE;
+        else
+            return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Trap pcidsk exceptions.                                         */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() );
+        return OGRERR_FAILURE;
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." );
+        return OGRERR_FAILURE;
+    }
+}
+
+/************************************************************************/
+/*                           DeleteFeature()                            */
+/************************************************************************/
+
+OGRErr OGRPCIDSKLayer::DeleteFeature( GIntBig nFID )
+
+{
+    try {
+
+        poVecSeg->DeleteShape( (PCIDSK::ShapeId) nFID );
+
+        return OGRERR_NONE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Trap exceptions and report as CPL errors.                       */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "%s", ex.what() );
+        return OGRERR_FAILURE;
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped." );
+        return OGRERR_FAILURE;
+    }
+}
+
+/************************************************************************/
+/*                          ICreateFeature()                            */
+/************************************************************************/
+
+OGRErr OGRPCIDSKLayer::ICreateFeature( OGRFeature *poFeature )
+
+{
+    try {
+
+        PCIDSK::ShapeId id = poVecSeg->CreateShape( 
+            (PCIDSK::ShapeId) poFeature->GetFID() );
+
+        poFeature->SetFID( (long) id );
+
+        return SetFeature( poFeature );
+    }
+/* -------------------------------------------------------------------- */
+/*      Trap exceptions and report as CPL errors.                       */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "%s", ex.what() );
+        return OGRERR_FAILURE;
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped." );
+        return OGRERR_FAILURE;
+    }
+    
+}
+
+/************************************************************************/
+/*                            ISetFeature()                             */
+/************************************************************************/
+
+OGRErr OGRPCIDSKLayer::ISetFeature( OGRFeature *poFeature )
+
+{
+    PCIDSK::ShapeId id = (PCIDSK::ShapeId) poFeature->GetFID();
+    
+/* -------------------------------------------------------------------- */
+/*      Translate attribute fields.                                     */
+/* -------------------------------------------------------------------- */
+    try {
+
+        int iPCI;
+        std::vector<PCIDSK::ShapeField>  aoPCIFields;
+
+        aoPCIFields.resize(poVecSeg->GetFieldCount());
+
+        for( iPCI = 0; iPCI < poVecSeg->GetFieldCount(); iPCI++ )
+        {
+            int iOGR;
+
+            iOGR = poFeatureDefn->GetFieldIndex(
+                poVecSeg->GetFieldName(iPCI).c_str() );
+
+            if( iOGR == -1 )
+                continue;
+
+            switch( poVecSeg->GetFieldType(iPCI) )
+            {
+              case PCIDSK::FieldTypeInteger:
+                aoPCIFields[iPCI].SetValue(
+                    poFeature->GetFieldAsInteger( iOGR ) );
+                break;
+
+              case PCIDSK::FieldTypeFloat:
+                aoPCIFields[iPCI].SetValue(
+                    (float) poFeature->GetFieldAsDouble( iOGR ) );
+                break;
+
+              case PCIDSK::FieldTypeDouble:
+                aoPCIFields[iPCI].SetValue(
+                    (double) poFeature->GetFieldAsDouble( iOGR ) );
+                break;
+
+              case PCIDSK::FieldTypeString:
+                aoPCIFields[iPCI].SetValue(
+                    poFeature->GetFieldAsString( iOGR ) );
+                break;
+
+              case PCIDSK::FieldTypeCountedInt:
+              {
+                  int nCount;
+                  const int *panList = 
+                      poFeature->GetFieldAsIntegerList( iOGR, &nCount );
+                  std::vector<PCIDSK::int32> anList;
+                  
+                  anList.resize( nCount );
+                  memcpy( &(anList[0]), panList, 4 * anList.size() );
+                  aoPCIFields[iPCI].SetValue( anList );
+              }
+              break;
+
+              default:
+                CPLAssert( FALSE );
+                break;
+            }
+        }
+
+        if( poVecSeg->GetFieldCount() > 0 )
+            poVecSeg->SetFields( id, aoPCIFields );
+
+/* -------------------------------------------------------------------- */
+/*      Translate the geometry.                                         */
+/* -------------------------------------------------------------------- */
+        std::vector<PCIDSK::ShapeVertex> aoVertices;
+        OGRGeometry *poGeometry = poFeature->GetGeometryRef();
+
+        if( poGeometry == NULL )
+        {
+        }
+
+        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
+        {
+            OGRPoint *poPoint = (OGRPoint *) poGeometry;
+
+            aoVertices.resize(1);
+            aoVertices[0].x = poPoint->getX();
+            aoVertices[0].y = poPoint->getY();
+            aoVertices[0].z = poPoint->getZ();
+        }
+
+        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbLineString )
+        {
+            OGRLineString *poLS = (OGRLineString *) poGeometry;
+            unsigned int i;
+
+            aoVertices.resize(poLS->getNumPoints());
+
+            for( i = 0; i < aoVertices.size(); i++ )
+            {
+                aoVertices[i].x = poLS->getX(i);
+                aoVertices[i].y = poLS->getY(i);
+                aoVertices[i].z = poLS->getZ(i);
+            }
+        }
+
+        else
+        {
+            CPLDebug( "PCIDSK", "Unsupported geometry type in SetFeature(): %s",
+                      poGeometry->getGeometryName() );
+        }
+
+        poVecSeg->SetVertices( id, aoVertices );
+
+    } /* try */
+
+/* -------------------------------------------------------------------- */
+/*      Trap exceptions and report as CPL errors.                       */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "%s", ex.what() );
+        return OGRERR_FAILURE;
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped." );
+        return OGRERR_FAILURE;
+    }
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            CreateField()                             */
+/************************************************************************/
+
+OGRErr OGRPCIDSKLayer::CreateField( OGRFieldDefn *poFieldDefn,
+                                    int bApproxOK )
+
+{
+    try {
+        
+        if( poFieldDefn->GetType() == OFTInteger )
+        {
+            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
+                                PCIDSK::FieldTypeInteger, 
+                                "", "" );
+            poFeatureDefn->AddFieldDefn( poFieldDefn );
+        }
+        else if( poFieldDefn->GetType() == OFTReal )
+        {
+            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
+                                PCIDSK::FieldTypeDouble, 
+                                "", "" );
+            poFeatureDefn->AddFieldDefn( poFieldDefn );
+        }
+        else if( poFieldDefn->GetType() == OFTString )
+        {
+            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
+                                PCIDSK::FieldTypeString, 
+                                "", "" );
+            poFeatureDefn->AddFieldDefn( poFieldDefn );
+        }
+        else if( poFieldDefn->GetType() == OFTIntegerList )
+        {
+            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
+                                PCIDSK::FieldTypeCountedInt, 
+                                "", "" );
+            poFeatureDefn->AddFieldDefn( poFieldDefn );
+        }
+        else if( bApproxOK )
+        {
+            // Fallback to treating everything else as a string field.
+            OGRFieldDefn oModFieldDefn(poFieldDefn);
+            oModFieldDefn.SetType( OFTString );
+            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
+                                PCIDSK::FieldTypeString, 
+                                "", "" );
+            poFeatureDefn->AddFieldDefn( &oModFieldDefn );
+        }
+        else
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to create field '%s' of unsupported data type.",
+                      poFieldDefn->GetNameRef() );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Trap exceptions and report as CPL errors.                       */
+/* -------------------------------------------------------------------- */
+    catch( PCIDSK::PCIDSKException ex )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "%s", ex.what() );
+        return OGRERR_FAILURE;
+    }
+    catch(...)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Non-PCIDSK exception trapped." );
+        return OGRERR_FAILURE;
+    }
+
+    return OGRERR_NONE;
+}
diff --git a/frmts/pcidsk/pcidskdataset.cpp b/frmts/pcidsk/pcidskdataset.cpp
index f028ff3..85d24df 100644
--- a/frmts/pcidsk/pcidskdataset.cpp
+++ b/frmts/pcidsk/pcidskdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pcidskdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pcidskdataset.cpp 28373 2015-01-30 00:14:24Z rouault $
  *
  * Project:  PCIDSK Database File
  * Purpose:  Read/write PCIDSK Database File used by the PCI software
@@ -30,7 +30,7 @@
 
 #include "gdal_pcidsk.h"
 
-CPL_CVSID("$Id: pcidskdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pcidskdataset.cpp 28373 2015-01-30 00:14:24Z rouault $");
 
 CPL_C_START
 void    GDALRegister_PCIDSK(void);
@@ -1446,16 +1446,17 @@ GDALDataset *PCIDSKDataset::Create( const char * pszFilename,
 }
 
 
-
 /************************************************************************/
 /*                             CreateCopy()                             */
 /************************************************************************/
 
 GDALDataset *
-PCIDSKDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                        int bStrict, char ** papszOptions, 
-                        GDALProgressFunc pfnProgress, void * pProgressData )
-
+PCIDSKDataset::CreateCopy( const char * pszFilename,
+                           GDALDataset *poSrcDS,
+                           CPL_UNUSED int bStrict,
+                           char ** papszOptions,
+                           GDALProgressFunc pfnProgress,
+                           void * pProgressData )
 {
     PCIDSKDataset	*poDS;
     GDALDataType eType;
@@ -1544,7 +1545,7 @@ PCIDSKDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
                 if( eErr != CE_None )
                 {
                     return NULL;
@@ -1554,7 +1555,7 @@ PCIDSKDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
 
                 if( eErr != CE_None )
                 {
@@ -1617,6 +1618,7 @@ void GDALRegister_PCIDSK()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "PCIDSK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "PCIDSK Database File" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/pcidsk/pcidskdataset2.cpp b/frmts/pcidsk/pcidskdataset2.cpp
index a33ba70..4c83a62 100644
--- a/frmts/pcidsk/pcidskdataset2.cpp
+++ b/frmts/pcidsk/pcidskdataset2.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pcidskdataset2.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pcidskdataset2.cpp 28292 2015-01-05 19:35:55Z rouault $
  *
  * Project:  PCIDSK Database File
  * Purpose:  Read/write PCIDSK Database File used by the PCI software, using
@@ -29,119 +29,13 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-#include "pcidsk.h"
-#include "pcidsk_pct.h"
-#include "gdal_pam.h"
-#include "cpl_string.h"
-#include "ogr_spatialref.h"
+#include "pcidskdataset2.h"
 
-CPL_CVSID("$Id: pcidskdataset2.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-using namespace PCIDSK;
+CPL_CVSID("$Id: pcidskdataset2.cpp 28292 2015-01-05 19:35:55Z rouault $");
 
 const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
 
 /************************************************************************/
-/*                              PCIDSK2Dataset                           */
-/************************************************************************/
-
-class PCIDSK2Dataset : public GDALPamDataset
-{
-    friend class PCIDSK2Band;
-
-    CPLString   osSRS;
-    CPLString   osLastMDValue;
-    char      **papszLastMDListValue;
-
-    PCIDSKFile  *poFile;
-
-    static GDALDataType  PCIDSKTypeToGDAL( eChanType eType );
-    void                 ProcessRPC();
-
-  public:
-                PCIDSK2Dataset();
-                ~PCIDSK2Dataset();
-
-    static int           Identify( GDALOpenInfo * );
-    static GDALDataset  *Open( GDALOpenInfo * );
-    static GDALDataset  *LLOpen( const char *pszFilename, PCIDSK::PCIDSKFile *,
-                                 GDALAccess eAccess );
-    static GDALDataset  *Create( const char * pszFilename,
-                                 int nXSize, int nYSize, int nBands,
-                                 GDALDataType eType,
-                                 char **papszParmList );
-
-    char              **GetFileList(void);
-    CPLErr              GetGeoTransform( double * padfTransform );
-    CPLErr              SetGeoTransform( double * );
-    const char         *GetProjectionRef();
-    CPLErr              SetProjection( const char * );
-
-    virtual char      **GetMetadataDomainList();
-    CPLErr              SetMetadata( char **, const char * );
-    char              **GetMetadata( const char* );
-    CPLErr              SetMetadataItem(const char*,const char*,const char*);
-    const char         *GetMetadataItem( const char*, const char*);
-
-    virtual void FlushCache(void);
-
-    virtual CPLErr IBuildOverviews( const char *, int, int *,
-                                    int, int *, GDALProgressFunc, void * );
-};
-
-/************************************************************************/
-/*                             PCIDSK2Band                              */
-/************************************************************************/
-
-class PCIDSK2Band : public GDALPamRasterBand
-{
-    friend class PCIDSK2Dataset;
-
-    PCIDSKChannel *poChannel;
-    PCIDSKFile    *poFile;
-
-    void        RefreshOverviewList();
-    std::vector<PCIDSK2Band*> apoOverviews;
-    
-    CPLString   osLastMDValue;
-    char      **papszLastMDListValue;
-
-    bool        CheckForColorTable();
-    GDALColorTable *poColorTable;
-    bool        bCheckedForColorTable;
-    int         nPCTSegNumber;
-
-    char      **papszCategoryNames;
-
-    void        Initialize();
-
-  public:
-                PCIDSK2Band( PCIDSK2Dataset *, PCIDSKFile *, int );
-                PCIDSK2Band( PCIDSKChannel * );
-                ~PCIDSK2Band();
-
-    virtual CPLErr IReadBlock( int, int, void * );
-    virtual CPLErr IWriteBlock( int, int, void * );
-
-    virtual int        GetOverviewCount();
-    virtual GDALRasterBand *GetOverview(int);
-
-    virtual GDALColorInterp GetColorInterpretation();
-    virtual GDALColorTable *GetColorTable();
-    virtual CPLErr SetColorTable( GDALColorTable * ); 
-
-    virtual void        SetDescription( const char * );
-
-    virtual char      **GetMetadataDomainList();
-    CPLErr              SetMetadata( char **, const char * );
-    char              **GetMetadata( const char* );
-    CPLErr              SetMetadataItem(const char*,const char*,const char*);
-    const char         *GetMetadataItem( const char*, const char*);
-
-    virtual char      **GetCategoryNames();
-};
-
-/************************************************************************/
 /* ==================================================================== */
 /*                            PCIDSK2Band                               */
 /* ==================================================================== */
@@ -900,6 +794,12 @@ PCIDSK2Dataset::~PCIDSK2Dataset()
 {
     FlushCache();
 
+    while( apoLayers.size() > 0 )
+    {
+        delete apoLayers.back();
+        apoLayers.pop_back();
+    }
+
     try {
         delete poFile;
         poFile = NULL;
@@ -1592,12 +1492,15 @@ CPLErr PCIDSK2Dataset::IBuildOverviews( const char *pszResampling,
             int    nOvFactor;
             GDALRasterBand * poOverview = poBand->GetOverview( j );
  
-            nOvFactor = (int) 
-                (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+            nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                            poBand->GetXSize(),
+                                            poOverview->GetYSize(),
+                                            poBand->GetYSize());
 
             if( nOvFactor == panOverviewList[i] 
-                || nOvFactor == GDALOvLevelAdjust( panOverviewList[i], 
-                                                   poBand->GetXSize() ) )
+                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], 
+                                                    poBand->GetXSize(), 
+                                                    poBand->GetYSize() ) )
                 panOverviewList[i] *= -1;
         }
 
@@ -1662,12 +1565,15 @@ CPLErr PCIDSK2Dataset::IBuildOverviews( const char *pszResampling,
                 int    nOvFactor;
                 GDALRasterBand * poOverview = poBand->GetOverview( j );
 
-                nOvFactor = (int) 
-                    (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+                nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                            poBand->GetXSize(),
+                                            poOverview->GetYSize(),
+                                            poBand->GetYSize());
 
                 if( nOvFactor == panOverviewList[i] 
-                    || nOvFactor == GDALOvLevelAdjust( panOverviewList[i], 
-                                                       poBand->GetXSize() ) )
+                    || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], 
+                                                       poBand->GetXSize(), 
+                                                       poBand->GetYSize() ) )
                 {
                     papoOverviewBands[nNewOverviews++] = poOverview;
                     anRegenLevels.push_back( j );
@@ -1771,15 +1677,34 @@ GDALDataset *PCIDSK2Dataset::Open( GDALOpenInfo * poOpenInfo )
             return NULL;
         }
 
-        /* Check if this is a vector-only PCIDSK file */
-        if( poFile->GetChannels() == 0 &&
+        /* Check if this is a vector-only PCIDSK file and that we are */
+        /* opened in raster-only mode */
+        if( poOpenInfo->eAccess == GA_ReadOnly &&
+            (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) != 0 &&
+            (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) == 0 &&
+            poFile->GetChannels() == 0 &&
             poFile->GetSegment( PCIDSK::SEG_VEC, "" ) != NULL )
         {
+            CPLDebug("PCIDSK", "This is a vector-only PCIDSK dataset, "
+                     "but it has been opened in read-only in raster-only mode");
+            delete poFile;
+            return NULL;
+        }
+        /* Reverse test */
+        if( poOpenInfo->eAccess == GA_ReadOnly &&
+            (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+            (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
+            poFile->GetChannels() != 0 &&
+            poFile->GetSegment( PCIDSK::SEG_VEC, "" ) == NULL )
+        {
+            CPLDebug("PCIDSK", "This is a raster-only PCIDSK dataset, "
+                     "but it has been opened in read-only in vector-only mode");
             delete poFile;
             return NULL;
         }
 
-        return LLOpen( poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess );
+        return LLOpen( poOpenInfo->pszFilename, poFile, poOpenInfo->eAccess,
+                       poOpenInfo->GetSiblingFiles() );
     }
 /* -------------------------------------------------------------------- */
 /*      Trap exceptions.                                                */
@@ -1807,14 +1732,15 @@ GDALDataset *PCIDSK2Dataset::Open( GDALOpenInfo * poOpenInfo )
 
 GDALDataset *PCIDSK2Dataset::LLOpen( const char *pszFilename, 
                                      PCIDSK::PCIDSKFile *poFile,
-                                     GDALAccess eAccess )
+                                     GDALAccess eAccess,
+                                     char** papszSiblingFiles )
 
 {
+    PCIDSK2Dataset   *poDS = NULL;
     try {
 /* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
 /* -------------------------------------------------------------------- */
-        PCIDSK2Dataset   *poDS = NULL;
 
         poDS = new PCIDSK2Dataset();
 
@@ -1879,6 +1805,18 @@ GDALDataset *PCIDSK2Dataset::LLOpen( const char *pszFilename,
         }
 
 /* -------------------------------------------------------------------- */
+/*      Create vector layers from vector segments.                      */
+/* -------------------------------------------------------------------- */
+        PCIDSK::PCIDSKSegment *segobj;
+        for( segobj = poFile->GetSegment( PCIDSK::SEG_VEC, "" );
+             segobj != NULL;
+             segobj = poFile->GetSegment( PCIDSK::SEG_VEC, "",
+                                          segobj->GetSegmentNumber() ) )
+        {
+            poDS->apoLayers.push_back( new OGRPCIDSKLayer( segobj, eAccess == GA_Update ) );
+        }
+
+/* -------------------------------------------------------------------- */
 /*      Process RPC segment, if there is one.                           */
 /* -------------------------------------------------------------------- */
         poDS->ProcessRPC();
@@ -1887,12 +1825,12 @@ GDALDataset *PCIDSK2Dataset::LLOpen( const char *pszFilename,
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
         poDS->SetDescription( pszFilename );
-        poDS->TryLoadXML();
+        poDS->TryLoadXML( papszSiblingFiles );
 
 /* -------------------------------------------------------------------- */
 /*      Open overviews.                                                 */
 /* -------------------------------------------------------------------- */
-        poDS->oOvManager.Initialize( poDS, pszFilename );
+        poDS->oOvManager.Initialize( poDS, pszFilename, papszSiblingFiles );
         
         return( poDS );
     }
@@ -1911,6 +1849,11 @@ GDALDataset *PCIDSK2Dataset::LLOpen( const char *pszFilename,
                   "PCIDSK SDK Failure in Open(), unexpected exception." );
     }
 
+/* -------------------------------------------------------------------- */
+/*      In case of exception, close dataset                             */
+/* -------------------------------------------------------------------- */
+    delete poDS;
+
     return NULL;
 }
 
@@ -1975,6 +1918,8 @@ GDALDataset *PCIDSK2Dataset::Create( const char * pszFilename,
 /*      Try creation.                                                   */
 /* -------------------------------------------------------------------- */
     try {
+        if( nBands == 0 )
+            nXSize = nYSize = 512;
         poFile = PCIDSK::Create( pszFilename, nXSize, nYSize, nBands, 
                                  &(aeChanTypes[0]), osOptions, 
                                  PCIDSK2GetInterfaces() );
@@ -2017,6 +1962,147 @@ GDALDataset *PCIDSK2Dataset::Create( const char * pszFilename,
 }
 
 /************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int PCIDSK2Dataset::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,ODsCCreateLayer) )
+        return eAccess == GA_Update;
+    else
+        return FALSE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *PCIDSK2Dataset::GetLayer( int iLayer )
+
+{
+    if( iLayer < 0 || iLayer >= (int) apoLayers.size() )
+        return NULL;
+    else
+        return apoLayers[iLayer];
+}
+
+/************************************************************************/
+/*                           ICreateLayer()                             */
+/************************************************************************/
+
+OGRLayer *
+PCIDSK2Dataset::ICreateLayer( const char * pszLayerName,
+                              OGRSpatialReference *poSRS,
+                              OGRwkbGeometryType eType,
+                              CPL_UNUSED char ** papszOptions )
+{
+/* -------------------------------------------------------------------- */
+/*      Verify we are in update mode.                                   */
+/* -------------------------------------------------------------------- */
+    if( eAccess != GA_Update )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+                  "Data source %s opened read-only.\n"
+                  "New layer %s cannot be created.\n",
+                  GetDescription(), pszLayerName );
+        
+        return NULL;
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Figure out what type of layer we need.                          */
+/* -------------------------------------------------------------------- */
+    std::string osLayerType;
+
+    switch( wkbFlatten(eType) )
+    {
+      case wkbPoint:
+        osLayerType = "POINTS";
+        break;
+    
+      case wkbLineString:
+        osLayerType = "ARCS";
+        break;
+
+      case wkbPolygon:
+        osLayerType = "WHOLE_POLYGONS";
+        break;
+        
+      case wkbNone:
+        osLayerType = "TABLE";
+        break;
+
+      default:
+        break;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create the segment.                                             */
+/* -------------------------------------------------------------------- */
+    int     nSegNum = poFile->CreateSegment( pszLayerName, "", 
+                                             PCIDSK::SEG_VEC, 0L );
+    PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment( nSegNum );
+    PCIDSK::PCIDSKVectorSegment *poVecSeg = 
+        dynamic_cast<PCIDSK::PCIDSKVectorSegment*>( poSeg );
+
+    if( osLayerType != "" )
+        poSeg->SetMetadataValue( "LAYER_TYPE", osLayerType );
+
+/* -------------------------------------------------------------------- */
+/*      Do we need to apply a coordinate system?                        */
+/* -------------------------------------------------------------------- */
+    char *pszGeosys = NULL;
+    char *pszUnits = NULL;
+    double *padfPrjParams = NULL;
+
+    if( poSRS != NULL 
+        && poSRS->exportToPCI( &pszGeosys, &pszUnits, 
+                               &padfPrjParams ) == OGRERR_NONE )
+    {
+        try
+        {
+            std::vector<double> adfPCIParameters;
+            int i;
+
+            for( i = 0; i < 17; i++ )
+                adfPCIParameters.push_back( padfPrjParams[i] );
+            
+            if( EQUALN(pszUnits,"FOOT",4) )
+                adfPCIParameters.push_back( 
+                    (double)(int) PCIDSK::UNIT_US_FOOT );
+            else if( EQUALN(pszUnits,"INTL FOOT",9) )
+                adfPCIParameters.push_back( 
+                    (double)(int) PCIDSK::UNIT_INTL_FOOT );
+            else if( EQUALN(pszUnits,"DEGREE",6) )
+                adfPCIParameters.push_back( 
+                    (double)(int) PCIDSK::UNIT_DEGREE );
+            else 
+                adfPCIParameters.push_back( 
+                    (double)(int) PCIDSK::UNIT_METER );
+            
+            poVecSeg->SetProjection( pszGeosys, adfPCIParameters );
+        }
+        catch( PCIDSK::PCIDSKException ex )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s", ex.what() );
+        }
+        
+        CPLFree( pszGeosys );
+        CPLFree( pszUnits );
+        CPLFree( padfPrjParams );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create the layer object.                                        */
+/* -------------------------------------------------------------------- */
+    apoLayers.push_back( new OGRPCIDSKLayer( poSeg, TRUE ) );
+
+    return apoLayers[apoLayers.size()-1];
+}
+
+/************************************************************************/
 /*                        GDALRegister_PCIDSK()                         */
 /************************************************************************/
 
@@ -2030,6 +2116,8 @@ void GDALRegister_PCIDSK()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "PCIDSK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "PCIDSK Database File" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -2052,6 +2140,7 @@ void GDALRegister_PCIDSK()
 "   </Option>"
 "   <Option name='TILESIZE' type='int' default='127' description='Tile Size (INTERLEAVING=TILED only)'/>"
 "</CreationOptionList>" ); 
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>" );
 
         poDriver->pfnIdentify = PCIDSK2Dataset::Identify;
         poDriver->pfnOpen = PCIDSK2Dataset::Open;
@@ -2060,5 +2149,3 @@ void GDALRegister_PCIDSK()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
-
diff --git a/frmts/pcidsk/pcidskdataset2.h b/frmts/pcidsk/pcidskdataset2.h
new file mode 100644
index 0000000..7d59927
--- /dev/null
+++ b/frmts/pcidsk/pcidskdataset2.h
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  PCIDSK Database File
+ * Purpose:  Read/write PCIDSK Database File used by the PCI software, using
+ *           the external PCIDSK library.
+ * Author:   Frank Warmerdam, warmerdam at pobox.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2009, Frank Warmerdam <warmerdam at pobox.com>
+ * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef PCIDSKDATASET2_H_INCLUDED
+#define PCIDSKDATASET2_H_INCLUDED
+
+#define GDAL_PCIDSK_DRIVER
+
+#include "pcidsk.h"
+#include "pcidsk_pct.h"
+#include "ogrsf_frmts.h"
+#include "pcidsk_vectorsegment.h"
+#include "gdal_pam.h"
+#include "cpl_string.h"
+#include "ogr_spatialref.h"
+
+using namespace PCIDSK;
+
+class OGRPCIDSKLayer;
+
+/************************************************************************/
+/*                              PCIDSK2Dataset                           */
+/************************************************************************/
+
+class PCIDSK2Dataset : public GDALPamDataset
+{
+    friend class PCIDSK2Band;
+
+    CPLString   osSRS;
+    CPLString   osLastMDValue;
+    char      **papszLastMDListValue;
+
+    PCIDSKFile  *poFile;
+
+    std::vector<OGRPCIDSKLayer*> apoLayers;
+
+    static GDALDataType  PCIDSKTypeToGDAL( eChanType eType );
+    void                 ProcessRPC();
+
+  public:
+                PCIDSK2Dataset();
+                ~PCIDSK2Dataset();
+
+    static int           Identify( GDALOpenInfo * );
+    static GDALDataset  *Open( GDALOpenInfo * );
+    static GDALDataset  *LLOpen( const char *pszFilename, PCIDSK::PCIDSKFile *,
+                                 GDALAccess eAccess,
+                                 char** papszSiblingFiles = NULL );
+    static GDALDataset  *Create( const char * pszFilename,
+                                 int nXSize, int nYSize, int nBands,
+                                 GDALDataType eType,
+                                 char **papszParmList );
+
+    char              **GetFileList(void);
+    CPLErr              GetGeoTransform( double * padfTransform );
+    CPLErr              SetGeoTransform( double * );
+    const char         *GetProjectionRef();
+    CPLErr              SetProjection( const char * );
+
+    virtual char      **GetMetadataDomainList();
+    CPLErr              SetMetadata( char **, const char * );
+    char              **GetMetadata( const char* );
+    CPLErr              SetMetadataItem(const char*,const char*,const char*);
+    const char         *GetMetadataItem( const char*, const char*);
+
+    virtual void FlushCache(void);
+
+    virtual CPLErr IBuildOverviews( const char *, int, int *,
+                                    int, int *, GDALProgressFunc, void * );
+
+    virtual int                 GetLayerCount() { return (int) apoLayers.size(); }
+    virtual OGRLayer            *GetLayer( int );
+
+    virtual int                 TestCapability( const char * );
+
+    virtual OGRLayer           *ICreateLayer( const char *, OGRSpatialReference *,
+                                     OGRwkbGeometryType, char ** );
+};
+
+/************************************************************************/
+/*                             PCIDSK2Band                              */
+/************************************************************************/
+
+class PCIDSK2Band : public GDALPamRasterBand
+{
+    friend class PCIDSK2Dataset;
+
+    PCIDSKChannel *poChannel;
+    PCIDSKFile    *poFile;
+
+    void        RefreshOverviewList();
+    std::vector<PCIDSK2Band*> apoOverviews;
+    
+    CPLString   osLastMDValue;
+    char      **papszLastMDListValue;
+
+    bool        CheckForColorTable();
+    GDALColorTable *poColorTable;
+    bool        bCheckedForColorTable;
+    int         nPCTSegNumber;
+
+    char      **papszCategoryNames;
+
+    void        Initialize();
+
+  public:
+                PCIDSK2Band( PCIDSK2Dataset *, PCIDSKFile *, int );
+                PCIDSK2Band( PCIDSKChannel * );
+                ~PCIDSK2Band();
+
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual CPLErr IWriteBlock( int, int, void * );
+
+    virtual int        GetOverviewCount();
+    virtual GDALRasterBand *GetOverview(int);
+
+    virtual GDALColorInterp GetColorInterpretation();
+    virtual GDALColorTable *GetColorTable();
+    virtual CPLErr SetColorTable( GDALColorTable * ); 
+
+    virtual void        SetDescription( const char * );
+
+    virtual char      **GetMetadataDomainList();
+    CPLErr              SetMetadata( char **, const char * );
+    char              **GetMetadata( const char* );
+    CPLErr              SetMetadataItem(const char*,const char*,const char*);
+    const char         *GetMetadataItem( const char*, const char*);
+
+    virtual char      **GetCategoryNames();
+};
+
+/************************************************************************/
+/*                             OGRPCIDSKLayer                              */
+/************************************************************************/
+
+class OGRPCIDSKLayer : public OGRLayer
+{
+    PCIDSK::PCIDSKVectorSegment *poVecSeg;
+    PCIDSK::PCIDSKSegment       *poSeg;
+
+    OGRFeatureDefn     *poFeatureDefn;
+
+    OGRFeature *        GetNextUnfilteredFeature();
+
+    int                 iRingStartField;
+    PCIDSK::ShapeId     hLastShapeId;
+
+    bool                bUpdateAccess;
+
+    OGRSpatialReference *poSRS;
+
+  public:
+    OGRPCIDSKLayer( PCIDSK::PCIDSKSegment*, bool bUpdate );
+    ~OGRPCIDSKLayer();
+
+    void                ResetReading();
+    OGRFeature *        GetNextFeature();
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+
+    OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
+
+    int                 TestCapability( const char * );
+
+    OGRErr              DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      CreateField( OGRFieldDefn *poField,
+                                     int bApproxOK = TRUE );
+
+    GIntBig             GetFeatureCount( int );
+    OGRErr              GetExtent( OGREnvelope *psExtent, int bForce );
+};
+
+#endif /*  PCIDSKDATASET2_H_INCLUDED */
diff --git a/frmts/pcidsk/sdk/channel/cbandinterleavedchannel.cpp b/frmts/pcidsk/sdk/channel/cbandinterleavedchannel.cpp
index 6c3ce52..bf01885 100644
--- a/frmts/pcidsk/sdk/channel/cbandinterleavedchannel.cpp
+++ b/frmts/pcidsk/sdk/channel/cbandinterleavedchannel.cpp
@@ -52,8 +52,8 @@ using namespace PCIDSK;
 /*                      CBandInterleavedChannel()                       */
 /************************************************************************/
 
-CBandInterleavedChannel::CBandInterleavedChannel( PCIDSKBuffer &image_header, 
-                                                  uint64 ih_offset, 
+CBandInterleavedChannel::CBandInterleavedChannel( PCIDSKBuffer &image_header,
+                                                  uint64 ih_offset,
                                                   CPL_UNUSED PCIDSKBuffer &file_header,
                                                   int channelnum,
                                                   CPCIDSKFile *file,
@@ -474,4 +474,3 @@ std::string CBandInterleavedChannel::MassageLink( std::string filename_in ) cons
 
     return filename_in;
 }
-
diff --git a/frmts/pcidsk/sdk/channel/cexternalchannel.cpp b/frmts/pcidsk/sdk/channel/cexternalchannel.cpp
index 6e70b1d..9ba29f3 100644
--- a/frmts/pcidsk/sdk/channel/cexternalchannel.cpp
+++ b/frmts/pcidsk/sdk/channel/cexternalchannel.cpp
@@ -52,8 +52,8 @@ using namespace PCIDSK;
 /*                          CExternalChannel()                          */
 /************************************************************************/
 
-CExternalChannel::CExternalChannel( PCIDSKBuffer &image_header, 
-                                    uint64 ih_offset, 
+CExternalChannel::CExternalChannel( PCIDSKBuffer &image_header,
+                                    uint64 ih_offset,
                                     CPL_UNUSED PCIDSKBuffer &file_header,
                                     std::string filename,
                                     int channelnum,
diff --git a/frmts/pcidsk/sdk/channel/cpcidskchannel.cpp b/frmts/pcidsk/sdk/channel/cpcidskchannel.cpp
index b8e4f53..5ffb2fe 100644
--- a/frmts/pcidsk/sdk/channel/cpcidskchannel.cpp
+++ b/frmts/pcidsk/sdk/channel/cpcidskchannel.cpp
@@ -482,10 +482,11 @@ void CPCIDSKChannel::GetChanInfo( std::string &filename, uint64 &image_offset,
 /*                            SetChanInfo()                             */
 /************************************************************************/
 
-void CPCIDSKChannel::SetChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED uint64 image_offset, 
-                                  CPL_UNUSED uint64 pixel_offset, CPL_UNUSED uint64 line_offset, 
+void CPCIDSKChannel::SetChanInfo( CPL_UNUSED std::string filename,
+                                  CPL_UNUSED uint64 image_offset,
+                                  CPL_UNUSED uint64 pixel_offset,
+                                  CPL_UNUSED uint64 line_offset,
                                   CPL_UNUSED bool little_endian )
-
 {
     ThrowPCIDSKException( "Attempt to SetChanInfo() on a channel that is not FILE interleaved." );
 }
@@ -510,10 +511,12 @@ void CPCIDSKChannel::GetEChanInfo( std::string &filename, int &echannel,
 /*                            SetEChanInfo()                            */
 /************************************************************************/
 
-void CPCIDSKChannel::SetEChanInfo( CPL_UNUSED std::string filename, CPL_UNUSED int echannel,
-                                   CPL_UNUSED int exoff, CPL_UNUSED int eyoff, 
-                                   CPL_UNUSED int exsize, CPL_UNUSED int eysize )
-
+void CPCIDSKChannel::SetEChanInfo( CPL_UNUSED std::string filename,
+                                   CPL_UNUSED int echannel,
+                                   CPL_UNUSED int exoff,
+                                   CPL_UNUSED int eyoff,
+                                   CPL_UNUSED int exsize,
+                                   CPL_UNUSED int eysize )
 {
     ThrowPCIDSKException( "Attempt to SetEChanInfo() on a channel that is not FILE interleaved." );
 }
diff --git a/frmts/pcidsk/sdk/channel/cpixelinterleavedchannel.cpp b/frmts/pcidsk/sdk/channel/cpixelinterleavedchannel.cpp
index 60e24b0..c1122e6 100644
--- a/frmts/pcidsk/sdk/channel/cpixelinterleavedchannel.cpp
+++ b/frmts/pcidsk/sdk/channel/cpixelinterleavedchannel.cpp
@@ -40,7 +40,7 @@ using namespace PCIDSK;
 /*                      CPixelInterleavedChannel()                      */
 /************************************************************************/
 
-CPixelInterleavedChannel::CPixelInterleavedChannel( PCIDSKBuffer &image_header, 
+CPixelInterleavedChannel::CPixelInterleavedChannel( PCIDSKBuffer &image_header,
                                                     uint64 ih_offset,
                                                     CPL_UNUSED PCIDSKBuffer &file_header,
                                                     int channelnum,
@@ -259,4 +259,3 @@ int CPixelInterleavedChannel::WriteBlock( int block_index, void *buffer )
 
     return 1;
 }
-
diff --git a/frmts/pcidsk/sdk/channel/ctiledchannel.cpp b/frmts/pcidsk/sdk/channel/ctiledchannel.cpp
index fcf2429..f4996d8 100644
--- a/frmts/pcidsk/sdk/channel/ctiledchannel.cpp
+++ b/frmts/pcidsk/sdk/channel/ctiledchannel.cpp
@@ -49,14 +49,13 @@ using namespace PCIDSK;
 /*                           CTiledChannel()                            */
 /************************************************************************/
 
-CTiledChannel::CTiledChannel( PCIDSKBuffer &image_header, 
+CTiledChannel::CTiledChannel( PCIDSKBuffer &image_header,
                               uint64 ih_offset,
                               CPL_UNUSED PCIDSKBuffer &file_header,
                               int channelnum,
                               CPCIDSKFile *file,
                               eChanType pixel_type )
         : CPCIDSKChannel( image_header, ih_offset, file, pixel_type, channelnum)
-
 {
 /* -------------------------------------------------------------------- */
 /*      Establish the virtual file we will be accessing.                */
diff --git a/frmts/pcidsk/sdk/core/metadataset_p.cpp b/frmts/pcidsk/sdk/core/metadataset_p.cpp
index f3ca92b..31da995 100644
--- a/frmts/pcidsk/sdk/core/metadataset_p.cpp
+++ b/frmts/pcidsk/sdk/core/metadataset_p.cpp
@@ -99,7 +99,7 @@ void MetadataSet::Load()
 
     MetadataSegment *md_seg = dynamic_cast<MetadataSegment *>( seg );
 
-    md_seg->FetchMetadata( group.c_str(), id, md_set );
+    md_seg->FetchGroupMetadata( group.c_str(), id, md_set );
     loaded = true;
 }
 
@@ -124,7 +124,6 @@ std::string MetadataSet::GetMetadataValue( const std::string& key )
 /************************************************************************/
 
 void MetadataSet::SetMetadataValue( const std::string& key, const std::string& value )
-
 {
     if( !loaded )
         Load();
@@ -140,15 +139,15 @@ void MetadataSet::SetMetadataValue( const std::string& key, const std::string& v
 
     if( seg == NULL )
     {
-        file->CreateSegment( "METADATA", 
-                             "Please do not modify this metadata segment.", 
+        file->CreateSegment( "METADATA",
+                             "Please do not modify this metadata segment.",
                              SEG_SYS, 0 );
         seg = file->GetSegment( SEG_SYS , "METADATA");
     }
 
     MetadataSegment *md_seg = dynamic_cast<MetadataSegment *>( seg );
 
-    md_seg->SetMetadataValue( group.c_str(), id, key, value );
+    md_seg->SetGroupMetadataValue( group.c_str(), id, key, value );
 }
 
 /************************************************************************/
@@ -156,7 +155,6 @@ void MetadataSet::SetMetadataValue( const std::string& key, const std::string& v
 /************************************************************************/
 
 std::vector<std::string> MetadataSet::GetMetadataKeys()
-
 {
     if( !loaded )
         Load();
@@ -168,8 +166,6 @@ std::vector<std::string> MetadataSet::GetMetadataKeys()
     {
         keys.push_back( (*it).first );
     }
-         
+
     return keys;
 }
-
-
diff --git a/frmts/pcidsk/sdk/core/pcidsk_utils.cpp b/frmts/pcidsk/sdk/core/pcidsk_utils.cpp
index 97c4420..a3f5231 100644
--- a/frmts/pcidsk/sdk/core/pcidsk_utils.cpp
+++ b/frmts/pcidsk/sdk/core/pcidsk_utils.cpp
@@ -395,7 +395,7 @@ std::vector<double> PCIDSK::ProjParmsFromText( std::string geosys,
 
     for( next = sparms.c_str(); *next != '\0'; )
     {
-        dparms.push_back( atof(next) );
+        dparms.push_back( CPLAtof(next) );
 
         // move past this token
         while( *next != '\0' && *next != ' ' )
@@ -454,7 +454,7 @@ std::string PCIDSK::ProjParmsToText( std::vector<double> dparms )
         if( dvalue == floor(dvalue) )
             sprintf( value, "%d", (int) dvalue );
         else
-            sprintf( value, "%.15g", dvalue );
+            CPLsprintf( value, "%.15g", dvalue );
         
         if( i > 0 )
             sparms += " ";
diff --git a/frmts/pcidsk/sdk/core/pcidskbuffer.cpp b/frmts/pcidsk/sdk/core/pcidskbuffer.cpp
index 2922422..cffd4bb 100644
--- a/frmts/pcidsk/sdk/core/pcidskbuffer.cpp
+++ b/frmts/pcidsk/sdk/core/pcidskbuffer.cpp
@@ -184,7 +184,7 @@ double PCIDSKBuffer::GetDouble( int offset, int size ) const
 
 /* -------------------------------------------------------------------- */
 /*      PCIDSK uses FORTRAN 'D' format for doubles - convert to 'E'     */
-/*      (C style) before calling atof.                                  */
+/*      (C style) before calling CPLAtof.                                  */
 /* -------------------------------------------------------------------- */
     int i;
 
@@ -193,14 +193,16 @@ double PCIDSKBuffer::GetDouble( int offset, int size ) const
         if( value_str[i] == 'D' )
             value_str[i] = 'E';
     }
-
+#ifdef PCIDSK_INTERNAL
+    return CPLAtof(value_str.c_str());
+#else
     std::stringstream oStream;
     oStream << value_str;
     double dValue = 0.0;
     oStream >> dValue;
 
     return dValue;
-//    return atof(value_str.c_str());
+#endif
 }
 
 /************************************************************************/
@@ -266,7 +268,7 @@ void PCIDSKBuffer::Put( double value, int offset, int size,
         fmt = "%g";
 
     char wrk[128];
-    snprintf( wrk, 127, fmt, value );
+    CPLsnprintf( wrk, 127, fmt, value );
 
     char *exponent = strstr(wrk,"E");
     if( exponent != NULL )
diff --git a/frmts/pcidsk/sdk/pcidsk_config.h b/frmts/pcidsk/sdk/pcidsk_config.h
index 2c97fdd..52606d4 100644
--- a/frmts/pcidsk/sdk/pcidsk_config.h
+++ b/frmts/pcidsk/sdk/pcidsk_config.h
@@ -82,4 +82,17 @@ namespace PCIDSK {
 #define PCIDSK_SDK_MAJOR_VERSION    0
 #define PCIDSK_SDK_MINOR_VERSION    1
 
+#ifndef GDAL_PCIDSK_DRIVER
+#ifdef PCIDSK_INTERNAL
+#include <stdlib.h>
+extern "C" double CPLAtof(const char*);
+extern "C" int CPLsprintf(char *str, const char* fmt, ...);
+extern "C" int CPLsnprintf(char *str, size_t size, const char* fmt, ...);
+#else
+#define CPLAtof atof
+#define CPLsprintf sprintf
+#define CPLsnprintf snprintf
+#endif
+#endif
+
 #endif // PCIDSK_CONFIG_H_INCLUDED
diff --git a/frmts/pcidsk/sdk/segment/cpcidsk_array.cpp b/frmts/pcidsk/sdk/segment/cpcidsk_array.cpp
index 656a27d..73a989d 100644
--- a/frmts/pcidsk/sdk/segment/cpcidsk_array.cpp
+++ b/frmts/pcidsk/sdk/segment/cpcidsk_array.cpp
@@ -112,12 +112,12 @@ void CPCIDSK_ARRAY::Load()
 
     for( unsigned int i = 0; i < nElements; i++ )
     {
-        /* TODO: Deal with strict-aliasing issue. */
         const double* pdValue = (const double*)seg_data.Get(i*8,8);
         char uValue[8];
         std::memcpy(uValue,pdValue,8);
         SwapData(uValue,8,1);
-        double dValue = *((double*)uValue);
+        double dValue;
+        memcpy(&dValue, uValue, 8);
         moArray.push_back(dValue);
     }
 
diff --git a/frmts/pcidsk/sdk/segment/cpcidskgeoref.cpp b/frmts/pcidsk/sdk/segment/cpcidskgeoref.cpp
index 671b1ed..bab64ad 100644
--- a/frmts/pcidsk/sdk/segment/cpcidskgeoref.cpp
+++ b/frmts/pcidsk/sdk/segment/cpcidskgeoref.cpp
@@ -317,7 +317,7 @@ void CPCIDSKGeoref::WriteParameters( std::vector<double> const& parms )
     Load();
 
     if( parms.size() < 17 )
-        ThrowPCIDSKException( "Did not get expected number of paramters in WriteParameters()" );
+        ThrowPCIDSKException( "Did not get expected number of parameters in WriteParameters()" );
 
     unsigned int i;
 
diff --git a/frmts/pcidsk/sdk/segment/metadatasegment.h b/frmts/pcidsk/sdk/segment/metadatasegment.h
index d4a47c3..a857a6d 100644
--- a/frmts/pcidsk/sdk/segment/metadatasegment.h
+++ b/frmts/pcidsk/sdk/segment/metadatasegment.h
@@ -48,16 +48,15 @@ namespace PCIDSK
     class MetadataSegment : virtual public CPCIDSKSegment
     {
 
-
     public:
         MetadataSegment( PCIDSKFile *file, int segment,
                          const char *segment_pointer );
         virtual     ~MetadataSegment();
 
-        void         FetchMetadata( const char *group, int id, 
-                                    std::map<std::string,std::string> &md_set );
-        void         SetMetadataValue( const char *group, int id,
-                                       const std::string& key, const std::string& value );
+        void         FetchGroupMetadata( const char *group, int id, 
+                                         std::map<std::string, std::string> &md_set );
+        void         SetGroupMetadataValue( const char *group, int id,
+                                            const std::string& key, const std::string& value );
 
         void         Synchronize();
                                    
diff --git a/frmts/pcidsk/sdk/segment/metadatasegment_p.cpp b/frmts/pcidsk/sdk/segment/metadatasegment_p.cpp
index ea6fba7..a0d9012 100644
--- a/frmts/pcidsk/sdk/segment/metadatasegment_p.cpp
+++ b/frmts/pcidsk/sdk/segment/metadatasegment_p.cpp
@@ -94,12 +94,11 @@ void MetadataSegment::Load()
 }
 
 /************************************************************************/
-/*                           FetchMetadata()                            */
+/*                           FetchGroupMetadata()                       */
 /************************************************************************/
 
-void MetadataSegment::FetchMetadata( const char *group, int id,
-                                     std::map<std::string,std::string> &md_set)
-
+void MetadataSegment::FetchGroupMetadata( const char *group, int id,
+                                          std::map<std::string, std::string> &md_set)
 {
 /* -------------------------------------------------------------------- */
 /*      Load the metadata segment if not already loaded.                */
@@ -166,12 +165,11 @@ void MetadataSegment::FetchMetadata( const char *group, int id,
 }
 
 /************************************************************************/
-/*                          SetMetadataValue()                          */
+/*                          SetGroupMetadataValue()                     */
 /************************************************************************/
 
-void MetadataSegment::SetMetadataValue( const char *group, int id,
-                                        const std::string& key, const std::string& value )
-
+void MetadataSegment::SetGroupMetadataValue( const char *group, int id,
+                                             const std::string& key, const std::string& value )
 {
     Load();
 
diff --git a/frmts/pcidsk/vsi_pcidsk_io.cpp b/frmts/pcidsk/vsi_pcidsk_io.cpp
index 45a88a4..397ae98 100644
--- a/frmts/pcidsk/vsi_pcidsk_io.cpp
+++ b/frmts/pcidsk/vsi_pcidsk_io.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vsi_pcidsk_io.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vsi_pcidsk_io.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  PCIDSK Database File
  * Purpose:  PCIDSK SDK compatiable io interface built on VSI.
@@ -32,7 +32,7 @@
 #include "cpl_multiproc.h"
 #include "pcidsk.h"
 
-CPL_CVSID("$Id: vsi_pcidsk_io.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: vsi_pcidsk_io.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 using namespace PCIDSK;
 
@@ -225,7 +225,7 @@ class CPLThreadMutex : public PCIDSK::Mutex
 
 {
 private:
-    void    *hMutex;
+    CPLMutex    *hMutex;
 
 public:
     CPLThreadMutex();
diff --git a/frmts/pcraster/GNUmakefile b/frmts/pcraster/GNUmakefile
index d0749f5..9f8079f 100644
--- a/frmts/pcraster/GNUmakefile
+++ b/frmts/pcraster/GNUmakefile
@@ -1,7 +1,7 @@
 
 include ../../GDALmake.opt
 
-CPPFLAGS := $(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS := $(XTRA_OPT)  $(CPPFLAGS)
 
 ifeq ($(PCRASTER_SETTING),internal)
 CPPFLAGS += -DUSE_IN_GDAL -Ilibcsf
diff --git a/frmts/pcraster/libcsf/AUTHORS b/frmts/pcraster/libcsf/AUTHORS
index 764f966..26bdb67 100644
--- a/frmts/pcraster/libcsf/AUTHORS
+++ b/frmts/pcraster/libcsf/AUTHORS
@@ -1,10 +1 @@
-DESIGN, IMPLEMENTATION and MAINTENANCE:
- Cees Wesseling, Willem van Deursen
- Utrecht University,              1992-1997
- PCRaster Environmental Software, 1997-present
-PORTING ISSUES:
- Edzer Pebesma
- Utrecht University
-PACKAGING:
- Kor de Jong
- Utrecht University
+PCRaster Research and Development team, Utrecht University
diff --git a/frmts/pcraster/libcsf/COPYING b/frmts/pcraster/libcsf/COPYING
index d9fc77e..ede206a 100644
--- a/frmts/pcraster/libcsf/COPYING
+++ b/frmts/pcraster/libcsf/COPYING
@@ -3,7 +3,7 @@ this directory (gdal/frmts/pcraster/libcsf).
 
 ------------------------------------------------------------------------
 
-Copyright (c) 1997-2003, Utrecht University
+Copyright (c) PCRaster owners
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/frmts/pcraster/libcsf/README b/frmts/pcraster/libcsf/README
index 5a20675..a6ba323 100644
--- a/frmts/pcraster/libcsf/README
+++ b/frmts/pcraster/libcsf/README
@@ -1,11 +1,11 @@
-Hi!
+This library reads and writes the native PCRaster format, formerly known as CSF.
 
-For information about how to use the library see csf.pdf which can found
-at http://pcraster.geog.uu.nl. More information about PCRaster can be
-found at: http://www.pcraster.nl and http://pcraster.geog.uu.nl.
+More information about PCRaster can be found at:
+http://www.pcraster.eu
+http://pcraster.geo.uu.nl
 
 Questions can be directed to the PCRaster mailing list:
-http://pcraster.geog.uu.nl/support.html
+http://pcraster.geo.uu.nl/support/questions-2/
 
-Have fun!
-PCRaster research and development team.
+Bug reports can be submitted to the PCRaster SourceForge page:
+http://sourceforge.net/p/pcraster/bugs-and-feature-requests/milestone/PCRaster/
diff --git a/frmts/pcraster/libcsf/_getcell.c b/frmts/pcraster/libcsf/_getcell.c
index 15089b3..4e5132d 100644
--- a/frmts/pcraster/libcsf/_getcell.c
+++ b/frmts/pcraster/libcsf/_getcell.c
@@ -1,6 +1,3 @@
-/*
- * _getcell.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/_getrow.c b/frmts/pcraster/libcsf/_getrow.c
index 5c52858..abc81ee 100644
--- a/frmts/pcraster/libcsf/_getrow.c
+++ b/frmts/pcraster/libcsf/_getrow.c
@@ -1,6 +1,3 @@
-/*
- * _getrow.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/_gsomece.c b/frmts/pcraster/libcsf/_gsomece.c
index 2cfd99f..a9779b6 100644
--- a/frmts/pcraster/libcsf/_gsomece.c
+++ b/frmts/pcraster/libcsf/_gsomece.c
@@ -1,6 +1,3 @@
-/*
- * _gsomece.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/_putcell.c b/frmts/pcraster/libcsf/_putcell.c
index 4f749a1..26493d6 100644
--- a/frmts/pcraster/libcsf/_putcell.c
+++ b/frmts/pcraster/libcsf/_putcell.c
@@ -1,6 +1,3 @@
-/*
- * _putcell.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/_rputrow.c b/frmts/pcraster/libcsf/_rputrow.c
index 05e9fec..86ce5e1 100644
--- a/frmts/pcraster/libcsf/_rputrow.c
+++ b/frmts/pcraster/libcsf/_rputrow.c
@@ -1,6 +1,3 @@
-/*
- * _rputrow.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/angle.c b/frmts/pcraster/libcsf/angle.c
index fb9775c..f5cf323 100644
--- a/frmts/pcraster/libcsf/angle.c
+++ b/frmts/pcraster/libcsf/angle.c
@@ -1,13 +1,3 @@
-
-/*
- * angle.c 
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/attravai.c b/frmts/pcraster/libcsf/attravai.c
index 25c2ded..f3dde6d 100644
--- a/frmts/pcraster/libcsf/attravai.c
+++ b/frmts/pcraster/libcsf/attravai.c
@@ -1,6 +1,3 @@
-/*
- * attravai.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/attrsize.c b/frmts/pcraster/libcsf/attrsize.c
index 3fb80f4..a707a6d 100644
--- a/frmts/pcraster/libcsf/attrsize.c
+++ b/frmts/pcraster/libcsf/attrsize.c
@@ -1,6 +1,3 @@
-/*
- * attrsize.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/cellsize.c b/frmts/pcraster/libcsf/cellsize.c
index cb970e0..cd69285 100644
--- a/frmts/pcraster/libcsf/cellsize.c
+++ b/frmts/pcraster/libcsf/cellsize.c
@@ -1,40 +1,3 @@
-
-/*
- * cellsize.c 
-   $Log$
-   Revision 1.3  2006/02/07 10:17:15  kdejong
-   Fixed endian compile problem
-   some rcs issues of Kor, I guess
-   Checked in by cees (cees at pcraster.nl) on account of Kor
-
-   Revision 1.3  2005/10/03 07:23:00  kor
-   Removed rcs id string
-
-   Revision 1.2  2000/02/05 21:25:48  cees
-   added LOCATION_ATTRIBUTER struct
-
-   Revision 1.1.1.1  2000/01/04 21:04:12  cees
-   Initial import Cees
-
-   Revision 2.0  1996/05/23 13:16:26  cees
-   csf2clean
-
-   Revision 1.1  1996/05/23 13:11:49  cees
-   Initial revision
-
-   Revision 1.2  1995/11/01 17:23:03  cees
-   .
-
- * Revision 1.1  1994/09/08  17:16:23  cees
- * Initial revision
- *
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/csfglob.c b/frmts/pcraster/libcsf/csfglob.c
index 521030d..246280f 100644
--- a/frmts/pcraster/libcsf/csfglob.c
+++ b/frmts/pcraster/libcsf/csfglob.c
@@ -1,8 +1,3 @@
-/*
- * csfglob.c
- */
-
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/csfimpl.h b/frmts/pcraster/libcsf/csfimpl.h
index e8bd3d7..61d91ef 100644
--- a/frmts/pcraster/libcsf/csfimpl.h
+++ b/frmts/pcraster/libcsf/csfimpl.h
@@ -7,7 +7,7 @@
 /**  RUU CROSS SYSTEM MAP FORMAT                                  */
 /**                                                               */
 /******************************************************************/
-/* number of maps that can be open at one time 
+/* number of maps that can be open at one time
  * FOPEN_MAX should be there in Ansi-C in <stdio.h>
  * stdio.h is included in csf.h, check if csf.h is included first
  */
@@ -43,13 +43,13 @@
 /* INTERFACE with PCRaster software
  */
 #ifdef USE_IN_PCR
-# include "stddefx.h" 
+# include "stddefx.h"
 # include "misc.h" /* malloc, free */
 # define  CSF_MALLOC ChkMalloc
 # define  CSF_FREE   Free
 #else
 # include <stdlib.h> /* malloc, free,abs */
-# include <assert.h> 
+# include <assert.h>
 # define  CSF_MALLOC malloc
 # define  CSF_FREE   free
 # ifdef DEBUG
@@ -100,22 +100,22 @@
 #define LAST_ATTR_IN_BLOCK 	(NR_ATTR_IN_BLOCK-1)
 
 
-typedef struct ATTR_REC 
+typedef struct ATTR_REC
 {
 		UINT2 attrId;	/* attribute identifier */
-		CSF_FADDR attrOffset;   /* file-offset of attribute */
+		CSF_FADDR32 attrOffset;   /* file-offset of attribute */
 		UINT4 attrSize;	/* size of attribute in bytes */
 } ATTR_REC;
 
 typedef struct ATTR_CNTRL_BLOCK
 {
 	ATTR_REC attrs[NR_ATTR_IN_BLOCK];
-	CSF_FADDR    next; /* file-offset of next block */
+	CSF_FADDR32    next; /* file-offset of next block */
 } ATTR_CNTRL_BLOCK;
 
 #define SIZE_OF_ATTR_CNTRL_BLOCK  \
- ((NR_ATTR_IN_BLOCK * (sizeof(UINT2) + sizeof(CSF_FADDR) + sizeof(UINT4))) \
-  + sizeof(CSF_FADDR) )
+ ((NR_ATTR_IN_BLOCK * (sizeof(UINT2) + sizeof(CSF_FADDR32) + sizeof(UINT4))) \
+  + sizeof(CSF_FADDR32) )
 
 /* Note that two empty holes in the attribute area are never merged */
 
@@ -134,7 +134,7 @@ typedef struct ATTR_CNTRL_BLOCK
 	 *  good as (2^16)-1
 	 */
 
-/* does y decrements from 
+/* does y decrements from
  * top to bottom in this projection type?
  * this will also hold for the old types
  * since only PT_XY was increments from
@@ -164,7 +164,7 @@ typedef struct ATTR_CNTRL_BLOCK
 
 #define READ_AS	 0 /* note that READ_AS is also used on procedures
 			that implies write access, under the condition of
-			write access both type bytes are equal, and the 
+			write access both type bytes are equal, and the
 			READ_AS byte is 0-alligned in the record, so this
 			byte is quicker accessible */
 	/* we will call READ_AS the ONLY_AS if write access is implied */
@@ -197,11 +197,11 @@ int   CsfIsBootedCsfKernel(void);
 void  CsfBootCsfKernel(void);
 void  CsfSetVarTypeMV( CSF_VAR_TYPE *var, CSF_CR cellRepr);
 void  CsfGetVarType(void *dest, const CSF_VAR_TYPE *src, CSF_CR cellRepr);
-void  CsfReadAttrBlock( MAP *m, CSF_FADDR pos, ATTR_CNTRL_BLOCK *b);
-int   CsfWriteAttrBlock(MAP *m, CSF_FADDR pos, ATTR_CNTRL_BLOCK *b);
+void  CsfReadAttrBlock( MAP *m, CSF_FADDR32 pos, ATTR_CNTRL_BLOCK *b);
+int   CsfWriteAttrBlock(MAP *m, CSF_FADDR32 pos, ATTR_CNTRL_BLOCK *b);
 int   CsfGetAttrIndex(CSF_ATTR_ID id, const ATTR_CNTRL_BLOCK *b);
-CSF_FADDR CsfGetAttrBlock(MAP *m, CSF_ATTR_ID id, ATTR_CNTRL_BLOCK *b);
-CSF_FADDR CsfGetAttrPosSize(MAP *m, CSF_ATTR_ID id, size_t *size);
+CSF_FADDR32 CsfGetAttrBlock(MAP *m, CSF_ATTR_ID id, ATTR_CNTRL_BLOCK *b);
+CSF_FADDR32 CsfGetAttrPosSize(MAP *m, CSF_ATTR_ID id, size_t *size);
 size_t CsfWriteSwapped(void *buf, size_t size, size_t n, FILE  *f);
 size_t CsfReadSwapped(void *buf, size_t size, size_t n, FILE  *f);
 size_t CsfWritePlain(void *buf, size_t size, size_t n, FILE  *f);
@@ -209,7 +209,7 @@ size_t CsfReadPlain(void *buf, size_t size, size_t n, FILE  *f);
 void   CsfSwap(void *buf, size_t size, size_t n);
 char *CsfStringPad(char *s, size_t reqSize);
 
-CSF_FADDR CsfSeekAttrSpace(MAP *m, CSF_ATTR_ID id, size_t size);
+CSF_FADDR32 CsfSeekAttrSpace(MAP *m, CSF_ATTR_ID id, size_t size);
 CSF_ATTR_ID CsfPutAttribute( MAP *m, CSF_ATTR_ID id, size_t size, size_t nitems, void *attr);
 CSF_ATTR_ID CsfGetAttribute(MAP *m, CSF_ATTR_ID id, size_t elSize, size_t *nmemb, void *attr);
 size_t      CsfAttributeSize(MAP *m, CSF_ATTR_ID id);
diff --git a/frmts/pcraster/libcsf/csfsup.c b/frmts/pcraster/libcsf/csfsup.c
index 3f5c487..0276e63 100644
--- a/frmts/pcraster/libcsf/csfsup.c
+++ b/frmts/pcraster/libcsf/csfsup.c
@@ -1,33 +1,3 @@
-/*
- * csfsup.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:34  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/06  13:21:04  cees
- * added c2man docs
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csftypes.h"
 #include <string.h>    /* memset */
diff --git a/frmts/pcraster/libcsf/csftypes.h b/frmts/pcraster/libcsf/csftypes.h
index b2ca051..db72e4c 100644
--- a/frmts/pcraster/libcsf/csftypes.h
+++ b/frmts/pcraster/libcsf/csftypes.h
@@ -61,7 +61,7 @@ typedef unsigned             char UINT1;
 #ifdef USE_IN_GDAL
 typedef GInt16   INT2;
 typedef GInt32   INT4;
-typedef GUInt16 UINT2;
+typedef GUInt16  UINT2;
 typedef GUInt32  UINT4;
 #else
 typedef CSF_SIGNED_SPECIFIER short                        int  INT2;
@@ -70,25 +70,26 @@ typedef unsigned             short                        int  UINT2;
 typedef unsigned             CSF_4BYTE_INT_SIZE_SPECIFIER int  UINT4;
 #endif
 
+#ifdef __GNUC__
+    /* Modern versions of GCC use knowledge about strict aliasing to implement
+     * certain optimizations. We have some code that fails to comply to the
+     * strict aliasing rules (see uses of UINT_ALIASING in this header).
+     * These are simple cases that should not be optimized. Using
+     * UINT_ALIASING will prevent gcc from optimizing these expressions.
+     * http://dbp-consulting.com/tutorials/StrictAliasing.html
+     * http://ohse.de/uwe/articles/gcc-attributes.html#type-may_alias
+     */
+    typedef UINT4 __attribute__((__may_alias__)) UINT4_ALIASING;
+#else
+    typedef UINT4 UINT4_ALIASING;
+#endif
+
 #undef CSF_4BYTE_INT_SIZE_SPECIFIER
 #undef CSF_SIGNED_SPECIFIER
 
 typedef float               REAL4; /* IEEE-754 32-bit */
 typedef double              REAL8; /* IEEE-754 64-bit */
 
-/* 64 bit specifier not yet used
- * but here is some code
- */
-#if defined(__GCC__) || defined(__MINGW32__)
-/* assume gcc, gcc likes it like this */
-typedef          long long  CSF_INT8;
-typedef unsigned long long  CSF_UINT8;
-#else
-#if defined(WIN32)
-typedef          __int64    CSF_INT8;
-typedef unsigned __int64    CSF_UINT8;
-#endif
-#endif
 
 /* endian mode
  * DEFINE WITH -D or find here
@@ -139,6 +140,15 @@ typedef unsigned __int64    CSF_UINT8;
 #  define CPU_LITTLE_ENDIAN
 #endif
 
+#ifdef __x86_64__
+/* linux/gcc defines this on intel 80x86_64 platform */
+#  define CPU_LITTLE_ENDIAN
+#endif
+#ifdef _M_X64
+/* Mscc defines this on intel 80x86_64 platform */
+#  define CPU_LITTLE_ENDIAN
+#endif
+
 #ifdef _M_IX86
 /* Borland C defines this */
 /* Win32/MSC defines this on intel 80x86 platform */
@@ -152,7 +162,7 @@ typedef unsigned __int64    CSF_UINT8;
 #endif
 
 /* endif probing */
-# endif 
+# endif
 
 /* endif no ENDIAN defined */
 # endif
@@ -201,8 +211,8 @@ typedef unsigned __int64    CSF_UINT8;
 typedef enum CSF_PT {
 
 	/* * these two can be returned by or passed to a csf2 function */
-	PT_YINCT2B=0,    /* Y increase from top to bottom */
-	PT_YDECT2B=1,    /* Y decrease from top to bottom */
+	PT_YINCT2B=0,    /* Y increase from top to bottom, wrong do not use */
+	PT_YDECT2B=1,    /* Y decrease from top to bottom, correct */
 
 	/* * this one CANNOT be returned by NOR passed to a csf2 function */
 	PT_UNDEFINED=100 /* just some value different from the rest */
@@ -214,7 +224,7 @@ typedef enum CSF_PT {
  */
 
 /* historical errors don't use them:
- * #define VS_NOTCLASSIFIED 2	
+ * #define VS_NOTCLASSIFIED 2
  * #define VS_CONTINUES 	 2
  *
  * NOTE new VS_* types must be different from CR_* values
@@ -358,7 +368,7 @@ typedef enum CSF_CR {
  * are NAN's
  * MV_REAL4 has the same bitpattern as a MV_UINT4
  * MV_REAL8 has the same bitpattern as two MV_UINT4's
- *          only the first 32 bits already identify a NAN, 
+ *          only the first 32 bits already identify a NAN,
  *          so that's what we test
  */
 #ifdef CPU_LITTLE_ENDIAN
@@ -369,8 +379,8 @@ typedef enum CSF_CR {
 #  define IS_MV_REAL4(x) (((const UINT2 *)(x))[1] == MV_UINT2)
 #  define IS_MV_REAL8(x) (((const UINT2 *)(x))[3] == MV_UINT2)
 # else
-#  define IS_MV_REAL4(x) ((*((const CSF_IN_GLOBAL_NS UINT4 *)(x))) == MV_UINT4)
-#  define IS_MV_REAL8(x) (((const CSF_IN_GLOBAL_NS UINT4 *)(x))[1] == MV_UINT4)
+#  define IS_MV_REAL4(x) ((*((const CSF_IN_GLOBAL_NS UINT4_ALIASING *)(x))) == MV_UINT4)
+#  define IS_MV_REAL8(x) (((const CSF_IN_GLOBAL_NS UINT4_ALIASING *)(x))[1] == MV_UINT4)
 # endif
 #else
 # ifdef CPU_BIG_ENDIAN
@@ -399,18 +409,18 @@ typedef enum CSF_CR {
 #define SET_MV_INT1(x)	( (*(( INT1 *)(x))) = MV_INT1)
 #define SET_MV_INT2(x)	( (*(( INT2 *)(x))) = MV_INT2)
 #define SET_MV_INT4(x)	( (*(( INT4 *)(x))) = MV_INT4)
-#define	SET_MV_REAL4(x)	((*(CSF_IN_GLOBAL_NS UINT4 *)(x)) = MV_UINT4)
+#define	SET_MV_REAL4(x)	((*(CSF_IN_GLOBAL_NS UINT4_ALIASING *)(x)) = MV_UINT4)
 #define	SET_MV_REAL8(x)	SET_MV_REAL4((x)),SET_MV_REAL4((((CSF_IN_GLOBAL_NS UINT4 *)(x))+1))
 
 /* copy of floats  by typecasting to
  * an integer since MV_REAL? is a NAN
  */
-#define	COPY_REAL4(dest,src) ( (*(UINT4 *)(dest)) = (*(const UINT4 *)(src)) )
+#define	COPY_REAL4(dest,src) ( (*(UINT4_ALIASING *)(dest)) = (*(const UINT4_ALIASING *)(src)) )
 #define	COPY_REAL8(dest,src) COPY_REAL4((dest),(src)),\
 		COPY_REAL4( (((UINT4 *)(dest))+1),(((const UINT4 *)(src))+1) )
 
 #ifdef __cplusplus
- };
+ }
 #endif
 
 #endif
diff --git a/frmts/pcraster/libcsf/delattr.c b/frmts/pcraster/libcsf/delattr.c
index b8cbb1d..840262c 100644
--- a/frmts/pcraster/libcsf/delattr.c
+++ b/frmts/pcraster/libcsf/delattr.c
@@ -1,36 +1,3 @@
-/*
- * delattr.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:36  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -50,7 +17,7 @@ CSF_ATTR_ID MdelAttribute(
 	CSF_ATTR_ID id)   /* identification of attribute */
 {
 	ATTR_CNTRL_BLOCK b;
-	CSF_FADDR pos;
+	CSF_FADDR32 pos;
 
 	if (! WRITE_ENABLE(m))
 	{
@@ -58,7 +25,7 @@ CSF_ATTR_ID MdelAttribute(
 		goto error;
 	}
 
-	pos = CsfGetAttrBlock(m, id, &b);  
+	pos = CsfGetAttrBlock(m, id, &b);
 	if (pos == 0)
 		goto error;
 
diff --git a/frmts/pcraster/libcsf/dumconv.c b/frmts/pcraster/libcsf/dumconv.c
index 08aa63c..92abf38 100644
--- a/frmts/pcraster/libcsf/dumconv.c
+++ b/frmts/pcraster/libcsf/dumconv.c
@@ -1,39 +1,3 @@
-
-/*
- * dumconv.c 
-   $Log$
-   Revision 1.3  2006/02/07 10:17:15  kdejong
-   Fixed endian compile problem
-   some rcs issues of Kor, I guess
-   Checked in by cees (cees at pcraster.nl) on account of Kor
-
-   Revision 1.3  2005/10/03 07:23:00  kor
-   Removed rcs id string
-
-   Revision 1.2  2005/09/29 18:43:22  cees
-   x86_64
-
-   Revision 1.1.1.1  2000/01/04 21:04:37  cees
-   Initial import Cees
-
-   Revision 2.0  1996/05/23 13:16:26  cees
-   csf2clean
-
-   Revision 1.1  1996/05/23 13:11:49  cees
-   Initial revision
-
-   Revision 1.2  1995/11/01 17:23:03  cees
-   .
-
- * Revision 1.1  1994/09/09  12:17:59  cees
- * Initial revision
- *
- */
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -63,8 +27,11 @@
  * does nothing
  */
 void CsfDummyConversion(
-                        CPL_UNUSED size_t nrCells,  
-                        CPL_UNUSED void *buf )
+  size_t  nrCells,
+  void   *buf)
 {
-	/* nothing */
+  /* nothing */
+  /* Shut up the C compiler */
+  (void)nrCells;
+  (void)buf;
 }
diff --git a/frmts/pcraster/libcsf/filename.c b/frmts/pcraster/libcsf/filename.c
index 4d0872e..185e654 100644
--- a/frmts/pcraster/libcsf/filename.c
+++ b/frmts/pcraster/libcsf/filename.c
@@ -1,33 +1,3 @@
-/*
- * filename.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:37  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gattrblk.c b/frmts/pcraster/libcsf/gattrblk.c
index ea7b9ef..a6604ae 100644
--- a/frmts/pcraster/libcsf/gattrblk.c
+++ b/frmts/pcraster/libcsf/gattrblk.c
@@ -1,39 +1,3 @@
-/*
- * gattrblk.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:37  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.4  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.3  1995/01/11  14:14:44  cees
- * added soem sinternal stuff
- *
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -45,14 +9,14 @@ Revision 1.4  1995/11/01 17:23:03  cees
  * or if found, the file position of the attribute
  * control block.
  */
-CSF_FADDR CsfGetAttrBlock(
+CSF_FADDR32 CsfGetAttrBlock(
 	MAP *m,     /* map handle */
 	CSF_ATTR_ID id,   /* identification of the attribute */
 	ATTR_CNTRL_BLOCK *b) /* write-only, attribute control block containing
 	                      * the id information.
 	                      */
 {
-	CSF_FADDR next;
+	CSF_FADDR32 next;
 
 	next = m->main.attrTable;
 	while (next != 0 )
@@ -72,7 +36,7 @@ CSF_FADDR CsfGetAttrBlock(
  * 0 if attribute is not found,
  * or if found, the file position of the attribute.
  */
-CSF_FADDR CsfGetAttrPosSize(
+CSF_FADDR32 CsfGetAttrPosSize(
 	MAP *m,     /* map handle */
 	CSF_ATTR_ID id,   /* identification of the attribute */
 	size_t *size) /* write-only the size of the attribute */
diff --git a/frmts/pcraster/libcsf/gattridx.c b/frmts/pcraster/libcsf/gattridx.c
index eebeba9..7ac67f7 100644
--- a/frmts/pcraster/libcsf/gattridx.c
+++ b/frmts/pcraster/libcsf/gattridx.c
@@ -1,34 +1,3 @@
-/*
- * gattridx.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:37  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/06  13:27:31  cees
- * const'fied
- * added c2man docs
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gdattype.c b/frmts/pcraster/libcsf/gdattype.c
index b7401d2..a3b2e89 100644
--- a/frmts/pcraster/libcsf/gdattype.c
+++ b/frmts/pcraster/libcsf/gdattype.c
@@ -1,37 +1,3 @@
-/*
- * gdattype.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:37  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/02  16:22:20  cees
- * added c2man doc
- * const'ified map handle
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/getattr.c b/frmts/pcraster/libcsf/getattr.c
index 53330d4..fd6246f 100644
--- a/frmts/pcraster/libcsf/getattr.c
+++ b/frmts/pcraster/libcsf/getattr.c
@@ -1,37 +1,3 @@
-/*
- * getattr.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:38  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
- * Revision 1.3  1995/11/01  17:23:03  cees
- * .
- *
- * Revision 1.2  1994/09/06  13:39:59  cees
- * added c2man docs
- * removed Merrno settin g if attr. is not avalaible
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/getx0.c b/frmts/pcraster/libcsf/getx0.c
index 6198386..b488f75 100644
--- a/frmts/pcraster/libcsf/getx0.c
+++ b/frmts/pcraster/libcsf/getx0.c
@@ -1,34 +1,3 @@
-/*
- * getx0.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:40  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gety0.c b/frmts/pcraster/libcsf/gety0.c
index 08af48b..0d6994f 100644
--- a/frmts/pcraster/libcsf/gety0.c
+++ b/frmts/pcraster/libcsf/gety0.c
@@ -1,33 +1,3 @@
-/*
- * gety0.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/ggisfid.c b/frmts/pcraster/libcsf/ggisfid.c
index 727bc40..f2fef42 100644
--- a/frmts/pcraster/libcsf/ggisfid.c
+++ b/frmts/pcraster/libcsf/ggisfid.c
@@ -1,37 +1,3 @@
-/*
- * ggisfid.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.4  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.3  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.2  1994/09/02  16:24:56  cees
- * added c2man doc
- * const'ified map handle
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gnrcols.c b/frmts/pcraster/libcsf/gnrcols.c
index 66f9651..de13dfc 100644
--- a/frmts/pcraster/libcsf/gnrcols.c
+++ b/frmts/pcraster/libcsf/gnrcols.c
@@ -1,33 +1,3 @@
-/*
- * gnrcols.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gnrrows.c b/frmts/pcraster/libcsf/gnrrows.c
index 71bdbcd..91db0df 100644
--- a/frmts/pcraster/libcsf/gnrrows.c
+++ b/frmts/pcraster/libcsf/gnrrows.c
@@ -1,33 +1,3 @@
-/*
- * gnrrows.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gproj.c b/frmts/pcraster/libcsf/gproj.c
index 6a4669b..af364b5 100644
--- a/frmts/pcraster/libcsf/gproj.c
+++ b/frmts/pcraster/libcsf/gproj.c
@@ -1,33 +1,3 @@
-/*
- * gproj.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gputproj.c b/frmts/pcraster/libcsf/gputproj.c
index 24d903a..48f997f 100644
--- a/frmts/pcraster/libcsf/gputproj.c
+++ b/frmts/pcraster/libcsf/gputproj.c
@@ -1,33 +1,3 @@
-/*
- * gputproj.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gvalscal.c b/frmts/pcraster/libcsf/gvalscal.c
index 734cf67..c6b1eba 100644
--- a/frmts/pcraster/libcsf/gvalscal.c
+++ b/frmts/pcraster/libcsf/gvalscal.c
@@ -1,34 +1,3 @@
-/*
- * gvalscal.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  13:15:05  cees
- * added c2man
- * const'fied map handle
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gvartype.c b/frmts/pcraster/libcsf/gvartype.c
index 52da33f..8ec0dc6 100644
--- a/frmts/pcraster/libcsf/gvartype.c
+++ b/frmts/pcraster/libcsf/gvartype.c
@@ -1,33 +1,3 @@
-/*
- * gvartype.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  13:20:54  cees
- * const'ified 2nd arg
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/gversion.c b/frmts/pcraster/libcsf/gversion.c
index b13988b..4221811 100644
--- a/frmts/pcraster/libcsf/gversion.c
+++ b/frmts/pcraster/libcsf/gversion.c
@@ -1,33 +1,3 @@
-/*
- * gversion.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  13:22:25  cees
- * const'ified map handle
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/ismv.c b/frmts/pcraster/libcsf/ismv.c
index 73df13e..babe55a 100644
--- a/frmts/pcraster/libcsf/ismv.c
+++ b/frmts/pcraster/libcsf/ismv.c
@@ -1,42 +1,3 @@
-/*
- * ismv.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:44  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  13:27:26  cees
- * changed for appCR field
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
-/********************************************************/
-/*							*/
-/*	IsMV						*/
-/*							*/
-/********************************************************/
-/* check if cellValue is a missing value		*/
-/********************************************************/
-
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/kernlcsf.c b/frmts/pcraster/libcsf/kernlcsf.c
index c12e056..3d3fe8e 100644
--- a/frmts/pcraster/libcsf/kernlcsf.c
+++ b/frmts/pcraster/libcsf/kernlcsf.c
@@ -1,18 +1,3 @@
-/*
- * kernlcsf.c
- *    Functions to create  and maintain the csf-kernel
- *     runtime structures
- */
-
-/**************************************************************************/
-/*  KERNLCSF.C                                                            */
-/*                                                                        */
-/*                                                                        */
-/**************************************************************************/
-
-/********/
-/* USES */
-/********/
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/legend.c b/frmts/pcraster/libcsf/legend.c
index b9fc472..3f3e336 100644
--- a/frmts/pcraster/libcsf/legend.c
+++ b/frmts/pcraster/libcsf/legend.c
@@ -1,7 +1,3 @@
-
-/*
- * legend.c 
- */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -13,7 +9,7 @@ static int NrLegendEntries(MAP *m)
 	int size = CsfAttributeSize(m, ATTR_ID_LEGEND_V2);
 	if (size == 0)
 	{
-		if ( (size = -1 * CsfAttributeSize(m, ATTR_ID_LEGEND_V1)) != 0 )
+		if ( (size = -(int)CsfAttributeSize(m, ATTR_ID_LEGEND_V1)) != 0 )
 			size -= CSF_LEGEND_ENTRY_SIZE;
 	}
 	return size/CSF_LEGEND_ENTRY_SIZE;
diff --git a/frmts/pcraster/libcsf/mclose.c b/frmts/pcraster/libcsf/mclose.c
index 33c1b0e..e1dcef1 100644
--- a/frmts/pcraster/libcsf/mclose.c
+++ b/frmts/pcraster/libcsf/mclose.c
@@ -1,10 +1,3 @@
-/*******************************************************/
-/*  Mclose.c               */
-/*******************************************************/
-/*  close map and if write permission write all    */
-/*  resident data to file                           */
-/*******************************************************/
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/mopen.c b/frmts/pcraster/libcsf/mopen.c
index a89dc16..56af168 100644
--- a/frmts/pcraster/libcsf/mopen.c
+++ b/frmts/pcraster/libcsf/mopen.c
@@ -1,10 +1,3 @@
-
-/*******************************************************/
-/*	FUNCTIE   MOPEN.C	                       */
-/*******************************************************/
-/*******************************************************/
-
-
 #include <string.h>
 
 #include "csf.h"
@@ -133,11 +126,11 @@ MAP  *Mopen(
  m->read((void *)&(m->raster.valueScale), sizeof(UINT2),(size_t)1,m->fp);
  m->read((void *)&(m->raster.cellRepr), sizeof(UINT2),(size_t)1,m->fp);
 
- if (0 != fread((void *)&(m->raster.minVal), sizeof(CSF_VAR_TYPE),(size_t)1,m->fp))
+ if (1 != fread((void *)&(m->raster.minVal), sizeof(CSF_VAR_TYPE),(size_t)1,m->fp))
  {
      fprintf(stderr, "WARNING: Unable to read min val in CSF.\n");
  }
- if (0 != fread((void *)&(m->raster.maxVal), sizeof(CSF_VAR_TYPE),(size_t)1,m->fp))
+ if (1 != fread((void *)&(m->raster.maxVal), sizeof(CSF_VAR_TYPE),(size_t)1,m->fp))
  {
      fprintf(stderr, "WARNING: Unable to read max val in CSF.\n");
  }
diff --git a/frmts/pcraster/libcsf/moreattr.c b/frmts/pcraster/libcsf/moreattr.c
index 33cf17f..d834858 100644
--- a/frmts/pcraster/libcsf/moreattr.c
+++ b/frmts/pcraster/libcsf/moreattr.c
@@ -1,7 +1,3 @@
-/*
- * moreattr.c 
- */
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/mperror.c b/frmts/pcraster/libcsf/mperror.c
index d28b2bd..f625219 100644
--- a/frmts/pcraster/libcsf/mperror.c
+++ b/frmts/pcraster/libcsf/mperror.c
@@ -1,6 +1,3 @@
-/*
- * mperror.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/pcrtypes.h b/frmts/pcraster/libcsf/pcrtypes.h
index 06fd7b3..c1bf244 100644
--- a/frmts/pcraster/libcsf/pcrtypes.h
+++ b/frmts/pcraster/libcsf/pcrtypes.h
@@ -11,6 +11,15 @@
 #define INCLUDED_STRING
 #endif
 
+/* NOTE that this file is included in the PCRaster gdal driver
+ *      it accounts for more compiler issues than we deal with
+ *      normally in PCRaster, such as the VC6 compiler.
+ *      64 bit integer typedefs are only defined for the PCRaster
+ *      source not for the Gdal driver.
+ *      The Gdal PCRaster driver defines USE_IN_GDAL, PCRaster sources
+ *      do not.
+ */
+
 // memset
 // use string.h not cstring
 // VC6 does not have memset in std
@@ -20,6 +29,36 @@
 #define INCLUDED_C_STRING
 #endif
 
+#ifndef USE_IN_GDAL
+ // exclude Gdal driver, only for PCRaster sources
+
+# ifdef _MSC_VER
+  typedef          __int64    PCR_INT8;
+  typedef unsigned __int64    PCR_UINT8;
+# else
+  // assume gcc FTTB
+  typedef          long long  PCR_INT8;
+  typedef unsigned long long  PCR_UINT8;
+# endif
+/* from gcc manual:
+  ISO C99 supports data types for integers that are at least 64 bits wide,
+  and as an extension GCC supports them in C89 mode and in C++. Simply
+  write long long int for a signed integer, or unsigned long long int for
+  an unsigned integer. To make an integer constant of type long long int,
+  add the suffix `LL' to the integer. To make an integer constant of type
+  unsigned long long int, add the suffix `ULL' to the integer.
+
+  WARNING: macros below are not typesafe, use  pcr::isMV and pcr::setMV instead
+ */
+#define MV_INT8   ((CSF_IN_GLOBAL_NS PCR_INT8)0x8000000000000000LL)
+#define MV_UINT8  ((CSF_IN_GLOBAL_NS PCR_UINT8)0xFFFFFFFFFFFFFFFFULL)
+#define IS_MV_INT8(x) ((*((const CSF_IN_GLOBAL_NS PCR_INT8 *)x)) == MV_INT8)
+#define IS_MV_UINT8(x) ((*((const CSF_IN_GLOBAL_NS PCR_UINT8 *)x)) == MV_UINT8)
+#define SET_MV_INT8(x) ( (*((PCR_INT8 *)(x))) = MV_INT8)
+#define SET_MV_UINT8(x) ( (*((PCR_UINT8 *)(x))) = MV_UINT8)
+
+#endif
+
 namespace pcr {
 /*!
   \brief     Tests if the value v is a missing value.
@@ -53,6 +92,14 @@ namespace pcr {
    PCR_DEF_ISMV(INT1)
    PCR_DEF_ISMV(INT2)
    PCR_DEF_ISMV(INT4)
+#  ifndef USE_IN_GDAL
+  template<>
+   inline bool isMV(const PCR_UINT8& v)
+   { return v == MV_UINT8; }
+  template<>
+   inline bool isMV(const PCR_INT8& v)
+   { return v == MV_INT8; }
+#  endif
 #  undef PCR_DEF_ISMV
   template<> inline bool isMV(const REAL4& v)
   { return IS_MV_REAL4(&v); }
@@ -88,6 +135,14 @@ template<> inline bool isMV(std::string const& string)
    PCR_DEF_SETMV(INT1)
    PCR_DEF_SETMV(INT2)
    PCR_DEF_SETMV(INT4)
+#  ifndef USE_IN_GDAL
+    template<>
+     inline void setMV(PCR_UINT8& v)
+     { v = MV_UINT8; }
+    template<>
+     inline void setMV(PCR_INT8& v)
+     { v = MV_INT8; }
+#  endif
 #  undef PCR_DEF_SETMV
 
   template<>
@@ -122,8 +177,9 @@ template<> inline bool isMV(std::string const& string)
 template<>
 inline void setMV(std::string& string)
 {
-//  string.clear();
-  string = "";
+  // VC6 does not have clear
+  // string.clear();
+  string="";
 }
 
 /*! \brief set array \a v of size \a n to all MV's
@@ -154,6 +210,9 @@ template<typename T>
   PCR_DEF_SETMV_MEMSET(UINT1)
   PCR_DEF_SETMV_MEMSET(UINT2)
   PCR_DEF_SETMV_MEMSET(UINT4)
+# ifndef USE_IN_GDAL
+  PCR_DEF_SETMV_MEMSET(PCR_UINT8)
+# endif
   PCR_DEF_SETMV_MEMSET(REAL4)
   PCR_DEF_SETMV_MEMSET(REAL8)
 # undef PCR_DEF_SETMV_MEMSET
@@ -166,7 +225,7 @@ template<typename T>
 /*!
  * \todo
  *   the isMV test is only needed for floats, to protect NAN evaluation
- *   what happens on bcc/win32
+ *   what once happened on bcc/win32. Should reevaluate that.
  */
 template<typename T>
   struct AlterToStdMV {
@@ -184,7 +243,7 @@ template<typename T>
 /*!
  * \todo
  *   the isMV test is only needed for floats, to protect NAN evaluation
- *   what happens on bcc/win32
+ *   what once happened on bcc/win32. Should reevaluate that.
  */
 template<typename T>
   struct ToStdMV {
@@ -207,7 +266,7 @@ template<typename T>
 /*!
  * \todo
  *   the isMV test is only needed for floats, to protect NAN evaluation
- *   what happens on bcc/win32
+ *   what once happened on bcc/win32. Should reevaluate that.
  */
 template<typename T>
   struct AlterFromStdMV {
@@ -225,7 +284,7 @@ template<typename T>
 /*!
  * \todo
  *   the isMV test is only needed for floats, to protect NAN evaluation
- *   what happens on bcc/win32
+ *   what once happened on bcc/win32. Should reevaluate that.
  */
 template<typename T>
   struct FromStdMV {
@@ -240,7 +299,7 @@ template<typename T>
     }
   };
 
-};
+}
 
 
 #endif
diff --git a/frmts/pcraster/libcsf/pgisfid.c b/frmts/pcraster/libcsf/pgisfid.c
index 6698b60..98814b8 100644
--- a/frmts/pcraster/libcsf/pgisfid.c
+++ b/frmts/pcraster/libcsf/pgisfid.c
@@ -1,33 +1,3 @@
-/*
- * pgisfid.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:52  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/pmaxval.c b/frmts/pcraster/libcsf/pmaxval.c
index 37e7082..ed5a2e5 100644
--- a/frmts/pcraster/libcsf/pmaxval.c
+++ b/frmts/pcraster/libcsf/pmaxval.c
@@ -1,40 +1,3 @@
-/*
- * pmaxval.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.3  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.2  2005/09/29 18:43:23  cees
-x86_64
-
-Revision 1.1.1.1  2000/01/04 21:04:52  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  15:59:34  cees
- * added app2file conversion
- * added c2man docs
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/pminval.c b/frmts/pcraster/libcsf/pminval.c
index 938b824..4b498eb 100644
--- a/frmts/pcraster/libcsf/pminval.c
+++ b/frmts/pcraster/libcsf/pminval.c
@@ -1,40 +1,3 @@
-/*
- * pminval.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.3  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.2  2005/09/29 18:43:23  cees
-x86_64
-
-Revision 1.1.1.1  2000/01/04 21:04:52  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/05  15:59:34  cees
- * added app2file conversion
- * added c2man docs
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/putattr.c b/frmts/pcraster/libcsf/putattr.c
index cbb8211..7dba3fd 100644
--- a/frmts/pcraster/libcsf/putattr.c
+++ b/frmts/pcraster/libcsf/putattr.c
@@ -24,7 +24,7 @@ CSF_ATTR_ID CsfUpdateAttribute(
 	CSF_ATTR_ID id,               /* attribute identification */
 	size_t itemSize,        /* size of each attribute element.
 	                         * 1 or sizeof(char) in case of a
-	                         * string 
+	                         * string
 	                         */
 	size_t nitems,          /* number of attribute elements or
 	                         * strlen+1 in case of a variable character
@@ -45,7 +45,7 @@ CSF_ATTR_ID CsfUpdateAttribute(
 /* write an attribute to a map (LIBRARY_INTERNAL)
  * MputAttribute writes exactly the number of bytes specified
  * by the size argument starting at the address of argument
- * attr. Which means that you can't simply pass a structure or an 
+ * attr. Which means that you can't simply pass a structure or an
  * array of structures as argument attr, due to the alignment
  * of fields within a structure and internal swapping. You can
  * only pass an array of elementary types (UINT1, REAL4, etc.)
@@ -65,7 +65,7 @@ CSF_ATTR_ID CsfPutAttribute(
 	CSF_ATTR_ID id,               /* attribute identification */
 	size_t itemSize,        /* size of each attribute element.
 	                         * 1 or sizeof(char) in case of a
-	                         * string 
+	                         * string
 	                         */
 	size_t nitems,          /* number of attribute elements or
 	                         * strlen+1 in case of a variable character
@@ -75,25 +75,25 @@ CSF_ATTR_ID CsfPutAttribute(
 	void *attr)       /* buffer containing attribute */
 {
 	size_t size = nitems * itemSize;
-	
+
 	PRECOND(CsfValidSize(itemSize));
 	PRECOND(size > 0);
 
 	if (CsfSeekAttrSpace(m,id,size) == 0)
 		goto error;
 
-	if (m->write(attr, itemSize, nitems, m->fp) != nitems) 
+	if (m->write(attr, itemSize, nitems, m->fp) != nitems)
 	{
 		M_ERROR(WRITE_ERROR);
 		goto error;
 	}
 	return(id); 		/* succes */
 error:	return(0);	/* failure */
-} 
+}
 
 /* seek to space for attribute  (LIBRARY_INTERNAL)
  * CsfSeekAttrSpace seeks to the a point in the file where
- * the attribute must be stored and update the attribute control 
+ * the attribute must be stored and update the attribute control
  * blocks accordingly.
  * Writing can still fail since there is no check if that space is really
  * avalaible on the device. After this call returns the file is already
@@ -105,13 +105,13 @@ error:	return(0);	/* failure */
  * NOACCESS
  * WRITE_ERROR
  */
-CSF_FADDR CsfSeekAttrSpace( 
+CSF_FADDR32 CsfSeekAttrSpace(
 	MAP *m,       		/* map handle */
 	CSF_ATTR_ID id,               /* attribute identification only for check if avalaible */
 	size_t size)            /* size to be seeked to */
 {
 	ATTR_CNTRL_BLOCK b;
-	CSF_FADDR currBlockPos, prevBlockPos=USED_UNINIT_ZERO, newPos, endBlock, resultPos=0;
+	CSF_FADDR32 currBlockPos, prevBlockPos=USED_UNINIT_ZERO, newPos, endBlock, resultPos=0;
 	int noPosFound;
 	int i;
 
@@ -129,8 +129,8 @@ CSF_FADDR CsfSeekAttrSpace(
 
 	currBlockPos = m->main.attrTable;
         noPosFound = 1;
-	while (noPosFound) 
-	{	
+	while (noPosFound)
+	{
 		if (currBlockPos == 0)
 		{
 			if (m->main.attrTable == 0)
@@ -143,7 +143,7 @@ CSF_FADDR CsfSeekAttrSpace(
 			}
 			else
 			{ /* NEW/NEXT BLOCK */
-				newPos = b.attrs[LAST_ATTR_IN_BLOCK].attrOffset 
+				newPos = b.attrs[LAST_ATTR_IN_BLOCK].attrOffset
 					+
 					b.attrs[LAST_ATTR_IN_BLOCK].attrSize;
 				b.next = newPos;
@@ -163,7 +163,7 @@ CSF_FADDR CsfSeekAttrSpace(
 			CsfReadAttrBlock(m, currBlockPos, &b);
 		i = 0; /* this is also the right index if a new block
 			   is added ! */
-		while (noPosFound  && i < NR_ATTR_IN_BLOCK) 
+		while (noPosFound  && i < NR_ATTR_IN_BLOCK)
 			switch (b.attrs[i].attrId)
 			{
 				case END_OF_ATTRS:
@@ -179,8 +179,7 @@ CSF_FADDR CsfSeekAttrSpace(
 						endBlock = b.next;
 					else
 						endBlock = b.attrs[i+1].attrOffset;
-					if ((size_t)(endBlock - b.attrs[i].attrOffset)
-						>= size)
+					if ( (size_t)( endBlock - b.attrs[i].attrOffset) >= size)
 						/* this position can
 							hold the attr */
 						noPosFound = 0;
@@ -190,10 +189,10 @@ CSF_FADDR CsfSeekAttrSpace(
 				 default:
                                             i++;
 			} /* switch */
-/*		if (b.next == 0) 
+/*		if (b.next == 0)
                      ? When did I change this CW
 		       remember this block position since it may be have
-		       to rewritten 
+		       to rewritten
 */
 		prevBlockPos = currBlockPos;
 		if (noPosFound)
diff --git a/frmts/pcraster/libcsf/putsomec.c b/frmts/pcraster/libcsf/putsomec.c
index c92b574..0f42792 100644
--- a/frmts/pcraster/libcsf/putsomec.c
+++ b/frmts/pcraster/libcsf/putsomec.c
@@ -1,6 +1,3 @@
-/*
- * putsomec.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/putx0.c b/frmts/pcraster/libcsf/putx0.c
index 6f6ee2c..6524d28 100644
--- a/frmts/pcraster/libcsf/putx0.c
+++ b/frmts/pcraster/libcsf/putx0.c
@@ -1,33 +1,3 @@
-/*
- * putx0.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:57  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/puty0.c b/frmts/pcraster/libcsf/puty0.c
index 2496aba..38b62de 100644
--- a/frmts/pcraster/libcsf/puty0.c
+++ b/frmts/pcraster/libcsf/puty0.c
@@ -1,33 +1,3 @@
-/*
- * puty0.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:57  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/pvalscal.c b/frmts/pcraster/libcsf/pvalscal.c
index be7cde2..d9a6dd1 100644
--- a/frmts/pcraster/libcsf/pvalscal.c
+++ b/frmts/pcraster/libcsf/pvalscal.c
@@ -1,36 +1,3 @@
-/*
- * pvalscal.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:57  cees
-Initial import Cees
-
-Revision 2.1  1996/12/29 19:35:21  cees
-src tree clean up
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/rattrblk.c b/frmts/pcraster/libcsf/rattrblk.c
index 7978db0..c545269 100644
--- a/frmts/pcraster/libcsf/rattrblk.c
+++ b/frmts/pcraster/libcsf/rattrblk.c
@@ -1,36 +1,3 @@
-/*
- * rattrblk.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.3  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.2  2005/09/29 18:43:23  cees
-x86_64
-
-Revision 1.1.1.1  2000/01/04 21:04:57  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -38,7 +5,7 @@ Revision 1.3  1995/11/01 17:23:03  cees
  */
 void CsfReadAttrBlock(
 	MAP *m,              /* map handle */
-	CSF_FADDR pos,           /* file position of block to be read */
+	CSF_FADDR32 pos,           /* file position of block to be read */
 	ATTR_CNTRL_BLOCK *b) /* write-only. attribute control block read */
 {
 	int i;
@@ -46,8 +13,8 @@ void CsfReadAttrBlock(
 	for(i=0; i < NR_ATTR_IN_BLOCK; i++)
 	{
 	 m->read((void *)&(b->attrs[i].attrId), sizeof(UINT2),(size_t)1,m->fp);
-	 m->read((void *)&(b->attrs[i].attrOffset), sizeof(CSF_FADDR),(size_t)1,m->fp);
+	 m->read((void *)&(b->attrs[i].attrOffset), sizeof(CSF_FADDR32),(size_t)1,m->fp);
 	 m->read((void *)&(b->attrs[i].attrSize), sizeof(UINT4),(size_t)1,m->fp);
 	}
-	m->read((void *)&(b->next), sizeof(CSF_FADDR),(size_t)1,m->fp);
+	m->read((void *)&(b->next), sizeof(CSF_FADDR32),(size_t)1,m->fp);
 }
diff --git a/frmts/pcraster/libcsf/rcomp.c b/frmts/pcraster/libcsf/rcomp.c
index f4b20c5..0b3010a 100644
--- a/frmts/pcraster/libcsf/rcomp.c
+++ b/frmts/pcraster/libcsf/rcomp.c
@@ -1,14 +1,3 @@
-/*
- * rcomp.c
- */
-
-/*****************************************************************/
-/*    FUNCTION :  RCOMPARE                                       */
-/*****************************************************************/
-/*             				                         */
-/*****************************************************************/
-
-
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/rcoords.c b/frmts/pcraster/libcsf/rcoords.c
index 590d67a..4100438 100644
--- a/frmts/pcraster/libcsf/rcoords.c
+++ b/frmts/pcraster/libcsf/rcoords.c
@@ -1,6 +1,3 @@
-/*
- * rcoords.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/rdup2.c b/frmts/pcraster/libcsf/rdup2.c
index e4d61e8..a8de2a9 100644
--- a/frmts/pcraster/libcsf/rdup2.c
+++ b/frmts/pcraster/libcsf/rdup2.c
@@ -1,7 +1,3 @@
-
-/*
- * rdup2.c 
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/reseterr.c b/frmts/pcraster/libcsf/reseterr.c
index 2ef6c1a..3b3f023 100644
--- a/frmts/pcraster/libcsf/reseterr.c
+++ b/frmts/pcraster/libcsf/reseterr.c
@@ -1,33 +1,3 @@
-/*
- * reseterr.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:04:59  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/08  17:16:23  cees
- * added c2man docs + small code changes
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/rextend.c b/frmts/pcraster/libcsf/rextend.c
index 016d758..f159fce 100644
--- a/frmts/pcraster/libcsf/rextend.c
+++ b/frmts/pcraster/libcsf/rextend.c
@@ -1,6 +1,3 @@
-/*
- * rextend.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 #include <math.h>
diff --git a/frmts/pcraster/libcsf/rmalloc.c b/frmts/pcraster/libcsf/rmalloc.c
index f2fcee8..15f778b 100644
--- a/frmts/pcraster/libcsf/rmalloc.c
+++ b/frmts/pcraster/libcsf/rmalloc.c
@@ -1,6 +1,3 @@
-/*
- * rmalloc.c 
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/rrowcol.c b/frmts/pcraster/libcsf/rrowcol.c
index 4fa09bc..f3525d9 100644
--- a/frmts/pcraster/libcsf/rrowcol.c
+++ b/frmts/pcraster/libcsf/rrowcol.c
@@ -1,6 +1,3 @@
-/*
- * rrowcol.c
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/ruseas.c b/frmts/pcraster/libcsf/ruseas.c
index e4f6549..b272d30 100644
--- a/frmts/pcraster/libcsf/ruseas.c
+++ b/frmts/pcraster/libcsf/ruseas.c
@@ -239,7 +239,7 @@ static void ConvertToREAL4( size_t nrCells, void *buf, CSF_CR src)
 				if ( ((UINT4 *)buf)[i] == MV_UINT4 )
 					((UINT4 *)buf)[i] = MV_UINT4;
 				else
-					((REAL4 *)buf)[i] = ((UINT4 *)buf)[i];
+					((REAL4 *)buf)[i] = (REAL4)((UINT4 *)buf)[i];
 			    }
 			while(i != 0);
 		}
@@ -438,82 +438,100 @@ int RuseAs(
   CSF_VS inFileVS = RgetValueScale(m);
   int hasInFileCellReprType2 =  HasInFileCellReprType2(inFileCR);
 
-  switch(useType)
-  {
-    case VS_BOOLEAN:
-  	switch(inFileVS) {
-	   case VS_LDD: case VS_DIRECTION:
-   			M_ERROR(CANT_USE_AS_BOOLEAN);
-   			return 1;
-   	   case VS_BOOLEAN:
-   	   		POSTCOND(inFileCR == CR_UINT1);
-   	   		m->appCR = CR_UINT1;
-   	   		m->file2app = same;
-   	   		m->app2file = same;
-   	   		return 0;
-   	   default:
-			if ( (! hasInFileCellReprType2) && WRITE_ENABLE(m) )
-			{ /* cellrepr is old one, we can't write that */
-					M_ERROR(CANT_USE_WRITE_BOOLEAN);
-					return 1;
-			}
-   			m->appCR = CR_UINT1;
-   			m->file2app  = ConvFuncBool(inFileCR);
-   			m->app2file = ConvFunc(inFileCR, CR_UINT1);
-   	   		return 0;
-   	} /* case useType == VS_BOOLEAN */
-   	break;
-
-   case VS_LDD:
-        switch(inFileVS) {
-         case VS_LDD:
-   	   		POSTCOND(inFileCR == CR_UINT1);
-   	   		m->appCR = CR_UINT1;
-   	   		m->file2app = same;
-   	   		m->app2file = same;
-   	   		return 0;
-        case VS_CLASSIFIED: 
-        case VS_NOTDETERMINED: 
-        	switch(inFileCR) {
-        	 case CR_UINT1:
-        	 	m->appCR = CR_UINT1;
-			m->file2app  = UINT1tLdd;
-			m->app2file = same;
-			return 0;
-		 case CR_INT2:
-		        if (WRITE_ENABLE(m))
-		        {  M_ERROR(CANT_USE_WRITE_LDD);
-			   return 1;
-		        }
-        	 	m->appCR = CR_UINT1;
-			m->file2app  = INT2tLdd;
-			m->app2file = illegal;
-			return 0;
-                  default:
-                    assert( FALSE );
-		}
-	default: M_ERROR(CANT_USE_AS_LDD);
-		 return 1;
+  /* it is very unconvenient that both, VS and CR are taken as arguments
+   * for this function, and previously were used in the switch statement
+   * now, at least 'special conversions' handled first
+   */
+  if((int)useType == VS_BOOLEAN){
+    switch(inFileVS) {
+      case VS_LDD:
+      case VS_DIRECTION: {
+        M_ERROR(CANT_USE_AS_BOOLEAN);
+        return 1;
       }
-      /* case useType == VS_LDD */
-      break;
-     case CR_UINT1:
-     case CR_INT4 :
-     case CR_REAL4:
-     case CR_REAL8:
-		if ( (! hasInFileCellReprType2) && WRITE_ENABLE(m) )
-		{ /* cellrepr is old one, we can't write that */
-				M_ERROR(CANT_USE_WRITE_OLDCR);
-				return 1;
-		}
-		m->appCR = useType;
-		m->file2app  = ConvFunc(useType, inFileCR);
-		m->app2file = ConvFunc(inFileCR, useType);
-		POSTCOND(m->file2app != NULL);
-		return 0;
-    default:
-    		M_ERROR(ILLEGAL_USE_TYPE);
-		return 1;
+      case VS_BOOLEAN: {
+        POSTCOND(inFileCR == CR_UINT1);
+        m->appCR = CR_UINT1;
+        m->file2app = same;
+        m->app2file = same;
+        return 0;
+      }
+      default: {
+        if((!hasInFileCellReprType2) && WRITE_ENABLE(m)) {
+          /* cellrepr is old one, we can't write that */
+          M_ERROR(CANT_USE_WRITE_BOOLEAN);
+          return 1;
+        }
+        m->appCR = CR_UINT1;
+        m->file2app  = ConvFuncBool(inFileCR);
+        m->app2file = ConvFunc(inFileCR, CR_UINT1);
+        return 0;
+      }
+    }
+  }
+  else if ((int)useType == VS_LDD){
+    switch(inFileVS) {
+      case VS_LDD: {
+        POSTCOND(inFileCR == CR_UINT1);
+        m->appCR = CR_UINT1;
+        m->file2app = same;
+        m->app2file = same;
+        return 0;
+      }
+      case VS_CLASSIFIED: 
+      case VS_NOTDETERMINED: {
+        switch(inFileCR) {
+          case CR_UINT1: {
+            m->appCR = CR_UINT1;
+            m->file2app  = UINT1tLdd;
+            m->app2file = same;
+            return 0;
+          }
+          case CR_INT2: {
+            if(WRITE_ENABLE(m)) {
+              M_ERROR(CANT_USE_WRITE_LDD);
+              return 1;
+            }
+            m->appCR = CR_UINT1;
+            m->file2app  = INT2tLdd;
+            m->app2file = illegal;
+            return 0;
+          }
+          default: {
+            /* This should never happen.
+             * Shut up compiler.
+             */
+            assert(0);
+          }
+        }
+      }
+      default: {
+        M_ERROR(CANT_USE_AS_LDD);
+        return 1;
+      }
+    }
+  }
+
+  switch(useType) {
+    case CR_UINT1:
+    case CR_INT4 :
+    case CR_REAL4:
+    case CR_REAL8: {
+      if((!hasInFileCellReprType2) && WRITE_ENABLE(m)) {
+        /* cellrepr is old one, we can't write that */
+        M_ERROR(CANT_USE_WRITE_OLDCR);
+        return 1;
+      }
+      m->appCR = useType;
+      m->file2app  = ConvFunc(useType, inFileCR);
+      m->app2file = ConvFunc(inFileCR, useType);
+      POSTCOND(m->file2app != NULL);
+      return 0;
+    }
+    default: {
+      M_ERROR(ILLEGAL_USE_TYPE);
+      return 1;
+    }
   }
   /* NOTREACHED */
 }
diff --git a/frmts/pcraster/libcsf/setangle.c b/frmts/pcraster/libcsf/setangle.c
index d4ee55c..d20278b 100644
--- a/frmts/pcraster/libcsf/setangle.c
+++ b/frmts/pcraster/libcsf/setangle.c
@@ -1,39 +1,3 @@
-
-/*
- * setangle.c 
-   $Log$
-   Revision 1.3  2006/02/07 10:17:15  kdejong
-   Fixed endian compile problem
-   some rcs issues of Kor, I guess
-   Checked in by cees (cees at pcraster.nl) on account of Kor
-
-   Revision 1.3  2005/10/03 07:23:00  kor
-   Removed rcs id string
-
-   Revision 1.2  2000/02/05 21:25:48  cees
-   added LOCATION_ATTRIBUTER struct
-
-   Revision 1.1.1.1  2000/01/04 21:05:05  cees
-   Initial import Cees
-
-   Revision 2.0  1996/05/23 13:16:26  cees
-   csf2clean
-
-   Revision 1.1  1996/05/23 13:11:49  cees
-   Initial revision
-
-   Revision 1.2  1995/11/01 17:23:03  cees
-   .
-
- * Revision 1.1  1994/09/07  13:23:08  cees
- * Initial revision
- *
- */
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include <math.h>
 #include "csf.h"
 #include "csfimpl.h"
diff --git a/frmts/pcraster/libcsf/setmv.c b/frmts/pcraster/libcsf/setmv.c
index 74d4caa..d5e2a98 100644
--- a/frmts/pcraster/libcsf/setmv.c
+++ b/frmts/pcraster/libcsf/setmv.c
@@ -1,34 +1,3 @@
-/*
- * setmv.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:05:06  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/09/06  13:04:27  cees
- * changed for appCR field
- * added c2man docs
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/setvtmv.c b/frmts/pcraster/libcsf/setvtmv.c
index cae0a78..7f71baa 100644
--- a/frmts/pcraster/libcsf/setvtmv.c
+++ b/frmts/pcraster/libcsf/setvtmv.c
@@ -1,30 +1,3 @@
-/*
- * setvtmv.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.2  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.1.1.1  2000/01/04 21:05:06  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.2  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/strconst.c b/frmts/pcraster/libcsf/strconst.c
index 4c78e69..6575338 100644
--- a/frmts/pcraster/libcsf/strconst.c
+++ b/frmts/pcraster/libcsf/strconst.c
@@ -1,12 +1,3 @@
-
-/*
- * strconst.c 
- */
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 
 /* global header (opt.) and strconst's prototypes "" */
diff --git a/frmts/pcraster/libcsf/strpad.c b/frmts/pcraster/libcsf/strpad.c
index f625159..31aee55 100644
--- a/frmts/pcraster/libcsf/strpad.c
+++ b/frmts/pcraster/libcsf/strpad.c
@@ -1,8 +1,3 @@
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include <string.h>
 
 /* global header (opt.) and strpad's prototypes "" */
diff --git a/frmts/pcraster/libcsf/swapio.c b/frmts/pcraster/libcsf/swapio.c
index b0c6506..6b80a68 100644
--- a/frmts/pcraster/libcsf/swapio.c
+++ b/frmts/pcraster/libcsf/swapio.c
@@ -1,8 +1,3 @@
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 
 /* global header (opt.) and swapio's prototypes "" */
@@ -52,9 +47,12 @@ int CsfValidSize(size_t size)
 #endif
 
 /* ARGSUSED */
-static void Swap1(CPL_UNUSED unsigned char * buf,  CPL_UNUSED size_t n)
+static void Swap1(unsigned char *buf,  size_t n)
 {
 	/* do nothing */
+  /* Shut up C compiler. */
+  (void)buf;
+  (void)n;
 }
 
 static void Swap2(unsigned char *b,  size_t n)
diff --git a/frmts/pcraster/libcsf/trackmm.c b/frmts/pcraster/libcsf/trackmm.c
index 37a52e4..92389e7 100644
--- a/frmts/pcraster/libcsf/trackmm.c
+++ b/frmts/pcraster/libcsf/trackmm.c
@@ -1,40 +1,3 @@
-
-/*
- * trackmm.c 
-   $Log$
-   Revision 1.3  2006/02/07 10:17:15  kdejong
-   Fixed endian compile problem
-   some rcs issues of Kor, I guess
-   Checked in by cees (cees at pcraster.nl) on account of Kor
-
-   Revision 1.2  2005/10/03 07:23:00  kor
-   Removed rcs id string
-
-   Revision 1.1.1.1  2000/01/04 21:05:11  cees
-   Initial import Cees
-
-   Revision 2.1  1996/12/29 19:35:21  cees
-   src tree clean up
-
-   Revision 2.0  1996/05/23 13:16:26  cees
-   csf2clean
-
-   Revision 1.1  1996/05/23 13:11:49  cees
-   Initial revision
-
-   Revision 1.2  1995/11/01 17:23:03  cees
-   .
-
- * Revision 1.1  1994/09/13  10:56:47  cees
- * Initial revision
- *
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h"
 #include "csfimpl.h"
 
diff --git a/frmts/pcraster/libcsf/vs2.c b/frmts/pcraster/libcsf/vs2.c
index fd30002..247fda9 100644
--- a/frmts/pcraster/libcsf/vs2.c
+++ b/frmts/pcraster/libcsf/vs2.c
@@ -1,10 +1,3 @@
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
-
-/* global header (opt.) and vsis's prototypes "" */
 #include "csf.h" 
 #include "csfimpl.h" 
 
diff --git a/frmts/pcraster/libcsf/vsdef.c b/frmts/pcraster/libcsf/vsdef.c
index b673b0f..4f58de9 100644
--- a/frmts/pcraster/libcsf/vsdef.c
+++ b/frmts/pcraster/libcsf/vsdef.c
@@ -1,43 +1,3 @@
-
-
-/*
- * vsdef.c 
-   $Log$
-   Revision 1.3  2006/02/07 10:17:15  kdejong
-   Fixed endian compile problem
-   some rcs issues of Kor, I guess
-   Checked in by cees (cees at pcraster.nl) on account of Kor
-
-   Revision 1.2  2005/10/03 07:23:00  kor
-   Removed rcs id string
-
-   Revision 1.1.1.1  2000/01/04 21:05:12  cees
-   Initial import Cees
-
-   Revision 2.0  1996/05/23 13:16:26  cees
-   csf2clean
-
-   Revision 1.1  1996/05/23 13:11:49  cees
-   Initial revision
-
-   Revision 1.2  1995/11/01 17:23:03  cees
-   .
-
- * Revision 1.1  1995/05/04  14:35:24  cees
- * Initial revision
- *
- * Revision 1.1  1994/09/02  14:30:00  cees
- * Initial revision
- *
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
-
-/* global header (opt.) and vsis's prototypes "" */
 #include "csf.h" 
 #include "csfimpl.h" 
 
diff --git a/frmts/pcraster/libcsf/vsis.c b/frmts/pcraster/libcsf/vsis.c
index aa5423d..51391a5 100644
--- a/frmts/pcraster/libcsf/vsis.c
+++ b/frmts/pcraster/libcsf/vsis.c
@@ -1,14 +1,3 @@
-/*
- * vsis.c 
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
-
-/* global header (opt.) and vsis's prototypes "" */
 #include "csf.h" 
 #include "csfimpl.h" 
 
diff --git a/frmts/pcraster/libcsf/vsvers.c b/frmts/pcraster/libcsf/vsvers.c
index 70f75c5..c60747b 100644
--- a/frmts/pcraster/libcsf/vsvers.c
+++ b/frmts/pcraster/libcsf/vsvers.c
@@ -1,13 +1,3 @@
-
-/*
- * vsvers.c 
- */
-
-/********/
-/* USES */
-/********/
-
-/* libs ext. <>, our ""  */
 #include "csf.h" 
 
 /* global header (opt.) and vsvers's prototypes "" */
diff --git a/frmts/pcraster/libcsf/wattrblk.c b/frmts/pcraster/libcsf/wattrblk.c
index 035dd9e..53b58f2 100644
--- a/frmts/pcraster/libcsf/wattrblk.c
+++ b/frmts/pcraster/libcsf/wattrblk.c
@@ -1,36 +1,3 @@
-/*
- * wattrblk.c
-$Log$
-Revision 1.3  2006/02/07 10:17:15  kdejong
-Fixed endian compile problem
-some rcs issues of Kor, I guess
-Checked in by cees (cees at pcraster.nl) on account of Kor
-
-Revision 1.3  2005/10/03 07:23:00  kor
-Removed rcs id string
-
-Revision 1.2  2005/09/29 18:43:23  cees
-x86_64
-
-Revision 1.1.1.1  2000/01/04 21:05:15  cees
-Initial import Cees
-
-Revision 2.0  1996/05/23 13:16:26  cees
-csf2clean
-
-Revision 1.1  1996/05/23 13:11:49  cees
-Initial revision
-
-Revision 1.3  1995/11/01 17:23:03  cees
-.
-
- * Revision 1.2  1994/08/31  15:36:16  cees
- * added c2man doc
- *
- * Revision 1.1  1994/08/26  13:33:23  cees
- * Initial revision
- *
- */
 #include "csf.h"
 #include "csfimpl.h"
 
@@ -39,8 +6,8 @@ Revision 1.3  1995/11/01 17:23:03  cees
  * 1 if seeking or writing failed
  */
 int CsfWriteAttrBlock(
-	MAP *m,          /* map handle */ 
-	CSF_FADDR pos,       /* file position where the block is written */
+	MAP *m,          /* map handle */
+	CSF_FADDR32 pos,       /* file position where the block is written */
 	ATTR_CNTRL_BLOCK *b) /* attribute control block to be written */
 {
  int i;
@@ -50,10 +17,10 @@ int CsfWriteAttrBlock(
 
  for(i=0; i < NR_ATTR_IN_BLOCK; i++)
   if ( m->write(&(b->attrs[i].attrId), sizeof(UINT2),(size_t)1,m->fp)    != 1 ||
-       m->write(&(b->attrs[i].attrOffset),sizeof(CSF_FADDR),(size_t)1,m->fp) != 1 ||
-       m->write(&(b->attrs[i].attrSize), sizeof(UINT4),(size_t)1,m->fp)  != 1 
+       m->write(&(b->attrs[i].attrOffset),sizeof(CSF_FADDR32),(size_t)1,m->fp) != 1 ||
+       m->write(&(b->attrs[i].attrSize), sizeof(UINT4),(size_t)1,m->fp)  != 1
      )
      return 1;
- 
- return m->write(&(b->next), sizeof(CSF_FADDR),(size_t)1,m->fp) != 1;
+
+ return m->write(&(b->next), sizeof(CSF_FADDR32),(size_t)1,m->fp) != 1;
 }
diff --git a/frmts/pcraster/pcrasterdataset.cpp b/frmts/pcraster/pcrasterdataset.cpp
index 682582c..5f37ad3 100644
--- a/frmts/pcraster/pcrasterdataset.cpp
+++ b/frmts/pcraster/pcrasterdataset.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: pcrasterdataset.cpp 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster CSF 2.0 raster file driver
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -27,21 +27,23 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-#include "gdal_pam.h"
-#include "cpl_string.h"
-
-CPL_CVSID("$Id: pcrasterdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
-
-#ifndef INCLUDED_PCRASTERDATASET
-#include "pcrasterdataset.h"
-#define INCLUDED_PCRASTERDATASET
-#endif
-
 #ifndef INCLUDED_IOSTREAM
 #include <iostream>
 #define INCLUDED_IOSTREAM
 #endif
 
+#ifndef INCLUDED_GDAL_PAM
+#include "gdal_pam.h"
+#define INCLUDED_GDAL_PAM
+#endif
+
+#ifndef INCLUDED_CPL_STRING
+#include "cpl_string.h"
+#define INCLUDED_CPL_STRING
+#endif
+
+CPL_CVSID("$Id: pcrasterdataset.cpp 28862 2015-04-07 10:10:25Z kdejong $");
+
 // PCRaster library headers.
 
 // Module headers.
@@ -50,6 +52,11 @@ CPL_CVSID("$Id: pcrasterdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
 #define INCLUDED_PCRASTERRASTERBAND
 #endif
 
+#ifndef INCLUDED_PCRASTERDATASET
+#include "pcrasterdataset.h"
+#define INCLUDED_PCRASTERDATASET
+#endif
+
 #ifndef INCLUDED_PCRASTERUTIL
 #include "pcrasterutil.h"
 #define INCLUDED_PCRASTERUTIL
@@ -80,7 +87,7 @@ GDALDataset* PCRasterDataset::open(
 {
   PCRasterDataset* dataset = 0;
 
-  if(info->fp && info->nHeaderBytes >= static_cast<int>(CSF_SIZE_SIG) &&
+  if(info->fpL && info->nHeaderBytes >= static_cast<int>(CSF_SIZE_SIG) &&
          strncmp((char*)info->pabyHeader, CSF_SIG, CSF_SIZE_SIG) == 0) {
     MOPEN_PERM mode = info->eAccess == GA_Update
          ? M_READ_WRITE
@@ -123,12 +130,12 @@ GDALDataset* PCRasterDataset::open(
   cell representations.
 */
 GDALDataset* PCRasterDataset::createCopy(
-         char const* filename,
-         GDALDataset* source,
-         CPL_UNUSED int strict,
-         CPL_UNUSED char** options,
-         GDALProgressFunc progress,
-         void* progressData)
+    char const* filename,
+    GDALDataset* source,
+    CPL_UNUSED int strict,
+    CPL_UNUSED char** options,
+    GDALProgressFunc progress,
+    void* progressData)
 {
   // Checks.
   int nrBands = source->GetRasterCount();
@@ -244,7 +251,7 @@ GDALDataset* PCRasterDataset::createCopy(
 
     // Get row from source.
     if(raster->RasterIO(GF_Read, 0, row, nrCols, 1, buffer, nrCols, 1,
-         raster->GetRasterDataType(), 0, 0) != CE_None) {
+         raster->GetRasterDataType(), 0, 0, NULL) != CE_None) {
       CPLError(CE_Failure, CPLE_FileIO,
          "PCRaster driver: Error reading from source raster");
       errorCode = CE_Failure;
@@ -285,14 +292,14 @@ GDALDataset* PCRasterDataset::createCopy(
       return NULL;
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.        */
 /* -------------------------------------------------------------------- */
-  GDALPamDataset *poDS = (GDALPamDataset *) 
+  GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( filename, GA_Update );
 
   if( poDS )
       poDS->CloneInfo( source, GCIF_PAM_DEFAULT );
-  
+
   return poDS;
 }
 
@@ -324,6 +331,7 @@ PCRasterDataset::PCRasterDataset(
   d_valueScale = RgetValueScale(d_map);
   CPLAssert(d_valueScale != VS_UNDEFINED);
   d_missingValue = ::missingValue(d_cellRepresentation);
+  d_location_changed = false;
 
   // Create band information objects.
   nBands = 1;
@@ -419,6 +427,136 @@ double PCRasterDataset::missingValue() const
 }
 
 
+GDALDataset* PCRasterDataset::create(
+     const char* filename,
+     int nr_cols,
+     int nr_rows,
+     int nrBands,
+     GDALDataType gdalType,
+     char** papszParmList)
+{
+  // Checks
+  if(nrBands != 1){
+    CPLError(CE_Failure, CPLE_NotSupported,
+         "PCRaster driver : "
+         "attempt to create dataset with too many bands (%d); "
+         "must be 1 band.\n", nrBands);
+    return NULL;
+  }
+
+  int row_col_max = INT4_MAX - 1;
+  if(nr_cols > row_col_max){
+    CPLError(CE_Failure, CPLE_NotSupported,
+         "PCRaster driver : "
+         "attempt to create dataset with too many columns (%d); "
+         "must be smaller than %d.", nr_cols, row_col_max);
+    return NULL;
+  }
+
+  if(nr_rows > row_col_max){
+    CPLError(CE_Failure, CPLE_NotSupported,
+         "PCRaster driver : "
+         "attempt to create dataset with too many rows (%d); "
+         "must be smaller than %d.", nr_rows, row_col_max);
+    return NULL;
+  }
+
+  if(gdalType != GDT_Byte &&
+     gdalType != GDT_Int32 &&
+     gdalType != GDT_Float32){
+     CPLError( CE_Failure, CPLE_AppDefined,
+       "PCRaster driver: "
+       "attempt to create dataset with an illegal data type (%s); "
+       "use either Byte, Int32 or Float32.",
+       GDALGetDataTypeName(gdalType));
+    return NULL;
+  }
+
+  // value scale must be specified by the user,
+  // determines cell representation
+  const char *valueScale = CSLFetchNameValue(
+    papszParmList,"PCRASTER_VALUESCALE");
+
+  if(valueScale == NULL){
+    CPLError(CE_Failure, CPLE_AppDefined,
+         "PCRaster driver: value scale can not be determined; "
+         "specify PCRASTER_VALUESCALE.");
+    return NULL;
+  }
+
+
+  CSF_VS csf_value_scale = string2ValueScale(valueScale);
+
+  if(csf_value_scale == VS_UNDEFINED){
+    CPLError( CE_Failure, CPLE_AppDefined,
+         "PCRaster driver: value scale can not be determined (%s); "
+         "use either VS_BOOLEAN, VS_NOMINAL, VS_ORDINAL, VS_SCALAR, "
+         "VS_DIRECTION, VS_LDD",
+          valueScale);
+    return NULL;
+  }
+
+  CSF_CR csf_cell_representation = GDALType2CellRepresentation(gdalType, false);
+
+  // default values
+  REAL8 west = 0.0;
+  REAL8 north = 0.0;
+  REAL8 length = 1.0;
+  REAL8 angle = 0.0;
+  CSF_PT projection = PT_YDECT2B;
+
+  // Create a new raster
+  MAP* map = Rcreate(filename, nr_rows, nr_cols, csf_cell_representation,
+         csf_value_scale, projection, west, north, angle, length);
+
+  if(!map){
+    CPLError(CE_Failure, CPLE_OpenFailed,
+         "PCRaster driver: Unable to create raster %s", filename);
+    return NULL;
+  }
+
+  Mclose(map);
+  map = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Re-open dataset, and copy any auxiliary pam information.        */
+/* -------------------------------------------------------------------- */
+  GDALPamDataset *poDS = (GDALPamDataset *)
+        GDALOpen(filename, GA_Update);
+
+  return poDS;
+}
+
+
+CPLErr PCRasterDataset::SetGeoTransform(double* transform)
+{
+  if((transform[2] != 0.0) || (transform[4] != 0.0)) {
+    CPLError(CE_Failure, CPLE_NotSupported,
+             "PCRaster driver: "
+             "rotated geotransformations are not supported.");
+    return CE_Failure;
+  }
+
+  if(transform[1] != transform[5] * -1.0 ) {
+    CPLError(CE_Failure, CPLE_NotSupported,
+             "PCRaster driver: "
+             "only the same width and height for cells is supported." );
+    return CE_Failure;
+  }
+
+  d_west = transform[0];
+  d_north = transform[3];
+  d_cellSize = transform[1];
+  d_location_changed = true;
+
+  return CE_None;
+}
+
+
+bool PCRasterDataset::location_changed() const {
+  return d_location_changed;
+}
+
 
 //------------------------------------------------------------------------------
 // DEFINITION OF FREE OPERATORS
@@ -429,6 +567,3 @@ double PCRasterDataset::missingValue() const
 //------------------------------------------------------------------------------
 // DEFINITION OF FREE FUNCTIONS
 //------------------------------------------------------------------------------
-
-
-
diff --git a/frmts/pcraster/pcrasterdataset.h b/frmts/pcraster/pcrasterdataset.h
index c477743..9231449 100644
--- a/frmts/pcraster/pcrasterdataset.h
+++ b/frmts/pcraster/pcrasterdataset.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterdataset.h 13149 2007-11-29 15:08:00Z warmerdam $
+ * $Id: pcrasterdataset.h 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster CSF 2.0 raster file driver declarations.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -31,6 +31,10 @@
 #define INCLUDED_PCRASTERDATASET
 
 // Library headers.
+#ifndef INCLUDED_GDAL_PAM
+#include "gdal_pam.h"
+#define INCLUDED_GDAL_PAM
+#endif
 
 // PCRaster library headers.
 #ifndef INCLUDED_CSF
@@ -39,7 +43,6 @@
 #endif
 
 // Module headers.
-#include "gdal_pam.h"
 
 // namespace {
   // PCRasterDataset declarations.
@@ -74,6 +77,13 @@ public:
 
   static GDALDataset* open             (GDALOpenInfo* info);
 
+  static GDALDataset* create           (const char* filename,
+                                        int nr_cols,
+                                        int nr_rows,
+                                        int nrBands,
+                                        GDALDataType gdalType,
+                                        char** papszParmList);
+
   static GDALDataset* createCopy       (char const* filename,
                                         GDALDataset* source,
                                         int strict,
@@ -104,6 +114,8 @@ private:
   //! No data value.
   double           d_missingValue;
 
+  bool             d_location_changed;
+
   //! Assignment operator. NOT IMPLEMENTED.
   PCRasterDataset& operator=           (const PCRasterDataset&);
 
@@ -124,6 +136,8 @@ public:
   // MANIPULATORS
   //----------------------------------------------------------------------------
 
+  CPLErr           SetGeoTransform     (double* transform);
+
   //----------------------------------------------------------------------------
   // ACCESSORS
   //----------------------------------------------------------------------------
@@ -138,6 +152,8 @@ public:
 
   double           missingValue        () const;
 
+  bool             location_changed    () const;
+
 };
 
 
diff --git a/frmts/pcraster/pcrastermisc.cpp b/frmts/pcraster/pcrastermisc.cpp
index e1270d7..71f23ac 100644
--- a/frmts/pcraster/pcrastermisc.cpp
+++ b/frmts/pcraster/pcrastermisc.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrastermisc.cpp 13149 2007-11-29 15:08:00Z warmerdam $
+ * $Id: pcrastermisc.cpp 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster driver support functions.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -38,11 +38,14 @@
 #define INCLUDED_STRING
 #endif
 
+#ifndef INCLUDED_GDAL_PAM
+#include "gdal_pam.h"
+#define INCLUDED_GDAL_PAM
+#endif
+
 // PCRaster library headers.
 
 // Module headers.
-#include "gdal_pam.h"
-
 #ifndef INCLUDED_PCRASTERDATASET
 #include "pcrasterdataset.h"
 #define INCLUDED_PCRASTERDATASET
@@ -61,19 +64,22 @@ void GDALRegister_PCRaster()
     if (! GDAL_CHECK_VERSION("PCRaster driver"))
         return;
 
-if(!GDALGetDriverByName("PCRaster")) {
+    if(!GDALGetDriverByName("PCRaster")) {
 
-    GDALDriver* driver = new GDALDriver();
+        GDALDriver* poDriver = new GDALDriver();
 
-    driver->SetDescription("PCRaster");
-    driver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCRaster Raster File");
-    driver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int32 Float32");
-    driver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_various.html#PCRaster");
-    driver->SetMetadataItem( GDAL_DMD_EXTENSION, "map" );
+        poDriver->SetDescription("PCRaster");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
 
-    driver->pfnOpen = PCRasterDataset::open;
-    driver->pfnCreateCopy = PCRasterDataset::createCopy;
+        poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCRaster Raster File");
+        poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int32 Float32");
+        poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_various.html#PCRaster");
+        poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "map" );
 
-    GetGDALDriverManager()->RegisterDriver(driver);
-}
+        poDriver->pfnOpen = PCRasterDataset::open;
+        poDriver->pfnCreate = PCRasterDataset::create;
+        poDriver->pfnCreateCopy = PCRasterDataset::createCopy;
+
+        GetGDALDriverManager()->RegisterDriver(poDriver);
+    }
 }
diff --git a/frmts/pcraster/pcrasterrasterband.cpp b/frmts/pcraster/pcrasterrasterband.cpp
index 3657d78..74c2423 100644
--- a/frmts/pcraster/pcrasterrasterband.cpp
+++ b/frmts/pcraster/pcrasterrasterband.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterrasterband.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: pcrasterrasterband.cpp 29063 2015-04-30 07:52:46Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster raster band implementation.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -38,6 +38,11 @@
 #define INCLUDED_CSF
 #endif
 
+#ifndef INCLUDED_CSFIMPL
+#include "csfimpl.h"
+#define INCLUDED_CSFIMPL
+#endif
+
 // Module headers.
 #ifndef INCLUDED_PCRASTERDATASET
 #include "pcrasterdataset.h"
@@ -75,7 +80,10 @@
 PCRasterRasterBand::PCRasterRasterBand(
          PCRasterDataset* dataset)
 
-  : GDALPamRasterBand(), d_dataset(dataset)
+  : GDALPamRasterBand(),
+    d_dataset(dataset),
+    d_missing_value(-FLT_MAX),
+    d_create_in(GDT_Unknown)
 
 {
   this->poDS = dataset;
@@ -248,9 +256,9 @@ double PCRasterRasterBand::GetMaximum(
 
 
 CPLErr PCRasterRasterBand::IReadBlock(
-                                      CPL_UNUSED int nBlockXoff,
-                                      int nBlockYoff,
-                                      void* buffer)
+    CPL_UNUSED int nBlockXoff,
+    int nBlockYoff,
+    void* buffer)
 {
   size_t nrCellsRead = RgetRow(d_dataset->map(), nBlockYoff, buffer);
 
@@ -267,6 +275,119 @@ CPLErr PCRasterRasterBand::IReadBlock(
 }
 
 
+CPLErr PCRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag,
+                                     int nXOff, int nYOff, int nXSize,
+                                     int nYSize, void * pData,
+                                     int nBufXSize, int nBufYSize,
+                                     GDALDataType eBufType,
+                                     GSpacing nPixelSpace,
+                                     GSpacing nLineSpace,
+                                     GDALRasterIOExtraArg* psExtraArg)
+{
+  if (eRWFlag == GF_Read){
+    // read should just be the default
+    return GDALRasterBand::IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
+                                     pData, nBufXSize, nBufYSize, eBufType,
+                                     nPixelSpace, nLineSpace, psExtraArg);
+  }
+  else{
+    // the datatype of the incoming data can be of different type than the
+    // cell representation used in the raster
+    // 'remember' the GDAL type to distinguish it later on in iWriteBlock
+    d_create_in = eBufType;
+    return GDALRasterBand::IRasterIO(GF_Write, nXOff, nYOff, nXSize, nYSize,
+                                     pData, nBufXSize, nBufYSize, eBufType,
+                                     nPixelSpace, nLineSpace, psExtraArg);
+
+  }
+}
+
+
+
+CPLErr PCRasterRasterBand::IWriteBlock(
+    CPL_UNUSED int nBlockXoff,
+    int nBlockYoff,
+    void* source)
+{
+  CSF_VS valuescale = d_dataset->valueScale();
+
+  if(valuescale == VS_LDD) {
+    if((d_create_in == GDT_Byte) || (d_create_in == GDT_Float32) || (d_create_in == GDT_Float64)) {
+      CPLError(CE_Failure, CPLE_NotSupported,
+               "PCRaster driver: "
+               "conversion from %s to LDD not supported",
+               GDALGetDataTypeName(d_create_in));
+      return CE_Failure;
+    }
+  }
+
+  // set new location attributes to the header
+  if (d_dataset->location_changed()){
+    REAL8 west = 0.0;
+    REAL8 north = 0.0;
+    REAL8 cellSize = 1.0;
+    double transform[6];
+    if(this->poDS->GetGeoTransform(transform) == CE_None) {
+      if(transform[2] == 0.0 && transform[4] == 0.0) {
+        west = static_cast<REAL8>(transform[0]);
+        north = static_cast<REAL8>(transform[3]);
+        cellSize = static_cast<REAL8>(transform[1]);
+      }
+    }
+    (void)RputXUL(d_dataset->map(), west);
+    (void)RputYUL(d_dataset->map(), north);
+    (void)RputCellSize(d_dataset->map(), cellSize);
+  }
+
+  int nr_cols = this->poDS->GetRasterXSize();
+
+  // new maps from create() set min/max to MV
+  // in case of reopening that map the min/max
+  // value tracking is disabled (MM_WRONGVALUE)
+  // reactivate it again to ensure that the output will
+  // get the correct values when values are written to map
+  d_dataset->map()->minMaxStatus = MM_KEEPTRACK;
+
+  // allocate memory for row
+  void* buffer = Rmalloc(d_dataset->map(), nr_cols);
+  memcpy(buffer, source, nr_cols * 4);
+
+  // convert source no_data values to MV in dest
+  if((valuescale == VS_BOOLEAN) || (valuescale == VS_LDD)) {
+    alterToStdMV(buffer, nr_cols, CR_UINT1, d_missing_value);
+  }
+  if((valuescale == VS_SCALAR) || (valuescale == VS_DIRECTION)) {
+    alterToStdMV(buffer, nr_cols, CR_REAL4, d_missing_value);
+  }
+  if((valuescale == VS_NOMINAL)|| (valuescale == VS_ORDINAL)) {
+    alterToStdMV(buffer, nr_cols, CR_INT4, d_missing_value);
+  }
+
+  // conversion of values according to value scale
+  if(valuescale == VS_BOOLEAN) {
+    castValuesToBooleanRange(buffer, nr_cols, CR_UINT1);
+  }
+  if(valuescale == VS_LDD) {
+    castValuesToLddRange(buffer, nr_cols);
+  }
+  if(valuescale == VS_DIRECTION) {
+    castValuesToDirectionRange(buffer, nr_cols);
+  }
+
+  RputRow(d_dataset->map(), nBlockYoff, buffer);
+  free(buffer);
+
+  return CE_None;
+}
+
+
+CPLErr PCRasterRasterBand::SetNoDataValue(double nodata){
+  d_missing_value = nodata;
+
+  return CE_None;
+}
+
+
 
 //------------------------------------------------------------------------------
 // DEFINITION OF FREE OPERATORS
@@ -277,6 +398,3 @@ CPLErr PCRasterRasterBand::IReadBlock(
 //------------------------------------------------------------------------------
 // DEFINITION OF FREE FUNCTIONS
 //------------------------------------------------------------------------------
-
-
-
diff --git a/frmts/pcraster/pcrasterrasterband.h b/frmts/pcraster/pcrasterrasterband.h
index c8eb18c..35acc78 100644
--- a/frmts/pcraster/pcrasterrasterband.h
+++ b/frmts/pcraster/pcrasterrasterband.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterrasterband.h 13149 2007-11-29 15:08:00Z warmerdam $
+ * $Id: pcrasterrasterband.h 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster raster band declaration.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -31,15 +31,15 @@
 #define INCLUDED_PCRASTERRASTERBAND
 
 // Library headers.
-
-// PCRaster library headers.
-
-// Module headers.
 #ifndef INCLUDED_GDAL_PAM
 #include "gdal_pam.h"
 #define INCLUDED_GDAL_PAM
 #endif
 
+// PCRaster library headers.
+
+// Module headers.
+
 
 
 // namespace {
@@ -64,6 +64,16 @@ private:
   //! Dataset this band is part of. For use only.
   PCRasterDataset const* d_dataset;
 
+  double           d_missing_value;
+
+  GDALDataType     d_create_in;
+
+  virtual CPLErr   IRasterIO           (GDALRWFlag, int, int, int, int,
+                                        void *, int, int, GDALDataType,
+                                        GSpacing nPixelSpace,
+                                        GSpacing nLineSpace,
+                                        GDALRasterIOExtraArg* psExtraArg);
+
   //! Assignment operator. NOT IMPLEMENTED.
   PCRasterRasterBand& operator=        (const PCRasterRasterBand&);
 
@@ -92,7 +102,13 @@ public:
   // MANIPULATORS
   //----------------------------------------------------------------------------
 
-  //----------------------------------------------------------------------------
+  CPLErr           IWriteBlock         (CPL_UNUSED int nBlockXoff,
+                                        int nBlockYoff,
+                                        void* buffer);
+
+  CPLErr           SetNoDataValue      (double no_data);
+
+ //----------------------------------------------------------------------------
   // ACCESSORS
   //----------------------------------------------------------------------------
 
diff --git a/frmts/pcraster/pcrasterutil.cpp b/frmts/pcraster/pcrasterutil.cpp
index df3599b..802c711 100644
--- a/frmts/pcraster/pcrasterutil.cpp
+++ b/frmts/pcraster/pcrasterutil.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterutil.cpp 15450 2008-10-03 10:59:32Z kdejong $
+ * $Id: pcrasterutil.cpp 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster driver support functions.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -314,8 +314,8 @@ CSF_VS GDALType2ValueScale(
              complex.
 
   If exact is false, conversion to CSF2.0 types will take place. This is
-  usefull for in file cell representations. If exact is true, and exact match
-  is made. This is usefull for in app cell representations.
+  useful for in file cell representations. If exact is true, and exact match
+  is made. This is useful for in app cell representations.
 
   If exact is false, this function always returns one of CR_UINT1, CR_INT4
   or CR_REAL4.
@@ -712,3 +712,24 @@ void castValuesToBooleanRange(
   }
 }
 
+
+
+void castValuesToDirectionRange(
+         void* buffer,
+         size_t size)
+{
+  std::for_each(static_cast<REAL4*>(buffer),
+       static_cast<REAL4*>(buffer) + size,
+       CastToDirection());
+}
+
+
+
+void castValuesToLddRange(
+         void* buffer,
+         size_t size)
+{
+  std::for_each(static_cast<UINT1*>(buffer),
+       static_cast<UINT1*>(buffer) + size,
+       CastToLdd());
+}
\ No newline at end of file
diff --git a/frmts/pcraster/pcrasterutil.h b/frmts/pcraster/pcrasterutil.h
index b318284..6ad55e6 100644
--- a/frmts/pcraster/pcrasterutil.h
+++ b/frmts/pcraster/pcrasterutil.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: pcrasterutil.h 15451 2008-10-03 10:59:42Z kdejong $
+ * $Id: pcrasterutil.h 28862 2015-04-07 10:10:25Z kdejong $
  *
  * Project:  PCRaster Integration
  * Purpose:  PCRaster driver support declarations.
- * Author:   Kor de Jong, k.dejong at geog.uu.nl
+ * Author:   Kor de Jong, Oliver Schmitz
  *
  ******************************************************************************
- * Copyright (c) 2004, Kor de Jong
+ * Copyright (c) PCRaster owners
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -101,6 +101,13 @@ void               castValuesToBooleanRange(
                                         size_t size,
                                         CSF_CR cellRepresentation);
 
+void               castValuesToDirectionRange(
+                                        void* buffer,
+                                        size_t size);
+
+void               castValuesToLddRange(void* buffer,
+                                        size_t size);
+
 template<typename T>
 struct CastToBooleanRange
 {
@@ -151,3 +158,32 @@ struct CastToBooleanRange<UINT4>
     }
   }
 };
+
+
+struct CastToDirection
+{
+  void operator()(REAL4& value) {
+    REAL4 factor = M_PI / 180.0;
+    if(!pcr::isMV(value)) {
+      value = REAL4(value * factor);
+    }
+  }
+};
+
+
+
+struct CastToLdd
+{
+  void operator()(UINT1& value) {
+    if(!pcr::isMV(value)) {
+      if((value < 1) || (value > 9)) {
+        CPLError(CE_Warning, CPLE_IllegalArg,
+         "PCRaster driver: incorrect LDD value used, assigned MV instead");
+        pcr::setMV(value);
+      }
+      else {
+        value = UINT1(value);
+      }
+    }
+  }
+};
\ No newline at end of file
diff --git a/frmts/pdf/GNUmakefile b/frmts/pdf/GNUmakefile
index ec632f1..208632c 100644
--- a/frmts/pdf/GNUmakefile
+++ b/frmts/pdf/GNUmakefile
@@ -1,8 +1,7 @@
-
-OBJ	=	pdfdataset.o pdfio.o pdfobject.o pdfcreatecopy.o
-
 include ../../GDALmake.opt
 
+OBJ	=	pdfdataset.o pdfio.o pdfobject.o pdfcreatecopy.o ogrpdflayer.o pdfwritabledataset.o pdfreadvectors.o
+
 ifeq ($(HAVE_POPPLER),yes)
 CPPFLAGS +=  -DHAVE_POPPLER
 endif
@@ -27,9 +26,9 @@ ifeq ($(HAVE_PODOFO),yes)
 CPPFLAGS +=  -DHAVE_PODOFO
 endif
 
-$(O_OBJ):       pdfobject.h pdfio.h pdfcreatecopy.h
+$(O_OBJ):       pdfobject.h pdfio.h pdfcreatecopy.h gdal_pdf.h
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) -I../vrt $(POPPLER_INC) $(PODOFO_INC)
+CPPFLAGS	:=	 $(CPPFLAGS) -I../vrt -I../mem -I../../ogr/ogrsf_frmts/mem $(POPPLER_INC) $(PODOFO_INC)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/pdf/frmt_pdf.html b/frmts/pdf/frmt_pdf.html
index 606a6db..d373215 100644
--- a/frmts/pdf/frmt_pdf.html
+++ b/frmts/pdf/frmt_pdf.html
@@ -1,5 +1,6 @@
 <html>
 <head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>Geospatial PDF</title>
 </head>
 
@@ -18,10 +19,10 @@ also optionally be drawn on top of the raster layer (see OGR_* creation options
 GDAL must be compiled with libpoppler support (GPL-licensed), and libpoppler itself must have been configured with
 --enable-xpdf-headers so that the xpdf C++ headers are available. Note: the poppler C++ API isn't
 stable, so the driver compilation may fail with too old or too recent poppler versions.
-Successfully tested versions are poppler >= 0.12.X and <= 0.24.0.
+Successfully tested versions are poppler >= 0.12.X and <= 0.26.0.
 <p>
 Starting with GDAL 1.9.0, as an alternative, the PDF driver can be compiled against libpodofo (LGPL-licensed)
-to avoid the libpoppler dependency. This is sufficient to get the georeferencing information. However, for
+to avoid the libpoppler dependency. This is sufficient to get the georeferencing and vector information. However, for
 getting the imagery, the pdftoppm utility that comes with the poppler distribution must be available in the system PATH.
 A temporary file will be generated in a directory determined by the following configuration options : CPL_TMPDIR,
 TMPDIR or TEMP (in that order). If none are defined, the current directory will be used.
@@ -42,6 +43,49 @@ Starting with GDAL 1.10.0, additional metadata, such as found in USGS Topo PDF c
 stored as XML raw content in the EMBEDDED_METADATA metadata domain.
 <p>
 
+<h2>Vector support</h2>
+
+<p>
+Starting with GDAL 1.10, this driver can read and write geospatial PDF with vector features.
+Vector read support requires linking to podofo or poppler libraries, but write support does not.
+
+The driver can read vector features encoded according to PDF's logical structure facilities (as described by "§10.6 - Logical Structure" of PDF spec),
+or retrieve only vector geometries for other vector PDF files.<p>
+
+<h2>Feature style support</h2>
+
+For write support, the driver has partial support for the style information attached to features,
+encoded according to the <a href="ogr_feature_style.html">OGR Feature Style Specification</a>.<p>
+
+The following tools are recognized :
+<ul>
+<li>For points, LABEL and SYMBOL.</li>
+<li>For lines, PEN.</li>
+<li>For polygons, PEN and BRUSH.</li>
+</ul>
+
+The supported attributes for each tool are summed up in the following table :<p>
+
+<table border="1">
+
+<tr>
+<th>Tool</th>
+<th>Supported attributes</th>
+<th>Example</th>
+</tr>
+
+<tr><td>PEN</td><td>color, width and dash pattern</td><td>PEN(c:#FF0000,w:5px)</td></tr>
+<tr><td>BRUSH</td><td>foreground color</td><td>BRUSH(fc:#0000FF)</td></tr>
+<tr><td>LABEL</td><td>text (limited to ASCII strings), foreground color, size, x and y offsets, and angle</td><td>LABEL(c:#000000,t:"Hello World!",s:5)</td></tr>
+<tr><td>SYMBOL</td><td>id (ogr-sym-0 to ogr-sym-9, and filenames for raster symbols), color and size</td>
+<td>SYMBOL(c:#00FF00,id:"ogr-sym-3",s:10)<br>SYMBOL(c:#00000080,id:"a_symbol.png")</td></tr>
+</table>
+<p>
+
+Alpha values are supported for colors to control the opacity. If not specified, for BRUSH, it is set at 50% opaque.<p>
+
+For SYMBOL with a bitmap name, only the alpha value of the color specified with 'c' is taken into account.<p>
+
 <h2>Configuration options</h2>
 
 <ul>
@@ -72,7 +116,7 @@ querying the LAYERS metadata domain.</li>
 <h2>LAYERS Metadata domain</h2>
 
 Starting with GDAL >= 1.10.0 and when GDAL is compiled against libpoppler, the LAYERS metadata domain can be queried
-to retrieve layer names that can be turned ON or OFF. This is usefull to know which values to specify for the
+to retrieve layer names that can be turned ON or OFF. This is useful to know which values to specify for the
 <i>GDAL_PDF_LAYERS</i> or <i>GDAL_PDF_LAYERS_OFF</i> configuration options.<p>
 
 For example :
@@ -172,7 +216,7 @@ specified, all the extra rasters will be placed in the default layer.</p></li>
 the /FTimesRoman and /FTimesBold fonts.</p></li>
 
 <li><p><b>EXTRA_IMAGES=image_file_name,x,y,scale[,link=some_url] (possibly repeated)</b>: A list of (ungeoreferenced) images to insert into
-the page as extra content. This is usefull to insert logos, legends, etc...
+the page as extra content. This is useful to insert logos, legends, etc...
 x and y are in user units from the lower left corner of the page, and the anchor point is the lower left pixel of the image.
 scale is a magnifying ratio (use 1 if unsure). If link=some_url is specified, the image will be selectable and its selection
 will cause a web browser to be opened on the specified URL.</p></li>
@@ -230,7 +274,7 @@ EXTRA_LAYER_NAME and OGR_DISPLAY_LAYER_NAMES.</p></li>
 <li><p><b>EXCLUSIVE_LAYERS=names</b>:
 Comma separated list of layer names, such that only one of those layers can be visible at a time.
 This is the behaviour of radio-buttons in a graphical user interface.
- he layer names can come from LAYER_NAME (main raster layer name), EXTRA_RASTERS_LAYER_NAME,
+ The layer names can come from LAYER_NAME (main raster layer name), EXTRA_RASTERS_LAYER_NAME,
 EXTRA_LAYER_NAME and OGR_DISPLAY_LAYER_NAMES.
 </p></li>
 
@@ -288,15 +332,10 @@ if (button == 4) app.launchURL('http://gdal.org/');
 
 <h2>See also</h2>
 
-Other drivers :
-<ul>
-<li><a href="../ogr/drv_pdf.html">OGR PDF driver</a></li>
-</ul>
-<p>
-
 Specifications :
 
 <ul>
+<li><a href="ogr/ogr_feature_style.html">OGR Feature Style Specification</a></li>
 <li><a href="http://portal.opengeospatial.org/files/?artifact_id=40537">OGC GeoPDF Encoding Best Practice Version 2.2 (08-139r3)</a></li>
 <li><a href="http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf">Adobe Supplement to ISO 32000</a></li>
 <li><a href="http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf">PDF Reference, version 1.7</a></li>
diff --git a/frmts/pdf/gdal_pdf.h b/frmts/pdf/gdal_pdf.h
new file mode 100644
index 0000000..2599d46
--- /dev/null
+++ b/frmts/pdf/gdal_pdf.h
@@ -0,0 +1,372 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  PDF Translator
+ * Purpose:  Definition of classes for OGR .pdf driver.
+ * Author:   Even Rouault, even dot rouault at mines dash paris dot org
+ *
+ ******************************************************************************
+ * Copyright (c) 2010-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _GDAL_PDF_H_INCLUDED
+#define _GDAL_PDF_H_INCLUDED
+
+#ifdef HAVE_POPPLER
+
+/* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
+/* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
+#define CPL_GBOOL_DEFINED
+#define OGR_FEATURESTYLE_INCLUDE
+
+#include <goo/gtypes.h>
+#endif
+
+#include "gdal_pam.h"
+#include "ogrsf_frmts.h"
+
+#include "ogr_mem.h"
+#include "pdfobject.h"
+
+#include <map>
+#include <stack>
+
+/************************************************************************/
+/*                             OGRPDFLayer                              */
+/************************************************************************/
+
+#if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+
+class PDFDataset;
+
+class OGRPDFLayer : public OGRMemLayer
+{
+    PDFDataset       *poDS;
+    int               bGeomTypeSet;
+    int               bGeomTypeMixed;
+
+public:
+        OGRPDFLayer(PDFDataset* poDS,
+                    const char * pszName,
+                    OGRSpatialReference *poSRS,
+                    OGRwkbGeometryType eGeomType);
+
+    void                Fill( GDALPDFArray* poArray );
+
+    virtual int                 TestCapability( const char * );
+};
+
+#endif
+
+/************************************************************************/
+/*                          OGRPDFWritableLayer                         */
+/************************************************************************/
+
+class PDFWritableVectorDataset;
+
+class OGRPDFWritableLayer : public OGRMemLayer
+{
+    PDFWritableVectorDataset       *poDS;
+
+public:
+        OGRPDFWritableLayer(PDFWritableVectorDataset* poDS,
+                    const char * pszName,
+                    OGRSpatialReference *poSRS,
+                    OGRwkbGeometryType eGeomType);
+
+    virtual int                 TestCapability( const char * );
+    virtual OGRErr              ICreateFeature( OGRFeature *poFeature );
+};
+
+/************************************************************************/
+/*                            GDALPDFTileDesc                           */
+/************************************************************************/
+
+typedef struct
+{
+    GDALPDFObject* poImage;
+    double         adfCM[6];
+    double         dfWidth;
+    double         dfHeight;
+    int            nBands;
+} GDALPDFTileDesc;
+
+/************************************************************************/
+/* ==================================================================== */
+/*                              PDFDataset                              */
+/* ==================================================================== */
+/************************************************************************/
+
+class PDFRasterBand;
+class PDFImageRasterBand;
+
+#ifdef HAVE_POPPLER
+class ObjectAutoFree;
+#endif
+
+#define MAX_TOKEN_SIZE 256
+#define TOKEN_STACK_SIZE 8
+
+#if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+
+class PDFDataset : public GDALPamDataset
+{
+    friend class PDFRasterBand;
+    friend class PDFImageRasterBand;
+
+    CPLString    osFilename;
+    CPLString    osUserPwd;
+    char        *pszWKT;
+    double       dfDPI;
+    int          bHasCTM;
+    double       adfCTM[6];
+    double       adfGeoTransform[6];
+    int          bGeoTransformValid;
+    int          nGCPCount;
+    GDAL_GCP    *pasGCPList;
+    int          bProjDirty;
+    int          bNeatLineDirty;
+
+    GDALMultiDomainMetadata oMDMD;
+    int          bInfoDirty;
+    int          bXMPDirty;
+
+    int          bUsePoppler;
+#ifdef HAVE_POPPLER
+    PDFDoc*      poDocPoppler;
+#endif
+#ifdef HAVE_PODOFO
+    PoDoFo::PdfMemDocument* poDocPodofo;
+    int          bPdfToPpmFailed;
+#endif
+    GDALPDFObject* poPageObj;
+
+    int          iPage;
+
+    GDALPDFObject *poImageObj;
+
+    double       dfMaxArea;
+    int          ParseLGIDictObject(GDALPDFObject* poLGIDict);
+    int          ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict, int* pbIsBestCandidate = NULL);
+    int          ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict);
+    int          ParseProjDict(GDALPDFDictionary* poProjDict);
+    int          ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight);
+    int          ParseMeasure(GDALPDFObject* poMeasure,
+                              double dfMediaBoxWidth, double dfMediaBoxHeight,
+                              double dfULX, double dfULY, double dfLRX, double dfLRY);
+
+    int          bTried;
+    GByte       *pabyCachedData;
+    int          nLastBlockXOff, nLastBlockYOff;
+
+    OGRPolygon*  poNeatLine;
+
+    std::vector<GDALPDFTileDesc> asTiles; /* in the order of the PDF file */
+    std::vector<int> aiTiles; /* in the order of blocks */
+    int          nBlockXSize;
+    int          nBlockYSize;
+    int          CheckTiledRaster();
+
+    void         GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands);
+    void         FindXMP(GDALPDFObject* poObj);
+    void         ParseInfo(GDALPDFObject* poObj);
+
+#ifdef HAVE_POPPLER
+    ObjectAutoFree* poCatalogObjectPoppler;
+#endif
+    GDALPDFObject* poCatalogObject;
+    GDALPDFObject* GetCatalog();
+
+#ifdef HAVE_POPPLER
+    void         AddLayer(const char* pszLayerName, OptionalContentGroup* ocg);
+    void         ExploreLayers(GDALPDFArray* poArray, int nRecLevel, CPLString osTopLayer = "");
+    void         FindLayers();
+    void         TurnLayersOnOff();
+    CPLStringList osLayerList;
+    std::map<CPLString, OptionalContentGroup*> oLayerOCGMap;
+#endif
+
+    CPLStringList osLayerWithRefList;
+    CPLString     FindLayerOCG(GDALPDFDictionary* poPageDict,
+                               const char* pszLayerName);
+    void          FindLayersGeneric(GDALPDFDictionary* poPageDict);
+
+    int          bUseOCG;
+
+    char       **papszOpenOptions;
+    static const char*  GetOption(char** papszOpenOptions,
+                                  const char* pszOptionName,
+                                  const char* pszDefaultVal);
+
+    int                 nLayers;
+    OGRLayer          **papoLayers;
+
+    double              dfPageWidth;
+    double              dfPageHeight;
+    void                PDFCoordsToSRSCoords(double x, double y,
+                                             double& X, double &Y);
+
+    std::map<int,OGRGeometry*> oMapMCID;
+    void                CleanupIntermediateResources();
+
+    std::map<CPLString, int> oMapOperators;
+    void                InitMapOperators();
+    
+    int                 bSetStyle;
+
+    void                ExploreTree(GDALPDFObject* poObj, int nRecLevel);
+    void                ExploreContents(GDALPDFObject* poObj, GDALPDFObject* poResources);
+
+    void                ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
+                                                             GDALPDFObject* poResources,
+                                                             std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer);
+    void                ExploreContentsNonStructured(GDALPDFObject* poObj, GDALPDFObject* poResources);
+
+    int                 UnstackTokens(const char* pszToken,
+                                      int nRequiredArgs,
+                                      char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
+                                      int& nTokenStackSize,
+                                      double* adfCoords);
+    OGRGeometry*        ParseContent(const char* pszContent,
+                                     GDALPDFObject* poResources,
+                                     int bInitBDCStack,
+                                     int bMatchQ,
+                                     std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
+                                     OGRPDFLayer* poCurLayer);
+    OGRGeometry*        BuildGeometry(std::vector<double>& oCoords,
+                                      int bHasFoundFill,
+                                      int bHasMultiPart);
+
+    int                 OpenVectorLayers(GDALPDFDictionary* poPageDict);
+
+  public:
+                 PDFDataset();
+    virtual     ~PDFDataset();
+
+    virtual const char* GetProjectionRef();
+    virtual CPLErr GetGeoTransform( double * );
+
+    virtual CPLErr      SetProjection(const char* pszWKTIn);
+    virtual CPLErr      SetGeoTransform(double* padfGeoTransform);
+
+    virtual char      **GetMetadataDomainList();
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                     const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                         const char * pszValue,
+                                         const char * pszDomain = "" );
+
+    virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
+                              void *, int, int, GDALDataType,
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
+
+    virtual int    GetGCPCount();
+    virtual const char *GetGCPProjection();
+    virtual const GDAL_GCP *GetGCPs();
+    virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
+                            const char *pszGCPProjection );
+
+    CPLErr ReadPixels( int nReqXOff, int nReqYOff,
+                       int nReqXSize, int nReqYSize,
+                       GSpacing nPixelSpace,
+                       GSpacing nLineSpace,
+                       GSpacing nBandSpace,
+                       GByte* pabyData );
+
+    virtual int                 GetLayerCount();
+    virtual OGRLayer*           GetLayer( int );
+
+    virtual int                 TestCapability( const char * );
+
+    OGRGeometry        *GetGeometryFromMCID(int nMCID);
+
+    static GDALDataset *Open( GDALOpenInfo * );
+    static int          Identify( GDALOpenInfo * );
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                         PDFRasterBand                                */
+/* ==================================================================== */
+/************************************************************************/
+
+class PDFRasterBand : public GDALPamRasterBand
+{
+    friend class PDFDataset;
+
+    CPLErr IReadBlockFromTile( int, int, void * );
+
+  public:
+
+                PDFRasterBand( PDFDataset *, int );
+
+    virtual CPLErr IReadBlock( int, int, void * );
+    virtual GDALColorInterp GetColorInterpretation();
+};
+
+#endif /*  defined(HAVE_POPPLER) || defined(HAVE_PODOFO) */
+
+/************************************************************************/
+/*                          PDFWritableDataset                          */
+/************************************************************************/
+
+class PDFWritableVectorDataset : public GDALDataset
+{
+        char**              papszOptions;
+
+        int                 nLayers;
+        OGRLayer          **papoLayers;
+
+        int                 bModified;
+
+    public:
+                            PDFWritableVectorDataset();
+                           ~PDFWritableVectorDataset();
+
+        virtual OGRLayer*           ICreateLayer( const char * pszLayerName,
+                                                OGRSpatialReference *poSRS,
+                                                OGRwkbGeometryType eType,
+                                                char ** papszOptions );
+
+        virtual OGRErr              SyncToDisk();
+
+        virtual int                 GetLayerCount();
+        virtual OGRLayer*           GetLayer( int );
+
+        virtual int                 TestCapability( const char * );
+
+        static GDALDataset* Create( const char * pszName,
+                                 int nXSize, int nYSize, int nBands,
+                                 GDALDataType eType, char ** papszOptions );
+
+        void                SetModified() { bModified = TRUE; }
+};
+
+GDALDataset* GDALPDFOpen(const char* pszFilename, GDALAccess eAccess);
+CPLString PDFSanitizeLayerName(const char* pszName);
+
+#endif /* ndef _GDAL_PDF_H_INCLUDED */
diff --git a/frmts/pdf/makefile.vc b/frmts/pdf/makefile.vc
index 30cc7eb..07867fe 100644
--- a/frmts/pdf/makefile.vc
+++ b/frmts/pdf/makefile.vc
@@ -1,11 +1,17 @@
 
-OBJ	=	pdfdataset.obj pdfio.obj pdfobject.obj pdfcreatecopy.obj
+OBJ	=	pdfdataset.obj pdfio.obj pdfobject.obj pdfcreatecopy.obj ogrpdflayer.obj pdfwritabledataset.obj pdfreadvectors.obj
+
+PLUGIN_DLL =	gdal_PDF.dll
 
 GDAL_ROOT	=	..\..
 
 !INCLUDE $(GDAL_ROOT)\nmake.opt
 
-EXTRAFLAGS = -I..\vrt $(POPPLER_EXTRAFLAGS) $(PODOFO_EXTRAFLAGS)
+!IFDEF PDF_PLUGIN
+OBJ = $(OBJ) ..\..\ogr\ogrsf_frmts\mem\ogrmemdatasource.obj ..\..\ogr\ogrsf_frmts\mem\ogrmemdriver.obj ..\..\ogr\ogrsf_frmts\mem\ogrmemlayer.obj
+!ENDIF
+
+EXTRAFLAGS =  -I..\vrt -I..\mem -I..\..\ogr\ogrsf_frmts\mem $(POPPLER_EXTRAFLAGS) $(PODOFO_EXTRAFLAGS)
 
 !IFDEF POPPLER_ENABLED
 POPPLER_EXTRAFLAGS = $(POPPLER_CFLAGS) $(POPPLER_HAS_OPTCONTENT_FLAGS) $(POPPLER_BASE_STREAM_HAS_TWO_ARGS_FLAGS) $(POPPLER_0_20_OR_LATER_FLAGS) $(POPPLER_0_23_OR_LATER_FLAGS) -DHAVE_POPPLER
@@ -37,4 +43,13 @@ default:	$(OBJ)
 
 clean:
 	-del *.obj
+	
+plugin:	$(PLUGIN_DLL)
+
+$(PLUGIN_DLL): $(OBJ)
+	link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) $(GDALLIB) $(POPPLER_LIBS) $(PODOFO_LIBS)
+	if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2
 
+plugin-install:
+	-mkdir $(PLUGINDIR)
+	$(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR)
\ No newline at end of file
diff --git a/frmts/pdf/ogrpdflayer.cpp b/frmts/pdf/ogrpdflayer.cpp
new file mode 100644
index 0000000..263494f
--- /dev/null
+++ b/frmts/pdf/ogrpdflayer.cpp
@@ -0,0 +1,209 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  PDF Translator
+ * Purpose:  Implements OGRPDFDataSource class
+ * Author:   Even Rouault, even dot rouault at mines dash paris dot org
+ *
+ ******************************************************************************
+ * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdal_pdf.h"
+
+CPL_CVSID("$Id$");
+
+#if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+
+/************************************************************************/
+/*                            OGRPDFLayer()                             */
+/************************************************************************/
+
+OGRPDFLayer::OGRPDFLayer( PDFDataset* poDS,
+                          const char * pszName,
+                          OGRSpatialReference *poSRS,
+                          OGRwkbGeometryType eGeomType ) :
+                                OGRMemLayer(pszName, poSRS, eGeomType )
+{
+    this->poDS = poDS;
+    bGeomTypeSet = FALSE;
+    bGeomTypeMixed = FALSE;
+}
+
+/************************************************************************/
+/*                              Fill()                                  */
+/************************************************************************/
+
+void OGRPDFLayer::Fill( GDALPDFArray* poArray )
+{
+    for(int i=0;i<poArray->GetLength();i++)
+    {
+        GDALPDFObject* poFeatureObj = poArray->Get(i);
+        if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
+            continue;
+
+        GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
+        if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
+            continue;
+
+        GDALPDFObject* poP = poA->GetDictionary()->Get("P");
+        if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
+            continue;
+
+        GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
+        int nK = -1;
+        if (poK != NULL && poK->GetType() == PDFObjectType_Int)
+            nK = poK->GetInt();
+
+        GDALPDFArray* poPArray = poP->GetArray();
+        int j;
+        for(j = 0;j<poPArray->GetLength();j++)
+        {
+            GDALPDFObject* poKV = poPArray->Get(j);
+            if (poKV->GetType() == PDFObjectType_Dictionary)
+            {
+                GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
+                GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
+                if (poN != NULL && poN->GetType() == PDFObjectType_String &&
+                    poV != NULL)
+                {
+                    int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
+                    OGRFieldType eType = OFTString;
+                    if (poV->GetType() == PDFObjectType_Int)
+                        eType = OFTInteger;
+                    else if (poV->GetType() == PDFObjectType_Real)
+                        eType = OFTReal;
+                    if (nIdx < 0)
+                    {
+                        OGRFieldDefn oField(poN->GetString().c_str(), eType);
+                        CreateField(&oField);
+                    }
+                    else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
+                                GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
+                    {
+                        OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
+                        AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
+                    }
+                }
+            }
+        }
+
+        OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
+        for(j = 0;j<poPArray->GetLength();j++)
+        {
+            GDALPDFObject* poKV = poPArray->Get(j);
+            if (poKV->GetType() == PDFObjectType_Dictionary)
+            {
+                GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
+                GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
+                if (poN != NULL && poN->GetType() == PDFObjectType_String &&
+                    poV != NULL)
+                {
+                    if (poV->GetType() == PDFObjectType_String)
+                        poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
+                    else if (poV->GetType() == PDFObjectType_Int)
+                        poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
+                    else if (poV->GetType() == PDFObjectType_Real)
+                        poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
+                }
+            }
+        }
+
+        if (nK >= 0)
+        {
+            OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
+            if (poGeom)
+            {
+                poGeom->assignSpatialReference(GetSpatialRef());
+                poFeature->SetGeometry(poGeom);
+            }
+        }
+
+        OGRGeometry* poGeom = poFeature->GetGeometryRef();
+        if( !bGeomTypeMixed && poGeom != NULL )
+        {
+            if (!bGeomTypeSet)
+            {
+                bGeomTypeSet = TRUE;
+                GetLayerDefn()->SetGeomType(poGeom->getGeometryType());
+            }
+            else if (GetLayerDefn()->GetGeomType() != poGeom->getGeometryType())
+            {
+                bGeomTypeMixed = TRUE;
+                GetLayerDefn()->SetGeomType(wkbUnknown);
+            }
+        }
+        ICreateFeature(poFeature);
+
+        delete poFeature;
+    }
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRPDFLayer::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,OLCStringsAsUTF8) )
+        return TRUE;
+    else
+        return OGRMemLayer::TestCapability(pszCap);
+}
+
+#endif /* defined(HAVE_POPPLER) || defined(HAVE_PODOFO) */
+
+/************************************************************************/
+/*                        OGRPDFWritableLayer()                         */
+/************************************************************************/
+
+OGRPDFWritableLayer::OGRPDFWritableLayer( PDFWritableVectorDataset* poDS,
+                          const char * pszName,
+                          OGRSpatialReference *poSRS,
+                          OGRwkbGeometryType eGeomType ) :
+                                OGRMemLayer(pszName, poSRS, eGeomType )
+{
+    this->poDS = poDS;
+}
+
+/************************************************************************/
+/*                           ICreateFeature()                           */
+/************************************************************************/
+
+OGRErr OGRPDFWritableLayer::ICreateFeature( OGRFeature *poFeature )
+{
+    poDS->SetModified();
+    return OGRMemLayer::ICreateFeature(poFeature);
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRPDFWritableLayer::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,OLCStringsAsUTF8) )
+        return TRUE;
+    else
+        return OGRMemLayer::TestCapability(pszCap);
+}
diff --git a/frmts/pdf/pdfcreatecopy.cpp b/frmts/pdf/pdfcreatecopy.cpp
index 7a977bd..773b8e9 100644
--- a/frmts/pdf/pdfcreatecopy.cpp
+++ b/frmts/pdf/pdfcreatecopy.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdfcreatecopy.cpp 27991 2014-11-21 09:09:00Z rouault $
+ * $Id: pdfcreatecopy.cpp 28780 2015-03-26 12:29:35Z rouault $
  *
  * Project:  PDF driver
  * Purpose:  GDALDataset driver for PDF dataset.
@@ -27,11 +27,7 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-/* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
-/* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
-#define CPL_GBOOL_DEFINED
-
-#include "pdfdataset.h"
+#include "gdal_pdf.h"
 #include "pdfcreatecopy.h"
 
 #include "cpl_vsi_virtual.h"
@@ -50,7 +46,7 @@
 /* Cf PDF reference v1.7, Appendix C, page 993 */
 #define MAXIMUM_SIZE_IN_UNITS   14400
 
-CPL_CVSID("$Id: pdfcreatecopy.cpp 27991 2014-11-21 09:09:00Z rouault $");
+CPL_CVSID("$Id: pdfcreatecopy.cpp 28780 2015-03-26 12:29:35Z rouault $");
 
 #define PIXEL_TO_GEO_X(x,y) adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2]
 #define PIXEL_TO_GEO_Y(x,y) adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5]
@@ -843,6 +839,8 @@ static GDALPDFObject* GDALPDFBuildOGC_BP_Datum(const OGRSpatialReference* poSRS)
             poPDFDatum = GDALPDFObjectRW::CreateString("NAS");
         else if( EQUAL(pszDatumDescription, SRS_DN_NAD83) || nEPSGDatum == 6269 )
             poPDFDatum = GDALPDFObjectRW::CreateString("NAR");
+        else if( nEPSGDatum == 6135 )
+            poPDFDatum = GDALPDFObjectRW::CreateString("OHA-M");
         else
         {
             CPLDebug("PDF",
@@ -3000,9 +2998,9 @@ int GDALPDFWriter::EndPage(const char* pszExtraImages,
         for(int i=0;i+4<=nCount; /* */)
         {
             const char* pszImageFilename = papszExtraImagesTokens[i+0];
-            double dfX = atof(papszExtraImagesTokens[i+1]);
-            double dfY = atof(papszExtraImagesTokens[i+2]);
-            double dfScale = atof(papszExtraImagesTokens[i+3]);
+            double dfX = CPLAtof(papszExtraImagesTokens[i+1]);
+            double dfY = CPLAtof(papszExtraImagesTokens[i+2]);
+            double dfScale = CPLAtof(papszExtraImagesTokens[i+3]);
             const char* pszLinkVal = NULL;
             i += 4;
             if( i < nCount && EQUALN(papszExtraImagesTokens[i],"link=",5) )
@@ -3416,7 +3414,7 @@ int GDALPDFWriter::WriteMask(GDALDataset* poSrcDS,
             nXOff, nYOff,
             nReqXSize, nReqYSize,
             pabyMask, nReqXSize, nReqYSize, GDT_Byte,
-            0, 0);
+            0, 0, NULL);
     if (eErr != CE_None)
     {
         VSIFree(pabyMask);
@@ -3673,7 +3671,7 @@ int GDALPDFWriter::WriteBlock(GDALDataset* poSrcDS,
                                 nReqXSize, nReqYSize,
                                 pabyMEMDSBuffer, nReqXSize, nReqYSize,
                                 GDT_Byte, nBands, NULL,
-                                0, 0, 0);
+                                0, 0, 0, NULL);
 
         if( eErr != CE_None )
         {
@@ -3857,7 +3855,7 @@ int GDALPDFWriter::WriteBlock(GDALDataset* poSrcDS,
             eErr = poBlockSrcDS->RasterIO(GF_Read,
                                           0, iLine, nReqXSize, 1,
                                           pabyLine, nReqXSize, 1, GDT_Byte,
-                                          nBands, NULL, nBands, 0, 1);
+                                          nBands, NULL, nBands, 0, 1, NULL);
             if( eErr != CE_None )
                 break;
 
diff --git a/frmts/pdf/pdfdataset.cpp b/frmts/pdf/pdfdataset.cpp
index 116cb74..4016a25 100644
--- a/frmts/pdf/pdfdataset.cpp
+++ b/frmts/pdf/pdfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdfdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: pdfdataset.cpp 28978 2015-04-23 09:14:09Z rouault $
  *
  * Project:  PDF driver
  * Purpose:  GDALDataset driver for PDF dataset.
@@ -27,14 +27,10 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-/* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
-/* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
-#define CPL_GBOOL_DEFINED
+#include "gdal_pdf.h"
 
-#include "pdfdataset.h"
 #include "cpl_vsi_virtual.h"
 #include "cpl_string.h"
-#include "gdal_pam.h"
 #include "ogr_spatialref.h"
 #include "ogr_geometry.h"
 #include "cpl_spawn.h"
@@ -43,31 +39,55 @@
 #include "cpl_multiproc.h"
 #include "pdfio.h"
 #include <goo/GooList.h>
-#endif
+#endif // HAVE_POPPLER
 
-#include "pdfobject.h"
 #include "pdfcreatecopy.h"
-
 #include <set>
-#include <map>
 
 #define GDAL_DEFAULT_DPI 150.0
 
 /* g++ -fPIC -g -Wall frmts/pdf/pdfdataset.cpp -shared -o gdal_PDF.so -Iport -Igcore -Iogr -L. -lgdal -lpoppler -I/usr/include/poppler */
 
-CPL_CVSID("$Id: pdfdataset.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: pdfdataset.cpp 28978 2015-04-23 09:14:09Z rouault $");
 
 CPL_C_START
 void    GDALRegister_PDF(void);
 CPL_C_END
 
 #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+static const char* pszOpenOptionList =
+"<OpenOptionList>"
+"  <Option name='RENDERING_OPTIONS' type='string-select' description='Which graphical elements to render' default='RASTER,VECTOR,TEXT' alt_config_option='GDAL_PDF_RENDERING_OPTIONS'>"
+"     <Value>RASTER,VECTOR,TEXT</Value>\n"
+"     <Value>RASTER,VECTOR</Value>\n"
+"     <Value>RASTER,TEXT</Value>\n"
+"     <Value>RASTER</Value>\n"
+"     <Value>VECTOR,TEXT</Value>\n"
+"     <Value>VECTOR</Value>\n"
+"     <Value>TEXT</Value>\n"
+"  </Option>"
+"  <Option name='DPI' type='float' description='Resolution in Dot Per Inch' default='72' alt_config_option='GDAL_PDF_DPI'/>"
+"  <Option name='USER_PWD' type='string' description='Password' alt_config_option='PDF_USER_PWD'/>"
+#if defined(HAVE_POPPLER) && defined(HAVE_PODOFO)
+"  <Option name='PDF_LIB' type='string-select' description='Which underlying PDF library to use' default='POPPLER' alt_config_option='GDAL_PDF_LIB'>"
+"     <Value>POPPLER</Value>\n"
+"     <Value>PODOFO</Value>\n"
+"  </Option>"
+#endif // HAVE_POPPLER && HAVE_PODOFO
+"  <Option name='LAYERS' type='string' description='List of layers (comma separated) to turn ON (or ALL to turn all layers ON)' alt_config_option='GDAL_PDF_LAYERS'/>"
+"  <Option name='LAYERS_OFF' type='string' description='List of layers (comma separated) to turn OFF' alt_config_option='GDAL_PDF_LAYERS_OFF'/>"
+"  <Option name='BANDS' type='string-select' description='Number of raster bands' default='3' alt_config_option='GDAL_PDF_BANDS'>"
+"     <Value>3</Value>\n"
+"     <Value>4</Value>\n"
+"  </Option>"
+"  <Option name='NEATLINE' type='string' description='The name of the neatline to select' alt_config_option='GDAL_PDF_NEATLINE'/>"
+"</OpenOptionList>";
 
 static double Get(GDALPDFObject* poObj, int nIndice = -1);
 
 #ifdef HAVE_POPPLER
 
-static void* hGlobalParamsMutex = NULL;
+static CPLMutex* hGlobalParamsMutex = NULL;
 
 /************************************************************************/
 /*                          ObjectAutoFree                              */
@@ -108,12 +128,9 @@ class GDALPDFOutputDev : public SplashOutputDev
 
     public:
         GDALPDFOutputDev(SplashColorMode colorModeA, int bitmapRowPadA,
-                         GBool reverseVideoA, SplashColorPtr paperColorA,
-                         GBool bitmapTopDownA = gTrue,
-                         GBool allowAntialiasA = gTrue) :
+                         GBool reverseVideoA, SplashColorPtr paperColorA) :
                 SplashOutputDev(colorModeA, bitmapRowPadA,
-                                reverseVideoA, paperColorA,
-                                bitmapTopDownA, allowAntialiasA),
+                                reverseVideoA, paperColorA),
                 bEnableVector(TRUE),
                 bEnableText(TRUE),
                 bEnableBitmap(TRUE) {}
@@ -495,174 +512,6 @@ void GDALPDFDumper::Dump(GDALPDFDictionary* poDict, int nDepth)
 }
 
 /************************************************************************/
-/*                            GDALPDFTileDesc                           */
-/************************************************************************/
-
-typedef struct
-{
-    GDALPDFObject* poImage;
-    double         adfCM[6];
-    double         dfWidth;
-    double         dfHeight;
-    int            nBands;
-} GDALPDFTileDesc;
-
-/************************************************************************/
-/* ==================================================================== */
-/*                              PDFDataset                              */
-/* ==================================================================== */
-/************************************************************************/
-
-class PDFRasterBand;
-class PDFImageRasterBand;
-
-class PDFDataset : public GDALPamDataset
-{
-    friend class PDFRasterBand;
-    friend class PDFImageRasterBand;
-
-    CPLString    osFilename;
-    CPLString    osUserPwd;
-    char        *pszWKT;
-    double       dfDPI;
-    int          bHasCTM;
-    double       adfCTM[6];
-    double       adfGeoTransform[6];
-    int          bGeoTransformValid;
-    int          nGCPCount;
-    GDAL_GCP    *pasGCPList;
-    int          bProjDirty;
-    int          bNeatLineDirty;
-
-    GDALMultiDomainMetadata oMDMD;
-    int          bInfoDirty;
-    int          bXMPDirty;
-
-    int          bUsePoppler;
-#ifdef HAVE_POPPLER
-    PDFDoc*      poDocPoppler;
-#endif
-#ifdef HAVE_PODOFO
-    PoDoFo::PdfMemDocument* poDocPodofo;
-    int          bPdfToPpmFailed;
-#endif
-    GDALPDFObject* poPageObj;
-
-    int          iPage;
-
-    GDALPDFObject *poImageObj;
-
-    double       dfMaxArea;
-    int          ParseLGIDictObject(GDALPDFObject* poLGIDict);
-    int          ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict, int* pbIsBestCandidate = NULL);
-    int          ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict);
-    int          ParseProjDict(GDALPDFDictionary* poProjDict);
-    int          ParseVP(GDALPDFObject* poVP, double dfMediaBoxWidth, double dfMediaBoxHeight);
-    int          ParseMeasure(GDALPDFObject* poMeasure,
-                              double dfMediaBoxWidth, double dfMediaBoxHeight,
-                              double dfULX, double dfULY, double dfLRX, double dfLRY);
-
-    int          bTried;
-    GByte       *pabyCachedData;
-    int          nLastBlockXOff, nLastBlockYOff;
-
-    OGRPolygon*  poNeatLine;
-
-    std::vector<GDALPDFTileDesc> asTiles; /* in the order of the PDF file */
-    std::vector<int> aiTiles; /* in the order of blocks */
-    int          nBlockXSize;
-    int          nBlockYSize;
-    int          CheckTiledRaster();
-
-    void         GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands);
-    void         FindXMP(GDALPDFObject* poObj);
-    void         ParseInfo(GDALPDFObject* poObj);
-
-#ifdef HAVE_POPPLER
-    ObjectAutoFree* poCatalogObjectPoppler;
-#endif
-    GDALPDFObject* poCatalogObject;
-    GDALPDFObject* GetCatalog();
-
-#ifdef HAVE_POPPLER
-    void         AddLayer(const char* pszLayerName, OptionalContentGroup* ocg);
-    void         ExploreLayers(GDALPDFArray* poArray, int nRecLevel, CPLString osTopLayer = "");
-    void         FindLayers();
-    void         TurnLayersOnOff();
-    CPLStringList osLayerList;
-    std::map<CPLString, OptionalContentGroup*> oLayerOCGMap;
-#endif
-
-    CPLStringList osLayerWithRefList;
-    CPLString     FindLayerOCG(GDALPDFDictionary* poPageDict,
-                               const char* pszLayerName);
-    void          FindLayersGeneric(GDALPDFDictionary* poPageDict);
-
-    int          bUseOCG;
-
-  public:
-                 PDFDataset();
-    virtual     ~PDFDataset();
-
-    virtual const char* GetProjectionRef();
-    virtual CPLErr GetGeoTransform( double * );
-
-    virtual CPLErr      SetProjection(const char* pszWKTIn);
-    virtual CPLErr      SetGeoTransform(double* padfGeoTransform);
-
-    virtual char      **GetMetadataDomainList();
-    virtual char      **GetMetadata( const char * pszDomain = "" );
-    virtual CPLErr      SetMetadata( char ** papszMetadata,
-                                     const char * pszDomain = "" );
-    virtual const char *GetMetadataItem( const char * pszName,
-                                         const char * pszDomain = "" );
-    virtual CPLErr      SetMetadataItem( const char * pszName,
-                                         const char * pszValue,
-                                         const char * pszDomain = "" );
-
-    virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
-                              void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
-
-    virtual int    GetGCPCount();
-    virtual const char *GetGCPProjection();
-    virtual const GDAL_GCP *GetGCPs();
-    virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
-                            const char *pszGCPProjection );
-
-    CPLErr ReadPixels( int nReqXOff, int nReqYOff,
-                       int nReqXSize, int nReqYSize,
-                       int nPixelSpace,
-                       int nLineSpace,
-                       int nBandSpace,
-                       GByte* pabyData );
-
-    static GDALDataset *Open( GDALOpenInfo * );
-    static int          Identify( GDALOpenInfo * );
-};
-
-/************************************************************************/
-/* ==================================================================== */
-/*                         PDFRasterBand                                */
-/* ==================================================================== */
-/************************************************************************/
-
-class PDFRasterBand : public GDALPamRasterBand
-{
-    friend class PDFDataset;
-
-    CPLErr IReadBlockFromTile( int, int, void * );
-
-  public:
-
-                PDFRasterBand( PDFDataset *, int );
-
-    virtual CPLErr IReadBlock( int, int, void * );
-    virtual GDALColorInterp GetColorInterpretation();
-};
-
-
-/************************************************************************/
 /*                         PDFRasterBand()                              */
 /************************************************************************/
 
@@ -982,16 +831,60 @@ CPLErr PDFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
 }
 
 /************************************************************************/
+/*                             GetOption()                              */
+/************************************************************************/
+
+const char* PDFDataset::GetOption(char** papszOpenOptions,
+                                  const char* pszOptionName,
+                                  const char* pszDefaultVal)
+{
+    CPLErr eLastErrType = CPLGetLastErrorType();
+    int nLastErrno = CPLGetLastErrorNo();
+    CPLString osLastErrorMsg(CPLGetLastErrorMsg());
+    CPLXMLNode* psNode = CPLParseXMLString(pszOpenOptionList);
+    CPLErrorSetState(eLastErrType, nLastErrno, osLastErrorMsg);
+    if( psNode == NULL ) return pszDefaultVal;
+    CPLXMLNode* psIter = psNode->psChild;
+    while( psIter != NULL )
+    {
+        if( EQUAL(CPLGetXMLValue( psIter, "name", "" ), pszOptionName) )
+        {
+            const char* pszVal = CSLFetchNameValue(papszOpenOptions, pszOptionName);
+            if( pszVal != NULL )
+            {
+                CPLDestroyXMLNode(psNode);
+                return pszVal;
+            }
+            const char* pszAltConfigOption = CPLGetXMLValue( psIter, "alt_config_option", NULL );
+            if( pszAltConfigOption != NULL )
+            {
+                pszVal = CPLGetConfigOption(pszAltConfigOption, pszDefaultVal);
+                CPLDestroyXMLNode(psNode);
+                return pszVal;
+            }
+            CPLDestroyXMLNode(psNode);
+            return pszDefaultVal;
+        }
+        psIter = psIter->psNext;
+    }
+    CPLError(CE_Failure, CPLE_AppDefined,
+             "Requesting an undocumented open option '%s'", pszOptionName);
+    CPLDestroyXMLNode(psNode);
+    return pszDefaultVal;
+}
+
+/************************************************************************/
 /*                             ReadPixels()                             */
 /************************************************************************/
 
 CPLErr PDFDataset::ReadPixels( int nReqXOff, int nReqYOff,
                                int nReqXSize, int nReqYSize,
-                               int nPixelSpace, int nLineSpace, int nBandSpace,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
                                GByte* pabyData )
 {
     CPLErr eErr = CE_None;
-    const char* pszRenderingOptions = CPLGetConfigOption("GDAL_PDF_RENDERING_OPTIONS", NULL);
+    const char* pszRenderingOptions = GetOption(papszOpenOptions, "RENDERING_OPTIONS", NULL);
 
 #ifdef HAVE_POPPLER
     if(bUsePoppler)
@@ -1156,7 +1049,7 @@ CPLErr PDFDataset::ReadPixels( int nReqXOff, int nReqYOff,
             nRet = CPLSystem(NULL, osCmd.c_str());
         }
         else
-#endif
+#endif // notdef
         {
             char** papszArgs = NULL;
             papszArgs = CSLAddString(papszArgs, "pdftoppm");
@@ -1207,7 +1100,7 @@ CPLErr PDFDataset::ReadPixels( int nReqXOff, int nReqYOff,
                                           pabyData,
                                           nReqXSize, nReqYSize,
                                           GDT_Byte, 3, NULL,
-                                          nPixelSpace, nLineSpace, nBandSpace);
+                                          nPixelSpace, nLineSpace, nBandSpace, NULL);
                 }
                 delete poDS;
             }
@@ -1358,6 +1251,16 @@ PDFDataset::PDFDataset()
 #endif
     nBlockXSize = 0;
     nBlockYSize = 0;
+    papszOpenOptions = NULL;
+    
+    nLayers = 0;
+    papoLayers = NULL;
+
+    dfPageWidth = dfPageHeight = 0;
+
+    bSetStyle = CSLTestBoolean(CPLGetConfigOption("OGR_PDF_SET_STYLE", "YES"));
+
+    InitMapOperators();
 }
 
 /************************************************************************/
@@ -1371,6 +1274,7 @@ static void PDFFreeDoc(PDFDoc* poDoc)
     {
         /* hack to avoid potential cross heap issues on Win32 */
         /* str is the VSIPDFFileStream object passed in the constructor of PDFDoc */
+        // NOTE: This is potentially very dangerous. See comment in VSIPDFFileStream::FillBuffer() */
         delete poDoc->str;
         poDoc->str = NULL;
 
@@ -1515,6 +1419,13 @@ PDFDataset::~PDFDataset()
     }
     CPLFree(pszWKT);
     pszWKT = NULL;
+    CSLDestroy(papszOpenOptions);
+
+    CleanupIntermediateResources();
+
+    for(int i=0;i<nLayers;i++)
+        delete papoLayers[i];
+    CPLFree( papoLayers );
 }
 
 
@@ -1527,7 +1438,9 @@ CPLErr PDFDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
 {
     int nBandBlockXSize, nBandBlockYSize;
     GetRasterBand(1)->GetBlockSize(&nBandBlockXSize, &nBandBlockYSize);
@@ -1555,7 +1468,7 @@ CPLErr PDFDataset::IRasterIO( GDALRWFlag eRWFlag,
                                         pData, nBufXSize, nBufYSize,
                                         eBufType, 
                                         nBandCount, panBandMap,
-                                        nPixelSpace, nLineSpace, nBandSpace );
+                                        nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -1989,10 +1902,10 @@ int PDFDataset::CheckTiledRaster()
 
 void PDFDataset::GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands)
 {
-    const char* pszDPI = CPLGetConfigOption("GDAL_PDF_DPI", NULL);
+    const char* pszDPI = GetOption(papszOpenOptions, "DPI", NULL);
     if (pszDPI != NULL)
     {
-        dfDPI = atof(pszDPI);
+        dfDPI = CPLAtof(pszDPI);
     }
     else
     {
@@ -2042,7 +1955,7 @@ void PDFDataset::GuessDPI(GDALPDFDictionary* poPageDict, int* pnBands)
                                 VSIFCloseL(fpDump);
                             }
                         }
-#endif
+#endif // DEBUG
                         osForm = GDALPDFParseStreamContentOnlyDrawForm(pszContent);
                         if (osForm.size() == 0)
                         {
@@ -2328,24 +2241,6 @@ void PDFDataset::ParseInfo(GDALPDFObject* poInfoObj)
     }
 }
 
-/************************************************************************/
-/*                           PDFSanitizeLayerName()                     */
-/************************************************************************/
-
-static
-CPLString PDFSanitizeLayerName(const char* pszName)
-{
-    CPLString osName;
-    for(int i=0; pszName[i] != '\0'; i++)
-    {
-        if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
-            osName += "_";
-        else if (pszName[i] != '"')
-            osName += pszName[i];
-    }
-    return osName;
-}
-
 #ifdef HAVE_POPPLER
 
 /************************************************************************/
@@ -2485,7 +2380,7 @@ void PDFDataset::TurnLayersOnOff()
         return;
 
     // Which layers to turn ON ?
-    const char* pszLayers = CPLGetConfigOption("GDAL_PDF_LAYERS", NULL);
+    const char* pszLayers = GetOption(papszOpenOptions, "LAYERS", NULL);
     if (pszLayers)
     {
         int i;
@@ -2510,7 +2405,7 @@ void PDFDataset::TurnLayersOnOff()
                     oIter->second->setState(OptionalContentGroup::On);
                 }
 
-                // Turn child layers on, unless there's one of them explicitely listed
+                // Turn child layers on, unless there's one of them explicitly listed
                 // in the list.
                 size_t nLen = strlen(papszLayers[i]);
                 int bFoundChildLayer = FALSE;
@@ -2575,7 +2470,7 @@ void PDFDataset::TurnLayersOnOff()
     }
 
     // Which layers to turn OFF ?
-    const char* pszLayersOFF = CPLGetConfigOption("GDAL_PDF_LAYERS_OFF", NULL);
+    const char* pszLayersOFF = GetOption(papszOpenOptions, "LAYERS_OFF", NULL);
     if (pszLayersOFF)
     {
         char** papszLayersOFF = CSLTokenizeString2(pszLayersOFF, ",", 0);
@@ -2711,7 +2606,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     if (!Identify(poOpenInfo))
         return NULL;
 
-    const char* pszUserPwd = CPLGetConfigOption("PDF_USER_PWD", NULL);
+    const char* pszUserPwd = GetOption(poOpenInfo->papszOpenOptions, "USER_PWD", NULL);
 
     int bOpenSubdataset = strncmp(poOpenInfo->pszFilename, "PDF:", 4) == 0;
     int bOpenSubdatasetImage = strncmp(poOpenInfo->pszFilename, "PDF_IMAGE:", 10) == 0;
@@ -2755,7 +2650,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
 #elif !defined(HAVE_POPPLER) && defined(HAVE_PODOFO)
     bUsePoppler = FALSE;
 #elif defined(HAVE_POPPLER) && defined(HAVE_PODOFO)
-    const char* pszPDFLib = CPLGetConfigOption("GDAL_PDF_LIB", "POPPLER");
+    const char* pszPDFLib = GetOption(poOpenInfo->papszOpenOptions, "PDF_LIB", "POPPLER");
     if (EQUAL(pszPDFLib, "POPPLER"))
         bUsePoppler = TRUE;
     else if (EQUAL(pszPDFLib, "PODOFO"))
@@ -2893,6 +2788,18 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
         return NULL;
     }
 
+    /* Sanity check to validate page count */
+    if( iPage != nPages )
+    {
+        poPagePoppler = poCatalogPoppler->getPage(nPages);
+        if ( poPagePoppler == NULL || !poPagePoppler->isOk() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Invalid PDF : invalid page count");
+            PDFFreeDoc(poDocPoppler);
+            return NULL;
+        }
+    }
+
     poPagePoppler = poCatalogPoppler->getPage(iPage);
     if ( poPagePoppler == NULL || !poPagePoppler->isOk() )
     {
@@ -2940,7 +2847,10 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
                 if (EQUAL(pszUserPwd, "ASK_INTERACTIVE"))
                 {
                     printf( "Enter password (will be echo'ed in the console): " );
-                    fgets( szPassword, sizeof(szPassword), stdin );
+                    if (0 == fgets( szPassword, sizeof(szPassword), stdin ))
+                    {
+                      fprintf(stderr, "WARNING: Error getting password.\n");
+                    }
                     szPassword[sizeof(szPassword)-1] = 0;
                     char* sz10 = strchr(szPassword, '\n');
                     if (sz10)
@@ -3006,6 +2916,10 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
 
     try
     {
+        /* Sanity check to validate page count */
+        if( iPage != nPages )
+            poPagePodofo = poDocPodofo->GetPage(nPages - 1);
+
         poPagePodofo = poDocPodofo->GetPage(iPage - 1);
     }
     catch(PoDoFo::PdfError& oError)
@@ -3066,6 +2980,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
     PDFDataset* poDS = new PDFDataset();
+    poDS->papszOpenOptions = CSLDuplicate(poOpenInfo->papszOpenOptions);
     poDS->bUsePoppler = bUsePoppler;
     poDS->osFilename = pszFilename;
     poDS->eAccess = poOpenInfo->eAccess;
@@ -3104,10 +3019,10 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     }
     else
     {
-        const char* pszDPI = CPLGetConfigOption("GDAL_PDF_DPI", NULL);
+        const char* pszDPI = GetOption(poOpenInfo->papszOpenOptions, "DPI", NULL);
         if (pszDPI != NULL)
         {
-            poDS->dfDPI = atof(pszDPI);
+            poDS->dfDPI = CPLAtof(pszDPI);
         }
     }
 
@@ -3136,6 +3051,8 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
 #endif
 
     double dfUserUnit = poDS->dfDPI * USER_UNIT_IN_INCH;
+    poDS->dfPageWidth = dfX2 - dfX1;
+    poDS->dfPageHeight = dfY2 - dfY1;
     poDS->nRasterXSize = (int) floor((dfX2 - dfX1) * dfUserUnit+0.5);
     poDS->nRasterYSize = (int) floor((dfY2 - dfY1) * dfUserUnit+0.5);
 
@@ -3156,6 +3073,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
         dfRotation = poPagePodofo->GetRotation();
 #endif
     if ( dfRotation == 90 ||
+         dfRotation == -90 ||
          dfRotation == 270 )
     {
 /* FIXME: the non poppler case should be implemented. This needs to rotate */
@@ -3175,7 +3093,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     /* Check if the PDF is only made of regularly tiled images */
     /* (like some USGS GeoPDF production) */
     if( dfRotation == 0.0 && poDS->asTiles.size() &&
-        EQUAL(CPLGetConfigOption("GDAL_PDF_LAYERS", "ALL"), "ALL") )
+        EQUAL(GetOption(poOpenInfo->papszOpenOptions, "LAYERS", "ALL"), "ALL") )
     {
         poDS->CheckTiledRaster();
         if (poDS->aiTiles.size() )
@@ -3191,14 +3109,36 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
         CPLDebug("PDF", "OGC Encoding Best Practice style detected");
         if (poDS->ParseLGIDictObject(poLGIDict))
         {
-            if (poDS->bHasCTM)
+            if (poDS->bHasCTM )
             {
-                poDS->adfGeoTransform[0] = poDS->adfCTM[4] + poDS->adfCTM[0] * dfX1 + poDS->adfCTM[2] * dfY2;
-                poDS->adfGeoTransform[1] = poDS->adfCTM[0] / dfUserUnit;
-                poDS->adfGeoTransform[2] = poDS->adfCTM[1] / dfUserUnit;
-                poDS->adfGeoTransform[3] = poDS->adfCTM[5] + poDS->adfCTM[1] * dfX1 + poDS->adfCTM[3] * dfY2;
-                poDS->adfGeoTransform[4] = - poDS->adfCTM[2] / dfUserUnit;
-                poDS->adfGeoTransform[5] = - poDS->adfCTM[3] / dfUserUnit;
+                if ( dfRotation == 90 )
+                {
+                    poDS->adfGeoTransform[0] = poDS->adfCTM[4];
+                    poDS->adfGeoTransform[1] = poDS->adfCTM[2] / dfUserUnit;
+                    poDS->adfGeoTransform[2] = poDS->adfCTM[0] / dfUserUnit;
+                    poDS->adfGeoTransform[3] = poDS->adfCTM[5];
+                    poDS->adfGeoTransform[4] = poDS->adfCTM[3] / dfUserUnit;
+                    poDS->adfGeoTransform[5] = poDS->adfCTM[1] / dfUserUnit;
+                }
+                else if ( dfRotation == -90 || dfRotation == 270 )
+                {
+                    poDS->adfGeoTransform[0] = poDS->adfCTM[4] + poDS->adfCTM[2] * poDS->dfPageHeight + poDS->adfCTM[0] * poDS->dfPageWidth;
+                    poDS->adfGeoTransform[1] = -poDS->adfCTM[2] / dfUserUnit;
+                    poDS->adfGeoTransform[2] = -poDS->adfCTM[0] / dfUserUnit;
+                    poDS->adfGeoTransform[3] = poDS->adfCTM[5] + poDS->adfCTM[3] * poDS->dfPageHeight + poDS->adfCTM[1] * poDS->dfPageWidth;
+                    poDS->adfGeoTransform[4] = -poDS->adfCTM[3] / dfUserUnit;
+                    poDS->adfGeoTransform[5] = -poDS->adfCTM[1] / dfUserUnit;
+                }
+                else
+                {
+                    poDS->adfGeoTransform[0] = poDS->adfCTM[4] + poDS->adfCTM[2] * poDS->dfPageHeight;
+                    poDS->adfGeoTransform[1] = poDS->adfCTM[0] / dfUserUnit;
+                    poDS->adfGeoTransform[2] = - poDS->adfCTM[2] / dfUserUnit;
+                    poDS->adfGeoTransform[3] = poDS->adfCTM[5] + poDS->adfCTM[3] * poDS->dfPageHeight;
+                    poDS->adfGeoTransform[4] = poDS->adfCTM[1] / dfUserUnit;
+                    poDS->adfGeoTransform[5] = - poDS->adfCTM[3] / dfUserUnit;
+                }
+                
                 poDS->bGeoTransformValid = TRUE;
             }
 
@@ -3207,8 +3147,25 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
             int i;
             for(i=0;i<poDS->nGCPCount;i++)
             {
-                poDS->pasGCPList[i].dfGCPPixel = poDS->pasGCPList[i].dfGCPPixel * dfUserUnit;
-                poDS->pasGCPList[i].dfGCPLine = poDS->nRasterYSize - poDS->pasGCPList[i].dfGCPLine * dfUserUnit;
+                if ( dfRotation == 90 )
+                {
+                    double dfPixel = poDS->pasGCPList[i].dfGCPPixel * dfUserUnit;
+                    double dfLine = poDS->pasGCPList[i].dfGCPLine * dfUserUnit;
+                    poDS->pasGCPList[i].dfGCPPixel = dfLine;
+                    poDS->pasGCPList[i].dfGCPLine = dfPixel;
+                }
+                else if ( dfRotation == -90 || dfRotation == 270 )
+                {
+                    double dfPixel = poDS->pasGCPList[i].dfGCPPixel * dfUserUnit;
+                    double dfLine = poDS->pasGCPList[i].dfGCPLine * dfUserUnit;
+                    poDS->pasGCPList[i].dfGCPPixel = poDS->nRasterXSize - dfLine;
+                    poDS->pasGCPList[i].dfGCPLine = poDS->nRasterYSize - dfPixel;
+                }
+                else
+                {
+                    poDS->pasGCPList[i].dfGCPPixel = poDS->pasGCPList[i].dfGCPPixel * dfUserUnit;
+                    poDS->pasGCPList[i].dfGCPLine = poDS->nRasterYSize - poDS->pasGCPList[i].dfGCPLine * dfUserUnit;
+                }
             }
         }
     }
@@ -3334,8 +3291,22 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
 
             for(i=0;i<nPoints;i++)
             {
-                double x = poRing->getX(i) * dfUserUnit;
-                double y = poDS->nRasterYSize - poRing->getY(i) * dfUserUnit;
+                double x, y;
+                if( dfRotation == 90.0 )
+                {
+                    x = poRing->getY(i) * dfUserUnit;
+                    y = poRing->getX(i) * dfUserUnit;
+                }
+                else if( dfRotation == -90.0 || dfRotation == 270.0 )
+                {
+                    x = poDS->nRasterXSize - poRing->getY(i) * dfUserUnit;
+                    y = poDS->nRasterYSize - poRing->getX(i) * dfUserUnit;
+                }
+                else
+                {
+                    x = poRing->getX(i) * dfUserUnit;
+                    y = poDS->nRasterYSize - poRing->getY(i) * dfUserUnit;
+                }
                 double X = poDS->adfGeoTransform[0] + x * poDS->adfGeoTransform[1] +
                                                       y * poDS->adfGeoTransform[2];
                 double Y = poDS->adfGeoTransform[3] + x * poDS->adfGeoTransform[4] +
@@ -3416,7 +3387,7 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
     int nBands = 3;
     if( nBandsGuessed )
         nBands = nBandsGuessed;
-    const char* pszPDFBands = CPLGetConfigOption("GDAL_PDF_BANDS", NULL);
+    const char* pszPDFBands = GetOption(poOpenInfo->papszOpenOptions, "BANDS", NULL);
     if( pszPDFBands )
     {
         nBands = atoi(pszPDFBands);
@@ -3446,6 +3417,20 @@ GDALDataset *PDFDataset::Open( GDALOpenInfo * poOpenInfo )
             poDS->SetBand(iBand, new PDFRasterBand(poDS, iBand));
     }
 
+    int bHasNonEmptyVectorLayers = poDS->OpenVectorLayers(poPageDict);
+
+    /* Check if this is a raster-only PCIDSK file and that we are */
+    /* opened in vector-only mode */
+    if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
+        (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0 &&
+        !bHasNonEmptyVectorLayers )
+    {
+        CPLDebug("PCIDSK", "This is a raster-only PDF dataset, "
+                    "but it has been opened in vector-only mode");
+        delete poDS;
+        return NULL;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
@@ -3543,26 +3528,26 @@ static double Get(GDALPDFObject* poObj, int nIndice)
         char chLast = pszStr[nLen-1];
         if (chLast == 'W' || chLast == 'E' || chLast == 'N' || chLast == 'S')
         {
-            double dfDeg = atof(pszStr);
+            double dfDeg = CPLAtof(pszStr);
             double dfMin = 0, dfSec = 0;
             const char* pszNext = strchr(pszStr, ' ');
             if (pszNext)
                 pszNext ++;
             if (pszNext)
-                dfMin = atof(pszNext);
+                dfMin = CPLAtof(pszNext);
             if (pszNext)
                 pszNext = strchr(pszNext, ' ');
             if (pszNext)
                 pszNext ++;
             if (pszNext)
-                dfSec = atof(pszNext);
+                dfSec = CPLAtof(pszNext);
             double dfVal = dfDeg + dfMin / 60 + dfSec / 3600;
             if (chLast == 'W' || chLast == 'S')
                 return -dfVal;
             else
                 return dfVal;
         }
-        return atof(pszStr);
+        return CPLAtof(pszStr);
     }
     else
     {
@@ -3654,7 +3639,7 @@ int PDFDataset::ParseLGIDictDictFirstPass(GDALPDFDictionary* poLGIDict,
     /* USGS PDF maps have several LGIDict. Keep the one whose description */
     /* is "Map Layers" by default */
     const char* pszNeatlineToSelect =
-        CPLGetConfigOption("GDAL_PDF_NEATLINE", "Map Layers");
+        GetOption(papszOpenOptions, "NEATLINE", "Map Layers");
 
 /* -------------------------------------------------------------------- */
 /*      Extract Neatline attribute                                      */
@@ -3799,7 +3784,8 @@ int PDFDataset::ParseLGIDictDictSecondPass(GDALPDFDictionary* poLGIDict)
     {
         GDALPDFArray* poRegistrationArray = poRegistration->GetArray();
         int nLength = poRegistrationArray->GetLength();
-        if (nLength > 4 || (!bHasCTM && nLength >= 2) )
+        if( nLength > 4 || (!bHasCTM && nLength >= 2) ||
+            CSLTestBoolean(CPLGetConfigOption("PDF_REPORT_GCPS", "NO")) )
         {
             nGCPCount = 0;
             pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nLength);
@@ -3917,6 +3903,7 @@ int PDFDataset::ParseProjDict(GDALPDFDictionary* poProjDict)
     {
         if (poDatum->GetType() == PDFObjectType_String)
         {
+            /* Using Annex A of http://portal.opengeospatial.org/files/?artifact_id=40537 */
             const char* pszDatum = poDatum->GetString().c_str();
             CPLDebug("PDF", "Datum = %s", pszDatum);
             if (EQUAL(pszDatum, "WE") || EQUAL(pszDatum, "WGE"))
@@ -3950,6 +3937,28 @@ int PDFDataset::ParseProjDict(GDALPDFDictionary* poProjDict)
             {
                 oSRS.importFromEPSG(4283);
             }
+            else if (EQUALN(pszDatum, "OHA-", 4)) /* Old Hawaiian */
+            {
+                oSRS.importFromEPSG(4135); /* matches OHA-M (Mean) */
+                if( !EQUAL(pszDatum, "OHA-M") )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Using OHA-M (Old Hawaiian Mean) definition for %s. Potential issue with datum shift parameters",
+                             pszDatum);
+                    OGR_SRSNode *poNode = oSRS.GetRoot();
+                    int iChild = poNode->FindChild( "AUTHORITY" );
+                    if( iChild != -1 )
+                        poNode->DestroyChild( iChild );
+                    iChild = poNode->FindChild( "DATUM" );
+                    if( iChild != -1 )
+                    {
+                        poNode = poNode->GetChild(iChild);
+                        iChild = poNode->FindChild( "AUTHORITY" );
+                        if( iChild != -1 )
+                            poNode->DestroyChild( iChild );
+                    }
+                }
+            }
             else
             {
                 CPLError(CE_Warning, CPLE_AppDefined,
@@ -4030,10 +4039,7 @@ int PDFDataset::ParseProjDict(GDALPDFDictionary* poProjDict)
                 {
                     double dfSemiMinor = Get(poEllipsoidDict, "SemiMinorAxis");
                     CPLDebug("PDF", "Datum.Ellipsoid.SemiMinorAxis = %.16g", dfSemiMinor);
-                    if( ABS(dfSemiMajor/dfSemiMinor) - 1.0 < 0.0000000000001 )
-                        dfInvFlattening = 0.0;
-                    else
-                        dfInvFlattening = -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
+                    dfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
                 }
                 
                 if( dfSemiMajor != 0.0 && dfInvFlattening != -1.0 )
@@ -4972,7 +4978,7 @@ CPLErr PDFDataset::SetGeoTransform(double* padfGeoTransform)
     bGeoTransformValid = TRUE;
     bProjDirty = TRUE;
 
-    /* Reset NEATLINE if not explicitely set by the user */
+    /* Reset NEATLINE if not explicitly set by the user */
     if (!bNeatLineDirty)
         SetMetadataItem("NEATLINE", NULL);
     return CE_None;
@@ -4986,7 +4992,7 @@ char **PDFDataset::GetMetadataDomainList()
 {
     return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
                                    TRUE,
-                                   "xml:XMP", "LAYERS_WITH_REF", "EMBEDDED_METADATA", NULL);
+                                   "xml:XMP", "LAYERS", "EMBEDDED_METADATA", NULL);
 }
 
 /************************************************************************/
@@ -4995,11 +5001,7 @@ char **PDFDataset::GetMetadataDomainList()
 
 char      **PDFDataset::GetMetadata( const char * pszDomain )
 {
-    if( pszDomain != NULL && EQUAL(pszDomain, "LAYERS_WITH_REF") )
-    {
-        return osLayerWithRefList.List(); /* Used by OGR driver */
-    }
-    else if( pszDomain != NULL && EQUAL(pszDomain, "EMBEDDED_METADATA") )
+    if( pszDomain != NULL && EQUAL(pszDomain, "EMBEDDED_METADATA") )
     {
         char** papszRet = oMDMD.GetMetadata(pszDomain);
         if( papszRet )
@@ -5057,15 +5059,6 @@ CPLErr      PDFDataset::SetMetadata( char ** papszMetadata,
 const char *PDFDataset::GetMetadataItem( const char * pszName,
                                          const char * pszDomain )
 {
-    if ( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "PDF_PAGE_OBJECT") )
-    {
-        return CPLSPrintf("%p", poPageObj);
-    }
-    if ( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "PDF_CATALOG_OBJECT") )
-    {
-        return CPLSPrintf("%p", GetCatalog());
-    }
-
     return oMDMD.GetMetadataItem(pszName, pszDomain);
 }
 
@@ -5155,7 +5148,7 @@ CPLErr PDFDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
     
     bProjDirty = TRUE;
 
-    /* Reset NEATLINE if not explicitely set by the user */
+    /* Reset NEATLINE if not explicitly set by the user */
     if (!bNeatLineDirty)
         SetMetadataItem("NEATLINE", NULL);
 
@@ -5164,20 +5157,18 @@ CPLErr PDFDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
 
 #endif // #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
 
-
 /************************************************************************/
 /*                          GDALPDFOpen()                               */
 /************************************************************************/
 
 GDALDataset* GDALPDFOpen(
-#if !defined(HAVE_POPPLER) && !defined(HAVE_PODOFO)
-CPL_UNUSED
-#endif
+#if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
                          const char* pszFilename,
-#if !defined(HAVE_POPPLER) && !defined(HAVE_PODOFO)
-CPL_UNUSED
-#endif
                          GDALAccess eAccess
+#else
+                         CPL_UNUSED const char* pszFilename,
+                         CPL_UNUSED GDALAccess eAccess
+#endif
                          )
 {
 #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
@@ -5201,6 +5192,23 @@ static void GDALPDFUnloadDriver(CPL_UNUSED GDALDriver * poDriver)
 }
 
 /************************************************************************/
+/*                           PDFSanitizeLayerName()                     */
+/************************************************************************/
+
+CPLString PDFSanitizeLayerName(const char* pszName)
+{
+    CPLString osName;
+    for(int i=0; pszName[i] != '\0'; i++)
+    {
+        if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
+            osName += "_";
+        else if (pszName[i] != '"')
+            osName += pszName[i];
+    }
+    return osName;
+}
+
+/************************************************************************/
 /*                         GDALRegister_PDF()                           */
 /************************************************************************/
 
@@ -5217,6 +5225,8 @@ void GDALRegister_PDF()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "PDF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Geospatial PDF" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -5227,10 +5237,10 @@ void GDALRegister_PDF()
 #ifdef HAVE_POPPLER
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
         poDriver->SetMetadataItem( "HAVE_POPPLER", "YES" );
-#endif
+#endif // HAVE_POPPLER
 #ifdef HAVE_PODOFO
         poDriver->SetMetadataItem( "HAVE_PODOFO", "YES" );
-#endif
+#endif // HAVE_PODOFO
 
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
 "<CreationOptionList>\n"
@@ -5291,12 +5301,14 @@ void GDALRegister_PDF()
 "</CreationOptionList>\n" );
 
 #if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, pszOpenOptionList );
         poDriver->pfnOpen = PDFDataset::Open;
         poDriver->pfnIdentify = PDFDataset::Identify;
         poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
-#endif
+#endif // HAVE_POPPLER || HAVE_PODOFO
 
         poDriver->pfnCreateCopy = GDALPDFCreateCopy;
+        poDriver->pfnCreate = PDFWritableVectorDataset::Create;
         poDriver->pfnUnloadDriver = GDALPDFUnloadDriver;
 
         GetGDALDriverManager()->RegisterDriver( poDriver );
diff --git a/frmts/pdf/pdfdataset.h b/frmts/pdf/pdfdataset.h
deleted file mode 100644
index 1518f70..0000000
--- a/frmts/pdf/pdfdataset.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/******************************************************************************
- * $Id: pdfdataset.h 27044 2014-03-16 23:41:27Z rouault $
- *
- * Project:  PDF driver
- * Purpose:  GDALDataset driver for PDF dataset.
- * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
- *
- ******************************************************************************
- * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * 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.
- ****************************************************************************/
-
-#ifndef PDFDATASET_H_INCLUDED
-#define PDFDATASET_H_INCLUDED
-
-#include "gdal_priv.h"
-
-GDALDataset* GDALPDFOpen(const char* pszFilename, GDALAccess eAccess);
-
-#endif // PDFDATASET_H_INCLUDED
diff --git a/frmts/pdf/pdfio.cpp b/frmts/pdf/pdfio.cpp
index 94acd10..0334311 100644
--- a/frmts/pdf/pdfio.cpp
+++ b/frmts/pdf/pdfio.cpp
@@ -27,17 +27,27 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-#ifdef HAVE_POPPLER
+#include "gdal_pdf.h"
 
-/* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
-/* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
-#define CPL_GBOOL_DEFINED
+#ifdef HAVE_POPPLER
 
 #include "pdfio.h"
 
 #include "cpl_vsi.h"
 
-CPL_CVSID("$Id: pdfio.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pdfio.cpp 28956 2015-04-20 16:17:55Z rouault $");
+
+
+#ifdef POPPLER_BASE_STREAM_HAS_TWO_ARGS
+/* Poppler 0.31.0 is the first one that needs to know the file size */
+static vsi_l_offset VSIPDFFileStreamGetSize(VSILFILE* f)
+{
+    VSIFSeekL(f, 0, SEEK_END);
+    vsi_l_offset nSize = VSIFTellL(f);
+    VSIFSeekL(f, 0, SEEK_SET);
+    return nSize;
+}
+#endif
 
 /************************************************************************/
 /*                         VSIPDFFileStream()                           */
@@ -45,7 +55,7 @@ CPL_CVSID("$Id: pdfio.cpp 27044 2014-03-16 23:41:27Z rouault $");
 
 VSIPDFFileStream::VSIPDFFileStream(VSILFILE* f, const char* pszFilename, Object *dictA):
 #ifdef POPPLER_BASE_STREAM_HAS_TWO_ARGS
-                                                        BaseStream(dictA, 0)
+                                                        BaseStream(dictA, (setPos_offset_type)VSIPDFFileStreamGetSize(f))
 #else
                                                         BaseStream(dictA)
 #endif
@@ -188,6 +198,27 @@ int VSIPDFFileStream::FillBuffer()
     if (nBufferLength == 0)
         return FALSE;
 
+    // Since we now report a non-zero length (as BaseStream::length member),
+    // PDFDoc::getPage() can go to the linearized mode if the file is linearized,
+    // and thus create a pageCache. If so, in PDFDoc::~PDFDoc(),
+    // if pageCache is not null, it would try to access the stream (str) through
+    // getPageCount(), but we have just freed and nullify str before in PDFFreeDoc().
+    // So make as if the file is not linearized to avoid those issues...
+    // All this is due to our attempt of avoiding cross-heap issues with allocation
+    // and liberation of VSIPDFFileStream as PDFDoc::str member.
+    if( nCurrentPos <= 0 )
+    {
+        for(int i=0;i<nToRead-(int)strlen("/Linearized ");i++)
+        {
+            if( memcmp(abyBuffer + i, "/Linearized ",
+                       strlen("/Linearized ")) == 0 )
+            {
+                memcpy(abyBuffer + i, "/XXXXXXXXXX ", strlen("/Linearized "));
+                break;
+            }
+        }
+    }
+
     return TRUE;
 }
 
@@ -195,7 +226,7 @@ int VSIPDFFileStream::FillBuffer()
 /*                                getChar()                             */
 /************************************************************************/
 
-/* The unoptimized version performs a bit well since we must go through */
+/* The unoptimized version performs a bit less since we must go through */
 /* the whole virtual I/O chain for each character reading. We save a few */
 /* percent with this extra internal caching */
 
@@ -326,4 +357,47 @@ void VSIPDFFileStream::moveStart(moveStart_delta_type delta)
     nPosInBuffer = nBufferLength = -1;
 }
 
+/************************************************************************/
+/*                          hasGetChars()                               */
+/************************************************************************/
+
+GBool VSIPDFFileStream::hasGetChars()
+{
+    return true;
+}
+
+/************************************************************************/
+/*                            getChars()                                */
+/************************************************************************/
+
+int VSIPDFFileStream::getChars(int nChars, Guchar *buffer)
+{
+    int nRead = 0;
+    while (nRead < nChars)
+    {
+        int nToRead = nChars - nRead;
+        if (nPosInBuffer == nBufferLength)
+        {
+            if (!bLimited && nToRead > BUFFER_SIZE)
+            {
+                int nJustRead = (int) VSIFReadL(buffer + nRead, 1, nToRead, f);
+                nPosInBuffer = nBufferLength = -1;
+                nCurrentPos += nJustRead;
+                nRead += nJustRead;
+                break;
+            }
+            else if (!FillBuffer() || nPosInBuffer >= nBufferLength)
+                break;
+        }
+        if( nToRead > nBufferLength - nPosInBuffer )
+            nToRead = nBufferLength - nPosInBuffer;
+
+        memcpy( buffer + nRead, abyBuffer + nPosInBuffer, nToRead );
+        nPosInBuffer += nToRead;
+        nCurrentPos += nToRead;
+        nRead += nToRead;
+    }
+    return nRead;
+}
+
 #endif
diff --git a/frmts/pdf/pdfio.h b/frmts/pdf/pdfio.h
index ebedc57..f649a1b 100644
--- a/frmts/pdf/pdfio.h
+++ b/frmts/pdf/pdfio.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdfio.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pdfio.h 28438 2015-02-07 21:47:35Z rouault $
  *
  * Project:  PDF driver
  * Purpose:  GDALDataset driver for PDF dataset.
@@ -93,6 +93,10 @@ class VSIPDFFileStream: public BaseStream
         virtual void       close();
 
     private:
+        /* Added in poppler 0.15.0 */
+        virtual GBool hasGetChars();
+        virtual int getChars(int nChars, Guchar *buffer);
+
         VSIPDFFileStream  *poParent;
         GooString         *poFilename;
         VSILFILE          *f;
diff --git a/frmts/pdf/pdfobject.cpp b/frmts/pdf/pdfobject.cpp
index 4a52a82..58995a4 100644
--- a/frmts/pdf/pdfobject.cpp
+++ b/frmts/pdf/pdfobject.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdfobject.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pdfobject.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  PDF driver
  * Purpose:  GDALDataset driver for PDF dataset.
@@ -27,14 +27,12 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-/* hack for PDF driver and poppler >= 0.15.0 that defines incompatible "typedef bool GBool" */
-/* in include/poppler/goo/gtypes.h with the one defined in cpl_port.h */
-#define CPL_GBOOL_DEFINED
+#include "gdal_pdf.h"
 
 #include <vector>
 #include "pdfobject.h"
 
-CPL_CVSID("$Id: pdfobject.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pdfobject.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                        ROUND_TO_INT_IF_CLOSE()                       */
@@ -198,11 +196,11 @@ void GDALPDFObject::Serialize(CPLString& osStr)
             else if (CanRepresentRealAsString())
             {
                 /* Used for OGC BP numeric values */
-                sprintf(szReal, "(%.16g)", dfReal);
+                CPLsprintf(szReal, "(%.16g)", dfReal);
             }
             else
             {
-                sprintf(szReal, "%.16f", dfReal);
+                CPLsprintf(szReal, "%.16f", dfReal);
 
                 /* Remove non significant trailing zeroes */
                 char* pszDot = strchr(szReal, '.');
diff --git a/frmts/pdf/pdfobject.h b/frmts/pdf/pdfobject.h
index 66da72a..448cab0 100644
--- a/frmts/pdf/pdfobject.h
+++ b/frmts/pdf/pdfobject.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdfobject.h 27331 2014-05-14 16:25:25Z rouault $
+ * $Id: pdfobject.h 27329 2014-05-14 16:24:17Z rouault $
  *
  * Project:  PDF driver
  * Purpose:  GDALDataset driver for PDF dataset.
diff --git a/frmts/pdf/pdfreadvectors.cpp b/frmts/pdf/pdfreadvectors.cpp
new file mode 100644
index 0000000..37d8f1d
--- /dev/null
+++ b/frmts/pdf/pdfreadvectors.cpp
@@ -0,0 +1,1666 @@
+/******************************************************************************
+ * $Id: pdfreadvectors.cpp 27942 2014-11-11 00:57:41Z rouault $
+ *
+ * Project:  PDF driver
+ * Purpose:  GDALDataset driver for PDF dataset (read vector features)
+ * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2010-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdal_pdf.h"
+
+#define SQUARE(x) ((x)*(x))
+#define EPSILON 1e-5
+
+CPL_CVSID("$Id: pdfreadvectors.cpp 27942 2014-11-11 00:57:41Z rouault $");
+
+#if defined(HAVE_POPPLER) || defined(HAVE_PODOFO)
+
+/************************************************************************/
+/*                        OpenVectorLayers()                            */
+/************************************************************************/
+
+int PDFDataset::OpenVectorLayers(GDALPDFDictionary* poPageDict)
+{
+    GetCatalog();
+    if( poCatalogObject == NULL )
+        return FALSE;
+
+    GDALPDFObject* poContents = poPageDict->Get("Contents");
+    if (poContents == NULL)
+        return FALSE;
+
+    if (poContents->GetType() != PDFObjectType_Dictionary &&
+        poContents->GetType() != PDFObjectType_Array)
+        return FALSE;
+
+    GDALPDFObject* poResources = poPageDict->Get("Resources");
+    if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
+        return FALSE;
+
+    GDALPDFObject* poStructTreeRoot = poCatalogObject->GetDictionary()->Get("StructTreeRoot");
+    if (CSLTestBoolean(CPLGetConfigOption("OGR_PDF_READ_NON_STRUCTURED", "NO")) ||
+        poStructTreeRoot == NULL ||
+        poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
+    {
+        ExploreContentsNonStructured(poContents, poResources);
+    }
+    else
+    {
+        ExploreContents(poContents, poResources);
+        ExploreTree(poStructTreeRoot, 0);
+    }
+
+    CleanupIntermediateResources();
+
+    int bEmptyDS = TRUE;
+    for(int i=0;i<nLayers;i++)
+    {
+        if (papoLayers[i]->GetFeatureCount() != 0)
+        {
+            bEmptyDS = FALSE;
+            break;
+        }
+    }
+    return !bEmptyDS;
+}
+
+/************************************************************************/
+/*                   CleanupIntermediateResources()                     */
+/************************************************************************/
+
+void PDFDataset::CleanupIntermediateResources()
+{
+    std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
+    for( ; oMapIter != oMapMCID.end(); ++oMapIter)
+        delete oMapIter->second;
+    oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
+}
+
+/************************************************************************/
+/*                          InitMapOperators()                          */
+/************************************************************************/
+
+typedef struct
+{
+    char        szOpName[4];
+    int         nArgs;
+} PDFOperator;
+
+static const PDFOperator asPDFOperators [] =
+{
+    { "b", 0 },
+    { "B", 0 },
+    { "b*", 0 },
+    { "B*", 0 },
+    { "BDC", 2 },
+    // BI
+    { "BMC", 1 },
+    // BT
+    { "BX", 0 },
+    { "c", 6 },
+    { "cm", 6 },
+    { "CS", 1 },
+    { "cs", 1 },
+    { "d", 1 }, /* we have ignored the first arg */
+    // d0
+    // d1
+    { "Do", 1 },
+    { "DP", 2 },
+    // EI
+    { "EMC", 0 },
+    // ET
+    { "EX", 0 },
+    { "f", 0 },
+    { "F", 0 },
+    { "f*", 0 },
+    { "G", 1 },
+    { "g", 1 },
+    { "gs", 1 },
+    { "h", 0 },
+    { "i", 1 },
+    // ID
+    { "j", 1 },
+    { "J", 1 },
+    { "K", 4 },
+    { "k", 4 },
+    { "l", 2 },
+    { "m", 2 },
+    { "M", 1 },
+    { "MP", 1 },
+    { "n", 0 },
+    { "q", 0 },
+    { "Q", 0 },
+    { "re", 4 },
+    { "RG", 3 },
+    { "rg", 3 },
+    { "ri", 1 },
+    { "s", 0 },
+    { "S", 0 },
+    { "SC", -1 },
+    { "sc", -1 },
+    { "SCN", -1 },
+    { "scn", -1 },
+    { "sh", 1 },
+    // T*
+    { "Tc", 1},
+    { "Td", 2},
+    { "TD", 2},
+    { "Tf", 1},
+    { "Tj", 1},
+    { "TJ", 1},
+    { "TL", 1},
+    { "Tm", 6},
+    { "Tr", 1},
+    { "Ts", 1},
+    { "Tw", 1},
+    { "Tz", 1},
+    { "v", 4 },
+    { "w", 1 },
+    { "W", 0 },
+    { "W*", 0 },
+    { "y", 4 },
+    // '
+    // "
+};
+
+void PDFDataset::InitMapOperators()
+{
+    for(size_t i=0;i<sizeof(asPDFOperators) / sizeof(asPDFOperators[0]); i++)
+        oMapOperators[asPDFOperators[i].szOpName] = asPDFOperators[i].nArgs;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int PDFDataset::TestCapability( CPL_UNUSED const char * pszCap )
+{
+    return FALSE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *PDFDataset::GetLayer( int iLayer )
+
+{
+    if (iLayer < 0 || iLayer >= nLayers)
+        return NULL;
+
+    return papoLayers[iLayer];
+}
+
+/************************************************************************/
+/*                            GetLayerCount()                           */
+/************************************************************************/
+
+int PDFDataset::GetLayerCount()
+{
+    return nLayers;
+}
+
+/************************************************************************/
+/*                            ExploreTree()                             */
+/************************************************************************/
+
+void PDFDataset::ExploreTree(GDALPDFObject* poObj, int nRecLevel)
+{
+    if (nRecLevel == 16)
+        return;
+
+    if (poObj->GetType() != PDFObjectType_Dictionary)
+        return;
+
+    GDALPDFDictionary* poDict = poObj->GetDictionary();
+
+    GDALPDFObject* poS = poDict->Get("S");
+    CPLString osS;
+    if (poS != NULL && poS->GetType() == PDFObjectType_Name)
+    {
+        osS = poS->GetName();
+    }
+
+    GDALPDFObject* poT = poDict->Get("T");
+    CPLString osT;
+    if (poT != NULL && poT->GetType() == PDFObjectType_String)
+    {
+        osT = poT->GetString();
+    }
+
+    GDALPDFObject* poK = poDict->Get("K");
+    if (poK == NULL)
+        return;
+
+    if (poK->GetType() == PDFObjectType_Array)
+    {
+        GDALPDFArray* poArray = poK->GetArray();
+        if (poArray->GetLength() > 0 &&
+            poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
+            poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
+            poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
+        {
+            CPLString osLayerName;
+            if (osT.size())
+                osLayerName = osT;
+            else
+            {
+                if (osS.size())
+                    osLayerName = osS;
+                else
+                    osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
+            }
+
+            const char* pszWKT = GetProjectionRef();
+            OGRSpatialReference* poSRS = NULL;
+            if (pszWKT && pszWKT[0] != '\0')
+            {
+                poSRS = new OGRSpatialReference();
+                poSRS->importFromWkt((char**) &pszWKT);
+            }
+
+            OGRPDFLayer* poLayer =
+                new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
+            delete poSRS;
+
+            poLayer->Fill(poArray);
+
+            papoLayers = (OGRLayer**)
+                CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+            papoLayers[nLayers] = poLayer;
+            nLayers ++;
+        }
+        else
+        {
+            for(int i=0;i<poArray->GetLength();i++)
+                ExploreTree(poArray->Get(i), nRecLevel + 1);
+        }
+    }
+    else if (poK->GetType() == PDFObjectType_Dictionary)
+    {
+        ExploreTree(poK, nRecLevel + 1);
+    }
+}
+
+/************************************************************************/
+/*                        GetGeometryFromMCID()                         */
+/************************************************************************/
+
+OGRGeometry* PDFDataset::GetGeometryFromMCID(int nMCID)
+{
+    std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
+    if (oMapIter != oMapMCID.end())
+        return oMapIter->second;
+    else
+        return NULL;
+}
+
+/************************************************************************/
+/*                            GraphicState                              */
+/************************************************************************/
+
+class GraphicState
+{
+    public:
+        double adfCM[6];
+        double adfStrokeColor[3];
+        double adfFillColor[3];
+
+        GraphicState()
+        {
+            adfCM[0] = 1;
+            adfCM[1] = 0;
+            adfCM[2] = 0;
+            adfCM[3] = 1;
+            adfCM[4] = 0;
+            adfCM[5] = 0;
+            adfStrokeColor[0] = 0.0;
+            adfStrokeColor[1] = 0.0;
+            adfStrokeColor[2] = 0.0;
+            adfFillColor[0] = 1.0;
+            adfFillColor[1] = 1.0;
+            adfFillColor[2] = 1.0;
+        }
+
+        void MultiplyBy(double adfMatrix[6])
+        {
+            /*
+            [ a b 0 ]     [ a' b' 0]     [ aa' + bc'       ab' + bd'       0 ]
+            [ c d 0 ]  *  [ c' d' 0]  =  [ ca' + dc'       cb' + dd'       0 ]
+            [ e f 1 ]     [ e' f' 1]     [ ea' + fc' + e'  eb' + fd' + f'  1 ]
+            */
+
+            double a = adfCM[0];
+            double b = adfCM[1];
+            double c = adfCM[2];
+            double d = adfCM[3];
+            double e = adfCM[4];
+            double f = adfCM[5];
+            double ap = adfMatrix[0];
+            double bp = adfMatrix[1];
+            double cp = adfMatrix[2];
+            double dp = adfMatrix[3];
+            double ep = adfMatrix[4];
+            double fp = adfMatrix[5];
+            adfCM[0] = a*ap + b*cp;
+            adfCM[1] = a*bp + b*dp;
+            adfCM[2] = c*ap + d*cp;
+            adfCM[3] = c*bp + d*dp;
+            adfCM[4] = e*ap + f*cp + ep;
+            adfCM[5] = e*bp + f*dp + fp;
+        }
+
+        void ApplyMatrix(double adfCoords[2])
+        {
+            double x = adfCoords[0];
+            double y = adfCoords[1];
+
+            adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
+            adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
+        }
+};
+
+/************************************************************************/
+/*                         PDFCoordsToSRSCoords()                       */
+/************************************************************************/
+
+void PDFDataset::PDFCoordsToSRSCoords(double x, double y,
+                                            double& X, double &Y)
+{
+    x = x / dfPageWidth * nRasterXSize;
+    y = (1 - y / dfPageHeight) * nRasterYSize;
+
+    X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
+    Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
+
+    if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
+        X = (int)floor(X + 0.5);
+    if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
+        Y = (int)floor(Y + 0.5);
+}
+
+/************************************************************************/
+/*                         PDFGetCircleCenter()                         */
+/************************************************************************/
+
+/* Return the center of a circle, or NULL if it is not recognized */
+
+static OGRPoint* PDFGetCircleCenter(OGRLineString* poLS)
+{
+    if (poLS == NULL || poLS->getNumPoints() != 5)
+        return NULL;
+
+    if (poLS->getY(0) == poLS->getY(2) &&
+        poLS->getX(1) == poLS->getX(3) &&
+        fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < EPSILON &&
+        fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < EPSILON)
+    {
+        return new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
+                            (poLS->getY(1) + poLS->getY(3)) / 2);
+    }
+    return NULL;
+}
+
+/************************************************************************/
+/*                         PDFGetSquareCenter()                         */
+/************************************************************************/
+
+/* Return the center of a square, or NULL if it is not recognized */
+
+static OGRPoint* PDFGetSquareCenter(OGRLineString* poLS)
+{
+    if (poLS == NULL || poLS->getNumPoints() < 4 || poLS->getNumPoints() > 5)
+        return NULL;
+
+    if (poLS->getX(0) == poLS->getX(3) &&
+        poLS->getY(0) == poLS->getY(1) &&
+        poLS->getX(1) == poLS->getX(2) &&
+        poLS->getY(2) == poLS->getY(3) &&
+        fabs(fabs(poLS->getX(0) - poLS->getX(1)) - fabs(poLS->getY(0) - poLS->getY(3))) < EPSILON)
+    {
+        return new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
+                            (poLS->getY(0) + poLS->getY(3)) / 2);
+    }
+    return NULL;
+}
+
+/************************************************************************/
+/*                        PDFGetTriangleCenter()                        */
+/************************************************************************/
+
+/* Return the center of a equilateral triangle, or NULL if it is not recognized */
+
+static OGRPoint* PDFGetTriangleCenter(OGRLineString* poLS)
+{
+    if (poLS == NULL || poLS->getNumPoints() < 3 || poLS->getNumPoints() > 4)
+        return NULL;
+
+    double dfSqD1 = SQUARE(poLS->getX(0) - poLS->getX(1)) + SQUARE(poLS->getY(0) - poLS->getY(1));
+    double dfSqD2 = SQUARE(poLS->getX(1) - poLS->getX(2)) + SQUARE(poLS->getY(1) - poLS->getY(2));
+    double dfSqD3 = SQUARE(poLS->getX(0) - poLS->getX(2)) + SQUARE(poLS->getY(0) - poLS->getY(2));
+    if (fabs(dfSqD1 - dfSqD2) < EPSILON && fabs(dfSqD2 - dfSqD3) < EPSILON)
+    {
+        return new OGRPoint((poLS->getX(0) + poLS->getX(1) + poLS->getX(2)) / 3,
+                            (poLS->getY(0) + poLS->getY(1) + poLS->getY(2)) / 3);
+    }
+    return NULL;
+}
+
+/************************************************************************/
+/*                          PDFGetStarCenter()                          */
+/************************************************************************/
+
+/* Return the center of a 5-point star, or NULL if it is not recognized */
+
+static OGRPoint* PDFGetStarCenter(OGRLineString* poLS)
+{
+    if (poLS == NULL || poLS->getNumPoints() < 10 || poLS->getNumPoints() > 11)
+        return NULL;
+
+    double dfSqD01 = SQUARE(poLS->getX(0) - poLS->getX(1)) +
+                     SQUARE(poLS->getY(0) - poLS->getY(1));
+    double dfSqD02 = SQUARE(poLS->getX(0) - poLS->getX(2)) +
+                       SQUARE(poLS->getY(0) - poLS->getY(2));
+    double dfSqD13 = SQUARE(poLS->getX(1) - poLS->getX(3)) +
+                      SQUARE(poLS->getY(1) - poLS->getY(3));
+    const double dfSin18divSin126 = 0.38196601125;
+    int bOK = fabs(dfSqD13 / dfSqD02 - SQUARE(dfSin18divSin126)) < EPSILON;
+    for(int i=1;i<10 && bOK;i++)
+    {
+        double dfSqDiip1 = SQUARE(poLS->getX(i) - poLS->getX((i+1)%10)) +
+                           SQUARE(poLS->getY(i) - poLS->getY((i+1)%10));
+        if (fabs(dfSqDiip1 - dfSqD01) > EPSILON)
+        {
+            bOK = FALSE;
+        }
+        double dfSqDiip2 = SQUARE(poLS->getX(i) - poLS->getX((i+2)%10)) +
+                           SQUARE(poLS->getY(i) - poLS->getY((i+2)%10));
+        if ( (i%2) == 1 && fabs(dfSqDiip2 - dfSqD13) > EPSILON )
+        {
+            bOK = FALSE;
+        }
+        if ( (i%2) == 0 && fabs(dfSqDiip2 - dfSqD02) > EPSILON )
+        {
+            bOK = FALSE;
+        }
+    }
+    if (bOK)
+    {
+        return new OGRPoint((poLS->getX(0) + poLS->getX(2) + poLS->getX(4) +
+                             poLS->getX(6) + poLS->getX(8)) / 5,
+                            (poLS->getY(0) + poLS->getY(2) + poLS->getY(4) +
+                             poLS->getY(6) + poLS->getY(8)) / 5);
+    }
+    return NULL;
+}
+
+/************************************************************************/
+/*                            UnstackTokens()                           */
+/************************************************************************/
+
+int PDFDataset::UnstackTokens(const char* pszToken,
+                                    int nRequiredArgs,
+                                    char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
+                                    int& nTokenStackSize,
+                                    double* adfCoords)
+{
+    if (nTokenStackSize < nRequiredArgs)
+    {
+        CPLDebug("PDF", "not enough arguments for %s", pszToken);
+        return FALSE;
+    }
+    nTokenStackSize -= nRequiredArgs;
+    for(int i=0;i<nRequiredArgs;i++)
+    {
+        adfCoords[i] = CPLAtof(aszTokenStack[nTokenStackSize+i]);
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                           ParseContent()                             */
+/************************************************************************/
+
+#define NEW_SUBPATH -99
+#define CLOSE_SUBPATH -98
+#define FILL_SUBPATH -97
+
+OGRGeometry* PDFDataset::ParseContent(const char* pszContent,
+                                            GDALPDFObject* poResources,
+                                            int bInitBDCStack,
+                                            int bMatchQ,
+                                            std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
+                                            OGRPDFLayer* poCurLayer)
+{
+
+#define PUSH(aszTokenStack, str, strlen) \
+    do \
+    { \
+        if(nTokenStackSize < TOKEN_STACK_SIZE) \
+            memcpy(aszTokenStack[nTokenStackSize ++], str, strlen + 1); \
+        else \
+        { \
+            CPLError(CE_Failure, CPLE_AppDefined, "Max token stack size reached");\
+            return NULL; \
+        }; \
+    } while(0)
+
+#define ADD_CHAR(szToken, c) \
+    do \
+    { \
+        if(nTokenSize < MAX_TOKEN_SIZE-1) \
+        { \
+            szToken[nTokenSize ++ ] = c; \
+            szToken[nTokenSize ] = '\0'; \
+        } \
+        else \
+        { \
+            CPLError(CE_Failure, CPLE_AppDefined, "Max token size reached");\
+            return NULL; \
+        }; \
+    } while(0)
+
+    char szToken[MAX_TOKEN_SIZE];
+    int nTokenSize = 0;
+    char ch;
+    char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE];
+    int nTokenStackSize = 0;
+    int bInString = FALSE;
+    int nBDCLevel = 0;
+    int nParenthesisLevel = 0;
+    int nArrayLevel = 0;
+    int nBTLevel = 0;
+    
+    int bCollectAllObjects = poResources != NULL && !bInitBDCStack && !bMatchQ;
+
+    GraphicState oGS;
+    std::stack<GraphicState> oGSStack;
+    std::stack<OGRPDFLayer*> oLayerStack;
+
+    std::vector<double> oCoords;
+    int bHasFoundFill = FALSE;
+    int bHasMultiPart = FALSE;
+    
+    szToken[0] = '\0';
+
+    if (bInitBDCStack)
+    {
+        PUSH(aszTokenStack, "dummy", 5);
+        PUSH(aszTokenStack, "dummy", 5);
+        oLayerStack.push(NULL);
+    }
+
+    while((ch = *pszContent) != '\0')
+    {
+        int bPushToken = FALSE;
+
+        if (!bInString && ch == '%')
+        {
+            /* Skip comments until end-of-line */
+            while((ch = *pszContent) != '\0')
+            {
+                if (ch == '\r' || ch == '\n')
+                    break;
+                pszContent ++;
+            }
+            if (ch == 0)
+                break;
+        }
+        else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
+        {
+            bPushToken = TRUE;
+        }
+
+        /* Ignore arrays */
+        else if (!bInString && nTokenSize == 0 && ch == '[')
+        {
+            nArrayLevel ++;
+        }
+        else if (!bInString && nArrayLevel && nTokenSize == 0 && ch == ']')
+        {
+            nArrayLevel --;
+        }
+
+        else if (!bInString && nTokenSize == 0 && ch == '(')
+        {
+            bInString = TRUE;
+            nParenthesisLevel ++;
+            ADD_CHAR(szToken, ch);
+        }
+        else if (bInString && ch == '(')
+        {
+            nParenthesisLevel ++;
+            ADD_CHAR(szToken, ch);
+        }
+        else if (bInString && ch == ')')
+        {
+            nParenthesisLevel --;
+            ADD_CHAR(szToken, ch);
+            if (nParenthesisLevel == 0)
+            {
+                bInString = FALSE;
+                bPushToken = TRUE;
+            }
+        }
+        else if (ch == '<' && pszContent[1] == '<' && nTokenSize == 0)
+        {
+            int nDictDepth = 0;
+
+            while(*pszContent != '\0')
+            {
+                if (pszContent[0] == '<' && pszContent[1] == '<')
+                {
+                    ADD_CHAR(szToken, '<');
+                    ADD_CHAR(szToken, '<');
+                    nDictDepth ++;
+                    pszContent += 2;
+                }
+                else if (pszContent[0] == '>' && pszContent[1] == '>')
+                {
+                    ADD_CHAR(szToken, '>');
+                    ADD_CHAR(szToken, '>');
+                    nDictDepth --;
+                    pszContent += 2;
+                    if (nDictDepth == 0)
+                        break;
+                }
+                else
+                {
+                    ADD_CHAR(szToken, *pszContent);
+                    pszContent ++;
+                }
+            }
+            if (nDictDepth == 0)
+            {
+                bPushToken = TRUE;
+                pszContent --;
+            }
+            else
+                break;
+        }
+        else
+        {
+            ADD_CHAR(szToken, ch);
+        }
+
+        pszContent ++;
+        if (pszContent[0] == '\0')
+            bPushToken = TRUE;
+
+#define EQUAL1(szToken, s) (szToken[0] == s[0] && szToken[1] == '\0')
+#define EQUAL2(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == '\0')
+#define EQUAL3(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == s[2] && szToken[3] == '\0')
+
+        if (bPushToken && nTokenSize)
+        {
+            if (EQUAL2(szToken, "BI"))
+            {
+                while(*pszContent != '\0')
+                {
+                    if( pszContent[0] == 'E' && pszContent[1] == 'I' && pszContent[2] == ' ' )
+                    {
+                        break;
+                    }
+                    pszContent ++;
+                }
+                if( pszContent[0] == 'E' )
+                    pszContent += 3;
+                else
+                    return NULL;
+            }
+            else if (EQUAL3(szToken, "BDC"))
+            {
+                if (nTokenStackSize < 2)
+                {
+                    CPLDebug("PDF",
+                                "not enough arguments for %s",
+                                szToken);
+                    return NULL;
+                }
+                nTokenStackSize -= 2;
+                const char* pszOC = aszTokenStack[nTokenStackSize];
+                const char* pszOCGName = aszTokenStack[nTokenStackSize+1];
+
+                nBDCLevel ++;
+
+                if( EQUAL3(pszOC, "/OC") && pszOCGName[0] == '/' )
+                {
+                    std::map<CPLString, OGRPDFLayer*>::iterator oIter =
+                        oMapPropertyToLayer.find(pszOCGName + 1);
+                    if( oIter != oMapPropertyToLayer.end() )
+                    {
+                        poCurLayer = oIter->second;
+                        //CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
+                    }
+                }
+
+                oLayerStack.push(poCurLayer);
+                //CPLDebug("PDF", "%s %s BDC", osOC.c_str(), osOCGName.c_str());
+            }
+            else if (EQUAL3(szToken, "EMC"))
+            {
+                //CPLDebug("PDF", "EMC");
+                if( !oLayerStack.empty() )
+                {
+                    oLayerStack.pop();
+                    if( !oLayerStack.empty() )
+                        poCurLayer = oLayerStack.top();
+                    else
+                        poCurLayer = NULL;
+
+                    /*if (poCurLayer)
+                    {
+                        CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
+                    }*/
+                }
+                else
+                {
+                    CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                    poCurLayer = NULL;
+                    //return NULL;
+                }
+
+                nBDCLevel --;
+                if (nBDCLevel == 0 && bInitBDCStack)
+                    break;
+            }
+
+            /* Ignore any text stuff */
+            else if (EQUAL2(szToken, "BT"))
+                nBTLevel ++;
+            else if (EQUAL2(szToken, "ET"))
+            {
+                nBTLevel --;
+                if (nBTLevel < 0)
+                {
+                    CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                    return NULL;
+                }
+            }
+            else if (!nArrayLevel && !nBTLevel)
+            {
+                int bEmitFeature = FALSE;
+
+                if( szToken[0] < 'A' )
+                {
+                    PUSH(aszTokenStack, szToken, nTokenSize);
+                }
+                else if (EQUAL1(szToken, "q"))
+                {
+                    oGSStack.push(oGS);
+                }
+                else if (EQUAL1(szToken, "Q"))
+                {
+                    if (oGSStack.empty())
+                    {
+                        CPLDebug("PDF", "not enough arguments for %s", szToken);
+                        return NULL;
+                    }
+
+                    oGS = oGSStack.top();
+                    oGSStack.pop();
+
+                    if (oGSStack.empty() && bMatchQ)
+                        break;
+                }
+                else if (EQUAL2(szToken, "cm"))
+                {
+                    double adfMatrix[6];
+                    if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfMatrix))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    oGS.MultiplyBy(adfMatrix);
+                }
+                else if (EQUAL1(szToken, "b") || /* closepath, fill, stroke */
+                         EQUAL2(szToken, "b*")   /* closepath, eofill, stroke */)
+                {
+                    if (!(oCoords.size() > 0 &&
+                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
+                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
+                    {
+                        oCoords.push_back(CLOSE_SUBPATH);
+                        oCoords.push_back(CLOSE_SUBPATH);
+                    }
+                    oCoords.push_back(FILL_SUBPATH);
+                    oCoords.push_back(FILL_SUBPATH);
+                    bHasFoundFill = TRUE;
+
+                    bEmitFeature = TRUE;
+                }
+                else if (EQUAL1(szToken, "B") ||  /* fill, stroke */
+                         EQUAL2(szToken, "B*") || /* eofill, stroke */
+                         EQUAL1(szToken, "f") ||  /* fill */
+                         EQUAL1(szToken, "F") ||  /* fill */
+                         EQUAL2(szToken, "f*")    /* eofill */ )
+                {
+                    oCoords.push_back(FILL_SUBPATH);
+                    oCoords.push_back(FILL_SUBPATH);
+                    bHasFoundFill = TRUE;
+
+                    bEmitFeature = TRUE;
+                }
+                else if (EQUAL1(szToken, "h")) /* close subpath */
+                {
+                    if (!(oCoords.size() > 0 &&
+                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
+                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
+                    {
+                        oCoords.push_back(CLOSE_SUBPATH);
+                        oCoords.push_back(CLOSE_SUBPATH);
+                    }
+                }
+                else if (EQUAL1(szToken, "n")) /* new subpath without stroking or filling */
+                {
+                    oCoords.resize(0);
+                }
+                else if (EQUAL1(szToken, "s")) /* close and stroke */
+                {
+                    if (!(oCoords.size() > 0 &&
+                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
+                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
+                    {
+                        oCoords.push_back(CLOSE_SUBPATH);
+                        oCoords.push_back(CLOSE_SUBPATH);
+                    }
+
+                    bEmitFeature = TRUE;
+                }
+                else if (EQUAL1(szToken, "S")) /* stroke */
+                {
+                    bEmitFeature = TRUE;
+                }
+                else if (EQUAL1(szToken, "m") || EQUAL1(szToken, "l"))
+                {
+                    double adfCoords[2];
+                    if (!UnstackTokens(szToken, 2, aszTokenStack, nTokenStackSize, adfCoords))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    if (EQUAL1(szToken, "m"))
+                    {
+                        if (oCoords.size() != 0)
+                            bHasMultiPart = TRUE;
+                        oCoords.push_back(NEW_SUBPATH);
+                        oCoords.push_back(NEW_SUBPATH);
+                    }
+
+                    oGS.ApplyMatrix(adfCoords);
+                    oCoords.push_back(adfCoords[0]);
+                    oCoords.push_back(adfCoords[1]);
+                }
+                else if (EQUAL1(szToken, "c")) /* Bezier curve */
+                {
+                    double adfCoords[6];
+                    if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfCoords))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    oGS.ApplyMatrix(adfCoords + 4);
+                    oCoords.push_back(adfCoords[4]);
+                    oCoords.push_back(adfCoords[5]);
+                }
+                else if (EQUAL1(szToken, "v") || EQUAL1(szToken, "y")) /* Bezier curve */
+                {
+                    double adfCoords[4];
+                    if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    oGS.ApplyMatrix(adfCoords + 2);
+                    oCoords.push_back(adfCoords[2]);
+                    oCoords.push_back(adfCoords[3]);
+                }
+                else if (EQUAL2(szToken, "re")) /* Rectangle */
+                {
+                    double adfCoords[4];
+                    if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    adfCoords[2] += adfCoords[0];
+                    adfCoords[3] += adfCoords[1];
+
+                    oGS.ApplyMatrix(adfCoords);
+                    oGS.ApplyMatrix(adfCoords + 2);
+
+                    if (oCoords.size() != 0)
+                        bHasMultiPart = TRUE;
+                    oCoords.push_back(NEW_SUBPATH);
+                    oCoords.push_back(NEW_SUBPATH);
+                    oCoords.push_back(adfCoords[0]);
+                    oCoords.push_back(adfCoords[1]);
+                    oCoords.push_back(adfCoords[2]);
+                    oCoords.push_back(adfCoords[1]);
+                    oCoords.push_back(adfCoords[2]);
+                    oCoords.push_back(adfCoords[3]);
+                    oCoords.push_back(adfCoords[0]);
+                    oCoords.push_back(adfCoords[3]);
+                    oCoords.push_back(CLOSE_SUBPATH);
+                    oCoords.push_back(CLOSE_SUBPATH);
+                }
+
+                else if (EQUAL2(szToken, "Do"))
+                {
+                    if (nTokenStackSize == 0)
+                    {
+                        CPLDebug("PDF",
+                                 "not enough arguments for %s",
+                                 szToken);
+                        return NULL;
+                    }
+
+                    CPLString osObjectName = aszTokenStack[--nTokenStackSize];
+
+                    if (osObjectName[0] != '/')
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+
+                    if (poResources == NULL)
+                    {
+                        if (osObjectName.find("/SymImage") == 0)
+                        {
+                            oCoords.push_back(oGS.adfCM[4] + oGS.adfCM[0] / 2);
+                            oCoords.push_back(oGS.adfCM[5] + oGS.adfCM[3] / 2);
+
+                            szToken[0] = '\0';
+                            nTokenSize = 0;
+
+                            if( poCurLayer != NULL)
+                                bEmitFeature = TRUE;
+                            else
+                                continue;
+                        }
+                        else
+                        {
+                            //CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                            return NULL;
+                        }
+                    }
+
+                    if( !bEmitFeature )
+                    {
+                        GDALPDFObject* poXObject =
+                            poResources->GetDictionary()->Get("XObject");
+                        if (poXObject == NULL ||
+                            poXObject->GetType() != PDFObjectType_Dictionary)
+                        {
+                            CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                            return NULL;
+                        }
+
+                        GDALPDFObject* poObject =
+                            poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
+                        if (poObject == NULL)
+                        {
+                            CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                            return NULL;
+                        }
+
+                        int bParseStream = TRUE;
+                        /* Check if the object is an image. If so, no need to try to parse */
+                        /* it. */
+                        if (poObject->GetType() == PDFObjectType_Dictionary)
+                        {
+                            GDALPDFObject* poSubtype = poObject->GetDictionary()->Get("Subtype");
+                            if (poSubtype != NULL &&
+                                poSubtype->GetType() == PDFObjectType_Name &&
+                                poSubtype->GetName() == "Image" )
+                            {
+                                bParseStream = FALSE;
+                            }
+                        }
+
+                        if( bParseStream )
+                        {
+                            GDALPDFStream* poStream = poObject->GetStream();
+                            if (!poStream)
+                            {
+                                CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                                return NULL;
+                            }
+
+                            char* pszStr = poStream->GetBytes();
+                            if( pszStr )
+                            {
+                                OGRGeometry* poGeom = ParseContent(pszStr, NULL, FALSE, FALSE,
+                                                                oMapPropertyToLayer, poCurLayer);
+                                CPLFree(pszStr);
+                                if (poGeom && !bCollectAllObjects)
+                                    return poGeom;
+                                delete poGeom;
+                            }
+                        }
+                    }
+                }
+                else if( EQUAL2(szToken, "RG") || EQUAL2(szToken, "rg") )
+                {
+                    double* padf = ( EQUAL2(szToken, "RG") ) ? oGS.adfStrokeColor : oGS.adfFillColor;
+                    if (!UnstackTokens(szToken, 3, aszTokenStack, nTokenStackSize, padf))
+                    {
+                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
+                        return NULL;
+                    }
+                }
+                else if (oMapOperators.find(szToken) != oMapOperators.end())
+                {
+                    int nArgs = oMapOperators[szToken];
+                    if (nArgs < 0)
+                    {
+                        while( nTokenStackSize != 0 )
+                        {
+                            CPLString osTopToken = aszTokenStack[--nTokenStackSize];
+                            if (oMapOperators.find(osTopToken) != oMapOperators.end())
+                                break;
+                        }
+                    }
+                    else
+                    {
+                        if( nArgs > nTokenStackSize )
+                        {
+                            CPLDebug("PDF",
+                                    "not enough arguments for %s",
+                                    szToken);
+                            return NULL;
+                        }
+                        nTokenStackSize -= nArgs;
+                    }
+                }
+                else
+                {
+                    PUSH(aszTokenStack, szToken, nTokenSize);
+                }
+
+                if( bEmitFeature && poCurLayer != NULL)
+                {
+                    OGRGeometry* poGeom = BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
+                    bHasFoundFill = bHasMultiPart = FALSE;
+                    if (poGeom)
+                    {
+                        OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
+                        if( bSetStyle )
+                        {
+                            OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
+                            if( eType == wkbLineString || eType == wkbMultiLineString )
+                            {
+                                poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X)",
+                                                                    (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
+                                                                    (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
+                                                                    (int)(oGS.adfStrokeColor[2] * 255 + 0.5)));
+                            }
+                            else if( eType == wkbPolygon || eType == wkbMultiPolygon )
+                            {
+                                poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X);BRUSH(fc:#%02X%02X%02X)",
+                                                                    (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
+                                                                    (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
+                                                                    (int)(oGS.adfStrokeColor[2] * 255 + 0.5),
+                                                                    (int)(oGS.adfFillColor[0] * 255 + 0.5),
+                                                                    (int)(oGS.adfFillColor[1] * 255 + 0.5),
+                                                                    (int)(oGS.adfFillColor[2] * 255 + 0.5)));
+                            }
+                        }
+                        poGeom->assignSpatialReference(poCurLayer->GetSpatialRef());
+                        poFeature->SetGeometryDirectly(poGeom);
+                        poCurLayer->CreateFeature(poFeature);
+                        delete poFeature;
+                    }
+
+                    oCoords.resize(0);
+                }
+            }
+
+            szToken[0] = '\0';
+            nTokenSize = 0;
+        }
+    }
+
+    if (nTokenStackSize != 0)
+    {
+        while(nTokenStackSize != 0)
+        {
+            nTokenStackSize--;
+            CPLDebug("PDF",
+                     "Remaing values in stack : %s",
+                     aszTokenStack[nTokenStackSize]);
+        }
+        return  NULL;
+    }
+
+    if (bCollectAllObjects)
+        return NULL;
+
+    return BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
+}
+
+/************************************************************************/
+/*                           BuildGeometry()                            */
+/************************************************************************/
+
+OGRGeometry* PDFDataset::BuildGeometry(std::vector<double>& oCoords,
+                                             int bHasFoundFill,
+                                             int bHasMultiPart)
+{
+    OGRGeometry* poGeom = NULL;
+
+    if (!oCoords.size())
+        return NULL;
+
+    if (oCoords.size() == 2)
+    {
+        double X, Y;
+        PDFCoordsToSRSCoords(oCoords[0], oCoords[1], X, Y);
+        poGeom = new OGRPoint(X, Y);
+    }
+    else if (!bHasFoundFill)
+    {
+        OGRLineString* poLS = NULL;
+        OGRMultiLineString* poMLS = NULL;
+        if (bHasMultiPart)
+        {
+            poMLS = new OGRMultiLineString();
+            poGeom = poMLS;
+        }
+
+        for(size_t i=0;i<oCoords.size();i+=2)
+        {
+            if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
+            {
+                poLS = new OGRLineString();
+                if (poMLS)
+                    poMLS->addGeometryDirectly(poLS);
+                else
+                    poGeom = poLS;
+            }
+            else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
+            {
+                if (poLS && poLS->getNumPoints() >= 2 &&
+                    !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
+                        poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
+                {
+                    poLS->addPoint(poLS->getX(0), poLS->getY(0));
+                }
+            }
+            else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
+            {
+                /* Should not happen */
+            }
+            else
+            {
+                if (poLS)
+                {
+                    double X, Y;
+                    PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
+
+                    poLS->addPoint(X, Y);
+                }
+            }
+        }
+
+        /* Recognize points as outputed by GDAL (ogr-sym-2 : circle (not filled)) */
+        OGRGeometry* poCenter = NULL;
+        if (poCenter == NULL && poLS != NULL && poLS->getNumPoints() == 5)
+        {
+            poCenter = PDFGetCircleCenter(poLS);
+        }
+
+        /* Recognize points as outputed by GDAL (ogr-sym-4: square (not filled)) */
+        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 4 || poLS->getNumPoints() == 5))
+        {
+            poCenter = PDFGetSquareCenter(poLS);
+        }
+
+        /* Recognize points as outputed by GDAL (ogr-sym-6: triangle (not filled)) */
+        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 3 || poLS->getNumPoints() == 4))
+        {
+            poCenter = PDFGetTriangleCenter(poLS);
+        }
+
+        /* Recognize points as outputed by GDAL (ogr-sym-8: star (not filled)) */
+        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 10 || poLS->getNumPoints() == 11))
+        {
+            poCenter = PDFGetStarCenter(poLS);
+        }
+
+        if (poCenter == NULL && poMLS != NULL && poMLS->getNumGeometries() == 2)
+        {
+            OGRLineString* poLS1 = (OGRLineString* )poMLS->getGeometryRef(0);
+            OGRLineString* poLS2 = (OGRLineString* )poMLS->getGeometryRef(1);
+
+            /* Recognize points as outputed by GDAL (ogr-sym-0: cross (+) ) */
+            if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
+                poLS1->getY(0) == poLS1->getY(1) &&
+                poLS2->getX(0) == poLS2->getX(1) &&
+                fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS2->getY(0) - poLS2->getY(1))) < EPSILON &&
+                fabs((poLS1->getX(0) + poLS1->getX(1)) / 2 - poLS2->getX(0)) < EPSILON &&
+                fabs((poLS2->getY(0) + poLS2->getY(1)) / 2 - poLS1->getY(0)) < EPSILON)
+            {
+                poCenter = new OGRPoint(poLS2->getX(0), poLS1->getY(0));
+            }
+            /* Recognize points as outputed by GDAL (ogr-sym-1: diagcross (X) ) */
+            else if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
+                     poLS1->getX(0) == poLS2->getX(0) &&
+                     poLS1->getY(0) == poLS2->getY(1) &&
+                     poLS1->getX(1) == poLS2->getX(1) &&
+                     poLS1->getY(1) == poLS2->getY(0) &&
+                     fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS1->getY(0) - poLS1->getY(1))) < EPSILON)
+            {
+                poCenter = new OGRPoint((poLS1->getX(0) + poLS1->getX(1)) / 2,
+                                        (poLS1->getY(0) + poLS1->getY(1)) / 2);
+            }
+        }
+
+        if (poCenter)
+        {
+            delete poGeom;
+            poGeom = poCenter;
+        }
+    }
+    else
+    {
+        OGRLinearRing* poLS = NULL;
+        int nPolys = 0;
+        OGRGeometry** papoPoly = NULL;
+
+        for(size_t i=0;i<oCoords.size();i+=2)
+        {
+            if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
+            {
+                delete poLS;
+                poLS = new OGRLinearRing();
+            }
+            else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
+                        (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
+            {
+                if (poLS)
+                {
+                    poLS->closeRings();
+
+                    OGRPoint* poCenter = NULL;
+
+                    if (nPolys == 0 &&
+                        poLS &&
+                        poLS->getNumPoints() == 5)
+                    {
+                        /* Recognize points as outputed by GDAL (ogr-sym-3 : circle (filled)) */
+                        poCenter = PDFGetCircleCenter(poLS);
+
+                        /* Recognize points as outputed by GDAL (ogr-sym-5: square (filled)) */
+                        if (poCenter == NULL)
+                            poCenter = PDFGetSquareCenter(poLS);
+
+                        /* ESRI points */
+                        if (poCenter == NULL &&
+                            oCoords.size() == 14 &&
+                            poLS->getY(0) == poLS->getY(1) &&
+                            poLS->getX(1) == poLS->getX(2) &&
+                            poLS->getY(2) == poLS->getY(3) &&
+                            poLS->getX(3) == poLS->getX(0))
+                        {
+                            poCenter = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
+                                                    (poLS->getY(0) + poLS->getY(2)) / 2);
+                        }
+                    }
+                    /* Recognize points as outputed by GDAL (ogr-sym-7: triangle (filled)) */
+                    else if (nPolys == 0 &&
+                             poLS &&
+                             poLS->getNumPoints() == 4)
+                    {
+                        poCenter = PDFGetTriangleCenter(poLS);
+                    }
+                    /* Recognize points as outputed by GDAL (ogr-sym-9: star (filled)) */
+                    else if (nPolys == 0 &&
+                             poLS &&
+                             poLS->getNumPoints() == 11)
+                    {
+                        poCenter = PDFGetStarCenter(poLS);
+                    }
+
+                    if (poCenter)
+                    {
+                        poGeom = poCenter;
+                        break;
+                    }
+
+                    if (poLS->getNumPoints() >= 3)
+                    {
+                        OGRPolygon* poPoly =  new OGRPolygon();
+                        poPoly->addRingDirectly(poLS);
+                        poLS = NULL;
+
+                        papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
+                        papoPoly[nPolys ++] = poPoly;
+                    }
+                    else
+                    {
+                        delete poLS;
+                        poLS = NULL;
+                    }
+                }
+            }
+            else
+            {
+                if (poLS)
+                {
+                    double X, Y;
+                    PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
+
+                    poLS->addPoint(X, Y);
+                }
+            }
+        }
+
+        delete poLS;
+
+        int bIsValidGeometry;
+        if (nPolys == 2 &&
+            ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
+            ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
+        {
+            OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
+            OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
+            if (poRing0->getNumPoints() == poRing1->getNumPoints())
+            {
+                int bSameRing = TRUE;
+                for(int i=0;i<poRing0->getNumPoints();i++)
+                {
+                    if (poRing0->getX(i) != poRing1->getX(i))
+                    {
+                        bSameRing = FALSE;
+                        break;
+                    }
+                    if (poRing0->getY(i) != poRing1->getY(i))
+                    {
+                        bSameRing = FALSE;
+                        break;
+                    }
+                }
+
+                /* Just keep on ring if they are identical */
+                if (bSameRing)
+                {
+                    delete papoPoly[1];
+                    nPolys = 1;
+                }
+            }
+        }
+        if (nPolys)
+        {
+            poGeom = OGRGeometryFactory::organizePolygons(
+                    papoPoly, nPolys, &bIsValidGeometry, NULL);
+        }
+        CPLFree(papoPoly);
+    }
+
+    return poGeom;
+}
+
+/************************************************************************/
+/*                          ExploreContents()                           */
+/************************************************************************/
+
+void PDFDataset::ExploreContents(GDALPDFObject* poObj,
+                                       GDALPDFObject* poResources)
+{
+    std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
+
+    if (poObj->GetType() == PDFObjectType_Array)
+    {
+        GDALPDFArray* poArray = poObj->GetArray();
+        for(int i=0;i<poArray->GetLength();i++)
+            ExploreContents(poArray->Get(i), poResources);
+    }
+
+    if (poObj->GetType() != PDFObjectType_Dictionary)
+        return;
+
+    GDALPDFStream* poStream = poObj->GetStream();
+    if (!poStream)
+        return;
+
+    char* pszStr = poStream->GetBytes();
+    if (!pszStr)
+        return;
+
+    const char* pszMCID = (const char*) pszStr;
+    while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
+    {
+        const char* pszBDC = strstr(pszMCID, "BDC");
+        if (pszBDC)
+        {
+            /* Hack for http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
+            /* FIXME: that logic is too fragile. */
+            const char* pszStartParsing = pszBDC;
+            const char* pszAfterBDC = pszBDC + 3;
+            int bMatchQ = FALSE;
+            while (pszAfterBDC[0] == ' ' || pszAfterBDC[0] == '\r' || pszAfterBDC[0] == '\n')
+                pszAfterBDC ++;
+            if (strncmp(pszAfterBDC, "0 0 m", 5) == 0)
+            {
+                const char* pszLastq = pszBDC;
+                while(pszLastq > pszStr && *pszLastq != 'q')
+                    pszLastq --;
+
+                if (pszLastq > pszStr && *pszLastq == 'q' &&
+                    (pszLastq[-1] == ' ' || pszLastq[-1] == '\r' || pszLastq[-1] == '\n') &&
+                    (pszLastq[1] == ' ' || pszLastq[1] == '\r' || pszLastq[1] == '\n'))
+                {
+                    pszStartParsing = pszLastq;
+                    bMatchQ = TRUE;
+                }
+            }
+
+            int nMCID = atoi(pszMCID + 6);
+            if (GetGeometryFromMCID(nMCID) == NULL)
+            {
+                OGRGeometry* poGeom = ParseContent(pszStartParsing, poResources,
+                                                   !bMatchQ, bMatchQ, oMapPropertyToLayer, NULL);
+                if( poGeom != NULL )
+                {
+                    /* Save geometry in map */
+                    oMapMCID[nMCID] = poGeom;
+                }
+            }
+        }
+        pszMCID += 5;
+    }
+    CPLFree(pszStr);
+}
+
+/************************************************************************/
+/*                   ExploreContentsNonStructured()                     */
+/************************************************************************/
+
+void PDFDataset::ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
+                                                            GDALPDFObject* poResources,
+                                                            std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer)
+{
+    if (poContents->GetType() == PDFObjectType_Array)
+    {
+        GDALPDFArray* poArray = poContents->GetArray();
+        char* pszConcatStr = NULL;
+        int nConcatLen = 0;
+        for(int i=0;i<poArray->GetLength();i++)
+        {
+            GDALPDFObject* poObj = poArray->Get(i);
+            if( poObj->GetType() != PDFObjectType_Dictionary)
+                break;
+            GDALPDFStream* poStream = poObj->GetStream();
+            if (!poStream)
+                break;
+            char* pszStr = poStream->GetBytes();
+            if (!pszStr)
+                break;
+            int nLen = (int)strlen(pszStr);
+            char* pszConcatStrNew = (char*)CPLRealloc(pszConcatStr, nConcatLen + nLen + 1);
+            if( pszConcatStrNew == NULL )
+            {
+                CPLFree(pszStr);
+                break;
+            }
+            pszConcatStr = pszConcatStrNew;
+            memcpy(pszConcatStr + nConcatLen, pszStr, nLen+1);
+            nConcatLen += nLen;
+            CPLFree(pszStr);
+        }
+        if( pszConcatStr )
+            ParseContent(pszConcatStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
+        CPLFree(pszConcatStr);
+        return;
+    }
+
+    if (poContents->GetType() != PDFObjectType_Dictionary)
+        return;
+
+    GDALPDFStream* poStream = poContents->GetStream();
+    if (!poStream)
+        return;
+
+    char* pszStr = poStream->GetBytes();
+    if( !pszStr )
+        return;
+    ParseContent(pszStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
+    CPLFree(pszStr);
+}
+
+void PDFDataset::ExploreContentsNonStructured(GDALPDFObject* poContents,
+                                                    GDALPDFObject* poResources)
+{
+    std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
+    if (poResources != NULL &&
+        poResources->GetType() == PDFObjectType_Dictionary)
+    {
+        GDALPDFObject* poProperties =
+            poResources->GetDictionary()->Get("Properties");
+        if (poProperties != NULL &&
+            poProperties->GetType() == PDFObjectType_Dictionary)
+        {
+            char** papszLayersWithRef = osLayerWithRefList.List();
+            char** papszIter = papszLayersWithRef;
+            std::map< std::pair<int, int>, OGRPDFLayer *> oMapNumGenToLayer;
+            while(papszIter && *papszIter)
+            {
+                char** papszTokens = CSLTokenizeString(*papszIter);
+
+                if( CSLCount(papszTokens) != 3 ) {
+                    CSLDestroy(papszTokens);
+                    CPLDebug("PDF", "Ignore '%s', unparsable.", *papszIter);
+                    papszIter ++;
+                    continue;
+                }
+
+                const char* pszLayerName = papszTokens[0];
+                int nNum = atoi(papszTokens[1]);
+                int nGen = atoi(papszTokens[2]);
+
+                CPLString osSanitizedName(PDFSanitizeLayerName(pszLayerName));
+
+                OGRPDFLayer* poLayer = (OGRPDFLayer*) GetLayerByName(osSanitizedName.c_str());
+                if (poLayer == NULL)
+                {
+                    const char* pszWKT = GetProjectionRef();
+                    OGRSpatialReference* poSRS = NULL;
+                    if (pszWKT && pszWKT[0] != '\0')
+                    {
+                        poSRS = new OGRSpatialReference();
+                        poSRS->importFromWkt((char**) &pszWKT);
+                    }
+
+                    poLayer =
+                        new OGRPDFLayer(this, osSanitizedName.c_str(), poSRS, wkbUnknown);
+                    delete poSRS;
+
+                    papoLayers = (OGRLayer**)
+                        CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+                    papoLayers[nLayers] = poLayer;
+                    nLayers ++;
+                }
+
+                oMapNumGenToLayer[ std::pair<int,int>(nNum, nGen) ] = poLayer;
+
+                CSLDestroy(papszTokens);
+                papszIter ++;
+            }
+
+            std::map<CPLString, GDALPDFObject*>& oMap =
+                                    poProperties->GetDictionary()->GetValues();
+            std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
+            std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
+
+            for(; oIter != oEnd; ++oIter)
+            {
+                const char* pszKey = oIter->first.c_str();
+                GDALPDFObject* poObj = oIter->second;
+                if( poObj->GetRefNum() != 0 )
+                {
+                    std::map< std::pair<int, int>, OGRPDFLayer *>::iterator
+                        oIterNumGenToLayer = oMapNumGenToLayer.find(
+                            std::pair<int,int>(poObj->GetRefNum(), poObj->GetRefGen()) );
+                    if( oIterNumGenToLayer != oMapNumGenToLayer.end() )
+                    {
+                        oMapPropertyToLayer[pszKey] = oIterNumGenToLayer->second;
+                    }
+                }
+            }
+        }
+    }
+
+    if( nLayers == 0 )
+        return;
+
+    ExploreContentsNonStructuredInternal(poContents,
+                                         poResources,
+                                         oMapPropertyToLayer);
+
+    /* Remove empty layers */
+    int i = 0;
+    while(i < nLayers)
+    {
+        if (papoLayers[i]->GetFeatureCount() == 0)
+        {
+            delete papoLayers[i];
+            if (i < nLayers - 1)
+            {
+                memmove(papoLayers + i, papoLayers + i + 1,
+                        (nLayers - 1 - i) * sizeof(OGRPDFLayer*));
+            }
+            nLayers --;
+        }
+        else
+            i ++;
+    }
+}
+
+#endif /* defined(HAVE_POPPLER) || defined(HAVE_PODOFO) */
diff --git a/frmts/pdf/pdfwritabledataset.cpp b/frmts/pdf/pdfwritabledataset.cpp
new file mode 100644
index 0000000..2471d58
--- /dev/null
+++ b/frmts/pdf/pdfwritabledataset.cpp
@@ -0,0 +1,334 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  PDF driver
+ * Purpose:  GDALDataset driver for PDF dataset (writable vector dataset)
+ * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2010-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdal_pdf.h"
+#include "pdfcreatecopy.h"
+#include "memdataset.h"
+
+CPL_CVSID("$Id$");
+
+/************************************************************************/
+/*                      PDFWritableVectorDataset()                      */
+/************************************************************************/
+
+PDFWritableVectorDataset::PDFWritableVectorDataset()
+{
+    papszOptions = NULL;
+    nLayers = 0;
+    papoLayers = NULL;
+    bModified = FALSE;
+}
+
+/************************************************************************/
+/*                      ~PDFWritableVectorDataset()                     */
+/************************************************************************/
+
+PDFWritableVectorDataset::~PDFWritableVectorDataset()
+{
+    SyncToDisk();
+
+    CSLDestroy(papszOptions);
+    for(int i=0;i<nLayers;i++)
+        delete papoLayers[i];
+    CPLFree( papoLayers );
+}
+
+/************************************************************************/
+/*                               Create()                               */
+/************************************************************************/
+
+GDALDataset* PDFWritableVectorDataset::Create( const char * pszName,
+                                               CPL_UNUSED int nXSize,
+                                               CPL_UNUSED int nYSize,
+                                               int nBands,
+                                               CPL_UNUSED GDALDataType eType,
+                                               char ** papszOptions )
+{
+    if( nBands != 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "PDFWritableVectorDataset::Create() can only be called with "
+                 "nBands = 0 to create a vector-only PDF");
+        return NULL;
+    }
+    PDFWritableVectorDataset* poDataset = new PDFWritableVectorDataset();
+
+    poDataset->SetDescription(pszName);
+    poDataset->papszOptions = CSLDuplicate(papszOptions);
+
+    return poDataset;
+}
+
+/************************************************************************/
+/*                           ICreateLayer()                             */
+/************************************************************************/
+
+OGRLayer *
+PDFWritableVectorDataset::ICreateLayer( const char * pszLayerName,
+                                        OGRSpatialReference *poSRS,
+                                        OGRwkbGeometryType eType,
+                                        CPL_UNUSED char ** papszOptions )
+{
+/* -------------------------------------------------------------------- */
+/*      Create the layer object.                                        */
+/* -------------------------------------------------------------------- */
+    OGRLayer* poLayer = new OGRPDFWritableLayer(this, pszLayerName, poSRS, eType);
+
+    papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+    papoLayers[nLayers] = poLayer;
+    nLayers ++;
+
+    return poLayer;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int PDFWritableVectorDataset::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,ODsCCreateLayer) )
+        return TRUE;
+    else
+        return FALSE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *PDFWritableVectorDataset::GetLayer( int iLayer )
+
+{
+    if (iLayer < 0 || iLayer >= nLayers)
+        return NULL;
+
+    return papoLayers[iLayer];
+}
+
+/************************************************************************/
+/*                            GetLayerCount()                           */
+/************************************************************************/
+
+int PDFWritableVectorDataset::GetLayerCount()
+{
+    return nLayers;
+}
+
+/************************************************************************/
+/*                            SyncToDisk()                              */
+/************************************************************************/
+
+OGRErr PDFWritableVectorDataset::SyncToDisk()
+{
+    if (nLayers == 0 || !bModified)
+        return OGRERR_NONE;
+
+    bModified = FALSE;
+
+    OGREnvelope sGlobalExtent;
+    int bHasExtent = FALSE;
+    for(int i=0;i<nLayers;i++)
+    {
+        OGREnvelope sExtent;
+        if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
+        {
+            bHasExtent = TRUE;
+            sGlobalExtent.Merge(sExtent);
+        }
+    }
+    if (!bHasExtent ||
+        sGlobalExtent.MinX == sGlobalExtent.MaxX ||
+        sGlobalExtent.MinY == sGlobalExtent.MaxY)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot compute spatial extent of features");
+        return OGRERR_FAILURE;
+    }
+
+    PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
+    const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
+    if (pszStreamCompressMethod)
+    {
+        if( EQUAL(pszStreamCompressMethod, "NONE") )
+            eStreamCompressMethod = COMPRESS_NONE;
+        else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
+            eStreamCompressMethod = COMPRESS_DEFLATE;
+        else
+        {
+            CPLError( CE_Warning, CPLE_NotSupported,
+                    "Unsupported value for STREAM_COMPRESS.");
+        }
+    }
+
+    const char* pszGEO_ENCODING =
+        CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
+
+    double dfDPI = CPLAtof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
+    if (dfDPI < 72.0)
+        dfDPI = 72.0;
+
+    const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
+
+    int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
+
+    PDFMargins sMargins;
+    sMargins.nLeft = nMargin;
+    sMargins.nRight = nMargin;
+    sMargins.nTop = nMargin;
+    sMargins.nBottom = nMargin;
+
+    const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
+    if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
+
+    const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
+    if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
+
+    const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
+    if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
+
+    const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
+    if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
+
+    const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
+    const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
+    const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
+
+    const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
+    const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
+    int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
+    const char* pszOGRLinkField = CSLFetchNameValue(papszOptions, "OGR_LINK_FIELD");
+
+    const char* pszOffLayers = CSLFetchNameValue(papszOptions, "OFF_LAYERS");
+    const char* pszExclusiveLayers = CSLFetchNameValue(papszOptions, "EXCLUSIVE_LAYERS");
+
+    const char* pszJavascript = CSLFetchNameValue(papszOptions, "JAVASCRIPT");
+    const char* pszJavascriptFile = CSLFetchNameValue(papszOptions, "JAVASCRIPT_FILE");
+
+/* -------------------------------------------------------------------- */
+/*      Create file.                                                    */
+/* -------------------------------------------------------------------- */
+    VSILFILE* fp = VSIFOpenL(GetDescription(), "wb");
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Unable to create PDF file %s.\n",
+                  GetDescription() );
+        return OGRERR_FAILURE;
+    }
+
+    GDALPDFWriter oWriter(fp);
+
+    double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
+
+    int nWidth, nHeight;
+
+    if (dfRatio < 1)
+    {
+        nWidth = 1024;
+        nHeight = nWidth * dfRatio;
+    }
+    else
+    {
+        nHeight = 1024;
+        nWidth = nHeight / dfRatio;
+    }
+
+    GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
+
+    double adfGeoTransform[6];
+    adfGeoTransform[0] = sGlobalExtent.MinX;
+    adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
+    adfGeoTransform[2] = 0;
+    adfGeoTransform[3] = sGlobalExtent.MaxY;
+    adfGeoTransform[4] = 0;
+    adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
+
+    poSrcDS->SetGeoTransform(adfGeoTransform);
+
+    OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
+    if (poSRS)
+    {
+        char* pszWKT = NULL;
+        poSRS->exportToWkt(&pszWKT);
+        poSrcDS->SetProjection(pszWKT);
+        CPLFree(pszWKT);
+    }
+
+    oWriter.SetInfo(poSrcDS, papszOptions);
+
+    oWriter.StartPage(poSrcDS,
+                      dfDPI,
+                      pszGEO_ENCODING,
+                      pszNEATLINE,
+                      &sMargins,
+                      eStreamCompressMethod,
+                      bWriteOGRAttributes);
+
+    int iObj = 0;
+    
+    char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
+
+    for(int i=0;i<nLayers;i++)
+    {
+        CPLString osLayerName;
+        if (CSLCount(papszLayerNames) < nLayers)
+            osLayerName = papoLayers[i]->GetName();
+        else
+            osLayerName = papszLayerNames[i];
+
+        oWriter.WriteOGRLayer((OGRDataSourceH)this,
+                              i,
+                              pszOGRDisplayField,
+                              pszOGRLinkField,
+                              osLayerName,
+                              bWriteOGRAttributes,
+                              iObj);
+    }
+
+    CSLDestroy(papszLayerNames);
+
+    oWriter.EndPage(pszExtraImages,
+                    pszExtraStream,
+                    pszExtraLayerName,
+                    pszOffLayers,
+                    pszExclusiveLayers);
+
+    if (pszJavascript)
+        oWriter.WriteJavascript(pszJavascript);
+    else if (pszJavascriptFile)
+        oWriter.WriteJavascriptFile(pszJavascriptFile);
+
+    oWriter.Close();
+
+    delete poSrcDS;
+
+    return OGRERR_NONE;
+}
diff --git a/frmts/pds/GNUmakefile b/frmts/pds/GNUmakefile
index 974d23c..a7e08b3 100644
--- a/frmts/pds/GNUmakefile
+++ b/frmts/pds/GNUmakefile
@@ -1,13 +1,13 @@
 
 include ../../GDALmake.opt
 
-OBJ	=	pdsdataset.o isis2dataset.o isis3dataset.o nasakeywordhandler.o
+OBJ	=	pdsdataset.o isis2dataset.o isis3dataset.o vicardataset.o nasakeywordhandler.o vicarkeywordhandler.o
 
-CPPFLAGS	:=	-I../raw $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../raw  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
-$(O_OBJ):       nasakeywordhandler.h ../raw/rawdataset.h
+$(O_OBJ):       nasakeywordhandler.h vicarkeywordhandler.h ../raw/rawdataset.h
 
 clean:
 	rm -f *.o $(O_OBJ)
diff --git a/frmts/pds/isis2dataset.cpp b/frmts/pds/isis2dataset.cpp
index 2133035..23fc03c 100644
--- a/frmts/pds/isis2dataset.cpp
+++ b/frmts/pds/isis2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: isis2dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: isis2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  ISIS Version 2 Driver
  * Purpose:  Implementation of ISIS2Dataset
@@ -50,7 +50,7 @@
 #include "cpl_string.h" 
 #include "nasakeywordhandler.h"
 
-CPL_CVSID("$Id: isis2dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: isis2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_ISIS2(void);
@@ -422,14 +422,14 @@ GDALDataset *ISIS2Dataset::Open( GDALOpenInfo * poOpenInfo )
     /***********   Grab Cellsize ************/
     value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_SCALE");
     if (strlen(value) > 0 ) {
-        dfXDim = (float) atof(value) * 1000.0; /* convert from km to m */
-        dfYDim = (float) atof(value) * 1000.0 * -1;
+        dfXDim = (float) CPLAtof(value) * 1000.0; /* convert from km to m */
+        dfYDim = (float) CPLAtof(value) * 1000.0 * -1;
     }
     
     /***********   Grab LINE_PROJECTION_OFFSET ************/
     value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
     if (strlen(value) > 0) {
-        yulcenter = (float) atof(value);
+        yulcenter = (float) CPLAtof(value);
         yulcenter = ((yulcenter) * dfYDim);
         dfULYMap = yulcenter - (dfYDim/2);
     }
@@ -437,7 +437,7 @@ GDALDataset *ISIS2Dataset::Open( GDALOpenInfo * poOpenInfo )
     /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
     value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
     if( strlen(value) > 0 ) {
-        xulcenter = (float) atof(value);
+        xulcenter = (float) CPLAtof(value);
         xulcenter = ((xulcenter) * dfXDim);
         dfULXMap = xulcenter - (dfXDim/2);
     }
@@ -453,27 +453,27 @@ GDALDataset *ISIS2Dataset::Open( GDALOpenInfo * poOpenInfo )
 
     /***********   Grab SEMI-MAJOR ************/
     semi_major = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
 
     /***********   Grab semi-minor ************/
     semi_minor = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;
 
     /***********   Grab CENTER_LAT ************/
     center_lat = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
 
     /***********   Grab CENTER_LON ************/
     center_lon = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
 
     /***********   Grab 1st std parallel ************/
     first_std_parallel = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
 
     /***********   Grab 2nd std parallel ************/
     second_std_parallel = 
-        atof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
+        CPLAtof(poDS->GetKeyword( "QUBE.IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
      
     /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
     // Need to further study how ocentric/ographic will effect the gdal library.
@@ -966,7 +966,8 @@ int ISIS2Dataset::WriteRaster(CPLString osFilename,
                               bool includeLabel,
                               GUIntBig iRecords,
                               GUIntBig iLabelRecords,
-                              CPL_UNUSED GDALDataType eType, CPL_UNUSED const char * pszInterleaving) {
+                              CPL_UNUSED GDALDataType eType,
+                              CPL_UNUSED const char * pszInterleaving) {
     GUIntBig nSize;
     GByte byZero(0);
     CPLString pszAccess("wb");
@@ -1093,11 +1094,11 @@ int ISIS2Dataset::WriteQUBE_Information(
 
 int ISIS2Dataset::WriteLabel(
     CPLString osFilename, CPLString osRasterFile, CPLString sObjectTag,
-    unsigned int nXSize, unsigned int nYSize, unsigned int nBands, 
+    unsigned int nXSize, unsigned int nYSize, unsigned int nBands,
     GDALDataType eType,
-    GUIntBig iRecords, const char * pszInterleaving, 
-    GUIntBig &iLabelRecords, CPL_UNUSED bool bRelaunch)
-
+    GUIntBig iRecords, const char * pszInterleaving,
+    GUIntBig &iLabelRecords,
+    CPL_UNUSED bool bRelaunch)
 {
     CPLDebug("ISIS2", "Write Label filename = %s, rasterfile = %s",osFilename.c_str(),osRasterFile.c_str());
     bool bAttachedLabel = EQUAL(osRasterFile, "");
@@ -1195,6 +1196,7 @@ int ISIS2Dataset::WriteLabel(
             poDriver = new GDALDriver();
         
             poDriver->SetDescription( "ISIS2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
             poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                        "USGS Astrogeology ISIS cube (Version 2)" );
             poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_isis2.html" );
diff --git a/frmts/pds/isis3dataset.cpp b/frmts/pds/isis3dataset.cpp
index 90d33a1..3fa0f6a 100644
--- a/frmts/pds/isis3dataset.cpp
+++ b/frmts/pds/isis3dataset.cpp
@@ -482,20 +482,20 @@ GDALDataset *ISIS3Dataset::Open( GDALOpenInfo * poOpenInfo )
     /***********   Grab Cellsize ************/
     value = poDS->GetKeyword("IsisCube.Mapping.PixelResolution");
     if (strlen(value) > 0 ) {
-        dfXDim = atof(value); /* values are in meters */
-        dfYDim = -atof(value);
+        dfXDim = CPLAtof(value); /* values are in meters */
+        dfYDim = -CPLAtof(value);
     }
     
     /***********   Grab UpperLeftCornerY ************/
     value = poDS->GetKeyword("IsisCube.Mapping.UpperLeftCornerY");
     if (strlen(value) > 0) {
-        dfULYMap = atof(value);
+        dfULYMap = CPLAtof(value);
     }
      
     /***********   Grab UpperLeftCornerX ************/
     value = poDS->GetKeyword("IsisCube.Mapping.UpperLeftCornerX");
     if( strlen(value) > 0 ) {
-        dfULXMap = atof(value);
+        dfULXMap = CPLAtof(value);
     }
      
     /***********  Grab TARGET_NAME  ************/
@@ -508,31 +508,31 @@ GDALDataset *ISIS3Dataset::Open( GDALOpenInfo * poOpenInfo )
 
     /***********   Grab SEMI-MAJOR ************/
     semi_major = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.EquatorialRadius"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.EquatorialRadius"));
 
     /***********   Grab semi-minor ************/
     semi_minor = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.PolarRadius"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.PolarRadius"));
 
     /***********   Grab CENTER_LAT ************/
     center_lat = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.CenterLatitude"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.CenterLatitude"));
 
     /***********   Grab CENTER_LON ************/
     center_lon = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.CenterLongitude"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.CenterLongitude"));
 
     /***********   Grab 1st std parallel ************/
     first_std_parallel = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.FirstStandardParallel"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.FirstStandardParallel"));
 
     /***********   Grab 2nd std parallel ************/
     second_std_parallel = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.SecondStandardParallel"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.SecondStandardParallel"));
      
     /***********   Grab scaleFactor ************/
     scaleFactor = 
-        atof(poDS->GetKeyword( "IsisCube.Mapping.scaleFactor", "1.0"));
+        CPLAtof(poDS->GetKeyword( "IsisCube.Mapping.scaleFactor", "1.0"));
      
     /*** grab      LatitudeType = Planetographic ****/
     // Need to further study how ocentric/ographic will effect the gdal library
@@ -911,6 +911,7 @@ void GDALRegister_ISIS3()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ISIS3" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "USGS Astrogeology ISIS cube (Version 3)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/pds/makefile.vc b/frmts/pds/makefile.vc
index 71a882d..0a34a1f 100644
--- a/frmts/pds/makefile.vc
+++ b/frmts/pds/makefile.vc
@@ -1,6 +1,6 @@
 
 OBJ	=	pdsdataset.obj isis2dataset.obj isis3dataset.obj \
-		nasakeywordhandler.obj
+		vicardataset.obj nasakeywordhandler.obj vicarkeywordhandler.obj
 
 GDAL_ROOT	=	..\..
 
diff --git a/frmts/pds/pdsdataset.cpp b/frmts/pds/pdsdataset.cpp
index 89a166a..6473a02 100644
--- a/frmts/pds/pdsdataset.cpp
+++ b/frmts/pds/pdsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pdsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pdsdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  PDS Driver; Planetary Data System Format
  * Purpose:  Implementation of PDSDataset
@@ -47,12 +47,19 @@
 #include "cpl_string.h" 
 #include "nasakeywordhandler.h"
 
-CPL_CVSID("$Id: pdsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pdsdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_PDS(void);
 CPL_C_END
 
+enum PDSLayout
+{
+    PDS_BSQ,
+    PDS_BIP,
+    PDS_BIL
+};
+
 /************************************************************************/
 /* ==================================================================== */
 /*			       PDSDataset	                        */
@@ -106,7 +113,10 @@ public:
     
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     static int          Identify( GDALOpenInfo * );
     static GDALDataset *Open( GDALOpenInfo * );
@@ -227,7 +237,9 @@ CPLErr PDSDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace)
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
 
 {
     if( poCompressedDS != NULL )
@@ -235,13 +247,14 @@ CPLErr PDSDataset::IRasterIO( GDALRWFlag eRWFlag,
                                          nXOff, nYOff, nXSize, nYSize, 
                                          pData, nBufXSize, nBufYSize, 
                                          eBufType, nBandCount, panBandMap,
-                                         nPixelSpace, nLineSpace, nBandSpace );
+                                         nPixelSpace, nLineSpace, nBandSpace,
+                                         psExtraArg);
     else
         return RawDataset::IRasterIO( eRWFlag, 
                                       nXOff, nYOff, nXSize, nYSize, 
                                       pData, nBufXSize, nBufYSize, 
                                       eBufType, nBandCount, panBandMap,
-                                      nPixelSpace, nLineSpace, nBandSpace );
+                                      nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -307,8 +320,8 @@ void PDSDataset::ParseSRS()
 
     value = GetKeyword(osPrefix + "IMAGE_MAP_PROJECTION.MAP_SCALE");
     if (strlen(value) > 0 ) {
-        dfXDim = atof(value);
-        dfYDim = atof(value) * -1;
+        dfXDim = CPLAtof(value);
+        dfYDim = CPLAtof(value) * -1;
 
         CPLString osKey(osPrefix + "IMAGE_MAP_PROJECTION.MAP_SCALE");
         CPLString unit = GetKeywordUnit(osKey,2); //KM
@@ -331,7 +344,7 @@ void PDSDataset::ParseSRS()
 /*      Calculate upper left corner of pixel in meters from the         */
 /*      upper  left center pixel sample/line offsets.  It doesn't       */
 /*      mean the defaults will work for every PDS image, as these       */
-/*      values are used inconsistantly.  Thus we have included          */
+/*      values are used inconsistently.  Thus we have included          */
 /*      conversion options to allow the user to override the            */
 /*      documented PDS3 default. Jan. 2011, for known mapping issues    */
 /*      see GDAL PDS page or mapping within ISIS3 source (USGS)         */
@@ -345,28 +358,28 @@ void PDSDataset::ParseSRS()
     double   dfLineOffset_Mult;
 
     dfSampleOffset_Shift = 
-        atof(CPLGetConfigOption( "PDS_SampleProjOffset_Shift", "-0.5" ));
+        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Shift", "-0.5" ));
     
     dfLineOffset_Shift = 
-        atof(CPLGetConfigOption( "PDS_LineProjOffset_Shift", "-0.5" ));
+        CPLAtof(CPLGetConfigOption( "PDS_LineProjOffset_Shift", "-0.5" ));
 
     dfSampleOffset_Mult =
-        atof(CPLGetConfigOption( "PDS_SampleProjOffset_Mult", "-1.0") );
+        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Mult", "-1.0") );
 
     dfLineOffset_Mult = 
-        atof( CPLGetConfigOption( "PDS_LineProjOffset_Mult", "1.0") );
+        CPLAtof( CPLGetConfigOption( "PDS_LineProjOffset_Mult", "1.0") );
 
     /***********   Grab LINE_PROJECTION_OFFSET ************/
     value = GetKeyword(osPrefix + "IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
     if (strlen(value) > 0) {
-        yulcenter = atof(value);
+        yulcenter = CPLAtof(value);
         dfULYMap = ((yulcenter + dfLineOffset_Shift) * -dfYDim * dfLineOffset_Mult);
         //notice dfYDim is negative here which is why it is again negated here
     }
     /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
     value = GetKeyword(osPrefix + "IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
     if( strlen(value) > 0 ) {
-        xulcenter = atof(value);
+        xulcenter = CPLAtof(value);
         dfULXMap = ((xulcenter + dfSampleOffset_Shift) * dfXDim * dfSampleOffset_Mult);
     }
 
@@ -395,27 +408,27 @@ void PDSDataset::ParseSRS()
      
     /******  Grab semi_major & convert to KM ******/
     semi_major = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) * 1000.0;
     
     /******  Grab semi-minor & convert to KM ******/
     semi_minor = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) * 1000.0;
 
     /***********   Grab CENTER_LAT ************/
     center_lat = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
 
     /***********   Grab CENTER_LON ************/
     center_lon = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
 
     /**********   Grab 1st std parallel *******/
     first_std_parallel = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
 
     /**********   Grab 2nd std parallel *******/
     second_std_parallel = 
-        atof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
+        CPLAtof(GetKeyword( osPrefix + "IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
      
     /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
     // Need to further study how ocentric/ographic will effect the gdal library.
@@ -672,13 +685,13 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
     // ^IMAGE             = 10851 <BYTES>
     // ^SPECTRAL_QUBE = 5  for multi-band images
 
-    CPLString osImageKeyword = osPrefix + "^IMAGE";
-    CPLString osQube = GetKeyword( osImageKeyword, "" );
+    CPLString osImageKeyword = "IMAGE";
+    CPLString osQube = GetKeyword( osPrefix + "^" + osImageKeyword, "" );
     CPLString osTargetFile = GetDescription();
 
     if (EQUAL(osQube,"")) {
-        osImageKeyword = "^SPECTRAL_QUBE";
-        osQube = GetKeyword( osImageKeyword );
+        osImageKeyword = "SPECTRAL_QUBE";
+        osQube = GetKeyword( osPrefix + "^" + osImageKeyword );
     }
 
     int nQube = atoi(osQube);
@@ -688,13 +701,13 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
     if( osQube.size() && osQube[0] == '(' )
     {
         osQube = "\"";
-        osQube += GetKeywordSub( osImageKeyword, 1 );
+        osQube += GetKeywordSub( osPrefix + "^" + osImageKeyword, 1 );
         osQube +=  "\"";
-        nDetachedOffset = atoi(GetKeywordSub( osImageKeyword, 2, "1")) - 1;
+        nDetachedOffset = atoi(GetKeywordSub( osPrefix + "^" + osImageKeyword, 2, "1")) - 1;
 
         // If this is not explicitly in bytes, then it is assumed to be in
         // records, and we need to translate to bytes.
-        if (strstr(GetKeywordSub(osImageKeyword,2),"<BYTES>") != NULL)
+        if (strstr(GetKeywordSub(osPrefix + "^" + osImageKeyword, 2),"<BYTES>") != NULL)
             bDetachedOffsetInBytes = TRUE;
     }
 
@@ -723,15 +736,18 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
     int nSkipBytes = 0;
     int itype;
     int record_bytes;
+    int nSuffixItems = 0, nSuffixLines = 0;
+    int nSuffixBytes = 4; // Default as per PDS specification 
     char chByteOrder = 'M';  //default to MSB
-    double dfNoData = 0.0;
+    double dfNoData = 0.0, dfScale = 1.0, dfOffset = 0.0;
+    const char *pszUnit = NULL, *pszDesc = NULL;
  
     /* -------------------------------------------------------------------- */
     /*      Checks to see if this is raw PDS image not compressed image     */
     /*      so ENCODING_TYPE either does not exist or it equals "N/A".      */
     /*      Compressed types will not be supported in this routine          */
     /* -------------------------------------------------------------------- */
-    const char *value;
+    CPLString value;
 
     CPLString osEncodingType = GetKeyword(osPrefix+"IMAGE.ENCODING_TYPE","N/A");
     CleanString(osEncodingType);
@@ -753,35 +769,35 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
     /** are there own keywords  "LINES" and "LINE_SAMPLES"    **/
     /** if not NULL then CORE_ITEMS keyword i.e. (234,322,2)  **/
     /***********************************************************/
-    char szLayout[10] = "BSQ"; //default to band seq.
-    value = GetKeyword( osPrefix+"IMAGE.AXIS_NAME", "" );
+    int eLayout = PDS_BSQ; //default to band seq.
+    value = GetKeyword( osPrefix+osImageKeyword+".AXIS_NAME", "" );
     if (EQUAL(value,"(SAMPLE,LINE,BAND)") ) {
-        strcpy(szLayout,"BSQ");
-        nCols = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",1));
-        nRows = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",2));
-        nBands = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",3));
+        eLayout = PDS_BSQ;
+        nCols = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",1));
+        nRows = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",2));
+        nBands = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",3));
     }
     else if (EQUAL(value,"(BAND,LINE,SAMPLE)") ) {
-        strcpy(szLayout,"BIP");
-        nBands = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",1));
-        nRows = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",2));
-        nCols = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",3));
+        eLayout = PDS_BIP;
+        nBands = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",1));
+        nRows = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",2));
+        nCols = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",3));
     }
     else if (EQUAL(value,"(SAMPLE,BAND,LINE)") ) {
-        strcpy(szLayout,"BIL");
-        nCols = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",1));
-        nBands = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",2));
-        nRows = atoi(GetKeywordSub(osPrefix+"IMAGE.CORE_ITEMS",3));
+        eLayout = PDS_BIL;
+        nCols = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",1));
+        nBands = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",2));
+        nRows = atoi(GetKeywordSub(osPrefix+osImageKeyword+".CORE_ITEMS",3));
     }
     else if ( EQUAL(value,"") ) {
-        strcpy(szLayout,"BSQ");
-        nCols = atoi(GetKeyword(osPrefix+"IMAGE.LINE_SAMPLES",""));
-        nRows = atoi(GetKeyword(osPrefix+"IMAGE.LINES",""));
-        nBands = atoi(GetKeyword(osPrefix+"IMAGE.BANDS","1"));
+        eLayout = PDS_BSQ;
+        nCols = atoi(GetKeyword(osPrefix+osImageKeyword+".LINE_SAMPLES",""));
+        nRows = atoi(GetKeyword(osPrefix+osImageKeyword+".LINES",""));
+        nBands = atoi(GetKeyword(osPrefix+osImageKeyword+".BANDS","1"));
     }
     else {
         CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "%s layout not supported. Abort\n\n", value);
+                  "%s layout not supported. Abort\n\n", value.c_str() );
         return FALSE;
     }
     
@@ -830,32 +846,88 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
 
     /**** Grab format type - pds supports 1,2,4,8,16,32,64 (in theory) **/
     /**** I have only seen 8, 16, 32 (float) in released datasets      **/
-    itype = atoi(GetKeyword(osPrefix+"IMAGE.SAMPLE_BITS",""));
-    switch(itype) {
-      case 8 :
-        eDataType = GDT_Byte;
-        dfNoData = NULL1;
-        break;
-      case 16 :
-        if( strstr(osST,"UNSIGNED") != NULL )
-            eDataType = GDT_UInt16;
-        else
-            eDataType = GDT_Int16;
-        dfNoData = NULL2;
-        break;
-      case 32 :
-        eDataType = GDT_Float32;
-        dfNoData = NULL3;
-        break;
-      case 64 :
-        eDataType = GDT_Float64;
-        dfNoData = NULL3;
-        break;
-      default :
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Sample_bits of %d is not supported in this gdal PDS reader.",
-                  itype); 
-        return FALSE;
+    CPLString osSB = GetKeyword(osPrefix+"IMAGE.SAMPLE_BITS","");
+    if ( osSB.size() > 0 )
+    {
+        itype = atoi(osSB);
+        switch(itype) {
+          case 8 :
+            eDataType = GDT_Byte;
+            dfNoData = NULL1;
+            break;
+          case 16 :
+            if( strstr(osST,"UNSIGNED") != NULL )
+                eDataType = GDT_UInt16;
+            else
+                eDataType = GDT_Int16;
+            dfNoData = NULL2;
+            break;
+          case 32 :
+            eDataType = GDT_Float32;
+            dfNoData = NULL3;
+            break;
+          case 64 :
+            eDataType = GDT_Float64;
+            dfNoData = NULL3;
+            break;
+          default :
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Sample_bits of %d is not supported in this gdal PDS reader.",
+                      itype); 
+            return FALSE;
+        }
+
+        dfOffset = CPLAtofM(GetKeyword(osPrefix+"IMAGE.OFFSET","0.0"));
+        dfScale = CPLAtofM(GetKeyword(osPrefix+"IMAGE.SCALING_FACTOR","1.0"));
+    }
+    else /* No IMAGE object, search for the QUBE. */
+    {
+        osSB = GetKeyword(osPrefix+"SPECTRAL_QUBE.CORE_ITEM_BYTES","");
+        itype = atoi(osSB);
+        switch(itype) {
+          case 1 :
+            eDataType = GDT_Byte;
+            break;
+          case 2 :
+            if( strstr(osST,"UNSIGNED") != NULL )
+                eDataType = GDT_UInt16;
+            else
+                eDataType = GDT_Int16;
+            break;
+          case 4 :
+            eDataType = GDT_Float32;
+            break;
+          default :
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "CORE_ITEM_BYTES of %d is not supported in this gdal PDS reader.",
+                      itype); 
+            return FALSE;
+        }
+
+        /* Parse suffix dimensions if defined. */
+        value = GetKeyword( osPrefix + "SPECTRAL_QUBE.SUFFIX_ITEMS", "" );
+        if ( value.size() > 0 )
+        {
+            value = GetKeyword(osPrefix + "SPECTRAL_QUBE.SUFFIX_BYTES", "");
+            if ( value.size() > 0 )
+                nSuffixBytes = atoi( value );
+
+            nSuffixItems = atoi(
+                GetKeywordSub(osPrefix+"SPECTRAL_QUBE.SUFFIX_ITEMS",1));
+            nSuffixLines = atoi(
+                GetKeywordSub(osPrefix+"SPECTRAL_QUBE.SUFFIX_ITEMS",2));
+        }
+
+        value = GetKeyword( osPrefix + "SPECTRAL_QUBE.CORE_NULL", "" );
+        if ( value.size() > 0 )
+            dfNoData = CPLAtofM( value );
+
+        dfOffset = CPLAtofM(
+            GetKeyword(osPrefix + "SPECTRAL_QUBE.CORE_BASE", "0.0") );
+        dfScale = CPLAtofM(
+            GetKeyword(osPrefix + "SPECTRAL_QUBE.CORE_MULTIPLIER", "1.0") );
+        pszUnit = GetKeyword(osPrefix + "SPECTRAL_QUBE.CORE_UNIT", NULL);
+        pszDesc = GetKeyword(osPrefix + "SPECTRAL_QUBE.CORE_NAME", NULL);
     }
 
 /* -------------------------------------------------------------------- */
@@ -940,19 +1012,20 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
     int     nLineOffset = record_bytes;
     int	    nPixelOffset, nBandOffset;
 
-    if( EQUAL(szLayout,"BIP") )
+    if( eLayout == PDS_BIP )
     {
         nPixelOffset = nItemSize * nBands;
         nBandOffset = nItemSize;
         nLineOffset = ((nPixelOffset * nCols + record_bytes - 1)/record_bytes)
             * record_bytes;
     }
-    else if( EQUAL(szLayout,"BSQ") )
+    else if( eLayout == PDS_BSQ )
     {
         nPixelOffset = nItemSize;
         nLineOffset = ((nPixelOffset * nCols + record_bytes - 1)/record_bytes)
             * record_bytes;
-        nBandOffset = nLineOffset * nRows;
+        nBandOffset = nLineOffset * nRows
+            + nSuffixLines * (nCols + nSuffixItems) * nSuffixBytes;
     }
     else /* assume BIL */
     {
@@ -997,16 +1070,18 @@ int PDSDataset::ParseImage( CPLString osPrefix, CPLString osFilenamePrefix )
                                        CPLAtofM(pszStdDev));
             }
         }
-        
+
         poBand->SetNoDataValue( dfNoData );
 
         SetBand( i+1, poBand );
 
         // Set offset/scale values at the PAM level.
-        poBand->SetOffset( 
-            CPLAtofM(GetKeyword(osPrefix+"IMAGE.OFFSET","0.0")));
-        poBand->SetScale( 
-            CPLAtofM(GetKeyword(osPrefix+"IMAGE.SCALING_FACTOR","1.0")));
+        poBand->SetOffset( dfOffset );
+        poBand->SetScale( dfScale );
+        if ( pszUnit )
+            poBand->SetUnitType( pszUnit );
+        if ( pszDesc )
+            poBand->SetDescription( pszDesc );
     }
 
     return TRUE;
@@ -1335,6 +1410,7 @@ void GDALRegister_PDS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "PDS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NASA Planetary Data System" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/pds/vicardataset.cpp b/frmts/pds/vicardataset.cpp
new file mode 100644
index 0000000..e110612
--- /dev/null
+++ b/frmts/pds/vicardataset.cpp
@@ -0,0 +1,835 @@
+/******************************************************************************
+ * 
+ * Project:  VICAR Driver; JPL/MIPL VICAR Format
+ * Purpose:  Implementation of VICARDataset
+ * Author:   Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+ *
+ * NOTE: This driver code is loosely based on the ISIS and PDS drivers.
+ * It is not intended to diminish the contribution of the original authors 
+ ******************************************************************************
+ * Copyright (c) 2014, Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+ * 
+ * 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.
+ ****************************************************************************/
+
+#define NULL1 0
+#define NULL2 -32768
+#define NULL3 -32768.
+
+#ifndef PI
+#  define PI 3.1415926535897932384626433832795
+#endif
+
+#include "rawdataset.h"
+#include "ogr_spatialref.h"
+#include "cpl_string.h" 
+#include "vicarkeywordhandler.h"
+
+#include <string>
+
+CPL_CVSID("$Id: vicardataset.cpp 28786 2015-03-26 21:13:18Z rouault $");
+
+CPL_C_START
+void GDALRegister_VICAR(void);
+CPL_C_END
+
+/************************************************************************/
+/* ==================================================================== */
+/*			       VICARDataset		                */
+/* ==================================================================== */
+/************************************************************************/
+
+class VICARDataset : public RawDataset
+{
+    VSILFILE	*fpImage;
+
+    GByte	abyHeader[10000];
+    CPLString   osExternalCube;
+    
+    VICARKeywordHandler  oKeywords;
+  
+    int         bGotTransform;
+    double      adfGeoTransform[6];
+  
+    CPLString   osProjection;
+
+    const char *GetKeyword( const char *pszPath, 
+                            const char *pszDefault = "");
+    
+public:
+    VICARDataset();
+    ~VICARDataset();
+  
+    virtual CPLErr GetGeoTransform( double * padfTransform );
+    virtual const char *GetProjectionRef(void);
+  
+    virtual char **GetFileList();
+
+    static int          Identify( GDALOpenInfo * );
+    static GDALDataset *Open( GDALOpenInfo * );
+    static GDALDataset *Create( const char * pszFilename,
+                                int nXSize, int nYSize, int nBands,
+                                GDALDataType eType, char ** papszParmList );
+
+};
+
+
+
+/************************************************************************/
+/*                            VICARDataset()                            */
+/************************************************************************/
+
+VICARDataset::VICARDataset()
+{
+    fpImage = NULL;
+    bGotTransform = FALSE;
+    adfGeoTransform[0] = 0.0;
+    adfGeoTransform[1] = 1.0;
+    adfGeoTransform[2] = 0.0;
+    adfGeoTransform[3] = 0.0;
+    adfGeoTransform[4] = 0.0;
+    adfGeoTransform[5] = 1.0;
+}
+
+/************************************************************************/
+/*                            ~VICARDataset()                            */
+/************************************************************************/
+
+VICARDataset::~VICARDataset()
+
+{
+    FlushCache();
+    if( fpImage != NULL )
+        VSIFCloseL( fpImage );
+}
+
+/************************************************************************/
+/*                            GetFileList()                             */
+/************************************************************************/
+
+char **VICARDataset::GetFileList()
+
+{
+    char **papszFileList = NULL;
+
+    papszFileList = GDALPamDataset::GetFileList();
+
+    if( strlen(osExternalCube) > 0 )
+        papszFileList = CSLAddString( papszFileList, osExternalCube );
+
+    return papszFileList;
+}
+
+/************************************************************************/
+/*                          GetProjectionRef()                          */
+/************************************************************************/
+
+const char *VICARDataset::GetProjectionRef()
+
+{
+    if( strlen(osProjection) > 0 )
+        return osProjection;
+    else
+        return GDALPamDataset::GetProjectionRef();
+}
+
+/************************************************************************/
+/*                          GetGeoTransform()                           */
+/************************************************************************/
+
+CPLErr VICARDataset::GetGeoTransform( double * padfTransform )
+
+{
+    if( bGotTransform )
+    {
+        memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
+        return CE_None;
+    }
+    else
+    {
+        return GDALPamDataset::GetGeoTransform( padfTransform );
+    }
+}
+
+/************************************************************************/
+/*                              Identify()                              */
+/************************************************************************/
+
+int VICARDataset::Identify( GDALOpenInfo * poOpenInfo )
+
+{
+    if( poOpenInfo->pabyHeader == NULL )
+        return FALSE;
+
+    return strstr((char*)poOpenInfo->pabyHeader,"LBLSIZE") != NULL &&
+           strstr((char*)poOpenInfo->pabyHeader,"FORMAT") != NULL &&
+           strstr((char*)poOpenInfo->pabyHeader,"NL") != NULL &&
+           strstr((char*)poOpenInfo->pabyHeader,"NS") != NULL &&
+           strstr((char*)poOpenInfo->pabyHeader,"NB") != NULL;
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset *VICARDataset::Open( GDALOpenInfo * poOpenInfo )
+{
+/* -------------------------------------------------------------------- */
+/*      Does this look like a VICAR dataset?                             */
+/* -------------------------------------------------------------------- */
+    if( !Identify( poOpenInfo ) )
+        return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Open the file using the large file API.                         */
+/* -------------------------------------------------------------------- */
+    VSILFILE *fpQube = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
+
+    if( fpQube == NULL )
+        return NULL;
+
+    VICARDataset 	*poDS;
+
+    poDS = new VICARDataset();
+    if( ! poDS->oKeywords.Ingest( fpQube, poOpenInfo->pabyHeader ) ) {
+        VSIFCloseL( fpQube );
+        delete poDS;
+        return NULL;
+    }
+    
+    VSIFCloseL( fpQube );
+
+    CPLString osQubeFile;
+    osQubeFile = poOpenInfo->pszFilename;
+    GDALDataType eDataType = GDT_Byte;
+
+    int	nRows = -1;
+    int nCols = -1;
+    int nBands = 1;
+    int nSkipBytes = 0;
+    int bIsDTM = FALSE;
+    char chByteOrder = 'M';
+    double dfNoData = 0.0;
+    const char *value;
+    
+    /***** CHECK ENDIANNESS **************/
+    
+    value = poDS->GetKeyword( "INTFMT" );
+    if (!EQUAL(value,"LOW") ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "%s layout not supported. Abort\n\n", value);
+        return FALSE;
+    }
+    value = poDS->GetKeyword( "REALFMT" );
+    if (!EQUAL(value,"RIEEE") ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "%s layout not supported. Abort\n\n", value);
+        return FALSE;
+    }
+    value = poDS->GetKeyword( "BREALFMT" );
+    if (EQUAL(value,"VAX") ) {
+        chByteOrder = 'I';
+    }
+    
+    /************ CHECK INSTRUMENT *****************/
+    /************ ONLY HRSC TESTED *****************/
+    
+    value = poDS->GetKeyword( "DTM.DTM_OFFSET" );
+    if (!EQUAL(value,"") ) {
+        bIsDTM = TRUE;
+    }
+    
+    
+    value = poDS->GetKeyword( "BLTYPE" );
+    if (!EQUAL(value,"M94_HRSC") && bIsDTM==FALSE ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "%s instrument not tested. Continue with caution!\n\n", value);
+    }
+    
+    /***********   Grab layout type (BSQ, BIP, BIL) ************/
+    
+    char szLayout[10] = "BSQ"; //default to band seq.
+    value = poDS->GetKeyword( "ORG" );
+    if (EQUAL(value,"BSQ") ) {
+        strcpy(szLayout,"BSQ");
+        nCols = atoi(poDS->GetKeyword("NS"));
+        nRows = atoi(poDS->GetKeyword("NL"));
+        nBands = atoi(poDS->GetKeyword("NB"));
+    }
+    else {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "%s layout not supported. Abort\n\n", value);
+        return FALSE;
+    }
+    
+    /***********   Grab record bytes  **********/
+    nSkipBytes = atoi(poDS->GetKeyword("NBB"));
+    
+    if (EQUAL( poDS->GetKeyword( "FORMAT" ), "BYTE" )) {
+        eDataType = GDT_Byte;
+        dfNoData = NULL1;
+    }
+    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "HALF" )) {
+        eDataType = GDT_Int16;
+        dfNoData = NULL2;
+        chByteOrder = 'I';
+    }
+    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "FULL" )) {
+        eDataType = GDT_UInt32;
+        dfNoData = 0;
+    } 
+    else if (EQUAL( poDS->GetKeyword( "FORMAT" ), "REAL" )) {
+        eDataType = GDT_Float32;
+        dfNoData = NULL3;
+        chByteOrder = 'I';
+    }
+    else {
+	    printf("Could not find known VICAR label entries!\n");
+        delete poDS;
+        return NULL;
+    }
+
+    if( nRows < 1 || nCols < 1 || nBands < 1 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "File %s appears to be a VICAR file, but failed to find some required keywords.", 
+                  poDS->GetDescription() );
+        return FALSE;
+    }
+/* -------------------------------------------------------------------- */
+/*      Capture some information from the file that is of interest.     */
+/* -------------------------------------------------------------------- */
+    poDS->nRasterXSize = nCols;
+    poDS->nRasterYSize = nRows;
+
+    double dfULXMap=0.5;
+    double dfULYMap = 0.5;
+    double dfXDim = 1.0;
+    double dfYDim = 1.0;
+    double xulcenter = 0.0;
+    double yulcenter = 0.0;
+
+    value = poDS->GetKeyword("MAP.MAP_SCALE");
+    if (strlen(value) > 0 ) {
+        dfXDim = CPLAtof(value);
+        dfYDim = CPLAtof(value) * -1;
+        dfXDim = dfXDim * 1000.0;
+        dfYDim = dfYDim * 1000.0;
+    }
+
+    double   dfSampleOffset_Shift;
+    double   dfLineOffset_Shift;
+    double   dfSampleOffset_Mult;
+    double   dfLineOffset_Mult;
+    
+    dfSampleOffset_Shift = 
+        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Shift", "-0.5" ));
+    
+    dfLineOffset_Shift = 
+        CPLAtof(CPLGetConfigOption( "PDS_LineProjOffset_Shift", "-0.5" ));
+
+    dfSampleOffset_Mult =
+        CPLAtof(CPLGetConfigOption( "PDS_SampleProjOffset_Mult", "-1.0") );
+
+    dfLineOffset_Mult = 
+        CPLAtof( CPLGetConfigOption( "PDS_LineProjOffset_Mult", "1.0") );
+
+    /***********   Grab LINE_PROJECTION_OFFSET ************/
+    value = poDS->GetKeyword("MAP.LINE_PROJECTION_OFFSET");
+    if (strlen(value) > 0) {
+        yulcenter = CPLAtof(value);
+        dfULYMap = ((yulcenter + dfLineOffset_Shift) * -dfYDim * dfLineOffset_Mult);
+    }
+    /***********   Grab SAMPLE_PROJECTION_OFFSET ************/
+    value = poDS->GetKeyword("MAP.SAMPLE_PROJECTION_OFFSET");
+    if( strlen(value) > 0 ) {
+        xulcenter = CPLAtof(value);
+        dfULXMap = ((xulcenter + dfSampleOffset_Shift) * dfXDim * dfSampleOffset_Mult);
+    }
+    
+/* ==================================================================== */
+/*      Get the coordinate system.                                      */
+/* ==================================================================== */
+    int	bProjectionSet = TRUE;
+    double semi_major = 0.0;
+    double semi_minor = 0.0;
+    double iflattening = 0.0;
+    double center_lat = 0.0;
+    double center_lon = 0.0;
+    double first_std_parallel = 0.0;
+    double second_std_parallel = 0.0;    
+    OGRSpatialReference oSRS;
+    
+    /***********  Grab TARGET_NAME  ************/
+    /**** This is the planets name i.e. MARS ***/
+    CPLString target_name = poDS->GetKeyword("MAP.TARGET_NAME");
+     
+    /**********   Grab MAP_PROJECTION_TYPE *****/
+    CPLString map_proj_name = 
+        poDS->GetKeyword( "MAP.MAP_PROJECTION_TYPE");
+     
+    /******  Grab semi_major & convert to KM ******/
+    semi_major = 
+        CPLAtof(poDS->GetKeyword( "MAP.A_AXIS_RADIUS")) * 1000.0;
+    
+    /******  Grab semi-minor & convert to KM ******/
+    semi_minor = 
+        CPLAtof(poDS->GetKeyword( "MAP.C_AXIS_RADIUS")) * 1000.0;
+
+    /***********   Grab CENTER_LAT ************/
+    center_lat = 
+        CPLAtof(poDS->GetKeyword( "MAP.CENTER_LATITUDE"));
+
+    /***********   Grab CENTER_LON ************/
+    center_lon = 
+        CPLAtof(poDS->GetKeyword( "MAP.CENTER_LONGITUDE"));
+
+    /**********   Grab 1st std parallel *******/
+    first_std_parallel = 
+        CPLAtof(poDS->GetKeyword( "MAP.FIRST_STANDARD_PARALLEL"));
+
+    /**********   Grab 2nd std parallel *******/
+    second_std_parallel = 
+        CPLAtof(poDS->GetKeyword( "MAP.SECOND_STANDARD_PARALLEL"));
+     
+    /*** grab  PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
+    // Need to further study how ocentric/ographic will effect the gdal library.
+    // So far we will use this fact to define a sphere or ellipse for some projections
+    // Frank - may need to talk this over
+    char bIsGeographic = TRUE;
+    value = poDS->GetKeyword("MAP.COORDINATE_SYSTEM_NAME");
+    if (EQUAL( value, "PLANETOCENTRIC" ))
+        bIsGeographic = FALSE; 
+
+/**   Set oSRS projection and parameters --- all PDS supported types added if apparently supported in oSRS
+      "AITOFF",  ** Not supported in GDAL??
+      "ALBERS", 
+      "BONNE",
+      "BRIESEMEISTER",   ** Not supported in GDAL??
+      "CYLINDRICAL EQUAL AREA",
+      "EQUIDISTANT",
+      "EQUIRECTANGULAR",
+      "GNOMONIC",
+      "HAMMER",    ** Not supported in GDAL??
+      "HENDU",     ** Not supported in GDAL??
+      "LAMBERT AZIMUTHAL EQUAL AREA",
+      "LAMBERT CONFORMAL",
+      "MERCATOR",
+      "MOLLWEIDE",
+      "OBLIQUE CYLINDRICAL",
+      "ORTHOGRAPHIC",
+      "SIMPLE CYLINDRICAL",
+      "SINUSOIDAL",
+      "STEREOGRAPHIC",
+      "TRANSVERSE MERCATOR",
+      "VAN DER GRINTEN",     ** Not supported in GDAL??
+      "WERNER"     ** Not supported in GDAL?? 
+**/ 
+    CPLDebug( "PDS","using projection %s\n\n", map_proj_name.c_str());
+
+    if ((EQUAL( map_proj_name, "EQUIRECTANGULAR" )) ||
+        (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) ||
+        (EQUAL( map_proj_name, "EQUIDISTANT" )) )  {
+        oSRS.SetEquirectangular2 ( 0.0, center_lon, center_lat, 0, 0 );
+    } else if (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) {
+        oSRS.SetOrthographic ( center_lat, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "SINUSOIDAL" )) {
+        oSRS.SetSinusoidal ( center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "MERCATOR" )) {
+        oSRS.SetMercator ( center_lat, center_lon, 1, 0, 0 );
+    } else if (EQUAL( map_proj_name, "STEREOGRAPHIC" )) {
+        oSRS.SetStereographic ( center_lat, center_lon, 1, 0, 0 );
+    } else if (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC")) {
+        oSRS.SetPS ( center_lat, center_lon, 1, 0, 0 );
+    } else if (EQUAL( map_proj_name, "TRANSVERSE_MERCATOR" )) {
+        oSRS.SetTM ( center_lat, center_lon, 1, 0, 0 );
+    } else if (EQUAL( map_proj_name, "LAMBERT_CONFORMAL_CONIC" )) {
+        oSRS.SetLCC ( first_std_parallel, second_std_parallel, 
+                      center_lat, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "LAMBERT_AZIMUTHAL_EQUAL_AREA" )) {
+        oSRS.SetLAEA( center_lat, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "CYLINDRICAL_EQUAL_AREA" )) {
+        oSRS.SetCEA  ( first_std_parallel, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "MOLLWEIDE" )) {
+        oSRS.SetMollweide ( center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "ALBERS" )) {
+        oSRS.SetACEA ( first_std_parallel, second_std_parallel, 
+                       center_lat, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "BONNE" )) {
+        oSRS.SetBonne ( first_std_parallel, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "GNOMONIC" )) {
+        oSRS.SetGnomonic ( center_lat, center_lon, 0, 0 );
+    } else if (EQUAL( map_proj_name, "OBLIQUE_CYLINDRICAL" )) { 
+        // hope Swiss Oblique Cylindrical is the same
+        oSRS.SetSOC ( center_lat, center_lon, 0, 0 );
+    } else {
+        CPLDebug( "VICAR",
+                  "Dataset projection %s is not supported. Continuing...",
+                  map_proj_name.c_str() );
+        bProjectionSet = FALSE;
+    }
+
+    if (bProjectionSet) {
+        //Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
+        CPLString proj_target_name = map_proj_name + " " + target_name;
+        oSRS.SetProjCS(proj_target_name); //set ProjCS keyword
+     
+        //The geographic/geocentric name will be the same basic name as the body name
+        //'GCS' = Geographic/Geocentric Coordinate System
+        CPLString geog_name = "GCS_" + target_name;
+        
+        //The datum and sphere names will be the same basic name aas the planet
+        CPLString datum_name = "D_" + target_name;
+        CPLString sphere_name = target_name; // + "_IAU_IAG");  //Might not be IAU defined so don't add
+          
+        //calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
+        if ((semi_major - semi_minor) < 0.0000001) 
+            iflattening = 0;
+        else
+            iflattening = semi_major / (semi_major - semi_minor);
+     
+        //Set the body size but take into consideration which proj is being used to help w/ compatibility
+        //Notice that most PDS projections are spherical based on the fact that ISIS/PICS are spherical 
+        //Set the body size but take into consideration which proj is being used to help w/ proj4 compatibility
+        //The use of a Sphere, polar radius or ellipse here is based on how ISIS does it internally
+        if ( ( (EQUAL( map_proj_name, "STEREOGRAPHIC" ) && (fabs(center_lat) == 90)) ) || 
+             (EQUAL( map_proj_name, "POLAR_STEREOGRAPHIC" )))  
+        {
+            if (bIsGeographic) { 
+                //Geograpraphic, so set an ellipse
+                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                                semi_major, iflattening, 
+                                "Reference_Meridian", 0.0 );
+            } else {
+                //Geocentric, so force a sphere using the semi-minor axis. I hope... 
+                sphere_name += "_polarRadius";
+                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                                semi_minor, 0.0, 
+                                "Reference_Meridian", 0.0 );
+            }
+        }
+        else if ( (EQUAL( map_proj_name, "SIMPLE_CYLINDRICAL" )) || 
+                  (EQUAL( map_proj_name, "EQUIDISTANT" )) || 
+                  (EQUAL( map_proj_name, "ORTHOGRAPHIC" )) || 
+                  (EQUAL( map_proj_name, "STEREOGRAPHIC" )) || 
+                  (EQUAL( map_proj_name, "SINUSOIDAL" )) ) {
+            //isis uses the spherical equation for these projections so force a sphere
+            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                            semi_major, 0.0, 
+                            "Reference_Meridian", 0.0 );
+        } 
+        else if (EQUAL( map_proj_name, "EQUIRECTANGULAR" )) { 
+            //isis uses local radius as a sphere, which is pre-calculated in the PDS label as the semi-major
+            sphere_name += "_localRadius";
+            oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                            semi_major, 0.0, 
+                            "Reference_Meridian", 0.0 );
+        } 
+        else { 
+            //All other projections: Mercator, Transverse Mercator, Lambert Conformal, etc.
+            //Geographic, so set an ellipse
+            if (bIsGeographic) {
+                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                                semi_major, iflattening, 
+                                "Reference_Meridian", 0.0 );
+            } else { 
+                //Geocentric, so force a sphere. I hope... 
+                oSRS.SetGeogCS( geog_name, datum_name, sphere_name,
+                                semi_major, 0.0, 
+                                "Reference_Meridian", 0.0 );
+            }
+        }
+
+        // translate back into a projection string.
+        char *pszResult = NULL;
+        oSRS.exportToWkt( &pszResult );
+        poDS->osProjection = pszResult;
+        CPLFree( pszResult );
+    }
+    {
+        poDS->bGotTransform = TRUE;
+        poDS->adfGeoTransform[0] = dfULXMap;
+        poDS->adfGeoTransform[1] = dfXDim;
+        poDS->adfGeoTransform[2] = 0.0;
+        poDS->adfGeoTransform[3] = dfULYMap;
+        poDS->adfGeoTransform[4] = 0.0;
+        poDS->adfGeoTransform[5] = dfYDim;
+    }
+    
+    if( !poDS->bGotTransform )
+        poDS->bGotTransform = 
+            GDALReadWorldFile( osQubeFile, "psw", 
+                               poDS->adfGeoTransform );
+
+    if( !poDS->bGotTransform )
+        poDS->bGotTransform = 
+            GDALReadWorldFile( osQubeFile, "wld", 
+                               poDS->adfGeoTransform );
+
+
+/* -------------------------------------------------------------------- */
+/*      Open target binary file.                                        */
+/* -------------------------------------------------------------------- */
+    if( poOpenInfo->eAccess == GA_ReadOnly )
+        poDS->fpImage = VSIFOpenL( osQubeFile, "r" );
+    else
+        poDS->fpImage = VSIFOpenL( osQubeFile, "r+" );
+
+    if( poDS->fpImage == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "Failed to open %s with write permission.\n%s", 
+                  osQubeFile.c_str(),
+                  VSIStrerror( errno ) );
+        delete poDS;
+        return NULL;
+    }
+
+    poDS->eAccess = poOpenInfo->eAccess;
+
+/* -------------------------------------------------------------------- */
+/*      Compute the line offsets.                                        */
+/* -------------------------------------------------------------------- */
+
+    long int        nItemSize = GDALGetDataTypeSize(eDataType)/8;
+    long int	    nLineOffset=0, nPixelOffset=0, nBandOffset=0;
+    nPixelOffset = nItemSize;
+    nLineOffset = nPixelOffset * nCols + atoi(poDS->GetKeyword("NBB")) ;
+    nBandOffset = nLineOffset * nRows;
+
+    nSkipBytes = atoi(poDS->GetKeyword("LBLSIZE"));
+
+/* -------------------------------------------------------------------- */
+/*      Create band information objects.                                */
+/* -------------------------------------------------------------------- */
+    int i;
+
+    for( i = 0; i < nBands; i++ )
+    {
+        GDALRasterBand	*poBand;
+
+        poBand = new RawRasterBand( poDS, i+1, poDS->fpImage, nSkipBytes + nBandOffset * i, 
+                                   nPixelOffset, nLineOffset, eDataType,
+#ifdef CPL_LSB                               
+                                   chByteOrder == 'I' || chByteOrder == 'L',
+#else
+                                   chByteOrder == 'M',
+#endif
+                                   TRUE );
+
+        poDS->SetBand( i+1, poBand );
+        poBand->SetNoDataValue( dfNoData );
+        if (bIsDTM==TRUE) {
+            poBand->SetScale( (double) CPLAtof(poDS->GetKeyword( "DTM.DTM_SCALING_FACTOR") ) );
+            poBand->SetOffset( (double) CPLAtof(poDS->GetKeyword( "DTM.DTM_OFFSET") ) );
+            const char* pszMin = poDS->GetKeyword( "DTM.DTM_MINIMUM_DN", NULL );
+            const char* pszMax = poDS->GetKeyword( "DTM.DTM_MAXIMUM_DN", NULL );
+            if (pszMin != NULL && pszMax != NULL )
+                poBand->SetStatistics(CPLAtofM(pszMin),CPLAtofM(pszMax),0,0);
+            const char* pszNoData = poDS->GetKeyword( "DTM.DTM_MISSING_DN", NULL );
+            if (pszNoData != NULL )
+                poBand->SetNoDataValue( CPLAtofM(pszNoData) );
+        } else if (EQUAL( poDS->GetKeyword( "BLTYPE"), "M94_HRSC" )) {
+            float scale=CPLAtof(poDS->GetKeyword("DLRTO8.REFLECTANCE_SCALING_FACTOR","-1."));
+            if (scale < 0.) {
+                scale = CPLAtof(poDS->GetKeyword( "HRCAL.REFLECTANCE_SCALING_FACTOR","1."));
+            }
+            poBand->SetScale( scale );
+            float offset=CPLAtof(poDS->GetKeyword("DLRTO8.REFLECTANCE_OFFSET","-1."));
+            if (offset < 0.) {
+                offset = CPLAtof(poDS->GetKeyword( "HRCAL.REFLECTANCE_OFFSET","0."));
+            }
+            poBand->SetOffset( offset );
+        }
+        const char* pszMin = poDS->GetKeyword( "STATISTICS.MINIMUM", NULL );
+        const char* pszMax = poDS->GetKeyword( "STATISTICS.MAXIMUM", NULL );
+        const char* pszMean = poDS->GetKeyword( "STATISTICS.MEAN", NULL );
+        const char* pszStdDev = poDS->GetKeyword( "STATISTICS.STANDARD_DEVIATION", NULL );
+        if (pszMin != NULL && pszMax != NULL && pszMean != NULL && pszStdDev != NULL )
+                poBand->SetStatistics(CPLAtofM(pszMin),CPLAtofM(pszMax),CPLAtofM(pszMean),CPLAtofM(pszStdDev));
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      Instrument-specific keywords as metadata.                       */
+/* -------------------------------------------------------------------- */
+
+/******************   HRSC    ******************************/
+   
+    if (EQUAL( poDS->GetKeyword( "BLTYPE"), "M94_HRSC" ) ) {
+        poDS->SetMetadataItem( "SPACECRAFT_NAME", poDS->GetKeyword( "M94_INSTRUMENT.INSTRUMENT_HOST_NAME") );
+        poDS->SetMetadataItem( "PRODUCT_TYPE", poDS->GetKeyword( "TYPE"));
+    	
+        if (EQUAL( poDS->GetKeyword( "M94_INSTRUMENT.DETECTOR_ID"), "MEX_HRSC_SRC" )) {
+            static const char *apszKeywords[] =  {
+                        "M94_ORBIT.IMAGE_TIME",
+                        "FILE.EVENT_TYPE",
+                        "FILE.PROCESSING_LEVEL_ID",
+                        "M94_INSTRUMENT.DETECTOR_ID", 
+                        "M94_CAMERAS.EXPOSURE_DURATION",
+                        "HRCONVER.INSTRUMENT_TEMPERATURE", NULL
+                    };
+            for( i = 0; apszKeywords[i] != NULL; i++ ) {
+                const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
+                if( pszKeywordValue != NULL )
+                    poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
+            }
+        } else {
+            static const char *apszKeywords[] =  {
+                "M94_ORBIT.START_TIME", "M94_ORBIT.STOP_TIME",
+                "M94_INSTRUMENT.DETECTOR_ID",
+                "M94_CAMERAS.MACROPIXEL_SIZE",
+                "FILE.EVENT_TYPE",
+                "M94_INSTRUMENT.MISSION_PHASE_NAME",
+                "HRORTHO.SPICE_FILE_NAME",
+                "HRCONVER.MISSING_FRAMES", "HRCONVER.OVERFLOW_FRAMES", "HRCONVER.ERROR_FRAMES",
+                "HRFOOT.BEST_GROUND_SAMPLING_DISTANCE",
+                "DLRTO8.RADIANCE_SCALING_FACTOR", "DLRTO8.RADIANCE_OFFSET",
+                "DLRTO8.REFLECTANCE_SCALING_FACTOR", "DLRTO8.REFLECTANCE_OFFSET",
+                "HRCAL.RADIANCE_SCALING_FACTOR", "HRCAL.RADIANCE_OFFSET",
+                "HRCAL.REFLECTANCE_SCALING_FACTOR", "HRCAL.REFLECTANCE_OFFSET",
+                "HRORTHO.DTM_NAME", "HRORTHO.EXTORI_FILE_NAME", "HRORTHO.GEOMETRIC_CALIB_FILE_NAME",
+                NULL
+            };
+            for( i = 0; apszKeywords[i] != NULL; i++ ) {
+                const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i], NULL );
+                if( pszKeywordValue != NULL )
+                    poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
+            }
+        }
+    }
+    if (bIsDTM==TRUE && EQUAL( poDS->GetKeyword( "MAP.TARGET_NAME"), "MARS" )) {
+        poDS->SetMetadataItem( "SPACECRAFT_NAME", "MARS_EXPRESS" );
+        poDS->SetMetadataItem( "PRODUCT_TYPE", "DTM");
+        static const char *apszKeywords[] = {
+            "DTM.DTM_MISSING_DN", "DTM.DTM_OFFSET", "DTM.DTM_SCALING_FACTOR", "DTM.DTM_A_AXIS_RADIUS", 
+            "DTM.DTM_B_AXIS_RADIUS", "DTM.DTM_C_AXIS_RADIUS", "DTM.DTM_DESC", "DTM.DTM_MINIMUM_DN",
+            "DTM.DTM_MAXIMUM_DN", NULL };
+        for( i = 0; apszKeywords[i] != NULL; i++ ) {
+            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
+            if( pszKeywordValue != NULL )
+                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
+        }
+    }
+
+
+/******************   DAWN   ******************************/
+    else if (EQUAL( poDS->GetKeyword( "INSTRUMENT_ID"), "FC2" )) {
+        poDS->SetMetadataItem( "SPACECRAFT_NAME", "DAWN" );
+        static const char *apszKeywords[] =  {"ORBIT_NUMBER","FILTER_NUMBER",
+        "FRONT_DOOR_STATUS",
+        "FIRST_LINE",
+        "FIRST_LINE_SAMPLE",
+        "PRODUCER_INSTITUTION_NAME",
+        "SOURCE_FILE_NAME",
+        "PROCESSING_LEVEL_ID",
+        "TARGET_NAME",
+        "LIMB_IN_IMAGE",
+        "POLE_IN_IMAGE",
+        "REFLECTANCE_SCALING_FACTOR",
+        "SPICE_FILE_NAME",
+        "SPACECRAFT_CENTRIC_LATITUDE",
+        "SPACECRAFT_EASTERN_LONGITUDE",
+        "FOOTPRINT_POSITIVE_LONGITUDE",
+            NULL };
+        for( i = 0; apszKeywords[i] != NULL; i++ ) {
+            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
+            if( pszKeywordValue != NULL )
+                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
+        }
+        
+    }
+    else if (bIsDTM==TRUE && EQUAL( poDS->GetKeyword( "TARGET_NAME"), "VESTA" )) {
+        poDS->SetMetadataItem( "SPACECRAFT_NAME", "DAWN" );
+        poDS->SetMetadataItem( "PRODUCT_TYPE", "DTM");
+        static const char *apszKeywords[] = {
+            "DTM_MISSING_DN", "DTM_OFFSET", "DTM_SCALING_FACTOR", "DTM_A_AXIS_RADIUS", 
+            "DTM_B_AXIS_RADIUS", "DTM_C_AXIS_RADIUS", "DTM_MINIMUM_DN",
+            "DTM_MAXIMUM_DN", "MAP_PROJECTION_TYPE", "COORDINATE_SYSTEM_NAME",
+            "POSITIVE_LONGITUDE_DIRECTION", "MAP_SCALE",
+            "CENTER_LONGITUDE", "LINE_PROJECTION_OFFSET", "SAMPLE_PROJECTION_OFFSET",
+            NULL };
+        for( i = 0; apszKeywords[i] != NULL; i++ ) {
+            const char *pszKeywordValue = poDS->GetKeyword( apszKeywords[i] );
+            if( pszKeywordValue != NULL )
+                poDS->SetMetadataItem( apszKeywords[i], pszKeywordValue );
+        }
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      END Instrument-specific keywords as metadata.                   */
+/* -------------------------------------------------------------------- */
+
+    if (EQUAL(poDS->GetKeyword( "EOL"), "1" ))
+        poDS->SetMetadataItem( "END-OF-DATASET_LABEL", "PRESENT" );
+    poDS->SetMetadataItem( "CONVERSION_DETAILS", "http://www.lpi.usra.edu/meetings/lpsc2014/pdf/1088.pdf" );
+
+/* -------------------------------------------------------------------- */
+/*      Initialize any PAM information.                                 */
+/* -------------------------------------------------------------------- */
+    poDS->TryLoadXML();
+
+/* -------------------------------------------------------------------- */
+/*      Check for overviews.                                            */
+/* -------------------------------------------------------------------- */
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+
+    return( poDS );
+}
+
+/************************************************************************/
+/*                             GetKeyword()                             */
+/************************************************************************/
+
+const char *VICARDataset::GetKeyword( const char *pszPath, 
+                                      const char *pszDefault )
+
+{
+    return oKeywords.GetKeyword( pszPath, pszDefault );
+}
+
+
+
+/************************************************************************/
+/*                         GDALRegister_VICAR()                         */
+/************************************************************************/
+
+void GDALRegister_VICAR()
+
+{
+    GDALDriver	*poDriver;
+
+    if( GDALGetDriverByName( "VICAR" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+        
+        poDriver->SetDescription( "VICAR" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "MIPL VICAR file" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_vicar.html" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = VICARDataset::Open;
+        poDriver->pfnIdentify = VICARDataset::Identify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
+
diff --git a/frmts/pds/vicarkeywordhandler.cpp b/frmts/pds/vicarkeywordhandler.cpp
new file mode 100644
index 0000000..8cc1100
--- /dev/null
+++ b/frmts/pds/vicarkeywordhandler.cpp
@@ -0,0 +1,355 @@
+/******************************************************************************
+* 
+* Project:  VICAR Driver; JPL/MIPL VICAR Format
+* Purpose:  Implementation of VICARKeywordHandler - a class to read 
+*           keyword data from VICAR data products.
+* Author:   Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+*
+* NOTE: This driver code is loosely based on the ISIS and PDS drivers.
+* It is not intended to diminish the contribution of the authors 
+******************************************************************************
+* Copyright (c) 2014, Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+* 
+* 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.
+****************************************************************************/
+
+
+#include "cpl_string.h" 
+#include "vicarkeywordhandler.h"
+
+/************************************************************************/
+/* ==================================================================== */
+/*                          VICARKeywordHandler                          */
+/* ==================================================================== */
+/************************************************************************/
+
+/************************************************************************/
+/*                         VICARKeywordHandler()                         */
+/************************************************************************/
+
+VICARKeywordHandler::VICARKeywordHandler()
+
+{
+    papszKeywordList = NULL;
+}
+
+/************************************************************************/
+/*                        ~VICARKeywordHandler()                         */
+/************************************************************************/
+
+VICARKeywordHandler::~VICARKeywordHandler()
+
+{
+    CSLDestroy( papszKeywordList );
+    papszKeywordList = NULL;
+}
+
+/************************************************************************/
+/*                               Ingest()                               */
+/************************************************************************/
+
+int VICARKeywordHandler::Ingest( VSILFILE *fp, GByte *pabyHeader )
+
+{
+/* -------------------------------------------------------------------- */
+/*      Read in buffer till we find END all on it's own line.           */
+/* -------------------------------------------------------------------- */
+    if( VSIFSeekL( fp, 0, SEEK_SET ) != 0 )
+        return FALSE;
+
+    char *pch1, *pch2;
+    char keyval[100];
+
+    // Find LBLSIZE Entry
+    char* pszLBLSIZE=strstr((char*)pabyHeader,"LBLSIZE");
+    int nOffset = 0;
+
+    if (pszLBLSIZE)
+        nOffset = pszLBLSIZE - (const char *)pabyHeader;
+    pch1=strstr((char*)pabyHeader+nOffset,"=");
+    if( pch1 == NULL ) return FALSE;
+    pch1 ++;
+    pch2=strstr((char*)pabyHeader+nOffset," ");
+    if( pch2 == NULL ) return FALSE;
+    strncpy(keyval,pch1,MAX(pch2-pch1, 99));
+    keyval[MAX(pch2-pch1, 99)] = 0;
+    LabelSize=atoi(keyval);    
+    if( LabelSize > 10 * 1024 * 124 )
+        return FALSE;
+
+    char* pszChunk = (char*) VSIMalloc(LabelSize+1);
+    if( pszChunk == NULL )
+        return FALSE;
+    int nBytesRead = VSIFReadL( pszChunk, 1, LabelSize, fp );
+    pszChunk[LabelSize] = 0;
+
+    osHeaderText += pszChunk ;
+    VSIFree(pszChunk);
+    pszHeaderNext = osHeaderText.c_str();
+    
+/* -------------------------------------------------------------------- */
+/*      Process name/value pairs, keeping track of a "path stack".      */
+/* -------------------------------------------------------------------- */
+    if( !ReadGroup("") )
+        return FALSE;
+/* -------------------------------------------------------------------- */
+/*      Now check for the Vicar End-of-Dataset Label...                 */
+/* -------------------------------------------------------------------- */
+    const char *pszResult;
+
+    pszResult = CSLFetchNameValue( papszKeywordList, "EOL" );
+    
+    if( pszResult == NULL )
+        return FALSE;
+
+    if( !EQUAL(pszResult,"1") ) 
+        return TRUE;
+
+/* -------------------------------------------------------------------- */
+/*      There is a EOL!   e.G.  h4231_0000.nd4.06                       */
+/* -------------------------------------------------------------------- */
+
+    long int	    nLineOffset=0, nPixelOffset=0, nBandOffset=0;
+    if (EQUAL( CSLFetchNameValue(papszKeywordList,"FORMAT" ), "BYTE" )) {
+        nPixelOffset = 1;
+    }
+    else if (EQUAL( CSLFetchNameValue(papszKeywordList,"FORMAT" ), "HALF" )) {
+        nPixelOffset = 2;
+    }
+    else if (EQUAL( CSLFetchNameValue(papszKeywordList,"FORMAT" ), "FULL" )) {
+        nPixelOffset = 4;
+    } 
+    else if (EQUAL( CSLFetchNameValue(papszKeywordList,"FORMAT" ), "REAL" )) {
+        nPixelOffset = 4;
+    }
+    long int nCols = atoi(CSLFetchNameValue(papszKeywordList,"NS")) ;
+    long int nRows = atoi(CSLFetchNameValue(papszKeywordList,"NL")) ;
+    int nBands = atoi(CSLFetchNameValue(papszKeywordList,"NB")) ;
+    int nBB = atoi(CSLFetchNameValue(papszKeywordList,"NBB")) ;
+    nLineOffset = nPixelOffset * nCols + nBB ;
+    nBandOffset = nLineOffset * nRows;
+    long int starteol = LabelSize + nBandOffset * nBands;
+    if( VSIFSeekL( fp, starteol, SEEK_SET ) != 0 ) {
+        printf("Error seeking to EOL!\n");
+        return FALSE;
+        }
+    char szChunk[100];
+    nBytesRead = VSIFReadL( szChunk, 1, 30, fp );
+    szChunk[nBytesRead] = '\0';
+    pszLBLSIZE=strstr(szChunk,"LBLSIZE");
+    nOffset=0;
+    
+    if (pszLBLSIZE)
+        nOffset = pszLBLSIZE - (const char *)szChunk;
+    pch1=strstr((char*)szChunk+nOffset,"=")+1;
+    pch2=strstr((char*)szChunk+nOffset," ");
+    strncpy(keyval,pch1,pch2-pch1);
+    int EOLabelSize=atoi(keyval);
+    if( EOLabelSize > 99 )
+        EOLabelSize = 99;
+    if( VSIFSeekL( fp, starteol, SEEK_SET ) != 0 ) {
+        printf("Error seeking again to EOL!\n");
+        return FALSE;
+        }
+    nBytesRead = VSIFReadL( szChunk, 1, EOLabelSize, fp );
+    szChunk[nBytesRead] = '\0';
+    osHeaderText += szChunk ;
+    osHeaderText.append("END");
+    pszHeaderNext = osHeaderText.c_str();
+    return ReadGroup( "" );
+    
+}
+
+/************************************************************************/
+/*                             ReadGroup()                              */
+/************************************************************************/
+
+int VICARKeywordHandler::ReadGroup( CPL_UNUSED const char *pszPathPrefix ) {
+    CPLString osName, osValue, osProperty;
+
+    for( ; TRUE; ) {
+        if( !ReadPair( osName, osValue ) ) {
+        //printf("Could not... \n");
+                return FALSE;
+                }
+            if( EQUAL(osName,"END") )
+            return TRUE;
+            else if( EQUAL(osName,"PROPERTY") || EQUAL(osName,"HISTORY") || EQUAL(osName,"TASK"))
+                osProperty = osValue;
+        else {
+            if ( !EQUAL(osProperty,"") )
+                osName = osProperty + "." + osName;
+            papszKeywordList = CSLSetNameValue( papszKeywordList, osName, osValue );
+        }
+    }
+}
+
+
+/************************************************************************/
+/*                              ReadPair()                              */
+/*                                                                      */
+/*      Read a name/value pair from the input stream.  Strip off        */
+/*      white space, ignore comments, split on '='.                     */
+/*      Returns TRUE on success.                                        */
+/************************************************************************/
+
+int VICARKeywordHandler::ReadPair( CPLString &osName, CPLString &osValue ) {
+
+    osName = "";
+    osValue = "";
+
+    if( !ReadWord( osName ) ) {
+    return FALSE;}
+
+    SkipWhite();
+    
+    // VICAR has no NULL string termination
+    if( *pszHeaderNext == '\0') {
+        osName="END";
+        return TRUE;
+    }
+
+    pszHeaderNext++;
+    
+    SkipWhite();
+    
+    osValue = "";
+
+    if( *pszHeaderNext == '(' && pszHeaderNext[1] == '\'' )
+    {
+        CPLString osWord;
+        while( ReadWord( osWord ) )
+        {
+            osValue += osWord;
+            if ( strlen(osWord) < 2 ) continue;
+            if( osWord[strlen(osWord)-1] == ')' && osWord[strlen(osWord)-2] == '\'' ) break;
+        }
+    }
+
+    else if( *pszHeaderNext == '(' && *pszHeaderNext-1 != '\'' )
+    {
+        CPLString osWord;
+
+        while( ReadWord( osWord ) )
+        {
+            SkipWhite();
+
+            osValue += osWord;
+            if( osWord[strlen(osWord)-1] == ')'  ) break;
+        }
+    }
+
+    else
+    {
+        if( !ReadWord( osValue ) ) return FALSE;
+
+    }
+        
+    SkipWhite();
+    
+    return TRUE;
+}
+
+/************************************************************************/
+/*                              ReadWord()                              */
+/*  Returns TRUE on success                                             */
+/************************************************************************/
+
+int VICARKeywordHandler::ReadWord( CPLString &osWord )
+
+{
+    osWord = "";
+
+    SkipWhite();
+
+    if( *pszHeaderNext == '\0') return TRUE;
+    
+    if( !( *pszHeaderNext != '='  && !isspace((unsigned char)*pszHeaderNext)) ) {
+    return FALSE;
+    }
+
+    if( *pszHeaderNext == '\'' )
+    {
+        pszHeaderNext++;
+        while( *pszHeaderNext != '\'' )
+        {
+            //Skip Double Quotes
+                        if( *pszHeaderNext+1 == '\'' ) continue;
+            osWord += *(pszHeaderNext++);
+        }
+        pszHeaderNext++;
+        return TRUE;
+    }
+
+    while( *pszHeaderNext != '=' && !isspace((unsigned char)*pszHeaderNext) )
+    {
+        osWord += *pszHeaderNext;
+        pszHeaderNext++;
+
+    }
+    
+    return TRUE;
+}
+
+/************************************************************************/
+/*                             SkipWhite()                              */
+/*  Skip white spaces and C style comments                              */
+/************************************************************************/
+
+void VICARKeywordHandler::SkipWhite()
+
+{
+    for( ; TRUE; )
+    {
+        if( isspace( (unsigned char)*pszHeaderNext ) )
+        {
+            pszHeaderNext++;
+            continue;
+        }
+        
+        // not white space, return. 
+        return;
+    }
+}
+
+/************************************************************************/
+/*                             GetKeyword()                             */
+/************************************************************************/
+
+const char *VICARKeywordHandler::GetKeyword( const char *pszPath, const char *pszDefault )
+
+{
+    const char *pszResult;
+
+    pszResult = CSLFetchNameValue( papszKeywordList, pszPath );
+    if( pszResult == NULL ){
+        return pszDefault;}
+    else
+        return pszResult;
+}
+
+/************************************************************************/
+/*                             GetKeywordList()                         */
+/************************************************************************/
+
+char **VICARKeywordHandler::GetKeywordList()
+{
+    return papszKeywordList;
+}
+
diff --git a/frmts/pds/vicarkeywordhandler.h b/frmts/pds/vicarkeywordhandler.h
new file mode 100644
index 0000000..36564e4
--- /dev/null
+++ b/frmts/pds/vicarkeywordhandler.h
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * 
+ * Project:  VICAR Driver; JPL/MIPL VICAR Format
+ * Purpose:  Implementation of VICARKeywordHandler - a class to read 
+ *           keyword data from VICAR data products.
+ * Authors:  Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+ *
+ * NOTE: This driver code is loosely based on the ISIS and PDS drivers.
+ * It is not intended to diminish the contribution of the authors 
+ ******************************************************************************
+ * Copyright (c) 2014, Sebastian Walter <sebastian dot walter at fu-berlin dot de>
+ * 
+ * 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.
+ ****************************************************************************/
+class VICARKeywordHandler
+{
+    char     **papszKeywordList;
+
+    CPLString osHeaderText;
+    const char *pszHeaderNext;
+
+    void    SkipWhite();
+    int     ReadWord( CPLString &osWord );
+    int     ReadPair( CPLString &osName, CPLString &osValue );
+    int     ReadGroup( const char *pszPathPrefix );
+    int     LabelSize;
+    int     Eol;
+
+public:
+    VICARKeywordHandler();
+    ~VICARKeywordHandler();
+
+    int     Ingest( VSILFILE *fp, GByte *pabyHeader );
+
+    const char *GetKeyword( const char *pszPath, const char *pszDefault );
+    char **GetKeywordList();
+};
diff --git a/frmts/pgchip/GNUmakefile b/frmts/pgchip/GNUmakefile
index 2019d53..43a2ef6 100644
--- a/frmts/pgchip/GNUmakefile
+++ b/frmts/pgchip/GNUmakefile
@@ -9,7 +9,7 @@ include ../../GDALmake.opt
 OBJ	=	pgchipdataset.o pgchiprasterband.o pgchiputilities.o
 
 
-CPPFLAGS	:= -Wall -g $(XTRA_OPT) $(PG_INC) $(POSTGIS_INC) $(GDAL_INCLUDE) $(CPPFLAGS )
+CPPFLAGS	:= -Wall -g $(XTRA_OPT) $(PG_INC) $(POSTGIS_INC)  $(CPPFLAGS )
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/pgchip/pgchipdataset.cpp b/frmts/pgchip/pgchipdataset.cpp
index 69c0b84..0712f7e 100644
--- a/frmts/pgchip/pgchipdataset.cpp
+++ b/frmts/pgchip/pgchipdataset.cpp
@@ -978,6 +978,7 @@ void GDALRegister_PGCHIP(){
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "PGCHIP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Postgis CHIP raster" );
                                    
diff --git a/frmts/plmosaic/GNUmakefile b/frmts/plmosaic/GNUmakefile
new file mode 100644
index 0000000..0cc74c5
--- /dev/null
+++ b/frmts/plmosaic/GNUmakefile
@@ -0,0 +1,13 @@
+
+include ../../GDALmake.opt
+
+OBJ	=	plmosaicdataset.o
+
+CPPFLAGS	:=	 $(JSON_INCLUDE) $(CPPFLAGS) 
+
+default:	$(OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(OBJ) $(O_OBJ)
+
+install-obj:	$(O_OBJ:.o=.$(OBJ_EXT))
diff --git a/frmts/plmosaic/frmt_plmosaic.html b/frmts/plmosaic/frmt_plmosaic.html
new file mode 100644
index 0000000..3bb60d4
--- /dev/null
+++ b/frmts/plmosaic/frmt_plmosaic.html
@@ -0,0 +1,241 @@
+<html>
+<head>
+<title>PLMosaic (Planet Labs Mosaics API)</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>PLMosaic (Planet Labs Mosaics API)</h1>
+
+(GDAL/OGR >= 2.0)<p>
+
+This driver can connect to Planet Labs Mosaics API.
+GDAL/OGR must be built with Curl support in order for the
+PLMosaic driver to be compiled.<p>
+
+The driver supports listing mosaics and reading them.
+Mosaics are accessed at their highest resolution (Google Maps
+level 15, i.e. 4.77 meters/pixel). Mosaics are typically composed of quads of
+4096x4096 pixels.<p>
+
+For mosaics of type Byte, overviews are available by using the tile API. For other
+data types, there is no support for overviews, so requests that involve downsampling may
+take a long time to complete.<p>
+
+<h2>Dataset name syntax</h2>
+
+The minimal syntax to open a datasource is : <pre>PLMosaic:[options]</pre><p>
+
+Additionnal optional parameters can be specified after the ':' sign.
+Currently the following one is supported :<p>
+
+<ul>
+<li> <b>api_key</b>=value: To specify the Planet API key. It is mandatory, unless
+it is supplied through the open option API_KEY, or the configuration option PL_API_KEY.</li>
+<li> <b>mosaic</b>=mosaic_name: To specify the mosaic name.</li>
+<li><b>cache_path</b>=path: To specify the path to a directory where cached
+quads (and tiles) are stored. A plmosaic_cache/{mosaic_name} subdirectory will be created
+under that path. The empty string can be used to disable any disk caching.</li>
+<li><b>trust_cache</b>=YES/NO: Whether already cached quads should be reused directly,
+without prior checking if the server has a more recent version. Note:
+this only applies to quads, and not tiles. Default is NO.</li>
+<li><b>use_tiles</b>=YES/NO: Whether to use the tile API to access full
+resolution data, instead of downloading quads. Only apply for Byte mosaics. Default is NO.</li>
+</ul>
+
+If several parameters are specified, they must be separated by a comma.<p>
+
+<p>If no mosaic parameter is supplied, the list of available mosaics will be
+returned as subdatasets. If only one mosaic is available, it will be directly
+opened.</p>
+
+<h2>Open options</h2>
+
+<p>The following open options are available : API_KEY, MOSAIC, CACHE_PATH,
+TRUST_CACHE and USE_TILES. They have the same semantics as the above
+describe parameters of same name.</p>
+
+<h2>Configuration options</h2>
+
+The following configuration options are available :
+<ul>
+<li><b>PL_API_KEY</b>=value: To specify the Planet API key.</li>
+</ul>
+
+<h2>Location information</h2>
+
+<p>
+The special <i>Pixel_{x}_{y}</i> metadata item of the <i>LocationInfo</i> metadata domain,
+where x is the column and y is the line in the mosaic, can be queried to get
+information about the underneath quad and the scenes that compose it (only scenes
+whose footprint intersect the point are listed). This is
+the syntax used by the gdallocationinfo utility
+(see <a href="https://trac.osgeo.org/gdal/wiki/rfc32_gdallocationinfo">RFC 32</a>)
+</p> 
+
+<p>Below an example of the return :
+<pre>
+<LocationInfo>
+    <Quad>
+        <id>L15-0455E-1272N</id>
+        <file_size>9205776</file_size>
+        <links_full>https://api.planet.com/v0/mosaics/color_balance_mosaic/quads/L15-0455E-1272N/full</links_full>
+        <links_mosaic>https://api.planet.com/v0/mosaics/color_balance_mosaic</links_mosaic>
+        <links_scenes>https://api.planet.com/v0/mosaics/color_balance_mosaic/quads/L15-0455E-1272N/scenes/</links_scenes>
+        <links_self>https://api.planet.com/v0/mosaics/color_balance_mosaic/quads/L15-0455E-1272N</links_self>
+        <links_thumbnail>https://api.planet.com/v0/mosaics/color_balance_mosaic/quads/L15-0455E-1272N/thumb</links_thumbnail>
+        <num_input_scenes>5</num_input_scenes>
+        <percent_covered>23.52</percent_covered>
+        <geometry>POLYGON ((-100.019531236 40.04443758,-100.019531236 39.909736229899998,-99.843749986099994 39.909736229899998,-99.843749986099994 40.04443758,-100.019531236 40.04443758))</geometry>
+    </Quad>
+    <Scenes>
+        <Scene>
+            <id>20141014_165043_0908</id>
+            <acquired>2014/10/14 16:50:43+00</acquired>
+            <camera_bit_depth>8</camera_bit_depth>
+            <camera_color_mode>RGB</camera_color_mode>
+            <camera_exposure_time>1170</camera_exposure_time>
+            <camera_gain>560</camera_gain>
+            <camera_tdi_pulses>4</camera_tdi_pulses>
+            <cloud_cover_estimated>0</cloud_cover_estimated>
+            <data_products_analytic_full>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908/full?product=analytic</data_products_analytic_full>
+            <data_products_visual_full>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908/full?product=visual</data_products_visual_full>
+            <file_size>52363596</file_size>
+            <image_statistics_gsd>4.22939278619</image_statistics_gsd>
+            <image_statistics_image_quality>standard</image_statistics_image_quality>
+            <image_statistics_snr>38.816414101138</image_statistics_snr>
+            <links_full>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908/full</links_full>
+            <links_self>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908</links_self>
+            <links_square_thumbnail>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908/square-thumb</links_square_thumbnail>
+            <links_thumbnail>https://api.planet.com/v0/scenes/ortho/20141014_165043_0908/thumb</links_thumbnail>
+            <quad_metadata_percentage_of_quad>1.72</quad_metadata_percentage_of_quad>
+            <sat_alt>625.335328005</sat_alt>
+            <sat_id>0908</sat_id>
+            <sat_lat>39.929866991</sat_lat>
+            <sat_lng>-99.7924758414</sat_lng>
+            <sat_off_nadir>2.16630567839854</sat_off_nadir>
+            <strip_id>1413305228.34946</strip_id>
+            <sun_altitude>37.0861376836067</sun_altitude>
+            <sun_azimuth>150.226745964007</sun_azimuth>
+            <sun_local_time_of_day>10.1924460550178</sun_local_time_of_day>
+            <geometry>POLYGON ((-99.972717127088671 39.955932287655287,-100.001449726838672 40.054504403484273,-100.15302892466832 40.028245144277392,-100.124005707005423 39.929632727481838,-99.972717127088671 39.955932287655287))</geometry>
+        </Scene>
+        <Scene>
+            ...
+        </Scene>
+    </Scenes>
+</LocationInfo>
+</pre>
+</p>
+
+<h3>Examples</h3>
+
+<li> Listing all mosaics available (with the rights of the account) :
+<pre>
+gdalinfo "PLMosaic:" -oo API_KEY=some_value
+</pre>
+or
+<pre>
+gdalinfo "PLMosaic:api_key=some_value"
+</pre>
+or
+<pre>
+gdalinfo "PLMosaic:" --config PL_API_KEY some_value
+</pre>
+
+returns (in case of multiple mosaics):
+
+<pre>
+Driver: PLMOSAIC/Planet Labs Mosaics API
+Files: none associated
+Size is 512, 512
+Coordinate System is `'
+Image Structure Metadata:
+  INTERLEAVE=PIXEL
+Subdatasets:
+  SUBDATASET_1_NAME=PLMOSAIC:mosaic=color_balance_mosaic
+  SUBDATASET_1_DESC=Color-Balanced Mosaic
+  ...
+Corner Coordinates:
+Upper Left  (    0.0,    0.0)
+Lower Left  (    0.0,  512.0)
+Upper Right (  512.0,    0.0)
+Lower Right (  512.0,  512.0)
+Center      (  256.0,  256.0)
+</pre>
+
+
+<li> Open a particular mosaic :
+<pre>
+gdalinfo "PLMosaic:mosaic=color_balance_mosaic" -oo API_KEY=some_value
+</pre>
+
+returns:
+<pre>
+Driver: PLMOSAIC/Planet Labs Mosaics API
+Files: none associated
+Size is 8388608, 8388608
+Coordinate System is:
+PROJCS["WGS 84 / Pseudo-Mercator",
+    GEOGCS["WGS 84",
+        DATUM["WGS_1984",
+            SPHEROID["WGS 84",6378137,298.257223563,
+                AUTHORITY["EPSG","7030"]],
+            AUTHORITY["EPSG","6326"]],
+        PRIMEM["Greenwich",0,
+            AUTHORITY["EPSG","8901"]],
+        UNIT["degree",0.0174532925199433,
+            AUTHORITY["EPSG","9122"]],
+        AUTHORITY["EPSG","4326"]],
+    PROJECTION["Mercator_1SP"],
+    PARAMETER["central_meridian",0],
+    PARAMETER["scale_factor",1],
+    PARAMETER["false_easting",0],
+    PARAMETER["false_northing",0],
+    UNIT["metre",1,
+        AUTHORITY["EPSG","9001"]],
+    AXIS["X",EAST],
+    AXIS["Y",NORTH],
+    EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs"],
+    AUTHORITY["EPSG","3857"]]
+Origin = (-20037508.339999999850988,20037508.339999999850988)
+Pixel Size = (4.777314267160000,-4.777314267160000)
+Metadata:
+  FIRST_ACQUIRED=2014-03-20T15:57:11+00:00
+  LAST_ACQUIRED=2015-04-06T11:38:16.570663+00:00
+  TITLE=Color-Balanced Mosaic
+Image Structure Metadata:
+  INTERLEAVE=PIXEL
+Corner Coordinates:
+Upper Left  (-20037508.340,20037508.340) (180d 0' 0.00"W, 85d 3' 4.06"N)
+Lower Left  (-20037508.340,-20037508.340) (180d 0' 0.00"W, 85d 3' 4.06"S)
+Upper Right (20037508.340,20037508.340) (180d 0' 0.00"E, 85d 3' 4.06"N)
+Lower Right (20037508.340,-20037508.340) (180d 0' 0.00"E, 85d 3' 4.06"S)
+Center      (   0.0000063,  -0.0000063) (  0d 0' 0.00"E,  0d 0' 0.00"S)
+Band 1 Block=256x256 Type=Byte, ColorInterp=Red
+  Overviews: 4194304x4194304, ..., 256x256
+  Mask Flags: PER_DATASET ALPHA 
+  Overviews of mask band: Overviews: 4194304x4194304, ..., 256x256
+Band 2 Block=256x256 Type=Byte, ColorInterp=Green
+  Overviews: 4194304x4194304, ..., 256x256
+  Mask Flags: PER_DATASET ALPHA 
+  Overviews of mask band: Overviews: 4194304x4194304, ..., 256x256
+Band 3 Block=256x256 Type=Byte, ColorInterp=Blue
+  Overviews: 4194304x4194304, ..., 256x256
+  Mask Flags: PER_DATASET ALPHA 
+  Overviews of mask band: Overviews: 4194304x4194304, ..., 256x256
+Band 4 Block=256x256 Type=Byte, ColorInterp=Alpha
+  Overviews: 4194304x4194304, ..., 256x256
+</pre>
+
+
+<h2>See Also</h2>
+
+<ul>
+<li> <a href="https://www.planet.com/docs/v0/mosaics/">Documentation of Planet Mosaics API</a><p>
+<li> <a href="https://www.planet.com/docs/v0/general-concepts/#authentication">API Authentication</a><p>
+<li> <a href="drv_plscenes.html">Vector PLScenes / Planet Scenes API driver</a><p>
+</ul>
+
+</body>
+</html>
diff --git a/frmts/plmosaic/makefile.vc b/frmts/plmosaic/makefile.vc
new file mode 100644
index 0000000..8bd163f
--- /dev/null
+++ b/frmts/plmosaic/makefile.vc
@@ -0,0 +1,16 @@
+
+OBJ	=	plmosaicdataset.obj
+
+EXTRAFLAGS = $(CURL_CFLAGS) $(CURL_INC)  -I..\..\ogr\ogrsf_frmts\geojson -I../../ogr/ogrsf_frmts/geojson/libjson
+
+GDAL_ROOT	=	..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+
+default:	$(OBJ)
+	xcopy /D  /Y *.obj ..\o
+
+clean:
+	-del *.obj
+	-del *.dll
diff --git a/frmts/plmosaic/plmosaicdataset.cpp b/frmts/plmosaic/plmosaicdataset.cpp
new file mode 100644
index 0000000..6e4bc20
--- /dev/null
+++ b/frmts/plmosaic/plmosaicdataset.cpp
@@ -0,0 +1,1511 @@
+/******************************************************************************
+ * $Id: plmosaicdataset.cpp 29019 2015-04-25 20:34:19Z rouault $
+ *
+ * Project:  PLMosaic driver
+ * Purpose:  PLMosaic driver
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Planet Labs
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdal_priv.h"
+#include "gdal_pam.h"
+#include "ogr_spatialref.h"
+#include "ogrsf_frmts.h"
+#include "cpl_http.h"
+#include "cpl_minixml.h"
+#include <json.h>
+
+CPL_CVSID("$Id: plmosaicdataset.cpp 29019 2015-04-25 20:34:19Z rouault $");
+
+extern "C" void GDALRegister_PLMOSAIC();
+
+// g++ -fPIC -g -Wall frmts/plmosaic/*.cpp -shared -o gdal_PLMOSAIC.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/geojson/libjson -L. -lgdal
+
+#define GM_ORIGIN  -20037508.340
+#define GM_ZOOM_0  ((2 * -(GM_ORIGIN)) / 256)
+
+/************************************************************************/
+/* ==================================================================== */
+/*                           PLMosaicDataset                            */
+/* ==================================================================== */
+/************************************************************************/
+
+class PLLinkedDataset;
+class PLLinkedDataset
+{
+public:
+    CPLString            osKey;
+    GDALDataset         *poDS;
+    PLLinkedDataset       *psPrev;
+    PLLinkedDataset       *psNext;
+
+                        PLLinkedDataset() : poDS(NULL), psPrev(NULL), psNext(NULL) {}
+};
+
+class PLMosaicRasterBand;
+
+class PLMosaicDataset : public GDALPamDataset
+{
+    friend class PLMosaicRasterBand;
+    
+        int                     bMustCleanPersistant;
+        CPLString               osCachePathRoot;
+        int                     bTrustCache;
+        CPLString               osBaseURL;
+        CPLString               osAPIKey;
+        CPLString               osMosaic;
+        char                   *pszWKT;
+        int                     nQuadSize;
+        CPLString               osQuadPattern;
+        CPLString               osQuadsURL;
+        int                     bHasGeoTransform;
+        double                  adfGeoTransform[6];
+        int                     nZoomLevel;
+        int                     bUseTMSForMain;
+        GDALDataset            *poTMSDS;
+
+        int                     nCacheMaxSize;
+        std::map<CPLString, PLLinkedDataset*> oMapLinkedDatasets;
+        PLLinkedDataset        *psHead;
+        PLLinkedDataset        *psTail;
+        void                    FlushDatasetsCache();
+        CPLString               GetMosaicCachePath();
+        void                    CreateMosaicCachePathIfNecessary();
+
+        int                     nLastMetaTileX;
+        int                     nLastMetaTileY;
+        CPLString               osLastQuadInformation;
+        CPLString               osLastQuadSceneInformation;
+        CPLString               osLastRetGetLocationInfo;
+        const char             *GetLocationInfo(int nPixel, int nLine);
+
+        char                  **GetBaseHTTPOptions();
+        CPLHTTPResult          *Download(const char* pszURL,
+                                         int bQuiet404Error = FALSE);
+        json_object            *RunRequest(const char* pszURL,
+                                           int bQuiet404Error = FALSE);
+        int                     OpenMosaic();
+        int                     ListSubdatasets();
+
+        CPLString               formatTileName(int tile_x, int tile_y);
+        void                    InsertNewDataset(CPLString osKey, GDALDataset* poDS);
+        GDALDataset*            OpenAndInsertNewDataset(CPLString osTmpFilename,
+                                                        CPLString osTilename);
+
+  public:
+                PLMosaicDataset();
+                ~PLMosaicDataset();
+    
+    static int Identify( GDALOpenInfo * poOpenInfo );
+    static GDALDataset  *Open( GDALOpenInfo * );
+
+    virtual CPLErr  IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
+
+    virtual void FlushCache(void);
+
+    virtual const char *GetProjectionRef();
+    virtual CPLErr      GetGeoTransform(double* padfGeoTransform);
+
+    GDALDataset        *GetMetaTile(int tile_x, int tile_y);
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                         PLMosaicRasterBand                           */
+/* ==================================================================== */
+/************************************************************************/
+
+class PLMosaicRasterBand : public GDALRasterBand
+{
+    friend class PLMosaicDataset;
+
+  public:
+
+                PLMosaicRasterBand( PLMosaicDataset * poDS, int nBand,
+                                    GDALDataType eDataType );
+
+    virtual CPLErr          IReadBlock( int, int, void * );
+    virtual CPLErr          IRasterIO( GDALRWFlag eRWFlag,
+                                  int nXOff, int nYOff, int nXSize, int nYSize,
+                                  void * pData, int nBufXSize, int nBufYSize,
+                                  GDALDataType eBufType,
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg);
+
+    virtual const char     *GetMetadataItem( const char* pszName,
+                                             const char * pszDomain = "" );
+
+    virtual GDALColorInterp GetColorInterpretation();
+
+    virtual int             GetOverviewCount();
+    virtual GDALRasterBand* GetOverview(int iOvrLevel);
+};
+
+
+/************************************************************************/
+/*                        PLMosaicRasterBand()                          */
+/************************************************************************/
+
+PLMosaicRasterBand::PLMosaicRasterBand( PLMosaicDataset *poDS, int nBand,
+                                        GDALDataType eDataType )
+
+{
+    this->eDataType = eDataType;
+    this->nBlockXSize = 256;
+    this->nBlockYSize = 256;
+
+    this->poDS = poDS;
+    this->nBand = nBand;
+    
+    if( eDataType == GDT_UInt16 )
+    {
+        if( nBand <= 3 )
+            SetMetadataItem("NBITS", "12", "IMAGE_STRUCTURE");
+    }
+}
+
+/************************************************************************/
+/*                             IReadBlock()                             */
+/************************************************************************/
+
+CPLErr PLMosaicRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
+                                       void * pImage )
+{
+    PLMosaicDataset* poMOSDS = (PLMosaicDataset*) poDS;
+    //CPLDebug("PLMOSAIC", "IReadBlock(band=%d, x=%d, y=%d)", nBand, xBlock, yBlock);
+
+    if( poMOSDS->bUseTMSForMain && poMOSDS->poTMSDS )
+        return poMOSDS->poTMSDS->GetRasterBand(nBand)->ReadBlock(nBlockXOff, nBlockYOff,
+                                                                pImage);
+
+    int bottom_yblock = (nRasterYSize - nBlockYOff * nBlockYSize) / nBlockYSize - 1;
+
+    int meta_tile_x = (nBlockXOff * nBlockXSize) / poMOSDS->nQuadSize;
+    int meta_tile_y = (bottom_yblock * nBlockYSize) / poMOSDS->nQuadSize;
+    int sub_tile_x = nBlockXOff % (poMOSDS->nQuadSize / nBlockXSize);
+    int sub_tile_y = nBlockYOff % (poMOSDS->nQuadSize / nBlockYSize);
+
+    GDALDataset *poMetaTileDS = poMOSDS->GetMetaTile(meta_tile_x, meta_tile_y);
+    if( poMetaTileDS == NULL )
+    {
+        memset(pImage, 0, 
+               nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType)/8));
+        return CE_None;
+    }
+
+    return poMetaTileDS->GetRasterBand(nBand)->
+                RasterIO( GF_Read, 
+                        sub_tile_x * nBlockXSize,
+                        sub_tile_y * nBlockYSize,
+                        nBlockXSize,
+                        nBlockYSize,
+                        pImage, nBlockXSize, nBlockYSize, 
+                        eDataType, 0, 0, NULL);
+}
+
+/************************************************************************/
+/*                             IRasterIO()                              */
+/************************************************************************/
+
+CPLErr PLMosaicRasterBand::IRasterIO( GDALRWFlag eRWFlag,
+                                         int nXOff, int nYOff, int nXSize, int nYSize,
+                                         void * pData, int nBufXSize, int nBufYSize,
+                                         GDALDataType eBufType,
+                                         GSpacing nPixelSpace, GSpacing nLineSpace,
+                                         GDALRasterIOExtraArg* psExtraArg )
+{
+    PLMosaicDataset* poMOSDS = (PLMosaicDataset*) poDS;
+    if( poMOSDS->bUseTMSForMain && poMOSDS->poTMSDS )
+        return poMOSDS->poTMSDS->GetRasterBand(nBand)->RasterIO(
+                                         eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                                         pData, nBufXSize, nBufYSize, eBufType,
+                                         nPixelSpace, nLineSpace, psExtraArg );
+
+    return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                                         pData, nBufXSize, nBufYSize, eBufType,
+                                         nPixelSpace, nLineSpace, psExtraArg );
+}
+
+/************************************************************************/
+/*                         GetMetadataItem()                            */
+/************************************************************************/
+
+const char* PLMosaicRasterBand::GetMetadataItem( const char* pszName,
+                                                 const char* pszDomain )
+{
+    int nPixel, nLine;
+    if( pszName != NULL && pszDomain != NULL && EQUAL(pszDomain, "LocationInfo") &&
+        sscanf(pszName, "Pixel_%d_%d", &nPixel, &nLine) == 2 )
+    {
+        PLMosaicDataset* poMOSDS = (PLMosaicDataset*) poDS;
+        return poMOSDS->GetLocationInfo(nPixel, nLine);
+    }
+    else
+        return GDALRasterBand::GetMetadataItem(pszName, pszDomain);
+}
+
+
+/************************************************************************/
+/*                         GetOverviewCount()                           */
+/************************************************************************/
+
+int PLMosaicRasterBand::GetOverviewCount()
+{
+    PLMosaicDataset *poGDS = (PLMosaicDataset *) poDS;
+    if( !poGDS->poTMSDS )
+        return 0;
+    return poGDS->poTMSDS->GetRasterBand(1)->GetOverviewCount();
+}
+
+/************************************************************************/
+/*                            GetOverview()                             */
+/************************************************************************/
+
+GDALRasterBand* PLMosaicRasterBand::GetOverview(int iOvrLevel)
+{
+    PLMosaicDataset *poGDS = (PLMosaicDataset *) poDS;
+    if (iOvrLevel < 0 || iOvrLevel >= GetOverviewCount())
+        return NULL;
+
+    poGDS->CreateMosaicCachePathIfNecessary();
+
+    return poGDS->poTMSDS->GetRasterBand(nBand)->GetOverview(iOvrLevel);
+}
+
+/************************************************************************/
+/*                       GetColorInterpretation()                       */
+/************************************************************************/
+
+GDALColorInterp PLMosaicRasterBand::GetColorInterpretation()
+{
+    switch( nBand )
+    {
+        case 1:
+            return GCI_RedBand;
+        case 2:
+            return GCI_GreenBand;
+        case 3:
+            return GCI_BlueBand;
+        case 4:
+            return GCI_AlphaBand;
+        default:
+            CPLAssert(FALSE);
+            return GCI_GrayIndex;
+    }
+}
+
+/************************************************************************/
+/* ==================================================================== */
+/*                           PLMosaicDataset                            */
+/* ==================================================================== */
+/************************************************************************/
+
+/************************************************************************/
+/*                        PLMosaicDataset()                            */
+/************************************************************************/
+
+PLMosaicDataset::PLMosaicDataset()
+{
+    bMustCleanPersistant = FALSE;
+    bTrustCache = FALSE;
+    pszWKT = NULL;
+    nQuadSize = 0;
+    bHasGeoTransform = FALSE;
+    adfGeoTransform[0] = 0;
+    adfGeoTransform[1] = 1;
+    adfGeoTransform[2] = 0;
+    adfGeoTransform[3] = 0;
+    adfGeoTransform[4] = 0;
+    adfGeoTransform[5] = 1;
+    nZoomLevel = 0;
+    psHead = NULL;
+    psTail = NULL;
+    SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
+    osCachePathRoot = CPLGetPath(CPLGenerateTempFilename(""));
+    nCacheMaxSize = 10;
+    nLastMetaTileX = -1;
+    nLastMetaTileY = -1;
+    bUseTMSForMain = FALSE;
+    poTMSDS = NULL;
+}
+
+/************************************************************************/
+/*                         ~PLMosaicDataset()                           */
+/************************************************************************/
+
+PLMosaicDataset::~PLMosaicDataset()
+
+{
+    FlushCache();
+    CPLFree(pszWKT);
+    delete poTMSDS;
+    if (bMustCleanPersistant)
+    {
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("PLMOSAIC:%p", this));
+        CPLHTTPFetch( osBaseURL, papszOptions);
+        CSLDestroy(papszOptions);
+    }
+
+}
+
+/************************************************************************/
+/*                      FlushDatasetsCache()                            */
+/************************************************************************/
+
+void PLMosaicDataset::FlushDatasetsCache()
+{
+    for( PLLinkedDataset* psIter = psHead; psIter != NULL;  )
+    {
+        PLLinkedDataset* psNext = psIter->psNext;
+        if( psIter->poDS )
+            GDALClose(psIter->poDS);
+        delete psIter;
+        psIter = psNext;
+    }
+    psHead = psTail = NULL;
+    oMapLinkedDatasets.clear();
+}
+
+/************************************************************************/
+/*                            FlushCache()                              */
+/************************************************************************/
+
+void PLMosaicDataset::FlushCache()
+{
+    FlushDatasetsCache();
+
+    nLastMetaTileX = -1;
+    nLastMetaTileY = -1;
+    osLastQuadInformation = "";
+    osLastQuadSceneInformation = "";
+    osLastRetGetLocationInfo = "";
+
+    GDALDataset::FlushCache();
+}
+
+/************************************************************************/
+/*                            Identify()                                */
+/************************************************************************/
+
+int PLMosaicDataset::Identify( GDALOpenInfo * poOpenInfo )
+
+{
+    return EQUALN(poOpenInfo->pszFilename, "PLMOSAIC:", strlen("PLMOSAIC:"));
+}
+
+/************************************************************************/
+/*                          GetBaseHTTPOptions()                         */
+/************************************************************************/
+
+char** PLMosaicDataset::GetBaseHTTPOptions()
+{
+    bMustCleanPersistant = TRUE;
+
+    char** papszOptions = NULL;
+    papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=PLMOSAIC:%p", this));
+    /* Use basic auth, rather than Authorization headers since curl would forward it to S3 */
+    papszOptions = CSLAddString(papszOptions, CPLSPrintf("USERPWD=%s:", osAPIKey.c_str()));
+    
+    return papszOptions;
+}
+
+/************************************************************************/
+/*                               Download()                             */
+/************************************************************************/
+
+CPLHTTPResult* PLMosaicDataset::Download(const char* pszURL,
+                                         int bQuiet404Error)
+{
+    char** papszOptions = CSLAddString(GetBaseHTTPOptions(), NULL);
+    CPLHTTPResult * psResult;
+    if( strncmp(osBaseURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
+        strncmp(pszURL, "/vsimem/", strlen("/vsimem/")) == 0 )
+    {
+        CPLDebug("PLSCENES", "Fetching %s", pszURL);
+        psResult = (CPLHTTPResult*) CPLCalloc(1, sizeof(CPLHTTPResult));
+        vsi_l_offset nDataLength = 0;
+        CPLString osURL(pszURL);
+        if( osURL[osURL.size()-1 ] == '/' )
+            osURL.resize(osURL.size()-1);
+        GByte* pabyBuf = VSIGetMemFileBuffer(osURL, &nDataLength, FALSE); 
+        if( pabyBuf )
+        {
+            psResult->pabyData = (GByte*) VSIMalloc(1 + (size_t)nDataLength);
+            if( psResult->pabyData )
+            {
+                memcpy(psResult->pabyData, pabyBuf, (size_t)nDataLength);
+                psResult->pabyData[nDataLength] = 0;
+                psResult->nDataLen = (size_t)nDataLength;
+            }
+        }
+        else
+        {
+            psResult->pszErrBuf =
+                CPLStrdup(CPLSPrintf("Error 404. Cannot find %s", pszURL));
+        }
+    }
+    else
+    {
+        if( bQuiet404Error )
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+        psResult = CPLHTTPFetch( pszURL, papszOptions);
+        if( bQuiet404Error )
+            CPLPopErrorHandler();
+    }
+    CSLDestroy(papszOptions);
+    
+    if( psResult->pszErrBuf != NULL )
+    {
+        if( !(bQuiet404Error && strstr(psResult->pszErrBuf, "404")) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "%s",
+                    psResult->pabyData ? (const char*) psResult->pabyData :
+                    psResult->pszErrBuf);
+        }
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    
+    if( psResult->pabyData == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+
+    return psResult;
+}
+
+/************************************************************************/
+/*                               RunRequest()                           */
+/************************************************************************/
+
+json_object* PLMosaicDataset::RunRequest(const char* pszURL,
+                                         int bQuiet404Error)
+{
+    CPLHTTPResult * psResult = Download(pszURL, bQuiet404Error);
+    if( psResult == NULL )
+    {
+        return NULL;
+    }
+
+    json_tokener* jstok = NULL;
+    json_object* poObj = NULL;
+
+    jstok = json_tokener_new();
+    poObj = json_tokener_parse_ex(jstok, (const char*) psResult->pabyData, -1);
+    if( jstok->err != json_tokener_success)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "JSON parsing error: %s (at offset %d)",
+                    json_tokener_error_desc(jstok->err), jstok->char_offset);
+        json_tokener_free(jstok);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    json_tokener_free(jstok);
+
+    CPLHTTPDestroyResult(psResult);
+
+    if( json_object_get_type(poObj) != json_type_object )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Return is not a JSON dictionary");
+        json_object_put(poObj);
+        poObj = NULL;
+    }
+    
+    return poObj;
+}
+
+/************************************************************************/
+/*                           PLMosaicGetParameter()                     */
+/************************************************************************/
+
+static CPLString PLMosaicGetParameter( GDALOpenInfo * poOpenInfo,
+                                       char** papszOptions,
+                                       const char* pszName,
+                                       const char* pszDefaultVal )
+{
+    return CSLFetchNameValueDef( papszOptions, pszName,
+        CSLFetchNameValueDef( poOpenInfo->papszOpenOptions, pszName,
+                              pszDefaultVal ));
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset *PLMosaicDataset::Open( GDALOpenInfo * poOpenInfo )
+
+{
+    if (!Identify(poOpenInfo) )
+        return NULL;
+
+    PLMosaicDataset* poDS = new PLMosaicDataset();
+
+    poDS->osBaseURL = CPLGetConfigOption("PL_URL", "https://api.planet.com/v0/mosaics/");
+    
+    char** papszOptions = CSLTokenizeStringComplex(
+            poOpenInfo->pszFilename+strlen("PLMosaic:"), ",", TRUE, FALSE );
+    for( char** papszIter = papszOptions; papszIter && *papszIter; papszIter ++ )
+    {
+        char* pszKey;
+        const char* pszValue = CPLParseNameValue(*papszIter, &pszKey);
+        if( pszValue != NULL )
+        {
+            if( !EQUAL(pszKey, "api_key") &&
+                !EQUAL(pszKey, "mosaic") &&
+                !EQUAL(pszKey, "cache_path") &&
+                !EQUAL(pszKey, "trust_cache") &&
+                !EQUAL(pszKey, "use_tiles") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported, "Unsupported option %s", pszKey);
+                CPLFree(pszKey);
+                delete poDS;
+                CSLDestroy(papszOptions);
+                return NULL;
+            }
+            CPLFree(pszKey);
+        }
+    }
+
+    poDS->osAPIKey = PLMosaicGetParameter(poOpenInfo, papszOptions, "api_key",
+                                          CPLGetConfigOption("PL_API_KEY",""));
+
+    if( poDS->osAPIKey.size() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Missing PL_API_KEY configuration option or API_KEY open option");
+        delete poDS;
+        CSLDestroy(papszOptions);
+        return NULL;
+    }
+
+    poDS->osMosaic = PLMosaicGetParameter(poOpenInfo, papszOptions, "mosaic", "");
+
+    poDS->osCachePathRoot = PLMosaicGetParameter(poOpenInfo, papszOptions, "cache_path",
+                                          CPLGetConfigOption("PL_CACHE_PATH",""));
+
+    poDS->bTrustCache = CSLTestBoolean(PLMosaicGetParameter(
+                        poOpenInfo, papszOptions, "trust_cache", "FALSE"));
+
+    poDS->bUseTMSForMain = CSLTestBoolean(PLMosaicGetParameter(
+                        poOpenInfo, papszOptions, "use_tiles", "FALSE"));
+
+    CSLDestroy(papszOptions);
+    papszOptions = NULL;
+
+    if( poDS->osMosaic.size() )
+    {
+        if( !poDS->OpenMosaic() )
+        {
+            delete poDS;
+            poDS = NULL;
+        }
+    }
+    else
+    {
+        if( !poDS->ListSubdatasets() )
+        {
+            delete poDS;
+            poDS = NULL;
+        }
+        else
+        {
+            char** papszMD = poDS->GetMetadata("SUBDATASETS");
+            if( CSLCount(papszMD) == 2 )
+            {
+                CPLString osOldFilename(poOpenInfo->pszFilename);
+                CPLString osMosaicConnectionString = CSLFetchNameValue(papszMD, "SUBDATASET_1_NAME");
+                delete poDS;
+                GDALOpenInfo oOpenInfo(osMosaicConnectionString.c_str(), GA_ReadOnly);
+                oOpenInfo.papszOpenOptions = poOpenInfo->papszOpenOptions;
+                poDS = (PLMosaicDataset*) Open(&oOpenInfo);
+                if( poDS )
+                    poDS->SetDescription(osOldFilename);
+            }
+        }
+    }
+    
+    if( poDS )
+        poDS->SetPamFlags(0);
+
+    return( poDS );
+}
+
+/************************************************************************/
+/*                           ReplaceSubString()                         */
+/************************************************************************/
+
+static void ReplaceSubString(CPLString &osTarget,
+                             CPLString osPattern,
+                             CPLString osReplacement)
+
+{
+    // assumes only one occurance of osPattern
+    size_t pos = osTarget.find(osPattern);
+    if( pos == CPLString::npos )
+        return;
+
+    osTarget.replace(pos, osPattern.size(), osReplacement); 
+}
+
+/************************************************************************/
+/*                            GetMosaicCachePath()                      */
+/************************************************************************/
+
+CPLString PLMosaicDataset::GetMosaicCachePath()
+{
+    if( osCachePathRoot.size() )
+    {
+        CPLString osCachePath(CPLFormFilename(osCachePathRoot, "plmosaic_cache", NULL));
+        CPLString osMosaicPath(CPLFormFilename(osCachePath, osMosaic, NULL));
+
+        return osMosaicPath;
+    }
+    return "";
+}
+
+/************************************************************************/
+/*                     CreateMosaicCachePathIfNecessary()               */
+/************************************************************************/
+
+void PLMosaicDataset::CreateMosaicCachePathIfNecessary()
+{
+    if( osCachePathRoot.size() )
+    {
+        CPLString osCachePath(CPLFormFilename(osCachePathRoot, "plmosaic_cache", NULL));
+        CPLString osMosaicPath(CPLFormFilename(osCachePath, osMosaic, NULL));
+
+        VSIStatBufL sStatBuf;
+        if( VSIStatL(osMosaicPath, &sStatBuf) != 0 )
+        {
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+            VSIMkdir(osCachePathRoot, 0755);
+            VSIMkdir(osCachePath, 0755);
+            VSIMkdir(osMosaicPath, 0755);
+            CPLPopErrorHandler();
+        }
+    }
+}
+
+/************************************************************************/
+/*                               OpenMosaic()                           */
+/************************************************************************/
+
+int PLMosaicDataset::OpenMosaic()
+{
+    CPLString osURL(osBaseURL);
+    if( osURL[osURL.size()-1] != '/' )
+        osURL += '/';
+    osURL += osMosaic;
+    json_object* poObj = RunRequest(osURL);
+    if( poObj == NULL )
+    {
+        return FALSE;
+    }
+
+    json_object* poCoordinateSystem = json_object_object_get(poObj, "coordinate_system");
+    json_object* poDataType = json_object_object_get(poObj, "datatype");
+    json_object* poQuadPattern = json_object_object_get(poObj, "quad_pattern");
+    json_object* poQuadSize = json_object_object_get(poObj, "quad_size");
+    json_object* poResolution = json_object_object_get(poObj, "resolution");
+    json_object* poLinks = json_object_object_get(poObj, "links");
+    json_object* poLinksQuads = NULL;
+    json_object* poLinksTiles = NULL;
+    if( poLinks != NULL && json_object_get_type(poLinks) == json_type_object )
+    {
+        poLinksQuads = json_object_object_get(poLinks, "quads");
+        poLinksTiles = json_object_object_get(poLinks, "tiles");
+    }
+    if( poCoordinateSystem == NULL || json_object_get_type(poCoordinateSystem) != json_type_string ||
+        poDataType == NULL || json_object_get_type(poDataType) != json_type_string ||
+        poQuadPattern == NULL || json_object_get_type(poQuadPattern) != json_type_string ||
+        poQuadSize == NULL || json_object_get_type(poQuadSize) != json_type_int ||
+        poResolution == NULL || (json_object_get_type(poResolution) != json_type_int &&
+                                 json_object_get_type(poResolution) != json_type_double) ||
+        poLinksQuads == NULL || json_object_get_type(poLinksQuads) != json_type_string )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Missing required parameter");
+        json_object_put(poObj);
+        return FALSE;
+    }
+    
+    const char* pszSRS = json_object_get_string(poCoordinateSystem);
+    if( !EQUAL(pszSRS, "EPSG:3857") )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported coordinate_system = %s",
+                 pszSRS);
+        json_object_put(poObj);
+        return FALSE;
+    }
+
+    OGRSpatialReference oSRS;
+    oSRS.SetFromUserInput(pszSRS);
+    oSRS.exportToWkt(&pszWKT);
+    
+    GDALDataType eDT = GDT_Unknown;
+    const char* pszDataType = json_object_get_string(poDataType);
+    if( EQUAL(pszDataType, "byte") )
+        eDT = GDT_Byte;
+    else if( EQUAL(pszDataType, "uint16") )
+        eDT = GDT_UInt16;
+    else if( EQUAL(pszDataType, "int16") )
+        eDT = GDT_Int16;
+    else
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported data_type = %s",
+                 pszDataType);
+        json_object_put(poObj);
+        return FALSE;
+    }
+    
+    if( bUseTMSForMain && eDT != GDT_Byte )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot use tile API for full resolution data on non Byte mosaic");
+        bUseTMSForMain = FALSE;
+    }
+
+    nQuadSize = json_object_get_int(poQuadSize);
+    if( nQuadSize <= 0 || (nQuadSize % 256) != 0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported quad_size = %d",
+                 nQuadSize);
+        json_object_put(poObj);
+        return FALSE;
+    }
+
+    double dfResolution = json_object_get_double(poResolution);
+    if( EQUAL(pszSRS, "EPSG:3857") )
+    {
+        double dfZoomLevel = log(GM_ZOOM_0 / dfResolution)/log(2.0);
+        nZoomLevel = (int)(dfZoomLevel + 0.1);
+        if( fabs(dfZoomLevel - nZoomLevel) > 1e-5 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported, "Unsupported resolution = %.12g",
+                    dfResolution);
+            json_object_put(poObj);
+            return FALSE;
+        }
+        bHasGeoTransform = TRUE;
+        adfGeoTransform[0] = GM_ORIGIN;
+        adfGeoTransform[1] = dfResolution;
+        adfGeoTransform[2] = 0;
+        adfGeoTransform[3] = -GM_ORIGIN;
+        adfGeoTransform[4] = 0;
+        adfGeoTransform[5] = -dfResolution;
+        nRasterXSize = (int)(2 * -GM_ORIGIN / dfResolution + 0.5);
+        nRasterYSize = nRasterXSize;
+    }
+    
+    const char* pszQuadPattern = json_object_get_string(poQuadPattern);
+    if( strstr(pszQuadPattern, "{tilex:") == NULL ||
+        strstr(pszQuadPattern, "{tiley:") == NULL )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "Invalid quad_pattern = %s",
+                 pszQuadPattern);
+        json_object_put(poObj);
+        return FALSE;
+    }
+    osQuadPattern = pszQuadPattern;
+    osQuadsURL = json_object_get_string(poLinksQuads);
+
+    // Use WMS/TMS driver for overviews (only for byte)
+    if( eDT == GDT_Byte && EQUAL(pszSRS, "EPSG:3857") &&
+        poLinksTiles != NULL && json_object_get_type(poLinksTiles) == json_type_string )
+    {
+        const char* pszLinksTiles = json_object_get_string(poLinksTiles);
+        if( strstr(pszLinksTiles, "{x}") == NULL || strstr(pszLinksTiles, "{y}") == NULL ||
+            strstr(pszLinksTiles, "{z}") == NULL )
+        {
+            CPLError(CE_Warning, CPLE_NotSupported, "Invalid links.tiles = %s",
+                     pszLinksTiles);
+        }
+        else
+        {
+            CPLString osCacheStr;
+            if( osCachePathRoot.size() )
+            {
+                osCacheStr = "    <Cache><Path>";
+                osCacheStr += GetMosaicCachePath();
+                osCacheStr += "</Path></Cache>\n";
+            }
+
+            CPLString osTMSURL(pszLinksTiles);
+            if( strncmp(pszLinksTiles, "https://", strlen("https://")) == 0 )
+            {
+                // Add API key as Basic auth
+                osTMSURL = "https://";
+                osTMSURL += osAPIKey;
+                osTMSURL += ":@";
+                osTMSURL += pszLinksTiles + strlen("https://");
+            }
+            ReplaceSubString(osTMSURL, "{x}", "${x}");
+            ReplaceSubString(osTMSURL, "{y}", "${y}");
+            ReplaceSubString(osTMSURL, "{z}", "${z}");
+            ReplaceSubString(osTMSURL, "{0-3}", "0");
+
+            CPLString osTMS = CPLSPrintf("<GDAL_WMS>\n"
+"    <Service name=\"TMS\">\n"
+"        <ServerUrl>%s</ServerUrl>\n"
+"    </Service>\n"
+"    <DataWindow>\n"
+"        <UpperLeftX>%.16g</UpperLeftX>\n"
+"        <UpperLeftY>%.16g</UpperLeftY>\n"
+"        <LowerRightX>%.16g</LowerRightX>\n"
+"        <LowerRightY>%.16g</LowerRightY>\n"
+"        <TileLevel>%d</TileLevel>\n"
+"        <TileCountX>1</TileCountX>\n"
+"        <TileCountY>1</TileCountY>\n"
+"        <YOrigin>top</YOrigin>\n"
+"    </DataWindow>\n"
+"    <Projection>%s</Projection>\n"
+"    <BlockSizeX>256</BlockSizeX>\n"
+"    <BlockSizeY>256</BlockSizeY>\n"
+"    <BandsCount>4</BandsCount>\n"
+"%s"
+"</GDAL_WMS>",
+                osTMSURL.c_str(),
+                adfGeoTransform[0],
+                adfGeoTransform[3],
+                adfGeoTransform[0] + nRasterXSize * adfGeoTransform[1],
+                adfGeoTransform[3] + nRasterYSize * adfGeoTransform[5],
+                nZoomLevel,
+                pszSRS,
+                osCacheStr.c_str());
+            //CPLDebug("PLMosaic", "TMS : %s", osTMS.c_str());
+
+            poTMSDS = (GDALDataset*)GDALOpenEx(osTMS, GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                               NULL, NULL, NULL);
+        }
+    }
+    
+    if( bUseTMSForMain && poTMSDS == NULL )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot find tile definition, so use_tiles will be ignored");
+        bUseTMSForMain = FALSE;
+    }
+
+    for(int i=0;i<4;i++)
+        SetBand(i + 1, new PLMosaicRasterBand(this, i + 1, eDT));
+
+    json_object* poFirstAcquired = json_object_object_get(poObj, "first_acquired");
+    if( poFirstAcquired != NULL && json_object_get_type(poFirstAcquired) == json_type_string )
+    {
+        SetMetadataItem("FIRST_ACQUIRED",
+                                 json_object_get_string(poFirstAcquired));
+    }
+    json_object* poLastAcquired = json_object_object_get(poObj, "last_acquired");
+    if( poLastAcquired != NULL && json_object_get_type(poLastAcquired) == json_type_string )
+    {
+        SetMetadataItem("LAST_ACQUIRED",
+                                 json_object_get_string(poLastAcquired));
+    }
+    json_object* poTitle = json_object_object_get(poObj, "title");
+    if( poTitle != NULL && json_object_get_type(poTitle) == json_type_string )
+    {
+        SetMetadataItem("TITLE", json_object_get_string(poTitle));
+    }
+
+    
+    json_object_put(poObj);
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          ListSubdatasets()                           */
+/************************************************************************/
+
+int PLMosaicDataset::ListSubdatasets()
+{
+    CPLString osURL(osBaseURL);
+    CPLStringList aosSubdatasets;
+    while(osURL.size())
+    {
+        json_object* poObj = RunRequest(osURL);
+        if( poObj == NULL )
+        {
+            return FALSE;
+        }
+
+        osURL = "";
+        json_object* poLinks = json_object_object_get(poObj, "links");
+        if( poLinks != NULL && json_object_get_type(poLinks) == json_type_object )
+        {
+            json_object* poNext = json_object_object_get(poLinks, "next");
+            if( poNext != NULL && json_object_get_type(poNext) == json_type_string )
+            {
+                osURL = json_object_get_string(poNext);
+            }
+        }
+
+        json_object* poMosaics = json_object_object_get(poObj, "mosaics");
+        if( poMosaics == NULL || json_object_get_type(poMosaics) != json_type_array )
+        {
+            json_object_put(poObj);
+            return FALSE;
+        }
+
+        int nMosaics = json_object_array_length(poMosaics);
+        for(int i=0;i< nMosaics;i++)
+        {
+            const char* pszName = NULL;
+            const char* pszTitle = NULL;
+            const char* pszSelf = NULL;
+            const char* pszCoordinateSystem = NULL;
+            json_object* poMosaic = json_object_array_get_idx(poMosaics, i);
+            if( poMosaic && json_object_get_type(poMosaic) == json_type_object )
+            {
+                json_object* poName = json_object_object_get(poMosaic, "name");
+                if( poName != NULL && json_object_get_type(poName) == json_type_string )
+                {
+                    pszName = json_object_get_string(poName);
+                }
+                json_object* poTitle = json_object_object_get(poMosaic, "title");
+                if( poTitle != NULL && json_object_get_type(poTitle) == json_type_string )
+                {
+                    pszTitle = json_object_get_string(poTitle);
+                }
+                poLinks = json_object_object_get(poMosaic, "links");
+                if( poLinks != NULL && json_object_get_type(poLinks) == json_type_object )
+                {
+                    json_object* poSelf = json_object_object_get(poLinks, "self");
+                    if( poSelf != NULL && json_object_get_type(poSelf) == json_type_string )
+                    {
+                        pszSelf = json_object_get_string(poSelf);
+                    }
+                }
+                json_object* poCoordinateSystem = json_object_object_get(poMosaic, "coordinate_system");
+                if( poCoordinateSystem && json_object_get_type(poCoordinateSystem) == json_type_string )
+                {
+                    pszCoordinateSystem = json_object_get_string(poCoordinateSystem);
+                }
+            }
+
+            if( pszName && pszSelf && pszCoordinateSystem &&
+                EQUAL(pszCoordinateSystem, "EPSG:3857") )
+            {
+                int nDatasetIdx = aosSubdatasets.Count() / 2 + 1;
+                aosSubdatasets.AddNameValue(
+                    CPLSPrintf("SUBDATASET_%d_NAME", nDatasetIdx),
+                    CPLSPrintf("PLMOSAIC:mosaic=%s", pszName));
+                if( pszTitle )
+                {
+                    aosSubdatasets.AddNameValue(
+                        CPLSPrintf("SUBDATASET_%d_DESC", nDatasetIdx),
+                        pszTitle);
+                }
+                else
+                {
+                    aosSubdatasets.AddNameValue(
+                        CPLSPrintf("SUBDATASET_%d_DESC", nDatasetIdx),
+                        CPLSPrintf("Mosaic %s", pszName));
+                }
+            }
+        }
+
+        json_object_put(poObj);
+    }
+    SetMetadata(aosSubdatasets.List(), "SUBDATASETS");
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            GetProjectionRef()                       */
+/************************************************************************/
+
+const char* PLMosaicDataset::GetProjectionRef()
+{
+    return (pszWKT) ? pszWKT : "";
+}
+
+/************************************************************************/
+/*                            GetGeoTransform()                         */
+/************************************************************************/
+
+CPLErr PLMosaicDataset::GetGeoTransform(double* padfGeoTransform)
+{
+    memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
+    return ( bHasGeoTransform ) ? CE_None : CE_Failure;
+}
+
+/************************************************************************/
+/*                          formatTileName()                            */
+/************************************************************************/
+
+CPLString PLMosaicDataset::formatTileName(int tile_x, int tile_y)
+
+{
+    CPLString result = osQuadPattern;
+    CPLString fragment;
+    size_t nPos;
+    int nDigits;
+
+    nPos = osQuadPattern.find("{tilex:");
+    nPos += strlen("{tilex:");
+    if( sscanf(osQuadPattern.c_str() + nPos, "0%dd}", &nDigits) != 1 ||
+        nDigits <= 0 || nDigits > 9 )
+        return result;
+    fragment.Printf(CPLSPrintf("%%0%dd", nDigits), tile_x);
+    ReplaceSubString(result, CPLSPrintf("{tilex:0%dd}", nDigits), fragment);
+
+    nPos = osQuadPattern.find("{tiley:");
+    nPos += strlen("{tiley:");
+    if( sscanf(osQuadPattern.c_str() + nPos, "0%dd}", &nDigits) != 1 ||
+        nDigits <= 0 || nDigits > 9 )
+        return result;
+    fragment.Printf(CPLSPrintf("%%0%dd", nDigits), tile_y);
+    ReplaceSubString(result, CPLSPrintf("{tiley:0%dd}", nDigits), fragment);
+
+    fragment.Printf("%d", nZoomLevel);
+    ReplaceSubString(result, "{glevel:d}", fragment);
+
+    return result;
+}
+
+/************************************************************************/
+/*                          InsertNewDataset()                          */
+/************************************************************************/
+
+void PLMosaicDataset::InsertNewDataset(CPLString osKey, GDALDataset* poDS)
+{
+    if( (int) oMapLinkedDatasets.size() == nCacheMaxSize )
+    {
+        CPLDebug("PLMOSAIC", "Discarding older entry %s from cache",
+                 psTail->osKey.c_str());
+        oMapLinkedDatasets.erase(psTail->osKey);
+        PLLinkedDataset* psNewTail = psTail->psPrev;
+        psNewTail->psNext = NULL;
+        if( psTail->poDS )
+            GDALClose( psTail->poDS );
+        delete psTail;
+        psTail = psNewTail;
+    }
+
+    PLLinkedDataset* psLinkedDataset = new PLLinkedDataset();
+    if( psHead )
+        psHead->psPrev = psLinkedDataset;
+    psLinkedDataset->osKey = osKey;
+    psLinkedDataset->psNext = psHead;
+    psLinkedDataset->poDS = poDS;
+    psHead = psLinkedDataset;
+    if( psTail == NULL )
+        psTail = psHead;
+    oMapLinkedDatasets[osKey] = psLinkedDataset;
+}
+
+/************************************************************************/
+/*                         OpenAndInsertNewDataset()                    */
+/************************************************************************/
+
+GDALDataset* PLMosaicDataset::OpenAndInsertNewDataset(CPLString osTmpFilename,
+                                                      CPLString osTilename)
+{
+    const char* const apszAllowedDrivers[2] = { "GTiff", NULL };
+    GDALDataset* poDS = (GDALDataset*)
+        GDALOpenEx(osTmpFilename, GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                            apszAllowedDrivers, NULL, NULL);
+    if( poDS != NULL )
+    {
+        if( poDS->GetRasterXSize() != nQuadSize ||
+            poDS->GetRasterYSize() != nQuadSize ||
+            poDS->GetRasterCount() != 4 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "Inconsistent metatile characteristics");
+            GDALClose(poDS);
+            poDS = NULL;
+        }
+    }
+    else
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid GTiff dataset: %s",
+                 osTilename.c_str());
+    }
+    
+    InsertNewDataset(osTilename, poDS);
+    return poDS;
+}
+
+/************************************************************************/
+/*                            GetMetaTile()                             */
+/************************************************************************/
+
+GDALDataset* PLMosaicDataset::GetMetaTile(int tile_x, int tile_y)
+{
+    CPLString osTilename = formatTileName(tile_x, tile_y);
+    std::map<CPLString,PLLinkedDataset*>::const_iterator it = 
+                                                    oMapLinkedDatasets.find(osTilename);
+    if( it == oMapLinkedDatasets.end() )
+    {
+        CPLString osTmpFilename;
+
+        CPLString osMosaicPath(GetMosaicCachePath());
+        osTmpFilename = CPLFormFilename(osMosaicPath,
+                CPLSPrintf("%s_%s.tif", osMosaic.c_str(), CPLGetFilename(osTilename)), NULL);
+        VSIStatBufL sStatBuf;
+        if( osCachePathRoot.size() && VSIStatL(osTmpFilename, &sStatBuf) == 0 )
+        {
+            if( bTrustCache )
+            {
+                return OpenAndInsertNewDataset(osTmpFilename, osTilename);
+            }
+
+            CPLDebug("PLMOSAIC", "File %s exists. Checking if it is up-to-date...",
+                     osTmpFilename.c_str());
+            // Fetch metatile metadata
+            json_object* poObj = RunRequest((osQuadsURL + osTilename).c_str());
+            if( poObj == NULL )
+            {
+                CPLDebug("PLMOSAIC", "Cannot get tile metadata");
+                InsertNewDataset(osTilename, NULL);
+                return NULL;
+            }
+
+            // Currently we only check by file size, which should be good enough
+            // as the metatiles are compressed, so a change in content is likely
+            // to cause a change in filesize. Use of a signature would be better
+            // though if available in the metadata
+            int nFileSize = 0;
+            json_object* poProperties = json_object_object_get(poObj, "properties");
+            if( poProperties && json_object_get_type(poProperties) == json_type_object )
+            {
+                json_object* poFileSize = json_object_object_get(poProperties, "file_size");
+                nFileSize = json_object_get_int(poFileSize);
+            }
+            json_object_put(poObj);
+            if( (int)sStatBuf.st_size == nFileSize )
+            {
+                CPLDebug("PLMOSAIC", "Cached tile is up-to-date");
+                return OpenAndInsertNewDataset(osTmpFilename, osTilename);
+            }
+            else
+            {
+                CPLDebug("PLMOSAIC", "Cached tile is not up-to-date");
+                VSIUnlink(osTmpFilename);
+            }
+        }
+
+        // Fetch the GeoTIFF now
+        CPLString osURL = osQuadsURL;
+        osURL += osTilename;
+        osURL += "/full";
+
+        CPLHTTPResult* psResult = Download(osURL, TRUE);
+        if( psResult == NULL )
+        {
+            InsertNewDataset(osTilename, NULL);
+            return NULL;
+        }
+
+        CreateMosaicCachePathIfNecessary();
+
+        VSILFILE* fp = osCachePathRoot.size() ? VSIFOpenL(osTmpFilename, "wb") : NULL;
+        if( fp )
+        {
+            VSIFWriteL(psResult->pabyData, 1, psResult->nDataLen, fp);
+            VSIFCloseL(fp);
+        }
+        else
+        {
+            // In case there's no temporary path or it is not writable
+            // use a in-memory dataset, and limit the cache to only one
+            if( osCachePathRoot.size() && nCacheMaxSize > 1 )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                         "Cannot write into %s. Using /vsimem and reduce cache to 1 entry",
+                         osCachePathRoot.c_str());
+                FlushDatasetsCache();
+                nCacheMaxSize = 1;
+            }
+            osTmpFilename =
+                CPLSPrintf("/vsimem/single_tile_plmosaic_cache/%s/%d_%d.tif",
+                           osMosaic.c_str(), tile_x, tile_y);
+            fp = VSIFOpenL(osTmpFilename, "wb");
+            if( fp )
+            {
+                VSIFWriteL(psResult->pabyData, 1, psResult->nDataLen, fp);
+                VSIFCloseL(fp);
+            }
+        }
+        CPLHTTPDestroyResult(psResult);
+        GDALDataset* poDS = OpenAndInsertNewDataset(osTmpFilename, osTilename);
+
+        if( strncmp(osTmpFilename, "/vsimem/single_tile_plmosaic_cache/",
+                    strlen("/vsimem/single_tile_plmosaic_cache/")) == 0 )
+            VSIUnlink(osTilename);
+
+        return poDS;
+    }
+
+    // Move link to head of MRU list
+    PLLinkedDataset* psLinkedDataset = it->second;
+    GDALDataset* poDS = psLinkedDataset->poDS;
+    if( psLinkedDataset != psHead )
+    {
+        if( psLinkedDataset == psTail )
+            psTail = psLinkedDataset->psPrev;
+        if( psLinkedDataset->psPrev )
+            psLinkedDataset->psPrev->psNext = psLinkedDataset->psNext;
+        if( psLinkedDataset->psNext )
+            psLinkedDataset->psNext->psPrev = psLinkedDataset->psPrev;
+        psLinkedDataset->psNext = psHead;
+        psLinkedDataset->psPrev = NULL;
+        psHead->psPrev = psLinkedDataset;
+        psHead = psLinkedDataset;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                       GetLocationInfo()                          */
+/************************************************************************/
+
+const char* PLMosaicDataset::GetLocationInfo(int nPixel, int nLine)
+{
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+
+    int nBlockXOff = nPixel / nBlockXSize;
+    int nBlockYOff = nLine / nBlockYSize;
+    int bottom_yblock = (nRasterYSize - nBlockYOff * nBlockYSize) / nBlockYSize - 1;
+
+    int meta_tile_x = (nBlockXOff * nBlockXSize) / nQuadSize;
+    int meta_tile_y = (bottom_yblock * nBlockYSize) / nQuadSize;
+
+    CPLString osQuadURL = osQuadsURL;
+    CPLString osTilename = formatTileName(meta_tile_x, meta_tile_y);
+    osQuadURL += osTilename;
+
+    if( meta_tile_x != nLastMetaTileX || meta_tile_y != nLastMetaTileY )
+    {
+        CPLHTTPResult* psResult;
+        psResult = Download(osQuadURL, TRUE);
+        if( psResult )
+            osLastQuadInformation = (const char*) psResult->pabyData;
+        else
+            osLastQuadInformation = "";
+        CPLHTTPDestroyResult(psResult);
+
+        CPLString osQuadScenesURL = osQuadURL + "/scenes/";
+
+        psResult = Download(osQuadScenesURL, TRUE);
+        if( psResult )
+            osLastQuadSceneInformation = (const char*) psResult->pabyData;
+        else
+            osLastQuadSceneInformation = "";
+        CPLHTTPDestroyResult(psResult);
+
+        nLastMetaTileX = meta_tile_x;
+        nLastMetaTileY = meta_tile_y;
+    }
+
+    osLastRetGetLocationInfo = "";
+
+    CPLXMLNode* psRoot = CPLCreateXMLNode(NULL, CXT_Element, "LocationInfo");
+
+    if( osLastQuadInformation.size() )
+    {
+        const char* const apszAllowedDrivers[2] = { "GeoJSON", NULL };
+        const char* const apszOptions[2] = { "FLATTEN_NESTED_ATTRIBUTES=YES", NULL };
+        CPLString osTmpJSonFilename;
+        osTmpJSonFilename.Printf("/vsimem/plmosaic/%p/quad.json", this);
+        VSIFCloseL(VSIFileFromMemBuffer(osTmpJSonFilename,
+                                        (GByte*)osLastQuadInformation.c_str(),
+                                        osLastQuadInformation.size(), FALSE));
+        GDALDataset* poDS = (GDALDataset*) GDALOpenEx(osTmpJSonFilename, GDAL_OF_VECTOR,
+                                                    apszAllowedDrivers, apszOptions, NULL);
+        VSIUnlink(osTmpJSonFilename);
+
+        if( poDS )
+        {
+            CPLXMLNode* psQuad = CPLCreateXMLNode(psRoot, CXT_Element, "Quad");
+            OGRLayer* poLayer = poDS->GetLayer(0);
+            OGRFeature* poFeat;
+            while( (poFeat = poLayer->GetNextFeature()) != NULL )
+            {
+                for(int i=0;i<poFeat->GetFieldCount();i++)
+                {
+                    if( poFeat->IsFieldSet(i) )
+                    {
+                        CPLXMLNode* psItem = CPLCreateXMLNode(psQuad,
+                            CXT_Element, poFeat->GetFieldDefnRef(i)->GetNameRef());
+                        CPLCreateXMLNode(psItem, CXT_Text, poFeat->GetFieldAsString(i));
+                    }
+                }
+                OGRGeometry* poGeom = poFeat->GetGeometryRef();
+                if( poGeom )
+                {
+                    CPLXMLNode* psItem = CPLCreateXMLNode(psQuad, CXT_Element, "geometry");
+                    char* pszWKT = NULL;
+                    poGeom->exportToWkt(&pszWKT);
+                    CPLCreateXMLNode(psItem, CXT_Text, pszWKT);
+                    CPLFree(pszWKT);
+                }
+                delete poFeat;
+            }
+
+            GDALClose(poDS);
+        }
+    }
+
+    if( osLastQuadSceneInformation.size() && pszWKT != NULL )
+    {
+        const char* const apszAllowedDrivers[2] = { "GeoJSON", NULL };
+        const char* const apszOptions[2] = { "FLATTEN_NESTED_ATTRIBUTES=YES", NULL };
+        CPLString osTmpJSonFilename;
+        osTmpJSonFilename.Printf("/vsimem/plmosaic/%p/scenes.json", this);
+        VSIFCloseL(VSIFileFromMemBuffer(osTmpJSonFilename,
+                                        (GByte*)osLastQuadSceneInformation.c_str(),
+                                        osLastQuadSceneInformation.size(), FALSE));
+        GDALDataset* poDS = (GDALDataset*) GDALOpenEx(osTmpJSonFilename, GDAL_OF_VECTOR,
+                                                    apszAllowedDrivers, apszOptions, NULL);
+        VSIUnlink(osTmpJSonFilename);
+
+        OGRSpatialReference oSRSSrc, oSRSDst;
+        oSRSSrc.SetFromUserInput(pszWKT);
+        oSRSDst.importFromEPSG(4326);
+        OGRCoordinateTransformation* poCT = OGRCreateCoordinateTransformation(&oSRSSrc,
+                                                                            &oSRSDst);
+        double x = adfGeoTransform[0] + nPixel * adfGeoTransform[1];
+        double y = adfGeoTransform[3] + nLine * adfGeoTransform[5];
+        if( poDS && poCT && poCT->Transform(1, &x, &y))
+        {
+            CPLXMLNode* psScenes = NULL;
+            OGRLayer* poLayer = poDS->GetLayer(0);
+            poLayer->SetSpatialFilterRect(x,y,x,y);
+            OGRFeature* poFeat;
+            while( (poFeat = poLayer->GetNextFeature()) != NULL )
+            {
+                OGRGeometry* poGeom = poFeat->GetGeometryRef();
+                if( poGeom )
+                {
+                    if( psScenes == NULL )
+                        psScenes = CPLCreateXMLNode(psRoot, CXT_Element, "Scenes");
+                    CPLXMLNode* psScene = CPLCreateXMLNode(psScenes, CXT_Element, "Scene");
+                    for(int i=0;i<poFeat->GetFieldCount();i++)
+                    {
+                        if( poFeat->IsFieldSet(i) )
+                        {
+                            CPLXMLNode* psItem = CPLCreateXMLNode(psScene,
+                                CXT_Element, poFeat->GetFieldDefnRef(i)->GetNameRef());
+                            CPLCreateXMLNode(psItem, CXT_Text, poFeat->GetFieldAsString(i));
+                        }
+                    }
+                    CPLXMLNode* psItem = CPLCreateXMLNode(psScene, CXT_Element, "geometry");
+                    char* pszWKT = NULL;
+                    poGeom->exportToWkt(&pszWKT);
+                    CPLCreateXMLNode(psItem, CXT_Text, pszWKT);
+                    CPLFree(pszWKT);
+                }
+                delete poFeat;
+            }
+        }
+        delete poCT;
+        if( poDS )
+            GDALClose(poDS);
+    }
+
+    char* pszXML = CPLSerializeXMLTree(psRoot);
+    CPLDestroyXMLNode(psRoot);
+    osLastRetGetLocationInfo = pszXML;
+    CPLFree(pszXML);
+
+    return osLastRetGetLocationInfo.c_str();
+}
+
+/************************************************************************/
+/*                             IRasterIO()                              */
+/************************************************************************/
+
+CPLErr  PLMosaicDataset::IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
+{
+    if( bUseTMSForMain && poTMSDS )
+        return poTMSDS->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+                                  pData, nBufXSize, nBufYSize,
+                                  eBufType, nBandCount, panBandMap,
+                                  nPixelSpace, nLineSpace, nBandSpace,
+                                  psExtraArg );
+
+    return BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+                               pData, nBufXSize, nBufYSize,
+                               eBufType, nBandCount, panBandMap,
+                               nPixelSpace, nLineSpace, nBandSpace,
+                               psExtraArg );
+}
+
+/************************************************************************/
+/*                      GDALRegister_PLMOSAIC()                         */
+/************************************************************************/
+
+void GDALRegister_PLMOSAIC()
+
+{
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "PLMOSAIC" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+        
+        poDriver->SetDescription( "PLMOSAIC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
+                                   "Planet Labs Mosaics API" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
+                                   "frmt_plmosaic.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "PLMOSAIC:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, 
+"<OpenOptionList>"
+"  <Option name='API_KEY' type='string' description='Account API key' required='true'/>"
+"  <Option name='MOSAIC' type='string' description='Mosaic name'/>"
+"  <Option name='CACHE_PATH' type='string' description='Directory where to put cached quads'/>"
+"  <Option name='TRUST_CACHE' type='boolean' description='Whether already cached quads should be trusted as the most recent version' default='NO'/>"
+"  <Option name='USE_TILES' type='boolean' description='Whether to use the tile API even for full resolution data (only for Byte mosaics)' default='NO'/>"
+"</OpenOptionList>" );
+
+        poDriver->pfnIdentify = PLMosaicDataset::Identify;
+        poDriver->pfnOpen = PLMosaicDataset::Open;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/frmts/png/GNUmakefile b/frmts/png/GNUmakefile
index 4ad3a47..f39c869 100644
--- a/frmts/png/GNUmakefile
+++ b/frmts/png/GNUmakefile
@@ -1,4 +1,4 @@
-# $Id: GNUmakefile 16755 2009-04-09 20:38:33Z chaitanya $
+# $Id: GNUmakefile 27976 2014-11-17 13:13:44Z rouault $
 #
 # Makefile to build libpng using GNU Make and GCC.
 #
@@ -35,7 +35,7 @@ ifeq ($(LIBZ_SETTING),internal)
 XTRA_OPT	:=	$(XTRA_OPT) -I../zlib
 endif
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/png/libpng/README b/frmts/png/libpng/README
index 3a29d60..771ca50 100644
--- a/frmts/png/libpng/README
+++ b/frmts/png/libpng/README
@@ -4,7 +4,7 @@ $Id$
 Updating libpng in GDAL tree should follow update of zlib library in frmts/zlib.
 *****************
 
-libpng 1.2.50 is the official PNG reference library.
+libpng 1.2.52 is the official PNG reference library.
 It supports almost all PNG features, is extensible,
 and has been extensively tested for over 15 years.
 
diff --git a/frmts/png/libpng/png.c b/frmts/png/libpng/png.c
index 18d26db..2ebb6f7 100644
--- a/frmts/png/libpng/png.c
+++ b/frmts/png/libpng/png.c
@@ -1,8 +1,8 @@
 
 /* png.c - location for general purpose libpng functions
  *
- * Last changed in libpng 1.2.46 [February 25, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -17,7 +17,7 @@
 #include "png.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef version_1_2_50 Your_png_h_is_not_version_1_2_50;
+typedef version_1_2_52 Your_png_h_is_not_version_1_2_52;
 
 /* Version information for C files.  This had better match the version
  * string defined in png.h.
@@ -718,20 +718,20 @@ png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
 png_charp PNGAPI
 png_get_copyright(png_structp png_ptr)
 {
-   png_ptr = png_ptr;  /* Silence compiler warning about unused png_ptr */
+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
 #ifdef PNG_STRING_COPYRIGHT
       return PNG_STRING_COPYRIGHT
 #else
 #ifdef __STDC__
    return ((png_charp) PNG_STRING_NEWLINE \
-     "libpng version 1.2.50 - July 10, 2012" PNG_STRING_NEWLINE \
-     "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
+     "libpng version 1.2.52 - November 20, 2014" PNG_STRING_NEWLINE \
+     "Copyright (c) 1998-2014 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
      "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
      "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
      PNG_STRING_NEWLINE);
 #else
-      return ((png_charp) "libpng version 1.2.50 - July 10, 2012\
-      Copyright (c) 1998-2011 Glenn Randers-Pehrson\
+      return ((png_charp) "libpng version 1.2.52 - November 20, 2014\
+      Copyright (c) 1998-2014 Glenn Randers-Pehrson\
       Copyright (c) 1996-1997 Andreas Dilger\
       Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.");
 #endif
@@ -750,7 +750,7 @@ png_charp PNGAPI
 png_get_libpng_ver(png_structp png_ptr)
 {
    /* Version of *.c files used when building libpng */
-   png_ptr = png_ptr;  /* Silence compiler warning about unused png_ptr */
+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
    return ((png_charp) PNG_LIBPNG_VER_STRING);
 }
 
@@ -758,7 +758,7 @@ png_charp PNGAPI
 png_get_header_ver(png_structp png_ptr)
 {
    /* Version of *.h files used when building libpng */
-   png_ptr = png_ptr;  /* Silence compiler warning about unused png_ptr */
+   PNG_UNUSED(png_ptr)  /* Silence compiler warning about unused png_ptr */
    return ((png_charp) PNG_LIBPNG_VER_STRING);
 }
 
@@ -766,7 +766,7 @@ png_charp PNGAPI
 png_get_header_version(png_structp png_ptr)
 {
    /* Returns longer string containing both version and date */
-   png_ptr = png_ptr;  /* Silence compiler warning about unused png_ptr */
+   PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */
 #ifdef __STDC__
    return ((png_charp) PNG_HEADER_VERSION_STRING
 #ifndef PNG_READ_SUPPORTED
@@ -1009,14 +1009,6 @@ png_check_IHDR(png_structp png_ptr,
       error = 1;
    }
 
-   if ( width > (PNG_UINT_32_MAX
-                 >> 3)      /* 8-byte RGBA pixels */
-                 - 64       /* bigrowbuf hack */
-                 - 1        /* filter byte */
-                 - 7*8      /* rounding of width to multiple of 8 pixels */
-                 - 8)       /* extra max_pixel_depth pad */
-      png_warning(png_ptr, "Width is too large for libpng to process pixels");
-
    /* Check other values */
    if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
        bit_depth != 8 && bit_depth != 16)
diff --git a/frmts/png/libpng/png.h b/frmts/png/libpng/png.h
index 3560969..ed9e429 100644
--- a/frmts/png/libpng/png.h
+++ b/frmts/png/libpng/png.h
@@ -1,7 +1,7 @@
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.2.50 - July 10, 2012
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * libpng version 1.2.52 - November 20, 2014
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -10,7 +10,7 @@
  * Authors and maintainers:
  *  libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
  *  libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- *  libpng versions 0.97, January 1998, through 1.2.50 - July 10, 2012: Glenn
+ *  libpng versions 0.97, January 1998, through 1.2.52 - November 20, 2014: Glenn
  *  See also "Contributing Authors", below.
  *
  * Note about libpng version numbers:
@@ -284,6 +284,14 @@
  *    1.2.49                  13    10249  12.so.0.49[.0]
  *    1.0.60                  10    10060  10.so.0.60[.0]
  *    1.2.50                  13    10250  12.so.0.50[.0]
+ *    1.2.51beta01-05         13    10251  12.so.0.51[.0]
+ *    1.2.51rc01-04           13    10251  12.so.0.51[.0]
+ *    1.0.61                  10    10061  10.so.0.61[.0]
+ *    1.2.51                  13    10251  12.so.0.51[.0]
+ *    1.2.52beta01            13    10252  12.so.0.52[.0]
+ *    1.2.52rc01-02           13    10252  12.so.0.52[.0]
+ *    1.0.62                  10    10062  10.so.0.62[.0]
+ *    1.2.52                  13    10252  12.so.0.52[.0]
  *
  *    Henceforth the source version will match the shared-library major
  *    and minor numbers; the shared-library major version number will be
@@ -315,8 +323,8 @@
  *
  * This code is released under the libpng license.
  *
- * libpng versions 1.2.6, August 15, 2004, through 1.2.50, July 10, 2012, are
- * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
+ * libpng versions 1.2.6, August 15, 2004, through 1.2.52, November 20, 2014, are
+ * Copyright (c) 2004, 2006-2013 Glenn Randers-Pehrson, and are
  * distributed according to the same disclaimer and license as libpng-1.2.5
  * with the following individual added to the list of Contributing Authors:
  *
@@ -427,13 +435,13 @@
  * Y2K compliance in libpng:
  * =========================
  *
- *    July 10, 2012
+ *    November 20, 2014
  *
  *    Since the PNG Development group is an ad-hoc body, we can't make
  *    an official declaration.
  *
  *    This is your unofficial assurance that libpng from version 0.71 and
- *    upward through 1.2.50 are Y2K compliant.  It is my belief that earlier
+ *    upward through 1.2.52 are Y2K compliant.  It is my belief that earlier
  *    versions were also Y2K compliant.
  *
  *    Libpng only has three year fields.  One is a 2-byte unsigned integer
@@ -489,9 +497,9 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.2.50"
+#define PNG_LIBPNG_VER_STRING "1.2.52"
 #define PNG_HEADER_VERSION_STRING \
-   " libpng version 1.2.50 - July 10, 2012\n"
+   " libpng version 1.2.52 - November 20, 2014\n"
 
 #define PNG_LIBPNG_VER_SONUM   0
 #define PNG_LIBPNG_VER_DLLNUM  13
@@ -499,7 +507,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   2
-#define PNG_LIBPNG_VER_RELEASE 50
+#define PNG_LIBPNG_VER_RELEASE 52
 /* This should match the numeric part of the final component of
  * PNG_LIBPNG_VER_STRING, omitting any leading zero:
  */
@@ -529,7 +537,7 @@
  * version 1.0.0 was mis-numbered 100 instead of 10000).  From
  * version 1.0.1 it's    xxyyzz, where x=major, y=minor, z=release
  */
-#define PNG_LIBPNG_VER 10250 /* 1.2.50 */
+#define PNG_LIBPNG_VER 10252 /* 1.2.52 */
 
 #ifndef PNG_VERSION_INFO_ONLY
 /* Include the compression library's header */
@@ -1569,7 +1577,7 @@ struct png_struct_def
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef png_structp version_1_2_50;
+typedef png_structp version_1_2_52;
 
 typedef png_struct FAR * FAR * png_structpp;
 
@@ -2656,7 +2664,7 @@ extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
 #      define png_debug(l,m) \
        { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
          (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
        }
 #    endif
@@ -2664,7 +2672,7 @@ extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
 #      define png_debug1(l,m,p1) \
        { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
          (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
        }
 #    endif
@@ -2672,7 +2680,7 @@ extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
 #      define png_debug2(l,m,p1,p2) \
        { \
        int num_tabs=l; \
-       fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
+       fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
          (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
        }
 #    endif
diff --git a/frmts/png/libpng/pngconf.h b/frmts/png/libpng/pngconf.h
index 042a5e9..008142e 100644
--- a/frmts/png/libpng/pngconf.h
+++ b/frmts/png/libpng/pngconf.h
@@ -1,8 +1,8 @@
 
 /* pngconf.h - machine configurable file for libpng
  *
- * libpng version 1.2.50 - July 10, 2012
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * libpng version 1.2.52 - November 20, 2014
+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -86,6 +86,18 @@
 #endif
 /* End of material added at libpng-1.2.19/1.2.21 */
 
+/* Added at libpng-1.2.51 (ported from 1.4.6) */
+#ifndef PNG_UNUSED
+/* Unused formal parameter warnings are silenced using the following macro
+ * which is expected to have no bad effects on performance (optimizing
+ * compilers will probably remove it entirely).  Note that if you replace
+ * it with something other than whitespace, you must include the terminating
+ * semicolon.
+ */
+#  define PNG_UNUSED(param) (void)param;
+#endif
+/* End of material added to libpng-1.4.6 */
+
 /* This is the size of the compression buffer, and thus the size of
  * an IDAT chunk.  Make this whatever size you feel is best for your
  * machine.  One of these will be allocated per png_struct.  When this
@@ -868,7 +880,7 @@
  * how large, set these two limits to 0.
  */
 #ifndef PNG_USER_CHUNK_CACHE_MAX
-#  define PNG_USER_CHUNK_CACHE_MAX 0
+#  define PNG_USER_CHUNK_CACHE_MAX 32765
 #endif
 
 /* Added at libpng-1.2.43 */
diff --git a/frmts/png/libpng/pngerror.c b/frmts/png/libpng/pngerror.c
index 025d52e..d8e7928 100644
--- a/frmts/png/libpng/pngerror.c
+++ b/frmts/png/libpng/pngerror.c
@@ -1,8 +1,8 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
  *
- * Last changed in libpng 1.2.45 [July 7, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -300,7 +300,7 @@ png_default_error(png_structp png_ptr, png_const_charp error_message)
    /* Here if not setjmp support or if png_ptr is null. */
    PNG_ABORT();
 #ifndef PNG_CONSOLE_IO_SUPPORTED
-   error_message = error_message; /* Make compiler happy */
+   PNG_UNUSED(error_message) /* Make compiler happy */
 #endif
 }
 
@@ -346,9 +346,9 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message)
      fprintf(stderr, PNG_STRING_NEWLINE);
    }
 #else
-   warning_message = warning_message; /* Make compiler happy */
+   PNG_UNUSED(warning_message) /* Make compiler happy */
 #endif
-   png_ptr = png_ptr; /* Make compiler happy */
+   PNG_UNUSED(png_ptr) /* Make compiler happy */
 }
 #endif /* PNG_WARNINGS_SUPPORTED */
 
diff --git a/frmts/png/libpng/pngget.c b/frmts/png/libpng/pngget.c
index d397329..c5d6543 100644
--- a/frmts/png/libpng/pngget.c
+++ b/frmts/png/libpng/pngget.c
@@ -1,8 +1,8 @@
 
 /* pngget.c - retrieval of values from info struct
  *
- * Last changed in libpng 1.2.43 [February 25, 2010]
- * Copyright (c) 1998-2010 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -893,7 +893,7 @@ png_uint_32 PNGAPI
 png_get_asm_flagmask (int flag_select)
 {
     /* Obsolete, to be removed from libpng-1.4.0 */
-    flag_select=flag_select;
+    PNG_UNUSED(flag_select)
     return 0L;
 }
 
@@ -903,7 +903,7 @@ png_uint_32 PNGAPI
 png_get_mmx_flagmask (int flag_select, int *compilerID)
 {
     /* Obsolete, to be removed from libpng-1.4.0 */
-    flag_select=flag_select;
+    PNG_UNUSED(flag_select)
     *compilerID = -1;   /* unknown (i.e., no asm/MMX code compiled) */
     return 0L;
 }
diff --git a/frmts/png/libpng/pngread.c b/frmts/png/libpng/pngread.c
index 69ee464..24277b1 100644
--- a/frmts/png/libpng/pngread.c
+++ b/frmts/png/libpng/pngread.c
@@ -1,8 +1,8 @@
 
 /* pngread.c - read a PNG file
  *
- * Last changed in libpng 1.2.48 [March 8, 2012]
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.52 [November 20, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -100,16 +100,22 @@ png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
 
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   if (user_png_ver)
+   if (user_png_ver != NULL)
    {
-      i = 0;
+      int found_dots = 0;
+      i = -1;
+
       do
       {
-         if (user_png_ver[i] != png_libpng_ver[i])
+         i++;
+         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
             png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-      } while (png_libpng_ver[i++]);
-    }
-    else
+         if (user_png_ver[i] == '.')
+            found_dots++;
+      } while (found_dots < 2 && user_png_ver[i] != 0 &&
+            PNG_LIBPNG_VER_STRING[i] != 0);
+   }
+   else
          png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
 
 
@@ -1405,7 +1411,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
    if (transforms & PNG_TRANSFORM_EXPAND)
       if ((png_ptr->bit_depth < 8) ||
           (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
-          (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+          (info_ptr->valid & PNG_INFO_tRNS))
          png_set_expand(png_ptr);
 #endif
 
@@ -1424,14 +1430,8 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
     * [0,65535] to the original [0,7] or [0,31], or whatever range the
     * colors were originally in:
     */
-   if ((transforms & PNG_TRANSFORM_SHIFT)
-       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
-   {
-      png_color_8p sig_bit;
-
-      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
-      png_set_shift(png_ptr, sig_bit);
-   }
+   if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT))
+      png_set_shift(png_ptr, &info_ptr->sig_bit);
 #endif
 
 #ifdef PNG_READ_BGR_SUPPORTED
@@ -1506,8 +1506,8 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
    /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);
 
-   transforms = transforms; /* Quiet compiler warnings */
-   params = params;
+   PNG_UNUSED(transforms) /* Quiet compiler warnings */
+   PNG_UNUSED(params)
 
 }
 #endif /* PNG_INFO_IMAGE_SUPPORTED */
diff --git a/frmts/png/libpng/pngrtran.c b/frmts/png/libpng/pngrtran.c
index 7f0ff92..0a760ce 100644
--- a/frmts/png/libpng/pngrtran.c
+++ b/frmts/png/libpng/pngrtran.c
@@ -1,8 +1,8 @@
 
 /* pngrtran.c - transforms the data in a row for PNG readers
  *
- * Last changed in libpng 1.2.49 [March 29, 2012]
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -917,7 +917,10 @@ png_init_read_transformations(png_structp png_ptr)
     for (i=0; i<png_ptr->num_trans; i++)
     {
       if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
+      {
         k=1; /* Partial transparency is present */
+        break;
+      }
     }
     if (k == 0)
       png_ptr->transformations &= ~PNG_GAMMA;
@@ -1376,6 +1379,9 @@ png_do_read_transformations(png_structp png_ptr)
    {
       if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
       {
+         if (png_ptr->palette == NULL)
+            png_error (png_ptr, "Palette is NULL in indexed image");
+
          png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
             png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
       }
diff --git a/frmts/png/libpng/pngrutil.c b/frmts/png/libpng/pngrutil.c
index 6164f28..707bc1b 100644
--- a/frmts/png/libpng/pngrutil.c
+++ b/frmts/png/libpng/pngrutil.c
@@ -1,8 +1,8 @@
 
 /* pngrutil.c - utilities to read a PNG file
  *
- * Last changed in libpng 1.2.48 [March 8, 2012]
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -659,7 +659,7 @@ png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    }
    png_crc_finish(png_ptr, length);
 
-   info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
+   PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
 }
 
 #ifdef PNG_READ_gAMA_SUPPORTED
@@ -2466,7 +2466,7 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
    png_crc_finish(png_ptr, skip);
 
 #ifndef PNG_READ_USER_CHUNKS_SUPPORTED
-   info_ptr = info_ptr; /* Quiet compiler warnings about unused info_ptr */
+   PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */
 #endif
 }
 
@@ -2923,7 +2923,7 @@ png_do_read_interlace(png_structp png_ptr)
       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width);
    }
 #ifndef PNG_READ_PACKSWAP_SUPPORTED
-   transformations = transformations; /* Silence compiler warning */
+   PNG_UNUSED(transformations) /* Silence compiler warning */
 #endif
 }
 #endif /* PNG_READ_INTERLACING_SUPPORTED */
diff --git a/frmts/png/libpng/pngset.c b/frmts/png/libpng/pngset.c
index 72d89fc..fed6a55 100644
--- a/frmts/png/libpng/pngset.c
+++ b/frmts/png/libpng/pngset.c
@@ -1,8 +1,8 @@
 
 /* pngset.c - storage of image information into info struct
  *
- * Last changed in libpng 1.2.49 [March 29, 2012]
- * Copyright (c) 1998-2012 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.51 [February 6, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -533,9 +533,11 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
 #ifdef PNG_FLOATING_POINT_SUPPORTED
    float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
 #endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
    png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
       int_green_y, int_blue_x, int_blue_y;
 #endif
+#endif
    png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
 
    if (png_ptr == NULL || info_ptr == NULL)
@@ -555,6 +557,7 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
 #endif
 
 #ifdef PNG_cHRM_SUPPORTED
+#  ifdef PNG_FIXED_POINT_SUPPORTED
    int_white_x = 31270L;
    int_white_y = 32900L;
    int_red_x   = 64000L;
@@ -563,8 +566,12 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
    int_green_y = 60000L;
    int_blue_x  = 15000L;
    int_blue_y  =  6000L;
+   png_set_cHRM_fixed(png_ptr, info_ptr,
+       int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
+       int_green_y, int_blue_x, int_blue_y);
+#  endif
 
-#ifdef PNG_FLOATING_POINT_SUPPORTED
+#  ifdef PNG_FLOATING_POINT_SUPPORTED
    white_x = (float).3127;
    white_y = (float).3290;
    red_x   = (float).64;
@@ -573,17 +580,9 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
    green_y = (float).60;
    blue_x  = (float).15;
    blue_y  = (float).06;
-#endif
-
-#ifdef PNG_FIXED_POINT_SUPPORTED
-   png_set_cHRM_fixed(png_ptr, info_ptr,
-       int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
-       int_green_y, int_blue_x, int_blue_y);
-#endif
-#ifdef PNG_FLOATING_POINT_SUPPORTED
    png_set_cHRM(png_ptr, info_ptr,
        white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
-#endif
+#  endif
 #endif /* cHRM */
 }
 #endif /* sRGB */
@@ -850,6 +849,12 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
    if (png_ptr == NULL || info_ptr == NULL)
       return;
 
+   if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH)
+      {
+        png_warning(png_ptr, "Ignoring invalid num_trans value");
+        return;
+      }
+
    if (trans != NULL)
    {
        /* It may not actually be necessary to set png_ptr->trans here;
@@ -1184,7 +1189,7 @@ png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags)
 /* Obsolete as of libpng-1.2.20 and will be removed from libpng-1.4.0 */
     if (png_ptr != NULL)
     png_ptr->asm_flags = 0;
-    asm_flags = asm_flags; /* Quiet the compiler */
+    PNG_UNUSED(asm_flags) /* Quiet the compiler */
 }
 
 /* This function was added to libpng 1.2.0 */
@@ -1197,8 +1202,8 @@ png_set_mmx_thresholds (png_structp png_ptr,
     if (png_ptr == NULL)
        return;
     /* Quiet the compiler */
-    mmx_bitdepth_threshold = mmx_bitdepth_threshold;
-    mmx_rowbytes_threshold = mmx_rowbytes_threshold;
+    PNG_UNUSED(mmx_bitdepth_threshold)
+    PNG_UNUSED(mmx_rowbytes_threshold)
 }
 #endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
 
diff --git a/frmts/png/libpng/pngwrite.c b/frmts/png/libpng/pngwrite.c
index 1d8c53f..894a984 100644
--- a/frmts/png/libpng/pngwrite.c
+++ b/frmts/png/libpng/pngwrite.c
@@ -1,8 +1,8 @@
 
 /* pngwrite.c - general routines to write a PNG file
  *
- * Last changed in libpng 1.2.45 [July 7, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.2.52 [November 20, 2014]
+ * Copyright (c) 1998-2014 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
@@ -525,15 +525,23 @@ png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
 #endif /* PNG_USER_MEM_SUPPORTED */
    png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
 
-   if (user_png_ver)
+   if (user_png_ver != NULL)
    {
-      i = 0;
+      int found_dots = 0;
+      i = -1;
+
       do
       {
-         if (user_png_ver[i] != png_libpng_ver[i])
+         i++;
+         if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
             png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
-      } while (png_libpng_ver[i++]);
+         if (user_png_ver[i] == '.')
+            found_dots++;
+      } while (found_dots < 2 && user_png_ver[i] != 0 &&
+            PNG_LIBPNG_VER_STRING[i] != 0);
    }
+   else
+      png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
 
    if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
    {
@@ -684,8 +692,9 @@ png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
          png_warning(png_ptr,
  "Application uses deprecated png_write_init() and should be recompiled.");
 #endif
-      }
-   } while (png_libpng_ver[i++]);
+   }
+      i++;
+   } while (png_libpng_ver[i] != 0 && user_png_ver[i] != 0);
 
    png_debug(1, "in png_write_init_3");
 
@@ -1586,8 +1595,8 @@ png_write_png(png_structp png_ptr, png_infop info_ptr,
    /* It is REQUIRED to call this to finish writing the rest of the file */
    png_write_end(png_ptr, info_ptr);
 
-   transforms = transforms; /* Quiet compiler warnings */
-   params = params;
+   PNG_UNUSED(transforms) /* Quiet compiler warnings */
+   PNG_UNUSED(params)
 }
 #endif
 #endif /* PNG_WRITE_SUPPORTED */
diff --git a/frmts/png/pngdataset.cpp b/frmts/png/pngdataset.cpp
index c36190e..c44a53a 100644
--- a/frmts/png/pngdataset.cpp
+++ b/frmts/png/pngdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pngdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: pngdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  PNG Driver
  * Purpose:  Implement GDAL PNG Support
@@ -50,7 +50,7 @@
 #include "cpl_string.h"
 #include <setjmp.h>
 
-CPL_CVSID("$Id: pngdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: pngdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_PNG(void);
@@ -126,6 +126,9 @@ class PNGDataset : public GDALPamDataset
 
     int         bHasReadICCMetadata;
     void        LoadICCProfile();
+    
+    static void WriteMetadataAsText(png_structp hPNG, png_infop psPNGInfo,
+                                    const char* pszKey, const char* pszValue);
 
   public:
                  PNGDataset();
@@ -150,6 +153,13 @@ class PNGDataset : public GDALPamDataset
     virtual const char *GetMetadataItem( const char * pszName,
                                          const char * pszDomain = NULL );
 
+    virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
+                                   void *, int, int, GDALDataType,
+                                   int, int *,
+                                   GSpacing, GSpacing,
+                                   GSpacing,
+                                   GDALRasterIOExtraArg* psExtraArg );
+
     // semi-private.
     jmp_buf     sSetJmpContext;
 
@@ -464,6 +474,98 @@ PNGDataset::~PNGDataset()
 }
 
 /************************************************************************/
+/*                            IsFullBandMap()                           */
+/************************************************************************/
+
+static int IsFullBandMap(int *panBandMap, int nBands)
+{
+    for(int i=0;i<nBands;i++)
+    {
+        if( panBandMap[i] != i + 1 )
+            return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                             IRasterIO()                              */
+/************************************************************************/
+
+CPLErr PNGDataset::IRasterIO( GDALRWFlag eRWFlag,
+                              int nXOff, int nYOff, int nXSize, int nYSize,
+                              void *pData, int nBufXSize, int nBufYSize,
+                              GDALDataType eBufType,
+                              int nBandCount, int *panBandMap,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
+
+{
+    if((eRWFlag == GF_Read) &&
+       (nBandCount == nBands) &&
+       (nXOff == 0) && (nYOff == 0) &&
+       (nXSize == nBufXSize) && (nXSize == nRasterXSize) &&
+       (nYSize == nBufYSize) && (nYSize == nRasterYSize) &&
+       (eBufType == GDT_Byte) &&
+       (eBufType == GetRasterBand(1)->GetRasterDataType()) &&
+       (pData != NULL) &&
+       (panBandMap != NULL) && IsFullBandMap(panBandMap, nBands))
+    {
+        int y;
+        CPLErr tmpError;
+        int x;
+
+        // Pixel interleaved case
+        if( nBandSpace == 1 )
+        {
+            for(y = 0; y < nYSize; ++y)
+            {
+                tmpError = LoadScanline(y);
+                if(tmpError != CE_None) return tmpError;
+                GByte* pabyScanline = pabyBuffer 
+                    + (y - nBufferStartLine) * nBands * nXSize;
+                if( nPixelSpace == nBandSpace * nBandCount )
+                {
+                    memcpy(&(((GByte*)pData)[(y*nLineSpace)]),
+                           pabyScanline, nBandCount * nXSize);
+                }
+                else
+                {
+                    for(x = 0; x < nXSize; ++x)
+                    {
+                        memcpy(&(((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace)]), 
+                               (const GByte*)&(pabyScanline[x* nBandCount]), nBandCount);
+                    }
+                }
+            }
+        }
+        else
+        {
+            for(y = 0; y < nYSize; ++y)
+            {
+                tmpError = LoadScanline(y);
+                if(tmpError != CE_None) return tmpError;
+                GByte* pabyScanline = pabyBuffer 
+                    + (y - nBufferStartLine) * nBands * nXSize;
+                for(x = 0; x < nXSize; ++x)
+                {
+                    for(int iBand=0;iBand<nBands;iBand++)
+                        ((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace) + iBand * nBandSpace] = pabyScanline[x*nBands+iBand];
+                }
+            }
+        }
+
+        return CE_None;
+    }
+
+    return GDALPamDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                                     pData, nBufXSize, nBufYSize, eBufType, 
+                                     nBandCount, panBandMap, 
+                                     nPixelSpace, nLineSpace, nBandSpace,
+                                     psExtraArg);
+}
+
+/************************************************************************/
 /*                          GetGeoTransform()                           */
 /************************************************************************/
 
@@ -741,7 +843,7 @@ void PNGDataset::CollectMetadata()
                 pszTag[i] = '_';
         }
 
-        SetMetadataItem( pszTag, text_ptr[iText].text );
+        GDALDataset::SetMetadataItem( pszTag, text_ptr[iText].text );
         CPLFree( pszTag );
     }
 }
@@ -996,25 +1098,14 @@ GDALDataset *PNGDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
-/*      Open a file handle using large file API.                        */
-/* -------------------------------------------------------------------- */
-    VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
-    if( fp == NULL )
-    {
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "Unexpected failure of VSIFOpenL(%s) in PNG Open()", 
-                  poOpenInfo->pszFilename );
-        return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
 /* -------------------------------------------------------------------- */
     PNGDataset 	*poDS;
 
     poDS = new PNGDataset();
 
-    poDS->fpImage = fp;
+    poDS->fpImage = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
     poDS->eAccess = poOpenInfo->eAccess;
     
     poDS->hPNG = png_create_read_struct( PNG_LIBPNG_VER_STRING, poDS, 
@@ -1210,13 +1301,13 @@ GDALDataset *PNGDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
-    poDS->TryLoadXML( poOpenInfo->papszSiblingFiles );
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Open overviews.                                                 */
 /* -------------------------------------------------------------------- */
     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
-                                 poOpenInfo->papszSiblingFiles );
+                                 poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -1271,6 +1362,42 @@ char **PNGDataset::GetFileList()
 }
 
 /************************************************************************/
+/*                          WriteMetadataAsText()                       */
+/************************************************************************/
+
+#if defined(PNG_iTXt_SUPPORTED) || ((PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 4) || PNG_LIBPNG_VER_MAJOR > 1)
+#define HAVE_ITXT_SUPPORT
+#endif
+
+#ifdef HAVE_ITXT_SUPPORT
+static int IsASCII(const char* pszStr)
+{
+    for(int i=0;pszStr[i]!='\0';i++)
+    {
+        if( ((GByte*)pszStr)[i] >= 128 )
+            return FALSE;
+    }
+    return TRUE;
+}
+#endif
+
+void PNGDataset::WriteMetadataAsText(png_structp hPNG, png_infop psPNGInfo,
+                                     const char* pszKey, const char* pszValue)
+{
+    png_text sText;
+    memset(&sText, 0, sizeof(png_text));
+    sText.compression = PNG_TEXT_COMPRESSION_NONE;
+    sText.key = (png_charp) pszKey;
+    sText.text = (png_charp) pszValue;
+#ifdef HAVE_ITXT_SUPPORT
+    // UTF-8 values should be written in iTXt, whereas TEXT should be LATIN-1 
+    if( !IsASCII(pszValue) && CPLIsUTF8(pszValue, -1) )
+        sText.compression = PNG_ITXT_COMPRESSION_NONE;
+#endif
+    png_set_text(hPNG, psPNGInfo, &sText, 1);
+}
+
+/************************************************************************/
 /*                             CreateCopy()                             */
 /************************************************************************/
 
@@ -1512,7 +1639,7 @@ PNGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
         if (pszGamma != NULL)
         {
-            double dfGamma = atof(pszGamma);
+            double dfGamma = CPLAtof(pszGamma);
             png_set_gAMA(hPNG, psPNGInfo, dfGamma);
         }
 
@@ -1554,7 +1681,7 @@ PNGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                 {
                     for( int j = 0; j < 3; j++ )
                     {
-                        double v = atof(apapszTokenList[i][j]);
+                        double v = CPLAtof(apapszTokenList[i][j]);
 
                         if (j == 2)
                         {
@@ -1652,6 +1779,48 @@ PNGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         }
     }
 
+/* -------------------------------------------------------------------- */
+/*      Add text info                                                   */
+/* -------------------------------------------------------------------- */
+    /* Predefined keywords. See "4.2.7 tEXt Textual data" of http://www.w3.org/TR/PNG-Chunks.html */
+    const char* apszKeywords[] = { "Title", "Author", "Description", "Copyright",
+                                   "Creation Time", "Software", "Disclaimer",
+                                   "Warning", "Source", "Comment", NULL };
+    int bWriteMetadataAsText = CSLTestBoolean(
+        CSLFetchNameValueDef(papszOptions, "WRITE_METADATA_AS_TEXT", "FALSE"));
+    for(int i=0;apszKeywords[i]!=NULL;i++)
+    {
+        const char* pszKey = apszKeywords[i];
+        const char* pszValue = CSLFetchNameValue(papszOptions, pszKey);
+        if( pszValue == NULL && bWriteMetadataAsText )
+            pszValue = poSrcDS->GetMetadataItem(pszKey);
+        if( pszValue != NULL )
+        {
+            WriteMetadataAsText(hPNG, psPNGInfo, pszKey, pszValue);
+        }
+    }
+    if( bWriteMetadataAsText )
+    {
+        char** papszSrcMD = poSrcDS->GetMetadata();
+        for( ; papszSrcMD && *papszSrcMD; papszSrcMD++ )
+        {
+            char* pszKey = NULL;
+            const char* pszValue = CPLParseNameValue(*papszSrcMD, &pszKey );
+            if( pszKey && pszValue )
+            {
+                if( CSLFindString((char**)apszKeywords, pszKey) < 0 &&
+                    !EQUAL(pszKey, "AREA_OR_POINT") && !EQUAL(pszKey, "NODATA_VALUES") )
+                {
+                    WriteMetadataAsText(hPNG, psPNGInfo, pszKey, pszValue);
+                }
+                CPLFree(pszKey);
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write infos                                                     */
+/* -------------------------------------------------------------------- */
     png_write_info( hPNG, psPNGInfo );
 
 /* -------------------------------------------------------------------- */
@@ -1667,15 +1836,14 @@ PNGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     {
         png_bytep       row = pabyScanline;
 
-        for( int iBand = 0; iBand < nBands; iBand++ )
-        {
-            GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
-            eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
-                                     pabyScanline + iBand*nWordSize, 
-                                     nXSize, 1, eType,
-                                     nBands * nWordSize, 
-                                     nBands * nXSize * nWordSize );
-        }
+        eErr = poSrcDS->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
+                                  pabyScanline, 
+                                  nXSize, 1, eType,
+                                  nBands, NULL,
+                                  nBands * nWordSize, 
+                                  nBands * nXSize * nWordSize,
+                                  nWordSize,
+                                  NULL );
 
 #ifdef CPL_LSB
         if( nBitDepth == 16 )
@@ -1719,21 +1887,23 @@ PNGDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
 
     /* If outputing to stdout, we can't reopen it, so we'll return */
     /* a fake dataset to make the caller happy */
     if( CSLTestBoolean(CPLGetConfigOption("GDAL_OPEN_AFTER_COPY", "YES")) )
     {
-        GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
-
         CPLPushErrorHandler(CPLQuietErrorHandler);
+        GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
         PNGDataset *poDS = (PNGDataset*) PNGDataset::Open( &oOpenInfo );
         CPLPopErrorHandler();
         if( poDS )
         {
-            poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
+            int nFlags = GCIF_PAM_DEFAULT;
+            if( bWriteMetadataAsText )
+                nFlags &= ~GCIF_METADATA;
+            poDS->CloneInfo( poSrcDS, nFlags );
             return poDS;
         }
         CPLErrorReset();
@@ -1818,7 +1988,7 @@ static void png_gdal_error( png_structp png_ptr, const char *error_message )
 
 static void png_gdal_warning( CPL_UNUSED png_structp png_ptr, const char *error_message )
 {
-    CPLError( CE_Warning, CPLE_AppDefined, 
+    CPLError( CE_Warning, CPLE_AppDefined,
               "libpng: %s", error_message );
 }
 
@@ -1836,6 +2006,7 @@ void GDALRegister_PNG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "PNG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Portable Network Graphics" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -1847,7 +2018,7 @@ void GDALRegister_PNG()
                                    "Byte UInt16" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
 "<CreationOptionList>\n"
-"   <Option name='WORLDFILE' type='boolean' description='Create world file'/>\n"
+"   <Option name='WORLDFILE' type='boolean' description='Create world file' default='FALSE'/>\n"
 "   <Option name='ZLEVEL' type='int' description='DEFLATE compression level 1-9' default='6'/>\n"
 "   <Option name='SOURCE_ICC_PROFILE' type='string' description='ICC Profile'/>\n"
 "   <Option name='SOURCE_ICC_PROFILE_NAME' type='string' descriptor='ICC Profile name'/>\n"
@@ -1856,6 +2027,11 @@ void GDALRegister_PNG()
 "   <Option name='SOURCE_PRIMARIES_BLUE' type='string' description='x,y,1.0 (xyY) blue chromaticity'/>\n"
 "   <Option name='SOURCE_WHITEPOINT' type='string' description='x,y,1.0 (xyY) whitepoint'/>\n"
 "   <Option name='PNG_GAMMA' type='string' description='Gamma'/>\n"
+"   <Option name='TITLE' type='string' description='Title'/>\n"
+"   <Option name='DESCRIPTION' type='string' description='Description'/>\n"
+"   <Option name='COPYRIGHT' type='string' description='Copyright'/>\n"
+"   <Option name='COMMENT' type='string' description='Comment'/>\n"
+"   <Option name='WRITE_METADATA_AS_TEXT' type='boolean' description='Whether to write source dataset metadata in TEXT chunks' default='FALSE'/>\n"
 "</CreationOptionList>\n" );
 
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
diff --git a/frmts/postgisraster/GNUmakefile b/frmts/postgisraster/GNUmakefile
index 02ebd7c..8a62ff3 100644
--- a/frmts/postgisraster/GNUmakefile
+++ b/frmts/postgisraster/GNUmakefile
@@ -7,7 +7,7 @@ include ../../GDALmake.opt
 OBJ	=	postgisrasterdriver.o postgisrasterdataset.o postgisrasterrasterband.o postgisrastertiledataset.o postgisrastertilerasterband.o postgisrastertools.o
 
 
-CPPFLAGS	:= -I ../mem -I ../vrt $(XTRA_OPT) $(PG_INC) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:= -I ../mem -I ../vrt $(XTRA_OPT) $(PG_INC)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/postgisraster/postgisraster.h b/frmts/postgisraster/postgisraster.h
index 7557d84..fe5aa2c 100644
--- a/frmts/postgisraster/postgisraster.h
+++ b/frmts/postgisraster/postgisraster.h
@@ -180,7 +180,7 @@ class PostGISRasterTileDataset;
 class PostGISRasterDriver : public GDALDriver {
 
 private:
-    void* hMutex;
+    CPLMutex* hMutex;
     std::map<CPLString, PGconn*> oMapConnection;
 public:
     PostGISRasterDriver();
@@ -334,7 +334,9 @@ public:
     virtual double GetNoDataValue(int *pbSuccess = NULL);
     virtual CPLErr SetNoDataValue(double);
     virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, 
-		int, int, GDALDataType, int, int);
+		int, int, GDALDataType,
+        GSpacing nPixelSpace, GSpacing nLineSpace,
+        GDALRasterIOExtraArg* psExtraArg);
 #ifdef notdef
     virtual CPLErr IReadBlock(int, int, void *);
 #endif
diff --git a/frmts/postgisraster/postgisrasterdataset.cpp b/frmts/postgisraster/postgisrasterdataset.cpp
index b7ed352..b1dec9c 100644
--- a/frmts/postgisraster/postgisrasterdataset.cpp
+++ b/frmts/postgisraster/postgisrasterdataset.cpp
@@ -806,7 +806,7 @@ GBool PostGISRasterDataset::AddComplexSource(PostGISRasterTileDataset* poRTDS)
         "Tile bounding box from (%d, %d) of size (%d, %d) will "
         "cover raster bounding box from (%d, %d) of size "
         "(%d, %d)", 0, 0, 
-        poRTDS>GetRasterXSize(), 
+        poRTDS->GetRasterXSize(), 
         poRTDS->GetRasterYSize(),
         nDstXOff, nDstYOff, nDstXSize, nDstYSize);
 #endif
@@ -1007,7 +1007,6 @@ GBool PostGISRasterDataset::LoadSources(int nXOff, int nYOff, int nXSize, int nY
     }
     else
     {
-        CPLLocaleC oCLocale;
         double adfProjWin[8];
         PolygonFromCoords(nXOff, nYOff, nXOff + nXSize, nYOff + nYSize, adfProjWin); 
         osSpatialFilter.Printf("%s && "
@@ -1407,12 +1406,6 @@ PostGISRasterTileDataset* PostGISRasterDataset::BuildRasterTileDataset(const cha
         return NULL;
     }
 
-#ifdef DEBUG_VERBOSE
-    CPLDebug("PostGIS_Raster", "PostGISRasterDataset::"
-            "Tile pixel size = (%f, %f)", tilePixelSizeX, 
-            tilePixelSizeY);
-#endif
-
     int nTileWidth = atoi(papszParams[POS_WIDTH]);
     int nTileHeight = atoi(papszParams[POS_HEIGHT]);
 
@@ -1929,7 +1922,6 @@ const char * pszValidConnectionString)
             dfTileUpperLeftX = CPLAtof(papszParams[POS_UPPERLEFTX]);
             dfTileUpperLeftY = CPLAtof(papszParams[POS_UPPERLEFTY]);
         
-            CPLLocaleC oCLocale;
             papszSubdatasets[2 * i] = 
                 CPLStrdup(CPLSPrintf("SUBDATASET_%d_NAME=PG:%s schema=%s table=%s column=%s "
                     "where='abs(ST_UpperLeftX(%s) - %.8f) < 1e-8 AND "
@@ -2810,7 +2802,7 @@ GetConnection(const char * pszFilename, char ** ppszConnectionString,
 int PostGISRasterDataset::Identify(GDALOpenInfo* poOpenInfo)
 {
     if (poOpenInfo->pszFilename == NULL ||
-        poOpenInfo->fp != NULL ||
+        poOpenInfo->fpL != NULL ||
         !EQUALN(poOpenInfo->pszFilename, "PG:", 3))
     {
         return FALSE;
@@ -3522,7 +3514,7 @@ PostGISRasterDataset::Delete(const char* pszFilename)
     poConn = GetConnection(pszFilename, &pszConnectionString, 
         &pszSchema, &pszTable, &pszColumn, &pszWhere,
         &nMode, &bBrowseDatabase);
-    if (poConn == NULL) {
+    if (poConn == NULL || pszSchema == NULL || pszTable == NULL) {
         CPLFree(pszConnectionString);
         CPLFree(pszSchema);
         CPLFree(pszTable);
@@ -3682,6 +3674,7 @@ void GDALRegister_PostGISRaster() {
         poDriver = new PostGISRasterDriver();
 
         poDriver->SetDescription("PostGISRaster");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
                 "PostGIS Raster driver");
         poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
diff --git a/frmts/postgisraster/postgisrasterrasterband.cpp b/frmts/postgisraster/postgisrasterrasterband.cpp
index 419f1e6..95e8014 100644
--- a/frmts/postgisraster/postgisrasterrasterband.cpp
+++ b/frmts/postgisraster/postgisrasterrasterband.cpp
@@ -325,8 +325,8 @@ static int SortTilesByPKID(const void* a, const void* b)
 
 CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, 
     int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, 
-    int nBufYSize, GDALDataType eBufType, int nPixelSpace, 
-    int nLineSpace)
+    int nBufYSize, GDALDataType eBufType,
+    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg)
 {
     /**
      * TODO: Write support not implemented yet
@@ -347,7 +347,7 @@ CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff,
     {
         if(OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, 
             pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, 
-            nLineSpace) == CE_None)
+            nLineSpace, psExtraArg) == CE_None)
                 
         return CE_None;
     }
@@ -416,7 +416,7 @@ CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff,
         
         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, 
             nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, 
-            nLineSpace);
+            nLineSpace, psExtraArg);
     }
 #endif    
     
@@ -638,7 +638,6 @@ CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff,
         } 
         
         else {
-            CPLLocaleC oCLocale; // Force C locale to avoid commas instead of decimal points (for QGIS e.g.)
             bHasWhere = TRUE;
             osCommand.Printf("SELECT %s, ST_Metadata(%s), %s FROM %s.%s WHERE ",
                              osRasterToFetch.c_str(), pszColumn,
@@ -745,7 +744,7 @@ CPLErr PostGISRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff,
         eErr = 
             poTileBand->poSource->RasterIO( nXOff, nYOff, nXSize, nYSize, 
                                             pData, nBufXSize, nBufYSize, 
-                                            eBufType, nPixelSpace, nLineSpace);
+                                            eBufType, nPixelSpace, nLineSpace, NULL);
     }
     
     // Free the object that holds pointers to matching tiles
diff --git a/frmts/postgisraster/postgisrastertilerasterband.cpp b/frmts/postgisraster/postgisrastertilerasterband.cpp
index b14c7ed..8a8b7de 100644
--- a/frmts/postgisraster/postgisrastertilerasterband.cpp
+++ b/frmts/postgisraster/postgisrastertilerasterband.cpp
@@ -109,7 +109,6 @@ CPLErr PostGISRasterTileRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
     
     // Get by upperleft
     else {
-        CPLLocaleC oCLocale; // Force C locale to avoid commas instead of decimal points (for QGIS e.g.)
         osCommand.Printf("select st_band(%s, %d) from %s.%s where "
             "abs(ST_UpperLeftX(%s) - %.8f) < 1e-8 and abs(ST_UpperLeftY(%s) - %.8f) < 1e-8", 
             poRTDS->poRDS->pszColumn, nBand, poRTDS->poRDS->pszSchema, poRTDS->poRDS->pszTable, poRTDS->poRDS->pszColumn, 
diff --git a/frmts/r/GNUmakefile b/frmts/r/GNUmakefile
index 8d02005..01efd20 100644
--- a/frmts/r/GNUmakefile
+++ b/frmts/r/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	rdataset.o rcreatecopy.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/r/rcreatecopy.cpp b/frmts/r/rcreatecopy.cpp
index a04d42b..a4d07f1 100644
--- a/frmts/r/rcreatecopy.cpp
+++ b/frmts/r/rcreatecopy.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rcreatecopy.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: rcreatecopy.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  R Format Driver
  * Purpose:  CreateCopy() implementation for R stats package object format.
@@ -30,7 +30,7 @@
 #include "gdal_pam.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: rcreatecopy.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: rcreatecopy.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -84,10 +84,12 @@ static void RWriteString( VSILFILE *fp, int bASCII, const char *pszValue )
 /************************************************************************/
 
 GDALDataset *
-RCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-             CPL_UNUSED int bStrict, char ** papszOptions, 
-             GDALProgressFunc pfnProgress, void * pProgressData )
-
+RCreateCopy( const char * pszFilename,
+             GDALDataset *poSrcDS,
+             CPL_UNUSED int bStrict,
+             char ** papszOptions,
+             GDALProgressFunc pfnProgress,
+             void * pProgressData )
 {
     int  nBands = poSrcDS->GetRasterCount();
     int  nXSize = poSrcDS->GetRasterXSize();
@@ -181,14 +183,14 @@ RCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
                                      padfScanline, nXSize, 1, GDT_Float64,
-                                     sizeof(double), 0 );
+                                     sizeof(double), 0, NULL );
 
             if( bASCII )
             {
                 for( iValue = 0; iValue < nXSize; iValue++ )
                 {
                     char szValue[128];
-                    sprintf(szValue,"%.16g\n", padfScanline[iValue] );
+                    CPLsprintf(szValue,"%.16g\n", padfScanline[iValue] );
                     VSIFWriteL( szValue, 1, strlen(szValue), fp );
                 }
             }
@@ -243,9 +245,9 @@ RCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         return NULL;
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = 
+    GDALPamDataset *poDS =
         (GDALPamDataset *) GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
@@ -253,4 +255,3 @@ RCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     return poDS;
 }
-
diff --git a/frmts/r/rdataset.cpp b/frmts/r/rdataset.cpp
index 4e16240..2e1af14 100644
--- a/frmts/r/rdataset.cpp
+++ b/frmts/r/rdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: rdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  R Format Driver
  * Purpose:  Read/write R stats package object format.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "../raw/rawdataset.h"
 
-CPL_CVSID("$Id: rdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: rdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void    GDALRegister_R(void);
@@ -130,7 +130,8 @@ RRasterBand::~RRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr RRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr RRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                int nBlockYOff,
                                 void * pImage )
 {
     memcpy( pImage, padfMatrixValues + nBlockYOff * nBlockXSize,
@@ -223,7 +224,7 @@ double RDataset::ReadFloat()
 {
     if( bASCII )
     {
-        return atof(ASCIIFGets());
+        return CPLAtof(ASCIIFGets());
     }
     else
     {
@@ -590,6 +591,7 @@ void GDALRegister_R()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "R" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "R Object Data Store" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -611,4 +613,3 @@ void GDALRegister_R()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/rasdaman/GNUmakefile b/frmts/rasdaman/GNUmakefile
index 2358225..f936c2c 100644
--- a/frmts/rasdaman/GNUmakefile
+++ b/frmts/rasdaman/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	rasdamandataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(RASDAMAN_INC)
+CPPFLAGS	:=	 $(CPPFLAGS) $(RASDAMAN_INC)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/rasdaman/rasdamandataset.cpp b/frmts/rasdaman/rasdamandataset.cpp
index 96abd7c..3c2efad 100644
--- a/frmts/rasdaman/rasdamandataset.cpp
+++ b/frmts/rasdaman/rasdamandataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rasdamandataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rasdamandataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  * Project:  rasdaman Driver
  * Purpose:  Implement Rasdaman GDAL driver
  * Author:   Constantin Jucovschi, jucovschi at yahoo.com
@@ -44,7 +44,7 @@
 
 #include "rasodmg/database.hh"
 
-CPL_CVSID("$Id: rasdamandataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rasdamandataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 
 CPL_C_START
@@ -122,7 +122,10 @@ protected:
 
   virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                             void *, int, int, GDALDataType,
-                            int, int *, int, int, int );
+                            int, int *,
+                            GSpacing nPixelSpace, GSpacing nLineSpace,
+                            GSpacing nBandSpace,
+                            GDALRasterIOExtraArg* psExtraArg);
 
 private:
 
@@ -186,7 +189,9 @@ CPLErr RasdamanDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
 {
   if (eRWFlag != GF_Read) {
     CPLError(CE_Failure, CPLE_NoWriteAccess, "Write support is not implemented.");
@@ -203,7 +208,8 @@ CPLErr RasdamanDataset::IRasterIO( GDALRWFlag eRWFlag,
 
   CPLErr ret = GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
                                       nBufXSize, nBufYSize, eBufType, nBandCount,
-                                      panBandMap, nPixelSpace, nLineSpace, nBandSpace);
+                                      panBandMap, nPixelSpace, nLineSpace, nBandSpace,
+                                      psExtraArg);
 
   transaction.commit();
   
@@ -567,7 +573,7 @@ GDALDataset *RasdamanDataset::Open( GDALOpenInfo * poOpenInfo )
 
   // fast checks if current module should handle the request
   // check 1: the request is not on a existing file in the file system
-  if (poOpenInfo->fp != NULL) {
+  if (poOpenInfo->fpL != NULL) {
     return NULL;
   }
   // check 2: the request contains --collection
@@ -714,6 +720,7 @@ extern void GDALRegister_RASDAMAN()
     poDriver = new GDALDriver();
 
     poDriver->SetDescription( "RASDAMAN" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                "RASDAMAN" );
     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/rasterlite/GNUmakefile b/frmts/rasterlite/GNUmakefile
index 6f515c5..1fbf5d3 100644
--- a/frmts/rasterlite/GNUmakefile
+++ b/frmts/rasterlite/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	rasterlitedataset.o rasterlitecreatecopy.o rasterliteoverviews.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) -I../../ogr
+CPPFLAGS	:=	 $(CPPFLAGS) -I../../ogr
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/rasterlite/frmt_rasterlite.html b/frmts/rasterlite/frmt_rasterlite.html
index f80cd31..95f22ad 100644
--- a/frmts/rasterlite/frmt_rasterlite.html
+++ b/frmts/rasterlite/frmt_rasterlite.html
@@ -203,9 +203,9 @@ $ gdaladdo RASTERLITE:my_db.sqlite,table=source 2 4 8 16 --config RASTERLITE_OVR
 
 <ul>
 <li><a href="http://www.gaia-gis.it/spatialite">Spatialite and Rasterlite home page</a></li>
-<li><a href="http://www.gaia-gis.it/spatialite/rasterlite-man.pdf">Rasterlite manual</a></li>
-<li><a href="http://www.gaia-gis.it/spatialite/rasterlite-how-to.pdf">Rasterlite howto</a></li>
-<li><a href="http://www.gaia-gis.it/spatialite/resources.html">Sample databases</a></li>
+<li><a href="http://www.gaia-gis.it/gaia-sins/rasterlite-docs/rasterlite-man.pdf">Rasterlite manual</a></li> 
+<li><a href="http://www.gaia-gis.it/gaia-sins/rasterlite-docs/rasterlite-how-to.pdf">Rasterlite howto</a></li> 
+<li><a href="http://www.gaia-gis.it/spatialite-2.3.1/resources.html">Sample databases</a></li> 
 <li><a href="http://gdal.org/ogr/drv_sqlite.html">OGR SQLite driver</a></li>
 </ul>
 
diff --git a/frmts/rasterlite/rasterlitecreatecopy.cpp b/frmts/rasterlite/rasterlitecreatecopy.cpp
index f1502ac..64f5980 100644
--- a/frmts/rasterlite/rasterlitecreatecopy.cpp
+++ b/frmts/rasterlite/rasterlitecreatecopy.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: rasterlitecreatecopy.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: rasterlitecreatecopy.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Rasterlite driver
  * Purpose:  Implement GDAL Rasterlite support using OGR SQLite driver
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  **********************************************************************
- * Copyright (c) 2009-2012, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2009-2012, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -33,7 +33,7 @@
 
 #include "rasterlitedataset.h"
 
-CPL_CVSID("$Id: rasterlitecreatecopy.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: rasterlitecreatecopy.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                  RasterliteGetTileDriverOptions ()                   */
@@ -260,7 +260,7 @@ OGRDataSourceH RasterliteCreateTables(OGRDataSourceH hDS, const char* pszTableNa
         /* Re-open the DB to take into account the new tables*/
         OGRReleaseDataSource(hDS);
         
-        hDS = OGROpen(osDBName.c_str(), TRUE, NULL);
+        hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
     }
     else
     {
@@ -292,7 +292,7 @@ OGRDataSourceH RasterliteCreateTables(OGRDataSourceH hDS, const char* pszTableNa
                     /* Re-open the DB to take into account the change of SRS */
                     OGRReleaseDataSource(hDS);
                     
-                    hDS = OGROpen(osDBName.c_str(), TRUE, NULL);
+                    hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
                 }
                 else
                 {
@@ -322,9 +322,10 @@ OGRDataSourceH RasterliteCreateTables(OGRDataSourceH hDS, const char* pszTableNa
 /************************************************************************/
 
 GDALDataset *
-RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                       CPL_UNUSED int bStrict, CPL_UNUSED char ** papszOptions, 
-                       GDALProgressFunc pfnProgress, void * pProgressData )
+RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
+                      CPL_UNUSED int bStrict,
+                      char ** papszOptions,
+                      GDALProgressFunc pfnProgress, void * pProgressData )
 {
     int nBands = poSrcDS->GetRasterCount();
     if (nBands == 0)
@@ -406,7 +407,7 @@ RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
         pszFilenameWithoutPrefix += 11;
     
     char** papszTokens = CSLTokenizeStringComplex( 
-                pszFilenameWithoutPrefix, ", ", FALSE, FALSE );
+                pszFilenameWithoutPrefix, ",", FALSE, FALSE );
     int nTokens = CSLCount(papszTokens);
     if (nTokens == 0)
     {
@@ -477,7 +478,7 @@ RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
     else
     {
-        hDS = OGROpen(osDBName.c_str(), TRUE, NULL);
+        hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update);
     }
     
     if (hDS == NULL)
@@ -526,15 +527,11 @@ RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     osSQL.Printf("SELECT COUNT(geometry) FROM \"%s\" "
                  "WHERE rowid IN "
                  "(SELECT pkid FROM \"idx_%s_metadata_geometry\" "
-                  "WHERE xmin < %.15f AND xmax > %.15f "
-                  "AND ymin < %.15f  AND ymax > %.15f) "
-                 "AND pixel_x_size >= %.15f AND pixel_x_size <= %.15f AND "
-                 "pixel_y_size >= %.15f AND pixel_y_size <= %.15f",
+                  "WHERE %s) AND %s",
                   osMetatadataLayer.c_str(),
                   osTableName.c_str(),
-                  maxx, minx, maxy, miny,
-                  adfGeoTransform[1] - 1e-15, adfGeoTransform[1] + 1e-15,
-                  - adfGeoTransform[5] - 1e-15, - adfGeoTransform[5] + 1e-15);
+                  RasterliteGetSpatialFilterCond(minx, miny, maxx, maxy).c_str(),
+                  RasterliteGetPixelSizeCond(adfGeoTransform[1], -adfGeoTransform[5]).c_str());
     
     int nOverlappingGeoms = 0;
     OGRLayerH hCountLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
@@ -605,7 +602,7 @@ RasterliteCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                      nReqXSize, nReqYSize,
                                      pabyMEMDSBuffer, nReqXSize, nReqYSize,
                                      eDataType, nBands, NULL,
-                                     0, 0, 0);
+                                     0, 0, 0, NULL);
             if (eErr != CE_None)
             {
                 break;
diff --git a/frmts/rasterlite/rasterlitedataset.cpp b/frmts/rasterlite/rasterlitedataset.cpp
index 9cb0dd8..ee1076c 100644
--- a/frmts/rasterlite/rasterlitedataset.cpp
+++ b/frmts/rasterlite/rasterlitedataset.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: rasterlitedataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rasterlitedataset.cpp 28027 2014-11-30 11:45:46Z rouault $
  *
  * Project:  GDAL Rasterlite driver
  * Purpose:  Implement GDAL Rasterlite support using OGR SQLite driver
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  **********************************************************************
- * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,7 +34,59 @@
 
 #include "rasterlitedataset.h"
 
-CPL_CVSID("$Id: rasterlitedataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rasterlitedataset.cpp 28027 2014-11-30 11:45:46Z rouault $");
+
+
+/************************************************************************/
+/*                        RasterliteOpenSQLiteDB()                      */
+/************************************************************************/
+
+OGRDataSourceH RasterliteOpenSQLiteDB(const char* pszFilename,
+                                      GDALAccess eAccess)
+{
+    const char* const apszAllowedDrivers[] = { "SQLITE", NULL };
+    return (OGRDataSourceH)GDALOpenEx(pszFilename,
+                                      GDAL_OF_VECTOR |
+                                      ((eAccess == GA_Update) ? GDAL_OF_UPDATE : 0),
+                                      apszAllowedDrivers, NULL, NULL);
+}
+
+/************************************************************************/
+/*                       RasterliteGetPixelSizeCond()                   */
+/************************************************************************/
+
+CPLString RasterliteGetPixelSizeCond(double dfPixelXSize,
+                                     double dfPixelYSize,
+                                     const char* pszTablePrefixWithDot)
+{
+    CPLString osCond;
+    osCond.Printf("((%spixel_x_size >= %s AND %spixel_x_size <= %s) AND "
+                   "(%spixel_y_size >= %s AND %spixel_y_size <= %s))",
+                  pszTablePrefixWithDot,
+                  CPLString().FormatC(dfPixelXSize - 1e-15,"%.15f").c_str(),
+                  pszTablePrefixWithDot,
+                  CPLString().FormatC(dfPixelXSize + 1e-15,"%.15f").c_str(),
+                  pszTablePrefixWithDot,
+                  CPLString().FormatC(dfPixelYSize - 1e-15,"%.15f").c_str(),
+                  pszTablePrefixWithDot,
+                  CPLString().FormatC(dfPixelYSize + 1e-15,"%.15f").c_str());
+    return osCond;
+}
+/************************************************************************/
+/*                     RasterliteGetSpatialFilterCond()                 */
+/************************************************************************/
+
+CPLString RasterliteGetSpatialFilterCond(double minx, double miny,
+                                         double maxx, double maxy)
+{
+    CPLString osCond;
+    osCond.Printf("(xmin < %s AND xmax > %s AND ymin < %s AND ymax > %s)",
+                  CPLString().FormatC(maxx,"%.15f").c_str(),
+                  CPLString().FormatC(minx,"%.15f").c_str(),
+                  CPLString().FormatC(maxy,"%.15f").c_str(),
+                  CPLString().FormatC(miny,"%.15f").c_str());
+    return osCond;
+}
 
 /************************************************************************/
 /*                            RasterliteBand()                          */
@@ -84,16 +136,12 @@ CPLErr RasterliteBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage
     osSQL.Printf("SELECT m.geometry, r.raster, m.id, m.width, m.height FROM \"%s_metadata\" AS m, "
                  "\"%s_rasters\" AS r WHERE m.rowid IN "
                  "(SELECT pkid FROM \"idx_%s_metadata_geometry\" "
-                  "WHERE xmin < %.15f AND xmax > %.15f "
-                  "AND ymin < %.15f  AND ymax > %.15f) "
-                 "AND m.pixel_x_size >= %.15f AND m.pixel_x_size <= %.15f AND "
-                 "m.pixel_y_size >= %.15f AND m.pixel_y_size <= %.15f AND r.id = m.id",
-                  poGDS->osTableName.c_str(),
-                  poGDS->osTableName.c_str(),
-                  poGDS->osTableName.c_str(),
-                  maxx, minx, maxy, miny,
-                  poGDS->adfGeoTransform[1] - 1e-15, poGDS->adfGeoTransform[1] + 1e-15,
-                  - poGDS->adfGeoTransform[5] - 1e-15, - poGDS->adfGeoTransform[5] + 1e-15);
+                  "WHERE %s) AND %s AND r.id = m.id",
+                 poGDS->osTableName.c_str(),
+                 poGDS->osTableName.c_str(),
+                 poGDS->osTableName.c_str(),
+                 RasterliteGetSpatialFilterCond(minx, miny, maxx, maxy).c_str(),
+                 RasterliteGetPixelSizeCond(poGDS->adfGeoTransform[1], -poGDS->adfGeoTransform[5], "m.").c_str());
     
     OGRLayerH hSQLLyr = OGR_DS_ExecuteSQL(poGDS->hDS, osSQL.c_str(), NULL, NULL);
     if (hSQLLyr == NULL)
@@ -203,7 +251,9 @@ CPLErr RasterliteBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage
                                               nDataSize, FALSE);
             VSIFCloseL(fp);
             
-            GDALDatasetH hDSTile = GDALOpen(osMemFileName.c_str(), GA_ReadOnly);
+            GDALDatasetH hDSTile = GDALOpenEx(osMemFileName.c_str(),
+                                              GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                              NULL, NULL, NULL);
             int nTileBands = 0;
             if (hDSTile && (nTileBands = GDALGetRasterCount(hDSTile)) == 0)
             {
@@ -762,11 +812,9 @@ int RasterliteDataset::GetBlockParams(OGRLayerH hRasterLyr, int nLevel,
     
     osSQL.Printf("SELECT m.geometry, r.raster, m.id "
                  "FROM \"%s_metadata\" AS m, \"%s_rasters\" AS r "
-                 "WHERE m.pixel_x_size >= %.15f AND m.pixel_x_size <= %.15f AND "
-                 "m.pixel_y_size >= %.15f AND m.pixel_y_size <= %.15f AND r.id = m.id",
+                 "WHERE %s AND r.id = m.id",
                  osTableName.c_str(), osTableName.c_str(),
-                 padfXResolutions[nLevel] - 1e-15, padfXResolutions[nLevel] + 1e-15,
-                 padfYResolutions[nLevel] - 1e-15, padfYResolutions[nLevel] + 1e-15);
+                 RasterliteGetPixelSizeCond(padfXResolutions[nLevel],padfYResolutions[nLevel], "m.").c_str());
     
     OGRLayerH hSQLLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
     if (hSQLLyr == NULL)
@@ -881,6 +929,7 @@ end:
 int RasterliteDataset::Identify(GDALOpenInfo* poOpenInfo)
 {
     if (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MBTILES") &&
+        !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "GPKG") &&
         poOpenInfo->nHeaderBytes >= 1024 &&
         EQUALN((const char*)poOpenInfo->pabyHeader, "SQLite Format 3", 15))
     {
@@ -922,7 +971,7 @@ GDALDataset* RasterliteDataset::Open(GDALOpenInfo* poOpenInfo)
     else
     {
         papszTokens = CSLTokenizeStringComplex( 
-                poOpenInfo->pszFilename + 11, ", ", FALSE, FALSE );
+                poOpenInfo->pszFilename + 11, ",", FALSE, FALSE );
         int nTokens = CSLCount(papszTokens);
         if (nTokens == 0)
         {
@@ -942,22 +991,22 @@ GDALDataset* RasterliteDataset::Open(GDALOpenInfo* poOpenInfo)
             else if (EQUALN(papszTokens[i], "minx=", 5))
             {
                 bMinXSet = TRUE;
-                minx = atof(papszTokens[i] + 5);
+                minx = CPLAtof(papszTokens[i] + 5);
             }
             else if (EQUALN(papszTokens[i], "miny=", 5))
             {
                 bMinYSet = TRUE;
-                miny = atof(papszTokens[i] + 5);
+                miny = CPLAtof(papszTokens[i] + 5);
             }
             else if (EQUALN(papszTokens[i], "maxx=", 5))
             {
                 bMaxXSet = TRUE;
-                maxx = atof(papszTokens[i] + 5);
+                maxx = CPLAtof(papszTokens[i] + 5);
             }
             else if (EQUALN(papszTokens[i], "maxy=", 5))
             {
                 bMaxYSet = TRUE;
-                maxy = atof(papszTokens[i] + 5);
+                maxy = CPLAtof(papszTokens[i] + 5);
             }
             else if (EQUALN(papszTokens[i], "bands=", 6))
             {
@@ -978,7 +1027,7 @@ GDALDataset* RasterliteDataset::Open(GDALOpenInfo* poOpenInfo)
 /*      Open underlying OGR DB                                          */
 /* -------------------------------------------------------------------- */
 
-    OGRDataSourceH hDS = OGROpen(osFileName.c_str(), (poOpenInfo->eAccess == GA_Update) ? TRUE : FALSE, NULL);
+    OGRDataSourceH hDS = RasterliteOpenSQLiteDB(osFileName.c_str(), poOpenInfo->eAccess);
     CPLDebug("RASTERLITE", "SQLite DB Open");
     
     RasterliteDataset* poDS = NULL;
@@ -1349,6 +1398,7 @@ void GDALRegister_Rasterlite()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "Rasterlite" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Rasterlite" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/rasterlite/rasterlitedataset.h b/frmts/rasterlite/rasterlitedataset.h
index be1d9cc..9fa44a9 100644
--- a/frmts/rasterlite/rasterlitedataset.h
+++ b/frmts/rasterlite/rasterlitedataset.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: rasterlitedataset.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rasterlitedataset.h 27566 2014-08-05 09:37:57Z rouault $
  *
  * Project:  GDAL Rasterlite driver
  * Purpose:  Implement GDAL Rasterlite support using OGR SQLite driver
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  **********************************************************************
- * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2009-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -31,9 +31,18 @@
 #define RASTERLITE_DATASET_INCLUDED
 
 #include "gdal_pam.h"
+#include "ogr_api.h"
 
 char** RasterliteGetTileDriverOptions(char** papszOptions);
 
+OGRDataSourceH RasterliteOpenSQLiteDB(const char* pszFilename,
+                                      GDALAccess eAccess);
+CPLString RasterliteGetPixelSizeCond(double dfPixelXSize,
+                                     double dfPixelYSize,
+                                     const char* pszTablePrefixWithDot = "");
+CPLString RasterliteGetSpatialFilterCond(double minx, double miny,
+                                         double maxx, double maxy);
+
 class RasterliteBand;
 
 /************************************************************************/
diff --git a/frmts/rasterlite/rasterliteoverviews.cpp b/frmts/rasterlite/rasterliteoverviews.cpp
index a8bfa77..1b77788 100644
--- a/frmts/rasterlite/rasterliteoverviews.cpp
+++ b/frmts/rasterlite/rasterliteoverviews.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: rasterliteoverviews.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rasterliteoverviews.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Rasterlite driver
  * Purpose:  Implement GDAL Rasterlite support using OGR SQLite driver
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  **********************************************************************
- * Copyright (c) 2009-2012, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2009-2012, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -33,7 +33,7 @@
 
 #include "rasterlitedataset.h"
 
-CPL_CVSID("$Id: rasterliteoverviews.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rasterliteoverviews.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                         ReloadOverviews()                            */
@@ -181,13 +181,9 @@ CPLErr RasterliteDataset::CleanOverviews()
     osSQL.Printf("BEGIN");
     OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
     
-    CPLString osResolutionCond;
-    osResolutionCond.Printf(
-                 "(pixel_x_size < %.15f OR pixel_x_size > %.15f) AND "
-                 "(pixel_y_size < %.15f OR pixel_y_size > %.15f)",
-                 padfXResolutions[0] - 1e-15, padfXResolutions[0] + 1e-15,
-                 padfYResolutions[0] - 1e-15, padfYResolutions[0] + 1e-15);
-    
+    CPLString osResolutionCond =
+        "NOT " + RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]);
+
     osSQL.Printf("DELETE FROM \"%s_rasters\" WHERE id "
                  "IN(SELECT id FROM \"%s_metadata\" WHERE %s)",
                   osTableName.c_str(), osTableName.c_str(),
@@ -251,12 +247,8 @@ CPLErr RasterliteDataset::CleanOverviewLevel(int nOvrFactor)
     osSQL.Printf("BEGIN");
     OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
     
-    CPLString osResolutionCond;
-    osResolutionCond.Printf(
-                 "pixel_x_size >= %.15f AND pixel_x_size <= %.15f AND "
-                 "pixel_y_size >= %.15f AND pixel_y_size <= %.15f",
-                 padfXResolutions[iLev] - 1e-15, padfXResolutions[iLev] + 1e-15,
-                 padfYResolutions[iLev] - 1e-15, padfYResolutions[iLev] + 1e-15);
+    CPLString osResolutionCond =
+        RasterliteGetPixelSizeCond(padfXResolutions[iLev], padfYResolutions[iLev]);
     
     osSQL.Printf("DELETE FROM \"%s_rasters\" WHERE id "
                  "IN(SELECT id FROM \"%s_metadata\" WHERE %s)",
@@ -373,11 +365,9 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
     CPLString osSourceName = "unknown";
     
     osSQL.Printf("SELECT source_name FROM \"%s\" WHERE "
-                 "pixel_x_size >= %.15f AND pixel_x_size <= %.15f AND "
-                 "pixel_y_size >= %.15f AND pixel_y_size <= %.15f LIMIT 1",
+                 "%s LIMIT 1",
                  osMetatadataLayer.c_str(),
-                 padfXResolutions[0] - 1e-15, padfXResolutions[0] + 1e-15,
-                 padfYResolutions[0] - 1e-15, padfYResolutions[0] + 1e-15);
+                 RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]).c_str());
     OGRLayerH hSQLLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
     if (hSQLLyr)
     {
@@ -468,7 +458,7 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
                                 nReqXSize * nOvrFactor, nReqYSize * nOvrFactor,
                                 pabyPrevOvrMEMDSBuffer, nPrevOvrReqXSize, nPrevOvrReqYSize,
                                 eDataType, nBands, NULL,
-                                0, 0, 0);
+                                0, 0, 0, NULL);
 
                 if (eErr != CE_None)
                 {
@@ -507,7 +497,7 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
                                 nReqXSize * nOvrFactor, nReqYSize * nOvrFactor,
                                 pabyMEMDSBuffer, nReqXSize, nReqYSize,
                                 eDataType, nBands, NULL,
-                                0, 0, 0);
+                                0, 0, 0, NULL);
                 if (eErr != CE_None)
                 {
                     break;
@@ -661,7 +651,7 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
             /* Re-open the DB to take into account the new tables*/
             OGRReleaseDataSource(hDS);
             
-            hDS = OGROpen(osFileName.c_str(), TRUE, NULL);
+            hDS = RasterliteOpenSQLiteDB(osFileName.c_str(), GA_Update);
 
             hRasterPyramidsLyr = OGR_DS_GetLayerByName(hDS, "raster_pyramids");
             if (hRasterPyramidsLyr == NULL)
@@ -672,11 +662,9 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
         /* Insert base resolution into raster_pyramids if not already done */
         int bHasBaseResolution = FALSE;
         osSQL.Printf("SELECT * FROM raster_pyramids WHERE "
-                     "table_prefix = '%s' AND pixel_x_size >= %.15f AND pixel_x_size <= %.15f AND "
-                     "pixel_y_size >= %.15f AND pixel_y_size <= %.15f",
+                     "table_prefix = '%s' AND %s",
                      osTableName.c_str(),
-                     padfXResolutions[0] - 1e-15, padfXResolutions[0] + 1e-15,
-                     padfYResolutions[0] - 1e-15, padfYResolutions[0] + 1e-15);
+                     RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]).c_str());
         hSQLLyr = OGR_DS_ExecuteSQL(hDS, osSQL.c_str(), NULL, NULL);
         if (hSQLLyr)
         {
@@ -691,12 +679,9 @@ CPLErr RasterliteDataset::CreateOverviewLevel(const char * pszResampling,
 
         if (!bHasBaseResolution)
         {
-            osSQL.Printf("SELECT COUNT(*) FROM \"%s\" WHERE "
-                          "pixel_x_size >= %.15f AND pixel_x_size <= %.15f AND "
-                          "pixel_y_size >= %.15f AND pixel_y_size <= %.15f",
+            osSQL.Printf("SELECT COUNT(*) FROM \"%s\" WHERE %s",
                           osMetatadataLayer.c_str(),
-                          padfXResolutions[0] - 1e-15, padfXResolutions[0] + 1e-15,
-                          padfYResolutions[0] - 1e-15, padfYResolutions[0] + 1e-15);
+                          RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]).c_str());
 
             int nBlocksMainRes = 0;
 
diff --git a/frmts/raw/GNUmakefile b/frmts/raw/GNUmakefile
index 914f764..b02c166 100644
--- a/frmts/raw/GNUmakefile
+++ b/frmts/raw/GNUmakefile
@@ -9,9 +9,9 @@ OBJ	=	rawdataset.o ehdrdataset.o pauxdataset.o doq1dataset.o \
 		idadataset.o ndfdataset.o dipxdataset.o genbindataset.o \
 		lcpdataset.o eirdataset.o gtxdataset.o loslasdataset.o \
 		ntv2dataset.o ace2dataset.o snodasdataset.o ctable2dataset.o \
-		krodataset.o
+		krodataset.o roipacdataset.o
+
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/raw/ace2dataset.cpp b/frmts/raw/ace2dataset.cpp
index f2ab309..d772fc6 100644
--- a/frmts/raw/ace2dataset.cpp
+++ b/frmts/raw/ace2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ace2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ace2dataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  ACE2 Driver
  * Purpose:  Implementation of ACE2 elevation format read support.
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: ace2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ace2dataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void    GDALRegister_ACE2(void);
@@ -385,6 +385,7 @@ void GDALRegister_ACE2()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "ACE2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "ACE2" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/raw/btdataset.cpp b/frmts/raw/btdataset.cpp
index 13041bb..13581fb 100644
--- a/frmts/raw/btdataset.cpp
+++ b/frmts/raw/btdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: btdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: btdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  VTP .bt Driver
  * Purpose:  Implementation of VTP .bt elevation format read/write support.
@@ -32,7 +32,7 @@
 #include "rawdataset.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: btdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: btdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void    GDALRegister_BT(void);
@@ -187,9 +187,10 @@ CPLErr BTRasterBand::IReadBlock( int nBlockXOff,
 /*                            IWriteBlock()                             */
 /************************************************************************/
 
-CPLErr BTRasterBand::IWriteBlock( int nBlockXOff, 
+CPLErr BTRasterBand::IWriteBlock( int nBlockXOff,
                                   CPL_UNUSED int nBlockYOff,
                                   void * pImage )
+
 {
     int nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
     GByte *pabyWrkBlock;
@@ -481,7 +482,7 @@ CPLErr BTDataset::SetProjection( const char *pszNewProjection )
 
         if( ABS(dfLinear - 0.3048) < 0.0000001 )
             nShortTemp = 2;
-        else if( ABS(dfLinear - atof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
+        else if( ABS(dfLinear - CPLAtof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
             nShortTemp = 3;
         else
             nShortTemp = 1;
@@ -569,7 +570,7 @@ GDALDataset *BTDataset::Open( GDALOpenInfo * poOpenInfo )
 
     strncpy( szVersion, (char *) (poDS->abyHeader + 7), 3 );
     szVersion[3] = '\0';
-    poDS->nVersionCode = (int) (atof(szVersion) * 10);
+    poDS->nVersionCode = (int) (CPLAtof(szVersion) * 10);
 
 /* -------------------------------------------------------------------- */
 /*      Extract core header information, being careful about the        */
@@ -677,9 +678,9 @@ GDALDataset *BTDataset::Open( GDALOpenInfo * poOpenInfo )
         if( nHUnits == 1 )
             oSRS.SetLinearUnits( SRS_UL_METER, 1.0 );
         else if( nHUnits == 2 )
-            oSRS.SetLinearUnits( SRS_UL_FOOT, atof(SRS_UL_FOOT_CONV) );
+            oSRS.SetLinearUnits( SRS_UL_FOOT, CPLAtof(SRS_UL_FOOT_CONV) );
         else if( nHUnits == 3 )
-            oSRS.SetLinearUnits( SRS_UL_US_FOOT, atof(SRS_UL_US_FOOT_CONV) );
+            oSRS.SetLinearUnits( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV) );
 
         // Translate some of the more obvious old USGS datum codes 
         if( nDatum == 0 )
@@ -807,10 +808,11 @@ GDALDataset *BTDataset::Open( GDALOpenInfo * poOpenInfo )
 /************************************************************************/
 
 GDALDataset *BTDataset::Create( const char * pszFilename,
-                                int nXSize, int nYSize, int nBands,
+                                int nXSize,
+                                int nYSize,
+                                int nBands,
                                 GDALDataType eType,
                                 CPL_UNUSED char ** papszOptions )
-
 {
 
 /* -------------------------------------------------------------------- */
@@ -942,6 +944,7 @@ void GDALRegister_BT()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "BT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "VTP .bt (Binary Terrain) 1.3 Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/raw/cpgdataset.cpp b/frmts/raw/cpgdataset.cpp
index 5ec2c9b..b5d760e 100644
--- a/frmts/raw/cpgdataset.cpp
+++ b/frmts/raw/cpgdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: cpgdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Polarimetric Workstation
  * Purpose:  Convair PolGASP data (.img/.hdr format). 
@@ -32,7 +32,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: cpgdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: cpgdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_CPG(void);
@@ -496,14 +496,14 @@ GDALDataset* CPGDataset::InitializeType1Or2Dataset( const char *pszFilename )
                  EQUAL(papszTokens[0],"reference") &&
                  EQUAL(papszTokens[1],"north") )
         {
-            dfnorth = atof(papszTokens[2]);
+            dfnorth = CPLAtof(papszTokens[2]);
             iUTMParamsFound++;
         }
         else if ( ( CSLCount( papszTokens ) >= 3 ) &&
                EQUAL(papszTokens[0],"reference") &&
                EQUAL(papszTokens[1],"east") )
         {
-            dfeast = atof(papszTokens[2]);
+            dfeast = CPLAtof(papszTokens[2]);
             iUTMParamsFound++;
         }  
         else if ( ( CSLCount( papszTokens ) >= 5 ) &&
@@ -547,24 +547,24 @@ GDALDataset* CPGDataset::InitializeType1Or2Dataset( const char *pszFilename )
         }
         else if( EQUAL(papszTokens[0],"altitude") )
         {
-            dfaltitude = atof(papszTokens[1]);
+            dfaltitude = CPLAtof(papszTokens[1]);
             iGeoParamsFound++;
         }
         else if( EQUAL(papszTokens[0],"near_srd") )
         {
-            dfnear_srd = atof(papszTokens[1]);
+            dfnear_srd = CPLAtof(papszTokens[1]);
             iGeoParamsFound++;
         }
 
         else if( EQUAL(papszTokens[0],"sample_size") )
         {
-            dfsample_size = atof(papszTokens[1]);
+            dfsample_size = CPLAtof(papszTokens[1]);
             iGeoParamsFound++;
             iUTMParamsFound++;
         }
         else if( EQUAL(papszTokens[0],"sample_size_az") )
         {
-            dfsample_size_az = atof(papszTokens[1]);
+            dfsample_size_az = CPLAtof(papszTokens[1]);
             iGeoParamsFound++;
             iUTMParamsFound++;
         }
@@ -884,16 +884,16 @@ GDALDataset *CPGDataset::InitializeType3Dataset( const char *pszFilename )
                  EQUAL(papszTokens[0],"project") &&
                  EQUAL(papszTokens[1],"origin:") )
         {
-            dfeast = atof(papszTokens[2]);
-            dfnorth = atof(papszTokens[3]);
+            dfeast = CPLAtof(papszTokens[2]);
+            dfnorth = CPLAtof(papszTokens[3]);
             iUTMParamsFound+=2;
         }
         else if ( ( CSLCount( papszTokens ) >= 4 ) &&
                EQUAL(papszTokens[0],"file") &&
                EQUAL(papszTokens[1],"start:"))
         {
-            dfOffsetX =  atof(papszTokens[2]);
-            dfOffsetY = atof(papszTokens[3]);
+            dfOffsetX =  CPLAtof(papszTokens[2]);
+            dfOffsetY = CPLAtof(papszTokens[3]);
             iUTMParamsFound+=2;
         }  
         else if ( ( CSLCount( papszTokens ) >= 6 ) &&
@@ -902,8 +902,8 @@ GDALDataset *CPGDataset::InitializeType3Dataset( const char *pszFilename )
                EQUAL(papszTokens[2],"on") &&
                EQUAL(papszTokens[3],"ground:"))
         {
-            dfxsize = atof(papszTokens[4]);
-            dfysize = atof(papszTokens[5]);
+            dfxsize = CPLAtof(papszTokens[4]);
+            dfysize = CPLAtof(papszTokens[5]);
             iUTMParamsFound+=2;
  
         }   
@@ -1264,9 +1264,9 @@ Im(SVV) = byte(10) ysca/127
 
 */
 
-CPLErr SIRC_QSLCRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void * pImage )
-
+CPLErr SIRC_QSLCRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                        int nBlockYOff,
+                                        void * pImage )
 {
     int	   offset, nBytesPerSample=10;
     GByte  *pabyRecord;
@@ -1417,8 +1417,9 @@ CPG_STOKESRasterBand::~CPG_STOKESRasterBand()
 
 /* Convert from Stokes to Covariance representation */
 
-CPLErr CPG_STOKESRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
-                                  void * pImage )
+CPLErr CPG_STOKESRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                         int nBlockYOff,
+                                         void * pImage )
 
 {
     int iPixel;
@@ -1689,6 +1690,7 @@ void GDALRegister_CPG()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "CPG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Convair PolGASP" );
 
diff --git a/frmts/raw/ctable2dataset.cpp b/frmts/raw/ctable2dataset.cpp
index 7a6472e..ea39ce9 100644
--- a/frmts/raw/ctable2dataset.cpp
+++ b/frmts/raw/ctable2dataset.cpp
@@ -326,10 +326,11 @@ const char *CTable2Dataset::GetProjectionRef()
 /************************************************************************/
 
 GDALDataset *CTable2Dataset::Create( const char * pszFilename,
-                                     int nXSize, int nYSize, CPL_UNUSED int nBands,
+                                     int nXSize,
+                                     int nYSize,
+                                     CPL_UNUSED int nBands,
                                      GDALDataType eType,
                                      char ** papszOptions )
-
 {
     if( eType != GDT_Float32 )
     {
@@ -443,6 +444,7 @@ void GDALRegister_CTable2()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "CTable2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "CTable2 Datum Grid Shift" );
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
@@ -457,4 +459,3 @@ void GDALRegister_CTable2()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/raw/dipxdataset.cpp b/frmts/raw/dipxdataset.cpp
index ea3e7ea..b47334d 100644
--- a/frmts/raw/dipxdataset.cpp
+++ b/frmts/raw/dipxdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dipxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: dipxdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implementation for ELAS DIPEx format variant.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: dipxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: dipxdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_DIPEx(void);
@@ -304,7 +304,7 @@ GDALDataset *DIPExDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -345,6 +345,7 @@ void GDALRegister_DIPEx()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DIPEx" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "DIPEx" );
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
diff --git a/frmts/raw/doq1dataset.cpp b/frmts/raw/doq1dataset.cpp
index 250ac99..76ef58d 100644
--- a/frmts/raw/doq1dataset.cpp
+++ b/frmts/raw/doq1dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: doq1dataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: doq1dataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  USGS DOQ Driver (First Generation Format)
  * Purpose:  Implementation of DOQ1Dataset
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: doq1dataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: doq1dataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 static double DOQGetField( unsigned char *, int );
 static void DOQGetDescription( GDALDataset *, unsigned char * );
@@ -347,6 +347,7 @@ void GDALRegister_DOQ1()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DOQ1" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "USGS DOQ (Old Style)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -378,7 +379,7 @@ static double DOQGetField( unsigned char *pabyData, int nBytes )
             szWork[i] = 'E';
     }
 
-    return atof(szWork);
+    return CPLAtof(szWork);
 }
 
 /************************************************************************/
diff --git a/frmts/raw/doq2dataset.cpp b/frmts/raw/doq2dataset.cpp
index c080f8e..aab6686 100644
--- a/frmts/raw/doq2dataset.cpp
+++ b/frmts/raw/doq2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: doq2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: doq2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  USGS DOQ Driver (Second Generation Format)
  * Purpose:  Implementation of DOQ2Dataset
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: doq2dataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: doq2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_DOQ2(void);
@@ -195,12 +195,12 @@ GDALDataset *DOQ2Dataset::Open( GDALOpenInfo * poOpenInfo )
         }
         else if( EQUAL(papszTokens[0],"XY_ORIGIN") && CSLCount(papszTokens) >= 3 )
         {
-            dfULXMap = atof(papszTokens[1]);
-            dfULYMap = atof(papszTokens[2]);
+            dfULXMap = CPLAtof(papszTokens[1]);
+            dfULYMap = CPLAtof(papszTokens[2]);
         }
         else if( EQUAL(papszTokens[0],"HORIZONTAL_RESOLUTION") )
         {
-            dfXDim = dfYDim = atof(papszTokens[1]);
+            dfXDim = dfYDim = CPLAtof(papszTokens[1]);
         }
 	else if( EQUAL(papszTokens[0],"BAND_ORGANIZATION") )
         {
@@ -432,6 +432,7 @@ void GDALRegister_DOQ2()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "DOQ2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "USGS DOQ (New Style)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/ehdrdataset.cpp b/frmts/raw/ehdrdataset.cpp
index f4f1cf2..bdf669d 100644
--- a/frmts/raw/ehdrdataset.cpp
+++ b/frmts/raw/ehdrdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ehdrdataset.cpp 27192 2014-04-16 09:59:42Z rouault $
+ * $Id: ehdrdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  ESRI .hdr Driver
  * Purpose:  Implementation of EHdrDataset
@@ -32,7 +32,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ehdrdataset.cpp 27192 2014-04-16 09:59:42Z rouault $");
+CPL_CVSID("$Id: ehdrdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_EHdr(void);
@@ -125,7 +125,9 @@ class EHdrRasterBand : public RawRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace,
+                              GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
   public:
     EHdrRasterBand( GDALDataset *poDS, int nBand, VSILFILE * fpRaw,
@@ -357,7 +359,9 @@ CPLErr EHdrRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace )
+                                  GSpacing nPixelSpace,
+                                  GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg )
 
 {
     // Defer to RawRasterBand
@@ -365,14 +369,14 @@ CPLErr EHdrRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return RawRasterBand::IRasterIO( eRWFlag, 
                                          nXOff, nYOff, nXSize, nYSize,
                                          pData, nBufXSize, nBufYSize, 
-                                         eBufType, nPixelSpace, nLineSpace );
+                                         eBufType, nPixelSpace, nLineSpace, psExtraArg );
 
     // Force use of IReadBlock() and IWriteBlock()
     else
         return GDALRasterBand::IRasterIO( eRWFlag, 
                                           nXOff, nYOff, nXSize, nYSize,
                                           pData, nBufXSize, nBufYSize, 
-                                          eBufType, nPixelSpace, nLineSpace );
+                                          eBufType, nPixelSpace, nLineSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -822,8 +826,8 @@ CPLErr EHdrDataset::ReadSTX()
             if (i > 0 && i <= nBands)
             {
               EHdrRasterBand* poBand = (EHdrRasterBand*)papoBands[i-1];
-              poBand->dfMin = atof(papszTokens[1]);
-              poBand->dfMax = atof(papszTokens[2]);
+              poBand->dfMin = CPLAtof(papszTokens[1]);
+              poBand->dfMax = CPLAtof(papszTokens[2]);
 
               int bNoDataSet = FALSE;
               double dfNoData = poBand->GetNoDataValue(&bNoDataSet);
@@ -842,12 +846,12 @@ CPLErr EHdrDataset::ReadSTX()
               // reads optional mean and stddev
               if ( !EQUAL(papszTokens[3], "#") )
               {
-                poBand->dfMean   = atof(papszTokens[3]);
+                poBand->dfMean   = CPLAtof(papszTokens[3]);
                 poBand->minmaxmeanstddev |= HAS_MEAN_FLAG;
               }
               if ( !EQUAL(papszTokens[4], "#") )
               {
-                poBand->dfStdDev = atof(papszTokens[4]);
+                poBand->dfStdDev = CPLAtof(papszTokens[4]);
                 poBand->minmaxmeanstddev |= HAS_STDDEV_FLAG;
               }
 
@@ -1001,15 +1005,16 @@ GDALDataset *EHdrDataset::Open( GDALOpenInfo * poOpenInfo )
         pszHeaderExt = "sch";
     }
 
-    if( poOpenInfo->papszSiblingFiles )
+    char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if( papszSiblingFiles )
     {
-        int iFile = CSLFindString(poOpenInfo->papszSiblingFiles, 
+        int iFile = CSLFindString(papszSiblingFiles, 
                                   CPLFormFilename( NULL, osName, pszHeaderExt ) );
         if( iFile < 0 ) // return if there is no corresponding .hdr file
             return NULL;
         
         osHDRFilename = 
-            CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile], 
+            CPLFormFilename( osPath, papszSiblingFiles[iFile], 
                              NULL );
     }
     else
@@ -2021,6 +2026,7 @@ void GDALRegister_EHdr()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "EHdr" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ESRI .hdr Labelled" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/eirdataset.cpp b/frmts/raw/eirdataset.cpp
index 15a4949..a3f96bd 100644
--- a/frmts/raw/eirdataset.cpp
+++ b/frmts/raw/eirdataset.cpp
@@ -571,6 +571,7 @@ void GDALRegister_EIR()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "EIR" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Erdas Imagine Raw" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/envidataset.cpp b/frmts/raw/envidataset.cpp
index 6de8f2c..b0b544c 100644
--- a/frmts/raw/envidataset.cpp
+++ b/frmts/raw/envidataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: envidataset.cpp 27366 2014-05-19 18:27:40Z rouault $
+ * $Id: envidataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  ENVI .hdr Driver
  * Purpose:  Implementation of ENVI .hdr labelled raw raster support.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include <algorithm>
 
-CPL_CVSID("$Id: envidataset.cpp 27366 2014-05-19 18:27:40Z rouault $");
+CPL_CVSID("$Id: envidataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void GDALRegister_ENVI(void);
@@ -368,8 +368,6 @@ void ENVIDataset::FlushCache()
     if ( band == NULL || !bHeaderDirty )
         return;
 
-    CPLLocaleC  oLocaleEnforcer;
-
     // If opening an existing file in Update mode (i.e. "r+") we need to make
     // sure any existing content is cleared, otherwise the file may contain
     // trailing content from the previous write.
@@ -1385,12 +1383,12 @@ int ENVIDataset::ProcessMapinfo( const char *pszMapinfo )
 /* -------------------------------------------------------------------- */
 /*      Capture geotransform.                                           */
 /* -------------------------------------------------------------------- */
-    adfGeoTransform[1] = atof(papszFields[5]);	    // Pixel width
-    adfGeoTransform[5] = -atof(papszFields[6]);	    // Pixel height
+    adfGeoTransform[1] = CPLAtof(papszFields[5]);	    // Pixel width
+    adfGeoTransform[5] = -CPLAtof(papszFields[6]);	    // Pixel height
     adfGeoTransform[0] =			    // Upper left X coordinate
-	atof(papszFields[3]) - (atof(papszFields[1]) - 1) * adfGeoTransform[1];
+	CPLAtof(papszFields[3]) - (CPLAtof(papszFields[1]) - 1) * adfGeoTransform[1];
     adfGeoTransform[3] =			    // Upper left Y coordinate
-	atof(papszFields[4]) - (atof(papszFields[2]) - 1) * adfGeoTransform[5];
+	CPLAtof(papszFields[4]) - (CPLAtof(papszFields[2]) - 1) * adfGeoTransform[5];
     adfGeoTransform[2] = 0.0;
     adfGeoTransform[4] = 0.0;
 
@@ -1538,7 +1536,7 @@ int ENVIDataset::ProcessMapinfo( const char *pszMapinfo )
     {
         /* Handle linear units first. */
         if (EQUAL(papszFields[nCount-1],"units=Feet") )
-            oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_FOOT, atof(SRS_UL_FOOT_CONV) );
+            oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_FOOT, CPLAtof(SRS_UL_FOOT_CONV) );
         else if (EQUAL(papszFields[nCount-1],"units=Meters") )
             oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_METER, 1. );
         else if (EQUAL(papszFields[nCount-1],"units=Km") )
@@ -1548,7 +1546,7 @@ int ENVIDataset::ProcessMapinfo( const char *pszMapinfo )
         else if (EQUAL(papszFields[nCount-1],"units=Miles") )
             oSRS.SetLinearUnitsAndUpdateParameters( "Mile", 1609.344 );
         else if (EQUAL(papszFields[nCount-1],"units=Nautical Miles") )
-            oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_NAUTICAL_MILE, atof(SRS_UL_NAUTICAL_MILE_CONV) );
+            oSRS.SetLinearUnitsAndUpdateParameters( SRS_UL_NAUTICAL_MILE, CPLAtof(SRS_UL_NAUTICAL_MILE_CONV) );
 	    
         /* Only handle angular units if we know the projection is geographic. */
         if (oSRS.IsGeographic()) 
@@ -1558,7 +1556,7 @@ int ENVIDataset::ProcessMapinfo( const char *pszMapinfo )
             else 
             {
                 /* Degrees, minutes and seconds will all be represented as degrees. */
-                oSRS.SetAngularUnits( SRS_UA_DEGREE,  atof(SRS_UA_DEGREE_CONV));
+                oSRS.SetAngularUnits( SRS_UA_DEGREE,  CPLAtof(SRS_UA_DEGREE_CONV));
 
                 double conversionFactor = 1.;
                 if (EQUAL(papszFields[nCount-1],"units=Minutes") )
@@ -1616,66 +1614,66 @@ void ENVIDataset::ProcessRPCinfo( const char *pszRPCinfo,
         return;
     }
 	
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[0]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[0]));
     SetMetadataItem("LINE_OFF",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[5]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[5]));
     SetMetadataItem("LINE_SCALE",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[1]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[1]));
     SetMetadataItem("SAMP_OFF",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[6]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[6]));
     SetMetadataItem("SAMP_SCALE",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[2]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[2]));
     SetMetadataItem("LAT_OFF",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[7]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[7]));
     SetMetadataItem("LAT_SCALE",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[3]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[3]));
     SetMetadataItem("LONG_OFF",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[8]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[8]));
     SetMetadataItem("LONG_SCALE",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[4]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[4]));
     SetMetadataItem("HEIGHT_OFF",sVal,"RPC");
-    snprintf(sVal, sizeof(sVal),  "%.16g",atof(papszFields[9]));
+    CPLsnprintf(sVal, sizeof(sVal),  "%.16g",CPLAtof(papszFields[9]));
     SetMetadataItem("HEIGHT_SCALE",sVal,"RPC");
 
     sVal[0] = '\0'; 
     int i;
     for(i = 0; i < 20; i++ )
-       snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ", 
-           atof(papszFields[10+i]));
+       CPLsnprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ", 
+           CPLAtof(papszFields[10+i]));
     SetMetadataItem("LINE_NUM_COEFF",sVal,"RPC");
 
     sVal[0] = '\0'; 
     for(i = 0; i < 20; i++ )
-       snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
-           atof(papszFields[30+i]));
+       CPLsnprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
+           CPLAtof(papszFields[30+i]));
     SetMetadataItem("LINE_DEN_COEFF",sVal,"RPC");
       
     sVal[0] = '\0'; 
     for(i = 0; i < 20; i++ )
-       snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
-           atof(papszFields[50+i]));
+       CPLsnprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
+           CPLAtof(papszFields[50+i]));
     SetMetadataItem("SAMP_NUM_COEFF",sVal,"RPC");
       
     sVal[0] = '\0'; 
     for(i = 0; i < 20; i++ )
-       snprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
-           atof(papszFields[70+i]));
+       CPLsnprintf(sVal+strlen(sVal), sizeof(sVal),  "%.16g ",
+           CPLAtof(papszFields[70+i]));
     SetMetadataItem("SAMP_DEN_COEFF",sVal,"RPC");
 	
-    snprintf(sVal, sizeof(sVal), "%.16g", 
-        atof(papszFields[3]) - atof(papszFields[8]));
+    CPLsnprintf(sVal, sizeof(sVal), "%.16g", 
+        CPLAtof(papszFields[3]) - CPLAtof(papszFields[8]));
     SetMetadataItem("MIN_LONG",sVal,"RPC");
 
-    snprintf(sVal, sizeof(sVal), "%.16g", 
-        atof(papszFields[3]) + atof(papszFields[8]) );
+    CPLsnprintf(sVal, sizeof(sVal), "%.16g", 
+        CPLAtof(papszFields[3]) + CPLAtof(papszFields[8]) );
     SetMetadataItem("MAX_LONG",sVal,"RPC");
 
-    snprintf(sVal, sizeof(sVal), "%.16g",
-        atof(papszFields[2]) - atof(papszFields[7]));
+    CPLsnprintf(sVal, sizeof(sVal), "%.16g",
+        CPLAtof(papszFields[2]) - CPLAtof(papszFields[7]));
     SetMetadataItem("MIN_LAT",sVal,"RPC");
 
-    snprintf(sVal, sizeof(sVal), "%.16g",
-        atof(papszFields[2]) + atof(papszFields[7]));
+    CPLsnprintf(sVal, sizeof(sVal), "%.16g",
+        CPLAtof(papszFields[2]) + CPLAtof(papszFields[7]));
     SetMetadataItem("MAX_LAT",sVal,"RPC");
 
     if (nCount == 93)
@@ -1687,8 +1685,8 @@ void ENVIDataset::ProcessRPCinfo( const char *pszRPCinfo,
 
     /*   Handle the chipping case where the image is a subset. */
     double rowOffset, colOffset;
-    rowOffset = (nCount == 93) ? atof(papszFields[90]) : 0;
-    colOffset = (nCount == 93) ? atof(papszFields[91]) : 0;
+    rowOffset = (nCount == 93) ? CPLAtof(papszFields[90]) : 0;
+    colOffset = (nCount == 93) ? CPLAtof(papszFields[91]) : 0;
     if (rowOffset || colOffset)
     {
         SetMetadataItem("ICHIP_SCALE_FACTOR", "1");
@@ -1699,23 +1697,23 @@ void ENVIDataset::ProcessRPCinfo( const char *pszRPCinfo,
         SetMetadataItem("ICHIP_OP_COL_11", "0.5");
         SetMetadataItem("ICHIP_OP_ROW_12", "0.5");
         SetMetadataItem("ICHIP_OP_COL_21", "0.5");
-        snprintf(sVal, sizeof(sVal), "%.16g", numCols - 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", numCols - 0.5);
         SetMetadataItem("ICHIP_OP_COL_12", sVal);
         SetMetadataItem("ICHIP_OP_COL_22", sVal);
-        snprintf(sVal, sizeof(sVal), "%.16g", numRows - 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", numRows - 0.5);
         SetMetadataItem("ICHIP_OP_ROW_21", sVal);
         SetMetadataItem("ICHIP_OP_ROW_22", sVal);
 
-        snprintf(sVal, sizeof(sVal), "%.16g", rowOffset + 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", rowOffset + 0.5);
         SetMetadataItem("ICHIP_FI_ROW_11", sVal);
         SetMetadataItem("ICHIP_FI_ROW_12", sVal);
-        snprintf(sVal, sizeof(sVal), "%.16g", colOffset + 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", colOffset + 0.5);
         SetMetadataItem("ICHIP_FI_COL_11", sVal);
         SetMetadataItem("ICHIP_FI_COL_21", sVal);
-        snprintf(sVal, sizeof(sVal), "%.16g", colOffset + numCols - 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", colOffset + numCols - 0.5);
         SetMetadataItem("ICHIP_FI_COL_12", sVal);
         SetMetadataItem("ICHIP_FI_COL_22", sVal);
-        snprintf(sVal, sizeof(sVal), "%.16g", rowOffset + numRows - 0.5);
+        CPLsnprintf(sVal, sizeof(sVal), "%.16g", rowOffset + numRows - 0.5);
         SetMetadataItem("ICHIP_FI_ROW_21", sVal);
         SetMetadataItem("ICHIP_FI_ROW_22", sVal);
     }
@@ -1933,7 +1931,8 @@ GDALDataset *ENVIDataset::Open( GDALOpenInfo * poOpenInfo )
     else
 	pszMode = "r";
     
-    if (poOpenInfo->papszSiblingFiles == NULL)
+    char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if (papszSiblingFiles == NULL)
     {
         osHdrFilename = CPLResetExtension( poOpenInfo->pszFilename, "hdr" );
         fpHeader = VSIFOpenL( osHdrFilename, pszMode );
@@ -1968,21 +1967,21 @@ GDALDataset *ENVIDataset::Open( GDALOpenInfo * poOpenInfo )
         CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
         CPLString osName = CPLGetFilename( poOpenInfo->pszFilename );
 
-        int iFile = CSLFindString(poOpenInfo->papszSiblingFiles, 
+        int iFile = CSLFindString(papszSiblingFiles, 
                                   CPLResetExtension( osName, "hdr" ) );
         if( iFile >= 0 )
         {
-            osHdrFilename = CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile], 
+            osHdrFilename = CPLFormFilename( osPath, papszSiblingFiles[iFile], 
                                              NULL );
             fpHeader = VSIFOpenL( osHdrFilename, pszMode );
         }
         else
         {
-            iFile = CSLFindString(poOpenInfo->papszSiblingFiles,
+            iFile = CSLFindString(papszSiblingFiles,
                                   CPLFormFilename( NULL, osName, "hdr" ));
             if( iFile >= 0 )
             {
-                osHdrFilename = CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile], 
+                osHdrFilename = CPLFormFilename( osPath, papszSiblingFiles[iFile], 
                                                  NULL );
                 fpHeader = VSIFOpenL( osHdrFilename, pszMode );
             }
@@ -2452,7 +2451,7 @@ GDALDataset *ENVIDataset::Open( GDALOpenInfo * poOpenInfo )
     if( CSLFetchNameValue(poDS->papszHeader,"data_ignore_value" ) != NULL )
     {
         for( i = 0; i < poDS->nBands; i++ )
-            ((RawRasterBand*)poDS->GetRasterBand(i+1))->SetNoDataValue(atof(
+            ((RawRasterBand*)poDS->GetRasterBand(i+1))->SetNoDataValue(CPLAtof(
                                                                              CSLFetchNameValue(poDS->papszHeader,"data_ignore_value")));
     }
 
@@ -2709,6 +2708,7 @@ void GDALRegister_ENVI()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "ENVI" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ENVI .hdr Labelled" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/fastdataset.cpp b/frmts/raw/fastdataset.cpp
index 2fd6127..fbc3621 100644
--- a/frmts/raw/fastdataset.cpp
+++ b/frmts/raw/fastdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fastdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: fastdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  EOSAT FAST Format reader
  * Purpose:  Reads Landsat FAST-L7A, IRS 1C/1D
@@ -33,7 +33,7 @@
 #include "ogr_spatialref.h"
 #include "rawdataset.h"
 
-CPL_CVSID("$Id: fastdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: fastdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_FAST(void);
@@ -1131,6 +1131,7 @@ void GDALRegister_FAST()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "FAST" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "EOSAT FAST Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/fujibasdataset.cpp b/frmts/raw/fujibasdataset.cpp
index 39de6fb..af2bb09 100644
--- a/frmts/raw/fujibasdataset.cpp
+++ b/frmts/raw/fujibasdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fujibasdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: fujibasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  eCognition
  * Purpose:  Implementation of FUJI BAS Format
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: fujibasdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: fujibasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_FujiBAS(void);
@@ -90,7 +90,7 @@ GDALDataset *FujiBASDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      We assume the user is pointing to the header (.pcb) file.       */
 /*      Does this appear to be a pcb file?                              */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->nHeaderBytes < 80 || poOpenInfo->fp == NULL )
+    if( poOpenInfo->nHeaderBytes < 80 || poOpenInfo->fpL == NULL )
         return NULL;
 
     if( !EQUALN((const char *)poOpenInfo->pabyHeader,"[Raw data]",10)
@@ -239,6 +239,7 @@ void GDALRegister_FujiBAS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "FujiBAS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Fuji BAS Scanner Image" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/genbindataset.cpp b/frmts/raw/genbindataset.cpp
index 4381420..7046953 100644
--- a/frmts/raw/genbindataset.cpp
+++ b/frmts/raw/genbindataset.cpp
@@ -257,7 +257,8 @@ GenBinBitRasterBand::GenBinBitRasterBand( GenBinDataset *poDS, int nBitsIn )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GenBinBitRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr GenBinBitRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                        int nBlockYOff,
                                         void * pImage )
 
 {
@@ -557,15 +558,16 @@ GDALDataset *GenBinDataset::Open( GDALOpenInfo * poOpenInfo )
     CPLString osName = CPLGetBasename( poOpenInfo->pszFilename );
     CPLString osHDRFilename;
 
-    if( poOpenInfo->papszSiblingFiles )
+    char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if( papszSiblingFiles )
     {
-        int iFile = CSLFindString(poOpenInfo->papszSiblingFiles, 
+        int iFile = CSLFindString(papszSiblingFiles, 
                                   CPLFormFilename( NULL, osName, "hdr" ) );
         if( iFile < 0 ) // return if there is no corresponding .hdr file
             return NULL;
 
         osHDRFilename = 
-            CPLFormFilename( osPath, poOpenInfo->papszSiblingFiles[iFile],
+            CPLFormFilename( osPath, papszSiblingFiles[iFile],
                              NULL );
     }
     else
@@ -887,6 +889,7 @@ void GDALRegister_GenBin()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GenBin" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Generic Binary (.hdr Labelled)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/gscdataset.cpp b/frmts/raw/gscdataset.cpp
index 0a79fb0..38112f1 100644
--- a/frmts/raw/gscdataset.cpp
+++ b/frmts/raw/gscdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gscdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gscdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  GSC Geogrid format driver.
  * Purpose:  Implements support for reading and writing GSC Geogrid format.
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gscdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gscdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -230,6 +230,7 @@ void GDALRegister_GSC()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GSC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "GSC Geogrid" );
 //        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/gtxdataset.cpp b/frmts/raw/gtxdataset.cpp
index f9410f9..b0efc30 100644
--- a/frmts/raw/gtxdataset.cpp
+++ b/frmts/raw/gtxdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gtxdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gtxdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Vertical Datum Transformation
  * Purpose:  Implementation of NOAA .gtx vertical datum shift file format.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: gtxdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: gtxdataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /**
 
@@ -314,10 +314,11 @@ const char *GTXDataset::GetProjectionRef()
 /************************************************************************/
 
 GDALDataset *GTXDataset::Create( const char * pszFilename,
-                                 int nXSize, int nYSize, CPL_UNUSED int nBands,
+                                 int nXSize,
+                                 int nYSize,
+                                 CPL_UNUSED int nBands,
                                  GDALDataType eType,
                                  CPL_UNUSED char ** papszOptions )
-
 {
     if( eType != GDT_Float32 )
     {
@@ -394,6 +395,7 @@ void GDALRegister_GTX()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "GTX" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NOAA Vertical Datum .GTX" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gtx" );
diff --git a/frmts/raw/hkvdataset.cpp b/frmts/raw/hkvdataset.cpp
index 109fde4..5bb67cd 100644
--- a/frmts/raw/hkvdataset.cpp
+++ b/frmts/raw/hkvdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hkvdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: hkvdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GView
  * Purpose:  Implementation of Atlantis HKV labelled blob support
@@ -34,7 +34,7 @@
 #include "ogr_spatialref.h"
 #include "atlsci_spheroid.h"
 
-CPL_CVSID("$Id: hkvdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: hkvdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_HKV(void);
@@ -461,7 +461,7 @@ CPLErr SaveHKVAttribFile( const char *pszFilenameIn,
 #endif
 
     if ( bNoDataSet )
-        fprintf( fp, "pixel.no_data = %f\n", dfNoDataValue );
+        fprintf( fp, "pixel.no_data = %s\n", CPLSPrintf("%f", dfNoDataValue) );
 
     /* version information- only create the new style */
     fprintf( fp, "version = 1.1");
@@ -600,11 +600,11 @@ CPLErr HKVDataset::SetGeoTransform( double * padfTransform )
 
     if (bSuccess)
     {
-        sprintf( szValue, "%.10f", temp_lat );
+        CPLsprintf( szValue, "%.10f", temp_lat );
         papszGeoref = CSLSetNameValue( papszGeoref, "top_left.latitude", 
                                        szValue );
 
-        sprintf( szValue, "%.10f", temp_long );
+        CPLsprintf( szValue, "%.10f", temp_long );
         papszGeoref = CSLSetNameValue( papszGeoref, "top_left.longitude", 
                                        szValue );
     }
@@ -643,11 +643,11 @@ CPLErr HKVDataset::SetGeoTransform( double * padfTransform )
 
     if (bSuccess)
     {
-        sprintf( szValue, "%.10f", temp_lat );
+        CPLsprintf( szValue, "%.10f", temp_lat );
         papszGeoref = CSLSetNameValue( papszGeoref, "top_right.latitude", 
                                        szValue );
 
-        sprintf( szValue, "%.10f", temp_long );
+        CPLsprintf( szValue, "%.10f", temp_long );
         papszGeoref = CSLSetNameValue( papszGeoref, "top_right.longitude", 
                                        szValue );
     }
@@ -686,11 +686,11 @@ CPLErr HKVDataset::SetGeoTransform( double * padfTransform )
 
     if (bSuccess)
     {
-        sprintf( szValue, "%.10f", temp_lat );
+        CPLsprintf( szValue, "%.10f", temp_lat );
         papszGeoref = CSLSetNameValue( papszGeoref, "bottom_left.latitude", 
                                        szValue );
 
-        sprintf( szValue, "%.10f", temp_long );
+        CPLsprintf( szValue, "%.10f", temp_long );
         papszGeoref = CSLSetNameValue( papszGeoref, "bottom_left.longitude", 
                                        szValue );
     }
@@ -734,11 +734,11 @@ CPLErr HKVDataset::SetGeoTransform( double * padfTransform )
 
     if (bSuccess)
     {
-        sprintf( szValue, "%.10f", temp_lat );
+        CPLsprintf( szValue, "%.10f", temp_lat );
         papszGeoref = CSLSetNameValue( papszGeoref, "bottom_right.latitude", 
                                        szValue );
 
-        sprintf( szValue, "%.10f", temp_long );
+        CPLsprintf( szValue, "%.10f", temp_long );
         papszGeoref = CSLSetNameValue( papszGeoref, "bottom_right.longitude", 
                                        szValue );
     }
@@ -781,11 +781,11 @@ CPLErr HKVDataset::SetGeoTransform( double * padfTransform )
 
     if (bSuccess)
     {
-        sprintf( szValue, "%.10f", temp_lat );
+        CPLsprintf( szValue, "%.10f", temp_lat );
         papszGeoref = CSLSetNameValue( papszGeoref, "centre.latitude", 
                                        szValue );
 
-        sprintf( szValue, "%.10f", temp_long );
+        CPLsprintf( szValue, "%.10f", temp_long );
         papszGeoref = CSLSetNameValue( papszGeoref, "centre.longitude", 
                                        szValue );
     }
@@ -867,7 +867,7 @@ CPLErr HKVDataset::SetProjection( const char * pszNewProjection )
       char *ol_txt;
         ol_txt=(char *) CPLMalloc(255);
         papszGeoref = CSLSetNameValue( papszGeoref, "projection.name", "utm" );
-        sprintf(ol_txt,"%f",oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0,&ogrerrorOl));
+        CPLsprintf(ol_txt,"%f",oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0,&ogrerrorOl));
         papszGeoref = CSLSetNameValue( papszGeoref, "projection.origin_longitude",
         ol_txt );
         CPLFree(ol_txt);
@@ -964,13 +964,13 @@ void HKVDataset::ProcessGeorefGCP( char **papszGeoref, const char *pszBase,
     if( CSLFetchNameValue(papszGeoref, szFieldName) == NULL )
         return;
     else
-        dfLat = atof(CSLFetchNameValue(papszGeoref, szFieldName));
+        dfLat = CPLAtof(CSLFetchNameValue(papszGeoref, szFieldName));
 
     sprintf( szFieldName, "%s.longitude", pszBase );
     if( CSLFetchNameValue(papszGeoref, szFieldName) == NULL )
         return;
     else
-        dfLong = atof(CSLFetchNameValue(papszGeoref, szFieldName));
+        dfLong = CPLAtof(CSLFetchNameValue(papszGeoref, szFieldName));
 
 /* -------------------------------------------------------------------- */
 /*      Add the gcp to the internal list.                               */
@@ -1098,7 +1098,7 @@ void HKVDataset::ProcessGeoref( const char * pszFilename )
 
     if( (pszProjName != NULL) && EQUAL(pszProjName,"utm") && (nGCPCount == 5) )
     {
-      /*int nZone = (int)((atof(pszOriginLong)+184.5) / 6.0); */
+      /*int nZone = (int)((CPLAtof(pszOriginLong)+184.5) / 6.0); */
         int nZone;
 
         if (pszOriginLong == NULL)
@@ -1109,7 +1109,7 @@ void HKVDataset::ProcessGeoref( const char * pszFilename )
             nZone = 31;
         }
         else
-            nZone = 31 + (int) floor(atof(pszOriginLong)/6.0);
+            nZone = 31 + (int) floor(CPLAtof(pszOriginLong)/6.0);
 
         OGRSpatialReference oUTM;
         OGRSpatialReference oLL;
@@ -1126,8 +1126,8 @@ void HKVDataset::ProcessGeoref( const char * pszFilename )
      
         if (pszOriginLong != NULL)
         {
-            oUTM.SetProjParm(SRS_PP_CENTRAL_MERIDIAN,atof(pszOriginLong));
-            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,atof(pszOriginLong));
+            oUTM.SetProjParm(SRS_PP_CENTRAL_MERIDIAN,CPLAtof(pszOriginLong));
+            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,CPLAtof(pszOriginLong));
         }
 
         if ((pszSpheroidName == NULL) || (EQUAL(pszSpheroidName,"wgs-84")) ||
@@ -1220,7 +1220,7 @@ void HKVDataset::ProcessGeoref( const char * pszFilename )
      
         if (pszOriginLong != NULL)
         {
-            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,atof(pszOriginLong));
+            oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,CPLAtof(pszOriginLong));
         }
 
         if ((pszSpheroidName == NULL) || (EQUAL(pszSpheroidName,"wgs-84")) ||
@@ -1376,7 +1376,7 @@ GDALDataset *HKVDataset::Open( GDALOpenInfo * poOpenInfo )
     if( pszValue != NULL )
     {
         bNoDataSet = TRUE;
-        dfNoDataValue = atof(pszValue);
+        dfNoDataValue = CPLAtof(pszValue);
     }
 
     pszValue = CSLFetchNameValue(papszAttrib,"channel.enumeration");
@@ -1402,7 +1402,7 @@ GDALDataset *HKVDataset::Open( GDALOpenInfo * poOpenInfo )
   
     if  (CSLFetchNameValue( papszAttrib, "version" ) != NULL)
       poDS->SetVersion((float)
-                       atof(CSLFetchNameValue(papszAttrib, "version")));
+                       CPLAtof(CSLFetchNameValue(papszAttrib, "version")));
     else
       poDS->SetVersion(1.0);
 
@@ -1713,10 +1713,12 @@ CPLErr HKVDataset::Delete( const char * pszName )
 /************************************************************************/
 
 GDALDataset *
-HKVDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                        CPL_UNUSED int bStrict, char ** papszOptions, 
-                        GDALProgressFunc pfnProgress, void * pProgressData )
-
+HKVDataset::CreateCopy( const char * pszFilename,
+                        GDALDataset *poSrcDS,
+                        CPL_UNUSED int bStrict,
+                        char ** papszOptions,
+                        GDALProgressFunc pfnProgress,
+                        void * pProgressData )
 {
     HKVDataset	*poDS;
     GDALDataType eType;
@@ -1812,7 +1814,7 @@ HKVDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
                 if( eErr != CE_None )
                 {
                     delete poDS;
@@ -1824,7 +1826,7 @@ HKVDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
 
                 if( eErr != CE_None )
                 {
@@ -1908,6 +1910,7 @@ void GDALRegister_HKV()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "MFF2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Vexcel MFF2 (HKV) Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/idadataset.cpp b/frmts/raw/idadataset.cpp
index 76b6bd0..c065649 100644
--- a/frmts/raw/idadataset.cpp
+++ b/frmts/raw/idadataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: idadataset.cpp 26117 2013-06-29 20:22:34Z rouault $
+ * $Id: idadataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  IDA Raster Driver
  * Purpose:  Implemenents IDA driver/dataset/rasterband.
@@ -31,7 +31,7 @@
 #include "ogr_spatialref.h"
 #include "gdal_rat.h"
 
-CPL_CVSID("$Id: idadataset.cpp 26117 2013-06-29 20:22:34Z rouault $");
+CPL_CVSID("$Id: idadataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void	GDALRegister_IDA(void);
@@ -68,7 +68,7 @@ class IDADataset : public RawDataset
     double      dfM;
     double      dfB;
 
-    FILE       *fpRaw;
+    VSILFILE   *fpRaw;
 
     char       *pszProjection;
     double      adfGeoTransform[6];
@@ -113,7 +113,7 @@ class IDARasterBand : public RawRasterBand
     GDALColorTable       *poColorTable;
 
   public:
-    		IDARasterBand( IDADataset *poDSIn, FILE *fpRaw, int nXSize );
+    		IDARasterBand( IDADataset *poDSIn, VSILFILE *fpRaw, int nXSize );
     virtual     ~IDARasterBand();
 
     virtual GDALRasterAttributeTable *GetDefaultRAT();
@@ -131,9 +131,9 @@ class IDARasterBand : public RawRasterBand
 /************************************************************************/
 
 IDARasterBand::IDARasterBand( IDADataset *poDSIn,
-                              FILE *fpRaw, int nXSize )
+                              VSILFILE *fpRaw, int nXSize )
         : RawRasterBand( poDSIn, 1, fpRaw, 512, 1, nXSize, 
-                         GDT_Byte, FALSE, FALSE )
+                         GDT_Byte, FALSE, TRUE )
 
 {
     poColorTable = NULL;
@@ -313,7 +313,7 @@ IDADataset::~IDADataset()
     FlushCache();
 
     if( fpRaw != NULL )
-        VSIFClose( fpRaw );
+        VSIFCloseL( fpRaw );
     CPLFree( pszProjection );
 }
 
@@ -392,8 +392,8 @@ void IDADataset::FlushCache()
     
     if( bHeaderDirty )
     {
-        VSIFSeek( fpRaw, 0, SEEK_SET );
-        VSIFWrite( abyHeader, 512, 1, fpRaw );
+        VSIFSeekL( fpRaw, 0, SEEK_SET );
+        VSIFWriteL( abyHeader, 512, 1, fpRaw );
         bHeaderDirty = FALSE;
     }
 }
@@ -687,7 +687,7 @@ GDALDataset *IDADataset::Open( GDALOpenInfo * poOpenInfo )
     int      nXSize, nYSize;
     GIntBig  nExpectedFileSize, nActualFileSize;
 
-    if( poOpenInfo->fp == NULL )
+    if( poOpenInfo->fpL == NULL )
         return NULL;
 
     if( poOpenInfo->nHeaderBytes < 512 )
@@ -713,9 +713,9 @@ GDALDataset *IDADataset::Open( GDALOpenInfo * poOpenInfo )
     // The file just be exactly the image size + header size in length.
     nExpectedFileSize = nXSize * nYSize + 512;
     
-    VSIFSeek( poOpenInfo->fp, 0, SEEK_END );
-    nActualFileSize = VSIFTell( poOpenInfo->fp );
-    VSIRewind( poOpenInfo->fp );
+    VSIFSeekL( poOpenInfo->fpL, 0, SEEK_END );
+    nActualFileSize = VSIFTellL( poOpenInfo->fpL );
+    VSIRewindL( poOpenInfo->fpL );
     
     if( nActualFileSize != nExpectedFileSize )
         return NULL;
@@ -896,12 +896,12 @@ CALCULATED =200
 /* -------------------------------------------------------------------- */
     if( poOpenInfo->eAccess == GA_ReadOnly )
     {
-        poDS->fpRaw = poOpenInfo->fp;
-        poOpenInfo->fp = NULL;
+        poDS->fpRaw = poOpenInfo->fpL;
+        poOpenInfo->fpL = NULL;
     }
     else
     {
-        poDS->fpRaw = VSIFOpen( poOpenInfo->pszFilename, "rb+" );
+        poDS->fpRaw = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
         poDS->eAccess = GA_Update;
         if( poDS->fpRaw == NULL )
         {
@@ -1111,12 +1111,15 @@ void GDALRegister_IDA()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "IDA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Image Data and Analysis" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
                                    "frmt_various.html#IDA" );
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
 
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
         poDriver->pfnOpen = IDADataset::Open;
         poDriver->pfnCreate = IDADataset::Create;
 
diff --git a/frmts/raw/krodataset.cpp b/frmts/raw/krodataset.cpp
index 5a7e4d8..86f468f 100644
--- a/frmts/raw/krodataset.cpp
+++ b/frmts/raw/krodataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: krodataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: krodataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  KRO format reader/writer
  * Purpose:  Implementation of KOLOR Raw Format
@@ -31,7 +31,7 @@
 #include "rawdataset.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: krodataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: krodataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /* http://www.autopano.net/wiki-en/Format_KRO */
 
@@ -220,7 +220,9 @@ GDALDataset *KRODataset::Open( GDALOpenInfo * poOpenInfo )
 /************************************************************************/
 
 GDALDataset *KRODataset::Create( const char * pszFilename,
-                                 int nXSize, int nYSize, int nBands,
+                                 int nXSize,
+                                 int nYSize,
+                                 int nBands,
                                  GDALDataType eType,
                                  CPL_UNUSED char ** papszOptions )
 {
@@ -300,6 +302,7 @@ void GDALRegister_KRO()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "KRO" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "KOLOR Raw" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "kro" );
diff --git a/frmts/raw/landataset.cpp b/frmts/raw/landataset.cpp
index 1f3f906..b0bd156 100644
--- a/frmts/raw/landataset.cpp
+++ b/frmts/raw/landataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: landataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: landataset.cpp 28435 2015-02-07 14:35:34Z rouault $
  *
  * Project:  eCognition
  * Purpose:  Implementation of Erdas .LAN / .GIS format.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: landataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: landataset.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 CPL_C_START
 void	GDALRegister_LAN(void);
@@ -200,7 +200,8 @@ LAN4BitRasterBand::~LAN4BitRasterBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr LAN4BitRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr LAN4BitRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                      int nBlockYOff,
                                       void * pImage )
 
 {
@@ -415,26 +416,40 @@ GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
 
     if( EQUALN(poDS->pachHeader,"HEADER",7) )
     {
-        poDS->nRasterXSize = (int) *((float *) (poDS->pachHeader + 16));
-        poDS->nRasterYSize = (int) *((float *) (poDS->pachHeader + 20));
+        float fTmp;
+        memcpy(&fTmp, poDS->pachHeader + 16, 4);
+        CPL_LSBPTR32(&fTmp);
+        poDS->nRasterXSize = (int) fTmp;
+        memcpy(&fTmp, poDS->pachHeader + 20, 4);
+        CPL_LSBPTR32(&fTmp);
+        poDS->nRasterYSize = (int) fTmp;
     }
     else
     {
-        poDS->nRasterXSize = *((GInt32 *) (poDS->pachHeader + 16));
-        poDS->nRasterYSize = *((GInt32 *) (poDS->pachHeader + 20));
+        GInt32 nTmp;
+        memcpy(&nTmp, poDS->pachHeader + 16, 4);
+        CPL_LSBPTR32(&nTmp);
+        poDS->nRasterXSize = nTmp;
+        memcpy(&nTmp, poDS->pachHeader + 20, 4);
+        CPL_LSBPTR32(&nTmp);
+        poDS->nRasterYSize = nTmp;
     }
 
-    if( *((GInt16 *) (poDS->pachHeader + 6)) == 0 )
+    GInt16 nTmp16;
+    memcpy(&nTmp16, poDS->pachHeader + 6, 2);
+    CPL_LSBPTR16(&nTmp16);
+
+    if( nTmp16 == 0 )
     {
         eDataType = GDT_Byte;
         nPixelOffset = 1;
     }
-    else if( *((GInt16 *) (poDS->pachHeader + 6)) == 1 ) /* 4bit! */
+    else if( nTmp16 == 1 ) /* 4bit! */
     {
         eDataType = GDT_Byte;
         nPixelOffset = -1;
     }
-    else if( *((GInt16 *) (poDS->pachHeader + 6)) == 2 )
+    else if( nTmp16 == 2 )
     {
         nPixelOffset = 2;
         eDataType = GDT_Int16;
@@ -443,13 +458,15 @@ GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
                   "Unsupported pixel type (%d).", 
-                  *((GInt16 *) (poDS->pachHeader + 6)) );
+                  nTmp16 );
                   
         delete poDS;
         return NULL;
     }
 
-    nBandCount = *((GInt16 *) (poDS->pachHeader + 8));
+    memcpy(&nTmp16, poDS->pachHeader + 8, 2);
+    CPL_LSBPTR16(&nTmp16);
+    nBandCount = nTmp16;
 
     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
         !GDALCheckBandCount(nBandCount, FALSE))
@@ -492,12 +509,22 @@ GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Try to interprete georeferencing.                               */
 /* -------------------------------------------------------------------- */
-    poDS->adfGeoTransform[0] = *((float *) (poDS->pachHeader + 112));
-    poDS->adfGeoTransform[1] = *((float *) (poDS->pachHeader + 120));
+    float fTmp;
+
+    memcpy(&fTmp, poDS->pachHeader + 112, 4);
+    CPL_LSBPTR32(&fTmp);
+    poDS->adfGeoTransform[0] = fTmp;
+    memcpy(&fTmp, poDS->pachHeader + 120, 4);
+    CPL_LSBPTR32(&fTmp);
+    poDS->adfGeoTransform[1] = fTmp;
     poDS->adfGeoTransform[2] = 0.0;
-    poDS->adfGeoTransform[3] = *((float *) (poDS->pachHeader + 116));
+    memcpy(&fTmp, poDS->pachHeader + 116, 4);
+    CPL_LSBPTR32(&fTmp);
+    poDS->adfGeoTransform[3] = fTmp;
     poDS->adfGeoTransform[4] = 0.0;
-    poDS->adfGeoTransform[5] = - *((float *) (poDS->pachHeader + 124));
+    memcpy(&fTmp, poDS->pachHeader + 124, 4);
+    CPL_LSBPTR32(&fTmp);
+    poDS->adfGeoTransform[5] = - fTmp;
 
     // adjust for center of pixel vs. top left corner of pixel.
     poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
@@ -518,7 +545,9 @@ GDALDataset *LANDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Try to come up with something for the coordinate system.        */
 /* -------------------------------------------------------------------- */
-    int nCoordSys = *((GInt16 *) (poDS->pachHeader + 88));
+    memcpy(&nTmp16, poDS->pachHeader + 88, 2);
+    CPL_LSBPTR16(&nTmp16);
+    int nCoordSys = nTmp16;
 
     if( nCoordSys == 0 )
     {
@@ -848,10 +877,11 @@ void LANDataset::CheckForStatistics()
 /************************************************************************/
 
 GDALDataset *LANDataset::Create( const char * pszFilename,
-                                 int nXSize, int nYSize, int nBands,
+                                 int nXSize,
+                                 int nYSize,
+                                 int nBands,
                                  GDALDataType eType,
                                  CPL_UNUSED char ** papszOptions )
-
 {
     if( eType != GDT_Byte && eType != GDT_Int16 )
     {
@@ -997,6 +1027,7 @@ void GDALRegister_LAN()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "LAN" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Erdas .LAN/.GIS" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -1011,4 +1042,3 @@ void GDALRegister_LAN()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/raw/lcpdataset.cpp b/frmts/raw/lcpdataset.cpp
index 4914836..ac48c08 100644
--- a/frmts/raw/lcpdataset.cpp
+++ b/frmts/raw/lcpdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: lcpdataset.cpp 27050 2014-03-18 00:09:03Z kyle $
+ * $Id: lcpdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  LCP Driver
  * Purpose:  FARSITE v.4 Landscape file (.lcp) reader for GDAL
@@ -7,8 +7,8 @@
  *
  ******************************************************************************
  * Copyright (c) 2008, Chris Toney
- * Copyright (c) 2008-2011, Even Rouault <even dot rouault at mines-paris dot org>
- * Copyright (c) 2013, Kyle Shannon <kyle at pobox dot com>
+ * Copyright (c) 2008-2011, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2013, Kyle Shannon <kyle at pobox dot com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: lcpdataset.cpp 27050 2014-03-18 00:09:03Z kyle $");
+CPL_CVSID("$Id: lcpdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_LCP(void);
@@ -753,7 +753,7 @@ GDALDataset *LCPDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     CPLFree(pszList);
 
@@ -814,7 +814,7 @@ CPLErr LCPDataset::ClassifyBandData( GDALRasterBand *poBand,
     {
         eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
                                  panValues, nXSize, 1, 
-                                 GDT_Int16, 0, 0 );
+                                 GDT_Int16, 0, 0, NULL );
         for( int iPixel = 0; iPixel < nXSize; iPixel++ )
         {
             if( panValues[iPixel] == -9999 )
@@ -1304,7 +1304,7 @@ GDALDataset *LCPDataset::CreateCopy( const char * pszFilename,
             pszUnit = oSrcSRS.GetAttrValue( "UNIT", 1 );
             if( pszUnit != NULL )
             {
-                double dfScale = atof( pszUnit );
+                double dfScale = CPLAtof( pszUnit );
                 if( dfScale != 1.0 )
                 {
                     if( bStrict )
@@ -1607,7 +1607,7 @@ GDALDataset *LCPDataset::CreateCopy( const char * pszFilename,
             GDALRasterBand * poBand = poSrcDS->GetRasterBand( iBand+1 );
             eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1,
                                      panScanline + iBand, nXSize, 1, GDT_Int16,
-                                     nBands * 2, nBands * nXSize * 2 );
+                                     nBands * 2, nBands * nXSize * 2, NULL );
             /* Not sure what to do here */
             if( eErr != CE_None )
             {
@@ -1704,6 +1704,7 @@ void GDALRegister_LCP()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "LCP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "FARSITE v.4 Landscape File (.lcp)" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "lcp" );
diff --git a/frmts/raw/loslasdataset.cpp b/frmts/raw/loslasdataset.cpp
index 1bbc74e..52c2368 100644
--- a/frmts/raw/loslasdataset.cpp
+++ b/frmts/raw/loslasdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: loslasdataset.cpp 20996 2010-10-28 18:38:15Z rouault $
+ * $Id: loslasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Horizontal Datum Formats
  * Purpose:  Implementation of NOAA/NADCON los/las datum shift format.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: loslasdataset.cpp 20996 2010-10-28 18:38:15Z rouault $");
+CPL_CVSID("$Id: loslasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /**
 
@@ -273,6 +273,7 @@ void GDALRegister_LOSLAS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "LOSLAS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NADCON .los/.las Datum Grid Shift" );
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
diff --git a/frmts/raw/makefile.vc b/frmts/raw/makefile.vc
index 0f18321..0d7cd72 100644
--- a/frmts/raw/makefile.vc
+++ b/frmts/raw/makefile.vc
@@ -7,7 +7,7 @@ OBJ	=	rawdataset.obj ehdrdataset.obj pauxdataset.obj doq1dataset.obj\
 		ndfdataset.obj dipxdataset.obj genbindataset.obj \
 		lcpdataset.obj eirdataset.obj gtxdataset.obj loslasdataset.obj \
 		ntv2dataset.obj ace2dataset.obj snodasdataset.obj \
-		ctable2dataset.obj krodataset.obj
+		ctable2dataset.obj krodataset.obj roipacdataset.obj
 
 GDAL_ROOT	=	..\..
 
diff --git a/frmts/raw/mffdataset.cpp b/frmts/raw/mffdataset.cpp
index 4725d75..754725e 100644
--- a/frmts/raw/mffdataset.cpp
+++ b/frmts/raw/mffdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: mffdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: mffdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GView
  * Purpose:  Implementation of Atlantis MFF Support
@@ -34,7 +34,7 @@
 #include "ogr_spatialref.h"
 #include "atlsci_spheroid.h"
 
-CPL_CVSID("$Id: mffdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: mffdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_MFF(void);
@@ -421,9 +421,9 @@ void MFFDataset::ScanForGCPs()
             pasGCPList[nGCPCount].pszId = CPLStrdup( pszBase );
                 
             pasGCPList[nGCPCount].dfGCPX = 
-                atof(CSLFetchNameValue(papszHdrLines, szLongName));
+                CPLAtof(CSLFetchNameValue(papszHdrLines, szLongName));
             pasGCPList[nGCPCount].dfGCPY = 
-                atof(CSLFetchNameValue(papszHdrLines, szLatName));
+                CPLAtof(CSLFetchNameValue(papszHdrLines, szLatName));
             pasGCPList[nGCPCount].dfGCPZ = 0.0;
 
             pasGCPList[nGCPCount].dfGCPPixel = dfRasterX;
@@ -461,11 +461,11 @@ void MFFDataset::ScanForGCPs()
             CPLFree( pasGCPList[nGCPCount].pszId );
             pasGCPList[nGCPCount].pszId = CPLStrdup( szName );
 
-            pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[3]);
-            pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[2]);
+            pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[3]);
+            pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[2]);
             pasGCPList[nGCPCount].dfGCPZ = 0.0;
-            pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[1])+0.5;
-            pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[0])+0.5;
+            pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[1])+0.5;
+            pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[0])+0.5;
 
             nGCPCount++;
         }
@@ -526,7 +526,7 @@ void MFFDataset::ScanForProjectionInfo()
             nZone = 31;
         }
         else
-            nZone = 31 + (int) floor(atof(pszOriginLong)/6.0);
+            nZone = 31 + (int) floor(CPLAtof(pszOriginLong)/6.0);
 
 
         if( nGCPCount >= 5 && pasGCPList[4].dfGCPY < 0 )
@@ -535,12 +535,12 @@ void MFFDataset::ScanForProjectionInfo()
             oProj.SetUTM( nZone, 1 );
      
         if (pszOriginLong != NULL)
-            oProj.SetProjParm(SRS_PP_CENTRAL_MERIDIAN,atof(pszOriginLong));
+            oProj.SetProjParm(SRS_PP_CENTRAL_MERIDIAN,CPLAtof(pszOriginLong));
         
     }
 
     if (pszOriginLong != NULL)
-        oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,atof(pszOriginLong));
+        oLL.SetProjParm(SRS_PP_LONGITUDE_OF_ORIGIN,CPLAtof(pszOriginLong));
 
     if (pszSpheroidName == NULL)
     {
@@ -571,8 +571,8 @@ void MFFDataset::ScanForProjectionInfo()
                                                   "SPHEROID_POLAR_RADIUS");
           if ((pszSpheroidEqRadius != NULL) && (pszSpheroidPolarRadius != NULL))
           {
-            eq_radius = atof( pszSpheroidEqRadius );
-            polar_radius = atof( pszSpheroidPolarRadius );
+            eq_radius = CPLAtof( pszSpheroidEqRadius );
+            polar_radius = CPLAtof( pszSpheroidPolarRadius );
             oProj.SetGeogCS( "unknown","unknown","unknown",
                          eq_radius, eq_radius/(eq_radius - polar_radius));
             oLL.SetGeogCS( "unknown","unknown","unknown",
@@ -692,7 +692,7 @@ GDALDataset *MFFDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      We assume the user is pointing to the header file.              */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->nHeaderBytes < 17 || poOpenInfo->fp == NULL )
+    if( poOpenInfo->nHeaderBytes < 17 || poOpenInfo->fpL == NULL )
         return NULL;
 
     if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"hdr") )
@@ -1142,12 +1142,12 @@ GDALDataset *MFFDataset::Create( const char * pszFilenameIn,
 /* -------------------------------------------------------------------- */
 /*      Create the header file.                                         */
 /* -------------------------------------------------------------------- */
-    FILE       *fp;
+    VSILFILE       *fp;
     const char *pszFilename;
 
     pszFilename = CPLFormFilename( NULL, pszBaseFilename, "hdr" );
 
-    fp = VSIFOpen( pszFilename, "wt" );
+    fp = VSIFOpenL( pszFilename, "wt" );
     if( fp == NULL )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -1156,20 +1156,20 @@ GDALDataset *MFFDataset::Create( const char * pszFilenameIn,
         return NULL;
     }
 
-    fprintf( fp, "IMAGE_FILE_FORMAT = MFF\n" );
-    fprintf( fp, "FILE_TYPE = IMAGE\n" );
-    fprintf( fp, "IMAGE_LINES = %d\n", nYSize );
-    fprintf( fp, "LINE_SAMPLES = %d\n", nXSize );
+    VSIFPrintfL( fp, "IMAGE_FILE_FORMAT = MFF\n" );
+    VSIFPrintfL( fp, "FILE_TYPE = IMAGE\n" );
+    VSIFPrintfL( fp, "IMAGE_LINES = %d\n", nYSize );
+    VSIFPrintfL( fp, "LINE_SAMPLES = %d\n", nXSize );
 #ifdef CPL_MSB     
-    fprintf( fp, "BYTE_ORDER = MSB\n" );
+    VSIFPrintfL( fp, "BYTE_ORDER = MSB\n" );
 #else
-    fprintf( fp, "BYTE_ORDER = LSB\n" );
+    VSIFPrintfL( fp, "BYTE_ORDER = LSB\n" );
 #endif
 
     if (CSLFetchNameValue(papszParmList,"NO_END") == NULL)
-        fprintf( fp, "END\n" );
+        VSIFPrintfL( fp, "END\n" );
     
-    VSIFClose( fp );
+    VSIFCloseL( fp );
    
 /* -------------------------------------------------------------------- */
 /*      Create the data files, but don't bother writing any data to them.*/
@@ -1190,7 +1190,7 @@ GDALDataset *MFFDataset::Create( const char * pszFilenameIn,
             sprintf( szExtension, "x%02d", iBand );
 
         pszFilename = CPLFormFilename( NULL, pszBaseFilename, szExtension );
-        fp = VSIFOpen( pszFilename, "wb" );
+        fp = VSIFOpenL( pszFilename, "wb" );
         if( fp == NULL )
         {
             CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -1199,8 +1199,8 @@ GDALDataset *MFFDataset::Create( const char * pszFilenameIn,
             return NULL;
         }
 
-        VSIFWrite( (void *) "", 1, 1, fp );
-        VSIFClose( fp );
+        VSIFWriteL( (void *) "", 1, 1, fp );
+        VSIFCloseL( fp );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1220,10 +1220,12 @@ GDALDataset *MFFDataset::Create( const char * pszFilenameIn,
 /************************************************************************/
 
 GDALDataset *
-MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                        CPL_UNUSED int bStrict, char ** papszOptions, 
-                        GDALProgressFunc pfnProgress, void * pProgressData )
-
+MFFDataset::CreateCopy( const char * pszFilename,
+                        GDALDataset *poSrcDS,
+                        CPL_UNUSED int bStrict,
+                        char ** papszOptions,
+                        GDALProgressFunc pfnProgress,
+                        void * pProgressData )
 {
     MFFDataset	*poDS;
     GDALDataType eType;
@@ -1320,7 +1322,7 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
                 if( eErr != CE_None )
                 {
                     delete poDS;
@@ -1332,7 +1334,7 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                                             iXOffset, iYOffset, 
                                             nTBXSize, nTBYSize,
                                             pData, nTBXSize, nTBYSize,
-                                            eType, 0, 0 );
+                                            eType, 0, 0, NULL );
 
                 if( eErr != CE_None )
                 {
@@ -1356,7 +1358,7 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 /* -------------------------------------------------------------------- */
     char	*pszBaseFilename;
     int         i;
-    FILE       *fp;
+    VSILFILE       *fp;
     const char *pszFilenameGEO;
 
     pszBaseFilename = (char *) CPLMalloc(strlen(pszFilename)+5);
@@ -1376,7 +1378,7 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
 
     pszFilenameGEO = CPLFormFilename( NULL, pszBaseFilename, "hdr" );
 
-    fp = VSIFOpen( pszFilenameGEO, "at" );
+    fp = VSIFOpenL( pszFilenameGEO, "at" );
     if( fp == NULL )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -1480,28 +1482,28 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     /* -------------------------------------------------------------------- */
     /*      top left                                                        */
     /* -------------------------------------------------------------------- */
-          fprintf( fp, "TOP_LEFT_CORNER_LATITUDE = %.10f\n", padfTiepoints[1] );
-          fprintf( fp, "TOP_LEFT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[0] );
+          VSIFPrintfL( fp, "TOP_LEFT_CORNER_LATITUDE = %.10f\n", padfTiepoints[1] );
+          VSIFPrintfL( fp, "TOP_LEFT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[0] );
     /* -------------------------------------------------------------------- */
     /*      top_right                                                       */
     /* -------------------------------------------------------------------- */
-          fprintf( fp, "TOP_RIGHT_CORNER_LATITUDE = %.10f\n", padfTiepoints[3] );
-          fprintf( fp, "TOP_RIGHT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[2] );
+          VSIFPrintfL( fp, "TOP_RIGHT_CORNER_LATITUDE = %.10f\n", padfTiepoints[3] );
+          VSIFPrintfL( fp, "TOP_RIGHT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[2] );
     /* -------------------------------------------------------------------- */
     /*      bottom_left                                                     */
     /* -------------------------------------------------------------------- */
-          fprintf( fp, "BOTTOM_LEFT_CORNER_LATITUDE = %.10f\n", padfTiepoints[5] );
-          fprintf( fp, "BOTTOM_LEFT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[4] );
+          VSIFPrintfL( fp, "BOTTOM_LEFT_CORNER_LATITUDE = %.10f\n", padfTiepoints[5] );
+          VSIFPrintfL( fp, "BOTTOM_LEFT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[4] );
     /* -------------------------------------------------------------------- */
     /*      bottom_right                                                    */
     /* -------------------------------------------------------------------- */
-          fprintf( fp, "BOTTOM_RIGHT_CORNER_LATITUDE = %.10f\n", padfTiepoints[7] );
-          fprintf( fp, "BOTTOM_RIGHT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[6] );
+          VSIFPrintfL( fp, "BOTTOM_RIGHT_CORNER_LATITUDE = %.10f\n", padfTiepoints[7] );
+          VSIFPrintfL( fp, "BOTTOM_RIGHT_CORNER_LONGITUDE = %.10f\n", padfTiepoints[6] );
     /* -------------------------------------------------------------------- */
     /*      Center                                                          */
     /* -------------------------------------------------------------------- */
-          fprintf( fp, "CENTRE_LATITUDE = %.10f\n", padfTiepoints[9] );
-          fprintf( fp, "CENTRE_LONGITUDE = %.10f\n", padfTiepoints[8] );
+          VSIFPrintfL( fp, "CENTRE_LATITUDE = %.10f\n", padfTiepoints[9] );
+          VSIFPrintfL( fp, "CENTRE_LONGITUDE = %.10f\n", padfTiepoints[8] );
     /* ------------------------------------------------------------------- */
     /*     Ellipsoid/projection                                            */
     /* --------------------------------------------------------------------*/
@@ -1531,19 +1533,19 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
              if ((oSRS.GetAttrValue("PROJECTION") != NULL) && 
                  (EQUAL(oSRS.GetAttrValue("PROJECTION"),SRS_PT_TRANSVERSE_MERCATOR)))
              {
-                 fprintf(fp,"PROJECTION_NAME = UTM\n");
-                 fprintf(fp,"PROJECTION_ORIGIN_LONGITUDE = %f\n",
+                 VSIFPrintfL(fp,"PROJECTION_NAME = UTM\n");
+                 VSIFPrintfL(fp,"PROJECTION_ORIGIN_LONGITUDE = %f\n",
                          oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0,&ogrerrorOl));
              }
              else if ((oSRS.GetAttrValue("PROJECTION") == NULL) && (oSRS.IsGeographic()))
              {
-                  fprintf(fp,"PROJECTION_NAME = LL\n");
+                  VSIFPrintfL(fp,"PROJECTION_NAME = LL\n");
              }
              else
              {
                   CPLError( CE_Warning, CPLE_AppDefined,
                   "Unrecognized projection- no georeferencing information transferred.");
-                  fprintf(fp,"PROJECTION_NAME = LL\n");
+                  VSIFPrintfL(fp,"PROJECTION_NAME = LL\n");
              }
              eq_radius = oSRS.GetSemiMajor(&ogrerrorEq);
              inv_flattening = oSRS.GetInvFlattening(&ogrerrorInvf);
@@ -1553,11 +1555,11 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
                  spheroid_name = mffEllipsoids->GetSpheroidNameByEqRadiusAndInvFlattening(eq_radius,inv_flattening);
                  if (spheroid_name != NULL)
                  {
-                     fprintf(fp,"SPHEROID_NAME = %s\n",spheroid_name );
+                     VSIFPrintfL(fp,"SPHEROID_NAME = %s\n",spheroid_name );
                  } 
                  else
                  {
-                     fprintf(fp,
+                     VSIFPrintfL(fp,
        "SPHEROID_NAME = USER_DEFINED\nSPHEROID_EQUATORIAL_RADIUS = %.10f\nSPHEROID_POLAR_RADIUS = %.10f\n",
                      eq_radius,eq_radius*(1-1.0/inv_flattening) );
                  }
@@ -1568,8 +1570,8 @@ MFFDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     } 
       
     CPLFree( padfTiepoints );
-    fprintf( fp, "END\n" );
-    VSIFClose( fp );
+    VSIFPrintfL( fp, "END\n" );
+    VSIFCloseL( fp );
    
     /* End of georeferencing stuff */
 
@@ -1615,6 +1617,7 @@ void GDALRegister_MFF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "MFF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Vexcel MFF Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
@@ -1623,6 +1626,8 @@ void GDALRegister_MFF()
         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
                                    "Byte UInt16 Float32 CInt16 CFloat32" );
 
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
         poDriver->pfnOpen = MFFDataset::Open;
         poDriver->pfnCreate = MFFDataset::Create;
         poDriver->pfnCreateCopy = MFFDataset::CreateCopy;
@@ -1630,4 +1635,3 @@ void GDALRegister_MFF()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/raw/ndfdataset.cpp b/frmts/raw/ndfdataset.cpp
index cbccf31..e5286a1 100644
--- a/frmts/raw/ndfdataset.cpp
+++ b/frmts/raw/ndfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ndfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ndfdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  NDF Driver
  * Purpose:  Implementation of NLAPS Data Format read support.
@@ -32,7 +32,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ndfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ndfdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -336,7 +336,7 @@ GDALDataset *NDFDataset::Open( GDALOpenInfo * poOpenInfo )
     {
         int i;
         for( i = 0; i < 15; i++ )
-            adfUSGSParms[i] = atof(papszParmTokens[i]);
+            adfUSGSParms[i] = CPLAtof(papszParmTokens[i]);
     }
     CSLDestroy(papszParmTokens);
     papszParmTokens = NULL;
@@ -390,17 +390,17 @@ GDALDataset *NDFDataset::Open( GDALOpenInfo * poOpenInfo )
         && CSLCount(papszUR) == 4 
         && CSLCount(papszLL) == 4 )
     {
-        poDS->adfGeoTransform[0] = atof(papszUL[2]);
+        poDS->adfGeoTransform[0] = CPLAtof(papszUL[2]);
         poDS->adfGeoTransform[1] = 
-            (atof(papszUR[2]) - atof(papszUL[2])) / (poDS->nRasterXSize-1);
+            (CPLAtof(papszUR[2]) - CPLAtof(papszUL[2])) / (poDS->nRasterXSize-1);
         poDS->adfGeoTransform[2] = 
-            (atof(papszUR[3]) - atof(papszUL[3])) / (poDS->nRasterXSize-1);
+            (CPLAtof(papszUR[3]) - CPLAtof(papszUL[3])) / (poDS->nRasterXSize-1);
 
-        poDS->adfGeoTransform[3] = atof(papszUL[3]);
+        poDS->adfGeoTransform[3] = CPLAtof(papszUL[3]);
         poDS->adfGeoTransform[4] = 
-            (atof(papszLL[2]) - atof(papszUL[2])) / (poDS->nRasterYSize-1);
+            (CPLAtof(papszLL[2]) - CPLAtof(papszUL[2])) / (poDS->nRasterYSize-1);
         poDS->adfGeoTransform[5] = 
-            (atof(papszLL[3]) - atof(papszUL[3])) / (poDS->nRasterYSize-1);
+            (CPLAtof(papszLL[3]) - CPLAtof(papszUL[3])) / (poDS->nRasterYSize-1);
 
         // Move origin up-left half a pixel.
         poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5;
@@ -441,6 +441,7 @@ void GDALRegister_NDF()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "NDF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NLAPS Data Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/ntv2dataset.cpp b/frmts/raw/ntv2dataset.cpp
index 3f57b57..c403749 100644
--- a/frmts/raw/ntv2dataset.cpp
+++ b/frmts/raw/ntv2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntv2dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ntv2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Horizontal Datum Formats
  * Purpose:  Implementation of NTv2 datum shift format used in Canada, France, 
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ntv2dataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ntv2dataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /** 
  * The header for the file, and each grid consists of 11 16byte records.
@@ -206,25 +206,25 @@ void NTv2Dataset::FlushCache()
         }
         else if( EQUAL(pszKey,"MAJOR_F") )
         {
-            double dfValue = atof(pszValue);
+            double dfValue = CPLAtof(pszValue);
             CPL_LSBPTR64( &dfValue );
             memcpy( achFileHeader + 7*16+8, &dfValue, 8 );
         }
         else if( EQUAL(pszKey,"MINOR_F") )
         {
-            double dfValue = atof(pszValue);
+            double dfValue = CPLAtof(pszValue);
             CPL_LSBPTR64( &dfValue );
             memcpy( achFileHeader + 8*16+8, &dfValue, 8 );
         }
         else if( EQUAL(pszKey,"MAJOR_T") )
         {
-            double dfValue = atof(pszValue);
+            double dfValue = CPLAtof(pszValue);
             CPL_LSBPTR64( &dfValue );
             memcpy( achFileHeader + 9*16+8, &dfValue, 8 );
         }
         else if( EQUAL(pszKey,"MINOR_T") )
         {
-            double dfValue = atof(pszValue);
+            double dfValue = CPLAtof(pszValue);
             CPL_LSBPTR64( &dfValue );
             memcpy( achFileHeader + 10*16+8, &dfValue, 8 );
         }
@@ -658,10 +658,10 @@ const char *NTv2Dataset::GetProjectionRef()
 /************************************************************************/
 
 GDALDataset *NTv2Dataset::Create( const char * pszFilename,
-                                  int nXSize, int nYSize, CPL_UNUSED int nBands,
+                                  int nXSize, int nYSize,
+                                  CPL_UNUSED int nBands,
                                   GDALDataType eType,
                                   char ** papszOptions )
-
 {
     if( eType != GDT_Float32 )
     {
@@ -867,6 +867,7 @@ void GDALRegister_NTv2()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "NTv2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "NTv2 Datum Grid Shift" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gsb" );
@@ -882,4 +883,3 @@ void GDALRegister_NTv2()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/raw/pauxdataset.cpp b/frmts/raw/pauxdataset.cpp
index 149f0e6..7868281 100644
--- a/frmts/raw/pauxdataset.cpp
+++ b/frmts/raw/pauxdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pauxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pauxdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  PCI .aux Driver
  * Purpose:  Implementation of PAuxDataset
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: pauxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pauxdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_PAux(void);
@@ -209,7 +209,7 @@ double PAuxRasterBand::GetNoDataValue( int *pbSuccess )
     if( pszLine == NULL )
         return -1e8;
     else
-        return atof(pszLine);
+        return CPLAtof(pszLine);
 }
 
 /************************************************************************/
@@ -231,7 +231,7 @@ CPLErr PAuxRasterBand::SetNoDataValue( double dfNewValue )
     }
 
     sprintf( szTarget, "METADATA_IMG_%d_NO_DATA_VALUE", nBand );
-    sprintf( szValue, "%24.12f", dfNewValue );
+    CPLsprintf( szValue, "%24.12f", dfNewValue );
     poPDS->papszAuxLines = 
         CSLSetNameValue( poPDS->papszAuxLines, szTarget, szValue );
     
@@ -372,7 +372,7 @@ char *PAuxDataset::PCI2WKT( const char *pszGeosys,
         papszTokens = CSLTokenizeString( pszProjParms );
         
         for( i=0; papszTokens != NULL && papszTokens[i] != NULL && i < 16; i++)
-            adfProjParms[i] = atof(papszTokens[i]);
+            adfProjParms[i] = CPLAtof(papszTokens[i]);
 
         CSLDestroy( papszTokens );
     }
@@ -439,13 +439,13 @@ void PAuxDataset::ScanForGCPs()
         {
             GDALInitGCPs( 1, pasGCPList + nGCPCount );
 
-            pasGCPList[nGCPCount].dfGCPX = atof(papszTokens[2]);
-            pasGCPList[nGCPCount].dfGCPY = atof(papszTokens[3]);
-            pasGCPList[nGCPCount].dfGCPPixel = atof(papszTokens[0]);
-            pasGCPList[nGCPCount].dfGCPLine = atof(papszTokens[1]);
+            pasGCPList[nGCPCount].dfGCPX = CPLAtof(papszTokens[2]);
+            pasGCPList[nGCPCount].dfGCPY = CPLAtof(papszTokens[3]);
+            pasGCPList[nGCPCount].dfGCPPixel = CPLAtof(papszTokens[0]);
+            pasGCPList[nGCPCount].dfGCPLine = CPLAtof(papszTokens[1]);
 
             if( CSLCount(papszTokens) > 4 )
-                pasGCPList[nGCPCount].dfGCPZ = atof(papszTokens[4]);
+                pasGCPList[nGCPCount].dfGCPZ = CPLAtof(papszTokens[4]);
 
             CPLFree( pasGCPList[nGCPCount].pszId );
             if( CSLCount(papszTokens) > 5 )
@@ -531,10 +531,10 @@ CPLErr PAuxDataset::GetGeoTransform( double * padfGeoTransform )
     {
         double	dfUpLeftX, dfUpLeftY, dfLoRightX, dfLoRightY;
 
-        dfUpLeftX = atof(CSLFetchNameValue(papszAuxLines, "UpLeftX" ));
-        dfUpLeftY = atof(CSLFetchNameValue(papszAuxLines, "UpLeftY" ));
-        dfLoRightX = atof(CSLFetchNameValue(papszAuxLines, "LoRightX" ));
-        dfLoRightY = atof(CSLFetchNameValue(papszAuxLines, "LoRightY" ));
+        dfUpLeftX = CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftX" ));
+        dfUpLeftY = CPLAtof(CSLFetchNameValue(papszAuxLines, "UpLeftY" ));
+        dfLoRightX = CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightX" ));
+        dfLoRightY = CPLAtof(CSLFetchNameValue(papszAuxLines, "LoRightY" ));
 
         padfGeoTransform[0] = dfUpLeftX;
         padfGeoTransform[1] = (dfLoRightX - dfUpLeftX) / GetRasterXSize();
@@ -573,20 +573,20 @@ CPLErr PAuxDataset::SetGeoTransform( double * padfGeoTransform )
     if( ABS(padfGeoTransform[0]) < 181 
         && ABS(padfGeoTransform[1]) < 1 )
     {
-        sprintf( szUpLeftX, "%.12f", padfGeoTransform[0] );
-        sprintf( szUpLeftY, "%.12f", padfGeoTransform[3] );
-        sprintf( szLoRightX, "%.12f", 
+        CPLsprintf( szUpLeftX, "%.12f", padfGeoTransform[0] );
+        CPLsprintf( szUpLeftY, "%.12f", padfGeoTransform[3] );
+        CPLsprintf( szLoRightX, "%.12f", 
                padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
-        sprintf( szLoRightY, "%.12f", 
+        CPLsprintf( szLoRightY, "%.12f", 
                padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
     }
     else
     {
-        sprintf( szUpLeftX, "%.3f", padfGeoTransform[0] );
-        sprintf( szUpLeftY, "%.3f", padfGeoTransform[3] );
-        sprintf( szLoRightX, "%.3f", 
+        CPLsprintf( szUpLeftX, "%.3f", padfGeoTransform[0] );
+        CPLsprintf( szUpLeftY, "%.3f", padfGeoTransform[3] );
+        CPLsprintf( szLoRightX, "%.3f", 
                padfGeoTransform[0] + padfGeoTransform[1] * GetRasterXSize() );
-        sprintf( szLoRightY, "%.3f", 
+        CPLsprintf( szLoRightY, "%.3f", 
                padfGeoTransform[3] + padfGeoTransform[5] * GetRasterYSize() );
     }
         
@@ -656,8 +656,9 @@ GDALDataset *PAuxDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Do we have a .aux file?                                         */
 /* -------------------------------------------------------------------- */
-    if( poOpenInfo->papszSiblingFiles != NULL
-        && CSLFindString( poOpenInfo->papszSiblingFiles, 
+    char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if( papszSiblingFiles != NULL
+        && CSLFindString( papszSiblingFiles, 
                           CPLGetFilename(osAuxFilename) ) == -1 )
     {
         return NULL;
@@ -1112,6 +1113,7 @@ void GDALRegister_PAux()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "PAux" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "PCI .aux Labelled" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/raw/pnmdataset.cpp b/frmts/raw/pnmdataset.cpp
index c2fb5d7..26bf627 100644
--- a/frmts/raw/pnmdataset.cpp
+++ b/frmts/raw/pnmdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: pnmdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: pnmdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  PNM Driver
  * Purpose:  Portable anymap file format imlementation
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include <ctype.h>
 
-CPL_CVSID("$Id: pnmdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: pnmdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void    GDALRegister_PNM(void);
@@ -414,6 +414,7 @@ void GDALRegister_PNM()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "PNM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Portable Pixmap Format (netpbm)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/raw/rawdataset.cpp b/frmts/raw/rawdataset.cpp
index b1b1fa0..338272b 100644
--- a/frmts/raw/rawdataset.cpp
+++ b/frmts/raw/rawdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rawdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: rawdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Generic Raw Binary Driver
  * Purpose:  Implementation of RawDataset and RawRasterBand classes.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: rawdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: rawdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                           RawRasterBand()                            */
@@ -348,9 +348,9 @@ CPLErr RawRasterBand::AccessLine( int iLine )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr RawRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr RawRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
-
 {
     CPLErr		eErr;
 
@@ -360,7 +360,7 @@ CPLErr RawRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
         return CE_Failure;
 
     eErr = AccessLine( nBlockYOff );
-    
+
 /* -------------------------------------------------------------------- */
 /*      Copy data from disk buffer to user block buffer.                */
 /* -------------------------------------------------------------------- */
@@ -375,9 +375,9 @@ CPLErr RawRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
 /*                            IWriteBlock()                             */
 /************************************************************************/
 
-CPLErr RawRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr RawRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,
+                                   int nBlockYOff,
                                    void * pImage )
-
 {
     CPLErr		eErr = CE_None;
 
@@ -574,7 +574,10 @@ int RawRasterBand::IsSignificantNumberOfLinesLoaded( int nLineOff, int nLines )
 /*                           CanUseDirectIO()                           */
 /************************************************************************/
 
-int RawRasterBand::CanUseDirectIO(CPL_UNUSED int nXOff, int nYOff, int nXSize, int nYSize,
+int RawRasterBand::CanUseDirectIO(CPL_UNUSED int nXOff,
+                                  int nYOff,
+                                  int nXSize,
+                                  int nYSize,
                                   CPL_UNUSED GDALDataType eBufType)
 {
 
@@ -590,7 +593,7 @@ int RawRasterBand::CanUseDirectIO(CPL_UNUSED int nXOff, int nYOff, int nXSize, i
 /* and no significant number of requested scanlines are already in the  */
 /* cache.                                                               */
 /* -------------------------------------------------------------------- */
-    if( nPixelOffset < 0 ) 
+    if( nPixelOffset < 0 )
     {
         return FALSE;
     }
@@ -620,7 +623,8 @@ CPLErr RawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
 
 {
     int         nBandDataSize = GDALGetDataTypeSize(eDataType) / 8;
@@ -633,7 +637,7 @@ CPLErr RawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                           nXSize, nYSize,
                                           pData, nBufXSize, nBufYSize,
                                           eBufType,
-                                          nPixelSpace, nLineSpace );
+                                          nPixelSpace, nLineSpace, psExtraArg );
     }
 
     CPLDebug("RAW", "Using direct IO implementation");
@@ -652,7 +656,7 @@ CPLErr RawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         {
             if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                   pData, nBufXSize, nBufYSize, 
-                                  eBufType, nPixelSpace, nLineSpace ) == CE_None )
+                                  eBufType, nPixelSpace, nLineSpace, psExtraArg ) == CE_None )
                 return CE_None;
         }
 
@@ -732,6 +736,14 @@ CPLErr RawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                        eBufType, nPixelSpace, 1 );
                     }
                 }
+
+                if( psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * (iLine + 1) / nBufYSize, "",
+                                            psExtraArg->pProgressData) )
+                {
+                    CPLFree( pabyData );
+                    return CE_Failure;
+                }
             }
 
             CPLFree( pabyData );
@@ -1155,7 +1167,9 @@ CPLErr RawDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType,
                               int nBandCount, int *panBandMap, 
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     const char* pszInterleave;
@@ -1179,6 +1193,10 @@ CPLErr RawDataset::IRasterIO( GDALRWFlag eRWFlag,
         }
         if( iBandIndex == nBandCount )
         {
+
+            GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+            void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
             CPLErr eErr = CE_None;
             for( iBandIndex = 0; 
                 iBandIndex < nBandCount && eErr == CE_None; 
@@ -1194,12 +1212,24 @@ CPLErr RawDataset::IRasterIO( GDALRWFlag eRWFlag,
                 }
 
                 pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
-                
+
+                psExtraArg->pfnProgress = GDALScaledProgress;
+                psExtraArg->pProgressData = 
+                    GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
+                                            1.0 * (iBandIndex + 1) / nBandCount,
+                                            pfnProgressGlobal,
+                                            pProgressDataGlobal );
+
                 eErr = poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                         (void *) pabyBandData, nBufXSize, nBufYSize,
-                                        eBufType, nPixelSpace, nLineSpace );
+                                        eBufType, nPixelSpace, nLineSpace, psExtraArg );
+
+                GDALDestroyScaledProgress( psExtraArg->pProgressData );
             }
 
+            psExtraArg->pfnProgress = pfnProgressGlobal;
+            psExtraArg->pProgressData = pProgressDataGlobal;
+
             return eErr;
         }
     }
@@ -1207,7 +1237,6 @@ CPLErr RawDataset::IRasterIO( GDALRWFlag eRWFlag,
     return  GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                     pData, nBufXSize, nBufYSize, eBufType, 
                                     nBandCount, panBandMap, 
-                                    nPixelSpace, nLineSpace, nBandSpace );
+                                    nPixelSpace, nLineSpace, nBandSpace,
+                                    psExtraArg);
 }
-
-
diff --git a/frmts/raw/rawdataset.h b/frmts/raw/rawdataset.h
index 80cdbe2..bdd00b8 100644
--- a/frmts/raw/rawdataset.h
+++ b/frmts/raw/rawdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rawdataset.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rawdataset.h 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Raw Translator
  * Purpose:  Implementation of RawDataset class.  Intented to be subclassed
@@ -52,7 +52,10 @@ class CPL_DLL RawDataset : public GDALPamDataset
   protected:
     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
                                    void *, int, int, GDALDataType,
-                                   int, int *, int, int, int );
+                                   int, int *,
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GSpacing nBandSpace,
+                                   GDALRasterIOExtraArg* psExtraArg );
   public:
                  RawDataset();
                  ~RawDataset() = 0;
@@ -108,7 +111,8 @@ protected:
 
     virtual CPLErr  IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     int         CanUseDirectIO(int nXOff, int nYOff, int nXSize, int nYSize,
                                GDALDataType eBufType);
diff --git a/frmts/raw/roipacdataset.cpp b/frmts/raw/roipacdataset.cpp
new file mode 100644
index 0000000..c63d69e
--- /dev/null
+++ b/frmts/raw/roipacdataset.cpp
@@ -0,0 +1,868 @@
+/******************************************************************************
+ * $Id: roipacdataset.cpp 28974 2015-04-22 17:57:26Z rouault $
+ *
+ * Project:  ROI_PAC Raster Reader
+ * Purpose:  Implementation of the ROI_PAC raster reader
+ * Author:   Matthieu Volat (ISTerre), matthieu.volat at ujf-grenoble.fr
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Matthieu Volat <matthieu.volat at ujf-grenoble.fr>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "rawdataset.h"
+#include "ogr_spatialref.h"
+
+CPL_CVSID("$Id: roipacdataset.cpp 28974 2015-04-22 17:57:26Z rouault $");
+
+CPL_C_START
+void    GDALRegister_ROIPAC(void);
+CPL_C_END
+
+/************************************************************************/
+/* ==================================================================== */
+/*                             ROIPACDataset                            */
+/* ==================================================================== */
+/************************************************************************/
+
+class ROIPACRasterBand;
+
+class ROIPACDataset : public RawDataset
+{
+    friend class ROIPACRasterBand;
+
+    VSILFILE    *fpImage;
+    VSILFILE    *fpRsc;
+    
+    char        *pszRscFilename;
+
+    double      adfGeoTransform[6];
+    bool        bValidGeoTransform;
+    char        *pszProjection;
+
+  public:
+                ROIPACDataset( void );
+                ~ROIPACDataset( void );
+    
+    static GDALDataset *Open( GDALOpenInfo *poOpenInfo );
+    static int          Identify( GDALOpenInfo *poOpenInfo );
+    static GDALDataset *Create( const char *pszFilename,
+                                int nXSize, int nYSize, int nBands,
+                                GDALDataType eType, char **papszOptions );
+
+    virtual void        FlushCache( void );
+    CPLErr              GetGeoTransform( double *padfTransform );
+    virtual CPLErr      SetGeoTransform( double *padfTransform );
+    const char         *GetProjectionRef( void );
+    virtual CPLErr      SetProjection( const char *pszNewProjection );
+    virtual char      **GetFileList( void );
+};
+
+/************************************************************************/
+/* ==================================================================== */
+/*                           ROIPACRasterBand                           */
+/* ==================================================================== */
+/************************************************************************/
+
+class ROIPACRasterBand : public RawRasterBand
+{
+    public:
+                ROIPACRasterBand( GDALDataset *poDS, int nBand, void *fpRaw,
+                                  vsi_l_offset nImgOffset, int nPixelOffset,
+                                  int nLineOffset,
+                                  GDALDataType eDataType, int bNativeOrder,
+                                  int bIsVSIL = FALSE, int bOwnsFP = FALSE );
+};
+
+/************************************************************************/
+/*                           getRscFilename()                           */
+/************************************************************************/
+
+static CPLString getRscFilename( GDALOpenInfo *poOpenInfo )
+{
+    CPLString osRscFilename;
+
+    char **papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if ( papszSiblingFiles == NULL )
+    {
+        osRscFilename = CPLFormFilename( NULL, poOpenInfo->pszFilename, 
+                                        "rsc" );
+        VSIStatBufL psRscStatBuf;
+        if ( VSIStatL( osRscFilename, &psRscStatBuf ) != 0 ) 
+        {
+            osRscFilename = "";
+        }
+    }
+    else
+    {
+        /* ------------------------------------------------------------ */
+        /*      We need to tear apart the filename to form a .rsc       */
+        /*      filename.                                               */
+        /* ------------------------------------------------------------ */
+        CPLString osPath = CPLGetPath( poOpenInfo->pszFilename );
+        CPLString osName = CPLGetFilename( poOpenInfo->pszFilename );
+
+        int iFile = CSLFindString( papszSiblingFiles,
+                                   CPLFormFilename( NULL, osName, "rsc" ) );
+        if( iFile >= 0 )
+        {
+            osRscFilename = CPLFormFilename( osPath,
+                                             papszSiblingFiles[iFile],
+                                             NULL );
+        }
+    }
+
+    return osRscFilename;
+}
+
+/************************************************************************/
+/*                            ROIPACDataset()                           */
+/************************************************************************/
+
+ROIPACDataset::ROIPACDataset( void )
+{
+    fpImage = NULL;
+    fpRsc = NULL;
+    pszRscFilename = NULL;
+    adfGeoTransform[0] =  0.0;
+    adfGeoTransform[1] =  1.0;
+    adfGeoTransform[2] =  0.0;
+    adfGeoTransform[3] =  0.0;
+    adfGeoTransform[4] =  0.0;
+    adfGeoTransform[5] =  1.0;
+    pszProjection = NULL;
+    bValidGeoTransform = false;
+}
+
+/************************************************************************/
+/*                            ~ROIPACDataset()                          */
+/************************************************************************/
+
+ROIPACDataset::~ROIPACDataset( void )
+{
+    FlushCache();
+    if ( fpRsc != NULL )
+    {
+        VSIFCloseL( fpRsc );
+    }
+    if ( fpImage != NULL )
+    {
+        VSIFCloseL( fpImage );
+    }
+    CPLFree( pszRscFilename );
+    CPLFree( pszProjection );
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset *ROIPACDataset::Open( GDALOpenInfo *poOpenInfo )
+{
+/* -------------------------------------------------------------------- */
+/*      Confirm that the header is compatible with a ROIPAC dataset.    */
+/* -------------------------------------------------------------------- */
+    if ( !Identify(poOpenInfo) )
+    {
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Open the .rsc file                                              */
+/* -------------------------------------------------------------------- */
+    CPLString osRscFilename = getRscFilename( poOpenInfo );
+    if ( osRscFilename.empty() )
+    {
+        return NULL;
+    }
+    VSILFILE *fpRsc;
+    if ( poOpenInfo->eAccess == GA_Update )
+    {
+        fpRsc = VSIFOpenL( osRscFilename, "r+" );
+    }
+    else
+    {
+        fpRsc = VSIFOpenL( osRscFilename, "r" );
+    }
+    if ( fpRsc == NULL )
+    {
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Load the .rsc information.                                      */
+/* -------------------------------------------------------------------- */
+    char **papszRsc = NULL;
+    while ( true )
+    {
+        const char *pszLine;
+        char **papszTokens;
+
+        pszLine = CPLReadLineL( fpRsc );
+        if (pszLine == NULL)
+        {
+            break;
+        }
+
+        papszTokens = CSLTokenizeString2( pszLine, " \t",
+                                          CSLT_STRIPLEADSPACES
+                                            | CSLT_STRIPENDSPACES
+                                            | CSLT_PRESERVEQUOTES
+                                            | CSLT_PRESERVEESCAPES );
+        if ( papszTokens == NULL 
+             || papszTokens[0] == NULL || papszTokens[1] == NULL )
+        {
+            CSLDestroy ( papszTokens );
+            break;
+        }
+        papszRsc = CSLSetNameValue( papszRsc,
+                                       papszTokens[0], papszTokens[1] );
+
+        CSLDestroy ( papszTokens );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Fetch required fields.                                          */
+/* -------------------------------------------------------------------- */
+    int nWidth = 0, nFileLength = 0;
+    if ( CSLFetchNameValue( papszRsc, "WIDTH" ) == NULL
+        || CSLFetchNameValue( papszRsc, "FILE_LENGTH" ) == NULL )
+    {
+        CSLDestroy( papszRsc );
+        VSIFCloseL( fpRsc );
+        return NULL;
+    }
+    nWidth = atoi( CSLFetchNameValue( papszRsc, "WIDTH" ) ); 
+    nFileLength = atoi( CSLFetchNameValue( papszRsc, "FILE_LENGTH" ) );
+
+/* -------------------------------------------------------------------- */
+/*      Create a corresponding GDALDataset.                             */
+/* -------------------------------------------------------------------- */
+    ROIPACDataset *poDS;
+    poDS = new ROIPACDataset();
+    poDS->nRasterXSize = nWidth;
+    poDS->nRasterYSize = nFileLength;
+    poDS->eAccess = poOpenInfo->eAccess;
+    poDS->fpRsc = fpRsc;
+    poDS->pszRscFilename = CPLStrdup( osRscFilename.c_str() );
+
+/* -------------------------------------------------------------------- */
+/*      Reopen file in update mode if necessary.                        */
+/* -------------------------------------------------------------------- */
+    if( poOpenInfo->eAccess == GA_Update )
+    {
+        poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb+" );
+    }
+    else
+    {
+        poDS->fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
+    }
+    if( poDS->fpImage == NULL )
+    {
+        delete poDS;
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Failed to re-open %s within ROI_PAC driver.\n",
+                  poOpenInfo->pszFilename );
+        CSLDestroy( papszRsc );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create band information objects.                                */
+/* -------------------------------------------------------------------- */
+    GDALDataType eDataType;
+    int nBands;
+    enum Interleave { LINE, PIXEL } eInterleave;
+    const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
+    if ( strcmp( pszExtension, "raw" ) == 0 )
+    {
+        /* ------------------------------------------------------------ */
+        /* TODO: ROI_PAC raw images are what would be GDT_CInt8 typed,  */
+        /* but since that type do not exist, we will have to implement  */
+        /* a specific case in the RasterBand to convert it to           */
+        /* GDT_CInt16 for example                                       */
+        /* ------------------------------------------------------------ */
+#if 0
+        eDataType = GDT_CInt8;
+        nBands = 1;
+        eInterleave = PIXEL;
+#else
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Reading ROI_PAC raw files is not supported yet." );
+        delete poDS;
+        CSLDestroy( papszRsc );
+        return NULL;
+#endif
+    }
+    else if ( strcmp( pszExtension, "int" ) == 0
+                || strcmp( pszExtension, "slc" ) == 0 )
+    {
+        eDataType = GDT_CFloat32;
+        nBands = 1;
+        eInterleave = PIXEL;
+    }
+    else if ( strcmp( pszExtension, "amp" ) == 0 )
+    {
+        eDataType = GDT_Float32;
+        nBands = 2;
+        eInterleave = PIXEL;
+    }
+    else if ( strcmp( pszExtension, "cor" ) == 0 
+                || strcmp( pszExtension, "hgt" ) == 0 
+                || strcmp( pszExtension, "unw" ) == 0 
+                || strcmp( pszExtension, "msk" ) == 0 
+                || strcmp( pszExtension, "trans" ) == 0 )
+    {
+        eDataType = GDT_Float32;
+        nBands = 2;
+        eInterleave = LINE;
+    }
+    else if ( strcmp( pszExtension, "dem" ) == 0 )
+    {
+        eDataType = GDT_Int16;
+        nBands = 1;
+        eInterleave = PIXEL;
+    }
+    else { /* Eeek */
+        delete poDS;
+        CSLDestroy( papszRsc );
+        return NULL;
+    }
+    int nPixelOffset;
+    int nLineOffset;
+    int nBandOffset;
+    if (eInterleave == LINE)
+    {
+        nPixelOffset = GDALGetDataTypeSize(eDataType)/8;
+        nLineOffset = nPixelOffset * nWidth * nBands;
+        nBandOffset = GDALGetDataTypeSize(eDataType)/8 * nWidth;
+    }
+    else { /* PIXEL */
+        nPixelOffset = GDALGetDataTypeSize(eDataType)/8 * nBands;
+        nLineOffset = nPixelOffset * nWidth * nBands;
+        nBandOffset = GDALGetDataTypeSize(eDataType)/8;
+    }
+    poDS->nBands = nBands;
+    for (int b = 0; b < nBands; b++)
+    {
+        poDS->SetBand( b + 1,
+                       new ROIPACRasterBand( poDS, b + 1, poDS->fpImage,
+                                             nBandOffset * b,
+                                             nPixelOffset, nLineOffset,
+                                             eDataType, TRUE,
+                                             TRUE, FALSE ) );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Interpret georeferencing, if present.                           */
+/* -------------------------------------------------------------------- */
+    if ( CSLFetchNameValue( papszRsc, "X_FIRST" ) != NULL
+          && CSLFetchNameValue( papszRsc, "X_STEP" ) != NULL
+          && CSLFetchNameValue( papszRsc, "Y_FIRST" ) != NULL
+          && CSLFetchNameValue( papszRsc, "Y_STEP" ) != NULL )
+    {
+        poDS->adfGeoTransform[0] = CPLAtof( CSLFetchNameValue( papszRsc,
+                                                               "X_FIRST" ) );
+        poDS->adfGeoTransform[1] = CPLAtof( CSLFetchNameValue( papszRsc, 
+                                                               "X_STEP" ) );
+        poDS->adfGeoTransform[2] = 0.0;
+        poDS->adfGeoTransform[3] = CPLAtof( CSLFetchNameValue( papszRsc, 
+                                                               "Y_FIRST" ) );
+        poDS->adfGeoTransform[4] = 0.0;
+        poDS->adfGeoTransform[5] = CPLAtof( CSLFetchNameValue( papszRsc, 
+                                                               "Y_STEP" ) );
+        poDS->bValidGeoTransform = true;
+    }
+    if ( CSLFetchNameValue( papszRsc, "PROJECTION" ) != NULL )
+    {
+        /* ------------------------------------------------------------ */
+        /* In ROI_PAC, images are georeferenced either with lat/long or */
+        /* UTM projection. However, using UTM projection is dangerous   */
+        /* because there is no North/South field, or use of latitude    */
+        /* bands!                                                       */
+        /* ------------------------------------------------------------ */
+        OGRSpatialReference oSRS;
+        if ( strcmp( CSLFetchNameValue( papszRsc, "PROJECTION" ),
+                     "LL" ) == 0 )
+        {
+            if ( CSLFetchNameValue( papszRsc, "DATUM" ) != NULL )
+            {
+                oSRS.SetWellKnownGeogCS( CSLFetchNameValue( papszRsc, 
+                                                            "DATUM" ) );
+            }
+            else {
+                oSRS.SetWellKnownGeogCS( "WGS84" );
+            }
+        }
+        else if( strncmp( CSLFetchNameValue( papszRsc, "PROJECTION" ),
+                          "UTM", 3 ) == 0 )
+        {
+            const char *pszZone = CSLFetchNameValue( papszRsc, 
+                                                     "PROJECTION" ) + 3;
+            oSRS.SetUTM( atoi( pszZone ), TRUE ); /* FIXME: north/south? */
+            if ( CSLFetchNameValue( papszRsc, "DATUM" ) != NULL )
+            {
+                oSRS.SetWellKnownGeogCS( CSLFetchNameValue( papszRsc, 
+                                                            "DATUM" ) );
+            }
+            else {
+                oSRS.SetWellKnownGeogCS( "NAD27" );
+            }
+        }
+        oSRS.exportToWkt( &poDS->pszProjection );
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      Set all the other header metadata into the ROI_PAC domain       */
+/* -------------------------------------------------------------------- */
+    for (int i = 0; i < CSLCount( papszRsc ); i++)
+    {
+        char **papszTokens;
+        papszTokens = CSLTokenizeString2( papszRsc[i],
+                                          "=",
+                                          CSLT_STRIPLEADSPACES
+                                            | CSLT_STRIPENDSPACES);
+        if ( strcmp( papszTokens[0], "WIDTH" ) == 0
+              || strcmp( papszTokens[0], "FILE_LENGTH" ) == 0
+              || strcmp( papszTokens[0], "X_FIRST" ) == 0
+              || strcmp( papszTokens[0], "X_STEP" ) == 0
+              || strcmp( papszTokens[0], "Y_FIRST" ) == 0
+              || strcmp( papszTokens[0], "Y_STEP" ) == 0
+              || strcmp( papszTokens[0], "PROJECTION" ) == 0 
+              || strcmp( papszTokens[0], "DATUM" ) == 0 )
+        {
+            CSLDestroy( papszTokens );
+            continue;
+        }
+        poDS->SetMetadataItem(papszTokens[0], papszTokens[1], "ROI_PAC");
+        CSLDestroy( papszTokens );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Free papszRsc                                                   */
+/* -------------------------------------------------------------------- */
+    CSLDestroy( papszRsc );
+
+/* -------------------------------------------------------------------- */
+/*      Initialize any PAM information.                                 */
+/* -------------------------------------------------------------------- */
+    poDS->SetDescription( poOpenInfo->pszFilename );
+    poDS->TryLoadXML(); 
+
+/* -------------------------------------------------------------------- */
+/*      Check for overviews.                                            */
+/* -------------------------------------------------------------------- */
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+
+    return( poDS );
+}
+
+/************************************************************************/
+/*                             Identify()                               */
+/************************************************************************/
+
+int ROIPACDataset::Identify( GDALOpenInfo *poOpenInfo )
+{
+/* -------------------------------------------------------------------- */
+/*      Check if:                                                       */
+/*      * 1. The data file extension is known                           */
+/* -------------------------------------------------------------------- */
+    const char *pszExtension = CPLGetExtension(poOpenInfo->pszFilename);
+    if ( strcmp( pszExtension, "raw" ) == 0 )
+    {
+        /* Since gdal do not read natively CInt8, more work is needed
+         * to read raw files */
+        return false;
+    }
+    bool bExtensionIsValid = strcmp( pszExtension, "int" ) == 0
+                               || strcmp( pszExtension, "slc" ) == 0
+                               || strcmp( pszExtension, "amp" ) == 0
+                               || strcmp( pszExtension, "cor" ) == 0
+                               || strcmp( pszExtension, "hgt" ) == 0
+                               || strcmp( pszExtension, "unw" ) == 0
+                               || strcmp( pszExtension, "msk" ) == 0
+                               || strcmp( pszExtension, "trans" ) == 0
+                               || strcmp( pszExtension, "dem" ) == 0;
+    if ( !bExtensionIsValid )
+    {
+        return false;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      * 2. there is a .rsc file                                      */
+/* -------------------------------------------------------------------- */
+    CPLString osRscFilename = getRscFilename( poOpenInfo );
+    if ( osRscFilename.empty() )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+/************************************************************************/
+/*                              Create()                                */
+/************************************************************************/
+
+GDALDataset *ROIPACDataset::Create( const char *pszFilename,
+                                    int nXSize, int nYSize, int nBands,
+                                    GDALDataType eType,
+                                    char **papszOptions )
+{
+/* -------------------------------------------------------------------- */
+/*      Verify input options.                                           */
+/* -------------------------------------------------------------------- */
+    const char *pszExtension = CPLGetExtension(pszFilename);
+    if ( strcmp( pszExtension, "int" ) == 0
+                || strcmp( pszExtension, "slc" ) == 0 )
+    {
+        if ( nBands != 1 || eType != GDT_CFloat32 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to create ROI_PAC %s dataset with an illegal\n"
+                          "number of bands (%d) and/or data type (%s).\n",
+                      pszExtension, nBands, GDALGetDataTypeName(eType) );
+            return NULL;
+        }
+    }
+    else if ( strcmp( pszExtension, "amp" ) == 0 )
+    {
+        if ( nBands != 2 || eType != GDT_Float32 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to create ROI_PAC %s dataset with an illegal\n"
+                          "number of bands (%d) and/or data type (%s).\n",
+                      pszExtension, nBands, GDALGetDataTypeName(eType) );
+            return NULL;
+        }
+    }
+    else if ( strcmp( pszExtension, "cor" ) == 0 
+                || strcmp( pszExtension, "hgt" ) == 0 
+                || strcmp( pszExtension, "unw" ) == 0 
+                || strcmp( pszExtension, "msk" ) == 0 
+                || strcmp( pszExtension, "trans" ) == 0 )
+    {
+        if ( nBands != 2 || eType != GDT_Float32 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to create ROI_PAC %s dataset with an illegal\n"
+                          "number of bands (%d) and/or data type (%s).\n",
+                      pszExtension, nBands, GDALGetDataTypeName(eType) );
+            return NULL;
+        }
+    }
+    else if ( strcmp( pszExtension, "dem" ) == 0 )
+    {
+        if ( nBands != 1 || eType != GDT_Int16 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Attempt to create ROI_PAC %s dataset with an illegal\n"
+                          "number of bands (%d) and/or data type (%s).\n",
+                      pszExtension, nBands, GDALGetDataTypeName(eType) );
+            return NULL;
+        }
+    }
+    else { /* Eeek */
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Attempt to create ROI_PAC dataset with an unknown type (%s)\n",
+                  pszExtension );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Try to create the file.                                         */
+/* -------------------------------------------------------------------- */
+    VSILFILE *fp;
+    fp = VSIFOpenL( pszFilename, "wb" );
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed.\n",
+                  pszFilename );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Just write out a couple of bytes to establish the binary        */
+/*      file, and then close it.                                        */
+/* -------------------------------------------------------------------- */
+    VSIFWriteL( (void *) "\0\0", 2, 1, fp );
+    VSIFCloseL( fp );
+
+/* -------------------------------------------------------------------- */
+/*      Open the RSC file.                                              */
+/* -------------------------------------------------------------------- */
+    const char  *pszRSCFilename;
+    pszRSCFilename = CPLFormFilename( NULL, pszFilename, "rsc" );
+    fp = VSIFOpenL( pszRSCFilename, "wt" );
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Attempt to create file `%s' failed.\n",
+                  pszRSCFilename );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write out the header.                                           */
+/* -------------------------------------------------------------------- */
+    VSIFPrintfL( fp, "%-40s %d\n", "WIDTH", nXSize );
+    VSIFPrintfL( fp, "%-40s %d\n", "FILE_LENGTH", nYSize );
+    VSIFCloseL( fp );
+
+    return (GDALDataset *) GDALOpen( pszFilename, GA_Update );
+}
+
+/************************************************************************/
+/*                             FlushCache()                             */
+/************************************************************************/
+
+void ROIPACDataset::FlushCache( void )
+{
+    RawDataset::FlushCache();
+
+    GDALRasterBand *band = (GetRasterCount() > 0) ? GetRasterBand(1) : NULL;
+
+    if ( eAccess == GA_ReadOnly || band == NULL )
+        return;
+
+    // If opening an existing file in Update mode (i.e. "r+") we need to make
+    // sure any existing content is cleared, otherwise the file may contain
+    // trailing content from the previous write.
+    VSIFTruncateL( fpRsc, 0 );
+
+    VSIFSeekL( fpRsc, 0, SEEK_SET );
+/* -------------------------------------------------------------------- */
+/*      Rewrite out the header.                                         */
+/* -------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/*      Raster dimensions.                                              */
+/* -------------------------------------------------------------------- */
+    VSIFPrintfL( fpRsc, "%-40s %d\n", "WIDTH", nRasterXSize );
+    VSIFPrintfL( fpRsc, "%-40s %d\n", "FILE_LENGTH", nRasterYSize );
+
+/* -------------------------------------------------------------------- */
+/*      Georeferencing.                                                 */
+/* -------------------------------------------------------------------- */
+    if ( pszProjection != NULL )
+    {
+        char *pszProjectionTmp = pszProjection;
+        OGRSpatialReference oSRS;
+        if( oSRS.importFromWkt( &pszProjectionTmp ) == OGRERR_NONE )
+        {
+            int bNorth;
+            int iUTMZone;
+
+            iUTMZone = oSRS.GetUTMZone( &bNorth );
+            if ( iUTMZone != 0 )
+            {
+                VSIFPrintfL( fpRsc, "%-40s %s%d\n", "PROJECTION", "UTM", iUTMZone );
+            }
+            else if ( oSRS.IsGeographic() )
+            {
+                VSIFPrintfL( fpRsc, "%-40s %s\n", "PROJECTION", "LL" );
+            }
+            else
+            {
+                CPLError( CE_Warning, CPLE_AppDefined,
+                          "ROI_PAC format only support Latitude/Longitude and "
+                              "UTM projections, discarding projection.");
+            }
+
+            if ( oSRS.GetAttrValue( "DATUM" ) != NULL )
+            {
+                if ( strcmp( oSRS.GetAttrValue( "DATUM" ), "WGS_1984" ) == 0 )
+                {
+                    VSIFPrintfL( fpRsc, "%-40s %s\n", "DATUM", "WGS84" );
+                }
+                else
+                {
+                    CPLError( CE_Warning, CPLE_AppDefined,
+                              "Datum \"%s\" probably not supported in the "
+                                  "ROI_PAC format, saving it anyway",
+                                  oSRS.GetAttrValue( "DATUM" ) );
+                    VSIFPrintfL( fpRsc, "%-40s %s\n", "DATUM", oSRS.GetAttrValue( "DATUM" ) );
+                }
+            }
+            if ( oSRS.GetAttrValue( "UNIT" ) != NULL )
+            {
+                VSIFPrintfL( fpRsc, "%-40s %s\n", "X_UNIT", oSRS.GetAttrValue( "UNIT" ) );
+                VSIFPrintfL( fpRsc, "%-40s %s\n", "Y_UNIT", oSRS.GetAttrValue( "UNIT" ) );
+            }
+        }
+    }
+    if( bValidGeoTransform )
+    {
+        if ( adfGeoTransform[2] != 0 || adfGeoTransform[4] != 0 )
+        {
+            CPLError( CE_Warning, CPLE_AppDefined,
+                      "ROI_PAC format do not support geotransform with "
+                          "rotation, discarding info.");
+        }
+        else
+        {
+            VSIFPrintfL( fpRsc, "%-40s %.16g\n", "X_FIRST", adfGeoTransform[0] );
+            VSIFPrintfL( fpRsc, "%-40s %.16g\n", "X_STEP", adfGeoTransform[1] );
+            VSIFPrintfL( fpRsc, "%-40s %.16g\n", "Y_FIRST", adfGeoTransform[3] );
+            VSIFPrintfL( fpRsc, "%-40s %.16g\n", "Y_STEP", adfGeoTransform[5] );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Metadata stored in the ROI_PAC domain.                          */
+/* -------------------------------------------------------------------- */
+    char** papszROIPACMetadata = GetMetadata( "ROI_PAC" );
+    for (int i = 0; i < CSLCount( papszROIPACMetadata ); i++)
+    {   
+        char **papszTokens;
+
+        /* Get the tokens from the metadata item */
+        papszTokens = CSLTokenizeString2( papszROIPACMetadata[i], 
+                                          "=", 
+                                          CSLT_STRIPLEADSPACES 
+                                            | CSLT_STRIPENDSPACES);
+        if ( CSLCount( papszTokens ) != 2 )
+        {   
+            CPLDebug("ROI_PAC",
+                     "Line of header file could not be split at = into two elements: %s",
+                     papszROIPACMetadata[i]);
+            CSLDestroy( papszTokens );
+            continue;
+        }
+
+        /* Don't write it out if it is one of the bits of metadata that is
+         * written out elsewhere in this routine */
+        if ( strcmp( papszTokens[0], "WIDTH" ) == 0
+              || strcmp( papszTokens[0], "FILE_LENGTH" ) == 0 )
+        {   
+            CSLDestroy( papszTokens );
+            continue;
+        }
+        VSIFPrintfL( fpRsc, "%-40s %s\n", papszTokens[0], papszTokens[1] );
+        CSLDestroy( papszTokens );
+    }
+}
+
+/************************************************************************/
+/*                         GetGeoTransform()                            */
+/************************************************************************/
+
+CPLErr ROIPACDataset::GetGeoTransform( double *padfTransform )
+{
+    memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform) );
+    return (bValidGeoTransform) ? CE_None : CE_Failure;
+}
+
+/************************************************************************/
+/*                          SetGeoTransform()                           */
+/************************************************************************/
+
+CPLErr ROIPACDataset::SetGeoTransform( double *padfTransform )
+{
+    memcpy( adfGeoTransform, padfTransform, sizeof(adfGeoTransform) );
+    bValidGeoTransform = true;
+    return CE_None;
+}
+
+/************************************************************************/
+/*                         GetProjectionRef()                           */
+/************************************************************************/
+
+const char *ROIPACDataset::GetProjectionRef( void )
+{
+    return (pszProjection != NULL) ? pszProjection : "";
+}
+
+/************************************************************************/
+/*                          SetProjection()                             */
+/************************************************************************/
+
+CPLErr ROIPACDataset::SetProjection( const char *pszNewProjection )
+
+{
+    CPLFree( pszProjection );
+    pszProjection = (pszNewProjection) ? CPLStrdup( pszNewProjection ) : NULL;
+    return CE_None;
+}
+
+/************************************************************************/
+/*                            GetFileList()                             */
+/************************************************************************/
+
+char **ROIPACDataset::GetFileList()
+{
+    char **papszFileList = NULL;
+
+    // Main data file, etc.  
+    papszFileList = RawDataset::GetFileList();
+
+    // RSC file. 
+    papszFileList = CSLAddString( papszFileList, pszRscFilename );
+
+    return papszFileList;
+}
+
+/************************************************************************/
+/*                         ROIPACRasterBand()                           */
+/************************************************************************/
+
+ROIPACRasterBand::ROIPACRasterBand( GDALDataset *poDS, int nBand, void *fpRaw,
+                                    vsi_l_offset nImgOffset, int nPixelOffset,
+                                    int nLineOffset,
+                                    GDALDataType eDataType, int bNativeOrder,
+                                    int bIsVSIL, int bOwnsFP ) :
+        RawRasterBand(poDS, nBand, fpRaw, nImgOffset, nPixelOffset,
+                      nLineOffset, eDataType, bNativeOrder, bIsVSIL, bOwnsFP)
+{
+}
+
+/************************************************************************/
+/*                        GDALRegister_ROIPAC()                         */
+/************************************************************************/
+
+void GDALRegister_ROIPAC( void )
+{
+    GDALDriver  *poDriver;
+
+    if (!GDAL_CHECK_VERSION("ROI_PAC"))
+    {
+        return;
+    }
+
+    if ( GDALGetDriverByName( "ROI_PAC" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+        
+        poDriver->SetDescription( "ROI_PAC" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
+                                   "ROI_PAC raster" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
+                                   "frmt_various.html#ROI_PAC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = ROIPACDataset::Open;
+        poDriver->pfnIdentify = ROIPACDataset::Identify;
+        poDriver->pfnCreate = ROIPACDataset::Create;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/frmts/raw/snodasdataset.cpp b/frmts/raw/snodasdataset.cpp
index 04e2ad9..194196f 100644
--- a/frmts/raw/snodasdataset.cpp
+++ b/frmts/raw/snodasdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: snodasdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: snodasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SNODAS driver
  * Purpose:  Implementation of SNODASDataset
@@ -31,7 +31,7 @@
 #include "ogr_srs_api.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: snodasdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: snodasdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 // g++ -g -Wall -fPIC frmts/raw/snodasdataset.cpp -shared -o gdal_SNODAS.so -Iport -Igcore -Ifrmts/raw -Iogr -L. -lgdal
 
@@ -501,6 +501,7 @@ void GDALRegister_SNODAS()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "SNODAS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Snow Data Assimilation System" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/rik/GNUmakefile b/frmts/rik/GNUmakefile
index 6e9016b..b7de07f 100644
--- a/frmts/rik/GNUmakefile
+++ b/frmts/rik/GNUmakefile
@@ -9,7 +9,7 @@ endif
 
 OBJ	=	rikdataset.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/rik/rikdataset.cpp b/frmts/rik/rikdataset.cpp
index 150449b..76580a4 100644
--- a/frmts/rik/rikdataset.cpp
+++ b/frmts/rik/rikdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rikdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rikdataset.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  RIK Reader
  * Purpose:  All code for RIK Reader
@@ -32,7 +32,7 @@
 #include <zlib.h>
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: rikdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rikdataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_RIK(void);
@@ -122,7 +122,7 @@ class RIKDataset : public GDALPamDataset
 {
     friend class RIKRasterBand;
 
-    FILE        *fp;
+    VSILFILE        *fp;
 
     double      fTransform[6];
 
@@ -140,6 +140,7 @@ class RIKDataset : public GDALPamDataset
     ~RIKDataset();
 
     static GDALDataset *Open( GDALOpenInfo * );
+    static int Identify( GDALOpenInfo * );
 
     CPLErr 	GetGeoTransform( double * padfTransform );
     const char *GetProjectionRef();
@@ -314,7 +315,7 @@ CPLErr RIKRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         return CE_None;
     }
 
-    VSIFSeek( poRDS->fp, nBlockOffset, SEEK_SET );
+    VSIFSeekL( poRDS->fp, nBlockOffset, SEEK_SET );
 
 /* -------------------------------------------------------------------- */
 /*      Read uncompressed block.                                        */
@@ -322,13 +323,13 @@ CPLErr RIKRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
 
     if( poRDS->options == 0x00 || poRDS->options == 0x40 )
     {
-        VSIFRead( pImage, 1, nBlockSize, poRDS->fp );
+        VSIFReadL( pImage, 1, nBlockSize, poRDS->fp );
         return CE_None;
     }
 
     // Read block to memory
     blockData = (GByte *) CPLMalloc(nBlockSize);
-    VSIFRead( blockData, 1, nBlockSize, poRDS->fp );
+    VSIFReadL( blockData, 1, nBlockSize, poRDS->fp );
 
     GUInt32 filePos = 0;
     GUInt32 imagePos = 0;
@@ -406,7 +407,7 @@ CPLErr RIKRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
             lastCode = code;
             code = GetNextLZWCode( codeBits, blockData,
                                    filePos, fileAlign, bitsTaken );
-            if( VSIFEof( poRDS->fp ) )
+            if( VSIFEofL( poRDS->fp ) )
             {
                 CPLFree( blockData );
                 CPLError( CE_Failure, CPLE_AppDefined,
@@ -604,7 +605,7 @@ RIKDataset::~RIKDataset()
     FlushCache();
     CPLFree( pOffsets );
     if( fp != NULL )
-        VSIFClose( fp );
+        VSIFCloseL( fp );
     delete poColorTable;
 }
 
@@ -634,14 +635,14 @@ const char *RIKDataset::GetProjectionRef()
 /*                             GetRikString()                           */
 /************************************************************************/
 
-static GUInt16 GetRikString( FILE *fp,
+static GUInt16 GetRikString( VSILFILE *fp,
                              char *str,
                              GUInt16 strLength )
 
 {
     GUInt16 actLength;
 
-    VSIFRead( &actLength, 1, sizeof(actLength), fp );
+    VSIFReadL( &actLength, 1, sizeof(actLength), fp );
 #ifdef CPL_MSB
     CPL_SWAP16PTR( &actLength );
 #endif
@@ -651,7 +652,7 @@ static GUInt16 GetRikString( FILE *fp,
         return actLength;
     }
 
-    VSIFRead( str, 1, actLength, fp );
+    VSIFReadL( str, 1, actLength, fp );
 
     str[actLength] = '\0';
 
@@ -659,13 +660,48 @@ static GUInt16 GetRikString( FILE *fp,
 }
 
 /************************************************************************/
+/*                          Identify()                                  */
+/************************************************************************/
+
+int RIKDataset::Identify( GDALOpenInfo * poOpenInfo )
+
+{
+    if( poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 50 )
+        return FALSE;
+
+    if( EQUALN((const char *) poOpenInfo->pabyHeader, "RIK3", 4) )
+    {
+        return TRUE;
+    }
+    else
+    {
+        GUInt16 actLength;
+        memcpy(&actLength, poOpenInfo->pabyHeader, 2);
+#ifdef CPL_MSB
+        CPL_SWAP16PTR( &actLength );
+#endif
+        if( actLength + 2 > 1024 )
+        {
+            return FALSE;
+        }
+        if( actLength == 0 )
+            return -1;
+        if( strlen( (const char*)poOpenInfo->pabyHeader + 2 ) != actLength )
+        {
+            return FALSE;
+        }
+        return TRUE;
+    }
+}
+
+/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
 GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if( poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 50 )
+    if( Identify(poOpenInfo) == FALSE )
         return NULL;
 
     bool rik3header = false;
@@ -673,12 +709,10 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
     if( EQUALN((const char *) poOpenInfo->pabyHeader, "RIK3", 4) )
     {
         rik3header = true;
+        VSIFSeekL( poOpenInfo->fpL, 4, SEEK_SET );
     }
-
-    if( rik3header )
-        VSIFSeek( poOpenInfo->fp, 4, SEEK_SET );
     else
-        VSIFSeek( poOpenInfo->fp, 0, SEEK_SET );
+        VSIFSeekL( poOpenInfo->fpL, 0, SEEK_SET );
 
 /* -------------------------------------------------------------------- */
 /*      Read the map name.                                              */
@@ -686,7 +720,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
     char name[1024];
 
-    GUInt16 nameLength = GetRikString( poOpenInfo->fp, name, sizeof(name) );
+    GUInt16 nameLength = GetRikString( poOpenInfo->fpL, name, sizeof(name) );
 
     if( nameLength > sizeof(name) - 1 )
     {
@@ -718,7 +752,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
         char projection[1024];
 
-        GUInt16 projLength = GetRikString( poOpenInfo->fp,
+        GUInt16 projLength = GetRikString( poOpenInfo->fpL,
                                            projection, sizeof(projection) );
 
         if( projLength > sizeof(projection) - 1 )
@@ -729,13 +763,13 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
         // Read unknown string
 
-        projLength = GetRikString( poOpenInfo->fp, projection, sizeof(projection) );
+        projLength = GetRikString( poOpenInfo->fpL, projection, sizeof(projection) );
 
         // Read map north edge
 
         char tmpStr[16];
 
-        GUInt16 tmpLength = GetRikString( poOpenInfo->fp,
+        GUInt16 tmpLength = GetRikString( poOpenInfo->fpL,
                                           tmpStr, sizeof(tmpStr) );
 
         if( tmpLength > sizeof(tmpStr) - 1 )
@@ -744,11 +778,11 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
             return NULL;
         }
 
-        header.fNorth = atof( tmpStr );
+        header.fNorth = CPLAtof( tmpStr );
 
         // Read map west edge
 
-        tmpLength = GetRikString( poOpenInfo->fp,
+        tmpLength = GetRikString( poOpenInfo->fpL,
                                   tmpStr, sizeof(tmpStr) );
 
         if( tmpLength > sizeof(tmpStr) - 1 )
@@ -757,16 +791,16 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
             return NULL;
         }
 
-        header.fWest = atof( tmpStr );
+        header.fWest = CPLAtof( tmpStr );
 
         // Read binary values
 
-        VSIFRead( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fp );
-        VSIFRead( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fp );
-        VSIFRead( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fp );
-        VSIFRead( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fp );
-        VSIFRead( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fp );
-        VSIFRead( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fp );
+        VSIFReadL( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL );
+        VSIFReadL( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL );
+        VSIFReadL( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fpL );
+        VSIFReadL( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fpL );
+        VSIFReadL( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fpL );
+        VSIFReadL( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fpL );
 #ifdef CPL_MSB
         CPL_SWAP32PTR( &header.iScale );
         CPL_SWAP32PTR( &header.iMPPNum );
@@ -776,10 +810,10 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
         CPL_SWAP32PTR( &header.iVertBlocks );
 #endif
 
-        VSIFRead( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fp );
-        VSIFRead( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fp );
+        VSIFReadL( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fpL );
+        VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL );
         header.iUnknown = header.iOptions;
-        VSIFRead( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fp );
+        VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL );
 
         header.fSouth = header.fNorth -
             header.iVertBlocks * header.iBlockHeight * header.iMPPNum;
@@ -794,13 +828,13 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Old RIK header.                                                 */
 /* -------------------------------------------------------------------- */
 
-        VSIFRead( &header.iUnknown, 1, sizeof(header.iUnknown), poOpenInfo->fp );
-        VSIFRead( &header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fp );
-        VSIFRead( &header.fWest, 1, sizeof(header.fWest), poOpenInfo->fp );
-        VSIFRead( &header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fp );
-        VSIFRead( &header.fEast, 1, sizeof(header.fEast), poOpenInfo->fp );
-        VSIFRead( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fp );
-        VSIFRead( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fp );
+        VSIFReadL( &header.iUnknown, 1, sizeof(header.iUnknown), poOpenInfo->fpL );
+        VSIFReadL( &header.fSouth, 1, sizeof(header.fSouth), poOpenInfo->fpL );
+        VSIFReadL( &header.fWest, 1, sizeof(header.fWest), poOpenInfo->fpL );
+        VSIFReadL( &header.fNorth, 1, sizeof(header.fNorth), poOpenInfo->fpL );
+        VSIFReadL( &header.fEast, 1, sizeof(header.fEast), poOpenInfo->fpL );
+        VSIFReadL( &header.iScale, 1, sizeof(header.iScale), poOpenInfo->fpL );
+        VSIFReadL( &header.iMPPNum, 1, sizeof(header.iMPPNum), poOpenInfo->fpL );
 #ifdef CPL_MSB
         CPL_SWAP64PTR( &header.fSouth );
         CPL_SWAP64PTR( &header.fWest );
@@ -829,7 +863,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
             header.fWest += 201000;
             header.fEast += 302005;
 
-            VSIFRead( &header.iMPPDen, 1, sizeof(header.iMPPDen), poOpenInfo->fp );
+            VSIFReadL( &header.iMPPDen, 1, sizeof(header.iMPPDen), poOpenInfo->fpL );
 #ifdef CPL_MSB
             CPL_SWAP32PTR( &header.iMPPDen );
 #endif
@@ -843,9 +877,9 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
         metersPerPixel = header.iMPPNum / double(header.iMPPDen);
 
-        VSIFRead( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fp );
-        VSIFRead( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fp );
-        VSIFRead( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fp );
+        VSIFReadL( &header.iBlockWidth, 1, sizeof(header.iBlockWidth), poOpenInfo->fpL );
+        VSIFReadL( &header.iBlockHeight, 1, sizeof(header.iBlockHeight), poOpenInfo->fpL );
+        VSIFReadL( &header.iHorBlocks, 1, sizeof(header.iHorBlocks), poOpenInfo->fpL );
 #ifdef CPL_MSB
         CPL_SWAP32PTR( &header.iBlockWidth );
         CPL_SWAP32PTR( &header.iBlockHeight );
@@ -858,7 +892,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
         if( !offsetBounds )
         {
-            VSIFRead( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fp );
+            VSIFReadL( &header.iVertBlocks, 1, sizeof(header.iVertBlocks), poOpenInfo->fpL );
 #ifdef CPL_MSB
             CPL_SWAP32PTR( &header.iVertBlocks );
 #endif
@@ -877,7 +911,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
                   header.iVertBlocks );
 #endif
 
-        VSIFRead( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fp );
+        VSIFReadL( &header.iBitsPerPixel, 1, sizeof(header.iBitsPerPixel), poOpenInfo->fpL );
 
         if( header.iBitsPerPixel != 8 )
         {
@@ -887,7 +921,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
             return NULL;
         }
 
-        VSIFRead( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fp );
+        VSIFReadL( &header.iOptions, 1, sizeof(header.iOptions), poOpenInfo->fpL );
 
         if( !header.iHorBlocks || !header.iVertBlocks )
            return NULL;
@@ -915,9 +949,9 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
     GUInt16 i;
     for( i = 0; i < 256; i++ )
     {
-        VSIFRead( &palette[i * 3 + 2], 1, 1, poOpenInfo->fp );
-        VSIFRead( &palette[i * 3 + 1], 1, 1, poOpenInfo->fp );
-        VSIFRead( &palette[i * 3 + 0], 1, 1, poOpenInfo->fp );
+        VSIFReadL( &palette[i * 3 + 2], 1, 1, poOpenInfo->fpL );
+        VSIFReadL( &palette[i * 3 + 1], 1, 1, poOpenInfo->fpL );
+        VSIFReadL( &palette[i * 3 + 0], 1, 1, poOpenInfo->fpL );
     }
 
 /* -------------------------------------------------------------------- */
@@ -940,7 +974,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
     if( header.iOptions == 0x00 )
     {
-        offsets[0] = VSIFTell( poOpenInfo->fp );
+        offsets[0] = VSIFTellL( poOpenInfo->fpL );
 
         for( GUInt32 i = 1; i < blocks; i++ )
         {
@@ -952,14 +986,14 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
     {
         for( GUInt32 i = 0; i < blocks; i++ )
         {
-            VSIFRead( &offsets[i], 1, sizeof(offsets[i]), poOpenInfo->fp );
+            VSIFReadL( &offsets[i], 1, sizeof(offsets[i]), poOpenInfo->fpL );
 #ifdef CPL_MSB
             CPL_SWAP32PTR( &offsets[i] );
 #endif
             if( rik3header )
             {
                 GUInt32 blockSize;
-                VSIFRead( &blockSize, 1, sizeof(blockSize), poOpenInfo->fp );
+                VSIFReadL( &blockSize, 1, sizeof(blockSize), poOpenInfo->fpL );
 #ifdef CPL_MSB
                 CPL_SWAP32PTR( &blockSize );
 #endif
@@ -973,7 +1007,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
     // File size
 
-    if( VSIFEof( poOpenInfo->fp ) )
+    if( VSIFEofL( poOpenInfo->fpL ) )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "File %s. Read past end of file.\n",
@@ -981,8 +1015,8 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
         return NULL;
     }
 
-    VSIFSeek( poOpenInfo->fp, 0, SEEK_END );
-    GUInt32 fileSize = VSIFTell( poOpenInfo->fp );
+    VSIFSeekL( poOpenInfo->fpL, 0, SEEK_END );
+    GUInt32 fileSize = VSIFTellL( poOpenInfo->fpL );
 
 #if RIK_HEADER_DEBUG
     CPLDebug( "RIK",
@@ -1084,8 +1118,8 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 
     poDS = new RIKDataset();
 
-    poDS->fp = poOpenInfo->fp;
-    poOpenInfo->fp = NULL;
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
 
     poDS->fTransform[0] = header.fWest - metersPerPixel / 2.0;
     poDS->fTransform[1] = metersPerPixel;
@@ -1135,7 +1169,7 @@ GDALDataset *RIKDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Confirm the requested access is supported.                      */
@@ -1166,13 +1200,17 @@ void GDALRegister_RIK()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "RIK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Swedish Grid RIK (.rik)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
                                    "frmt_various.html#RIK" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rik" );
 
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
         poDriver->pfnOpen = RIKDataset::Open;
+        poDriver->pfnIdentify = RIKDataset::Identify;
 
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
diff --git a/frmts/rmf/GNUmakefile b/frmts/rmf/GNUmakefile
index 2b61186..edcfce0 100644
--- a/frmts/rmf/GNUmakefile
+++ b/frmts/rmf/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	rmfdataset.o rmflzw.o rmfdem.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/rmf/rmfdataset.cpp b/frmts/rmf/rmfdataset.cpp
index 6b717ce..337083a 100644
--- a/frmts/rmf/rmfdataset.cpp
+++ b/frmts/rmf/rmfdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rmfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Raster Matrix Format
  * Purpose:  Read/write raster files used in GIS "Integratsia"
@@ -33,7 +33,7 @@
 
 #include "rmfdataset.h"
 
-CPL_CVSID("$Id: rmfdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void    GDALRegister_RMF(void);
@@ -1810,6 +1810,7 @@ void GDALRegister_RMF()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "RMF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "Raster Matrix Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/rs2/GNUmakefile b/frmts/rs2/GNUmakefile
index 3dfb2e0..1c42e70 100644
--- a/frmts/rs2/GNUmakefile
+++ b/frmts/rs2/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	rs2dataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/rs2/rs2dataset.cpp b/frmts/rs2/rs2dataset.cpp
index b7daf1a..525ad1f 100644
--- a/frmts/rs2/rs2dataset.cpp
+++ b/frmts/rs2/rs2dataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rs2dataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: rs2dataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Polarimetric Workstation
  * Purpose:  Radarsat 2 - XML Products (product.xml) driver
@@ -32,7 +32,7 @@
 #include "cpl_minixml.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: rs2dataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: rs2dataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_RS2(void);
@@ -223,7 +223,7 @@ CPLErr RS2RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                   nRequestXSize, nRequestYSize,
                                   pImage, nRequestXSize, nRequestYSize, 
                                   GDT_Int16,
-                                  2, NULL, 4, nBlockXSize * 4, 2 );
+                                  2, NULL, 4, nBlockXSize * 4, 2, NULL );
 
 /* -------------------------------------------------------------------- */
 /*      File has one sample marked as sample format void, a 32bits.     */
@@ -239,7 +239,7 @@ CPLErr RS2RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                   nRequestXSize, nRequestYSize, 
                                   pImage, nRequestXSize, nRequestYSize, 
                                   GDT_UInt32,
-                                  1, NULL, 4, nBlockXSize * 4, 0 );
+                                  1, NULL, 4, nBlockXSize * 4, 0, NULL );
 
 #ifdef CPL_LSB
         /* First, undo the 32bit swap. */
@@ -264,7 +264,7 @@ CPLErr RS2RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                   nRequestXSize, nRequestYSize, 
                                   pImage, nRequestXSize, nRequestYSize,
                                   GDT_UInt16,
-                                  1, NULL, 2, nBlockXSize * 2, 0 );
+                                  1, NULL, 2, nBlockXSize * 2, 0, NULL );
     else if ( eDataType == GDT_Byte ) 
         /* Ticket #2104: Support for ScanSAR products */
         return
@@ -274,7 +274,7 @@ CPLErr RS2RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                   nRequestXSize, nRequestYSize,
                                   pImage, nRequestXSize, nRequestYSize,
                                   GDT_Byte,
-                                  1, NULL, 1, nBlockXSize, 0 );
+                                  1, NULL, 1, nBlockXSize, 0, NULL );
     else
     {
         CPLAssert( FALSE );
@@ -428,7 +428,7 @@ CPLErr RS2CalibRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                   nBlockXSize, nRequestYSize,
                                   pnImageTmp, nBlockXSize, nRequestYSize, 
                                   GDT_Int16,
-                                  2, NULL, 4, nBlockXSize * 4, 2 );
+                                  2, NULL, 4, nBlockXSize * 4, 2, NULL );
 
         }
         else {
@@ -439,7 +439,7 @@ CPLErr RS2CalibRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                       nBlockXSize, nRequestYSize, 
                                       pnImageTmp, nBlockXSize, nRequestYSize, 
                                       GDT_UInt32,
-                                      1, NULL, 4, nBlockXSize * 4, 0 );
+                                      1, NULL, 4, nBlockXSize * 4, 0, NULL );
 
 #ifdef CPL_LSB
             /* First, undo the 32bit swap. */ 
@@ -475,7 +475,7 @@ CPLErr RS2CalibRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                               nBlockXSize, nRequestYSize, 
                               pnImageTmp, nBlockXSize, nRequestYSize,
                               GDT_UInt16,
-                              1, NULL, 2, nBlockXSize * 2, 0 );
+                              1, NULL, 2, nBlockXSize * 2, 0, NULL );
 
         /* iterate over detected values */
         for (int i = 0; i < nBlockYSize; i++) {
@@ -499,7 +499,7 @@ CPLErr RS2CalibRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                             nBlockXSize, nRequestYSize,
                             pnImageTmp, nBlockXSize, nRequestYSize,
                             GDT_Byte,
-                            1, NULL, 1, 1, 0);
+                            1, NULL, 1, 1, 0, NULL);
 
         /* iterate over detected values */
         for (int i = 0; i < nBlockYSize; i++) {
@@ -1135,17 +1135,17 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
             double testx, testy, br_x, br_y, tl_x, tl_y, tr_x, tr_y, 
                 bl_x, bl_y; 
 
-            tl_x = strtod(CPLGetXMLValue( psPos, 
+            tl_x = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "upperLeftCorner.mapCoordinate.easting", "0.0" ), NULL);
-            tl_y = strtod(CPLGetXMLValue( psPos, 
+            tl_y = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "upperLeftCorner.mapCoordinate.northing", "0.0" ), NULL);
-            bl_x = strtod(CPLGetXMLValue( psPos, 
+            bl_x = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "lowerLeftCorner.mapCoordinate.easting", "0.0" ), NULL);
-            bl_y = strtod(CPLGetXMLValue( psPos, 
+            bl_y = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "lowerLeftCorner.mapCoordinate.northing", "0.0" ), NULL);
-            tr_x = strtod(CPLGetXMLValue( psPos, 
+            tr_x = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "upperRightCorner.mapCoordinate.easting", "0.0" ), NULL);
-            tr_y = strtod(CPLGetXMLValue( psPos, 
+            tr_y = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "upperRightCorner.mapCoordinate.northing", "0.0" ), NULL);
             poDS->adfGeoTransform[1] = (tr_x - tl_x)/(poDS->nRasterXSize - 1);
             poDS->adfGeoTransform[4] = (tr_y - tl_y)/(poDS->nRasterXSize - 1);
@@ -1157,9 +1157,9 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
                                         - 0.5*poDS->adfGeoTransform[5]);
 
             /* Use bottom right pixel to test geotransform */
-            br_x = strtod(CPLGetXMLValue( psPos, 
+            br_x = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "lowerRightCorner.mapCoordinate.easting", "0.0"  ), NULL);
-            br_y = strtod(CPLGetXMLValue( psPos, 
+            br_y = CPLStrtod(CPLGetXMLValue( psPos, 
                                           "lowerRightCorner.mapCoordinate.northing", "0.0"  ), NULL);
             testx = poDS->adfGeoTransform[0] + poDS->adfGeoTransform[1] *
                 (poDS->nRasterXSize - 0.5) + poDS->adfGeoTransform[2] *
@@ -1200,9 +1200,9 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
         OGRSpatialReference oLL, oPrj;
 
         pszEllipsoidName = CPLGetXMLValue( psEllipsoid, "ellipsoidName", "" );
-        minor_axis = atof(CPLGetXMLValue( psEllipsoid, "semiMinorAxis", 
+        minor_axis = CPLAtof(CPLGetXMLValue( psEllipsoid, "semiMinorAxis", 
                                           "0.0" ));
-        major_axis = atof(CPLGetXMLValue( psEllipsoid, "semiMajorAxis", 
+        major_axis = CPLAtof(CPLGetXMLValue( psEllipsoid, "semiMajorAxis", 
                                           "0.0" ));
 
         if ( EQUAL(pszEllipsoidName, "") || ( minor_axis == 0.0 ) || 
@@ -1248,9 +1248,9 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
                 pszHemisphere = CPLGetXMLValue( psUtmParams,
                                                 "hemisphere", "" );
 #if 0
-                origEasting = strtod(CPLGetXMLValue( psUtmParams,
+                origEasting = CPLStrtod(CPLGetXMLValue( psUtmParams,
                                                      "mapOriginFalseEasting", "0.0" ), NULL);
-                origNorthing = strtod(CPLGetXMLValue( psUtmParams,
+                origNorthing = CPLStrtod(CPLGetXMLValue( psUtmParams,
                                                       "mapOriginFalseNorthing", "0.0" ), NULL);
 #endif
                 if ( EQUALN(pszHemisphere,"southern",8) )
@@ -1264,17 +1264,17 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
             else if ((psNspParams != NULL) && poDS->bHaveGeoTransform) {
                 double origEasting, origNorthing, copLong, copLat, sP1, sP2;
 
-                origEasting = strtod(CPLGetXMLValue( psNspParams, 
+                origEasting = CPLStrtod(CPLGetXMLValue( psNspParams, 
                                                      "mapOriginFalseEasting", "0.0" ), NULL);
-                origNorthing = strtod(CPLGetXMLValue( psNspParams, 
+                origNorthing = CPLStrtod(CPLGetXMLValue( psNspParams, 
                                                       "mapOriginFalseNorthing", "0.0" ), NULL);
-                copLong = strtod(CPLGetXMLValue( psNspParams,  
+                copLong = CPLStrtod(CPLGetXMLValue( psNspParams,  
                                                  "centerOfProjectionLongitude", "0.0" ), NULL);
-                copLat = strtod(CPLGetXMLValue( psNspParams, 
+                copLat = CPLStrtod(CPLGetXMLValue( psNspParams, 
                                                 "centerOfProjectionLatitude", "0.0" ), NULL);
-                sP1 = strtod(CPLGetXMLValue( psNspParams, 
+                sP1 = CPLStrtod(CPLGetXMLValue( psNspParams, 
                                              "standardParallels1", "0.0" ), NULL);
-                sP2 = strtod(CPLGetXMLValue( psNspParams, 
+                sP2 = CPLStrtod(CPLGetXMLValue( psNspParams, 
                                              "standardParallels2", "0.0" ), NULL);
 
                 if (EQUALN(pszProj,"ARC",3)) {
@@ -1359,15 +1359,15 @@ GDALDataset *RS2Dataset::Open( GDALOpenInfo * poOpenInfo )
             psGCP->pszId = CPLStrdup( szID );
             psGCP->pszInfo = CPLStrdup("");
             psGCP->dfGCPPixel = 
-                atof(CPLGetXMLValue(psNode,"imageCoordinate.pixel","0"));
+                CPLAtof(CPLGetXMLValue(psNode,"imageCoordinate.pixel","0"));
             psGCP->dfGCPLine = 
-                atof(CPLGetXMLValue(psNode,"imageCoordinate.line","0"));
+                CPLAtof(CPLGetXMLValue(psNode,"imageCoordinate.line","0"));
             psGCP->dfGCPX = 
-                atof(CPLGetXMLValue(psNode,"geodeticCoordinate.longitude",""));
+                CPLAtof(CPLGetXMLValue(psNode,"geodeticCoordinate.longitude",""));
             psGCP->dfGCPY = 
-                atof(CPLGetXMLValue(psNode,"geodeticCoordinate.latitude",""));
+                CPLAtof(CPLGetXMLValue(psNode,"geodeticCoordinate.latitude",""));
             psGCP->dfGCPZ = 
-                atof(CPLGetXMLValue(psNode,"geodeticCoordinate.height",""));
+                CPLAtof(CPLGetXMLValue(psNode,"geodeticCoordinate.height",""));
         }
     }
 
@@ -1520,6 +1520,7 @@ void GDALRegister_RS2()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "RS2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "RadarSat 2 XML Product" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_rs2.html" );
diff --git a/frmts/saga/GNUmakefile b/frmts/saga/GNUmakefile
index a53b0ed..985aa34 100644
--- a/frmts/saga/GNUmakefile
+++ b/frmts/saga/GNUmakefile
@@ -3,8 +3,6 @@ include ../../GDALmake.opt
 
 OBJ	=	sagadataset.o
 
-CPPFLAGS	=	$(GDAL_INCLUDE)
-
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
 clean:
diff --git a/frmts/saga/sagadataset.cpp b/frmts/saga/sagadataset.cpp
index fb10cb7..26db273 100644
--- a/frmts/saga/sagadataset.cpp
+++ b/frmts/saga/sagadataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sagadataset.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: sagadataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  * Project:  SAGA GIS Binary Driver
  * Purpose:  Implements the SAGA GIS Binary Grid Format.
  * Author:   Volker Wichmann, wichmann at laserdata.at
@@ -37,7 +37,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: sagadataset.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: sagadataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #ifndef INT_MAX
 # define INT_MAX 2147483647
@@ -673,7 +673,7 @@ GDALDataset *SAGADataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -1084,6 +1084,7 @@ void GDALRegister_SAGA()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "SAGA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "SAGA GIS Binary Grid (.sdat)" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/sde/GNUmakefile b/frmts/sde/GNUmakefile
index 2814186..452569a 100644
--- a/frmts/sde/GNUmakefile
+++ b/frmts/sde/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	sdedataset.o sdeerror.o sderasterband.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(SDE_INC) -DFRMT_sde $(CPPFLAGS)
+CPPFLAGS	:=	 $(SDE_INC) -DFRMT_sde $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/sde/sdedataset.cpp b/frmts/sde/sdedataset.cpp
index 09b1596..7c4dc68 100644
--- a/frmts/sde/sdedataset.cpp
+++ b/frmts/sde/sdedataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sdedataset.cpp 22255 2011-04-29 19:03:26Z warmerdam $
+ * $Id: sdedataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  ESRI ArcSDE Raster reader
  * Purpose:  Dataset implementaion for ESRI ArcSDE Rasters
@@ -526,6 +526,7 @@ void GDALRegister_SDE()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "SDE" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ESRI ArcSDE" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/sdts/GNUmakefile b/frmts/sdts/GNUmakefile
index 6307363..a1cd2b8 100644
--- a/frmts/sdts/GNUmakefile
+++ b/frmts/sdts/GNUmakefile
@@ -12,7 +12,7 @@ OBJ	=	sdtsiref.o sdtscatd.o sdtslinereader.o sdtslib.o \
 		sdtspolygonreader.o sdtsxref.o sdtsrasterreader.o \
 		sdtsindexedreader.o
 
-CPPFLAGS :=	-I$(ISO8211DIR) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS :=	-I$(ISO8211DIR)  $(CPPFLAGS)
 
 SDTSLIB	=	libsdts_al.a
 LIBS	:=	$(SDTSLIB) $(ISO8211DIR)/libiso8211.a $(GDAL_LIB) $(LIBS)
diff --git a/frmts/sdts/sdts2shp.cpp b/frmts/sdts/sdts2shp.cpp
index e15c38b..a23c906 100644
--- a/frmts/sdts/sdts2shp.cpp
+++ b/frmts/sdts/sdts2shp.cpp
@@ -1,5 +1,5 @@
 /* ****************************************************************************
- * $Id: sdts2shp.cpp 19952 2010-07-02 05:44:18Z warmerdam $
+ * $Id: sdts2shp.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  SDTS Translator
  * Purpose:  Mainline for converting to ArcView Shapefiles.
@@ -31,7 +31,7 @@
 #include "shapefil.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: sdts2shp.cpp 19952 2010-07-02 05:44:18Z warmerdam $");
+CPL_CVSID("$Id: sdts2shp.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 static int  bVerbose = FALSE;
 
@@ -111,7 +111,7 @@ int main( int nArgc, char ** papszArgv )
 /* -------------------------------------------------------------------- */
 /*      Massage shapefile name to have no extension.                    */
 /* -------------------------------------------------------------------- */
-    pszShapefile = strdup( pszShapefile );
+    pszShapefile = CPLStrdup(pszShapefile);
     for( i = strlen(pszShapefile)-1; i >= 0; i-- )
     {
         if( pszShapefile[i] == '.' )
diff --git a/frmts/sdts/sdtsdataset.cpp b/frmts/sdts/sdtsdataset.cpp
index 0cc3e67..66df9a7 100644
--- a/frmts/sdts/sdtsdataset.cpp
+++ b/frmts/sdts/sdtsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sdtsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: sdtsdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SDTS Translator
  * Purpose:  GDALDataset driver for SDTS Raster translator.
@@ -32,7 +32,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: sdtsdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: sdtsdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /**
  \file sdtsdataset.cpp
@@ -289,7 +289,7 @@ GDALDataset *SDTSDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
 /*      Check for external overviews.                                   */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return( poDS );
 }
@@ -400,6 +400,7 @@ void GDALRegister_SDTS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "SDTS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "SDTS Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/sdts/sdtslinereader.cpp b/frmts/sdts/sdtslinereader.cpp
index 0ce905d..1d7ad75 100644
--- a/frmts/sdts/sdtslinereader.cpp
+++ b/frmts/sdts/sdtslinereader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sdtslinereader.cpp 25839 2013-04-02 18:54:20Z rouault $
+ * $Id: sdtslinereader.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  SDTS Translator
  * Purpose:  Implementation of SDTSLineReader and SDTSRawLine classes.
@@ -29,7 +29,7 @@
 
 #include "sdts_al.h"
 
-CPL_CVSID("$Id: sdtslinereader.cpp 25839 2013-04-02 18:54:20Z rouault $");
+CPL_CVSID("$Id: sdtslinereader.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -73,7 +73,7 @@ SDTSRawLine::~SDTSRawLine()
 int SDTSRawLine::Read( SDTS_IREF * poIREF, DDFRecord * poRecord )
 
 {
-    // E.Rouault: Not sure if this test is really usefull
+    // E.Rouault: Not sure if this test is really useful
     if( poRecord->GetStringSubfield( "LINE", 0, "MODN", 0 ) == NULL )
         return FALSE;
     
diff --git a/frmts/sdts/sdtsrasterreader.cpp b/frmts/sdts/sdtsrasterreader.cpp
index 41ac301..3d514b4 100644
--- a/frmts/sdts/sdtsrasterreader.cpp
+++ b/frmts/sdts/sdtsrasterreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sdtsrasterreader.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: sdtsrasterreader.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SDTS Translator
  * Purpose:  Implementation of SDTSRasterReader class.
@@ -30,7 +30,7 @@
 
 #include "sdts_al.h"
 
-CPL_CVSID("$Id: sdtsrasterreader.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: sdtsrasterreader.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          SDTSRasterReader()                          */
@@ -363,12 +363,14 @@ int SDTSRasterReader::Open( SDTS_CATD * poCATD, SDTS_IREF * poIREF,
 
   */
 
-int SDTSRasterReader::GetBlock( CPL_UNUSED int nXOffset, int nYOffset, void * pData )
+int SDTSRasterReader::GetBlock( CPL_UNUSED int nXOffset,
+                                int nYOffset,
+                                void * pData )
 {
     DDFRecord   *poRecord = NULL;
     int         nBytesPerValue;
     int         iTry;
-    
+
     CPLAssert( nXOffset == 0 );
 
 /* -------------------------------------------------------------------- */
@@ -601,5 +603,3 @@ int SDTSRasterReader::GetMinMax( double * pdfMin, double * pdfMax,
     
     return !bFirst;
 }
-
-
diff --git a/frmts/sgi/GNUmakefile b/frmts/sgi/GNUmakefile
index a8129cd..e454177 100644
--- a/frmts/sgi/GNUmakefile
+++ b/frmts/sgi/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	= sgidataset.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/sgi/sgidataset.cpp b/frmts/sgi/sgidataset.cpp
index 198291d..c7e938f 100644
--- a/frmts/sgi/sgidataset.cpp
+++ b/frmts/sgi/sgidataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sgidataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: sgidataset.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SGI Image Driver
  * Purpose:  Implement SGI Image Support based on Paul Bourke's SGI Image code.
@@ -36,7 +36,7 @@
 #include "cpl_port.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: sgidataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: sgidataset.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 CPL_C_START
 void	GDALRegister_SGI(void);
@@ -266,12 +266,12 @@ SGIRasterBand::SGIRasterBand(SGIDataset* poDS, int nBand)
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr SGIRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr SGIRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff,
+                                 int nBlockYOff,
 				 void*  pImage)
-
 {
     SGIDataset* poGDS = (SGIDataset*) poDS;
-    
+
     CPLAssert(nBlockXOff == 0);
 
 /* -------------------------------------------------------------------- */
@@ -284,9 +284,9 @@ CPLErr SGIRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
 /*                             IWritelock()                             */
 /************************************************************************/
 
-CPLErr SGIRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr SGIRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void*  pImage)
-
 {
     SGIDataset* poGDS = (SGIDataset*) poDS;
     ImageRec *image = &(poGDS->image);
@@ -685,9 +685,11 @@ GDALDataset* SGIDataset::Open(GDALOpenInfo* poOpenInfo)
 /************************************************************************/
 
 GDALDataset *SGIDataset::Create( const char * pszFilename,
-                                 int nXSize, int nYSize, int nBands,
-                                 GDALDataType eType, CPL_UNUSED char **papszOptions )
-
+                                 int nXSize,
+                                 int nYSize,
+                                 int nBands,
+                                 GDALDataType eType,
+                                 CPL_UNUSED char **papszOptions )
 {
     if( eType != GDT_Byte )
     {
@@ -816,6 +818,7 @@ void GDALRegister_SGI()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription("SGI");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, 
                                   "SGI Image File Format 1.0");
         poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rgb");
@@ -828,4 +831,3 @@ void GDALRegister_SGI()
         GetGDALDriverManager()->RegisterDriver(poDriver);
     }
 }
-
diff --git a/frmts/srtmhgt/GNUmakefile b/frmts/srtmhgt/GNUmakefile
index 648af2a..663095b 100644
--- a/frmts/srtmhgt/GNUmakefile
+++ b/frmts/srtmhgt/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	= srtmhgtdataset.o
 
-CPPFLAGS	:=	$(XTRA_OPT) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(XTRA_OPT)  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/srtmhgt/srtmhgtdataset.cpp b/frmts/srtmhgt/srtmhgtdataset.cpp
index 03b2570..9a0044c 100644
--- a/frmts/srtmhgt/srtmhgtdataset.cpp
+++ b/frmts/srtmhgt/srtmhgtdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: srtmhgtdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: srtmhgtdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  SRTM HGT Driver
  * Purpose:  SRTM HGT File Read Support.
@@ -38,7 +38,7 @@
 
 #define SRTMHG_NODATA_VALUE -32768
 
-CPL_CVSID("$Id: srtmhgtdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: srtmhgtdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void	GDALRegister_SRTMHGT(void);
@@ -385,10 +385,12 @@ GDALDataset* SRTMHGTDataset::Open(GDALOpenInfo* poOpenInfo)
 /*                              CreateCopy()                            */
 /************************************************************************/
 
-GDALDataset * SRTMHGTDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-                                          int bStrict, CPL_UNUSED char ** papszOptions, 
-                                          GDALProgressFunc pfnProgress, void * pProgressData )
-
+GDALDataset * SRTMHGTDataset::CreateCopy( const char * pszFilename,
+                                          GDALDataset *poSrcDS,
+                                          int bStrict,
+                                          CPL_UNUSED char ** papszOptions,
+                                          GDALProgressFunc pfnProgress,
+                                          void * pProgressData )
 {
     int  nBands = poSrcDS->GetRasterCount();
     int  nXSize = poSrcDS->GetRasterXSize();
@@ -504,7 +506,7 @@ GDALDataset * SRTMHGTDataset::CreateCopy( const char * pszFilename, GDALDataset
     {
         poSrcBand->RasterIO( GF_Read, 0, iY, nXSize, 1,
                             (void *) panData, nXSize, 1,
-                            GDT_Int16, 0, 0 );
+                            GDT_Int16, 0, 0, NULL );
 
         /* Translate nodata values */
         if (bSrcBandHasNoData && srcBandNoData != SRTMHG_NODATA_VALUE)
@@ -566,6 +568,7 @@ void GDALRegister_SRTMHGT()
   {
     poDriver = new GDALDriver();
     poDriver->SetDescription("SRTMHGT");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SRTMHGT File Format");
     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hgt");
     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, 
@@ -582,4 +585,3 @@ void GDALRegister_SRTMHGT()
     GetGDALDriverManager()->RegisterDriver(poDriver);
   }
 }
-
diff --git a/frmts/terragen/GNUmakefile b/frmts/terragen/GNUmakefile
index 6d8ba54..113c183 100644
--- a/frmts/terragen/GNUmakefile
+++ b/frmts/terragen/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	terragendataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/terragen/terragendataset.cpp b/frmts/terragen/terragendataset.cpp
index d1c7a52..57e3ecc 100644
--- a/frmts/terragen/terragendataset.cpp
+++ b/frmts/terragen/terragendataset.cpp
@@ -106,7 +106,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-// CPL_CVSID("$Id: terragendataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+// CPL_CVSID("$Id: terragendataset.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void	GDALRegister_Terragen(void);
@@ -270,9 +270,9 @@ TerragenRasterBand::TerragenRasterBand( TerragenDataset *poDS )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr TerragenRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr TerragenRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                       int nBlockYOff,
                                        void* pImage )
-
 {
     //CPLAssert( sizeof(float) == sizeof(GInt32) );
     CPLAssert( nBlockXOff == 0  );
@@ -366,9 +366,9 @@ double TerragenRasterBand::GetOffset(int* pbSuccess)
 /************************************************************************/
 
 CPLErr TerragenRasterBand::IWriteBlock
-( 
-	CPL_UNUSED int nBlockXOff, 
-	int nBlockYOff,
+(
+    CPL_UNUSED int nBlockXOff,
+    int nBlockYOff,
     void* pImage
 )
 {
@@ -910,8 +910,8 @@ CPLErr TerragenDataset::SetProjection( const char * pszNewProjection )
 
         if( approx_equal(dfLinear, 0.3048))
             m_dMetersPerGroundUnit = 0.3048;
-        else if( approx_equal(dfLinear, atof(SRS_UL_US_FOOT_CONV)) )
-            m_dMetersPerGroundUnit = atof(SRS_UL_US_FOOT_CONV);
+        else if( approx_equal(dfLinear, CPLAtof(SRS_UL_US_FOOT_CONV)) )
+            m_dMetersPerGroundUnit = CPLAtof(SRS_UL_US_FOOT_CONV);
         else
             m_dMetersPerGroundUnit = 1.0;
     }
@@ -981,12 +981,12 @@ GDALDataset* TerragenDataset::Create
     const char* pszValue = CSLFetchNameValue( 
 		papszOptions,"MINUSERPIXELVALUE");
     if( pszValue != NULL )
-        poDS->m_dLogSpan[0] = atof( pszValue );
+        poDS->m_dLogSpan[0] = CPLAtof( pszValue );
 
     pszValue = CSLFetchNameValue( 
 		papszOptions,"MAXUSERPIXELVALUE");
     if( pszValue != NULL )
-        poDS->m_dLogSpan[1] = atof( pszValue );
+        poDS->m_dLogSpan[1] = CPLAtof( pszValue );
 
 
 	if( poDS->m_dLogSpan[1] <= poDS->m_dLogSpan[0] )
@@ -1143,6 +1143,7 @@ void GDALRegister_Terragen()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "Terragen" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, 
                                    "ter" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
@@ -1162,5 +1163,3 @@ void GDALRegister_Terragen()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
-
diff --git a/frmts/til/GNUmakefile b/frmts/til/GNUmakefile
index b59878f..d4d4363 100644
--- a/frmts/til/GNUmakefile
+++ b/frmts/til/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	tildataset.o
 
-CPPFLAGS	:=	-I../vrt $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../vrt  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/til/tildataset.cpp b/frmts/til/tildataset.cpp
index 7451835..06bc4cf 100644
--- a/frmts/til/tildataset.cpp
+++ b/frmts/til/tildataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tildataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: tildataset.cpp 29123 2015-05-03 11:05:46Z bishop $
  *
  * Project:  EarthWatch .TIL Driver
  * Purpose:  Implementation of the TILDataset class.
@@ -35,8 +35,9 @@
 #include "vrtdataset.h"
 #include "cpl_multiproc.h"
 #include "cplkeywordparser.h"
+#include "gdal_mdreader.h"
 
-CPL_CVSID("$Id: tildataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: tildataset.cpp 29123 2015-05-03 11:05:46Z bishop $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -49,8 +50,7 @@ class CPL_DLL TILDataset : public GDALPamDataset
     VRTDataset *poVRTDS;
     std::vector<GDALDataset *> apoTileDS;
 
-    CPLString                  osRPBFilename;
-    CPLString                  osIMDFilename;
+    char **papszMetadataFiles;
 
   protected:
     virtual int         CloseDependentDatasets();
@@ -84,7 +84,8 @@ class TILRasterBand : public GDALPamRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 };
 
 /************************************************************************/
@@ -121,20 +122,21 @@ CPLErr TILRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GDALRasterIOExtraArg* psExtraArg )
 
 {
     if(GetOverviewCount() > 0)
     {
         return GDALPamRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                  pData, nBufXSize, nBufYSize, eBufType,
-                                 nPixelSpace, nLineSpace );
+                                 nPixelSpace, nLineSpace, psExtraArg );
     }
     else //if not exist TIL overviews, try to use band source overviews
     {
         return poVRTBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                  pData, nBufXSize, nBufYSize, eBufType,
-                                 nPixelSpace, nLineSpace );
+                                 nPixelSpace, nLineSpace, psExtraArg );
     }
 }
 
@@ -152,6 +154,7 @@ TILDataset::TILDataset()
 
 {
     poVRTDS = NULL;
+    papszMetadataFiles = NULL;
 }
 
 /************************************************************************/
@@ -162,6 +165,7 @@ TILDataset::~TILDataset()
 
 {
     CloseDependentDatasets();
+    CSLDestroy(papszMetadataFiles);
 }
 
 /************************************************************************/
@@ -228,16 +232,22 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     
     CPLString osDirname = CPLGetDirname(poOpenInfo->pszFilename);
 
+// get metadata reader
+
+    GDALMDReaderManager mdreadermanager;
+    GDALMDReaderBase* mdreader = mdreadermanager.GetReader(poOpenInfo->pszFilename, 
+                                         poOpenInfo->GetSiblingFiles(), MDR_DG);
+                                              
+    if(NULL == mdreader)    
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Unable to open .TIL dataset due to missing metadata file." );
+        return NULL;
+    }                                     
 /* -------------------------------------------------------------------- */
 /*      Try to find the corresponding .IMD file.                        */
 /* -------------------------------------------------------------------- */
-    char **papszIMD = NULL;
-    CPLString osIMDFilename = 
-        GDALFindAssociatedFile( poOpenInfo->pszFilename, "IMD", 
-                                poOpenInfo->papszSiblingFiles, 0 );
-
-    if( osIMDFilename != "" )
-        papszIMD = GDALLoadIMDFile( osIMDFilename, NULL );
+    char **papszIMD = mdreader->GetMetadataDomain(MD_DOMAIN_IMD);
 
     if( papszIMD == NULL )
     {
@@ -252,7 +262,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "Missing a required field in the .IMD file." );
-        CSLDestroy( papszIMD );
         return NULL;
     }
 
@@ -263,7 +272,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     
     if( fp == NULL )
     {
-        CSLDestroy( papszIMD );
         return NULL;
     }
 
@@ -272,7 +280,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     if( !oParser.Ingest( fp ) )
     {
         VSIFCloseL( fp );
-        CSLDestroy( papszIMD );
         return NULL;
     }
 
@@ -286,15 +293,13 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     TILDataset 	*poDS;
 
     poDS = new TILDataset();
-
-    poDS->osIMDFilename = osIMDFilename; 
-    poDS->SetMetadata( papszIMD, "IMD" );
+    poDS->papszMetadataFiles = mdreader->GetMetadataFiles();
+    mdreader->FillMetadata(&poDS->oMDMD);
     poDS->nRasterXSize = atoi(CSLFetchNameValueDef(papszIMD,"numColumns","0"));
     poDS->nRasterYSize = atoi(CSLFetchNameValueDef(papszIMD,"numRows","0"));
     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
     {
         delete poDS;
-        CSLDestroy( papszIMD );
         return NULL;
     }
 
@@ -309,7 +314,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
         CPLError( CE_Failure, CPLE_AppDefined,
                   "Missing TILE_1.filename in .TIL file." );
         delete poDS;
-        CSLDestroy( papszIMD );
         return NULL;
     }
 
@@ -324,7 +328,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     if( poTemplateDS == NULL || poTemplateDS->GetRasterCount() == 0)
     {
         delete poDS;
-        CSLDestroy( papszIMD );
         if (poTemplateDS != NULL)
             GDALClose( poTemplateDS );
         return NULL;
@@ -390,7 +393,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Missing TILE_%d.filename in .TIL file.", iTile );
             delete poDS;
-            CSLDestroy( papszIMD );
             return NULL;
         }
         
@@ -440,29 +442,6 @@ GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
-/*      Set RPC and IMD metadata.                                       */
-/* -------------------------------------------------------------------- */
-    poDS->osRPBFilename = 
-        GDALFindAssociatedFile( poOpenInfo->pszFilename, "RPB", 
-                                poOpenInfo->papszSiblingFiles, 0 );
-    if( poDS->osRPBFilename != "" )
-    {
-        char **papszRPCMD = GDALLoadRPBFile( poOpenInfo->pszFilename,
-                                             poOpenInfo->papszSiblingFiles );
-        
-        if( papszRPCMD != NULL )
-        {
-            poDS->SetMetadata( papszRPCMD, "RPC" );
-            CSLDestroy( papszRPCMD );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Cleanup                                                         */
-/* -------------------------------------------------------------------- */
-    CSLDestroy( papszIMD );
-
-/* -------------------------------------------------------------------- */
 /*      Initialize any PAM information.                                 */
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
@@ -489,12 +468,14 @@ char **TILDataset::GetFileList()
     for( i = 0; i < apoTileDS.size(); i++ )
         papszFileList = CSLAddString( papszFileList,
                                       apoTileDS[i]->GetDescription() );
-    
-    papszFileList = CSLAddString( papszFileList, osIMDFilename );
-
-
-    if( osRPBFilename != "" )
-        papszFileList = CSLAddString( papszFileList, osRPBFilename );
+                                      
+    if(NULL != papszMetadataFiles)
+    {
+        for( int i = 0; papszMetadataFiles[i] != NULL; i++ )
+        {
+            papszFileList = CSLAddString( papszFileList, papszMetadataFiles[i] );
+        }
+    }
 
     return papszFileList;
 }
@@ -513,6 +494,7 @@ void GDALRegister_TIL()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "TIL" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "EarthWatch .TIL" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/tsx/GNUmakefile b/frmts/tsx/GNUmakefile
index d3e8d06..a53ce4f 100644
--- a/frmts/tsx/GNUmakefile
+++ b/frmts/tsx/GNUmakefile
@@ -1,7 +1,7 @@
 include ../../GDALmake.opt
 
 OBJ	=	tsxdataset.o
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 clean:
diff --git a/frmts/tsx/tsxdataset.cpp b/frmts/tsx/tsxdataset.cpp
index c32ce52..949cf02 100644
--- a/frmts/tsx/tsxdataset.cpp
+++ b/frmts/tsx/tsxdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tsxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: tsxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:     TerraSAR-X XML Product Support
  * Purpose:     Support for TerraSAR-X XML Metadata files
@@ -36,7 +36,7 @@
 
 #define MAX_GCPS 5000    //this should be more than enough ground control points
 
-CPL_CVSID("$Id: tsxdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: tsxdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void GDALRegister_TSX(void);
@@ -199,13 +199,13 @@ CPLErr TSXRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
         return poBand->RasterIO( GF_Read, nBlockXOff * nBlockXSize,
             nBlockYOff * nBlockYSize, nBlockXSize, nRequestYSize,
             pImage, nBlockXSize, nRequestYSize, GDT_CInt16, 1, NULL, 4,
-            nBlockXSize * 4, 0 );
+            nBlockXSize * 4, 0, NULL );
     }
     else { /* Detected Product */
         return poBand->RasterIO( GF_Read, nBlockXOff * nBlockXSize,
             nBlockYOff * nBlockYSize, nBlockXSize, nRequestYSize,
             pImage, nBlockXSize, nRequestYSize, GDT_UInt16, 1, NULL, 2,
-            nBlockXSize * 2, 0 );
+            nBlockXSize * 2, 0, NULL );
     }
 }
 
@@ -256,7 +256,7 @@ TSXDataset::~TSXDataset() {
 
 int TSXDataset::Identify( GDALOpenInfo *poOpenInfo )
 {
-    if (poOpenInfo->fp == NULL || poOpenInfo->nHeaderBytes < 260)
+    if (poOpenInfo->fpL == NULL || poOpenInfo->nHeaderBytes < 260)
     {
         if( poOpenInfo->bIsDirectory )
         {
@@ -312,8 +312,8 @@ bool TSXDataset::getGCPsFromGEOREF_XML(char *pszGeorefFilename)
     if (psSphere!=NULL)
     {
         pszEllipsoidName = CPLGetXMLValue( psSphere, "ellipsoidID", "" );
-        minor_axis = atof(CPLGetXMLValue( psSphere, "semiMinorAxis", "0.0" ));
-        major_axis = atof(CPLGetXMLValue( psSphere, "semiMajorAxis", "0.0" ));
+        minor_axis = CPLAtof(CPLGetXMLValue( psSphere, "semiMinorAxis", "0.0" ));
+        major_axis = CPLAtof(CPLGetXMLValue( psSphere, "semiMajorAxis", "0.0" ));
         //save datum parameters to the spatial reference
         if ( EQUAL(pszEllipsoidName, "") || minor_axis==0.0 || major_axis==0.0 )
         {
@@ -399,16 +399,16 @@ bool TSXDataset::getGCPsFromGEOREF_XML(char *pszGeorefFilename)
          psGCP->pszId = CPLStrdup( szID );
          psGCP->pszInfo = CPLStrdup("");
          psGCP->dfGCPPixel =
-             atof(CPLGetXMLValue(psNode,"col","0"));
+             CPLAtof(CPLGetXMLValue(psNode,"col","0"));
          psGCP->dfGCPLine =
-             atof(CPLGetXMLValue(psNode,"row","0"));
+             CPLAtof(CPLGetXMLValue(psNode,"row","0"));
          psGCP->dfGCPX =
-             atof(CPLGetXMLValue(psNode,"lon",""));
+             CPLAtof(CPLGetXMLValue(psNode,"lon",""));
          psGCP->dfGCPY =
-             atof(CPLGetXMLValue(psNode,"lat",""));
+             CPLAtof(CPLGetXMLValue(psNode,"lat",""));
          //looks like height is in meters - should it be converted so xyz are all on the same scale??
          psGCP->dfGCPZ = 0;
-             //atof(CPLGetXMLValue(psNode,"height",""));
+             //CPLAtof(CPLGetXMLValue(psNode,"height",""));
     }
 
     CPLFree(pszGCPProjection);
@@ -658,7 +658,7 @@ GDALDataset *TSXDataset::Open( GDALOpenInfo *poOpenInfo ) {
         {
             CPLXMLNode *psNode;
             int nGCP = 0;
-            double dfAvgHeight = atof(CPLGetXMLValue(psSceneInfo,
+            double dfAvgHeight = CPLAtof(CPLGetXMLValue(psSceneInfo,
                 "sceneAverageHeight", "0.0"));
 
             //count and allocate gcps - there should be five - 4 corners and a centre
@@ -684,11 +684,11 @@ GDALDataset *TSXDataset::Open( GDALOpenInfo *poOpenInfo ) {
                         !EQUAL(psNode->pszValue, "sceneCornerCoord"))
                         continue;
 
-                    psGCP->dfGCPPixel = atof(CPLGetXMLValue(psNode, "refColumn",
+                    psGCP->dfGCPPixel = CPLAtof(CPLGetXMLValue(psNode, "refColumn",
                         "0.0"));
-                    psGCP->dfGCPLine = atof(CPLGetXMLValue(psNode, "refRow", "0.0"));
-                    psGCP->dfGCPX = atof(CPLGetXMLValue(psNode, "lon", "0.0"));
-                    psGCP->dfGCPY = atof(CPLGetXMLValue(psNode, "lat", "0.0"));
+                    psGCP->dfGCPLine = CPLAtof(CPLGetXMLValue(psNode, "refRow", "0.0"));
+                    psGCP->dfGCPX = CPLAtof(CPLGetXMLValue(psNode, "lon", "0.0"));
+                    psGCP->dfGCPY = CPLAtof(CPLGetXMLValue(psNode, "lat", "0.0"));
                     psGCP->dfGCPZ = dfAvgHeight;
                     psGCP->pszId = CPLStrdup( CPLSPrintf( "%d", nGCP ) );
                     psGCP->pszInfo = CPLStrdup("");
@@ -800,6 +800,7 @@ void GDALRegister_TSX() {
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "TSX" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "TerraSAR-X Product" );
 /*        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_tsx.html" ); */
diff --git a/frmts/usgsdem/GNUmakefile b/frmts/usgsdem/GNUmakefile
index 199fe31..23753bc 100644
--- a/frmts/usgsdem/GNUmakefile
+++ b/frmts/usgsdem/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	usgsdemdataset.o usgsdem_create.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I../../alg $(CPPFLAGS)
+CPPFLAGS	:=	 -I../../alg $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/usgsdem/usgsdem_create.cpp b/frmts/usgsdem/usgsdem_create.cpp
index 202aafa..3f6edae 100644
--- a/frmts/usgsdem/usgsdem_create.cpp
+++ b/frmts/usgsdem/usgsdem_create.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: usgsdem_create.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: usgsdem_create.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  USGS DEM Driver
  * Purpose:  CreateCopy() implementation.
@@ -37,7 +37,7 @@
 #include "gdalwarper.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: usgsdem_create.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: usgsdem_create.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 typedef struct 
 {
@@ -112,7 +112,7 @@ const char *USGSDEMDecToPackedDMS( double dfDec )
     nMinutes = (int) floor( ( dfDec - nDegrees ) * 60.0 );
     dfSeconds = (dfDec - nDegrees) * 3600.0 - nMinutes * 60.0;
 
-    sprintf( szPackBuf, "%4d%2d%7.4f", 
+    CPLsprintf( szPackBuf, "%4d%2d%7.4f", 
              nSign * nDegrees, nMinutes, dfSeconds );
     return szPackBuf;
 }
@@ -185,9 +185,9 @@ static void USGSDEMPrintDouble( char *pszBuffer, double dfValue )
         return;
 
 #if defined(HAVE_SNPRINTF)
-    snprintf( szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue );
+    CPLsnprintf( szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue );
 #else
-    sprintf( szTemp, pszFormat, dfValue );
+    CPLsprintf( szTemp, pszFormat, dfValue );
 #endif
     szTemp[DOUBLE_BUFFER_SIZE - 1] = '\0';
 
@@ -235,9 +235,9 @@ static void USGSDEMPrintSingle( char *pszBuffer, double dfValue )
         return;
 
 #if defined(HAVE_SNPRINTF)
-    snprintf( szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue );
+    CPLsnprintf( szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue );
 #else
-    sprintf( szTemp, pszFormat, dfValue );
+    CPLsprintf( szTemp, pszFormat, dfValue );
 #endif
     szTemp[DOUBLE_BUFFER_SIZE - 1] = '\0';
 
@@ -878,8 +878,8 @@ USGSDEM_LookupNTSByLoc( double dfULLong, double dfULLat,
         if( CSLCount( papszTokens ) != 4 )
             continue;
 
-        if( ABS(dfULLong - atof(papszTokens[2])) < 0.01 
-            && ABS(dfULLat - atof(papszTokens[3])) < 0.01 )
+        if( ABS(dfULLong - CPLAtof(papszTokens[2])) < 0.01 
+            && ABS(dfULLat - CPLAtof(papszTokens[3])) < 0.01 )
         {
             bGotHit = TRUE;
             strncpy( pszTile, papszTokens[0], 7 );
@@ -940,8 +940,8 @@ USGSDEM_LookupNTSByTile( const char *pszTile, char *pszName,
             bGotHit = TRUE;
             if( pszName != NULL )
                 strncpy( pszName, papszTokens[1], 100 );
-            *pdfULLong = atof(papszTokens[2]);
-            *pdfULLat = atof(papszTokens[3]);
+            *pdfULLong = CPLAtof(papszTokens[2]);
+            *pdfULLat = CPLAtof(papszTokens[3]);
         }
 
         CSLDestroy( papszTokens );
@@ -1268,7 +1268,7 @@ static int USGSDEMProductSetup_DEFAULT( USGSDEMWriteInfo *psWInfo )
 /*      made to translate it properly into the USGS nodata value.       */
 /************************************************************************/
 
-static int USGSDEMLoadRaster( USGSDEMWriteInfo *psWInfo,
+static int USGSDEMLoadRaster( CPL_UNUSED USGSDEMWriteInfo *psWInfo,
                               CPL_UNUSED GDALRasterBand *poSrcBand )
 {
     CPLErr eErr;
@@ -1394,9 +1394,12 @@ static int USGSDEMLoadRaster( USGSDEMWriteInfo *psWInfo,
 /************************************************************************/
 
 GDALDataset *
-USGSDEMCreateCopy( const char *pszFilename, GDALDataset *poSrcDS, 
-                   int bStrict, char **papszOptions,
-                   CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void * pProgressData )
+USGSDEMCreateCopy( const char *pszFilename,
+                   GDALDataset *poSrcDS,
+                   int bStrict,
+                   char **papszOptions,
+                   CPL_UNUSED GDALProgressFunc pfnProgress,
+                   CPL_UNUSED void * pProgressData )
 {
     USGSDEMWriteInfo sWInfo;
 
@@ -1466,11 +1469,11 @@ USGSDEMCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
      }
      else 
      {
-         // XXX: We are using atof() here instead of CPLAtof() because
+         // XXX: We are using CPLAtof() here instead of CPLAtof() because
          // zResolution value comes from user's input and supposed to be
-         // written according to user's current locale. atof() honors locale
+         // written according to user's current locale. CPLAtof() honors locale
          // setting, CPLAtof() is not.
-         sWInfo.dfElevStepSize = atof( zResolution );
+         sWInfo.dfElevStepSize = CPLAtof( zResolution );
          if ( sWInfo.dfElevStepSize <= 0 )
          {
              /* don't allow negative values */
@@ -1560,9 +1563,9 @@ USGSDEMCreateCopy( const char *pszFilename, GDALDataset *poSrcDS,
     USGSDEMWriteCleanup( &sWInfo );
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = (GDALPamDataset *) 
+    GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
diff --git a/frmts/usgsdem/usgsdemdataset.cpp b/frmts/usgsdem/usgsdemdataset.cpp
index f4bd939..0da5164 100644
--- a/frmts/usgsdem/usgsdemdataset.cpp
+++ b/frmts/usgsdem/usgsdemdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: usgsdemdataset.cpp 28352 2015-01-23 18:48:38Z rouault $
+ * $Id: usgsdemdataset.cpp 28351 2015-01-23 18:47:42Z rouault $
  *
  * Project:  USGS DEM Driver
  * Purpose:  All reader for USGS DEM Reader
@@ -34,7 +34,7 @@
 #include "gdal_pam.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: usgsdemdataset.cpp 28352 2015-01-23 18:48:38Z rouault $");
+CPL_CVSID("$Id: usgsdemdataset.cpp 28351 2015-01-23 18:47:42Z rouault $");
 
 CPL_C_START
 void	GDALRegister_USGSDEM(void);
@@ -327,7 +327,8 @@ USGSDEMRasterBand::USGSDEMRasterBand( USGSDEMDataset *poDS )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr USGSDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, CPL_UNUSED int nBlockYOff,
+CPLErr USGSDEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                      CPL_UNUSED int nBlockYOff,
                                       void * pImage )
 
 {
@@ -854,6 +855,7 @@ void GDALRegister_USGSDEM()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "USGSDEM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, 
                                    "dem" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
diff --git a/frmts/vrt/GNUmakefile b/frmts/vrt/GNUmakefile
index 327e4f0..95722bf 100644
--- a/frmts/vrt/GNUmakefile
+++ b/frmts/vrt/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	vrtdataset.o vrtrasterband.o vrtdriver.o vrtsources.o \
 		vrtfilters.o vrtsourcedrasterband.o vrtrawrasterband.o \
 		vrtwarped.o vrtderivedrasterband.o
 
-CPPFLAGS	:=	-I../raw $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../raw  $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/vrt/vrt_tutorial.dox b/frmts/vrt/vrt_tutorial.dox
index 20060fc..7b9bf7e 100644
--- a/frmts/vrt/vrt_tutorial.dox
+++ b/frmts/vrt/vrt_tutorial.dox
@@ -1,5 +1,5 @@
 #ifndef DOXYGEN_SKIP
-/* $Id: vrt_tutorial.dox 27700 2014-09-20 13:42:12Z goatbar $ */
+/* $Id: vrt_tutorial.dox 28951 2015-04-18 23:25:15Z rouault $ */
 #endif /* DOXYGEN_SKIP */
 
 /*!
@@ -46,6 +46,9 @@ for developers.<p>
 
 \section gdal_vrttut_format .vrt Format
 
+A <a href="http://svn.osgeo.org/gdal/trunk/gdal/data/gdalvrt.xsd">XML schema of the GDAL VRT format</a>
+is available.<p>
+
 Virtual files stored on disk are kept in an XML format with the following
 elements.<p>
 
@@ -97,8 +100,10 @@ georeferenced coordinates in the same format as the SRS element.<P>
 
 <li> <b>Metadata</b>: This element contains a list of metadata name/value 
 pairs associated with the VRTDataset as a whole, or a VRTRasterBand.   It has
-<MDI> (metadata item) subelements which have a "key" attribute and the value
-as the data of the element.  
+<MDI> (metadata item) subelements which have a "key" attribute and the value
+as the data of the element. The Metadata element can be repeated multiple times,
+in which case it must be accompanied with a "domain" attribute to indicate the
+name of the metadata domain.
 
 \code
   <Metadata>
@@ -279,13 +284,48 @@ a mask band. For example mask,1 means the the mask band of the first band of the
       <DstRect xOff="0" yOff="0" xSize="512" ySize="512"/>
     </SimpleSource>
 \endcode
+
+Starting with GDAL 2.0, a OpenOptions subelement can be added to specify
+the open options to apply when opening the source dataset. It has <OOI> (open option item)
+subelements which have a "key" attribute and the value as the data of the element.
+
+\code
+    <SimpleSource>
+      <SourceFilename relativeToVRT="1">utm.tif</SourceFilename>
+      <OpenOptions>
+          <OOI key="OVERVIEW_LEVEL">0</OOI>
+      </OpenOptions>
+      <SourceBand>1</SourceBand>
+      <SourceProperties RasterXSize="256" RasterYSize="256" DataType="Byte" BlockXSize="128" BlockYSize="128"/>
+      <SrcRect xOff="0" yOff="0" xSize="256" ySize="256"/>
+      <DstRect xOff="0" yOff="0" xSize="256" ySize="256"/>
+    </SimpleSource>
+\endcode
+
+Starting with GDAL 2.0, a resampling attribute can be specified on a SimpleSource
+or ComplexSource element to specified the resampling algorithm used when the
+size of the destination rectangle is not the same as the size of the source
+rectangle. The values allowed for that attribute are : nearest,bilinear,cubic,
+cubicspline,lanczos,average,mode.
+
+\code
+    <SimpleSource resampling="cubic">
+      <SourceFilename relativeToVRT="1">utm.tif</SourceFilename>
+      <SourceBand>1</SourceBand>
+      <SourceProperties RasterXSize="256" RasterYSize="256" DataType="Byte" BlockXSize="128" BlockYSize="128"/>
+      <SrcRect xOff="0" yOff="0" xSize="256" ySize="256"/>
+      <DstRect xOff="0" yOff="0" xSize="128" ySize="128"/>
+    </SimpleSource>
+\endcode
+
 </li>
 
 <li> <b>AveragedSource</b>: The AveragedSource is derived from the
 SimpleSource and shares the same properties except that it uses an averaging
 resampling instead of a nearest neighbour algorithm as in SimpleSource, when
 the size of the destination rectangle is not the same as the size of the source
-rectangle
+rectangle. Note: starting with GDAL 2.0, a more general mechanism to specify
+resampling algorithms can be used. See above paragraph about the 'resampling' attribute.
 
 <li> <b>ComplexSource</b>: The ComplexSource is derived from the
 SimpleSource (so it shares the SourceFilename, SourceBand, SrcRect and 
@@ -831,4 +871,20 @@ underlying datasets. So, if you open twice the same VRT dataset by the same
 thread, both VRT datasets will share the same handles to the underlying
 datasets.
 
+\section gdal_vrttut_perf Performance considerations
+
+A VRT can reference many (hundreds, thousands, or more) datasets. Due to
+operating system limitations, and for performance at opening time, it is
+not reasonable/possible to open them all at the same time. GDAL has a "pool"
+of datasets opened by VRT files whose maximum limit is 100 by default. When it
+needs to access a dataset referenced by a VRT, it checks if it is already in
+the pool of open datasets. If not, when the pool has reached its limit, it closes
+the least recently used dataset to be able to open the new one. This maximum
+limit of the pool can be increased by setting the GDAL_MAX_DATASET_POOL_SIZE
+ configuration option to a bigger value. Note that a typical user process on
+Linux is limited to 1024 simultaneously opened files, and you should let some
+margin for shared libraries, etc...
+As of GDAL 2.0, gdal_translate and gdalwarp, by default, increase the pool size
+to 450.
+
 */
diff --git a/frmts/vrt/vrtdataset.cpp b/frmts/vrt/vrtdataset.cpp
index eeb9c18..338bc94 100644
--- a/frmts/vrt/vrtdataset.cpp
+++ b/frmts/vrt/vrtdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: vrtdataset.cpp 29038 2015-04-28 09:03:36Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTDataset
@@ -33,7 +33,7 @@
 #include "cpl_minixml.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: vrtdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: vrtdataset.cpp 29038 2015-04-28 09:03:36Z rouault $");
 
 /************************************************************************/
 /*                            VRTDataset()                             */
@@ -224,7 +224,9 @@ CPLXMLNode *VRTDataset::SerializeToXML( const char *pszVRTPath )
 /* -------------------------------------------------------------------- */
     psMD = oMDMD.Serialize();
     if( psMD != NULL )
+    {
         CPLAddXMLChild( psDSTree, psMD );
+    }
 
  /* -------------------------------------------------------------------- */
  /*      GCPs                                                            */
@@ -326,7 +328,7 @@ CPLErr VRTDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
         else
         {
             for( int iTA = 0; iTA < 6; iTA++ )
-                adfGeoTransform[iTA] = atof(papszTokens[iTA]);
+                adfGeoTransform[iTA] = CPLAtof(papszTokens[iTA]);
             bGeoTransformSet = TRUE;
         }
 
@@ -627,17 +629,17 @@ GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     char        *pszXML;
 
-    VSILFILE        *fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
+    VSILFILE        *fp = poOpenInfo->fpL;
     if( fp != NULL )
     {
         unsigned int nLength;
 
+        poOpenInfo->fpL = NULL;
+
         VSIFSeekL( fp, 0, SEEK_END );
         nLength = (int) VSIFTellL( fp );
         VSIFSeekL( fp, 0, SEEK_SET );
 
-        // Unsigned always >= 0.
-        // nLength = MAX(0, nLength);
         pszXML = (char *) VSIMalloc(nLength+1);
 
         if( pszXML == NULL )
@@ -648,7 +650,7 @@ GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
                       nLength );
             return NULL;
         }
-
+        
         if( VSIFReadL( pszXML, 1, nLength, fp ) != nLength )
         {
             VSIFCloseL(fp);
@@ -717,6 +719,12 @@ GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
     {
         pszXML = CPLStrdup( poOpenInfo->pszFilename );
     }
+    
+    if( CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH") != NULL )
+    {
+        CPLFree(pszVRTPath);
+        pszVRTPath = CPLStrdup(CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH"));
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Turn the XML representation into a VRTDataset.                  */
@@ -733,7 +741,8 @@ GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Open overviews.                                                 */
 /* -------------------------------------------------------------------- */
     if( fp != NULL && poDS != NULL )
-        poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
+        poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename,
+                                     poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -965,7 +974,7 @@ CPLErr VRTDataset::AddBand( GDALDataType eType, char **papszOptions )
                 if( CSLCount(papszTokens) > 1 )
                     sscanf( papszTokens[1], "%p", &pCBData );
                 if( CSLCount(papszTokens) > 2 )
-                    dfNoDataValue = atof( papszTokens[2] );
+                    dfNoDataValue = CPLAtof( papszTokens[2] );
 
                 poBand->AddFuncSource( pfnReadFunc, pCBData, dfNoDataValue );
             }
@@ -1165,6 +1174,7 @@ int VRTDataset::CheckCompatibleForDatasetIO()
     int iBand;
     int nSources = 0;
     VRTSource    **papoSources = NULL;
+    CPLString osResampling;
     for(iBand = 0; iBand < nBands; iBand++)
     {
         if (!((VRTRasterBand *) papoBands[iBand])->IsSourcedRasterBand())
@@ -1193,6 +1203,7 @@ int VRTDataset::CheckCompatibleForDatasetIO()
                     return FALSE;
                 if (poSource->GetBand()->GetBand() != iBand + 1)
                     return FALSE;
+                osResampling = poSource->GetResampling();
             }
         }
         else if (nSources != poBand->nSources)
@@ -1213,6 +1224,8 @@ int VRTDataset::CheckCompatibleForDatasetIO()
                     return FALSE;
                 if (poSource->GetBand()->GetBand() != iBand + 1)
                     return FALSE;
+                if (osResampling.compare(poSource->GetResampling()) != 0)
+                    return FALSE;
             }
         }
     }
@@ -1244,11 +1257,13 @@ GDALDataset* VRTDataset::GetSingleSimpleSource()
         return NULL;
 
     /* Check that it uses the full source dataset */
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
     int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
     poSource->GetSrcDstWindow( 0, 0,
                                poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
                                poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
+                               &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                                &nReqXOff, &nReqYOff,
                                &nReqXSize, &nReqYSize,
                                &nOutXOff, &nOutYOff,
@@ -1276,7 +1291,9 @@ CPLErr VRTDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType,
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
 {
     if (bCompatibleForDatasetIO < 0)
     {
@@ -1298,24 +1315,42 @@ CPLErr VRTDataset::IRasterIO( GDALRWFlag eRWFlag,
             poBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
                                 pabyBandData, nBufXSize, nBufYSize,
                                 eBufType,
-                                nPixelSpace, nLineSpace);
+                                nPixelSpace, nLineSpace, psExtraArg);
 
             poBand->nSources = nSavedSources;
         }
 
         CPLErr eErr = CE_None;
+
+        GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+        void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
         /* Use the last band, because when sources reference a GDALProxyDataset, they */
         /* don't necessary instanciate all underlying rasterbands */
         VRTSourcedRasterBand* poBand = (VRTSourcedRasterBand* )papoBands[nBands - 1];
         for(int iSource = 0; eErr == CE_None && iSource < poBand->nSources; iSource++)
         {
+            psExtraArg->pfnProgress = GDALScaledProgress;
+            psExtraArg->pProgressData = 
+                GDALCreateScaledProgress( 1.0 * iSource / poBand->nSources,
+                                        1.0 * (iSource + 1) / poBand->nSources,
+                                        pfnProgressGlobal,
+                                        pProgressDataGlobal );
+
             VRTSimpleSource* poSource = (VRTSimpleSource* )poBand->papoSources[iSource];
             eErr = poSource->DatasetRasterIO( nXOff, nYOff, nXSize, nYSize,
                                               pData, nBufXSize, nBufYSize,
                                               eBufType,
                                               nBandCount, panBandMap,
-                                              nPixelSpace, nLineSpace, nBandSpace);
+                                              nPixelSpace, nLineSpace, nBandSpace,
+                                              psExtraArg);
+
+            GDALDestroyScaledProgress( psExtraArg->pProgressData );
         }
+
+        psExtraArg->pfnProgress = pfnProgressGlobal;
+        psExtraArg->pProgressData = pProgressDataGlobal;
+
         return eErr;
     }
 
@@ -1323,5 +1358,5 @@ CPLErr VRTDataset::IRasterIO( GDALRWFlag eRWFlag,
                                   pData, nBufXSize, nBufYSize,
                                   eBufType,
                                   nBandCount, panBandMap,
-                                  nPixelSpace, nLineSpace, nBandSpace);
+                                  nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
 }
diff --git a/frmts/vrt/vrtdataset.h b/frmts/vrt/vrtdataset.h
index a4e050a..b7a81ea 100644
--- a/frmts/vrt/vrtdataset.h
+++ b/frmts/vrt/vrtdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtdataset.h 27542 2014-07-22 21:25:37Z rouault $
+ * $Id: vrtdataset.h 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Declaration of virtual gdal dataset classes.
@@ -39,11 +39,13 @@
 int VRTApplyMetadata( CPLXMLNode *, GDALMajorObject * );
 CPLXMLNode *VRTSerializeMetadata( GDALMajorObject * );
 
+#if 0
 int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
                                 int nPointCount,
                                 double *padfX, double *padfY, double *padfZ,
                                 int *panSuccess );
 void* VRTDeserializeWarpedOverviewTransformer( CPLXMLNode *psTree );
+#endif
 
 /************************************************************************/
 /*                          VRTOverviewInfo()                           */
@@ -80,7 +82,8 @@ public:
     virtual CPLErr  RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace ) = 0;
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg ) = 0;
 
     virtual double GetMinimum( int nXSize, int nYSize, int *pbSuccess ) = 0;
     virtual double GetMaximum( int nXSize, int nYSize, int *pbSuccess ) = 0;
@@ -92,7 +95,7 @@ public:
                                       GDALProgressFunc pfnProgress, void *pProgressData ) = 0;
     virtual CPLErr  GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData ) = 0;
 
@@ -179,7 +182,9 @@ class CPL_DLL VRTDataset : public GDALDataset
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType,
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace);
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
 
     virtual CPLXMLNode *SerializeToXML( const char *pszVRTPath);
     virtual CPLErr      XMLInit( CPLXMLNode *, const char * );
@@ -209,16 +214,18 @@ class CPL_DLL VRTWarpedDataset : public VRTDataset
     int               nBlockYSize;
     GDALWarpOperation *poWarper;
 
+    int               nOverviewCount;
+    VRTWarpedDataset **papoOverviews;
+    int               nSrcOvrLevel;
+    
+    void              CreateImplicitOverviews();
+
     friend class VRTWarpedRasterBand;
 
   protected:
     virtual int         CloseDependentDatasets();
 
 public:
-    int               nOverviewCount;
-    VRTWarpedDataset  **papoOverviews;
-
-public:
                       VRTWarpedDataset( int nXSize, int nYSize );
                      ~VRTWarpedDataset();
 
@@ -227,6 +234,9 @@ public:
     virtual CPLErr IBuildOverviews( const char *, int, int *,
                                     int, int *, GDALProgressFunc, void * );
     
+    virtual CPLErr SetMetadataItem( const char *pszName, const char *pszValue,
+                                    const char *pszDomain = "" );
+
     virtual CPLXMLNode *SerializeToXML( const char *pszVRTPath );
     virtual CPLErr    XMLInit( CPLXMLNode *, const char * );
 
@@ -310,17 +320,17 @@ class CPL_DLL VRTRasterBand : public GDALRasterBand
     virtual GDALRasterBand *GetOverview(int);
     
     virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                          int nBuckets, int * panHistogram,
+                          int nBuckets, GUIntBig * panHistogram,
                           int bIncludeOutOfRange, int bApproxOK,
                           GDALProgressFunc, void *pProgressData );
 
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                        int *pnBuckets, int ** ppanHistogram,
+                                        int *pnBuckets, GUIntBig ** ppanHistogram,
                                         int bForce,
                                         GDALProgressFunc, void *pProgressData);
 
     virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int *panHistogram );
+                                        int nBuckets, GUIntBig *panHistogram );
 
     CPLErr         CopyCommonInfoFrom( GDALRasterBand * );
     
@@ -377,7 +387,8 @@ class CPL_DLL VRTSourcedRasterBand : public VRTRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     virtual char      **GetMetadataDomainList();
     virtual const char *GetMetadataItem( const char * pszName,
@@ -400,7 +411,7 @@ class CPL_DLL VRTSourcedRasterBand : public VRTRasterBand
                                       double *pdfMean, double *pdfStdDev,
                                       GDALProgressFunc pfnProgress, void *pProgressData );
     virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData );
 
@@ -488,7 +499,8 @@ class CPL_DLL VRTDerivedRasterBand : public VRTSourcedRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     static CPLErr AddPixelFunction
         (const char *pszFuncName, GDALDerivedPixelFunc pfnPixelFunc);
@@ -525,7 +537,8 @@ class CPL_DLL VRTRawRasterBand : public VRTRasterBand
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IWriteBlock( int, int, void * );
@@ -592,6 +605,7 @@ protected:
 
     int                 bNoDataSet;
     double              dfNoDataValue;
+    CPLString           osResampling;
 
 public:
             VRTSimpleSource();
@@ -605,15 +619,20 @@ public:
     void           SetSrcWindow( int, int, int, int );
     void           SetDstWindow( int, int, int, int );
     void           SetNoDataValue( double dfNoDataValue );
+    const CPLString& GetResampling() const { return osResampling; }
+    void           SetResampling( const char* pszResampling );
 
     int            GetSrcDstWindow( int, int, int, int, int, int, 
+                                    double *pdfReqXOff, double *pdfReqYOff,
+                                    double *pdfReqXSize, double *pdfReqYSize,
                                     int *, int *, int *, int *,
                                     int *, int *, int *, int * );
 
     virtual CPLErr  RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual double GetMinimum( int nXSize, int nYSize, int *pbSuccess );
     virtual double GetMaximum( int nXSize, int nYSize, int *pbSuccess );
@@ -625,7 +644,7 @@ public:
                                       GDALProgressFunc pfnProgress, void *pProgressData );
     virtual CPLErr  GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData );
 
@@ -647,7 +666,9 @@ public:
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType,
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace);
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
 };
 
 /************************************************************************/
@@ -661,7 +682,8 @@ public:
     virtual CPLErr  RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual double GetMinimum( int nXSize, int nYSize, int *pbSuccess );
     virtual double GetMaximum( int nXSize, int nYSize, int *pbSuccess );
@@ -673,7 +695,7 @@ public:
                                       GDALProgressFunc pfnProgress, void *pProgressData );
     virtual CPLErr  GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData );
 
@@ -713,7 +735,8 @@ protected:
                                       int nReqXSize, int nReqYSize,
                                       void *pData, int nOutXSize, int nOutYSize,
                                       GDALDataType eBufType,
-                                      int nPixelSpace, int nLineSpace );
+                                      GSpacing nPixelSpace, GSpacing nLineSpace,
+                                      GDALRasterIOExtraArg* psExtraArg );
 
 public:
                    VRTComplexSource();
@@ -722,7 +745,8 @@ public:
     virtual CPLErr RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                              void *pData, int nBufXSize, int nBufYSize, 
                              GDALDataType eBufType, 
-                             int nPixelSpace, int nLineSpace );
+                             GSpacing nPixelSpace, GSpacing nLineSpace,
+                             GDALRasterIOExtraArg* psExtraArg );
 
     virtual double GetMinimum( int nXSize, int nYSize, int *pbSuccess );
     virtual double GetMaximum( int nXSize, int nYSize, int *pbSuccess );
@@ -734,7 +758,7 @@ public:
                                       GDALProgressFunc pfnProgress, void *pProgressData );
     virtual CPLErr  GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData );
 
@@ -786,7 +810,8 @@ public:
     virtual CPLErr  RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 };
 
 /************************************************************************/
@@ -845,7 +870,8 @@ public:
     virtual CPLErr  RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                               void *pData, int nBufXSize, int nBufYSize, 
                               GDALDataType eBufType, 
-                              int nPixelSpace, int nLineSpace );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     virtual double GetMinimum( int nXSize, int nYSize, int *pbSuccess );
     virtual double GetMaximum( int nXSize, int nYSize, int *pbSuccess );
@@ -857,7 +883,7 @@ public:
                                       GDALProgressFunc pfnProgress, void *pProgressData );
     virtual CPLErr  GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData );
 
diff --git a/frmts/vrt/vrtderivedrasterband.cpp b/frmts/vrt/vrtderivedrasterband.cpp
index 3c2e80d..2459b2b 100644
--- a/frmts/vrt/vrtderivedrasterband.cpp
+++ b/frmts/vrt/vrtderivedrasterband.cpp
@@ -261,7 +261,9 @@ CPLErr VRTDerivedRasterBand::IRasterIO(GDALRWFlag eRWFlag,
 				       int nXOff, int nYOff, int nXSize, 
 				       int nYSize, void * pData, int nBufXSize,
 				       int nBufYSize, GDALDataType eBufType,
-				       int nPixelSpace, int nLineSpace )
+				       GSpacing nPixelSpace,
+                       GSpacing nLineSpace,
+                       GDALRasterIOExtraArg* psExtraArg )
 {
     GDALDerivedPixelFunc pfnPixelFunc;
     void **pBuffers;
@@ -317,7 +319,7 @@ CPLErr VRTDerivedRasterBand::IRasterIO(GDALRWFlag eRWFlag,
     {
         if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                               pData, nBufXSize, nBufYSize, 
-                              eBufType, nPixelSpace, nLineSpace ) == CE_None )
+                              eBufType, nPixelSpace, nLineSpace, psExtraArg ) == CE_None )
             return CE_None;
     }
 
@@ -350,8 +352,8 @@ CPLErr VRTDerivedRasterBand::IRasterIO(GDALRWFlag eRWFlag,
             }
             CPLError( CE_Failure, CPLE_OutOfMemory,
                 "VRTDerivedRasterBand::IRasterIO:" \
-                "Out of memory allocating %d bytes.\n",
-                nPixelSpace * nBufXSize * nBufYSize);
+                "Out of memory allocating " CPL_FRMT_GIB " bytes.\n",
+                (GIntBig)nPixelSpace * nBufXSize * nBufYSize);
             return CE_Failure;
         }
 
@@ -373,13 +375,16 @@ CPLErr VRTDerivedRasterBand::IRasterIO(GDALRWFlag eRWFlag,
         }
     }
 
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     /* ---- Load values for sources into packed buffers ---- */
     for(iSource = 0; iSource < nSources; iSource++) {
         eErr = ((VRTSource *)papoSources[iSource])->RasterIO
 	    (nXOff, nYOff, nXSize, nYSize, 
 	     pBuffers[iSource], nBufXSize, nBufYSize, 
 	     eSrcType, GDALGetDataTypeSize( eSrcType ) / 8,
-             (GDALGetDataTypeSize( eSrcType ) / 8) * nBufXSize);
+             (GDALGetDataTypeSize( eSrcType ) / 8) * nBufXSize, &sExtraArg);
     }
 
     /* ---- Apply pixel function ---- */
diff --git a/frmts/vrt/vrtdriver.cpp b/frmts/vrt/vrtdriver.cpp
index 8dabe76..89781ed 100644
--- a/frmts/vrt/vrtdriver.cpp
+++ b/frmts/vrt/vrtdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: vrtdriver.cpp 28979 2015-04-23 10:25:51Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTDriver
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "gdal_alg_priv.h"
 
-CPL_CVSID("$Id: vrtdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: vrtdriver.cpp 28979 2015-04-23 10:25:51Z rouault $");
 
 /************************************************************************/
 /*                             VRTDriver()                              */
@@ -43,9 +43,13 @@ VRTDriver::VRTDriver()
 
 {
     papszSourceParsers = NULL;
+#if 0
     pDeserializerData = GDALRegisterTransformDeserializer("WarpedOverviewTransformer",
                                                           VRTWarpedOverviewTransform,
                                                           VRTDeserializeWarpedOverviewTransformer);
+#else
+    pDeserializerData = NULL;
+#endif
 }
 
 /************************************************************************/
@@ -56,11 +60,12 @@ VRTDriver::~VRTDriver()
 
 {
     CSLDestroy( papszSourceParsers );
-
+#if 0
     if ( pDeserializerData )
     {
         GDALUnregisterTransformDeserializer( pDeserializerData );
     }
+#endif
 }
 
 /************************************************************************/
@@ -154,9 +159,12 @@ VRTSource *VRTDriver::ParseSource( CPLXMLNode *psSrc, const char *pszVRTPath )
 /************************************************************************/
 
 static GDALDataset *
-VRTCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-               int bStrict, char ** papszOptions, 
-               CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void * pProgressData )
+VRTCreateCopy( const char * pszFilename,
+               GDALDataset *poSrcDS,
+               int bStrict,
+               char ** papszOptions,
+               CPL_UNUSED GDALProgressFunc pfnProgress,
+               CPL_UNUSED void * pProgressData )
 {
     VRTDataset *poVRTDS = NULL;
 
@@ -351,6 +359,7 @@ void GDALRegister_VRT()
         poDriver = new VRTDriver();
         
         poDriver->SetDescription( "VRT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Virtual Raster" );
         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vrt" );
@@ -364,6 +373,11 @@ void GDALRegister_VRT()
         poDriver->pfnIdentify = VRTDataset::Identify;
         poDriver->pfnDelete = VRTDataset::Delete;
 
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='ROOT_PATH' type='string' description='Root path to evaluate relative paths inside the VRT. Mainly useful for inlined VRT, or in-memory VRT, where their own directory does not make sense'/>"
+"</OpenOptionList>" );
+
         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
         poDriver->AddSourceParser( "SimpleSource", 
@@ -379,4 +393,3 @@ void GDALRegister_VRT()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/frmts/vrt/vrtfilters.cpp b/frmts/vrt/vrtfilters.cpp
index dbbb7aa..ad291c9 100644
--- a/frmts/vrt/vrtfilters.cpp
+++ b/frmts/vrt/vrtfilters.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtfilters.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vrtfilters.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of some filter types.
@@ -32,7 +32,7 @@
 #include "cpl_minixml.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: vrtfilters.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: vrtfilters.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -117,7 +117,9 @@ CPLErr
 VRTFilteredSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, 
                              void *pData, int nBufXSize, int nBufYSize, 
                              GDALDataType eBufType, 
-                             int nPixelSpace, int nLineSpace )
+                             GSpacing nPixelSpace,
+                             GSpacing nLineSpace,
+                             GDALRasterIOExtraArg* psExtraArg )
 
 {
 /* -------------------------------------------------------------------- */
@@ -129,16 +131,18 @@ VRTFilteredSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
     {
         return VRTComplexSource::RasterIO( nXOff, nYOff, nXSize, nYSize, 
                                            pData, nBufXSize, nBufYSize, 
-                                           eBufType, nPixelSpace, nLineSpace );
+                                           eBufType, nPixelSpace, nLineSpace, psExtraArg );
     }
 
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
     int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
 
     if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
+                        &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
         return CE_None;
@@ -287,7 +291,7 @@ VRTFilteredSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
                                               + nLineOffset * nTopFill
                                               + nPixelOffset * nLeftFill,
                                             nFileXSize, nFileYSize, eOperDataType,
-                                            nPixelOffset, nLineOffset );
+                                            nPixelOffset, nLineOffset, psExtraArg );
 
     if( eErr != CE_None )
     {
@@ -562,7 +566,7 @@ CPLErr VRTKernelFilteredSource::XMLInit( CPLXMLNode *psTree,
     padfNewCoefs = (double *) CPLMalloc(sizeof(double) * nCoefs);
 
     for( i = 0; i < nCoefs; i++ )
-        padfNewCoefs[i] = atof(papszCoefItems[i]);
+        padfNewCoefs[i] = CPLAtof(papszCoefItems[i]);
 
     eErr = SetKernel( nNewKernelSize, padfNewCoefs );
 
@@ -610,7 +614,7 @@ CPLXMLNode *VRTKernelFilteredSource::SerializeToXML( const char *pszVRTPath )
 
     strcpy( pszKernelCoefs, "" );
     for( iCoef = 0; iCoef < nCoefCount; iCoef++ )
-        sprintf( pszKernelCoefs + strlen(pszKernelCoefs), 
+        CPLsprintf( pszKernelCoefs + strlen(pszKernelCoefs), 
                  "%.8g ", padfKernelCoefs[iCoef] );
     
     CPLSetXMLValue( psKernel, "Size", CPLSPrintf( "%d", nKernelSize ) );
diff --git a/frmts/vrt/vrtrasterband.cpp b/frmts/vrt/vrtrasterband.cpp
index 62c4c65..3936f05 100644
--- a/frmts/vrt/vrtrasterband.cpp
+++ b/frmts/vrt/vrtrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtrasterband.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vrtrasterband.cpp 29038 2015-04-28 09:03:36Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTRasterBand
@@ -32,7 +32,7 @@
 #include "cpl_minixml.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: vrtrasterband.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: vrtrasterband.cpp 29038 2015-04-28 09:03:36Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -332,8 +332,8 @@ CPLErr VRTRasterBand::XMLInit( CPLXMLNode * psTree,
 
     SetUnitType( CPLGetXMLValue( psTree, "UnitType", NULL ) );
 
-    SetOffset( atof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
-    SetScale( atof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
+    SetOffset( CPLAtof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
+    SetScale( CPLAtof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
 
     if( CPLGetXMLValue( psTree, "ColorInterp", NULL ) != NULL )
     {
@@ -539,7 +539,9 @@ CPLXMLNode *VRTRasterBand::SerializeToXML( const char *pszVRTPath )
 
     psMD = oMDMD.Serialize();
     if( psMD != NULL )
+    {
         CPLAddXMLChild( psTree, psMD );
+    }
 
     if( strlen(GetDescription()) > 0 )
         CPLSetXMLValue( psTree, "Description", GetDescription() );
@@ -790,7 +792,7 @@ GDALColorInterp VRTRasterBand::GetColorInterpretation()
 /************************************************************************/
 
 CPLErr VRTRasterBand::GetHistogram( double dfMin, double dfMax,
-                                    int nBuckets, int * panHistogram,
+                                    int nBuckets, GUIntBig * panHistogram,
                                     int bIncludeOutOfRange, int bApproxOK,
                                     GDALProgressFunc pfnProgress, 
                                     void *pProgressData )
@@ -806,13 +808,13 @@ CPLErr VRTRasterBand::GetHistogram( double dfMin, double dfMax,
                                            bIncludeOutOfRange, bApproxOK );
     if( psHistItem != NULL )
     {
-        int *panTempHist = NULL;
+        GUIntBig *panTempHist = NULL;
 
         if( PamParseHistogram( psHistItem, &dfMin, &dfMax, &nBuckets, 
                                &panTempHist,
                                &bIncludeOutOfRange, &bApproxOK ) )
         {
-            memcpy( panHistogram, panTempHist, sizeof(int) * nBuckets );
+            memcpy( panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets );
             CPLFree( panTempHist );
             return CE_None;
         }
@@ -859,7 +861,7 @@ CPLErr VRTRasterBand::GetHistogram( double dfMin, double dfMax,
 /************************************************************************/
 
 CPLErr VRTRasterBand::SetDefaultHistogram( double dfMin, double dfMax, 
-                                           int nBuckets, int *panHistogram)
+                                           int nBuckets, GUIntBig *panHistogram)
 
 {
     CPLXMLNode *psNode;
@@ -909,7 +911,7 @@ CPLErr VRTRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
 
 CPLErr 
 VRTRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax, 
-                                    int *pnBuckets, int **ppanHistogram, 
+                                    int *pnBuckets, GUIntBig **ppanHistogram, 
                                     int bForce,
                                     GDALProgressFunc pfnProgress, 
                                     void *pProgressData )
diff --git a/frmts/vrt/vrtrawrasterband.cpp b/frmts/vrt/vrtrawrasterband.cpp
index 6d9af68..7b69da7 100644
--- a/frmts/vrt/vrtrawrasterband.cpp
+++ b/frmts/vrt/vrtrawrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtrawrasterband.cpp 27502 2014-07-06 15:18:51Z rouault $
+ * $Id: vrtrawrasterband.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTRawRasterBand
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "rawdataset.h"
 
-CPL_CVSID("$Id: vrtrawrasterband.cpp 27502 2014-07-06 15:18:51Z rouault $");
+CPL_CVSID("$Id: vrtrawrasterband.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -80,8 +80,9 @@ CPLErr VRTRawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
-
+                                 GSpacing nPixelSpace,
+                                 GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg)
 {
     if( poRawRaster == NULL )
     {
@@ -108,7 +109,7 @@ CPLErr VRTRawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     {
         if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                               pData, nBufXSize, nBufYSize, 
-                              eBufType, nPixelSpace, nLineSpace ) == CE_None )
+                              eBufType, nPixelSpace, nLineSpace, psExtraArg ) == CE_None )
             return CE_None;
     }
     
@@ -116,7 +117,7 @@ CPLErr VRTRawRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
     return poRawRaster->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                   pData, nBufXSize, nBufYSize, 
-                                  eBufType, nPixelSpace, nLineSpace );
+                                  eBufType, nPixelSpace, nLineSpace, psExtraArg );
 }
 
 /************************************************************************/
diff --git a/frmts/vrt/vrtsourcedrasterband.cpp b/frmts/vrt/vrtsourcedrasterband.cpp
index 529aab2..aadf366 100644
--- a/frmts/vrt/vrtsourcedrasterband.cpp
+++ b/frmts/vrt/vrtsourcedrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtsourcedrasterband.cpp 27542 2014-07-22 21:25:37Z rouault $
+ * $Id: vrtsourcedrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTSourcedRasterBand
@@ -32,7 +32,7 @@
 #include "cpl_minixml.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: vrtsourcedrasterband.cpp 27542 2014-07-22 21:25:37Z rouault $");
+CPL_CVSID("$Id: vrtsourcedrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -118,7 +118,9 @@ CPLErr VRTSourcedRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace,
+                                 GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
 
 {
     int         iSource;
@@ -153,7 +155,7 @@ CPLErr VRTSourcedRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     {
         if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                               pData, nBufXSize, nBufYSize, 
-                              eBufType, nPixelSpace, nLineSpace ) == CE_None )
+                              eBufType, nPixelSpace, nLineSpace, psExtraArg ) == CE_None )
             return CE_None;
     }
 
@@ -195,17 +197,33 @@ CPLErr VRTSourcedRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     
     nRecursionCounter ++;
 
+    GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+    void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
 /* -------------------------------------------------------------------- */
 /*      Overlay each source in turn over top this.                      */
 /* -------------------------------------------------------------------- */
     for( iSource = 0; eErr == CE_None && iSource < nSources; iSource++ )
     {
+        psExtraArg->pfnProgress = GDALScaledProgress;
+            psExtraArg->pProgressData = 
+                GDALCreateScaledProgress( 1.0 * iSource / nSources,
+                                        1.0 * (iSource + 1) / nSources,
+                                        pfnProgressGlobal,
+                                        pProgressDataGlobal );
+
         eErr = 
             papoSources[iSource]->RasterIO( nXOff, nYOff, nXSize, nYSize, 
                                             pData, nBufXSize, nBufYSize, 
-                                            eBufType, nPixelSpace, nLineSpace);
+                                            eBufType, nPixelSpace, nLineSpace,
+                                            psExtraArg);
+
+        GDALDestroyScaledProgress( psExtraArg->pProgressData );
     }
-    
+
+    psExtraArg->pfnProgress = pfnProgressGlobal;
+    psExtraArg->pProgressData = pProgressDataGlobal;
+
     nRecursionCounter --;
     
     return eErr;
@@ -232,11 +250,14 @@ CPLErr VRTSourcedRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     else
         nReadYSize = nBlockYSize;
 
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     return IRasterIO( GF_Read, 
                       nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize, 
                       nReadXSize, nReadYSize, 
                       pImage, nReadXSize, nReadYSize, eDataType, 
-                      nPixelSize, nPixelSize * nBlockXSize );
+                      nPixelSize, nPixelSize * nBlockXSize, &sExtraArg );
 }
 
 
@@ -572,7 +593,7 @@ VRTSourcedRasterBand::ComputeStatistics( int bApproxOK,
 /************************************************************************/
 
 CPLErr VRTSourcedRasterBand::GetHistogram( double dfMin, double dfMax, 
-                                     int nBuckets, int *panHistogram, 
+                                     int nBuckets, GUIntBig *panHistogram, 
                                      int bIncludeOutOfRange, int bApproxOK,
                                      GDALProgressFunc pfnProgress, 
                                      void *pProgressData )
@@ -727,7 +748,7 @@ CPLErr VRTSourcedRasterBand::XMLInit( CPLXMLNode * psTree,
 /* -------------------------------------------------------------------- */
     if( nSources == 0 )
         CPLDebug( "VRT", "No valid sources found for band in VRT file:\n%s",
-                  pszVRTPath );
+                  pszVRTPath ? pszVRTPath : "(null)" );
 
     return CE_None;
 }
@@ -742,6 +763,9 @@ CPLXMLNode *VRTSourcedRasterBand::SerializeToXML( const char *pszVRTPath )
     CPLXMLNode *psTree;
 
     psTree = VRTRasterBand::SerializeToXML( pszVRTPath );
+    CPLXMLNode* psLastChild = psTree->psChild;
+    while( psLastChild != NULL && psLastChild->psNext != NULL )
+        psLastChild = psLastChild->psNext;
 
 /* -------------------------------------------------------------------- */
 /*      Process Sources.                                                */
@@ -753,7 +777,13 @@ CPLXMLNode *VRTSourcedRasterBand::SerializeToXML( const char *pszVRTPath )
         psXMLSrc = papoSources[iSource]->SerializeToXML( pszVRTPath );
         
         if( psXMLSrc != NULL )
-            CPLAddXMLChild( psTree, psXMLSrc );
+        {
+            if( psLastChild == NULL )
+                psTree->psChild = psXMLSrc;
+            else
+                psLastChild->psNext = psXMLSrc;
+            psLastChild = psXMLSrc;
+        }
     }
 
     return psTree;
@@ -1078,8 +1108,11 @@ const char *VRTSourcedRasterBand::GetMetadataItem( const char * pszName,
             double adfInvGeoTransform[6];
             double dfGeoX, dfGeoY;
 
-            if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
+            dfGeoX = CPLAtof(pszName + 9);
+            const char* pszUnderscore = strchr(pszName + 9, '_');
+            if( !pszUnderscore )
                 return NULL;
+            dfGeoY = CPLAtof(pszUnderscore + 1);
 
             if( GetDataset() == NULL )
                 return NULL;
@@ -1118,6 +1151,7 @@ const char *VRTSourcedRasterBand::GetMetadataItem( const char * pszName,
         
         for( int iSource = 0; iSource < nSources; iSource++ )
         {
+            double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
             int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
             int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
 
@@ -1127,6 +1161,7 @@ const char *VRTSourcedRasterBand::GetMetadataItem( const char * pszName,
             VRTSimpleSource *poSrc = (VRTSimpleSource *) papoSources[iSource];
 
             if( !poSrc->GetSrcDstWindow( iPixel, iLine, 1, 1, 1, 1,
+                                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                                          &nReqXOff, &nReqYOff, 
                                          &nReqXSize, &nReqYSize,
                                          &nOutXOff, &nOutYOff, 
diff --git a/frmts/vrt/vrtsources.cpp b/frmts/vrt/vrtsources.cpp
index 1968120..a6980d3 100644
--- a/frmts/vrt/vrtsources.cpp
+++ b/frmts/vrt/vrtsources.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtsources.cpp 27957 2014-11-12 23:09:34Z rouault $
+ * $Id: vrtsources.cpp 28979 2015-04-23 10:25:51Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTSimpleSource, VRTFuncSource and 
@@ -34,9 +34,16 @@
 #include "cpl_minixml.h"
 #include "cpl_string.h"
 
+/* See #5459 */
+#ifdef isnan
+#define HAS_ISNAN_MACRO
+#endif
 #include <algorithm>
+#if defined(HAS_ISNAN_MACRO) && !defined(isnan)
+#define isnan std::isnan
+#endif
 
-CPL_CVSID("$Id: vrtsources.cpp 27957 2014-11-12 23:09:34Z rouault $");
+CPL_CVSID("$Id: vrtsources.cpp 28979 2015-04-23 10:25:51Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -52,8 +59,10 @@ VRTSource::~VRTSource()
 /*                             GetFileList()                            */
 /************************************************************************/
 
-void VRTSource::GetFileList(CPL_UNUSED char*** ppapszFileList, CPL_UNUSED int *pnSize,
-                            CPL_UNUSED int *pnMaxSize, CPL_UNUSED CPLHashSet* hSetFiles)
+void VRTSource::GetFileList(CPL_UNUSED char*** ppapszFileList,
+                            CPL_UNUSED int *pnSize,
+                            CPL_UNUSED int *pnMaxSize,
+                            CPL_UNUSED CPLHashSet* hSetFiles)
 {
 }
 
@@ -212,12 +221,19 @@ CPLXMLNode *VRTSimpleSource::SerializeToXML( const char *pszVRTPath )
 
     psSrc = CPLCreateXMLNode( NULL, CXT_Element, "SimpleSource" );
 
+    if( osResampling.size() )
+    {
+        CPLCreateXMLNode( 
+            CPLCreateXMLNode( psSrc, CXT_Attribute, "resampling" ), 
+                CXT_Text, osResampling.c_str() );
+    }
+
     VSIStatBufL sStat;
     CPLString osTmp;
     if ( strstr(poDS->GetDescription(), "/vsicurl/http") != NULL ||
          strstr(poDS->GetDescription(), "/vsicurl/ftp") != NULL )
     {
-        /* Testing the existence of remote ressources can be excruciating */
+        /* Testing the existence of remote resources can be excruciating */
         /* slow, so let's just suppose they exist */
         pszRelativePath = poDS->GetDescription();
         bRelativeToVRT = FALSE;
@@ -292,6 +308,9 @@ CPLXMLNode *VRTSimpleSource::SerializeToXML( const char *pszVRTPath )
                           CXT_Attribute, "relativeToVRT" ), 
         CXT_Text, bRelativeToVRT ? "1" : "0" );
 
+    char** papszOpenOptions = poDS->GetOpenOptions();
+    GDALSerializeOpenOptionsToXML(psSrc, papszOpenOptions);
+
     if (poMaskBandMainBand)
         CPLSetXMLValue( psSrc, "SourceBand",
                         CPLSPrintf("mask,%d",poMaskBandMainBand->GetBand()) );
@@ -350,6 +369,8 @@ CPLXMLNode *VRTSimpleSource::SerializeToXML( const char *pszVRTPath )
 CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
 
 {
+    osResampling = CPLGetXMLValue( psSrc, "resampling", "");
+
 /* -------------------------------------------------------------------- */
 /*      Prepare filename.                                               */
 /* -------------------------------------------------------------------- */
@@ -444,7 +465,7 @@ CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
     /* Newly generated VRT will have RasterXSize, RasterYSize, DataType, */
     /* BlockXSize, BlockYSize tags, so that we don't have actually to */
     /* open the real dataset immediately, but we can use a proxy dataset */
-    /* instead. This is particularly usefull when dealing with huge VRT */
+    /* instead. This is particularly useful when dealing with huge VRT */
     /* For example, a VRT with the world coverage of DTED0 (25594 files) */
     CPLXMLNode* psSrcProperties = CPLGetXMLNode(psSrc,"SourceProperties");
     int nRasterXSize = 0, nRasterYSize =0;
@@ -472,6 +493,10 @@ CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         nBlockYSize = atoi(CPLGetXMLValue(psSrcProperties,"BlockYSize","0"));
     }
 
+    char** papszOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
+    if( strstr(pszSrcDSName,"<VRTDataset") != NULL )
+        papszOpenOptions = CSLSetNameValue(papszOpenOptions, "ROOT_PATH", pszVRTPath);
+
     GDALDataset *poSrcDS;
     if (nRasterXSize == 0 || nRasterYSize == 0 || eDataType == (GDALDataType)-1 ||
         nBlockXSize == 0 || nBlockYSize == 0)
@@ -479,7 +504,9 @@ CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         /* -------------------------------------------------------------------- */
         /*      Open the file (shared).                                         */
         /* -------------------------------------------------------------------- */
-        poSrcDS = (GDALDataset *) GDALOpenShared( pszSrcDSName, GA_ReadOnly );
+        poSrcDS = (GDALDataset *) GDALOpenEx(
+                    pszSrcDSName, GDAL_OF_SHARED | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR, NULL,
+                    (const char* const* )papszOpenOptions, NULL );
     }
     else
     {
@@ -488,6 +515,7 @@ CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         /* -------------------------------------------------------------------- */
         int i;
         GDALProxyPoolDataset* proxyDS = new GDALProxyPoolDataset(pszSrcDSName, nRasterXSize, nRasterYSize, GA_ReadOnly, TRUE);
+        proxyDS->SetOpenOptions(papszOpenOptions);
         poSrcDS = proxyDS;
 
         /* Only the information of rasterBand nSrcBand will be accurate */
@@ -497,6 +525,8 @@ CPLErr VRTSimpleSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         if (bGetMaskBand)
             ((GDALProxyPoolRasterBand*)proxyDS->GetRasterBand(nSrcBand))->AddSrcMaskBandDescription(eDataType, nBlockXSize, nBlockYSize);
     }
+    
+    CSLDestroy(papszOpenOptions);
 
     CPLFree( pszSrcDSName );
     
@@ -571,7 +601,7 @@ void VRTSimpleSource::GetFileList(char*** ppapszFileList, int *pnSize,
         if ( strstr(pszFilename, "/vsicurl/http") != NULL ||
              strstr(pszFilename, "/vsicurl/ftp") != NULL )
         {
-            /* Testing the existence of remote ressources can be excruciating */
+            /* Testing the existence of remote resources can be excruciating */
             /* slow, so let's just suppose they exist */
         }
         else
@@ -675,6 +705,8 @@ void VRTSimpleSource::DstToSrc( double dfX, double dfY,
 int 
 VRTSimpleSource::GetSrcDstWindow( int nXOff, int nYOff, int nXSize, int nYSize,
                                   int nBufXSize, int nBufYSize,
+                                  double *pdfReqXOff, double *pdfReqYOff,
+                                  double *pdfReqXSize, double *pdfReqYSize,
                                   int *pnReqXOff, int *pnReqYOff,
                                   int *pnReqXSize, int *pnReqYSize,
                                   int *pnOutXOff, int *pnOutYOff, 
@@ -762,31 +794,38 @@ VRTSimpleSource::GetSrcDstWindow( int nXOff, int nYOff, int nXSize, int nYSize,
 /* -------------------------------------------------------------------- */
     double      dfScaleX = nSrcXSize / (double) nDstXSize;
     double      dfScaleY = nSrcYSize / (double) nDstYSize;
-
-    *pnReqXOff = (int) floor((nRXOff - nDstXOff) * dfScaleX + nSrcXOff);
-    *pnReqYOff = (int) floor((nRYOff - nDstYOff) * dfScaleY + nSrcYOff);
-
-    *pnReqXSize = (int) floor(nRXSize * dfScaleX + 0.5);
-    *pnReqYSize = (int) floor(nRYSize * dfScaleY + 0.5);
+    
+    *pdfReqXOff = (nRXOff - nDstXOff) * dfScaleX + nSrcXOff;
+    *pdfReqYOff = (nRYOff - nDstYOff) * dfScaleY + nSrcYOff;
+    *pdfReqXSize = nRXSize * dfScaleX;
+    *pdfReqYSize = nRYSize * dfScaleY;
 
 /* -------------------------------------------------------------------- */
 /*      Clamp within the bounds of the available source data.           */
 /* -------------------------------------------------------------------- */
-    if( *pnReqXOff < 0 )
+    if( *pdfReqXOff < 0 )
     {
-        *pnReqXSize += *pnReqXOff;
-        *pnReqXOff = 0;
-
+        *pdfReqXSize += *pdfReqXOff;
+        *pdfReqXOff = 0;
         bModifiedX = TRUE;
     }
-    
-    if( *pnReqYOff < 0 )
+    if( *pdfReqYOff < 0 )
     {
-        *pnReqYSize += *pnReqYOff;
-        *pnReqYOff = 0;
+        *pdfReqYSize += *pdfReqYOff;
+        *pdfReqYOff = 0;
         bModifiedY = TRUE;
     }
 
+    *pnReqXOff = (int) floor(*pdfReqXOff);
+    *pnReqYOff = (int) floor(*pdfReqYOff);
+
+    *pnReqXSize = (int) floor(*pdfReqXSize + 0.5);
+    *pnReqYSize = (int) floor(*pdfReqYSize + 0.5);
+
+/* -------------------------------------------------------------------- */
+/*      Clamp within the bounds of the available source data.           */
+/* -------------------------------------------------------------------- */
+
     if( *pnReqXSize == 0 )
         *pnReqXSize = 1;
     if( *pnReqYSize == 0 )
@@ -839,7 +878,7 @@ VRTSimpleSource::GetSrcDstWindow( int nXOff, int nYOff, int nXSize, int nYSize,
         dfScaleWinToBufX = nBufXSize / (double) nXSize;
 
         *pnOutXOff = (int) ((dfDstULX - nXOff) * dfScaleWinToBufX+0.001);
-        *pnOutXSize = (int) ((dfDstLRX - nXOff) * dfScaleWinToBufX+0.001) 
+        *pnOutXSize = (int) ((dfDstLRX - nXOff) * dfScaleWinToBufX+0.5) 
             - *pnOutXOff;
 
         *pnOutXOff = MAX(0,*pnOutXOff);
@@ -852,7 +891,7 @@ VRTSimpleSource::GetSrcDstWindow( int nXOff, int nYOff, int nXSize, int nYSize,
         dfScaleWinToBufY = nBufYSize / (double) nYSize;
 
         *pnOutYOff = (int) ((dfDstULY - nYOff) * dfScaleWinToBufY+0.001);
-        *pnOutYSize = (int) ((dfDstLRY - nYOff) * dfScaleWinToBufY+0.001) 
+        *pnOutYSize = (int) ((dfDstLRY - nYOff) * dfScaleWinToBufY+0.5) 
             - *pnOutYOff;
 
         *pnOutYOff = MAX(0,*pnOutYOff);
@@ -874,10 +913,20 @@ CPLErr
 VRTSimpleSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
                            void *pData, int nBufXSize, int nBufYSize, 
                            GDALDataType eBufType, 
-                           int nPixelSpace, int nLineSpace )
+                           GSpacing nPixelSpace,
+                           GSpacing nLineSpace,
+                           GDALRasterIOExtraArg* psExtraArg )
 
 {
+    GDALRasterIOExtraArg sExtraArg;
+    if( psExtraArg == NULL )
+    {
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+        psExtraArg = &sExtraArg;
+    }
+
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -885,6 +934,7 @@ VRTSimpleSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 
     if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize,
                           nBufXSize, nBufYSize, 
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
     {
@@ -896,14 +946,29 @@ VRTSimpleSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 /* -------------------------------------------------------------------- */
     CPLErr eErr;
 
+    GDALRIOResampleAlg     eResampleAlgBack = psExtraArg->eResampleAlg;
+    if( osResampling.size() )
+    {
+        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(osResampling);
+    }
+    psExtraArg->bFloatingPointWindowValidity = TRUE;
+    psExtraArg->dfXOff = dfReqXOff;
+    psExtraArg->dfYOff = dfReqYOff;
+    psExtraArg->dfXSize = dfReqXSize;
+    psExtraArg->dfYSize = dfReqYSize;
+
     eErr = 
         poRasterBand->RasterIO( GF_Read, 
                                 nReqXOff, nReqYOff, nReqXSize, nReqYSize,
                                 ((unsigned char *) pData) 
                                 + nOutXOff * nPixelSpace
-                                + (size_t)nOutYOff * nLineSpace, 
+                                + (GPtrDiff_t)nOutYOff * nLineSpace, 
                                 nOutXSize, nOutYSize, 
-                                eBufType, nPixelSpace, nLineSpace );
+                                eBufType, nPixelSpace, nLineSpace, psExtraArg );
+
+    if( osResampling.size() )
+        psExtraArg->eResampleAlg = eResampleAlgBack;
+    psExtraArg->bFloatingPointWindowValidity = FALSE;
 
     return eErr;
 }
@@ -915,6 +980,7 @@ VRTSimpleSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 double VRTSimpleSource::GetMinimum( int nXSize, int nYSize, int *pbSuccess )
 {
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -922,6 +988,7 @@ double VRTSimpleSource::GetMinimum( int nXSize, int nYSize, int *pbSuccess )
 
     if( !GetSrcDstWindow( 0, 0, nXSize, nYSize,
                           nXSize, nYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ||
         nReqXOff != 0 || nReqYOff != 0 ||
@@ -942,6 +1009,7 @@ double VRTSimpleSource::GetMinimum( int nXSize, int nYSize, int *pbSuccess )
 double VRTSimpleSource::GetMaximum( int nXSize, int nYSize, int *pbSuccess )
 {
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -949,6 +1017,7 @@ double VRTSimpleSource::GetMaximum( int nXSize, int nYSize, int *pbSuccess )
 
     if( !GetSrcDstWindow( 0, 0, nXSize, nYSize,
                           nXSize, nYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ||
         nReqXOff != 0 || nReqYOff != 0 ||
@@ -969,6 +1038,7 @@ double VRTSimpleSource::GetMaximum( int nXSize, int nYSize, int *pbSuccess )
 CPLErr VRTSimpleSource::ComputeRasterMinMax( int nXSize, int nYSize, int bApproxOK, double* adfMinMax )
 {
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -976,6 +1046,7 @@ CPLErr VRTSimpleSource::ComputeRasterMinMax( int nXSize, int nYSize, int bApprox
 
     if( !GetSrcDstWindow( 0, 0, nXSize, nYSize,
                           nXSize, nYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ||
         nReqXOff != 0 || nReqYOff != 0 ||
@@ -999,6 +1070,7 @@ CPLErr VRTSimpleSource::ComputeStatistics( int nXSize, int nYSize,
                                       GDALProgressFunc pfnProgress, void *pProgressData )
 {
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -1006,6 +1078,7 @@ CPLErr VRTSimpleSource::ComputeStatistics( int nXSize, int nYSize,
 
     if( !GetSrcDstWindow( 0, 0, nXSize, nYSize,
                           nXSize, nYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ||
         nReqXOff != 0 || nReqYOff != 0 ||
@@ -1026,11 +1099,12 @@ CPLErr VRTSimpleSource::ComputeStatistics( int nXSize, int nYSize,
 
 CPLErr VRTSimpleSource::GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData )
 {
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -1038,6 +1112,7 @@ CPLErr VRTSimpleSource::GetHistogram( int nXSize, int nYSize,
 
     if( !GetSrcDstWindow( 0, 0, nXSize, nYSize,
                           nXSize, nYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ||
         nReqXOff != 0 || nReqYOff != 0 ||
@@ -1062,7 +1137,9 @@ CPLErr VRTSimpleSource::DatasetRasterIO(
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType,
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
 {
     if (!EQUAL(GetType(), "SimpleSource"))
     {
@@ -1072,6 +1149,7 @@ CPLErr VRTSimpleSource::DatasetRasterIO(
     }
 
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
@@ -1079,6 +1157,7 @@ CPLErr VRTSimpleSource::DatasetRasterIO(
 
     if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize,
                           nBufXSize, nBufYSize,
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
     {
@@ -1089,14 +1168,39 @@ CPLErr VRTSimpleSource::DatasetRasterIO(
     if (poDS == NULL)
         return CE_Failure;
 
-    return poDS->RasterIO( GF_Read,
+    GDALRIOResampleAlg     eResampleAlgBack = psExtraArg->eResampleAlg;
+    if( osResampling.size() )
+    {
+        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(osResampling);
+    }
+    psExtraArg->bFloatingPointWindowValidity = TRUE;
+    psExtraArg->dfXOff = dfReqXOff;
+    psExtraArg->dfYOff = dfReqYOff;
+    psExtraArg->dfXSize = dfReqXSize;
+    psExtraArg->dfYSize = dfReqYSize;
+
+    CPLErr eErr = poDS->RasterIO( GF_Read,
                            nReqXOff, nReqYOff, nReqXSize, nReqYSize,
                            ((unsigned char *) pData)
                            + nOutXOff * nPixelSpace
-                           + (size_t)nOutYOff * nLineSpace,
+                           + (GPtrDiff_t)nOutYOff * nLineSpace,
                            nOutXSize, nOutYSize,
                            eBufType, nBandCount, panBandMap,
-                           nPixelSpace, nLineSpace, nBandSpace );
+                           nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
+    if( osResampling.size() )
+        psExtraArg->eResampleAlg = eResampleAlgBack;
+    psExtraArg->bFloatingPointWindowValidity = FALSE;
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                          SetResampling()                             */
+/************************************************************************/
+
+void VRTSimpleSource::SetResampling( const char* pszResampling )
+{
+    osResampling = (pszResampling) ? pszResampling : "";
 }
 
 /************************************************************************/
@@ -1139,16 +1243,27 @@ CPLErr
 VRTAveragedSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
                            void *pData, int nBufXSize, int nBufYSize, 
                            GDALDataType eBufType, 
-                           int nPixelSpace, int nLineSpace )
+                           GSpacing nPixelSpace,
+                           GSpacing nLineSpace,
+                           GDALRasterIOExtraArg* psExtraArg )
 
 {
+    GDALRasterIOExtraArg sExtraArg;
+    if( psExtraArg == NULL )
+    {
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+        psExtraArg = &sExtraArg;
+    }
+
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
     int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
 
     if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, 
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
         return CE_None;
@@ -1171,11 +1286,26 @@ VRTAveragedSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 /*      Load it.                                                        */
 /* -------------------------------------------------------------------- */
     CPLErr eErr;
-    
+
+    GDALRIOResampleAlg     eResampleAlgBack = psExtraArg->eResampleAlg;
+    if( osResampling.size() )
+    {
+        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(osResampling);
+    }
+    psExtraArg->bFloatingPointWindowValidity = TRUE;
+    psExtraArg->dfXOff = dfReqXOff;
+    psExtraArg->dfYOff = dfReqYOff;
+    psExtraArg->dfXSize = dfReqXSize;
+    psExtraArg->dfYSize = dfReqYSize;
+
     eErr = poRasterBand->RasterIO( GF_Read, 
                                    nReqXOff, nReqYOff, nReqXSize, nReqYSize,
                                    pafSrc, nReqXSize, nReqYSize, GDT_Float32, 
-                                   0, 0 );
+                                   0, 0, psExtraArg );
+
+    if( osResampling.size() )
+        psExtraArg->eResampleAlg = eResampleAlgBack;
+    psExtraArg->bFloatingPointWindowValidity = FALSE;
 
     if( eErr != CE_None )
     {
@@ -1274,7 +1404,7 @@ VRTAveragedSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 
             pDstLocation = ((GByte *)pData) 
                 + nPixelSpace * iBufPixel
-                + (size_t)nLineSpace * iBufLine;
+                + (GPtrDiff_t)nLineSpace * iBufLine;
 
             if( eBufType == GDT_Byte )
                 *pDstLocation = (GByte) MIN(255,MAX(0,dfOutputValue + 0.5));
@@ -1293,7 +1423,9 @@ VRTAveragedSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 /*                             GetMinimum()                             */
 /************************************************************************/
 
-double VRTAveragedSource::GetMinimum( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize, int *pbSuccess )
+double VRTAveragedSource::GetMinimum( CPL_UNUSED int nXSize,
+                                      CPL_UNUSED int nYSize,
+                                      CPL_UNUSED int *pbSuccess )
 {
     *pbSuccess = FALSE;
     return 0;
@@ -1305,7 +1437,7 @@ double VRTAveragedSource::GetMinimum( CPL_UNUSED int nXSize, CPL_UNUSED int nYSi
 
 double VRTAveragedSource::GetMaximum( CPL_UNUSED int nXSize,
                                       CPL_UNUSED int nYSize,
-                                      int *pbSuccess )
+                                      CPL_UNUSED int *pbSuccess )
 {
     *pbSuccess = FALSE;
     return 0;
@@ -1327,11 +1459,15 @@ CPLErr VRTAveragedSource::ComputeRasterMinMax( CPL_UNUSED int nXSize,
 /*                         ComputeStatistics()                          */
 /************************************************************************/
 
-CPLErr VRTAveragedSource::ComputeStatistics( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-                                             CPL_UNUSED int bApproxOK, 
-                                             CPL_UNUSED double *pdfMin, CPL_UNUSED double *pdfMax, 
-                                             CPL_UNUSED double *pdfMean, CPL_UNUSED double *pdfStdDev,
-                                             CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void *pProgressData )
+CPLErr VRTAveragedSource::ComputeStatistics( CPL_UNUSED int nXSize,
+                                             CPL_UNUSED int nYSize,
+                                             CPL_UNUSED int bApproxOK,
+                                             CPL_UNUSED double *pdfMin,
+                                             CPL_UNUSED double *pdfMax,
+                                             CPL_UNUSED double *pdfMean,
+                                             CPL_UNUSED double *pdfStdDev,
+                                             CPL_UNUSED GDALProgressFunc pfnProgress,
+                                             CPL_UNUSED void *pProgressData )
 {
     return CE_Failure;
 }
@@ -1340,11 +1476,16 @@ CPLErr VRTAveragedSource::ComputeStatistics( CPL_UNUSED int nXSize, CPL_UNUSED i
 /*                            GetHistogram()                            */
 /************************************************************************/
 
-CPLErr VRTAveragedSource::GetHistogram( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-                                        CPL_UNUSED double dfMin, CPL_UNUSED double dfMax,
-                                        CPL_UNUSED int nBuckets, CPL_UNUSED int * panHistogram,
-                                        CPL_UNUSED int bIncludeOutOfRange, CPL_UNUSED int bApproxOK,
-                                        CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void *pProgressData )
+CPLErr VRTAveragedSource::GetHistogram( CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED double dfMin,
+                                        CPL_UNUSED double dfMax,
+                                        CPL_UNUSED int nBuckets,
+                                        CPL_UNUSED GUIntBig * panHistogram,
+                                        CPL_UNUSED int bIncludeOutOfRange,
+                                        CPL_UNUSED int bApproxOK,
+                                        CPL_UNUSED GDALProgressFunc pfnProgress,
+                                        CPL_UNUSED void *pProgressData )
 {
     return CE_Failure;
 }
@@ -1485,26 +1626,26 @@ CPLErr VRTComplexSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         || CPLGetXMLValue(psSrc, "ScaleRatio", NULL) != NULL )
     {
         eScalingType = VRT_SCALING_LINEAR;
-        dfScaleOff = atof(CPLGetXMLValue(psSrc, "ScaleOffset", "0") );
-        dfScaleRatio = atof(CPLGetXMLValue(psSrc, "ScaleRatio", "1") );
+        dfScaleOff = CPLAtof(CPLGetXMLValue(psSrc, "ScaleOffset", "0") );
+        dfScaleRatio = CPLAtof(CPLGetXMLValue(psSrc, "ScaleRatio", "1") );
     }
     else if( CPLGetXMLValue(psSrc, "Exponent", NULL) != NULL &&
              CPLGetXMLValue(psSrc, "DstMin", NULL) != NULL && 
              CPLGetXMLValue(psSrc, "DstMax", NULL) != NULL )
     {
         eScalingType = VRT_SCALING_EXPONENTIAL;
-        dfExponent = atof(CPLGetXMLValue(psSrc, "Exponent", "1.0") );
+        dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0") );
 
         if( CPLGetXMLValue(psSrc, "SrcMin", NULL) != NULL 
          && CPLGetXMLValue(psSrc, "SrcMax", NULL) != NULL )
         {
-            dfSrcMin = atof(CPLGetXMLValue(psSrc, "SrcMin", "0.0") );
-            dfSrcMax = atof(CPLGetXMLValue(psSrc, "SrcMax", "0.0") );
+            dfSrcMin = CPLAtof(CPLGetXMLValue(psSrc, "SrcMin", "0.0") );
+            dfSrcMax = CPLAtof(CPLGetXMLValue(psSrc, "SrcMax", "0.0") );
             bSrcMinMaxDefined = TRUE;
         }
 
-        dfDstMin = atof(CPLGetXMLValue(psSrc, "DstMin", "0.0") );
-        dfDstMax = atof(CPLGetXMLValue(psSrc, "DstMax", "0.0") );
+        dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0") );
+        dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0") );
     }
 
     if( CPLGetXMLValue(psSrc, "NODATA", NULL) != NULL )
@@ -1555,8 +1696,8 @@ CPLErr VRTComplexSource::XMLInit( CPLXMLNode *psSrc, const char *pszVRTPath )
         
         for ( nIndex = 0; nIndex < nLUTItemCount; nIndex++ )
         {
-            padfLUTInputs[nIndex] = atof( papszValues[nIndex * 2] );
-            padfLUTOutputs[nIndex] = atof( papszValues[nIndex * 2 + 1] );
+            padfLUTInputs[nIndex] = CPLAtof( papszValues[nIndex * 2] );
+            padfLUTOutputs[nIndex] = CPLAtof( papszValues[nIndex * 2 + 1] );
 
 	    // Enforce the requirement that the LUT input array is monotonically non-decreasing.
 	    if ( nIndex > 0 && padfLUTInputs[nIndex] < padfLUTInputs[nIndex - 1] )
@@ -1656,27 +1797,55 @@ CPLErr
 VRTComplexSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
                             void *pData, int nBufXSize, int nBufYSize, 
                             GDALDataType eBufType, 
-                            int nPixelSpace, int nLineSpace )
+                            GSpacing nPixelSpace,
+                            GSpacing nLineSpace,
+                            GDALRasterIOExtraArg* psExtraArg)
     
 {
+    GDALRasterIOExtraArg sExtraArg;
+    if( psExtraArg == NULL )
+    {
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+        psExtraArg = &sExtraArg;
+    }
+
     // The window we will actually request from the source raster band.
+    double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
     int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
 
     // The window we will actual set _within_ the pData buffer.
     int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
 
     if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, 
+                          &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
                           &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
                           &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) )
         return CE_None;
 
-    return RasterIOInternal(nReqXOff, nReqYOff, nReqXSize, nReqYSize,
+    GDALRIOResampleAlg     eResampleAlgBack = psExtraArg->eResampleAlg;
+    if( osResampling.size() )
+    {
+        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(osResampling);
+    }
+    psExtraArg->bFloatingPointWindowValidity = TRUE;
+    psExtraArg->dfXOff = dfReqXOff;
+    psExtraArg->dfYOff = dfReqYOff;
+    psExtraArg->dfXSize = dfReqXSize;
+    psExtraArg->dfYSize = dfReqYSize;
+
+    CPLErr eErr = RasterIOInternal(nReqXOff, nReqYOff, nReqXSize, nReqYSize,
                        ((GByte *)pData)
                             + nPixelSpace * nOutXOff
-                            + (size_t)nLineSpace * nOutYOff,
+                            + (GPtrDiff_t)nLineSpace * nOutYOff,
                        nOutXSize, nOutYSize,
                        eBufType,
-                       nPixelSpace, nLineSpace );
+                       nPixelSpace, nLineSpace, psExtraArg );
+
+    if( osResampling.size() )
+        psExtraArg->eResampleAlg = eResampleAlgBack;
+    psExtraArg->bFloatingPointWindowValidity = FALSE;
+
+    return eErr;
 }
 
 /************************************************************************/
@@ -1689,7 +1858,9 @@ CPLErr VRTComplexSource::RasterIOInternal( int nReqXOff, int nReqYOff,
                                       int nReqXSize, int nReqYSize,
                                       void *pData, int nOutXSize, int nOutYSize,
                                       GDALDataType eBufType,
-                                      int nPixelSpace, int nLineSpace )
+                                      GSpacing nPixelSpace,
+                                      GSpacing nLineSpace,
+                                      GDALRasterIOExtraArg* psExtraArg )
 {
 /* -------------------------------------------------------------------- */
 /*      Read into a temporary buffer.                                   */
@@ -1718,10 +1889,20 @@ CPLErr VRTComplexSource::RasterIOInternal( int nReqXOff, int nReqYOff,
             CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
             return CE_Failure;
         }
+
+        GDALRIOResampleAlg     eResampleAlgBack = psExtraArg->eResampleAlg;
+        if( osResampling.size() )
+        {
+            psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(osResampling);
+        }
+
         eErr = poRasterBand->RasterIO( GF_Read, 
                                        nReqXOff, nReqYOff, nReqXSize, nReqYSize,
                                        pafData, nOutXSize, nOutYSize, eWrkDataType,
-                                       nWordSize, nWordSize * nOutXSize );
+                                       nWordSize, nWordSize * (GSpacing)nOutXSize, psExtraArg );
+        if( osResampling.size() )
+            psExtraArg->eResampleAlg = eResampleAlgBack;
+
         if( eErr != CE_None )
         {
             CPLFree( pafData );
@@ -1755,7 +1936,7 @@ CPLErr VRTComplexSource::RasterIOInternal( int nReqXOff, int nReqYOff,
 
             pDstLocation = ((GByte *)pData)
                 + nPixelSpace * iX
-                + (size_t)nLineSpace * iY;
+                + (GPtrDiff_t)nLineSpace * iY;
 
             if (pafData && !bIsComplex)
             {
@@ -1932,7 +2113,7 @@ CPLErr VRTComplexSource::ComputeRasterMinMax( int nXSize, int nYSize, int bAppro
 
 CPLErr VRTComplexSource::GetHistogram( int nXSize, int nYSize,
                                   double dfMin, double dfMax,
-                                  int nBuckets, int * panHistogram,
+                                  int nBuckets, GUIntBig * panHistogram,
                                   int bIncludeOutOfRange, int bApproxOK,
                                   GDALProgressFunc pfnProgress, void *pProgressData )
 {
@@ -2011,31 +2192,32 @@ CPLXMLNode *VRTFuncSource::SerializeToXML( CPL_UNUSED const char * pszVRTPath )
 /*                              RasterIO()                              */
 /************************************************************************/
 
-CPLErr 
+CPLErr
 VRTFuncSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
-                         void *pData, int nBufXSize, int nBufYSize, 
-                         GDALDataType eBufType, 
-                         int nPixelSpace, int nLineSpace )
-
+                         void *pData, int nBufXSize, int nBufYSize,
+                         GDALDataType eBufType,
+                         GSpacing nPixelSpace,
+                         GSpacing nLineSpace,
+                         CPL_UNUSED GDALRasterIOExtraArg* psExtraArg )
 {
     if( nPixelSpace*8 == GDALGetDataTypeSize( eBufType )
-        && nLineSpace == nPixelSpace * nXSize 
-        && nBufXSize == nXSize && nBufYSize == nYSize 
+        && nLineSpace == nPixelSpace * nXSize
+        && nBufXSize == nXSize && nBufYSize == nYSize
         && eBufType == eType )
     {
         return pfnReadFunc( pCBData,
-                            nXOff, nYOff, nXSize, nYSize, 
+                            nXOff, nYOff, nXSize, nYSize,
                             pData );
     }
     else
     {
-        printf( "%d,%d  %d,%d, %d,%d %d,%d %d,%d\n", 
-                nPixelSpace*8, GDALGetDataTypeSize(eBufType),
-                nLineSpace, nPixelSpace * nXSize, 
-                nBufXSize, nXSize, 
-                nBufYSize, nYSize, 
+        printf( "%d,%d  %d,%d, %d,%d %d,%d %d,%d\n",
+                (int)nPixelSpace*8, GDALGetDataTypeSize(eBufType),
+                (int)nLineSpace, (int)nPixelSpace * nXSize,
+                nBufXSize, nXSize,
+                nBufYSize, nYSize,
                 (int) eBufType, (int) eType );
-        CPLError( CE_Failure, CPLE_AppDefined, 
+        CPLError( CE_Failure, CPLE_AppDefined,
                   "VRTFuncSource::RasterIO() - Irregular request." );
         return CE_Failure;
     }
@@ -2045,7 +2227,9 @@ VRTFuncSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize,
 /*                             GetMinimum()                             */
 /************************************************************************/
 
-double VRTFuncSource::GetMinimum( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize, int *pbSuccess )
+double VRTFuncSource::GetMinimum( CPL_UNUSED int nXSize,
+                                  CPL_UNUSED int nYSize,
+                                  CPL_UNUSED CPL_UNUSED int *pbSuccess )
 {
     *pbSuccess = FALSE;
     return 0;
@@ -2055,7 +2239,9 @@ double VRTFuncSource::GetMinimum( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
 /*                             GetMaximum()                             */
 /************************************************************************/
 
-double VRTFuncSource::GetMaximum( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize, int *pbSuccess )
+double VRTFuncSource::GetMaximum( CPL_UNUSED int nXSize,
+                                  CPL_UNUSED int nYSize,
+                                  CPL_UNUSED int *pbSuccess )
 {
     *pbSuccess = FALSE;
     return 0;
@@ -2077,11 +2263,15 @@ CPLErr VRTFuncSource::ComputeRasterMinMax( CPL_UNUSED int nXSize,
 /*                         ComputeStatistics()                          */
 /************************************************************************/
 
-CPLErr VRTFuncSource::ComputeStatistics( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-                                         CPL_UNUSED int bApproxOK, 
-                                         CPL_UNUSED double *pdfMin, CPL_UNUSED double *pdfMax, 
-                                         CPL_UNUSED double *pdfMean, CPL_UNUSED double *pdfStdDev,
-                                         CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void *pProgressData )
+CPLErr VRTFuncSource::ComputeStatistics( CPL_UNUSED int nXSize,
+                                         CPL_UNUSED int nYSize,
+                                         CPL_UNUSED int bApproxOK,
+                                         CPL_UNUSED double *pdfMin,
+                                         CPL_UNUSED double *pdfMax,
+                                         CPL_UNUSED double *pdfMean,
+                                         CPL_UNUSED double *pdfStdDev,
+                                         CPL_UNUSED GDALProgressFunc pfnProgress,
+                                         CPL_UNUSED void *pProgressData )
 {
     return CE_Failure;
 }
@@ -2090,11 +2280,16 @@ CPLErr VRTFuncSource::ComputeStatistics( CPL_UNUSED int nXSize, CPL_UNUSED int n
 /*                            GetHistogram()                            */
 /************************************************************************/
 
-CPLErr VRTFuncSource::GetHistogram( CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-                                    CPL_UNUSED double dfMin, CPL_UNUSED double dfMax,
-                                    CPL_UNUSED int nBuckets, CPL_UNUSED int * panHistogram,
-                                    CPL_UNUSED int bIncludeOutOfRange, CPL_UNUSED int bApproxOK,
-                                    CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void *pProgressData )
+CPLErr VRTFuncSource::GetHistogram( CPL_UNUSED int nXSize,
+                                    CPL_UNUSED int nYSize,
+                                    CPL_UNUSED double dfMin,
+                                    CPL_UNUSED double dfMax,
+                                    CPL_UNUSED int nBuckets,
+                                    CPL_UNUSED GUIntBig * panHistogram,
+                                    CPL_UNUSED int bIncludeOutOfRange,
+                                    CPL_UNUSED int bApproxOK,
+                                    CPL_UNUSED GDALProgressFunc pfnProgress,
+                                    CPL_UNUSED void *pProgressData )
 {
     return CE_Failure;
 }
@@ -2136,4 +2331,3 @@ VRTSource *VRTParseCoreSources( CPLXMLNode *psChild, const char *pszVRTPath )
     delete poSource;
     return NULL;
 }
-
diff --git a/frmts/vrt/vrtwarped.cpp b/frmts/vrt/vrtwarped.cpp
index 6b3c5b0..93cf472 100644
--- a/frmts/vrt/vrtwarped.cpp
+++ b/frmts/vrt/vrtwarped.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vrtwarped.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: vrtwarped.cpp 28292 2015-01-05 19:35:55Z rouault $
  *
  * Project:  Virtual GDAL Datasets
  * Purpose:  Implementation of VRTWarpedRasterBand *and VRTWarpedDataset.
@@ -35,7 +35,7 @@
 #include "gdal_alg_priv.h"
 #include <cassert>
 
-CPL_CVSID("$Id: vrtwarped.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: vrtwarped.cpp 28292 2015-01-05 19:35:55Z rouault $");
 
 /************************************************************************/
 /*                      GDALAutoCreateWarpedVRT()                       */
@@ -188,12 +188,12 @@ GDALAutoCreateWarpedVRT( GDALDatasetH hSrcDS,
     if( pszDstWKT != NULL )
         GDALSetProjection( hDstDS, pszDstWKT );
     else if( pszSrcWKT != NULL )
-        GDALSetProjection( hDstDS, pszDstWKT );
+        GDALSetProjection( hDstDS, pszSrcWKT );
     else if( GDALGetGCPCount( hSrcDS ) > 0 )
         GDALSetProjection( hDstDS, GDALGetGCPProjection( hSrcDS ) );
     else 
         GDALSetProjection( hDstDS, GDALGetProjectionRef( hSrcDS ) );
-
+    
     return hDstDS;
 }
 
@@ -285,6 +285,7 @@ VRTWarpedDataset::VRTWarpedDataset( int nXSize, int nYSize )
 
     nOverviewCount = 0;
     papoOverviews = NULL;
+    nSrcOvrLevel = -2;
 }
 
 /************************************************************************/
@@ -376,6 +377,33 @@ int VRTWarpedDataset::CloseDependentDatasets()
 }
 
 /************************************************************************/
+/*                         SetSrcOverviewLevel()                        */
+/************************************************************************/
+
+CPLErr VRTWarpedDataset::SetMetadataItem( const char *pszName, const char *pszValue,
+                                          const char *pszDomain )
+
+{
+
+    if( (pszDomain == NULL || EQUAL(pszDomain, "")) && EQUAL(pszName, "SrcOvrLevel") )
+    {
+        int nOldValue = nSrcOvrLevel;
+        if( EQUAL(pszValue, "AUTO") )
+            nSrcOvrLevel = -2;
+        else if( EQUALN(pszValue,"AUTO-",5) )
+            nSrcOvrLevel = -2-atoi(pszValue + 5);
+        else if( EQUAL(pszValue, "NONE") )
+            nSrcOvrLevel = -1;
+        else if( CPLGetValueType(pszValue) == CPL_VALUE_INTEGER )
+            nSrcOvrLevel = atoi(pszValue); 
+        if( nSrcOvrLevel != nOldValue )
+            SetNeedsFlush();
+        return CE_None;
+    }
+    return VRTDataset::SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+/************************************************************************/
 /*                             Initialize()                             */
 /*                                                                      */
 /*      Initialize a dataset from passed in warp options.               */
@@ -411,6 +439,139 @@ CPLErr VRTWarpedDataset::Initialize( void *psWO )
 }
 
 /************************************************************************/
+/*                        CreateImplicitOverviews()                     */
+/*                                                                      */
+/*      For each overview of the source dataset, create an overview     */
+/*      in the warped VRT dataset.                                      */
+/************************************************************************/
+
+void VRTWarpedDataset::CreateImplicitOverviews()
+{
+    if( poWarper == NULL || nOverviewCount != 0 )
+        return;
+
+    const GDALWarpOptions *psWO = poWarper->GetOptions();
+
+    if( psWO->hSrcDS == NULL || GDALGetRasterCount(psWO->hSrcDS) == 0 )
+        return;
+
+    GDALDataset* poSrcDS = (GDALDataset*)psWO->hSrcDS;
+    int nOvrCount = poSrcDS->GetRasterBand(1)->GetOverviewCount();
+    for(int iOvr = 0; iOvr < nOvrCount; iOvr++)
+    {
+        int bDeleteSrcOvrDataset = FALSE;
+        GDALDataset* poSrcOvrDS = poSrcDS;
+        if( nSrcOvrLevel < -2 )
+        {
+            if( iOvr + nSrcOvrLevel + 2 >= 0 )
+            {
+                bDeleteSrcOvrDataset = TRUE;
+                poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS,
+                                               iOvr + nSrcOvrLevel + 2, FALSE, FALSE);
+            }
+        }
+        else if( nSrcOvrLevel == -2 )
+        {
+            bDeleteSrcOvrDataset = TRUE;
+            poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS, iOvr, FALSE, FALSE);
+        }
+        else if( nSrcOvrLevel >= 0 )
+        {
+            bDeleteSrcOvrDataset = TRUE;
+            poSrcOvrDS = GDALCreateOverviewDataset(poSrcDS, nSrcOvrLevel, TRUE, FALSE);
+        }
+        if( poSrcOvrDS == NULL )
+            break;
+
+        double dfSrcRatioX = (double)poSrcDS->GetRasterXSize() / poSrcOvrDS->GetRasterXSize();
+        double dfSrcRatioY = (double)poSrcDS->GetRasterYSize() / poSrcOvrDS->GetRasterYSize();
+        double dfTargetRatio = (double)poSrcDS->GetRasterXSize() /
+            poSrcDS->GetRasterBand(1)->GetOverview(iOvr)->GetXSize();
+                
+/* -------------------------------------------------------------------- */
+/*      Figure out the desired output bounds and resolution.            */
+/* -------------------------------------------------------------------- */
+        double adfDstGeoTransform[6];
+        int    nDstPixels, nDstLines;
+        
+        nDstPixels = (int)(nRasterXSize / dfTargetRatio + 0.5);
+        nDstLines = (int)(nRasterYSize / dfTargetRatio + 0.5);
+        GetGeoTransform(adfDstGeoTransform);
+        if( adfDstGeoTransform[2] == 0.0 && adfDstGeoTransform[4] == 0.0 )
+        {
+            adfDstGeoTransform[1] *= (double)nRasterXSize / nDstPixels;
+            adfDstGeoTransform[5] *= (double)nRasterYSize / nDstLines;
+        }
+        else
+        {
+            adfDstGeoTransform[1] *= dfTargetRatio;
+            adfDstGeoTransform[2] *= dfTargetRatio;
+            adfDstGeoTransform[4] *= dfTargetRatio;
+            adfDstGeoTransform[5] *= dfTargetRatio;
+        }
+        
+        if( nDstPixels < 1 || nDstLines < 1 )
+        {
+            if( bDeleteSrcOvrDataset )
+                delete poSrcOvrDS;
+            break;
+        }
+                
+/* -------------------------------------------------------------------- */
+/*      Create transformer and warping options.                         */
+/* -------------------------------------------------------------------- */
+        void *pTransformerArg = GDALCreateSimilarTransformer(psWO->pTransformerArg,
+                                                             dfSrcRatioX,
+                                                             dfSrcRatioY);
+        if( pTransformerArg == NULL )
+        {
+            if( bDeleteSrcOvrDataset )
+                delete poSrcOvrDS;
+            break;
+        }
+
+        GDALWarpOptions* psWOOvr = GDALCloneWarpOptions( psWO );
+        psWOOvr->hSrcDS = (GDALDatasetH)poSrcOvrDS;
+        psWOOvr->pfnTransformer = psWO->pfnTransformer;
+        psWOOvr->pTransformerArg = pTransformerArg;
+
+/* -------------------------------------------------------------------- */
+/*      Update the transformer to include an output geotransform        */
+/*      back to pixel/line coordinates.                                 */
+/*                                                                      */
+/* -------------------------------------------------------------------- */
+        GDALSetTransformerDstGeoTransform( 
+            psWOOvr->pTransformerArg, adfDstGeoTransform );
+
+/* -------------------------------------------------------------------- */
+/*      Create the VRT file.                                            */
+/* -------------------------------------------------------------------- */
+        GDALDatasetH hDstDS;
+
+        hDstDS = GDALCreateWarpedVRT( (GDALDatasetH)poSrcOvrDS,
+                                      nDstPixels, nDstLines, 
+                                      adfDstGeoTransform, psWOOvr );
+        
+        if( bDeleteSrcOvrDataset )
+            GDALDereferenceDataset( (GDALDatasetH)poSrcOvrDS );
+        
+        GDALDestroyWarpOptions(psWOOvr);
+        
+        if( hDstDS == NULL )
+        {
+            GDALDestroyTransformer( pTransformerArg );
+            break;
+        }
+        
+        nOverviewCount++;
+        papoOverviews = (VRTWarpedDataset **)
+            CPLRealloc( papoOverviews, sizeof(void*) * nOverviewCount );
+
+        papoOverviews[nOverviewCount-1] = (VRTWarpedDataset*)hDstDS;
+    }
+}
+
+/************************************************************************/
 /*                            GetFileList()                             */
 /************************************************************************/
 
@@ -466,6 +627,13 @@ void* VRTCreateWarpedOverviewTransformer( GDALTransformerFunc pfnBaseTransformer
 static
 void VRTDestroyWarpedOverviewTransformer(void* pTransformArg);
 
+static
+int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
+                                int nPointCount,
+                                double *padfX, double *padfY, double *padfZ,
+                                int *panSuccess );
+                                
+#if 0
 /************************************************************************/
 /*                VRTSerializeWarpedOverviewTransformer()               */
 /************************************************************************/
@@ -521,8 +689,8 @@ static void VRTWarpedOverviewTransformerOwnsSubtransformer( void *pTransformArg,
 void* VRTDeserializeWarpedOverviewTransformer( CPLXMLNode *psTree )
 
 {
-    double dfXOverviewFactor = atof(CPLGetXMLValue( psTree, "XFactor",  "1" ));
-    double dfYOverviewFactor = atof(CPLGetXMLValue( psTree, "YFactor",  "1" ));
+    double dfXOverviewFactor = CPLAtof(CPLGetXMLValue( psTree, "XFactor",  "1" ));
+    double dfYOverviewFactor = CPLAtof(CPLGetXMLValue( psTree, "YFactor",  "1" ));
     CPLXMLNode *psContainer;
     GDALTransformerFunc pfnBaseTransform = NULL;
     void *pBaseTransformerArg = NULL;
@@ -555,7 +723,7 @@ void* VRTDeserializeWarpedOverviewTransformer( CPLXMLNode *psTree )
         return pApproxCBData;
     }
 }
-
+#endif
 
 /************************************************************************/
 /*                   VRTCreateWarpedOverviewTransformer()               */
@@ -581,12 +749,13 @@ void* VRTCreateWarpedOverviewTransformer( GDALTransformerFunc pfnBaseTransformer
     psSCTInfo->dfYOverviewFactor = dfYOverviewFactor;
     psSCTInfo->bOwnSubtransformer = FALSE;
 
-    strcpy( psSCTInfo->sTI.szSignature, "GTI" );
+    memcpy( psSCTInfo->sTI.abySignature, GDAL_GTI2_SIGNATURE, strlen(GDAL_GTI2_SIGNATURE) );
     psSCTInfo->sTI.pszClassName = "VRTWarpedOverviewTransformer";
     psSCTInfo->sTI.pfnTransform = VRTWarpedOverviewTransform;
     psSCTInfo->sTI.pfnCleanup = VRTDestroyWarpedOverviewTransformer;
+#if 0
     psSCTInfo->sTI.pfnSerialize = VRTSerializeWarpedOverviewTransformer;
-
+#endif
     return psSCTInfo;
 }
 
@@ -609,6 +778,7 @@ void VRTDestroyWarpedOverviewTransformer(void* pTransformArg)
 /*                     VRTWarpedOverviewTransform()                     */
 /************************************************************************/
 
+static
 int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
                                 int nPointCount,
                                 double *padfX, double *padfY, double *padfZ,
@@ -652,14 +822,18 @@ int VRTWarpedOverviewTransform( void *pTransformArg, int bDstToSrc,
 /*      accomplish downsampling by the desired factor.                  */
 /************************************************************************/
 
-CPLErr 
-VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling, 
-                                   int nOverviews, int *panOverviewList, 
-                                   CPL_UNUSED int nListBands, CPL_UNUSED int *panBandList,
-                                   GDALProgressFunc pfnProgress, 
+CPLErr
+VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
+                                   int nOverviews,
+                                   int *panOverviewList,
+                                   CPL_UNUSED int nListBands,
+                                   CPL_UNUSED int *panBandList,
+                                   GDALProgressFunc pfnProgress,
                                    void * pProgressData )
-    
 {
+    if( poWarper == NULL )
+        return CE_Failure;
+
 /* -------------------------------------------------------------------- */
 /*      Initial progress result.                                        */
 /* -------------------------------------------------------------------- */
@@ -684,14 +858,17 @@ VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
         for( j = 0; j < nOverviewCount; j++ )
         {
             int    nOvFactor;
-            VRTWarpedDataset *poOverview = papoOverviews[j];
-            
-            nOvFactor = (int) 
-                (0.5+GetRasterXSize() / (double) poOverview->GetRasterXSize());
+            GDALDataset *poOverview = papoOverviews[j];
+
+            nOvFactor = GDALComputeOvFactor(poOverview->GetRasterXSize(),
+                                            GetRasterXSize(),
+                                            poOverview->GetRasterYSize(),
+                                            GetRasterYSize());
 
             if( nOvFactor == panOverviewList[i] 
-                || nOvFactor == GDALOvLevelAdjust( panOverviewList[i], 
-                                                   GetRasterXSize() ) )
+                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], 
+                                                   GetRasterXSize(), 
+                                                   GetRasterYSize() ) )
                 panOverviewList[i] *= -1;
         }
 
@@ -716,6 +893,25 @@ VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
                                  
         nOYSize = (GetRasterYSize() + panNewOverviewList[i] - 1) 
             / panNewOverviewList[i];
+        
+/* -------------------------------------------------------------------- */
+/*      Find the most appropriate base dataset onto which to build the  */
+/*      new one. The preference will be an overview dataset with a ratio*/
+/*      greater than ours, and which is not using                       */
+/*      VRTWarpedOverviewTransform, since those ones are slow. The other*/
+/*      ones are based on overviews of the source dataset.              */
+/* -------------------------------------------------------------------- */
+        VRTWarpedDataset* poBaseDataset = this;
+        for( int j = 0; j < nOverviewCount; j++ )
+        {
+            if( papoOverviews[j]->GetRasterXSize() > nOXSize &&
+                papoOverviews[j]->poWarper->GetOptions()->pfnTransformer !=
+                                                VRTWarpedOverviewTransform &&
+                papoOverviews[j]->GetRasterXSize() < poBaseDataset->GetRasterXSize() )
+            {
+                poBaseDataset = papoOverviews[j];
+            }
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Create the overview dataset.                                    */
@@ -738,12 +934,12 @@ VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
             CPLRealloc( papoOverviews, sizeof(void*) * nOverviewCount );
 
         papoOverviews[nOverviewCount-1] = poOverviewDS;
-        
+
 /* -------------------------------------------------------------------- */
 /*      Prepare update transformation information that will apply       */
 /*      the overview decimation.                                        */
 /* -------------------------------------------------------------------- */
-        GDALWarpOptions *psWO = (GDALWarpOptions *) poWarper->GetOptions();
+        GDALWarpOptions *psWO = (GDALWarpOptions *) poBaseDataset->poWarper->GetOptions();
 
 /* -------------------------------------------------------------------- */
 /*      Initialize the new dataset with adjusted warp options, and      */
@@ -756,8 +952,8 @@ VRTWarpedDataset::IBuildOverviews( CPL_UNUSED const char *pszResampling,
         psWO->pTransformerArg = VRTCreateWarpedOverviewTransformer(
                                         pfnTransformerBase,
                                         pTransformerBaseArg,
-                                        GetRasterXSize() / (double) nOXSize,
-                                        GetRasterYSize() / (double) nOYSize );
+                                        poBaseDataset->GetRasterXSize() / (double) nOXSize,
+                                        poBaseDataset->GetRasterYSize() / (double) nOYSize );
 
         poOverviewDS->Initialize( psWO );
 
@@ -924,8 +1120,22 @@ CPLErr VRTWarpedDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
     }
 
 /* -------------------------------------------------------------------- */
+/*      Deserialize SrcOvrLevel                                         */
+/* -------------------------------------------------------------------- */
+    const char* pszSrcOvrLevel = CPLGetXMLValue( psTree, "SrcOvrLevel", NULL );
+    if( pszSrcOvrLevel != NULL )
+    {
+        SetMetadataItem("SrcOvrLevel", pszSrcOvrLevel);
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Generate overviews, if appropriate.                             */
 /* -------------------------------------------------------------------- */
+    
+    CreateImplicitOverviews();
+    
+    /* OverviewList is historical, and quite inefficient, since it uses */
+    /* the full resolution source dataset, so only build it afterwards */
     char **papszTokens = CSLTokenizeString( 
         CPLGetXMLValue( psTree, "OverviewList", "" ));
     int iOverview;
@@ -978,30 +1188,55 @@ CPLXMLNode *VRTWarpedDataset::SerializeToXML( const char *pszVRTPath )
                                  CPLSPrintf( "%d", nBlockYSize ) );
 
 /* -------------------------------------------------------------------- */
-/*      Serialize the overview list.                                    */
+/*      Serialize the overview list (only for non implicit overviews)   */
 /* -------------------------------------------------------------------- */
     if( nOverviewCount > 0 )
     {
         char *pszOverviewList;
         int iOverview;
-        
-        pszOverviewList = (char *) CPLMalloc(nOverviewCount*8 + 10);
-        pszOverviewList[0] = '\0';
-        for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
+                    
+        int nSrcDSOvrCount = 0;
+        if( poWarper != NULL  && poWarper->GetOptions() != NULL &&
+            poWarper->GetOptions()->hSrcDS != NULL &&
+            GDALGetRasterCount(poWarper->GetOptions()->hSrcDS) > 0 )
         {
-            int nOvFactor;
+            nSrcDSOvrCount = ((GDALDataset*)poWarper->GetOptions()->hSrcDS)->
+                                        GetRasterBand(1)->GetOverviewCount();
+        }
 
-            nOvFactor = (int) 
-                (0.5+GetRasterXSize() 
-                 / (double) papoOverviews[iOverview]->GetRasterXSize());
+        if( nOverviewCount != nSrcDSOvrCount )
+        {
+            pszOverviewList = (char *) CPLMalloc(nOverviewCount*8 + 10);
+            pszOverviewList[0] = '\0';
+            for( iOverview = 0; iOverview < nOverviewCount; iOverview++ )
+            {
+                int nOvFactor;
 
-            sprintf( pszOverviewList + strlen(pszOverviewList), 
-                     "%d ", nOvFactor );
-        }
+                nOvFactor = (int) 
+                    (0.5+GetRasterXSize() 
+                     / (double) papoOverviews[iOverview]->GetRasterXSize());
+
+                sprintf( pszOverviewList + strlen(pszOverviewList), 
+                         "%d ", nOvFactor );
+            }
 
-        CPLCreateXMLElementAndValue( psTree, "OverviewList", pszOverviewList );
+            CPLCreateXMLElementAndValue( psTree, "OverviewList", pszOverviewList );
 
-        CPLFree( pszOverviewList );
+            CPLFree( pszOverviewList );
+        }
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Serialize source overview level.                                */
+/* -------------------------------------------------------------------- */
+    if( nSrcOvrLevel != -2 )
+    {
+        if( nSrcOvrLevel < -2 )
+            CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", CPLSPrintf("AUTO%d", nSrcOvrLevel+2) );
+        else if( nSrcOvrLevel == -1 )
+            CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", "NONE" );
+        else
+            CPLCreateXMLElementAndValue( psTree, "SrcOvrLevel", CPLSPrintf("%d", nSrcOvrLevel) );
     }
 
 /* ==================================================================== */
@@ -1172,11 +1407,18 @@ CPLErr VRTWarpedDataset::ProcessBlock( int iBlockX, int iBlockY )
 /*      Warp into this buffer.                                          */
 /* -------------------------------------------------------------------- */
     CPLErr eErr;
+    
+    int nReqXSize = nBlockXSize;
+    if( iBlockX * nBlockXSize + nReqXSize > nRasterXSize )
+        nReqXSize = nRasterXSize - iBlockX * nBlockXSize;
+    int nReqYSize = nBlockYSize;
+    if( iBlockY * nBlockYSize + nReqYSize > nRasterYSize )
+        nReqYSize = nRasterYSize - iBlockY * nBlockYSize;
 
     eErr = 
         poWarper->WarpRegionToBuffer( 
             iBlockX * nBlockXSize, iBlockY * nBlockYSize, 
-            nBlockXSize, nBlockYSize,
+            nReqXSize, nReqYSize,
             pabyDstBuffer, psWO->eWorkingDataType );
 
     if( eErr != CE_None )
@@ -1200,12 +1442,29 @@ CPLErr VRTWarpedDataset::ProcessBlock( int iBlockX, int iBlockY )
         {
             if ( poBlock->GetDataRef() != NULL )
             {
-                GDALCopyWords( pabyDstBuffer + iBand*nBlockXSize*nBlockYSize*nWordSize,
-                            psWO->eWorkingDataType, nWordSize, 
-                            poBlock->GetDataRef(), 
-                            poBlock->GetDataType(), 
-                            GDALGetDataTypeSize(poBlock->GetDataType())/8,
-                            nBlockXSize * nBlockYSize );
+                if( nReqXSize == nBlockXSize && nReqYSize == nBlockYSize )
+                {
+                    GDALCopyWords( pabyDstBuffer + iBand*nBlockXSize*nBlockYSize*nWordSize,
+                                psWO->eWorkingDataType, nWordSize, 
+                                poBlock->GetDataRef(), 
+                                poBlock->GetDataType(), 
+                                GDALGetDataTypeSize(poBlock->GetDataType())/8,
+                                nBlockXSize * nBlockYSize );
+                }
+                else
+                {
+                    GByte* pabyBlock = (GByte*) poBlock->GetDataRef();
+                    int nDTSize = GDALGetDataTypeSize(poBlock->GetDataType())/8;
+                    for(int iY=0;iY<nReqYSize;iY++)
+                    {
+                        GDALCopyWords( pabyDstBuffer + iBand*nReqXSize*nReqYSize*nWordSize + iY * nReqXSize*nWordSize,
+                                       psWO->eWorkingDataType, nWordSize, 
+                                       pabyBlock + iY * nBlockXSize * nDTSize, 
+                                       poBlock->GetDataType(), 
+                                       nDTSize,
+                                       nReqXSize );
+                    }
+                }
             }
 
             poBlock->DropLock();
@@ -1367,6 +1626,8 @@ int VRTWarpedRasterBand::GetOverviewCount()
 
 {
     VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
+    
+    poWDS->CreateImplicitOverviews();
 
     return poWDS->nOverviewCount;
 }
@@ -1380,9 +1641,8 @@ GDALRasterBand *VRTWarpedRasterBand::GetOverview( int iOverview )
 {
     VRTWarpedDataset *poWDS = (VRTWarpedDataset *) poDS;
 
-    if( iOverview < 0 || iOverview >= poWDS->nOverviewCount )
+    if( iOverview < 0 || iOverview >= GetOverviewCount() )
         return NULL;
     else
         return poWDS->papoOverviews[iOverview]->GetRasterBand( nBand );
 }
-
diff --git a/frmts/wcs/GNUmakefile b/frmts/wcs/GNUmakefile
index 1db91e3..421e75e 100644
--- a/frmts/wcs/GNUmakefile
+++ b/frmts/wcs/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	wcsdataset.o httpdriver.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) 
+CPPFLAGS	:=	 $(CPPFLAGS) 
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/wcs/httpdriver.cpp b/frmts/wcs/httpdriver.cpp
index 74ee381..640bc66 100644
--- a/frmts/wcs/httpdriver.cpp
+++ b/frmts/wcs/httpdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: httpdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: httpdriver.cpp 29102 2015-05-01 22:26:04Z rouault $
  *
  * Project:  WCS Client Driver
  * Purpose:  Implementation of an HTTP fetching driver.
@@ -33,7 +33,7 @@
 #include "cpl_http.h"
 #include "cpl_atomic_ops.h"
 
-CPL_CVSID("$Id: httpdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: httpdriver.cpp 29102 2015-05-01 22:26:04Z rouault $");
 
 
 /************************************************************************/
@@ -143,7 +143,8 @@ static GDALDataset *HTTPOpen( GDALOpenInfo * poOpenInfo )
     /* suppress errors as not all drivers support /vsimem */
     CPLPushErrorHandler( CPLQuietErrorHandler );
     GDALDataset *poDS = (GDALDataset *) 
-        GDALOpen( osResultFilename, GA_ReadOnly );
+        GDALOpenEx( osResultFilename, poOpenInfo->nOpenFlags, NULL,
+                    poOpenInfo->papszOpenOptions, NULL);
     CPLPopErrorHandler();
 
 /* -------------------------------------------------------------------- */
@@ -153,8 +154,13 @@ static GDALDataset *HTTPOpen( GDALOpenInfo * poOpenInfo )
     if( poDS == NULL )
     {
         CPLString osTempFilename;
-        
-        osTempFilename.Printf( "/tmp/%s", CPLGetFilename(osResultFilename) );
+
+#ifdef WIN32
+        const char* pszPath = CPLGetPath(CPLGenerateTempFilename(NULL));
+#else
+        const char* pszPath = "/tmp";
+#endif
+        osTempFilename = CPLFormFilename(pszPath, CPLGetFilename(osResultFilename), NULL );
         if( CPLCopyFile( osTempFilename, osResultFilename ) != 0 )
         {
             CPLError( CE_Failure, CPLE_OpenFailed, 
@@ -164,10 +170,17 @@ static GDALDataset *HTTPOpen( GDALOpenInfo * poOpenInfo )
         else
         {
             poDS =  (GDALDataset *) 
-                GDALOpen( osTempFilename, GA_ReadOnly );
-            VSIUnlink( osTempFilename ); /* this may not work on windows */
+                GDALOpenEx( osTempFilename, poOpenInfo->nOpenFlags, NULL,
+                            poOpenInfo->papszOpenOptions, NULL );
+            if( VSIUnlink( osTempFilename ) != 0 && poDS != NULL )
+                poDS->MarkSuppressOnClose(); /* VSIUnlink() may not work on windows */
+            if( poDS && strcmp(poDS->GetDescription(), osTempFilename) == 0 )
+                poDS->SetDescription(poOpenInfo->pszFilename);
+
         }
     }
+    else if( strcmp(poDS->GetDescription(), osResultFilename) == 0 )
+        poDS->SetDescription(poOpenInfo->pszFilename);
 
 /* -------------------------------------------------------------------- */
 /*      Release our hold on the vsi memory file, though if it is        */
@@ -193,6 +206,8 @@ void GDALRegister_HTTP()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "HTTP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "HTTP Fetching Wrapper" );
         
diff --git a/frmts/wcs/wcsdataset.cpp b/frmts/wcs/wcsdataset.cpp
index 1e31b4c..0e2d0c9 100644
--- a/frmts/wcs/wcsdataset.cpp
+++ b/frmts/wcs/wcsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: wcsdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: wcsdataset.cpp 28218 2014-12-25 18:09:13Z goatbar $
  *
  * Project:  WCS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WCS.
@@ -34,7 +34,7 @@
 #include "cpl_http.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: wcsdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: wcsdataset.cpp 28218 2014-12-25 18:09:13Z goatbar $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -70,7 +70,10 @@ class CPL_DLL WCSDataset : public GDALPamDataset
     int         TestUseBlockIO( int, int, int, int, int, int );
     CPLErr      DirectRasterIO( GDALRWFlag, int, int, int, int,
                                 void *, int, int, GDALDataType,
-                                int, int *, int, int, int );
+                                int, int *,
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GSpacing nBandSpace,
+                                GDALRasterIOExtraArg* psExtraArg);
     CPLErr      GetCoverage( int nXOff, int nYOff, int nXSize, int nYSize,
                              int nBufXSize, int nBufYSize, 
                              int nBandCount, int *panBandList,
@@ -78,7 +81,10 @@ class CPL_DLL WCSDataset : public GDALPamDataset
 
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *,
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg);
 
     int		DescribeCoverage();
     int         ExtractGridInfo100();
@@ -131,7 +137,8 @@ class WCSRasterBand : public GDALPamRasterBand
     
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GDALRasterIOExtraArg* psExtraArg );
 
   public:
 
@@ -320,7 +327,7 @@ CPLErr WCSRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
             eErr = poTileBand->RasterIO( GF_Read, 
                                          0, 0, nBlockXSize, nBlockYSize, 
                                          pImage, nBlockXSize, nBlockYSize, 
-                                         eDataType, 0, 0 );
+                                         eDataType, 0, 0, NULL );
         }
         else
         {
@@ -338,7 +345,7 @@ CPLErr WCSRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
                                             0, 0, nBlockXSize, nBlockYSize,
                                             poBlock->GetDataRef(),
                                             nBlockXSize, nBlockYSize,
-                                            eDataType, 0, 0 );
+                                            eDataType, 0, 0, NULL );
                 poBlock->DropLock();
             }
             else
@@ -364,7 +371,8 @@ CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace, int nLineSpace )
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg)
     
 {
     if( (poODS->nMaxCols > 0 && poODS->nMaxCols < nBufXSize)
@@ -376,14 +384,14 @@ CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamRasterBand::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nPixelSpace, nLineSpace );
+            nPixelSpace, nLineSpace, psExtraArg );
     else
         return poODS->DirectRasterIO( 
             eRWFlag, 
             nXOff * nResFactor, nYOff * nResFactor, 
             nXSize * nResFactor, nYSize * nResFactor,
             pData, nBufXSize, nBufYSize, eBufType, 
-            1, &nBand, nPixelSpace, nLineSpace, 0 );
+            1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg );
 }
 
 /************************************************************************/
@@ -393,7 +401,6 @@ CPLErr WCSRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 double WCSRasterBand::GetNoDataValue( int *pbSuccess )
 
 {
-    CPLLocaleC  oLocaleEnforcer;
     const char *pszSV = CPLGetXMLValue( poODS->psService, "NoDataValue", NULL);
 
     if( pszSV == NULL )
@@ -402,7 +409,7 @@ double WCSRasterBand::GetNoDataValue( int *pbSuccess )
     {
         if( pbSuccess )
             *pbSuccess = TRUE;
-        return atof(pszSV);
+        return CPLAtof(pszSV);
     }
 }
 
@@ -500,9 +507,12 @@ WCSDataset::~WCSDataset()
 /*      (FALSE) for a given request configuration and environment.      */
 /************************************************************************/
 
-int WCSDataset::TestUseBlockIO( CPL_UNUSED int nXOff, CPL_UNUSED int nYOff, int nXSize, int nYSize,
-                                int nBufXSize, int nBufYSize )
-
+int WCSDataset::TestUseBlockIO( CPL_UNUSED int nXOff,
+                                CPL_UNUSED int nYOff,
+                                int nXSize,
+                                int nYSize,
+                                int nBufXSize,
+                                int nBufYSize )
 {
     int bUseBlockedIO = bForceCachedIO;
 
@@ -528,7 +538,9 @@ CPLErr WCSDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace)
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg)
 
 {
     if( (nMaxCols > 0 && nMaxCols < nBufXSize)
@@ -542,12 +554,12 @@ CPLErr WCSDataset::IRasterIO( GDALRWFlag eRWFlag,
         return GDALPamDataset::IRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
     else
         return DirectRasterIO( 
             eRWFlag, nXOff, nYOff, nXSize, nYSize,
             pData, nBufXSize, nBufYSize, eBufType, 
-            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace );
+            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
 }
 
 /************************************************************************/
@@ -556,25 +568,32 @@ CPLErr WCSDataset::IRasterIO( GDALRWFlag eRWFlag,
 /*      Make exactly one request to the server for this data.           */
 /************************************************************************/
 
-CPLErr 
+CPLErr
 WCSDataset::DirectRasterIO( CPL_UNUSED GDALRWFlag eRWFlag,
-                            int nXOff, int nYOff, int nXSize, int nYSize,
-                            void * pData, int nBufXSize, int nBufYSize,
-                            GDALDataType eBufType, 
-                            int nBandCount, int *panBandMap,
-                            int nPixelSpace, int nLineSpace, int nBandSpace)
-
+                            int nXOff,
+                            int nYOff,
+                            int nXSize,
+                            int nYSize,
+                            void * pData,
+                            int nBufXSize,
+                            int nBufYSize,
+                            GDALDataType eBufType,
+                            int nBandCount,
+                            int *panBandMap,
+                            GSpacing nPixelSpace, GSpacing nLineSpace,
+                            GSpacing nBandSpace,
+                            CPL_UNUSED GDALRasterIOExtraArg* psExtraArg)
 {
-    CPLDebug( "WCS", "DirectRasterIO(%d,%d,%d,%d) -> (%d,%d) (%d bands)\n", 
-              nXOff, nYOff, nXSize, nYSize, 
+    CPLDebug( "WCS", "DirectRasterIO(%d,%d,%d,%d) -> (%d,%d) (%d bands)\n",
+              nXOff, nYOff, nXSize, nYSize,
               nBufXSize, nBufYSize, nBandCount );
 
 /* -------------------------------------------------------------------- */
 /*      Get the coverage.                                               */
 /* -------------------------------------------------------------------- */
     CPLHTTPResult *psResult = NULL;
-    CPLErr eErr = 
-        GetCoverage( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, 
+    CPLErr eErr =
+        GetCoverage( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
                      nBandCount, panBandMap, &psResult );
 
     if( eErr != CE_None )
@@ -639,7 +658,7 @@ WCSDataset::DirectRasterIO( CPL_UNUSED GDALRWFlag eRWFlag,
                                      0, 0, nBufXSize, nBufYSize,
                                      ((GByte *) pData) + 
                                      iBand * nBandSpace, nBufXSize, nBufYSize, 
-                                     eBufType, nPixelSpace, nLineSpace );
+                                     eBufType, nPixelSpace, nLineSpace, NULL );
     }
     
 /* -------------------------------------------------------------------- */
@@ -665,8 +684,6 @@ CPLErr WCSDataset::GetCoverage( int nXOff, int nYOff, int nXSize, int nYSize,
                                 CPLHTTPResult **ppsResult )
 
 {
-    CPLLocaleC oLocaleEnforcer;
-
 /* -------------------------------------------------------------------- */
 /*      Figure out the georeferenced extents.                           */
 /* -------------------------------------------------------------------- */
@@ -948,7 +965,6 @@ int WCSDataset::DescribeCoverage()
 int WCSDataset::ExtractGridInfo100()
 
 {
-    CPLLocaleC  oLocaleEnforcer; 
     CPLXMLNode * psCO = CPLGetXMLNode( psService, "CoverageOffering" );
 
     if( psCO == NULL )
@@ -1174,7 +1190,7 @@ int WCSDataset::ExtractGridInfo100()
     {
         const char *pszSV = CPLGetXMLValue( psCO, "rangeSet.RangeSet.nullValues.singleValue", NULL );
         
-        if( pszSV != NULL && (atof(pszSV) != 0.0 || *pszSV == '0') )
+        if( pszSV != NULL && (CPLAtof(pszSV) != 0.0 || *pszSV == '0') )
         {
             bServiceDirty = TRUE;
             CPLCreateXMLElementAndValue( psService, "NoDataValue", 
@@ -1278,7 +1294,6 @@ static int ParseBoundingBox( CPLXMLNode *psBoundingBox, CPLString &osCRS,
                              double &dfUpperX, double &dfUpperY )
 
 {
-    CPLLocaleC  oLocaleEnforcer; 
     int nRet = TRUE;
 
     osCRS = CPLGetXMLValue( psBoundingBox, "crs", "" );
@@ -1292,10 +1307,10 @@ static int ParseBoundingBox( CPLXMLNode *psBoundingBox, CPLString &osCRS,
 
     if( CSLCount(papszLC) >= 2 && CSLCount(papszUC) >= 2 )
     {
-        dfLowerX = atof(papszLC[0]);
-        dfLowerY = atof(papszLC[1]);
-        dfUpperX = atof(papszUC[0]);
-        dfUpperY = atof(papszUC[1]);
+        dfLowerX = CPLAtof(papszLC[0]);
+        dfLowerY = CPLAtof(papszLC[1]);
+        dfUpperX = CPLAtof(papszUC[0]);
+        dfUpperY = CPLAtof(papszUC[1]);
     }
     else
         nRet = FALSE;
@@ -1316,8 +1331,6 @@ static int ParseBoundingBox( CPLXMLNode *psBoundingBox, CPLString &osCRS,
 int WCSDataset::ExtractGridInfo()
 
 {
-    CPLLocaleC  oLocaleEnforcer; 
-
     if( nVersion == 100 )
         return ExtractGridInfo100();
 
@@ -1367,12 +1380,12 @@ int WCSDataset::ExtractGridInfo()
         if( CSLCount(papszOffsetTokens) == 4
             && CSLCount(papszOriginTokens) == 2 )
         {
-            adfGeoTransform[0] = atof(papszOriginTokens[0]);
-            adfGeoTransform[1] = atof(papszOffsetTokens[0]);
-            adfGeoTransform[2] = atof(papszOffsetTokens[1]);
-            adfGeoTransform[3] = atof(papszOriginTokens[1]);
-            adfGeoTransform[4] = atof(papszOffsetTokens[2]);
-            adfGeoTransform[5] = atof(papszOffsetTokens[3]);
+            adfGeoTransform[0] = CPLAtof(papszOriginTokens[0]);
+            adfGeoTransform[1] = CPLAtof(papszOffsetTokens[0]);
+            adfGeoTransform[2] = CPLAtof(papszOffsetTokens[1]);
+            adfGeoTransform[3] = CPLAtof(papszOriginTokens[1]);
+            adfGeoTransform[4] = CPLAtof(papszOffsetTokens[2]);
+            adfGeoTransform[5] = CPLAtof(papszOffsetTokens[3]);
         }
         else
         {
@@ -1388,12 +1401,12 @@ int WCSDataset::ExtractGridInfo()
         if( CSLCount(papszOffsetTokens) == 6
             && CSLCount(papszOriginTokens) == 3 )
         {
-            adfGeoTransform[0] = atof(papszOriginTokens[0]);
-            adfGeoTransform[1] = atof(papszOffsetTokens[0]);
-            adfGeoTransform[2] = atof(papszOffsetTokens[1]);
-            adfGeoTransform[3] = atof(papszOriginTokens[1]);
-            adfGeoTransform[4] = atof(papszOffsetTokens[3]);
-            adfGeoTransform[5] = atof(papszOffsetTokens[4]);
+            adfGeoTransform[0] = CPLAtof(papszOriginTokens[0]);
+            adfGeoTransform[1] = CPLAtof(papszOffsetTokens[0]);
+            adfGeoTransform[2] = CPLAtof(papszOffsetTokens[1]);
+            adfGeoTransform[3] = CPLAtof(papszOriginTokens[1]);
+            adfGeoTransform[4] = CPLAtof(papszOffsetTokens[3]);
+            adfGeoTransform[5] = CPLAtof(papszOffsetTokens[4]);
         }
         else
         {
@@ -1409,12 +1422,12 @@ int WCSDataset::ExtractGridInfo()
         if( CSLCount(papszOffsetTokens) == 2
             && CSLCount(papszOriginTokens) == 2 )
         {
-            adfGeoTransform[0] = atof(papszOriginTokens[0]);
-            adfGeoTransform[1] = atof(papszOffsetTokens[0]);
+            adfGeoTransform[0] = CPLAtof(papszOriginTokens[0]);
+            adfGeoTransform[1] = CPLAtof(papszOffsetTokens[0]);
             adfGeoTransform[2] = 0.0;
-            adfGeoTransform[3] = atof(papszOriginTokens[1]);
+            adfGeoTransform[3] = CPLAtof(papszOriginTokens[1]);
             adfGeoTransform[4] = 0.0;
-            adfGeoTransform[5] = atof(papszOffsetTokens[1]);
+            adfGeoTransform[5] = CPLAtof(papszOffsetTokens[1]);
         }
         else
         {
@@ -1598,7 +1611,7 @@ int WCSDataset::ExtractGridInfo()
         const char *pszSV = 
             CPLGetXMLValue( psCO, "Range.Field.NullValue", NULL );
         
-        if( pszSV != NULL && (atof(pszSV) != 0.0 || *pszSV == '0') )
+        if( pszSV != NULL && (CPLAtof(pszSV) != 0.0 || *pszSV == '0') )
         {
             bServiceDirty = TRUE;
             CPLCreateXMLElementAndValue( psService, "NoDataValue", 
@@ -2402,6 +2415,7 @@ void GDALRegister_WCS()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "WCS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "OGC Web Coverage Service" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/webp/GNUmakefile b/frmts/webp/GNUmakefile
index ce06549..835a60a 100644
--- a/frmts/webp/GNUmakefile
+++ b/frmts/webp/GNUmakefile
@@ -3,7 +3,7 @@ include ../../GDALmake.opt
 
 OBJ	=	webpdataset.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/webp/webpdataset.cpp b/frmts/webp/webpdataset.cpp
index 9e334f3..61e113c 100644
--- a/frmts/webp/webpdataset.cpp
+++ b/frmts/webp/webpdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: webpdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: webpdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  GDAL WEBP Driver
  * Purpose:  Implement GDAL WEBP Support based on libwebp
@@ -33,7 +33,7 @@
 #include "webp/decode.h"
 #include "webp/encode.h"
 
-CPL_CVSID("$Id: webpdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: webpdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 CPL_C_START
 void    GDALRegister_WEBP(void);
@@ -65,7 +65,10 @@ class WEBPDataset : public GDALPamDataset
 
     virtual CPLErr      IRasterIO( GDALRWFlag, int, int, int, int,
                                    void *, int, int, GDALDataType,
-                                   int, int *, int, int, int );
+                                   int, int *,
+                                   GSpacing nPixelSpace, GSpacing nLineSpace,
+                                   GSpacing nBandSpace,
+                                   GDALRasterIOExtraArg* psExtraArg);
 
     virtual char      **GetMetadataDomainList();
     virtual char  **GetMetadata( const char * pszDomain = "" );
@@ -286,6 +289,10 @@ CPLErr WEBPDataset::Uncompress()
     bHasBeenUncompressed = TRUE;
     eUncompressErrRet = CE_Failure;
 
+    pabyUncompressed = (GByte*)VSIMalloc3(nRasterXSize, nRasterYSize, nBands);
+    if (pabyUncompressed == NULL)
+        return CE_Failure;
+
     VSIFSeekL(fpImage, 0, SEEK_END);
     vsi_l_offset nSize = VSIFTellL(fpImage);
     if (nSize != (vsi_l_offset)(uint32_t)nSize)
@@ -326,7 +333,9 @@ CPLErr WEBPDataset::IRasterIO( GDALRWFlag eRWFlag,
                               void *pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType,
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     if((eRWFlag == GF_Read) &&
@@ -335,22 +344,37 @@ CPLErr WEBPDataset::IRasterIO( GDALRWFlag eRWFlag,
        (nXSize == nBufXSize) && (nXSize == nRasterXSize) &&
        (nYSize == nBufYSize) && (nYSize == nRasterYSize) &&
        (eBufType == GDT_Byte) && 
-       (nPixelSpace == nBands) &&
-       (nLineSpace == (nPixelSpace*nXSize)) &&
-       (nBandSpace == 1) &&
        (pData != NULL) &&
        (panBandMap != NULL) &&
        (panBandMap[0] == 1) && (panBandMap[1] == 2) && (panBandMap[2] == 3) && (nBands == 3 || panBandMap[3] == 4))
     {
-        Uncompress();
-        memcpy(pData, pabyUncompressed, nBands * nXSize * nYSize);
+        if( Uncompress() != CE_None )
+            return CE_Failure;
+        if( nPixelSpace == nBands && nLineSpace == (nPixelSpace*nXSize) && nBandSpace == 1 )
+        {
+            memcpy(pData, pabyUncompressed, nBands * nXSize * nYSize);
+        }
+        else
+        {
+            for(int y = 0; y < nYSize; ++y)
+            {
+                GByte* pabyScanline = pabyUncompressed + y * nBands * nXSize;
+                for(int x = 0; x < nXSize; ++x)
+                {
+                    for(int iBand=0;iBand<nBands;iBand++)
+                        ((GByte*)pData)[(y*nLineSpace) + (x*nPixelSpace) + iBand * nBandSpace] = pabyScanline[x*nBands+iBand];
+                }
+            }
+        }
+
         return CE_None;
     }
 
     return GDALPamDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                      pData, nBufXSize, nBufYSize, eBufType,
                                      nBandCount, panBandMap,
-                                     nPixelSpace, nLineSpace, nBandSpace);
+                                     nPixelSpace, nLineSpace, nBandSpace,
+                                     psExtraArg);
 }
 
 /************************************************************************/
@@ -382,7 +406,7 @@ int WEBPDataset::Identify( GDALOpenInfo * poOpenInfo )
 GDALDataset *WEBPDataset::Open( GDALOpenInfo * poOpenInfo )
 
 {
-    if( !Identify( poOpenInfo ) )
+    if( !Identify( poOpenInfo ) || poOpenInfo->fpL == NULL )
         return NULL;
 
     int nWidth, nHeight;
@@ -418,21 +442,6 @@ GDALDataset *WEBPDataset::Open( GDALOpenInfo * poOpenInfo )
     }
 
 /* -------------------------------------------------------------------- */
-/*      Open the file using the large file api.                         */
-/* -------------------------------------------------------------------- */
-    VSILFILE* fpImage = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
-
-    if( fpImage == NULL )
-        return NULL;
-
-    GByte* pabyUncompressed = (GByte*)VSIMalloc3(nWidth, nHeight, nBands);
-    if (pabyUncompressed == NULL)
-    {
-        VSIFCloseL(fpImage);
-        return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
 /*      Create a corresponding GDALDataset.                             */
 /* -------------------------------------------------------------------- */
     WEBPDataset  *poDS;
@@ -440,8 +449,8 @@ GDALDataset *WEBPDataset::Open( GDALOpenInfo * poOpenInfo )
     poDS = new WEBPDataset();
     poDS->nRasterXSize = nWidth;
     poDS->nRasterYSize = nHeight;
-    poDS->fpImage = fpImage;
-    poDS->pabyUncompressed = pabyUncompressed;
+    poDS->fpImage = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Create band information objects.                                */
@@ -454,12 +463,12 @@ GDALDataset *WEBPDataset::Open( GDALOpenInfo * poOpenInfo )
 /* -------------------------------------------------------------------- */
     poDS->SetDescription( poOpenInfo->pszFilename );
 
-    poDS->TryLoadXML( poOpenInfo->papszSiblingFiles );
+    poDS->TryLoadXML( poOpenInfo->GetSiblingFiles() );
 
 /* -------------------------------------------------------------------- */
 /*      Open overviews.                                                 */
 /* -------------------------------------------------------------------- */
-    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->papszSiblingFiles );
+    poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename, poOpenInfo->GetSiblingFiles() );
 
     return poDS;
 }
@@ -491,12 +500,14 @@ int WEBPDatasetWriter(const uint8_t* data, size_t data_size,
 /*                        WEBPDatasetProgressHook()                     */
 /************************************************************************/
 
+#if WEBP_ENCODER_ABI_VERSION >= 0x0100
 static
 int WEBPDatasetProgressHook(int percent, const WebPPicture* const picture)
 {
     WebPUserData* pUserData = (WebPUserData*)picture->custom_ptr;
     return pUserData->pfnProgress( percent / 100.0, NULL, pUserData->pProgressData );
 }
+#endif
 
 /************************************************************************/
 /*                              CreateCopy()                            */
@@ -573,7 +584,7 @@ WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     const char* pszQUALITY = CSLFetchNameValue(papszOptions, "QUALITY"); 
     if( pszQUALITY != NULL )
     {
-        fQuality = (float) atof(pszQUALITY);
+        fQuality = (float) CPLAtof(pszQUALITY);
         if( fQuality < 0.0f || fQuality > 100.0f )
         {
             CPLError( CE_Failure, CPLE_IllegalArg,
@@ -633,7 +644,7 @@ WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     const char* pszPSNR = CSLFetchNameValue(papszOptions, "PSNR");
     if (pszPSNR)
     {
-        sConfig.target_PSNR = atof(pszPSNR);
+        sConfig.target_PSNR = CPLAtof(pszPSNR);
         if (sConfig.target_PSNR < 0)
         {
             CPLError( CE_Failure, CPLE_IllegalArg,
@@ -725,7 +736,7 @@ WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     eErr = poSrcDS->RasterIO( GF_Read, 0, 0, nXSize, nYSize,
                               pabyBuffer, nXSize, nYSize, GDT_Byte,
                               nBands, NULL,
-                              nBands, nBands * nXSize, 1 );
+                              nBands, nBands * nXSize, 1, NULL );
 
 /* -------------------------------------------------------------------- */
 /*      Import and write to file                                        */
@@ -790,7 +801,7 @@ WEBPDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
     GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
 
@@ -822,6 +833,7 @@ void GDALRegister_WEBP()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "WEBP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "WEBP" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
diff --git a/frmts/wms/GNUmakefile b/frmts/wms/GNUmakefile
index f45d5d9..4b20a1f 100644
--- a/frmts/wms/GNUmakefile
+++ b/frmts/wms/GNUmakefile
@@ -6,9 +6,9 @@ OBJ =	gdalwmscache.o gdalwmsdataset.o gdalwmsrasterband.o \
 	wmsutils.o wmsdriver.o minidriver_wms.o \
 	minidriver_tileservice.o minidriver_worldwind.o \
 	minidriver_tms.o minidriver_tiled_wms.o wmsmetadataset.o \
-	minidriver_virtualearth.o
+	minidriver_virtualearth.o minidriver_arcgis_server.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(CURL_INC)
+CPPFLAGS	:=	 $(CPPFLAGS) $(CURL_INC)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
@@ -20,4 +20,4 @@ install-obj:	$(O_OBJ:.o=.$(OBJ_EXT))
 $(OBJ) $(O_OBJ):	gdalhttp.h md5.h minidriver_tileservice.h \
 	minidriver_wms.h minidriver_worldwind.h minidriver_tms.h \
 	minidriver_tiled_wms.h wmsdriver.h wmsmetadataset.h \
-	minidriver_virtualearth.h
+	minidriver_virtualearth.h minidriver_arcgis_server.h
diff --git a/frmts/wms/frmt_ags_arcgisonline.xml b/frmts/wms/frmt_ags_arcgisonline.xml
new file mode 100644
index 0000000..90e209c
--- /dev/null
+++ b/frmts/wms/frmt_ags_arcgisonline.xml
@@ -0,0 +1,15 @@
+<GDAL_WMS>
+    <Service name="AGS">
+	    <ServerUrl>http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer</ServerUrl>
+	    <BBoxOrder>xyXY</BBoxOrder>
+        <SRS>3857</SRS>
+    </Service>
+    <DataWindow>
+        <UpperLeftX>-20037508.34</UpperLeftX>
+        <UpperLeftY>20037508.34</UpperLeftY>
+        <LowerRightX>20037508.34</LowerRightX>
+        <LowerRightY>-20037508.34</LowerRightY>
+        <SizeX>512</SizeX>
+        <SizeY>512</SizeY>
+    </DataWindow>    
+</GDAL_WMS>
diff --git a/frmts/wms/frmt_wms.html b/frmts/wms/frmt_wms.html
index 540609b..757c2d4 100644
--- a/frmts/wms/frmt_wms.html
+++ b/frmts/wms/frmt_wms.html
@@ -18,7 +18,7 @@
 <p>
   Accessing several different types of web image services is possible
   using the WMS format in GDAL. Services are accessed by creating a
-  local service description XML file -- there are examples below for 
+  local service description XML file -- there are examples below for
   each of the supported image services. It is important that there be no
   spaces or other content before the <tt><GDAL_WMS></tt> element.
 </p>
@@ -30,7 +30,7 @@
 		</tr>
 		<tr>
 			<td class="xml">    <Service name="<span class="value">WMS</span>"></td>
-			<td class="desc">Define what mini-driver to use, currently supported are: WMS, WorldWind, TileService, TMS, TiledWMS or VirtualEarth. (required)</td>
+			<td class="desc">Define what mini-driver to use, currently supported are: WMS, WorldWind, TileService, TMS, TiledWMS, VirtualEarth or AGS. (required)</td>
 		</tr>
 		<tr>
 			<td class="xml">        <Version><span class="value">1.1.1</span></Version></td>
@@ -42,7 +42,8 @@
 		</tr>
 		<tr>
 			<td class="xml">        <SRS><span class="value">EPSG:4326</span></SRS></td>
-			<td class="desc">Image projection (optional, defaults to EPSG:4326, WMS version 1.1.1 or below only)</td>
+			<td class="desc">Image projection (optional, defaults to EPSG:4326 in WMS and 102100 in AGS, WMS version 1.1.1 or below only and ArcGIS Server).
+			For ArcGIS Server the spatial reference can be specified as either a well-known ID or as a <a href="http://resources.arcgis.com/en/help/rest/apiref/geometry.html#sr">spatial reference json object</a></td>
 		</tr>
 		<tr>
 			<td class="xml">        <CRS><span class="value">CRS:83</span></CRS></td>
@@ -57,8 +58,8 @@
             <td class="desc">Set to TRUE to include "transparent=TRUE" in the WMS GetMap request (optional defaults to FALSE).  The request format and BandsCount need to support alpha.</td>
         </tr>
 		<tr>
-			<td class="xml">        <Layers><span class="value">modis,global_mosaic</span></Layers></td>
-			<td class="desc">Comma separated list of layers. (required, except for TiledWMS)</td>
+			<td class="xml">        <Layers><span class="value">modis%2Cglobal_mosaic</span></Layers></td>
+			<td class="desc">A URL encoded, comma separated string of layers (required, except for TiledWMS)</td>
 		</tr>
         <tr>
             <td class="xml">        <TiledGroupName><span class="value">Clementine</span></TiledGroupName></td>
@@ -137,6 +138,10 @@
 		<tr>
 			<td class="xml">    <Projection><span class="value">EPSG:4326</span></Projection></td>
 			<td class="desc">Image projection (optional, defaults to value reported by mini-driver or EPSG:4326)</td>
+		</tr>		
+		<tr>
+			<td class="xml">    <IdentificationTolerance><span class="value">2</span></IdentificationTolerance></td>
+			<td class="desc">Identification tolerance (optional, defaults to 2)</td>
 		</tr>
 		<tr>
 			<td class="xml">    <BandsCount><span class="value">3</span></BandsCount></td>
@@ -188,7 +193,7 @@
 		</tr>
 		<tr>
 			<td class="xml">    <OfflineMode><span class="value">true</span></OfflineMode></td>
-			<td class="desc">Do not download any new images, use only what is in cache. Usefull only with cache enabled. (optional, defaults to false)</td>
+			<td class="desc">Do not download any new images, use only what is in cache. Useful only with cache enabled. (optional, defaults to false)</td>
 		</tr>
 		<tr>
 			<td class="xml">    <AdviseRead><span class="value">true</span></AdviseRead></td>
@@ -206,14 +211,18 @@
 			<td class="xml">    <UserAgent><span class="value">GDAL WMS driver (http://www.gdal.org/frmt_wms.html)</span></UserAgent></td>
 			<td class="desc">HTTP User-agent string. Some servers might require a well-known user-agent such as "Mozilla/5.0" (optional, defaults to "GDAL WMS driver (http://www.gdal.org/frmt_wms.html)"). Added in GDAL 1.8.0</td>
 		</tr>
-        <tr>
-            <td class="xml">    <UserPwd><span class="value">user:password</span></UserPwd></td>
-            <td class="desc">User and Password for HTTP authentication (optional). Added in GDAL 1.10.0</td>
-        </tr>
-        <tr>
-            <td class="xml">    <Referer><span class="value">http://example.foo/</span></Referer></td>
-            <td class="desc">HTTP Referer string. Some servers might require it (optional). Added in GDAL 1.9.0</td>
-        </tr>
+		<tr>
+			<td class="xml">    <UserPwd><span class="value">user:password</span></UserPwd></td>
+			<td class="desc">User and Password for HTTP authentication (optional). Added in GDAL 1.10.0</td>
+		</tr>
+		<tr>
+			<td class="xml">    <UnsafeSSL><span class="value">true</span></UnsafeSSL></td>
+			<td class="desc">Skip SSL certificate verification. May be needed if server is using a self signed certificate (optional, defaults to false). Added in GDAL 1.8.0.</td>
+		</tr>
+		<tr>
+			<td class="xml">    <Referer><span class="value">http://example.foo/</span></Referer></td>
+			<td class="desc">HTTP Referer string. Some servers might require it (optional). Added in GDAL 1.9.0</td>
+		</tr>
 		<tr>
 			<td class="xml">    <ZeroBlockHttpCodes><span class="value">204,404</span></ZeroBlockHttpCodes></td>
 			<td class="desc">Comma separated list of HTTP response codes that will be interpreted as a 0 filled image (i.e. black for 3 bands, and transparent for 4 bands) instead of aborting the request. Added in GDAL 1.9.0. (optional, defaults to 204)</td>
@@ -234,13 +243,13 @@
 
 <h2>Minidrivers</h2>
 <p>
-  The GDAL WMS driver has support for several internal 'minidrivers', which 
+  The GDAL WMS driver has support for several internal 'minidrivers', which
   allow access to different web mapping services. Each of these services may
   support a different set of options in the Service block.
 </p>
 <h3>WMS</h3>
 <p>
-  Communications with an OGC WMS server. Has support for both tiled and 
+  Communications with an OGC WMS server. Has support for both tiled and
   untiled requests.
 </p>
 
@@ -248,7 +257,7 @@
      Starting with GDAL >= 1.10, WMS layers can be queried (through a GetFeatureInfo request) with the gdallocationinfo utility, or
      with a GetMetadataItem("Pixel_iCol_iLine", "LocationInfo") call on a band object.<p>
      <pre>gdallocationinfo "WMS:http://demo.opengeo.org/geoserver/gwc/service/wms?SERVICE=WMS&VERSION=1.1.1&
-                            REQUEST=GetMap&LAYERS=og:bugsites&SRS=EPSG:900913&
+                            REQUEST=GetMap&LAYERS=og%3Abugsites&SRS=EPSG:900913&
                             BBOX=-1.15841845090625E7,5479006.186718751,-1.1505912992109375E7,5557277.703671876&
                             FORMAT=image/png&TILESIZE=256&OVERVIEWCOUNT=25&MINRESOLUTION=0.0046653459640220&TILED=true"
                            -geoloc -11547071.455 5528616 -xml -b 1
@@ -305,12 +314,12 @@ Report pixel="248595" line="191985">
 
 <h3>TMS (GDAL 1.7.0 and later)</h3>
 <p>
-  The TMS Minidriver is designed primarily to support the users of the 
+  The TMS Minidriver is designed primarily to support the users of the
   <a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">TMS
   Specification</a>. This service supports only access by tiles.
 </p>
 <p>
-  Because TMS is similar to many other 'x/y/z' flavored services on the web, 
+  Because TMS is similar to many other 'x/y/z' flavored services on the web,
   this service can also be used to access these services. To use it in this
   fashion, you can use replacement variables, of the format ${x}, ${y}, etc.
 </p>
@@ -329,7 +338,7 @@ Report pixel="248595" line="191985">
   A typical ServerURL might look like:<br />
   <tt>http://tilecache.osgeo.org/wms-c/Basic.py/${version}/${layer}/${z}/${x}/${y}.${format}</tt><br />
   In order to better suit TMS users, any URL that does not contain "${" will automatically have the string above (after "Basic.py/") appended to their URL.
-</p> 
+</p>
 <p>
   The TMS Service has 3 XML configuration elements that are different from
   other services: <tt>Format</tt> which defaults to <tt>jpg</tt>, <tt>Layer</tt> which has no default, and <tt>Version</tt> which defaults to <tt>1.0.0</tt>.
@@ -339,10 +348,10 @@ Report pixel="248595" line="191985">
   DataWindow level, which is the YOrigin element. This element should be one of
   <tt>bottom</tt> (the default in TMS) or <tt>top</tt>, which matches
   OpenStreetMap and many other popular tile services.
-</p>  
+</p>
 <p>
   Two examples of usage of the TMS service are included in the examples below.
-</p>  
+</p>
 
 <h3>OnEarth Tiled WMS (GDAL 1.9.0 and later)</h3>
 <p>
@@ -380,7 +389,19 @@ Access to web-based Virtual Earth tile services. Access is always tile based.<p>
 <li>BlockSizeX = 256</li>
 <li>BlockSizeY = 256</li>
 </ul>
-</p> 
+</p>
+
+<h3>ArcGIS REST API (GDAL 2.0 and later)</h3>
+<p>
+Access to ArcGIS REST <a href="http://resources.arcgis.com/en/help/rest/apiref/mapserver.html">map service resource</a> (untiled requests). 
+</p>
+<p>AGS layers can be <a href="http://resources.arcgis.com/en/help/rest/apiref/identify.html">queried</a> (through a GetFeatureInfo request) with the gdallocationinfo utility, or with a GetMetadataItem("Pixel_iCol_iLine", "LocationInfo") call on a band object.
+</p>
+
+<p>
+     <pre>gdallocationinfo -wgs84 "<GDAL_WMS><Service name=\"AGS\"><ServerUrl>http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Specialty/ESRI_StateCityHighway_USA/MapServer</ServerUrl><BBoxOrder>xyXY</BBoxOrder><SRS>3857</SRS></Service><DataWindow><UpperLeftX>-20037508.34</UpperLeftX><UpperLeftY>20037508.34</UpperLeftY><LowerRightX>20037508.34</LowerRightX><LowerRightY>-2003750 [...]
+    </pre>
+
 
 <h2>Examples</h2>
 
@@ -394,10 +415,10 @@ Access to web-based Virtual Earth tile services. Access is always tile based.<p>
     </li>
 
     <li><p>
-	<a href="frmt_wms_metacarta_wmsc.xml">metacarta_wmsc.xml</a> - 
+	<a href="frmt_wms_metacarta_wmsc.xml">metacarta_wmsc.xml</a> -
 	It is possible to configure a WMS Service conforming to a WMS-C cache by
-	specifying a number of overviews and specifying the 'block size' as the 
-	tile size of the cache. The following example is a sample set up for 
+	specifying a number of overviews and specifying the 'block size' as the
+	tile size of the cache. The following example is a sample set up for
 	a 19-level "Global Profile" WMS-C cache.
 	<pre>gdal_translate -of PNG -outsize 500 250 metacarta_wmsc.xml metacarta_wmsc.png</pre>
 	<img src="http://sydney.freeearthfoundation.com/gdalwms/metacarta_wmsc.png" alt="example output">
@@ -446,6 +467,10 @@ Access to web-based Virtual Earth tile services. Access is always tile based.<p>
     <li><p>
      <a href="frmt_wms_virtualearth.xml">VirtualEarth Aerial Layer</a> accessed with the VirtualEarth minidriver.
     </p></li>
+    
+    <li><p>
+     <a href="frmt_ags_arcgisonline.xml">ArcGIS online sample server layer</a> accessed with the ArcGIS Server REST API minidriver.
+    </p></li>
 
 </ul>
 
@@ -470,7 +495,7 @@ A list of subdatasets will be returned, resulting from the parsing of the GetCap
 
 <li><p>
 (GDAL >= 1.9.0) a pseudo GetMap request, such as the subdataset name returned by the previous syntax :
-<pre>gdalinfo "WMS:http://wms.geobase.ca/wms-bin/cubeserv.cgi?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=DNEC_250K:ELEVATION/ELEVATION&SRS=EPSG:42304&BBOX=-3000000,-1500000,6000000,4500000"</pre>
+<pre>gdalinfo "WMS:http://wms.geobase.ca/wms-bin/cubeserv.cgi?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=DNEC_250K%3AELEVATION%2FELEVATION&SRS=EPSG:42304&BBOX=-3000000,-1500000,6000000,4500000"</pre>
 </p></li>
 
 <li><p>
@@ -493,6 +518,7 @@ A list of subdatasets will be returned, resulting from the parsing of the GetTil
 <li><a href="http://www.worldwindcentral.com/wiki/TileService">WorldWind TileService</a></li>
 <li><a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">TMS Specification</a></li>
 <li><a href="http://onearth.jpl.nasa.gov/tiled.html">OnEarth Tiled WMS specification</a></li>
+<li><a href="http://resources.arcgis.com/en/help/rest/apiref/">ArcGIS Server REST API</a></li>
 </ul>
 
 </body>
diff --git a/frmts/wms/frmt_wms_openstreetmap_tms.xml b/frmts/wms/frmt_wms_openstreetmap_tms.xml
index 3c197a0..c236e0e 100644
--- a/frmts/wms/frmt_wms_openstreetmap_tms.xml
+++ b/frmts/wms/frmt_wms_openstreetmap_tms.xml
@@ -12,7 +12,7 @@
         <TileCountY>1</TileCountY>
         <YOrigin>top</YOrigin>
     </DataWindow>
-    <Projection>EPSG:900913</Projection>
+    <Projection>EPSG:3857</Projection>
     <BlockSizeX>256</BlockSizeX>
     <BlockSizeY>256</BlockSizeY>
     <BandsCount>3</BandsCount>
diff --git a/frmts/wms/gdalwmscache.cpp b/frmts/wms/gdalwmscache.cpp
index 0074fbb..20026be 100644
--- a/frmts/wms/gdalwmscache.cpp
+++ b/frmts/wms/gdalwmscache.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwmscache.cpp 27555 2014-08-02 17:47:11Z rouault $
+ * $Id: gdalwmscache.cpp 27554 2014-08-02 17:46:37Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
diff --git a/frmts/wms/gdalwmsdataset.cpp b/frmts/wms/gdalwmsdataset.cpp
index 03e9ec1..ff95daa 100644
--- a/frmts/wms/gdalwmsdataset.cpp
+++ b/frmts/wms/gdalwmsdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwmsdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalwmsdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
@@ -219,10 +219,10 @@ CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) {
                 {
                     if ((ulx[0] != '\0') && (uly[0] != '\0') && (lrx[0] != '\0') && (lry[0] != '\0'))
                     {
-                        m_data_window.m_x0 = atof(ulx);
-                        m_data_window.m_y0 = atof(uly);
-                        m_data_window.m_x1 = atof(lrx);
-                        m_data_window.m_y1 = atof(lry);
+                        m_data_window.m_x0 = CPLAtof(ulx);
+                        m_data_window.m_y0 = CPLAtof(uly);
+                        m_data_window.m_x1 = CPLAtof(lrx);
+                        m_data_window.m_y1 = CPLAtof(lry);
                     }
                     else
                     {
@@ -380,7 +380,7 @@ CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) {
     
     if (ret == CE_None) {
         const char *pszHttpZeroBlockCodes = CPLGetXMLValue(config, "ZeroBlockHttpCodes", "");
-        if(pszHttpZeroBlockCodes == '\0') {
+        if(pszHttpZeroBlockCodes[0] == '\0') {
             m_http_zeroblock_codes.push_back(204);
         } else {
             char **kv = CSLTokenizeString2(pszHttpZeroBlockCodes,",",CSLT_HONOURSTRINGS);
@@ -541,7 +541,12 @@ CPLErr GDALWMSDataset::Initialize(CPLXMLNode *config) {
 /************************************************************************/
 /*                             IRasterIO()                              */
 /************************************************************************/
-CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, int pixel_space, int line_space, int band_space) {
+CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
+                                 void *buffer, int bsx, int bsy, GDALDataType bdt,
+                                 int band_count, int *band_map,
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GSpacing nBandSpace,
+                                 GDALRasterIOExtraArg* psExtraArg) {
     CPLErr ret;
 
     if (rw != GF_Read) return CE_Failure;
@@ -555,7 +560,8 @@ CPLErr GDALWMSDataset::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
     m_hint.m_overview = -1;
     m_hint.m_valid = true;
     //	printf("[%p] GDALWMSDataset::IRasterIO(x0: %d, y0: %d, sx: %d, sy: %d, bsx: %d, bsy: %d, band_count: %d, band_map: %p)\n", this, x0, y0, sx, sy, bsx, bsy, band_count, band_map);
-    ret = GDALDataset::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, band_count, band_map, pixel_space, line_space, band_space);
+    ret = GDALDataset::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, band_count, band_map,
+                                 nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
     m_hint.m_valid = false;
 
     return ret;
@@ -601,8 +607,11 @@ CPLErr GDALWMSDataset::SetGeoTransform(CPL_UNUSED double *gt) {
 CPLErr GDALWMSDataset::AdviseRead(int x0, int y0,
                                   int sx, int sy,
                                   int bsx, int bsy,
-                                  GDALDataType bdt, CPL_UNUSED int band_count, CPL_UNUSED int *band_map,
+                                  GDALDataType bdt,
+                                  CPL_UNUSED int band_count,
+                                  CPL_UNUSED int *band_map,
                                   char **options) {
+//    printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
     if (m_offline_mode || !m_use_advise_read) return CE_None;
     if (m_cache == NULL) return CE_Failure;
 
diff --git a/frmts/wms/gdalwmsrasterband.cpp b/frmts/wms/gdalwmsrasterband.cpp
index 2e977a8..16d0156 100644
--- a/frmts/wms/gdalwmsrasterband.cpp
+++ b/frmts/wms/gdalwmsrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalwmsrasterband.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gdalwmsrasterband.cpp 28562 2015-02-26 15:00:55Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  GDALWMSRasterBand implementation.
@@ -37,7 +37,10 @@ GDALWMSRasterBand::GDALWMSRasterBand(GDALWMSDataset *parent_dataset, int band, d
     m_overview = -1;
     m_color_interp = GCI_Undefined;
 
-    poDS = parent_dataset;
+    if( scale == 1.0 )
+        poDS = parent_dataset;
+    else
+        poDS = NULL;
     nRasterXSize = static_cast<int>(m_parent_dataset->m_data_window.m_sx * scale + 0.5);
     nRasterYSize = static_cast<int>(m_parent_dataset->m_data_window.m_sy * scale + 0.5);
     nBand = band;
@@ -238,7 +241,8 @@ CPLErr GDALWMSRasterBand::ReadBlocks(int x, int y, void *buffer, int bx0, int by
                         }
                     }
                 } else {
-                    CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n  URL: %s\n  HTTP status code: %d, error: %s.",
+                    CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: Unable to download block %d, %d.\n  URL: %s\n  HTTP status code: %d, error: %s.\n"
+                        "Add the HTTP status code to <ZeroBlockHttpCodes> to ignore that error (see http://www.gdal.org/frmt_wms.html).",
                         download_blocks[i].x, download_blocks[i].y, download_requests[i].pszURL, download_requests[i].nStatus, 
 		    download_requests[i].pszError ? download_requests[i].pszError : "(null)");
                     ret = CE_Failure;
@@ -284,7 +288,10 @@ CPLErr GDALWMSRasterBand::IReadBlock(int x, int y, void *buffer) {
     return eErr;
 }
 
-CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int pixel_space, int line_space) {
+CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy,
+                                    void *buffer, int bsx, int bsy, GDALDataType bdt,
+                                    GSpacing nPixelSpace, GSpacing nLineSpace,
+                                    GDALRasterIOExtraArg* psExtraArg) {
     CPLErr ret;
 
     if (rw != GF_Read) return CE_Failure;
@@ -297,7 +304,7 @@ CPLErr GDALWMSRasterBand::IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int s
     m_parent_dataset->m_hint.m_sy = sy;
     m_parent_dataset->m_hint.m_overview = m_overview;
     m_parent_dataset->m_hint.m_valid = true;
-    ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, pixel_space, line_space);
+    ret = GDALRasterBand::IRasterIO(rw, x0, y0, sx, sy, buffer, bsx, bsy, bdt, nPixelSpace, nLineSpace, psExtraArg);
     m_parent_dataset->m_hint.m_valid = false;
 
     return ret;
@@ -421,15 +428,14 @@ const char *GDALWMSRasterBand::GetMetadataItem( const char * pszName,
             double dfGeoX, dfGeoY;
 
             {
-                CPLLocaleC oLocaleEnforcer;
-                if( sscanf( pszName+9, "%lf_%lf", &dfGeoX, &dfGeoY ) != 2 )
+                dfGeoX = CPLAtof(pszName + 9);
+                const char* pszUnderscore = strchr(pszName + 9, '_');
+                if( !pszUnderscore )
                     return NULL;
+                dfGeoY = CPLAtof(pszUnderscore+1);
             }
 
-            if( GetDataset() == NULL )
-                return NULL;
-
-            if( GetDataset()->GetGeoTransform( adfGeoTransform ) != CE_None )
+            if( m_parent_dataset->GetGeoTransform( adfGeoTransform ) != CE_None )
                 return NULL;
 
             if( !GDALInvGeoTransform( adfGeoTransform, adfInvGeoTransform ) )
@@ -448,8 +454,8 @@ const char *GDALWMSRasterBand::GetMetadataItem( const char * pszName,
             /* the values if we are an overview */
             if (m_overview >= 0)
             {
-                iPixel = (int) (1.0 * iPixel * GetXSize() / GetDataset()->GetRasterBand(1)->GetXSize());
-                iLine = (int) (1.0 * iLine * GetYSize() / GetDataset()->GetRasterBand(1)->GetYSize());
+                iPixel = (int) (1.0 * iPixel * GetXSize() / m_parent_dataset->GetRasterBand(1)->GetXSize());
+                iLine = (int) (1.0 * iLine * GetYSize() / m_parent_dataset->GetRasterBand(1)->GetYSize());
             }
         }
         else
@@ -654,7 +660,7 @@ CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name,
                                 // TODO: This hack is from #3493 - not sure it really belongs here.
 				if ((GDT_Int16==dt)&&(GDT_UInt16==ds->GetRasterBand(ib)->GetRasterDataType()))
 				    dt=GDT_UInt16;
-				if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, dt, 1, &ib, pixel_space, line_space, 0) != CE_None) {
+				if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, dt, 1, &ib, pixel_space, line_space, 0, NULL) != CE_None) {
 				    CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
 				    ret = CE_Failure;
 				}
@@ -680,7 +686,7 @@ CPLErr GDALWMSRasterBand::ReadBlockFromFile(int x, int y, const char *file_name,
                                }     
                             }
                         } else if (ib <= 4) {
-                            if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0) != CE_None) {
+                            if (ds->RasterIO(GF_Read, 0, 0, sx, sy, p, sx, sy, eDataType, 1, NULL, pixel_space, line_space, 0, NULL) != CE_None) {
                                 CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS: RasterIO failed on downloaded block.");
                                 ret = CE_Failure;
                             }
@@ -804,8 +810,11 @@ CPLErr GDALWMSRasterBand::ReportWMSException(const char *file_name) {
 
 CPLErr GDALWMSRasterBand::AdviseRead(int x0, int y0,
                                      int sx, int sy,
-                                     CPL_UNUSED int bsx, CPL_UNUSED int bsy,
-                                     CPL_UNUSED GDALDataType bdt, CPL_UNUSED char **options) {
+                                     CPL_UNUSED int bsx,
+                                     CPL_UNUSED int bsy,
+                                     CPL_UNUSED GDALDataType bdt,
+                                     CPL_UNUSED char **options) {
+//    printf("AdviseRead(%d, %d, %d, %d)\n", x0, y0, sx, sy);
     if (m_parent_dataset->m_offline_mode || !m_parent_dataset->m_use_advise_read) return CE_None;
     if (m_parent_dataset->m_cache == NULL) return CE_Failure;
 
diff --git a/frmts/wms/makefile.vc b/frmts/wms/makefile.vc
index d42fd77..47da4d0 100644
--- a/frmts/wms/makefile.vc
+++ b/frmts/wms/makefile.vc
@@ -4,7 +4,7 @@ OBJ	= \
 	gdalhttp.obj md5.obj minidriver.obj  wmsdriver.obj \
 	minidriver_wms.obj minidriver_tileservice.obj \
 	minidriver_worldwind.obj minidriver_tms.obj minidriver_tiled_wms.obj \
-	wmsmetadataset.obj minidriver_virtualearth.obj
+	wmsmetadataset.obj minidriver_virtualearth.obj minidriver_arcgis_server.obj
 
 EXTRAFLAGS = -DHAVE_CURL $(CURL_CFLAGS) $(CURL_INC)
 
diff --git a/frmts/wms/minidriver.cpp b/frmts/wms/minidriver.cpp
index ee2189b..58d8856 100644
--- a/frmts/wms/minidriver.cpp
+++ b/frmts/wms/minidriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  GDALWMSMiniDriver base class implementation.
@@ -30,7 +30,7 @@
 #include "wmsdriver.h"
 
 static volatile GDALWMSMiniDriverManager *g_mini_driver_manager = NULL;
-static void *g_mini_driver_manager_mutex = NULL;
+static CPLMutex *g_mini_driver_manager_mutex = NULL;
 
 GDALWMSMiniDriver::GDALWMSMiniDriver() {
     m_parent_dataset = 0;
@@ -46,8 +46,7 @@ CPLErr GDALWMSMiniDriver::Initialize(CPL_UNUSED CPLXMLNode *config) {
 void GDALWMSMiniDriver::GetCapabilities(CPL_UNUSED GDALWMSMiniDriverCapabilities *caps) {
 }
 
-void GDALWMSMiniDriver::ImageRequest(CPL_UNUSED CPLString *url,
-                                     CPL_UNUSED const GDALWMSImageRequestInfo &iri) {
+void GDALWMSMiniDriver::ImageRequest(CPL_UNUSED CPLString *url, CPL_UNUSED const GDALWMSImageRequestInfo &iri) {
 }
 
 void GDALWMSMiniDriver::TiledImageRequest(CPL_UNUSED CPLString *url,
diff --git a/frmts/wms/minidriver_arcgis_server.cpp b/frmts/wms/minidriver_arcgis_server.cpp
new file mode 100644
index 0000000..6dd62c9
--- /dev/null
+++ b/frmts/wms/minidriver_arcgis_server.cpp
@@ -0,0 +1,263 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  Arc GIS Server Client Driver
+ * Purpose:  Implementation of Dataset and RasterBand classes for WMS
+ *           and other similar services.
+ * Author:   Alexander Lisovenko
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "wmsdriver.h"
+#include "minidriver_arcgis_server.h"
+
+CPP_GDALWMSMiniDriverFactory(AGS)
+
+GDALWMSMiniDriver_AGS::GDALWMSMiniDriver_AGS()
+{
+}
+
+GDALWMSMiniDriver_AGS::~GDALWMSMiniDriver_AGS()
+{
+}
+
+CPLErr GDALWMSMiniDriver_AGS::Initialize(CPLXMLNode *config)
+{
+	CPLErr ret = CE_None;
+	int i;
+
+    if (ret == CE_None) 
+    {
+        const char *base_url = CPLGetXMLValue(config, "ServerURL", "");
+        if (base_url[0] != '\0') 
+        {
+            /* Try the old name */
+            base_url = CPLGetXMLValue(config, "ServerUrl", "");
+        }
+        
+        if (base_url[0] != '\0') 
+        {
+            m_base_url = base_url;
+        }
+        else 
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: ServerURL missing.");
+            ret = CE_Failure;
+        }
+    }
+
+	if (ret == CE_None) 
+	{
+        m_image_format = CPLGetXMLValue(config, "ImageFormat", "png");
+        m_transparent = CPLGetXMLValue(config, "Transparent","");
+		// the transparent flag needs to be "true" or "false" 
+		// in lower case according to the ArcGIS Server REST API
+        for(i = 0; i < (int)m_transparent.size(); i++)
+        {
+			m_transparent[i] = (char) tolower(m_transparent[i]);
+        }
+        
+		m_layers = CPLGetXMLValue(config, "Layers", "");
+    }
+    
+	if (ret == CE_None) 
+	{
+		const char* irs = CPLGetXMLValue(config, "SRS", "102100");
+		
+		if (irs != NULL)
+		{
+	        if(EQUALN(irs, "EPSG:", 5)) //if we have EPSG code just convert it to WKT
+	        {
+	            m_projection_wkt = ProjToWKT(irs);
+	            m_irs = irs + 5;
+	        }
+	        else //if we have AGS code - try if it's EPSG
+		    {
+		        m_irs = irs;
+		        m_projection_wkt = ProjToWKT("EPSG:" + m_irs);
+		    }
+		    // TODO: if we have AGS JSON    
+		}
+		m_identification_tolerance = CPLGetXMLValue(config, "IdentificationTolerance", "2");
+	}
+
+	if (ret == CE_None)
+	{
+        const char *bbox_order = CPLGetXMLValue(config, "BBoxOrder", "xyXY");
+        if (bbox_order[0] != '\0') 
+        {
+            for (i = 0; i < 4; ++i) 
+            {
+                if ((bbox_order[i] != 'x') && (bbox_order[i] != 'y') && 
+                    (bbox_order[i] != 'X') && (bbox_order[i] != 'Y')) 
+                    break;
+            }
+            
+            if (i == 4) 
+            {
+                m_bbox_order = bbox_order;
+            } 
+            else 
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: Incorrect BBoxOrder.");
+                ret = CE_Failure;
+            }
+        } 
+        else
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "GDALWMS, ArcGIS Server mini-driver: BBoxOrder missing.");
+            ret = CE_Failure;
+        }
+    }
+	
+    return ret;
+}
+
+void GDALWMSMiniDriver_AGS::GetCapabilities(GDALWMSMiniDriverCapabilities *caps) 
+{
+    caps->m_capabilities_version = 1;
+    caps->m_has_arb_overviews = 1;
+    caps->m_has_image_request = 1;
+    caps->m_has_tiled_image_requeset = 1;
+    caps->m_max_overview_count = 32;
+}
+
+void GDALWMSMiniDriver_AGS::ImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri) 
+{
+    *url = m_base_url;
+
+    if (m_base_url.ifind( "/export?") == std::string::npos)
+        URLAppend(url, "/export?");
+	
+	URLAppendF(url, "&f=image");
+	URLAppendF(url, "&bbox=%.8f,%.8f,%.8f,%.8f", 
+		GetBBoxCoord(iri, m_bbox_order[0]), GetBBoxCoord(iri, m_bbox_order[1]), 
+        GetBBoxCoord(iri, m_bbox_order[2]), GetBBoxCoord(iri, m_bbox_order[3]));
+	URLAppendF(url, "&size=%d,%d", iri.m_sx,iri.m_sy);
+	URLAppendF(url, "&dpi=");
+	URLAppendF(url, "&imageSR=%s", m_irs.c_str());
+	URLAppendF(url, "&bboxSR=%s", m_irs.c_str());
+	URLAppendF(url, "&format=%s", m_image_format.c_str());
+
+	URLAppendF(url, "&layerdefs=");
+	URLAppendF(url, "&layers=%s", m_layers.c_str());
+
+    if(m_transparent.size())
+	    URLAppendF(url, "&transparent=%s", m_transparent.c_str());
+    else
+        URLAppendF(url, "&transparent=%s", "false");
+        
+	URLAppendF(url, "&time=");
+	URLAppendF(url, "&layerTimeOptions=");
+	URLAppendF(url, "&dynamicLayers=");
+
+	CPLDebug("AGS", "URL = %s\n", url->c_str());
+}
+
+void GDALWMSMiniDriver_AGS::TiledImageRequest(CPLString *url, 
+                                      const GDALWMSImageRequestInfo &iri, 
+                                      const GDALWMSTiledImageRequestInfo &tiri) 
+{
+	ImageRequest(url, iri);
+}
+
+
+void GDALWMSMiniDriver_AGS::GetTiledImageInfo(CPLString *url,
+                                              const GDALWMSImageRequestInfo &iri,
+                                              const GDALWMSTiledImageRequestInfo &tiri,
+                                              int nXInBlock,
+                                              int nYInBlock)
+{
+    *url = m_base_url;
+
+    if (m_base_url.ifind( "/identify?") == std::string::npos)
+        URLAppend(url, "/identify?");
+
+	URLAppendF(url, "&f=json");
+
+	double fX = GetBBoxCoord(iri, 'x') + nXInBlock * (GetBBoxCoord(iri, 'X') - 
+	            GetBBoxCoord(iri, 'x')) / iri.m_sx;
+	double fY = GetBBoxCoord(iri, 'y') + (iri.m_sy - nYInBlock) * (GetBBoxCoord(iri, 'Y') - 
+	            GetBBoxCoord(iri, 'y')) / iri.m_sy;
+	            
+    URLAppendF(url, "&geometry=%8f,%8f", fX, fY);
+	URLAppendF(url, "&geometryType=esriGeometryPoint");
+
+	URLAppendF(url, "&sr=%s", m_irs.c_str());
+	URLAppendF(url, "&layerdefs=");
+	URLAppendF(url, "&time=");
+	URLAppendF(url, "&layerTimeOptions=");
+
+	CPLString layers("visible");
+	if ( m_layers.find("show") != std::string::npos )
+	{
+		layers = m_layers;
+		layers.replace( layers.find("show"), 4, "all" );
+	}
+	
+	if ( m_layers.find("hide") != std::string::npos )
+	{
+		layers = "top";
+	}
+	
+	if ( m_layers.find("include") != std::string::npos )
+	{
+		layers = "top";
+	}
+	
+	if ( m_layers.find("exclude") != std::string::npos )
+	{
+		layers = "top";
+	}
+
+	URLAppendF(url, "&layers=%s", layers.c_str());
+
+	URLAppendF(url, "&tolerance=%s", m_identification_tolerance.c_str());
+	URLAppendF(url, "&mapExtent=%.8f,%.8f,%.8f,%.8f", 
+		GetBBoxCoord(iri, m_bbox_order[0]), GetBBoxCoord(iri, m_bbox_order[1]), 
+        GetBBoxCoord(iri, m_bbox_order[2]), GetBBoxCoord(iri, m_bbox_order[3]));
+	URLAppendF(url, "&imageDisplay=%d,%d,96", iri.m_sx,iri.m_sy);
+	URLAppendF(url, "&returnGeometry=false");
+
+	URLAppendF(url, "&maxAllowableOffset=");
+    CPLDebug("AGS", "URL = %s", url->c_str());
+}
+
+
+const char *GDALWMSMiniDriver_AGS::GetProjectionInWKT() 
+{
+    return m_projection_wkt.c_str();
+}
+
+double GDALWMSMiniDriver_AGS::GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what) 
+{
+    switch (what) 
+    {
+        case 'x': return MIN(iri.m_x0, iri.m_x1);
+        case 'y': return MIN(iri.m_y0, iri.m_y1);
+        case 'X': return MAX(iri.m_x0, iri.m_x1);
+        case 'Y': return MAX(iri.m_y0, iri.m_y1);
+    }
+    return 0.0;
+}
+
diff --git a/frmts/wms/minidriver_arcgis_server.h b/frmts/wms/minidriver_arcgis_server.h
new file mode 100644
index 0000000..28c0006
--- /dev/null
+++ b/frmts/wms/minidriver_arcgis_server.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  Arc GIS Server Client Driver
+ * Purpose:  Implementation of Dataset and RasterBand classes for WMS
+ *           and other similar services.
+ * Author:   Alexander Lisovenko
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+H_GDALWMSMiniDriverFactory(AGS)
+
+class GDALWMSMiniDriver_AGS : public GDALWMSMiniDriver
+{
+public:
+    GDALWMSMiniDriver_AGS();
+    virtual ~GDALWMSMiniDriver_AGS();
+
+public:
+    virtual CPLErr Initialize(CPLXMLNode *config);
+    virtual void GetCapabilities(GDALWMSMiniDriverCapabilities *caps);
+    virtual void ImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri);
+    virtual void TiledImageRequest(CPLString *url, const GDALWMSImageRequestInfo &iri, 
+                                   const GDALWMSTiledImageRequestInfo &tiri);
+    virtual void GetTiledImageInfo(CPLString *url,
+                                   const GDALWMSImageRequestInfo &iri,
+                                   const GDALWMSTiledImageRequestInfo &tiri,
+                                   int nXInBlock,
+                                   int nYInBlock);
+    virtual const char *GetProjectionInWKT();
+
+protected:
+    double GetBBoxCoord(const GDALWMSImageRequestInfo &iri, char what);
+
+protected:
+    CPLString m_base_url;
+	/* 
+	 * png | png8 | png24 | jpg | pdf | bmp | gif | svg | png32  
+	 * http://resources.arcgis.com/en/help/rest/apiref/  
+	 * Parameter - format 
+	 */
+	CPLString m_image_format;
+	CPLString m_transparent;
+	CPLString m_bbox_order;
+	CPLString m_irs;
+
+    CPLString m_layers;
+    CPLString m_srs;
+    CPLString m_crs;
+    CPLString m_projection_wkt;
+
+	CPLString m_identification_tolerance;
+};
+
diff --git a/frmts/wms/minidriver_tiled_wms.cpp b/frmts/wms/minidriver_tiled_wms.cpp
index 12fd0d0..e96d744 100644
--- a/frmts/wms/minidriver_tiled_wms.cpp
+++ b/frmts/wms/minidriver_tiled_wms.cpp
@@ -246,7 +246,7 @@ static void FindChangePattern( char *cdata,char **substs, char **keys, CPLString
                         break;
                     }
                     // Execute the substitution on the "ret" string
-                    URLSearchAndReplace(&ret,key,found_value);
+                    URLSearchAndReplace(&ret,key,"%s",found_value);
                 }
                 if (found_key!=NULL) CPLFree(found_key);
             }
@@ -283,7 +283,7 @@ double GDALWMSMiniDriver_TiledWMS::Scale(const char *request) {
     int bbox=FindBbox(request);
     if (bbox<0) return 0;
     double x,y,X,Y;
-    sscanf(request+bbox,"%lf,%lf,%lf,%lf",&x,&y,&X,&Y);
+    CPLsscanf(request+bbox,"%lf,%lf,%lf,%lf",&x,&y,&X,&Y);
     return (m_data_window.m_x1-m_data_window.m_x0)/(X-x)*m_bsx/m_data_window.m_sx;
 }
 
@@ -446,10 +446,10 @@ CPLErr GDALWMSMiniDriver_TiledWMS::Initialize(CPLXMLNode *config)
             break;
         }
 
-        m_data_window.m_x0=atof(CPLGetXMLValue(bbox,"minx","0"));
-        m_data_window.m_x1=atof(CPLGetXMLValue(bbox,"maxx","-1"));
-        m_data_window.m_y0=atof(CPLGetXMLValue(bbox,"maxy","0"));
-        m_data_window.m_y1=atof(CPLGetXMLValue(bbox,"miny","-1"));
+        m_data_window.m_x0=CPLAtof(CPLGetXMLValue(bbox,"minx","0"));
+        m_data_window.m_x1=CPLAtof(CPLGetXMLValue(bbox,"maxx","-1"));
+        m_data_window.m_y0=CPLAtof(CPLGetXMLValue(bbox,"maxy","0"));
+        m_data_window.m_y1=CPLAtof(CPLGetXMLValue(bbox,"miny","-1"));
 
         if ((m_data_window.m_x1-m_data_window.m_x0)<0) {
             CPLError(ret=CE_Failure,CPLE_AppDefined,"%s%s", SIG,
@@ -580,7 +580,7 @@ CPLErr GDALWMSMiniDriver_TiledWMS::Initialize(CPLXMLNode *config)
                 }
 
                 double x,y,X,Y;
-                if (sscanf(CSLFetchNameValueDef(papszTokens,"BBOX", ""),"%lf,%lf,%lf,%lf",&x,&y,&X,&Y)!=4)
+                if (CPLsscanf(CSLFetchNameValueDef(papszTokens,"BBOX", ""),"%lf,%lf,%lf,%lf",&x,&y,&X,&Y)!=4)
                 {
                     CPLError(ret=CE_Failure,CPLE_AppDefined,
                         "%s Error parsing BBOX, pattern %d\n",SIG,overview_count+1);
@@ -696,4 +696,3 @@ void GDALWMSMiniDriver_TiledWMS::TiledImageRequest(CPLString *url, const GDALWMS
 const char *GDALWMSMiniDriver_TiledWMS::GetProjectionInWKT() {
     return m_projection_wkt.c_str();
 }
-
diff --git a/frmts/wms/minidriver_tileservice.cpp b/frmts/wms/minidriver_tileservice.cpp
index 5ea3349..364fcf0 100644
--- a/frmts/wms/minidriver_tileservice.cpp
+++ b/frmts/wms/minidriver_tileservice.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver_tileservice.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver_tileservice.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
diff --git a/frmts/wms/minidriver_tms.cpp b/frmts/wms/minidriver_tms.cpp
index d8e0c39..f4d7bcb 100644
--- a/frmts/wms/minidriver_tms.cpp
+++ b/frmts/wms/minidriver_tms.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver_tms.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver_tms.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
diff --git a/frmts/wms/minidriver_virtualearth.cpp b/frmts/wms/minidriver_virtualearth.cpp
index 9d57f3a..e5e4724 100644
--- a/frmts/wms/minidriver_virtualearth.cpp
+++ b/frmts/wms/minidriver_virtualearth.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver_virtualearth.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver_virtualearth.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
diff --git a/frmts/wms/minidriver_wms.cpp b/frmts/wms/minidriver_wms.cpp
index b7ef8ce..f9b3c97 100644
--- a/frmts/wms/minidriver_wms.cpp
+++ b/frmts/wms/minidriver_wms.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver_wms.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver_wms.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
@@ -152,7 +152,6 @@ void GDALWMSMiniDriver_WMS::GetCapabilities(GDALWMSMiniDriverCapabilities *caps)
 
 void GDALWMSMiniDriver_WMS::BuildURL(CPLString *url, const GDALWMSImageRequestInfo &iri, const char* pszRequest) {
     // http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&width=1000&height=500&layers=modis,global_mosaic&styles=&srs=EPSG:4326&format=image/jpeg&bbox=-180.000000,-90.000000,180.000000,090.000000
-    CPLLocaleC oLocaleEnforcer;
     *url = m_base_url;
     if (m_base_url.ifind( "service=") == std::string::npos)
         URLAppend(url, "&service=WMS");
diff --git a/frmts/wms/minidriver_worldwind.cpp b/frmts/wms/minidriver_worldwind.cpp
index 4be8c32..ead4822 100644
--- a/frmts/wms/minidriver_worldwind.cpp
+++ b/frmts/wms/minidriver_worldwind.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: minidriver_worldwind.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: minidriver_worldwind.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
diff --git a/frmts/wms/wmsdriver.cpp b/frmts/wms/wmsdriver.cpp
index 2462398..54cfca4 100644
--- a/frmts/wms/wmsdriver.cpp
+++ b/frmts/wms/wmsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: wmsdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: wmsdriver.cpp 28911 2015-04-15 14:46:06Z bishop $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
@@ -38,6 +38,7 @@
 #include "minidriver_tms.h"
 #include "minidriver_tiled_wms.h"
 #include "minidriver_virtualearth.h"
+#include "minidriver_arcgis_server.h"
 
 /************************************************************************/
 /*              GDALWMSDatasetGetConfigFromURL()                        */
@@ -209,8 +210,7 @@ CPLXMLNode * GDALWMSDatasetGetConfigFromURL(GDALOpenInfo *poOpenInfo)
     }
 
     char* pszEscapedURL = CPLEscapeString(osBaseURL.c_str(), -1, CPLES_XML);
-    char* pszEscapedLayerURL = CPLEscapeString(osLayer.c_str(), -1, CPLES_URL);
-    char* pszEscapedLayerXML = CPLEscapeString(pszEscapedLayerURL, -1, CPLES_XML);
+    char* pszEscapedLayerXML = CPLEscapeString(osLayer.c_str(), -1, CPLES_XML);
 
     CPLString osXML = CPLSPrintf(
             "<GDAL_WMS>\n"
@@ -252,7 +252,6 @@ CPLXMLNode * GDALWMSDatasetGetConfigFromURL(GDALOpenInfo *poOpenInfo)
             nOverviewCount);
 
     CPLFree(pszEscapedURL);
-    CPLFree(pszEscapedLayerURL);
     CPLFree(pszEscapedLayerXML);
 
     CSLDestroy(papszTokens);
@@ -674,6 +673,11 @@ int GDALWMSDataset::Identify(GDALOpenInfo *poOpenInfo)
     {
         return TRUE;
     }
+    else if (poOpenInfo->nHeaderBytes == 0 &&
+              EQUALN(pszFilename, "AGS:", 4))
+    {
+        return TRUE;
+    }
     else
         return FALSE;
 }
@@ -801,6 +805,11 @@ GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
         CPLDestroyXMLNode( psXML );
         return poRet;
     }
+    else if (poOpenInfo->nHeaderBytes == 0 &&
+              EQUALN(pszFilename, "AGS:", 4))
+    {
+		return NULL;
+    }
     else
         return NULL;
     if (config == NULL) return NULL;
@@ -812,7 +821,7 @@ GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
     {
         CPLDestroyXMLNode(config);
         CPLError( CE_Failure, CPLE_NotSupported, 
-                  "The WMS driver does not support update access to existing"
+                  "The WMS poDriver does not support update access to existing"
                   " datasets.\n" );
         return NULL;
     }
@@ -843,7 +852,8 @@ GDALDataset *GDALWMSDataset::Open(GDALOpenInfo *poOpenInfo)
 
 GDALDataset *GDALWMSDataset::CreateCopy( const char * pszFilename,
                                          GDALDataset *poSrcDS,
-                                         CPL_UNUSED int bStrict, CPL_UNUSED char ** papszOptions,
+                                         CPL_UNUSED int bStrict,
+                                         CPL_UNUSED char ** papszOptions,
                                          CPL_UNUSED GDALProgressFunc pfnProgress,
                                          CPL_UNUSED void * pProgressData )
 {
@@ -889,22 +899,23 @@ static void GDALDeregister_WMS( GDALDriver * )
 /************************************************************************/
 
 void GDALRegister_WMS() {
-    GDALDriver *driver;
+    GDALDriver *poDriver;
     if (GDALGetDriverByName("WMS") == NULL) {
-        driver = new GDALDriver();
+        poDriver = new GDALDriver();
 
-        driver->SetDescription("WMS");
-        driver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service");
-        driver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_wms.html");
-        driver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
-        driver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
+        poDriver->SetDescription("WMS");
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "OGC Web Map Service");
+        poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "frmt_wms.html");
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
 
-        driver->pfnOpen = GDALWMSDataset::Open;
-        driver->pfnIdentify = GDALWMSDataset::Identify;
-        driver->pfnUnloadDriver = GDALDeregister_WMS;
-        driver->pfnCreateCopy = GDALWMSDataset::CreateCopy;
+        poDriver->pfnOpen = GDALWMSDataset::Open;
+        poDriver->pfnIdentify = GDALWMSDataset::Identify;
+        poDriver->pfnUnloadDriver = GDALDeregister_WMS;
+        poDriver->pfnCreateCopy = GDALWMSDataset::CreateCopy;
 
-        GetGDALDriverManager()->RegisterDriver(driver);
+        GetGDALDriverManager()->RegisterDriver(poDriver);
 
         GDALWMSMiniDriverManager *const mdm = GetGDALWMSMiniDriverManager();
         mdm->Register(new GDALWMSMiniDriverFactory_WMS());
@@ -913,5 +924,6 @@ void GDALRegister_WMS() {
         mdm->Register(new GDALWMSMiniDriverFactory_TMS());
         mdm->Register(new GDALWMSMiniDriverFactory_TiledWMS());
         mdm->Register(new GDALWMSMiniDriverFactory_VirtualEarth());
+        mdm->Register(new GDALWMSMiniDriverFactory_AGS());
     }
 }
diff --git a/frmts/wms/wmsdriver.h b/frmts/wms/wmsdriver.h
index 28478c8..7ce6a4a 100644
--- a/frmts/wms/wmsdriver.h
+++ b/frmts/wms/wmsdriver.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: wmsdriver.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: wmsdriver.h 28432 2015-02-06 21:15:27Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  Implementation of Dataset and RasterBand classes for WMS
@@ -58,14 +58,14 @@ class GDALWMSRasterBand;
 CPLString MD5String(const char *s);
 CPLString ProjToWKT(const CPLString &proj);
 void URLAppend(CPLString *url, const char *s);
-void URLAppendF(CPLString *url, const char *s, ...);
+void URLAppendF(CPLString *url, const char *s, ...) CPL_PRINT_FUNC_FORMAT (2, 3);
 void URLAppend(CPLString *url, const CPLString &s);
 CPLString BufferToVSIFile(GByte *buffer, size_t size);
 CPLErr MakeDirs(const char *path);
 
 
 int StrToBool(const char *p);
-int URLSearchAndReplace (CPLString *base, const char *search, const char *fmt, ...);
+int URLSearchAndReplace (CPLString *base, const char *search, const char *fmt, ...) CPL_PRINT_FUNC_FORMAT (3, 4);
 /* Convert a.b.c.d to a * 0x1000000 + b * 0x10000 + c * 0x100 + d */
 int VersionStringToInt(const char *version);
 
@@ -346,7 +346,12 @@ public:
                                     void * pProgressData );
 
 protected:
-    virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int band_count, int *band_map, int pixel_space, int line_space, int band_space);
+    virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer,
+                             int bsx, int bsy, GDALDataType bdt,
+                             int band_count, int *band_map,
+                             GSpacing nPixelSpace, GSpacing nLineSpace,
+                             GSpacing nBandSpace,
+                             GDALRasterIOExtraArg* psExtraArg);
     CPLErr Initialize(CPLXMLNode *config);
 
     GDALWMSDataWindow m_data_window;
@@ -410,7 +415,9 @@ public:
     virtual GDALColorInterp GetColorInterpretation();
     virtual CPLErr SetColorInterpretation( GDALColorInterp );
     virtual CPLErr IReadBlock(int x, int y, void *buffer);
-    virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt, int pixel_space, int line_space);
+    virtual CPLErr IRasterIO(GDALRWFlag rw, int x0, int y0, int sx, int sy, void *buffer, int bsx, int bsy, GDALDataType bdt,
+                             GSpacing nPixelSpace, GSpacing nLineSpace,
+                             GDALRasterIOExtraArg* psExtraArg);
     virtual int HasArbitraryOverviews();
     virtual int GetOverviewCount();
     virtual GDALRasterBand *GetOverview(int n);
diff --git a/frmts/wms/wmsmetadataset.cpp b/frmts/wms/wmsmetadataset.cpp
index 47ad08a..777e8e9 100644
--- a/frmts/wms/wmsmetadataset.cpp
+++ b/frmts/wms/wmsmetadataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: wmsmetadataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: wmsmetadataset.cpp 27892 2014-10-20 22:02:57Z rouault $
  *
  * Project:  WMS Client Driver
  * Purpose:  Definition of GDALWMSMetaDataset class
@@ -244,14 +244,15 @@ void GDALWMSMetaDataset::AddSubDataset( const char* pszLayerName,
                                         const char* pszMaxY,
                                         CPLString osFormat,
                                         CPLString osTransparent)
-
 {
     CPLString osSubdatasetName = "WMS:";
     osSubdatasetName += osGetURL;
     osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "SERVICE", "WMS");
     osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "VERSION", osVersion);
     osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "REQUEST", "GetMap");
-    osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", pszLayerName);
+    char* pszEscapedLayerName = CPLEscapeString(pszLayerName, -1, CPLES_URL);
+    osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "LAYERS", pszEscapedLayerName);
+    CPLFree(pszEscapedLayerName);
     if(VersionStringToInt(osVersion.c_str())>= VersionStringToInt("1.3.0"))
     {
         osSubdatasetName = CPLURLAddKVP(osSubdatasetName, "CRS", pszSRS);
@@ -760,4 +761,3 @@ GDALDataset* GDALWMSMetaDataset::AnalyzeTileMapService(CPLXMLNode* psXML)
 
     return poDS;
 }
-
diff --git a/frmts/xpm/GNUmakefile b/frmts/xpm/GNUmakefile
index 42405de..733ec3d 100644
--- a/frmts/xpm/GNUmakefile
+++ b/frmts/xpm/GNUmakefile
@@ -5,7 +5,7 @@ include ../../GDALmake.opt
 
 XTRAOPTS = -I../mem
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(XTRAOPTS) $(CPPFLAGS)
+CPPFLAGS	:=	 $(XTRAOPTS) $(CPPFLAGS)
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/xpm/xpmdataset.cpp b/frmts/xpm/xpmdataset.cpp
index 36332a3..bec7664 100644
--- a/frmts/xpm/xpmdataset.cpp
+++ b/frmts/xpm/xpmdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: xpmdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: xpmdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
  *
  * Project:  XPM Driver
  * Purpose:  Implement GDAL XPM Support
@@ -34,7 +34,7 @@
 #include "gdal_frmts.h"						      
 
 
-CPL_CVSID("$Id: xpmdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: xpmdataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
 
 static unsigned char *ParseXPM( const char *pszInput,
                                 int *pnXSize, int *pnYSize, 
@@ -200,13 +200,16 @@ GDALDataset *XPMDataset::Open( GDALOpenInfo * poOpenInfo )
 /************************************************************************/
 
 static GDALDataset *
-XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS, 
-               int bStrict, CPL_UNUSED char ** papszOptions, 
-               CPL_UNUSED GDALProgressFunc pfnProgress, CPL_UNUSED void * pProgressData )
+XPMCreateCopy( const char * pszFilename,
+               CPL_UNUSED GDALDataset *poSrcDS,
+               int bStrict,
+               CPL_UNUSED char ** papszOptions,
+               CPL_UNUSED GDALProgressFunc pfnProgress,
+               CPL_UNUSED void * pProgressData )
 {
-    const int  nBands = poSrcDS->GetRasterCount();
-    const int  nXSize = poSrcDS->GetRasterXSize();
-    const int  nYSize = poSrcDS->GetRasterYSize();
+    int  nBands = poSrcDS->GetRasterCount();
+    int  nXSize = poSrcDS->GetRasterXSize();
+    int  nYSize = poSrcDS->GetRasterYSize();
     GDALColorTable *poCT;
 
 /* -------------------------------------------------------------------- */
@@ -383,7 +386,7 @@ XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     for( iLine = 0; iLine < nYSize; iLine++ )
     {
         poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, 
-                          (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0 );
+                          (void *) pabyScanline, nXSize, 1, GDT_Byte, 0, 0, NULL );
         
         VSIFPutcL( '"', fpPBM );
         for( int iPixel = 0; iPixel < nXSize; iPixel++ )
@@ -401,9 +404,9 @@ XPMCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
     VSIFCloseL( fpPBM );
 
 /* -------------------------------------------------------------------- */
-/*      Re-open dataset, and copy any auxilary pam information.         */
+/*      Re-open dataset, and copy any auxiliary pam information.         */
 /* -------------------------------------------------------------------- */
-    GDALPamDataset *poDS = (GDALPamDataset *) 
+    GDALPamDataset *poDS = (GDALPamDataset *)
         GDALOpen( pszFilename, GA_ReadOnly );
 
     if( poDS )
@@ -426,6 +429,7 @@ void GDALRegister_XPM()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "XPM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "X11 PixMap Format" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/xyz/GNUmakefile b/frmts/xyz/GNUmakefile
index 08a3cb4..7fb5fbe 100644
--- a/frmts/xyz/GNUmakefile
+++ b/frmts/xyz/GNUmakefile
@@ -3,7 +3,7 @@ OBJ	=	xyzdataset.o
 
 include ../../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/xyz/xyzdataset.cpp b/frmts/xyz/xyzdataset.cpp
index 28d3ac4..896e6be 100644
--- a/frmts/xyz/xyzdataset.cpp
+++ b/frmts/xyz/xyzdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: xyzdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: xyzdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  XYZ driver
  * Purpose:  GDALDataset driver for XYZ dataset.
@@ -30,8 +30,10 @@
 #include "cpl_vsi_virtual.h"
 #include "cpl_string.h"
 #include "gdal_pam.h"
+#include <vector>
+#include <algorithm>
 
-CPL_CVSID("$Id: xyzdataset.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: xyzdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_XYZ(void);
@@ -124,12 +126,12 @@ XYZRasterBand::XYZRasterBand( XYZDataset *poDS, int nBand, GDALDataType eDT )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr XYZRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff, int nBlockYOff,
+CPLErr XYZRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
+                                  int nBlockYOff,
                                   void * pImage )
-
 {
     XYZDataset *poGDS = (XYZDataset *) poDS;
-    
+
     if (poGDS->fp == NULL)
         return CE_Failure;
 
@@ -422,7 +424,7 @@ XYZDataset::XYZDataset()
     nDataLineNum = INT_MAX;
     nLineNum = 0;
     nCommentLineCount = 0;
-    chDecimalSep = 0;
+    chDecimalSep = '.';
     bHasHeaderLine = FALSE;
     nXIndex = -1;
     nYIndex = -1;
@@ -480,7 +482,7 @@ int XYZDataset::IdentifyEx( GDALOpenInfo * poOpenInfo,
 
     GDALOpenInfo* poOpenInfoToDelete = NULL;
     /*  GZipped .xyz files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     if (strlen(poOpenInfo->pszFilename) > 6 &&
         EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") &&
         !EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
@@ -489,7 +491,7 @@ int XYZDataset::IdentifyEx( GDALOpenInfo * poOpenInfo,
         osFilename += poOpenInfo->pszFilename;
         poOpenInfo = poOpenInfoToDelete =
                 new GDALOpenInfo(osFilename.c_str(), GA_ReadOnly,
-                                 poOpenInfo->papszSiblingFiles);
+                                 poOpenInfo->GetSiblingFiles());
     }
 
     if (poOpenInfo->nHeaderBytes == 0)
@@ -612,7 +614,7 @@ GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo )
     CPLString osFilename(poOpenInfo->pszFilename);
 
     /*  GZipped .xyz files are common, so automagically open them */
-    /*  if the /vsigzip/ has not been explicitely passed */
+    /*  if the /vsigzip/ has not been explicitly passed */
     if (strlen(poOpenInfo->pszFilename) > 6 &&
         EQUAL(poOpenInfo->pszFilename + strlen(poOpenInfo->pszFilename) - 6, "xyz.gz") &&
         !EQUALN(poOpenInfo->pszFilename, "/vsigzip/", 9))
@@ -703,17 +705,17 @@ GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Parse data lines                                                */
 /* -------------------------------------------------------------------- */
 
-    int nXSize = 0, nYSize = 0;
     int nLineNum = 0;
     int nDataLineNum = 0;
     double dfX = 0, dfY = 0, dfZ = 0;
     double dfMinX = 0, dfMinY = 0, dfMaxX = 0, dfMaxY = 0;
     double dfMinZ = 0, dfMaxZ = 0;
     double dfLastX = 0, dfLastY = 0;
-    double dfStepX = 0, dfStepY = 0;
+    std::vector<double> adfStepX, adfStepY;
     GDALDataType eDT = GDT_Byte;
     int bSameNumberOfValuesPerLine = TRUE;
     char chDecimalSep = '\0';
+    int bStepYSign = 0;
     while((pszLine = CPLReadLine2L(fp, 100, NULL)) != NULL)
     {
         nLineNum ++;
@@ -831,103 +833,85 @@ GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo )
             return NULL;
         }
 
-        if (nDataLineNum == 2)
+        if (nDataLineNum == 1)
         {
-            dfStepX = dfX - dfLastX;
-            if (dfStepX <= 0)
-            {
-                CPLError(CE_Failure, CPLE_AppDefined,
-                         "Ungridded dataset: At line %d, X spacing was %f. Expected >0 value",
-                         nLineNum, dfStepX);
-                VSIFCloseL(fp);
-                return NULL;
-            }
+            dfMinX = dfMaxX = dfX;
+            dfMinY = dfMaxY = dfY;
         }
-        else if (nDataLineNum > 2)
+        else
         {
-            //double dfNewStepX = dfX - dfLastX;
-            double dfNewStepY = dfY - dfLastY;
-            if (dfNewStepY != 0)
+            double dfStepY = dfY - dfLastY;
+            if( dfStepY == 0.0 )
             {
-                nYSize ++;
-                if (dfStepY == 0)
-                {
-                    nXSize = nDataLineNum - 1;
-                    double dfAdjustedStepX = (dfMaxX - dfMinX) / (nXSize - 1);
-                    if (fabs(dfStepX - dfAdjustedStepX) > 1e-8)
-                    {
-                        CPLDebug("XYZ", "Adjusting stepx from %f to %f", dfStepX, dfAdjustedStepX);
-                    }
-                    dfStepX = dfAdjustedStepX;
-                }
-                if (fabs(dfX - dfMinX) > 1e-8)
+                double dfStepX = dfX - dfLastX;
+                if( dfStepX <= 0 )
                 {
-                    if( dfX < dfMinX && fmod(dfMinX - dfX, dfStepX) < 1e-8 )
-                    {
-                        bSameNumberOfValuesPerLine = FALSE;
-                        //CPLDebug("XYZ", "Adjusting minx to %f", dfX);
-                        dfMinX = dfX;
-                        nXSize = 1 + (int)((dfMaxX - dfMinX) / dfStepX + 1e-5 );
-                    }
-                    else if( !(dfX > dfMinX && fmod(dfX - dfMinX, dfStepX) < 1e-8) )
-                    {
-                        CPLError(CE_Failure, CPLE_AppDefined,
-                                "Ungridded dataset: At line %d, X is %f, where as %f was expected (1)",
-                                nLineNum, dfX, dfMinX);
-                        VSIFCloseL(fp);
-                        return NULL;
-                    }
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                         "Ungridded dataset: At line %d, X spacing was %f. Expected >0 value",
+                         nLineNum, dfStepX);
+                    VSIFCloseL(fp);
+                    return NULL;
                 }
-                if (fabs(dfLastX - dfMaxX) > 1e-8)
+                if( std::find(adfStepX.begin(), adfStepX.end(), dfStepX) == adfStepX.end() )
                 {
-                    if( dfLastX > dfMaxX && fmod(dfLastX - dfMaxX, dfStepX) < 1e-8 )
+                    int bAddNewValue = TRUE;
+                    std::vector<double>::iterator oIter = adfStepX.begin();
+                    while( oIter != adfStepX.end() )
                     {
-                        bSameNumberOfValuesPerLine = FALSE;
-                        //CPLDebug("XYZ", "Adjusting maxx to %f", dfLastX);
-                        dfMaxX = dfLastX;
-                        nXSize = 1 + (int)((dfMaxX - dfMinX) / dfStepX + 1e-5 );
+                        if( dfStepX < *oIter && fmod( *oIter, dfStepX ) < 1e-8 )
+                        {
+                            adfStepX.erase(oIter);
+                        }
+                        else if( dfStepX > *oIter && fmod( dfStepX, *oIter ) < 1e-8 )
+                        {
+                            bAddNewValue = FALSE;
+                            break;
+                        }
+                        else
+                        {
+                            ++ oIter;
+                        }
                     }
-                    else if( !(dfLastX < dfMaxX && fmod(dfMaxX - dfLastX, dfStepX) < 1e-8) )
+                    if( bAddNewValue )
                     {
-                        CPLError(CE_Failure, CPLE_AppDefined,
-                                "Ungridded dataset: At line %d, X is %f, where as %f was expected (2)",
-                                nLineNum - 1, dfLastX, dfMaxX);
-                        VSIFCloseL(fp);
-                        return NULL;
+                        adfStepX.push_back(dfStepX);
+                        if( adfStepX.size() == 10 )
+                        {
+                            CPLError(CE_Failure, CPLE_AppDefined,
+                                "Ungridded dataset: too many stepX values");
+                            VSIFCloseL(fp);
+                            return NULL;
+                        }
                     }
                 }
-                /*if (dfStepY != 0 && fabs(dfNewStepY - dfStepY) > 1e-8)
+            }
+            else
+            {
+                int bNewStepYSign = (dfStepY < 0.0) ? -1 : 1;
+                if( bStepYSign == 0 )
+                    bStepYSign = bNewStepYSign;
+                else if( bStepYSign != bNewStepYSign )
                 {
                     CPLError(CE_Failure, CPLE_AppDefined,
-                             "Ungridded dataset: At line %d, Y spacing was %f, whereas it was %f before",
-                             nLineNum, dfNewStepY, dfStepY);
+                         "Ungridded dataset: At line %d, change of Y direction",
+                         nLineNum);
                     VSIFCloseL(fp);
                     return NULL;
-                }*/
-                dfStepY = dfNewStepY;
-            }
-            //else if (dfNewStepX != 0)
-            //{
-                /*if (dfStepX != 0 && fabs(dfNewStepX - dfStepX) > 1e-8)
+                }
+                if( bNewStepYSign < 0 ) dfStepY = -dfStepY;
+                if( adfStepY.size() == 0 )
+                    adfStepY.push_back(dfStepY);
+                else if( adfStepY[0] != dfStepY )
                 {
                     CPLError(CE_Failure, CPLE_AppDefined,
-                             "At line %d, X spacing was %f, whereas it was %f before",
-                             nLineNum, dfNewStepX, dfStepX);
+                        "Ungridded dataset: At line %d, too many stepY values", nLineNum);
                     VSIFCloseL(fp);
                     return NULL;
-                }*/
-            //}
-        }
+                }
+            }
 
-        if (nDataLineNum == 1)
-        {
-            dfMinX = dfMaxX = dfX;
-            dfMinY = dfMaxY = dfY;
-        }
-        else
-        {
-            if (dfStepY == 0 && dfX < dfMinX) dfMinX = dfX;
-            if (dfStepY == 0 && dfX > dfMaxX) dfMaxX = dfX;
+            if (dfX < dfMinX) dfMinX = dfX;
+            if (dfX > dfMaxX) dfMaxX = dfX;
             if (dfY < dfMinY) dfMinY = dfY;
             if (dfY > dfMaxY) dfMaxY = dfY;
         }
@@ -935,38 +919,32 @@ GDALDataset *XYZDataset::Open( GDALOpenInfo * poOpenInfo )
         dfLastX = dfX;
         dfLastY = dfY;
     }
-    nYSize ++;
 
-    if (dfStepX == 0)
+    if (adfStepX.size() != 1)
     {
         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine X spacing");
         VSIFCloseL(fp);
         return NULL;
     }
 
-    if (dfStepY == 0)
+    if (adfStepY.size() != 1)
     {
         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't determine Y spacing");
         VSIFCloseL(fp);
         return NULL;
     }
 
-    double dfAdjustedStepY = ((dfStepY < 0) ? -1 : 1) * (dfMaxY - dfMinY) / (nYSize - 1);
-    if (fabs(dfStepY - dfAdjustedStepY) > 1e-8)
-    {
-        CPLDebug("XYZ", "Adjusting stepy from %f to %f", dfStepY, dfAdjustedStepY);
-    }
-    dfStepY = dfAdjustedStepY;
+    double dfStepX = adfStepX[0];
+    double dfStepY = adfStepY[0] * bStepYSign;
+    int nXSize = 1 + int((dfMaxX - dfMinX) / dfStepX + 0.5);
+    int nYSize = 1 + int((dfMaxY - dfMinY) / fabs(dfStepY) + 0.5);
 
     //CPLDebug("XYZ", "minx=%f maxx=%f stepx=%f", dfMinX, dfMaxX, dfStepX);
     //CPLDebug("XYZ", "miny=%f maxy=%f stepy=%f", dfMinY, dfMaxY, dfStepY);
 
-    if (bSameNumberOfValuesPerLine && nDataLineNum != nXSize * nYSize)
+    if (nDataLineNum != nXSize * nYSize)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Found %d lines. Expected %d",
-                 nDataLineNum,nXSize * nYSize);
-        VSIFCloseL(fp);
-        return NULL;
+        bSameNumberOfValuesPerLine = FALSE;
     }
     
     if (poOpenInfo->eAccess == GA_Update)
@@ -1131,7 +1109,7 @@ GDALDataset* XYZDataset::CreateCopy( const char * pszFilename,
         eErr = poSrcDS->GetRasterBand(1)->RasterIO(
                                             GF_Read, 0, j, nXSize, 1,
                                             pLineBuffer, nXSize, 1,
-                                            eReqDT, 0, 0);
+                                            eReqDT, 0, 0, NULL);
         if (eErr != CE_None)
             break;
         double dfY = adfGeoTransform[3] + (j + 0.5) * adfGeoTransform[5];
@@ -1141,9 +1119,9 @@ GDALDataset* XYZDataset::CreateCopy( const char * pszFilename,
             char szBuf[256];
             double dfX = adfGeoTransform[0] + (i + 0.5) * adfGeoTransform[1];
             if (eReqDT == GDT_Int32)
-                sprintf(szBuf, "%.18g%c%.18g%c%d\n", dfX, pszColSep[0], dfY, pszColSep[0], ((int*)pLineBuffer)[i]);
+                CPLsprintf(szBuf, "%.18g%c%.18g%c%d\n", dfX, pszColSep[0], dfY, pszColSep[0], ((int*)pLineBuffer)[i]);
             else
-                sprintf(szBuf, "%.18g%c%.18g%c%.18g\n", dfX, pszColSep[0], dfY, pszColSep[0], ((float*)pLineBuffer)[i]);
+                CPLsprintf(szBuf, "%.18g%c%.18g%c%.18g\n", dfX, pszColSep[0], dfY, pszColSep[0], ((float*)pLineBuffer)[i]);
             osBuf += szBuf;
             if( (i & 1023) == 0 || i == nXSize - 1 )
             {
@@ -1221,6 +1199,7 @@ void GDALRegister_XYZ()
         poDriver = new GDALDriver();
         
         poDriver->SetDescription( "XYZ" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "ASCII Gridded XYZ" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
diff --git a/frmts/zlib/deflate.h b/frmts/zlib/deflate.h
index e16b2da..180cc50 100644
--- a/frmts/zlib/deflate.h
+++ b/frmts/zlib/deflate.h
@@ -8,7 +8,7 @@
    subject to change. Applications should only use zlib.h.
  */
 
-/* @(#) $Id: deflate.h 10656 2007-01-19 01:31:01Z mloskot $ */
+/* @(#) $Id: deflate.h 28039 2014-11-30 18:24:59Z rouault $ */
 
 #ifndef DEFLATE_H
 #define DEFLATE_H
@@ -188,7 +188,7 @@ typedef struct internal_state {
     int nice_match; /* Stop searching when current match exceeds this */
 
                 /* used by trees.c: */
-    /* Didn't use ct_data typedef below to supress compiler warning */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
     struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
     struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
     struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
diff --git a/frmts/zmap/GNUmakefile b/frmts/zmap/GNUmakefile
index b45a92f..f94d954 100644
--- a/frmts/zmap/GNUmakefile
+++ b/frmts/zmap/GNUmakefile
@@ -3,7 +3,7 @@ OBJ	=	zmapdataset.o
 
 include ../../GDALmake.opt
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS)
+
 
 default:	$(OBJ:.o=.$(OBJ_EXT))
 
diff --git a/frmts/zmap/zmapdataset.cpp b/frmts/zmap/zmapdataset.cpp
index e6c9d5b..7f6cf45 100644
--- a/frmts/zmap/zmapdataset.cpp
+++ b/frmts/zmap/zmapdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: zmapdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: zmapdataset.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  ZMap driver
  * Purpose:  GDALDataset driver for ZMap dataset.
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include "gdal_pam.h"
 
-CPL_CVSID("$Id: zmapdataset.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: zmapdataset.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 CPL_C_START
 void    GDALRegister_ZMap(void);
@@ -111,9 +111,9 @@ ZMapRasterBand::ZMapRasterBand( ZMapDataset *poDS )
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr ZMapRasterBand::IReadBlock( int nBlockXOff, CPL_UNUSED int nBlockYOff,
-                                  void * pImage )
-
+CPLErr ZMapRasterBand::IReadBlock( int nBlockXOff,
+                                   CPL_UNUSED int nBlockYOff,
+                                   void * pImage )
 {
     int i;
     ZMapDataset *poGDS = (ZMapDataset *) poDS;
@@ -519,10 +519,11 @@ static void WriteRightJustified(VSILFILE* fp, double dfValue, int nWidth,
 /************************************************************************/
 
 GDALDataset* ZMapDataset::CreateCopy( const char * pszFilename,
-                                     GDALDataset *poSrcDS,
-                                     int bStrict, CPL_UNUSED char ** papszOptions,
-                                     GDALProgressFunc pfnProgress,
-                                     void * pProgressData )
+                                      GDALDataset *poSrcDS,
+                                      int bStrict,
+                                      CPL_UNUSED char ** papszOptions,
+                                      GDALProgressFunc pfnProgress,
+                                      void * pProgressData )
 {
 /* -------------------------------------------------------------------- */
 /*      Some some rudimentary checks                                    */
@@ -648,7 +649,7 @@ GDALDataset* ZMapDataset::CreateCopy( const char * pszFilename,
         eErr = poSrcDS->GetRasterBand(1)->RasterIO(
                                             GF_Read, i, 0, 1, nYSize,
                                             padfLineBuffer, 1, nYSize,
-                                            GDT_Float64, 0, 0);
+                                            GDT_Float64, 0, 0, NULL);
         if (eErr != CE_None)
             break;
         int bEOLPrinted = FALSE;
@@ -707,6 +708,7 @@ void GDALRegister_ZMap()
         poDriver = new GDALDriver();
 
         poDriver->SetDescription( "ZMap" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
                                    "ZMap Plus Grid" );
         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
@@ -722,4 +724,3 @@ void GDALRegister_ZMap()
         GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/gcore/GNUmakefile b/gcore/GNUmakefile
index c831914..c9ef0fa 100644
--- a/gcore/GNUmakefile
+++ b/gcore/GNUmakefile
@@ -7,11 +7,12 @@ OBJ	=	gdalopeninfo.o gdaldrivermanager.o gdaldriver.o gdaldataset.o \
 		gdaldefaultoverviews.o gdalpamdataset.o gdalpamrasterband.o \
 		gdaljp2metadata.o gdaljp2box.o gdalmultidomainmetadata.o \
 		gdal_rat.o gdalgmlcoverage.o gdalpamproxydb.o \
-		gdalallvalidmaskband.o gdalnodatamaskband.o gdal_rpcimdio.o \
+                gdalallvalidmaskband.o gdalnodatamaskband.o \
  		gdalproxydataset.o gdalproxypool.o gdaldefaultasync.o \
 		gdalnodatavaluesmaskband.o gdaldllmain.o gdalexif.o gdalclientserver.o \
 		gdalgeorefpamdataset.o gdaljp2abstractdataset.o gdalvirtualmem.o \
-		gdalrescaledalphaband.o
+		gdaloverviewdataset.o gdalrescaledalphaband.o gdaljp2structure.o \
+		gdal_mdreader.o gdaljp2metadatagenerator.o
 
 # Enable the following if you want to use MITAB's code to convert
 # .tab coordinate systems into well known text.  But beware that linking
@@ -24,13 +25,21 @@ XTRA_OPT 	:=	$(XTRA_OPT) -DRENAME_INTERNAL_LIBTIFF_SYMBOLS
 endif
 endif
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(CPPFLAGS) $(PAM_SETTING) $(XTRA_OPT) -I../frmts/gtiff
+CPPFLAGS	:=	 -I../frmts/gtiff -I../frmts/mem -I../frmts/vrt -I../ogr -I../ogr/ogrsf_frmts/generic $(JSON_INCLUDE) $(CPPFLAGS) $(PAM_SETTING) $(XTRA_OPT)
 
-default:	$(OBJ:.o=.$(OBJ_EXT))
+ifeq ($(HAVE_SQLITE),yes)
+CXXFLAGS :=	$(CXXFLAGS) -DSQLITE_ENABLED
+endif
+
+ifeq ($(HAVE_LIBXML2),yes)
+CXXFLAGS	:=	$(CXXFLAGS) $(LIBXML2_INC) -DHAVE_LIBXML2
+endif
+
+default: mdreader-target $(OBJ:.o=.$(OBJ_EXT))
 
 $(OBJ):	gdal_priv.h gdal_proxy.h
 
-clean:
+clean: mdreader-clean
 	$(RM) *.o $(O_OBJ)
 
 docs:	
diff --git a/gcore/gdal.h b/gcore/gdal.h
index 3a55ec0..68eb13f 100644
--- a/gcore/gdal.h
+++ b/gcore/gdal.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal.h 29123 2015-05-03 11:05:46Z bishop $
  *
  * Project:  GDAL Core
  * Purpose:  GDAL Core C/Public declarations.
@@ -43,6 +43,8 @@
 #include "cpl_error.h"
 #include "cpl_progress.h"
 #include "cpl_virtualmem.h"
+#include "cpl_minixml.h"
+#include "ogr_api.h"
 #endif
 
 /* -------------------------------------------------------------------- */
@@ -101,6 +103,69 @@ typedef enum {
     /*! Write data */  GF_Write = 1
 } GDALRWFlag;
 
+/* NOTE: values are selected to be consistant with GDALResampleAlg of alg/gdalwarper.h */ 
+/** RasterIO() resampling method.
+  * @since GDAL 2.0
+  */
+typedef enum
+{
+    /*! Nearest neighbour */                            GRIORA_NearestNeighbour = 0,
+    /*! Bilinear (2x2 kernel) */                        GRIORA_Bilinear = 1,
+    /*! Cubic Convolution Approximation (4x4 kernel) */ GRIORA_Cubic = 2,
+    /*! Cubic B-Spline Approximation (4x4 kernel) */    GRIORA_CubicSpline = 3,
+    /*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRIORA_Lanczos = 4,
+    /*! Average */                                      GRIORA_Average = 5,
+    /*! Mode (selects the value which appears most often of all the sampled points) */
+                                                        GRIORA_Mode = 6,
+    /*! Gauss blurring */                               GRIORA_Gauss = 7
+    /* NOTE: values 8 to 12 are reserved for max,min,med,Q1,Q3 */
+} GDALRIOResampleAlg;
+
+/* NOTE to developers: only add members, and if so edit INIT_RASTERIO_EXTRA_ARG */
+/* and INIT_RASTERIO_EXTRA_ARG */
+/** Structure to pass extra arguments to RasterIO() method
+  * @since GDAL 2.0
+  */
+typedef struct
+{
+    /*! Version of structure (to allow future extensions of the structure) */ 
+    int                    nVersion;
+
+    /*! Resampling algorithm */ 
+    GDALRIOResampleAlg     eResampleAlg;
+
+    /*! Progress callback */ 
+    GDALProgressFunc       pfnProgress;
+    /*! Progress callback user data */ 
+    void                  *pProgressData;
+
+    /*! Indicate if dfXOff, dfYOff, dfXSize and dfYSize are set.
+        Mostly reserved from the VRT driver to communicate a more precise
+        source window. Must be such that dfXOff - nXOff < 1.0 and
+        dfYOff - nYOff < 1.0 and nXSize - dfXSize < 1.0 and nYSize - dfYSize < 1.0 */
+    int                    bFloatingPointWindowValidity;
+    /*! Pixel offset to the top left corner. Only valid if bFloatingPointWindowValidity = TRUE */
+    double                 dfXOff;
+    /*! Line offset to the top left corner. Only valid if bFloatingPointWindowValidity = TRUE */
+    double                 dfYOff;
+    /*! Width in pixels of the area of interest. Only valid if bFloatingPointWindowValidity = TRUE */
+    double                 dfXSize;
+    /*! Height in pixels of the area of interest. Only valid if bFloatingPointWindowValidity = TRUE */
+    double                 dfYSize;
+} GDALRasterIOExtraArg;
+
+#define RASTERIO_EXTRA_ARG_CURRENT_VERSION  1
+
+/** Macro to initialize an instance of GDALRasterIOExtraArg structure.
+  * @since GDAL 2.0
+  */
+#define INIT_RASTERIO_EXTRA_ARG(s)  \
+    do { (s).nVersion = RASTERIO_EXTRA_ARG_CURRENT_VERSION; \
+         (s).eResampleAlg = GRIORA_NearestNeighbour; \
+         (s).pfnProgress = NULL; \
+         (s).pProgressData = NULL; \
+         (s).bFloatingPointWindowValidity = FALSE; } while(0)
+
 /*! Types of color interpretation for raster bands. */
 typedef enum
 {
@@ -167,11 +232,6 @@ typedef void *GDALRasterBandH;
 /** Opaque type used for the C bindings of the C++ GDALDriver class */
 typedef void *GDALDriverH;
 
-#ifndef DOXYGEN_SKIP
-/* Deprecated / unused */
-typedef void *GDALProjDefH;
-#endif
-
 /** Opaque type used for the C bindings of the C++ GDALColorTable class */
 typedef void *GDALColorTableH;
 
@@ -181,33 +241,92 @@ typedef void *GDALRasterAttributeTableH;
 /** Opaque type used for the C bindings of the C++ GDALAsyncReader class */
 typedef void *GDALAsyncReaderH;
 
+/** Type to express pixel, line or band spacing. Signed 64 bit integer. */
+typedef GIntBig GSpacing;
+
 /* ==================================================================== */
 /*      Registration/driver related.                                    */
 /* ==================================================================== */
 
-#ifndef DOXYGEN_SKIP
-/* Deprecated / unused */
-typedef struct {
-    char      *pszOptionName;
-    char      *pszValueType;   /* "boolean", "int", "float", "string", 
-                                  "string-select" */
-    char      *pszDescription;
-    char      **papszOptions;
-} GDALOptionDefinition;
-#endif
-
+/** Long name of the driver */
 #define GDAL_DMD_LONGNAME "DMD_LONGNAME"
+
+/** URL (relative to http://gdal.org/) to the help page of the driver */
 #define GDAL_DMD_HELPTOPIC "DMD_HELPTOPIC"
+
+/** MIME type handled by the driver. */
 #define GDAL_DMD_MIMETYPE "DMD_MIMETYPE"
+
+/** Extension handled by the driver. */
 #define GDAL_DMD_EXTENSION "DMD_EXTENSION"
-#define GDAL_DMD_CREATIONOPTIONLIST "DMD_CREATIONOPTIONLIST" 
-#define GDAL_DMD_CREATIONDATATYPES "DMD_CREATIONDATATYPES" 
+
+/** Connection prefix to provide as the file name of the the open function.
+ * Typically set for non-file based drivers. Generally used with open options.
+ * @since GDAL 2.0
+ */
+#define GDAL_DMD_CONNECTION_PREFIX "DMD_CONNECTION_PREFIX"
+
+/** List of (space separated) extensions handled by the driver.
+ * @since GDAL 2.0
+ */
+#define GDAL_DMD_EXTENSIONS "DMD_EXTENSIONS"
+
+/** XML snippet with creation options. */
+#define GDAL_DMD_CREATIONOPTIONLIST "DMD_CREATIONOPTIONLIST"
+
+/** XML snippet with open options.
+ * @since GDAL 2.0
+ */
+#define GDAL_DMD_OPENOPTIONLIST "DMD_OPENOPTIONLIST" 
+
+/** List of (space separated) raster data types support by the Create()/CreateCopy() API. */
+#define GDAL_DMD_CREATIONDATATYPES "DMD_CREATIONDATATYPES"
+
+/** List of (space separated) vector field types support by the CreateField() API.
+ * @since GDAL 2.0
+ * */
+#define GDAL_DMD_CREATIONFIELDDATATYPES "DMD_CREATIONFIELDDATATYPES"
+
+/** Capability set by a driver that exposes Subdatasets. */
 #define GDAL_DMD_SUBDATASETS "DMD_SUBDATASETS" 
 
+/** Capability set by a driver that implements the Open() API. */
+#define GDAL_DCAP_OPEN       "DCAP_OPEN"
+
+/** Capability set by a driver that implements the Create() API. */
 #define GDAL_DCAP_CREATE     "DCAP_CREATE"
+
+/** Capability set by a driver that implements the CreateCopy() API. */
 #define GDAL_DCAP_CREATECOPY "DCAP_CREATECOPY"
+
+/** Capability set by a driver that can read/create datasets through the VSI*L API. */
 #define GDAL_DCAP_VIRTUALIO  "DCAP_VIRTUALIO"
 
+/** Capability set by a driver having raster capability.
+ * @since GDAL 2.0
+ */
+#define GDAL_DCAP_RASTER     "DCAP_RASTER"
+
+/** Capability set by a driver having vector capability.
+ * @since GDAL 2.0
+ */
+#define GDAL_DCAP_VECTOR     "DCAP_VECTOR"
+
+/** Capability set by a driver that can create fields with NOT NULL constraint. 
+ * @since GDAL 2.0
+ */
+#define GDAL_DCAP_NOTNULL_FIELDS "DCAP_NOTNULL_FIELDS" 
+
+/** Capability set by a driver that can create fields with DEFAULT values. 
+ * @since GDAL 2.0
+ */
+#define GDAL_DCAP_DEFAULT_FIELDS "DCAP_DEFAULT_FIELDS" 
+
+/** Capability set by a driver that can create geometry fields with NOT NULL constraint.
+ * @since GDAL 2.0
+ */
+#define GDAL_DCAP_NOTNULL_GEOMFIELDS "DCAP_NOTNULL_GEOMFIELDS" 
+
 void CPL_DLL CPL_STDCALL GDALAllRegister( void );
 
 GDALDatasetH CPL_DLL CPL_STDCALL GDALCreate( GDALDriverH hDriver,
@@ -222,6 +341,73 @@ GDALDriverH CPL_DLL CPL_STDCALL GDALIdentifyDriver( const char * pszFilename,
 GDALDatasetH CPL_DLL CPL_STDCALL
 GDALOpen( const char *pszFilename, GDALAccess eAccess ) CPL_WARN_UNUSED_RESULT;
 GDALDatasetH CPL_DLL CPL_STDCALL GDALOpenShared( const char *, GDALAccess ) CPL_WARN_UNUSED_RESULT;
+
+
+/* Note: we define GDAL_OF_READONLY and GDAL_OF_UPDATE to be on purpose */
+/* equals to GA_ReadOnly and GA_Update */
+
+/** Open in read-only mode.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_READONLY        0x00
+
+/** Open in update mode.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_UPDATE          0x01
+
+/** Allow raster and vector drivers to be used.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_ALL             0x00
+
+/** Allow raster drivers to be used.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_RASTER          0x02
+
+/** Allow vector drivers to be used.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_VECTOR          0x04
+/* Some space for GDAL 3.0 new types ;-) */
+/*#define     GDAL_OF_OTHER_KIND1   0x08 */
+/*#define     GDAL_OF_OTHER_KIND2   0x10 */
+#ifndef DOXYGEN_SKIP
+#define     GDAL_OF_KIND_MASK       0x1E
+#endif
+
+/** Open in shared mode.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_SHARED          0x20
+
+/** Emit error message in case of failed open.
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_VERBOSE_ERROR   0x40
+
+/** Open as internal dataset. Such dataset isn't registered in the global list
+ * of opened dataset. Cannot be used with GDAL_OF_SHARED.
+ *
+ * Used by GDALOpenEx().
+ * @since GDAL 2.0
+ */
+#define     GDAL_OF_INTERNAL        0x80
+
+GDALDatasetH CPL_DLL CPL_STDCALL GDALOpenEx( const char* pszFilename,
+                                             unsigned int nOpenFlags,
+                                             const char* const* papszAllowedDrivers,
+                                             const char* const* papszOpenOptions,
+                                             const char* const* papszSiblingFiles ) CPL_WARN_UNUSED_RESULT;
+
 int          CPL_DLL CPL_STDCALL GDALDumpOpenDatasets( FILE * );
 
 GDALDriverH CPL_DLL CPL_STDCALL GDALGetDriverByName( const char * );
@@ -231,6 +417,7 @@ void        CPL_DLL CPL_STDCALL GDALDestroyDriver( GDALDriverH );
 int         CPL_DLL CPL_STDCALL GDALRegisterDriver( GDALDriverH );
 void        CPL_DLL CPL_STDCALL GDALDeregisterDriver( GDALDriverH );
 void        CPL_DLL CPL_STDCALL GDALDestroyDriverManager( void );
+void        CPL_DLL             GDALDestroy( void );
 CPLErr      CPL_DLL CPL_STDCALL GDALDeleteDataset( GDALDriverH, const char * );
 CPLErr      CPL_DLL CPL_STDCALL GDALRenameDataset( GDALDriverH, 
                                                    const char * pszNewName,
@@ -311,6 +498,8 @@ void CPL_DLL CPL_STDCALL GDALSetDescription( GDALMajorObjectH, const char * );
 /*      GDALDataset class ... normally this represents one file.        */
 /* ==================================================================== */
 
+#define GDAL_DS_LAYER_CREATIONOPTIONLIST "DS_LAYER_CREATIONOPTIONLIST" 
+
 GDALDriverH CPL_DLL CPL_STDCALL GDALGetDatasetDriver( GDALDatasetH );
 char CPL_DLL ** CPL_STDCALL GDALGetFileList( GDALDatasetH );
 void CPL_DLL CPL_STDCALL   GDALClose( GDALDatasetH );
@@ -340,6 +529,14 @@ CPLErr CPL_DLL CPL_STDCALL GDALDatasetRasterIO(
     int nBandCount, int *panBandCount, 
     int nPixelSpace, int nLineSpace, int nBandSpace);
 
+CPLErr CPL_DLL CPL_STDCALL GDALDatasetRasterIOEx( 
+    GDALDatasetH hDS, GDALRWFlag eRWFlag,
+    int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize,
+    void * pBuffer, int nBXSize, int nBYSize, GDALDataType eBDataType,
+    int nBandCount, int *panBandCount, 
+    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+    GDALRasterIOExtraArg* psExtraArg);
+
 CPLErr CPL_DLL CPL_STDCALL GDALDatasetAdviseRead( GDALDatasetH hDS, 
     int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize,
     int nBXSize, int nBYSize, GDALDataType eBDataType,
@@ -384,6 +581,27 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
                          const char *pszResampling, 
                          GDALProgressFunc pfnProgress, void *pProgressData );
 
+int    CPL_DLL GDALDatasetGetLayerCount( GDALDatasetH );
+OGRLayerH CPL_DLL GDALDatasetGetLayer( GDALDatasetH, int );
+OGRLayerH CPL_DLL GDALDatasetGetLayerByName( GDALDatasetH, const char * );
+OGRErr    CPL_DLL GDALDatasetDeleteLayer( GDALDatasetH, int );
+OGRLayerH CPL_DLL GDALDatasetCreateLayer( GDALDatasetH, const char *, 
+                                      OGRSpatialReferenceH, OGRwkbGeometryType,
+                                      char ** );
+OGRLayerH CPL_DLL GDALDatasetCopyLayer( GDALDatasetH, OGRLayerH, const char *,
+                                        char ** );
+int    CPL_DLL GDALDatasetTestCapability( GDALDatasetH, const char * );
+OGRLayerH CPL_DLL GDALDatasetExecuteSQL( GDALDatasetH, const char *,
+                                     OGRGeometryH, const char * );
+void   CPL_DLL GDALDatasetReleaseResultSet( GDALDatasetH, OGRLayerH );
+OGRStyleTableH CPL_DLL GDALDatasetGetStyleTable( GDALDatasetH );
+void   CPL_DLL GDALDatasetSetStyleTableDirectly( GDALDatasetH, OGRStyleTableH );
+void   CPL_DLL GDALDatasetSetStyleTable( GDALDatasetH, OGRStyleTableH );
+OGRErr CPL_DLL GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce);
+OGRErr CPL_DLL GDALDatasetCommitTransaction(GDALDatasetH hDS);
+OGRErr CPL_DLL GDALDatasetRollbackTransaction(GDALDatasetH hDS);
+
+
 /* ==================================================================== */
 /*      GDALRasterBand ... one band/channel in a dataset.               */
 /* ==================================================================== */
@@ -435,6 +653,12 @@ GDALRasterIO( GDALRasterBandH hRBand, GDALRWFlag eRWFlag,
               int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize,
               void * pBuffer, int nBXSize, int nBYSize,GDALDataType eBDataType,
               int nPixelSpace, int nLineSpace );
+CPLErr CPL_DLL CPL_STDCALL 
+GDALRasterIOEx( GDALRasterBandH hRBand, GDALRWFlag eRWFlag,
+              int nDSXOff, int nDSYOff, int nDSXSize, int nDSYSize,
+              void * pBuffer, int nBXSize, int nBYSize,GDALDataType eBDataType,
+              GSpacing nPixelSpace, GSpacing nLineSpace,
+              GDALRasterIOExtraArg* psExtraArg );
 CPLErr CPL_DLL CPL_STDCALL GDALReadBlock( GDALRasterBandH, int, int, void * );
 CPLErr CPL_DLL CPL_STDCALL GDALWriteBlock( GDALRasterBandH, int, int, void * );
 int CPL_DLL CPL_STDCALL GDALGetRasterBandXSize( GDALRasterBandH );
@@ -484,20 +708,37 @@ CPLErr CPL_DLL CPL_STDCALL GDALGetRasterHistogram( GDALRasterBandH hBand,
                                        int nBuckets, int *panHistogram,
                                        int bIncludeOutOfRange, int bApproxOK,
                                        GDALProgressFunc pfnProgress,
+                                       void * pProgressData ) CPL_WARN_DEPRECATED("Use GDALGetRasterHistogramEx() instead");
+CPLErr CPL_DLL CPL_STDCALL GDALGetRasterHistogramEx( GDALRasterBandH hBand,
+                                       double dfMin, double dfMax,
+                                       int nBuckets, GUIntBig *panHistogram,
+                                       int bIncludeOutOfRange, int bApproxOK,
+                                       GDALProgressFunc pfnProgress,
                                        void * pProgressData );
 CPLErr CPL_DLL CPL_STDCALL GDALGetDefaultHistogram( GDALRasterBandH hBand,
                                        double *pdfMin, double *pdfMax,
                                        int *pnBuckets, int **ppanHistogram,
                                        int bForce,
                                        GDALProgressFunc pfnProgress,
+                                       void * pProgressData ) CPL_WARN_DEPRECATED("Use GDALGetDefaultHistogramEx() instead");
+CPLErr CPL_DLL CPL_STDCALL GDALGetDefaultHistogramEx( GDALRasterBandH hBand,
+                                       double *pdfMin, double *pdfMax,
+                                       int *pnBuckets, GUIntBig **ppanHistogram,
+                                       int bForce,
+                                       GDALProgressFunc pfnProgress,
                                        void * pProgressData );
 CPLErr CPL_DLL CPL_STDCALL GDALSetDefaultHistogram( GDALRasterBandH hBand,
                                        double dfMin, double dfMax,
-                                       int nBuckets, int *panHistogram );
+                                       int nBuckets, int *panHistogram ) CPL_WARN_DEPRECATED("Use GDALSetDefaultHistogramEx() instead");
+CPLErr CPL_DLL CPL_STDCALL GDALSetDefaultHistogramEx( GDALRasterBandH hBand,
+                                       double dfMin, double dfMax,
+                                       int nBuckets, GUIntBig *panHistogram );
 int CPL_DLL CPL_STDCALL
 GDALGetRandomRasterSample( GDALRasterBandH, int, float * );
 GDALRasterBandH CPL_DLL CPL_STDCALL
 GDALGetRasterSampleOverview( GDALRasterBandH, int );
+GDALRasterBandH CPL_DLL CPL_STDCALL
+GDALGetRasterSampleOverviewEx( GDALRasterBandH, GUIntBig );
 CPLErr CPL_DLL CPL_STDCALL GDALFillRaster( GDALRasterBandH hBand,
                           double dfRealValue, double dfImaginaryValue );
 CPLErr CPL_DLL CPL_STDCALL
@@ -570,16 +811,6 @@ int CPL_DLL CPL_STDCALL GDALLoadOziMapFile( const char *, double *, char **,
                                             int *, GDAL_GCP ** );
 int CPL_DLL CPL_STDCALL GDALReadOziMapFile( const char * ,  double *,
                                             char **, int *, GDAL_GCP ** );
-char CPL_DLL ** CPL_STDCALL GDALLoadRPBFile( const char *pszFilename, 
-                                             char **papszSiblingFiles );
-char CPL_DLL ** CPL_STDCALL GDALLoadRPCFile( const char *pszFilename, 
-                                             char **papszSiblingFiles );
-CPLErr CPL_DLL CPL_STDCALL GDALWriteRPBFile( const char *pszFilename, 
-                                             char **papszMD );
-char CPL_DLL ** CPL_STDCALL GDALLoadIMDFile( const char *pszFilename, 
-                                             char **papszSiblingFiles );
-CPLErr CPL_DLL CPL_STDCALL GDALWriteIMDFile( const char *pszFilename, 
-                                             char **papszMD );
 
 const char CPL_DLL * CPL_STDCALL GDALDecToDMS( double, const char *, int );
 double CPL_DLL CPL_STDCALL GDALPackedDMSToDec( double );
@@ -844,6 +1075,12 @@ CPLVirtualMem CPL_DLL* GDALRasterBandGetTiledVirtualMem( GDALRasterBandH hBand,
                                                          int bSingleThreadUsage,
                                                          char **papszOptions );
 
+/* =================================================================== */
+/*      Misc API                                                        */
+/* ==================================================================== */
+
+CPLXMLNode CPL_DLL* GDALGetJPEG2000Structure(const char* pszFilename,
+                                             char** papszOptions);
 
 CPL_C_END
 
diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h
index 2a3526b..261f241 100644
--- a/gcore/gdal_frmts.h
+++ b/gcore/gdal_frmts.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_frmts.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal_frmts.h 28859 2015-04-07 08:40:10Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Prototypes for all format specific driver initializations.
@@ -120,6 +120,7 @@ void CPL_DLL GDALRegister_DIPEx(void);
 void CPL_DLL GDALRegister_ISIS3(void);
 void CPL_DLL GDALRegister_ISIS2(void);
 void CPL_DLL GDALRegister_PDS(void);
+void CPL_DLL GDALRegister_VICAR(void);
 void CPL_DLL GDALRegister_IDRISI(void);
 void CPL_DLL GDALRegister_Terragen(void);
 void CPL_DLL GDALRegister_WCS(void);
@@ -178,6 +179,9 @@ void CPL_DLL GDALRegister_MBTiles(void);
 void CPL_DLL GDALRegister_ARG(void);
 void CPL_DLL GDALRegister_IRIS(void);
 void CPL_DLL GDALRegister_KRO(void);
+void CPL_DLL GDALRegister_KEA(void);
+void CPL_DLL GDALRegister_ROIPAC(void);
+void CPL_DLL GDALRegister_PLMOSAIC(void);
 CPL_C_END
 
 #endif /* ndef GDAL_FRMTS_H_INCLUDED */
diff --git a/gcore/gdal_mdreader.cpp b/gcore/gdal_mdreader.cpp
new file mode 100644
index 0000000..8e4f143
--- /dev/null
+++ b/gcore/gdal_mdreader.cpp
@@ -0,0 +1,1072 @@
+/******************************************************************************
+ * $Id: gdal_mdreader.cpp 29143 2015-05-03 20:49:53Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata (mainly the remote sensing imagery) from files of 
+ *           different providers like DigitalGlobe, GeoEye etc.
+ * Author:   Frank Warmerdam, warmerdam at pobox.com
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) HER MAJESTY THE QUEEN IN RIGHT OF CANADA (2008)
+ * as represented by the Canadian Nuclear Safety Commission
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#include "gdal_mdreader.h"
+#include "cpl_string.h"
+#include "cplkeywordparser.h"
+
+//readers
+#include "mdreader/reader_digital_globe.h"
+#include "mdreader/reader_geo_eye.h"
+#include "mdreader/reader_orb_view.h"
+#include "mdreader/reader_pleiades.h"
+#include "mdreader/reader_rdk1.h"
+#include "mdreader/reader_landsat.h"
+
+CPL_CVSID("$Id: gdal_mdreader.cpp 29143 2015-05-03 20:49:53Z rouault $");
+
+/**
+ * The RPC parameters names
+ */
+
+static const char *apszRPCTXTSingleValItems[] =
+{
+    RPC_LINE_OFF,
+    RPC_SAMP_OFF,
+    RPC_LAT_OFF,
+    RPC_LONG_OFF,
+    RPC_HEIGHT_OFF,
+    RPC_LINE_SCALE,
+    RPC_SAMP_SCALE,
+    RPC_LAT_SCALE,
+    RPC_LONG_SCALE,
+    RPC_HEIGHT_SCALE,
+    NULL
+};
+
+static const char *apszRPCTXT20ValItems[] =
+{
+    RPC_LINE_NUM_COEFF,
+    RPC_LINE_DEN_COEFF,
+    RPC_SAMP_NUM_COEFF,
+    RPC_SAMP_DEN_COEFF,
+    NULL
+};
+
+/**
+ * GDALMDReaderManager()
+ */  
+GDALMDReaderManager::GDALMDReaderManager()
+{
+    m_pReader = NULL;
+}
+
+/**
+ * ~GDALMDReaderManager()
+ */
+GDALMDReaderManager::~GDALMDReaderManager()
+{
+   if(NULL != m_pReader)
+   {
+       delete m_pReader;
+   }
+}
+
+/**
+ * GetReader()
+ */
+
+#define INIT_READER(reader) \
+    GDALMDReaderBase* pReaderBase = new reader(pszPath, papszSiblingFiles); \
+    if(pReaderBase->HasRequiredFiles()) { m_pReader = pReaderBase; \
+    return m_pReader; } \
+    delete pReaderBase
+
+GDALMDReaderBase* GDALMDReaderManager::GetReader(const char *pszPath,
+                                                 char **papszSiblingFiles,
+                                                 GUInt32 nType)
+{
+    if(nType & MDR_DG)
+    {
+        INIT_READER(GDALMDReaderDigitalGlobe);
+    }
+
+    // required filename.tif filename.pvl filename_rpc.txt
+    if(nType & MDR_OV)
+    {
+        INIT_READER(GDALMDReaderOrbView);
+    }
+
+    // required filename.tif filename_rpc.txt (filename_metadata.txt optional)
+    if(nType & MDR_GE)
+    {
+        INIT_READER(GDALMDReaderGeoEye);
+    }
+
+    if(nType & MDR_PLEIADES)
+    {
+        INIT_READER(GDALMDReaderPleiades);
+    }
+
+    if(nType & MDR_RDK1)
+    {
+        INIT_READER(GDALMDReaderResursDK1);
+    }
+
+    if(nType & MDR_LS)
+    {
+        INIT_READER(GDALMDReaderLandsat);
+    }
+
+    return NULL;
+}
+
+/**
+ * GDALMDReaderBase()
+ */ 
+GDALMDReaderBase::GDALMDReaderBase(CPL_UNUSED const char *pszPath,
+                                   CPL_UNUSED char **papszSiblingFiles)
+{
+    m_bIsMetadataLoad = false;    
+    m_papszIMDMD = NULL;
+    m_papszRPCMD = NULL;
+    m_papszIMAGERYMD = NULL;
+    m_papszDEFAULTMD = NULL;    
+} 
+
+/**
+ * ~GDALMDReaderBase()
+ */
+GDALMDReaderBase::~GDALMDReaderBase()
+{
+    CSLDestroy(m_papszIMDMD);
+    CSLDestroy(m_papszRPCMD);
+    CSLDestroy(m_papszIMAGERYMD);
+    CSLDestroy(m_papszDEFAULTMD);
+} 
+
+/**
+ * GetMetadataItem()
+ */
+char ** GDALMDReaderBase::GetMetadataDomain(const char *pszDomain)
+{
+    LoadMetadata();
+    if(EQUAL(pszDomain, MD_DOMAIN_DEFAULT))
+        return m_papszDEFAULTMD;
+    else if(EQUAL(pszDomain, MD_DOMAIN_IMD))
+        return m_papszIMDMD;    
+    else if(EQUAL(pszDomain, MD_DOMAIN_RPC))
+        return m_papszRPCMD;   
+    else if(EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
+        return m_papszIMAGERYMD;             
+    return NULL;    
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderBase::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+    m_bIsMetadataLoad = true;
+}
+
+/**
+ * GetAcqisitionTimeFromString1()
+ */
+const time_t GDALMDReaderBase::GetAcquisitionTimeFromString(
+        const char* pszDateTime)
+{
+    if(NULL == pszDateTime)
+        return 0;
+
+    int iYear;
+    int iMonth;
+    int iDay;
+    int iHours;
+    int iMin;
+    int iSec;
+
+    int r = sscanf ( pszDateTime, "%d-%d-%dT%d:%d:%d.%*dZ",
+                     &iYear, &iMonth, &iDay, &iHours, &iMin, &iSec);
+
+    if (r != 6)
+        return 0;
+
+    struct tm tmDateTime;
+    tmDateTime.tm_sec = iSec;
+    tmDateTime.tm_min = iMin;
+    tmDateTime.tm_hour = iHours;
+    tmDateTime.tm_mday = iDay;
+    tmDateTime.tm_mon = iMonth - 1;
+    tmDateTime.tm_year = iYear - 1900;
+    tmDateTime.tm_isdst = -1;
+
+    return mktime(&tmDateTime);
+}
+
+/**
+ * FillMetadata()
+ */
+
+#define SETMETADATA(mdmd, md, domain) if(NULL != md) { \
+    char** papszCurrentMd = CSLDuplicate(mdmd->GetMetadata(domain)); \
+    papszCurrentMd = CSLMerge(papszCurrentMd, md); \
+    mdmd->SetMetadata(papszCurrentMd, domain); \
+    CSLDestroy(papszCurrentMd); }
+
+bool GDALMDReaderBase::FillMetadata(GDALMultiDomainMetadata* poMDMD)
+{
+    if(NULL == poMDMD)
+        return false;
+        
+    LoadMetadata();
+
+    SETMETADATA(poMDMD, m_papszIMDMD, MD_DOMAIN_IMD );
+    SETMETADATA(poMDMD, m_papszRPCMD, MD_DOMAIN_RPC );
+    SETMETADATA(poMDMD, m_papszIMAGERYMD, MD_DOMAIN_IMAGERY );
+    SETMETADATA(poMDMD, m_papszDEFAULTMD, MD_DOMAIN_DEFAULT );
+    
+    return true;
+}
+
+/**
+ * AddXMLNameValueToList()
+ */
+char** GDALMDReaderBase::AddXMLNameValueToList(char** papszList,
+                                               const char *pszName,
+                                               const char *pszValue)
+{
+    return CSLAddNameValue(papszList, pszName, pszValue);
+}
+
+/**
+ * CPLReadXMLToList()
+ */
+char** GDALMDReaderBase::ReadXMLToList(CPLXMLNode* psNode, char** papszList,
+                                          const char* pszName)
+{
+    if(NULL == psNode)
+        return papszList;
+
+    if (psNode->eType == CXT_Text)
+    {
+        return AddXMLNameValueToList(papszList, pszName, psNode->pszValue);
+    }
+
+    if (psNode->eType == CXT_Element)
+    {
+
+        int nAddIndex = 0;
+        bool bReset = false;
+        const char* pszLastNodeName = NULL;
+        for(CPLXMLNode* psChildNode = psNode->psChild; NULL != psChildNode;
+            psChildNode = psChildNode->psNext)
+        {
+            if (psChildNode->eType == CXT_Element)
+            {
+                if(bReset)
+                {
+                    bReset = false;
+                    nAddIndex = 0;
+                }
+                // check name duplicates
+                if(NULL != psChildNode->psNext && psChildNode->psNext->eType == CXT_Element)
+                {
+                    if(EQUAL(psChildNode->pszValue, psChildNode->psNext->pszValue))
+                    {
+                        nAddIndex++;
+                        pszLastNodeName = psChildNode->pszValue;
+                    }
+                    else
+                    { // the name changed
+                        pszLastNodeName = NULL;
+                        if(nAddIndex > 0)
+                        {
+                            bReset = true;
+                            nAddIndex++;
+                        }
+                    }
+                }
+                else if( pszLastNodeName && EQUAL(psChildNode->pszValue, pszLastNodeName) )
+                {
+                    nAddIndex++;
+                }
+
+                char szName[512];
+                if(nAddIndex > 0)
+                {
+                    CPLsnprintf( szName, 511, "%s_%d", psChildNode->pszValue,
+                                 nAddIndex);
+                }
+                else
+                {
+                    CPLStrlcpy(szName, psChildNode->pszValue, 511);
+                }
+
+                char szNameNew[512];
+                if(CPLStrnlen( pszName, 511 ) > 0) //if no prefix just set name to node name
+                {
+                    CPLsnprintf( szNameNew, 511, "%s.%s", pszName, szName );
+                }
+                else
+                {
+                    CPLsnprintf( szNameNew, 511, "%s.%s", psNode->pszValue, szName );
+                }
+
+                papszList = ReadXMLToList(psChildNode, papszList, szNameNew);
+            }
+            else if( psChildNode->eType == CXT_Attribute )
+            {
+                papszList = AddXMLNameValueToList(papszList,
+                                                  CPLSPrintf("%s.%s", pszName, psChildNode->pszValue),
+                                                  psChildNode->psChild->pszValue);
+            }
+            else
+            {
+                // Text nodes should always have name
+                if(EQUAL(pszName, ""))
+                {
+                    papszList = ReadXMLToList(psChildNode, papszList, psNode->pszValue);
+                }
+                else
+                {
+                    papszList = ReadXMLToList(psChildNode, papszList, pszName);
+                }
+            }
+        }
+
+        // proceed next only on top level
+
+        if(NULL != psNode->psNext && EQUAL(pszName, ""))
+        {
+             papszList = ReadXMLToList(psNode->psNext, papszList, pszName);
+        }
+    }
+
+    return papszList;
+}
+
+//------------------------------------------------------------------------------
+// Miscellaneous functions
+//------------------------------------------------------------------------------
+
+
+/**
+ * GDALCheckFileHeader()
+ */
+const bool GDALCheckFileHeader(const CPLString& soFilePath,
+                               const char * pszTestString, int nBufferSize)
+{
+    VSILFILE* fpL = VSIFOpenL( soFilePath, "r" );
+    if( fpL == NULL )
+        return false;
+    char *pBuffer = new char[nBufferSize + 1];
+    pBuffer[nBufferSize] = 0;
+    int nReadBytes = (int) VSIFReadL( pBuffer, 1, nBufferSize, fpL );
+    VSIFCloseL(fpL);
+    if(nReadBytes == 0)
+    {
+        delete [] pBuffer;
+        return false;
+    }
+
+    bool bResult = strstr(pBuffer, pszTestString) != NULL;
+    delete [] pBuffer;
+
+    return bResult;
+}
+
+/**
+ * CPLStrip()
+ */
+CPLString CPLStrip(const CPLString& sString, const char cChar)
+{
+    if(sString.empty())
+        return sString;
+
+    size_t dCopyFrom = 0;
+    size_t dCopyCount = sString.size();
+
+    if (sString[0] == cChar)
+    {
+        dCopyFrom++;
+        dCopyCount--;
+    }
+
+    if (sString[sString.size() - 1] == cChar)
+        dCopyCount--;
+
+    if(dCopyCount == 0)
+        return CPLString();
+    
+    return sString.substr(dCopyFrom, dCopyCount);
+}
+
+/**
+ * CPLStripQuotes()
+ */
+CPLString CPLStripQuotes(const CPLString& sString)
+{
+    return CPLStrip( CPLStrip(sString, '"'), '\'');
+}
+
+
+
+
+/************************************************************************/
+/*                          GDALLoadRPBFile()                           */
+/************************************************************************/
+
+static const char *apszRPBMap[] = {
+    apszRPCTXTSingleValItems[0], "IMAGE.lineOffset",
+    apszRPCTXTSingleValItems[1], "IMAGE.sampOffset",
+    apszRPCTXTSingleValItems[2], "IMAGE.latOffset",
+    apszRPCTXTSingleValItems[3], "IMAGE.longOffset",
+    apszRPCTXTSingleValItems[4], "IMAGE.heightOffset",
+    apszRPCTXTSingleValItems[5], "IMAGE.lineScale",
+    apszRPCTXTSingleValItems[6], "IMAGE.sampScale",
+    apszRPCTXTSingleValItems[7], "IMAGE.latScale",
+    apszRPCTXTSingleValItems[8], "IMAGE.longScale",
+    apszRPCTXTSingleValItems[9], "IMAGE.heightScale",
+    apszRPCTXT20ValItems[0], "IMAGE.lineNumCoef",
+    apszRPCTXT20ValItems[1], "IMAGE.lineDenCoef",
+    apszRPCTXT20ValItems[2], "IMAGE.sampNumCoef",
+    apszRPCTXT20ValItems[3], "IMAGE.sampDenCoef",
+    NULL,             NULL };
+
+char **GDALLoadRPBFile( const CPLString& soFilePath )
+{
+    if( soFilePath.empty() )
+        return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    CPLKeywordParser oParser;
+
+    VSILFILE *fp = VSIFOpenL( soFilePath, "r" );
+
+    if( fp == NULL )
+        return NULL;
+
+    if( !oParser.Ingest( fp ) )
+    {
+        VSIFCloseL( fp );
+        return NULL;
+    }
+
+    VSIFCloseL( fp );
+
+/* -------------------------------------------------------------------- */
+/*      Extract RPC information, in a GDAL "standard" metadata format.  */
+/* -------------------------------------------------------------------- */
+    int i;
+    char **papszMD = NULL;
+    for( i = 0; apszRPBMap[i] != NULL; i += 2 )
+    {
+        const char *pszRPBVal = oParser.GetKeyword( apszRPBMap[i+1] );
+        CPLString osAdjVal;
+
+        if( pszRPBVal == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s file found, but missing %s field (and possibly others).",
+                      soFilePath.c_str(), apszRPBMap[i+1] );
+            CSLDestroy( papszMD );
+            return NULL;
+        }
+
+        if( strchr(pszRPBVal,',') == NULL )
+            osAdjVal = pszRPBVal;
+        else
+        {
+            // strip out commas and turn newlines into spaces.
+            int j;
+
+            for( j = 0; pszRPBVal[j] != '\0'; j++ )
+            {
+                switch( pszRPBVal[j] )
+                {
+                  case ',':
+                  case '\n':
+                  case '\r':
+                    osAdjVal += ' ';
+                    break;
+
+                  case '(':
+                  case ')':
+                    break;
+
+                  default:
+                    osAdjVal += pszRPBVal[j];
+                }
+            }
+        }
+
+        papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], osAdjVal );
+    }
+
+    return papszMD;
+}
+
+/************************************************************************/
+/*                          GDALLoadRPCFile()                           */
+/************************************************************************/
+
+/* Load a GeoEye _rpc.txt file. See ticket http://trac.osgeo.org/gdal/ticket/3639 */
+
+char ** GDALLoadRPCFile( const CPLString& soFilePath )
+{
+    if( soFilePath.empty() )
+        return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    char **papszLines = CSLLoad2( soFilePath, 100, 100, NULL );
+    if(!papszLines)
+        return NULL;
+
+    char **papszMD = NULL;
+
+    /* From LINE_OFF to HEIGHT_SCALE */
+    for(size_t i = 0; i < 19; i += 2 )
+    {
+        const char *pszRPBVal = CSLFetchNameValue(papszLines, apszRPBMap[i] );
+        if( pszRPBVal == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                "%s file found, but missing %s field (and possibly others).",
+                soFilePath.c_str(), apszRPBMap[i]);
+            CSLDestroy( papszMD );
+            CSLDestroy( papszLines );
+            return NULL;
+        }
+        else
+        {
+            while( *pszRPBVal == ' ' ) pszRPBVal ++;
+            papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], pszRPBVal );
+        }
+    }
+
+    /* For LINE_NUM_COEFF, LINE_DEN_COEFF, SAMP_NUM_COEFF, SAMP_DEN_COEFF */
+    /* parameters that have 20 values each */
+    for(size_t i = 20; apszRPBMap[i] != NULL; i += 2 )
+    {
+        CPLString soVal;
+        for(int j = 1; j <= 20; j++)
+        {
+            CPLString soRPBMapItem;
+            soRPBMapItem.Printf("%s_%d", apszRPBMap[i], j);
+            const char *pszRPBVal = CSLFetchNameValue(papszLines, soRPBMapItem.c_str() );
+            if( pszRPBVal == NULL )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s file found, but missing %s field (and possibly others).",
+                    soFilePath.c_str(), soRPBMapItem.c_str() );
+                CSLDestroy( papszMD );
+                CSLDestroy( papszLines );
+                return NULL;
+            }
+            else
+            {
+                while( *pszRPBVal == ' ' ) pszRPBVal ++;
+                soVal += pszRPBVal;
+                soVal += " ";
+            }
+        }
+        papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], soVal.c_str() );
+    }
+
+    CSLDestroy( papszLines );
+    return papszMD;
+}
+
+/************************************************************************/
+/*                         GDALWriteRPCTXTFile()                        */
+/************************************************************************/
+
+CPLErr GDALWriteRPCTXTFile( const char *pszFilename, char **papszMD )
+
+{
+    CPLString osRPCFilename = pszFilename;
+    CPLString soPt(".");
+    size_t found = osRPCFilename.rfind(soPt);
+    if (found == CPLString::npos)
+        return CE_Failure;
+    osRPCFilename.replace (found, osRPCFilename.size() - found, "_RPC.TXT");
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    VSILFILE *fp = VSIFOpenL( osRPCFilename, "w" );
+
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Unable to create %s for writing.\n%s",
+                  osRPCFilename.c_str(), CPLGetLastErrorMsg() );
+        return CE_Failure;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write RPC values from our RPC metadata.                         */
+/* -------------------------------------------------------------------- */
+    int i;
+
+    for( i = 0; apszRPCTXTSingleValItems[i] != NULL; i ++ )
+    {
+        const char *pszRPCVal = CSLFetchNameValue( papszMD, apszRPCTXTSingleValItems[i] );
+        if( pszRPCVal == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s field missing in metadata, %s file not written.",
+                      apszRPCTXTSingleValItems[i], osRPCFilename.c_str() );
+            VSIFCloseL( fp );
+            VSIUnlink( osRPCFilename );
+            return CE_Failure;
+        }
+
+        VSIFPrintfL( fp, "%s: %s\n", apszRPCTXTSingleValItems[i], pszRPCVal );
+    }
+
+
+    for( i = 0; apszRPCTXT20ValItems[i] != NULL; i ++ )
+    {
+        const char *pszRPCVal = CSLFetchNameValue( papszMD, apszRPCTXT20ValItems[i] );
+        if( pszRPCVal == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s field missing in metadata, %s file not written.",
+                      apszRPCTXTSingleValItems[i], osRPCFilename.c_str() );
+            VSIFCloseL( fp );
+            VSIUnlink( osRPCFilename );
+            return CE_Failure;
+        }
+
+        char **papszItems = CSLTokenizeStringComplex( pszRPCVal, " ,",
+                                                          FALSE, FALSE );
+
+        if( CSLCount(papszItems) != 20 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s field is corrupt (not 20 values), %s file not written.\n%s = %s",
+                      apszRPCTXT20ValItems[i], osRPCFilename.c_str(),
+                      apszRPCTXT20ValItems[i], pszRPCVal );
+            VSIFCloseL( fp );
+            VSIUnlink( osRPCFilename );
+            CSLDestroy( papszItems );
+            return CE_Failure;
+        }
+
+        int j;
+
+        for( j = 0; j < 20; j++ )
+        {
+            VSIFPrintfL( fp, "%s_%d: %s\n", apszRPCTXT20ValItems[i], j+1,
+                         papszItems[j] );
+        }
+        CSLDestroy( papszItems );
+    }
+
+
+    VSIFCloseL( fp );
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                          GDALWriteRPBFile()                          */
+/************************************************************************/
+
+CPLErr GDALWriteRPBFile( const char *pszFilename, char **papszMD )
+
+{
+    CPLString osRPBFilename = CPLResetExtension( pszFilename, "RPB" );
+
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    VSILFILE *fp = VSIFOpenL( osRPBFilename, "w" );
+
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Unable to create %s for writing.\n%s",
+                  osRPBFilename.c_str(), CPLGetLastErrorMsg() );
+        return CE_Failure;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write the prefix information.                                   */
+/* -------------------------------------------------------------------- */
+    VSIFPrintfL( fp, "%s", "satId = \"QB02\";\n" );
+    VSIFPrintfL( fp, "%s", "bandId = \"P\";\n" );
+    VSIFPrintfL( fp, "%s", "SpecId = \"RPC00B\";\n" );
+    VSIFPrintfL( fp, "%s", "BEGIN_GROUP = IMAGE\n" );
+    VSIFPrintfL( fp, "%s", "\terrBias = 0.0;\n" );
+    VSIFPrintfL( fp, "%s", "\terrRand = 0.0;\n" );
+
+/* -------------------------------------------------------------------- */
+/*      Write RPC values from our RPC metadata.                         */
+/* -------------------------------------------------------------------- */
+    int i;
+
+    for( i = 0; apszRPBMap[i] != NULL; i += 2 )
+    {
+        const char *pszRPBVal = CSLFetchNameValue( papszMD, apszRPBMap[i] );
+        const char *pszRPBTag;
+
+        if( pszRPBVal == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "%s field missing in metadata, %s file not written.",
+                      apszRPBMap[i], osRPBFilename.c_str() );
+            VSIFCloseL( fp );
+            VSIUnlink( osRPBFilename );
+            return CE_Failure;
+        }
+
+        pszRPBTag = apszRPBMap[i+1];
+        if( EQUALN(pszRPBTag,"IMAGE.",6) )
+            pszRPBTag += 6;
+
+        if( strstr(apszRPBMap[i], "COEF" ) == NULL )
+        {
+            VSIFPrintfL( fp, "\t%s = %s;\n", pszRPBTag, pszRPBVal );
+        }
+        else
+        {
+            // Reformat in brackets with commas over multiple lines.
+
+            VSIFPrintfL( fp, "\t%s = (\n", pszRPBTag );
+
+            char **papszItems = CSLTokenizeStringComplex( pszRPBVal, " ,",
+                                                          FALSE, FALSE );
+
+            if( CSLCount(papszItems) != 20 )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                          "%s field is corrupt (not 20 values), %s file not written.\n%s = %s",
+                          apszRPBMap[i], osRPBFilename.c_str(),
+                          apszRPBMap[i], pszRPBVal );
+                VSIFCloseL( fp );
+                VSIUnlink( osRPBFilename );
+                CSLDestroy( papszItems );
+                return CE_Failure;
+            }
+
+            int j;
+
+            for( j = 0; j < 20; j++ )
+            {
+                if( j < 19 )
+                    VSIFPrintfL( fp, "\t\t\t%s,\n", papszItems[j] );
+                else
+                    VSIFPrintfL( fp, "\t\t\t%s);\n", papszItems[j] );
+            }
+            CSLDestroy( papszItems );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Write end part                                                  */
+/* -------------------------------------------------------------------- */
+    VSIFPrintfL( fp, "%s", "END_GROUP = IMAGE\n" );
+    VSIFPrintfL( fp, "END;\n" );
+    VSIFCloseL( fp );
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                           GDAL_IMD_AA2R()                            */
+/*                                                                      */
+/*      Translate AA version IMD file to R version.                     */
+/************************************************************************/
+
+static int GDAL_IMD_AA2R( char ***ppapszIMD )
+
+{
+    char **papszIMD = *ppapszIMD;
+
+/* -------------------------------------------------------------------- */
+/*      Verify that we have a new format file.                          */
+/* -------------------------------------------------------------------- */
+    const char *pszValue = CSLFetchNameValue( papszIMD, "version" );
+
+    if( pszValue == NULL )
+        return FALSE;
+
+    if( EQUAL(pszValue,"\"R\"") )
+        return TRUE;
+
+    if( !EQUAL(pszValue,"\"AA\"") )
+    {
+        CPLDebug( "IMD", "The file is not the expected 'version = \"AA\"' format.\nProceeding, but file may be corrupted." );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Fix the version line.                                           */
+/* -------------------------------------------------------------------- */
+    papszIMD = CSLSetNameValue( papszIMD, "version", "\"R\"" );
+
+/* -------------------------------------------------------------------- */
+/*      remove a bunch of fields.                                       */
+/* -------------------------------------------------------------------- */
+    int iKey;
+
+    static const char *apszToRemove[] = {
+        "productCatalogId",
+        "childCatalogId",
+        "productType",
+        "numberOfLooks",
+        "effectiveBandwidth",
+        "mode",
+        "scanDirection",
+        "cloudCover",
+        "productGSD",
+        NULL };
+
+    for( iKey = 0; apszToRemove[iKey] != NULL; iKey++ )
+    {
+        int iTarget = CSLFindName( papszIMD, apszToRemove[iKey] );
+        if( iTarget != -1 )
+            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Replace various min/mean/max with just the mean.                */
+/* -------------------------------------------------------------------- */
+    static const char *keylist[] = {
+        "CollectedRowGSD",
+        "CollectedColGSD",
+        "SunAz",
+        "SunEl",
+        "SatAz",
+        "SatEl",
+        "InTrackViewAngle",
+        "CrossTrackViewAngle",
+        "OffNadirViewAngle",
+        NULL };
+
+    for( iKey = 0; keylist[iKey] != NULL; iKey++ )
+    {
+        CPLString osTarget;
+        int       iTarget;
+
+        osTarget.Printf( "IMAGE_1.min%s", keylist[iKey] );
+        iTarget = CSLFindName( papszIMD, osTarget );
+        if( iTarget != -1 )
+            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
+
+        osTarget.Printf( "IMAGE_1.max%s", keylist[iKey] );
+        iTarget = CSLFindName( papszIMD, osTarget );
+        if( iTarget != -1 )
+            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
+
+        osTarget.Printf( "IMAGE_1.mean%s", keylist[iKey] );
+        iTarget = CSLFindName( papszIMD, osTarget );
+        if( iTarget != -1 )
+        {
+            CPLString osValue = CSLFetchNameValue( papszIMD, osTarget );
+            CPLString osLine;
+
+            osTarget.Printf( "IMAGE_1.%c%s",
+                             tolower(keylist[iKey][0]),
+                             keylist[iKey]+1 );
+
+            osLine = osTarget + "=" + osValue;
+
+            CPLFree( papszIMD[iTarget] );
+            papszIMD[iTarget] = CPLStrdup(osLine);
+        }
+    }
+
+    *ppapszIMD = papszIMD;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          GDALLoadIMDFile()                           */
+/************************************************************************/
+
+char ** GDALLoadIMDFile( const CPLString& osFilePath )
+{
+    if( osFilePath.empty() )
+        return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    CPLKeywordParser oParser;
+
+    VSILFILE *fp = VSIFOpenL( osFilePath, "r" );
+
+    if( fp == NULL )
+        return NULL;
+
+    if( !oParser.Ingest( fp ) )
+    {
+        VSIFCloseL( fp );
+        return NULL;
+    }
+
+    VSIFCloseL( fp );
+
+/* -------------------------------------------------------------------- */
+/*      Consider version changing.                                      */
+/* -------------------------------------------------------------------- */
+    char **papszIMD = CSLDuplicate( oParser.GetAllKeywords() );
+    const char *pszVersion = CSLFetchNameValue( papszIMD, "version" );
+
+    if( pszVersion == NULL )
+    {
+        /* ? */;
+    }
+    else if( EQUAL(pszVersion,"\"AA\"") )
+    {
+        GDAL_IMD_AA2R( &papszIMD );
+    }
+
+    return papszIMD;
+}
+
+/************************************************************************/
+/*                       GDALWriteIMDMultiLine()                        */
+/*                                                                      */
+/*      Write a value that is split over multiple lines.                */
+/************************************************************************/
+
+static void GDALWriteIMDMultiLine( VSILFILE *fp, const char *pszValue )
+
+{
+    char **papszItems = CSLTokenizeStringComplex( pszValue, "(,) ",
+                                                  FALSE, FALSE );
+    int nItemCount = CSLCount(papszItems);
+    int i;
+
+    VSIFPrintfL( fp, "(\n" );
+
+    for( i = 0; i < nItemCount; i++ )
+    {
+        if( i == nItemCount-1 )
+            VSIFPrintfL( fp, "\t%s );\n", papszItems[i] );
+        else
+            VSIFPrintfL( fp, "\t%s,\n", papszItems[i] );
+    }
+    CSLDestroy( papszItems );
+}
+
+/************************************************************************/
+/*                          GDALWriteIMDFile()                          */
+/************************************************************************/
+
+CPLErr GDALWriteIMDFile( const char *pszFilename, char **papszMD )
+
+{
+    CPLString osRPBFilename = CPLResetExtension( pszFilename, "IMD" );
+
+/* -------------------------------------------------------------------- */
+/*      Read file and parse.                                            */
+/* -------------------------------------------------------------------- */
+    VSILFILE *fp = VSIFOpenL( osRPBFilename, "w" );
+
+    if( fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed,
+                  "Unable to create %s for writing.\n%s",
+                  osRPBFilename.c_str(), CPLGetLastErrorMsg() );
+        return CE_Failure;
+    }
+
+/* ==================================================================== */
+/* -------------------------------------------------------------------- */
+/*      Loop through all values writing.                                */
+/* -------------------------------------------------------------------- */
+/* ==================================================================== */
+    int iKey;
+    CPLString osCurSection;
+
+    for( iKey = 0; papszMD[iKey] != NULL; iKey++ )
+    {
+        char *pszRawKey = NULL;
+        const char *pszValue = CPLParseNameValue( papszMD[iKey], &pszRawKey );
+        CPLString osKeySection, osKeyItem;
+        char *pszDot = strchr(pszRawKey,'.');
+
+/* -------------------------------------------------------------------- */
+/*      Split stuff like BAND_P.ULLon into section and item.            */
+/* -------------------------------------------------------------------- */
+        if( pszDot == NULL )
+        {
+            osKeyItem = pszRawKey;
+        }
+        else
+        {
+            osKeyItem = pszDot+1;
+            *pszDot = '\0';
+            osKeySection = pszRawKey;
+        }
+        CPLFree( pszRawKey );
+
+/* -------------------------------------------------------------------- */
+/*      Close and/or start sections as needed.                          */
+/* -------------------------------------------------------------------- */
+        if( osCurSection.size() && !EQUAL(osCurSection,osKeySection) )
+            VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
+
+        if( osKeySection.size() && !EQUAL(osCurSection,osKeySection) )
+            VSIFPrintfL( fp, "BEGIN_GROUP = %s\n", osKeySection.c_str() );
+
+        osCurSection = osKeySection;
+
+/* -------------------------------------------------------------------- */
+/*      Print out simple item.                                          */
+/* -------------------------------------------------------------------- */
+        if( osCurSection.size() )
+            VSIFPrintfL( fp, "\t%s = ", osKeyItem.c_str() );
+        else
+            VSIFPrintfL( fp, "%s = ", osKeyItem.c_str() );
+
+        if( pszValue[0] != '(' )
+            VSIFPrintfL( fp, "%s;\n", pszValue );
+        else
+            GDALWriteIMDMultiLine( fp, pszValue );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Close off.                                                      */
+/* -------------------------------------------------------------------- */
+    if( osCurSection.size() )
+        VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
+
+    VSIFPrintfL( fp, "END;\n" );
+
+    VSIFCloseL( fp );
+
+    return CE_None;
+}
diff --git a/gcore/gdal_mdreader.h b/gcore/gdal_mdreader.h
new file mode 100644
index 0000000..9e7937d
--- /dev/null
+++ b/gcore/gdal_mdreader.h
@@ -0,0 +1,202 @@
+/******************************************************************************
+ * $Id: gdal_mdreader.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata (mainly the remote sensing imagery) from files of 
+ *           different providers like DigitalGlobe, GeoEye etc.
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#ifndef GDAL_MDREADER_H_INCLUDED
+#define GDAL_MDREADER_H_INCLUDED
+
+
+#include "cpl_port.h"
+#include "gdal_priv.h"
+
+#define MD_DOMAIN_IMD "IMD"              /**< image metadata section */
+#define MD_DOMAIN_RPC "RPC"              /**< rpc metadata section */
+#define MD_DOMAIN_IMAGERY "IMAGERY"      /**< imagery metadata section */
+#define MD_DOMAIN_DEFAULT ""             /**< default metadata section */
+
+#define MD_NAME_ACQDATETIME "ACQUISITIONDATETIME"  /**< Acquisition Date Time property name. The time should be in UTC */
+#define MD_NAME_SATELLITE   "SATELLITEID"          /**< Satellite identificator property name */
+#define MD_NAME_CLOUDCOVER  "CLOUDCOVER"           /**< Cloud coverage property name. The value between 0 - 100 or 999 if n/a */
+#define MD_NAME_MDTYPE      "METADATATYPE"         /**< Metadata reader type property name. The reader processed this metadata */
+
+#define MD_DATETIMEFORMAT "%Y-%m-%d %H:%M:%S"      /**< Date time format */
+#define MD_CLOUDCOVER_NA "999"               /**< The value if cloud cover n/a*/
+
+/**
+ * RPC/RPB specific defines
+ */
+
+#define RPC_LINE_OFF        "LINE_OFF"
+#define RPC_SAMP_OFF        "SAMP_OFF"
+#define RPC_LAT_OFF         "LAT_OFF"
+#define RPC_LONG_OFF        "LONG_OFF"
+#define RPC_HEIGHT_OFF      "HEIGHT_OFF"
+#define RPC_LINE_SCALE      "LINE_SCALE"
+#define RPC_SAMP_SCALE      "SAMP_SCALE"
+#define RPC_LAT_SCALE       "LAT_SCALE"
+#define RPC_LONG_SCALE      "LONG_SCALE"
+#define RPC_HEIGHT_SCALE    "HEIGHT_SCALE"
+#define RPC_LINE_NUM_COEFF  "LINE_NUM_COEFF"
+#define RPC_LINE_DEN_COEFF  "LINE_DEN_COEFF"
+#define RPC_SAMP_NUM_COEFF  "SAMP_NUM_COEFF"
+#define RPC_SAMP_DEN_COEFF  "SAMP_DEN_COEFF"
+
+/**
+ * Enumerator of metadata readers
+ */
+
+typedef enum {
+    MDR_None     = 0x000000,    /**< no reader */
+    MDR_DG       = 0x000001,    /**< Digital Globe, METADATATYPE=DG */
+    MDR_GE       = 0x000002,    /**< Geo Eye,       METADATATYPE=GE */
+    MDR_OV       = 0x000004,    /**< Orb View,      METADATATYPE=OV */
+    MDR_PLEIADES = 0x000008,    /**< Pleiades,      METADATATYPE=DIMAP */
+    MDR_RDK1     = 0x000010,    /**< Resurs DK1,    METADATATYPE=MSP */
+    MDR_LS       = 0x000020,    /**< Landsat,       METADATATYPE=ODL */
+    MDR_ANY  = MDR_DG | MDR_GE | MDR_OV | MDR_PLEIADES | MDR_RDK1 |
+               MDR_LS /**< any reader */
+} MDReaders;
+
+
+/**
+ * The base class for all metadata readers
+ */
+class GDALMDReaderBase{
+public:
+    GDALMDReaderBase(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderBase();
+
+    /**
+     * @brief Get specified metadata domain
+     * @param pszDomain The metadata domain to return  
+     * @return List of metadata items 
+     */
+    virtual char ** GetMetadataDomain(const char *pszDomain);
+    /**
+     * @brief Fill provided metatada store class
+     * @param poMDMD Metatada store class
+     * @return true on success or false
+     */
+    virtual bool FillMetadata(GDALMultiDomainMetadata* poMDMD);
+    /**
+      * @brief Determine whether the input parameter correspond to the particular 
+      *        provider of remote sensing data completely
+      * @return True if all needed sources files found
+      */
+    virtual const bool HasRequiredFiles() const = 0;
+    /**
+     * @brief Get metadata file names. The caller become owner of returned list
+     *        and have to free it via CSLDestroy.
+     * @return A file name list
+     */
+    virtual char** GetMetadataFiles() const = 0;
+protected:
+    /**
+     * @brief Load metadata to the correspondent IMD, RPB, IMAGERY and DEFAULT
+     *        domains
+     */
+    virtual void LoadMetadata();
+    /**
+     * @brief Convert string like 2012-02-25T00:25:59.9440000Z to time
+     * @param pszDateTime String to convert
+     * @return value in time_t
+     */
+    virtual const time_t GetAcquisitionTimeFromString(const char* pszDateTime);
+    /**
+     * @brief ReadXMLToList Transform xml to list of NULL terminated name=value
+     *        strings
+     * @param psNode A xml node to process
+     * @param papszList A list to fill with name=value strings
+     * @param pszName A name of parent node. For root xml node should be empty.
+     *        If name is not empty, the sibling nodes will not proceed
+     * @return An input list filled with values
+     */
+    virtual char** ReadXMLToList(CPLXMLNode* psNode, char** papszList,
+                         const char* pszName = "");
+    /**
+     * @brief AddXMLNameValueToList Execute from ReadXMLToList to add name and
+     *        value to list. One can override this function for special
+     *        processing input values before add to list.
+     * @param papszList A list to fill with name=value strings
+     * @param pszName A name to add
+     * @param pszValue A value to add
+     * @return
+     */
+    virtual char** AddXMLNameValueToList(char** papszList, const char *pszName,
+                                         const char *pszValue);
+protected:
+    char **m_papszIMDMD;
+    char **m_papszRPCMD;
+    char **m_papszIMAGERYMD;
+    char **m_papszDEFAULTMD;
+    bool m_bIsMetadataLoad; 
+};
+
+/**
+ * The metadata reader main class.
+ * The main purpose of this class is to provide an correspondent reader 
+ * for provided path. 
+ */
+class CPL_DLL GDALMDReaderManager{
+public:
+    GDALMDReaderManager();
+    virtual ~GDALMDReaderManager();
+    
+    /**
+     * @brief Try to detect metadata reader correspondent to the provided 
+     *        datasource path 
+     * @param pszPath a path to GDALDataset 
+     * @param papszSiblingFiles file list for metadata search purposes
+     * @param nType a preferable reader type (may be the OR of MDReaders)
+     * @return an appropriate reader or NULL if no such reader or error.
+     * The pointer delete by the GDALMDReaderManager, so the user have not
+     * delete it.
+     */
+    virtual GDALMDReaderBase* GetReader(const char *pszPath, 
+                                        char **papszSiblingFiles, 
+                                        GUInt32 nType = MDR_ANY);
+protected:
+    GDALMDReaderBase *m_pReader;
+};
+
+// misc
+CPLString CPLStrip(const CPLString& osString, const char cChar);
+CPLString CPLStripQuotes(const CPLString& osString);
+char** GDALLoadRPBFile( const CPLString& osFilePath );
+char** GDALLoadRPCFile( const CPLString& osFilePath );
+char** GDALLoadIMDFile( const CPLString& osFilePath );
+const bool GDALCheckFileHeader(const CPLString& soFilePath,
+                               const char * pszTestString,
+                               int nBufferSize = 256);
+
+CPLErr GDALWriteRPBFile( const char *pszFilename, char **papszMD );
+CPLErr GDALWriteRPCTXTFile( const char *pszFilename, char **papszMD );
+CPLErr GDALWriteIMDFile( const char *pszFilename, char **papszMD );
+
+#endif //GDAL_MDREADER_H_INCLUDED
diff --git a/gcore/gdal_misc.cpp b/gcore/gdal_misc.cpp
index 3e1a91c..d4d3cc5 100644
--- a/gcore/gdal_misc.cpp
+++ b/gcore/gdal_misc.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_misc.cpp 27121 2014-04-03 22:08:55Z rouault $
+ * $Id: gdal_misc.cpp 29123 2015-05-03 11:05:46Z bishop $
  *
  * Project:  GDAL Core
  * Purpose:  Free standing functions for GDAL.
@@ -35,9 +35,10 @@
 #include <ctype.h>
 #include <string>
 
-CPL_CVSID("$Id: gdal_misc.cpp 27121 2014-04-03 22:08:55Z rouault $");
+CPL_CVSID("$Id: gdal_misc.cpp 29123 2015-05-03 11:05:46Z bishop $");
 
 #include "ogr_spatialref.h"
+#include "gdal_mdreader.h"
 
 /************************************************************************/
 /*                           __pure_virtual()                           */
@@ -956,7 +957,7 @@ int CPL_STDCALL GDALLoadOziMapFile( const char *pszFilename,
     {
         if ( EQUALN(papszLines[iLine], "MSF,", 4) )
         {
-            dfMSF = atof(papszLines[iLine] + 4);
+            dfMSF = CPLAtof(papszLines[iLine] + 4);
             if (dfMSF <= 0.01) /* Suspicious values */
             {
                 CPLDebug("OZI", "Suspicious MSF value : %s", papszLines[iLine]);
@@ -1262,7 +1263,7 @@ int CPL_STDCALL GDALLoadTabFile( const char *pszFilename,
 /*      possible.  Otherwise we will need to use them as GCPs.          */
 /* -------------------------------------------------------------------- */
     if( !GDALGCPsToGeoTransform( nCoordinateCount, asGCPs, padfGeoTransform, 
-                                 FALSE ) )
+                                 CSLTestBoolean(CPLGetConfigOption("TAB_APPROX_GEOTRANSFORM", "NO")) ) )
     {
         if (pnGCPCount && ppasGCPs)
         {
@@ -1317,6 +1318,9 @@ int GDALReadTabFile2( const char * pszBaseFilename,
     if (ppszTabFileNameOut)
         *ppszTabFileNameOut = NULL;
 
+    if( !GDALCanFileAcceptSidecarFile(pszBaseFilename) )
+        return FALSE;
+
     pszTAB = CPLResetExtension( pszBaseFilename, "tab" );
 
     if (papszSiblingFiles)
@@ -1515,6 +1519,9 @@ int GDALReadWorldFile2( const char *pszBaseFilename, const char *pszExtension,
     if (ppszWorldFileNameOut)
         *ppszWorldFileNameOut = NULL;
 
+    if( !GDALCanFileAcceptSidecarFile(pszBaseFilename) )
+        return FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      If we aren't given an extension, try both the unix and          */
 /*      windows style extensions.                                       */
@@ -2143,10 +2150,12 @@ GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
 /* -------------------------------------------------------------------- */
     if( !bApproxOK )
     {
-        double dfPixelSize = ABS(padfGeoTransform[1]) 
+        // FIXME? Not sure if it is the more accurate way of computing
+        // pixel size
+        double dfPixelSize = 0.5 * (ABS(padfGeoTransform[1]) 
             + ABS(padfGeoTransform[2])
             + ABS(padfGeoTransform[4])
-            + ABS(padfGeoTransform[5]);
+            + ABS(padfGeoTransform[5]));
 
         for( i = 0; i < nGCPCount; i++ )
         {
@@ -2165,7 +2174,11 @@ GDALGCPsToGeoTransform( int nGCPCount, const GDAL_GCP *pasGCPs,
 
             if( ABS(dfErrorX) > 0.25 * dfPixelSize 
                 || ABS(dfErrorY) > 0.25 * dfPixelSize )
+            {
+                CPLDebug("GDAL", "dfErrorX/dfPixelSize = %.2f, dfErrorY/dfPixelSize = %.2f",
+                         ABS(dfErrorX)/dfPixelSize, ABS(dfErrorY)/dfPixelSize);
                 return FALSE;
+            }
         }
     }
 
@@ -2269,7 +2282,9 @@ void GDALComposeGeoTransforms(const double *padfGT1, const double *padfGT2,
  *
  * @param nArgc number of values in the argument list.
  * @param ppapszArgv pointer to the argument list array (will be updated in place).
- * @param nOptions unused for now.
+ * @param nOptions a or-able combination of GDAL_OF_RASTER and GDAL_OF_VECTOR
+ *                 to determine which drivers should be displayed by --formats.
+ *                 If set to 0, GDAL_OF_RASTER is assumed.
  *
  * @return updated nArgc argument count.  Return of 0 requests terminate 
  * without error, return of -1 requests exit with error code.
@@ -2283,8 +2298,6 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
     int  iArg;
     char **papszArgv = *ppapszArgv;
 
-    (void) nOptions;
-    
 /* -------------------------------------------------------------------- */
 /*      Preserve the program name.                                      */
 /* -------------------------------------------------------------------- */
@@ -2475,35 +2488,59 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
         else if( EQUAL(papszArgv[iArg], "--formats") )
         {
             int iDr;
+            
+            if( nOptions == 0 )
+                nOptions = GDAL_OF_RASTER;
 
             printf( "Supported Formats:\n" );
             for( iDr = 0; iDr < GDALGetDriverCount(); iDr++ )
             {
                 GDALDriverH hDriver = GDALGetDriver(iDr);
-                const char *pszRWFlag, *pszVirtualIO, *pszSubdatasets;
-                
-                if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) )
-                    pszRWFlag = "rw+";
-                else if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATECOPY, 
-                                              NULL ) )
-                    pszRWFlag = "rw";
+
+                const char *pszRFlag = "", *pszWFlag, *pszVirtualIO, *pszSubdatasets, *pszKind;
+                char** papszMD = GDALGetMetadata( hDriver, NULL );
+
+                if( nOptions == GDAL_OF_RASTER &&
+                    !CSLFetchBoolean( papszMD, GDAL_DCAP_RASTER, FALSE ) )
+                    continue;
+                if( nOptions == GDAL_OF_VECTOR &&
+                    !CSLFetchBoolean( papszMD, GDAL_DCAP_VECTOR, FALSE ) )
+                    continue;
+
+                if( CSLFetchBoolean( papszMD, GDAL_DCAP_OPEN, FALSE ) )
+                    pszRFlag = "r";
+
+                if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATE, FALSE ) )
+                    pszWFlag = "w+";
+                else if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATECOPY, FALSE ) )
+                    pszWFlag = "w";
                 else
-                    pszRWFlag = "ro";
-                
-                if( GDALGetMetadataItem( hDriver, GDAL_DCAP_VIRTUALIO, NULL) )
+                    pszWFlag = "o";
+
+                if( CSLFetchBoolean( papszMD, GDAL_DCAP_VIRTUALIO, FALSE ) )
                     pszVirtualIO = "v";
                 else
                     pszVirtualIO = "";
 
-                pszSubdatasets = GDALGetMetadataItem( hDriver, GDAL_DMD_SUBDATASETS, NULL );
-                if( pszSubdatasets && CSLTestBoolean( pszSubdatasets ) )
+                if( CSLFetchBoolean( papszMD, GDAL_DMD_SUBDATASETS, FALSE ) )
                     pszSubdatasets = "s";
                 else
                     pszSubdatasets = "";
 
-                printf( "  %s (%s%s%s): %s\n",
+                if( CSLFetchBoolean( papszMD, GDAL_DCAP_RASTER, FALSE ) &&
+                    CSLFetchBoolean( papszMD, GDAL_DCAP_VECTOR, FALSE ))
+                    pszKind = "raster,vector";
+                else if( CSLFetchBoolean( papszMD, GDAL_DCAP_RASTER, FALSE ) )
+                    pszKind = "raster";
+                else if( CSLFetchBoolean( papszMD, GDAL_DCAP_VECTOR, FALSE ) )
+                    pszKind = "vector";
+                else
+                    pszKind = "unknown kind";
+
+                printf( "  %s -%s- (%s%s%s%s): %s\n",
                         GDALGetDriverShortName( hDriver ),
-                        pszRWFlag, pszVirtualIO, pszSubdatasets,
+                        pszKind,
+                        pszRFlag, pszWFlag, pszVirtualIO, pszSubdatasets,
                         GDALGetDriverLongName( hDriver ) );
             }
 
@@ -2544,10 +2581,16 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
             printf( "  Long Name: %s\n", GDALGetDriverLongName( hDriver ) );
 
             papszMD = GDALGetMetadata( hDriver, NULL );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_RASTER, FALSE ) )
+                printf( "  Supports: Raster\n" );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_VECTOR, FALSE ) )
+                printf( "  Supports: Vector\n" );
+
+            const char* pszExt = CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSIONS );
+            if( pszExt != NULL )
+                printf( "  Extension%s: %s\n", (strchr(pszExt, ' ') ? "s" : ""),
+                        pszExt );
 
-            if( CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) )
-                printf( "  Extension: %s\n", 
-                        CSLFetchNameValue( papszMD, GDAL_DMD_EXTENSION ) );
             if( CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) )
                 printf( "  Mime Type: %s\n", 
                         CSLFetchNameValue( papszMD, GDAL_DMD_MIMETYPE ) );
@@ -2557,6 +2600,8 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
             
             if( CSLFetchBoolean( papszMD, GDAL_DMD_SUBDATASETS, FALSE ) )
                 printf( "  Supports: Subdatasets\n" );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_OPEN, FALSE ) )
+                printf( "  Supports: Open() - Open existing dataset.\n" );
             if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATE, FALSE ) )
                 printf( "  Supports: Create() - Create writeable dataset.\n" );
             if( CSLFetchBoolean( papszMD, GDAL_DCAP_CREATECOPY, FALSE ) )
@@ -2566,6 +2611,15 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
             if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) )
                 printf( "  Creation Datatypes: %s\n",
                         CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONDATATYPES ) );
+            if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATATYPES ) )
+                printf( "  Creation Field Datatypes: %s\n",
+                        CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONFIELDDATATYPES ) );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_NOTNULL_FIELDS, FALSE ) )
+                printf( "  Supports: Creating fields with NOT NULL constraint.\n" );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_DEFAULT_FIELDS, FALSE ) )
+                printf( "  Supports: Creating fields with DEFAULT values.\n" );
+            if( CSLFetchBoolean( papszMD, GDAL_DCAP_NOTNULL_GEOMFIELDS, FALSE ) )
+                printf( "  Supports: Creating geometry fields with NOT NULL constraint.\n" );
             if( CSLFetchNameValue( papszMD, GDAL_DMD_CREATIONOPTIONLIST ) )
             {
                 CPLXMLNode *psCOL = 
@@ -2580,6 +2634,39 @@ GDALGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
                 printf( "\n%s\n", pszFormattedXML );
                 CPLFree( pszFormattedXML );
             }
+            if( CSLFetchNameValue( papszMD, GDAL_DS_LAYER_CREATIONOPTIONLIST ) )
+            {
+                CPLXMLNode *psCOL = 
+                    CPLParseXMLString( 
+                        CSLFetchNameValue( papszMD, 
+                                           GDAL_DS_LAYER_CREATIONOPTIONLIST ) );
+                char *pszFormattedXML = 
+                    CPLSerializeXMLTree( psCOL );
+
+                CPLDestroyXMLNode( psCOL );
+                
+                printf( "\n%s\n", pszFormattedXML );
+                CPLFree( pszFormattedXML );
+            }
+
+            if( CSLFetchNameValue( papszMD, GDAL_DMD_CONNECTION_PREFIX ) )
+                printf( "  Connection prefix: %s\n", 
+                        CSLFetchNameValue( papszMD, GDAL_DMD_CONNECTION_PREFIX ) );
+
+            if( CSLFetchNameValue( papszMD, GDAL_DMD_OPENOPTIONLIST ) )
+            {
+                CPLXMLNode *psCOL = 
+                    CPLParseXMLString( 
+                        CSLFetchNameValue( papszMD, 
+                                           GDAL_DMD_OPENOPTIONLIST ) );
+                char *pszFormattedXML = 
+                    CPLSerializeXMLTree( psCOL );
+
+                CPLDestroyXMLNode( psCOL );
+                
+                printf( "%s\n", pszFormattedXML );
+                CPLFree( pszFormattedXML );
+            }
             return 0;
         }
 
@@ -2690,37 +2777,37 @@ static int _FetchDblFromMD( char **papszMD, const char *pszKey,
 int CPL_STDCALL GDALExtractRPCInfo( char **papszMD, GDALRPCInfo *psRPC )
 
 {
-    if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL )
+    if( CSLFetchNameValue( papszMD, RPC_LINE_NUM_COEFF ) == NULL )
         return FALSE;
 
-    if( CSLFetchNameValue( papszMD, "LINE_NUM_COEFF" ) == NULL 
-        || CSLFetchNameValue( papszMD, "LINE_DEN_COEFF" ) == NULL 
-        || CSLFetchNameValue( papszMD, "SAMP_NUM_COEFF" ) == NULL 
-        || CSLFetchNameValue( papszMD, "SAMP_DEN_COEFF" ) == NULL )
+    if( CSLFetchNameValue( papszMD, RPC_LINE_NUM_COEFF ) == NULL
+        || CSLFetchNameValue( papszMD, RPC_LINE_DEN_COEFF ) == NULL
+        || CSLFetchNameValue( papszMD, RPC_SAMP_NUM_COEFF ) == NULL
+        || CSLFetchNameValue( papszMD, RPC_SAMP_DEN_COEFF ) == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
                  "Some required RPC metadata missing in GDALExtractRPCInfo()");
         return FALSE;
     }
 
-    _FetchDblFromMD( papszMD, "LINE_OFF", &(psRPC->dfLINE_OFF), 1, 0.0 );
-    _FetchDblFromMD( papszMD, "LINE_SCALE", &(psRPC->dfLINE_SCALE), 1, 1.0 );
-    _FetchDblFromMD( papszMD, "SAMP_OFF", &(psRPC->dfSAMP_OFF), 1, 0.0 );
-    _FetchDblFromMD( papszMD, "SAMP_SCALE", &(psRPC->dfSAMP_SCALE), 1, 1.0 );
-    _FetchDblFromMD( papszMD, "HEIGHT_OFF", &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
-    _FetchDblFromMD( papszMD, "HEIGHT_SCALE", &(psRPC->dfHEIGHT_SCALE),1, 1.0);
-    _FetchDblFromMD( papszMD, "LAT_OFF", &(psRPC->dfLAT_OFF), 1, 0.0 );
-    _FetchDblFromMD( papszMD, "LAT_SCALE", &(psRPC->dfLAT_SCALE), 1, 1.0 );
-    _FetchDblFromMD( papszMD, "LONG_OFF", &(psRPC->dfLONG_OFF), 1, 0.0 );
-    _FetchDblFromMD( papszMD, "LONG_SCALE", &(psRPC->dfLONG_SCALE), 1, 1.0 );
+    _FetchDblFromMD( papszMD, RPC_LINE_OFF, &(psRPC->dfLINE_OFF), 1, 0.0 );
+    _FetchDblFromMD( papszMD, RPC_LINE_SCALE, &(psRPC->dfLINE_SCALE), 1, 1.0 );
+    _FetchDblFromMD( papszMD, RPC_SAMP_OFF, &(psRPC->dfSAMP_OFF), 1, 0.0 );
+    _FetchDblFromMD( papszMD, RPC_SAMP_SCALE, &(psRPC->dfSAMP_SCALE), 1, 1.0 );
+    _FetchDblFromMD( papszMD, RPC_HEIGHT_OFF, &(psRPC->dfHEIGHT_OFF), 1, 0.0 );
+    _FetchDblFromMD( papszMD, RPC_HEIGHT_SCALE, &(psRPC->dfHEIGHT_SCALE),1, 1.0);
+    _FetchDblFromMD( papszMD, RPC_LAT_OFF, &(psRPC->dfLAT_OFF), 1, 0.0 );
+    _FetchDblFromMD( papszMD, RPC_LAT_SCALE, &(psRPC->dfLAT_SCALE), 1, 1.0 );
+    _FetchDblFromMD( papszMD, RPC_LONG_OFF, &(psRPC->dfLONG_OFF), 1, 0.0 );
+    _FetchDblFromMD( papszMD, RPC_LONG_SCALE, &(psRPC->dfLONG_SCALE), 1, 1.0 );
 
-    _FetchDblFromMD( papszMD, "LINE_NUM_COEFF", psRPC->adfLINE_NUM_COEFF, 
+    _FetchDblFromMD( papszMD, RPC_LINE_NUM_COEFF, psRPC->adfLINE_NUM_COEFF,
                      20, 0.0 );
-    _FetchDblFromMD( papszMD, "LINE_DEN_COEFF", psRPC->adfLINE_DEN_COEFF, 
+    _FetchDblFromMD( papszMD, RPC_LINE_DEN_COEFF, psRPC->adfLINE_DEN_COEFF,
                      20, 0.0 );
-    _FetchDblFromMD( papszMD, "SAMP_NUM_COEFF", psRPC->adfSAMP_NUM_COEFF, 
+    _FetchDblFromMD( papszMD, RPC_SAMP_NUM_COEFF, psRPC->adfSAMP_NUM_COEFF,
                      20, 0.0 );
-    _FetchDblFromMD( papszMD, "SAMP_DEN_COEFF", psRPC->adfSAMP_DEN_COEFF, 
+    _FetchDblFromMD( papszMD, RPC_SAMP_DEN_COEFF, psRPC->adfSAMP_DEN_COEFF,
                      20, 0.0 );
     
     _FetchDblFromMD( papszMD, "MIN_LONG", &(psRPC->dfMIN_LONG), 1, -180.0 );
@@ -3151,19 +3238,143 @@ void GDALDeserializeGCPListFromXML( CPLXMLNode* psGCPList,
         CPLFree( psGCP->pszInfo );
         psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
 
-        psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
-        psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
+        psGCP->dfGCPPixel = CPLAtof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
+        psGCP->dfGCPLine = CPLAtof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
 
-        psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
-        psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
+        psGCP->dfGCPX = CPLAtof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
+        psGCP->dfGCPY = CPLAtof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
         const char* pszZ = CPLGetXMLValue(psXMLGCP,"Z",NULL);
         if( pszZ == NULL )
         {
             /* Note: GDAL 1.10.1 and older generated #GCPZ, but could not read it back */
             pszZ = CPLGetXMLValue(psXMLGCP,"GCPZ","0.0");
         }
-        psGCP->dfGCPZ = atof(pszZ);
+        psGCP->dfGCPZ = CPLAtof(pszZ);
 
         (*pnGCPCount) ++;
     }
 }
+
+/************************************************************************/
+/*                   GDALSerializeOpenOptionsToXML()                    */
+/************************************************************************/
+
+void GDALSerializeOpenOptionsToXML( CPLXMLNode* psParentNode, char** papszOpenOptions)
+{
+    if( papszOpenOptions != NULL )
+    {
+        CPLXMLNode* psOpenOptions = CPLCreateXMLNode( psParentNode, CXT_Element, "OpenOptions" );
+        CPLXMLNode* psLastChild = NULL;
+
+        for(char** papszIter = papszOpenOptions; *papszIter != NULL; papszIter ++ )
+        {
+            const char *pszRawValue;
+            char *pszKey = NULL;
+            CPLXMLNode *psOOI;
+
+            pszRawValue = CPLParseNameValue( *papszIter, &pszKey );
+
+            psOOI = CPLCreateXMLNode( NULL, CXT_Element, "OOI" );
+            if( psLastChild == NULL )
+                psOpenOptions->psChild = psOOI;
+            else
+                psLastChild->psNext = psOOI;
+            psLastChild = psOOI;
+
+            CPLSetXMLValue( psOOI, "#key", pszKey );
+            CPLCreateXMLNode( psOOI, CXT_Text, pszRawValue );
+
+            CPLFree( pszKey );
+        }
+    }
+}
+
+/************************************************************************/
+/*                  GDALDeserializeOpenOptionsFromXML()                 */
+/************************************************************************/
+
+char** GDALDeserializeOpenOptionsFromXML( CPLXMLNode* psParentNode )
+{
+    char** papszOpenOptions = NULL;
+    CPLXMLNode* psOpenOptions = CPLGetXMLNode(psParentNode, "OpenOptions");
+    if( psOpenOptions != NULL )
+    {
+        CPLXMLNode* psOOI;
+        for( psOOI = psOpenOptions->psChild; psOOI != NULL;
+                psOOI = psOOI->psNext )
+        {
+            if( !EQUAL(psOOI->pszValue,"OOI")
+                || psOOI->eType != CXT_Element
+                || psOOI->psChild == NULL
+                || psOOI->psChild->psNext == NULL
+                || psOOI->psChild->eType != CXT_Attribute
+                || psOOI->psChild->psChild == NULL )
+                continue;
+
+            char* pszName = psOOI->psChild->psChild->pszValue;
+            char* pszValue = psOOI->psChild->psNext->pszValue;
+            if( pszName != NULL && pszValue != NULL )
+                papszOpenOptions = CSLSetNameValue( papszOpenOptions, pszName, pszValue );
+        }
+    }
+    return papszOpenOptions;
+}
+
+/************************************************************************/
+/*                    GDALRasterIOGetResampleAlg()                      */
+/************************************************************************/
+
+GDALRIOResampleAlg GDALRasterIOGetResampleAlg(const char* pszResampling)
+{
+    GDALRIOResampleAlg eResampleAlg = GRIORA_NearestNeighbour;
+    if( EQUALN(pszResampling, "NEAR", 4) )
+        eResampleAlg = GRIORA_NearestNeighbour;
+    else if( EQUAL(pszResampling, "BILINEAR") )
+        eResampleAlg = GRIORA_Bilinear;
+    else if( EQUAL(pszResampling, "CUBIC") )
+        eResampleAlg = GRIORA_Cubic;
+    else if( EQUAL(pszResampling, "CUBICSPLINE") )
+        eResampleAlg = GRIORA_CubicSpline;
+    else if( EQUAL(pszResampling, "LANCZOS") )
+        eResampleAlg = GRIORA_Lanczos;
+    else if( EQUAL(pszResampling, "AVERAGE") )
+        eResampleAlg = GRIORA_Average;
+    else if( EQUAL(pszResampling, "MODE") )
+        eResampleAlg = GRIORA_Mode;
+    else if( EQUAL(pszResampling, "GAUSS") )
+        eResampleAlg = GRIORA_Gauss;
+    else
+        CPLError(CE_Warning, CPLE_NotSupported,
+                "GDAL_RASTERIO_RESAMPLING = %s not supported", pszResampling);
+    return eResampleAlg;
+}
+
+/************************************************************************/
+/*                   GDALRasterIOExtraArgSetResampleAlg()               */
+/************************************************************************/
+
+void GDALRasterIOExtraArgSetResampleAlg(GDALRasterIOExtraArg* psExtraArg,
+                                        int nXSize, int nYSize,
+                                        int nBufXSize, int nBufYSize)
+{
+    if( (nBufXSize != nXSize || nBufYSize != nYSize) &&
+        psExtraArg->eResampleAlg == GRIORA_NearestNeighbour  )
+    {
+        const char* pszResampling = CPLGetConfigOption("GDAL_RASTERIO_RESAMPLING", NULL);
+        if( pszResampling != NULL )
+        {
+            psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(pszResampling);
+        }
+    }
+}
+
+/************************************************************************/
+/*                     GDALCanFileAcceptSidecarFile()                   */
+/************************************************************************/
+
+int GDALCanFileAcceptSidecarFile(const char* pszFilename)
+{
+    if( strstr(pszFilename, "/vsicurl/") && strchr(pszFilename, '?') )
+        return FALSE;
+    return TRUE;
+}
diff --git a/gcore/gdal_pam.h b/gcore/gdal_pam.h
index 3f0580e..1e3c1c0 100644
--- a/gcore/gdal_pam.h
+++ b/gcore/gdal_pam.h
@@ -1,8 +1,8 @@
 /******************************************************************************
- * $Id: gdal_pam.h 26117 2013-06-29 20:22:34Z rouault $
+ * $Id: gdal_pam.h 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
- * Purpose:  Declaration for Peristable Auxilary Metadata classes.
+ * Purpose:  Declaration for Peristable Auxiliary Metadata classes.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -99,6 +99,8 @@ public:
     CPLString   osPhysicalFilename;
     CPLString   osSubdatasetName;
     CPLString   osAuxFilename;
+
+    int         bHasMetadata;
 };
 
 /* ******************************************************************** */
@@ -263,17 +265,17 @@ class CPL_DLL GDALPamRasterBand : public GDALRasterBand
     CPLErr SetScale( double );
 
     virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                          int nBuckets, int * panHistogram,
+                          int nBuckets, GUIntBig * panHistogram,
                           int bIncludeOutOfRange, int bApproxOK,
                           GDALProgressFunc, void *pProgressData );
 
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                        int *pnBuckets, int ** ppanHistogram,
+                                        int *pnBuckets, GUIntBig ** ppanHistogram,
                                         int bForce,
                                         GDALProgressFunc, void *pProgressData);
 
     virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int *panHistogram );
+                                        int nBuckets, GUIntBig *panHistogram );
 
     virtual CPLErr      SetMetadata( char ** papszMetadata,
                                      const char * pszDomain = "" );
@@ -294,7 +296,7 @@ class CPL_DLL GDALPamRasterBand : public GDALRasterBand
 // These are mainly helper functions for internal use.
 int CPL_DLL PamParseHistogram( CPLXMLNode *psHistItem, 
                                double *pdfMin, double *pdfMax, 
-                               int *pnBuckets, int **ppanHistogram, 
+                               int *pnBuckets, GUIntBig **ppanHistogram, 
                                int *pbIncludeOutOfRange, int *pbApproxOK );
 CPLXMLNode CPL_DLL *
 PamFindMatchingHistogram( CPLXMLNode *psSavedHistograms,
@@ -302,7 +304,7 @@ PamFindMatchingHistogram( CPLXMLNode *psSavedHistograms,
                           int bIncludeOutOfRange, int bApproxOK );
 CPLXMLNode CPL_DLL *
 PamHistogramToXMLTree( double dfMin, double dfMax,
-                       int nBuckets, int * panHistogram,
+                       int nBuckets, GUIntBig * panHistogram,
                        int bIncludeOutOfRange, int bApprox );
 
 // For managing the proxy file database.
diff --git a/gcore/gdal_priv.h b/gcore/gdal_priv.h
index 34220ad..1f4940e 100644
--- a/gcore/gdal_priv.h
+++ b/gcore/gdal_priv.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_priv.h 27874 2014-10-17 18:36:22Z rouault $
+ * $Id: gdal_priv.h 29097 2015-05-01 20:13:36Z rouault $
  *
  * Name:     gdal_priv.h
  * Project:  GDAL Core
@@ -57,7 +57,10 @@ class GDALAsyncReader;
 #include "cpl_conv.h"
 #include "cpl_string.h"
 #include "cpl_minixml.h"
+#include "cpl_multiproc.h"
 #include <vector>
+#include <map>
+#include "ogr_core.h"
 
 #define GMO_VALID                0x0001
 #define GMO_IGNORE_UNIMPLEMENTED 0x0002
@@ -120,7 +123,7 @@ class CPL_DLL GDALMajorObject
     virtual            ~GDALMajorObject();
 
     int                 GetMOFlags();
-    void                SetMOFlags(int nFlags);
+    void                SetMOFlags(int nFlagsIn);
                         
     virtual const char *GetDescription() const;
     virtual void        SetDescription( const char * );
@@ -170,7 +173,7 @@ class CPL_DLL GDALDefaultOverviews
                GDALDefaultOverviews();
                ~GDALDefaultOverviews();
 
-    void       Initialize( GDALDataset *poDS, const char *pszName = NULL, 
+    void       Initialize( GDALDataset *poDSIn, const char *pszName = NULL, 
                            char **papszSiblingFiles = NULL,
                            int bNameIsOVR = FALSE );
 
@@ -219,57 +222,77 @@ class CPL_DLL GDALDefaultOverviews
 
 class CPL_DLL GDALOpenInfo
 {
+    int         bHasGotSiblingFiles;
+    char        **papszSiblingFiles;
+    int         nHeaderBytesTried;
+
   public:
-                GDALOpenInfo( const char * pszFile, GDALAccess eAccessIn,
+                GDALOpenInfo( const char * pszFile, int nOpenFlagsIn,
                               char **papszSiblingFiles = NULL );
                 ~GDALOpenInfo( void );
 
     char        *pszFilename;
-    char        **papszSiblingFiles;
+    char**      papszOpenOptions;
 
     GDALAccess  eAccess;
+    int         nOpenFlags;
 
     int         bStatOK;
     int         bIsDirectory;
 
-    FILE        *fp;
+    VSILFILE   *fpL;
 
     int         nHeaderBytes;
     GByte       *pabyHeader;
 
+    int         TryToIngest(int nBytes);
+    char      **GetSiblingFiles();
 };
 
 /* ******************************************************************** */
 /*                             GDALDataset                              */
 /* ******************************************************************** */
 
-/* Internal method for now. Might be subject to later revisions */
-GDALDatasetH GDALOpenInternal( const char * pszFilename, GDALAccess eAccess,
-                               const char* const * papszAllowedDrivers);
-GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
-                               const char* const * papszAllowedDrivers);
+class OGRLayer;
+class OGRGeometry;
+class OGRSpatialReference;
+class OGRStyleTable;
+class swq_select;
+class swq_select_parse_options;
+typedef struct GDALSQLParseInfo GDALSQLParseInfo;
+
+#ifdef DETECT_OLD_IRASTERIO
+typedef void signature_changed;
+#endif
+
+#ifdef GDAL_COMPILATION
+#define OPTIONAL_OUTSIDE_GDAL(val)
+#else
+#define OPTIONAL_OUTSIDE_GDAL(val) = val
+#endif
 
 //! A set of associated raster bands, usually from one file.
 
 class CPL_DLL GDALDataset : public GDALMajorObject
 {
-    friend GDALDatasetH CPL_STDCALL GDALOpen( const char *, GDALAccess);
-    friend GDALDatasetH CPL_STDCALL GDALOpenShared( const char *, GDALAccess);
-
-    /* Internal method for now. Might be subject to later revisions */
-    friend GDALDatasetH GDALOpenInternal( const char *, GDALAccess, const char* const * papszAllowedDrivers);
-    friend GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
-                                          const char* const * papszAllowedDrivers);
+    friend GDALDatasetH CPL_STDCALL GDALOpenEx( const char* pszFilename,
+                                 unsigned int nOpenFlags,
+                                 const char* const* papszAllowedDrivers,
+                                 const char* const* papszOpenOptions,
+                                 const char* const* papszSiblingFiles );
+    friend void CPL_STDCALL GDALClose( GDALDatasetH hDS );
 
     friend class GDALDriver;
     friend class GDALDefaultOverviews;
     friend class GDALProxyDataset;
     friend class GDALDriverManager;
+    
+    void AddToDatasetOpenList();
 
   protected:
     GDALDriver  *poDriver;
     GDALAccess  eAccess;
-    
+
     // Stored raster information.
     int         nRasterXSize;
     int         nRasterYSize;
@@ -280,8 +303,13 @@ class CPL_DLL GDALDataset : public GDALMajorObject
 
     int         nRefCount;
     int         bShared;
+    GByte       bIsInternal;
+    GByte       bSuppressOnClose;
+    GByte       bReserved1;
+    GByte       bReserved2;
 
                 GDALDataset(void);
+
     void        RasterInitialize( int, int );
     void        SetBand( int, GDALRasterBand * );
 
@@ -289,14 +317,22 @@ class CPL_DLL GDALDataset : public GDALMajorObject
     
     virtual CPLErr IBuildOverviews( const char *, int, int *,
                                     int, int *, GDALProgressFunc, void * );
-    
+
+#ifdef DETECT_OLD_IRASTERIO
+    virtual signature_changed IRasterIO( GDALRWFlag, int, int, int, int,
+                              void *, int, int, GDALDataType,
+                              int, int *, int, int, int ) {};
+#endif
+
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int *, int, int, int );
+                              int, int *, GSpacing, GSpacing, GSpacing,
+                              GDALRasterIOExtraArg* psExtraArg );
 
     CPLErr BlockBasedRasterIO( GDALRWFlag, int, int, int, int,
                                void *, int, int, GDALDataType,
-                               int, int *, int, int, int );
+                               int, int *, GSpacing, GSpacing, GSpacing,
+                               GDALRasterIOExtraArg* psExtraArg );
     void   BlockBasedFlushCache();
 
     CPLErr ValidateRasterIOOrAdviseReadParameters(
@@ -307,6 +343,10 @@ class CPL_DLL GDALDataset : public GDALMajorObject
                                int nBandCount, int *panBandMap);
 
     virtual int         CloseDependentDatasets();
+    
+    int                 ValidateLayerCreationOptions( const char* const* papszLCO );
+    
+    char            **papszOpenOptions;
 
     friend class GDALRasterBand;
     
@@ -332,7 +372,9 @@ class CPL_DLL GDALDataset : public GDALMajorObject
     virtual void *GetInternalHandle( const char * );
     virtual GDALDriver *GetDriver(void);
     virtual char      **GetFileList(void);
-
+    
+    virtual     const char* GetDriverName();
+    
     virtual int    GetGCPCount();
     virtual const char *GetGCPProjection();
     virtual const GDAL_GCP *GetGCPs();
@@ -345,7 +387,7 @@ class CPL_DLL GDALDataset : public GDALMajorObject
                                int nBandCount, int *panBandList,
                                char **papszOptions );
 
-    virtual CPLErr          CreateMaskBand( int nFlags );
+    virtual CPLErr          CreateMaskBand( int nFlagsIn );
 
     virtual GDALAsyncReader* 
         BeginAsyncReader(int nXOff, int nYOff, int nXSize, int nYSize,
@@ -358,7 +400,12 @@ class CPL_DLL GDALDataset : public GDALMajorObject
 
     CPLErr      RasterIO( GDALRWFlag, int, int, int, int,
                           void *, int, int, GDALDataType,
-                          int, int *, int, int, int );
+                          int, int *, GSpacing, GSpacing, GSpacing,
+                          GDALRasterIOExtraArg* psExtraArg
+#ifndef DOXYGEN_SKIP
+                          OPTIONAL_OUTSIDE_GDAL(NULL)
+#endif
+                          );
 
     int           Reference();
     int           Dereference();
@@ -366,6 +413,10 @@ class CPL_DLL GDALDataset : public GDALMajorObject
 
     int           GetShared();
     void          MarkAsShared();
+    
+    void          MarkSuppressOnClose() { bSuppressOnClose = TRUE; }
+    
+    char        **GetOpenOptions() { return papszOpenOptions; }
 
     static GDALDataset **GetOpenDatasets( int *pnDatasetCount );
 
@@ -373,6 +424,77 @@ class CPL_DLL GDALDataset : public GDALMajorObject
                            int, int *, GDALProgressFunc, void * );
 
     void ReportError(CPLErr eErrClass, int err_no, const char *fmt, ...)  CPL_PRINT_FUNC_FORMAT (4, 5);
+
+private:
+    CPLMutex        *m_hMutex;
+
+    OGRLayer*       BuildLayerFromSelectInfo(swq_select* psSelectInfo,
+                                             OGRGeometry *poSpatialFilter,
+                                             const char *pszDialect,
+                                             swq_select_parse_options* poSelectParseOptions);
+
+  public:
+
+    virtual int         GetLayerCount();
+    virtual OGRLayer    *GetLayer(int);
+    virtual OGRLayer    *GetLayerByName(const char *);
+    virtual OGRErr      DeleteLayer(int);
+
+    virtual int         TestCapability( const char * );
+
+    virtual OGRLayer   *CreateLayer( const char *pszName, 
+                                     OGRSpatialReference *poSpatialRef = NULL,
+                                     OGRwkbGeometryType eGType = wkbUnknown,
+                                     char ** papszOptions = NULL );
+    virtual OGRLayer   *CopyLayer( OGRLayer *poSrcLayer, 
+                                   const char *pszNewName, 
+                                   char **papszOptions = NULL );
+
+    virtual OGRStyleTable *GetStyleTable();
+    virtual void        SetStyleTableDirectly( OGRStyleTable *poStyleTable );
+                            
+    virtual void        SetStyleTable(OGRStyleTable *poStyleTable);
+
+    virtual OGRLayer *  ExecuteSQL( const char *pszStatement,
+                                    OGRGeometry *poSpatialFilter,
+                                    const char *pszDialect );
+    virtual void        ReleaseResultSet( OGRLayer * poResultsSet );
+
+    int                 GetRefCount() const;
+    int                 GetSummaryRefCount() const;
+    OGRErr              Release();
+
+    virtual OGRErr      StartTransaction(int bForce=FALSE);
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
+    
+    static int          IsGenericSQLDialect(const char* pszDialect);
+    
+    // Semi-public methods. Only to be used by in-tree drivers.
+    GDALSQLParseInfo*   BuildParseInfo(swq_select* psSelectInfo,
+                                       swq_select_parse_options* poSelectParseOptions);
+    void                DestroyParseInfo(GDALSQLParseInfo* psParseInfo );
+    OGRLayer *          ExecuteSQL( const char *pszStatement,
+                                    OGRGeometry *poSpatialFilter,
+                                    const char *pszDialect,
+                                    swq_select_parse_options* poSelectParseOptions);
+
+  protected:
+
+    virtual OGRLayer   *ICreateLayer( const char *pszName, 
+                                     OGRSpatialReference *poSpatialRef = NULL,
+                                     OGRwkbGeometryType eGType = wkbUnknown,
+                                     char ** papszOptions = NULL );
+
+    OGRErr              ProcessSQLCreateIndex( const char * );
+    OGRErr              ProcessSQLDropIndex( const char * );
+    OGRErr              ProcessSQLDropTable( const char * );
+    OGRErr              ProcessSQLAlterTableAddColumn( const char * );
+    OGRErr              ProcessSQLAlterTableDropColumn( const char * );
+    OGRErr              ProcessSQLAlterTableAlterColumn( const char * );
+    OGRErr              ProcessSQLAlterTableRenameColumn( const char * );
+
+    OGRStyleTable      *m_poStyleTable;
 };
 
 /* ******************************************************************** */
@@ -400,6 +522,11 @@ class CPL_DLL GDALRasterBlock
     
     GDALRasterBlock     *poNext;
     GDALRasterBlock     *poPrevious;
+    
+    int                  bMustDetach;
+    
+    void        Touch_unlocked( void );
+    void        Detach_unlocked( void );
 
   public:
                 GDALRasterBlock( GDALRasterBand *, int, int );
@@ -424,12 +551,14 @@ class CPL_DLL GDALRasterBlock
     int         GetLockCount() { return nLockCount; }
 
     void        *GetDataRef( void ) { return pData; }
+    int          GetBlockSize() { return nXSize * nYSize * (GDALGetDataTypeSize(eType) / 8); }
 
     /// @brief Accessor to source GDALRasterBand object.
     /// @return source raster band of the raster block.
     GDALRasterBand *GetBand() { return poBand; }
 
-    static int  FlushCacheBlock();
+    static void FlushDirtyBlocks();
+    static int  FlushCacheBlock(int bDirtyBlocksOnly = FALSE);
     static void Verify();
 
     static int  SafeLockBlock( GDALRasterBlock ** );
@@ -455,6 +584,7 @@ public:
                 ~GDALColorTable();
 
     GDALColorTable *Clone() const;
+    int             IsSame(const GDALColorTable* poOtherCT) const;
 
     GDALPaletteInterp GetPaletteInterpretation() const;
 
@@ -480,6 +610,7 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
     void           SetFlushBlockErr( CPLErr eErr );
 
     friend class GDALRasterBlock;
+    CPLErr         UnreferenceBlock( int nXBlockOff, int nYBlockOff );
 
   protected:
     GDALDataset *poDS;
@@ -515,15 +646,25 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
     friend class GDALProxyRasterBand;
     friend class GDALDefaultOverviews;
 
+    CPLErr RasterIOResampled( GDALRWFlag, int, int, int, int,
+                              void *, int, int, GDALDataType,
+                              GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
   protected:
     virtual CPLErr IReadBlock( int, int, void * ) = 0;
     virtual CPLErr IWriteBlock( int, int, void * );
+
+#ifdef DETECT_OLD_IRASTERIO
+    virtual signature_changed IRasterIO( GDALRWFlag, int, int, int, int,
+                              void *, int, int, GDALDataType,
+                              int, int ) {};
+#endif
+
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
     CPLErr         OverviewRasterIO( GDALRWFlag, int, int, int, int,
                                      void *, int, int, GDALDataType,
-                                     int, int );
+                                     GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
 
     int            InitBlockInfo();
 
@@ -546,7 +687,11 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
     
     CPLErr      RasterIO( GDALRWFlag, int, int, int, int,
                           void *, int, int, GDALDataType,
-                          int, int );
+                          GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg
+#ifndef DOXYGEN_SKIP
+                          OPTIONAL_OUTSIDE_GDAL(NULL)
+#endif
+                          );
     CPLErr      ReadBlock( int, int, void * );
 
     CPLErr      WriteBlock( int, int, void * );
@@ -595,7 +740,7 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
     virtual int HasArbitraryOverviews();
     virtual int GetOverviewCount();
     virtual GDALRasterBand *GetOverview(int);
-    virtual GDALRasterBand *GetRasterSampleOverview( int );
+    virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig );
     virtual CPLErr BuildOverviews( const char *, int, int *,
                                    GDALProgressFunc, void * );
 
@@ -604,23 +749,23 @@ class CPL_DLL GDALRasterBand : public GDALMajorObject
                                GDALDataType eDT, char **papszOptions );
 
     virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                          int nBuckets, int * panHistogram,
+                          int nBuckets, GUIntBig * panHistogram,
                           int bIncludeOutOfRange, int bApproxOK,
                           GDALProgressFunc, void *pProgressData );
 
     virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                        int *pnBuckets, int ** ppanHistogram,
+                                        int *pnBuckets, GUIntBig ** ppanHistogram,
                                         int bForce,
                                         GDALProgressFunc, void *pProgressData);
     virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int *panHistogram );
+                                        int nBuckets, GUIntBig *panHistogram );
 
     virtual GDALRasterAttributeTable *GetDefaultRAT();
     virtual CPLErr SetDefaultRAT( const GDALRasterAttributeTable * );
 
     virtual GDALRasterBand *GetMaskBand();
     virtual int             GetMaskFlags();
-    virtual CPLErr          CreateMaskBand( int nFlags );
+    virtual CPLErr          CreateMaskBand( int nFlagsIn );
 
     virtual CPLVirtualMem  *GetVirtualMemAuto( GDALRWFlag eRWFlag,
                                                int *pnPixelSpace,
@@ -660,7 +805,7 @@ class CPL_DLL GDALNoDataMaskBand : public GDALRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
 
   public:
                 GDALNoDataMaskBand( GDALRasterBand * );
@@ -696,7 +841,7 @@ class GDALRescaledAlphaBand : public GDALRasterBand
     virtual CPLErr IReadBlock( int, int, void * );
     virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                               void *, int, int, GDALDataType,
-                              int, int );
+                              GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
 
   public:
                 GDALRescaledAlphaBand( GDALRasterBand * );
@@ -725,6 +870,10 @@ class CPL_DLL GDALDriver : public GDALMajorObject
                         GDALDriver();
                         ~GDALDriver();
 
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                 const char * pszValue,
+                                 const char * pszDomain = "" );
+
 /* -------------------------------------------------------------------- */
 /*      Public C++ methods.                                             */
 /* -------------------------------------------------------------------- */
@@ -742,7 +891,7 @@ class CPL_DLL GDALDriver : public GDALMajorObject
                                      int, char **,
                                      GDALProgressFunc pfnProgress, 
                                      void * pProgressData ) CPL_WARN_UNUSED_RESULT;
-    
+
 /* -------------------------------------------------------------------- */
 /*      The following are semiprivate, not intended to be accessed      */
 /*      by anyone but the formats instantiating and populating the      */
@@ -766,6 +915,10 @@ class CPL_DLL GDALDriver : public GDALMajorObject
 
     void                (*pfnUnloadDriver)(GDALDriver *);
 
+    /* Return 1 if the passed file is certainly recognized by the driver */
+    /* Return 0 if the passed file is certainly NOT recognized by the driver */
+    /* Return -1 if the passed file may be or may not be recognized by the driver,
+       and that a potentially costly test must be done with pfnOpen */
     int                 (*pfnIdentify)( GDALOpenInfo * );
 
     CPLErr              (*pfnRename)( const char * pszNewName,
@@ -773,6 +926,14 @@ class CPL_DLL GDALDriver : public GDALMajorObject
     CPLErr              (*pfnCopyFiles)( const char * pszNewName,
                                          const char * pszOldName );
 
+    /* For legacy OGR drivers */
+    GDALDataset         *(*pfnOpenWithDriverArg)( GDALDriver*, GDALOpenInfo * );
+    GDALDataset         *(*pfnCreateVectorOnly)( GDALDriver*,
+                                                 const char * pszName,
+                                                 char ** papszOptions );
+    CPLErr              (*pfnDeleteDataSource)( GDALDriver*,
+                                                 const char * pszName );
+
 /* -------------------------------------------------------------------- */
 /*      Helper methods.                                                 */
 /* -------------------------------------------------------------------- */
@@ -806,8 +967,13 @@ class CPL_DLL GDALDriverManager : public GDALMajorObject
 {
     int         nDrivers;
     GDALDriver  **papoDrivers;
-
-    char        *pszHome;
+    std::map<CPLString, GDALDriver*> oMapNameToDrivers;
+    
+    GDALDriver  *GetDriver_unlocked( int iDriver )
+            { return (iDriver >= 0 && iDriver < nDrivers) ? papoDrivers[iDriver] : NULL; }
+    
+    GDALDriver  *GetDriverByName_unlocked( const char * pszName )
+            { return oMapNameToDrivers[CPLString(pszName).toupper()]; }
     
  public:
                 GDALDriverManager();
@@ -818,14 +984,10 @@ class CPL_DLL GDALDriverManager : public GDALMajorObject
     GDALDriver  *GetDriverByName( const char * );
 
     int         RegisterDriver( GDALDriver * );
-    void        MoveDriver( GDALDriver *, int );
     void        DeregisterDriver( GDALDriver * );
 
     void        AutoLoadDrivers();
     void        AutoSkipDrivers();
-
-    const char *GetHome();
-    void        SetHome( const char * );
 };
 
 CPL_C_START
@@ -898,6 +1060,29 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
                                  const char * pszResampling, 
                                  GDALProgressFunc pfnProgress, void * pProgressData );
 
+typedef CPLErr (*GDALResampleFunction)
+                      ( double dfXRatioDstToSrc,
+                        double dfYRatioDstToSrc,
+                        double dfSrcXDelta,
+                        double dfSrcYDelta,
+                        GDALDataType eWrkDataType,
+                        void * pChunk,
+                        GByte * pabyChunkNodataMask,
+                        int nChunkXOff, int nChunkXSize,
+                        int nChunkYOff, int nChunkYSize,
+                        int nDstXOff, int nDstXOff2,
+                        int nDstYOff, int nDstYOff2,
+                        GDALRasterBand * poOverview,
+                        const char * pszResampling,
+                        int bHasNoData, float fNoDataValue,
+                        GDALColorTable* poColorTable,
+                        GDALDataType eSrcDataType);
+
+GDALResampleFunction GDALGetResampleFunction(const char* pszResampling,
+                                                 int* pnRadius);
+GDALDataType GDALGetOvrWorkDataType(const char* pszResampling,
+                                        GDALDataType eSrcDataType);
+
 CPL_C_START
 
 #ifndef WIN32CE
@@ -930,9 +1115,17 @@ GDALDefaultBuildOverviews( GDALDataset *hSrcDS, const char * pszBasename,
 int CPL_DLL GDALBandGetBestOverviewLevel(GDALRasterBand* poBand,
                                          int &nXOff, int &nYOff,
                                          int &nXSize, int &nYSize,
-                                         int nBufXSize, int nBufYSize);
+                                         int nBufXSize, int nBufYSize) CPL_WARN_DEPRECATED("Use GDALBandGetBestOverviewLevel2 instead");
+int CPL_DLL GDALBandGetBestOverviewLevel2(GDALRasterBand* poBand,
+                                         int &nXOff, int &nYOff,
+                                         int &nXSize, int &nYSize,
+                                         int nBufXSize, int nBufYSize,
+                                         GDALRasterIOExtraArg* psExtraArg);
 
-int CPL_DLL GDALOvLevelAdjust( int nOvLevel, int nXSize );
+int CPL_DLL GDALOvLevelAdjust( int nOvLevel, int nXSize ) CPL_WARN_DEPRECATED("Use GDALOvLevelAdjust2 instead");
+int CPL_DLL GDALOvLevelAdjust2( int nOvLevel, int nXSize, int nYSize );
+int CPL_DLL GDALComputeOvFactor( int nOvrXSize, int nRasterXSize,
+                                 int nOvrYSize, int nRasterYSize );
 
 GDALDataset CPL_DLL *
 GDALFindAssociatedAuxFile( const char *pszBasefile, GDALAccess eAccess,
@@ -955,7 +1148,7 @@ int CPL_DLL GDALCheckDatasetDimensions( int nXSize, int nYSize );
 int CPL_DLL GDALCheckBandCount( int nBands, int bIsZeroAllowed );
 
 
-// Test if 2 floating point values match. Usefull when comparing values
+// Test if 2 floating point values match. Useful when comparing values
 // stored as a string at some point. See #3573, #4183, #4506
 #define ARE_REAL_EQUAL(dfVal1, dfVal2) \
  (dfVal1 == dfVal2 || fabs(dfVal1 - dfVal2) < 1e-10 || (dfVal2 != 0 && fabs(1 - dfVal1 / dfVal2) < 1e-10 ))
@@ -971,11 +1164,14 @@ int GDALReadTabFile2( const char * pszBaseFilename,
                       int *pnGCPCount, GDAL_GCP **ppasGCPs,
                       char** papszSiblingFiles, char** ppszTabFileNameOut );
 
+void CPL_DLL GDALCopyRasterIOExtraArg(GDALRasterIOExtraArg* psDestArg,
+                                      GDALRasterIOExtraArg* psSrcArg);
+
 CPL_C_END
 
 void GDALNullifyOpenDatasetsList();
-void** GDALGetphDMMutex();
-void** GDALGetphDLMutex();
+CPLMutex** GDALGetphDMMutex();
+CPLMutex** GDALGetphDLMutex();
 void GDALNullifyProxyPoolSingleton();
 GDALDriver* GDALGetAPIPROXYDriver();
 void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID);
@@ -989,6 +1185,23 @@ CPLErr EXIFExtractMetadata(char**& papszMetadata,
                            int bSwabflag, int nTIFFHEADER,
                            int& nExifOffset, int& nInterOffset, int& nGPSOffset);
 
+int GDALValidateOpenOptions( GDALDriverH hDriver,
+                             const char* const* papszOptionOptions);
+int GDALValidateOptions( const char* pszOptionList,
+                         const char* const* papszOptionsToValidate,
+                         const char* pszErrorMessageOptionType,
+                         const char* pszErrorMessageContainerName);
+
+GDALRIOResampleAlg GDALRasterIOGetResampleAlg(const char* pszResampling);
+
+void GDALRasterIOExtraArgSetResampleAlg(GDALRasterIOExtraArg* psExtraArg,
+                                        int nXSize, int nYSize,
+                                        int nBufXSize, int nBufYSize);
+
+/* CPL_DLL exported, but only for gdalwarp */
+GDALDataset CPL_DLL* GDALCreateOverviewDataset(GDALDataset* poDS, int nOvrLevel,
+                                               int bThisLevelOnly, int bOwnDS);
+
 #define DIV_ROUND_UP(a, b) ( ((a) % (b)) == 0 ? ((a) / (b)) : (((a) / (b)) + 1) )
 
 // Number of data samples that will be used to compute approximate statistics
@@ -1008,4 +1221,9 @@ void GDALDeserializeGCPListFromXML( CPLXMLNode* psGCPList,
                                     char** ppszGCPProjection );
 CPL_C_END
 
+void GDALSerializeOpenOptionsToXML( CPLXMLNode* psParentNode, char** papszOpenOptions);
+char** GDALDeserializeOpenOptionsFromXML( CPLXMLNode* psParentNode );
+
+int GDALCanFileAcceptSidecarFile(const char* pszFilename);
+
 #endif /* ndef GDAL_PRIV_H_INCLUDED */
diff --git a/gcore/gdal_proxy.h b/gcore/gdal_proxy.h
index cb0351f..a007056 100644
--- a/gcore/gdal_proxy.h
+++ b/gcore/gdal_proxy.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_proxy.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdal_proxy.h 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  GDAL Core C++/Private declarations
@@ -51,7 +51,8 @@ class CPL_DLL GDALProxyDataset : public GDALDataset
                                     int, int *, GDALProgressFunc, void * );
         virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                                 void *, int, int, GDALDataType,
-                                int, int *, int, int, int );
+                                int, int *, GSpacing, GSpacing, GSpacing,
+                                GDALRasterIOExtraArg* psExtraArg );
     public:
 
         virtual char      **GetMetadataDomainList();
@@ -106,7 +107,7 @@ class CPL_DLL GDALProxyRasterBand : public GDALRasterBand
         virtual CPLErr IWriteBlock( int, int, void * );
         virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
                                 void *, int, int, GDALDataType,
-                                int, int );
+                                GSpacing, GSpacing, GDALRasterIOExtraArg* psExtraArg );
 
     public:
 
@@ -153,7 +154,7 @@ class CPL_DLL GDALProxyRasterBand : public GDALRasterBand
         virtual int HasArbitraryOverviews();
         virtual int GetOverviewCount();
         virtual GDALRasterBand *GetOverview(int);
-        virtual GDALRasterBand *GetRasterSampleOverview( int );
+        virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig );
         virtual CPLErr BuildOverviews( const char *, int, int *,
                                     GDALProgressFunc, void * );
 
@@ -162,16 +163,16 @@ class CPL_DLL GDALProxyRasterBand : public GDALRasterBand
                                 GDALDataType eDT, char **papszOptions );
 
         virtual CPLErr  GetHistogram( double dfMin, double dfMax,
-                            int nBuckets, int * panHistogram,
+                            int nBuckets, GUIntBig * panHistogram,
                             int bIncludeOutOfRange, int bApproxOK,
                             GDALProgressFunc, void *pProgressData );
 
         virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                            int *pnBuckets, int ** ppanHistogram,
+                                            int *pnBuckets, GUIntBig ** ppanHistogram,
                                             int bForce,
                                             GDALProgressFunc, void *pProgressData);
         virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                            int nBuckets, int *panHistogram );
+                                            int nBuckets, GUIntBig *panHistogram );
 
         virtual GDALRasterAttributeTable *GetDefaultRAT();
         virtual CPLErr SetDefaultRAT( const GDALRasterAttributeTable * );
@@ -226,6 +227,7 @@ class CPL_DLL GDALProxyPoolDataset : public GDALProxyDataset
                             double * padfGeoTransform = NULL);
         ~GDALProxyPoolDataset();
 
+        void         SetOpenOptions(char** papszOpenOptions);
         void         AddSrcBandDescription( GDALDataType eDataType, int nBlockXSize, int nBlockYSize);
 
         virtual const char *GetProjectionRef(void);
@@ -296,7 +298,7 @@ class CPL_DLL GDALProxyPoolRasterBand : public GDALProxyRasterBand
         virtual const char *GetUnitType();
         virtual GDALColorTable *GetColorTable();
         virtual GDALRasterBand *GetOverview(int);
-        virtual GDALRasterBand *GetRasterSampleOverview( int nDesiredSamples); // TODO
+        virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig nDesiredSamples); // TODO
         virtual GDALRasterBand *GetMaskBand();
 
 };
diff --git a/gcore/gdal_rat.cpp b/gcore/gdal_rat.cpp
index def5d2a..37d6201 100644
--- a/gcore/gdal_rat.cpp
+++ b/gcore/gdal_rat.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_rat.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdal_rat.cpp 28016 2014-11-26 15:13:41Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALRasterAttributeTable and related classes.
@@ -31,7 +31,7 @@
 #include "gdal_priv.h"
 #include "gdal_rat.h"
 
-CPL_CVSID("$Id: gdal_rat.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdal_rat.cpp 28016 2014-11-26 15:13:41Z rouault $");
 
 /**
  * \class GDALRasterAttributeTable
@@ -374,7 +374,7 @@ int GDALRasterAttributeTable::GetRowOfValue( int nValue ) const
  * @return CE_None on success or CE_Failure if something goes wrong.
  */
 
-CPLErr GDALRasterAttributeTable::CreateColumn( CPL_UNUSED const char *pszFieldName, 
+CPLErr GDALRasterAttributeTable::CreateColumn( CPL_UNUSED const char *pszFieldName,
                                                CPL_UNUSED GDALRATFieldType eFieldType,
                                                CPL_UNUSED GDALRATFieldUsage eFieldUsage )
 {
@@ -422,7 +422,7 @@ CPLErr CPL_STDCALL GDALRATCreateColumn( GDALRasterAttributeTableH hRAT,
  * @return CE_None on success or CE_Failure on failure.
  */
 
-CPLErr GDALRasterAttributeTable::SetLinearBinning( CPL_UNUSED double dfRow0MinIn, 
+CPLErr GDALRasterAttributeTable::SetLinearBinning( CPL_UNUSED double dfRow0MinIn,
                                                    CPL_UNUSED double dfBinSizeIn )
 {
     return CE_Failure;
@@ -514,12 +514,12 @@ CPLXMLNode *GDALRasterAttributeTable::Serialize() const
 
     if( GetLinearBinning(&dfRow0Min, &dfBinSize) )
     {
-        sprintf( szValue, "%.16g", dfRow0Min );
+        CPLsprintf( szValue, "%.16g", dfRow0Min );
         CPLCreateXMLNode( 
             CPLCreateXMLNode( psTree, CXT_Attribute, "Row0Min" ), 
             CXT_Text, szValue );
 
-        sprintf( szValue, "%.16g", dfBinSize );
+        CPLsprintf( szValue, "%.16g", dfBinSize );
         CPLCreateXMLNode( 
             CPLCreateXMLNode( psTree, CXT_Attribute, "BinSize" ), 
             CXT_Text, szValue );
@@ -580,7 +580,7 @@ CPLXMLNode *GDALRasterAttributeTable::Serialize() const
             if( GetTypeOfCol(iCol) == GFT_Integer )
                 sprintf( szValue, "%d", GetValueAsInt(iRow, iCol) );
             else if( GetTypeOfCol(iCol) == GFT_Real )
-                sprintf( szValue, "%.16g", GetValueAsDouble(iRow, iCol) );
+                CPLsprintf( szValue, "%.16g", GetValueAsDouble(iRow, iCol) );
             else
                 pszValue = GetValueAsString(iRow, iCol);
 
@@ -607,8 +607,8 @@ CPLErr GDALRasterAttributeTable::XMLInit( CPLXMLNode *psTree,
     if( CPLGetXMLValue( psTree, "Row0Min", NULL ) 
         && CPLGetXMLValue( psTree, "BinSize", NULL ) )
     {
-        SetLinearBinning( atof(CPLGetXMLValue( psTree, "Row0Min","" )), 
-                          atof(CPLGetXMLValue( psTree, "BinSize","" )) );
+        SetLinearBinning( CPLAtof(CPLGetXMLValue( psTree, "Row0Min","" )), 
+                          CPLAtof(CPLGetXMLValue( psTree, "BinSize","" )) );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1353,7 +1353,7 @@ GDALDefaultRasterAttributeTable::GetValueAsDouble( int iRow, int iField ) const
         return aoFields[iField].adfValues[iRow];
 
       case GFT_String:
-        return atof( aoFields[iField].aosValues[iRow].c_str() );
+        return CPLAtof( aoFields[iField].aosValues[iRow].c_str() );
     }
 
     return 0;
@@ -1443,7 +1443,7 @@ void GDALDefaultRasterAttributeTable::SetValue( int iRow, int iField,
         break;
         
       case GFT_Real:
-        aoFields[iField].adfValues[iRow] = atof(pszValue);
+        aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
         break;
         
       case GFT_String:
@@ -1579,7 +1579,7 @@ void GDALDefaultRasterAttributeTable::SetValue( int iRow, int iField,
       {
           char szValue[100];
 
-          sprintf( szValue, "%.15g", dfValue );
+          CPLsprintf( szValue, "%.15g", dfValue );
           aoFields[iField].aosValues[iRow] = szValue;
       }
       break;
diff --git a/gcore/gdal_rpcimdio.cpp b/gcore/gdal_rpcimdio.cpp
deleted file mode 100644
index d3204d6..0000000
--- a/gcore/gdal_rpcimdio.cpp
+++ /dev/null
@@ -1,644 +0,0 @@
-/******************************************************************************
- * $Id: gdal_rpcimdio.cpp 22057 2011-03-28 15:20:21Z warmerdam $
- *
- * Project:  GDAL Core
- * Purpose:  Functions for reading RPC and IMD formats, and normalizing.
- * Author:   Frank Warmerdam, warmerdam at pobox.com
- *
- ******************************************************************************
- * Copyright (c) HER MAJESTY THE QUEEN IN RIGHT OF CANADA (2008)
- * as represented by the Canadian Nuclear Safety Commission
- *
- * 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.
- ****************************************************************************/
-
-#include "gdal.h"
-#include "gdal_priv.h"
-#include "cpl_string.h"
-#include "cplkeywordparser.h"
-
-CPL_CVSID("$Id: gdal_rpcimdio.cpp 22057 2011-03-28 15:20:21Z warmerdam $");
-
-/************************************************************************/
-/*                          GDALLoadRPBFile()                           */
-/************************************************************************/
-
-static const char *apszRPBMap[] = {
-    "LINE_OFF",       "IMAGE.lineOffset",
-    "SAMP_OFF",       "IMAGE.sampOffset",
-    "LAT_OFF",        "IMAGE.latOffset",
-    "LONG_OFF",       "IMAGE.longOffset",
-    "HEIGHT_OFF",     "IMAGE.heightOffset",
-    "LINE_SCALE",     "IMAGE.lineScale",
-    "SAMP_SCALE",     "IMAGE.sampScale",
-    "LAT_SCALE",      "IMAGE.latScale",
-    "LONG_SCALE",     "IMAGE.longScale",
-    "HEIGHT_SCALE",   "IMAGE.heightScale",
-    "LINE_NUM_COEFF", "IMAGE.lineNumCoef",
-    "LINE_DEN_COEFF", "IMAGE.lineDenCoef",
-    "SAMP_NUM_COEFF", "IMAGE.sampNumCoef",
-    "SAMP_DEN_COEFF", "IMAGE.sampDenCoef",
-    NULL,             NULL };
-
-char **CPL_STDCALL GDALLoadRPBFile( const char *pszFilename,
-                                    char **papszSiblingFiles )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Try to identify the RPB file in upper or lower case.            */
-/* -------------------------------------------------------------------- */
-    CPLString osTarget = GDALFindAssociatedFile( pszFilename, "RPB", 
-                                                 papszSiblingFiles, 0 );
-
-    if( osTarget == "" )
-        return NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Read file and parse.                                            */
-/* -------------------------------------------------------------------- */
-    CPLKeywordParser oParser;
-
-    VSILFILE *fp = VSIFOpenL( osTarget, "r" );
-
-    if( fp == NULL )
-        return NULL;
-    
-    if( !oParser.Ingest( fp ) )
-    {
-        VSIFCloseL( fp );
-        return NULL;
-    }
-
-    VSIFCloseL( fp );
-
-/* -------------------------------------------------------------------- */
-/*      Extract RPC information, in a GDAL "standard" metadata format.  */
-/* -------------------------------------------------------------------- */
-    int i;
-    char **papszMD = NULL;
-    for( i = 0; apszRPBMap[i] != NULL; i += 2 )
-    {
-        const char *pszRPBVal = oParser.GetKeyword( apszRPBMap[i+1] );
-        CPLString osAdjVal;
-
-        if( pszRPBVal == NULL )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "%s file found, but missing %s field (and possibly others).",
-                      osTarget.c_str(), apszRPBMap[i+1] );
-            CSLDestroy( papszMD );
-            return NULL;
-        }
-
-        if( strchr(pszRPBVal,',') == NULL )
-            osAdjVal = pszRPBVal;
-        else
-        {
-            // strip out commas and turn newlines into spaces.
-            int j;
-
-            for( j = 0; pszRPBVal[j] != '\0'; j++ )
-            {
-                switch( pszRPBVal[j] ) 
-                {
-                  case ',':
-                  case '\n':
-                  case '\r':
-                    osAdjVal += ' ';
-                    break;
-                    
-                  case '(':
-                  case ')':
-                    break;
-
-                  default:
-                    osAdjVal += pszRPBVal[j];
-                }
-            }
-        }
-
-        papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], osAdjVal );
-    }
-
-    return papszMD;
-}
-
-/************************************************************************/
-/*                          GDALLoadRPCFile()                           */
-/************************************************************************/
-
-/* Load a GeoEye _rpc.txt file. See ticket http://trac.osgeo.org/gdal/ticket/3639 */
-
-char **CPL_STDCALL GDALLoadRPCFile( const char *pszFilename,
-                                    char **papszSiblingFiles )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Try to identify the RPC file in upper or lower case.            */
-/* -------------------------------------------------------------------- */
-    CPLString osTarget; 
-
-    /* Is this already a _RPC.TXT file ? */
-    if (strlen(pszFilename) > 8 && EQUAL(pszFilename + strlen(pszFilename) - 8, "_RPC.TXT"))
-        osTarget = pszFilename;
-    else
-    {
-        CPLString osSrcPath = pszFilename;
-        CPLString soPt(".");
-        size_t found = osSrcPath.rfind(soPt);
-        if (found == CPLString::npos)
-            return NULL;
-        osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
-        CPLString osTarget = osSrcPath; 
-
-        if( papszSiblingFiles == NULL )
-        {
-            VSIStatBufL sStatBuf;
-
-            if( VSIStatL( osTarget, &sStatBuf ) != 0 )
-            {
-                osSrcPath = pszFilename;
-                osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
-                osTarget = osSrcPath; 
-
-                if( VSIStatL( osTarget, &sStatBuf ) != 0 )
-                {
-                    osSrcPath = pszFilename;
-                    osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
-                    osTarget = osSrcPath; 
-
-                    if( VSIStatL( osTarget, &sStatBuf ) != 0 )
-                    {
-                        return NULL;
-                    }
-                }
-            }
-        }
-        else
-        {
-            int iSibling = CSLFindString( papszSiblingFiles, 
-                                        CPLGetFilename(osTarget) );
-            if( iSibling < 0 )
-                return NULL;
-
-            osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
-            osTarget += papszSiblingFiles[iSibling];
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Read file and parse.                                            */
-/* -------------------------------------------------------------------- */
-    char **papszLines = CSLLoad2( osTarget, 100, 100, NULL );
-    if(!papszLines)
-        return NULL;
-
-    char **papszMD = NULL;
-
-    /* From LINE_OFF to HEIGHT_SCALE */
-    for(size_t i = 0; i < 19; i += 2 )
-    {
-        const char *pszRPBVal = CSLFetchNameValue(papszLines, apszRPBMap[i] );
-        if( pszRPBVal == NULL )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                "%s file found, but missing %s field (and possibly others).",
-                osTarget.c_str(), apszRPBMap[i]);
-            CSLDestroy( papszMD );
-            CSLDestroy( papszLines );
-            return NULL;
-        }
-        else
-        {
-            papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], pszRPBVal );
-        }
-    }
-       
-    /* For LINE_NUM_COEFF, LINE_DEN_COEFF, SAMP_NUM_COEFF, SAMP_DEN_COEFF */
-    /* parameters that have 20 values each */
-    for(size_t i = 20; apszRPBMap[i] != NULL; i += 2 )
-    {
-        CPLString soVal;
-        for(int j = 1; j <= 20; j++)
-        {
-            CPLString soRPBMapItem;
-            soRPBMapItem.Printf("%s_%d", apszRPBMap[i], j);
-            const char *pszRPBVal = CSLFetchNameValue(papszLines, soRPBMapItem.c_str() );
-            if( pszRPBVal == NULL )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined,
-                    "%s file found, but missing %s field (and possibly others).",
-                    osTarget.c_str(), soRPBMapItem.c_str() );
-                CSLDestroy( papszMD );
-                CSLDestroy( papszLines );
-                return NULL;
-            }
-            else
-            {
-                soVal += pszRPBVal;
-                soVal += " ";
-            }
-        }
-        papszMD = CSLSetNameValue( papszMD, apszRPBMap[i], soVal.c_str() );
-    }
-
-    CSLDestroy( papszLines );
-    return papszMD;
-}
-
-/************************************************************************/
-/*                          GDALWriteRPBFile()                          */
-/************************************************************************/
-
-CPLErr CPL_STDCALL GDALWriteRPBFile( const char *pszFilename, char **papszMD )
-
-{
-    CPLString osRPBFilename = CPLResetExtension( pszFilename, "RPB" );
-    
-
-/* -------------------------------------------------------------------- */
-/*      Read file and parse.                                            */
-/* -------------------------------------------------------------------- */
-    VSILFILE *fp = VSIFOpenL( osRPBFilename, "w" );
-
-    if( fp == NULL )
-    {
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                  "Unable to create %s for writing.\n%s", 
-                  osRPBFilename.c_str(), CPLGetLastErrorMsg() );
-        return CE_Failure;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Write the prefix information.                                   */
-/* -------------------------------------------------------------------- */
-    VSIFPrintfL( fp, "%s", "satId = \"QB02\";\n" );
-    VSIFPrintfL( fp, "%s", "bandId = \"P\";\n" );
-    VSIFPrintfL( fp, "%s", "SpecId = \"RPC00B\";\n" );
-    VSIFPrintfL( fp, "%s", "BEGIN_GROUP = IMAGE\n" );
-    VSIFPrintfL( fp, "%s", "\terrBias = 0.0;\n" );
-    VSIFPrintfL( fp, "%s", "\terrRand = 0.0;\n" );
-
-/* -------------------------------------------------------------------- */
-/*      Write RPC values from our RPC metadata.                         */
-/* -------------------------------------------------------------------- */
-    int i;
-
-    for( i = 0; apszRPBMap[i] != NULL; i += 2 )
-    {
-        const char *pszRPBVal = CSLFetchNameValue( papszMD, apszRPBMap[i] );
-        const char *pszRPBTag;
-
-        if( pszRPBVal == NULL )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "%s field missing in metadata, %s file not written.",
-                      apszRPBMap[i], osRPBFilename.c_str() );
-            VSIFCloseL( fp );
-            VSIUnlink( osRPBFilename );
-            return CE_Failure;
-        }
-
-        pszRPBTag = apszRPBMap[i+1];
-        if( EQUALN(pszRPBTag,"IMAGE.",6) )
-            pszRPBTag += 6;
-
-        if( strstr(apszRPBMap[i], "COEF" ) == NULL )
-        {
-            VSIFPrintfL( fp, "\t%s = %s;\n", pszRPBTag, pszRPBVal );
-        }
-        else
-        {
-            // Reformat in brackets with commas over multiple lines.
-
-            VSIFPrintfL( fp, "\t%s = (\n", pszRPBTag );
-
-            char **papszItems = CSLTokenizeStringComplex( pszRPBVal, " ,", 
-                                                          FALSE, FALSE );
-
-            if( CSLCount(papszItems) != 20 )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined,
-                          "%s field is corrupt (not 20 values), %s file not written.\n%s = %s",
-                          apszRPBMap[i], osRPBFilename.c_str(),
-                          apszRPBMap[i], pszRPBVal );
-                VSIFCloseL( fp );
-                VSIUnlink( osRPBFilename );
-                return CE_Failure;
-            }
-
-            int j;
-
-            for( j = 0; j < 20; j++ )
-            {
-                if( j < 19 )
-                    VSIFPrintfL( fp, "\t\t\t%s,\n", papszItems[j] );
-                else
-                    VSIFPrintfL( fp, "\t\t\t%s);\n", papszItems[j] );
-            }
-            CSLDestroy( papszItems );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Write end part                                                  */
-/* -------------------------------------------------------------------- */
-    VSIFPrintfL( fp, "%s", "END_GROUP = IMAGE\n" );
-    VSIFPrintfL( fp, "END;\n" );
-    VSIFCloseL( fp );
-    
-    return CE_None;
-}
-
-/************************************************************************/
-/*                           GDAL_IMD_AA2R()                            */
-/*                                                                      */
-/*      Translate AA version IMD file to R version.                     */
-/************************************************************************/
-
-static int GDAL_IMD_AA2R( char ***ppapszIMD )
-
-{
-    char **papszIMD = *ppapszIMD;
-
-/* -------------------------------------------------------------------- */
-/*      Verify that we have a new format file.                          */
-/* -------------------------------------------------------------------- */
-    const char *pszValue = CSLFetchNameValue( papszIMD, "version" );
-    
-    if( pszValue == NULL )
-        return FALSE;
-    
-    if( EQUAL(pszValue,"\"R\"") )
-        return TRUE;
-
-    if( !EQUAL(pszValue,"\"AA\"") )
-    {
-        CPLDebug( "IMD", "The file is not the expected 'version = \"AA\"' format.\nProceeding, but file may be corrupted." );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Fix the version line.                                           */
-/* -------------------------------------------------------------------- */
-    papszIMD = CSLSetNameValue( papszIMD, "version", "\"R\"" );
-
-/* -------------------------------------------------------------------- */
-/*      remove a bunch of fields.                                       */
-/* -------------------------------------------------------------------- */
-    int iKey;
-
-    static const char *apszToRemove[] = {
-        "productCatalogId",
-        "childCatalogId",
-        "productType",
-        "numberOfLooks",
-        "effectiveBandwidth",
-        "mode",
-        "scanDirection",
-        "cloudCover",
-        "productGSD",
-        NULL };
-
-    for( iKey = 0; apszToRemove[iKey] != NULL; iKey++ )
-    {
-        int iTarget = CSLFindName( papszIMD, apszToRemove[iKey] );
-        if( iTarget != -1 )
-            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Replace various min/mean/max with just the mean.                */
-/* -------------------------------------------------------------------- */
-    static const char *keylist[] = { 
-        "CollectedRowGSD",
-        "CollectedColGSD",
-        "SunAz",
-        "SunEl",
-        "SatAz",
-        "SatEl",
-        "InTrackViewAngle",
-        "CrossTrackViewAngle",
-        "OffNadirViewAngle",
-        NULL };
-
-    for( iKey = 0; keylist[iKey] != NULL; iKey++ )
-    {
-        CPLString osTarget;
-        int       iTarget;
-
-        osTarget.Printf( "IMAGE_1.min%s", keylist[iKey] );
-        iTarget = CSLFindName( papszIMD, osTarget );
-        if( iTarget != -1 )
-            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
-
-        osTarget.Printf( "IMAGE_1.max%s", keylist[iKey] );
-        iTarget = CSLFindName( papszIMD, osTarget );
-        if( iTarget != -1 )
-            papszIMD = CSLRemoveStrings( papszIMD, iTarget, 1, NULL );
-
-        osTarget.Printf( "IMAGE_1.mean%s", keylist[iKey] );
-        iTarget = CSLFindName( papszIMD, osTarget );
-        if( iTarget != -1 )
-        {
-            CPLString osValue = CSLFetchNameValue( papszIMD, osTarget );
-            CPLString osLine;
-            
-            osTarget.Printf( "IMAGE_1.%c%s", 
-                             tolower(keylist[iKey][0]), 
-                             keylist[iKey]+1 );
-
-            osLine = osTarget + "=" + osValue;
-
-            CPLFree( papszIMD[iTarget] );
-            papszIMD[iTarget] = CPLStrdup(osLine);
-        }
-    }
-
-    *ppapszIMD = papszIMD;
-    return TRUE;
-}
-
-/************************************************************************/
-/*                          GDALLoadIMDFile()                           */
-/************************************************************************/
-
-char ** CPL_STDCALL GDALLoadIMDFile( const char *pszFilename,
-                                     char **papszSiblingFiles )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Try to identify the IMD file in upper or lower case.            */
-/* -------------------------------------------------------------------- */
-    CPLString osTarget = GDALFindAssociatedFile( pszFilename, "IMD", 
-                                                 papszSiblingFiles, 0 );
-
-    if( osTarget == "" )
-        return NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Read file and parse.                                            */
-/* -------------------------------------------------------------------- */
-    CPLKeywordParser oParser;
-
-    VSILFILE *fp = VSIFOpenL( osTarget, "r" );
-
-    if( fp == NULL )
-        return NULL;
-    
-    if( !oParser.Ingest( fp ) )
-    {
-        VSIFCloseL( fp );
-        return NULL;
-    }
-
-    VSIFCloseL( fp );
-
-/* -------------------------------------------------------------------- */
-/*      Consider version changing.                                      */
-/* -------------------------------------------------------------------- */
-    char **papszIMD = CSLDuplicate( oParser.GetAllKeywords() );
-    const char *pszVersion = CSLFetchNameValue( papszIMD, "version" );
-
-    if( pszVersion == NULL )
-    {
-        /* ? */;
-    }
-    else if( EQUAL(pszVersion,"\"AA\"") )
-    {
-        GDAL_IMD_AA2R( &papszIMD );
-    }
-
-    return papszIMD;
-}
-
-/************************************************************************/
-/*                       GDALWriteIMDMultiLine()                        */
-/*                                                                      */
-/*      Write a value that is split over multiple lines.                */
-/************************************************************************/
- 
-static void GDALWriteIMDMultiLine( VSILFILE *fp, const char *pszValue )
-
-{
-    char **papszItems = CSLTokenizeStringComplex( pszValue, "(,) ", 
-                                                  FALSE, FALSE );
-    int nItemCount = CSLCount(papszItems);
-    int i;
-
-    VSIFPrintfL( fp, "(\n" );
-
-    for( i = 0; i < nItemCount; i++ )
-    {
-        if( i == nItemCount-1 )
-            VSIFPrintfL( fp, "\t%s );\n", papszItems[i] );
-        else
-            VSIFPrintfL( fp, "\t%s,\n", papszItems[i] );
-    }
-    CSLDestroy( papszItems );
-}
-
-/************************************************************************/
-/*                          GDALWriteIMDFile()                          */
-/************************************************************************/
-
-CPLErr CPL_STDCALL GDALWriteIMDFile( const char *pszFilename, char **papszMD )
-
-{
-    CPLString osRPBFilename = CPLResetExtension( pszFilename, "IMD" );
-
-/* -------------------------------------------------------------------- */
-/*      Read file and parse.                                            */
-/* -------------------------------------------------------------------- */
-    VSILFILE *fp = VSIFOpenL( osRPBFilename, "w" );
-
-    if( fp == NULL )
-    {
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                  "Unable to create %s for writing.\n%s", 
-                  osRPBFilename.c_str(), CPLGetLastErrorMsg() );
-        return CE_Failure;
-    }
-
-/* ==================================================================== */
-/* -------------------------------------------------------------------- */
-/*      Loop through all values writing.                                */
-/* -------------------------------------------------------------------- */
-/* ==================================================================== */
-    int iKey;
-    CPLString osCurSection;
-
-    for( iKey = 0; papszMD[iKey] != NULL; iKey++ )
-    {
-        char *pszRawKey = NULL;
-        const char *pszValue = CPLParseNameValue( papszMD[iKey], &pszRawKey );
-        CPLString osKeySection, osKeyItem;
-        char *pszDot = strchr(pszRawKey,'.');
-
-/* -------------------------------------------------------------------- */
-/*      Split stuff like BAND_P.ULLon into section and item.            */
-/* -------------------------------------------------------------------- */
-        if( pszDot == NULL )
-        {
-            osKeyItem = pszRawKey;
-        }
-        else
-        {
-            osKeyItem = pszDot+1;
-            *pszDot = '\0';
-            osKeySection = pszRawKey;
-        }
-        CPLFree( pszRawKey );
-
-/* -------------------------------------------------------------------- */
-/*      Close and/or start sections as needed.                          */
-/* -------------------------------------------------------------------- */
-        if( osCurSection.size() && !EQUAL(osCurSection,osKeySection) )
-            VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
-
-        if( osKeySection.size() && !EQUAL(osCurSection,osKeySection) )
-            VSIFPrintfL( fp, "BEGIN_GROUP = %s\n", osKeySection.c_str() );
-
-        osCurSection = osKeySection;
-
-/* -------------------------------------------------------------------- */
-/*      Print out simple item.                                          */
-/* -------------------------------------------------------------------- */
-        if( osCurSection.size() )
-            VSIFPrintfL( fp, "\t%s = ", osKeyItem.c_str() );
-        else
-            VSIFPrintfL( fp, "%s = ", osKeyItem.c_str() );
-
-        if( pszValue[0] != '(' )
-            VSIFPrintfL( fp, "%s;\n", pszValue );
-        else
-            GDALWriteIMDMultiLine( fp, pszValue );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Close off.                                                      */
-/* -------------------------------------------------------------------- */
-    if( osCurSection.size() )
-        VSIFPrintfL( fp, "END_GROUP = %s\n", osCurSection.c_str() );
-    
-    VSIFPrintfL( fp, "END;\n" );
-    
-    VSIFCloseL( fp );
-    
-    return CE_None;
-}
diff --git a/gcore/gdal_version.h b/gcore/gdal_version.h
index e2d2fdd..b6bc902 100644
--- a/gcore/gdal_version.h
+++ b/gcore/gdal_version.h
@@ -4,9 +4,9 @@
 /* -------------------------------------------------------------------- */
 
 #ifndef GDAL_VERSION_MAJOR
-#  define GDAL_VERSION_MAJOR    1
-#  define GDAL_VERSION_MINOR    11
-#  define GDAL_VERSION_REV      2
+#  define GDAL_VERSION_MAJOR    2
+#  define GDAL_VERSION_MINOR    0
+#  define GDAL_VERSION_REV      0
 #  define GDAL_VERSION_BUILD    0
 #endif
 
@@ -22,8 +22,8 @@
 #endif
 
 #ifndef GDAL_RELEASE_DATE
-#  define GDAL_RELEASE_DATE     20150210
+#  define GDAL_RELEASE_DATE     20150504
 #endif
 #ifndef GDAL_RELEASE_NAME
-#  define GDAL_RELEASE_NAME     "1.11.2"
+#  define GDAL_RELEASE_NAME     "2.0.0beta1"
 #endif
diff --git a/gcore/gdalallvalidmaskband.cpp b/gcore/gdalallvalidmaskband.cpp
index 1daaeb2..b5ab48f 100644
--- a/gcore/gdalallvalidmaskband.cpp
+++ b/gcore/gdalallvalidmaskband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalallvalidmaskband.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdalallvalidmaskband.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALAllValidMaskBand, a class implementing all
@@ -30,7 +30,7 @@
 
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalallvalidmaskband.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdalallvalidmaskband.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        GDALAllValidMaskBand()                        */
@@ -62,10 +62,10 @@ GDALAllValidMaskBand::~GDALAllValidMaskBand()
 /*                             IReadBlock()                             */
 /************************************************************************/
 
-CPLErr GDALAllValidMaskBand::IReadBlock( CPL_UNUSED int nXBlockOff, CPL_UNUSED int nYBlockOff,
+CPLErr GDALAllValidMaskBand::IReadBlock( CPL_UNUSED int nXBlockOff,
+                                         CPL_UNUSED int nYBlockOff,
                                          void * pImage )
 {
-    // TODO: Suspicious that the offsets are not uses.
     memset( pImage, 255, nBlockXSize * nBlockYSize );
 
     return CE_None;
diff --git a/gcore/gdalclientserver.cpp b/gcore/gdalclientserver.cpp
index 35018ab..1026b21 100644
--- a/gcore/gdalclientserver.cpp
+++ b/gcore/gdalclientserver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalclientserver.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdalclientserver.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  GDAL Client/server dataset mechanism.
@@ -121,7 +121,7 @@ from multiple threads. However, it is safe to use several client datasets from m
 
 /* REMINDER: upgrade this number when the on-wire protocol changes */
 /* Note: please at least keep the version exchange protocol unchanged ! */
-#define GDAL_CLIENT_SERVER_PROTOCOL_MAJOR 1
+#define GDAL_CLIENT_SERVER_PROTOCOL_MAJOR 2
 #define GDAL_CLIENT_SERVER_PROTOCOL_MINOR 0
 
 #include <map>
@@ -156,7 +156,7 @@ typedef struct
     double dfComplete;
     char  *pszProgressMsg;
     int    bRet;
-    void  *hMutex;
+    CPLMutex  *hMutex;
 } GDALServerAsyncProgress;
 
 typedef enum
@@ -372,8 +372,7 @@ static void MyChdir(
 #ifndef WIN32
 CPL_UNUSED
 #endif
-                    const char* pszCWD
-                    )
+    const char* pszCWD)
 {
 #ifdef WIN32
     SetCurrentDirectory(pszCWD);
@@ -435,7 +434,8 @@ class GDALClientDataset: public GDALPamDataset
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace);
+                               GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg);
     public:
                             GDALClientDataset(GDALPipe* p);
                             ~GDALClientDataset();
@@ -539,7 +539,7 @@ class GDALClientRasterBand : public GDALPamRasterBand
                                 int nXOff, int nYOff, int nXSize, int nYSize,
                                 void * pData, int nBufXSize, int nBufYSize,
                                 GDALDataType eBufType,
-                                int nPixelSpace, int nLineSpace );
+                                GSpacing nPixelSpace, GSpacing nLineSpace );
     protected:
 
         virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void* pImage);
@@ -548,7 +548,8 @@ class GDALClientRasterBand : public GDALPamRasterBand
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace );
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg);
 
     public:
         GDALClientRasterBand(GDALPipe* p, int iSrvBand,
@@ -611,17 +612,17 @@ class GDALClientRasterBand : public GDALPamRasterBand
         virtual CPLErr ComputeRasterMinMax( int, double* );
 
         virtual CPLErr GetHistogram( double dfMin, double dfMax, 
-                                     int nBuckets, int *panHistogram, 
+                                     int nBuckets, GUIntBig *panHistogram, 
                                      int bIncludeOutOfRange, int bApproxOK,
                                      GDALProgressFunc pfnProgress, 
                                      void *pProgressData );
 
         virtual CPLErr GetDefaultHistogram( double *pdfMin, double *pdfMax,
-                                            int *pnBuckets, int ** ppanHistogram,
+                                            int *pnBuckets, GUIntBig ** ppanHistogram,
                                             int bForce,
                                             GDALProgressFunc, void *pProgressData);
         virtual CPLErr SetDefaultHistogram( double dfMin, double dfMax,
-                                            int nBuckets, int *panHistogram );
+                                            int nBuckets, GUIntBig *panHistogram );
 
         virtual int HasArbitraryOverviews();
         virtual int GetOverviewCount();
@@ -641,7 +642,7 @@ class GDALClientRasterBand : public GDALPamRasterBand
                                 int nBufXSize, int nBufYSize, 
                                 GDALDataType eDT, char **papszOptions );
         /*
-        virtual GDALRasterBand *GetRasterSampleOverview( int );
+        virtual GDALRasterBand *GetRasterSampleOverview( GUIntBig );
         */
 
 };
@@ -844,6 +845,11 @@ static int GDALPipeRead(GDALPipe* p, int* pnInt)
     return GDALPipeRead(p, pnInt, 4);
 }
 
+static int GDALPipeRead(GDALPipe* p, GIntBig* pnInt)
+{
+    return GDALPipeRead(p, pnInt, 8);
+}
+
 static int GDALPipeRead(GDALPipe* p, CPLErr* peErr)
 {
     return GDALPipeRead(p, peErr, 4);
@@ -937,6 +943,22 @@ static int GDALPipeRead(GDALPipe* p, int nItems, int** ppanInt)
     return TRUE;
 }
 
+static int GDALPipeRead(GDALPipe* p, int nItems, GUIntBig** ppanInt)
+{
+    int nSize;
+    *ppanInt = NULL;
+    if( !GDALPipeRead(p, &nSize) )
+        return FALSE;
+    if( nSize != nItems * (int)sizeof(GUIntBig) )
+        return FALSE;
+    *ppanInt = (GUIntBig*) VSIMalloc(nSize);
+    if( *ppanInt == NULL )
+        return FALSE;
+    if( !GDALPipeRead_nolength(p, nSize, *ppanInt) )
+        return FALSE;
+    return TRUE;
+}
+
 static int GDALPipeRead(GDALPipe* p, GDALColorTable** ppoColorTable)
 {
     int nPaletteInterp, nCount;
@@ -1122,6 +1144,11 @@ static int GDALPipeWrite(GDALPipe* p, int nInt)
     return GDALPipeWrite(p, &nInt, 4);
 }
 
+static int GDALPipeWrite(GDALPipe* p, GIntBig nInt)
+{
+    return GDALPipeWrite(p, &nInt, 8);
+}
+
 static int GDALPipeWrite(GDALPipe* p, double dfDouble)
 {
     return GDALPipeWrite(p, &dfDouble, 8);
@@ -2533,7 +2560,7 @@ static int GDALServerLoop(GDALPipe* p,
             GDALDataType eBufType;
             int nBufType;
             int nBandCount;
-            int nPixelSpace, nLineSpace, nBandSpace;
+            GSpacing nPixelSpace, nLineSpace, nBandSpace;
             int* panBandMap = NULL;
             if( !GDALPipeRead(p, &nXOff) ||
                 !GDALPipeRead(p, &nYOff) ||
@@ -2568,7 +2595,8 @@ static int GDALServerLoop(GDALPipe* p,
                                          pBuffer, nBufXSize, nBufYSize,
                                          eBufType,
                                          nBandCount, panBandMap,
-                                         nPixelSpace, nLineSpace, nBandSpace);
+                                         nPixelSpace, nLineSpace, nBandSpace,
+                                         NULL);
             CPLFree(panBandMap);
             GDALEmitEndOfJunkMarker(p);
             GDALPipeWrite(p, eErr);
@@ -2584,7 +2612,7 @@ static int GDALServerLoop(GDALPipe* p,
             GDALDataType eBufType;
             int nBufType;
             int nBandCount;
-            int nPixelSpace, nLineSpace, nBandSpace;
+            GSpacing nPixelSpace, nLineSpace, nBandSpace;
             int* panBandMap = NULL;
             if( !GDALPipeRead(p, &nXOff) ||
                 !GDALPipeRead(p, &nYOff) ||
@@ -2626,7 +2654,8 @@ static int GDALServerLoop(GDALPipe* p,
                                          pBuffer, nBufXSize, nBufYSize,
                                          eBufType,
                                          nBandCount, panBandMap,
-                                         nPixelSpace, nLineSpace, nBandSpace);
+                                         nPixelSpace, nLineSpace, nBandSpace,
+                                         NULL);
             CPLFree(panBandMap);
             GDALEmitEndOfJunkMarker(p);
             GDALPipeWrite(p, eErr);
@@ -2903,7 +2932,7 @@ static int GDALServerLoop(GDALPipe* p,
             CPLErr eErr = poBand->RasterIO(GF_Read,
                                            nXOff, nYOff, nXSize, nYSize,
                                            pBuffer, nBufXSize, nBufYSize,
-                                           eBufType, 0, 0);
+                                           eBufType, 0, 0, NULL);
             GDALEmitEndOfJunkMarker(p);
             GDALPipeWrite(p, eErr);
             GDALPipeWrite(p, nSize, pBuffer);
@@ -2941,7 +2970,7 @@ static int GDALServerLoop(GDALPipe* p,
             CPLErr eErr = poBand->RasterIO(GF_Write,
                                            nXOff, nYOff, nXSize, nYSize,
                                            pBuffer, nBufXSize, nBufYSize,
-                                           eBufType, 0, 0);
+                                           eBufType, 0, 0, NULL);
             GDALEmitEndOfJunkMarker(p);
             GDALPipeWrite(p, eErr);
         }
@@ -3020,7 +3049,7 @@ static int GDALServerLoop(GDALPipe* p,
                 !GDALPipeRead(p, &bIncludeOutOfRange) ||
                 !GDALPipeRead(p, &bApproxOK) )
                 break;
-            int* panHistogram = (int*) VSIMalloc2(sizeof(int), nBuckets);
+            GUIntBig* panHistogram = (GUIntBig*) VSIMalloc2(sizeof(GUIntBig), nBuckets);
             if( panHistogram == NULL )
                 break;
             CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, 
@@ -3030,7 +3059,7 @@ static int GDALServerLoop(GDALPipe* p,
             GDALPipeWrite(p, eErr);
             if( eErr != CE_Failure )
             {
-                GDALPipeWrite(p, nBuckets * sizeof(int), panHistogram);
+                GDALPipeWrite(p, nBuckets * sizeof(GUIntBig), panHistogram);
             }
             CPLFree(panHistogram);
         }
@@ -3041,7 +3070,7 @@ static int GDALServerLoop(GDALPipe* p,
             int bForce;
             if( !GDALPipeRead(p, &bForce) )
                 break;
-            int* panHistogram = NULL;
+            GUIntBig* panHistogram = NULL;
             CPLErr eErr = poBand->GetDefaultHistogram(&dfMin, &dfMax,
                                                       &nBuckets, &panHistogram,
                                                       bForce, NULL, NULL);
@@ -3052,7 +3081,7 @@ static int GDALServerLoop(GDALPipe* p,
                 GDALPipeWrite(p, dfMin);
                 GDALPipeWrite(p, dfMax);
                 GDALPipeWrite(p, nBuckets);
-                GDALPipeWrite(p, nBuckets * sizeof(int) , panHistogram);
+                GDALPipeWrite(p, nBuckets * sizeof(GUIntBig) , panHistogram);
             }
             CPLFree(panHistogram);
         }
@@ -3060,7 +3089,7 @@ static int GDALServerLoop(GDALPipe* p,
         {
             double dfMin, dfMax;
             int nBuckets;
-            int* panHistogram = NULL;
+            GUIntBig* panHistogram = NULL;
             if( !GDALPipeRead(p, &dfMin) ||
                 !GDALPipeRead(p, &dfMax) ||
                 !GDALPipeRead(p, &nBuckets) ||
@@ -3438,7 +3467,8 @@ CPLErr GDALClientDataset::IRasterIO( GDALRWFlag eRWFlag,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType, 
                                  int nBandCount, int *panBandMap,
-                                 int nPixelSpace, int nLineSpace, int nBandSpace)
+                                 GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                                 GDALRasterIOExtraArg* psExtraArg)
 {
     if( !SupportsInstr(( eRWFlag == GF_Read ) ? INSTR_IRasterIO_Read : INSTR_IRasterIO_Write ) )
         return GDALPamDataset::IRasterIO( eRWFlag,
@@ -3446,7 +3476,8 @@ CPLErr GDALClientDataset::IRasterIO( GDALRWFlag eRWFlag,
                                           pData, nBufXSize, nBufYSize,
                                           eBufType, 
                                           nBandCount, panBandMap,
-                                          nPixelSpace, nLineSpace, nBandSpace );
+                                          nPixelSpace, nLineSpace, nBandSpace,
+                                          psExtraArg );
 
     CLIENT_ENTER();
     CPLErr eRet = CE_Failure;
@@ -3499,9 +3530,9 @@ CPLErr GDALClientDataset::IRasterIO( GDALRWFlag eRWFlag,
     }
     else
     {
-        if( !GDALPipeWrite(p, 0) ||
-            !GDALPipeWrite(p, 0) ||
-            !GDALPipeWrite(p, 0) )
+        if( !GDALPipeWrite(p, nPixelSpace * 0) ||
+            !GDALPipeWrite(p, nLineSpace * 0) ||
+            !GDALPipeWrite(p, nBandSpace * 0) )
             return CE_Failure;
     }
 
@@ -4513,7 +4544,7 @@ CPLErr GDALClientRasterBand::ComputeRasterMinMax( int bApproxOK,
 /************************************************************************/
 
 CPLErr GDALClientRasterBand::GetHistogram( double dfMin, double dfMax, 
-                                           int nBuckets, int *panHistogram, 
+                                           int nBuckets, GUIntBig *panHistogram, 
                                            int bIncludeOutOfRange,
                                            int bApproxOK,
                                            GDALProgressFunc pfnProgress, 
@@ -4529,7 +4560,7 @@ CPLErr GDALClientRasterBand::GetHistogram( double dfMin, double dfMax,
     CPLErr eDefaultRet = CE_Failure;
     if( CSLTestBoolean(CPLGetConfigOption("QGIS_HACK", "NO")) )
     {
-        memset(panHistogram, 0, sizeof(int) * nBuckets);
+        memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
         eDefaultRet = CE_None;
     }
     if( !WriteInstr(INSTR_Band_GetHistogram) ||
@@ -4549,7 +4580,7 @@ CPLErr GDALClientRasterBand::GetHistogram( double dfMin, double dfMax,
     {
         int nSize;
         if( !GDALPipeRead(p, &nSize) ||
-            nSize != nBuckets * (int)sizeof(int) ||
+            nSize != nBuckets * (int)sizeof(GUIntBig) ||
             !GDALPipeRead_nolength(p, nSize, panHistogram) )
             return eDefaultRet;
     }
@@ -4566,7 +4597,7 @@ CPLErr GDALClientRasterBand::GetHistogram( double dfMin, double dfMax,
 CPLErr GDALClientRasterBand::GetDefaultHistogram( double *pdfMin,
                                                   double *pdfMax,
                                                   int *pnBuckets,
-                                                  int ** ppanHistogram,
+                                                  GUIntBig ** ppanHistogram,
                                                   int bForce,
                                                   GDALProgressFunc pfnProgress,
                                                   void *pProgressData )
@@ -4593,14 +4624,14 @@ CPLErr GDALClientRasterBand::GetDefaultHistogram( double *pdfMin,
             !GDALPipeRead(p, &nBuckets) ||
             !GDALPipeRead(p, &nSize) )
             return CE_Failure;
-        if( nSize != nBuckets * (int)sizeof(int) )
+        if( nSize != nBuckets * (int)sizeof(GUIntBig) )
             return CE_Failure;
         if( pdfMin ) *pdfMin = dfMin;
         if( pdfMax ) *pdfMax = dfMax;
         if( pnBuckets ) *pnBuckets = nBuckets;
         if( ppanHistogram )
         {
-            *ppanHistogram = (int*)VSIMalloc(nSize);
+            *ppanHistogram = (GUIntBig*)VSIMalloc(nSize);
             if( *ppanHistogram == NULL )
                 return CE_Failure;
             if( !GDALPipeRead_nolength(p, nSize, *ppanHistogram) )
@@ -4608,7 +4639,7 @@ CPLErr GDALClientRasterBand::GetDefaultHistogram( double *pdfMin,
         }
         else
         {
-            int *panHistogram = (int*)VSIMalloc(nSize);
+            GUIntBig *panHistogram = (GUIntBig*)VSIMalloc(nSize);
             if( panHistogram == NULL )
                 return CE_Failure;
             if( !GDALPipeRead_nolength(p, nSize, panHistogram) )
@@ -4628,7 +4659,7 @@ CPLErr GDALClientRasterBand::GetDefaultHistogram( double *pdfMin,
 /************************************************************************/
 
 CPLErr GDALClientRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
-                                              int nBuckets, int *panHistogram )
+                                              int nBuckets, GUIntBig *panHistogram )
 {
     if( !SupportsInstr(INSTR_Band_SetDefaultHistogram) )
         return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
@@ -4638,7 +4669,7 @@ CPLErr GDALClientRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
         !GDALPipeWrite(p, dfMin) ||
         !GDALPipeWrite(p, dfMax) ||
         !GDALPipeWrite(p, nBuckets) ||
-        !GDALPipeWrite(p, nBuckets * sizeof(int), panHistogram) )
+        !GDALPipeWrite(p, nBuckets * sizeof(GUIntBig), panHistogram) )
         return CE_Failure;
     return CPLErrOnlyRet(p);
 }
@@ -4705,7 +4736,7 @@ CPLErr GDALClientRasterBand::IRasterIO_read_internal(
                                     int nXOff, int nYOff, int nXSize, int nYSize,
                                     void * pData, int nBufXSize, int nBufYSize,
                                     GDALDataType eBufType,
-                                    int nPixelSpace, int nLineSpace )
+                                    GSpacing nPixelSpace, GSpacing nLineSpace)
 {
     CPLErr eRet = CE_Failure;
 
@@ -4780,14 +4811,15 @@ CPLErr GDALClientRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                     int nXOff, int nYOff, int nXSize, int nYSize,
                                     void * pData, int nBufXSize, int nBufYSize,
                                     GDALDataType eBufType,
-                                    int nPixelSpace, int nLineSpace )
+                                    GSpacing nPixelSpace, GSpacing nLineSpace,
+                                    GDALRasterIOExtraArg* psExtraArg )
 {
     if( !SupportsInstr( (eRWFlag == GF_Read) ? INSTR_Band_IRasterIO_Read : INSTR_Band_IRasterIO_Write) )
         return GDALPamRasterBand::IRasterIO( eRWFlag,
                                              nXOff, nYOff, nXSize, nYSize,
                                              pData, nBufXSize, nBufYSize,
                                              eBufType, 
-                                             nPixelSpace, nLineSpace );
+                                             nPixelSpace, nLineSpace, psExtraArg );
 
     CLIENT_ENTER();
     CPLErr eRet = CE_Failure;
@@ -6008,7 +6040,7 @@ static void GDALUnloadAPIPROXYDriver(CPL_UNUSED GDALDriver* poDriver)
             }
         }
     }
-    poAPIPROXYDriver = NULL; 
+    poAPIPROXYDriver = NULL;
 }
 
 /************************************************************************/
@@ -6042,6 +6074,7 @@ GDALDriver* GDALGetAPIPROXYDriver()
         poAPIPROXYDriver = new GDALDriver();
 
         poAPIPROXYDriver->SetDescription( "API_PROXY" );
+        poAPIPROXYDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         poAPIPROXYDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "API_PROXY" );
 
diff --git a/gcore/gdalcolortable.cpp b/gcore/gdalcolortable.cpp
index f88fc11..2adaad8 100644
--- a/gcore/gdalcolortable.cpp
+++ b/gcore/gdalcolortable.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalcolortable.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalcolortable.cpp 28082 2014-12-05 18:06:30Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Color table implementation.
@@ -30,7 +30,7 @@
 
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalcolortable.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalcolortable.cpp 28082 2014-12-05 18:06:30Z rouault $");
 
 /************************************************************************/
 /*                           GDALColorTable()                           */
@@ -460,3 +460,22 @@ GDALCreateColorRamp( GDALColorTableH hTable,
     ((GDALColorTable *) hTable)->CreateColorRamp( nStartIndex, psStartColor, 
                                                   nEndIndex, psEndColor );
 }
+
+/************************************************************************/
+/*                           IsSame()                                   */
+/************************************************************************/
+
+/**
+ * \brief Returns if the current color table is the same as another one.
+ *
+ * @param poOtherCT other color table to be compared to.
+ * @return TRUE if both color tables are identical.
+ * @since GDAL 2.0
+ */
+
+int GDALColorTable::IsSame(const GDALColorTable* poOtherCT) const
+{
+    return aoEntries.size() == poOtherCT->aoEntries.size() &&
+           (aoEntries.size() == 0 ||
+            memcmp(&aoEntries[0], &poOtherCT->aoEntries[0], aoEntries.size() * sizeof(GDALColorEntry)) == 0);
+}
diff --git a/gcore/gdaldataset.cpp b/gcore/gdaldataset.cpp
index d656254..60cd1ce 100644
--- a/gcore/gdaldataset.cpp
+++ b/gcore/gdaldataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldataset.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdaldataset.cpp 29097 2015-05-01 20:13:36Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Base class for raster file formats.  
@@ -32,9 +32,21 @@
 #include "cpl_string.h"
 #include "cpl_hash_set.h"
 #include "cpl_multiproc.h"
+#include "ogr_featurestyle.h"
+#include "swq.h"
+#include "ogr_gensql.h"
+#include "ogr_attrind.h"
+#include "ogr_p.h"
+#include "ogrunionlayer.h"
+#include "ograpispy.h"
+
+#ifdef SQLITE_ENABLED
+#include "../sqlite/ogrsqliteexecutesql.h"
+#endif
+
 #include <map>
 
-CPL_CVSID("$Id: gdaldataset.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdaldataset.cpp 29097 2015-05-01 20:13:36Z rouault $");
 
 CPL_C_START
 GDALAsyncReader *
@@ -60,26 +72,18 @@ typedef struct
     GDALDataset *poDS;
 } SharedDatasetCtxt;
 
-typedef struct
-{
-    GDALDataset *poDS;
-    /* In the case of a shared dataset, memorize the PID of the thread */
-    /* that marked the dataset as shared, so that we can remove it from */
-    /* the phSharedDatasetSet in the destructor of the dataset, even */
-    /* if GDALClose is called from a different thread */
-    /* Ideally, this should be stored in the GDALDataset object itself */
-    /* but this is inconvenient to change the object size at that time */
-    GIntBig      nPIDCreatorForShared; 
-} DatasetCtxt;
-
 /* Set of datasets opened as shared datasets (with GDALOpenShared) */
 /* The values in the set are of type SharedDatasetCtxt */
 static CPLHashSet* phSharedDatasetSet = NULL; 
 
 /* Set of all datasets created in the constructor of GDALDataset */
-/* The values in the set are of type DatasetCtxt */
-static CPLHashSet* phAllDatasetSet = NULL;
-static void *hDLMutex = NULL;
+/* In the case of a shared dataset, memorize the PID of the thread */
+/* that marked the dataset as shared, so that we can remove it from */
+/* the phSharedDatasetSet in the destructor of the dataset, even */
+/* if GDALClose is called from a different thread */
+static std::map<GDALDataset*, GIntBig>* poAllDatasetMap = NULL;
+
+static CPLMutex *hDLMutex = NULL;
 
 /* Static array of all datasets. Used by GDALGetOpenDatasets */
 /* Not thread-safe. See GDALGetOpenDatasets */
@@ -107,31 +111,12 @@ static void GDALSharedDatasetFreeFunc(void* elt)
     CPLFree(psStruct);
 }
 
-static unsigned long GDALDatasetHashFunc(const void* elt)
-{
-    DatasetCtxt* psStruct = (DatasetCtxt*) elt;
-    return (unsigned long)(GUIntBig) psStruct->poDS;
-}
-
-static int GDALDatasetEqualFunc(const void* elt1, const void* elt2)
-{
-    DatasetCtxt* psStruct1 = (DatasetCtxt*) elt1;
-    DatasetCtxt* psStruct2 = (DatasetCtxt*) elt2;
-    return psStruct1->poDS == psStruct2->poDS ;
-}
-
-static void GDALDatasetFreeFunc(void* elt)
-{
-    DatasetCtxt* psStruct = (DatasetCtxt*) elt;
-    CPLFree(psStruct);
-}
-
 /************************************************************************/
 /* Functions shared between gdalproxypool.cpp and gdaldataset.cpp */
 /************************************************************************/
 
 /* The open-shared mutex must be used by the ProxyPool too */
-void** GDALGetphDLMutex()
+CPLMutex** GDALGetphDLMutex()
 {
     return &hDLMutex;
 }
@@ -192,26 +177,20 @@ GDALDataset::GDALDataset()
     papoBands = NULL;
     nRefCount = 1;
     bShared = FALSE;
-
-/* -------------------------------------------------------------------- */
-/*      Add this dataset to the open dataset list.                      */
-/* -------------------------------------------------------------------- */
-    {
-        CPLMutexHolderD( &hDLMutex );
-
-        if (phAllDatasetSet == NULL)
-            phAllDatasetSet = CPLHashSetNew(GDALDatasetHashFunc, GDALDatasetEqualFunc, GDALDatasetFreeFunc);
-        DatasetCtxt* ctxt = (DatasetCtxt*)CPLMalloc(sizeof(DatasetCtxt));
-        ctxt->poDS = this;
-        ctxt->nPIDCreatorForShared = -1;
-        CPLHashSetInsert(phAllDatasetSet, ctxt);
-    }
+    bIsInternal = TRUE;
+    bSuppressOnClose = FALSE;
+    bReserved1 = FALSE;
+    bReserved2 = FALSE;
+    papszOpenOptions = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Set forced caching flag.                                        */
 /* -------------------------------------------------------------------- */
     bForceCachedIO =  CSLTestBoolean( 
         CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") );
+    
+    m_poStyleTable = NULL;
+    m_hMutex = NULL;
 }
 
 
@@ -240,8 +219,8 @@ GDALDataset::~GDALDataset()
     int         i;
 
     // we don't want to report destruction of datasets that 
-    // were never really open.
-    if( nBands != 0 || !EQUAL(GetDescription(),"") )
+    // were never really open or meant as internal
+    if( !bIsInternal && ( nBands != 0 || !EQUAL(GetDescription(),"") ) )
     {
         if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() )
             CPLDebug( "GDAL", 
@@ -253,18 +232,21 @@ GDALDataset::~GDALDataset()
                       "GDALClose(%s, this=%p)", GetDescription(), this );
     }
 
+    if( bSuppressOnClose )
+        VSIUnlink(GetDescription());
+
 /* -------------------------------------------------------------------- */
 /*      Remove dataset from the "open" dataset list.                    */
 /* -------------------------------------------------------------------- */
+    if( !bIsInternal )
     {
         CPLMutexHolderD( &hDLMutex );
-        if( phAllDatasetSet )
+        if( poAllDatasetMap )
         {
-            DatasetCtxt sStruct;
-            sStruct.poDS = this;
-            DatasetCtxt* psStruct = (DatasetCtxt*) CPLHashSetLookup(phAllDatasetSet, &sStruct);
-            GIntBig nPIDCreatorForShared = psStruct->nPIDCreatorForShared;
-            CPLHashSetRemove(phAllDatasetSet, psStruct);
+            std::map<GDALDataset*, GIntBig>::iterator oIter = poAllDatasetMap->find(this);
+            CPLAssert(oIter != poAllDatasetMap->end());
+            GIntBig nPIDCreatorForShared = oIter->second;
+            poAllDatasetMap->erase(oIter);
 
             if (bShared && phSharedDatasetSet != NULL)
             {
@@ -284,10 +266,10 @@ GDALDataset::~GDALDataset()
                 }
             }
 
-            if (CPLHashSetSize(phAllDatasetSet) == 0)
+            if (poAllDatasetMap->size() == 0)
             {
-                CPLHashSetDestroy(phAllDatasetSet);
-                phAllDatasetSet = NULL;
+                delete poAllDatasetMap;
+                poAllDatasetMap = NULL;
                 if (phSharedDatasetSet)
                 {
                     CPLHashSetDestroy(phSharedDatasetSet);
@@ -309,6 +291,35 @@ GDALDataset::~GDALDataset()
     }
 
     CPLFree( papoBands );
+
+    if ( m_poStyleTable )
+    {
+        delete m_poStyleTable;
+        m_poStyleTable = NULL;
+    }
+
+    if( m_hMutex != NULL )
+        CPLDestroyMutex( m_hMutex );
+
+    CSLDestroy( papszOpenOptions );
+}
+
+/************************************************************************/
+/*                      AddToDatasetOpenList()                          */
+/************************************************************************/
+
+void GDALDataset::AddToDatasetOpenList()
+{
+/* -------------------------------------------------------------------- */
+/*      Add this dataset to the open dataset list.                      */
+/* -------------------------------------------------------------------- */
+    bIsInternal = FALSE;
+
+    CPLMutexHolderD( &hDLMutex );
+
+    if (poAllDatasetMap == NULL)
+        poAllDatasetMap = new std::map<GDALDataset*, GIntBig>;
+    (*poAllDatasetMap)[this] = -1;
 }
 
 /************************************************************************/
@@ -321,6 +332,12 @@ GDALDataset::~GDALDataset()
  * Any raster (or other GDAL) data written via GDAL calls, but buffered
  * internally will be written to disk.
  *
+ * The default implementation of this method just calls the FlushCache() method
+ * on each of the raster bands and the SyncToDisk() method
+ * on each of the layers.  Conceptionally, calling FlushCache() on a dataset
+ * should include any work that might be accomplished by calling SyncToDisk()
+ * on layers in that dataset.
+ *
  * Using this method does not prevent use from calling GDALClose()
  * to properly close a dataset and ensure that important data not addressed
  * by FlushCache() is written in the file.
@@ -336,13 +353,28 @@ void GDALDataset::FlushCache()
     // This sometimes happens if a dataset is destroyed before completely
     // built. 
 
-    if( papoBands == NULL )
-        return;
+    if( papoBands != NULL )
+    {
+        for( i = 0; i < nBands; i++ )
+        {
+            if( papoBands[i] != NULL )
+                papoBands[i]->FlushCache();
+        }
+    }
 
-    for( i = 0; i < nBands; i++ )
+    int nLayers = GetLayerCount();
+    if( nLayers > 0 )
     {
-        if( papoBands[i] != NULL )
-            papoBands[i]->FlushCache();
+        CPLMutexHolderD( &m_hMutex );
+        for( i = 0; i < nLayers ; i++ )
+        {
+            OGRLayer *poLayer = GetLayer(i);
+
+            if( poLayer )
+            {
+                poLayer->SyncToDisk();
+            }
+        }
     }
 }
 
@@ -782,7 +814,7 @@ const char * CPL_STDCALL GDALGetProjectionRef( GDALDatasetH hDS )
  * is not writable, or because the dataset does not support the indicated
  * projection.  Many formats do not support writing projections.
  *
- * This method is the same as the C GDALSetProjection() function. 
+ * This method is the same as the C GDALSetProjection() function.
  *
  * @param pszProjection projection reference string.
  *
@@ -900,11 +932,12 @@ CPLErr CPL_STDCALL GDALGetGeoTransform( GDALDatasetH hDS, double * padfTransform
  */
 
 CPLErr GDALDataset::SetGeoTransform( CPL_UNUSED double * padfTransform )
+
 {
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
                   "SetGeoTransform() not supported for this dataset." );
-    
+
     return( CE_Failure );
 }
 
@@ -919,7 +952,8 @@ CPLErr GDALDataset::SetGeoTransform( CPL_UNUSED double * padfTransform )
  */
 
 CPLErr CPL_STDCALL 
-GDALSetGeoTransform( GDALDatasetH hDS, CPL_UNUSED double * padfTransform )
+GDALSetGeoTransform( GDALDatasetH hDS, double * padfTransform )
+
 {
     VALIDATE_POINTER1( hDS, "GDALSetGeoTransform", CE_Failure );
 
@@ -942,6 +976,7 @@ GDALSetGeoTransform( GDALDatasetH hDS, CPL_UNUSED double * padfTransform )
  */
 
 void *GDALDataset::GetInternalHandle( CPL_UNUSED const char * pszHandleName )
+
 {
     return( NULL );
 }
@@ -1109,6 +1144,8 @@ void GDALDataset::MarkAsShared()
     CPLAssert( !bShared );
 
     bShared = TRUE;
+    if( bIsInternal )
+        return;
 
     GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
     SharedDatasetCtxt* psStruct;
@@ -1133,10 +1170,7 @@ void GDALDataset::MarkAsShared()
     {
         CPLHashSetInsert(phSharedDatasetSet, psStruct);
 
-        DatasetCtxt sStruct;
-        sStruct.poDS = this;
-        DatasetCtxt* psStruct = (DatasetCtxt*) CPLHashSetLookup(phAllDatasetSet, &sStruct);
-        psStruct->nPIDCreatorForShared = nPID;
+        (*poAllDatasetMap)[this] = nPID;
     }
 }
 
@@ -1453,7 +1487,9 @@ CPLErr GDALDataset::IRasterIO( GDALRWFlag eRWFlag,
                                void * pData, int nBufXSize, int nBufYSize,
                                GDALDataType eBufType, 
                                int nBandCount, int *panBandMap,
-                               int nPixelSpace, int nLineSpace, int nBandSpace)
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg )
     
 {
     int iBandIndex; 
@@ -1469,9 +1505,13 @@ CPLErr GDALDataset::IRasterIO( GDALRWFlag eRWFlag,
         return BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                    pData, nBufXSize, nBufYSize,
                                    eBufType, nBandCount, panBandMap,
-                                   nPixelSpace, nLineSpace, nBandSpace );
+                                   nPixelSpace, nLineSpace, nBandSpace,
+                                   psExtraArg );
     }
 
+    GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+    void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
     for( iBandIndex = 0; 
          iBandIndex < nBandCount && eErr == CE_None; 
          iBandIndex++ )
@@ -1486,11 +1526,24 @@ CPLErr GDALDataset::IRasterIO( GDALRWFlag eRWFlag,
         }
 
         pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
-        
+
+        psExtraArg->pfnProgress = GDALScaledProgress;
+        psExtraArg->pProgressData = 
+            GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
+                                      1.0 * (iBandIndex + 1) / nBandCount,
+                                      pfnProgressGlobal,
+                                      pProgressDataGlobal );
+
         eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                                   (void *) pabyBandData, nBufXSize, nBufYSize,
-                                  eBufType, nPixelSpace, nLineSpace );
+                                  eBufType, nPixelSpace, nLineSpace,
+                                  psExtraArg );
+
+        GDALDestroyScaledProgress( psExtraArg->pProgressData );
     }
+    
+    psExtraArg->pfnProgress = pfnProgressGlobal;
+    psExtraArg->pProgressData = pProgressDataGlobal;
 
     return eErr;
 }
@@ -1569,7 +1622,6 @@ CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
     return eErr;
 }
 
-
 /************************************************************************/
 /*                              RasterIO()                              */
 /************************************************************************/
@@ -1593,7 +1645,8 @@ CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
  * on "block boundaries" as returned by GetBlockSize(), or use the
  * ReadBlock() and WriteBlock() methods.
  *
- * This method is the same as the C GDALDatasetRasterIO() function.
+ * This method is the same as the C GDALDatasetRasterIO() or
+ * GDALDatasetRasterIOEx() functions.
  *
  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
  * write a region of data.
@@ -1643,6 +1696,12 @@ CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
  * nLineSpace * nBufYSize implying band sequential organization
  * of the data buffer. 
  *
+ * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg structure with additional
+ * arguments to specify resampling and progress callback, or NULL for default
+ * behaviour. The GDAL_RASTERIO_RESAMPLING configuration option can also be defined
+ * to override the default resampling to one of BILINEAR, CUBIC, CUBICSPLINE,
+ * LANCZOS, AVERAGE or MODE.
+ *
  * @return CE_Failure if the access fails, otherwise CE_None.
  */
 
@@ -1651,12 +1710,30 @@ CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
                               void * pData, int nBufXSize, int nBufYSize,
                               GDALDataType eBufType, 
                               int nBandCount, int *panBandMap,
-                              int nPixelSpace, int nLineSpace, int nBandSpace )
+                              GSpacing nPixelSpace, GSpacing nLineSpace,
+                              GSpacing nBandSpace,
+                              GDALRasterIOExtraArg* psExtraArg )
 
 {
     int i = 0;
     int bNeedToFreeBandMap = FALSE;
     CPLErr eErr = CE_None;
+    
+    GDALRasterIOExtraArg sExtraArg;
+    if( psExtraArg == NULL )
+    {
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+        psExtraArg = &sExtraArg;
+    }
+    else if( psExtraArg->nVersion != RASTERIO_EXTRA_ARG_CURRENT_VERSION )
+    {
+        ReportError( CE_Failure, CPLE_AppDefined,
+                     "Unhandled version of GDALRasterIOExtraArg" );
+        return CE_Failure;
+    }
+
+    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize,
+                                       nBufXSize, nBufYSize);
 
     if( NULL == pData )
     {
@@ -1694,26 +1771,11 @@ CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
     
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > INT_MAX / nBufXSize)
-        {
-            ReportError( CE_Failure, CPLE_AppDefined,
-                      "Int overflow : %d x %d", nPixelSpace, nBufXSize );
-            return CE_Failure;
-        }
         nLineSpace = nPixelSpace * nBufXSize;
     }
-    
-    /* The nBandCount > 1 test is necessary to allow reading only */
-    /* one band, even if the nLineSpace would overflow, but as it */
-    /* is not used in that case, it can be left to 0 (#3481) */
+
     if( nBandSpace == 0 && nBandCount > 1 )
     {
-        if (nLineSpace > INT_MAX / nBufYSize)
-        {
-            ReportError( CE_Failure, CPLE_AppDefined,
-                      "Int overflow : %d x %d", nLineSpace, nBufYSize );
-            return CE_Failure;
-        }
         nBandSpace = nLineSpace * nBufYSize;
     }
 
@@ -1743,7 +1805,8 @@ CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
             BlockBasedRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                 pData, nBufXSize, nBufYSize, eBufType,
                                 nBandCount, panBandMap,
-                                nPixelSpace, nLineSpace, nBandSpace );
+                                nPixelSpace, nLineSpace, nBandSpace,
+                                psExtraArg );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1755,7 +1818,8 @@ CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
             IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                        pData, nBufXSize, nBufYSize, eBufType,
                        nBandCount, panBandMap,
-                       nPixelSpace, nLineSpace, nBandSpace );
+                       nPixelSpace, nLineSpace, nBandSpace,
+                       psExtraArg );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1774,6 +1838,9 @@ CPLErr GDALDataset::RasterIO( GDALRWFlag eRWFlag,
 /**
  * \brief Read/write a region of image data from multiple bands.
  *
+ * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
+ * resolution, progress callback, etc. are needed)
+ *
  * @see GDALDataset::RasterIO()
  */
 
@@ -1789,28 +1856,47 @@ GDALDatasetRasterIO( GDALDatasetH hDS, GDALRWFlag eRWFlag,
     VALIDATE_POINTER1( hDS, "GDALDatasetRasterIO", CE_Failure );
 
     GDALDataset    *poDS = (GDALDataset *) hDS;
-    
+
     return( poDS->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                             pData, nBufXSize, nBufYSize, eBufType,
                             nBandCount, panBandMap, 
-                            nPixelSpace, nLineSpace, nBandSpace ) );
+                            nPixelSpace, nLineSpace, nBandSpace, NULL ) );
 }
-                     
+
 /************************************************************************/
-/*                          GetOpenDatasets()                           */
+/*                       GDALDatasetRasterIOEx()                        */
 /************************************************************************/
 
-static int GDALGetOpenDatasetsForeach(void* elt, void* user_data)
-{
-    int* pnIndex = (int*) user_data;
-    DatasetCtxt* psStruct = (DatasetCtxt*) elt;
+/**
+ * \brief Read/write a region of image data from multiple bands.
+ *
+ * @see GDALDataset::RasterIO()
+ * @since GDAL 2.0
+ */
 
-    ppDatasets[*pnIndex] = psStruct->poDS;
+CPLErr CPL_STDCALL
+GDALDatasetRasterIOEx( GDALDatasetH hDS, GDALRWFlag eRWFlag,
+                       int nXOff, int nYOff, int nXSize, int nYSize,
+                       void * pData, int nBufXSize, int nBufYSize,
+                       GDALDataType eBufType,
+                       int nBandCount, int *panBandMap,
+                       GSpacing nPixelSpace, GSpacing nLineSpace,
+                       GSpacing nBandSpace,
+                       GDALRasterIOExtraArg* psExtraArg )
+    
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetRasterIOEx", CE_Failure );
 
-    (*pnIndex) ++;
+    GDALDataset    *poDS = (GDALDataset *) hDS;
 
-    return TRUE;
+    return( poDS->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                            pData, nBufXSize, nBufYSize, eBufType,
+                            nBandCount, panBandMap, 
+                            nPixelSpace, nLineSpace, nBandSpace, psExtraArg ) );
 }
+/************************************************************************/
+/*                          GetOpenDatasets()                           */
+/************************************************************************/
 
 /**
  * \brief Fetch all open GDAL dataset handles.
@@ -1831,12 +1917,14 @@ GDALDataset **GDALDataset::GetOpenDatasets( int *pnCount )
 {
     CPLMutexHolderD( &hDLMutex );
 
-    if (phAllDatasetSet != NULL)
+    if (poAllDatasetMap != NULL)
     {
-        int nIndex = 0;
-        *pnCount = CPLHashSetSize(phAllDatasetSet);
+        int i = 0;
+        *pnCount = poAllDatasetMap->size();
         ppDatasets = (GDALDataset**) CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset*));
-        CPLHashSetForeach(phAllDatasetSet, GDALGetOpenDatasetsForeach, &nIndex);
+        std::map<GDALDataset*, GIntBig>::iterator oIter = poAllDatasetMap->begin();
+        for(; oIter != poAllDatasetMap->end(); ++oIter, i++ )
+            ppDatasets[i] = oIter->first;
         return ppDatasets;
     }
     else
@@ -1870,11 +1958,11 @@ void CPL_STDCALL GDALGetOpenDatasets( GDALDatasetH **ppahDSList, int *pnCount )
 /*                        GDALCleanOpenDatasetsList()                   */
 /************************************************************************/
 
-/* Usefull when called from the child of a fork(), to avoid closing */
+/* Useful when called from the child of a fork(), to avoid closing */
 /* the datasets of the parent at the child termination */
 void GDALNullifyOpenDatasetsList()
 {
-    phAllDatasetSet = NULL;
+    poAllDatasetMap = NULL;
     phSharedDatasetSet = NULL;
     ppDatasets = NULL;
     hDLMutex = NULL;
@@ -2080,7 +2168,8 @@ char **GDALDataset::GetFileList()
 /* -------------------------------------------------------------------- */
 /*      Do we have a world file?                                        */
 /* -------------------------------------------------------------------- */
-    if( bMainFileReal )
+    if( bMainFileReal &&
+        !GDALCanFileAcceptSidecarFile(osMainFilename) )
     {
         const char* pszExtension = CPLGetExtension( osMainFilename );
         if( strlen(pszExtension) > 2 )
@@ -2234,6 +2323,7 @@ CPLErr CPL_STDCALL GDALCreateDatasetMaskBand( GDALDatasetH hDS, int nFlags )
  * process through the \ref gdal_api_proxy mechanism.
  *
  * \sa GDALOpenShared()
+ * \sa GDALOpenEx()
  *
  * @param pszFilename the name of the file to access.  In the case of
  * exotic drivers this may not refer to a physical file, but instead contain
@@ -2251,23 +2341,145 @@ GDALDatasetH CPL_STDCALL
 GDALOpen( const char * pszFilename, GDALAccess eAccess )
 
 {
-    return GDALOpenInternal(pszFilename, eAccess, NULL);
+    return GDALOpenEx( pszFilename,
+                       GDAL_OF_RASTER |
+                       (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
+                       GDAL_OF_VERBOSE_ERROR,
+                       NULL, NULL, NULL );
 }
 
-/* The drivers listed in papszAllowedDrivers can be in any order */
-/* Only the order of registration will be taken into account */
-GDALDatasetH GDALOpenInternal( const char * pszFilename, GDALAccess eAccess,
-                               const char* const * papszAllowedDrivers)
-{
-    GDALOpenInfo oOpenInfo( pszFilename, eAccess );
-    return GDALOpenInternal(oOpenInfo, papszAllowedDrivers);
-}
 
-GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
-                               const char* const * papszAllowedDrivers)
+/************************************************************************/
+/*                             GDALOpenEx()                             */
+/************************************************************************/
+
+/**
+ * \brief Open a raster or vector file as a GDALDataset.
+ *
+ * This function will try to open the passed file, or virtual dataset
+ * name by invoking the Open method of each registered GDALDriver in turn. 
+ * The first successful open will result in a returned dataset.  If all
+ * drivers fail then NULL is returned and an error is issued.
+ *
+ * Several recommendations :
+ * <ul>
+ * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not recommended
+ * to open a new dataset on the same underlying file.</li>
+ * <li>The returned dataset should only be accessed by one thread at a time. If you
+ * want to use it from different threads, you must add all necessary code (mutexes, etc.)
+ * to avoid concurrent use of the object. (Some drivers, such as GeoTIFF, maintain internal
+ * state variables that are updated each time a new block is read, thus preventing concurrent
+ * use.) </li>
+ * </ul>
+ *
+ * For drivers supporting the VSI virtual file API, it is possible to open
+ * a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive
+ * (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler())
+ *
+ * In some situations (dealing with unverified data), the datasets can be opened in another
+ * process through the \ref gdal_api_proxy mechanism.
+ *
+ * In order to reduce the need for searches through the operating system
+ * file system machinery, it is possible to give an optional list of files with
+ * the papszSiblingFiles parameter.
+ * This is the list of all files at the same level in the file system as the
+ * target file, including the target file. The filenames must not include any
+ * path components, are an essentially just the output of CPLReadDir() on the
+ * parent directory. If the target object does not have filesystem semantics
+ * then the file list should be NULL.
+ *
+ * @param pszFilename the name of the file to access.  In the case of
+ * exotic drivers this may not refer to a physical file, but instead contain
+ * information for the driver on how to access a dataset.  It should be in UTF-8
+ * encoding.
+ *
+ * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined through
+ * logical or operator.
+ * <ul>
+ * <li>Driver kind: GDAL_OF_RASTER for raster drivers, GDAL_OF_VECTOR for vector drivers.
+ *     If none of the value is specified, both kinds are implied.</li>
+ * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.</li>
+ * <li>Shared mode: GDAL_OF_SHARED. If set, it allows the sharing of
+ *  GDALDataset handles for a dataset with other callers that have set GDAL_OF_SHARED.
+ * In particular, GDALOpenEx() will first consult its list of currently
+ * open and shared GDALDataset's, and if the GetDescription() name for one
+ * exactly matches the pszFilename passed to GDALOpenEx() it will be
+ * referenced and returned, if GDALOpenEx() is called from the same thread.</li>
+ * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set, a failed attempt to open the
+ * file will lead to an error message to be reported.</li>
+ * </ul>
+ *
+ * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
+ * terminated list of strings with the driver short names that must be considered.
+ *
+ * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
+ * options passed to candidate drivers. An option exists for all drivers,
+ * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
+ * The level index starts at 0. The level number can be suffixed by "only" to specify that
+ * only this overview level must be visible, and not sub-levels.
+ * Open options are validated by default, and a warning is emitted in case the
+ * option is not recognized. In some scenarios, it might be not desirable (e.g.
+ * when not knowing which driver will open the file), so the special open option
+ * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings.
+ *
+ * @param papszSiblingFiles  NULL, or a NULL terminated list of strings that are
+ * filenames that are auxiliary to the main filename. If NULL is passed, a probing
+ * of the file system will be done.
+ *
+ * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
+ * this handle can be cast to a GDALDataset *. 
+ *
+ * @since GDAL 2.0
+ */
+
+GDALDatasetH CPL_STDCALL GDALOpenEx( const char* pszFilename,
+                                 unsigned int nOpenFlags,
+                                 const char* const* papszAllowedDrivers,
+                                 const char* const* papszOpenOptions,
+                                 const char* const* papszSiblingFiles )
 {
+    VALIDATE_POINTER1( pszFilename, "GDALOpen", NULL );
+
+/* -------------------------------------------------------------------- */
+/*      In case of shared dataset, first scan the existing list to see  */
+/*      if it could already contain the requested dataset.              */
+/* -------------------------------------------------------------------- */
+    if( nOpenFlags & GDAL_OF_SHARED )
+    {
+        if( nOpenFlags & GDAL_OF_INTERNAL )
+        {
+            CPLError(CE_Failure, CPLE_IllegalArg, "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
+            return NULL;
+        }
+        
+        CPLMutexHolderD( &hDLMutex );
+
+        if (phSharedDatasetSet != NULL)
+        {
+            GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
+            SharedDatasetCtxt* psStruct;
+            SharedDatasetCtxt sStruct;
+
+            sStruct.nPID = nThisPID;
+            sStruct.pszDescription = (char*) pszFilename;
+            sStruct.eAccess = (nOpenFlags & GDAL_OF_UPDATE) ? GA_Update : GA_ReadOnly;
+            psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct);
+            if (psStruct == NULL && (nOpenFlags & GDAL_OF_UPDATE) == 0)
+            {
+                sStruct.eAccess = GA_Update;
+                psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct);
+            }
+            if (psStruct)
+            {
+                psStruct->poDS->Reference();
+                return psStruct->poDS;
+            }
+        }
+    }
 
-    VALIDATE_POINTER1( oOpenInfo.pszFilename, "GDALOpen", NULL );
+    /* If no driver kind is specified, assume all are to be probed */
+    if( (nOpenFlags & GDAL_OF_KIND_MASK) == 0 )
+        nOpenFlags |= GDAL_OF_KIND_MASK;
 
     {
         int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP );
@@ -2288,11 +2500,18 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
 
     int         iDriver;
     GDALDriverManager *poDM = GetGDALDriverManager();
-    CPLLocaleC  oLocaleForcer;
+    //CPLLocaleC  oLocaleForcer;
 
     CPLErrorReset();
     CPLAssert( NULL != poDM );
 
+    /* Build GDALOpenInfo just now to avoid useless file stat'ing if a */
+    /* shared dataset was asked before */
+    GDALOpenInfo oOpenInfo(pszFilename,
+                           nOpenFlags,
+                           (char**) papszSiblingFiles);
+    oOpenInfo.papszOpenOptions = (char**) papszOpenOptions;
+
     for( iDriver = -1; iDriver < poDM->GetDriverCount(); iDriver++ )
     {
         GDALDriver      *poDriver;
@@ -2308,31 +2527,120 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
                 continue;
         }
 
-        if ( poDriver->pfnOpen == NULL )
+        if( (nOpenFlags & GDAL_OF_RASTER) != 0 &&
+            (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
+            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == NULL )
+            continue;
+        if( (nOpenFlags & GDAL_OF_VECTOR) != 0 &&
+            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
+            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == NULL )
+            continue;
+
+        /* Remove general OVERVIEW_LEVEL open options from list before */
+        /* passing it to the driver, if it isn't a driver specific option already */
+        char** papszTmpOpenOptions = NULL;
+        if( CSLFetchNameValue((char**)papszOpenOptions, "OVERVIEW_LEVEL") != NULL &&
+            (poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST) == NULL ||
+             CPLString(poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST)).ifind("OVERVIEW_LEVEL") == std::string::npos) )
+        {
+            papszTmpOpenOptions = CSLDuplicate((char**)papszOpenOptions);
+            papszTmpOpenOptions = CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", NULL);
+            oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
+        }
+
+        if( poDriver->pfnIdentify && poDriver->pfnIdentify(&oOpenInfo) > 0 )
+        {
+            GDALValidateOpenOptions( poDriver, oOpenInfo.papszOpenOptions );
+        }
+
+        if ( poDriver->pfnOpen != NULL )
+        {
+            poDS = poDriver->pfnOpen( &oOpenInfo );
+        }
+        else if( poDriver->pfnOpenWithDriverArg != NULL )
+        {
+            poDS = poDriver->pfnOpenWithDriverArg( poDriver, &oOpenInfo );
+        }
+        else
+        {
+            CSLDestroy(papszTmpOpenOptions);
+            oOpenInfo.papszOpenOptions = (char**) papszOpenOptions;
             continue;
+        }
+
+        CSLDestroy(papszTmpOpenOptions);
+        oOpenInfo.papszOpenOptions = (char**) papszOpenOptions;
 
-        poDS = poDriver->pfnOpen( &oOpenInfo );
         if( poDS != NULL )
         {
             if( strlen(poDS->GetDescription()) == 0 )
-                poDS->SetDescription( oOpenInfo.pszFilename );
+                poDS->SetDescription( pszFilename );
 
             if( poDS->poDriver == NULL )
                 poDS->poDriver = poDriver;
 
+            if( poDS->papszOpenOptions == NULL )
+                poDS->papszOpenOptions = CSLDuplicate((char**)papszOpenOptions);
 
-            if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() )
-                CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s (pid=%d, responsiblePID=%d).",
-                          oOpenInfo.pszFilename, poDS, poDriver->GetDescription(),
-                          (int)CPLGetPID(), (int)GDALGetResponsiblePIDForCurrentThread() );
-            else
-                CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
-                          oOpenInfo.pszFilename, poDS, poDriver->GetDescription() );
+            if( !(nOpenFlags & GDAL_OF_INTERNAL) )
+            {
+                if( CPLGetPID() != GDALGetResponsiblePIDForCurrentThread() )
+                    CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s (pid=%d, responsiblePID=%d).",
+                              pszFilename, poDS, poDriver->GetDescription(),
+                              (int)CPLGetPID(), (int)GDALGetResponsiblePIDForCurrentThread() );
+                else
+                    CPLDebug( "GDAL", "GDALOpen(%s, this=%p) succeeds as %s.",
+                              pszFilename, poDS, poDriver->GetDescription() );
+
+                poDS->AddToDatasetOpenList();
+            }
 
             int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP );
             if( pnRecCount )
                 (*pnRecCount) --;
 
+            if( nOpenFlags & GDAL_OF_SHARED )
+            {
+                if (strcmp(pszFilename, poDS->GetDescription()) != 0)
+                {
+                    CPLError(CE_Warning, CPLE_NotSupported,
+                            "A dataset opened by GDALOpenShared should have the same filename (%s) "
+                            "and description (%s)",
+                            pszFilename, poDS->GetDescription());
+                }
+                else
+                {
+                    poDS->MarkAsShared();
+                }
+            }
+
+            /* Deal with generic OVERVIEW_LEVEL open option, unless it is */
+            /* driver specific */
+            if( CSLFetchNameValue((char**) papszOpenOptions, "OVERVIEW_LEVEL") != NULL &&
+                (poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST) == NULL ||
+                CPLString(poDriver->GetMetadataItem(GDAL_DMD_OPENOPTIONLIST)).ifind("OVERVIEW_LEVEL") == std::string::npos) )
+            {
+                CPLString osVal(CSLFetchNameValue((char**) papszOpenOptions, "OVERVIEW_LEVEL"));
+                int nOvrLevel = atoi(osVal);
+                int bThisLevelOnly = osVal.ifind("only") != std::string::npos;
+                GDALDataset* poOvrDS = GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly, TRUE);
+                if( poOvrDS == NULL )
+                {
+                    if( nOpenFlags & GDAL_OF_VERBOSE_ERROR )
+                    {
+                        CPLError( CE_Failure, CPLE_OpenFailed,
+                                  "Cannot open overview level %d of %s",
+                                  nOvrLevel, pszFilename );
+                    }
+                    GDALClose( poDS );
+                    poDS = NULL;
+                }
+                else
+                {
+                    poDS = poOvrDS;
+                }
+            }
+
             return (GDALDatasetH) poDS;
         }
 
@@ -2346,15 +2654,18 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
         }
     }
 
-    if( oOpenInfo.bStatOK )
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                  "`%s' not recognised as a supported file format.\n",
-                  oOpenInfo.pszFilename );
-    else
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                  "`%s' does not exist in the file system,\n"
-                  "and is not recognised as a supported dataset name.\n",
-                  oOpenInfo.pszFilename );
+    if( nOpenFlags & GDAL_OF_VERBOSE_ERROR )
+    {
+        if( oOpenInfo.bStatOK )
+            CPLError( CE_Failure, CPLE_OpenFailed,
+                    "`%s' not recognised as a supported file format.\n",
+                    pszFilename );
+        else
+            CPLError( CE_Failure, CPLE_OpenFailed,
+                    "`%s' does not exist in the file system,\n"
+                    "and is not recognised as a supported dataset name.\n",
+                    pszFilename );
+    }
 
     int* pnRecCount = (int*)CPLGetTLS( CTLS_GDALDATASET_REC_PROTECT_MAP );
     if( pnRecCount )
@@ -2381,7 +2692,7 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
  * Starting with GDAL 1.6.0, if GDALOpenShared() is called on the same pszFilename
  * from two different threads, a different GDALDataset object will be returned as
  * it is not safe to use the same dataset from different threads, unless the user
- * does explicitely use mutexes in its code.
+ * does explicitly use mutexes in its code.
  *
  * For drivers supporting the VSI virtual file API, it is possible to open
  * a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive
@@ -2391,6 +2702,7 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
  * process through the \ref gdal_api_proxy mechanism.
  *
  * \sa GDALOpen()
+ * \sa GDALOpenEx()
  *
  * @param pszFilename the name of the file to access.  In the case of
  * exotic drivers this may not refer to a physical file, but instead contain
@@ -2406,87 +2718,38 @@ GDALDatasetH GDALOpenInternal( GDALOpenInfo& oOpenInfo,
  
 GDALDatasetH CPL_STDCALL 
 GDALOpenShared( const char *pszFilename, GDALAccess eAccess )
-
 {
     VALIDATE_POINTER1( pszFilename, "GDALOpenShared", NULL );
+    return GDALOpenEx( pszFilename,
+                       GDAL_OF_RASTER |
+                       (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
+                       GDAL_OF_SHARED |
+                       GDAL_OF_VERBOSE_ERROR,
+                       NULL, NULL, NULL );
+}
 
-/* -------------------------------------------------------------------- */
-/*      First scan the existing list to see if it could already         */
-/*      contain the requested dataset.                                  */
-/* -------------------------------------------------------------------- */
-    {
-        CPLMutexHolderD( &hDLMutex );
+/************************************************************************/
+/*                             GDALClose()                              */
+/************************************************************************/
 
-        if (phSharedDatasetSet != NULL)
-        {
-            GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
-            SharedDatasetCtxt* psStruct;
-            SharedDatasetCtxt sStruct;
-
-            sStruct.nPID = nThisPID;
-            sStruct.pszDescription = (char*) pszFilename;
-            sStruct.eAccess = eAccess;
-            psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct);
-            if (psStruct == NULL && eAccess == GA_ReadOnly)
-            {
-                sStruct.eAccess = GA_Update;
-                psStruct = (SharedDatasetCtxt*) CPLHashSetLookup(phSharedDatasetSet, &sStruct);
-            }
-            if (psStruct)
-            {
-                psStruct->poDS->Reference();
-                return psStruct->poDS;
-            }
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Try opening the the requested dataset.                          */
-/* -------------------------------------------------------------------- */
-    GDALDataset *poDataset;
-
-    poDataset = (GDALDataset *) GDALOpen( pszFilename, eAccess );
-    if( poDataset != NULL )
-    {
-        if (strcmp(pszFilename, poDataset->GetDescription()) != 0)
-        {
-            CPLError(CE_Warning, CPLE_NotSupported,
-                     "A dataset opened by GDALOpenShared should have the same filename (%s) "
-                     "and description (%s)",
-                     pszFilename, poDataset->GetDescription());
-        }
-        else
-        {
-            poDataset->MarkAsShared();
-        }
-    }
-    
-    return (GDALDatasetH) poDataset;
-}
-
-/************************************************************************/
-/*                             GDALClose()                              */
-/************************************************************************/
-
-/**
- * \brief Close GDAL dataset. 
- *
- * For non-shared datasets (opened with GDALOpen()) the dataset is closed
- * using the C++ "delete" operator, recovering all dataset related resources.  
- * For shared datasets (opened with GDALOpenShared()) the dataset is 
- * dereferenced, and closed only if the referenced count has dropped below 1.
- *
- * @param hDS The dataset to close.  May be cast from a "GDALDataset *". 
- */
+/**
+ * \brief Close GDAL dataset. 
+ *
+ * For non-shared datasets (opened with GDALOpen()) the dataset is closed
+ * using the C++ "delete" operator, recovering all dataset related resources.  
+ * For shared datasets (opened with GDALOpenShared()) the dataset is 
+ * dereferenced, and closed only if the referenced count has dropped below 1.
+ *
+ * @param hDS The dataset to close.  May be cast from a "GDALDataset *". 
+ */
 
 void CPL_STDCALL GDALClose( GDALDatasetH hDS )
 
 {
-    VALIDATE_POINTER0( hDS, "GDALClose" );
+    if( hDS == NULL )
+        return;
 
     GDALDataset *poDS = (GDALDataset *) hDS;
-    CPLMutexHolderD( &hDLMutex );
-    CPLLocaleC  oLocaleForcer;
 
     if (poDS->GetShared())
     {
@@ -2539,12 +2802,9 @@ static int GDALDumpOpenSharedDatasetsForeach(void* elt, void* user_data)
 }
 
 
-static int GDALDumpOpenDatasetsForeach(void* elt, void* user_data)
+static int GDALDumpOpenDatasetsForeach(GDALDataset* poDS, FILE *fp)
 {
-    DatasetCtxt* psStruct = (DatasetCtxt*) elt;
-    FILE *fp = (FILE*) user_data;
     const char *pszDriverName;
-    GDALDataset *poDS = psStruct->poDS;
 
     /* Don't list shared datasets. They have already been listed by */
     /* GDALDumpOpenSharedDatasetsForeach */
@@ -2587,15 +2847,19 @@ int CPL_STDCALL GDALDumpOpenDatasets( FILE *fp )
 
     CPLMutexHolderD( &hDLMutex );
 
-    if (phAllDatasetSet != NULL)
+    if (poAllDatasetMap != NULL)
     {
         VSIFPrintf( fp, "Open GDAL Datasets:\n" );
-        CPLHashSetForeach(phAllDatasetSet, GDALDumpOpenDatasetsForeach, fp);
+        std::map<GDALDataset*, GIntBig>::iterator oIter = poAllDatasetMap->begin();
+        for(; oIter != poAllDatasetMap->end(); ++oIter )
+        {
+            GDALDumpOpenDatasetsForeach(oIter->first, fp);
+        }
         if (phSharedDatasetSet != NULL)
         {
             CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach, fp);
         }
-        return CPLHashSetSize(phAllDatasetSet);
+        return (int)poAllDatasetMap->size();
     }
     else
     {
@@ -2834,3 +3098,2624 @@ void GDALDataset::ReportError(CPLErr eErrClass, int err_no, const char *fmt, ...
     }
     va_end(args);
 }
+
+/************************************************************************/
+/*                            GetDriverName()                           */
+/************************************************************************/
+
+const char* GDALDataset::GetDriverName()
+{
+    if( poDriver )
+        return poDriver->GetDescription();
+    return "";
+}
+
+/************************************************************************/
+/*                     GDALDatasetReleaseResultSet()                    */
+/************************************************************************/
+
+/**
+ \brief Release results of ExecuteSQL().
+
+ This function should only be used to deallocate OGRLayers resulting from
+ an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
+ results set before destroying the GDALDataset may cause errors. 
+
+ This function is the same as the C++ method GDALDataset::ReleaseResultSet()
+
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @param poResultsSet the result of a previous ExecuteSQL() call.
+
+*/ 
+void GDALDatasetReleaseResultSet( GDALDatasetH hDS, OGRLayerH hLayer )
+
+{
+    VALIDATE_POINTER0( hDS, "GDALDatasetReleaseResultSet" );
+
+    ((GDALDataset *) hDS)->ReleaseResultSet( (OGRLayer *) hLayer );
+}
+
+/************************************************************************/
+/*                     GDALDatasetTestCapability()                      */
+/************************************************************************/
+
+/**
+ \brief Test if capability is available.
+
+ One of the following dataset capability names can be passed into this
+ function, and a TRUE or FALSE value will be returned indicating whether or not
+ the capability is available for this object.
+
+ <ul>
+  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
+  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing layers.<p>
+  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
+        datasource support CreateGeomField() just after layer creation.<p>
+  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve geometries.<p>
+  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient) transactions.<p>
+  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports transactions through emulation.<p>
+ </ul>
+
+ The \#define macro forms of the capability names should be used in preference
+ to the strings themselves to avoid mispelling.
+
+ This function is the same as the C++ method GDALDataset::TestCapability()
+
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @param pszCapability the capability to test.
+
+ @return TRUE if capability available otherwise FALSE.
+
+*/ 
+int GDALDatasetTestCapability( GDALDatasetH hDS, const char *pszCap )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetTestCapability", 0 );
+    VALIDATE_POINTER1( pszCap, "GDALDatasetTestCapability", 0 );
+
+    return ((GDALDataset *) hDS)->TestCapability( pszCap );
+}
+
+/************************************************************************/
+/*                       GDALDatasetGetLayerCount()                     */
+/************************************************************************/
+
+/**
+ \brief Get the number of layers in this dataset.
+
+ This function is the same as the C++ method GDALDataset::GetLayerCount()
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @return layer count.
+*/
+
+int GDALDatasetGetLayerCount( GDALDatasetH hDS )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetH", 0 );
+
+    return ((GDALDataset *)hDS)->GetLayerCount();
+}
+
+/************************************************************************/
+/*                        GDALDatasetGetLayer()                         */
+/************************************************************************/
+
+/**
+ \brief Fetch a layer by index.
+
+ The returned layer remains owned by the 
+ GDALDataset and should not be deleted by the application.
+
+ This function is the same as the C++ method GDALDataset::GetLayer()
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @param iLayer a layer number between 0 and GetLayerCount()-1.
+
+ @return the layer, or NULL if iLayer is out of range or an error occurs.
+*/
+
+OGRLayerH GDALDatasetGetLayer( GDALDatasetH hDS, int iLayer )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetGetLayer", NULL );
+
+    return (OGRLayerH) ((GDALDataset*)hDS)->GetLayer( iLayer );
+}
+
+/************************************************************************/
+/*                     GDALDatasetGetLayerByName()                      */
+/************************************************************************/
+
+/**
+ \brief Fetch a layer by name.
+
+ The returned layer remains owned by the 
+ GDALDataset and should not be deleted by the application.
+
+ This function is the same as the C++ method GDALDataset::GetLayerByName()
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @param pszLayerName the layer name of the layer to fetch.
+
+ @return the layer, or NULL if Layer is not found or an error occurs.
+*/
+
+OGRLayerH GDALDatasetGetLayerByName( GDALDatasetH hDS, const char *pszName )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetGetLayerByName", NULL );
+
+    return (OGRLayerH) ((GDALDataset *) hDS)->GetLayerByName( pszName );
+}
+
+/************************************************************************/
+/*                        GDALDatasetDeleteLayer()                      */
+/************************************************************************/
+
+/**
+ \brief Delete the indicated layer from the datasource.
+
+ If this function is supported
+ the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
+
+ This method is the same as the C++ method GDALDataset::DeleteLayer().
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle.
+ @param iLayer the index of the layer to delete. 
+
+ @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
+ layers is not supported for this datasource.
+
+*/
+OGRErr GDALDatasetDeleteLayer( GDALDatasetH hDS, int iLayer )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE );
+
+    return ((GDALDataset *) hDS)->DeleteLayer( iLayer );
+}
+
+/************************************************************************/
+/*                            CreateLayer()                             */
+/************************************************************************/
+
+/**
+\brief This method attempts to create a new layer on the dataset with the indicated name, coordinate system, geometry type.
+
+The papszOptions argument
+can be used to control driver specific creation options.  These options are
+normally documented in the format specific documentation. 
+
+ In GDAL 2.0, drivers should extend the ICreateLayer() method and not CreateLayer().
+ CreateLayer() adds validation of layer creation options, before delegating the
+ actual work to ICreateLayer().
+
+ This method is the same as the C function GDALDatasetCreateLayer() and the
+ deprecated OGR_DS_CreateLayer(). 
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @param hDS the dataset handle
+ @param pszName the name for the new layer.  This should ideally not 
+match any existing layer on the datasource.
+ @param poSpatialRef the coordinate system to use for the new layer, or NULL if
+no coordinate system is available. 
+ @param eGType the geometry type for the layer.  Use wkbUnknown if there
+are no constraints on the types geometry to be written. 
+ @param papszOptions a StringList of name=value options.  Options are driver
+specific.
+
+ @return NULL is returned on failure, or a new OGRLayer handle on success. 
+
+<b>Example:</b>
+
+\code
+#include "gdal.h" 
+#include "cpl_string.h"
+
+...
+
+        OGRLayer *poLayer;
+        char     **papszOptions;
+
+        if( !poDS->TestCapability( ODsCCreateLayer ) )
+        {
+        ...
+        }
+
+        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
+        poLayer = poDS->CreateLayer( "NewLayer", NULL, wkbUnknown,
+                                     papszOptions );
+        CSLDestroy( papszOptions );
+
+        if( poLayer == NULL )
+        {
+            ...
+        }        
+\endcode
+*/
+
+OGRLayer *GDALDataset::CreateLayer( const char * pszName,
+                                      OGRSpatialReference * poSpatialRef,
+                                      OGRwkbGeometryType eGType,
+                                      char **papszOptions )
+
+{
+    ValidateLayerCreationOptions( papszOptions );
+
+    if( OGR_GT_IsNonLinear(eGType) && !TestCapability(ODsCCurveGeometries) )
+    {
+        eGType = OGR_GT_GetLinear(eGType);
+    }
+
+    OGRLayer* poLayer = ICreateLayer(pszName, poSpatialRef, eGType, papszOptions);
+#ifdef DEBUG
+    if( poLayer != NULL && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
+        !poLayer->TestCapability(OLCCurveGeometries) )
+    {
+        CPLError( CE_Warning, CPLE_AppDefined,
+                  "Inconsistant driver: Layer geometry type is non-linear, but "
+                  "TestCapability(OLCCurveGeometries) returns FALSE." );
+    }
+#endif
+
+    return poLayer;
+}
+
+/************************************************************************/
+/*                         GDALDatasetCreateLayer()                     */
+/************************************************************************/
+
+/**
+\brief This function attempts to create a new layer on the dataset with the indicated name, coordinate system, geometry type.
+
+The papszOptions argument
+can be used to control driver specific creation options.  These options are
+normally documented in the format specific documentation. 
+
+ This method is the same as the C++ method GDALDataset::CreateLayer().
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle
+ @param pszName the name for the new layer.  This should ideally not 
+match any existing layer on the datasource.
+ @param poSpatialRef the coordinate system to use for the new layer, or NULL if
+no coordinate system is available. 
+ @param eGType the geometry type for the layer.  Use wkbUnknown if there
+are no constraints on the types geometry to be written. 
+ @param papszOptions a StringList of name=value options.  Options are driver
+specific.
+
+ @return NULL is returned on failure, or a new OGRLayer handle on success. 
+
+<b>Example:</b>
+
+\code
+#include "gdal.h" 
+#include "cpl_string.h"
+
+...
+
+        OGRLayer *poLayer;
+        char     **papszOptions;
+
+        if( !poDS->TestCapability( ODsCCreateLayer ) )
+        {
+        ...
+        }
+
+        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
+        poLayer = poDS->CreateLayer( "NewLayer", NULL, wkbUnknown,
+                                     papszOptions );
+        CSLDestroy( papszOptions );
+
+        if( poLayer == NULL )
+        {
+            ...
+        }        
+\endcode
+*/
+
+OGRLayerH GDALDatasetCreateLayer( GDALDatasetH hDS, 
+                              const char * pszName,
+                              OGRSpatialReferenceH hSpatialRef,
+                              OGRwkbGeometryType eType,
+                              char ** papszOptions )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetCreateLayer", NULL );
+
+    if (pszName == NULL)
+    {
+        CPLError ( CE_Failure, CPLE_ObjectNull, "Name was NULL in GDALDatasetCreateLayer");
+        return 0;
+    }
+    return (OGRLayerH) ((GDALDataset *)hDS)->CreateLayer( 
+        pszName, (OGRSpatialReference *) hSpatialRef, eType, papszOptions );
+}
+
+
+/************************************************************************/
+/*                         GDALDatasetCopyLayer()                       */
+/************************************************************************/
+
+/**
+ \brief Duplicate an existing layer.
+
+ This function creates a new layer, duplicate the field definitions of the
+ source layer and then duplicate each features of the source layer.
+ The papszOptions argument
+ can be used to control driver specific creation options.  These options are
+ normally documented in the format specific documentation.
+ The source layer may come from another dataset.
+
+ This method is the same as the C++ method GDALDataset::CopyLayer()
+ 
+ @since GDAL 2.0
+
+ @param hDS the dataset handle. 
+ @param hSrcLayer source layer.
+ @param pszNewName the name of the layer to create.
+ @param papszOptions a StringList of name=value options.  Options are driver
+                     specific.
+
+ @return an handle to the layer, or NULL if an error occurs.
+*/
+OGRLayerH GDALDatasetCopyLayer( GDALDatasetH hDS, 
+                                OGRLayerH hSrcLayer, const char *pszNewName,
+                                char **papszOptions )
+
+{
+    VALIDATE_POINTER1( hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", NULL );
+    VALIDATE_POINTER1( hSrcLayer, "GDALDatasetCopyLayer", NULL );
+    VALIDATE_POINTER1( pszNewName, "GDALDatasetCopyLayer", NULL );
+
+    return (OGRLayerH) 
+        ((GDALDataset *) hDS)->CopyLayer( (OGRLayer *) hSrcLayer, 
+                                            pszNewName, papszOptions );
+}
+
+/************************************************************************/
+/*                        GDALDatasetExecuteSQL()                       */
+/************************************************************************/
+
+/**
+ \brief Execute an SQL statement against the data store. 
+
+ The result of an SQL query is either NULL for statements that are in error,
+ or that have no results set, or an OGRLayer pointer representing a results
+ set from the query.  Note that this OGRLayer is in addition to the layers
+ in the data store and must be destroyed with 
+ ReleaseResultSet() before the dataset is closed
+ (destroyed).  
+
+ This method is the same as the C++ method GDALDataset::ExecuteSQL()
+
+ For more information on the SQL dialect supported internally by OGR
+ review the <a href="ogr_sql.html">OGR SQL</a> document.  Some drivers (ie.
+ Oracle and PostGIS) pass the SQL directly through to the underlying RDBMS.
+
+ Starting with OGR 1.10, the <a href="ogr_sql_sqlite.html">SQLITE dialect</a>
+ can also be used.
+ 
+ @since GDAL 2.0
+ 
+ @param hDS the dataset handle.
+ @param pszStatement the SQL statement to execute. 
+ @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
+ @param pszDialect allows control of the statement dialect. If set to NULL, the
+OGR SQL engine will be used, except for RDBMS drivers that will use their dedicated SQL engine,
+unless OGRSQL is explicitely passed as the dialect. Starting with OGR 1.10, the SQLITE dialect
+can also be used.
+
+ @return an OGRLayer containing the results of the query.  Deallocate with
+ ReleaseResultSet().
+
+*/
+
+OGRLayerH GDALDatasetExecuteSQL( GDALDatasetH hDS, 
+                             const char *pszStatement,
+                             OGRGeometryH hSpatialFilter,
+                             const char *pszDialect )
+
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetExecuteSQL", NULL );
+
+    return (OGRLayerH) 
+        ((GDALDataset *)hDS)->ExecuteSQL( pszStatement,
+                                            (OGRGeometry *) hSpatialFilter,
+                                            pszDialect );
+}
+
+/************************************************************************/
+/*                      GDALDatasetGetStyleTable()                      */
+/************************************************************************/
+
+/**
+ \brief Returns dataset style table.
+ 
+ This function is the same as the C++ method GDALDataset::GetStyleTable()
+ 
+ @since GDAL 2.0
+ 
+ @param hDS the dataset handle
+ @return handle to a style table which should not be modified or freed by the
+ caller.
+*/
+
+OGRStyleTableH GDALDatasetGetStyleTable( GDALDatasetH hDS )
+
+{
+    VALIDATE_POINTER1( hDS, "OGR_DS_GetStyleTable", NULL );
+    
+    return (OGRStyleTableH) ((GDALDataset *) hDS)->GetStyleTable( );
+}
+
+/************************************************************************/
+/*                    GDALDatasetSetStyleTableDirectly()                */
+/************************************************************************/
+
+/**
+ \brief Set dataset style table.
+ 
+ This function operate exactly as GDALDatasetSetStyleTable() except that it
+ assumes ownership of the passed table.
+ 
+ This function is the same as the C++ method GDALDataset::SetStyleTableDirectly()
+ 
+ @since GDAL 2.0
+ 
+ @param hDS the dataset handle
+ @param hStyleTable style table handle to set
+
+*/
+
+void GDALDatasetSetStyleTableDirectly( GDALDatasetH hDS,
+                                   OGRStyleTableH hStyleTable )
+
+{
+    VALIDATE_POINTER0( hDS, "OGR_DS_SetStyleTableDirectly" );
+    
+    ((GDALDataset *) hDS)->SetStyleTableDirectly( (OGRStyleTable *) hStyleTable);
+}
+
+/************************************************************************/
+/*                     GDALDatasetSetStyleTable()                       */
+/************************************************************************/
+
+/**
+ \brief Set dataset style table.
+ 
+ This function operate exactly as GDALDatasetSetStyleTableDirectly() except that it
+ assumes ownership of the passed table.
+ 
+ This function is the same as the C++ method GDALDataset::SetStyleTable()
+ 
+ @since GDAL 2.0
+ 
+ @param hDS the dataset handle
+ @param hStyleTable style table handle to set
+
+*/
+
+void GDALDatasetSetStyleTable( GDALDatasetH hDS, OGRStyleTableH hStyleTable )
+
+{
+    VALIDATE_POINTER0( hDS, "OGR_DS_SetStyleTable" );
+    VALIDATE_POINTER0( hStyleTable, "OGR_DS_SetStyleTable" );
+    
+    ((GDALDataset *) hDS)->SetStyleTable( (OGRStyleTable *) hStyleTable);
+}
+
+/************************************************************************/
+/*                    ValidateLayerCreationOptions()                    */
+/************************************************************************/
+
+int GDALDataset::ValidateLayerCreationOptions( const char* const* papszLCO )
+{
+    const char *pszOptionList = GetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST );
+    if( pszOptionList == NULL && poDriver != NULL )
+    {
+        pszOptionList = 
+             poDriver->GetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST );
+    }
+    CPLString osDataset;
+    osDataset.Printf("dataset %s", GetDescription());
+    return GDALValidateOptions( pszOptionList, papszLCO,
+                                "layer creation option",
+                                osDataset );
+}
+
+/************************************************************************/
+/*                              Release()                               */
+/************************************************************************/
+
+/**
+ \fn OGRErr OGRDataSource::Release();
+
+\brief Drop a reference to this dataset, and if the reference count drops to one close (destroy) the dataset.
+
+This method is the same as the C function OGRReleaseDataSource().
+
+ at deprecated. In GDAL 2, use GDALClose() instead
+
+ at return OGRERR_NONE on success or an error code. 
+*/
+
+OGRErr GDALDataset::Release()
+
+{
+    GDALClose( (GDALDatasetH) this );
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            GetRefCount()                             */
+/************************************************************************/
+
+/**
+\brief Fetch reference count.
+
+This method is the same as the C function OGR_DS_GetRefCount().
+
+In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ at return the current reference count for the datasource object itself.
+*/
+
+
+int GDALDataset::GetRefCount() const
+
+{
+    return nRefCount;
+}
+
+/************************************************************************/
+/*                         GetSummaryRefCount()                         */
+/************************************************************************/
+
+/**
+\brief Fetch reference count of datasource and all owned layers.
+
+This method is the same as the C function  OGR_DS_GetSummaryRefCount().
+
+In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ at deprecated
+ 
+ at return the current summary reference count for the datasource and its layers.
+*/
+
+int GDALDataset::GetSummaryRefCount() const
+
+{
+    CPLMutexHolderD( (CPLMutex**) &m_hMutex );
+    int nSummaryCount = nRefCount;
+    int iLayer;
+    GDALDataset *poUseThis = (GDALDataset *) this;
+
+    for( iLayer=0; iLayer < poUseThis->GetLayerCount(); iLayer++ )
+        nSummaryCount += poUseThis->GetLayer( iLayer )->GetRefCount();
+
+    return nSummaryCount;
+}
+
+/************************************************************************/
+/*                           ICreateLayer()                             */
+/************************************************************************/
+
+/**
+\brief This method attempts to create a new layer on the dataset with the indicated name, coordinate system, geometry type.
+
+This method is reserved to implementation by drivers.
+
+The papszOptions argument
+can be used to control driver specific creation options.  These options are
+normally documented in the format specific documentation. 
+
+ @param pszName the name for the new layer.  This should ideally not 
+match any existing layer on the datasource.
+ @param poSpatialRef the coordinate system to use for the new layer, or NULL if
+no coordinate system is available. 
+ @param eGType the geometry type for the layer.  Use wkbUnknown if there
+are no constraints on the types geometry to be written. 
+ @param papszOptions a StringList of name=value options.  Options are driver
+specific.
+
+ @return NULL is returned on failure, or a new OGRLayer handle on success. 
+ 
+ @since GDAL 2.0
+*/
+
+OGRLayer *GDALDataset::ICreateLayer( const char * pszName,
+                                      OGRSpatialReference * poSpatialRef,
+                                      OGRwkbGeometryType eGType,
+                                      char **papszOptions )
+
+{
+    (void) eGType;
+    (void) poSpatialRef;
+    (void) pszName;
+    (void) papszOptions;
+
+    CPLError( CE_Failure, CPLE_NotSupported,
+              "CreateLayer() not supported by this dataset." );
+              
+    return NULL;
+}
+
+/************************************************************************/
+/*                             CopyLayer()                              */
+/************************************************************************/
+
+/**
+ \brief Duplicate an existing layer.
+
+ This method creates a new layer, duplicate the field definitions of the
+ source layer and then duplicate each features of the source layer.
+ The papszOptions argument
+ can be used to control driver specific creation options.  These options are
+ normally documented in the format specific documentation.
+ The source layer may come from another dataset.
+
+ This method is the same as the C function GDALDatasetCopyLayer() and the
+ deprecated OGR_DS_CopyLayer().
+
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @param poSrcLayer source layer.
+ @param pszNewName the name of the layer to create.
+ @param papszOptions a StringList of name=value options.  Options are driver
+                     specific.
+
+ @return an handle to the layer, or NULL if an error occurs.
+*/
+
+OGRLayer *GDALDataset::CopyLayer( OGRLayer *poSrcLayer, 
+                                    const char *pszNewName, 
+                                    char **papszOptions )
+
+{
+    OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
+    OGRLayer *poDstLayer = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Create the layer.                                               */
+/* -------------------------------------------------------------------- */
+    if( !TestCapability( ODsCCreateLayer ) )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported, 
+                  "This datasource does not support creation of layers." );
+        return NULL;
+    }
+
+    CPLErrorReset();
+    if( poSrcDefn->GetGeomFieldCount() > 1 &&
+        TestCapability(ODsCCreateGeomFieldAfterCreateLayer) )
+    {
+        poDstLayer =ICreateLayer( pszNewName, NULL, wkbNone, papszOptions );
+    }
+    else
+    {
+        poDstLayer =ICreateLayer( pszNewName, poSrcLayer->GetSpatialRef(),
+                                  poSrcDefn->GetGeomType(), papszOptions );
+    }
+    
+    if( poDstLayer == NULL )
+        return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Add fields.  Default to copy all fields, and make sure to       */
+/*      establish a mapping between indices, rather than names, in      */
+/*      case the target datasource has altered it (e.g. Shapefile       */
+/*      limited to 10 char field names).                                */
+/* -------------------------------------------------------------------- */
+    int         nSrcFieldCount = poSrcDefn->GetFieldCount();
+    int         nDstFieldCount = 0;
+    int         iField, *panMap;
+
+    // Initialize the index-to-index map to -1's
+    panMap = (int *) CPLMalloc( sizeof(int) * nSrcFieldCount );
+    for( iField=0; iField < nSrcFieldCount; iField++)
+        panMap[iField] = -1;
+
+    /* Caution : at the time of writing, the MapInfo driver */
+    /* returns NULL until a field has been added */
+    OGRFeatureDefn* poDstFDefn = poDstLayer->GetLayerDefn();
+    if (poDstFDefn)
+        nDstFieldCount = poDstFDefn->GetFieldCount();    
+    for( iField = 0; iField < nSrcFieldCount; iField++ )
+    {
+        OGRFieldDefn* poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
+        OGRFieldDefn oFieldDefn( poSrcFieldDefn );
+
+        /* The field may have been already created at layer creation */
+        int iDstField = -1;
+        if (poDstFDefn)
+            iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
+        if (iDstField >= 0)
+        {
+            panMap[iField] = iDstField;
+        }
+        else if (poDstLayer->CreateField( &oFieldDefn ) == OGRERR_NONE)
+        {
+            /* now that we've created a field, GetLayerDefn() won't return NULL */
+            if (poDstFDefn == NULL)
+                poDstFDefn = poDstLayer->GetLayerDefn();
+
+            /* Sanity check : if it fails, the driver is buggy */
+            if (poDstFDefn != NULL &&
+                poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "The output driver has claimed to have added the %s field, but it did not!",
+                         oFieldDefn.GetNameRef() );
+            }
+            else
+            {
+                panMap[iField] = nDstFieldCount;
+                nDstFieldCount ++;
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create geometry fields.                                         */
+/* -------------------------------------------------------------------- */
+    if( poSrcDefn->GetGeomFieldCount() > 1 &&
+        TestCapability(ODsCCreateGeomFieldAfterCreateLayer) )
+    {
+        int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
+        for( iField = 0; iField < nSrcGeomFieldCount; iField++ )
+        {
+            poDstLayer->CreateGeomField( poSrcDefn->GetGeomFieldDefn(iField) );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Check if the destination layer supports transactions and set a  */
+/*      default number of features in a single transaction.             */
+/* -------------------------------------------------------------------- */
+    int nGroupTransactions = 0;
+    if( poDstLayer->TestCapability( OLCTransactions ) )
+        nGroupTransactions = 128;
+
+/* -------------------------------------------------------------------- */
+/*      Transfer features.                                              */
+/* -------------------------------------------------------------------- */
+    OGRFeature  *poFeature;
+
+    poSrcLayer->ResetReading();
+
+    if( nGroupTransactions <= 0 )
+    {
+      while( TRUE )
+      {
+        OGRFeature      *poDstFeature = NULL;
+
+        poFeature = poSrcLayer->GetNextFeature();
+        
+        if( poFeature == NULL )
+            break;
+
+        CPLErrorReset();
+        poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+
+        if( poDstFeature->SetFrom( poFeature, panMap, TRUE ) != OGRERR_NONE )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Unable to translate feature " CPL_FRMT_GIB " from layer %s.\n",
+                      poFeature->GetFID(), poSrcDefn->GetName() );
+            OGRFeature::DestroyFeature( poFeature );
+            CPLFree(panMap);
+            return poDstLayer;
+        }
+
+        poDstFeature->SetFID( poFeature->GetFID() );
+
+        OGRFeature::DestroyFeature( poFeature );
+
+        CPLErrorReset();
+        if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
+        {
+            OGRFeature::DestroyFeature( poDstFeature );
+            CPLFree(panMap);
+            return poDstLayer;
+        }
+
+        OGRFeature::DestroyFeature( poDstFeature );
+      }
+    }
+    else
+    {
+      int i, bStopTransfer = FALSE, bStopTransaction = FALSE;
+      int nFeatCount = 0; // Number of features in the temporary array
+      int nFeaturesToAdd = 0;
+      OGRFeature **papoDstFeature =
+          (OGRFeature **)CPLCalloc(sizeof(OGRFeature *), nGroupTransactions);
+      while( !bStopTransfer )
+      {
+/* -------------------------------------------------------------------- */
+/*      Fill the array with features                                    */
+/* -------------------------------------------------------------------- */
+        for( nFeatCount = 0; nFeatCount < nGroupTransactions; nFeatCount++ )
+        {
+            poFeature = poSrcLayer->GetNextFeature();
+
+            if( poFeature == NULL )
+            {
+                bStopTransfer = 1;
+                break;
+            }
+
+            CPLErrorReset();
+            papoDstFeature[nFeatCount] =
+                        OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
+
+            if( papoDstFeature[nFeatCount]->SetFrom( poFeature, panMap, TRUE ) != OGRERR_NONE )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                          "Unable to translate feature " CPL_FRMT_GIB " from layer %s.\n",
+                          poFeature->GetFID(), poSrcDefn->GetName() );
+                OGRFeature::DestroyFeature( poFeature );
+                bStopTransfer = TRUE;
+                break;
+            }
+
+            papoDstFeature[nFeatCount]->SetFID( poFeature->GetFID() );
+
+            OGRFeature::DestroyFeature( poFeature );
+        }
+        nFeaturesToAdd = nFeatCount;
+
+        CPLErrorReset();
+        bStopTransaction = FALSE;
+        while( !bStopTransaction )
+        {
+            bStopTransaction = TRUE;
+            poDstLayer->StartTransaction();
+            for( i = 0; i < nFeaturesToAdd; i++ )
+            {
+                if( poDstLayer->CreateFeature( papoDstFeature[i] ) != OGRERR_NONE )
+                {
+                    nFeaturesToAdd = i;
+                    bStopTransfer = TRUE;
+                    bStopTransaction = FALSE;
+                }
+            }
+            if( bStopTransaction )
+                poDstLayer->CommitTransaction();
+            else
+                poDstLayer->RollbackTransaction();
+        }
+
+        for( i = 0; i < nFeatCount; i++ )
+            OGRFeature::DestroyFeature( papoDstFeature[i] );
+      }
+      CPLFree(papoDstFeature);
+    }
+
+    CPLFree(panMap);
+
+    return poDstLayer;
+}
+
+/************************************************************************/
+/*                            DeleteLayer()                             */
+/************************************************************************/
+
+/**
+ \brief Delete the indicated layer from the datasource.
+
+ If this method is supported
+ the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
+
+ This method is the same as the C function GDALDatasetDeleteLayer() and the
+ deprecated OGR_DS_DeleteLayer().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @param iLayer the index of the layer to delete. 
+
+ @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
+ layers is not supported for this datasource.
+
+*/
+OGRErr GDALDataset::DeleteLayer( int iLayer )
+
+{
+    (void) iLayer;
+    CPLError( CE_Failure, CPLE_NotSupported,
+              "DeleteLayer() not supported by this dataset." );
+              
+    return OGRERR_UNSUPPORTED_OPERATION;
+}
+
+/************************************************************************/
+/*                           GetLayerByName()                           */
+/************************************************************************/
+
+/**
+ \brief Fetch a layer by name.
+
+ The returned layer remains owned by the 
+ GDALDataset and should not be deleted by the application.
+
+ This method is the same as the C function GDALDatasetGetLayerByName() and the
+ deprecated OGR_DS_GetLayerByName().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @param pszLayerName the layer name of the layer to fetch.
+
+ @return the layer, or NULL if Layer is not found or an error occurs.
+*/
+
+OGRLayer *GDALDataset::GetLayerByName( const char *pszName )
+
+{
+    CPLMutexHolderD( &m_hMutex );
+
+    if ( ! pszName )
+        return NULL;
+
+    int  i;
+
+    /* first a case sensitive check */
+    for( i = 0; i < GetLayerCount(); i++ )
+    {
+        OGRLayer *poLayer = GetLayer(i);
+
+        if( strcmp( pszName, poLayer->GetName() ) == 0 )
+            return poLayer;
+    }
+
+    /* then case insensitive */
+    for( i = 0; i < GetLayerCount(); i++ )
+    {
+        OGRLayer *poLayer = GetLayer(i);
+
+        if( EQUAL( pszName, poLayer->GetName() ) )
+            return poLayer;
+    }
+
+    return NULL;
+}
+
+/************************************************************************/
+/*                       ProcessSQLCreateIndex()                        */
+/*                                                                      */
+/*      The correct syntax for creating an index in our dialect of      */
+/*      SQL is:                                                         */
+/*                                                                      */
+/*        CREATE INDEX ON <layername> USING <columnname>                */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLCreateIndex( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    if( CSLCount(papszTokens) != 6 
+        || !EQUAL(papszTokens[0],"CREATE")
+        || !EQUAL(papszTokens[1],"INDEX")
+        || !EQUAL(papszTokens[2],"ON")
+        || !EQUAL(papszTokens[4],"USING") )
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Syntax error in CREATE INDEX command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'CREATE INDEX ON <table> USING <field>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    int  i;
+    OGRLayer *poLayer = NULL;
+
+    {
+        CPLMutexHolderD( &m_hMutex );
+
+        for( i = 0; i < GetLayerCount(); i++ )
+        {
+            poLayer = GetLayer(i);
+            
+            if( EQUAL(poLayer->GetName(),papszTokens[3]) )
+                break;
+        }
+        
+        if( i >= GetLayerCount() )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "CREATE INDEX ON failed, no such layer as `%s'.",
+                      papszTokens[3] );
+            CSLDestroy( papszTokens );
+            return OGRERR_FAILURE;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Does this layer even support attribute indexes?                 */
+/* -------------------------------------------------------------------- */
+    if( poLayer->GetIndex() == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "CREATE INDEX ON not supported by this driver." );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named field.                                           */
+/* -------------------------------------------------------------------- */
+    for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
+    {
+        if( EQUAL(papszTokens[5],
+                  poLayer->GetLayerDefn()->GetFieldDefn(i)->GetNameRef()) )
+            break;
+    }
+
+    CSLDestroy( papszTokens );
+
+    if( i >= poLayer->GetLayerDefn()->GetFieldCount() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "`%s' failed, field not found.",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Attempt to create the index.                                    */
+/* -------------------------------------------------------------------- */
+    OGRErr eErr;
+
+    eErr = poLayer->GetIndex()->CreateIndex( i );
+    if( eErr == OGRERR_NONE )
+        eErr = poLayer->GetIndex()->IndexAllFeatures( i );
+    else
+    {
+        if( strlen(CPLGetLastErrorMsg()) == 0 )
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "Cannot '%s'", pszSQLCommand);
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                        ProcessSQLDropIndex()                         */
+/*                                                                      */
+/*      The correct syntax for droping one or more indexes in           */
+/*      the OGR SQL dialect is:                                         */
+/*                                                                      */
+/*          DROP INDEX ON <layername> [USING <columnname>]              */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLDropIndex( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    if( (CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6)
+        || !EQUAL(papszTokens[0],"DROP")
+        || !EQUAL(papszTokens[1],"INDEX")
+        || !EQUAL(papszTokens[2],"ON") 
+        || (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4],"USING")) )
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Syntax error in DROP INDEX command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    int  i;
+    OGRLayer *poLayer=NULL;
+
+    {
+        CPLMutexHolderD( &m_hMutex );
+
+        for( i = 0; i < GetLayerCount(); i++ )
+        {
+            poLayer = GetLayer(i);
+        
+            if( EQUAL(poLayer->GetName(),papszTokens[3]) )
+                break;
+        }
+
+        if( i >= GetLayerCount() )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "CREATE INDEX ON failed, no such layer as `%s'.",
+                      papszTokens[3] );
+            CSLDestroy( papszTokens );
+            return OGRERR_FAILURE;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Does this layer even support attribute indexes?                 */
+/* -------------------------------------------------------------------- */
+    if( poLayer->GetIndex() == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Indexes not supported by this driver." );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If we weren't given a field name, drop all indexes.             */
+/* -------------------------------------------------------------------- */
+    OGRErr eErr;
+
+    if( CSLCount(papszTokens) == 4 )
+    {
+        for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
+        {
+            OGRAttrIndex *poAttrIndex;
+
+            poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
+            if( poAttrIndex != NULL )
+            {
+                eErr = poLayer->GetIndex()->DropIndex( i );
+                if( eErr != OGRERR_NONE )
+                {
+                    CSLDestroy(papszTokens);
+                    return eErr;
+                }
+            }
+        }
+
+        CSLDestroy(papszTokens);
+        return OGRERR_NONE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named field.                                           */
+/* -------------------------------------------------------------------- */
+    for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
+    {
+        if( EQUAL(papszTokens[5],
+                  poLayer->GetLayerDefn()->GetFieldDefn(i)->GetNameRef()) )
+            break;
+    }
+
+    CSLDestroy( papszTokens );
+
+    if( i >= poLayer->GetLayerDefn()->GetFieldCount() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "`%s' failed, field not found.",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Attempt to drop the index.                                      */
+/* -------------------------------------------------------------------- */
+    eErr = poLayer->GetIndex()->DropIndex( i );
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                        ProcessSQLDropTable()                         */
+/*                                                                      */
+/*      The correct syntax for dropping a table (layer) in the OGR SQL  */
+/*      dialect is:                                                     */
+/*                                                                      */
+/*          DROP TABLE <layername>                                      */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLDropTable( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    if( CSLCount(papszTokens) != 3
+        || !EQUAL(papszTokens[0],"DROP")
+        || !EQUAL(papszTokens[1],"TABLE") )
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Syntax error in DROP TABLE command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'DROP TABLE <table>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    int  i;
+    OGRLayer *poLayer=NULL;
+
+    for( i = 0; i < GetLayerCount(); i++ )
+    {
+        poLayer = GetLayer(i);
+        
+        if( EQUAL(poLayer->GetName(),papszTokens[2]) )
+            break;
+    }
+    
+    if( i >= GetLayerCount() )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "DROP TABLE failed, no such layer as `%s'.",
+                  papszTokens[2] );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+    CSLDestroy( papszTokens );
+
+/* -------------------------------------------------------------------- */
+/*      Delete it.                                                      */
+/* -------------------------------------------------------------------- */
+
+    return DeleteLayer( i );
+}
+
+/************************************************************************/
+/*                    GDALDatasetParseSQLType()                       */
+/************************************************************************/
+
+/* All arguments will be altered */
+static OGRFieldType GDALDatasetParseSQLType(char* pszType, int& nWidth, int &nPrecision)
+{
+    char* pszParenthesis = strchr(pszType, '(');
+    if (pszParenthesis)
+    {
+        nWidth = atoi(pszParenthesis + 1);
+        *pszParenthesis = '\0';
+        char* pszComma = strchr(pszParenthesis + 1, ',');
+        if (pszComma)
+            nPrecision = atoi(pszComma + 1);
+    }
+
+    OGRFieldType eType = OFTString;
+    if (EQUAL(pszType, "INTEGER"))
+        eType = OFTInteger;
+    else if (EQUAL(pszType, "INTEGER[]"))
+        eType = OFTIntegerList;
+    else if (EQUAL(pszType, "FLOAT") ||
+             EQUAL(pszType, "NUMERIC") ||
+             EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
+             EQUAL(pszType, "REAL") /* unofficial alias */)
+        eType = OFTReal;
+    else if (EQUAL(pszType, "FLOAT[]") ||
+             EQUAL(pszType, "NUMERIC[]") ||
+             EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
+             EQUAL(pszType, "REAL[]") /* unofficial alias */)
+        eType = OFTRealList;
+    else if (EQUAL(pszType, "CHARACTER") ||
+             EQUAL(pszType, "TEXT") /* unofficial alias */ ||
+             EQUAL(pszType, "STRING") /* unofficial alias */ ||
+             EQUAL(pszType, "VARCHAR") /* unofficial alias */)
+        eType = OFTString;
+    else if (EQUAL(pszType, "TEXT[]") ||
+             EQUAL(pszType, "STRING[]") /* unofficial alias */||
+             EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
+        eType = OFTStringList;
+    else if (EQUAL(pszType, "DATE"))
+        eType = OFTDate;
+    else if (EQUAL(pszType, "TIME"))
+        eType = OFTTime;
+    else if (EQUAL(pszType, "TIMESTAMP") ||
+             EQUAL(pszType, "DATETIME") /* unofficial alias */ )
+        eType = OFTDateTime;
+    else
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Unsupported column type '%s'. Defaulting to VARCHAR",
+                 pszType);
+    }
+    return eType;
+}
+
+/************************************************************************/
+/*                    ProcessSQLAlterTableAddColumn()                   */
+/*                                                                      */
+/*      The correct syntax for adding a column in the OGR SQL           */
+/*      dialect is:                                                     */
+/*                                                                      */
+/*          ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype>*/
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLAlterTableAddColumn( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    const char* pszLayerName = NULL;
+    const char* pszColumnName = NULL;
+    char* pszType = NULL;
+    int iTypeIndex = 0;
+    int nTokens = CSLCount(papszTokens);
+
+    if( nTokens >= 7
+        && EQUAL(papszTokens[0],"ALTER")
+        && EQUAL(papszTokens[1],"TABLE")
+        && EQUAL(papszTokens[3],"ADD")
+        && EQUAL(papszTokens[4],"COLUMN"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[5];
+        iTypeIndex = 6;
+    }
+    else if( nTokens >= 6
+             && EQUAL(papszTokens[0],"ALTER")
+             && EQUAL(papszTokens[1],"TABLE")
+             && EQUAL(papszTokens[3],"ADD"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[4];
+        iTypeIndex = 5;
+    }
+    else
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Syntax error in ALTER TABLE ADD COLUMN command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Merge type components into a single string if there were split  */
+/*      with spaces                                                     */
+/* -------------------------------------------------------------------- */
+    CPLString osType;
+    for(int i=iTypeIndex;i<nTokens;i++)
+    {
+        osType += papszTokens[i];
+        CPLFree(papszTokens[i]);
+    }
+    pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
+    papszTokens[iTypeIndex + 1] = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    OGRLayer *poLayer = GetLayerByName(pszLayerName);
+    if( poLayer == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such layer as `%s'.",
+                  pszSQLCommand,
+                  pszLayerName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Add column.                                                     */
+/* -------------------------------------------------------------------- */
+
+    int nWidth = 0, nPrecision = 0;
+    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
+    OGRFieldDefn oFieldDefn(pszColumnName, eType);
+    oFieldDefn.SetWidth(nWidth);
+    oFieldDefn.SetPrecision(nPrecision);
+
+    CSLDestroy( papszTokens );
+
+    return poLayer->CreateField( &oFieldDefn );
+}
+
+/************************************************************************/
+/*                    ProcessSQLAlterTableDropColumn()                  */
+/*                                                                      */
+/*      The correct syntax for droping a column in the OGR SQL          */
+/*      dialect is:                                                     */
+/*                                                                      */
+/*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLAlterTableDropColumn( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    const char* pszLayerName = NULL;
+    const char* pszColumnName = NULL;
+    if( CSLCount(papszTokens) == 6
+        && EQUAL(papszTokens[0],"ALTER")
+        && EQUAL(papszTokens[1],"TABLE")
+        && EQUAL(papszTokens[3],"DROP")
+        && EQUAL(papszTokens[4],"COLUMN"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[5];
+    }
+    else if( CSLCount(papszTokens) == 5
+             && EQUAL(papszTokens[0],"ALTER")
+             && EQUAL(papszTokens[1],"TABLE")
+             && EQUAL(papszTokens[3],"DROP"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[4];
+    }
+    else
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Syntax error in ALTER TABLE DROP COLUMN command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] <columnname>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    OGRLayer *poLayer = GetLayerByName(pszLayerName);
+    if( poLayer == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such layer as `%s'.",
+                  pszSQLCommand,
+                  pszLayerName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the field.                                                 */
+/* -------------------------------------------------------------------- */
+
+    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
+    if( nFieldIndex < 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such field as `%s'.",
+                  pszSQLCommand,
+                  pszColumnName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      Remove it.                                                      */
+/* -------------------------------------------------------------------- */
+
+    CSLDestroy( papszTokens );
+
+    return poLayer->DeleteField( nFieldIndex );
+}
+
+/************************************************************************/
+/*                 ProcessSQLAlterTableRenameColumn()                   */
+/*                                                                      */
+/*      The correct syntax for renaming a column in the OGR SQL         */
+/*      dialect is:                                                     */
+/*                                                                      */
+/*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    const char* pszLayerName = NULL;
+    const char* pszOldColName = NULL;
+    const char* pszNewColName = NULL;
+    if( CSLCount(papszTokens) == 8
+        && EQUAL(papszTokens[0],"ALTER")
+        && EQUAL(papszTokens[1],"TABLE")
+        && EQUAL(papszTokens[3],"RENAME")
+        && EQUAL(papszTokens[4],"COLUMN")
+        && EQUAL(papszTokens[6],"TO"))
+    {
+        pszLayerName = papszTokens[2];
+        pszOldColName = papszTokens[5];
+        pszNewColName = papszTokens[7];
+    }
+    else if( CSLCount(papszTokens) == 7
+             && EQUAL(papszTokens[0],"ALTER")
+             && EQUAL(papszTokens[1],"TABLE")
+             && EQUAL(papszTokens[3],"RENAME")
+             && EQUAL(papszTokens[5],"TO"))
+    {
+        pszLayerName = papszTokens[2];
+        pszOldColName = papszTokens[4];
+        pszNewColName = papszTokens[6];
+    }
+    else
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] <columnname> TO <newname>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    OGRLayer *poLayer = GetLayerByName(pszLayerName);
+    if( poLayer == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such layer as `%s'.",
+                  pszSQLCommand,
+                  pszLayerName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the field.                                                 */
+/* -------------------------------------------------------------------- */
+
+    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
+    if( nFieldIndex < 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such field as `%s'.",
+                  pszSQLCommand,
+                  pszOldColName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Rename column.                                                  */
+/* -------------------------------------------------------------------- */
+    OGRFieldDefn* poOldFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
+    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
+    oNewFieldDefn.SetName(pszNewColName);
+
+    CSLDestroy( papszTokens );
+
+    return poLayer->AlterFieldDefn( nFieldIndex, &oNewFieldDefn, ALTER_NAME_FLAG );
+}
+
+/************************************************************************/
+/*                 ProcessSQLAlterTableAlterColumn()                    */
+/*                                                                      */
+/*      The correct syntax for altering the type of a column in the     */
+/*      OGR SQL dialect is:                                             */
+/*                                                                      */
+/*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
+/************************************************************************/
+
+OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn( const char *pszSQLCommand )
+
+{
+    char **papszTokens = CSLTokenizeString( pszSQLCommand );
+
+/* -------------------------------------------------------------------- */
+/*      Do some general syntax checking.                                */
+/* -------------------------------------------------------------------- */
+    const char* pszLayerName = NULL;
+    const char* pszColumnName = NULL;
+    char* pszType = NULL;
+    int iTypeIndex = 0;
+    int nTokens = CSLCount(papszTokens);
+
+    if( nTokens >= 8
+        && EQUAL(papszTokens[0],"ALTER")
+        && EQUAL(papszTokens[1],"TABLE")
+        && EQUAL(papszTokens[3],"ALTER")
+        && EQUAL(papszTokens[4],"COLUMN")
+        && EQUAL(papszTokens[6],"TYPE"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[5];
+        iTypeIndex = 7;
+    }
+    else if( nTokens >= 7
+             && EQUAL(papszTokens[0],"ALTER")
+             && EQUAL(papszTokens[1],"TABLE")
+             && EQUAL(papszTokens[3],"ALTER")
+             && EQUAL(papszTokens[5],"TYPE"))
+    {
+        pszLayerName = papszTokens[2];
+        pszColumnName = papszTokens[4];
+        iTypeIndex = 6;
+    }
+    else
+    {
+        CSLDestroy( papszTokens );
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
+                  "Was '%s'\n"
+                  "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <columntype>'",
+                  pszSQLCommand );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Merge type components into a single string if there were split  */
+/*      with spaces                                                     */
+/* -------------------------------------------------------------------- */
+    CPLString osType;
+    for(int i=iTypeIndex;i<nTokens;i++)
+    {
+        osType += papszTokens[i];
+        CPLFree(papszTokens[i]);
+    }
+    pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
+    papszTokens[iTypeIndex + 1] = NULL;
+
+/* -------------------------------------------------------------------- */
+/*      Find the named layer.                                           */
+/* -------------------------------------------------------------------- */
+    OGRLayer *poLayer = GetLayerByName(pszLayerName);
+    if( poLayer == NULL )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such layer as `%s'.",
+                  pszSQLCommand,
+                  pszLayerName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Find the field.                                                 */
+/* -------------------------------------------------------------------- */
+
+    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
+    if( nFieldIndex < 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "%s failed, no such field as `%s'.",
+                  pszSQLCommand,
+                  pszColumnName );
+        CSLDestroy( papszTokens );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Alter column.                                                   */
+/* -------------------------------------------------------------------- */
+
+    OGRFieldDefn* poOldFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
+    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
+
+    int nWidth = 0, nPrecision = 0;
+    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
+    oNewFieldDefn.SetType(eType);
+    oNewFieldDefn.SetWidth(nWidth);
+    oNewFieldDefn.SetPrecision(nPrecision);
+
+    int nFlags = 0;
+    if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
+        nFlags |= ALTER_TYPE_FLAG;
+    if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
+        poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
+        nFlags |= ALTER_WIDTH_PRECISION_FLAG;
+
+    CSLDestroy( papszTokens );
+
+    if (nFlags == 0)
+        return OGRERR_NONE;
+    else
+        return poLayer->AlterFieldDefn( nFieldIndex, &oNewFieldDefn, nFlags );
+}
+
+/************************************************************************/
+/*                             ExecuteSQL()                             */
+/************************************************************************/
+
+/**
+ \brief Execute an SQL statement against the data store. 
+
+ The result of an SQL query is either NULL for statements that are in error,
+ or that have no results set, or an OGRLayer pointer representing a results
+ set from the query.  Note that this OGRLayer is in addition to the layers
+ in the data store and must be destroyed with 
+ ReleaseResultSet() before the dataset is closed
+ (destroyed).  
+
+ This method is the same as the C function GDALDatasetExecuteSQL() and the
+ deprecated OGR_DS_ExecuteSQL().
+
+ For more information on the SQL dialect supported internally by OGR
+ review the <a href="ogr_sql.html">OGR SQL</a> document.  Some drivers (ie.
+ Oracle and PostGIS) pass the SQL directly through to the underlying RDBMS.
+
+ Starting with OGR 1.10, the <a href="ogr_sql_sqlite.html">SQLITE dialect</a>
+ can also be used.
+
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @param pszStatement the SQL statement to execute. 
+ @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
+ @param pszDialect allows control of the statement dialect. If set to NULL, the
+OGR SQL engine will be used, except for RDBMS drivers that will use their dedicated SQL engine,
+unless OGRSQL is explicitely passed as the dialect. Starting with OGR 1.10, the SQLITE dialect
+can also be used.
+
+ @return an OGRLayer containing the results of the query.  Deallocate with
+ ReleaseResultSet().
+
+*/
+
+OGRLayer * GDALDataset::ExecuteSQL( const char *pszStatement,
+                                      OGRGeometry *poSpatialFilter,
+                                      const char *pszDialect )
+
+{
+    return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, NULL);
+}
+
+OGRLayer * GDALDataset::ExecuteSQL( const char *pszStatement,
+                                    OGRGeometry *poSpatialFilter,
+                                    const char *pszDialect,
+                                    swq_select_parse_options* poSelectParseOptions)
+
+{
+    swq_select *psSelectInfo = NULL;
+
+    if( pszDialect != NULL && EQUAL(pszDialect, "SQLite") )
+    {
+#ifdef SQLITE_ENABLED
+        return OGRSQLiteExecuteSQL( this, pszStatement, poSpatialFilter, pszDialect );
+#else
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "The SQLite driver needs to be compiled to support the SQLite SQL dialect");
+        return NULL;
+#endif
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Handle CREATE INDEX statements specially.                       */
+/* -------------------------------------------------------------------- */
+    if( EQUALN(pszStatement,"CREATE INDEX",12) )
+    {
+        ProcessSQLCreateIndex( pszStatement );
+        return NULL;
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Handle DROP INDEX statements specially.                         */
+/* -------------------------------------------------------------------- */
+    if( EQUALN(pszStatement,"DROP INDEX",10) )
+    {
+        ProcessSQLDropIndex( pszStatement );
+        return NULL;
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Handle DROP TABLE statements specially.                         */
+/* -------------------------------------------------------------------- */
+    if( EQUALN(pszStatement,"DROP TABLE",10) )
+    {
+        ProcessSQLDropTable( pszStatement );
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Handle ALTER TABLE statements specially.                        */
+/* -------------------------------------------------------------------- */
+    if( EQUALN(pszStatement,"ALTER TABLE",11) )
+    {
+        char **papszTokens = CSLTokenizeString( pszStatement );
+        if( CSLCount(papszTokens) >= 4 &&
+            EQUAL(papszTokens[3],"ADD") )
+        {
+            ProcessSQLAlterTableAddColumn( pszStatement );
+            CSLDestroy(papszTokens);
+            return NULL;
+        }
+        else if( CSLCount(papszTokens) >= 4 &&
+                 EQUAL(papszTokens[3],"DROP") )
+        {
+            ProcessSQLAlterTableDropColumn( pszStatement );
+            CSLDestroy(papszTokens);
+            return NULL;
+        }
+        else if( CSLCount(papszTokens) >= 4 &&
+                 EQUAL(papszTokens[3],"RENAME") )
+        {
+            ProcessSQLAlterTableRenameColumn( pszStatement );
+            CSLDestroy(papszTokens);
+            return NULL;
+        }
+        else if( CSLCount(papszTokens) >= 4 &&
+                 EQUAL(papszTokens[3],"ALTER") )
+        {
+            ProcessSQLAlterTableAlterColumn( pszStatement );
+            CSLDestroy(papszTokens);
+            return NULL;
+        }
+        else
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Unsupported ALTER TABLE command : %s",
+                      pszStatement );
+            CSLDestroy(papszTokens);
+            return NULL;
+        }
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Preparse the SQL statement.                                     */
+/* -------------------------------------------------------------------- */
+    psSelectInfo = new swq_select();
+    swq_custom_func_registrar* poCustomFuncRegistrar = NULL;
+    if( poSelectParseOptions != NULL )
+        poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
+    if( psSelectInfo->preparse( pszStatement,
+                                poCustomFuncRegistrar != NULL ) != CPLE_None )
+    {
+        delete psSelectInfo;
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If there is no UNION ALL, build result layer.                   */
+/* -------------------------------------------------------------------- */
+    if( psSelectInfo->poOtherSelect == NULL )
+    {
+        return BuildLayerFromSelectInfo(psSelectInfo,
+                                        poSpatialFilter,
+                                        pszDialect,
+                                        poSelectParseOptions);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Build result union layer.                                       */
+/* -------------------------------------------------------------------- */
+    int nSrcLayers = 0;
+    OGRLayer** papoSrcLayers = NULL;
+
+    do
+    {
+        swq_select* psNextSelectInfo = psSelectInfo->poOtherSelect;
+        psSelectInfo->poOtherSelect = NULL;
+
+        OGRLayer* poLayer = BuildLayerFromSelectInfo(psSelectInfo,
+                                                     poSpatialFilter,
+                                                     pszDialect,
+                                                     poSelectParseOptions);
+        if( poLayer == NULL )
+        {
+            /* Each source layer owns an independant select info */
+            for(int i=0;i<nSrcLayers;i++)
+                delete papoSrcLayers[i];
+            CPLFree(papoSrcLayers);
+
+            /* So we just have to destroy the remaining select info */
+            delete psNextSelectInfo;
+
+            return NULL;
+        }
+        else
+        {
+            papoSrcLayers = (OGRLayer**) CPLRealloc(papoSrcLayers,
+                                sizeof(OGRLayer*) * (nSrcLayers + 1));
+            papoSrcLayers[nSrcLayers] = poLayer;
+            nSrcLayers ++;
+
+            psSelectInfo = psNextSelectInfo;
+        }
+    }
+    while( psSelectInfo != NULL );
+
+    return new OGRUnionLayer("SELECT",
+                                nSrcLayers,
+                                papoSrcLayers,
+                                TRUE);
+}
+
+/************************************************************************/
+/*                        BuildLayerFromSelectInfo()                    */
+/************************************************************************/
+
+struct GDALSQLParseInfo
+{
+    swq_field_list sFieldList;
+    int            nExtraDSCount;
+    GDALDataset**  papoExtraDS;
+    char          *pszWHERE;
+};
+
+OGRLayer* GDALDataset::BuildLayerFromSelectInfo(swq_select* psSelectInfo,
+                                                OGRGeometry *poSpatialFilter,
+                                                const char *pszDialect,
+                                                swq_select_parse_options* poSelectParseOptions)
+{
+    OGRGenSQLResultsLayer *poResults = NULL;
+    GDALSQLParseInfo* psParseInfo = BuildParseInfo(psSelectInfo,
+                                                   poSelectParseOptions);
+
+    if( psParseInfo )
+    {
+        poResults = new OGRGenSQLResultsLayer( this, psSelectInfo,
+                                               poSpatialFilter,
+                                               psParseInfo->pszWHERE,
+                                               pszDialect );
+    }
+    else
+    {
+        delete psSelectInfo;
+    }
+    DestroyParseInfo(psParseInfo);
+
+    return poResults;
+}
+
+/************************************************************************/
+/*                             DestroyParseInfo()                       */
+/************************************************************************/
+
+void GDALDataset::DestroyParseInfo(GDALSQLParseInfo* psParseInfo )
+{
+    if( psParseInfo != NULL )
+    {
+        CPLFree( psParseInfo->sFieldList.names );
+        CPLFree( psParseInfo->sFieldList.types );
+        CPLFree( psParseInfo->sFieldList.table_ids );
+        CPLFree( psParseInfo->sFieldList.ids );
+
+        /* Release the datasets we have opened with OGROpenShared() */
+        /* It is safe to do that as the 'new OGRGenSQLResultsLayer' itself */
+        /* has taken a reference on them, which it will release in its */
+        /* destructor */
+        for(int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; iEDS++)
+            GDALClose( (GDALDatasetH)psParseInfo->papoExtraDS[iEDS] );
+        CPLFree(psParseInfo->papoExtraDS);
+
+        CPLFree(psParseInfo->pszWHERE);
+
+        CPLFree(psParseInfo);
+    }
+}
+
+/************************************************************************/
+/*                            BuildParseInfo()                          */
+/************************************************************************/
+
+GDALSQLParseInfo* GDALDataset::BuildParseInfo(swq_select* psSelectInfo,
+                                              swq_select_parse_options* poSelectParseOptions)
+{
+    int            nFIDIndex = 0;
+
+    GDALSQLParseInfo* psParseInfo = (GDALSQLParseInfo*)CPLCalloc(1, sizeof(GDALSQLParseInfo));
+
+/* -------------------------------------------------------------------- */
+/*      Validate that all the source tables are recognised, count       */
+/*      fields.                                                         */
+/* -------------------------------------------------------------------- */
+    int  nFieldCount = 0, iTable, iField;
+
+    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
+    {
+        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
+        OGRLayer *poSrcLayer;
+        GDALDataset *poTableDS = this;
+
+        if( psTableDef->data_source != NULL )
+        {
+            poTableDS = (GDALDataset *) 
+                OGROpenShared( psTableDef->data_source, FALSE, NULL );
+            if( poTableDS == NULL )
+            {
+                if( strlen(CPLGetLastErrorMsg()) == 0 )
+                    CPLError( CE_Failure, CPLE_AppDefined, 
+                              "Unable to open secondary datasource\n"
+                              "`%s' required by JOIN.",
+                              psTableDef->data_source );
+
+                DestroyParseInfo(psParseInfo);
+                return NULL;
+            }
+
+            /* Keep in an array to release at the end of this function */
+            psParseInfo->papoExtraDS = (GDALDataset** )CPLRealloc(
+                               psParseInfo->papoExtraDS,
+                               sizeof(GDALDataset*) * (psParseInfo->nExtraDSCount + 1));
+            psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
+        }
+
+        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );
+
+        if( poSrcLayer == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "SELECT from table %s failed, no such table/featureclass.",
+                      psTableDef->table_name );
+
+            DestroyParseInfo(psParseInfo);
+            return NULL;
+        }
+
+        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
+        if( iTable == 0 || (poSelectParseOptions &&
+                            poSelectParseOptions->bAddSecondaryTablesGeometryFields) )
+            nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Build the field list for all indicated tables.                  */
+/* -------------------------------------------------------------------- */
+
+    psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
+    psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
+
+    psParseInfo->sFieldList.count = 0;
+    psParseInfo->sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+SPECIAL_FIELD_COUNT) );
+    psParseInfo->sFieldList.types = (swq_field_type *)  
+        CPLMalloc( sizeof(swq_field_type) * (nFieldCount+SPECIAL_FIELD_COUNT) );
+    psParseInfo->sFieldList.table_ids = (int *) 
+        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
+    psParseInfo->sFieldList.ids = (int *) 
+        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
+    
+    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
+    {
+        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
+        GDALDataset *poTableDS = this;
+        OGRLayer *poSrcLayer;
+        
+        if( psTableDef->data_source != NULL )
+        {
+            poTableDS = (GDALDataset *) 
+                OGROpenShared( psTableDef->data_source, FALSE, NULL );
+            CPLAssert( poTableDS != NULL );
+            poTableDS->Dereference();
+        }
+
+        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );
+
+        for( iField = 0; 
+             iField < poSrcLayer->GetLayerDefn()->GetFieldCount();
+             iField++ )
+        {
+            OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
+            int iOutField = psParseInfo->sFieldList.count++;
+            psParseInfo->sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
+            if( poFDefn->GetType() == OFTInteger )
+            {
+                if( poFDefn->GetSubType() == OFSTBoolean )
+                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
+                else
+                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
+            }
+            else if( poFDefn->GetType() == OFTInteger64 )
+            {
+                if( poFDefn->GetSubType() == OFSTBoolean )
+                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
+                else
+                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
+            }
+            else if( poFDefn->GetType() == OFTReal )
+                psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
+            else if( poFDefn->GetType() == OFTString )
+                psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
+            else if( poFDefn->GetType() == OFTTime )
+                psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
+            else if( poFDefn->GetType() == OFTDate )
+                psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
+            else if( poFDefn->GetType() == OFTDateTime )
+                psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
+            else
+                psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
+
+            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
+            psParseInfo->sFieldList.ids[iOutField] = iField;
+        }
+
+        if( iTable == 0 || (poSelectParseOptions &&
+                            poSelectParseOptions->bAddSecondaryTablesGeometryFields) )
+        {
+            nFIDIndex = psParseInfo->sFieldList.count;
+
+            for( iField = 0; 
+                 iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
+                 iField++ )
+            {
+                OGRGeomFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
+                int iOutField = psParseInfo->sFieldList.count++;
+                psParseInfo->sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
+                if( *psParseInfo->sFieldList.names[iOutField] == '\0' )
+                    psParseInfo->sFieldList.names[iOutField] = (char*) OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME;
+                psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
+
+                psParseInfo->sFieldList.table_ids[iOutField] = iTable;
+                psParseInfo->sFieldList.ids[iOutField] =
+                    GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(poSrcLayer->GetLayerDefn(), iField);
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
+/* -------------------------------------------------------------------- */
+    int bAlwaysPrefixWithTableName = poSelectParseOptions &&
+                                     poSelectParseOptions->bAlwaysPrefixWithTableName;
+    if( psSelectInfo->expand_wildcard( &psParseInfo->sFieldList,
+                                       bAlwaysPrefixWithTableName)  != CE_None )
+    {
+        DestroyParseInfo(psParseInfo);
+        return NULL;
+    }
+
+    for (iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
+    {
+        psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] = (char*) SpecialFieldNames[iField];
+        psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] = SpecialFieldTypes[iField];
+        psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
+        psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] = nFIDIndex + iField;
+        psParseInfo->sFieldList.count++;
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Finish the parse operation.                                     */
+/* -------------------------------------------------------------------- */
+    if( psSelectInfo->parse( &psParseInfo->sFieldList, poSelectParseOptions ) != CE_None )
+    {
+        DestroyParseInfo(psParseInfo);
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Extract the WHERE expression to use separately.                 */
+/* -------------------------------------------------------------------- */
+    if( psSelectInfo->where_expr != NULL )
+    {
+        psParseInfo->pszWHERE = psSelectInfo->where_expr->Unparse( &psParseInfo->sFieldList, '"' );
+        //CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
+    }
+
+    return psParseInfo;
+}
+
+/************************************************************************/
+/*                          ReleaseResultSet()                          */
+/************************************************************************/
+
+/**
+ \brief Release results of ExecuteSQL().
+
+ This method should only be used to deallocate OGRLayers resulting from
+ an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
+ results set before destroying the GDALDataset may cause errors. 
+
+ This method is the same as the C function GDALDatasetReleaseResultSet() and the
+ deprecated OGR_DS_ReleaseResultSet().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @param poResultsSet the result of a previous ExecuteSQL() call.
+
+*/ 
+void GDALDataset::ReleaseResultSet( OGRLayer * poResultsSet )
+
+{
+    delete poResultsSet;
+}
+
+/************************************************************************/
+/*                            GetStyleTable()                           */
+/************************************************************************/
+
+/**
+ \brief Returns dataset style table.
+ 
+ This method is the same as the C function GDALDatasetGetStyleTable() and the
+ deprecated OGR_DS_GetStyleTable().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @return pointer to a style table which should not be modified or freed by the
+ caller.
+*/
+
+OGRStyleTable *GDALDataset::GetStyleTable()
+{
+    return m_poStyleTable;
+}
+
+/************************************************************************/
+/*                         SetStyleTableDirectly()                      */
+/************************************************************************/
+
+/**
+ \brief Set dataset style table.
+ 
+ This method operate exactly as SetStyleTable() except that it
+ assumes ownership of the passed table.
+ 
+ This method is the same as the C function GDALDatasetSetStyleTableDirectly() and
+ the deprecated OGR_DS_SetStyleTableDirectly().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @param poStyleTable pointer to style table to set
+
+*/
+void GDALDataset::SetStyleTableDirectly( OGRStyleTable *poStyleTable )
+{
+    if ( m_poStyleTable )
+        delete m_poStyleTable;
+    m_poStyleTable = poStyleTable;
+}
+
+/************************************************************************/
+/*                            SetStyleTable()                           */
+/************************************************************************/
+
+/**
+ \brief Set dataset style table.
+ 
+ This method operate exactly as SetStyleTableDirectly() except
+ that it does not assume ownership of the passed table.
+ 
+ This method is the same as the C function GDALDatasetSetStyleTable() and the
+ deprecated OGR_DS_SetStyleTable().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+ 
+ @param poStyleTable pointer to style table to set
+
+*/
+
+void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
+{
+    if ( m_poStyleTable )
+        delete m_poStyleTable;
+    if ( poStyleTable )
+        m_poStyleTable = poStyleTable->Clone();
+}
+
+/************************************************************************/
+/*                         IsGenericSQLDialect()                        */
+/************************************************************************/
+
+int GDALDataset::IsGenericSQLDialect(const char* pszDialect)
+{
+    return ( pszDialect != NULL && (EQUAL(pszDialect,"OGRSQL") ||
+                                    EQUAL(pszDialect,"SQLITE")) );
+
+}
+
+/************************************************************************/
+/*                            GetLayerCount()                           */
+/************************************************************************/
+
+/**
+ \brief Get the number of layers in this dataset.
+
+ This method is the same as the C function GDALDatasetGetLayerCount(),
+ and the deprecated OGR_DS_GetLayerCount().
+ 
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @return layer count.
+*/
+
+int GDALDataset::GetLayerCount()
+{
+    return 0;
+}
+
+/************************************************************************/
+/*                                GetLayer()                            */
+/************************************************************************/
+
+/**
+ \brief Fetch a layer by index.
+
+ The returned layer remains owned by the 
+ GDALDataset and should not be deleted by the application.
+
+ This method is the same as the C function GDALDatasetGetLayer() and the
+ deprecated OGR_DS_GetLayer().
+
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @param iLayer a layer number between 0 and GetLayerCount()-1.
+
+ @return the layer, or NULL if iLayer is out of range or an error occurs.
+*/
+
+OGRLayer* GDALDataset::GetLayer(CPL_UNUSED int iLayer)
+{
+    return NULL;
+}
+
+/************************************************************************/
+/*                            TestCapability()                          */
+/************************************************************************/
+
+/**
+ \brief Test if capability is available.
+
+ One of the following dataset capability names can be passed into this
+ method, and a TRUE or FALSE value will be returned indicating whether or not
+ the capability is available for this object.
+
+ <ul>
+  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
+  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing layers.<p>
+  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
+        datasource support CreateGeomField() just after layer creation.<p>
+  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve geometries.<p>
+  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient) transactions.<p>
+  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports transactions through emulation.<p>
+ </ul>
+
+ The \#define macro forms of the capability names should be used in preference
+ to the strings themselves to avoid mispelling.
+
+ This method is the same as the C function GDALDatasetTestCapability() and the
+ deprecated OGR_DS_TestCapability().
+
+ In GDAL 1.X, this method used to be in the OGRDataSource class.
+
+ @param pszCapability the capability to test.
+
+ @return TRUE if capability available otherwise FALSE.
+
+*/
+
+int GDALDataset::TestCapability( CPL_UNUSED const char * pszCap )
+{
+    return FALSE;
+}
+
+/************************************************************************/
+/*                           StartTransaction()                         */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, StartTransaction creates a transaction.
+
+ If starting the transaction fails, will return 
+ OGRERR_FAILURE. Datasources which do not support transactions will 
+ always return OGRERR_UNSUPPORTED_OPERATION.
+
+ Nested transactions are not supported.
+ 
+ All changes done after the start of the transaction are definitely applied in the
+ datasource if CommitTransaction() is called. They may be cancelled by calling
+ RollbackTransaction() instead.
+ 
+ At the time of writing, transactions only apply on vector layers.
+ 
+ Datasets that support transactions will advertize the ODsCTransactions capability.
+ Use of transactions at dataset level is generally prefered to transactions at
+ layer level, whose scope is rarely limited to the layer from which it was started.
+ 
+ In case StartTransaction() fails, neither CommitTransaction() or RollbackTransaction()
+ should be called.
+ 
+ If an error occurs after a successful StartTransaction(), the whole
+ transaction may or may not be implicitely cancelled, depending on drivers. (e.g.
+ the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
+ error, an explicit call to RollbackTransaction() should be done to keep things balanced.
+ 
+ By default, when bForce is set to FALSE, only "efficient" transactions will be
+ attempted. Some drivers may offer an emulation of transactions, but sometimes
+ with significant overhead, in which case the user must explicitely allow for such
+ an emulation by setting bForce to TRUE. Drivers that offer emulated transactions
+ should advertize the ODsCEmulatedTransactions capability (and not ODsCTransactions).
+ 
+ This function is the same as the C function GDALDatasetStartTransaction().
+
+ @param bForce can be set to TRUE if an emulation, possibly slow, of a transaction
+               mechanism is acceptable.
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
+{
+    return OGRERR_UNSUPPORTED_OPERATION;
+}
+
+/************************************************************************/
+/*                      GDALDatasetStartTransaction()                   */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, StartTransaction creates a transaction.
+
+ If starting the transaction fails, will return 
+ OGRERR_FAILURE. Datasources which do not support transactions will 
+ always return OGRERR_UNSUPPORTED_OPERATION.
+
+ Nested transactions are not supported.
+ 
+ All changes done after the start of the transaction are definitely applied in the
+ datasource if CommitTransaction() is called. They may be cancelled by calling
+ RollbackTransaction() instead.
+ 
+ At the time of writing, transactions only apply on vector layers.
+ 
+ Datasets that support transactions will advertize the ODsCTransactions capability.
+ Use of transactions at dataset level is generally prefered to transactions at
+ layer level, whose scope is rarely limited to the layer from which it was started.
+ 
+ In case StartTransaction() fails, neither CommitTransaction() or RollbackTransaction()
+ should be called.
+
+ If an error occurs after a successful StartTransaction(), the whole
+ transaction may or may not be implicitely cancelled, depending on drivers. (e.g.
+ the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
+ error, an explicit call to RollbackTransaction() should be done to keep things balanced.
+
+ By default, when bForce is set to FALSE, only "efficient" transactions will be
+ attempted. Some drivers may offer an emulation of transactions, but sometimes
+ with significant overhead, in which case the user must explicitely allow for such
+ an emulation by setting bForce to TRUE. Drivers that offer emulated transactions
+ should advertize the ODsCEmulatedTransactions capability (and not ODsCTransactions).
+
+ This function is the same as the C++ method GDALDataset::StartTransaction()
+
+ @param hDS the dataset handle.
+ @param bForce can be set to TRUE if an emulation, possibly slow, of a transaction
+               mechanism is acceptable.
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetStartTransaction", OGRERR_INVALID_HANDLE );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
+#endif
+
+    return ((GDALDataset*) hDS)->StartTransaction(bForce);
+}
+
+/************************************************************************/
+/*                           CommitTransaction()                        */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, CommitTransaction commits a transaction.
+
+ If no transaction is active, or the commit fails, will return 
+ OGRERR_FAILURE. Datasources which do not support transactions will 
+ always return OGRERR_UNSUPPORTED_OPERATION. 
+ 
+ Depending on drivers, this may or may not abort layer sequential readings that
+ are active.
+
+ This function is the same as the C function GDALDatasetCommitTransaction().
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDataset::CommitTransaction()
+{
+    return OGRERR_UNSUPPORTED_OPERATION;
+}
+
+/************************************************************************/
+/*                        GDALDatasetCommitTransaction()                */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, CommitTransaction commits a transaction.
+
+ If no transaction is active, or the commit fails, will return 
+ OGRERR_FAILURE. Datasources which do not support transactions will 
+ always return OGRERR_UNSUPPORTED_OPERATION. 
+ 
+ Depending on drivers, this may or may not abort layer sequential readings that
+ are active.
+
+ This function is the same as the C++ method GDALDataset::CommitTransaction()
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetCommitTransaction", OGRERR_INVALID_HANDLE );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Dataset_CommitTransaction(hDS);
+#endif
+
+    return ((GDALDataset*) hDS)->CommitTransaction();
+}
+
+/************************************************************************/
+/*                           RollbackTransaction()                      */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction. 
+ If no transaction is active, or the rollback fails, will return  
+ OGRERR_FAILURE. Datasources which do not support transactions will
+ always return OGRERR_UNSUPPORTED_OPERATION. 
+
+ This function is the same as the C function GDALDatasetRollbackTransaction().
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDataset::RollbackTransaction()
+{
+    return OGRERR_UNSUPPORTED_OPERATION;
+}
+
+/************************************************************************/
+/*                     GDALDatasetRollbackTransaction()                 */
+/************************************************************************/
+
+/**
+ \brief For datasources which support transactions, RollbackTransaction will roll back a datasource to its state before the start of the current transaction. 
+ If no transaction is active, or the rollback fails, will return  
+ OGRERR_FAILURE. Datasources which do not support transactions will
+ always return OGRERR_UNSUPPORTED_OPERATION. 
+
+ This function is the same as the C++ method GDALDataset::RollbackTransaction().
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+*/
+OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
+{
+    VALIDATE_POINTER1( hDS, "GDALDatasetRollbackTransaction", OGRERR_INVALID_HANDLE );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Dataset_RollbackTransaction(hDS);
+#endif
+
+    return ((GDALDataset*) hDS)->RollbackTransaction();
+}
diff --git a/gcore/gdaldefaultasync.cpp b/gcore/gdaldefaultasync.cpp
index 29d2770..eef271f 100644
--- a/gcore/gdaldefaultasync.cpp
+++ b/gcore/gdaldefaultasync.cpp
@@ -297,14 +297,14 @@ GDALDefaultAsyncReader::GetNextUpdatedRegion(CPL_UNUSED double dfTimeout,
                                              int* pnBufYOff,
                                              int* pnBufXSize,
                                              int* pnBufYSize )
-
 {
     CPLErr eErr;
 
-    eErr = poDS->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize, 
-                           pBuf, nBufXSize, nBufYSize, eBufType, 
-                           nBandCount, panBandMap, 
-                           nPixelSpace, nLineSpace, nBandSpace );
+    eErr = poDS->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize,
+                           pBuf, nBufXSize, nBufYSize, eBufType,
+                           nBandCount, panBandMap,
+                           nPixelSpace, nLineSpace, nBandSpace,
+                           NULL );
 
     *pnBufXOff = 0;
     *pnBufYOff = 0;
@@ -316,4 +316,3 @@ GDALDefaultAsyncReader::GetNextUpdatedRegion(CPL_UNUSED double dfTimeout,
     else
         return GARIO_ERROR;
 }
-
diff --git a/gcore/gdaldefaultoverviews.cpp b/gcore/gdaldefaultoverviews.cpp
index 68b6a83..8a32a17 100644
--- a/gcore/gdaldefaultoverviews.cpp
+++ b/gcore/gdaldefaultoverviews.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldefaultoverviews.cpp 27657 2014-09-10 07:21:17Z rouault $
+ * $Id: gdaldefaultoverviews.cpp 28907 2015-04-14 15:14:32Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Helper code to implement overview and mask support for many 
@@ -32,7 +32,7 @@
 #include "gdal_priv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdaldefaultoverviews.cpp 27657 2014-09-10 07:21:17Z rouault $");
+CPL_CVSID("$Id: gdaldefaultoverviews.cpp 28907 2015-04-14 15:14:32Z rouault $");
 
 /************************************************************************/
 /*                        GDALDefaultOverviews()                        */
@@ -187,7 +187,11 @@ void GDALDefaultOverviews::OverviewScan()
         if( bInitNameIsOVR )
             osOvrFilename = pszInitName;
         else
+        {
+            if( !GDALCanFileAcceptSidecarFile(pszInitName) )
+                return;
             osOvrFilename.Printf( "%s.ovr", pszInitName );
+        }
 
         bExists = CPLCheckForFile( (char *) osOvrFilename.c_str(), 
                                    papszInitSiblingFiles );
@@ -205,9 +209,10 @@ void GDALDefaultOverviews::OverviewScan()
 
         if( bExists )
         {
-            GDALOpenInfo oOpenInfo(osOvrFilename, poDS->GetAccess(),
-                                   papszInitSiblingFiles);
-            poODS = (GDALDataset*) GDALOpenInternal( oOpenInfo, NULL );
+            poODS = (GDALDataset*) GDALOpenEx( osOvrFilename,
+                                               GDAL_OF_RASTER |
+                                               ((poDS->GetAccess() == GA_Update) ? GDAL_OF_UPDATE : 0),
+                                               NULL, NULL, papszInitSiblingFiles );
         }
     }
 
@@ -395,6 +400,49 @@ int GDALOvLevelAdjust( int nOvLevel, int nXSize )
     return (int) (0.5 + nXSize / (double) nOXSize);
 }
 
+
+int GDALOvLevelAdjust2( int nOvLevel, int nXSize, int nYSize )
+
+{
+    /* Select the larger dimension to have increased accuracy, but */
+    /* with a slight preference to x even if (a bit) smaller than y */
+    /* in an attempt to behave closer as previous behaviour */
+    if( nXSize >= nYSize / 2 && !(nXSize < nYSize && nXSize < nOvLevel) )
+    {
+        int     nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
+    
+        return (int) (0.5 + nXSize / (double) nOXSize);
+    }
+    else
+    {
+        int     nOYSize = (nYSize + nOvLevel - 1) / nOvLevel;
+    
+        return (int) (0.5 + nYSize / (double) nOYSize);
+    }
+}
+
+/************************************************************************/
+/*                         GDALComputeOvFactor()                        */
+/************************************************************************/
+
+int GDALComputeOvFactor( int nOvrXSize, int nRasterXSize,
+                         int nOvrYSize, int nRasterYSize )
+{
+    /* Select the larger dimension to have increased accuracy, but */
+    /* with a slight preference to x even if (a bit) smaller than y */
+    /* in an attempt to behave closer as previous behaviour */
+    if( nRasterXSize >= nRasterYSize / 2 )
+    {
+        return (int) 
+                (0.5 + nRasterXSize / (double) nOvrXSize);
+    }
+    else
+    {
+        return (int) 
+                (0.5 + nRasterYSize / (double) nOvrYSize);
+    }
+}
+
 /************************************************************************/
 /*                           CleanOverviews()                           */
 /*                                                                      */
@@ -587,12 +635,15 @@ GDALDefaultOverviews::BuildOverviews(
             if (poOverview == NULL)
                 continue;
  
-            nOvFactor = (int) 
-                (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+            nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                             poBand->GetXSize(),
+                                             poOverview->GetYSize(),
+                                             poBand->GetYSize());
 
             if( nOvFactor == panOverviewList[i] 
-                || nOvFactor == GDALOvLevelAdjust( panOverviewList[i], 
-                                                   poBand->GetXSize() ) )
+                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], 
+                                                   poBand->GetXSize(), 
+                                                   poBand->GetYSize() ) )
                 panOverviewList[i] *= -1;
         }
 
@@ -712,13 +763,16 @@ GDALDefaultOverviews::BuildOverviews(
                 if (bHasNoData)
                   poOverview->SetNoDataValue(noDataValue);
 
-                nOvFactor = (int) 
-                    (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
+                nOvFactor = GDALComputeOvFactor(poOverview->GetXSize(),
+                                                 poBand->GetXSize(),
+                                                 poOverview->GetYSize(),
+                                                 poBand->GetYSize());
 
                 if( nOvFactor == - panOverviewList[i] 
                     || (panOverviewList[i] < 0 &&
-                        nOvFactor == GDALOvLevelAdjust( -panOverviewList[i],
-                                                       poBand->GetXSize() )) )
+                        nOvFactor == GDALOvLevelAdjust2( -panOverviewList[i],
+                                                       poBand->GetXSize(),
+                                                       poBand->GetYSize() )) )
                 {
                     papoOverviewBands[nNewOverviews++] = poOverview;
                     break;
@@ -1034,6 +1088,8 @@ int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
     if( EQUAL(CPLGetExtension(pszBasename),"msk") )
         return FALSE;
 
+    if( !GDALCanFileAcceptSidecarFile(pszBasename) )
+        return FALSE;
     osMskFilename.Printf( "%s.msk", pszBasename );
 
     int bExists = CPLCheckForFile( (char *) osMskFilename.c_str(), 
@@ -1054,9 +1110,10 @@ int GDALDefaultOverviews::HaveMaskFile( char ** papszSiblingFiles,
 /* -------------------------------------------------------------------- */
 /*      Open the file.                                                  */
 /* -------------------------------------------------------------------- */
-    GDALOpenInfo oOpenInfo(osMskFilename, poDS->GetAccess(),
-                           papszInitSiblingFiles);
-    poMaskDS = (GDALDataset *) GDALOpenInternal( oOpenInfo, NULL );
+    poMaskDS = (GDALDataset *) GDALOpenEx( osMskFilename,
+                                           GDAL_OF_RASTER |
+                                           ((poDS->GetAccess() == GA_Update) ? GDAL_OF_UPDATE : 0),
+                                           NULL, NULL, papszInitSiblingFiles );
     CPLAssert( poMaskDS != poDS );
 
     if( poMaskDS == NULL )
diff --git a/gcore/gdaldllmain.cpp b/gcore/gdaldllmain.cpp
index 7efa1ca..0531f71 100644
--- a/gcore/gdaldllmain.cpp
+++ b/gcore/gdaldllmain.cpp
@@ -42,6 +42,48 @@ int GDALIsInGlobalDestructor(void)
     return bInGDALGlobalDestructor;
 }
 
+#ifndef _MSC_VER
+void CPLFinalizeTLS();
+#endif
+
+/************************************************************************/
+/*                           GDALDestroy()                              */
+/************************************************************************/
+
+/** Finalize GDAL/OGR library.
+ *
+ * This function calls GDALDestroyDriverManager() and OGRCleanupAll() and
+ * finalize Thread Local Storage variables.
+ *
+ * This function should *not* usually be explicitely called by application code
+ * if GDAL is dynamically linked, since it is automatically called through
+ * the unregistration mechanisms of dynamic library loading.
+ *
+ * Note: no GDAL/OGR code should be called after this call !
+ *
+ * @since GDAL 2.0
+ */
+
+static int bGDALDestroyAlreadyCalled = FALSE;
+void GDALDestroy(void)
+{
+    if( bGDALDestroyAlreadyCalled )
+        return;
+    bGDALDestroyAlreadyCalled = TRUE;
+
+    CPLDebug("GDAL", "In GDALDestroy - unloading GDAL shared library.");
+    bInGDALGlobalDestructor = TRUE;
+    GDALDestroyDriverManager();
+
+#ifdef OGR_ENABLED
+    OGRCleanupAll();
+#endif
+    bInGDALGlobalDestructor = FALSE;
+#ifndef _MSC_VER
+    CPLFinalizeTLS();
+#endif
+}
+
 /************************************************************************/
 /*  The library set-up/clean-up routines implemented with               */
 /*  GNU C/C++ extensions.                                               */
@@ -50,7 +92,7 @@ int GDALIsInGlobalDestructor(void)
 #ifdef __GNUC__
 
 static void GDALInitialize(void) __attribute__ ((constructor)) ;
-static void GDALDestroy(void)    __attribute__ ((destructor)) ;
+static void GDALDestructor(void) __attribute__ ((destructor)) ;
 
 /************************************************************************/
 /* Called when GDAL is loaded by loader or by dlopen(),                 */
@@ -61,6 +103,11 @@ static void GDALInitialize(void)
 {
     // nothing to do
     //CPLDebug("GDAL", "Library loaded");
+#ifdef DEBUG
+    const char* pszLocale = CPLGetConfigOption("GDAL_LOCALE", NULL);
+    if( pszLocale )
+        CPLsetlocale( LC_ALL, pszLocale );
+#endif
 }
 
 /************************************************************************/
@@ -68,22 +115,13 @@ static void GDALInitialize(void)
 /* and before dlclose() returns.                                        */
 /************************************************************************/
 
-static void GDALDestroy(void)
+static void GDALDestructor(void)
 {
-    // TODO: Confirm if calling CPLCleanupTLS here is safe
-    //CPLCleanupTLS();
-    
+    if( bGDALDestroyAlreadyCalled )
+        return;
     if( !CSLTestBoolean(CPLGetConfigOption("GDAL_DESTROY", "YES")) )
         return;
-
-    CPLDebug("GDAL", "In GDALDestroy - unloading GDAL shared library.");
-    bInGDALGlobalDestructor = TRUE;
-    GDALDestroyDriverManager();
-
-#ifdef OGR_ENABLED
-    OGRCleanupAll();
-#endif
-    bInGDALGlobalDestructor = FALSE;
+    GDALDestroy();
 }
 
 #endif // __GNUC__
@@ -116,13 +154,7 @@ extern "C" int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpRese
     }
     else if (dwReason == DLL_PROCESS_DETACH)
     {
-        bInGDALGlobalDestructor = TRUE;
-        ::GDALDestroyDriverManager();
-
-#ifdef OGR_ENABLED
-        ::OGRCleanupAll();
-#endif
-        bInGDALGlobalDestructor = FALSE;
+        GDALDestroy();
     }
 
 	return 1; // ignroed for all reasons but DLL_PROCESS_ATTACH
diff --git a/gcore/gdaldriver.cpp b/gcore/gdaldriver.cpp
index a02300e..b795c96 100644
--- a/gcore/gdaldriver.cpp
+++ b/gcore/gdaldriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdaldriver.cpp 29077 2015-04-30 13:23:31Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALDriver class (and C wrappers)
@@ -29,8 +29,9 @@
  ****************************************************************************/
 
 #include "gdal_priv.h"
+#include "ogrsf_frmts.h"
 
-CPL_CVSID("$Id: gdaldriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdaldriver.cpp 29077 2015-04-30 13:23:31Z rouault $");
 
 CPL_C_START
 const char* GDALClientDatasetGetFilename(const char* pszFilename);
@@ -52,6 +53,9 @@ GDALDriver::GDALDriver()
     pfnIdentify = NULL;
     pfnRename = NULL;
     pfnCopyFiles = NULL;
+    pfnOpenWithDriverArg = NULL;
+    pfnCreateVectorOnly = NULL;
+    pfnDeleteDataSource = NULL;
 }
 
 /************************************************************************/
@@ -109,6 +113,9 @@ void CPL_STDCALL GDALDestroyDriver( GDALDriverH hDriver )
  * In some situations, the new dataset can be created in another process through the
  * \ref gdal_api_proxy mechanism.
  *
+ * In GDAL 2, the arguments nXSize, nYSize and nBands can be passed to 0 when
+ * creating a vector-only dataset for a compatible driver.
+ *
  * Equivelent of the C function GDALCreate().
  * 
  * @param pszFilename the name of the dataset to create.  UTF-8 encoded.
@@ -117,6 +124,8 @@ void CPL_STDCALL GDALDestroyDriver( GDALDriverH hDriver )
  * @param nBands number of bands.
  * @param eType type of raster.
  * @param papszOptions list of driver specific control parameters.
+ * The APPEND_SUBDATASET=YES option can be
+ * specified to avoid prior destruction of existing dataset.
  *
  * @return NULL on failure, or a new GDALDataset.
  */
@@ -126,12 +135,12 @@ GDALDataset * GDALDriver::Create( const char * pszFilename,
                                   GDALDataType eType, char ** papszOptions )
 
 {
-    CPLLocaleC  oLocaleForcer;
+    //CPLLocaleC  oLocaleForcer;
 
 /* -------------------------------------------------------------------- */
 /*      Does this format support creation.                              */
 /* -------------------------------------------------------------------- */
-    if( pfnCreate == NULL )
+    if( pfnCreate == NULL && pfnCreateVectorOnly == NULL )
     {
         CPLError( CE_Failure, CPLE_NotSupported,
                   "GDALDriver::Create() ... no create method implemented"
@@ -151,7 +160,9 @@ GDALDataset * GDALDriver::Create( const char * pszFilename,
         return NULL;
     }
 
-    if( nXSize < 1 || nYSize < 1 )
+    if( GetMetadataItem(GDAL_DCAP_RASTER) != NULL &&
+        GetMetadataItem(GDAL_DCAP_VECTOR) == NULL &&
+        (nXSize < 1 || nYSize < 1) )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "Attempt to create %dx%d dataset is illegal,"
@@ -217,8 +228,18 @@ GDALDataset * GDALDriver::Create( const char * pszFilename,
               GDALGetDataTypeName( eType ), 
               papszOptions );
     
-    poDS = pfnCreate( pszFilename, nXSize, nYSize, nBands, eType,
-                      papszOptions );
+    if( pfnCreate != NULL )
+    {
+        poDS = pfnCreate( pszFilename, nXSize, nYSize, nBands, eType,
+                          papszOptions );
+    }
+    else
+    {
+        if( nBands > 0 )
+            poDS = NULL;
+        else
+            poDS = pfnCreateVectorOnly( this, pszFilename, papszOptions );
+    }
 
     if( poDS != NULL )
     {
@@ -228,6 +249,8 @@ GDALDataset * GDALDriver::Create( const char * pszFilename,
         
         if( poDS->poDriver == NULL )
             poDS->poDriver = this;
+
+        poDS->AddToDatasetOpenList();
     }
 
     return poDS;
@@ -344,12 +367,6 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
     
     CPLErrorReset();
 
-    if( !pfnProgress( 0.0, NULL, pProgressData ) )
-    {
-        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
-        return NULL;
-    }
-
 /* -------------------------------------------------------------------- */
 /*      Validate that we can create the output as requested.            */
 /* -------------------------------------------------------------------- */
@@ -359,12 +376,39 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 
     CPLDebug( "GDAL", "Using default GDALDriver::CreateCopy implementation." );
 
-    if (nBands == 0)
+    int nLayerCount = poSrcDS->GetLayerCount();
+    if (nBands == 0 && nLayerCount == 0 && GetMetadataItem(GDAL_DCAP_VECTOR) == NULL )
     {
         CPLError( CE_Failure, CPLE_NotSupported,
                   "GDALDriver::DefaultCreateCopy does not support zero band" );
         return NULL;
     }
+    if( poSrcDS->GetDriver() != NULL &&
+        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) != NULL &&
+        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) == NULL &&
+        GetMetadataItem(GDAL_DCAP_RASTER) == NULL &&
+        GetMetadataItem(GDAL_DCAP_VECTOR) != NULL )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Source driver is raster-only whereas output driver is vector-only" );
+        return NULL;
+    }
+    else if( poSrcDS->GetDriver() != NULL &&
+        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_RASTER) == NULL &&
+        poSrcDS->GetDriver()->GetMetadataItem(GDAL_DCAP_VECTOR) != NULL &&
+        GetMetadataItem(GDAL_DCAP_RASTER) != NULL &&
+        GetMetadataItem(GDAL_DCAP_VECTOR) == NULL )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Source driver is vector-only whereas output driver is raster-only" );
+        return NULL;
+    }
+
+    if( !pfnProgress( 0.0, NULL, pProgressData ) )
+    {
+        CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
+        return NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Propogate some specific structural metadata as options if it    */
@@ -378,7 +422,7 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
         "PIXELTYPE", "IMAGE_STRUCTURE", 
         NULL };
 
-    for( iOptItem = 0; apszOptItems[iOptItem] != NULL; iOptItem += 2 )
+    for( iOptItem = 0; nBands > 0 && apszOptItems[iOptItem] != NULL; iOptItem += 2 )
     {
         // does the source have this metadata item on the first band?
         const char *pszValue = 
@@ -409,10 +453,11 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 /*      Create destination dataset.                                     */
 /* -------------------------------------------------------------------- */
     GDALDataset  *poDstDS;
-    GDALDataType eType;
+    GDALDataType eType = GDT_Unknown;
     CPLErr       eErr = CE_None;
 
-    eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
+    if( nBands > 0 )
+        eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
     poDstDS = Create( pszFilename, nXSize, nYSize, 
                       nBands, eType, papszCreateOptions );
                       
@@ -420,6 +465,19 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 
     if( poDstDS == NULL )
         return NULL;
+    int nDstBands = poDstDS->GetRasterCount();
+    if( nDstBands != nBands )
+    {
+        if( GetMetadataItem(GDAL_DCAP_RASTER) != NULL )
+        {
+            /* Shouldn't happen for a well-behaved driver */
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "Output driver created only %d bands whereas %d were expected",
+                     nDstBands, nBands);
+            eErr = CE_Failure;
+        }
+        nDstBands = 0;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Try setting the projection and geotransform if it seems         */
@@ -427,6 +485,9 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 /* -------------------------------------------------------------------- */
     double      adfGeoTransform[6];
 
+    if( nDstBands == 0 && !bStrict )
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+
     if( eErr == CE_None
         && poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None 
         && (adfGeoTransform[0] != 0.0 
@@ -462,6 +523,9 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
             eErr = CE_None;
     }
 
+    if( nDstBands == 0 && !bStrict )
+        CPLPopErrorHandler();
+
 /* -------------------------------------------------------------------- */
 /*      Copy metadata.                                                  */
 /* -------------------------------------------------------------------- */
@@ -480,7 +544,7 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 /*      Loop copying bands.                                             */
 /* -------------------------------------------------------------------- */
     for( int iBand = 0; 
-         eErr == CE_None && iBand < nBands; 
+         eErr == CE_None && iBand < nDstBands; 
          iBand++ )
     {
         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
@@ -546,7 +610,7 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 /* -------------------------------------------------------------------- */
 /*      Copy image data.                                                */
 /* -------------------------------------------------------------------- */
-    if( eErr == CE_None )
+    if( eErr == CE_None && nDstBands > 0 )
         eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS, 
                                            (GDALDatasetH) poDstDS, 
                                            NULL, pfnProgress, pProgressData );
@@ -554,10 +618,30 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
 /* -------------------------------------------------------------------- */
 /*      Should we copy some masks over?                                 */
 /* -------------------------------------------------------------------- */
-    if( eErr == CE_None )
+    if( eErr == CE_None && nDstBands > 0 )
         eErr = DefaultCopyMasks( poSrcDS, poDstDS, eErr );
 
 /* -------------------------------------------------------------------- */
+/*      Copy vector layers                                              */
+/* -------------------------------------------------------------------- */
+
+    if( eErr == CE_None )
+    {
+        if( nLayerCount > 0 && poDstDS->TestCapability(ODsCCreateLayer) )
+        {
+            for( int iLayer = 0; iLayer < nLayerCount; iLayer++ )
+            {
+                OGRLayer        *poLayer = poSrcDS->GetLayer(iLayer);
+
+                if( poLayer == NULL )
+                    continue;
+
+                poDstDS->CopyLayer( poLayer, poLayer->GetName(), NULL );
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Try to cleanup the output dataset if the translation failed.    */
 /* -------------------------------------------------------------------- */
     if( eErr != CE_None )
@@ -613,7 +697,8 @@ GDALDataset *GDALDriver::DefaultCreateCopy( const char * pszFilename,
  * normally FALSE indicating that the copy may adapt as needed for the 
  * output format. 
  * @param papszOptions additional format dependent options controlling 
- * creation of the output file. 
+ * creation of the output file. The APPEND_SUBDATASET=YES option can be
+ * specified to avoid prior destruction of existing dataset.
  * @param pfnProgress a function to be used to report progress of the copy.
  * @param pProgressData application data passed into progress function.
  *
@@ -627,7 +712,7 @@ GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
                                      void * pProgressData )
 
 {
-    CPLLocaleC  oLocaleForcer;
+    //CPLLocaleC  oLocaleForcer;
 
     if( pfnProgress == NULL )
         pfnProgress = GDALDummyProgress;
@@ -668,19 +753,38 @@ GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
 /*      name.  But even if that seems to fail we will continue since    */
 /*      it might just be a corrupt file or something.                   */
 /* -------------------------------------------------------------------- */
-    if( !CSLFetchBoolean(papszOptions, "APPEND_SUBDATASET", FALSE) &&
+    int bAppendSubdataset = CSLFetchBoolean(papszOptions, "APPEND_SUBDATASET", FALSE);
+    if( !bAppendSubdataset &&
         CSLFetchBoolean(papszOptions, "QUIET_DELETE_ON_CREATE_COPY", TRUE) )
         QuietDelete( pszFilename );
 
+    char** papszOptionsToDelete = NULL;
     int iIdxQuietDeleteOnCreateCopy = 
         CSLPartialFindString(papszOptions, "QUIET_DELETE_ON_CREATE_COPY=");
-    char** papszOptionsToDelete = NULL;
     if( iIdxQuietDeleteOnCreateCopy >= 0 )
     {
-        papszOptions = CSLRemoveStrings(CSLDuplicate(papszOptions), iIdxQuietDeleteOnCreateCopy, 1, NULL);
+        if( papszOptionsToDelete == NULL )
+            papszOptionsToDelete = CSLDuplicate(papszOptions);
+        papszOptions = CSLRemoveStrings(papszOptionsToDelete, iIdxQuietDeleteOnCreateCopy, 1, NULL);
         papszOptionsToDelete = papszOptions;
     }
-    
+
+/* -------------------------------------------------------------------- */
+/*      If _INTERNAL_DATASET=YES, the returned dataset will not be      */
+/*      registered in the global list of open datasets.                 */
+/* -------------------------------------------------------------------- */
+    int iIdxInternalDataset =
+        CSLPartialFindString(papszOptions, "_INTERNAL_DATASET=");
+    int bInternalDataset = FALSE;
+    if( iIdxInternalDataset >= 0 )
+    {
+        bInternalDataset = CSLFetchBoolean(papszOptions, "_INTERNAL_DATASET", FALSE);
+        if( papszOptionsToDelete == NULL )
+            papszOptionsToDelete = CSLDuplicate(papszOptions);
+        papszOptions = CSLRemoveStrings(papszOptionsToDelete, iIdxInternalDataset, 1, NULL);
+        papszOptionsToDelete = papszOptions;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Validate creation options.                                      */
 /* -------------------------------------------------------------------- */
@@ -705,12 +809,17 @@ GDALDataset *GDALDriver::CreateCopy( const char * pszFilename,
 
             if( poDstDS->poDriver == NULL )
                 poDstDS->poDriver = this;
+
+            if( !bInternalDataset )
+                poDstDS->AddToDatasetOpenList();
         }
     }
     else
+    {
         poDstDS = DefaultCreateCopy( pszFilename, poSrcDS, bStrict, 
                                   papszOptions, pfnProgress, pProgressData );
-
+    }
+        
     CSLDestroy(papszOptionsToDelete);
     return poDstDS;
 }
@@ -765,14 +874,43 @@ GDALDatasetH CPL_STDCALL GDALCreateCopy( GDALDriverH hDriver,
 CPLErr GDALDriver::QuietDelete( const char *pszName )
 
 {
+    VSIStatBufL sStat;
+    int bExists = VSIStatExL(pszName, &sStat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) == 0;
+
+#ifdef S_ISFIFO
+    if( bExists && S_ISFIFO(sStat.st_mode) )
+        return CE_None;
+#endif
+
+    if( bExists &&
+        VSI_ISDIR(sStat.st_mode) )
+    {
+        /* It is not desirable to remove directories quietly */
+        /* Necessary to avoid ogr_mitab_12 to destroy file created at ogr_mitab_7 */
+        return CE_None;
+    }
+
+    CPLPushErrorHandler(CPLQuietErrorHandler);
     GDALDriver *poDriver = (GDALDriver*) GDALIdentifyDriver( pszName, NULL );
+    CPLPopErrorHandler();
 
     if( poDriver == NULL )
         return CE_None;
 
     CPLDebug( "GDAL", "QuietDelete(%s) invoking Delete()", pszName );
 
-    return poDriver->Delete( pszName );
+    CPLErr eErr;
+    int bQuiet = ( !bExists && poDriver->pfnDelete == NULL && poDriver->pfnDeleteDataSource == NULL );
+    if( bQuiet )
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+    eErr  = poDriver->Delete( pszName );
+    if( bQuiet )
+    {
+        CPLPopErrorHandler();
+        CPLErrorReset();
+        eErr = CE_None;
+    }
+    return eErr;
 }
 
 /************************************************************************/
@@ -803,11 +941,13 @@ CPLErr GDALDriver::Delete( const char * pszFilename )
 {
     if( pfnDelete != NULL )
         return pfnDelete( pszFilename );
+    else if( pfnDeleteDataSource != NULL )
+        return pfnDeleteDataSource( this, pszFilename );
 
 /* -------------------------------------------------------------------- */
 /*      Collect file list.                                              */
 /* -------------------------------------------------------------------- */
-    GDALDatasetH hDS = (GDALDataset *) GDALOpen(pszFilename,GA_ReadOnly);
+    GDALDatasetH hDS = (GDALDataset *) GDALOpenEx(pszFilename,0,NULL,NULL,NULL);
         
     if( hDS == NULL )
     {
@@ -1267,13 +1407,55 @@ const char * CPL_STDCALL GDALGetDriverCreationOptionList( GDALDriverH hDriver )
 int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                                              char** papszCreationOptions)
 {
-    int bRet = TRUE;
     VALIDATE_POINTER1( hDriver, "GDALValidateCreationOptions", FALSE );
-
     const char *pszOptionList = 
         ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST );
+    CPLString osDriver;
+    osDriver.Printf("driver %s", ((GDALDriver *) hDriver)->GetDescription());
+    char** papszOptionsToValidate = papszCreationOptions;
+    char** papszOptionsToFree = NULL;
+    if( CSLFetchNameValue( papszCreationOptions, "APPEND_SUBDATASET") )
+    {
+        papszOptionsToValidate = papszOptionsToFree =
+            CSLSetNameValue(CSLDuplicate(papszCreationOptions), "APPEND_SUBDATASET", NULL);
+    }
+    int bRet = GDALValidateOptions( pszOptionList,
+                                (const char* const* )papszOptionsToValidate,
+                                "creation option",
+                                osDriver);
+    CSLDestroy(papszOptionsToFree);
+    return bRet;
+}
+
+/************************************************************************/
+/*                     GDALValidateOpenOptions()                        */
+/************************************************************************/
+
+int GDALValidateOpenOptions( GDALDriverH hDriver,
+                             const char* const* papszOpenOptions)
+{
+    VALIDATE_POINTER1( hDriver, "GDALValidateOpenOptions", FALSE );
+    const char *pszOptionList = 
+        ((GDALDriver *) hDriver)->GetMetadataItem( GDAL_DMD_OPENOPTIONLIST );
+    CPLString osDriver;
+    osDriver.Printf("driver %s", ((GDALDriver *) hDriver)->GetDescription());
+    return GDALValidateOptions( pszOptionList, papszOpenOptions,
+                                "open option",
+                                osDriver);
+}
+
+/************************************************************************/
+/*                           GDALValidateOptions()                      */
+/************************************************************************/
+
+int GDALValidateOptions( const char* pszOptionList,
+                         const char* const* papszOptionsToValidate,
+                         const char* pszErrorMessageOptionType,
+                         const char* pszErrorMessageContainerName)
+{
+    int bRet = TRUE;
 
-    if( papszCreationOptions == NULL || *papszCreationOptions == NULL)
+    if( papszOptionsToValidate == NULL || *papszOptionsToValidate == NULL)
         return TRUE;
     if( pszOptionList == NULL )
         return TRUE;
@@ -1282,23 +1464,30 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
     if (psNode == NULL)
     {
         CPLError(CE_Warning, CPLE_AppDefined,
-                 "Could not parse creation option list of driver %s. Assuming creation options are valid.",
-                 ((GDALDriver *) hDriver)->GetDescription());
+                 "Could not parse %s list of %s. Assuming options are valid.",
+                 pszErrorMessageOptionType, pszErrorMessageContainerName);
         return TRUE;
     }
 
-    while(*papszCreationOptions)
+    while(*papszOptionsToValidate)
     {
         char* pszKey = NULL;
-        const char* pszValue = CPLParseNameValue(*papszCreationOptions, &pszKey);
+        const char* pszValue = CPLParseNameValue(*papszOptionsToValidate, &pszKey);
         if (pszKey == NULL)
         {
             CPLError(CE_Warning, CPLE_NotSupported,
-                     "Creation option '%s' is not formatted with the key=value format",
-                     *papszCreationOptions);
+                     "%s '%s' is not formatted with the key=value format",
+                     pszErrorMessageOptionType,
+                     *papszOptionsToValidate);
             bRet = FALSE;
 
-            papszCreationOptions ++;
+            papszOptionsToValidate ++;
+            continue;
+        }
+
+        if( EQUAL(pszKey, "VALIDATE_OPEN_OPTIONS") )
+        {
+            papszOptionsToValidate ++;
             continue;
         }
 
@@ -1316,27 +1505,81 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                     break;
                 }
 
-                if (EQUAL(pszOptionName, pszKey) ||
-                    EQUAL(CPLGetXMLValue(psChildNode, "alias", ""), pszKey))
+                /* For option names beginning by a wildcard */
+                if( pszOptionName[0] == '*' &&
+                    strlen(pszKey) > strlen(pszOptionName) &&
+                    EQUAL( pszKey + strlen(pszKey) - strlen(pszOptionName + 1), pszOptionName + 1 ) )
                 {
                     break;
                 }
+
+                if (EQUAL(pszOptionName, pszKey) )
+                {
+                    break;
+                }
+                const char* pszAlias = CPLGetXMLValue(psChildNode, "alias",
+                            CPLGetXMLValue(psChildNode, "deprecated_alias", ""));
+                if (EQUAL(pszAlias, pszKey) )
+                {
+                    CPLDebug("GDAL", "Using deprecated alias '%s'. New name is '%s'",
+                             pszAlias, pszOptionName);
+                    break;
+                }
             }
             psChildNode = psChildNode->psNext;
         }
         if (psChildNode == NULL)
         {
-            CPLError(CE_Warning, CPLE_NotSupported,
-                     "Driver %s does not support %s creation option",
-                     ((GDALDriver *) hDriver)->GetDescription(),
-                     pszKey);
-            CPLFree(pszKey);
-            bRet = FALSE;
+            if( !EQUAL(pszErrorMessageOptionType, "open option") ||
+                CSLFetchBoolean((char**)papszOptionsToValidate, "VALIDATE_OPEN_OPTIONS", TRUE) )
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                        "%s does not support %s %s",
+                        pszErrorMessageContainerName,
+                        pszErrorMessageOptionType,
+                        pszKey);
+                bRet = FALSE;
+            }
 
-            papszCreationOptions ++;
+            CPLFree(pszKey);
+            papszOptionsToValidate ++;
             continue;
         }
+
+#ifdef DEBUG
+        CPLXMLNode* psChildSubNode = psChildNode->psChild;
+        while(psChildSubNode)
+        {
+            if( psChildSubNode->eType == CXT_Attribute )
+            {
+                if( !(EQUAL(psChildSubNode->pszValue, "name") ||
+                      EQUAL(psChildSubNode->pszValue, "alias") ||
+                      EQUAL(psChildSubNode->pszValue, "deprecated_alias") ||
+                      EQUAL(psChildSubNode->pszValue, "alt_config_option") ||
+                      EQUAL(psChildSubNode->pszValue, "description") ||
+                      EQUAL(psChildSubNode->pszValue, "type") ||
+                      EQUAL(psChildSubNode->pszValue, "min") ||
+                      EQUAL(psChildSubNode->pszValue, "max") ||
+                      EQUAL(psChildSubNode->pszValue, "default") ||
+                      EQUAL(psChildSubNode->pszValue, "maxsize") ||
+                      EQUAL(psChildSubNode->pszValue, "required")) )
+                {
+                    /* Driver error */
+                    CPLError(CE_Warning, CPLE_NotSupported,
+                             "%s : unhandled attribute '%s' for %s %s.",
+                             pszErrorMessageContainerName,
+                             psChildSubNode->pszValue,
+                             pszKey,
+                             pszErrorMessageOptionType);
+                }
+            }
+            psChildSubNode = psChildSubNode->psNext;
+        }
+#endif
+
         const char* pszType = CPLGetXMLValue(psChildNode, "type", NULL);
+        const char* pszMin = CPLGetXMLValue(psChildNode, "min", NULL);
+        const char* pszMax = CPLGetXMLValue(psChildNode, "max", NULL);
         if (pszType != NULL)
         {
             if (EQUAL(pszType, "INT") || EQUAL(pszType, "INTEGER"))
@@ -1348,13 +1591,30 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                            *pszValueIter == '+' || *pszValueIter == '-'))
                     {
                         CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is an unexpected value for %s creation option of type int.",
-                             pszValue, pszKey);
+                             "'%s' is an unexpected value for %s %s of type int.",
+                             pszValue, pszKey, pszErrorMessageOptionType);
                         bRet = FALSE;
                         break;
                     }
                     pszValueIter++;
                 }
+                if( *pszValueIter == '0' )
+                {
+                    if( pszMin && atoi(pszValue) < atoi(pszMin) )
+                    {
+                        CPLError(CE_Warning, CPLE_NotSupported,
+                             "'%s' is an unexpected value for %s %s that should be >= %s.",
+                             pszValue, pszKey, pszErrorMessageOptionType, pszMin);
+                        break;
+                    }
+                    if( pszMax && atoi(pszValue) > atoi(pszMax) )
+                    {
+                        CPLError(CE_Warning, CPLE_NotSupported,
+                             "'%s' is an unexpected value for %s %s that should be <= %s.",
+                             pszValue, pszKey, pszErrorMessageOptionType, pszMax);
+                        break;
+                    }
+                }
             }
             else if (EQUAL(pszType, "UNSIGNED INT"))
             {
@@ -1365,25 +1625,59 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                            *pszValueIter == '+'))
                     {
                         CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is an unexpected value for %s creation option of type unsigned int.",
-                             pszValue, pszKey);
+                             "'%s' is an unexpected value for %s %s of type unsigned int.",
+                             pszValue, pszKey, pszErrorMessageOptionType);
                         bRet = FALSE;
                         break;
                     }
                     pszValueIter++;
+                    if( *pszValueIter == '0' )
+                    {
+                        if( pszMin && atoi(pszValue) < atoi(pszMin) )
+                        {
+                            CPLError(CE_Warning, CPLE_NotSupported,
+                                "'%s' is an unexpected value for %s %s that should be >= %s.",
+                                pszValue, pszKey, pszErrorMessageOptionType, pszMin);
+                            break;
+                        }
+                        if( pszMax && atoi(pszValue) > atoi(pszMax) )
+                        {
+                            CPLError(CE_Warning, CPLE_NotSupported,
+                                "'%s' is an unexpected value for %s %s that should be <= %s.",
+                                pszValue, pszKey, pszErrorMessageOptionType, pszMax);
+                            break;
+                        }
+                    }
                 }
             }
             else if (EQUAL(pszType, "FLOAT"))
             {
                 char* endPtr = NULL;
-                CPLStrtod(pszValue, &endPtr);
+                double dfVal = CPLStrtod(pszValue, &endPtr);
                 if ( !(endPtr == NULL || *endPtr == '\0') )
                 {
                     CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is an unexpected value for %s creation option of type float.",
-                             pszValue, pszKey);
+                             "'%s' is an unexpected value for %s %s of type float.",
+                             pszValue, pszKey, pszErrorMessageOptionType);
                     bRet = FALSE;
                 }
+                else
+                {
+                    if( pszMin && dfVal < CPLAtof(pszMin) )
+                    {
+                        CPLError(CE_Warning, CPLE_NotSupported,
+                             "'%s' is an unexpected value for %s %s that should be >= %s.",
+                             pszValue, pszKey, pszErrorMessageOptionType, pszMin);
+                        break;
+                    }
+                    if( pszMax && dfVal > CPLAtof(pszMax) )
+                    {
+                        CPLError(CE_Warning, CPLE_NotSupported,
+                             "'%s' is an unexpected value for %s %s that should be <= %s.",
+                             pszValue, pszKey, pszErrorMessageOptionType, pszMax);
+                        break;
+                    }
+                }
             }
             else if (EQUAL(pszType, "BOOLEAN"))
             {
@@ -1391,8 +1685,8 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                       EQUAL(pszValue, "OFF") || EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "NO")))
                 {
                     CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is an unexpected value for %s creation option of type boolean.",
-                             pszValue, pszKey);
+                             "'%s' is an unexpected value for %s %s of type boolean.",
+                             pszValue, pszKey, pszErrorMessageOptionType);
                     bRet = FALSE;
                 }
             }
@@ -1424,8 +1718,8 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                 if (!bMatchFound)
                 {
                     CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is an unexpected value for %s creation option of type string-select.",
-                             pszValue, pszKey);
+                             "'%s' is an unexpected value for %s %s of type string-select.",
+                             pszValue, pszKey, pszErrorMessageOptionType);
                     bRet = FALSE;
                 }
             }
@@ -1437,8 +1731,9 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
                     if ((int)strlen(pszValue) > atoi(pszMaxSize))
                     {
                         CPLError(CE_Warning, CPLE_NotSupported,
-                             "'%s' is of size %d, whereas maximum size for %s creation option is %d.",
-                             pszValue, (int)strlen(pszValue), pszKey, atoi(pszMaxSize));
+                             "'%s' is of size %d, whereas maximum size for %s %s is %d.",
+                             pszValue, (int)strlen(pszValue), pszKey,
+                                 pszErrorMessageOptionType, atoi(pszMaxSize));
                         bRet = FALSE;
                     }
                 }
@@ -1447,22 +1742,24 @@ int CPL_STDCALL GDALValidateCreationOptions( GDALDriverH hDriver,
             {
                 /* Driver error */
                 CPLError(CE_Warning, CPLE_NotSupported,
-                     "Driver %s : type '%s' for %s creation option is not recognized.",
-                     ((GDALDriver *) hDriver)->GetDescription(),
-                     pszType,
-                     pszKey);
+                         "%s : type '%s' for %s %s is not recognized.",
+                         pszErrorMessageContainerName,
+                         pszType,
+                         pszKey,
+                         pszErrorMessageOptionType);
             }
         }
         else
         {
             /* Driver error */
             CPLError(CE_Warning, CPLE_NotSupported,
-                     "Driver %s : no type for %s creation option.",
-                     ((GDALDriver *) hDriver)->GetDescription(),
-                     pszKey);
+                     "%s : no type for %s %s.",
+                     pszErrorMessageContainerName,
+                     pszKey,
+                     pszErrorMessageOptionType);
         }
         CPLFree(pszKey);
-        papszCreationOptions++;
+        papszOptionsToValidate++;
     }
 
     CPLDestroyXMLNode(psNode);
@@ -1510,15 +1807,17 @@ GDALIdentifyDriver( const char * pszFilename,
     int         	iDriver;
     GDALDriverManager  *poDM = GetGDALDriverManager();
     GDALOpenInfo        oOpenInfo( pszFilename, GA_ReadOnly, papszFileList );
-    CPLLocaleC          oLocaleForcer;
+    //CPLLocaleC          oLocaleForcer;
 
     CPLErrorReset();
     CPLAssert( NULL != poDM );
-    
-    for( iDriver = -1; iDriver < poDM->GetDriverCount(); iDriver++ )
+
+    int nDriverCount = poDM->GetDriverCount();
+
+    // First pass: only use drivers that have a pfnIdentify implementation
+    for( iDriver = -1; iDriver < nDriverCount; iDriver++ )
     {
         GDALDriver      *poDriver;
-        GDALDataset     *poDS;
 
         if( iDriver < 0 )
             poDriver = GDALGetAPIPROXYDriver();
@@ -1529,10 +1828,31 @@ GDALIdentifyDriver( const char * pszFilename,
 
         if( poDriver->pfnIdentify != NULL )
         {
-            if( poDriver->pfnIdentify( &oOpenInfo ) )
+            if( poDriver->pfnIdentify( &oOpenInfo ) > 0 )
                 return (GDALDriverH) poDriver;
         }
-        else if( poDriver->pfnOpen != NULL )
+    }
+
+    // Second pass: slow method
+    for( iDriver = -1; iDriver < nDriverCount; iDriver++ )
+    {
+        GDALDriver      *poDriver;
+        GDALDataset     *poDS;
+
+        if( iDriver < 0 )
+            poDriver = GDALGetAPIPROXYDriver();
+        else
+            poDriver = poDM->GetDriver( iDriver );
+
+        VALIDATE_POINTER1( poDriver, "GDALIdentifyDriver", NULL );
+
+        if( poDriver->pfnIdentify != NULL )
+        {
+            if( poDriver->pfnIdentify( &oOpenInfo ) == 0 )
+                continue;
+        }
+
+        if( poDriver->pfnOpen != NULL )
         {
             poDS = poDriver->pfnOpen( &oOpenInfo );
             if( poDS != NULL )
@@ -1544,7 +1864,40 @@ GDALIdentifyDriver( const char * pszFilename,
             if( CPLGetLastErrorNo() != 0 )
                 return NULL;
         }
+        else if( poDriver->pfnOpenWithDriverArg != NULL )
+        {
+            poDS = poDriver->pfnOpenWithDriverArg( poDriver, &oOpenInfo );
+            if( poDS != NULL )
+            {
+                delete poDS;
+                return (GDALDriverH) poDriver;
+            }
+
+            if( CPLGetLastErrorNo() != 0 )
+                return NULL;
+        }
     }
 
     return NULL;
 }
+
+/************************************************************************/
+/*                          SetMetadataItem()                           */
+/************************************************************************/
+
+CPLErr GDALDriver::SetMetadataItem( const char * pszName, 
+                                    const char * pszValue, 
+                                    const char * pszDomain )
+
+{
+    if( pszDomain == NULL || pszDomain[0] == '\0' )
+    {
+        /* Automatically sets GDAL_DMD_EXTENSIONS from GDAL_DMD_EXTENSION */
+        if( EQUAL(pszName, GDAL_DMD_EXTENSION) &&
+            GDALMajorObject::GetMetadataItem(GDAL_DMD_EXTENSIONS) == NULL )
+        {
+            GDALMajorObject::SetMetadataItem(GDAL_DMD_EXTENSIONS, pszValue);
+        }
+    }
+    return GDALMajorObject::SetMetadataItem(pszName, pszValue, pszDomain);
+}
diff --git a/gcore/gdaldrivermanager.cpp b/gcore/gdaldrivermanager.cpp
index 72e4d97..2909ee8 100644
--- a/gcore/gdaldrivermanager.cpp
+++ b/gcore/gdaldrivermanager.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaldrivermanager.cpp 27121 2014-04-03 22:08:55Z rouault $
+ * $Id: gdaldrivermanager.cpp 29110 2015-05-02 11:54:16Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALDriverManager class.
@@ -43,7 +43,7 @@
 #  endif
 #endif
 
-CPL_CVSID("$Id: gdaldrivermanager.cpp 27121 2014-04-03 22:08:55Z rouault $");
+CPL_CVSID("$Id: gdaldrivermanager.cpp 29110 2015-05-02 11:54:16Z rouault $");
 
 static const char *pszUpdatableINST_DATA = 
 "__INST_DATA_TARGET:                                                                                                                                      ";
@@ -55,9 +55,9 @@ static const char *pszUpdatableINST_DATA =
 /************************************************************************/
 
 static volatile GDALDriverManager        *poDM = NULL;
-static void *hDMMutex = NULL;
+static CPLMutex *hDMMutex = NULL;
 
-void** GDALGetphDMMutex() { return &hDMMutex; }
+CPLMutex** GDALGetphDMMutex() { return &hDMMutex; }
 
 /************************************************************************/
 /*                        GetGDALDriverManager()                        */
@@ -101,7 +101,6 @@ GDALDriverManager::GDALDriverManager()
 {
     nDrivers = 0;
     papoDrivers = NULL;
-    pszHome = CPLStrdup("");
 
     CPLAssert( poDM == NULL );
 
@@ -181,7 +180,7 @@ GDALDriverManager::~GDALDriverManager()
         }
     } while(bHasDroppedRef);
 
-    /* Now let's destroy the dataset pool. Nobody shoud use it afterwards */
+    /* Now let's destroy the dataset pool. Nobody should use it afterwards */
     /* if people have well released their dependent datasets above */
     GDALDatasetPoolForceDestroy();
 
@@ -214,7 +213,6 @@ GDALDriverManager::~GDALDriverManager()
 /*      Cleanup local memory.                                           */
 /* -------------------------------------------------------------------- */
     VSIFree( papoDrivers );
-    VSIFree( pszHome );
 
 /* -------------------------------------------------------------------- */
 /*      Cleanup any Proxy related memory.                               */
@@ -351,10 +349,7 @@ GDALDriver * GDALDriverManager::GetDriver( int iDriver )
 {
     CPLMutexHolderD( &hDMMutex );
 
-    if( iDriver < 0 || iDriver >= nDrivers )
-        return NULL;
-    else
-        return papoDrivers[iDriver];
+    return GetDriver_unlocked(iDriver);
 }
 
 /************************************************************************/
@@ -405,7 +400,7 @@ int GDALDriverManager::RegisterDriver( GDALDriver * poDriver )
 /*      If it is already registered, just return the existing           */
 /*      index.                                                          */
 /* -------------------------------------------------------------------- */
-    if( GetDriverByName( poDriver->GetDescription() ) != NULL )
+    if( GetDriverByName_unlocked( poDriver->GetDescription() ) != NULL )
     {
         int             i;
 
@@ -429,12 +424,39 @@ int GDALDriverManager::RegisterDriver( GDALDriver * poDriver )
     papoDrivers[nDrivers] = poDriver;
     nDrivers++;
 
+    if( poDriver->pfnOpen != NULL ||
+        poDriver->pfnOpenWithDriverArg != NULL )
+        poDriver->SetMetadataItem( GDAL_DCAP_OPEN, "YES" );
+
     if( poDriver->pfnCreate != NULL )
         poDriver->SetMetadataItem( GDAL_DCAP_CREATE, "YES" );
     
     if( poDriver->pfnCreateCopy != NULL )
         poDriver->SetMetadataItem( GDAL_DCAP_CREATECOPY, "YES" );
 
+    /* Backward compability for GDAL raster out-of-tree drivers: */
+    /* if a driver hasn't explicitely set a vector capability, assume it is */
+    /* a raster driver (legacy OGR drivers will have DCAP_VECTOR set before */
+    /* calling RegisterDriver() ) */
+    if( poDriver->GetMetadataItem( GDAL_DCAP_RASTER ) == NULL &&
+        poDriver->GetMetadataItem( GDAL_DCAP_VECTOR ) == NULL )
+    {
+        CPLDebug("GDAL", "Assuming DCAP_RASTER for driver %s. Please fix it.",
+                 poDriver->GetDescription() );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+    }
+    
+    if( poDriver->GetMetadataItem( GDAL_DMD_OPENOPTIONLIST ) != NULL &&
+        poDriver->pfnIdentify == NULL &&
+        !EQUALN(poDriver->GetDescription(), "Interlis", strlen("Interlis")) )
+    {
+        CPLDebug("GDAL", "Driver %s that defines GDAL_DMD_OPENOPTIONLIST must also "
+                 "implement Identify(), so that it can be used",
+                 poDriver->GetDescription() );
+    }
+
+    oMapNameToDrivers[CPLString(poDriver->GetDescription()).toupper()] = poDriver;
+    
     int iResult = nDrivers - 1;
 
     return iResult;
@@ -488,6 +510,7 @@ void GDALDriverManager::DeregisterDriver( GDALDriver * poDriver )
     if( i == nDrivers )
         return;
 
+    oMapNameToDrivers.erase(CPLString(poDriver->GetDescription()).toupper());
     while( i < nDrivers-1 )
     {
         papoDrivers[i] = papoDrivers[i+1];
@@ -532,17 +555,9 @@ void CPL_STDCALL GDALDeregisterDriver( GDALDriverH hDriver )
 GDALDriver * GDALDriverManager::GetDriverByName( const char * pszName )
 
 {
-    int         i;
-
     CPLMutexHolderD( &hDMMutex );
 
-    for( i = 0; i < nDrivers; i++ )
-    {
-        if( EQUAL(papoDrivers[i]->GetDescription(), pszName) )
-            return papoDrivers[i];
-    }
-
-    return NULL;
+    return oMapNameToDrivers[CPLString(pszName).toupper()];
 }
 
 /************************************************************************/
@@ -564,69 +579,64 @@ GDALDriverH CPL_STDCALL GDALGetDriverByName( const char * pszName )
 }
 
 /************************************************************************/
-/*                              GetHome()                               */
-/************************************************************************/
-
-const char *GDALDriverManager::GetHome()
-
-{
-    return pszHome;
-}
-
-/************************************************************************/
-/*                              SetHome()                               */
-/************************************************************************/
-
-void GDALDriverManager::SetHome( const char * pszNewHome )
-
-{
-    CPLMutexHolderD( &hDMMutex );
-
-    CPLFree( pszHome );
-    pszHome = CPLStrdup(pszNewHome);
-}
-
-/************************************************************************/
 /*                          AutoSkipDrivers()                           */
 /************************************************************************/
 
 /**
  * \brief This method unload undesirable drivers.
  *
- * All drivers specified in the space delimited list in the GDAL_SKIP 
+ * All drivers specified in the comma delimited list in the GDAL_SKIP 
  * environment variable) will be deregistered and destroyed.  This method 
  * should normally be called after registration of standard drivers to allow 
  * the user a way of unloading undesired drivers.  The GDALAllRegister()
  * function already invokes AutoSkipDrivers() at the end, so if that functions
  * is called, it should not be necessary to call this method from application
  * code. 
+ *
+ * Note: space separator is also accepted for backward compatibility, but some
+ * vector formats have spaces in their names, so it is encouraged to use comma
+ * to avoid issues.
  */
 
 void GDALDriverManager::AutoSkipDrivers()
 
 {
-    if( CPLGetConfigOption( "GDAL_SKIP", NULL ) == NULL )
-        return;
-
-    char **papszList = CSLTokenizeString( CPLGetConfigOption("GDAL_SKIP","") );
-
-    for( int i = 0; i < CSLCount(papszList); i++ )
+    char **apapszList[2] = { NULL, NULL };
+    const char* pszGDAL_SKIP = CPLGetConfigOption( "GDAL_SKIP", NULL );
+    if( pszGDAL_SKIP != NULL )
+    {
+        /* Favour comma as a separator. If not found, then use space */
+        const char* pszSep = (strchr(pszGDAL_SKIP, ',') != NULL) ? "," : " ";
+        apapszList[0] = CSLTokenizeStringComplex( pszGDAL_SKIP, pszSep, FALSE, FALSE);
+    }
+    const char* pszOGR_SKIP = CPLGetConfigOption( "OGR_SKIP", NULL );
+    if( pszOGR_SKIP != NULL )
     {
-        GDALDriver *poDriver = GetDriverByName( papszList[i] );
+        /* OGR has always used comma as a separator */
+        apapszList[1] = CSLTokenizeStringComplex(pszOGR_SKIP, ",", FALSE, FALSE);
+    }
 
-        if( poDriver == NULL )
-            CPLError( CE_Warning, CPLE_AppDefined, 
-                      "Unable to find driver %s to unload from GDAL_SKIP environment variable.", 
-                      papszList[i] );
-        else
+    for( int j = 0; j < 2; j++ )
+    {
+        for( int i = 0; apapszList[j] != NULL &&  apapszList[j][i] != NULL; i++ )
         {
-            CPLDebug( "GDAL", "AutoSkipDriver(%s)", papszList[i] );
-            DeregisterDriver( poDriver );
-            delete poDriver;
+            GDALDriver *poDriver = GetDriverByName( apapszList[j][i] );
+
+            if( poDriver == NULL )
+                CPLError( CE_Warning, CPLE_AppDefined, 
+                        "Unable to find driver %s to unload from GDAL_SKIP environment variable.", 
+                        apapszList[j][i] );
+            else
+            {
+                CPLDebug( "GDAL", "AutoSkipDriver(%s)", apapszList[j][i] );
+                DeregisterDriver( poDriver );
+                delete poDriver;
+            }
         }
     }
 
-    CSLDestroy( papszList );
+    CSLDestroy( apapszList[0] );
+    CSLDestroy( apapszList[1] );
 }
 
 /************************************************************************/
@@ -660,6 +670,8 @@ void GDALDriverManager::AutoLoadDrivers()
     char     **papszSearchPath = NULL;
     const char *pszGDAL_DRIVER_PATH = 
         CPLGetConfigOption( "GDAL_DRIVER_PATH", NULL );
+    if( pszGDAL_DRIVER_PATH == NULL )
+        pszGDAL_DRIVER_PATH = CPLGetConfigOption( "OGR_DRIVER_PATH", NULL );
 
 /* -------------------------------------------------------------------- */
 /*      Allow applications to completely disable this search by         */
@@ -719,19 +731,6 @@ void GDALDriverManager::AutoLoadDrivers()
                                      num2str(GDAL_VERSION_MINOR) "/PlugIns" );
    #endif
 
-
-        if( strlen(GetHome()) > 0 )
-        {
-            papszSearchPath = CSLAddString( papszSearchPath, 
-                                  CPLFormFilename( GetHome(),
-    #ifdef MACOSX_FRAMEWORK 
-                                     "/Library/Application Support/GDAL/"
-                                     num2str(GDAL_VERSION_MAJOR) "."  
-                                     num2str(GDAL_VERSION_MINOR) "/PlugIns", NULL ) );
-    #else
-                                                    "lib/gdalplugins", NULL ) );
-    #endif                                           
-        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -755,26 +754,35 @@ void GDALDriverManager::AutoLoadDrivers()
             osABISpecificDir = papszSearchPath[iDir];
 
         papszFiles = CPLReadDir( osABISpecificDir );
+        int nFileCount = CSLCount(papszFiles);
 
-        for( int iFile = 0; iFile < CSLCount(papszFiles); iFile++ )
+        for( int iFile = 0; iFile < nFileCount; iFile++ )
         {
             char   *pszFuncName;
             const char *pszFilename;
             const char *pszExtension = CPLGetExtension( papszFiles[iFile] );
             void   *pRegister;
 
-            if( !EQUALN(papszFiles[iFile],"gdal_",5) )
-                continue;
-
             if( !EQUAL(pszExtension,"dll") 
                 && !EQUAL(pszExtension,"so") 
                 && !EQUAL(pszExtension,"dylib") )
                 continue;
 
-            pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
-            sprintf( pszFuncName, "GDALRegister_%s", 
-                     CPLGetBasename(papszFiles[iFile]) + 5 );
-            
+            if( EQUALN(papszFiles[iFile],"gdal_",strlen("gdal_")) )
+            {
+                pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
+                sprintf( pszFuncName, "GDALRegister_%s", 
+                     CPLGetBasename(papszFiles[iFile]) + strlen("gdal_") );
+            }
+            else if ( EQUALN(papszFiles[iFile],"ogr_",strlen("ogr_")) )
+            {
+                pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
+                sprintf( pszFuncName, "RegisterOGR%s", 
+                     CPLGetBasename(papszFiles[iFile]) + strlen("ogr_") );
+            }
+            else
+                continue;
+
             pszFilename = 
                 CPLFormFilename( osABISpecificDir, 
                                  papszFiles[iFile], NULL );
diff --git a/gcore/gdalexif.cpp b/gcore/gdalexif.cpp
index 4739ea4..f98573d 100644
--- a/gcore/gdalexif.cpp
+++ b/gcore/gdalexif.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalexif.cpp 27255 2014-04-26 19:39:48Z rouault $
+ * $Id: gdalexif.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GDAL
  * Purpose:  Implements a EXIF directory reader
@@ -39,7 +39,7 @@
 
 #include "gdalexif.h"
 
-CPL_CVSID("$Id: gdalexif.cpp 27255 2014-04-26 19:39:48Z rouault $");
+CPL_CVSID("$Id: gdalexif.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                         EXIFPrintData()                              */
@@ -136,7 +136,7 @@ static void EXIFPrintData(char* pszData, GUInt16 type,
           sprintf(pszTemp,"%s(0)",sep);
       }
       else{
-          sprintf(pszTemp, "%s(%g)", sep,
+          CPLsprintf(pszTemp, "%s(%g)", sep,
               (double) lp[0]/ (double)lp[1]);
       }
       sep = " ";
@@ -151,7 +151,7 @@ static void EXIFPrintData(char* pszData, GUInt16 type,
   case TIFF_SRATIONAL: {
     register GInt32 *lp = (GInt32*)data;
     for(;count>0;count--) {
-      sprintf(pszTemp, "%s(%g)", sep,
+      CPLsprintf(pszTemp, "%s(%g)", sep,
           (float) lp[0]/ (float) lp[1]);
       sep = " ";
       lp += 2;
@@ -165,7 +165,7 @@ static void EXIFPrintData(char* pszData, GUInt16 type,
   case TIFF_FLOAT: {
     register float *fp = (float *)data;
     for(;count>0;count--) {
-      sprintf(pszTemp, "%s%g", sep, *fp++), sep = " ";
+      CPLsprintf(pszTemp, "%s%g", sep, *fp++), sep = " ";
       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
           break;
       strcat(pszDataEnd,pszTemp);
@@ -176,7 +176,7 @@ static void EXIFPrintData(char* pszData, GUInt16 type,
   case TIFF_DOUBLE: {
     register double *dp = (double *)data;
     for(;count>0;count--) {
-      sprintf(pszTemp, "%s%g", sep, *dp++), sep = " ";
+      CPLsprintf(pszTemp, "%s%g", sep, *dp++), sep = " ";
       if (strlen(pszTemp) + pszDataEnd - pszData >= MAXSTRINGLENGTH)
           break;
       strcat(pszDataEnd,pszTemp);
diff --git a/gcore/gdalgmlcoverage.cpp b/gcore/gdalgmlcoverage.cpp
index 6d5040e..e861191 100644
--- a/gcore/gdalgmlcoverage.cpp
+++ b/gcore/gdalgmlcoverage.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalgmlcoverage.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: gdalgmlcoverage.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  Generic support for GML Coverage descriptions.
@@ -34,7 +34,7 @@
 #include "ogr_geometry.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: gdalgmlcoverage.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: gdalgmlcoverage.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                        ParseGMLCoverageDesc()                        */
@@ -157,11 +157,11 @@ CPLErr GDALParseGMLCoverage( CPLXMLNode *psXML,
         && poOriginGeometry != NULL )
     {
         padfGeoTransform[0] = poOriginGeometry->getX();
-        padfGeoTransform[1] = atof(papszOffset1Tokens[0]);
-        padfGeoTransform[2] = atof(papszOffset1Tokens[1]);
+        padfGeoTransform[1] = CPLAtof(papszOffset1Tokens[0]);
+        padfGeoTransform[2] = CPLAtof(papszOffset1Tokens[1]);
         padfGeoTransform[3] = poOriginGeometry->getY();
-        padfGeoTransform[4] = atof(papszOffset2Tokens[0]);
-        padfGeoTransform[5] = atof(papszOffset2Tokens[1]);
+        padfGeoTransform[4] = CPLAtof(papszOffset2Tokens[0]);
+        padfGeoTransform[5] = CPLAtof(papszOffset2Tokens[1]);
 
         // offset from center of pixel.
         padfGeoTransform[0] -= padfGeoTransform[1]*0.5;
diff --git a/gcore/gdaljp2abstractdataset.cpp b/gcore/gdaljp2abstractdataset.cpp
index 7e33a3e..8f8ba33 100644
--- a/gcore/gdaljp2abstractdataset.cpp
+++ b/gcore/gdaljp2abstractdataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaljp2abstractdataset.cpp 27181 2014-04-14 19:32:33Z rouault $
+ * $Id: gdaljp2abstractdataset.cpp 29131 2015-05-03 14:47:58Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  GDALGeorefPamDataset with helper to read georeferencing and other
@@ -31,6 +31,8 @@
 
 #include "gdaljp2abstractdataset.h"
 #include "gdaljp2metadata.h"
+#include "ogrsf_frmts.h"
+#include "gdal_mdreader.h"
 
 /************************************************************************/
 /*                     GDALJP2AbstractDataset()                         */
@@ -38,6 +40,9 @@
 
 GDALJP2AbstractDataset::GDALJP2AbstractDataset()
 {
+    pszWldFilename = NULL;
+    poMemDS = NULL;
+    papszMetadataFiles = NULL;
 }
 
 /************************************************************************/
@@ -46,6 +51,25 @@ GDALJP2AbstractDataset::GDALJP2AbstractDataset()
 
 GDALJP2AbstractDataset::~GDALJP2AbstractDataset()
 {
+    CPLFree(pszWldFilename);
+    CloseDependentDatasets();
+    CSLDestroy(papszMetadataFiles);
+}
+
+/************************************************************************/
+/*                      CloseDependentDatasets()                        */
+/************************************************************************/
+
+int GDALJP2AbstractDataset::CloseDependentDatasets()
+{
+    int bRet = GDALGeorefPamDataset::CloseDependentDatasets();
+    if( poMemDS )
+    {
+        GDALClose(poMemDS);
+        poMemDS = NULL;
+        bRet = TRUE;
+    }
+    return bRet;
 }
 
 /************************************************************************/
@@ -53,8 +77,9 @@ GDALJP2AbstractDataset::~GDALJP2AbstractDataset()
 /************************************************************************/
 
 void GDALJP2AbstractDataset::LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
-                                             const char* pszOverideFilename)
+                                             const char* pszOverideFilenameIn)
 {
+    const char* pszOverideFilename = pszOverideFilenameIn;
     if( pszOverideFilename == NULL )
         pszOverideFilename = poOpenInfo->pszFilename;
 
@@ -63,7 +88,10 @@ void GDALJP2AbstractDataset::LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
 /* -------------------------------------------------------------------- */
     GDALJP2Metadata oJP2Geo;
 
-    if( oJP2Geo.ReadAndParse( pszOverideFilename ) )
+    if( (poOpenInfo->fpL != NULL && pszOverideFilenameIn == NULL &&
+         oJP2Geo.ReadAndParse(poOpenInfo->fpL) ) ||
+        (!(poOpenInfo->fpL != NULL && pszOverideFilenameIn == NULL) &&
+         oJP2Geo.ReadAndParse( pszOverideFilename )) )
     {
         CPLFree(pszProjection);
         pszProjection = CPLStrdup(oJP2Geo.pszProjection);
@@ -75,20 +103,26 @@ void GDALJP2AbstractDataset::LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
             GDALDuplicateGCPs( oJP2Geo.nGCPCount, oJP2Geo.pasGCPList );
 
         if( oJP2Geo.bPixelIsPoint )
-            GDALPamDataset::SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
+            GDALDataset::SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT);
+        if( oJP2Geo.papszRPCMD )
+            GDALDataset::SetMetadata( oJP2Geo.papszRPCMD, "RPC" );
     }
 
+/* -------------------------------------------------------------------- */
+/*      Report XML UUID box in a dedicated metadata domain              */
+/* -------------------------------------------------------------------- */
     if (oJP2Geo.pszXMPMetadata)
     {
         char *apszMDList[2];
         apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
         apszMDList[1] = NULL;
-        GDALPamDataset::SetMetadata(apszMDList, "xml:XMP");
+        GDALDataset::SetMetadata(apszMDList, "xml:XMP");
     }
 
 /* -------------------------------------------------------------------- */
 /*      Do we have any XML boxes we would like to treat as special      */
-/*      domain metadata?                                                */
+/*      domain metadata? (Note: the GDAL multidomain metadata XML box   */
+/*      has been excluded and is dealt a few lines below.               */
 /* -------------------------------------------------------------------- */
     int iBox;
 
@@ -108,25 +142,68 @@ void GDALJP2AbstractDataset::LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
         apszMDList[0] = (char *) pszXML;
         apszMDList[1] = NULL;
 
-        GDALPamDataset::SetMetadata( apszMDList, osDomain );
+        GDALDataset::SetMetadata( apszMDList, osDomain );
 
         CPLFree( pszName );
     }
 
 /* -------------------------------------------------------------------- */
-/*      Do we have other misc metadata?                                 */
+/*      Do we have GDAL metadata?                                       */
+/* -------------------------------------------------------------------- */
+    if( oJP2Geo.pszGDALMultiDomainMetadata != NULL )
+    {
+        CPLXMLNode* psXMLNode = CPLParseXMLString(oJP2Geo.pszGDALMultiDomainMetadata);
+        if( psXMLNode )
+        {
+            GDALMultiDomainMetadata oLocalMDMD;
+            oLocalMDMD.XMLInit(psXMLNode, FALSE);
+            char** papszDomainList = oLocalMDMD.GetDomainList();
+            char** papszIter = papszDomainList;
+            GDALDataset::SetMetadata(oLocalMDMD.GetMetadata());
+            while( papszIter && *papszIter )
+            {
+                if( !EQUAL(*papszIter, "") && !EQUAL(*papszIter, "IMAGE_STRUCTURE") )
+                {
+                    if( GDALDataset::GetMetadata(*papszIter) != NULL )
+                    {
+                        CPLDebug("GDALJP2",
+                                 "GDAL metadata overrides metadata in %s domain over metadata read from other boxes",
+                                 *papszIter);
+                    }
+                    GDALDataset::SetMetadata(oLocalMDMD.GetMetadata(*papszIter), *papszIter);
+                }
+                papszIter ++;
+            }
+            CPLDestroyXMLNode(psXMLNode);
+        }
+        else
+            CPLErrorReset();
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Do we have other misc metadata (from resd box for now) ?        */
 /* -------------------------------------------------------------------- */
     if( oJP2Geo.papszMetadata != NULL )
     {
-        char **papszMD = CSLDuplicate(GDALPamDataset::GetMetadata());
+        char **papszMD = CSLDuplicate(GDALDataset::GetMetadata());
 
         papszMD = CSLMerge( papszMD, oJP2Geo.papszMetadata );
-        GDALPamDataset::SetMetadata( papszMD );
+        GDALDataset::SetMetadata( papszMD );
 
         CSLDestroy( papszMD );
     }
 
 /* -------------------------------------------------------------------- */
+/*      Do we have XML IPR ?                                            */
+/* -------------------------------------------------------------------- */
+    if( oJP2Geo.pszXMLIPR != NULL )
+    {
+        char* apszMD[2] = { NULL, NULL };
+        apszMD[0] = oJP2Geo.pszXMLIPR;
+        GDALDataset::SetMetadata( apszMD, "xml:IPR" );
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Check for world file.                                           */
 /* -------------------------------------------------------------------- */
     if( !bGeoTransformValid )
@@ -134,9 +211,310 @@ void GDALJP2AbstractDataset::LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
         bGeoTransformValid |=
             GDALReadWorldFile2( pszOverideFilename, NULL,
                                 adfGeoTransform,
-                                poOpenInfo->papszSiblingFiles, NULL )
+                                poOpenInfo->GetSiblingFiles(), &pszWldFilename )
             || GDALReadWorldFile2( pszOverideFilename, ".wld",
                                    adfGeoTransform,
-                                   poOpenInfo->papszSiblingFiles, NULL );
+                                   poOpenInfo->GetSiblingFiles(), &pszWldFilename );
     }
+
+    GDALMDReaderManager mdreadermanager;
+    GDALMDReaderBase* mdreader = mdreadermanager.GetReader(poOpenInfo->pszFilename,
+                                poOpenInfo->GetSiblingFiles(), MDR_ANY);
+    if(NULL != mdreader)
+    {
+        mdreader->FillMetadata(&(oMDMD));
+        papszMetadataFiles = mdreader->GetMetadataFiles();
+    }
+}
+
+/************************************************************************/
+/*                            GetFileList()                             */
+/************************************************************************/
+
+char **GDALJP2AbstractDataset::GetFileList()
+
+{
+    char **papszFileList = GDALGeorefPamDataset::GetFileList();
+
+    if( pszWldFilename != NULL &&
+        CSLFindString( papszFileList, pszWldFilename ) == -1 )
+    {
+        papszFileList = CSLAddString( papszFileList, pszWldFilename );
+    }
+    if(NULL != papszMetadataFiles)
+    {
+        for( int i = 0; papszMetadataFiles[i] != NULL; i++ )
+        {
+            papszFileList = CSLAddString( papszFileList, papszMetadataFiles[i] );
+        }
+    }
+    return papszFileList;
+}
+
+/************************************************************************/
+/*                        LoadVectorLayers()                            */
+/************************************************************************/
+
+void GDALJP2AbstractDataset::LoadVectorLayers(int bOpenRemoteResources)
+{
+    char** papszGMLJP2 = GetMetadata("xml:gml.root-instance");
+    if( papszGMLJP2 == NULL )
+        return;
+    GDALDriver* poMemDriver = (GDALDriver*)GDALGetDriverByName("Memory");
+    if( poMemDriver == NULL )
+        return;
+    CPLXMLNode* psRoot = CPLParseXMLString(papszGMLJP2[0]);
+    if( psRoot == NULL )
+        return;
+    CPLXMLNode* psCC = CPLGetXMLNode(psRoot, "=gmljp2:GMLJP2CoverageCollection");
+    if( psCC == NULL )
+    {
+        CPLDestroyXMLNode(psRoot);
+        return;
+    }
+
+    // Find feature collections
+    CPLXMLNode* psCCChildIter = psCC->psChild;
+    int nLayersAtCC = 0;
+    int nLayersAtGC = 0;
+    for( ; psCCChildIter != NULL; psCCChildIter = psCCChildIter->psNext )
+    {
+        if( psCCChildIter->eType != CXT_Element ||
+            strcmp(psCCChildIter->pszValue, "gmljp2:featureMember") != 0 ||
+            psCCChildIter->psChild == NULL ||
+            psCCChildIter->psChild->eType != CXT_Element )
+            continue;
+
+        CPLXMLNode* psGCorGMLJP2Features = psCCChildIter->psChild;
+        int bIsGC = ( strstr(psGCorGMLJP2Features->pszValue, "GridCoverage") != NULL );
+
+        CPLXMLNode* psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2Features->psChild;
+        for( ; psGCorGMLJP2FeaturesChildIter != NULL;
+               psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2FeaturesChildIter->psNext )
+        {
+            if( psGCorGMLJP2FeaturesChildIter->eType != CXT_Element ||
+                strcmp(psGCorGMLJP2FeaturesChildIter->pszValue, "gmljp2:feature") != 0 ||
+                psGCorGMLJP2FeaturesChildIter->psChild == NULL )
+                continue;
+
+            CPLXMLNode* psFC = NULL;
+            int bFreeFC = FALSE;
+            CPLString osGMLTmpFile;
+
+            CPLXMLNode* psChild = psGCorGMLJP2FeaturesChildIter->psChild;
+            if( psChild->eType == CXT_Attribute &&
+                strcmp(psChild->pszValue, "xlink:href") == 0 &&
+                strncmp(psChild->psChild->pszValue,
+                        "gmljp2://xml/", strlen("gmljp2://xml/")) == 0 )
+            {
+                const char* pszBoxName = psChild->psChild->pszValue + strlen("gmljp2://xml/");
+                char** papszBoxData = GetMetadata(CPLSPrintf("xml:%s", pszBoxName));
+                if( papszBoxData != NULL )
+                {
+                    psFC = CPLParseXMLString(papszBoxData[0]);
+                    bFreeFC = TRUE;
+                }
+                else
+                {
+                    CPLDebug("GMLJP2",
+                             "gmljp2:feature references %s, but no corresponding box found",
+                             psChild->psChild->pszValue);
+                }
+            }
+            if( psChild->eType == CXT_Attribute &&
+                strcmp(psChild->pszValue, "xlink:href") == 0 &&
+                (strncmp(psChild->psChild->pszValue, "http://", strlen("http://")) == 0 ||
+                 strncmp(psChild->psChild->pszValue, "https://", strlen("https://")) == 0) )
+            {
+                if( !bOpenRemoteResources )
+                    CPLDebug("GMLJP2", "Remote feature collection %s mentionned in GMLJP2 box",
+                             psChild->psChild->pszValue);
+                else
+                    osGMLTmpFile = "/vsicurl/" + CPLString(psChild->psChild->pszValue);
+            }
+            else if( psChild->eType == CXT_Element &&
+                     strstr(psChild->pszValue, "FeatureCollection") != NULL )
+            {
+                psFC = psChild;
+            }
+            if( psFC == NULL && osGMLTmpFile.size() == 0 )
+                continue;
+
+            if( psFC != NULL )
+            {
+                osGMLTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/my.gml", this);
+                // Create temporary .gml file
+                CPLSerializeXMLTreeToFile(psFC, osGMLTmpFile);
+            }
+
+            CPLDebug("GMLJP2", "Found a FeatureCollection at %s level",
+                     (bIsGC) ? "GridCoverage" : "CoverageCollection");
+
+            CPLString osXSDTmpFile;
+
+            if( psFC )
+            {
+                // Try to localize its .xsd schema in a GMLJP2 auxiliary box
+                const char* pszSchemaLocation = CPLGetXMLValue(psFC, "xsi:schemaLocation", NULL);
+                if( pszSchemaLocation )
+                {
+                    char **papszTokens = CSLTokenizeString2(
+                            pszSchemaLocation, " \t\n", 
+                            CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
+
+                    if( (CSLCount(papszTokens) % 2) == 0 )
+                    {
+                        for(char** papszIter = papszTokens; *papszIter; papszIter += 2 )
+                        {
+                            if( strncmp(papszIter[1], "gmljp2://xml/", strlen("gmljp2://xml/")) == 0 )
+                            {
+                                const char* pszBoxName = papszIter[1] + strlen("gmljp2://xml/");
+                                char** papszBoxData = GetMetadata(CPLSPrintf("xml:%s", pszBoxName));
+                                if( papszBoxData != NULL )
+                                {
+                                    osXSDTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/my.xsd", this);
+                                    VSIFCloseL(VSIFileFromMemBuffer(osXSDTmpFile,
+                                                                    (GByte*)papszBoxData[0],
+                                                                    strlen(papszBoxData[0]),
+                                                                    FALSE));
+                                }
+                                else
+                                {
+                                    CPLDebug("GMLJP2",
+                                            "Feature collection references %s, but no corresponding box found",
+                                            papszIter[1]);
+                                }
+                                break;
+                            }
+                        }
+                    }
+                    CSLDestroy(papszTokens);
+                }
+                if( bFreeFC )
+                {
+                    CPLDestroyXMLNode(psFC);
+                    psFC = NULL;
+                }
+            }
+
+            GDALDriverH hDrv = GDALIdentifyDriver(osGMLTmpFile, NULL);
+            GDALDriverH hGMLDrv = GDALGetDriverByName("GML");
+            if( hDrv != NULL && hDrv == hGMLDrv )
+            {
+                char* apszOpenOptions[2];
+                apszOpenOptions[0] = (char*) "FORCE_SRS_DETECTION=YES";
+                apszOpenOptions[1] = NULL;
+                GDALDataset* poTmpDS = (GDALDataset*)GDALOpenEx( osGMLTmpFile,
+                                        GDAL_OF_VECTOR, NULL, apszOpenOptions, NULL );
+                if( poTmpDS )
+                {
+                    int nLayers = poTmpDS->GetLayerCount();
+                    for(int i=0;i<nLayers;i++)
+                    {
+                        if( poMemDS == NULL )
+                            poMemDS = poMemDriver->Create("", 0, 0, 0, GDT_Unknown, NULL);
+                        OGRLayer* poSrcLyr = poTmpDS->GetLayer(i);
+                        const char* pszLayerName;
+                        if( bIsGC )
+                            pszLayerName = CPLSPrintf("FC_GridCoverage_%d_%s",
+                                                    ++nLayersAtGC, poSrcLyr->GetName());
+                        else
+                            pszLayerName = CPLSPrintf("FC_CoverageCollection_%d_%s",
+                                                    ++nLayersAtCC, poSrcLyr->GetName());
+                        poMemDS->CopyLayer(poSrcLyr, pszLayerName, NULL);
+                    }
+                    GDALClose(poTmpDS);
+
+                    // In case we don't have a schema, a .gfs might have been generated
+                    VSIUnlink(CPLSPrintf("/vsimem/gmljp2/%p/my.gfs", this));
+                }
+            }
+            else
+            {
+                CPLDebug("GMLJP2", "No GML driver found to read feature collection");
+            }
+
+            if( strncmp(osGMLTmpFile, "/vsicurl/", strlen("/vsicurl/")) != 0 )
+                VSIUnlink(osGMLTmpFile);
+            if( osXSDTmpFile.size() )
+                VSIUnlink(osXSDTmpFile);
+        }
+    }
+
+    // Find annotations
+    psCCChildIter = psCC->psChild;
+    int nAnnotations = 0;
+    for( ; psCCChildIter != NULL; psCCChildIter = psCCChildIter->psNext )
+    {
+        if( psCCChildIter->eType != CXT_Element ||
+            strcmp(psCCChildIter->pszValue, "gmljp2:featureMember") != 0 ||
+            psCCChildIter->psChild == NULL ||
+            psCCChildIter->psChild->eType != CXT_Element )
+            continue;
+        CPLXMLNode* psGCorGMLJP2Features = psCCChildIter->psChild;
+        int bIsGC = ( strstr(psGCorGMLJP2Features->pszValue, "GridCoverage") != NULL );
+        if( !bIsGC )
+            continue;
+        CPLXMLNode* psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2Features->psChild;
+        for( ; psGCorGMLJP2FeaturesChildIter != NULL;
+               psGCorGMLJP2FeaturesChildIter = psGCorGMLJP2FeaturesChildIter->psNext )
+        {
+            if( psGCorGMLJP2FeaturesChildIter->eType != CXT_Element ||
+                strcmp(psGCorGMLJP2FeaturesChildIter->pszValue, "gmljp2:annotation") != 0 ||
+                psGCorGMLJP2FeaturesChildIter->psChild == NULL ||
+                psGCorGMLJP2FeaturesChildIter->psChild->eType != CXT_Element ||
+                strstr(psGCorGMLJP2FeaturesChildIter->psChild->pszValue, "kml") == NULL )
+                continue;
+            CPLDebug("GMLJP2", "Found a KML annotation");
+
+            // Create temporary .kml file
+            CPLXMLNode* psKML = psGCorGMLJP2FeaturesChildIter->psChild;
+            CPLString osKMLTmpFile(CPLSPrintf("/vsimem/gmljp2/%p/my.kml", this));
+            CPLSerializeXMLTreeToFile(psKML, osKMLTmpFile);
+
+            GDALDataset* poTmpDS = (GDALDataset*)GDALOpenEx( osKMLTmpFile,
+                                    GDAL_OF_VECTOR, NULL, NULL, NULL );
+            if( poTmpDS )
+            {
+                int nLayers = poTmpDS->GetLayerCount();
+                for(int i=0;i<nLayers;i++)
+                {
+                    if( poMemDS == NULL )
+                        poMemDS = poMemDriver->Create("", 0, 0, 0, GDT_Unknown, NULL);
+                    OGRLayer* poSrcLyr = poTmpDS->GetLayer(i);
+                    const char* pszLayerName;
+                    pszLayerName = CPLSPrintf("Annotation_%d_%s",
+                                                ++nAnnotations, poSrcLyr->GetName());
+                    poMemDS->CopyLayer(poSrcLyr, pszLayerName, NULL);
+                }
+                GDALClose(poTmpDS);
+            }
+            else
+            {
+                CPLDebug("GMLJP2", "No KML/LIBKML driver found to read annotation");
+            }
+
+            VSIUnlink(osKMLTmpFile);
+        }
+    }
+
+    CPLDestroyXMLNode(psRoot);
+}
+
+/************************************************************************/
+/*                           GetLayerCount()                            */
+/************************************************************************/
+
+int GDALJP2AbstractDataset::GetLayerCount()
+{
+    return (poMemDS != NULL) ? poMemDS->GetLayerCount() : 0;
+}
+
+/************************************************************************/
+/*                             GetLayer()                               */
+/************************************************************************/
+
+OGRLayer* GDALJP2AbstractDataset::GetLayer(int i)
+{
+    return (poMemDS != NULL) ? poMemDS->GetLayer(i) : NULL;
 }
diff --git a/gcore/gdaljp2abstractdataset.h b/gcore/gdaljp2abstractdataset.h
index 5e8debe..e1593fc 100644
--- a/gcore/gdaljp2abstractdataset.h
+++ b/gcore/gdaljp2abstractdataset.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaljp2abstractdataset.h 26571 2013-10-30 10:59:11Z rouault $
+ * $Id: gdaljp2abstractdataset.h 29131 2015-05-03 14:47:58Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  GDALGeorefPamDataset with helper to read georeferencing and other
@@ -35,12 +35,26 @@
 
 class CPL_DLL GDALJP2AbstractDataset: public GDALGeorefPamDataset
 {
+    char*               pszWldFilename;
+
+    GDALDataset*        poMemDS;
+    char**              papszMetadataFiles;
+
+  protected:
+    virtual int         CloseDependentDatasets();
+
   public:
         GDALJP2AbstractDataset();
         ~GDALJP2AbstractDataset();
 
         void LoadJP2Metadata(GDALOpenInfo* poOpenInfo,
                              const char* pszOverideFilename = NULL);
+        void            LoadVectorLayers(int bOpenRemoteResources = FALSE);
+
+        virtual char      **GetFileList(void);
+
+        virtual int         GetLayerCount();
+        virtual OGRLayer   *GetLayer(int i);
 };
 
 #endif /* GDAL_JP2_ABSTRACT_DATASET_H_INCLUDED */
diff --git a/gcore/gdaljp2box.cpp b/gcore/gdaljp2box.cpp
index c250db4..47dd66a 100644
--- a/gcore/gdaljp2box.cpp
+++ b/gcore/gdaljp2box.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaljp2box.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdaljp2box.cpp 28691 2015-03-08 20:07:02Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  GDALJP2Box Implementation - Low level JP2 box reader.
@@ -31,7 +31,7 @@
 #include "gdaljp2metadata.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdaljp2box.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdaljp2box.cpp 28691 2015-03-08 20:07:02Z rouault $");
 
 /************************************************************************/
 /*                             GDALJP2Box()                             */
@@ -97,6 +97,9 @@ int GDALJP2Box::ReadNext()
 int GDALJP2Box::ReadFirstChild( GDALJP2Box *poSuperBox )
 
 {
+    if( poSuperBox == NULL )
+        return ReadFirst();
+
     szBoxType[0] = '\0';
     if( !poSuperBox->IsSuperBox() )
         return FALSE;
@@ -111,6 +114,9 @@ int GDALJP2Box::ReadFirstChild( GDALJP2Box *poSuperBox )
 int GDALJP2Box::ReadNextChild( GDALJP2Box *poSuperBox )
 
 {
+    if( poSuperBox == NULL )
+        return ReadNext();
+
     if( !ReadNext() )
         return FALSE;
 
@@ -176,11 +182,13 @@ int GDALJP2Box::ReadBox()
     {
         VSIFSeekL( fpVSIL, 0, SEEK_END );
         nBoxLength = VSIFTellL( fpVSIL ) - nBoxOffset;
+        VSIFSeekL( fpVSIL, nDataOffset, SEEK_SET );
     }
 
     if( EQUAL(szBoxType,"uuid") )
     {
-        VSIFReadL( abyUUID, 16, 1, fpVSIL );
+        if( VSIFReadL( abyUUID, 16, 1, fpVSIL ) != 1 )
+            return FALSE;
         nDataOffset += 16;
     }
 
@@ -214,6 +222,11 @@ int GDALJP2Box::IsSuperBox()
 GByte *GDALJP2Box::ReadBoxData()
 
 {
+    if( GetDataLength() > 100 * 1024 * 1024 )
+        return FALSE;
+
+    VSIFSeekL( fpVSIL, nDataOffset, SEEK_SET );
+    
     char *pszData = (char *) CPLMalloc((int)GetDataLength() + 1);
 
     if( (GIntBig) VSIFReadL( pszData, 1, (int)GetDataLength(), fpVSIL ) 
@@ -251,9 +264,9 @@ int GDALJP2Box::DumpReadable( FILE *fpOut, int nIndentLevel )
     for(i=0;i<nIndentLevel;i++)
         fprintf( fpOut, "  " );
 
-    fprintf( fpOut, "  Type=%s, Offset=%d/%d, Data Size=%d",
-             szBoxType, (int) nBoxOffset, (int) nDataOffset, 
-             (int)(nBoxLength - (nDataOffset - nBoxOffset)) );
+    fprintf( fpOut, "  Type=%s, Offset=" CPL_FRMT_GIB "/" CPL_FRMT_GIB", Data Size=" CPL_FRMT_GIB,
+             szBoxType, nBoxOffset, nDataOffset, 
+             GetDataLength() );
 
     if( IsSuperBox() )
     {
@@ -286,6 +299,8 @@ int GDALJP2Box::DumpReadable( FILE *fpOut, int nIndentLevel )
             fprintf( fpOut, " (GeoTIFF)" );
         if( EQUAL(pszHex,"96A9F1F1DC98402DA7AED68E34451809") )
             fprintf( fpOut, " (MSI Worldfile)" );
+        if( EQUAL(pszHex,"BE7ACFCB97A942E89C71999491E3AFAC") )
+            fprintf( fpOut, " (XMP)" );
         CPLFree( pszHex );
 
         fprintf( fpOut, "\n" );
@@ -326,26 +341,68 @@ void GDALJP2Box::SetWritableData( int nLength, const GByte *pabyDataIn )
 }
 
 /************************************************************************/
+/*                          AppendWritableData()                        */
+/************************************************************************/
+
+void GDALJP2Box::AppendWritableData( int nLength, const void *pabyDataIn )
+
+{
+    if( pabyData == NULL )
+    {
+        nBoxOffset = -9; // virtual offsets for data length computation.
+        nDataOffset = -1;
+        nBoxLength = 8;
+    }
+
+    pabyData = (GByte *) CPLRealloc(pabyData, GetDataLength() + nLength);
+    memcpy( pabyData + GetDataLength(), pabyDataIn, nLength );
+
+    nBoxLength += nLength;
+}
+
+/************************************************************************/
+/*                              AppendUInt32()                          */
+/************************************************************************/
+
+void GDALJP2Box::AppendUInt32( GUInt32 nVal )
+{
+    CPL_MSBPTR32(&nVal);
+    AppendWritableData(4, &nVal);
+}
+
+/************************************************************************/
+/*                              AppendUInt16()                          */
+/************************************************************************/
+
+void GDALJP2Box::AppendUInt16( GUInt16 nVal )
+{
+    CPL_MSBPTR16(&nVal);
+    AppendWritableData(2, &nVal);
+}
+/************************************************************************/
+/*                              AppendUInt8()                           */
+/************************************************************************/
+
+void GDALJP2Box::AppendUInt8( GByte nVal )
+{
+    AppendWritableData(1, &nVal);
+}
+
+/************************************************************************/
 /*                           CreateUUIDBox()                            */
 /************************************************************************/
 
 GDALJP2Box *GDALJP2Box::CreateUUIDBox( 
-    const GByte *pabyUUID, int nDataSize, GByte *pabyData )
+    const GByte *pabyUUID, int nDataSize, const GByte *pabyData )
 
 {
     GDALJP2Box *poBox;
 
     poBox = new GDALJP2Box();
     poBox->SetType( "uuid" );
-    memcpy( poBox->abyUUID, pabyUUID, 16 );
 
-    GByte *pabyMergedData = (GByte *) CPLMalloc(16+nDataSize);
-    memcpy( pabyMergedData, pabyUUID, 16 );
-    memcpy( pabyMergedData+16, pabyData, nDataSize );
-    
-    poBox->SetWritableData( 16 + nDataSize, pabyMergedData );
-    
-    CPLFree( pabyMergedData );
+    poBox->AppendWritableData( 16, pabyUUID );
+    poBox->AppendWritableData( nDataSize, pabyData );
 
     return poBox;
 }
@@ -355,8 +412,17 @@ GDALJP2Box *GDALJP2Box::CreateUUIDBox(
 /************************************************************************/
 
 GDALJP2Box *GDALJP2Box::CreateAsocBox( int nCount, GDALJP2Box **papoBoxes )
+{
+    return CreateSuperBox("asoc", nCount, papoBoxes);
+}
 
 
+/************************************************************************/
+/*                           CreateAsocBox()                            */
+/************************************************************************/
+
+GDALJP2Box *GDALJP2Box::CreateSuperBox( const char* pszType,
+                                        int nCount, GDALJP2Box **papoBoxes )
 {
     int nDataSize=0, iBox;
     GByte *pabyCompositeData, *pabyNext;
@@ -393,7 +459,7 @@ GDALJP2Box *GDALJP2Box::CreateAsocBox( int nCount, GDALJP2Box **papoBoxes )
 /* -------------------------------------------------------------------- */
     GDALJP2Box *poAsoc = new GDALJP2Box();
 
-    poAsoc->SetType( "asoc" );
+    poAsoc->SetType( pszType );
     poAsoc->SetWritableData( nDataSize, pabyCompositeData );
     
     CPLFree( pabyCompositeData );
@@ -439,4 +505,3 @@ GDALJP2Box *GDALJP2Box::CreateLabelledXMLAssoc( const char *pszLabel,
     
     return CreateAsocBox( 2, aoList );
 }
-
diff --git a/gcore/gdaljp2metadata.cpp b/gcore/gdaljp2metadata.cpp
index 0ad28f2..9bde12d 100644
--- a/gcore/gdaljp2metadata.cpp
+++ b/gcore/gdaljp2metadata.cpp
@@ -1,13 +1,15 @@
 /******************************************************************************
- * $Id: gdaljp2metadata.cpp 27182 2014-04-14 20:03:08Z rouault $
+ * $Id: gdaljp2metadata.cpp 29082 2015-04-30 17:03:52Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  GDALJP2Metadata - Read GeoTIFF and/or GML georef info.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
+ *           Even Rouault <even dot rouault at spatialys dot com>
  *
  ******************************************************************************
  * Copyright (c) 2005, Frank Warmerdam <warmerdam at pobox.com>
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2015, Even Rouault <even dot rouault at spatialys dot com>
+ * Copyright (c) 2015, European Union Satellite Centre
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -35,8 +37,10 @@
 #include "ogr_geometry.h"
 #include "ogr_api.h"
 #include "gt_wkt_srs_for_gdal.h"
+#include "json.h"
+#include "gdaljp2metadatagenerator.h"
 
-CPL_CVSID("$Id: gdaljp2metadata.cpp 27182 2014-04-14 20:03:08Z rouault $");
+CPL_CVSID("$Id: gdaljp2metadata.cpp 29082 2015-04-30 17:03:52Z rouault $");
 
 static const unsigned char msi_uuid2[16] =
 {0xb1,0x4b,0xf8,0xbd,0x08,0x3d,0x4b,0x43,
@@ -70,6 +74,8 @@ GDALJP2Metadata::GDALJP2Metadata()
     nGCPCount = 0;
     pasGCPList = NULL;
 
+    papszRPCMD = NULL;
+
     papszGMLMetadata = NULL;
     papszMetadata = NULL;
 
@@ -80,6 +86,8 @@ GDALJP2Metadata::GDALJP2Metadata()
     pabyMSIGData = NULL;
 
     pszXMPMetadata = NULL;
+    pszGDALMultiDomainMetadata = NULL;
+    pszXMLIPR = NULL;
 
     bHaveGeoTransform = FALSE;
     adfGeoTransform[0] = 0.0;
@@ -104,6 +112,7 @@ GDALJP2Metadata::~GDALJP2Metadata()
         GDALDeinitGCPs( nGCPCount, pasGCPList );
         CPLFree( pasGCPList );
     }
+    CSLDestroy(papszRPCMD);
 
     for( int i=0; i < nGeoTIFFBoxesCount; i++ )
     {
@@ -114,6 +123,8 @@ GDALJP2Metadata::~GDALJP2Metadata()
     CSLDestroy( papszGMLMetadata );
     CSLDestroy( papszMetadata );
     CPLFree( pszXMPMetadata );
+    CPLFree( pszGDALMultiDomainMetadata );
+    CPLFree( pszXMLIPR );
 }
 
 /************************************************************************/
@@ -139,14 +150,8 @@ int GDALJP2Metadata::ReadAndParse( const char *pszFilename )
         return FALSE;
     }
 
-    ReadBoxes( fpLL );
+    int bRet = ReadAndParse( fpLL );
     VSIFCloseL( fpLL );
-            
-/* -------------------------------------------------------------------- */
-/*      Try JP2GeoTIFF, GML and finally MSIG to get something.          */
-/* -------------------------------------------------------------------- */
-    if( !ParseJP2GeoTIFF() && !ParseGMLCoverageDesc() )
-        ParseMSIG();
 
 /* -------------------------------------------------------------------- */
 /*      If we still don't have a geotransform, look for a world         */
@@ -157,15 +162,32 @@ int GDALJP2Metadata::ReadAndParse( const char *pszFilename )
         bHaveGeoTransform = 
             GDALReadWorldFile( pszFilename, NULL, adfGeoTransform )
             || GDALReadWorldFile( pszFilename, ".wld", adfGeoTransform );
+        bRet |= bHaveGeoTransform;
     }
 
+    return bRet;
+}
+
+
+int GDALJP2Metadata::ReadAndParse( VSILFILE *fpLL )
+
+{
+    ReadBoxes( fpLL );
+
+/* -------------------------------------------------------------------- */
+/*      Try JP2GeoTIFF, GML and finally MSIG to get something.          */
+/* -------------------------------------------------------------------- */
+    if( !ParseJP2GeoTIFF() && !ParseGMLCoverageDesc() )
+        ParseMSIG();
+
 /* -------------------------------------------------------------------- */
 /*      Return success either either of projection or geotransform      */
 /*      or gcps.                                                        */
 /* -------------------------------------------------------------------- */
     return bHaveGeoTransform
         || nGCPCount > 0 
-        || (pszProjection != NULL && strlen(pszProjection) > 0);
+        || (pszProjection != NULL && strlen(pszProjection) > 0)
+        || papszRPCMD != NULL;
 }
 
 /************************************************************************/
@@ -180,7 +202,8 @@ void GDALJP2Metadata::CollectGMLData( GDALJP2Box *poGMLData )
 {
     GDALJP2Box oChildBox( poGMLData->GetFILE() );
 
-    oChildBox.ReadFirstChild( poGMLData );
+    if( !oChildBox.ReadFirstChild( poGMLData ) )
+        return;
 
     while( strlen(oChildBox.GetType()) > 0 )
     {
@@ -191,26 +214,85 @@ void GDALJP2Metadata::CollectGMLData( GDALJP2Box *poGMLData )
             char *pszLabel = NULL;
             char *pszXML = NULL;
 
-            oSubChildBox.ReadFirstChild( &oChildBox );
+            if( !oSubChildBox.ReadFirstChild( &oChildBox ) )
+                break;
             
             while( strlen(oSubChildBox.GetType()) > 0 )
             {
                 if( EQUAL(oSubChildBox.GetType(),"lbl ") )
                     pszLabel = (char *)oSubChildBox.ReadBoxData();
                 else if( EQUAL(oSubChildBox.GetType(),"xml ") )
+                {
                     pszXML = (char *) oSubChildBox.ReadBoxData();
 
-                oSubChildBox.ReadNextChild( &oChildBox );
+                    // Some GML data contains \0 instead of \n !
+                    // See http://trac.osgeo.org/gdal/ticket/5760
+                    if( pszXML )
+                    {
+                        int nXMLLength = (int)oSubChildBox.GetDataLength();
+                        int i;
+                        for(i=nXMLLength-1; i >= 0; i--)
+                        {
+                            if( pszXML[i] == '\0' )
+                                nXMLLength --;
+                            else
+                                break;
+                        }
+                        for(i=0;i<nXMLLength;i++)
+                        {
+                            if( pszXML[i] == '\0' )
+                                break;
+                        }
+                        if( i < nXMLLength )
+                        {
+                            CPLPushErrorHandler(CPLQuietErrorHandler);
+                            CPLXMLNode* psNode = CPLParseXMLString(pszXML);
+                            CPLPopErrorHandler();
+                            if( psNode == NULL )
+                            {
+                                CPLDebug("GMLJP2", "GMLJP2 data contains nul characters inside content. Replacing them by \\n");
+                                for(int i=0;i<nXMLLength;i++)
+                                {
+                                    if( pszXML[i] == '\0' )
+                                        pszXML[i] = '\n';
+                                }
+                            }
+                            else
+                                CPLDestroyXMLNode(psNode);
+                        }
+                    }
+                }
+
+                if( !oSubChildBox.ReadNextChild( &oChildBox ) )
+                    break;
             }
             
             if( pszLabel != NULL && pszXML != NULL )
+            {
                 papszGMLMetadata = CSLSetNameValue( papszGMLMetadata, 
                                                     pszLabel, pszXML );
+
+                if( strcmp(pszLabel, "gml.root-instance") == 0 &&
+                    pszGDALMultiDomainMetadata == NULL &&
+                    strstr(pszXML, "GDALMultiDomainMetadata") != NULL )
+                {
+                    CPLXMLNode* psTree = CPLParseXMLString(pszXML);
+                    if( psTree != NULL )
+                    {
+                        CPLXMLNode* psGDALMDMD = CPLSearchXMLNode(psTree, "GDALMultiDomainMetadata");
+                        if( psGDALMDMD )
+                            pszGDALMultiDomainMetadata = CPLSerializeXMLTree(psGDALMDMD);
+                    }
+                    CPLDestroyXMLNode(psTree);
+                }
+            }
+
             CPLFree( pszLabel );
             CPLFree( pszXML );
         }
         
-        oChildBox.ReadNextChild( poGMLData );
+        if( !oChildBox.ReadNextChild( poGMLData ) )
+            break;
     }
 }
 
@@ -297,8 +379,7 @@ int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
 /*      Collect XMP box.                                                */
 /* -------------------------------------------------------------------- */
         if( EQUAL(oBox.GetType(),"uuid")
-            && memcmp( oBox.GetUUID(), xmp_uuid, 16 ) == 0 &&
-            pszXMPMetadata == NULL )
+            && memcmp( oBox.GetUUID(), xmp_uuid, 16 ) == 0 )
         {
             if( pszXMPMetadata == NULL )
             {
@@ -317,8 +398,8 @@ int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
         {
             GDALJP2Box oSubBox( fpVSIL );
 
-            oSubBox.ReadFirstChild( &oBox );
-            if( EQUAL(oSubBox.GetType(),"lbl ") )
+            if( oSubBox.ReadFirstChild( &oBox ) && 
+                EQUAL(oSubBox.GetType(),"lbl ") )
             {
                 char *pszLabel = (char *) oSubBox.ReadBoxData();
                 if( pszLabel != NULL && EQUAL(pszLabel,"gml.data") )
@@ -335,12 +416,28 @@ int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
         if( EQUAL(oBox.GetType(),"xml ") )
         {
             CPLString osBoxName;
+
             char *pszXML = (char *) oBox.ReadBoxData();
+            if( strncmp(pszXML, "<GDALMultiDomainMetadata>",
+                        strlen("<GDALMultiDomainMetadata>")) == 0 )
+            {
+                if( pszGDALMultiDomainMetadata == NULL )
+                {
+                    pszGDALMultiDomainMetadata = pszXML;
+                    pszXML = NULL;
+                }
+                else
+                {
+                    CPLDebug("GDALJP2", "Too many GDAL metadata boxes. Ignoring this one");
+                }
+            }
+            else
+            {
+                osBoxName.Printf( "BOX_%d", iBox++ );
 
-            osBoxName.Printf( "BOX_%d", iBox++ );
-            
-            papszGMLMetadata = CSLSetNameValue( papszGMLMetadata, 
-                                                osBoxName, pszXML );
+                papszGMLMetadata = CSLSetNameValue( papszGMLMetadata, 
+                                                    osBoxName, pszXML );
+            }
             CPLFree( pszXML );
         }
 
@@ -404,6 +501,29 @@ int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
             }
         }
 
+/* -------------------------------------------------------------------- */
+/*      Collect IPR box.                                                */
+/* -------------------------------------------------------------------- */
+        if( EQUAL(oBox.GetType(),"jp2i") )
+        {
+            if( pszXMLIPR == NULL )
+            {
+                pszXMLIPR = (char*) oBox.ReadBoxData();
+                CPLXMLNode* psNode = CPLParseXMLString(pszXMLIPR);
+                if( psNode == NULL )
+                {
+                    CPLFree(pszXMLIPR);
+                    pszXMLIPR = NULL;
+                }
+                else
+                    CPLDestroyXMLNode(psNode);
+            }
+            else
+            {
+                CPLDebug("GDALJP2", "Too many IPR boxes. Ignoring this one");
+            }
+        }
+
         if (!oBox.ReadNext())
             break;
     }
@@ -418,12 +538,16 @@ int GDALJP2Metadata::ReadBoxes( VSILFILE *fpVSIL )
 int GDALJP2Metadata::ParseJP2GeoTIFF()
 
 {
+    if(! CSLTestBoolean(CPLGetConfigOption("GDAL_USE_GEOJP2", "TRUE")) )
+        return FALSE;
+
     int abValidProjInfo[MAX_JP2GEOTIFF_BOXES] = { FALSE };
     char* apszProjection[MAX_JP2GEOTIFF_BOXES] = { NULL };
     double aadfGeoTransform[MAX_JP2GEOTIFF_BOXES][6];
     int anGCPCount[MAX_JP2GEOTIFF_BOXES] = { 0 };
     GDAL_GCP    *apasGCPList[MAX_JP2GEOTIFF_BOXES] = { NULL };
     int abPixelIsPoint[MAX_JP2GEOTIFF_BOXES] = { 0 };
+    char** apapszRPCMD[MAX_JP2GEOTIFF_BOXES] = { NULL };
 
     int i;
     int nMax = MIN(nGeoTIFFBoxesCount, MAX_JP2GEOTIFF_BOXES);
@@ -441,7 +565,8 @@ int GDALJP2Metadata::ParseJP2GeoTIFF()
         if( GTIFWktFromMemBufEx( pasGeoTIFFBoxes[i].nGeoTIFFSize,
                                pasGeoTIFFBoxes[i].pabyGeoTIFFData,
                                &apszProjection[i], aadfGeoTransform[i],
-                               &anGCPCount[i], &apasGCPList[i], &abPixelIsPoint[i] ) == CE_None )
+                               &anGCPCount[i], &apasGCPList[i],
+                               &abPixelIsPoint[i], &apapszRPCMD[i] ) == CE_None )
         {
             if( apszProjection[i] != NULL && strlen(apszProjection[i]) != 0 ) 
                 abValidProjInfo[i] = TRUE;
@@ -474,7 +599,8 @@ int GDALJP2Metadata::ParseJP2GeoTIFF()
                 || aadfGeoTransform[i][3] != 0 
                 || aadfGeoTransform[i][4] != 0
                 || aadfGeoTransform[i][5] != 1
-                || anGCPCount[i] > 0)
+                || anGCPCount[i] > 0
+                || apapszRPCMD[i] != NULL )
             {
                 iBestIndex = i;
             }
@@ -488,6 +614,7 @@ int GDALJP2Metadata::ParseJP2GeoTIFF()
         nGCPCount = anGCPCount[iBestIndex];
         pasGCPList = apasGCPList[iBestIndex];
         bPixelIsPoint = abPixelIsPoint[iBestIndex];
+        papszRPCMD = apapszRPCMD[iBestIndex];
 
         if( adfGeoTransform[0] != 0 
             || adfGeoTransform[1] != 1 
@@ -514,6 +641,7 @@ int GDALJP2Metadata::ParseJP2GeoTIFF()
                 GDALDeinitGCPs( anGCPCount[i], apasGCPList[i] );
                 CPLFree( apasGCPList[i] );
             }
+            CSLDestroy( apapszRPCMD[i] );
         }
     }
 
@@ -718,6 +846,9 @@ int GDALJP2Metadata::GMLSRSLookup( const char *pszURN )
 int GDALJP2Metadata::ParseGMLCoverageDesc() 
 
 {
+    if(! CSLTestBoolean(CPLGetConfigOption("GDAL_USE_GMLJP2", "TRUE")) )
+        return FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      Do we have an XML doc that is apparently a coverage             */
 /*      description?                                                    */
@@ -810,11 +941,11 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
         && poOriginGeometry != NULL )
     {
         adfGeoTransform[0] = poOriginGeometry->getX();
-        adfGeoTransform[1] = atof(papszOffset1Tokens[0]);
-        adfGeoTransform[2] = atof(papszOffset2Tokens[0]);
+        adfGeoTransform[1] = CPLAtof(papszOffset1Tokens[0]);
+        adfGeoTransform[2] = CPLAtof(papszOffset2Tokens[0]);
         adfGeoTransform[3] = poOriginGeometry->getY();
-        adfGeoTransform[4] = atof(papszOffset1Tokens[1]);
-        adfGeoTransform[5] = atof(papszOffset2Tokens[1]);
+        adfGeoTransform[4] = CPLAtof(papszOffset1Tokens[1]);
+        adfGeoTransform[5] = CPLAtof(papszOffset2Tokens[1]);
 
         // offset from center of pixel.
         adfGeoTransform[0] -= adfGeoTransform[1]*0.5;
@@ -845,6 +976,14 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
                             "=FeatureCollection.boundedBy.Envelope.srsName",
                             NULL );
     }
+/* -------------------------------------------------------------------- */
+/*      Examples of DGIWG_Profile_of_JPEG2000_for_Georeference_Imagery.pdf */
+/*      have srsName only on RectifiedGrid element.                     */
+/* -------------------------------------------------------------------- */
+    if( psRG != NULL && pszSRSName == NULL )
+    {
+        pszSRSName = CPLGetXMLValue( psRG,  "srsName", NULL );
+    }
 
 /* -------------------------------------------------------------------- */
 /*      If we have gotten a geotransform, then try to interprete the    */
@@ -862,9 +1001,14 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
             if( oSRS.SetFromUserInput( pszSRSName ) == OGRERR_NONE )
                 oSRS.exportToWkt( &pszProjection );
         }
-        else if( EQUALN(pszSRSName,"urn:",4) 
+        else if( (EQUALN(pszSRSName,"urn:",4) 
                  && strstr(pszSRSName,":def:") != NULL
-                 && oSRS.importFromURN(pszSRSName) == OGRERR_NONE )
+                 && oSRS.importFromURN(pszSRSName) == OGRERR_NONE) ||
+                 /* GMLJP2 v2.0 uses CRS URL instead of URN */
+                 /* See e.g. http://schemas.opengis.net/gmljp2/2.0/examples/minimalInstance.xml */
+                 (EQUALN(pszSRSName,"http://www.opengis.net/def/crs/",
+                         strlen("http://www.opengis.net/def/crs/")) 
+                 && oSRS.importFromCRSURL(pszSRSName) == OGRERR_NONE) )
         {
             oSRS.exportToWkt( &pszProjection );
 
@@ -900,7 +1044,7 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
                                                "FALSE" ) ) )
     {
         bNeedAxisFlip = FALSE;
-        CPLDebug( "GMLJP2", "Supressed axis flipping based on GDAL_IGNORE_AXIS_ORIENTATION." );
+        CPLDebug( "GMLJP2", "Suppressed axis flipping based on GDAL_IGNORE_AXIS_ORIENTATION." );
     }
 
     if( bNeedAxisFlip )
@@ -917,7 +1061,12 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
         int swapWith1Index = 4;
         int swapWith2Index = 5;
 
-        if( CSLTestBoolean( CPLGetConfigOption( "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER",
+        /* Look if we have GDAL_JP2K_ALT_OFFSETVECTOR_ORDER=TRUE as a XML comment */
+        int bHasAltOffsetVectorOrderComment =
+            strstr(pszCoverage, "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER=TRUE") != NULL;
+
+        if( bHasAltOffsetVectorOrderComment ||
+            CSLTestBoolean( CPLGetConfigOption( "GDAL_JP2K_ALT_OFFSETVECTOR_ORDER",
                                                 "FALSE" ) ) )
         {
             swapWith1Index = 5;
@@ -933,6 +1082,16 @@ int GDALJP2Metadata::ParseGMLCoverageDesc()
         dfTemp = adfGeoTransform[2];
         adfGeoTransform[2] = adfGeoTransform[swapWith2Index];
         adfGeoTransform[swapWith2Index] = dfTemp;
+
+        /* Found in autotest/gdrivers/data/ll.jp2 */
+        if( adfGeoTransform[1] == 0.0 && adfGeoTransform[2] < 0.0 &&
+            adfGeoTransform[4] > 0.0 && adfGeoTransform[5] == 0.0 )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "It is likely that the axis order of the GMLJP2 box is not "
+                     "consistant with the EPSG order and that the resulting georeferencing "
+                     "will be incorrect. Try setting GDAL_IGNORE_AXIS_ORIENTATION=TRUE if it is the case");
+        }
     }
 
     return pszProjection != NULL && bSuccess;
@@ -977,6 +1136,17 @@ void GDALJP2Metadata::SetGeoTransform( double *padfGT )
 }
 
 /************************************************************************/
+/*                             SetRPCMD()                               */
+/************************************************************************/
+
+void GDALJP2Metadata::SetRPCMD( char** papszRPCMDIn )
+
+{
+    CSLDestroy( papszRPCMD );
+    papszRPCMD = CSLDuplicate(papszRPCMDIn);
+}
+
+/************************************************************************/
 /*                          CreateJP2GeoTIFF()                          */
 /************************************************************************/
 
@@ -992,7 +1162,8 @@ GDALJP2Box *GDALJP2Metadata::CreateJP2GeoTIFF()
 
     if( GTIFMemBufFromWktEx( pszProjection, adfGeoTransform, 
                              nGCPCount, pasGCPList,
-                             &nGTBufSize, &pabyGTBuf, bPixelIsPoint ) != CE_None )
+                             &nGTBufSize, &pabyGTBuf, bPixelIsPoint,
+                             papszRPCMD ) != CE_None )
         return NULL;
 
     if( nGTBufSize == 0 )
@@ -1011,64 +1182,27 @@ GDALJP2Box *GDALJP2Metadata::CreateJP2GeoTIFF()
 }
 
 /************************************************************************/
-/*                         PrepareCoverageBox()                         */
+/*                     GetGMLJP2GeoreferencingInfo()                    */
 /************************************************************************/
 
-GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
-
+int GDALJP2Metadata::GetGMLJP2GeoreferencingInfo( int& nEPSGCode,
+                                                  double adfOrigin[2],
+                                                  double adfXVector[2],
+                                                  double adfYVector[2],
+                                                  const char*& pszComment,
+                                                  CPLString& osDictBox )
 {
-/* -------------------------------------------------------------------- */
-/*      This is a backdoor to let us embed a literal gmljp2 chunk       */
-/*      supplied by the user as an external file.  This is mostly       */
-/*      for preparing test files with exotic contents.                  */
-/* -------------------------------------------------------------------- */
-    if( CPLGetConfigOption( "GMLJP2OVERRIDE", NULL ) != NULL )
-    {
-        VSILFILE *fp = VSIFOpenL( CPLGetConfigOption( "GMLJP2OVERRIDE",""), "r" );
-        char *pszGML = NULL;
-
-        if( fp == NULL )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "Unable to open GMLJP2OVERRIDE file." );
-            return NULL;
-        }
-        
-        VSIFSeekL( fp, 0, SEEK_END );
-        int nLength = (int) VSIFTellL( fp );
-        pszGML = (char *) CPLCalloc(1,nLength+1);
-        VSIFSeekL( fp, 0, SEEK_SET );
-        VSIFReadL( pszGML, 1, nLength, fp );
-        VSIFCloseL( fp );
-
-        GDALJP2Box *apoGMLBoxes[2];
-
-        apoGMLBoxes[0] = GDALJP2Box::CreateLblBox( "gml.data" );
-        apoGMLBoxes[1] = 
-            GDALJP2Box::CreateLabelledXMLAssoc( "gml.root-instance", 
-                                                pszGML );
-
-        GDALJP2Box *poGMLData = GDALJP2Box::CreateAsocBox( 2, apoGMLBoxes);
-        
-        delete apoGMLBoxes[0];
-        delete apoGMLBoxes[1];
-
-        CPLFree( pszGML );
-        
-        return poGMLData;
-    }
 
 /* -------------------------------------------------------------------- */
 /*      Try do determine a PCS or GCS code we can use.                  */
 /* -------------------------------------------------------------------- */
     OGRSpatialReference oSRS;
     char *pszWKTCopy = (char *) pszProjection;
-    int nEPSGCode = 0;
-    char szSRSName[100];
+    nEPSGCode = 0;
     int  bNeedAxisFlip = FALSE;
 
     if( oSRS.importFromWkt( &pszWKTCopy ) != OGRERR_NONE )
-        return NULL;
+        return FALSE;
 
     if( oSRS.IsProjected() )
     {
@@ -1086,24 +1220,31 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
         if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
         {
             nEPSGCode = atoi(oSRS.GetAuthorityCode( "GEOGCS" ));
+        }
+    }
+
+    // Save error state as importFromEPSGA() will call CPLReset()
+    int errNo = CPLGetLastErrorNo();
+    CPLErr eErr = CPLGetLastErrorType();
+    CPLString osLastErrorMsg = CPLGetLastErrorMsg();
+
+    // Determinte if we need to flix axis. Reimport from EPSG and make
+    // sure not to strip axis definitions to determine the axis order.
+    if( nEPSGCode != 0 && oSRS.importFromEPSGA(nEPSGCode) == OGRERR_NONE )
+    {
+        if( oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting() )
+        {
             bNeedAxisFlip = TRUE;
         }
     }
 
-    if( nEPSGCode != 0 )
-        sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
-    else
-        strcpy( szSRSName, 
-                "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
+    // Restore error state
+    CPLErrorSetState( eErr, errNo, osLastErrorMsg);
 
 /* -------------------------------------------------------------------- */
 /*      Prepare coverage origin and offset vectors.  Take axis          */
 /*      order into account if needed.                                   */
 /* -------------------------------------------------------------------- */
-    double adfOrigin[2];
-    double adfXVector[2];
-    double adfYVector[2];
-    
     adfOrigin[0] = adfGeoTransform[0] + adfGeoTransform[1] * 0.5
         + adfGeoTransform[4] * 0.5;
     adfOrigin[1] = adfGeoTransform[3] + adfGeoTransform[2] * 0.5
@@ -1119,9 +1260,10 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
                                                "FALSE" ) ) )
     {
         bNeedAxisFlip = FALSE;
-        CPLDebug( "GMLJP2", "Supressed axis flipping on write based on GDAL_IGNORE_AXIS_ORIENTATION." );
+        CPLDebug( "GMLJP2", "Suppressed axis flipping on write based on GDAL_IGNORE_AXIS_ORIENTATION." );
     }
 
+    pszComment = "";
     if( bNeedAxisFlip )
     {
         double dfTemp;
@@ -1146,19 +1288,127 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
             dfTemp = adfYVector[0];
             adfYVector[0] = adfXVector[1];
             adfXVector[1] = dfTemp;
+
+            /* We add this as an XML comment so that we know we must do OffsetVector flipping on reading */
+            pszComment = "              <!-- GDAL_JP2K_ALT_OFFSETVECTOR_ORDER=TRUE: First "
+                         "value of offset is latitude/northing component of the "
+                         "latitude/northing axis. -->\n";
         }
         else
         {
-        dfTemp = adfXVector[0];
-        adfXVector[0] = adfXVector[1];
-        adfXVector[1] = dfTemp;
+            dfTemp = adfXVector[0];
+            adfXVector[0] = adfXVector[1];
+            adfXVector[1] = dfTemp;
+
+            dfTemp = adfYVector[0];
+            adfYVector[0] = adfYVector[1];
+            adfYVector[1] = dfTemp;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If we need a user defined CRSDictionary entry, prepare it       */
+/*      here.                                                           */
+/* -------------------------------------------------------------------- */
+    if( nEPSGCode == 0 )
+    {
+        char *pszGMLDef = NULL;
+
+        if( oSRS.exportToXML( &pszGMLDef, NULL ) == OGRERR_NONE )
+        {
+            char* pszWKT = NULL;
+            oSRS.exportToWkt(&pszWKT);
+            char* pszXMLEscapedWKT = CPLEscapeString(pszWKT, -1, CPLES_XML);
+            CPLFree(pszWKT);
+            osDictBox.Printf(  
+"<gml:Dictionary gml:id=\"CRSU1\" \n"
+"        xmlns:gml=\"http://www.opengis.net/gml\"\n"
+"        xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
+"        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+"        xsi:schemaLocation=\"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/base/gml.xsd\">\n"
+"  <gml:description>Dictionnary for cursom SRS %s</gml:description>\n"
+"  <gml:name>Dictionnary for custom SRS</gml:name>\n"
+"  <gml:dictionaryEntry>\n"
+"%s\n"
+"  </gml:dictionaryEntry>\n"
+"</gml:Dictionary>\n",
+                     pszXMLEscapedWKT, pszGMLDef );
+            CPLFree(pszXMLEscapedWKT);
+        }
+        CPLFree( pszGMLDef );
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          CreateGMLJP2()                              */
+/************************************************************************/
+
+GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
+
+{
+/* -------------------------------------------------------------------- */
+/*      This is a backdoor to let us embed a literal gmljp2 chunk       */
+/*      supplied by the user as an external file.  This is mostly       */
+/*      for preparing test files with exotic contents.                  */
+/* -------------------------------------------------------------------- */
+    if( CPLGetConfigOption( "GMLJP2OVERRIDE", NULL ) != NULL )
+    {
+        VSILFILE *fp = VSIFOpenL( CPLGetConfigOption( "GMLJP2OVERRIDE",""), "r" );
+        char *pszGML = NULL;
 
-        dfTemp = adfYVector[0];
-        adfYVector[0] = adfYVector[1];
-        adfYVector[1] = dfTemp;
+        if( fp == NULL )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "Unable to open GMLJP2OVERRIDE file." );
+            return NULL;
         }
+        
+        VSIFSeekL( fp, 0, SEEK_END );
+        int nLength = (int) VSIFTellL( fp );
+        pszGML = (char *) CPLCalloc(1,nLength+1);
+        VSIFSeekL( fp, 0, SEEK_SET );
+        VSIFReadL( pszGML, 1, nLength, fp );
+        VSIFCloseL( fp );
+
+        GDALJP2Box *apoGMLBoxes[2];
+
+        apoGMLBoxes[0] = GDALJP2Box::CreateLblBox( "gml.data" );
+        apoGMLBoxes[1] = 
+            GDALJP2Box::CreateLabelledXMLAssoc( "gml.root-instance", 
+                                                pszGML );
+
+        GDALJP2Box *poGMLData = GDALJP2Box::CreateAsocBox( 2, apoGMLBoxes);
+        
+        delete apoGMLBoxes[0];
+        delete apoGMLBoxes[1];
+
+        CPLFree( pszGML );
+        
+        return poGMLData;
+    }
+
+    int nEPSGCode;
+    double adfOrigin[2];
+    double adfXVector[2];
+    double adfYVector[2];
+    const char* pszComment = "";
+    CPLString osDictBox;
+    if( !GetGMLJP2GeoreferencingInfo( nEPSGCode, adfOrigin,
+                                      adfXVector, adfYVector,
+                                      pszComment, osDictBox ) )
+    {
+        return NULL;
     }
 
+    char szSRSName[100];
+    if( nEPSGCode != 0 )
+        sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
+    else
+        strcpy( szSRSName, 
+                "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
+
 /* -------------------------------------------------------------------- */
 /*      For now we hardcode for a minimal instance format.              */
 /* -------------------------------------------------------------------- */
@@ -1191,12 +1441,14 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
 "                  <gml:pos>%.15g %.15g</gml:pos>\n"
 "                </gml:Point>\n"
 "              </gml:origin>\n"
+"%s"
 "              <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
 "              <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
 "            </gml:RectifiedGrid>\n"
 "          </gml:rectifiedGridDomain>\n"
 "          <gml:rangeSet>\n"
 "            <gml:File>\n"
+"              <gml:rangeParameters/>\n"
 "              <gml:fileName>gmljp2://codestream/0</gml:fileName>\n"
 "              <gml:fileStructure>Record Interleaved</gml:fileStructure>\n"
 "            </gml:File>\n"
@@ -1207,42 +1459,17 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
 "  </gml:featureMember>\n"
 "</gml:FeatureCollection>\n",
              nXSize-1, nYSize-1, szSRSName, adfOrigin[0], adfOrigin[1],
+             pszComment,
              szSRSName, adfXVector[0], adfXVector[1], 
              szSRSName, adfYVector[0], adfYVector[1] );
 
 /* -------------------------------------------------------------------- */
-/*      If we need a user defined CRSDictionary entry, prepare it       */
-/*      here.                                                           */
+/*      Setup the gml.data label.                                       */
 /* -------------------------------------------------------------------- */
-    CPLString osDictBox;
+    GDALJP2Box *apoGMLBoxes[5];
+    int nGMLBoxes = 0;
 
-    if( nEPSGCode == 0 )
-    {
-        char *pszGMLDef = NULL;
-
-        if( oSRS.exportToXML( &pszGMLDef, NULL ) == OGRERR_NONE )
-        {
-            osDictBox.Printf(  
-"<gml:Dictionary gml:id=\"CRSU1\" \n"
-"        xmlns:gml=\"http://www.opengis.net/gml\"\n"
-"        xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
-"        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
-"  <gml:dictionaryEntry>\n"
-"%s\n"
-"  </gml:dictionaryEntry>\n"
-"</gml:Dictionary>\n",
-                     pszGMLDef );
-        }
-        CPLFree( pszGMLDef );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Setup the gml.data label.                                       */
-/* -------------------------------------------------------------------- */
-    GDALJP2Box *apoGMLBoxes[5];
-    int nGMLBoxes = 0;
-
-    apoGMLBoxes[nGMLBoxes++] = GDALJP2Box::CreateLblBox( "gml.data" );
+    apoGMLBoxes[nGMLBoxes++] = GDALJP2Box::CreateLblBox( "gml.data" );
 
 /* -------------------------------------------------------------------- */
 /*      Setup gml.root-instance.                                        */
@@ -1253,7 +1480,7 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
 /* -------------------------------------------------------------------- */
 /*      Add optional dictionary.                                        */
 /* -------------------------------------------------------------------- */
-    if( strlen(osDictBox) > 0 )
+    if( osDictBox.size() > 0 )
         apoGMLBoxes[nGMLBoxes++] = 
             GDALJP2Box::CreateLabelledXMLAssoc( "CRSDictionary.gml",
                                                 osDictBox );
@@ -1272,4 +1499,1510 @@ GDALJP2Box *GDALJP2Metadata::CreateGMLJP2( int nXSize, int nYSize )
     return poGMLData;
 }
 
+/************************************************************************/
+/*                      GDALGMLJP2GetXMLRoot()                          */
+/************************************************************************/
+
+static CPLXMLNode* GDALGMLJP2GetXMLRoot(CPLXMLNode* psNode)
+{
+    for( ; psNode != NULL; psNode = psNode->psNext )
+    {
+        if( psNode->eType == CXT_Element && psNode->pszValue[0] != '?' )
+            return psNode;
+    }
+    return NULL;
+}
+
+/************************************************************************/
+/*            GDALGMLJP2PatchFeatureCollectionSubstitutionGroup()       */
+/************************************************************************/
+
+static void GDALGMLJP2PatchFeatureCollectionSubstitutionGroup(CPLXMLNode* psRoot)
+{
+    /* GML 3.2 SF profile recommands the feature collection type to derive */
+    /* from gml:AbstractGML to prevent it to be included in another feature */
+    /* collection, but this is what we want to do. So patch that... */
+
+    /* <xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractGML"/> */
+    /* --> */
+    /* <xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/> */
+    if( psRoot->eType == CXT_Element &&
+        (strcmp(psRoot->pszValue, "schema") == 0 || strcmp(psRoot->pszValue, "xs:schema") == 0) )
+    {
+        for(CPLXMLNode* psIter = psRoot->psChild; psIter != NULL; psIter = psIter->psNext)
+        {
+            if( psIter->eType == CXT_Element &&
+                (strcmp(psIter->pszValue, "element") == 0 || strcmp(psIter->pszValue, "xs:element") == 0) &&
+                strcmp(CPLGetXMLValue(psIter, "name", ""), "FeatureCollection") == 0 &&
+                strcmp(CPLGetXMLValue(psIter, "substitutionGroup", ""), "gml:AbstractGML") == 0 )
+            {
+                CPLDebug("GMLJP2", "Patching substitutionGroup=\"gml:AbstractGML\" to \"gml:AbstractFeature\"");
+                CPLSetXMLValue( psIter, "#substitutionGroup", "gml:AbstractFeature" );
+                break;
+            }
+        }
+    }
+}
+
+/************************************************************************/
+/*                          CreateGMLJP2V2()                            */
+/************************************************************************/
+
+class GMLJP2V2GMLFileDesc
+{
+    public:
+        CPLString osFile;
+        CPLString osRemoteResource;
+        CPLString osNamespace;
+        CPLString osSchemaLocation;
+        int       bInline;
+        int       bParentCoverageCollection;
+
+            GMLJP2V2GMLFileDesc(): bInline(TRUE), bParentCoverageCollection(TRUE) {}
+};
+
+class GMLJP2V2AnnotationDesc
+{
+    public:
+        CPLString osFile;
+};
+
+class GMLJP2V2MetadataDesc
+{
+    public:
+        CPLString osFile;
+        CPLString osContent;
+        CPLString osTemplateFile;
+        CPLString osSourceFile;
+        int       bGDALMetadata;
+        int       bParentCoverageCollection;
+
+            GMLJP2V2MetadataDesc(): bGDALMetadata(FALSE), bParentCoverageCollection(TRUE) {}
+};
+
+class GMLJP2V2StyleDesc
+{
+    public:
+        CPLString osFile;
+        int       bParentCoverageCollection;
+
+            GMLJP2V2StyleDesc(): bParentCoverageCollection(TRUE) {}
+};
+
+class GMLJP2V2ExtensionDesc
+{
+    public:
+        CPLString osFile;
+        int       bParentCoverageCollection;
+
+            GMLJP2V2ExtensionDesc(): bParentCoverageCollection(TRUE) {}
+};
+class GMLJP2V2BoxDesc
+{
+    public:
+        CPLString osFile;
+        CPLString osLabel;
+};
+
+GDALJP2Box *GDALJP2Metadata::CreateGMLJP2V2( int nXSize, int nYSize,
+                                             const char* pszDefFilename,
+                                             GDALDataset* poSrcDS )
+
+{
+    CPLString osRootGMLId = "ID_GMLJP2_0";
+    CPLString osGridCoverage;
+    CPLString osGridCoverageFile;
+    int bCRSURL = TRUE;
+    std::vector<GMLJP2V2MetadataDesc> aoMetadata;
+    std::vector<GMLJP2V2AnnotationDesc> aoAnnotations;
+    std::vector<GMLJP2V2GMLFileDesc> aoGMLFiles;
+    std::vector<GMLJP2V2StyleDesc> aoStyles;
+    std::vector<GMLJP2V2ExtensionDesc> aoExtensions;
+    std::vector<GMLJP2V2BoxDesc> aoBoxes;
+
+/* -------------------------------------------------------------------- */
+/*      Parse definition file.                                          */
+/* -------------------------------------------------------------------- */
+    if( pszDefFilename && !EQUAL(pszDefFilename, "YES") && !EQUAL(pszDefFilename, "TRUE") )
+    {
+        GByte* pabyContent = NULL;
+        if( pszDefFilename[0] != '{' )
+        {
+            if( !VSIIngestFile( NULL, pszDefFilename, &pabyContent, NULL, -1 ) )
+                return NULL;
+        }
+
+/*
+{
+    "#doc" : "Unless otherwise specified, all elements are optional",
+
+    "#root_instance_doc": "Describe content of the GMLJP2CoverageCollection",
+    "root_instance": {
+        "#gml_id_doc": "Specify GMLJP2CoverageCollection id here. Default is ID_GMLJP2_0",
+        "gml_id": "some_gml_id",
+
+        "#grid_coverage_file_doc": [
+            "External XML file, whose root might be a GMLJP2GridCoverage, ",
+            "GMLJP2RectifiedGridCoverage or a GMLJP2ReferenceableGridCoverage",
+            "If not specified, GDAL will auto-generate a GMLJP2RectifiedGridCoverage" ],
+        "grid_coverage_file": "gmljp2gridcoverage.xml",
+
+        "#crs_url_doc": [
+            "true for http://www.opengis.net/def/crs/EPSG/0/XXXX CRS URL.",
+            "If false, use CRS URN. Default value is true" ],
+        "crs_url": true,
+
+        "#metadata_doc": [ "An array of metadata items. Can be either strings, with ",
+                           "a filename or directly inline XML content, or either ",
+                           "a more complete description." ],
+        "metadata": [
+
+            "dcmetadata.xml",
+
+            {
+                "#file_doc": "Can use relative or absolute paths. Exclusive of content, gdal_metadata and generated_metadata.",
+                "file": "dcmetadata.xml",
+
+                "#gdal_metadata_doc": "Whether to serialize GDAL metadata as GDALMultiDomainMetadata",
+                "gdal_metadata": false,
+
+                "#dynamic_metadata_doc":
+                    [ "The metadata file will be generated from a template and a source file.",
+                      "The template is a valid GMLJP2 metadata XML tree with placeholders like",
+                      "{{{XPATH(some_xpath_expression)}}}",
+                      "that are evalated from the source XML file. Typical use case",
+                      "is to generate a gmljp2:eopMetadata from the XML metadata",
+                      "provided by the image provider in their own particular format." ],
+                "dynamic_metadata" :
+                {
+                    "template": "my_template.xml",
+                    "source": "my_source.xml"
+                },
+
+                "#content": "Exclusive of file. Inline XML metadata content",
+                "content": "<gmljp2:metadata>Some simple textual metadata</gmljp2:metadata>",
+
+                "#parent_node": ["Where to put the metadata.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            },
+        ],
+
+        "#annotations_doc": [ "An array of filenames, either directly KML files",
+                              "or other vector files recognized by GDAL that ",
+                              "will be translated on-the-fly as KML" ],
+        "annotations": [
+            "my.kml"
+        ],
+
+        "#gml_filelist_doc" :[
+            "An array of GML files. Can be either GML filenames, ",
+            "or a more complete description" ],
+        "gml_filelist": [
+
+            "my.gml",
+
+            {
+                "#file_doc": "Can use relative or absolute paths. Exclusive of remote_resource",
+                "file": "converted/test_0.gml",
+
+                "#remote_resource_doc": "URL of a feature collection that must be referenced through a xlink:href",
+                "remote_resource": "http://svn.osgeo.org/gdal/trunk/autotest/ogr/data/expected_gml_gml32.gml",
+
+                "#namespace_doc": ["The namespace in schemaLocation for which to substitute",
+                                  "its original schemaLocation with the one provided below.",
+                                  "Ignored for a remote_resource"],
+                "namespace": "http://example.com",
+
+                "#schema_location_doc": ["Value of the substitued schemaLocation. ",
+                                         "Typically a schema box label (link)",
+                                         "Ignored for a remote_resource"],
+                "schema_location": "gmljp2://xml/schema_0.xsd",
+
+                "#inline_doc": [
+                    "Whether to inline the content, or put it in a separate xml box. Default is true",
+                    "Ignored for a remote_resource." ],
+                "inline": true,
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ],
+
+        "#styles_doc: [ "An array of styles. For example SLD files" ],
+        "styles" : [
+            {
+                "#file_doc": "Can use relative or absolute paths.",
+                "file": "my.sld",
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ],
+
+        "#extensions_doc: [ "An array of extensions." ],
+        "extensions" : [
+            {
+                "#file_doc": "Can use relative or absolute paths.",
+                "file": "my.xml",
+
+                "#parent_node": ["Where to put the FeatureCollection.",
+                                 "Under CoverageCollection (default) or GridCoverage" ],
+                "parent_node": "CoverageCollection"
+            }
+        ]
+    },
+
+    "#boxes_doc": "An array to describe the content of XML asoc boxes",
+    "boxes": [
+        {
+            "#file_doc": "can use relative or absolute paths. Required",
+            "file": "converted/test_0.xsd",
+
+            "#label_doc": ["the label of the XML box. If not specified, will be the ",
+                          "filename without the directory part." ],
+            "label": "schema_0.xsd"
+        }
+    ]
+}
+*/
+
+        json_tokener* jstok = NULL;
+        json_object* poObj = NULL;
+
+        jstok = json_tokener_new();
+        poObj = json_tokener_parse_ex(jstok, pabyContent ? (const char*) pabyContent : pszDefFilename, -1);
+        CPLFree(pabyContent);
+        if( jstok->err != json_tokener_success)
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                        "JSON parsing error: %s (at offset %d)",
+                        json_tokener_error_desc(jstok->err), jstok->char_offset);
+            json_tokener_free(jstok);
+            return NULL;
+        }
+        json_tokener_free(jstok);
+
+        json_object* poRootInstance = json_object_object_get(poObj, "root_instance");
+        if( poRootInstance && json_object_get_type(poRootInstance) == json_type_object )
+        {
+            json_object* poGMLId = json_object_object_get(poRootInstance, "gml_id");
+            if( poGMLId && json_object_get_type(poGMLId) == json_type_string )
+                osRootGMLId = json_object_get_string(poGMLId);
+
+            json_object* poGridCoverageFile = json_object_object_get(poRootInstance, "grid_coverage_file");
+            if( poGridCoverageFile && json_object_get_type(poGridCoverageFile) == json_type_string )
+                osGridCoverageFile = json_object_get_string(poGridCoverageFile);
+
+            json_object* poCRSURL = json_object_object_get(poRootInstance, "crs_url");
+            if( poCRSURL && json_object_get_type(poCRSURL) == json_type_boolean )
+                bCRSURL = json_object_get_boolean(poCRSURL);
+
+
+            json_object* poMetadatas = json_object_object_get(poRootInstance, "metadata"); 
+            if( poMetadatas && json_object_get_type(poMetadatas) == json_type_array )
+            {
+                for(int i=0;i<json_object_array_length(poMetadatas);i++)
+                {
+                    json_object* poMetadata = json_object_array_get_idx(poMetadatas, i);
+                    if( poMetadata && json_object_get_type(poMetadata) == json_type_string )
+                    {
+                        GMLJP2V2MetadataDesc oDesc;
+                        const char* pszStr = json_object_get_string(poMetadata);
+                        if( pszStr[0] == '<' )
+                            oDesc.osContent = pszStr;
+                        else
+                            oDesc.osFile = pszStr;
+                        aoMetadata.push_back(oDesc);
+                    }
+                    else if ( poMetadata && json_object_get_type(poMetadata) == json_type_object )
+                    {
+                        const char* pszFile = NULL;
+                        json_object* poFile = json_object_object_get(poMetadata, "file");
+                        if( poFile && json_object_get_type(poFile) == json_type_string )
+                            pszFile = json_object_get_string(poFile);
+                        
+                        const char* pszContent = NULL;
+                        json_object* poContent = json_object_object_get(poMetadata, "content");
+                        if( poContent && json_object_get_type(poContent) == json_type_string )
+                            pszContent = json_object_get_string(poContent);
+
+                        const char* pszTemplate = NULL;
+                        const char* pszSource = NULL;
+                        json_object* poDynamicMetadata = json_object_object_get(poMetadata, "dynamic_metadata");
+                        if( poDynamicMetadata && json_object_get_type(poDynamicMetadata) == json_type_object )
+                        {
+#ifdef HAVE_LIBXML2
+                            if( CSLTestBoolean(CPLGetConfigOption("GDAL_DEBUG_PROCESS_DYNAMIC_METADATA", "YES")) )
+                            {
+                                json_object* poTemplate = json_object_object_get(poDynamicMetadata, "template");
+                                if( poTemplate && json_object_get_type(poTemplate) == json_type_string )
+                                    pszTemplate = json_object_get_string(poTemplate);
+
+                                json_object* poSource = json_object_object_get(poDynamicMetadata, "source");
+                                if( poSource && json_object_get_type(poSource) == json_type_string )
+                                    pszSource = json_object_get_string(poSource);
+                            }
+                            else
+#endif
+                            {
+                            CPLError(CE_Warning, CPLE_NotSupported,
+                                     "dynamic_metadata not supported since libxml2 is not available");
+                            }
+                        }
+
+                        int bGDALMetadata = FALSE;
+                        json_object* poGDALMetadata = json_object_object_get(poMetadata, "gdal_metadata");
+                        if( poGDALMetadata && json_object_get_type(poGDALMetadata) == json_type_boolean )
+                            bGDALMetadata = json_object_get_boolean(poGDALMetadata);
+
+                        if( pszFile != NULL || pszContent != NULL ||
+                            (pszTemplate != NULL && pszSource != NULL) ||
+                            bGDALMetadata )
+                        {
+                            GMLJP2V2MetadataDesc oDesc;
+                            if( pszFile )
+                                oDesc.osFile = pszFile;
+                            if( pszContent )
+                                oDesc.osContent = pszContent;
+                            if( pszTemplate )
+                                oDesc.osTemplateFile = pszTemplate;
+                            if( pszSource )
+                                oDesc.osSourceFile = pszSource;
+                            oDesc.bGDALMetadata = bGDALMetadata;
+
+                            json_object* poLocation = json_object_object_get(poMetadata, "parent_node");
+                            if( poLocation && json_object_get_type(poLocation) == json_type_string )
+                            {
+                                const char* pszLocation = json_object_get_string(poLocation);
+                                if( EQUAL(pszLocation, "CoverageCollection") )
+                                    oDesc.bParentCoverageCollection  = TRUE;
+                                else if( EQUAL(pszLocation, "GridCoverage") )
+                                    oDesc.bParentCoverageCollection = FALSE;
+                                else
+                                    CPLError(CE_Warning, CPLE_NotSupported,
+                                             "metadata[].parent_node should be CoverageCollection or GridCoverage");
+                            }
+
+                            aoMetadata.push_back(oDesc);
+                        }
+                    }
+                }
+            }
+
+            json_object* poAnnotations = json_object_object_get(poRootInstance, "annotations"); 
+            if( poAnnotations && json_object_get_type(poAnnotations) == json_type_array )
+            {
+                for(int i=0;i<json_object_array_length(poAnnotations);i++)
+                {
+                    json_object* poAnnotation = json_object_array_get_idx(poAnnotations, i);
+                    if( poAnnotation && json_object_get_type(poAnnotation) == json_type_string )
+                    {
+                        GMLJP2V2AnnotationDesc oDesc;
+                        oDesc.osFile = json_object_get_string(poAnnotation);
+                        aoAnnotations.push_back(oDesc);
+                    }
+                }
+            }
+
+            json_object* poGMLFileList = json_object_object_get(poRootInstance, "gml_filelist"); 
+            if( poGMLFileList && json_object_get_type(poGMLFileList) == json_type_array )
+            {
+                for(int i=0;i<json_object_array_length(poGMLFileList);i++)
+                {
+                    json_object* poGMLFile = json_object_array_get_idx(poGMLFileList, i);
+                    if( poGMLFile && json_object_get_type(poGMLFile) == json_type_object )
+                    {
+                        const char* pszFile = NULL;
+                        json_object* poFile = json_object_object_get(poGMLFile, "file");
+                        if( poFile && json_object_get_type(poFile) == json_type_string )
+                            pszFile = json_object_get_string(poFile);
+
+                        const char* pszRemoteResource = NULL;
+                        json_object* poRemoteResource = json_object_object_get(poGMLFile, "remote_resource");
+                        if( poRemoteResource && json_object_get_type(poRemoteResource) == json_type_string )
+                            pszRemoteResource = json_object_get_string(poRemoteResource);
+
+                        if( pszFile || pszRemoteResource )
+                        {
+                            GMLJP2V2GMLFileDesc oDesc;
+                            if( pszFile )
+                                oDesc.osFile = pszFile;
+                            else if( pszRemoteResource )
+                                oDesc.osRemoteResource = pszRemoteResource;
+
+                            json_object* poNamespace = json_object_object_get(poGMLFile, "namespace");
+                            if( poNamespace && json_object_get_type(poNamespace) == json_type_string )
+                                oDesc.osNamespace = json_object_get_string(poNamespace);
+
+                            json_object* poSchemaLocation = json_object_object_get(poGMLFile, "schema_location");
+                            if( poSchemaLocation && json_object_get_type(poSchemaLocation) == json_type_string )
+                                oDesc.osSchemaLocation = json_object_get_string(poSchemaLocation);
+
+                            json_object* poInline = json_object_object_get(poGMLFile, "inline");
+                            if( poInline && json_object_get_type(poInline) == json_type_boolean )
+                                oDesc.bInline = json_object_get_boolean(poInline);
+
+
+                            json_object* poLocation = json_object_object_get(poGMLFile, "parent_node");
+                            if( poLocation && json_object_get_type(poLocation) == json_type_string )
+                            {
+                                const char* pszLocation = json_object_get_string(poLocation);
+                                if( EQUAL(pszLocation, "CoverageCollection") )
+                                    oDesc.bParentCoverageCollection  = TRUE;
+                                else if( EQUAL(pszLocation, "GridCoverage") )
+                                    oDesc.bParentCoverageCollection = FALSE;
+                                else
+                                    CPLError(CE_Warning, CPLE_NotSupported,
+                                             "gml_filelist[].parent_node should be CoverageCollection or GridCoverage");
+                            }
+
+                            aoGMLFiles.push_back(oDesc);
+                        }
+                    }
+                    else if( poGMLFile && json_object_get_type(poGMLFile) == json_type_string )
+                    {
+                        GMLJP2V2GMLFileDesc oDesc;
+                        oDesc.osFile = json_object_get_string(poGMLFile);
+                        aoGMLFiles.push_back(oDesc);
+                    }
+                }
+            }
+
+            json_object* poStyles = json_object_object_get(poRootInstance, "styles"); 
+            if( poStyles && json_object_get_type(poStyles) == json_type_array )
+            {
+                for(int i=0;i<json_object_array_length(poStyles);i++)
+                {
+                    json_object* poStyle = json_object_array_get_idx(poStyles, i);
+                    if( poStyle && json_object_get_type(poStyle) == json_type_object )
+                    {
+                        const char* pszFile = NULL;
+                        json_object* poFile = json_object_object_get(poStyle, "file");
+                        if( poFile && json_object_get_type(poFile) == json_type_string )
+                            pszFile = json_object_get_string(poFile);
+
+                        if( pszFile )
+                        {
+                            GMLJP2V2StyleDesc oDesc;
+                            oDesc.osFile = pszFile;
+
+                            json_object* poLocation = json_object_object_get(poStyle, "parent_node");
+                            if( poLocation && json_object_get_type(poLocation) == json_type_string )
+                            {
+                                const char* pszLocation = json_object_get_string(poLocation);
+                                if( EQUAL(pszLocation, "CoverageCollection") )
+                                    oDesc.bParentCoverageCollection  = TRUE;
+                                else if( EQUAL(pszLocation, "GridCoverage") )
+                                    oDesc.bParentCoverageCollection = FALSE;
+                                else
+                                    CPLError(CE_Warning, CPLE_NotSupported,
+                                             "styles[].parent_node should be CoverageCollection or GridCoverage");
+                            }
+
+                            aoStyles.push_back(oDesc);
+                        }
+                    }
+                    else if( poStyle && json_object_get_type(poStyle) == json_type_string )
+                    {
+                        GMLJP2V2StyleDesc oDesc;
+                        oDesc.osFile = json_object_get_string(poStyle);
+                        aoStyles.push_back(oDesc);
+                    }
+                }
+            }
+
+            json_object* poExtensions = json_object_object_get(poRootInstance, "extensions"); 
+            if( poExtensions && json_object_get_type(poExtensions) == json_type_array )
+            {
+                for(int i=0;i<json_object_array_length(poExtensions);i++)
+                {
+                    json_object* poExtension = json_object_array_get_idx(poExtensions, i);
+                    if( poExtension && json_object_get_type(poExtension) == json_type_object )
+                    {
+                        const char* pszFile = NULL;
+                        json_object* poFile = json_object_object_get(poExtension, "file");
+                        if( poFile && json_object_get_type(poFile) == json_type_string )
+                            pszFile = json_object_get_string(poFile);
+
+                        if( pszFile )
+                        {
+                            GMLJP2V2ExtensionDesc oDesc;
+                            oDesc.osFile = pszFile;
+
+                            json_object* poLocation = json_object_object_get(poExtension, "parent_node");
+                            if( poLocation && json_object_get_type(poLocation) == json_type_string )
+                            {
+                                const char* pszLocation = json_object_get_string(poLocation);
+                                if( EQUAL(pszLocation, "CoverageCollection") )
+                                    oDesc.bParentCoverageCollection  = TRUE;
+                                else if( EQUAL(pszLocation, "GridCoverage") )
+                                    oDesc.bParentCoverageCollection = FALSE;
+                                else
+                                    CPLError(CE_Warning, CPLE_NotSupported,
+                                             "extensions[].parent_node should be CoverageCollection or GridCoverage");
+                            }
+
+                            aoExtensions.push_back(oDesc);
+                        }
+                    }
+                    else if( poExtension && json_object_get_type(poExtension) == json_type_string )
+                    {
+                        GMLJP2V2ExtensionDesc oDesc;
+                        oDesc.osFile = json_object_get_string(poExtension);
+                        aoExtensions.push_back(oDesc);
+                    }
+                }
+            }
+        }
+
+        json_object* poBoxes = json_object_object_get(poObj, "boxes"); 
+        if( poBoxes && json_object_get_type(poBoxes) == json_type_array )
+        {
+            for(int i=0;i<json_object_array_length(poBoxes);i++)
+            {
+                json_object* poBox = json_object_array_get_idx(poBoxes, i);
+                if( poBox && json_object_get_type(poBox) == json_type_object )
+                {
+                    json_object* poFile = json_object_object_get(poBox, "file");
+                    if( poFile && json_object_get_type(poFile) == json_type_string )
+                    {
+                        GMLJP2V2BoxDesc oDesc;
+                        oDesc.osFile = json_object_get_string(poFile);
+
+                        json_object* poLabel = json_object_object_get(poBox, "label");
+                        if( poLabel && json_object_get_type(poLabel) == json_type_string )
+                            oDesc.osLabel = json_object_get_string(poLabel);
+                        else
+                            oDesc.osLabel = CPLGetFilename(oDesc.osFile);
+
+                        aoBoxes.push_back(oDesc);
+                    }
+                }
+                else if( poBox && json_object_get_type(poBox) == json_type_string )
+                {
+                    GMLJP2V2BoxDesc oDesc;
+                    oDesc.osFile = json_object_get_string(poBox);
+                    oDesc.osLabel = CPLGetFilename(oDesc.osFile);
+                    aoBoxes.push_back(oDesc);
+                }
+            }
+        }
+
+        json_object_put(poObj);
+
+        // Check that if a GML file points to an internal schemaLocation,
+        // the matching box really exists.
+        for(int i=0;i<(int)aoGMLFiles.size();i++)
+        {
+            if( aoGMLFiles[i].osSchemaLocation.size() &&
+                strncmp(aoGMLFiles[i].osSchemaLocation, "gmljp2://xml/",
+                        strlen("gmljp2://xml/")) == 0 )
+            {
+                const char* pszLookedLabel =
+                    aoGMLFiles[i].osSchemaLocation.c_str() + strlen("gmljp2://xml/");
+                int bFound = FALSE;
+                for(int j=0; !bFound && j<(int)aoBoxes.size();j++)
+                    bFound = (strcmp(pszLookedLabel, aoBoxes[j].osLabel) == 0);
+                if( !bFound )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "GML file %s has a schema_location=%s, but no box with label %s is defined",
+                             aoGMLFiles[i].osFile.c_str(),
+                             aoGMLFiles[i].osSchemaLocation.c_str(),
+                             pszLookedLabel);
+                }
+            }
+        }
+
+        // Read custom grid coverage file
+        if( osGridCoverageFile.size() > 0 )
+        {
+            CPLXMLNode* psTmp = CPLParseXMLFile(osGridCoverageFile);
+            if( psTmp == NULL )
+                return NULL;
+            CPLXMLNode* psTmpRoot = GDALGMLJP2GetXMLRoot(psTmp);
+            if( psTmpRoot )
+            {
+                char* pszTmp = CPLSerializeXMLTree(psTmpRoot);
+                osGridCoverage = pszTmp;
+                CPLFree(pszTmp);
+            }
+            CPLDestroyXMLNode(psTmp);
+        }
+    }
+
+    CPLString osDictBox;
+    CPLString osDoc;
+
+    if( osGridCoverage.size() == 0 )
+    {
+/* -------------------------------------------------------------------- */
+/*      Prepare GMLJP2RectifiedGridCoverage                             */
+/* -------------------------------------------------------------------- */
+        int nEPSGCode = 0;
+        double adfOrigin[2];
+        double adfXVector[2];
+        double adfYVector[2];
+        const char* pszComment = "";   
+        if( !GetGMLJP2GeoreferencingInfo( nEPSGCode, adfOrigin,
+                                        adfXVector, adfYVector,
+                                        pszComment, osDictBox ) )
+        {
+            return NULL;
+        }
+
+        char szSRSName[100] = {0};
+        if( nEPSGCode != 0 )
+        {
+            if( bCRSURL )
+                sprintf( szSRSName, "http://www.opengis.net/def/crs/EPSG/0/%d", nEPSGCode );
+            else
+                sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
+        }
+        else
+            strcpy( szSRSName, 
+                    "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
+
+        osGridCoverage.Printf(
+"   <gmljp2:GMLJP2RectifiedGridCoverage gml:id=\"RGC_1_%s\">\n"
+"     <gml:domainSet>\n"
+"      <gml:RectifiedGrid gml:id=\"RGC_1_GRID_%s\" dimension=\"2\" srsName=\"%s\">\n"
+"       <gml:limits>\n"
+"         <gml:GridEnvelope>\n"
+"           <gml:low>0 0</gml:low>\n"
+"           <gml:high>%d %d</gml:high>\n"
+"         </gml:GridEnvelope>\n"
+"       </gml:limits>\n"
+"       <gml:axisName>x</gml:axisName>\n"
+"       <gml:axisName>y</gml:axisName>\n"
+"       <gml:origin>\n"
+"         <gml:Point gml:id=\"P0001\" srsName=\"%s\">\n"
+"           <gml:pos>%.15g %.15g</gml:pos>\n"
+"         </gml:Point>\n"
+"       </gml:origin>\n"
+"%s"
+"       <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
+"       <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
+"      </gml:RectifiedGrid>\n"
+"     </gml:domainSet>\n"
+"     <gml:rangeSet>\n"
+"      <gml:File>\n"
+"        <gml:rangeParameters/>\n"
+"        <gml:fileName>gmljp2://codestream/0</gml:fileName>\n"
+"        <gml:fileStructure>inapplicable</gml:fileStructure>\n"
+"      </gml:File>\n"
+"     </gml:rangeSet>\n"
+"     <gmlcov:rangeType/>\n"
+"   </gmljp2:GMLJP2RectifiedGridCoverage>\n",
+            osRootGMLId.c_str(),
+            osRootGMLId.c_str(),
+            szSRSName,
+            nXSize-1, nYSize-1, szSRSName, adfOrigin[0], adfOrigin[1],
+            pszComment,
+            szSRSName, adfXVector[0], adfXVector[1], 
+            szSRSName, adfYVector[0], adfYVector[1] );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Main node.                                                      */
+/* -------------------------------------------------------------------- */
+    osDoc.Printf( 
+//"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<gmljp2:GMLJP2CoverageCollection gml:id=\"%s\"\n"
+"     xmlns:gml=\"http://www.opengis.net/gml/3.2\"\n"
+"     xmlns:gmlcov=\"http://www.opengis.net/gmlcov/1.0\"\n"
+"     xmlns:gmljp2=\"http://www.opengis.net/gmljp2/2.0\"\n"
+"     xmlns:swe=\"http://www.opengis.net/swe/2.0\"\n"
+"     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+"     xsi:schemaLocation=\"http://www.opengis.net/gmljp2/2.0 http://schemas.opengis.net/gmljp2/2.0/gmljp2.xsd\">\n"
+"  <gml:gridDomain/>\n"
+"  <gml:rangeSet>\n"
+"   <gml:File>\n"
+"     <gml:rangeParameters/>\n"
+"     <gml:fileName>gmljp2://codestream</gml:fileName>\n"
+"     <gml:fileStructure>inapplicable</gml:fileStructure>\n"
+"   </gml:File>\n"
+"  </gml:rangeSet>\n"
+"  <gmlcov:rangeType/>\n"
+"  <gmljp2:featureMember>\n"
+"%s"
+"  </gmljp2:featureMember>\n"
+"</gmljp2:GMLJP2CoverageCollection>\n",
+                 osRootGMLId.c_str(),
+                 osGridCoverage.c_str() );
+
+/* -------------------------------------------------------------------- */
+/*      Process metadata, annotations and features collections.         */
+/* -------------------------------------------------------------------- */
+    std::vector<CPLString> aosTmpFiles;
+    int bRootHasXLink = FALSE;
+    if( aoMetadata.size() || aoAnnotations.size() || aoGMLFiles.size() ||
+        aoStyles.size() || aoExtensions.size() )
+    {
+        CPLXMLNode* psRoot = CPLParseXMLString(osDoc);
+        CPLAssert(psRoot);
+        CPLXMLNode* psGMLJP2CoverageCollection = GDALGMLJP2GetXMLRoot(psRoot);
+        CPLAssert(psGMLJP2CoverageCollection);
+
+        for( int i=0; i < (int)aoMetadata.size(); i++ )
+        {
+            CPLXMLNode* psMetadata;
+            if( aoMetadata[i].osFile.size() )
+                psMetadata = CPLParseXMLFile(aoMetadata[i].osFile);
+            else if( aoMetadata[i].osContent.size() )
+                psMetadata = CPLParseXMLString(aoMetadata[i].osContent);
+            else if( aoMetadata[i].bGDALMetadata )
+            {
+                psMetadata = CreateGDALMultiDomainMetadataXML(poSrcDS, TRUE);
+                if( psMetadata )
+                {
+                    CPLSetXMLValue(psMetadata, "#xmlns", "http://gdal.org");
+                    CPLXMLNode* psNewMetadata = CPLCreateXMLNode(NULL, CXT_Element, "gmljp2:metadata");
+                    CPLAddXMLChild(psNewMetadata, psMetadata);
+                    psMetadata = psNewMetadata;
+                }
+            }
+            else
+                psMetadata = GDALGMLJP2GenerateMetadata(aoMetadata[i].osTemplateFile,
+                                                        aoMetadata[i].osSourceFile);
+            if( psMetadata == NULL )
+                continue;
+            CPLXMLNode* psMetadataRoot = GDALGMLJP2GetXMLRoot(psMetadata);
+            if( psMetadataRoot )
+            {
+                if( strcmp(psMetadataRoot->pszValue, "eop:EarthObservation") == 0 )
+                {
+                    CPLXMLNode* psNewMetadata = CPLCreateXMLNode(NULL, CXT_Element, "gmljp2:eopMetadata");
+                    CPLAddXMLChild(psNewMetadata, CPLCloneXMLTree(psMetadataRoot));
+                    CPLDestroyXMLNode(psMetadata);
+                    psMetadata = psMetadataRoot = psNewMetadata;
+                }
+                if( strcmp(psMetadataRoot->pszValue, "gmljp2:isoMetadata") != 0 &&
+                    strcmp(psMetadataRoot->pszValue, "gmljp2:eopMetadata") != 0 &&
+                    strcmp(psMetadataRoot->pszValue, "gmljp2:dcMetadata") != 0 &&
+                    strcmp(psMetadataRoot->pszValue, "gmljp2:metadata") != 0 )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "The metadata root node should be one of gmljp2:isoMetadata, "
+                             "gmljp2:eopMetadata, gmljp2:dcMetadata or gmljp2:metadata");
+                }
+                else if( aoMetadata[i].bParentCoverageCollection )
+                {
+                    /*  Insert the gmlcov:metadata link as the next sibbling of */
+                    /* GMLJP2CoverageCollection.rangeType */
+                    CPLXMLNode* psRangeType =
+                        CPLGetXMLNode(psGMLJP2CoverageCollection, "gmlcov:rangeType");
+                    CPLAssert(psRangeType);
+                    CPLXMLNode* psNodeAfterWhichToInsert = psRangeType;
+                    CPLXMLNode* psNext = psNodeAfterWhichToInsert->psNext;
+                    while( psNext != NULL && psNext->eType == CXT_Element &&
+                           strcmp(psNext->pszValue, "gmlcov:metadata") == 0 )
+                    {
+                        psNodeAfterWhichToInsert = psNext;
+                        psNext = psNext->psNext;
+                    }
+                    psNodeAfterWhichToInsert->psNext = NULL;
+                    CPLXMLNode* psGMLCovMetadata = CPLCreateXMLNode(
+                        psGMLJP2CoverageCollection, CXT_Element, "gmlcov:metadata" );
+                    psGMLCovMetadata->psNext = psNext;
+                    CPLXMLNode* psGMLJP2Metadata = CPLCreateXMLNode(
+                        psGMLCovMetadata, CXT_Element, "gmljp2:Metadata" );
+                    CPLAddXMLChild( psGMLJP2Metadata, CPLCloneXMLTree(psMetadataRoot) );
+                }
+                else
+                {
+                    /* Insert the gmlcov:metadata link as the last child of */
+                    /* GMLJP2RectifiedGridCoverage typically */
+                    CPLXMLNode* psFeatureMemberOfGridCoverage =
+                        CPLGetXMLNode(psGMLJP2CoverageCollection, "gmljp2:featureMember");
+                    CPLAssert(psFeatureMemberOfGridCoverage);
+                    CPLXMLNode* psGridCoverage = psFeatureMemberOfGridCoverage->psChild;
+                    CPLAssert(psGridCoverage);
+                    CPLXMLNode* psGMLCovMetadata = CPLCreateXMLNode(
+                        psGridCoverage, CXT_Element, "gmlcov:metadata" );
+                    CPLXMLNode* psGMLJP2Metadata = CPLCreateXMLNode(
+                        psGMLCovMetadata, CXT_Element, "gmljp2:Metadata" );
+                    CPLAddXMLChild( psGMLJP2Metadata, CPLCloneXMLTree(psMetadataRoot) );
+                }
+            }
+            CPLDestroyXMLNode(psMetadata);
+        }
+
+        // Examples of inline or reference feature collections can be found
+        // in http://schemas.opengis.net/gmljp2/2.0/examples/gmljp2.xml
+
+        for( int i=0; i < (int)aoGMLFiles.size(); i++ )
+        {
+            // Is the file already a GML file ?
+            CPLXMLNode* psGMLFile = NULL;
+            if( aoGMLFiles[i].osFile.size() )
+            {
+                if( EQUAL(CPLGetExtension(aoGMLFiles[i].osFile), "gml") ||
+                    EQUAL(CPLGetExtension(aoGMLFiles[i].osFile), "xml") )
+                {
+                    psGMLFile = CPLParseXMLFile(aoGMLFiles[i].osFile);
+                }
+                GDALDriverH hDrv = NULL;
+                if( psGMLFile == NULL )
+                {
+                    hDrv = GDALIdentifyDriver(aoGMLFiles[i].osFile, NULL);
+                    if( hDrv == NULL )
+                    {
+                        CPLError(CE_Failure, CPLE_AppDefined,
+                                "%s is no a GDAL recognized file",
+                                aoGMLFiles[i].osFile.c_str());
+                        continue;
+                    }
+                }
+                GDALDriverH hGMLDrv = GDALGetDriverByName("GML");
+                if( psGMLFile == NULL && hDrv == hGMLDrv )
+                {
+                    // Yes, parse it
+                    psGMLFile = CPLParseXMLFile(aoGMLFiles[i].osFile);
+                }
+                else if( psGMLFile == NULL )
+                {
+                    if( hGMLDrv == NULL )
+                    {
+                        CPLError(CE_Failure, CPLE_AppDefined,
+                                "Cannot translate %s to GML",
+                                aoGMLFiles[i].osFile.c_str());
+                        continue;
+                    }
+
+                    // On-the-fly translation to GML 3.2
+                    GDALDatasetH hSrcDS = GDALOpenEx(aoGMLFiles[i].osFile, 0, NULL, NULL, NULL);
+                    if( hSrcDS )
+                    {
+                        CPLString osTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/%d/%s.gml",
+                                                        this,
+                                                        i,
+                                                        CPLGetBasename(aoGMLFiles[i].osFile));
+                        char* apszOptions[2];
+                        apszOptions[0] = (char*) "FORMAT=GML3.2";
+                        apszOptions[1] = NULL;
+                        GDALDatasetH hDS = GDALCreateCopy(hGMLDrv, osTmpFile, hSrcDS,
+                                                        FALSE, apszOptions, NULL, NULL);
+                        if( hDS )
+                        {
+                            GDALClose(hDS);
+                            psGMLFile = CPLParseXMLFile(osTmpFile);
+                            aoGMLFiles[i].osFile = osTmpFile;
+                            VSIUnlink(osTmpFile);
+                            aosTmpFiles.push_back(CPLResetExtension(osTmpFile, "xsd"));
+                        }
+                        else
+                        {
+                            CPLError(CE_Failure, CPLE_AppDefined,
+                                    "Conversion of %s to GML failed",
+                                    aoGMLFiles[i].osFile.c_str());
+                        }
+                    }
+                    GDALClose(hSrcDS);
+                }
+                if( psGMLFile == NULL )
+                    continue;
+            }
+
+            CPLXMLNode* psGMLFileRoot = psGMLFile ? GDALGMLJP2GetXMLRoot(psGMLFile) : NULL;
+            if( psGMLFileRoot || aoGMLFiles[i].osRemoteResource.size() ) 
+            {
+                CPLXMLNode *node_f;
+                if( aoGMLFiles[i].bParentCoverageCollection )
+                {
+                    // Insert in gmljp2:featureMember.gmljp2:GMLJP2Features.gmljp2:feature
+                    CPLXMLNode *node_fm = CPLCreateXMLNode(
+                            psGMLJP2CoverageCollection, CXT_Element, "gmljp2:featureMember" );
+
+                    CPLXMLNode *node_gf = CPLCreateXMLNode(
+                            node_fm, CXT_Element, "gmljp2:GMLJP2Features" );
+
+
+                    CPLSetXMLValue(node_gf, "#gml:id", CPLSPrintf("%s_GMLJP2Features_%d",
+                                                                    osRootGMLId.c_str(),
+                                                                    i));
+
+                    node_f = CPLCreateXMLNode( node_gf, CXT_Element, "gmljp2:feature"  );
+                }
+                else
+                {
+                    CPLXMLNode* psFeatureMemberOfGridCoverage =
+                        CPLGetXMLNode(psGMLJP2CoverageCollection, "gmljp2:featureMember");
+                    CPLAssert(psFeatureMemberOfGridCoverage);
+                    CPLXMLNode* psGridCoverage = psFeatureMemberOfGridCoverage->psChild;
+                    CPLAssert(psGridCoverage);
+                    node_f = CPLCreateXMLNode( psGridCoverage, CXT_Element, "gmljp2:feature"  );
+                }
+
+                if( !aoGMLFiles[i].bInline || aoGMLFiles[i].osRemoteResource.size() )
+                {
+                    if( !bRootHasXLink )
+                    {
+                        bRootHasXLink = TRUE;
+                        CPLSetXMLValue(psGMLJP2CoverageCollection, "#xmlns:xlink",
+                                       "http://www.w3.org/1999/xlink");
+                    }
+                }
+
+                if( aoGMLFiles[i].osRemoteResource.size() )
+                {
+                    CPLSetXMLValue(node_f, "#xlink:href",
+                                   aoGMLFiles[i].osRemoteResource.c_str());
+                    continue;
+                }
+
+                CPLString osTmpFile;
+                if( !aoGMLFiles[i].bInline || aoGMLFiles[i].osRemoteResource.size() )
+                {
+                    osTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/%d/%s.gml",
+                                           this,
+                                           i,
+                                           CPLGetBasename(aoGMLFiles[i].osFile));
+                    aosTmpFiles.push_back(osTmpFile);
+
+                    GMLJP2V2BoxDesc oDesc;
+                    oDesc.osFile = osTmpFile;
+                    oDesc.osLabel = CPLGetFilename(oDesc.osFile);
+                    aoBoxes.push_back(oDesc);
+
+                    CPLSetXMLValue(node_f, "#xlink:href",
+                            CPLSPrintf("gmljp2://xml/%s", oDesc.osLabel.c_str()));
+                }
+
+                if( CPLGetXMLNode(psGMLFileRoot, "xmlns") == NULL &&
+                    CPLGetXMLNode(psGMLFileRoot, "xmlns:gml") == NULL )
+                {
+                    CPLSetXMLValue(psGMLFileRoot, "#xmlns",
+                                   "http://www.opengis.net/gml/3.2");
+                }
+
+                // modify the gml id making it unique for this document
+                CPLXMLNode* psGMLFileGMLId =
+                    CPLGetXMLNode(psGMLFileRoot, "gml:id");
+                if( psGMLFileGMLId && psGMLFileGMLId->eType == CXT_Attribute )
+                    CPLSetXMLValue( psGMLFileGMLId, "", 
+                                    CPLSPrintf("%s_%d_%s",
+                                                osRootGMLId.c_str(), i,
+                                                psGMLFileGMLId->psChild->pszValue) );
+                psGMLFileGMLId = NULL;
+                //PrefixAllGMLIds(psGMLFileRoot, CPLSPrintf("%s_%d_", osRootGMLId.c_str(), i));
+
+                // replace schema location
+                CPLXMLNode* psSchemaLocation =
+                    CPLGetXMLNode(psGMLFileRoot, "xsi:schemaLocation");
+                if( psSchemaLocation && psSchemaLocation->eType == CXT_Attribute )
+                {
+                    char **papszTokens = CSLTokenizeString2(
+                        psSchemaLocation->psChild->pszValue, " \t\n", 
+                        CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES);
+                    CPLString osSchemaLocation;
+
+                    if( CSLCount(papszTokens) == 2 &&
+                        aoGMLFiles[i].osNamespace.size() == 0 &&
+                        aoGMLFiles[i].osSchemaLocation.size() )
+                    {
+                        osSchemaLocation += papszTokens[0];
+                        osSchemaLocation += " ";
+                        osSchemaLocation += aoGMLFiles[i].osSchemaLocation;
+                    }
+
+                    else if( CSLCount(papszTokens) == 2 &&
+                                (aoGMLFiles[i].osNamespace.size() == 0 ||
+                                strcmp(papszTokens[0], aoGMLFiles[i].osNamespace) == 0) &&
+                                aoGMLFiles[i].osSchemaLocation.size() == 0 )
+                    {
+                        VSIStatBufL sStat;
+                        CPLString osXSD;
+                        if( CSLCount(papszTokens) == 2 &&
+                            !CPLIsFilenameRelative(papszTokens[1]) &&
+                            VSIStatL(papszTokens[1], &sStat) == 0 )
+                        {
+                            osXSD = papszTokens[1];
+                        }
+                        else if( CSLCount(papszTokens) == 2 &&
+                                CPLIsFilenameRelative(papszTokens[1]) &&
+                                VSIStatL(CPLFormFilename(CPLGetDirname(aoGMLFiles[i].osFile),
+                                                        papszTokens[1], NULL),
+                                        &sStat) == 0 )
+                        {
+                            osXSD = CPLFormFilename(CPLGetDirname(aoGMLFiles[i].osFile),
+                                                        papszTokens[1], NULL);
+                        }
+                        if( osXSD.size() )
+                        {
+                            GMLJP2V2BoxDesc oDesc;
+                            oDesc.osFile = osXSD;
+                            oDesc.osLabel = CPLGetFilename(oDesc.osFile);
+                            osSchemaLocation += papszTokens[0];
+                            osSchemaLocation += " ";
+                            osSchemaLocation += "gmljp2://xml/";
+                            osSchemaLocation += oDesc.osLabel;
+                            int j;
+                            for( j=0; j<(int)aoBoxes.size(); j++)
+                            {
+                                if( aoBoxes[j].osLabel == oDesc.osLabel )
+                                    break;
+                            }
+                            if( j == (int)aoBoxes.size() )
+                                aoBoxes.push_back(oDesc);
+                        }
+                    }
+
+                    else if( (CSLCount(papszTokens) % 2) == 0 )
+                    {
+                        for(char** papszIter = papszTokens; *papszIter; papszIter += 2 )
+                        {
+                            if( osSchemaLocation.size() )
+                                osSchemaLocation += " ";
+                            if( aoGMLFiles[i].osNamespace.size() &&
+                                aoGMLFiles[i].osSchemaLocation.size() &&
+                                strcmp(papszIter[0], aoGMLFiles[i].osNamespace) == 0 )
+                            {
+                                osSchemaLocation += papszIter[0];
+                                osSchemaLocation += " ";
+                                osSchemaLocation += aoGMLFiles[i].osSchemaLocation;
+                            }
+                            else
+                            {
+                                osSchemaLocation += papszIter[0];
+                                osSchemaLocation += " ";
+                                osSchemaLocation += papszIter[1];
+                            }
+                        }
+                    }
+                    CSLDestroy(papszTokens);
+                    CPLSetXMLValue( psSchemaLocation, "", osSchemaLocation);
+                }
+
+                if( aoGMLFiles[i].bInline )
+                    CPLAddXMLChild(node_f, CPLCloneXMLTree(psGMLFileRoot));
+                else
+                    CPLSerializeXMLTreeToFile( psGMLFile, osTmpFile );
+            }
+            CPLDestroyXMLNode(psGMLFile);
+        }
+
+        // Cf http://schemas.opengis.net/gmljp2/2.0/examples/gmljp2_annotation.xml
+        for( int i=0; i < (int)aoAnnotations.size(); i++ )
+        {
+            // Is the file already a KML file ?
+            CPLXMLNode* psKMLFile = NULL;
+            if( EQUAL(CPLGetExtension(aoAnnotations[i].osFile), "kml") )
+                 psKMLFile = CPLParseXMLFile(aoAnnotations[i].osFile);
+            GDALDriverH hDrv = NULL;
+            if( psKMLFile == NULL )
+            {
+                hDrv = GDALIdentifyDriver(aoAnnotations[i].osFile, NULL);
+                if( hDrv == NULL )
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined, "%s is no a GDAL recognized file",
+                             aoAnnotations[i].osFile.c_str());
+                    continue;
+                }
+            }
+            GDALDriverH hKMLDrv = GDALGetDriverByName("KML");
+            GDALDriverH hLIBKMLDrv = GDALGetDriverByName("LIBKML");
+            if( psKMLFile == NULL && (hDrv == hKMLDrv || hDrv == hLIBKMLDrv) )
+            {
+                // Yes, parse it
+                psKMLFile = CPLParseXMLFile(aoAnnotations[i].osFile);
+            }
+            else if( psKMLFile == NULL )
+            {
+                if( hKMLDrv == NULL && hLIBKMLDrv == NULL )
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined, "Cannot translate %s to KML",
+                             aoAnnotations[i].osFile.c_str());
+                    continue;
+                }
+
+                // On-the-fly translation to KML
+                GDALDatasetH hSrcDS = GDALOpenEx(aoAnnotations[i].osFile, 0, NULL, NULL, NULL);
+                if( hSrcDS )
+                {
+                    CPLString osTmpFile = CPLSPrintf("/vsimem/gmljp2/%p/%d/%s.kml",
+                                                     this,
+                                                     i,
+                                                     CPLGetBasename(aoAnnotations[i].osFile));
+                    char* apszOptions[2];
+                    apszOptions[0] = NULL;
+                    apszOptions[1] = NULL;
+                    GDALDatasetH hDS = GDALCreateCopy(hLIBKMLDrv ? hLIBKMLDrv : hKMLDrv,
+                                                      osTmpFile, hSrcDS,
+                                                      FALSE, apszOptions, NULL, NULL);
+                    if( hDS )
+                    {
+                        GDALClose(hDS);
+                        psKMLFile = CPLParseXMLFile(osTmpFile);
+                        aoAnnotations[i].osFile = osTmpFile;
+                        VSIUnlink(osTmpFile);
+                    }
+                    else
+                    {
+                        CPLError(CE_Failure, CPLE_AppDefined, "Conversion of %s to KML failed",
+                                  aoAnnotations[i].osFile.c_str());
+                    }
+                }
+                GDALClose(hSrcDS);
+            }
+            if( psKMLFile == NULL )
+                continue;
+
+            CPLXMLNode* psKMLFileRoot = GDALGMLJP2GetXMLRoot(psKMLFile);
+            if( psKMLFileRoot ) 
+            {
+                CPLXMLNode* psFeatureMemberOfGridCoverage =
+                    CPLGetXMLNode(psGMLJP2CoverageCollection, "gmljp2:featureMember");
+                CPLAssert(psFeatureMemberOfGridCoverage);
+                CPLXMLNode* psGridCoverage = psFeatureMemberOfGridCoverage->psChild;
+                CPLAssert(psGridCoverage);
+                CPLXMLNode *psAnnotation = CPLCreateXMLNode(
+                            psGridCoverage, CXT_Element, "gmljp2:annotation" );
+
+                /* Add a xsi:schemaLocation if not already present */
+                if( psKMLFileRoot->eType == CXT_Element &&
+                    strcmp(psKMLFileRoot->pszValue, "kml") == 0 &&
+                    CPLGetXMLNode(psKMLFileRoot, "xsi:schemaLocation") == NULL &&
+                    strcmp(CPLGetXMLValue(psKMLFileRoot, "xmlns", ""),
+                           "http://www.opengis.net/kml/2.2") == 0  )
+                {
+                    CPLSetXMLValue(psKMLFileRoot, "#xsi:schemaLocation",
+                                   "http://www.opengis.net/kml/2.2 http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd");
+                }
+
+                CPLAddXMLChild(psAnnotation, CPLCloneXMLTree(psKMLFileRoot));
+            }
+            CPLDestroyXMLNode(psKMLFile);
+        }
+
+        // Add styles
+        for( int i=0; i < (int)aoStyles.size(); i++ )
+        {
+            CPLXMLNode* psStyle = CPLParseXMLFile(aoStyles[i].osFile);
+            if( psStyle == NULL )
+                continue;
+
+            CPLXMLNode* psStyleRoot = GDALGMLJP2GetXMLRoot(psStyle);
+            if( psStyleRoot ) 
+            {
+                CPLXMLNode *psGMLJP2Style;
+                if( aoStyles[i].bParentCoverageCollection )
+                {
+                    psGMLJP2Style = CPLCreateXMLNode( psGMLJP2CoverageCollection, CXT_Element, "gmljp2:style"  );
+                }
+                else
+                {
+                    CPLXMLNode* psFeatureMemberOfGridCoverage =
+                        CPLGetXMLNode(psGMLJP2CoverageCollection, "gmljp2:featureMember");
+                    CPLAssert(psFeatureMemberOfGridCoverage);
+                    CPLXMLNode* psGridCoverage = psFeatureMemberOfGridCoverage->psChild;
+                    CPLAssert(psGridCoverage);
+                    psGMLJP2Style = CPLCreateXMLNode( psGridCoverage, CXT_Element, "gmljp2:style"  );
+                }
+
+                // Add dummy namespace for validation purposes if needed
+                if( strchr(psStyleRoot->pszValue, ':') == NULL &&
+                    CPLGetXMLValue(psStyleRoot, "xmlns", NULL) == NULL )
+                {
+                    CPLSetXMLValue(psStyleRoot, "#xmlns", "http://undefined_namespace");
+                }
+
+                CPLAddXMLChild( psGMLJP2Style, CPLCloneXMLTree(psStyleRoot) );
+            }
+            CPLDestroyXMLNode(psStyle);
+        }
+
+        // Add extensions
+        for( int i=0; i < (int)aoExtensions.size(); i++ )
+        {
+            CPLXMLNode* psExtension = CPLParseXMLFile(aoExtensions[i].osFile);
+            if( psExtension == NULL )
+                continue;
+
+            CPLXMLNode* psExtensionRoot = GDALGMLJP2GetXMLRoot(psExtension);
+            if( psExtensionRoot ) 
+            {
+                CPLXMLNode *psGMLJP2Extension;
+                if( aoExtensions[i].bParentCoverageCollection )
+                {
+                    psGMLJP2Extension = CPLCreateXMLNode( psGMLJP2CoverageCollection, CXT_Element, "gmljp2:extension"  );
+                }
+                else
+                {
+                    CPLXMLNode* psFeatureMemberOfGridCoverage =
+                        CPLGetXMLNode(psGMLJP2CoverageCollection, "gmljp2:featureMember");
+                    CPLAssert(psFeatureMemberOfGridCoverage);
+                    CPLXMLNode* psGridCoverage = psFeatureMemberOfGridCoverage->psChild;
+                    CPLAssert(psGridCoverage);
+                    psGMLJP2Extension = CPLCreateXMLNode( psGridCoverage, CXT_Element, "gmljp2:extension"  );
+                }
+
+                // Add dummy namespace for validation purposes if needed
+                if( strchr(psExtensionRoot->pszValue, ':') == NULL &&
+                    CPLGetXMLValue(psExtensionRoot, "xmlns", NULL) == NULL )
+                {
+                    CPLSetXMLValue(psExtensionRoot, "#xmlns", "http://undefined_namespace");
+                }
+
+                CPLAddXMLChild( psGMLJP2Extension, CPLCloneXMLTree(psExtensionRoot) );
+            }
+            CPLDestroyXMLNode(psExtension);
+        }
+
+        char* pszRoot = CPLSerializeXMLTree(psRoot);
+        CPLDestroyXMLNode(psRoot);
+        psRoot = NULL;
+        osDoc = pszRoot;
+        CPLFree(pszRoot);
+        pszRoot = NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Setup the gml.data label.                                       */
+/* -------------------------------------------------------------------- */
+    std::vector<GDALJP2Box *> apoGMLBoxes;
+
+    apoGMLBoxes.push_back(GDALJP2Box::CreateLblBox( "gml.data" ));
+
+/* -------------------------------------------------------------------- */
+/*      Setup gml.root-instance.                                        */
+/* -------------------------------------------------------------------- */
+    apoGMLBoxes.push_back(
+        GDALJP2Box::CreateLabelledXMLAssoc( "gml.root-instance", osDoc ));
+
+/* -------------------------------------------------------------------- */
+/*      Add optional dictionary.                                        */
+/* -------------------------------------------------------------------- */
+    if( osDictBox.size() > 0 )
+        apoGMLBoxes.push_back(
+            GDALJP2Box::CreateLabelledXMLAssoc( "CRSDictionary.gml",
+                                                osDictBox ) );
+
+/* -------------------------------------------------------------------- */
+/*      Additional user specified boxes.                                */
+/* -------------------------------------------------------------------- */
+    for( int i=0; i < (int)aoBoxes.size(); i++ )
+    {
+        GByte* pabyContent = NULL;
+        if( VSIIngestFile( NULL, aoBoxes[i].osFile, &pabyContent, NULL, -1 ) )
+        {
+            CPLXMLNode* psNode = CPLParseXMLString((const char*)pabyContent);
+            CPLFree(pabyContent);
+            pabyContent = NULL;
+            if( psNode )
+            {
+                CPLXMLNode* psRoot = GDALGMLJP2GetXMLRoot(psNode);
+                if( psRoot ) 
+                {
+                    GDALGMLJP2PatchFeatureCollectionSubstitutionGroup(psRoot);
+                    pabyContent = (GByte*) CPLSerializeXMLTree(psRoot);
+                    apoGMLBoxes.push_back(
+                        GDALJP2Box::CreateLabelledXMLAssoc( aoBoxes[i].osLabel,
+                                                            (const char*)pabyContent ) );
+                }
+                CPLDestroyXMLNode (psNode);
+            }
+        }
+        CPLFree(pabyContent);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Bundle gml.data boxes into an association.                      */
+/* -------------------------------------------------------------------- */
+    GDALJP2Box *poGMLData = GDALJP2Box::CreateAsocBox( (int)apoGMLBoxes.size(),
+                                                       &apoGMLBoxes[0]);
+
+/* -------------------------------------------------------------------- */
+/*      Cleanup working boxes.                                          */
+/* -------------------------------------------------------------------- */
+    for( int i=0; i < (int)apoGMLBoxes.size(); i++ )
+        delete apoGMLBoxes[i];
+
+    for( int i=0; i < (int)aosTmpFiles.size(); i++ )
+    {
+        VSIUnlink(aosTmpFiles[i]);
+    }
+
+    return poGMLData;
+}
+
+/************************************************************************/
+/*                 CreateGDALMultiDomainMetadataXML()                   */
+/************************************************************************/
+
+CPLXMLNode* GDALJP2Metadata::CreateGDALMultiDomainMetadataXML(
+                                       GDALDataset* poSrcDS,
+                                       int bMainMDDomainOnly )
+{
+    GDALMultiDomainMetadata oLocalMDMD;
+    char** papszSrcMD = CSLDuplicate(poSrcDS->GetMetadata());
+    /* Remove useless metadata */
+    papszSrcMD = CSLSetNameValue(papszSrcMD, GDALMD_AREA_OR_POINT, NULL);
+    papszSrcMD = CSLSetNameValue(papszSrcMD, "TIFFTAG_RESOLUTIONUNIT", NULL);
+    papszSrcMD = CSLSetNameValue(papszSrcMD, "TIFFTAG_XREpsMasterXMLNodeSOLUTION", NULL);
+    papszSrcMD = CSLSetNameValue(papszSrcMD, "TIFFTAG_YRESOLUTION", NULL);
+    papszSrcMD = CSLSetNameValue(papszSrcMD, "Corder", NULL); /* from JP2KAK */
+    if( poSrcDS->GetDriver() != NULL &&
+        EQUAL(poSrcDS->GetDriver()->GetDescription(), "JP2ECW") )
+    {
+        papszSrcMD = CSLSetNameValue(papszSrcMD, "COMPRESSION_RATE_TARGET", NULL);
+        papszSrcMD = CSLSetNameValue(papszSrcMD, "COLORSPACE", NULL);
+        papszSrcMD = CSLSetNameValue(papszSrcMD, "VERSION", NULL);
+    }
+
+    int bHasMD = FALSE;
+    if( papszSrcMD && *papszSrcMD )
+    {
+        bHasMD = TRUE;
+        oLocalMDMD.SetMetadata(papszSrcMD);
+    }
+    CSLDestroy(papszSrcMD);
+
+    if( !bMainMDDomainOnly )
+    {
+        char** papszMDList = poSrcDS->GetMetadataDomainList();
+        for( char** papszMDListIter = papszMDList; 
+            papszMDListIter && *papszMDListIter; ++papszMDListIter )
+        {
+            if( !EQUAL(*papszMDListIter, "") &&
+                !EQUAL(*papszMDListIter, "IMAGE_STRUCTURE") &&
+                !EQUAL(*papszMDListIter, "JPEG2000") &&
+                !EQUALN(*papszMDListIter, "xml:BOX_", strlen("xml:BOX_")) &&
+                !EQUAL(*papszMDListIter, "xml:gml.root-instance") &&
+                !EQUAL(*papszMDListIter, "xml:XMP") &&
+                !EQUAL(*papszMDListIter, "xml:IPR") )
+            {
+                papszSrcMD = poSrcDS->GetMetadata(*papszMDListIter);
+                if( papszSrcMD && *papszSrcMD )
+                {
+                    bHasMD = TRUE;
+                    oLocalMDMD.SetMetadata(papszSrcMD, *papszMDListIter);
+                }
+            }
+        }
+        CSLDestroy(papszMDList);
+    }
 
+    CPLXMLNode* psMasterXMLNode = NULL;
+    if( bHasMD )
+    {
+        CPLXMLNode* psXMLNode = oLocalMDMD.Serialize();
+        psMasterXMLNode = CPLCreateXMLNode( NULL, CXT_Element,
+                                                    "GDALMultiDomainMetadata" );
+        psMasterXMLNode->psChild = psXMLNode;
+    }
+    return psMasterXMLNode;
+}
+
+/************************************************************************/
+/*                CreateGDALMultiDomainMetadataXMLBox()                 */
+/************************************************************************/
+
+GDALJP2Box *GDALJP2Metadata::CreateGDALMultiDomainMetadataXMLBox(
+                                       GDALDataset* poSrcDS,
+                                       int bMainMDDomainOnly )
+{
+    CPLXMLNode* psMasterXMLNode = CreateGDALMultiDomainMetadataXML(
+                                       poSrcDS, bMainMDDomainOnly );
+    if( psMasterXMLNode == NULL )
+        return NULL;
+    char* pszXML = CPLSerializeXMLTree(psMasterXMLNode);
+    CPLDestroyXMLNode(psMasterXMLNode);
+
+    GDALJP2Box* poBox = new GDALJP2Box();
+    poBox->SetType("xml ");
+    poBox->SetWritableData(strlen(pszXML) + 1, (const GByte*)pszXML);
+    CPLFree(pszXML);
+
+    return poBox;
+}
+
+/************************************************************************/
+/*                         WriteXMLBoxes()                              */
+/************************************************************************/
+
+GDALJP2Box** GDALJP2Metadata::CreateXMLBoxes( GDALDataset* poSrcDS,
+                                              int* pnBoxes )
+{
+    GDALJP2Box** papoBoxes = NULL;
+    *pnBoxes = 0;
+    char** papszMDList = poSrcDS->GetMetadataDomainList();
+    for( char** papszMDListIter = papszMDList; 
+        papszMDListIter && *papszMDListIter; ++papszMDListIter )
+    {
+        /* Write metadata that look like originating from JP2 XML boxes */
+        /* as a standalone JP2 XML box */
+        if( EQUALN(*papszMDListIter, "xml:BOX_", strlen("xml:BOX_")) )
+        {
+            char** papszSrcMD = poSrcDS->GetMetadata(*papszMDListIter);
+            if( papszSrcMD && *papszSrcMD )
+            {
+                GDALJP2Box* poBox = new GDALJP2Box();
+                poBox->SetType("xml ");
+                poBox->SetWritableData(strlen(*papszSrcMD) + 1,
+                                       (const GByte*)*papszSrcMD);
+                papoBoxes = (GDALJP2Box**)CPLRealloc(papoBoxes,
+                                        sizeof(GDALJP2Box*) * (*pnBoxes + 1));
+                papoBoxes[(*pnBoxes) ++] = poBox;
+            }
+        }
+    }
+    CSLDestroy(papszMDList);
+    return papoBoxes;
+}
+
+/************************************************************************/
+/*                          CreateXMPBox()                              */
+/************************************************************************/
+
+GDALJP2Box *GDALJP2Metadata::CreateXMPBox ( GDALDataset* poSrcDS )
+{
+    char** papszSrcMD = poSrcDS->GetMetadata("xml:XMP");
+    GDALJP2Box* poBox = NULL;
+    if( papszSrcMD && * papszSrcMD )
+    {
+        poBox = GDALJP2Box::CreateUUIDBox(xmp_uuid,
+                                          strlen(*papszSrcMD) + 1,
+                                          (const GByte*)*papszSrcMD);
+    }
+    return poBox;
+}
+
+/************************************************************************/
+/*                          CreateIPRBox()                              */
+/************************************************************************/
+
+GDALJP2Box *GDALJP2Metadata::CreateIPRBox ( GDALDataset* poSrcDS )
+{
+    char** papszSrcMD = poSrcDS->GetMetadata("xml:IPR");
+    GDALJP2Box* poBox = NULL;
+    if( papszSrcMD && * papszSrcMD )
+    {
+        poBox = new GDALJP2Box();
+        poBox->SetType("jp2i");
+        poBox->SetWritableData(strlen(*papszSrcMD) + 1,
+                                        (const GByte*)*papszSrcMD);
+    }
+    return poBox;
+}
+
+/************************************************************************/
+/*                           IsUUID_MSI()                              */
+/************************************************************************/
+
+int GDALJP2Metadata::IsUUID_MSI(const GByte *abyUUID)
+{
+    return memcmp(abyUUID, msi_uuid2, 16) == 0;
+}
+
+/************************************************************************/
+/*                           IsUUID_XMP()                               */
+/************************************************************************/
+
+int GDALJP2Metadata::IsUUID_XMP(const GByte *abyUUID)
+{
+    return memcmp(abyUUID, xmp_uuid, 16) == 0;
+}
diff --git a/gcore/gdaljp2metadata.h b/gcore/gdaljp2metadata.h
index 6b90a50..e0ff390 100644
--- a/gcore/gdaljp2metadata.h
+++ b/gcore/gdaljp2metadata.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdaljp2metadata.h 27181 2014-04-14 19:32:33Z rouault $
+ * $Id: gdaljp2metadata.h 29054 2015-04-29 19:31:41Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  JP2 Box Reader (and GMLJP2 Interpreter)
@@ -34,6 +34,8 @@
 #include "cpl_conv.h"
 #include "cpl_vsi.h"
 #include "gdal.h"
+#include "gdal_priv.h"
+#include "cpl_minixml.h"
 
 /************************************************************************/
 /*                              GDALJP2Box                              */
@@ -68,7 +70,12 @@ public:
     int         ReadFirstChild( GDALJP2Box *poSuperBox );
     int         ReadNextChild( GDALJP2Box *poSuperBox );
 
+    GIntBig     GetBoxOffset() const { return nBoxOffset; }
+    GIntBig     GetBoxLength() const { return nBoxLength; }
+
+    GIntBig     GetDataOffset() const { return nDataOffset; }
     GIntBig     GetDataLength();
+
     const char *GetType() { return szBoxType; }
     
     GByte      *ReadBoxData();
@@ -84,15 +91,21 @@ public:
     // write support
     void        SetType( const char * );
     void        SetWritableData( int nLength, const GByte *pabyData );
+    void        AppendWritableData( int nLength, const void *pabyDataIn );
+    void        AppendUInt32( GUInt32 nVal );
+    void        AppendUInt16( GUInt16 nVal );
+    void        AppendUInt8( GByte nVal );
     const GByte*GetWritableData() { return pabyData; }
 
     // factory methods.
+    static GDALJP2Box *CreateSuperBox( const char* pszType,
+                                       int nCount, GDALJP2Box **papoBoxes );
     static GDALJP2Box *CreateAsocBox( int nCount, GDALJP2Box **papoBoxes );
     static GDALJP2Box *CreateLblBox( const char *pszLabel );
     static GDALJP2Box *CreateLabelledXMLAssoc( const char *pszLabel,
                                                const char *pszXML );
     static GDALJP2Box *CreateUUIDBox( const GByte *pabyUUID, 
-                                      int nDataSize, GByte *pabyData );
+                                      int nDataSize, const GByte *pabyData );
 };
 
 /************************************************************************/
@@ -113,6 +126,16 @@ private:
 
     int    nMSIGSize;
     GByte  *pabyMSIGData;
+    
+    int      GetGMLJP2GeoreferencingInfo( int& nEPSGCode,
+                                          double adfOrigin[2],
+                                          double adfXVector[2],
+                                          double adfYVector[2],
+                                          const char*& pszComment,
+                                          CPLString& osDictBox );
+    static CPLXMLNode* CreateGDALMultiDomainMetadataXML(
+                                       GDALDataset* poSrcDS,
+                                       int bMainMDDomainOnly );
 
 public:
     char  **papszGMLMetadata;
@@ -125,9 +148,13 @@ public:
 
     int         nGCPCount;
     GDAL_GCP    *pasGCPList;
+    
+    char **papszRPCMD;
 
-    char  **papszMetadata;
+    char  **papszMetadata; /* TIFFTAG_?RESOLUTION* for now from resd box */
     char   *pszXMPMetadata;
+    char   *pszGDALMultiDomainMetadata; /* as serialized XML */
+    char   *pszXMLIPR; /* if an IPR box with XML content has been found */
 
 public:
             GDALJP2Metadata();
@@ -139,15 +166,30 @@ public:
     int     ParseMSIG();
     int     ParseGMLCoverageDesc();
 
+    int     ReadAndParse( VSILFILE * fpVSIL );
     int     ReadAndParse( const char *pszFilename );
 
     // Write oriented. 
     void    SetProjection( const char *pszWKT );
     void    SetGeoTransform( double * );
     void    SetGCPs( int, const GDAL_GCP * );
+    void    SetRPCMD( char** papszRPCMDIn );
     
     GDALJP2Box *CreateJP2GeoTIFF();
     GDALJP2Box *CreateGMLJP2( int nXSize, int nYSize );
+    GDALJP2Box *CreateGMLJP2V2( int nXSize, int nYSize,
+                                const char* pszDefFilename,
+                                GDALDataset* poSrcDS );
+
+    static GDALJP2Box* CreateGDALMultiDomainMetadataXMLBox(
+                                       GDALDataset* poSrcDS,
+                                       int bMainMDDomainOnly );
+    static GDALJP2Box** CreateXMLBoxes( GDALDataset* poSrcDS,
+                                        int* pnBoxes );
+    static GDALJP2Box *CreateXMPBox ( GDALDataset* poSrcDS );
+    static GDALJP2Box *CreateIPRBox ( GDALDataset* poSrcDS );
+    static int   IsUUID_MSI(const GByte *abyUUID);
+    static int   IsUUID_XMP(const GByte *abyUUID);
 };
 
 #endif /* ndef GDAL_JP2READER_H_INCLUDED */
diff --git a/gcore/gdaljp2metadatagenerator.cpp b/gcore/gdaljp2metadatagenerator.cpp
new file mode 100644
index 0000000..9048048
--- /dev/null
+++ b/gcore/gdaljp2metadatagenerator.cpp
@@ -0,0 +1,915 @@
+/******************************************************************************
+ * $Id: gdaljp2metadatagenerator.cpp 29073 2015-04-30 11:38:01Z rouault $
+ *
+ * Project:  GDAL 
+ * Purpose:  GDALJP2Metadata: metadata generator
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, European Union Satellite Centre
+ *
+ * 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.
+ ****************************************************************************/
+
+#include <vector>
+#include "gdaljp2metadatagenerator.h"
+
+CPL_CVSID("$Id: gdaljp2metadatagenerator.cpp 29073 2015-04-30 11:38:01Z rouault $");
+
+//#define ENABLE_BRAIN_DAMAGE
+
+#ifdef HAVE_LIBXML2
+
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+/************************************************************************/
+/*                            GDALGMLJP2Expr                            */
+/************************************************************************/
+
+typedef enum 
+{
+    GDALGMLJP2Expr_Unknown,
+    GDALGMLJP2Expr_XPATH,
+    GDALGMLJP2Expr_STRING_LITERAL,
+#ifdef ENABLE_BRAIN_DAMAGE
+    GDALGMLJP2Expr_NUMERIC_LITERAL,
+    GDALGMLJP2Expr_ADD,
+    GDALGMLJP2Expr_SUB,
+    GDALGMLJP2Expr_NOT,
+    GDALGMLJP2Expr_AND,
+    GDALGMLJP2Expr_OR,
+    GDALGMLJP2Expr_EQ,
+    GDALGMLJP2Expr_NEQ,
+    GDALGMLJP2Expr_LT,
+    GDALGMLJP2Expr_LE,
+    GDALGMLJP2Expr_GT,
+    GDALGMLJP2Expr_GE,
+    GDALGMLJP2Expr_IF,
+    GDALGMLJP2Expr_CONCAT,
+    GDALGMLJP2Expr_EVAL,
+    GDALGMLJP2Expr_CAST_TO_STRING,
+    GDALGMLJP2Expr_CAST_TO_NUMERIC,
+    GDALGMLJP2Expr_SUBSTRING,
+    GDALGMLJP2Expr_SUBSTRING_BEFORE,
+    GDALGMLJP2Expr_SUBSTRING_AFTER,
+    GDALGMLJP2Expr_STRING_LENGTH,
+    GDALGMLJP2Expr_UUID
+#endif
+} GDALGMLJP2ExprType;
+
+// {{{IF(EQ(XPATH(), '5'), '', '')}}}
+
+class GDALGMLJP2Expr
+{
+        static void             SkipSpaces(const char*& pszStr);
+        static GDALGMLJP2Expr*  BuildNaryOp(const char* pszOriStr,
+                                            const char*& pszStr, int nary);
+
+    public:
+        GDALGMLJP2ExprType           eType;
+        CPLString                    osValue;
+#ifdef ENABLE_BRAIN_DAMAGE
+        std::vector<GDALGMLJP2Expr*> apoSubExpr;
+#endif
+
+                                GDALGMLJP2Expr(): eType(GDALGMLJP2Expr_Unknown) {}
+                                GDALGMLJP2Expr(const char* pszVal): eType(GDALGMLJP2Expr_STRING_LITERAL), osValue(pszVal) {}
+                                GDALGMLJP2Expr(CPLString osVal): eType(GDALGMLJP2Expr_STRING_LITERAL), osValue(osVal) {}
+#ifdef ENABLE_BRAIN_DAMAGE
+                                GDALGMLJP2Expr(bool b): eType(GDALGMLJP2Expr_STRING_LITERAL), osValue(b ? "true" : "false") {}
+#endif
+                               ~GDALGMLJP2Expr();
+
+        GDALGMLJP2Expr          Evaluate(xmlXPathContextPtr pXPathCtx,
+                                         xmlDocPtr pDoc);
+
+        static GDALGMLJP2Expr*  Build(const char* pszOriStr,
+                                      const char*& pszStr);
+        static void             ReportError(const char* pszOriStr,
+                                            const char* pszStr,
+                                            const char* pszIntroMessage = "Parsing error at:\n");
+};
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+GDALGMLJP2Expr::~GDALGMLJP2Expr()
+{
+#ifdef ENABLE_BRAIN_DAMAGE
+    for(size_t i=0;i<apoSubExpr.size();i++)
+        delete apoSubExpr[i];
+#endif
+}
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+void GDALGMLJP2Expr::ReportError(const char* pszOriStr,
+                                 const char* pszStr,
+                                 const char* pszIntroMessage)
+{
+    size_t nDist = (size_t)(pszStr - pszOriStr);
+    if( nDist > 40 )
+        nDist = 40;
+    CPLString osErrMsg(pszIntroMessage);
+    CPLString osInvalidExpr = CPLString(pszStr - nDist).substr(0, nDist + 20);
+    for(int i=(int)nDist-1;i>=0;i--)
+    {
+        if( osInvalidExpr[i] == '\n' )
+        {
+            osInvalidExpr = osInvalidExpr.substr(i+1);
+            nDist -= i+1;
+            break;
+        }
+    }
+    for(size_t i=nDist;i<osInvalidExpr.size();i++)
+    {
+        if( osInvalidExpr[i] == '\n' )
+        {
+            osInvalidExpr.resize(i);
+            break;
+        }
+    }
+    osErrMsg += osInvalidExpr;
+    osErrMsg += "\n";
+    for(size_t i=0;i<nDist;i++)
+        osErrMsg += " ";
+    osErrMsg += "^";
+    CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrMsg.c_str());
+}
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+void GDALGMLJP2Expr::SkipSpaces(const char*& pszStr)
+{
+    while( *pszStr == ' ' || *pszStr == '\t' || *pszStr == '\r' || *pszStr ==  '\n' )
+        pszStr ++;
+}
+
+#ifdef ENABLE_BRAIN_DAMAGE
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+GDALGMLJP2Expr* GDALGMLJP2Expr::BuildNaryOp(const char* pszOriStr,
+                                            const char*& pszStr, int nary)
+{
+    GDALGMLJP2Expr* poExpr = new GDALGMLJP2Expr();
+
+    SkipSpaces(pszStr);
+    if( *pszStr != '(' )
+    {
+        ReportError(pszOriStr, pszStr);
+        delete poExpr;
+        return NULL;
+    }
+    pszStr ++;
+    SkipSpaces(pszStr);
+    for( int i=0;nary < 0 || i<nary;i++)
+    {
+        GDALGMLJP2Expr* poSubExpr = Build(pszOriStr, pszStr);
+        if( poSubExpr == NULL )
+        {
+            delete poExpr;
+            return NULL;
+        }
+        SkipSpaces(pszStr);
+        poExpr->apoSubExpr.push_back(poSubExpr);
+        if( nary < 0 && *pszStr == ')' )
+        {
+            break;
+        }
+        else if( nary < 0 || i < nary - 1 )
+        {
+            if( *pszStr != ',' )
+            {
+                ReportError(pszOriStr, pszStr);
+                delete poExpr;
+                return NULL;
+            }
+            pszStr ++;
+            SkipSpaces(pszStr);
+        }
+    }
+    if( *pszStr != ')' )
+    {
+        ReportError(pszOriStr, pszStr);
+        delete poExpr;
+        return NULL;
+    }
+    pszStr ++;
+    return poExpr;
+}
+
+#endif // ENABLE_BRAIN_DAMAGE
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+#ifdef ENABLE_BRAIN_DAMAGE
+
+typedef struct
+{
+    const char*        pszOp;
+    GDALGMLJP2ExprType eType;
+    int                nary;
+} GDALGMLJP2Operators;
+
+#endif
+
+GDALGMLJP2Expr* GDALGMLJP2Expr::Build(const char* pszOriStr,
+                                      const char*& pszStr)
+{
+    if( EQUALN(pszStr, "{{{", strlen("{{{")) )
+    {
+        pszStr += strlen("{{{");
+        SkipSpaces(pszStr);
+        GDALGMLJP2Expr* poExpr = Build(pszOriStr, pszStr);
+        if( poExpr == NULL )
+            return NULL;
+        SkipSpaces(pszStr);
+        if( !EQUALN(pszStr, "}}}", strlen("}}}")) )
+        {
+            ReportError(pszOriStr, pszStr);
+            delete poExpr;
+            return NULL;
+        }
+        pszStr += strlen("}}}");
+        return poExpr;
+    }
+    else if( EQUALN(pszStr, "XPATH", strlen("XPATH")) )
+    {
+        pszStr += strlen("XPATH");
+        SkipSpaces(pszStr);
+        if( *pszStr != '(' )
+        {
+            ReportError(pszOriStr, pszStr);
+            return NULL;
+        }
+        pszStr ++;
+        SkipSpaces(pszStr);
+        CPLString osValue;
+        int nParenthesisIndent = 0;
+        char chLiteralQuote = '\0';
+        while( *pszStr )
+        {
+            if( chLiteralQuote != '\0' )
+            {
+                if( *pszStr == chLiteralQuote )
+                    chLiteralQuote = '\0';
+                osValue += *pszStr;
+                pszStr++;
+            }
+            else if( *pszStr == '\'' || *pszStr == '"' )
+            {
+                chLiteralQuote = *pszStr;
+                osValue += *pszStr;
+                pszStr++;
+            }
+            else if( *pszStr == '(' )
+            {
+                nParenthesisIndent ++;
+                osValue += *pszStr;
+                pszStr++;
+            }
+            else if( *pszStr == ')' )
+            {
+                nParenthesisIndent --;
+                if( nParenthesisIndent < 0 )
+                {
+                    pszStr++;
+                    GDALGMLJP2Expr* poExpr = new GDALGMLJP2Expr();
+                    poExpr->eType = GDALGMLJP2Expr_XPATH;
+                    poExpr->osValue = osValue;
+                    //CPLDebug("GMLJP2", "XPath expression '%s'", osValue.c_str());
+                    return poExpr;
+                }
+                osValue += *pszStr;
+                pszStr++;
+            }
+            else
+            {
+                osValue += *pszStr;
+                pszStr++;
+            }
+        }
+        ReportError(pszOriStr, pszStr);
+        return NULL;
+    }
+#ifdef ENABLE_BRAIN_DAMAGE
+    else if( pszStr[0] == '\'' )
+    {
+        pszStr ++;
+        CPLString osValue;
+        while( *pszStr )
+        {
+            if( *pszStr == '\\' )
+            {
+                if( pszStr[1] == '\\' )
+                    osValue += "\\";
+                else if( pszStr[1] == '\'' )
+                    osValue += "\'";
+                else
+                {
+                    ReportError(pszOriStr, pszStr);
+                    return NULL;
+                }
+                pszStr += 2;
+            }
+            else if( *pszStr == '\'' )
+            {
+                pszStr ++;
+                GDALGMLJP2Expr* poExpr = new GDALGMLJP2Expr();
+                poExpr->eType = GDALGMLJP2Expr_STRING_LITERAL;
+                poExpr->osValue = osValue;
+                return poExpr;
+            }
+            else
+            {
+                osValue += *pszStr;
+                pszStr ++;
+            }
+        }
+        ReportError(pszOriStr, pszStr);
+        return NULL;
+    }
+    else if( pszStr[0] == '-' || pszStr[0] == '.'||
+             (pszStr[0] >= '0' && pszStr[0] <= '9') )
+    {
+        CPLString osValue;
+        while( *pszStr )
+        {
+            if( *pszStr == ' ' || *pszStr == ')' || *pszStr == ',' || *pszStr == '}' )
+            {
+                GDALGMLJP2Expr* poExpr = new GDALGMLJP2Expr();
+                poExpr->eType = GDALGMLJP2Expr_NUMERIC_LITERAL;
+                poExpr->osValue = osValue;
+                return poExpr;
+            }
+            osValue += *pszStr;
+            pszStr ++;
+        }
+        ReportError(pszOriStr, pszStr);
+        return NULL;
+    }
+    else
+    {
+        static const GDALGMLJP2Operators asOperators[] =
+        {
+            { "IF", GDALGMLJP2Expr_IF, 3 },
+            { "ADD", GDALGMLJP2Expr_ADD, 2 },
+            { "AND", GDALGMLJP2Expr_AND, 2 },
+            { "OR", GDALGMLJP2Expr_OR, 2 },
+            { "NOT", GDALGMLJP2Expr_NOT, 1 },
+            { "EQ", GDALGMLJP2Expr_EQ, 2 },
+            { "NEQ", GDALGMLJP2Expr_NEQ, 2 },
+            { "LT", GDALGMLJP2Expr_LT, 2 },
+            { "LE", GDALGMLJP2Expr_LE, 2 },
+            { "GT", GDALGMLJP2Expr_GT, 2 },
+            { "GE", GDALGMLJP2Expr_GE, 2 },
+            { "CONCAT", GDALGMLJP2Expr_CONCAT, -1 },
+            { "NUMERIC", GDALGMLJP2Expr_CAST_TO_NUMERIC, 1 },
+            { "STRING_LENGTH", GDALGMLJP2Expr_STRING_LENGTH, 1 },
+            { "STRING", GDALGMLJP2Expr_CAST_TO_STRING, 1 }, /* must be after */
+            { "SUBSTRING_BEFORE", GDALGMLJP2Expr_SUBSTRING_BEFORE, 2 },
+            { "SUBSTRING_AFTER", GDALGMLJP2Expr_SUBSTRING_AFTER, 2 },
+            { "SUBSTRING", GDALGMLJP2Expr_SUBSTRING, 3 }, /* must be after */
+            { "SUB", GDALGMLJP2Expr_SUB, 2 }, /* must be after */
+            { "UUID", GDALGMLJP2Expr_UUID, 0},
+            { "EVAL", GDALGMLJP2Expr_EVAL, 1}
+        };
+        for(size_t i=0; i<sizeof(asOperators)/sizeof(asOperators[0]);i++)
+        {
+            const char* pszOp = asOperators[i].pszOp;
+            if( EQUALN(pszStr, pszOp, strlen(pszOp)) )
+            {
+                pszStr += strlen(pszOp);
+                GDALGMLJP2Expr* poExpr = BuildNaryOp(pszOriStr, pszStr, asOperators[i].nary);
+                if( poExpr )
+                {
+                    if( asOperators[i].eType == GDALGMLJP2Expr_NEQ )
+                    {
+                        poExpr->eType = GDALGMLJP2Expr_EQ;
+                        GDALGMLJP2Expr* poTopExpr = new GDALGMLJP2Expr();
+                        poTopExpr->eType = GDALGMLJP2Expr_NOT;
+                        poTopExpr->apoSubExpr.push_back(poExpr);
+                        poExpr = poTopExpr;
+                    }
+                    else if( asOperators[i].eType == GDALGMLJP2Expr_GT )
+                    {
+                        poExpr->eType = GDALGMLJP2Expr_LE;
+                        GDALGMLJP2Expr* poTopExpr = new GDALGMLJP2Expr();
+                        poTopExpr->eType = GDALGMLJP2Expr_NOT;
+                        poTopExpr->apoSubExpr.push_back(poExpr);
+                        poExpr = poTopExpr;
+                    }
+                    else if( asOperators[i].eType == GDALGMLJP2Expr_GE )
+                    {
+                        poExpr->eType = GDALGMLJP2Expr_LT;
+                        GDALGMLJP2Expr* poTopExpr = new GDALGMLJP2Expr();
+                        poTopExpr->eType = GDALGMLJP2Expr_NOT;
+                        poTopExpr->apoSubExpr.push_back(poExpr);
+                        poExpr = poTopExpr;
+                    }
+                    else
+                        poExpr->eType = asOperators[i].eType;
+                }
+                return poExpr;
+            }
+        }
+        ReportError(pszOriStr, pszStr);
+        return NULL;
+    }
+#else
+    else
+    {
+        ReportError(pszOriStr, pszStr);
+        return NULL;
+    }
+#endif
+}
+
+/************************************************************************/
+/*                       GDALGMLJP2HexFormatter()                       */
+/************************************************************************/
+
+static const char* GDALGMLJP2HexFormatter(GByte nVal)
+{
+    return CPLSPrintf("%02X", nVal);
+}
+
+/************************************************************************/
+/*                            Evaluate()                                */
+/************************************************************************/
+
+static CPLString GDALGMLJP2EvalExpr(const CPLString& osTemplate,
+                                    xmlXPathContextPtr pXPathCtx,
+                                    xmlDocPtr pDoc);
+
+GDALGMLJP2Expr GDALGMLJP2Expr::Evaluate(xmlXPathContextPtr pXPathCtx,
+                                   xmlDocPtr pDoc)
+{
+    switch(eType)
+    {
+#ifdef ENABLE_BRAIN_DAMAGE
+        case GDALGMLJP2Expr_STRING_LITERAL:
+        case GDALGMLJP2Expr_NUMERIC_LITERAL:
+            return *this;
+#endif
+
+        case GDALGMLJP2Expr_XPATH:
+        {
+            xmlXPathObjectPtr pXPathObj = xmlXPathEvalExpression(
+                    (const xmlChar*)osValue.c_str(), pXPathCtx);
+            if( pXPathObj == NULL )
+                return GDALGMLJP2Expr("");
+
+            // Add result of the evaluation
+            CPLString osXMLRes;
+            if( pXPathObj->type == XPATH_STRING )
+                osXMLRes = (const char*)pXPathObj->stringval;
+            else if( pXPathObj->type == XPATH_BOOLEAN )
+                osXMLRes = pXPathObj->boolval ? "true" : "false";
+            else if( pXPathObj->type == XPATH_NUMBER )
+                osXMLRes = CPLSPrintf("%.16g", pXPathObj->floatval);
+            else if( pXPathObj->type == XPATH_NODESET )
+            {
+                xmlNodeSetPtr pNodes = pXPathObj->nodesetval;
+                int nNodes = (pNodes) ? pNodes->nodeNr : 0;
+                for(int i=0;i<nNodes;i++)
+                {
+                    xmlNodePtr pCur = pNodes->nodeTab[i];
+
+                    xmlBufferPtr pBuf = xmlBufferCreate();
+                    xmlNodeDump(pBuf, pDoc, pCur, 2, 1);
+                    osXMLRes += (const char*)xmlBufferContent(pBuf);
+                    xmlBufferFree(pBuf);
+                }
+            }
+
+            xmlXPathFreeObject(pXPathObj);
+            return GDALGMLJP2Expr(osXMLRes);
+        }
+#ifdef ENABLE_BRAIN_DAMAGE
+        case GDALGMLJP2Expr_AND:
+        {
+            return GDALGMLJP2Expr(
+                apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue == "true" &&
+                apoSubExpr[1]->Evaluate(pXPathCtx,pDoc).osValue == "true" );
+        }
+
+        case GDALGMLJP2Expr_OR:
+        {
+            return GDALGMLJP2Expr(
+                apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue == "true" ||
+                apoSubExpr[1]->Evaluate(pXPathCtx,pDoc).osValue == "true" );
+        }
+
+        case GDALGMLJP2Expr_NOT:
+        {
+            return GDALGMLJP2Expr(
+                apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue != "true");
+        }
+
+        case GDALGMLJP2Expr_ADD:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            GDALGMLJP2Expr oExpr(CPLSPrintf("%.16g", CPLAtof(oExpr1.osValue) + CPLAtof(oExpr2.osValue)));
+            oExpr.eType = GDALGMLJP2Expr_NUMERIC_LITERAL;
+            return oExpr;
+        }
+
+        case GDALGMLJP2Expr_SUB:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            GDALGMLJP2Expr oExpr(CPLSPrintf("%.16g", CPLAtof(oExpr1.osValue) - CPLAtof(oExpr2.osValue)));
+            oExpr.eType = GDALGMLJP2Expr_NUMERIC_LITERAL;
+            return oExpr;
+        }
+
+        case GDALGMLJP2Expr_EQ:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            bool bRes;
+            if( oExpr1.eType == GDALGMLJP2Expr_NUMERIC_LITERAL &&
+                oExpr2.eType == GDALGMLJP2Expr_NUMERIC_LITERAL )
+            {
+                bRes = ( CPLAtof(oExpr1.osValue) == CPLAtof(oExpr2.osValue) );
+            }
+            else
+            {
+                bRes = (oExpr1.osValue == oExpr2.osValue );
+            }
+            return GDALGMLJP2Expr(bRes);
+        }
+
+        case GDALGMLJP2Expr_LT:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            bool bRes;
+            if( oExpr1.eType == GDALGMLJP2Expr_NUMERIC_LITERAL &&
+                oExpr2.eType == GDALGMLJP2Expr_NUMERIC_LITERAL )
+            {
+                bRes = ( CPLAtof(oExpr1.osValue) < CPLAtof(oExpr2.osValue) );
+            }
+            else
+            {
+                bRes = (oExpr1.osValue < oExpr2.osValue );
+            }
+            return GDALGMLJP2Expr(bRes);
+        }
+
+        case GDALGMLJP2Expr_LE:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            bool bRes;
+            if( oExpr1.eType == GDALGMLJP2Expr_NUMERIC_LITERAL &&
+                oExpr2.eType == GDALGMLJP2Expr_NUMERIC_LITERAL )
+            {
+                bRes = ( CPLAtof(oExpr1.osValue) <= CPLAtof(oExpr2.osValue) );
+            }
+            else
+            {
+                bRes = (oExpr1.osValue <= oExpr2.osValue );
+            }
+            return GDALGMLJP2Expr(bRes);
+        }
+
+        case GDALGMLJP2Expr_IF:
+        {
+            if( apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue == "true" )
+                return apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            else
+                return apoSubExpr[2]->Evaluate(pXPathCtx,pDoc);
+        }
+
+        case GDALGMLJP2Expr_EVAL:
+        {
+            return GDALGMLJP2Expr(
+                GDALGMLJP2EvalExpr(apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue,pXPathCtx,pDoc));
+        }
+
+        case GDALGMLJP2Expr_CONCAT:
+        {
+            CPLString osRet;
+            for(size_t i=0;i<apoSubExpr.size();i++)
+                osRet += apoSubExpr[i]->Evaluate(pXPathCtx,pDoc).osValue;
+            return GDALGMLJP2Expr(osRet);
+        }
+
+        case GDALGMLJP2Expr_CAST_TO_NUMERIC:
+        {
+            GDALGMLJP2Expr oExpr = CPLSPrintf("%.16g", CPLAtof(apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue));
+            oExpr.eType = GDALGMLJP2Expr_NUMERIC_LITERAL;
+            return oExpr;
+        }
+
+        case GDALGMLJP2Expr_CAST_TO_STRING:
+        {
+            GDALGMLJP2Expr oExpr = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue;
+            oExpr.eType = GDALGMLJP2Expr_STRING_LITERAL;
+            return oExpr;
+        }
+        
+        case GDALGMLJP2Expr_UUID:
+        {
+            CPLString osRet;
+            static int nCounter = 0;
+            srand((unsigned int)time(NULL) + nCounter);
+            nCounter ++;
+            for( int i=0; i<4; i ++ )
+                osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            osRet += "-";
+            osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            osRet += "-";
+            osRet += GDALGMLJP2HexFormatter((rand() & 0x0F) | 0x40); // set the version number bits (4 == random)
+            osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            osRet += "-";
+            osRet += GDALGMLJP2HexFormatter((rand() & 0x3F) | 0x80); // set the variant bits
+            osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            osRet += "-";
+            for( int i=0; i<6; i ++ )
+                osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+            return GDALGMLJP2Expr(osRet);
+        }
+        
+        case GDALGMLJP2Expr_STRING_LENGTH:
+        {
+            GDALGMLJP2Expr oExpr(CPLSPrintf("%d",
+                (int)strlen(apoSubExpr[0]->Evaluate(pXPathCtx,pDoc).osValue)));
+            oExpr.eType = GDALGMLJP2Expr_NUMERIC_LITERAL;
+            return oExpr;
+        }
+
+        case GDALGMLJP2Expr_SUBSTRING:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr3 = apoSubExpr[2]->Evaluate(pXPathCtx,pDoc);
+            int nStart = atoi(oExpr2.osValue);
+            int nLen = atoi(oExpr3.osValue);
+            nStart --; /* from XPath/SQL convention to C convention */
+            if( nStart < 0 )
+            {
+                nLen += nStart;
+                nStart = 0;
+            }
+            if( nLen < 0 )
+                return GDALGMLJP2Expr("");
+            if( nStart >= (int)oExpr1.osValue.size() )
+                return GDALGMLJP2Expr("");
+            if( nStart + nLen > (int)oExpr1.osValue.size() )
+                nLen = (int)oExpr1.osValue.size() - nStart;
+            return GDALGMLJP2Expr(oExpr1.osValue.substr(nStart, nLen));
+        }
+
+        case GDALGMLJP2Expr_SUBSTRING_BEFORE:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            size_t nPos = oExpr1.osValue.find(oExpr2.osValue);
+            if( nPos == std::string::npos )
+                return GDALGMLJP2Expr("");
+            return GDALGMLJP2Expr(oExpr1.osValue.substr(0, nPos));
+        }
+
+        case GDALGMLJP2Expr_SUBSTRING_AFTER:
+        {
+            const GDALGMLJP2Expr& oExpr1 = apoSubExpr[0]->Evaluate(pXPathCtx,pDoc);
+            const GDALGMLJP2Expr& oExpr2 = apoSubExpr[1]->Evaluate(pXPathCtx,pDoc);
+            size_t nPos = oExpr1.osValue.find(oExpr2.osValue);
+            if( nPos == std::string::npos )
+                return GDALGMLJP2Expr("");
+            return GDALGMLJP2Expr(oExpr1.osValue.substr(nPos + oExpr2.osValue.size()));
+        }
+#endif
+        default:
+            CPLAssert(FALSE);
+            return GDALGMLJP2Expr("");
+    }
+}
+
+/************************************************************************/
+/*                        GDALGMLJP2EvalExpr()                          */
+/************************************************************************/
+
+static CPLString GDALGMLJP2EvalExpr(const CPLString& osTemplate,
+                                    xmlXPathContextPtr pXPathCtx,
+                                    xmlDocPtr pDoc)
+{
+    CPLString osXMLRes;
+    size_t nPos = 0;
+    while( TRUE )
+    {
+        // Get next expression
+        size_t nStartPos = osTemplate.find("{{{", nPos);
+        if( nStartPos == std::string::npos)
+        {
+            // Add terminating portion of the template
+            osXMLRes += osTemplate.substr(nPos);
+            break;
+        }
+
+        // Add portion of template before the expression
+        osXMLRes += osTemplate.substr(nPos, nStartPos - nPos);
+        
+        const char* pszExpr = osTemplate.c_str() + nStartPos;
+        GDALGMLJP2Expr* poExpr = GDALGMLJP2Expr::Build(pszExpr, pszExpr);
+        if( poExpr == NULL )
+            break;
+        nPos = (size_t)(pszExpr - osTemplate.c_str());
+        osXMLRes += poExpr->Evaluate(pXPathCtx,pDoc).osValue;
+        delete poExpr;
+    }
+    return osXMLRes;
+}
+
+/************************************************************************/
+/*                      GDALGMLJP2XPathErrorHandler()                   */
+/************************************************************************/
+
+static void GDALGMLJP2XPathErrorHandler(CPL_UNUSED void * userData, 
+                                        xmlErrorPtr error)
+{
+    if( error->domain == XML_FROM_XPATH &&
+        error->str1 != NULL &&
+        error->int1 < (int)strlen(error->str1) )
+    {
+        GDALGMLJP2Expr::ReportError(error->str1,
+                                    error->str1 + error->int1,
+                                    "XPath error:\n");
+    }
+    else
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "An error occured in libxml2");
+    }
+}
+
+/************************************************************************/
+/*                    GDALGMLJP2RegisterNamespaces()                    */
+/************************************************************************/
+
+static void GDALGMLJP2RegisterNamespaces(xmlXPathContextPtr pXPathCtx,
+                                         xmlNode* pNode)
+{
+    for(; pNode; pNode = pNode->next)
+    {
+        if( pNode->type == XML_ELEMENT_NODE)
+        {
+            if( pNode->ns != NULL && pNode->ns->prefix != NULL )
+            {
+                //printf("%s %s\n",pNode->ns->prefix, pNode->ns->href);
+                if(xmlXPathRegisterNs(pXPathCtx, pNode->ns->prefix, pNode->ns->href) != 0)
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Registration of namespace %s failed",
+                             (const char*)pNode->ns->prefix);
+                }
+            }
+        }
+
+        GDALGMLJP2RegisterNamespaces(pXPathCtx, pNode->children);
+    }
+}
+
+/************************************************************************/
+/*                         GDALGMLJP2XPathIf()                          */
+/************************************************************************/
+
+static void GDALGMLJP2XPathIf(xmlXPathParserContextPtr ctxt, int nargs)
+{
+    xmlXPathObjectPtr cond_val,then_val,else_val;
+
+    CHECK_ARITY(3);
+    else_val = valuePop(ctxt);
+    then_val = valuePop(ctxt);
+    CAST_TO_BOOLEAN
+    cond_val = valuePop(ctxt);
+
+    if( cond_val->boolval )
+    {
+        xmlXPathFreeObject(else_val);
+        valuePush(ctxt, then_val);
+    }
+    else
+    {
+        xmlXPathFreeObject(then_val);
+        valuePush(ctxt, else_val);
+    }
+    xmlXPathFreeObject(cond_val);
+}
+
+/************************************************************************/
+/*                        GDALGMLJP2XPathUUID()                         */
+/************************************************************************/
+
+static void GDALGMLJP2XPathUUID(xmlXPathParserContextPtr ctxt, int nargs)
+{
+    CHECK_ARITY(0);
+
+    CPLString osRet;
+    static int nCounter = 0;
+    srand((unsigned int)time(NULL) + nCounter);
+    nCounter ++;
+    for( int i=0; i<4; i ++ )
+        osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+    osRet += "-";
+    osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+    osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+    osRet += "-";
+    osRet += GDALGMLJP2HexFormatter((rand() & 0x0F) | 0x40); // set the version number bits (4 == random)
+    osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+    osRet += "-";
+    osRet += GDALGMLJP2HexFormatter((rand() & 0x3F) | 0x80); // set the variant bits
+    osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+    osRet += "-";
+    for( int i=0; i<6; i ++ )
+        osRet += GDALGMLJP2HexFormatter(rand() & 0xFF);
+
+    valuePush(ctxt, xmlXPathNewString((const xmlChar*)osRet.c_str()));
+}
+
+#endif /* defined(LIBXML2) */
+
+/************************************************************************/
+/*                      GDALGMLJP2GenerateMetadata()                    */
+/************************************************************************/
+
+CPLXMLNode* GDALGMLJP2GenerateMetadata(const CPLString& osTemplateFile,
+                                       const CPLString& osSourceFile)
+{
+#ifndef HAVE_LIBXML2
+    return NULL;
+#else
+    GByte* pabyStr = NULL;
+    if( !VSIIngestFile( NULL, osTemplateFile, &pabyStr, NULL, -1 ) )
+        return NULL;
+    CPLString osTemplate((const char*)pabyStr);
+    CPLFree(pabyStr);
+    
+    if( !VSIIngestFile( NULL, osSourceFile, &pabyStr, NULL, -1 ) )
+        return NULL;
+    CPLString osSource((const char*)pabyStr);
+    CPLFree(pabyStr);
+    
+    xmlDocPtr pDoc = xmlParseDoc((const xmlChar *)osSource.c_str());
+    if( pDoc == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot parse %s",
+                 osSourceFile.c_str());
+        return NULL;
+    }
+
+    xmlXPathContextPtr pXPathCtx = xmlXPathNewContext(pDoc);
+    if( pXPathCtx == NULL )
+    {
+        xmlFreeDoc(pDoc); 
+        return NULL;
+    }
+
+    xmlXPathRegisterFunc(pXPathCtx, (const xmlChar *)"if", GDALGMLJP2XPathIf);
+    xmlXPathRegisterFunc(pXPathCtx, (const xmlChar *)"uuid", GDALGMLJP2XPathUUID);
+
+    pXPathCtx->error = GDALGMLJP2XPathErrorHandler;
+    
+    GDALGMLJP2RegisterNamespaces(pXPathCtx, xmlDocGetRootElement(pDoc));
+
+    CPLString osXMLRes = GDALGMLJP2EvalExpr(osTemplate, pXPathCtx, pDoc);
+
+    xmlXPathFreeContext(pXPathCtx); 
+    xmlFreeDoc(pDoc); 
+
+    return CPLParseXMLString(osXMLRes);
+#endif
+}
diff --git a/gcore/gdaljp2metadatagenerator.h b/gcore/gdaljp2metadatagenerator.h
new file mode 100644
index 0000000..79b5df8
--- /dev/null
+++ b/gcore/gdaljp2metadatagenerator.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ * $Id: gdaljp2metadatagenerator.h 29048 2015-04-29 14:48:33Z rouault $
+ *
+ * Project:  GDAL 
+ * Purpose:  GDALJP2Metadata: metadata generator
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, European Union Satellite Centre
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef GDAL_JP2METADATA_GENERATOR_H_INCLUDED
+#define GDAL_JP2METADATA_GENERATOR_H_INCLUDED
+
+
+#include "cpl_string.h"
+#include "cpl_minixml.h"
+
+CPLXMLNode* GDALGMLJP2GenerateMetadata(const CPLString& osTemplateFile,
+                                       const CPLString& osSourceFile);
+
+#endif /* GDAL_JP2METADATA_GENERATOR_H_INCLUDED */
diff --git a/gcore/gdaljp2structure.cpp b/gcore/gdaljp2structure.cpp
new file mode 100644
index 0000000..526027e
--- /dev/null
+++ b/gcore/gdaljp2structure.cpp
@@ -0,0 +1,1425 @@
+/******************************************************************************
+ * $Id: gdaljp2structure.cpp 28766 2015-03-24 23:32:21Z rouault $
+ *
+ * Project:  GDAL 
+ * Purpose:  GDALJP2Stucture - Dump structure of a JP2/J2K file
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, European Union (European Environment Agency)
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdaljp2metadata.h"
+
+static void AddField(CPLXMLNode* psParent, const char* pszFieldName,
+                     int nFieldSize, const char* pszValue,
+                     const char* pszDescription = NULL)
+{
+    CPLXMLNode* psField = CPLCreateXMLElementAndValue(
+                                    psParent, "Field", pszValue );
+    CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
+    CPLAddXMLAttributeAndValue(psField, "type", "string" );
+    CPLAddXMLAttributeAndValue(psField, "size", CPLSPrintf("%d", nFieldSize )  );
+    if( pszDescription )
+        CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
+}
+
+static void AddHexField(CPLXMLNode* psParent, const char* pszFieldName,
+                        int nFieldSize, const char* pszValue,
+                        const char* pszDescription = NULL)
+{
+    CPLXMLNode* psField = CPLCreateXMLElementAndValue(
+                                    psParent, "Field", pszValue );
+    CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
+    CPLAddXMLAttributeAndValue(psField, "type", "hexint" );
+    CPLAddXMLAttributeAndValue(psField, "size", CPLSPrintf("%d", nFieldSize )  );
+    if( pszDescription )
+        CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
+}
+
+static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GByte nVal,
+                     const char* pszDescription = NULL)
+{
+    CPLXMLNode* psField = CPLCreateXMLElementAndValue(
+                                psParent, "Field", CPLSPrintf("%d", nVal) );
+    CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
+    CPLAddXMLAttributeAndValue(psField, "type", "uint8" );
+    if( pszDescription )
+        CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
+}
+
+static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GUInt16 nVal,
+                     const char* pszDescription = NULL)
+{
+    CPLXMLNode* psField = CPLCreateXMLElementAndValue(
+                                psParent, "Field", CPLSPrintf("%d", nVal) );
+    CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
+    CPLAddXMLAttributeAndValue(psField, "type", "uint16" );
+    if( pszDescription )
+        CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
+}
+
+static void AddField(CPLXMLNode* psParent, const char* pszFieldName, GUInt32 nVal,
+                     const char* pszDescription = NULL)
+{
+    CPLXMLNode* psField = CPLCreateXMLElementAndValue(
+                                psParent, "Field", CPLSPrintf("%u", nVal) );
+    CPLAddXMLAttributeAndValue(psField, "name", pszFieldName );
+    CPLAddXMLAttributeAndValue(psField, "type", "uint32" );
+    if( pszDescription )
+        CPLAddXMLAttributeAndValue(psField, "description", pszDescription );
+}
+
+static const char* GetInterpretationOfBPC(GByte bpc)
+{
+    if( bpc == 255 )
+        return NULL;
+    if( (bpc & 0x80) )
+        return CPLSPrintf("Signed %d bits", 1 + (bpc & 0x7F));
+    else
+        return CPLSPrintf("Unsigned %d bits", 1 + bpc);
+}
+
+static const char* GetStandardFieldString(GUInt16 nVal)
+{
+    switch(nVal)
+    {
+        case 1: return "Codestream contains no extensions";
+        case 2: return "Contains multiple composition layers";
+        case 3: return "Codestream is compressed using JPEG 2000 and requires at least a Profile 0 decoder";
+        case 4: return "Codestream is compressed using JPEG 2000 and requires at least a Profile 1 decoder";
+        case 5: return "Codestream is compressed using JPEG 2000 unrestricted";
+        case 35: return "Contains IPR metadata";
+        case 67: return "Contains GMLJP2 metadata";
+        default: return NULL;
+    }
+}
+
+static void DumpGeoTIFFBox(CPLXMLNode* psBox,
+                           GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    GDALDriver* poVRTDriver = (GDALDriver*) GDALGetDriverByName("VRT");
+    if( pabyBoxData && poVRTDriver)
+    {
+        CPLString osTmpFilename(CPLSPrintf("/vsimem/tmp_%p.tif", oBox.GetFILE()));
+        VSIFCloseL(VSIFileFromMemBuffer(
+            osTmpFilename, pabyBoxData, nBoxDataLength, TRUE) );
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        GDALDataset* poDS = (GDALDataset*) GDALOpen(osTmpFilename, GA_ReadOnly);
+        CPLPopErrorHandler();
+        if( poDS )
+        {
+            CPLString osTmpVRTFilename(CPLSPrintf("/vsimem/tmp_%p.vrt", oBox.GetFILE()));
+            GDALDataset* poVRTDS = poVRTDriver->CreateCopy(osTmpVRTFilename, poDS, FALSE, NULL, NULL, NULL);
+            GDALClose(poVRTDS);
+            GByte* pabyXML = VSIGetMemFileBuffer( osTmpVRTFilename, NULL, FALSE );
+            CPLXMLNode* psXMLVRT = CPLParseXMLString((const char*)pabyXML);
+            if( psXMLVRT )
+            {
+                CPLXMLNode* psXMLContentNode = 
+                    CPLCreateXMLNode( psBox, CXT_Element, "DecodedGeoTIFF" );
+                psXMLContentNode->psChild = psXMLVRT;
+                CPLXMLNode* psPrev = NULL;
+                for(CPLXMLNode* psIter = psXMLVRT->psChild; psIter; psIter = psIter->psNext)
+                {
+                    if( psIter->eType == CXT_Element &&
+                        strcmp(psIter->pszValue, "VRTRasterBand") == 0 )
+                    {
+                        CPLXMLNode* psNext = psIter->psNext;
+                        psIter->psNext = NULL;
+                        CPLDestroyXMLNode(psIter);
+                        if( psPrev )
+                            psPrev->psNext = psNext;
+                        else
+                            break;
+                        psIter = psPrev;
+                    }
+                    psPrev = psIter;
+                }
+                CPLCreateXMLNode(psXMLVRT, CXT_Element, "VRTRasterBand");
+            }
+
+            VSIUnlink(osTmpVRTFilename);
+            GDALClose(poDS);
+        }
+        VSIUnlink(osTmpFilename);
+    }
+}
+
+static void DumpFTYPBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        if( nRemainingLength >= 4 )
+        {
+            char szBranding[5];
+            memcpy(szBranding, pabyIter, 4);
+            szBranding[4] = 0;
+            AddField(psDecodedContent, "BR", 4, szBranding);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+        }
+        if( nRemainingLength >= 4 )
+        {
+            GUInt32 nVal;
+            memcpy(&nVal, pabyIter, 4);
+            CPL_MSBPTR32(&nVal);
+            AddField(psDecodedContent, "MinV", nVal);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+        }
+        int nCLIndex = 0;
+        while( nRemainingLength >= 4 )
+        {
+            char szBranding[5];
+            memcpy(szBranding, pabyIter, 4);
+            szBranding[4] = 0;
+            AddField(psDecodedContent,
+                        CPLSPrintf("CL%d", nCLIndex),
+                        4, szBranding);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+            nCLIndex ++;
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpIHDRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        if( nRemainingLength >= 4 )
+        {
+            GUInt32 nVal;
+            memcpy(&nVal, pabyIter, 4);
+            CPL_MSBPTR32(&nVal);
+            AddField(psDecodedContent, "HEIGHT", nVal);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+        }
+        if( nRemainingLength >= 4 )
+        {
+            GUInt32 nVal;
+            memcpy(&nVal, pabyIter, 4);
+            CPL_MSBPTR32(&nVal);
+            AddField(psDecodedContent, "WIDTH", nVal);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+        }
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            AddField(psDecodedContent, "NC", nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "BPC", *pabyIter,
+                        GetInterpretationOfBPC(*pabyIter));
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "C", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "UnkC", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "IPR", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpBPCCBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        int nBPCIndex = 0;
+        while( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent,
+                        CPLSPrintf("BPC%d", nBPCIndex),
+                        *pabyIter,
+                        GetInterpretationOfBPC(*pabyIter));
+            nBPCIndex ++;
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpCOLRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        GByte nMeth;
+        if( nRemainingLength >= 1 )
+        {
+            nMeth = *pabyIter;
+            AddField(psDecodedContent, "METH", nMeth,
+                        (nMeth == 0) ? "Enumerated Colourspace":
+                        (nMeth == 0) ? "Restricted ICC profile": NULL);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "PREC", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, "APPROX", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 4 )
+        {
+            GUInt32 nVal;
+            memcpy(&nVal, pabyIter, 4);
+            CPL_MSBPTR32(&nVal);
+            AddField(psDecodedContent, "EnumCS", nVal,
+                        (nVal == 16) ? "sRGB" :
+                        (nVal == 17) ? "greyscale":
+                        (nVal == 18) ? "sYCC" : NULL);
+            pabyIter += 4;
+            nRemainingLength -= 4;
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpPCLRBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        GUInt16 NE = 0;
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            NE = nVal;
+            AddField(psDecodedContent, "NE", nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        GByte NPC = 0;
+        if( nRemainingLength >= 1 )
+        {
+            NPC = *pabyIter;
+            AddField(psDecodedContent, "NPC", NPC);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        int b8BitOnly = TRUE;
+        for(int i=0;i<NPC;i++)
+        {
+            if( nRemainingLength >= 1 )
+            {
+                b8BitOnly &= (*pabyIter <= 7);
+                AddField(psDecodedContent,
+                            CPLSPrintf("B%d", i),
+                            *pabyIter,
+                            GetInterpretationOfBPC(*pabyIter));
+                pabyIter += 1;
+                nRemainingLength -= 1;
+            }
+        }
+        if( b8BitOnly )
+        {
+            for(int j=0;j<NE;j++)
+            {
+                for(int i=0;i<NPC;i++)
+                {
+                    if( nRemainingLength >= 1 )
+                    {
+                        AddField(psDecodedContent,
+                                CPLSPrintf("C_%d_%d", j, i),
+                                *pabyIter);
+                        pabyIter += 1;
+                        nRemainingLength -= 1;
+                    }
+                }
+            }
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpCMAPBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        int nIndex = 0;
+        while( nRemainingLength >= 2 + 1 + 1 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            AddField(psDecodedContent,
+                        CPLSPrintf("CMP%d", nIndex),
+                        nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+
+            AddField(psDecodedContent,
+                        CPLSPrintf("MTYP%d", nIndex),
+                        *pabyIter,
+                        (*pabyIter == 0) ? "Direct use":
+                        (*pabyIter == 1) ? "Palette mapping": NULL);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+
+            AddField(psDecodedContent,
+                        CPLSPrintf("PCOL%d", nIndex),
+                        *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+
+            nIndex ++;
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpCDEFBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        GUInt16 nChannels = 0;
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            nChannels = nVal;
+            CPL_MSBPTR16(&nVal);
+            AddField(psDecodedContent, "N", nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        for( int i=0; i < nChannels; i++ )
+        {
+            if( nRemainingLength >= 2 )
+            {
+                GUInt16 nVal;
+                memcpy(&nVal, pabyIter, 2);
+                CPL_MSBPTR16(&nVal);
+                AddField(psDecodedContent,
+                            CPLSPrintf("Cn%d", i),
+                            nVal);
+                pabyIter += 2;
+                nRemainingLength -= 2;
+            }
+            if( nRemainingLength >= 2 )
+            {
+                GUInt16 nVal;
+                memcpy(&nVal, pabyIter, 2);
+                CPL_MSBPTR16(&nVal);
+                AddField(psDecodedContent,
+                            CPLSPrintf("Typ%d", i),
+                            nVal,
+                            (nVal == 0) ? "Colour channel":
+                            (nVal == 1) ? "Opacity channel":
+                            (nVal == 2) ? "Premultiplied opacity":
+                            (nVal == 65535) ? "Not specified" : NULL);
+                pabyIter += 2;
+                nRemainingLength -= 2;
+            }
+            if( nRemainingLength >= 2 )
+            {
+                GUInt16 nVal;
+                memcpy(&nVal, pabyIter, 2);
+                CPL_MSBPTR16(&nVal);
+                AddField(psDecodedContent,
+                            CPLSPrintf("Asoc%d", i),
+                            nVal,
+                            (nVal == 0) ? "Associated to the whole image":
+                            (nVal == 65535) ? "Not associated with a particular colour":
+                            "Associated with a particular colour");
+                pabyIter += 2;
+                nRemainingLength -= 2;
+            }
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpRESxBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    char chC = oBox.GetType()[3];
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        GUInt16 nNumV = 0, nNumH = 0, nDenomV = 1, nDenomH = 1, nExpV = 0, nExpH = 0;
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            nNumV = nVal;
+            AddField(psDecodedContent, CPLSPrintf("VR%cN", chC), nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            nDenomV = nVal;
+            AddField(psDecodedContent, CPLSPrintf("VR%cD", chC), nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            nNumH = nVal;
+            AddField(psDecodedContent, CPLSPrintf("HR%cN", chC), nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            nDenomH = nVal;
+            AddField(psDecodedContent, CPLSPrintf("HR%cD", chC), nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, CPLSPrintf("VR%cE", chC), *pabyIter);
+            nExpV = *pabyIter;
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= 1 )
+        {
+            AddField(psDecodedContent, CPLSPrintf("HR%cE", chC), *pabyIter);
+            nExpH = *pabyIter;
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength == 0 )
+        {
+            CPLCreateXMLElementAndValue(psDecodedContent, "VRes",
+                CPLSPrintf("%.03f", 1.0 * nNumV / nDenomV * pow(10.0, nExpV)));
+            CPLCreateXMLElementAndValue(psDecodedContent, "HRes",
+                CPLSPrintf("%.03f", 1.0 * nNumH / nDenomH * pow(10.0, nExpH)));
+        }
+        else if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static void DumpRREQBox(CPLXMLNode* psBox, GDALJP2Box& oBox)
+{
+    GIntBig nBoxDataLength = oBox.GetDataLength();
+    GByte* pabyBoxData = oBox.ReadBoxData();
+    if( pabyBoxData )
+    {
+        CPLXMLNode* psDecodedContent = 
+            CPLCreateXMLNode( psBox, CXT_Element, "DecodedContent" );
+        GIntBig nRemainingLength = nBoxDataLength;
+        GByte* pabyIter = pabyBoxData;
+        GByte ML = 0;
+        if( nRemainingLength >= 1 )
+        {
+            ML = *pabyIter;
+            AddField(psDecodedContent, "ML", *pabyIter);
+            pabyIter += 1;
+            nRemainingLength -= 1;
+        }
+        if( nRemainingLength >= ML )
+        {
+            CPLString osHex("0x");
+            for(int i=0;i<ML;i++)
+            {
+                osHex += CPLSPrintf("%02X", *pabyIter);
+                pabyIter += 1;
+                nRemainingLength -= 1;
+            }
+            AddHexField(psDecodedContent, "FUAM", (int)ML, osHex.c_str());
+        }
+        if( nRemainingLength >= ML )
+        {
+            CPLString osHex("0x");
+            for(int i=0;i<ML;i++)
+            {
+                osHex += CPLSPrintf("%02X", *pabyIter);
+                pabyIter += 1;
+                nRemainingLength -= 1;
+            }
+            AddHexField(psDecodedContent, "DCM", (int)ML, osHex.c_str());
+        }
+        GUInt16 NSF = 0;
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            NSF = nVal;
+            AddField(psDecodedContent, "NSF", nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        for(int iNSF=0;iNSF<NSF;iNSF++)
+        {
+            if( nRemainingLength >= 2 )
+            {
+                GUInt16 nVal;
+                memcpy(&nVal, pabyIter, 2);
+                CPL_MSBPTR16(&nVal);
+                AddField(psDecodedContent,
+                            CPLSPrintf("SF%d", iNSF), nVal,
+                            GetStandardFieldString(nVal));
+                pabyIter += 2;
+                nRemainingLength -= 2;
+            }
+            if( nRemainingLength >= ML )
+            {
+                CPLString osHex("0x");
+                for(int i=0;i<ML;i++)
+                {
+                    osHex += CPLSPrintf("%02X", *pabyIter);
+                    pabyIter += 1;
+                    nRemainingLength -= 1;
+                }
+                AddHexField(psDecodedContent,
+                            CPLSPrintf("SM%d", iNSF),
+                            (int)ML, osHex.c_str());
+            }
+        }
+        GUInt16 NVF = 0;
+        if( nRemainingLength >= 2 )
+        {
+            GUInt16 nVal;
+            memcpy(&nVal, pabyIter, 2);
+            CPL_MSBPTR16(&nVal);
+            NVF = nVal;
+            AddField(psDecodedContent, "NVF", nVal);
+            pabyIter += 2;
+            nRemainingLength -= 2;
+        }
+        for(int iNVF=0;iNVF<NVF;iNVF++)
+        {
+            if( nRemainingLength >= 16 )
+            {
+                CPLString osHex("0x");
+                for(int i=0;i<16;i++)
+                {
+                    osHex += CPLSPrintf("%02X", *pabyIter);
+                    pabyIter += 1;
+                    nRemainingLength -= 1;
+                }
+                AddHexField(psDecodedContent,
+                            CPLSPrintf("VF%d", iNVF),
+                            (int)ML, osHex.c_str());
+            }
+            if( nRemainingLength >= ML )
+            {
+                CPLString osHex("0x");
+                for(int i=0;i<ML;i++)
+                {
+                    osHex += CPLSPrintf("%02X", *pabyIter);
+                    pabyIter += 1;
+                    nRemainingLength -= 1;
+                }
+                AddHexField(psDecodedContent,
+                            CPLSPrintf("VM%d", iNVF),
+                            (int)ML, osHex.c_str());
+            }
+        }
+        if( nRemainingLength > 0 )
+            CPLCreateXMLElementAndValue(
+                    psDecodedContent, "RemainingBytes",
+                    CPLSPrintf("%d", (int)nRemainingLength ));
+    }
+    CPLFree(pabyBoxData);
+}
+
+static CPLXMLNode* CreateMarker(CPLXMLNode* psCSBox, const char* pszName,
+                                GIntBig nOffset, GIntBig nLength)
+{
+    CPLXMLNode* psMarker = CPLCreateXMLNode( psCSBox, CXT_Element, "Marker" );
+    CPLAddXMLAttributeAndValue(psMarker, "name", pszName );
+    CPLAddXMLAttributeAndValue(psMarker, "offset",
+                               CPLSPrintf(CPL_FRMT_GIB, nOffset )  );
+    CPLAddXMLAttributeAndValue(psMarker, "length",
+                               CPLSPrintf(CPL_FRMT_GIB, 2 + nLength ) );
+    return psMarker;
+}
+
+static void AddError(CPLXMLNode* psParent, const char* pszErrorMsg,
+                     GIntBig nOffset = 0)
+{
+    CPLXMLNode* psError = CPLCreateXMLNode( psParent, CXT_Element, "Error" );
+    CPLAddXMLAttributeAndValue(psError, "message", pszErrorMsg );
+    if( nOffset )
+    {
+        CPLAddXMLAttributeAndValue(psError, "offset",
+                                CPLSPrintf(CPL_FRMT_GIB, nOffset )  );
+    }
+}
+
+static const char* GetMarkerName(GByte byVal)
+{
+    switch(byVal)
+    {
+        case 0x90: return "SOT";
+        case 0x51: return "SIZ";
+        case 0x52: return "COD";
+        case 0x53: return "COC";
+        case 0x55: return "TLM";
+        case 0x57: return "PLM";
+        case 0x58: return "PLT";
+        case 0x5C: return "QCD";
+        case 0x5D: return "QCC";
+        case 0x5E: return "RGN";
+        case 0x5F: return "POC";
+        case 0x60: return "PPM";
+        case 0x61: return "PPT";
+        case 0x63: return "CRG";
+        case 0x64: return "COM";
+        default: return CPLSPrintf("Unknown 0xFF%02X", byVal);
+    }
+}
+
+/************************************************************************/
+/*                       DumpJPK2CodeStream()                           */
+/************************************************************************/
+
+static CPLXMLNode* DumpJPK2CodeStream(CPLXMLNode* psBox,
+                                      VSILFILE* fp,
+                                      GIntBig nBoxDataOffset,
+                                      GIntBig nBoxDataLength)
+{
+    VSIFSeekL(fp, nBoxDataOffset, SEEK_SET);
+    GByte abyMarker[2];
+    CPLXMLNode* psCSBox = CPLCreateXMLNode( psBox, CXT_Element, "JP2KCodeStream" );
+    GByte* pabyMarkerData = (GByte*)CPLMalloc(65535+1);
+    GIntBig nNextTileOffset = 0;
+    while( TRUE )
+    {
+        GIntBig nOffset = (GIntBig)VSIFTellL(fp);
+        if( nOffset == nBoxDataOffset + nBoxDataLength )
+            break;
+        if( VSIFReadL(abyMarker, 2, 1, fp) != 1 )
+        {
+            AddError(psCSBox, "Cannot read marker", nOffset);
+            break;
+        }
+        if( abyMarker[0] != 0xFF )
+        {
+            AddError(psCSBox, "Not a marker", nOffset);
+            break;
+        }
+        if( abyMarker[1] == 0x4F )
+        {
+            CreateMarker( psCSBox, "SOC", nOffset, 0 );
+            continue;
+        }
+        if( abyMarker[1] == 0x93 )
+        {
+            GIntBig nMarkerSize = 0;
+            int bBreak = FALSE;
+            if( nNextTileOffset == 0 )
+            {
+                nMarkerSize = (nBoxDataOffset + nBoxDataLength - 2) - nOffset - 2;
+                VSIFSeekL(fp, nBoxDataOffset + nBoxDataLength - 2, SEEK_SET);
+                if( VSIFReadL(abyMarker, 2, 1, fp) != 1 ||
+                    abyMarker[0] != 0xFF || abyMarker[1] != 0xD9 )
+                {
+                    /* autotest/gdrivers/data/rgb16_ecwsdk.jp2 does not end */
+                    /* with a EOC... */
+                    nMarkerSize += 2;
+                    bBreak = TRUE;
+                }
+            }
+            else if( nNextTileOffset >= nOffset + 2 )
+                nMarkerSize = nNextTileOffset - nOffset - 2;
+
+            CreateMarker( psCSBox, "SOD", nOffset, nMarkerSize );
+            if( bBreak )
+                break;
+
+            if( nNextTileOffset && nNextTileOffset == nOffset )
+            {
+                /* Found with Pleiades images. openjpeg doesn't like it either */
+                nNextTileOffset = 0;
+            }
+            else if( nNextTileOffset && nNextTileOffset >= nOffset + 2 )
+            {
+                VSIFSeekL(fp, nNextTileOffset, SEEK_SET);
+                nNextTileOffset = 0;
+            }
+            else
+            {
+                /* We have seek and check before we hit a EOC */
+                CreateMarker( psCSBox, "EOC", nOffset, 0 );
+            }
+            continue;
+        }
+        if( abyMarker[1] == 0xD9 )
+        {
+            CreateMarker( psCSBox, "EOC", nOffset, 0 );
+            continue;
+        }
+        /* Reserved markers */
+        if( abyMarker[1] >= 0x30 && abyMarker[1] <= 0x3F )
+        {
+            CreateMarker( psCSBox, CPLSPrintf("Unknown 0xFF%02X", abyMarker[1]), nOffset, 0 );
+            continue;
+        }
+
+        GUInt16 nMarkerSize;
+        if( VSIFReadL(&nMarkerSize, 2, 1, fp) != 1 )
+        {
+            AddError(psCSBox, CPLSPrintf("Cannot read marker size of %s", GetMarkerName(abyMarker[1])), nOffset);
+            break;
+        }
+        CPL_MSBPTR16(&nMarkerSize);
+        if( nMarkerSize < 2 )
+        {
+            AddError(psCSBox, CPLSPrintf("Invalid marker size of %s", GetMarkerName(abyMarker[1])), nOffset);
+            break;
+        }
+
+        CPLXMLNode* psMarker = CreateMarker( psCSBox, GetMarkerName(abyMarker[1]), nOffset, nMarkerSize );
+        if( VSIFReadL(pabyMarkerData, nMarkerSize - 2, 1, fp) != 1 )
+        {
+            AddError(psMarker, "Cannot read marker data", nOffset);
+            break;
+        }
+        GByte* pabyMarkerDataIter = pabyMarkerData;
+        GUInt16 nRemainingMarkerSize = nMarkerSize - 2;
+        GUInt32 nLastVal = 0;
+
+
+#define READ_MARKER_FIELD_UINT8_COMMENT(name, comment) \
+        do { if( nRemainingMarkerSize >= 1 ) { \
+            nLastVal = *pabyMarkerDataIter; \
+            AddField(psMarker, name, *pabyMarkerDataIter, comment); \
+            pabyMarkerDataIter += 1; \
+            nRemainingMarkerSize -= 1; \
+            } \
+            else { \
+                AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
+                nLastVal = 0; \
+            } \
+        } while(0)
+
+#define READ_MARKER_FIELD_UINT8(name) \
+        READ_MARKER_FIELD_UINT8_COMMENT(name, NULL)
+
+#define READ_MARKER_FIELD_UINT16_COMMENT(name, comment) \
+        do { if( nRemainingMarkerSize >= 2 ) { \
+            GUInt16 nVal; \
+            memcpy(&nVal, pabyMarkerDataIter, 2); \
+            CPL_MSBPTR16(&nVal); \
+            nLastVal = nVal; \
+            AddField(psMarker, name, nVal, comment); \
+            pabyMarkerDataIter += 2; \
+            nRemainingMarkerSize -= 2; \
+            } \
+            else { \
+                AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
+                nLastVal = 0; \
+            } \
+        } while(0)
+
+#define READ_MARKER_FIELD_UINT16(name) \
+        READ_MARKER_FIELD_UINT16_COMMENT(name, NULL)
+
+#define READ_MARKER_FIELD_UINT32_COMMENT(name, comment) \
+        do { if( nRemainingMarkerSize >= 4 ) { \
+            GUInt32 nVal; \
+            memcpy(&nVal, pabyMarkerDataIter, 4); \
+            CPL_MSBPTR32(&nVal); \
+            AddField(psMarker, name, nVal, comment); \
+            nLastVal = nVal; \
+            pabyMarkerDataIter += 4; \
+            nRemainingMarkerSize -= 4; \
+            } \
+            else { \
+                AddError(psMarker, CPLSPrintf("Cannot read field %s", name)); \
+                nLastVal = 0; \
+            } \
+        } while(0)
+
+#define READ_MARKER_FIELD_UINT32(name) \
+        READ_MARKER_FIELD_UINT32_COMMENT(name, NULL)
+
+        if( abyMarker[1] == 0x90 ) /* SOT */
+        {
+            READ_MARKER_FIELD_UINT16("Isot");
+            READ_MARKER_FIELD_UINT32("Psot");
+            GUInt32 PSOT = nLastVal;
+            READ_MARKER_FIELD_UINT8("TPsot");
+            READ_MARKER_FIELD_UINT8("TNsot");
+            if( nRemainingMarkerSize > 0 )
+                CPLCreateXMLElementAndValue(
+                        psMarker, "RemainingBytes",
+                        CPLSPrintf("%d", (int)nRemainingMarkerSize ));
+
+            if( PSOT )
+                nNextTileOffset = nOffset + PSOT;
+        }
+        else if( abyMarker[1] == 0x51 ) /* SIZ */
+        {
+            READ_MARKER_FIELD_UINT16_COMMENT("Rsiz",
+                                            (nLastVal == 0) ? "Unrestricted profile":
+                                            (nLastVal == 1) ? "Profile 0":
+                                            (nLastVal == 2) ? "Profile 1": NULL);
+            READ_MARKER_FIELD_UINT32("Xsiz");
+            READ_MARKER_FIELD_UINT32("Ysiz");
+            READ_MARKER_FIELD_UINT32("XOsiz");
+            READ_MARKER_FIELD_UINT32("YOsiz");
+            READ_MARKER_FIELD_UINT32("XTsiz");
+            READ_MARKER_FIELD_UINT32("YTsiz");
+            READ_MARKER_FIELD_UINT32("XTOSiz");
+            READ_MARKER_FIELD_UINT32("YTOSiz");
+            READ_MARKER_FIELD_UINT16("Csiz");
+            int CSiz = nLastVal;
+            for(int i=0;i<CSiz;i++)
+            {
+                READ_MARKER_FIELD_UINT8_COMMENT(CPLSPrintf("Ssiz%d", i),
+                                                GetInterpretationOfBPC(nLastVal));
+                READ_MARKER_FIELD_UINT8(CPLSPrintf("XRsiz%d", i));
+                READ_MARKER_FIELD_UINT8(CPLSPrintf("YRsiz%d", i));
+            }
+            if( nRemainingMarkerSize > 0 )
+                CPLCreateXMLElementAndValue(
+                        psMarker, "RemainingBytes",
+                        CPLSPrintf("%d", (int)nRemainingMarkerSize ));
+        }
+        else if( abyMarker[1] == 0x52 ) /* COD */
+        {
+            int bHasPrecincts = TRUE;
+            if( nRemainingMarkerSize >= 1 ) {
+                nLastVal = *pabyMarkerDataIter;
+                CPLString osInterp;
+                if( nLastVal & 0x1 )
+                {
+                    bHasPrecincts = TRUE;
+                    osInterp += "User defined precincts";
+                }
+                else
+                    osInterp += "Standard precincts";
+                osInterp += ", ";
+                if( nLastVal & 0x2 )
+                    osInterp += "SOP marker segments may be used";
+                else
+                    osInterp += "No SOP marker segments";
+                osInterp += ", ";
+                if( nLastVal & 0x4 )
+                    osInterp += "EPH marker segments may be used";
+                else
+                    osInterp += "No EPH marker segments";
+                AddField(psMarker, "Scod", (GByte)nLastVal, osInterp.c_str());
+                pabyMarkerDataIter += 1;
+                nRemainingMarkerSize -= 1;
+            }
+            else {
+                AddError(psMarker, CPLSPrintf("Cannot read field %s", "Scod"));
+                nLastVal = 0;
+            }
+            READ_MARKER_FIELD_UINT8_COMMENT("SGcod_Progress",
+                                            (nLastVal == 0) ? "LRCP" :
+                                            (nLastVal == 1) ? "RLCP" :
+                                            (nLastVal == 2) ? "RPCL" :
+                                            (nLastVal == 3) ? "PCRL" :
+                                            (nLastVal == 4) ? "CPRL" : NULL);
+            READ_MARKER_FIELD_UINT16("SGcod_NumLayers");
+            READ_MARKER_FIELD_UINT8("SGcod_MCT");
+            READ_MARKER_FIELD_UINT8("SPcod_NumDecompositions");
+            READ_MARKER_FIELD_UINT8_COMMENT("SPcod_xcb_minus_2", CPLSPrintf("%d", 1 << (2+nLastVal)));
+            READ_MARKER_FIELD_UINT8_COMMENT("SPcod_ycb_minus_2", CPLSPrintf("%d", 1 << (2+nLastVal)));
+            if( nRemainingMarkerSize >= 1 ) {
+                nLastVal = *pabyMarkerDataIter;
+                CPLString osInterp;
+                if( nLastVal & 0x1 )
+                    osInterp += "Selective arithmetic coding bypass";
+                else
+                    osInterp += "No selective arithmetic coding bypass";
+                osInterp += ", ";
+                if( nLastVal & 0x2 )
+                    osInterp += "Reset context probabilities on coding pass boundaries";
+                else
+                    osInterp += "No reset of context probabilities on coding pass boundaries";
+                osInterp += ", ";
+                if( nLastVal & 0x4 )
+                    osInterp += "Termination on each coding pass";
+                else
+                    osInterp += "No termination on each coding pass";
+                osInterp += ", ";
+                if( nLastVal & 0x8 )
+                    osInterp += "Vertically causal context";
+                else
+                    osInterp += "No vertically causal context";
+                osInterp += ", ";
+                if( nLastVal & 0x10 )
+                    osInterp += "Predictable termination";
+                else
+                    osInterp += "No predictable termination";
+                osInterp += ", ";
+                if( nLastVal & 0x20 )
+                    osInterp += "Segmentation symbols are used";
+                else
+                    osInterp += "No segmentation symbols are used";
+                AddField(psMarker, "SPcod_cbstyle", (GByte)nLastVal, osInterp.c_str());
+                pabyMarkerDataIter += 1;
+                nRemainingMarkerSize -= 1;
+            }
+            else {
+                AddError(psMarker, CPLSPrintf("Cannot read field %s", "SPcod_cbstyle"));
+                nLastVal = 0;
+            }
+            READ_MARKER_FIELD_UINT8_COMMENT("SPcod_transformation",
+                                            (nLastVal == 0) ? "9-7 irreversible":
+                                            (nLastVal == 1) ? "5-3 reversible": NULL);
+            if( bHasPrecincts )
+            {
+                int i = 0;
+                while( nRemainingMarkerSize >= 1 )
+                {
+                    nLastVal = *pabyMarkerDataIter;
+                    AddField(psMarker, CPLSPrintf("SPcod_Precincts%d", i), *pabyMarkerDataIter,
+                             CPLSPrintf("PPx=%d PPy=%d: %dx%d",
+                                        nLastVal & 0xf, nLastVal >> 4,
+                                        1 << (nLastVal & 0xf), 1 << (nLastVal >> 4)));
+                    pabyMarkerDataIter += 1;
+                    nRemainingMarkerSize -= 1;
+                    i ++;
+                }
+            }
+            if( nRemainingMarkerSize > 0 )
+                CPLCreateXMLElementAndValue(
+                        psMarker, "RemainingBytes",
+                        CPLSPrintf("%d", (int)nRemainingMarkerSize ));
+        }
+        else if( abyMarker[1] == 0x53 ) /* COC */
+        {
+        }
+        else if( abyMarker[1] == 0x55 ) /* TLM */
+        {
+            CPLXMLNode* psMarker = CreateMarker( psCSBox, "TLM", nOffset, nMarkerSize );
+            READ_MARKER_FIELD_UINT8("Ztlm");
+            int ST = 0, SP = 0;
+            READ_MARKER_FIELD_UINT8_COMMENT("Stlm",
+                    CPLSPrintf("ST=%d SP=%d",
+                               (ST = (nLastVal >> 4) & 3),
+                               (SP = ((nLastVal >> 6) & 1))));
+            int nTilePartDescLength = ST + ((SP == 0) ? 2 : 4);
+            int i = 0;
+            while( nRemainingMarkerSize >= nTilePartDescLength )
+            {
+                if( ST == 1 )
+                    READ_MARKER_FIELD_UINT8(CPLSPrintf("Ttlm%d", i));
+                else if( ST == 2 )
+                    READ_MARKER_FIELD_UINT16(CPLSPrintf("Ttlm%d", i));
+                if( SP == 0 )
+                    READ_MARKER_FIELD_UINT16(CPLSPrintf("Ptlm%d", i));
+                else
+                    READ_MARKER_FIELD_UINT32(CPLSPrintf("Ptlm%d", i));
+                i ++;
+            }
+            if( nRemainingMarkerSize > 0 )
+                CPLCreateXMLElementAndValue(
+                        psMarker, "RemainingBytes",
+                        CPLSPrintf("%d", (int)nRemainingMarkerSize ));
+        }
+        else if( abyMarker[1] == 0x57 ) /* PLM */
+        {
+        }
+        else if( abyMarker[1] == 0x58 ) /* PLT */
+        {
+        }
+        else if( abyMarker[1] == 0x5C ) /* QCD */
+        {
+        }
+        else if( abyMarker[1] == 0x5D ) /* QCC */
+        {
+        }
+        else if( abyMarker[1] == 0x5E ) /* RGN */
+        {
+        }
+        else if( abyMarker[1] == 0x5F ) /* POC */
+        {
+        }
+        else if( abyMarker[1] == 0x60 ) /* PPM */
+        {
+        }
+        else if( abyMarker[1] == 0x61 ) /* PPT */
+        {
+        }
+        else if( abyMarker[1] == 0x63 ) /* CRG */
+        {
+        }
+        else if( abyMarker[1] == 0x64 ) /* COM */
+        {
+            READ_MARKER_FIELD_UINT16_COMMENT("Rcom", (nLastVal == 0 ) ? "Binary" : (nLastVal == 1) ? "LATIN1" : NULL);
+            if( nLastVal == 1 )
+            {
+                GByte abyBackup = pabyMarkerDataIter[nRemainingMarkerSize];
+                pabyMarkerDataIter[nRemainingMarkerSize] = 0;
+                AddField(psMarker, "COM", (int)nRemainingMarkerSize, (const char*)pabyMarkerDataIter);
+                pabyMarkerDataIter[nRemainingMarkerSize] = abyBackup;
+            }
+        }
+
+        VSIFSeekL(fp, nOffset + 2 + nMarkerSize, SEEK_SET);
+    }
+    CPLFree(pabyMarkerData);
+    return psCSBox;
+}
+
+/************************************************************************/
+/*                      GDALGetJPEG2000StructureInternal()              */
+/************************************************************************/
+
+static
+void GDALGetJPEG2000StructureInternal(CPLXMLNode* psParent,
+                                      VSILFILE* fp,
+                                      GDALJP2Box* poParentBox,
+                                      char** papszOptions)
+{
+    static const char* szHex = "0123456789ABCDEF";
+    GDALJP2Box oBox( fp );
+    if( oBox.ReadFirstChild(poParentBox) )
+    {
+        while( strlen(oBox.GetType()) > 0 )
+        {
+            GIntBig nBoxDataLength = oBox.GetDataLength();
+            const char* pszBoxType = oBox.GetType();
+
+            CPLXMLNode* psBox = CPLCreateXMLNode( psParent, CXT_Element, "JP2Box" );
+            CPLAddXMLAttributeAndValue(psBox, "name", pszBoxType );
+            CPLAddXMLAttributeAndValue(psBox, "box_offset",
+                                       CPLSPrintf(CPL_FRMT_GIB, oBox.GetBoxOffset() )  );
+            CPLAddXMLAttributeAndValue(psBox, "box_length",
+                                       CPLSPrintf(CPL_FRMT_GIB, oBox.GetBoxLength() ) );
+            CPLAddXMLAttributeAndValue(psBox, "data_offset",
+                                       CPLSPrintf(CPL_FRMT_GIB, oBox.GetDataOffset() ) );
+            CPLAddXMLAttributeAndValue(psBox, "data_length",
+                                       CPLSPrintf(CPL_FRMT_GIB, nBoxDataLength ) );
+
+            if( oBox.IsSuperBox() )
+            {
+                GDALGetJPEG2000StructureInternal(psBox, fp, &oBox, papszOptions);
+            }
+            else
+            {
+                if( strcmp(pszBoxType, "uuid") == 0 )
+                {
+                    char* pszBinaryContent = (char*)VSIMalloc( 2 * 16 + 1 );
+                    const GByte* pabyUUID = oBox.GetUUID();
+                    for(int i=0;i<16;i++)
+                    {
+                        pszBinaryContent[2*i] = szHex[pabyUUID[i] >> 4];
+                        pszBinaryContent[2*i+1] = szHex[pabyUUID[i] & 0xf];
+                    }
+                    pszBinaryContent[2*16] = '\0';
+                    CPLXMLNode* psUUIDNode =
+                                CPLCreateXMLNode( psBox, CXT_Element, "UUID" );
+                    if( GDALJP2Metadata::IsUUID_MSI(pabyUUID) )
+                        CPLAddXMLAttributeAndValue(psUUIDNode, "description", "GeoTIFF" );
+                    else if( GDALJP2Metadata::IsUUID_XMP(pabyUUID) )
+                        CPLAddXMLAttributeAndValue(psUUIDNode, "description", "XMP" );
+                    CPLCreateXMLNode( psUUIDNode, CXT_Text, pszBinaryContent);
+                    VSIFree(pszBinaryContent);
+                }
+
+                if( (CSLFetchBoolean(papszOptions, "BINARY_CONTENT", FALSE) ||
+                     CSLFetchBoolean(papszOptions, "ALL", FALSE) ) &&
+                    strcmp(pszBoxType, "jp2c") != 0 &&
+                    nBoxDataLength < 100 * 1024 )
+                {
+                    CPLXMLNode* psBinaryContent = CPLCreateXMLNode( psBox, CXT_Element, "BinaryContent" );
+                    GByte* pabyBoxData = oBox.ReadBoxData();
+                    int nBoxLength = (int)nBoxDataLength;
+                    char* pszBinaryContent = (char*)VSIMalloc( 2 * nBoxLength + 1 );
+                    if( pabyBoxData && pszBinaryContent )
+                    {
+                        for(int i=0;i<nBoxLength;i++)
+                        {
+                            pszBinaryContent[2*i] = szHex[pabyBoxData[i] >> 4];
+                            pszBinaryContent[2*i+1] = szHex[pabyBoxData[i] & 0xf];
+                        }
+                        pszBinaryContent[2*nBoxLength] = '\0';
+                        CPLCreateXMLNode( psBinaryContent, CXT_Text, pszBinaryContent );
+                    }
+                    CPLFree(pabyBoxData);
+                    VSIFree(pszBinaryContent);
+                }
+
+                if( (CSLFetchBoolean(papszOptions, "TEXT_CONTENT", FALSE) ||
+                     CSLFetchBoolean(papszOptions, "ALL", FALSE) ) &&
+                    strcmp(pszBoxType, "jp2c") != 0 &&
+                    nBoxDataLength < 100 * 1024 )
+                {
+                    GByte* pabyBoxData = oBox.ReadBoxData();
+                    if( pabyBoxData )
+                    {
+                        if( CPLIsUTF8((const char*)pabyBoxData, -1) &&
+                            (int)strlen((const char*)pabyBoxData) + 2 >= nBoxDataLength  )
+                        {
+                            CPLXMLNode* psXMLContentBox = NULL;
+                            if( ((const char*)pabyBoxData)[0] ==  '<' )
+                            {
+                                CPLPushErrorHandler(CPLQuietErrorHandler);
+                                psXMLContentBox = CPLParseXMLString((const char*)pabyBoxData);
+                                CPLPopErrorHandler();
+                            }
+                            if( psXMLContentBox )
+                            {
+                                CPLXMLNode* psXMLContentNode = 
+                                    CPLCreateXMLNode( psBox, CXT_Element, "XMLContent" );
+                                psXMLContentNode->psChild = psXMLContentBox;
+                            }
+                            else
+                            {
+                                CPLCreateXMLNode( 
+                                    CPLCreateXMLNode( psBox, CXT_Element, "TextContent" ),
+                                        CXT_Text, (const char*)pabyBoxData);
+                            }
+                        }
+                    }
+                    CPLFree(pabyBoxData);
+                }
+
+                if( strcmp(pszBoxType, "jp2c") == 0 )
+                {
+                    if( CSLFetchBoolean(papszOptions, "CODESTREAM", FALSE) ||
+                        CSLFetchBoolean(papszOptions, "ALL", FALSE) )
+                    {
+                        DumpJPK2CodeStream(psBox, fp,
+                                           oBox.GetDataOffset(), nBoxDataLength);
+                    }
+                }
+                else if( strcmp(pszBoxType, "uuid") == 0 &&
+                         GDALJP2Metadata::IsUUID_MSI(oBox.GetUUID()) )
+                {
+                    DumpGeoTIFFBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "ftyp") == 0 )
+                {
+                    DumpFTYPBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "ihdr") == 0 )
+                {
+                    DumpIHDRBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "bpcc") == 0 )
+                {
+                    DumpBPCCBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "colr") == 0 )
+                {
+                    DumpCOLRBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "pclr") == 0 )
+                {
+                    DumpPCLRBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "cmap") == 0 )
+                {
+                    DumpCMAPBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "cdef") == 0 )
+                {
+                    DumpCDEFBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "resc") == 0 ||
+                         strcmp(pszBoxType, "resd") == 0)
+                {
+                    DumpRESxBox(psBox, oBox);
+                }
+                else if( strcmp(pszBoxType, "rreq") == 0 )
+                {
+                    DumpRREQBox(psBox, oBox);
+                }
+            }
+
+            if (!oBox.ReadNextChild(poParentBox))
+                break;
+        }
+    }
+}
+
+/************************************************************************/
+/*                        GDALGetJPEG2000Structure()                    */
+/************************************************************************/
+
+static const unsigned char jpc_header[] = {0xff,0x4f};
+static const unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP  ' */
+
+/** Dump the structure of a JPEG2000 file as a XML tree.
+ *
+ * @param pszFilename filename.
+ * @param papszOptions NULL terminated list of options, or NULL.
+ *                     Allowed options are BINARY_CONTENT=YES, TEXT_CONTENT=YES,
+ *                     CODESTREAM=YES, ALL=YES.
+ * @return XML tree (to be freed with CPLDestroyXMLNode()) or NULL in case
+ *         of error
+ * @since GDAL 2.0
+ */
+
+CPLXMLNode* GDALGetJPEG2000Structure(const char* pszFilename,
+                                     char** papszOptions)
+{
+    VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
+    if( fp == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename);
+        return NULL;
+    }
+    GByte abyHeader[16];
+    if( VSIFReadL(abyHeader, 16, 1, fp) != 1 ||
+        (memcmp(abyHeader, jpc_header, sizeof(jpc_header)) != 0 &&
+         memcmp(abyHeader + 4, jp2_box_jp, sizeof(jp2_box_jp)) != 0) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "%s is not a JPEG2000 file", pszFilename);
+        VSIFCloseL(fp);
+        return NULL;
+    }
+    
+    CPLXMLNode* psParent = NULL;
+    if( memcmp(abyHeader, jpc_header, sizeof(jpc_header)) == 0 )
+    {
+        if( CSLFetchBoolean(papszOptions, "CODESTREAM", FALSE) ||
+            CSLFetchBoolean(papszOptions, "ALL", FALSE) )
+        {
+            VSIFSeekL(fp, 0, SEEK_END);
+            GIntBig nBoxDataLength = (GIntBig)VSIFTellL(fp);
+            psParent = DumpJPK2CodeStream(NULL, fp, 0, nBoxDataLength);
+            CPLAddXMLAttributeAndValue(psParent, "filename", pszFilename );
+        }
+    }
+    else
+    {
+        psParent = CPLCreateXMLNode( NULL, CXT_Element, "JP2File" );
+        CPLAddXMLAttributeAndValue(psParent, "filename", pszFilename );
+        GDALGetJPEG2000StructureInternal(psParent, fp, NULL, papszOptions );
+    }
+
+    VSIFCloseL(fp);
+    return psParent;
+}
diff --git a/gcore/gdalmultidomainmetadata.cpp b/gcore/gdalmultidomainmetadata.cpp
index 60620e5..e843304 100644
--- a/gcore/gdalmultidomainmetadata.cpp
+++ b/gcore/gdalmultidomainmetadata.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalmultidomainmetadata.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdalmultidomainmetadata.cpp 29038 2015-04-28 09:03:36Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALMultiDomainMetadata class.  This class
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include <map>
 
-CPL_CVSID("$Id: gdalmultidomainmetadata.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdalmultidomainmetadata.cpp 29038 2015-04-28 09:03:36Z rouault $");
 
 /************************************************************************/
 /*                      GDALMultiDomainMetadata()                       */
@@ -234,6 +234,7 @@ int GDALMultiDomainMetadata::XMLInit( CPLXMLNode *psTree, CPL_UNUSED int bMerge
             
             char *pszDoc = CPLSerializeXMLTree( psSubDoc );
 
+            poMDList->Clear();
             poMDList->AddStringDirectly( pszDoc );
         }
 
@@ -279,6 +280,10 @@ CPLXMLNode *GDALMultiDomainMetadata::Serialize()
          iDomain++)
     {
         char **papszMD = papoMetadataLists[iDomain]->List();
+        // Do not serialize empty domains
+        if( papszMD == NULL || papszMD[0] == NULL )
+            continue;
+
         CPLXMLNode *psMD;
         int bFormatXML = FALSE;
         
@@ -308,6 +313,7 @@ CPLXMLNode *GDALMultiDomainMetadata::Serialize()
         if( !bFormatXML )
         {
             CPLXMLNode* psLastChild = NULL;
+            // To go after domain attribute
             if( psMD->psChild != NULL )
             {
                 psLastChild = psMD->psChild;
@@ -344,4 +350,3 @@ CPLXMLNode *GDALMultiDomainMetadata::Serialize()
 
     return psFirst;
 }
-
diff --git a/gcore/gdalnodatamaskband.cpp b/gcore/gdalnodatamaskband.cpp
index 88c3c3f..56b348b 100644
--- a/gcore/gdalnodatamaskband.cpp
+++ b/gcore/gdalnodatamaskband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalnodatamaskband.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalnodatamaskband.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALNoDataMaskBand, a class implementing all
@@ -31,7 +31,7 @@
 
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalnodatamaskband.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalnodatamaskband.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                        GDALNoDataMaskBand()                          */
@@ -142,7 +142,8 @@ CPLErr GDALNoDataMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff,
                                nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
                                nXSizeRequest, nYSizeRequest,
                                pabySrc, nXSizeRequest, nYSizeRequest,
-                               eWrkDT, 0, nBlockXSize * (GDALGetDataTypeSize(eWrkDT)/8) );
+                               eWrkDT, 0, nBlockXSize * (GDALGetDataTypeSize(eWrkDT)/8),
+                               NULL );
     if( eErr != CE_None )
     {
         CPLFree(pabySrc);
@@ -249,7 +250,8 @@ CPLErr GDALNoDataMaskBand::IRasterIO( GDALRWFlag eRWFlag,
                                       int nXOff, int nYOff, int nXSize, int nYSize,
                                       void * pData, int nBufXSize, int nBufYSize,
                                       GDALDataType eBufType,
-                                      int nPixelSpace, int nLineSpace )
+                                      GSpacing nPixelSpace, GSpacing nLineSpace,
+                                      GDALRasterIOExtraArg* psExtraArg )
 {
     /* Optimization in common use case (#4488) */
     /* This avoids triggering the block cache on this band, which helps */
@@ -262,7 +264,7 @@ CPLErr GDALNoDataMaskBand::IRasterIO( GDALRWFlag eRWFlag,
         CPLErr eErr = poParent->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize,
                                           pData, nBufXSize, nBufYSize,
                                           eBufType,
-                                          nPixelSpace, nLineSpace );
+                                          nPixelSpace, nLineSpace, psExtraArg );
         if (eErr != CE_None)
             return eErr;
 
@@ -282,5 +284,5 @@ CPLErr GDALNoDataMaskBand::IRasterIO( GDALRWFlag eRWFlag,
     return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                       pData, nBufXSize, nBufYSize,
                                       eBufType,
-                                      nPixelSpace, nLineSpace );
+                                      nPixelSpace, nLineSpace, psExtraArg );
 }
diff --git a/gcore/gdalnodatavaluesmaskband.cpp b/gcore/gdalnodatavaluesmaskband.cpp
index 4bf5fe1..42a07f1 100644
--- a/gcore/gdalnodatavaluesmaskband.cpp
+++ b/gcore/gdalnodatavaluesmaskband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalnodatavaluesmaskband.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalnodatavaluesmaskband.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALNoDataValuesMaskBand, a class implementing 
@@ -32,7 +32,7 @@
 
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalnodatavaluesmaskband.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalnodatavaluesmaskband.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                   GDALNoDataValuesMaskBand()                         */
@@ -48,7 +48,7 @@ GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand( GDALDataset* poDS )
     padfNodataValues = (double*)CPLMalloc(sizeof(double) * poDS->GetRasterCount());
     for(i=0;i<poDS->GetRasterCount();i++)
     {
-        padfNodataValues[i] = atof(papszNoDataValues[i]);
+        padfNodataValues[i] = CPLAtof(papszNoDataValues[i]);
     }
 
     CSLDestroy(papszNoDataValues);
@@ -159,7 +159,8 @@ CPLErr GDALNoDataValuesMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff,
                                    nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
                                    nXSizeRequest, nYSizeRequest,
                                    pabySrc + iBand * nBandOffsetByte, nXSizeRequest, nYSizeRequest,
-                                   eWrkDT, 0, nBlockXSize * (GDALGetDataTypeSize(eWrkDT)/8) );
+                                   eWrkDT, 0, nBlockXSize * (GDALGetDataTypeSize(eWrkDT)/8),
+                                   NULL);
         if( eErr != CE_None )
             return eErr;
     }
diff --git a/gcore/gdalopeninfo.cpp b/gcore/gdalopeninfo.cpp
index 92d5567..6211947 100644
--- a/gcore/gdalopeninfo.cpp
+++ b/gcore/gdalopeninfo.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalopeninfo.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalopeninfo.cpp 29107 2015-05-02 11:23:26Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALOpenInfo class.
@@ -35,7 +35,7 @@
 #include <unistd.h>
 #endif
 
-CPL_CVSID("$Id: gdalopeninfo.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalopeninfo.cpp 29107 2015-05-02 11:23:26Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -47,7 +47,7 @@ CPL_CVSID("$Id: gdalopeninfo.cpp 27044 2014-03-16 23:41:27Z rouault $");
 /*                            GDALOpenInfo()                            */
 /************************************************************************/
 
-GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, GDALAccess eAccessIn,
+GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, int nOpenFlagsIn,
                             char **papszSiblingsIn )
 
 {
@@ -73,11 +73,14 @@ GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, GDALAccess eAccessIn,
 /* -------------------------------------------------------------------- */
 
     nHeaderBytes = 0;
+    nHeaderBytesTried = 0;
     pabyHeader = NULL;
     bIsDirectory = FALSE;
     bStatOK = FALSE;
-    eAccess = eAccessIn;
-    fp = NULL;
+    nOpenFlags = nOpenFlagsIn;
+    eAccess = (nOpenFlags & GDAL_OF_UPDATE) ? GA_Update : GA_ReadOnly;
+    fpL = NULL;
+    papszOpenOptions = NULL;
 
 #ifdef HAVE_READLINK
     int  bHasRetried = FALSE;
@@ -91,76 +94,96 @@ GDALOpenInfo::GDALOpenInfo( const char * pszFilenameIn, GDALAccess eAccessIn,
 #ifdef HAVE_READLINK
 retry:
 #endif
-    if( VSIStatExL( pszFilename, &sStat,
-                    VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 )
+    int bPotentialDirectory = FALSE;
+
+    /* Check if the filename might be a directory of a special virtual file system */
+    if( strncmp(pszFilename, "/vsizip/", strlen("/vsizip/")) == 0 ||
+        strncmp(pszFilename, "/vsitar/", strlen("/vsitar/")) == 0 )
     {
-        bStatOK = TRUE;
+        const char* pszExt = CPLGetExtension(pszFilename);
+        if( EQUAL(pszExt, "zip") || EQUAL(pszExt, "tar") || EQUAL(pszExt, "gz") )
+            bPotentialDirectory = TRUE;
+    }
+    else if( strncmp(pszFilename, "/vsicurl/", strlen("/vsicurl/")) == 0 )
+    {
+        bPotentialDirectory = TRUE;
+    }
 
-        if( VSI_ISREG( sStat.st_mode ) )
+    if( bPotentialDirectory )
+    {
+        /* For those special files, opening them with VSIFOpenL() might result */
+        /* in content, even if they should be considered as directories, so */
+        /* use stat */
+        if( VSIStatExL( pszFilename, &sStat,
+                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 )
         {
-            pabyHeader = (GByte *) CPLCalloc(1025,1);
-
-            fp = VSIFOpen( pszFilename, "rb" );
+            bStatOK = TRUE;
+            if( VSI_ISDIR( sStat.st_mode ) )
+                bIsDirectory = TRUE;
+        }
+    }
 
-            if( fp != NULL )
-            {
-                nHeaderBytes = (int) VSIFRead( pabyHeader, 1, 1024, fp );
+    if( !bIsDirectory )
+        fpL = VSIFOpenL( pszFilename, (eAccess == GA_Update) ? "r+b" : "rb" );
+    if( fpL != NULL )
+    {
+        bStatOK = TRUE;
+        pabyHeader = (GByte *) CPLCalloc(1025,1);
+        nHeaderBytesTried = 1024;
+        nHeaderBytes = (int) VSIFReadL( pabyHeader, 1, nHeaderBytesTried, fpL );
+        VSIRewindL( fpL );
 
-                VSIRewind( fp );
-            }
-            /* XXX: ENOENT is used to catch the case of virtual filesystem
-             * when we do not have a real file with such a name. Under some
-             * circumstances EINVAL reported instead of ENOENT in Windows
-             * (for filenames containing colon, e.g. "smth://name"). 
-             * See also: #2437 */
-            else if( errno == 27 /* "File to large" */ 
-                     || errno == ENOENT || errno == EINVAL
-#ifdef EOVERFLOW
-                     || errno == EOVERFLOW
-#else
-                     || errno == 75 /* Linux EOVERFLOW */
-                     || errno == 79 /* Solaris EOVERFLOW */ 
-#endif
-                     )
-            {
-                VSILFILE* fpL = VSIFOpenL( pszFilename, "rb" );
-                if( fpL != NULL )
-                {
-                    nHeaderBytes = (int) VSIFReadL( pabyHeader, 1, 1024, fpL );
-                    VSIFCloseL( fpL );
-                }
-            }
-        }
-        else if( VSI_ISDIR( sStat.st_mode ) )
+        /* If we cannot read anything, check if it is not a directory instead */
+        if( nHeaderBytes == 0 &&
+            VSIStatExL( pszFilename, &sStat,
+                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 &&
+            VSI_ISDIR( sStat.st_mode ) )
+        {
+            VSIFCloseL(fpL);
+            fpL = NULL;
+            CPLFree(pabyHeader);
+            pabyHeader = NULL;
             bIsDirectory = TRUE;
+        }
     }
-#ifdef HAVE_READLINK
-    else if (!bHasRetried)
+    else if( !bStatOK )
     {
-        /* If someone creates a file with "ln -sf /vsicurl/http://download.osgeo.org/gdal/data/gtiff/utm.tif my_remote_utm.tif" */
-        /* we will be able to open it by passing my_remote_utm.tif */
-        /* This helps a lot for GDAL based readers that only provide file explorers to open datasets */
-        char szPointerFilename[2048];
-        int nBytes = readlink(pszFilename, szPointerFilename, sizeof(szPointerFilename));
-        if (nBytes != -1)
+        if( VSIStatExL( pszFilename, &sStat,
+                        VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) == 0 )
         {
-            szPointerFilename[MIN(nBytes, (int)sizeof(szPointerFilename)-1)] = 0;
-            CPLFree(pszFilename);
-            pszFilename = CPLStrdup(szPointerFilename);
-            papszSiblingsIn = NULL;
-            bHasRetried = TRUE;
-            goto retry;
+            bStatOK = TRUE;
+            if( VSI_ISDIR( sStat.st_mode ) )
+                bIsDirectory = TRUE;
+        }
+#ifdef HAVE_READLINK
+        else if ( !bHasRetried && strncmp(pszFilename, "/vsi", strlen("/vsi")) != 0 )
+        {
+            /* If someone creates a file with "ln -sf /vsicurl/http://download.osgeo.org/gdal/data/gtiff/utm.tif my_remote_utm.tif" */
+            /* we will be able to open it by passing my_remote_utm.tif */
+            /* This helps a lot for GDAL based readers that only provide file explorers to open datasets */
+            char szPointerFilename[2048];
+            int nBytes = readlink(pszFilename, szPointerFilename, sizeof(szPointerFilename));
+            if (nBytes != -1)
+            {
+                szPointerFilename[MIN(nBytes, (int)sizeof(szPointerFilename)-1)] = 0;
+                CPLFree(pszFilename);
+                pszFilename = CPLStrdup(szPointerFilename);
+                papszSiblingsIn = NULL;
+                bHasRetried = TRUE;
+                goto retry;
+            }
         }
-    }
 #endif
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Capture sibling list either from passed in values, or by        */
-/*      scanning for them.                                              */
+/*      scanning for them only if requested through GetSiblingFiles().  */
 /* -------------------------------------------------------------------- */
     if( papszSiblingsIn != NULL )
     {
         papszSiblingFiles = CSLDuplicate( papszSiblingsIn );
+        bHasGotSiblingFiles = TRUE;
     }
     else if( bStatOK && !bIsDirectory )
     {
@@ -169,29 +192,26 @@ retry:
         if (EQUAL(pszOptionVal, "EMPTY_DIR"))
         {
             papszSiblingFiles = CSLAddString( NULL, CPLGetFilename(pszFilename) );
+            bHasGotSiblingFiles = TRUE;
         }
         else if( CSLTestBoolean(pszOptionVal) )
         {
             /* skip reading the directory */
             papszSiblingFiles = NULL;
+            bHasGotSiblingFiles = TRUE;
         }
         else
         {
-            CPLString osDir = CPLGetDirname( pszFilename );
-            papszSiblingFiles = VSIReadDir( osDir );
-
-            /* Small optimization to avoid unnecessary stat'ing from PAux or ENVI */
-            /* drivers. The MBTiles driver needs no companion file. */
-            if( papszSiblingFiles == NULL &&
-                strncmp(pszFilename, "/vsicurl/", 9) == 0 &&
-                EQUAL(CPLGetExtension( pszFilename ),"mbtiles") )
-            {
-                papszSiblingFiles = CSLAddString( NULL, CPLGetFilename(pszFilename) );
-            }
+            /* will be lazy loaded */
+            papszSiblingFiles = NULL;
+            bHasGotSiblingFiles = FALSE;
         }
     }
     else
+    {
         papszSiblingFiles = NULL;
+        bHasGotSiblingFiles = TRUE;
+    }
 }
 
 /************************************************************************/
@@ -204,8 +224,53 @@ GDALOpenInfo::~GDALOpenInfo()
     VSIFree( pabyHeader );
     CPLFree( pszFilename );
 
-    if( fp != NULL )
-        VSIFClose( fp );
+    if( fpL != NULL )
+        VSIFCloseL( fpL );
     CSLDestroy( papszSiblingFiles );
 }
 
+/************************************************************************/
+/*                         GetSiblingFiles()                            */
+/************************************************************************/
+
+char** GDALOpenInfo::GetSiblingFiles()
+{
+    if( bHasGotSiblingFiles )
+        return papszSiblingFiles;
+    bHasGotSiblingFiles = TRUE;
+
+    CPLString osDir = CPLGetDirname( pszFilename );
+    papszSiblingFiles = VSIReadDir( osDir );
+
+    /* Small optimization to avoid unnecessary stat'ing from PAux or ENVI */
+    /* drivers. The MBTiles driver needs no companion file. */
+    if( papszSiblingFiles == NULL &&
+        strncmp(pszFilename, "/vsicurl/", 9) == 0 &&
+        EQUAL(CPLGetExtension( pszFilename ),"mbtiles") )
+    {
+        papszSiblingFiles = CSLAddString( NULL, CPLGetFilename(pszFilename) );
+    }
+
+    return papszSiblingFiles;
+}
+
+
+/************************************************************************/
+/*                           TryToIngest()                              */
+/************************************************************************/
+
+int GDALOpenInfo::TryToIngest(int nBytes)
+{
+    if( fpL == NULL )
+        return FALSE;
+    if( nHeaderBytes < nHeaderBytesTried )
+        return TRUE;
+    pabyHeader = (GByte*) CPLRealloc(pabyHeader, nBytes + 1);
+    memset(pabyHeader, 0, nBytes + 1);
+    VSIRewindL(fpL);
+    nHeaderBytesTried = nBytes;
+    nHeaderBytes = (int) VSIFReadL(pabyHeader, 1, nBytes, fpL);
+    VSIRewindL(fpL);
+
+    return TRUE;
+}
diff --git a/gcore/gdaloverviewdataset.cpp b/gcore/gdaloverviewdataset.cpp
new file mode 100644
index 0000000..de93452
--- /dev/null
+++ b/gcore/gdaloverviewdataset.cpp
@@ -0,0 +1,570 @@
+/******************************************************************************
+ * $Id: gdaloverviewdataset.cpp 29128 2015-05-03 13:21:49Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Implementation of a dataset overview warping class
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "gdal_proxy.h"
+#include "gdal_mdreader.h"
+
+CPL_CVSID("$Id: gdaloverviewdataset.cpp 29128 2015-05-03 13:21:49Z rouault $");
+
+/** In GDAL, GDALRasterBand::GetOverview() returns a stand-alone band, that
+    may have no parent dataset. This can be inconvenient in certain contexts, where
+    cross-band processing must be done, or when API expect a fully fledge dataset.
+    Furthermore even if overview band has a container dataset, that one often
+    fails to declare its projection, geotransform, etc... which make it somehow
+    useless. GDALOverviewDataset remedies to those deficiencies.
+*/
+
+class GDALOverviewBand;
+
+/* ******************************************************************** */
+/*                          GDALOverviewDataset                         */
+/* ******************************************************************** */
+
+class GDALOverviewDataset : public GDALDataset
+{
+    private:
+
+        friend class GDALOverviewBand;
+
+        GDALDataset* poMainDS;
+        int          bOwnDS;
+
+        GDALDataset* poOvrDS; /* will be often NULL */
+        int          nOvrLevel;
+        int          bThisLevelOnly;
+
+        int          nGCPCount;
+        GDAL_GCP    *pasGCPList;
+        char       **papszMD_RPC;
+        char       **papszMD_GEOLOCATION;
+
+        static void  Rescale(char**& papszMD, const char* pszItem,
+                             double dfRatio, double dfDefaultVal);
+
+    protected:
+        virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
+                                void *, int, int, GDALDataType,
+                                int, int *,
+                                GSpacing, GSpacing, GSpacing,
+                                GDALRasterIOExtraArg* psExtraArg );
+
+    public:
+                        GDALOverviewDataset(GDALDataset* poMainDS, int nOvrLevel,
+                                            int bThisLevelOnly,
+                                            int bOwnDS);
+        virtual        ~GDALOverviewDataset();
+
+        virtual const char *GetProjectionRef(void);
+        virtual CPLErr GetGeoTransform( double * );
+
+        virtual int    GetGCPCount();
+        virtual const char *GetGCPProjection();
+        virtual const GDAL_GCP *GetGCPs();
+
+        virtual char  **GetMetadata( const char * pszDomain = "" );
+        virtual const char *GetMetadataItem( const char * pszName,
+                                             const char * pszDomain = "" );
+
+        virtual int        CloseDependentDatasets();
+};
+
+/* ******************************************************************** */
+/*                           GDALOverviewBand                           */
+/* ******************************************************************** */
+
+class GDALOverviewBand : public GDALProxyRasterBand
+{
+    protected:
+        friend class GDALOverviewDataset;
+
+        GDALRasterBand*         poUnderlyingBand;
+        virtual GDALRasterBand* RefUnderlyingRasterBand();
+
+    public:
+                    GDALOverviewBand(GDALOverviewDataset* poDS, int nBand);
+        virtual    ~GDALOverviewBand();
+
+        virtual CPLErr FlushCache();
+
+        virtual int GetOverviewCount();
+        virtual GDALRasterBand *GetOverview(int);
+};
+
+/************************************************************************/
+/*                       GDALCreateOverviewDataset()                    */
+/************************************************************************/
+
+GDALDataset* GDALCreateOverviewDataset(GDALDataset* poMainDS, int nOvrLevel,
+                                       int bThisLevelOnly, int bOwnDS)
+{
+    /* Sanity checks */
+    int nBands = poMainDS->GetRasterCount();
+    if( nBands == 0 )
+        return NULL;
+
+    for(int i = 1; i<= nBands; i++ )
+    {
+        if( poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel) == NULL )
+        {
+            return NULL;
+        }
+        if( poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel)->GetXSize() !=
+            poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize() ||
+            poMainDS->GetRasterBand(i)->GetOverview(nOvrLevel)->GetYSize() !=
+            poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize() )
+        {
+            return NULL;
+        }
+    }
+
+    return new GDALOverviewDataset(poMainDS, nOvrLevel, bThisLevelOnly, bOwnDS);
+}
+
+/************************************************************************/
+/*                        GDALOverviewDataset()                         */
+/************************************************************************/
+
+GDALOverviewDataset::GDALOverviewDataset(GDALDataset* poMainDS,
+                                         int nOvrLevel,
+                                         int bThisLevelOnly,
+                                         int bOwnDS)
+{
+    this->poMainDS = poMainDS;
+    this->nOvrLevel = nOvrLevel;
+    this->bOwnDS = bOwnDS;
+    this->bThisLevelOnly = bThisLevelOnly;
+    eAccess = poMainDS->GetAccess();
+    nRasterXSize = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize();
+    nRasterYSize = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize();
+    poOvrDS = poMainDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetDataset();
+    if( poOvrDS != NULL && poOvrDS == poMainDS )
+    {
+        CPLDebug("GDAL", "Dataset of overview is the same as the main band. This is not expected");
+        poOvrDS = NULL;
+    }
+    nBands = poMainDS->GetRasterCount();
+    for(int i=0;i<nBands;i++)
+    {
+        SetBand(i+1, new GDALOverviewBand(this, i+1));
+    }
+    nGCPCount = 0;
+    pasGCPList = NULL;
+    papszMD_RPC = NULL;
+    papszMD_GEOLOCATION = NULL;
+
+    /* We create a fake driver that has the same name as the original */
+    /* one, but we cannot use the real driver object, so that code */
+    /* doesn't try to cast the GDALOverviewDataset* as a native dataset */
+    /* object */
+    if( poMainDS->GetDriver() != NULL )
+    {
+        poDriver = new GDALDriver();
+        poDriver->SetDescription(poMainDS->GetDriver()->GetDescription());
+        poDriver->SetMetadata(poMainDS->GetDriver()->GetMetadata());
+    }
+
+    SetDescription( poMainDS->GetDescription() );
+
+    CPLDebug( "GDAL", "GDALOverviewDataset(%s, this=%p) creation.",
+                          poMainDS->GetDescription(), this );
+
+    papszOpenOptions = CSLDuplicate(poMainDS->GetOpenOptions());
+    /* Add OVERVIEW_LEVEL if not called from GDALOpenEx() but directly */
+    papszOpenOptions = CSLSetNameValue(papszOpenOptions, "OVERVIEW_LEVEL",
+                                       CPLSPrintf("%d", nOvrLevel));
+}
+
+/************************************************************************/
+/*                       ~GDALOverviewDataset()                         */
+/************************************************************************/
+
+GDALOverviewDataset::~GDALOverviewDataset()
+{
+    FlushCache();
+
+    CloseDependentDatasets();
+
+    if( nGCPCount > 0 )
+    {
+        GDALDeinitGCPs( nGCPCount, pasGCPList );
+        CPLFree( pasGCPList );
+    }
+    CSLDestroy(papszMD_RPC);
+
+    CSLDestroy(papszMD_GEOLOCATION);
+
+    delete poDriver;
+}
+
+/************************************************************************/
+/*                      CloseDependentDatasets()                        */
+/************************************************************************/
+
+int GDALOverviewDataset::CloseDependentDatasets()
+{
+    int bRet = FALSE;
+
+    if( bOwnDS )
+    {
+        for(int i=0;i<nBands;i++)
+        {
+            ((GDALOverviewBand*)papoBands[i])->poUnderlyingBand = NULL;
+        }
+        GDALClose( poMainDS );
+        poMainDS = NULL;
+        bOwnDS = FALSE;
+        bRet = TRUE;
+    }
+
+    return bRet;
+}
+
+/************************************************************************/
+/*                             IRasterIO()                              */
+/*                                                                      */
+/*      The default implementation of IRasterIO() is to pass the        */
+/*      request off to each band objects rasterio methods with          */
+/*      appropriate arguments.                                          */
+/************************************************************************/
+
+CPLErr GDALOverviewDataset::IRasterIO( GDALRWFlag eRWFlag,
+                               int nXOff, int nYOff, int nXSize, int nYSize,
+                               void * pData, int nBufXSize, int nBufYSize,
+                               GDALDataType eBufType, 
+                               int nBandCount, int *panBandMap,
+                               GSpacing nPixelSpace, GSpacing nLineSpace,
+                               GSpacing nBandSpace,
+                               GDALRasterIOExtraArg* psExtraArg)
+    
+{
+    int iBandIndex; 
+    CPLErr eErr = CE_None;
+
+    /* In case the overview bands are really linked to a dataset, then issue */
+    /* the request to that dataset */
+    if( poOvrDS != NULL )
+    {
+        return poOvrDS->RasterIO(
+            eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
+            eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
+            psExtraArg);
+    }
+
+    GDALProgressFunc  pfnProgressGlobal = psExtraArg->pfnProgress;
+    void             *pProgressDataGlobal = psExtraArg->pProgressData;
+
+    for( iBandIndex = 0; 
+         iBandIndex < nBandCount && eErr == CE_None; 
+         iBandIndex++ )
+    {
+        GDALOverviewBand *poBand = (GDALOverviewBand*) GetRasterBand(panBandMap[iBandIndex]);
+        GByte *pabyBandData;
+
+        if (poBand == NULL)
+        {
+            eErr = CE_Failure;
+            break;
+        }
+
+        pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
+
+        psExtraArg->pfnProgress = GDALScaledProgress;
+        psExtraArg->pProgressData = 
+            GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
+                                      1.0 * (iBandIndex + 1) / nBandCount,
+                                      pfnProgressGlobal,
+                                      pProgressDataGlobal );
+
+        eErr = poBand->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
+                                  (void *) pabyBandData, nBufXSize, nBufYSize,
+                                  eBufType, nPixelSpace, nLineSpace, psExtraArg );
+
+        GDALDestroyScaledProgress( psExtraArg->pProgressData );
+    }
+    
+    psExtraArg->pfnProgress = pfnProgressGlobal;
+    psExtraArg->pProgressData = pProgressDataGlobal;
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                          GetProjectionRef()                          */
+/************************************************************************/
+
+const char *GDALOverviewDataset::GetProjectionRef()
+
+{
+    return poMainDS->GetProjectionRef();
+}
+
+/************************************************************************/
+/*                          GetGeoTransform()                           */
+/************************************************************************/
+
+CPLErr GDALOverviewDataset::GetGeoTransform( double * padfTransform )
+
+{
+    double adfGeoTransform[6];
+    if( poMainDS->GetGeoTransform(adfGeoTransform) == CE_None )
+    {
+        if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0 )
+        {
+            adfGeoTransform[1] *= (double)poMainDS->GetRasterXSize() / nRasterXSize;
+            adfGeoTransform[5] *= (double)poMainDS->GetRasterYSize() / nRasterYSize;
+        }
+        else
+        {
+            /* If the x and y ratios are not equal, then we cannot really */
+            /* compute a geotransform */
+            double dfRatio = (double)poMainDS->GetRasterXSize() / nRasterXSize;
+            adfGeoTransform[1] *= dfRatio;
+            adfGeoTransform[2] *= dfRatio;
+            adfGeoTransform[4] *= dfRatio;
+            adfGeoTransform[5] *= dfRatio;
+        }
+        memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
+
+        return CE_None;
+    }
+    else
+        return CE_Failure;
+}
+
+/************************************************************************/
+/*                            GetGCPCount()                             */
+/************************************************************************/
+
+int GDALOverviewDataset::GetGCPCount()
+
+{
+    return poMainDS->GetGCPCount();
+}
+
+/************************************************************************/
+/*                          GetGCPProjection()                          */
+/************************************************************************/
+
+const char *GDALOverviewDataset::GetGCPProjection()
+
+{
+    return poMainDS->GetGCPProjection();
+}
+
+/************************************************************************/
+/*                               GetGCPs()                              */
+/************************************************************************/
+
+const GDAL_GCP *GDALOverviewDataset::GetGCPs()
+
+{
+    if( pasGCPList != NULL )
+        return pasGCPList;
+    
+    const GDAL_GCP* pasGCPsMain = poMainDS->GetGCPs();
+    if( pasGCPsMain == NULL )
+        return NULL;
+    nGCPCount = poMainDS->GetGCPCount();
+
+    pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPsMain );
+    for(int i = 0; i < nGCPCount; i++)
+    {
+        pasGCPList[i].dfGCPPixel *= (double)nRasterXSize / poMainDS->GetRasterXSize();
+        pasGCPList[i].dfGCPLine *= (double)nRasterYSize / poMainDS->GetRasterYSize();
+    }
+    return pasGCPList;
+}
+
+/************************************************************************/
+/*                             Rescale()                                */
+/************************************************************************/
+
+void GDALOverviewDataset::Rescale(char**& papszMD, const char* pszItem,
+                                  double dfRatio, double dfDefaultVal)
+{
+    double dfVal = CPLAtofM(CSLFetchNameValueDef(papszMD, pszItem,
+                                            CPLSPrintf("%.18g", dfDefaultVal)));
+    dfVal *= dfRatio;
+    papszMD = CSLSetNameValue(papszMD, pszItem, CPLSPrintf("%.18g", dfVal));
+}
+
+/************************************************************************/
+/*                            GetMetadata()                             */
+/************************************************************************/
+
+char  **GDALOverviewDataset::GetMetadata( const char * pszDomain )
+{
+    char** papszMD;
+    if (poOvrDS != NULL)
+    {
+        papszMD = poOvrDS->GetMetadata(pszDomain);
+        if( papszMD != NULL )
+            return papszMD;
+    }
+
+    papszMD = poMainDS->GetMetadata(pszDomain);
+
+    /* We may need to rescale some values from the RPC metadata domain */
+    if( pszDomain != NULL && EQUAL(pszDomain, MD_DOMAIN_RPC) && papszMD != NULL )
+    {
+        if( papszMD_RPC )
+            return papszMD_RPC;
+        papszMD_RPC = CSLDuplicate(papszMD);
+
+        Rescale(papszMD_RPC, RPC_LINE_OFF,
+                (double)nRasterYSize / poMainDS->GetRasterYSize(), 0.0);
+        Rescale(papszMD_RPC, RPC_LINE_SCALE,
+                (double)nRasterYSize / poMainDS->GetRasterYSize(), 1.0);
+        Rescale(papszMD_RPC, RPC_SAMP_OFF,
+                (double)nRasterXSize / poMainDS->GetRasterXSize(), 0.0);
+        Rescale(papszMD_RPC, RPC_SAMP_SCALE,
+                (double)nRasterXSize / poMainDS->GetRasterXSize(), 1.0);
+
+        papszMD = papszMD_RPC;
+    }
+
+    /* We may need to rescale some values from the GEOLOCATION metadata domain */
+    if( pszDomain != NULL && EQUAL(pszDomain, "GEOLOCATION") && papszMD != NULL )
+    {
+        if( papszMD_GEOLOCATION )
+            return papszMD_GEOLOCATION;
+        papszMD_GEOLOCATION = CSLDuplicate(papszMD);
+
+        Rescale(papszMD_GEOLOCATION, "PIXEL_OFFSET",
+                (double)poMainDS->GetRasterXSize() / nRasterXSize, 0.0);
+        Rescale(papszMD_GEOLOCATION, "LINE_OFFSET",
+                (double)poMainDS->GetRasterYSize() / nRasterYSize, 0.0);
+
+        Rescale(papszMD_GEOLOCATION, "PIXEL_STEP",
+                (double)nRasterXSize / poMainDS->GetRasterXSize(), 1.0);
+        Rescale(papszMD_GEOLOCATION, "LINE_STEP",
+                (double)nRasterYSize / poMainDS->GetRasterYSize(), 1.0);
+
+        papszMD = papszMD_GEOLOCATION;
+    }
+
+    return papszMD;
+}
+
+/************************************************************************/
+/*                          GetMetadataItem()                           */
+/************************************************************************/
+
+const char *GDALOverviewDataset::GetMetadataItem( const char * pszName,
+                                                  const char * pszDomain )
+{
+    if (poOvrDS != NULL)
+    {
+        const char* pszValue = poOvrDS->GetMetadataItem(pszName, pszDomain);
+        if( pszValue != NULL )
+            return pszValue;
+    }
+
+    if( pszDomain != NULL && (EQUAL(pszDomain, "RPC") ||
+                              EQUAL(pszDomain, "GEOLOCATION")) )
+    {
+        char** papszMD = GetMetadata(pszDomain);
+        return CSLFetchNameValue(papszMD, pszName);
+    }
+
+    return poMainDS->GetMetadataItem(pszName, pszDomain);
+}
+
+/************************************************************************/
+/*                          GDALOverviewBand()                          */
+/************************************************************************/
+
+GDALOverviewBand::GDALOverviewBand(GDALOverviewDataset* poDS, int nBand)
+{
+    this->poDS = poDS;
+    this->nBand = nBand;
+    poUnderlyingBand = poDS->poMainDS->GetRasterBand(nBand)->GetOverview(poDS->nOvrLevel);
+    nRasterXSize = poDS->nRasterXSize;
+    nRasterYSize = poDS->nRasterYSize;
+    eDataType = poUnderlyingBand->GetRasterDataType();
+    poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
+}
+
+/************************************************************************/
+/*                         ~GDALOverviewBand()                          */
+/************************************************************************/
+
+GDALOverviewBand::~GDALOverviewBand()
+{
+    FlushCache();
+}
+
+/************************************************************************/
+/*                              FlushCache()                            */
+/************************************************************************/
+
+CPLErr GDALOverviewBand::FlushCache()
+{
+    if( ((GDALOverviewDataset*)poDS)->poMainDS )
+        return poUnderlyingBand->FlushCache();
+    return CE_None;
+}
+
+/************************************************************************/
+/*                        RefUnderlyingRasterBand()                     */
+/************************************************************************/
+
+GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
+{
+    if( ((GDALOverviewDataset*)poDS)->poMainDS )
+        return poUnderlyingBand;
+    else
+        return NULL;
+}
+
+/************************************************************************/
+/*                         GetOverviewCount()                           */
+/************************************************************************/
+
+int GDALOverviewBand::GetOverviewCount()
+{
+    GDALOverviewDataset* poOvrDS = (GDALOverviewDataset*)poDS;
+    if( poOvrDS->bThisLevelOnly )
+        return 0;
+    GDALDataset* poMainDS = poOvrDS->poMainDS;
+    return poMainDS->GetRasterBand(nBand)->GetOverviewCount() - poOvrDS->nOvrLevel - 1;
+}
+
+/************************************************************************/
+/*                           GetOverview()                              */
+/************************************************************************/
+
+GDALRasterBand *GDALOverviewBand::GetOverview(int iOvr)
+{
+    if( iOvr < 0 || iOvr >= GetOverviewCount() )
+        return NULL;
+    GDALOverviewDataset* poOvrDS = (GDALOverviewDataset*)poDS;
+    GDALDataset* poMainDS = poOvrDS->poMainDS;
+    return poMainDS->GetRasterBand(nBand)->GetOverview(iOvr + poOvrDS->nOvrLevel + 1);
+}
diff --git a/gcore/gdalpamdataset.cpp b/gcore/gdalpamdataset.cpp
index df3c4fb..4945070 100644
--- a/gcore/gdalpamdataset.cpp
+++ b/gcore/gdalpamdataset.cpp
@@ -1,9 +1,9 @@
 /******************************************************************************
- * $Id: gdalpamdataset.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalpamdataset.cpp 29038 2015-04-28 09:03:36Z rouault $
  *
  * Project:  GDAL Core
- * Purpose:  Implementation of GDALPamDataset, a dataset base class that 
- *           knows how to persist auxilary metadata into a support XML file.
+ * Purpose:  Implementation of GDALPamDataset, a dataset base class that
+ *           knows how to persist auxiliary metadata into a support XML file.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ogr_spatialref.h"
 
-CPL_CVSID("$Id: gdalpamdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalpamdataset.cpp 29038 2015-04-28 09:03:36Z rouault $");
 
 /************************************************************************/
 /*                           GDALPamDataset()                           */
@@ -43,8 +43,8 @@ CPL_CVSID("$Id: gdalpamdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
  * \class GDALPamDataset "gdal_pam.h"
  * 
  * A subclass of GDALDataset which introduces the ability to save and
- * restore auxilary information (coordinate system, gcps, metadata, 
- * etc) not supported by a file format via an "auxilary metadata" file
+ * restore auxiliary information (coordinate system, gcps, metadata, 
+ * etc) not supported by a file format via an "auxiliary metadata" file
  * with the .aux.xml extension.  
  * 
  * <h3>Enabling PAM</h3>
@@ -55,8 +55,8 @@ CPL_CVSID("$Id: gdalpamdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
  * to YES in Windows and Unix builds.
  *
  * <h3>PAM Proxy Files</h3>
- * 
- * In order to be able to record auxilary information about files on 
+ *
+ * In order to be able to record auxiliary information about files on
  * read-only media such as CDROMs or in directories where the user does not
  * have write permissions, it is possible to enable the "PAM Proxy Database".
  * When enabled the .aux.xml files are kept in a different directory, writable
@@ -69,8 +69,8 @@ CPL_CVSID("$Id: gdalpamdataset.cpp 27044 2014-03-16 23:41:27Z rouault $");
  *
  * <h3>Adding PAM to Drivers</h3>
  *
- * Drivers for physical file formats that wish to support persistent auxilary 
- * metadata in addition to that for the format itself should derive their 
+ * Drivers for physical file formats that wish to support persistent auxiliary
+ * metadata in addition to that for the format itself should derive their
  * dataset class from GDALPamDataset instead of directly from GDALDataset.
  * The raster band classes should also be derived from GDALPamRasterBand.
  *
@@ -204,15 +204,15 @@ CPLXMLNode *GDALPamDataset::SerializeToXML( const char *pszUnused )
 /* -------------------------------------------------------------------- */
 /*      Metadata.                                                       */
 /* -------------------------------------------------------------------- */
-    CPLXMLNode *psMD;
-
-    psMD = oMDMD.Serialize();
-    if( psMD != NULL )
+    if( psPam->bHasMetadata )
     {
-        if( psMD->psChild == NULL && psMD->psNext == NULL )
-            CPLDestroyXMLNode( psMD );
-        else
+        CPLXMLNode *psMD;
+
+        psMD = oMDMD.Serialize();
+        if( psMD != NULL )
+        {
             CPLAddXMLChild( psDSTree, psMD );
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -294,6 +294,7 @@ void GDALPamDataset::PamInitialize()
     psPam->nGCPCount = 0;
     psPam->pasGCPList = NULL;
     psPam->pszGCPProjection = NULL;
+    psPam->bHasMetadata = FALSE;
 
     int iBand;
     
@@ -371,7 +372,7 @@ CPLErr GDALPamDataset::XMLInit( CPLXMLNode *psTree, const char *pszUnused )
         else
         {
             for( int iTA = 0; iTA < 6; iTA++ )
-                psPam->adfGeoTransform[iTA] = atof(papszTokens[iTA]);
+                psPam->adfGeoTransform[iTA] = CPLAtof(papszTokens[iTA]);
             psPam->bHaveGeoTransform = TRUE;
         }
 
@@ -566,6 +567,8 @@ const char *GDALPamDataset::BuildPamFilename()
         psPam->pszPamFilename = CPLStrdup(pszProxyPam);
     else
     {
+        if( !GDALCanFileAcceptSidecarFile(pszPhysicalFile) )
+            return NULL;
         psPam->pszPamFilename = (char*) CPLMalloc(strlen(pszPhysicalFile)+10);
         strcpy( psPam->pszPamFilename, pszPhysicalFile );
         strcat( psPam->pszPamFilename, ".aux.xml" );
@@ -733,7 +736,7 @@ CPLErr GDALPamDataset::TrySaveXML()
         return CE_None;
 
 /* -------------------------------------------------------------------- */
-/*      Build the XML representation of the auxilary metadata.          */
+/*      Build the XML representation of the auxiliary metadata.          */
 /* -------------------------------------------------------------------- */
     psTree = SerializeToXML( NULL );
 
@@ -799,7 +802,7 @@ CPLErr GDALPamDataset::TrySaveXML()
     }
 
 /* -------------------------------------------------------------------- */
-/*      Try saving the auxilary metadata.                               */
+/*      Try saving the auxiliary metadata.                               */
 /* -------------------------------------------------------------------- */
     int bSaved;
     
@@ -808,7 +811,7 @@ CPLErr GDALPamDataset::TrySaveXML()
     CPLPopErrorHandler();
 
 /* -------------------------------------------------------------------- */
-/*      If it fails, check if we have a proxy directory for auxilary    */
+/*      If it fails, check if we have a proxy directory for auxiliary    */
 /*      metadata to be stored in, and try to save there.                */
 /* -------------------------------------------------------------------- */
     if( bSaved )
@@ -829,10 +832,11 @@ CPLErr GDALPamDataset::TrySaveXML()
             psPam->pszPamFilename = CPLStrdup(pszNewPam);
             eErr = TrySaveXML();
         }
-        else
+        /* No way we can save into a /vsicurl resource */
+        else if( strncmp(psPam->pszPamFilename, "/vsicurl", strlen("/vsicurl")) != 0 )
         {
             CPLError( CE_Warning, CPLE_AppDefined, 
-                      "Unable to save auxilary information in %s.",
+                      "Unable to save auxiliary information in %s.",
                       psPam->pszPamFilename );
             eErr = CE_Warning;
         }
@@ -859,7 +863,7 @@ CPLErr GDALPamDataset::CloneInfo( GDALDataset *poSrcDS, int nCloneFlags )
     PamInitialize();
 
 /* -------------------------------------------------------------------- */
-/*      Supress NotImplemented error messages - mainly needed if PAM    */
+/*      Suppress NotImplemented error messages - mainly needed if PAM   */
 /*      disabled.                                                       */
 /* -------------------------------------------------------------------- */
     SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
@@ -1218,7 +1222,10 @@ CPLErr GDALPamDataset::SetMetadata( char **papszMetadata,
     PamInitialize();
 
     if( psPam )
+    {
+        psPam->bHasMetadata = TRUE;
         MarkPamDirty();
+    }
 
     return GDALDataset::SetMetadata( papszMetadata, pszDomain );
 }
@@ -1235,7 +1242,10 @@ CPLErr GDALPamDataset::SetMetadataItem( const char *pszName,
     PamInitialize();
 
     if( psPam )
+    {
+        psPam->bHasMetadata = TRUE;
         MarkPamDirty();
+    }
 
     return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
 }
@@ -1447,7 +1457,8 @@ CPLErr GDALPamDataset::TryLoadAux(char **papszSiblingFiles)
 
         // histograms?
         double dfMin, dfMax;
-        int nBuckets, *panHistogram=NULL;
+        int nBuckets;
+        GUIntBig *panHistogram=NULL;
 
         if( poAuxBand->GetDefaultHistogram( &dfMin, &dfMax, 
                                             &nBuckets, &panHistogram,
diff --git a/gcore/gdalpamproxydb.cpp b/gcore/gdalpamproxydb.cpp
index b771f74..4491519 100644
--- a/gcore/gdalpamproxydb.cpp
+++ b/gcore/gdalpamproxydb.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalpamproxydb.cpp 22812 2011-07-25 04:50:23Z warmerdam $
+ * $Id: gdalpamproxydb.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of the GDAL PAM Proxy database interface.
@@ -35,7 +35,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gdalpamproxydb.cpp 22812 2011-07-25 04:50:23Z warmerdam $");
+CPL_CVSID("$Id: gdalpamproxydb.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -62,7 +62,7 @@ class GDALPamProxyDB
 
 static int bProxyDBInitialized = FALSE;
 static GDALPamProxyDB *poProxyDB = NULL;
-static void *hProxyDBLock = NULL;
+static CPLMutex *hProxyDBLock = NULL;
 
 /************************************************************************/
 /*                            CheckLoadDB()                             */
diff --git a/gcore/gdalpamrasterband.cpp b/gcore/gdalpamrasterband.cpp
index e83d9cf..f69be18 100644
--- a/gcore/gdalpamrasterband.cpp
+++ b/gcore/gdalpamrasterband.cpp
@@ -1,9 +1,9 @@
 /******************************************************************************
- * $Id: gdalpamrasterband.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdalpamrasterband.cpp 29038 2015-04-28 09:03:36Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALPamRasterBand, a raster band base class
- *           that knows how to persistently store auxilary metadata in an
+ *           that knows how to persistently store auxiliary metadata in an
  *           external xml file. 
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
@@ -34,7 +34,7 @@
 #include "gdal_rat.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: gdalpamrasterband.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdalpamrasterband.cpp 29038 2015-04-28 09:03:36Z rouault $");
 
 /************************************************************************/
 /*                         GDALPamRasterBand()                          */
@@ -62,7 +62,6 @@ GDALPamRasterBand::~GDALPamRasterBand()
 /************************************************************************/
 
 CPLXMLNode *GDALPamRasterBand::SerializeToXML( CPL_UNUSED const char *pszUnused )
-
 {
     if( psPam == NULL )
         return NULL;
@@ -95,7 +94,7 @@ CPLXMLNode *GDALPamRasterBand::SerializeToXML( CPL_UNUSED const char *pszUnused
 
         /* hex encode real floating point values */
         if( psPam->dfNoDataValue != floor(psPam->dfNoDataValue) 
-            || psPam->dfNoDataValue != atof(oFmt) )
+            || psPam->dfNoDataValue != CPLAtof(oFmt) )
         {
             double dfNoDataLittleEndian;
 
@@ -221,10 +220,7 @@ CPLXMLNode *GDALPamRasterBand::SerializeToXML( CPL_UNUSED const char *pszUnused
     psMD = oMDMD.Serialize();
     if( psMD != NULL )
     {
-        if( psMD->psChild == NULL )
-            CPLDestroyXMLNode( psMD );
-        else
-            CPLAddXMLChild( psTree, psMD );
+        CPLAddXMLChild( psTree, psMD );
     }
 
 /* -------------------------------------------------------------------- */
@@ -310,7 +306,6 @@ void GDALPamRasterBand::PamClear()
 /************************************************************************/
 
 CPLErr GDALPamRasterBand::XMLInit( CPLXMLNode *psTree, CPL_UNUSED const char *pszUnused )
-
 {
     PamInitialize();
 
@@ -341,21 +336,21 @@ CPLErr GDALPamRasterBand::XMLInit( CPLXMLNode *psTree, CPL_UNUSED const char *ps
             else
             {
                 GDALPamRasterBand::SetNoDataValue( 
-                    atof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
+                    CPLAtof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
             }
             CPLFree( pabyBin );
         }
         else
         {
             GDALPamRasterBand::SetNoDataValue( 
-                atof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
+                CPLAtof(CPLGetXMLValue( psTree, "NoDataValue", "0" )) );
         }
     }
 
     GDALPamRasterBand::SetOffset( 
-        atof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
+        CPLAtof(CPLGetXMLValue( psTree, "Offset", "0.0" )) );
     GDALPamRasterBand::SetScale( 
-        atof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
+        CPLAtof(CPLGetXMLValue( psTree, "Scale", "1.0" )) );
 
     GDALPamRasterBand::SetUnitType( CPLGetXMLValue( psTree, "UnitType", NULL));
 
@@ -422,16 +417,16 @@ CPLErr GDALPamRasterBand::XMLInit( CPLXMLNode *psTree, CPL_UNUSED const char *ps
         && CPLGetXMLNode( psTree, "Maximum" ) != NULL )
     {
         psPam->bHaveMinMax = TRUE;
-        psPam->dfMin = atof(CPLGetXMLValue(psTree, "Minimum","0"));
-        psPam->dfMax = atof(CPLGetXMLValue(psTree, "Maximum","0"));
+        psPam->dfMin = CPLAtof(CPLGetXMLValue(psTree, "Minimum","0"));
+        psPam->dfMax = CPLAtof(CPLGetXMLValue(psTree, "Maximum","0"));
     }
 
     if( CPLGetXMLNode( psTree, "Mean" ) != NULL 
         && CPLGetXMLNode( psTree, "StandardDeviation" ) != NULL )
     {
         psPam->bHaveStats = TRUE;
-        psPam->dfMean = atof(CPLGetXMLValue(psTree, "Mean","0"));
-        psPam->dfStdDev = atof(CPLGetXMLValue(psTree,"StandardDeviation","0"));
+        psPam->dfMean = CPLAtof(CPLGetXMLValue(psTree, "Mean","0"));
+        psPam->dfStdDev = CPLAtof(CPLGetXMLValue(psTree,"StandardDeviation","0"));
     }
 
 /* -------------------------------------------------------------------- */
@@ -485,7 +480,7 @@ CPLErr GDALPamRasterBand::CloneInfo( GDALRasterBand *poSrcBand,
     PamInitialize();
 
 /* -------------------------------------------------------------------- */
-/*      Supress NotImplemented error messages - mainly needed if PAM    */
+/*      Suppress NotImplemented error messages - mainly needed if PAM   */
 /*      disabled.                                                       */
 /* -------------------------------------------------------------------- */
     SetMOFlags( nSavedMOFlags | GMO_IGNORE_UNIMPLEMENTED );
@@ -975,18 +970,20 @@ void GDALPamRasterBand::SetDescription( const char *pszDescription )
 /*                         PamParseHistogram()                          */
 /************************************************************************/
 
-int 
-PamParseHistogram( CPLXMLNode *psHistItem, 
-                   double *pdfMin, double *pdfMax, 
-                   int *pnBuckets, int **ppanHistogram, 
-                   CPL_UNUSED int *pbIncludeOutOfRange, CPL_UNUSED int *pbApproxOK )
+int
+PamParseHistogram( CPLXMLNode *psHistItem,
+                   double *pdfMin, double *pdfMax,
+                   int *pnBuckets, GUIntBig **ppanHistogram,
+                   CPL_UNUSED int *pbIncludeOutOfRange,
+                   CPL_UNUSED int *pbApproxOK )
 {
     if( psHistItem == NULL )
         return FALSE;
 
-    *pdfMin = atof(CPLGetXMLValue( psHistItem, "HistMin", "0"));
-    *pdfMax = atof(CPLGetXMLValue( psHistItem, "HistMax", "1"));
+    *pdfMin = CPLAtof(CPLGetXMLValue( psHistItem, "HistMin", "0"));
+    *pdfMax = CPLAtof(CPLGetXMLValue( psHistItem, "HistMax", "1"));
     *pnBuckets = atoi(CPLGetXMLValue( psHistItem, "BucketCount","2"));
+
     if (*pnBuckets <= 0 || *pnBuckets > INT_MAX / 2)
         return FALSE;
 
@@ -1002,11 +999,11 @@ PamParseHistogram( CPLXMLNode *psHistItem,
     if( strlen(pszHistCounts) < 2 * (size_t)(*pnBuckets) -1 )
     {
         CPLError(CE_Failure, CPLE_AppDefined,
-                 "HistCounts content isn't consistant with BucketCount value");
+                 "HistCounts content isn't consistent with BucketCount value");
         return FALSE;
     }
 
-    *ppanHistogram = (int *) VSICalloc(sizeof(int),*pnBuckets);
+    *ppanHistogram = (GUIntBig *) VSICalloc(sizeof(GUIntBig),*pnBuckets);
     if (*ppanHistogram == NULL)
     {
         CPLError(CE_Failure, CPLE_OutOfMemory,
@@ -1016,7 +1013,7 @@ PamParseHistogram( CPLXMLNode *psHistItem,
 
     for( iBucket = 0; iBucket < *pnBuckets; iBucket++ )
     {
-        (*ppanHistogram)[iBucket] = atoi(pszHistCounts);
+        (*ppanHistogram)[iBucket] = CPLAtoGIntBig(pszHistCounts);
         
         // skip to next number.
         while( *pszHistCounts != '\0' && *pszHistCounts != '|' )
@@ -1048,8 +1045,8 @@ PamFindMatchingHistogram( CPLXMLNode *psSavedHistograms,
             || !EQUAL(psXMLHist->pszValue,"HistItem") )
             continue;
 
-        double dfHistMin = atof(CPLGetXMLValue( psXMLHist, "HistMin", "0"));
-        double dfHistMax = atof(CPLGetXMLValue( psXMLHist, "HistMax", "0"));
+        double dfHistMin = CPLAtof(CPLGetXMLValue( psXMLHist, "HistMin", "0"));
+        double dfHistMax = CPLAtof(CPLGetXMLValue( psXMLHist, "HistMax", "0"));
 
         if( !(ARE_REAL_EQUAL(dfHistMin, dfMin))
             || !(ARE_REAL_EQUAL(dfHistMax, dfMax))
@@ -1074,7 +1071,7 @@ PamFindMatchingHistogram( CPLXMLNode *psSavedHistograms,
 
 CPLXMLNode *
 PamHistogramToXMLTree( double dfMin, double dfMax,
-                       int nBuckets, int * panHistogram,
+                       int nBuckets, GUIntBig * panHistogram,
                        int bIncludeOutOfRange, int bApprox )
 
 {
@@ -1107,7 +1104,7 @@ PamHistogramToXMLTree( double dfMin, double dfMax,
     pszHistCounts[0] = '\0';
     for( iBucket = 0; iBucket < nBuckets; iBucket++ )
     {
-        sprintf( pszHistCounts + iHistOffset, "%d", panHistogram[iBucket] );
+        sprintf( pszHistCounts + iHistOffset, CPL_FRMT_GUIB, panHistogram[iBucket] );
         if( iBucket < nBuckets-1 )
             strcat( pszHistCounts + iHistOffset, "|" );
         iHistOffset += strlen(pszHistCounts+iHistOffset);
@@ -1124,7 +1121,7 @@ PamHistogramToXMLTree( double dfMin, double dfMax,
 /************************************************************************/
 
 CPLErr GDALPamRasterBand::GetHistogram( double dfMin, double dfMax,
-                                        int nBuckets, int * panHistogram,
+                                        int nBuckets, GUIntBig * panHistogram,
                                         int bIncludeOutOfRange, int bApproxOK,
                                         GDALProgressFunc pfnProgress, 
                                         void *pProgressData )
@@ -1148,13 +1145,13 @@ CPLErr GDALPamRasterBand::GetHistogram( double dfMin, double dfMax,
                                            bIncludeOutOfRange, bApproxOK );
     if( psHistItem != NULL )
     {
-        int *panTempHist = NULL;
+        GUIntBig *panTempHist = NULL;
 
         if( PamParseHistogram( psHistItem, &dfMin, &dfMax, &nBuckets, 
                                &panTempHist,
                                &bIncludeOutOfRange, &bApproxOK ) )
         {
-            memcpy( panHistogram, panTempHist, sizeof(int) * nBuckets );
+            memcpy( panHistogram, panTempHist, sizeof(GUIntBig) * nBuckets );
             CPLFree( panTempHist );
             return CE_None;
         }
@@ -1201,7 +1198,7 @@ CPLErr GDALPamRasterBand::GetHistogram( double dfMin, double dfMax,
 /************************************************************************/
 
 CPLErr GDALPamRasterBand::SetDefaultHistogram( double dfMin, double dfMax, 
-                                               int nBuckets, int *panHistogram)
+                                               int nBuckets, GUIntBig *panHistogram)
 
 {
     CPLXMLNode *psNode;
@@ -1257,7 +1254,7 @@ CPLErr GDALPamRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
 
 CPLErr 
 GDALPamRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax, 
-                                        int *pnBuckets, int **ppanHistogram, 
+                                        int *pnBuckets, GUIntBig **ppanHistogram, 
                                         int bForce,
                                         GDALProgressFunc pfnProgress, 
                                         void *pProgressData )
@@ -1332,4 +1329,3 @@ CPLErr GDALPamRasterBand::SetDefaultRAT( const GDALRasterAttributeTable *poRAT)
 
     return CE_None;
 }
-
diff --git a/gcore/gdalproxydataset.cpp b/gcore/gdalproxydataset.cpp
index 4552032..bd6d67b 100644
--- a/gcore/gdalproxydataset.cpp
+++ b/gcore/gdalproxydataset.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalproxydataset.cpp 27723 2014-09-22 18:21:08Z goatbar $
+ * $Id: gdalproxydataset.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  A dataset and raster band classes that act as proxy for underlying
@@ -30,7 +30,7 @@
 
 #include "gdal_proxy.h"
 
-CPL_CVSID("$Id: gdalproxydataset.cpp 27723 2014-09-22 18:21:08Z goatbar $");
+CPL_CVSID("$Id: gdalproxydataset.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /* ******************************************************************** */
 /*                        GDALProxyDataset                              */
@@ -60,11 +60,12 @@ D_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, IRasterIO,
                         void * pData, int nBufXSize, int nBufYSize,
                         GDALDataType eBufType, 
                         int nBandCount, int *panBandMap,
-                        int nPixelSpace, int nLineSpace, int nBandSpace),
+                        GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
+                        GDALRasterIOExtraArg* psExtraArg),
                         ( eRWFlag, nXOff, nYOff, nXSize, nYSize, 
                         pData, nBufXSize, nBufYSize,
                         eBufType, nBandCount, panBandMap,
-                        nPixelSpace, nLineSpace, nBandSpace ))
+                        nPixelSpace, nLineSpace, nBandSpace, psExtraArg ))
 
 
 D_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, IBuildOverviews,
@@ -184,11 +185,12 @@ RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, IRasterIO,
                                 int nXOff, int nYOff, int nXSize, int nYSize,
                                 void * pData, int nBufXSize, int nBufYSize,
                                 GDALDataType eBufType,
-                                int nPixelSpace,
-                                int nLineSpace ), 
+                                GSpacing nPixelSpace,
+                                GSpacing nLineSpace,
+                                GDALRasterIOExtraArg* psExtraArg ), 
                         (eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                 pData, nBufXSize, nBufYSize, eBufType,
-                                nPixelSpace, nLineSpace ) )
+                                nPixelSpace, nLineSpace, psExtraArg ) )
 
 RB_PROXY_METHOD_WITH_RET(char**, NULL, GetMetadataDomainList, (), ())
 RB_PROXY_METHOD_WITH_RET(char**, NULL, GetMetadata, (const char * pszDomain), (pszDomain))
@@ -247,7 +249,7 @@ RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
 RB_PROXY_METHOD_WITH_RET(int, 0,  GetOverviewCount, (), ())
 RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetOverview, (int arg1), (arg1))
 RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL,  GetRasterSampleOverview,
-                        (int arg1), (arg1))
+                        (GUIntBig arg1), (arg1))
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
                         (const char * arg1, int arg2, int *arg3,
@@ -262,7 +264,7 @@ RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, AdviseRead,
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, GetHistogram,
                         ( double dfMin, double dfMax,
-                        int nBuckets, int * panHistogram,
+                        int nBuckets, GUIntBig * panHistogram,
                         int bIncludeOutOfRange, int bApproxOK,
                         GDALProgressFunc pfn, void *pProgressData ),
                         (dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
@@ -270,7 +272,7 @@ RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, GetHistogram,
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, GetDefaultHistogram,
                         (double *pdfMin, double *pdfMax,
-                        int *pnBuckets, int ** ppanHistogram,
+                        int *pnBuckets, GUIntBig ** ppanHistogram,
                         int bForce,
                         GDALProgressFunc pfn, void *pProgressData ),
                         (pdfMin, pdfMax, pnBuckets, ppanHistogram, bForce,
@@ -278,7 +280,7 @@ RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, GetDefaultHistogram,
 
 RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, SetDefaultHistogram,
                         ( double dfMin, double dfMax,
-                        int nBuckets, int * panHistogram ),
+                        int nBuckets, GUIntBig * panHistogram ),
                         (dfMin, dfMax, nBuckets, panHistogram))
 
 RB_PROXY_METHOD_WITH_RET(GDALRasterAttributeTable *, NULL,
diff --git a/gcore/gdalproxypool.cpp b/gcore/gdalproxypool.cpp
index 79db267..ad49d0f 100644
--- a/gcore/gdalproxypool.cpp
+++ b/gcore/gdalproxypool.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalproxypool.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: gdalproxypool.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  A dataset and raster band classes that differ the opening of the
@@ -31,7 +31,7 @@
 #include "gdal_proxy.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gdalproxypool.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: gdalproxypool.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /* We *must* share the same mutex as the gdaldataset.cpp file, as we are */
 /* doing GDALOpen() calls that can indirectly call GDALOpenShared() on */
@@ -89,7 +89,9 @@ class GDALDatasetPool
         /* least greater or equal than the maximum number of threads */
         GDALDatasetPool(int maxSize);
         ~GDALDatasetPool();
-        GDALProxyPoolCacheEntry* _RefDataset(const char* pszFileName, GDALAccess eAccess);
+        GDALProxyPoolCacheEntry* _RefDataset(const char* pszFileName,
+                                             GDALAccess eAccess,
+                                             char** papszOpenOptions);
 
         void ShowContent();
         void CheckLinks();
@@ -97,7 +99,9 @@ class GDALDatasetPool
     public:
         static void Ref();
         static void Unref();
-        static GDALProxyPoolCacheEntry* RefDataset(const char* pszFileName, GDALAccess eAccess);
+        static GDALProxyPoolCacheEntry* RefDataset(const char* pszFileName,
+                                                   GDALAccess eAccess,
+                                                   char** papszOpenOptions);
         static void UnrefDataset(GDALProxyPoolCacheEntry* cacheEntry);
 
         static void PreventDestroy();
@@ -183,7 +187,9 @@ void GDALDatasetPool::CheckLinks()
 /*                            _RefDataset()                             */
 /************************************************************************/
 
-GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName, GDALAccess eAccess)
+GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName,
+                                                      GDALAccess eAccess,
+                                                      char** papszOpenOptions)
 {
     GDALProxyPoolCacheEntry* cur = firstEntry;
     GIntBig responsiblePID = GDALGetResponsiblePIDForCurrentThread();
@@ -296,7 +302,9 @@ GDALProxyPoolCacheEntry* GDALDatasetPool::_RefDataset(const char* pszFileName, G
     cur->refCount = 1;
 
     refCountOfDisableRefCount ++;
-    cur->poDS = (GDALDataset*) GDALOpen(pszFileName, eAccess);
+    int nFlag = ((eAccess == GA_Update) ? GDAL_OF_UPDATE : GDAL_OF_READONLY) | GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR;
+    cur->poDS = (GDALDataset*) GDALOpenEx( pszFileName, nFlag, NULL,
+                           (const char* const* )papszOpenOptions, NULL );
     refCountOfDisableRefCount --;
 
     return cur;
@@ -382,10 +390,12 @@ void GDALDatasetPoolForceDestroy()
 /*                           RefDataset()                               */
 /************************************************************************/
 
-GDALProxyPoolCacheEntry* GDALDatasetPool::RefDataset(const char* pszFileName, GDALAccess eAccess)
+GDALProxyPoolCacheEntry* GDALDatasetPool::RefDataset(const char* pszFileName,
+                                                     GDALAccess eAccess,
+                                                     char** papszOpenOptions)
 {
     CPLMutexHolderD( GDALGetphDLMutex() );
-    return singleton->_RefDataset(pszFileName, eAccess);
+    return singleton->_RefDataset(pszFileName, eAccess, papszOpenOptions);
 }
 
 /************************************************************************/
@@ -559,6 +569,16 @@ GDALProxyPoolDataset::~GDALProxyPoolDataset()
 }
 
 /************************************************************************/
+/*                        SetOpenOptions()                              */
+/************************************************************************/
+
+void GDALProxyPoolDataset::SetOpenOptions(char** papszOpenOptions)
+{
+    CPLAssert(this->papszOpenOptions == NULL);
+    this->papszOpenOptions = CSLDuplicate(papszOpenOptions);
+}
+
+/************************************************************************/
 /*                    AddSrcBandDescription()                           */
 /************************************************************************/
 
@@ -585,7 +605,7 @@ GDALDataset* GDALProxyPoolDataset::RefUnderlyingDataset()
     /* a VRT of GeoTIFFs that have associated .aux files */
     GIntBig curResponsiblePID = GDALGetResponsiblePIDForCurrentThread();
     GDALSetResponsiblePIDForCurrentThread(responsiblePID);
-    cacheEntry = GDALDatasetPool::RefDataset(GetDescription(), eAccess);
+    cacheEntry = GDALDatasetPool::RefDataset(GetDescription(), eAccess, papszOpenOptions);
     GDALSetResponsiblePIDForCurrentThread(curResponsiblePID);
     if (cacheEntry != NULL)
     {
@@ -1110,7 +1130,7 @@ GDALRasterBand *GDALProxyPoolRasterBand::GetOverview(int nOverviewBand)
 /*                     GetRasterSampleOverview()                        */
 /* ******************************************************************** */
 
-GDALRasterBand *GDALProxyPoolRasterBand::GetRasterSampleOverview( CPL_UNUSED int nDesiredSamples)
+GDALRasterBand *GDALProxyPoolRasterBand::GetRasterSampleOverview( CPL_UNUSED GUIntBig nDesiredSamples)
 {
     CPLError(CE_Failure, CPLE_AppDefined,
              "GDALProxyPoolRasterBand::GetRasterSampleOverview : not implemented yet");
diff --git a/gcore/gdalrasterband.cpp b/gcore/gdalrasterband.cpp
index a3c945c..2d730bc 100644
--- a/gcore/gdalrasterband.cpp
+++ b/gcore/gdalrasterband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalrasterband.cpp 27858 2014-10-15 08:41:23Z rouault $
+ * $Id: gdalrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Base class for format specific band class implementation.  This
@@ -37,7 +37,7 @@
 #define TO_SUBBLOCK(x) ((x) >> 6)
 #define WITHIN_SUBBLOCK(x) ((x) & 0x3f)
 
-CPL_CVSID("$Id: gdalrasterband.cpp 27858 2014-10-15 08:41:23Z rouault $");
+CPL_CVSID("$Id: gdalrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $");
 
 /************************************************************************/
 /*                           GDALRasterBand()                           */
@@ -125,7 +125,7 @@ GDALRasterBand::~GDALRasterBand()
  * on "block boundaries" as returned by GetBlockSize(), or use the
  * ReadBlock() and WriteBlock() methods.
  *
- * This method is the same as the C GDALRasterIO() function.
+ * This method is the same as the C GDALRasterIO() or GDALRasterIOEx() functions.
  *
  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
  * write a region of data.
@@ -164,6 +164,12 @@ GDALRasterBand::~GDALRasterBand()
  * pData to the start of the next. If defaulted (0) the size of the datatype
  * eBufType * nBufXSize is used.
  *
+ * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg structure with additional
+ * arguments to specify resampling and progress callback, or NULL for default
+ * behaviour. The GDAL_RASTERIO_RESAMPLING configuration option can also be defined
+ * to override the default resampling to one of BILINEAR, CUBIC, CUBICSPLINE,
+ * LANCZOS, AVERAGE or MODE.
+ *
  * @return CE_Failure if the access fails, otherwise CE_None.
  */
 
@@ -171,16 +177,32 @@ CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
                                  int nXOff, int nYOff, int nXSize, int nYSize,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
-                                 int nPixelSpace,
-                                 int nLineSpace )
+                                 GSpacing nPixelSpace,
+                                 GSpacing nLineSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
 
 {
+    GDALRasterIOExtraArg sExtraArg;
+    if( psExtraArg == NULL )
+    {
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+        psExtraArg = &sExtraArg;
+    }
+    else if( psExtraArg->nVersion != RASTERIO_EXTRA_ARG_CURRENT_VERSION )
+    {
+        ReportError( CE_Failure, CPLE_AppDefined,
+                     "Unhandled version of GDALRasterIOExtraArg" );
+        return CE_Failure;
+    }
+
+    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize,
+                                       nBufXSize, nBufYSize);
 
     if( NULL == pData )
     {
         ReportError( CE_Failure, CPLE_AppDefined,
                   "The buffer into which the data should be read is null" );
-            return CE_Failure;
+        return CE_Failure;
     }
 
 /* -------------------------------------------------------------------- */
@@ -217,12 +239,6 @@ CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
     
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > INT_MAX / nBufXSize)
-        {
-            ReportError( CE_Failure, CPLE_AppDefined,
-                      "Int overflow : %d x %d", nPixelSpace, nBufXSize );
-            return CE_Failure;
-        }
         nLineSpace = nPixelSpace * nBufXSize;
     }
     
@@ -253,11 +269,11 @@ CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
     if( bForceCachedIO )
         return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                          pData, nBufXSize, nBufYSize, eBufType,
-                                         nPixelSpace, nLineSpace );
+                                         nPixelSpace, nLineSpace, psExtraArg );
     else
         return IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                           pData, nBufXSize, nBufYSize, eBufType,
-                          nPixelSpace, nLineSpace ) ;
+                          nPixelSpace, nLineSpace, psExtraArg ) ;
 }
 
 /************************************************************************/
@@ -267,6 +283,9 @@ CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
 /**
  * \brief Read/write a region of image data for this band.
  *
+ * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
+ * resolution, progress callback, etc. are needed)
+ * 
  * @see GDALRasterBand::RasterIO()
  */
 
@@ -284,9 +303,37 @@ GDALRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
 
     return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                               pData, nBufXSize, nBufYSize, eBufType,
-                              nPixelSpace, nLineSpace ) );
+                              nPixelSpace, nLineSpace, NULL) );
+}
+
+/************************************************************************/
+/*                            GDALRasterIOEx()                          */
+/************************************************************************/
+
+/**
+ * \brief Read/write a region of image data for this band.
+ *
+ * @see GDALRasterBand::RasterIO()
+ * @since GDAL 2.0
+ */
+
+CPLErr CPL_STDCALL 
+GDALRasterIOEx( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
+              int nXOff, int nYOff, int nXSize, int nYSize,
+              void * pData, int nBufXSize, int nBufYSize,
+              GDALDataType eBufType,
+              GSpacing nPixelSpace, GSpacing nLineSpace,
+              GDALRasterIOExtraArg* psExtraArg )
+    
+{
+    VALIDATE_POINTER1( hBand, "GDALRasterIOEx", CE_Failure );
+
+    GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
+
+    return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
+                              pData, nBufXSize, nBufYSize, eBufType,
+                              nPixelSpace, nLineSpace, psExtraArg) );
 }
-                     
 /************************************************************************/
 /*                             ReadBlock()                              */
 /************************************************************************/
@@ -321,14 +368,14 @@ GDALRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
  * undermined value.
  *
 <pre>
- CPLErr GetHistogram( GDALRasterBand *poBand, int *panHistogram )
+ CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
 
  {
      int        nXBlocks, nYBlocks, nXBlockSize, nYBlockSize;
      int        iXBlock, iYBlock;
      GByte      *pabyData;
 
-     memset( panHistogram, 0, sizeof(int) * 256 );
+     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
 
      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
 
@@ -947,6 +994,80 @@ CPLErr CPL_STDCALL GDALFlushRasterCache( GDALRasterBandH hBand )
     return ((GDALRasterBand *) hBand)->FlushCache();
 }
 
+
+/************************************************************************/
+/*                        UnreferenceBlock()                            */
+/*                                                                      */
+/*      Unreference the block from our array of blocks                  */
+/*      This method should only be called by                            */
+/*      GDALRasterBlock::Internalize(), and under the block cache mutex */
+/************************************************************************/
+
+CPLErr GDALRasterBand::UnreferenceBlock( int nXBlockOff, int nYBlockOff )
+{
+
+    if( !papoBlocks )
+        return CE_None;
+    
+/* -------------------------------------------------------------------- */
+/*      Validate the request                                            */
+/* -------------------------------------------------------------------- */
+    if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
+    {
+        ReportError( CE_Failure, CPLE_IllegalArg,
+                  "Illegal nBlockXOff value (%d) in "
+                        "GDALRasterBand::FlushBlock()\n",
+                  nXBlockOff );
+
+        return( CE_Failure );
+    }
+
+    if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
+    {
+        ReportError( CE_Failure, CPLE_IllegalArg,
+                  "Illegal nBlockYOff value (%d) in "
+                        "GDALRasterBand::FlushBlock()\n",
+                  nYBlockOff );
+
+        return( CE_Failure );
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Simple case for single level caches.                            */
+/* -------------------------------------------------------------------- */
+    if( !bSubBlockingActive )
+    {
+        int nBlockIndex = nXBlockOff + nYBlockOff * nBlocksPerRow;
+
+        papoBlocks[nBlockIndex] = NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Identify our subblock.                                          */
+/* -------------------------------------------------------------------- */
+    else
+    {
+        int nSubBlock = TO_SUBBLOCK(nXBlockOff) 
+            + TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
+
+        if( papoBlocks[nSubBlock] == NULL )
+            return CE_None;
+
+/* -------------------------------------------------------------------- */
+/*      Check within subblock.                                          */
+/* -------------------------------------------------------------------- */
+        GDALRasterBlock **papoSubBlockGrid = 
+            (GDALRasterBlock **) papoBlocks[nSubBlock];
+
+        int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
+            + WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
+
+        papoSubBlockGrid[nBlockInSubBlock] = NULL;
+    }
+
+    return CE_None;
+}
+
 /************************************************************************/
 /*                             FlushBlock()                             */
 /*                                                                      */
@@ -957,7 +1078,8 @@ CPLErr CPL_STDCALL GDALFlushRasterCache( GDALRasterBandH hBand )
 /*      Protected method.                                               */
 /************************************************************************/
 
-CPLErr GDALRasterBand::FlushBlock( int nXBlockOff, int nYBlockOff, int bWriteDirtyBlock )
+CPLErr GDALRasterBand::FlushBlock( int nXBlockOff, int nYBlockOff,
+                                   int bWriteDirtyBlock )
 
 {
     int             nBlockIndex;
@@ -1021,7 +1143,7 @@ CPLErr GDALRasterBand::FlushBlock( int nXBlockOff, int nYBlockOff, int bWriteDir
         
         int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
             + WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
-        
+
         GDALRasterBlock::SafeLockBlock( papoSubBlockGrid + nBlockInSubBlock );
 
         poBlock = papoSubBlockGrid[nBlockInSubBlock];
@@ -1322,15 +1444,10 @@ CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue) {
         return CE_Failure;
     }
     
-    // Initialize the first element of the block, doing type conversion
+    // Initialize the source block
     double complexSrc[2] = { dfRealValue, dfImaginaryValue };
-    GDALCopyWords(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType, 0, 1);
-
-    // Copy first element to the rest of the block
-    for (unsigned char* blockPtr = srcBlock + elementSize; 
-	 blockPtr < srcBlock + blockByteSize; blockPtr += elementSize) {
-	memcpy(blockPtr, srcBlock, elementSize);
-    }
+    GDALCopyWords(complexSrc, GDT_CFloat64, 0,
+                  srcBlock, eDataType, elementSize, blockSize);
 
     // Write block to block cache
     for (int j = 0; j < nBlocksPerColumn; ++j) {
@@ -1487,7 +1604,7 @@ CPLErr GDALRasterBand::SetCategoryNames( CPL_UNUSED char ** papszNames )
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
                   "SetCategoryNames() not supported for this dataset." );
-    
+
     return CE_Failure;
 }
 
@@ -1580,6 +1697,7 @@ GDALGetRasterNoDataValue( GDALRasterBandH hBand, int *pbSuccess )
  */
 
 CPLErr GDALRasterBand::SetNoDataValue( CPL_UNUSED double dfNoData )
+
 {
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
@@ -2106,7 +2224,8 @@ GDALRasterBandH CPL_STDCALL GDALGetOverview( GDALRasterBandH hBand, int i )
  * The same band as was passed in will be returned if it has not overviews,
  * or if none of the overviews have enough samples.
  *
- * This method is the same as the C function GDALGetRasterSampleOverview().
+ * This method is the same as the C functions GDALGetRasterSampleOverview()
+ * and GDALGetRasterSampleOverviewEx().
  *
  * @param nDesiredSamples the returned band will have at least this many 
  * pixels.
@@ -2114,7 +2233,7 @@ GDALRasterBandH CPL_STDCALL GDALGetOverview( GDALRasterBandH hBand, int i )
  * @return optimal overview or the band itself. 
  */
 
-GDALRasterBand *GDALRasterBand::GetRasterSampleOverview( int nDesiredSamples )
+GDALRasterBand *GDALRasterBand::GetRasterSampleOverview( GUIntBig nDesiredSamples )
 
 {
     double dfBestSamples = 0; 
@@ -2149,7 +2268,11 @@ GDALRasterBand *GDALRasterBand::GetRasterSampleOverview( int nDesiredSamples )
 /**
  * \brief Fetch best sampling overview.
  *
+ * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
+ * billion samples.
+ *
  * @see GDALRasterBand::GetRasterSampleOverview()
+ * @see GDALGetRasterSampleOverviewEx()
  */
 
 GDALRasterBandH CPL_STDCALL 
@@ -2160,6 +2283,28 @@ GDALGetRasterSampleOverview( GDALRasterBandH hBand, int nDesiredSamples )
 
     GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
     return (GDALRasterBandH)
+        poBand->GetRasterSampleOverview( nDesiredSamples < 0 ? 0 : (GUIntBig)nDesiredSamples );
+}
+
+/************************************************************************/
+/*                    GDALGetRasterSampleOverviewEx()                   */
+/************************************************************************/
+
+/**
+ * \brief Fetch best sampling overview.
+ *
+ * @see GDALRasterBand::GetRasterSampleOverview()
+ * @since GDAL 2.0
+ */
+
+GDALRasterBandH CPL_STDCALL 
+GDALGetRasterSampleOverviewEx( GDALRasterBandH hBand, GUIntBig nDesiredSamples )
+
+{
+    VALIDATE_POINTER1( hBand, "GDALGetRasterSampleOverviewEx", NULL );
+
+    GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
+    return (GDALRasterBandH)
         poBand->GetRasterSampleOverview( nDesiredSamples );
 }
 
@@ -2277,7 +2422,7 @@ double CPL_STDCALL GDALGetRasterOffset( GDALRasterBandH hBand, int *pbSuccess )
  *
  * @param dfNewOffset the new offset.
  *
- * @return CE_None or success or CE_Failure on failure. 
+ * @return CE_None or success or CE_Failure on failure.
  */
 
 CPLErr GDALRasterBand::SetOffset( CPL_UNUSED double dfNewOffset )
@@ -2285,7 +2430,7 @@ CPLErr GDALRasterBand::SetOffset( CPL_UNUSED double dfNewOffset )
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
                   "SetOffset() not supported on this raster band." );
-    
+
     return CE_Failure;
 }
 
@@ -2376,15 +2521,16 @@ double CPL_STDCALL GDALGetRasterScale( GDALRasterBandH hBand, int *pbSuccess )
  * 
  * @param dfNewScale the new scale.
  *
- * @return CE_None or success or CE_Failure on failure. 
+ * @return CE_None or success or CE_Failure on failure.
  */
 
 CPLErr GDALRasterBand::SetScale( CPL_UNUSED double dfNewScale )
+
 {
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
                   "SetScale() not supported on this raster band." );
-    
+
     return CE_Failure;
 }
 
@@ -2465,7 +2611,7 @@ const char * CPL_STDCALL GDALGetRasterUnitType( GDALRasterBandH hBand )
  *
  * @param pszNewValue the new unit type value.
  *
- * @return CE_None on success or CE_Failure if not succuessful, or 
+ * @return CE_None on success or CE_Failure if not succuessful, or
  * unsupported.
  */
 
@@ -2670,7 +2816,7 @@ GDALDatasetH CPL_STDCALL GDALGetBandDataset( GDALRasterBandH hBand )
  * bucket boundaries don't fall right on integer values causing possible errors
  * due to rounding after scaling. 
 <pre>
-    int anHistogram[256];
+    GUIntBig anHistogram[256];
 
     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE, 
                           GDALDummyProgress, NULL );
@@ -2682,7 +2828,8 @@ GDALDatasetH CPL_STDCALL GDALGetBandDataset( GDALRasterBandH hBand )
  * in generating histogram based luts for instance.  Generally bApproxOK is
  * much faster than an exactly computed histogram.
  *
- * This method is the same as the C function GDALGetRasterHistogram().
+ * This method is the same as the C functions GDALGetRasterHistogram() and
+ * GDALGetRasterHistogramEx().
  *
  * @param dfMin the lower bound of the histogram.
  * @param dfMax the upper bound of the histogram.
@@ -2699,7 +2846,7 @@ GDALDatasetH CPL_STDCALL GDALGetBandDataset( GDALRasterBandH hBand )
  */
 
 CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax, 
-                                     int nBuckets, int *panHistogram, 
+                                     int nBuckets, GUIntBig *panHistogram, 
                                      int bIncludeOutOfRange, int bApproxOK,
                                      GDALProgressFunc pfnProgress, 
                                      void *pProgressData )
@@ -2732,20 +2879,20 @@ CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax,
 /* -------------------------------------------------------------------- */
 /*      Read actual data and build histogram.                           */
 /* -------------------------------------------------------------------- */
-    double      dfScale;
-
     if( !pfnProgress( 0.0, "Compute Histogram", pProgressData ) )
     {
         ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
         return CE_Failure;
     }
 
-    dfScale = nBuckets / (dfMax - dfMin);
-    memset( panHistogram, 0, sizeof(int) * nBuckets );
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
+    const double dfScale = nBuckets / (dfMax - dfMin);
+    memset( panHistogram, 0, sizeof(GUIntBig) * nBuckets );
 
-    double dfNoDataValue;
     int bGotNoDataValue;
-    dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
+    const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
     /* Not advertized. May be removed at any time. Just as a provision if the */
     /* old behaviour made sense somethimes... */
@@ -2787,7 +2934,7 @@ CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax,
             CPLMalloc(GDALGetDataTypeSize(eDataType)/8 * nXReduced * nYReduced);
 
         CPLErr eErr = IRasterIO( GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
-                   nXReduced, nYReduced, eDataType, 0, 0 );
+                   nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
         if ( eErr != CE_None )
         {
             CPLFree(pData);
@@ -3103,7 +3250,11 @@ CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax,
 /**
  * \brief Compute raster histogram. 
  *
+ * Use GDALGetRasterHistogramEx() instead to get correct counts for values
+ * exceeding 2 billion.
+ *
  * @see GDALRasterBand::GetHistogram()
+ * @see GDALGetRasterHistogramEx()
  */
 
 CPLErr CPL_STDCALL 
@@ -3119,6 +3270,65 @@ GDALGetRasterHistogram( GDALRasterBandH hBand,
     VALIDATE_POINTER1( panHistogram, "GDALGetRasterHistogram", CE_Failure );
 
     GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
+    
+    GUIntBig* panHistogramTemp = (GUIntBig*)VSIMalloc2(sizeof(GUIntBig), nBuckets);
+    if( panHistogramTemp == NULL )
+    {
+        poBand->ReportError( CE_Failure, CPLE_OutOfMemory,
+                     "Out of memory in GDALGetRasterHistogram()." );
+        return CE_Failure;
+    }
+
+    CPLErr eErr = poBand->GetHistogram( dfMin, dfMax, nBuckets, panHistogramTemp, 
+                      bIncludeOutOfRange, bApproxOK,
+                      pfnProgress, pProgressData );
+
+    if( eErr == CE_None )
+    {
+        for(int i=0;i<nBuckets;i++)
+        {
+            if( panHistogramTemp[i] > INT_MAX )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Count for bucket %d, which is " CPL_FRMT_GUIB " exceeds maximum 32 bit value",
+                         i, panHistogramTemp[i]);
+                panHistogram[i] = INT_MAX;
+            }
+            else
+                panHistogram[i] = (int)panHistogramTemp[i];
+        }
+    }
+    
+    CPLFree(panHistogramTemp);
+    
+    return eErr;
+}
+
+/************************************************************************/
+/*                      GDALGetRasterHistogramEx()                      */
+/************************************************************************/
+
+/**
+ * \brief Compute raster histogram. 
+ *
+ * @see GDALRasterBand::GetHistogram()
+ *
+ * @since GDAL 2.0
+ */
+
+CPLErr CPL_STDCALL 
+GDALGetRasterHistogramEx( GDALRasterBandH hBand, 
+                        double dfMin, double dfMax, 
+                        int nBuckets, GUIntBig *panHistogram, 
+                        int bIncludeOutOfRange, int bApproxOK,
+                        GDALProgressFunc pfnProgress, 
+                        void *pProgressData )
+    
+{
+    VALIDATE_POINTER1( hBand, "GDALGetRasterHistogramEx", CE_Failure );
+    VALIDATE_POINTER1( panHistogram, "GDALGetRasterHistogramEx", CE_Failure );
+
+    GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
 
     return poBand->GetHistogram( dfMin, dfMax, nBuckets, panHistogram, 
                       bIncludeOutOfRange, bApproxOK,
@@ -3136,7 +3346,8 @@ GDALGetRasterHistogram( GDALRasterBandH hBand,
  * method is overriden by derived classes (such as GDALPamRasterBand, VRTDataset, HFADataset...)
  * that may be able to fetch efficiently an already stored histogram.
  *
- * This method is the same as the C function GDALGetDefaultHistogram().
+ * This method is the same as the C functions GDALGetDefaultHistogram() and
+ * GDALGetDefaultHistogramEx().
  *
  * @param pdfMin pointer to double value that will contain the lower bound of the histogram.
  * @param pdfMax pointer to double value that will contain the upper bound of the histogram.
@@ -3152,7 +3363,7 @@ GDALGetRasterHistogram( GDALRasterBandH hBand,
 
 CPLErr 
     GDALRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax, 
-                                         int *pnBuckets, int **ppanHistogram, 
+                                         int *pnBuckets, GUIntBig **ppanHistogram, 
                                          int bForce,
                                          GDALProgressFunc pfnProgress, 
                                          void *pProgressData )
@@ -3193,7 +3404,7 @@ CPLErr
             return eErr;
     }
 
-    *ppanHistogram = (int *) VSICalloc(sizeof(int), nBuckets);
+    *ppanHistogram = (GUIntBig *) VSICalloc(sizeof(GUIntBig), nBuckets);
     if( *ppanHistogram == NULL )
     {
         ReportError( CE_Failure, CPLE_OutOfMemory,
@@ -3213,7 +3424,11 @@ CPLErr
 /**
   * \brief Fetch default raster histogram. 
   *
-  * @see GDALRasterBand::GetDefaultHistogram()
+  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
+  * exceeding 2 billion.
+  *
+  * @see GDALRasterBand::GDALGetDefaultHistogram()
+  * @see GDALGetRasterHistogramEx()
   */
 
 CPLErr CPL_STDCALL GDALGetDefaultHistogram( GDALRasterBandH hBand, 
@@ -3231,10 +3446,72 @@ CPLErr CPL_STDCALL GDALGetDefaultHistogram( GDALRasterBandH hBand,
     VALIDATE_POINTER1( ppanHistogram, "GDALGetDefaultHistogram", CE_Failure );
 
     GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
+    GUIntBig* panHistogramTemp = NULL;
+    CPLErr eErr = poBand->GetDefaultHistogram( pdfMin, pdfMax,
+        pnBuckets, &panHistogramTemp, bForce, pfnProgress, pProgressData );
+    if( eErr == CE_None )
+    {
+        int nBuckets = *pnBuckets;
+        *ppanHistogram = (int*) VSIMalloc2(sizeof(int), nBuckets);
+        if( *ppanHistogram == NULL )
+        {
+            poBand->ReportError( CE_Failure, CPLE_OutOfMemory,
+                        "Out of memory in GDALGetDefaultHistogram()." );
+            VSIFree(panHistogramTemp);
+            return CE_Failure;
+        }
+
+        for(int i=0;i<nBuckets;i++)
+        {
+            if( panHistogramTemp[i] > INT_MAX )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Count for bucket %d, which is " CPL_FRMT_GUIB " exceeds maximum 32 bit value",
+                         i, panHistogramTemp[i]);
+                (*ppanHistogram)[i] = INT_MAX;
+            }
+            else
+                (*ppanHistogram)[i] = (int)panHistogramTemp[i];
+        }
+
+        CPLFree(panHistogramTemp);
+    }
+    else
+        *ppanHistogram = NULL;
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                      GDALGetDefaultHistogramEx()                     */
+/************************************************************************/
+
+/**
+  * \brief Fetch default raster histogram. 
+  *
+  * @see GDALRasterBand::GetDefaultHistogram()
+  *
+  * @since GDAL 2.0
+  */
+
+CPLErr CPL_STDCALL GDALGetDefaultHistogramEx( GDALRasterBandH hBand, 
+                                double *pdfMin, double *pdfMax, 
+                                int *pnBuckets, GUIntBig **ppanHistogram, 
+                                int bForce,
+                                GDALProgressFunc pfnProgress, 
+                                void *pProgressData )
+
+{
+    VALIDATE_POINTER1( hBand, "GDALGetDefaultHistogram", CE_Failure );
+    VALIDATE_POINTER1( pdfMin, "GDALGetDefaultHistogram", CE_Failure );
+    VALIDATE_POINTER1( pdfMax, "GDALGetDefaultHistogram", CE_Failure );
+    VALIDATE_POINTER1( pnBuckets, "GDALGetDefaultHistogram", CE_Failure );
+    VALIDATE_POINTER1( ppanHistogram, "GDALGetDefaultHistogram", CE_Failure );
+
+    GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
     return poBand->GetDefaultHistogram( pdfMin, pdfMax,
         pnBuckets, ppanHistogram, bForce, pfnProgress, pProgressData );
 }
-
 /************************************************************************/
 /*                             AdviseRead()                             */
 /************************************************************************/
@@ -3277,9 +3554,11 @@ CPLErr CPL_STDCALL GDALGetDefaultHistogram( GDALRasterBandH hBand,
  * is ignored. 
  */
 
-CPLErr GDALRasterBand::AdviseRead( 
-    CPL_UNUSED int nXOff, CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-    CPL_UNUSED int nBufXSize, CPL_UNUSED int nBufYSize, CPL_UNUSED GDALDataType eBufType, CPL_UNUSED char **papszOptions )
+CPLErr GDALRasterBand::AdviseRead(
+    CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
+    CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
+    CPL_UNUSED int nBufXSize, CPL_UNUSED int nBufYSize,
+    CPL_UNUSED GDALDataType eBufType, CPL_UNUSED char **papszOptions )
 {
     return CE_None;
 }
@@ -3327,7 +3606,7 @@ GDALRasterAdviseRead( GDALRasterBandH hBand,
  * but no warning will have been issued.   This is a non-standard use of
  * the CE_Warning return value to indicate "nothing done". 
  *
- * Note that file formats using PAM (Persistent Auxilary Metadata) services
+ * Note that file formats using PAM (Persistent Auxiliary Metadata) services
  * will generally cache statistics in the .pam file allowing fast fetch
  * after the first request. 
  *
@@ -3501,21 +3780,29 @@ GDALRasterBand::ComputeStatistics( int bApproxOK,
 /* -------------------------------------------------------------------- */
     double      dfMin = 0.0, dfMax = 0.0;
     int         bGotNoDataValue, bFirstValue = TRUE;
-    double      dfNoDataValue, dfSum = 0.0, dfSum2 = 0.0;
+    /* Using Welford algorithm ( http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance ) */
+    /* to compute standard deviation in a more numerically robust way than */
+    /* the difference of the sum of square values with the square of the sum */
+    /* dfMean and dfM2 are updated at each sample */
+    /* dfM2 is the sum of square of differences to the current mean */
+    double      dfMean = 0.0, dfM2 = 0.0;
     GIntBig     nSampleCount = 0;
 
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     if( !pfnProgress( 0.0, "Compute Statistics", pProgressData ) )
     {
         ReportError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
         return CE_Failure;
     }
 
-    dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
+    const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
 
     const char* pszPixelType = GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
     int bSignedByte = (pszPixelType != NULL && EQUAL(pszPixelType, "SIGNEDBYTE"));
-    
+
     if ( bApproxOK && HasArbitraryOverviews() )
     {
 /* -------------------------------------------------------------------- */
@@ -3548,7 +3835,7 @@ GDALRasterBand::ComputeStatistics( int bApproxOK,
             CPLMalloc(GDALGetDataTypeSize(eDataType)/8 * nXReduced * nYReduced);
 
         CPLErr eErr = IRasterIO( GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
-                   nXReduced, nYReduced, eDataType, 0, 0 );
+                   nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
         if ( eErr != CE_None )
         {
             CPLFree(pData);
@@ -3629,10 +3916,10 @@ GDALRasterBand::ComputeStatistics( int bApproxOK,
                     dfMax = MAX(dfMax,dfValue);
                 }
 
-                dfSum += dfValue;
-                dfSum2 += dfValue * dfValue;
-
                 nSampleCount++;
+                double dfDelta = dfValue - dfMean;
+                dfMean += dfDelta / nSampleCount;
+                dfM2 += dfDelta * (dfValue - dfMean);
             }
         }
 
@@ -3764,10 +4051,10 @@ GDALRasterBand::ComputeStatistics( int bApproxOK,
                         dfMax = MAX(dfMax,dfValue);
                     }
 
-                    dfSum += dfValue;
-                    dfSum2 += dfValue * dfValue;
-
                     nSampleCount++;
+                    double dfDelta = dfValue - dfMean;
+                    dfMean += dfDelta / nSampleCount;
+                    dfM2 += dfDelta * (dfValue - dfMean);
                 }
             }
 
@@ -3792,8 +4079,7 @@ GDALRasterBand::ComputeStatistics( int bApproxOK,
 /* -------------------------------------------------------------------- */
 /*      Save computed information.                                      */
 /* -------------------------------------------------------------------- */
-    double dfMean = dfSum / nSampleCount;
-    double dfStdDev = sqrt((dfSum2 / nSampleCount) - (dfMean * dfMean));
+    double dfStdDev = sqrt(dfM2 / nSampleCount);
 
     if( nSampleCount > 0 )
         SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
@@ -3881,16 +4167,16 @@ CPLErr GDALRasterBand::SetStatistics( double dfMin, double dfMax,
 {
     char szValue[128] = { 0 };
 
-    sprintf( szValue, "%.14g", dfMin );
+    CPLsprintf( szValue, "%.14g", dfMin );
     SetMetadataItem( "STATISTICS_MINIMUM", szValue );
 
-    sprintf( szValue, "%.14g", dfMax );
+    CPLsprintf( szValue, "%.14g", dfMax );
     SetMetadataItem( "STATISTICS_MAXIMUM", szValue );
 
-    sprintf( szValue, "%.14g", dfMean );
+    CPLsprintf( szValue, "%.14g", dfMean );
     SetMetadataItem( "STATISTICS_MEAN", szValue );
 
-    sprintf( szValue, "%.14g", dfStdDev );
+    CPLsprintf( szValue, "%.14g", dfStdDev );
     SetMetadataItem( "STATISTICS_STDDEV", szValue );
 
     return CE_None;
@@ -3972,26 +4258,27 @@ CPLErr GDALRasterBand::ComputeRasterMinMax( int bApproxOK,
 /* -------------------------------------------------------------------- */
     if ( bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews() )
     {
-        GDALRasterBand *poBand;
-
-        poBand = GetRasterSampleOverview( GDALSTAT_APPROX_NUMSAMPLES );
+        GDALRasterBand *poBand =
+          GetRasterSampleOverview( GDALSTAT_APPROX_NUMSAMPLES );
 
         if ( poBand != this )
             return poBand->ComputeRasterMinMax( FALSE, adfMinMax );
     }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Read actual data and compute minimum and maximum.               */
 /* -------------------------------------------------------------------- */
     int     bGotNoDataValue, bFirstValue = TRUE;
-    double  dfNoDataValue;
 
-    dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
+    const double dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
     bGotNoDataValue = bGotNoDataValue && !CPLIsNan(dfNoDataValue);
 
     const char* pszPixelType = GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
     int bSignedByte = (pszPixelType != NULL && EQUAL(pszPixelType, "SIGNEDBYTE"));
-    
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     if ( bApproxOK && HasArbitraryOverviews() )
     {
 /* -------------------------------------------------------------------- */
@@ -4024,7 +4311,7 @@ CPLErr GDALRasterBand::ComputeRasterMinMax( int bApproxOK,
             CPLMalloc(GDALGetDataTypeSize(eDataType)/8 * nXReduced * nYReduced);
 
         CPLErr eErr = IRasterIO( GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
-                   nXReduced, nYReduced, eDataType, 0, 0 );
+                   nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg );
         if ( eErr != CE_None )
         {
             CPLFree(pData);
@@ -4285,10 +4572,14 @@ GDALComputeRasterMinMax( GDALRasterBandH hBand, int bApproxOK,
 /**
  * \brief Set default histogram.
  *
- * This method is the same as the C function GDALSetDefaultHistogram().
+ * This method is the same as the C function GDALSetDefaultHistogram() and
+ * GDALSetDefaultHistogramEx()
  */
-CPLErr GDALRasterBand::SetDefaultHistogram( CPL_UNUSED double dfMin, CPL_UNUSED double dfMax, 
-                                            CPL_UNUSED int nBuckets, CPL_UNUSED int *panHistogram )
+CPLErr GDALRasterBand::SetDefaultHistogram( CPL_UNUSED double dfMin,
+                                            CPL_UNUSED double dfMax,
+                                            CPL_UNUSED int nBuckets,
+                                            CPL_UNUSED GUIntBig *panHistogram )
+
 {
     if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
         ReportError( CE_Failure, CPLE_NotSupported,
@@ -4304,7 +4595,11 @@ CPLErr GDALRasterBand::SetDefaultHistogram( CPL_UNUSED double dfMin, CPL_UNUSED
 /**
  * \brief Set default histogram.
  *
+ * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
+ * 2 billion.
+ *
  * @see GDALRasterBand::SetDefaultHistogram()
+ * @see GDALSetRasterHistogramEx()
  */
 
 CPLErr CPL_STDCALL GDALSetDefaultHistogram( GDALRasterBandH hBand, 
@@ -4315,6 +4610,47 @@ CPLErr CPL_STDCALL GDALSetDefaultHistogram( GDALRasterBandH hBand,
     VALIDATE_POINTER1( hBand, "GDALSetDefaultHistogram", CE_Failure );
 
     GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
+    
+    GUIntBig* panHistogramTemp = (GUIntBig*) VSIMalloc2(sizeof(GUIntBig), nBuckets);
+    if( panHistogramTemp == NULL )
+    {
+        poBand->ReportError( CE_Failure, CPLE_OutOfMemory,
+                    "Out of memory in GDALSetDefaultHistogram()." );
+        return CE_Failure;
+    }
+
+    for(int i=0;i<nBuckets;i++)
+    {
+        panHistogramTemp[i] = (GUIntBig)panHistogram[i];
+    }
+    
+    CPLErr eErr = poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, panHistogramTemp );
+    
+    CPLFree(panHistogramTemp);
+    
+    return eErr;
+}
+
+/************************************************************************/
+/*                     GDALSetDefaultHistogramEx()                      */
+/************************************************************************/
+
+/**
+ * \brief Set default histogram.
+ *
+ * @see GDALRasterBand::SetDefaultHistogram()
+ *
+ * @since GDAL 2.0
+ */
+
+CPLErr CPL_STDCALL GDALSetDefaultHistogramEx( GDALRasterBandH hBand, 
+                                            double dfMin, double dfMax, 
+                                            int nBuckets, GUIntBig *panHistogram )
+
+{
+    VALIDATE_POINTER1( hBand, "GDALSetDefaultHistogramEx", CE_Failure );
+
+    GDALRasterBand *poBand = static_cast<GDALRasterBand*>(hBand);
     return poBand->SetDefaultHistogram( dfMin, dfMax, nBuckets, panHistogram );
 }
 
@@ -4374,7 +4710,7 @@ GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT( GDALRasterBandH hBand)
  *
  * @param poRAT the RAT to assign to the band.
  *
- * @return CE_None on success or CE_Failure if unsupported or otherwise 
+ * @return CE_None on success or CE_Failure if unsupported or otherwise
  * failing.
  */
 
@@ -4766,7 +5102,7 @@ CPLErr CPL_STDCALL GDALCreateMaskBand( GDALRasterBandH hBand, int nFlags )
 /**
  * \brief Compute translation table for color tables.
  *
- * When the raster band has a palette index, it may be usefull to compute
+ * When the raster band has a palette index, it may be useful to compute
  * the "translation" of this palette to the palette of another band.
  * The translation tries to do exact matching first, and then approximate
  * matching if no exact matching is possible.
@@ -5074,4 +5410,3 @@ CPLVirtualMem * GDALGetVirtualMemAuto( GDALRasterBandH hBand,
     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace,
                                      pnLineSpace, papszOptions);
 }
-
diff --git a/gcore/gdalrasterblock.cpp b/gcore/gdalrasterblock.cpp
index 5e396ec..16fe4e3 100644
--- a/gcore/gdalrasterblock.cpp
+++ b/gcore/gdalrasterblock.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalrasterblock.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gdalrasterblock.cpp 28894 2015-04-13 14:55:20Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALRasterBlock class and related global 
@@ -32,16 +32,56 @@
 #include "gdal_priv.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: gdalrasterblock.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: gdalrasterblock.cpp 28894 2015-04-13 14:55:20Z rouault $");
 
 static int bCacheMaxInitialized = FALSE;
 static GIntBig nCacheMax = 40 * 1024*1024;
 static volatile GIntBig nCacheUsed = 0;
 
-static volatile GDALRasterBlock *poOldest = NULL;    /* tail */
-static volatile GDALRasterBlock *poNewest = NULL;    /* head */
+static GDALRasterBlock *poOldest = NULL;    /* tail */
+static GDALRasterBlock *poNewest = NULL;    /* head */
 
-static void *hRBMutex = NULL;
+#if 0
+static CPLMutex *hRBLock = NULL;
+#define INITIALIZE_LOCK         CPLMutexHolderD( &hRBLock )
+#define TAKE_LOCK               CPLMutexHolderOptionalLockD( hRBLock )
+#define DESTROY_LOCK            CPLDestroyMutex( hRBLock )
+#else
+
+static CPLLock* hRBLock = NULL;
+static int bDebugContention = FALSE;
+static CPLLockType GetLockType()
+{
+    static int nLockType = -1;
+    if( nLockType < 0 )
+    {
+        const char* pszLockType = CPLGetConfigOption("GDAL_RB_LOCK_TYPE", "ADAPTIVE");
+        if( EQUAL(pszLockType, "ADAPTIVE") )
+            nLockType = LOCK_ADAPTIVE_MUTEX;
+        else if( EQUAL(pszLockType, "RECURSIVE") )
+            nLockType = LOCK_RECURSIVE_MUTEX;
+        else if( EQUAL(pszLockType, "SPIN") )
+            nLockType = LOCK_SPIN;
+        else
+        {
+            CPLError(CE_Warning, CPLE_NotSupported,
+                     "GDAL_RB_LOCK_TYPE=%s not supported. Falling back to ADAPTIVE",
+                     pszLockType);
+            nLockType = LOCK_ADAPTIVE_MUTEX;
+        }
+        bDebugContention = CSLTestBoolean(CPLGetConfigOption("GDAL_RB_LOCK_DEBUG_CONTENTION", "NO"));
+    }
+    return (CPLLockType) nLockType;
+}
+
+#define INITIALIZE_LOCK         CPLLockHolderD( &hRBLock, GetLockType() ); \
+                                CPLLockSetDebugPerf(hRBLock, bDebugContention)
+#define TAKE_LOCK               CPLLockHolderOptionalLockD( hRBLock )
+#define DESTROY_LOCK            CPLDestroyLock( hRBLock )
+
+#endif
+
+//#define ENABLE_DEBUG
 
 /************************************************************************/
 /*                          GDALSetCacheMax()                           */
@@ -166,6 +206,9 @@ GIntBig CPL_STDCALL GDALGetCacheMax64()
 {
     if( !bCacheMaxInitialized )
     {
+        {
+            INITIALIZE_LOCK;
+        }
         const char* pszCacheMax = CPLGetConfigOption("GDAL_CACHEMAX",NULL);
         bCacheMaxInitialized = TRUE;
         if( pszCacheMax != NULL )
@@ -304,43 +347,79 @@ int CPL_STDCALL GDALFlushCacheBlock()
  *
  * C++ analog to the C function GDALFlushCacheBlock().
  * 
+ * @param bDirtyBlocksOnly Only flushes dirty blocks.
  * @return TRUE if successful or FALSE if no flushable block is found.
  */
 
-int GDALRasterBlock::FlushCacheBlock()
+int GDALRasterBlock::FlushCacheBlock(int bDirtyBlocksOnly)
 
 {
-    int nXOff, nYOff;
-    GDALRasterBand *poBand;
+    GDALRasterBlock *poTarget;
 
     {
-        CPLMutexHolderD( &hRBMutex );
-        GDALRasterBlock *poTarget = (GDALRasterBlock *) poOldest;
+        INITIALIZE_LOCK;
+        poTarget = poOldest;
 
-        while( poTarget != NULL && poTarget->GetLockCount() > 0 ) 
+        while( poTarget != NULL && (poTarget->GetLockCount() > 0 ||
+               (bDirtyBlocksOnly && !poTarget->GetDirty())) )
             poTarget = poTarget->poPrevious;
         
         if( poTarget == NULL )
             return FALSE;
 
-        poTarget->Detach();
-
-        nXOff = poTarget->GetXOff();
-        nYOff = poTarget->GetYOff();
-        poBand = poTarget->GetBand();
+        poTarget->Detach_unlocked();
+        poTarget->GetBand()->UnreferenceBlock(poTarget->GetXOff(),poTarget->GetYOff());
     }
 
-    CPLErr eErr = poBand->FlushBlock( nXOff, nYOff );
-    if (eErr != CE_None)
+    /* Note: flushing dirty blocks to disk is not really safe */
+    /* if the underlying dataset is being read/written by another thread */
+    /* This issue has always existed and has no obvious fix */
+    /* So only read-only operations should be considered thread-safe with */
+    /* the global cache */
+    if( poTarget->GetDirty() )
     {
-        /* Save the error for later reporting */
-        poBand->SetFlushBlockErr(eErr);
+        CPLErr eErr = poTarget->Write();
+        if( eErr != CE_None )
+        {
+             /* Save the error for later reporting */
+            poTarget->GetBand()->SetFlushBlockErr(eErr);
+        }
     }
+    delete poTarget;
 
     return TRUE;
 }
 
 /************************************************************************/
+/*                          FlushDirtyBlocks()                          */
+/************************************************************************/
+
+/**
+ * \brief Flush all dirty blocks from cache.
+ *
+ * This static method is normally used to recover memory and is especially
+ * usefull when doing multi-threaded code that can trigger the block cache.
+ *
+ * Due to the current design of the block cache, dirty blocks belonging to a same
+ * dataset could be pushed simultanously to the IWriteBlock() method of that
+ * dataset from different threads, causing races.
+ *
+ * Calling this method before that code can help workarounding that issue,
+ * in a multiple readers, one writer scenario.
+ *
+ * @since GDAL 2.0
+ */
+
+void GDALRasterBlock::FlushDirtyBlocks()
+
+{
+    while( FlushCacheBlock(TRUE) )
+    {
+        /* go on */
+    }
+}
+
+/************************************************************************/
 /*                          GDALRasterBlock()                           */
 /************************************************************************/
 
@@ -377,6 +456,7 @@ GDALRasterBlock::GDALRasterBlock( GDALRasterBand *poBandIn,
 
     nXOff = nXOffIn;
     nYOff = nYOffIn;
+    bMustDetach = TRUE;
 }
 
 /************************************************************************/
@@ -396,16 +476,7 @@ GDALRasterBlock::~GDALRasterBlock()
 
     if( pData != NULL )
     {
-        int nSizeInBytes;
-
         VSIFree( pData );
-
-        nSizeInBytes = (nXSize * nYSize * GDALGetDataTypeSize(eType)+7)/8;
-
-        {
-            CPLMutexHolderD( &hRBMutex );
-            nCacheUsed -= nSizeInBytes;
-        }
     }
 
     CPLAssert( nLockCount == 0 );
@@ -431,8 +502,15 @@ GDALRasterBlock::~GDALRasterBlock()
 void GDALRasterBlock::Detach()
 
 {
-    CPLMutexHolderD( &hRBMutex );
+    if( bMustDetach )
+    {
+        TAKE_LOCK;
+        Detach_unlocked();
+    }
+}
 
+void GDALRasterBlock::Detach_unlocked()
+{
     if( poOldest == this )
         poOldest = poPrevious;
 
@@ -449,6 +527,14 @@ void GDALRasterBlock::Detach()
 
     poPrevious = NULL;
     poNext = NULL;
+    bMustDetach = FALSE;
+
+    if( pData )
+        nCacheUsed -= GetBlockSize();
+
+#ifdef ENABLE_DEBUG
+    Verify();
+#endif
 }
 
 /************************************************************************/
@@ -463,7 +549,7 @@ void GDALRasterBlock::Detach()
 void GDALRasterBlock::Verify()
 
 {
-    CPLMutexHolderD( &hRBMutex );
+    TAKE_LOCK;
 
     CPLAssert( (poNewest == NULL && poOldest == NULL)
                || (poNewest != NULL && poOldest != NULL) );
@@ -473,20 +559,17 @@ void GDALRasterBlock::Verify()
         CPLAssert( poNewest->poPrevious == NULL );
         CPLAssert( poOldest->poNext == NULL );
         
-        for( GDALRasterBlock *poBlock = (GDALRasterBlock *) poNewest; 
+        GDALRasterBlock* poLast = NULL;
+        for( GDALRasterBlock *poBlock = poNewest; 
              poBlock != NULL;
              poBlock = poBlock->poNext )
         {
-            if( poBlock->poPrevious )
-            {
-                CPLAssert( poBlock->poPrevious->poNext == poBlock );
-            }
+            CPLAssert( poBlock->poPrevious == poLast );
 
-            if( poBlock->poNext )
-            {
-                CPLAssert( poBlock->poNext->poPrevious == poBlock );
-            }
+            poLast = poBlock;
         }
+
+        CPLAssert( poOldest == poLast );
     }
 }
 
@@ -535,11 +618,27 @@ CPLErr GDALRasterBlock::Write()
 void GDALRasterBlock::Touch()
 
 {
-    CPLMutexHolderD( &hRBMutex );
+    TAKE_LOCK;
+    Touch_unlocked();
+}
+
 
+void GDALRasterBlock::Touch_unlocked()
+
+{
     if( poNewest == this )
         return;
 
+    // In theory, we shouldn't try to touch a block that has been detached
+    CPLAssert(bMustDetach);
+    if( !bMustDetach )
+    {
+        if( pData )
+            nCacheUsed += GetBlockSize();
+
+        bMustDetach = TRUE;
+    }
+
     if( poOldest == this )
         poOldest = this->poPrevious;
     
@@ -550,7 +649,7 @@ void GDALRasterBlock::Touch()
         poNext->poPrevious = poPrevious;
 
     poPrevious = NULL;
-    poNext = (GDALRasterBlock *) poNewest;
+    poNext = poNewest;
 
     if( poNewest != NULL )
     {
@@ -587,49 +686,105 @@ void GDALRasterBlock::Touch()
 CPLErr GDALRasterBlock::Internalize()
 
 {
-    CPLMutexHolderD( &hRBMutex );
     void        *pNewData;
     int         nSizeInBytes;
-    GIntBig     nCurCacheMax = GDALGetCacheMax64();
 
-    /* No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo() */
-    nSizeInBytes = nXSize * nYSize * (GDALGetDataTypeSize(eType) / 8);
+    CPLAssert( pData == NULL );
 
-    pNewData = VSIMalloc( nSizeInBytes );
-    if( pNewData == NULL )
-    {
-        CPLError( CE_Failure, CPLE_OutOfMemory, 
-                  "GDALRasterBlock::Internalize : Out of memory allocating %d bytes.",
-                  nSizeInBytes);
-        return( CE_Failure );
-    }
+    // This call will initialize the hRBLock mutex. Other call places can
+    // only be called if we have go through there.
+    GIntBig     nCurCacheMax = GDALGetCacheMax64();
 
-    if( pData != NULL )
-        memcpy( pNewData, pData, nSizeInBytes );
-    
-    pData = pNewData;
+    /* No risk of overflow as it is checked in GDALRasterBand::InitBlockInfo() */
+    nSizeInBytes = GetBlockSize();
 
 /* -------------------------------------------------------------------- */
 /*      Flush old blocks if we are nearing our memory limit.            */
 /* -------------------------------------------------------------------- */
-    AddLock(); /* don't flush this block! */
+    GDALRasterBlock* apoBlocksToFree[64];
+    int nBlocksToFree = 0;
+    {
+        TAKE_LOCK;
 
-    nCacheUsed += nSizeInBytes;
-    while( nCacheUsed > nCurCacheMax )
+        nCacheUsed += nSizeInBytes;
+        GDALRasterBlock *poTarget = poOldest;
+        while( nCacheUsed > nCurCacheMax )
+        {
+            while( poTarget != NULL && poTarget->GetLockCount() > 0 ) 
+                poTarget = poTarget->poPrevious;
+
+            if( poTarget != NULL )
+            {
+                GDALRasterBlock* _poPrevious = poTarget->poPrevious;
+
+                poTarget->Detach_unlocked();
+                poTarget->GetBand()->UnreferenceBlock(poTarget->GetXOff(),poTarget->GetYOff());
+
+                apoBlocksToFree[nBlocksToFree++] = poTarget;
+                if( nBlocksToFree == 64 )
+                {
+                    CPLDebug("GDAL", "More than 64 blocks are flagged to be flushed. Not trying more");
+                    break;
+                }
+
+                poTarget = _poPrevious;
+            }
+            else
+                break;
+        }
+
+    /* -------------------------------------------------------------------- */
+    /*      Add this block to the list.                                     */
+    /* -------------------------------------------------------------------- */
+        Touch_unlocked();
+    }
+
+    /* Now free blocks we have detached and removed from their band */
+    pNewData = NULL;
+    for(int i=0;i<nBlocksToFree;i++)
     {
-        GIntBig nOldCacheUsed = nCacheUsed;
+        GDALRasterBlock *poBlock = apoBlocksToFree[i];
+
+        /* Note: flushing dirty blocks to disk is not really safe */
+        /* if the underlying dataset is being read/written by another thread */
+        /* This issue has always existed and has no obvious fix */
+        /* So only read-only operations should be considered thread-safe with */
+        /* the global cache */
+        if( poBlock->GetDirty() )
+        {
+            CPLErr eErr = poBlock->Write();
+            if( eErr != CE_None )
+            {
+                 /* Save the error for later reporting */
+                poBlock->GetBand()->SetFlushBlockErr(eErr);
+            }
+        }
 
-        GDALFlushCacheBlock();
+        /* Try to recycle the data of an existing block */
+        void* pDataBlock = poBlock->pData;
+        if( pNewData == NULL && pDataBlock != NULL &&
+            poBlock->GetBlockSize() >= nSizeInBytes )
+        {
+            pNewData = pDataBlock;
+            poBlock->pData = NULL;
+        }
 
-        if( nCacheUsed == nOldCacheUsed )
-            break;
+        delete poBlock;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Add this block to the list.                                     */
-/* -------------------------------------------------------------------- */
-    Touch();
-    DropLock();
+    if( pNewData == NULL )
+    {
+        pNewData = VSIMalloc( nSizeInBytes );
+        if( pNewData == NULL )
+        {
+            CPLError( CE_Failure, CPLE_OutOfMemory, 
+                    "GDALRasterBlock::Internalize : Out of memory allocating %d bytes.",
+                    nSizeInBytes);
+            return( CE_Failure );
+        }
+    }
+
+    pData = pNewData;
 
     return( CE_None );
 }
@@ -690,12 +845,12 @@ int GDALRasterBlock::SafeLockBlock( GDALRasterBlock ** ppBlock )
 {
     CPLAssert( NULL != ppBlock );
 
-    CPLMutexHolderD( &hRBMutex );
+    TAKE_LOCK;
 
     if( *ppBlock != NULL )
     {
         (*ppBlock)->AddLock();
-        (*ppBlock)->Touch();
+        (*ppBlock)->Touch_unlocked();
         
         return TRUE;
     }
@@ -709,7 +864,7 @@ int GDALRasterBlock::SafeLockBlock( GDALRasterBlock ** ppBlock )
 
 void GDALRasterBlock::DestroyRBMutex()
 {
-    if( hRBMutex != NULL )
-        CPLDestroyMutex(hRBMutex);
-    hRBMutex = NULL;
+    if( hRBLock != NULL )
+        DESTROY_LOCK;
+    hRBLock = NULL;
 }
diff --git a/gcore/gdalrescaledalphaband.cpp b/gcore/gdalrescaledalphaband.cpp
index a25a962..c48fb34 100644
--- a/gcore/gdalrescaledalphaband.cpp
+++ b/gcore/gdalrescaledalphaband.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalrescaledalphaband.cpp 27858 2014-10-15 08:41:23Z rouault $
+ * $Id: gdalrescaledalphaband.cpp 28053 2014-12-04 09:31:07Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Implementation of GDALRescaledAlphaBand, a class implementing
@@ -30,7 +30,7 @@
 
 #include "gdal_priv.h"
 
-CPL_CVSID("$Id: gdalrescaledalphaband.cpp 27858 2014-10-15 08:41:23Z rouault $");
+CPL_CVSID("$Id: gdalrescaledalphaband.cpp 28053 2014-12-04 09:31:07Z rouault $");
 
 /************************************************************************/
 /*                        GDALRescaledAlphaBand()                       */
@@ -79,10 +79,13 @@ CPLErr GDALRescaledAlphaBand::IReadBlock( int nXBlockOff, int nYBlockOff,
     if (nYBlockOff * nBlockYSize + nBlockYSize > nRasterYSize)
         nYSizeRequest = nRasterYSize - nYBlockOff * nBlockYSize;
 
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
     return IRasterIO(GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
                      nXSizeRequest, nYSizeRequest, pImage,
                      nXSizeRequest, nYSizeRequest, GDT_Byte,
-                     1, nBlockXSize);
+                     1, nBlockXSize, &sExtraArg);
 }
 
 /************************************************************************/
@@ -93,7 +96,9 @@ CPLErr GDALRescaledAlphaBand::IRasterIO( GDALRWFlag eRWFlag,
                                       int nXOff, int nYOff, int nXSize, int nYSize,
                                       void * pData, int nBufXSize, int nBufYSize,
                                       GDALDataType eBufType,
-                                      int nPixelSpace, int nLineSpace )
+                                      GSpacing nPixelSpace,
+                                      GSpacing nLineSpace,
+                                      GDALRasterIOExtraArg* psExtraArg )
 {
     /* Optimization in common use case */
     /* This avoids triggering the block cache on this band, which helps */
@@ -117,7 +122,7 @@ CPLErr GDALRescaledAlphaBand::IRasterIO( GDALRWFlag eRWFlag,
             CPLErr eErr = poParent->RasterIO( GF_Read, nXOff, nYOff + j, nXSize, 1,
                                               pTemp, nBufXSize, 1,
                                               GDT_UInt16,
-                                              0, 0 );
+                                              0, 0, NULL );
             if (eErr != CE_None)
                 return eErr;
 
@@ -140,5 +145,5 @@ CPLErr GDALRescaledAlphaBand::IRasterIO( GDALRWFlag eRWFlag,
     return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                       pData, nBufXSize, nBufYSize,
                                       eBufType,
-                                      nPixelSpace, nLineSpace );
+                                      nPixelSpace, nLineSpace, psExtraArg );
 }
diff --git a/gcore/gdalsse_priv.h b/gcore/gdalsse_priv.h
new file mode 100644
index 0000000..e323e87
--- /dev/null
+++ b/gcore/gdalsse_priv.h
@@ -0,0 +1,571 @@
+/******************************************************************************
+ * $Id: gdalsse_priv.h 28877 2015-04-08 23:11:36Z rouault $
+ *
+ * Project:  GDAL
+ * Purpose:  SSE2 helper
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef GDALSSE_PRIV_H_INCLUDED
+#define GDALSSE_PRIV_H_INCLUDED
+
+/* We restrict to 64bit processors because they are guaranteed to have SSE2 */
+/* Could possibly be used too on 32bit, but we would need to check at runtime */
+#if (defined(__x86_64) || defined(_M_X64)) && !defined(USE_SSE2_EMULATION)
+
+/* Requires SSE2 */
+#include <emmintrin.h>
+#include <string.h>
+
+class XMMReg2Double
+{
+  public:
+    __m128d xmm;
+
+    XMMReg2Double() {}
+    XMMReg2Double(double  val)  { xmm = _mm_load_sd (&val); }
+    XMMReg2Double(const XMMReg2Double& other) : xmm(other.xmm) {}
+
+    static inline XMMReg2Double Zero()
+    {
+        XMMReg2Double reg;
+        reg.Zeroize();
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const double* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const float* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2ValAligned(const double* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2ValAligned(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const unsigned char* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const short* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const unsigned short* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+    
+    inline void nsLoad2Val(const double* ptr)
+    {
+        xmm = _mm_loadu_pd(ptr);
+    }
+
+    inline void nsLoad2ValAligned(const double* pval)
+    {
+        xmm = _mm_load_pd(pval);
+    }
+
+    inline void nsLoad2Val(const float* pval)
+    {
+        __m128 temp1 = _mm_load_ss(pval);
+        __m128 temp2 = _mm_load_ss(pval + 1);
+        temp1 = _mm_shuffle_ps(temp1, temp2, _MM_SHUFFLE(1,0,1,0));
+        temp1 = _mm_shuffle_ps(temp1, temp1, _MM_SHUFFLE(3,3,2,0));
+        xmm = _mm_cvtps_pd(temp1);
+    }
+
+    inline void nsLoad2Val(const unsigned char* ptr)
+    {
+        __m128i xmm_i = _mm_cvtsi32_si128(*(unsigned short*)(ptr));
+        xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
+        xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
+        xmm = _mm_cvtepi32_pd(xmm_i);
+    }
+
+    inline void nsLoad2Val(const short* ptr)
+    {
+        int i;
+        memcpy(&i, ptr, 4);
+        __m128i xmm_i = _mm_cvtsi32_si128(i);
+        xmm_i = _mm_unpacklo_epi16(xmm_i,xmm_i); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|b|b|a|a */
+        xmm_i = _mm_srai_epi32(xmm_i, 16);       /* 0|0|0|0|b|b|a|a --> 0|0|0|0|sign(b)|b|sign(a)|a */
+        xmm = _mm_cvtepi32_pd(xmm_i);
+    }
+
+    inline void nsLoad2Val(const unsigned short* ptr)
+    {
+        int i;
+        memcpy(&i, ptr, 4);
+        __m128i xmm_i = _mm_cvtsi32_si128(i);
+        xmm_i = _mm_unpacklo_epi16(xmm_i,xmm_i); /* 0|0|0|0|0|0|b|a --> 0|0|0|0|b|b|a|a */
+        xmm_i = _mm_srli_epi32(xmm_i, 16);       /* 0|0|0|0|b|b|a|a --> 0|0|0|0|0|b|0|a */
+        xmm = _mm_cvtepi32_pd(xmm_i);
+    }
+    
+    static inline void Load4Val(const unsigned char* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        __m128i xmm_i = _mm_cvtsi32_si128(*(int*)(ptr));
+        xmm_i = _mm_unpacklo_epi8(xmm_i, _mm_setzero_si128());
+        xmm_i = _mm_unpacklo_epi16(xmm_i, _mm_setzero_si128());
+        low.xmm = _mm_cvtepi32_pd(xmm_i);
+        high.xmm =  _mm_cvtepi32_pd(_mm_shuffle_epi32(xmm_i,_MM_SHUFFLE(3,2,3,2)));
+    }
+
+    static inline void Load4Val(const short* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const unsigned short* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const double* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const float* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        __m128 temp1 = _mm_loadu_ps(ptr);
+        __m128 temp2 = _mm_shuffle_ps(temp1, temp1, _MM_SHUFFLE(3,2,3,2));
+        low.xmm = _mm_cvtps_pd(temp1);
+        high.xmm = _mm_cvtps_pd(temp2);
+    }
+    
+    inline void Zeroize()
+    {
+        xmm = _mm_setzero_pd();
+    }
+
+    inline const XMMReg2Double& operator= (const XMMReg2Double& other)
+    {
+        xmm = other.xmm;
+        return *this;
+    }
+
+    inline const XMMReg2Double& operator+= (const XMMReg2Double& other)
+    {
+        xmm = _mm_add_pd(xmm, other.xmm);
+        return *this;
+    }
+
+    inline XMMReg2Double operator+ (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.xmm = _mm_add_pd(xmm, other.xmm);
+        return ret;
+    }
+
+    inline XMMReg2Double operator- (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.xmm = _mm_sub_pd(xmm, other.xmm);
+        return ret;
+    }
+
+    inline XMMReg2Double operator* (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.xmm = _mm_mul_pd(xmm, other.xmm);
+        return ret;
+    }
+
+    inline const XMMReg2Double& operator*= (const XMMReg2Double& other)
+    {
+        xmm = _mm_mul_pd(xmm, other.xmm);
+        return *this;
+    }
+
+    inline void AddLowAndHigh()
+    {
+        __m128d xmm2;
+        xmm2 = _mm_shuffle_pd(xmm,xmm,_MM_SHUFFLE2(0,1)); /* transfer high word into low word of xmm2 */
+        xmm = _mm_add_pd(xmm, xmm2);
+    }
+    
+    inline void Store2Double(double* pval)
+    {
+        _mm_storeu_pd(pval, xmm);
+    }
+    
+    inline void Store2DoubleAligned(double* pval)
+    {
+        _mm_store_pd(pval, xmm);
+    }
+
+    inline operator double () const
+    {
+        double val;
+        _mm_store_sd(&val, xmm);
+        return val;
+    }
+};
+
+#else
+
+#warning "Software emulation of SSE2 !"
+
+class XMMReg2Double
+{
+  public:
+    double low;
+    double high;
+
+    XMMReg2Double() {}
+    XMMReg2Double(double  val)  { low = val; high = 0.0; }
+    XMMReg2Double(const XMMReg2Double& other) : low(other.low), high(other.high) {}
+
+    static inline XMMReg2Double Zero()
+    {
+        XMMReg2Double reg;
+        reg.Zeroize();
+        return reg;
+    }
+    
+    static inline XMMReg2Double Load2Val(const double* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2ValAligned(const double* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2ValAligned(ptr);
+        return reg;
+    }
+    
+    static inline XMMReg2Double Load2Val(const float* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const unsigned char* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    static inline XMMReg2Double Load2Val(const short* ptr)
+    {
+        XMMReg2Double reg;
+        reg.nsLoad2Val(ptr);
+        return reg;
+    }
+
+    inline void nsLoad2Val(const double* pval)
+    {
+        low = pval[0];
+        high = pval[1];
+    }
+
+    inline void nsLoad2ValAligned(const double* pval)
+    {
+        low = pval[0];
+        high = pval[1];
+    }
+
+    inline void nsLoad2Val(const float* pval)
+    {
+        low = pval[0];
+        high = pval[1];
+    }
+
+    inline void nsLoad2Val(const unsigned char* ptr)
+    {
+        low = ptr[0];
+        high = ptr[1];
+    }
+
+    inline void nsLoad2Val(const short* ptr)
+    {
+        low = ptr[0];
+        high = ptr[1];
+    }
+
+    inline void nsLoad2Val(const unsigned short* ptr)
+    {
+        low = ptr[0];
+        high = ptr[1];
+    }
+    
+    static inline void Load4Val(const unsigned char* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.low = ptr[0];
+        low.high = ptr[1];
+        high.low = ptr[2];
+        high.high = ptr[3];
+    }
+
+    static inline void Load4Val(const short* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const unsigned short* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const double* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    static inline void Load4Val(const float* ptr, XMMReg2Double& low, XMMReg2Double& high)
+    {
+        low.nsLoad2Val(ptr);
+        high.nsLoad2Val(ptr+2);
+    }
+
+    inline void Zeroize()
+    {
+        low = 0.0;
+        high = 0.0;
+    }
+
+    inline const XMMReg2Double& operator= (const XMMReg2Double& other)
+    {
+        low = other.low;
+        high = other.high;
+        return *this;
+    }
+
+    inline const XMMReg2Double& operator+= (const XMMReg2Double& other)
+    {
+        low += other.low;
+        high += other.high;
+        return *this;
+    }
+
+    inline XMMReg2Double operator+ (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.low = low + other.low;
+        ret.high = high + other.high;
+        return ret;
+    }
+
+    inline XMMReg2Double operator- (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.low = low - other.low;
+        ret.high = high - other.high;
+        return ret;
+    }
+
+    inline XMMReg2Double operator* (const XMMReg2Double& other)
+    {
+        XMMReg2Double ret;
+        ret.low = low * other.low;
+        ret.high = high * other.high;
+        return ret;
+    }
+
+    inline const XMMReg2Double& operator*= (const XMMReg2Double& other)
+    {
+        low *= other.low;
+        high *= other.high;
+        return *this;
+    }
+
+    inline void AddLowAndHigh()
+    {
+        double add = low + high;
+        low = add;
+        high = add;
+    }
+
+    inline void Store2Double(double* pval)
+    {
+        pval[0] = low;
+        pval[1] = high;
+    }
+    
+    inline void Store2DoubleAligned(double* pval)
+    {
+        pval[0] = low;
+        pval[1] = high;
+    }
+
+    inline operator double () const
+    {
+        return low;
+    }
+};
+
+#endif /*  defined(__x86_64) || defined(_M_X64) */
+
+class XMMReg4Double
+{
+  public:
+    XMMReg2Double low, high;
+
+    XMMReg4Double() {}
+    XMMReg4Double(const XMMReg4Double& other) : low(other.low), high(other.high) {}
+
+    static inline XMMReg4Double Zero()
+    {
+        XMMReg4Double reg;
+        reg.low.Zeroize();
+        reg.high.Zeroize();
+        return reg;
+    }
+    
+    static inline XMMReg4Double Load4Val(const unsigned char* ptr)
+    {
+        XMMReg4Double reg;
+        XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
+        return reg;
+    }
+
+    static inline XMMReg4Double Load4Val(const short* ptr)
+    {
+        XMMReg4Double reg;
+        reg.low.nsLoad2Val(ptr);
+        reg.high.nsLoad2Val(ptr+2);
+        return reg;
+    }
+
+    static inline XMMReg4Double Load4Val(const unsigned short* ptr)
+    {
+        XMMReg4Double reg;
+        reg.low.nsLoad2Val(ptr);
+        reg.high.nsLoad2Val(ptr+2);
+        return reg;
+    }
+
+    static inline XMMReg4Double Load4Val(const double* ptr)
+    {
+        XMMReg4Double reg;
+        reg.low.nsLoad2Val(ptr);
+        reg.high.nsLoad2Val(ptr+2);
+        return reg;
+    }
+
+    static inline XMMReg4Double Load4ValAligned(const double* ptr)
+    {
+        XMMReg4Double reg;
+        reg.low.nsLoad2ValAligned(ptr);
+        reg.high.nsLoad2ValAligned(ptr+2);
+        return reg;
+    }
+
+    static inline XMMReg4Double Load4Val(const float* ptr)
+    {
+        XMMReg4Double reg;
+        XMMReg2Double::Load4Val(ptr, reg.low, reg.high);
+        return reg;
+    }
+    
+    inline const XMMReg4Double& operator= (const XMMReg4Double& other)
+    {
+        low = other.low;
+        high = other.high;
+        return *this;
+    }
+
+    inline const XMMReg4Double& operator+= (const XMMReg4Double& other)
+    {
+        low += other.low;
+        high += other.high;
+        return *this;
+    }
+
+    inline XMMReg4Double operator+ (const XMMReg4Double& other)
+    {
+        XMMReg4Double ret;
+        ret.low = low + other.low;
+        ret.high = high + other.high;
+        return ret;
+    }
+
+    inline XMMReg4Double operator- (const XMMReg4Double& other)
+    {
+        XMMReg4Double ret;
+        ret.low = low - other.low;
+        ret.high = high - other.high;
+        return ret;
+    }
+
+    inline XMMReg4Double operator* (const XMMReg4Double& other)
+    {
+        XMMReg4Double ret;
+        ret.low = low * other.low;
+        ret.high = high * other.high;
+        return ret;
+    }
+
+    inline const XMMReg4Double& operator*= (const XMMReg4Double& other)
+    {
+        low *= other.low;
+        high *= other.high;
+        return *this;
+    }
+
+    inline void AddLowAndHigh()
+    {
+        low = low + high;
+        low.AddLowAndHigh();
+    }
+
+    inline XMMReg2Double& GetLow()
+    {
+        return low;
+    }
+};
+
+#endif /* GDALSSE_PRIV_H_INCLUDED */
diff --git a/gcore/gdalvirtualmem.cpp b/gcore/gdalvirtualmem.cpp
index 0f54653..a827143 100644
--- a/gcore/gdalvirtualmem.cpp
+++ b/gcore/gdalvirtualmem.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: gdalvirtualmem.cpp 27922 2014-11-05 13:01:30Z rouault $
+ * $Id: gdalvirtualmem.cpp 27921 2014-11-05 12:58:23Z rouault $
  *
  * Name:     gdalvirtualmem.cpp
  * Project:  GDAL
@@ -32,6 +32,10 @@
 #include "cpl_conv.h"
 #include "cpl_virtualmem.h"
 
+/* To be changed if we go to 64-bit RasterIO coordinates and spacing */
+typedef int coord_type;
+typedef int spacing_type;
+
 /************************************************************************/
 /*                            GDALVirtualMem                            */
 /************************************************************************/
@@ -40,12 +44,12 @@ class GDALVirtualMem
 {
     GDALDatasetH hDS;
     GDALRasterBandH hBand;
-    int nXOff;
-    int nYOff;
+    coord_type nXOff;
+    coord_type nYOff;
     /*int nXSize;
     int nYSize;*/
-    int nBufXSize;
-    int nBufYSize;
+    coord_type nBufXSize;
+    coord_type nBufYSize;
     GDALDataType eBufType;
     int nBandCount;
     int* panBandMap;
@@ -59,9 +63,9 @@ class GDALVirtualMem
     int  IsCompact() const { return bIsCompact; }
     int  IsBandSequential() const { return bIsBandSequential; }
 
-    void GetXYBand( size_t nOffset, int& x, int& y, int& band ) const;
-    size_t GetOffset(int x, int y, int band) const;
-    int  GotoNextPixel(int& x, int& y, int& band) const;
+    void GetXYBand( size_t nOffset, coord_type& x, coord_type& y, int& band ) const;
+    size_t GetOffset(coord_type x, coord_type y, int band) const;
+    int  GotoNextPixel(coord_type& x, coord_type& y, int& band) const;
 
     void DoIOBandSequential( GDALRWFlag eRWFlag, size_t nOffset,
                               void* pPage, size_t nBytes ) const;
@@ -71,9 +75,9 @@ class GDALVirtualMem
 public:
              GDALVirtualMem( GDALDatasetH hDS,
                              GDALRasterBandH hBand,
-                          int nXOff, int nYOff,
-                          int nXSize, int nYSize,
-                          int nBufXSize, int nBufYSize,
+                          coord_type nXOff, coord_type nYOff,
+                          coord_type nXSize, coord_type nYSize,
+                          coord_type nBufXSize, coord_type nBufYSize,
                           GDALDataType eBufType,
                           int nBandCount, const int* panBandMapIn,
                           int nPixelSpace,
@@ -104,9 +108,10 @@ public:
 
 GDALVirtualMem::GDALVirtualMem( GDALDatasetH hDS,
                                 GDALRasterBandH hBand,
-                                int nXOff, int nYOff,
-                                CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
-                                int nBufXSize, int nBufYSize,
+                                coord_type nXOff, coord_type nYOff,
+                                CPL_UNUSED coord_type nXSize,
+                                CPL_UNUSED coord_type nYSize,
+                                coord_type nBufXSize, coord_type nBufYSize,
                                 GDALDataType eBufType,
                                 int nBandCount, const int* panBandMapIn,
                                 int nPixelSpace,
@@ -165,25 +170,25 @@ GDALVirtualMem::~GDALVirtualMem()
 /*                              GetXYBand()                             */
 /************************************************************************/
 
-void GDALVirtualMem::GetXYBand( size_t nOffset, int& x, int& y, int& band ) const
+void GDALVirtualMem::GetXYBand( size_t nOffset, coord_type& x, coord_type& y, int& band ) const
 {
     if( IsBandSequential() )
     {
         if( nBandCount == 1 )
             band = 0;
         else
-            band = nOffset / nBandSpace;
-        y = (nOffset - band * nBandSpace) / nLineSpace;
-        x = (nOffset - band * nBandSpace - y * nLineSpace) / nPixelSpace;
+            band = (int)(nOffset / nBandSpace);
+        y = (coord_type)((nOffset - band * nBandSpace) / nLineSpace);
+        x = (coord_type)((nOffset - band * nBandSpace - y * nLineSpace) / nPixelSpace);
     }
     else
     {
-        y = nOffset / nLineSpace;
-        x = (nOffset - y * nLineSpace) / nPixelSpace;
+        y = (coord_type)(nOffset / nLineSpace);
+        x = (coord_type)((nOffset - y * nLineSpace) / nPixelSpace);
         if( nBandCount == 1 )
             band = 0;
         else
-            band = (nOffset - y * nLineSpace - x * nPixelSpace) / nBandSpace;
+            band = (int)((nOffset - y * nLineSpace - x * nPixelSpace) / nBandSpace);
     }
 }
 
@@ -191,7 +196,7 @@ void GDALVirtualMem::GetXYBand( size_t nOffset, int& x, int& y, int& band ) cons
 /*                            GotoNextPixel()                           */
 /************************************************************************/
 
-int GDALVirtualMem::GotoNextPixel(int& x, int& y, int& band) const
+int GDALVirtualMem::GotoNextPixel(coord_type& x, coord_type& y, int& band) const
 {
     if( IsBandSequential() )
     {
@@ -232,9 +237,9 @@ int GDALVirtualMem::GotoNextPixel(int& x, int& y, int& band) const
 /*                              GetOffset()                             */
 /************************************************************************/
 
-size_t GDALVirtualMem::GetOffset(int x, int y, int band) const
+size_t GDALVirtualMem::GetOffset(coord_type x, coord_type y, int band) const
 {
-    return x * nPixelSpace + y * nLineSpace + band * nBandSpace;
+    return (size_t)(x * nPixelSpace + y * nLineSpace + band * nBandSpace);
 }
 
 /************************************************************************/
@@ -244,7 +249,8 @@ size_t GDALVirtualMem::GetOffset(int x, int y, int band) const
 void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                         const size_t nOffset, void* pPage, size_t nBytes ) const
 {
-    int x, y, band;
+    coord_type x, y;
+    int band;
 
     GetXYBand(nOffset, x, y, band);
     /*fprintf(stderr, "eRWFlag=%d, nOffset=%d, x=%d, y=%d, band=%d\n",
@@ -284,7 +290,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
         if( nEndOffsetEndOfPixel - nOffset > nBytes )
         {
             // Not enough space: find last possible band
-            int xEnd, yEnd;
+            coord_type xEnd, yEnd;
             GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
             CPLAssert(x == xEnd);
             CPLAssert(y == yEnd);
@@ -298,7 +304,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                             (char*)pPage + nOffsetShift,
                             1, 1, eBufType,
                             bandEnd - band, panBandMap + band,
-                            nPixelSpace, nLineSpace, nBandSpace );
+                            nPixelSpace, (spacing_type)nLineSpace, (spacing_type)nBandSpace );
 
         if( bandEnd < nBandCount )
             return;
@@ -317,7 +323,8 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
     if( nEndOffsetEndOfLine - nOffset > nBytes )
     {
         // No : read/write as many pixels on this line as possible
-        int xEnd, yEnd, bandEnd;
+        coord_type xEnd, yEnd;
+        int bandEnd;
         GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
         CPLAssert(y == yEnd);
 
@@ -328,7 +335,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                                 (char*) pPage + nOffsetShift,
                                 xEnd - x, 1, eBufType,
                                 nBandCount, panBandMap,
-                                nPixelSpace, nLineSpace, nBandSpace );
+                                nPixelSpace, (spacing_type)nLineSpace, (spacing_type)nBandSpace );
         }
 
         // Are there partial bands to read/write for the last pixel ?
@@ -348,7 +355,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                                 (char*) pPage + nOffsetShift,
                                 1, 1, eBufType,
                                 bandEnd, panBandMap,
-                                nPixelSpace, nLineSpace, nBandSpace );
+                                nPixelSpace, (spacing_type)nLineSpace, (spacing_type)nBandSpace );
         }
 
         return;
@@ -362,7 +369,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                     (char*)pPage + nOffsetShift,
                     nBufXSize - x, 1, eBufType,
                     nBandCount, panBandMap,
-                    nPixelSpace, nLineSpace, nBandSpace );
+                    nPixelSpace, (spacing_type)nLineSpace, (spacing_type)nBandSpace );
 
         // Go to beginning of next line
         x = nBufXSize - 1;
@@ -376,7 +383,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
     }
 
     // How many whole lines can we store/load ?
-    int nLineCount = (nBytes - nOffsetShift) / nLineSpace;
+    coord_type nLineCount = (coord_type)((nBytes - nOffsetShift) / nLineSpace);
     if( y + nLineCount > nBufYSize )
         nLineCount = nBufYSize - y;
     if( nLineCount > 0 )
@@ -386,7 +393,7 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
                              (GByte*) pPage + nOffsetShift,
                              nBufXSize, nLineCount, eBufType,
                              nBandCount, panBandMap,
-                             nPixelSpace, nLineSpace, nBandSpace );
+                             nPixelSpace, (spacing_type)nLineSpace, (spacing_type)nBandSpace );
         
         y += nLineCount;
         if( y == nBufYSize )
@@ -409,7 +416,8 @@ void GDALVirtualMem::DoIOPixelInterleaved( GDALRWFlag eRWFlag,
 void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
                         const size_t nOffset, void* pPage, size_t nBytes ) const
 {
-    int x, y, band;
+    coord_type x, y;
+    int band;
 
     GetXYBand(nOffset, x, y, band);
     /*fprintf(stderr, "eRWFlag=%d, nOffset=%d, x=%d, y=%d, band=%d\n",
@@ -443,7 +451,8 @@ void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
     if( nEndOffsetEndOfLine - nOffset > nBytes )
     {
         // No : read/write as many pixels on this line as possible
-        int xEnd, yEnd, bandEnd;
+        coord_type xEnd, yEnd;
+        int bandEnd;
         GetXYBand(nOffset + nBytes, xEnd, yEnd, bandEnd);
         CPLAssert(y == yEnd);
         CPLAssert(band == bandEnd);
@@ -451,7 +460,7 @@ void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
                       nXOff + x, nYOff + y, xEnd - x, 1,
                       (char*)pPage + nOffsetShift,
                       xEnd - x, 1, eBufType,
-                      nPixelSpace, nLineSpace );
+                      nPixelSpace, (spacing_type)nLineSpace );
 
         return;
     }
@@ -463,7 +472,7 @@ void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
                     nXOff + x, nYOff + y, nBufXSize - x, 1,
                     (char*)pPage + nOffsetShift,
                     nBufXSize - x, 1, eBufType,
-                    nPixelSpace, nLineSpace );
+                    nPixelSpace, (spacing_type)nLineSpace );
 
         // Go to beginning of next line
         x = nBufXSize - 1;
@@ -476,7 +485,7 @@ void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
     }
 
     // How many whole lines can we store/load ?
-    int nLineCount = (nBytes - nOffsetShift) / nLineSpace;
+    coord_type nLineCount = (coord_type)((nBytes - nOffsetShift) / nLineSpace);
     if( y + nLineCount > nBufYSize )
         nLineCount = nBufYSize - y;
     if( nLineCount > 0 )
@@ -485,7 +494,7 @@ void GDALVirtualMem::DoIOBandSequential( GDALRWFlag eRWFlag,
                     nXOff + 0, nYOff + y, nBufXSize, nLineCount,
                     (GByte*) pPage + nOffsetShift,
                     nBufXSize, nLineCount, eBufType,
-                    nPixelSpace, nLineSpace );
+                    nPixelSpace, (spacing_type)nLineSpace );
 
         y += nLineCount;
         if( y == nBufYSize )
@@ -617,9 +626,9 @@ static int GDALCheckBandParameters( GDALDatasetH hDS,
 static CPLVirtualMem* GDALGetVirtualMem( GDALDatasetH hDS,
                                          GDALRasterBandH hBand,
                                          GDALRWFlag eRWFlag,
-                                         int nXOff, int nYOff,
-                                         int nXSize, int nYSize,
-                                         int nBufXSize, int nBufYSize,
+                                         coord_type nXOff, coord_type nYOff,
+                                         coord_type nXSize, coord_type nYSize,
+                                         coord_type nBufXSize, coord_type nBufYSize,
                                          GDALDataType eBufType,
                                          int nBandCount, int* panBandMap,
                                          int nPixelSpace,
diff --git a/gcore/jp2dump.cpp b/gcore/jp2dump.cpp
old mode 100755
new mode 100644
diff --git a/gcore/makefile.vc b/gcore/makefile.vc
index bdaad65..711b5cd 100644
--- a/gcore/makefile.vc
+++ b/gcore/makefile.vc
@@ -7,11 +7,12 @@ OBJ	=	gdalopeninfo.obj gdaldrivermanager.obj gdaldriver.obj \
 		gdaljp2metadata.obj gdaljp2box.obj gdalgmlcoverage.obj \
 		gdalmultidomainmetadata.obj gdalpamproxydb.obj \
 		gdalallvalidmaskband.obj gdalnodatamaskband.obj \
-		gdal_rpcimdio.obj gdalproxydataset.obj gdalproxypool.obj \
+                gdalproxydataset.obj gdalproxypool.obj \
 		gdalnodatavaluesmaskband.obj gdaldefaultasync.obj \
 		gdaldllmain.obj gdalexif.obj gdalclientserver.obj \
 		gdalgeorefpamdataset.obj  gdaljp2abstractdataset.obj \
-		gdalvirtualmem.obj gdalrescaledalphaband.obj
+		gdalvirtualmem.obj gdaloverviewdataset.obj gdalrescaledalphaband.obj \
+		gdaljp2structure.obj gdal_mdreader.obj gdaljp2metadatagenerator.obj
 
 RES	=	Version.res
 
@@ -19,14 +20,30 @@ GDAL_ROOT	=	..
 
 !INCLUDE ..\nmake.opt
 
-EXTRAFLAGS =	$(PAM_SETTING) -I..\frmts\gtiff
+EXTRAFLAGS =	$(PAM_SETTING) -I..\frmts\gtiff -I..\frmts\mem -I..\frmts\vrt -I..\ogr\ogrsf_frmts\generic -I..\ogr\ogrsf_frmts\geojson\libjson $(SQLITEDEF)
 
-default:	$(OBJ) $(RES)
+!IFDEF SQLITE_LIB
+SQLITEDEF	=	-DSQLITE_ENABLED
+!ENDIF
+
+!IFDEF LIBXML2_INC
+EXTRAFLAGS =	$(EXTRAFLAGS) -DHAVE_LIBXML2 $(LIBXML2_INC)
+!ENDIF
+
+default:	$(OBJ) $(RES) mdreader_dir
 
 clean:
 	-del *.obj *.res
+	cd mdreader
+	$(MAKE) /f makefile.vc clean
+	cd ..
 
 Version.res:	
-	rc -fo Version.res -r -I..\port Version.rc
+	rc -fo Version.res -r -I..\port -I..\ogr Version.rc
 
 gdal_misc.obj:	gdal_misc.cpp gdal_version.h
+
+mdreader_dir:
+	cd mdreader
+	$(MAKE) /f makefile.vc
+	cd ..
diff --git a/gcore/mdreader/GNUmakefile b/gcore/mdreader/GNUmakefile
new file mode 100644
index 0000000..4061015
--- /dev/null
+++ b/gcore/mdreader/GNUmakefile
@@ -0,0 +1,26 @@
+
+include ../../GDALmake.opt
+
+OBJ	=	reader_digital_globe.o reader_geo_eye.o reader_orb_view.o \
+                reader_pleiades.o reader_rdk1.o reader_landsat.o
+
+UP_OBJ   = $(addprefix ../,$(OBJ))
+
+default:	$(UP_OBJ:.o=.$(OBJ_EXT))
+
+install-obj:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+../%.$(OBJ_EXT):	%.c
+	$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+../%.$(OBJ_EXT):	%.cpp
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+%.$(OBJ_EXT):	%.c
+	$(CC) $(GDAL_INCLUDE) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+%.$(OBJ_EXT):	%.cpp
+	$(CXX) $(GDAL_INCLUDE) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
+
+clean:
+	$(RM) *.o $(O_OBJ)
diff --git a/gcore/mdreader/makefile.vc b/gcore/mdreader/makefile.vc
new file mode 100644
index 0000000..a9c054d
--- /dev/null
+++ b/gcore/mdreader/makefile.vc
@@ -0,0 +1,12 @@
+OBJ	=	reader_digital_globe.obj reader_geo_eye.obj reader_orb_view.obj \
+                reader_pleiades.obj reader_rdk1.obj reader_landsat.obj
+
+!INCLUDE ..\..\nmake.opt
+
+EXTRAFLAGS =	-I..\..\port -I..\..\ogr -I..\
+
+default:	$(OBJ)
+    xcopy /D  /Y *.obj ..\
+
+clean:
+	-del *.obj *.res
diff --git a/gcore/mdreader/reader_digital_globe.cpp b/gcore/mdreader/reader_digital_globe.cpp
new file mode 100644
index 0000000..4d3cfab
--- /dev/null
+++ b/gcore/mdreader/reader_digital_globe.cpp
@@ -0,0 +1,280 @@
+/******************************************************************************
+ * $Id: reader_digital_globe.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from DigitalGlobe imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#include "reader_digital_globe.h"
+ 
+CPL_CVSID("$Id: reader_digital_globe.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderDigitalGlobe()
+ */
+GDALMDReaderDigitalGlobe::GDALMDReaderDigitalGlobe(const char *pszPath, 
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    m_osIMDSourceFilename = GDALFindAssociatedFile( pszPath, "IMD", 
+                                                         papszSiblingFiles, 0 );
+    m_osRPBSourceFilename = GDALFindAssociatedFile( pszPath, "RPB", 
+                                                         papszSiblingFiles, 0 );    
+    m_osXMLSourceFilename = GDALFindAssociatedFile( pszPath, "XML", 
+                                                         papszSiblingFiles, 0 );
+
+    if( m_osIMDSourceFilename.size() )
+        CPLDebug( "MDReaderDigitalGlobe", "IMD Filename: %s",
+                  m_osIMDSourceFilename.c_str() );
+    if( m_osRPBSourceFilename.size() )
+        CPLDebug( "MDReaderDigitalGlobe", "RPB Filename: %s",
+                  m_osRPBSourceFilename.c_str() );
+    if( m_osXMLSourceFilename.size() )
+        CPLDebug( "MDReaderDigitalGlobe", "XML Filename: %s",
+                  m_osXMLSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderDigitalGlobe()
+ */ 
+GDALMDReaderDigitalGlobe::~GDALMDReaderDigitalGlobe()
+{
+    
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderDigitalGlobe::HasRequiredFiles() const
+{
+    if (!m_osIMDSourceFilename.empty())
+        return true;
+    if (!m_osRPBSourceFilename.empty())
+        return true;
+
+    // check <isd>
+    if(!m_osXMLSourceFilename.empty() &&
+            GDALCheckFileHeader(m_osXMLSourceFilename, "<isd>"))
+        return true;
+
+    return false;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderDigitalGlobe::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+        
+    if (!m_osIMDSourceFilename.empty())
+    {
+        m_papszIMDMD = GDALLoadIMDFile( m_osIMDSourceFilename );
+    }
+
+    if(!m_osRPBSourceFilename.empty())
+    {
+        m_papszRPCMD = GDALLoadRPBFile( m_osRPBSourceFilename );
+    }
+
+    if((NULL == m_papszIMDMD || NULL == m_papszRPCMD) && !m_osXMLSourceFilename.empty())
+    { 
+        CPLXMLNode* psNode = CPLParseXMLFile(m_osXMLSourceFilename);
+       
+        if(psNode != NULL)
+        {
+            CPLXMLNode* psisdNode = psNode->psNext;
+            if(psisdNode != NULL)
+            {
+                if( m_papszIMDMD == NULL )
+                    m_papszIMDMD = LoadIMDXmlNode( CPLSearchXMLNode(psisdNode,
+                                                                        "IMD") );
+                if( m_papszRPCMD == NULL )
+                    m_papszRPCMD = LoadRPBXmlNode( CPLSearchXMLNode(psisdNode,
+                                                                        "RPB") );
+            }
+            CPLDestroyXMLNode(psNode);
+        }
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "DG");
+           
+    m_bIsMetadataLoad = true;      
+    
+    if(NULL == m_papszIMDMD)
+    {
+        return;
+    }   
+    //extract imagery metadata
+    const char* pszSatId = CSLFetchNameValue(m_papszIMDMD, "IMAGE.SATID");
+    if(NULL != pszSatId)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, 
+                                           MD_NAME_SATELLITE,
+                                           CPLStripQuotes(pszSatId));
+    }
+    else
+    {
+        pszSatId = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.SATID");
+        if(NULL != pszSatId)
+        {
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                               MD_NAME_SATELLITE,
+                                               CPLStripQuotes(pszSatId));
+        }
+    }
+    
+    const char* pszCloudCover = CSLFetchNameValue(m_papszIMDMD, 
+                                                  "IMAGE.CLOUDCOVER");
+    if(NULL != pszCloudCover)
+    {
+        double fCC = CPLAtofM(pszCloudCover);
+        if(fCC < 0)
+        {
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
+                                               MD_CLOUDCOVER_NA);
+        }
+        else
+        {
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                          MD_NAME_CLOUDCOVER, CPLSPrintf("%d", int(fCC * 100)));
+        }
+    }
+    else
+    {
+        pszCloudCover = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.cloudCover");
+        if(NULL != pszCloudCover)
+        {
+            double fCC = CPLAtofM(pszCloudCover);
+            if(fCC < 0)
+            {
+                m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
+                                                   MD_CLOUDCOVER_NA);
+            }
+            else
+            {
+                m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                              MD_NAME_CLOUDCOVER, CPLSPrintf("%d", int(fCC * 100)));
+            }
+        }
+    }
+    
+    const char* pszDateTime = CSLFetchNameValue(m_papszIMDMD,
+                                       "IMAGE.FIRSTLINETIME");
+    if(NULL != pszDateTime)
+    {
+        time_t timeStart = GetAcquisitionTimeFromString(pszDateTime);
+        char szMidDateTime[80];
+        strftime (szMidDateTime, 80, MD_DATETIMEFORMAT, localtime(&timeStart));
+
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_ACQDATETIME,
+                                           szMidDateTime);
+    }
+    else
+    {
+        pszDateTime = CSLFetchNameValue(m_papszIMDMD, "IMAGE_1.firstLineTime");
+        if(NULL != pszDateTime)
+        {
+            time_t timeStart = GetAcquisitionTimeFromString(pszDateTime);
+            char szMidDateTime[80];
+            strftime (szMidDateTime, 80, MD_DATETIMEFORMAT, localtime(&timeStart));
+
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                               MD_NAME_ACQDATETIME,
+                                               szMidDateTime);
+        }
+    }
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderDigitalGlobe::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osIMDSourceFilename.empty()) 
+        papszFileList = CSLAddString( papszFileList, m_osIMDSourceFilename );
+    if(!m_osRPBSourceFilename.empty()) 
+        papszFileList = CSLAddString( papszFileList, m_osRPBSourceFilename );
+    if(!m_osXMLSourceFilename.empty()) 
+        papszFileList = CSLAddString( papszFileList, m_osXMLSourceFilename );
+    
+    return papszFileList;
+}
+
+/**
+ * GDALLoadIMDXmlNode()
+ */
+char** GDALMDReaderDigitalGlobe::LoadIMDXmlNode(CPLXMLNode* psNode)
+{
+    if(NULL == psNode)
+        return NULL;    
+    char** papszList = NULL;
+    return ReadXMLToList(psNode->psChild, papszList);
+}
+
+/**
+ * GDALLoadRPBXmlNode()
+ */
+static const char *apszRPBMap[] = {
+    RPC_LINE_OFF,   "image.lineOffset",
+    RPC_SAMP_OFF,   "image.sampOffset",
+    RPC_LAT_OFF,    "image.latOffset",
+    RPC_LONG_OFF,   "image.longOffset",
+    RPC_HEIGHT_OFF, "image.heightOffset",
+    RPC_LINE_SCALE, "image.lineScale",
+    RPC_SAMP_SCALE, "image.sampScale",
+    RPC_LAT_SCALE,  "image.latScale",
+    RPC_LONG_SCALE, "image.longScale",
+    RPC_HEIGHT_SCALE,   "image.heightScale",
+    RPC_LINE_NUM_COEFF, "image.lineNumCoefList.lineNumCoef",
+    RPC_LINE_DEN_COEFF, "image.lineDenCoefList.lineDenCoef",
+    RPC_SAMP_NUM_COEFF, "image.sampNumCoefList.sampNumCoef",
+    RPC_SAMP_DEN_COEFF, "image.sampDenCoefList.sampDenCoef",
+    NULL,             NULL };
+
+char** GDALMDReaderDigitalGlobe::LoadRPBXmlNode(CPLXMLNode* psNode)
+{
+    if(NULL == psNode)
+        return NULL;
+    char** papszList = NULL;
+    papszList = ReadXMLToList(psNode->psChild, papszList);
+
+    if(NULL == papszList)
+        return NULL;
+    
+    char** papszRPB = NULL;
+    for( int i = 0; apszRPBMap[i] != NULL; i += 2 )
+    {
+        papszRPB = CSLAddNameValue(papszRPB, apszRPBMap[i],
+                               CSLFetchNameValue(papszList, apszRPBMap[i + 1]));
+    }
+
+    CSLDestroy(papszList);
+      
+    return papszRPB;
+}
diff --git a/gcore/mdreader/reader_digital_globe.h b/gcore/mdreader/reader_digital_globe.h
new file mode 100644
index 0000000..5fd0ae3
--- /dev/null
+++ b/gcore/mdreader/reader_digital_globe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * $Id: reader_digital_globe.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from DigitalGlobe imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#ifndef READER_DIGITAL_GLOBE_H_INCLUDED
+#define READER_DIGITAL_GLOBE_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for DigitalGlobe
+
+TIFF filename:        aaaaaaaaaa.tif
+Metadata filename:    aaaaaaaaaa.IMD
+RPC filename:         aaaaaaaaaa.RPB
+
+Common metadata (from metadata filename):
+    MDName_SatelliteId:            satId    
+    MDName_CloudCover:             cloudCover
+    MDName_AcquisitionDateTime:    earliestAcqTime, latestAcqTime
+
+OR
+Metadata and RPC filename:    aaaaaaaaaa.XML
+Common metadata (from metadata filename):
+    MDName_SatelliteId:            SATID    
+    MDName_CloudCover:             CLOUDCOVER
+    MDName_AcquisitionDateTime:    EARLIESTACQTIME, LATESTACQTIME
+
+*/
+
+class GDALMDReaderDigitalGlobe: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderDigitalGlobe(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderDigitalGlobe();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+    char** LoadRPBXmlNode(CPLXMLNode* psNode);
+    char** LoadIMDXmlNode(CPLXMLNode* psNode);
+protected:    
+    CPLString m_osXMLSourceFilename;
+    CPLString m_osIMDSourceFilename;
+    CPLString m_osRPBSourceFilename;
+};
+
+#endif //READER_DIGITAL_GLOBE_H_INCLUDED
diff --git a/gcore/mdreader/reader_geo_eye.cpp b/gcore/mdreader/reader_geo_eye.cpp
new file mode 100644
index 0000000..d364754
--- /dev/null
+++ b/gcore/mdreader/reader_geo_eye.cpp
@@ -0,0 +1,363 @@
+/******************************************************************************
+ * $Id: reader_geo_eye.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from GeoEye imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#include "reader_geo_eye.h"
+
+CPL_CVSID("$Id: reader_geo_eye.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderGeoEye()
+ */
+GDALMDReaderGeoEye::GDALMDReaderGeoEye(const char *pszPath, 
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    
+    const char* pszBaseName = CPLGetBasename(pszPath);
+    const char* pszDirName = CPLGetDirname(pszPath);
+
+    // get _metadata.txt file
+    
+    // split file name by _rgb_ or _pan_
+    char szMetadataName[512] = {0};
+    size_t i;
+    for(i = 0; i < CPLStrnlen(pszBaseName, 511); i++)
+    {
+        szMetadataName[i] = pszBaseName[i];
+        if(EQUALN(pszBaseName + i, "_rgb_", 5) || EQUALN(pszBaseName + i, "_pan_", 5))
+        {
+            break;
+        }
+    }
+    
+    // form metadata file name
+    CPLStrlcpy(szMetadataName + i, "_metadata.txt", 14);
+    const char* pszIMDSourceFilename = CPLFormFilename( pszDirName,
+                                                        szMetadataName, NULL );
+    if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+    {
+        m_osIMDSourceFilename = pszIMDSourceFilename;
+    }                                                     
+    else
+    {
+        CPLStrlcpy(szMetadataName + i, "_METADATA.TXT", 14);
+        pszIMDSourceFilename = CPLFormFilename( pszDirName, szMetadataName, NULL );
+        if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+        {
+            m_osIMDSourceFilename = pszIMDSourceFilename;
+        }
+    }
+
+    // get _rpc.txt file
+    
+    const char* pszRPBSourceFilename = CPLFormFilename( pszDirName,
+                                                        CPLSPrintf("%s_rpc",
+                                                        pszBaseName),
+                                                        "txt" );
+    if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+    {
+        m_osRPBSourceFilename = pszRPBSourceFilename;
+    }
+    else
+    {
+        pszRPBSourceFilename = CPLFormFilename( pszDirName, CPLSPrintf("%s_RPC",
+                                                pszBaseName), "TXT" );
+        if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+        {
+            m_osRPBSourceFilename = pszRPBSourceFilename;
+        }
+    }
+
+    if( m_osIMDSourceFilename.size() )
+        CPLDebug( "MDReaderGeoEye", "IMD Filename: %s",
+                  m_osIMDSourceFilename.c_str() );
+    if( m_osRPBSourceFilename.size() )
+        CPLDebug( "MDReaderGeoEye", "RPB Filename: %s",
+                  m_osRPBSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderGeoEye()
+ */ 
+GDALMDReaderGeoEye::~GDALMDReaderGeoEye()
+{
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderGeoEye::HasRequiredFiles() const
+{
+    if (!m_osIMDSourceFilename.empty())
+        return true;
+
+    if (!m_osRPBSourceFilename.empty())
+        return true;
+
+    return false;
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderGeoEye::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osIMDSourceFilename.empty())
+        papszFileList= CSLAddString( papszFileList, m_osIMDSourceFilename );
+    if(!m_osRPBSourceFilename.empty())
+        papszFileList = CSLAddString( papszFileList, m_osRPBSourceFilename );
+
+    return papszFileList;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderGeoEye::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;        
+
+    if (!m_osIMDSourceFilename.empty())
+    {
+        m_papszIMDMD = LoadIMDWktFile( );
+    }
+
+    if(!m_osRPBSourceFilename.empty())
+    {
+        m_papszRPCMD = GDALLoadRPCFile( m_osRPBSourceFilename );
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "GE");
+           
+    m_bIsMetadataLoad = true;      
+    
+    if(NULL == m_papszIMDMD)
+    {
+        return;
+    }   
+    
+    //extract imagery metadata
+    const char* pszSatId = CSLFetchNameValue(m_papszIMDMD,
+                                             "Source Image Metadata.Sensor");
+    if(NULL != pszSatId)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_SATELLITE,
+                                           CPLStripQuotes(pszSatId));
+    }
+        
+    const char* pszCloudCover = CSLFetchNameValue(m_papszIMDMD,
+                                   "Source Image Metadata.Percent Cloud Cover");
+    if(NULL != pszCloudCover)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_CLOUDCOVER, pszCloudCover);
+    }
+    
+    const char* pszDateTime = CSLFetchNameValue(m_papszIMDMD,
+                                 "Source Image Metadata.Acquisition Date/Time");
+                                         
+    if(NULL != pszDateTime)
+    {
+        char buffer[80];
+        time_t timeMid = GetAcquisitionTimeFromString(pszDateTime);
+
+        strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, 
+                                           MD_NAME_ACQDATETIME, buffer);
+    }  
+}
+
+/**
+ * GetAcqisitionTimeFromString()
+ */
+const time_t GDALMDReaderGeoEye::GetAcquisitionTimeFromString(
+        const char* pszDateTime)
+{
+    if(NULL == pszDateTime)
+        return 0;
+        
+    int iYear;
+    int iMonth;
+    int iDay;
+    int iHours;
+    int iMin;
+    int iSec = 0;
+
+// string exampe: Acquisition Date/Time: 2006-03-01 11:08 GMT
+
+    int r = sscanf ( pszDateTime, "%d-%d-%d %d:%d GMT", &iYear, &iMonth,
+                     &iDay, &iHours, &iMin);
+
+    if (r != 5)
+        return 0;
+    
+    struct tm tmDateTime;
+    tmDateTime.tm_sec = iSec;
+    tmDateTime.tm_min = iMin;
+    tmDateTime.tm_hour = iHours;
+    tmDateTime.tm_mday = iDay;
+    tmDateTime.tm_mon = iMonth - 1;
+    tmDateTime.tm_year = iYear - 1900;
+    tmDateTime.tm_isdst = -1;
+
+    return mktime(&tmDateTime);
+}
+
+/**
+ * LoadWKTIMDFile()
+ */
+char** GDALMDReaderGeoEye::LoadIMDWktFile() const
+{	
+    char** papszResultList = NULL;
+    char** papszLines = CSLLoad( m_osIMDSourceFilename );
+    bool bBeginSection = false;
+    CPLString osSection;
+    CPLString osKeyLevel1;
+    CPLString osKeyLevel2;
+    CPLString osKeyLevel3;
+    int nLevel = 0;
+    int nSpaceCount;
+
+    if( papszLines == NULL )
+        return NULL;
+
+    for( int i = 0; papszLines[i] != NULL; i++ )
+    {
+        // skip section (=== or ---) lines
+
+        if(EQUALN( papszLines[i], "===",3))
+        {
+            bBeginSection = true;
+            continue;
+        }
+
+        if(EQUALN( papszLines[i], "---",3) || CPLStrnlen(papszLines[i], 512) == 0)
+            continue;
+
+        // check the metadata level
+        nSpaceCount = 0;
+        for(int j = 0; j < 11; j++)
+        {
+            if(papszLines[i][j] != ' ')
+                break;
+            nSpaceCount++;
+        }
+
+        if(nSpaceCount % 3 != 0)
+            continue; // not a metadata item
+        nLevel = nSpaceCount / 3;
+
+        const char *pszValue;
+        char *pszKey = NULL;
+        pszValue = CPLParseNameValue(papszLines[i], &pszKey);
+
+        if(NULL != pszValue && CPLStrnlen(pszValue, 512) > 0)
+        {
+
+            CPLString osCurrentKey;
+            if(nLevel == 0)
+            {
+                osCurrentKey = CPLOPrintf("%s", pszKey);
+            }
+            else if(nLevel == 1)
+            {
+                osCurrentKey = osKeyLevel1 + "." +
+                        CPLOPrintf("%s", pszKey + nSpaceCount);
+            }
+            else if(nLevel == 2)
+            {
+                osCurrentKey = osKeyLevel1 + "." +
+                        osKeyLevel2 + "." + CPLOPrintf("%s", pszKey + nSpaceCount);
+            }
+            else if(nLevel == 3)
+            {
+                osCurrentKey = osKeyLevel1 + "." +
+                        osKeyLevel2 + "." + osKeyLevel3 + "." +
+                        CPLOPrintf("%s", pszKey + nSpaceCount);
+            }
+
+            if(!osSection.empty())
+            {
+                osCurrentKey = osSection + "." + osCurrentKey;
+            }
+
+            papszResultList = CSLAddNameValue(papszResultList, osCurrentKey, pszValue);
+        }
+
+        if(NULL != pszKey && CPLStrnlen(pszKey, 512) > 0)
+        {
+            if(bBeginSection)
+            {
+                osSection = CPLOPrintf("%s", pszKey);
+                bBeginSection = false;
+            }
+            else if(nLevel == 0)
+            {
+                osKeyLevel1 = CPLOPrintf("%s", pszKey);
+            }
+            else if(nLevel == 1)
+            {
+                osKeyLevel2 = CPLOPrintf("%s", pszKey + nSpaceCount);
+            }
+            else if(nLevel == 2)
+            {
+                osKeyLevel3 = CPLOPrintf("%s", pszKey + nSpaceCount);
+            }
+        }
+        else
+        {
+            if(bBeginSection)
+            {
+                osSection = CPLOPrintf("%s", papszLines[i]);
+                bBeginSection = false;
+            }
+            else if(nLevel == 0)
+            {
+                osKeyLevel1 = CPLOPrintf("%s", papszLines[i]);
+            }
+            else if(nLevel == 1)
+            {
+                osKeyLevel2 = CPLOPrintf("%s", papszLines[i] + nSpaceCount);
+            }
+            else if(nLevel == 2)
+            {
+                osKeyLevel3 = CPLOPrintf("%s", papszLines[i]+ nSpaceCount);
+            }
+        }
+
+        CPLFree( pszKey );
+    }
+
+    CSLDestroy( papszLines );
+
+    return papszResultList;
+}
diff --git a/gcore/mdreader/reader_geo_eye.h b/gcore/mdreader/reader_geo_eye.h
new file mode 100644
index 0000000..d2644f5
--- /dev/null
+++ b/gcore/mdreader/reader_geo_eye.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * $Id: reader_geo_eye.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from GeoEye imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015, NextGIS info at nextgis.ru
+ *
+ * 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.
+ ****************************************************************************/
+ 
+#ifndef READER_GEO_EYE_H_INCLUDED
+#define READER_GEO_EYE_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for Geo Eye
+
+TIFF filename:        aaaaaaaaaa.tif
+Metadata filename:    *_metadata*
+RPC filename:         aaaaaaaaaa_rpc.txt
+
+Common metadata (from metadata filename):
+    MDName_SatelliteId:            Sensor
+    MDName_CloudCover:             Percent Cloud Cover
+    MDName_AcquisitionDateTime:    Acquisition Date/Time
+
+*/
+
+class GDALMDReaderGeoEye: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderGeoEye(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderGeoEye();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+    virtual const time_t GetAcquisitionTimeFromString(const char* pszDateTime);
+    char **LoadRPCWktFile() const;
+    char **LoadIMDWktFile() const;
+protected:
+    CPLString m_osIMDSourceFilename;
+    CPLString m_osRPBSourceFilename;
+};
+
+#endif // READER_GEO_EYE_H_INCLUDED
diff --git a/gcore/mdreader/reader_landsat.cpp b/gcore/mdreader/reader_landsat.cpp
new file mode 100644
index 0000000..e2918f1
--- /dev/null
+++ b/gcore/mdreader/reader_landsat.cpp
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * $Id: reader_landsat.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Landsat imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "reader_landsat.h"
+
+CPL_CVSID("$Id: reader_landsat.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderLandsat()
+ */
+GDALMDReaderLandsat::GDALMDReaderLandsat(const char *pszPath,
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    const char* pszBaseName = CPLGetBasename(pszPath);
+    const char* pszDirName = CPLGetDirname(pszPath);
+
+    // split file name by _B or _b
+    char szMetadataName[512] = {0};
+    size_t i;
+    for(i = 0; i < CPLStrnlen(pszBaseName, 511); i++)
+    {
+        szMetadataName[i] = pszBaseName[i];
+        if(EQUALN(pszBaseName + i, "_B", 2) || EQUALN(pszBaseName + i, "_b", 2))
+        {
+            break;
+        }
+    }
+
+    // form metadata file name
+    CPLStrlcpy(szMetadataName + i, "_MTL.txt", 9);
+
+    //CPLDebug( "MDReaderLandsat", "Try IMD Filename: %s",
+    //        szMetadataName );
+
+    const char* pszIMDSourceFilename = CPLFormFilename( pszDirName,
+                                                        szMetadataName, NULL );
+    if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+    {
+        m_osIMDSourceFilename = pszIMDSourceFilename;
+    }
+    else
+    {
+        CPLStrlcpy(szMetadataName + i, "_MTL.TXT", 9);
+        pszIMDSourceFilename = CPLFormFilename( pszDirName, szMetadataName, NULL );
+        if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+        {
+            m_osIMDSourceFilename = pszIMDSourceFilename;
+        }
+    }
+
+    if( m_osIMDSourceFilename.size() )
+        CPLDebug( "MDReaderLandsat", "IMD Filename: %s",
+                  m_osIMDSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderLandsat()
+ */
+GDALMDReaderLandsat::~GDALMDReaderLandsat()
+{
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderLandsat::HasRequiredFiles() const
+{
+    if (!m_osIMDSourceFilename.empty())
+        return true;
+
+    return false;
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderLandsat::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osIMDSourceFilename.empty())
+        papszFileList= CSLAddString( papszFileList, m_osIMDSourceFilename );
+
+    return papszFileList;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderLandsat::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+
+    if (!m_osIMDSourceFilename.empty())
+    {
+        m_papszIMDMD = GDALLoadIMDFile( m_osIMDSourceFilename );
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "ODL");
+
+    m_bIsMetadataLoad = true;
+
+    // date/time
+    // DATE_ACQUIRED = 2013-04-07
+    // SCENE_CENTER_TIME = 15:47:03.0882620Z
+
+    // L1_METADATA_FILE.PRODUCT_METADATA.SPACECRAFT_ID
+    const char* pszSatId = CSLFetchNameValue(m_papszIMDMD,
+                            "L1_METADATA_FILE.PRODUCT_METADATA.SPACECRAFT_ID");
+    if(NULL != pszSatId)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
+                                           CPLStripQuotes(pszSatId));
+    }
+
+    // L1_METADATA_FILE.IMAGE_ATTRIBUTES.CLOUD_COVER
+    const char* pszCloudCover = CSLFetchNameValue(m_papszIMDMD,
+                            "L1_METADATA_FILE.IMAGE_ATTRIBUTES.CLOUD_COVER");
+    if(NULL != pszCloudCover)
+    {
+        double fCC = CPLAtofM(pszCloudCover);
+        if(fCC < 0)
+        {
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
+                                               MD_CLOUDCOVER_NA);
+        }
+        else
+        {
+            m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                          MD_NAME_CLOUDCOVER, CPLSPrintf("%d", int(fCC)));
+        }
+    }
+
+    // L1_METADATA_FILE.PRODUCT_METADATA.ACQUISITION_DATE
+    // L1_METADATA_FILE.PRODUCT_METADATA.SCENE_CENTER_SCAN_TIME
+
+    // L1_METADATA_FILE.PRODUCT_METADATA.DATE_ACQUIRED
+    // L1_METADATA_FILE.PRODUCT_METADATA.SCENE_CENTER_TIME
+
+    const char* pszDate = CSLFetchNameValue(m_papszIMDMD,
+                          "L1_METADATA_FILE.PRODUCT_METADATA.ACQUISITION_DATE");
+    if(NULL == pszDate)
+    {
+        pszDate = CSLFetchNameValue(m_papszIMDMD,
+                             "L1_METADATA_FILE.PRODUCT_METADATA.DATE_ACQUIRED");
+    }
+
+    if(NULL != pszDate)
+    {
+        const char* pszTime = CSLFetchNameValue(m_papszIMDMD,
+                    "L1_METADATA_FILE.PRODUCT_METADATA.SCENE_CENTER_SCAN_TIME");
+        if(NULL == pszTime)
+        {
+            pszTime = CSLFetchNameValue(m_papszIMDMD,
+                         "L1_METADATA_FILE.PRODUCT_METADATA.SCENE_CENTER_TIME");
+        }
+        if(NULL == pszTime)
+            pszTime = "00:00:00.000000Z";
+
+        char buffer[80];
+        time_t timeMid = GetAcquisitionTimeFromString(CPLSPrintf( "%sT%s",
+                                                     pszDate, pszTime));
+        strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_ACQDATETIME, buffer);
+    }
+
+}
diff --git a/gcore/mdreader/reader_landsat.h b/gcore/mdreader/reader_landsat.h
new file mode 100644
index 0000000..b59f761
--- /dev/null
+++ b/gcore/mdreader/reader_landsat.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * $Id: reader_landsat.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Landsat imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef READER_LANDSAT_H_INCLUDED
+#define READER_LANDSAT_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for Landsat
+
+TIFF filename:		xxxxxx_aaa.tif
+Metadata filename:	xxxxxx_MTL.txt
+RPC filename:           
+
+Common metadata (from metadata filename):
+        MDName_SatelliteId:         SPACECRAFT_ID
+        MDName_CloudCover:          CLOUD_COVER (Landsat 8)
+        MDName_AcquisitionDateTime: ACQUISITION_DATE,
+                                    SCENE_CENTER_SCAN_TIME (Landsat 5,7) or
+                                    DATE_ACQUIRED, SCENE_CENTER_TIME (Landsat 8);
+
+*/
+
+class GDALMDReaderLandsat: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderLandsat(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderLandsat();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+protected:
+    CPLString m_osIMDSourceFilename;
+};
+
+#endif // READER_LANDSAT_H_INCLUDED
diff --git a/gcore/mdreader/reader_orb_view.cpp b/gcore/mdreader/reader_orb_view.cpp
new file mode 100644
index 0000000..c39ead2
--- /dev/null
+++ b/gcore/mdreader/reader_orb_view.cpp
@@ -0,0 +1,161 @@
+/******************************************************************************
+ * $Id: reader_orb_view.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from OrbView imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "reader_orb_view.h"
+
+CPL_CVSID("$Id: reader_orb_view.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderOrbView()
+ */
+GDALMDReaderOrbView::GDALMDReaderOrbView(const char *pszPath,
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    m_osIMDSourceFilename = GDALFindAssociatedFile( pszPath, "PVL",
+                                                    papszSiblingFiles, 0 );
+
+    const char* pszBaseName = CPLGetBasename(pszPath);
+    const char* pszDirName = CPLGetDirname(pszPath);
+
+    const char* pszRPBSourceFilename = CPLFormFilename( pszDirName,
+                                                        CPLSPrintf("%s_rpc",
+                                                        pszBaseName),
+                                                        "txt" );
+    if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+    {
+        m_osRPBSourceFilename = pszRPBSourceFilename;
+    }
+    else
+    {
+        pszRPBSourceFilename = CPLFormFilename( pszDirName, CPLSPrintf("%s_RPC",
+                                                pszBaseName), "TXT" );
+        if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+        {
+            m_osRPBSourceFilename = pszRPBSourceFilename;
+        }
+    }
+
+    if( m_osIMDSourceFilename.size() )
+        CPLDebug( "MDReaderOrbView", "IMD Filename: %s",
+                  m_osIMDSourceFilename.c_str() );
+    if( m_osRPBSourceFilename.size() )
+        CPLDebug( "MDReaderOrbView", "RPB Filename: %s",
+                  m_osRPBSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderOrbView()
+ */
+GDALMDReaderOrbView::~GDALMDReaderOrbView()
+{
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderOrbView::HasRequiredFiles() const
+{
+    if (!m_osIMDSourceFilename.empty() && !m_osRPBSourceFilename.empty())
+        return true;
+
+    return false;
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderOrbView::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osIMDSourceFilename.empty())
+        papszFileList= CSLAddString( papszFileList, m_osIMDSourceFilename );
+    if(!m_osRPBSourceFilename.empty())
+        papszFileList = CSLAddString( papszFileList, m_osRPBSourceFilename );
+
+    return papszFileList;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderOrbView::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+
+    if (!m_osIMDSourceFilename.empty())
+    {
+        m_papszIMDMD = GDALLoadIMDFile( m_osIMDSourceFilename );
+    }
+
+    if(!m_osRPBSourceFilename.empty())
+    {
+        m_papszRPCMD = GDALLoadRPCFile( m_osRPBSourceFilename );
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "OV");
+
+    m_bIsMetadataLoad = true;
+
+    if(NULL == m_papszIMDMD)
+    {
+        return;
+    }
+
+    //extract imagery metadata
+    const char* pszSatId = CSLFetchNameValue(m_papszIMDMD,
+                                             "sensorInfo.satelliteName");
+    if(NULL != pszSatId)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_SATELLITE,
+                                           CPLStripQuotes(pszSatId));
+    }
+
+    const char* pszCloudCover = CSLFetchNameValue(m_papszIMDMD,
+                                   "productInfo.productCloudCoverPercentage");
+    if(NULL != pszCloudCover)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_CLOUDCOVER, pszCloudCover);
+    }
+
+    const char* pszDateTime = CSLFetchNameValue(m_papszIMDMD,
+                                 "inputImageInfo.firstLineAcquisitionDateTime");
+
+    if(NULL != pszDateTime)
+    {
+        char buffer[80];
+        time_t timeMid = GetAcquisitionTimeFromString(pszDateTime);
+        strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_ACQDATETIME, buffer);
+    }
+}
diff --git a/gcore/mdreader/reader_orb_view.h b/gcore/mdreader/reader_orb_view.h
new file mode 100644
index 0000000..9185078
--- /dev/null
+++ b/gcore/mdreader/reader_orb_view.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ * $Id: reader_orb_view.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from OrbView imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef READER_ORB_VIEW_H_INCLUDED
+#define READER_ORB_VIEW_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for OrbView
+
+TIFF filename:        aaaaaaaaa.tif
+Metadata filename:    aaaaaaaaa.pvl
+RPC filename:         aaaaaaaaa_rpc.txt
+
+Common metadata (from metadata filename):
+    MDName_SatelliteId:         sensorInfo.satelliteName
+    MDName_CloudCover:          productInfo.productCloudCoverPercentage
+    MDName_AcquisitionDateTime: inputImageInfo.firstLineAcquisitionDateTime
+*/
+class GDALMDReaderOrbView: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderOrbView(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderOrbView();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+protected:
+    CPLString m_osIMDSourceFilename;
+    CPLString m_osRPBSourceFilename;
+};
+
+#endif // READER_ORB_VIEW_H_INCLUDED
+
diff --git a/gcore/mdreader/reader_pleiades.cpp b/gcore/mdreader/reader_pleiades.cpp
new file mode 100644
index 0000000..75ad6e9
--- /dev/null
+++ b/gcore/mdreader/reader_pleiades.cpp
@@ -0,0 +1,326 @@
+/******************************************************************************
+ * $Id: reader_pleiades.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Pleiades imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "reader_pleiades.h"
+
+CPL_CVSID("$Id: reader_pleiades.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderPleiades()
+ */
+GDALMDReaderPleiades::GDALMDReaderPleiades(const char *pszPath,
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    const char* pszBaseName = CPLGetBasename(pszPath);
+
+    const char* pszDirName = CPLGetDirname(pszPath);
+
+    const char* pszIMDSourceFilename = CPLFormFilename( pszDirName,
+                                CPLSPrintf("DIM_%s", pszBaseName + 4), "XML" );
+    const char* pszRPBSourceFilename = CPLFormFilename( pszDirName,
+                                CPLSPrintf("RPC_%s", pszBaseName + 4), "XML" );
+
+    // find last underline
+    char sBaseName[512];
+    int nLastUnderline = 0;
+    for(size_t i = 4; i < CPLStrnlen(pszBaseName, 512); i++)
+    {
+        sBaseName[i - 4] = pszBaseName[i];
+        if(pszBaseName[i] == '_')
+            nLastUnderline = i - 4;
+    }
+
+    sBaseName[nLastUnderline] = 0;
+
+    if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+    {
+        m_osIMDSourceFilename = pszIMDSourceFilename;
+    }
+    else
+    {
+        pszIMDSourceFilename = CPLFormFilename( pszDirName, CPLSPrintf("DIM_%s",
+                                                            sBaseName), "XML" );
+        if (CPLCheckForFile((char*)pszIMDSourceFilename, papszSiblingFiles))
+        {
+            m_osIMDSourceFilename = pszIMDSourceFilename;
+        }
+    }
+
+    if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+    {
+        m_osRPBSourceFilename = pszRPBSourceFilename;
+    }
+    else
+    {
+        pszRPBSourceFilename = CPLFormFilename( pszDirName, CPLSPrintf("RPC_%s",
+                                                            sBaseName), "XML" );
+        if (CPLCheckForFile((char*)pszRPBSourceFilename, papszSiblingFiles))
+        {
+            m_osRPBSourceFilename = pszRPBSourceFilename;
+        }
+    }
+
+    if( m_osIMDSourceFilename.size() )
+        CPLDebug( "MDReaderPleiades", "IMD Filename: %s",
+                  m_osIMDSourceFilename.c_str() );
+    if( m_osRPBSourceFilename.size() )
+        CPLDebug( "MDReaderPleiades", "RPB Filename: %s",
+                  m_osRPBSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderPleiades()
+ */
+GDALMDReaderPleiades::~GDALMDReaderPleiades()
+{
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderPleiades::HasRequiredFiles() const
+{
+    if (!m_osIMDSourceFilename.empty())
+        return true;
+    if (!m_osRPBSourceFilename.empty())
+        return true;
+
+    return false;
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderPleiades::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osIMDSourceFilename.empty())
+        papszFileList= CSLAddString( papszFileList, m_osIMDSourceFilename );
+    if(!m_osRPBSourceFilename.empty())
+        papszFileList = CSLAddString( papszFileList, m_osRPBSourceFilename );
+
+    return papszFileList;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderPleiades::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+
+    if (!m_osIMDSourceFilename.empty())
+    {
+        CPLXMLNode* psNode = CPLParseXMLFile(m_osIMDSourceFilename);
+
+        if(psNode != NULL)
+        {
+            CPLXMLNode* psisdNode = CPLSearchXMLNode(psNode, "=Dimap_Document");
+
+            if(psisdNode != NULL)
+            {
+                m_papszIMDMD = ReadXMLToList(psisdNode->psChild, m_papszIMDMD);
+            }
+            CPLDestroyXMLNode(psNode);
+        }
+    }
+
+    if(!m_osRPBSourceFilename.empty())
+    {
+        m_papszRPCMD = LoadRPCXmlFile( );
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "DIMAP");
+
+    m_bIsMetadataLoad = true;
+
+    if(NULL == m_papszIMDMD)
+    {
+        return;
+    }
+
+    //extract imagery metadata
+    int nCounter = -1;
+    const char* pszSatId1 = CSLFetchNameValue(m_papszIMDMD,
+                  "Dataset_Sources.Source_Identification.Strip_Source.MISSION");
+    if(NULL == pszSatId1)
+    {
+        nCounter = 1;
+        for(int i = 0; i < 5; i++)
+        {
+            pszSatId1 = CSLFetchNameValue(m_papszIMDMD,
+            CPLSPrintf("Dataset_Sources.Source_Identification_%d.Strip_Source.MISSION",
+                       nCounter));
+            if(NULL != pszSatId1)
+                break;
+            nCounter++;
+        }
+    }
+
+
+    const char* pszSatId2;
+    if(nCounter == -1)
+        pszSatId2 = CSLFetchNameValue(m_papszIMDMD,
+            "Dataset_Sources.Source_Identification.Strip_Source.MISSION_INDEX");
+    else
+        pszSatId2 = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
+            "Dataset_Sources.Source_Identification_%d.Strip_Source.MISSION_INDEX",
+            nCounter));
+
+    if(NULL != pszSatId1 && NULL != pszSatId2)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                           MD_NAME_SATELLITE, CPLSPrintf( "%s %s",
+                           CPLStripQuotes(pszSatId1).c_str(),
+                           CPLStripQuotes(pszSatId2).c_str()));
+    }
+    else if(NULL != pszSatId1 && NULL == pszSatId2)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                MD_NAME_SATELLITE, CPLStripQuotes(pszSatId1));
+    }
+    else if(NULL == pszSatId1 && NULL != pszSatId2)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                MD_NAME_SATELLITE, CPLStripQuotes(pszSatId2));
+    }
+
+
+    const char* pszDate;
+    if(nCounter == -1)
+        pszDate = CSLFetchNameValue(m_papszIMDMD,
+             "Dataset_Sources.Source_Identification.Strip_Source.IMAGING_DATE");
+    else
+        pszDate = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
+             "Dataset_Sources.Source_Identification_%d.Strip_Source.IMAGING_DATE",
+             nCounter));
+
+    if(NULL != pszDate)
+    {
+        const char* pszTime;
+        if(nCounter == -1)
+            pszTime = CSLFetchNameValue(m_papszIMDMD,
+             "Dataset_Sources.Source_Identification.Strip_Source.IMAGING_TIME");
+        else
+            pszTime = CSLFetchNameValue(m_papszIMDMD, CPLSPrintf(
+             "Dataset_Sources.Source_Identification_%d.Strip_Source.IMAGING_TIME",
+             nCounter));
+
+        if(NULL == pszTime)
+            pszTime = "00:00:00.0Z";
+
+        char buffer[80];
+        time_t timeMid = GetAcquisitionTimeFromString(CPLSPrintf( "%sT%s",
+                                                     pszDate, pszTime));
+        strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_ACQDATETIME, buffer);
+    }
+
+    m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
+                                       MD_CLOUDCOVER_NA);
+}
+
+/**
+ * LoadRPCXmlFile()
+ */
+
+static const char *apszRPBMap[] = {
+    RPC_LINE_OFF,   "RFM_Validity.LINE_OFF",
+    RPC_SAMP_OFF,   "RFM_Validity.SAMP_OFF",
+    RPC_LAT_OFF,    "RFM_Validity.LAT_OFF",
+    RPC_LONG_OFF,   "RFM_Validity.LONG_OFF",
+    RPC_HEIGHT_OFF, "RFM_Validity.HEIGHT_OFF",
+    RPC_LINE_SCALE, "RFM_Validity.LINE_SCALE",
+    RPC_SAMP_SCALE, "RFM_Validity.SAMP_SCALE",
+    RPC_LAT_SCALE,  "RFM_Validity.LAT_SCALE",
+    RPC_LONG_SCALE, "RFM_Validity.LONG_SCALE",
+    RPC_HEIGHT_SCALE,   "RFM_Validity.HEIGHT_SCALE",
+    NULL,             NULL };
+
+static const char *apszRPCTXT20ValItems[] =
+{
+    RPC_LINE_NUM_COEFF,
+    RPC_LINE_DEN_COEFF,
+    RPC_SAMP_NUM_COEFF,
+    RPC_SAMP_DEN_COEFF,
+    NULL
+};
+
+char** GDALMDReaderPleiades::LoadRPCXmlFile()
+{
+    CPLXMLNode* pNode = CPLParseXMLFile(m_osRPBSourceFilename);
+
+    if(NULL == pNode)
+        return NULL;
+
+    // search Global_RFM
+    char** papszRawRPCList = NULL;
+    CPLXMLNode* pGRFMNode = CPLSearchXMLNode(pNode, "=Global_RFM");
+
+    if(pGRFMNode != NULL)
+    {
+        papszRawRPCList = ReadXMLToList(pGRFMNode->psChild, papszRawRPCList);
+    }
+
+    if( NULL == papszRawRPCList )
+    {
+        CPLDestroyXMLNode(pNode);
+        return NULL;        
+    }
+
+    // format list
+    char** papszRPB = NULL;
+    int i, j;
+    for( i = 0; apszRPBMap[i] != NULL; i += 2 )
+    {
+        papszRPB = CSLAddNameValue(papszRPB, apszRPBMap[i],
+                        CSLFetchNameValue(papszRawRPCList, apszRPBMap[i + 1]));
+    }
+
+    // merge coefficients
+    for( i = 0; apszRPCTXT20ValItems[i] != NULL; i++ )
+    {
+        CPLString value;
+        for( j = 1; j < 21; j++ )
+        {
+            const char* pszValue = CSLFetchNameValue(papszRawRPCList,
+                 CPLSPrintf("Inverse_Model.%s_%d", apszRPCTXT20ValItems[i], j)); // Direct_Model
+            if(NULL != pszValue)
+                value = value + " " + CPLString(pszValue);
+        }
+        papszRPB = CSLAddNameValue(papszRPB, apszRPCTXT20ValItems[i], value);
+    }
+
+    CSLDestroy(papszRawRPCList);
+    CPLDestroyXMLNode(pNode);
+    return papszRPB;
+}
diff --git a/gcore/mdreader/reader_pleiades.h b/gcore/mdreader/reader_pleiades.h
new file mode 100644
index 0000000..40a5ba5
--- /dev/null
+++ b/gcore/mdreader/reader_pleiades.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ * $Id: reader_pleiades.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Pleiades imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef READER_PLEIADES_H_INCLUDED
+#define READER_PLEIADES_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for Pleiades
+
+TIFF filename:        IMG_xxxxxx.tif
+Metadata filename:    DIM_xxxxxx.XML
+RPC filename:         RPC_xxxxxx.XML
+
+Common metadata (from metadata filename):
+    MDName_SatelliteId:            MISSION, MISSION_INDEX
+    MDName_AcquisitionDateTime:    IMAGING_DATE, IMAGING_TIME
+
+*/
+
+class GDALMDReaderPleiades: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderPleiades(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderPleiades();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+    char** LoadRPCXmlFile();
+protected:
+    CPLString m_osIMDSourceFilename;
+    CPLString m_osRPBSourceFilename;
+};
+
+#endif // READER_PLEIADES_H_INCLUDED
diff --git a/gcore/mdreader/reader_rdk1.cpp b/gcore/mdreader/reader_rdk1.cpp
new file mode 100644
index 0000000..19d7975
--- /dev/null
+++ b/gcore/mdreader/reader_rdk1.cpp
@@ -0,0 +1,210 @@
+/******************************************************************************
+ * $Id: reader_rdk1.cpp 29145 2015-05-04 10:00:40Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Resurs-DK1 imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "reader_rdk1.h"
+
+CPL_CVSID("$Id: reader_rdk1.cpp 29145 2015-05-04 10:00:40Z rouault $");
+
+/**
+ * GDALMDReaderResursDK1()
+ */
+GDALMDReaderResursDK1::GDALMDReaderResursDK1(const char *pszPath,
+        char **papszSiblingFiles) : GDALMDReaderBase(pszPath, papszSiblingFiles)
+{
+    m_osXMLSourceFilename = GDALFindAssociatedFile( pszPath, "XML",
+                                                         papszSiblingFiles, 0 );
+    if( m_osXMLSourceFilename.size() )
+        CPLDebug( "MDReaderResursDK1", "XML Filename: %s",
+                  m_osXMLSourceFilename.c_str() );
+}
+
+/**
+ * ~GDALMDReaderResursDK1()
+ */
+GDALMDReaderResursDK1::~GDALMDReaderResursDK1()
+{
+}
+
+/**
+ * HasRequiredFiles()
+ */
+const bool GDALMDReaderResursDK1::HasRequiredFiles() const
+{
+    // check <MSP_ROOT>
+    if (!m_osXMLSourceFilename.empty() &&
+            GDALCheckFileHeader(m_osXMLSourceFilename, "<MSP_ROOT>"))
+        return true;
+
+    return false;
+}
+
+/**
+ * GetMetadataFiles()
+ */
+char** GDALMDReaderResursDK1::GetMetadataFiles() const
+{
+    char **papszFileList = NULL;
+    if(!m_osXMLSourceFilename.empty())
+        papszFileList= CSLAddString( papszFileList, m_osXMLSourceFilename );
+
+    return papszFileList;
+}
+
+/**
+ * LoadMetadata()
+ */
+void GDALMDReaderResursDK1::LoadMetadata()
+{
+    if(m_bIsMetadataLoad)
+        return;
+
+    if (!m_osXMLSourceFilename.empty())
+    {
+        CPLXMLNode* psNode = CPLParseXMLFile(m_osXMLSourceFilename);
+
+        if(psNode != NULL)
+        {
+            CPLXMLNode* pMSPRootNode = CPLSearchXMLNode(psNode, "=MSP_ROOT");
+
+            if(pMSPRootNode != NULL)
+            {
+                m_papszIMDMD = ReadXMLToList(pMSPRootNode, m_papszIMDMD, "MSP_ROOT");
+            }
+            CPLDestroyXMLNode(psNode);
+        }
+    }
+
+    m_papszDEFAULTMD = CSLAddNameValue(m_papszDEFAULTMD, MD_NAME_MDTYPE, "MSP");
+
+    m_bIsMetadataLoad = true;
+
+    if(NULL == m_papszIMDMD)
+    {
+        return;
+    }
+
+    //extract imagery metadata
+    const char* pszSatId = CSLFetchNameValue(m_papszIMDMD, "MSP_ROOT.cCodeKA");
+    if(NULL != pszSatId)
+    {
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_SATELLITE,
+                                           CPLStripQuotes(pszSatId));
+    }
+
+
+    const char* pszDate = CSLFetchNameValue(m_papszIMDMD,
+                                            "MSP_ROOT.Normal.dSceneDate");
+
+    if(NULL != pszDate)
+    {
+        const char* pszTime = CSLFetchNameValue(m_papszIMDMD,
+                                         "MSP_ROOT.Normal.tSceneTime");
+        if(NULL == pszTime)
+            pszTime = "00:00:00.000000";
+
+        char buffer[80];
+        time_t timeMid = GetAcquisitionTimeFromString(CPLSPrintf( "%s %s",
+                                                     pszDate, pszTime));
+        strftime (buffer, 80, MD_DATETIMEFORMAT, localtime(&timeMid));
+        m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD,
+                                           MD_NAME_ACQDATETIME, buffer);
+    }
+
+    m_papszIMAGERYMD = CSLAddNameValue(m_papszIMAGERYMD, MD_NAME_CLOUDCOVER,
+                                       MD_CLOUDCOVER_NA);
+}
+
+/**
+ * GetAcqisitionTimeFromString()
+ */
+const time_t GDALMDReaderResursDK1::GetAcquisitionTimeFromString(
+        const char* pszDateTime)
+{
+    if(NULL == pszDateTime)
+        return 0;
+
+    int iYear;
+    int iMonth;
+    int iDay;
+    int iHours;
+    int iMin;
+    int iSec;
+
+// string exampe: <Normal>
+//                  tSceneTime = 10:21:36.000000
+//                  dSceneDate = 16/9/2008
+//                </Normal>
+
+    int r = sscanf ( pszDateTime, "%d/%d/%d %d:%d:%d.%*s",
+                     &iDay, &iMonth, &iYear, &iHours, &iMin, &iSec);
+
+    if (r != 6)
+        return 0;
+
+    struct tm tmDateTime;
+    tmDateTime.tm_sec = iSec;
+    tmDateTime.tm_min = iMin;
+    tmDateTime.tm_hour = iHours;
+    tmDateTime.tm_mday = iDay;
+    tmDateTime.tm_mon = iMonth - 1;
+    tmDateTime.tm_year = iYear - 1900;
+    tmDateTime.tm_isdst = -1;
+
+    return mktime(&tmDateTime) - 10800; // int UTC+3 MSK
+}
+
+char** GDALMDReaderResursDK1::AddXMLNameValueToList(char** papszList,
+                                               const char *pszName,
+                                               const char *pszValue)
+{
+    char** papszTokens = CSLTokenizeString2( pszValue, "\n",
+        CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES );
+
+    for(int i = 0; papszTokens[i] != NULL; i++ )
+    {
+
+        char** papszSubTokens = CSLTokenizeString2( papszTokens[i], "=",
+            CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES );
+        if(CSLCount(papszSubTokens) < 2)
+        {
+            CSLDestroy( papszSubTokens );
+            continue;
+        }
+
+        papszList = CSLAddNameValue(papszList, CPLSPrintf("%s.%s", pszName,
+                                              papszSubTokens[0]),
+                                              papszSubTokens[1]);
+        CSLDestroy( papszSubTokens );
+    }
+
+    CSLDestroy( papszTokens );
+
+    return papszList;
+}
diff --git a/gcore/mdreader/reader_rdk1.h b/gcore/mdreader/reader_rdk1.h
new file mode 100644
index 0000000..c096423
--- /dev/null
+++ b/gcore/mdreader/reader_rdk1.h
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * $Id: reader_rdk1.h 29138 2015-05-03 19:12:48Z rouault $
+ *
+ * Project:  GDAL Core
+ * Purpose:  Read metadata from Resurs-DK1 imagery.
+ * Author:   Alexander Lisovenko
+ * Author:   Dmitry Baryshnikov, polimax at mail.ru
+ *
+ ******************************************************************************
+ * Copyright (c) 2014-2015 NextGIS <info at nextgis.ru>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef READER_RDK1_H_INCLUDED
+#define READER_RDK1_H_INCLUDED
+
+#include "../gdal_mdreader.h"
+
+/**
+ at brief Metadata reader for RDK1
+
+TIFF filename:		aaaaaaaaaa.tif
+Metadata filename:	aaaaaaaaaa.xml
+RPC filename:
+
+Common metadata (from metadata filename):
+        MDName_SatelliteId:			cCodeKA
+        MDName_AcquisitionDateTime:	dSceneDate, tSceneTime
+*/
+
+class GDALMDReaderResursDK1: public GDALMDReaderBase
+{
+public:
+    GDALMDReaderResursDK1(const char *pszPath, char **papszSiblingFiles);
+    virtual ~GDALMDReaderResursDK1();
+    virtual const bool HasRequiredFiles() const;
+    virtual char** GetMetadataFiles() const;
+protected:
+    virtual void LoadMetadata();
+    virtual const time_t GetAcquisitionTimeFromString(const char* pszDateTime);
+    virtual char** AddXMLNameValueToList(char** papszList, const char *pszName,
+                                         const char *pszValue);
+protected:
+    CPLString m_osXMLSourceFilename;
+};
+
+#endif // READER_RDK1_H_INCLUDED
+
diff --git a/gcore/overview.cpp b/gcore/overview.cpp
index ad7d322..4dbda98 100644
--- a/gcore/overview.cpp
+++ b/gcore/overview.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: overview.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: overview.cpp 28142 2014-12-14 20:09:42Z goatbar $
  *
  * Project:  GDAL Core
  * Purpose:  Helper code to implement overview support in different drivers.
@@ -29,59 +29,29 @@
  ****************************************************************************/
 
 #include "gdal_priv.h"
+#include "gdalwarper.h"
 
-CPL_CVSID("$Id: overview.cpp 27739 2014-09-25 18:49:52Z goatbar $");
-
-typedef CPLErr (*GDALDownsampleFunction)
-                      ( int nSrcWidth, int nSrcHeight,
-                        GDALDataType eWrkDataType,
-                        void * pChunk,
-                        GByte * pabyChunkNodataMask,
-                        int nChunkXOff, int nChunkXSize,
-                        int nChunkYOff, int nChunkYSize,
-                        GDALRasterBand * poOverview,
-                        const char * pszResampling,
-                        int bHasNoData, float fNoDataValue,
-                        GDALColorTable* poColorTable,
-                        GDALDataType eSrcDataType);
+CPL_CVSID("$Id: overview.cpp 28142 2014-12-14 20:09:42Z goatbar $");
 
 /************************************************************************/
-/*                     GDALDownsampleChunk32R_Near()                    */
+/*                     GDALResampleChunk32R_Near()                      */
 /************************************************************************/
 
 template <class T>
 static CPLErr
-GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_NearT( double dfXRatioDstToSrc,
+                              double dfYRatioDstToSrc,
                               GDALDataType eWrkDataType,
                               T * pChunk,
-                              CPL_UNUSED GByte * pabyChunkNodataMask_unused,
                               int nChunkXOff, int nChunkXSize,
-                              int nChunkYOff, int nChunkYSize,
-                              GDALRasterBand * poOverview,
-                              CPL_UNUSED const char * pszResampling_unused,
-                              CPL_UNUSED int bHasNoData_unused, CPL_UNUSED float fNoDataValue_unused,
-                              CPL_UNUSED GDALColorTable* poColorTable_unused,
-                              CPL_UNUSED GDALDataType eSrcDataType)
+                              int nChunkYOff,
+                              int nDstXOff, int nDstXOff2,
+                              int nDstYOff, int nDstYOff2,
+                              GDALRasterBand * poOverview)
 
 {
     CPLErr eErr = CE_None;
 
-    int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
-
-    nOXSize = poOverview->GetXSize();
-    nOYSize = poOverview->GetYSize();
-
-/* -------------------------------------------------------------------- */
-/*      Figure out the column to start writing to, and the first column */
-/*      to not write to.                                                */
-/* -------------------------------------------------------------------- */
-    nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
-    nDstXOff2 = (int)
-        (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
-
-    if( nChunkXOff + nChunkXSize == nSrcWidth )
-        nDstXOff2 = nOXSize;
-
     int nDstXWidth = nDstXOff2 - nDstXOff;
 
 /* -------------------------------------------------------------------- */
@@ -94,25 +64,12 @@ GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
     if( pDstScanline == NULL || panSrcXOff == NULL )
     {
         CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunk32R: Out of memory for line buffer." );
+                  "GDALResampleChunk32R: Out of memory for line buffer." );
         VSIFree(pDstScanline);
         VSIFree(panSrcXOff);
         return CE_Failure;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int)
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
-
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
-
 /* ==================================================================== */
 /*      Precompute inner loop constants.                                */
 /* ==================================================================== */
@@ -122,7 +79,7 @@ GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
         int   nSrcXOff;
 
         nSrcXOff =
-            (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
+            (int) (0.5 + iDstPixel * dfXRatioDstToSrc);
         if ( nSrcXOff < nChunkXOff )
             nSrcXOff = nChunkXOff;
 
@@ -137,7 +94,7 @@ GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
         T *pSrcScanline;
         int   nSrcYOff;
 
-        nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
+        nSrcYOff = (int) (0.5 + iDstLine * dfYRatioDstToSrc);
         if ( nSrcYOff < nChunkYOff )
             nSrcYOff = nChunkYOff;
 
@@ -153,7 +110,7 @@ GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
 
         eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXWidth, 1,
                                      pDstScanline, nDstXWidth, 1, eWrkDataType,
-                                     0, 0 );
+                                     0, 0, NULL );
     }
 
     CPLFree( pDstScanline );
@@ -163,65 +120,102 @@ GDALDownsampleChunk32R_NearT( int nSrcWidth, int nSrcHeight,
 }
 
 static CPLErr
-GDALDownsampleChunk32R_Near( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_Near( double dfXRatioDstToSrc,
+                        double dfYRatioDstToSrc,
+                        CPL_UNUSED double dfSrcXDelta,
+                        CPL_UNUSED double dfSrcYDelta,
                         GDALDataType eWrkDataType,
                         void * pChunk,
-                        GByte * pabyChunkNodataMask_unused,
+                        CPL_UNUSED GByte * pabyChunkNodataMask_unused,
                         int nChunkXOff, int nChunkXSize,
-                        int nChunkYOff, int nChunkYSize,
+                        int nChunkYOff, CPL_UNUSED int nChunkYSize,
+                        int nDstXOff, int nDstXOff2,
+                        int nDstYOff, int nDstYOff2,
                         GDALRasterBand * poOverview,
-                        const char * pszResampling_unused,
-                        int bHasNoData_unused, float fNoDataValue_unused,
-                        GDALColorTable* poColorTable_unused,
-                        GDALDataType eSrcDataType)
+                        CPL_UNUSED const char * pszResampling_unused,
+                        CPL_UNUSED int bHasNoData_unused,
+                        CPL_UNUSED float fNoDataValue_unused,
+                        CPL_UNUSED GDALColorTable* poColorTable_unused,
+                        CPL_UNUSED GDALDataType eSrcDataType)
 {
     if (eWrkDataType == GDT_Byte)
-        return GDALDownsampleChunk32R_NearT(nSrcWidth, nSrcHeight,
+        return GDALResampleChunk32R_NearT(dfXRatioDstToSrc,
+                        dfYRatioDstToSrc,
                         eWrkDataType,
                         (GByte *) pChunk,
-                        pabyChunkNodataMask_unused,
                         nChunkXOff, nChunkXSize,
-                        nChunkYOff, nChunkYSize,
-                        poOverview,
-                        pszResampling_unused,
-                        bHasNoData_unused, fNoDataValue_unused,
-                        poColorTable_unused,
-                        eSrcDataType);
+                        nChunkYOff,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview);
+    else if (eWrkDataType == GDT_UInt16)
+        return GDALResampleChunk32R_NearT(dfXRatioDstToSrc,
+                        dfYRatioDstToSrc,
+                        eWrkDataType,
+                        (GInt16 *) pChunk,
+                        nChunkXOff, nChunkXSize,
+                        nChunkYOff,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview);
     else if (eWrkDataType == GDT_Float32)
-        return GDALDownsampleChunk32R_NearT(nSrcWidth, nSrcHeight,
+        return GDALResampleChunk32R_NearT(dfXRatioDstToSrc,
+                        dfYRatioDstToSrc,
                         eWrkDataType,
                         (float *) pChunk,
-                        pabyChunkNodataMask_unused,
                         nChunkXOff, nChunkXSize,
-                        nChunkYOff, nChunkYSize,
-                        poOverview,
-                        pszResampling_unused,
-                        bHasNoData_unused, fNoDataValue_unused,
-                        poColorTable_unused,
-                        eSrcDataType);
+                        nChunkYOff,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview);
 
     CPLAssert(0);
     return CE_Failure;
 }
 
 /************************************************************************/
-/*                    GDALDownsampleChunk32R_Average()                  */
+/*                          GDALFindBestEntry()                         */
+/************************************************************************/
+
+static int GDALFindBestEntry(int nEntryCount, const GDALColorEntry* aEntries,
+                             int nR, int nG, int nB)
+{
+    int i;
+    int nMinDist = 0;
+    int iBestEntry = 0;
+    for(i=0;i<nEntryCount;i++)
+    {
+        int nDist = (nR - aEntries[i].c1) *  (nR - aEntries[i].c1) +
+            (nG - aEntries[i].c2) *  (nG - aEntries[i].c2) +
+            (nB - aEntries[i].c3) *  (nB - aEntries[i].c3);
+        if (i == 0 || nDist < nMinDist)
+        {
+            nMinDist = nDist;
+            iBestEntry = i;
+        }
+    }
+    return iBestEntry;
+}
+
+/************************************************************************/
+/*                    GDALResampleChunk32R_Average()                    */
 /************************************************************************/
 
 template <class T, class Tsum>
 static CPLErr
-GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_AverageT( double dfXRatioDstToSrc,
+                                 double dfYRatioDstToSrc,
                                  GDALDataType eWrkDataType,
                                  T* pChunk,
                                  GByte * pabyChunkNodataMask,
                                  int nChunkXOff, int nChunkXSize,
                                  int nChunkYOff, int nChunkYSize,
+                                 int nDstXOff, int nDstXOff2,
+                                 int nDstYOff, int nDstYOff2,
                                  GDALRasterBand * poOverview,
                                  const char * pszResampling,
                                  int bHasNoData, float fNoDataValue,
-                                 GDALColorTable* poColorTable,
-                                 CPL_UNUSED GDALDataType eSrcDataType)
-
+                                 GDALColorTable* poColorTable)
 {
     CPLErr eErr = CE_None;
 
@@ -229,7 +223,7 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
     if (bBit2Grayscale)
         poColorTable = NULL;
 
-    int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
+    int nOXSize, nOYSize;
     T    *pDstScanline;
 
     T      tNoDataValue = (T)fNoDataValue;
@@ -239,18 +233,8 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
     nOXSize = poOverview->GetXSize();
     nOYSize = poOverview->GetYSize();
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the column to start writing to, and the first column */
-/*      to not write to.                                                */
-/* -------------------------------------------------------------------- */
-    nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
-    nDstXOff2 = (int)
-        (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
-
-    if( nChunkXOff + nChunkXSize == nSrcWidth )
-        nDstXOff2 = nOXSize;
-
-    int nChunkRightXOff = MIN(nSrcWidth, nChunkXOff + nChunkXSize);
+    int nChunkRightXOff = nChunkXOff + nChunkXSize;
+    int nChunkBottomYOff = nChunkYOff + nChunkYSize;
     int nDstXWidth = nDstXOff2 - nDstXOff;
 
 /* -------------------------------------------------------------------- */
@@ -263,26 +247,12 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
     if( pDstScanline == NULL || panSrcXOffShifted == NULL )
     {
         CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunk32R: Out of memory for line buffer." );
+                  "GDALResampleChunk32R: Out of memory for line buffer." );
         VSIFree(pDstScanline);
         VSIFree(panSrcXOffShifted);
         return CE_Failure;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int)
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
-
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
-
-
     int nEntryCount = 0;
     GDALColorEntry* aEntries = NULL;
     if (poColorTable)
@@ -306,14 +276,20 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
         int   nSrcXOff, nSrcXOff2;
 
         nSrcXOff =
-            (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
+            (int) (0.5 + iDstPixel * dfXRatioDstToSrc);
         if ( nSrcXOff < nChunkXOff )
             nSrcXOff = nChunkXOff;
         nSrcXOff2 = (int)
-            (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
+            (0.5 + (iDstPixel+1)* dfXRatioDstToSrc);
+        if( nSrcXOff2 == nSrcXOff )
+            nSrcXOff2 ++;
 
-        if( nSrcXOff2 > nChunkRightXOff || iDstPixel == nOXSize-1 )
+        if( nSrcXOff2 > nChunkRightXOff || (dfXRatioDstToSrc > 1 && iDstPixel == nOXSize-1) )
+        {
+            if( nSrcXOff == nChunkRightXOff && nChunkRightXOff - 1 >= nChunkXOff )
+                nSrcXOff = nChunkRightXOff - 1;
             nSrcXOff2 = nChunkRightXOff;
+        }
 
         panSrcXOffShifted[2 * (iDstPixel - nDstXOff)] = nSrcXOff - nChunkXOff;
         panSrcXOffShifted[2 * (iDstPixel - nDstXOff) + 1] = nSrcXOff2 - nChunkXOff;
@@ -328,17 +304,23 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
     {
         int   nSrcYOff, nSrcYOff2 = 0;
 
-        nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
+        nSrcYOff = (int) (0.5 + iDstLine * dfYRatioDstToSrc);
         if ( nSrcYOff < nChunkYOff )
             nSrcYOff = nChunkYOff;
 
         nSrcYOff2 =
-            (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
+            (int) (0.5 + (iDstLine+1) * dfYRatioDstToSrc);
+        if( nSrcYOff2 == nSrcYOff )
+            nSrcYOff2 ++;
 
-        if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
-            nSrcYOff2 = nSrcHeight;
-        if( nSrcYOff2 > nChunkYOff + nChunkYSize)
-            nSrcYOff2 = nChunkYOff + nChunkYSize;
+        if( nSrcYOff2 > nChunkBottomYOff || (dfYRatioDstToSrc > 1 && iDstLine == nOYSize-1) )
+        {
+            if( nSrcYOff == nChunkBottomYOff && nChunkBottomYOff - 1 >= nChunkYOff )
+                nSrcYOff = nChunkBottomYOff - 1;
+            nSrcYOff2 = nChunkBottomYOff;
+        }
+        if( nSrcYOff2 <= nSrcYOff )
+            CPLDebug("GDAL", "nSrcYOff=%d nSrcYOff2=%d", nSrcYOff, nSrcYOff2);
 
 /* -------------------------------------------------------------------- */
 /*      Loop over destination pixels                                    */
@@ -346,7 +328,7 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
         if (poColorTable == NULL)
         {
             if (bSrcXSpacingIsTwo && nSrcYOff2 == nSrcYOff + 2 &&
-                pabyChunkNodataMask == NULL && eWrkDataType == GDT_Byte)
+                pabyChunkNodataMask == NULL && (eWrkDataType == GDT_Byte || eWrkDataType == GDT_UInt16))
             {
                 /* Optimized case : no nodata, overview by a factor of 2 and regular x and y src spacing */
                 T* pSrcScanlineShifted = pChunk + panSrcXOffShifted[0] + (nSrcYOff - nChunkYOff) * nChunkXSize;
@@ -393,7 +375,7 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
 
                     if( nCount == 0 )
                         pDstScanline[iDstPixel] = tNoDataValue;
-                    else if (eWrkDataType == GDT_Byte)
+                    else if (eWrkDataType == GDT_Byte || eWrkDataType == GDT_UInt16)
                         pDstScanline[iDstPixel] = (T) ((dfTotal + nCount / 2) / nCount);
                     else
                         pDstScanline[iDstPixel] = (T) (dfTotal / nCount);
@@ -437,29 +419,18 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
                     pDstScanline[iDstPixel] = tNoDataValue;
                 else
                 {
-                    int nR = nTotalR / nCount, nG = nTotalG / nCount, nB = nTotalB / nCount;
-                    int i;
-                    Tsum dfMinDist = 0;
-                    int iBestEntry = 0;
-                    for(i=0;i<nEntryCount;i++)
-                    {
-                        Tsum dfDist = (nR - aEntries[i].c1) *  (nR - aEntries[i].c1) +
-                            (nG - aEntries[i].c2) *  (nG - aEntries[i].c2) +
-                            (nB - aEntries[i].c3) *  (nB - aEntries[i].c3);
-                        if (i == 0 || dfDist < dfMinDist)
-                        {
-                            dfMinDist = dfDist;
-                            iBestEntry = i;
-                        }
-                    }
-                    pDstScanline[iDstPixel] = (T)iBestEntry;
+                    int nR = (nTotalR + nCount / 2) / nCount,
+                        nG = (nTotalG + nCount / 2) / nCount,
+                        nB = (nTotalB + nCount / 2) / nCount;
+                    pDstScanline[iDstPixel] = (T)GDALFindBestEntry(
+                        nEntryCount, aEntries, nR, nG, nB);
                 }
             }
         }
 
         eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXWidth, 1,
                                      pDstScanline, nDstXWidth, 1, eWrkDataType,
-                                     0, 0 );
+                                     0, 0, NULL );
     }
 
     CPLFree( pDstScanline );
@@ -470,58 +441,81 @@ GDALDownsampleChunk32R_AverageT( int nSrcWidth, int nSrcHeight,
 }
 
 static CPLErr
-GDALDownsampleChunk32R_Average( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_Average( double dfXRatioDstToSrc, double dfYRatioDstToSrc,
+                        CPL_UNUSED double dfSrcXDelta,
+                        CPL_UNUSED double dfSrcYDelta,
                         GDALDataType eWrkDataType,
                         void * pChunk,
                         GByte * pabyChunkNodataMask,
-                        int nChunkXOff, int nChunkXSize,
+                        int nChunkXOff, int nChunkXSize, 
                         int nChunkYOff, int nChunkYSize,
+                        int nDstXOff, int nDstXOff2,
+                        int nDstYOff, int nDstYOff2,
                         GDALRasterBand * poOverview,
                         const char * pszResampling,
                         int bHasNoData, float fNoDataValue,
                         GDALColorTable* poColorTable,
-                        GDALDataType eSrcDataType)
+                        CPL_UNUSED GDALDataType eSrcDataType)
 {
     if (eWrkDataType == GDT_Byte)
-        return GDALDownsampleChunk32R_AverageT<GByte, int>(nSrcWidth, nSrcHeight,
+        return GDALResampleChunk32R_AverageT<GByte, int>(dfXRatioDstToSrc, dfYRatioDstToSrc,
                         eWrkDataType,
                         (GByte *) pChunk,
                         pabyChunkNodataMask,
                         nChunkXOff, nChunkXSize,
                         nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview,
+                        pszResampling,
+                        bHasNoData, fNoDataValue,
+                        poColorTable);
+    else if (eWrkDataType == GDT_UInt16 && dfXRatioDstToSrc * dfYRatioDstToSrc < 65536 )
+        return GDALResampleChunk32R_AverageT<GUInt16, GUInt32>(dfXRatioDstToSrc, dfYRatioDstToSrc,
+                        eWrkDataType,
+                        (GUInt16 *) pChunk,
+                        pabyChunkNodataMask,
+                        nChunkXOff, nChunkXSize,
+                        nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
                         poOverview,
                         pszResampling,
                         bHasNoData, fNoDataValue,
-                        poColorTable,
-                        eSrcDataType);
+                        poColorTable);
     else if (eWrkDataType == GDT_Float32)
-        return GDALDownsampleChunk32R_AverageT<float, double>(nSrcWidth, nSrcHeight,
+        return GDALResampleChunk32R_AverageT<float, double>(dfXRatioDstToSrc, dfYRatioDstToSrc,
                         eWrkDataType,
                         (float *) pChunk,
                         pabyChunkNodataMask,
                         nChunkXOff, nChunkXSize,
                         nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
                         poOverview,
                         pszResampling,
                         bHasNoData, fNoDataValue,
-                        poColorTable,
-                        eSrcDataType);
+                        poColorTable);
 
     CPLAssert(0);
     return CE_Failure;
 }
 
 /************************************************************************/
-/*                    GDALDownsampleChunk32R_Gauss()                    */
+/*                    GDALResampleChunk32R_Gauss()                      */
 /************************************************************************/
 
 static CPLErr
-GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_Gauss( double dfXRatioDstToSrc, double dfYRatioDstToSrc,
+                              CPL_UNUSED double dfSrcXDelta,
+                              CPL_UNUSED double dfSrcYDelta,
                               CPL_UNUSED GDALDataType eWrkDataType,
                               void * pChunk,
                               GByte * pabyChunkNodataMask,
                               int nChunkXOff, int nChunkXSize,
                               int nChunkYOff, int nChunkYSize,
+                              int nDstXOff, int nDstXOff2,
+                              int nDstYOff, int nDstYOff2,
                               GDALRasterBand * poOverview,
                               CPL_UNUSED const char * pszResampling,
                               int bHasNoData, float fNoDataValue,
@@ -536,7 +530,7 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
 /* -------------------------------------------------------------------- */
 /*      Create the filter kernel and allocate scanline buffer.          */
 /* -------------------------------------------------------------------- */
-    int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
+    int nOXSize, nOYSize;
     float    *pafDstScanline;
     int nGaussMatrixDim = 3;
     const int *panGaussMatrix;
@@ -562,7 +556,7 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
 
     nOXSize = poOverview->GetXSize();
     nOYSize = poOverview->GetYSize();
-    int nResYFactor = (int) (0.5 + (double)nSrcHeight/(double)nOYSize);
+    int nResYFactor = (int) (0.5 + dfYRatioDstToSrc);
 
     // matrix for gauss filter
     if(nResYFactor <= 2 )
@@ -581,40 +575,14 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
         nGaussMatrixDim=7;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the column to start writing to, and the first column */
-/*      to not write to.                                                */
-/* -------------------------------------------------------------------- */
-    nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
-    nDstXOff2 = (int)
-        (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
-
-    if( nChunkXOff + nChunkXSize == nSrcWidth )
-        nDstXOff2 = nOXSize;
-
-
     pafDstScanline = (float *) VSIMalloc((nDstXOff2 - nDstXOff) * sizeof(float));
     if( pafDstScanline == NULL )
     {
         CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunk32R: Out of memory for line buffer." );
+                  "GDALResampleChunk32R: Out of memory for line buffer." );
         return CE_Failure;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int)
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
-
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
-
-
     int nEntryCount = 0;
     GDALColorEntry* aEntries = NULL;
     if (poColorTable)
@@ -628,7 +596,8 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
         }
     }
 
-    int nChunkRightXOff = MIN(nSrcWidth, nChunkXOff + nChunkXSize);
+    int nChunkRightXOff = nChunkXOff + nChunkXSize;
+    int nChunkBottomYOff = nChunkYOff + nChunkYSize;
 
 /* ==================================================================== */
 /*      Loop over destination scanlines.                                */
@@ -639,8 +608,8 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
         GByte *pabySrcScanlineNodataMask;
         int   nSrcYOff, nSrcYOff2 = 0, iDstPixel;
 
-        nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
-        nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight) + 1;
+        nSrcYOff = (int) (0.5 + iDstLine * dfYRatioDstToSrc);
+        nSrcYOff2 = (int) (0.5 + (iDstLine+1) * dfYRatioDstToSrc) + 1;
 
         if( nSrcYOff < nChunkYOff )
         {
@@ -651,14 +620,16 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
         int iSizeY = nSrcYOff2 - nSrcYOff;
         nSrcYOff = nSrcYOff + iSizeY/2 - nGaussMatrixDim/2;
         nSrcYOff2 = nSrcYOff + nGaussMatrixDim;
+        int nYShiftGaussMatrix = 0;
         if(nSrcYOff < 0)
+        {
+            nYShiftGaussMatrix = -nSrcYOff;
             nSrcYOff = 0;
+        }
 
 
-        if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
-            nSrcYOff2 = nSrcHeight;
-        if( nSrcYOff2 > nChunkYOff + nChunkYSize)
-            nSrcYOff2 = nChunkYOff + nChunkYSize;
+        if( nSrcYOff2 > nChunkBottomYOff || (dfYRatioDstToSrc > 1 && iDstLine == nOYSize-1) )
+            nSrcYOff2 = nChunkBottomYOff;
 
         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nChunkXSize);
         if (pabyChunkNodataMask != NULL)
@@ -673,16 +644,20 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
         {
             int   nSrcXOff, nSrcXOff2;
 
-            nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
-            nSrcXOff2 = (int)(0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth) + 1;
+            nSrcXOff = (int) (0.5 + iDstPixel * dfXRatioDstToSrc);
+            nSrcXOff2 = (int)(0.5 + (iDstPixel+1) * dfXRatioDstToSrc) + 1;
 
             int iSizeX = nSrcXOff2 - nSrcXOff;
             nSrcXOff = nSrcXOff + iSizeX/2 - nGaussMatrixDim/2;
             nSrcXOff2 = nSrcXOff + nGaussMatrixDim;
+            int nXShiftGaussMatrix = 0;
             if(nSrcXOff < 0)
+            {
+                nXShiftGaussMatrix = -nSrcXOff;
                 nSrcXOff = 0;
+            }
 
-            if( nSrcXOff2 > nChunkRightXOff || iDstPixel == nOXSize-1 )
+            if( nSrcXOff2 > nChunkRightXOff || (dfXRatioDstToSrc > 1 && iDstPixel == nOXSize-1) )
                 nSrcXOff2 = nChunkRightXOff;
 
             if (poColorTable == NULL)
@@ -690,7 +665,8 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
                 double dfTotal = 0.0, val;
                 int  nCount = 0, iX, iY;
                 int  i = 0,j = 0;
-                const int *panLineWeight = panGaussMatrix;
+                const int *panLineWeight = panGaussMatrix +
+                    nYShiftGaussMatrix * nGaussMatrixDim + nXShiftGaussMatrix;
 
                 for( j=0, iY = nSrcYOff; iY < nSrcYOff2;
                         iY++, j++, panLineWeight += nGaussMatrixDim )
@@ -726,7 +702,8 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
                 int  nTotalR = 0, nTotalG = 0, nTotalB = 0;
                 int  nTotalWeight = 0, iX, iY;
                 int  i = 0,j = 0;
-                const int *panLineWeight = panGaussMatrix;
+                const int *panLineWeight = panGaussMatrix +
+                    nYShiftGaussMatrix * nGaussMatrixDim + nXShiftGaussMatrix;
 
                 for( j=0, iY = nSrcYOff; iY < nSrcYOff2;
                         iY++, j++, panLineWeight += nGaussMatrixDim )
@@ -759,23 +736,12 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
                         pafDstScanline[iDstPixel - nDstXOff] = 0.0;
                     else
                     {
-                        int nR = nTotalR / nTotalWeight, nG = nTotalG / nTotalWeight, nB = nTotalB / nTotalWeight;
-                        int i;
-                        double dfMinDist = 0;
-                        int iBestEntry = 0;
-                        for(i=0;i<nEntryCount;i++)
-                        {
-                            double dfDist = (nR - aEntries[i].c1) *  (nR - aEntries[i].c1) +
-                                (nG - aEntries[i].c2) *  (nG - aEntries[i].c2) +
-                                (nB - aEntries[i].c3) *  (nB - aEntries[i].c3);
-                            if (i == 0 || dfDist < dfMinDist)
-                            {
-                                dfMinDist = dfDist;
-                                iBestEntry = i;
-                            }
-                        }
+                        int nR = (nTotalR + nTotalWeight / 2) / nTotalWeight,
+                            nG = (nTotalG + nTotalWeight / 2) / nTotalWeight,
+                            nB = (nTotalB + nTotalWeight / 2) / nTotalWeight;
                         pafDstScanline[iDstPixel - nDstXOff] =
-                            (float) iBestEntry;
+                            (float) GDALFindBestEntry(
+                                    nEntryCount, aEntries, nR, nG, nB);
                     }
                 }
             }
@@ -784,7 +750,7 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
 
         eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXOff2 - nDstXOff, 1,
                                      pafDstScanline, nDstXOff2 - nDstXOff, 1, GDT_Float32,
-                                     0, 0 );
+                                     0, 0, NULL );
     }
 
     CPLFree( pafDstScanline );
@@ -794,21 +760,26 @@ GDALDownsampleChunk32R_Gauss( int nSrcWidth, int nSrcHeight,
 }
 
 /************************************************************************/
-/*                    GDALDownsampleChunk32R_Mode()                     */
+/*                    GDALResampleChunk32R_Mode()                       */
 /************************************************************************/
 
 static CPLErr
-GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
+GDALResampleChunk32R_Mode( double dfXRatioDstToSrc, double dfYRatioDstToSrc,
+                             CPL_UNUSED double dfSrcXDelta,
+                             CPL_UNUSED double dfSrcYDelta,
                              CPL_UNUSED GDALDataType eWrkDataType,
                              void * pChunk,
                              GByte * pabyChunkNodataMask,
                              int nChunkXOff, int nChunkXSize,
                              int nChunkYOff, int nChunkYSize,
+                             int nDstXOff, int nDstXOff2,
+                             int nDstYOff, int nDstYOff2,
                              GDALRasterBand * poOverview,
                              CPL_UNUSED const char * pszResampling,
                              int bHasNoData, float fNoDataValue,
                              GDALColorTable* poColorTable,
                              GDALDataType eSrcDataType)
+
 {
     CPLErr eErr = CE_None;
 
@@ -817,46 +788,20 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
 /* -------------------------------------------------------------------- */
 /*      Create the filter kernel and allocate scanline buffer.          */
 /* -------------------------------------------------------------------- */
-    int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
+    int nOXSize, nOYSize;
     float    *pafDstScanline;
 
     nOXSize = poOverview->GetXSize();
     nOYSize = poOverview->GetYSize();
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the column to start writing to, and the first column */
-/*      to not write to.                                                */
-/* -------------------------------------------------------------------- */
-    nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
-    nDstXOff2 = (int)
-        (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
-
-    if( nChunkXOff + nChunkXSize == nSrcWidth )
-        nDstXOff2 = nOXSize;
-
-
     pafDstScanline = (float *) VSIMalloc((nDstXOff2 - nDstXOff) * sizeof(float));
     if( pafDstScanline == NULL )
     {
         CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunk32R: Out of memory for line buffer." );
+                  "GDALResampleChunk32R: Out of memory for line buffer." );
         return CE_Failure;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int)
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
-
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
-
-
     int nEntryCount = 0;
     GDALColorEntry* aEntries = NULL;
     if (poColorTable)
@@ -874,7 +819,8 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
     float*   pafVals = NULL;
     int*     panSums = NULL;
 
-    int nChunkRightXOff = MIN(nSrcWidth, nChunkXOff + nChunkXSize);
+    int nChunkRightXOff = nChunkXOff + nChunkXSize;
+    int nChunkBottomYOff = nChunkYOff + nChunkYSize;
 
 /* ==================================================================== */
 /*      Loop over destination scanlines.                                */
@@ -885,17 +831,21 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
         GByte *pabySrcScanlineNodataMask;
         int   nSrcYOff, nSrcYOff2 = 0, iDstPixel;
 
-        nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
+        nSrcYOff = (int) (0.5 + iDstLine * dfYRatioDstToSrc);
         if ( nSrcYOff < nChunkYOff )
             nSrcYOff = nChunkYOff;
 
         nSrcYOff2 =
-            (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
+            (int) (0.5 + (iDstLine+1) * dfYRatioDstToSrc);
+        if( nSrcYOff2 == nSrcYOff )
+            nSrcYOff2 ++;
 
-        if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
-            nSrcYOff2 = nSrcHeight;
-        if( nSrcYOff2 > nChunkYOff + nChunkYSize)
-            nSrcYOff2 = nChunkYOff + nChunkYSize;
+        if( nSrcYOff2 > nChunkBottomYOff || (dfYRatioDstToSrc > 1 && iDstLine == nOYSize-1) )
+        {
+            if( nSrcYOff == nChunkBottomYOff && nChunkBottomYOff - 1 >= nChunkYOff )
+                nSrcYOff = nChunkBottomYOff - 1;
+            nSrcYOff2 = nChunkBottomYOff;
+        }
 
         pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nChunkXSize);
         if (pabyChunkNodataMask != NULL)
@@ -911,14 +861,20 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
             int   nSrcXOff, nSrcXOff2;
 
             nSrcXOff =
-                (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
+                (int) (0.5 + iDstPixel * dfXRatioDstToSrc);
             if ( nSrcXOff < nChunkXOff )
                 nSrcXOff = nChunkXOff;
             nSrcXOff2 = (int)
-                (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
+                (0.5 + (iDstPixel+1) * dfXRatioDstToSrc);
+            if( nSrcXOff2 == nSrcXOff )
+                nSrcXOff2 ++;
 
-            if( nSrcXOff2 > nChunkRightXOff || iDstPixel == nOXSize-1 )
+            if( nSrcXOff2 > nChunkRightXOff || (dfXRatioDstToSrc > 1 && iDstPixel == nOXSize-1) )
+            {
+                if( nSrcXOff == nChunkRightXOff && nChunkRightXOff - 1 >= nChunkXOff )
+                    nSrcXOff = nChunkRightXOff - 1;
                 nSrcXOff2 = nChunkRightXOff;
+            }
 
             if (eSrcDataType != GDT_Byte || nEntryCount > 256)
             {
@@ -1013,7 +969,7 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
 
         eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXOff2 - nDstXOff, 1,
                                      pafDstScanline, nDstXOff2 - nDstXOff, 1, GDT_Float32,
-                                     0, 0 );
+                                     0, 0, NULL );
     }
 
     CPLFree( pafDstScanline );
@@ -1025,239 +981,819 @@ GDALDownsampleChunk32R_Mode( int nSrcWidth, int nSrcHeight,
 }
 
 /************************************************************************/
-/*                    GDALDownsampleChunk32R_Cubic()                    */
+/*                  GDALResampleConvolutionHorizontal()                 */
 /************************************************************************/
 
-static CPLErr
-GDALDownsampleChunk32R_Cubic( int nSrcWidth, int nSrcHeight,
-                              CPL_UNUSED GDALDataType eWrkDataType,
-                              void * pChunk,
-                              CPL_UNUSED GByte * pabyChunkNodataMask,
-                              int nChunkXOff, int nChunkXSize,
-                              int nChunkYOff, int nChunkYSize,
-                              GDALRasterBand * poOverview,
-                              CPL_UNUSED const char * pszResampling,
-                              CPL_UNUSED int bHasNoData, CPL_UNUSED float fNoDataValue,
-                              GDALColorTable* poColorTable,
-                              CPL_UNUSED GDALDataType eSrcDataType)
+template<class T> static inline double GDALResampleConvolutionHorizontal(
+                            const T* pChunk, const double* padfWeights, int nSrcPixelCount)
 {
+    double dfVal1 = 0.0, dfVal2 = 0.0;
+    int i = 0;
+    for(;i+3<nSrcPixelCount;i+=4)
+    {
+        dfVal1 += pChunk[i] * padfWeights[i];
+        dfVal1 += pChunk[i+1] * padfWeights[i+1];
+        dfVal2 += pChunk[i+2] * padfWeights[i+2];
+        dfVal2 += pChunk[i+3] * padfWeights[i+3];
+    }
+    for(;i<nSrcPixelCount;i++)
+    {
+        dfVal1 += pChunk[i] * padfWeights[i];
+    }
+    return dfVal1 + dfVal2;
+}
 
-    CPLErr eErr = CE_None;
+template<class T> static inline void GDALResampleConvolutionHorizontalWithMask(
+                            const T* pChunk, const GByte* pabyMask,
+                            const double* padfWeights, int nSrcPixelCount,
+                            double& dfVal, double &dfWeightSum)
+{
+    dfVal = 0;
+    dfWeightSum = 0;
+    int i = 0;
+    for(;i+3<nSrcPixelCount;i+=4)
+    {
+        double dfWeight0 = padfWeights[i] * pabyMask[i];
+        double dfWeight1 = padfWeights[i+1] * pabyMask[i+1];
+        double dfWeight2 = padfWeights[i+2] * pabyMask[i+2];
+        double dfWeight3 = padfWeights[i+3] * pabyMask[i+3];
+        dfVal += pChunk[i] * dfWeight0;
+        dfVal += pChunk[i+1] * dfWeight1;
+        dfVal += pChunk[i+2] * dfWeight2;
+        dfVal += pChunk[i+3] * dfWeight3;
+        dfWeightSum += dfWeight0 + dfWeight1 + dfWeight2 + dfWeight3;
+    }
+    for(;i<nSrcPixelCount;i++)
+    {
+        double dfWeight = padfWeights[i] * pabyMask[i];
+        dfVal += pChunk[i] * dfWeight;
+        dfWeightSum += dfWeight;
+    }
+}
 
-    float * pafChunk = (float*) pChunk;
+template<class T> static inline void GDALResampleConvolutionHorizontal_3rows(
+                            const T* pChunkRow1, const T* pChunkRow2, const T* pChunkRow3,
+                            const double* padfWeights, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    double dfVal1 = 0.0, dfVal2 = 0.0,
+           dfVal3 = 0.0, dfVal4 = 0.0,
+           dfVal5 = 0.0, dfVal6 = 0.0;
+    int i = 0;
+    for(;i+3<nSrcPixelCount;i+=4)
+    {
+        dfVal1 += pChunkRow1[i] * padfWeights[i];
+        dfVal1 += pChunkRow1[i+1] * padfWeights[i+1];
+        dfVal2 += pChunkRow1[i+2] * padfWeights[i+2];
+        dfVal2 += pChunkRow1[i+3] * padfWeights[i+3];
+        dfVal3 += pChunkRow2[i] * padfWeights[i];
+        dfVal3 += pChunkRow2[i+1] * padfWeights[i+1];
+        dfVal4 += pChunkRow2[i+2] * padfWeights[i+2];
+        dfVal4 += pChunkRow2[i+3] * padfWeights[i+3];
+        dfVal5 += pChunkRow3[i] * padfWeights[i];
+        dfVal5 += pChunkRow3[i+1] * padfWeights[i+1];
+        dfVal6 += pChunkRow3[i+2] * padfWeights[i+2];
+        dfVal6 += pChunkRow3[i+3] * padfWeights[i+3];
+    }
+    for(;i<nSrcPixelCount;i++)
+    {
+        dfVal1 += pChunkRow1[i] * padfWeights[i];
+        dfVal3 += pChunkRow2[i] * padfWeights[i];
+        dfVal5 += pChunkRow3[i] * padfWeights[i];
+    }
+    dfRes1 = dfVal1 + dfVal2;
+    dfRes2 = dfVal3 + dfVal4;
+    dfRes3 = dfVal5 + dfVal6;
+}
 
-/* -------------------------------------------------------------------- */
-/*      Create the filter kernel and allocate scanline buffer.          */
-/* -------------------------------------------------------------------- */
-    int      nDstXOff, nDstXOff2, nDstYOff, nDstYOff2, nOXSize, nOYSize;
-    float    *pafDstScanline;
+template<class T> static inline void GDALResampleConvolutionHorizontalPixelCountLess8_3rows(
+                            const T* pChunkRow1, const T* pChunkRow2, const T* pChunkRow3,
+                            const double* padfWeights, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    GDALResampleConvolutionHorizontal_3rows(
+                            pChunkRow1, pChunkRow2, pChunkRow3,
+                            padfWeights, nSrcPixelCount,
+                            dfRes1, dfRes2, dfRes3);
+}
 
-    nOXSize = poOverview->GetXSize();
-    nOYSize = poOverview->GetYSize();
+/************************************************************************/
+/*                  GDALResampleConvolutionVertical()                   */
+/************************************************************************/
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the column to start writing to, and the first column */
-/*      to not write to.                                                */
-/* -------------------------------------------------------------------- */
-    nDstXOff = (int) (0.5 + (nChunkXOff/(double)nSrcWidth) * nOXSize);
-    nDstXOff2 = (int)
-        (0.5 + ((nChunkXOff+nChunkXSize)/(double)nSrcWidth) * nOXSize);
+template<class T> static inline double GDALResampleConvolutionVertical(
+                 const T* pChunk, int nStride, const double* padfWeights, int nSrcLineCount)
+{
+    double dfVal1 = 0.0, dfVal2 = 0.0;
+    int i = 0, j = 0;
+    for(;i+3<nSrcLineCount;i+=4, j+=4*nStride)
+    {
+        dfVal1 += pChunk[j] * padfWeights[i];
+        dfVal1 += pChunk[j + nStride] * padfWeights[i+1];
+        dfVal2 += pChunk[j + 2 * nStride] * padfWeights[i+2];
+        dfVal2 += pChunk[j + 3 * nStride] * padfWeights[i+3];
+    }
+    for(;i<nSrcLineCount;i++,j+=nStride)
+    {
+        dfVal1 += pChunk[j] * padfWeights[i];
+    }
+    return dfVal1 + dfVal2;
+}
 
-    if( nChunkXOff + nChunkXSize == nSrcWidth )
-        nDstXOff2 = nOXSize;
+template<class T> static inline void GDALResampleConvolutionVertical_2cols(
+                 const T* pChunk, int nStride, const double* padfWeights, int nSrcLineCount,
+                 double& dfRes1, double& dfRes2)
+{
+    double dfVal1 = 0.0, dfVal2 = 0.0,
+           dfVal3 = 0.0, dfVal4 = 0.0;
+    int i = 0, j = 0;
+    for(;i+3<nSrcLineCount;i+=4, j+=4*nStride)
+    {
+        dfVal1 += pChunk[j] * padfWeights[i];
+        dfVal3 += pChunk[j+1] * padfWeights[i];
+        dfVal1 += pChunk[j + nStride] * padfWeights[i+1];
+        dfVal3 += pChunk[j+1 + nStride] * padfWeights[i+1];
+        dfVal2 += pChunk[j + 2 * nStride] * padfWeights[i+2];
+        dfVal4 += pChunk[j+1 + 2 * nStride] * padfWeights[i+2];
+        dfVal2 += pChunk[j + 3 * nStride] * padfWeights[i+3];
+        dfVal4 += pChunk[j+1 + 3 * nStride] * padfWeights[i+3];
+    }
+    for(;i<nSrcLineCount;i++,j+=nStride)
+    {
+        dfVal1 += pChunk[j] * padfWeights[i];
+        dfVal3 += pChunk[j+1] * padfWeights[i];
+    }
+    dfRes1 = dfVal1 + dfVal2;
+    dfRes2 = dfVal3 + dfVal4;
+}
+/* We restrict to 64bit processors because they are guaranteed to have SSE2 */
+/* Could possibly be used too on 32bit, but we would need to check at runtime */
+#if defined(__x86_64) || defined(_M_X64)
+#define USE_SSE2
+#endif
 
+#ifdef USE_SSE2
+#include <gdalsse_priv.h>
 
-    pafDstScanline = (float *) VSIMalloc((nDstXOff2 - nDstXOff) * sizeof(float));
-    if( pafDstScanline == NULL )
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontalSSE2<T>                */
+/************************************************************************/
+
+template<class T> static inline double GDALResampleConvolutionHorizontalSSE2(
+                         const T* pChunk, const double* padfWeightsAligned, int nSrcPixelCount)
+{
+    XMMReg4Double v_acc1 = XMMReg4Double::Zero();
+    XMMReg4Double v_acc2 = XMMReg4Double::Zero();
+    int i = 0;
+    for(;i+7<nSrcPixelCount;i+=8)
     {
-        CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunk32R: Out of memory for line buffer." );
-        return CE_Failure;
+        // Retrieve the pixel & accumulate
+        XMMReg4Double v_pixels1 = XMMReg4Double::Load4Val(pChunk+i);
+        XMMReg4Double v_pixels2 = XMMReg4Double::Load4Val(pChunk+i+4);
+        XMMReg4Double v_weight1 = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i);
+        XMMReg4Double v_weight2 = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i+4);
+
+        v_acc1 += v_pixels1 * v_weight1;
+        v_acc2 += v_pixels2 * v_weight2;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int)
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
+    v_acc1 += v_acc2;
+    v_acc1.AddLowAndHigh();
+
+    double dfVal = (double)v_acc1.GetLow();
+    for(;i<nSrcPixelCount;i++)
+    {
+        dfVal += pChunk[i] * padfWeightsAligned[i];
+    }
+    return dfVal;
+}
 
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontal<GByte>                */
+/************************************************************************/
 
+template<> inline double GDALResampleConvolutionHorizontal<GByte>(
+                         const GByte* pChunk, const double* padfWeightsAligned, int nSrcPixelCount)
+{
+    return GDALResampleConvolutionHorizontalSSE2(pChunk, padfWeightsAligned, nSrcPixelCount);
+}
 
-    int nEntryCount = 0;
-    GDALColorEntry* aEntries = NULL;
-    if (poColorTable)
+template<> inline double GDALResampleConvolutionHorizontal<GUInt16>(
+                         const GUInt16* pChunk, const double* padfWeightsAligned, int nSrcPixelCount)
+{
+    return GDALResampleConvolutionHorizontalSSE2(pChunk, padfWeightsAligned, nSrcPixelCount);
+}
+
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontalWithMaskSSE2<T>        */
+/************************************************************************/
+
+template<class T> static inline void GDALResampleConvolutionHorizontalWithMaskSSE2(
+                            const T* pChunk, const GByte* pabyMask,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfVal, double &dfWeightSum)
+{
+    int i = 0;
+    XMMReg4Double v_acc = XMMReg4Double::Zero(),
+                  v_acc_weight = XMMReg4Double::Zero();
+    for(;i+3<nSrcPixelCount;i+=4)
     {
-        int i;
-        nEntryCount = poColorTable->GetColorEntryCount();
-        aEntries = (GDALColorEntry* )CPLMalloc(sizeof(GDALColorEntry) * nEntryCount);
-        for(i=0;i<nEntryCount;i++)
-        {
-            poColorTable->GetColorEntryAsRGB(i, &aEntries[i]);
-        }
+        XMMReg4Double v_pixels = XMMReg4Double::Load4Val(pChunk+i);
+        XMMReg4Double v_mask = XMMReg4Double::Load4Val(pabyMask+i);
+        XMMReg4Double v_weight = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i);
+        v_weight *= v_mask;
+        v_acc += v_pixels * v_weight;
+        v_acc_weight += v_weight;
     }
+    v_acc.AddLowAndHigh();
+    v_acc_weight.AddLowAndHigh();
+    dfVal = (double)v_acc.GetLow();
+    dfWeightSum = (double)v_acc_weight.GetLow();
+    for(;i<nSrcPixelCount;i++)
+    {
+        double dfWeight = padfWeightsAligned[i] * pabyMask[i];
+        dfVal += pChunk[i] * dfWeight;
+        dfWeightSum += dfWeight;
+    }
+}
 
-    int nChunkRightXOff = MIN(nSrcWidth, nChunkXOff + nChunkXSize);
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontalWithMask<GByte>        */
+/************************************************************************/
 
-/* ==================================================================== */
-/*      Loop over destination scanlines.                                */
-/* ==================================================================== */
-    for( int iDstLine = nDstYOff; iDstLine < nDstYOff2 && eErr == CE_None; iDstLine++ )
+template<> inline void GDALResampleConvolutionHorizontalWithMask<GByte>(
+                            const GByte* pChunk, const GByte* pabyMask,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfVal, double &dfWeightSum)
+{
+    GDALResampleConvolutionHorizontalWithMaskSSE2(pChunk, pabyMask,
+                                                  padfWeightsAligned,
+                                                  nSrcPixelCount,
+                                                  dfVal, dfWeightSum);
+}
+
+template<> inline void GDALResampleConvolutionHorizontalWithMask<GUInt16>(
+                            const GUInt16* pChunk, const GByte* pabyMask,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfVal, double &dfWeightSum)
+{
+    GDALResampleConvolutionHorizontalWithMaskSSE2(pChunk, pabyMask,
+                                                  padfWeightsAligned,
+                                                  nSrcPixelCount,
+                                                  dfVal, dfWeightSum);
+}
+
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontal_3rows_SSE2<T>         */
+/************************************************************************/
+
+template<class T> static inline void GDALResampleConvolutionHorizontal_3rows_SSE2(
+                            const T* pChunkRow1, const T* pChunkRow2, const T* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    XMMReg4Double v_acc1 = XMMReg4Double::Zero(),
+                  v_acc2 = XMMReg4Double::Zero(),
+                  v_acc3 = XMMReg4Double::Zero();
+    int i = 0;
+    for(;i+7<nSrcPixelCount;i+=8)
     {
-        float *pafSrcScanline;
-        // GByte *pabySrcScanlineNodataMask;
-        int   nSrcYOff, nSrcYOff2 = 0, iDstPixel;
+        // Retrieve the pixel & accumulate
+        XMMReg4Double v_pixels1 = XMMReg4Double::Load4Val(pChunkRow1+i);
+        XMMReg4Double v_pixels2 = XMMReg4Double::Load4Val(pChunkRow1+i+4);
+        XMMReg4Double v_weight1 = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i);
+        XMMReg4Double v_weight2 = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i+4);
 
-        nSrcYOff = (int) floor(((iDstLine+0.5)/(double)nOYSize) * nSrcHeight - 0.5)-1;
-        nSrcYOff2 = nSrcYOff + 4;
-        if(nSrcYOff < 0)
-            nSrcYOff = 0;
-        if(nSrcYOff < nChunkYOff)
-            nSrcYOff = nChunkYOff;
+        v_acc1 += v_pixels1 * v_weight1;
+        v_acc1 += v_pixels2 * v_weight2;
 
-        if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
-            nSrcYOff2 = nSrcHeight;
-        if( nSrcYOff2 > nChunkYOff + nChunkYSize)
-            nSrcYOff2 = nChunkYOff + nChunkYSize;
+        v_pixels1 = XMMReg4Double::Load4Val(pChunkRow2+i);
+        v_pixels2 = XMMReg4Double::Load4Val(pChunkRow2+i+4);
+        v_acc2 += v_pixels1 * v_weight1;
+        v_acc2 += v_pixels2 * v_weight2;
 
-        pafSrcScanline = pafChunk + ((nSrcYOff-nChunkYOff) * nChunkXSize);
-#if 0
-        // pabySrcScanlineNodataMask is unused.
-        if (pabyChunkNodataMask != NULL)
-            pabySrcScanlineNodataMask = pabyChunkNodataMask + ((nSrcYOff-nChunkYOff) * nChunkXSize);
-        else
-            pabySrcScanlineNodataMask = NULL;
-#endif
+        v_pixels1 = XMMReg4Double::Load4Val(pChunkRow3+i);
+        v_pixels2 = XMMReg4Double::Load4Val(pChunkRow3+i+4);
+        v_acc3 += v_pixels1 * v_weight1;
+        v_acc3 += v_pixels2 * v_weight2;
+
+    }
+
+    v_acc1.AddLowAndHigh();
+    v_acc2.AddLowAndHigh();
+    v_acc3.AddLowAndHigh();
+
+    dfRes1 = (double)v_acc1.GetLow();
+    dfRes2 = (double)v_acc2.GetLow();
+    dfRes3 = (double)v_acc3.GetLow();
+    for(;i<nSrcPixelCount;i++)
+    {
+        dfRes1 += pChunkRow1[i] * padfWeightsAligned[i];
+        dfRes2 += pChunkRow2[i] * padfWeightsAligned[i];
+        dfRes3 += pChunkRow3[i] * padfWeightsAligned[i];
+    }
+}
+
+/************************************************************************/
+/*              GDALResampleConvolutionHorizontal_3rows<GByte>          */
+/************************************************************************/
+
+template<> inline void GDALResampleConvolutionHorizontal_3rows<GByte>(
+                            const GByte* pChunkRow1, const GByte* pChunkRow2, const GByte* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    GDALResampleConvolutionHorizontal_3rows_SSE2(pChunkRow1, pChunkRow2, pChunkRow3,
+                                                 padfWeightsAligned, nSrcPixelCount,
+                                                 dfRes1, dfRes2, dfRes3);
+}
+
+template<> inline void GDALResampleConvolutionHorizontal_3rows<GUInt16>(
+                            const GUInt16* pChunkRow1, const GUInt16* pChunkRow2, const GUInt16* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    GDALResampleConvolutionHorizontal_3rows_SSE2(pChunkRow1, pChunkRow2, pChunkRow3,
+                                                 padfWeightsAligned, nSrcPixelCount,
+                                                 dfRes1, dfRes2, dfRes3);
+}
+
+/************************************************************************/
+/*     GDALResampleConvolutionHorizontalPixelCountLess8_3rows_SSE2<T>   */
+/************************************************************************/
+
+template<class T> static inline void GDALResampleConvolutionHorizontalPixelCountLess8_3rows_SSE2(
+                            const T* pChunkRow1, const T* pChunkRow2, const T* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    XMMReg4Double v_acc1 = XMMReg4Double::Zero(),
+                  v_acc2 = XMMReg4Double::Zero(),
+                  v_acc3 = XMMReg4Double::Zero();
+    int i = 0;
+    for(;i+3<nSrcPixelCount;i+=4)
+    {
+        // Retrieve the pixel & accumulate
+        XMMReg4Double v_pixels1 = XMMReg4Double::Load4Val(pChunkRow1+i);
+        XMMReg4Double v_pixels2 = XMMReg4Double::Load4Val(pChunkRow2+i);
+        XMMReg4Double v_pixels3 = XMMReg4Double::Load4Val(pChunkRow3+i);
+        XMMReg4Double v_weight = XMMReg4Double::Load4ValAligned(padfWeightsAligned+i);
+
+        v_acc1 += v_pixels1 * v_weight;
+        v_acc2 += v_pixels2 * v_weight;
+        v_acc3 += v_pixels3 * v_weight;
+    }
+
+    v_acc1.AddLowAndHigh();
+    v_acc2.AddLowAndHigh();
+    v_acc3.AddLowAndHigh();
+
+    dfRes1 = (double)v_acc1.GetLow();
+    dfRes2 = (double)v_acc2.GetLow();
+    dfRes3 = (double)v_acc3.GetLow();
+    for(;i<nSrcPixelCount;i++)
+    {
+        dfRes1 += pChunkRow1[i] * padfWeightsAligned[i];
+        dfRes2 += pChunkRow2[i] * padfWeightsAligned[i];
+        dfRes3 += pChunkRow3[i] * padfWeightsAligned[i];
+    }
+}
+
+/************************************************************************/
+/*     GDALResampleConvolutionHorizontalPixelCountLess8_3rows<GByte>    */
+/************************************************************************/
+
+template<> inline void GDALResampleConvolutionHorizontalPixelCountLess8_3rows<GByte>(
+                            const GByte* pChunkRow1, const GByte* pChunkRow2, const GByte* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    GDALResampleConvolutionHorizontalPixelCountLess8_3rows_SSE2(pChunkRow1, pChunkRow2, pChunkRow3,
+                                                                padfWeightsAligned, nSrcPixelCount,
+                                                                dfRes1, dfRes2, dfRes3);
+}
+
+template<> inline void GDALResampleConvolutionHorizontalPixelCountLess8_3rows<GUInt16>(
+                            const GUInt16* pChunkRow1, const GUInt16* pChunkRow2, const GUInt16* pChunkRow3,
+                            const double* padfWeightsAligned, int nSrcPixelCount,
+                            double& dfRes1, double& dfRes2, double& dfRes3)
+{
+    GDALResampleConvolutionHorizontalPixelCountLess8_3rows_SSE2(pChunkRow1, pChunkRow2, pChunkRow3,
+                                                                padfWeightsAligned, nSrcPixelCount,
+                                                                dfRes1, dfRes2, dfRes3);
+}
+
+#endif /*  USE_SSE2 */
+
+/************************************************************************/
+/*                   GDALResampleChunk32R_Convolution()                 */
+/************************************************************************/
+
+template<class T> static CPLErr
+GDALResampleChunk32R_ConvolutionT( double dfXRatioDstToSrc, double dfYRatioDstToSrc,
+                                     double dfSrcXDelta,
+                                     double dfSrcYDelta,
+                                     T * pChunk,
+                                     GByte * pabyChunkNodataMask,
+                                     int nChunkXOff, int nChunkXSize,
+                                     int nChunkYOff, int nChunkYSize,
+                                     int nDstXOff, int nDstXOff2,
+                                     int nDstYOff, int nDstYOff2,
+                                     GDALRasterBand * poOverview,
+                                     int bHasNoData,
+                                     float fNoDataValue,
+                                     FilterFuncType pfnFilterFunc,
+                                     FilterFunc4ValuesType pfnFilterFunc4Values,
+                                     int nKernelRadius )
+
+{
+
+    CPLErr eErr = CE_None;
+
+    if (!bHasNoData)
+        fNoDataValue = 0.0f;
 
 /* -------------------------------------------------------------------- */
-/*      Loop over destination pixels                                    */
+/*      Allocate work buffers.                                          */
 /* -------------------------------------------------------------------- */
-        for( iDstPixel = nDstXOff; iDstPixel < nDstXOff2; iDstPixel++ )
-        {
-            int   nSrcXOff, nSrcXOff2;
+    int nDstXSize = nDstXOff2 - nDstXOff;
 
-            nSrcXOff = (int) floor(((iDstPixel+0.5)/(double)nOXSize) * nSrcWidth - 0.5)-1;
-            nSrcXOff2 = nSrcXOff + 4;
+    double dfXScale = 1.0 / dfXRatioDstToSrc;
+    double dfXScaleWeight = ( dfXScale >= 1.0 ) ? 1.0 : dfXScale;
+    double dfXScaledRadius = nKernelRadius / dfXScaleWeight;
+    double dfYScale = 1.0 / dfYRatioDstToSrc;
+    double dfYScaleWeight = ( dfYScale >= 1.0 ) ? 1.0 : dfYScale;
+    double dfYScaledRadius = nKernelRadius / dfYScaleWeight;
 
-            if(nSrcXOff < 0)
-                nSrcXOff = 0;
+    float* pafDstScanline = (float *) VSIMalloc(nDstXSize * sizeof(float));
 
-            if( nSrcXOff2 > nChunkRightXOff || iDstPixel == nOXSize-1 )
-                nSrcXOff2 = nChunkRightXOff;
+    /* Temporary array to store result of horizontal filter */
+    double* padfHorizontalFiltered = (double*) VSIMalloc(nChunkYSize * nDstXSize * sizeof(double));
 
-            // If we do not seem to have our full 4x4 window just
-            // do nearest resampling.
-            if( nSrcXOff2 - nSrcXOff != 4 || nSrcYOff2 - nSrcYOff != 4 )
-            {
-                int nLSrcYOff = (int) (0.5+(iDstLine/(double)nOYSize) * nSrcHeight);
-                int nLSrcXOff = (int) (0.5+(iDstPixel/(double)nOXSize) * nSrcWidth);
+    /* To store convolution coefficients */
+    double* padfWeightsAlloc = (double*) CPLMalloc((int)(
+        2 + 2 * MAX(dfXScaledRadius, dfYScaledRadius) + 0.5 + 1 /* for alignment*/) * sizeof(double));
+
+    GByte* pabyChunkNodataMaskHorizontalFiltered = NULL;
+    if( pabyChunkNodataMask )
+        pabyChunkNodataMaskHorizontalFiltered = (GByte*) VSIMalloc(nChunkYSize * nDstXSize);
+    if( pafDstScanline == NULL || padfHorizontalFiltered == NULL ||
+        padfWeightsAlloc == NULL || (pabyChunkNodataMask != NULL && pabyChunkNodataMaskHorizontalFiltered == NULL) )
+    {
+        CPLError( CE_Failure, CPLE_OutOfMemory,
+                  "GDALResampleChunk32R_ConvolutionT: Out of memory for work buffers." );
+        VSIFree(pafDstScanline);
+        VSIFree(padfHorizontalFiltered);
+        VSIFree(padfWeightsAlloc);
+        VSIFree(pabyChunkNodataMaskHorizontalFiltered);
+        return CE_Failure;
+    }
+
+    /* Make sure we are aligned on 16 bits */
+    double* padfWeights = padfWeightsAlloc;
+    if( (((size_t)padfWeights) % 16) != 0 )
+        padfWeights ++;
+
+/* ==================================================================== */
+/*      Fist pass: horizontal filter                                    */
+/* ==================================================================== */
+    int nChunkRightXOff = nChunkXOff + nChunkXSize;
+#ifdef USE_SSE2
+    int bSrcPixelCountLess8 = dfXScaledRadius < 4;
+#endif
+    for( int iDstPixel = nDstXOff; iDstPixel < nDstXOff2; iDstPixel++ )
+    {
+        double dfSrcPixel = (iDstPixel+0.5)*dfXRatioDstToSrc + dfSrcXDelta;
+        int nSrcPixelStart = (int)floor(dfSrcPixel - dfXScaledRadius + 0.5);
+        int nSrcPixelStop = (int)(dfSrcPixel + dfXScaledRadius + 0.5);
+        if( nSrcPixelStart < nChunkXOff )
+            nSrcPixelStart = nChunkXOff;
+        if( nSrcPixelStop > nChunkRightXOff )
+            nSrcPixelStop = nChunkRightXOff;
+#if 0
+        if( nSrcPixelStart < nChunkXOff && nChunkXOff > 0 )
+        {
+            printf("truncated iDstPixel = %d\n", iDstPixel);
+        }
+        if( nSrcPixelStop > nChunkRightXOff && nChunkRightXOff < nSrcWidth )
+        {
+            printf("truncated iDstPixel = %d\n", iDstPixel);
+        }
+#endif
+        int nSrcPixelCount = nSrcPixelStop - nSrcPixelStart;
+        double dfWeightSum = 0.0;
 
-                if( nLSrcYOff < nChunkYOff )
-                    nLSrcYOff = nChunkYOff;
-                if( nLSrcYOff > nChunkYOff + nChunkYSize - 1 )
-                    nLSrcYOff = nChunkYOff + nChunkYSize - 1;
+        /* Compute convolution coefficients */
+        int nSrcPixel = nSrcPixelStart;
+        double dfX = dfXScaleWeight * (nSrcPixel - dfSrcPixel + 0.5);
+        for( ; nSrcPixel + 3 < nSrcPixelStop; nSrcPixel+=4)
+        {
+            padfWeights[nSrcPixel - nSrcPixelStart] = dfX;
+            dfX += dfXScaleWeight;
+            padfWeights[nSrcPixel+1 - nSrcPixelStart] = dfX;
+            dfX += dfXScaleWeight;
+            padfWeights[nSrcPixel+2 - nSrcPixelStart] = dfX;
+            dfX += dfXScaleWeight;
+            padfWeights[nSrcPixel+3 - nSrcPixelStart] = dfX;
+            dfX += dfXScaleWeight;
+            dfWeightSum += pfnFilterFunc4Values(padfWeights + nSrcPixel - nSrcPixelStart);
+        }
+        for( ; nSrcPixel < nSrcPixelStop; nSrcPixel++, dfX += dfXScaleWeight)
+        {
+            double dfWeight = pfnFilterFunc(dfX);
+            padfWeights[nSrcPixel - nSrcPixelStart] = dfWeight;
+            dfWeightSum += dfWeight;
+        }
+
+        if( pabyChunkNodataMask == NULL )
+        {
+            if( dfWeightSum != 0 )
+            {
+                double dfInvWeightSum = 1.0 / dfWeightSum;
+                for(int i=0;i<nSrcPixelCount;i++)
+                    padfWeights[i] *= dfInvWeightSum;
+            }
 
-                pafDstScanline[iDstPixel - nDstXOff] =
-                    pafChunk[(nLSrcYOff-nChunkYOff) * nChunkXSize
-                                + (nLSrcXOff - nChunkXOff)];
+            int iSrcLineOff = 0;
+#ifdef USE_SSE2
+            if( bSrcPixelCountLess8 )
+            {
+                for( ; iSrcLineOff+2 < nChunkYSize; iSrcLineOff +=3 )
+                {
+                    int j=iSrcLineOff * nChunkXSize + (nSrcPixelStart - nChunkXOff);
+                    double dfVal1, dfVal2, dfVal3;
+                    GDALResampleConvolutionHorizontalPixelCountLess8_3rows(
+                        pChunk + j, pChunk + j + nChunkXSize, pChunk + j + 2 * nChunkXSize,
+                        padfWeights, nSrcPixelCount, dfVal1, dfVal2, dfVal3);
+                    padfHorizontalFiltered[iSrcLineOff * nDstXSize + iDstPixel - nDstXOff] = dfVal1;
+                    padfHorizontalFiltered[(iSrcLineOff+1) * nDstXSize + iDstPixel - nDstXOff] = dfVal2;
+                    padfHorizontalFiltered[(iSrcLineOff+2) * nDstXSize + iDstPixel - nDstXOff] = dfVal3;
+                }
             }
             else
+#endif
+            {
+                for( ; iSrcLineOff+2 < nChunkYSize; iSrcLineOff +=3 )
+                {
+                    int j=iSrcLineOff * nChunkXSize + (nSrcPixelStart - nChunkXOff);
+                    double dfVal1, dfVal2, dfVal3;
+                    GDALResampleConvolutionHorizontal_3rows(
+                        pChunk + j, pChunk + j + nChunkXSize, pChunk + j + 2 * nChunkXSize,
+                        padfWeights, nSrcPixelCount, dfVal1, dfVal2, dfVal3);
+                    padfHorizontalFiltered[iSrcLineOff * nDstXSize + iDstPixel - nDstXOff] = dfVal1;
+                    padfHorizontalFiltered[(iSrcLineOff+1) * nDstXSize + iDstPixel - nDstXOff] = dfVal2;
+                    padfHorizontalFiltered[(iSrcLineOff+2) * nDstXSize + iDstPixel - nDstXOff] = dfVal3;
+                }
+            }
+            for( ; iSrcLineOff < nChunkYSize; iSrcLineOff ++ )
+            {
+                int j=iSrcLineOff * nChunkXSize + (nSrcPixelStart - nChunkXOff);
+                double dfVal =
+                    GDALResampleConvolutionHorizontal(pChunk + j,
+                                                padfWeights, nSrcPixelCount);
+                padfHorizontalFiltered[iSrcLineOff * nDstXSize + iDstPixel - nDstXOff] = dfVal;
+            }
+        }
+        else
+        {
+            for( int iSrcLineOff = 0; iSrcLineOff < nChunkYSize; iSrcLineOff ++ )
             {
-#define CubicConvolution(distance1,distance2,distance3,f0,f1,f2,f3) \
-(  (   -f0 +     f1 - f2 + f3) * distance3                       \
-+ (2.0*(f0 - f1) + f2 - f3) * distance2                         \
-+ (   -f0          + f2     ) * distance1                       \
-+               f1                         )
-
-                int ic;
-                double adfRowResults[4];
-                double dfSrcX = (((iDstPixel+0.5)/(double)nOXSize) * nSrcWidth);
-                double dfDeltaX = dfSrcX - 0.5 - (nSrcXOff+1);
-                double dfDeltaX2 = dfDeltaX * dfDeltaX;
-                double dfDeltaX3 = dfDeltaX2 * dfDeltaX;
-
-                for ( ic = 0; ic < 4; ic++ )
+                double dfVal;
+                int j=iSrcLineOff * nChunkXSize + (nSrcPixelStart - nChunkXOff);
+                GDALResampleConvolutionHorizontalWithMask(pChunk + j, pabyChunkNodataMask + j,
+                                                            padfWeights, nSrcPixelCount,
+                                                            dfVal, dfWeightSum);
+                int nTempOffset = iSrcLineOff * nDstXSize + iDstPixel - nDstXOff;
+                if( dfWeightSum > 0.0 )
                 {
-                    float *pafSrcRow = pafSrcScanline +
-                        nSrcXOff-nChunkXOff+(nSrcYOff+ic-nSrcYOff)*nChunkXSize;
-
-                    adfRowResults[ic] =
-                        CubicConvolution(dfDeltaX, dfDeltaX2, dfDeltaX3,
-                                            pafSrcRow[0],
-                                            pafSrcRow[1],
-                                            pafSrcRow[2],
-                                            pafSrcRow[3] );
+                    padfHorizontalFiltered[nTempOffset] = dfVal / dfWeightSum;
+                    pabyChunkNodataMaskHorizontalFiltered[nTempOffset] = 1;
                 }
+                else
+                {
+                    padfHorizontalFiltered[nTempOffset] = 0.0;
+                    pabyChunkNodataMaskHorizontalFiltered[nTempOffset] = 0;
+                }
+            }
+        }
+    }
+
+/* ==================================================================== */
+/*      Second pass: vertical filter                                    */
+/* ==================================================================== */
+    int nChunkBottomYOff = nChunkYOff + nChunkYSize;
+    for( int iDstLine = nDstYOff; iDstLine < nDstYOff2; iDstLine++ )
+    {
+        double dfSrcLine = (iDstLine+0.5)*dfYRatioDstToSrc + dfSrcYDelta;
+        int nSrcLineStart = (int)floor(dfSrcLine - dfYScaledRadius + 0.5);
+        int nSrcLineStop = (int)(dfSrcLine + dfYScaledRadius + 0.5);
+        if( nSrcLineStart < nChunkYOff )
+            nSrcLineStart = nChunkYOff;
+        if( nSrcLineStop > nChunkBottomYOff )
+            nSrcLineStop = nChunkBottomYOff;
+#if 0
+        if( nSrcLineStart < nChunkYOff &&
+            nChunkYOff > 0 )
+        {
+            printf("truncated iDstLine = %d\n", iDstLine);
+        }
+        if( nSrcLineStop > nChunkBottomYOff && nChunkBottomYOff < nSrcHeight )
+        {
+            printf("truncated iDstLine = %d\n", iDstLine);
+        }
+#endif
+        int nSrcLineCount = nSrcLineStop - nSrcLineStart;
+        double dfWeightSum = 0.0;
+
+        /* Compute convolution coefficients */
+        int nSrcLine = nSrcLineStart;
+        double dfY = dfYScaleWeight * (nSrcLine - dfSrcLine + 0.5);
+        for( ; nSrcLine + 3 < nSrcLineStop; nSrcLine+=4, dfY += 4 * dfYScaleWeight)
+        {
+            padfWeights[nSrcLine - nSrcLineStart] = dfY;
+            padfWeights[nSrcLine+1 - nSrcLineStart] = dfY + dfYScaleWeight;
+            padfWeights[nSrcLine+2 - nSrcLineStart] = dfY + 2 * dfYScaleWeight;
+            padfWeights[nSrcLine+3 - nSrcLineStart] = dfY + 3 * dfYScaleWeight;
+            dfWeightSum += pfnFilterFunc4Values(padfWeights + nSrcLine - nSrcLineStart);
+        }
+        for( ; nSrcLine < nSrcLineStop; nSrcLine++, dfY += dfYScaleWeight)
+        {
+            double dfWeight = pfnFilterFunc(dfY);
+            padfWeights[nSrcLine - nSrcLineStart] = dfWeight;
+            dfWeightSum += dfWeight;
+        }
 
-                double dfSrcY = (((iDstLine+0.5)/(double)nOYSize) * nSrcHeight);
-                double dfDeltaY = dfSrcY - 0.5 - (nSrcYOff+1);
-                double dfDeltaY2 = dfDeltaY * dfDeltaY;
-                double dfDeltaY3 = dfDeltaY2 * dfDeltaY;
-
-                pafDstScanline[iDstPixel - nDstXOff] = (float)
-                    CubicConvolution(dfDeltaY, dfDeltaY2, dfDeltaY3,
-                                        adfRowResults[0],
-                                        adfRowResults[1],
-                                        adfRowResults[2],
-                                        adfRowResults[3] );
+        if( pabyChunkNodataMask == NULL )
+        {
+            if( dfWeightSum != 0 )
+            {
+                double dfInvWeightSum = 1.0 / dfWeightSum;
+                for(int i=0;i<nSrcLineCount;i++)
+                    padfWeights[i] *= dfInvWeightSum;
+            }
+
+            int iFilteredPixelOff = 0;
+            int j=(nSrcLineStart - nChunkYOff) * nDstXSize;
+            for( ; iFilteredPixelOff+1 < nDstXSize; iFilteredPixelOff += 2, j+=2 )
+            {
+                double dfVal1, dfVal2;
+                GDALResampleConvolutionVertical_2cols(
+                    padfHorizontalFiltered + j, nDstXSize, padfWeights, nSrcLineCount, dfVal1, dfVal2);
+                pafDstScanline[iFilteredPixelOff] = (float)dfVal1;
+                pafDstScanline[iFilteredPixelOff+1] = (float)dfVal2;
+            }
+            if( iFilteredPixelOff < nDstXSize )
+            {
+                double dfVal = GDALResampleConvolutionVertical(
+                    padfHorizontalFiltered + j, nDstXSize, padfWeights, nSrcLineCount);
+                pafDstScanline[iFilteredPixelOff] = (float)dfVal;
+            }
+        }
+        else
+        {
+            for( int iFilteredPixelOff = 0; iFilteredPixelOff < nDstXSize; iFilteredPixelOff ++ )
+            {
+                double dfVal = 0.0;
+                dfWeightSum = 0.0;
+                for(int i=0, j=(nSrcLineStart - nChunkYOff) * nDstXSize + iFilteredPixelOff;
+                    i<nSrcLineCount; i++, j+=nDstXSize)
+                {
+                    double dfWeight = padfWeights[i] * pabyChunkNodataMaskHorizontalFiltered[j];
+                    dfVal += padfHorizontalFiltered[j] * dfWeight;
+                    dfWeightSum += dfWeight;
+                }
+                if( dfWeightSum > 0.0 )
+                {
+                    pafDstScanline[iFilteredPixelOff] = (float)(dfVal / dfWeightSum);
+                }
+                else
+                {
+                    pafDstScanline[iFilteredPixelOff] = fNoDataValue;
+                }
             }
         }
 
-        eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXOff2 - nDstXOff, 1,
-                                     pafDstScanline, nDstXOff2 - nDstXOff, 1, GDT_Float32,
-                                     0, 0 );
+        eErr = poOverview->RasterIO( GF_Write, nDstXOff, iDstLine, nDstXSize, 1,
+                                     pafDstScanline, nDstXSize, 1, GDT_Float32,
+                                     0, 0, NULL );
     }
 
-    CPLFree( pafDstScanline );
-    CPLFree( aEntries );
+    VSIFree( padfWeightsAlloc );
+    VSIFree( padfHorizontalFiltered );
+    VSIFree( pafDstScanline );
+    VSIFree(pabyChunkNodataMaskHorizontalFiltered);
 
     return eErr;
 }
 
+static CPLErr GDALResampleChunk32R_Convolution(
+                        double dfXRatioDstToSrc, double dfYRatioDstToSrc,
+                        double dfSrcXDelta,
+                        double dfSrcYDelta,
+                        GDALDataType eWrkDataType,
+                        void * pChunk,
+                        GByte * pabyChunkNodataMask,
+                        int nChunkXOff, int nChunkXSize,
+                        int nChunkYOff, int nChunkYSize,
+                        int nDstXOff, int nDstXOff2,
+                        int nDstYOff, int nDstYOff2,
+                        GDALRasterBand * poOverview,
+                        const char * pszResampling,
+                        int bHasNoData, float fNoDataValue,
+                        CPL_UNUSED GDALColorTable* poColorTable_unused,
+                        CPL_UNUSED GDALDataType eSrcDataType)
+{
+    GDALResampleAlg eResample;
+    if( EQUAL(pszResampling, "BILINEAR") )
+        eResample = GRA_Bilinear;
+    else if( EQUAL(pszResampling, "CUBIC") )
+        eResample = GRA_Cubic;
+    else if( EQUAL(pszResampling, "CUBICSPLINE") )
+        eResample = GRA_CubicSpline;
+    else if( EQUAL(pszResampling, "LANCZOS") )
+        eResample = GRA_Lanczos;
+    else
+    {
+        CPLAssert(0);
+        return CE_Failure;
+    }
+    int nKernelRadius = GWKGetFilterRadius(eResample);
+    FilterFuncType pfnFilterFunc = GWKGetFilterFunc(eResample);
+    FilterFunc4ValuesType pfnFilterFunc4Values = GWKGetFilterFunc4Values(eResample);
+
+    if (eWrkDataType == GDT_Byte)
+        return GDALResampleChunk32R_ConvolutionT(dfXRatioDstToSrc, dfYRatioDstToSrc,
+                        dfSrcXDelta, dfSrcYDelta,
+                        (GByte *) pChunk, pabyChunkNodataMask,
+                        nChunkXOff, nChunkXSize, 
+                        nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview,
+                        bHasNoData, fNoDataValue,
+                        pfnFilterFunc,
+                        pfnFilterFunc4Values,
+                        nKernelRadius);
+   else if (eWrkDataType == GDT_UInt16)
+        return GDALResampleChunk32R_ConvolutionT(dfXRatioDstToSrc, dfYRatioDstToSrc,
+                        dfSrcXDelta, dfSrcYDelta,
+                        (GUInt16 *) pChunk, pabyChunkNodataMask,
+                        nChunkXOff, nChunkXSize, 
+                        nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview,
+                        bHasNoData, fNoDataValue,
+                        pfnFilterFunc,
+                        pfnFilterFunc4Values,
+                        nKernelRadius);
+    else if (eWrkDataType == GDT_Float32)
+        return GDALResampleChunk32R_ConvolutionT(dfXRatioDstToSrc, dfYRatioDstToSrc,
+                        dfSrcXDelta, dfSrcYDelta,
+                        (float *) pChunk, pabyChunkNodataMask,
+                        nChunkXOff, nChunkXSize,
+                        nChunkYOff, nChunkYSize,
+                        nDstXOff, nDstXOff2,
+                        nDstYOff, nDstYOff2,
+                        poOverview,
+                        bHasNoData, fNoDataValue,
+                        pfnFilterFunc,
+                        pfnFilterFunc4Values,
+                        nKernelRadius);
+
+    CPLAssert(0);
+    return CE_Failure;
+}
+
 /************************************************************************/
-/*                       GDALDownsampleChunkC32R()                      */
+/*                       GDALResampleChunkC32R()                        */
 /************************************************************************/
 
 static CPLErr
-GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight, 
+GDALResampleChunkC32R( int nSrcWidth, int nSrcHeight, 
                          float * pafChunk, int nChunkYOff, int nChunkYSize,
+                         int nDstYOff, int nDstYOff2,
                          GDALRasterBand * poOverview,
                          const char * pszResampling )
     
 {
-    int      nDstYOff, nDstYOff2, nOXSize, nOYSize;
+    int      nOXSize, nOYSize;
     float    *pafDstScanline;
     CPLErr   eErr = CE_None;
 
     nOXSize = poOverview->GetXSize();
     nOYSize = poOverview->GetYSize();
+    double dfXRatioDstToSrc = (double)nSrcWidth / nOXSize;
+    double dfYRatioDstToSrc = (double)nSrcHeight / nOYSize;
 
     pafDstScanline = (float *) VSIMalloc(nOXSize * sizeof(float) * 2);
     if( pafDstScanline == NULL )
     {
         CPLError( CE_Failure, CPLE_OutOfMemory,
-                  "GDALDownsampleChunkC32R: Out of memory for line buffer." );
+                  "GDALResampleChunkC32R: Out of memory for line buffer." );
         return CE_Failure;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Figure out the line to start writing to, and the first line     */
-/*      to not write to.  In theory this approach should ensure that    */
-/*      every output line will be written if all input chunks are       */
-/*      processed.                                                      */
-/* -------------------------------------------------------------------- */
-    nDstYOff = (int) (0.5 + (nChunkYOff/(double)nSrcHeight) * nOYSize);
-    nDstYOff2 = (int) 
-        (0.5 + ((nChunkYOff+nChunkYSize)/(double)nSrcHeight) * nOYSize);
-
-    if( nChunkYOff + nChunkYSize == nSrcHeight )
-        nDstYOff2 = nOYSize;
-    
 /* ==================================================================== */
 /*      Loop over destination scanlines.                                */
 /* ==================================================================== */
@@ -1266,13 +1802,20 @@ GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight,
         float *pafSrcScanline;
         int   nSrcYOff, nSrcYOff2, iDstPixel;
 
-        nSrcYOff = (int) (0.5 + (iDstLine/(double)nOYSize) * nSrcHeight);
+        nSrcYOff = (int) (0.5 + iDstLine * dfYRatioDstToSrc);
         if( nSrcYOff < nChunkYOff )
             nSrcYOff = nChunkYOff;
         
-        nSrcYOff2 = (int) (0.5 + ((iDstLine+1)/(double)nOYSize) * nSrcHeight);
+        nSrcYOff2 = (int) (0.5 + (iDstLine+1) * dfYRatioDstToSrc);
+        if( nSrcYOff2 == nSrcYOff )
+            nSrcYOff2 ++;
+
         if( nSrcYOff2 > nSrcHeight || iDstLine == nOYSize-1 )
+        {
+            if( nSrcYOff == nSrcHeight && nSrcHeight - 1 >= nChunkYOff )
+                nSrcYOff = nSrcHeight - 1;
             nSrcYOff2 = nSrcHeight;
+        }
         if( nSrcYOff2 > nChunkYOff + nChunkYSize )
             nSrcYOff2 = nChunkYOff + nChunkYSize;
 
@@ -1285,12 +1828,18 @@ GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight,
         {
             int   nSrcXOff, nSrcXOff2;
 
-            nSrcXOff = (int) (0.5 + (iDstPixel/(double)nOXSize) * nSrcWidth);
+            nSrcXOff = (int) (0.5 + iDstPixel * dfXRatioDstToSrc);
             nSrcXOff2 = (int) 
-                (0.5 + ((iDstPixel+1)/(double)nOXSize) * nSrcWidth);
-            if( nSrcXOff2 > nSrcWidth )
+                (0.5 + (iDstPixel+1) * dfXRatioDstToSrc);
+            if( nSrcXOff2 == nSrcXOff )
+                nSrcXOff2 ++;
+            if( nSrcXOff2 > nSrcWidth || iDstPixel == nOXSize-1 )
+            {
+                if( nSrcXOff == nSrcWidth && nSrcWidth - 1 >= 0 )
+                    nSrcXOff = nSrcWidth - 1;
                 nSrcXOff2 = nSrcWidth;
-            
+            }
+
             if( EQUALN(pszResampling,"NEAR",4) )
             {
                 pafDstScanline[iDstPixel*2] = pafSrcScanline[nSrcXOff*2];
@@ -1370,7 +1919,7 @@ GDALDownsampleChunkC32R( int nSrcWidth, int nSrcHeight,
 
         eErr = poOverview->RasterIO( GF_Write, 0, iDstLine, nOXSize, 1, 
                                      pafDstScanline, nOXSize, 1, GDT_CFloat32, 
-                                     0, 0 );
+                                     0, 0, NULL );
     }
 
     CPLFree( pafDstScanline );
@@ -1475,26 +2024,48 @@ GDALRegenerateCascadingOverviews(
 }
 
 /************************************************************************/
-/*                    GDALGetDownsampleFunction()                       */
+/*                    GDALGetResampleFunction()                         */
 /************************************************************************/
 
-static
-GDALDownsampleFunction GDALGetDownsampleFunction(const char* pszResampling)
+GDALResampleFunction GDALGetResampleFunction(const char* pszResampling,
+                                                 int* pnRadius)
 {
+    if( pnRadius ) *pnRadius = 0;
     if( EQUALN(pszResampling,"NEAR",4) )
-        return GDALDownsampleChunk32R_Near;
+        return GDALResampleChunk32R_Near;
     else if( EQUALN(pszResampling,"AVER",4) )
-        return GDALDownsampleChunk32R_Average;
+        return GDALResampleChunk32R_Average;
     else if( EQUALN(pszResampling,"GAUSS",5) )
-        return GDALDownsampleChunk32R_Gauss;
+    {
+        if( pnRadius ) *pnRadius = 1;
+        return GDALResampleChunk32R_Gauss;
+    }
     else if( EQUALN(pszResampling,"MODE",4) )
-        return GDALDownsampleChunk32R_Mode;
-    else if( EQUALN(pszResampling,"CUBIC",5) )
-        return GDALDownsampleChunk32R_Cubic;
+        return GDALResampleChunk32R_Mode;
+    else if( EQUAL(pszResampling,"CUBIC") )
+    {
+        if( pnRadius ) *pnRadius = GWKGetFilterRadius(GRA_Cubic);
+        return GDALResampleChunk32R_Convolution;
+    }
+    else if( EQUAL(pszResampling,"CUBICSPLINE") )
+    {
+        if( pnRadius ) *pnRadius = GWKGetFilterRadius(GRA_CubicSpline);
+        return GDALResampleChunk32R_Convolution;
+    }
+    else if( EQUAL(pszResampling,"LANCZOS") )
+    {
+        if( pnRadius ) *pnRadius = GWKGetFilterRadius(GRA_Lanczos);
+        return GDALResampleChunk32R_Convolution;
+    }
+    else if( EQUAL(pszResampling,"BILINEAR") )
+    {
+        if( pnRadius ) *pnRadius = GWKGetFilterRadius(GRA_Bilinear);
+        return GDALResampleChunk32R_Convolution;
+    }
     else
     {
        CPLError( CE_Failure, CPLE_AppDefined,
-                  "GDALGetDownsampleFunction: Unsupported resampling method \"%s\".",
+                  "GDALGetResampleFunction: Unsupported resampling method \"%s\".",
                   pszResampling );
         return NULL;
     }
@@ -1504,12 +2075,25 @@ GDALDownsampleFunction GDALGetDownsampleFunction(const char* pszResampling)
 /*                      GDALGetOvrWorkDataType()                        */
 /************************************************************************/
 
-static GDALDataType GDALGetOvrWorkDataType(const char* pszResampling,
+GDALDataType GDALGetOvrWorkDataType(const char* pszResampling,
                                         GDALDataType eSrcDataType)
 {
-    if( (EQUALN(pszResampling,"NEAR",4) || EQUALN(pszResampling,"AVER",4)) &&
+    if( (EQUALN(pszResampling,"NEAR",4) ||
+         EQUALN(pszResampling,"AVER",4) ||
+         EQUAL(pszResampling,"CUBIC") ||
+         EQUAL(pszResampling,"CUBICSPLINE") ||
+         EQUAL(pszResampling,"LANCZOS") ||
+         EQUAL(pszResampling,"BILINEAR")) &&
         eSrcDataType == GDT_Byte)
         return GDT_Byte;
+    else if( (EQUALN(pszResampling,"NEAR",4) ||
+         EQUALN(pszResampling,"AVER",4) ||
+         EQUAL(pszResampling,"CUBIC") ||
+         EQUAL(pszResampling,"CUBICSPLINE") ||
+         EQUAL(pszResampling,"LANCZOS") ||
+         EQUAL(pszResampling,"BILINEAR")) &&
+        eSrcDataType == GDT_UInt16)
+        return GDT_UInt16;
     else
         return GDT_Float32;
 }
@@ -1553,7 +2137,7 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
 {
     GDALRasterBand *poSrcBand = (GDALRasterBand *) hSrcBand;
     GDALRasterBand **papoOvrBands = (GDALRasterBand **) pahOvrBands;
-    int    nFullResYChunk, nWidth;
+    int    nFullResYChunk, nWidth, nHeight;
     int    nFRXBlockSize, nFRYBlockSize;
     GDALDataType eType;
     int    bHasNoData;
@@ -1566,8 +2150,10 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
     if( EQUAL(pszResampling,"NONE") )
         return CE_None;
 
-    GDALDownsampleFunction pfnDownsampleFn = GDALGetDownsampleFunction(pszResampling);
-    if (pfnDownsampleFn == NULL)
+    int nKernelRadius;
+    GDALResampleFunction pfnResampleFn = GDALGetResampleFunction(pszResampling,
+                                                                       &nKernelRadius);
+    if (pfnResampleFn == NULL)
         return CE_Failure;
 
 /* -------------------------------------------------------------------- */
@@ -1597,6 +2183,17 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
                     "without a palette will probably lead to unexpected results.");
         }
     }
+    // Not ready yet
+    else if( (EQUAL(pszResampling,"CUBIC") ||
+              EQUAL(pszResampling,"CUBICSPLINE") ||
+              EQUAL(pszResampling,"LANCZOS") ||
+              EQUAL(pszResampling,"BILINEAR") )
+        && poSrcBand->GetColorInterpretation() == GCI_PaletteIndex )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                    "Computing %s overviews on palette index raster bands "
+                    "will probably lead to unexpected results.", pszResampling);
+    }
 
 
     /* If we have a nodata mask and we are doing something more complicated */
@@ -1605,6 +2202,7 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
     GDALRasterBand* poMaskBand = NULL;
     int nMaskFlags = 0;
     int bUseNoDataMask = FALSE;
+
     if( !EQUALN(pszResampling,"NEAR",4) )
     {
         /* Special case if we are the alpha band. We want it to be considered */
@@ -1633,7 +2231,12 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
     /* In case the mask made be computed from another band of the dataset, */
     /* we can't use cascaded generation, as the computation of the overviews */
     /* of the band used for the mask band may not have yet occured (#3033) */
-    if( (EQUALN(pszResampling,"AVER",4) || EQUALN(pszResampling,"GAUSS",5)) && nOverviewCount > 1
+    if( (EQUALN(pszResampling,"AVER",4) |
+         EQUALN(pszResampling,"GAUSS",5) ||
+         EQUAL(pszResampling,"CUBIC") ||
+         EQUAL(pszResampling,"CUBICSPLINE") ||
+         EQUAL(pszResampling,"LANCZOS") ||
+         EQUAL(pszResampling,"BILINEAR")) && nOverviewCount > 1
          && !(bUseNoDataMask && nMaskFlags != GMF_NODATA))
         return GDALRegenerateCascadingOverviews( poSrcBand, 
                                                  nOverviewCount, papoOvrBands,
@@ -1660,12 +2263,24 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
         eType = GDALGetOvrWorkDataType(pszResampling, poSrcBand->GetRasterDataType());
 
     nWidth = poSrcBand->GetXSize();
+    nHeight = poSrcBand->GetYSize();
+    
+    int nMaxOvrFactor = 1;
+    for( int iOverview = 0; iOverview < nOverviewCount; iOverview ++ )
+    {
+        int nDstWidth = papoOvrBands[iOverview]->GetXSize();
+        int nDstHeight = papoOvrBands[iOverview]->GetYSize();
+        nMaxOvrFactor = MAX( nMaxOvrFactor, (int)((double)nWidth / nDstWidth + 0.5) );
+        nMaxOvrFactor = MAX( nMaxOvrFactor, (int)((double)nHeight / nDstHeight + 0.5) );
+    }
+    int nMaxChunkYSizeQueried = nFullResYChunk + 2 * nKernelRadius * nMaxOvrFactor;
+
     pChunk = 
-        VSIMalloc3((GDALGetDataTypeSize(eType)/8), nFullResYChunk, nWidth );
+        VSIMalloc3((GDALGetDataTypeSize(eType)/8), nMaxChunkYSizeQueried, nWidth );
     if (bUseNoDataMask)
     {
         pabyChunkNodataMask = (GByte *) 
-            (GByte*) VSIMalloc2( nFullResYChunk, nWidth );
+            (GByte*) VSIMalloc2( nMaxChunkYSizeQueried, nWidth );
     }
 
     if( pChunk == NULL || (bUseNoDataMask && pabyChunkNodataMask == NULL))
@@ -1687,28 +2302,38 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
     CPLErr eErr = CE_None;
 
     for( nChunkYOff = 0; 
-         nChunkYOff < poSrcBand->GetYSize() && eErr == CE_None; 
+         nChunkYOff < nHeight && eErr == CE_None; 
          nChunkYOff += nFullResYChunk )
     {
-        if( !pfnProgress( nChunkYOff / (double) poSrcBand->GetYSize(), 
+        if( !pfnProgress( nChunkYOff / (double) nHeight, 
                           NULL, pProgressData ) )
         {
             CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
             eErr = CE_Failure;
         }
 
-        if( nFullResYChunk + nChunkYOff > poSrcBand->GetYSize() )
-            nFullResYChunk = poSrcBand->GetYSize() - nChunkYOff;
+        if( nFullResYChunk + nChunkYOff > nHeight )
+            nFullResYChunk = nHeight - nChunkYOff;
         
+        int nChunkYOffQueried = nChunkYOff - nKernelRadius * nMaxOvrFactor;
+        int nChunkYSizeQueried = nFullResYChunk + 2 * nKernelRadius * nMaxOvrFactor;
+        if( nChunkYOffQueried < 0 )
+        {
+            nChunkYSizeQueried += nChunkYOffQueried;
+            nChunkYOffQueried = 0;
+        }
+        if( nChunkYOffQueried + nChunkYSizeQueried > nHeight )
+            nChunkYSizeQueried = nHeight - nChunkYOffQueried;
+
         /* read chunk */
         if (eErr == CE_None)
-            eErr = poSrcBand->RasterIO( GF_Read, 0, nChunkYOff, nWidth, nFullResYChunk, 
-                                pChunk, nWidth, nFullResYChunk, eType,
-                                0, 0 );
+            eErr = poSrcBand->RasterIO( GF_Read, 0, nChunkYOffQueried, nWidth, nChunkYSizeQueried, 
+                                pChunk, nWidth, nChunkYSizeQueried, eType,
+                                0, 0, NULL );
         if (eErr == CE_None && bUseNoDataMask)
-            eErr = poMaskBand->RasterIO( GF_Read, 0, nChunkYOff, nWidth, nFullResYChunk, 
-                                pabyChunkNodataMask, nWidth, nFullResYChunk, GDT_Byte,
-                                0, 0 );
+            eErr = poMaskBand->RasterIO( GF_Read, 0, nChunkYOffQueried, nWidth, nChunkYSizeQueried, 
+                                pabyChunkNodataMask, nWidth, nChunkYSizeQueried, GDT_Byte,
+                                0, 0, NULL );
 
         /* special case to promote 1bit data to 8bit 0/255 values */
         if( EQUAL(pszResampling,"AVERAGE_BIT2GRAYSCALE") )
@@ -1718,7 +2343,7 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
             if (eType == GDT_Float32)
             {
                 float* pafChunk = (float*)pChunk;
-                for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
                 {
                     if( pafChunk[i] == 1.0 )
                         pafChunk[i] = 255.0;
@@ -1727,12 +2352,21 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
             else if (eType == GDT_Byte)
             {
                 GByte* pabyChunk = (GByte*)pChunk;
-                for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
                 {
                     if( pabyChunk[i] == 1 )
                         pabyChunk[i] = 255;
                 }
             }
+            else if (eType == GDT_UInt16)
+            {
+                GUInt16* pasChunk = (GUInt16*)pChunk;
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
+                {
+                    if( pasChunk[i] == 1 )
+                        pasChunk[i] = 255;
+                }
+            }
             else {
                 CPLAssert(0);
             }
@@ -1744,7 +2378,7 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
             if (eType == GDT_Float32)
             {
                 float* pafChunk = (float*)pChunk;
-                for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
                 {
                     if( pafChunk[i] == 1.0 )
                         pafChunk[i] = 0.0;
@@ -1755,7 +2389,7 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
             else if (eType == GDT_Byte)
             {
                 GByte* pabyChunk = (GByte*)pChunk;
-                for( i = nFullResYChunk*nWidth - 1; i >= 0; i-- )
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
                 {
                     if( pabyChunk[i] == 1 )
                         pabyChunk[i] = 0;
@@ -1763,6 +2397,17 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
                         pabyChunk[i] = 255;
                 }
             }
+            else if (eType == GDT_UInt16)
+            {
+                GUInt16* pasChunk = (GUInt16*)pChunk;
+                for( i = nChunkYSizeQueried*nWidth - 1; i >= 0; i-- )
+                {
+                    if( pasChunk[i] == 1 )
+                        pasChunk[i] = 0;
+                    else if( pasChunk[i] == 0 )
+                        pasChunk[i] = 255;
+                }
+            }
             else {
                 CPLAssert(0);
             }
@@ -1770,19 +2415,44 @@ GDALRegenerateOverviews( GDALRasterBandH hSrcBand,
 
         for( int iOverview = 0; iOverview < nOverviewCount && eErr == CE_None; iOverview++ )
         {
-            if( eType == GDT_Byte || eType == GDT_Float32 )
-                eErr = pfnDownsampleFn(nWidth, poSrcBand->GetYSize(),
+            int nDstWidth = papoOvrBands[iOverview]->GetXSize();
+            int nDstHeight = papoOvrBands[iOverview]->GetYSize();
+
+            double dfXRatioDstToSrc = (double)nWidth / nDstWidth;
+            double dfYRatioDstToSrc = (double)nHeight / nDstHeight;
+
+/* -------------------------------------------------------------------- */
+/*      Figure out the line to start writing to, and the first line     */
+/*      to not write to.  In theory this approach should ensure that    */
+/*      every output line will be written if all input chunks are       */
+/*      processed.                                                      */
+/* -------------------------------------------------------------------- */
+            int nDstYOff = (int) (0.5 + nChunkYOff/dfYRatioDstToSrc);
+            int nDstYOff2 = (int)
+                (0.5 + (nChunkYOff+nFullResYChunk)/dfYRatioDstToSrc);
+
+            if( nChunkYOff + nFullResYChunk == nHeight )
+                nDstYOff2 = nDstHeight;
+            //CPLDebug("GDAL", "nDstYOff=%d, nDstYOff2=%d", nDstYOff, nDstYOff2);
+
+            if( eType == GDT_Byte || eType == GDT_UInt16 || eType == GDT_Float32 )
+                eErr = pfnResampleFn(dfXRatioDstToSrc, dfYRatioDstToSrc,
+                                       0.0, 0.0,
                                               eType,
                                               pChunk,
                                               pabyChunkNodataMask,
                                               0, nWidth,
-                                              nChunkYOff, nFullResYChunk,
+                                              nChunkYOffQueried, nChunkYSizeQueried,
+                                              0, nDstWidth,
+                                              nDstYOff, nDstYOff2,
                                               papoOvrBands[iOverview], pszResampling,
                                               bHasNoData, fNoDataValue, poColorTable,
                                               poSrcBand->GetRasterDataType());
             else
-                eErr = GDALDownsampleChunkC32R(nWidth, poSrcBand->GetYSize(), 
-                                               (float*)pChunk, nChunkYOff, nFullResYChunk,
+                eErr = GDALResampleChunkC32R(nWidth, nHeight, 
+                                               (float*)pChunk,
+                                               nChunkYOffQueried, nChunkYSizeQueried,
+                                               nDstYOff, nDstYOff2,
                                                papoOvrBands[iOverview], pszResampling);
         }
     }
@@ -1879,15 +2549,23 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
         return CE_None;
 
     /* Sanity checks */
-    if (!EQUALN(pszResampling, "NEAR", 4) && !EQUAL(pszResampling, "AVERAGE") && !EQUAL(pszResampling, "GAUSS"))
+    if (!EQUALN(pszResampling, "NEAR", 4) &&
+        !EQUAL(pszResampling, "AVERAGE") &&
+        !EQUAL(pszResampling, "GAUSS") &&
+        !EQUAL(pszResampling, "CUBIC") &&
+        !EQUAL(pszResampling,"CUBICSPLINE") &&
+        !EQUAL(pszResampling,"LANCZOS") &&
+        !EQUAL(pszResampling,"BILINEAR"))
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "GDALRegenerateOverviewsMultiBand: pszResampling='%s' not supported", pszResampling);
         return CE_Failure;
     }
 
-    GDALDownsampleFunction pfnDownsampleFn = GDALGetDownsampleFunction(pszResampling);
-    if (pfnDownsampleFn == NULL)
+    int nKernelRadius;
+    GDALResampleFunction pfnResampleFn = GDALGetResampleFunction(pszResampling,
+                                                                       &nKernelRadius);
+    if (pfnResampleFn == NULL)
         return CE_Failure;
 
     int nSrcWidth = papoSrcBands[0]->GetXSize();
@@ -1991,16 +2669,25 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
             iSrcOverview = iOverview - 1;
         }
 
-        /* Compute the chunck size of the source such as it will match the size of */
+        double dfXRatioDstToSrc = (double)nSrcWidth / nDstWidth;
+        double dfYRatioDstToSrc = (double)nSrcHeight / nDstHeight;
+
+        /* Compute the maximum chunck size of the source such as it will match the size of */
         /* a block of the overview */
-        int nFullResXChunk = (nDstBlockXSize * nSrcWidth) / nDstWidth;
-        int nFullResYChunk = (nDstBlockYSize * nSrcHeight) / nDstHeight;
+        int nFullResXChunk = 1 + (int)(nDstBlockXSize * dfXRatioDstToSrc);
+        int nFullResYChunk = 1 + (int)(nDstBlockYSize * dfYRatioDstToSrc);
+
+        int nOvrFactor = MAX( (int)(0.5 + dfXRatioDstToSrc),
+                              (int)(0.5 + dfYRatioDstToSrc) );
+        if( nOvrFactor == 0 ) nOvrFactor = 1;
+        int nFullResXChunkQueried = nFullResXChunk + 2 * nKernelRadius * nOvrFactor;
+        int nFullResYChunkQueried = nFullResYChunk + 2 * nKernelRadius * nOvrFactor;
 
         void** papaChunk = (void**) CPLMalloc(nBands * sizeof(void*));
         GByte* pabyChunkNoDataMask = NULL;
         for(iBand=0;iBand<nBands;iBand++)
         {
-            papaChunk[iBand] = VSIMalloc3(nFullResXChunk, nFullResYChunk, GDALGetDataTypeSize(eWrkDataType) / 8);
+            papaChunk[iBand] = VSIMalloc3(nFullResXChunkQueried, nFullResYChunkQueried, GDALGetDataTypeSize(eWrkDataType) / 8);
             if( papaChunk[iBand] == NULL )
             {
                 while ( --iBand >= 0)
@@ -2016,7 +2703,7 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
         }
         if (bUseNoDataMask)
         {
-            pabyChunkNoDataMask = (GByte*) VSIMalloc2(nFullResXChunk, nFullResYChunk);
+            pabyChunkNoDataMask = (GByte*) VSIMalloc2(nFullResXChunkQueried, nFullResYChunkQueried);
             if( pabyChunkNoDataMask == NULL )
             {
                 for(iBand=0;iBand<nBands;iBand++)
@@ -2033,15 +2720,33 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
             }
         }
 
-        int nChunkYOff;
+        int nDstYOff;
         /* Iterate on destination overview, block by block */
-        for( nChunkYOff = 0; nChunkYOff < nSrcHeight && eErr == CE_None; nChunkYOff += nFullResYChunk )
+        for( nDstYOff = 0; nDstYOff < nDstHeight && eErr == CE_None; nDstYOff += nDstBlockYSize )
         {
-            int nYCount;
-            if  (nChunkYOff + nFullResYChunk <= nSrcHeight)
-                nYCount = nFullResYChunk;
+            int nDstYCount;
+            if  (nDstYOff + nDstBlockYSize <= nDstHeight)
+                nDstYCount = nDstBlockYSize;
             else
-                nYCount = nSrcHeight - nChunkYOff;
+                nDstYCount = nDstHeight - nDstYOff;
+
+            int nChunkYOff = (int) (0.5 + nDstYOff * dfYRatioDstToSrc);
+            int nChunkYOff2 = (int) (0.5 + (nDstYOff + nDstYCount) * dfYRatioDstToSrc);
+            if( nChunkYOff2 > nSrcHeight || nDstYOff + nDstYCount == nDstHeight)
+                nChunkYOff2 = nSrcHeight;
+            int nYCount = nChunkYOff2 - nChunkYOff;
+            CPLAssert(nYCount <= nFullResYChunk);
+
+            int nChunkYOffQueried = nChunkYOff - nKernelRadius * nOvrFactor;
+            int nChunkYSizeQueried = nYCount + 2 * nKernelRadius * nOvrFactor;
+            if( nChunkYOffQueried < 0 )
+            {
+                nChunkYSizeQueried += nChunkYOffQueried;
+                nChunkYOffQueried = 0;
+            }
+            if( nChunkYSizeQueried + nChunkYOffQueried > nSrcHeight )
+                nChunkYSizeQueried = nSrcHeight - nChunkYOffQueried;
+            CPLAssert(nChunkYSizeQueried <= nFullResYChunkQueried);
 
             if( !pfnProgress( dfCurPixelCount / dfTotalPixelCount, 
                               NULL, pProgressData ) )
@@ -2050,14 +2755,36 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
                 eErr = CE_Failure;
             }
 
-            int nChunkXOff;
-            for( nChunkXOff = 0; nChunkXOff < nSrcWidth && eErr == CE_None; nChunkXOff += nFullResXChunk )
+            int nDstXOff;
+            /* Iterate on destination overview, block by block */
+            for( nDstXOff = 0; nDstXOff < nDstWidth && eErr == CE_None; nDstXOff += nDstBlockXSize )
             {
-                int nXCount;
-                if  (nChunkXOff + nFullResXChunk <= nSrcWidth)
-                    nXCount = nFullResXChunk;
+                int nDstXCount;
+                if  (nDstXOff + nDstBlockXSize <= nDstWidth)
+                    nDstXCount = nDstBlockXSize;
                 else
-                    nXCount = nSrcWidth - nChunkXOff;
+                    nDstXCount = nDstWidth - nDstXOff;
+
+                int nChunkXOff = (int) (0.5 + nDstXOff * dfXRatioDstToSrc);
+                int nChunkXOff2 = (int) (0.5 + (nDstXOff + nDstXCount) * dfXRatioDstToSrc);
+                if( nChunkXOff2 > nSrcWidth || nDstXOff + nDstXCount == nDstWidth)
+                    nChunkXOff2 = nSrcWidth;
+                int nXCount = nChunkXOff2 - nChunkXOff;
+                CPLAssert(nXCount <= nFullResXChunk);
+
+                int nChunkXOffQueried = nChunkXOff - nKernelRadius * nOvrFactor;
+                int nChunkXSizeQueried = nXCount + 2 * nKernelRadius * nOvrFactor;
+                if( nChunkXOffQueried < 0 )
+                {
+                    nChunkXSizeQueried += nChunkXOffQueried;
+                    nChunkXOffQueried = 0;
+                }
+                if( nChunkXSizeQueried + nChunkXOffQueried > nSrcWidth )
+                    nChunkXSizeQueried = nSrcWidth - nChunkXOffQueried;
+                CPLAssert(nChunkXSizeQueried <= nFullResXChunkQueried);
+                /*CPLDebug("GDAL", "Reading (%dx%d -> %dx%d) for output (%dx%d -> %dx%d)",
+                         nChunkXOff, nChunkYOff, nXCount, nYCount,
+                         nDstXOff, nDstYOff, nDstXCount, nDstYCount);*/
 
                 /* Read the source buffers for all the bands */
                 for(iBand=0;iBand<nBands && eErr == CE_None;iBand++)
@@ -2068,11 +2795,11 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
                     else
                         poSrcBand = papapoOverviewBands[iBand][iSrcOverview];
                     eErr = poSrcBand->RasterIO( GF_Read,
-                                                nChunkXOff, nChunkYOff,
-                                                nXCount, nYCount, 
+                                                nChunkXOffQueried, nChunkYOffQueried,
+                                                nChunkXSizeQueried, nChunkYSizeQueried, 
                                                 papaChunk[iBand],
-                                                nXCount, nYCount,
-                                                eWrkDataType, 0, 0 );
+                                                nChunkXSizeQueried, nChunkYSizeQueried,
+                                                eWrkDataType, 0, 0, NULL );
                 }
 
                 if (bUseNoDataMask && eErr == CE_None)
@@ -2083,28 +2810,31 @@ GDALRegenerateOverviewsMultiBand(int nBands, GDALRasterBand** papoSrcBands,
                     else
                         poSrcBand = papapoOverviewBands[0][iSrcOverview];
                     eErr = poSrcBand->GetMaskBand()->RasterIO( GF_Read,
-                                                               nChunkXOff, nChunkYOff,
-                                                               nXCount, nYCount, 
+                                                               nChunkXOffQueried, nChunkYOffQueried,
+                                                               nChunkXSizeQueried, nChunkYSizeQueried, 
                                                                pabyChunkNoDataMask,
-                                                               nXCount, nYCount,
-                                                               GDT_Byte, 0, 0 );
+                                                               nChunkXSizeQueried, nChunkYSizeQueried,
+                                                               GDT_Byte, 0, 0, NULL );
                 }
 
                 /* Compute the resulting overview block */
                 for(iBand=0;iBand<nBands && eErr == CE_None;iBand++)
                 {
-                    eErr = pfnDownsampleFn(nSrcWidth, nSrcHeight,
-                                                  eWrkDataType,
-                                                  papaChunk[iBand],
-                                                  pabyChunkNoDataMask,
-                                                  nChunkXOff, nXCount,
-                                                  nChunkYOff, nYCount,
-                                                  papapoOverviewBands[iBand][iOverview],
-                                                  pszResampling,
-                                                  pabHasNoData[iBand],
-                                                  pafNoDataValue[iBand],
-                                                  /*poColorTable*/ NULL,
-                                                  eDataType);
+                    eErr = pfnResampleFn(   dfXRatioDstToSrc, dfYRatioDstToSrc,
+                                            0.0, 0.0,
+                                            eWrkDataType,
+                                            papaChunk[iBand],
+                                            pabyChunkNoDataMask,
+                                            nChunkXOffQueried, nChunkXSizeQueried,
+                                            nChunkYOffQueried, nChunkYSizeQueried,
+                                            nDstXOff, nDstXOff + nDstXCount,
+                                            nDstYOff, nDstYOff + nDstYCount,
+                                            papapoOverviewBands[iBand][iOverview],
+                                            pszResampling,
+                                            pabHasNoData[iBand],
+                                            pafNoDataValue[iBand],
+                                            /*poColorTable*/ NULL,
+                                            eDataType);
                 }
             }
 
@@ -2200,7 +2930,7 @@ GDALComputeBandStats( GDALRasterBandH hSrcBand,
 
         CPLErr eErr = poSrcBand->RasterIO( GF_Read, 0, iLine, nWidth, 1,
                              pafData, nWidth, 1, eWrkType,
-                             0, 0 );
+                             0, 0, NULL );
         if ( eErr != CE_None )
         {
             CPLFree( pafData );
@@ -2351,7 +3081,7 @@ GDALOverviewMagnitudeCorrection( GDALRasterBandH hBaseBand,
 
             poOverview->RasterIO( GF_Read, 0, iLine, nWidth, 1,
                                   pafData, nWidth, 1, eWrkType,
-                                  0, 0 );
+                                  0, 0, NULL );
             
             for( iPixel = 0; iPixel < nWidth; iPixel++ )
             {
@@ -2370,7 +3100,7 @@ GDALOverviewMagnitudeCorrection( GDALRasterBandH hBaseBand,
 
             poOverview->RasterIO( GF_Write, 0, iLine, nWidth, 1,
                                   pafData, nWidth, 1, eWrkType,
-                                  0, 0 );
+                                  0, 0, NULL );
         }
 
         if( !pfnProgress( 1.0, NULL, pProgressData ) )
diff --git a/gcore/rasterio.cpp b/gcore/rasterio.cpp
index 5c42baa..ba0ffb3 100644
--- a/gcore/rasterio.cpp
+++ b/gcore/rasterio.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: rasterio.cpp 27904 2014-10-23 23:42:29Z rouault $
+ * $Id: rasterio.cpp 28620 2015-03-05 16:56:28Z rouault $
  *
  * Project:  GDAL Core
  * Purpose:  Contains default implementation of GDALRasterBand::IRasterIO()
@@ -30,6 +30,10 @@
  ****************************************************************************/
 
 #include "gdal_priv.h"
+#include "gdal_vrt.h"
+#include "vrtdataset.h"
+#include "memdataset.h"
+#include "gdalwarper.h"
 
 // Define a list of "C++" compilers that have broken template support or
 // broken scoping so we can fall back on the legacy implementation of
@@ -48,7 +52,7 @@
 #endif
 
 
-CPL_CVSID("$Id: rasterio.cpp 27904 2014-10-23 23:42:29Z rouault $");
+CPL_CVSID("$Id: rasterio.cpp 28620 2015-03-05 16:56:28Z rouault $");
 
 /************************************************************************/
 /*                             IRasterIO()                              */
@@ -62,7 +66,8 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                   int nXOff, int nYOff, int nXSize, int nYSize,
                                   void * pData, int nBufXSize, int nBufYSize,
                                   GDALDataType eBufType,
-                                  int nPixelSpace, int nLineSpace )
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg )
 
 {
     int         nBandDataSize = GDALGetDataTypeSize( eDataType ) / 8;
@@ -93,6 +98,7 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 //        printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 1\n", 
 //                nXOff, nYOff, nXSize, nYSize, 
 //                (int) eRWFlag );
+        CPLErr eErr = CE_None;
 
         for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
         {
@@ -110,6 +116,21 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                     && nYOff <= nLBlockY * nBlockYSize
                     && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize;
 
+                /* Is this a partial tile at right and/or bottom edges of */
+                /* the raster, and that is going to be completely written ? */
+                /* If so, don't load it from storage, but zeroized it so that */
+                /* the content outsize of the validity area is initialized */
+                int bMemZeroBuffer = FALSE;
+                if( eRWFlag == GF_Write && !bJustInitialize &&
+                    nXOff == 0 && nXSize == nBlockXSize &&
+                    nYOff <= nLBlockY * nBlockYSize &&
+                    nYOff + nYSize == GetYSize() &&
+                    (nLBlockY+1) * nBlockYSize > GetYSize() )
+                {
+                    bJustInitialize = TRUE;
+                    bMemZeroBuffer = TRUE;
+                }
+
                 if( poBlock )
                     poBlock->DropLock();
 
@@ -119,7 +140,8 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                     CPLError( CE_Failure, CPLE_AppDefined,
             "GetBlockRef failed at X block offset %d, "
                         "Y block offset %d", 0, nLBlockY );
-            return( CE_Failure );
+                    eErr = CE_Failure;
+                    break;
                 }
 
                 if( eRWFlag == GF_Write )
@@ -129,7 +151,13 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                 if( pabySrcBlock == NULL )
                 {
                     poBlock->DropLock();
-                    return CE_Failure;
+                    eErr = CE_Failure;
+                    break;
+                }
+                if( bMemZeroBuffer )
+                {
+                    memset(pabySrcBlock, 0,
+                           nBandDataSize * nBlockXSize * nBlockYSize);
                 }
             }
 
@@ -139,13 +167,13 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
             if( eDataType == eBufType )
             {
                 if( eRWFlag == GF_Read )
-                    memcpy( ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
+                    memcpy( ((GByte *) pData) + (GPtrDiff_t)iBufYOff * nLineSpace,
                             pabySrcBlock + nSrcByteOffset, 
-                            nLineSpace );
+                            (size_t)nLineSpace );
                 else
                     memcpy( pabySrcBlock + nSrcByteOffset, 
-                            ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
-                            nLineSpace );
+                            ((GByte *) pData) + (GPtrDiff_t)iBufYOff * nLineSpace,
+                            (size_t)nLineSpace );
             }
             else
             {
@@ -154,20 +182,28 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                 if( eRWFlag == GF_Read )
                     GDALCopyWords( pabySrcBlock + nSrcByteOffset,
                                    eDataType, nBandDataSize,
-                                   ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
-                                   eBufType, nPixelSpace, nBufXSize );
+                                   ((GByte *) pData) + (GPtrDiff_t)iBufYOff * nLineSpace,
+                                   eBufType, (int)nPixelSpace, nBufXSize );
                 else
-                    GDALCopyWords( ((GByte *) pData) + (size_t)iBufYOff * nLineSpace,
-                                   eBufType, nPixelSpace,
+                    GDALCopyWords( ((GByte *) pData) + (GPtrDiff_t)iBufYOff * nLineSpace,
+                                   eBufType, (int)nPixelSpace,
                                    pabySrcBlock + nSrcByteOffset,
                                    eDataType, nBandDataSize, nBufXSize );
             }
+
+            if( psExtraArg->pfnProgress != NULL &&
+                !psExtraArg->pfnProgress(1.0 * (iBufYOff + 1) / nBufYSize, "",
+                                         psExtraArg->pProgressData) )
+            {
+                eErr = CE_Failure;
+                break;
+            }
         }
 
         if( poBlock )
             poBlock->DropLock();
 
-        return CE_None;
+        return eErr;
     }
     
 /* ==================================================================== */
@@ -178,10 +214,13 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         && GetOverviewCount() > 0 && eRWFlag == GF_Read )
     {
         int         nOverview;
+        GDALRasterIOExtraArg sExtraArg;
+    
+        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
 
         nOverview =
-            GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
-                                        nBufXSize, nBufYSize);
+            GDALBandGetBestOverviewLevel2(this, nXOff, nYOff, nXSize, nYSize,
+                                          nBufXSize, nBufYSize, &sExtraArg);
         if (nOverview >= 0)
         {
             GDALRasterBand* poOverviewBand = GetOverview(nOverview);
@@ -190,7 +229,7 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
             return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                             pData, nBufXSize, nBufYSize, eBufType,
-                                            nPixelSpace, nLineSpace );
+                                            nPixelSpace, nLineSpace, &sExtraArg );
         }
     }
     
@@ -201,7 +240,7 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         nLineSpace == nPixelSpace * nBufXSize &&
         CSLTestBoolean(CPLGetConfigOption("GDAL_NO_COSTLY_OVERVIEW", "NO")) )
     {
-        memset(pData, 0, nLineSpace * nBufYSize);
+        memset(pData, 0, (size_t)(nLineSpace * nBufYSize));
         return CE_None;
     }
 
@@ -232,10 +271,11 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
         int nYInc = 0;
         for( iBufYOff = 0, iSrcY = nYOff; iBufYOff < nBufYSize; iBufYOff+=nYInc, iSrcY+=nYInc )
         {
-            size_t  iBufOffset, iSrcOffset;
+            GPtrDiff_t  iBufOffset;
+            GPtrDiff_t  iSrcOffset;
             int     nXSpan;
 
-            iBufOffset = (size_t)iBufYOff * nLineSpace;
+            iBufOffset = (GPtrDiff_t)iBufYOff * (GPtrDiff_t)nLineSpace;
             nLBlockY = iSrcY / nBlockYSize;
             nLBlockX = nLBlockXStart;
             iSrcX = nXOff;
@@ -245,7 +285,7 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
                 nXSpan = (nLBlockX + 1) * nBlockXSize;
                 nXSpan = ( ( nXSpan < nXSpanEnd )?nXSpan:nXSpanEnd ) - iSrcX;
-                nXSpanSize = nXSpan * nPixelSpace;
+                nXSpanSize = nXSpan * (int)nPixelSpace;
 
                 int bJustInitialize = 
                     eRWFlag == GF_Write
@@ -254,6 +294,22 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                     && nXOff <= nLBlockX * nBlockXSize
                     && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
 
+                /* Is this a partial tile at right and/or bottom edges of */
+                /* the raster, and that is going to be completely written ? */
+                /* If so, don't load it from storage, but zeroized it so that */
+                /* the content outsize of the validity area is initialized */
+                int bMemZeroBuffer = FALSE;
+                if( eRWFlag == GF_Write && !bJustInitialize &&
+                    nXOff <= nLBlockX * nBlockXSize &&
+                    nYOff <= nLBlockY * nBlockYSize &&
+                    (nXOff + nXSize >= (nLBlockX+1) * nBlockXSize ||
+                     (nXOff + nXSize == GetXSize() && (nLBlockX+1) * nBlockXSize > GetXSize())) &&
+                    (nYOff + nYSize >= (nLBlockY+1) * nBlockYSize ||
+                     (nYOff + nYSize == GetYSize() && (nLBlockY+1) * nBlockYSize > GetYSize())) )
+                {
+                    bJustInitialize = TRUE;
+                    bMemZeroBuffer = TRUE;
+                }
 //                printf( "bJustInitialize = %d (%d,%d,%d,%d)\n", 
 //                        bJustInitialize,
 //                        nYOff, nYSize, 
@@ -282,12 +338,16 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                     poBlock->DropLock();
                     return CE_Failure;
                 }
-
+                if( bMemZeroBuffer )
+                {
+                    memset(pabySrcBlock, 0,
+                           nBandDataSize * nBlockXSize * nBlockYSize);
+                }
 /* -------------------------------------------------------------------- */
 /*      Copy over this chunk of data.                                   */
 /* -------------------------------------------------------------------- */
-                iSrcOffset = ((size_t)iSrcX - (size_t)nLBlockX*nBlockXSize
-                    + ((size_t)(iSrcY) - (size_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
+                iSrcOffset = ((GPtrDiff_t)iSrcX - (GPtrDiff_t)nLBlockX*nBlockXSize
+                    + ((GPtrDiff_t)(iSrcY) - (GPtrDiff_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
                 /* Fill up as many rows as possible for the loaded block */
                 int kmax = MIN(nBlockYSize - (iSrcY % nBlockYSize), nBufYSize - iBufYOff);
                 for(int k=0; k<kmax;k++)
@@ -296,11 +356,11 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                         && nPixelSpace == nBufDataSize )
                     {
                         if( eRWFlag == GF_Read )
-                            memcpy( ((GByte *) pData) + iBufOffset + (size_t)k * nLineSpace,
+                            memcpy( ((GByte *) pData) + iBufOffset + (GPtrDiff_t)k * nLineSpace,
                                     pabySrcBlock + iSrcOffset, nXSpanSize );
                         else
                             memcpy( pabySrcBlock + iSrcOffset, 
-                                    ((GByte *) pData) + iBufOffset + (size_t)k * nLineSpace, nXSpanSize );
+                                    ((GByte *) pData) + iBufOffset + (GPtrDiff_t)k * nLineSpace, nXSpanSize );
                     }
                     else
                     {
@@ -309,11 +369,11 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                         if( eRWFlag == GF_Read )
                             GDALCopyWords( pabySrcBlock + iSrcOffset,
                                         eDataType, nBandDataSize,
-                                        ((GByte *) pData) + iBufOffset + (size_t)k * nLineSpace,
-                                        eBufType, nPixelSpace, nXSpan );
+                                        ((GByte *) pData) + iBufOffset + (GPtrDiff_t)k * nLineSpace,
+                                        eBufType, (int)nPixelSpace, nXSpan );
                         else
-                            GDALCopyWords( ((GByte *) pData) + iBufOffset + (size_t)k * nLineSpace,
-                                        eBufType, nPixelSpace,
+                            GDALCopyWords( ((GByte *) pData) + iBufOffset + (GPtrDiff_t)k * nLineSpace,
+                                        eBufType, (int)nPixelSpace,
                                         pabySrcBlock + iSrcOffset,
                                         eDataType, nBandDataSize, nXSpan );
                     }
@@ -331,6 +391,13 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
             /* Compute the increment to go on a block boundary */
             nYInc = nBlockYSize - (iSrcY % nBlockYSize);
+
+            if( psExtraArg->pfnProgress != NULL &&
+                !psExtraArg->pfnProgress(1.0 * MIN(nBufYSize, iBufYOff + nYInc) / nBufYSize, "",
+                                         psExtraArg->pProgressData) )
+            {
+                return CE_Failure;
+            }
         }
 
         return CE_None;
@@ -341,13 +408,32 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 /*      request.  This is the most general implementation.              */
 /* ==================================================================== */
 
+    double dfXOff, dfYOff, dfXSize, dfYSize;
+    if( psExtraArg->bFloatingPointWindowValidity )
+    {
+        dfXOff = psExtraArg->dfXOff;
+        dfYOff = psExtraArg->dfYOff;
+        dfXSize = psExtraArg->dfXSize;
+        dfYSize = psExtraArg->dfYSize;
+        CPLAssert(dfXOff - nXOff < 1.0);
+        CPLAssert(dfYOff - nYOff < 1.0);
+        CPLAssert(nXSize - dfXSize < 1.0);
+        CPLAssert(nYSize - dfYSize < 1.0);
+    }
+    else
+    {
+        dfXOff = nXOff;
+        dfYOff = nYOff;
+        dfXSize = nXSize;
+        dfYSize = nYSize;
+    }
 /* -------------------------------------------------------------------- */
 /*      Compute stepping increment.                                     */
 /* -------------------------------------------------------------------- */
     double dfSrcXInc, dfSrcYInc;
-    dfSrcXInc = nXSize / (double) nBufXSize;
-    dfSrcYInc = nYSize / (double) nBufYSize;
-
+    dfSrcXInc = dfXSize / (double) nBufXSize;
+    dfSrcYInc = dfYSize / (double) nBufYSize;
+    CPLErr eErr = CE_None;
 
 //    printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 3\n", 
 //            nXOff, nYOff, nXSize, nYSize, 
@@ -363,13 +449,18 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 
         for( iDstY = nYOff; iDstY < nYOff + nYSize; iDstY ++)
         {
-            size_t   iBufOffset, iDstOffset;
+            GPtrDiff_t iBufOffset, iDstOffset;
             iBufYOff = (int)((iDstY - nYOff) / dfSrcYInc);
 
             for( iDstX = nXOff; iDstX < nXOff + nXSize; iDstX ++)
             {
                 iBufXOff = (int)((iDstX - nXOff) / dfSrcXInc);
-                iBufOffset = (size_t)iBufYOff * nLineSpace + iBufXOff * nPixelSpace;
+                iBufOffset = (GPtrDiff_t)iBufYOff * (GPtrDiff_t)nLineSpace + iBufXOff * (GPtrDiff_t)nPixelSpace;
+
+                // FIXME: this code likely doesn't work if the dirty block gets flushed
+                // to disk before being completely written.
+                // In the meantime, bJustInitalize should probably be set to FALSE
+                // even if it is not ideal performance wise, and for lossy compression
 
     /* -------------------------------------------------------------------- */
     /*      Ensure we have the appropriate block loaded.                    */
@@ -387,7 +478,18 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                         && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
                         && nXOff <= nLBlockX * nBlockXSize
                         && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
-
+                    /*int bMemZeroBuffer = FALSE;
+                    if( !bJustInitialize &&
+                        nXOff <= nLBlockX * nBlockXSize &&
+                        nYOff <= nLBlockY * nBlockYSize &&
+                        (nXOff + nXSize >= (nLBlockX+1) * nBlockXSize ||
+                         (nXOff + nXSize == GetXSize() && (nLBlockX+1) * nBlockXSize > GetXSize())) &&
+                        (nYOff + nYSize >= (nLBlockY+1) * nBlockYSize ||
+                         (nYOff + nYSize == GetYSize() && (nLBlockY+1) * nBlockYSize > GetYSize())) )
+                    {
+                        bJustInitialize = TRUE;
+                        bMemZeroBuffer = TRUE;
+                    }*/
                     if( poBlock != NULL )
                         poBlock->DropLock();
 
@@ -406,13 +508,18 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                         poBlock->DropLock();
                         return CE_Failure;
                     }
+                    /*if( bMemZeroBuffer )
+                    {
+                        memset(pabyDstBlock, 0,
+                            nBandDataSize * nBlockXSize * nBlockYSize);
+                    }*/
                 }
 
     /* -------------------------------------------------------------------- */
     /*      Copy over this pixel of data.                                   */
     /* -------------------------------------------------------------------- */
-                iDstOffset = ((size_t)iDstX - (size_t)nLBlockX*nBlockXSize
-                    + ((size_t)iDstY - (size_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
+                iDstOffset = ((GPtrDiff_t)iDstX - (GPtrDiff_t)nLBlockX*nBlockXSize
+                    + ((GPtrDiff_t)iDstY - (GPtrDiff_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
 
                 if( eDataType == eBufType )
                 {
@@ -429,10 +536,48 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                 1 );
                 }
             }
+
+            if( psExtraArg->pfnProgress != NULL &&
+                !psExtraArg->pfnProgress(1.0 * (iDstY - nYOff + 1) / nYSize, "",
+                                         psExtraArg->pProgressData) )
+            {
+                eErr = CE_Failure;
+                break;
+            }
         }
     }
     else
     {
+        if( psExtraArg->eResampleAlg != GRIORA_NearestNeighbour )
+        {
+            if( (psExtraArg->eResampleAlg == GRIORA_Cubic ||
+                 psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
+                 psExtraArg->eResampleAlg == GRIORA_Bilinear ||
+                 psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
+                GetColorTable() != NULL )
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                         "Resampling method not supported on paletted band. "
+                         "Falling back to nearest neighbour");
+            }
+            else if( psExtraArg->eResampleAlg == GRIORA_Gauss &&
+                     GDALDataTypeIsComplex( eDataType ) )
+            {
+                CPLError(CE_Warning, CPLE_NotSupported,
+                         "Resampling method not supported on complex data type band. "
+                         "Falling back to nearest neighbour");
+            }
+            else
+            {
+                return RasterIOResampled( eRWFlag,
+                                          nXOff, nYOff, nXSize, nYSize,
+                                          pData, nBufXSize, nBufYSize,
+                                          eBufType,
+                                          nPixelSpace, nLineSpace,
+                                          psExtraArg );
+            }
+        }
+
         double      dfSrcX, dfSrcY;
         int         nLimitBlockY = 0;
         int         bByteCopy = ( eDataType == eBufType && nBandDataSize == 1); 
@@ -444,13 +589,13 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
 /* -------------------------------------------------------------------- */
         for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
         {
-            size_t   iBufOffset, iSrcOffset;
+            GPtrDiff_t iBufOffset, iSrcOffset;
 
-            dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
-            dfSrcX = 0.5 * dfSrcXInc + nXOff;
+            dfSrcY = (iBufYOff+0.5) * dfSrcYInc + dfYOff;
+            dfSrcX = 0.5 * dfSrcXInc + dfXOff;
             iSrcY = (int) dfSrcY;
 
-            iBufOffset = (size_t)iBufYOff * nLineSpace;
+            iBufOffset = (GPtrDiff_t)iBufYOff * (GPtrDiff_t)nLineSpace;
 
             if( iSrcY >= nLimitBlockY )
             {
@@ -461,7 +606,7 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
             else if( (int)dfSrcX < nStartBlockX )
                 nStartBlockX = -nBlockXSize; /* make sure a new block is loaded */
 
-            size_t iSrcOffsetCst = (iSrcY - nLBlockY*nBlockYSize) * (size_t)nBlockXSize;
+            GPtrDiff_t iSrcOffsetCst = (iSrcY - nLBlockY*nBlockYSize) * (GPtrDiff_t)nBlockXSize;
 
             for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++, dfSrcX += dfSrcXInc )
             {
@@ -484,21 +629,22 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                                  FALSE );
                     if( poBlock == NULL )
                     {
-                        return( CE_Failure );
+                        eErr = CE_Failure;
+                        break;
                     }
 
                     pabySrcBlock = (GByte *) poBlock->GetDataRef();
                     if( pabySrcBlock == NULL )
                     {
-                        poBlock->DropLock();
-                        return CE_Failure;
+                        eErr = CE_Failure;
+                        break;
                     }
                 }
 
     /* -------------------------------------------------------------------- */
     /*      Copy over this pixel of data.                                   */
     /* -------------------------------------------------------------------- */
-                iSrcOffset = ((size_t)nDiffX + iSrcOffsetCst)*nBandDataSize;
+                iSrcOffset = ((GPtrDiff_t)nDiffX + iSrcOffsetCst)*nBandDataSize;
 
                 if( bByteCopy )
                 {
@@ -518,7 +664,17 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
                                 1 );
                 }
 
-                iBufOffset += nPixelSpace;
+                iBufOffset += (int)nPixelSpace;
+            }
+            if( eErr == CE_Failure )
+                break;
+
+            if( psExtraArg->pfnProgress != NULL &&
+                !psExtraArg->pfnProgress(1.0 * (iBufYOff + 1) / nBufYSize, "",
+                                         psExtraArg->pProgressData) )
+            {
+                eErr = CE_Failure;
+                break;
             }
         }
     }
@@ -526,7 +682,421 @@ CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     if( poBlock != NULL )
         poBlock->DropLock();
 
-    return( CE_None );
+    return( eErr );
+}
+
+/************************************************************************/
+/*                         GDALRasterIOTransformer()                    */
+/************************************************************************/
+
+typedef struct
+{
+    double dfXOff, dfYOff;
+    double dfXRatioDstToSrc, dfYRatioDstToSrc;
+} GDALRasterIOTransformerStruct;
+
+static int GDALRasterIOTransformer( void *pTransformerArg,
+                                    CPL_UNUSED int bDstToSrc, int nPointCount,
+                                    double *x, double *y, CPL_UNUSED double *z,
+                                    int *panSuccess )
+{
+    CPLAssert(bDstToSrc);
+    GDALRasterIOTransformerStruct* psParams = (GDALRasterIOTransformerStruct*) pTransformerArg;
+    for(int i = 0; i < nPointCount; i++)
+    {
+        x[i] = x[i] * psParams->dfXRatioDstToSrc + psParams->dfXOff;
+        y[i] = y[i] * psParams->dfYRatioDstToSrc + psParams->dfYOff;
+        panSuccess[i] = TRUE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          RasterIOResampled()                         */
+/************************************************************************/
+
+CPLErr GDALRasterBand::RasterIOResampled( CPL_UNUSED GDALRWFlag eRWFlag,
+                                  int nXOff, int nYOff, int nXSize, int nYSize,
+                                  void * pData, int nBufXSize, int nBufYSize,
+                                  GDALDataType eBufType,
+                                  GSpacing nPixelSpace, GSpacing nLineSpace,
+                                  GDALRasterIOExtraArg* psExtraArg )
+{
+    CPLErr eErr = CE_None;
+
+    // Determine if we use warping resampling or overview resampling
+    int bUseWarp;
+    if( !GDALDataTypeIsComplex( eDataType ) )
+        bUseWarp = FALSE;
+    else
+        bUseWarp = TRUE;
+
+    double dfXOff, dfYOff, dfXSize, dfYSize;
+    if( psExtraArg->bFloatingPointWindowValidity )
+    {
+        dfXOff = psExtraArg->dfXOff;
+        dfYOff = psExtraArg->dfYOff;
+        dfXSize = psExtraArg->dfXSize;
+        dfYSize = psExtraArg->dfYSize;
+        CPLAssert(dfXOff - nXOff < 1.0);
+        CPLAssert(dfYOff - nYOff < 1.0);
+        CPLAssert(nXSize - dfXSize < 1.0);
+        CPLAssert(nYSize - dfYSize < 1.0);
+    }
+    else
+    {
+        dfXOff = nXOff;
+        dfYOff = nYOff;
+        dfXSize = nXSize;
+        dfYSize = nYSize;
+    }
+
+    double dfXRatioDstToSrc = dfXSize / nBufXSize;
+    double dfYRatioDstToSrc = dfYSize / nBufYSize;
+
+    /* Determine the coordinates in the "virtual" output raster to see */
+    /* if there are not integers, in which case we will use them as a shift */
+    /* so that subwindow extracts give the exact same results as entire raster */
+    /* scaling */
+    double dfDestXOff = dfXOff / dfXRatioDstToSrc;
+    int bHasXOffVirtual = FALSE;
+    int nDestXOffVirtual = 0;
+    if( fabs(dfDestXOff - (int)(dfDestXOff + 0.5)) < 1e-8 )
+    {
+        bHasXOffVirtual = TRUE;
+        dfXOff = nXOff;
+        nDestXOffVirtual = (int)(dfDestXOff + 0.5);
+    }
+
+    double dfDestYOff = dfYOff / dfYRatioDstToSrc;
+    int bHasYOffVirtual = FALSE;
+    int nDestYOffVirtual = 0;
+    if( fabs(dfDestYOff - (int)(dfDestYOff + 0.5)) < 1e-8 )
+    {
+        bHasYOffVirtual = TRUE;
+        dfYOff = nYOff;
+        nDestYOffVirtual = (int)(dfDestYOff + 0.5);
+    }
+
+    /* Create a MEM dataset that wraps the output buffer */
+    GDALDataset* poMEMDS = MEMDataset::Create("", nDestXOffVirtual + nBufXSize,
+                                              nDestYOffVirtual + nBufYSize, 0,
+                                              eBufType, NULL);
+    char szBuffer[64];
+    int nRet;
+
+    nRet = CPLPrintPointer(szBuffer, (GByte*)pData - nPixelSpace * nDestXOffVirtual
+                            - nLineSpace * nDestYOffVirtual, sizeof(szBuffer));
+    szBuffer[nRet] = 0;
+    char** papszOptions = CSLSetNameValue(NULL, "DATAPOINTER", szBuffer);
+
+    papszOptions = CSLSetNameValue(papszOptions, "PIXELOFFSET",
+                                CPLSPrintf(CPL_FRMT_GIB, (GIntBig)nPixelSpace));
+
+    papszOptions = CSLSetNameValue(papszOptions, "LINEOFFSET",
+                                CPLSPrintf(CPL_FRMT_GIB, (GIntBig)nLineSpace));
+
+    poMEMDS->AddBand(eBufType, papszOptions);
+    CSLDestroy(papszOptions);
+    GDALRasterBandH hMEMBand = (GDALRasterBandH)poMEMDS->GetRasterBand(1);
+
+    /* Do the resampling */
+    if( bUseWarp )
+    {
+        VRTDatasetH hVRTDS = NULL;
+        GDALRasterBandH hVRTBand = NULL;
+        if( GetDataset() == NULL )
+        {
+            /* Create VRT dataset that wraps the whole dataset */
+            hVRTDS = VRTCreate(nRasterXSize, nRasterYSize);
+            VRTAddBand( hVRTDS, eDataType, NULL );
+            hVRTBand = GDALGetRasterBand(hVRTDS, 1);
+            VRTAddSimpleSource( (VRTSourcedRasterBandH)hVRTBand,
+                                (GDALRasterBandH)this, 
+                                0, 0, 
+                                nRasterXSize, nRasterYSize,
+                                0, 0,
+                                nRasterXSize, nRasterYSize,
+                                NULL, VRT_NODATA_UNSET );
+
+            /* Add a mask band if needed */
+            if( GetMaskFlags() != GMF_ALL_VALID )
+            {
+                ((GDALDataset*)hVRTDS)->CreateMaskBand(0);
+                VRTSourcedRasterBand* poVRTMaskBand =
+                    (VRTSourcedRasterBand*)(((GDALRasterBand*)hVRTBand)->GetMaskBand());
+                poVRTMaskBand->
+                    AddMaskBandSource( this, 
+                                    0, 0, 
+                                    nRasterXSize, nRasterYSize,
+                                    0, 0,
+                                    nRasterXSize, nRasterYSize);
+            }
+        }
+
+        GDALWarpOptions* psWarpOptions = GDALCreateWarpOptions();
+        psWarpOptions->eResampleAlg = (GDALResampleAlg)psExtraArg->eResampleAlg;
+        psWarpOptions->hSrcDS = (GDALDatasetH) (hVRTDS ? hVRTDS : GetDataset());
+        psWarpOptions->hDstDS = (GDALDatasetH) poMEMDS;
+        psWarpOptions->nBandCount = 1;
+        int nSrcBandNumber = (hVRTDS ? 1 : nBand);
+        int nDstBandNumber = 1;
+        psWarpOptions->panSrcBands = &nSrcBandNumber;
+        psWarpOptions->panDstBands = &nDstBandNumber;
+        psWarpOptions->pfnProgress = psExtraArg->pfnProgress ?
+                    psExtraArg->pfnProgress : GDALDummyProgress;
+        psWarpOptions->pProgressArg = psExtraArg->pProgressData;
+        psWarpOptions->pfnTransformer = GDALRasterIOTransformer;
+        GDALRasterIOTransformerStruct sTransformer;
+        sTransformer.dfXOff = (bHasXOffVirtual) ? 0 : dfXOff;
+        sTransformer.dfYOff = (bHasYOffVirtual) ? 0 : dfYOff;
+        sTransformer.dfXRatioDstToSrc = dfXRatioDstToSrc;
+        sTransformer.dfYRatioDstToSrc = dfYRatioDstToSrc;
+        psWarpOptions->pTransformerArg = &sTransformer;
+
+        GDALWarpOperationH hWarpOperation = GDALCreateWarpOperation(psWarpOptions);
+        eErr = GDALChunkAndWarpImage( hWarpOperation,
+                                      nDestXOffVirtual, nDestYOffVirtual,
+                                      nBufXSize, nBufYSize );
+        GDALDestroyWarpOperation( hWarpOperation );
+
+        psWarpOptions->panSrcBands = NULL;
+        psWarpOptions->panDstBands = NULL;
+        GDALDestroyWarpOptions( psWarpOptions );
+
+        if( hVRTDS )
+            GDALClose(hVRTDS);
+    }
+    else
+    {
+        const char* pszResampling =
+            (psExtraArg->eResampleAlg == GRIORA_Bilinear) ? "BILINEAR" :
+            (psExtraArg->eResampleAlg == GRIORA_Cubic) ? "CUBIC" :
+            (psExtraArg->eResampleAlg == GRIORA_CubicSpline) ? "CUBICSPLINE" :
+            (psExtraArg->eResampleAlg == GRIORA_Lanczos) ? "LANCZOS" :
+            (psExtraArg->eResampleAlg == GRIORA_Average) ? "AVERAGE" :
+            (psExtraArg->eResampleAlg == GRIORA_Mode) ? "MODE" :
+            (psExtraArg->eResampleAlg == GRIORA_Gauss) ? "GAUSS" : "UNKNOWN";
+
+        int nKernelRadius;
+        GDALResampleFunction pfnResampleFunc =
+                        GDALGetResampleFunction(pszResampling, &nKernelRadius);
+        CPLAssert(pfnResampleFunc);
+        GDALDataType eWrkDataType = 
+            GDALGetOvrWorkDataType(pszResampling, eDataType);
+        int bHasNoData = FALSE;
+        float fNoDataValue = (float) GetNoDataValue(&bHasNoData);
+        if( !bHasNoData )
+            fNoDataValue = 0.0f;
+
+        int nDstBlockXSize = nBufXSize;
+        int nDstBlockYSize = nBufYSize;
+        int nFullResXChunk, nFullResYChunk;
+        while(TRUE)
+        {
+            nFullResXChunk = 3 + (int)(nDstBlockXSize * dfXRatioDstToSrc);
+            nFullResYChunk = 3 + (int)(nDstBlockYSize * dfYRatioDstToSrc);
+            if( (nDstBlockXSize == 1 && nDstBlockYSize == 1) ||
+                ((GIntBig)nFullResXChunk * nFullResYChunk <= 1024 * 1024) )
+                break;
+            /* When operating on the full width of a raster whose block width is */
+            /* the raster width, prefer doing chunks in height */
+            if( nFullResXChunk >= nXSize && nXSize == nBlockXSize && nDstBlockYSize > 1 )
+                nDstBlockYSize /= 2;
+            /* Otherwise cut the maximal dimension */
+            else if( nDstBlockXSize > 1 && nFullResXChunk > nFullResYChunk )
+                nDstBlockXSize /= 2;
+            else
+                nDstBlockYSize /= 2;
+        }
+
+        int nOvrFactor = MAX( (int)(0.5 + dfXRatioDstToSrc),
+                                (int)(0.5 + dfYRatioDstToSrc) );
+        if( nOvrFactor == 0 ) nOvrFactor = 1;
+        int nFullResXSizeQueried = nFullResXChunk + 2 * nKernelRadius * nOvrFactor;
+        int nFullResYSizeQueried = nFullResYChunk + 2 * nKernelRadius * nOvrFactor;
+
+        void * pChunk = 
+            VSIMalloc3((GDALGetDataTypeSize(eWrkDataType)/8),
+                        nFullResXSizeQueried, nFullResYSizeQueried );
+        GByte * pabyChunkNoDataMask = NULL;
+
+        GDALRasterBand* poMaskBand = NULL;
+        int nMaskFlags = 0;
+        int bUseNoDataMask = FALSE;
+
+        poMaskBand = GetMaskBand();
+        nMaskFlags = GetMaskFlags();
+
+        bUseNoDataMask = ((nMaskFlags & GMF_ALL_VALID) == 0);
+        if (bUseNoDataMask)
+        {
+            pabyChunkNoDataMask = (GByte *) 
+                (GByte*) VSIMalloc2( nFullResXSizeQueried, nFullResYSizeQueried );
+        }
+        if( pChunk == NULL || (bUseNoDataMask && pabyChunkNoDataMask == NULL) )
+        {
+            GDALClose(poMEMDS);
+            CPLFree(pChunk);
+            CPLFree(pabyChunkNoDataMask);
+            CPLError( CE_Failure, CPLE_OutOfMemory,
+                      "Out of memory in RasterIO()." );
+            return CE_Failure;
+        }
+
+        int nTotalBlocks = ((nBufXSize + nDstBlockXSize - 1) / nDstBlockXSize) *
+                           ((nBufYSize + nDstBlockYSize - 1) / nDstBlockYSize);
+        int nBlocksDone = 0;
+
+        int nDstYOff;
+        for( nDstYOff = 0; nDstYOff < nBufYSize && eErr == CE_None;
+            nDstYOff += nDstBlockYSize )
+        {
+            int nDstYCount;
+            if  (nDstYOff + nDstBlockYSize <= nBufYSize)
+                nDstYCount = nDstBlockYSize;
+            else
+                nDstYCount = nBufYSize - nDstYOff;
+
+            int nChunkYOff = nYOff + (int) (nDstYOff * dfYRatioDstToSrc);
+            int nChunkYOff2 = nYOff + 1 + (int) ceil((nDstYOff + nDstYCount) * dfYRatioDstToSrc);
+            if( nChunkYOff2 > nRasterYSize )
+                nChunkYOff2 = nRasterYSize;
+            int nYCount = nChunkYOff2 - nChunkYOff;
+            CPLAssert(nYCount <= nFullResYChunk);
+
+            int nChunkYOffQueried = nChunkYOff - nKernelRadius * nOvrFactor;
+            int nChunkYSizeQueried = nYCount + 2 * nKernelRadius * nOvrFactor;
+            if( nChunkYOffQueried < 0 )
+            {
+                nChunkYSizeQueried += nChunkYOffQueried;
+                nChunkYOffQueried = 0;
+            }
+            if( nChunkYSizeQueried + nChunkYOffQueried > nRasterYSize )
+                nChunkYSizeQueried = nRasterYSize - nChunkYOffQueried;
+            CPLAssert(nChunkYSizeQueried <= nFullResYSizeQueried);
+
+            int nDstXOff;
+            for( nDstXOff = 0; nDstXOff < nBufXSize && eErr == CE_None;
+                nDstXOff += nDstBlockXSize )
+            {
+                int nDstXCount;
+                if  (nDstXOff + nDstBlockXSize <= nBufXSize)
+                    nDstXCount = nDstBlockXSize;
+                else
+                    nDstXCount = nBufXSize - nDstXOff;
+
+                int nChunkXOff = nXOff + (int) (nDstXOff * dfXRatioDstToSrc);
+                int nChunkXOff2 = nXOff + 1 + (int) ceil((nDstXOff + nDstXCount) * dfXRatioDstToSrc);
+                if( nChunkXOff2 > nRasterXSize )
+                    nChunkXOff2 = nRasterXSize;
+                int nXCount = nChunkXOff2 - nChunkXOff;
+                CPLAssert(nXCount <= nFullResXChunk);
+
+                int nChunkXOffQueried = nChunkXOff - nKernelRadius * nOvrFactor;
+                int nChunkXSizeQueried = nXCount + 2 * nKernelRadius * nOvrFactor;
+                if( nChunkXOffQueried < 0 )
+                {
+                    nChunkXSizeQueried += nChunkXOffQueried;
+                    nChunkXOffQueried = 0;
+                }
+                if( nChunkXSizeQueried + nChunkXOffQueried > nRasterXSize )
+                    nChunkXSizeQueried = nRasterXSize - nChunkXOffQueried;
+                CPLAssert(nChunkXSizeQueried <= nFullResXSizeQueried);
+
+                /* Read the source buffers */
+                eErr = RasterIO( GF_Read,
+                                nChunkXOffQueried, nChunkYOffQueried,
+                                nChunkXSizeQueried, nChunkYSizeQueried, 
+                                pChunk,
+                                nChunkXSizeQueried, nChunkYSizeQueried,
+                                eWrkDataType, 0, 0, NULL );
+
+                int bSkipResample = FALSE;
+                int bNoDataMaskFullyOpaque = FALSE;
+                if (eErr == CE_None && bUseNoDataMask)
+                {
+                    eErr = poMaskBand->RasterIO( GF_Read,
+                                                 nChunkXOffQueried,
+                                                 nChunkYOffQueried,
+                                                 nChunkXSizeQueried,
+                                                 nChunkYSizeQueried, 
+                                                 pabyChunkNoDataMask,
+                                                 nChunkXSizeQueried,
+                                                 nChunkYSizeQueried,
+                                                 GDT_Byte, 0, 0, NULL );
+
+                    /* Optimizations if mask if fully opaque or transparent */
+                    int nPixels = nChunkXSizeQueried * nChunkYSizeQueried;
+                    GByte bVal = pabyChunkNoDataMask[0];
+                    int i = 1;
+                    for( ; i < nPixels; i++ )
+                    {
+                        if( pabyChunkNoDataMask[i] != bVal )
+                            break;
+                    }
+                    if( i == nPixels )
+                    {
+                        if( bVal == 0 )
+                        {
+                            for(int j=0;j<nDstYCount;j++)
+                            {
+                                GDALCopyWords(&fNoDataValue, GDT_Float32, 0,
+                                            (GByte*)pData + nLineSpace * (j + nDstYOff) +
+                                                        nDstXOff * nPixelSpace,
+                                            eBufType, (int)nPixelSpace,
+                                            nDstXCount);
+                            }
+                            bSkipResample = TRUE;
+                        }
+                        else
+                        {
+                            bNoDataMaskFullyOpaque = TRUE;
+                        }
+                    }
+                }
+
+                if( !bSkipResample && eErr == CE_None )
+                {
+                    eErr = pfnResampleFunc( dfXRatioDstToSrc,
+                                            dfYRatioDstToSrc,
+                                            dfXOff - nXOff, /* == 0 if bHasXOffVirtual */
+                                            dfYOff - nYOff, /* == 0 if bHasYOffVirtual */
+                                            eWrkDataType,
+                                            pChunk,
+                                            (bNoDataMaskFullyOpaque) ? NULL : pabyChunkNoDataMask,
+                                            nChunkXOffQueried - ((bHasXOffVirtual) ? 0 : nXOff),
+                                            nChunkXSizeQueried,
+                                            nChunkYOffQueried - ((bHasYOffVirtual) ? 0 : nYOff),
+                                            nChunkYSizeQueried,
+                                            nDstXOff + nDestXOffVirtual,
+                                            nDstXOff + nDestXOffVirtual + nDstXCount,
+                                            nDstYOff + nDestYOffVirtual,
+                                            nDstYOff + nDestYOffVirtual + nDstYCount,
+                                            (GDALRasterBand *) hMEMBand,
+                                            pszResampling,
+                                            bHasNoData, fNoDataValue,
+                                            GetColorTable(),
+                                            eDataType );
+                }
+
+                nBlocksDone ++;
+                if( eErr == CE_None && psExtraArg->pfnProgress != NULL &&
+                    !psExtraArg->pfnProgress(1.0 * nBlocksDone / nTotalBlocks, "",
+                                             psExtraArg->pProgressData) )
+                {
+                    eErr = CE_Failure;
+                }
+            }
+        }
+
+        CPLFree(pChunk);
+        CPLFree(pabyChunkNoDataMask);
+    }
+
+    GDALClose(poMEMDS);
+
+    return eErr;
 }
 
 /************************************************************************/
@@ -2110,14 +2680,24 @@ void GDALCopyBits( const GByte *pabySrcData, int nSrcOffset, int nSrcStep,
 /*                    GDALGetBestOverviewLevel()                        */
 /*                                                                      */
 /* Returns the best overview level to satisfy the query or -1 if none   */
-/* Also updates nXOff, nYOff, nXSize, nYSize when returning a valid     */
-/* overview level                                                       */
+/* Also updates nXOff, nYOff, nXSize, nYSize and psExtraArg when        */
+/* returning a valid overview level                                     */
 /************************************************************************/
 
 int GDALBandGetBestOverviewLevel(GDALRasterBand* poBand,
                                  int &nXOff, int &nYOff,
                                  int &nXSize, int &nYSize,
-                                 int nBufXSize, int nBufYSize)
+                                 int nBufXSize, int nBufYSize )
+{
+    return GDALBandGetBestOverviewLevel2(poBand, nXOff, nYOff, nXSize, nYSize,
+                                        nBufXSize, nBufYSize, NULL);
+}
+
+int GDALBandGetBestOverviewLevel2(GDALRasterBand* poBand,
+                                  int &nXOff, int &nYOff,
+                                  int &nXSize, int &nYSize,
+                                  int nBufXSize, int nBufYSize,
+                                  GDALRasterIOExtraArg* psExtraArg )
 {
     double dfDesiredResolution;
 /* -------------------------------------------------------------------- */
@@ -2208,6 +2788,14 @@ int GDALBandGetBestOverviewLevel(GDALRasterBand* poBand,
     nXSize = nOXSize;
     nYSize = nOYSize;
     
+    if( psExtraArg && psExtraArg->bFloatingPointWindowValidity )
+    {
+        psExtraArg->dfXOff /= dfXRes;
+        psExtraArg->dfXSize /= dfXRes;
+        psExtraArg->dfYOff /= dfYRes;
+        psExtraArg->dfYSize /= dfYRes;
+    }
+    
     return nBestOverviewLevel;
 }
 
@@ -2225,15 +2813,19 @@ CPLErr GDALRasterBand::OverviewRasterIO( GDALRWFlag eRWFlag,
                                 int nXOff, int nYOff, int nXSize, int nYSize,
                                 void * pData, int nBufXSize, int nBufYSize,
                                 GDALDataType eBufType,
-                                int nPixelSpace, int nLineSpace )
+                                GSpacing nPixelSpace, GSpacing nLineSpace,
+                                GDALRasterIOExtraArg* psExtraArg )
 
 
 {
     int         nOverview;
+    GDALRasterIOExtraArg sExtraArg;
+    
+    GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
 
     nOverview =
-        GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
-                                     nBufXSize, nBufYSize);
+        GDALBandGetBestOverviewLevel2(this, nXOff, nYOff, nXSize, nYSize,
+                                      nBufXSize, nBufYSize, &sExtraArg);
     if (nOverview < 0)
         return CE_Failure;
         
@@ -2246,7 +2838,7 @@ CPLErr GDALRasterBand::OverviewRasterIO( GDALRWFlag eRWFlag,
 
     return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
                                      pData, nBufXSize, nBufYSize, eBufType,
-                                     nPixelSpace, nLineSpace );
+                                     nPixelSpace, nLineSpace, &sExtraArg );
 }
 
 /************************************************************************/
@@ -2325,9 +2917,9 @@ int GDALDatasetGetBestOverviewLevel(GDALDataset* poDS,
         }
     }
  
-    return GDALBandGetBestOverviewLevel(poFirstBand,
+    return GDALBandGetBestOverviewLevel2(poFirstBand,
                                         nXOff, nYOff, nXSize, nYSize,
-                                        nBufXSize, nBufYSize);
+                                        nBufXSize, nBufYSize, NULL);
 }
 
 /************************************************************************/
@@ -2363,7 +2955,9 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                                  void * pData, int nBufXSize, int nBufYSize,
                                  GDALDataType eBufType,
                                  int nBandCount, int *panBandMap,
-                                 int nPixelSpace, int nLineSpace,int nBandSpace)
+                                 GSpacing nPixelSpace, GSpacing nLineSpace,
+                                 GSpacing nBandSpace,
+                                 GDALRasterIOExtraArg* psExtraArg )
     
 {
     GByte      **papabySrcBlock = NULL;
@@ -2405,7 +2999,7 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                                                eBufType, 
                                                nBandCount, panBandMap,
                                                nPixelSpace, nLineSpace, 
-                                               nBandSpace );
+                                               nBandSpace, psExtraArg );
             }
 
             if( eDataType != poBand->GetRasterDataType() 
@@ -2420,7 +3014,7 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                                                eBufType, 
                                                nBandCount, panBandMap,
                                                nPixelSpace, nLineSpace, 
-                                               nBandSpace );
+                                               nBandSpace, psExtraArg );
             }
         }
     }
@@ -2431,8 +3025,12 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
 /*      IRasterIO(), but ensuring that all bands of one block are       */
 /*      called before proceeding to the next.                           */
 /* ==================================================================== */
+
     if( nXSize == nBufXSize && nYSize == nBufYSize )    
     {
+        GDALRasterIOExtraArg sDummyExtraArg;
+        INIT_RASTERIO_EXTRA_ARG(sDummyExtraArg);
+
         int nChunkYSize, nChunkXSize, nChunkXOff, nChunkYOff;
 
         for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff += nChunkYSize )
@@ -2459,7 +3057,7 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
 
                 pabyChunkData = ((GByte *) pData) 
                     + iBufXOff * nPixelSpace 
-                    + iBufYOff * nLineSpace;
+                    + (GPtrDiff_t)iBufYOff * nLineSpace;
 
                 for( iBand = 0; iBand < nBandCount; iBand++ )
                 {
@@ -2469,13 +3067,19 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                         poBand->GDALRasterBand::IRasterIO( 
                             eRWFlag, nChunkXOff, nChunkYOff, 
                             nChunkXSize, nChunkYSize, 
-                            pabyChunkData + iBand * nBandSpace, 
+                            pabyChunkData + (GPtrDiff_t)iBand * nBandSpace, 
                             nChunkXSize, nChunkYSize, eBufType, 
-                            nPixelSpace, nLineSpace );
+                            nPixelSpace, nLineSpace, &sDummyExtraArg );
                     if( eErr != CE_None )
                         return eErr;
                 }
             }
+
+            if( psExtraArg->pfnProgress != NULL &&
+                !psExtraArg->pfnProgress(1.0 * MAX(nBufYSize,iBufYOff + nChunkYSize) / nBufYSize, "", psExtraArg->pProgressData) )
+            {
+                return CE_Failure;
+            }
         }
 
         return CE_None;
@@ -2491,7 +3095,20 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                                        eBufType, 
                                        nBandCount, panBandMap,
                                        nPixelSpace, nLineSpace, 
-                                       nBandSpace );
+                                       nBandSpace, psExtraArg );
+    }
+
+    /* We could have a smarter implementation, but that will do for now */
+    if( psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
+        (nBufXSize != nXSize || nBufYSize != nYSize) )
+    {
+        return GDALDataset::IRasterIO( eRWFlag, 
+                                       nXOff, nYOff, nXSize, nYSize, 
+                                       pData, nBufXSize, nBufYSize, 
+                                       eBufType, 
+                                       nBandCount, panBandMap,
+                                       nPixelSpace, nLineSpace, 
+                                       nBandSpace, psExtraArg );
     }
 
 /* ==================================================================== */
@@ -2530,12 +3147,13 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
 /* -------------------------------------------------------------------- */
     for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
     {
-        int     iBufOffset, iSrcOffset;
+        GPtrDiff_t  iBufOffset;
+        int         iSrcOffset;
         
         dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
         iSrcY = (int) dfSrcY;
 
-        iBufOffset = iBufYOff * nLineSpace;
+        iBufOffset = (GPtrDiff_t)iBufYOff * (GPtrDiff_t)nLineSpace;
         
         for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++ )
         {
@@ -2545,6 +3163,11 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
             
             iSrcX = (int) dfSrcX;
 
+            // FIXME: this code likely doesn't work if the dirty block gets flushed
+            // to disk before being completely written.
+            // In the meantime, bJustInitalize should probably be set to FALSE
+            // even if it is not ideal performance wise, and for lossy compression
+
 /* -------------------------------------------------------------------- */
 /*      Ensure we have the appropriate block loaded.                    */
 /* -------------------------------------------------------------------- */
@@ -2562,7 +3185,18 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                     && nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
                     && nXOff <= nLBlockX * nBlockXSize
                     && nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
-
+                /*int bMemZeroBuffer = FALSE;
+                if( eRWFlag == GF_Write && !bJustInitialize &&
+                    nXOff <= nLBlockX * nBlockXSize &&
+                    nYOff <= nLBlockY * nBlockYSize &&
+                    (nXOff + nXSize >= (nLBlockX+1) * nBlockXSize ||
+                     (nXOff + nXSize == GetRasterXSize() && (nLBlockX+1) * nBlockXSize > GetRasterXSize())) &&
+                    (nYOff + nYSize >= (nLBlockY+1) * nBlockYSize ||
+                     (nYOff + nYSize == GetRasterYSize() && (nLBlockY+1) * nBlockYSize > GetRasterYSize())) )
+                {
+                    bJustInitialize = TRUE;
+                    bMemZeroBuffer = TRUE;
+                }*/
                 for( iBand = 0; iBand < nBandCount; iBand++ )
                 {
                     GDALRasterBand *poBand = GetRasterBand( panBandMap[iBand]);
@@ -2590,19 +3224,24 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                         eErr = CE_Failure; 
                         goto CleanupAndReturn;
                     }
+                    /*if( bMemZeroBuffer )
+                    {
+                        memset(papabySrcBlock[iBand], 0,
+                            nBandDataSize * nBlockXSize * nBlockYSize);
+                    }*/
                 }
             }
 
 /* -------------------------------------------------------------------- */
 /*      Copy over this pixel of data.                                   */
 /* -------------------------------------------------------------------- */
-            iSrcOffset = (iSrcX - nLBlockX*nBlockXSize
-                + (iSrcY - nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
+            iSrcOffset = ((GPtrDiff_t)iSrcX - (GPtrDiff_t)nLBlockX*nBlockXSize
+                + ((GPtrDiff_t)iSrcY - (GPtrDiff_t)nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
 
             for( iBand = 0; iBand < nBandCount; iBand++ )
             {
                 GByte *pabySrcBlock = papabySrcBlock[iBand];
-                int iBandBufOffset = iBufOffset + iBand * nBandSpace;
+                GPtrDiff_t iBandBufOffset = iBufOffset + (GPtrDiff_t)iBand * (GPtrDiff_t)nBandSpace;
                 
                 if( eDataType == eBufType )
                 {
@@ -2630,7 +3269,7 @@ GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
                 }
             }
 
-            iBufOffset += nPixelSpace;
+            iBufOffset += (int)nPixelSpace;
         }
     }
 
@@ -2683,6 +3322,9 @@ static void GDALCopyWholeRasterGetSwathSize(GDALRasterBand *poSrcPrototypeBand,
     int nSwathCols  = nXSize;
     int nSwathLines = nBlockYSize;
 
+    const char* pszSrcCompression =
+        poSrcPrototypeBand->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
+
 /* -------------------------------------------------------------------- */
 /*      What will our swath size be?                                    */
 /* -------------------------------------------------------------------- */
@@ -2696,13 +3338,19 @@ static void GDALCopyWholeRasterGetSwathSize(GDALRasterBand *poSrcPrototypeBand,
     else
     {
         /* As a default, take one 1/4 of the cache size */
-        nTargetSwathSize = MIN(INT_MAX, GDALGetCacheMax64() / 4);
+        nTargetSwathSize = (int)MIN(INT_MAX, GDALGetCacheMax64() / 4);
 
         /* but if the minimum idal swath buf size is less, then go for it to */
         /* avoid unnecessarily abusing RAM usage */
         GIntBig nIdealSwathBufSize = (GIntBig)nSwathCols * nSwathLines * nPixelSize;
+        if( pszSrcCompression != NULL && EQUAL(pszSrcCompression, "JPEG2000") &&
+            (!bDstIsCompressed || ((nSrcBlockXSize % nBlockXSize) == 0 && (nSrcBlockYSize % nBlockYSize) == 0)) )
+        {
+            nIdealSwathBufSize = MAX(nIdealSwathBufSize,
+                                     (GIntBig)nSwathCols * nSrcBlockYSize * nPixelSize);
+        }
         if( nTargetSwathSize > nIdealSwathBufSize )
-            nTargetSwathSize = nIdealSwathBufSize;
+            nTargetSwathSize = (int)nIdealSwathBufSize;
     }
 
     if (nTargetSwathSize < 1000000)
@@ -2716,17 +3364,17 @@ static void GDALCopyWholeRasterGetSwathSize(GDALRasterBand *poSrcPrototypeBand,
                  "should be at least the size of the swath (%d) (GDAL_SWATH_SIZE config. option)", GDALGetCacheMax64(), nTargetSwathSize);
     }
 
-#define IS_MULTIPLE_OF(x,y) ((y)%(x) == 0)
+#define IS_DIVIDER_OF(x,y) ((y)%(x) == 0)
 #define ROUND_TO(x,y) (((x)/(y))*(y))
 
     /* if both input and output datasets are tiled, that the tile dimensions */
     /* are "compatible", try to stick  to a swath dimension that is a multiple */
     /* of input and output block dimensions */
     if (nBlockXSize != nXSize && nSrcBlockXSize != nXSize &&
-        IS_MULTIPLE_OF(nBlockXSize, nMaxBlockXSize) &&
-        IS_MULTIPLE_OF(nSrcBlockXSize, nMaxBlockXSize) &&
-        IS_MULTIPLE_OF(nBlockYSize, nMaxBlockYSize) &&
-        IS_MULTIPLE_OF(nSrcBlockYSize, nMaxBlockYSize))
+        IS_DIVIDER_OF(nBlockXSize, nMaxBlockXSize) &&
+        IS_DIVIDER_OF(nSrcBlockXSize, nMaxBlockXSize) &&
+        IS_DIVIDER_OF(nBlockYSize, nMaxBlockYSize) &&
+        IS_DIVIDER_OF(nSrcBlockYSize, nMaxBlockYSize))
     {
         if (((GIntBig)nMaxBlockXSize) * nMaxBlockYSize * nPixelSize <=
                                                     (GIntBig)nTargetSwathSize)
@@ -2761,8 +3409,8 @@ static void GDALCopyWholeRasterGetSwathSize(GDALRasterBand *poSrcPrototypeBand,
 
         CPLDebug( "GDAL",
               "GDALCopyWholeRasterGetSwathSize(): adjusting to %d line swath "
-              "since requirement (%d * %d bytes) exceed target swath size (%d bytes) (GDAL_SWATH_SIZE config. option)",
-              nSwathLines, nBlockYSize, nMemoryPerCol, nTargetSwathSize);
+              "since requirement (" CPL_FRMT_GIB " bytes) exceed target swath size (%d bytes) (GDAL_SWATH_SIZE config. option)",
+              nSwathLines, (GIntBig)nBlockYSize * nMemoryPerCol, nTargetSwathSize);
     }
     // If we are processing single scans, try to handle several at once.
     // If we are handling swaths already, only grow the swath if a row
@@ -2774,13 +3422,43 @@ static void GDALCopyWholeRasterGetSwathSize(GDALRasterBand *poSrcPrototypeBand,
 
         /* If possible try to align to source and target block height */
         if ((nSwathLines % nMaxBlockYSize) != 0 && nSwathLines > nMaxBlockYSize &&
-            IS_MULTIPLE_OF(nBlockYSize, nMaxBlockYSize) &&
-            IS_MULTIPLE_OF(nSrcBlockYSize, nMaxBlockYSize))
+            IS_DIVIDER_OF(nBlockYSize, nMaxBlockYSize) &&
+            IS_DIVIDER_OF(nSrcBlockYSize, nMaxBlockYSize))
             nSwathLines = ROUND_TO(nSwathLines, nMaxBlockYSize);
     }
 
+    if( pszSrcCompression != NULL && EQUAL(pszSrcCompression, "JPEG2000") &&
+        (!bDstIsCompressed ||
+            (IS_DIVIDER_OF(nBlockXSize, nSrcBlockXSize) &&
+             IS_DIVIDER_OF(nBlockYSize, nSrcBlockYSize))) )
+    {
+        /* Typical use case: converting from Pleaiades that is 2048x2048 tiled */
+        if (nSwathLines < nSrcBlockYSize)
+        {
+            nSwathLines = nSrcBlockYSize;
+
+            /* Number of pixels that can be read/write simultaneously */
+            nSwathCols = nTargetSwathSize / (nSrcBlockXSize * nPixelSize);
+            nSwathCols = ROUND_TO(nSwathCols, nSrcBlockXSize);
+            if (nSwathCols == 0)
+                nSwathCols = nSrcBlockXSize;
+            if (nSwathCols > nXSize)
+                nSwathCols = nXSize;
 
-    if (bDstIsCompressed)
+            CPLDebug( "GDAL",
+              "GDALCopyWholeRasterGetSwathSize(): because of compression and too high block,\n"
+              "use partial width at one time");
+        }
+        else if ((nSwathLines % nSrcBlockYSize) != 0)
+        {
+            /* Round on a multiple of nSrcBlockYSize */
+            nSwathLines = ROUND_TO(nSwathLines, nSrcBlockYSize);
+            CPLDebug( "GDAL",
+              "GDALCopyWholeRasterGetSwathSize(): because of compression, \n"
+              "round nSwathLines to block height : %d", nSwathLines);
+        }
+    }
+    else if (bDstIsCompressed)
     {
         if (nSwathLines < nBlockYSize)
         {
@@ -2917,6 +3595,8 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
     if( pszInterleave != NULL 
         && (EQUAL(pszInterleave,"PIXEL") || EQUAL(pszInterleave,"LINE")) )
         bInterleave = TRUE;
+    else if( pszInterleave != NULL && EQUAL(pszInterleave,"BAND") )
+        bInterleave = FALSE;
 
     /* If the destination is compressed, we must try to write blocks just once, to save */
     /* disk space (GTiff case for example), and to avoid data loss (JPEG compression for example) */
@@ -2954,6 +3634,12 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
             "GDALDatasetCopyWholeRaster(): %d*%d swaths, bInterleave=%d", 
             nSwathCols, nSwathLines, bInterleave );
 
+    if( nSwathCols == nXSize && poSrcDS->GetDriver() != NULL &&
+        EQUAL(poSrcDS->GetDriver()->GetDescription(), "ECW") )
+    {
+        poSrcDS->AdviseRead(0, 0, nXSize, nYSize, nXSize, nYSize, eDT, nBandCount, NULL, NULL);
+    }
+
 /* ==================================================================== */
 /*      Band oriented (uninterleaved) case.                             */
 /* ==================================================================== */
@@ -2961,6 +3647,14 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
     {
         int iBand, iX, iY;
 
+        GDALRasterIOExtraArg sExtraArg;
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
+        int nTotalBlocks = nBandCount *
+                           ((nYSize + nSwathLines - 1) / nSwathLines) *
+                           ((nXSize + nSwathCols - 1) / nSwathCols);
+        int nBlocksDone = 0;
+
         for( iBand = 0; iBand < nBandCount && eErr == CE_None; iBand++ )
         {
             int nBand = iBand+1;
@@ -2979,24 +3673,31 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
                     if( iX + nThisCols > nXSize )
                         nThisCols = nXSize - iX;
 
+                    sExtraArg.pfnProgress = GDALScaledProgress;
+                    sExtraArg.pProgressData = 
+                        GDALCreateScaledProgress( nBlocksDone / (double)nTotalBlocks,
+                                                (nBlocksDone + 0.5) / (double)nTotalBlocks,
+                                                pfnProgress,
+                                                pProgressData );
+
                     eErr = poSrcDS->RasterIO( GF_Read, 
                                             iX, iY, nThisCols, nThisLines,
                                             pSwathBuf, nThisCols, nThisLines, 
                                             eDT, 1, &nBand, 
-                                            0, 0, 0 );
+                                            0, 0, 0, &sExtraArg );
+
+                    GDALDestroyScaledProgress( sExtraArg.pProgressData );
 
                     if( eErr == CE_None )
                         eErr = poDstDS->RasterIO( GF_Write, 
                                                 iX, iY, nThisCols, nThisLines,
                                                 pSwathBuf, nThisCols, nThisLines, 
                                                 eDT, 1, &nBand,
-                                                0, 0, 0 );
-
+                                                0, 0, 0, NULL );
+                    nBlocksDone ++;
                     if( eErr == CE_None 
-                        && !pfnProgress( 
-                            iBand / (float)nBandCount
-                            + (iY+nThisLines) / (float) (nYSize*nBandCount),
-                            NULL, pProgressData ) )
+                        && !pfnProgress( nBlocksDone / (double)nTotalBlocks,
+                                        NULL, pProgressData ) )
                     {
                         eErr = CE_Failure;
                         CPLError( CE_Failure, CPLE_UserInterrupt, 
@@ -3014,6 +3715,13 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
     {
         int iY, iX;
 
+        GDALRasterIOExtraArg sExtraArg;
+        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+
+        int nTotalBlocks = ((nYSize + nSwathLines - 1) / nSwathLines) *
+                           ((nXSize + nSwathCols - 1) / nSwathCols);
+        int nBlocksDone = 0;
+
         for( iY = 0; iY < nYSize && eErr == CE_None; iY += nSwathLines )
         {
             int nThisLines = nSwathLines;
@@ -3028,21 +3736,31 @@ CPLErr CPL_STDCALL GDALDatasetCopyWholeRaster(
                 if( iX + nThisCols > nXSize )
                     nThisCols = nXSize - iX;
 
+                sExtraArg.pfnProgress = GDALScaledProgress;
+                sExtraArg.pProgressData = 
+                    GDALCreateScaledProgress( nBlocksDone / (double)nTotalBlocks,
+                                            (nBlocksDone + 0.5) / (double)nTotalBlocks,
+                                            pfnProgress,
+                                            pProgressData );
+
                 eErr = poSrcDS->RasterIO( GF_Read, 
                                         iX, iY, nThisCols, nThisLines,
                                         pSwathBuf, nThisCols, nThisLines, 
                                         eDT, nBandCount, NULL, 
-                                        0, 0, 0 );
+                                        0, 0, 0, &sExtraArg );
+
+                GDALDestroyScaledProgress( sExtraArg.pProgressData );
 
                 if( eErr == CE_None )
                     eErr = poDstDS->RasterIO( GF_Write, 
                                             iX, iY, nThisCols, nThisLines,
                                             pSwathBuf, nThisCols, nThisLines, 
                                             eDT, nBandCount, NULL, 
-                                            0, 0, 0 );
+                                            0, 0, 0, NULL );
 
+                nBlocksDone ++;
                 if( eErr == CE_None 
-                    && !pfnProgress( (iY+nThisLines) / (float) nYSize,
+                    && !pfnProgress( nBlocksDone / (double)nTotalBlocks,
                                     NULL, pProgressData ) )
                 {
                     eErr = CE_Failure;
@@ -3189,13 +3907,13 @@ CPLErr CPL_STDCALL GDALRasterBandCopyWholeRaster(
             eErr = poSrcBand->RasterIO( GF_Read,
                                     iX, iY, nThisCols, nThisLines,
                                     pSwathBuf, nThisCols, nThisLines,
-                                    eDT, 0, 0 );
+                                    eDT, 0, 0, NULL );
 
             if( eErr == CE_None )
                 eErr = poDstBand->RasterIO( GF_Write,
                                         iX, iY, nThisCols, nThisLines,
                                         pSwathBuf, nThisCols, nThisLines,
-                                        eDT, 0, 0 );
+                                        eDT, 0, 0, NULL );
 
             if( eErr == CE_None
                 && !pfnProgress(
@@ -3216,3 +3934,28 @@ CPLErr CPL_STDCALL GDALRasterBandCopyWholeRaster(
 
     return eErr;
 }
+
+
+/************************************************************************/
+/*                      GDALCopyRasterIOExtraArg ()                     */
+/************************************************************************/
+
+void GDALCopyRasterIOExtraArg(GDALRasterIOExtraArg* psDestArg,
+                              GDALRasterIOExtraArg* psSrcArg)
+{
+    INIT_RASTERIO_EXTRA_ARG(*psDestArg);
+    if( psSrcArg )
+    {
+        psDestArg->eResampleAlg = psSrcArg->eResampleAlg;
+        psDestArg->pfnProgress = psSrcArg->pfnProgress;
+        psDestArg->pProgressData = psSrcArg->pProgressData;
+        psDestArg->bFloatingPointWindowValidity = psSrcArg->bFloatingPointWindowValidity;
+        if( psSrcArg->bFloatingPointWindowValidity )
+        {
+            psDestArg->dfXOff = psSrcArg->dfXOff;
+            psDestArg->dfYOff = psSrcArg->dfYOff;
+            psDestArg->dfXSize = psSrcArg->dfXSize;
+            psDestArg->dfYSize = psSrcArg->dfYSize;
+        }
+    }
+}
diff --git a/m4/acinclude.m4 b/m4/acinclude.m4
index 1daa09c..167875d 100644
--- a/m4/acinclude.m4
+++ b/m4/acinclude.m4
@@ -1,5 +1,5 @@
 dnl ***************************************************************************
-dnl $Id: acinclude.m4 26534 2013-10-16 12:10:05Z rouault $
+dnl $Id: acinclude.m4 28182 2014-12-20 19:53:13Z goatbar $
 dnl
 dnl Project:  GDAL
 dnl Purpose:  Configure extra local definitions.
@@ -192,7 +192,15 @@ AC_DEFUN([AC_UNIX_STDIO_64],
   if test x"$with_unix_stdio_64" = x"yes" ; then
     AC_MSG_RESULT([yes])
 
-    AC_CHECK_FUNC(stat64, VSI_STAT64=stat64 VSI_STAT64_T=stat64, VSI_STAT64=stat VSI_STAT64_T=stat)
+    case "${host_os}" in
+      darwin*)
+        VSI_STAT64=stat
+        VSI_STAT64_T=stat
+        ;;
+      *)      
+        AC_CHECK_FUNC(stat64, VSI_STAT64=stat64 VSI_STAT64_T=stat64, VSI_STAT64=stat VSI_STAT64_T=stat)
+        ;;
+    esac
     AC_CHECK_FUNC(fopen64, VSI_FOPEN64=fopen64, VSI_FOPEN64=fopen)
     AC_CHECK_FUNC(ftruncate64, VSI_FTRUNCATE64=ftruncate64, VSI_FTRUNCATE64=ftruncate)
 
diff --git a/makefile.vc b/makefile.vc
index 0e03543..d49359a 100644
--- a/makefile.vc
+++ b/makefile.vc
@@ -26,17 +26,11 @@ OGR_BASE_INCLUDE = /INCLUDE:$(SYM_PREFIX)OGRFeatureStylePuller \
 		/INCLUDE:$(SYM_PREFIX)OGR_G_GetPointCount 
 
 
-!IFDEF INCLUDE_OGR_FRMTS
 CPPFLAGS = $(CPPFLAGS) -DOGR_ENABLED
 OGR_OBJ = ogr\ogrsf_frmts\ogrsf_frmts.lib ogr\ogr.lib
 OGR_INCLUDE = $(OGR_BASE_INCLUDE) \
 		/INCLUDE:$(SYM_PREFIX)OGRRegisterAll
 
-!ELSE
-OGR_OBJ = ogr\ogr.lib
-OGR_INCLUDE =	$(OGR_BASE_INCLUDE)
-!ENDIF
-
 !IF DEFINED(STDCALL) && !DEFINED(WIN64)
 
 !IF $(MSVC_VER) < 1500
@@ -149,11 +143,7 @@ ogr_dir:      port_dir
 	cd ..\sdts
 	$(MAKE) /f makefile.vc
 	cd ..\..\ogr
-!IFDEF INCLUDE_OGR_FRMTS
 	$(MAKE) /f makefile.vc ogr.lib frmts
-!ELSE
-	$(MAKE) /f makefile.vc ogr.lib
-!ENDIF
 	cd ..
 
 lib_dist:	default
diff --git a/man/man1/gdal-config.1 b/man/man1/gdal-config.1
index a841b26..19abb8c 100644
--- a/man/man1/gdal-config.1
+++ b/man/man1/gdal-config.1
@@ -1,8 +1,8 @@
-.TH "gdal-config" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal-config" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal-config \- .TH "gdal-config" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal-config \- .TH "gdal-config" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdal2tiles.1 b/man/man1/gdal2tiles.1
index 4cde8bc..5b606ca 100644
--- a/man/man1/gdal2tiles.1
+++ b/man/man1/gdal2tiles.1
@@ -1,8 +1,8 @@
-.TH "gdal2tiles" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal2tiles" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal2tiles \- .TH "gdal2tiles" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal2tiles \- .TH "gdal2tiles" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdal_calc.1 b/man/man1/gdal_calc.1
index 330f091..f95d437 100644
--- a/man/man1/gdal_calc.1
+++ b/man/man1/gdal_calc.1
@@ -1,8 +1,8 @@
-.TH "gdal_calc" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_calc" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_calc \- .TH "gdal_calc" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_calc \- .TH "gdal_calc" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -20,7 +20,7 @@ Options:
                         numpy array functions (i.e. logical_and())
   -A A                  input gdal raster file, note you can use any letter
                         A-Z
-  --A_band=A_BAND       number of raster band for file A (default 0)
+  --A_band=A_BAND       number of raster band for file A (default 1)
   --outfile=OUTF        output file to generate or fill
   --NoDataValue=NODATAVALUE
                         set output nodata value (Defaults to datatype specific
diff --git a/man/man1/gdal_contour.1 b/man/man1/gdal_contour.1
index cf4ebea..75555ba 100644
--- a/man/man1/gdal_contour.1
+++ b/man/man1/gdal_contour.1
@@ -1,8 +1,8 @@
-.TH "gdal_contour" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_contour" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_contour \- .TH "gdal_contour" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_contour \- .TH "gdal_contour" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdal_edit.1 b/man/man1/gdal_edit.1
index 987e24d..b613548 100644
--- a/man/man1/gdal_edit.1
+++ b/man/man1/gdal_edit.1
@@ -1,8 +1,8 @@
-.TH "gdal_edit" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_edit" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_edit \- .TH "gdal_edit" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_edit \- .TH "gdal_edit" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -14,20 +14,21 @@ gdal_edit \- Edit in place various information of an existing GDAL dataset
 
 gdal_edit [--help-general] [-ro] [-a_srs srs_def] [-a_ullr ulx uly lrx lry]
           [-tr xres yres] [-unsetgt] [-a_nodata value]
+          [-unsetstats] [-stats] [-approx_stats]
           [-gcp pixel line easting northing [elevation]]*
-          [-mo "META-TAG=VALUE"]*  datasetname
+          [-unsetmd] [-oo NAME=VALUE]* [-mo "META-TAG=VALUE"]*  datasetname
 .fi
 .PP
 .SH "DESCRIPTION"
 .PP
-The gdal_edit.py script can be used to allows to edit in place various information of an existing GDAL dataset (projection, geotransform, nodata, metadata).
+The gdal_edit.py script can be used to edit in place various information of an existing GDAL dataset (projection, geotransform, nodata, metadata).
 .PP
 It works only with raster formats that support update access to existing datasets. 
 .IP "\fB\fB--help-general\fP:\fP" 1c
 Gives a brief usage message for the generic GDAL commandline options and exit. 
 .PP
 .IP "\fB\fB-ro\fP:\fP" 1c
-(GDAL >= 1.11) Open the dataset in read-only. Might be usefull for drivers refusing to use the dataset in update-mode. In which case, updated information will go into PAM .aux.xml files.
+(GDAL >= 1.11) Open the dataset in read-only. Might be useful for drivers refusing to use the dataset in update-mode. In which case, updated information will go into PAM .aux.xml files.
 .PP
 .IP "\fB\fB-a_srs\fP \fIsrs_def\fP:\fP" 1c
 .PP
@@ -42,18 +43,35 @@ Set target resolution. The values must be expressed in georeferenced units. Both
 .IP "\fB\fB-unsetgt\fP:\fP" 1c
 Remove the georeference information.
 .PP
+.IP "\fB\fB-unsetstats\fP:\fP" 1c
+(GDAL >= 2.0) Remove band statistics information.
+.PP
+.IP "\fB\fB-stats\fP:\fP" 1c
+(GDAL >= 2.0) Calculate and store band statistics.
+.PP
+.IP "\fB\fB-approx_stats\fP:\fP" 1c
+(GDAL >= 2.0) Calculate and store approximate band statistics.
+.PP
 .IP "\fB\fB-a_nodata\fP \fIvalue\fP:\fP" 1c
 Assign a specified nodata value to output bands.
 .PP
 .IP "\fB\fB-gcp\fP \fIpixel line easting northing [elevation]\fP:\fP" 1c
 Add the indicated ground control point to the dataset. This option may be provided multiple times to provide a set of GCPs. 
 .PP
+.IP "\fB\fB-unsetmd\fP:\fP" 1c
+(GDAL >= 2.0) Remove existing metadata (in the default metadata domain). Can be combined with -mo.
+.PP
 .IP "\fB\fB-mo\fP \fI'META-TAG=VALUE'\fP:\fP" 1c
-Passes a metadata key and value to set on the output dataset if possible.
+Passes a metadata key and value to set on the output dataset if possible. This metadata is added to the existing metadata items, unless -unsetmd is also specified.
+.PP
+.IP "\fB\fB-oo\fP \fI'NAME=VALUE'\fP:\fP" 1c
+(GDAL >= 2.0) Open option (format specific).
 .PP
 .PP
 .PP
 -a_ullr, -tr and -unsetgt options are exclusive.
+.PP
+-unsetstats and either -stats or -approx_stats options are exclusive.
 .SH "EXAMPLE"
 .PP
 .PP
diff --git a/man/man1/gdal_fillnodata.1 b/man/man1/gdal_fillnodata.1
index 32cb11e..dda1d3c 100644
--- a/man/man1/gdal_fillnodata.1
+++ b/man/man1/gdal_fillnodata.1
@@ -1,8 +1,8 @@
-.TH "gdal_fillnodata" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_fillnodata" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_fillnodata \- .TH "gdal_fillnodata" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_fillnodata \- .TH "gdal_fillnodata" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -24,7 +24,7 @@ The gdal_fillnodata.py script fills selection regions (usually nodata areas) by
 Additional details on the algorithm are available in the GDALFillNodata() docs.
 .PP
 .IP "\fB\fB-q\fP:\fP" 1c
-The script runs in quiet mode. The progress monitor is supressed and routine messages are not displayed.
+The script runs in quiet mode. The progress monitor is suppressed and routine messages are not displayed.
 .PP
 .IP "\fB\fB-md\fP \fImax_distance\fP:\fP" 1c
 The maximum distance (in pixels) that the algorithm will search out for values to interpolate.
diff --git a/man/man1/gdal_grid.1 b/man/man1/gdal_grid.1
index 1ff0d3e..c0ff49d 100644
--- a/man/man1/gdal_grid.1
+++ b/man/man1/gdal_grid.1
@@ -1,8 +1,8 @@
-.TH "gdal_grid" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_grid" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_grid \- .TH "gdal_grid" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_grid \- .TH "gdal_grid" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdal_merge.1 b/man/man1/gdal_merge.1
index a85dec8..ca89b55 100644
--- a/man/man1/gdal_merge.1
+++ b/man/man1/gdal_merge.1
@@ -1,8 +1,8 @@
-.TH "gdal_merge" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_merge" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_merge \- .TH "gdal_merge" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_merge \- .TH "gdal_merge" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -67,7 +67,7 @@ Create an image with the pixels in all bands initialized to 255.
 .fi
 .PP
 .PP
-Create an RGB image that shows blue in pixels with no data. The first two bands will be initialized to 0 and the third band will be initalized to 255.
+Create an RGB image that shows blue in pixels with no data. The first two bands will be initialized to 0 and the third band will be initialized to 255.
 .PP
 .PP
 .nf
diff --git a/man/man1/gdal_polygonize.1 b/man/man1/gdal_polygonize.1
index 36b72c2..cdbdbcf 100644
--- a/man/man1/gdal_polygonize.1
+++ b/man/man1/gdal_polygonize.1
@@ -1,8 +1,8 @@
-.TH "gdal_polygonize" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_polygonize" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_polygonize \- .TH "gdal_polygonize" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_polygonize \- .TH "gdal_polygonize" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -52,7 +52,7 @@ The name of the layer created to hold the polygon features.
 The name of the field to create (defaults to 'DN'). 
 .PP
 .IP "\fB\fB-q\fP:\fP" 1c
-The script runs in quiet mode. The progress monitor is supressed and routine messages are not displayed. 
+The script runs in quiet mode. The progress monitor is suppressed and routine messages are not displayed. 
 .PP
 .PP
 .PP
diff --git a/man/man1/gdal_proximity.1 b/man/man1/gdal_proximity.1
index 94abf12..cd6beeb 100644
--- a/man/man1/gdal_proximity.1
+++ b/man/man1/gdal_proximity.1
@@ -1,8 +1,8 @@
-.TH "gdal_proximity" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_proximity" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_proximity \- .TH "gdal_proximity" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_proximity \- .TH "gdal_proximity" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -16,7 +16,8 @@ gdal_proximity.py srcfile dstfile [-srcband n] [-dstband n]
                   [-of format] [-co name=value]*
                   [-ot Byte/Int16/Int32/Float32/etc]
                   [-values n,n,n] [-distunits PIXEL/GEO]
-                  [-maxdist n] [-nodata n] [-fixed-buf-val n]
+                  [-maxdist n] [-nodata n] [-use_input_nodata YES/NO]
+                  [-fixed-buf-val n] 
 .fi
 .PP
 .SH "DESCRIPTION"
@@ -51,11 +52,14 @@ A list of target pixel values in the source image to be considered target pixels
 Indicate whether distances generated should be in pixel or georeferenced coordinates (default PIXEL). 
 .PP
 .IP "\fB\fB-maxdist\fP \fIn\fP:\fP" 1c
-The maximum distance to be generated. All pixels beyond this distance will be assigned either the nodata value, or 65535. Distance is interpreted in pixels unless -distunits GEO is specified. 
+The maximum distance to be generated. The nodata value will be used for pixels beyond this distance. If a nodata value is not provided, the output band will be queried for its nodata value. If the output band does not have a nodata value, then the value 65535 will be used. Distance is interpreted in pixels unless -distunits GEO is specified. 
 .PP
 .IP "\fB\fB-nodata\fP \fIn\fP:\fP" 1c
 Specify a nodata value to use for the destination proximity raster. 
 .PP
+.IP "\fB\fB-use_input_nodata\fP \fIYES/NO\fP:\fP" 1c
+(GDAL >= 2.0) Indicate whether nodata pixels in the input raster should be nodata in the output raster (default NO). 
+.PP
 .IP "\fB\fB-fixed-buf-val\fP \fIn\fP:\fP" 1c
 Specify a value to be applied to all pixels that are within the -maxdist of target pixels (including the target pixels) instead of a distance value. 
 .PP
diff --git a/man/man1/gdal_rasterize.1 b/man/man1/gdal_rasterize.1
index 0a9528f..775bd13 100644
--- a/man/man1/gdal_rasterize.1
+++ b/man/man1/gdal_rasterize.1
@@ -1,8 +1,8 @@
-.TH "gdal_rasterize" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_rasterize" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_rasterize \- .TH "gdal_rasterize" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_rasterize \- .TH "gdal_rasterize" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -25,11 +25,11 @@ Usage: gdal_rasterize [-b band]* [-i] [-at]
 .PP
 .SH "DESCRIPTION"
 .PP
-This program burns vector geometries (points, lines and polygons) into the raster band(s) of a raster image. Vectors are read from OGR supported vector formats.
+This program burns vector geometries (points, lines, and polygons) into the raster band(s) of a raster image. Vectors are read from OGR supported vector formats.
 .PP
-Note that the vector data must in the same coordinate system as the raster data; on the fly reprojection is not provided.
+Note that the vector data must be in the same coordinate system as the raster data; on the fly reprojection is not provided.
 .PP
-Since GDAL 1.8.0, the target GDAL file can be created by gdal_rasterize. One of -tr or -ts option must be used in that case.
+Since GDAL 1.8.0, the target GDAL file can be created by gdal_rasterize. Either the -tr or -ts option must be used in that case.
 .PP
 .IP "\fB\fB-b\fP \fIband\fP: \fP" 1c
 The band(s) to burn values into. Multiple -b arguments may be used to burn into a list of bands. The default is to burn into band 1.
@@ -38,13 +38,13 @@ The band(s) to burn values into. Multiple -b arguments may be used to burn into
 Invert rasterization. Burn the fixed burn value, or the burn value associated with the first feature into all parts of the image \fInot\fP inside the provided a polygon.
 .PP
 .IP "\fB\fB-at\fP: \fP" 1c
-Enables the ALL_TOUCHED rasterization option so that all pixels touched by lines or polygons will be updated not just those one the line render path, or whose center point is within the polygon. Defaults to disabled for normal rendering rules.
+Enables the ALL_TOUCHED rasterization option so that all pixels touched by lines or polygons will be updated, not just those on the line render path, or whose center point is within the polygon. Defaults to disabled for normal rendering rules.
 .PP
 .IP "\fB\fB-burn\fP \fIvalue\fP: \fP" 1c
 A fixed value to burn into a band for all objects. A list of -burn options can be supplied, one per band being written to.
 .PP
 .IP "\fB\fB-a\fP \fIattribute_name\fP: \fP" 1c
-Identifies an attribute field on the features to be used for a burn in value. The value will be burned into all output bands.
+Identifies an attribute field on the features to be used for a burn-in value. The value will be burned into all output bands.
 .PP
 .IP "\fB\fB-3d\fP: \fP" 1c
 Indicates that a burn value should be extracted from the 'Z' values of the feature. These values are adjusted by the burn value given by '-burn value' or '-a attribute_name' if provided. As of now, only points and lines are drawn in 3D.
@@ -74,16 +74,16 @@ An SQL statement to be evaluated against the datasource to produce a virtual lay
 (GDAL >= 1.8.0) Passes a creation option to the output format driver. Multiple \fB-co\fP options may be listed. See format specific documentation for legal creation options for each format.
 .PP
 .IP "\fB\fB-te\fP \fIxmin ymin xmax ymax\fP :\fP" 1c
-(GDAL >= 1.8.0) set georeferenced extents. The values must be expressed in georeferenced units. If not specified, the extent of the output file will be the extent of the vector layers. 
+(GDAL >= 1.8.0) Set georeferenced extents. The values must be expressed in georeferenced units. If not specified, the extent of the output file will be the extent of the vector layers. 
 .PP
 .IP "\fB\fB-tr\fP \fIxres yres\fP :\fP" 1c
-(GDAL >= 1.8.0) set target resolution. The values must be expressed in georeferenced units. Both must be positive values. 
+(GDAL >= 1.8.0) Set target resolution. The values must be expressed in georeferenced units. Both must be positive values. 
 .PP
 .IP "\fB\fB-tap\fP:\fP" 1c
-(GDAL >= 1.8.0) (target aligned pixels) align the coordinates of the extent of the output file to the values of the -tr, such that the aligned extent includes the minimum extent.
+(GDAL >= 1.8.0) (target aligned pixels) Align the coordinates of the extent of the output file to the values of the -tr, such that the aligned extent includes the minimum extent.
 .PP
 .IP "\fB\fB-ts\fP \fIwidth height\fP:\fP" 1c
-(GDAL >= 1.8.0) set output file size in pixels and lines. Note that -ts cannot be used with -tr
+(GDAL >= 1.8.0) Set output file size in pixels and lines. Note that -ts cannot be used with -tr
 .PP
 .IP "\fB\fB-ot\fP \fItype\fP:\fP" 1c
 (GDAL >= 1.8.0) For the output bands to be of the indicated data type. Defaults to Float64
diff --git a/man/man1/gdal_retile.1 b/man/man1/gdal_retile.1
index 7434f8b..67f8b2c 100644
--- a/man/man1/gdal_retile.1
+++ b/man/man1/gdal_retile.1
@@ -1,8 +1,8 @@
-.TH "gdal_retile" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_retile" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_retile \- .TH "gdal_retile" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_retile \- .TH "gdal_retile" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdal_sieve.1 b/man/man1/gdal_sieve.1
index eca889c..0ff2b97 100644
--- a/man/man1/gdal_sieve.1
+++ b/man/man1/gdal_sieve.1
@@ -1,8 +1,8 @@
-.TH "gdal_sieve" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_sieve" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_sieve \- .TH "gdal_sieve" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_sieve \- .TH "gdal_sieve" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -23,7 +23,7 @@ The gdal_sieve.py script removes raster polygons smaller than a provided thresho
 Additional details on the algorithm are available in the GDALSieveFilter() docs.
 .PP
 .IP "\fB\fB-q\fP:\fP" 1c
-The script runs in quiet mode. The progress monitor is supressed and routine messages are not displayed.
+The script runs in quiet mode. The progress monitor is suppressed and routine messages are not displayed.
 .PP
 .IP "\fB\fB-st\fP \fIthreshold\fP:\fP" 1c
 Set the size threshold in pixels. Only raster polygons smaller than this size will be removed.
diff --git a/man/man1/gdal_translate.1 b/man/man1/gdal_translate.1
index 4b7ba64..248be70 100644
--- a/man/man1/gdal_translate.1
+++ b/man/man1/gdal_translate.1
@@ -1,8 +1,8 @@
-.TH "gdal_translate" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_translate" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_translate \- .TH "gdal_translate" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_translate \- .TH "gdal_translate" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -16,13 +16,16 @@ gdal_translate [--help-general]
        [-ot {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/
              CInt16/CInt32/CFloat32/CFloat64}] [-strict]
        [-of format] [-b band] [-mask band] [-expand {gray|rgb|rgba}]
-       [-outsize xsize[%] ysize[%]]
+       [-outsize xsize[%]|0 ysize[%]|0] [-tr xres yres]
+       [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]
        [-unscale] [-scale[_bn] [src_min src_max [dst_min dst_max]]]* [-exponent[_bn] exp_val]*
-       [-srcwin xoff yoff xsize ysize] [-projwin ulx uly lrx lry] [-epo] [-eco]
+       [-srcwin xoff yoff xsize ysize] [-epo] [-eco]
+       [-projwin ulx uly lrx lry] [-projwin_srs srs_def]
        [-a_srs srs_def] [-a_ullr ulx uly lrx lry] [-a_nodata value]
        [-gcp pixel line easting northing [elevation]]*
        [-mo "META-TAG=VALUE"]* [-q] [-sds]
        [-co "NAME=VALUE"]* [-stats] [-norat]
+       [-oo NAME=VALUE]*
        src_dataset dst_dataset
 .fi
 .PP
@@ -42,8 +45,12 @@ Select an input band \fIband\fP for output. Bands are numbered from 1. Multiple
 (GDAL >= 1.8.0) Select an input band \fIband\fP to create output dataset mask band. Bands are numbered from 1. \fIband\fP can be set to 'none' to avoid copying the global mask of the input dataset if it exists. Otherwise it is copied by default ('auto'), unless the mask is an alpha channel, or if it is explicitly used to be a regular band of the output dataset ('-b mask'). \fIband\fP can also be set to 'mask,1' (or just 'mask') to mean the mask band of the 1st band of the input dataset. 
 .IP "\fB\fB-expand\fP \fIgray|rgb|rgba\fP:\fP" 1c
 (From GDAL 1.6.0) To expose a dataset with 1 band with a color table as a dataset with 3 (RGB) or 4 (RGBA) bands. Useful for output drivers such as JPEG, JPEG2000, MrSID, ECW that don't support color indexed datasets. The 'gray' value (from GDAL 1.7.0) enables to expand a dataset with a color table that only contains gray levels to a gray indexed dataset. 
-.IP "\fB\fB-outsize\fP \fIxsize[%] ysize[%]\fP:\fP" 1c
-Set the size of the output file. Outsize is in pixels and lines unless '%' is attached in which case it is as a fraction of the input image size. 
+.IP "\fB\fB-outsize\fP \fIxsize[%]|0 ysize[%]|0\fP:\fP" 1c
+Set the size of the output file. Outsize is in pixels and lines unless '%' is attached in which case it is as a fraction of the input image size. Starting with GDAL 2.0, if one of the 2 values is set to 0, its value will be determined from the other one, while maintaining the aspect ratio of the source dataset. 
+.IP "\fB\fB-tr\fP xres yres :\fP" 1c
+(starting with GDAL 2.0) set target resolution. The values must be expressed in georeferenced units. Both must be positive values. This is exclusive with -outsize and -a_ullr.  
+.IP "\fB\fB-r\fP \fI{nearest (default),bilinear,cubic,cubicspline,lanczos,average,mode}\fP:\fP" 1c
+(GDAL >= 2.0) Select a resampling algorithm. 
 .IP "\fB\fB-scale\fP \fI[src_min src_max [dst_min dst_max]]\fP:\fP" 1c
 Rescale the input pixels values from the range \fIsrc_min\fP to \fIsrc_max\fP to the range \fIdst_min\fP to \fIdst_max\fP. If omitted the output range is 0 to 255. If omitted the input range is automatically computed from the source data. Before GDAL 1.11, it can be specified only once, and in that case, it applies to all bands of the output dataset. Starting with GDAL 1.11, -scale can be repeated several times (if specified only once, it also applies to all bands of the output dataset), [...]
 .IP "\fB\fB-exponent\fP \fI exp_val\fP:\fP" 1c
@@ -53,7 +60,9 @@ Apply the scale/offset metadata for the bands to convert scaled values to unscal
 .IP "\fB\fB-srcwin\fP \fIxoff yoff xsize ysize\fP:\fP" 1c
 Selects a subwindow from the source image for copying based on pixel/line location.  
 .IP "\fB\fB-projwin\fP \fIulx uly lrx lry\fP:\fP" 1c
-Selects a subwindow from the source image for copying (like \fB-srcwin\fP) but with the corners given in georeferenced coordinates.  
+Selects a subwindow from the source image for copying (like \fB-srcwin\fP) but with the corners given in georeferenced coordinates (by default expressed in the SRS of the dataset. Can be changed with -projwin_srs).  
+.IP "\fB\fB-projwin_srs\fP \fIsrs_def\fP:\fP" 1c
+(GDAL >= 2.0) Specifies the SRS in which to interpret the coordinates given with -projwin. The \fIsrs_def\fP may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file containing the WKT. Note that this does not cause reprojection of the dataset to the specified SRS.  
 .IP "\fB\fB-epo\fP: (Error when Partially Outside)\fP" 1c
 (GDAL >= 1.10) If this option is set, \fB-srcwin\fP or \fB-projwin\fP values that falls partially outside the source raster extent will be considered as an error. The default behaviour starting with GDAL 1.10 is to accept such requests, when they were considered as an error before. 
 .IP "\fB\fB-eco\fP: (Error when Completely Outside)\fP" 1c
@@ -61,9 +70,9 @@ Selects a subwindow from the source image for copying (like \fB-srcwin\fP) but w
 .IP "\fB\fB-a_srs\fP \fIsrs_def\fP:\fP" 1c
 Override the projection for the output file. The \fIsrs_def\fP may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file containing the WKT.  
 .IP "\fB\fB-a_ullr\fP \fIulx uly lrx lry\fP:\fP" 1c
-Assign/override the georeferenced bounds of the output file. This assigns georeferenced bounds to the output file, ignoring what would have been derived from the source file. 
+Assign/override the georeferenced bounds of the output file. This assigns georeferenced bounds to the output file, ignoring what would have been derived from the source file. So this does not cause reprojection to the specified SRS.  
 .IP "\fB\fB-a_nodata\fP \fIvalue\fP:\fP" 1c
-Assign a specified nodata value to output bands. Starting with GDAL 1.8.0, can be set to \fInone\fP to avoid setting a nodata value to the output file if one exists for the source file 
+Assign a specified nodata value to output bands. Starting with GDAL 1.8.0, can be set to \fInone\fP to avoid setting a nodata value to the output file if one exists for the source file. Note that, if the input dataset has a nodata value, this does not cause pixel values that are equal to that nodata value to be changed to the value specified with this option. 
 .IP "\fB\fB-mo\fP \fI'META-TAG=VALUE'\fP:\fP" 1c
 Passes a metadata key and value to set on the output dataset if possible. 
 .IP "\fB\fB-co\fP \fI'NAME=VALUE'\fP:\fP" 1c
@@ -78,6 +87,8 @@ Copy all subdatasets of this file to individual output files. Use with formats l
 (GDAL >= 1.8.0) Force (re)computation of statistics. 
 .IP "\fB\fB-norat\fP\fP" 1c
 (GDAL >= 1.11) Do not copy source RAT into destination dataset. 
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific) 
 .IP "\fB\fIsrc_dataset\fP:\fP" 1c
 The source dataset name. It can be either file name, URL of data source or subdataset name for multi-dataset files. 
 .IP "\fB\fIdst_dataset\fP:\fP" 1c
diff --git a/man/man1/gdal_utilities.1 b/man/man1/gdal_utilities.1
index f073f26..703be2f 100644
--- a/man/man1/gdal_utilities.1
+++ b/man/man1/gdal_utilities.1
@@ -1,8 +1,8 @@
-.TH "gdal_utilities" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdal_utilities" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdal_utilities \- .TH "gdal_utilities" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdal_utilities \- .TH "gdal_utilities" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdaladdo.1 b/man/man1/gdaladdo.1
index 0667339..5368acd 100644
--- a/man/man1/gdaladdo.1
+++ b/man/man1/gdaladdo.1
@@ -1,8 +1,8 @@
-.TH "gdaladdo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdaladdo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdaladdo \- .TH "gdaladdo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdaladdo \- .TH "gdaladdo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -12,16 +12,16 @@ gdaladdo \- builds or rebuilds overview images
 .PP
 .nf
 
-gdaladdo [-r {nearest,average,gauss,cubic,average_mp,average_magphase,mode}]
+gdaladdo [-r {nearest,average,gauss,cubic,cubicspline,lanczos,average_mp,average_magphase,mode}]
          [-b band]
-         [-ro] [-clean] [--help-general] filename levels
+         [-ro] [-clean] [-oo NAME=VALUE]* [--help-general] filename levels
 .fi
 .PP
 .SH "DESCRIPTION"
 .PP
 The gdaladdo utility can be used to build or rebuild overview images for most supported file formats with one of several downsampling algorithms.
 .PP
-.IP "\fB\fB-r\fP \fI{nearest (default),average,gauss,cubic,average_mp,average_magphase,mode}\fP:\fP" 1c
+.IP "\fB\fB-r\fP \fI{nearest (default),average,gauss,cubic,cubicspline,lanczos,average_mp,average_magphase,mode}\fP:\fP" 1c
 Select a resampling algorithm. 
 .IP "\fB\fB-b\fP \fIband\fP:\fP" 1c
 (available from GDAL 1.10) Select an input band \fIband\fP for overview generation. Band numbering starts from 1. Multiple \fB-b\fP switches may be used to select a set of input bands to generate overviews. 
@@ -29,13 +29,15 @@ Select a resampling algorithm.
 (available from GDAL 1.6.0) open the dataset in read-only mode, in order to generate external overview (for GeoTIFF especially).  
 .IP "\fB\fB-clean\fP:\fP" 1c
 (available from GDAL 1.7.0) remove all overviews.  
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific) 
 .IP "\fB\fIfilename\fP:\fP" 1c
 The file to build overviews for (or whose overviews must be removed).  
 .IP "\fB\fIlevels\fP:\fP" 1c
 A list of integral overview levels to build. Ignored with -clean option. 
 .PP
 .PP
-\fIMode\fP (available from GDAL 1.6.0) selects the value which appears most often of all the sampled points. \fIaverage_mp\fP is unsuitable for use. \fIAverage_magphase\fP averages complex data in mag/phase space. \fINearest\fP and \fIaverage\fP are applicable to normal image data. \fINearest\fP applies a nearest neighbour (simple sampling) resampler, while \fIaverage\fP computes the average of all non-NODATA contributing pixels. \fICubic\fP resampling (available from GDAL 1.7.0) applies [...]
+\fIMode\fP (available from GDAL 1.6.0) selects the value which appears most often of all the sampled points. \fIaverage_mp\fP is unsuitable for use. \fIAverage_magphase\fP averages complex data in mag/phase space. \fINearest\fP and \fIaverage\fP are applicable to normal image data. \fINearest\fP applies a nearest neighbour (simple sampling) resampler, while \fIaverage\fP computes the average of all non-NODATA contributing pixels. \fICubic\fP resampling (available from GDAL 1.7.0) applies [...]
 .PP
 gdaladdo will honour properly NODATA_VALUES tuples (special dataset metadata) so that only a given RGB triplet (in case of a RGB image) will be considered as the nodata value and not each value of the triplet independently per band.
 .PP
diff --git a/man/man1/gdalbuildvrt.1 b/man/man1/gdalbuildvrt.1
index b41c3d0..93efc68 100644
--- a/man/man1/gdalbuildvrt.1
+++ b/man/man1/gdalbuildvrt.1
@@ -1,8 +1,8 @@
-.TH "gdalbuildvrt" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalbuildvrt" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalbuildvrt \- .TH "gdalbuildvrt" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalbuildvrt \- .TH "gdalbuildvrt" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -20,6 +20,7 @@ gdalbuildvrt [-tileindex field_name]
              [-addalpha] [-hidenodata]
              [-srcnodata "value [value...]"] [-vrtnodata "value [value...]"] 
              [-a_srs srs_def]
+             [-r {nearest,bilinear,cubic,cubicspline,lanczos,average,mode}]
              [-input_file_list my_liste.txt] [-overwrite] output.vrt [gdalfile]*
 .fi
 .PP
@@ -79,6 +80,9 @@ In case the resolution of all input files is not the same, the -resolution flag
 .IP "\fB\fB-a_srs\fP \fIsrs_def\fP:\fP" 1c
 (starting with GDAL 1.10) Override the projection for the output file. The \fIsrs_def\fP may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file containing the WKT. 
 .PP
+.IP "\fB\fB-r\fP \fI{nearest (default),bilinear,cubic,cubicspline,lanczos,average,mode}\fP:\fP" 1c
+(GDAL >= 2.0) Select a resampling algorithm.
+.PP
 .IP "\fB\fB-input_file_list\fP:\fP" 1c
 To specify a text file with an input filename on each line 
 .PP
diff --git a/man/man1/gdalcompare.1 b/man/man1/gdalcompare.1
index 3625889..63ced76 100644
--- a/man/man1/gdalcompare.1
+++ b/man/man1/gdalcompare.1
@@ -1,8 +1,8 @@
-.TH "gdalcompare" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalcompare" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalcompare \- .TH "gdalcompare" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalcompare \- .TH "gdalcompare" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdaldem.1 b/man/man1/gdaldem.1
index 8c8f062..e640a70 100644
--- a/man/man1/gdaldem.1
+++ b/man/man1/gdaldem.1
@@ -1,8 +1,8 @@
-.TH "gdaldem" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdaldem" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdaldem \- .TH "gdaldem" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdaldem \- .TH "gdaldem" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdalinfo.1 b/man/man1/gdalinfo.1
index 486cbd1..41b1649 100644
--- a/man/man1/gdalinfo.1
+++ b/man/man1/gdalinfo.1
@@ -1,8 +1,8 @@
-.TH "gdalinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalinfo \- .TH "gdalinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalinfo \- .TH "gdalinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -15,7 +15,7 @@ gdalinfo \- lists information about a raster dataset
 gdalinfo [--help-general] [-mm] [-stats] [-hist] [-nogcp] [-nomd]
          [-norat] [-noct] [-nofl] [-checksum] [-proj4]
          [-listmdd] [-mdd domain|`all`]*
-         [-sd subdataset] datasetname
+         [-sd subdataset] [-oo NAME=VALUE]* datasetname
 .fi
 .PP
 .SH "DESCRIPTION"
@@ -33,7 +33,7 @@ Report histogram information for all bands.
 Suppress ground control points list printing. It may be useful for datasets with huge amount of GCPs, such as L1B AVHRR or HDF4 MODIS which contain thousands of them. 
 .IP "\fB\fB-nomd\fP\fP" 1c
 Suppress metadata printing. Some datasets may contain a lot of metadata strings. 
-.IP "\fB\fB-nrat\fP\fP" 1c
+.IP "\fB\fB-norat\fP\fP" 1c
 Suppress printing of raster attribute table. 
 .IP "\fB\fB-noct\fP\fP" 1c
 Suppress printing of color table. 
@@ -49,6 +49,8 @@ Report metadata for the specified domain. Starting with GDAL 1.11, 'all' can be
 (GDAL >= 1.9.0) If the input dataset contains several subdatasets read and display a subdataset with specified number (starting from 1). This is an alternative of giving the full subdataset name. 
 .IP "\fB\fB-proj4\fP\fP" 1c
 (GDAL >= 1.9.0) Report a PROJ.4 string corresponding to the file's coordinate system. 
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific) 
 .PP
 .PP
 The gdalinfo will report all of the following (if known):
diff --git a/man/man1/gdallocationinfo.1 b/man/man1/gdallocationinfo.1
index c84888b..c502fe3 100644
--- a/man/man1/gdallocationinfo.1
+++ b/man/man1/gdallocationinfo.1
@@ -1,8 +1,8 @@
-.TH "gdallocationinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdallocationinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdallocationinfo \- .TH "gdallocationinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdallocationinfo \- .TH "gdallocationinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -16,7 +16,7 @@ gdallocationinfo \- raster query tool
 Usage: gdallocationinfo [--help-general] [-xml] [-lifonly] [-valonly]
                         [-b band]* [-overview overview_level]
                         [-l_srs srs_def] [-geoloc] [-wgs84]
-                        srcfile [x y]
+                        [-oo NAME=VALUE]* srcfile [x y]
 .fi
 .PP
 .SH "DESCRIPTION"
@@ -47,6 +47,9 @@ Indicates input x,y points are in the georeferencing system of the image.
 .IP "\fB\fB-wgs84\fP: \fP" 1c
 Indicates input x,y points are WGS84 long, lat.
 .PP
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP: \fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific)
+.PP
 .IP "\fB\fIsrcfile\fP:\fP" 1c
 The source GDAL raster datasource name.
 .PP
diff --git a/man/man1/gdalmanage.1 b/man/man1/gdalmanage.1
index 79a1bd7..0615354 100644
--- a/man/man1/gdalmanage.1
+++ b/man/man1/gdalmanage.1
@@ -1,8 +1,8 @@
-.TH "gdalmanage" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalmanage" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalmanage \- .TH "gdalmanage" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalmanage \- .TH "gdalmanage" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdalmove.1 b/man/man1/gdalmove.1
index 526174c..cf9a2d3 100644
--- a/man/man1/gdalmove.1
+++ b/man/man1/gdalmove.1
@@ -1,8 +1,8 @@
-.TH "gdalmove" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalmove" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalmove \- .TH "gdalmove" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalmove \- .TH "gdalmove" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdalsrsinfo.1 b/man/man1/gdalsrsinfo.1
index b4a6cc7..6f832f1 100644
--- a/man/man1/gdalsrsinfo.1
+++ b/man/man1/gdalsrsinfo.1
@@ -1,8 +1,8 @@
-.TH "gdalsrsinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalsrsinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalsrsinfo \- .TH "gdalsrsinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalsrsinfo \- .TH "gdalsrsinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdaltindex.1 b/man/man1/gdaltindex.1
index 6b25fa9..a9fe903 100644
--- a/man/man1/gdaltindex.1
+++ b/man/man1/gdaltindex.1
@@ -1,8 +1,8 @@
-.TH "gdaltindex" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdaltindex" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdaltindex \- .TH "gdaltindex" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdaltindex \- .TH "gdaltindex" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/gdaltransform.1 b/man/man1/gdaltransform.1
index 4adc1c8..8e58aef 100644
--- a/man/man1/gdaltransform.1
+++ b/man/man1/gdaltransform.1
@@ -1,8 +1,8 @@
-.TH "gdaltransform" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdaltransform" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdaltransform \- .TH "gdaltransform" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdaltransform \- .TH "gdaltransform" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -15,7 +15,7 @@ gdaltransform \- transforms coordinates
 gdaltransform [--help-general]
     [-i] [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
     [-order n] [-tps] [-rpc] [-geoloc]
-    [-gcp pixel line easting northing [elevation]]*
+    [-gcp pixel line easting northing [elevation]]* [-output_xy]
     [srcfile [dstfile]]
 .fi
 .PP
@@ -41,6 +41,8 @@ Force use of Geolocation Arrays.
 Inverse transformation: from destination to source. 
 .IP "\fB\fB-gcp\fP\fIpixel line easting northing [elevation]\fP: \fP" 1c
 Provide a GCP to be used for transformation (generally three or more are required) 
+.IP "\fB\fB-output_xy\fP: \fP" 1c
+(GDAL >= 2.0) Restrict output to 'x y' instead of 'x y z' 
 .IP "\fB\fIsrcfile\fP:\fP" 1c
 File with source projection definition or GCP's. If not given, source projection is read from the command-line -s_srs or -gcp parameters  
 .IP "\fB\fIdstfile\fP:\fP" 1c
diff --git a/man/man1/gdalwarp.1 b/man/man1/gdalwarp.1
index 944583c..247cd13 100644
--- a/man/man1/gdalwarp.1
+++ b/man/man1/gdalwarp.1
@@ -1,8 +1,8 @@
-.TH "gdalwarp" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "gdalwarp" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-gdalwarp \- .TH "gdalwarp" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+gdalwarp \- .TH "gdalwarp" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -17,14 +17,15 @@ gdalwarp [--help-general] [--formats]
     [-s_srs srs_def] [-t_srs srs_def] [-to "NAME=VALUE"]
     [-order n | -tps | -rpc | -geoloc] [-et err_threshold]
     [-refine_gcps tolerance [minimum_gcps]]
-    [-te xmin ymin xmax ymax] [-tr xres yres] [-tap] [-ts width height]
-    [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
+    [-te xmin ymin xmax ymax] [-te_srs srs_def]
+    [-tr xres yres] [-tap] [-ts width height]
+    [-ovr level|AUTO|AUTO-n|NONE] [-wo "NAME=VALUE"] [-ot Byte/Int16/...] [-wt Byte/Int16]
     [-srcnodata "value [value...]"] [-dstnodata "value [value...]"] -dstalpha
     [-r resampling_method] [-wm memory_in_mb] [-multi] [-q]
     [-cutline datasource] [-cl layer] [-cwhere expression]
     [-csql statement] [-cblend dist_in_pixels] [-crop_to_cutline]
     [-of format] [-co "NAME=VALUE"]* [-overwrite]
-    [-nomd] [-cvmd meta_conflict_value] [-setci]
+    [-nomd] [-cvmd meta_conflict_value] [-setci] [-oo NAME=VALUE]*
     srcfile* dstfile
 .fi
 .PP
@@ -51,15 +52,19 @@ error threshold for transformation approximation (in pixel units - defaults to 0
 .IP "\fB\fB-refine_gcps\fP \fItolerance minimum_gcps\fP:\fP" 1c
 (GDAL >= 1.9.0) refines the GCPs by automatically eliminating outliers. Outliers will be eliminated until minimum_gcps are left or when no outliers can be detected. The tolerance is passed to adjust when a GCP will be eliminated. Not that GCP refinement only works with polynomial interpolation. The tolerance is in pixel units if no projection is available, otherwise it is in SRS units. If minimum_gcps is not provided, the minimum GCPs according to the polynomial model is used. 
 .IP "\fB\fB-te\fP \fIxmin ymin xmax ymax\fP:\fP" 1c
-set georeferenced extents of output file to be created (in target SRS). 
+set georeferenced extents of output file to be created (in target SRS by default, or in the SRS specified with -te_srs)  
+.IP "\fB\fB-te_srs\fP \fIsrs_def\fP:\fP" 1c
+(GDAL >= 2.0) Specifies the SRS in which to interpret the coordinates given with -te. The \fIsrs_def\fP may be any of the usual GDAL/OGR forms, complete WKT, PROJ.4, EPSG:n or a file containing the WKT. This must not be confused with -t_srs which is the target SRS of the output dataset. -te_srs is a conveniency e.g. when knowing the output coordinates in a geodetic long/lat SRS, but still wanting a result in a projected coordinate system.  
 .IP "\fB\fB-tr\fP \fIxres yres\fP:\fP" 1c
 set output file resolution (in target georeferenced units) 
 .IP "\fB\fB-tap\fP:\fP" 1c
 (GDAL >= 1.8.0) (target aligned pixels) align the coordinates of the extent of the output file to the values of the -tr, such that the aligned extent includes the minimum extent. 
 .IP "\fB\fB-ts\fP \fIwidth height\fP:\fP" 1c
 set output file size in pixels and lines. If width or height is set to 0, the other dimension will be guessed from the computed resolution. Note that -ts cannot be used with -tr 
+.IP "\fB\fB-ovr\fP \fIlevel|AUTO|AUTO-n|NONE>\fP:\fP" 1c
+(GDAL >= 2.0) To specify which overview level of source files must be used. The default choice, AUTO, will select the overview level whose resolution is the closest to the target resolution. Specify an integer value (0-based, i.e. 0=1st overview level) to select a particular level. Specify AUTO-n where n is an integer greater or equal to 1, to select an overview level below the AUTO one. Or specify NONE to force the base resolution to be used. 
 .IP "\fB\fB-wo\fP \fI'NAME=VALUE'\fP:\fP" 1c
-Set a warp options. The GDALWarpOptions::papszWarpOptions docs show all options. Multiple \fB-wo\fP options may be listed. 
+Set a warp option. The GDALWarpOptions::papszWarpOptions docs show all options. Multiple \fB-wo\fP options may be listed. 
 .IP "\fB\fB-ot\fP \fItype\fP:\fP" 1c
 For the output bands to be of the indicated data type. 
 .IP "\fB\fB-wt\fP \fItype\fP:\fP" 1c
@@ -80,11 +85,21 @@ Lanczos windowed sinc resampling.
 average resampling, computes the average of all non-NODATA contributing pixels. (GDAL >= 1.10.0) 
 .IP "\fB\fBmode\fP: \fP" 1c
 mode resampling, selects the value which appears most often of all the sampled points. (GDAL >= 1.10.0) 
+.IP "\fB\fBmax\fP: \fP" 1c
+maximum resampling, selects the maximum value from all non-NODATA contributing pixels. (GDAL >= 2.0.0) 
+.IP "\fB\fBmin\fP: \fP" 1c
+minimum resampling, selects the minimum value from all non-NODATA contributing pixels. (GDAL >= 2.0.0) 
+.IP "\fB\fBmed\fP: \fP" 1c
+median resampling, selects the median value of all non-NODATA contributing pixels. (GDAL >= 2.0.0) 
+.IP "\fB\fBq1\fP: \fP" 1c
+first quartile resampling, selects the first quartile value of all non-NODATA contributing pixels. (GDAL >= 2.0.0) 
+.IP "\fB\fBq3\fP: \fP" 1c
+third quartile resampling, selects the third quartile value of all non-NODATA contributing pixels. (GDAL >= 2.0.0) 
 .PP
 .IP "\fB\fB-srcnodata\fP \fIvalue [value...]\fP:\fP" 1c
 Set nodata masking values for input bands (different values can be supplied for each band). If more than one value is supplied all values should be quoted to keep them together as a single operating system argument. Masked values will not be used in interpolation. Use a value of \fCNone\fP to ignore intrinsic nodata settings on the source dataset. 
 .IP "\fB\fB-dstnodata\fP \fIvalue [value...]\fP:\fP" 1c
-Set nodata values for output bands (different values can be supplied for each band). If more than one value is supplied all values should be quoted to keep them together as a single operating system argument. New files will be initialized to this value and if possible the nodata value will be recorded in the output file. Use a value of \fCNone\fP to ensure that nodata is not defined (GDAL>=2.0). If this argument is not used then nodata values will be copied from the source dataset (GDAL>=2.0). 
+Set nodata values for output bands (different values can be supplied for each band). If more than one value is supplied all values should be quoted to keep them together as a single operating system argument. New files will be initialized to this value and if possible the nodata value will be recorded in the output file. Use a value of \fCNone\fP to ensure that nodata is not defined (GDAL>=1.11). If this argument is not used then nodata values will be copied from the source dataset (GDAL [...]
 .IP "\fB\fB-dstalpha\fP:\fP" 1c
 Create an output alpha band to identify nodata (unset/transparent) pixels.  
 .IP "\fB\fB-wm\fP \fImemory_in_mb\fP:\fP" 1c
@@ -117,7 +132,9 @@ Set a blend distance to use to blend over cutlines (in pixels).
 .IP "\fB\fB-cvmd\fP \fImeta_conflict_value\fP:\fP" 1c
 (GDAL >= 1.10.0) Value to set metadata items that conflict between source datasets (default is '*'). Use '' to remove conflicting items.  
 .IP "\fB\fB-setci\fP:\fP" 1c
-(GDAL >= 1.10.0) Set the color interpretation of the bands of the target dataset from the source dataset.
+(GDAL >= 1.10.0) Set the color interpretation of the bands of the target dataset from the source dataset. 
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific)
 .PP
 .IP "\fB\fIsrcfile\fP:\fP" 1c
 The source file name(s).  
@@ -125,7 +142,7 @@ The source file name(s).
 The destination file name.  
 .PP
 .PP
-Mosaicing into an existing output file is supported if the output file already exists. The spatial extent of the existing file will not be modified to accomodate new data, so you may have to remove it in that case, or use the -overwrite option.
+Mosaicing into an existing output file is supported if the output file already exists. The spatial extent of the existing file will not be modified to accommodate new data, so you may have to remove it in that case, or use the -overwrite option.
 .PP
 Polygon cutlines may be used as a mask to restrict the area of the destination file that may be updated, including blending. If the OGR layer containing the cutline features has no explicit SRS, the cutline features must be in the SRS of the destination file. When outputing to a not yet existing target dataset, its extent will be the one of the original raster unless -te or -crop_to_cutline are specified.
 .SH "EXAMPLE"
@@ -147,6 +164,9 @@ For instance, the second channel of an ASTER image stored in HDF with control po
 gdalwarp HDF4_SDS:ASTER_L1B:"pg-PR1B0000-2002031402_100_001":2 pg-PR1B0000-2002031402_100_001_2.tif
 .fi
 .PP
+.SH "SEE ALSO"
+.PP
+http://trac.osgeo.org/gdal/wiki/UserDocs/GdalWarp : Wiki page discussing options and behaviours of gdalwarp
 .SH "AUTHORS"
 .PP
 Frank Warmerdam <warmerdam at pobox.com>, Silke Reimer <silke at intevation.de> 
diff --git a/man/man1/nearblack.1 b/man/man1/nearblack.1
index fa0729a..340300c 100644
--- a/man/man1/nearblack.1
+++ b/man/man1/nearblack.1
@@ -1,8 +1,8 @@
-.TH "nearblack" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "nearblack" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-nearblack \- .TH "nearblack" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+nearblack \- .TH "nearblack" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/ogr2ogr.1 b/man/man1/ogr2ogr.1
index 885e4c4..cefb0f5 100644
--- a/man/man1/ogr2ogr.1
+++ b/man/man1/ogr2ogr.1
@@ -1,8 +1,8 @@
-.TH "ogr2ogr" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "ogr2ogr" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-ogr2ogr \- .TH "ogr2ogr" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+ogr2ogr \- .TH "ogr2ogr" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -21,10 +21,13 @@ Usage: ogr2ogr [--help-general] [-skipfailures] [-append] [-update]
                [-a_srs srs_def] [-t_srs srs_def] [-s_srs srs_def]
                [-f format_name] [-overwrite] [[-dsco NAME=VALUE] ...]
                dst_datasource_name src_datasource_name
-               [-lco NAME=VALUE] [-nln name] [-nlt type] [-dim 2|3|layer_dim] [layer [layer ...]]
+               [-lco NAME=VALUE] [-nln name]
+               [-nlt type|PROMOTE_TO_MULTI|CONVERT_TO_LINEAR]
+               [-dim 2|3|layer_dim] [layer [layer ...]]
 
 Advanced options :
                [-gt n]
+               [[-oo NAME=VALUE] ...] [[-doo NAME=VALUE] ...]
                [-clipsrc [xmin ymin xmax ymax]|WKT|datasource|spat_extent]
                [-clipsrcsql sql_statement] [-clipsrclayer layer]
                [-clipsrcwhere expression]
@@ -33,12 +36,15 @@ Advanced options :
                [-clipdstwhere expression]
                [-wrapdateline] [-datelineoffset val]
                [[-simplify tolerance] | [-segmentize max_dist]]
-               [-addfields]
+               [-addfields] [-unsetFid]
+               [-relaxedFieldNameMatch] [-forceNullable] [-unsetDefault]
                [-fieldTypeToString All|(type1[,type2]*)] [-unsetFieldWidth]
+               [-mapFieldType type1|All=type2[,type3=type4]*]
                [-fieldmap identity | index1[,index2]*]
                [-splitlistfields] [-maxsubfields val]
                [-explodecollections] [-zfield field_name]
                [-gcp pixel line easting northing [elevation]]* [-order n | -tps]
+               [-nomd] [-mo \"META-TAG=VALUE\"]*
 
 .fi
 .PP
@@ -89,7 +95,7 @@ Layer creation option (format specific)
 .IP "\fB\fB-nln\fP\fI name\fP:\fP" 1c
 Assign an alternate name to the new layer 
 .IP "\fB\fB-nlt\fP\fI type\fP:\fP" 1c
-Define the geometry type for the created layer. One of NONE, GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT, MULTIPOLYGON or MULTILINESTRING. Add '25D' to the name to get 2.5D versions. Starting with GDAL 1.10, PROMOTE_TO_MULTI can be used to automatically promote layers that mix polygon or multipolygons to multipolygons, and layers that mix linestrings or multilinestrings to multilinestrings. Can be usefull when converting shapefiles to PostGIS (and other target dr [...]
+Define the geometry type for the created layer. One of NONE, GEOMETRY, POINT, LINESTRING, POLYGON, GEOMETRYCOLLECTION, MULTIPOINT, MULTIPOLYGON or MULTILINESTRING. And CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE and MULTISURFACE for GDAL 2.0 non-linear geometry types. Add '25D' to the name to get 2.5D versions. Starting with GDAL 1.10, PROMOTE_TO_MULTI can be used to automatically promote layers that mix polygon or multipolygons to multipolygons, and layers that mix linestrin [...]
 .IP "\fB\fB-dim\fP\fI val\fP:\fP" 1c
 (starting with GDAL 1.10) Force the coordinate dimension to val (valid values are 2 or 3). This affects both the layer geometry type, and feature geometries. Starting with GDAL 1.11, the value can be set to 'layer_dim' to instruct feature geometries to be promoted to the coordinate dimension declared by the layer.  
 .IP "\fB\fB-a_srs\fP\fI srs_def\fP:\fP" 1c
@@ -99,7 +105,7 @@ Reproject/transform to this SRS on output
 .IP "\fB\fB-s_srs\fP\fI srs_def\fP:\fP" 1c
 Override source SRS 
 .IP "\fB\fB-preserve_fid\fP:\fP" 1c
-Use the FID of the source features instead of letting the output driver to automatically assign a new one. 
+Use the FID of the source features instead of letting the output driver to automatically assign a new one. Note: starting with GDAL 2.0, if not in append mode, this behaviour becomes the default if the output driver has a FID layer creation option. In which case the name of the source FID column will be used and source feature IDs will be attempted to be preserved. This behaviour can be disabled by setting -unsetFid 
 .IP "\fB\fB-fid\fP \fIfid\fP:\fP" 1c
 If provided, only the feature with this feature id will be reported. Operates exclusive of the spatial or attribute queries. Note: if you want to select several features based on their feature id, you can also use the fact the 'fid' is a special field recognized by OGR SQL. So, '-where 'fid in (1,3,5)'' would select features 1, 3 and 5. 
 .PP
@@ -108,6 +114,10 @@ Srs_def can be a full WKT definition (hard to escape properly), or a well known
 .PP
 Advanced options :
 .PP
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Input dataset open option (format specific) 
+.IP "\fB\fB-doo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Destination dataset open option (format specific), only valid in -update mode 
 .IP "\fB\fB-gt\fP \fIn\fP:\fP" 1c
 group \fIn\fP features per transaction (default 20000 in OGR 1.11, 200 in previous releases). Increase the value for better performance when writing into DBMS drivers that have transaction support. 
 .IP "\fB\fB-clipsrc\fP\fI [xmin ymin xmax ymax]|WKT|datasource|spat_extent\fP: \fP" 1c
@@ -135,7 +145,9 @@ Restrict desired geometries based on attribute query.
 .IP "\fB\fB-segmentize\fP\fI max_dist\fP:\fP" 1c
 (starting with GDAL 1.6.0) maximum distance between 2 nodes. Used to create intermediate points 
 .IP "\fB\fB-fieldTypeToString\fP\fI type1, ...\fP:\fP" 1c
-(starting with GDAL 1.7.0) converts any field of the specified type to a field of type string in the destination layer. Valid types are : Integer, Real, String, Date, Time, DateTime, Binary, IntegerList, RealList, StringList. Special value \fBAll\fP can be used to convert all fields to strings. This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query. 
+(starting with GDAL 1.7.0) converts any field of the specified type to a field of type string in the destination layer. Valid types are : Integer, Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Special value \fBAll\fP can be used to convert all fields to strings. This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query. Note that this does not influence the field types used by the sour [...]
+.IP "\fB\fB-mapFieldType\fP\fI srctype|All=dsttype, ...\fP:\fP" 1c
+(starting with GDAL 2.0) converts any field of the specified type to another type. Valid types are : Integer, Integer64, Real, String, Date, Time, DateTime, Binary, IntegerList, Integer64List, RealList, StringList. Types can also include subtype between parenthesis, such as Integer(Boolean), Real(Float32), ... Special value \fBAll\fP can be used to convert all fields to another type. This is an alternate way to using the CAST operator of OGR SQL, that may avoid typing a long SQL query. T [...]
 .IP "\fB\fB-unsetFieldWidth\fP:\fP" 1c
 (starting with GDAL 1.11) set field width and precision to 0. 
 .IP "\fB\fB-splitlistfields\fP:\fP" 1c
@@ -155,7 +167,20 @@ To be combined with -splitlistfields to limit the number of subfields created fo
 .IP "\fB\fB-fieldmap\fP:\fP" 1c
 (starting with GDAL 1.10.0) Specifies the list of field indexes to be copied from the source to the destination. The (n)th value specified in the list is the index of the field in the target layer definition in which the n(th) field of the source layer must be copied. Index count starts at zero. There must be exactly as many values in the list as the count of the fields in the source layer. We can use the 'identity' setting to specify that the fields should be transferred by using the sa [...]
 .IP "\fB\fB-addfields\fP:\fP" 1c
-(starting with GDAL 1.11) This is a specialized version of -append. Contrary to -append, -addfields has the effect of adding, to existing target layers, the new fields found in source layers. This option is usefull when merging files that have non-strictly identical structures. This might not work for output formats that don't support adding fields to existing non-empty layers. 
+(starting with GDAL 1.11) This is a specialized version of -append. Contrary to -append, -addfields has the effect of adding, to existing target layers, the new fields found in source layers. This option is useful when merging files that have non-strictly identical structures. This might not work for output formats that don't support adding fields to existing non-empty layers. 
+.IP "\fB\fB-relaxedFieldNameMatch\fP:\fP" 1c
+(starting with GDAL 1.11) Do field name matching between source and existing target layer in a more relaxed way if the target driver has an implementation for it. [-relaxedFieldNameMatch] [-forceNullable] 
+.IP "\fB\fB-forceNullable\fP:\fP" 1c
+(starting with GDAL 2.0) Do not propagate not-nullable constraints to target layer if they exist in source layer.. 
+.IP "\fB\fB-unsetDefault\fP:\fP" 1c
+(starting with GDAL 2.0) Do not propagate default field values to target layer if they exist in source layer.. 
+.IP "\fB\fB-unsetFid\fP:\fP" 1c
+(starting with GDAL 2.0) Can be specify to prevent the new default behaviour that consists in, if the output driver has a FID layer creation option and we are not in append mode, to preserve the name of the source FID column and source feature IDs 
+.IP "\fB\fB-nomd\fP:\fP" 1c
+(starting with GDAL 2.0) To disable copying of metadata from source dataset and layers into target dataset and layers, when supported by output driver. 
+.IP "\fB\fB-mo\fP \fI'META-TAG=VALUE'\fP:\fP" 1c
+(starting with GDAL 2.0) Passes a metadata key and value to set on the output dataset, when supported by output driver.
+.PP
 .PP
 .SH "PERFORMANCE HINTS"
 .PP
diff --git a/man/man1/ogr_utilities.1 b/man/man1/ogr_utilities.1
index 7b3daf1..6b26a09 100644
--- a/man/man1/ogr_utilities.1
+++ b/man/man1/ogr_utilities.1
@@ -1,8 +1,8 @@
-.TH "ogr_utilities" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "ogr_utilities" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-ogr_utilities \- .TH "ogr_utilities" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+ogr_utilities \- .TH "ogr_utilities" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/ogrinfo.1 b/man/man1/ogrinfo.1
index 8398f67..5a1e517 100644
--- a/man/man1/ogrinfo.1
+++ b/man/man1/ogrinfo.1
@@ -1,8 +1,8 @@
-.TH "ogrinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "ogrinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-ogrinfo \- .TH "ogrinfo" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+ogrinfo \- .TH "ogrinfo" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -16,7 +16,9 @@ ogrinfo \- lists information about an OGR supported data source
 ogrinfo [--help-general] [-ro] [-q] [-where restricted_where]
         [-spat xmin ymin xmax ymax] [-geomfield field] [-fid fid]
         [-sql statement] [-dialect dialect] [-al] [-so] [-fields={YES/NO}]
-        [-geom={YES/NO/SUMMARY}][--formats]
+        [-geom={YES/NO/SUMMARY}] [-formats] [[-oo NAME=VALUE] ...]
+        [-nomd] [-listmdd] [-mdd domain|`all`]*
+        [-nocount] [-noextent]
         datasource_name [layer [layer ...]]
 
 .fi
@@ -30,7 +32,7 @@ Open the data source in read-only mode.
 .IP "\fB\fB-al\fP:\fP" 1c
 List all features of all layers (used instead of having to give layer names as arguments). 
 .IP "\fB\fB-so\fP:\fP" 1c
-Summary Only: supress listing of features, show only the summary information like projection, schema, feature count and extents. 
+Summary Only: suppress listing of features, show only the summary information like projection, schema, feature count and extents. 
 .IP "\fB\fB-q\fP:\fP" 1c
 Quiet verbose reporting of various information, including coordinate system, layer schema, extents, and feature count.  
 .IP "\fB\fB-where\fP \fIrestricted_where\fP:\fP" 1c
@@ -49,6 +51,18 @@ If provided, only the feature with this feature id will be reported. Operates ex
 (starting with GDAL 1.6.0) If set to NO, the feature dump will not display field values. Default value is YES. 
 .IP "\fB\fB-geom\fP={YES/NO/SUMMARY}:\fP" 1c
 (starting with GDAL 1.6.0) If set to NO, the feature dump will not display the geometry. If set to SUMMARY, only a summary of the geometry will be displayed. If set to YES, the geometry will be reported in full OGC WKT format. Default value is YES. 
+.IP "\fB\fB-oo\fP \fINAME=VALUE\fP:\fP" 1c
+(starting with GDAL 2.0) Dataset open option (format specific) 
+.IP "\fB\fB-nomd\fP\fP" 1c
+(starting with GDAL 2.0) Suppress metadata printing. Some datasets may contain a lot of metadata strings. 
+.IP "\fB\fB-listmdd\fP\fP" 1c
+(starting with GDAL 2.0) List all metadata domains available for the dataset. 
+.IP "\fB\fB-mdd domain\fP\fP" 1c
+(starting with GDAL 2.0) Report metadata for the specified domain. 'all' can be used to report metadata in all domains 
+.IP "\fB\fB-nocount\fP\fP" 1c
+(starting with GDAL 2.0) Suppress feature count printing. 
+.IP "\fB\fB-noextent\fP\fP" 1c
+(starting with GDAL 2.0) Suppress spatial extent printing. 
 .IP "\fB\fB--formats\fP:\fP" 1c
 List the format drivers that are enabled. 
 .IP "\fB\fIdatasource_name\fP:\fP" 1c
diff --git a/man/man1/ogrlineref.1 b/man/man1/ogrlineref.1
index 062c486..2c3f82a 100644
--- a/man/man1/ogrlineref.1
+++ b/man/man1/ogrlineref.1
@@ -1,8 +1,8 @@
-.TH "ogrlineref" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "ogrlineref" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-ogrlineref \- .TH "ogrlineref" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+ogrlineref \- .TH "ogrlineref" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -43,7 +43,7 @@ Show the usage.
 .IP "\fB\fB-progress\fP:\fP" 1c
 Show progress. 
 .IP "\fB\fB-quiet\fP:\fP" 1c
-Supress all messages except errors and results. 
+Suppress all messages except errors and results. 
 .IP "\fB\fB-f\fP \fIformat_name\fP:\fP" 1c
 Select an output format name. The default is to create a shapefile. 
 .IP "\fB\fB-dsco\fP \fINAME=VALUE\fP:\fP" 1c
diff --git a/man/man1/ogrtindex.1 b/man/man1/ogrtindex.1
index a40c7e9..da86152 100644
--- a/man/man1/ogrtindex.1
+++ b/man/man1/ogrtindex.1
@@ -1,8 +1,8 @@
-.TH "ogrtindex" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "ogrtindex" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-ogrtindex \- .TH "ogrtindex" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+ogrtindex \- .TH "ogrtindex" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
@@ -34,6 +34,8 @@ The name to use for the dataset name. Defaults to LOCATION.
 Filenames are written with absolute paths 
 .IP "\fB\fB-skip_different_projection\fP:\fP" 1c
 Only layers with same projection ref as layers already inserted in the tileindex will be inserted. 
+.IP "\fB\fB-accept_different_schemas\fP:\fP" 1c
+By default ogrtindex checks that all layers inserted into the index have the same attribute schemas. If you specify this option, this test will be disabled. Be aware that resulting index may be incompatible with MapServer! 
 .PP
 .PP
 If no -lnum or -lname arguments are given it is assumed that all layers in source datasets should be added to the tile index as independent records.
diff --git a/man/man1/pct2rgb.1 b/man/man1/pct2rgb.1
index 84c3faa..c5eee33 100644
--- a/man/man1/pct2rgb.1
+++ b/man/man1/pct2rgb.1
@@ -1,8 +1,8 @@
-.TH "pct2rgb" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "pct2rgb" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-pct2rgb \- .TH "pct2rgb" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+pct2rgb \- .TH "pct2rgb" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/man/man1/rgb2pct.1 b/man/man1/rgb2pct.1
index fdb9ce6..eccbeb1 100644
--- a/man/man1/rgb2pct.1
+++ b/man/man1/rgb2pct.1
@@ -1,8 +1,8 @@
-.TH "rgb2pct" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+.TH "rgb2pct" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
-rgb2pct \- .TH "rgb2pct" 1 "Tue Feb 10 2015" "GDAL" \" -*- nroff -*-
+rgb2pct \- .TH "rgb2pct" 1 "Mon May 4 2015" "GDAL" \" -*- nroff -*-
 .ad l
 .nh
 .SH NAME
diff --git a/nmake.opt b/nmake.opt
index ba1ecc4..7eb7d86 100644
--- a/nmake.opt
+++ b/nmake.opt
@@ -1,4 +1,4 @@
-# $Id: nmake.opt 28317 2015-01-15 22:49:41Z tamas $
+# $Id: nmake.opt 28874 2015-04-08 15:10:44Z dron $
 #
 # nmake.opt - main configuration file for NMAKE makefiles.
 #
@@ -31,6 +31,7 @@
 # Check version of Visual C++ compiler:
 # nmake -f makefile.vc MSVC_VER=xxxx
 # where xxxx is one of following:
+# 1900 = 14.0(2015)
 # 1800 = 12.0(2013)
 # 1700 = 11.0(2012)
 # 1600 = 10.0(2010)
@@ -141,7 +142,7 @@ OPTFLAGS= $(CXX_PDB_FLAGS) /nologo /MD /EHsc /GR /DDEBUG
 !ENDIF  # OPTFLAGS
 
 # 
-# Set flags controlling warnings level, and supression of some warnings.
+# Set flags controlling warnings level, and suppression of some warnings.
 # 
 !IFNDEF WARNFLAGS
 WARNFLAGS =	/W4 /wd4127 /wd4251 /wd4275 /wd4786 /wd4100 /wd4245 /wd4206 /wd4018 /wd4389
@@ -176,8 +177,9 @@ LDEBUG= /debug
 STDCALL=YES
 
 # Version number embedded in DLL name. 
+# If GDAL version is X.Y.Z, VERSION = X * 100 + Y
 !IFNDEF VERSION
-VERSION =	111
+VERSION =	200
 !ENDIF
 
 # Comment the following out if you want PAM supported disabled
@@ -349,12 +351,22 @@ JPEG12_SUPPORTED = 1
 #HDF4_PLUGIN = NO
 #HDF4_DIR =	D:\warmerda\HDF41r5
 #HDF4_LIB =	/LIBPATH:$(HDF4_DIR)\lib Ws2_32.lib
+# HDF4 library newer than 4.2.5 has a SDreset_maxopenfiles/SDget_maxopenfiles
+# interface which allows to open many HDF files simultaneously (the max
+# number of files was previously hardcoded and too low, smth. like 32).
+# Uncomment following if your library is newer than 4.2.5.
+#HDF4_HAS_MAXOPENFILES = YES
 
 # Uncomment the following and update to enable NCSA HDF Release 5 support.
 #HDF5_PLUGIN = NO
 #HDF5_DIR =	c:\warmerda\supportlibs\hdf5\5-164-win
 #HDF5_LIB =	$(HDF5_DIR)\dll\hdf5dll.lib 
 
+# Uncomment the following and update to enable KEA support.
+#KEA_PLUGIN = NO
+#KEA_CFLAGS = -Ic:\kea\include
+#KEA_LIB = c:\kea\libkea.lib 
+
 # Uncomment the following for MrSID support.  Only MRSID_DIR is required,
 # which may point to a MrSID Raster SDK, Lidar SDK, or the combined SDK, and
 # will auto-configure the mrsid and/or mrsid_lidar drivers as appropriate.
@@ -542,6 +554,8 @@ OCI_INCLUDE =	-I$(ORACLE_HOME)\oci\include
 #PODOFO_ENABLED = YES
 #PODOFO_CFLAGS = -Ie:/podofo-svn/install/include -Ie:/podofo-svn/install/include/podofo
 #PODOFO_LIBS = e:/podofo-svn/install/lib/podofo.lib E:/release-1500-dev/release-1500/lib/freetype239.lib gdi32.lib
+# Build PDF driver as plugin
+#PDF_PLUGIN = NO
 
 # Uncomment for LZMA TIFF support
 #LZMA_CFLAGS = -IC:/gdal_trunk/xz-5.0.0-windows/include
@@ -608,7 +622,7 @@ OGR_FLAG = -DOGR_ENABLED
 LINKER_FLAGS = $(EXTRA_LINKER_FLAGS) $(MSVC_VLD_LIB) $(LDEBUG)
 
 
-CFLAGS	=	$(OPTFLAGS) $(WARNFLAGS) $(SSEFLAGS) $(INC) $(EXTRAFLAGS) $(OGR_FLAG) $(MSVC_VLD_FLAGS)
+CFLAGS	=	$(OPTFLAGS) $(WARNFLAGS) $(SSEFLAGS) $(INC) $(EXTRAFLAGS) $(OGR_FLAG) $(MSVC_VLD_FLAGS) -DGDAL_COMPILATION
 CPPFLAGS = $(CFLAGS) 
 MAKE	=	nmake /nologo
 
@@ -654,6 +668,22 @@ FITS_LIB_LINK =
 !ENDIF
 !ENDIF
 
+!IFDEF POPPLER_LIBS
+!IF "$(PDF_PLUGIN)" != "YES"
+PDF_LIB_LINK = $(POPPLER_LIBS)
+!ELSE
+PDF_LIB_LINK =
+!ENDIF
+!ENDIF
+
+!IFDEF PODOFO_LIBS
+!IF "$(PDF_PLUGIN)" != "YES"
+PDF_LIB_LINK = $(PODOFO_LIBS)
+!ELSE
+PDF_LIB_LINK =
+!ENDIF
+!ENDIF
+
 !IFDEF NETCDF_LIB
 !IF "$(NETCDF_PLUGIN)" != "YES"
 NETCDF_LIB_LINK = $(NETCDF_LIB)
@@ -678,6 +708,14 @@ HDF5_LIB_LINK =
 !ENDIF
 !ENDIF
 
+!IFDEF KEA_LIB
+!IF "$(KEA_PLUGIN)" != "YES"
+KEA_LIB_LINK = $(KEA_LIB)
+!ELSE
+KEA_LIB_LINK =
+!ENDIF
+!ENDIF
+
 !IFDEF FGDB_LIB
 !IF "$(FGDB_PLUGIN)" != "YES"
 FGDB_LIB_LINK = $(FGDB_LIB)
@@ -702,10 +740,10 @@ EXTERNAL_LIBS =	$(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \
 	$(ECW_LIB_LINK) $(HDF4_LIB_LINK) $(FME_LIB) $(MRSID_LIB_LINK) \
 	$(FITS_LIB_LINK) $(JPEG_LIB) $(NETCDF_LIB_LINK) $(PROJ4_LIB) \
 	$(GEOTIFF_LIB) $(TIFF_LIB) $(PROJ_LIBRARY) $(SQLITE_LIB) \
-	$(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(SDE_LIB) $(ARCOBJECTS_LIB) $(DWG_LIB) \
+	$(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(KEA_LIB_LINK) $(SDE_LIB) $(ARCOBJECTS_LIB) $(DWG_LIB) \
 	$(IDB_LIB) $(CURL_LIB) $(DODS_LIB) $(KAKLIB) $(PCIDSK_LIB) \
 	$(ODBCLIB) $(JASPER_LIB) $(PNG_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \
-	$(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(POPPLER_LIBS) $(PODOFO_LIBS) $(LZMA_LIBS) \
+	$(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) \
 	$(LIBICONV_LIBRARY) $(WEBP_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \
 	$(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) ws2_32.lib
 		
diff --git a/ogr/GNUmakefile b/ogr/GNUmakefile
index 4c904e0..d4d4045 100644
--- a/ogr/GNUmakefile
+++ b/ogr/GNUmakefile
@@ -25,7 +25,7 @@ else
 ZLIB_XTRA_OPT =
 endif
 
-CPPFLAGS	:=	-Iogrsf_frmts -Iogrsf_frmts/mem -I. $(GDAL_INCLUDE) $(PROJ_INCLUDE) $(PROJ_FLAGS) $(CPPFLAGS) $(ZLIB_XTRA_OPT)
+CPPFLAGS	:=	-Iogrsf_frmts -Iogrsf_frmts/mem -I.  $(PROJ_INCLUDE) $(PROJ_FLAGS) $(CPPFLAGS) $(ZLIB_XTRA_OPT)
 
 default:	lib
 
@@ -53,20 +53,16 @@ sublibs:
 else
 
 sublibs:
+	(cd ogrsf_frmts/mitab; $(MAKE))
+	(cd ogrsf_frmts/generic; $(MAKE))
 
 endif
 
 docs:
-	rm -rf html/*
-	doxygen
-	cp ogrsf_frmts/*/drv_*.html html
-	cp ogrsf_frmts/ogr_formats.html html
-	cp ogr_feature_style.html html
+	echo "This target does not exist anymore. Use top-level"
 
 install-docs:
-	$(INSTALL_DIR) $(DESTDIR)$(INST_DOCS)/ogr
-	cp html/* $(DESTDIR)$(INST_DOCS)/ogr
-	cp ../doc/ogr/*.gif $(DESTDIR)$(INST_DOCS)/ogr
+	echo "This target does not exist anymore. Use top-level"
 
 gdalso:	$(GDAL_SLIB)
 
@@ -74,11 +70,7 @@ $(GDAL_SLIB):
 	(cd ..; $(MAKE) check-lib)
 
 web-update:	docs
-	$(INSTALL_DIR) $(INST_HTML)/ogr
-	cp html/* $(INST_HTML)/ogr
-	cp ogrsf_frmts/*/drv_*.html $(INST_HTML)/ogr
-	cp ogrsf_frmts/ogr_formats.html $(INST_HTML)/ogr
-	cp ../doc/ogr/*.gif $(INST_HTML)/ogr
+	echo "This target does not exist anymore. Use top-level"
 
 install:
 	for f in $(INST_H_FILES) ; \
diff --git a/ogr/file.lst b/ogr/file.lst
index 52b5cd4..d9db14e 100644
--- a/ogr/file.lst
+++ b/ogr/file.lst
@@ -11,6 +11,12 @@ OBJ =	ogrgeometryfactory.o \
 	ogrsurface.o \
 	ogrmultipoint.o \
 	ogrmultilinestring.o \
+    ogrcircularstring.o \
+    ogrcompoundcurve.o \
+    ogrcurvepolygon.o \
+    ogrcurvecollection.o \
+    ogrmulticurve.o \
+    ogrmultisurface.o \
 	ogr_api.o \
 	ogrfeature.o \
 	ogrfeaturedefn.o \
@@ -47,4 +53,5 @@ OBJ =	ogrgeometryfactory.o \
 	ogr_geocoding.o \
     osr_cs_wkt.o \
 	osr_cs_wkt_parser.o \
-    ogrgeomfielddefn.o
+    ogrgeomfielddefn.o \
+    ograpispy.o
diff --git a/ogr/gml2ogrgeometry.cpp b/ogr/gml2ogrgeometry.cpp
index 07c8d7a..7ab4e00 100644
--- a/ogr/gml2ogrgeometry.cpp
+++ b/ogr/gml2ogrgeometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gml2ogrgeometry.cpp 27908 2014-10-26 13:06:58Z rouault $
+ * $Id: gml2ogrgeometry.cpp 28751 2015-03-20 15:21:49Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Code to translate between GML and OGR geometry forms.
@@ -46,6 +46,7 @@
 #include "cpl_string.h"
 #include <ctype.h>
 #include "ogr_p.h"
+#include "ogrsf_frmts/xplane/ogr_xplane_geo_utils.h"
 
 #ifndef PI
 #define PI  3.14159265358979323846
@@ -233,12 +234,13 @@ static int AddPoint( OGRGeometry *poGeometry,
         return TRUE;
     }
                 
-    else if( eType == wkbLineString )
+    else if( eType == wkbLineString ||
+             eType == wkbCircularString )
     {
         if( nDimension == 3 )
-            ((OGRLineString *) poGeometry)->addPoint( dfX, dfY, dfZ );
+            ((OGRSimpleCurve *) poGeometry)->addPoint( dfX, dfY, dfZ );
         else
-            ((OGRLineString *) poGeometry)->addPoint( dfX, dfY );
+            ((OGRSimpleCurve *) poGeometry)->addPoint( dfX, dfY );
 
         return TRUE;
     }
@@ -254,7 +256,8 @@ static int AddPoint( OGRGeometry *poGeometry,
 /*                        ParseGMLCoordinates()                         */
 /************************************************************************/
 
-static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeometry )
+static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeometry,
+                                int nSRSDimension )
 
 {
     const CPLXMLNode *psCoordinates = FindBareXMLChild( psGeomNode, "coordinates" );
@@ -413,10 +416,11 @@ static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeo
                 if( psPointPropertyIter->eType != CXT_Element  )
                     continue;
 
-                if (EQUAL(BareGMLElement(psPointPropertyIter->pszValue),"Point") )
+                const char* pszBareElement = BareGMLElement(psPointPropertyIter->pszValue);
+                if (EQUAL(pszBareElement,"Point") || EQUAL(pszBareElement,"ElevatedPoint") )
                 {
                     OGRPoint oPoint;
-                    if( ParseGMLCoordinates( psPointPropertyIter, &oPoint ) )
+                    if( ParseGMLCoordinates( psPointPropertyIter, &oPoint, nSRSDimension ) )
                     {
                         int bSuccess = AddPoint( poGeometry, oPoint.getX(),
                                                  oPoint.getY(), oPoint.getZ(),
@@ -428,6 +432,16 @@ static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeo
                     }
                 }
             }
+
+            if( psPos->psChild && psPos->psChild->eType == CXT_Attribute &&
+                psPos->psChild->psNext == NULL &&
+                strcmp(psPos->psChild->pszValue, "xlink:href") == 0 )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Cannot resolve xlink:href='%s'. Try setting GML_SKIP_RESOLVE_ELEMS=NONE",
+                         psPos->psChild->psChild->pszValue);
+            }
+
             continue;
         }
 
@@ -490,6 +504,8 @@ static int ParseGMLCoordinates( const CPLXMLNode *psGeomNode, OGRGeometry *poGeo
             pszSRSDimension = CPLGetXMLValue( (CPLXMLNode*) psGeomNode, "srsDimension", NULL);
         if (pszSRSDimension != NULL)
             nDimension = atoi(pszSRSDimension);
+        else if( nSRSDimension != 0 ) /* or use one coming from a still higher level element (#5606) */
+            nDimension = nSRSDimension;
 
         if (nDimension != 2 && nDimension != 3)
         {
@@ -659,6 +675,109 @@ static OGRPolygon *GML2FaceExtRing( OGRGeometry *poGeom )
 #endif
 
 /************************************************************************/
+/*                   GML2OGRGeometry_AddToCompositeCurve()              */
+/************************************************************************/
+
+static
+int GML2OGRGeometry_AddToCompositeCurve(OGRCompoundCurve* poCC,
+                                        OGRGeometry* poGeom,
+                                        int& bChildrenAreAllLineString)
+{
+    if( poGeom == NULL ||
+        !OGR_GT_IsCurve(poGeom->getGeometryType()) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                "CompositeCurve: Got %.500s geometry as Member instead of a curve.",
+                poGeom ? poGeom->getGeometryName() : "NULL" );
+        return FALSE;
+    }
+
+    /* Crazy but allowed by GML: composite in composite */
+    if( wkbFlatten(poGeom->getGeometryType()) == wkbCompoundCurve )
+    {
+        OGRCompoundCurve* poCCChild = (OGRCompoundCurve* ) poGeom;
+        while( poCCChild->getNumCurves() != 0 )
+        {
+            OGRCurve* poCurve = poCCChild->stealCurve(0);
+            if( wkbFlatten(poCurve->getGeometryType()) != wkbLineString )
+                bChildrenAreAllLineString = FALSE;
+            if( poCC->addCurveDirectly( poCurve ) != OGRERR_NONE )
+            {
+                delete poCurve;
+                return FALSE;
+            }
+        }
+        delete poCCChild;
+    }
+    else
+    {
+        if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+            bChildrenAreAllLineString = FALSE;
+
+        if( poCC->addCurveDirectly( (OGRCurve*)poGeom ) != OGRERR_NONE )
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                   GML2OGRGeometry_AddToCompositeCurve()              */
+/************************************************************************/
+
+static
+int GML2OGRGeometry_AddToMultiSurface(OGRMultiSurface* poMS,
+                                      OGRGeometry*& poGeom,
+                                      const char* pszMemberElement,
+                                      int& bChildrenAreAllPolygons)
+{
+    if (poGeom == NULL)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
+                    pszMemberElement );
+        return FALSE;
+    }
+
+    OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
+    if( eType == wkbPolygon || eType == wkbCurvePolygon )
+    {
+        if( eType != wkbPolygon )
+            bChildrenAreAllPolygons = FALSE;
+
+        if( poMS->addGeometryDirectly( poGeom ) != OGRERR_NONE )
+        {
+            return FALSE;
+        }
+    }
+    else if (eType == wkbMultiPolygon || eType == wkbMultiSurface)
+    {
+        OGRMultiSurface* poMS2 = (OGRMultiSurface*) poGeom;
+        int i;
+        for(i=0;i<poMS2->getNumGeometries();i++)
+        {
+            if( wkbFlatten(poMS2->getGeometryRef(i)->getGeometryType()) != wkbPolygon )
+                bChildrenAreAllPolygons = FALSE;
+
+            if( poMS->addGeometry(poMS2->getGeometryRef(i)) != OGRERR_NONE )
+            {
+                return FALSE;
+            }
+        }
+        delete poGeom;
+        poGeom = NULL;
+    }
+    else
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Got %.500s geometry as %s.",
+                    poGeom->getGeometryName(), pszMemberElement );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
 /*                      GML2OGRGeometry_XMLNode()                       */
 /*                                                                      */
 /*      Translates the passed XMLnode and it's children into an         */
@@ -666,14 +785,45 @@ static OGRPolygon *GML2FaceExtRing( OGRGeometry *poGeom )
 /*      collections.                                                    */
 /************************************************************************/
 
+static
+OGRGeometry *GML2OGRGeometry_XMLNode_Internal( const CPLXMLNode *psNode,
+                                               int bGetSecondaryGeometryOption,
+                                               int nRecLevel,
+                                               int nSRSDimension,
+                                               const char* pszSRSName,
+                                               int bIgnoreGSG = FALSE,
+                                               int bOrientation = TRUE,
+                                               int bFaceHoleNegative = FALSE );
+
 OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                                       int bGetSecondaryGeometryOption,
                                       int nRecLevel,
+                                      int nSRSDimension,
                                       int bIgnoreGSG,
                                       int bOrientation,
                                       int bFaceHoleNegative ) 
 
 {
+    return GML2OGRGeometry_XMLNode_Internal(psNode,
+                                            bGetSecondaryGeometryOption,
+                                            nRecLevel, nSRSDimension,
+                                            NULL,
+                                            bIgnoreGSG, bOrientation,
+                                            bFaceHoleNegative);
+}
+
+static
+OGRGeometry *GML2OGRGeometry_XMLNode_Internal( const CPLXMLNode *psNode,
+                                               int bGetSecondaryGeometryOption,
+                                               int nRecLevel,
+                                               int nSRSDimension,
+                                               const char* pszSRSName,
+                                               int bIgnoreGSG,
+                                               int bOrientation,
+                                               int bFaceHoleNegative )
+{
+    const int bCastToLinearTypeIfPossible = TRUE;     /* hard-coded for now */
+
     if( psNode != NULL && strcmp(psNode->pszValue, "?xml") == 0 )
         psNode = psNode->psNext;
     while( psNode != NULL && psNode->eType == CXT_Comment )
@@ -681,6 +831,13 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     if( psNode == NULL )
         return NULL;
 
+    const char* pszSRSDimension = CPLGetXMLValue( (CPLXMLNode*) psNode, "srsDimension", NULL);
+    if( pszSRSDimension != NULL )
+        nSRSDimension = atoi(pszSRSDimension);
+    
+    if( pszSRSName == NULL )
+        pszSRSName = CPLGetXMLValue( (CPLXMLNode*) psNode, "srsName", NULL);
+
     const char *pszBaseGeometry = BareGMLElement( psNode->pszValue );
     if (bGetSecondaryGeometryOption < 0)
         bGetSecondaryGeometryOption = CSLTestBoolean(CPLGetConfigOption("GML_GET_SECONDARY_GEOM", "NO"));
@@ -709,8 +866,6 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         EQUAL(pszBaseGeometry,"Rectangle"))
     {
         const CPLXMLNode *psChild;
-        OGRPolygon *poPolygon = new OGRPolygon();
-        OGRLinearRing *poRing;
 
         // Find outer ring.
         psChild = FindBareXMLChild( psNode, "outerBoundaryIs" );
@@ -721,31 +876,55 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         if( psChild == NULL )
         {
             /* <gml:Polygon/> is invalid GML2, but valid GML3, so be tolerant */
-            return poPolygon;
+            return new OGRPolygon();
         }
 
         // Translate outer ring and add to polygon.
-        poRing = (OGRLinearRing *) 
-            GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                     nRecLevel + 1 );
-        if( poRing == NULL )
+        OGRGeometry* poGeom =
+            GML2OGRGeometry_XMLNode_Internal( psChild,
+                                              bGetSecondaryGeometryOption,
+                                              nRecLevel + 1, nSRSDimension,
+                                              pszSRSName );
+        if( poGeom == NULL )
         {
             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior ring");
-            delete poPolygon;
             return NULL;
         }
 
-        if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
+        if( !OGR_GT_IsCurve(poGeom->getGeometryType()) )
         {
             CPLError( CE_Failure, CPLE_AppDefined, 
-                      "%s: Got %.500s geometry as outerBoundaryIs instead of LINEARRING.",
-                      pszBaseGeometry, poRing->getGeometryName() );
-            delete poPolygon;
-            delete poRing;
+                      "%s: Got %.500s geometry as outerBoundaryIs.",
+                      pszBaseGeometry, poGeom->getGeometryName() );
+            delete poGeom;
             return NULL;
         }
 
-        poPolygon->addRingDirectly( poRing );
+        if( wkbFlatten(poGeom->getGeometryType()) == wkbLineString &&
+            !EQUAL(poGeom->getGeometryName(), "LINEARRING") )
+        {
+            poGeom = OGRCurve::CastToLinearRing((OGRCurve*)poGeom);
+        }
+
+        OGRCurvePolygon *poCP;
+        int bIsPolygon;
+        if( EQUAL(poGeom->getGeometryName(), "LINEARRING") )
+        {
+            poCP = new OGRPolygon();
+            bIsPolygon = TRUE;
+        }
+        else
+        {
+            poCP = new OGRCurvePolygon();
+            bIsPolygon = FALSE;
+        }
+
+        if( poCP->addRingDirectly( (OGRCurve*)poGeom ) != OGRERR_NONE )
+        {
+            delete poCP;
+            delete poGeom;
+            return NULL;
+        }
 
         // Find all inner rings 
         for( psChild = psNode->psChild; 
@@ -758,32 +937,70 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             {
                 const CPLXMLNode* psInteriorChild = GetChildElement(psChild);
                 if (psInteriorChild != NULL)
-                    poRing = (OGRLinearRing *) 
-                        GML2OGRGeometry_XMLNode( psInteriorChild, bGetSecondaryGeometryOption,
-                                                 nRecLevel + 1);
+                    poGeom =
+                        GML2OGRGeometry_XMLNode_Internal( psInteriorChild,
+                                                          bGetSecondaryGeometryOption,
+                                                          nRecLevel + 1,
+                                                          nSRSDimension,
+                                                          pszSRSName );
                 else
-                    poRing = NULL;
-                if (poRing == NULL)
+                    poGeom = NULL;
+                if (poGeom == NULL)
                 {
                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid interior ring");
-                    delete poPolygon;
+                    delete poCP;
                     return NULL;
                 }
-                if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
+
+                if( !OGR_GT_IsCurve(poGeom->getGeometryType()) )
                 {
                     CPLError( CE_Failure, CPLE_AppDefined, 
-                              "%s: Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
-                              pszBaseGeometry, poRing->getGeometryName() );
-                    delete poPolygon;
-                    delete poRing;
+                            "%s: Got %.500s geometry as innerBoundaryIs.",
+                            pszBaseGeometry, poGeom->getGeometryName() );
+                    delete poCP;
+                    delete poGeom;
                     return NULL;
                 }
 
-                poPolygon->addRingDirectly( poRing );
+                if( bIsPolygon )
+                {
+                    if( !EQUAL(poGeom->getGeometryName(), "LINEARRING") )
+                    {
+                        if (wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
+                        {
+                            OGRLineString* poLS = (OGRLineString*)poGeom;
+                            poGeom = OGRCurve::CastToLinearRing(poLS);
+                        }
+                        else
+                        {
+                            /* Might fail if some rings are not closed */
+                            /* We used to be tolerant about that with Polygon */
+                            /* but we have become stricter with CurvePolygon */
+                            poCP = OGRSurface::CastToCurvePolygon( (OGRPolygon*)poCP );
+                            if( poCP == NULL )
+                            {
+                                delete poGeom;
+                                return NULL;
+                            }
+                            bIsPolygon = FALSE;
+                        }
+                    }
+                }
+                else
+                {
+                    if( EQUAL(poGeom->getGeometryName(), "LINEARRING") )
+                        poGeom = OGRCurve::CastToLineString( (OGRCurve*)poGeom );
+                }
+                if( poCP->addRingDirectly( (OGRCurve*)poGeom ) != OGRERR_NONE )
+                {
+                    delete poCP;
+                    delete poGeom;
+                    return NULL;
+                }
             }
         }
 
-        return poPolygon;
+        return poCP;
     }
 
 /* -------------------------------------------------------------------- */
@@ -793,7 +1010,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLinearRing   *poLinearRing = new OGRLinearRing();
         
-        if( !ParseGMLCoordinates( psNode, poLinearRing ) )
+        if( !ParseGMLCoordinates( psNode, poLinearRing, nSRSDimension ) )
         {
             delete poLinearRing;
             return NULL;
@@ -807,9 +1024,15 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 /* -------------------------------------------------------------------- */
     if( EQUAL(pszBaseGeometry,"Ring") )
     {
-        OGRLinearRing   *poLinearRing = new OGRLinearRing();
+        OGRCurve* poRing = NULL;
+        OGRCompoundCurve   *poCC = NULL;
+        int bChildrenAreAllLineString = TRUE;
         const CPLXMLNode *psChild;
 
+        int bLastCurveWasApproximateArc = FALSE;
+        int bLastCurveWasApproximateArcInvertedAxisOrder = FALSE;
+        double dfLastCurveApproximateArcRadius = 0;
+
         for( psChild = psNode->psChild; 
              psChild != NULL; psChild = psChild->psNext )
         {
@@ -820,10 +1043,24 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 OGRGeometry* poGeom;
                 if (psCurveChild != NULL)
                     poGeom =
-                        GML2OGRGeometry_XMLNode( psCurveChild, bGetSecondaryGeometryOption,
-                                                 nRecLevel + 1);
+                        GML2OGRGeometry_XMLNode_Internal( psCurveChild,
+                                                          bGetSecondaryGeometryOption,
+                                                          nRecLevel + 1,
+                                                          nSRSDimension,
+                                                          pszSRSName );
                 else
+                {
+                    if( psChild->psChild && psChild->psChild->eType == CXT_Attribute &&
+                        psChild->psChild->psNext == NULL &&
+                        strcmp(psChild->psChild->pszValue, "xlink:href") == 0 )
+                    {
+                        CPLError(CE_Warning, CPLE_AppDefined,
+                                "Cannot resolve xlink:href='%s'. Try setting GML_SKIP_RESOLVE_ELEMS=NONE",
+                                psChild->psChild->psChild->pszValue);
+                    }
+
                     poGeom = NULL;
+                }
 
                 // try to join multiline string to one linestring
                 if( poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString )
@@ -832,38 +1069,172 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 }
 
                 if( poGeom == NULL 
-                    || wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                    || !OGR_GT_IsCurve(poGeom->getGeometryType()) )
                 {
                     delete poGeom;
-                    delete poLinearRing;
+                    delete poRing;
+                    delete poCC;
                     return NULL;
                 }
 
-                OGRLineString *poLS = (OGRLineString *) poGeom;
-                if( poLS->getNumPoints() < 2 )
+                if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                    bChildrenAreAllLineString = FALSE;
+
+                /* Ad-hoc logic to handle nicely connecting ArcByCenterPoint */
+                /* with consecutive curves, as found in some AIXM files */
+                int bIsApproximateArc = FALSE;
+                const CPLXMLNode* psChild2, *psChild3;
+                if( strcmp(psCurveChild->pszValue, "Curve") == 0 &&
+                    (psChild2 = GetChildElement(psCurveChild)) != NULL &&
+                    strcmp(psChild2->pszValue, "segments") == 0 &&
+                    (psChild3 = GetChildElement(psChild2)) != NULL &&
+                    strcmp(psChild3->pszValue, "ArcByCenterPoint") == 0 )
                 {
-                    // skip it
-                }
-                else if( poLinearRing->getNumPoints() > 0
-                    && fabs(poLinearRing->getX(poLinearRing->getNumPoints()-1) - poLS->getX(0)) < 1e-14
-                    && fabs(poLinearRing->getY(poLinearRing->getNumPoints()-1) - poLS->getY(0)) < 1e-14
-                    && fabs(poLinearRing->getZ(poLinearRing->getNumPoints()-1) - poLS->getZ(0)) < 1e-14 )
-                {
-                    // Skip the first point of the new linestring to avoid
-                    // invalidate duplicate points
-                    poLinearRing->addSubLineString( poLS, 1 );
+                    const CPLXMLNode* psRadius = FindBareXMLChild( psChild3, "radius");
+                    if( psRadius && psRadius->eType == CXT_Element )
+                    {
+                        double dfRadius = CPLAtof(CPLGetXMLValue((CPLXMLNode*)psRadius, NULL, "0"));
+                        const char* pszUnits = CPLGetXMLValue((CPLXMLNode*)psRadius, "uom", NULL);
+                        int bSRSUnitIsDeegree = FALSE;
+                        int bInvertedAxisOrder = FALSE;
+                        if( pszSRSName != NULL )
+                        {
+                            OGRSpatialReference oSRS;
+                            if( oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE )
+                            {
+                                if( oSRS.IsGeographic() )
+                                {
+                                    bInvertedAxisOrder = oSRS.EPSGTreatsAsLatLong();
+                                    bSRSUnitIsDeegree = fabs(oSRS.GetAngularUnits(NULL) - CPLAtof(SRS_UA_DEGREE_CONV)) < 1e-8;
+                                }
+                            }
+                        }
+                        if( bSRSUnitIsDeegree && pszUnits != NULL &&
+                            (EQUAL(pszUnits, "m") || EQUAL(pszUnits, "nm") ||
+                             EQUAL(pszUnits, "mi") || EQUAL(pszUnits, "ft")) )
+                        {
+                            bIsApproximateArc = TRUE;
+                            if( EQUAL(pszUnits, "nm") )
+                                dfRadius *= CPLAtof(SRS_UL_INTL_NAUT_MILE_CONV);
+                            else if( EQUAL(pszUnits, "mi") )
+                                dfRadius *= CPLAtof(SRS_UL_INTL_STAT_MILE_CONV);
+                            else if( EQUAL(pszUnits, "ft") )
+                                dfRadius *= CPLAtof(SRS_UL_INTL_FOOT_CONV);
+                            dfLastCurveApproximateArcRadius = dfRadius;
+                            bLastCurveWasApproximateArcInvertedAxisOrder = bInvertedAxisOrder;
+                        }
+                    }
                 }
+
+                if( poCC == NULL && poRing == NULL )
+                    poRing = (OGRCurve*)poGeom;
                 else
                 {
-                    // Add the whole new line string
-                    poLinearRing->addSubLineString( poLS );
+                    if( poCC == NULL )
+                    {
+                        poCC = new OGRCompoundCurve();
+                        if( poCC->addCurveDirectly(poRing) != OGRERR_NONE )
+                        {
+                            delete poGeom;
+                            delete poRing;
+                            delete poCC;
+                            return NULL;
+                        }
+                        poRing = NULL;
+                    }
+
+                    if( bIsApproximateArc )
+                    {
+                        if( poGeom->getGeometryType() == wkbLineString )
+                        {
+                            OGRCurve* poPreviousCurve = poCC->getCurve(poCC->getNumCurves()-1);
+                            OGRLineString* poLS = (OGRLineString*)poGeom;
+                            if( poPreviousCurve->getNumPoints() >= 2 && poLS->getNumPoints() >= 2 )
+                            {
+                                OGRPoint p, p2;
+                                poPreviousCurve->EndPoint(&p);
+                                poLS->StartPoint(&p2);
+                                double dfDistance;
+                                if( bLastCurveWasApproximateArcInvertedAxisOrder )
+                                    dfDistance = OGRXPlane_Distance(p.getX(), p.getY(), p2.getX(), p2.getY());
+                                else
+                                    dfDistance = OGRXPlane_Distance(p.getY(), p.getX(), p2.getY(), p2.getX());
+                                //CPLDebug("OGR", "%f %f\n", dfDistance, dfLastCurveApproximateArcRadius / 10 );
+                                if( dfDistance < dfLastCurveApproximateArcRadius / 5 )
+                                {
+                                    CPLDebug("OGR", "Moving approximate start of ArcByCenterPoint to end of previous curve");
+                                    poLS->setPoint(0, &p);
+                                }
+                            }
+                        }
+                    }
+                    else if( bLastCurveWasApproximateArc )
+                    {
+                        OGRCurve* poPreviousCurve = poCC->getCurve(poCC->getNumCurves()-1);
+                        if( poPreviousCurve->getGeometryType() == wkbLineString )
+                        {
+                            OGRLineString* poLS = (OGRLineString*)poPreviousCurve;
+                            if( poLS->getNumPoints() >= 2 && ((OGRCurve*)poGeom)->getNumPoints() >= 2 )
+                            {
+                                OGRPoint p, p2;
+                                ((OGRCurve*)poGeom)->StartPoint(&p);
+                                poLS->EndPoint(&p2);
+                                double dfDistance;
+                                if( bLastCurveWasApproximateArcInvertedAxisOrder )
+                                    dfDistance = OGRXPlane_Distance(p.getX(), p.getY(), p2.getX(), p2.getY());
+                                else
+                                    dfDistance = OGRXPlane_Distance(p.getY(), p.getX(), p2.getY(), p2.getX());
+                                //CPLDebug("OGR", "%f %f\n", dfDistance, dfLastCurveApproximateArcRadius / 10 );
+                                // "A-311 WHEELER AFB OAHU, HI.xml" needs more than 10%
+                                if( dfDistance < dfLastCurveApproximateArcRadius / 5 )
+                                {
+                                    CPLDebug("OGR", "Moving approximate end of last ArcByCenterPoint to start of current curve");
+                                    poLS->setPoint(poLS->getNumPoints()-1, &p);
+                                }
+                            }
+                        }
+                    }
+
+                    if( poCC->addCurveDirectly((OGRCurve*)poGeom) != OGRERR_NONE )
+                    {
+                        delete poGeom;
+                        delete poCC;
+                        return NULL;
+                    }
                 }
 
-                delete poLS;
+                bLastCurveWasApproximateArc = bIsApproximateArc;
             }
         }
 
-        return poLinearRing;
+        if( poRing )
+        {
+            if( poRing->getNumPoints() < 2 || !poRing->get_IsClosed() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "Non-closed ring");
+                delete poRing;
+                return NULL;
+            }
+            return poRing;
+        }
+        
+        if( poCC == NULL )
+            return NULL;
+
+        else if( bCastToLinearTypeIfPossible && bChildrenAreAllLineString )
+        {
+            return OGRCurve::CastToLinearRing(poCC);
+        }
+        else
+        {
+            if( poCC->getNumPoints() < 2 || !poCC->get_IsClosed() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "Non-closed ring");
+                delete poCC;
+                return NULL;
+            }
+            return poCC;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -875,7 +1246,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLineString   *poLine = new OGRLineString();
         
-        if( !ParseGMLCoordinates( psNode, poLine ) )
+        if( !ParseGMLCoordinates( psNode, poLine, nSRSDimension ) )
         {
             delete poLine;
             return NULL;
@@ -884,6 +1255,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         return poLine;
     }
 
+#if 0
 /* -------------------------------------------------------------------- */
 /*      Arc/Circle : we approximate them by linear segments             */
 /* -------------------------------------------------------------------- */
@@ -892,13 +1264,12 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLineString   *poLine = new OGRLineString();
 
-        if( !ParseGMLCoordinates( psNode, poLine ) ||
+        if( !ParseGMLCoordinates( psNode, poLine, nSRSDimension ) ||
             poLine->getNumPoints() != 3 )
         {
             delete poLine;
             return NULL;
         }
-
         double x0 = poLine->getX(0);
         double y0 = poLine->getY(0);
         double x1 = poLine->getX(1);
@@ -949,10 +1320,10 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         int nSign = (det >= 0) ? 1 : -1;
 
         double alpha, dfRemainder;
-        double dfStep = atof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4")) / 180 * PI;
+        double dfStep = CPLAtof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4")) / 180 * PI;
 
         // make sure the segments are not too short
-        double dfMinStepLength = atof( CPLGetConfigOption("OGR_ARC_MINLENGTH","0") );
+        double dfMinStepLength = CPLAtof( CPLGetConfigOption("OGR_ARC_MINLENGTH","0") );
         if ( dfMinStepLength > 0.0 && dfStep * R < dfMinStepLength )
         {
             CPLDebug( "GML", "Increasing arc step to %lf° (was %lf° with segment length %lf at radius %lf; min segment length is %lf)",
@@ -1011,6 +1382,400 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 
         return poLine;
     }
+#endif
+/* -------------------------------------------------------------------- */
+/*      Arc                                                             */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"Arc") )
+    {
+        OGRCircularString   *poCC = new OGRCircularString();
+
+        if( !ParseGMLCoordinates( psNode, poCC, nSRSDimension ) )
+        {
+            delete poCC;
+            return NULL;
+        }
+
+        if( poCC->getNumPoints() != 3 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Bad number of points in Arc");
+            delete poCC;
+            return NULL;
+        }
+
+        return poCC;
+    }
+
+/* -------------------------------------------------------------------- */
+/*     ArcString                                                        */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"ArcString") )
+    {
+        OGRCircularString   *poCC = new OGRCircularString();
+
+        if( !ParseGMLCoordinates( psNode, poCC, nSRSDimension ) )
+        {
+            delete poCC;
+            return NULL;
+        }
+
+        if( poCC->getNumPoints() < 3 || (poCC->getNumPoints() % 2) != 1 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Bad number of points in ArcString");
+            delete poCC;
+            return NULL;
+        }
+
+        return poCC;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Circle                                                          */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"Circle") )
+    {
+        OGRLineString   *poLine = new OGRLineString();
+
+        if( !ParseGMLCoordinates( psNode, poLine, nSRSDimension ) )
+        {
+            delete poLine;
+            return NULL;
+        }
+
+        if( poLine->getNumPoints() != 3 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Bad number of points in Circle");
+            delete poLine;
+            return NULL;
+        }
+
+        double R, cx, cy, alpha0, alpha1, alpha2;
+        if( !OGRGeometryFactory::GetCurveParmeters(
+                               poLine->getX(0), poLine->getY(0),
+                               poLine->getX(1), poLine->getY(1),
+                               poLine->getX(2), poLine->getY(2),
+                               R, cx, cy, alpha0, alpha1, alpha2 ) )
+        {
+            delete poLine;
+            return NULL;
+        }
+
+        OGRCircularString   *poCC = new OGRCircularString();
+        OGRPoint p;
+        poLine->getPoint(0, &p);
+        poCC->addPoint(&p);
+        poLine->getPoint(1, &p);
+        poCC->addPoint(&p);
+        poLine->getPoint(2, &p);
+        poCC->addPoint(&p);
+        double alpha4 = (alpha2 > alpha0) ? alpha0 + 2 * M_PI : alpha0 - 2 * M_PI;
+        double alpha3 = (alpha2 + alpha4) / 2;
+        double x = cx + R * cos(alpha3);
+        double y = cy + R * sin(alpha3);
+        if( poCC->getCoordinateDimension() == 3 )
+            poCC->addPoint( x, y, p.getZ() );
+        else
+            poCC->addPoint( x, y );
+        poLine->getPoint(0, &p);
+        poCC->addPoint(&p);
+        delete poLine;
+        return poCC;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      ArcByBulge                                                      */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"ArcByBulge") )
+    {
+        const CPLXMLNode *psChild;
+
+        psChild = FindBareXMLChild( psNode, "bulge");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing bulge element." );
+            return NULL;
+        }
+        double dfBulge = CPLAtof(psChild->psChild->pszValue);
+
+        psChild = FindBareXMLChild( psNode, "normal");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing normal element." );
+            return NULL;
+        }
+        double dfNormal = CPLAtof(psChild->psChild->pszValue);
+
+
+        OGRLineString* poLS = new OGRLineString();
+        if( !ParseGMLCoordinates( psNode, poLS, nSRSDimension ) )
+        {
+            delete poLS;
+            return NULL;
+        }
+
+        if( poLS->getNumPoints() != 2 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Bad number of points in ArcByBulge");
+            delete poLS;
+            return NULL;
+        }
+
+        OGRCircularString   *poCC = new OGRCircularString();
+        OGRPoint p;
+        poLS->getPoint(0, &p);
+        poCC->addPoint(&p);
+
+        double dfMidX = (poLS->getX(0) + poLS->getX(1)) / 2;
+        double dfMidY = (poLS->getY(0) + poLS->getY(1)) / 2;
+        double dfDirX = (poLS->getX(1) - poLS->getX(0)) / 2;
+        double dfDirY = (poLS->getY(1) - poLS->getY(0)) / 2;
+        double dfNormX = -dfDirY;
+        double dfNormY = dfDirX;
+        double dfNorm = sqrt(dfNormX * dfNormX + dfNormY * dfNormY);
+        if( dfNorm )
+        {
+            dfNormX /= dfNorm;
+            dfNormY /= dfNorm;
+        }
+        double dfNewX = dfMidX + dfNormX * dfBulge * dfNormal;
+        double dfNewY = dfMidY + dfNormY * dfBulge * dfNormal;
+
+        if( poCC->getCoordinateDimension() == 3 )
+            poCC->addPoint( dfNewX, dfNewY, p.getZ() );
+        else
+            poCC->addPoint( dfNewX, dfNewY );
+
+        poLS->getPoint(1, &p);
+        poCC->addPoint(&p);
+
+        delete poLS;
+        return poCC;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      ArcByCenterPoint                                                */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"ArcByCenterPoint") )
+    {
+        const CPLXMLNode *psChild;
+
+        psChild = FindBareXMLChild( psNode, "radius");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing radius element." );
+            return NULL;
+        }
+        double dfRadius = CPLAtof(CPLGetXMLValue((CPLXMLNode*)psChild, NULL, "0"));
+        const char* pszUnits = CPLGetXMLValue((CPLXMLNode*)psChild, "uom", NULL);
+
+        psChild = FindBareXMLChild( psNode, "startAngle");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing startAngle element." );
+            return NULL;
+        }
+        double dfStartAngle = CPLAtof(CPLGetXMLValue((CPLXMLNode*)psChild, NULL, "0"));
+
+        psChild = FindBareXMLChild( psNode, "endAngle");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing endAngle element." );
+            return NULL;
+        }
+        double dfEndAngle = CPLAtof(CPLGetXMLValue((CPLXMLNode*)psChild, NULL, "0"));
+
+        OGRPoint p;
+        if( !ParseGMLCoordinates( psNode, &p, nSRSDimension ) )
+        {
+            return NULL;
+        }
+        
+        int bSRSUnitIsDeegree = FALSE;
+        int bInvertedAxisOrder = FALSE;
+        if( pszSRSName != NULL )
+        {
+            OGRSpatialReference oSRS;
+            if( oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE )
+            {
+                if( oSRS.IsGeographic() )
+                {
+                    bInvertedAxisOrder = oSRS.EPSGTreatsAsLatLong();
+                    bSRSUnitIsDeegree = fabs(oSRS.GetAngularUnits(NULL) - CPLAtof(SRS_UA_DEGREE_CONV)) < 1e-8;
+                }
+            }
+        }
+
+        double dfCenterX = p.getX();
+        double dfCenterY = p.getY();
+        
+        if( bSRSUnitIsDeegree && pszUnits != NULL &&
+            (EQUAL(pszUnits, "m") || EQUAL(pszUnits, "nm") ||
+             EQUAL(pszUnits, "mi") || EQUAL(pszUnits, "ft")) )
+        {
+            OGRLineString* poLS = new OGRLineString();
+            double dfStep = CPLAtof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4"));
+            double dfDistance = dfRadius;
+            if( EQUAL(pszUnits, "nm") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_NAUT_MILE_CONV);
+            else if( EQUAL(pszUnits, "mi") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_STAT_MILE_CONV);
+            else if( EQUAL(pszUnits, "ft") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_FOOT_CONV);
+            double dfSign = (dfStartAngle < dfEndAngle) ? 1 : -1;
+            for(double dfAngle = dfStartAngle; (dfAngle - dfEndAngle) * dfSign < 0; dfAngle += dfSign * dfStep)
+            {
+                double dfLong, dfLat;
+                if( bInvertedAxisOrder )
+                {
+                    OGRXPlane_ExtendPosition(dfCenterX, dfCenterY,
+                                             dfDistance, 90-dfAngle, /* not sure of angle conversion here...*/
+                                             &dfLat, &dfLong);
+                    p.setY( dfLat );
+                    p.setX( dfLong );
+                }
+                else
+                {
+                    OGRXPlane_ExtendPosition(dfCenterY, dfCenterX,
+                                             dfDistance, 90-dfAngle,
+                                             &dfLat, &dfLong);
+                    p.setX( dfLong );
+                    p.setY( dfLat );
+                }
+                poLS->addPoint(&p);             
+            }
+            
+            double dfLong, dfLat;
+            if( bInvertedAxisOrder )
+            {
+                OGRXPlane_ExtendPosition(dfCenterX, dfCenterY,
+                                         dfDistance, 90-dfEndAngle, /* not sure of angle conversion here...*/
+                                         &dfLat, &dfLong);
+                p.setY( dfLat );
+                p.setX( dfLong );
+            }
+            else
+            {
+                OGRXPlane_ExtendPosition(dfCenterY, dfCenterX,
+                                         dfDistance, 90-dfEndAngle,
+                                         &dfLat, &dfLong);
+                p.setX( dfLong );
+                p.setY( dfLat );
+            }
+            poLS->addPoint(&p);
+
+            return poLS;
+        }
+
+        OGRCircularString   *poCC = new OGRCircularString();
+        p.setX( dfCenterX + dfRadius * cos(dfStartAngle * M_PI / 180.0) );
+        p.setY( dfCenterY + dfRadius * sin(dfStartAngle * M_PI / 180.0) );
+        poCC->addPoint(&p);
+        p.setX( dfCenterX + dfRadius * cos((dfStartAngle+dfEndAngle)/2 * M_PI / 180.0) );
+        p.setY( dfCenterY + dfRadius * sin((dfStartAngle+dfEndAngle)/2 * M_PI / 180.0) );
+        poCC->addPoint(&p);
+        p.setX( dfCenterX + dfRadius * cos(dfEndAngle * M_PI / 180.0) );
+        p.setY( dfCenterY + dfRadius * sin(dfEndAngle * M_PI / 180.0) );
+        poCC->addPoint(&p);
+        return poCC;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      CircleByCenterPoint                                             */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"CircleByCenterPoint") )
+    {
+        const CPLXMLNode *psChild;
+
+        psChild = FindBareXMLChild( psNode, "radius");
+        if( psChild == NULL || psChild->eType != CXT_Element )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Missing radius element." );
+            return NULL;
+        }
+        double dfRadius = CPLAtof(CPLGetXMLValue((CPLXMLNode*)psChild, NULL, "0"));
+        const char* pszUnits = CPLGetXMLValue((CPLXMLNode*)psChild, "uom", NULL);
+
+        OGRPoint p;
+        if( !ParseGMLCoordinates( psNode, &p, nSRSDimension ) )
+        {
+            return NULL;
+        }
+        
+        int bSRSUnitIsDeegree = FALSE;
+        int bInvertedAxisOrder = FALSE;
+        if( pszSRSName != NULL )
+        {
+            OGRSpatialReference oSRS;
+            if( oSRS.SetFromUserInput(pszSRSName) == OGRERR_NONE )
+            {
+                if( oSRS.IsGeographic() )
+                {
+                    bInvertedAxisOrder = oSRS.EPSGTreatsAsLatLong();
+                    bSRSUnitIsDeegree = fabs(oSRS.GetAngularUnits(NULL) - CPLAtof(SRS_UA_DEGREE_CONV)) < 1e-8;
+                }
+            }
+        }
+
+        double dfCenterX = p.getX();
+        double dfCenterY = p.getY();
+        
+        if( bSRSUnitIsDeegree && pszUnits != NULL &&
+            (EQUAL(pszUnits, "m") || EQUAL(pszUnits, "nm") ||
+             EQUAL(pszUnits, "mi") || EQUAL(pszUnits, "ft")) )
+        {
+            OGRLineString* poLS = new OGRLineString();
+            double dfStep = CPLAtof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4"));
+            double dfDistance = dfRadius;
+            if( EQUAL(pszUnits, "nm") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_NAUT_MILE_CONV);
+            else if( EQUAL(pszUnits, "mi") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_STAT_MILE_CONV);
+            else if( EQUAL(pszUnits, "ft") )
+                dfDistance *= CPLAtof(SRS_UL_INTL_FOOT_CONV);
+            for(double dfAngle = 0; dfAngle < 360; dfAngle += dfStep)
+            {
+                double dfLong, dfLat;
+                if( bInvertedAxisOrder )
+                {
+                    OGRXPlane_ExtendPosition(dfCenterX, dfCenterY,
+                                             dfDistance, dfAngle,
+                                             &dfLat, &dfLong);
+                    p.setY( dfLat );
+                    p.setX( dfLong );
+                }
+                else
+                {
+                    OGRXPlane_ExtendPosition(dfCenterY, dfCenterX,
+                                             dfDistance, dfAngle,
+                                             &dfLat, &dfLong);
+                    p.setX( dfLong );
+                    p.setY( dfLat );
+                }
+                poLS->addPoint(&p);             
+            }
+            poLS->getPoint(0, &p);
+            poLS->addPoint(&p);     
+            return poLS;
+        }
+
+        OGRCircularString   *poCC = new OGRCircularString();
+        p.setX( dfCenterX - dfRadius );
+        p.setY( dfCenterY );
+        poCC->addPoint(&p);
+        p.setX( dfCenterX + dfRadius);
+        p.setY( dfCenterY );
+        poCC->addPoint(&p);
+        p.setX( dfCenterX - dfRadius );
+        p.setY( dfCenterY );
+        poCC->addPoint(&p);
+        return poCC;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      PointType                                                       */
@@ -1021,7 +1786,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRPoint *poPoint = new OGRPoint();
         
-        if( !ParseGMLCoordinates( psNode, poPoint ) )
+        if( !ParseGMLCoordinates( psNode, poPoint, nSRSDimension ) )
         {
             delete poPoint;
             return NULL;
@@ -1037,7 +1802,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLineString  oPoints;
 
-        if( !ParseGMLCoordinates( psNode, &oPoints ) )
+        if( !ParseGMLCoordinates( psNode, &oPoints, nSRSDimension ) )
             return NULL;
 
         if( oPoints.getNumPoints() < 2 )
@@ -1119,20 +1884,25 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         EQUAL(pszBaseGeometry,"CompositeSurface") )
     {
         const CPLXMLNode *psChild;
-        OGRMultiPolygon *poMPoly = new OGRMultiPolygon();
+        OGRMultiSurface* poMS;
+        if( EQUAL(pszBaseGeometry,"MultiPolygon") )
+            poMS = new OGRMultiPolygon();
+        else
+            poMS = new OGRMultiSurface();
         int bReconstructTopology = FALSE;
+        int bChildrenAreAllPolygons = TRUE;
 
         // Iterate over children
         for( psChild = psNode->psChild; 
              psChild != NULL;
              psChild = psChild->psNext ) 
         {
+            const char* pszMemberElement = BareGMLElement(psChild->pszValue);
             if( psChild->eType == CXT_Element
-                && (EQUAL(BareGMLElement(psChild->pszValue),"polygonMember") ||
-                    EQUAL(BareGMLElement(psChild->pszValue),"surfaceMember")) )
+                && (EQUAL(pszMemberElement,"polygonMember") ||
+                    EQUAL(pszMemberElement,"surfaceMember")) )
             {
                 const CPLXMLNode* psSurfaceChild = GetChildElement(psChild);
-                OGRPolygon *poPolygon;
 
                 if (psSurfaceChild != NULL)
                 {
@@ -1156,14 +1926,15 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                                 OGRLinearRing* poRing;
                                 if (psInteriorChild != NULL)
                                     poRing = (OGRLinearRing *) 
-                                        GML2OGRGeometry_XMLNode( psInteriorChild, bGetSecondaryGeometryOption,
-                                                                nRecLevel + 1);
+                                        GML2OGRGeometry_XMLNode_Internal(
+                                            psInteriorChild, bGetSecondaryGeometryOption,
+                                            nRecLevel + 1, nSRSDimension, pszSRSName );
                                 else
                                     poRing = NULL;
                                 if (poRing == NULL)
                                 {
                                     CPLError( CE_Failure, CPLE_AppDefined, "Invalid interior ring");
-                                    delete poMPoly;
+                                    delete poMS;
                                     return NULL;
                                 }
                                 if( !EQUAL(poRing->getGeometryName(),"LINEARRING") )
@@ -1172,90 +1943,58 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                                             "%s: Got %.500s geometry as innerBoundaryIs instead of LINEARRING.",
                                             pszBaseGeometry, poRing->getGeometryName() );
                                     delete poRing;
-                                    delete poMPoly;
+                                    delete poMS;
                                     return NULL;
                                 }
 
                                 bReconstructTopology = TRUE;
-                                poPolygon = new OGRPolygon();
+                                OGRPolygon *poPolygon = new OGRPolygon();
                                 poPolygon->addRingDirectly( poRing );
-                                poMPoly->addGeometryDirectly( poPolygon );
+                                poMS->addGeometryDirectly( poPolygon );
                             }
                         }
                     }
                     else
                     {
-                        poPolygon = (OGRPolygon *) 
-                            GML2OGRGeometry_XMLNode( psSurfaceChild, bGetSecondaryGeometryOption,
-                                                     nRecLevel + 1);
-
-                        if( poPolygon == NULL )
-                        {
-                            CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
-                                    BareGMLElement(psChild->pszValue));
-                            delete poMPoly;
-                            return NULL;
-                        }
-
-                        if( !EQUAL(poPolygon->getGeometryName(),"POLYGON") )
+                        OGRGeometry* poGeom =
+                            GML2OGRGeometry_XMLNode_Internal( psSurfaceChild,
+                                  bGetSecondaryGeometryOption,
+                                  nRecLevel + 1, nSRSDimension, pszSRSName );
+                        if( !GML2OGRGeometry_AddToMultiSurface(poMS, poGeom,
+                                                               pszMemberElement,
+                                                               bChildrenAreAllPolygons) )
                         {
-                            CPLError( CE_Failure, CPLE_AppDefined, 
-                                    "Got %.500s geometry as polygonMember instead of MULTIPOLYGON.",
-                                    poPolygon->getGeometryName() );
-                            delete poPolygon;
-                            delete poMPoly;
+                            delete poGeom;
+                            delete poMS;
                             return NULL;
                         }
-
-                        poMPoly->addGeometryDirectly( poPolygon );
                     }
                 }
             }
             else if (psChild->eType == CXT_Element
-                && EQUAL(BareGMLElement(psChild->pszValue),"surfaceMembers") )
+                    && EQUAL(pszMemberElement,"surfaceMembers") )
             {
                 const CPLXMLNode *psChild2;
                 for( psChild2 = psChild->psChild;
                      psChild2 != NULL;
                      psChild2 = psChild2->psNext )
                 {
+                    pszMemberElement = BareGMLElement(psChild2->pszValue);
                     if( psChild2->eType == CXT_Element
-                        && (EQUAL(BareGMLElement(psChild2->pszValue),"Surface") ||
-                            EQUAL(BareGMLElement(psChild2->pszValue),"Polygon") ||
-                            EQUAL(BareGMLElement(psChild2->pszValue),"PolygonPatch") ||
-                            EQUAL(BareGMLElement(psChild2->pszValue),"CompositeSurface")) )
+                        && (EQUAL(pszMemberElement,"Surface") ||
+                            EQUAL(pszMemberElement,"Polygon") ||
+                            EQUAL(pszMemberElement,"PolygonPatch") ||
+                            EQUAL(pszMemberElement,"CompositeSurface")) )
                     {
-                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
-                                                                       nRecLevel + 1);
-                        if (poGeom == NULL)
+                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode_Internal(
+                            psChild2, bGetSecondaryGeometryOption,
+                            nRecLevel + 1, nSRSDimension, pszSRSName );
+                        if( !GML2OGRGeometry_AddToMultiSurface(poMS, poGeom,
+                                                               pszMemberElement,
+                                                               bChildrenAreAllPolygons) )
                         {
-                            CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
-                                    BareGMLElement(psChild2->pszValue));
-                            delete poMPoly;
-                            return NULL;
-                        }
-
-                        if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
-                        {
-                            poMPoly->addGeometryDirectly( (OGRPolygon*) poGeom );
-                        }
-                        else if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
-                        {
-                            OGRMultiPolygon* poMPoly2 = (OGRMultiPolygon*) poGeom;
-                            int i;
-                            for(i=0;i<poMPoly2->getNumGeometries();i++)
-                            {
-                                poMPoly->addGeometry(poMPoly2->getGeometryRef(i));
-                            }
                             delete poGeom;
-                        }
-                        else
-                        {
-                            CPLError( CE_Failure, CPLE_AppDefined,
-                                    "Got %.500s geometry as polygonMember instead of POLYGON/MULTIPOLYGON.",
-                                    poGeom->getGeometryName() );
-                            delete poGeom;
-                            delete poMPoly;
+                            delete poMS;
                             return NULL;
                         }
                     }
@@ -1263,8 +2002,14 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             }
         }
 
-        if( bReconstructTopology )
+        if( bReconstructTopology && bChildrenAreAllPolygons )
         {
+            OGRMultiPolygon* poMPoly;
+            if( wkbFlatten(poMS->getGeometryType()) == wkbMultiSurface )
+                poMPoly = OGRMultiSurface::CastToMultiPolygon(poMS);
+            else
+                poMPoly = (OGRMultiPolygon*)poMS;
+            CPLAssert(poMPoly); /* that should not fail really ! */
             int nPolygonCount = poMPoly->getNumGeometries();
             OGRGeometry** papoPolygons = new OGRGeometry*[ nPolygonCount ];
             for(int i=0;i<nPolygonCount;i++)
@@ -1280,7 +2025,16 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             return poRet;
         }
         else
-            return poMPoly;
+        {
+            if( bCastToLinearTypeIfPossible && 
+                wkbFlatten(poMS->getGeometryType()) == wkbMultiSurface &&
+                bChildrenAreAllPolygons )
+            {
+                return OGRMultiSurface::CastToMultiPolygon(poMS);
+            }
+            else
+                return poMS;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1305,8 +2059,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 if (psPointChild != NULL)
                 {
                     poPoint = (OGRPoint *) 
-                        GML2OGRGeometry_XMLNode( psPointChild, bGetSecondaryGeometryOption,
-                                                 nRecLevel + 1);
+                        GML2OGRGeometry_XMLNode_Internal( psPointChild,
+                              bGetSecondaryGeometryOption,
+                              nRecLevel + 1, nSRSDimension, pszSRSName );
                     if( poPoint == NULL 
                         || wkbFlatten(poPoint->getGeometryType()) != wkbPoint )
                     {
@@ -1332,8 +2087,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                     if( psChild2->eType == CXT_Element
                         && (EQUAL(BareGMLElement(psChild2->pszValue),"Point")) )
                     {
-                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
-                                                                       nRecLevel + 1);
+                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode_Internal(
+                            psChild2, bGetSecondaryGeometryOption,
+                            nRecLevel + 1, nSRSDimension, pszSRSName );
                         if (poGeom == NULL)
                         {
                             CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
@@ -1383,8 +2139,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 OGRGeometry *poGeom;
 
                 if (psLineStringChild != NULL)
-                    poGeom = GML2OGRGeometry_XMLNode( psLineStringChild, bGetSecondaryGeometryOption,
-                                                      nRecLevel + 1);
+                    poGeom = GML2OGRGeometry_XMLNode_Internal( psLineStringChild,
+                          bGetSecondaryGeometryOption,
+                          nRecLevel + 1, nSRSDimension, pszSRSName );
                 else
                     poGeom = NULL;
                 if( poGeom == NULL 
@@ -1407,13 +2164,13 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 
 
 /* -------------------------------------------------------------------- */
-/*      MultiCurve / CompositeCurve                                     */
+/*      MultiCurve                                                      */
 /* -------------------------------------------------------------------- */
-    if( EQUAL(pszBaseGeometry,"MultiCurve") ||
-        EQUAL(pszBaseGeometry,"CompositeCurve") )
+    if( EQUAL(pszBaseGeometry,"MultiCurve") )
     {
-        const CPLXMLNode *psChild, *psCurve;
-        OGRMultiLineString *poMLS = new OGRMultiLineString();
+        const CPLXMLNode *psChild;
+        OGRMultiCurve *poMC = new OGRMultiCurve();
+        int bChildrenAreAllLineString = TRUE;
 
         // collect curveMembers
         for( psChild = psNode->psChild; 
@@ -1423,40 +2180,31 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             if( psChild->eType == CXT_Element
                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
             {
-                OGRGeometry *poGeom;
-
-                // There can be only one curve under a curveMember.
-                // Currently "Curve" and "LineString" are handled.
-                psCurve = FindBareXMLChild( psChild, "Curve" );
-                if( psCurve == NULL )
-                    psCurve = FindBareXMLChild( psChild, "LineString" );
-                if( psCurve == NULL )
-                {
-                    if( GetChildElement(psChild) != NULL )
-                    {
-                        CPLError( CE_Failure, CPLE_AppDefined, 
-                                "Failed to get curve element in curveMember" );
-                        delete poMLS;
-                        return NULL;
-                    }
-                }
-                else
+                const CPLXMLNode *psChild2 = GetChildElement(psChild);
+                if( psChild2 != NULL ) /* empty curveMember is valid */
                 {
-                    poGeom = GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
-                                                    nRecLevel + 1);
+                    OGRGeometry* poGeom = GML2OGRGeometry_XMLNode_Internal(
+                        psChild2, bGetSecondaryGeometryOption,
+                        nRecLevel + 1, nSRSDimension, pszSRSName );
                     if( poGeom == NULL ||
-                        ( wkbFlatten(poGeom->getGeometryType()) != wkbLineString ) )
+                        !OGR_GT_IsCurve(poGeom->getGeometryType()) )
                     {
                         CPLError( CE_Failure, CPLE_AppDefined, 
-                                "MultiCurve: Got %.500s geometry as Member instead of LINESTRING.",
+                                "MultiCurve: Got %.500s geometry as Member instead of a curve.",
                                 poGeom ? poGeom->getGeometryName() : "NULL" );
                         if( poGeom != NULL ) delete poGeom;
-                        delete poMLS;
+                        delete poMC;
                         return NULL;
                     }
 
-                    poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
-                }
+                    if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                        bChildrenAreAllLineString = FALSE;
+
+                    if( poMC->addGeometryDirectly( poGeom ) != OGRERR_NONE )
+                    {
+                        delete poGeom;
+                    }
+            }
             }
             else if (psChild->eType == CXT_Element
                 && EQUAL(BareGMLElement(psChild->pszValue),"curveMembers") )
@@ -1466,39 +2214,108 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                      psChild2 != NULL;
                      psChild2 = psChild2->psNext )
                 {
-                    if( psChild2->eType == CXT_Element
-                        && (EQUAL(BareGMLElement(psChild2->pszValue),"LineString")) )
+                    if( psChild2->eType == CXT_Element )
                     {
-                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psChild2, bGetSecondaryGeometryOption,
-                                                                       nRecLevel + 1);
-                        if (poGeom == NULL)
+                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode_Internal(
+                            psChild2, bGetSecondaryGeometryOption,
+                            nRecLevel + 1, nSRSDimension, pszSRSName );
+                        if (poGeom == NULL ||
+                            !OGR_GT_IsCurve(poGeom->getGeometryType()) )
                         {
-                            CPLError( CE_Failure, CPLE_AppDefined, "Invalid %s",
-                                    BareGMLElement(psChild2->pszValue));
-                            delete poMLS;
+                            CPLError( CE_Failure, CPLE_AppDefined, 
+                                    "MultiCurve: Got %.500s geometry as Member instead of a curve.",
+                                    poGeom ? poGeom->getGeometryName() : "NULL" );
+                            if( poGeom != NULL ) delete poGeom;
+                            delete poMC;
                             return NULL;
                         }
 
-                        if (wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
+                        if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                            bChildrenAreAllLineString = FALSE;
+
+                        if( poMC->addGeometryDirectly( poGeom ) != OGRERR_NONE )
                         {
-                            poMLS->addGeometryDirectly( (OGRLineString *)poGeom );
+                            delete poGeom;
                         }
-                        else
+                    }
+                }
+            }
+        }
+
+        if( bCastToLinearTypeIfPossible && bChildrenAreAllLineString )
+        {
+            return OGRMultiCurve::CastToMultiLineString(poMC);
+        }
+        else
+            return poMC;
+    }
+
+
+/* -------------------------------------------------------------------- */
+/*      CompositeCurve                                                  */
+/* -------------------------------------------------------------------- */
+    if( EQUAL(pszBaseGeometry,"CompositeCurve") )
+    {
+        const CPLXMLNode *psChild;
+        OGRCompoundCurve *poCC = new OGRCompoundCurve();
+        int bChildrenAreAllLineString = TRUE;
+
+        // collect curveMembers
+        for( psChild = psNode->psChild; 
+             psChild != NULL;
+             psChild = psChild->psNext ) 
+        {
+            if( psChild->eType == CXT_Element
+                && EQUAL(BareGMLElement(psChild->pszValue),"curveMember") )
+            {
+                const CPLXMLNode *psChild2 = GetChildElement(psChild);
+                if( psChild2 != NULL ) /* empty curveMember is valid */
+                {
+                    OGRGeometry*poGeom = GML2OGRGeometry_XMLNode_Internal(
+                        psChild2, bGetSecondaryGeometryOption,
+                        nRecLevel + 1, nSRSDimension, pszSRSName );
+                    if( !GML2OGRGeometry_AddToCompositeCurve(poCC, poGeom,
+                                                                bChildrenAreAllLineString) )
+                    {
+                        delete poGeom;
+                        delete poCC;
+                        return NULL;
+                    }
+                }
+            }
+            else if (psChild->eType == CXT_Element
+                && EQUAL(BareGMLElement(psChild->pszValue),"curveMembers") )
+            {
+                const CPLXMLNode *psChild2;
+                for( psChild2 = psChild->psChild;
+                     psChild2 != NULL;
+                     psChild2 = psChild2->psNext )
+                {
+                    if( psChild2->eType == CXT_Element )
+                    {
+                        OGRGeometry* poGeom = GML2OGRGeometry_XMLNode_Internal(
+                            psChild2, bGetSecondaryGeometryOption,
+                            nRecLevel + 1, nSRSDimension, pszSRSName );
+                        if( !GML2OGRGeometry_AddToCompositeCurve(poCC, poGeom,
+                                                             bChildrenAreAllLineString) )
                         {
-                            CPLError( CE_Failure, CPLE_AppDefined,
-                                    "Got %.500s geometry as curveMember instead of LINESTRING.",
-                                    poGeom->getGeometryName() );
                             delete poGeom;
-                            delete poMLS;
+                            delete poCC;
                             return NULL;
                         }
                     }
                 }
             }
         }
-        return poMLS;
-    }
 
+        if( bCastToLinearTypeIfPossible && bChildrenAreAllLineString )
+        {
+            return OGRCurve::CastToLineString(poCC);
+        }
+        else
+            return poCC;
+    }
+    
 /* -------------------------------------------------------------------- */
 /*      Curve                                                           */
 /* -------------------------------------------------------------------- */
@@ -1516,10 +2333,11 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 
         OGRGeometry *poGeom;
 
-        poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                          nRecLevel + 1);
+        poGeom = GML2OGRGeometry_XMLNode_Internal(
+            psChild, bGetSecondaryGeometryOption,
+            nRecLevel + 1, nSRSDimension, pszSRSName );
         if( poGeom == NULL ||
-            wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+            !OGR_GT_IsCurve(poGeom->getGeometryType()) )
         {
             CPLError( CE_Failure, CPLE_AppDefined, 
                 "Curve: Got %.500s geometry as Member instead of segments.",
@@ -1537,7 +2355,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     if( EQUAL(pszBaseGeometry,"segments") )
     {
         const CPLXMLNode *psChild;
-        OGRLineString *poLS = new OGRLineString();
+        OGRCurve* poCurve = NULL;
+        OGRCompoundCurve *poCC = NULL;
+        int bChildrenAreAllLineString = TRUE;
 
         for( psChild = psNode->psChild; 
              psChild != NULL;
@@ -1545,51 +2365,71 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 
         {
             if( psChild->eType == CXT_Element
-                && (EQUAL(BareGMLElement(psChild->pszValue),"LineStringSegment") ||
+                /*&& (EQUAL(BareGMLElement(psChild->pszValue),"LineStringSegment") ||
                     EQUAL(BareGMLElement(psChild->pszValue),"GeodesicString") ||
                     EQUAL(BareGMLElement(psChild->pszValue),"Arc") ||
-                    EQUAL(BareGMLElement(psChild->pszValue),"Circle")) )
+                    EQUAL(BareGMLElement(psChild->pszValue),"Circle"))*/ )
             {
                 OGRGeometry *poGeom;
 
-                poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                                  nRecLevel + 1);
-                if( poGeom != NULL &&
-                    wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                poGeom = GML2OGRGeometry_XMLNode_Internal(
+                    psChild, bGetSecondaryGeometryOption,
+                    nRecLevel + 1, nSRSDimension, pszSRSName );
+                if( poGeom == NULL ||
+                    !OGR_GT_IsCurve(poGeom->getGeometryType()) )
                 {
                     CPLError( CE_Failure, CPLE_AppDefined,
-                              "segments: Got %.500s geometry as Member instead of LINESTRING.",
+                              "segments: Got %.500s geometry as Member instead of curve.",
                               poGeom ? poGeom->getGeometryName() : "NULL" );
                     delete poGeom;
-                    delete poLS;
+                    delete poCurve;
+                    delete poCC;
                     return NULL;
                 }
-                OGRLineString *poAddLS = (OGRLineString *)poGeom;
-                if( poAddLS != NULL && poAddLS->getNumPoints() >= 2 )
+
+                if( wkbFlatten(poGeom->getGeometryType()) != wkbLineString )
+                    bChildrenAreAllLineString = FALSE;
+
+                if( poCC == NULL && poCurve == NULL )
+                    poCurve = (OGRCurve*)poGeom;
+                else
                 {
-                    if( poLS->getNumPoints() > 0
-                        && fabs(poLS->getX(poLS->getNumPoints()-1)
-                                - poAddLS->getX(0)) < 1e-14
-                        && fabs(poLS->getY(poLS->getNumPoints()-1)
-                                - poAddLS->getY(0)) < 1e-14
-                        && fabs(poLS->getZ(poLS->getNumPoints()-1)
-                                - poAddLS->getZ(0)) < 1e-14) 
+                    if( poCC == NULL )
                     {
-                        // Skip the first point of the new linestring to avoid
-                        // invalidate duplicate points (#4451)
-                        poLS->addSubLineString( poAddLS, 1 );
+                        poCC = new OGRCompoundCurve();
+                        if( poCC->addCurveDirectly(poCurve) != OGRERR_NONE )
+                        {
+                            delete poGeom;
+                            delete poCurve;
+                            delete poCC;
+                            return NULL;
+                        }
+                        poCurve = NULL;
                     }
-                    else
+
+                    if( poCC->addCurveDirectly((OGRCurve*)poGeom) != OGRERR_NONE )
                     {
-                        // Add the whole new line string
-                        poLS->addSubLineString( poAddLS );
+                        delete poGeom;
+                        delete poCC;
+                        return NULL;
                     }
                 }
-                delete poGeom;
             }
         }
 
-        return poLS;
+        if( poCurve != NULL )
+            return poCurve;
+        if( poCC == NULL )
+            return NULL;
+
+        if( bCastToLinearTypeIfPossible && bChildrenAreAllLineString )
+        {
+            return OGRCurve::CastToLineString(poCC);
+        }
+        else
+        {
+            return poCC;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1617,8 +2457,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
 
                 if (psGeometryChild != NULL)
                 {
-                    poGeom = GML2OGRGeometry_XMLNode( psGeometryChild, bGetSecondaryGeometryOption,
-                                                      nRecLevel + 1 );
+                    poGeom = GML2OGRGeometry_XMLNode_Internal(
+                        psGeometryChild, bGetSecondaryGeometryOption,
+                        nRecLevel + 1, nSRSDimension, pszSRSName );
                     if( poGeom == NULL )
                     {
                         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -1686,8 +2527,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
             if( psPoint == NULL ) goto nonode;
 
-            poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
-                                              nRecLevel + 1, TRUE );
+            poGeom = GML2OGRGeometry_XMLNode_Internal(
+                psPoint, bGetSecondaryGeometryOption,
+                nRecLevel + 1, nSRSDimension, pszSRSName, TRUE );
             if( poGeom == NULL
                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
             {
@@ -1726,8 +2568,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 psPoint = FindBareXMLChild(pspointProperty,"ConnectionPoint");
             if( psPoint == NULL ) goto nonode;
 
-            poGeom = GML2OGRGeometry_XMLNode( psPoint, bGetSecondaryGeometryOption,
-                                              nRecLevel + 1, TRUE );
+            poGeom = GML2OGRGeometry_XMLNode_Internal(
+                psPoint, bGetSecondaryGeometryOption,
+                nRecLevel + 1, nSRSDimension, pszSRSName, TRUE );
             if( poGeom == NULL
                 || wkbFlatten(poGeom->getGeometryType()) != wkbPoint )
             {
@@ -1771,8 +2614,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             return NULL;
         }
 
-        poLineString = (OGRLineString *)GML2OGRGeometry_XMLNode( psCurve, bGetSecondaryGeometryOption,
-                                                                 nRecLevel + 1, TRUE );
+        poLineString = (OGRLineString *)GML2OGRGeometry_XMLNode_Internal(
+            psCurve, bGetSecondaryGeometryOption,
+            nRecLevel + 1, nSRSDimension, pszSRSName, TRUE );
         if( poLineString == NULL 
             || wkbFlatten(poLineString->getGeometryType()) != wkbLineString )
         {
@@ -1853,8 +2697,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             {
                 OGRGeometry *poGeom;
 
-                poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                                  nRecLevel + 1 );
+                poGeom = GML2OGRGeometry_XMLNode_Internal(
+                    psChild, bGetSecondaryGeometryOption,
+                    nRecLevel + 1, nSRSDimension, pszSRSName );
                 if( poGeom == NULL )
                 {
                     CPLError( CE_Failure, CPLE_AppDefined, 
@@ -1983,8 +2828,11 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                   {
                     OGRGeometry *poEdgeGeom;
 
-                    poEdgeGeom = GML2OGRGeometry_XMLNode( psDirectedEdgeChild,
+                    poEdgeGeom = GML2OGRGeometry_XMLNode_Internal( psDirectedEdgeChild,
                                                           bGetSecondaryGeometryOption,
+                                                          nRecLevel + 1,
+                                                          nSRSDimension,
+                                                          pszSRSName,
                                                           TRUE );
 
                     if( poEdgeGeom == NULL ||
@@ -2127,9 +2975,11 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
               {
                 OGRGeometry *poEdgeGeom;
 
-                poEdgeGeom = GML2OGRGeometry_XMLNode( psDirectedEdgeChild,
+                poEdgeGeom = GML2OGRGeometry_XMLNode_Internal( psDirectedEdgeChild,
                                                       bGetSecondaryGeometryOption,
                                                       nRecLevel + 1,
+                                                      nSRSDimension,
+                                                      pszSRSName,
                                                       TRUE,
                                                       bFaceOrientation );
 
@@ -2229,7 +3079,6 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     if( EQUAL(pszBaseGeometry,"Surface") )
     {
         const CPLXMLNode *psChild;
-        OGRGeometry *poResult = NULL;
 
         // Find outer ring.
         psChild = FindBareXMLChild( psNode, "patches" );
@@ -2245,6 +3094,8 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             return new OGRPolygon();
         }
 
+        OGRMultiSurface* poMS = NULL;
+        OGRGeometry* poResult = NULL;
         for( ; psChild != NULL; psChild = psChild->psNext )
         {
             if( psChild->eType == CXT_Element
@@ -2252,28 +3103,51 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                     EQUAL(BareGMLElement(psChild->pszValue),"Triangle") ||
                     EQUAL(BareGMLElement(psChild->pszValue),"Rectangle")))
             {
-                OGRPolygon *poPolygon = (OGRPolygon *) 
-                    GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                             nRecLevel + 1 );
-                if( poPolygon == NULL )
-                    return NULL;
-                
-                if( poResult == NULL )
-                    poResult = poPolygon;
-                else if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon )
+                OGRGeometry *poGeom =
+                    GML2OGRGeometry_XMLNode_Internal(
+                        psChild, bGetSecondaryGeometryOption,
+                        nRecLevel + 1, nSRSDimension, pszSRSName );
+                if( poGeom == NULL )
                 {
-                    OGRMultiPolygon *poMP = new OGRMultiPolygon();
-                    poMP->addGeometryDirectly( poResult );
-                    poMP->addGeometryDirectly( poPolygon );
-                    poResult = poMP;
+                    delete poResult;
+                    return NULL;
                 }
+
+                OGRwkbGeometryType eGeomType = wkbFlatten(poGeom->getGeometryType());
+
+                if( poResult == NULL )
+                    poResult = poGeom;
                 else
                 {
-                    ((OGRMultiPolygon *) poResult)->addGeometryDirectly( poPolygon );
+                    if( poMS == NULL )
+                    {
+                        if( wkbFlatten(poResult->getGeometryType()) == wkbPolygon &&
+                            eGeomType == wkbPolygon )
+                            poMS = new OGRMultiPolygon();
+                        else
+                            poMS = new OGRMultiSurface();
+#ifdef DEBUG
+                        OGRErr eErr =
+#endif
+                          poMS->addGeometryDirectly( poResult );
+                        CPLAssert(eErr == OGRERR_NONE);
+                        poResult = poMS;
+                    }
+                    else if( eGeomType != wkbPolygon &&
+                             wkbFlatten(poMS->getGeometryType()) == wkbMultiPolygon )
+                    {
+                        poMS = OGRMultiPolygon::CastToMultiSurface((OGRMultiPolygon*)poMS);
+                        poResult = poMS;
+                    }
+#ifdef DEBUG
+                    OGRErr eErr =
+#endif
+                      poMS->addGeometryDirectly( poGeom );
+                    CPLAssert(eErr == OGRERR_NONE);
                 }
             }
         }
-        
+
         return poResult;
     }
 
@@ -2305,8 +3179,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                 && EQUAL(BareGMLElement(psChild->pszValue),"Triangle") )
             {
                 OGRPolygon *poPolygon = (OGRPolygon *)
-                    GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                             nRecLevel + 1 );
+                    GML2OGRGeometry_XMLNode_Internal(
+                        psChild, bGetSecondaryGeometryOption,
+                        nRecLevel + 1, nSRSDimension, pszSRSName );
                 if( poPolygon == NULL )
                     return NULL;
 
@@ -2348,8 +3223,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
         }
 
         // Get the geometry inside <exterior>
-        poGeom = GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                          nRecLevel + 1 );
+        poGeom = GML2OGRGeometry_XMLNode_Internal(
+            psChild, bGetSecondaryGeometryOption,
+            nRecLevel + 1, nSRSDimension, pszSRSName );
         if( poGeom == NULL )
         {
             CPLError( CE_Failure, CPLE_AppDefined, "Invalid exterior element");
@@ -2390,8 +3266,9 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
             return NULL;
         }
 
-        return GML2OGRGeometry_XMLNode( psChild, bGetSecondaryGeometryOption,
-                                        nRecLevel + 1 );
+        return GML2OGRGeometry_XMLNode_Internal(
+            psChild, bGetSecondaryGeometryOption,
+            nRecLevel + 1, nSRSDimension, pszSRSName );
     }
 
 /* -------------------------------------------------------------------- */
@@ -2404,7 +3281,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLinearRing   *poRing = new OGRLinearRing();
 
-        if( !ParseGMLCoordinates( psNode, poRing ) )
+        if( !ParseGMLCoordinates( psNode, poRing, nSRSDimension ) )
         {
             delete poRing;
             return NULL;
@@ -2424,7 +3301,7 @@ OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
     {
         OGRLineString   *poLS = new OGRLineString();
 
-        if( !ParseGMLCoordinates( psNode, poLS ) )
+        if( !ParseGMLCoordinates( psNode, poLS, nSRSDimension ) )
         {
             delete poLS;
             return NULL;
@@ -2517,7 +3394,7 @@ OGRGeometryH OGR_G_CreateFromGML( const char *pszGML )
 
     /* Must be in synced in OGR_G_CreateFromGML(), OGRGMLLayer::OGRGMLLayer() and GMLReader::GMLReader() */
     int bFaceHoleNegative = CSLTestBoolean(CPLGetConfigOption("GML_FACE_HOLE_NEGATIVE", "NO"));
-    poGeometry = GML2OGRGeometry_XMLNode( psGML, -1, 0, FALSE, TRUE, bFaceHoleNegative );
+    poGeometry = GML2OGRGeometry_XMLNode( psGML, -1, 0, 0, FALSE, TRUE, bFaceHoleNegative );
 
     CPLDestroyXMLNode( psGML );
     
diff --git a/ogr/makefile.vc b/ogr/makefile.vc
index 451fbc4..746e588 100644
--- a/ogr/makefile.vc
+++ b/ogr/makefile.vc
@@ -9,6 +9,8 @@ GDAL_ROOT = 	..
 
 !IFDEF INCLUDE_OGR_FRMTS
 EXTRAFLAGS = $(EXTRAFLAGS) -DOGR_ENABLED -DHAVE_MITAB
+!ELSE
+EXTRAFLAGS = $(EXTRAFLAGS) -DHAVE_MITAB
 !ENDIF
 
 !IFDEF EXPAT_DIR
@@ -17,11 +19,13 @@ EXTRAFLAGS = $(EXTRAFLAGS) $(EXPAT_INCLUDE) -DHAVE_EXPAT
 
 
 OGR_FRMTS =	ogrsf_frmts\ogrsf_frmts.lib ogrsf_frmts\ogrsf_frmts_sup.lib
-OBJ_OGR	=	ogrgeometryfactory.obj ogrpoint.obj ogrcurve.obj ogr_api.obj \
+OBJ_OGR	=	ogrgeometryfactory.obj ogrpoint.obj ogrcurve.obj ogrsurface.obj ogr_api.obj \
 		ogrlinestring.obj ogrpolygon.obj ogrlinearring.obj \
 		ogrutils.obj ogrgeometry.obj ogrgeometrycollection.obj \
 		ogrmultipolygon.obj ogrmultilinestring.obj ogr_opt.obj \
-                ogrmultipoint.obj ogrfeature.obj ogrfeaturedefn.obj \
+		ogrmultipoint.obj ogrcircularstring.obj ogrcompoundcurve.obj \
+		ogrcurvepolygon.obj ogrcurvecollection.obj ogrmultisurface.obj \
+		ogrmulticurve.obj ogrfeature.obj ogrfeaturedefn.obj \
 		ogrfielddefn.obj ogr_srsnode.obj ogrspatialreference.obj \
 		ogr_srs_proj4.obj ogr_fromepsg.obj ogrct.obj \
 		ogrfeaturestyle.obj ogr_srs_esri.obj ogrfeaturequery.obj \
@@ -32,7 +36,7 @@ OBJ_OGR	=	ogrgeometryfactory.obj ogrpoint.obj ogrcurve.obj ogr_api.obj \
 		swq.obj swq_parser.obj swq_select.obj swq_op_registrar.obj \
 		swq_op_general.obj swq_expr_node.obj ogrpgeogeometry.obj \
 		ogrgeomediageometry.obj ogr_geocoding.obj osr_cs_wkt.obj \
-		osr_cs_wkt_parser.obj ogrgeomfielddefn.obj
+		osr_cs_wkt_parser.obj ogrgeomfielddefn.obj ograpispy.obj
 
 default:        ogr.lib 
 
diff --git a/ogr/ogr2gmlgeometry.cpp b/ogr/ogr2gmlgeometry.cpp
index cff0cdf..b1304a9 100644
--- a/ogr/ogr2gmlgeometry.cpp
+++ b/ogr/ogr2gmlgeometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr2gmlgeometry.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr2gmlgeometry.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  GML Translator
  * Purpose:  Code to translate OGRGeometry to GML string representation.
@@ -47,6 +47,9 @@
 #include "cpl_error.h"
 #include "cpl_conv.h"
 
+#define SRSDIM_LOC_GEOMETRY (1 << 0)
+#define SRSDIM_LOC_POSLIST  (1 << 1)
+
 /************************************************************************/
 /*                        MakeGMLCoordinate()                           */
 /************************************************************************/
@@ -69,23 +72,23 @@ static void MakeGMLCoordinate( char *pszTarget,
         if( x == (int) x && y == (int) y )
             sprintf( pszTarget, "%d,%d", (int) x, (int) y );
         else if( fabs(x) < 370 && fabs(y) < 370 )
-            sprintf( pszTarget, "%.16g,%.16g", x, y );
+            CPLsprintf( pszTarget, "%.16g,%.16g", x, y );
         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 )
-            sprintf( pszTarget, "%.16g,%.16g", x, y );
+            CPLsprintf( pszTarget, "%.16g,%.16g", x, y );
         else
-            sprintf( pszTarget, "%.3f,%.3f", x, y );
+            CPLsprintf( pszTarget, "%.3f,%.3f", x, y );
     }
     else
     {
         if( x == (int) x && y == (int) y && z == (int) z )
             sprintf( pszTarget, "%d,%d,%d", (int) x, (int) y, (int) z );
         else if( fabs(x) < 370 && fabs(y) < 370 )
-            sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
+            CPLsprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 
                  || fabs(z) > 100000000.0 )
-            sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
+            CPLsprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
         else
-            sprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
+            CPLsprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
     }
 #endif
 }
@@ -130,7 +133,7 @@ static void AppendCoordinateList( OGRLineString *poLine,
 
 {
     char        szCoordinate[256];
-    int         b3D = (poLine->getGeometryType() & wkb25DBit);
+    int         b3D = wkbHasZ(poLine->getGeometryType());
 
     *pnLength += strlen(*ppszText + *pnLength);
     _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
@@ -211,10 +214,13 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
         }
     }
 
+    OGRwkbGeometryType eType = poGeometry->getGeometryType();
+    OGRwkbGeometryType eFType = wkbFlatten(eType);
+
 /* -------------------------------------------------------------------- */
 /*      2D Point                                                        */
 /* -------------------------------------------------------------------- */
-    if( poGeometry->getGeometryType() == wkbPoint )
+    if( eType == wkbPoint )
     {
         char    szCoordinate[256];
         OGRPoint *poPoint = (OGRPoint *) poGeometry;
@@ -234,7 +240,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      3D Point                                                        */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbPoint25D )
+    else if( eType == wkbPoint25D )
     {
         char    szCoordinate[256];
         OGRPoint *poPoint = (OGRPoint *) poGeometry;
@@ -256,8 +262,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      LineString and LinearRing                                       */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbLineString 
-             || poGeometry->getGeometryType() == wkbLineString25D )
+    else if( eFType == wkbLineString )
     {
         int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
 
@@ -298,8 +303,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      Polygon                                                         */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbPolygon 
-             || poGeometry->getGeometryType() == wkbPolygon25D )
+    else if( eFType == wkbPolygon )
     {
         OGRPolygon      *poPolygon = (OGRPolygon *) poGeometry;
 
@@ -357,10 +361,10 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      MultiPolygon, MultiLineString, MultiPoint, MultiGeometry        */
 /* -------------------------------------------------------------------- */
-    else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon 
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
+    else if( eFType == wkbMultiPolygon 
+             || eFType == wkbMultiLineString
+             || eFType == wkbMultiPoint
+             || eFType == wkbGeometryCollection )
     {
         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
         int             iMember;
@@ -370,7 +374,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
         // Buffer for opening tag + srsName attribute
         char* pszElemOpen = NULL;
 
-        if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
+        if( eFType == wkbMultiPolygon )
         {
             pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiPolygon%s>", szAttributes );
@@ -378,7 +382,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
             pszElemClose = "MultiPolygon>";
             pszMemberElem = "polygonMember>";
         }
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
+        else if( eFType == wkbMultiLineString )
         {
             pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiLineString%s>", szAttributes );
@@ -386,7 +390,7 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
             pszElemClose = "MultiLineString>";
             pszMemberElem = "lineStringMember>";
         }
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
+        else if( eFType == wkbMultiPoint )
         {
             pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );
@@ -432,6 +436,8 @@ static int OGR2GMLGeometryAppend( OGRGeometry *poGeometry,
     }
     else
     {
+        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported geometry type %s",
+                 OGRGeometryTypeToName(eType));
         return FALSE;
     }
 
@@ -500,18 +506,18 @@ CPLXMLNode *OGR_G_ExportEnvelopeToGMLTree( OGRGeometryH hGeometry )
 /*                     AppendGML3CoordinateList()                       */
 /************************************************************************/
 
-static void AppendGML3CoordinateList( OGRLineString *poLine, int bCoordSwap,
-                                  char **ppszText, int *pnLength,
-                                  int *pnMaxLength )
+static void AppendGML3CoordinateList( const OGRSimpleCurve *poLine, int bCoordSwap,
+                                      char **ppszText, int *pnLength,
+                                      int *pnMaxLength, int nSRSDimensionLocFlags )
 
 {
     char        szCoordinate[256];
-    int         b3D = (poLine->getGeometryType() & wkb25DBit);
+    int         b3D = wkbHasZ(poLine->getGeometryType());
 
     *pnLength += strlen(*ppszText + *pnLength);
     _GrowBuffer( *pnLength + 40, ppszText, pnMaxLength );
 
-    if (b3D)
+    if (b3D && (nSRSDimensionLocFlags & SRSDIM_LOC_POSLIST) != 0)
         strcat( *ppszText + *pnLength, "<gml:posList srsDimension=\"3\">" );
     else
         strcat( *ppszText + *pnLength, "<gml:posList>" );
@@ -551,14 +557,16 @@ static void AppendGML3CoordinateList( OGRLineString *poLine, int bCoordSwap,
 /*                      OGR2GML3GeometryAppend()                        */
 /************************************************************************/
 
-static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
+static int OGR2GML3GeometryAppend( const OGRGeometry *poGeometry,
                                    const OGRSpatialReference* poParentSRS,
-                                  char **ppszText, int *pnLength,
-                                  int *pnMaxLength,
-                                  int bIsSubGeometry,
-                                  int bLongSRS,
-                                  int bLineStringAsCurve,
-                                  const char* pszGMLId = NULL)
+                                   char **ppszText, int *pnLength,
+                                   int *pnMaxLength,
+                                   int bIsSubGeometry,
+                                   int bLongSRS,
+                                   int bLineStringAsCurve,
+                                   const char* pszGMLId,
+                                   int nSRSDimensionLocFlags,
+                                   int bForceLineStringAsLinearRing )
 
 {
 
@@ -566,7 +574,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
 /*      Check for Spatial Reference System attached to given geometry   */
 /* -------------------------------------------------------------------- */
 
-    // Buffer for srsName and gml:id attributes (srsName="..." gml:id="...")
+    // Buffer for srsName, srsDimension and gml:id attributes (srsName="..." gml:id="...")
     char szAttributes[256];
     int nAttrsLength = 0;
 
@@ -632,6 +640,15 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
         }
     }
 
+    if( (nSRSDimensionLocFlags & SRSDIM_LOC_GEOMETRY) != 0 &&
+        wkbHasZ(poGeometry->getGeometryType()) )
+    {
+        strcat(szAttributes, " srsDimension=\"3\"");
+        nAttrsLength = strlen(szAttributes);
+
+        nSRSDimensionLocFlags &= ~SRSDIM_LOC_GEOMETRY;
+    }
+
     if (pszGMLId != NULL && nAttrsLength + 9 + strlen(pszGMLId) + 1 < sizeof(szAttributes))
     {
         strcat(szAttributes, " gml:id=\"");
@@ -640,10 +657,13 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
         nAttrsLength = strlen(szAttributes);
     }
 
+    OGRwkbGeometryType eType = poGeometry->getGeometryType();
+    OGRwkbGeometryType eFType = wkbFlatten(eType);
+
 /* -------------------------------------------------------------------- */
 /*      2D Point                                                        */
 /* -------------------------------------------------------------------- */
-    if( poGeometry->getGeometryType() == wkbPoint )
+    if( eType == wkbPoint )
     {
         char    szCoordinate[256];
         OGRPoint *poPoint = (OGRPoint *) poGeometry;
@@ -667,7 +687,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      3D Point                                                        */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbPoint25D )
+    else if( eType == wkbPoint25D )
     {
         char    szCoordinate[256];
         OGRPoint *poPoint = (OGRPoint *) poGeometry;
@@ -692,10 +712,10 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
 /* -------------------------------------------------------------------- */
 /*      LineString and LinearRing                                       */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbLineString
-             || poGeometry->getGeometryType() == wkbLineString25D )
+    else if( eFType == wkbLineString )
     {
-        int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING");
+        int bRing = EQUAL(poGeometry->getGeometryName(),"LINEARRING") ||
+                    bForceLineStringAsLinearRing;
         if (!bRing && bLineStringAsCurve)
         {
             AppendString( ppszText, pnLength, pnMaxLength,
@@ -705,7 +725,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
             AppendString( ppszText, pnLength, pnMaxLength,
                             "><gml:segments><gml:LineStringSegment>" );
             AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
-                                ppszText, pnLength, pnMaxLength );
+                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
             AppendString( ppszText, pnLength, pnMaxLength,
                             "</gml:LineStringSegment></gml:segments></gml:Curve>" );
         }
@@ -734,7 +754,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
             CPLFree( pszLineTagName );
 
             AppendGML3CoordinateList( (OGRLineString *) poGeometry, bCoordSwap,
-                                ppszText, pnLength, pnMaxLength );
+                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
 
             if( bRing )
                 AppendString( ppszText, pnLength, pnMaxLength,
@@ -746,12 +766,91 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
     }
 
 /* -------------------------------------------------------------------- */
+/*      ArcString or Circle                                             */
+/* -------------------------------------------------------------------- */
+    else if( eFType == wkbCircularString )
+    {
+        AppendString( ppszText, pnLength, pnMaxLength,
+                        "<gml:Curve" );
+        AppendString( ppszText, pnLength, pnMaxLength,
+                        szAttributes );
+        OGRSimpleCurve* poSC = (OGRSimpleCurve *) poGeometry;
+        /* SQL MM has a unique type for arc and circle, GML not */
+        if( poSC->getNumPoints() == 3 &&
+            poSC->getX(0) == poSC->getX(2) &&
+            poSC->getY(0) == poSC->getY(2) )
+        {
+            double dfMidX = (poSC->getX(0) + poSC->getX(1)) / 2;
+            double dfMidY = (poSC->getY(0) + poSC->getY(1)) / 2;
+            double dfDirX = (poSC->getX(1) - poSC->getX(0)) / 2;
+            double dfDirY = (poSC->getY(1) - poSC->getY(0)) / 2;
+            double dfNormX = -dfDirY;
+            double dfNormY = dfDirX;
+            double dfNewX = dfMidX + dfNormX;
+            double dfNewY = dfMidY + dfNormY;
+            OGRLineString* poLS = new OGRLineString();
+            OGRPoint p;
+            poSC->getPoint(0, &p);
+            poLS->addPoint(&p);
+            poSC->getPoint(1, &p);
+            if( poSC->getCoordinateDimension() == 3 )
+                poLS->addPoint(dfNewX, dfNewY, p.getZ());
+            else
+                poLS->addPoint(dfNewX, dfNewY);
+            poLS->addPoint(&p);
+            AppendString( ppszText, pnLength, pnMaxLength,
+                            "><gml:segments><gml:Circle>" );
+            AppendGML3CoordinateList( poLS, bCoordSwap,
+                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
+            AppendString( ppszText, pnLength, pnMaxLength,
+                            "</gml:Circle></gml:segments></gml:Curve>" );
+            delete poLS;
+        }
+        else
+        {
+            AppendString( ppszText, pnLength, pnMaxLength,
+                            "><gml:segments><gml:ArcString>" );
+            AppendGML3CoordinateList( poSC, bCoordSwap,
+                                ppszText, pnLength, pnMaxLength, nSRSDimensionLocFlags );
+            AppendString( ppszText, pnLength, pnMaxLength,
+                            "</gml:ArcString></gml:segments></gml:Curve>" );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      CompositeCurve                                                  */
+/* -------------------------------------------------------------------- */
+    else if( eFType == wkbCompoundCurve )
+    {
+        AppendString( ppszText, pnLength, pnMaxLength,
+                        "<gml:CompositeCurve" );
+        AppendString( ppszText, pnLength, pnMaxLength,
+                        szAttributes );
+        AppendString( ppszText, pnLength, pnMaxLength,">");
+
+        OGRCompoundCurve* poCC = (OGRCompoundCurve*)poGeometry;
+        for(int i=0;i<poCC->getNumCurves();i++)
+        {
+            AppendString( ppszText, pnLength, pnMaxLength,
+                          "<gml:curveMember>" );
+            if( !OGR2GML3GeometryAppend( poCC->getCurve(i), poSRS, ppszText, pnLength,
+                                         pnMaxLength, TRUE, bLongSRS,
+                                         bLineStringAsCurve,
+                                         NULL, nSRSDimensionLocFlags, FALSE) )
+                return FALSE;
+            AppendString( ppszText, pnLength, pnMaxLength,
+                          "</gml:curveMember>" );
+        }
+        AppendString( ppszText, pnLength, pnMaxLength,
+                      "</gml:CompositeCurve>" );
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Polygon                                                         */
 /* -------------------------------------------------------------------- */
-    else if( poGeometry->getGeometryType() == wkbPolygon
-             || poGeometry->getGeometryType() == wkbPolygon25D )
+    else if( eFType == wkbPolygon || eFType == wkbCurvePolygon )
     {
-        OGRPolygon      *poPolygon = (OGRPolygon *) poGeometry;
+        OGRCurvePolygon      *poCP = (OGRCurvePolygon *) poGeometry;
 
         // Buffer for polygon tag name + srsName attribute if set
         const size_t nPolyTagLength = 13;
@@ -769,14 +868,15 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
 
         // Don't add srsName to polygon rings
 
-        if( poPolygon->getExteriorRing() != NULL )
+        if( poCP->getExteriorRingCurve() != NULL )
         {
             AppendString( ppszText, pnLength, pnMaxLength,
                           "<gml:exterior>" );
 
-            if( !OGR2GML3GeometryAppend( poPolygon->getExteriorRing(), poSRS,
-                                        ppszText, pnLength, pnMaxLength,
-                                        TRUE, bLongSRS, bLineStringAsCurve ) )
+            if( !OGR2GML3GeometryAppend( poCP->getExteriorRingCurve(), poSRS,
+                                         ppszText, pnLength, pnMaxLength,
+                                         TRUE, bLongSRS, bLineStringAsCurve,
+                                         NULL, nSRSDimensionLocFlags, TRUE) )
             {
                 return FALSE;
             }
@@ -785,15 +885,17 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
                           "</gml:exterior>" );
         }
 
-        for( int iRing = 0; iRing < poPolygon->getNumInteriorRings(); iRing++ )
+        for( int iRing = 0; iRing < poCP->getNumInteriorRings(); iRing++ )
         {
-            OGRLinearRing *poRing = poPolygon->getInteriorRing(iRing);
+            OGRCurve *poRing = poCP->getInteriorRingCurve(iRing);
 
             AppendString( ppszText, pnLength, pnMaxLength,
                           "<gml:interior>" );
 
             if( !OGR2GML3GeometryAppend( poRing, poSRS, ppszText, pnLength,
-                                        pnMaxLength, TRUE, bLongSRS, bLineStringAsCurve ) )
+                                         pnMaxLength, TRUE, bLongSRS,
+                                         bLineStringAsCurve,
+                                         NULL, nSRSDimensionLocFlags, TRUE) )
                 return FALSE;
 
             AppendString( ppszText, pnLength, pnMaxLength,
@@ -805,12 +907,14 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
     }
 
 /* -------------------------------------------------------------------- */
-/*      MultiPolygon, MultiLineString, MultiPoint, MultiGeometry        */
+/*      MultiSurface, MultiCurve, MultiPoint, MultiGeometry             */
 /* -------------------------------------------------------------------- */
-    else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
+    else if( eFType == wkbMultiPolygon
+             || eFType == wkbMultiSurface
+             || eFType == wkbMultiLineString
+             || eFType == wkbMultiCurve
+             || eFType == wkbMultiPoint
+             || eFType == wkbGeometryCollection )
     {
         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
         int             iMember;
@@ -820,7 +924,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
         // Buffer for opening tag + srsName attribute
         char* pszElemOpen = NULL;
 
-        if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon )
+        if( eFType == wkbMultiPolygon || eFType == wkbMultiSurface )
         {
             pszElemOpen = (char *) CPLMalloc( 13 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiSurface%s>", szAttributes );
@@ -828,7 +932,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
             pszElemClose = "MultiSurface>";
             pszMemberElem = "surfaceMember>";
         }
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString )
+        else if( eFType == wkbMultiLineString || eFType == wkbMultiCurve )
         {
             pszElemOpen = (char *) CPLMalloc( 16 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiCurve%s>", szAttributes );
@@ -836,7 +940,7 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
             pszElemClose = "MultiCurve>";
             pszMemberElem = "curveMember>";
         }
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint )
+        else if( eFType == wkbMultiPoint )
         {
             pszElemOpen = (char *) CPLMalloc( 11 + nAttrsLength + 1 );
             sprintf( pszElemOpen, "MultiPoint%s>", szAttributes );
@@ -868,9 +972,9 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
                 pszGMLIdSub = CPLStrdup(CPLSPrintf("%s.%d", pszGMLId, iMember));
 
             if( !OGR2GML3GeometryAppend( poMember, poSRS,
-                                        ppszText, pnLength, pnMaxLength,
-                                        TRUE, bLongSRS, bLineStringAsCurve,
-                                         pszGMLIdSub) )
+                                         ppszText, pnLength, pnMaxLength,
+                                         TRUE, bLongSRS, bLineStringAsCurve,
+                                         pszGMLIdSub, nSRSDimensionLocFlags, FALSE ) )
             {
                 CPLFree(pszGMLIdSub);
                 return FALSE;
@@ -890,6 +994,8 @@ static int OGR2GML3GeometryAppend( OGRGeometry *poGeometry,
     }
     else
     {
+        CPLError(CE_Failure, CPLE_NotSupported, "Unsupported geometry type %s",
+                 OGRGeometryTypeToName(eType));
         return FALSE;
     }
 
@@ -951,7 +1057,7 @@ char *OGR_G_ExportToGML( OGRGeometryH hGeometry )
  * types assuming the this is available in the gml namespace.  The returned
  * string should be freed with CPLFree() when no longer required.
  *
- * The supported options in OGR 1.8.0 are :
+ * The supported options are :
  * <ul>
  * <li> FORMAT=GML3. Otherwise it will default to GML 2.1.2 output.
  * <li> GML3_LINESTRING_ELEMENT=curve. (Only valid for FORMAT=GML3) To use gml:Curve element for linestrings.
@@ -963,8 +1069,15 @@ char *OGR_G_ExportToGML( OGRGeometryH hGeometry )
  *      If set to NO, SRS with EPSG authority will be written with the "EPSG:" prefix, even if they are in lat/long order.
  * <li> GMLID=astring. If specified, a gml:id attribute will be written in the top-level geometry element with the provided value.
  *      Required for GML 3.2 compatibility.
+ * <li> SRSDIMENSION_LOC=POSLIST/GEOMETRY/GEOMETRY,POSLIST. (Only valid for FORMAT=GML3, GDAL >= 2.0) Default to POSLIST.
+ *      For 2.5D geometries, define the location where to attach the srsDimension attribute.
+ *      There are diverging implementations. Some put in on the <gml:posList> element, other
+ *      on the top geometry element.
  * </ul>
  *
+ * Note that curve geometries like CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, 
+ * MULTICURVE or MULTISURFACE are not supported in GML 2.
+ *
  * This method is the same as the C++ method OGRGeometry::exportToGML().
  *
  * @param hGeometry handle to the geometry.
@@ -993,8 +1106,23 @@ char *OGR_G_ExportToGMLEx( OGRGeometryH hGeometry, char** papszOptions )
         int bLineStringAsCurve = (pszLineStringElement && EQUAL(pszLineStringElement, "curve"));
         int bLongSRS = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "GML3_LONGSRS", "YES"));
         const char* pszGMLId = CSLFetchNameValue(papszOptions, "GMLID");
+        const char* pszSRSDimensionLoc = CSLFetchNameValueDef(papszOptions,"SRSDIMENSION_LOC","POSLIST");
+        char** papszSRSDimensionLoc = CSLTokenizeString2(pszSRSDimensionLoc, ",", 0);
+        int nSRSDimensionLocFlags = 0;
+        for(int i=0; papszSRSDimensionLoc[i] != NULL; i++)
+        {
+            if( EQUAL(papszSRSDimensionLoc[i], "POSLIST") )
+                nSRSDimensionLocFlags |= SRSDIM_LOC_POSLIST;
+            else if( EQUAL(papszSRSDimensionLoc[i], "GEOMETRY") )
+                nSRSDimensionLocFlags |= SRSDIM_LOC_GEOMETRY;
+            else
+                CPLDebug("OGR", "Unrecognized location for srsDimension : %s",
+                         papszSRSDimensionLoc[i]);
+        }
+        CSLDestroy(papszSRSDimensionLoc);
         if( !OGR2GML3GeometryAppend( (OGRGeometry *) hGeometry, NULL, &pszText,
-                                    &nLength, &nMaxLength, FALSE, bLongSRS, bLineStringAsCurve, pszGMLId ))
+                                    &nLength, &nMaxLength, FALSE, bLongSRS,
+                                     bLineStringAsCurve, pszGMLId, nSRSDimensionLocFlags, FALSE ))
         {
             CPLFree( pszText );
             return NULL;
diff --git a/ogr/ogr_api.cpp b/ogr/ogr_api.cpp
index 261ef32..2abe6cb 100644
--- a/ogr/ogr_api.cpp
+++ b/ogr/ogr_api.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_api.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_api.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  C API Functions that don't correspond one-to-one with C++ 
@@ -33,6 +33,8 @@
 #include "ogr_api.h"
 #include "cpl_error.h"
 
+static int bNonLinearGeometriesEnabled = TRUE;
+
 /************************************************************************/
 /*                        OGR_G_GetPointCount()                         */
 /************************************************************************/
@@ -51,18 +53,13 @@ int OGR_G_GetPointCount( OGRGeometryH hGeom )
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_GetPointCount", 0 );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
-    {
-      case wkbPoint:
+    OGRwkbGeometryType eGType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( eGType == wkbPoint )
         return 1;
-
-      case wkbLineString:
-      {
-          OGRLineString *poLine = (OGRLineString *) hGeom;
-          return poLine->getNumPoints();
-      }
-
-      default:
+    else if( OGR_GT_IsCurve(eGType) )
+        return ((OGRCurve *) hGeom)->getNumPoints();
+    else
+    {
         // autotest/pymod/ogrtest.py calls this method on any geometry. So keep silent
         //CPLError(CE_Failure, CPLE_NotSupported, "Incompatible geometry for operation");
         return 0;
@@ -90,6 +87,7 @@ void OGR_G_SetPointCount( OGRGeometryH hGeom, int nNewPointCount )
     switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
     {
       case wkbLineString:
+      case wkbCircularString:
       {
         OGRLineString *poLine = (OGRLineString *) hGeom;
         poLine->setNumPoints( nNewPointCount );
@@ -131,6 +129,7 @@ double OGR_G_GetX( OGRGeometryH hGeom, int i )
       }
 
       case wkbLineString:
+      case wkbCircularString:
       {
           OGRLineString* poLS = (OGRLineString *) hGeom;
           if (i < 0 || i >= poLS->getNumPoints())
@@ -177,6 +176,7 @@ double OGR_G_GetY( OGRGeometryH hGeom, int i )
       }
 
       case wkbLineString:
+      case wkbCircularString:
       {
           OGRLineString* poLS = (OGRLineString *) hGeom;
           if (i < 0 || i >= poLS->getNumPoints())
@@ -223,6 +223,7 @@ double OGR_G_GetZ( OGRGeometryH hGeom, int i )
       }
 
       case wkbLineString:
+      case wkbCircularString:
       {
           OGRLineString* poLS = (OGRLineString *) hGeom;
           if (i < 0 || i >= poLS->getNumPoints())
@@ -283,6 +284,7 @@ int OGR_G_GetPoints( OGRGeometryH hGeom,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
       {
           OGRLineString* poLS = (OGRLineString *) hGeom;
           poLS->getPoints(pabyX, nXStride, pabyY, nYStride, pabyZ, nZStride);
@@ -337,6 +339,7 @@ void OGR_G_GetPoint( OGRGeometryH hGeom, int i,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
       {
           OGRLineString* poLS = (OGRLineString *) hGeom;
           if (i < 0 || i >= poLS->getNumPoints())
@@ -399,6 +402,7 @@ void CPL_DLL OGR_G_SetPoints( OGRGeometryH hGeom, int nPointsIn,
         break;
       }
       case wkbLineString:
+      case wkbCircularString:
       {
         OGRLineString* poLine = (OGRLineString *) hGeom;
 
@@ -437,7 +441,7 @@ void CPL_DLL OGR_G_SetPoints( OGRGeometryH hGeom, int nPointsIn,
  *
  * If iPoint is larger than the number of existing
  * points in the linestring, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * @param hGeom handle to the geometry to add a vertex to.
  * @param i the index of the vertex to assign (zero based) or
@@ -471,6 +475,7 @@ void OGR_G_SetPoint( OGRGeometryH hGeom, int i,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
       {
           if (i < 0)
           {
@@ -495,7 +500,7 @@ void OGR_G_SetPoint( OGRGeometryH hGeom, int i,
  *
  * If iPoint is larger than the number of existing
  * points in the linestring, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * @param hGeom handle to the geometry to add a vertex to.
  * @param i the index of the vertex to assign (zero based) or
@@ -527,6 +532,7 @@ void OGR_G_SetPoint_2D( OGRGeometryH hGeom, int i,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
       {
           if (i < 0)
           {
@@ -575,6 +581,7 @@ void OGR_G_AddPoint( OGRGeometryH hGeom,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
         ((OGRLineString *) hGeom)->addPoint( dfX, dfY, dfZ );
         break;
 
@@ -614,6 +621,7 @@ void OGR_G_AddPoint_2D( OGRGeometryH hGeom,
       break;
 
       case wkbLineString:
+      case wkbCircularString:
         ((OGRLineString *) hGeom)->addPoint( dfX, dfY );
         break;
 
@@ -645,21 +653,20 @@ int OGR_G_GetGeometryCount( OGRGeometryH hGeom )
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_GetGeometryCount", 0 );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) )
     {
-      case wkbPolygon:
-        if( ((OGRPolygon *)hGeom)->getExteriorRing() == NULL )
+        if( ((OGRCurvePolygon *)hGeom)->getExteriorRingCurve() == NULL )
             return 0;
         else
-            return ((OGRPolygon *)hGeom)->getNumInteriorRings() + 1;
-
-      case wkbMultiPoint:
-      case wkbMultiLineString:
-      case wkbMultiPolygon:
-      case wkbGeometryCollection:
+            return ((OGRCurvePolygon *)hGeom)->getNumInteriorRings() + 1;
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCompoundCurve) )
+        return ((OGRCompoundCurve *)hGeom)->getNumCurves();
+    else if( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
         return ((OGRGeometryCollection *)hGeom)->getNumGeometries();
-
-      default:
+    else
+    {
         // autotest/pymod/ogrtest.py calls this method on any geometry. So keep silent
         //CPLError(CE_Failure, CPLE_NotSupported, "Incompatible geometry for operation");
         return 0;
@@ -699,24 +706,22 @@ OGRGeometryH OGR_G_GetGeometryRef( OGRGeometryH hGeom, int iSubGeom )
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_GetGeometryRef", NULL );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) )
     {
-      case wkbPolygon:
         if( iSubGeom == 0 )
             return (OGRGeometryH) 
-                ((OGRPolygon *)hGeom)->getExteriorRing();
+                ((OGRCurvePolygon *)hGeom)->getExteriorRingCurve();
         else
             return (OGRGeometryH) 
-                ((OGRPolygon *)hGeom)->getInteriorRing(iSubGeom-1);
-
-      case wkbMultiPoint:
-      case wkbMultiLineString:
-      case wkbMultiPolygon:
-      case wkbGeometryCollection:
-        return (OGRGeometryH) 
-            ((OGRGeometryCollection *)hGeom)->getGeometryRef( iSubGeom );
-
-      default:
+                ((OGRCurvePolygon *)hGeom)->getInteriorRingCurve(iSubGeom-1);
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCompoundCurve) )
+        return (OGRGeometryH) ((OGRCompoundCurve *)hGeom)->getCurve(iSubGeom);
+    else if( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
+        return (OGRGeometryH) ((OGRGeometryCollection *)hGeom)->getGeometryRef( iSubGeom );
+    else
+    {
         CPLError(CE_Failure, CPLE_NotSupported, "Incompatible geometry for operation");
         return 0;
     }
@@ -755,31 +760,26 @@ OGRErr OGR_G_AddGeometry( OGRGeometryH hGeom, OGRGeometryH hNewSubGeom )
     VALIDATE_POINTER1( hGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION );
     VALIDATE_POINTER1( hNewSubGeom, "OGR_G_AddGeometry", OGRERR_UNSUPPORTED_OPERATION );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
-    {
-      case wkbPolygon:
-      {
-          if( !EQUAL( ((OGRGeometry*) hNewSubGeom)->getGeometryName(), "LINEARRING" ) )
-          {
-              return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-          }
-          else
-          {
-              ((OGRPolygon *)hGeom)->addRing( (OGRLinearRing *) hNewSubGeom );
-              return OGRERR_NONE;
-          }
-      }
-
-      case wkbMultiPoint:
-      case wkbMultiLineString:
-      case wkbMultiPolygon:
-      case wkbGeometryCollection:
-        return ((OGRGeometryCollection *)hGeom)->addGeometry( 
-            (OGRGeometry *) hNewSubGeom );
+    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
 
-      default:
-        return OGRERR_UNSUPPORTED_OPERATION;
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) )
+    {
+        if( OGR_GT_IsCurve( wkbFlatten(((OGRGeometry *) hNewSubGeom)->getGeometryType()) ) )
+            eErr = ((OGRCurvePolygon *)hGeom)->addRing( (OGRCurve *) hNewSubGeom );
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCompoundCurve) )
+    {
+        if( OGR_GT_IsCurve( wkbFlatten(((OGRGeometry *) hNewSubGeom)->getGeometryType()) ) )
+            eErr = ((OGRCompoundCurve *)hGeom)->addCurve( (OGRCurve *) hNewSubGeom );
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
+    {
+        eErr = ((OGRGeometryCollection *)hGeom)->addGeometry( 
+                                                (OGRGeometry *) hNewSubGeom );
     }
+
+    return eErr;
 }
 
 /************************************************************************/
@@ -816,31 +816,29 @@ OGRErr OGR_G_AddGeometryDirectly( OGRGeometryH hGeom,
     VALIDATE_POINTER1( hGeom, "OGR_G_AddGeometryDirectly", OGRERR_UNSUPPORTED_OPERATION );
     VALIDATE_POINTER1( hNewSubGeom, "OGR_G_AddGeometryDirectly", OGRERR_UNSUPPORTED_OPERATION );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRErr eErr = OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
+
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) )
     {
-      case wkbPolygon:
-      {
-          if( !EQUAL( ((OGRGeometry*) hNewSubGeom)->getGeometryName(), "LINEARRING" ) )
-          {
-              return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-          }
-          else
-          {
-              ((OGRPolygon *)hGeom)->addRingDirectly( (OGRLinearRing *) hNewSubGeom );
-              return OGRERR_NONE;
-          }
-      }
+        if( OGR_GT_IsCurve( wkbFlatten(((OGRGeometry *) hNewSubGeom)->getGeometryType()) ) )
+            eErr = ((OGRCurvePolygon *)hGeom)->addRingDirectly( (OGRCurve *) hNewSubGeom );
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCompoundCurve) )
+    {
+        if( OGR_GT_IsCurve( wkbFlatten(((OGRGeometry *) hNewSubGeom)->getGeometryType()) ) )
+            eErr = ((OGRCompoundCurve *)hGeom)->addCurveDirectly( (OGRCurve *) hNewSubGeom );
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
+    {
+        eErr = ((OGRGeometryCollection *)hGeom)->addGeometryDirectly( 
+                                                (OGRGeometry *) hNewSubGeom );
+    }
 
-      case wkbMultiPoint:
-      case wkbMultiLineString:
-      case wkbMultiPolygon:
-      case wkbGeometryCollection:
-        return ((OGRGeometryCollection *)hGeom)->addGeometryDirectly( 
-            (OGRGeometry *) hNewSubGeom );
+    if( eErr != OGRERR_NONE )
+        delete (OGRGeometry*)hNewSubGeom;
 
-      default:
-        return OGRERR_UNSUPPORTED_OPERATION;
-    }
+    return eErr;
 }
 
 /************************************************************************/
@@ -870,29 +868,24 @@ OGRErr OGR_G_AddGeometryDirectly( OGRGeometryH hGeom,
  * out of range.
  */
 
-
-
 OGRErr OGR_G_RemoveGeometry( OGRGeometryH hGeom, int iGeom, int bDelete )
 
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_RemoveGeometry", 0 );
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                "OGR_G_RemoveGeometry() not supported on polygons yet." );
+        return OGRERR_UNSUPPORTED_OPERATION;
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
     {
-      case wkbPolygon:
-      {
-          CPLError( CE_Failure, CPLE_AppDefined, 
-                    "OGR_G_RemoveGeometry() not supported on polygons yet." );
-          return OGRERR_UNSUPPORTED_OPERATION;
-      }
-
-      case wkbMultiPoint:
-      case wkbMultiLineString:
-      case wkbMultiPolygon:
-      case wkbGeometryCollection:
         return ((OGRGeometryCollection *)hGeom)->removeGeometry( iGeom,bDelete);
-
-      default:
+    }
+    else
+    {
         return OGRERR_UNSUPPORTED_OPERATION;
     }
 }
@@ -904,7 +897,7 @@ OGRErr OGR_G_RemoveGeometry( OGRGeometryH hGeom, int iGeom, int bDelete )
 /**
  * \brief Compute length of a geometry.
  *
- * Computes the area for OGRCurve or MultiCurve objects.
+ * Computes the length for OGRCurve or MultiCurve objects.
  * Undefined for all other geometry types (returns zero). 
  *
  * This function utilizes the C++ get_Length() method.
@@ -920,28 +913,26 @@ double OGR_G_Length( OGRGeometryH hGeom )
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_GetLength", 0 );
 
-    double fLength = 0.0;
+    double dfLength;
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsCurve(eType) )
+    {
+        dfLength = ((OGRCurve *) hGeom)->get_Length();
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbMultiCurve) ||
+             eType == wkbGeometryCollection )
+    {
+        dfLength = ((OGRGeometryCollection *) hGeom)->get_Length();
+    }
+    else
     {
-      case wkbLinearRing:
-      case wkbLineString:
-        fLength = ((OGRCurve *) hGeom)->get_Length();
-        break;
-
-      case wkbMultiLineString:
-      case wkbGeometryCollection:
-        fLength = ((OGRGeometryCollection *) hGeom)->get_Length();
-        break;
-
-      default:
         CPLError( CE_Warning, CPLE_AppDefined,
                   "OGR_G_Length() called against a non-curve geometry type." );
-
-        fLength = 0.0;
+        dfLength = 0.0;
     }
 
-    return fLength;
+    return dfLength;
 }
 
 /************************************************************************/
@@ -968,41 +959,31 @@ double OGR_G_Area( OGRGeometryH hGeom )
 {
     VALIDATE_POINTER1( hGeom, "OGR_G_Area", 0 );
 
-    double fArea = 0.0;
+    double dfArea;
 
-    switch( wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType()) )
+    OGRwkbGeometryType eType = wkbFlatten(((OGRGeometry *) hGeom)->getGeometryType());
+    if( OGR_GT_IsSurface(eType) )
+    {
+        dfArea = ((OGRSurface *) hGeom)->get_Area();
+    }
+    else if( OGR_GT_IsCurve(eType) )
+    {
+        dfArea = ((OGRCurve *) hGeom)->get_Area();
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbMultiSurface) ||
+             eType == wkbGeometryCollection )
+    {
+        dfArea = ((OGRGeometryCollection *) hGeom)->get_Area();
+    }
+    else
     {
-      case wkbPolygon:
-        fArea = ((OGRPolygon *) hGeom)->get_Area();
-        break;
-
-      case wkbMultiPolygon:
-        fArea = ((OGRMultiPolygon *) hGeom)->get_Area();
-        break;
-
-      case wkbLinearRing:
-      case wkbLineString:
-        /* This test below is required to filter out wkbLineString geometries
-         * not being of type of wkbLinearRing.
-         */
-        if( EQUAL( ((OGRGeometry*) hGeom)->getGeometryName(), "LINEARRING" ) )
-        {
-            fArea = ((OGRLinearRing *) hGeom)->get_Area();
-        }
-        break;
-
-      case wkbGeometryCollection:
-        fArea = ((OGRGeometryCollection *) hGeom)->get_Area();
-        break;
-
-      default:
         CPLError( CE_Warning, CPLE_AppDefined,
                   "OGR_G_Area() called against non-surface geometry type." );
 
-        fArea = 0.0;
+        dfArea = 0.0;
     }
 
-    return fArea;
+    return dfArea;
 }
 
 /**
@@ -1016,3 +997,217 @@ double OGR_G_GetArea( OGRGeometryH hGeom )
 {
     return OGR_G_Area( hGeom );
 }
+
+#ifndef OGR_ENABLED
+OGRGeometryH OGR_G_CreateGeometryFromJson( const char* )
+{
+    return NULL;
+}
+
+char* OGR_G_ExportToKML( OGRGeometryH, const char* pszAltitudeMode )
+{
+    return NULL;
+}
+
+char* OGR_G_ExportToJson( OGRGeometryH )
+{
+    return NULL;
+}
+char* OGR_G_ExportToJsonEx( OGRGeometryH, char** papszOptions )
+{
+    return NULL;
+}
+#endif
+
+/************************************************************************/
+/*                         OGR_G_HasCurveGeometry()                     */
+/************************************************************************/
+
+/**
+ * \brief Returns if this geometry is or has curve geometry.
+ *
+ * Returns if a geometry is or has CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
+ * MULTICURVE or MULTISURFACE in it.
+*
+ * If bLookForNonLinear is set to TRUE, it will be actually looked if the
+ * geometry or its subgeometries are or contain a non-linear geometry in them. In which
+ * case, if the method returns TRUE, it means that OGR_G_GetLinearGeometry() would
+ * return an approximate version of the geometry. Otherwise, OGR_G_GetLinearGeometry()
+ * would do a conversion, but with just converting container type, like
+ * COMPOUNDCURVE -> LINESTRING, MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON,
+ * resulting in a "loss-less" conversion.
+ *
+ * This function is the same as C++ method OGRGeometry::hasCurveGeometry().
+ *
+ * @param hGeom the geometry to operate on.
+ * @param bLookForNonLinear set it to TRUE to check if the geometry is or contains
+ * a CIRCULARSTRING.
+ * @return TRUE if this geometry is or has curve geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_G_HasCurveGeometry( OGRGeometryH hGeom, int bLookForNonLinear )
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_HasCurveGeometry", FALSE );
+    return ((OGRGeometry *) hGeom)->hasCurveGeometry(bLookForNonLinear);
+}
+
+/************************************************************************/
+/*                         OGR_G_GetLinearGeometry()                   */
+/************************************************************************/
+
+/**
+ * \brief Return, possibly approximate, linear version of this geometry.
+ *
+ * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
+ * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
+ *
+ * The ownership of the returned geometry belongs to the caller.
+ *
+ * The reverse function is OGR_G_GetCurveGeometry().
+ *
+ * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() and 
+ * CurvePolygon::CurvePolyToPoly() methods.
+ *
+ * This function is the same as C++ method OGRGeometry::getLinearGeometry().
+ *
+ * @param hGeom the geometry to operate on. 
+ * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
+ * arc, zero to use the default setting.
+ * @param papszOptions options as a null-terminated list of strings or NULL.
+ *                     See OGRGeometryFactory::curveToLineString() for valid options.
+ *
+ * @return a new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry( OGRGeometryH hGeom,
+                                                double dfMaxAngleStepSizeDegrees,
+                                                char** papszOptions )
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_GetLinearGeometry", NULL );
+    return (OGRGeometryH) ((OGRGeometry *) hGeom)->getLinearGeometry(dfMaxAngleStepSizeDegrees,
+                                                                       (const char* const*)papszOptions );
+}
+
+/************************************************************************/
+/*                         OGR_G_GetCurveGeometry()                     */
+/************************************************************************/
+
+/**
+ * \brief Return curve version of this geometry.
+ *
+ * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
+ * MULTICURVE or MULTISURFACE in it, by de-approximating linear into curve geometries.
+ *
+ * If the geometry has no curve portion, the returned geometry will be a clone
+ * of it.
+ *
+ * The ownership of the returned geometry belongs to the caller.
+ *
+ * The reverse function is OGR_G_GetLinearGeometry().
+ *
+ * This function is the same as C++ method OGRGeometry::getCurveGeometry().
+ *
+ * @param hGeom the geometry to operate on. 
+ * @param papszOptions options as a null-terminated list of strings.
+ *                     Unused for now. Must be set to NULL.
+ *
+ * @return a new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry( OGRGeometryH hGeom,
+                                             char** papszOptions )
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_GetCurveGeometry", NULL );
+    return (OGRGeometryH) ((OGRGeometry *) hGeom)->getCurveGeometry((const char* const*)papszOptions);
+}
+
+/************************************************************************/
+/*                          OGR_G_Value()                               */
+/************************************************************************/
+/**
+ * \brief Fetch point at given distance along curve.
+ *
+ * This function relates to the SF COM ICurve::get_Value() method.
+ *
+ * This function is the same as the C++ method OGRCurve::Value().
+ *
+ * @param hGeom curve geometry.
+ * @param dfDistance distance along the curve at which to sample position.
+ *                   This distance should be between zero and get_Length()
+ *                   for this curve.
+ * @return a point or NULL.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometryH OGR_G_Value( OGRGeometryH hGeom, double dfDistance )
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_Value", NULL );
+
+    if( OGR_GT_IsCurve(((OGRGeometry *) hGeom)->getGeometryType()) )
+    {
+        OGRPoint* p = new OGRPoint();
+        ((OGRCurve *) hGeom)->Value(dfDistance, p);
+        return (OGRGeometryH)p;
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+/************************************************************************/
+/*                 OGRSetNonLinearGeometriesEnabledFlag()               */
+/************************************************************************/
+
+/**
+ * \brief Set flag to enable/disable returning non-linear geometries in the C API.
+ *
+ * This flag has only an effect on the OGR_F_GetGeometryRef(), OGR_F_GetGeomFieldRef(),
+ * OGR_L_GetGeomType(), OGR_GFld_GetType() and OGR_FD_GetGeomType() C API, and
+ * corresponding methods in the SWIG bindings. It is meant as making it simple
+ * for applications using the OGR C API not to have to deal with non-linear geometries,
+ * even if such geometries might be returned by drivers. In which case, they
+ * will be transformed into their closest linear geometry, by doing linear
+ * approximation, with OGR_G_ForceTo().
+ *
+ * Libraries should generally *not* use that method, since that could interfere
+ * with other libraries or applications.
+ *
+ * Note that it *does* not affect the behaviour of the C++ API.
+ *
+ * @param bFlag TRUE if non-linear geometries might be returned (default value).
+ *              FALSE to ask for non-linear geometries to be approximated as linear geometries.
+ *
+ * @return a point or NULL.
+ *
+ * @since GDAL 2.0
+ */
+
+void OGRSetNonLinearGeometriesEnabledFlag(int bFlag)
+{
+    bNonLinearGeometriesEnabled = bFlag;
+}
+
+/************************************************************************/
+/*                 OGRGetNonLinearGeometriesEnabledFlag()               */
+/************************************************************************/
+
+/**
+ * \brief Get flag to enable/disable returning non-linear geometries in the C API.
+ *
+ * return TRUE if non-linear geometries might be returned (default value is TRUE)
+ *
+ * @since GDAL 2.0
+ * @see OGRSetNonLinearGeometriesEnabledFlag()
+ */
+int OGRGetNonLinearGeometriesEnabledFlag(void)
+{
+    return bNonLinearGeometriesEnabled;
+}
diff --git a/ogr/ogr_api.h b/ogr/ogr_api.h
index 7067acc..5c9fca4 100644
--- a/ogr/ogr_api.h
+++ b/ogr/ogr_api.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_api.h 27071 2014-03-21 21:52:46Z rouault $
+ * $Id: ogr_api.h 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  C API for OGR Geometry, Feature, Layers, DataSource and drivers.
@@ -41,6 +41,7 @@
  */
 
 #include "cpl_progress.h"
+#include "cpl_minixml.h"
 #include "ogr_core.h"
 
 CPL_C_START
@@ -91,6 +92,9 @@ OGRGeometryH CPL_DLL OGR_G_ForceToLineString( OGRGeometryH );
 OGRGeometryH CPL_DLL OGR_G_ForceToMultiPolygon( OGRGeometryH );
 OGRGeometryH CPL_DLL OGR_G_ForceToMultiPoint( OGRGeometryH );
 OGRGeometryH CPL_DLL OGR_G_ForceToMultiLineString( OGRGeometryH );
+OGRGeometryH CPL_DLL OGR_G_ForceTo( OGRGeometryH hGeom,
+                                    OGRwkbGeometryType eTargetType,
+                                    char** papszOptions );
 
 int    CPL_DLL OGR_G_GetDimension( OGRGeometryH );
 int    CPL_DLL OGR_G_GetCoordinateDimension( OGRGeometryH );
@@ -100,9 +104,11 @@ void   CPL_DLL OGR_G_GetEnvelope( OGRGeometryH, OGREnvelope * );
 void   CPL_DLL OGR_G_GetEnvelope3D( OGRGeometryH, OGREnvelope3D * );
 OGRErr CPL_DLL OGR_G_ImportFromWkb( OGRGeometryH, unsigned char *, int );
 OGRErr CPL_DLL OGR_G_ExportToWkb( OGRGeometryH, OGRwkbByteOrder, unsigned char*);
+OGRErr CPL_DLL OGR_G_ExportToIsoWkb( OGRGeometryH, OGRwkbByteOrder, unsigned char*);
 int    CPL_DLL OGR_G_WkbSize( OGRGeometryH hGeom );
 OGRErr CPL_DLL OGR_G_ImportFromWkt( OGRGeometryH, char ** );
 OGRErr CPL_DLL OGR_G_ExportToWkt( OGRGeometryH, char ** );
+OGRErr CPL_DLL OGR_G_ExportToIsoWkt( OGRGeometryH, char ** );
 OGRwkbGeometryType CPL_DLL OGR_G_GetGeometryType( OGRGeometryH );
 const char CPL_DLL *OGR_G_GetGeometryName( OGRGeometryH );
 void   CPL_DLL OGR_G_DumpReadable( OGRGeometryH, FILE *, const char * );
@@ -113,11 +119,9 @@ OGRGeometryH CPL_DLL OGR_G_CreateFromGML( const char * );
 char   CPL_DLL *OGR_G_ExportToGML( OGRGeometryH );
 char   CPL_DLL *OGR_G_ExportToGMLEx( OGRGeometryH, char** papszOptions );
 
-#if defined(_CPL_MINIXML_H_INCLUDED)
 OGRGeometryH CPL_DLL OGR_G_CreateFromGMLTree( const CPLXMLNode * );
 CPLXMLNode CPL_DLL *OGR_G_ExportToGMLTree( OGRGeometryH );
 CPLXMLNode CPL_DLL *OGR_G_ExportEnvelopeToGMLTree( OGRGeometryH );
-#endif
 
 char   CPL_DLL *OGR_G_ExportToKML( OGRGeometryH, const char* pszAltitudeMode );
 
@@ -162,6 +166,7 @@ double CPL_DLL OGR_G_Distance( OGRGeometryH, OGRGeometryH );
 double CPL_DLL OGR_G_Length( OGRGeometryH );
 double CPL_DLL OGR_G_Area( OGRGeometryH );
 int    CPL_DLL OGR_G_Centroid( OGRGeometryH, OGRGeometryH );
+OGRGeometryH CPL_DLL OGR_G_Value( OGRGeometryH, double dfDistance );
 
 void   CPL_DLL OGR_G_Empty( OGRGeometryH );
 int    CPL_DLL OGR_G_IsEmpty( OGRGeometryH );
@@ -210,6 +215,13 @@ OGRErr CPL_DLL OGR_G_AddGeometry( OGRGeometryH, OGRGeometryH );
 OGRErr CPL_DLL OGR_G_AddGeometryDirectly( OGRGeometryH, OGRGeometryH );
 OGRErr CPL_DLL OGR_G_RemoveGeometry( OGRGeometryH, int, int );
 
+int CPL_DLL OGR_G_HasCurveGeometry( OGRGeometryH, int bLookForNonLinear );
+OGRGeometryH CPL_DLL OGR_G_GetLinearGeometry( OGRGeometryH hGeom,
+                                              double dfMaxAngleStepSizeDegrees,
+                                              char** papszOptions);
+OGRGeometryH CPL_DLL OGR_G_GetCurveGeometry( OGRGeometryH hGeom,
+                                             char** papszOptions );
+
 OGRGeometryH CPL_DLL OGRBuildPolygonFromEdges( OGRGeometryH hLinesAsCollection,
                                        int bBestEffort, 
                                        int bAutoClose, 
@@ -221,6 +233,9 @@ OGRErr CPL_DLL OGRSetGenerate_DB2_V72_BYTE_ORDER(
 
 int CPL_DLL OGRGetGenerate_DB2_V72_BYTE_ORDER(void);
 
+void CPL_DLL OGRSetNonLinearGeometriesEnabledFlag(int bFlag);
+int CPL_DLL OGRGetNonLinearGeometriesEnabledFlag(void);
+
 /* -------------------------------------------------------------------- */
 /*      Feature related (ogr_feature.h)                                 */
 /* -------------------------------------------------------------------- */
@@ -247,6 +262,8 @@ void   CPL_DLL OGR_Fld_SetName( OGRFieldDefnH, const char * );
 const char CPL_DLL *OGR_Fld_GetNameRef( OGRFieldDefnH );
 OGRFieldType CPL_DLL OGR_Fld_GetType( OGRFieldDefnH );
 void   CPL_DLL OGR_Fld_SetType( OGRFieldDefnH, OGRFieldType );
+OGRFieldSubType CPL_DLL OGR_Fld_GetSubType( OGRFieldDefnH );
+void   CPL_DLL OGR_Fld_SetSubType( OGRFieldDefnH, OGRFieldSubType );
 OGRJustification CPL_DLL OGR_Fld_GetJustify( OGRFieldDefnH );
 void   CPL_DLL OGR_Fld_SetJustify( OGRFieldDefnH, OGRJustification );
 int    CPL_DLL OGR_Fld_GetWidth( OGRFieldDefnH );
@@ -257,8 +274,16 @@ void   CPL_DLL OGR_Fld_Set( OGRFieldDefnH, const char *, OGRFieldType,
                             int, int, OGRJustification );
 int    CPL_DLL OGR_Fld_IsIgnored( OGRFieldDefnH hDefn );
 void   CPL_DLL OGR_Fld_SetIgnored( OGRFieldDefnH hDefn, int );
+int    CPL_DLL OGR_Fld_IsNullable( OGRFieldDefnH hDefn );
+void   CPL_DLL OGR_Fld_SetNullable( OGRFieldDefnH hDefn, int );
+const char CPL_DLL *OGR_Fld_GetDefault( OGRFieldDefnH hDefn );
+void   CPL_DLL OGR_Fld_SetDefault( OGRFieldDefnH hDefn, const char* );
+int    CPL_DLL OGR_Fld_IsDefaultDriverSpecific( OGRFieldDefnH hDefn );
 
 const char CPL_DLL *OGR_GetFieldTypeName( OGRFieldType );
+const char CPL_DLL *OGR_GetFieldSubTypeName( OGRFieldSubType );
+int CPL_DLL OGR_AreTypeSubTypeCompatible( OGRFieldType eType,
+                                          OGRFieldSubType eSubType );
 
 /* OGRGeomFieldDefnH */
 
@@ -275,6 +300,9 @@ OGRSpatialReferenceH CPL_DLL OGR_GFld_GetSpatialRef( OGRGeomFieldDefnH );
 void                 CPL_DLL OGR_GFld_SetSpatialRef( OGRGeomFieldDefnH,
                                                      OGRSpatialReferenceH hSRS );
 
+int                  CPL_DLL OGR_GFld_IsNullable( OGRGeomFieldDefnH hDefn );
+void                 CPL_DLL OGR_GFld_SetNullable( OGRGeomFieldDefnH hDefn, int );
+
 int                  CPL_DLL OGR_GFld_IsIgnored( OGRGeomFieldDefnH hDefn );
 void                 CPL_DLL OGR_GFld_SetIgnored( OGRGeomFieldDefnH hDefn, int );
 
@@ -334,25 +362,35 @@ void   CPL_DLL OGR_F_UnsetField( OGRFeatureH, int );
 OGRField CPL_DLL *OGR_F_GetRawFieldRef( OGRFeatureH, int );
 
 int    CPL_DLL OGR_F_GetFieldAsInteger( OGRFeatureH, int );
+GIntBig CPL_DLL OGR_F_GetFieldAsInteger64( OGRFeatureH, int );
 double CPL_DLL OGR_F_GetFieldAsDouble( OGRFeatureH, int );
 const char CPL_DLL *OGR_F_GetFieldAsString( OGRFeatureH, int );
 const int CPL_DLL *OGR_F_GetFieldAsIntegerList( OGRFeatureH, int, int * );
+const GIntBig CPL_DLL *OGR_F_GetFieldAsInteger64List( OGRFeatureH, int, int * );
 const double CPL_DLL *OGR_F_GetFieldAsDoubleList( OGRFeatureH, int, int * );
 char  CPL_DLL **OGR_F_GetFieldAsStringList( OGRFeatureH, int );
 GByte CPL_DLL *OGR_F_GetFieldAsBinary( OGRFeatureH, int, int * );
 int   CPL_DLL  OGR_F_GetFieldAsDateTime( OGRFeatureH, int, int *, int *, int *,
                                          int *, int *, int *, int * );
+int   CPL_DLL OGR_F_GetFieldAsDateTimeEx( OGRFeatureH hFeat, int iField,
+                                int *pnYear, int *pnMonth, int *pnDay,
+                                int *pnHour, int *pnMinute, float *pfSecond,
+                                int *pnTZFlag );
 
 void   CPL_DLL OGR_F_SetFieldInteger( OGRFeatureH, int, int );
+void   CPL_DLL OGR_F_SetFieldInteger64( OGRFeatureH, int, GIntBig );
 void   CPL_DLL OGR_F_SetFieldDouble( OGRFeatureH, int, double );
 void   CPL_DLL OGR_F_SetFieldString( OGRFeatureH, int, const char * );
 void   CPL_DLL OGR_F_SetFieldIntegerList( OGRFeatureH, int, int, int * );
+void   CPL_DLL OGR_F_SetFieldInteger64List( OGRFeatureH, int, int, const GIntBig * );
 void   CPL_DLL OGR_F_SetFieldDoubleList( OGRFeatureH, int, int, double * );
 void   CPL_DLL OGR_F_SetFieldStringList( OGRFeatureH, int, char ** );
 void   CPL_DLL OGR_F_SetFieldRaw( OGRFeatureH, int, OGRField * );
 void   CPL_DLL OGR_F_SetFieldBinary( OGRFeatureH, int, int, GByte * );
 void   CPL_DLL OGR_F_SetFieldDateTime( OGRFeatureH, int, 
                                        int, int, int, int, int, int, int );
+void   CPL_DLL OGR_F_SetFieldDateTimeEx( OGRFeatureH, int, 
+                                       int, int, int, int, int, float, int );
 
 int               CPL_DLL OGR_F_GetGeomFieldCount( OGRFeatureH hFeat );
 OGRGeomFieldDefnH CPL_DLL OGR_F_GetGeomFieldDefnRef( OGRFeatureH hFeat,
@@ -368,8 +406,8 @@ OGRErr            CPL_DLL OGR_F_SetGeomFieldDirectly( OGRFeatureH hFeat,
 OGRErr            CPL_DLL OGR_F_SetGeomField( OGRFeatureH hFeat,
                                               int iField, OGRGeometryH hGeom );
 
-long   CPL_DLL OGR_F_GetFID( OGRFeatureH );
-OGRErr CPL_DLL OGR_F_SetFID( OGRFeatureH, long );
+GIntBig CPL_DLL OGR_F_GetFID( OGRFeatureH );
+OGRErr CPL_DLL OGR_F_SetFID( OGRFeatureH, GIntBig );
 void   CPL_DLL OGR_F_DumpReadable( OGRFeatureH, FILE * );
 OGRErr CPL_DLL OGR_F_SetFrom( OGRFeatureH, OGRFeatureH, int );
 OGRErr CPL_DLL OGR_F_SetFromWithMap( OGRFeatureH, OGRFeatureH, int , int * );
@@ -381,6 +419,11 @@ OGRStyleTableH CPL_DLL OGR_F_GetStyleTable( OGRFeatureH );
 void   CPL_DLL OGR_F_SetStyleTableDirectly( OGRFeatureH, OGRStyleTableH );
 void   CPL_DLL OGR_F_SetStyleTable( OGRFeatureH, OGRStyleTableH );
 
+void   CPL_DLL OGR_F_FillUnsetWithDefault( OGRFeatureH hFeat,
+                                           int bNotNullableOnly,
+                                           char** papszOptions );
+int    CPL_DLL OGR_F_Validate( OGRFeatureH, int nValidateFlags, int bEmitError );
+
 /* -------------------------------------------------------------------- */
 /*      ogrsf_frmts.h                                                   */
 /* -------------------------------------------------------------------- */
@@ -411,15 +454,15 @@ void     CPL_DLL OGR_L_SetSpatialFilterRectEx( OGRLayerH, int iGeomField,
 OGRErr CPL_DLL OGR_L_SetAttributeFilter( OGRLayerH, const char * );
 void   CPL_DLL OGR_L_ResetReading( OGRLayerH );
 OGRFeatureH CPL_DLL OGR_L_GetNextFeature( OGRLayerH );
-OGRErr CPL_DLL OGR_L_SetNextByIndex( OGRLayerH, long );
-OGRFeatureH CPL_DLL OGR_L_GetFeature( OGRLayerH, long );
+OGRErr CPL_DLL OGR_L_SetNextByIndex( OGRLayerH, GIntBig );
+OGRFeatureH CPL_DLL OGR_L_GetFeature( OGRLayerH, GIntBig );
 OGRErr CPL_DLL OGR_L_SetFeature( OGRLayerH, OGRFeatureH );
 OGRErr CPL_DLL OGR_L_CreateFeature( OGRLayerH, OGRFeatureH );
-OGRErr CPL_DLL OGR_L_DeleteFeature( OGRLayerH, long );
+OGRErr CPL_DLL OGR_L_DeleteFeature( OGRLayerH, GIntBig );
 OGRFeatureDefnH CPL_DLL OGR_L_GetLayerDefn( OGRLayerH );
 OGRSpatialReferenceH CPL_DLL OGR_L_GetSpatialRef( OGRLayerH );
 int    CPL_DLL OGR_L_FindFieldIndex( OGRLayerH, const char *, int bExactMatch );
-int    CPL_DLL OGR_L_GetFeatureCount( OGRLayerH, int );
+GIntBig CPL_DLL OGR_L_GetFeatureCount( OGRLayerH, int );
 OGRErr CPL_DLL OGR_L_GetExtent( OGRLayerH, OGREnvelope *, int );
 OGRErr  CPL_DLL OGR_L_GetExtentEx( OGRLayerH, int iGeomField,
                                    OGREnvelope *psExtent, int bForce );
diff --git a/ogr/ogr_apitut.dox b/ogr/ogr_apitut.dox
index 9e42246..2e0d62d 100644
--- a/ogr/ogr_apitut.dox
+++ b/ogr/ogr_apitut.dox
@@ -14,7 +14,7 @@ utility for dumping point layers from an OGR data source to stdout in
 comma-delimited format. 
 
 Initially it is necessary to register all the format drivers that are desired.
-This is normally accomplished by calling OGRRegisterAll() which registers
+This is normally accomplished by calling GDALAllRegister() which registers
 all format drivers built into GDAL/OGR.  
 
 In C++ :
@@ -24,54 +24,55 @@ In C++ :
 int main()
 
 {
-	OGRRegisterAll();
+    GDALAllRegister();
 \endcode
 
 In C :
 \code
-#include "ogr_api.h"
+#include "gdal.h"
 
 int main()
 
 {
-	OGRRegisterAll();
+    GDALAllRegister();
 \endcode
 
 Next we need to open the input OGR datasource.  Datasources can be files, 
 RDBMSes, directories full of files, or even remote web services depending on
 the driver being used.  However, the datasource name is always a single
 string.  In this case we are hardcoded to open a particular shapefile.
-The second argument (FALSE) tells the OGRSFDriverRegistrar::Open() method 
-that we don't require update access.  On failure NULL is returned, and
+The second argument (GDAL_OF_VECTOR) tells the OGROpen() method 
+that we want a vector driver to be use and that don't require update access.
+On failure NULL is returned, and
 we report an error. 
 
 In C++ :
 \code
-    OGRDataSource       *poDS;
+    GDALDataset       *poDS;
 
-    poDS = OGRSFDriverRegistrar::Open( "point.shp", FALSE );
+    poDS = (GDALDataset*) GDALOpenEx( "point.shp", GDAL_OF_VECTOR, NULL, NULL, NULL );
     if( poDS == NULL )
     {
-	printf( "Open failed.\n" );
-	exit( 1 );
+        printf( "Open failed.\n" );
+        exit( 1 );
     }
 \endcode
 
 In C :
 \code
-    OGRDataSourceH hDS;
+    GDALDatasetH hDS;
 
-    hDS = OGROpen( "point.shp", FALSE, NULL );
+    hDS = GDALOpenEx( "point.shp", GDAL_OF_VECTOR, NULL, NULL, NULL );
     if( hDS == NULL )
     {
-	printf( "Open failed.\n" );
-	exit( 1 );
+        printf( "Open failed.\n" );
+        exit( 1 );
     }
 \endcode
 
-An OGRDataSource can potentially have many layers associated with it.  The 
-number of layers available can be queried with OGRDataSource::GetLayerCount()
-and individual layers fetched by index using OGRDataSource::GetLayer().  
+A GDALDataset can potentially have many layers associated with it.  The 
+number of layers available can be queried with GDALDataset::GetLayerCount()
+and individual layers fetched by index using GDALDataset::GetLayer().  
 However, we will just fetch the layer by name. 
 
 In C++ :
@@ -85,7 +86,7 @@ In C :
 \code
     OGRLayerH hLayer;
 
-    hLayer = OGR_DS_GetLayerByName( hDS, "point" );
+    hLayer = GDALDatasetGetLayerByName( hDS, "point" );
 \endcode
 
 Now we want to start reading features from the layer.  Before we start we 
@@ -123,42 +124,46 @@ and fetch and report the attributes based on their type.
 
 In C++ :
 \code
-	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
-	int iField;
+    OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+    int iField;
 
-	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
-        {
-	    OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField );
-
-	    if( poFieldDefn->GetType() == OFTInteger )
-		printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
-	    else if( poFieldDefn->GetType() == OFTReal )
-		printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
-	    else if( poFieldDefn->GetType() == OFTString )
-		printf( "%s,", poFeature->GetFieldAsString(iField) );
-	    else
-		printf( "%s,", poFeature->GetFieldAsString(iField) );
-        }
+    for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+    {
+        OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField );
+
+        if( poFieldDefn->GetType() == OFTInteger )
+            printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
+        else if( poFieldDefn->GetType() == OFTInteger64 )
+            printf( CPL_FRMT_GIB ",", poFeature->GetFieldAsInteger64( iField ) );
+        else if( poFieldDefn->GetType() == OFTReal )
+            printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
+        else if( poFieldDefn->GetType() == OFTString )
+            printf( "%s,", poFeature->GetFieldAsString(iField) );
+        else
+            printf( "%s,", poFeature->GetFieldAsString(iField) );
+    }
 \endcode
 
 In C :
 \code
-	OGRFeatureDefnH hFDefn = OGR_L_GetLayerDefn(hLayer);
-	int iField;
+    OGRFeatureDefnH hFDefn = OGR_L_GetLayerDefn(hLayer);
+    int iField;
 
-	for( iField = 0; iField < OGR_FD_GetFieldCount(hFDefn); iField++ )
-        {
-	    OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn( hFDefn, iField );
-
-	    if( OGR_Fld_GetType(hFieldDefn) == OFTInteger )
-		printf( "%d,", OGR_F_GetFieldAsInteger( hFeature, iField ) );
-	    else if( OGR_Fld_GetType(hFieldDefn) == OFTReal )
-		printf( "%.3f,", OGR_F_GetFieldAsDouble( hFeature, iField) );
-	    else if( OGR_Fld_GetType(hFieldDefn) == OFTString )
-		printf( "%s,", OGR_F_GetFieldAsString( hFeature, iField) );
-	    else
-		printf( "%s,", OGR_F_GetFieldAsString( hFeature, iField) );
-        }
+    for( iField = 0; iField < OGR_FD_GetFieldCount(hFDefn); iField++ )
+    {
+        OGRFieldDefnH hFieldDefn = OGR_FD_GetFieldDefn( hFDefn, iField );
+
+        if( OGR_Fld_GetType(hFieldDefn) == OFTInteger )
+            printf( "%d,", OGR_F_GetFieldAsInteger( hFeature, iField ) );
+        else if( OGR_Fld_GetType(hFieldDefn) == OFTInteger64 )
+            printf( CPL_FRMT_GIB ",", OGR_F_GetFieldAsInteger64( hFeature, iField ) );
+        else if( OGR_Fld_GetType(hFieldDefn) == OFTReal )
+            printf( "%.3f,", OGR_F_GetFieldAsDouble( hFeature, iField) );
+        else if( OGR_Fld_GetType(hFieldDefn) == OFTString )
+            printf( "%s,", OGR_F_GetFieldAsString( hFeature, iField) );
+        else
+            printf( "%s,", OGR_F_GetFieldAsString( hFeature, iField) );
+    }
 \endcode
 
 There are a few more field types than those explicitly handled above, but
@@ -174,36 +179,36 @@ placeholders.
 
 In C++ :
 \code
-	OGRGeometry *poGeometry;
+    OGRGeometry *poGeometry;
 
-	poGeometry = poFeature->GetGeometryRef();
-	if( poGeometry != NULL 
+    poGeometry = poFeature->GetGeometryRef();
+    if( poGeometry != NULL 
             && wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
-        {
-	    OGRPoint *poPoint = (OGRPoint *) poGeometry;
+    {
+        OGRPoint *poPoint = (OGRPoint *) poGeometry;
 
-	    printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
-        }
-	else
-	{
-	    printf( "no point geometry\n" );
-	}	
+        printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
+    }
+    else
+    {
+        printf( "no point geometry\n" );
+    }
 \endcode
 
 In C :
 \code
-	OGRGeometryH hGeometry;
+    OGRGeometryH hGeometry;
 
-	hGeometry = OGR_F_GetGeometryRef(hFeature);
-	if( hGeometry != NULL 
+    hGeometry = OGR_F_GetGeometryRef(hFeature);
+    if( hGeometry != NULL 
             && wkbFlatten(OGR_G_GetGeometryType(hGeometry)) == wkbPoint )
-        {
-	    printf( "%.3f,%3.f\n", OGR_G_GetX(hGeometry, 0), OGR_G_GetY(hGeometry, 0) );
-        }
-	else
-	{
-	    printf( "no point geometry\n" );
-	}	
+    {
+        printf( "%.3f,%3.f\n", OGR_G_GetX(hGeometry, 0), OGR_G_GetY(hGeometry, 0) );
+    }
+    else
+    {
+        printf( "no point geometry\n" );
+    }
 \endcode
 
 The wkbFlatten() macro is used above to convert the type for a wkbPoint25D 
@@ -286,31 +291,25 @@ feature.
 
 In C++ :
 \code
-   	OGRFeature::DestroyFeature( poFeature );
+        OGRFeature::DestroyFeature( poFeature );
     }
 \endcode
 
 In C :
 \code
-   	OGR_F_Destroy( hFeature );
+        OGR_F_Destroy( hFeature );
     }
 \endcode
 
-The OGRLayer returned by OGRDataSource::GetLayerByName() is also a reference
-to an internal layer owned by the OGRDataSource so we don't need to delete
+The OGRLayer returned by GDALDataset::GetLayerByName() is also a reference
+to an internal layer owned by the GDALDataset so we don't need to delete
 it.  But we do need to delete the datasource in order to close the input file.
 Once again we do this with a custom delete method to avoid special win32 
 heap issus. 
 
-In C++ :
-\code
-    OGRDataSource::DestroyDataSource( poDS );
-}
-\endcode
-
-In C :
+In C/C++ :
 \code
-    OGR_DS_Destroy( hDS );
+    GDALClose( poDS );
 }
 \endcode
 
@@ -323,15 +322,15 @@ In C++ :
 int main()
 
 {
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    OGRDataSource       *poDS;
+    GDALDataset       *poDS;
 
-    poDS = OGRSFDriverRegistrar::Open( "point.shp", FALSE );
+    poDS = (GDALDataset*) GDALOpenEx( "point.shp", GDAL_OF_VECTOR, NULL, NULL, NULL );
     if( poDS == NULL )
     {
-	printf( "Open failed.\n" );
-	exit( 1 );
+        printf( "Open failed.\n" );
+        exit( 1 );
     }
 
     OGRLayer  *poLayer;
@@ -343,65 +342,67 @@ int main()
     poLayer->ResetReading();
     while( (poFeature = poLayer->GetNextFeature()) != NULL )
     {
-	OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
-	int iField;
+        OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
+        int iField;
 
-	for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
+        for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
         {
-	    OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField );
-
-	    if( poFieldDefn->GetType() == OFTInteger )
-		printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
-	    else if( poFieldDefn->GetType() == OFTReal )
-		printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
-	    else if( poFieldDefn->GetType() == OFTString )
-		printf( "%s,", poFeature->GetFieldAsString(iField) );
-	    else
-		printf( "%s,", poFeature->GetFieldAsString(iField) );
+            OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField );
+
+            if( poFieldDefn->GetType() == OFTInteger )
+                printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
+            else if( poFieldDefn->GetType() == OFTInteger64 )
+                printf( CPL_FRMT_GIB ",", poFeature->GetFieldAsInteger64( iField ) );
+            else if( poFieldDefn->GetType() == OFTReal )
+                printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
+            else if( poFieldDefn->GetType() == OFTString )
+                printf( "%s,", poFeature->GetFieldAsString(iField) );
+            else
+                printf( "%s,", poFeature->GetFieldAsString(iField) );
         }
 
-	OGRGeometry *poGeometry;
+        OGRGeometry *poGeometry;
 
-	poGeometry = poFeature->GetGeometryRef();
-	if( poGeometry != NULL 
-            && wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
+        poGeometry = poFeature->GetGeometryRef();
+        if( poGeometry != NULL 
+                && wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
         {
-	    OGRPoint *poPoint = (OGRPoint *) poGeometry;
+            OGRPoint *poPoint = (OGRPoint *) poGeometry;
 
-	    printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
+            printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
+        }
+        else
+        {
+            printf( "no point geometry\n" );
         }
-	else
-	{
-	    printf( "no point geometry\n" );
-	}	
-   	OGRFeature::DestroyFeature( poFeature );
+        OGRFeature::DestroyFeature( poFeature );
     }
 
-    OGRDataSource::DestroyDataSource( poDS );
+    GDALClose( poDS );
 }
 \endcode
 
 In C :
 \code
-#include "ogr_api.h"
+#include "gdal.h"
 
 int main()
 
 {
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    OGRDataSourceH hDS;
+    GDALDatasetH hDS;
     OGRLayerH hLayer;
     OGRFeatureH hFeature;
 
-    hDS = OGROpen( "point.shp", FALSE, NULL );
+    hDS = GDALOpenEx( "point.shp", GDAL_OF_VECTOR, NULL, NULL, NULL );
     if( hDS == NULL )
     {
         printf( "Open failed.\n" );
         exit( 1 );
     }
 
-    hLayer = OGR_DS_GetLayerByName( hDS, "point" );
+    hLayer = GDALDatasetGetLayerByName( hDS, "point" );
 
     OGR_L_ResetReading(hLayer);
     while( (hFeature = OGR_L_GetNextFeature(hLayer)) != NULL )
@@ -418,6 +419,8 @@ int main()
 
             if( OGR_Fld_GetType(hFieldDefn) == OFTInteger )
                 printf( "%d,", OGR_F_GetFieldAsInteger( hFeature, iField ) );
+            else if( OGR_Fld_GetType(hFieldDefn) == OFTInteger64 )
+                printf( CPL_FRMT_GIB ",", OGR_F_GetFieldAsInteger64( hFeature, iField ) );
             else if( OGR_Fld_GetType(hFieldDefn) == OFTReal )
                 printf( "%.3f,", OGR_F_GetFieldAsDouble( hFeature, iField) );
             else if( OGR_Fld_GetType(hFieldDefn) == OFTString )
@@ -440,16 +443,16 @@ int main()
         OGR_F_Destroy( hFeature );
     }
 
-    OGR_DS_Destroy( hDS );
+    GDALClose( hDS );
 }
 \endcode
 
 In Python:
 \code
 import sys
-import ogr
+from osgeo import gdal
 
-ds = ogr.Open( "point.shp" )
+ds = gdal.OpenEx( "point.shp", gdal.OF_VECTOR )
 if ds is None:
     print "Open failed.\n"
     sys.exit( 1 )
@@ -466,8 +469,8 @@ for feat in lyr:
 
         # Tests below can be simplified with just :
         # print feat.GetField(i)
-        if field_defn.GetType() == ogr.OFTInteger:
-            print "%d" % feat.GetFieldAsInteger(i)
+        if field_defn.GetType() == ogr.OFTInteger or field_defn.GetType() == ogr.OFTInteger64:
+            print "%d" % feat.GetFieldAsInteger64(i)
         elif field_defn.GetType() == ogr.OFTReal:
             print "%.3f" % feat.GetFieldAsDouble(i)
         elif field_defn.GetType() == ogr.OFTString:
@@ -500,16 +503,15 @@ In C++ :
 int main()
 {
     const char *pszDriverName = "ESRI Shapefile";
-    OGRSFDriver *poDriver;
+    GDALDriver *poDriver;
 
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
-		pszDriverName );
+    poDriver = GetGDALDriverManager()->GetDriverByName(pszDriverName );
     if( poDriver == NULL )
     {
-	printf( "%s driver not available.\n", pszDriverName );
-	exit( 1 );
+        printf( "%s driver not available.\n", pszDriverName );
+        exit( 1 );
     }
 \endcode
 
@@ -520,46 +522,48 @@ In C :
 int main()
 {
     const char *pszDriverName = "ESRI Shapefile";
-    OGRSFDriverH hDriver;
+    GDALDriver *poDriver;
 
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    hDriver = OGRGetDriverByName( pszDriverName );
-    if( hDriver == NULL )
+    poDriver = (GDALDriver*) GDALGetDriverByName(pszDriverName );
+    if( poDriver == NULL )
     {
-	printf( "%s driver not available.\n", pszDriverName );
-	exit( 1 );
+        printf( "%s driver not available.\n", pszDriverName );
+        exit( 1 );
     }
 \endcode
 
 Next we create the datasource.  The ESRI Shapefile driver allows us to create
 a directory full of shapefiles, or a single shapefile as a datasource.  In
 this case we will explicitly create a single file by including the extension
-in the name.  Other drivers behave differently.  The second argument to 
+in the name.  Other drivers behave differently.
+The second, third, fourth and fifth argument are related to raster dimensions
+(in case the driver has raster capabilities). The last argument to 
 the call is a list of option values, but we will just be using defaults in
 this case.  Details of the options supported are also format specific. 
 
 In C ++ :
 \code
-    OGRDataSource *poDS;
+    GDALDataset *poDS;
 
-    poDS = poDriver->CreateDataSource( "point_out.shp", NULL );
+    poDS = poDriver->Create( "point_out.shp", 0, 0, 0, GDT_Unknown, NULL );
     if( poDS == NULL )
     {
-	printf( "Creation of output file failed.\n" );
-	exit( 1 );
+        printf( "Creation of output file failed.\n" );
+        exit( 1 );
     }
 \endcode
 
 In C :
 \code
-    OGRDataSourceH hDS;
+    GDALDatasetH hDS;
 
-    hDS = OGR_Dr_CreateDataSource( hDriver, "point_out.shp", NULL );
+    hDS = GDALCreate( hDriver, "point_out.shp", 0, 0, 0, GDT_Unknown, NULL );
     if( hDS == NULL )
     {
-	printf( "Creation of output file failed.\n" );
-	exit( 1 );
+        printf( "Creation of output file failed.\n" );
+        exit( 1 );
     }
 \endcode
 
@@ -575,8 +579,8 @@ In C++ :
     poLayer = poDS->CreateLayer( "point_out", NULL, wkbPoint, NULL );
     if( poLayer == NULL )
     {
-	printf( "Layer creation failed.\n" );
-	exit( 1 );
+        printf( "Layer creation failed.\n" );
+        exit( 1 );
     }
 \endcode
 
@@ -584,11 +588,11 @@ In C :
 \code
     OGRLayerH hLayer;
 
-    hLayer = OGR_DS_CreateLayer( hDS, "point_out", NULL, wkbPoint, NULL );
+    hLayer = GDALDatasetCreateLayer( hDS, "point_out", NULL, wkbPoint, NULL );
     if( hLayer == NULL )
     {
-	printf( "Layer creation failed.\n" );
-	exit( 1 );
+        printf( "Layer creation failed.\n" );
+        exit( 1 );
     }
 \endcode
 
@@ -611,7 +615,7 @@ In C++:
 
     if( poLayer->CreateField( &oField ) != OGRERR_NONE )
     {
-	printf( "Creating Name field failed.\n" );
+        printf( "Creating Name field failed.\n" );
         exit( 1 );
     }
 \endcode
@@ -626,7 +630,7 @@ In C:
 
     if( OGR_L_CreateField( hLayer, hFieldDefn, TRUE ) != OGRERR_NONE )
     {
-	printf( "Creating Name field failed.\n" );
+        printf( "Creating Name field failed.\n" );
         exit( 1 );
     }
 
@@ -653,18 +657,18 @@ associated with the layer it will be written to.
 
 In C++ :
 \code
-	OGRFeature *poFeature;
+        OGRFeature *poFeature;
 
-	poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
-	poFeature->SetField( "Name", szName );
+        poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
+        poFeature->SetField( "Name", szName );
 \endcode
 
 In C :
 \code
-	OGRFeatureH hFeature;
+        OGRFeatureH hFeature;
 
-	hFeature = OGR_F_Create( OGR_L_GetLayerDefn( hLayer ) );
-	OGR_F_SetFieldString( hFeature, OGR_F_GetFieldIndex(hFeature, "Name"), szName );
+        hFeature = OGR_F_Create( OGR_L_GetLayerDefn( hLayer ) );
+        OGR_F_SetFieldString( hFeature, OGR_F_GetFieldIndex(hFeature, "Name"), szName );
 \endcode
 
 We create a local geometry object, and assign its copy (indirectly) to the feature.
@@ -675,21 +679,21 @@ of the geometry.
 
 In C++ :
 \code
-	OGRPoint pt;
-	pt.setX( x );
-	pt.setY( y );
-	
-	poFeature->SetGeometry( &pt ); 
+        OGRPoint pt;
+        pt.setX( x );
+        pt.setY( y );
+        
+        poFeature->SetGeometry( &pt ); 
 \endcode
 
 In C :
 \code
-	OGRGeometryH hPt;
-	hPt = OGR_G_CreateGeometry(wkbPoint);
-	OGR_G_SetPoint_2D(hPt, 0, x, y);
-	
-	OGR_F_SetGeometry( hFeature, hPt ); 
-	OGR_G_DestroyGeometry(hPt);
+        OGRGeometryH hPt;
+        hPt = OGR_G_CreateGeometry(wkbPoint);
+        OGR_G_SetPoint_2D(hPt, 0, x, y);
+        
+        OGR_F_SetGeometry( hFeature, hPt ); 
+        OGR_G_DestroyGeometry(hPt);
 \endcode
 
 Now we create a feature in the file.  The OGRLayer::CreateFeature() does not
@@ -697,40 +701,34 @@ take ownership of our feature so we clean it up when done with it.
 
 In C++ :
 \code
-	if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
+        if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
         {
-	   printf( "Failed to create feature in shapefile.\n" );
+            printf( "Failed to create feature in shapefile.\n" );
            exit( 1 );
         }
-	
-	OGRFeature::DestroyFeature( poFeature );
+
+        OGRFeature::DestroyFeature( poFeature );
    }
 \endcode
 
 In C :
 \code
-	if( OGR_L_CreateFeature( hLayer, hFeature ) != OGRERR_NONE )
+        if( OGR_L_CreateFeature( hLayer, hFeature ) != OGRERR_NONE )
         {
-	   printf( "Failed to create feature in shapefile.\n" );
+            printf( "Failed to create feature in shapefile.\n" );
            exit( 1 );
         }
-	
-	OGR_F_Destroy( hFeature );
+
+        OGR_F_Destroy( hFeature );
    }
 \endcode
 
 Finally we need to close down the datasource in order to ensure headers
 are written out in an orderly way and all resources are recovered.
 
-In C++ :
-\code
-    OGRDataSource::DestroyDataSource( poDS );
-}
-\endcode
-
-In C :
+In C/C++ :
 \code
-    OGR_DS_Destroy( hDS );
+    GDALClose( poDS );
 }
 \endcode
 
@@ -743,25 +741,24 @@ In C++ :
 int main()
 {
     const char *pszDriverName = "ESRI Shapefile";
-    OGRSFDriver *poDriver;
+    GDALDriver *poDriver;
 
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
-		pszDriverName );
+    poDriver = GetGDALDriverManager()->GetDriverByName(pszDriverName );
     if( poDriver == NULL )
     {
-	printf( "%s driver not available.\n", pszDriverName );
-	exit( 1 );
+        printf( "%s driver not available.\n", pszDriverName );
+        exit( 1 );
     }
 
-    OGRDataSource *poDS;
+    GDALDataset *poDS;
 
-    poDS = poDriver->CreateDataSource( "point_out.shp", NULL );
+    poDS = poDriver->Create( "point_out.shp", 0, 0, 0, GDT_Unknown, NULL );
     if( poDS == NULL )
     {
-	printf( "Creation of output file failed.\n" );
-	exit( 1 );
+        printf( "Creation of output file failed.\n" );
+        exit( 1 );
     }
 
     OGRLayer *poLayer;
@@ -769,8 +766,8 @@ int main()
     poLayer = poDS->CreateLayer( "point_out", NULL, wkbPoint, NULL );
     if( poLayer == NULL )
     {
-	printf( "Layer creation failed.\n" );
-	exit( 1 );
+        printf( "Layer creation failed.\n" );
+        exit( 1 );
     }
 
     OGRFieldDefn oField( "Name", OFTString );
@@ -779,7 +776,7 @@ int main()
 
     if( poLayer->CreateField( &oField ) != OGRERR_NONE )
     {
-	printf( "Creating Name field failed.\n" );
+        printf( "Creating Name field failed.\n" );
         exit( 1 );
     }
 
@@ -789,62 +786,62 @@ int main()
     while( !feof(stdin) 
            && fscanf( stdin, "%lf,%lf,%32s", &x, &y, szName ) == 3 )
     {
-	OGRFeature *poFeature;
+        OGRFeature *poFeature;
 
-	poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
-	poFeature->SetField( "Name", szName );
+        poFeature = OGRFeature::CreateFeature( poLayer->GetLayerDefn() );
+        poFeature->SetField( "Name", szName );
 
-	OGRPoint pt;
-	
-  	pt.setX( x );
+        OGRPoint pt;
+        
+        pt.setX( x );
         pt.setY( y );
- 
+    
         poFeature->SetGeometry( &pt ); 
 
-	if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
+        if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
         {
-	   printf( "Failed to create feature in shapefile.\n" );
-           exit( 1 );
+            printf( "Failed to create feature in shapefile.\n" );
+            exit( 1 );
         }
 
-         OGRFeature::DestroyFeature( poFeature );
+        OGRFeature::DestroyFeature( poFeature );
     }
 
-    OGRDataSource::DestroyDataSource( poDS );
+    GDALClose( poDS );
 }
 \endcode
 
 In C :
 \code
-#include "ogr_api.h"
+#include "gdal.h"
 
 int main()
 {
     const char *pszDriverName = "ESRI Shapefile";
-    OGRSFDriverH hDriver;
-    OGRDataSourceH hDS;
+    GDALDriverH hDriver;
+    GDALDatasetH hDS;
     OGRLayerH hLayer;
     OGRFieldDefnH hFieldDefn;
     double x, y;
     char szName[33];
 
-    OGRRegisterAll();
+    GDALAllRegister();
 
-    hDriver = OGRGetDriverByName( pszDriverName );
+    hDriver = GDALGetDriverByName( pszDriverName );
     if( hDriver == NULL )
     {
         printf( "%s driver not available.\n", pszDriverName );
         exit( 1 );
     }
 
-    hDS = OGR_Dr_CreateDataSource( hDriver, "point_out.shp", NULL );
+    hDS = GDALCreate( hDriver, "point_out.shp", 0, 0, 0, GDT_Unknown, NULL );
     if( hDS == NULL )
     {
         printf( "Creation of output file failed.\n" );
         exit( 1 );
     }
 
-    hLayer = OGR_DS_CreateLayer( hDS, "point_out", NULL, wkbPoint, NULL );
+    hLayer = GDALDatasetCreateLayer( hDS, "point_out", NULL, wkbPoint, NULL );
     if( hLayer == NULL )
     {
         printf( "Layer creation failed.\n" );
@@ -887,23 +884,24 @@ int main()
         OGR_F_Destroy( hFeature );
    }
 
-   OGR_DS_Destroy( hDS );
+   GDALClose( hDS );
 }
 \endcode
 
 In Python :
 \code
 import sys
-import ogr
+from osgeo import gdal
+from osgeo import ogr
 import string
 
 driverName = "ESRI Shapefile"
-drv = ogr.GetDriverByName( driverName )
+drv = gdal.GetDriverByName( driverName )
 if drv is None:
     print "%s driver not available.\n" % driverName
     sys.exit( 1 )
 
-ds = drv.CreateDataSource( "point_out.shp" )
+ds = drv.Create( "point_out.shp", 0, 0, 0, gdal.GDT_Unknown )
 if ds is None:
     print "Creation of output file failed.\n"
     sys.exit( 1 )
diff --git a/ogr/ogr_arch.dox b/ogr/ogr_arch.dox
index 195d414..f552536 100644
--- a/ogr/ogr_arch.dox
+++ b/ogr/ogr_arch.dox
@@ -18,42 +18,42 @@ specifications.<p>
 \section ogr_arch_overview Class Overview
 
 <ul>
-<li> <b>Geometry</b> (<a href="ogr__geometry_8h-source.html">ogr_geometry.h</a>): 
+<li> <b>Geometry</b> (<a href="ogr__geometry_8h_source.html">ogr_geometry.h</a>): 
 The geometry classes (OGRGeometry, etc) encapsulate the OpenGIS model vector 
 data as well as providing some geometry operations, and translation to/from
 well known binary and text format.  A geometry includes a spatial reference
 system (projection).<p>
 
 <li> <b>Spatial Reference</b> 
-(<a href="ogr__spatialref_8h-source.html">ogr_spatialref.h</a>):
+(<a href="ogr__spatialref_8h_source.html">ogr_spatialref.h</a>):
 An OGRSpatialReference encapsulates the definition of a projection and 
 datum.<p>
 
-<li> <b>Feature</b> (<a href="ogr__feature_8h-source.html">ogr_feature.h</a>):
+<li> <b>Feature</b> (<a href="ogr__feature_8h_source.html">ogr_feature.h</a>):
 The OGRFeature encapsulates the definition of a whole feature, that is a 
 geometry and a set of attributes.<p>
 
 <li> <b>Feature Class Definition</b>
-(<a href="ogr__feature_8h-source.html">ogr_feature.h</a>): 
+(<a href="ogr__feature_8h_source.html">ogr_feature.h</a>): 
 The OGRFeatureDefn class captures the schema (set of field definitions) for
 a group of related features (normally a whole layer).<p>
 
 <li> <b>Layer</b>
-(<a href="ogrsf__frmts_8h-source.html">ogrsf_frmts.h</a>): 
+(<a href="ogrsf__frmts_8h_source.html">ogrsf_frmts.h</a>): 
 OGRLayer is an abstract base class represent a layer of features in an 
-OGRDataSource.<p>
+GDALDataset.<p>
 
-<li> <b>Data Source</b>
-(<a href="ogrsf__frmts_8h-source.html">ogrsf_frmts.h</a>): 
-An OGRDataSource is an abstract base class
+<li> <b>Dataset</b>
+(<a href="gdal__priv_8h_source.html">gdal_priv.h</a>): 
+A GDALDataset is an abstract base class
 representing a file or database containing one or more OGRLayer
 objects.<p>
 
 <li> <b>Drivers</b> 
-(<a href="ogrsf__frmts_8h-source.html">ogrsf_frmts.h</a>):
-An OGRSFDriver represents a translator for a specific
-format, opening OGRDataSource objects.  All available drivers are managed 
-by the OGRSFDriverRegistrar.<p>
+(<a href="gdal__priv_8h_source.html">gdal_priv.h</a>):
+A GDALDriver represents a translator for a specific
+format, opening GDALDataset objects.  All available drivers are managed 
+by the GDALDriverManager.<p>
 
 </ul>
 
@@ -63,14 +63,18 @@ The geometry classes are represent various kinds of vector geometry.  All
 the geometry classes derived from OGRGeometry which defines the common 
 services of all geometries.  Types of geometry include OGRPoint, OGRLineString,
 OGRPolygon, OGRGeometryCollection, OGRMultiPolygon, OGRMultiPoint, 
-and OGRMultiLineString.<p>
+and OGRMultiLineString.
+
+GDAL 2.0 extends those geometry type with non-linear geometries with the
+OGRCircularString, OGRCompoundCurve, OGRCurvePolygon, OGRMultiCurve and
+OGRMultiSurface classes.
 
 Additional intermediate abstract base classes contain functionality that
 could eventually be implemented by other geometry types.  These include
 OGRCurve (base class for OGRLineString) and OGRSurface (base class for 
 OGRPolygon).  Some intermediate interfaces modelled in the simple features
 abstract model and SFCOM are not modelled in OGR at this time.  In most 
-cases the methods are aggregated into other classes.  This may change.<p>
+cases the methods are aggregated into other classes.<p>
 
 The OGRGeometryFactory is used to convert well known text, and well known
 binary format data into geometries.  These are predefined ASCII and binary
@@ -91,6 +95,15 @@ aspect that has been well thought out.  In particular, it would be
 possible to create specialized classes using the OGRGeometryFactory without
 modifying it.<p>
 
+\subsection ogr_arch_geometry_compat_curves Compatibility issues with GDAL 2.0 non-linear geometries
+
+Generic mechanisms have been introduced so that creating or modifying a feature
+with a non-linear geometry in a layer of a driver that does not support it will
+transform that geometry in the closest matching linear geometry.
+
+On the other side, when retrieving data from the OGR C API, the OGRSetNonLinearGeometriesEnabledFlag()
+function can be used, so that geometries and layer geometry type returned are
+also converted to their linear approximation if necessary.
 
 \section ogr_arch_srs Spatial Reference
 
@@ -129,10 +142,9 @@ manner by the feature of that type (or feature class).<p>
 The feature id (FID) of a feature is intended to be a unique identifier for
 the feature within the layer it is a member of.  Freestanding features, or
 features not yet written to a layer may have a null (OGRNullFID) feature id. 
-The feature ids are modelled in OGR as a long integer; however, this is
-not sufficiently expressive to model the natural feature ids in some
-formats.  For instance, the GML feature id is a string, and the row id in
-Oracle is larger than 4 bytes.<p>
+The feature ids are modelled in OGR as a 64-bit integer (GDAL 2.0 or later);
+however, this is not sufficiently expressive to model the natural feature ids in some
+formats.  For instance, the GML feature id is a string.<p>
 
 The feature class
 also contains an indicator of the types of geometry allowed for that feature
@@ -196,50 +208,48 @@ SFCORBA support using OGR.
 
 The OGRLayer class is an abstract base class.  An implementation is 
 expected to be subclassed for each file format driver implemented. 
-OGRLayers are normally owned directly by their OGRDataSource, and aren't
+OGRLayers are normally owned directly by their GDALDataset, and aren't
 instantiated or destroyed directly.<p>
 
-\section ogr_arch_data_source Data Source
+\section ogr_arch_dataset Dataset
 
-An OGRDataSource represents a set of OGRLayer objects.  This usually 
-represents a single file, set of files, database or gateway.  An OGRDataSource
+A GDALDataset represents a set of OGRLayer objects.  This usually 
+represents a single file, set of files, database or gateway.  A GDALDataset
 has a list of OGRLayers which it owns but can return references to.<p>
 
-OGRDataSource is an abstract base class.  An implementation is 
+GDALDataset is an abstract base class.  An implementation is 
 expected to be subclassed for each file format driver implemented.
-OGRDataSource objects are not normally instantiated directly but rather with
-the assistance of an OGRSFDriver.  Deleting an OGRDataSource closes access
+GDALDataset objects are not normally instantiated directly but rather with
+the assistance of an GDALDriver.  Deleting an GDALDataset closes access
 to the underlying persistent data source, but does not normally result in 
 deletion of that file.<p>
 
-An OGRDataSource has a name (usually a filename) that can be used to reopen
-the data source with an OGRSFDriver.<p>
+A GDALDataset has a name (usually a filename) that can be used to reopen
+the data source with a GDALDriver.<p>
 
-The OGRDataSource also has support for executing a datasource specific
+The GDALDataset also has support for executing a datasource specific
 command, normally a form of SQL.   This is accomplished via the
-OGRDataSource::ExecuteSQL() method.  While some datasources (such as PostGIS
+GDALDataset::ExecuteSQL() method.  While some datasources (such as PostGIS
 and Oracle) pass the SQL through to an underlying database, OGR also includes
 support for evaluating a subset of the SQL SELECT statement against any
 datasource. <p>
 
 \section ogr_arch_drivers Drivers
 
-An OGRSFDriver object is instantiated for each file format supported.  
-The OGRSFDriver objects are registered with the OGRSFDriverRegistrar, a
-singleton class that is normally used to open new data sources.<p>
+A GDALDriver object is instantiated for each file format supported.  
+The GDALDriver objects are registered with the GDALDriverManager, a
+singleton class that is normally used to open new datasets.<p>
 
-It is intended that a new OGRSFDriver derived class be implemented for each
+It is intended that a new GDALDriver object is instanciated and define function
+pointers for operations like Identify(), Open() for each
 file format to be supported (along with a file format specific 
-OGRDataSource, and OGRLayer classes).<p>
+GDALDataset, and OGRLayer classes).<p>
 
 On application startup registration
 functions are normally called for each desired file format.  These functions
-instantiate the appropriate OGRSFDriver objects, and register them with the
-OGRSFDriverRegistrar.  When a data source is to be opened, the registrar
-will normally try each OGRSFDriver in turn, until one succeeds, returning
-an OGRDataSource object.<p>
-
-It is not intended that the OGRSFDriverRegistrar be 
-derived from.<p>
+instantiate the appropriate GDALDriver objects, and register them with the
+GDALDriverManager.  When a dataset is to be opened, the driver manager
+will normally try each GDALDataset in turn, until one succeeds, returning
+a GDALDataset object.<p>
 
 */
diff --git a/ogr/ogr_core.h b/ogr/ogr_core.h
index ef3337e..a1819df 100644
--- a/ogr/ogr_core.h
+++ b/ogr/ogr_core.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_core.h 27792 2014-10-04 09:02:06Z rouault $
+ * $Id: ogr_core.h 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Define some core portability services for cross-platform OGR code.
@@ -158,7 +158,7 @@ typedef struct
  * Simple container for a bounding region in 3D.
  */
 
-#if defined(__cplusplus) && !defined(CPL_SUPRESS_CPLUSPLUS)
+#if defined(__cplusplus) && !defined(CPL_SURESS_CPLUSPLUS)
 class CPL_DLL OGREnvelope3D : public OGREnvelope
 {
   public:
@@ -293,6 +293,7 @@ typedef int OGRErr;
 #define OGRERR_FAILURE             6
 #define OGRERR_UNSUPPORTED_SRS     7
 #define OGRERR_INVALID_HANDLE      8
+#define OGRERR_NON_EXISTING_FEATURE 9   /* added in GDAL 2.0 */
 
 typedef int     OGRBoolean;
 
@@ -308,6 +309,7 @@ typedef int     OGRBoolean;
 typedef enum 
 {
     wkbUnknown = 0,         /**< unknown type, non-standard */
+
     wkbPoint = 1,           /**< 0-dimensional geometric object, standard WKB */
     wkbLineString = 2,      /**< 1-dimensional geometric object with linear
                              *   interpolation between Points, standard WKB */
@@ -319,8 +321,25 @@ typedef enum
     wkbMultiPolygon = 6,    /**< GeometryCollection of Polygons, standard WKB */
     wkbGeometryCollection = 7, /**< geometric object that is a collection of 1
                                     or more geometric objects, standard WKB */
+
+    wkbCircularString = 8,  /**< one or more circular arc segments connected end to end,
+                             *   ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCompoundCurve = 9,   /**< sequence of contiguous curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCurvePolygon = 10,   /**< planar surface, defined by 1 exterior boundary
+                             *   and zero or more interior boundaries, that are curves.
+                             *    ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiCurve = 11,     /**< GeometryCollection of Curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiSurface = 12,   /**< GeometryCollection of Surfaces, ISO SQL/MM Part 3. GDAL >= 2.0 */
+
     wkbNone = 100,          /**< non-standard, for pure attribute records */
     wkbLinearRing = 101,    /**< non-standard, just for createGeometry() */
+
+    wkbCircularStringZ = 1008,  /**< wkbCircularString with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCompoundCurveZ = 1009,   /**< wkbCompoundCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCurvePolygonZ = 1010,    /**< wkbCurvePolygon with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiCurveZ = 1011,      /**< wkbMultiCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiSurfaceZ = 1012,    /**< wkbMultiSurface with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+
     wkbPoint25D = 0x80000001, /**< 2.5D extension as per 99-402 */
     wkbLineString25D = 0x80000002, /**< 2.5D extension as per 99-402 */
     wkbPolygon25D = 0x80000003, /**< 2.5D extension as per 99-402 */
@@ -328,29 +347,73 @@ typedef enum
     wkbMultiLineString25D = 0x80000005, /**< 2.5D extension as per 99-402 */
     wkbMultiPolygon25D = 0x80000006, /**< 2.5D extension as per 99-402 */
     wkbGeometryCollection25D = 0x80000007 /**< 2.5D extension as per 99-402 */
+
 } OGRwkbGeometryType;
 
+/* Outside of OGRwkbGeometryType since they are abstract types */
+#define wkbCurve            ((OGRwkbGeometryType)13)      /**< Curve (abstract type). SF-SQL 1.2 */
+#define wkbSurface          ((OGRwkbGeometryType)14)      /**< Surface (abstract type). SF-SQL 1.2 */
+
 /**
  * Output variants of WKB we support. 
+ *
  * 99-402 was a short-lived extension to SFSQL 1.1 that used a high-bit flag
  * to indicate the presence of Z coordiantes in a WKB geometry.
+ *
  * SQL/MM Part 3 and SFSQL 1.2 use offsets of 1000 (Z), 2000 (M) and 3000 (ZM)
  * to indicate the present of higher dimensional coordinates in a WKB geometry.
+ * Reference: <a href="https://portal.opengeospatial.org/files/?artifact_id=320243">
+ * 09-009_Committee_Draft_ISOIEC_CD_13249-3_SQLMM_Spatial.pdf</a>,
+ * ISO/IEC JTC 1/SC 32 N 1820, ISO/IEC CD 13249-3:201x(E), Date: 2009-01-16.
+ * The codes are also found in §8.2.3 of <a href="http://portal.opengeospatial.org/files/?artifact_id=25355">
+ * OGC 06-103r4 "OpenGIS® Implementation Standard for Geographic information - Simple feature access - Part 1: Common architecture", v1.2.1</a>
  */
 typedef enum 
 {
-    wkbVariantOgc, /**< Old-style 99-402 extended dimension (Z) WKB types */
-    wkbVariantIso  /**< SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension (Z&M) WKB types */
+    wkbVariantOldOgc, /**< Old-style 99-402 extended dimension (Z) WKB types */
+    wkbVariantIso,  /**< SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension (Z&M) WKB types */
+    wkbVariantPostGIS1 /**< PostGIS 1.X has different codes for CurvePolygon, MultiCurve and MultiSurface */
 } OGRwkbVariant;
 
+
+/** @deprecated in GDAL 2.0. Use wkbHasZ() or wkbSetZ() instead */
+#ifndef GDAL_COMPILATION
 #define wkb25DBit 0x80000000
-#define wkbFlatten(x)  ((OGRwkbGeometryType) ((x) & (~wkb25DBit)))
+#endif
+
+/** Return the 2D geometry type corresponding to the specified geometry type */
+#define wkbFlatten(x)  OGR_GT_Flatten((OGRwkbGeometryType)(x))
+
+/** Return if the geometry type is a 3D geometry type
+  * @since GDAL 2.0
+  */
+#define wkbHasZ(x)     OGR_GT_HasZ(x)
+
+/** Return the 3D geometry type corresponding to the specified geometry type.
+  * @since GDAL 2.0
+  */
+#define wkbSetZ(x)     OGR_GT_SetZ(x)
 
 #define ogrZMarker 0x21125711
 
 const char CPL_DLL * OGRGeometryTypeToName( OGRwkbGeometryType eType );
 OGRwkbGeometryType CPL_DLL OGRMergeGeometryTypes( OGRwkbGeometryType eMain,
                                                   OGRwkbGeometryType eExtra );
+OGRwkbGeometryType CPL_DLL OGRMergeGeometryTypesEx( OGRwkbGeometryType eMain,
+                                                    OGRwkbGeometryType eExtra,
+                                                    int bAllowPromotingToCurves );
+OGRwkbGeometryType CPL_DLL OGR_GT_Flatten( OGRwkbGeometryType eType );
+OGRwkbGeometryType CPL_DLL OGR_GT_SetZ( OGRwkbGeometryType eType );
+OGRwkbGeometryType CPL_DLL OGR_GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM );
+int                CPL_DLL OGR_GT_HasZ( OGRwkbGeometryType eType );
+int                CPL_DLL OGR_GT_IsSubClassOf( OGRwkbGeometryType eType,
+                                                OGRwkbGeometryType eSuperType );
+int                CPL_DLL OGR_GT_IsCurve( OGRwkbGeometryType );
+int                CPL_DLL OGR_GT_IsSurface( OGRwkbGeometryType );
+int                CPL_DLL OGR_GT_IsNonLinear( OGRwkbGeometryType );
+OGRwkbGeometryType CPL_DLL OGR_GT_GetCollection( OGRwkbGeometryType eType );
+OGRwkbGeometryType CPL_DLL OGR_GT_GetCurve( OGRwkbGeometryType eType );
+OGRwkbGeometryType CPL_DLL OGR_GT_GetLinear( OGRwkbGeometryType eType );
 
 typedef enum 
 {
@@ -370,10 +433,71 @@ typedef enum
 #  define DB2_V72_UNFIX_BYTE_ORDER(x) (x)
 #endif
 
+/** Alter field name.
+ * Used by OGR_L_AlterFieldDefn().
+ */
 #define ALTER_NAME_FLAG            0x1
+
+/** Alter field type.
+ * Used by OGR_L_AlterFieldDefn().
+ */
 #define ALTER_TYPE_FLAG            0x2
+
+/** Alter field width and precision.
+ * Used by OGR_L_AlterFieldDefn().
+ */
 #define ALTER_WIDTH_PRECISION_FLAG 0x4
-#define ALTER_ALL_FLAG             (ALTER_NAME_FLAG | ALTER_TYPE_FLAG | ALTER_WIDTH_PRECISION_FLAG)
+
+/** Alter field NOT NULL constraint.
+ * Used by OGR_L_AlterFieldDefn().
+ * @since GDAL 2.0
+ */
+#define ALTER_NULLABLE_FLAG        0x8
+
+/** Alter field DEFAULT value.
+ * Used by OGR_L_AlterFieldDefn().
+ * @since GDAL 2.0
+ */
+#define ALTER_DEFAULT_FLAG         0x10
+
+/** Alter all parameters of field definition.
+ * Used by OGR_L_AlterFieldDefn().
+ */
+#define ALTER_ALL_FLAG             (ALTER_NAME_FLAG | ALTER_TYPE_FLAG | ALTER_WIDTH_PRECISION_FLAG | ALTER_NULLABLE_FLAG | ALTER_DEFAULT_FLAG)
+
+
+/** Validate that fields respect not-null constraints.
+ * Used by OGR_F_Validate().
+ * @since GDAL 2.0
+ */
+#define OGR_F_VAL_NULL           0x00000001
+
+/** Validate that geometries respect geometry column type.
+ * Used by OGR_F_Validate().
+ * @since GDAL 2.0
+ */
+#define OGR_F_VAL_GEOM_TYPE      0x00000002
+
+/** Validate that (string) fields respect field width.
+ * Used by OGR_F_Validate().
+ * @since GDAL 2.0
+ */
+#define OGR_F_VAL_WIDTH          0x00000004
+
+/** Allow fields that are null when there's an associated default value.
+ * This can be used for drivers where the low-level layers will automatically set the
+ * field value to the associated default value.
+ * This flag only makes sense if OGR_F_VAL_NULL is set too.
+ * Used by OGR_F_Validate().
+ * @since GDAL 2.0
+ */
+#define OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT       0x00000008
+
+/** Enable all validation tests.
+ * Used by OGR_F_Validate().
+ * @since GDAL 2.0
+ */
+#define OGR_F_VAL_ALL            0xFFFFFFFF
 
 /************************************************************************/
 /*                  ogr_feature.h related definitions.                  */
@@ -399,10 +523,33 @@ typedef enum
   /** Date */                                   OFTDate = 9,
   /** Time */                                   OFTTime = 10,
   /** Date and Time */                          OFTDateTime = 11,
-                                                OFTMaxType = 11
+  /** Single 64bit integer */                   OFTInteger64 = 12,
+  /** List of 64bit integers */                 OFTInteger64List = 13,
+                                                OFTMaxType = 13
 } OGRFieldType;
 
 /**
+ * List of field subtypes. A subtype represents a hint, a restriction of the
+ * main type, that is not strictly necessary to consult.
+ * This list is likely to be extended in the
+ * future ... avoid coding applications based on the assumption that all
+ * field types can be known.
+ * Most subtypes only make sense for a restricted set of main types.
+ * @since GDAL 2.0
+ */
+typedef enum
+{
+    /** No subtype. This is the default value */        OFSTNone = 0,
+    /** Boolean integer. Only valid for OFTInteger and OFTIntegerList.*/
+                                                        OFSTBoolean = 1,
+    /** Signed 16-bit integer. Only valid for OFTInteger and OFTIntegerList. */
+                                                        OFSTInt16 = 2,
+    /** Single precision (32 bit) floatint point. Only valid for OFTReal and OFTRealList. */
+                                                        OFSTFloat32 = 3,
+                                                        OFSTMaxSubType = 3
+} OGRFieldSubType;
+
+/**
  * Display justification for field values.
  */
 
@@ -426,6 +573,7 @@ typedef enum
 
 typedef union {
     int         Integer;
+    GIntBig     Integer64;
     double      Real;
     char       *String;
     
@@ -436,6 +584,11 @@ typedef union {
     
     struct {
         int     nCount;
+        GIntBig *paList;
+    } Integer64List;
+
+    struct {
+        int     nCount;
         double  *paList;
     } RealList;
     
@@ -460,12 +613,15 @@ typedef union {
         GByte   Day;
         GByte   Hour;
         GByte   Minute;
-        GByte   Second;
         GByte   TZFlag; /* 0=unknown, 1=localtime(ambiguous), 
                            100=GMT, 104=GMT+1, 80=GMT-5, etc */
+        GByte   Reserved; /* must be set to 0 */
+        float   Second; /* with millisecond accuracy. at the end of the structure, so as to keep it 12 bytes on 32 bit */
     } Date;
 } OGRField;
 
+#define OGR_GET_MS(floatingpoint_sec)   (int)(((floatingpoint_sec) - (int)(floatingpoint_sec)) * 1000 + 0.5)
+
 int CPL_DLL OGRParseDate( const char *pszInput, OGRField *psOutput, 
                           int nOptions );
 
@@ -488,14 +644,26 @@ int CPL_DLL OGRParseDate( const char *pszInput, OGRField *psOutput,
 #define OLCStringsAsUTF8       "StringsAsUTF8"
 #define OLCIgnoreFields        "IgnoreFields"
 #define OLCCreateGeomField     "CreateGeomField"
+#define OLCCurveGeometries     "CurveGeometries"
 
 #define ODsCCreateLayer        "CreateLayer"
 #define ODsCDeleteLayer        "DeleteLayer"
 #define ODsCCreateGeomFieldAfterCreateLayer   "CreateGeomFieldAfterCreateLayer"
+#define ODsCCurveGeometries    "CurveGeometries"
+#define ODsCTransactions       "Transactions"
+#define ODsCEmulatedTransactions "EmulatedTransactions"
 
 #define ODrCCreateDataSource   "CreateDataSource"
 #define ODrCDeleteDataSource   "DeleteDataSource"
 
+/* -------------------------------------------------------------------- */
+/*      Layer metadata items.                                           */
+/* -------------------------------------------------------------------- */
+/** Capability set to YES as metadata on a layer that has features with
+  * 64 bit identifiers.
+  @since GDAL 2.0
+  */
+#define OLMD_FID64             "OLMD_FID64"
 
 /************************************************************************/
 /*                  ogr_featurestyle.h related definitions.             */
diff --git a/ogr/ogr_drivertut.dox b/ogr/ogr_drivertut.dox
index 75dfca2..cbd1e35 100644
--- a/ogr/ogr_drivertut.dox
+++ b/ogr/ogr_drivertut.dox
@@ -8,8 +8,8 @@
 \section odt_overall Overall Approach
 
 In general new formats are added to OGR by implementing format specific
-drivers with subclasses of OGRSFDriver, OGRDataSource and OGRLayer.  The
-OGRSFDriver subclass is registered with the OGRSFDriverRegistrar at runtime.
+drivers with intanciating a GDALDriver and subclasses of GDALDatasetand OGRLayer.  The
+GDALDriver instance is registered with the GDALDriverManager at runtime.
 
 Before following this tutorial to implement an OGR driver, please review 
 the <a href="ogr_arch.html">OGR Architecture</a> document carefully. 
@@ -24,113 +24,112 @@ The tutorial will be based on implementing a simple ascii point format.
 <li> \ref odt_layer_bro
 </ol>
 
-\section odt_driver_ro Implementing OGRSFDriver
+\section odt_driver_ro Implementing GDALDriver
 
-The format specific driver class is implemented as a subclass of OGRSFDriver.
+The format specific driver class is implemented as a instance of GDALDriver.
 One instance of the driver will normally be created, and registered with
-the OGRSFDriverRegistrar().  The instantiation of the driver is normally 
+the GDALDriverManager.  The instantiation of the driver is normally 
 handled by a global C callable registration function, similar to the
 following placed in the same file as the driver class. 
 
-\verbatim
+\code
 void RegisterOGRSPF()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSPFDriver );
-}
-\endverbatim
+    GDALDriver  *poDriver;
 
-The driver class declaration generally looks something like this for a
-format with read or read and update access (the Open() method), creation 
-support (the CreateDataSource() method), and the ability to delete a datasource
-(the DeleteDataSource() method).
+    if( GDALGetDriverByName( "SPF" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
-\verbatim
-class OGRSPFDriver : public OGRSFDriver
-{
-  public:
-                ~OGRSPFDriver();
-                
-    const char    *GetName();
-    OGRDataSource *Open( const char *, int );
-    OGRDataSource *CreateDataSource( const char *, char ** );
-    OGRErr         DeleteDataSource( const char *pszName );
-    int            TestCapability( const char * );
-};
-\endverbatim
+        poDriver->SetDescription( "SPF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Long name for SPF driver" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "spf" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_spf.html" );
 
-The constructor generally does nothing.  The OGRSFDriver::GetName() method 
-returns a static string with the name of the driver.  This name is specified 
-on the commandline when creating datasources so it is generally good to keep 
-it short and without any special characters or spaces. 
+        poDriver->pfnOpen = OGRSPFDriverOpen;
+        poDriver->pfnIdentify = OGRSPFDriverIdentify;
+        poDriver->pfnCreate = OGRSPFDriverCreate;
 
-\verbatim
-OGRSPFDriver::~OGRSPFDriver()
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
-{
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
+\endcode
 
-const char *OGRSPFDriver::GetName()
-{
-    return "SPF";
-}
-\endverbatim
+The SetDescription() sets the name of the driver.  This name is specified 
+on the commandline when creating datasources so it is generally good to keep 
+it short and without any special characters or spaces.
+
+SetMetadataItem( GDAL_DCAP_VECTOR, "YES" ) is specified to indicate that the driver
+will handle vector data.
+
+SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ) is specified to indicate that the
+driver can deal with files opened with the VSI*L GDAL API.
+Otherwise this metadata item should not be defined.
+
+The driver declaration generally looks something like this for a
+format with read or read and update access (the Open() method) and creation 
+support (the Create() method).
+
+\code
 
-The Open() method is called by OGRSFDriverRegistrar::Open(), or from the 
-C API OGROpen().  The OGRSFDriver::Open() method should quietly return NULL if 
+static GDALDataset* OGRSPFDriverOpen(GDALOpenInfo* poOpenInfo);
+static int          OGRSPFDriverIdentify(GDALOpenInfo* poOpenInfo);
+static GDALDataset* OGRSPFDriverCreate(const char* pszName, int nXSize, int nYSize,
+                                       int nBands, GDALDataType eDT, char** papszOptions);
+\endcode
+
+
+The Open() method is called by GDALOpenEx(). It should quietly return NULL if 
 the passed
 filename is not of the format supported by the driver.  If it is the target
-format, then a new OGRDataSource object for the datasource should be returned.
+format, then a new GDALDataset object for the dataset should be returned.
 
 It is common for the Open() method to be delegated to an Open() method on
-the actual format's OGRDataSource class.
+the actual format's GDALDataset class.
 
-\verbatim
-OGRDataSource *OGRSPFDriver::Open( const char * pszFilename, int bUpdate )
+\code
+static GDALDataset *OGRSPFDriverOpen( GDALOpenInfo* poOpenInfo )
 {
-    OGRSPFDataSource   *poDS = new OGRSPFDataSource();
+    if( !OGRSPFDriverIdentify(poOpenInfo) )
+        return NULL;
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    OGRSPFDataSource   *poDS = new OGRSPFDataSource();
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAcces == GA_Update ) )
     {
         delete poDS;
-	return NULL;
+        return NULL;
     }
     else
         return poDS;
 }
-\endverbatim
-
-In OGR the capabilities of drivers, datasources and layers are determined
-by calling TestCapability() on the various objects with names strings 
-representing specific optional capabilities.  For the driver the only two
-capabilities currently tested for are the ability to create datasources and
-to delete them.  In our first pass as a read only SPF driver, these are
-both disabled.  The default return value for unrecognised capabilities 
-should always be FALSE, and the symbolic #defines for capability names
-(defined in ogr_core.h) should be used instead of the literal strings to 
-avoid typos. 
+\endcode
 
-\verbatim
-int OGRSPFDriver::TestCapability( const char * pszCap )
+The Identify() method is implemented as such :
 
+\code
+static int OGRSPFDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return FALSE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return FALSE;
-    else
-        return FALSE;
+// -------------------------------------------------------------------- 
+//      Does this appear to be an .spf file?                           
+// --------------------------------------------------------------------
+    return EQUAL( CPLGetExtension(poOpenInfo->pszFilename), "spf" );
 }
-\endverbatim
+\endcode
+
 
-Examples of the CreateDataSource() and DeleteDataSource() methods are left 
-for the section on creation and update. 
+Examples of the Create() method is left for the section on creation and update. 
 
 \section odt_datasource_bro Basic Read Only Data Source
 
 We will start implementing a minimal read-only datasource.  No attempt is
 made to optimize operations, and default implementations of many methods
-inherited from OGRDataSource are used.  
+inherited from GDALDataset are used.  
 
 The primary responsibility of the datasource is to manage the list of layers.
 In the case of the SPF format a datasource is a single file representing one
@@ -144,11 +143,9 @@ For this simple case we provide a stub TestCapability() that returns FALSE
 for all extended capabilities.  The TestCapability() method is pure virtual,
 so it does need to be implemented.
 
-\verbatim
-class OGRSPFDataSource : public OGRDataSource
+\code
+class OGRSPFDataSource : public GDALDataset
 {
-    char                *pszName;
-    
     OGRSPFLayer       **papoLayers;
     int                 nLayers;
 
@@ -157,28 +154,24 @@ class OGRSPFDataSource : public OGRDataSource
                         ~OGRSPFDataSource();
 
     int                 Open( const char * pszFilename, int bUpdate );
-    
-    const char          *GetName() { return pszName; }
 
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
     int                 TestCapability( const char * ) { return FALSE; }
 };
-\endverbatim
+\endcode
 
 The constructor is a simple initializer to a default state.  The Open() will
 take care of actually attaching it to a file.  The destructor is responsible
 for orderly cleanup of layers.  
 
-\verbatim
+\code
 OGRSPFDataSource::OGRSPFDataSource()
 
 {
     papoLayers = NULL;
     nLayers = 0;
-
-    pszName = NULL;
 }
 
 OGRSPFDataSource::~OGRSPFDataSource()
@@ -187,10 +180,8 @@ OGRSPFDataSource::~OGRSPFDataSource()
     for( int i = 0; i < nLayers; i++ )
         delete papoLayers[i];
     CPLFree( papoLayers );
-
-    CPLFree( pszName );
 }
-\endverbatim
+\endcode
 
 The Open() method is the most important one on the datasource, though
 in this particular instance it passes most of it's work off to the
@@ -206,19 +197,13 @@ is generally a poor way of identifying a file format.  If available, checking
 In the case of the SPF format, update in place is not supported, 
 so we always fail if bUpdate is FALSE. 
 
-\verbatim
+\code
 int  OGRSPFDataSource::Open( const char *pszFilename, int bUpdate )
 
 {
-// -------------------------------------------------------------------- 
-//      Does this appear to be an .spf file?                           
-// --------------------------------------------------------------------
-    if( !EQUAL( CPLGetExtension(pszFilename), "spf" ) )
-        return FALSE;
-
     if( bUpdate )
     {
-	CPLError( CE_Failure, CPLE_OpenFailed, 
+        CPLError( CE_Failure, CPLE_OpenFailed, 
                   "Update access not supported by the SPF driver." );
         return FALSE;
     }
@@ -235,12 +220,12 @@ int  OGRSPFDataSource::Open( const char *pszFilename, int bUpdate )
 
     return TRUE;
 }
-\endverbatim
+\endcode
 
 A GetLayer() method also needs to be implemented.  Since the layer list
 is created in the Open() this is just a lookup with some safety testing.
 
-\verbatim
+\code
 OGRLayer *OGRSPFDataSource::GetLayer( int iLayer )
 
 {
@@ -249,7 +234,7 @@ OGRLayer *OGRSPFDataSource::GetLayer( int iLayer )
     else
         return papoLayers[iLayer];
 }
-\endverbatim
+\endcode
 
 \section odt_layer_bro Read Only Layer
 
@@ -258,7 +243,7 @@ access to a set of feature objects in a consistent coordinate system
 with a particular set of attribute columns.  Our class definition looks like
 this:
 
-\verbatim
+\code
 class OGRSPFLayer : public OGRLayer
 {
     OGRFeatureDefn     *poFeatureDefn;
@@ -278,7 +263,7 @@ class OGRSPFLayer : public OGRLayer
 
     int                 TestCapability( const char * ) { return FALSE; }
 };
-\endverbatim
+\endcode
 
 The layer constructor is responsible for initialization.  The most important
 initialization is setting up the OGRFeatureDefn for the layer.  This defines
@@ -291,13 +276,14 @@ As OGRFeature's for this layer will also take a reference to this definition
 it is important that we also establish a reference on behalf of the layer
 itself. 
 
-\verbatim
+\code
 OGRSPFLayer::OGRSPFLayer( const char *pszFilename )
 
 {
     nNextFID = 0;
 
     poFeatureDefn = new OGRFeatureDefn( CPLGetBasename( pszFilename ) );
+    SetDescription(poFeatureDefn->GetName());
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPoint );
    
@@ -309,7 +295,7 @@ OGRSPFLayer::OGRSPFLayer( const char *pszFilename )
     if( fp == NULL )
         return;
 }
-\endverbatim
+\endcode
 
 Note that the destructor uses Release() on the OGRFeatureDefn.  This will
 destroy the feature definition if the reference count drops to zero, but if
@@ -317,7 +303,7 @@ the application is still holding onto a feature from this layer, then that
 feature will hold a reference to the feature definition and it will not
 be destroyed here (which is good!).  
 
-\verbatim
+\code
 OGRSPFLayer::~OGRSPFLayer()
 
 {
@@ -325,7 +311,7 @@ OGRSPFLayer::~OGRSPFLayer()
     if( fp != NULL )
         VSIFCloseL( fp );
 }
-\endverbatim
+\endcode
 
 The GetNextFeature() method is usually the work horse of OGRLayer 
 implementations.  It is responsible for reading the next feature according
@@ -335,7 +321,7 @@ The while() loop is present to loop until we find a satisfactory
 feature.  The first section of code is for parsing a single line of 
 the SPF text file and establishing the x, y and name for the line.
 
-\verbatim
+\code
 OGRFeature *OGRSPFLayer::GetNextFeature()
 
 {
@@ -372,19 +358,19 @@ OGRFeature *OGRSPFLayer::GetNextFeature()
         else
             pszName = pszLine+1;
 
-\endverbatim
+\endcode
 
 The next section turns the x, y and name into a feature.  Also note that
 we assign a linearly incremented feature id.  In our case we started at
 zero for the first feature, though some drivers start at 1.  
 
-\verbatim
+\code
         OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
         
         poFeature->SetGeometryDirectly( new OGRPoint( dfX, dfY ) );
         poFeature->SetField( 0, pszName );
         poFeature->SetFID( nNextFID++ );
-\endverbatim
+\endcode
 
 Next we check if the feature matches our current attribute or 
 spatial filter if we have them.  Methods on the OGRLayer base class 
@@ -397,7 +383,7 @@ spatial filtering ahead of time using a spatial index.
 If the feature meets our criteria we return it.  Otherwise we destroy it,
 and return to the top of the loop to fetch another to try.  
 
-\verbatim
+\code
         if( (m_poFilterGeom == NULL
              || FilterGeometry( poFeature->GetGeometryRef() ) )
             && (m_poAttrQuery == NULL
@@ -407,21 +393,21 @@ and return to the top of the loop to fetch another to try.
         delete poFeature;
     }
 }
-\endverbatim
+\endcode
 
 While in the middle of reading a feature set from a layer, or at any other
 time the application can call ResetReading() which is intended to restart
 reading at the beginning of the feature set.  We implement this by seeking
 back to the beginning of the file, and resetting our feature id counter. 
 
-\verbatim
+\code
 void OGRSPFLayer::ResetReading()
 
 {
     VSIFSeekL( fp, 0, SEEK_SET );
     nNextFID = 0;
 }
-\endverbatim
+\endcode
 
 In this implementation we do not provide a custom implementation for the
 GetFeature() method.  This means an attempt to read a particular feature
diff --git a/ogr/ogr_expat.cpp b/ogr/ogr_expat.cpp
index 71cff3b..6e90d09 100644
--- a/ogr/ogr_expat.cpp
+++ b/ogr/ogr_expat.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_expat.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogr_expat.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OGR
  * Purpose:  Convenience function for parsing with Expat library
@@ -32,7 +32,7 @@
 #include "ogr_expat.h"
 #include "cpl_error.h"
 
-CPL_CVSID("$Id: ogr_expat.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogr_expat.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define OGR_EXPAT_MAX_ALLOWED_ALLOC 10000000
 
diff --git a/ogr/ogr_feature.h b/ogr/ogr_feature.h
index 8c43ed6..f413ad9 100644
--- a/ogr/ogr_feature.h
+++ b/ogr/ogr_feature.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_feature.h 27110 2014-03-28 21:29:20Z rouault $
+ * $Id: ogr_feature.h 28968 2015-04-21 19:00:02Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Class for representing a whole feature, and layer schemas.
@@ -46,7 +46,17 @@
 /************************************************************************/
 
 /**
- * Definition of an attribute of an OGRFeatureDefn.
+ * Definition of an attribute of an OGRFeatureDefn. A field is described by :
+ * <ul>
+ * <li>a name. See SetName() / GetNameRef()</li>
+ * <li>a type: OFTString, OFTInteger, OFTReal, ... See SetType() / GetType()</li>
+ * <li>a subtype (optional): OFSTBoolean, ... See SetSubType() / GetSubType()</li>
+ * <li>a width (optional): maximal number of characters. See SetWidth() / GetWidth()</li>
+ * <li>a precision (optional): number of digits after decimal point. See SetPrecision() / GetPrecision()</li>
+ * <li>a NOT NULL constraint (optional). See SetNullable() / IsNullable()</li>
+ * <li>a default value (optional).  See SetDefault() / GetDefault()</li>
+ * <li>a boolean to indicate whether it should be ignored when retrieving features.  See SetIgnored() / IsIgnored()</li>
+ * </ul>
  */
 
 class CPL_DLL OGRFieldDefn
@@ -57,9 +67,12 @@ class CPL_DLL OGRFieldDefn
     OGRJustification    eJustify;               
     int                 nWidth;                 /* zero is variable */
     int                 nPrecision;
-    OGRField            uDefault;
+    char                *pszDefault;
     
     int                 bIgnore;
+    OGRFieldSubType     eSubType;
+    
+    int                 bNullable;
 
     void                Initialize( const char *, OGRFieldType );
     
@@ -72,9 +85,13 @@ class CPL_DLL OGRFieldDefn
     const char         *GetNameRef() { return pszName; }
 
     OGRFieldType        GetType() { return eType; }
-    void                SetType( OGRFieldType eTypeIn ) { eType = eTypeIn;}
+    void                SetType( OGRFieldType eTypeIn );
     static const char  *GetFieldTypeName( OGRFieldType );
 
+    OGRFieldSubType     GetSubType() { return eSubType; }
+    void                SetSubType( OGRFieldSubType eSubTypeIn );
+    static const char  *GetFieldSubTypeName( OGRFieldSubType );
+
     OGRJustification    GetJustify() { return eJustify; }
     void                SetJustify( OGRJustification eJustifyIn )
                                                 { eJustify = eJustifyIn; }
@@ -89,11 +106,15 @@ class CPL_DLL OGRFieldDefn
     void                Set( const char *, OGRFieldType, int = 0, int = 0,
                              OGRJustification = OJUndefined );
 
-    void                SetDefault( const OGRField * );
-    const OGRField     *GetDefaultRef() { return &uDefault; }
-    
+    void                SetDefault( const char* );
+    const char         *GetDefault() const;
+    int                 IsDefaultDriverSpecific() const;
+
     int                 IsIgnored() { return bIgnore; }
-    void                SetIgnored( int bIgnore ) { this->bIgnore = bIgnore; }
+    void                SetIgnored( int bIgnoreIn ) { bIgnore = bIgnoreIn; }
+
+    int                 IsNullable() const { return bNullable; }
+    void                SetNullable( int bNullableIn ) { bNullable = bNullableIn; }
 
     int                 IsSame( const OGRFieldDefn * ) const;
 };
@@ -103,10 +124,17 @@ class CPL_DLL OGRFieldDefn
 /************************************************************************/
 
 /**
- * Definition of a geometry field of an OGRFeatureDefn. A geometry field
- * is described by a name, a geometry type and a spatial reference system.
+ * Definition of a geometry field of an OGRFeatureDefn. A geometry field is
+ * described by :
+ * <ul>
+ * <li>a name. See SetName() / GetNameRef()</li>
+ * <li>a type: wkbPoint, wkbLineString, ... See SetType() / GetType()</li>
+ * <li>a spatial reference system (optional). See SetSpatialRef() / GetSpatialRef()</li>
+ * <li>a NOT NULL constraint (optional). See SetNullable() / IsNullable()</li>
+ * <li>a boolean to indicate whether it should be ignored when retrieving features.  See SetIgnored() / IsIgnored()</li>
+ * </ul>
  *
- * @since OGR 2.0
+ * @since OGR 1.11
  */
 
 class CPL_DLL OGRGeomFieldDefn
@@ -117,6 +145,7 @@ protected:
         OGRSpatialReference* poSRS;
 
         int                 bIgnore;
+        int                 bNullable;
 
         void                Initialize( const char *, OGRwkbGeometryType );
 
@@ -133,10 +162,13 @@ public:
         void                SetType( OGRwkbGeometryType eTypeIn );
 
         virtual OGRSpatialReference* GetSpatialRef();
-        void                 SetSpatialRef(OGRSpatialReference* poSRS);
+        void                 SetSpatialRef(OGRSpatialReference* poSRSIn);
 
         int                 IsIgnored() { return bIgnore; }
-        void                SetIgnored( int bIgnore ) { this->bIgnore = bIgnore; }
+        void                SetIgnored( int bIgnoreIn ) { bIgnore = bIgnoreIn; }
+
+        int                 IsNullable() const { return bNullable; }
+        void                SetNullable( int bNullableIn ) { bNullable = bNullableIn; }
 
         int                 IsSame( OGRGeomFieldDefn * );
 };
@@ -154,11 +186,12 @@ public:
  * of features but doesn't necessarily relate to all of a layer, or just one
  * layer.
  *
- * This object also can contain some other information such as a name, the
- * base geometry type and potentially other metadata.
+ * This object also can contain some other information such as a name and
+ * potentially other metadata.
  *
+ * It is essentially a collection of field descriptions (OGRFieldDefn class).
  * Starting with GDAL 1.11, in addition to attribute fields, it can also
- * contain multiple geometry fields.
+ * contain multiple geometry fields (OGRGeomFieldDefn class).
  *
  * It is reasonable for different translators to derive classes from
  * OGRFeatureDefn with additional translator specific information. 
@@ -233,7 +266,7 @@ class CPL_DLL OGRFeature
 {
   private:
 
-    long                nFID;
+    GIntBig              nFID;
     OGRFeatureDefn      *poDefn;
     OGRGeometry        **papoGeometries;
     OGRField            *pauFields;
@@ -283,9 +316,11 @@ class CPL_DLL OGRFeature
     OGRField           *GetRawFieldRef( int i ) { return pauFields + i; }
 
     int                 GetFieldAsInteger( int i );
+    GIntBig             GetFieldAsInteger64( int i );
     double              GetFieldAsDouble( int i );
     const char         *GetFieldAsString( int i );
     const int          *GetFieldAsIntegerList( int i, int *pnCount );
+    const GIntBig      *GetFieldAsInteger64List( int i, int *pnCount );
     const double       *GetFieldAsDoubleList( int i, int *pnCount );
     char              **GetFieldAsStringList( int i );
     GByte              *GetFieldAsBinary( int i, int *pnCount );
@@ -293,9 +328,15 @@ class CPL_DLL OGRFeature
                                      int *pnYear, int *pnMonth, int *pnDay,
                                      int *pnHour, int *pnMinute, int *pnSecond, 
                                      int *pnTZFlag );
+    int                 GetFieldAsDateTime( int i, 
+                                     int *pnYear, int *pnMonth, int *pnDay,
+                                     int *pnHour, int *pnMinute, float *pfSecond, 
+                                     int *pnTZFlag );
 
     int                 GetFieldAsInteger( const char *pszFName )
                       { return GetFieldAsInteger( GetFieldIndex(pszFName) ); }
+    GIntBig             GetFieldAsInteger64( const char *pszFName )
+                      { return GetFieldAsInteger64( GetFieldIndex(pszFName) ); }
     double              GetFieldAsDouble( const char *pszFName )
                       { return GetFieldAsDouble( GetFieldIndex(pszFName) ); }
     const char         *GetFieldAsString( const char *pszFName )
@@ -304,6 +345,10 @@ class CPL_DLL OGRFeature
                                                int *pnCount )
                       { return GetFieldAsIntegerList( GetFieldIndex(pszFName),
                                                       pnCount ); }
+    const GIntBig      *GetFieldAsInteger64List( const char *pszFName,
+                                               int *pnCount )
+                      { return GetFieldAsInteger64List( GetFieldIndex(pszFName),
+                                                      pnCount ); }
     const double       *GetFieldAsDoubleList( const char *pszFName,
                                               int *pnCount )
                       { return GetFieldAsDoubleList( GetFieldIndex(pszFName),
@@ -312,19 +357,23 @@ class CPL_DLL OGRFeature
                       { return GetFieldAsStringList(GetFieldIndex(pszFName)); }
 
     void                SetField( int i, int nValue );
+    void                SetField( int i, GIntBig nValue );
     void                SetField( int i, double dfValue );
     void                SetField( int i, const char * pszValue );
     void                SetField( int i, int nCount, int * panValues );
+    void                SetField( int i, int nCount, const GIntBig * panValues );
     void                SetField( int i, int nCount, double * padfValues );
     void                SetField( int i, char ** papszValues );
     void                SetField( int i, OGRField * puValue );
     void                SetField( int i, int nCount, GByte * pabyBinary );
     void                SetField( int i, int nYear, int nMonth, int nDay,
-                                  int nHour=0, int nMinute=0, int nSecond=0, 
+                                  int nHour=0, int nMinute=0, float fSecond=0.f, 
                                   int nTZFlag = 0 );
 
     void                SetField( const char *pszFName, int nValue )
                            { SetField( GetFieldIndex(pszFName), nValue ); }
+    void                SetField( const char *pszFName, GIntBig nValue )
+                           { SetField( GetFieldIndex(pszFName), nValue ); }
     void                SetField( const char *pszFName, double dfValue )
                            { SetField( GetFieldIndex(pszFName), dfValue ); }
     void                SetField( const char *pszFName, const char * pszValue)
@@ -333,6 +382,9 @@ class CPL_DLL OGRFeature
                                   int * panValues )
                          { SetField(GetFieldIndex(pszFName),nCount,panValues);}
     void                SetField( const char *pszFName, int nCount,
+                                  const GIntBig * panValues )
+                         { SetField(GetFieldIndex(pszFName),nCount,panValues);}
+    void                SetField( const char *pszFName, int nCount,
                                   double * padfValues )
                          {SetField(GetFieldIndex(pszFName),nCount,padfValues);}
     void                SetField( const char *pszFName, char ** papszValues )
@@ -341,14 +393,14 @@ class CPL_DLL OGRFeature
                            { SetField( GetFieldIndex(pszFName), puValue ); }
     void                SetField( const char *pszFName, 
                                   int nYear, int nMonth, int nDay,
-                                  int nHour=0, int nMinute=0, int nSecond=0, 
+                                  int nHour=0, int nMinute=0, float fSecond=0.f, 
                                   int nTZFlag = 0 )
                            { SetField( GetFieldIndex(pszFName), 
                                        nYear, nMonth, nDay, 
-                                       nHour, nMinute, nSecond, nTZFlag ); }
+                                       nHour, nMinute, fSecond, nTZFlag ); }
 
-    long                GetFID() { return nFID; }
-    virtual OGRErr      SetFID( long nFID );
+    GIntBig             GetFID() { return nFID; }
+    virtual OGRErr      SetFID( GIntBig nFIDIn );
 
     void                DumpReadable( FILE *, char** papszOptions = NULL );
 
@@ -361,14 +413,17 @@ class CPL_DLL OGRFeature
     OGRErr              RemapGeomFields( OGRFeatureDefn *poNewDefn, 
                                      int *panRemapSource );
 
+    int                 Validate( int nValidateFlags,
+                                  int bEmitError );
+    void                FillUnsetWithDefault(int bNotNullableOnly,
+                                             char** papszOptions );
+
     virtual const char *GetStyleString();
     virtual void        SetStyleString( const char * );
     virtual void        SetStyleStringDirectly( char * );
     virtual OGRStyleTable *GetStyleTable() { return m_poStyleTable; }
     virtual void        SetStyleTable(OGRStyleTable *poStyleTable);
-    virtual void        SetStyleTableDirectly(OGRStyleTable *poStyleTable)
-                            { if ( m_poStyleTable ) delete m_poStyleTable;
-                              m_poStyleTable = poStyleTable; }
+    virtual void        SetStyleTableDirectly(OGRStyleTable *poStyleTable);
 
     static OGRFeature  *CreateFeature( OGRFeatureDefn * );
     static void         DestroyFeature( OGRFeature * );
@@ -380,6 +435,7 @@ class CPL_DLL OGRFeature
 
 class OGRLayer;
 class swq_expr_node;
+class swq_custom_func_registrar;
 
 class CPL_DLL OGRFeatureQuery
 {
@@ -389,7 +445,7 @@ class CPL_DLL OGRFeatureQuery
 
     char          **FieldCollector( void *, char ** );
 
-    long       *EvaluateAgainstIndices( swq_expr_node*, OGRLayer *, int& nFIDCount);
+    GIntBig       *EvaluateAgainstIndices( swq_expr_node*, OGRLayer *, GIntBig& nFIDCount);
     
     int         CanUseIndex( swq_expr_node*, OGRLayer * );
     
@@ -397,16 +453,17 @@ class CPL_DLL OGRFeatureQuery
                 OGRFeatureQuery();
                 ~OGRFeatureQuery();
 
-    OGRErr      Compile( OGRFeatureDefn *, const char * );
+    OGRErr      Compile( OGRFeatureDefn *, const char *,
+                         int bCheck = TRUE, swq_custom_func_registrar* poCustomFuncRegistrar = NULL );
     int         Evaluate( OGRFeature * );
 
-    long       *EvaluateAgainstIndices( OGRLayer *, OGRErr * );
+    GIntBig       *EvaluateAgainstIndices( OGRLayer *, OGRErr * );
     
     int         CanUseIndex( OGRLayer * );
 
     char      **GetUsedFields();
 
-    void       *GetSWGExpr() { return pSWQExpr; }
+    void       *GetSWQExpr() { return pSWQExpr; }
 };
 
 #endif /* ndef _OGR_FEATURE_H_INCLUDED */
diff --git a/ogr/ogr_fromepsg.cpp b/ogr/ogr_fromepsg.cpp
index 9334875..232e3df 100644
--- a/ogr/ogr_fromepsg.cpp
+++ b/ogr/ogr_fromepsg.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_fromepsg.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogr_fromepsg.cpp 28565 2015-02-27 10:26:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Generate an OGRSpatialReference object based on an EPSG
@@ -32,8 +32,9 @@
 #include "ogr_spatialref.h"
 #include "ogr_p.h"
 #include "cpl_csv.h"
+#include <vector>
 
-CPL_CVSID("$Id: ogr_fromepsg.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogr_fromepsg.cpp 28565 2015-02-27 10:26:21Z rouault $");
 
 #ifndef PI
 #  define PI 3.14159265358979323846
@@ -402,6 +403,27 @@ EPSGGetUOMLengthInfo( int nUOMLengthCode,
 }
 
 /************************************************************************/
+/*                         EPSGNegateString()                           */
+/************************************************************************/
+
+static void EPSGNegateString(CPLString& osValue)
+{
+    if( osValue.compare("0") == 0 )
+        return;
+    if( osValue[0] == '-' )
+    {
+        osValue = osValue.substr(1);
+        return;
+    }
+    if( osValue[0] == '+' )
+    {
+        osValue[0] = '-';
+        return;
+    }
+    osValue = "-" + osValue;
+}
+
+/************************************************************************/
 /*                       EPSGGetWGS84Transform()                        */
 /*                                                                      */
 /*      The following code attempts to find a bursa-wolf                */
@@ -414,7 +436,7 @@ EPSGGetUOMLengthInfo( int nUOMLengthCode,
 /*         to limitations in the CSV API.                               */
 /************************************************************************/
 
-int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform )
+int EPSGGetWGS84Transform( int nGeogCS, std::vector<CPLString>& asTransform )
 
 {
     int         nMethodCode, iDXField, iField;
@@ -459,8 +481,15 @@ int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform )
     if (iDXField < 0 || CSLCount(papszLine) < iDXField + 7)
         return FALSE;
 
+    asTransform.resize(0);
     for( iField = 0; iField < 7; iField++ )
-        padfTransform[iField] = CPLAtof(papszLine[iDXField+iField]);
+    {
+        const char* pszValue = papszLine[iDXField+iField];
+        if( pszValue[0] )
+            asTransform.push_back(pszValue);
+        else
+            asTransform.push_back("0");
+    }
 
 /* -------------------------------------------------------------------- */
 /*      9607 - coordinate frame rotation has reverse signs on the       */
@@ -469,9 +498,9 @@ int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform )
 /* -------------------------------------------------------------------- */
     if( nMethodCode == 9607 )
     {
-        padfTransform[3] *= -1;
-        padfTransform[4] *= -1;
-        padfTransform[5] *= -1;
+        EPSGNegateString(asTransform[3]);
+        EPSGNegateString(asTransform[4]);
+        EPSGNegateString(asTransform[5]);
     }
         
     return TRUE;
@@ -742,11 +771,10 @@ OSRGetEllipsoidInfo( int nCode, char ** ppszName,
                                   "ELLIPSOID_CODE", szSearchKey, CC_Integer,
                                   "SEMI_MINOR_AXIS" )) * dfToMeters;
 
-            if( dfSemiMajor != 0.0 && dfSemiMajor != dfSemiMinor )
-                *pdfInvFlattening = 
-                    -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
-            else
+            if( dfSemiMajor == 0.0 )
                 *pdfInvFlattening = 0.0;
+            else
+                *pdfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
         }
     }
 
@@ -1232,7 +1260,7 @@ static OGRErr SetEPSGGeogCS( OGRSpatialReference * poSRS, int nGeogCS )
     int  nDatumCode, nPMCode, nUOMAngle, nEllipsoidCode, nCSC;
     char *pszGeogCSName = NULL, *pszDatumName = NULL, *pszEllipsoidName = NULL;
     char *pszPMName = NULL, *pszAngleName = NULL;
-    double dfPMOffset, dfSemiMajor, dfInvFlattening, adfBursaTransform[7];
+    double dfPMOffset, dfSemiMajor, dfInvFlattening;
     double dfAngleInDegrees, dfAngleInRadians;
 
     if( !EPSGGetGCSInfo( nGeogCS, &pszGeogCSName,
@@ -1275,17 +1303,16 @@ static OGRErr SetEPSGGeogCS( OGRSpatialReference * poSRS, int nGeogCS )
                       pszPMName, dfPMOffset,
                       pszAngleName, dfAngleInRadians );
 
-    if( EPSGGetWGS84Transform( nGeogCS, adfBursaTransform ) )
+    std::vector<CPLString> asBursaTransform;
+    if( EPSGGetWGS84Transform( nGeogCS, asBursaTransform ) )
     {
         OGR_SRSNode     *poWGS84;
-        char            szValue[100];
 
         poWGS84 = new OGR_SRSNode( "TOWGS84" );
 
         for( int iCoeff = 0; iCoeff < 7; iCoeff++ )
         {
-            sprintf( szValue, "%g", adfBursaTransform[iCoeff] );
-            poWGS84->AddChild( new OGR_SRSNode( szValue ) );
+            poWGS84->AddChild( new OGR_SRSNode( asBursaTransform[iCoeff].c_str() ) );
         }
 
         poSRS->GetAttrNode( "DATUM" )->AddChild( poWGS84 );
@@ -1324,9 +1351,10 @@ static OGRErr SetEPSGGeogCS( OGRSpatialReference * poSRS, int nGeogCS )
 /*      parameter code.                                                 */
 /************************************************************************/
 
-static double OGR_FetchParm( double *padfProjParms, int *panParmIds, 
-                             int nTargetId, CPL_UNUSED double dfFromGreenwich )
-
+static double OGR_FetchParm( double *padfProjParms,
+                             int *panParmIds,
+                             int nTargetId,
+                             CPL_UNUSED double dfFromGreenwich )
 {
     int i;
     double dfResult;
@@ -1341,7 +1369,7 @@ static double OGR_FetchParm( double *padfProjParms, int *panParmIds,
       case PseudoStdParallelScaleFactor:
         dfResult = 1.0;
         break;
-        
+
       case AngleRectifiedToSkewedGrid:
         dfResult = 90.0;
         break;
@@ -1615,6 +1643,7 @@ static OGRErr SetEPSGProjCS( OGRSpatialReference * poSRS, int nPCSCode )
         break;
 
       case 9823: /* Equidistant Cylindrical / Plate Carre / Equirectangular */
+      case 9842:
       case 1028:
       case 1029:
         poSRS->SetEquirectangular( OGR_FP( NatOriginLat ),
@@ -1697,13 +1726,6 @@ static OGRErr SetEPSGVertCS( OGRSpatialReference * poSRS, int nVertCSCode )
         CSLGetField( papszRecord,
                      CSVGetFileFieldId(pszFilename,
                                        "DATUM_NAME")) );
-/* -------------------------------------------------------------------- */
-/*      Setup the VERT_DATUM node.                                      */
-/* -------------------------------------------------------------------- */
-    poSRS->SetAuthority( "VERT_CS|VERT_DATUM", "EPSG",
-                         atoi(CSLGetField( papszRecord,
-                                           CSVGetFileFieldId(pszFilename,
-                                                             "DATUM_CODE"))) );
 
 /* -------------------------------------------------------------------- */
 /*      Should we add a geoidgrids extension node?                      */
@@ -1719,7 +1741,15 @@ static OGRErr SetEPSGVertCS( OGRSpatialReference * poSRS, int nVertCSCode )
 
         poSRS->SetExtension( "VERT_CS|VERT_DATUM", "PROJ4_GRIDS", pszParm11 );
     }
-    
+
+/* -------------------------------------------------------------------- */
+/*      Setup the VERT_DATUM node.                                      */
+/* -------------------------------------------------------------------- */
+    poSRS->SetAuthority( "VERT_CS|VERT_DATUM", "EPSG",
+                         atoi(CSLGetField( papszRecord,
+                                           CSVGetFileFieldId(pszFilename,
+                                                             "DATUM_CODE"))) );
+
 /* -------------------------------------------------------------------- */
 /*      Set linear units.                                               */
 /* -------------------------------------------------------------------- */
@@ -1988,7 +2018,7 @@ static OGRErr SetEPSGGeocCS( OGRSpatialReference * poSRS, int nGCSCode )
 
         for( int iCoeff = 0; iCoeff < 7; iCoeff++ )
         {
-            sprintf( szValue, "%g", adfBursaTransform[iCoeff] );
+            CPLsprintf( szValue, "%g", adfBursaTransform[iCoeff] );
             poWGS84->AddChild( new OGR_SRSNode( szValue ) );
         }
 
@@ -2156,7 +2186,6 @@ OGRErr OGRSpatialReference::importFromEPSGA( int nCode )
 
 {
     OGRErr  eErr;
-    CPLLocaleC  oLocaleForcer;
 
     bNormInfoSet = FALSE;
 
@@ -2768,4 +2797,3 @@ int OSREPSGTreatsAsNorthingEasting( OGRSpatialReferenceH hSRS )
 
     return ((OGRSpatialReference *) hSRS)->EPSGTreatsAsNorthingEasting();
 }
-
diff --git a/ogr/ogr_geocoding.cpp b/ogr/ogr_geocoding.cpp
index b44ba0b..b29e76d 100644
--- a/ogr/ogr_geocoding.cpp
+++ b/ogr/ogr_geocoding.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_geocoding.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogr_geocoding.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Client of geocoding service.
@@ -77,7 +77,7 @@ int OGR_gettimeofday(struct timeval *tv, struct timezone *tzIgnored)
 #include "ogr_mem.h"
 #include "ogrsf_frmts.h"
 
-CPL_CVSID("$Id: ogr_geocoding.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogr_geocoding.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 struct _OGRGeocodingSessionHS
 {
@@ -96,7 +96,7 @@ struct _OGRGeocodingSessionHS
     OGRDataSource* poDS;
 };
 
-static void* hMutex = NULL;
+static CPLMutex* hMutex = NULL;
 static double dfLastQueryTimeStampOSMNominatim = 0.0;
 static double dfLastQueryTimeStampMapQuestNominatim = 0.0;
 
@@ -202,7 +202,7 @@ int OGRGeocodeHasStringValidFormat(const char* pszQueryTemplate)
  *      <a href="http://msdn.microsoft.com/en-us/library/ff701714.aspx">"BING"</a> or
  *       other value.
  *      Note: "YAHOO" is no longer available as a free service.
- * <li> "EMAIL": used by OSM_NOMINATIM. Optional, but recommanded.
+ * <li> "EMAIL": used by OSM_NOMINATIM. Optional, but recommended.
  * <li> "USERNAME": used by GEONAMES. Compulsory in that case.
  * <li> "KEY": used by BING. Compulsory in that case.
  * <li> "APPLICATION": used to set the User-Agent MIME header. Defaults
diff --git a/ogr/ogr_geometry.h b/ogr/ogr_geometry.h
index 9890575..cfbcfc1 100644
--- a/ogr/ogr_geometry.h
+++ b/ogr/ogr_geometry.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_geometry.h 27088 2014-03-24 23:18:08Z bishop $
+ * $Id: ogr_geometry.h 28123 2014-12-10 19:27:55Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Classes for manipulating simple features that is not specific
@@ -51,6 +51,8 @@ class OGRRawPoint
           {
                   x = y = 0.0;
           }
+
+          OGRRawPoint(double x, double y) : x(x), y(y) {}
     double      x;
     double      y;
 };
@@ -58,12 +60,29 @@ class OGRRawPoint
 typedef struct GEOSGeom_t *GEOSGeom;
 typedef struct GEOSContextHandle_HS *GEOSContextHandle_t;
 
+class OGRPoint;
+class OGRCurve;
+class OGRCompoundCurve;
+class OGRLinearRing;
+class OGRLineString;
+class OGRSurface;
+class OGRCurvePolygon;
+class OGRPolygon;
+class OGRMultiSurface;
+class OGRMultiPolygon;
+class OGRMultiCurve;
+class OGRMultiLineString;
+
+typedef OGRLineString* (*OGRCurveCasterToLineString)(OGRCurve*);
+typedef OGRLinearRing* (*OGRCurveCasterToLinearRing)(OGRCurve*);
+
+typedef OGRPolygon*      (*OGRSurfaceCasterToPolygon)(OGRSurface*);
+typedef OGRCurvePolygon* (*OGRSurfaceCasterToCurvePolygon)(OGRSurface*);
+
 /************************************************************************/
 /*                             OGRGeometry                              */
 /************************************************************************/
 
-class OGRPoint;
-
 /**
  * Abstract base class for all geometry classes.
  *
@@ -72,7 +91,13 @@ class OGRPoint;
  * between geometries is described in the SFCOM, or other simple features interface
  * specifications, like "OpenGIS® Implementation Specification for
  * Geographic information - Simple feature access - Part 1: Common architecture"
- * (<a href="http://www.opengeospatial.org/standards/sfa">OGC 06-103r3</a>)
+ * (<a href="http://www.opengeospatial.org/standards/sfa">OGC 06-103r4</a>)
+ *
+ * In GDAL 2.0, the hierarchy of classes has been extended with
+ * <a href="https://portal.opengeospatial.org/files/?artifact_id=32024">
+ * (working draft) ISO SQL/MM Part 3 (ISO/IEC 13249-3)</a> curve geometries :
+ * CIRCULARSTRING (OGRCircularString), COMPOUNDCURVE (OGRCompoundCurve),
+ * CURVEPOLYGON (OGRCurvePolygon), MULTICURVE (OGRMultiCurve) and MULTISURFACE (OGRMultiSurface).
  *
  */
  
@@ -82,9 +107,31 @@ class CPL_DLL OGRGeometry
     OGRSpatialReference * poSRS;                // may be NULL
 
   protected:
+    friend class OGRCurveCollection;
+
     int                   nCoordDimension;
-    int getIsoGeometryType() const;
-    
+
+    OGRErr                importPreambuleFromWkt( char ** ppszInput,
+                                                  int* pbHasZ, int* pbHasM );
+    OGRErr                importCurveCollectionFromWkt( char ** ppszInput,
+                                                  int bAllowEmptyComponent,
+                                                  int bAllowLineString,
+                                                  int bAllowCurve,
+                                                  int bAllowCompoundCurve,
+                                                  OGRErr (*pfnAddCurveDirectly)(OGRGeometry* poSelf, OGRCurve* poCurve) );
+    OGRErr                importPreambuleFromWkb( unsigned char * pabyData,
+                                                  int nSize,
+                                                  OGRwkbByteOrder& eByteOrder,
+                                                  OGRBoolean& b3D,
+                                                  OGRwkbVariant eWkbVariant );
+    OGRErr                importPreambuleOfCollectionFromWkb(
+                                                        unsigned char * pabyData,
+                                                        int& nSize,
+                                                        int& nDataOffset,
+                                                        OGRwkbByteOrder& eByteOrder,
+                                                        int nMinSubGeomSize,
+                                                        int& nGeomCount,
+                                                        OGRwkbVariant eWkbVariant );
   public:
                 OGRGeometry();
     virtual     ~OGRGeometry();
@@ -103,13 +150,14 @@ class CPL_DLL OGRGeometry
 
     // IWks Interface
     virtual int WkbSize() const = 0;
-    virtual OGRErr importFromWkb( unsigned char *, int=-1 )=0;
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const = 0;
+    virtual OGRErr importFromWkb( unsigned char *, int=-1, OGRwkbVariant=wkbVariantOldOgc )=0;
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const = 0;
     virtual OGRErr importFromWkt( char ** ppszInput ) = 0;
-    virtual OGRErr exportToWkt( char ** ppszDstText ) const = 0;
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const = 0;
     
     // non-standard
     virtual OGRwkbGeometryType getGeometryType() const = 0;
+    OGRwkbGeometryType    getIsoGeometryType() const;
     virtual const char *getGeometryName() const = 0;
     virtual void   dumpReadable( FILE *, const char * = NULL, char** papszOptions = NULL ) const;
     virtual void   flattenTo2D() = 0;
@@ -120,6 +168,10 @@ class CPL_DLL OGRGeometry
     static GEOSContextHandle_t createGEOSContext();
     static void freeGEOSContext(GEOSContextHandle_t hGEOSCtxt);
     virtual GEOSGeom exportToGEOS(GEOSContextHandle_t hGEOSCtxt) const;
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
+                                             const char* const* papszOptions = NULL) const;
 
     virtual void closeRings();
 
@@ -134,7 +186,7 @@ class CPL_DLL OGRGeometry
     virtual void segmentize(double dfMaxLength);
 
     // ISpatialRelation
-    virtual OGRBoolean  Intersects( OGRGeometry * ) const;
+    virtual OGRBoolean  Intersects( const OGRGeometry * ) const;
     virtual OGRBoolean  Equals( OGRGeometry * ) const = 0;
     virtual OGRBoolean  Disjoint( const OGRGeometry * ) const;
     virtual OGRBoolean  Touches( const OGRGeometry * ) const;
@@ -169,6 +221,9 @@ class CPL_DLL OGRGeometry
     static int bGenerate_DB2_V72_BYTE_ORDER;
 
     virtual void        swapXY();
+    
+    static OGRGeometry* CastToIdentity(OGRGeometry* poGeom) { return poGeom; }
+    static OGRGeometry* CastToError(OGRGeometry* poGeom);
 };
 
 /************************************************************************/
@@ -195,13 +250,14 @@ class CPL_DLL OGRPoint : public OGRGeometry
 
     // IWks Interface
     virtual int WkbSize() const;
-    virtual OGRErr importFromWkb( unsigned char *, int=-1 );
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const;
+    virtual OGRErr importFromWkb( unsigned char *, int=-1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ppszDstText ) const;
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
     
     // IGeometry
     virtual int getDimension() const;
+    virtual int getCoordinateDimension() const;
     virtual OGRGeometry *clone() const;
     virtual void empty();
     virtual void getEnvelope( OGREnvelope * psEnvelope ) const;
@@ -215,12 +271,14 @@ class CPL_DLL OGRPoint : public OGRGeometry
 
     // Non standard
     virtual void setCoordinateDimension( int nDimension ); 
-    void        setX( double xIn ) { x = xIn; if (nCoordDimension == 0) nCoordDimension = 2; }
-    void        setY( double yIn ) { y = yIn; if (nCoordDimension == 0) nCoordDimension = 2; }
+    void        setX( double xIn ) { x = xIn; if (nCoordDimension <= 0) nCoordDimension = 2; }
+    void        setY( double yIn ) { y = yIn; if (nCoordDimension <= 0) nCoordDimension = 2; }
     void        setZ( double zIn ) { z = zIn; nCoordDimension=3; }
 
     // ISpatialRelation
     virtual OGRBoolean  Equals( OGRGeometry * ) const;
+    virtual OGRBoolean  Intersects( const OGRGeometry * ) const;
+    virtual OGRBoolean  Within( const OGRGeometry * ) const;
     
     // Non standard from OGRGeometry
     virtual const char *getGeometryName() const;
@@ -232,38 +290,88 @@ class CPL_DLL OGRPoint : public OGRGeometry
 };
 
 /************************************************************************/
+/*                            OGRPointIterator                          */
+/************************************************************************/
+
+/**
+ * Interface for a point iterator.
+ *
+ * @since GDAL 2.0
+ */
+
+class CPL_DLL OGRPointIterator
+{
+    public:
+        virtual ~OGRPointIterator();
+        virtual OGRBoolean getNextPoint(OGRPoint* p) = 0;
+
+        static void destroy(OGRPointIterator*);
+};
+
+/************************************************************************/
 /*                               OGRCurve                               */
 /************************************************************************/
 
 /**
- * Abstract curve base class.
+ * Abstract curve base class for OGRLineString, OGRCircularString and
+ * OGRCompoundCurve
  */
 
 class CPL_DLL OGRCurve : public OGRGeometry
 {
-  public:
+  protected:
             OGRCurve();
+
+    virtual OGRCurveCasterToLineString GetCasterToLineString() const = 0;
+    virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const = 0;
+
+    friend class OGRCurvePolygon;
+    friend class OGRCompoundCurve;
+    virtual int    ContainsPoint( const OGRPoint* p ) const;
+    virtual double get_AreaOfCurveSegments() const = 0;
+
+  public:
     virtual ~OGRCurve();
+
     // ICurve methods
     virtual double get_Length() const = 0;
     virtual void StartPoint(OGRPoint *) const = 0;
     virtual void EndPoint(OGRPoint *) const = 0;
     virtual int  get_IsClosed() const;
     virtual void Value( double, OGRPoint * ) const = 0;
+    virtual OGRLineString* CurveToLine(double dfMaxAngleStepSizeDegrees = 0,
+                                       const char* const* papszOptions = NULL) const = 0;
+    virtual int getDimension() const;
+
+    // non standard
+    virtual int getNumPoints() const = 0;
+    virtual OGRPointIterator* getPointIterator() const = 0;
+    virtual OGRBoolean IsConvex() const;
+    virtual double get_Area() const = 0;
 
+    static OGRCompoundCurve* CastToCompoundCurve(OGRCurve* puCurve);
+    static OGRLineString*    CastToLineString(OGRCurve* poCurve);
+    static OGRLinearRing*    CastToLinearRing(OGRCurve* poCurve);
 };
 
 /************************************************************************/
-/*                            OGRLineString                             */
+/*                             OGRSimpleCurve                           */
 /************************************************************************/
 
 /**
- * Concrete representation of a multi-vertex line.
+ * Abstract curve base class for OGRLineString and OGRCircularString
+ *
+ * Note: this class does not exist in SQL/MM standard and exists for
+ * implementation convenience.
+ *
+ * @since GDAL 2.0
  */
 
-class CPL_DLL OGRLineString : public OGRCurve
+class CPL_DLL OGRSimpleCurve: public OGRCurve
 {
   protected:
+    friend class OGRGeometry;
+
     int         nPointCount;
     OGRRawPoint *paoPoints;
     double      *padfZ;
@@ -271,19 +379,25 @@ class CPL_DLL OGRLineString : public OGRCurve
     void        Make3D();
     void        Make2D();
 
+    OGRErr      importFromWKTListOnly( char ** ppszInput, int bHasZ, int bHasM,
+                                       OGRRawPoint*& paoPointsIn, int& nMaxPoints,
+                                       double*& padfZIn );
+
+    virtual double get_LinearArea() const;
+
+                OGRSimpleCurve();
+
   public:
-                OGRLineString();
-    virtual     ~OGRLineString();
+    virtual     ~OGRSimpleCurve();
 
     // IWks Interface
     virtual int WkbSize() const;
-    virtual OGRErr importFromWkb( unsigned char *, int = -1 );
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const;
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ppszDstText ) const;
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
 
     // IGeometry interface
-    virtual int getDimension() const;
     virtual OGRGeometry *clone() const;
     virtual void empty();
     virtual void getEnvelope( OGREnvelope * psEnvelope ) const;
@@ -297,9 +411,9 @@ class CPL_DLL OGRLineString : public OGRCurve
     virtual void Value( double, OGRPoint * ) const;
     virtual double Project(const OGRPoint *) const;
     virtual OGRLineString* getSubLine(double, double, int) const;
-    
+
     // ILineString methods
-    int         getNumPoints() const { return nPointCount; }
+    virtual int getNumPoints() const { return nPointCount; }
     void        getPoint( int, OGRPoint * ) const;
     double      getX( int i ) const { return paoPoints[i].x; }
     double      getY( int i ) const { return paoPoints[i].y; }
@@ -317,7 +431,7 @@ class CPL_DLL OGRLineString : public OGRCurve
     void        setPoint( int, double, double, double );
     void        setPoints( int, OGRRawPoint *, double * = NULL );
     void        setPoints( int, double * padfX, double * padfY,
-                           double *padfZ = NULL );
+                           double *padfZIn = NULL );
     void        addPoint( OGRPoint * );
     void        addPoint( double, double );
     void        addPoint( double, double, double );
@@ -330,10 +444,9 @@ class CPL_DLL OGRLineString : public OGRCurve
     void        addSubLineString( const OGRLineString *, 
                                   int nStartVertex = 0, int nEndVertex = -1 );
     void        reversePoints( void );
+    virtual OGRPointIterator* getPointIterator() const;
 
     // non-standard from OGRGeometry
-    virtual OGRwkbGeometryType getGeometryType() const;
-    virtual const char *getGeometryName() const;
     virtual OGRErr  transform( OGRCoordinateTransformation *poCT );
     virtual void flattenTo2D();
     virtual void segmentize(double dfMaxLength);
@@ -342,6 +455,45 @@ class CPL_DLL OGRLineString : public OGRCurve
 };
 
 /************************************************************************/
+/*                            OGRLineString                             */
+/************************************************************************/
+
+/**
+ * Concrete representation of a multi-vertex line.
+ *
+ * Note: for implementation convenience, we make it inherit from OGRSimpleCurve whereas
+ * SFSQL and SQL/MM only make it inherits from OGRCurve.
+ */
+
+class CPL_DLL OGRLineString : public OGRSimpleCurve
+{
+  protected:
+    static OGRLineString* TransferMembersAndDestroy(
+                                            OGRLineString* poSrc,
+                                            OGRLineString* poDst);
+
+    static OGRLinearRing* CastToLinearRing(OGRLineString* poLS);
+
+    virtual OGRCurveCasterToLineString GetCasterToLineString() const;
+    virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const;
+
+    virtual double get_AreaOfCurveSegments() const;
+
+  public:
+                OGRLineString();
+    virtual    ~OGRLineString();
+
+    virtual OGRLineString* CurveToLine(double dfMaxAngleStepSizeDegrees = 0,
+                                       const char* const* papszOptions = NULL) const;
+    virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;
+    virtual double get_Area() const;
+
+    // non-standard from OGRGeometry
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual const char *getGeometryName() const;
+};
+
+/************************************************************************/
 /*                            OGRLinearRing                             */
 /************************************************************************/
 
@@ -361,11 +513,13 @@ class CPL_DLL OGRLineString : public OGRCurve
  * cannot genearally be used with GEOS for operations like Intersects(). 
  * Instead the polygon should be used, or the OGRLinearRing should be
  * converted to an OGRLineString for such operations. 
+ *
+ * Note: this class exists in SFSQL 1.2, but not in ISO SQL/MM Part 3.
  */
 
 class CPL_DLL OGRLinearRing : public OGRLineString
 {
-  private:
+  protected:
     friend class OGRPolygon; 
     
     // These are not IWks compatible ... just a convenience for OGRPolygon.
@@ -375,10 +529,15 @@ class CPL_DLL OGRLinearRing : public OGRLineString
     virtual OGRErr _exportToWkb( OGRwkbByteOrder, int b3D, 
                                  unsigned char * ) const;
     
+    static OGRLineString* CastToLineString(OGRLinearRing* poLR);
+
+    virtual OGRCurveCasterToLineString GetCasterToLineString() const;
+    virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const;
+
   public:
                         OGRLinearRing();
                         OGRLinearRing( OGRLinearRing * );
-                        ~OGRLinearRing();
+    virtual            ~OGRLinearRing();
 
     // Non standard.
     virtual const char *getGeometryName() const;
@@ -386,7 +545,6 @@ class CPL_DLL OGRLinearRing : public OGRLineString
     virtual int isClockwise() const;
     virtual void reverseWindingOrder();
     virtual void closeRings();
-    virtual double get_Area() const;
     OGRBoolean isPointInRing(const OGRPoint* pt, int bTestEnvelope = TRUE) const;
     OGRBoolean isPointOnRingBoundary(const OGRPoint* pt, int bTestEnvelope = TRUE) const;
     
@@ -394,8 +552,229 @@ class CPL_DLL OGRLinearRing : public OGRLineString
     // for the purposes of WKB form.  These methods always fail since this
     // object cant be serialized on its own. 
     virtual int WkbSize() const;
-    virtual OGRErr importFromWkb( unsigned char *, int=-1 );
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const;
+    virtual OGRErr importFromWkb( unsigned char *, int=-1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
+};
+
+/************************************************************************/
+/*                         OGRCircularString                            */
+/************************************************************************/
+
+/**
+ * Concrete representation of a circular string, that is to say a curve made
+ * of one or several arc circles.
+ *
+ * Note: for implementation convenience, we make it inherit from OGRSimpleCurve whereas
+ * SQL/MM only makes it inherits from OGRCurve.
+ *
+ * Compatibility: ISO SQL/MM Part 3.
+ *
+ * @since GDAL 2.0
+ */
+
+class CPL_DLL OGRCircularString : public OGRSimpleCurve
+{
+  private:
+    void        ExtendEnvelopeWithCircular( OGREnvelope * psEnvelope ) const;
+    OGRBoolean  IsValidFast() const;
+    int         IsFullCircle( double& cx, double& cy, double& square_R ) const;
+
+  protected:
+    virtual OGRCurveCasterToLineString GetCasterToLineString() const;
+    virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const;
+    virtual int    ContainsPoint( const OGRPoint* p ) const;
+    virtual double get_AreaOfCurveSegments() const;
+
+  public:
+                OGRCircularString();
+    virtual    ~OGRCircularString();
+
+    // IWks Interface
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
+    virtual OGRErr importFromWkt( char ** );
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
+
+    // IGeometry interface
+    virtual OGRBoolean  IsValid() const;
+    virtual void getEnvelope( OGREnvelope * psEnvelope ) const;
+    virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const;
+
+    // ICurve methods
+    virtual double get_Length() const;
+    virtual OGRLineString* CurveToLine(double dfMaxAngleStepSizeDegrees = 0,
+                                       const char* const* papszOptions = NULL) const;
+    virtual void Value( double, OGRPoint * ) const;
+    virtual double get_Area() const;
+
+    // non-standard from OGRGeometry
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual const char *getGeometryName() const;
+    virtual void segmentize(double dfMaxLength);
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
+                                             const char* const* papszOptions = NULL) const;
+};
+
+/************************************************************************/
+/*                           OGRCurveCollection                         */
+/************************************************************************/
+
+/**
+ * Utility class to store a collection of curves. Used as a member of
+ * OGRCompoundCurve and OGRCurvePolygon.
+ *
+ * This class is only exported because of linking issues. It should never
+ * be directly used.
+ *
+ * @since GDAL 2.0
+ */
+
+class CPL_DLL OGRCurveCollection
+{
+  protected:
+    friend class OGRCompoundCurve;
+    friend class OGRCurvePolygon;
+    friend class OGRPolygon;
+
+    int         nCurveCount;
+    OGRCurve  **papoCurves;
+
+  public:
+                OGRCurveCollection();
+               ~OGRCurveCollection();
+
+    void            empty(OGRGeometry* poGeom);
+    OGRBoolean      IsEmpty() const;
+    void            getEnvelope( OGREnvelope * psEnvelope ) const;
+    void            getEnvelope( OGREnvelope3D * psEnvelope ) const;
+
+    OGRErr          addCurveDirectly( OGRGeometry* poGeom, OGRCurve* poCurve,
+                                      int bNeedRealloc );
+    int             WkbSize() const;
+    OGRErr          importPreambuleFromWkb( OGRGeometry* poGeom,
+                                            unsigned char * pabyData,
+                                            int& nSize,
+                                            int& nDataOffset,
+                                            OGRwkbByteOrder& eByteOrder,
+                                            int nMinSubGeomSize,
+                                            OGRwkbVariant eWkVariant );
+    OGRErr          importBodyFromWkb( OGRGeometry* poGeom,
+                                       unsigned char * pabyData,
+                                       int nSize,
+                                       int nDataOffset,
+                                       int bAcceptCompoundCurve,
+                                       OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry* poGeom, OGRCurve* poCurve),
+                                       OGRwkbVariant eWkVariant );
+    OGRErr          exportToWkt( const OGRGeometry* poGeom, char ** ppszDstText ) const;
+    OGRErr          exportToWkb( const OGRGeometry* poGeom, OGRwkbByteOrder,
+                                 unsigned char *, OGRwkbVariant eWkbVariant ) const;
+    OGRBoolean      Equals(OGRCurveCollection *poOCC) const;
+    void            setCoordinateDimension( OGRGeometry* poGeom, int nNewDimension );
+    int             getNumCurves() const;
+    OGRCurve       *getCurve( int );
+    const OGRCurve *getCurve( int ) const;
+    OGRCurve       *stealCurve( int );
+    OGRErr          transform( OGRGeometry* poGeom,
+                               OGRCoordinateTransformation *poCT );
+    void            flattenTo2D(OGRGeometry* poGeom);
+    void            segmentize(double dfMaxLength);
+    void            swapXY();
+    OGRBoolean      hasCurveGeometry(int bLookForNonLinear) const;
+};
+
+/************************************************************************/
+/*                            OGRCompoundCurve                          */
+/************************************************************************/
+
+/**
+ * Concrete representation of a compound curve, made of curves: OGRLineString
+ * and OGRCircularString. Each curve is connected by its first point to
+ * the last point of the previous curve.
+ *
+ * Compatibility: ISO SQL/MM Part 3.
+ *
+ * @since GDAL 2.0
+ */
+
+class CPL_DLL OGRCompoundCurve : public OGRCurve
+{
+  private:
+    OGRCurveCollection oCC;
+
+    OGRErr      addCurveDirectlyInternal( OGRCurve* poCurve,
+                                          double dfToleranceEps,
+                                          int bNeedRealloc );
+    static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve );
+    static OGRErr addCurveDirectlyFromWkb( OGRGeometry* poSelf, OGRCurve* poCurve );
+    OGRLineString* CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
+                                       const char* const* papszOptions,
+                                       int bIsLinearRing) const;
+
+  protected:
+    static OGRLineString* CastToLineString(OGRCompoundCurve* poCC);
+    static OGRLinearRing* CastToLinearRing(OGRCompoundCurve* poCC);
+
+    virtual OGRCurveCasterToLineString GetCasterToLineString() const;
+    virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const;
+
+  public:
+                OGRCompoundCurve();
+    virtual     ~OGRCompoundCurve();
+
+    // IWks Interface
+    virtual int WkbSize() const;
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
+    virtual OGRErr importFromWkt( char ** );
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
+
+    // IGeometry interface
+    virtual OGRGeometry *clone() const;
+    virtual void empty();
+    virtual void getEnvelope( OGREnvelope * psEnvelope ) const;
+    virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const;
+    virtual OGRBoolean  IsEmpty() const;
+
+    // ICurve methods
+    virtual double get_Length() const;
+    virtual void StartPoint(OGRPoint *) const;
+    virtual void EndPoint(OGRPoint *) const;
+    virtual void Value( double, OGRPoint * ) const;
+    virtual OGRLineString* CurveToLine(double dfMaxAngleStepSizeDegrees = 0,
+                                       const char* const* papszOptions = NULL) const;
+    
+    virtual int getNumPoints() const;
+    virtual double get_AreaOfCurveSegments() const;
+    virtual double get_Area() const;
+
+    // ISpatialRelation
+    virtual OGRBoolean  Equals( OGRGeometry * ) const;
+
+    // ICompoundCurve method
+    int             getNumCurves() const;
+    OGRCurve       *getCurve( int );
+    const OGRCurve *getCurve( int ) const;
+    
+    // non standard.
+    virtual void setCoordinateDimension( int nDimension ); 
+        
+    OGRErr         addCurve( OGRCurve*, double dfToleranceEps = 1e-14  );
+    OGRErr         addCurveDirectly( OGRCurve*, double dfToleranceEps = 1e-14 );
+    OGRCurve      *stealCurve( int );
+    virtual OGRPointIterator* getPointIterator() const;
+
+    // non-standard from OGRGeometry
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual const char *getGeometryName() const;
+    virtual OGRErr  transform( OGRCoordinateTransformation *poCT );
+    virtual void flattenTo2D();
+    virtual void segmentize(double dfMaxLength);
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
+                                             const char* const* papszOptions = NULL) const;
+
+    virtual void        swapXY();
 };
 
 /************************************************************************/
@@ -403,37 +782,63 @@ class CPL_DLL OGRLinearRing : public OGRLineString
 /************************************************************************/
 
 /**
- * Abstract base class for 2 dimensional objects like polygons.
+ * Abstract base class for 2 dimensional objects like polygons or curve polygons.
  */
 
 class CPL_DLL OGRSurface : public OGRGeometry
 {
+  protected:
+
+    virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon() const = 0;
+    virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon() const = 0;
+
   public:
     virtual double      get_Area() const = 0;
     virtual OGRErr      PointOnSurface( OGRPoint * poPoint ) const = 0;
+
+    static OGRPolygon*      CastToPolygon(OGRSurface* poSurface);
+    static OGRCurvePolygon* CastToCurvePolygon(OGRSurface* poSurface);
 };
 
+
 /************************************************************************/
-/*                              OGRPolygon                              */
+/*                          OGRCurvePolygon                             */
 /************************************************************************/
 
 /**
- * Concrete class representing polygons.
+ * Concrete class representing curve polygons.
  *
- * Note that the OpenGIS simple features polygons consist of one outer
- * ring, and zero or more inner rings.  A polygon cannot represent disconnected
+ * Note that curve polygons consist of one outer (curve) ring, and zero or
+ * more inner rings.  A curve polygon cannot represent disconnected
  * regions (such as multiple islands in a political body).  The
- * OGRMultiPolygon must be used for this.
+ * OGRMultiSurface must be used for this.
+ *
+ * Compatibility: ISO SQL/MM Part 3.
+ *
+ * @since GDAL 2.0
  */
 
-class CPL_DLL OGRPolygon : public OGRSurface
+class CPL_DLL OGRCurvePolygon : public OGRSurface
 {
-    int         nRingCount;
-    OGRLinearRing **papoRings;
-    
+  private:
+    OGRBoolean      ContainsPoint( const OGRPoint* p ) const;
+    virtual int   checkRing( OGRCurve * poNewRing ) const;
+    OGRErr        addRingDirectlyInternal( OGRCurve* poCurve, int bNeedRealloc );
+    static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve );
+    static OGRErr addCurveDirectlyFromWkb( OGRGeometry* poSelf, OGRCurve* poCurve );
+
+  protected:
+    friend class OGRPolygon;
+    OGRCurveCollection oCC;
+
+    static OGRPolygon* CastToPolygon(OGRCurvePolygon* poCP);
+
+    virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon() const;
+    virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon() const;
+
   public:
-                OGRPolygon();
-    virtual     ~OGRPolygon();
+                OGRCurvePolygon();
+    virtual    ~OGRCurvePolygon();
 
     // Non standard (OGRGeometry).
     virtual const char *getGeometryName() const;
@@ -444,6 +849,9 @@ class CPL_DLL OGRPolygon : public OGRSurface
     virtual void flattenTo2D();
     virtual OGRBoolean  IsEmpty() const;
     virtual void segmentize(double dfMaxLength);
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
+                                             const char* const* papszOptions = NULL) const;
 
     // ISurface Interface
     virtual double      get_Area() const;
@@ -451,28 +859,98 @@ class CPL_DLL OGRPolygon : public OGRSurface
     
     // IWks Interface
     virtual int WkbSize() const;
-    virtual OGRErr importFromWkb( unsigned char *, int = -1 );
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const;
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ppszDstText ) const;
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant eWkbVariant = wkbVariantOldOgc ) const;
 
     // IGeometry
     virtual int getDimension() const;
     virtual void getEnvelope( OGREnvelope * psEnvelope ) const;
     virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const;
+    
+    // ICurvePolygon
+    virtual OGRPolygon* CurvePolyToPoly(double dfMaxAngleStepSizeDegrees = 0,
+                                        const char* const* papszOptions = NULL) const;
 
     // ISpatialRelation
     virtual OGRBoolean  Equals( OGRGeometry * ) const;
-    
+    virtual OGRBoolean  Intersects( const OGRGeometry * ) const;
+    virtual OGRBoolean  Contains( const OGRGeometry * ) const;
+
     // Non standard
     virtual void setCoordinateDimension( int nDimension ); 
 
-    void        addRing( OGRLinearRing * );
-    void        addRingDirectly( OGRLinearRing * );
+    OGRErr        addRing( OGRCurve * );
+    OGRErr        addRingDirectly( OGRCurve * );
+
+    OGRCurve *getExteriorRingCurve();
+    const OGRCurve *getExteriorRingCurve() const;
+    int         getNumInteriorRings() const;
+    OGRCurve *getInteriorRingCurve( int );
+    const OGRCurve *getInteriorRingCurve( int ) const;
+
+    OGRCurve *stealExteriorRingCurve();
+
+    virtual void        swapXY();
+};
+
+/************************************************************************/
+/*                              OGRPolygon                              */
+/************************************************************************/
+
+/**
+ * Concrete class representing polygons.
+ *
+ * Note that the OpenGIS simple features polygons consist of one outer
+ * ring (linearring), and zero or more inner rings.  A polygon cannot represent disconnected
+ * regions (such as multiple islands in a political body).  The
+ * OGRMultiPolygon must be used for this.
+ */
+
+class CPL_DLL OGRPolygon : public OGRCurvePolygon
+{
+  protected:
+    friend class OGRMultiSurface;
+
+    virtual int checkRing( OGRCurve * poNewRing ) const;
+    OGRErr      importFromWKTListOnly( char ** ppszInput, int bHasZ, int bHasM,
+                                       OGRRawPoint*& paoPoints, int& nMaxPoints,
+                                       double*& padfZ );
+
+    static OGRCurvePolygon* CastToCurvePolygon(OGRPolygon* poPoly);
+
+    virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon() const;
+    virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon() const;
+
+  public:
+                OGRPolygon();
+    virtual    ~OGRPolygon();
+
+    // Non standard (OGRGeometry).
+    virtual const char *getGeometryName() const;
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
+                                             const char* const* papszOptions = NULL) const;
+
+    // ISurface Interface
+    virtual int         PointOnSurface( OGRPoint * poPoint ) const;
+    
+    // IWks Interface
+    virtual int WkbSize() const;
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
+    virtual OGRErr importFromWkt( char ** );
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
+    
+    // ICurvePolygon
+    virtual OGRPolygon* CurvePolyToPoly(double dfMaxAngleStepSizeDegrees = 0,
+                                        const char* const* papszOptions = NULL) const;
 
     OGRLinearRing *getExteriorRing();
     const OGRLinearRing *getExteriorRing() const;
-    int         getNumInteriorRings() const;
     OGRLinearRing *getInteriorRing( int );
     const OGRLinearRing *getInteriorRing( int ) const;
 
@@ -482,8 +960,6 @@ class CPL_DLL OGRPolygon : public OGRSurface
     OGRBoolean IsPointOnSurface( const OGRPoint * ) const;
 
     virtual void closeRings();
-
-    virtual void        swapXY();
 };
 
 /************************************************************************/
@@ -499,11 +975,21 @@ class CPL_DLL OGRPolygon : public OGRSurface
 
 class CPL_DLL OGRGeometryCollection : public OGRGeometry
 {
+    OGRErr      importFromWkbInternal( unsigned char * pabyData, int nSize, int nRecLevel,
+                                       OGRwkbVariant );
+    OGRErr      importFromWktInternal( char **ppszInput, int nRecLevel );
+
+  protected:
     int         nGeomCount;
     OGRGeometry **papoGeoms;
 
-    OGRErr      importFromWkbInternal( unsigned char * pabyData, int nSize, int nRecLevel );
-    OGRErr      importFromWktInternal( char **ppszInput, int nRecLevel );
+    OGRErr                      exportToWktInternal( char ** ppszDstText,
+                                                     OGRwkbVariant eWkbVariant,
+                                                     const char* pszSkipPrefix ) const;
+    virtual OGRBoolean         isCompatibleSubType( OGRwkbGeometryType ) const;
+    
+    static OGRGeometryCollection* TransferMembersAndDestroy(OGRGeometryCollection* poSrc,
+                                                  OGRGeometryCollection* poDst);
 
   public:
                 OGRGeometryCollection();
@@ -518,13 +1004,16 @@ class CPL_DLL OGRGeometryCollection : public OGRGeometry
     virtual void flattenTo2D();
     virtual OGRBoolean  IsEmpty() const;
     virtual void segmentize(double dfMaxLength);
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;
+    virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0, const char* const* papszOptions = NULL) const;
 
     // IWks Interface
     virtual int WkbSize() const;
-    virtual OGRErr importFromWkb( unsigned char *, int = -1 );
-    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOgc ) const;
+    virtual OGRErr importFromWkb( unsigned char *, int = -1, OGRwkbVariant=wkbVariantOldOgc );
+    virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *, OGRwkbVariant=wkbVariantOldOgc ) const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ppszDstText ) const;
+    virtual OGRErr exportToWkt( char ** ppszDstText, OGRwkbVariant=wkbVariantOldOgc ) const;
 
     virtual double get_Length() const;
     virtual double get_Area() const;
@@ -554,34 +1043,71 @@ class CPL_DLL OGRGeometryCollection : public OGRGeometry
 };
 
 /************************************************************************/
-/*                           OGRMultiPolygon                            */
+/*                          OGRMultiSurface                             */
 /************************************************************************/
 
 /**
- * A collection of non-overlapping OGRPolygons.
+ * A collection of non-overlapping OGRSurface.
  *
- * Note that the IMultiSurface class hasn't been modelled, nor have any
- * of it's methods. 
+ * @since GDAL 2.0
  */
 
-class CPL_DLL OGRMultiPolygon : public OGRGeometryCollection
+class CPL_DLL OGRMultiSurface : public OGRGeometryCollection
 {
+  protected:
+    virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType ) const;
+
   public:
-            OGRMultiPolygon();
+            OGRMultiSurface();
+    virtual ~OGRMultiSurface();
+
     // Non standard (OGRGeometry).
     virtual const char *getGeometryName() const;
     virtual OGRwkbGeometryType getGeometryType() const;
-    virtual OGRGeometry *clone() const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ) const;
+    virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc ) const;
+    
+    // IMultiSurface methods
+    virtual OGRErr      PointOnSurface( OGRPoint * poPoint ) const;
 
     // IGeometry methods
     virtual int getDimension() const;
 
     // Non standard
-    virtual OGRErr addGeometryDirectly( OGRGeometry * );
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
 
-    virtual double  get_Area() const;
+    static OGRMultiPolygon* CastToMultiPolygon(OGRMultiSurface* poMS);
+};
+
+/************************************************************************/
+/*                           OGRMultiPolygon                            */
+/************************************************************************/
+
+/**
+ * A collection of non-overlapping OGRPolygon.
+ */
+
+class CPL_DLL OGRMultiPolygon : public OGRMultiSurface
+{
+  protected:
+    virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType ) const;
+
+  public:
+            OGRMultiPolygon();
+    virtual ~OGRMultiPolygon();
+
+    // Non standard (OGRGeometry).
+    virtual const char *getGeometryName() const;
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc ) const;
+    
+    // IMultiSurface methods
+    virtual OGRErr      PointOnSurface( OGRPoint * poPoint ) const;
+
+    // Non standard
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+    
+    static OGRMultiSurface* CastToMultiSurface(OGRMultiPolygon* poMP);
 };
 
 /************************************************************************/
@@ -589,7 +1115,7 @@ class CPL_DLL OGRMultiPolygon : public OGRGeometryCollection
 /************************************************************************/
 
 /**
- * A collection of OGRPoints.
+ * A collection of OGRPoint.
  */
 
 class CPL_DLL OGRMultiPoint : public OGRGeometryCollection
@@ -597,47 +1123,87 @@ class CPL_DLL OGRMultiPoint : public OGRGeometryCollection
   private:
     OGRErr  importFromWkt_Bracketed( char **, int bHasM, int bHasZ );
 
+  protected:
+    virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType ) const;
+
   public:
             OGRMultiPoint();
+    virtual ~OGRMultiPoint();
+
     // Non standard (OGRGeometry).
     virtual const char *getGeometryName() const;
     virtual OGRwkbGeometryType getGeometryType() const;
-    virtual OGRGeometry *clone() const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ) const;
+    virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc ) const;
 
     // IGeometry methods
     virtual int getDimension() const;
 
     // Non standard
-    virtual OGRErr addGeometryDirectly( OGRGeometry * );
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
 };
 
 /************************************************************************/
-/*                          OGRMultiLineString                          */
+/*                          OGRMultiCurve                               */
 /************************************************************************/
 
 /**
- * A collection of OGRLineStrings.
+ * A collection of OGRCurve.
+ *
+ * @since GDAL 2.0
  */
 
-class CPL_DLL OGRMultiLineString : public OGRGeometryCollection
+class CPL_DLL OGRMultiCurve : public OGRGeometryCollection
 {
+  protected:
+    static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve );
+    virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType ) const;
+
   public:
-            OGRMultiLineString();
-            ~OGRMultiLineString();
+            OGRMultiCurve();
+    virtual ~OGRMultiCurve();
+
     // Non standard (OGRGeometry).
     virtual const char *getGeometryName() const;
     virtual OGRwkbGeometryType getGeometryType() const;
-    virtual OGRGeometry *clone() const;
     virtual OGRErr importFromWkt( char ** );
-    virtual OGRErr exportToWkt( char ** ) const;
+    virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc ) const;
 
     // IGeometry methods
     virtual int getDimension() const;
     
     // Non standard
-    virtual OGRErr addGeometryDirectly( OGRGeometry * );
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+
+    static OGRMultiLineString* CastToMultiLineString(OGRMultiCurve* poMC);
+};
+
+/************************************************************************/
+/*                          OGRMultiLineString                          */
+/************************************************************************/
+
+/**
+ * A collection of OGRLineString.
+ */
+
+class CPL_DLL OGRMultiLineString : public OGRMultiCurve
+{
+  protected:
+    virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType ) const;
+
+  public:
+            OGRMultiLineString();
+    virtual ~OGRMultiLineString();
+
+    // Non standard (OGRGeometry).
+    virtual const char *getGeometryName() const;
+    virtual OGRwkbGeometryType getGeometryType() const;
+    virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc ) const;
+    
+    // Non standard
+    virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
+
+    static OGRMultiCurve* CastToMultiCurve(OGRMultiLineString* poMLS);
 };
 
 
@@ -659,7 +1225,7 @@ class CPL_DLL OGRGeometryFactory
                                          int nRecLevel );
   public:
     static OGRErr createFromWkb( unsigned char *, OGRSpatialReference *,
-                                 OGRGeometry **, int = -1 );
+                                 OGRGeometry **, int = -1, OGRwkbVariant=wkbVariantOldOgc );
     static OGRErr createFromWkt( char **, OGRSpatialReference *,
                                  OGRGeometry ** );
     static OGRErr createFromFgf( unsigned char *, OGRSpatialReference *,
@@ -675,6 +1241,10 @@ class CPL_DLL OGRGeometryFactory
     static OGRGeometry * forceToMultiPolygon( OGRGeometry * );
     static OGRGeometry * forceToMultiPoint( OGRGeometry * );
     static OGRGeometry * forceToMultiLineString( OGRGeometry * );
+    
+    static OGRGeometry * forceTo( OGRGeometry* poGeom,
+                                  OGRwkbGeometryType eTargetType,
+                                  const char*const* papszOptions = NULL );
 
     static OGRGeometry * organizePolygons( OGRGeometry **papoPolygons,
                                            int nPolygonCount,
@@ -692,6 +1262,20 @@ class CPL_DLL OGRGeometryFactory
                               double dfRotation, 
                               double dfStartAngle, double dfEndAngle,
                               double dfMaxAngleStepSizeDegrees );
+
+    static int GetCurveParmeters(double x0, double y0,
+                                 double x1, double y1,
+                                 double x2, double y2,
+                                 double& R, double& cx, double& cy,
+                                 double& alpha0, double& alpha1, double& alpha2 );
+    static OGRLineString* curveToLineString( double x0, double y0, double z0,
+                                             double x1, double y1, double z1,
+                                             double x2, double y2, double z2,
+                                             int bHasZ,
+                                             double dfMaxAngleStepSizeDegrees,
+                                             const char*const* papszOptions = NULL );
+    static OGRCurve* curveFromLineString(const OGRLineString* poLS,
+                                         const char*const* papszOptions = NULL);
 };
 
 OGRwkbGeometryType CPL_DLL OGRFromOGCGeomType( const char *pszGeomType );
diff --git a/ogr/ogr_geos.h b/ogr/ogr_geos.h
index edb546c..f9d24cf 100644
--- a/ogr/ogr_geos.h
+++ b/ogr/ogr_geos.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_geos.h 17469 2009-07-28 18:28:27Z warmerdam $
+ * $Id: ogr_geos.h 27483 2014-06-30 20:49:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Definitions related to support for use of GEOS in OGR.
@@ -33,6 +33,10 @@
 #define OGR_GEOS_H_INCLUDED
 
 #ifdef HAVE_GEOS 
+// To avoid accidental use of non reentrant GEOS API.
+// (check only effective in GEOS >= 3.5)
+#  define GEOS_USE_ONLY_R_API
+
 #  include <geos_c.h>
 #else
 
diff --git a/ogr/ogr_opt.cpp b/ogr/ogr_opt.cpp
index 383b203..e7c70c9 100644
--- a/ogr/ogr_opt.cpp
+++ b/ogr/ogr_opt.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_opt.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_opt.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OpenGIS Simple Features
  * Purpose:  Functions for getting list of projection types, and their parms.
@@ -31,7 +31,7 @@
 #include "ogr_srs_api.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogr_opt.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_opt.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 static const char *papszParameterDefinitions[] = {
     SRS_PP_CENTRAL_MERIDIAN,    "Central Meridian",     "Long",  "0.0",
@@ -468,6 +468,12 @@ static const char *papszProjectionDefinitions[] = {
     SRS_PP_FALSE_EASTING, 
     SRS_PP_FALSE_NORTHING,
 
+    "*",
+    SRS_PT_QSC,
+    "Quadrilateralized Spherical Cube",
+    SRS_PP_LATITUDE_OF_ORIGIN,
+    SRS_PP_CENTRAL_MERIDIAN,
+
     NULL
 };
 
@@ -603,7 +609,7 @@ int OPTGetParameterInfo( const char * pszProjectionMethod,
             if( ppszType != NULL )
                 *ppszType = (char *)papszParameterDefinitions[i+2];
             if( pdfDefaultValue != NULL )
-                *pdfDefaultValue = atof(papszParameterDefinitions[i+3]);
+                *pdfDefaultValue = CPLAtof(papszParameterDefinitions[i+3]);
 
             return TRUE;
         }
diff --git a/ogr/ogr_p.h b/ogr/ogr_p.h
index d97af45..69a4daf 100644
--- a/ogr/ogr_p.h
+++ b/ogr/ogr_p.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_p.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_p.h 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Some private helper functions and stuff for OGR implementation.
@@ -52,6 +52,16 @@
 #  define OGR_SWAP(x)   (x == wkbXDR)
 #endif
 
+/* PostGIS 1.X has non standard codes for the following geometry types */
+#define POSTGIS15_CURVEPOLYGON  13  /* instead of 10 */
+#define POSTGIS15_MULTICURVE    14  /* instead of 11 */
+#define POSTGIS15_MULTISURFACE  15  /* instead of 12 */
+
+/* Has been deprecated. Can only be used in very specific circumstances */
+#ifdef GDAL_COMPILATION
+#define wkb25DBitInternalUse 0x80000000
+#endif
+
 /* -------------------------------------------------------------------- */
 /*      helper function for parsing well known text format vector objects.*/
 /* -------------------------------------------------------------------- */
@@ -81,15 +91,11 @@ void OGRFormatDouble( char *pszBuffer, int nBufferLen, double dfVal, char chDeci
 /* they are compiled as plugins  */
 int CPL_DLL OGRGetDayOfWeek(int day, int month, int year);
 int CPL_DLL OGRParseXMLDateTime( const char* pszXMLDateTime,
-                               int *pnYear, int *pnMonth, int *pnDay,
-                               int *pnHour, int *pnMinute, float* pfSecond, int *pnTZ);
+                                 OGRField* psField );
 int CPL_DLL OGRParseRFC822DateTime( const char* pszRFC822DateTime,
-                                  int *pnYear, int *pnMonth, int *pnDay,
-                                  int *pnHour, int *pnMinute, int *pnSecond, int *pnTZ);
-char CPL_DLL * OGRGetRFC822DateTime(int year, int month, int day,
-                                    int hour, int minute, int second, int TZ);
-char CPL_DLL * OGRGetXMLDateTime(int year, int month, int day,
-                                 int hour, int minute, int second, int TZFlag);
+                                    OGRField* psField );
+char CPL_DLL * OGRGetRFC822DateTime(const OGRField* psField);
+char CPL_DLL * OGRGetXMLDateTime(const OGRField* psField);
 char CPL_DLL * OGRGetXML_UTF8_EscapedString(const char* pszString);
 
 int OGRCompareDate(   OGRField *psFirstTuple,
@@ -130,22 +136,28 @@ OGRErr CPL_DLL OGRCheckPermutation(int* panPermutation, int nSize);
 OGRGeometry *GML2OGRGeometry_XMLNode( const CPLXMLNode *psNode,
                                       int bGetSecondaryGeometryOption,
                                       int nRecLevel = 0,
+                                      int nSRSDimension = 0,
                                       int bIgnoreGSG = FALSE,
                                       int bOrientation = TRUE,
-                                      int bFaceHoleNegative = FALSE );
+                                      int bFaceHoleNegative = FALSE);
 
 /************************************************************************/
 /*                        PostGIS EWKB encoding                         */
 /************************************************************************/
 
-OGRGeometry CPL_DLL *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID );
-OGRGeometry CPL_DLL *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID );
-char CPL_DLL * OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId );
+OGRGeometry CPL_DLL *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID,
+                                          int bIsPostGIS1_EWKB  );
+OGRGeometry CPL_DLL *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID,
+                                             int bIsPostGIS1_EWKB );
+char CPL_DLL * OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId,
+                                     int bIsPostGIS1_EWKB );
 
 /************************************************************************/
 /*                        WKB Type Handling encoding                    */
 /************************************************************************/
 
-OGRErr OGRReadWKBGeometryType( unsigned char * pabyData, OGRwkbGeometryType *eGeometryType, OGRBoolean *b3D );
+OGRErr OGRReadWKBGeometryType( unsigned char * pabyData,
+                               OGRwkbVariant wkbVariant,
+                               OGRwkbGeometryType *eGeometryType, OGRBoolean *b3D );
 
 #endif /* ndef OGR_P_H_INCLUDED */
diff --git a/ogr/ogr_spatialref.h b/ogr/ogr_spatialref.h
index b0f2f8a..d3ec944 100644
--- a/ogr/ogr_spatialref.h
+++ b/ogr/ogr_spatialref.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_spatialref.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_spatialref.h 28972 2015-04-22 10:39:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Classes for manipulating spatial reference systems in a
@@ -193,7 +193,6 @@ class CPL_DLL OGRSpatialReference
                                 double *padfPrjParams, long iDatum, 
                                 int nUSGSAngleFormat = USGS_ANGLE_PACKEDDMS );
     OGRErr      importFromPanorama( long, long, long, double* );
-    OGRErr      importFromOzi( const char *, const char *, const char * );
     OGRErr      importFromOzi( const char * const* papszLines );
     OGRErr      importFromWMSAUTO( const char *pszAutoDef );
     OGRErr      importFromXML( const char * );
@@ -537,6 +536,9 @@ class CPL_DLL OGRSpatialReference
     OGRErr      SetWagner( int nVariation, double dfCenterLat,
                            double dfFalseEasting, double dfFalseNorthing );
 
+    /** Quadrilateralized Spherical Cube */
+    OGRErr      SetQSC(double dfCenterLat, double dfCenterLong);
+
     /** State Plane */
     OGRErr      SetStatePlane( int nZone, int bNAD83 = TRUE,
                                const char *pszOverrideUnitName = NULL,
@@ -548,6 +550,8 @@ class CPL_DLL OGRSpatialReference
     OGRErr      ImportFromESRIWisconsinWKT( 
         const char* pszPrjName, double dfCentralMeridian, double dfLatOfOrigin, 
         const char* pszUnitsName, const char* pszCSName = 0 );
+
+    static OGRSpatialReference* GetWGS84SRS();
 };
 
 /************************************************************************/
diff --git a/ogr/ogr_sql.dox b/ogr/ogr_sql.dox
index 93962dc..3b640bc 100644
--- a/ogr/ogr_sql.dox
+++ b/ogr/ogr_sql.dox
@@ -1,7 +1,7 @@
 /*! \page ogr_sql OGR SQL
 
-The OGRDataSource supports executing commands against a datasource via the
-OGRDataSource::ExecuteSQL() method.  While in theory 
+The GDALDataset supports executing commands against a datasource via the
+GDALDataset::ExecuteSQL() method.  While in theory 
 any sort of command could be handled this way, in practice the mechanism is 
 used to provide a subset of SQL SELECT capability to applications.  This 
 page discusses the generic SQL implementation implemented within OGR, and 
@@ -94,7 +94,7 @@ property values:
 
 \code
 SELECT MIN(prop_value), MAX(prop_value), AVG(prop_value), SUM(prop_value), 
-       COUNT(prop_value) FROM polylayer WHERE prov_name = "Ontario"
+       COUNT(prop_value) FROM polylayer WHERE prov_name = 'Ontario'
 \endcode
 
 It is also possible to apply the COUNT() operator to a DISTINCT SELECT to get
@@ -123,6 +123,8 @@ the JOIN section.
 Field definitions can also be complex expressions using arithmetic, and 
 functional operators.   However, the DISTINCT keyword, and summarization 
 operators like MIN, MAX, AVG and SUM may not be applied to expression fields.
+Starting with GDAL 2.0, boolean resulting expressions (comparisons, logical
+operators) can also be used.
 
 \code
 SELECT cost+tax from invoice
@@ -153,6 +155,13 @@ SELECT SUBSTR('abcdef',4)   FROM xxx   --> 'def'
 SELECT SUBSTR('abcdef',-2)  FROM xxx   --> 'ef'
 \endcode
 
+Starting with OGR 2.0, the <i>hstore_get_value()</i> function can be used to extract
+a value associate to a key from a HSTORE string, formatted like 'key=>value,other_key=>other_value,...'
+
+\code
+SELECT hstore_get_value('a => b, "key with space"=> "value with space"', 'key with space') FROM xxx --> 'value with space'
+\endcode
+
 \subsubsection ogr_sql_fname_alias Using the field name alias
 
 OGR SQL supports renaming the fields following the SQL92 specification by
@@ -167,7 +176,7 @@ Therefore we cannot rename the fields inside an operator, but we can
 rename whole column expression, like these two:
 
 \code
-SELECT COUNT(areacode) AS 'count' FROM polylayer
+SELECT COUNT(areacode) AS "count" FROM polylayer
 SELECT dollars/100.0 AS cents FROM polylayer
 \endcode
 
@@ -183,10 +192,13 @@ SELECT *, CAST(OGR_STYLE AS character(255)) FROM rivers
 Currently casting to the following target types are supported:
 
 <ol>
+<li> boolean (GDAL >= 2.0)
 <li> character(field_length). By default, field_length=1.
 <li> float(field_length)
 <li> numeric(field_length, field_precision)
+<li> smallint(field_length) : 16 bit signed integer (GDAL >= 2.0)
 <li> integer(field_length)
+<li> bigint(field_length), 64 bit integer, extension to SQL92 (GDAL >= 2.0)
 <li> date(field_length)
 <li> time(field_length)
 <li> timestamp(field_length)
@@ -209,6 +221,19 @@ Starting with OGR 1.11, casting a WKT string to a geometry is allowed.
 geometry_type can be POINT[Z], LINESTRING[Z], POLYGON[Z], MULTIPOINT[Z],
 MULTILINESTRING[Z], MULTIPOLYGON[Z], GEOMETRYCOLLECTION[Z] or GEOMETRY[Z].
 
+\subsubsection ogr_sql_quot String literals and identifiers quoting
+
+Starting with GDAL 2.0 (see <a href="http://trac.osgeo.org/gdal/wiki/rfc52_strict_sql_quoting">RFC 52 - Strict OGR SQL quoting</a>),
+strict SQL92 rules are applied regarding string literals
+and identifiers quoting.
+
+String literals (constants) must be surrounded with single-quote characters. e.g.
+WHERE a_field = 'a_value'
+
+Identifiers (column names and tables names) can be used unquoted if they don't
+contain special characters or are not a SQL reserved keyword. Otherwise they must
+be surroundered with double-quote characters. e.g. WHERE "from" = 5
+
 \subsection ogr_sql_where WHERE
 
 The argument to the WHERE clause is a logical expression used select records 
@@ -264,8 +289,8 @@ value for membership in the provided set.
     Value              Value Set            Matches?
     ------             -------              --------
     321                IN (456,123)         No
-    "Ontario"          IN ("Ontario","BC")  Yes
-    "Ont"              IN ("Ontario","BC")  No
+    'Ontario'          IN ('Ontario','BC')  Yes
+    'Ont'              IN ('Ontario','BC')  No
     1                  IN (0,2,4,6)         No
 \endcode
 
@@ -283,7 +308,7 @@ clear.  Some more complicated predicates are:
 
 \code
 SELECT * FROM poly WHERE (prop_value >= 100000) AND (prop_value < 200000)
-SELECT * FROM poly WHERE NOT (area_code LIKE "N0N%")
+SELECT * FROM poly WHERE NOT (area_code LIKE 'N0N%')
 SELECT * FROM poly WHERE (prop_value IS NOT NULL) AND (prop_value < 100000)
 \endcode
 
@@ -404,6 +429,15 @@ SELECT city.name, prov.name, nation.name FROM city
   LEFT JOIN nation ON city.nation_id = nation.id
 \endcode
 
+Before GDAL 2.0, the expression after ON should necessarily be of the form
+"{primary_table}.{field_name} = {secondary_table}.{field_name}", and in that
+order.
+Starting with GDAL 2.0, it is possible to use a more complex boolean expression,
+involving multiple comparison operators, but with the restrictions mentionned
+in the below "JOIN limitations" section. In particular, in case of multiple joins (3 tables
+or more) the fields compared in a JOIN must belong to the primary table (the one
+after FROM) and the table of the active JOIN.
+
 \subsection ogr_sql_join_limits JOIN Limitations
 
 <ol>
@@ -513,7 +547,7 @@ areas of its members. For non-surface geometries the returned area is 0.0.
 For example, to select only polygon features larger than a given area:
 
 \code
-SELECT * FROM nation WHERE OGR_GEOM_AREA > 10000000'
+SELECT * FROM nation WHERE OGR_GEOM_AREA > 10000000
 \endcode 
 
 \subsection ogr_sql_style OGR_STYLE
@@ -597,11 +631,11 @@ DROP TABLE nation
 
 \section ogr_sql_exec_sql ExecuteSQL()
 
-SQL is executed against an OGRDataSource, not against a specific layer.  The
+SQL is executed against an GDALDataset, not against a specific layer.  The
 call looks like this:
 
 \code
-OGRLayer * OGRDataSource::ExecuteSQL( const char *pszSQLCommand,
+OGRLayer * GDALDataset::ExecuteSQL( const char *pszSQLCommand,
 				      OGRGeometry *poSpatialFilter,
                                       const char *pszDialect );
 \endcode
@@ -618,7 +652,7 @@ restriction.<p>
 The result of an ExecuteSQL() call is usually a temporary OGRLayer representing
 the results set from the statement.  This is the case for a SELECT statement
 for instance.  The returned temporary layer should be released with 
-OGRDataSource::ReleaseResultsSet() method when no longer needed.  Failure
+GDALDataset::ReleaseResultsSet() method when no longer needed.  Failure
 to release it before the datasource is destroyed may result in a crash.<p>
 
 \section ogr_sql_non_ogr_sql Non-OGR SQL
@@ -630,7 +664,7 @@ Oracle (<a href="/ogr/drv_oci.html">OCI</a>),
 <a href="/ogr/drv_odbc.html">ODBC</a>,
 ESRI Personal Geodatabase (<a href="/ogr/drv_pgeo.html">PGeo</a>) and
 MS SQL Spatial (<a href="/ogr/drv_mssqlspatial.html">MSSQLSpatial</a>),
-override the OGRDataSource::ExecuteSQL() function with dedicated implementation 
+override the GDALDataset::ExecuteSQL() function with dedicated implementation 
 and, by default, pass the SQL statements directly to the underlying RDBMS. 
 In these cases the SQL syntax varies in some particulars from OGR SQL.
 Also, anything possible in SQL can then be accomplished for these particular
diff --git a/ogr/ogr_sql_sqlite.dox b/ogr/ogr_sql_sqlite.dox
index e134864..7ba0292 100644
--- a/ogr/ogr_sql_sqlite.dox
+++ b/ogr/ogr_sql_sqlite.dox
@@ -6,7 +6,7 @@ This assumes that GDAL/OGR is built with support for SQLite (>= 3.6), and prefer
 with <a href="http://www.gaia-gis.it/spatialite/">Spatialite</a> support too to benefit from spatial functions.<p>
 
 The SQLite dialect may be used with any OGR datasource, like the OGR SQL dialect. It
-is available through the OGRDataSource::ExecuteSQL() method by specifying the pszDialect to
+is available through the GDALDataset::ExecuteSQL() method by specifying the pszDialect to
 "SQLITE". For the <a href="../ogrinfo.html">ogrinfo</a> or <a href="../ogr2ogr.html">ogr2ogr</a>
 utility, you must specify the "-dialect SQLITE" option.<p>
 
@@ -171,6 +171,15 @@ from a blob compressed with the ZLib deflate algorithm.
 If the decompressed binary is a string, use
 CAST(ogr_inflate(compressed_blob) AS VARCHAR). See CPLZLibInflate().<p>
 
+\subsubsection ogr_sql_sqlite_other_functions Other functions
+
+Starting with OGR 2.0, the <i>hstore_get_value()</i> function can be used to extract
+a value associate to a key from a HSTORE string, formatted like "key=>value,other_key=>other_value,..."
+
+\code
+SELECT hstore_get_value('a => b, "key with space"=> "value with space"', 'key with space') --> 'value with space'
+\endcode
+
 \subsection ogr_sql_sqlite_ogr_geocode_function OGR geocoding functions
 
 The following SQL functions are available : <b>ogr_geocode(...)</b> and <b>ogr_geocode_reverse(...)</b>.<p>
diff --git a/ogr/ogr_srs_api.h b/ogr/ogr_srs_api.h
index 8fe73fd..afb08ee 100644
--- a/ogr/ogr_srs_api.h
+++ b/ogr/ogr_srs_api.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_api.h 27109 2014-03-28 20:26:34Z kyle $
+ * $Id: ogr_srs_api.h 28972 2015-04-22 10:39:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  C API and constant declarations for OGR Spatial References.
@@ -136,6 +136,9 @@ typedef enum {
                                 "Lambert_Azimuthal_Equal_Area"
 #define SRS_PT_MERCATOR_1SP     "Mercator_1SP"
 #define SRS_PT_MERCATOR_2SP     "Mercator_2SP"
+// Mercator_Auxiliary_Sphere is used used by ESRI to mean EPSG:3875
+#define SRS_PT_MERCATOR_AUXILIARY_SPHERE                                 \
+                                "Mercator_Auxiliary_Sphere"
 #define SRS_PT_MILLER_CYLINDRICAL "Miller_Cylindrical"
 #define SRS_PT_MOLLWEIDE        "Mollweide"
 #define SRS_PT_NEW_ZEALAND_MAP_GRID                                     \
@@ -182,7 +185,14 @@ typedef enum {
 #define SRS_PT_WAGNER_V         "Wagner_V"
 #define SRS_PT_WAGNER_VI        "Wagner_VI"
 #define SRS_PT_WAGNER_VII       "Wagner_VII"
-                                
+#define SRS_PT_QSC              "Quadrilateralized_Spherical_Cube"
+#define SRS_PT_AITOFF           "Aitoff" 
+#define SRS_PT_WINKEL_I         "Winkel_I" 
+#define SRS_PT_WINKEL_II        "Winkel_II" 
+#define SRS_PT_WINKEL_TRIPEL    "Winkel_Tripel" 
+#define SRS_PT_CRASTER_PARABOLIC    "Craster_Parabolic" 
+#define SRS_PT_LOXIMUTHAL        "Loximuthal"
+#define SRS_PT_QUARTIC_AUTHALIC  "Quartic_Authalic"
 
 #define SRS_PP_CENTRAL_MERIDIAN         "central_meridian"
 #define SRS_PP_SCALE_FACTOR             "scale_factor"
@@ -330,8 +340,7 @@ OGRErr CPL_DLL OSRImportFromDict( OGRSpatialReferenceH, const char *,
                                   const char * );
 OGRErr CPL_DLL OSRImportFromPanorama( OGRSpatialReferenceH, long, long, long,
                                       double * );
-OGRErr CPL_DLL OSRImportFromOzi( OGRSpatialReferenceH , const char *, const char *,
-                                 const char * );
+OGRErr CPL_DLL OSRImportFromOzi( OGRSpatialReferenceH , const char * const *);
 OGRErr CPL_DLL OSRImportFromMICoordSys( OGRSpatialReferenceH, const char *);
 OGRErr CPL_DLL OSRImportFromERM( OGRSpatialReferenceH,
                                  const char *, const char *, const char * );
@@ -702,6 +711,13 @@ OGRErr CPL_DLL OSRSetWagner( OGRSpatialReferenceH hSRS, int nVariation,
                              double dfFalseEasting,
                              double dfFalseNorthing );
 
+/** Quadrilateralized Spherical Cube */
+OGRErr CPL_DLL OSRSetQSC( OGRSpatialReferenceH hSRS,
+                              double dfCenterLat, double dfCenterLong );
+
+double CPL_DLL OSRCalcInvFlattening( double dfSemiMajor, double dfSemiMinor );
+double CPL_DLL OSRCalcSemiMinorFromInvFlattening( double dfSemiMajor, double dfInvFlattening );
+
 void CPL_DLL OSRCleanup( void );
 
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogr_srs_erm.cpp b/ogr/ogr_srs_erm.cpp
index e5e7aaa..62a6e8e 100644
--- a/ogr/ogr_srs_erm.cpp
+++ b/ogr/ogr_srs_erm.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_erm.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_srs_erm.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implement ERMapper projection conversions.
@@ -31,7 +31,7 @@
 #include "ogr_spatialref.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogr_srs_erm.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_srs_erm.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                         OSRImportFromERM()                           */
@@ -111,7 +111,7 @@ OGRErr OGRSpatialReference::importFromERM( const char *pszProj,
             return eErr;
 
         if( EQUAL(pszUnits,"FEET") )
-            SetLinearUnits( SRS_UL_US_FOOT, atof(SRS_UL_US_FOOT_CONV));
+            SetLinearUnits( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV));
         else
             SetLinearUnits( SRS_UL_METER, 1.0 );
     }
@@ -203,7 +203,7 @@ OGRErr OGRSpatialReference::exportToERM( char *pszProj, char *pszDatum,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Is our GEOGCS name already defined in ecw_cs.dat?               */
+/*      Is our GEOGCS name already defined in ecw_cs.wkt?               */
 /* -------------------------------------------------------------------- */
     OGRSpatialReference oSRSWork;
     const char *pszWKTDatum = GetAttrValue( "DATUM" );
@@ -302,7 +302,7 @@ OGRErr OGRSpatialReference::exportToERM( char *pszProj, char *pszDatum,
     }
 
 /* -------------------------------------------------------------------- */
-/*      Is our PROJCS name already defined in ecw_cs.dat?               */
+/*      Is our PROJCS name already defined in ecw_cs.wkt?               */
 /* -------------------------------------------------------------------- */
     else
     {
diff --git a/ogr/ogr_srs_esri.cpp b/ogr/ogr_srs_esri.cpp
index b8e4f51..e662fff 100644
--- a/ogr/ogr_srs_esri.cpp
+++ b/ogr/ogr_srs_esri.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_esri.cpp 27050 2014-03-18 00:09:03Z kyle $
+ * $Id: ogr_srs_esri.cpp 29116 2015-05-02 20:39:55Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference translation to/from ESRI .prj definitions.
@@ -36,7 +36,7 @@
 
 #include "ogr_srs_esri_names.h"
 
-CPL_CVSID("$Id: ogr_srs_esri.cpp 27050 2014-03-18 00:09:03Z kyle $");
+CPL_CVSID("$Id: ogr_srs_esri.cpp 29116 2015-05-02 20:39:55Z rouault $");
 
 void  SetNewName( OGRSpatialReference* pOgr, const char* keyName, const char* newName );
 int   RemapImgWGSProjcsName(OGRSpatialReference* pOgr, const char* pszProjCSName, 
@@ -104,7 +104,7 @@ static const char *apszLambertConformalConicMapping[] = {
     NULL, NULL };
 
 static char **papszDatumMapping = NULL;
-static void* hDatumMappingMutex = NULL;
+static CPLMutex* hDatumMappingMutex = NULL;
  
 static const char *apszDefaultDatumMapping[] = {
     "6267", "North_American_1927", SRS_DN_NAD27,
@@ -552,19 +552,19 @@ static double OSR_GDV( char **papszNV, const char * pszField,
             {
                 /* http://agdcftp1.wr.usgs.gov/pub/projects/lcc/akcan_lcc/akcan.tar.gz contains */
                 /* weird values for the second. Ignore it and the result looks correct */
-                double dfSecond = atof(papszTokens[2]);
+                double dfSecond = CPLAtof(papszTokens[2]);
                 if (dfSecond < 0.0 || dfSecond >= 60.0)
                     dfSecond = 0.0;
 
-                dfValue = ABS(atof(papszTokens[0]))
-                    + atof(papszTokens[1]) / 60.0
+                dfValue = ABS(CPLAtof(papszTokens[0]))
+                    + CPLAtof(papszTokens[1]) / 60.0
                     + dfSecond / 3600.0;
 
-                if( atof(papszTokens[0]) < 0.0 )
+                if( CPLAtof(papszTokens[0]) < 0.0 )
                     dfValue *= -1;
             }
             else if( CSLCount(papszTokens) > 0 )
-                dfValue = atof(papszTokens[0]);
+                dfValue = CPLAtof(papszTokens[0]);
             else
                 dfValue = dfDefaultValue;
 
@@ -585,7 +585,7 @@ static double OSR_GDV( char **papszNV, const char * pszField,
         if( papszNV[iLine] == NULL )
             return dfDefaultValue;
         else
-            return atof( papszNV[iLine] + strlen(pszField) );
+            return CPLAtof( papszNV[iLine] + strlen(pszField) );
     }
 }
 
@@ -835,6 +835,14 @@ OGRErr OGRSpatialReference::importFromESRI( char **papszPrj )
                      OSR_GDV( papszPrj, "PARAM_3", 0.0 ) );
     }
 
+    else if( EQUAL(osProj, SRS_PT_MERCATOR_AUXILIARY_SPHERE) )
+    {
+       // This is EPSG:3875 Pseudo Mercator. We might as well import it from
+       // the EPSG spec.
+       CPLString osAuxiliarySphereType;
+       importFromEPSG(3857);
+    }
+
     else if( EQUAL(osProj,"POLYCONIC") )
     {
         SetPolyconic( OSR_GDV( papszPrj, "PARAM_2", 0.0 ),
@@ -937,10 +945,10 @@ OGRErr OGRSpatialReference::importFromESRI( char **papszPrj )
         if( EQUAL(osValue, "" ) )
             SetLinearUnitsAndUpdateParameters( SRS_UL_METER, 1.0 );
         else if( EQUAL(osValue,"FEET") )
-            SetLinearUnitsAndUpdateParameters( SRS_UL_US_FOOT, atof(SRS_UL_US_FOOT_CONV) );
-        else if( atof(osValue) != 0.0 )
+            SetLinearUnitsAndUpdateParameters( SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV) );
+        else if( CPLAtof(osValue) != 0.0 )
             SetLinearUnitsAndUpdateParameters( "user-defined", 
-                                               1.0 / atof(osValue) );
+                                               1.0 / CPLAtof(osValue) );
         else
             SetLinearUnitsAndUpdateParameters( osValue, 1.0 );
 
@@ -981,7 +989,6 @@ OGRErr OGRSpatialReference::morphToESRI()
 {
     OGRErr      eErr;
 
-    CPLLocaleC localeC;
 /* -------------------------------------------------------------------- */
 /*      Fixup ordering, missing linear units, etc.                      */
 /* -------------------------------------------------------------------- */
@@ -1129,26 +1136,26 @@ OGRErr OGRSpatialReference::morphToESRI()
 /* -------------------------------------------------------------------- */
 /*      Force Unnamed to Unknown for most common locations.             */
 /* -------------------------------------------------------------------- */
-    static const char *apszUnknownMapping[] = { 
-        "Unknown", "Unnamed",
-        NULL, NULL 
-    };
-
-    GetRoot()->applyRemapper( "PROJCS", 
-                              (char **)apszUnknownMapping+1,
-                              (char **)apszUnknownMapping+0, 2 );
-    GetRoot()->applyRemapper( "GEOGCS", 
-                              (char **)apszUnknownMapping+1,
-                              (char **)apszUnknownMapping+0, 2 );
-    GetRoot()->applyRemapper( "DATUM", 
-                              (char **)apszUnknownMapping+1,
-                              (char **)apszUnknownMapping+0, 2 );
-    GetRoot()->applyRemapper( "SPHEROID", 
-                              (char **)apszUnknownMapping+1,
-                              (char **)apszUnknownMapping+0, 2 );
-    GetRoot()->applyRemapper( "PRIMEM", 
-                              (char **)apszUnknownMapping+1,
-                              (char **)apszUnknownMapping+0, 2 );
+        static const char *apszUnknownMapping[] = { 
+            "Unknown", "Unnamed",
+            NULL, NULL 
+        };
+
+        GetRoot()->applyRemapper( "PROJCS", 
+                                  (char **)apszUnknownMapping+1,
+                                  (char **)apszUnknownMapping+0, 2 );
+        GetRoot()->applyRemapper( "GEOGCS", 
+                                  (char **)apszUnknownMapping+1,
+                                  (char **)apszUnknownMapping+0, 2 );
+        GetRoot()->applyRemapper( "DATUM", 
+                                  (char **)apszUnknownMapping+1,
+                                  (char **)apszUnknownMapping+0, 2 );
+        GetRoot()->applyRemapper( "SPHEROID", 
+                                  (char **)apszUnknownMapping+1,
+                                  (char **)apszUnknownMapping+0, 2 );
+        GetRoot()->applyRemapper( "PRIMEM", 
+                                  (char **)apszUnknownMapping+1,
+                                  (char **)apszUnknownMapping+0, 2 );
     
 /* -------------------------------------------------------------------- */
 /*      If the PROJCS name is unset, use the PROJECTION name in         */
@@ -1672,6 +1679,25 @@ OGRErr OGRSpatialReference::morphFromESRI()
         GetRoot()->applyRemapper( 
             "PARAMETER", (char **)apszLambertConformalConicMapping + 0,
             (char **)apszLambertConformalConicMapping + 1, 2 );
+
+        /* LCC 1SP has duplicated parameters Standard_Parallel_1 and Latitude_Of_Origin */
+        /* http://trac.osgeo.org/gdal/ticket/2072 */
+        if( EQUAL( pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP ) )
+        {
+            OGR_SRSNode *poPROJCS = GetAttrNode( "PROJCS" );
+            int iSP1Child = FindProjParm( "Standard_Parallel_1", poPROJCS );
+            int iLatOrigChild = FindProjParm( "Latitude_Of_Origin", poPROJCS );
+            if( iSP1Child != -1 && iLatOrigChild != 1 )
+            {
+                /* Do a sanity check before removing Standard_Parallel_1 */
+                if( EQUAL(poPROJCS->GetChild(iSP1Child)->GetValue(),
+                          poPROJCS->GetChild(iLatOrigChild)->GetValue()) )
+                {
+                    poPROJCS->DestroyChild( iSP1Child );
+                }
+            }
+        }
+
     }
 
 /* -------------------------------------------------------------------- */
@@ -1691,6 +1717,24 @@ OGRErr OGRSpatialReference::morphFromESRI()
                               (char **)papszDatumMapping+2, 3 );
 
 /* -------------------------------------------------------------------- */
+/*      Special case for Peru96 related SRS that should use the         */
+/*      Peru96 DATUM, but in ESRI world, both Peru96 and SIRGAS-Chile   */
+/*      are translated as D_SIRGAS-Chile.                               */
+/* -------------------------------------------------------------------- */
+    int bPeru96Datum = FALSE;
+    if( poDatum != NULL && EQUAL(poDatum->GetValue(), "SIRGAS_Chile") )
+    {
+        const char* pszSRSName = GetAttrValue("PROJCS");
+        if( pszSRSName == NULL )
+            pszSRSName = GetAttrValue("GEOGCS");
+        if( strstr(pszSRSName, "Peru96") )
+        {
+            bPeru96Datum = TRUE;
+            poDatum->SetValue( "Peru96" );
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Fix TOWGS84, DATUM or GEOGCS                                    */
 /* -------------------------------------------------------------------- */
     /* TODO test more ESRI WKT; also add PROJCS */
@@ -1722,6 +1766,11 @@ OGRErr OGRSpatialReference::morphFromESRI()
                                                  DMGetEPSGCode(i), CC_Integer );
                 if ( papszRecord != NULL )
                 {
+                    /* skip the SIRGAS-Chile record for Peru96 related SRS */
+                    if( bPeru96Datum && EQUAL(CSLGetField( papszRecord,
+                                    CSVGetFileFieldId(pszFilename,"DATUM_NAME")), "SIRGAS-Chile") )
+                        continue;
+
                     /* make sure we got a valid EPSG code and it is not DEPRECATED */
                     int nGeogCS = atoi( CSLGetField( papszRecord,
                                                      CSVGetFileFieldId(pszFilename,"COORD_REF_SYS_CODE")) );
@@ -1882,12 +1931,12 @@ OGRErr OSRMorphFromESRI( OGRSpatialReferenceH hSRS )
 /************************************************************************/
 void SetNewName( OGRSpatialReference* pOgr, const char* keyName, const char* newName )
 {
-  OGR_SRSNode *poNode = pOgr->GetAttrNode( keyName );
-  OGR_SRSNode *poNodeChild = NULL;
-  if(poNode)
-    poNodeChild = poNode->GetChild(0);
-  if( poNodeChild)
-      poNodeChild->SetValue( newName);
+    OGR_SRSNode *poNode = pOgr->GetAttrNode( keyName );
+    OGR_SRSNode *poNodeChild = NULL;
+    if(poNode)
+        poNodeChild = poNode->GetChild(0);
+    if( poNodeChild)
+        poNodeChild->SetValue( newName);
 }
 
 /************************************************************************/
@@ -1897,16 +1946,16 @@ void SetNewName( OGRSpatialReference* pOgr, const char* keyName, const char* new
 /************************************************************************/
 int RemapImgWGSProjcsName( OGRSpatialReference* pOgr, const char* pszProjCSName, const char* pszProgCSName )
 {
-  if(EQUAL(pszProgCSName, "WGS_1972") || EQUAL(pszProgCSName, "WGS_1984") )
-  {
-    char* newName = (char *) CPLMalloc(strlen(pszProjCSName) + 10);
-    sprintf( newName, "%s_", pszProgCSName );
-    strcat(newName, pszProjCSName);
-    SetNewName( pOgr, "PROJCS", newName );
-    CPLFree( newName );
-    return 1;
-  }
-  return -1;
+    if(EQUAL(pszProgCSName, "WGS_1972") || EQUAL(pszProgCSName, "WGS_1984") )
+    {
+        char* newName = (char *) CPLMalloc(strlen(pszProjCSName) + 10);
+        sprintf( newName, "%s_", pszProgCSName );
+        strcat(newName, pszProjCSName);
+        SetNewName( pOgr, "PROJCS", newName );
+        CPLFree( newName );
+        return 1;
+    }
+    return -1;
 }
 
 /************************************************************************/
@@ -1916,52 +1965,52 @@ int RemapImgWGSProjcsName( OGRSpatialReference* pOgr, const char* pszProjCSName,
 /************************************************************************/
 
 int RemapImgUTMNames( OGRSpatialReference* pOgr, const char* pszProjCSName, const char* pszProgCSName, 
-                                          char **mappingTable )
+                      char **mappingTable )
 {
-  long i;
-  long iIndex = -1;
-  for( i = 0; mappingTable[i] != NULL; i += 5 )
-  {
-    if( EQUAL(pszProjCSName, mappingTable[i]) )
+    long i;
+    long iIndex = -1;
+    for( i = 0; mappingTable[i] != NULL; i += 5 )
     {
-      long j = i;
-      while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
-      {
-        if( EQUAL(pszProgCSName, mappingTable[j+1]) )
+        if( EQUAL(pszProjCSName, mappingTable[i]) )
         {
-          iIndex = j;
-          break;
+            long j = i;
+            while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
+            {
+                if( EQUAL(pszProgCSName, mappingTable[j+1]) )
+                {
+                    iIndex = j;
+                    break;
+                }
+                j += 5;
+            }
+            if (iIndex >= 0)
+                break;
         }
-        j += 5;
-      }
-      if (iIndex >= 0)
-        break;
     }
-  }
-  if(iIndex >= 0)
-  {
-    OGR_SRSNode *poNode = pOgr->GetAttrNode( "PROJCS" );
-    OGR_SRSNode *poNodeChild = NULL;
-    if(poNode)
-      poNodeChild = poNode->GetChild(0);
-    if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
-        poNodeChild->SetValue( mappingTable[iIndex+2]);
-
-    poNode = pOgr->GetAttrNode( "GEOGCS" );
-    poNodeChild = NULL;
-    if(poNode)
-      poNodeChild = poNode->GetChild(0);
-    if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
-        poNodeChild->SetValue( mappingTable[iIndex+3]);
-
-    poNode = pOgr->GetAttrNode( "DATUM" );
-    poNodeChild = NULL;
-    if(poNode)
-      poNodeChild = poNode->GetChild(0);
-    if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
-        poNodeChild->SetValue( mappingTable[iIndex+4]);
-  }
-  return iIndex;
+    if(iIndex >= 0)
+    {
+        OGR_SRSNode *poNode = pOgr->GetAttrNode( "PROJCS" );
+        OGR_SRSNode *poNodeChild = NULL;
+        if(poNode)
+            poNodeChild = poNode->GetChild(0);
+        if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
+            poNodeChild->SetValue( mappingTable[iIndex+2]);
+
+        poNode = pOgr->GetAttrNode( "GEOGCS" );
+        poNodeChild = NULL;
+        if(poNode)
+            poNodeChild = poNode->GetChild(0);
+        if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
+            poNodeChild->SetValue( mappingTable[iIndex+3]);
+
+        poNode = pOgr->GetAttrNode( "DATUM" );
+        poNodeChild = NULL;
+        if(poNode)
+            poNodeChild = poNode->GetChild(0);
+        if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
+            poNodeChild->SetValue( mappingTable[iIndex+4]);
+    }
+    return iIndex;
 }
 
 /************************************************************************/
@@ -1971,28 +2020,28 @@ int RemapImgUTMNames( OGRSpatialReference* pOgr, const char* pszProjCSName, cons
 /************************************************************************/
 
 int RemapNameBasedOnKeyName( OGRSpatialReference* pOgr, const char* pszName, const char* pszkeyName, 
-                                                 char **mappingTable )
+                             char **mappingTable )
 {
-  long i;
-  long iIndex = -1;
-  for( i = 0; mappingTable[i] != NULL; i += 2 )
-  {
-    if( EQUAL(pszName, mappingTable[i]) )
+    long i;
+    long iIndex = -1;
+    for( i = 0; mappingTable[i] != NULL; i += 2 )
     {
-      iIndex = i;
-      break;
+        if( EQUAL(pszName, mappingTable[i]) )
+        {
+            iIndex = i;
+            break;
+        }
     }
-  }
-  if(iIndex >= 0) 
-  {
-    OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyName );
-    OGR_SRSNode *poNodeChild = NULL;
-    if(poNode)
-      poNodeChild = poNode->GetChild(0);
-    if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
-        poNodeChild->SetValue( mappingTable[iIndex+1]);
-  }
-  return iIndex;
+    if(iIndex >= 0) 
+    {
+        OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyName );
+        OGR_SRSNode *poNodeChild = NULL;
+        if(poNode)
+            poNodeChild = poNode->GetChild(0);
+        if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
+            poNodeChild->SetValue( mappingTable[iIndex+1]);
+    }
+    return iIndex;
 }
 
 /************************************************************************/
@@ -2002,45 +2051,45 @@ int RemapNameBasedOnKeyName( OGRSpatialReference* pOgr, const char* pszName, con
 /************************************************************************/
 
 int RemapNamesBasedOnTwo( OGRSpatialReference* pOgr, const char* name1, const char* name2, 
-                                              char **mappingTable, long nTableStepSize, 
-                                              char** pszkeyNames, long nKeys )
+                          char **mappingTable, long nTableStepSize, 
+                          char** pszkeyNames, long nKeys )
 {
-  long i, n, n1;
-  long iIndex = -1;
-  for( i = 0; mappingTable[i] != NULL; i += nTableStepSize )
-  {
-    n = strlen(name1);
-    n1 = strlen(mappingTable[i]); 
-    if( EQUALN(name1, mappingTable[i], n1<=n? n1 : n) )
+    long i, n, n1;
+    long iIndex = -1;
+    for( i = 0; mappingTable[i] != NULL; i += nTableStepSize )
     {
-      long j = i;
-      while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
-      {
-        if( EQUALN(name2, mappingTable[j+1], strlen(mappingTable[j+1])) )
+        n = strlen(name1);
+        n1 = strlen(mappingTable[i]); 
+        if( EQUALN(name1, mappingTable[i], n1<=n? n1 : n) )
         {
-          iIndex = j;
-          break;
+            long j = i;
+            while(mappingTable[j] != NULL && EQUAL(mappingTable[i], mappingTable[j]))
+            {
+                if( EQUALN(name2, mappingTable[j+1], strlen(mappingTable[j+1])) )
+                {
+                    iIndex = j;
+                    break;
+                }
+                j += 3;
+            }
+            if (iIndex >= 0)
+                break;
         }
-        j += 3;
-      }
-      if (iIndex >= 0)
-        break;
     }
-  }
-  if(iIndex >= 0)
-  {
-    for( i = 0; i < nKeys; i ++ )
+    if(iIndex >= 0)
     {
-      OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyNames[i] );
-      OGR_SRSNode *poNodeChild = NULL;
-      if(poNode)
-        poNodeChild = poNode->GetChild(0);
-      if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
-          poNodeChild->SetValue( mappingTable[iIndex+i+2]);
-    }
+        for( i = 0; i < nKeys; i ++ )
+        {
+            OGR_SRSNode *poNode = pOgr->GetAttrNode( pszkeyNames[i] );
+            OGR_SRSNode *poNodeChild = NULL;
+            if(poNode)
+                poNodeChild = poNode->GetChild(0);
+            if( poNodeChild && strlen(poNodeChild->GetValue()) > 0 )
+                poNodeChild->SetValue( mappingTable[iIndex+i+2]);
+        }
 
-  }
-  return iIndex;
+    }
+    return iIndex;
 }
 
 /************************************************************************/
@@ -2050,37 +2099,37 @@ int RemapNamesBasedOnTwo( OGRSpatialReference* pOgr, const char* name1, const ch
 /************************************************************************/
 
 int RemapPValuesBasedOnProjCSAndPName( OGRSpatialReference* pOgr, const char* pszProgCSName, 
-                                                                      char **mappingTable )
+                                       char **mappingTable )
 {
-  long ret = 0;
-  OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
-  for( int i = 0; mappingTable[i] != NULL; i += 4 )
-  {
-    while( mappingTable[i] != NULL && EQUALN(pszProgCSName, mappingTable[i], strlen(mappingTable[i])) )
+    long ret = 0;
+    OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
+    for( int i = 0; mappingTable[i] != NULL; i += 4 )
     {
-      OGR_SRSNode *poParm;
-      const char* pszParamName = mappingTable[i+1];
-      const char* pszParamValue = mappingTable[i+2];
-      for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
-      {
-          poParm = poPROJCS->GetChild( iChild );
+        while( mappingTable[i] != NULL && EQUALN(pszProgCSName, mappingTable[i], strlen(mappingTable[i])) )
+        {
+            OGR_SRSNode *poParm;
+            const char* pszParamName = mappingTable[i+1];
+            const char* pszParamValue = mappingTable[i+2];
+            for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
+            {
+                poParm = poPROJCS->GetChild( iChild );
 
-          if( EQUAL(poParm->GetValue(),"PARAMETER") 
-              && poParm->GetChildCount() == 2 
-              && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) 
-              && EQUALN(poParm->GetChild(1)->GetValue(),pszParamValue, strlen(pszParamValue) ) )
-          {
-              poParm->GetChild(1)->SetValue( mappingTable[i+3] );
-              break;
-          }
-      }
-      ret ++;
-      i += 4;
+                if( EQUAL(poParm->GetValue(),"PARAMETER") 
+                    && poParm->GetChildCount() == 2 
+                    && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) 
+                    && EQUALN(poParm->GetChild(1)->GetValue(),pszParamValue, strlen(pszParamValue) ) )
+                {
+                    poParm->GetChild(1)->SetValue( mappingTable[i+3] );
+                    break;
+                }
+            }
+            ret ++;
+            i += 4;
+        }
+        if (ret > 0)
+            break;
     }
-    if (ret > 0)
-      break;
-  }
-  return ret;
+    return ret;
 }
 
 /************************************************************************/
@@ -2127,37 +2176,37 @@ int RemapPNamesBasedOnProjCSAndPName( OGRSpatialReference* pOgr, const char* psz
 /*      Delete non-ESRI parameters                                      */
 /************************************************************************/
 int DeleteParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProjectionName, 
-                                                             char **mappingTable )
+                               char **mappingTable )
 {
-  long iIndex = -1, ret = -1;
-  for( int i = 0; mappingTable[i] != NULL; i += 2 )
-  {
-    if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
+    long iIndex = -1, ret = -1;
+    for( int i = 0; mappingTable[i] != NULL; i += 2 )
     {
-      OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
-      OGR_SRSNode *poParm;
-      const char* pszParamName = mappingTable[i+1];
-      iIndex = -1;
-      for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
-      {
-        poParm = poPROJCS->GetChild( iChild );
-
-        if( EQUAL(poParm->GetValue(),"PARAMETER") 
-            && poParm->GetChildCount() == 2 
-            && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) )
+        if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
         {
-          iIndex = iChild;
-          break;
+            OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
+            OGR_SRSNode *poParm;
+            const char* pszParamName = mappingTable[i+1];
+            iIndex = -1;
+            for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
+            {
+                poParm = poPROJCS->GetChild( iChild );
+
+                if( EQUAL(poParm->GetValue(),"PARAMETER") 
+                    && poParm->GetChildCount() == 2 
+                    && EQUAL(poParm->GetChild(0)->GetValue(),pszParamName) )
+                {
+                    iIndex = iChild;
+                    break;
+                }
+            }
+            if(iIndex >= 0)
+            {
+                poPROJCS->DestroyChild( iIndex );
+                ret ++;
+            }
         }
-      }
-      if(iIndex >= 0)
-      {
-        poPROJCS->DestroyChild( iIndex );
-        ret ++;
-      }
     }
-  }
-  return ret;
+    return ret;
 }
 /************************************************************************/
 /*                          AddParamBasedOnPrjName()                    */
@@ -2165,36 +2214,36 @@ int DeleteParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProject
 /*      Add ESRI style parameters                                       */
 /************************************************************************/
 int AddParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProjectionName, 
-                                                          char **mappingTable )
+                            char **mappingTable )
 {
-  long ret = -1;
-  OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
-  for( int i = 0; mappingTable[i] != NULL; i += 3 )
-  {
-    if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
+    long ret = -1;
+    OGR_SRSNode *poPROJCS = pOgr->GetAttrNode( "PROJCS" );
+    for( int i = 0; mappingTable[i] != NULL; i += 3 )
     {
-      OGR_SRSNode *poParm;
-      int exist = 0;
-      for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
-      {
-        poParm = poPROJCS->GetChild( iChild );
+        if( EQUALN(pszProjectionName, mappingTable[i], strlen(mappingTable[i])) )
+        {
+            OGR_SRSNode *poParm;
+            int exist = 0;
+            for( int iChild = 0; iChild < poPROJCS->GetChildCount(); iChild++ )
+            {
+                poParm = poPROJCS->GetChild( iChild );
 
-        if( EQUAL(poParm->GetValue(),"PARAMETER") 
-            && poParm->GetChildCount() == 2 
-            && EQUAL(poParm->GetChild(0)->GetValue(),mappingTable[i+1]) )
-          exist = 1;
-      }
-      if(!exist)
-      {
-        poParm = new OGR_SRSNode( "PARAMETER" );
-        poParm->AddChild( new OGR_SRSNode( mappingTable[i+1] ) );
-        poParm->AddChild( new OGR_SRSNode( mappingTable[i+2] ) );
-        poPROJCS->AddChild( poParm );
-        ret ++;
-      }
+                if( EQUAL(poParm->GetValue(),"PARAMETER") 
+                    && poParm->GetChildCount() == 2 
+                    && EQUAL(poParm->GetChild(0)->GetValue(),mappingTable[i+1]) )
+                    exist = 1;
+            }
+            if(!exist)
+            {
+                poParm = new OGR_SRSNode( "PARAMETER" );
+                poParm->AddChild( new OGR_SRSNode( mappingTable[i+1] ) );
+                poParm->AddChild( new OGR_SRSNode( mappingTable[i+2] ) );
+                poPROJCS->AddChild( poParm );
+                ret ++;
+            }
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
 /************************************************************************/
@@ -2204,27 +2253,27 @@ int AddParamBasedOnPrjName( OGRSpatialReference* pOgr, const char* pszProjection
 /************************************************************************/
 int RemapGeogCSName( OGRSpatialReference* pOgr, const char *pszGeogCSName )
 {
-  static const char *keyNamesG[] = {
-    "GEOGCS"};
-  int ret = -1;
-
-  const char* pszUnitName = pOgr->GetAttrValue( "GEOGCS|UNIT");
-  if(pszUnitName)
-    ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszUnitName, (char**)apszGcsNameMappingBasedOnUnit, 3, (char**)keyNamesG, 1);
-  if(ret < 0)
-  {
-    const char* pszPrimeName = pOgr->GetAttrValue("PRIMEM");
-    if(pszPrimeName)
-      ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszPrimeName, (char**)apszGcsNameMappingBasedPrime, 3, (char**)keyNamesG, 1);
+    static const char *keyNamesG[] = {
+        "GEOGCS"};
+    int ret = -1;
+
+    const char* pszUnitName = pOgr->GetAttrValue( "GEOGCS|UNIT");
+    if(pszUnitName)
+        ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszUnitName, (char**)apszGcsNameMappingBasedOnUnit, 3, (char**)keyNamesG, 1);
     if(ret < 0)
-      ret = RemapNameBasedOnKeyName( pOgr, pszGeogCSName+4, "GEOGCS", (char**)apszGcsNameMapping);
-  }
-  if(ret < 0)
-  {
-    const char* pszProjCS = pOgr->GetAttrValue( "PROJCS" );
-    ret = RemapNamesBasedOnTwo( pOgr, pszProjCS, pszGeogCSName, (char**)apszGcsNameMappingBasedOnProjCS, 3, (char**)keyNamesG, 1);
-  }
-  return ret;
+    {
+        const char* pszPrimeName = pOgr->GetAttrValue("PRIMEM");
+        if(pszPrimeName)
+            ret = RemapNamesBasedOnTwo( pOgr, pszGeogCSName+4, pszPrimeName, (char**)apszGcsNameMappingBasedPrime, 3, (char**)keyNamesG, 1);
+        if(ret < 0)
+            ret = RemapNameBasedOnKeyName( pOgr, pszGeogCSName+4, "GEOGCS", (char**)apszGcsNameMapping);
+    }
+    if(ret < 0)
+    {
+        const char* pszProjCS = pOgr->GetAttrValue( "PROJCS" );
+        ret = RemapNamesBasedOnTwo( pOgr, pszProjCS, pszGeogCSName, (char**)apszGcsNameMappingBasedOnProjCS, 3, (char**)keyNamesG, 1);
+    }
+    return ret;
 }
 
 /************************************************************************/
@@ -2235,111 +2284,111 @@ int RemapGeogCSName( OGRSpatialReference* pOgr, const char *pszGeogCSName )
 
 OGRErr OGRSpatialReference::ImportFromESRIStatePlaneWKT(  int code, const char* datumName, const char* unitsName, int pcsCode, const char* csName )
 {
-  int i;
-  long searchCode = -1;
+    int i;
+    long searchCode = -1;
 
-  /* if the CS name is known */
-  if (code == 0 && !datumName && !unitsName && pcsCode == 32767 && csName)
-  {
-    char codeS[10];
-    if (FindCodeFromDict( "esri_StatePlane_extra.wkt", csName, codeS ) != OGRERR_NONE)
-      return OGRERR_FAILURE;
-    return importFromDict( "esri_StatePlane_extra.wkt", codeS);
-  }
-
-  /* Find state plane prj str by pcs code only */
-  if( code == 0 && !datumName && pcsCode != 32767 )
-  {
+    /* if the CS name is known */
+    if (code == 0 && !datumName && !unitsName && pcsCode == 32767 && csName)
+    {
+        char codeS[10];
+        if (FindCodeFromDict( "esri_StatePlane_extra.wkt", csName, codeS ) != OGRERR_NONE)
+            return OGRERR_FAILURE;
+        return importFromDict( "esri_StatePlane_extra.wkt", codeS);
+    }
 
-    int unitCode = 1;
-    if( EQUAL(unitsName, "international_feet") )
-      unitCode = 3;
-    else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
-      unitCode = 2;
-   for(i=0; statePlanePcsCodeToZoneCode[i] != 0; i+=2)
+    /* Find state plane prj str by pcs code only */
+    if( code == 0 && !datumName && pcsCode != 32767 )
     {
-      if( pcsCode == statePlanePcsCodeToZoneCode[i] )
-      {
-        searchCode = statePlanePcsCodeToZoneCode[i+1];
-        int unitIndex =  searchCode % 10;
-        if( (unitCode == 1 && !(unitIndex == 0 || unitIndex == 1)) 
-            || (unitCode == 2 && !(unitIndex == 2 || unitIndex == 3 || unitIndex == 4 ))
-            || (unitCode == 3 && !(unitIndex == 5 || unitIndex == 6 )) )
+
+        int unitCode = 1;
+        if( EQUAL(unitsName, "international_feet") )
+            unitCode = 3;
+        else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
+            unitCode = 2;
+        for(i=0; statePlanePcsCodeToZoneCode[i] != 0; i+=2)
         {
-          searchCode -= unitIndex; 
-          switch (unitIndex)
-          {
-          case 0:
-          case 3:
-          case 5:
-            if(unitCode == 2)
-              searchCode += 3;
-            else if(unitCode == 3)
-              searchCode += 5;
-            break;
-          case 1:
-          case 2:
-          case 6:
-            if(unitCode == 1)
-              searchCode += 1;
-            if(unitCode == 2)
-              searchCode += 2;
-            else if(unitCode == 3)
-              searchCode += 6;
-           break;
-          case 4:
-            if(unitCode == 2)
-              searchCode += 4;
-            break;
-          }
+            if( pcsCode == statePlanePcsCodeToZoneCode[i] )
+            {
+                searchCode = statePlanePcsCodeToZoneCode[i+1];
+                int unitIndex =  searchCode % 10;
+                if( (unitCode == 1 && !(unitIndex == 0 || unitIndex == 1)) 
+                    || (unitCode == 2 && !(unitIndex == 2 || unitIndex == 3 || unitIndex == 4 ))
+                    || (unitCode == 3 && !(unitIndex == 5 || unitIndex == 6 )) )
+                {
+                    searchCode -= unitIndex; 
+                    switch (unitIndex)
+                    {
+                      case 0:
+                      case 3:
+                      case 5:
+                        if(unitCode == 2)
+                            searchCode += 3;
+                        else if(unitCode == 3)
+                            searchCode += 5;
+                        break;
+                      case 1:
+                      case 2:
+                      case 6:
+                        if(unitCode == 1)
+                            searchCode += 1;
+                        if(unitCode == 2)
+                            searchCode += 2;
+                        else if(unitCode == 3)
+                            searchCode += 6;
+                        break;
+                      case 4:
+                        if(unitCode == 2)
+                            searchCode += 4;
+                        break;
+                    }
+                }
+                break;
+            }
         }
-        break;
-      }
-    }
-  }
-  else /* Find state plane prj str by all inputs. */
-  {
-    /* Need to have a specail EPSG-ESRI zone code mapping first. */
-    for(i=0; statePlaneZoneMapping[i] != 0; i+=3)
-    {
-      if( code == statePlaneZoneMapping[i] 
-       && (statePlaneZoneMapping[i+1] == -1 || pcsCode == statePlaneZoneMapping[i+1]))
-      {
-        code = statePlaneZoneMapping[i+2];
-        break;
-      }
     }
-    searchCode = (long)code * 10;
-    if(EQUAL(datumName, "HARN"))
+    else /* Find state plane prj str by all inputs. */
     {
-      if( EQUAL(unitsName, "international_feet") )
-        searchCode += 5;
-      else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
-        searchCode += 3;
-    }
-    else if(strstr(datumName, "NAD") && strstr(datumName, "83"))
-    {
-      if( EQUAL(unitsName, "meters") )
-         searchCode += 1;
-      else if( EQUAL(unitsName, "international_feet") )
-        searchCode += 6;
-      else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
-         searchCode += 2;
+        /* Need to have a specail EPSG-ESRI zone code mapping first. */
+        for(i=0; statePlaneZoneMapping[i] != 0; i+=3)
+        {
+            if( code == statePlaneZoneMapping[i] 
+                && (statePlaneZoneMapping[i+1] == -1 || pcsCode == statePlaneZoneMapping[i+1]))
+            {
+                code = statePlaneZoneMapping[i+2];
+                break;
+            }
+        }
+        searchCode = (long)code * 10;
+        if(EQUAL(datumName, "HARN"))
+        {
+            if( EQUAL(unitsName, "international_feet") )
+                searchCode += 5;
+            else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
+                searchCode += 3;
+        }
+        else if(strstr(datumName, "NAD") && strstr(datumName, "83"))
+        {
+            if( EQUAL(unitsName, "meters") )
+                searchCode += 1;
+            else if( EQUAL(unitsName, "international_feet") )
+                searchCode += 6;
+            else if( strstr(unitsName, "feet") || strstr(unitsName, "foot") )
+                searchCode += 2;
+        }
+        else if(strstr(datumName, "NAD") && strstr(datumName, "27") && !EQUAL(unitsName, "meters"))
+        {
+            searchCode += 4;
+        }
+        else
+            searchCode = -1;
     }
-    else if(strstr(datumName, "NAD") && strstr(datumName, "27") && !EQUAL(unitsName, "meters"))
+    if(searchCode > 0)
     {
-      searchCode += 4;
+        char codeS[10];
+        sprintf(codeS, "%d", (int)searchCode);
+        return importFromDict( "esri_StatePlane_extra.wkt", codeS);
     }
-    else
-      searchCode = -1;
-  }
-  if(searchCode > 0)
-  {
-    char codeS[10];
-    sprintf(codeS, "%d", (int)searchCode);
-    return importFromDict( "esri_StatePlane_extra.wkt", codeS);
-  }
-  return OGRERR_FAILURE;
+    return OGRERR_FAILURE;
 }
 
 /************************************************************************/
@@ -2350,39 +2399,39 @@ OGRErr OGRSpatialReference::ImportFromESRIStatePlaneWKT(  int code, const char*
 
 OGRErr OGRSpatialReference::ImportFromESRIWisconsinWKT( const char* prjName, double centralMeridian, double latOfOrigin, const char* unitsName, const char* csName )
 {
-  /* if the CS name is known */
-  if (!prjName && !unitsName && csName)
-  {
-    char codeS[10];
-    if (FindCodeFromDict( "esri_Wisconsin_extra.wkt", csName, codeS ) != OGRERR_NONE)
-      return OGRERR_FAILURE;
-    return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
-  }
-  double* tableWISCRS;
-  if(EQUALN(prjName, "Lambert_Conformal_Conic", 22))
-    tableWISCRS = apszWISCRS_LCC_meter;
-  else if(EQUAL(prjName, SRS_PT_TRANSVERSE_MERCATOR))
-    tableWISCRS = apszWISCRS_TM_meter;
-  else
-    return OGRERR_FAILURE;
-  int k = -1;
-  for(int i=0; tableWISCRS[i] != 0; i+=3)
-  {
-    if( fabs(centralMeridian - tableWISCRS[i]) <= 0.0000000001 && fabs(latOfOrigin - tableWISCRS[i+1]) <= 0.0000000001) 
+    /* if the CS name is known */
+    if (!prjName && !unitsName && csName)
     {
-      k = (long)tableWISCRS[i+2];
-      break;
+        char codeS[10];
+        if (FindCodeFromDict( "esri_Wisconsin_extra.wkt", csName, codeS ) != OGRERR_NONE)
+            return OGRERR_FAILURE;
+        return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
     }
-  }
-  if(k > 0)
-  {
-    if(!EQUAL(unitsName, "meters"))
-      k += 100;
-    char codeS[10];
-    sprintf(codeS, "%d", k);
-    return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
-  }
-  return OGRERR_FAILURE;
+    double* tableWISCRS;
+    if(EQUALN(prjName, "Lambert_Conformal_Conic", 22))
+        tableWISCRS = apszWISCRS_LCC_meter;
+    else if(EQUAL(prjName, SRS_PT_TRANSVERSE_MERCATOR))
+        tableWISCRS = apszWISCRS_TM_meter;
+    else
+        return OGRERR_FAILURE;
+    int k = -1;
+    for(int i=0; tableWISCRS[i] != 0; i+=3)
+    {
+        if( fabs(centralMeridian - tableWISCRS[i]) <= 0.0000000001 && fabs(latOfOrigin - tableWISCRS[i+1]) <= 0.0000000001) 
+        {
+            k = (long)tableWISCRS[i+2];
+            break;
+        }
+    }
+    if(k > 0)
+    {
+        if(!EQUAL(unitsName, "meters"))
+            k += 100;
+        char codeS[10];
+        sprintf(codeS, "%d", k);
+        return importFromDict( "esri_Wisconsin_extra.wkt", codeS);
+    }
+    return OGRERR_FAILURE;
 }
 
 /************************************************************************/
diff --git a/ogr/ogr_srs_esri_names.h b/ogr/ogr_srs_esri_names.h
index 8477c71..964aeab 100644
--- a/ogr/ogr_srs_esri_names.h
+++ b/ogr/ogr_srs_esri_names.h
@@ -214,6 +214,10 @@ static const char *apszParamNameMapping[] = {
 "Orthographic", "central_meridian", "Longitude_Of_Center",
 "Orthographic", "latitude_of_origin", "Latitude_Of_Center",
 "New_Zealand_Map_Grid", "central_meridian", "Longitude_Of_Origin",
+"Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "latitude_of_point_1", "Latitude_Of_1st_Point",
+"Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "longitude_of_point_1", "Longitude_Of_1st_Point",
+"Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "latitude_of_point_2", "Latitude_Of_2nd_Point",
+"Hotine_Oblique_Mercator_Two_Point_Natural_Origin", "longitude_of_point_2", "Longitude_Of_2nd_Point", 
 NULL, NULL, NULL};
 
 static const char *apszDeleteParametersBasedOnProjection[] = {
diff --git a/ogr/ogr_srs_ozi.cpp b/ogr/ogr_srs_ozi.cpp
index f020147..73e5a39 100644
--- a/ogr/ogr_srs_ozi.cpp
+++ b/ogr/ogr_srs_ozi.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_ozi.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_srs_ozi.cpp 28972 2015-04-22 10:39:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference translation from OziExplorer
@@ -33,74 +33,37 @@
 #include "cpl_conv.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: ogr_srs_ozi.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_srs_ozi.cpp 28972 2015-04-22 10:39:11Z rouault $");
 
 /************************************************************************/
 /*                          OSRImportFromOzi()                          */
 /************************************************************************/
 
-OGRErr OSRImportFromOzi( OGRSpatialReferenceH hSRS,
-                         const char *pszDatum, const char *pszProj,
-                         const char *pszProjParms )
-
-{
-    VALIDATE_POINTER1( hSRS, "OSRImportFromOzi", CE_Failure );
-
-    return ((OGRSpatialReference *) hSRS)->importFromOzi( pszDatum, pszProj,
-                                                          pszProjParms );
-}
-
-/************************************************************************/
-/*                            importFromOzi()                           */
-/************************************************************************/
-
-/**
- * Note : This method is obsolete, but has been kept to avoid breaking the API.
- *        It can be removed in GDAL 2.0
- */
-
 /**
  * Import coordinate system from OziExplorer projection definition.
  *
- * This method will import projection definition in style, used by
+ * This function will import projection definition in style, used by
  * OziExplorer software.
  *
- * This function is the equivalent of the C function OSRImportFromOzi().
- *
- * @param pszDatum Datum string. This is a fifth string in the
- * OziExplorer .MAP file.
- *
- * @param pszProj Projection string. Search for line starting with
- * "Map Projection" name in the OziExplorer .MAP file and supply it as a
- * whole in this parameter.
+ * Note: another version of this function with a different signature existed
+ * in GDAL 1.X.
  *
- * @param pszProjParms String containing projection parameters. Search for
- * "Projection Setup" name in the OziExplorer .MAP file and supply it as a
- * whole in this parameter.
+ * @param hSRS spatial reference object.
+ * @param papszLines Map file lines. This is an array of strings containing
+ * the whole OziExplorer .MAP file. The array is terminated by a NULL pointer.
  * 
  * @return OGRERR_NONE on success or an error code in case of failure. 
  *
- * @deprecated Use importFromOzi( const char * const* papszLines ) instead
+ * @since OGR 2.0
  */
 
-OGRErr OGRSpatialReference::importFromOzi( const char *pszDatum,
-                                           const char *pszProj,
-                                           const char *pszProjParms )
+OGRErr OSRImportFromOzi( OGRSpatialReferenceH hSRS,
+                         const char * const* papszLines )
 
 {
-    const char* papszLines[8];
-
-    // Fake
-    papszLines[0] = "";
-    papszLines[1] = "";
-    papszLines[2] = "";
-    papszLines[3] = "";
-    papszLines[4] = pszDatum; /* Must be in that position */
-    papszLines[5] = pszProj; /* Must be after 5th line */
-    papszLines[6] = pszProjParms; /* Must be after 5th line */
-    papszLines[7] = NULL;
-
-    return importFromOzi(papszLines);
+    VALIDATE_POINTER1( hSRS, "OSRImportFromOzi", CE_Failure );
+
+    return ((OGRSpatialReference *) hSRS)->importFromOzi( papszLines );
 }
 
 /************************************************************************/
diff --git a/ogr/ogr_srs_pci.cpp b/ogr/ogr_srs_pci.cpp
index e49b183..69dcd49 100644
--- a/ogr/ogr_srs_pci.cpp
+++ b/ogr/ogr_srs_pci.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_pci.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogr_srs_pci.cpp 28565 2015-02-27 10:26:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference translation to/from PCI georeferencing
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: ogr_srs_pci.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogr_srs_pci.cpp 28565 2015-02-27 10:26:21Z rouault $");
 
 typedef struct 
 {
@@ -270,7 +270,7 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
              || EQUALN( pszProj, "FOOT", 4 ) )
     {
         SetLocalCS( "FEET" );
-        SetLinearUnits( "FEET", atof(SRS_UL_FOOT_CONV) );
+        SetLinearUnits( "FEET", CPLAtof(SRS_UL_FOOT_CONV) );
     }
 
     else if( EQUALN( pszProj, "ACEA", 4 ) )
@@ -438,7 +438,7 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
 
         SetStatePlane( iZone, !bIsNAD27 );
         SetLinearUnitsAndUpdateParameters( SRS_UL_FOOT,
-                                           atof(SRS_UL_FOOT_CONV) );
+                                           CPLAtof(SRS_UL_FOOT_CONV) );
     }
 
     else if( EQUALN( pszProj, "SPAF", 4 ) )
@@ -449,7 +449,7 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
 
         SetStatePlane( iZone, !bIsNAD27 );
         SetLinearUnitsAndUpdateParameters( SRS_UL_US_FOOT,
-                                           atof(SRS_UL_US_FOOT_CONV) );
+                                           CPLAtof(SRS_UL_US_FOOT_CONV) );
     }
 
     else if( EQUALN( pszProj, "TM", 2 ) )
@@ -621,12 +621,7 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
                         {
                             dfSemiMajor = CPLAtof( papszLineItems[2] );
                             double dfSemiMinor = CPLAtof( papszLineItems[3] );
-
-                            if( ABS(dfSemiMajor - dfSemiMinor) < 0.01 )
-                                dfInvFlattening = 0.0;
-                            else
-                                dfInvFlattening = 
-                                    dfSemiMajor / (dfSemiMajor - dfSemiMinor);
+                            dfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
                             break;
                         }
                         CSLDestroy( papszLineItems );
@@ -644,16 +639,8 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
                 && padfPrjParams[0] != 0.0 )
             {
                 dfSemiMajor = padfPrjParams[0];
-
-                if( ABS(padfPrjParams[0] - padfPrjParams[1]) < 0.01 )
-                {
-                    dfInvFlattening = 0.0;
-                }
-                else
-                {
-                    dfInvFlattening =
-                        padfPrjParams[0]/(padfPrjParams[0]-padfPrjParams[1]);
-                }
+                double dfSemiMinor = padfPrjParams[1];
+                dfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
             }
 
 /* -------------------------------------------------------------------- */
@@ -732,7 +719,7 @@ OGRErr OGRSpatialReference::importFromPCI( const char *pszProj,
         if( EQUAL( pszUnits, "METRE" ) )
             SetLinearUnits( SRS_UL_METER, 1.0 );
         else if( EQUAL( pszUnits, "DEGREE" ) )
-            SetAngularUnits( SRS_UA_DEGREE, atof(SRS_UA_DEGREE_CONV) );
+            SetAngularUnits( SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV) );
         else
             SetLinearUnits( SRS_UL_METER, 1.0 );
     }
@@ -821,9 +808,9 @@ OGRErr OGRSpatialReference::exportToPCI( char **ppszProj, char **ppszUnits,
     double dfFromGreenwich = 0.0;
 
     if( poPRIMEM != NULL && poPRIMEM->GetChildCount() >= 2
-        && atof(poPRIMEM->GetChild(1)->GetValue()) != 0.0 )
+        && CPLAtof(poPRIMEM->GetChild(1)->GetValue()) != 0.0 )
     {
-        dfFromGreenwich = atof(poPRIMEM->GetChild(1)->GetValue());
+        dfFromGreenwich = CPLAtof(poPRIMEM->GetChild(1)->GetValue());
     }
 #endif
 
@@ -1190,13 +1177,7 @@ OGRErr OGRSpatialReference::exportToPCI( char **ppszProj, char **ppszUnits,
         {
             const char *pszCSV = CSVFilename( "pci_ellips.txt" );
             FILE *fp = NULL;
-            double dfSemiMinor;
-
-            if( dfInvFlattening == 0.0 )
-                dfSemiMinor = dfSemiMajor;
-            else
-                dfSemiMinor = dfSemiMajor * (1.0 - 1.0/dfInvFlattening);
-
+            double dfSemiMinor = OSRCalcSemiMinorFromInvFlattening(dfSemiMajor, dfInvFlattening);
 
             if( pszCSV )
                 fp = VSIFOpen( pszCSV, "r" );
@@ -1228,15 +1209,7 @@ OGRErr OGRSpatialReference::exportToPCI( char **ppszProj, char **ppszUnits,
         {                                   
             CPLPrintStringFill( szEarthModel, "E999", 4 );
             (*ppadfPrjParams)[0] = dfSemiMajor;
-            if ( ABS( dfInvFlattening ) < 0.000000000001 )
-            {
-                (*ppadfPrjParams)[1] = dfSemiMajor;
-            }
-            else
-            {
-                (*ppadfPrjParams)[1] =
-                    dfSemiMajor * (1.0 - 1.0/dfInvFlattening);
-            }
+            (*ppadfPrjParams)[1] = OSRCalcSemiMinorFromInvFlattening(dfSemiMajor, dfInvFlattening);
         }
     }
 
diff --git a/ogr/ogr_srs_proj4.cpp b/ogr/ogr_srs_proj4.cpp
index de8839e..1a6db83 100644
--- a/ogr/ogr_srs_proj4.cpp
+++ b/ogr/ogr_srs_proj4.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_proj4.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogr_srs_proj4.cpp 29114 2015-05-02 20:19:13Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference interface to PROJ.4.
@@ -32,10 +32,11 @@
 #include "ogr_spatialref.h"
 #include "ogr_p.h"
 #include "cpl_conv.h"
+#include <vector>
 
-extern int EPSGGetWGS84Transform( int nGeogCS, double *padfTransform );
+extern int EPSGGetWGS84Transform( int nGeogCS, std::vector<CPLString>& asTransform );
 
-CPL_CVSID("$Id: ogr_srs_proj4.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogr_srs_proj4.cpp 29114 2015-05-02 20:19:13Z rouault $");
 
 /* -------------------------------------------------------------------- */
 /*      The following list comes from osrs/proj/src/pj_ellps.c          */
@@ -382,7 +383,6 @@ OGRErr OGRSpatialReference::importFromProj4( const char * pszProj4 )
     int  i;
     char *pszCleanCopy;
     int   bAddProj4Extension = FALSE;
-    CPLLocaleC  oLocaleEnforcer;
 
 /* -------------------------------------------------------------------- */
 /*      Clear any existing definition.                                  */
@@ -935,6 +935,12 @@ OGRErr OGRSpatialReference::importFromProj4( const char * pszProj4 )
                    OSR_GDV( papszNV, "y_0", 0.0 ) );
     }
 
+    else if( EQUAL(pszProj,"qsc") )
+    {
+        SetQSC( OSR_GDV( papszNV, "lat_0", 0.0 ),
+                OSR_GDV( papszNV, "lon_0", 0.0 ) );
+    }
+
     else if( EQUAL(pszProj,"tpeqd") )
     {
         SetTPED( OSR_GDV( papszNV, "lat_1", 0.0 ), 
@@ -1018,11 +1024,7 @@ OGRErr OGRSpatialReference::importFromProj4( const char * pszProj4 )
             {
                 CPLAssert( EQUALN(ogr_pj_ellps[i+2],"b=",2) );
                 dfSemiMinor = CPLAtof(ogr_pj_ellps[i+2]+2);
-                
-                if( ABS(dfSemiMajor/dfSemiMinor) - 1.0 < 0.0000000000001 )
-                    dfInvFlattening = 0.0;
-                else
-                    dfInvFlattening = -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
+                dfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
             }
             
             SetGeogCS( ogr_pj_ellps[i+3], "unknown", ogr_pj_ellps[i], 
@@ -1079,10 +1081,7 @@ OGRErr OGRSpatialReference::importFromProj4( const char * pszProj4 )
 
         if( dfInvFlattening == -1.0 )
         {
-            if( ABS(dfSemiMajor/dfSemiMinor) - 1.0 < 0.0000000000001 )
-                dfInvFlattening = 0.0;
-            else
-                dfInvFlattening = -1.0 / (dfSemiMinor/dfSemiMajor - 1.0);
+            dfInvFlattening = OSRCalcInvFlattening(dfSemiMajor, dfSemiMinor);
         }
         
         SetGeogCS( "unnamed ellipse", "unknown", "unnamed",
@@ -1128,6 +1127,7 @@ OGRErr OGRSpatialReference::importFromProj4( const char * pszProj4 )
     if( pszValue != NULL )
     {
         SetExtension( "DATUM", "PROJ4_GRIDS", pszValue );
+        FixupOrdering();
     }
 
 /* -------------------------------------------------------------------- */
@@ -1417,7 +1417,7 @@ static const char *LinearToProj4( double dfLinearConv,
         return "in";
     
     else if( EQUAL(pszLinearUnits,SRS_UL_FOOT) 
-             || fabs(dfLinearConv - atof(SRS_UL_FOOT_CONV)) < 0.000000001 )
+             || fabs(dfLinearConv - CPLAtof(SRS_UL_FOOT_CONV)) < 0.000000001 )
         return "ft";
     
     else if( EQUAL(pszLinearUnits,"IYARD") || dfLinearConv == 0.9144 )
@@ -1433,7 +1433,7 @@ static const char *LinearToProj4( double dfLinearConv,
         return "cm";
 
     else if( EQUAL(pszLinearUnits,SRS_UL_US_FOOT) 
-             || fabs(dfLinearConv - atof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
+             || fabs(dfLinearConv - CPLAtof(SRS_UL_US_FOOT_CONV)) < 0.00000001 )
         return "us-ft";
 
     else if( EQUAL(pszLinearUnits,SRS_UL_NAUTICAL_MILE) )
@@ -1507,7 +1507,6 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 {
     char        szProj4[512];
     const char *pszProjection = GetAttrValue("PROJECTION");
-    CPLLocaleC  oLocaleEnforcer;
 
     szProj4[0] = '\0';
 
@@ -1548,11 +1547,11 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     if( pszProjection == NULL && IsGeographic() )
     {
-        sprintf( szProj4+strlen(szProj4), "+proj=longlat " );
+        CPLsprintf( szProj4+strlen(szProj4), "+proj=longlat " );
     }
     else if( IsGeocentric() )
     {
-        sprintf( szProj4+strlen(szProj4), "+proj=geocent " );
+        CPLsprintf( szProj4+strlen(szProj4), "+proj=geocent " );
     }
 
     else if( pszProjection == NULL && !IsGeographic() )
@@ -1563,7 +1562,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     }
     else if( EQUAL(pszProjection,SRS_PT_CYLINDRICAL_EQUAL_AREA) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=cea +lon_0=%.16g +lat_ts=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
@@ -1573,7 +1572,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_BONNE) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=bonne +lon_0=%.16g +lat_1=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
@@ -1583,7 +1582,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_CASSINI_SOLDNER) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=cass +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1593,7 +1592,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_NEW_ZEALAND_MAP_GRID) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=nzmg +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1613,7 +1612,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
         if( CSLTestBoolean(CPLGetConfigOption("OSR_USE_ETMERC", "FALSE")) )
         {
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=etmerc +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                      GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1624,14 +1623,14 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         else if( nZone != 0 )
         {
             if( bNorth )
-                sprintf( szProj4+strlen(szProj4), "+proj=utm +zone=%d ", 
+                CPLsprintf( szProj4+strlen(szProj4), "+proj=utm +zone=%d ", 
                          nZone );
             else
-                sprintf( szProj4+strlen(szProj4),"+proj=utm +zone=%d +south ", 
+                CPLsprintf( szProj4+strlen(szProj4),"+proj=utm +zone=%d +south ", 
                          nZone );
         }            
         else
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=tmerc +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                      GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1642,7 +1641,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_SOUTH_ORIENTED) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=tmerc +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g +axis=wsu ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1654,14 +1653,14 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     else if( EQUAL(pszProjection,SRS_PT_MERCATOR_1SP) )
     {
         if( GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0) == 0.0 )
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=merc +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                      GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
                      GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
                      GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
         else if( GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0) == 1.0 )
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=merc +lon_0=%.16g +lat_ts=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -1678,7 +1677,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_MERCATOR_2SP) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=merc +lon_0=%.16g +lat_ts=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
@@ -1686,9 +1685,29 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
                  GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
     }
 
+    else if( EQUAL(pszProjection,SRS_PT_MERCATOR_AUXILIARY_SPHERE) )
+    {
+       // This is EPSG:3875 Pseudo Mercator. No point in trying to parse the
+       // rest of the parameters, since we know pretty much everything at this
+       // stage.
+       CPLsprintf( szProj4+strlen(szProj4),
+		"+proj=merc +a=%.16g +b=%.16g +lat_ts=%.16g"
+		" +lon_0=%.16g +x_0=%.16g +y_0=%.16g +k=%.16g +units=m"
+		" +nadgrids=@null +wktext  +no_defs",
+		GetSemiMajor(), GetSemiMajor(),
+		GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
+		GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+		GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+		GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0),
+		GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0) );
+       *ppszProj4 = CPLStrdup( szProj4 );
+       
+       return OGRERR_NONE;
+    }
+
     else if( EQUAL(pszProjection,SRS_PT_OBLIQUE_STEREOGRAPHIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=sterea +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
 //         "+proj=stere +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -1700,7 +1719,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_STEREOGRAPHIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=stere +lat_0=%.16g +lon_0=%.16g +k=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1712,7 +1731,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     else if( EQUAL(pszProjection,SRS_PT_POLAR_STEREOGRAPHIC) )
     {
         if( GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0) >= 0.0 )
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=stere +lat_0=90 +lat_ts=%.16g +lon_0=%.16g "
                      "+k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,90.0),
@@ -1721,7 +1740,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
                      GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
                      GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
         else
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=stere +lat_0=-90 +lat_ts=%.16g +lon_0=%.16g "
                      "+k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,-90.0),
@@ -1733,7 +1752,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_EQUIRECTANGULAR) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eqc +lat_ts=%.16g +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -1744,7 +1763,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_GAUSSSCHREIBERTMERCATOR) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=gstmerc +lat_0=%.16g +lon_0=%.16g"
                  " +k_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,-21.116666667),
@@ -1756,7 +1775,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_GNOMONIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=gnom +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1766,7 +1785,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ORTHOGRAPHIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=ortho +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1776,7 +1795,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=laea +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1786,7 +1805,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_AZIMUTHAL_EQUIDISTANT) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=aeqd +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1796,7 +1815,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_EQUIDISTANT_CONIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eqdc +lat_0=%.16g +lon_0=%.16g +lat_1=%.16g +lat_2=%.16g"
                  " +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0),
@@ -1809,7 +1828,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_MILLER_CYLINDRICAL) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=mill +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g +R_A ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1819,7 +1838,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_MOLLWEIDE) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=moll +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1828,7 +1847,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_I) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck1 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1837,7 +1856,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_II) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck2 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1846,7 +1865,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_III) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck3 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1855,7 +1874,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_IV) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck4 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1864,7 +1883,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_V) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck5 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1873,7 +1892,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_VI) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=eck6 +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1882,7 +1901,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_POLYCONIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=poly +lat_0=%.16g +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
@@ -1892,7 +1911,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=aea +lat_1=%.16g +lat_2=%.16g +lat_0=%.16g +lon_0=%.16g"
                  " +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
@@ -1905,7 +1924,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_ROBINSON) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=robin +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1914,7 +1933,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_VANDERGRINTEN) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=vandg +lon_0=%.16g +x_0=%.16g +y_0=%.16g +R_A ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1923,7 +1942,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_SINUSOIDAL) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=sinu +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1932,7 +1951,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_GALL_STEREOGRAPHIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=gall +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1941,7 +1960,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_GOODE_HOMOLOSINE) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=goode +lon_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
@@ -1950,12 +1969,12 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_IGH) )
     {
-        sprintf( szProj4+strlen(szProj4), "+proj=igh " );
+        CPLsprintf( szProj4+strlen(szProj4), "+proj=igh " );
     }
 
     else if( EQUAL(pszProjection,SRS_PT_GEOSTATIONARY_SATELLITE) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=geos +lon_0=%.16g +h=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
                  GetNormProjParm(SRS_PP_SATELLITE_HEIGHT,35785831.0),
@@ -1966,7 +1985,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP)
              || EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=lcc +lat_1=%.16g +lat_2=%.16g +lat_0=%.16g +lon_0=%.16g"
                  " +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0),
@@ -1979,7 +1998,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=lcc +lat_1=%.16g +lat_0=%.16g +lon_0=%.16g"
                  " +k_0=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -1996,7 +2015,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         if( fabs(GetNormProjParm(SRS_PP_AZIMUTH,0.0) - 90.0) < 0.0001 
             && fabs(GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,0.0)-90.0) < 0.0001 )
         {
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=somerc +lat_0=%.16g +lon_0=%.16g"
                      " +k_0=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -2007,7 +2026,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         }
         else
         {
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=omerc +lat_0=%.16g +lonc=%.16g +alpha=%.16g"
                      " +k=%.16g +x_0=%.16g +y_0=%.16g +no_uoff ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -2021,7 +2040,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
             // Note that gamma is only supported by PROJ 4.8.0 and later.
             if( GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,1000.0) != 1000.0 )
             {
-                sprintf( szProj4+strlen(szProj4), "+gamma=%.16g ",
+                CPLsprintf( szProj4+strlen(szProj4), "+gamma=%.16g ",
                          GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,1000.0));
             }
         }
@@ -2033,7 +2052,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         if( fabs(GetNormProjParm(SRS_PP_AZIMUTH,0.0) - 90.0) < 0.0001 
             && fabs(GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,0.0)-90.0) < 0.0001 )
         {
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=somerc +lat_0=%.16g +lon_0=%.16g"
                      " +k_0=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -2044,7 +2063,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         }
         else
         {
-            sprintf( szProj4+strlen(szProj4),
+            CPLsprintf( szProj4+strlen(szProj4),
                      "+proj=omerc +lat_0=%.16g +lonc=%.16g +alpha=%.16g"
                      " +k=%.16g +x_0=%.16g +y_0=%.16g ",
                      GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -2058,7 +2077,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
             // Note that gamma is only supported by PROJ 4.8.0 and later.
             if( GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,1000.0) != 1000.0 )
             {
-                sprintf( szProj4+strlen(szProj4), "+gamma=%.16g ",
+                CPLsprintf( szProj4+strlen(szProj4), "+gamma=%.16g ",
                          GetNormProjParm(SRS_PP_RECTIFIED_GRID_ANGLE,1000.0));
             }
         }
@@ -2067,15 +2086,17 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     else if( EQUAL(pszProjection,
                    SRS_PT_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        // Not really clear which of Point_1/1st_Point convention is the
+        // "normalized" one, so accept both
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=omerc +lat_0=%.16g"
                  " +lon_1=%.16g +lat_1=%.16g +lon_2=%.16g +lat_2=%.16g"
                  " +k=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
-                 GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_1,0.0),
-                 GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_1,0.0),
-                 GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_2,0.0),
-                 GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_2,0.0),
+                 GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_1,GetNormProjParm(SRS_PP_LONGITUDE_OF_1ST_POINT,0.0)),
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_1,GetNormProjParm(SRS_PP_LATITUDE_OF_1ST_POINT,0.0)),
+                 GetNormProjParm(SRS_PP_LONGITUDE_OF_POINT_2,GetNormProjParm(SRS_PP_LONGITUDE_OF_2ND_POINT,0.0)),
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_POINT_2,GetNormProjParm(SRS_PP_LATITUDE_OF_2ND_POINT,0.0)),
                  GetNormProjParm(SRS_PP_SCALE_FACTOR,1.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
@@ -2083,7 +2104,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_KROVAK) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=krovak +lat_0=%.16g +lon_0=%.16g +alpha=%.16g"
                  " +k=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0),
@@ -2096,7 +2117,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection,SRS_PT_TWO_POINT_EQUIDISTANT) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=tpeqd +lat_1=%.16g +lon_1=%.16g "
                  "+lat_2=%.16g +lon_2=%.16g "
                  "+x_0=%.16g +y_0=%.16g ",
@@ -2110,7 +2131,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_IMW_POLYCONIC) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=iwm_p +lat_1=%.16g +lat_2=%.16g +lon_0=%.16g "
                  "+x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_1ST_POINT, 0.0),
@@ -2122,7 +2143,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_I) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag1 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
@@ -2130,7 +2151,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_II) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag2 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
@@ -2138,7 +2159,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_III) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag3 +lat_ts=%.16g +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
@@ -2147,7 +2168,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_IV) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag4 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
@@ -2155,7 +2176,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_V) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag5 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
@@ -2163,7 +2184,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_VI) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag6 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
@@ -2171,16 +2192,24 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
 
     else if( EQUAL(pszProjection, SRS_PT_WAGNER_VII) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=wag7 +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) );
     }
 
+    else if( EQUAL(pszProjection,SRS_PT_QSC) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=qsc +lat_0=%.16g +lon_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0) );
+    }
+
     /* Note: This never really gets used currently.  See bug 423 */
     else if( EQUAL(pszProjection,SRS_PT_SWISS_OBLIQUE_CYLINDRICAL) )
     {
-        sprintf( szProj4+strlen(szProj4),
+        CPLsprintf( szProj4+strlen(szProj4),
                  "+proj=somerc +lat_0=%.16g +lon_0=%.16g"
                  " +x_0=%.16g +y_0=%.16g ",
                  GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
@@ -2188,6 +2217,86 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
                  GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
                  GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
     }
+    else if( EQUAL(pszProjection,SRS_PT_AITOFF) )
+    {
+        //+lat_ts=0.0
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=aitoff +lat_0=%.16g +lon_0=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0) );
+    }
+ 
+    else if( EQUAL(pszProjection,SRS_PT_WINKEL_I) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=wink1 +lat_0=%.16g +lon_0=%.16g lat_ts=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,45.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
+
+    else if( EQUAL(pszProjection,SRS_PT_WINKEL_II) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=wink2 +lat_0=%.16g +lon_0=%.16g +lat_1=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,40.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
+
+    else if( EQUAL(pszProjection,SRS_PT_WINKEL_TRIPEL) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=wintri +lat_0=%.16g +lon_0=%.16g +lat_1=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,40.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
+
+    else if( EQUAL(pszProjection,SRS_PT_CRASTER_PARABOLIC) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=crast +lat_0=%.16g +lon_0=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
+
+    else if( EQUAL(pszProjection,SRS_PT_LOXIMUTHAL) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=loxim +lon_0=%.16g +lat_1=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,40.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
+
+    else if( EQUAL(pszProjection,SRS_PT_QUARTIC_AUTHALIC) )
+    {
+        CPLsprintf( szProj4+strlen(szProj4),
+                 "+proj=qua_aut +lat_0=%.16g +lon_0=%.16g"
+                 " +x_0=%.16g +y_0=%.16g ",
+                 GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0),
+                 GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_EASTING,0.0),
+                 GetNormProjParm(SRS_PP_FALSE_NORTHING,0.0));
+    }
 
     else
     {
@@ -2311,10 +2420,10 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
     char szEllipseDef[128];
 
     if( pszPROJ4Ellipse == NULL )
-        sprintf( szEllipseDef, "+a=%.16g +b=%.16g ",
+        CPLsprintf( szEllipseDef, "+a=%.16g +b=%.16g ",
                  GetSemiMajor(), GetSemiMinor() );
     else
-        sprintf( szEllipseDef, "+ellps=%s ",
+        CPLsprintf( szEllipseDef, "+ellps=%s ",
                  pszPROJ4Ellipse );
 
 /* -------------------------------------------------------------------- */
@@ -2409,17 +2518,17 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         // based on the EPSG GCS code.
         else if( nEPSGGeogCS != -1 && pszPROJ4Datum == NULL )
         {
-            double padfTransform[7];
-            if( EPSGGetWGS84Transform( nEPSGGeogCS, padfTransform ) )
+            std::vector<CPLString> asBursaTransform;
+            if( EPSGGetWGS84Transform( nEPSGGeogCS, asBursaTransform ) )
             {
-                sprintf( szTOWGS84, "+towgs84=%.16g,%.16g,%.16g,%.16g,%.16g,%.16g,%.16g",
-                         padfTransform[0],
-                         padfTransform[1],
-                         padfTransform[2],
-                         padfTransform[3],
-                         padfTransform[4],
-                         padfTransform[5],
-                         padfTransform[6] );
+                CPLsprintf( szTOWGS84, "+towgs84=%s,%s,%s,%s,%s,%s,%s",
+                         asBursaTransform[0].c_str(),
+                         asBursaTransform[1].c_str(),
+                         asBursaTransform[2].c_str(),
+                         asBursaTransform[3].c_str(),
+                         asBursaTransform[4].c_str(),
+                         asBursaTransform[5].c_str(),
+                         asBursaTransform[6].c_str() );
                 SAFE_PROJ4_STRCAT( szEllipseDef );
                 szEllipseDef[0] = '\0';
 
@@ -2468,7 +2577,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         }
         else
         {
-            sprintf( szPMValue, "%.16g", dfFromGreenwich );
+            CPLsprintf( szPMValue, "%.16g", dfFromGreenwich );
         }
 
         SAFE_PROJ4_STRCAT( "+pm=" );
@@ -2494,7 +2603,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         if( pszPROJ4Units == NULL )
         {
             char szLinearConv[128];
-            sprintf( szLinearConv, "%.16g", dfLinearConv );
+            CPLsprintf( szLinearConv, "%.16g", dfLinearConv );
             SAFE_PROJ4_STRCAT( "+to_meter=" );
             SAFE_PROJ4_STRCAT( szLinearConv );
             SAFE_PROJ4_STRCAT( " " );
@@ -2541,7 +2650,7 @@ OGRErr OGRSpatialReference::exportToProj4( char ** ppszProj4 ) const
         if( pszPROJ4Units == NULL )
         {
             char szLinearConv[128];
-            sprintf( szLinearConv, "%.16g", dfLinearConv );
+            CPLsprintf( szLinearConv, "%.16g", dfLinearConv );
             SAFE_PROJ4_STRCAT( "+vto_meter=" );
             SAFE_PROJ4_STRCAT( szLinearConv );
             SAFE_PROJ4_STRCAT( " " );
diff --git a/ogr/ogr_srs_usgs.cpp b/ogr/ogr_srs_usgs.cpp
index de0d50a..20fc4de 100644
--- a/ogr/ogr_srs_usgs.cpp
+++ b/ogr/ogr_srs_usgs.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_usgs.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_srs_usgs.cpp 28565 2015-02-27 10:26:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference translation to/from USGS georeferencing
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: ogr_srs_usgs.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_srs_usgs.cpp 28565 2015-02-27 10:26:21Z rouault $");
 
 /************************************************************************/
 /*  GCTP projection codes.                                              */
@@ -675,13 +675,7 @@ OGRErr OGRSpatialReference::importFromUSGS( long iProjSys, long iZone,
             {
                 if ( padfPrjParams[1] > 1.0 )
                 {
-                    if( ABS(padfPrjParams[0] - padfPrjParams[1]) < 0.01 )
-                        dfInvFlattening = 0.0;
-                    else
-                    {
-                        dfInvFlattening = padfPrjParams[0]
-                            / ( padfPrjParams[0] - padfPrjParams[1] );
-                    }
+                    dfInvFlattening = OSRCalcInvFlattening(padfPrjParams[0], padfPrjParams[1] );
                 }
                 else if ( padfPrjParams[1] > 0.0 )
                 {
diff --git a/ogr/ogr_srs_validate.cpp b/ogr/ogr_srs_validate.cpp
index 351fc77..17dbada 100644
--- a/ogr/ogr_srs_validate.cpp
+++ b/ogr/ogr_srs_validate.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_validate.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_srs_validate.cpp 27975 2014-11-17 12:37:48Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of the OGRSpatialReference::Validate() method and
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "osr_cs_wkt.h"
 
-CPL_CVSID("$Id: ogr_srs_validate.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_srs_validate.cpp 27975 2014-11-17 12:37:48Z rouault $");
 
 /* why would fipszone and zone be paramers when they relate to a composite
    projection which renders done into a non-zoned projection? */
@@ -127,6 +127,7 @@ static const char *papszProjectionSupported[] =
     SRS_PT_WAGNER_V,
     SRS_PT_WAGNER_VI,
     SRS_PT_WAGNER_VII,
+    SRS_PT_QSC,
     SRS_PT_GAUSSSCHREIBERTMERCATOR,
     SRS_PT_KROVAK,
     SRS_PT_CYLINDRICAL_EQUAL_AREA,
@@ -506,6 +507,11 @@ static const char *papszProjWithParms[] = {
     SRS_PP_FALSE_NORTHING,
     NULL,
 
+    SRS_PT_QSC,
+    SRS_PP_LATITUDE_OF_ORIGIN,
+    SRS_PP_CENTRAL_MERIDIAN,
+    NULL,
+
     SRS_PT_GAUSSSCHREIBERTMERCATOR,
     SRS_PP_LATITUDE_OF_ORIGIN,
     SRS_PP_CENTRAL_MERIDIAN,
@@ -1005,6 +1011,11 @@ OGRErr OGRSpatialReference::Validate(OGR_SRSNode *poRoot)
                 if (eErr != OGRERR_NONE)
                     return eErr;
             }
+            else if( EQUAL(poNode->GetValue(),"EXTENSION") )
+            {
+                // We do not try to control the sub-organization of 
+                // EXTENSION nodes.
+            }
             else if( EQUAL(poNode->GetValue(),"AUTHORITY") )
             {
                 OGRErr eErr = ValidateAuthority(poNode);
diff --git a/ogr/ogr_srs_xml.cpp b/ogr/ogr_srs_xml.cpp
index 04a60af..77bb663 100644
--- a/ogr/ogr_srs_xml.cpp
+++ b/ogr/ogr_srs_xml.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srs_xml.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogr_srs_xml.cpp 28767 2015-03-25 10:48:08Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGRSpatialReference interface to OGC XML (014r4).
@@ -218,7 +218,7 @@ static CPLXMLNode *addAuthorityIDBlock( CPLXMLNode *psTarget,
 /*      Prepare the codespace attribute.                                */
 /* -------------------------------------------------------------------- */
     CPLCreateXMLNode(
-        CPLCreateXMLNode( psName, CXT_Attribute, "gml:codeSpace" ),
+        CPLCreateXMLNode( psName, CXT_Attribute, "codeSpace" ),
         CXT_Text, szURN );
 
 /* -------------------------------------------------------------------- */
@@ -238,7 +238,7 @@ static CPLXMLNode *addAuthorityIDBlock( CPLXMLNode *psTarget,
 
 static void addGMLId( CPLXMLNode *psParent )
 {
-    static void *hGMLIdMutex = NULL;
+    static CPLMutex *hGMLIdMutex = NULL;
     CPLMutexHolderD( &hGMLIdMutex );
 
     /* CPLXMLNode *psId; */
@@ -304,7 +304,7 @@ static void addProjArg( const OGRSpatialReference *poSRS, CPLXMLNode *psBase,
 {
     CPLXMLNode *psNode, *psValue;
 
-    psNode = CPLCreateXMLNode( psBase, CXT_Element, "gml:usesParameterValue" );
+    psNode = CPLCreateXMLNode( psBase, CXT_Element, "gml:usesValue" );
 
 /* -------------------------------------------------------------------- */
 /*      Handle the UOM.                                                 */
@@ -319,7 +319,7 @@ static void addProjArg( const OGRSpatialReference *poSRS, CPLXMLNode *psBase,
     psValue = CPLCreateXMLNode( psNode, CXT_Element, "gml:value" );
 
     CPLCreateXMLNode( 
-        CPLCreateXMLNode( psValue, CXT_Attribute, "gml:uom" ),
+        CPLCreateXMLNode( psValue, CXT_Attribute, "uom" ),
         CXT_Text, pszUOMValue );
     
 /* -------------------------------------------------------------------- */
@@ -517,7 +517,7 @@ static CPLXMLNode *exportGeogCSToXML( const OGRSpatialReference *poSRS )
             CPLCreateXMLNode( psPM, CXT_Element, "gml:greenwichLongitude" ),
             CXT_Element, "gml:angle" );
     
-    CPLCreateXMLNode( CPLCreateXMLNode( psAngle, CXT_Attribute, "gml:uom" ),
+    CPLCreateXMLNode( CPLCreateXMLNode( psAngle, CXT_Attribute, "uom" ),
                       CXT_Text, "urn:ogc:def:uom:EPSG::9102" );
 
     CPLCreateXMLNode( psAngle, CXT_Text, 
@@ -550,7 +550,7 @@ static CPLXMLNode *exportGeogCSToXML( const OGRSpatialReference *poSRS )
         psParmXML = CPLCreateXMLNode( psEllipseXML, CXT_Element, 
                                       "gml:semiMajorAxis" );
 
-        CPLCreateXMLNode( CPLCreateXMLNode(psParmXML,CXT_Attribute,"gml:uom"),
+        CPLCreateXMLNode( CPLCreateXMLNode(psParmXML,CXT_Attribute,"uom"),
                           CXT_Text, "urn:ogc:def:uom:EPSG::9001" );
 
         CPLCreateXMLNode( psParmXML, CXT_Text, 
@@ -562,7 +562,7 @@ static CPLXMLNode *exportGeogCSToXML( const OGRSpatialReference *poSRS )
                                   "gml:secondDefiningParameter" ),
                 CXT_Element, "gml:inverseFlattening" );
         
-        CPLCreateXMLNode( CPLCreateXMLNode(psParmXML,CXT_Attribute,"gml:uom"),
+        CPLCreateXMLNode( CPLCreateXMLNode(psParmXML,CXT_Attribute,"uom"),
                           CXT_Text, "urn:ogc:def:uom:EPSG::9201" );
 
         CPLCreateXMLNode( psParmXML, CXT_Text, 
@@ -628,6 +628,9 @@ static CPLXMLNode *exportProjCSToXML( const OGRSpatialReference *poSRS )
     psConv = CPLCreateXMLNode( psDefinedBy, CXT_Element, "gml:Conversion");
     addGMLId( psConv );
 
+    CPLCreateXMLNode(CPLCreateXMLNode(psConv, CXT_Element, "gml:coordinateOperationName"),
+                     CXT_Text, pszProjection);
+    
 /* -------------------------------------------------------------------- */
 /*      Transverse Mercator                                             */
 /* -------------------------------------------------------------------- */
@@ -667,6 +670,12 @@ static CPLXMLNode *exportProjCSToXML( const OGRSpatialReference *poSRS )
         addProjArg( poSRS, psConv, "Linear", 0.0,
                     8807, SRS_PP_FALSE_NORTHING );
     }
+    
+    else
+    {
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "Unhandled projection method %s", pszProjection);
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Define the cartesian coordinate system.                         */
@@ -708,10 +717,10 @@ static CPLXMLNode *exportProjCSToXML( const OGRSpatialReference *poSRS )
  * will be assigned. 
  * @param pszDialect currently ignored. The dialect used is GML based.
  *
- * @return OGRERR_NONE on success or an error code on failure. 
+ * @return OGRERR_NONE on success or an error code on failure.
  */
 
-OGRErr OGRSpatialReference::exportToXML( char **ppszRawXML, 
+OGRErr OGRSpatialReference::exportToXML( char **ppszRawXML,
                                          CPL_UNUSED const char * pszDialect ) const
 {
     CPLXMLNode *psXMLTree = NULL;
@@ -991,7 +1000,7 @@ static double getProjectionParm( CPLXMLNode *psRootNode,
                                                    NULL );
 
             if( pszValue != NULL )
-                return atof(pszValue);
+                return CPLAtof(pszValue);
             else
                 return dfDefault;
         }
@@ -1032,7 +1041,7 @@ static double getNormalizedValue( CPLXMLNode *psNode, const char *pszPath,
     
     // Add normalization later.
 
-    return atof(psValueNode->pszValue);
+    return CPLAtof(psValueNode->pszValue);
 }
 
 /************************************************************************/
diff --git a/ogr/ogr_srsnode.cpp b/ogr/ogr_srsnode.cpp
index 5b6858b..efde2f0 100644
--- a/ogr/ogr_srsnode.cpp
+++ b/ogr/ogr_srsnode.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_srsnode.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_srsnode.cpp 27975 2014-11-17 12:37:48Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGR_SRSNode class.
@@ -31,7 +31,7 @@
 #include "ogr_spatialref.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogr_srsnode.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_srsnode.cpp 27975 2014-11-17 12:37:48Z rouault $");
 
 /************************************************************************/
 /*                            OGR_SRSNode()                             */
@@ -854,16 +854,16 @@ static const char * const apszPROJCSRule[] =
   NULL };
 
 static const char * const apszDATUMRule[] = 
-{ "DATUM", "SPHEROID", "TOWGS84", "AUTHORITY", NULL };
+{ "DATUM", "SPHEROID", "TOWGS84", "EXTENSION", "AUTHORITY", NULL };
 
 static const char * const apszGEOGCSRule[] = 
-{ "GEOGCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "AUTHORITY", NULL };
+{ "GEOGCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "EXTENSION", "AUTHORITY", NULL };
 
 static const char * const apszGEOCCSRule[] = 
 { "GEOCCS", "DATUM", "PRIMEM", "UNIT", "AXIS", "AUTHORITY", NULL };
 
 static const char * const apszVERTCSRule[] = 
-{ "VERT_CS", "VERT_DATUM", "UNIT", "AXIS", "AUTHORITY", NULL };
+{ "VERT_CS", "VERT_DATUM", "UNIT", "AXIS", "EXTENSION", "AUTHORITY", NULL };
 
 static const char * const *apszOrderingRules[] = {
     apszPROJCSRule, apszGEOGCSRule, apszDATUMRule, apszGEOCCSRule, apszVERTCSRule, NULL };
diff --git a/ogr/ograpispy.cpp b/ogr/ograpispy.cpp
new file mode 100644
index 0000000..b0f3969
--- /dev/null
+++ b/ogr/ograpispy.cpp
@@ -0,0 +1,1085 @@
+/******************************************************************************
+ * $Id: ograpispy.cpp 28808 2015-03-28 15:01:36Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  OGR C API "Spy"
+ * Author:   Even Rouault, even.rouault at spatialys.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "cpl_port.h"
+
+#include <stdio.h>
+#include <map>
+#include <set>
+
+#include "ograpispy.h"
+
+#include "gdal.h"
+#include "ogr_spatialref.h"
+#include "ogr_geometry.h"
+#include "ogr_feature.h"
+#include "ogrsf_frmts.h"
+#include "cpl_string.h"
+
+#ifdef OGRAPISPY_ENABLED
+
+int bOGRAPISpyEnabled = FALSE;
+static CPLString osSnapshotPath, osSpyFile;
+static FILE* fpSpyFile = NULL;
+extern "C" int CPL_DLL GDALIsInGlobalDestructor(void);
+
+class LayerDescription
+{
+    public:
+        int iLayer;
+
+        LayerDescription(): iLayer(-1) {}
+        LayerDescription(int iLayer): iLayer(iLayer) {}
+};
+
+class DatasetDescription
+{
+    public:
+        int iDS;
+        std::map<OGRLayerH, LayerDescription> oMapLayer;
+
+        DatasetDescription() : iDS(-1) {}
+        DatasetDescription(int iDS) : iDS(iDS) {}
+        ~DatasetDescription();
+};
+
+class FeatureDefnDescription
+{
+    public:
+        OGRFeatureDefnH hFDefn;
+        int iUniqueNumber;
+        std::map<OGRFieldDefnH, int> oMapFieldDefn;
+        std::map<OGRGeomFieldDefnH, int> oMapGeomFieldDefn;
+
+        FeatureDefnDescription(): hFDefn(NULL), iUniqueNumber(-1) {}
+        FeatureDefnDescription(OGRFeatureDefnH hFDefn, int iUniqueNumber): hFDefn(hFDefn), iUniqueNumber(iUniqueNumber) {}
+        void Free();
+};
+
+static std::map<OGRDataSourceH, DatasetDescription> oMapDS;
+static std::map<OGRLayerH, CPLString> oGlobalMapLayer;
+static OGRLayerH hLayerGetNextFeature = NULL;
+static OGRLayerH hLayerGetLayerDefn = NULL;
+static int bDeferGetFieldCount = FALSE;
+static int nGetNextFeatureCalls = 0;
+static std::set<CPLString> aoSetCreatedDS;
+static std::map<OGRFeatureDefnH, FeatureDefnDescription> oMapFDefn;
+static std::map<OGRGeomFieldDefnH, CPLString> oGlobalMapGeomFieldDefn;
+static std::map<OGRFieldDefnH, CPLString> oGlobalMapFieldDefn;
+
+void FeatureDefnDescription::Free()
+{
+    {
+        std::map<OGRGeomFieldDefnH, int>::iterator oIter = oMapGeomFieldDefn.begin();
+        for(; oIter != oMapGeomFieldDefn.end(); ++oIter)
+            oGlobalMapGeomFieldDefn.erase(oIter->first);
+    }
+    {
+        std::map<OGRFieldDefnH, int>::iterator oIter = oMapFieldDefn.begin();
+        for(; oIter != oMapFieldDefn.end(); ++oIter)
+            oGlobalMapFieldDefn.erase(oIter->first);
+    }
+}
+
+DatasetDescription::~DatasetDescription()
+{
+    std::map<OGRLayerH, LayerDescription>::iterator oIter = oMapLayer.begin();
+    for(; oIter != oMapLayer.end(); ++oIter)
+        oGlobalMapLayer.erase(oIter->first);
+}
+
+static void OGRAPISpyFileReopen()
+{
+    if( fpSpyFile == NULL )
+    {
+        fpSpyFile = fopen(osSpyFile, "ab");
+        if( fpSpyFile == NULL )
+            fpSpyFile = stderr;
+    }
+}
+
+static void OGRAPISpyFileClose()
+{
+    if( fpSpyFile != stdout && fpSpyFile != stderr )
+    {
+        fclose(fpSpyFile);
+        fpSpyFile = NULL;
+    }
+}
+
+static int OGRAPISpyEnabled()
+{
+    const char* pszSpyFile = CPLGetConfigOption("OGR_API_SPY_FILE", NULL);
+    bOGRAPISpyEnabled = (pszSpyFile != NULL);
+    if( !bOGRAPISpyEnabled )
+    {
+        osSpyFile.resize(0);
+        aoSetCreatedDS.clear();
+        return FALSE;
+    }
+    if( osSpyFile.size() )
+        return TRUE;
+
+    osSpyFile = pszSpyFile;
+
+    const char* pszSnapshotPath = CPLGetConfigOption("OGR_API_SPY_SNAPSHOT_PATH", ".");
+    if( EQUAL(pszSnapshotPath, "NO") )
+        osSnapshotPath = "";
+    else
+        osSnapshotPath = pszSnapshotPath;
+
+    if( EQUAL(pszSpyFile, "stdout") )
+        fpSpyFile = stdout;
+    else if( EQUAL(pszSpyFile, "stderr") )
+        fpSpyFile = stderr;
+    else
+        fpSpyFile = fopen(pszSpyFile, "wb");
+    if( fpSpyFile == NULL )
+        fpSpyFile = stderr;
+
+    fprintf(fpSpyFile, "# This file is generated by the OGR_API_SPY mechanism.\n");
+    fprintf(fpSpyFile, "from osgeo import ogr\n");
+    fprintf(fpSpyFile, "from osgeo import osr\n");
+    fprintf(fpSpyFile, "import os\n");
+    fprintf(fpSpyFile, "import shutil\n");
+    fprintf(fpSpyFile, "os.access\n"); // to make pyflakes happy in case it's unused later
+    fprintf(fpSpyFile, "shutil.copy\n"); // same here
+    fprintf(fpSpyFile, "\n");
+
+    return TRUE;
+}
+
+static CPLString OGRAPISpyGetOptions(char** papszOptions)
+{
+    CPLString options;
+    if( papszOptions == NULL )
+    {
+        options = "[]";
+    }
+    else
+    {
+        options = "[";
+        for(char** papszIter = papszOptions; *papszIter != NULL; papszIter++)
+        {
+            if( papszIter != papszOptions )
+                options += ", ";
+            options += "'";
+            options += *papszIter;
+            options += "'";
+        }
+        options += "]";
+    }
+
+    return options;
+}
+
+static CPLString OGRAPISpyGetString(const char* pszStr)
+{
+    if( pszStr == NULL )
+        return "None";
+    CPLString osRet = "'";
+    while( *pszStr )
+    {
+        if( *pszStr == '\'' )
+            osRet += "\\'";
+        else if( *pszStr == '\\' )
+            osRet += "\\\\";
+        else
+            osRet += *pszStr;
+        pszStr ++;
+    }
+    osRet += "'";
+    return osRet;
+}
+
+static CPLString OGRAPISpyGetDSVar(OGRDataSourceH hDS)
+{
+    if( hDS && oMapDS.find(hDS) == oMapDS.end() )
+    {
+        int i = (int)oMapDS.size() + 1;
+        oMapDS[hDS] = DatasetDescription(i);
+    }
+    return CPLSPrintf("ds%d", (hDS) ? oMapDS[hDS].iDS : 0);
+}
+
+static CPLString OGRAPISpyGetLayerVar(OGRLayerH hLayer)
+{
+    return oGlobalMapLayer[hLayer];
+}
+
+static CPLString OGRAPISpyGetAndRegisterLayerVar(OGRDataSourceH hDS,
+                                                 OGRLayerH hLayer)
+{
+    DatasetDescription& dd = oMapDS[hDS];
+    if( hLayer && dd.oMapLayer.find(hLayer) == dd.oMapLayer.end() )
+    {
+        int i = (int)dd.oMapLayer.size() + 1;
+        dd.oMapLayer[hLayer] = i;
+        oGlobalMapLayer[hLayer] = OGRAPISpyGetDSVar(hDS) + "_" + CPLSPrintf("lyr%d", i);
+    }
+    return OGRAPISpyGetDSVar(hDS) + "_" +
+           CPLSPrintf("lyr%d", (hLayer) ? dd.oMapLayer[hLayer].iLayer : 0);
+}
+
+static CPLString OGRAPISpyGetSRS(OGRSpatialReferenceH hSpatialRef)
+{
+    if (hSpatialRef == NULL)
+        return "None";
+
+    char* pszWKT = NULL;
+    ((OGRSpatialReference*)hSpatialRef)->exportToWkt(&pszWKT);
+    const char* pszRet = CPLSPrintf("osr.SpatialReference(\"\"\"%s\"\"\")", pszWKT);
+    CPLFree(pszWKT);
+    return pszRet;
+}
+
+static CPLString OGRAPISpyGetGeom(OGRGeometryH hGeom)
+{
+    if (hGeom == NULL)
+        return "None";
+
+    char* pszWKT = NULL;
+    ((OGRGeometry*)hGeom)->exportToWkt(&pszWKT);
+    const char* pszRet = CPLSPrintf("ogr.CreateGeometryFromWkt('%s')", pszWKT);
+    CPLFree(pszWKT);
+    return pszRet;
+}
+
+#define casePrefixOgrDot(x)  case x: return "ogr." #x;
+
+static CPLString OGRAPISpyGetGeomType(OGRwkbGeometryType eType)
+{
+    switch(eType)
+    {
+        casePrefixOgrDot(wkbUnknown)
+        casePrefixOgrDot(wkbPoint)
+        casePrefixOgrDot(wkbLineString)
+        casePrefixOgrDot(wkbPolygon)
+        casePrefixOgrDot(wkbMultiPoint)
+        casePrefixOgrDot(wkbMultiLineString)
+        casePrefixOgrDot(wkbMultiPolygon)
+        casePrefixOgrDot(wkbGeometryCollection)
+        casePrefixOgrDot(wkbCircularString)
+        casePrefixOgrDot(wkbCompoundCurve)
+        casePrefixOgrDot(wkbCurvePolygon)
+        casePrefixOgrDot(wkbMultiCurve)
+        casePrefixOgrDot(wkbMultiSurface)
+        casePrefixOgrDot(wkbNone)
+        casePrefixOgrDot(wkbLinearRing)
+        casePrefixOgrDot(wkbCircularStringZ)
+        casePrefixOgrDot(wkbCompoundCurveZ)
+        casePrefixOgrDot(wkbCurvePolygonZ)
+        casePrefixOgrDot(wkbMultiCurveZ)
+        casePrefixOgrDot(wkbMultiSurfaceZ)
+        casePrefixOgrDot(wkbPoint25D)
+        casePrefixOgrDot(wkbLineString25D)
+        casePrefixOgrDot(wkbPolygon25D)
+        casePrefixOgrDot(wkbMultiPoint25D)
+        casePrefixOgrDot(wkbMultiLineString25D)
+        casePrefixOgrDot(wkbMultiPolygon25D)
+        casePrefixOgrDot(wkbGeometryCollection25D)
+    }
+    return "error";
+}
+
+static CPLString OGRAPISpyGetFieldType(OGRFieldType eType)
+{
+    switch(eType)
+    {
+        casePrefixOgrDot(OFTInteger)
+        casePrefixOgrDot(OFTInteger64)
+        casePrefixOgrDot(OFTIntegerList)
+        casePrefixOgrDot(OFTInteger64List)
+        casePrefixOgrDot(OFTReal)
+        casePrefixOgrDot(OFTRealList)
+        casePrefixOgrDot(OFTString)
+        casePrefixOgrDot(OFTStringList)
+        casePrefixOgrDot(OFTWideString)
+        casePrefixOgrDot(OFTWideStringList)
+        casePrefixOgrDot(OFTBinary)
+        casePrefixOgrDot(OFTDate)
+        casePrefixOgrDot(OFTTime)
+        casePrefixOgrDot(OFTDateTime)
+    }
+    return "error";
+}
+
+static CPLString OGRAPISpyGetFeatureDefnVar(OGRFeatureDefnH hFDefn)
+{
+    std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter = oMapFDefn.find(hFDefn);
+    int i;
+    if( oIter == oMapFDefn.end() )
+    {
+        i = (int)oMapFDefn.size() + 1;
+        oMapFDefn[hFDefn] = FeatureDefnDescription(hFDefn, i);
+        ((OGRFeatureDefn*)hFDefn)->Reference(); // so that we can check when they are no longer used
+    }
+    else
+        i = oIter->second.iUniqueNumber;
+    return CPLSPrintf("fdefn%d", i);
+}
+
+static void OGRAPISpyFlushDefered()
+{
+    OGRAPISpyFileReopen();
+    if( hLayerGetLayerDefn != NULL )
+    {
+        OGRFeatureDefnH hDefn = (OGRFeatureDefnH)(((OGRLayer*)hLayerGetLayerDefn)->GetLayerDefn());
+        fprintf(fpSpyFile, "%s = %s.GetLayerDefn()\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            OGRAPISpyGetLayerVar(hLayerGetLayerDefn).c_str());
+
+        if( bDeferGetFieldCount )
+        {
+            fprintf(fpSpyFile, "%s.GetFieldCount()\n",
+                    OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
+            bDeferGetFieldCount = FALSE;
+        }
+
+        hLayerGetLayerDefn = NULL;
+    }
+
+    if( nGetNextFeatureCalls == 1)
+    {
+        fprintf(fpSpyFile, "%s.GetNextFeature()\n",
+            OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
+        hLayerGetNextFeature = NULL;
+        nGetNextFeatureCalls = 0;
+    }
+    else if( nGetNextFeatureCalls > 0)
+    {
+        fprintf(fpSpyFile, "for i in range(%d):\n", nGetNextFeatureCalls);
+        fprintf(fpSpyFile, "    %s.GetNextFeature()\n",
+            OGRAPISpyGetLayerVar(hLayerGetNextFeature).c_str());
+        hLayerGetNextFeature = NULL;
+        nGetNextFeatureCalls = 0;
+    }
+}
+
+int OGRAPISpyOpenTakeSnapshot(const char* pszName, int bUpdate)
+{
+    if( !OGRAPISpyEnabled() || !bUpdate || osSnapshotPath.size() == 0 ||
+        aoSetCreatedDS.find(pszName) != aoSetCreatedDS.end() )
+        return -1;
+    OGRAPISpyFlushDefered();
+
+    VSIStatBufL sStat;
+    if( VSIStatL( pszName, &sStat ) == 0 )
+    {
+        GDALDatasetH hDS = GDALOpenEx(pszName, GDAL_OF_VECTOR, NULL, NULL, NULL);
+        if( hDS )
+        {
+            char** papszFileList = ((GDALDataset*)hDS)->GetFileList();
+            GDALClose(hDS);
+            if( papszFileList )
+            {
+                int i = 1;
+                CPLString osBaseDir;
+                CPLString osSrcDir;
+                CPLString osWorkingDir;
+                while(TRUE)
+                {
+                    osBaseDir = CPLFormFilename(osSnapshotPath,
+                                        CPLSPrintf("snapshot_%d", i), NULL );
+                    if( VSIStatL( osBaseDir, &sStat ) != 0 )
+                        break;
+                    i++;
+                }
+                VSIMkdir( osBaseDir, 0777 );
+                osSrcDir = CPLFormFilename( osBaseDir, "source", NULL );
+                VSIMkdir( osSrcDir, 0777 );
+                osWorkingDir = CPLFormFilename( osBaseDir, "working", NULL );
+                VSIMkdir( osWorkingDir, 0777 );
+                fprintf(fpSpyFile, "# Take snapshot of %s\n", pszName);
+                fprintf(fpSpyFile, "try:\n");
+                fprintf(fpSpyFile, "    shutil.rmtree('%s')\n", osWorkingDir.c_str());
+                fprintf(fpSpyFile, "except:\n");
+                fprintf(fpSpyFile, "    pass\n");
+                fprintf(fpSpyFile, "os.mkdir('%s')\n", osWorkingDir.c_str());
+                for(char** papszIter = papszFileList; *papszIter; papszIter++)
+                {
+                    CPLString osSnapshotSrcFile = CPLFormFilename(
+                            osSrcDir, CPLGetFilename(*papszIter), NULL);
+                    CPLString osSnapshotWorkingFile = CPLFormFilename(
+                            osWorkingDir, CPLGetFilename(*papszIter), NULL);
+                    CPLCopyFile( osSnapshotSrcFile, *papszIter );
+                    CPLCopyFile( osSnapshotWorkingFile, *papszIter );
+                    fprintf(fpSpyFile, "shutil.copy('%s', '%s')\n",
+                            osSnapshotSrcFile.c_str(),
+                            osSnapshotWorkingFile.c_str());
+                }
+                CSLDestroy(papszFileList);
+                return i;
+            }
+        }
+    }
+    return -1;
+}
+
+void OGRAPISpyOpen(const char* pszName, int bUpdate, int iSnapshot, GDALDatasetH* phDS)
+{
+    if( !OGRAPISpyEnabled() ) return;
+    OGRAPISpyFlushDefered();
+
+    CPLString osName;
+    if( iSnapshot > 0 )
+    {
+        CPLString osBaseDir = CPLFormFilename(osSnapshotPath,
+                                   CPLSPrintf("snapshot_%d", iSnapshot), NULL );
+        CPLString osWorkingDir = CPLFormFilename( osBaseDir, "working", NULL );
+        osName = CPLFormFilename(osWorkingDir, CPLGetFilename(pszName), NULL);
+        pszName = osName.c_str();
+
+        if( *phDS != NULL )
+        {
+            GDALClose( (GDALDatasetH) *phDS );
+            *phDS = GDALOpenEx(pszName, GDAL_OF_VECTOR | GDAL_OF_UPDATE, NULL, NULL, NULL);
+        }
+    }
+
+    if( *phDS != NULL )
+        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar((OGRDataSourceH) *phDS).c_str());
+    fprintf(fpSpyFile, "ogr.Open(%s, update = %d)\n",
+            OGRAPISpyGetString(pszName).c_str(), bUpdate);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpyPreClose(OGRDataSourceH hDS)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "ds%d = None\n", oMapDS[hDS].iDS);
+    oMapDS.erase(hDS);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpyPostClose(CPL_UNUSED OGRDataSourceH hDS)
+{
+    if( !GDALIsInGlobalDestructor() )
+    {
+        std::map<OGRFeatureDefnH, FeatureDefnDescription>::iterator oIter =
+                                                                oMapFDefn.begin();
+        std::vector<OGRFeatureDefnH> oArray;
+        for(; oIter != oMapFDefn.end(); ++oIter)
+        {
+            FeatureDefnDescription& featureDefnDescription = oIter->second;
+            if( ((OGRFeatureDefn*)featureDefnDescription.hFDefn)->GetReferenceCount() == 1 )
+            {
+                oArray.push_back(featureDefnDescription.hFDefn);
+            }
+        }
+        for(size_t i = 0; i < oArray.size(); i++)
+        {
+            FeatureDefnDescription& featureDefnDescription = oMapFDefn[oArray[i]];
+            ((OGRFeatureDefn*)featureDefnDescription.hFDefn)->Release();
+            featureDefnDescription.Free();
+            oMapFDefn.erase(oArray[i]);
+        }
+    }
+}
+
+void OGRAPISpyCreateDataSource(OGRSFDriverH hDriver, const char* pszName,
+                               char** papszOptions, OGRDataSourceH hDS)
+{
+    if( !OGRAPISpyEnabled() ) return;
+    OGRAPISpyFlushDefered();
+    if( hDS != NULL )
+        fprintf(fpSpyFile, "%s = ", OGRAPISpyGetDSVar(hDS).c_str());
+    fprintf(fpSpyFile, "ogr.GetDriverByName('%s').CreateDataSource(%s, options = %s)\n",
+            GDALGetDriverShortName((GDALDriverH)hDriver),
+            OGRAPISpyGetString(pszName).c_str(),
+            OGRAPISpyGetOptions(papszOptions).c_str());
+    if( hDS != NULL )
+    {
+        aoSetCreatedDS.insert(pszName);
+    }
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpyDeleteDataSource(OGRSFDriverH hDriver, const char* pszName)
+{
+    if( !OGRAPISpyEnabled() ) return;
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "ogr.GetDriverByName('%s').DeleteDataSource(%s)\n",
+            GDALGetDriverShortName((GDALDriverH)hDriver),
+            OGRAPISpyGetString(pszName).c_str());
+    aoSetCreatedDS.erase(pszName);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_GetLayer( OGRDataSourceH hDS, int iLayer, OGRLayerH hLayer )
+{
+    OGRAPISpyFlushDefered();
+    if( hLayer != NULL )
+        fprintf(fpSpyFile, "%s = ",
+            OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
+    fprintf(fpSpyFile, "%s.GetLayer(%d)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(),
+            iLayer);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_GetLayerCount( OGRDataSourceH hDS )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetLayerCount()\n", OGRAPISpyGetDSVar(hDS).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_GetLayerByName( OGRDataSourceH hDS, const char* pszLayerName,
+                                  OGRLayerH hLayer )
+{
+    OGRAPISpyFlushDefered();
+    if( hLayer != NULL )
+        fprintf(fpSpyFile, "%s = ",
+            OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
+    fprintf(fpSpyFile, "%s.GetLayerByName(%s)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(),
+            OGRAPISpyGetString(pszLayerName).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_ExecuteSQL( OGRDataSourceH hDS, 
+                              const char *pszStatement,
+                              OGRGeometryH hSpatialFilter,
+                              const char *pszDialect,
+                              OGRLayerH hLayer)
+{
+    OGRAPISpyFlushDefered();
+    if( hLayer != NULL )
+        fprintf(fpSpyFile, "%s = ",
+            OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
+    fprintf(fpSpyFile, "%s.ExecuteSQL(%s, %s, %s)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(),
+            OGRAPISpyGetString(pszStatement).c_str(),
+            OGRAPISpyGetGeom(hSpatialFilter).c_str(),
+            OGRAPISpyGetString(pszDialect).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_ReleaseResultSet( OGRDataSourceH hDS, OGRLayerH hLayer)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.ReleaseResultSet(%s)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(),
+            (hLayer) ? OGRAPISpyGetLayerVar(hLayer).c_str() : "None");
+
+    DatasetDescription& dd = oMapDS[hDS];
+    dd.oMapLayer.erase(hLayer);
+    oGlobalMapLayer.erase(hLayer);
+
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_CreateLayer( OGRDataSourceH hDS, 
+                               const char * pszName,
+                               OGRSpatialReferenceH hSpatialRef,
+                               OGRwkbGeometryType eType,
+                               char ** papszOptions,
+                               OGRLayerH hLayer)
+{
+    OGRAPISpyFlushDefered();
+    if( hLayer != NULL )
+        fprintf(fpSpyFile, "%s = ",
+            OGRAPISpyGetAndRegisterLayerVar(hDS, hLayer).c_str());
+    fprintf(fpSpyFile, "%s.CreateLayer(%s, srs = %s, geom_type = %s, options = %s)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(),
+            OGRAPISpyGetString(pszName).c_str(),
+            OGRAPISpyGetSRS(hSpatialRef).c_str(),
+            OGRAPISpyGetGeomType(eType).c_str(),
+            OGRAPISpyGetOptions(papszOptions).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_DS_DeleteLayer( OGRDataSourceH hDS, int iLayer )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.DeleteLayer(%d)\n",
+            OGRAPISpyGetDSVar(hDS).c_str(), iLayer);
+    // Should perhaps remove from the maps
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_Dataset_StartTransaction( GDALDatasetH hDS, int bForce )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.StartTransaction(%d)\n",
+            OGRAPISpyGetDSVar((OGRDataSourceH)hDS).c_str(), bForce);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_Dataset_CommitTransaction( GDALDatasetH hDS )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.CommitTransaction()\n",
+            OGRAPISpyGetDSVar((OGRDataSourceH)hDS).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_Dataset_RollbackTransaction( GDALDatasetH hDS )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.RollbackTransaction()\n",
+            OGRAPISpyGetDSVar((OGRDataSourceH)hDS).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_GetFeatureCount( OGRLayerH hLayer, int bForce )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetFeatureCount(force = %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_GetExtent( OGRLayerH hLayer, int bForce )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetExtent(force = %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), bForce);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_GetExtentEx( OGRLayerH hLayer, int iGeomField, int bForce )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetExtent(geom_field = %d, force = %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), iGeomField, bForce);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetAttributeFilter( OGRLayerH hLayer, const char* pszFilter )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.SetAttributeFilter(%s)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            OGRAPISpyGetString(pszFilter).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_GetFeature( OGRLayerH hLayer, GIntBig nFeatureId )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetFeature(" CPL_FRMT_GIB ")\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), nFeatureId);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetNextByIndex( OGRLayerH hLayer, GIntBig nIndex )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.SetNextByIndex(" CPL_FRMT_GIB ")\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), nIndex);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_GetNextFeature( OGRLayerH hLayer )
+{
+    if( hLayerGetNextFeature != hLayer )
+    {
+        OGRAPISpyFlushDefered();
+        OGRAPISpyFileClose();
+    }
+    hLayerGetNextFeature = hLayer;
+    nGetNextFeatureCalls++;
+}
+
+static void OGRAPISpyDumpFeature( OGRFeatureH hFeat )
+{
+    OGRFeature* poFeature = (OGRFeature*) hFeat;
+
+    fprintf(fpSpyFile, "f = ogr.Feature(%s)\n",
+            OGRAPISpyGetFeatureDefnVar((OGRFeatureDefnH)(poFeature->GetDefnRef())).c_str());
+    if( poFeature->GetFID() != -1 )
+        fprintf(fpSpyFile, "f.SetFID(" CPL_FRMT_GIB ")\n", poFeature->GetFID());
+    int i;
+    for(i = 0; i < poFeature->GetFieldCount(); i++)
+    {
+        if( poFeature->IsFieldSet(i) )
+        {
+            switch( poFeature->GetFieldDefnRef(i)->GetType())
+            {
+                case OFTInteger: fprintf(fpSpyFile, "f.SetField(%d, %d)\n", i,
+                    poFeature->GetFieldAsInteger(i)); break;
+                case OFTReal: fprintf(fpSpyFile, "%s", CPLSPrintf("f.SetField(%d, %.16g)\n", i,
+                    poFeature->GetFieldAsDouble(i))); break;
+                case OFTString: fprintf(fpSpyFile, "f.SetField(%d, %s)\n", i,
+                    OGRAPISpyGetString(poFeature->GetFieldAsString(i)).c_str()); break;
+                default: fprintf(fpSpyFile, "f.SetField(%d, %s) #FIXME\n", i,
+                    OGRAPISpyGetString(poFeature->GetFieldAsString(i)).c_str()); break;
+            }
+        }
+    }
+    for(i = 0; i < poFeature->GetGeomFieldCount(); i++)
+    {
+        OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
+        if( poGeom != NULL )
+        {
+            fprintf(fpSpyFile, "f.SetGeomField(%d, %s)\n", i, OGRAPISpyGetGeom(
+                (OGRGeometryH)poGeom ).c_str() ); 
+        }
+    }
+    const char* pszStyleString = poFeature->GetStyleString();
+    if( pszStyleString != NULL )
+        fprintf(fpSpyFile, "f.SetStyleString(%s)\n",
+                OGRAPISpyGetString(pszStyleString).c_str() ); 
+}
+
+void OGRAPISpy_L_SetFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
+{
+    OGRAPISpyFlushDefered();
+    OGRAPISpyDumpFeature(hFeat);
+    fprintf(fpSpyFile, "%s.SetFeature(f)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str());
+    fprintf(fpSpyFile, "f = None\n"); /* in case layer defn is changed afterwards */
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
+{
+    OGRAPISpyFlushDefered();
+    OGRAPISpyDumpFeature(hFeat);
+    fprintf(fpSpyFile, "%s.CreateFeature(f)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str());
+    fprintf(fpSpyFile, "f = None\n"); /* in case layer defn is changed afterwards */
+    OGRAPISpyFileClose();
+}
+
+static void OGRAPISpyDumpFieldDefn( OGRFieldDefn* poFieldDefn )
+{
+    fprintf(fpSpyFile, "fd = ogr.FieldDefn(%s, %s)\n",
+            OGRAPISpyGetString(poFieldDefn->GetNameRef()).c_str(),
+            OGRAPISpyGetFieldType(poFieldDefn->GetType()).c_str());
+    if( poFieldDefn->GetWidth() > 0 )
+        fprintf(fpSpyFile, "fd.SetWidth(%d)\n", poFieldDefn->GetWidth() );
+    if( poFieldDefn->GetPrecision() > 0 )
+        fprintf(fpSpyFile, "fd.SetPrecision(%d)\n", poFieldDefn->GetPrecision() );
+    if( !poFieldDefn->IsNullable() )
+        fprintf(fpSpyFile, "fd.SetNullable(0)\n");
+    if( poFieldDefn->GetDefault() != NULL )
+        fprintf(fpSpyFile, "fd.SetDefault(%s)\n",
+                OGRAPISpyGetString(poFieldDefn->GetDefault()).c_str());
+}
+
+void OGRAPISpy_L_CreateField( OGRLayerH hLayer, OGRFieldDefnH hField, 
+                              int bApproxOK )
+{
+    OGRAPISpyFlushDefered();
+    OGRFieldDefn* poFieldDefn = (OGRFieldDefn*) hField;
+    OGRAPISpyDumpFieldDefn(poFieldDefn);
+    fprintf(fpSpyFile, "%s.CreateField(fd, approx_ok = %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_DeleteField( OGRLayerH hLayer, int iField )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.DeleteField(%d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), iField);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_ReorderFields( OGRLayerH hLayer, int* panMap )
+{
+    OGRAPISpyFlushDefered();
+    OGRLayer* poLayer = (OGRLayer*) hLayer;
+    fprintf(fpSpyFile, "%s.ReorderFields([",
+            OGRAPISpyGetLayerVar(hLayer).c_str());
+    for( int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
+    {
+        if( i > 0 ) fprintf(fpSpyFile, ", ");
+        fprintf(fpSpyFile, "%d", panMap[i]);
+    }
+    fprintf(fpSpyFile, "])\n");
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_ReorderField( OGRLayerH hLayer, int iOldFieldPos,
+                               int iNewFieldPos )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.ReorderField(%d, %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), iOldFieldPos, iNewFieldPos);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_AlterFieldDefn( OGRLayerH hLayer, int iField,
+                                 OGRFieldDefnH hNewFieldDefn, int nFlags )
+{
+    OGRAPISpyFlushDefered();
+    OGRFieldDefn* poFieldDefn = (OGRFieldDefn*) hNewFieldDefn;
+    OGRAPISpyDumpFieldDefn(poFieldDefn);
+    fprintf(fpSpyFile, "%s.AlterFieldDefn(%d, fd, %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), iField, nFlags);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_CreateGeomField( OGRLayerH hLayer, OGRGeomFieldDefnH hField, 
+                                  int bApproxOK )
+{
+    OGRAPISpyFlushDefered();
+    OGRGeomFieldDefn* poGeomFieldDefn = (OGRGeomFieldDefn*) hField;
+    fprintf(fpSpyFile, "geom_fd = ogr.GeomFieldDefn(%s, %s)\n",
+            OGRAPISpyGetString(poGeomFieldDefn->GetNameRef()).c_str(),
+            OGRAPISpyGetGeomType(poGeomFieldDefn->GetType()).c_str());
+    if( poGeomFieldDefn->GetSpatialRef() != NULL )
+        fprintf(fpSpyFile, "geom_fd.SetSpatialRef(%s)\n", OGRAPISpyGetSRS(
+            (OGRSpatialReferenceH)poGeomFieldDefn->GetSpatialRef()).c_str() );
+    if( !poGeomFieldDefn->IsNullable() )
+        fprintf(fpSpyFile, "geom_fd.SetNullable(0)\n");
+    fprintf(fpSpyFile, "%s.CreateGeomField(geom_fd, approx_ok = %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), bApproxOK);
+    OGRAPISpyFileClose();
+}
+
+static void OGRAPISpy_L_Op( OGRLayerH hLayer, const char* pszMethod )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.%s()\n", OGRAPISpyGetLayerVar(hLayer).c_str(), pszMethod);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_StartTransaction( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "StartTransaction"); }
+void OGRAPISpy_L_CommitTransaction( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "CommitTransaction"); }
+void OGRAPISpy_L_RollbackTransaction( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "RollbackTransaction"); }
+
+void OGRAPISpy_L_GetLayerDefn( OGRLayerH hLayer )
+{
+    if( hLayer != hLayerGetLayerDefn )
+    {
+        OGRAPISpyFlushDefered();
+        hLayerGetLayerDefn = hLayer;
+        OGRAPISpyFileClose();
+    }
+}
+
+void OGRAPISpy_L_GetSpatialRef( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetSpatialRef"); }
+void OGRAPISpy_L_GetSpatialFilter( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetSpatialFilter"); }
+void OGRAPISpy_L_ResetReading( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "ResetReading"); }
+void OGRAPISpy_L_SyncToDisk( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "SyncToDisk"); }
+void OGRAPISpy_L_GetFIDColumn( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetFIDColumn"); }
+void OGRAPISpy_L_GetGeometryColumn( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetGeometryColumn"); }
+void OGRAPISpy_L_GetName( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetName"); }
+void OGRAPISpy_L_GetGeomType( OGRLayerH hLayer ) { OGRAPISpy_L_Op(hLayer, "GetGeomType"); }
+
+void OGRAPISpy_L_FindFieldIndex( OGRLayerH hLayer, const char *pszFieldName,
+                                 int bExactMatch )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.FindFieldIndex(%s, %d)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            OGRAPISpyGetString(pszFieldName).c_str(), bExactMatch);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_TestCapability( OGRLayerH hLayer, const char* pszCap )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.TestCapability(%s)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            OGRAPISpyGetString(pszCap).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetSpatialFilter( OGRLayerH hLayer, OGRGeometryH hGeom )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.SetSpatialFilter(%s)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            OGRAPISpyGetGeom(hGeom).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetSpatialFilterEx( OGRLayerH hLayer, int iGeomField,
+                                     OGRGeometryH hGeom )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.SetSpatialFilter(%d, %s)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            iGeomField,
+            OGRAPISpyGetGeom(hGeom).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetSpatialFilterRect( OGRLayerH hLayer,
+                                       double dfMinX, double dfMinY, 
+                                       double dfMaxX, double dfMaxY)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s", CPLSPrintf("%s.SetSpatialFilterRect(%.16g, %.16g, %.16g, %.16g)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            dfMinX, dfMinY, dfMaxX, dfMaxY));
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetSpatialFilterRectEx( OGRLayerH hLayer, int iGeomField,
+                                         double dfMinX, double dfMinY, 
+                                         double dfMaxX, double dfMaxY)
+{
+
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s", CPLSPrintf("%s.SetSpatialFilterRect(%d, "
+            "%.16g, %.16g, %.16g, %.16g)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            iGeomField,
+            dfMinX, dfMinY, dfMaxX, dfMaxY));
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_DeleteFeature( OGRLayerH hLayer, GIntBig nFID )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.DeleteFeature(" CPL_FRMT_GIB ")\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(), nFID);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_L_SetIgnoredFields( OGRLayerH hLayer,
+                                   const char** papszIgnoredFields )
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.SetIgnoredFields(%s)\n",
+            OGRAPISpyGetLayerVar(hLayer).c_str(),
+            OGRAPISpyGetOptions((char**)papszIgnoredFields).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetGeomType(OGRFeatureDefnH hDefn)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetGeomType()\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetFieldCount(OGRFeatureDefnH hDefn)
+{
+    if( hLayerGetLayerDefn != NULL &&
+        (OGRFeatureDefnH)(((OGRLayer*)hLayerGetLayerDefn)->GetLayerDefn()) == hDefn )
+    {
+        bDeferGetFieldCount = TRUE;
+    }
+    else
+    {
+        OGRAPISpyFlushDefered();
+        fprintf(fpSpyFile, "%s.GetFieldCount()\n",
+                OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
+        OGRAPISpyFileClose();
+    }
+}
+
+void OGRAPISpy_FD_GetFieldDefn(OGRFeatureDefnH hDefn, int iField,
+                               OGRFieldDefnH hField)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s_fielddefn%d = %s.GetFieldDefn(%d)\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            iField,
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            iField);
+
+    std::map<OGRFieldDefnH, CPLString>::iterator oIter =
+                            oGlobalMapFieldDefn.find(hField);
+    if( oIter == oGlobalMapFieldDefn.end() )
+    {
+        oMapFDefn[hDefn].oMapFieldDefn[hField] = iField;
+        oGlobalMapFieldDefn[hField] = CPLSPrintf("%s_fielddefn%d",
+                                                     OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+                                                     iField);
+    }
+
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetFieldIndex(OGRFeatureDefnH hDefn, const char* pszFieldName)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetFieldIndex(%s)\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            OGRAPISpyGetString(pszFieldName).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_Fld_GetXXXX(OGRFieldDefnH hField, const char* pszOp)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.%s()\n",
+            oGlobalMapFieldDefn[hField].c_str(), pszOp);
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetGeomFieldCount(OGRFeatureDefnH hDefn)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetGeomFieldCount()\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField,
+                                   OGRGeomFieldDefnH hGeomField)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s_geomfielddefn%d = %s.GetGeomFieldDefn(%d)\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            iGeomField,
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            iGeomField);
+
+    std::map<OGRGeomFieldDefnH, CPLString>::iterator oIter =
+                            oGlobalMapGeomFieldDefn.find(hGeomField);
+    if( oIter == oGlobalMapGeomFieldDefn.end() )
+    {
+        oMapFDefn[hDefn].oMapGeomFieldDefn[hGeomField] = iGeomField;
+        oGlobalMapGeomFieldDefn[hGeomField] = CPLSPrintf("%s_geomfielddefn%d",
+                                                     OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+                                                     iGeomField);
+    }
+
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_FD_GetGeomFieldIndex(OGRFeatureDefnH hDefn, const char* pszFieldName)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.GetGeomFieldIndex(%s)\n",
+            OGRAPISpyGetFeatureDefnVar(hDefn).c_str(),
+            OGRAPISpyGetString(pszFieldName).c_str());
+    OGRAPISpyFileClose();
+}
+
+void OGRAPISpy_GFld_GetXXXX(OGRGeomFieldDefnH hGeomField, const char* pszOp)
+{
+    OGRAPISpyFlushDefered();
+    fprintf(fpSpyFile, "%s.%s()\n",
+            oGlobalMapGeomFieldDefn[hGeomField].c_str(), pszOp);
+    OGRAPISpyFileClose();
+}
+
+#endif /* OGRAPISPY_ENABLED */
diff --git a/ogr/ograpispy.h b/ogr/ograpispy.h
new file mode 100644
index 0000000..1b7174d
--- /dev/null
+++ b/ogr/ograpispy.h
@@ -0,0 +1,173 @@
+/******************************************************************************
+ * $Id: ograpispy.h 28807 2015-03-28 14:46:31Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  OGR C API "Spy"
+ * Author:   Even Rouault, even.rouault at spatialys.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGRAPISPY_H_INCLUDED
+#define _OGRAPISPY_H_INCLUDED
+
+#include "gdal.h"
+
+/**
+ * \file ograpispy.h
+ * 
+ * OGR C API spy.
+ *
+ * If GDAL is compiled with OGRAPISPY_ENABLED defined (which is the case for a
+ * DEBUG build), a mechanism to trace calls to the OGR *C* API is available
+ * (calls to the C++ API will not be traced)
+ *
+ * Provided there is compile-time support, the mechanism must also be enabled at
+ * runtime by setting the OGR_API_SPY_FILE configuration option
+ * to a file where the calls to the OGR C API will be dumped (stdout and stderr
+ * are recognized as special strings to name the standard output and error files).
+ * The traced calls are outputted as a OGR Python script.
+ *
+ * Only calls that may have side-effects to the behaviour of drivers are traced.
+ *
+ * If a file-based datasource is open in update mode, a snapshot of its initial
+ * state is stored in a 'snapshot' directory, and then a copy of it is made as
+ * the working datasource. That way, the generated script can be executed in a
+ * reproducible way. The path for snapshots is the current working directory by
+ * default, and can be changed by setting the OGR_API_SPY_SNAPSHOT_PATH
+ * configuration option. If it is set to NO, the snapshot feature will be disabled.
+ * The reliability of snapshoting relies on if the dataset correctly implements
+ * GetFileList() (for multi-file datasources)
+ *
+ * @since GDAL 2.0
+ */
+
+
+#ifdef DEBUG
+#define OGRAPISPY_ENABLED
+#endif
+
+#ifdef OGRAPISPY_ENABLED
+
+CPL_C_START
+
+extern int bOGRAPISpyEnabled;
+
+int OGRAPISpyOpenTakeSnapshot(const char* pszName, int bUpdate);
+void OGRAPISpyOpen(const char* pszName, int bUpdate, int iSnapshot,
+                   GDALDatasetH* phDS);
+void OGRAPISpyPreClose(OGRDataSourceH hDS);
+void OGRAPISpyPostClose(OGRDataSourceH hDS);
+void OGRAPISpyCreateDataSource(OGRSFDriverH hDriver, const char* pszName,
+                               char** papszOptions, OGRDataSourceH hDS);
+void OGRAPISpyDeleteDataSource(OGRSFDriverH hDriver, const char* pszName);
+
+void OGRAPISpy_DS_GetLayerCount( OGRDataSourceH hDS );
+void OGRAPISpy_DS_GetLayer( OGRDataSourceH hDS, int iLayer, OGRLayerH hLayer );
+void OGRAPISpy_DS_GetLayerByName( OGRDataSourceH hDS, const char* pszLayerName,
+                                  OGRLayerH hLayer );
+void OGRAPISpy_DS_ExecuteSQL( OGRDataSourceH hDS, 
+                              const char *pszStatement,
+                              OGRGeometryH hSpatialFilter,
+                              const char *pszDialect,
+                              OGRLayerH hLayer);
+void OGRAPISpy_DS_ReleaseResultSet( OGRDataSourceH hDS, OGRLayerH hLayer);
+
+void OGRAPISpy_DS_CreateLayer( OGRDataSourceH hDS, 
+                               const char * pszName,
+                               OGRSpatialReferenceH hSpatialRef,
+                               OGRwkbGeometryType eType,
+                               char ** papszOptions,
+                               OGRLayerH hLayer);
+void OGRAPISpy_DS_DeleteLayer( OGRDataSourceH hDS, int iLayer );
+
+void OGRAPISpy_Dataset_StartTransaction( GDALDatasetH hDS, int bForce );
+void OGRAPISpy_Dataset_CommitTransaction( GDALDatasetH hDS );
+void OGRAPISpy_Dataset_RollbackTransaction( GDALDatasetH hDS );
+
+void OGRAPISpy_L_GetFeatureCount( OGRLayerH hLayer, int bForce );
+void OGRAPISpy_L_GetExtent( OGRLayerH hLayer, int bForce );
+void OGRAPISpy_L_GetExtentEx( OGRLayerH hLayer, int iGeomField, int bForce );
+void OGRAPISpy_L_SetAttributeFilter( OGRLayerH hLayer, const char* pszFilter );
+void OGRAPISpy_L_GetFeature( OGRLayerH hLayer, GIntBig nFeatureId );
+void OGRAPISpy_L_SetNextByIndex( OGRLayerH hLayer, GIntBig nIndex );
+void OGRAPISpy_L_GetNextFeature( OGRLayerH hLayer );
+void OGRAPISpy_L_SetFeature( OGRLayerH hLayer, OGRFeatureH hFeat );
+void OGRAPISpy_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat );
+void OGRAPISpy_L_CreateField( OGRLayerH hLayer, OGRFieldDefnH hField, 
+                              int bApproxOK );
+void OGRAPISpy_L_DeleteField( OGRLayerH hLayer, int iField );
+void OGRAPISpy_L_ReorderFields( OGRLayerH hLayer, int* panMap );
+void OGRAPISpy_L_ReorderField( OGRLayerH hLayer, int iOldFieldPos,
+                               int iNewFieldPos );
+void OGRAPISpy_L_AlterFieldDefn( OGRLayerH hLayer, int iField,
+                                 OGRFieldDefnH hNewFieldDefn,
+                                 int nFlags );
+void OGRAPISpy_L_CreateGeomField( OGRLayerH hLayer, OGRGeomFieldDefnH hField, 
+                                  int bApproxOK );
+void OGRAPISpy_L_StartTransaction( OGRLayerH hLayer );
+void OGRAPISpy_L_CommitTransaction( OGRLayerH hLayer );
+void OGRAPISpy_L_RollbackTransaction( OGRLayerH hLayer );
+void OGRAPISpy_L_GetLayerDefn( OGRLayerH hLayer );
+void OGRAPISpy_L_FindFieldIndex( OGRLayerH hLayer, const char *pszFieldName,
+                                 int bExactMatch );
+void OGRAPISpy_L_GetSpatialRef( OGRLayerH hLayer );
+void OGRAPISpy_L_TestCapability( OGRLayerH hLayer, const char* pszCap );
+void OGRAPISpy_L_GetSpatialFilter( OGRLayerH hLayer );
+void OGRAPISpy_L_SetSpatialFilter( OGRLayerH hLayer, OGRGeometryH hGeom );
+void OGRAPISpy_L_SetSpatialFilterEx( OGRLayerH hLayer, int iGeomField,
+                                     OGRGeometryH hGeom );
+void OGRAPISpy_L_SetSpatialFilterRect( OGRLayerH hLayer,
+                                       double dfMinX, double dfMinY, 
+                                       double dfMaxX, double dfMaxY);
+void OGRAPISpy_L_SetSpatialFilterRectEx( OGRLayerH hLayer, int iGeomField,
+                                         double dfMinX, double dfMinY, 
+                                         double dfMaxX, double dfMaxY);
+void OGRAPISpy_L_ResetReading( OGRLayerH hLayer );
+void OGRAPISpy_L_SyncToDisk( OGRLayerH hLayer );
+void OGRAPISpy_L_DeleteFeature( OGRLayerH hLayer, GIntBig nFID );
+void OGRAPISpy_L_GetFIDColumn( OGRLayerH hLayer );
+void OGRAPISpy_L_GetGeometryColumn( OGRLayerH hLayer );
+void OGRAPISpy_L_GetName( OGRLayerH hLayer );
+void OGRAPISpy_L_GetGeomType( OGRLayerH hLayer );
+void OGRAPISpy_L_SetIgnoredFields( OGRLayerH hLayer,
+                                   const char** papszIgnoredFields );
+
+void OGRAPISpy_FD_GetGeomType(OGRFeatureDefnH hDefn);
+void OGRAPISpy_FD_GetFieldCount(OGRFeatureDefnH hDefn);
+void OGRAPISpy_FD_GetFieldDefn(OGRFeatureDefnH hDefn, int iField,
+                               OGRFieldDefnH hGeomField);
+void OGRAPISpy_FD_GetFieldIndex(OGRFeatureDefnH hDefn, const char* pszFieldName);
+
+void OGRAPISpy_Fld_GetXXXX(OGRFieldDefnH hField, const char* pszOp);
+
+void OGRAPISpy_FD_GetGeomFieldCount(OGRFeatureDefnH hDefn);
+void OGRAPISpy_FD_GetGeomFieldDefn(OGRFeatureDefnH hDefn, int iGeomField,
+                                   OGRGeomFieldDefnH hGeomField);
+void OGRAPISpy_FD_GetGeomFieldIndex(OGRFeatureDefnH hDefn, const char* pszFieldName);
+void OGRAPISpy_GFld_GetXXXX(OGRGeomFieldDefnH hGeomField, const char* pszOp);
+
+CPL_C_END
+
+#endif /* OGRAPISPY_ENABLED */
+
+#endif /*  _OGRAPISPY_H_INCLUDED */
diff --git a/ogr/ogrcircularstring.cpp b/ogr/ogrcircularstring.cpp
new file mode 100644
index 0000000..5221d57
--- /dev/null
+++ b/ogr/ogrcircularstring.cpp
@@ -0,0 +1,715 @@
+/******************************************************************************
+ * $Id: ogrcircularstring.cpp 28005 2014-11-26 10:04:43Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRCircularString geometry class.
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2010, 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include <assert.h>
+#include <vector>
+
+CPL_CVSID("$Id");
+
+/************************************************************************/
+/*                         OGRCircularString()                          */
+/************************************************************************/
+
+/**
+ * \brief Create an empty circular string.
+ */
+
+OGRCircularString::OGRCircularString()
+
+{
+}
+
+/************************************************************************/
+/*                        ~OGRCircularString()                          */
+/************************************************************************/
+
+OGRCircularString::~OGRCircularString()
+
+{
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRCircularString::getGeometryType() const
+
+{
+    if( getCoordinateDimension() == 3 )
+        return wkbCircularStringZ;
+    else
+        return wkbCircularString;
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRCircularString::getGeometryName() const
+
+{
+    return "CIRCULARSTRING";
+}
+
+/************************************************************************/
+/*                           importFromWkb()                            */
+/*                                                                      */
+/*      Initialize from serialized stream in well known binary          */
+/*      format.                                                         */
+/************************************************************************/
+
+OGRErr OGRCircularString::importFromWkb( unsigned char * pabyData,
+                                         int nSize,
+                                         OGRwkbVariant eWkbVariant )
+
+{
+    OGRErr eErr = OGRSimpleCurve::importFromWkb(pabyData, nSize, eWkbVariant);
+    if (eErr == OGRERR_NONE)
+    {
+        if (!IsValidFast())
+        {
+            empty();
+            return OGRERR_CORRUPT_DATA;
+        }
+    }
+    return eErr;
+}
+
+/************************************************************************/
+/*                            exportToWkb()                             */
+/*                                                                      */
+/*      Build a well known binary representation of this object.        */
+/************************************************************************/
+
+OGRErr  OGRCircularString::exportToWkb( OGRwkbByteOrder eByteOrder,
+                                        unsigned char * pabyData,
+                                        OGRwkbVariant eWkbVariant  ) const
+
+{
+    if (!IsValidFast())
+    {
+        return OGRERR_FAILURE;
+    }
+
+    if( eWkbVariant == wkbVariantOldOgc ) /* does not make sense for new geometries, so patch it */
+        eWkbVariant = wkbVariantIso;
+    return OGRSimpleCurve::exportToWkb(eByteOrder, pabyData, eWkbVariant);
+}
+
+/************************************************************************/
+/*                           importFromWkt()                            */
+/*                                                                      */
+/*      Instantiate from well known text format.  Currently this is     */
+/*      `CIRCULARSTRING [Z] ( x y [z], x y [z], ...)',                  */
+/************************************************************************/
+
+OGRErr OGRCircularString::importFromWkt( char ** ppszInput )
+
+{
+    OGRErr eErr = OGRSimpleCurve::importFromWkt(ppszInput);
+    if (eErr == OGRERR_NONE)
+    {
+        if (!IsValidFast())
+        {
+            empty();
+            return OGRERR_CORRUPT_DATA;
+        }
+    }
+    return eErr;
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+
+OGRErr OGRCircularString::exportToWkt( char ** ppszDstText,
+                                       CPL_UNUSED OGRwkbVariant eWkbVariant ) const
+
+{
+    if (!IsValidFast())
+    {
+        return OGRERR_FAILURE;
+    }
+
+    return OGRSimpleCurve::exportToWkt(ppszDstText, wkbVariantIso);
+}
+
+/************************************************************************/
+/*                             get_Length()                             */
+/*                                                                      */
+/*      For now we return a simple euclidian 2D distance.               */
+/************************************************************************/
+
+double OGRCircularString::get_Length() const
+
+{
+    double dfLength = 0.0;
+    double R, cx, cy, alpha0, alpha1, alpha2;
+    int i;
+    for(i=0;i<nPointCount-2;i+=2)
+    {
+        double x0 = paoPoints[i].x, y0 = paoPoints[i].y,
+               x1 = paoPoints[i+1].x, y1 = paoPoints[i+1].y,
+               x2 = paoPoints[i+2].x, y2 = paoPoints[i+2].y;
+        if( OGRGeometryFactory::GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                                            R, cx, cy, alpha0, alpha1, alpha2) )
+        {
+            dfLength += fabs(alpha2 - alpha0) * R;
+        }
+        else
+        {
+            dfLength += sqrt((x2-x0)*(x2-x0)+(y2-y0)*(y2-y0));
+        }
+    }
+    return dfLength;
+}
+
+/************************************************************************/
+/*                       ExtendEnvelopeWithCircular()                   */
+/************************************************************************/
+
+void OGRCircularString::ExtendEnvelopeWithCircular( OGREnvelope * psEnvelope ) const
+{
+    if( !IsValidFast() || nPointCount == 0 )
+        return;
+
+    /* Loop through circular portions and determine if they include some */
+    /* extremities of the circle */
+    for(int i=0;i<nPointCount-2;i+=2)
+    {
+        double x0 = paoPoints[i].x, y0 = paoPoints[i].y,
+               x1 = paoPoints[i+1].x, y1 = paoPoints[i+1].y,
+               x2 = paoPoints[i+2].x, y2 = paoPoints[i+2].y;
+        double R, cx, cy, alpha0, alpha1, alpha2;
+        if( OGRGeometryFactory::GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                                            R, cx, cy, alpha0, alpha1, alpha2))
+        {
+            int quadrantStart = (int)floor(alpha0 / (M_PI / 2));
+            int quadrantEnd  = (int)floor(alpha2 / (M_PI / 2));
+            if( quadrantStart > quadrantEnd )
+            {
+                int tmp = quadrantStart;
+                quadrantStart = quadrantEnd;
+                quadrantEnd = tmp;
+            }
+            /* Transition trough quadrants in counter-clock wise direction */
+            for( int j=quadrantStart+1; j<=quadrantEnd; j++)
+            {
+                switch( ((j+8)%4) )
+                {
+                    case 0:
+                        psEnvelope->MaxX = MAX(psEnvelope->MaxX, cx + R);
+                        break;
+                    case 1:
+                        psEnvelope->MaxY = MAX(psEnvelope->MaxY, cy + R);
+                        break;
+                    case 2:
+                        psEnvelope->MinX = MIN(psEnvelope->MinX, cx - R);
+                        break;
+                    case 3:
+                        psEnvelope->MinY = MIN(psEnvelope->MaxY, cy - R);
+                        break;
+                    default:
+                        CPLAssert(FALSE);
+                        break;
+                }
+            }
+        }
+    }
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCircularString::getEnvelope( OGREnvelope * psEnvelope ) const
+
+{
+    OGRSimpleCurve::getEnvelope(psEnvelope);
+    ExtendEnvelopeWithCircular(psEnvelope);
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCircularString::getEnvelope( OGREnvelope3D * psEnvelope ) const
+
+{
+    OGRSimpleCurve::getEnvelope(psEnvelope);
+    ExtendEnvelopeWithCircular(psEnvelope);
+}
+
+/************************************************************************/
+/*                     OGRCircularString::segmentize()                  */
+/************************************************************************/
+
+void OGRCircularString::segmentize( double dfMaxLength )
+{
+    if( !IsValidFast() || nPointCount == 0 )
+        return;
+
+    /* So as to make sure that the same line followed in both directions */
+    /* result in the same segmentized line */
+    if ( paoPoints[0].x < paoPoints[nPointCount - 1].x ||
+         (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
+          paoPoints[0].y < paoPoints[nPointCount - 1].y) )
+    {
+        reversePoints();
+        segmentize(dfMaxLength);
+        reversePoints();
+    }
+
+    std::vector<OGRRawPoint> aoRawPoint;
+    std::vector<double> adfZ;
+    for(int i=0;i<nPointCount-2;i+=2)
+    {
+        double x0 = paoPoints[i].x, y0 = paoPoints[i].y,
+               x1 = paoPoints[i+1].x, y1 = paoPoints[i+1].y,
+               x2 = paoPoints[i+2].x, y2 = paoPoints[i+2].y;
+        double R, cx, cy, alpha0, alpha1, alpha2;
+
+        aoRawPoint.push_back(OGRRawPoint(x0,y0));
+        if( padfZ )
+            adfZ.push_back(padfZ[i]);
+
+        /* We have strong constraints on the number of intermediate points */
+        /* we can add */
+
+        if( OGRGeometryFactory::GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                                            R, cx, cy, alpha0, alpha1, alpha2) )
+        {
+            /* It is an arc circle */
+            double dfSegmentLength1 = fabs(alpha1 - alpha0) * R;
+            double dfSegmentLength2 = fabs(alpha2 - alpha1) * R;
+            if( dfSegmentLength1 > dfMaxLength || dfSegmentLength2 > dfMaxLength )
+            {
+                int nIntermediatePoints = 1 + 2 * (int)floor(dfSegmentLength1 / dfMaxLength / 2);
+                double dfStep = (alpha1 - alpha0) / (nIntermediatePoints + 1);
+                for(int j=1;j<=nIntermediatePoints;j++)
+                {
+                    double alpha = alpha0 + dfStep * j;
+                    double x = cx + R * cos(alpha), y = cy + R * sin(alpha);
+                    aoRawPoint.push_back(OGRRawPoint(x,y));
+                    if( padfZ )
+                    {
+                        double z = padfZ[i] + (padfZ[i+1] - padfZ[i]) * (alpha - alpha0) / (alpha1 - alpha0);
+                        adfZ.push_back(z);
+                    }
+                }
+            }
+            aoRawPoint.push_back(OGRRawPoint(x1,y1));
+            if( padfZ )
+                adfZ.push_back(padfZ[i+1]);
+
+            if( dfSegmentLength1 > dfMaxLength || dfSegmentLength2 > dfMaxLength )
+            {
+                int nIntermediatePoints = 1 + 2 * (int)floor(dfSegmentLength2 / dfMaxLength / 2);
+                double dfStep = (alpha2 - alpha1) / (nIntermediatePoints + 1);
+                for(int j=1;j<=nIntermediatePoints;j++)
+                {
+                    double alpha = alpha1 + dfStep * j;
+                    double x = cx + R * cos(alpha), y = cy + R * sin(alpha);
+                    aoRawPoint.push_back(OGRRawPoint(x,y));
+                    if( padfZ )
+                    {
+                        double z = padfZ[i+1] + (padfZ[i+2] - padfZ[i+1]) * (alpha - alpha1) / (alpha2 - alpha1);
+                        adfZ.push_back(z);
+                    }
+                }
+            }
+        }
+        else
+        {
+            /* It is a straight line */
+            double dfSegmentLength1 = sqrt((x1-x0)*(x1-x0)+(y1-y0)*(y1-y0));
+            double dfSegmentLength2 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
+            if( dfSegmentLength1 > dfMaxLength || dfSegmentLength2 > dfMaxLength )
+            {
+                int nIntermediatePoints = 1 + 2 * (int)ceil(dfSegmentLength1 / dfMaxLength / 2);
+                for(int j=1;j<=nIntermediatePoints;j++)
+                {
+                    aoRawPoint.push_back(OGRRawPoint(
+                            x0 + j * (x1-x0) / (nIntermediatePoints + 1),
+                            y0 + j * (y1-y0) / (nIntermediatePoints + 1)));
+                    if( padfZ )
+                        adfZ.push_back(padfZ[i] + j * (padfZ[i+1]-padfZ[i]) / (nIntermediatePoints + 1));
+                }
+            }
+
+            aoRawPoint.push_back(OGRRawPoint(x1,y1));
+            if( padfZ )
+                adfZ.push_back(padfZ[i+1]);
+
+            if( dfSegmentLength1 > dfMaxLength || dfSegmentLength2 > dfMaxLength )
+            {
+                int nIntermediatePoints = 1 + 2 * (int)ceil(dfSegmentLength2 / dfMaxLength / 2);
+                for(int j=1;j<=nIntermediatePoints;j++)
+                {
+                    aoRawPoint.push_back(OGRRawPoint(
+                            x1 + j * (x2-x1) / (nIntermediatePoints + 1),
+                            y1 + j * (y2-y1) / (nIntermediatePoints + 1)));
+                    if( padfZ )
+                        adfZ.push_back(padfZ[i+1] + j * (padfZ[i+2]-padfZ[i+1]) / (nIntermediatePoints + 1));
+                }
+            }
+        }
+    }
+    aoRawPoint.push_back(paoPoints[nPointCount-1]);
+    if( padfZ )
+        adfZ.push_back(padfZ[nPointCount-1]);
+
+    CPLAssert(aoRawPoint.size() == 0 || (aoRawPoint.size() >= 3 && (aoRawPoint.size() % 2) == 1));
+    if( padfZ )
+    {
+        CPLAssert(adfZ.size() == aoRawPoint.size());
+    }
+
+    /* Is there actually something to modify ? */
+    if( nPointCount < (int)aoRawPoint.size() )
+    {
+        nPointCount = (int)aoRawPoint.size();
+        paoPoints = (OGRRawPoint *)
+                OGRRealloc(paoPoints, sizeof(OGRRawPoint) * nPointCount);
+        memcpy(paoPoints, &aoRawPoint[0], sizeof(OGRRawPoint) * nPointCount);
+        if( padfZ )
+        {
+            padfZ = (double*) OGRRealloc(padfZ, sizeof(double) * aoRawPoint.size());
+            memcpy(padfZ, &adfZ[0], sizeof(double) * nPointCount);
+        }
+    }
+}
+
+/************************************************************************/
+/*                               Value()                                */
+/*                                                                      */
+/*      Get an interpolated point at some distance along the curve.     */
+/************************************************************************/
+
+void OGRCircularString::Value( double dfDistance, OGRPoint * poPoint ) const
+
+{
+    double      dfLength = 0;
+    int         i;
+
+    if( dfDistance < 0 )
+    {
+        StartPoint( poPoint );
+        return;
+    }
+    
+    for(i=0;i<nPointCount-2;i+=2)
+    {
+        double x0 = paoPoints[i].x, y0 = paoPoints[i].y,
+               x1 = paoPoints[i+1].x, y1 = paoPoints[i+1].y,
+               x2 = paoPoints[i+2].x, y2 = paoPoints[i+2].y;
+        double R, cx, cy, alpha0, alpha1, alpha2;
+
+        /* We have strong constraints on the number of intermediate points */
+        /* we can add */
+
+        if( OGRGeometryFactory::GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                                            R, cx, cy, alpha0, alpha1, alpha2) )
+        {
+            /* It is an arc circle */
+            double dfSegLength = fabs(alpha2 - alpha0) * R;
+            if (dfSegLength > 0)
+            {
+                if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >= 
+                                                dfDistance) )
+                {
+                    double      dfRatio;
+
+                    dfRatio = (dfDistance - dfLength) / dfSegLength;
+                    
+                    double alpha = alpha0 * (1 - dfRatio) + alpha2 * dfRatio;
+                    double x = cx + R * cos(alpha), y = cy + R * sin(alpha);
+
+                    poPoint->setX( x );
+                    poPoint->setY( y );
+
+                    if( getCoordinateDimension() == 3 )
+                        poPoint->setZ( padfZ[i] * (1 - dfRatio)
+                                    + padfZ[i+2] * dfRatio );
+                    
+                    return;
+                }
+
+                dfLength += dfSegLength;
+            }
+        }
+        else
+        {
+            /* It is a straight line */
+            double dfSegLength = sqrt((x2-x0)*(x2-x0)+(y2-y0)*(y2-y0));
+            if (dfSegLength > 0)
+            {
+                if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >= 
+                                                dfDistance) )
+                {
+                    double      dfRatio;
+
+                    dfRatio = (dfDistance - dfLength) / dfSegLength;
+
+                    poPoint->setX( paoPoints[i].x * (1 - dfRatio)
+                                + paoPoints[i+2].x * dfRatio );
+                    poPoint->setY( paoPoints[i].y * (1 - dfRatio)
+                                + paoPoints[i+2].y * dfRatio );
+
+                    if( getCoordinateDimension() == 3 )
+                        poPoint->setZ( padfZ[i] * (1 - dfRatio)
+                                    + padfZ[i+2] * dfRatio );
+                    
+                    return;
+                }
+
+                dfLength += dfSegLength;
+            }
+        }
+    }
+
+    EndPoint( poPoint );
+}
+
+/************************************************************************/
+/*                          CurveToLine()                               */
+/************************************************************************/
+
+OGRLineString* OGRCircularString::CurveToLine(double dfMaxAngleStepSizeDegrees,
+                                              const char* const* papszOptions) const
+{
+    OGRLineString* poLine = new OGRLineString();
+    poLine->assignSpatialReference(getSpatialReference());
+
+    int bHasZ = (getCoordinateDimension() == 3);
+    int i;
+    for(i=0;i<nPointCount-2;i+=2)
+    {
+        OGRLineString* poArc = OGRGeometryFactory::curveToLineString(
+                paoPoints[i].x, paoPoints[i].y, padfZ ? padfZ[i] : 0.0,
+                paoPoints[i+1].x, paoPoints[i+1].y, padfZ ? padfZ[i+1] : 0.0,
+                paoPoints[i+2].x, paoPoints[i+2].y, padfZ ? padfZ[i+2] : 0.0,
+                bHasZ,
+                dfMaxAngleStepSizeDegrees,
+                papszOptions);
+        poLine->addSubLineString(poArc, (i == 0) ? 0 : 1);
+        delete poArc;
+    }
+    return poLine;
+}
+
+/************************************************************************/
+/*                        IsValidFast()                                 */
+/************************************************************************/
+
+OGRBoolean OGRCircularString::IsValidFast(  ) const
+
+{
+    if (nPointCount == 1 || nPointCount == 2 ||
+        (nPointCount >= 3 && (nPointCount % 2) == 0))
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Bad number of points in circular string : %d", nPointCount);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            IsValid()                                 */
+/************************************************************************/
+
+OGRBoolean OGRCircularString::IsValid(  ) const
+
+{
+    return IsValidFast() && OGRGeometry::IsValid();
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRCircularString::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
+{
+    return TRUE;
+}
+
+/************************************************************************/
+/*                         getLinearGeometry()                        */
+/************************************************************************/
+
+OGRGeometry* OGRCircularString::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
+                                                    const char* const* papszOptions) const
+{
+    return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
+}
+
+/************************************************************************/
+/*                     GetCasterToLineString()                          */
+/************************************************************************/
+
+OGRCurveCasterToLineString OGRCircularString::GetCasterToLineString() const {
+    return (OGRCurveCasterToLineString) OGRGeometry::CastToError;
+}
+
+/************************************************************************/
+/*                        GetCasterToLinearRing()                       */
+/************************************************************************/
+
+OGRCurveCasterToLinearRing OGRCircularString::GetCasterToLinearRing() const {
+    return (OGRCurveCasterToLinearRing) OGRGeometry::CastToError;
+}
+
+/************************************************************************/
+/*                            IsFullCircle()                            */
+/************************************************************************/
+
+int OGRCircularString::IsFullCircle( double& cx, double& cy, double& square_R ) const
+{
+    if( getNumPoints() == 3 && get_IsClosed() )
+    {
+        double x0 = getX(0);
+        double y0 = getY(0);
+        double x1 = getX(1);
+        double y1 = getY(1);
+        cx = (x0 + x1) / 2;
+        cy = (y0 + y1) / 2;
+        square_R = (x1-cx)*(x1-cx)+(y1-cy)*(y1-cy);
+        return TRUE;
+    }
+    /* Full circle defined by 2 arcs ? */
+    else if( getNumPoints() == 5 && get_IsClosed() )
+    {
+        double R_1, cx_1, cy_1, alpha0_1, alpha1_1, alpha2_1;
+        double R_2, cx_2, cy_2, alpha0_2, alpha1_2, alpha2_2;
+        if( OGRGeometryFactory::GetCurveParmeters(
+                getX(0), getY(0),
+                getX(1), getY(1),
+                getX(2), getY(2),
+                R_1, cx_1, cy_1, alpha0_1, alpha1_1, alpha2_1) &&
+            OGRGeometryFactory::GetCurveParmeters(
+                getX(2), getY(2),
+                getX(3), getY(3),
+                getX(4), getY(4),
+                R_2, cx_2, cy_2, alpha0_2, alpha1_2, alpha2_2) &&
+            fabs(R_1-R_2) < 1e-10 &&
+            fabs(cx_1-cx_2) < 1e-10 &&
+            fabs(cy_1-cy_2) < 1e-10 &&
+            (alpha2_1 - alpha0_1) * (alpha2_2 - alpha0_2) > 0 )
+        {
+            cx = cx_1;
+            cy = cy_1;
+            square_R = R_1 * R_1;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/************************************************************************/
+/*                       get_AreaOfCurveSegments()                      */
+/************************************************************************/
+
+double OGRCircularString::get_AreaOfCurveSegments() const
+{
+    double dfArea = 0;
+    for( int i=0; i < getNumPoints() - 2; i += 2 )
+    {
+        double x0 = getX(i), y0 = getY(i),
+               x1 = getX(i+1), y1 = getY(i+1),
+               x2 = getX(i+2), y2 = getY(i+2);
+        double R, cx, cy, alpha0, alpha1, alpha2;
+        if( OGRGeometryFactory::GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                                            R, cx, cy, alpha0, alpha1, alpha2))
+        {
+            double delta_alpha01 = alpha1 - alpha0; /* should be <= PI in absolute value */
+            double delta_alpha12 = alpha2 - alpha1; /* same */
+            /* This is my maths, but wikipedia confirms it... */
+            /* Cf http://en.wikipedia.org/wiki/Circular_segment */
+            dfArea += 0.5 * R * R * fabs( delta_alpha01 - sin(delta_alpha01) +
+                                          delta_alpha12 - sin(delta_alpha12) );
+        }
+    }
+    return dfArea;
+}
+
+/************************************************************************/
+/*                           get_Area()                                 */
+/************************************************************************/
+
+double OGRCircularString::get_Area() const
+{
+    double cx, cy, square_R;
+
+    if( IsEmpty() || !get_IsClosed() )
+        return 0;
+
+    if( IsFullCircle(cx, cy, square_R) )
+    {
+        return M_PI * square_R;
+    }
+
+    /* Optimization for convex rings */
+    if( IsConvex() )
+    {
+        /* Compute area of shape without the circular segments */
+        double dfArea = get_LinearArea();
+
+        /* Add the area of the spherical segments */
+        dfArea += get_AreaOfCurveSegments();
+
+        return dfArea;
+    }
+    else
+    {
+        OGRLineString* poLS = CurveToLine();
+        double dfArea = poLS->get_Area();
+        delete poLS;
+
+        return dfArea;
+    }
+}
+
+/************************************************************************/
+/*                           ContainsPoint()                            */
+/************************************************************************/
+
+int OGRCircularString::ContainsPoint( const OGRPoint* p ) const
+{
+    double cx, cy, square_R;
+    if( IsFullCircle(cx, cy, square_R) )
+    {
+        double square_dist = (p->getX()- cx)*(p->getX()- cx)+
+                             (p->getY()- cy)*(p->getY()- cy);
+        return square_dist <= square_R;
+    }
+    return -1;
+}
diff --git a/ogr/ogrcompoundcurve.cpp b/ogr/ogrcompoundcurve.cpp
new file mode 100644
index 0000000..dad2a82
--- /dev/null
+++ b/ogr/ogrcompoundcurve.cpp
@@ -0,0 +1,800 @@
+/******************************************************************************
+ * $Id: ogrcompoundcurve.cpp 27960 2014-11-14 18:31:32Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRCompoundCurve geometry class.
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include <assert.h>
+
+CPL_CVSID("$Id");
+
+/************************************************************************/
+/*                         OGRCompoundCurve()                           */
+/************************************************************************/
+
+/**
+ * \brief Create an empty compound curve.
+ */
+
+OGRCompoundCurve::OGRCompoundCurve()
+
+{
+}
+
+/************************************************************************/
+/*                         ~OGRCompoundCurve()                          */
+/************************************************************************/
+
+OGRCompoundCurve::~OGRCompoundCurve()
+
+{
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRCompoundCurve::getGeometryType() const
+
+{
+    if( getCoordinateDimension() == 3 )
+        return wkbCompoundCurveZ;
+    else
+        return wkbCompoundCurve;
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRCompoundCurve::getGeometryName() const
+
+{
+    return "COMPOUNDCURVE";
+}
+
+/************************************************************************/
+/*                              WkbSize()                               */
+/************************************************************************/
+int OGRCompoundCurve::WkbSize() const
+{
+    return oCC.WkbSize();
+}
+
+/************************************************************************/
+/*                       addCurveDirectlyFromWkt()                      */
+/************************************************************************/
+
+OGRErr OGRCompoundCurve::addCurveDirectlyFromWkb( OGRGeometry* poSelf,
+                                                  OGRCurve* poCurve )
+{
+    OGRCompoundCurve* poCC = (OGRCompoundCurve*)poSelf;
+    return poCC->addCurveDirectlyInternal( poCurve, 1e-14, FALSE );
+}
+
+/************************************************************************/
+/*                           importFromWkb()                            */
+/************************************************************************/
+
+OGRErr OGRCompoundCurve::importFromWkb( unsigned char * pabyData,
+                                        int nSize,
+                                        OGRwkbVariant eWkbVariant )
+{
+    OGRwkbByteOrder eByteOrder;
+    int nDataOffset = 0;
+    OGRErr eErr = oCC.importPreambuleFromWkb(this, pabyData, nSize, nDataOffset,
+                                             eByteOrder, 9, eWkbVariant);
+    if( eErr >= 0 )
+        return eErr;
+
+    return oCC.importBodyFromWkb(this, pabyData, nSize, nDataOffset,
+                                 FALSE /* bAcceptCompoundCurve */, addCurveDirectlyFromWkb,
+                                 eWkbVariant);
+}
+
+/************************************************************************/
+/*                            exportToWkb()                             */
+/************************************************************************/
+OGRErr OGRCompoundCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
+                                      unsigned char * pabyData,
+                                      OGRwkbVariant eWkbVariant  ) const
+{
+    if( eWkbVariant == wkbVariantOldOgc ) /* does not make sense for new geometries, so patch it */
+        eWkbVariant = wkbVariantIso;
+    return oCC.exportToWkb(this, eByteOrder, pabyData, eWkbVariant);
+}
+
+/************************************************************************/
+/*                       addCurveDirectlyFromWkt()                      */
+/************************************************************************/
+
+OGRErr OGRCompoundCurve::addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve )
+{
+    return ((OGRCompoundCurve*)poSelf)->addCurveDirectly(poCurve);
+}
+
+/************************************************************************/
+/*                           importFromWkt()                            */
+/************************************************************************/
+
+OGRErr OGRCompoundCurve::importFromWkt( char ** ppszInput )
+{
+    return importCurveCollectionFromWkt( ppszInput,
+                                         FALSE, /* bAllowEmptyComponent */
+                                         TRUE, /* bAllowLineString */
+                                         TRUE, /* bAllowCurve */
+                                         FALSE, /* bAllowCompoundCurve */
+                                         addCurveDirectlyFromWkt );
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+OGRErr OGRCompoundCurve::exportToWkt( char ** ppszDstText,
+                                      CPL_UNUSED OGRwkbVariant eWkbVariant ) const
+
+{
+    return oCC.exportToWkt(this, ppszDstText);
+}
+
+/************************************************************************/
+/*                               clone()                                */
+/************************************************************************/
+
+OGRGeometry *OGRCompoundCurve::clone() const
+{
+    OGRCompoundCurve       *poNewCC;
+
+    poNewCC = new OGRCompoundCurve;
+    poNewCC->assignSpatialReference( getSpatialReference() );
+
+    for( int i = 0; i < oCC.nCurveCount; i++ )
+    {
+        poNewCC->addCurve( oCC.papoCurves[i] );
+    }
+
+    return poNewCC;
+}
+
+/************************************************************************/
+/*                               empty()                                */
+/************************************************************************/
+
+void OGRCompoundCurve::empty()
+{
+    oCC.empty(this);
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCompoundCurve::getEnvelope( OGREnvelope * psEnvelope ) const
+{
+    oCC.getEnvelope(psEnvelope);
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCompoundCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
+{
+    oCC.getEnvelope(psEnvelope);
+}
+
+/************************************************************************/
+/*                               IsEmpty()                              */
+/************************************************************************/
+
+OGRBoolean OGRCompoundCurve::IsEmpty() const
+{
+    return oCC.IsEmpty();
+}
+
+/************************************************************************/
+/*                             get_Length()                             */
+/*                                                                      */
+/*      For now we return a simple euclidian 2D distance.               */
+/************************************************************************/
+
+double OGRCompoundCurve::get_Length() const
+{
+    double dfLength = 0.0;
+    for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
+        dfLength += oCC.papoCurves[iGeom]->get_Length();
+    return dfLength;
+}
+
+/************************************************************************/
+/*                             StartPoint()                             */
+/************************************************************************/
+
+void OGRCompoundCurve::StartPoint(OGRPoint *p) const
+{
+    CPLAssert(oCC.nCurveCount > 0);
+    oCC.papoCurves[0]->StartPoint(p);
+}
+
+/************************************************************************/
+/*                              EndPoint()                              */
+/************************************************************************/
+
+void OGRCompoundCurve::EndPoint(OGRPoint *p) const
+{
+    CPLAssert(oCC.nCurveCount > 0);
+    oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(p);
+}
+
+/************************************************************************/
+/*                               Value()                                */
+/************************************************************************/
+
+void OGRCompoundCurve::Value( double dfDistance, OGRPoint *poPoint ) const
+{
+
+    if( dfDistance < 0 )
+    {
+        StartPoint( poPoint );
+        return;
+    }
+
+    double dfLength = 0;
+    for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
+    {
+        double dfSegLength = oCC.papoCurves[iGeom]->get_Length();
+        if (dfSegLength > 0)
+        {
+            if( (dfLength <= dfDistance) && ((dfLength + dfSegLength) >= 
+                                             dfDistance) )
+            {
+                oCC.papoCurves[iGeom]->Value(dfDistance - dfLength, poPoint);
+
+                return;
+            }
+
+            dfLength += dfSegLength;
+        }
+    }
+    
+    EndPoint( poPoint );
+}
+
+/************************************************************************/
+/*                         CurveToLineInternal()                        */
+/************************************************************************/
+
+OGRLineString* OGRCompoundCurve::CurveToLineInternal(double dfMaxAngleStepSizeDegrees,
+                                                     const char* const* papszOptions,
+                                                     int bIsLinearRing) const
+{
+    OGRLineString* poLine;
+    if( bIsLinearRing )
+        poLine = new OGRLinearRing();
+    else
+        poLine = new OGRLineString();
+    poLine->assignSpatialReference(getSpatialReference());
+    for( int iGeom = 0; iGeom < oCC.nCurveCount; iGeom++ )
+    {
+        OGRLineString* poSubLS = oCC.papoCurves[iGeom]->CurveToLine(dfMaxAngleStepSizeDegrees,
+                                                                    papszOptions);
+        poLine->addSubLineString(poSubLS, (iGeom == 0) ? 0 : 1);
+        delete poSubLS;
+    }
+    return poLine;
+}
+
+/************************************************************************/
+/*                          CurveToLine()                               */
+/************************************************************************/
+
+OGRLineString* OGRCompoundCurve::CurveToLine(double dfMaxAngleStepSizeDegrees,
+                                             const char* const* papszOptions) const
+{
+    return CurveToLineInternal(dfMaxAngleStepSizeDegrees, papszOptions, FALSE);
+}
+
+/************************************************************************/
+/*                               Equals()                                */
+/************************************************************************/
+
+OGRBoolean  OGRCompoundCurve::Equals( OGRGeometry *poOther ) const
+{
+    OGRCompoundCurve *poOCC = (OGRCompoundCurve *) poOther;
+
+    if( poOCC == this )
+        return TRUE;
+    
+    if( poOther->getGeometryType() != getGeometryType() )
+        return FALSE;
+    
+    return oCC.Equals(&(poOCC->oCC));
+}
+
+/************************************************************************/
+/*                       setCoordinateDimension()                       */
+/************************************************************************/
+
+void OGRCompoundCurve::setCoordinateDimension( int nNewDimension )
+{
+    oCC.setCoordinateDimension( this, nNewDimension );
+}
+
+/************************************************************************/
+/*                          getNumCurves()                              */
+/************************************************************************/
+
+/**
+ * \brief Return the number of curves.
+ *
+ * Note that the number of curves making this compound curve.
+ *
+ * Relates to the ISO SQL/MM ST_NumCurves() function.
+ *
+ * @return number of curves.
+ */
+
+int          OGRCompoundCurve::getNumCurves() const
+{
+    return oCC.nCurveCount;
+}
+
+/************************************************************************/
+/*                           getCurve()                                 */
+/************************************************************************/
+
+/**
+ * \brief Fetch reference to indicated internal ring.
+ *
+ * Note that the returned curve pointer is to an internal data object of
+ * the OGRCompoundCurve.  It should not be modified or deleted by the application,
+ * and the pointer is only valid till the polygon is next modified.  Use
+ * the OGRGeometry::clone() method to make a separate copy within the
+ * application.
+ *
+ * Relates to the ISO SQL/MM ST_CurveN() function.
+ *
+ * @param iRing curve index from 0 to getNumCurves() - 1.
+ *
+ * @return pointer to curve.  May be NULL.
+ */
+
+OGRCurve    *OGRCompoundCurve::getCurve( int i )
+{
+    return oCC.getCurve(i);
+}
+
+/************************************************************************/
+/*                           getCurve()                                 */
+/************************************************************************/
+
+/**
+ * \brief Fetch reference to indicated internal ring.
+ *
+ * Note that the returned curve pointer is to an internal data object of
+ * the OGRCompoundCurve.  It should not be modified or deleted by the application,
+ * and the pointer is only valid till the polygon is next modified.  Use
+ * the OGRGeometry::clone() method to make a separate copy within the
+ * application.
+ *
+ * Relates to the ISO SQL/MM ST_CurveN() function.
+ *
+ * @param iRing curve index from 0 to getNumCurves() - 1.
+ *
+ * @return pointer to curve.  May be NULL.
+ */
+
+const OGRCurve *OGRCompoundCurve::getCurve( int i ) const
+{
+    return oCC.getCurve(i);
+}
+
+/************************************************************************/
+/*                           stealCurve()                               */
+/************************************************************************/
+
+OGRCurve* OGRCompoundCurve::stealCurve( int i )
+{
+    return oCC.stealCurve(i);
+}
+
+/************************************************************************/
+/*                            addCurve()                                */
+/************************************************************************/
+
+/**
+ * \brief Add a curve to the container.
+ *
+ * The passed geometry is cloned to make an internal copy.
+ *
+ * There is no ISO SQL/MM analog to this method.
+ *
+ * This method is the same as the C function OGR_G_AddGeometry().
+ *
+ * @param poCurve geometry to add to the container.
+ * @param dfToleranceEps tolerance when checking that the first point of a
+ *                       segment matches then end point of the previous one.
+ *                       Default value: 1e-14.
+ *
+ * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
+ * (for example if curves are not contiguous)
+ */
+
+OGRErr OGRCompoundCurve::addCurve( OGRCurve* poCurve, double dfToleranceEps )
+{
+    OGRCurve* poClonedCurve = (OGRCurve*)poCurve->clone();
+    OGRErr eErr = addCurveDirectly( poClonedCurve, dfToleranceEps );
+    if( eErr != OGRERR_NONE )
+        delete poClonedCurve;
+    return eErr;
+}
+
+/************************************************************************/
+/*                          addCurveDirectly()                          */
+/************************************************************************/
+
+/**
+ * \brief Add a curve directly to the container.
+ *
+ * Ownership of the passed geometry is taken by the container rather than
+ * cloning as addCurve() does.
+ *
+ * There is no ISO SQL/MM analog to this method.
+ *
+ * This method is the same as the C function OGR_G_AddGeometryDirectly().
+ *
+ * @param poCurve geometry to add to the container.
+ * @param dfToleranceEps tolerance when checking that the first point of a
+ *                       segment matches then end point of the previous one.
+ *                       Default value: 1e-14.
+ *
+ * @return OGRERR_NONE if successful, or OGRERR_FAILURE in case of error
+ * (for example if curves are not contiguous)
+ */
+OGRErr OGRCompoundCurve::addCurveDirectly( OGRCurve* poCurve,
+                                           double dfToleranceEps )
+{
+    return addCurveDirectlyInternal(poCurve, dfToleranceEps, TRUE );
+}
+
+OGRErr OGRCompoundCurve::addCurveDirectlyInternal( OGRCurve* poCurve,
+                                                   double dfToleranceEps,
+                                                   int bNeedRealloc )
+{
+    if( poCurve->getNumPoints() == 1 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid curve: not enough points");
+        return OGRERR_FAILURE;
+    }
+
+    OGRwkbGeometryType eCurveType = wkbFlatten(poCurve->getGeometryType());
+    if( EQUAL(poCurve->getGeometryName(), "LINEARRING") )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
+        return OGRERR_FAILURE;
+    }
+    else if( eCurveType == wkbCompoundCurve )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot add a compound curve inside a compound curve");
+        return OGRERR_FAILURE;
+    }
+
+    if( oCC.nCurveCount > 0 )
+    {
+        if( oCC.papoCurves[oCC.nCurveCount-1]->IsEmpty() ||
+            poCurve->IsEmpty() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
+            return OGRERR_FAILURE;
+        }
+
+        OGRPoint end, start;
+        oCC.papoCurves[oCC.nCurveCount-1]->EndPoint(&end);
+        poCurve->StartPoint(&start);
+        if( fabs(end.getX() - start.getX()) > dfToleranceEps ||
+            fabs(end.getY() - start.getY()) > dfToleranceEps ||
+            fabs(end.getZ() - start.getZ()) > dfToleranceEps )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Non contiguous curves");
+            return OGRERR_FAILURE;
+        }
+        ((OGRSimpleCurve*)poCurve)->setPoint(0, &end); /* patch so that it matches exactly */
+    }
+
+    return oCC.addCurveDirectly(this, poCurve, bNeedRealloc);
+}
+
+/************************************************************************/
+/*                             transform()                              */
+/************************************************************************/
+
+OGRErr  OGRCompoundCurve::transform( OGRCoordinateTransformation *poCT )
+{
+    return oCC.transform(this, poCT);
+}
+
+/************************************************************************/
+/*                            flattenTo2D()                             */
+/************************************************************************/
+
+void OGRCompoundCurve::flattenTo2D()
+{
+    oCC.flattenTo2D(this);
+}
+
+/************************************************************************/
+/*                              segmentize()                            */
+/************************************************************************/
+
+void OGRCompoundCurve::segmentize(double dfMaxLength)
+{
+    oCC.segmentize(dfMaxLength);
+}
+
+/************************************************************************/
+/*                               swapXY()                               */
+/************************************************************************/
+
+void OGRCompoundCurve::swapXY()
+{
+    oCC.swapXY();
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRCompoundCurve::hasCurveGeometry(int bLookForNonLinear) const
+{
+    if( bLookForNonLinear )
+    {
+        return oCC.hasCurveGeometry(bLookForNonLinear);
+    }
+    else
+        return TRUE;
+}
+
+/************************************************************************/
+/*                         getLinearGeometry()                        */
+/************************************************************************/
+
+OGRGeometry* OGRCompoundCurve::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
+                                                   const char* const* papszOptions) const
+{
+    return CurveToLine(dfMaxAngleStepSizeDegrees, papszOptions);
+}
+
+/************************************************************************/
+/*                           getNumPoints()                             */
+/************************************************************************/
+
+int OGRCompoundCurve::getNumPoints() const
+{
+    int nPoints = 0;
+    for( int i = 0; i < oCC.nCurveCount; i++ )
+    {
+        nPoints += oCC.papoCurves[i]->getNumPoints();
+        if( i != 0 )
+            nPoints --;
+    }
+    return nPoints;
+}
+
+/************************************************************************/
+/*                      OGRCompoundCurvePointIterator                   */
+/************************************************************************/
+
+class OGRCompoundCurvePointIterator: public OGRPointIterator
+{
+        const OGRCompoundCurve *poCC;
+        int                     iCurCurve;
+        OGRPointIterator       *poCurveIter;
+
+    public:
+        OGRCompoundCurvePointIterator(const OGRCompoundCurve* poCC) :
+                            poCC(poCC), iCurCurve(0), poCurveIter(NULL) {}
+       ~OGRCompoundCurvePointIterator() { delete poCurveIter; }
+
+        virtual OGRBoolean getNextPoint(OGRPoint* p);
+};
+
+/************************************************************************/
+/*                            getNextPoint()                            */
+/************************************************************************/
+
+OGRBoolean OGRCompoundCurvePointIterator::getNextPoint(OGRPoint* p)
+{
+    if( iCurCurve == poCC->getNumCurves() )
+        return FALSE;
+    if( poCurveIter == NULL )
+        poCurveIter = poCC->getCurve(0)->getPointIterator();
+    if( !poCurveIter->getNextPoint(p) )
+    {
+        iCurCurve ++;
+        if( iCurCurve == poCC->getNumCurves() )
+            return FALSE;
+        delete poCurveIter;
+        poCurveIter = poCC->getCurve(iCurCurve)->getPointIterator();
+        /* skip first point */
+        return poCurveIter->getNextPoint(p) &&
+               poCurveIter->getNextPoint(p);
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                         getPointIterator()                           */
+/************************************************************************/
+
+OGRPointIterator* OGRCompoundCurve::getPointIterator() const
+{
+    return new OGRCompoundCurvePointIterator(this);
+}
+
+/************************************************************************/
+/*                         CastToLineString()                        */
+/************************************************************************/
+
+OGRLineString* OGRCompoundCurve::CastToLineString(OGRCompoundCurve* poCC)
+{
+    for(int i=0;i<poCC->oCC.nCurveCount;i++)
+    {
+        poCC->oCC.papoCurves[i] = OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
+        if( poCC->oCC.papoCurves[i] == NULL )
+        {
+            delete poCC;
+            return NULL;
+        }
+    }
+
+    if( poCC->oCC.nCurveCount == 1 )
+    {
+        OGRLineString* poLS = (OGRLineString*) poCC->oCC.papoCurves[0];
+        poLS->assignSpatialReference(poCC->getSpatialReference());
+        poCC->oCC.papoCurves[0] = NULL;
+        delete poCC;
+        return poLS;
+    }
+
+    OGRLineString* poLS = poCC->CurveToLineInternal(0, NULL, FALSE);
+    delete poCC;
+    return poLS;
+}
+
+/************************************************************************/
+/*                           CastToLinearRing()                         */
+/************************************************************************/
+
+/**
+ * \brief Cast to linear ring.
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poCC the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRLinearRing* OGRCompoundCurve::CastToLinearRing(OGRCompoundCurve* poCC)
+{
+    for(int i=0;i<poCC->oCC.nCurveCount;i++)
+    {
+        poCC->oCC.papoCurves[i] = OGRCurve::CastToLineString(poCC->oCC.papoCurves[i]);
+        if( poCC->oCC.papoCurves[i] == NULL )
+        {
+            delete poCC;
+            return NULL;
+        }
+    }
+
+    if( poCC->oCC.nCurveCount == 1 )
+    {
+        OGRLinearRing* poLR = OGRCurve::CastToLinearRing( poCC->oCC.papoCurves[0] );
+        if( poLR != NULL )
+        {
+            poLR->assignSpatialReference(poCC->getSpatialReference());
+        }
+        poCC->oCC.papoCurves[0] = NULL;
+        delete poCC;
+        return poLR;
+    }
+
+    OGRLinearRing* poLR = (OGRLinearRing*)poCC->CurveToLineInternal(0, NULL, TRUE);
+    delete poCC;
+    return poLR;
+}
+
+/************************************************************************/
+/*                     GetCasterToLineString()                          */
+/************************************************************************/
+
+OGRCurveCasterToLineString OGRCompoundCurve::GetCasterToLineString() const {
+    return (OGRCurveCasterToLineString) OGRCompoundCurve::CastToLineString;
+}
+
+/************************************************************************/
+/*                        GetCasterToLinearRing()                       */
+/************************************************************************/
+
+OGRCurveCasterToLinearRing OGRCompoundCurve::GetCasterToLinearRing() const {
+    return (OGRCurveCasterToLinearRing) OGRCompoundCurve::CastToLinearRing;
+}
+
+/************************************************************************/
+/*                           get_Area()                                 */
+/************************************************************************/
+
+double OGRCompoundCurve::get_Area() const
+{
+    if( IsEmpty() || !get_IsClosed() )
+        return 0;
+
+    /* Optimization for convex rings */
+    if( IsConvex() )
+    {
+        /* Compute area of shape without the circular segments */
+        OGRPointIterator* poIter = getPointIterator();
+        OGRLineString oLS;
+        oLS.setNumPoints( getNumPoints() );
+        OGRPoint p;
+        for(int i = 0; poIter->getNextPoint(&p); i++ )
+        {
+            oLS.setPoint( i, p.getX(), p.getY() );
+        }
+        double dfArea = oLS.get_Area();
+        delete poIter;
+
+        /* Add the area of the spherical segments */
+        dfArea += get_AreaOfCurveSegments();
+
+        return dfArea;
+    }
+    else
+    {
+        OGRLineString* poLS = CurveToLine();
+        double dfArea = poLS->get_Area();
+        delete poLS;
+
+        return dfArea;
+    }
+}
+
+/************************************************************************/
+/*                       get_AreaOfCurveSegments()                      */
+/************************************************************************/
+
+double OGRCompoundCurve::get_AreaOfCurveSegments() const
+{
+    double dfArea = 0;
+    for( int i = 0; i < getNumCurves(); i++ )
+    {
+        const OGRCurve* poPart = getCurve(i);
+        dfArea += poPart->get_AreaOfCurveSegments();
+    }
+    return dfArea;
+}
diff --git a/ogr/ogrct.cpp b/ogr/ogrct.cpp
index 3b4c0e7..905aaca 100644
--- a/ogr/ogrct.cpp
+++ b/ogr/ogrct.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrct.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrct.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRSCoordinateTransformation class.
@@ -39,7 +39,7 @@
 #include "proj_api.h"
 #endif
 
-CPL_CVSID("$Id: ogrct.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrct.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 /* ==================================================================== */
 /*      PROJ.4 interface stuff.                                         */
@@ -60,7 +60,7 @@ typedef struct { double u, v; } projUV;
 
 #endif
 
-static void *hPROJMutex = NULL;
+static CPLMutex *hPROJMutex = NULL;
 
 static projPJ       (*pfn_pj_init_plus)(const char *) = NULL;
 static projPJ       (*pfn_pj_init)(int, char**) = NULL;
@@ -184,10 +184,9 @@ static const char* GetProjLibraryName()
 /*                          LoadProjLibrary()                           */
 /************************************************************************/
 
-static int LoadProjLibrary()
+static int LoadProjLibrary_unlocked()
 
 {
-    CPLMutexHolderD( &hPROJMutex );
     static int  bTriedToLoad = FALSE;
     const char *pszLibName;
     
@@ -286,6 +285,13 @@ static int LoadProjLibrary()
     return( TRUE );
 }
 
+static int LoadProjLibrary()
+
+{
+    CPLMutexHolderD( &hPROJMutex );
+    return LoadProjLibrary_unlocked();
+}
+
 /************************************************************************/
 /*                         OCTProj4Normalize()                          */
 /*                                                                      */
@@ -303,9 +309,11 @@ char *OCTProj4Normalize( const char *pszProj4Src )
 
     CPLMutexHolderD( &hPROJMutex );
 
-    if( !LoadProjLibrary() || pfn_pj_dalloc == NULL || pfn_pj_get_def == NULL )
+    if( !LoadProjLibrary_unlocked() || pfn_pj_dalloc == NULL || pfn_pj_get_def == NULL )
         return CPLStrdup( pszProj4Src );
 
+    CPLLocaleC  oLocaleEnforcer;
+
     psPJSource = pfn_pj_init_plus( pszProj4Src );
 
     if( psPJSource == NULL )
@@ -540,6 +548,7 @@ int OGRProj4CT::Initialize( OGRSpatialReference * poSourceIn,
                             OGRSpatialReference * poTargetIn )
 
 {
+    CPLLocaleC  oLocaleEnforcer;
     if (pjctx != NULL)
     {
         return InitializeNoLock(poSourceIn, poTargetIn);
@@ -579,7 +588,7 @@ int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn,
         OGR_SRSNode *poUNITS = poSRSSource->GetAttrNode( "GEOGCS|UNIT" );
         if( poUNITS && poUNITS->GetChildCount() >= 2 )
         {
-            dfSourceToRadians = atof(poUNITS->GetChild(1)->GetValue());
+            dfSourceToRadians = CPLAtof(poUNITS->GetChild(1)->GetValue());
             if( dfSourceToRadians == 0.0 )
                 dfSourceToRadians = DEG_TO_RAD;
         }
@@ -594,7 +603,7 @@ int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn,
         OGR_SRSNode *poUNITS = poSRSTarget->GetAttrNode( "GEOGCS|UNIT" );
         if( poUNITS && poUNITS->GetChildCount() >= 2 )
         {
-            double dfTargetToRadians = atof(poUNITS->GetChild(1)->GetValue());
+            double dfTargetToRadians = CPLAtof(poUNITS->GetChild(1)->GetValue());
             if( dfTargetToRadians != 0.0 )
                 dfTargetFromRadians = 1 / dfTargetToRadians;
         }
@@ -609,14 +618,14 @@ int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn,
     {
         bSourceWrap = bTargetWrap = TRUE;
         dfSourceWrapLong = dfTargetWrapLong = 
-            atof(CPLGetConfigOption( "CENTER_LONG", "" ));
+            CPLAtof(CPLGetConfigOption( "CENTER_LONG", "" ));
         CPLDebug( "OGRCT", "Wrap at %g.", dfSourceWrapLong );
     }
 
     pszCENTER_LONG = poSRSSource->GetExtension( "GEOGCS", "CENTER_LONG" );
     if( pszCENTER_LONG != NULL )
     {
-        dfSourceWrapLong = atof(pszCENTER_LONG);
+        dfSourceWrapLong = CPLAtof(pszCENTER_LONG);
         bSourceWrap = TRUE;
         CPLDebug( "OGRCT", "Wrap source at %g.", dfSourceWrapLong );
     }
@@ -624,7 +633,7 @@ int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn,
     pszCENTER_LONG = poSRSTarget->GetExtension( "GEOGCS", "CENTER_LONG" );
     if( pszCENTER_LONG != NULL )
     {
-        dfTargetWrapLong = atof(pszCENTER_LONG);
+        dfTargetWrapLong = CPLAtof(pszCENTER_LONG);
         bTargetWrap = TRUE;
         CPLDebug( "OGRCT", "Wrap target at %g.", dfTargetWrapLong );
     }
@@ -633,11 +642,11 @@ int OGRProj4CT::InitializeNoLock( OGRSpatialReference * poSourceIn,
     
     /* The threshold is rather experimental... Works well with the cases of ticket #2305 */
     if (bSourceLatLong)
-        dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", ".1" ));
+        dfThreshold = CPLAtof(CPLGetConfigOption( "THRESHOLD", ".1" ));
     else
         /* 1 works well for most projections, except for +proj=aeqd that requires */
         /* a tolerance of 10000 */
-        dfThreshold = atof(CPLGetConfigOption( "THRESHOLD", "10000" ));
+        dfThreshold = CPLAtof(CPLGetConfigOption( "THRESHOLD", "10000" ));
 
 /* -------------------------------------------------------------------- */
 /*      Establish PROJ.4 handle for source if projection.               */
@@ -941,7 +950,7 @@ int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z,
 /* -------------------------------------------------------------------- */
 /*      Try to report an error through CPL.  Get proj.4 error string    */
 /*      if possible.  Try to avoid reporting thousands of error         */
-/*      ... supress further error reporting on this OGRProj4CT if we    */
+/*      ... suppress further error reporting on this OGRProj4CT if we   */
 /*      have already reported 20 errors.                                */
 /* -------------------------------------------------------------------- */
     if( err != 0 )
@@ -973,7 +982,7 @@ int OGRProj4CT::TransformEx( int nCount, double *x, double *y, double *z,
         else if( nErrorCount == 20 )
         {
             CPLError( CE_Failure, CPLE_AppDefined, 
-                      "Reprojection failed, err = %d, further errors will be supressed on the transform object.", 
+                      "Reprojection failed, err = %d, further errors will be suppressed on the transform object.", 
                       err );
         }
 
diff --git a/ogr/ogrcurve.cpp b/ogr/ogrcurve.cpp
index 9ebc9e5..ff7238a 100644
--- a/ogr/ogrcurve.cpp
+++ b/ogr/ogrcurve.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcurve.cpp 16574 2009-03-14 13:09:10Z rouault $
+ * $Id: ogrcurve.cpp 28004 2014-11-26 09:58:44Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRCurve geometry class. 
@@ -30,17 +30,35 @@
 #include "ogr_geometry.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrcurve.cpp 16574 2009-03-14 13:09:10Z rouault $");
+CPL_CVSID("$Id: ogrcurve.cpp 28004 2014-11-26 09:58:44Z rouault $");
+
+/************************************************************************/
+/*                                OGRCurve()                            */
+/************************************************************************/
 
 OGRCurve::OGRCurve()
 {
 }
 
+/************************************************************************/
+/*                               ~OGRCurve()                            */
+/************************************************************************/
+
 OGRCurve::~OGRCurve()
 {
 }
 
 /************************************************************************/
+/*                            getDimension()                            */
+/************************************************************************/
+
+int OGRCurve::getDimension() const
+
+{
+    return 1;
+}
+
+/************************************************************************/
 /*                            get_IsClosed()                            */
 /************************************************************************/
 
@@ -112,9 +130,261 @@ int OGRCurve::get_IsClosed() const
  *
  * This method relates to the SF COM ICurve::get_Value() method.
  *
+ * This function is the same as the C function OGR_G_Value().
+ *
  * @param dfDistance distance along the curve at which to sample position.
  *                   This distance should be between zero and get_Length()
  *                   for this curve.
  * @param poPoint the point to be assigned the curve position.
  */
 
+/**
+ * \fn OGRLineString* OGRCurve::CurveToLine( double dfMaxAngleStepSizeDegrees, const char* const* papszOptions ) const;
+ *
+ * \brief Return a linestring from a curve geometry.
+ *
+ * The returned geometry is a new instance whose ownership belongs to the caller.
+ *
+ * If the dfMaxAngleStepSizeDegrees is zero, then a default value will be
+ * used.  This is currently 4 degrees unless the user has overridden the
+ * value with the OGR_ARC_STEPSIZE configuration variable. 
+ *
+ * This method relates to the ISO SQL/MM Part 3 ICurve::CurveToLine() method.
+ *
+ * This function is the same as C function OGR_G_CurveToLine().
+ *
+ * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
+ * arc, zero to use the default setting.
+ * @param papszOptions options as a null-terminated list of strings or NULL.
+ *                     See OGRGeometryFactory::curveToLineString() for valid options.
+ *
+ * @return a line string approximating the curve
+ *
+ * @since GDAL 2.0
+ */
+
+/**
+ * \fn int OGRCurve::getNumPoints() const;
+ *
+ * \brief Return the number of points of a curve geometry.
+ *
+ *
+ * This method, as a method of OGRCurve, does not relate to a standard.
+ * For circular strings or linestrings, it returns the number of points,
+ * conforming to SF COM NumPoints().
+ * For compound curves, it returns the sum of the number of points of each
+ * of its components (non including intermediate starting/ending points of
+ * the different parts).
+ *
+ * @return the number of points of the curve.
+ *
+ * @since GDAL 2.0
+ */
+
+/**
+ * \fn OGRPointIterator* OGRCurve::getPointIterator() const;
+ *
+ * \brief Returns a point iterator over the curve.
+ *
+ * The curve must not be modified while an iterator exists on it.
+ *
+ * The iterator must be destroyed with OGRPointIterator::destroy().
+ *
+ * @return a point iterator over the curve.
+ *
+ * @since GDAL 2.0
+ */
+
+/**
+ * \fn double OGRCurve::get_Area() const;
+ *
+ * \brief Get the area of the (closed) curve.
+ *
+ * This method is designed to be used by OGRCurvePolygon::get_Area().
+ *
+ * @return the area of the feature in square units of the spatial reference
+ * system in use.
+ *
+ * @since GDAL 2.0
+ */
+
+/**
+ * \fn double OGRCurve::get_AreaOfCurveSegments() const;
+ *
+ * \brief Get the area of the purely curve portions of a (closed) curve.
+ *
+ * This method is designed to be used on a closed convex curve.
+ *
+ * @return the area of the feature in square units of the spatial reference
+ * system in use.
+ *
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                              IsConvex()                              */
+/************************************************************************/
+
+/**
+ * \brief Returns if a (closed) curve forms a convex shape.
+ *
+ * @return TRUE if the curve forms a convex shape.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRBoolean OGRCurve::IsConvex() const
+{
+    OGRBoolean bRet = TRUE;
+    OGRPointIterator* poPointIter = getPointIterator();
+    OGRPoint p1, p2, p3;
+    if( poPointIter->getNextPoint(&p1) &&
+        poPointIter->getNextPoint(&p2) )
+    {
+        while( poPointIter->getNextPoint(&p3) )
+        {
+            double crossproduct = (p2.getX() - p1.getX()) * (p3.getY() - p2.getY()) -
+                                  (p2.getY() - p1.getY()) * (p3.getX() - p2.getX());
+            if( crossproduct > 0 )
+            {
+                bRet = FALSE;
+                break;
+            }
+            p1.setX(p2.getX());
+            p1.setY(p2.getY());
+            p2.setX(p3.getX());
+            p2.setY(p3.getY());
+        }
+    }
+    delete poPointIter;
+    return bRet;
+}
+
+/************************************************************************/
+/*                          CastToCompoundCurve()                       */
+/************************************************************************/
+
+/**
+ * \brief Cast to compound curve
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poCurve the input geometry - ownership is passed to the method.
+ * @return new geometry
+ *
+ * @since GDAL 2.0
+ */
+
+OGRCompoundCurve* OGRCurve::CastToCompoundCurve(OGRCurve* poCurve)
+{
+    OGRCompoundCurve* poCC = new OGRCompoundCurve();
+    if( poCurve->getGeometryType() == wkbLineString )
+        poCurve = CastToLineString(poCurve);
+    if( !poCurve->IsEmpty() && poCC->addCurveDirectly(poCurve) != OGRERR_NONE )
+    {
+        delete poCC;
+        delete poCurve;
+        return NULL;
+    }
+    poCC->assignSpatialReference(poCurve->getSpatialReference());
+    return poCC;
+}
+
+/************************************************************************/
+/*                          CastToLineString()                          */
+/************************************************************************/
+
+/**
+ * \brief Cast to linestring
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poCurve the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRLineString* OGRCurve::CastToLineString(OGRCurve* poCurve)
+{
+    OGRCurveCasterToLineString pfn = poCurve->GetCasterToLineString();
+    return pfn(poCurve);
+}
+
+/************************************************************************/
+/*                          CastToLinearRing()                          */
+/************************************************************************/
+
+/**
+ * \brief Cast to linear ring
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poCurve the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRLinearRing* OGRCurve::CastToLinearRing(OGRCurve* poCurve)
+{
+    OGRCurveCasterToLinearRing pfn = poCurve->GetCasterToLinearRing();
+    return pfn(poCurve);
+}
+
+/************************************************************************/
+/*                           ContainsPoint()                            */
+/************************************************************************/
+
+/**
+ * \brief Returns if a point is contained in a (closed) curve.
+ *
+ * Final users should use OGRGeometry::Contains() instead.
+ * 
+ * @param p the point to test
+ * @return TRUE if it is inside the curve, FALSE otherwise or -1 if unknown.
+ *
+ * @since GDAL 2.0
+ */
+
+int OGRCurve::ContainsPoint( CPL_UNUSED const OGRPoint* p ) const
+{
+    return -1;
+}
+
+/************************************************************************/
+/*                          ~OGRPointIterator()                         */
+/************************************************************************/
+
+OGRPointIterator::~OGRPointIterator()
+{
+}
+
+/**
+ * \fn OGRBoolean OGRPointIterator::getNextPoint(OGRPoint* p);
+ *
+ * \brief Returns the next point followed by the iterator.
+ *
+ * @param p point to fill.
+ *
+ * @return TRUE in case of success, or FALSE if the end of the curve is reached.
+ *
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                              destroy()                               */
+/************************************************************************/
+
+/**
+ * \brief Destroys a point iterator.
+ *
+ * @since GDAL 2.0
+ */
+void OGRPointIterator::destroy(OGRPointIterator* poIter)
+{
+    delete poIter;
+}
diff --git a/ogr/ogrcurvecollection.cpp b/ogr/ogrcurvecollection.cpp
new file mode 100644
index 0000000..e5c5ea7
--- /dev/null
+++ b/ogr/ogrcurvecollection.cpp
@@ -0,0 +1,599 @@
+/******************************************************************************
+ * $Id: ogrcurvecollection.cpp 27960 2014-11-14 18:31:32Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRCurveCollection class.
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include <assert.h>
+
+CPL_CVSID("$Id");
+
+/************************************************************************/
+/*                         OGRCurveCollection()                         */
+/************************************************************************/
+
+OGRCurveCollection::OGRCurveCollection()
+
+{
+    nCurveCount = 0;
+    papoCurves = NULL;
+}
+
+/************************************************************************/
+/*                         ~OGRCurveCollection()                        */
+/************************************************************************/
+
+OGRCurveCollection::~OGRCurveCollection()
+
+{
+    empty(NULL);
+}
+
+/************************************************************************/
+/*                              WkbSize()                               */
+/************************************************************************/
+
+int OGRCurveCollection::WkbSize() const
+{
+    int         nSize = 9;
+
+    for( int i = 0; i < nCurveCount; i++ )
+    {
+        nSize += papoCurves[i]->WkbSize();
+    }
+
+    return nSize;
+}
+
+/************************************************************************/
+/*                          addCurveDirectly()                          */
+/************************************************************************/
+
+OGRErr OGRCurveCollection::addCurveDirectly( OGRGeometry* poGeom,
+                                             OGRCurve* poCurve,
+                                             int bNeedRealloc )
+{
+    if( poCurve->getCoordinateDimension() == 3 && poGeom->getCoordinateDimension() != 3 )
+        poGeom->setCoordinateDimension(3);
+    else if( poCurve->getCoordinateDimension() != 3 && poGeom->getCoordinateDimension() == 3 )
+        poCurve->setCoordinateDimension(3);
+
+    if( bNeedRealloc )
+    {
+        papoCurves = (OGRCurve **) OGRRealloc( papoCurves,
+                                             sizeof(OGRCurve*) * (nCurveCount+1) );
+    }
+
+    papoCurves[nCurveCount] = poCurve;
+
+    nCurveCount++;
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                        importPreambuleFromWkb()                      */
+/************************************************************************/
+
+OGRErr OGRCurveCollection::importPreambuleFromWkb( OGRGeometry* poGeom,
+                                                   unsigned char * pabyData,
+                                                   int& nSize,
+                                                   int& nDataOffset,
+                                                   OGRwkbByteOrder& eByteOrder,
+                                                   int nMinSubGeomSize,
+                                                   OGRwkbVariant eWkbVariant )
+{
+    OGRErr eErr = poGeom->importPreambuleOfCollectionFromWkb(
+                                                        pabyData,
+                                                        nSize,
+                                                        nDataOffset,
+                                                        eByteOrder,
+                                                        nMinSubGeomSize,
+                                                        nCurveCount,
+                                                        eWkbVariant );
+    if( eErr >= 0 )
+        return eErr;
+
+    papoCurves = (OGRCurve **) VSIMalloc2(sizeof(void*), nCurveCount);
+    if (nCurveCount != 0 && papoCurves == NULL)
+    {
+        nCurveCount = 0;
+        return OGRERR_NOT_ENOUGH_MEMORY;
+    }
+
+    return -1;
+}
+
+/************************************************************************/
+/*                       importBodyFromWkb()                            */
+/************************************************************************/
+
+OGRErr OGRCurveCollection::importBodyFromWkb( OGRGeometry* poGeom,
+                                       unsigned char * pabyData,
+                                       int nSize,
+                                       int nDataOffset,
+                                       int bAcceptCompoundCurve,
+                                       OGRErr (*pfnAddCurveDirectlyFromWkb)(OGRGeometry* poGeom, OGRCurve* poCurve),
+                                       OGRwkbVariant eWkbVariant )
+{
+
+/* -------------------------------------------------------------------- */
+/*      Get the Geoms.                                                  */
+/* -------------------------------------------------------------------- */
+    int nIter = nCurveCount;
+    nCurveCount = 0;
+    for( int iGeom = 0; iGeom < nIter; iGeom++ )
+    {
+        OGRErr  eErr;
+        OGRGeometry* poSubGeom = NULL;
+
+        /* Parses sub-geometry */
+        unsigned char* pabySubData = pabyData + nDataOffset;
+        if( nSize < 9 && nSize != -1 )
+            return OGRERR_NOT_ENOUGH_DATA;
+
+        OGRwkbGeometryType eSubGeomType;
+        OGRBoolean bIs3D;
+        if ( OGRReadWKBGeometryType( pabySubData, eWkbVariant, &eSubGeomType, &bIs3D ) != OGRERR_NONE )
+            return OGRERR_FAILURE;
+
+        if( (eSubGeomType != wkbCompoundCurve && OGR_GT_IsCurve(eSubGeomType)) ||
+            (bAcceptCompoundCurve && eSubGeomType == wkbCompoundCurve) )
+        {
+            eErr = OGRGeometryFactory::
+                createFromWkb( pabySubData, NULL,
+                               &poSubGeom, nSize, eWkbVariant );
+        }
+        else
+        {
+            CPLDebug("OGR", "Cannot add geometry of type (%d) to geometry of type (%d)",
+                     eSubGeomType, poGeom->getGeometryType());
+            return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
+        }
+
+        if( eErr == OGRERR_NONE )
+            eErr = pfnAddCurveDirectlyFromWkb(poGeom, (OGRCurve*)poSubGeom);
+        if( eErr != OGRERR_NONE )
+        {
+            delete poSubGeom;
+            return eErr;
+        }
+
+        int nSubGeomWkbSize = poSubGeom->WkbSize();
+        if( nSize != -1 )
+            nSize -= nSubGeomWkbSize;
+
+        nDataOffset += nSubGeomWkbSize;
+    }
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+
+OGRErr OGRCurveCollection::exportToWkt( const OGRGeometry* poGeom,
+                                        char ** ppszDstText ) const
+
+{
+    char        **papszGeoms;
+    int         iGeom, nCumulativeLength = 0;
+    OGRErr      eErr;
+
+    if( nCurveCount == 0 )
+    {
+        CPLString osEmpty;
+        if( poGeom->getCoordinateDimension()  == 3 )
+            osEmpty.Printf("%s Z EMPTY",poGeom->getGeometryName());
+        else
+            osEmpty.Printf("%s EMPTY",poGeom->getGeometryName());
+        *ppszDstText = CPLStrdup(osEmpty);
+        return OGRERR_NONE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Build a list of strings containing the stuff for each Geom.     */
+/* -------------------------------------------------------------------- */
+    papszGeoms = (char **) CPLCalloc(sizeof(char *),nCurveCount);
+
+    for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        eErr = papoCurves[iGeom]->exportToWkt( &(papszGeoms[iGeom]), wkbVariantIso );
+        if( eErr != OGRERR_NONE )
+            goto error;
+
+        nCumulativeLength += strlen(papszGeoms[iGeom]);
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Allocate the right amount of space for the aggregated string    */
+/* -------------------------------------------------------------------- */
+    *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nCurveCount +
+                                    strlen(poGeom->getGeometryName()) + 10);
+
+    if( *ppszDstText == NULL )
+    {
+        eErr = OGRERR_NOT_ENOUGH_MEMORY;
+        goto error;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Build up the string, freeing temporary strings as we go.        */
+/* -------------------------------------------------------------------- */
+    strcpy( *ppszDstText, poGeom->getGeometryName() );
+    if( poGeom->getCoordinateDimension() == 3 )
+        strcat( *ppszDstText, " Z" );
+    strcat( *ppszDstText, " (" );
+    nCumulativeLength = strlen(*ppszDstText);
+
+    for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        if( iGeom > 0 )
+            (*ppszDstText)[nCumulativeLength++] = ',';
+
+        /* We must strip the explicit "LINESTRING " prefix */
+        int nSkip = 0;
+        if( !papoCurves[iGeom]->IsEmpty() &&
+            EQUALN(papszGeoms[iGeom], "LINESTRING ", strlen("LINESTRING ")) )
+        {
+            nSkip = strlen("LINESTRING ");
+            if( EQUALN(papszGeoms[iGeom] + nSkip, "Z ", 2) )
+                nSkip += 2;
+        }
+
+        int nGeomLength = strlen(papszGeoms[iGeom] + nSkip);
+        memcpy( *ppszDstText + nCumulativeLength, papszGeoms[iGeom] + nSkip, nGeomLength );
+        nCumulativeLength += nGeomLength;
+        VSIFree( papszGeoms[iGeom] );
+    }
+
+    (*ppszDstText)[nCumulativeLength++] = ')';
+    (*ppszDstText)[nCumulativeLength] = '\0';
+
+    CPLFree( papszGeoms );
+
+    return OGRERR_NONE;
+
+error:
+    for( iGeom = 0; iGeom < nCurveCount; iGeom++ )
+        CPLFree( papszGeoms[iGeom] );
+    CPLFree( papszGeoms );
+    return eErr;
+}
+
+/************************************************************************/
+/*                            exportToWkb()                             */
+/************************************************************************/
+
+OGRErr OGRCurveCollection::exportToWkb( const OGRGeometry* poGeom,
+                                        OGRwkbByteOrder eByteOrder,
+                                        unsigned char * pabyData,
+                                        OGRwkbVariant eWkbVariant ) const
+{
+    int         nOffset;
+    
+/* -------------------------------------------------------------------- */
+/*      Set the byte order.                                             */
+/* -------------------------------------------------------------------- */
+    pabyData[0] = DB2_V72_UNFIX_BYTE_ORDER((unsigned char) eByteOrder);
+
+/* -------------------------------------------------------------------- */
+/*      Set the geometry feature type, ensuring that 3D flag is         */
+/*      preserved.                                                      */
+/* -------------------------------------------------------------------- */
+    GUInt32 nGType = poGeom->getIsoGeometryType();
+    if( eWkbVariant == wkbVariantPostGIS1 )
+    {
+        int bIs3D = wkbHasZ((OGRwkbGeometryType)nGType);
+        nGType = wkbFlatten(nGType);
+        if( nGType == wkbCurvePolygon )
+            nGType = POSTGIS15_CURVEPOLYGON;
+        if( bIs3D )
+            nGType = (OGRwkbGeometryType)(nGType | wkb25DBitInternalUse); /* yes we explicitely set wkb25DBit */
+    }
+
+    if( eByteOrder == wkbNDR )
+        nGType = CPL_LSBWORD32( nGType );
+    else
+        nGType = CPL_MSBWORD32( nGType );
+
+    memcpy( pabyData + 1, &nGType, 4 );
+    
+/* -------------------------------------------------------------------- */
+/*      Copy in the raw data.                                           */
+/* -------------------------------------------------------------------- */
+    if( OGR_SWAP( eByteOrder ) )
+    {
+        int     nCount;
+
+        nCount = CPL_SWAP32( nCurveCount );
+        memcpy( pabyData+5, &nCount, 4 );
+    }
+    else
+    {
+        memcpy( pabyData+5, &nCurveCount, 4 );
+    }
+    
+    nOffset = 9;
+    
+/* ==================================================================== */
+/*      Serialize each of the Geoms.                                    */
+/* ==================================================================== */
+    for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        papoCurves[iGeom]->exportToWkb( eByteOrder, pabyData + nOffset, eWkbVariant );
+
+        nOffset += papoCurves[iGeom]->WkbSize();
+    }
+    
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                               empty()                                */
+/************************************************************************/
+
+void OGRCurveCollection::empty(OGRGeometry* poGeom)
+{
+    if( papoCurves != NULL )
+    {
+        for( int i = 0; i < nCurveCount; i++ )
+        {
+            delete papoCurves[i];
+        }
+        OGRFree( papoCurves );
+    }
+
+    nCurveCount = 0;
+    papoCurves = NULL;
+    if( poGeom )
+        poGeom->setCoordinateDimension(2);
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCurveCollection::getEnvelope( OGREnvelope * psEnvelope ) const
+{
+    OGREnvelope3D         oEnv3D;
+    getEnvelope(&oEnv3D);
+    psEnvelope->MinX = oEnv3D.MinX;
+    psEnvelope->MinY = oEnv3D.MinY;
+    psEnvelope->MaxX = oEnv3D.MaxX;
+    psEnvelope->MaxY = oEnv3D.MaxY;
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCurveCollection::getEnvelope( OGREnvelope3D * psEnvelope ) const
+{
+    OGREnvelope3D       oGeomEnv;
+    int                 bExtentSet = FALSE;
+
+    for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        if (!papoCurves[iGeom]->IsEmpty())
+        {
+            if (!bExtentSet)
+            {
+                papoCurves[iGeom]->getEnvelope( psEnvelope );
+                bExtentSet = TRUE;
+            }
+            else
+            {
+                papoCurves[iGeom]->getEnvelope( &oGeomEnv );
+                psEnvelope->Merge( oGeomEnv );
+            }
+        }
+    }
+
+    if (!bExtentSet)
+    {
+        psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
+        psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
+    }
+}
+
+/************************************************************************/
+/*                               IsEmpty()                              */
+/************************************************************************/
+
+OGRBoolean OGRCurveCollection::IsEmpty() const
+{
+    return nCurveCount == 0;
+}
+
+/************************************************************************/
+/*                               Equals()                                */
+/************************************************************************/
+
+OGRBoolean  OGRCurveCollection::Equals( OGRCurveCollection *poOCC ) const
+{
+    if( getNumCurves() != poOCC->getNumCurves() )
+        return FALSE;
+    
+    // we should eventually test the SRS.
+
+    for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        if( !getCurve(iGeom)->Equals(poOCC->getCurve(iGeom)) )
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                       setCoordinateDimension()                       */
+/************************************************************************/
+
+void OGRCurveCollection::setCoordinateDimension( OGRGeometry* poGeom,
+                                                 int nNewDimension )
+{
+    for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        papoCurves[iGeom]->setCoordinateDimension( nNewDimension );
+    }
+
+    poGeom->OGRGeometry::setCoordinateDimension( nNewDimension );
+}
+
+/************************************************************************/
+/*                          getNumCurves()                              */
+/************************************************************************/
+
+int          OGRCurveCollection::getNumCurves() const
+{
+    return nCurveCount;
+}
+
+/************************************************************************/
+/*                           getCurve()                                 */
+/************************************************************************/
+
+OGRCurve    *OGRCurveCollection::getCurve( int i )
+{
+    if( i < 0 || i >= nCurveCount )
+        return NULL;
+    return papoCurves[i];
+}
+
+/************************************************************************/
+/*                           getCurve()                                 */
+/************************************************************************/
+
+const OGRCurve *OGRCurveCollection::getCurve( int i ) const
+{
+    if( i < 0 || i >= nCurveCount )
+        return NULL;
+    return papoCurves[i];
+}
+
+/************************************************************************/
+/*                           stealCurve()                               */
+/************************************************************************/
+
+OGRCurve* OGRCurveCollection::stealCurve( int i )
+{
+    if( i < 0 || i >= nCurveCount )
+        return NULL;
+    OGRCurve* poRet = papoCurves[i];
+    if( i < nCurveCount - 1 )
+    {
+        memmove(papoCurves + i, papoCurves + i + 1, (nCurveCount - i - 1) * sizeof(OGRCurve*));
+    }
+    nCurveCount --;
+    return poRet;
+}
+
+/************************************************************************/
+/*                             transform()                              */
+/************************************************************************/
+
+OGRErr  OGRCurveCollection::transform( OGRGeometry* poGeom,
+                                       OGRCoordinateTransformation *poCT )
+{
+#ifdef DISABLE_OGRGEOM_TRANSFORM
+    return OGRERR_FAILURE;
+#else
+    for( int iGeom = 0; iGeom < nCurveCount; iGeom++ )
+    {
+        OGRErr  eErr;
+
+        eErr = papoCurves[iGeom]->transform( poCT );
+        if( eErr != OGRERR_NONE )
+        {
+            if( iGeom != 0 )
+            {
+                CPLDebug("OGR", 
+                         "OGRCurveCollection::transform() failed for a geometry other\n"
+                         "than the first, meaning some geometries are transformed\n"
+                         "and some are not!\n" );
+
+                return OGRERR_FAILURE;
+            }
+
+            return eErr;
+        }
+    }
+
+    poGeom->assignSpatialReference( poCT->GetTargetCS() );
+
+    return OGRERR_NONE;
+#endif
+}
+
+/************************************************************************/
+/*                            flattenTo2D()                             */
+/************************************************************************/
+
+void OGRCurveCollection::flattenTo2D(OGRGeometry* poGeom)
+{
+    for( int i = 0; i < nCurveCount; i++ )
+        papoCurves[i]->flattenTo2D();
+
+    poGeom->setCoordinateDimension(2);
+}
+
+/************************************************************************/
+/*                              segmentize()                            */
+/************************************************************************/
+
+void OGRCurveCollection::segmentize(double dfMaxLength)
+{
+    for( int i = 0; i < nCurveCount; i++ )
+        papoCurves[i]->segmentize(dfMaxLength);
+}
+
+/************************************************************************/
+/*                               swapXY()                               */
+/************************************************************************/
+
+void OGRCurveCollection::swapXY()
+{
+    for( int i = 0; i < nCurveCount; i++ )
+        papoCurves[i]->swapXY();
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRCurveCollection::hasCurveGeometry(int bLookForNonLinear) const
+{
+    for( int i = 0; i < nCurveCount; i++ )
+    {
+        if( papoCurves[i]->hasCurveGeometry(bLookForNonLinear) )
+            return TRUE;
+    }
+    return FALSE;
+}
diff --git a/ogr/ogrcurvepolygon.cpp b/ogr/ogrcurvepolygon.cpp
new file mode 100644
index 0000000..5edd963
--- /dev/null
+++ b/ogr/ogrcurvepolygon.cpp
@@ -0,0 +1,717 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRCurvePolygon geometry class.
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include "ogr_geos.h"
+#include "ogr_api.h"
+
+CPL_CVSID("$Id$");
+
+/************************************************************************/
+/*                            OGRCurvePolygon()                         */
+/************************************************************************/
+
+/**
+ * \brief Create an empty curve polygon.
+ */
+
+OGRCurvePolygon::OGRCurvePolygon()
+
+{
+}
+
+/************************************************************************/
+/*                           ~OGRCurvePolygon()                         */
+/************************************************************************/
+
+OGRCurvePolygon::~OGRCurvePolygon()
+
+{
+}
+
+/************************************************************************/
+/*                               clone()                                */
+/************************************************************************/
+
+OGRGeometry *OGRCurvePolygon::clone() const
+
+{
+    OGRCurvePolygon  *poNewPolygon;
+
+    poNewPolygon = (OGRCurvePolygon*)
+            OGRGeometryFactory::createGeometry(getGeometryType());
+    poNewPolygon->assignSpatialReference( getSpatialReference() );
+
+    for( int i = 0; i < oCC.nCurveCount; i++ )
+    {
+        poNewPolygon->addRing( oCC.papoCurves[i] );
+    }
+
+    return poNewPolygon;
+}
+
+/************************************************************************/
+/*                               empty()                                */
+/************************************************************************/
+
+void OGRCurvePolygon::empty()
+
+{
+    oCC.empty(this);
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRCurvePolygon::getGeometryType() const
+
+{
+    if( nCoordDimension == 3 )
+        return wkbCurvePolygonZ;
+    else
+        return wkbCurvePolygon;
+}
+
+/************************************************************************/
+/*                            getDimension()                            */
+/************************************************************************/
+
+int OGRCurvePolygon::getDimension() const
+
+{
+    return 2;
+}
+
+/************************************************************************/
+/*                            flattenTo2D()                             */
+/************************************************************************/
+
+void OGRCurvePolygon::flattenTo2D()
+
+{
+    oCC.flattenTo2D(this);
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRCurvePolygon::getGeometryName() const
+
+{
+    return "CURVEPOLYGON";
+}
+
+/************************************************************************/
+/*                         getExteriorRingCurve()                       */
+/************************************************************************/
+
+/**
+ * \brief Fetch reference to external polygon ring.
+ *
+ * Note that the returned ring pointer is to an internal data object of
+ * the OGRCurvePolygon.  It should not be modified or deleted by the application,
+ * and the pointer is only valid till the polygon is next modified.  Use
+ * the OGRGeometry::clone() method to make a separate copy within the
+ * application.
+ *
+ * Relates to the SFCOM IPolygon::get_ExteriorRing() method.
+ *
+ * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is empty.
+ */
+
+OGRCurve *OGRCurvePolygon::getExteriorRingCurve()
+
+{
+    return oCC.getCurve(0);
+}
+
+const OGRCurve *OGRCurvePolygon::getExteriorRingCurve() const
+
+{
+    return oCC.getCurve(0);
+}
+
+/************************************************************************/
+/*                        getNumInteriorRings()                         */
+/************************************************************************/
+
+/**
+ * \brief Fetch the number of internal rings.
+ *
+ * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
+ *
+ * @return count of internal rings, zero or more.
+ */
+
+
+int OGRCurvePolygon::getNumInteriorRings() const
+
+{
+    if( oCC.nCurveCount > 0 )
+        return oCC.nCurveCount-1;
+    else
+        return 0;
+}
+
+/************************************************************************/
+/*                       getInteriorRingCurve()                         */
+/************************************************************************/
+
+/**
+ * \brief Fetch reference to indicated internal ring.
+ *
+ * Note that the returned ring pointer is to an internal data object of
+ * the OGRCurvePolygon.  It should not be modified or deleted by the application,
+ * and the pointer is only valid till the polygon is next modified.  Use
+ * the OGRGeometry::clone() method to make a separate copy within the
+ * application.
+ *
+ * Relates to the SFCOM IPolygon::get_InternalRing() method.
+ *
+ * @param iRing internal ring index from 0 to getNumInternalRings() - 1.
+ *
+ * @return pointer to interior ring.  May be NULL.
+ */
+
+OGRCurve *OGRCurvePolygon::getInteriorRingCurve( int iRing )
+
+{
+    return oCC.getCurve(iRing + 1);
+}
+
+const OGRCurve *OGRCurvePolygon::getInteriorRingCurve( int iRing ) const
+
+{
+    return oCC.getCurve(iRing + 1);
+}
+
+/************************************************************************/
+/*                        stealExteriorRingCurve()                      */
+/************************************************************************/
+
+/**
+ * \brief "Steal" reference to external ring.
+ *
+ * After the call to that function, only call to stealInteriorRing() or
+ * destruction of the OGRCurvePolygon is valid. Other operations may crash.
+ *
+ * @return pointer to external ring.  May be NULL if the OGRCurvePolygon is empty.
+ */
+
+OGRCurve *OGRCurvePolygon::stealExteriorRingCurve()
+{
+    if( oCC.nCurveCount == 0 )
+        return NULL;
+    OGRCurve *poRet = oCC.papoCurves[0];
+    oCC.papoCurves[0] = NULL;
+    return poRet;
+}
+
+/************************************************************************/
+/*                              addRing()                               */
+/************************************************************************/
+
+/**
+ * \brief Add a ring to a polygon.
+ *
+ * If the polygon has no external ring (it is empty) this will be used as
+ * the external ring, otherwise it is used as an internal ring.  The passed
+ * OGRCurve remains the responsibility of the caller (an internal copy
+ * is made).
+ *
+ * This method has no SFCOM analog.
+ *
+ * @param poNewRing ring to be added to the polygon.
+ * @return OGRERR_NONE in case of success
+ */
+
+OGRErr OGRCurvePolygon::addRing( OGRCurve * poNewRing )
+
+{
+    OGRCurve* poNewRingCloned = (OGRCurve* )poNewRing->clone();
+    OGRErr eErr = addRingDirectly(poNewRingCloned);
+    if( eErr != OGRERR_NONE )
+        delete poNewRingCloned;
+    return eErr;
+}
+
+/************************************************************************/
+/*                            checkRing()                               */
+/************************************************************************/
+
+int OGRCurvePolygon::checkRing( OGRCurve * poNewRing ) const
+{
+    if( !poNewRing->IsEmpty() && !poNewRing->get_IsClosed() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Non closed ring.");
+        return FALSE;
+    }
+
+    if( wkbFlatten(poNewRing->getGeometryType()) == wkbLineString )
+    {
+        if( poNewRing->getNumPoints() == 0 || poNewRing->getNumPoints() < 4 )
+        {
+            return FALSE;
+        }
+
+        if( EQUAL(poNewRing->getGeometryName(), "LINEARRING") )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Linearring not allowed.");
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          addRingDirectly()                           */
+/************************************************************************/
+
+/**
+ * \brief Add a ring to a polygon.
+ *
+ * If the polygon has no external ring (it is empty) this will be used as
+ * the external ring, otherwise it is used as an internal ring.  Ownership
+ * of the passed ring is assumed by the OGRCurvePolygon, but otherwise this
+ * method operates the same as OGRCurvePolygon::AddRing().
+ *
+ * This method has no SFCOM analog.
+ *
+ * @param poNewRing ring to be added to the polygon.
+ * @return OGRERR_NONE in case of success
+ */
+
+OGRErr OGRCurvePolygon::addRingDirectly( OGRCurve * poNewRing )
+{
+    return addRingDirectlyInternal( poNewRing, TRUE );
+}
+
+OGRErr OGRCurvePolygon::addRingDirectlyInternal( OGRCurve* poNewRing,
+                                                 int bNeedRealloc )
+{
+    if( !checkRing(poNewRing) )
+        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
+
+    return oCC.addCurveDirectly(this, poNewRing, bNeedRealloc);
+}
+
+/************************************************************************/
+/*                              WkbSize()                               */
+/*                                                                      */
+/*      Return the size of this object in well known binary             */
+/*      representation including the byte order, and type information.  */
+/************************************************************************/
+
+int OGRCurvePolygon::WkbSize() const
+
+{
+    return oCC.WkbSize();
+}
+
+/************************************************************************/
+/*                       addCurveDirectlyFromWkt()                      */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::addCurveDirectlyFromWkb( OGRGeometry* poSelf,
+                                                 OGRCurve* poCurve )
+{
+    OGRCurvePolygon* poCP = (OGRCurvePolygon*)poSelf;
+    return poCP->addRingDirectlyInternal( poCurve, FALSE );
+}
+
+/************************************************************************/
+/*                           importFromWkb()                            */
+/*                                                                      */
+/*      Initialize from serialized stream in well known binary          */
+/*      format.                                                         */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::importFromWkb( unsigned char * pabyData,
+                                       int nSize,
+                                       OGRwkbVariant eWkbVariant )
+
+{
+    OGRwkbByteOrder eByteOrder;
+    int nDataOffset = 0;
+    OGRErr eErr = oCC.importPreambuleFromWkb(this, pabyData, nSize, nDataOffset,
+                                             eByteOrder, 9, eWkbVariant);
+    if( eErr >= 0 )
+        return eErr;
+
+    return oCC.importBodyFromWkb(this, pabyData, nSize, nDataOffset,
+                                 TRUE /* bAcceptCompoundCurve */, addCurveDirectlyFromWkb,
+                                 eWkbVariant);
+}
+
+/************************************************************************/
+/*                            exportToWkb()                             */
+/*                                                                      */
+/*      Build a well known binary representation of this object.        */
+/************************************************************************/
+
+OGRErr  OGRCurvePolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
+                                      unsigned char * pabyData,
+                                      OGRwkbVariant eWkbVariant ) const
+
+{
+    if( eWkbVariant == wkbVariantOldOgc ) /* does not make sense for new geometries, so patch it */
+        eWkbVariant = wkbVariantIso;
+    return oCC.exportToWkb(this, eByteOrder, pabyData, eWkbVariant);
+}
+
+/************************************************************************/
+/*                       addCurveDirectlyFromWkt()                      */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve )
+{
+    return ((OGRCurvePolygon*)poSelf)->addRingDirectly(poCurve);
+}
+
+/************************************************************************/
+/*                           importFromWkt()                            */
+/*                                                                      */
+/*      Instantiate from well known text format.                        */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::importFromWkt( char ** ppszInput )
+
+{
+    return importCurveCollectionFromWkt( ppszInput,
+                                         FALSE, /* bAllowEmptyComponent */
+                                         TRUE, /* bAllowLineString */
+                                         TRUE, /* bAllowCurve */
+                                         TRUE, /* bAllowCompoundCurve */
+                                         addCurveDirectlyFromWkt );
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::exportToWkt( char ** ppszDstText,
+                                CPL_UNUSED OGRwkbVariant eWkbVariant ) const
+
+{
+    return oCC.exportToWkt(this, ppszDstText);
+}
+
+/************************************************************************/
+/*                           CurvePolyToPoly()                          */
+/************************************************************************/
+
+/**
+ * \brief Return a polygon from a curve polygon.
+ *
+ * This method is the same as C function OGR_G_CurvePolyToPoly().
+ *
+ * The returned geometry is a new instance whose ownership belongs to the caller.
+ *
+ * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
+ * arc, zero to use the default setting.
+ * @param papszOptions options as a null-terminated list of strings.
+ *                     Unused for now. Must be set to NULL.
+ *
+ * @return a linestring
+ *
+ * @since OGR 2.0
+ */
+
+OGRPolygon* OGRCurvePolygon::CurvePolyToPoly(double dfMaxAngleStepSizeDegrees,
+                                             const char* const* papszOptions) const
+{
+    OGRPolygon* poPoly = new OGRPolygon();
+    poPoly->assignSpatialReference(getSpatialReference());
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
+    {
+        OGRLineString* poLS = oCC.papoCurves[iRing]->CurveToLine(dfMaxAngleStepSizeDegrees,
+                                                                 papszOptions);
+        poPoly->addRingDirectly(OGRCurve::CastToLinearRing(poLS));
+    }
+    return poPoly;
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::hasCurveGeometry(int bLookForNonLinear) const
+{
+    if( bLookForNonLinear )
+    {
+        return oCC.hasCurveGeometry(bLookForNonLinear);
+    }
+    else
+        return TRUE;
+}
+
+/************************************************************************/
+/*                         getLinearGeometry()                        */
+/************************************************************************/
+
+OGRGeometry* OGRCurvePolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
+                                                  const char* const* papszOptions) const
+{
+    return CurvePolyToPoly(dfMaxAngleStepSizeDegrees, papszOptions);
+}
+
+/************************************************************************/
+/*                           PointOnSurface()                           */
+/************************************************************************/
+
+int OGRCurvePolygon::PointOnSurface( OGRPoint *poPoint ) const
+
+{
+    OGRPolygon* poPoly = CurvePolyToPoly();
+    int ret = poPoly->PointOnSurface(poPoint);
+    delete poPoly;
+    return ret;
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+
+void OGRCurvePolygon::getEnvelope( OGREnvelope * psEnvelope ) const
+
+{
+    oCC.getEnvelope(psEnvelope);
+}
+
+/************************************************************************/
+/*                            getEnvelope()                             */
+/************************************************************************/
+ 
+void OGRCurvePolygon::getEnvelope( OGREnvelope3D * psEnvelope ) const
+
+{
+    oCC.getEnvelope(psEnvelope);
+}
+
+/************************************************************************/
+/*                               Equal()                                */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::Equals( OGRGeometry * poOther ) const
+
+{
+    OGRCurvePolygon *poOPoly = (OGRCurvePolygon *) poOther;
+
+    if( poOPoly == this )
+        return TRUE;
+    
+    if( poOther->getGeometryType() != getGeometryType() )
+        return FALSE;
+
+    if ( IsEmpty() && poOther->IsEmpty() )
+        return TRUE;
+    
+    return oCC.Equals( &(poOPoly->oCC) );
+}
+
+/************************************************************************/
+/*                             transform()                              */
+/************************************************************************/
+
+OGRErr OGRCurvePolygon::transform( OGRCoordinateTransformation *poCT )
+
+{
+    return oCC.transform(this, poCT);
+}
+
+/************************************************************************/
+/*                              get_Area()                              */
+/************************************************************************/
+
+double OGRCurvePolygon::get_Area() const
+
+{
+    double dfArea = 0.0;
+
+    if( getExteriorRingCurve() != NULL )
+    {
+        int iRing;
+
+        dfArea = getExteriorRingCurve()->get_Area();
+
+        for( iRing = 0; iRing < getNumInteriorRings(); iRing++ )
+        {
+            dfArea -= getInteriorRingCurve(iRing)->get_Area();
+        }
+    }
+
+    return dfArea;
+}
+
+/************************************************************************/
+/*                       setCoordinateDimension()                       */
+/************************************************************************/
+
+void OGRCurvePolygon::setCoordinateDimension( int nNewDimension )
+
+{
+    oCC.setCoordinateDimension(this, nNewDimension);
+}
+
+
+/************************************************************************/
+/*                               IsEmpty()                              */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::IsEmpty(  ) const
+{
+    return oCC.IsEmpty();
+}
+
+/************************************************************************/
+/*                              segmentize()                            */
+/************************************************************************/
+
+void OGRCurvePolygon::segmentize( double dfMaxLength )
+{
+    oCC.segmentize(dfMaxLength);
+}
+
+/************************************************************************/
+/*                               swapXY()                               */
+/************************************************************************/
+
+void OGRCurvePolygon::swapXY()
+{
+    oCC.swapXY();
+}
+
+/************************************************************************/
+/*                           ContainsPoint()                             */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::ContainsPoint( const OGRPoint* p ) const
+{
+    if( getExteriorRingCurve() != NULL &&
+        getNumInteriorRings() == 0 )
+    {
+        int nRet = getExteriorRingCurve()->ContainsPoint(p);
+        if( nRet >= 0 )
+            return nRet;
+    }
+    return OGRGeometry::Contains(p);
+}
+
+/************************************************************************/
+/*                               Contains()                             */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::Contains( const OGRGeometry *poOtherGeom ) const
+
+{
+    if( !IsEmpty() && poOtherGeom != NULL &&
+        wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint )
+    {
+        return ContainsPoint((OGRPoint*)poOtherGeom);
+    }
+    else
+        return OGRGeometry::Contains(poOtherGeom);
+}
+
+/************************************************************************/
+/*                              Intersects()                            */
+/************************************************************************/
+
+OGRBoolean OGRCurvePolygon::Intersects( const OGRGeometry *poOtherGeom ) const
+
+{
+    if( !IsEmpty() && poOtherGeom != NULL &&
+        wkbFlatten(poOtherGeom->getGeometryType()) == wkbPoint )
+    {
+        return ContainsPoint((OGRPoint*)poOtherGeom);
+    }
+    else
+        return OGRGeometry::Intersects(poOtherGeom);
+}
+
+/************************************************************************/
+/*                           CastToPolygon()                            */
+/************************************************************************/
+
+/**
+ * \brief Convert to polygon.
+ *
+ * This method should only be called if the curve polygon actually only contains
+ * instances of OGRLineString. This can be verified if hasCurveGeometry(TRUE)
+ * returns FALSE. It is not intended to approximate curve polygons. For that
+ * use getLinearGeometry().
+ * 
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure). 
+ * 
+ * @param poMS the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRPolygon* OGRCurvePolygon::CastToPolygon(OGRCurvePolygon* poCP)
+{
+    for(int i=0;i<poCP->oCC.nCurveCount;i++)
+    {
+        poCP->oCC.papoCurves[i] = OGRCurve::CastToLinearRing(poCP->oCC.papoCurves[i]);
+        if( poCP->oCC.papoCurves[i] == NULL )
+        {
+            delete poCP;
+            return NULL;
+        }
+    }
+    OGRPolygon* poPoly = new OGRPolygon();
+    poPoly->setCoordinateDimension(poCP->getCoordinateDimension());
+    poPoly->assignSpatialReference(poCP->getSpatialReference());
+    poPoly->oCC.nCurveCount = poCP->oCC.nCurveCount;
+    poPoly->oCC.papoCurves = poCP->oCC.papoCurves;
+    poCP->oCC.nCurveCount = 0;
+    poCP->oCC.papoCurves = NULL;
+    delete poCP;
+    return poPoly;
+}
+
+/************************************************************************/
+/*                      GetCasterToPolygon()                            */
+/************************************************************************/
+
+OGRSurfaceCasterToPolygon OGRCurvePolygon::GetCasterToPolygon() const {
+    return (OGRSurfaceCasterToPolygon) OGRCurvePolygon::CastToPolygon;
+}
+
+/************************************************************************/
+/*                      OGRSurfaceCasterToCurvePolygon()                */
+/************************************************************************/
+
+OGRSurfaceCasterToCurvePolygon OGRCurvePolygon::GetCasterToCurvePolygon() const {
+    return (OGRSurfaceCasterToCurvePolygon) OGRGeometry::CastToIdentity;
+}
diff --git a/ogr/ogrfeature.cpp b/ogr/ogrfeature.cpp
index da53f76..a1cd3a6 100644
--- a/ogr/ogrfeature.cpp
+++ b/ogr/ogrfeature.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfeature.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrfeature.cpp 28900 2015-04-14 09:40:34Z rouault $
  * 
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRFeature class implementation. 
@@ -31,9 +31,11 @@
 #include "ogr_feature.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
+#include "cpl_time.h"
 #include <vector>
+#include <errno.h>
 
-CPL_CVSID("$Id: ogrfeature.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrfeature.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 /************************************************************************/
 /*                             OGRFeature()                             */
@@ -140,6 +142,7 @@ OGRFeature::~OGRFeature()
             break;
 
           case OFTIntegerList:
+          case OFTInteger64List:
           case OFTRealList:
             CPLFree( pauFields[i].IntegerList.paList );
             break;
@@ -510,7 +513,18 @@ OGRGeometryH OGR_F_GetGeometryRef( OGRFeatureH hFeat )
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_GetGeometryRef", NULL );
 
-    return (OGRGeometryH) ((OGRFeature *) hFeat)->GetGeometryRef();
+    OGRFeature* poFeature = (OGRFeature *) hFeat; 
+    OGRGeometry* poGeom = poFeature->GetGeometryRef();
+
+    if( !OGRGetNonLinearGeometriesEnabledFlag() && poGeom != NULL &&
+        OGR_GT_IsNonLinear(poGeom->getGeometryType()) )
+    {
+        OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(poGeom->getGeometryType());
+        poGeom = OGRGeometryFactory::forceTo(poFeature->StealGeometry(), eTargetType);
+        poFeature->SetGeomFieldDirectly(0, poGeom);
+    }
+
+    return (OGRGeometryH)poGeom;
 }
 
 
@@ -585,7 +599,18 @@ OGRGeometryH OGR_F_GetGeomFieldRef( OGRFeatureH hFeat, int iField )
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_GetGeomFieldRef", NULL );
 
-    return (OGRGeometryH) ((OGRFeature *) hFeat)->GetGeomFieldRef(iField);
+    OGRFeature* poFeature = (OGRFeature *) hFeat; 
+    OGRGeometry* poGeom = poFeature->GetGeomFieldRef(iField);
+
+    if( !OGRGetNonLinearGeometriesEnabledFlag() && poGeom != NULL &&
+        OGR_GT_IsNonLinear(poGeom->getGeometryType()) )
+    {
+        OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(poGeom->getGeometryType());
+        poGeom = OGRGeometryFactory::forceTo(poFeature->StealGeometry(iField), eTargetType);
+        poFeature->SetGeomFieldDirectly(iField, poGeom);
+    }
+
+    return (OGRGeometryH)poGeom;
 }
 
 /************************************************************************/
@@ -608,7 +633,7 @@ OGRGeometryH OGR_F_GetGeomFieldRef( OGRFeatureH hFeat, int iField )
  *
  * @return OGRERR_NONE if successful, or OGRERR_FAILURE if the index is invalid,
  * or OGR_UNSUPPORTED_GEOMETRY_TYPE if the geometry type is illegal for the
- * OGRFeatureDefn (checking not yet implemented). 
+ * OGRFeatureDefn (checking not yet implemented).
  *
  * @since GDAL 1.11
  */ 
@@ -877,6 +902,12 @@ OGRFieldDefnH OGR_F_GetFieldDefnRef( OGRFeatureH hFeat, int i )
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_GetFieldDefnRef", NULL );
 
+    if( i < 0 || i >= ((OGRFeature *) hFeat)->GetFieldCount() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid index : %d", i);
+        return NULL;
+    }
+
     return (OGRFieldDefnH) ((OGRFeature *) hFeat)->GetFieldDefnRef(i);
 }
 
@@ -1167,6 +1198,7 @@ void OGRFeature::UnsetField( int iField )
     {
       case OFTRealList:
       case OFTIntegerList:
+      case OFTInteger64List:
         CPLFree( pauFields[iField].IntegerList.paList );
         break;
 
@@ -1260,7 +1292,8 @@ OGRField *OGR_F_GetRawFieldRef( OGRFeatureH hFeat, int iField )
  * \brief Fetch field value as integer.
  *
  * OFTString features will be translated using atoi().  OFTReal fields
- * will be cast to integer.   Other field types, or errors will result in
+ * will be cast to integer. OFTInteger64 are demoted to 32 bit, with
+ * clamping if out-of-range. Other field types, or errors will result in
  * a return value of zero.
  *
  * This method is the same as the C function OGR_F_GetFieldAsInteger().
@@ -1280,7 +1313,16 @@ int OGRFeature::GetFieldAsInteger( int iField )
         switch (iSpecialField)
         {
         case SPF_FID:
-            return GetFID();
+        {
+            int nVal = (nFID > INT_MAX) ? INT_MAX : (nFID < INT_MIN) ? INT_MIN : (int) nFID;
+            if( (GIntBig)nVal != nFID )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                 "Integer overflow occured when trying to return 64bit integer. "
+                 "Use GetFieldAsInteger64() instead");
+            }
+            return nVal;
+        }
 
         case SPF_OGR_GEOM_AREA:
             if( GetGeomFieldCount() == 0 || papoGeometries[0] == NULL )
@@ -1300,11 +1342,24 @@ int OGRFeature::GetFieldAsInteger( int iField )
     if( !IsFieldSet(iField) )
         return 0;
     
-    if( poFDefn->GetType() == OFTInteger )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTInteger )
         return pauFields[iField].Integer;
-    else if( poFDefn->GetType() == OFTReal )
+    else if( eType == OFTInteger64 )
+    {
+        GIntBig nVal64 = pauFields[iField].Integer64;
+        int nVal = (nVal64 > INT_MAX) ? INT_MAX : (nVal64 < INT_MIN) ? INT_MIN : (int) nVal64;
+        if( (GIntBig)nVal != nVal64 )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                 "Integer overflow occured when trying to return 64bit integer. "
+                 "Use GetFieldAsInteger64() instead");
+        }
+        return nVal;
+    }
+    else if( eType == OFTReal )
         return (int) pauFields[iField].Real;
-    else if( poFDefn->GetType() == OFTString )
+    else if( eType == OFTString )
     {
         if( pauFields[iField].String == NULL )
             return 0;
@@ -1343,13 +1398,112 @@ int OGR_F_GetFieldAsInteger( OGRFeatureH hFeat, int iField )
 }
 
 /************************************************************************/
+/*                        GetFieldAsInteger64()                         */
+/************************************************************************/
+
+/**
+ * \brief Fetch field value as integer 64 bit.
+ *
+ * OFTInteger are promoted to 64 bit.
+ * OFTString features will be translated using CPLAtoGIntBig().  OFTReal fields
+ * will be cast to integer.   Other field types, or errors will result in
+ * a return value of zero.
+ *
+ * This method is the same as the C function OGR_F_GetFieldAsInteger64().
+ *
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ *
+ * @return the field value.
+ * @since GDAL 2.0
+ */
+
+GIntBig OGRFeature::GetFieldAsInteger64( int iField )
+
+{
+    int iSpecialField = iField - poDefn->GetFieldCount();
+    if (iSpecialField >= 0)
+    {
+    // special field value accessors
+        switch (iSpecialField)
+        {
+        case SPF_FID:
+            return nFID;
+        
+        case SPF_OGR_GEOM_AREA:
+            if( GetGeomFieldCount() == 0 || papoGeometries[0] == NULL )
+                return 0;
+            return (int)OGR_G_Area((OGRGeometryH)papoGeometries[0]);
+
+        default:
+            return 0;
+        }
+    }
+    
+    OGRFieldDefn        *poFDefn = poDefn->GetFieldDefn( iField );
+    
+    if( poFDefn == NULL )
+        return 0;
+    
+    if( !IsFieldSet(iField) )
+        return 0;
+    
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTInteger )
+        return (GIntBig) pauFields[iField].Integer;
+    else if( eType == OFTInteger64 )
+        return pauFields[iField].Integer64;
+    else if( eType == OFTReal )
+        return (GIntBig) pauFields[iField].Real;
+    else if( eType == OFTString )
+    {
+        if( pauFields[iField].String == NULL )
+            return 0;
+        else
+        {
+            return CPLAtoGIntBigEx(pauFields[iField].String, TRUE, NULL);
+        }
+    }
+    else
+        return 0;
+}
+
+/************************************************************************/
+/*                      OGR_F_GetFieldAsInteger64()                     */
+/************************************************************************/
+
+/**
+ * \brief Fetch field value as integer 64 bit.
+ *
+ * OFTInteger are promoted to 64 bit.
+ * OFTString features will be translated using CPLAtoGIntBig().  OFTReal fields
+ * will be cast to integer.   Other field types, or errors will result in
+ * a return value of zero.
+ *
+ * This function is the same as the C++ method OGRFeature::GetFieldAsInteger64().
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ *
+ * @return the field value.
+ * @since GDAL 2.0
+ */
+
+GIntBig OGR_F_GetFieldAsInteger64( OGRFeatureH hFeat, int iField )
+
+{
+    VALIDATE_POINTER1( hFeat, "OGR_F_GetFieldAsInteger64", 0 );
+
+    return ((OGRFeature *)hFeat)->GetFieldAsInteger64(iField);
+}
+
+/************************************************************************/
 /*                          GetFieldAsDouble()                          */
 /************************************************************************/
 
 /**
  * \brief Fetch field value as a double.
  *
- * OFTString features will be translated using atof().  OFTInteger fields
+ * OFTString features will be translated using CPLAtof().  OFTInteger and OFTInteger64 fields
  * will be cast to double.   Other field types, or errors will result in
  * a return value of zero.
  *
@@ -1370,7 +1524,7 @@ double OGRFeature::GetFieldAsDouble( int iField )
         switch (iSpecialField)
         {
         case SPF_FID:
-            return GetFID();
+            return (double)GetFID();
 
         case SPF_OGR_GEOM_AREA:
             if( GetGeomFieldCount() == 0 || papoGeometries[0] == NULL )
@@ -1390,16 +1544,19 @@ double OGRFeature::GetFieldAsDouble( int iField )
     if( !IsFieldSet(iField) )
         return 0.0;
     
-    if( poFDefn->GetType() == OFTReal )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTReal )
         return pauFields[iField].Real;
-    else if( poFDefn->GetType() == OFTInteger )
+    else if( eType == OFTInteger )
         return pauFields[iField].Integer;
-    else if( poFDefn->GetType() == OFTString )
+    else if( eType == OFTInteger64 )
+        return (double) pauFields[iField].Integer64;
+    else if( eType == OFTString )
     {
         if( pauFields[iField].String == NULL )
             return 0;
         else
-            return atof(pauFields[iField].String);
+            return CPLAtof(pauFields[iField].String);
     }
     else
         return 0.0;
@@ -1412,7 +1569,7 @@ double OGRFeature::GetFieldAsDouble( int iField )
 /**
  * \brief Fetch field value as a double.
  *
- * OFTString features will be translated using atof().  OFTInteger fields
+ * OFTString features will be translated using CPLAtof().  OFTInteger fields
  * will be cast to double.   Other field types, or errors will result in
  * a return value of zero.
  *
@@ -1467,7 +1624,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
         switch (iSpecialField)
         {
           case SPF_FID:
-            snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%ld", GetFID() );
+            snprintf( szTempBuffer, TEMP_BUFFER_SIZE, CPL_FRMT_GIB, GetFID() );
             return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
 
           case SPF_OGR_GEOMETRY:
@@ -1497,7 +1654,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
             if( GetGeomFieldCount() == 0 || papoGeometries[0] == NULL )
                 return "";
 
-            snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%.16g", 
+            CPLsnprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%.16g", 
                       OGR_G_Area((OGRGeometryH)papoGeometries[0]) );
             return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
 
@@ -1514,20 +1671,27 @@ const char *OGRFeature::GetFieldAsString( int iField )
     if( !IsFieldSet(iField) )
         return "";
     
-    if( poFDefn->GetType() == OFTString )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTString )
     {
         if( pauFields[iField].String == NULL )
             return "";
         else
             return pauFields[iField].String;
     }
-    else if( poFDefn->GetType() == OFTInteger )
+    else if( eType == OFTInteger )
     {
         snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
                   "%d", pauFields[iField].Integer );
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTReal )
+    else if( eType == OFTInteger64 )
+    {
+        snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
+                  CPL_FRMT_GIB, pauFields[iField].Integer64 );
+        return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
+    }
+    else if( eType == OFTReal )
     {
         char    szFormat[64];
 
@@ -1539,22 +1703,34 @@ const char *OGRFeature::GetFieldAsString( int iField )
         else
             strcpy( szFormat, "%.15g" );
         
-        snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
+        CPLsnprintf( szTempBuffer, TEMP_BUFFER_SIZE,
                   szFormat, pauFields[iField].Real );
         
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTDateTime )
+    else if( eType == OFTDateTime )
     {
-        snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
-                  "%04d/%02d/%02d %02d:%02d:%02d", 
-                  pauFields[iField].Date.Year,
-                  pauFields[iField].Date.Month,
-                  pauFields[iField].Date.Day,
-                  pauFields[iField].Date.Hour,
-                  pauFields[iField].Date.Minute,
-                  pauFields[iField].Date.Second );
-        
+        int ms = OGR_GET_MS(pauFields[iField].Date.Second);
+        if( ms != 0 )
+            snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
+                    "%04d/%02d/%02d %02d:%02d:%06.3f", 
+                    pauFields[iField].Date.Year,
+                    pauFields[iField].Date.Month,
+                    pauFields[iField].Date.Day,
+                    pauFields[iField].Date.Hour,
+                    pauFields[iField].Date.Minute,
+                    pauFields[iField].Date.Second );
+        else /* default format */
+            snprintf( szTempBuffer, TEMP_BUFFER_SIZE,
+                    "%04d/%02d/%02d %02d:%02d:%02d", 
+                    pauFields[iField].Date.Year,
+                    pauFields[iField].Date.Month,
+                    pauFields[iField].Date.Day,
+                    pauFields[iField].Date.Hour,
+                    pauFields[iField].Date.Minute,
+                    (int)pauFields[iField].Date.Second );
+
+
         if( pauFields[iField].Date.TZFlag > 1 )
         {
             int nOffset = (pauFields[iField].Date.TZFlag - 100) * 15;
@@ -1579,7 +1755,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
 
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTDate )
+    else if( eType == OFTDate )
     {
         snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%04d/%02d/%02d",
                   pauFields[iField].Date.Year,
@@ -1588,16 +1764,23 @@ const char *OGRFeature::GetFieldAsString( int iField )
 
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTTime )
+    else if( eType == OFTTime )
     {
-        snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%2d:%02d:%02d", 
+        int ms = OGR_GET_MS(pauFields[iField].Date.Second);
+        if( ms != 0 )
+            snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%02d:%02d:%06.3f", 
                   pauFields[iField].Date.Hour,
                   pauFields[iField].Date.Minute,
                   pauFields[iField].Date.Second );
+        else
+            snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "%02d:%02d:%02d", 
+                  pauFields[iField].Date.Hour,
+                  pauFields[iField].Date.Minute,
+                  (int)pauFields[iField].Date.Second );
         
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTIntegerList )
+    else if( eType == OFTIntegerList )
     {
         char    szItem[32];
         int     i, nCount = pauFields[iField].IntegerList.nCount;
@@ -1626,7 +1809,36 @@ const char *OGRFeature::GetFieldAsString( int iField )
         
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTRealList )
+    else if( eType == OFTInteger64List )
+    {
+        char    szItem[32];
+        int     i, nCount = pauFields[iField].Integer64List.nCount;
+
+        snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "(%d:", nCount );
+        for( i = 0; i < nCount; i++ )
+        {
+            snprintf( szItem, sizeof(szItem), CPL_FRMT_GIB,
+                      pauFields[iField].Integer64List.paList[i] );
+            if( strlen(szTempBuffer) + strlen(szItem) + 6
+                >= sizeof(szTempBuffer) )
+            {
+                break;
+            }
+            
+            if( i > 0 )
+                strcat( szTempBuffer, "," );
+            
+            strcat( szTempBuffer, szItem );
+        }
+
+        if( i < nCount )
+            strcat( szTempBuffer, ",...)" );
+        else
+            strcat( szTempBuffer, ")" );
+        
+        return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
+    }
+    else if( eType == OFTRealList )
     {
         char    szItem[40];
         char    szFormat[64];
@@ -1643,7 +1855,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
         snprintf( szTempBuffer, TEMP_BUFFER_SIZE, "(%d:", nCount );
         for( i = 0; i < nCount; i++ )
         {
-            snprintf( szItem, sizeof(szItem), szFormat,
+            CPLsnprintf( szItem, sizeof(szItem), szFormat,
                       pauFields[iField].RealList.paList[i] );
             if( strlen(szTempBuffer) + strlen(szItem) + 6
                 >= sizeof(szTempBuffer) )
@@ -1664,7 +1876,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
         
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTStringList )
+    else if( eType == OFTStringList )
     {
         int     i, nCount = pauFields[iField].StringList.nCount;
 
@@ -1692,7 +1904,7 @@ const char *OGRFeature::GetFieldAsString( int iField )
         
         return m_pszTmpFieldValue = CPLStrdup( szTempBuffer );
     }
-    else if( poFDefn->GetType() == OFTBinary )
+    else if( eType == OFTBinary )
     {
         int     nCount = pauFields[iField].Binary.nCount;
         char    *pszHex;
@@ -1816,6 +2028,79 @@ const int *OGR_F_GetFieldAsIntegerList( OGRFeatureH hFeat, int iField,
 }
 
 /************************************************************************/
+/*                      GetFieldAsInteger64List()                       */
+/************************************************************************/
+
+/**
+ * \brief Fetch field value as a list of 64 bit integers.
+ *
+ * Currently this method only works for OFTInteger64List fields.
+ *
+ * This method is the same as the C function OGR_F_GetFieldAsInteger64List().
+ *
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param pnCount an integer to put the list count (number of integers) into.
+ *
+ * @return the field value.  This list is internal, and should not be
+ * modified, or freed.  Its lifetime may be very brief.  If *pnCount is zero
+ * on return the returned pointer may be NULL or non-NULL.
+ * @since GDAL 2.0
+ */
+
+const GIntBig *OGRFeature::GetFieldAsInteger64List( int iField, int *pnCount )
+
+{
+    OGRFieldDefn        *poFDefn = poDefn->GetFieldDefn( iField );
+
+    if( poFDefn != NULL && IsFieldSet(iField) &&
+        poFDefn->GetType() == OFTInteger64List )
+    {
+        if( pnCount != NULL )
+            *pnCount = pauFields[iField].Integer64List.nCount;
+
+        return pauFields[iField].Integer64List.paList;
+    }
+    else
+    {
+        if( pnCount != NULL )
+            *pnCount = 0;
+        
+        return NULL;
+    }
+}
+
+/************************************************************************/
+/*                   OGR_F_GetFieldAsInteger64List()                    */
+/************************************************************************/
+
+/**
+ * \brief Fetch field value as a list of 64 bit integers.
+ *
+ * Currently this function only works for OFTInteger64List fields.
+ *
+ * This function is the same as the C++ method 
+ * OGRFeature::GetFieldAsInteger64List().
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param pnCount an integer to put the list count (number of integers) into.
+ *
+ * @return the field value.  This list is internal, and should not be
+ * modified, or freed.  Its lifetime may be very brief.  If *pnCount is zero
+ * on return the returned pointer may be NULL or non-NULL.
+ * @since GDAL 2.0
+ */
+
+const GIntBig *OGR_F_GetFieldAsInteger64List( OGRFeatureH hFeat, int iField, 
+                                  int *pnCount )
+
+{
+    VALIDATE_POINTER1( hFeat, "OGR_F_GetFieldAsInteger64List", NULL );
+
+    return ((OGRFeature *)hFeat)->GetFieldAsInteger64List(iField, pnCount);
+}
+
+/************************************************************************/
 /*                        GetFieldAsDoubleList()                        */
 /************************************************************************/
 
@@ -1964,7 +2249,7 @@ char **OGR_F_GetFieldAsStringList( OGRFeatureH hFeat, int iField )
 /**
  * \brief Fetch field value as binary data.
  *
- * Currently this method only works for OFTBinary fields.
+ * This method only works for OFTBinary and OFTString fields.
  *
  * This method is the same as the C function OGR_F_GetFieldAsBinary().
  *
@@ -1993,6 +2278,11 @@ GByte *OGRFeature::GetFieldAsBinary( int iField, int *pnBytes )
         *pnBytes = pauFields[iField].Binary.nCount;
         return pauFields[iField].Binary.paData;
     }
+    else if( poFDefn->GetType() == OFTString )
+    {
+        *pnBytes = (int)strlen(pauFields[iField].String);
+        return (GByte*)pauFields[iField].String;
+    }
     else
     {
         return NULL;
@@ -2006,7 +2296,7 @@ GByte *OGRFeature::GetFieldAsBinary( int iField, int *pnBytes )
 /**
  * \brief Fetch field value as binary.
  *
- * Currently this method only works for OFTBinary fields.
+ * This method only works for OFTBinary and OFTString fields.
  *
  * This function is the same as the C++ method 
  * OGRFeature::GetFieldAsBinary().
@@ -2045,7 +2335,7 @@ GByte *OGR_F_GetFieldAsBinary( OGRFeatureH hFeat, int iField, int *pnBytes )
  * @param pnDay (1-31)
  * @param pnHour (0-23)
  * @param pnMinute (0-59)
- * @param pnSecond (0-59)
+ * @param pfSecond (0-59 with millisecond accuracy)
  * @param pnTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
  *
  * @return TRUE on success or FALSE on failure.
@@ -2053,7 +2343,7 @@ GByte *OGR_F_GetFieldAsBinary( OGRFeatureH hFeat, int iField, int *pnBytes )
 
 int OGRFeature::GetFieldAsDateTime( int iField,
                                     int *pnYear, int *pnMonth, int *pnDay,
-                                    int *pnHour, int *pnMinute, int *pnSecond,
+                                    int *pnHour, int *pnMinute, float *pfSecond,
                                     int *pnTZFlag )
 
 {
@@ -2080,11 +2370,11 @@ int OGRFeature::GetFieldAsDateTime( int iField,
             *pnHour = pauFields[iField].Date.Hour;
         if( pnMinute )
             *pnMinute = pauFields[iField].Date.Minute;
-        if( pnSecond )
-            *pnSecond = pauFields[iField].Date.Second;
+        if( pfSecond )
+            *pfSecond = pauFields[iField].Date.Second;
         if( pnTZFlag )
             *pnTZFlag = pauFields[iField].Date.TZFlag;
-        
+
         return TRUE;
     }
     else
@@ -2093,6 +2383,18 @@ int OGRFeature::GetFieldAsDateTime( int iField,
     }
 }
 
+int OGRFeature::GetFieldAsDateTime( int iField,
+                                    int *pnYear, int *pnMonth, int *pnDay,
+                                    int *pnHour, int *pnMinute, int *pnSecond,
+                                    int *pnTZFlag )
+{
+    float fSecond;
+    int nRet = GetFieldAsDateTime( iField, pnYear, pnMonth, pnDay, pnHour, pnMinute,
+                                   &fSecond, pnTZFlag);
+    if( pnSecond ) *pnSecond = (int)fSecond;
+    return nRet;
+}
+
 /************************************************************************/
 /*                      OGR_F_GetFieldAsDateTime()                      */
 /************************************************************************/
@@ -2116,6 +2418,8 @@ int OGRFeature::GetFieldAsDateTime( int iField,
  * @param pnTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
  *
  * @return TRUE on success or FALSE on failure.
+ *
+ * @see Use OGR_F_GetFieldAsDateTimeEx() for second with millisecond accuracy.
  */
 
 int OGR_F_GetFieldAsDateTime( OGRFeatureH hFeat, int iField,
@@ -2126,20 +2430,96 @@ int OGR_F_GetFieldAsDateTime( OGRFeatureH hFeat, int iField,
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_GetFieldAsDateTime", 0 );
 
+    float fSecond;
+    int nRet =((OGRFeature *)hFeat)->GetFieldAsDateTime( iField,
+                                                      pnYear, pnMonth, pnDay,
+                                                      pnHour, pnMinute,&fSecond,
+                                                      pnTZFlag );
+    if( pnSecond ) *pnSecond = (int)fSecond;
+    return nRet;
+}
+
+/************************************************************************/
+/*                     OGR_F_GetFieldAsDateTimeEx()                     */
+/************************************************************************/
+
+/**
+ * \brief Fetch field value as date and time.
+ *
+ * Currently this method only works for OFTDate, OFTTime and OFTDateTime fields.
+ *
+ * This function is the same as the C++ method 
+ * OGRFeature::GetFieldAsDateTime().
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param pnYear (including century)
+ * @param pnMonth (1-12)
+ * @param pnDay (1-31)
+ * @param pnHour (0-23)
+ * @param pnMinute (0-59)
+ * @param pfSecond (0-59 with millisecond accuracy)
+ * @param pnTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
+ *
+ * @return TRUE on success or FALSE on failure.
+ * @since GDAL 2.0
+ */
+
+int OGR_F_GetFieldAsDateTimeEx( OGRFeatureH hFeat, int iField,
+                                int *pnYear, int *pnMonth, int *pnDay,
+                                int *pnHour, int *pnMinute, float *pfSecond,
+                                int *pnTZFlag )
+    
+{
+    VALIDATE_POINTER1( hFeat, "OGR_F_GetFieldAsDateTimeEx", 0 );
+
     return ((OGRFeature *)hFeat)->GetFieldAsDateTime( iField,
                                                       pnYear, pnMonth, pnDay,
-                                                      pnHour, pnMinute,pnSecond,
+                                                      pnHour, pnMinute,pfSecond,
                                                       pnTZFlag );
 }
 
 /************************************************************************/
+/*                        OGRFeatureGetIntegerValue()                   */
+/************************************************************************/
+
+static int OGRFeatureGetIntegerValue(OGRFieldDefn *poFDefn, int nValue)
+{
+    if( poFDefn->GetSubType() == OFSTBoolean && nValue != 0 && nValue != 1 )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Only 0 or 1 should be passed for a OFSTBoolean subtype. "
+                 "Considering this non-zero value as 1.");
+        nValue = 1;
+    }
+    else if( poFDefn->GetSubType() == OFSTInt16 )
+    {
+        if( nValue < -32768 )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                    "Out-of-range value for a OFSTInt16 subtype. "
+                    "Considering this value as -32768.");
+            nValue = -32768;
+        }
+        else if( nValue > 32767 )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                    "Out-of-range value for a OFSTInt16 subtype. "
+                    "Considering this value as 32767.");
+            nValue = 32767;
+        }
+    }
+    return nValue;
+}
+
+/************************************************************************/
 /*                              SetField()                              */
 /************************************************************************/
 
 /**
  * \brief Set field to integer value. 
  *
- * OFTInteger and OFTReal fields will be set directly.  OFTString fields
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
  * will be assigned a string representation of the value, but not necessarily
  * taking into account formatting constraints on this field.  Other field
  * types may be unaffected.
@@ -2158,25 +2538,35 @@ void OGRFeature::SetField( int iField, int nValue )
     if( poFDefn == NULL )
         return;
 
-    if( poFDefn->GetType() == OFTInteger )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTInteger )
     {
-        pauFields[iField].Integer = nValue;
+        pauFields[iField].Integer = OGRFeatureGetIntegerValue(poFDefn, nValue);
         pauFields[iField].Set.nMarker2 = 0;
     }
-    else if( poFDefn->GetType() == OFTReal )
+    else if( eType == OFTInteger64 )
+    {
+        pauFields[iField].Integer64 = OGRFeatureGetIntegerValue(poFDefn, nValue);
+    }
+    else if( eType == OFTReal )
     {
         pauFields[iField].Real = nValue;
     }
-    else if( poFDefn->GetType() == OFTIntegerList )
+    else if( eType == OFTIntegerList )
     {
         SetField( iField, 1, &nValue );
     }
-    else if( poFDefn->GetType() == OFTRealList )
+    else if( eType == OFTInteger64List )
+    {
+        GIntBig nVal64 = nValue;
+        SetField( iField, 1, &nVal64 );
+    }
+    else if( eType == OFTRealList )
     {
         double dfValue = nValue;
         SetField( iField, 1, &dfValue );
     }
-    else if( poFDefn->GetType() == OFTString )
+    else if( eType == OFTString )
     {
         char    szTempBuffer[64];
 
@@ -2200,7 +2590,7 @@ void OGRFeature::SetField( int iField, int nValue )
 /**
  * \brief Set field to integer value. 
  *
- * OFTInteger and OFTReal fields will be set directly.  OFTString fields
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
  * will be assigned a string representation of the value, but not necessarily
  * taking into account formatting constraints on this field.  Other field
  * types may be unaffected.
@@ -2225,9 +2615,119 @@ void OGR_F_SetFieldInteger( OGRFeatureH hFeat, int iField, int nValue )
 /************************************************************************/
 
 /**
+ * \brief Set field to 64 bit integer value. 
+ *
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
+ * will be assigned a string representation of the value, but not necessarily
+ * taking into account formatting constraints on this field.  Other field
+ * types may be unaffected.
+ *
+ * This method is the same as the C function OGR_F_SetFieldInteger64().
+ *
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param nValue the value to assign.
+ * @since GDAL 2.0
+ */
+
+void OGRFeature::SetField( int iField, GIntBig nValue )
+
+{
+    OGRFieldDefn        *poFDefn = poDefn->GetFieldDefn( iField );
+
+    if( poFDefn == NULL )
+        return;
+
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTInteger )
+    {
+        int nVal32 = (nValue < INT_MIN ) ? INT_MIN : (nValue > INT_MAX) ? INT_MAX : (int)nValue;
+        if( (GIntBig)nVal32 != nValue )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                 "Integer overflow occured when trying to set 32bit field.");
+        }
+        SetField(iField, nVal32);
+    }
+    else if( eType == OFTInteger64 )
+    {
+        pauFields[iField].Integer64 = nValue;
+    }
+    else if( eType == OFTReal )
+    {
+        pauFields[iField].Real = (double) nValue;
+    }
+    else if( eType == OFTIntegerList )
+    {
+        int nVal32 = (nValue < INT_MIN ) ? INT_MIN : (nValue > INT_MAX) ? INT_MAX : (int)nValue;
+        if( (GIntBig)nVal32 != nValue )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                 "Integer overflow occured when trying to set 32bit field.");
+        }
+        SetField( iField, 1, &nVal32 );
+    }
+    else if( eType == OFTInteger64List )
+    {
+        SetField( iField, 1, &nValue );
+    }
+    else if( eType == OFTRealList )
+    {
+        double dfValue = (double) nValue;
+        SetField( iField, 1, &dfValue );
+    }
+    else if( eType == OFTString )
+    {
+        char    szTempBuffer[64];
+
+        sprintf( szTempBuffer, CPL_FRMT_GIB, nValue );
+
+        if( IsFieldSet( iField) )
+            CPLFree( pauFields[iField].String );
+
+        pauFields[iField].String = CPLStrdup( szTempBuffer );
+    }
+    else
+    {
+        /* do nothing for other field types */
+    }
+}
+
+/************************************************************************/
+/*                      OGR_F_SetFieldInteger64()                       */
+/************************************************************************/
+
+/**
+ * \brief Set field to 64 bit integer value. 
+ *
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
+ * will be assigned a string representation of the value, but not necessarily
+ * taking into account formatting constraints on this field.  Other field
+ * types may be unaffected.
+ *
+ * This function is the same as the C++ method OGRFeature::SetField().
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param nValue the value to assign.
+ * @since GDAL 2.0
+ */
+
+void OGR_F_SetFieldInteger64( OGRFeatureH hFeat, int iField, GIntBig nValue )
+
+{
+    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldInteger64" );
+
+    ((OGRFeature *)hFeat)->SetField( iField, nValue );
+}
+
+/************************************************************************/
+/*                              SetField()                              */
+/************************************************************************/
+
+/**
  * \brief Set field to double value. 
  *
- * OFTInteger and OFTReal fields will be set directly.  OFTString fields
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
  * will be assigned a string representation of the value, but not necessarily
  * taking into account formatting constraints on this field.  Other field
  * types may be unaffected.
@@ -2246,29 +2746,45 @@ void OGRFeature::SetField( int iField, double dfValue )
     if( poFDefn == NULL )
         return;
     
-    if( poFDefn->GetType() == OFTReal )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTReal )
     {
+        /*if( poFDefn->GetSubType() == OFSTFloat32 && dfValue != (double)(float)dfValue )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                 "Passed value cannot be exactly representing as a single-precision floating point value.");
+            dfValue = (double)(float)dfValue;
+        }*/
         pauFields[iField].Real = dfValue;
     }
-    else if( poFDefn->GetType() == OFTInteger )
+    else if( eType == OFTInteger )
     {
         pauFields[iField].Integer = (int) dfValue;
         pauFields[iField].Set.nMarker2 = 0;
     }
-    else if( poFDefn->GetType() == OFTRealList )
+    else if( eType == OFTInteger64 )
+    {
+        pauFields[iField].Integer64 = (GIntBig) dfValue;
+    }
+    else if( eType == OFTRealList )
     {
         SetField( iField, 1, &dfValue );
     }
-    else if( poFDefn->GetType() == OFTIntegerList )
+    else if( eType == OFTIntegerList )
     {
         int nValue = (int) dfValue;
         SetField( iField, 1, &nValue );
     }
-    else if( poFDefn->GetType() == OFTString )
+    else if( eType == OFTInteger64List )
+    {
+        GIntBig nValue = (GIntBig) dfValue;
+        SetField( iField, 1, &nValue );
+    }
+    else if( eType == OFTString )
     {
         char    szTempBuffer[128];
 
-        sprintf( szTempBuffer, "%.16g", dfValue );
+        CPLsprintf( szTempBuffer, "%.16g", dfValue );
 
         if( IsFieldSet( iField) )
             CPLFree( pauFields[iField].String );
@@ -2288,7 +2804,7 @@ void OGRFeature::SetField( int iField, double dfValue )
 /**
  * \brief Set field to double value. 
  *
- * OFTInteger and OFTReal fields will be set directly.  OFTString fields
+ * OFTInteger, OFTInteger64 and OFTReal fields will be set directly.  OFTString fields
  * will be assigned a string representation of the value, but not necessarily
  * taking into account formatting constraints on this field.  Other field
  * types may be unaffected.
@@ -2316,7 +2832,8 @@ void OGR_F_SetFieldDouble( OGRFeatureH hFeat, int iField, double dfValue )
  * \brief Set field to string value. 
  *
  * OFTInteger fields will be set based on an atoi() conversion of the string.
- * OFTReal fields will be set based on an atof() conversion of the string.
+ * OFTInteger64 fields will be set based on an CPLAtoGIntBig() conversion of the string.
+ * OFTReal fields will be set based on an CPLAtof() conversion of the string.
  * Other field types may be unaffected.
  *
  * This method is the same as the C function OGR_F_SetFieldString().
@@ -2330,32 +2847,39 @@ void OGRFeature::SetField( int iField, const char * pszValue )
 {
     static int bWarn = -1;
     OGRFieldDefn *poFDefn = poDefn->GetFieldDefn( iField );
-    char *pszLast;
+    char *pszLast = NULL;
 
     if( bWarn < 0 )
-        bWarn = CSLTestBoolean( CPLGetConfigOption( "OGR_SETFIELD_NUMERIC_WARNING", "NO" ) );
+        bWarn = CSLTestBoolean( CPLGetConfigOption( "OGR_SETFIELD_NUMERIC_WARNING", "YES" ) );
 
     if( poFDefn == NULL )
         return;
     
-    if( poFDefn->GetType() == OFTString )
+    OGRFieldType eType = poFDefn->GetType();
+    if( eType == OFTString )
     {
         if( IsFieldSet(iField) )
             CPLFree( pauFields[iField].String );
             
         pauFields[iField].String = CPLStrdup( pszValue );
     }
-    else if( poFDefn->GetType() == OFTInteger )
+    else if( eType == OFTInteger )
     {
+        errno = 0; /* As allowed by C standard, some systems like MSVC doesn't reset errno */
         long nVal = strtol(pszValue, &pszLast, 10);
+        nVal = OGRFeatureGetIntegerValue(poFDefn, nVal);
         pauFields[iField].Integer = (nVal > INT_MAX) ? INT_MAX : (nVal < INT_MIN) ? INT_MIN : (int) nVal;
-        if( bWarn && (nVal != (long)pauFields[iField].Integer || !pszLast || *pszLast ) )
+        if( bWarn && (errno == ERANGE || nVal != (long)pauFields[iField].Integer || !pszLast || *pszLast ) )
             CPLError(CE_Warning, CPLE_AppDefined,
                      "Value '%s' of field %s.%s parsed incompletely to integer %d.",
                      pszValue, poDefn->GetName(), poFDefn->GetNameRef(), pauFields[iField].Integer );
         pauFields[iField].Set.nMarker2 = OGRUnsetMarker;
     }
-    else if( poFDefn->GetType() == OFTReal )
+    else if( eType == OFTInteger64 )
+    {
+        pauFields[iField].Integer64 = CPLAtoGIntBigEx(pszValue, bWarn, NULL);
+    }
+    else if( eType == OFTReal )
     {
         pauFields[iField].Real = CPLStrtod(pszValue, &pszLast);
         if( bWarn && ( !pszLast || *pszLast ) )
@@ -2363,17 +2887,18 @@ void OGRFeature::SetField( int iField, const char * pszValue )
                       "Value '%s' of field %s.%s parsed incompletely to real %.16g.",
                       pszValue, poDefn->GetName(), poFDefn->GetNameRef(), pauFields[iField].Real );
     }
-    else if( poFDefn->GetType() == OFTDate 
-             || poFDefn->GetType() == OFTTime
-             || poFDefn->GetType() == OFTDateTime )
+    else if( eType == OFTDate 
+             || eType == OFTTime
+             || eType == OFTDateTime )
     {
         OGRField sWrkField;
 
         if( OGRParseDate( pszValue, &sWrkField, 0 ) )
             memcpy( pauFields+iField, &sWrkField, sizeof(sWrkField));
     }
-    else if( poFDefn->GetType() == OFTIntegerList 
-             || poFDefn->GetType() == OFTRealList )
+    else if( eType == OFTIntegerList 
+             || eType == OFTInteger64List 
+             || eType == OFTRealList )
     {
         char **papszValueList = NULL;
 
@@ -2388,65 +2913,220 @@ void OGRFeature::SetField( int iField, const char * pszValue )
         {
             /* do nothing - the count does not match entries */
         }
-        else if( poFDefn->GetType() == OFTIntegerList )
+        else if( eType == OFTIntegerList )
         {
             int i, nCount = atoi(papszValueList[0]);
             std::vector<int> anValues;
+            if( nCount == CSLCount(papszValueList)-1 )
+            {
+                for( i=0; i < nCount; i++ )
+                {
+                    errno = 0; /* As allowed by C standard, some systems like MSVC doesn't reset errno */
+                    int nVal = atoi(papszValueList[i+1]);
+                    if( errno == ERANGE )
+                    {
+                        CPLError(CE_Warning, CPLE_AppDefined,
+                                 "32 bit integer overflow when converting %s",
+                                 pszValue);
+                    }
+                    anValues.push_back( nVal );
+                }
+                SetField( iField, nCount, &(anValues[0]) );
+            }
+        }
+        else if( eType == OFTInteger64List )
+        {
+            int i, nCount = atoi(papszValueList[0]);
+            std::vector<GIntBig> anValues;
+            if( nCount == CSLCount(papszValueList)-1 )
+            {
+                for( i=0; i < nCount; i++ )
+                {
+                    GIntBig nVal = CPLAtoGIntBigEx(papszValueList[i+1], TRUE, NULL);
+                    anValues.push_back( nVal );
+                }
+                SetField( iField, nCount, &(anValues[0]) );
+            }
+        }
+        else if( eType == OFTRealList )
+        {
+            int i, nCount = atoi(papszValueList[0]);
+            std::vector<double> adfValues;
+            if( nCount == CSLCount(papszValueList)-1 )
+            {
+                for( i=0; i < nCount; i++ )
+                    adfValues.push_back( CPLAtof(papszValueList[i+1]) );
+                SetField( iField, nCount, &(adfValues[0]) );
+            }
+        }
+
+        CSLDestroy(papszValueList);
+    }
+    else if ( eType == OFTStringList )
+    {
+        if( pszValue && *pszValue )
+        {
+            if( pszValue[0] == '(' && strchr(pszValue,':') != NULL )
+            {
+                char** papszValueList = CSLTokenizeString2( 
+                                                        pszValue, ",:()", 0 );
+                int i, nCount = atoi(papszValueList[0]);
+                std::vector<char*> aosValues;
+                if( nCount == CSLCount(papszValueList)-1 )
+                {
+                    for( i=0; i < nCount; i++ )
+                        aosValues.push_back( papszValueList[i+1] );
+                    aosValues.push_back( NULL );
+                    SetField( iField, &(aosValues[0]) );
+                }
+                CSLDestroy(papszValueList);
+            }
+            else
+            {
+                const char *papszValues[2] = { pszValue, 0 };
+                SetField( iField, (char **) papszValues );
+            }
+        }
+    }
+    else
+    {
+        /* do nothing for other field types */;
+    }
+}
+
+/************************************************************************/
+/*                        OGR_F_SetFieldString()                        */
+/************************************************************************/
+
+/**
+ * \brief Set field to string value. 
+ *
+ * OFTInteger fields will be set based on an atoi() conversion of the string.
+ * OFTInteger64 fields will be set based on an CPLAtoGIntBig() conversion of the string.
+ * OFTReal fields will be set based on an CPLAtof() conversion of the string.
+ * Other field types may be unaffected.
+ *
+ * This function is the same as the C++ method OGRFeature::SetField().
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to fetch, from 0 to GetFieldCount()-1.
+ * @param pszValue the value to assign.
+ */
+
+void OGR_F_SetFieldString( OGRFeatureH hFeat, int iField, const char *pszValue)
+
+{
+    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldString" );
+
+    ((OGRFeature *)hFeat)->SetField( iField, pszValue );
+}
+
+/************************************************************************/
+/*                              SetField()                              */
+/************************************************************************/
+
+/**
+ * \brief Set field to list of integers value. 
+ *
+ * This method currently on has an effect of OFTIntegerList, OFTInteger64List
+ * and OFTRealList fields.
+ *
+ * This method is the same as the C function OGR_F_SetFieldIntegerList().
+ *
+ * @param iField the field to set, from 0 to GetFieldCount()-1.
+ * @param nCount the number of values in the list being assigned.
+ * @param panValues the values to assign.
+ */
+
+void OGRFeature::SetField( int iField, int nCount, int *panValues )
+
+{
+    OGRFieldDefn        *poFDefn = poDefn->GetFieldDefn( iField );
+
+    if( poFDefn == NULL )
+        return;
+    
+    if( poFDefn->GetType() == OFTIntegerList )
+    {
+        OGRField        uField;
+        int            *panValuesMod = NULL;
+
+        if( poFDefn->GetSubType() == OFSTBoolean || poFDefn->GetSubType() == OFSTInt16 )
+        {
+            for( int i=0;i<nCount;i++)
+            {
+                int nVal = OGRFeatureGetIntegerValue(poFDefn, panValues[i]);
+                if( panValues[i] != nVal )
+                {
+                    if( panValuesMod == NULL )
+                    {
+                        panValuesMod = (int*)CPLMalloc(nCount * sizeof(int));
+                        memcpy(panValuesMod, panValues, nCount * sizeof(int));
+                    }
+                    panValuesMod[i] = nVal;
+                }
+            }
+        }
+
+        uField.IntegerList.nCount = nCount;
+        uField.Set.nMarker2 = 0;
+        uField.IntegerList.paList = panValuesMod ? panValuesMod : panValues;
 
-            for( i=0; i < nCount; i++ )
-                anValues.push_back( atoi(papszValueList[i+1]) );
-            SetField( iField, nCount, &(anValues[0]) );
-        }
-        else if( poFDefn->GetType() == OFTRealList )
-        {
-            int i, nCount = atoi(papszValueList[0]);
-            std::vector<double> adfValues;
+        SetField( iField, &uField );
+        CPLFree(panValuesMod);
+    }
+    else if( poFDefn->GetType() == OFTInteger64List )
+    {
+        std::vector<GIntBig> anValues;
 
-            for( i=0; i < nCount; i++ )
-                adfValues.push_back( atof(papszValueList[i+1]) );
-            SetField( iField, nCount, &(adfValues[0]) );
-        }
+        for( int i=0; i < nCount; i++ )
+            anValues.push_back( panValues[i] );
 
-        CSLDestroy(papszValueList);
+        SetField( iField, nCount, &anValues[0] );
     }
-    else if ( poFDefn->GetType() == OFTStringList )
+    else if( poFDefn->GetType() == OFTRealList )
     {
-        if( pszValue && *pszValue )
-        {
-            const char *papszValues[2] = { pszValue, 0 };
-            SetField( iField, (char **) papszValues );
-        }
+        std::vector<double> adfValues;
+
+        for( int i=0; i < nCount; i++ )
+            adfValues.push_back( (double) panValues[i] );
+
+        SetField( iField, nCount, &adfValues[0] );
     }
-    else
+    else if( (poFDefn->GetType() == OFTInteger ||
+              poFDefn->GetType() == OFTInteger64 || 
+              poFDefn->GetType() == OFTReal)
+             && nCount == 1 )
     {
-        /* do nothing for other field types */;
+        SetField( iField, panValues[0] );
     }
 }
 
 /************************************************************************/
-/*                        OGR_F_SetFieldString()                        */
+/*                     OGR_F_SetFieldIntegerList()                      */
 /************************************************************************/
 
 /**
- * \brief Set field to string value. 
+ * \brief Set field to list of integers value. 
  *
- * OFTInteger fields will be set based on an atoi() conversion of the string.
- * OFTReal fields will be set based on an atof() conversion of the string.
- * Other field types may be unaffected.
+ * This function currently on has an effect of OFTIntegerList, OFTInteger64List
+ * and OFTRealList fields.
  *
  * This function is the same as the C++ method OGRFeature::SetField().
  *
  * @param hFeat handle to the feature that owned the field.
- * @param iField the field to fetch, from 0 to GetFieldCount()-1.
- * @param pszValue the value to assign.
+ * @param iField the field to set, from 0 to GetFieldCount()-1.
+ * @param nCount the number of values in the list being assigned.
+ * @param panValues the values to assign.
  */
 
-void OGR_F_SetFieldString( OGRFeatureH hFeat, int iField, const char *pszValue)
+void OGR_F_SetFieldIntegerList( OGRFeatureH hFeat, int iField, 
+                                int nCount, int *panValues )
 
 {
-    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldString" );
+    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldIntegerList" );
 
-    ((OGRFeature *)hFeat)->SetField( iField, pszValue );
+    ((OGRFeature *)hFeat)->SetField( iField, nCount, panValues );
 }
 
 /************************************************************************/
@@ -2454,18 +3134,20 @@ void OGR_F_SetFieldString( OGRFeatureH hFeat, int iField, const char *pszValue)
 /************************************************************************/
 
 /**
- * \brief Set field to list of integers value. 
+ * \brief Set field to list of 64 bit integers value. 
  *
- * This method currently on has an effect of OFTIntegerList fields.
+ * This method currently on has an effect of OFTIntegerList, OFTInteger64List
+ * and OFTRealList fields.
  *
- * This method is the same as the C function OGR_F_SetFieldIntegerList().
+ * This method is the same as the C function OGR_F_SetFieldIntege64rList().
  *
  * @param iField the field to set, from 0 to GetFieldCount()-1.
  * @param nCount the number of values in the list being assigned.
  * @param panValues the values to assign.
+ * @since GDAL 2.0
  */
 
-void OGRFeature::SetField( int iField, int nCount, int *panValues )
+void OGRFeature::SetField( int iField, int nCount, const GIntBig *panValues )
 
 {
     OGRFieldDefn        *poFDefn = poDefn->GetFieldDefn( iField );
@@ -2475,11 +3157,28 @@ void OGRFeature::SetField( int iField, int nCount, int *panValues )
     
     if( poFDefn->GetType() == OFTIntegerList )
     {
-        OGRField        uField;
+        std::vector<int> anValues;
 
-        uField.IntegerList.nCount = nCount;
+        for( int i=0; i < nCount; i++ )
+        {
+            GIntBig nValue = panValues[i];
+            int nVal32 = (nValue < INT_MIN ) ? INT_MIN : (nValue > INT_MAX) ? INT_MAX : (int)nValue;
+            if( (GIntBig)nVal32 != nValue )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                     "Integer overflow occured when trying to set 32bit field.");
+            }
+            anValues.push_back( nVal32 );
+        }
+
+        SetField( iField, nCount, &anValues[0] );
+    }
+    else if( poFDefn->GetType() == OFTInteger64List )
+    {
+        OGRField uField;
+        uField.Integer64List.nCount = nCount;
         uField.Set.nMarker2 = 0;
-        uField.IntegerList.paList = panValues;
+        uField.Integer64List.paList = (GIntBig*) panValues;
 
         SetField( iField, &uField );
     }
@@ -2492,7 +3191,9 @@ void OGRFeature::SetField( int iField, int nCount, int *panValues )
 
         SetField( iField, nCount, &adfValues[0] );
     }
-    else if( (poFDefn->GetType() == OFTInteger || poFDefn->GetType() == OFTReal)
+    else if( (poFDefn->GetType() == OFTInteger ||
+              poFDefn->GetType() == OFTInteger64 ||
+              poFDefn->GetType() == OFTReal)
              && nCount == 1 )
     {
         SetField( iField, panValues[0] );
@@ -2500,13 +3201,14 @@ void OGRFeature::SetField( int iField, int nCount, int *panValues )
 }
 
 /************************************************************************/
-/*                     OGR_F_SetFieldIntegerList()                      */
+/*                    OGR_F_SetFieldInteger64List()                     */
 /************************************************************************/
 
 /**
- * \brief Set field to list of integers value. 
+ * \brief Set field to list of 64 bit integers value. 
  *
- * This function currently on has an effect of OFTIntegerList fields.
+ * This function currently on has an effect of OFTIntegerList, OFTInteger64List
+ * and OFTRealList fields.
  *
  * This function is the same as the C++ method OGRFeature::SetField().
  *
@@ -2514,13 +3216,14 @@ void OGRFeature::SetField( int iField, int nCount, int *panValues )
  * @param iField the field to set, from 0 to GetFieldCount()-1.
  * @param nCount the number of values in the list being assigned.
  * @param panValues the values to assign.
+ * @since GDAL 2.0
  */
 
-void OGR_F_SetFieldIntegerList( OGRFeatureH hFeat, int iField, 
-                                int nCount, int *panValues )
+void OGR_F_SetFieldInteger64List( OGRFeatureH hFeat, int iField, 
+                                int nCount, const GIntBig *panValues )
 
 {
-    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldIntegerList" );
+    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldInteger64List" );
 
     ((OGRFeature *)hFeat)->SetField( iField, nCount, panValues );
 }
@@ -2532,7 +3235,8 @@ void OGR_F_SetFieldIntegerList( OGRFeatureH hFeat, int iField,
 /**
  * \brief Set field to list of doubles value. 
  *
- * This method currently on has an effect of OFTRealList fields.
+ * This method currently on has an effect of OFTIntegerList, OFTInteger64List,
+ * OFTRealList fields.
  *
  * This method is the same as the C function OGR_F_SetFieldDoubleList().
  *
@@ -2568,7 +3272,18 @@ void OGRFeature::SetField( int iField, int nCount, double * padfValues )
 
         SetField( iField, nCount, &anValues[0] );
     }
-    else if( (poFDefn->GetType() == OFTInteger || poFDefn->GetType() == OFTReal)
+    else if( poFDefn->GetType() == OFTInteger64List )
+    {
+        std::vector<GIntBig> anValues;
+
+        for( int i=0; i < nCount; i++ )
+            anValues.push_back( (GIntBig) padfValues[i] );
+
+        SetField( iField, nCount, &anValues[0] );
+    }
+    else if( (poFDefn->GetType() == OFTInteger ||
+              poFDefn->GetType() == OFTInteger64 || 
+              poFDefn->GetType() == OFTReal)
              && nCount == 1 )
     {
         SetField( iField, padfValues[0] );
@@ -2582,7 +3297,8 @@ void OGRFeature::SetField( int iField, int nCount, double * padfValues )
 /**
  * \brief Set field to list of doubles value. 
  *
- * This function currently on has an effect of OFTRealList fields.
+ * This function currently on has an effect of OFTIntegerList, OFTInteger64List,
+ * OFTRealList fields.
  *
  * This function is the same as the C++ method OGRFeature::SetField().
  *
@@ -2695,6 +3411,14 @@ void OGRFeature::SetField( int iField, int nBytes, GByte *pabyData )
 
         SetField( iField, &uField );
     }
+    else if( poFDefn->GetType() == OFTString )
+    {
+        char* pszStr = (char*)CPLMalloc(nBytes + 1);
+        memcpy(pszStr, pabyData, nBytes);
+        pszStr[nBytes] = 0;
+        SetField( iField, pszStr );
+        CPLFree( pszStr);
+    }
 }
 
 /************************************************************************/
@@ -2741,12 +3465,12 @@ void OGR_F_SetFieldBinary( OGRFeatureH hFeat, int iField,
  * @param nDay (1-31)
  * @param nHour (0-23)
  * @param nMinute (0-59)
- * @param nSecond (0-59)
+ * @param fSecond (0-59, with millisecond accuracy)
  * @param nTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
  */
 
 void OGRFeature::SetField( int iField, int nYear, int nMonth, int nDay,
-                           int nHour, int nMinute, int nSecond, 
+                           int nHour, int nMinute, float fSecond, 
                            int nTZFlag )
 
 {
@@ -2771,7 +3495,7 @@ void OGRFeature::SetField( int iField, int nYear, int nMonth, int nDay,
         pauFields[iField].Date.Day = (GByte)nDay;
         pauFields[iField].Date.Hour = (GByte)nHour;
         pauFields[iField].Date.Minute = (GByte)nMinute;
-        pauFields[iField].Date.Second = (GByte)nSecond;
+        pauFields[iField].Date.Second = fSecond;
         pauFields[iField].Date.TZFlag = (GByte)nTZFlag;
     }
 }
@@ -2795,6 +3519,8 @@ void OGRFeature::SetField( int iField, int nYear, int nMonth, int nDay,
  * @param nMinute (0-59)
  * @param nSecond (0-59)
  * @param nTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
+ *
+ * @see Use OGR_F_SetFieldDateTimeEx() for second with millisecond accuracy.
  */
 
 void OGR_F_SetFieldDateTime( OGRFeatureH hFeat, int iField, 
@@ -2811,6 +3537,42 @@ void OGR_F_SetFieldDateTime( OGRFeatureH hFeat, int iField,
 }
 
 /************************************************************************/
+/*                      OGR_F_SetFieldDateTimeEx()                      */
+/************************************************************************/
+
+/**
+ * \brief Set field to datetime.
+ *
+ * This method currently only has an effect for OFTDate, OFTTime and OFTDateTime
+ * fields.
+ *
+ * @param hFeat handle to the feature that owned the field.
+ * @param iField the field to set, from 0 to GetFieldCount()-1.
+ * @param nYear (including century)
+ * @param nMonth (1-12)
+ * @param nDay (1-31)
+ * @param nHour (0-23)
+ * @param nMinute (0-59)
+ * @param fSecond (0-59, with millisecond accuracy)
+ * @param nTZFlag (0=unknown, 1=localtime, 100=GMT, see data model for details)
+ *
+ * @since GDAL 2.0
+ */
+
+void OGR_F_SetFieldDateTimeEx( OGRFeatureH hFeat, int iField, 
+                             int nYear, int nMonth, int nDay,
+                             int nHour, int nMinute, float fSecond, 
+                             int nTZFlag )
+
+
+{
+    VALIDATE_POINTER0( hFeat, "OGR_F_SetFieldDateTimeEx" );
+
+    ((OGRFeature *)hFeat)->SetField( iField, nYear, nMonth, nDay,
+                                     nHour, nMinute, fSecond, nTZFlag );
+}
+
+/************************************************************************/
 /*                              SetField()                              */
 /************************************************************************/
 
@@ -2840,6 +3602,14 @@ void OGRFeature::SetField( int iField, OGRField * puValue )
     {
         pauFields[iField] = *puValue;
     }
+    else if( poFDefn->GetType() == OFTInteger64 )
+    {
+        pauFields[iField] = *puValue;
+    }
+    else if( poFDefn->GetType() == OFTInteger64 )
+    {
+        pauFields[iField] = *puValue;
+    }
     else if( poFDefn->GetType() == OFTReal )
     {
         pauFields[iField] = *puValue;
@@ -2885,6 +3655,28 @@ void OGRFeature::SetField( int iField, OGRField * puValue )
             pauFields[iField].IntegerList.nCount = nCount;
         }
     }
+    else if( poFDefn->GetType() == OFTInteger64List )
+    {
+        int     nCount = puValue->Integer64List.nCount;
+        
+        if( IsFieldSet( iField ) )
+            CPLFree( pauFields[iField].Integer64List.paList );
+        
+        if( puValue->Set.nMarker1 == OGRUnsetMarker
+            && puValue->Set.nMarker2 == OGRUnsetMarker )
+        {
+            pauFields[iField] = *puValue;
+        }
+        else
+        {
+            pauFields[iField].Integer64List.paList =
+                (GIntBig *) CPLMalloc(sizeof(GIntBig) * nCount);
+            memcpy( pauFields[iField].Integer64List.paList,
+                    puValue->Integer64List.paList,
+                    sizeof(GIntBig) * nCount );
+            pauFields[iField].Integer64List.nCount = nCount;
+        }
+    }
     else if( poFDefn->GetType() == OFTRealList )
     {
         int     nCount = puValue->RealList.nCount;
@@ -3012,7 +3804,7 @@ void OGRFeature::DumpReadable( FILE * fpOut, char** papszOptions )
     if( fpOut == NULL )
         fpOut = stdout;
 
-    fprintf( fpOut, "OGRFeature(%s):%ld\n", poDefn->GetName(), GetFID() );
+    fprintf( fpOut, "OGRFeature(%s):" CPL_FRMT_GIB "\n", poDefn->GetName(), GetFID() );
 
     const char* pszDisplayFields =
             CSLFetchNameValue(papszOptions, "DISPLAY_FIELDS");
@@ -3022,9 +3814,15 @@ void OGRFeature::DumpReadable( FILE * fpOut, char** papszOptions )
         {
             OGRFieldDefn    *poFDefn = poDefn->GetFieldDefn(iField);
 
+            const char* pszType = (poFDefn->GetSubType() != OFSTNone) ?
+                CPLSPrintf("%s(%s)",
+                           poFDefn->GetFieldTypeName( poFDefn->GetType() ),
+                           poFDefn->GetFieldSubTypeName(poFDefn->GetSubType())) :
+                poFDefn->GetFieldTypeName( poFDefn->GetType() );
+
             fprintf( fpOut, "  %s (%s) = ",
                     poFDefn->GetNameRef(),
-                    OGRFieldDefn::GetFieldTypeName(poFDefn->GetType()) );
+                    pszType );
 
             if( IsFieldSet( iField ) )
                 fprintf( fpOut, "%s\n", GetFieldAsString( iField ) );
@@ -3100,30 +3898,32 @@ void OGR_F_DumpReadable( OGRFeatureH hFeat, FILE *fpOut )
 /************************************************************************/
 
 /**
- * \fn long OGRFeature::GetFID();
+ * \fn GIntBig OGRFeature::GetFID();
  *
  * \brief Get feature identifier.
  *
  * This method is the same as the C function OGR_F_GetFID().
+ * Note: since GDAL 2.0, this method returns a GIntBig (previously a long)
  *
  * @return feature id or OGRNullFID if none has been assigned.
  */
 
 /************************************************************************/
-/*                            OGR_F_GetFID()                            */
+/*                            OGR_F_GetFID()                          */
 /************************************************************************/
 
 /**
  * \brief Get feature identifier.
  *
  * This function is the same as the C++ method OGRFeature::GetFID().
+ * Note: since GDAL 2.0, this method returns a GIntBig (previously a long)
  *
  * @param hFeat handle to the feature from which to get the feature
  * identifier.
  * @return feature id or OGRNullFID if none has been assigned.
  */
 
-long OGR_F_GetFID( OGRFeatureH hFeat )
+GIntBig OGR_F_GetFID( OGRFeatureH hFeat )
 
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_GetFID", 0 );
@@ -3150,7 +3950,7 @@ long OGR_F_GetFID( OGRFeatureH hFeat )
  * @return On success OGRERR_NONE, or on failure some other value. 
  */
 
-OGRErr OGRFeature::SetFID( long nFID )
+OGRErr OGRFeature::SetFID( GIntBig nFID )
 
 {
     this->nFID = nFID;
@@ -3178,7 +3978,7 @@ OGRErr OGRFeature::SetFID( long nFID )
  * @return On success OGRERR_NONE, or on failure some other value. 
  */
 
-OGRErr OGR_F_SetFID( OGRFeatureH hFeat, long nFID )
+OGRErr OGR_F_SetFID( OGRFeatureH hFeat, GIntBig nFID )
 
 {
     VALIDATE_POINTER1( hFeat, "OGR_F_SetFID", CE_Failure );
@@ -3233,6 +4033,12 @@ OGRBoolean OGRFeature::Equal( OGRFeature * poFeature )
                        poFeature->GetFieldAsInteger(i) )
                     return FALSE;
                 break;
+                
+            case OFTInteger64:
+                if( GetFieldAsInteger64(i) !=
+                       poFeature->GetFieldAsInteger64(i) )
+                    return FALSE;
+                break;
 
             case OFTReal:
                 if( GetFieldAsDouble(i) !=
@@ -3263,6 +4069,23 @@ OGRBoolean OGRFeature::Equal( OGRFeature * poFeature )
                 break;
             }
 
+            case OFTInteger64List:
+            {
+                int nCount1, nCount2;
+                const GIntBig* pnList1 = GetFieldAsInteger64List(i, &nCount1);
+                const GIntBig* pnList2 =
+                          poFeature->GetFieldAsInteger64List(i, &nCount2);
+                if( nCount1 != nCount2 )
+                    return FALSE;
+                int j;
+                for(j=0;j<nCount1;j++)
+                {
+                    if( pnList1[j] != pnList2[j] )
+                        return FALSE;
+                }
+                break;
+            }
+            
             case OFTRealList:
             {
                 int nCount1, nCount2;
@@ -3304,17 +4127,18 @@ OGRBoolean OGRFeature::Equal( OGRFeature * poFeature )
             case OFTDateTime:
             {
                 int nYear1, nMonth1, nDay1, nHour1,
-                    nMinute1, nSecond1, nTZFlag1;
+                    nMinute1, nTZFlag1;
                 int nYear2, nMonth2, nDay2, nHour2,
-                    nMinute2, nSecond2, nTZFlag2;
+                    nMinute2, nTZFlag2;
+                float fSecond1, fSecond2;
                 GetFieldAsDateTime(i, &nYear1, &nMonth1, &nDay1,
-                              &nHour1, &nMinute1, &nSecond1, &nTZFlag1);
+                              &nHour1, &nMinute1, &fSecond1, &nTZFlag1);
                 poFeature->GetFieldAsDateTime(i, &nYear2, &nMonth2, &nDay2,
-                              &nHour2, &nMinute2, &nSecond2, &nTZFlag2);
+                              &nHour2, &nMinute2, &fSecond2, &nTZFlag2);
 
                 if( !(nYear1 == nYear2 && nMonth1 == nMonth2 &&
                       nDay1 == nDay2 && nHour1 == nHour2 &&
-                      nMinute1 == nMinute2 && nSecond1 == nSecond2 &&
+                      nMinute1 == nMinute2 && fSecond1 == fSecond2 &&
                       nTZFlag1 == nTZFlag2) )
                     return FALSE;
                 break;
@@ -3679,6 +4503,10 @@ OGRErr OGRFeature::SetFieldsFrom( OGRFeature * poSrcFeature, int *panMap ,
             SetField( iDstField, poSrcFeature->GetFieldAsInteger( iField ) );
             break;
 
+          case OFTInteger64:
+            SetField( iDstField, poSrcFeature->GetFieldAsInteger64( iField ) );
+            break;
+            
           case OFTReal:
             SetField( iDstField, poSrcFeature->GetFieldAsDouble( iField ) );
             break;
@@ -3702,6 +4530,21 @@ OGRErr OGRFeature::SetFieldsFrom( OGRFeature * poSrcFeature, int *panMap ,
           }
           break;
 
+          case OFTInteger64List:
+          {
+              if (GetFieldDefnRef(iDstField)->GetType() == OFTString)
+              {
+                  SetField( iDstField, poSrcFeature->GetFieldAsString(iField) );
+              }
+              else
+              {
+                  int nCount;
+                  const GIntBig *panValues = poSrcFeature->GetFieldAsInteger64List( iField, &nCount);
+                  SetField( iDstField, nCount, panValues );
+              }
+          }
+          break;
+
           case OFTRealList:
           {
               if (GetFieldDefnRef(iDstField)->GetType() == OFTString)
@@ -3915,6 +4758,17 @@ void OGRFeature::SetStyleTable(OGRStyleTable *poStyleTable)
     m_poStyleTable = ( poStyleTable ) ? poStyleTable->Clone() : NULL;
 }
 
+//************************************************************************/
+/*                          SetStyleTableDirectly()                      */
+/************************************************************************/
+
+void OGRFeature::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
+{
+    if ( m_poStyleTable )
+        delete m_poStyleTable;
+    m_poStyleTable = poStyleTable;
+}
+
 /************************************************************************/
 /*                            RemapFields()                             */
 /*                                                                      */
@@ -4055,3 +4909,244 @@ void OGR_F_SetStyleTable( OGRFeatureH hFeat,
     
     ((OGRFeature *) hFeat)->SetStyleTable( (OGRStyleTable *) hStyleTable);
 }
+
+/************************************************************************/
+/*                          FillUnsetWithDefault()                      */
+/************************************************************************/
+
+/**
+ * \brief Fill unset fields with default values that might be defined.
+ *
+ * This method is the same as the C function OGR_F_FillUnsetWithDefault().
+ *
+ * @param bNotNullableOnly if we should fill only unset fields with a not-null
+ *                     constraint.
+ * @param papszOptions unused currently. Must be set to NULL.
+ * @since GDAL 2.0
+ */
+
+void OGRFeature::FillUnsetWithDefault(int bNotNullableOnly,
+                                      CPL_UNUSED char** papszOptions)
+{
+    int nFieldCount = poDefn->GetFieldCount();
+    for(int i = 0; i < nFieldCount; i ++ )
+    {
+        if( IsFieldSet(i) )
+            continue;
+        if( bNotNullableOnly && poDefn->GetFieldDefn(i)->IsNullable() )
+            continue;
+        const char* pszDefault = poDefn->GetFieldDefn(i)->GetDefault();
+        OGRFieldType eType = poDefn->GetFieldDefn(i)->GetType();
+        if( pszDefault != NULL )
+        {
+            if( eType == OFTDate || eType == OFTTime || eType == OFTDateTime )
+            {
+                if( EQUALN(pszDefault, "CURRENT", strlen("CURRENT")) )
+                {
+                    time_t t = time(NULL);
+                    struct tm brokendown;
+                    CPLUnixTimeToYMDHMS(t, &brokendown);
+                    SetField(i, brokendown.tm_year + 1900,
+                                brokendown.tm_mon + 1,
+                                brokendown.tm_mday,
+                                brokendown.tm_hour,
+                                brokendown.tm_min,
+                                brokendown.tm_sec,
+                                100 );
+                }
+                else
+                {
+                    int nYear, nMonth, nDay, nHour, nMinute;
+                    float fSecond;
+                    if( sscanf(pszDefault, "'%d/%d/%d %d:%d:%f'",
+                               &nYear, &nMonth, &nDay,
+                               &nHour, &nMinute, &fSecond) == 6 )
+                    {
+                        SetField(i, nYear, nMonth, nDay, nHour, nMinute,
+                                 fSecond, 100 );
+                    }
+                }
+            }
+            else if( eType == OFTString &&
+                     pszDefault[0] == '\'' &&
+                     pszDefault[strlen(pszDefault)-1] == '\'' )
+            {
+                CPLString osDefault(pszDefault + 1);
+                osDefault.resize(osDefault.size()-1);
+                char* pszTmp = CPLUnescapeString(osDefault, NULL, CPLES_SQL);
+                SetField(i, pszTmp);
+                CPLFree(pszTmp);
+            }
+            else
+                SetField(i, pszDefault);
+        }
+    }
+}
+
+/************************************************************************/
+/*                     OGR_F_FillUnsetWithDefault()                     */
+/************************************************************************/
+
+/**
+ * \brief Fill unset fields with default values that might be defined.
+ *
+ * This function is the same as the C++ method OGRFeature::FillUnsetWithDefault().
+ *
+ * @param hFeat handle to the feature.
+ * @param bNotNullableOnly if we should fill only unset fields with a not-null
+ *                     constraint.
+ * @param papszOptions unused currently. Must be set to NULL.
+ * @since GDAL 2.0
+ */
+
+void OGR_F_FillUnsetWithDefault( OGRFeatureH hFeat,
+                                 int bNotNullableOnly,
+                                 char** papszOptions)
+
+{
+    VALIDATE_POINTER0( hFeat, "OGR_F_FillUnsetWithDefault" );
+
+    ((OGRFeature *) hFeat)->FillUnsetWithDefault( bNotNullableOnly, papszOptions );
+}
+
+/************************************************************************/
+/*                              Validate()                              */
+/************************************************************************/
+
+/**
+ * \brief Validate that a feature meets constraints of its schema.
+ *
+ * The scope of test is specified with the nValidateFlags parameter.
+ *
+ * Regarding OGR_F_VAL_WIDTH, the test is done assuming the string width must
+ * be interpreted as the number of UTF-8 characters. Some drivers might interpret
+ * the width as the number of bytes instead. So this test is rather conservative
+ * (if it fails, then it will fail for all interpretations).
+ *
+ * This method is the same as the C function OGR_F_Validate().
+ *
+ * @param nValidateFlags OGR_F_VAL_ALL or combination of OGR_F_VAL_NULL,
+ *                       OGR_F_VAL_GEOM_TYPE, OGR_F_VAL_WIDTH and OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT
+ *                       with '|' operator
+ * @param bEmitError TRUE if a CPLError() must be emitted when a check fails
+ * @return TRUE if all enabled validation tests pass.
+ * @since GDAL 2.0
+ */
+
+int OGRFeature::Validate( int nValidateFlags, int bEmitError )
+
+{
+    int bRet = TRUE;
+
+    int i;
+    int nGeomFieldCount = poDefn->GetGeomFieldCount();
+    for(i = 0; i < nGeomFieldCount; i ++ )
+    {
+        if( (nValidateFlags & OGR_F_VAL_NULL) &&
+            !poDefn->GetGeomFieldDefn(i)->IsNullable() &&
+            GetGeomFieldRef(i) == NULL )
+        {
+            bRet = FALSE;
+            if( bEmitError )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                            "Geometry field %s has a NULL content which is not allowed",
+                            poDefn->GetGeomFieldDefn(i)->GetNameRef());
+            }
+        }
+        if( (nValidateFlags & OGR_F_VAL_GEOM_TYPE) &&
+            poDefn->GetGeomFieldDefn(i)->GetType() != wkbUnknown )
+        {
+            OGRGeometry* poGeom = GetGeomFieldRef(i);
+            if( poGeom != NULL )
+            {
+                OGRwkbGeometryType eType = poDefn->GetGeomFieldDefn(i)->GetType();
+                OGRwkbGeometryType eFType = poGeom->getGeometryType();
+                if( (eType == wkbSetZ(wkbUnknown) && !wkbHasZ(eFType)) ||
+                    (eType != wkbSetZ(wkbUnknown) && eFType != eType) )
+                {
+                    bRet = FALSE;
+                    if( bEmitError )
+                    {
+                        CPLError(CE_Failure, CPLE_AppDefined,
+                                 "Geometry field %s has a %s geometry whereas %s is expected",
+                                 poDefn->GetGeomFieldDefn(i)->GetNameRef(),
+                                 OGRGeometryTypeToName(eFType),
+                                 OGRGeometryTypeToName(eType));
+                    }
+                }
+            }
+        }
+    }
+    int nFieldCount = poDefn->GetFieldCount();
+    for(i = 0; i < nFieldCount; i ++ )
+    {
+        if( (nValidateFlags & OGR_F_VAL_NULL) &&
+            !poDefn->GetFieldDefn(i)->IsNullable() &&
+            !IsFieldSet(i) &&
+            (!(nValidateFlags & OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT) ||
+               poDefn->GetFieldDefn(i)->GetDefault() == NULL))
+        {
+            bRet = FALSE;
+            if( bEmitError )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                         "Field %s has a NULL content which is not allowed",
+                         poDefn->GetFieldDefn(i)->GetNameRef());
+            }
+        }
+        if( (nValidateFlags & OGR_F_VAL_WIDTH) &&
+            poDefn->GetFieldDefn(i)->GetWidth() > 0 &&
+            poDefn->GetFieldDefn(i)->GetType() == OFTString &&
+            IsFieldSet(i) &&
+            CPLIsUTF8(GetFieldAsString(i), -1) &&
+            CPLStrlenUTF8(GetFieldAsString(i)) > poDefn->GetFieldDefn(i)->GetWidth())
+        {
+            bRet = FALSE;
+            if( bEmitError )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                         "Field %s has a %d UTF-8 characters whereas a maximum of %d is allowed",
+                         poDefn->GetFieldDefn(i)->GetNameRef(),
+                         CPLStrlenUTF8(GetFieldAsString(i)),
+                         poDefn->GetFieldDefn(i)->GetWidth());
+            }
+        }
+    }
+
+    return bRet;
+}
+
+/************************************************************************/
+/*                           OGR_F_Validate()                           */
+/************************************************************************/
+
+/**
+ * \brief Validate that a feature meets constraints of its schema.
+ *
+ * The scope of test is specified with the nValidateFlags parameter.
+ *
+ * Regarding OGR_F_VAL_WIDTH, the test is done assuming the string width must
+ * be interpreted as the number of UTF-8 characters. Some drivers might interpret
+ * the width as the number of bytes instead. So this test is rather conservative
+ * (if it fails, then it will fail for all interpretations).
+ *
+ * This function is the same as the C++ method
+ * OGRFeature::Validate().
+ *
+ * @param hFeat handle to the feature to validate.
+ * @param nValidateFlags OGR_F_VAL_ALL or combination of OGR_F_VAL_NULL,
+ *                       OGR_F_VAL_GEOM_TYPE, OGR_F_VAL_WIDTH and OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT
+ *                       with '|' operator
+ * @param bEmitError TRUE if a CPLError() must be emitted when a check fails
+ * @return TRUE if all enabled validation tests pass.
+ * @since GDAL 2.0
+ */
+
+int OGR_F_Validate( OGRFeatureH hFeat, int nValidateFlags, int bEmitError )
+
+{
+    VALIDATE_POINTER1( hFeat, "OGR_F_Validate", FALSE );
+
+    return ((OGRFeature *) hFeat)->Validate( nValidateFlags, bEmitError );
+}
diff --git a/ogr/ogrfeaturedefn.cpp b/ogr/ogrfeaturedefn.cpp
index 2e4abba..d690d4b 100644
--- a/ogr/ogrfeaturedefn.cpp
+++ b/ogr/ogrfeaturedefn.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfeaturedefn.cpp 27110 2014-03-28 21:29:20Z rouault $
+ * $Id: ogrfeaturedefn.cpp 28807 2015-03-28 14:46:31Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRFeatureDefn class implementation.
@@ -31,8 +31,9 @@
 #include "ogr_feature.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrfeaturedefn.cpp 27110 2014-03-28 21:29:20Z rouault $");
+CPL_CVSID("$Id: ogrfeaturedefn.cpp 28807 2015-03-28 14:46:31Z rouault $");
 
 /************************************************************************/
 /*                           OGRFeatureDefn()                           */
@@ -281,6 +282,11 @@ int OGRFeatureDefn::GetFieldCount()
 int OGR_FD_GetFieldCount( OGRFeatureDefnH hDefn )
 
 {
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetFieldCount(hDefn);
+#endif
+
     return ((OGRFeatureDefn *) hDefn)->GetFieldCount();
 }
 
@@ -338,7 +344,13 @@ OGRFieldDefn *OGRFeatureDefn::GetFieldDefn( int iField )
 OGRFieldDefnH OGR_FD_GetFieldDefn( OGRFeatureDefnH hDefn, int iField )
 
 {
-    return (OGRFieldDefnH) ((OGRFeatureDefn *) hDefn)->GetFieldDefn( iField );
+    OGRFieldDefnH hFieldDefnH = (OGRFieldDefnH) ((OGRFeatureDefn *) hDefn)->GetFieldDefn( iField );
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetFieldDefn(hDefn, iField, hFieldDefnH);
+#endif
+
+    return hFieldDefnH;
 }
 
 /************************************************************************/
@@ -581,6 +593,11 @@ int OGRFeatureDefn::GetGeomFieldCount()
 int OGR_FD_GetGeomFieldCount( OGRFeatureDefnH hDefn )
 
 {
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetGeomFieldCount(hDefn);
+#endif
+
     return ((OGRFeatureDefn *) hDefn)->GetGeomFieldCount();
 }
 
@@ -636,7 +653,15 @@ OGRGeomFieldDefn *OGRFeatureDefn::GetGeomFieldDefn( int iGeomField )
 OGRGeomFieldDefnH OGR_FD_GetGeomFieldDefn( OGRFeatureDefnH hDefn, int iGeomField )
 
 {
-    return (OGRGeomFieldDefnH) ((OGRFeatureDefn *) hDefn)->GetGeomFieldDefn( iGeomField );
+    OGRGeomFieldDefnH hGeomField =
+        (OGRGeomFieldDefnH) ((OGRFeatureDefn *) hDefn)->GetGeomFieldDefn( iGeomField );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetGeomFieldDefn(hDefn, iGeomField, hGeomField);
+#endif
+
+    return hGeomField;
 }
 
 /************************************************************************/
@@ -829,6 +854,11 @@ int OGR_FD_GetGeomFieldIndex( OGRFeatureDefnH hDefn,
                               const char *pszGeomFieldName )
 
 {
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetGeomFieldIndex(hDefn, pszGeomFieldName);
+#endif
+
     return ((OGRFeatureDefn *)hDefn)->GetGeomFieldIndex( pszGeomFieldName );
 }
 
@@ -859,7 +889,10 @@ OGRwkbGeometryType OGRFeatureDefn::GetGeomType()
 {
     if( GetGeomFieldCount() == 0 )
         return wkbNone;
-    return GetGeomFieldDefn(0)->GetType();
+    OGRwkbGeometryType eType = GetGeomFieldDefn(0)->GetType();
+    if( eType == (wkbUnknown | wkb25DBitInternalUse) && CSLTestBoolean(CPLGetConfigOption("QGIS_HACK", "NO")) )
+        eType = wkbUnknown;
+    return eType;
 }
 
 /************************************************************************/
@@ -879,7 +912,17 @@ OGRwkbGeometryType OGRFeatureDefn::GetGeomType()
 OGRwkbGeometryType OGR_FD_GetGeomType( OGRFeatureDefnH hDefn )
 
 {
-    return ((OGRFeatureDefn *) hDefn)->GetGeomType();
+    OGRwkbGeometryType eType = ((OGRFeatureDefn *) hDefn)->GetGeomType();
+    if( OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag() )
+    {
+        eType = OGR_GT_GetLinear(eType);
+    }
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetGeomType(hDefn);
+#endif
+
+    return eType;
 }
 
 /************************************************************************/
@@ -1104,6 +1147,11 @@ int OGRFeatureDefn::GetFieldIndex( const char * pszFieldName )
 int OGR_FD_GetFieldIndex( OGRFeatureDefnH hDefn, const char *pszFieldName )
 
 {
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_FD_GetFieldIndex(hDefn, pszFieldName);
+#endif
+
     return ((OGRFeatureDefn *)hDefn)->GetFieldIndex( pszFieldName );
 }
 
diff --git a/ogr/ogrfeaturequery.cpp b/ogr/ogrfeaturequery.cpp
index d08dd10..f77b3cb 100644
--- a/ogr/ogrfeaturequery.cpp
+++ b/ogr/ogrfeaturequery.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfeaturequery.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrfeaturequery.cpp 28968 2015-04-21 19:00:02Z rouault $
  * 
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of simple SQL WHERE style attributes queries
@@ -35,7 +35,7 @@
 #include "ogr_p.h"
 #include "ogr_attrind.h"
 
-CPL_CVSID("$Id: ogrfeaturequery.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrfeaturequery.cpp 28968 2015-04-21 19:00:02Z rouault $");
 
 /************************************************************************/
 /*     Support for special attributes (feature query and selection)     */
@@ -72,7 +72,9 @@ OGRFeatureQuery::~OGRFeatureQuery()
 /************************************************************************/
 
 OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn, 
-                                 const char * pszExpression )
+                                 const char * pszExpression,
+                                 int bCheck,
+                                 swq_custom_func_registrar* poCustomFuncRegistrar )
 
 {
 /* -------------------------------------------------------------------- */
@@ -107,8 +109,22 @@ OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn,
         switch( poField->GetType() )
         {
           case OFTInteger:
-            paeFieldTypes[iField] = SWQ_INTEGER;
-            break;
+          {
+              if( poField->GetSubType() == OFSTBoolean )
+                  paeFieldTypes[iField] = SWQ_BOOLEAN;
+              else
+                  paeFieldTypes[iField] = SWQ_INTEGER;
+              break;
+          }
+
+          case OFTInteger64:
+          {
+              if( poField->GetSubType() == OFSTBoolean )
+                  paeFieldTypes[iField] = SWQ_BOOLEAN;
+              else
+                  paeFieldTypes[iField] = SWQ_INTEGER64;
+              break;
+          }
 
           case OFTReal:
             paeFieldTypes[iField] = SWQ_FLOAT;
@@ -158,6 +174,8 @@ OGRErr OGRFeatureQuery::Compile( OGRFeatureDefn *poDefn,
     poTargetDefn = poDefn;
     eCPLErr = swq_expr_compile( pszExpression, nFieldCount,
                                 papszFieldNames, paeFieldTypes, 
+                                bCheck,
+                                poCustomFuncRegistrar,
                                 (swq_expr_node **) &pSWQExpr );
     if( eCPLErr != CE_None )
     {
@@ -197,6 +215,11 @@ static swq_expr_node *OGRFeatureFetcher( swq_expr_node *op, void *pFeatureIn )
             poFeature->GetFieldAsInteger(op->field_index) );
         break;
 
+      case SWQ_INTEGER64:
+        poRetNode = new swq_expr_node( 
+            poFeature->GetFieldAsInteger64(op->field_index) );
+        break;
+
       case SWQ_FLOAT:
         poRetNode = new swq_expr_node( 
             poFeature->GetFieldAsDouble(op->field_index) );
@@ -231,9 +254,11 @@ int OGRFeatureQuery::Evaluate( OGRFeature *poFeature )
     if( poResult == NULL )
         return FALSE;
 
-    CPLAssert( poResult->field_type == SWQ_BOOLEAN );
-
-    int bLogicalResult = poResult->int_value;
+    int bLogicalResult = FALSE;
+    if( poResult->field_type == SWQ_INTEGER ||
+        poResult->field_type == SWQ_INTEGER64 ||
+        poResult->field_type == SWQ_BOOLEAN )
+        bLogicalResult = (int)poResult->int_value;
 
     delete poResult;
 
@@ -311,12 +336,19 @@ int OGRFeatureQuery::CanUseIndex( swq_expr_node *psExpr,
 /*      multi-part queries with ranges.                                 */
 /************************************************************************/
 
-static int CompareLong(const void *a, const void *b)
+static int CompareGIntBig(const void *pa, const void *pb)
 {
-	return (*(const long *)a) - (*(const long *)b);
+    GIntBig a = *((const GIntBig*)pa);
+    GIntBig b = *((const GIntBig*)pb);
+    if( a < b )
+        return -1;
+    else if( a > b )
+        return 1;
+    else
+        return 0;
 }
 
-long *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer, 
+GIntBig *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer, 
                                                OGRErr *peErr )
 
 {
@@ -331,26 +363,27 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( OGRLayer *poLayer,
     if ( poLayer->GetIndex() == NULL )
         return NULL;
 
-    int nFIDCount = 0;
+    GIntBig nFIDCount = 0;
     return EvaluateAgainstIndices(psExpr, poLayer, nFIDCount);
 }
 
 /* The input arrays must be sorted ! */
 static
-long* OGRORLongArray(long panFIDList1[], int nFIDCount1,
-                     long panFIDList2[], int nFIDCount2, int& nFIDCount)
+GIntBig* OGRORGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
+                           GIntBig panFIDList2[], GIntBig nFIDCount2,
+                           GIntBig& nFIDCount)
 {
-    int nMaxCount = nFIDCount1 + nFIDCount2;
-    long* panFIDList = (long*) CPLMalloc((nMaxCount+1) * sizeof(long));
+    GIntBig nMaxCount = nFIDCount1 + nFIDCount2;
+    GIntBig* panFIDList = (GIntBig*) CPLMalloc((size_t)(nMaxCount+1) * sizeof(GIntBig));
     nFIDCount = 0;
 
-    int i1 = 0, i2 =0;
+    GIntBig i1 = 0, i2 =0;
     for(;i1<nFIDCount1 || i2<nFIDCount2;)
     {
         if (i1 < nFIDCount1 && i2 < nFIDCount2)
         {
-            long nVal1 = panFIDList1[i1];
-            long nVal2 = panFIDList2[i2];
+            GIntBig nVal1 = panFIDList1[i1];
+            GIntBig nVal2 = panFIDList2[i2];
             if (nVal1 < nVal2)
             {
                 if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
@@ -390,13 +423,13 @@ long* OGRORLongArray(long panFIDList1[], int nFIDCount1,
         }
         else if (i1 < nFIDCount1)
         {
-            long nVal1 = panFIDList1[i1];
+            GIntBig nVal1 = panFIDList1[i1];
             panFIDList[nFIDCount ++] = nVal1;
             i1 ++;
         }
         else if (i2 < nFIDCount2)
         {
-            long nVal2 = panFIDList2[i2];
+            GIntBig nVal2 = panFIDList2[i2];
             panFIDList[nFIDCount ++] = nVal2;
             i2 ++;
         }
@@ -409,18 +442,19 @@ long* OGRORLongArray(long panFIDList1[], int nFIDCount1,
 
 /* The input arrays must be sorted ! */
 static
-long* OGRANDLongArray(long panFIDList1[], int nFIDCount1,
-                      long panFIDList2[], int nFIDCount2, int& nFIDCount)
+GIntBig* OGRANDGIntBigArray(GIntBig panFIDList1[], GIntBig nFIDCount1,
+                            GIntBig panFIDList2[], GIntBig nFIDCount2,
+                            GIntBig& nFIDCount)
 {
-    int nMaxCount = MAX(nFIDCount1, nFIDCount2);
-    long* panFIDList = (long*) CPLMalloc((nMaxCount+1) * sizeof(long));
+    GIntBig nMaxCount = MAX(nFIDCount1, nFIDCount2);
+    GIntBig* panFIDList = (GIntBig*) CPLMalloc((size_t)(nMaxCount+1) * sizeof(GIntBig));
     nFIDCount = 0;
 
-    int i1 = 0, i2 =0;
+    GIntBig i1 = 0, i2 =0;
     for(;i1<nFIDCount1 && i2<nFIDCount2;)
     {
-        long nVal1 = panFIDList1[i1];
-        long nVal2 = panFIDList2[i2];
+        GIntBig nVal1 = panFIDList1[i1];
+        GIntBig nVal2 = panFIDList2[i2];
         if (nVal1 < nVal2)
         {
             if (i1+1 < nFIDCount1 && panFIDList1[i1+1] <= nVal2)
@@ -458,9 +492,9 @@ long* OGRANDLongArray(long panFIDList1[], int nFIDCount1,
     return panFIDList;
 }
 
-long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
-                                               OGRLayer *poLayer,
-                                               int& nFIDCount )
+GIntBig *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
+                                                  OGRLayer *poLayer,
+                                                  GIntBig& nFIDCount )
 {
     OGRAttrIndex *poIndex;
 
@@ -474,18 +508,18 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
     if ((psExpr->nOperation == SWQ_OR || psExpr->nOperation == SWQ_AND) &&
          psExpr->nSubExprCount == 2)
     {
-        int nFIDCount1 = 0, nFIDCount2 = 0;
-        long* panFIDList1 = EvaluateAgainstIndices( psExpr->papoSubExpr[0], poLayer, nFIDCount1 );
-        long* panFIDList2 = panFIDList1 == NULL ? NULL :
+        GIntBig nFIDCount1 = 0, nFIDCount2 = 0;
+        GIntBig* panFIDList1 = EvaluateAgainstIndices( psExpr->papoSubExpr[0], poLayer, nFIDCount1 );
+        GIntBig* panFIDList2 = panFIDList1 == NULL ? NULL :
                             EvaluateAgainstIndices( psExpr->papoSubExpr[1], poLayer, nFIDCount2 );
-        long* panFIDList = NULL;
+        GIntBig* panFIDList = NULL;
         if (panFIDList1 != NULL && panFIDList2 != NULL)
         {
             if (psExpr->nOperation == SWQ_OR )
-                panFIDList = OGRORLongArray(panFIDList1, nFIDCount1,
+                panFIDList = OGRORGIntBigArray(panFIDList1, nFIDCount1,
                                             panFIDList2, nFIDCount2, nFIDCount);
             else if (psExpr->nOperation == SWQ_AND )
-                panFIDList = OGRANDLongArray(panFIDList1, nFIDCount1,
+                panFIDList = OGRANDGIntBigArray(panFIDList1, nFIDCount1,
                                             panFIDList2, nFIDCount2, nFIDCount);
 
         }
@@ -523,7 +557,7 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
     if (psExpr->nOperation == SWQ_IN)
     {
         int nLength;
-        long *panFIDs = NULL;
+        GIntBig *panFIDs = NULL;
         int iIN;
 
         for( iIN = 1; iIN < psExpr->nSubExprCount; iIN++ )
@@ -534,7 +568,14 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
                 if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
                     sValue.Integer = (int) psExpr->papoSubExpr[iIN]->float_value;
                 else
-                    sValue.Integer = psExpr->papoSubExpr[iIN]->int_value;
+                    sValue.Integer = (int) psExpr->papoSubExpr[iIN]->int_value;
+                break;
+
+              case OFTInteger64:
+                if (psExpr->papoSubExpr[iIN]->field_type == SWQ_FLOAT)
+                    sValue.Integer64 = (GIntBig) psExpr->papoSubExpr[iIN]->float_value;
+                else
+                    sValue.Integer64 = psExpr->papoSubExpr[iIN]->int_value;
                 break;
 
               case OFTReal:
@@ -550,13 +591,15 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
                 return NULL;
             }
 
-            panFIDs = poIndex->GetAllMatches( &sValue, panFIDs, &nFIDCount, &nLength );
+            int nFIDCount32 = 0;
+            panFIDs = poIndex->GetAllMatches( &sValue, panFIDs, &nFIDCount32, &nLength );
+            nFIDCount = nFIDCount32;
         }
 
         if (nFIDCount > 1)
         {
             /* the returned FIDs are expected to be in sorted order */
-            qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
+            qsort(panFIDs, (size_t)nFIDCount, sizeof(GIntBig), CompareGIntBig);
         }
         return panFIDs;
     }
@@ -570,7 +613,14 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
         if (poValue->field_type == SWQ_FLOAT)
             sValue.Integer = (int) poValue->float_value;
         else
-            sValue.Integer = poValue->int_value;
+            sValue.Integer = (int) poValue->int_value;
+        break;
+      
+      case OFTInteger64:
+        if (poValue->field_type == SWQ_FLOAT)
+            sValue.Integer64 = (GIntBig) poValue->float_value;
+        else
+            sValue.Integer64 = poValue->int_value;
         break;
         
       case OFTReal:
@@ -587,11 +637,13 @@ long *OGRFeatureQuery::EvaluateAgainstIndices( swq_expr_node *psExpr,
     }
 
     int nLength = 0;
-    long *panFIDs = poIndex->GetAllMatches( &sValue, NULL, &nFIDCount, &nLength );
+    int nFIDCount32 = 0;
+    GIntBig* panFIDs = poIndex->GetAllMatches( &sValue, NULL, &nFIDCount32, &nLength );
+    nFIDCount = nFIDCount32;
     if (nFIDCount > 1)
     {
         /* the returned FIDs are expected to be in sorted order */
-        qsort(panFIDs, nFIDCount, sizeof(long), CompareLong);
+        qsort(panFIDs, (size_t)nFIDCount, sizeof(GIntBig), CompareGIntBig);
     }
     return panFIDs;
 }
diff --git a/ogr/ogrfeaturestyle.cpp b/ogr/ogrfeaturestyle.cpp
index 50468ad..22fc55e 100644
--- a/ogr/ogrfeaturestyle.cpp
+++ b/ogr/ogrfeaturestyle.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfeaturestyle.cpp 27071 2014-03-21 21:52:46Z rouault $
+ * $Id: ogrfeaturestyle.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Feature Representation string API
@@ -34,7 +34,7 @@
 #include "ogr_featurestyle.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: ogrfeaturestyle.cpp 27071 2014-03-21 21:52:46Z rouault $");
+CPL_CVSID("$Id: ogrfeaturestyle.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 CPL_C_START
 void OGRFeatureStylePuller() {}
@@ -2071,10 +2071,10 @@ double OGRStyleTool::GetParamDbl(const OGRStyleParamId &sStyleParam ,
         // if sStyleParam.bGeoref == TRUE , need to convert to output value;
       case OGRSTypeString:
         if (sStyleParam.bGeoref)
-          return ComputeWithUnit(atof(sStyleValue.pszValue),
+          return ComputeWithUnit(CPLAtof(sStyleValue.pszValue),
                                  sStyleValue.eUnit);
         else
-          return atof(sStyleValue.pszValue);
+          return CPLAtof(sStyleValue.pszValue);
       case OGRSTypeDouble:
         if (sStyleParam.bGeoref)
           return ComputeWithUnit(sStyleValue.dfValue,
@@ -2117,7 +2117,7 @@ void OGRStyleTool::SetParamStr(const OGRStyleParamId &sStyleParam ,
         sStyleValue.pszValue = CPLStrdup(pszParamString);
         break;
       case OGRSTypeDouble:
-        sStyleValue.dfValue = atof(pszParamString);
+        sStyleValue.dfValue = CPLAtof(pszParamString);
         break;
       case OGRSTypeInteger:
       case OGRSTypeBoolean:
diff --git a/ogr/ogrfielddefn.cpp b/ogr/ogrfielddefn.cpp
index 19de781..20e615a 100644
--- a/ogr/ogrfielddefn.cpp
+++ b/ogr/ogrfielddefn.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfielddefn.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrfielddefn.cpp 28806 2015-03-28 14:37:47Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRFieldDefn class implementation.
@@ -31,8 +31,9 @@
 #include "ogr_feature.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrfielddefn.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrfielddefn.cpp 28806 2015-03-28 14:37:47Z rouault $");
 
 /************************************************************************/
 /*                            OGRFieldDefn()                            */
@@ -41,6 +42,8 @@ CPL_CVSID("$Id: ogrfielddefn.cpp 27044 2014-03-16 23:41:27Z rouault $");
 /**
  * \brief Constructor.
  *
+ * By default, fields have no width, precision, are nullable and not ignored.
+ *
  * @param pszNameIn the name of the new field.
  * @param eTypeIn the type of the new field.
  */
@@ -71,7 +74,9 @@ OGRFieldDefn::OGRFieldDefn( OGRFieldDefn *poPrototype )
     SetJustify( poPrototype->GetJustify() );
     SetWidth( poPrototype->GetWidth() );
     SetPrecision( poPrototype->GetPrecision() );
-//    SetDefault( poPrototype->GetDefaultRef() );
+    SetSubType( poPrototype->GetSubType() );
+    SetNullable( poPrototype->IsNullable() );
+    SetDefault( poPrototype->GetDefault() );
 }
 
 /************************************************************************/
@@ -80,6 +85,8 @@ OGRFieldDefn::OGRFieldDefn( OGRFieldDefn *poPrototype )
 /**
  * \brief Create a new field definition.
  *
+ * By default, fields have no width, precision, are nullable and not ignored.
+ *
  * This function is the same as the CPP method OGRFieldDefn::OGRFieldDefn().
  *
  * @param pszName the name of the new field definition.
@@ -107,8 +114,10 @@ void OGRFieldDefn::Initialize( const char * pszNameIn, OGRFieldType eTypeIn )
     nWidth = 0;         // should these be defined in some particular way
     nPrecision = 0;     // for numbers?
 
-    memset( &uDefault, 0, sizeof(OGRField) );
+    pszDefault = NULL;
     bIgnore = FALSE;
+    eSubType = OFSTNone;
+    bNullable = TRUE;
 }
 
 /************************************************************************/
@@ -119,6 +128,7 @@ OGRFieldDefn::~OGRFieldDefn()
 
 {
     CPLFree( pszName );
+    CPLFree( pszDefault );
 }
 
 /************************************************************************/
@@ -204,6 +214,12 @@ void OGR_Fld_SetName( OGRFieldDefnH hDefn, const char *pszName )
 const char *OGR_Fld_GetNameRef( OGRFieldDefnH hDefn )
 
 {
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Fld_GetXXXX(hDefn, "GetNameRef");
+#endif
+
     return ((OGRFieldDefn *) hDefn)->GetNameRef();
 }
 
@@ -236,6 +252,12 @@ const char *OGR_Fld_GetNameRef( OGRFieldDefnH hDefn )
 OGRFieldType OGR_Fld_GetType( OGRFieldDefnH hDefn )
 
 {
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Fld_GetXXXX(hDefn, "GetType");
+#endif
+
     return ((OGRFieldDefn *) hDefn)->GetType();
 }
 
@@ -244,8 +266,6 @@ OGRFieldType OGR_Fld_GetType( OGRFieldDefnH hDefn )
 /************************************************************************/
 
 /**
- * \fn void OGRFieldDefn::SetType( OGRFieldType eType );
- *
  * \brief Set the type of this field.
  * This should never be done to an OGRFieldDefn
  * that is already part of an OGRFeatureDefn.
@@ -255,6 +275,18 @@ OGRFieldType OGR_Fld_GetType( OGRFieldDefnH hDefn )
  * @param eType the new field type.
  */
 
+void OGRFieldDefn::SetType( OGRFieldType eTypeIn )
+{
+    if( !OGR_AreTypeSubTypeCompatible(eTypeIn, eSubType) )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Type and subtype of field definition are not compatible. Reseting to OFSTNone");
+        eSubType = OFSTNone;
+    }
+    eType = eTypeIn;
+}
+
+
 /************************************************************************/
 /*                          OGR_Fld_SetType()                           */
 /************************************************************************/
@@ -276,37 +308,300 @@ void OGR_Fld_SetType( OGRFieldDefnH hDefn, OGRFieldType eType )
 }
 
 /************************************************************************/
+/*                             GetSubType()                             */
+/************************************************************************/
+
+/**
+ * \fn OGRFieldSubType OGRFieldDefn::GetSubType();
+ *
+ * \brief Fetch subtype of this field.
+ *
+ * This method is the same as the C function OGR_Fld_GetSubType().
+ *
+ * @return field subtype.
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                         OGR_Fld_GetSubType()                         */
+/************************************************************************/
+/**
+ * \brief Fetch subtype of this field.
+ *
+ * This function is the same as the CPP method OGRFieldDefn::GetSubType().
+ *
+ * @param hDefn handle to the field definition to get subtype from.
+ * @return field subtype.
+ * @since GDAL 2.0
+ */
+
+OGRFieldSubType OGR_Fld_GetSubType( OGRFieldDefnH hDefn )
+
+{
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_Fld_GetXXXX(hDefn, "GetSubType");
+#endif
+
+    return ((OGRFieldDefn *) hDefn)->GetSubType();
+}
+
+/************************************************************************/
+/*                             SetSubType()                             */
+/************************************************************************/
+
+/**
+ * \brief Set the subtype of this field.
+ * This should never be done to an OGRFieldDefn
+ * that is already part of an OGRFeatureDefn.
+ *
+ * This method is the same as the C function OGR_Fld_SetSubType().
+ *
+ * @param eSubType the new field subtype.
+ * @since GDAL 2.0
+ */
+void OGRFieldDefn::SetSubType( OGRFieldSubType eSubTypeIn )
+{
+    if( !OGR_AreTypeSubTypeCompatible(eType, eSubTypeIn) )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Type and subtype of field definition are not compatible. Reseting to OFSTNone");
+        eSubType = OFSTNone;
+    }
+    else
+    {
+        eSubType = eSubTypeIn;
+    }
+}
+
+/************************************************************************/
+/*                         OGR_Fld_SetSubType()                         */
+/************************************************************************/
+/**
+ * \brief Set the subtype of this field.
+ * This should never be done to an OGRFieldDefn
+ * that is already part of an OGRFeatureDefn.
+ *
+ * This function is the same as the CPP method OGRFieldDefn::SetSubType().
+ *
+ * @param hDefn handle to the field definition to set type to.
+ * @param eSubType the new field subtype.
+ * @since GDAL 2.0
+ */
+
+void OGR_Fld_SetSubType( OGRFieldDefnH hDefn, OGRFieldSubType eSubType )
+
+{
+    ((OGRFieldDefn *) hDefn)->SetSubType( eSubType );
+}
+
+/************************************************************************/
 /*                             SetDefault()                             */
 /************************************************************************/
 
 /**
  * \brief Set default field value.
  *
- * Currently use of OGRFieldDefn "defaults" is discouraged.  This feature
- * may be fleshed out in the future.
+ * The default field value is taken into account by drivers (generally those with
+ * a SQL interface) that support it at field creation time. OGR will generally not
+ * automatically set the default field value to null fields by itself when calling
+ * OGRFeature::CreateFeature() / OGRFeature::SetFeature(), but will let the
+ * low-level layers to do the job. So retrieving the feature from the layer is
+ * recommended.
+ *
+ * The accepted values are NULL, a numeric value, a litteral value enclosed
+ * between single quote characters (and inner single quote characters escaped by
+ * repetition of the single quote character),
+ * CURRENT_TIMESTAMP, CURRENT_TIME, CURRENT_DATE or
+ * a driver specific expression (that might be ignored by other drivers).
+ * For a datetime literal value, format should be 'YYYY/MM/DD HH:MM:SS[.sss]'
+ * (considered as UTC time).
  *
+ * Drivers that support writing DEFAULT clauses will advertize the
+ * GDAL_DCAP_DEFAULT_FIELDS driver metadata item.
+ *
+ * This function is the same as the C function OGR_Fld_SetDefault().
+ *
+ * @param pszDefault new default field value or NULL pointer.
+ *
+ * @since GDAL 2.0
  */
 
-void OGRFieldDefn::SetDefault( const OGRField * puDefaultIn )
+void OGRFieldDefn::SetDefault( const char* pszDefaultIn )
 
 {
-    switch( eType )
+    CPLFree(pszDefault);
+    pszDefault = NULL;
+
+    if( pszDefaultIn && pszDefaultIn[0] == '\'' )
     {
-      case OFTInteger:
-      case OFTReal:
-        uDefault = *puDefaultIn;
-        break;
+        if( pszDefaultIn[strlen(pszDefaultIn)-1] != '\'' )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Incorrectly quoted string literal");
+            return;
+        }
+        const char* pszPtr = pszDefaultIn + 1;
+        for(; *pszPtr != '\0'; pszPtr ++ )
+        {
+            if( *pszPtr == '\'' )
+            {
+                if( pszPtr[1] == '\0' )
+                    break;
+                if( pszPtr[1] != '\'' )
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined, "Incorrectly quoted string literal");
+                    return;
+                }
+                pszPtr ++;
+            }
+        }
+        if( *pszPtr == '\0' )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Incorrectly quoted string literal");
+            return;
+        }
+    }
 
-      case OFTString:
-//        CPLFree( uDefault.String );
-//        uDefault.String = CPLStrdup( puDefaultIn->String );
-        break;
+    pszDefault = pszDefaultIn ? CPLStrdup(pszDefaultIn) : NULL;
+}
 
-      default:
-        // add handling for other complex types.
-        CPLAssert( FALSE );
-        break;
-    }
+/************************************************************************/
+/*                         OGR_Fld_SetDefault()                         */
+/************************************************************************/
+
+/**
+ * \brief Set default field value.
+ *
+ * The default field value is taken into account by drivers (generally those with
+ * a SQL interface) that support it at field creation time. OGR will generally not
+ * automatically set the default field value to null fields by itself when calling
+ * OGRFeature::CreateFeature() / OGRFeature::SetFeature(), but will let the
+ * low-level layers to do the job. So retrieving the feature from the layer is
+ * recommended.
+ *
+ * The accepted values are NULL, a numeric value, a litteral value enclosed
+ * between single quote characters (and inner single quote characters escaped by
+ * repetition of the single quote character),
+ * CURRENT_TIMESTAMP, CURRENT_TIME, CURRENT_DATE or
+ * a driver specific expression (that might be ignored by other drivers).
+ * For a datetime literal value, format should be 'YYYY/MM/DD HH:MM:SS[.sss]'
+ * (considered as UTC time).
+ *
+ * Drivers that support writing DEFAULT clauses will advertize the
+ * GDAL_DCAP_DEFAULT_FIELDS driver metadata item.
+ *
+ * This function is the same as the C++ method OGRFieldDefn::SetDefault().
+ *
+ * @param hDefn handle to the field definition.
+ * @param pszDefault new default field value or NULL pointer.
+ *
+ * @since GDAL 2.0
+ */
+
+void   CPL_DLL OGR_Fld_SetDefault( OGRFieldDefnH hDefn, const char* pszDefault )
+{
+    ((OGRFieldDefn *) hDefn)->SetDefault( pszDefault );
+}
+
+/************************************************************************/
+/*                             GetDefault()                             */
+/************************************************************************/
+
+/**
+ * \brief Get default field value.
+ *
+ * This function is the same as the C function OGR_Fld_GetDefault().
+ *
+ * @return default field value or NULL.
+ * @since GDAL 2.0
+ */
+
+const char* OGRFieldDefn::GetDefault() const
+
+{
+    return pszDefault;
+}
+
+/************************************************************************/
+/*                         OGR_Fld_GetDefault()                         */
+/************************************************************************/
+
+/**
+ * \brief Get default field value.
+ *
+ * This function is the same as the C++ method OGRFieldDefn::GetDefault().
+ *
+ * @param hDefn handle to the field definition.
+ * @return default field value or NULL.
+ * @since GDAL 2.0
+ */
+
+const char *OGR_Fld_GetDefault( OGRFieldDefnH hDefn )
+{
+    return ((OGRFieldDefn *) hDefn)->GetDefault();
+}
+
+/************************************************************************/
+/*                        IsDefaultDriverSpecific()                     */
+/************************************************************************/
+
+/**
+ * \brief Returns whether the default value is driver specific.
+ *
+ * Driver specific default values are those that are *not* NULL, a numeric value,
+ * a litteral value enclosed between single quote characters, CURRENT_TIMESTAMP,
+ * CURRENT_TIME, CURRENT_DATE or datetime literal value.
+ *
+ * This method is the same as the C function OGR_Fld_IsDefaultDriverSpecific().
+ *
+ * @return TRUE if the default value is driver specific.
+ * @since GDAL 2.0
+ */
+
+int OGRFieldDefn::IsDefaultDriverSpecific() const
+{
+    if( pszDefault == NULL )
+        return FALSE;
+
+    if( EQUAL(pszDefault, "NULL") ||
+        EQUAL(pszDefault, "CURRENT_TIMESTAMP") ||
+        EQUAL(pszDefault, "CURRENT_TIME") ||
+        EQUAL(pszDefault, "CURRENT_DATE") )
+        return FALSE;
+
+    if( pszDefault[0] == '\'' && pszDefault[strlen(pszDefault)-1] == '\'' )
+        return FALSE;
+
+    char* pszEnd = NULL;
+    CPLStrtod(pszDefault, &pszEnd);
+    if( *pszEnd == '\0' )
+        return FALSE;
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                     OGR_Fld_IsDefaultDriverSpecific()                */
+/************************************************************************/
+
+/**
+ * \brief Returns whether the default value is driver specific.
+ *
+ * Driver specific default values are those that are *not* NULL, a numeric value,
+ * a litteral value enclosed between single quote characters, CURRENT_TIMESTAMP,
+ * CURRENT_TIME, CURRENT_DATE or datetime literal value.
+ *
+ * This function is the same as the C++ method OGRFieldDefn::IsDefaultDriverSpecific().
+ *
+ * @param hDefn handle to the field definition
+ * @return TRUE if the default value is driver specific.
+ * @since GDAL 2.0
+ */
+
+int OGR_Fld_IsDefaultDriverSpecific( OGRFieldDefnH hDefn )
+{
+    return ((OGRFieldDefn *) hDefn)->IsDefaultDriverSpecific();
 }
 
 /************************************************************************/
@@ -332,6 +627,9 @@ const char * OGRFieldDefn::GetFieldTypeName( OGRFieldType eType )
       case OFTInteger:
         return "Integer";
 
+      case OFTInteger64:
+        return "Integer64";
+
       case OFTReal:
         return "Real";
 
@@ -341,6 +639,9 @@ const char * OGRFieldDefn::GetFieldTypeName( OGRFieldType eType )
       case OFTIntegerList:
         return "IntegerList";
 
+      case OFTInteger64List:
+        return "Integer64List";
+
       case OFTRealList:
         return "RealList";
 
@@ -384,6 +685,90 @@ const char *OGR_GetFieldTypeName( OGRFieldType eType )
 }
 
 /************************************************************************/
+/*                        GetFieldSubTypeName()                         */
+/************************************************************************/
+
+/**
+ * \brief Fetch human readable name for a field subtype.
+ *
+ * This static method is the same as the C function OGR_GetFieldSubTypeName().
+ *
+ * @param eSubType the field subtype to get name for.
+ *
+ * @return pointer to an internal static name string. It should not be
+ * modified or freed.
+ *
+ * @since GDAL 2.0
+ */
+
+const char * OGRFieldDefn::GetFieldSubTypeName( OGRFieldSubType eSubType )
+
+{
+    switch( eSubType )
+    {
+      case OFSTNone:
+        return "None";
+
+      case OFSTBoolean:
+        return "Boolean";
+
+      case OFSTInt16:
+        return "Int16";
+
+      case OFSTFloat32:
+        return "Float32";
+
+      default:
+        return "(unknown)";
+    }
+}
+
+/************************************************************************/
+/*                       OGR_GetFieldSubTypeName()                      */
+/************************************************************************/
+/**
+ * \brief Fetch human readable name for a field subtype.
+ *
+ * This function is the same as the CPP method 
+ * OGRFieldDefn::GetFieldSubTypeName().
+ *
+ * @param eSubType the field subtype to get name for.
+ * @return the name.
+ *
+ * @since GDAL 2.0
+ */
+
+const char *OGR_GetFieldSubTypeName( OGRFieldSubType eSubType )
+
+{
+    return OGRFieldDefn::GetFieldSubTypeName( eSubType );
+}
+
+/************************************************************************/
+/*                       OGR_IsValidTypeAndSubType()                    */
+/************************************************************************/
+/**
+ * \brief Return if type and subtype are compatible
+ *
+ * @param eType the field type.
+ * @param eSubType the field subtype.
+ * @return TRUE if type and subtype are compatible
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_AreTypeSubTypeCompatible( OGRFieldType eType, OGRFieldSubType eSubType )
+{
+    if( eSubType == OFSTNone )
+        return TRUE;
+    if( eSubType == OFSTBoolean || eSubType == OFSTInt16 )
+        return eType == OFTInteger || eType == OFTIntegerList;
+    if( eSubType == OFSTFloat32 )
+        return eType == OFTReal || eType == OFTRealList;
+    return FALSE;
+}
+
+/************************************************************************/
 /*                             GetJustify()                             */
 /************************************************************************/
 
@@ -392,6 +777,8 @@ const char *OGR_GetFieldTypeName( OGRFieldType eType )
  *
  * \brief Get the justification for this field.
  *
+ * Note: no driver is know to use the concept of field justification.
+ *
  * This method is the same as the C function OGR_Fld_GetJustify().
  *
  * @return the justification.
@@ -405,6 +792,8 @@ const char *OGR_GetFieldTypeName( OGRFieldType eType )
  *
  * This function is the same as the CPP method OGRFieldDefn::GetJustify().
  *
+ * Note: no driver is know to use the concept of field justification.
+ *
  * @param hDefn handle to the field definition to get justification from.
  * @return the justification.
  */
@@ -424,6 +813,8 @@ OGRJustification OGR_Fld_GetJustify( OGRFieldDefnH hDefn )
  *
  * \brief Set the justification for this field.
  *
+ * Note: no driver is know to use the concept of field justification.
+ *
  * This method is the same as the C function OGR_Fld_SetJustify().
  *
  * @param eJustify the new justification.
@@ -435,6 +826,8 @@ OGRJustification OGR_Fld_GetJustify( OGRFieldDefnH hDefn )
 /**
  * \brief Set the justification for this field.
  *
+ * Note: no driver is know to use the concept of field justification.
+ *
  * This function is the same as the CPP method OGRFieldDefn::SetJustify().
  *
  * @param hDefn handle to the field definition to set justification to.
@@ -722,6 +1115,102 @@ int OGRFieldDefn::IsSame( const OGRFieldDefn * poOtherFieldDefn ) const
 {
     return (strcmp(pszName, poOtherFieldDefn->pszName) == 0 &&
             eType == poOtherFieldDefn->eType &&
+            eSubType == poOtherFieldDefn->eSubType &&
             nWidth == poOtherFieldDefn->nWidth &&
-            nPrecision == poOtherFieldDefn->nPrecision);
+            nPrecision == poOtherFieldDefn->nPrecision &&
+            bNullable == poOtherFieldDefn->bNullable);
+}
+
+/************************************************************************/
+/*                             IsNullable()                             */
+/************************************************************************/
+
+/**
+ * \fn int OGRFieldDefn::IsNullable() const
+ *
+ * \brief Return whether this field can receive null values.
+ *
+ * By default, fields are nullable.
+ *
+ * Even if this method returns FALSE (i.e not-nullable field), it doesn't mean
+ * that OGRFeature::IsFieldSet() will necessary return TRUE, as fields can be
+ * temporary unset and null/not-null validation is usually done when
+ * OGRLayer::CreateFeature()/SetFeature() is called.
+ *
+ * This method is the same as the C function OGR_Fld_IsNullable().
+ *
+ * @return TRUE if the field is authorized to be null.
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                         OGR_Fld_IsNullable()                         */
+/************************************************************************/
+
+/**
+ * \brief Return whether this field can receive null values.
+ *
+ * By default, fields are nullable.
+ *
+ * Even if this method returns FALSE (i.e not-nullable field), it doesn't mean
+ * that OGRFeature::IsFieldSet() will necessary return TRUE, as fields can be
+ * temporary unset and null/not-null validation is usually done when
+ * OGRLayer::CreateFeature()/SetFeature() is called.
+ *
+ * This method is the same as the C++ method OGRFieldDefn::IsNullable().
+ *
+ * @param hDefn handle to the field definition
+ * @return TRUE if the field is authorized to be null.
+ * @since GDAL 2.0
+ */
+
+int OGR_Fld_IsNullable( OGRFieldDefnH hDefn )
+{
+    return ((OGRFieldDefn *) hDefn)->IsNullable();
+}
+
+/************************************************************************/
+/*                            SetNullable()                             */
+/************************************************************************/
+
+/**
+ * \fn void OGRFieldDefn::SetNullable( int bNullableIn );
+ *
+ * \brief Set whether this field can receive null values.
+ *
+ * By default, fields are nullable, so this method is generally called with FALSE
+ * to set a not-null constraint.
+ *
+ * Drivers that support writing not-null constraint will advertize the
+ * GDAL_DCAP_NOTNULL_FIELDS driver metadata item.
+ *
+ * This method is the same as the C function OGR_Fld_SetNullable().
+ *
+ * @param bNullableIn FALSE if the field must have a not-null constraint.
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                        OGR_Fld_SetNullable()                          */
+/************************************************************************/
+
+/**
+ * \brief Set whether this field can receive null values.
+ *
+ * By default, fields are nullable, so this method is generally called with FALSE
+ * to set a not-null constraint.
+ *
+ * Drivers that support writing not-null constraint will advertize the
+ * GDAL_DCAP_NOTNULL_FIELDS driver metadata item.
+ *
+ * This method is the same as the C++ method OGRFieldDefn::SetNullable().
+ *
+ * @param hDefn handle to the field definition
+ * @param bNullableIn FALSE if the field must have a not-null constraint.
+ * @since GDAL 2.0
+ */
+
+void OGR_Fld_SetNullable( OGRFieldDefnH hDefn, int bNullableIn )
+{
+    ((OGRFieldDefn *) hDefn)->SetNullable( bNullableIn );
 }
diff --git a/ogr/ogrgeomediageometry.cpp b/ogr/ogrgeomediageometry.cpp
index 5211f2a..6b6c962 100644
--- a/ogr/ogrgeomediageometry.cpp
+++ b/ogr/ogrgeomediageometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomediageometry.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeomediageometry.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements decoder of geomedia geometry blobs
@@ -30,7 +30,7 @@
 #include "ogrgeomediageometry.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrgeomediageometry.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgeomediageometry.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 #define GEOMEDIA_POINT          0xC0
 #define GEOMEDIA_ORIENTED_POINT 0xC8
@@ -353,7 +353,6 @@ OGRErr OGRCreateFromGeomedia( GByte *pabyGeom,
 
                 if (poColl->addGeometryDirectly(poSubGeom) != OGRERR_NONE)
                 {
-                    //printf("%d %d\n", poColl->getGeometryType() & ~wkb25DBit, poSubGeom->getGeometryType() & ~wkb25DBit);
                     delete poSubGeom;
                 }
             }
diff --git a/ogr/ogrgeometry.cpp b/ogr/ogrgeometry.cpp
index 83cc3b6..fb350bc 100644
--- a/ogr/ogrgeometry.cpp
+++ b/ogr/ogrgeometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeometry.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgeometry.cpp 28548 2015-02-24 17:30:15Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements a few base methods on OGRGeometry.
@@ -35,7 +35,7 @@
 #include "cpl_multiproc.h"
 #include <assert.h>
 
-CPL_CVSID("$Id: ogrgeometry.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgeometry.cpp 28548 2015-02-24 17:30:15Z rouault $");
 
 int OGRGeometry::bGenerate_DB2_V72_BYTE_ORDER = FALSE;
 
@@ -118,8 +118,8 @@ void OGRGeometry::dumpReadable( FILE * fp, const char * pszPrefix, char** papszO
     if (pszDisplayGeometry != NULL && EQUAL(pszDisplayGeometry, "SUMMARY"))
     {
         OGRLineString *poLine;
-        OGRPolygon *poPoly;
-        OGRLinearRing *poRing;
+        OGRCurvePolygon *poPoly;
+        OGRCurve *poRing;
         OGRGeometryCollection *poColl;
         fprintf( fp, "%s%s : ", pszPrefix, getGeometryName() );
         switch( getGeometryType() )
@@ -132,31 +132,47 @@ void OGRGeometry::dumpReadable( FILE * fp, const char * pszPrefix, char** papszO
                 break;
             case wkbLineString:
             case wkbLineString25D:
+            case wkbCircularString:
+            case wkbCircularStringZ:
                 poLine = (OGRLineString*)this;
                 fprintf( fp, "%d points\n", poLine->getNumPoints() );
                 break;
             case wkbPolygon:
             case wkbPolygon25D:
+            case wkbCurvePolygon:
+            case wkbCurvePolygonZ:
             {
                 int ir;
                 int nRings;
-                poPoly = (OGRPolygon*)this;
-                poRing = poPoly->getExteriorRing();
+                poPoly = (OGRCurvePolygon*)this;
+                poRing = poPoly->getExteriorRingCurve();
                 nRings = poPoly->getNumInteriorRings();
                 if (poRing == NULL)
                     fprintf( fp, "empty");
                 else
                 {
                     fprintf( fp, "%d points", poRing->getNumPoints() );
+                    if( wkbFlatten(poRing->getGeometryType()) == wkbCompoundCurve )
+                    {
+                        fprintf( fp, " (");
+                        poRing->dumpReadable(fp, NULL, papszOptions);
+                        fprintf( fp, ")");
+                    }
                     if (nRings)
                     {
                         fprintf( fp, ", %d inner rings (", nRings);
                         for( ir = 0; ir < nRings; ir++)
                         {
+                            poRing = poPoly->getInteriorRingCurve(ir);
                             if (ir)
                                 fprintf( fp, ", ");
-                            fprintf( fp, "%d points",
-                                    poPoly->getInteriorRing(ir)->getNumPoints() );
+                            fprintf( fp, "%d points", poRing->getNumPoints() );
+                            if( wkbFlatten(poRing->getGeometryType()) == wkbCompoundCurve )
+                            {
+                                fprintf( fp, " (");
+                                poRing->dumpReadable(fp, NULL, papszOptions);
+                                fprintf( fp, ")");
+                            }
                         }
                         fprintf( fp, ")");
                     }
@@ -164,13 +180,37 @@ void OGRGeometry::dumpReadable( FILE * fp, const char * pszPrefix, char** papszO
                 fprintf( fp, "\n");
                 break;
             }
+            case wkbCompoundCurve:
+            case wkbCompoundCurveZ:
+            {
+                OGRCompoundCurve* poCC = (OGRCompoundCurve* )this;
+                if( poCC->getNumCurves() == 0 )
+                    fprintf( fp, "empty");
+                else
+                {
+                    for(int i=0;i<poCC->getNumCurves();i++)
+                    {
+                        if (i)
+                            fprintf( fp, ", ");
+                        fprintf( fp, "%s (%d points)",
+                                 poCC->getCurve(i)->getGeometryName(),
+                                 poCC->getCurve(i)->getNumPoints() );
+                    }
+                }
+                break;
+            }
+
             case wkbMultiPoint:
-            case wkbMultiPoint25D:
             case wkbMultiLineString:
-            case wkbMultiLineString25D:
             case wkbMultiPolygon:
-            case wkbMultiPolygon25D:
+            case wkbMultiCurve:
+            case wkbMultiSurface:
             case wkbGeometryCollection:
+            case wkbMultiPoint25D:
+            case wkbMultiLineString25D:
+            case wkbMultiPolygon25D:
+            case wkbMultiCurveZ:
+            case wkbMultiSurfaceZ:
             case wkbGeometryCollection25D:
             {
                 int ig;
@@ -307,7 +347,7 @@ void OGR_G_AssignSpatialReference( OGRGeometryH hGeom,
  * @return TRUE if the geometries intersect, otherwise FALSE.
  */
 
-OGRBoolean OGRGeometry::Intersects( OGRGeometry *poOtherGeom ) const
+OGRBoolean OGRGeometry::Intersects( const OGRGeometry *poOtherGeom ) const
 
 {
     OGREnvelope         oEnv1, oEnv2;
@@ -388,7 +428,7 @@ int OGR_G_Intersects( OGRGeometryH hGeom, OGRGeometryH hOtherGeom )
     VALIDATE_POINTER1( hGeom, "OGR_G_Intersects", FALSE );
     VALIDATE_POINTER1( hOtherGeom, "OGR_G_Intersects", FALSE );
 
-    return ((OGRGeometry *) hGeom)->Intersects( (OGRGeometry *) hOtherGeom );
+    return ((OGRGeometry *) hGeom)->Intersects( (const OGRGeometry *) hOtherGeom );
 }
 
 int OGR_G_Intersect( OGRGeometryH hGeom, OGRGeometryH hOtherGeom )
@@ -397,7 +437,7 @@ int OGR_G_Intersect( OGRGeometryH hGeom, OGRGeometryH hOtherGeom )
     VALIDATE_POINTER1( hGeom, "OGR_G_Intersect", FALSE );
     VALIDATE_POINTER1( hOtherGeom, "OGR_G_Intersect", FALSE );
 
-    return ((OGRGeometry *) hGeom)->Intersects( (OGRGeometry *) hOtherGeom );
+    return ((OGRGeometry *) hGeom)->Intersects( (const OGRGeometry *) hOtherGeom );
 }
 
 /************************************************************************/
@@ -567,12 +607,18 @@ OGRErr OGR_G_Transform( OGRGeometryH hGeom,
  * @return 0 for points, 1 for lines and 2 for surfaces.
  */
 
-int OGRGeometry::getIsoGeometryType() const
+
+/**
+ * \brief Get the geometry type that conforms with ISO SQL/MM Part3
+ *
+ * @return the geometry type that conforms with ISO SQL/MM Part3
+ */
+OGRwkbGeometryType OGRGeometry::getIsoGeometryType() const
 {
-    int nGType = wkbFlatten(getGeometryType());
+    OGRwkbGeometryType nGType = wkbFlatten(getGeometryType());
 
     if ( getCoordinateDimension() == 3 )
-        nGType += 1000;
+        nGType = (OGRwkbGeometryType)(nGType + 1000);
 
     return nGType;
 }
@@ -920,7 +966,7 @@ void OGR_G_GetEnvelope3D( OGRGeometryH hGeom, OGREnvelope3D *psEnvelope )
 }
 
 /**
- * \fn OGRErr OGRGeometry::importFromWkb( unsigned char * pabyData, int nSize);
+ * \fn OGRErr OGRGeometry::importFromWkb( unsigned char * pabyData, int nSize, OGRwkbVariant eWkbVariant =wkbVariantOldOgc );
  *
  * \brief Assign geometry from well known binary data.
  *
@@ -935,6 +981,7 @@ void OGR_G_GetEnvelope3D( OGRGeometryH hGeom, OGREnvelope3D *psEnvelope )
  *
  * @param pabyData the binary input data.
  * @param nSize the size of pabyData in bytes, or zero if not known.
+ * @param eWkbVariant if wkbVariantPostGIS1, special interpretation is done for curve geometries code
  *
  * @return OGRERR_NONE if all goes well, otherwise any of
  * OGRERR_NOT_ENOUGH_DATA, OGRERR_UNSUPPORTED_GEOMETRY_TYPE, or
@@ -975,13 +1022,14 @@ OGRErr OGR_G_ImportFromWkb( OGRGeometryH hGeom,
 /**
  * \fn OGRErr OGRGeometry::exportToWkb( OGRwkbByteOrder eByteOrder,
                                         unsigned char * pabyData,
-                                        OGRwkbVariant eWkbVariant=wkbVariantOgc ) const
+                                        OGRwkbVariant eWkbVariant=wkbVariantOldOgc ) const
  *
  * \brief Convert a geometry into well known binary format.
  *
  * This method relates to the SFCOM IWks::ExportToWKB() method.
  *
- * This method is the same as the C function OGR_G_ExportToWkb().
+ * This method is the same as the C function OGR_G_ExportToWkb() or OGR_G_ExportToIsoWkb(),
+ * depending on the value of eWkbVariant.
  *
  * @param eByteOrder One of wkbXDR or wkbNDR indicating MSB or LSB byte order
  *               respectively.
@@ -989,7 +1037,7 @@ OGRErr OGR_G_ImportFromWkb( OGRGeometryH hGeom,
  *                      written.  This buffer must be at least
  *                      OGRGeometry::WkbSize() byte in size.
  * @param eWkbVariant What standard to use when exporting geometries with 
- *                      three dimensions (or more). The default wkbVariantOgc is 
+ *                      three dimensions (or more). The default wkbVariantOldOgc is 
  *                      the historical OGR variant. wkbVariantIso is the 
  *                      variant defined in ISO SQL/MM and adopted by OGC 
  *                      for SFSQL 1.2.
@@ -1001,11 +1049,17 @@ OGRErr OGR_G_ImportFromWkb( OGRGeometryH hGeom,
 /*                         OGR_G_ExportToWkb()                          */
 /************************************************************************/
 /**
- * \brief Convert a geometry into well known binary format.
+ * \brief Convert a geometry well known binary format
  *
  * This function relates to the SFCOM IWks::ExportToWKB() method.
  *
- * This function is the same as the CPP method OGRGeometry::exportToWkb().
+ * For backward compatibility purposes, it exports the Old-style 99-402
+ * extended dimension (Z) WKB types for types Point, LineString, Polygon,
+ * MultiPoint, MultiLineString, MultiPolygon and GeometryCollection.
+ * For other geometry types, it is equivalent to OGR_G_ExportToIsoWkb().
+ *
+ * This function is the same as the CPP method OGRGeometry::exportToWkb(OGRwkbByteOrder, unsigned char *, OGRwkbVariant)
+ * with eWkbVariant = wkbVariantOldOgc.
  *
  * @param hGeom handle on the geometry to convert to a well know binary 
  * data from.
@@ -1027,6 +1081,40 @@ OGRErr OGR_G_ExportToWkb( OGRGeometryH hGeom, OGRwkbByteOrder eOrder,
     return ((OGRGeometry *) hGeom)->exportToWkb( eOrder, pabyDstBuffer );
 }
 
+/************************************************************************/
+/*                        OGR_G_ExportToIsoWkb()                        */
+/************************************************************************/
+/**
+ * \brief Convert a geometry into SFSQL 1.2 / ISO SQL/MM Part 3 well known binary format
+ *
+ * This function relates to the SFCOM IWks::ExportToWKB() method.
+ * It exports the SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension (Z&M) WKB types
+ *
+ * This function is the same as the CPP method  OGRGeometry::exportToWkb(OGRwkbByteOrder, unsigned char *, OGRwkbVariant)
+ * with eWkbVariant = wkbVariantIso.
+ *
+ * @param hGeom handle on the geometry to convert to a well know binary 
+ * data from.
+ * @param eOrder One of wkbXDR or wkbNDR indicating MSB or LSB byte order
+ *               respectively.
+ * @param pabyDstBuffer a buffer into which the binary representation is
+ *                      written.  This buffer must be at least
+ *                      OGR_G_WkbSize() byte in size.
+ *
+ * @return Currently OGRERR_NONE is always returned.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRErr OGR_G_ExportToIsoWkb( OGRGeometryH hGeom, OGRwkbByteOrder eOrder,
+                          unsigned char *pabyDstBuffer )
+
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_ExportToIsoWkb", OGRERR_FAILURE );
+
+    return ((OGRGeometry *) hGeom)->exportToWkb( eOrder, pabyDstBuffer, wkbVariantIso );
+}
+
 /**
  * \fn OGRErr OGRGeometry::importFromWkt( char ** ppszInput );
  *
@@ -1079,8 +1167,116 @@ OGRErr OGR_G_ImportFromWkt( OGRGeometryH hGeom, char ** ppszSrcText )
     return ((OGRGeometry *) hGeom)->importFromWkt( ppszSrcText );
 }
 
+
+/************************************************************************/
+/*                        importPreambuleFromWkt()                      */
+/************************************************************************/
+
+/* Returns -1 if processing must continue */
+OGRErr OGRGeometry::importPreambuleFromWkt( char ** ppszInput,
+                                            int* pbHasZ, int* pbHasM )
+{
+    char        szToken[OGR_WKT_TOKEN_MAX];
+    const char  *pszInput = *ppszInput;
+
+/* -------------------------------------------------------------------- */
+/*      Clear existing Geoms.                                           */
+/* -------------------------------------------------------------------- */
+    empty();
+
+/* -------------------------------------------------------------------- */
+/*      Read and verify the type keyword, and ensure it matches the     */
+/*      actual type of this container.                                  */
+/* -------------------------------------------------------------------- */
+    pszInput = OGRWktReadToken( pszInput, szToken );
+
+    if( !EQUAL(szToken,getGeometryName()) )
+        return OGRERR_CORRUPT_DATA;
+
+/* -------------------------------------------------------------------- */
+/*      Check for EMPTY ...                                             */
+/* -------------------------------------------------------------------- */
+    const char *pszPreScan;
+    int bHasZ = FALSE, bHasM = FALSE;
+
+    pszPreScan = OGRWktReadToken( pszInput, szToken );
+    if( EQUAL(szToken,"EMPTY") )
+    {
+        *ppszInput = (char *) pszPreScan;
+        empty();
+        return OGRERR_NONE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Check for Z, M or ZM. Will ignore the Measure                   */
+/* -------------------------------------------------------------------- */
+    else if( EQUAL(szToken,"Z") )
+    {
+        bHasZ = TRUE;
+    }
+    else if( EQUAL(szToken,"M") )
+    {
+        bHasM = TRUE;
+    }
+    else if( EQUAL(szToken,"ZM") )
+    {
+        bHasZ = TRUE;
+        bHasM = TRUE;
+    }
+    *pbHasZ = bHasZ;
+    *pbHasM = bHasM;
+
+    if (bHasZ || bHasM)
+    {
+        pszInput = pszPreScan;
+        pszPreScan = OGRWktReadToken( pszInput, szToken );
+        if( EQUAL(szToken,"EMPTY") )
+        {
+            *ppszInput = (char *) pszPreScan;
+            empty();
+            if( bHasZ )
+                setCoordinateDimension(3);
+
+            /* FIXME?: In theory we should store the M presence */
+            /* if we want to allow round-trip with ExportToWKT v1.2 */
+            return OGRERR_NONE;
+        }
+    }
+
+    if( !EQUAL(szToken,"(") )
+        return OGRERR_CORRUPT_DATA;
+
+    if ( !bHasZ && !bHasM )
+    {
+        /* Test for old-style XXXXXXXXX(EMPTY) */
+        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
+        if( EQUAL(szToken,"EMPTY") )
+        {
+            pszPreScan = OGRWktReadToken( pszPreScan, szToken );
+
+            if( EQUAL(szToken,",") )
+            {
+                /* This is OK according to SFSQL SPEC. */
+            }
+            else if( !EQUAL(szToken,")") )
+                return OGRERR_CORRUPT_DATA;
+            else
+            {
+                *ppszInput = (char *) pszPreScan;
+                empty();
+                return OGRERR_NONE;
+            }
+        }
+    }
+    
+    *ppszInput = (char*) pszInput;
+
+    return -1;
+}
+
+
 /**
- * \fn OGRErr OGRGeometry::exportToWkt( char ** ppszDstText ) const;
+ * \fn OGRErr OGRGeometry::exportToWkt( char ** ppszDstText, OGRwkbVariant eWkbVariant = wkbVariantOldOgc ) const;
  *
  * \brief Convert a geometry into well known text format.
  *
@@ -1091,6 +1287,9 @@ OGRErr OGR_G_ImportFromWkt( OGRGeometryH hGeom, char ** ppszSrcText )
  * @param ppszDstText a text buffer is allocated by the program, and assigned
  *                    to the passed pointer. After use, *ppszDstText should be
  *                    freed with OGRFree().
+ * @param eWkbVariant the specification that must be conformed too :
+ *                    - wbkVariantOgc for old-style 99-402 extended dimension (Z) WKB types
+ *                    - wbkVariantIso for SFSQL 1.2 and ISO SQL/MM Part 3
  *
  * @return Currently OGRERR_NONE is always returned.
  */
@@ -1098,11 +1297,17 @@ OGRErr OGR_G_ImportFromWkt( OGRGeometryH hGeom, char ** ppszSrcText )
 /************************************************************************/
 /*                         OGR_G_ExportToWkt()                          */
 /************************************************************************/
+
 /**
  * \brief Convert a geometry into well known text format.
  *
  * This function relates to the SFCOM IWks::ExportToWKT() method.
  *
+ * For backward compatibility purposes, it exports the Old-style 99-402
+ * extended dimension (Z) WKB types for types Point, LineString, Polygon,
+ * MultiPoint, MultiLineString, MultiPolygon and GeometryCollection.
+ * For other geometry types, it is equivalent to OGR_G_ExportToIsoWkt().
+ *
  * This function is the same as the CPP method OGRGeometry::exportToWkt().
  *
  * @param hGeom handle on the geometry to convert to a text format from.
@@ -1121,6 +1326,36 @@ OGRErr OGR_G_ExportToWkt( OGRGeometryH hGeom, char **ppszSrcText )
     return ((OGRGeometry *) hGeom)->exportToWkt( ppszSrcText );
 }
 
+/************************************************************************/
+/*                      OGR_G_ExportToIsoWkt()                          */
+/************************************************************************/
+
+/**
+ * \brief Convert a geometry into SFSQL 1.2 / ISO SQL/MM Part 3 well known text format
+ *
+ * This function relates to the SFCOM IWks::ExportToWKT() method.
+ * It exports the SFSQL 1.2 and ISO SQL/MM Part 3 extended dimension (Z&M) WKB types
+ *
+ * This function is the same as the CPP method OGRGeometry::exportToWkt(,wkbVariantIso).
+ *
+ * @param hGeom handle on the geometry to convert to a text format from.
+ * @param ppszSrcText a text buffer is allocated by the program, and assigned
+ *                    to the passed pointer. After use, *ppszDstText should be
+ *                    freed with OGRFree().
+ *
+ * @return Currently OGRERR_NONE is always returned.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRErr OGR_G_ExportToIsoWkt( OGRGeometryH hGeom, char **ppszSrcText )
+
+{
+    VALIDATE_POINTER1( hGeom, "OGR_G_ExportToIsoWkt", OGRERR_FAILURE );
+
+    return ((OGRGeometry *) hGeom)->exportToWkt( ppszSrcText, wkbVariantIso );
+}
+
 /**
  * \fn OGRwkbGeometryType OGRGeometry::getGeometryType() const;
  *
@@ -1568,29 +1803,47 @@ int OGR_G_IsRing( OGRGeometryH hGeom )
 
 OGRwkbGeometryType OGRFromOGCGeomType( const char *pszGeomType )
 {
-    unsigned int n25DBit = 0;
+    OGRwkbGeometryType eType;
+    int bConvertTo3D = FALSE;
     if( *pszGeomType != '\0' )
     {
         char ch = pszGeomType[strlen(pszGeomType)-1];
         if( ch == 'z' || ch == 'Z' )
-            n25DBit = wkb25DBit;
+        {
+            bConvertTo3D = TRUE;
+        }
     }
     if ( EQUALN_CST(pszGeomType, "POINT") )
-        return (OGRwkbGeometryType)(wkbPoint | n25DBit);
+        eType = wkbPoint;
     else if ( EQUALN_CST(pszGeomType, "LINESTRING") )
-        return (OGRwkbGeometryType)(wkbLineString | n25DBit);
+        eType = wkbLineString;
     else if ( EQUALN_CST(pszGeomType, "POLYGON") )
-        return (OGRwkbGeometryType)(wkbPolygon | n25DBit);
+        eType = wkbPolygon;
     else if ( EQUALN_CST(pszGeomType, "MULTIPOINT") )
-        return (OGRwkbGeometryType)(wkbMultiPoint | n25DBit);
+        eType = wkbMultiPoint;
     else if ( EQUALN_CST(pszGeomType, "MULTILINESTRING") )
-        return (OGRwkbGeometryType)(wkbMultiLineString | n25DBit);
+        eType = wkbMultiLineString;
     else if ( EQUALN_CST(pszGeomType, "MULTIPOLYGON") )
-        return (OGRwkbGeometryType)(wkbMultiPolygon | n25DBit);
+        eType = wkbMultiPolygon;
     else if ( EQUALN_CST(pszGeomType, "GEOMETRYCOLLECTION") )
-        return (OGRwkbGeometryType)(wkbGeometryCollection | n25DBit);
+        eType = wkbGeometryCollection;
+    else if ( EQUALN_CST(pszGeomType, "CIRCULARSTRING") )
+        eType = wkbCircularString;
+    else if ( EQUALN_CST(pszGeomType, "COMPOUNDCURVE") )
+        eType = wkbCompoundCurve;
+    else if ( EQUALN_CST(pszGeomType, "CURVEPOLYGON") )
+        eType = wkbCurvePolygon;
+    else if ( EQUALN_CST(pszGeomType, "MULTICURVE") )
+        eType = wkbMultiCurve;
+    else if ( EQUALN_CST(pszGeomType, "MULTISURFACE") )
+        eType = wkbMultiSurface;
     else
-        return (OGRwkbGeometryType)(wkbUnknown | n25DBit);
+        eType = wkbUnknown;
+
+    if( bConvertTo3D )
+        eType = wkbSetZ(eType);
+    
+    return eType;
 }
 
 /************************************************************************/
@@ -1619,6 +1872,16 @@ const char * OGRToOGCGeomType( OGRwkbGeometryType eGeomType )
             return "MULTIPOLYGON";
         case wkbGeometryCollection:
             return "GEOMETRYCOLLECTION";
+        case wkbCircularString:
+            return "CIRCULARSTRING";
+        case wkbCompoundCurve:
+            return "COMPOUNDCURVE";
+        case wkbCurvePolygon:
+            return "CURVEPOLYGON";
+        case wkbMultiCurve:
+            return "MULTICURVE";
+        case wkbMultiSurface:
+            return "MULTISURFACE";
         default:
             return "";
     }
@@ -1629,7 +1892,7 @@ const char * OGRToOGCGeomType( OGRwkbGeometryType eGeomType )
 /************************************************************************/
 
 /**
- * \brief Fetch a human readable name corresponding to an OGRwkBGeometryType value.
+ * \brief Fetch a human readable name corresponding to an OGRwkbGeometryType value.
  * The returned value should not be modified, or freed by the application.
  *
  * This function is C callable.
@@ -1694,6 +1957,36 @@ const char *OGRGeometryTypeToName( OGRwkbGeometryType eType )
         else
             return "3D Geometry Collection";
 
+      case wkbCircularString:
+        if( b2D )
+            return "Circular String";
+        else
+            return "3D Circular String";
+
+      case wkbCompoundCurve:
+        if( b2D )
+            return "Compound Curve";
+        else
+            return "3D Compound Curve";
+
+      case wkbCurvePolygon:
+        if( b2D )
+            return "Curve Polygon";
+        else
+            return "3D Curve Polygon";
+
+      case wkbMultiCurve:
+        if( b2D )
+            return "Multi Curve";
+        else
+            return "3D Multi Curve";
+
+      case wkbMultiSurface:
+        if( b2D )
+            return "Multi Surface";
+        else
+            return "3D Multi Surface";
+
       case wkbNone:
         return "None";
 
@@ -1739,15 +2032,51 @@ OGRMergeGeometryTypes( OGRwkbGeometryType eMain,
                        OGRwkbGeometryType eExtra )
 
 {
-    int n25DFlag = 0;
+    return OGRMergeGeometryTypesEx(eMain, eExtra, FALSE);
+}
+
+/**
+ * \brief Find common geometry type.
+ *
+ * Given two geometry types, find the most specific common
+ * type.  Normally used repeatedly with the geometries in a
+ * layer to try and establish the most specific geometry type
+ * that can be reported for the layer.
+ *
+ * NOTE: wkbUnknown is the "worst case" indicating a mixture of
+ * geometry types with nothing in common but the base geometry
+ * type.  wkbNone should be used to indicate that no geometries
+ * have been encountered yet, and means the first geometry
+ * encounted will establish the preliminary type.
+ *
+ * If bAllowPromotingToCurves is set to TRUE, mixing Polygon and CurvePolygon
+ * will return CurvePolygon. Mixing LineString, CircularString, CompoundCurve
+ * will return CompoundCurve. Mixing MultiPolygon and MultiSurface will return
+ * MultiSurface. Mixing MultiCurve and MultiLineString will return MultiCurve.
+ * 
+ * @param eMain the first input geometry type.
+ * @param eExtra the second input geometry type.
+ * @param bAllowPromotingToCurves determine if promotion to curve type must be done.
+ *
+ * @return the merged geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType 
+OGRMergeGeometryTypesEx( OGRwkbGeometryType eMain,
+                         OGRwkbGeometryType eExtra,
+                         int bAllowPromotingToCurves )
+
+{
+    int bHasZ;
     OGRwkbGeometryType eFMain = wkbFlatten(eMain);
     OGRwkbGeometryType eFExtra = wkbFlatten(eExtra);
-        
-    if( eFMain != eMain || eFExtra != eExtra )
-        n25DFlag = wkb25DBit;
+
+    bHasZ = ( eFMain != eMain || eFExtra != eExtra );
 
     if( eFMain == wkbUnknown || eFExtra == wkbUnknown )
-        return (OGRwkbGeometryType) (((int) wkbUnknown) | n25DFlag);
+        return OGR_GT_SetModifier(wkbUnknown, bHasZ, FALSE);
 
     if( eFMain == wkbNone )
         return eExtra;
@@ -1756,23 +2085,31 @@ OGRMergeGeometryTypes( OGRwkbGeometryType eMain,
         return eMain;
 
     if( eFMain == eFExtra )
-        return (OGRwkbGeometryType) (((int) eFMain) | n25DFlag);
+    {
+        return OGR_GT_SetModifier(eFMain, bHasZ, FALSE);
+    }
+
+    if( bAllowPromotingToCurves )
+    {
+        if( OGR_GT_IsCurve(eFMain) && OGR_GT_IsCurve(eFExtra) )
+            return OGR_GT_SetModifier(wkbCompoundCurve, bHasZ, FALSE);
+
+        if( OGR_GT_IsSubClassOf(eFMain, eFExtra) )
+            return OGR_GT_SetModifier(eFExtra, bHasZ, FALSE);
+
+        if( OGR_GT_IsSubClassOf(eFExtra, eFMain) )
+            return OGR_GT_SetModifier(eFMain, bHasZ, FALSE);
+    }
 
     // Both are geometry collections.
-    if( (eFMain == wkbGeometryCollection
-         || eFMain == wkbMultiPoint
-         || eFMain == wkbMultiLineString
-         || eFMain == wkbMultiPolygon)
-        && (eFExtra == wkbGeometryCollection
-            || eFExtra == wkbMultiPoint
-            || eFExtra == wkbMultiLineString
-            || eFMain == wkbMultiPolygon) )
+    if( OGR_GT_IsSubClassOf(eFMain, wkbGeometryCollection) &&
+        OGR_GT_IsSubClassOf(eFExtra, wkbGeometryCollection) )
     {
-        return (OGRwkbGeometryType) (((int) wkbGeometryCollection) | n25DFlag);
+        return OGR_GT_SetModifier(wkbGeometryCollection, bHasZ, FALSE);
     }
 
     // Nothing apparently in common.
-    return (OGRwkbGeometryType) (((int) wkbUnknown) | n25DFlag);
+    return OGR_GT_SetModifier(wkbUnknown, bHasZ, FALSE);
 }
 
 /**
@@ -1992,7 +2329,7 @@ GEOSGeom OGRGeometry::exportToGEOS(GEOSContextHandle_t hGEOSCtxt) const
     /* POINT EMPTY is exported to WKB as if it were POINT(0 0) */
     /* so that particular case is necessary */
     if (wkbFlatten(getGeometryType()) == wkbPoint &&
-        nCoordDimension == 0)
+        IsEmpty())
     {
         return GEOSGeomFromWKT_r(hGEOSCtxt, "POINT EMPTY");
     }
@@ -2001,18 +2338,118 @@ GEOSGeom OGRGeometry::exportToGEOS(GEOSContextHandle_t hGEOSCtxt) const
     size_t nDataSize;
     unsigned char *pabyData = NULL;
 
-    nDataSize = WkbSize();
+    const OGRGeometry* poLinearGeom = (hasCurveGeometry()) ? getLinearGeometry() : this;
+    nDataSize = poLinearGeom->WkbSize();
     pabyData = (unsigned char *) CPLMalloc(nDataSize);
-    if( exportToWkb( wkbNDR, pabyData ) == OGRERR_NONE )
+    if( poLinearGeom->exportToWkb( wkbNDR, pabyData ) == OGRERR_NONE )
         hGeom = GEOSGeomFromWKB_buf_r( hGEOSCtxt, pabyData, nDataSize );
 
     CPLFree( pabyData );
 
+    if( poLinearGeom != this )
+        delete poLinearGeom;
+
     return hGeom;
 
 #endif /* HAVE_GEOS */
 }
 
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+/**
+ * \brief Returns if this geometry is or has curve geometry.
+ *
+ * Returns if a geometry is, contains or may contain a CIRCULARSTRING, COMPOUNDCURVE,
+ * CURVEPOLYGON, MULTICURVE or MULTISURFACE.
+ *
+ * If bLookForNonLinear is set to TRUE, it will be actually looked if the
+ * geometry or its subgeometries are or contain a non-linear geometry in them. In which
+ * case, if the method returns TRUE, it means that getLinearGeometry() would
+ * return an approximate version of the geometry. Otherwise, getLinearGeometry()
+ * would do a conversion, but with just converting container type, like
+ * COMPOUNDCURVE -> LINESTRING, MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON,
+ * resulting in a "loss-less" conversion.
+ *
+ * This method is the same as the C function OGR_G_HasCurveGeometry().
+ *
+ * @param bLookForNonLinear set it to TRUE to check if the geometry is or contains
+ * a CIRCULARSTRING.
+ *
+ * @return TRUE if this geometry is or has curve geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRBoolean OGRGeometry::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
+{
+    return FALSE;
+}
+
+/************************************************************************/
+/*                         getLinearGeometry()                        */
+/************************************************************************/
+
+/**
+ * \brief Return, possibly approximate, non-curve version of this geometry.
+ *
+ * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
+ * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
+ *
+ * The ownership of the returned geometry belongs to the caller.
+ *
+ * The reverse method is OGRGeometry::getCurveGeometry().
+ *
+ * This method is the same as the C function OGR_G_GetLinearGeometry().
+ *
+ * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
+ * arc, zero to use the default setting.
+ * @param papszOptions options as a null-terminated list of strings.
+ *                     See OGRGeometryFactory::curveToLineString() for valid options.
+ *
+ * @return a new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometry* OGRGeometry::getLinearGeometry(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
+                                            CPL_UNUSED const char* const* papszOptions) const
+{
+    return clone();
+}
+
+/************************************************************************/
+/*                             getCurveGeometry()                       */
+/************************************************************************/
+
+/**
+ * \brief Return curve version of this geometry.
+ *
+ * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
+ * MULTICURVE or MULTISURFACE in it, by de-approximating curve geometries.
+ *
+ * If the geometry has no curve portion, the returned geometry will be a clone
+ * of it.
+ *
+ * The ownership of the returned geometry belongs to the caller.
+ *
+ * The reverse method is OGRGeometry::getLinearGeometry().
+ *
+ * This function is the same as C function OGR_G_GetCurveGeometry().
+ *
+ * @param papszOptions options as a null-terminated list of strings.
+ *                     Unused for now. Must be set to NULL.
+ *
+ * @return a new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometry* OGRGeometry::getCurveGeometry(CPL_UNUSED const char* const* papszOptions) const
+{
+    return clone();
+}
 
 /************************************************************************/
 /*                              Distance()                              */
@@ -2116,6 +2553,26 @@ double OGR_G_Distance( OGRGeometryH hFirst, OGRGeometryH hOther )
 }
 
 /************************************************************************/
+/*                       OGRGeometryRebuildCurves()                     */
+/************************************************************************/
+
+static OGRGeometry* OGRGeometryRebuildCurves(const OGRGeometry* poGeom,
+                                             const OGRGeometry* poOtherGeom,
+                                             OGRGeometry* poOGRProduct)
+{
+    if( poOGRProduct != NULL &&
+        wkbFlatten(poOGRProduct->getGeometryType()) != wkbPoint &&
+        (poGeom->hasCurveGeometry() ||
+         (poOtherGeom && poOtherGeom->hasCurveGeometry())) )
+    {
+        OGRGeometry* poCurveGeom = poOGRProduct->getCurveGeometry();
+        delete poOGRProduct;
+        return poCurveGeom;
+    }
+    return poOGRProduct;
+}
+
+/************************************************************************/
 /*                             ConvexHull()                             */
 /************************************************************************/
 
@@ -2148,7 +2605,7 @@ OGRGeometry *OGRGeometry::ConvexHull() const
 
     GEOSGeom hGeosGeom = NULL;
     GEOSGeom hGeosHull = NULL;
-    OGRGeometry *poHullOGRGeom = NULL;
+    OGRGeometry *poOGRProduct = NULL;
 
     GEOSContextHandle_t hGEOSCtxt = createGEOSContext();
     hGeosGeom = exportToGEOS(hGEOSCtxt);
@@ -2159,15 +2616,16 @@ OGRGeometry *OGRGeometry::ConvexHull() const
 
         if( hGeosHull != NULL )
         {
-            poHullOGRGeom = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosHull);
-            if( poHullOGRGeom != NULL && getSpatialReference() != NULL )
-                poHullOGRGeom->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosHull);
+            if( poOGRProduct != NULL && getSpatialReference() != NULL )
+                poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosHull);
         }
     }
     freeGEOSContext( hGEOSCtxt );
 
-    return poHullOGRGeom;
+    return poOGRProduct;
 
 #endif /* HAVE_GEOS */
 }
@@ -2251,6 +2709,7 @@ OGRGeometry *OGRGeometry::Boundary() const
             poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosProduct);
             if( poOGRProduct != NULL && getSpatialReference() != NULL )
                 poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2382,6 +2841,7 @@ OGRGeometry *OGRGeometry::Buffer( double dfDist, int nQuadSegs ) const
             poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosProduct);
             if( poOGRProduct != NULL && getSpatialReference() != NULL )
                 poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2491,6 +2951,7 @@ OGRGeometry *OGRGeometry::Intersection( const OGRGeometry *poOtherGeom ) const
             {
                 poOGRProduct->assignSpatialReference(getSpatialReference());
             }
+            poOGRProduct = OGRGeometryRebuildCurves(this, poOtherGeom, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2591,6 +3052,7 @@ OGRGeometry *OGRGeometry::Union( const OGRGeometry *poOtherGeom ) const
             {
                 poOGRProduct->assignSpatialReference(getSpatialReference());
             }
+            poOGRProduct = OGRGeometryRebuildCurves(this, poOtherGeom, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2679,6 +3141,7 @@ OGRGeometry *OGRGeometry::UnionCascaded() const
             poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt, hGeosProduct);
             if( poOGRProduct != NULL && getSpatialReference() != NULL )
                 poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2772,6 +3235,7 @@ OGRGeometry *OGRGeometry::Difference( const OGRGeometry *poOtherGeom ) const
             {
                 poOGRProduct->assignSpatialReference(getSpatialReference());
             }
+            poOGRProduct = OGRGeometryRebuildCurves(this, poOtherGeom, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -2875,6 +3339,7 @@ OGRGeometry::SymDifference( const OGRGeometry *poOtherGeom ) const
             {
                 poOGRProduct->assignSpatialReference(getSpatialReference());
             }
+            poOGRProduct = OGRGeometryRebuildCurves(this, poOtherGeom, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -3770,6 +4235,7 @@ OGRGeometry *OGRGeometry::Simplify(double dTolerance) const
             poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt,  hGeosProduct );
             if( poOGRProduct != NULL && getSpatialReference() != NULL )
                 poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -3855,6 +4321,7 @@ OGRGeometry *OGRGeometry::SimplifyPreserveTopology(double dTolerance) const
             poOGRProduct = OGRGeometryFactory::createFromGEOS(hGEOSCtxt,  hGeosProduct );
             if( poOGRProduct != NULL && getSpatialReference() != NULL )
                 poOGRProduct->assignSpatialReference(getSpatialReference());
+            poOGRProduct = OGRGeometryRebuildCurves(this, NULL, poOGRProduct);
             GEOSGeom_destroy_r( hGEOSCtxt, hGeosProduct );
         }
     }
@@ -4160,7 +4627,8 @@ int OGRPreparedGeometryIntersects( const OGRPreparedGeometry* poPreparedGeom,
 #define WKBSRIDFLAG 0x20000000
 #define WKBBBOXFLAG 0x10000000
 
-OGRGeometry *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID )
+OGRGeometry *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID,
+                                  int bIsPostGIS1_EWKB )
 
 {
     OGRGeometry *poGeometry = NULL;
@@ -4218,7 +4686,8 @@ OGRGeometry *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID )
 /* -------------------------------------------------------------------- */
 /*      Try to ingest the geometry.                                     */
 /* -------------------------------------------------------------------- */
-    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLength );
+    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLength, 
+                                       (bIsPostGIS1_EWKB) ? wkbVariantPostGIS1 : wkbVariantOldOgc );
 
     return poGeometry;
 }
@@ -4227,7 +4696,8 @@ OGRGeometry *OGRGeometryFromEWKB( GByte *pabyWKB, int nLength, int* pnSRID )
 /*                     OGRGeometryFromHexEWKB()                         */
 /************************************************************************/
 
-OGRGeometry *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID )
+OGRGeometry *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID,
+                                     int bIsPostGIS1_EWKB  )
 
 {
     GByte   *pabyWKB;
@@ -4239,7 +4709,7 @@ OGRGeometry *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID )
 
     pabyWKB = CPLHexToBinary(pszBytea, &nWKBLength);
 
-    poGeometry = OGRGeometryFromEWKB(pabyWKB, nWKBLength, pnSRID);
+    poGeometry = OGRGeometryFromEWKB(pabyWKB, nWKBLength, pnSRID, bIsPostGIS1_EWKB);
 
     CPLFree(pabyWKB);
 
@@ -4250,7 +4720,8 @@ OGRGeometry *OGRGeometryFromHexEWKB( const char *pszBytea, int* pnSRID )
 /*                       OGRGeometryToHexEWKB()                         */
 /************************************************************************/
 
-char* OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId )
+char* OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId,
+                            int bIsPostGIS1_EWKB  )
 {
     GByte       *pabyWKB;
     char        *pszTextBuf;
@@ -4260,7 +4731,8 @@ char* OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId )
     int nWkbSize = poGeometry->WkbSize();
     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
 
-    if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
+    if( poGeometry->exportToWkb( wkbNDR, pabyWKB,
+            bIsPostGIS1_EWKB ? wkbVariantPostGIS1 : wkbVariantOldOgc ) != OGRERR_NONE )
     {
         CPLFree( pabyWKB );
         return CPLStrdup("");
@@ -4320,3 +4792,580 @@ char* OGRGeometryToHexEWKB( OGRGeometry * poGeometry, int nSRSId )
 
     return pszTextBuf;
 }
+
+/**
+ * \fn void OGRGeometry::segmentize(double dfMaxLength);
+ *
+ * \brief Add intermediate vertices to a geometry.
+ *
+ * This method modifies the geometry to add intermediate vertices if necessary
+ * so that the maximum length between 2 consecutives vertices is lower than
+ * dfMaxLength.
+ *
+ * @param dfMaxLength maximum length between 2 consecutives vertices.
+ */
+
+
+/************************************************************************/
+/*                       importPreambuleFromWkb()                       */
+/************************************************************************/
+
+OGRErr OGRGeometry::importPreambuleFromWkb( unsigned char * pabyData,
+                                            int nSize,
+                                            OGRwkbByteOrder& eByteOrder,
+                                            OGRBoolean& b3D,
+                                            OGRwkbVariant eWkbVariant )
+{
+    if( nSize < 9 && nSize != -1 )
+        return OGRERR_NOT_ENOUGH_DATA;
+
+/* -------------------------------------------------------------------- */
+/*      Get the byte order byte.                                        */
+/* -------------------------------------------------------------------- */
+    eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
+    if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
+        return OGRERR_CORRUPT_DATA;
+
+/* -------------------------------------------------------------------- */
+/*      Get the geometry feature type.                                  */
+/* -------------------------------------------------------------------- */
+    OGRwkbGeometryType eGeometryType;
+    OGRErr err = OGRReadWKBGeometryType( pabyData, eWkbVariant, &eGeometryType, &b3D );
+
+    if( err != OGRERR_NONE || eGeometryType != wkbFlatten(getGeometryType()) )
+        return OGRERR_CORRUPT_DATA;
+
+    return -1;
+}
+
+/************************************************************************/
+/*                    importPreambuleOfCollectionFromWkb()              */
+/*                                                                      */
+/*      Utility method for OGRSimpleCurve, OGRCompoundCurve,            */
+/*      OGRCurvePolygon and OGRGeometryCollection.                      */
+/************************************************************************/
+
+OGRErr OGRGeometry::importPreambuleOfCollectionFromWkb( unsigned char * pabyData,
+                                                        int& nSize,
+                                                        int& nDataOffset,
+                                                        OGRwkbByteOrder& eByteOrder,
+                                                        int nMinSubGeomSize,
+                                                        int& nGeomCount,
+                                                        OGRwkbVariant eWkbVariant )
+{
+    nGeomCount = 0;
+    OGRBoolean b3D = FALSE;
+
+    OGRErr eErr = importPreambuleFromWkb( pabyData, nSize, eByteOrder, b3D, eWkbVariant );
+    if( eErr >= 0 )
+        return eErr;
+
+/* -------------------------------------------------------------------- */
+/*      Clear existing Geoms.                                           */
+/* -------------------------------------------------------------------- */
+    empty();
+
+    if( b3D )
+        setCoordinateDimension(3);
+
+/* -------------------------------------------------------------------- */
+/*      Get the sub-geometry count.                                     */
+/* -------------------------------------------------------------------- */
+    memcpy( &nGeomCount, pabyData + 5, 4 );
+    
+    if( OGR_SWAP( eByteOrder ) )
+        nGeomCount = CPL_SWAP32(nGeomCount);
+
+    if (nGeomCount < 0 || nGeomCount > INT_MAX / 4)
+    {
+        nGeomCount = 0;
+        return OGRERR_CORRUPT_DATA;
+    }
+
+    /* Each ring has a minimum of nMinSubGeomSize bytes */
+    if (nSize != -1 && nSize - 9 < nGeomCount * nMinSubGeomSize)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "Length of input WKB is too small" );
+        nGeomCount = 0;
+        return OGRERR_NOT_ENOUGH_DATA;
+    }
+
+    nDataOffset = 9;
+    if( nSize != -1 )
+        nSize -= nDataOffset;
+
+    return -1;
+}
+
+/************************************************************************/
+/*                      importCurveCollectionFromWkt()                  */
+/*                                                                      */
+/*      Utility method for OGRCompoundCurve, OGRCurvePolygon and        */
+/*      OGRMultiCurve.                                                  */
+/************************************************************************/
+
+OGRErr OGRGeometry::importCurveCollectionFromWkt( char ** ppszInput,
+                                                  int bAllowEmptyComponent,
+                                                  int bAllowLineString,
+                                                  int bAllowCurve,
+                                                  int bAllowCompoundCurve,
+                                                  OGRErr (*pfnAddCurveDirectly)(OGRGeometry* poSelf, OGRCurve* poCurve) )
+
+{
+    int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
+
+    if( bHasZ )
+        setCoordinateDimension(3);
+
+    char        szToken[OGR_WKT_TOKEN_MAX];
+    const char  *pszInput = *ppszInput;
+    eErr = OGRERR_NONE;
+
+    /* Skip first '(' */
+    pszInput = OGRWktReadToken( pszInput, szToken );
+
+/* ==================================================================== */
+/*      Read each curve in turn.   Note that we try to reuse the same   */
+/*      point list buffer from curve to curve to cut down on            */
+/*      allocate/deallocate overhead.                                   */
+/* ==================================================================== */
+    OGRRawPoint *paoPoints = NULL;
+    int          nMaxPoints = 0;
+    double      *padfZ = NULL;
+
+    do
+    {
+
+    /* -------------------------------------------------------------------- */
+    /*      Get the first token, which should be the geometry type.         */
+    /* -------------------------------------------------------------------- */
+        const char* pszInputBefore = pszInput;
+        pszInput = OGRWktReadToken( pszInput, szToken );
+
+    /* -------------------------------------------------------------------- */
+    /*      Do the import.                                                  */
+    /* -------------------------------------------------------------------- */
+        OGRCurve* poCurve = NULL;
+        if (EQUAL(szToken,"("))
+        {
+            OGRLineString* poLine = new OGRLineString();
+            poCurve = poLine;
+            pszInput = pszInputBefore;
+            eErr = poLine->importFromWKTListOnly( (char**)&pszInput, bHasZ, bHasM,
+                                                   paoPoints, nMaxPoints, padfZ );
+        }
+        else if (bAllowEmptyComponent && EQUAL(szToken, "EMPTY") )
+        {
+            poCurve = new OGRLineString();
+        }
+        /* We accept LINESTRING() but this is an extension to the BNF, also */
+        /* accepted by PostGIS */
+        else if ( (bAllowLineString && EQUAL(szToken,"LINESTRING")) ||
+                  (bAllowCurve && !EQUAL(szToken,"LINESTRING") &&
+                   !EQUAL(szToken,"COMPOUNDCURVE") && OGR_GT_IsCurve(OGRFromOGCGeomType(szToken))) ||
+                  (bAllowCompoundCurve && EQUAL(szToken,"COMPOUNDCURVE")) )
+        {
+            OGRGeometry* poGeom = NULL;
+            pszInput = pszInputBefore;
+            eErr = OGRGeometryFactory::createFromWkt( (char **) &pszInput,
+                                                       NULL, &poGeom );
+            poCurve = (OGRCurve*) poGeom;
+        }
+        else
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s", szToken);
+            eErr = OGRERR_CORRUPT_DATA;
+        }
+
+        if( eErr == OGRERR_NONE )
+            eErr = pfnAddCurveDirectly( this, poCurve );
+        if( eErr != OGRERR_NONE )
+        {
+            delete poCurve;
+            break;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Read the delimeter following the surface.                       */
+/* -------------------------------------------------------------------- */
+        pszInput = OGRWktReadToken( pszInput, szToken );
+
+    } while( szToken[0] == ',' && eErr == OGRERR_NONE );
+
+    CPLFree( paoPoints );
+    CPLFree( padfZ );
+
+/* -------------------------------------------------------------------- */
+/*      freak if we don't get a closing bracket.                        */
+/* -------------------------------------------------------------------- */
+
+    if( eErr != OGRERR_NONE )
+        return eErr;
+
+    if( szToken[0] != ')' )
+        return OGRERR_CORRUPT_DATA;
+    
+    *ppszInput = (char *) pszInput;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                          OGR_GT_Flatten()                            */
+/************************************************************************/
+/**
+ * \brief Returns the 2D geometry type corresponding to the passed geometry type.
+ *
+ * This function is intended to work with geometry types as old-style 99-402
+ * extended dimension (Z) WKB types, as well as with newer SFSQL 1.2 and
+ * ISO SQL/MM Part 3 extended dimension (Z&M) WKB types.
+ *
+ * @param eType Input geometry type
+ *
+ * @return 2D geometry type corresponding to the passed geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_Flatten( OGRwkbGeometryType eType )
+{
+    eType = (OGRwkbGeometryType) (eType & (~wkb25DBitInternalUse));
+    if( eType >= 1001 && eType < 2000 ) /* ISO Z */
+        return (OGRwkbGeometryType) (eType - 1000);
+    if( eType >= 2000 && eType < 3000 ) /* ISO M */
+        return (OGRwkbGeometryType) (eType - 2000);
+    if( eType >= 3000 && eType < 4000 ) /* ISO ZM */
+        return (OGRwkbGeometryType) (eType - 3000);
+    return eType;
+}
+
+/************************************************************************/
+/*                          OGR_GT_HasZ()                               */
+/************************************************************************/
+/**
+ * \brief Return if the geometry type is a 3D geometry type.
+ *
+ * @param eType Input geometry type
+ *
+ * @return TRUE if the geometry type is a 3D geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_GT_HasZ( OGRwkbGeometryType eType )
+{
+    if( eType & wkb25DBitInternalUse )
+        return TRUE;
+    if( eType >= 1001 && eType < 2000 )
+        return TRUE;
+    return FALSE;
+}
+
+/************************************************************************/
+/*                           OGR_GT_SetZ()                              */
+/************************************************************************/
+/**
+ * \brief Returns the 3D geometry type corresponding to the passed geometry type.
+ *
+ * @param eType Input geometry type
+ *
+ * @return 3D geometry type corresponding to the passed geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_SetZ( OGRwkbGeometryType eType )
+{
+    if( OGR_GT_HasZ(eType) || eType == wkbNone )
+        return eType;
+    if( eType >= wkbUnknown && eType <= wkbGeometryCollection )
+        return (OGRwkbGeometryType)(eType | wkb25DBitInternalUse);
+    else
+        return (OGRwkbGeometryType)(eType + 1000);
+}
+
+/************************************************************************/
+/*                        OGR_GT_SetModifier()                          */
+/************************************************************************/
+/**
+ * \brief Returns a 2D or 3D geometry type depending on parameter.
+ *
+ * @param eType Input geometry type
+ * @param bHasZ TRUE if the output geometry type must be 3D.
+ * @param bHasM Must be set to FALSE currently.
+ *
+ * @return Output geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_SetModifier( OGRwkbGeometryType eType, int bHasZ,
+                                       CPL_UNUSED int bHasM )
+{
+    if( bHasZ )
+        return OGR_GT_SetZ(eType);
+    else
+        return wkbFlatten(eType);
+}
+
+/************************************************************************/
+/*                        OGR_GT_IsSubClassOf)                          */
+/************************************************************************/
+/**
+ * \brief Returns if a type is a subclass of another one
+ *
+ * @param eType Type.
+ * @param eSuperType Super type
+ *
+ * @return TRUE if eType is a subclass of eSuperType.
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_GT_IsSubClassOf( OGRwkbGeometryType eType,
+                         OGRwkbGeometryType eSuperType )
+{
+    eSuperType = wkbFlatten(eSuperType);
+    eType = wkbFlatten(eType);
+
+    if( eSuperType == eType || eSuperType == wkbUnknown )
+        return TRUE;
+
+    if( eSuperType == wkbGeometryCollection )
+        return eType == wkbMultiPoint || eType == wkbMultiLineString ||
+               eType == wkbMultiPolygon || eType == wkbMultiCurve ||
+               eType == wkbMultiSurface;
+
+    if( eSuperType == wkbCurvePolygon )
+        return eType == wkbPolygon;
+
+    if( eSuperType == wkbMultiCurve )
+        return eType == wkbMultiLineString;
+
+    if( eSuperType == wkbMultiSurface )
+        return eType == wkbMultiPolygon;
+
+    if( eSuperType == wkbCurve )
+        return eType == wkbLineString || eType == wkbCircularString ||
+               eType == wkbCompoundCurve;
+
+    if( eSuperType == wkbSurface )
+        return eType == wkbCurvePolygon || eType == wkbPolygon;
+
+    return FALSE;
+}
+
+/************************************************************************/
+/*                       OGR_GT_GetCollection()                         */
+/************************************************************************/
+/**
+ * \brief Returns the collection type that can contain the passed geometry type
+ *
+ * Handled conversions are : wkbNone->wkbNone, wkbPoint -> wkbMultiPoint,
+ * wkbLineString->wkbMultiLineString, wkbPolygon->wkbMultiPolygon,
+ * wkbCircularString->wkbMultiCurve, wkbCompoundCurve->wkbMultiCurve,
+ * wkbCurvePolygon->wkbMultiSurface.
+ * In other cases, wkbUnknown is returned
+ *
+ * Passed Z flag is preserved.
+ *
+ * @param eType Input geometry type
+ *
+ * @return the collection type that can contain the passed geometry type or wkbUnknown
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_GetCollection( OGRwkbGeometryType eType )
+{
+    if( eType == wkbNone )
+        return wkbNone;
+    OGRwkbGeometryType eFGType = wkbFlatten(eType);
+    if( eFGType == wkbPoint )
+        eType = wkbMultiPoint;
+
+    else if( eFGType == wkbLineString )
+        eType = wkbMultiLineString;
+
+    else if( eFGType == wkbPolygon )
+        eType = wkbMultiPolygon;
+
+    else if( OGR_GT_IsCurve(eFGType) )
+        eType = wkbMultiCurve;
+
+    else if( OGR_GT_IsSurface(eFGType) )
+        eType = wkbMultiSurface;
+    
+    else
+        return wkbUnknown;
+
+    if( wkbHasZ(eType) )
+        eType = wkbSetZ(eType);
+
+    return eType;
+}
+
+/************************************************************************/
+/*                        OGR_GT_GetCurve()                             */
+/************************************************************************/
+/**
+ * \brief Returns the curve geometry type that can contain the passed geometry type
+ *
+ * Handled conversions are : wkbPolygon -> wkbCurvePolygon,
+ * wkbLineString->wkbCompoundCurve, wkbMultiPolygon->wkbMultiSurface
+ * and wkbMultiLineString->wkbMultiCurve.
+ * In other cases, the passed geometry is returned.
+ *
+ * Passed Z flag is preserved.
+ *
+ * @param eType Input geometry type
+ *
+ * @return the curve type that can contain the passed geometry type
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_GetCurve( OGRwkbGeometryType eType )
+{
+    OGRwkbGeometryType eFGType = wkbFlatten(eType);
+
+    if( eFGType == wkbLineString )
+        eType = wkbCompoundCurve;
+
+    else if( eFGType == wkbPolygon )
+        eType = wkbCurvePolygon;
+
+    else if( eFGType == wkbMultiLineString )
+        eType = wkbMultiCurve;
+
+    else if( eFGType == wkbMultiPolygon )
+        eType = wkbMultiSurface;
+
+    if( wkbHasZ(eType) )
+        eType = wkbSetZ(eType);
+
+    return eType;
+}
+
+/************************************************************************/
+/*                        OGR_GT_GetLinear()                          */
+/************************************************************************/
+/**
+ * \brief Returns the non-curve geometry type that can contain the passed geometry type
+ *
+ * Handled conversions are : wkbCurvePolygon -> wkbPolygon,
+ * wkbCircularString->wkbLineString, wkbCompoundCurve->wkbLineString,
+ * wkbMultiSurface->wkbMultiPolygon and wkbMultiCurve->wkbMultiLineString.
+ * In other cases, the passed geometry is returned.
+ *
+ * Passed Z flag is preserved.
+ *
+ * @param eType Input geometry type
+ *
+ * @return the non-curve type that can contain the passed geometry type
+ *
+ * @since GDAL 2.0
+ */
+
+OGRwkbGeometryType OGR_GT_GetLinear( OGRwkbGeometryType eType )
+{
+    OGRwkbGeometryType eFGType = wkbFlatten(eType);
+
+    if( OGR_GT_IsCurve(eFGType) )
+        eType = wkbLineString;
+
+    else if( OGR_GT_IsSurface(eFGType) )
+        eType = wkbPolygon;
+
+    else if( eFGType == wkbMultiCurve )
+        eType = wkbMultiLineString;
+
+    else if( eFGType == wkbMultiSurface )
+        eType = wkbMultiPolygon;
+
+    if( wkbHasZ(eType) )
+        eType = wkbSetZ(eType);
+
+    return eType;
+}
+
+/************************************************************************/
+/*                           OGR_GT_IsCurve()                           */
+/************************************************************************/
+
+/**
+ * \brief Return if a geometry type is an instance of Curve
+ *
+ * Such geometry type are wkbLineString, wkbCircularString, wkbCompoundCurve
+ * and their 3D variant.
+ *
+ * @param eGeomType the geometry type
+ * @return TRUE if the geometry type is an instance of Curve
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_GT_IsCurve( OGRwkbGeometryType eGeomType )
+{
+    return OGR_GT_IsSubClassOf( eGeomType, wkbCurve );
+}
+
+/************************************************************************/
+/*                         OGR_GT_IsSurface()                           */
+/************************************************************************/
+
+/**
+ * \brief Return if a geometry type is an instance of Surface
+ *
+ * Such geometry type are wkbCurvePolygon and wkbPolygon
+ * and their 3D variant.
+ *
+ * @param eGeomType the geometry type
+ * @return TRUE if the geometry type is an instance of Surface
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_GT_IsSurface( OGRwkbGeometryType eGeomType )
+{
+    return OGR_GT_IsSubClassOf( eGeomType, wkbSurface );
+}
+
+/************************************************************************/
+/*                          OGR_GT_IsNonLinear()                        */
+/************************************************************************/
+
+/**
+ * \brief Return if a geometry type is a non-linear geometry type.
+ *
+ * Such geometry type are wkbCircularString, wkbCompoundCurve, wkbCurvePolygon,
+ * wkbMultiCurve, wkbMultiSurface and their 3D variant.
+ *
+ * @param eGeomType the geometry type
+ * @return TRUE if the geometry type is a non-linear geometry type.
+ *
+ * @since GDAL 2.0
+ */
+
+int OGR_GT_IsNonLinear( OGRwkbGeometryType eGeomType )
+{
+    OGRwkbGeometryType eFGeomType = wkbFlatten(eGeomType);
+    return eFGeomType == wkbCircularString || eFGeomType == wkbCompoundCurve ||
+           eFGeomType == wkbCurvePolygon || eFGeomType == wkbMultiCurve ||
+           eFGeomType == wkbMultiSurface;
+}
+
+/************************************************************************/
+/*                          CastToError()                               */
+/************************************************************************/
+
+OGRGeometry* OGRGeometry::CastToError(OGRGeometry* poGeom)
+{
+    CPLError(CE_Failure, CPLE_AppDefined,
+             "%s found. Conversion impossible", poGeom->getGeometryName());
+    delete poGeom;
+    return NULL;
+}
diff --git a/ogr/ogrgeometrycollection.cpp b/ogr/ogrgeometrycollection.cpp
index 57a1233..965a4bb 100644
--- a/ogr/ogrgeometrycollection.cpp
+++ b/ogr/ogrgeometrycollection.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeometrycollection.cpp 27610 2014-08-27 15:47:43Z rouault $
+ * $Id: ogrgeometrycollection.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRGeometryCollection class.
@@ -30,8 +30,9 @@
 
 #include "ogr_geometry.h"
 #include "ogr_p.h"
+#include "ogr_api.h"
 
-CPL_CVSID("$Id: ogrgeometrycollection.cpp 27610 2014-08-27 15:47:43Z rouault $");
+CPL_CVSID("$Id: ogrgeometrycollection.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                       OGRGeometryCollection()                        */
@@ -79,7 +80,6 @@ void OGRGeometryCollection::empty()
     nCoordDimension = 2;
 }
 
-
 /************************************************************************/
 /*                               clone()                                */
 /************************************************************************/
@@ -89,7 +89,8 @@ OGRGeometry *OGRGeometryCollection::clone() const
 {
     OGRGeometryCollection       *poNewGC;
 
-    poNewGC = new OGRGeometryCollection;
+    poNewGC = (OGRGeometryCollection*)
+            OGRGeometryFactory::createGeometry(getGeometryType());
     poNewGC->assignSpatialReference( getSpatialReference() );
 
     for( int i = 0; i < nGeomCount; i++ )
@@ -282,6 +283,14 @@ OGRErr OGRGeometryCollection::addGeometry( const OGRGeometry * poNewGeom )
 OGRErr OGRGeometryCollection::addGeometryDirectly( OGRGeometry * poNewGeom )
 
 {
+    if( !isCompatibleSubType(poNewGeom->getGeometryType()) )
+        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
+
+    if( poNewGeom->getCoordinateDimension() == 3 && getCoordinateDimension() != 3 )
+        setCoordinateDimension(3);
+    else if( poNewGeom->getCoordinateDimension() != 3 && getCoordinateDimension() == 3 )
+        poNewGeom->setCoordinateDimension(3);
+
     papoGeoms = (OGRGeometry **) OGRRealloc( papoGeoms,
                                              sizeof(void*) * (nGeomCount+1) );
 
@@ -289,9 +298,6 @@ OGRErr OGRGeometryCollection::addGeometryDirectly( OGRGeometry * poNewGeom )
 
     nGeomCount++;
 
-    if( poNewGeom->getCoordinateDimension() == 3 )
-        nCoordDimension = 3;
-
     return OGRERR_NONE;
 }
 
@@ -370,7 +376,8 @@ int OGRGeometryCollection::WkbSize() const
 /************************************************************************/
 
 OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
-                                                     int nSize, int nRecLevel )
+                                                     int nSize, int nRecLevel,
+                                                     OGRwkbVariant eWkbVariant )
 
 {
     OGRwkbByteOrder     eByteOrder;
@@ -384,57 +391,17 @@ OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
                     nRecLevel );
         return OGRERR_CORRUPT_DATA;
     }
-    
-    if( nSize < 9 && nSize != -1 )
-        return OGRERR_NOT_ENOUGH_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the byte order byte.                                        */
-/* -------------------------------------------------------------------- */
-    eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
-    if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the geometry feature type.  For now we assume that          */
-/*      geometry type is between 0 and 255 so we only have to fetch     */
-/*      one byte.                                                       */
-/* -------------------------------------------------------------------- */
-
-    OGRBoolean b3D;
-    OGRwkbGeometryType eGeometryType;
-    OGRErr err = OGRReadWKBGeometryType( pabyData, &eGeometryType, &b3D );
-
-    if ( err != OGRERR_NONE || eGeometryType != wkbFlatten(getGeometryType()) )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Clear existing Geoms.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
-    
-/* -------------------------------------------------------------------- */
-/*      Get the geometry count.                                         */
-/* -------------------------------------------------------------------- */
-    memcpy( &nGeomCount, pabyData + 5, 4 );
-    
-    if( OGR_SWAP( eByteOrder ) )
-        nGeomCount = CPL_SWAP32(nGeomCount);
-
-    if (nGeomCount < 0 || nGeomCount > INT_MAX / 9)
-    {
-        nGeomCount = 0;
-        return OGRERR_CORRUPT_DATA;
-    }
 
-    /* Each geometry has a minimum of 9 bytes */
-    if (nSize != -1 && nSize - 9 < nGeomCount * 9)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Length of input WKB is too small" );
-        nGeomCount = 0;
-        return OGRERR_NOT_ENOUGH_DATA;
-    }
+    nGeomCount = 0;
+    OGRErr eErr = importPreambuleOfCollectionFromWkb( pabyData,
+                                                      nSize,
+                                                      nDataOffset,
+                                                      eByteOrder,
+                                                      9,
+                                                      nGeomCount,
+                                                      eWkbVariant );
+    if( eErr >= 0 )
+        return eErr;
 
     papoGeoms = (OGRGeometry **) VSIMalloc2(sizeof(void*), nGeomCount);
     if (nGeomCount != 0 && papoGeoms == NULL)
@@ -443,10 +410,6 @@ OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
         return OGRERR_NOT_ENOUGH_MEMORY;
     }
 
-    nDataOffset = 9;
-    if( nSize != -1 )
-        nSize -= nDataOffset;
-
 /* -------------------------------------------------------------------- */
 /*      Get the Geoms.                                                  */
 /* -------------------------------------------------------------------- */
@@ -459,53 +422,39 @@ OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
         unsigned char* pabySubData = pabyData + nDataOffset;
         if( nSize < 9 && nSize != -1 )
             return OGRERR_NOT_ENOUGH_DATA;
-        OGRwkbByteOrder eSubGeomByteOrder =
-            DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabySubData);
-
-        if( eSubGeomByteOrder != wkbXDR && eSubGeomByteOrder != wkbNDR )
-            return OGRERR_CORRUPT_DATA;
 
         OGRwkbGeometryType eSubGeomType;
         OGRBoolean bIs3D;
-        if ( OGRReadWKBGeometryType( pabySubData, &eSubGeomType, &bIs3D ) != OGRERR_NONE )
-            return OGRERR_FAILURE;
+        eErr = OGRReadWKBGeometryType( pabySubData, eWkbVariant, &eSubGeomType, &bIs3D );
+        if( eErr != OGRERR_NONE )
+            return eErr;
 
-        if( eSubGeomType == wkbPoint ||
-            eSubGeomType == wkbLineString ||
-            eSubGeomType == wkbPolygon)
+        if( !isCompatibleSubType(eSubGeomType) )
         {
-            eErr = OGRGeometryFactory::
-                createFromWkb( pabySubData, NULL,
-                               &poSubGeom, nSize );
+            nGeomCount = iGeom;
+            CPLDebug("OGR", "Cannot add geometry of type (%d) to geometry of type (%d)",
+                     eSubGeomType, getGeometryType());
+            return OGRERR_CORRUPT_DATA;
         }
-        else if (eSubGeomType == wkbGeometryCollection ||
-                 eSubGeomType == wkbMultiPolygon ||
-                 eSubGeomType == wkbMultiPoint ||
-                 eSubGeomType == wkbMultiLineString)
+
+        if( OGR_GT_IsSubClassOf(eSubGeomType, wkbGeometryCollection) )
         {
             poSubGeom = OGRGeometryFactory::createGeometry( eSubGeomType );
             eErr = ((OGRGeometryCollection*)poSubGeom)->
-                        importFromWkbInternal( pabySubData, nSize, nRecLevel + 1 );
+                        importFromWkbInternal( pabySubData, nSize, nRecLevel + 1, eWkbVariant );
         }
         else
-            return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-
-        if( eErr != OGRERR_NONE )
         {
-            nGeomCount = iGeom;
-            delete poSubGeom;
-            return eErr;
+            eErr = OGRGeometryFactory::
+                createFromWkb( pabySubData, NULL,
+                               &poSubGeom, nSize, eWkbVariant );
         }
 
-        if( (eGeometryType == wkbMultiPoint && eSubGeomType != wkbPoint) ||
-            (eGeometryType == wkbMultiLineString && eSubGeomType != wkbLineString) ||
-            (eGeometryType == wkbMultiPolygon && eSubGeomType != wkbPolygon) )
+        if( eErr != OGRERR_NONE )
         {
             nGeomCount = iGeom;
-            CPLDebug("OGR", "Cannot add geometry of type (%d) to geometry of type (%d)",
-                     eSubGeomType, eGeometryType);
             delete poSubGeom;
-            return OGRERR_CORRUPT_DATA;
+            return eErr;
         }
 
         papoGeoms[iGeom] = poSubGeom;
@@ -519,7 +468,7 @@ OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
 
         nDataOffset += nSubGeomWkbSize;
     }
-    
+
     return OGRERR_NONE;
 }
 
@@ -531,10 +480,11 @@ OGRErr OGRGeometryCollection::importFromWkbInternal( unsigned char * pabyData,
 /************************************************************************/
 
 OGRErr OGRGeometryCollection::importFromWkb( unsigned char * pabyData,
-                                             int nSize )
+                                             int nSize,
+                                             OGRwkbVariant eWkbVariant )
 
 {
-    return importFromWkbInternal(pabyData, nSize, 0);
+    return importFromWkbInternal(pabyData, nSize, 0, eWkbVariant);
 }
 
 /************************************************************************/
@@ -550,6 +500,13 @@ OGRErr  OGRGeometryCollection::exportToWkb( OGRwkbByteOrder eByteOrder,
 {
     int         nOffset;
     
+    if( eWkbVariant == wkbVariantOldOgc &&
+        (wkbFlatten(getGeometryType()) == wkbMultiCurve ||
+         wkbFlatten(getGeometryType()) == wkbMultiSurface) ) /* does not make sense for new geometries, so patch it */
+    {
+        eWkbVariant = wkbVariantIso;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Set the byte order.                                             */
 /* -------------------------------------------------------------------- */
@@ -563,6 +520,17 @@ OGRErr  OGRGeometryCollection::exportToWkb( OGRwkbByteOrder eByteOrder,
     
     if ( eWkbVariant == wkbVariantIso )
         nGType = getIsoGeometryType();
+    else if( eWkbVariant == wkbVariantPostGIS1 )
+    {
+        int bIs3D = wkbHasZ((OGRwkbGeometryType)nGType);
+        nGType = wkbFlatten(nGType);
+        if( nGType == wkbMultiCurve )
+            nGType = POSTGIS15_MULTICURVE;
+        else if( nGType == wkbMultiSurface )
+            nGType = POSTGIS15_MULTISURFACE;
+        if( bIs3D )
+            nGType = (OGRwkbGeometryType)(nGType | wkb25DBitInternalUse); /* yes we explicitely set wkb25DBit */
+    }
     
     if( eByteOrder == wkbNDR )
         nGType = CPL_LSBWORD32( nGType );
@@ -608,11 +576,6 @@ OGRErr  OGRGeometryCollection::exportToWkb( OGRwkbByteOrder eByteOrder,
 OGRErr OGRGeometryCollection::importFromWktInternal( char ** ppszInput, int nRecLevel )
 
 {
-
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-
-
     /* Arbitrary value, but certainly large enough for reasonable usages ! */
     if( nRecLevel == 32 )
     {
@@ -622,86 +585,13 @@ OGRErr OGRGeometryCollection::importFromWktInternal( char ** ppszInput, int nRec
         return OGRERR_CORRUPT_DATA;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Clear existing Geoms.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the type keyword, and ensure it matches the     */
-/*      actual type of this container.                                  */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,getGeometryName()) )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ...                                             */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
     int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
 
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
-
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style GEOMETRYCOLLECTION(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszInput = OGRWktReadToken( pszPreScan, szToken );
-
-            if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszInput;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
+    char        szToken[OGR_WKT_TOKEN_MAX];
+    const char  *pszInput = *ppszInput;
 
     /* Skip first '(' */
     pszInput = OGRWktReadToken( pszInput, szToken );
@@ -717,8 +607,7 @@ OGRErr OGRGeometryCollection::importFromWktInternal( char ** ppszInput, int nRec
     /* -------------------------------------------------------------------- */
     /*      Get the first token, which should be the geometry type.         */
     /* -------------------------------------------------------------------- */
-        if( OGRWktReadToken( pszInput, szToken ) == NULL )
-            return OGRERR_CORRUPT_DATA;
+        OGRWktReadToken( pszInput, szToken );
 
     /* -------------------------------------------------------------------- */
     /*      Do the import.                                                  */
@@ -733,10 +622,13 @@ OGRErr OGRGeometryCollection::importFromWktInternal( char ** ppszInput, int nRec
             eErr = OGRGeometryFactory::createFromWkt( (char **) &pszInput,
                                                        NULL, &poGeom );
 
+        if( eErr == OGRERR_NONE )
+            eErr = addGeometryDirectly( poGeom );
         if( eErr != OGRERR_NONE )
+        {
+            delete poGeom;
             return eErr;
-
-        addGeometryDirectly( poGeom );
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Read the delimeter following the ring.                          */
@@ -774,37 +666,75 @@ OGRErr OGRGeometryCollection::importFromWkt( char ** ppszInput )
 /*      equivelent.  This could be made alot more CPU efficient!        */
 /************************************************************************/
 
-OGRErr OGRGeometryCollection::exportToWkt( char ** ppszDstText ) const
+OGRErr OGRGeometryCollection::exportToWkt( char ** ppszDstText,
+                                           OGRwkbVariant eWkbVariant ) const
+{
+    return exportToWktInternal(ppszDstText, eWkbVariant, NULL);
+}
+
+OGRErr OGRGeometryCollection::exportToWktInternal( char ** ppszDstText,
+                                           OGRwkbVariant eWkbVariant,
+                                           const char* pszSkipPrefix ) const
 
 {
     char        **papszGeoms;
     int         iGeom, nCumulativeLength = 0;
     OGRErr      eErr;
-
-    if( getNumGeometries() == 0 )
-    {
-        *ppszDstText = CPLStrdup("GEOMETRYCOLLECTION EMPTY");
-        return OGRERR_NONE;
-    }
+    int bMustWriteComma = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Build a list of strings containing the stuff for each Geom.     */
 /* -------------------------------------------------------------------- */
-    papszGeoms = (char **) CPLCalloc(sizeof(char *),nGeomCount);
+    papszGeoms = (nGeomCount) ? (char **) CPLCalloc(sizeof(char *),nGeomCount) : NULL;
 
     for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
     {
-        eErr = papoGeoms[iGeom]->exportToWkt( &(papszGeoms[iGeom]) );
+        eErr = papoGeoms[iGeom]->exportToWkt( &(papszGeoms[iGeom]), eWkbVariant );
         if( eErr != OGRERR_NONE )
             goto error;
 
-        nCumulativeLength += strlen(papszGeoms[iGeom]);
+        int nSkip = 0;
+        if( pszSkipPrefix != NULL &&
+            EQUALN(papszGeoms[iGeom], pszSkipPrefix, strlen(pszSkipPrefix)) &&
+            papszGeoms[iGeom][strlen(pszSkipPrefix)] == ' ' )
+        {
+            nSkip = strlen(pszSkipPrefix) + 1;
+            if( EQUALN(papszGeoms[iGeom] + nSkip, "Z ", 2) )
+                nSkip += 2;
+
+            /* skip empty subgeoms */
+            if( papszGeoms[iGeom][nSkip] != '(' )
+            {
+                CPLDebug( "OGR", "OGRGeometryCollection::exportToWkt() - skipping %s.",
+                         papszGeoms[iGeom] );
+                CPLFree( papszGeoms[iGeom] );
+                papszGeoms[iGeom] = NULL;
+                continue;
+            }
+        }
+
+        nCumulativeLength += strlen(papszGeoms[iGeom] + nSkip);
     }
-    
+
+/* -------------------------------------------------------------------- */
+/*      Return XXXXXXXXXXXXXXX EMPTY if we get no valid line string.    */
+/* -------------------------------------------------------------------- */
+    if( nCumulativeLength == 0 )
+    {
+        CPLFree( papszGeoms );
+        CPLString osEmpty;
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            osEmpty.Printf("%s Z EMPTY",getGeometryName());
+        else
+            osEmpty.Printf("%s EMPTY",getGeometryName());
+        *ppszDstText = CPLStrdup(osEmpty);
+        return OGRERR_NONE;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Allocate the right amount of space for the aggregated string    */
 /* -------------------------------------------------------------------- */
-    *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nGeomCount + 23);
+    *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nGeomCount + 25);
 
     if( *ppszDstText == NULL )
     {
@@ -816,16 +746,32 @@ OGRErr OGRGeometryCollection::exportToWkt( char ** ppszDstText ) const
 /*      Build up the string, freeing temporary strings as we go.        */
 /* -------------------------------------------------------------------- */
     strcpy( *ppszDstText, getGeometryName() );
+    if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+        strcat( *ppszDstText, " Z" );
     strcat( *ppszDstText, " (" );
     nCumulativeLength = strlen(*ppszDstText);
 
     for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
-    {                                                           
-        if( iGeom > 0 )
+    {
+        if( papszGeoms[iGeom] == NULL )
+            continue;
+
+        if( bMustWriteComma )
             (*ppszDstText)[nCumulativeLength++] = ',';
-        
-        int nGeomLength = strlen(papszGeoms[iGeom]);
-        memcpy( *ppszDstText + nCumulativeLength, papszGeoms[iGeom], nGeomLength );
+        bMustWriteComma = TRUE;
+
+        int nSkip = 0;
+        if( pszSkipPrefix != NULL &&
+            EQUALN(papszGeoms[iGeom], pszSkipPrefix, strlen(pszSkipPrefix)) &&
+            papszGeoms[iGeom][strlen(pszSkipPrefix)] == ' ' )
+        {
+            nSkip = strlen(pszSkipPrefix) + 1;
+            if( EQUALN(papszGeoms[iGeom] + nSkip, "Z ", 2) )
+                nSkip += 2;
+        }
+
+        int nGeomLength = strlen(papszGeoms[iGeom] + nSkip);
+        memcpy( *ppszDstText + nCumulativeLength, papszGeoms[iGeom] + nSkip, nGeomLength );
         nCumulativeLength += nGeomLength;
         VSIFree( papszGeoms[iGeom] );
     }
@@ -851,39 +797,12 @@ error:
 void OGRGeometryCollection::getEnvelope( OGREnvelope * psEnvelope ) const
 
 {
-    OGREnvelope         oGeomEnv;
-    int                 bExtentSet = FALSE;
-
-    for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
-    {
-        if (!papoGeoms[iGeom]->IsEmpty())
-        {
-            if (!bExtentSet)
-            {
-                papoGeoms[iGeom]->getEnvelope( psEnvelope );
-                bExtentSet = TRUE;
-            }
-            else
-            {
-                papoGeoms[iGeom]->getEnvelope( &oGeomEnv );
-
-                if( psEnvelope->MinX > oGeomEnv.MinX )
-                    psEnvelope->MinX = oGeomEnv.MinX;
-                if( psEnvelope->MinY > oGeomEnv.MinY )
-                    psEnvelope->MinY = oGeomEnv.MinY;
-                if( psEnvelope->MaxX < oGeomEnv.MaxX )
-                    psEnvelope->MaxX = oGeomEnv.MaxX;
-                if( psEnvelope->MaxY < oGeomEnv.MaxY )
-                    psEnvelope->MaxY = oGeomEnv.MaxY;
-            }
-        }
-    }
-
-    if (!bExtentSet)
-    {
-        psEnvelope->MinX = psEnvelope->MinY = 0;
-        psEnvelope->MaxX = psEnvelope->MaxY = 0;
-    }
+    OGREnvelope3D         oEnv3D;
+    getEnvelope(&oEnv3D);
+    psEnvelope->MinX = oEnv3D.MinX;
+    psEnvelope->MinY = oEnv3D.MinY;
+    psEnvelope->MaxX = oEnv3D.MaxX;
+    psEnvelope->MaxY = oEnv3D.MaxY;
 }
 
 /************************************************************************/
@@ -908,20 +827,7 @@ void OGRGeometryCollection::getEnvelope( OGREnvelope3D * psEnvelope ) const
             else
             {
                 papoGeoms[iGeom]->getEnvelope( &oGeomEnv );
-
-                if( psEnvelope->MinX > oGeomEnv.MinX )
-                    psEnvelope->MinX = oGeomEnv.MinX;
-                if( psEnvelope->MinY > oGeomEnv.MinY )
-                    psEnvelope->MinY = oGeomEnv.MinY;
-                if( psEnvelope->MaxX < oGeomEnv.MaxX )
-                    psEnvelope->MaxX = oGeomEnv.MaxX;
-                if( psEnvelope->MaxY < oGeomEnv.MaxY )
-                    psEnvelope->MaxY = oGeomEnv.MaxY;
-
-                if( psEnvelope->MinZ > oGeomEnv.MinZ )
-                    psEnvelope->MinZ = oGeomEnv.MinZ;
-                if( psEnvelope->MaxZ < oGeomEnv.MaxZ )
-                    psEnvelope->MaxZ = oGeomEnv.MaxZ;
+                psEnvelope->Merge( oGeomEnv );
             }
         }
     }
@@ -1054,19 +960,15 @@ double OGRGeometryCollection::get_Length() const
     for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
     {
         OGRGeometry* geom = papoGeoms[iGeom];
-        switch( wkbFlatten(geom->getGeometryType()) )
+        OGRwkbGeometryType eType = wkbFlatten(geom->getGeometryType());
+        if( OGR_GT_IsCurve(eType) )
         {
-            case wkbLinearRing:
-            case wkbLineString:
-                dfLength += ((OGRCurve *) geom)->get_Length();
-                break;
-
-            case wkbGeometryCollection:
-                dfLength +=((OGRGeometryCollection *) geom)->get_Length();
-                break;
-
-            default:
-                break;
+            dfLength += ((OGRCurve *) geom)->get_Length();
+        }
+        else if( OGR_GT_IsSubClassOf(eType, wkbMultiCurve) ||
+                eType == wkbGeometryCollection )
+        {
+            dfLength += ((OGRGeometryCollection *) geom)->get_Length();
         }
     }
 
@@ -1095,33 +997,19 @@ double OGRGeometryCollection::get_Area() const
     for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
     {
         OGRGeometry* geom = papoGeoms[iGeom];
-        switch( wkbFlatten(geom->getGeometryType()) )
+        OGRwkbGeometryType eType = wkbFlatten(geom->getGeometryType());
+        if( OGR_GT_IsSurface(eType) )
         {
-            case wkbPolygon:
-                dfArea += ((OGRPolygon *) geom)->get_Area();
-                break;
-
-            case wkbMultiPolygon:
-                dfArea += ((OGRMultiPolygon *) geom)->get_Area();
-                break;
-
-            case wkbLinearRing:
-            case wkbLineString:
-                /* This test below is required to filter out wkbLineString geometries
-                * not being of type of wkbLinearRing.
-                */
-                if( EQUAL( ((OGRGeometry*) geom)->getGeometryName(), "LINEARRING" ) )
-                {
-                    dfArea += ((OGRLinearRing *) geom)->get_Area();
-                }
-                break;
-
-            case wkbGeometryCollection:
-                dfArea +=((OGRGeometryCollection *) geom)->get_Area();
-                break;
-
-            default:
-                break;
+            dfArea += ((OGRSurface *) geom)->get_Area();
+        }
+        else if( OGR_GT_IsCurve(eType) )
+        {
+            dfArea += ((OGRCurve *) geom)->get_Area();
+        }
+        else if( OGR_GT_IsSubClassOf(eType, wkbMultiSurface) ||
+                eType == wkbGeometryCollection )
+        {
+            dfArea += ((OGRGeometryCollection *) geom)->get_Area();
         }
     }
 
@@ -1159,3 +1047,89 @@ void OGRGeometryCollection::swapXY()
     for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
         papoGeoms[iGeom]->swapXY();
 }
+
+/************************************************************************/
+/*                          isCompatibleSubType()                       */
+/************************************************************************/
+
+OGRBoolean OGRGeometryCollection::isCompatibleSubType( OGRwkbGeometryType ) const
+{
+    /* We accept all geometries as sub-geometries */
+    return TRUE;
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRGeometryCollection::hasCurveGeometry(int bLookForNonLinear) const
+{
+    for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
+    {
+        if( papoGeoms[iGeom]->hasCurveGeometry(bLookForNonLinear) )
+            return TRUE;
+    }
+    return FALSE;
+}
+
+/************************************************************************/
+/*                         getLinearGeometry()                        */
+/************************************************************************/
+
+OGRGeometry* OGRGeometryCollection::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
+                                                        const char* const* papszOptions) const
+{
+    OGRGeometryCollection* poGC = (OGRGeometryCollection*)
+        OGRGeometryFactory::createGeometry(OGR_GT_GetLinear(getGeometryType()));
+    poGC->assignSpatialReference( getSpatialReference() );
+    for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
+    {
+        OGRGeometry* poSubGeom = papoGeoms[iGeom]->getLinearGeometry(dfMaxAngleStepSizeDegrees,
+                                                                       papszOptions);
+        poGC->addGeometryDirectly( poSubGeom );
+    }
+    return poGC;
+}
+
+/************************************************************************/
+/*                             getCurveGeometry()                       */
+/************************************************************************/
+
+OGRGeometry* OGRGeometryCollection::getCurveGeometry(const char* const* papszOptions) const
+{
+    OGRGeometryCollection* poGC = (OGRGeometryCollection*)
+        OGRGeometryFactory::createGeometry(OGR_GT_GetCurve(getGeometryType()));
+    poGC->assignSpatialReference( getSpatialReference() );
+    int bHasCurveGeometry = FALSE;
+    for( int iGeom = 0; iGeom < nGeomCount; iGeom++ )
+    {
+        OGRGeometry* poSubGeom = papoGeoms[iGeom]->getCurveGeometry(papszOptions);
+        if( poSubGeom->hasCurveGeometry() )
+            bHasCurveGeometry = TRUE;
+        poGC->addGeometryDirectly( poSubGeom );
+    }
+    if( !bHasCurveGeometry )
+    {
+        delete poGC;
+        return clone();
+    }
+    return poGC;
+}
+
+/************************************************************************/
+/*                      TransferMembersAndDestroy()                     */
+/************************************************************************/
+
+OGRGeometryCollection* OGRGeometryCollection::TransferMembersAndDestroy(
+                                            OGRGeometryCollection* poSrc,
+                                            OGRGeometryCollection* poDst)
+{
+    poDst->assignSpatialReference(poSrc->getSpatialReference());
+    poDst->setCoordinateDimension(poSrc->getCoordinateDimension());
+    poDst->nGeomCount = poSrc->nGeomCount;
+    poDst->papoGeoms = poSrc->papoGeoms;
+    poSrc->nGeomCount = 0;
+    poSrc->papoGeoms = NULL;
+    delete poSrc;
+    return poDst;
+}
diff --git a/ogr/ogrgeometryfactory.cpp b/ogr/ogrgeometryfactory.cpp
index dd283ae..9a7097d 100644
--- a/ogr/ogrgeometryfactory.cpp
+++ b/ogr/ogrgeometryfactory.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeometryfactory.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeometryfactory.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Factory for converting geometry to and from well known binary
@@ -8,7 +8,7 @@
  *
  ******************************************************************************
  * Copyright (c) 1999, Frank Warmerdam
- * Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys dot com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,11 +34,7 @@
 #include "ogr_p.h"
 #include "ogr_geos.h"
 
-CPL_CVSID("$Id: ogrgeometryfactory.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-#ifndef PI
-#define PI  3.14159265358979323846
-#endif 
+CPL_CVSID("$Id: ogrgeometryfactory.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /*                           createFromWkb()                            */
@@ -77,7 +73,8 @@ CPL_CVSID("$Id: ogrgeometryfactory.cpp 27044 2014-03-16 23:41:27Z rouault $");
 OGRErr OGRGeometryFactory::createFromWkb(unsigned char *pabyData,
                                          OGRSpatialReference * poSR,
                                          OGRGeometry **ppoReturn,
-                                         int nBytes )
+                                         int nBytes,
+                                         OGRwkbVariant eWkbVariant )
 
 {
     OGRwkbGeometryType eGeometryType;
@@ -121,7 +118,7 @@ OGRErr OGRGeometryFactory::createFromWkb(unsigned char *pabyData,
 /* -------------------------------------------------------------------- */
 
     OGRBoolean bIs3D;
-    OGRErr err = OGRReadWKBGeometryType( pabyData, &eGeometryType, &bIs3D );
+    OGRErr err = OGRReadWKBGeometryType( pabyData, eWkbVariant, &eGeometryType, &bIs3D );
 
     if( err != OGRERR_NONE )
         return err;
@@ -139,13 +136,20 @@ OGRErr OGRGeometryFactory::createFromWkb(unsigned char *pabyData,
 /* -------------------------------------------------------------------- */
 /*      Import from binary.                                             */
 /* -------------------------------------------------------------------- */
-    eErr = poGeom->importFromWkb( pabyData, nBytes );
+    eErr = poGeom->importFromWkb( pabyData, nBytes, eWkbVariant );
 
 /* -------------------------------------------------------------------- */
 /*      Assign spatial reference system.                                */
 /* -------------------------------------------------------------------- */
     if( eErr == OGRERR_NONE )
     {
+        if ( poGeom->hasCurveGeometry() && 
+             CSLTestBoolean(CPLGetConfigOption("OGR_STROKE_CURVE", "FALSE")) ) 
+        {
+            OGRGeometry* poNewGeom = poGeom->getLinearGeometry();
+            delete poGeom; 
+            poGeom = poNewGeom; 
+        }
         poGeom->assignSpatialReference( poSR );
         *ppoReturn = poGeom;
     }
@@ -294,6 +298,31 @@ OGRErr OGRGeometryFactory::createFromWkt(char **ppszData,
         poGeom = new OGRMultiLineString();
     }
 
+    else if( EQUAL(szToken,"CIRCULARSTRING") )
+    {
+        poGeom = new OGRCircularString();
+    }
+
+    else if( EQUAL(szToken,"COMPOUNDCURVE") )
+    {
+        poGeom = new OGRCompoundCurve();
+    }
+
+    else if( EQUAL(szToken,"CURVEPOLYGON") )
+    {
+        poGeom = new OGRCurvePolygon();
+    }
+
+    else if( EQUAL(szToken,"MULTICURVE") )
+    {
+        poGeom = new OGRMultiCurve();
+    }
+
+    else if( EQUAL(szToken,"MULTISURFACE") )
+    {
+        poGeom = new OGRMultiSurface();
+    }
+
     else
     {
         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
@@ -309,6 +338,13 @@ OGRErr OGRGeometryFactory::createFromWkt(char **ppszData,
 /* -------------------------------------------------------------------- */
     if( eErr == OGRERR_NONE )
     {
+        if ( poGeom->hasCurveGeometry() && 
+             CSLTestBoolean(CPLGetConfigOption("OGR_STROKE_CURVE", "FALSE")) ) 
+        {
+            OGRGeometry* poNewGeom = poGeom->getLinearGeometry();
+            delete poGeom; 
+            poGeom = poNewGeom; 
+        }
         poGeom->assignSpatialReference( poSR );
         *ppoReturn = poGeom;
         *ppszData = pszInput;
@@ -404,6 +440,21 @@ OGRGeometryFactory::createGeometry( OGRwkbGeometryType eGeometryType )
       case wkbLinearRing:
           return new OGRLinearRing();
 
+      case wkbCircularString:
+          return new OGRCircularString();
+
+      case wkbCompoundCurve:
+          return new OGRCompoundCurve();
+
+      case wkbCurvePolygon:
+          return new OGRCurvePolygon();
+
+      case wkbMultiCurve:
+          return new OGRMultiCurve();
+
+      case wkbMultiSurface:
+          return new OGRMultiSurface();
+
       default:
           return NULL;
     }
@@ -485,9 +536,10 @@ void OGR_G_DestroyGeometry( OGRGeometryH hGeom )
 /**
  * \brief Convert to polygon.
  *
- * Tries to force the provided geometry to be a polygon.  Currently
- * this just effects a change on multipolygons.  The passed in geometry is
- * consumed and a new one returned (or potentially the same one). 
+ * Tries to force the provided geometry to be a polygon. This effects a change
+ * on multipolygons.
+ * Starting with GDAL 2.0, curve polygons or closed curves will be changed to polygons.
+ * The passed in geometry is consumed and a new one returned (or potentially the same one). 
  * 
  * @param poGeom the input geometry - ownership is passed to the method.
  * @return new geometry.
@@ -501,15 +553,52 @@ OGRGeometry *OGRGeometryFactory::forceToPolygon( OGRGeometry *poGeom )
 
     OGRwkbGeometryType eGeomType = wkbFlatten(poGeom->getGeometryType());
 
+    if( eGeomType == wkbCurvePolygon )
+    {
+        if( !poGeom->hasCurveGeometry(TRUE) )
+            return OGRSurface::CastToPolygon(((OGRCurvePolygon*)poGeom));
+
+        OGRPolygon* poPoly = ((OGRCurvePolygon*)poGeom)->CurvePolyToPoly();
+        delete poGeom;
+        return poPoly;
+    }
+
+    if( OGR_GT_IsCurve(eGeomType) &&
+        ((OGRCurve*)poGeom)->getNumPoints() >= 3 &&
+        ((OGRCurve*)poGeom)->get_IsClosed() )
+    {
+        OGRPolygon *poPolygon = new OGRPolygon();
+        poPolygon->assignSpatialReference(poGeom->getSpatialReference());
+
+        if( !poGeom->hasCurveGeometry(TRUE) )
+        {
+            poPolygon->addRingDirectly( OGRCurve::CastToLinearRing((OGRCurve*)poGeom) );
+        }
+        else
+        {
+            OGRLineString* poLS = ((OGRCurve*)poGeom)->CurveToLine();
+            poPolygon->addRingDirectly( OGRCurve::CastToLinearRing(poLS) );
+            delete poGeom;
+        }
+        return poPolygon;
+    }
+
     if( eGeomType != wkbGeometryCollection
-        && eGeomType != wkbMultiPolygon )
+        && eGeomType != wkbMultiPolygon
+        && eGeomType != wkbMultiSurface )
         return poGeom;
 
     // build an aggregated polygon from all the polygon rings in the container.
     OGRPolygon *poPolygon = new OGRPolygon();
     OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
-    if( poGeom->getSpatialReference() != NULL )
-        poPolygon->assignSpatialReference(poGeom->getSpatialReference());
+    if( poGeom->hasCurveGeometry() )
+    {
+        OGRGeometryCollection *poNewGC = (OGRGeometryCollection *) poGC->getLinearGeometry();
+        delete poGC;
+        poGeom = poGC = poNewGC;
+    }
+
+    poPolygon->assignSpatialReference(poGeom->getSpatialReference());
     int iGeom;
 
     for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
@@ -589,19 +678,36 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPolygon( OGRGeometry *poGeom )
     }
 
 /* -------------------------------------------------------------------- */
+/*      If this is already a MultiSurface with compatible content,      */
+/*      just cast                                                       */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbMultiSurface &&
+        !((OGRMultiSurface*)poGeom)->hasCurveGeometry(TRUE) )
+    {
+        return OGRMultiSurface::CastToMultiPolygon((OGRMultiSurface*)poGeom);
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Check for the case of a geometrycollection that can be          */
 /*      promoted to MultiPolygon.                                       */
 /* -------------------------------------------------------------------- */
-    if( eGeomType == wkbGeometryCollection )
+    if( eGeomType == wkbGeometryCollection ||
+        eGeomType == wkbMultiSurface )
     {
         int iGeom;
         int bAllPoly = TRUE;
         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
+        if( poGeom->hasCurveGeometry() )
+        {
+            OGRGeometryCollection *poNewGC = (OGRGeometryCollection *) poGC->getLinearGeometry();
+            delete poGC;
+            poGeom = poGC = poNewGC;
+        }
 
         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
         {
-            if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType())
-                != wkbPolygon )
+            OGRwkbGeometryType eSubGeomType = wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType());
+            if( eSubGeomType != wkbPolygon )
                 bAllPoly = FALSE;
         }
 
@@ -609,8 +715,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPolygon( OGRGeometry *poGeom )
             return poGeom;
         
         OGRMultiPolygon *poMP = new OGRMultiPolygon();
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
 
         while( poGC->getNumGeometries() > 0 )
         {
@@ -623,6 +728,16 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPolygon( OGRGeometry *poGeom )
         return poMP;
     }
 
+    if( eGeomType == wkbCurvePolygon )
+    {
+        OGRPolygon* poPoly = ((OGRCurvePolygon*)poGeom)->CurvePolyToPoly();
+        OGRMultiPolygon *poMP = new OGRMultiPolygon();
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->addGeometryDirectly( poPoly );
+        delete poGeom;
+        return poMP;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Eventually we should try to split the polygon into component    */
 /*      island polygons.  But thats alot of work and can be put off.    */
@@ -631,8 +746,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPolygon( OGRGeometry *poGeom )
         return poGeom;
 
     OGRMultiPolygon *poMP = new OGRMultiPolygon();
-    if( poGeom->getSpatialReference() != NULL )
-        poMP->assignSpatialReference(poGeom->getSpatialReference());
+    poMP->assignSpatialReference(poGeom->getSpatialReference());
     poMP->addGeometryDirectly( poGeom );
 
     return poMP;
@@ -669,7 +783,8 @@ OGRGeometryH OGR_G_ForceToMultiPolygon( OGRGeometryH hGeom )
  * \brief Convert to multipoint.
  *
  * Tries to force the provided geometry to be a multipoint.  Currently
- * this just effects a change on points.  The passed in geometry is
+ * this just effects a change on points or collection of points.
+ * The passed in geometry is
  * consumed and a new one returned (or potentially the same one). 
  * 
  * @return new geometry.
@@ -712,8 +827,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPoint( OGRGeometry *poGeom )
             return poGeom;
         
         OGRMultiPoint *poMP = new OGRMultiPoint();
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
 
         while( poGC->getNumGeometries() > 0 )
         {
@@ -730,8 +844,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiPoint( OGRGeometry *poGeom )
         return poGeom;
 
     OGRMultiPoint *poMP = new OGRMultiPoint();
-    if( poGeom->getSpatialReference() != NULL )
-        poMP->assignSpatialReference(poGeom->getSpatialReference());
+    poMP->assignSpatialReference(poGeom->getSpatialReference());
     poMP->addGeometryDirectly( poGeom );
 
     return poMP;
@@ -770,9 +883,12 @@ OGRGeometryH OGR_G_ForceToMultiPoint( OGRGeometryH hGeom )
  * Tries to force the provided geometry to be a multilinestring.
  *
  * - linestrings are placed in a multilinestring.
+ * - circularstrings and compoundcurves will be approximated and placed in a
+ * multilinestring.
  * - geometry collections will be converted to multilinestring if they only 
  * contain linestrings.
  * - polygons will be changed to a collection of linestrings (one per ring).
+ * - curvepolygons will be approximated and changed to a collection of linestrings (one per ring).
  *
  * The passed in geometry is
  * consumed and a new one returned (or potentially the same one). 
@@ -805,11 +921,16 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
         int iGeom;
         int bAllLines = TRUE;
         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
+        if( poGeom->hasCurveGeometry() )
+        {
+            OGRGeometryCollection *poNewGC = (OGRGeometryCollection *) poGC->getLinearGeometry();
+            delete poGC;
+            poGeom = poGC = poNewGC;
+        }
 
         for( iGeom = 0; iGeom < poGC->getNumGeometries(); iGeom++ )
         {
-            if( wkbFlatten(poGC->getGeometryRef(iGeom)->getGeometryType())
-                != wkbLineString )
+            if( poGC->getGeometryRef(iGeom)->getGeometryType() != wkbLineString )
                 bAllLines = FALSE;
         }
 
@@ -817,8 +938,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
             return poGeom;
         
         OGRMultiLineString *poMP = new OGRMultiLineString();
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
 
         while( poGC->getNumGeometries() > 0 )
         {
@@ -837,8 +957,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
     if( eGeomType == wkbLineString )
     {
         OGRMultiLineString *poMP = new OGRMultiLineString();
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
         poMP->addGeometryDirectly( poGeom );
         return poMP;
     }
@@ -846,14 +965,21 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
 /* -------------------------------------------------------------------- */
 /*      Convert polygons into a multilinestring.                        */
 /* -------------------------------------------------------------------- */
-    if( eGeomType == wkbPolygon )
+    if( eGeomType == wkbPolygon || eGeomType == wkbCurvePolygon )
     {
         OGRMultiLineString *poMP = new OGRMultiLineString();
-        OGRPolygon *poPoly = (OGRPolygon *) poGeom;
+        OGRPolygon *poPoly;
+        if( eGeomType == wkbPolygon )
+            poPoly = (OGRPolygon *) poGeom;
+        else
+        {
+            poPoly = ((OGRCurvePolygon*) poGeom)->CurvePolyToPoly();
+            delete poGeom;
+            poGeom = poPoly;
+        }
         int iRing;
 
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
 
         for( iRing = 0; iRing < poPoly->getNumInteriorRings()+1; iRing++ )
         {
@@ -875,7 +1001,7 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
             poNewLS->addSubLineString( poLR );
             poMP->addGeometryDirectly( poNewLS );
         }
-        
+
         delete poPoly;
 
         return poMP;
@@ -884,14 +1010,21 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
 /* -------------------------------------------------------------------- */
 /*      Convert multi-polygons into a multilinestring.                  */
 /* -------------------------------------------------------------------- */
-    if( eGeomType == wkbMultiPolygon )
+    if( eGeomType == wkbMultiPolygon || eGeomType == wkbMultiSurface )
     {
         OGRMultiLineString *poMP = new OGRMultiLineString();
-        OGRMultiPolygon *poMPoly = (OGRMultiPolygon *) poGeom;
+        OGRMultiPolygon *poMPoly;
+        if( eGeomType == wkbMultiPolygon )
+            poMPoly = (OGRMultiPolygon *) poGeom;
+        else
+        {
+            poMPoly = (OGRMultiPolygon *) poGeom->getLinearGeometry();
+            delete poGeom;
+            poGeom = poMPoly;
+        }
         int iPoly;
 
-        if( poGeom->getSpatialReference() != NULL )
-            poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
 
         for( iPoly = 0; iPoly < poMPoly->getNumGeometries(); iPoly++ )
         {
@@ -924,6 +1057,40 @@ OGRGeometry *OGRGeometryFactory::forceToMultiLineString( OGRGeometry *poGeom )
         return poMP;
     }
 
+/* -------------------------------------------------------------------- */
+/*      If it's a curve line, approximate it and wrap in a multilinestring */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbCircularString ||
+        eGeomType == wkbCompoundCurve )
+    {
+        OGRMultiLineString *poMP = new OGRMultiLineString();
+        poMP->assignSpatialReference(poGeom->getSpatialReference());
+        poMP->addGeometryDirectly( ((OGRCurve*)poGeom)->CurveToLine() );
+        delete poGeom;
+        return poMP;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If this is already a MultiCurve with compatible content,        */
+/*      just cast                                                       */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbMultiCurve &&
+        !((OGRMultiCurve*)poGeom)->hasCurveGeometry(TRUE) )
+    {
+        return OGRMultiCurve::CastToMultiLineString((OGRMultiCurve*)poGeom);
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If it's a multicurve, call getLinearGeometry()                */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbMultiCurve )
+    {
+        OGRGeometry* poNewGeom = poGeom->getLinearGeometry();
+        CPLAssert( wkbFlatten(poNewGeom->getGeometryType()) == wkbMultiLineString );
+        delete poGeom;
+        return (OGRMultiLineString*) poNewGeom;
+    }
+
     return poGeom;
 }
 
@@ -1039,7 +1206,7 @@ typedef enum
  * with care.
  *
  * If the OGR_ORGANIZE_POLYGONS configuration option is defined, its value will override
- * the value of the METHOD option of papszOptions (usefull to modify the behaviour of the
+ * the value of the METHOD option of papszOptions (useful to modify the behaviour of the
  * shapefile driver)
  *
  * @param papoPolygons array of geometry pointers - should all be OGRPolygons.
@@ -2231,9 +2398,8 @@ static void Sub360ToLon( OGRGeometry* poGeom )
             
             break;
         }
-            
+
         case wkbLineString:
-        case wkbLinearRing:
         {
             OGRLineString* poLineString = (OGRLineString* )poGeom;
             int nPointCount = poLineString->getNumPoints();
@@ -2489,6 +2655,15 @@ OGRGeometry* OGRGeometryFactory::transformWithOptions( const OGRGeometry* poSrcG
 }
 
 /************************************************************************/
+/*                       OGRGF_GetDefaultStepSize()                     */
+/************************************************************************/
+
+static double OGRGF_GetDefaultStepSize()
+{
+    return CPLAtofM(CPLGetConfigOption("OGR_ARC_STEPSIZE","4"));
+}
+
+/************************************************************************/
 /*                        approximateArcAngles()                        */
 /************************************************************************/
 
@@ -2530,13 +2705,12 @@ OGRGeometry* OGRGeometryFactory::approximateArcAngles(
     double             dfSlice;
     int                iPoint, nVertexCount;
     OGRLineString     *poLine = new OGRLineString();
-    double             dfRotationRadians = dfRotation * PI / 180.0;
+    double             dfRotationRadians = dfRotation * M_PI / 180.0;
 
     // support default arc step setting.
-    if( dfMaxAngleStepSizeDegrees == 0 )
+    if( dfMaxAngleStepSizeDegrees < 1e-6 )
     {
-        dfMaxAngleStepSizeDegrees = 
-            atof(CPLGetConfigOption("OGR_ARC_STEPSIZE","4"));
+        dfMaxAngleStepSizeDegrees = OGRGF_GetDefaultStepSize();
     }
 
     // switch direction 
@@ -2558,7 +2732,7 @@ OGRGeometry* OGRGeometryFactory::approximateArcAngles(
         double      dfArcX, dfArcY;
         double      dfEllipseX, dfEllipseY;
 
-        dfAngleOnEllipse = (dfStartAngle + iPoint * dfSlice) * PI / 180.0;
+        dfAngleOnEllipse = (dfStartAngle + iPoint * dfSlice) * M_PI / 180.0;
 
         // Compute position on the unrotated ellipse. 
         dfEllipseX = cos(dfAngleOnEllipse) * dfPrimaryRadius;
@@ -2631,8 +2805,13 @@ OGR_G_ApproximateArcAngles(
 /**
  * \brief Convert to line string.
  *
- * Tries to force the provided geometry to be a line string.  Currently
- * this just effects a change on multilinestrings.  The passed in geometry is
+ * Tries to force the provided geometry to be a line string.  This nominally
+ * effects a change on multilinestrings.
+ * In GDAL 2.0, for polygons or curvepolygons that have a single exterior ring,
+ * it will return the ring. For circular strings or compound curves, it will
+ * return an approximated line string.
+ *
+ * The passed in geometry is
  * consumed and a new one returned (or potentially the same one).
  *
  * @param poGeom the input geometry - ownership is passed to the method.
@@ -2652,12 +2831,65 @@ OGRGeometry *OGRGeometryFactory::forceToLineString( OGRGeometry *poGeom, bool bO
 
     OGRwkbGeometryType eGeomType = wkbFlatten(poGeom->getGeometryType());
 
+/* -------------------------------------------------------------------- */
+/*      If this is already a LineString, nothing to do                  */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbLineString )
+    {
+        /* except if it is a linearring */
+        poGeom = OGRCurve::CastToLineString((OGRCurve*)poGeom);
+
+        return poGeom;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If it's a polygon with a single ring, return it                 */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbPolygon || eGeomType == wkbCurvePolygon )
+    {
+        OGRCurvePolygon* poCP = (OGRCurvePolygon*)poGeom;
+        if( poCP->getNumInteriorRings() == 0 )
+        {
+            OGRCurve* poRing = poCP->stealExteriorRingCurve();
+            delete poCP;
+            return forceToLineString(poRing);
+        }
+        return poGeom;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If it's a curve line, call CurveToLine()                        */
+/* -------------------------------------------------------------------- */
+    if( eGeomType == wkbCircularString ||
+        eGeomType == wkbCompoundCurve )
+    {
+        OGRGeometry* poNewGeom = ((OGRCurve*)poGeom)->CurveToLine();
+        delete poGeom;
+        return poNewGeom;
+    }
+
+
     if( eGeomType != wkbGeometryCollection
-        && eGeomType != wkbMultiLineString )
+        && eGeomType != wkbMultiLineString
+        && eGeomType != wkbMultiCurve )
         return poGeom;
 
     // build an aggregated linestring from all the linestrings in the container.
     OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeom;
+    if( poGeom->hasCurveGeometry() )
+    {
+        OGRGeometryCollection *poNewGC = (OGRGeometryCollection *) poGC->getLinearGeometry();
+        delete poGC;
+        poGeom = poGC = poNewGC;
+    }
+
+    if( poGC->getNumGeometries() == 0 )
+    {
+        poGeom = new OGRLineString();
+        poGeom->assignSpatialReference(poGC->getSpatialReference());
+        delete poGC;
+        return poGeom;
+    }
 
     int iGeom0 = 0;
     while( iGeom0 < poGC->getNumGeometries() )
@@ -2758,3 +2990,1292 @@ OGRGeometryH OGR_G_ForceToLineString( OGRGeometryH hGeom )
     return (OGRGeometryH)
         OGRGeometryFactory::forceToLineString( (OGRGeometry *) hGeom );
 }
+
+
+/************************************************************************/
+/*                           forceTo()                                  */
+/************************************************************************/
+
+/**
+ * \brief Convert to another geometry type
+ *
+ * Tries to force the provided geometry to the specified geometry type.
+ *
+ * It can promote 'single' geometry type to their corresponding collection type
+ * (see OGR_GT_GetCollection()) or the reverse. non-linear geometry type to
+ * their corresponding linear geometry type (see OGR_GT_GetLinear()), by
+ * possibly approximating circular arcs they may contain.
+ * Regarding conversion from linear geometry types to curve geometry types, only
+ * "wraping" will be done. No attempt to retrieve potential circular arcs by
+ * de-approximating stroking will be done. For that, OGRGeometry::getCurveGeometry()
+ * can be used.
+ *
+ * The passed in geometry is consumed and a new one returned (or potentially the same one).
+ *
+ * @param poGeom the input geometry - ownership is passed to the method.
+ * @param eTargetType target output geometry type.
+ * @param papszOptions options as a null-terminated list of strings or NULL.
+ * @return new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometry * OGRGeometryFactory::forceTo( OGRGeometry* poGeom,
+                                           OGRwkbGeometryType eTargetType,
+                                           const char*const* papszOptions )
+{
+    if( poGeom == NULL )
+        return poGeom;
+
+    eTargetType = wkbFlatten(eTargetType);
+    OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
+    if( eType == eTargetType || eTargetType == wkbUnknown )
+        return poGeom;
+
+    if( poGeom->IsEmpty() )
+    {
+        OGRGeometry* poRet = createGeometry(eTargetType);
+        if( poRet )
+            poRet->assignSpatialReference(poGeom->getSpatialReference());
+        delete poGeom;
+        return poRet;
+    }
+
+    /* Promote single to multi */
+    if( !OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) &&
+         OGR_GT_IsSubClassOf(OGR_GT_GetCollection(eType), eTargetType) )
+    {
+        OGRGeometryCollection* poRet = (OGRGeometryCollection*)createGeometry(eTargetType);
+        if( poRet )
+        {
+            poRet->assignSpatialReference(poGeom->getSpatialReference());
+            if( eType == wkbLineString )
+                poGeom = OGRCurve::CastToLineString( (OGRCurve*)poGeom );
+            poRet->addGeometryDirectly(poGeom);
+        }
+        else
+            delete poGeom;
+        return poRet;
+    }
+
+    int bIsCurve = OGR_GT_IsCurve(eType);
+    if( bIsCurve && eTargetType == wkbCompoundCurve )
+    {
+        return OGRCurve::CastToCompoundCurve((OGRCurve*)poGeom);
+    }
+    else if( bIsCurve && eTargetType == wkbCurvePolygon )
+    {
+        OGRCurve* poCurve = (OGRCurve*)poGeom;
+        if( poCurve->getNumPoints() >= 3 && poCurve->get_IsClosed() )
+        {
+            OGRCurvePolygon* poCP = new OGRCurvePolygon();
+            if( poCP->addRingDirectly( poCurve ) == OGRERR_NONE )
+            {
+                poCP->assignSpatialReference(poGeom->getSpatialReference());
+                return poCP;
+            }
+            else
+            {
+                delete poCP;
+            }
+        }
+    }
+    else if( eType == wkbLineString &&
+             OGR_GT_IsSubClassOf(eTargetType, wkbMultiSurface) )
+    {
+        OGRGeometry* poTmp = forceTo(poGeom, wkbPolygon, papszOptions);
+        if( wkbFlatten(poTmp->getGeometryType()) != eType)
+            return forceTo(poTmp, eTargetType, papszOptions);
+    }
+    else if( bIsCurve && eTargetType == wkbMultiSurface )
+    {
+        OGRGeometry* poTmp = forceTo(poGeom, wkbCurvePolygon, papszOptions);
+        if( wkbFlatten(poTmp->getGeometryType()) != eType)
+            return forceTo(poTmp, eTargetType, papszOptions);
+    }
+    else if( bIsCurve && eTargetType == wkbMultiPolygon )
+    {
+        OGRGeometry* poTmp = forceTo(poGeom, wkbPolygon, papszOptions);
+        if( wkbFlatten(poTmp->getGeometryType()) != eType)
+            return forceTo(poTmp, eTargetType, papszOptions);
+    }
+    else if (eType == wkbPolygon && eTargetType == wkbCurvePolygon)
+    {
+        return OGRSurface::CastToCurvePolygon((OGRPolygon*)poGeom);
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) &&
+             eTargetType == wkbCompoundCurve )
+    {
+        OGRCurvePolygon* poPoly = (OGRCurvePolygon*)poGeom;
+        if( poPoly->getNumInteriorRings() == 0 )
+        {
+            OGRCurve* poRet = poPoly->stealExteriorRingCurve();
+            if( poRet )
+                poRet->assignSpatialReference(poGeom->getSpatialReference());
+            delete poPoly;
+            return forceTo(poRet, eTargetType, papszOptions);
+        }
+    }
+    else if ( eType == wkbMultiPolygon && eTargetType == wkbMultiSurface )
+    {
+        return OGRMultiPolygon::CastToMultiSurface((OGRMultiPolygon*)poGeom);
+    }
+    else if ( eType == wkbMultiLineString && eTargetType == wkbMultiCurve )
+    {
+        return OGRMultiLineString::CastToMultiCurve((OGRMultiLineString*)poGeom);
+    }
+    else if ( OGR_GT_IsSubClassOf(eType, wkbGeometryCollection) )
+    {
+        OGRGeometryCollection* poGC = (OGRGeometryCollection*)poGeom;
+        if( poGC->getNumGeometries() == 1 )
+        {
+            OGRGeometry* poSubGeom = poGC->getGeometryRef(0);
+            if( poSubGeom )
+                poSubGeom->assignSpatialReference(poGeom->getSpatialReference());
+            poGC->removeGeometry(0, FALSE);
+            OGRGeometry* poRet = forceTo(poSubGeom, eTargetType, papszOptions);
+            if( OGR_GT_IsSubClassOf(wkbFlatten(poRet->getGeometryType()), eTargetType) )
+            {
+                delete poGC;
+                return poRet;
+            }
+            poGC->addGeometryDirectly(poSubGeom);
+        }
+    }
+    else if( OGR_GT_IsSubClassOf(eType, wkbCurvePolygon) &&
+             (OGR_GT_IsSubClassOf(eTargetType, wkbMultiSurface) ||
+              OGR_GT_IsSubClassOf(eTargetType, wkbMultiCurve)) )
+    {
+        OGRCurvePolygon* poCP = (OGRCurvePolygon*)poGeom;
+        if( poCP->getNumInteriorRings() == 0 )
+        {
+            OGRCurve* poRing = poCP->getExteriorRingCurve();
+            poRing->assignSpatialReference(poGeom->getSpatialReference());
+            OGRwkbGeometryType eRingType = poRing->getGeometryType();
+            OGRGeometry* poRingDup = poRing->clone();
+            OGRGeometry* poRet = forceTo(poRingDup, eTargetType, papszOptions);
+            if( poRet->getGeometryType() != eRingType )
+            {
+                delete poCP;
+                return poRet;
+            }
+            else
+                delete poRet;
+        }
+    }
+
+    if( eTargetType == wkbLineString )
+    {
+        poGeom = forceToLineString(poGeom);
+    }
+    else if( eTargetType == wkbPolygon )
+    {
+        poGeom = forceToPolygon(poGeom);
+    }
+    else if( eTargetType == wkbMultiPolygon )
+    {
+        poGeom = forceToMultiPolygon(poGeom);
+    }
+    else if( eTargetType == wkbMultiLineString )
+    {
+        poGeom = forceToMultiLineString(poGeom);
+    }
+    else if( eTargetType == wkbMultiPoint )
+    {
+        poGeom = forceToMultiPoint(poGeom);
+    }
+
+    return poGeom;
+}
+
+
+/************************************************************************/
+/*                          OGR_G_ForceTo()                             */
+/************************************************************************/
+
+/**
+ * \brief Convert to another geometry type
+ *
+ * This function is the same as the C++ method OGRGeometryFactory::forceTo().
+ *
+ * @param hGeom the input geometry - ownership is passed to the method.
+ * @param eTargetType target output geometry type.
+ * @param papszOptions options as a null-terminated list of strings or NULL.
+ * @return new geometry.
+ *
+ * @since GDAL 2.0
+ */
+
+OGRGeometryH OGR_G_ForceTo( OGRGeometryH hGeom,
+                            OGRwkbGeometryType eTargetType,
+                            char** papszOptions )
+
+{
+    return (OGRGeometryH)
+        OGRGeometryFactory::forceTo( (OGRGeometry *) hGeom, eTargetType,
+                                     (const char* const*)papszOptions );
+}
+
+
+/************************************************************************/
+/*                         GetCurveParmeters()                          */
+/************************************************************************/
+
+/**
+ * \brief Returns the parameter of an arc circle.
+ *
+ * @param x0 x of first point
+ * @param y0 y of first point
+ * @param z0 z of first point
+ * @param x1 x of intermediate point
+ * @param y1 y of intermediate point
+ * @param z1 z of intermediate point
+ * @param x2 x of final point
+ * @param y2 y of final point
+ * @param z2 z of final point
+ * @param R radius (output)
+ * @param cx x of arc center (output)
+ * @param cx y of arc center (output)
+ * @param alpha0 angle between center and first point (output)
+ * @param alpha1 angle between center and intermediate point (output)
+ * @param alpha2 angle between center and final point (output)
+ * @return TRUE if the points are not aligned and define an arc circle.
+ *
+ * @since GDAL 2.0
+ */
+
+#define DISTANCE(x1,y1,x2,y2) sqrt(((x2)-(x1))*((x2)-(x1))+((y2)-(y1))*((y2)-(y1)))
+
+int OGRGeometryFactory::GetCurveParmeters(
+    double x0, double y0, double x1, double y1, double x2, double y2,
+    double& R, double& cx, double& cy, double& alpha0, double& alpha1, double& alpha2 )
+{
+    /* Circle */
+    if( x0 == x2 && y0 == y2 && (x0 != x1 || y0 != y1) )
+    {
+        cx = (x0 + x1) / 2;
+        cy = (y0 + y1) / 2;
+        R = DISTANCE(cx,cy,x0,y0);
+        /* Arbitrarily pick counter-clock-wise order (like PostGIS does) */
+        alpha0 = atan2(y0 - cy, x0 - cx);
+        alpha1 = alpha0 + M_PI;
+        alpha2 = alpha0 + 2 * M_PI;
+        return TRUE;
+    }
+
+    double dx01 = x1 - x0;
+    double dy01 = y1 - y0;
+    double dx12 = x2 - x1;
+    double dy12 = y2 - y1;
+
+    /* Normalize above values so as to make sure we don't end up with */
+    /* computing a difference of too big values */
+    double dfScale = fabs(dx01);
+    if( fabs(dy01) > dfScale ) dfScale = fabs(dy01);
+    if( fabs(dx12) > dfScale ) dfScale = fabs(dx12);
+    if( fabs(dy12) > dfScale ) dfScale = fabs(dy12);
+    double dfInvScale = 1.0 / dfScale;
+    dx01 *= dfInvScale;
+    dy01 *= dfInvScale;
+    dx12 *= dfInvScale;
+    dy12 *= dfInvScale;
+
+    double det = dx01 * dy12 - dx12 * dy01;
+    if( fabs(det) < 1e-8 )
+    {
+        return FALSE;
+    }
+    double x01_mid = (x0 + x1) * dfInvScale;
+    double x12_mid = (x1 + x2) * dfInvScale;
+    double y01_mid = (y0 + y1) * dfInvScale;
+    double y12_mid = (y1 + y2) * dfInvScale;
+    double c01 = dx01 * x01_mid + dy01 * y01_mid;
+    double c12 = dx12 * x12_mid + dy12 * y12_mid;
+    cx =  0.5 * dfScale * (c01 * dy12 - c12 * dy01) / det;
+    cy =  0.5 * dfScale * (- c01 * dx12 + c12 * dx01) / det;
+
+    alpha0 = atan2((y0 - cy) * dfInvScale, (x0 - cx) * dfInvScale);
+    alpha1 = atan2((y1 - cy) * dfInvScale, (x1 - cx) * dfInvScale);
+    alpha2 = atan2((y2 - cy) * dfInvScale, (x2 - cx) * dfInvScale);
+    R = DISTANCE(cx,cy,x0,y0);
+
+    /* if det is negative, the orientation if clockwise */
+    if (det < 0)
+    {
+        if (alpha1 > alpha0)
+            alpha1 -= 2 * M_PI;
+        if (alpha2 > alpha1)
+            alpha2 -= 2 * M_PI;
+    }
+    else
+    {
+        if (alpha1 < alpha0)
+            alpha1 += 2 * M_PI;
+        if (alpha2 < alpha1)
+            alpha2 += 2 * M_PI;
+    }
+
+    CPLAssert((alpha0 <= alpha1 && alpha1 <= alpha2) ||
+                (alpha0 >= alpha1 && alpha1 >= alpha2));
+
+    return TRUE;
+}
+
+
+/************************************************************************/
+/*                      OGRGeometryFactoryStrokeArc()                   */
+/************************************************************************/
+
+//#define ROUND_ANGLE_METHOD
+
+static void OGRGeometryFactoryStrokeArc(OGRLineString* poLine,
+                                        double cx, double cy, double R,
+                                        double z0, double z1, int bHasZ,
+                                        double alpha0, double alpha1,
+                                        double dfStep,
+                                        int bStealthConstraints)
+{
+    double alpha;
+
+    int nSign = (dfStep > 0) ? 1 : -1;
+
+#ifdef ROUND_ANGLE_METHOD
+    /* Initial approach: no longer used */
+    /* Discretize on angles that are multiple of dfStep so as to not */
+    /* depend on winding order. */
+    if (dfStep > 0 )
+    {
+        alpha = floor(alpha0  / dfStep) * dfStep;
+        if( alpha <= alpha0 )
+            alpha += dfStep;
+    }
+    else
+    {
+        alpha = ceil(alpha0  / dfStep) * dfStep;
+        if( alpha >= alpha0 )
+            alpha += dfStep;
+    }
+#else
+    /* Constant angle between all points, so as to not depend on winding order */
+    int nSteps = (int)(fabs((alpha1 - alpha0) / dfStep)+0.5);
+    if( bStealthConstraints ) 
+    {
+        /* We need at least 6 intermediate vertex, and if more additional */
+        /* multiples of 2 */
+        if( nSteps < 1+6 )
+            nSteps = 1+6;
+        else
+            nSteps = 1+6 + 2 * ((nSteps - (1+6) + (2-1)) / 2);
+    }
+    else if( nSteps < 4 )
+        nSteps = 4;
+    dfStep = nSign * fabs((alpha1 - alpha0) / nSteps);
+    alpha = alpha0 + dfStep;
+#endif
+
+    for(; (alpha - alpha1) * nSign < -1e-8; alpha += dfStep)
+    {
+        double dfX = cx + R * cos(alpha), dfY = cy + R * sin(alpha);
+        if( bHasZ )
+        {
+            double z = z0 + (z1 - z0) * (alpha - alpha0) / (alpha1 - alpha0);
+            poLine->addPoint(dfX, dfY, z);
+        }
+        else
+            poLine->addPoint(dfX, dfY);
+    }
+}
+
+/************************************************************************/
+/*                         OGRGF_SetHiddenValue()                       */
+/************************************************************************/
+
+#define HIDDEN_ALPHA_WIDTH        32
+#define HIDDEN_ALPHA_SCALE        (GUInt32)((((GUIntBig)1) << HIDDEN_ALPHA_WIDTH)-2)
+#define HIDDEN_ALPHA_HALF_WIDTH   (HIDDEN_ALPHA_WIDTH / 2)
+#define HIDDEN_ALPHA_HALF_MASK    ((1 << HIDDEN_ALPHA_HALF_WIDTH)-1)
+
+/* Encode 16-bit nValue in the 8-lsb of dfX and dfY */
+
+#ifdef CPL_LSB
+#define DOUBLE_LSB_OFFSET   0
+#else
+#define DOUBLE_LSB_OFFSET   7
+#endif
+
+static void OGRGF_SetHiddenValue(GUInt16 nValue, double& dfX, double &dfY)
+{
+    GByte abyData[8];
+
+    memcpy(abyData, &dfX, sizeof(double));
+    abyData[DOUBLE_LSB_OFFSET] = (GByte)(nValue & 0xFF);
+    memcpy(&dfX, abyData, sizeof(double));
+
+    memcpy(abyData, &dfY, sizeof(double));
+    abyData[DOUBLE_LSB_OFFSET] = (GByte)(nValue >> 8);
+    memcpy(&dfY, abyData, sizeof(double));
+}
+
+/************************************************************************/
+/*                         OGRGF_GetHiddenValue()                       */
+/************************************************************************/
+
+/* Decode 16-bit nValue from the 8-lsb of dfX and dfY */
+static GUInt16 OGRGF_GetHiddenValue(double dfX, double dfY)
+{
+    GUInt16 nValue;
+
+    GByte abyData[8];
+    memcpy(abyData, &dfX, sizeof(double));
+    nValue = abyData[DOUBLE_LSB_OFFSET];
+    memcpy(abyData, &dfY, sizeof(double));
+    nValue |= (abyData[DOUBLE_LSB_OFFSET] << 8);
+
+    return nValue;
+}
+
+/************************************************************************/
+/*                     OGRGF_NeedSwithArcOrder()                        */
+/************************************************************************/
+
+/* We need to define a full ordering between starting point and ending point */
+/* whatever it is */
+static int OGRGF_NeedSwithArcOrder(double x0, double y0,
+                                   double x2, double y2)
+{
+    return ( x0 < x2 || (x0 == x2 && y0 < y2) );
+}
+
+/************************************************************************/
+/*                         curveToLineString()                          */
+/************************************************************************/
+
+/**
+ * \brief Converts an arc circle into an approximate line string
+ *
+ * The arc circle is defined by a first point, an intermediate point and a
+ * final point.
+ *
+ * The provided dfMaxAngleStepSizeDegrees is a hint. The discretization
+ * algorithm may pick a slightly different value.
+ *
+ * So as to avoid gaps when rendering curve polygons that share common arcs,
+ * this method is guaranteed to return a line with reversed vertex if called
+ * with inverted first and final point, and identical intermediate point.
+ *
+ * @param x0 x of first point
+ * @param y0 y of first point
+ * @param z0 z of first point
+ * @param x1 x of intermediate point
+ * @param y1 y of intermediate point
+ * @param z1 z of intermediate point
+ * @param x2 x of final point
+ * @param y2 y of final point
+ * @param z2 z of final point
+ * @param bHasZ TRUE if z must be taken into account
+ * @param dfMaxAngleStepSizeDegrees  the largest step in degrees along the
+ * arc, zero to use the default setting.
+ * @param papszOptions options as a null-terminated list of strings or NULL.
+ * Recognized options:
+ * <ul>
+ * <li>ADD_INTERMEDIATE_POINT=STEALTH/YES/NO (Default to STEALTH).
+ *         Determine if and how the intermediate point must be output in the linestring.
+ *         If set to STEALTH, no explicit intermediate point is added but its
+ *         properties are encoded in low significant bits of intermediate points
+ *         and OGRGeometryFactory::curveFromLineString() can decode them.
+ *         This is the best compromise for round-tripping in OGR and better results
+ *         with PostGIS <a href="http://postgis.org/docs/ST_LineToCurve.html">ST_LineToCurve()</a>
+ *         If set to YES, the intermediate point is explicitely added to the linestring.
+ *         If set to NO, the intermediate point is not explicitely added.
+ * </li>
+ * </ul>
+ *
+ * @return the converted geometry (ownership to caller).
+ *
+ * @since GDAL 2.0
+ */
+
+OGRLineString* OGRGeometryFactory::curveToLineString(
+                                            double x0, double y0, double z0,
+                                            double x1, double y1, double z1,
+                                            double x2, double y2, double z2,
+                                            int bHasZ,
+                                            double dfMaxAngleStepSizeDegrees,
+                                            const char*const* papszOptions )
+{
+    double R, cx, cy, alpha0, alpha1, alpha2;
+
+    /* So as to make sure the same curve followed in both direction results */
+    /* in perfectly(=binary identical) symetrical points */
+    if( OGRGF_NeedSwithArcOrder(x0,y0,x2,y2) )
+    {
+        OGRLineString* poLS = curveToLineString(x2,y2,z2,x1,y1,z1,x0,y0,z0,
+                                                bHasZ, dfMaxAngleStepSizeDegrees,
+                                                papszOptions);
+        poLS->reversePoints();
+        return poLS;
+    }
+
+    OGRLineString* poLine = new OGRLineString();
+    int bIsArc = TRUE;
+    if( !GetCurveParmeters(x0, y0, x1, y1, x2, y2,
+                           R, cx, cy, alpha0, alpha1, alpha2)) 
+    {
+        bIsArc = FALSE;
+        cx = cy = R = alpha0 = alpha1 = alpha2 = 0.0;
+    }
+
+    int nSign = (alpha1 >= alpha0) ? 1 : -1;
+
+    // support default arc step setting.
+    if( dfMaxAngleStepSizeDegrees < 1e-6 )
+    {
+        dfMaxAngleStepSizeDegrees = OGRGF_GetDefaultStepSize();
+    }
+
+    double dfStep =
+        dfMaxAngleStepSizeDegrees / 180 * M_PI;
+    if (dfStep <= 0.01 / 180 * M_PI)
+    {
+        CPLDebug("OGR", "Too small arc step size: limiting to 0.01 degree.");
+        dfStep = 0.01 / 180 * M_PI;
+    }
+
+    dfStep *= nSign;
+
+    if( bHasZ )
+        poLine->addPoint(x0, y0, z0);
+    else
+        poLine->addPoint(x0, y0);
+
+    int bAddIntermediatePoint = FALSE;
+    int bStealth = TRUE;
+    for(const char* const* papszIter = papszOptions; papszIter && *papszIter; papszIter++)
+    {
+        char* pszKey = NULL;
+        const char* pszValue = CPLParseNameValue(*papszIter, &pszKey);
+        if( pszKey != NULL && EQUAL(pszKey, "ADD_INTERMEDIATE_POINT") )
+        {
+            if( EQUAL(pszValue, "YES") || EQUAL(pszValue, "TRUE") || EQUAL(pszValue, "ON") )
+            {
+                bAddIntermediatePoint = TRUE;
+                bStealth = FALSE;
+            }
+            else if( EQUAL(pszValue, "NO") || EQUAL(pszValue, "FALSE") || EQUAL(pszValue, "OFF") )
+            {
+                bAddIntermediatePoint = FALSE;
+                bStealth = FALSE;
+            }
+            else if( EQUAL(pszValue, "STEALTH") )
+            {
+                /* default */
+            }
+        }
+        else
+        {
+            CPLError(CE_Warning, CPLE_NotSupported, "Unsupported option: %s",
+                        *papszIter);
+        }
+        CPLFree(pszKey);
+    }
+
+    if( !bIsArc || bAddIntermediatePoint )
+    {
+        OGRGeometryFactoryStrokeArc(poLine, cx, cy, R,
+                                    z0, z1, bHasZ,
+                                    alpha0, alpha1, dfStep,
+                                    FALSE);
+
+        if( bHasZ )
+            poLine->addPoint(x1, y1, z1);
+        else
+            poLine->addPoint(x1, y1);
+
+        OGRGeometryFactoryStrokeArc(poLine, cx, cy, R,
+                                    z1, z2, bHasZ,
+                                    alpha1, alpha2, dfStep,
+                                    FALSE);
+    }
+    else
+    {
+        OGRGeometryFactoryStrokeArc(poLine, cx, cy, R,
+                                    z0, z2, bHasZ,
+                                    alpha0, alpha2, dfStep,
+                                    bStealth);
+
+        if( bStealth )
+        {
+            /* 'Hide' the angle of the intermediate point in the 8 low-significant */
+            /* bits of the x,y of the first 2 computed points (so 32 bits), */
+            /* then put 0xFF, and on the last couple points put again the */
+            /* angle but in reverse order, so that overall the low-significant bits */
+            /* of all the points are symetrical w.r.t the mid-point */
+            double dfRatio = (alpha1 - alpha0) / (alpha2 - alpha0);
+            GUInt32 nAlphaRatio = (GUInt32)(0.5 + HIDDEN_ALPHA_SCALE * dfRatio);
+            GUInt16 nAlphaRatioLow = nAlphaRatio & HIDDEN_ALPHA_HALF_MASK;
+            GUInt16 nAlphaRatioHigh = nAlphaRatio >> HIDDEN_ALPHA_HALF_WIDTH;
+            /*printf("alpha0=%f, alpha1=%f, alpha2=%f, dfRatio=%f, nAlphaRatio = %u\n",
+                   alpha0, alpha1, alpha2, dfRatio, nAlphaRatio);*/
+
+            CPLAssert( ((poLine->getNumPoints()-1 - 6) % 2) == 0 );
+
+            for(int i=1;i+1<poLine->getNumPoints();i+=2)
+            {
+                double dfX, dfY;
+                GUInt16 nVal = 0xFFFF;
+
+                dfX = poLine->getX(i);
+                dfY = poLine->getY(i);
+                if( i == 1 )
+                    nVal = nAlphaRatioLow;
+                else if( i == poLine->getNumPoints() - 2 )
+                    nVal = nAlphaRatioHigh;
+                OGRGF_SetHiddenValue(nVal, dfX, dfY);
+                poLine->setPoint(i, dfX, dfY);
+
+                dfX = poLine->getX(i+1);
+                dfY = poLine->getY(i+1);
+                if( i == 1 )
+                    nVal = nAlphaRatioHigh;
+                else if( i == poLine->getNumPoints() - 2 )
+                    nVal = nAlphaRatioLow;
+                OGRGF_SetHiddenValue(nVal, dfX, dfY);
+                poLine->setPoint(i+1, dfX, dfY);
+            }
+        }
+    }
+
+    if( bHasZ )
+        poLine->addPoint(x2, y2, z2);
+    else
+        poLine->addPoint(x2, y2);
+
+    return poLine;
+}
+
+/************************************************************************/
+/*                         OGRGF_FixAngle()                             */
+/************************************************************************/
+
+/* Fix dfAngle by offsets of 2 PI so that it lies between dfAngleStart and */
+/* dfAngleStop, whatever their respective order. */
+static double OGRGF_FixAngle(double dfAngleStart, double dfAngleStop, double dfAngle)
+{
+    if( dfAngleStart < dfAngleStop )
+    {
+        while( dfAngle <= dfAngleStart + 1e-8 )
+            dfAngle += 2 * M_PI;
+    }
+    else
+    {
+        while( dfAngle >= dfAngleStart - 1e-8 )
+            dfAngle -= 2 * M_PI;
+    }
+    return dfAngle;
+}
+
+/************************************************************************/
+/*                         OGRGF_DetectArc()                            */
+/************************************************************************/
+
+//#define VERBOSE_DEBUG_CURVEFROMLINESTRING
+
+static int OGRGF_DetectArc(const OGRLineString* poLS, int i,
+                           OGRCompoundCurve*& poCC,
+                           OGRCircularString*& poCS,
+                           OGRLineString*& poLSNew)
+{
+    OGRPoint p0, p1, p2, p3;
+    if( i + 3 >= poLS->getNumPoints() )
+        return -1;
+
+    poLS->getPoint(i, &p0);
+    poLS->getPoint(i+1, &p1);
+    poLS->getPoint(i+2, &p2);
+    double R_1, cx_1, cy_1, alpha0_1, alpha1_1, alpha2_1;
+    if( !(OGRGeometryFactory::GetCurveParmeters(p0.getX(), p0.getY(),
+                            p1.getX(), p1.getY(),
+                            p2.getX(), p2.getY(),
+                            R_1, cx_1, cy_1,
+                            alpha0_1, alpha1_1, alpha2_1) &&
+          fabs(alpha2_1 - alpha0_1) < 2 * 20.0 / 180.0 * M_PI) )
+    {
+        return -1;
+    }
+
+    int j;
+    double dfDeltaAlpha10 = alpha1_1 - alpha0_1;
+    double dfDeltaAlpha21 = alpha2_1 - alpha1_1;
+    double dfMaxDeltaAlpha = MAX(fabs(dfDeltaAlpha10),
+                                    fabs(dfDeltaAlpha21));
+    GUInt32 nAlphaRatioRef =
+            OGRGF_GetHiddenValue(p1.getX(), p1.getY()) |
+        (OGRGF_GetHiddenValue(p2.getX(), p2.getY()) << HIDDEN_ALPHA_HALF_WIDTH);
+    int bFoundFFFFFFFFPattern = FALSE;
+    int bFoundReversedAlphaRatioRef = FALSE;
+    int bValidAlphaRatio = (nAlphaRatioRef > 0 && nAlphaRatioRef < 0xFFFFFFFF);
+    int nCountValidAlphaRatio = 1;
+
+    double dfScale = MAX(1, R_1);
+    dfScale = MAX(dfScale, fabs(cx_1));
+    dfScale = MAX(dfScale, fabs(cy_1));
+    dfScale = pow(10.0, ceil(log10(dfScale)));
+    double dfInvScale  = 1.0 / dfScale ;
+
+    int bInitialConstantStep =
+        (fabs(dfDeltaAlpha10 - dfDeltaAlpha21) / dfMaxDeltaAlpha) < 1e-4;
+    double dfDeltaEpsilon = ( bInitialConstantStep ) ?
+        dfMaxDeltaAlpha * 1e-4 : dfMaxDeltaAlpha/10;
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+    printf("----------------------------\n");
+    printf("Curve beginning at offset i = %d\n", i);
+    printf("Initial alpha ratio = %u\n", nAlphaRatioRef);
+    printf("Initial R = %.16g, cx = %.16g, cy = %.16g\n", R_1, cx_1, cy_1);
+    printf("dfScale = %f\n", dfScale);
+    printf("bInitialConstantStep = %d, "
+            "fabs(dfDeltaAlpha10 - dfDeltaAlpha21)=%.8g, "
+            "dfMaxDeltaAlpha = %.8f, "
+            "dfDeltaEpsilon = %.8f (%.8f)\n",
+            bInitialConstantStep,
+            fabs(dfDeltaAlpha10 - dfDeltaAlpha21),
+            dfMaxDeltaAlpha,
+            dfDeltaEpsilon, 1.0 / 180.0 * M_PI);
+#endif
+    int iMidPoint = -1;
+    double dfLastValidAlpha = alpha2_1;
+
+    double dfLastLogRelDiff = 0;
+
+    for(j = i + 1; j + 2 < poLS->getNumPoints(); j++ )
+    {
+        poLS->getPoint(j, &p1);
+        poLS->getPoint(j+1, &p2);
+        poLS->getPoint(j+2, &p3);
+        double R_2, cx_2, cy_2, alpha0_2, alpha1_2, alpha2_2;
+        /* Check that the new candidate arc shares the same */
+        /* radius, center and winding order */
+        if( !(OGRGeometryFactory::GetCurveParmeters(p1.getX(), p1.getY(),
+                                p2.getX(), p2.getY(),
+                                p3.getX(), p3.getY(),
+                                R_2, cx_2, cy_2,
+                                alpha0_2, alpha1_2, alpha2_2)) )
+        {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("End of curve at j=%d\n : straight line", j);
+#endif
+            break;
+        }
+
+        double dfRelDiffR = fabs(R_1 - R_2) * dfInvScale;
+        double dfRelDiffCx = fabs(cx_1 - cx_2) * dfInvScale;
+        double dfRelDiffCy = fabs(cy_1 - cy_2) * dfInvScale;
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("j=%d: R = %.16g, cx = %.16g, cy = %.16g, "
+                "rel_diff_R=%.8g rel_diff_cx=%.8g rel_diff_cy=%.8g\n",
+                j, R_2, cx_2, cy_2, dfRelDiffR, dfRelDiffCx, dfRelDiffCy);
+#endif
+
+        if( //(dfRelDiffR > 1e-8 || dfRelDiffCx > 1e-8 || dfRelDiffCy > 1e-8) ||
+            (dfRelDiffR > 1e-6 && dfRelDiffCx > 1e-6 && dfRelDiffCy > 1e-6) ||
+            dfDeltaAlpha10 * (alpha1_2 - alpha0_2) < 0 )
+        {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("End of curve at j=%d\n", j);
+#endif
+            break;
+        }
+
+        if( dfRelDiffR > 0 && dfRelDiffCx > 0 && dfRelDiffCy > 0 )
+        {
+            double dfLogRelDiff = MIN(MIN(fabs(log10(dfRelDiffR)),
+                                          fabs(log10(dfRelDiffCx))),
+                                      fabs(log10(dfRelDiffCy)));
+            /*printf("dfLogRelDiff = %f, dfLastLogRelDiff=%f, "
+                     "dfLogRelDiff - dfLastLogRelDiff=%f\n",
+                     dfLogRelDiff, dfLastLogRelDiff,
+                     dfLogRelDiff - dfLastLogRelDiff);*/
+            if( dfLogRelDiff > 0 && dfLastLogRelDiff > 0 &&
+                dfLastLogRelDiff >= 8 && dfLogRelDiff <= 8 &&
+                dfLogRelDiff < dfLastLogRelDiff - 2 )
+            {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                printf("End of curve at j=%d. Significant different in "
+                       "relative error w.r.t previous points\n", j);
+#endif
+                break;
+            }
+            dfLastLogRelDiff = dfLogRelDiff;
+        }
+
+        double dfStep10 = fabs(alpha1_2 - alpha0_2);
+        double dfStep21 = fabs(alpha2_2 - alpha1_2);
+        /* Check that the angle step is consistant with the original */
+        /* step. */
+        if( !(dfStep10 < 2 * dfMaxDeltaAlpha && dfStep21 < 2 * dfMaxDeltaAlpha) )
+        {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("End of curve at j=%d: dfStep10=%f, dfStep21=%f, 2*dfMaxDeltaAlpha=%f\n",
+                    j, dfStep10, dfStep21, 2 * dfMaxDeltaAlpha);
+#endif
+            break;
+        }
+
+        if( bValidAlphaRatio && j > i + 1 && (i % 2) != (j % 2 ) )
+        {
+            GUInt32 nAlphaRatioReversed =
+                (OGRGF_GetHiddenValue(p1.getX(), p1.getY()) << HIDDEN_ALPHA_HALF_WIDTH) |
+                (OGRGF_GetHiddenValue(p2.getX(), p2.getY()));
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("j=%d, nAlphaRatioReversed = %u\n",
+                        j, nAlphaRatioReversed);
+#endif
+            if( !bFoundFFFFFFFFPattern && nAlphaRatioReversed == 0xFFFFFFFF )
+            {
+                bFoundFFFFFFFFPattern = TRUE;
+                nCountValidAlphaRatio ++;
+            }
+            else if( bFoundFFFFFFFFPattern && !bFoundReversedAlphaRatioRef &&
+                        nAlphaRatioReversed == 0xFFFFFFFF )
+            {
+                nCountValidAlphaRatio ++;
+            }
+            else if( bFoundFFFFFFFFPattern && !bFoundReversedAlphaRatioRef &&
+                        nAlphaRatioReversed == nAlphaRatioRef )
+            {
+                bFoundReversedAlphaRatioRef = TRUE;
+                nCountValidAlphaRatio ++;
+            }
+            else
+            {
+                if( bInitialConstantStep &&
+                    fabs(dfLastValidAlpha - alpha0_1) >= M_PI &&
+                    nCountValidAlphaRatio > 10 )
+                {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                    printf("End of curve at j=%d: "
+                            "fabs(dfLastValidAlpha - alpha0_1)=%f, "
+                            "nCountValidAlphaRatio=%d\n",
+                            j,
+                            fabs(dfLastValidAlpha - alpha0_1),
+                            nCountValidAlphaRatio);
+#endif
+                    if( dfLastValidAlpha - alpha0_1 > 0 )
+                    {
+                        while( dfLastValidAlpha - alpha0_1 - dfMaxDeltaAlpha - M_PI > -dfMaxDeltaAlpha/10 )
+                        {
+                            dfLastValidAlpha -= dfMaxDeltaAlpha;
+                            j --;
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                            printf("--> corrected as fabs(dfLastValidAlpha - alpha0_1)=%f, j=%d\n",
+                                fabs(dfLastValidAlpha - alpha0_1), j);
+#endif
+                        }
+                    }
+                    else
+                    {
+                        while( dfLastValidAlpha - alpha0_1 + dfMaxDeltaAlpha + M_PI < dfMaxDeltaAlpha/10 )
+                        {
+                            dfLastValidAlpha += dfMaxDeltaAlpha;
+                            j --;
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                            printf("--> corrected as fabs(dfLastValidAlpha - alpha0_1)=%f, j=%d\n",
+                                fabs(dfLastValidAlpha - alpha0_1), j);
+#endif
+                        }
+                    }
+                    poLS->getPoint(j+1, &p2);
+                    break;
+                }
+
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                printf("j=%d, nAlphaRatioReversed = %u --> unconsistant values accross arc. Don't use it\n",
+                        j, nAlphaRatioReversed);
+#endif
+                bValidAlphaRatio = FALSE;
+            }
+        }
+
+        /* Correct current end angle, consistently with start angle */
+        dfLastValidAlpha = OGRGF_FixAngle(alpha0_1, alpha1_1, alpha2_2);
+
+        /* Try to detect the precise intermediate point of the */
+        /* arc circle by detecting irregular angle step */
+        /* This is OK if we don't detect the right point or fail */
+        /* to detect it */
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("j=%d A(0,1)-maxDelta=%.8f A(1,2)-maxDelta=%.8f "
+                "x1=%.8f y1=%.8f x2=%.8f y2=%.8f x3=%.8f y3=%.8f\n",
+                j, fabs(dfStep10 - dfMaxDeltaAlpha), fabs(dfStep21 - dfMaxDeltaAlpha),
+                p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());
+#endif
+        if( j > i + 1 && iMidPoint < 0 && dfDeltaEpsilon < 1.0 / 180.0 * M_PI )
+        {
+            if( fabs(dfStep10 - dfMaxDeltaAlpha) > dfDeltaEpsilon )
+                iMidPoint = j + ((bInitialConstantStep) ? 0 : 1);
+            else if( fabs(dfStep21 - dfMaxDeltaAlpha) > dfDeltaEpsilon )
+                iMidPoint = j + ((bInitialConstantStep) ? 1 : 2);
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            if( iMidPoint >= 0 )
+            {
+                OGRPoint pMid;
+                poLS->getPoint(iMidPoint, &pMid);
+                printf("Midpoint detected at j = %d, iMidPoint = %d, x=%.8f y=%.8f\n",
+                        j, iMidPoint, pMid.getX(), pMid.getY());
+            }
+#endif
+        }
+    }
+
+    /* Take a minimum threshold of consecutive points */
+    /* on the arc to avoid false positives */
+    if( j < i + 3 )
+        return -1;
+
+    bValidAlphaRatio &= (bFoundFFFFFFFFPattern && bFoundReversedAlphaRatioRef );
+
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+    printf("bValidAlphaRatio=%d bFoundFFFFFFFFPattern=%d, bFoundReversedAlphaRatioRef=%d\n",
+            bValidAlphaRatio, bFoundFFFFFFFFPattern, bFoundReversedAlphaRatioRef);
+    printf("alpha0_1=%f dfLastValidAlpha=%f\n",
+            alpha0_1, dfLastValidAlpha);
+#endif
+
+    if( poLSNew != NULL )
+    {
+        double dfScale2 = MAX(1, fabs(p0.getX()));
+        dfScale2 = MAX(dfScale, fabs(p0.getY()));
+        /* Not strictly necessary, but helps having 'clean' lines without duplicated points */
+        if( fabs(poLSNew->getX(poLSNew->getNumPoints()-1) - p0.getX()) / dfScale2 > 1e-8 ||
+            fabs(poLSNew->getY(poLSNew->getNumPoints()-1) - p0.getY()) / dfScale2 > 1e-8 )
+            poLSNew->addPoint(&p0);
+        if( poLSNew->getNumPoints() >= 2 )
+        {
+            if( poCC == NULL )
+                poCC = new OGRCompoundCurve();
+            poCC->addCurveDirectly(poLSNew);
+        }
+        else
+            delete poLSNew;
+        poLSNew = NULL;
+    }
+
+    if( poCS == NULL )
+    {
+        poCS = new OGRCircularString();
+        poCS->addPoint(&p0);
+    }
+
+    OGRPoint* poFinalPoint =
+            ( j + 2 >= poLS->getNumPoints() ) ? &p3 : &p2;
+
+    double dfXMid = 0.0, dfYMid = 0.0, dfZMid = 0.0;
+    if( bValidAlphaRatio )
+    {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("Using alpha ratio...\n");
+#endif
+        double dfAlphaMid;
+        if( OGRGF_NeedSwithArcOrder(p0.getX(),p0.getY(),
+                                    poFinalPoint->getX(),
+                                    poFinalPoint->getY()) )
+        {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("Switching angles\n");
+#endif
+            dfAlphaMid = dfLastValidAlpha + nAlphaRatioRef *
+                    (alpha0_1 - dfLastValidAlpha) / HIDDEN_ALPHA_SCALE;
+            dfAlphaMid = OGRGF_FixAngle(alpha0_1, dfLastValidAlpha, dfAlphaMid);
+        }
+        else
+        {
+            dfAlphaMid = alpha0_1 + nAlphaRatioRef *
+                    (dfLastValidAlpha - alpha0_1) / HIDDEN_ALPHA_SCALE;
+        }
+
+        dfXMid = cx_1 + R_1 * cos(dfAlphaMid);
+        dfYMid = cy_1 + R_1 * sin(dfAlphaMid);
+
+#define IS_ALMOST_INTEGER(x)  ((fabs((x)-floor((x)+0.5)))<1e-8)
+
+        if( poLS->getCoordinateDimension() == 3 )
+        {
+            double dfLastAlpha = 0.0;
+            double dfLastZ = 0.0;
+            int k;
+            for( k = i; k < j+2; k++ )
+            {
+                OGRPoint p;
+                poLS->getPoint(k, &p);
+                double dfAlpha = atan2(p.getY() - cy_1, p.getX() - cx_1);
+                dfAlpha = OGRGF_FixAngle(alpha0_1, dfLastValidAlpha, dfAlpha);
+                if( k > i && ((dfAlpha < dfLastValidAlpha && dfAlphaMid < dfAlpha) ||
+                              (dfAlpha > dfLastValidAlpha && dfAlphaMid > dfAlpha)) )
+                {
+                    double dfRatio = ( dfAlphaMid - dfLastAlpha ) / ( dfAlpha - dfLastAlpha );
+                    dfZMid = (1 - dfRatio) * dfLastZ + dfRatio * p.getZ();
+                    break;
+                }
+                dfLastAlpha = dfAlpha;
+                dfLastZ = p.getZ();
+            }
+            if( k == j + 2 )
+                dfZMid = dfLastZ;
+            if( IS_ALMOST_INTEGER(dfZMid) )
+                dfZMid = (int)floor(dfZMid+0.5);
+        }
+
+        /* A few rounding strategies in case the mid point was at "exact" coordinates */
+        if( R_1 > 1e-5 )
+        {
+            int bStartEndInteger = ( IS_ALMOST_INTEGER(p0.getX()) &&
+                                     IS_ALMOST_INTEGER(p0.getY()) &&
+                                     IS_ALMOST_INTEGER(poFinalPoint->getX()) &&
+                                     IS_ALMOST_INTEGER(poFinalPoint->getY()) );
+            if( bStartEndInteger &&
+                fabs(dfXMid - floor(dfXMid+0.5)) / dfScale < 1e-4 &&
+                fabs(dfYMid - floor(dfYMid+0.5)) / dfScale < 1e-4 )
+            {
+                dfXMid = (int)floor(dfXMid+0.5);
+                dfYMid = (int)floor(dfYMid+0.5);
+                // Sometimes rounding to closest is not best approach
+                // Try neighbouring integers to look for the one that
+                // minimize the error w.r.t to the arc center
+                // But only do that if the radius is greater than
+                // the magnitude of the delta that we will try !
+                double dfBestRError = fabs(R_1 - DISTANCE(dfXMid,dfYMid,cx_1,cy_1));
+                int iBestX = 0, iBestY = 0;
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                printf("initial_error=%f\n", dfBestRError);
+#endif
+                if( dfBestRError > 0.001 && R_1 > 2 )
+                {
+                    int nSearchRadius = 1;
+                    // Extend the search radius if the arc circle radius
+                    // is much higher than the coordinate values
+                    double dfMaxCoords = MAX(fabs(p0.getX()), fabs(p0.getY()));
+                    dfMaxCoords = MAX(dfMaxCoords, poFinalPoint->getX());
+                    dfMaxCoords = MAX(dfMaxCoords, poFinalPoint->getY());
+                    dfMaxCoords = MAX(dfMaxCoords, dfXMid);
+                    dfMaxCoords = MAX(dfMaxCoords, dfYMid);
+                    if( R_1 > dfMaxCoords * 1000 )
+                        nSearchRadius = 100;
+                    else if( R_1 > dfMaxCoords * 10 )
+                        nSearchRadius = 10;
+                    for(int iY=-nSearchRadius;iY<=nSearchRadius;iY++)
+                    {
+                        for(int iX=-nSearchRadius;iX<=nSearchRadius;iX ++)
+                        {
+                            double dfCandidateX = dfXMid+iX;
+                            double dfCandidateY = dfYMid+iY;
+                            if( fabs(dfCandidateX - p0.getX()) < 1e-8 &&
+                                fabs(dfCandidateY - p0.getY()) < 1e-8 )
+                                continue;
+                            if( fabs(dfCandidateX - poFinalPoint->getX()) < 1e-8 &&
+                                fabs(dfCandidateY - poFinalPoint->getY()) < 1e-8 )
+                                continue;
+                            double dfRError = fabs(R_1 - DISTANCE(dfCandidateX,dfCandidateY,cx_1,cy_1));
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+                            printf("x=%d y=%d error=%f besterror=%f\n",
+                                    (int)(dfXMid+iX),(int)(dfYMid+iY),dfRError,dfBestRError);
+#endif
+                            if( dfRError < dfBestRError )
+                            {
+                                iBestX = iX;
+                                iBestY = iY;
+                                dfBestRError = dfRError;
+                            }
+                        }
+                    }
+                }
+                dfXMid += iBestX;
+                dfYMid += iBestY;
+            }
+            else
+            {
+                /* Limit the number of significant figures in decimal representation */
+                if( fabs(dfXMid) < 100000000 )
+                {
+                    dfXMid = ((GIntBig)floor(dfXMid * 100000000+0.5)) / 100000000.0;
+                }
+                if( fabs(dfYMid) < 100000000 )
+                {
+                    dfYMid = ((GIntBig)floor(dfYMid * 100000000+0.5)) / 100000000.0;
+                }
+            }
+        }
+
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("dfAlphaMid=%f, x_mid = %f, y_mid = %f\n", dfLastValidAlpha, dfXMid, dfYMid);
+#endif
+    }
+
+    /* If this is a full circle of a non-polygonal zone, we must */
+    /* use a 5-point representation to keep the winding order */
+    if( p0.Equals(poFinalPoint) &&
+        !EQUAL(poLS->getGeometryName(), "LINEARRING") )
+    {
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("Full circle of a non-polygonal zone\n");
+#endif
+        poLS->getPoint((i + j + 2) / 4, &p1);
+        poCS->addPoint(&p1);
+        if( bValidAlphaRatio )
+        {
+            p1.setX( dfXMid );
+            p1.setY( dfYMid );
+            if( poLS->getCoordinateDimension() == 3 )
+                p1.setZ( dfZMid );
+        }
+        else
+        {
+            poLS->getPoint((i + j + 1) / 2, &p1);
+        }
+        poCS->addPoint(&p1);
+        poLS->getPoint(3 * (i + j + 2) / 4, &p1);
+        poCS->addPoint(&p1);
+    }
+
+    else if( bValidAlphaRatio )
+    {
+        p1.setX( dfXMid );
+        p1.setY( dfYMid );
+        if( poLS->getCoordinateDimension() == 3 )
+            p1.setZ( dfZMid );
+        poCS->addPoint(&p1);
+    }
+
+    /* If we have found a candidate for a precise intermediate */
+    /* point, use it */
+    else if( iMidPoint >= 1 && iMidPoint < j )
+    {
+        poLS->getPoint(iMidPoint, &p1);
+        poCS->addPoint(&p1);
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+        printf("Using detected midpoint...\n");
+        printf("x_mid = %f, y_mid = %f\n", p1.getX(), p1.getY());
+#endif
+        }
+        /* Otherwise pick up the mid point between both extremities */
+        else
+        {
+            poLS->getPoint((i + j + 1) / 2, &p1);
+            poCS->addPoint(&p1);
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+            printf("Pickup 'random' midpoint at index=%d...\n", (i + j + 1) / 2);
+            printf("x_mid = %f, y_mid = %f\n", p1.getX(), p1.getY());
+#endif
+        }
+        poCS->addPoint(poFinalPoint);
+
+#ifdef VERBOSE_DEBUG_CURVEFROMLINESTRING
+    printf("----------------------------\n");
+#endif
+
+    if( j + 2 >= poLS->getNumPoints() )
+        return -2;
+    return j + 1;
+}
+
+/************************************************************************/
+/*                        curveFromLineString()                         */
+/************************************************************************/
+
+/**
+ * \brief Try to convert a linestring approximating curves into a curve.
+ *
+ * This method can return a COMPOUNDCURVE, a CIRCULARSTRING or a LINESTRING.
+ *
+ * This method is the reverse of curveFromLineString().
+ *
+ * @param poLS handle to the geometry to convert.
+ * @param papszOptions options as a null-terminated list of strings.
+ *                     Unused for now. Must be set to NULL.
+ *
+ * @return the converted geometry (ownership to caller).
+ *
+ * @since GDAL 2.0
+ */
+
+OGRCurve* OGRGeometryFactory::curveFromLineString(const OGRLineString* poLS,
+                                                  CPL_UNUSED const char*const* papszOptions)
+{
+    OGRCompoundCurve* poCC = NULL;
+    OGRCircularString* poCS = NULL;
+    OGRLineString* poLSNew = NULL;
+    for(int i=0; i< poLS->getNumPoints(); /* nothing */)
+    {
+        int iNewI = OGRGF_DetectArc(poLS, i, poCC, poCS, poLSNew);
+        if( iNewI == -2 )
+            break;
+        if( iNewI >= 0 )
+        {
+            i = iNewI;
+            continue;
+        }
+
+        if( poCS != NULL )
+        {
+            if( poCC == NULL )
+                poCC = new OGRCompoundCurve();
+            poCC->addCurveDirectly(poCS);
+            poCS = NULL;
+        }
+
+        OGRPoint p;
+        poLS->getPoint(i, &p);
+        if( poLSNew == NULL )
+        {
+            poLSNew = new OGRLineString();
+            poLSNew->addPoint(&p);
+        }
+        /* Not strictly necessary, but helps having 'clean' lines without duplicated points */
+        else
+        {
+            double dfScale = MAX(1, fabs(p.getX()));
+            dfScale = MAX(dfScale, fabs(p.getY()));
+            if( fabs(poLSNew->getX(poLSNew->getNumPoints()-1) - p.getX()) / dfScale > 1e-8 ||
+                fabs(poLSNew->getY(poLSNew->getNumPoints()-1) - p.getY()) / dfScale > 1e-8 )
+            {
+                poLSNew->addPoint(&p);
+            }
+        }
+
+        i++ ;
+    }
+
+    OGRCurve* poRet;
+
+    if( poLSNew != NULL && poLSNew->getNumPoints() < 2 )
+    {
+        delete poLSNew;
+        poLSNew = NULL;
+        if( poCC != NULL )
+        {
+            if( poCC->getNumCurves() == 1 )
+            {
+                poRet = poCC->stealCurve(0);
+                delete poCC;
+                poCC = NULL;
+            }
+            else
+                poRet = poCC;
+        }
+        else
+            poRet = (OGRCurve*)poLS->clone();
+    }
+    else if( poCC != NULL )
+    {
+        poCC->addCurveDirectly(poLSNew ? (OGRCurve*)poLSNew : (OGRCurve*)poCS);
+        poRet = poCC;
+    }
+    else if( poLSNew != NULL )
+        poRet = poLSNew;
+    else if( poCS != NULL )
+        poRet = poCS;
+    else
+        poRet = (OGRCurve*)poLS->clone();
+
+    poRet->assignSpatialReference( poLS->getSpatialReference() );
+
+    return poRet;
+}
diff --git a/ogr/ogrgeomfielddefn.cpp b/ogr/ogrgeomfielddefn.cpp
index fb89508..167f04a 100644
--- a/ogr/ogrgeomfielddefn.cpp
+++ b/ogr/ogrgeomfielddefn.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomfielddefn.cpp 27110 2014-03-28 21:29:20Z rouault $
+ * $Id: ogrgeomfielddefn.cpp 28806 2015-03-28 14:37:47Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRGeomFieldDefn class implementation.
@@ -30,8 +30,9 @@
 #include "ogr_feature.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrgeomfielddefn.cpp 27110 2014-03-28 21:29:20Z rouault $");
+CPL_CVSID("$Id: ogrgeomfielddefn.cpp 28806 2015-03-28 14:37:47Z rouault $");
 
 /************************************************************************/
 /*                         OGRGeomFieldDefn()                           */
@@ -72,6 +73,7 @@ OGRGeomFieldDefn::OGRGeomFieldDefn( OGRGeomFieldDefn *poPrototype )
 {
     Initialize( poPrototype->GetNameRef(), poPrototype->GetType() );
     SetSpatialRef( poPrototype->GetSpatialRef() );
+    SetNullable( poPrototype->IsNullable() );
 }
 
 /************************************************************************/
@@ -108,6 +110,7 @@ void OGRGeomFieldDefn::Initialize( const char * pszNameIn,
     eGeomType = eTypeIn;
     poSRS = NULL;
     bIgnore = FALSE;
+    bNullable = TRUE;
 }
 
 /************************************************************************/
@@ -218,6 +221,12 @@ const char *OGR_GFld_GetNameRef( OGRGeomFieldDefnH hDefn )
 
 {
     VALIDATE_POINTER1( hDefn, "OGR_GFld_GetNameRef", "" );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_GFld_GetXXXX(hDefn, "GetNameRef");
+#endif
+
     return ((OGRGeomFieldDefn *) hDefn)->GetNameRef();
 }
 
@@ -255,7 +264,18 @@ OGRwkbGeometryType OGR_GFld_GetType( OGRGeomFieldDefnH hDefn )
 
 {
     VALIDATE_POINTER1( hDefn, "OGR_GFld_GetType", wkbUnknown );
-    return ((OGRGeomFieldDefn *) hDefn)->GetType();
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_GFld_GetXXXX(hDefn, "GetType");
+#endif
+
+    OGRwkbGeometryType eType = ((OGRGeomFieldDefn *) hDefn)->GetType();
+    if( OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag() )
+    {
+        eType = OGR_GT_GetLinear(eType);
+    }
+    return eType;
 }
 
 /************************************************************************/
@@ -416,6 +436,12 @@ OGRSpatialReference* OGRGeomFieldDefn::GetSpatialRef()
 OGRSpatialReferenceH OGR_GFld_GetSpatialRef( OGRGeomFieldDefnH hDefn )
 {
     VALIDATE_POINTER1( hDefn, "OGR_GFld_GetSpatialRef", NULL );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_GFld_GetXXXX(hDefn, "GetSpatialRef");
+#endif
+
     return (OGRSpatialReferenceH) ((OGRGeomFieldDefn *) hDefn)->GetSpatialRef();
 }
 
@@ -484,7 +510,8 @@ void OGR_GFld_SetSpatialRef( OGRGeomFieldDefnH hDefn, OGRSpatialReferenceH hSRS
 int OGRGeomFieldDefn::IsSame( OGRGeomFieldDefn * poOtherFieldDefn )
 {
     if( !(strcmp(GetNameRef(), poOtherFieldDefn->GetNameRef()) == 0 &&
-                 GetType() == poOtherFieldDefn->GetType()) )
+                 GetType() == poOtherFieldDefn->GetType() &&
+                 IsNullable() == poOtherFieldDefn->IsNullable()) )
         return FALSE;
     OGRSpatialReference* poMySRS = GetSpatialRef();
     OGRSpatialReference* poOtherSRS = poOtherFieldDefn->GetSpatialRef();
@@ -492,3 +519,101 @@ int OGRGeomFieldDefn::IsSame( OGRGeomFieldDefn * poOtherFieldDefn )
             (poMySRS != NULL && poOtherSRS != NULL &&
              poMySRS->IsSame(poOtherSRS)));
 }
+
+/************************************************************************/
+/*                             IsNullable()                             */
+/************************************************************************/
+
+/**
+ * \fn int OGRGeomFieldDefn::IsNullable() const
+ *
+ * \brief Return whether this geometry field can receive null values.
+ *
+ * By default, fields are nullable.
+ *
+ * Even if this method returns FALSE (i.e not-nullable field), it doesn't mean
+ * that OGRFeature::IsFieldSet() will necessary return TRUE, as fields can be
+ * temporary unset and null/not-null validation is usually done when
+ * OGRLayer::CreateFeature()/SetFeature() is called.
+ *
+ * Note that not-nullable geometry fields might also contain 'empty' geometries.
+ *
+ * This method is the same as the C function OGR_GFld_IsNullable().
+ *
+ * @return TRUE if the field is authorized to be null.
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                         OGR_GFld_IsNullable()                        */
+/************************************************************************/
+
+/**
+ * \brief Return whether this geometry field can receive null values.
+ *
+ * By default, fields are nullable.
+ *
+ * Even if this method returns FALSE (i.e not-nullable field), it doesn't mean
+ * that OGRFeature::IsFieldSet() will necessary return TRUE, as fields can be
+ * temporary unset and null/not-null validation is usually done when
+ * OGRLayer::CreateFeature()/SetFeature() is called.
+ *
+ * Note that not-nullable geometry fields might also contain 'empty' geometries.
+ *
+ * This method is the same as the C++ method OGRGeomFieldDefn::IsNullable().
+ *
+ * @param hDefn handle to the field definition
+ * @return TRUE if the field is authorized to be null.
+ * @since GDAL 2.0
+ */
+
+int OGR_GFld_IsNullable( OGRGeomFieldDefnH hDefn )
+{
+    return ((OGRGeomFieldDefn *) hDefn)->IsNullable();
+}
+
+/************************************************************************/
+/*                            SetNullable()                             */
+/************************************************************************/
+
+/**
+ * \fn void OGRGeomFieldDefn::SetNullable( int bNullableIn );
+ *
+ * \brief Set whether this geometry field can receive null values.
+ *
+ * By default, fields are nullable, so this method is generally called with FALSE
+ * to set a not-null constraint.
+ *
+ * Drivers that support writing not-null constraint will advertize the
+ * GDAL_DCAP_NOTNULL_GEOMFIELDS driver metadata item.
+ *
+ * This method is the same as the C function OGR_GFld_SetNullable().
+ *
+ * @param bNullableIn FALSE if the field must have a not-null constraint.
+ * @since GDAL 2.0
+ */
+
+/************************************************************************/
+/*                        OGR_GFld_SetNullable()                        */
+/************************************************************************/
+
+/**
+ * \brief Set whether this geometry field can receive null values.
+ *
+ * By default, fields are nullable, so this method is generally called with FALSE
+ * to set a not-null constraint.
+ *
+ * Drivers that support writing not-null constraint will advertize the
+ * GDAL_DCAP_NOTNULL_GEOMFIELDS driver metadata item.
+ *
+ * This method is the same as the C++ method OGRGeomFieldDefn::SetNullable().
+ *
+ * @param hDefn handle to the field definition
+ * @param bNullableIn FALSE if the field must have a not-null constraint.
+ * @since GDAL 2.0
+ */
+
+void OGR_GFld_SetNullable( OGRGeomFieldDefnH hDefn, int bNullableIn )
+{
+    ((OGRGeomFieldDefn *) hDefn)->SetNullable( bNullableIn );
+}
diff --git a/ogr/ogrlinearring.cpp b/ogr/ogrlinearring.cpp
index 231713e..bf9ebdb 100644
--- a/ogr/ogrlinearring.cpp
+++ b/ogr/ogrlinearring.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlinearring.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrlinearring.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRLinearRing geometry class.
@@ -31,7 +31,7 @@
 #include "ogr_geometry.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrlinearring.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrlinearring.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                           OGRLinearRing()                            */
@@ -45,6 +45,7 @@ OGRLinearRing::OGRLinearRing()
 /************************************************************************/
 /*                          ~OGRLinearRing()                            */
 /************************************************************************/
+
 OGRLinearRing::~OGRLinearRing()
 
 {
@@ -103,12 +104,11 @@ int OGRLinearRing::WkbSize() const
 /*      Disable method for this class.                                  */
 /************************************************************************/
 
-OGRErr OGRLinearRing::importFromWkb( unsigned char *pabyData, int nSize ) 
+OGRErr OGRLinearRing::importFromWkb( CPL_UNUSED unsigned char *pabyData,
+                                     CPL_UNUSED  int nSize,
+                                     CPL_UNUSED OGRwkbVariant eWkbVariant ) 
 
 {
-    (void) pabyData;
-    (void) nSize;
-
     return OGRERR_UNSUPPORTED_OPERATION;
 }
 
@@ -118,15 +118,11 @@ OGRErr OGRLinearRing::importFromWkb( unsigned char *pabyData, int nSize )
 /*      Disable method for this class.                                  */
 /************************************************************************/
 
-OGRErr OGRLinearRing::exportToWkb( OGRwkbByteOrder eByteOrder, 
-                                   unsigned char * pabyData,
-                                   OGRwkbVariant eWkbVariant ) const
+OGRErr OGRLinearRing::exportToWkb( CPL_UNUSED OGRwkbByteOrder eByteOrder, 
+                                   CPL_UNUSED unsigned char * pabyData,
+                                   CPL_UNUSED OGRwkbVariant eWkbVariant ) const
 
 {
-    (void) eByteOrder;
-    (void) pabyData;
-    (void) eWkbVariant;
-
     return OGRERR_UNSUPPORTED_OPERATION;
 }
 
@@ -469,42 +465,6 @@ void OGRLinearRing::closeRings()
 }
 
 /************************************************************************/
-/*                              get_Area()                              */
-/************************************************************************/
-
-/**
- * \brief Compute area of ring.
- *
- * The area is computed according to Green's Theorem:  
- *
- * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1, 
- * assuming the last point is a duplicate of the first. 
- *
- * @return computed area.
- */
-
-double OGRLinearRing::get_Area() const
-
-{
-    double dfAreaSum = 0.0;
-    int i;
-
-    if( nPointCount < 2 )
-        return 0;
-
-    dfAreaSum = paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount-1].y);
-
-    for( i = 1; i < nPointCount-1; i++ )
-    {
-        dfAreaSum += paoPoints[i].x * (paoPoints[i+1].y - paoPoints[i-1].y);
-    }
-
-    dfAreaSum += paoPoints[nPointCount-1].x * (paoPoints[0].y - paoPoints[nPointCount-2].y);
-
-    return 0.5 * fabs(dfAreaSum);
-}
-
-/************************************************************************/
 /*                              isPointInRing()                         */
 /************************************************************************/
 
@@ -636,3 +596,37 @@ OGRBoolean OGRLinearRing::isPointOnRingBoundary(const OGRPoint* poPoint, int bTe
 
     return 0;
 }
+
+/************************************************************************/
+/*                          CastToLineString()                          */
+/************************************************************************/
+
+/**
+ * \brief Cast to line string.
+ *
+ * The passed in geometry is consumed and a new one returned .
+ * 
+ * @param poLR the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRLineString* OGRLinearRing::CastToLineString(OGRLinearRing* poLR)
+{
+    return TransferMembersAndDestroy(poLR, new OGRLineString());
+}
+
+/************************************************************************/
+/*                     GetCasterToLineString()                          */
+/************************************************************************/
+
+OGRCurveCasterToLineString OGRLinearRing::GetCasterToLineString() const {
+    return (OGRCurveCasterToLineString) OGRLinearRing::CastToLineString;
+}
+
+/************************************************************************/
+/*                        GetCasterToLinearRing()                       */
+/************************************************************************/
+
+OGRCurveCasterToLinearRing OGRLinearRing::GetCasterToLinearRing() const {
+    return (OGRCurveCasterToLinearRing) OGRGeometry::CastToIdentity;
+}
diff --git a/ogr/ogrlinestring.cpp b/ogr/ogrlinestring.cpp
index cbed43d..b56c9a4 100644
--- a/ogr/ogrlinestring.cpp
+++ b/ogr/ogrlinestring.cpp
@@ -1,8 +1,8 @@
 /******************************************************************************
- * $Id: ogrlinestring.cpp 27111 2014-03-28 21:34:19Z rouault $
+ * $Id: ogrlinestring.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
- * Purpose:  The OGRLineString geometry class.
+ * Purpose:  The OGRSimpleCurve and OGRLineString geometry classes.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -33,17 +33,13 @@
 #include <assert.h>
 #include "ogr_geos.h"
 
-CPL_CVSID("$Id: ogrlinestring.cpp 27111 2014-03-28 21:34:19Z rouault $");
+CPL_CVSID("$Id: ogrlinestring.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
-/*                           OGRLineString()                            */
+/*                           OGRSimpleCurve()                           */
 /************************************************************************/
 
-/**
- * \brief Create an empty line string.
- */
-
-OGRLineString::OGRLineString()
+OGRSimpleCurve::OGRSimpleCurve()
 
 {
     nPointCount = 0;
@@ -52,10 +48,10 @@ OGRLineString::OGRLineString()
 }
 
 /************************************************************************/
-/*                           ~OGRLineString()                           */
+/*                          ~OGRSimpleCurve()                           */
 /************************************************************************/
 
-OGRLineString::~OGRLineString()
+OGRSimpleCurve::~OGRSimpleCurve()
 
 {
     if( paoPoints != NULL )
@@ -65,49 +61,26 @@ OGRLineString::~OGRLineString()
 }
 
 /************************************************************************/
-/*                          getGeometryType()                           */
-/************************************************************************/
-
-OGRwkbGeometryType OGRLineString::getGeometryType() const
-
-{
-    if( nCoordDimension == 3 )
-        return wkbLineString25D;
-    else
-        return wkbLineString;
-}
-
-
-/************************************************************************/
 /*                            flattenTo2D()                             */
 /************************************************************************/
 
-void OGRLineString::flattenTo2D()
+void OGRSimpleCurve::flattenTo2D()
 
 {
     Make2D();
 }
 
 /************************************************************************/
-/*                          getGeometryName()                           */
-/************************************************************************/
-
-const char * OGRLineString::getGeometryName() const
-
-{
-    return "LINESTRING";
-}
-
-/************************************************************************/
 /*                               clone()                                */
 /************************************************************************/
 
-OGRGeometry *OGRLineString::clone() const
+OGRGeometry *OGRSimpleCurve::clone() const
 
 {
     OGRLineString       *poNewLineString;
 
-    poNewLineString = new OGRLineString();
+    poNewLineString = (OGRLineString*)
+            OGRGeometryFactory::createGeometry(getGeometryType());
 
     poNewLineString->assignSpatialReference( getSpatialReference() );
     poNewLineString->setPoints( nPointCount, paoPoints, padfZ );
@@ -120,27 +93,17 @@ OGRGeometry *OGRLineString::clone() const
 /*                               empty()                                */
 /************************************************************************/
 
-void OGRLineString::empty()
+void OGRSimpleCurve::empty()
 
 {
     setNumPoints( 0 );
 }
 
 /************************************************************************/
-/*                            getDimension()                            */
-/************************************************************************/
-
-int OGRLineString::getDimension() const
-
-{
-    return 1;
-}
-
-/************************************************************************/
 /*                       setCoordinateDimension()                       */
 /************************************************************************/
 
-void OGRLineString::setCoordinateDimension( int nNewDimension )
+void OGRSimpleCurve::setCoordinateDimension( int nNewDimension )
 
 {
     nCoordDimension = nNewDimension;
@@ -157,7 +120,7 @@ void OGRLineString::setCoordinateDimension( int nNewDimension )
 /*      representation including the byte order, and type information.  */
 /************************************************************************/
 
-int OGRLineString::WkbSize() const
+int OGRSimpleCurve::WkbSize() const
 
 {
     return 5 + 4 + 8 * nPointCount * getCoordinateDimension();
@@ -167,7 +130,7 @@ int OGRLineString::WkbSize() const
 /*                               Make2D()                               */
 /************************************************************************/
 
-void OGRLineString::Make2D()
+void OGRSimpleCurve::Make2D()
 
 {
     if( padfZ != NULL )
@@ -182,7 +145,7 @@ void OGRLineString::Make2D()
 /*                               Make3D()                               */
 /************************************************************************/
 
-void OGRLineString::Make3D()
+void OGRSimpleCurve::Make3D()
 
 {
     if( padfZ == NULL )
@@ -208,7 +171,7 @@ void OGRLineString::Make3D()
  * @param poPoint a point to initialize with the fetched point.
  */
 
-void    OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
+void    OGRSimpleCurve::getPoint( int i, OGRPoint * poPoint ) const
 
 {
     assert( i >= 0 );
@@ -223,7 +186,7 @@ void    OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
 }
 
 /**
- * \fn int OGRLineString::getNumPoints() const;
+ * \fn int OGRSimpleCurve::getNumPoints() const;
  *
  * \brief Fetch vertex count.
  *
@@ -233,7 +196,7 @@ void    OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
  */
 
 /**
- * \fn double OGRLineString::getX( int iVertex ) const;
+ * \fn double OGRSimpleCurve::getX( int iVertex ) const;
  *
  * \brief Get X at vertex.
  *
@@ -246,7 +209,7 @@ void    OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
  */
 
 /**
- * \fn double OGRLineString::getY( int iVertex ) const;
+ * \fn double OGRSimpleCurve::getY( int iVertex ) const;
  *
  * \brief Get Y at vertex.
  *
@@ -274,7 +237,7 @@ void    OGRLineString::getPoint( int i, OGRPoint * poPoint ) const
  * @return Z value.
  */
 
-double OGRLineString::getZ( int iVertex ) const
+double OGRSimpleCurve::getZ( int iVertex ) const
 
 {
     if( padfZ != NULL && iVertex >= 0 && iVertex < nPointCount 
@@ -300,7 +263,7 @@ double OGRLineString::getZ( int iVertex ) const
  * @param nNewPointCount the new number of points for geometry.
  */
 
-void OGRLineString::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
+void OGRSimpleCurve::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
 
 {
     if( nNewPointCount == 0 )
@@ -360,7 +323,7 @@ void OGRLineString::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
  *
  * If iPoint is larger than the number of necessary the number of existing
  * points in the line string, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * There is no SFCOM analog to this method.
  * 
@@ -368,7 +331,7 @@ void OGRLineString::setNumPoints( int nNewPointCount, int bZeroizeNewContent )
  * @param poPoint the value to assign to the vertex.
  */
 
-void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
+void OGRSimpleCurve::setPoint( int iPoint, OGRPoint * poPoint )
 
 {
     if (poPoint->getCoordinateDimension() < 3)
@@ -386,7 +349,7 @@ void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
  *
  * If iPoint is larger than the number of necessary the number of existing
  * points in the line string, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  * 
  * There is no SFCOM analog to this method.
  *
@@ -396,7 +359,7 @@ void OGRLineString::setPoint( int iPoint, OGRPoint * poPoint )
  * @param zIn input Z coordinate to assign (defaults to zero).
  */
 
-void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn )
+void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn, double zIn )
 
 {
     if( getCoordinateDimension() == 2 )
@@ -423,7 +386,7 @@ void OGRLineString::setPoint( int iPoint, double xIn, double yIn, double zIn )
     }
 }
 
-void OGRLineString::setPoint( int iPoint, double xIn, double yIn )
+void OGRSimpleCurve::setPoint( int iPoint, double xIn, double yIn )
 
 {
     if( iPoint >= nPointCount )
@@ -441,7 +404,7 @@ void OGRLineString::setPoint( int iPoint, double xIn, double yIn )
 /*                                setZ()                                */
 /************************************************************************/
 
-void OGRLineString::setZ( int iPoint, double zIn )
+void OGRSimpleCurve::setZ( int iPoint, double zIn )
 {
     if( getCoordinateDimension() == 2 )
         Make3D();
@@ -472,7 +435,7 @@ void OGRLineString::setZ( int iPoint, double zIn )
  * @param poPoint the point to assign to the new vertex.
  */
 
-void OGRLineString::addPoint( OGRPoint * poPoint )
+void OGRSimpleCurve::addPoint( OGRPoint * poPoint )
 
 {
     if ( poPoint->getCoordinateDimension() < 3 )
@@ -498,13 +461,13 @@ void OGRLineString::addPoint( OGRPoint * poPoint )
  * @param z the Z coordinate to assign to the new point (defaults to zero).
  */
 
-void OGRLineString::addPoint( double x, double y, double z )
+void OGRSimpleCurve::addPoint( double x, double y, double z )
 
 {
     setPoint( nPointCount, x, y, z );
 }
 
-void OGRLineString::addPoint( double x, double y )
+void OGRSimpleCurve::addPoint( double x, double y )
 
 {
     setPoint( nPointCount, x, y );
@@ -528,7 +491,7 @@ void OGRLineString::addPoint( double x, double y )
  * @param padfZ the Z values that go with the points (optional, may be NULL).
  */
 
-void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
+void OGRSimpleCurve::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
                                double * padfZ )
 
 {
@@ -571,7 +534,7 @@ void OGRLineString::setPoints( int nPointsIn, OGRRawPoint * paoPointsIn,
  * NULL for 2D objects).
  */
 
-void OGRLineString::setPoints( int nPointsIn, double * padfX, double * padfY,
+void OGRSimpleCurve::setPoints( int nPointsIn, double * padfX, double * padfY,
                                double * padfZ )
 
 {
@@ -619,7 +582,7 @@ void OGRLineString::setPoints( int nPointsIn, double * padfX, double * padfY,
  * @param padfZ the Z values that go with the points (optional, may be NULL).
  */
 
-void OGRLineString::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
+void OGRSimpleCurve::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) const
 {
     if ( ! paoPointsOut )
         return;
@@ -663,7 +626,7 @@ void OGRLineString::getPoints( OGRRawPoint * paoPointsOut, double * padfZ ) cons
  * @since OGR 1.9.0
  */
 
-void OGRLineString::getPoints( void* pabyX, int nXStride,
+void OGRSimpleCurve::getPoints( void* pabyX, int nXStride,
                                void* pabyY, int nYStride,
                                void* pabyZ, int nZStride)  const
 {
@@ -708,7 +671,7 @@ void OGRLineString::getPoints( void* pabyX, int nXStride,
  * reversing the point ordering (first for last, etc).  
  */
 
-void OGRLineString::reversePoints()
+void OGRSimpleCurve::reversePoints()
 
 {
     int i;
@@ -748,7 +711,7 @@ void OGRLineString::reversePoints()
  * the last vertex of the other line string. 
  */
 
-void OGRLineString::addSubLineString( const OGRLineString *poOtherLine, 
+void OGRSimpleCurve::addSubLineString( const OGRLineString *poOtherLine, 
                                       int nStartVertex, int nEndVertex )
 
 {
@@ -830,54 +793,35 @@ void OGRLineString::addSubLineString( const OGRLineString *poOtherLine,
 /*      format.                                                         */
 /************************************************************************/
 
-OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
-                                     int nSize )
+OGRErr OGRSimpleCurve::importFromWkb( unsigned char * pabyData,
+                                      int nSize,
+                                      OGRwkbVariant eWkbVariant )
 
 {
     OGRwkbByteOrder     eByteOrder;
-    
-    if( nSize < 9 && nSize != -1 )
-        return OGRERR_NOT_ENOUGH_DATA;
+    int                 nDataOffset = 0;
+    int                 nNewNumPoints = 0;
+
+    OGRErr eErr = importPreambuleOfCollectionFromWkb( pabyData,
+                                                      nSize,
+                                                      nDataOffset,
+                                                      eByteOrder,
+                                                      16,
+                                                      nNewNumPoints,
+                                                      eWkbVariant );
+    if( eErr >= 0 )
+        return eErr;
 
-/* -------------------------------------------------------------------- */
-/*      Get the byte order byte.                                        */
-/* -------------------------------------------------------------------- */
-    eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
-    if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the geometry feature type.  For now we assume that          */
-/*      geometry type is between 0 and 255 so we only have to fetch     */
-/*      one byte.                                                       */
-/* -------------------------------------------------------------------- */
-    OGRBoolean bIs3D;
-    OGRwkbGeometryType eGeometryType;
-    OGRErr err = OGRReadWKBGeometryType( pabyData, &eGeometryType, &bIs3D );
-
-    if( err != OGRERR_NONE || eGeometryType != wkbLineString )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the vertex count.                                           */
-/* -------------------------------------------------------------------- */
-    int         nNewNumPoints;
-    
-    memcpy( &nNewNumPoints, pabyData + 5, 4 );
-    
-    if( OGR_SWAP( eByteOrder ) )
-        nNewNumPoints = CPL_SWAP32(nNewNumPoints);
-    
     /* Check if the wkb stream buffer is big enough to store
      * fetched number of points.
      * 16 or 24 - size of point structure
      */
-    int nPointSize = (bIs3D ? 24 : 16);
+    int nPointSize = (getCoordinateDimension() == 3 ? 24 : 16);
     if (nNewNumPoints < 0 || nNewNumPoints > INT_MAX / nPointSize)
         return OGRERR_CORRUPT_DATA;
     int nBufferMinSize = nPointSize * nNewNumPoints;
 
-    if( nSize != -1 && nBufferMinSize > nSize-9 )
+    if( nSize != -1 && nBufferMinSize > nSize )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "Length of input WKB is too small" );
@@ -887,18 +831,13 @@ OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
     setNumPoints( nNewNumPoints, FALSE );
     if (nPointCount < nNewNumPoints)
         return OGRERR_FAILURE;
-    
-    if( bIs3D )
-        Make3D();
-    else
-        Make2D();
-    
+
 /* -------------------------------------------------------------------- */
 /*      Get the vertex.                                                 */
 /* -------------------------------------------------------------------- */
     int i = 0;
     
-    if( bIs3D )
+    if( getCoordinateDimension() == 3 )
     {
         for( i = 0; i < nPointCount; i++ )
         {
@@ -922,7 +861,7 @@ OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
             CPL_SWAPDOUBLE( &(paoPoints[i].y) );
         }
 
-        if( bIs3D )
+        if( getCoordinateDimension() == 3 )
         {
             for( i = 0; i < nPointCount; i++ )
             {
@@ -940,7 +879,7 @@ OGRErr OGRLineString::importFromWkb( unsigned char * pabyData,
 /*      Build a well known binary representation of this object.        */
 /************************************************************************/
 
-OGRErr  OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
+OGRErr  OGRSimpleCurve::exportToWkb( OGRwkbByteOrder eByteOrder,
                                     unsigned char * pabyData,
                                     OGRwkbVariant eWkbVariant ) const
 
@@ -957,7 +896,9 @@ OGRErr  OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
 
     if ( eWkbVariant == wkbVariantIso )
         nGType = getIsoGeometryType();
-    
+    else if( eWkbVariant == wkbVariantPostGIS1 && wkbHasZ((OGRwkbGeometryType)nGType) )
+        nGType = (OGRwkbGeometryType)(wkbFlatten(nGType) | wkb25DBitInternalUse); /* yes we explicitely set wkb25DBit */
+
     if( eByteOrder == wkbNDR )
         nGType = CPL_LSBWORD32( nGType );
     else
@@ -1012,97 +953,24 @@ OGRErr  OGRLineString::exportToWkb( OGRwkbByteOrder eByteOrder,
 /*      `LINESTRING ( x y, x y, ...)',                                  */
 /************************************************************************/
 
-OGRErr OGRLineString::importFromWkt( char ** ppszInput )
+OGRErr OGRSimpleCurve::importFromWkt( char ** ppszInput )
 
 {
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-
-    empty();
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the ``LINESTRING'' keyword token.               */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,getGeometryName()) )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY                                                 */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
     int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
 
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
-
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style LINESTRING(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszInput = OGRWktReadToken( pszPreScan, szToken );
-
-            if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszInput;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
+    const char  *pszInput = *ppszInput;
 
 /* -------------------------------------------------------------------- */
 /*      Read the point list.                                            */
 /* -------------------------------------------------------------------- */
-    int      nMaxPoint = 0;
-
     nPointCount = 0;
 
-    pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoint,
-                                 &nPointCount );
+    int nMaxPoints = 0;
+    pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
+                                &nPointCount );
     if( pszInput == NULL )
         return OGRERR_CORRUPT_DATA;
 
@@ -1122,7 +990,42 @@ OGRErr OGRLineString::importFromWkt( char ** ppszInput )
         else
             nCoordDimension = 3;
     }
-    
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                        importFromWKTListOnly()                       */
+/*                                                                      */
+/*      Instantiate from "(x y, x y, ...)"                              */
+/************************************************************************/
+
+OGRErr OGRSimpleCurve::importFromWKTListOnly( char ** ppszInput, int bHasZ, int bHasM,
+                                              OGRRawPoint*& paoPointsIn, int& nMaxPointsIn,
+                                              double*& padfZIn )
+
+{
+    const char  *pszInput = *ppszInput;
+
+/* -------------------------------------------------------------------- */
+/*      Read the point list.                                            */
+/* -------------------------------------------------------------------- */
+    int nPointCountRead = 0;
+
+    pszInput = OGRWktReadPoints( pszInput, &paoPointsIn, &padfZIn, &nMaxPointsIn,
+                                 &nPointCountRead );
+
+    if( pszInput == NULL )
+        return OGRERR_CORRUPT_DATA;
+
+    *ppszInput = (char *) pszInput;
+
+    /* Ignore Z array when we have a POLYGON M */
+    if (bHasM && !bHasZ)
+        setPoints( nPointCountRead, paoPointsIn, NULL );
+    else
+        setPoints( nPointCountRead, paoPointsIn, padfZIn );
+
     return OGRERR_NONE;
 }
 
@@ -1133,10 +1036,11 @@ OGRErr OGRLineString::importFromWkt( char ** ppszInput )
 /*      equivelent.  This could be made alot more CPU efficient!        */
 /************************************************************************/
 
-OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
+OGRErr OGRSimpleCurve::exportToWkt( char ** ppszDstText,
+                                   OGRwkbVariant eWkbVariant ) const
 
 {
-    int         nMaxString = nPointCount * 40 * 3 + 20;
+    int         nMaxString = nPointCount * 40 * 3 + 25;
     int         nRetLen = 0;
 
 /* -------------------------------------------------------------------- */
@@ -1145,7 +1049,10 @@ OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
     if( IsEmpty() )
     {
         CPLString osEmpty;
-        osEmpty.Printf("%s EMPTY",getGeometryName());
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            osEmpty.Printf("%s Z EMPTY",getGeometryName());
+        else
+            osEmpty.Printf("%s EMPTY",getGeometryName());
         *ppszDstText = CPLStrdup(osEmpty);
         return OGRERR_NONE;
     }
@@ -1157,14 +1064,17 @@ OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
     if( *ppszDstText == NULL )
         return OGRERR_NOT_ENOUGH_MEMORY;
 
-    sprintf( *ppszDstText, "%s (", getGeometryName() );
+    if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+        sprintf( *ppszDstText, "%s Z (", getGeometryName() );
+    else
+        sprintf( *ppszDstText, "%s (", getGeometryName() );
 
     for( int i = 0; i < nPointCount; i++ )
     {
         if( nMaxString <= (int) strlen(*ppszDstText+nRetLen) + 32 + nRetLen )
         {
             CPLDebug( "OGR", 
-                      "OGRLineString::exportToWkt() ... buffer overflow.\n"
+                      "OGRSimpleCurve::exportToWkt() ... buffer overflow.\n"
                       "nMaxString=%d, strlen(*ppszDstText) = %d, i=%d\n"
                       "*ppszDstText = %s", 
                       nMaxString, (int) strlen(*ppszDstText), i, *ppszDstText );
@@ -1205,7 +1115,7 @@ OGRErr OGRLineString::exportToWkt( char ** ppszDstText ) const
 /*      For now we return a simple euclidian 2D distance.               */
 /************************************************************************/
 
-double OGRLineString::get_Length() const
+double OGRSimpleCurve::get_Length() const
 
 {
     double      dfLength = 0;
@@ -1227,7 +1137,7 @@ double OGRLineString::get_Length() const
 /*                             StartPoint()                             */
 /************************************************************************/
 
-void OGRLineString::StartPoint( OGRPoint * poPoint ) const
+void OGRSimpleCurve::StartPoint( OGRPoint * poPoint ) const
 
 {
     getPoint( 0, poPoint );
@@ -1237,7 +1147,7 @@ void OGRLineString::StartPoint( OGRPoint * poPoint ) const
 /*                              EndPoint()                              */
 /************************************************************************/
 
-void OGRLineString::EndPoint( OGRPoint * poPoint ) const
+void OGRSimpleCurve::EndPoint( OGRPoint * poPoint ) const
 
 {
     getPoint( nPointCount-1, poPoint );
@@ -1249,7 +1159,7 @@ void OGRLineString::EndPoint( OGRPoint * poPoint ) const
 /*      Get an interpolated point at some distance along the curve.     */
 /************************************************************************/
 
-void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
+void OGRSimpleCurve::Value( double dfDistance, OGRPoint * poPoint ) const
 
 {
     double      dfLength = 0;
@@ -1285,7 +1195,7 @@ void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
 
                 if( getCoordinateDimension() == 3 )
                     poPoint->setZ( padfZ[i] * (1 - dfRatio)
-                                   + padfZ[i] * dfRatio );
+                                   + padfZ[i+1] * dfRatio );
                 
                 return;
             }
@@ -1328,7 +1238,7 @@ void OGRLineString::Value( double dfDistance, OGRPoint * poPoint ) const
 #endif
 
 
-double OGRLineString::Project(const OGRPoint *poPoint) const
+double OGRSimpleCurve::Project(const OGRPoint *poPoint) const
 
 {
     double dfResult = -1;
@@ -1383,7 +1293,7 @@ double OGRLineString::Project(const OGRPoint *poPoint) const
 */
 
 
-OGRLineString* OGRLineString::getSubLine(double dfDistanceFrom, double dfDistanceTo, int bAsRatio) const
+OGRLineString* OGRSimpleCurve::getSubLine(double dfDistanceFrom, double dfDistanceTo, int bAsRatio) const
 
 {
     OGRLineString       *poNewLineString;
@@ -1560,7 +1470,7 @@ OGRLineString* OGRLineString::getSubLine(double dfDistanceFrom, double dfDistanc
 /*                            getEnvelope()                             */
 /************************************************************************/
 
-void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const
+void OGRSimpleCurve::getEnvelope( OGREnvelope * psEnvelope ) const
 
 {
     double      dfMinX, dfMinY, dfMaxX, dfMaxY;
@@ -1600,7 +1510,7 @@ void OGRLineString::getEnvelope( OGREnvelope * psEnvelope ) const
 /*                            getEnvelope()                             */
 /************************************************************************/
 
-void OGRLineString::getEnvelope( OGREnvelope3D * psEnvelope ) const
+void OGRSimpleCurve::getEnvelope( OGREnvelope3D * psEnvelope ) const
 
 {
     getEnvelope((OGREnvelope*)psEnvelope);
@@ -1632,7 +1542,7 @@ void OGRLineString::getEnvelope( OGREnvelope3D * psEnvelope ) const
 /*                               Equals()                                */
 /************************************************************************/
 
-OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const
+OGRBoolean OGRSimpleCurve::Equals( OGRGeometry * poOther ) const
 
 {
     OGRLineString       *poOLine = (OGRLineString *) poOther;
@@ -1666,7 +1576,7 @@ OGRBoolean OGRLineString::Equals( OGRGeometry * poOther ) const
 /*                             transform()                              */
 /************************************************************************/
 
-OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT )
+OGRErr OGRSimpleCurve::transform( OGRCoordinateTransformation *poCT )
 
 {
 #ifdef DISABLE_OGRGEOM_TRANSFORM
@@ -1780,16 +1690,16 @@ OGRErr OGRLineString::transform( OGRCoordinateTransformation *poCT )
 /*                               IsEmpty()                              */
 /************************************************************************/
 
-OGRBoolean OGRLineString::IsEmpty(  ) const
+OGRBoolean OGRSimpleCurve::IsEmpty(  ) const
 {
     return (nPointCount == 0);
 }
 
 /************************************************************************/
-/*                     OGRLineString::segmentize()                      */
+/*                     OGRSimpleCurve::segmentize()                      */
 /************************************************************************/
 
-void OGRLineString::segmentize( double dfMaxLength )
+void OGRSimpleCurve::segmentize( double dfMaxLength )
 {
     if (dfMaxLength <= 0)
     {
@@ -1797,6 +1707,19 @@ void OGRLineString::segmentize( double dfMaxLength )
                  "dfMaxLength must be strictly positive");
         return;
     }
+    if( nPointCount < 2 )
+        return;
+
+    /* So as to make sure that the same line followed in both directions */
+    /* result in the same segmentized line */
+    if ( paoPoints[0].x < paoPoints[nPointCount - 1].x ||
+         (paoPoints[0].x == paoPoints[nPointCount - 1].x &&
+          paoPoints[0].y < paoPoints[nPointCount - 1].y) )
+    {
+        reversePoints();
+        segmentize(dfMaxLength);
+        reversePoints();
+    }
 
     int i;
     OGRRawPoint* paoNewPoints = NULL;
@@ -1869,7 +1792,7 @@ void OGRLineString::segmentize( double dfMaxLength )
 /*                               swapXY()                               */
 /************************************************************************/
 
-void OGRLineString::swapXY()
+void OGRSimpleCurve::swapXY()
 {
     int i;
     for( i = 0; i < nPointCount; i++ )
@@ -1879,3 +1802,219 @@ void OGRLineString::swapXY()
         paoPoints[i].y = dfTemp;
     }
 }
+
+/************************************************************************/
+/*                       OGRSimpleCurvePointIterator                    */
+/************************************************************************/
+
+class OGRSimpleCurvePointIterator: public OGRPointIterator
+{
+        const OGRSimpleCurve* poSC;
+        int                   iCurPoint;
+    
+    public:
+        OGRSimpleCurvePointIterator(const OGRSimpleCurve* poSC) : poSC(poSC), iCurPoint(0) {}
+
+        virtual OGRBoolean getNextPoint(OGRPoint* p);
+};
+
+/************************************************************************/
+/*                            getNextPoint()                            */
+/************************************************************************/
+
+OGRBoolean OGRSimpleCurvePointIterator::getNextPoint(OGRPoint* p)
+{
+    if( iCurPoint >= poSC->getNumPoints() )
+        return FALSE;
+    poSC->getPoint(iCurPoint, p);
+    iCurPoint ++;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                         getPointIterator()                           */
+/************************************************************************/
+
+OGRPointIterator* OGRSimpleCurve::getPointIterator() const
+{
+    return new OGRSimpleCurvePointIterator(this);
+}
+
+/************************************************************************/
+/*                           OGRLineString()                            */
+/************************************************************************/
+
+/**
+ * \brief Create an empty line string.
+ */
+
+OGRLineString::OGRLineString()
+
+{
+}
+
+/************************************************************************/
+/*                          ~OGRLineString()                            */
+/************************************************************************/
+
+OGRLineString::~OGRLineString()
+
+{
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRLineString::getGeometryType() const
+
+{
+    if( nCoordDimension == 3 )
+        return wkbLineString25D;
+    else
+        return wkbLineString;
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRLineString::getGeometryName() const
+
+{
+    return "LINESTRING";
+}
+
+/************************************************************************/
+/*                          curveToLine()                               */
+/************************************************************************/
+
+OGRLineString* OGRLineString::CurveToLine(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
+                                          CPL_UNUSED const char* const* papszOptions) const
+{
+    return (OGRLineString*)clone();
+}
+
+/************************************************************************/
+/*                          get_LinearArea()                          */
+/************************************************************************/
+
+/**
+ * \brief Compute area of ring / closed linestring.
+ *
+ * The area is computed according to Green's Theorem:  
+ *
+ * Area is "Sum(x(i)*(y(i+1) - y(i-1)))/2" for i = 0 to pointCount-1, 
+ * assuming the last point is a duplicate of the first. 
+ *
+ * @return computed area.
+ */
+
+double OGRSimpleCurve::get_LinearArea() const
+
+{
+    double dfAreaSum;
+    int i;
+
+    if( nPointCount < 2 )
+        return 0;
+
+    dfAreaSum = paoPoints[0].x * (paoPoints[1].y - paoPoints[nPointCount-1].y);
+
+    for( i = 1; i < nPointCount-1; i++ )
+    {
+        dfAreaSum += paoPoints[i].x * (paoPoints[i+1].y - paoPoints[i-1].y);
+    }
+
+    dfAreaSum += paoPoints[nPointCount-1].x * (paoPoints[0].y - paoPoints[nPointCount-2].y);
+
+    return 0.5 * fabs(dfAreaSum);
+}
+
+/************************************************************************/
+/*                             getCurveGeometry()                       */
+/************************************************************************/
+
+OGRGeometry* OGRLineString::getCurveGeometry(const char* const* papszOptions) const
+{
+    return OGRGeometryFactory::curveFromLineString(this, papszOptions);
+}
+
+/************************************************************************/
+/*                      TransferMembersAndDestroy()                     */
+/************************************************************************/
+
+OGRLineString* OGRLineString::TransferMembersAndDestroy(
+                                            OGRLineString* poSrc,
+                                            OGRLineString* poDst)
+{
+    poDst->setCoordinateDimension(poSrc->getCoordinateDimension());
+    poDst->assignSpatialReference(poSrc->getSpatialReference());
+    poDst->nPointCount = poSrc->nPointCount;
+    poDst->paoPoints = poSrc->paoPoints;
+    poDst->padfZ = poSrc->padfZ;
+    poSrc->nPointCount = 0;
+    poSrc->paoPoints = NULL;
+    poSrc->padfZ = NULL;
+    delete poSrc;
+    return poDst;
+}
+
+/************************************************************************/
+/*                         CastToLinearRing()                           */
+/************************************************************************/
+
+/**
+ * \brief Cast to linear ring.
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poLS the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRLinearRing* OGRLineString::CastToLinearRing(OGRLineString* poLS)
+{
+    if( poLS->nPointCount < 2 || !poLS->get_IsClosed() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot convert non-closed linestring to linearring");
+        delete poLS;
+        return NULL;
+    }
+    return (OGRLinearRing*)TransferMembersAndDestroy(poLS, new OGRLinearRing());
+}
+
+/************************************************************************/
+/*                     GetCasterToLineString()                          */
+/************************************************************************/
+
+OGRCurveCasterToLineString OGRLineString::GetCasterToLineString() const {
+    return (OGRCurveCasterToLineString) OGRGeometry::CastToIdentity;
+}
+
+/************************************************************************/
+/*                        GetCasterToLinearRing()                       */
+/************************************************************************/
+
+OGRCurveCasterToLinearRing OGRLineString::GetCasterToLinearRing() const {
+    return (OGRCurveCasterToLinearRing) OGRLineString::CastToLinearRing;
+}
+
+/************************************************************************/
+/*                            get_Area()                                */
+/************************************************************************/
+
+double OGRLineString::get_Area() const
+{
+    return get_LinearArea();
+}
+
+/************************************************************************/
+/*                       get_AreaOfCurveSegments()                      */
+/************************************************************************/
+
+double OGRLineString::get_AreaOfCurveSegments() const
+{
+    return 0;
+}
diff --git a/ogr/ogrmulticurve.cpp b/ogr/ogrmulticurve.cpp
new file mode 100644
index 0000000..274f3f1
--- /dev/null
+++ b/ogr/ogrmulticurve.cpp
@@ -0,0 +1,178 @@
+/******************************************************************************
+ * $Id: ogrmulticurve.cpp 27960 2014-11-14 18:31:32Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRMultiCurve class.
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include "ogr_api.h"
+
+CPL_CVSID("$Id: ogrmulticurve.cpp 27960 2014-11-14 18:31:32Z rouault $");
+
+/************************************************************************/
+/*                            OGRMultiCurve()                           */
+/************************************************************************/
+
+/**
+ * \brief Create an empty multi curve collection.
+ */
+
+OGRMultiCurve::OGRMultiCurve()
+{
+}
+
+/************************************************************************/
+/*                           ~OGRMultiCurve()                           */
+/************************************************************************/
+
+OGRMultiCurve::~OGRMultiCurve()
+{
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRMultiCurve::getGeometryType() const
+
+{
+    if( getCoordinateDimension() == 3 )
+        return wkbMultiCurveZ;
+    else
+        return wkbMultiCurve;
+}
+
+/************************************************************************/
+/*                            getDimension()                            */
+/************************************************************************/
+
+int OGRMultiCurve::getDimension() const
+
+{
+    return 1;
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRMultiCurve::getGeometryName() const
+
+{
+    return "MULTICURVE";
+}
+
+/************************************************************************/
+/*                          isCompatibleSubType()                       */
+/************************************************************************/
+
+OGRBoolean OGRMultiCurve::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
+{
+    return OGR_GT_IsCurve(eGeomType);
+}
+
+/************************************************************************/
+/*                       addCurveDirectlyFromWkt()                      */
+/************************************************************************/
+
+OGRErr OGRMultiCurve::addCurveDirectlyFromWkt( OGRGeometry* poSelf, OGRCurve* poCurve )
+{
+    return ((OGRMultiCurve*)poSelf)->addGeometryDirectly(poCurve);
+}
+
+/************************************************************************/
+/*                           importFromWkt()                            */
+/*                                                                      */
+/*      Instantiate from well known text format.                        */
+/************************************************************************/
+
+OGRErr OGRMultiCurve::importFromWkt( char ** ppszInput )
+
+{
+    int bIsMultiCurve = (wkbFlatten(getGeometryType()) == wkbMultiCurve);
+    return importCurveCollectionFromWkt( ppszInput,
+                                         TRUE, /* bAllowEmptyComponent */
+                                         bIsMultiCurve, /* bAllowLineString */
+                                         bIsMultiCurve, /* bAllowCurve */
+                                         bIsMultiCurve, /* bAllowCompoundCurve */
+                                         addCurveDirectlyFromWkt );
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+
+OGRErr OGRMultiCurve::exportToWkt( char ** ppszDstText,
+                                   CPL_UNUSED OGRwkbVariant eWkbVariant ) const
+
+{
+    return exportToWktInternal( ppszDstText, wkbVariantIso, "LINESTRING" );
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRMultiCurve::hasCurveGeometry(int bLookForNonLinear) const
+{
+    if( bLookForNonLinear )
+        return OGRGeometryCollection::hasCurveGeometry(TRUE);
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          CastToMultiLineString()                     */
+/************************************************************************/
+
+/**
+ * \brief Cast to multi line string.
+ *
+ * This method should only be called if the multicurve actually only contains
+ * instances of OGRLineString. This can be verified if hasCurveGeometry(TRUE)
+ * returns FALSE. It is not intended to approximate circular curves. For that
+ * use getLinearGeometry().
+ * 
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure). 
+ * 
+ * @param poMS the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRMultiLineString* OGRMultiCurve::CastToMultiLineString(OGRMultiCurve* poMC)
+{
+    for(int i=0;i<poMC->nGeomCount;i++)
+    {
+        poMC->papoGeoms[i] = OGRCurve::CastToLineString( (OGRCurve*)poMC->papoGeoms[i] );
+        if( poMC->papoGeoms[i] == NULL )
+        {
+            delete poMC;
+            return NULL;
+        }
+    }
+    return (OGRMultiLineString*) TransferMembersAndDestroy(poMC, new OGRMultiLineString());
+}
diff --git a/ogr/ogrmultilinestring.cpp b/ogr/ogrmultilinestring.cpp
index 0815586..3273455 100644
--- a/ogr/ogrmultilinestring.cpp
+++ b/ogr/ogrmultilinestring.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmultilinestring.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmultilinestring.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRMultiLineString class.
@@ -31,18 +31,22 @@
 #include "ogr_geometry.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrmultilinestring.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmultilinestring.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                        OGRMultiLineString()                          */
 /************************************************************************/
 
+/**
+ * \brief Create an empty multi line string collection.
+ */
+
 OGRMultiLineString::OGRMultiLineString()
 {
 }
 
 /************************************************************************/
-/*                        ~OGRMultiLineString()                         */
+/*                       ~OGRMultiLineString()                          */
 /************************************************************************/
 
 OGRMultiLineString::~OGRMultiLineString()
@@ -63,16 +67,6 @@ OGRwkbGeometryType OGRMultiLineString::getGeometryType() const
 }
 
 /************************************************************************/
-/*                            getDimension()                            */
-/************************************************************************/
-
-int OGRMultiLineString::getDimension() const
-
-{
-    return 1;
-}
-
-/************************************************************************/
 /*                          getGeometryName()                           */
 /************************************************************************/
 
@@ -83,299 +77,48 @@ const char * OGRMultiLineString::getGeometryName() const
 }
 
 /************************************************************************/
-/*                        addGeometryDirectly()                         */
+/*                          isCompatibleSubType()                       */
 /************************************************************************/
 
-OGRErr OGRMultiLineString::addGeometryDirectly( OGRGeometry * poNewGeom )
-
+OGRBoolean OGRMultiLineString::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
 {
-    if( poNewGeom->getGeometryType() != wkbLineString 
-        && poNewGeom->getGeometryType() != wkbLineString25D ) 
-        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-
-    return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
+    return wkbFlatten(eGeomType) == wkbLineString;
 }
 
 /************************************************************************/
-/*                               clone()                                */
+/*                            exportToWkt()                             */
 /************************************************************************/
 
-OGRGeometry *OGRMultiLineString::clone() const
+OGRErr OGRMultiLineString::exportToWkt( char ** ppszDstText,
+                                        OGRwkbVariant eWkbVariant ) const
 
 {
-    OGRMultiLineString  *poNewGC;
-
-    poNewGC = new OGRMultiLineString;
-    poNewGC->assignSpatialReference( getSpatialReference() );
-
-    for( int i = 0; i < getNumGeometries(); i++ )
-    {
-        poNewGC->addGeometry( getGeometryRef(i) );
-    }
-
-    return poNewGC;
+    return exportToWktInternal( ppszDstText, eWkbVariant, "LINESTRING" );
 }
 
 /************************************************************************/
-/*                           importFromWkt()                            */
-/*                                                                      */
-/*      Instantiate from well known text format.  Currently this is     */
-/*      `MULTILINESTRING ((x y, x y, ...),(x y, ...),...)'.             */
+/*                         hasCurveGeometry()                           */
 /************************************************************************/
 
-OGRErr OGRMultiLineString::importFromWkt( char ** ppszInput )
-
+OGRBoolean OGRMultiLineString::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
 {
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-    OGRErr      eErr;
-
-/* -------------------------------------------------------------------- */
-/*      Clear existing rings.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the ``MULTILINESTRING'' keyword token.          */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,getGeometryName()) )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ...                                             */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
-    int bHasZ = FALSE, bHasM = FALSE;
-
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
-
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style MULTILINESTRING(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-
-            if( EQUAL(szToken,",") )
-            {
-                /* This is OK according to SFSQL SPEC. */
-            }
-            else if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszPreScan;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
-
-    /* Skip first '(' */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-/* ==================================================================== */
-/*      Read each line in turn.  Note that we try to reuse the same     */
-/*      point list buffer from ring to ring to cut down on              */
-/*      allocate/deallocate overhead.                                   */
-/* ==================================================================== */
-    OGRRawPoint *paoPoints = NULL;
-    int         nMaxPoints = 0;
-    double      *padfZ = NULL;
-    
-    do
-    {
-        int     nPoints = 0;
-
-        const char* pszNext = OGRWktReadToken( pszInput, szToken );
-        if (EQUAL(szToken,"EMPTY"))
-        {
-            eErr = addGeometryDirectly( new OGRLineString() );
-            if( eErr != OGRERR_NONE )
-                return eErr;
-
-            pszInput = OGRWktReadToken( pszNext, szToken );
-            if ( !EQUAL(szToken, ",") )
-                break;
-
-            continue;
-        }
-/* -------------------------------------------------------------------- */
-/*      Read points for one line from input.                            */
-/* -------------------------------------------------------------------- */
-        pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
-                                     &nPoints );
-
-        if( pszInput == NULL || nPoints == 0 )
-        {
-            eErr = OGRERR_CORRUPT_DATA;
-            break;
-        }
-        
-/* -------------------------------------------------------------------- */
-/*      Create the new line, and add to collection.                     */
-/* -------------------------------------------------------------------- */
-        OGRLineString   *poLine;
-
-        poLine = new OGRLineString();
-        /* Ignore Z array when we have a MULTILINESTRING M */
-        if (bHasM && !bHasZ)
-            poLine->setPoints( nPoints, paoPoints, NULL );
-        else
-            poLine->setPoints( nPoints, paoPoints, padfZ );
-
-        eErr = addGeometryDirectly( poLine ); 
-
-/* -------------------------------------------------------------------- */
-/*      Read the delimeter following the ring.                          */
-/* -------------------------------------------------------------------- */
-        
-        pszInput = OGRWktReadToken( pszInput, szToken );
-    } while( szToken[0] == ',' && eErr == OGRERR_NONE );
-
-/* -------------------------------------------------------------------- */
-/*      freak if we don't get a closing bracket.                        */
-/* -------------------------------------------------------------------- */
-    CPLFree( paoPoints );
-    CPLFree( padfZ );
-   
-    if( eErr != OGRERR_NONE )
-        return eErr;
-
-    if( szToken[0] != ')' )
-        return OGRERR_CORRUPT_DATA;
-    
-    *ppszInput = (char *) pszInput;
-    return OGRERR_NONE;
+    return FALSE;
 }
 
 /************************************************************************/
-/*                            exportToWkt()                             */
-/*                                                                      */
-/*      Translate this structure into it's well known text format       */
-/*      equivelent.  This could be made alot more CPU efficient!        */
+/*                          CastToMultiCurve()                          */
 /************************************************************************/
 
-OGRErr OGRMultiLineString::exportToWkt( char ** ppszDstText ) const
+/**
+ * \brief Cast to multicurve.
+ *
+ * The passed in geometry is consumed and a new one returned .
+ * 
+ * @param poMLS the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
 
+OGRMultiCurve* OGRMultiLineString::CastToMultiCurve(OGRMultiLineString* poMLS)
 {
-    char        **papszLines;
-    int         iLine, nCumulativeLength = 0, nValidLineStrings=0;
-    OGRErr      eErr;
-
-/* -------------------------------------------------------------------- */
-/*      Build a list of strings containing the stuff for each ring.     */
-/* -------------------------------------------------------------------- */
-    papszLines = (char **) CPLCalloc(sizeof(char *),getNumGeometries());
-
-    for( iLine = 0; iLine < getNumGeometries(); iLine++ )
-    {
-        eErr = getGeometryRef(iLine)->exportToWkt( &(papszLines[iLine]) );
-        if( eErr != OGRERR_NONE )
-            return eErr;
-
-        if( !EQUALN(papszLines[iLine],"LINESTRING (", 12) )
-        {
-            CPLDebug( "OGR", "OGRMultiLineString::exportToWkt() - skipping %s.",
-                      papszLines[iLine] );
-            CPLFree( papszLines[iLine] );
-            papszLines[iLine] = NULL;
-            continue;
-        }
-
-        nCumulativeLength += strlen(papszLines[iLine] + 11);
-        nValidLineStrings++;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Return MULTILINESTRING EMPTY if we get no valid line string.    */
-/* -------------------------------------------------------------------- */
-    if( nValidLineStrings == 0 )
-    {
-        CPLFree( papszLines );
-        *ppszDstText = CPLStrdup("MULTILINESTRING EMPTY");
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Allocate exactly the right amount of space for the              */
-/*      aggregated string.                                              */
-/* -------------------------------------------------------------------- */
-    *ppszDstText = (char *) VSIMalloc(nCumulativeLength+getNumGeometries()+20);
-
-    if( *ppszDstText == NULL )
-        return OGRERR_NOT_ENOUGH_MEMORY;
-
-/* -------------------------------------------------------------------- */
-/*      Build up the string, freeing temporary strings as we go.        */
-/* -------------------------------------------------------------------- */
-    char *pszAppendPoint = *ppszDstText;
-
-    strcpy( pszAppendPoint, "MULTILINESTRING (" );
-
-    int bMustWriteComma = FALSE;
-    for( iLine = 0; iLine < getNumGeometries(); iLine++ )
-    {                                                           
-        if( papszLines[iLine] == NULL )
-            continue;
-
-        if( bMustWriteComma )
-            strcat( pszAppendPoint, "," );
-        bMustWriteComma = TRUE;
-        
-        strcat( pszAppendPoint, papszLines[iLine] + 11 );
-        pszAppendPoint += strlen(pszAppendPoint);
-
-        VSIFree( papszLines[iLine] );
-    }
-
-    strcat( pszAppendPoint, ")" );
-
-    CPLFree( papszLines );
-
-    return OGRERR_NONE;
+    return (OGRMultiCurve*) TransferMembersAndDestroy(poMLS, new OGRMultiCurve());
 }
-
diff --git a/ogr/ogrmultipoint.cpp b/ogr/ogrmultipoint.cpp
index 4a13e85..88f1640 100644
--- a/ogr/ogrmultipoint.cpp
+++ b/ogr/ogrmultipoint.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmultipoint.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmultipoint.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRMultiPoint class.
@@ -32,17 +32,29 @@
 #include "ogr_p.h"
 #include <assert.h>
 
-CPL_CVSID("$Id: ogrmultipoint.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmultipoint.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                           OGRMultiPoint()                            */
 /************************************************************************/
 
+/**
+ * \brief Create an empty multi point collection.
+ */
+
 OGRMultiPoint::OGRMultiPoint()
 {
 }
 
 /************************************************************************/
+/*                          ~OGRMultiPoint()                            */
+/************************************************************************/
+
+OGRMultiPoint::~OGRMultiPoint()
+{
+}
+
+/************************************************************************/
 /*                          getGeometryType()                           */
 /************************************************************************/
 
@@ -76,41 +88,12 @@ const char * OGRMultiPoint::getGeometryName() const
 }
 
 /************************************************************************/
-/*                        addGeometryDirectly()                         */
-/*                                                                      */
-/*      Add a new geometry to a collection.  Subclasses should          */
-/*      override this to verify the type of the new geometry, and       */
-/*      then call this method to actually add it.                       */
+/*                          isCompatibleSubType()                       */
 /************************************************************************/
 
-OGRErr OGRMultiPoint::addGeometryDirectly( OGRGeometry * poNewGeom )
-
+OGRBoolean OGRMultiPoint::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
 {
-    if( poNewGeom->getGeometryType() != wkbPoint 
-        && poNewGeom->getGeometryType() != wkbPoint25D )
-        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-
-    return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
-}
-
-/************************************************************************/
-/*                               clone()                                */
-/************************************************************************/
-
-OGRGeometry *OGRMultiPoint::clone() const
-
-{
-    OGRMultiPoint       *poNewGC;
-
-    poNewGC = new OGRMultiPoint;
-    poNewGC->assignSpatialReference( getSpatialReference() );
-
-    for( int i = 0; i < getNumGeometries(); i++ )
-    {
-        poNewGC->addGeometry( getGeometryRef(i) );
-    }
-
-    return poNewGC;
+    return wkbFlatten(eGeomType) == wkbPoint;
 }
 
 /************************************************************************/
@@ -120,10 +103,11 @@ OGRGeometry *OGRMultiPoint::clone() const
 /*      equivelent.  This could be made alot more CPU efficient!        */
 /************************************************************************/
 
-OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
+OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText,
+                                   OGRwkbVariant eWkbVariant ) const
 
 {
-    int         nMaxString = getNumGeometries() * 20 + 128;
+    int         nMaxString = getNumGeometries() * 22 + 128;
     int         nRetLen = 0;
 
 /* -------------------------------------------------------------------- */
@@ -131,7 +115,10 @@ OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
 /* -------------------------------------------------------------------- */
     if( IsEmpty() )
     {
-        *ppszDstText = CPLStrdup("MULTIPOINT EMPTY");
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            *ppszDstText = CPLStrdup("MULTIPOINT Z EMPTY");
+        else
+            *ppszDstText = CPLStrdup("MULTIPOINT EMPTY");
         return OGRERR_NONE;
     }
 
@@ -139,7 +126,10 @@ OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
     if( *ppszDstText == NULL )
         return OGRERR_NOT_ENOUGH_MEMORY;
 
-    sprintf( *ppszDstText, "%s (", getGeometryName() );
+    if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+        sprintf( *ppszDstText, "%s Z (", getGeometryName() );
+    else
+        sprintf( *ppszDstText, "%s (", getGeometryName() );
 
     int bMustWriteComma = FALSE;
     for( int i = 0; i < getNumGeometries(); i++ )
@@ -163,12 +153,24 @@ OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
             nMaxString = nMaxString * 2;
             *ppszDstText = (char *) CPLRealloc(*ppszDstText,nMaxString);
         }
-        
+
+        if( eWkbVariant == wkbVariantIso )
+        {
+            strcat( *ppszDstText + nRetLen, "(" );
+            nRetLen ++;
+        }
+
         OGRMakeWktCoordinate( *ppszDstText + nRetLen,
                               poPoint->getX(), 
                               poPoint->getY(),
                               poPoint->getZ(),
                               poPoint->getCoordinateDimension() );
+
+        if( eWkbVariant == wkbVariantIso )
+        {
+            strcat( *ppszDstText + nRetLen, ")" );
+            nRetLen ++;
+        }
     }
 
     strcat( *ppszDstText+nRetLen, ")" );
@@ -183,104 +185,26 @@ OGRErr OGRMultiPoint::exportToWkt( char ** ppszDstText ) const
 OGRErr OGRMultiPoint::importFromWkt( char ** ppszInput )
 
 {
+    const char *pszInputBefore = *ppszInput;
+    int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
 
     char        szToken[OGR_WKT_TOKEN_MAX];
     const char  *pszInput = *ppszInput;
     int         iGeom;
-    OGRErr      eErr = OGRERR_NONE;
-
-/* -------------------------------------------------------------------- */
-/*      Clear existing Geoms.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
+    eErr = OGRERR_NONE;
 
-/* -------------------------------------------------------------------- */
-/*      Read and verify the type keyword, and ensure it matches the     */
-/*      actual type of this container.                                  */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,getGeometryName()) )
-        return OGRERR_CORRUPT_DATA;
-
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ...                                             */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
-    int bHasZ = FALSE, bHasM = FALSE;
-
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
-
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style MULTIPOINT(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-
-            if( EQUAL(szToken,",") )
-            {
-                /* This is OK according to SFSQL SPEC. */
-            }
-            else if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszPreScan;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
-
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
+    const char* pszPreScan = OGRWktReadToken( pszInput, szToken );
     OGRWktReadToken( pszPreScan, szToken );
 
     // Do we have an inner bracket? 
     if (EQUAL(szToken,"(") || EQUAL(szToken, "EMPTY") )
+    {
+        *ppszInput = (char*) pszInputBefore;
         return importFromWkt_Bracketed( ppszInput, bHasM, bHasZ );
+    }
 
     if (bHasZ || bHasM)
     {
@@ -428,4 +352,11 @@ OGRErr OGRMultiPoint::importFromWkt_Bracketed( char ** ppszInput, int bHasM, int
     return OGRERR_NONE;
 }
 
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
 
+OGRBoolean OGRMultiPoint::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
+{
+    return FALSE;
+}
diff --git a/ogr/ogrmultipolygon.cpp b/ogr/ogrmultipolygon.cpp
index 913a781..748ff3d 100644
--- a/ogr/ogrmultipolygon.cpp
+++ b/ogr/ogrmultipolygon.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmultipolygon.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmultipolygon.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRMultiPolygon class.
@@ -29,39 +29,42 @@
  ****************************************************************************/
 
 #include "ogr_geometry.h"
+#include "ogr_api.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrmultipolygon.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmultipolygon.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                          OGRMultiPolygon()                           */
 /************************************************************************/
 
+/**
+ * \brief Create an empty multi polygon collection.
+ */
+
 OGRMultiPolygon::OGRMultiPolygon()
 {
 }
 
 /************************************************************************/
-/*                          getGeometryType()                           */
+/*                         ~OGRMultiPolygon()                           */
 /************************************************************************/
 
-OGRwkbGeometryType OGRMultiPolygon::getGeometryType() const
-
+OGRMultiPolygon::~OGRMultiPolygon()
 {
-    if( getCoordinateDimension() == 3 )
-        return wkbMultiPolygon25D;
-    else
-        return wkbMultiPolygon;
 }
 
 /************************************************************************/
-/*                            getDimension()                            */
+/*                          getGeometryType()                           */
 /************************************************************************/
 
-int OGRMultiPolygon::getDimension() const
+OGRwkbGeometryType OGRMultiPolygon::getGeometryType() const
 
 {
-    return 2;
+    if( getCoordinateDimension() == 3 )
+        return wkbMultiPolygon25D;
+    else
+        return wkbMultiPolygon;
 }
 
 /************************************************************************/
@@ -75,388 +78,73 @@ const char * OGRMultiPolygon::getGeometryName() const
 }
 
 /************************************************************************/
-/*                        addGeometryDirectly()                         */
+/*                          isCompatibleSubType()                       */
 /************************************************************************/
 
-OGRErr OGRMultiPolygon::addGeometryDirectly( OGRGeometry * poNewGeom )
-
+OGRBoolean OGRMultiPolygon::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
 {
-    if( poNewGeom->getGeometryType() != wkbPolygon 
-        && poNewGeom->getGeometryType() != wkbPolygon25D )
-        return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
-
-    return OGRGeometryCollection::addGeometryDirectly( poNewGeom );
+    return wkbFlatten(eGeomType) == wkbPolygon;
 }
 
 /************************************************************************/
-/*                               clone()                                */
+/*                            exportToWkt()                             */
 /************************************************************************/
 
-OGRGeometry *OGRMultiPolygon::clone() const
+OGRErr OGRMultiPolygon::exportToWkt( char ** ppszDstText,
+                                        OGRwkbVariant eWkbVariant ) const
 
 {
-    OGRMultiPolygon     *poNewGC;
-
-    poNewGC = new OGRMultiPolygon;
-    poNewGC->assignSpatialReference( getSpatialReference() );
-
-    for( int i = 0; i < getNumGeometries(); i++ )
-    {
-        poNewGC->addGeometry( getGeometryRef(i) );
-    }
-
-    return poNewGC;
+    return exportToWktInternal( ppszDstText, eWkbVariant, "POLYGON" );
 }
 
 /************************************************************************/
-/*                           importFromWkt()                            */
-/*                                                                      */
-/*      Instantiate from well known text format.  Currently this is     */
-/*      `MULTIPOLYGON ((x y, x y, ...),(x y, ...),...)'.                */
+/*                         hasCurveGeometry()                           */
 /************************************************************************/
 
-OGRErr OGRMultiPolygon::importFromWkt( char ** ppszInput )
-
+OGRBoolean OGRMultiPolygon::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
 {
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-    OGRErr      eErr = OGRERR_NONE;
-
-/* -------------------------------------------------------------------- */
-/*      Clear existing rings.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the MULTIPOLYGON keyword token.                 */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,getGeometryName()) )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ...                                             */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
-    int bHasZ = FALSE, bHasM = FALSE;
-
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
-
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style MULTIPOLYGON(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-
-            if( EQUAL(szToken,",") )
-            {
-                /* This is OK according to SFSQL SPEC. */
-            }
-            else if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszPreScan;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
-
-    /* Skip first '(' */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-/* ==================================================================== */
-/*      Read each polygon in turn.  Note that we try to reuse the same  */
-/*      point list buffer from ring to ring to cut down on              */
-/*      allocate/deallocate overhead.                                   */
-/* ==================================================================== */
-    OGRRawPoint *paoPoints = NULL;
-    int         nMaxPoints = 0;
-    double      *padfZ = NULL;
-    
-    do
-    {
-        OGRPolygon      *poPolygon = new OGRPolygon();
-
-/* -------------------------------------------------------------------- */
-/*      The next character should be a ( indicating the start of the    */
-/*      list of polygons.                                               */
-/* -------------------------------------------------------------------- */
-        pszInput = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken, "EMPTY") )
-        {
-            eErr = addGeometryDirectly( poPolygon );
-            if( eErr != OGRERR_NONE )
-                return eErr;
-
-            pszInput = OGRWktReadToken( pszInput, szToken );
-            if ( !EQUAL(szToken, ",") )
-                break;
-
-            continue;
-        }
-        else if( szToken[0] != '(' )
-        {
-            eErr = OGRERR_CORRUPT_DATA;
-            delete poPolygon;
-            break;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Loop over each ring in this polygon.                            */
-/* -------------------------------------------------------------------- */
-        do
-        {
-            int     nPoints = 0;
-
-            const char* pszNext = OGRWktReadToken( pszInput, szToken );
-            if (EQUAL(szToken,"EMPTY"))
-            {
-                poPolygon->addRingDirectly( new OGRLinearRing() );
-
-                pszInput = OGRWktReadToken( pszNext, szToken );
-                if ( !EQUAL(szToken, ",") )
-                    break;
-
-                continue;
-            }
-
-/* -------------------------------------------------------------------- */
-/*      Read points for one line from input.                            */
-/* -------------------------------------------------------------------- */
-            pszInput = OGRWktReadPoints( pszInput, &paoPoints, &padfZ, &nMaxPoints,
-                                         &nPoints );
-
-            if( pszInput == NULL || nPoints == 0 )
-            {
-                eErr = OGRERR_CORRUPT_DATA;
-                break;
-            }
-        
-/* -------------------------------------------------------------------- */
-/*      Create the new line, and add to collection.                     */
-/* -------------------------------------------------------------------- */
-            OGRLinearRing       *poLine;
-
-            poLine = new OGRLinearRing();
-            /* Ignore Z array when we have a MULTIPOLYGON M */
-            if (bHasM && !bHasZ)
-                poLine->setPoints( nPoints, paoPoints, NULL );
-            else
-                poLine->setPoints( nPoints, paoPoints, padfZ );
-
-            poPolygon->addRingDirectly( poLine ); 
-
-/* -------------------------------------------------------------------- */
-/*      Read the delimeter following the ring.                          */
-/* -------------------------------------------------------------------- */
-        
-            pszInput = OGRWktReadToken( pszInput, szToken );
-        } while( szToken[0] == ',' && eErr == OGRERR_NONE );
-
-/* -------------------------------------------------------------------- */
-/*      Verify that we have a closing bracket.                          */
-/* -------------------------------------------------------------------- */
-        if( eErr == OGRERR_NONE )
-        {
-            if( szToken[0] != ')' )
-                eErr = OGRERR_CORRUPT_DATA;
-            else
-                pszInput = OGRWktReadToken( pszInput, szToken );
-        }
-        
-/* -------------------------------------------------------------------- */
-/*      Add the polygon to the MULTIPOLYGON.                            */
-/* -------------------------------------------------------------------- */
-        if( eErr == OGRERR_NONE )
-            eErr = addGeometryDirectly( poPolygon );
-        else
-            delete poPolygon;
-
-    } while( szToken[0] == ',' && eErr == OGRERR_NONE );
-
-/* -------------------------------------------------------------------- */
-/*      freak if we don't get a closing bracket.                        */
-/* -------------------------------------------------------------------- */
-    CPLFree( paoPoints );
-    CPLFree( padfZ );
-   
-    if( eErr != OGRERR_NONE )
-        return eErr;
-
-    if( szToken[0] != ')' )
-        return OGRERR_CORRUPT_DATA;
-    
-    *ppszInput = (char *) pszInput;
-    return OGRERR_NONE;
+    return FALSE;
 }
 
 /************************************************************************/
-/*                            exportToWkt()                             */
-/*                                                                      */
-/*      Translate this structure into it's well known text format       */
-/*      equivelent.  This could be made alot more CPU efficient!        */
+/*                            PointOnSurface()                          */
 /************************************************************************/
 
-OGRErr OGRMultiPolygon::exportToWkt( char ** ppszDstText ) const
-
+OGRErr OGRMultiPolygon::PointOnSurface( OGRPoint * poPoint ) const
 {
-    char        **papszPolygons;
-    int         iPoly, nCumulativeLength = 0, nValidPolys=0;
-    OGRErr      eErr;
-    int         bMustWriteComma = FALSE;
+    if( poPoint == NULL || poPoint->IsEmpty() )
+        return OGRERR_FAILURE;
 
-/* -------------------------------------------------------------------- */
-/*      Build a list of strings containing the stuff for each ring.     */
-/* -------------------------------------------------------------------- */
-    papszPolygons = (char **) CPLCalloc(sizeof(char *),getNumGeometries());
+    OGRGeometryH hInsidePoint = OGR_G_PointOnSurface( (OGRGeometryH) this );
+    if( hInsidePoint == NULL )
+        return OGRERR_FAILURE;
 
-    for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
-    {
-        eErr = getGeometryRef(iPoly)->exportToWkt( &(papszPolygons[iPoly]) );
-        if( eErr != OGRERR_NONE )
-            goto error;
-
-        if( !EQUALN(papszPolygons[iPoly],"POLYGON (", 9) )
-        {
-            CPLDebug( "OGR", "OGRMultiPolygon::exportToWkt() - skipping %s.",
-                      papszPolygons[iPoly] );
-            CPLFree( papszPolygons[iPoly] );
-            papszPolygons[iPoly] = NULL;
-            continue;
-        }
-        
-        nCumulativeLength += strlen(papszPolygons[iPoly] + 8);
-        nValidPolys++;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Return MULTIPOLYGON EMPTY if we get no valid polygons.          */
-/* -------------------------------------------------------------------- */
-    if( nValidPolys == 0 )
-    {
-        CPLFree( papszPolygons );
-        *ppszDstText = CPLStrdup("MULTIPOLYGON EMPTY");
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Allocate exactly the right amount of space for the              */
-/*      aggregated string.                                              */
-/* -------------------------------------------------------------------- */
-    *ppszDstText = (char *) VSIMalloc(nCumulativeLength+getNumGeometries()+20);
-
-    if( *ppszDstText == NULL )
+    OGRPoint *poInsidePoint = (OGRPoint *) hInsidePoint;
+    if( poInsidePoint->IsEmpty() )
+        poPoint->empty();
+    else
     {
-        eErr = OGRERR_NOT_ENOUGH_MEMORY;
-        goto error;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Build up the string, freeing temporary strings as we go.        */
-/* -------------------------------------------------------------------- */
-    strcpy( *ppszDstText, "MULTIPOLYGON (" );
-    nCumulativeLength = strlen(*ppszDstText);
-
-    for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
-    {                                                           
-        if( papszPolygons[iPoly] == NULL )
-            continue;
-
-        if( bMustWriteComma )
-            (*ppszDstText)[nCumulativeLength++] = ',';
-        bMustWriteComma = TRUE;
-        
-        int nPolyLength = strlen(papszPolygons[iPoly] + 8);
-        memcpy( *ppszDstText + nCumulativeLength, papszPolygons[iPoly] + 8, nPolyLength );
-        nCumulativeLength += nPolyLength;
-        VSIFree( papszPolygons[iPoly] );
+        poPoint->setX( poInsidePoint->getX() );
+        poPoint->setY( poInsidePoint->getY() );
     }
 
-    (*ppszDstText)[nCumulativeLength++] = ')';
-    (*ppszDstText)[nCumulativeLength] = '\0';
-
-    CPLFree( papszPolygons );
-
     return OGRERR_NONE;
-
-error:
-    for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
-        CPLFree( papszPolygons[iPoly] );
-    CPLFree( papszPolygons );
-    return eErr;
 }
 
 /************************************************************************/
-/*                              get_Area()                              */
+/*                          CastToMultiSurface()                        */
 /************************************************************************/
 
 /**
- * Compute area of multipolygon.
+ * \brief Cast to multisurface.
  *
- * The area is computed as the sum of the areas of all polygon members
- * in this collection.
- *
- * @return computed area.
+ * The passed in geometry is consumed and a new one returned .
+ * 
+ * @param poMP the input geometry - ownership is passed to the method.
+ * @return new geometry.
  */
 
-double OGRMultiPolygon::get_Area() const
-
+OGRMultiSurface* OGRMultiPolygon::CastToMultiSurface(OGRMultiPolygon* poMP)
 {
-    double dfArea = 0.0;
-    int iPoly;
-
-    for( iPoly = 0; iPoly < getNumGeometries(); iPoly++ )
-    {
-        OGRPolygon *poPoly = (OGRPolygon *) getGeometryRef( iPoly );
-
-        dfArea += poPoly->get_Area();
-    }
-
-    return dfArea;
+    return (OGRMultiSurface*) TransferMembersAndDestroy(poMP, new OGRMultiSurface());
 }
-
diff --git a/ogr/ogrmultisurface.cpp b/ogr/ogrmultisurface.cpp
new file mode 100644
index 0000000..e1c6cbd
--- /dev/null
+++ b/ogr/ogrmultisurface.cpp
@@ -0,0 +1,284 @@
+/******************************************************************************
+ * $Id: ogrmultisurface.cpp 27960 2014-11-14 18:31:32Z rouault $
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  The OGRMultiSurface class.
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geometry.h"
+#include "ogr_p.h"
+#include "ogr_api.h"
+
+CPL_CVSID("$Id: ogrmultisurface.cpp 27960 2014-11-14 18:31:32Z rouault $");
+
+/************************************************************************/
+/*                          OGRMultiSurface()                           */
+/************************************************************************/
+
+/**
+ * \brief Create an empty multi surface collection.
+ */
+
+OGRMultiSurface::OGRMultiSurface()
+{
+}
+
+/************************************************************************/
+/*                         ~OGRMultiSurface()                           */
+/************************************************************************/
+
+OGRMultiSurface::~OGRMultiSurface()
+{
+}
+
+/************************************************************************/
+/*                          getGeometryType()                           */
+/************************************************************************/
+
+OGRwkbGeometryType OGRMultiSurface::getGeometryType() const
+
+{
+    if( getCoordinateDimension() == 3 )
+        return wkbMultiSurfaceZ;
+    else
+        return wkbMultiSurface;
+}
+
+/************************************************************************/
+/*                            getDimension()                            */
+/************************************************************************/
+
+int OGRMultiSurface::getDimension() const
+
+{
+    return 2;
+}
+
+/************************************************************************/
+/*                          getGeometryName()                           */
+/************************************************************************/
+
+const char * OGRMultiSurface::getGeometryName() const
+
+{
+    return "MULTISURFACE";
+}
+
+/************************************************************************/
+/*                          isCompatibleSubType()                       */
+/************************************************************************/
+
+OGRBoolean OGRMultiSurface::isCompatibleSubType( OGRwkbGeometryType eGeomType ) const
+{
+    return OGR_GT_IsSurface(eGeomType);
+}
+
+/************************************************************************/
+/*                           importFromWkt()                            */
+/*                                                                      */
+/*      Instantiate from well known text format.                        */
+/************************************************************************/
+
+OGRErr OGRMultiSurface::importFromWkt( char ** ppszInput )
+
+{
+    int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
+
+    if( bHasZ )
+        setCoordinateDimension(3);
+
+    int bIsMultiSurface = (wkbFlatten(getGeometryType()) == wkbMultiSurface);
+
+    char        szToken[OGR_WKT_TOKEN_MAX];
+    const char  *pszInput = *ppszInput;
+    eErr = OGRERR_NONE;
+
+    /* Skip first '(' */
+    pszInput = OGRWktReadToken( pszInput, szToken );
+
+/* ==================================================================== */
+/*      Read each surface in turn.  Note that we try to reuse the same  */
+/*      point list buffer from ring to ring to cut down on              */
+/*      allocate/deallocate overhead.                                   */
+/* ==================================================================== */
+    OGRRawPoint *paoPoints = NULL;
+    int          nMaxPoints = 0;
+    double      *padfZ = NULL;
+
+    do
+    {
+
+    /* -------------------------------------------------------------------- */
+    /*      Get the first token, which should be the geometry type.         */
+    /* -------------------------------------------------------------------- */
+        const char* pszInputBefore = pszInput;
+        pszInput = OGRWktReadToken( pszInput, szToken );
+
+        OGRSurface* poSurface;
+
+    /* -------------------------------------------------------------------- */
+    /*      Do the import.                                                  */
+    /* -------------------------------------------------------------------- */
+        if (EQUAL(szToken,"("))
+        {
+            OGRPolygon      *poPolygon = new OGRPolygon();
+            poSurface = poPolygon;
+            pszInput = pszInputBefore;
+            eErr = poPolygon->importFromWKTListOnly( (char**)&pszInput, bHasZ, bHasM,
+                                                     paoPoints, nMaxPoints, padfZ );
+        }
+        else if (EQUAL(szToken, "EMPTY") )
+        {
+            poSurface = new OGRPolygon();
+        }
+        /* We accept POLYGON() but this is an extension to the BNF, also */
+        /* accepted by PostGIS */
+        else if (bIsMultiSurface &&
+                 (EQUAL(szToken,"POLYGON") ||
+                  EQUAL(szToken,"CURVEPOLYGON")))
+        {
+            OGRGeometry* poGeom = NULL;
+            pszInput = pszInputBefore;
+            eErr = OGRGeometryFactory::createFromWkt( (char **) &pszInput,
+                                                       NULL, &poGeom );
+            poSurface = (OGRSurface*) poGeom;
+        }
+        else
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Unexpected token : %s", szToken);
+            eErr = OGRERR_CORRUPT_DATA;
+            break;
+        }
+
+        if( eErr == OGRERR_NONE )
+            eErr = addGeometryDirectly( poSurface );
+        if( eErr != OGRERR_NONE )
+        {
+            delete poSurface;
+            break;
+        }
+
+/* -------------------------------------------------------------------- */
+/*      Read the delimeter following the surface.                       */
+/* -------------------------------------------------------------------- */
+        pszInput = OGRWktReadToken( pszInput, szToken );
+
+    } while( szToken[0] == ',' && eErr == OGRERR_NONE );
+
+    CPLFree( paoPoints );
+    CPLFree( padfZ );
+
+/* -------------------------------------------------------------------- */
+/*      freak if we don't get a closing bracket.                        */
+/* -------------------------------------------------------------------- */
+
+    if( eErr != OGRERR_NONE )
+        return eErr;
+
+    if( szToken[0] != ')' )
+        return OGRERR_CORRUPT_DATA;
+    
+    *ppszInput = (char *) pszInput;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            exportToWkt()                             */
+/************************************************************************/
+
+OGRErr OGRMultiSurface::exportToWkt( char ** ppszDstText,
+                                     CPL_UNUSED OGRwkbVariant eWkbVariant ) const
+
+{
+    return exportToWktInternal( ppszDstText, wkbVariantIso, "POLYGON" );
+}
+
+/************************************************************************/
+/*                         hasCurveGeometry()                           */
+/************************************************************************/
+
+OGRBoolean OGRMultiSurface::hasCurveGeometry(int bLookForNonLinear) const
+{
+    if( bLookForNonLinear )
+        return OGRGeometryCollection::hasCurveGeometry(TRUE);
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            PointOnSurface()                          */
+/************************************************************************/
+
+/** \brief This method relates to the SFCOM IMultiSurface::get_PointOnSurface() method.
+ *
+ * NOTE: Only implemented when GEOS included in build.
+ *
+ * @param poPoint point to be set with an internal point. 
+ *
+ * @return OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. 
+ */
+
+OGRErr OGRMultiSurface::PointOnSurface( OGRPoint * poPoint ) const
+{
+    OGRMultiPolygon* poMPoly = (OGRMultiPolygon*) getLinearGeometry();
+    OGRErr ret = poMPoly->PointOnSurface(poPoint);
+    delete poMPoly;
+    return ret;
+}
+
+/************************************************************************/
+/*                         CastToMultiPolygon()                         */
+/************************************************************************/
+
+/**
+ * \brief Cast to multipolygon.
+ *
+ * This method should only be called if the multisurface actually only contains
+ * instances of OGRPolygon. This can be verified if hasCurveGeometry(TRUE)
+ * returns FALSE. It is not intended to approximate curve polygons. For that
+ * use getLinearGeometry().
+ * 
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure). 
+ * 
+ * @param poMS the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRMultiPolygon* OGRMultiSurface::CastToMultiPolygon(OGRMultiSurface* poMS)
+{
+    for(int i=0;i<poMS->nGeomCount;i++)
+    {
+        poMS->papoGeoms[i] = OGRSurface::CastToPolygon( (OGRSurface*)poMS->papoGeoms[i] );
+        if( poMS->papoGeoms[i] == NULL )
+        {
+            delete poMS;
+            return NULL;
+        }
+    }
+    return (OGRMultiPolygon*) TransferMembersAndDestroy(poMS, new OGRMultiPolygon());
+}
diff --git a/ogr/ogrpgeogeometry.cpp b/ogr/ogrpgeogeometry.cpp
index e858091..e1722de 100644
--- a/ogr/ogrpgeogeometry.cpp
+++ b/ogr/ogrpgeogeometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeogeometry.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgeogeometry.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements decoder of shapebin geometry for PGeo
@@ -34,7 +34,7 @@
 #include "ogr_p.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrpgeogeometry.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgeogeometry.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 #define SHPP_TRISTRIP   0
 #define SHPP_TRIFAN     1
@@ -294,7 +294,7 @@ OGRErr OGRWriteToShapeBin( OGRGeometry *poGeom,
     }
 
     OGRwkbGeometryType nOGRType = wkbFlatten(poGeom->getGeometryType());
-    int b3d = (poGeom->getGeometryType() & wkb25DBit);
+    int b3d = wkbHasZ(poGeom->getGeometryType());
     int nCoordDims = b3d ? 3 : 2;
 
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogrpoint.cpp b/ogr/ogrpoint.cpp
index 49a11c5..d46f4f7 100644
--- a/ogr/ogrpoint.cpp
+++ b/ogr/ogrpoint.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpoint.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpoint.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The Point geometry class.
@@ -34,7 +34,11 @@
 /* for std::numeric_limits */
 #include <limits>
 
-CPL_CVSID("$Id: ogrpoint.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpoint.cpp 27959 2014-11-14 18:29:21Z rouault $");
+
+/* CAUTION: we use nCoordDimension == -2 to mean POINT EMPTY (2D) and
+                   nCoordDimension == -3 to mean POINT Z EMPTY
+*/
 
 /************************************************************************/
 /*                              OGRPoint()                              */
@@ -113,7 +117,7 @@ void OGRPoint::empty()
 
 {
     x = y = z = 0.0;
-    nCoordDimension = 0;
+    nCoordDimension = -2;
 }
 
 /************************************************************************/
@@ -133,7 +137,7 @@ int OGRPoint::getDimension() const
 OGRwkbGeometryType OGRPoint::getGeometryType() const
 
 {
-    if( nCoordDimension == 3 )
+    if( getCoordinateDimension() == 3 )
         return wkbPoint25D;
     else
         return wkbPoint;
@@ -162,6 +166,16 @@ void OGRPoint::flattenTo2D()
 }
 
 /************************************************************************/
+/*                       getCoordinateDimension()                       */
+/************************************************************************/
+
+int OGRPoint::getCoordinateDimension() const
+
+{
+    return nCoordDimension < 0 ? -nCoordDimension : nCoordDimension;
+}
+
+/************************************************************************/
 /*                       setCoordinateDimension()                       */
 /************************************************************************/
 
@@ -184,7 +198,7 @@ void OGRPoint::setCoordinateDimension( int nNewDimension )
 int OGRPoint::WkbSize() const
 
 {
-    if( nCoordDimension != 3 )
+    if( getCoordinateDimension() != 3 )
         return 21;
     else
         return 29;
@@ -198,32 +212,19 @@ int OGRPoint::WkbSize() const
 /************************************************************************/
 
 OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
-                                int nSize )
+                                int nSize,
+                                OGRwkbVariant eWkbVariant )
 
 {
     OGRwkbByteOrder     eByteOrder;
-    
-    if( nSize < 21 && nSize != -1 )
-        return OGRERR_NOT_ENOUGH_DATA;
+    OGRBoolean          bIs3D = FALSE;
 
-/* -------------------------------------------------------------------- */
-/*      Get the byte order byte.                                        */
-/* -------------------------------------------------------------------- */
-    eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
-    if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
-        return OGRERR_CORRUPT_DATA;
+    OGRErr eErr = importPreambuleFromWkb( pabyData, nSize, eByteOrder, bIs3D, eWkbVariant );
+    if( eErr >= 0 )
+        return eErr;
 
-/* -------------------------------------------------------------------- */
-/*      Get the geometry feature type.  For now we assume that          */
-/*      geometry type is between 0 and 255 so we only have to fetch     */
-/*      one byte.                                                       */
-/* -------------------------------------------------------------------- */
-    OGRBoolean bIs3D;
-    OGRwkbGeometryType eGeometryType;
-    OGRErr err = OGRReadWKBGeometryType( pabyData, &eGeometryType, &bIs3D );
-
-    if( err != OGRERR_NONE || eGeometryType != wkbPoint )
-        return OGRERR_CORRUPT_DATA;
+    if ( nSize < ((bIs3D) ? 29 : 21) && nSize != -1 )
+        return OGRERR_NOT_ENOUGH_DATA;
 
 /* -------------------------------------------------------------------- */
 /*      Get the vertex.                                                 */
@@ -239,9 +240,6 @@ OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
 
     if( bIs3D )
     {
-        if ( nSize < 29 && nSize != -1 )
-            return OGRERR_NOT_ENOUGH_DATA;
-
         memcpy( &z, pabyData + 5 + 16, 8 );
         if( OGR_SWAP( eByteOrder ) )
         {
@@ -255,6 +253,10 @@ OGRErr OGRPoint::importFromWkb( unsigned char * pabyData,
         nCoordDimension = 2;
     }
 
+    /* Detect NaN coordinates --> EMPTY */
+    if( x != x && y != y )
+        nCoordDimension = -nCoordDimension;
+
     return OGRERR_NONE;
 }
 
@@ -298,13 +300,13 @@ OGRErr  OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
         double dNan = std::numeric_limits<double>::quiet_NaN();
         memcpy( pabyData+5, &dNan, 8 );
         memcpy( pabyData+5+8, &dNan, 8 );
-        if( nCoordDimension == 3 )
+        if( getCoordinateDimension() == 3 )
             memcpy( pabyData+5+16, &dNan, 8 );
     }
     else
     {
         memcpy( pabyData+5, &x, 16 );
-        if( nCoordDimension == 3 )
+        if( getCoordinateDimension() == 3 )
         {
             memcpy( pabyData + 5 + 16, &z, 8 );
         }
@@ -318,7 +320,7 @@ OGRErr  OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
         CPL_SWAPDOUBLE( pabyData + 5 );
         CPL_SWAPDOUBLE( pabyData + 5 + 8 );
 
-        if( nCoordDimension == 3 )
+        if( getCoordinateDimension() == 3 )
             CPL_SWAPDOUBLE( pabyData + 5 + 16 );
     }
 
@@ -335,83 +337,17 @@ OGRErr  OGRPoint::exportToWkb( OGRwkbByteOrder eByteOrder,
 OGRErr OGRPoint::importFromWkt( char ** ppszInput )
 
 {
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the ``POINT'' keyword token.                    */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,"POINT") )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ... but treat like a point at 0,0.              */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
     int bHasZ = FALSE, bHasM = FALSE;
-
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
     {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
+        if( eErr == OGRERR_NONE ) /* only the case for an EMPTY case */
+            nCoordDimension = (bHasZ) ? -3 : -2;
 
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
+        return eErr;
     }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
-
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
-
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
 
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style POINT(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszInput = OGRWktReadToken( pszPreScan, szToken );
-
-            if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszInput;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
+    const char  *pszInput = *ppszInput;
 
 /* -------------------------------------------------------------------- */
 /*      Read the point list which should consist of exactly one point.  */
@@ -468,18 +404,27 @@ OGRErr OGRPoint::importFromWkt( char ** ppszInput )
 /*      equivelent.                                                     */
 /************************************************************************/
 
-OGRErr OGRPoint::exportToWkt( char ** ppszDstText ) const
+OGRErr OGRPoint::exportToWkt( char ** ppszDstText,
+                              OGRwkbVariant eWkbVariant ) const
 
 {
     char        szTextEquiv[140];
     char        szCoordinate[80];
 
     if ( IsEmpty() )
-        *ppszDstText = CPLStrdup( "POINT EMPTY" );
+    {
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            *ppszDstText = CPLStrdup("POINT Z EMPTY");
+        else
+            *ppszDstText = CPLStrdup("POINT EMPTY");
+    }
     else
     {
-        OGRMakeWktCoordinate(szCoordinate, x, y, z, nCoordDimension );
-        sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
+        OGRMakeWktCoordinate(szCoordinate, x, y, z, getCoordinateDimension() );
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            sprintf( szTextEquiv, "POINT Z (%s)", szCoordinate );
+        else
+            sprintf( szTextEquiv, "POINT (%s)", szCoordinate );
         *ppszDstText = CPLStrdup( szTextEquiv );
     }
     
@@ -620,7 +565,7 @@ OGRErr OGRPoint::transform( OGRCoordinateTransformation *poCT )
 
 OGRBoolean OGRPoint::IsEmpty(  ) const
 {
-    return nCoordDimension == 0;
+    return nCoordDimension < 0;
 }
 
 /************************************************************************/
@@ -633,3 +578,35 @@ void OGRPoint::swapXY()
     x = y;
     y = dfTemp;
 }
+
+/************************************************************************/
+/*                               Within()                               */
+/************************************************************************/
+
+OGRBoolean OGRPoint::Within( const OGRGeometry *poOtherGeom ) const
+
+{
+    if( !IsEmpty() && poOtherGeom != NULL &&
+        wkbFlatten(poOtherGeom->getGeometryType()) == wkbCurvePolygon )
+    {
+        return ((OGRCurvePolygon*)poOtherGeom)->Contains(this);
+    }
+    else
+        return OGRGeometry::Within(poOtherGeom);
+}
+
+/************************************************************************/
+/*                              Intersects()                            */
+/************************************************************************/
+
+OGRBoolean OGRPoint::Intersects( const OGRGeometry *poOtherGeom ) const
+
+{
+    if( !IsEmpty() && poOtherGeom != NULL &&
+        wkbFlatten(poOtherGeom->getGeometryType()) == wkbCurvePolygon )
+    {
+        return ((OGRCurvePolygon*)poOtherGeom)->Intersects(this);
+    }
+    else
+        return OGRGeometry::Intersects(poOtherGeom);
+}
diff --git a/ogr/ogrpolygon.cpp b/ogr/ogrpolygon.cpp
index 76f7ebc..2ed1431 100644
--- a/ogr/ogrpolygon.cpp
+++ b/ogr/ogrpolygon.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpolygon.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpolygon.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRPolygon geometry class.
@@ -33,7 +33,7 @@
 #include "ogr_geos.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: ogrpolygon.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpolygon.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                             OGRPolygon()                             */
@@ -46,8 +46,6 @@ CPL_CVSID("$Id: ogrpolygon.cpp 27044 2014-03-16 23:41:27Z rouault $");
 OGRPolygon::OGRPolygon()
 
 {
-    nRingCount = 0;
-    papoRings = NULL;
 }
 
 /************************************************************************/
@@ -57,47 +55,6 @@ OGRPolygon::OGRPolygon()
 OGRPolygon::~OGRPolygon()
 
 {
-    empty();
-}
-
-/************************************************************************/
-/*                               clone()                                */
-/************************************************************************/
-
-OGRGeometry *OGRPolygon::clone() const
-
-{
-    OGRPolygon  *poNewPolygon;
-
-    poNewPolygon = new OGRPolygon;
-    poNewPolygon->assignSpatialReference( getSpatialReference() );
-
-    for( int i = 0; i < nRingCount; i++ )
-    {
-        poNewPolygon->addRing( papoRings[i] );
-    }
-
-    return poNewPolygon;
-}
-
-/************************************************************************/
-/*                               empty()                                */
-/************************************************************************/
-
-void OGRPolygon::empty()
-
-{
-    if( papoRings != NULL )
-    {
-        for( int i = 0; i < nRingCount; i++ )
-        {
-            delete papoRings[i];
-        }
-        OGRFree( papoRings );
-    }
-
-    papoRings = NULL;
-    nRingCount = 0;
 }
 
 /************************************************************************/
@@ -113,30 +70,6 @@ OGRwkbGeometryType OGRPolygon::getGeometryType() const
         return wkbPolygon;
 }
 
-
-/************************************************************************/
-/*                            getDimension()                            */
-/************************************************************************/
-
-int OGRPolygon::getDimension() const
-
-{
-    return 2;
-}
-
-/************************************************************************/
-/*                            flattenTo2D()                             */
-/************************************************************************/
-
-void OGRPolygon::flattenTo2D()
-
-{
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        papoRings[iRing]->flattenTo2D();
-
-    nCoordDimension = 2;
-}
-
 /************************************************************************/
 /*                          getGeometryName()                           */
 /************************************************************************/
@@ -168,8 +101,8 @@ const char * OGRPolygon::getGeometryName() const
 OGRLinearRing *OGRPolygon::getExteriorRing()
 
 {
-    if( nRingCount > 0 )
-        return papoRings[0];
+    if( oCC.nCurveCount > 0 )
+        return (OGRLinearRing*) oCC.papoCurves[0];
     else
         return NULL;
 }
@@ -177,8 +110,8 @@ OGRLinearRing *OGRPolygon::getExteriorRing()
 const OGRLinearRing *OGRPolygon::getExteriorRing() const
 
 {
-    if( nRingCount > 0 )
-        return papoRings[0];
+    if( oCC.nCurveCount > 0 )
+        return (OGRLinearRing*) oCC.papoCurves[0];
     else
         return NULL;
 }
@@ -198,33 +131,7 @@ const OGRLinearRing *OGRPolygon::getExteriorRing() const
 
 OGRLinearRing *OGRPolygon::stealExteriorRing()
 {
-    if( nRingCount == 0 )
-        return NULL;
-    OGRLinearRing *poRet = papoRings[0];
-    papoRings[0] = NULL;
-    return poRet;
-}
-
-/************************************************************************/
-/*                        getNumInteriorRings()                         */
-/************************************************************************/
-
-/**
- * \brief Fetch the number of internal rings.
- *
- * Relates to the SFCOM IPolygon::get_NumInteriorRings() method.
- *
- * @return count of internal rings, zero or more.
- */
-
-
-int OGRPolygon::getNumInteriorRings() const
-
-{
-    if( nRingCount > 0 )
-        return nRingCount-1;
-    else
-        return 0;
+    return (OGRLinearRing*)stealExteriorRingCurve();
 }
 
 /************************************************************************/
@@ -250,19 +157,19 @@ int OGRPolygon::getNumInteriorRings() const
 OGRLinearRing *OGRPolygon::getInteriorRing( int iRing )
 
 {
-    if( iRing < 0 || iRing >= nRingCount-1 )
+    if( iRing < 0 || iRing >= oCC.nCurveCount-1 )
         return NULL;
     else
-        return papoRings[iRing+1];
+        return (OGRLinearRing*) oCC.papoCurves[iRing+1];
 }
 
 const OGRLinearRing *OGRPolygon::getInteriorRing( int iRing ) const
 
 {
-    if( iRing < 0 || iRing >= nRingCount-1 )
+    if( iRing < 0 || iRing >= oCC.nCurveCount-1 )
         return NULL;
     else
-        return papoRings[iRing+1];
+        return (OGRLinearRing*) oCC.papoCurves[iRing+1];
 }
 
 /************************************************************************/
@@ -281,74 +188,26 @@ const OGRLinearRing *OGRPolygon::getInteriorRing( int iRing ) const
 
 OGRLinearRing *OGRPolygon::stealInteriorRing(int iRing)
 {
-    if( iRing < 0 || iRing >= nRingCount-1 )
+    if( iRing < 0 || iRing >= oCC.nCurveCount-1 )
         return NULL;
-    OGRLinearRing *poRet = papoRings[iRing+1];
-    papoRings[iRing+1] = NULL;
+    OGRLinearRing *poRet = (OGRLinearRing*) oCC.papoCurves[iRing+1];
+    oCC.papoCurves[iRing+1] = NULL;
     return poRet;
 }
 
 /************************************************************************/
-/*                              addRing()                               */
-/************************************************************************/
-
-/**
- * \brief Add a ring to a polygon.
- *
- * If the polygon has no external ring (it is empty) this will be used as
- * the external ring, otherwise it is used as an internal ring.  The passed
- * OGRLinearRing remains the responsibility of the caller (an internal copy
- * is made).
- *
- * This method has no SFCOM analog.
- *
- * @param poNewRing ring to be added to the polygon.
- */
-
-void OGRPolygon::addRing( OGRLinearRing * poNewRing )
-
-{
-    papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
-                                               sizeof(void*) * (nRingCount+1));
-
-    papoRings[nRingCount] = new OGRLinearRing( poNewRing );
-
-    nRingCount++;
-
-    if( poNewRing->getCoordinateDimension() == 3 )
-        nCoordDimension = 3;
-}
-
-/************************************************************************/
-/*                          addRingDirectly()                           */
+/*                            checkRing()                               */
 /************************************************************************/
 
-/**
- * \brief Add a ring to a polygon.
- *
- * If the polygon has no external ring (it is empty) this will be used as
- * the external ring, otherwise it is used as an internal ring.  Ownership
- * of the passed ring is assumed by the OGRPolygon, but otherwise this
- * method operates the same as OGRPolygon::AddRing().
- *
- * This method has no SFCOM analog.
- *
- * @param poNewRing ring to be added to the polygon.
- */
-
-void OGRPolygon::addRingDirectly( OGRLinearRing * poNewRing )
-
+int OGRPolygon::checkRing( OGRCurve * poNewRing ) const
 {
-    papoRings = (OGRLinearRing **) OGRRealloc( papoRings,
-                                               sizeof(void*) * (nRingCount+1));
-
-    papoRings[nRingCount] = poNewRing;
-
-    nRingCount++;
-
+    if ( !(EQUAL(poNewRing->getGeometryName(), "LINEARRING")) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong curve type. Expected LINEARRING.");
+        return FALSE;
+    }
 
-    if( poNewRing->getCoordinateDimension() == 3 )
-        nCoordDimension = 3;
+    return TRUE;
 }
 
 /************************************************************************/
@@ -364,9 +223,9 @@ int OGRPolygon::WkbSize() const
     int         nSize = 9;
     int         b3D = getCoordinateDimension() == 3;
 
-    for( int i = 0; i < nRingCount; i++ )
+    for( int i = 0; i < oCC.nCurveCount; i++ )
     {
-        nSize += papoRings[i]->_WkbSize( b3D );
+        nSize += ((OGRLinearRing*)oCC.papoCurves[i])->_WkbSize( b3D );
     }
 
     return nSize;
@@ -380,109 +239,41 @@ int OGRPolygon::WkbSize() const
 /************************************************************************/
 
 OGRErr OGRPolygon::importFromWkb( unsigned char * pabyData,
-                                  int nSize )
+                                  int nSize,
+                                  OGRwkbVariant eWkbVariant )
 
 {
-    OGRwkbByteOrder     eByteOrder;
-    int                 nDataOffset;
-    
-    if( nSize < 9 && nSize != -1 )
-        return OGRERR_NOT_ENOUGH_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the byte order byte.                                        */
-/* -------------------------------------------------------------------- */
-    eByteOrder = DB2_V72_FIX_BYTE_ORDER((OGRwkbByteOrder) *pabyData);
-    if (!( eByteOrder == wkbXDR || eByteOrder == wkbNDR ))
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Get the geometry feature type.  For now we assume that          */
-/*      geometry type is between 0 and 255 so we only have to fetch     */
-/*      one byte.                                                       */
-/* -------------------------------------------------------------------- */
-
-    OGRBoolean b3D;
-    OGRwkbGeometryType eGeometryType;
-    OGRErr err = OGRReadWKBGeometryType( pabyData, &eGeometryType, &b3D );
-
-    if( err != OGRERR_NONE || eGeometryType != wkbPolygon )
-        return OGRERR_CORRUPT_DATA;
-
-    if( b3D )
-        nCoordDimension = 3;
-    else
-        nCoordDimension = 2;
-
-
-/* -------------------------------------------------------------------- */
-/*      Do we already have some rings?                                  */
-/* -------------------------------------------------------------------- */
-    if( nRingCount != 0 )
-    {
-        for( int iRing = 0; iRing < nRingCount; iRing++ )
-            delete papoRings[iRing];
-
-        OGRFree( papoRings );
-        papoRings = NULL;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Get the ring count.                                             */
-/* -------------------------------------------------------------------- */
-    memcpy( &nRingCount, pabyData + 5, 4 );
-    
-    if( OGR_SWAP( eByteOrder ) )
-        nRingCount = CPL_SWAP32(nRingCount);
-
-    if (nRingCount < 0 || nRingCount > INT_MAX / 4)
-    {
-        nRingCount = 0;
-        return OGRERR_CORRUPT_DATA;
-    }
-
-    /* Each ring has a minimum of 4 bytes (point count) */
-    if (nSize != -1 && nSize - 9 < nRingCount * 4)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Length of input WKB is too small" );
-        nRingCount = 0;
-        return OGRERR_NOT_ENOUGH_DATA;
-    }
-
-    papoRings = (OGRLinearRing **) VSIMalloc2(sizeof(void*), nRingCount);
-    if (nRingCount != 0 && papoRings == NULL)
-    {
-        nRingCount = 0;
-        return OGRERR_NOT_ENOUGH_MEMORY;
-    }
-
-    nDataOffset = 9;
-    if( nSize != -1 )
-        nSize -= nDataOffset;
+    OGRwkbByteOrder eByteOrder;
+    int nDataOffset = 0;
+    OGRErr eErr = oCC.importPreambuleFromWkb(this, pabyData, nSize, nDataOffset,
+                                             eByteOrder, 4, eWkbVariant);
+    if( eErr >= 0 )
+        return eErr;
 
+    int b3D = (nCoordDimension == 3);
 /* -------------------------------------------------------------------- */
 /*      Get the rings.                                                  */
 /* -------------------------------------------------------------------- */
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
     {
         OGRErr  eErr;
         
-        papoRings[iRing] = new OGRLinearRing();
-        eErr = papoRings[iRing]->_importFromWkb( eByteOrder, b3D,
+        OGRLinearRing* poLR = new OGRLinearRing();
+        oCC.papoCurves[iRing] = poLR;
+        eErr = poLR->_importFromWkb( eByteOrder, b3D,
                                                  pabyData + nDataOffset,
                                                  nSize );
         if( eErr != OGRERR_NONE )
         {
-            delete papoRings[iRing];
-            nRingCount = iRing;
+            delete oCC.papoCurves[iRing];
+            oCC.nCurveCount = iRing;
             return eErr;
         }
 
         if( nSize != -1 )
-            nSize -= papoRings[iRing]->_WkbSize( b3D );
+            nSize -= poLR->_WkbSize( b3D );
 
-        nDataOffset += papoRings[iRing]->_WkbSize( b3D );
+        nDataOffset += poLR->_WkbSize( b3D );
     }
     
     return OGRERR_NONE;
@@ -529,12 +320,12 @@ OGRErr  OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
     {
         int     nCount;
 
-        nCount = CPL_SWAP32( nRingCount );
+        nCount = CPL_SWAP32( oCC.nCurveCount );
         memcpy( pabyData+5, &nCount, 4 );
     }
     else
     {
-        memcpy( pabyData+5, &nRingCount, 4 );
+        memcpy( pabyData+5, &oCC.nCurveCount, 4 );
     }
     
     nOffset = 9;
@@ -542,12 +333,13 @@ OGRErr  OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
 /* ==================================================================== */
 /*      Serialize each of the rings.                                    */
 /* ==================================================================== */
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
     {
-        papoRings[iRing]->_exportToWkb( eByteOrder, b3D,
+        OGRLinearRing* poLR = (OGRLinearRing*) oCC.papoCurves[iRing];
+        poLR->_exportToWkb( eByteOrder, b3D,
                                         pabyData + nOffset );
 
-        nOffset += papoRings[iRing]->_WkbSize(b3D);
+        nOffset += poLR->_WkbSize(b3D);
     }
     
     return OGRERR_NONE;
@@ -563,104 +355,54 @@ OGRErr  OGRPolygon::exportToWkb( OGRwkbByteOrder eByteOrder,
 OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
 
 {
-    char        szToken[OGR_WKT_TOKEN_MAX];
-    const char  *pszInput = *ppszInput;
-
-/* -------------------------------------------------------------------- */
-/*      Clear existing rings.                                           */
-/* -------------------------------------------------------------------- */
-    empty();
-
-/* -------------------------------------------------------------------- */
-/*      Read and verify the ``POLYGON'' keyword token.                  */
-/* -------------------------------------------------------------------- */
-    pszInput = OGRWktReadToken( pszInput, szToken );
-
-    if( !EQUAL(szToken,"POLYGON") )
-        return OGRERR_CORRUPT_DATA;
-
-/* -------------------------------------------------------------------- */
-/*      Check for EMPTY ...                                             */
-/* -------------------------------------------------------------------- */
-    const char *pszPreScan;
     int bHasZ = FALSE, bHasM = FALSE;
+    OGRErr      eErr = importPreambuleFromWkt(ppszInput, &bHasZ, &bHasM);
+    if( eErr >= 0 )
+        return eErr;
 
-    pszPreScan = OGRWktReadToken( pszInput, szToken );
-    if( EQUAL(szToken,"EMPTY") )
-    {
-        *ppszInput = (char *) pszPreScan;
-        empty();
-        return OGRERR_NONE;
-    }
+    OGRRawPoint *paoPoints = NULL;
+    int          nMaxPoints = 0;
+    double      *padfZ = NULL;
 
-/* -------------------------------------------------------------------- */
-/*      Check for Z, M or ZM. Will ignore the Measure                   */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(szToken,"Z") )
-    {
-        bHasZ = TRUE;
-    }
-    else if( EQUAL(szToken,"M") )
-    {
-        bHasM = TRUE;
-    }
-    else if( EQUAL(szToken,"ZM") )
-    {
-        bHasZ = TRUE;
-        bHasM = TRUE;
-    }
+    eErr = importFromWKTListOnly( ppszInput, bHasZ, bHasM,
+                                  paoPoints, nMaxPoints, padfZ );
 
-    if (bHasZ || bHasM)
-    {
-        pszInput = pszPreScan;
-        pszPreScan = OGRWktReadToken( pszInput, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            *ppszInput = (char *) pszPreScan;
-            empty();
-            /* FIXME?: In theory we should store the dimension and M presence */
-            /* if we want to allow round-trip with ExportToWKT v1.2 */
-            return OGRERR_NONE;
-        }
-    }
+    CPLFree( paoPoints );
+    CPLFree( padfZ );
 
-    if( !EQUAL(szToken,"(") )
-        return OGRERR_CORRUPT_DATA;
+    return eErr;
+}
 
-    if ( !bHasZ && !bHasM )
-    {
-        /* Test for old-style POLYGON(EMPTY) */
-        pszPreScan = OGRWktReadToken( pszPreScan, szToken );
-        if( EQUAL(szToken,"EMPTY") )
-        {
-            pszPreScan = OGRWktReadToken( pszPreScan, szToken );
+/************************************************************************/
+/*                        importFromWKTListOnly()                       */
+/*                                                                      */
+/*      Instantiate from "((x y, x y, ...),(x y, ...),...)"             */
+/************************************************************************/
 
-            if( EQUAL(szToken,",") )
-            {
-                /* This is OK according to SFSQL SPEC. */
-            }
-            else if( !EQUAL(szToken,")") )
-                return OGRERR_CORRUPT_DATA;
-            else
-            {
-                *ppszInput = (char *) pszPreScan;
-                empty();
-                return OGRERR_NONE;
-            }
-        }
-    }
+OGRErr OGRPolygon::importFromWKTListOnly( char ** ppszInput, int bHasZ, int bHasM,
+                                          OGRRawPoint*& paoPoints, int& nMaxPoints,
+                                          double*& padfZ )
+
+{
+    char        szToken[OGR_WKT_TOKEN_MAX];
+    const char  *pszInput = *ppszInput;
 
     /* Skip first '(' */
     pszInput = OGRWktReadToken( pszInput, szToken );
+    if( EQUAL(szToken, "EMPTY") )
+    {
+        *ppszInput = (char*) pszInput;
+        return OGRERR_NONE;
+    }
+    if( !EQUAL(szToken, "(") )
+        return OGRERR_CORRUPT_DATA;
 
 /* ==================================================================== */
 /*      Read each ring in turn.  Note that we try to reuse the same     */
 /*      point list buffer from ring to ring to cut down on              */
 /*      allocate/deallocate overhead.                                   */
 /* ==================================================================== */
-    OGRRawPoint *paoPoints = NULL;
-    int         nMaxPoints = 0, nMaxRings = 0;
-    double      *padfZ = NULL;
+    int         nMaxRings = 0;
 
     nCoordDimension = 2;
     
@@ -674,14 +416,14 @@ OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
 /* -------------------------------------------------------------------- */
 /*      Do we need to grow the ring array?                              */
 /* -------------------------------------------------------------------- */
-            if( nRingCount == nMaxRings )
+            if( oCC.nCurveCount == nMaxRings )
             {
                 nMaxRings = nMaxRings * 2 + 1;
-                papoRings = (OGRLinearRing **)
-                    CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
+                oCC.papoCurves = (OGRCurve **)
+                    CPLRealloc(oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing*));
             }
-            papoRings[nRingCount] = new OGRLinearRing();
-            nRingCount++;
+            oCC.papoCurves[oCC.nCurveCount] = new OGRLinearRing();
+            oCC.nCurveCount++;
 
             pszInput = OGRWktReadToken( pszNext, szToken );
             if ( !EQUAL(szToken, ",") )
@@ -698,31 +440,31 @@ OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
 
         if( pszInput == NULL || nPoints == 0 )
         {
-            CPLFree( paoPoints );
             return OGRERR_CORRUPT_DATA;
         }
         
 /* -------------------------------------------------------------------- */
 /*      Do we need to grow the ring array?                              */
 /* -------------------------------------------------------------------- */
-        if( nRingCount == nMaxRings )
+        if( oCC.nCurveCount == nMaxRings )
         {
             nMaxRings = nMaxRings * 2 + 1;
-            papoRings = (OGRLinearRing **)
-                CPLRealloc(papoRings, nMaxRings * sizeof(OGRLinearRing*));
+            oCC.papoCurves = (OGRCurve **)
+                CPLRealloc(oCC.papoCurves, nMaxRings * sizeof(OGRLinearRing*));
         }
 
 /* -------------------------------------------------------------------- */
 /*      Create the new ring, and assign to ring list.                   */
 /* -------------------------------------------------------------------- */
-        papoRings[nRingCount] = new OGRLinearRing();
+        OGRLinearRing* poLR = new OGRLinearRing();
+        oCC.papoCurves[oCC.nCurveCount] = poLR;
         /* Ignore Z array when we have a POLYGON M */
         if (bHasM && !bHasZ)
-            papoRings[nRingCount]->setPoints( nPoints, paoPoints, NULL );
+            poLR->setPoints( nPoints, paoPoints, NULL );
         else
-            papoRings[nRingCount]->setPoints( nPoints, paoPoints, padfZ );
+            poLR->setPoints( nPoints, paoPoints, padfZ );
 
-        nRingCount++;
+        oCC.nCurveCount++;
 
         if( padfZ && !(bHasM && !bHasZ) )
             nCoordDimension = 3;
@@ -737,8 +479,6 @@ OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
 /* -------------------------------------------------------------------- */
 /*      freak if we don't get a closing bracket.                        */
 /* -------------------------------------------------------------------- */
-    CPLFree( paoPoints );
-    CPLFree( padfZ );
 
     if( szToken[0] != ')' )
         return OGRERR_CORRUPT_DATA;
@@ -754,7 +494,8 @@ OGRErr OGRPolygon::importFromWkt( char ** ppszInput )
 /*      equivelent.  This could be made alot more CPU efficient!        */
 /************************************************************************/
 
-OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
+OGRErr OGRPolygon::exportToWkt( char ** ppszDstText,
+                                OGRwkbVariant eWkbVariant ) const
 
 {
     char        **papszRings;
@@ -768,25 +509,29 @@ OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
     if (getExteriorRing() == NULL || 
         getExteriorRing()->IsEmpty() )
     {
-        *ppszDstText = CPLStrdup("POLYGON EMPTY");
+        if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+            *ppszDstText = CPLStrdup("POLYGON Z EMPTY");
+        else
+            *ppszDstText = CPLStrdup("POLYGON EMPTY");
         return OGRERR_NONE;
     }
 
 /* -------------------------------------------------------------------- */
 /*      Build a list of strings containing the stuff for each ring.     */
 /* -------------------------------------------------------------------- */
-    papszRings = (char **) CPLCalloc(sizeof(char *),nRingCount);
+    papszRings = (char **) CPLCalloc(sizeof(char *),oCC.nCurveCount);
 
-    for( iRing = 0; iRing < nRingCount; iRing++ )
+    for( iRing = 0; iRing < oCC.nCurveCount; iRing++ )
     {
-        papoRings[iRing]->setCoordinateDimension( getCoordinateDimension() );
-        if( papoRings[iRing]->getNumPoints() == 0 )
+        OGRLinearRing* poLR = (OGRLinearRing*) oCC.papoCurves[iRing];
+        poLR->setCoordinateDimension( getCoordinateDimension() );
+        if( poLR->getNumPoints() == 0 )
         {
             papszRings[iRing] = NULL;
             continue;
         }
 
-        eErr = papoRings[iRing]->exportToWkt( &(papszRings[iRing]) );
+        eErr = poLR->exportToWkt( &(papszRings[iRing]) );
         if( eErr != OGRERR_NONE )
             goto error;
 
@@ -800,7 +545,7 @@ OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
 /*      Allocate exactly the right amount of space for the              */
 /*      aggregated string.                                              */
 /* -------------------------------------------------------------------- */
-    *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nNonEmptyRings + 11);
+    *ppszDstText = (char *) VSIMalloc(nCumulativeLength + nNonEmptyRings + 15);
 
     if( *ppszDstText == NULL )
     {
@@ -811,10 +556,13 @@ OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
 /* -------------------------------------------------------------------- */
 /*      Build up the string, freeing temporary strings as we go.        */
 /* -------------------------------------------------------------------- */
-    strcpy( *ppszDstText, "POLYGON (" );
+    if( getCoordinateDimension() == 3 && eWkbVariant == wkbVariantIso )
+        strcpy( *ppszDstText, "POLYGON Z (" );
+    else
+        strcpy( *ppszDstText, "POLYGON (" );
     nCumulativeLength = strlen(*ppszDstText);
 
-    for( iRing = 0; iRing < nRingCount; iRing++ )
+    for( iRing = 0; iRing < oCC.nCurveCount; iRing++ )
     {                                                           
         if( papszRings[iRing] == NULL )
         {
@@ -840,7 +588,7 @@ OGRErr OGRPolygon::exportToWkt( char ** ppszDstText ) const
     return OGRERR_NONE;
 
 error:
-    for( iRing = 0; iRing < nRingCount; iRing++ )
+    for( iRing = 0; iRing < oCC.nCurveCount; iRing++ )
         CPLFree(papszRings[iRing]);
     CPLFree(papszRings);
     return eErr;
@@ -872,276 +620,135 @@ int OGRPolygon::PointOnSurface( OGRPoint *poPoint ) const
     return OGRERR_NONE;
 }
 
-
 /************************************************************************/
-/*                            getEnvelope()                             */
+/*                           IsPointOnSurface()                           */
 /************************************************************************/
 
-void OGRPolygon::getEnvelope( OGREnvelope * psEnvelope ) const
-
+OGRBoolean OGRPolygon::IsPointOnSurface( const OGRPoint * pt) const
 {
-    OGREnvelope         oRingEnv;
-    int                 bExtentSet = FALSE;
+    if ( NULL == pt)
+        return 0;
 
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
     {
-        if (!papoRings[iRing]->IsEmpty())
+        if ( ((OGRLinearRing*)oCC.papoCurves[iRing])->isPointInRing(pt) )
         {
-            if (!bExtentSet)
-            {
-                papoRings[iRing]->getEnvelope( psEnvelope );
-                bExtentSet = TRUE;
-            }
-            else
-            {
-                papoRings[iRing]->getEnvelope( &oRingEnv );
-
-                if( psEnvelope->MinX > oRingEnv.MinX )
-                    psEnvelope->MinX = oRingEnv.MinX;
-                if( psEnvelope->MinY > oRingEnv.MinY )
-                    psEnvelope->MinY = oRingEnv.MinY;
-                if( psEnvelope->MaxX < oRingEnv.MaxX )
-                    psEnvelope->MaxX = oRingEnv.MaxX;
-                if( psEnvelope->MaxY < oRingEnv.MaxY )
-                    psEnvelope->MaxY = oRingEnv.MaxY;
-            }
+            return 1;
         }
     }
 
-    if (!bExtentSet)
-    {
-        psEnvelope->MinX = psEnvelope->MinY = 0;
-        psEnvelope->MaxX = psEnvelope->MaxY = 0;
-    }
+    return 0;
 }
 
 /************************************************************************/
-/*                            getEnvelope()                             */
+/*                             closeRings()                             */
 /************************************************************************/
- 
-void OGRPolygon::getEnvelope( OGREnvelope3D * psEnvelope ) const
 
-{
-    OGREnvelope3D       oRingEnv;
-    int                 bExtentSet = FALSE;
-
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-    {
-        if (!papoRings[iRing]->IsEmpty())
-        {
-            if (!bExtentSet)
-            {
-                papoRings[iRing]->getEnvelope( psEnvelope );
-                bExtentSet = TRUE;
-            }
-            else
-            {
-                papoRings[iRing]->getEnvelope( &oRingEnv );
-
-                if( psEnvelope->MinX > oRingEnv.MinX )
-                    psEnvelope->MinX = oRingEnv.MinX;
-                if( psEnvelope->MinY > oRingEnv.MinY )
-                    psEnvelope->MinY = oRingEnv.MinY;
-                if( psEnvelope->MaxX < oRingEnv.MaxX )
-                    psEnvelope->MaxX = oRingEnv.MaxX;
-                if( psEnvelope->MaxY < oRingEnv.MaxY )
-                    psEnvelope->MaxY = oRingEnv.MaxY;
-
-                if( psEnvelope->MinZ > oRingEnv.MinZ )
-                    psEnvelope->MinZ = oRingEnv.MinZ;
-                if( psEnvelope->MaxZ < oRingEnv.MaxZ )
-                    psEnvelope->MaxZ = oRingEnv.MaxZ;
-            }
-        }
-    }
+void OGRPolygon::closeRings()
 
-    if (!bExtentSet)
-    {
-        psEnvelope->MinX = psEnvelope->MinY = psEnvelope->MinZ = 0;
-        psEnvelope->MaxX = psEnvelope->MaxY = psEnvelope->MaxZ = 0;
-    }
+{
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
+        oCC.papoCurves[iRing]->closeRings();
 }
 
 /************************************************************************/
-/*                               Equal()                                */
+/*                           CurvePolyToPoly()                          */
 /************************************************************************/
 
-OGRBoolean OGRPolygon::Equals( OGRGeometry * poOther ) const
-
+OGRPolygon* OGRPolygon::CurvePolyToPoly(CPL_UNUSED double dfMaxAngleStepSizeDegrees,
+                                        CPL_UNUSED const char* const* papszOptions) const
 {
-    OGRPolygon *poOPoly = (OGRPolygon *) poOther;
-
-    if( poOPoly == this )
-        return TRUE;
-    
-    if( poOther->getGeometryType() != getGeometryType() )
-        return FALSE;
-
-    if ( IsEmpty() && poOther->IsEmpty() )
-        return TRUE;
-
-    if( getNumInteriorRings() != poOPoly->getNumInteriorRings() )
-        return FALSE;
-
-    if( getExteriorRing() == NULL && poOPoly->getExteriorRing() == NULL )
-        /* ok */;
-    else if( getExteriorRing() == NULL || poOPoly->getExteriorRing() == NULL )
-        return FALSE;
-    else if( !getExteriorRing()->Equals( poOPoly->getExteriorRing() ) )
-        return FALSE;
-    
-    // we should eventually test the SRS.
-
-    for( int iRing = 0; iRing < getNumInteriorRings(); iRing++ )
-    {
-        if( !getInteriorRing(iRing)->Equals(poOPoly->getInteriorRing(iRing)) )
-            return FALSE;
-    }
-
-    return TRUE;
+    return (OGRPolygon*) clone();
 }
 
 /************************************************************************/
-/*                             transform()                              */
+/*                         hasCurveGeometry()                           */
 /************************************************************************/
 
-OGRErr OGRPolygon::transform( OGRCoordinateTransformation *poCT )
-
+OGRBoolean OGRPolygon::hasCurveGeometry(CPL_UNUSED int bLookForNonLinear) const
 {
-#ifdef DISABLE_OGRGEOM_TRANSFORM
-    return OGRERR_FAILURE;
-#else
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-    {
-        OGRErr  eErr;
-
-        eErr = papoRings[iRing]->transform( poCT );
-        if( eErr != OGRERR_NONE )
-        {
-            if( iRing != 0 )
-            {
-                CPLDebug("OGR", 
-                         "OGRPolygon::transform() failed for a ring other\n"
-                         "than the first, meaning some rings are transformed\n"
-                         "and some are not!\n" );
-
-                return OGRERR_FAILURE;
-            }
-
-            return eErr;
-        }
-    }
-
-    assignSpatialReference( poCT->GetTargetCS() );
-
-    return OGRERR_NONE;
-#endif
+    return FALSE;
 }
 
 /************************************************************************/
-/*                           IsPointOnSurface()                           */
+/*                         getLinearGeometry()                        */
 /************************************************************************/
 
-OGRBoolean OGRPolygon::IsPointOnSurface( const OGRPoint * pt) const
+OGRGeometry* OGRPolygon::getLinearGeometry(double dfMaxAngleStepSizeDegrees,
+                                             const char* const* papszOptions) const
 {
-    if ( NULL == pt)
-        return 0;
-
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-    {
-        if ( papoRings[iRing]->isPointInRing(pt) )
-        {
-            return 1;
-        }
-    }
-
-    return 0;
+    return OGRGeometry::getLinearGeometry(dfMaxAngleStepSizeDegrees, papszOptions);
 }
 
 /************************************************************************/
-/*                             closeRings()                             */
+/*                             getCurveGeometry()                       */
 /************************************************************************/
 
-void OGRPolygon::closeRings()
-
+OGRGeometry* OGRPolygon::getCurveGeometry(const char* const* papszOptions) const
 {
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        papoRings[iRing]->closeRings();
+    OGRCurvePolygon* poCC = new OGRCurvePolygon();
+    poCC->assignSpatialReference( getSpatialReference() );
+    int bHasCurveGeometry = FALSE;
+    for( int iRing = 0; iRing < oCC.nCurveCount; iRing++ )
+    {
+        OGRCurve* poSubGeom = (OGRCurve* )oCC.papoCurves[iRing]->getCurveGeometry(papszOptions);
+        if( wkbFlatten(poSubGeom->getGeometryType()) != wkbLineString )
+            bHasCurveGeometry = TRUE;
+        poCC->addRingDirectly( poSubGeom );
+    }
+    if( !bHasCurveGeometry )
+    {
+        delete poCC;
+        return clone();
+    }
+    return poCC;
 }
 
 /************************************************************************/
-/*                              get_Area()                              */
+/*                        CastToCurvePolygon()                          */
 /************************************************************************/
 
 /**
- * \brief Compute area of polygon.
- *
- * The area is computed as the area of the outer ring less the area of all
- * internal rings. 
+ * \brief Cast to curve polygon.
  *
- * @return computed area.
+ * The passed in geometry is consumed and a new one returned .
+ * 
+ * @param poPoly the input geometry - ownership is passed to the method.
+ * @return new geometry.
  */
 
-double OGRPolygon::get_Area() const
-
+OGRCurvePolygon* OGRPolygon::CastToCurvePolygon(OGRPolygon* poPoly)
 {
-    double dfArea = 0.0;
+    OGRCurvePolygon* poCP = new OGRCurvePolygon();
+    poCP->setCoordinateDimension(poPoly->getCoordinateDimension());
+    poCP->assignSpatialReference(poPoly->getSpatialReference());
+    poCP->oCC.nCurveCount = poPoly->oCC.nCurveCount;
+    poCP->oCC.papoCurves = poPoly->oCC.papoCurves;
+    poPoly->oCC.nCurveCount = 0;
+    poPoly->oCC.papoCurves = NULL;
 
-    if( getExteriorRing() != NULL )
+    for( int iRing = 0; iRing < poCP->oCC.nCurveCount; iRing++ )
     {
-        int iRing;
-
-        dfArea = getExteriorRing()->get_Area();
-
-        for( iRing = 0; iRing < getNumInteriorRings(); iRing++ )
-            dfArea -= getInteriorRing( iRing )->get_Area();
+        poCP->oCC.papoCurves[iRing] = OGRLinearRing::CastToLineString(
+                                    (OGRLinearRing*)poCP->oCC.papoCurves[iRing] );
     }
 
-    return dfArea;
+    delete poPoly;
+    return poCP;
 }
 
 /************************************************************************/
-/*                       setCoordinateDimension()                       */
+/*                      GetCasterToPolygon()                            */
 /************************************************************************/
 
-void OGRPolygon::setCoordinateDimension( int nNewDimension )
-
-{
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        papoRings[iRing]->setCoordinateDimension( nNewDimension );
-
-    OGRGeometry::setCoordinateDimension( nNewDimension );
+OGRSurfaceCasterToPolygon OGRPolygon::GetCasterToPolygon() const {
+    return (OGRSurfaceCasterToPolygon) OGRGeometry::CastToIdentity;
 }
 
-
 /************************************************************************/
-/*                               IsEmpty()                              */
+/*                      OGRSurfaceCasterToCurvePolygon()                */
 /************************************************************************/
 
-OGRBoolean OGRPolygon::IsEmpty(  ) const
-{
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        if ( papoRings[iRing]->IsEmpty() == FALSE )
-            return FALSE;
-    return TRUE;
-}
-
-/************************************************************************/
-/*                       OGRPolygon::segmentize()                       */
-/************************************************************************/
-
-void OGRPolygon::segmentize( double dfMaxLength )
-{
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        papoRings[iRing]->segmentize(dfMaxLength);
-}
-
-/************************************************************************/
-/*                               swapXY()                               */
-/************************************************************************/
-
-void OGRPolygon::swapXY()
-{
-    for( int iRing = 0; iRing < nRingCount; iRing++ )
-        papoRings[iRing]->swapXY();
+OGRSurfaceCasterToCurvePolygon OGRPolygon::GetCasterToCurvePolygon() const {
+    return (OGRSurfaceCasterToCurvePolygon) OGRPolygon::CastToCurvePolygon;
 }
diff --git a/ogr/ogrsf_frmts/GNUmakefile b/ogr/ogrsf_frmts/GNUmakefile
index f3f8585..4d8b371 100644
--- a/ogr/ogrsf_frmts/GNUmakefile
+++ b/ogr/ogrsf_frmts/GNUmakefile
@@ -6,7 +6,7 @@ SUBDIRS-yes	:= \
 	mitab ntf gpx rec s57 sdts shape tiger vrt \
 	geoconcept xplane georss gtm dxf pgdump gpsbabel \
 	sua openair pds htf aeronavfaa edigeo svg idrisi \
-	arcgen segukooa segy sxf openfilegdb wasp
+	arcgen segukooa segy sxf openfilegdb wasp selafin jml
 
 SUBDIRS-$(HAVE_DODS)	+= dods
 SUBDIRS-$(HAVE_DWGDIRECT) += dxfdwg
@@ -32,6 +32,7 @@ SUBDIRS-$(MDB_ENABLED)  += mdb
 SUBDIRS-$(CURL_SETTING) += gft
 SUBDIRS-$(CURL_SETTING) += gme
 SUBDIRS-$(CURL_SETTING) += couchdb
+SUBDIRS-$(CURL_SETTING) += cloudant
 SUBDIRS-$(HAVE_FREEXL)  += xls
 SUBDIRS-$(HAVE_EXPAT)   += ods
 SUBDIRS-$(HAVE_EXPAT)   += xlsx
@@ -40,17 +41,8 @@ SUBDIRS-$(HAVE_SQLITE)	+= gpkg
 SUBDIRS-$(HAVE_SQLITE)	+= osm
 SUBDIRS-$(HAVE_SOSI)	+= sosi
 SUBDIRS-$(CURL_SETTING) += cartodb
-
-ifeq ($(PCIDSK_SETTING),internal)
-SUBDIRS-yes  += pcidsk
-endif
-ifeq ($(PCIDSK_SETTING),external)
-SUBDIRS-yes  += pcidsk
-endif
-
-ifneq ($(LIBZ_SETTING),no)
-SUBDIRS-yes  += pdf
-endif
+SUBDIRS-$(CURL_SETTING) += plscenes
+SUBDIRS-$(CURL_SETTING) += csw
 
 default:	$(foreach d,$(SUBDIRS-yes),$(d)-target)
 
diff --git a/ogr/ogrsf_frmts/aeronavfaa/GNUmakefile b/ogr/ogrsf_frmts/aeronavfaa/GNUmakefile
index 0ba05f0..cdf7460 100644
--- a/ogr/ogrsf_frmts/aeronavfaa/GNUmakefile
+++ b/ogr/ogrsf_frmts/aeronavfaa/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ograeronavfaadriver.o ograeronavfaadatasource.o ograeronavfaalayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../xplane $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../xplane  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/aeronavfaa/ogr_aeronavfaa.h b/ogr/ogrsf_frmts/aeronavfaa/ogr_aeronavfaa.h
index 241314e..0dbf3b6 100644
--- a/ogr/ogrsf_frmts/aeronavfaa/ogr_aeronavfaa.h
+++ b/ogr/ogrsf_frmts/aeronavfaa/ogr_aeronavfaa.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_aeronavfaa.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_aeronavfaa.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  AeronavFAA Translator
  * Purpose:  Definition of classes for OGR AeronavFAA driver.
@@ -174,8 +174,7 @@ class OGRAeronavFAADataSource : public OGRDataSource
                         OGRAeronavFAADataSource();
                         ~OGRAeronavFAADataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -185,19 +184,5 @@ class OGRAeronavFAADataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                         OGRAeronavFAADriver                          */
-/************************************************************************/
-
-class OGRAeronavFAADriver : public OGRSFDriver
-{
-  public:
-                ~OGRAeronavFAADriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
 
 #endif /* ndef _OGR_AeronavFAA_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadatasource.cpp b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadatasource.cpp
index 26a9d79..63329c7 100644
--- a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadatasource.cpp
+++ b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograeronavfaadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograeronavfaadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  AeronavFAA Translator
  * Purpose:  Implements OGRAeronavFAADataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ograeronavfaadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograeronavfaadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                      OGRAeronavFAADataSource()                       */
@@ -86,21 +86,14 @@ OGRLayer *OGRAeronavFAADataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRAeronavFAADataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRAeronavFAADataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
 // --------------------------------------------------------------------
 //      Does this appear to be a .dat file?
 // --------------------------------------------------------------------
-    if( !EQUAL(CPLGetExtension(pszFilename), "dat") )
-        return FALSE;
 
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     if (fp == NULL)
diff --git a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadriver.cpp b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadriver.cpp
index 8338dfc..8a6f9a1 100644
--- a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadriver.cpp
+++ b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaadriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograeronavfaadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograeronavfaadriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  AeronavFAA Translator
  * Purpose:  Implements OGRAeronavFAADriver.
@@ -30,41 +30,30 @@
 #include "ogr_aeronavfaa.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ograeronavfaadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograeronavfaadriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 // g++ ogr/ogrsf_frmts/aeronavfaa/*.cpp -Wall -g -fPIC -shared -o ogr_AeronavFAA.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts/aernovfaa -Iogr/ogrsf_frmts
 
 extern "C" void RegisterOGRAeronavFAA();
 
-/************************************************************************/
-/*                       ~OGRAeronavFAADriver()                         */
-/************************************************************************/
-
-OGRAeronavFAADriver::~OGRAeronavFAADriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRAeronavFAADriver::GetName()
-
-{
-    return "AeronavFAA";
-}
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRAeronavFAADriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRAeronavFAADriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if (poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "dat") )
+    {
+        return NULL;
+    }
+
     OGRAeronavFAADataSource   *poDS = new OGRAeronavFAADataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -74,21 +63,30 @@ OGRDataSource *OGRAeronavFAADriver::Open( const char * pszFilename, int bUpdate
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRAeronavFAADriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                        RegisterOGRAeronavFAA()                       */
 /************************************************************************/
 
 void RegisterOGRAeronavFAA()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRAeronavFAADriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "AeronavFAA" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "AeronavFAA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Aeronav FAA" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_aeronavfaa.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRAeronavFAADriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaalayer.cpp b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaalayer.cpp
index 51cfdbd..7b1bfba 100644
--- a/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaalayer.cpp
+++ b/ogr/ogrsf_frmts/aeronavfaa/ograeronavfaalayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograeronavfaalayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograeronavfaalayer.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  AeronavFAA Translator
  * Purpose:  Implements OGRAeronavFAALayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ograeronavfaalayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograeronavfaalayer.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                        OGRAeronavFAALayer()                          */
@@ -53,6 +53,7 @@ OGRAeronavFAALayer::OGRAeronavFAALayer( VSILFILE* fp, const char* pszLayerName )
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
     poFeatureDefn->Reference();
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    SetDescription( poFeatureDefn->GetName() );
 }
 
 /************************************************************************/
@@ -189,7 +190,7 @@ static int GetLatLon(const char* pszLat,
     memcpy(szSec, pszLat + 6, MAX((int)sizeof(szSec) - 1, nSecLen));
     szSec[MAX((int)sizeof(szSec) - 1, nSecLen)] = 0;
 
-    dfLat = atoi(szDeg) + atoi(szMin) / 60. + atof(szSec) / 3600.;
+    dfLat = atoi(szDeg) + atoi(szMin) / 60. + CPLAtof(szSec) / 3600.;
     if (chLatHemisphere == 'S')
         dfLat = -dfLat;
 
@@ -203,7 +204,7 @@ static int GetLatLon(const char* pszLat,
     memcpy(szSec, pszLon + 7, MAX((int)sizeof(szSec) - 1, nSecLen));
     szSec[MAX((int)sizeof(szSec) - 1, nSecLen)] = 0;
 
-    dfLon = atoi(szDeg) + atoi(szMin) / 60. + atof(szSec) / 3600.;
+    dfLon = atoi(szDeg) + atoi(szMin) / 60. + CPLAtof(szSec) / 3600.;
     if (chLonHemisphere == ' ' || chLonHemisphere == 'W')
         dfLon = -dfLon;
 
@@ -750,4 +751,3 @@ void OGRAeronavFAAIAPLayer::ResetReading()
     osAPTName = "";
     osAPTId = "";
 }
-
diff --git a/ogr/ogrsf_frmts/arcgen/GNUmakefile b/ogr/ogrsf_frmts/arcgen/GNUmakefile
index 1856074..20086a5 100644
--- a/ogr/ogrsf_frmts/arcgen/GNUmakefile
+++ b/ogr/ogrsf_frmts/arcgen/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ograrcgendriver.o ograrcgendatasource.o ograrcgenlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h b/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h
index b3de804..263d6b7 100644
--- a/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h
+++ b/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_arcgen.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_arcgen.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Arc/Info Generate Translator
  * Purpose:  Definition of classes for OGR .arcgen driver.
@@ -76,8 +76,7 @@ class OGRARCGENDataSource : public OGRDataSource
                         OGRARCGENDataSource();
                         ~OGRARCGENDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -87,19 +86,4 @@ class OGRARCGENDataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                             OGRARCGENDriver                             */
-/************************************************************************/
-
-class OGRARCGENDriver : public OGRSFDriver
-{
-  public:
-                ~OGRARCGENDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_ARCGEN_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp
index 93008f0..eb7543b 100644
--- a/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp
+++ b/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograrcgendatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograrcgendatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Arc/Info Generate Translator
  * Purpose:  Implements OGRARCGENDataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ograrcgendatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograrcgendatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          OGRARCGENDataSource()                          */
@@ -86,14 +86,9 @@ OGRLayer *OGRARCGENDataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRARCGENDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRARCGENDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
 // -------------------------------------------------------------------- 
@@ -104,54 +99,6 @@ int OGRARCGENDataSource::Open( const char * pszFilename, int bUpdateIn)
     if (fp == NULL)
         return FALSE;
 
-    /* Check that the first line is compatible with a generate file */
-    /* and in particular contain >= 32 && <= 127 bytes */
-    char szFirstLine[256+1];
-    int nRet = VSIFReadL(szFirstLine, 1, 256, fp);
-    szFirstLine[nRet] = '\0';
-
-    int i;
-    int bFoundEOL = FALSE;
-    for(i=0;szFirstLine[i] != '\0';i++)
-    {
-        if (szFirstLine[i] == '\n' || szFirstLine[i] == '\r')
-        {
-            bFoundEOL = TRUE;
-            szFirstLine[i] = '\0';
-            break;
-        }
-        if (szFirstLine[i] < 32)
-        {
-            VSIFCloseL(fp);
-            return FALSE;
-        }
-    }
-
-    if (!bFoundEOL)
-    {
-        VSIFCloseL(fp);
-        return FALSE;
-    }
-
-    char** papszTokens = CSLTokenizeString2( szFirstLine, " ,", 0 );
-    int nTokens = CSLCount(papszTokens);
-    if (nTokens != 1 && nTokens != 3 && nTokens != 4)
-    {
-        VSIFCloseL(fp);
-        CSLDestroy(papszTokens);
-        return FALSE;
-    }
-    for(int i=0;i<nTokens;i++)
-    {
-        if( CPLGetValueType(papszTokens[i]) == CPL_VALUE_STRING )
-        {
-            VSIFCloseL(fp);
-            CSLDestroy(papszTokens);
-            return FALSE;
-        }
-    }
-    CSLDestroy(papszTokens);
-
     /* Go to end of file, and count the number of END keywords */
     /* If there's 1, it's a point layer */
     /* If there's 2, it's a linestring or polygon layer */
diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp
index d8169f5..8a69e72 100644
--- a/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp
+++ b/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograrcgendriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograrcgendriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Arc/Info Generate Translator
  * Purpose:  Implements OGRARCGENDriver.
@@ -30,39 +30,73 @@
 #include "ogr_arcgen.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ograrcgendriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograrcgendriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGRARCGEN();
 
-/************************************************************************/
-/*                           ~OGRARCGENDriver()                            */
-/************************************************************************/
-
-OGRARCGENDriver::~OGRARCGENDriver()
-
-{
-}
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRARCGENDriver::GetName()
+static GDALDataset *OGRARCGENDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    return "ARCGEN";
-}
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL )
+    {
+        return NULL;
+    }
 
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
+    /* Check that the first line is compatible with a generate file */
+    /* and in particular contain >= 32 && <= 127 bytes */
+    int i;
+    int bFoundEOL = FALSE;
+    char* szFirstLine = CPLStrdup((const char*) poOpenInfo->pabyHeader);
+    for(i=0;szFirstLine[i] != '\0';i++)
+    {
+        if (szFirstLine[i] == '\n' || szFirstLine[i] == '\r')
+        {
+            bFoundEOL = TRUE;
+            szFirstLine[i] = '\0';
+            break;
+        }
+        if (szFirstLine[i] < 32)
+        {
+            CPLFree(szFirstLine);
+            return NULL;
+        }
+    }
 
-OGRDataSource *OGRARCGENDriver::Open( const char * pszFilename, int bUpdate )
+    if (!bFoundEOL)
+    {
+        CPLFree(szFirstLine);
+        return NULL;
+    }
+
+    char** papszTokens = CSLTokenizeString2( szFirstLine, " ,", 0 );
+    int nTokens = CSLCount(papszTokens);
+    if (nTokens != 1 && nTokens != 3 && nTokens != 4)
+    {
+        CSLDestroy(papszTokens);
+        CPLFree(szFirstLine);
+        return NULL;
+    }
+    for(int i=0;i<nTokens;i++)
+    {
+        if( CPLGetValueType(papszTokens[i]) == CPL_VALUE_STRING )
+        {
+            CSLDestroy(papszTokens);
+            CPLFree(szFirstLine);
+            return NULL;
+        }
+    }
+    CSLDestroy(papszTokens);
+    CPLFree(szFirstLine);
 
-{
     OGRARCGENDataSource   *poDS = new OGRARCGENDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -72,21 +106,30 @@ OGRDataSource *OGRARCGENDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRARCGENDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRARCGEN()                           */
 /************************************************************************/
 
 void RegisterOGRARCGEN()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRARCGENDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "ARCGEN" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "ARCGEN" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Arc/Info Generate" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_arcgen.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRARCGENDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp
index 85bff7a..29bd01d 100644
--- a/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp
+++ b/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ograrcgenlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ograrcgenlayer.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Arc/Info Generate Translator
  * Purpose:  Implements OGRARCGENLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ograrcgenlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ograrcgenlayer.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRARCGENLayer()                             */
@@ -53,6 +53,7 @@ OGRARCGENLayer::OGRARCGENLayer( const char* pszFilename,
 
     OGRFieldDefn    oField1( "ID", OFTInteger);
     poFeatureDefn->AddFieldDefn( &oField1 );
+    SetDescription( poFeatureDefn->GetName() );
 }
 
 /************************************************************************/
@@ -138,13 +139,13 @@ OGRFeature *OGRARCGENLayer::GetNextRawFeature()
                 poFeature->SetField(0, papszTokens[0]);
                 if (nTokens == 3)
                     poFeature->SetGeometryDirectly(
-                        new OGRPoint(atof(papszTokens[1]),
-                                     atof(papszTokens[2])));
+                        new OGRPoint(CPLAtof(papszTokens[1]),
+                                     CPLAtof(papszTokens[2])));
                 else
                     poFeature->SetGeometryDirectly(
-                        new OGRPoint(atof(papszTokens[1]),
-                                     atof(papszTokens[2]),
-                                     atof(papszTokens[3])));
+                        new OGRPoint(CPLAtof(papszTokens[1]),
+                                     CPLAtof(papszTokens[2]),
+                                     CPLAtof(papszTokens[3])));
                 CSLDestroy(papszTokens);
                 return poFeature;
             }
@@ -199,14 +200,14 @@ OGRFeature *OGRARCGENLayer::GetNextRawFeature()
         {
             if (nTokens == 2)
             {
-                poLS->addPoint(atof(papszTokens[0]),
-                               atof(papszTokens[1]));
+                poLS->addPoint(CPLAtof(papszTokens[0]),
+                               CPLAtof(papszTokens[1]));
             }
             else if (nTokens == 3)
             {
-                poLS->addPoint(atof(papszTokens[0]),
-                               atof(papszTokens[1]),
-                               atof(papszTokens[2]));
+                poLS->addPoint(CPLAtof(papszTokens[0]),
+                               CPLAtof(papszTokens[1]),
+                               CPLAtof(papszTokens[2]));
             }
             else
             {
@@ -229,4 +230,3 @@ int OGRARCGENLayer::TestCapability( CPL_UNUSED const char * pszCap )
 {
     return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/arcobjects/GNUmakefile b/ogr/ogrsf_frmts/arcobjects/GNUmakefile
index 5c27e45..83f9633 100644
--- a/ogr/ogrsf_frmts/arcobjects/GNUmakefile
+++ b/ogr/ogrsf_frmts/arcobjects/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	aodriver.o aoatasource.o aolayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(AO_INC) $(CPPFLAGS)
+CPPFLAGS	:=	 $(AO_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/arcobjects/aolayer.cpp b/ogr/ogrsf_frmts/arcobjects/aolayer.cpp
index c65344c..bdd0a5c 100644
--- a/ogr/ogrsf_frmts/arcobjects/aolayer.cpp
+++ b/ogr/ogrsf_frmts/arcobjects/aolayer.cpp
@@ -489,7 +489,7 @@ OGRFeature* AOLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *AOLayer::GetFeature( long oid )
+OGRFeature *AOLayer::GetFeature( GIntBig oid )
 {
   HRESULT hr;
 
@@ -516,7 +516,7 @@ OGRFeature *AOLayer::GetFeature( long oid )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int AOLayer::GetFeatureCount( int bForce )
+GIntBig AOLayer::GetFeatureCount( int bForce )
 {
   HRESULT hr;
 
diff --git a/ogr/ogrsf_frmts/arcobjects/ogr_ao.h b/ogr/ogrsf_frmts/arcobjects/ogr_ao.h
index 6eae26c..0824f2d 100644
--- a/ogr/ogrsf_frmts/arcobjects/ogr_ao.h
+++ b/ogr/ogrsf_frmts/arcobjects/ogr_ao.h
@@ -70,13 +70,13 @@ public:
 
   virtual void        ResetReading();
   virtual OGRFeature* GetNextFeature();
-  virtual OGRFeature* GetFeature( long nFeatureId );
+  virtual OGRFeature* GetFeature( GIntBig nFeatureId );
 
   HRESULT GetTable(ITable** ppTable);
 
 
   virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce );
-  virtual int         GetFeatureCount( int bForce );
+  virtual GIntBig     GetFeatureCount( int bForce );
   virtual OGRErr      SetAttributeFilter( const char *pszQuery );
   virtual void 	      SetSpatialFilterRect (double dfMinX, double dfMinY, double dfMaxX, double dfMaxY);
   virtual void        SetSpatialFilter( OGRGeometry * );
@@ -85,9 +85,9 @@ public:
   virtual OGRErr      CreateField( OGRFieldDefn *poFieldIn,
   int bApproxOK );
 
-  virtual OGRErr      SetFeature( OGRFeature *poFeature );
-  virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-  virtual OGRErr      DeleteFeature( long nFID );
+  virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+  virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+  virtual OGRErr      DeleteFeature( GIntBig nFID );
 */
    OGRFeatureDefn *    GetLayerDefn() { return m_pFeatureDefn; }
 
@@ -139,7 +139,7 @@ public:
 
   
   /*
-  virtual OGRLayer* CreateLayer( const char *,
+  virtual OGRLayer* ICreateLayer( const char *,
                                  OGRSpatialReference* = NULL,
                                  OGRwkbGeometryType = wkbUnknown,
                                  char** = NULL );
diff --git a/ogr/ogrsf_frmts/avc/GNUmakefile b/ogr/ogrsf_frmts/avc/GNUmakefile
index 87eda0a..e690f78 100644
--- a/ogr/ogrsf_frmts/avc/GNUmakefile
+++ b/ogr/ogrsf_frmts/avc/GNUmakefile
@@ -12,7 +12,7 @@ AVC_OBJ	=	avc_bin.o avc_binwr.o avc_e00gen.o avc_e00parse.o \
 
 OBJ =	$(AVC_OBJ) $(OGR_OBJ)
 
-CPPFLAGS	:=	-I../shape -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I../shape -I.. -I../..  $(CPPFLAGS)
 
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
diff --git a/ogr/ogrsf_frmts/avc/avc_bin.c b/ogr/ogrsf_frmts/avc/avc_bin.c
index 1c66b2e..2c93f29 100644
--- a/ogr/ogrsf_frmts/avc/avc_bin.c
+++ b/ogr/ogrsf_frmts/avc/avc_bin.c
@@ -1555,7 +1555,8 @@ AVCTxt *AVCBinReadNextTxt(AVCBinFile *psFile)
  *
  * Returns 0 on success or -1 on error.
  **********************************************************************/
-int _AVCBinReadNextRxp(AVCRawBinFile *psFile, AVCRxp *psRxp, 
+int _AVCBinReadNextRxp(AVCRawBinFile *psFile,
+                       AVCRxp *psRxp,
                        CPL_UNUSED int nPrecision)
 {
 
diff --git a/ogr/ogrsf_frmts/avc/avc_binwr.c b/ogr/ogrsf_frmts/avc/avc_binwr.c
index f217807..4f69f2d 100644
--- a/ogr/ogrsf_frmts/avc/avc_binwr.c
+++ b/ogr/ogrsf_frmts/avc/avc_binwr.c
@@ -1175,8 +1175,9 @@ int _AVCBinWriteTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
  *
  * Returns 0 on success or -1 on error.
  **********************************************************************/
-int _AVCBinWritePCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt, 
-                              CPL_UNUSED int nPrecision, AVCRawBinFile *psIndexFile)
+int _AVCBinWritePCCoverageTxt(AVCRawBinFile *psFile, AVCTxt *psTxt,
+                              CPL_UNUSED int nPrecision,
+                              AVCRawBinFile *psIndexFile)
 {
     int i, nRecSize, nCurPos, nStrLen, numVertices;
 
@@ -1302,7 +1303,8 @@ int AVCBinWriteTxt(AVCBinFile *psFile, AVCTxt *psTxt)
  *
  * Returns 0 on success or -1 on error.
  **********************************************************************/
-int _AVCBinWriteRxp(AVCRawBinFile *psFile, AVCRxp *psRxp, 
+int _AVCBinWriteRxp(AVCRawBinFile *psFile,
+                    AVCRxp *psRxp,
                     CPL_UNUSED int nPrecision)
 {
 
@@ -1909,11 +1911,12 @@ AVCBinFile *AVCBinWriteCreateTable(const char *pszInfoPath,
  * AVCBinClose() will eventually have to be called to release the 
  * resources used by the AVCBinFile structure.
  **********************************************************************/
-AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath, 
+AVCBinFile *_AVCBinWriteCreateDBFTable(const char *pszPath,
                                        const char *pszCoverName,
                                        AVCTableDef *psSrcTableDef,
                                        AVCCoverType eCoverType,
-                                       int nPrecision, CPL_UNUSED AVCDBCSInfo *psDBCSInfo)
+                                       int nPrecision,
+                                       CPL_UNUSED AVCDBCSInfo *psDBCSInfo)
 {
     AVCBinFile    *psFile;
     AVCTableDef   *psTableDef = NULL;
@@ -2336,4 +2339,3 @@ int AVCBinWriteTableRec(AVCBinFile *psFile, AVCField *pasFields)
                                     psFile->hdr.psTableDef->nRecSize,
                                     psFile->pszFilename);
 }
-
diff --git a/ogr/ogrsf_frmts/avc/avc_e00gen.c b/ogr/ogrsf_frmts/avc/avc_e00gen.c
index 2cb5d57..21b0d77 100644
--- a/ogr/ogrsf_frmts/avc/avc_e00gen.c
+++ b/ogr/ogrsf_frmts/avc/avc_e00gen.c
@@ -1330,7 +1330,7 @@ const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields,
                  */
                 nLen = AVCPrintRealValue(pszBuf2, AVC_DOUBLE_PREC,
                                          AVCFileTABLE,
-                                         atof((char*)pasFields[i].pszStr));
+                                         CPLAtof((char*)pasFields[i].pszStr));
                 pszBuf2 += nLen;
             }
 #endif
@@ -1343,7 +1343,7 @@ const char *AVCE00GenTableRec(AVCE00GenInfo *psInfo, int numFields,
                 pszBuf2[0] = '\0';
                 nLen = AVCPrintRealValue(pszBuf2, AVC_SINGLE_PREC, 
                                        AVCFileTABLE,
-                                         atof((char*)pasFields[i].pszStr));
+                                         CPLAtof((char*)pasFields[i].pszStr));
                 pszBuf2 += nLen;
             }
             else if (nType == AVC_FT_BININT && nSize == 4)
diff --git a/ogr/ogrsf_frmts/avc/avc_e00parse.c b/ogr/ogrsf_frmts/avc/avc_e00parse.c
index b44f3b2..4c47d5f 100644
--- a/ogr/ogrsf_frmts/avc/avc_e00parse.c
+++ b/ogr/ogrsf_frmts/avc/avc_e00parse.c
@@ -740,12 +740,12 @@ AVCArc   *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine)
          * Single precision ARCs: 2 pairs of X,Y values per line
          * Except on the last line with an odd number of vertices)
          *------------------------------------------------------------*/
-        psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine);
-        psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+14);
+        psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
+        psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine+14);
         if (psInfo->iCurItem < psInfo->numItems && nLen >= 56)
         {
-            psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine+28);
-            psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+42);
+            psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine+28);
+            psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine+42);
         }
     }
     else if (psInfo->iCurItem < psInfo->numItems && 
@@ -755,8 +755,8 @@ AVCArc   *AVCE00ParseNextArcLine(AVCE00ParseInfo *psInfo, const char *pszLine)
         /*-------------------------------------------------------------
          * Double precision ARCs: 1 pair of X,Y values per line
          *------------------------------------------------------------*/
-        psArc->pasVertices[psInfo->iCurItem].x = atof(pszLine);
-        psArc->pasVertices[psInfo->iCurItem++].y = atof(pszLine+21);
+        psArc->pasVertices[psInfo->iCurItem].x = CPLAtof(pszLine);
+        psArc->pasVertices[psInfo->iCurItem++].y = CPLAtof(pszLine+21);
     }
     else
     {
@@ -854,15 +854,15 @@ AVCPal   *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine)
 
             if (psInfo->nPrecision == AVC_SINGLE_PREC)
             {
-                psPal->sMin.x = atof(pszLine + 10);
-                psPal->sMin.y = atof(pszLine + 24);
-                psPal->sMax.x = atof(pszLine + 38);
-                psPal->sMax.y = atof(pszLine + 52);
+                psPal->sMin.x = CPLAtof(pszLine + 10);
+                psPal->sMin.y = CPLAtof(pszLine + 24);
+                psPal->sMax.x = CPLAtof(pszLine + 38);
+                psPal->sMax.y = CPLAtof(pszLine + 52);
             }
             else
             {
-                psPal->sMin.x = atof(pszLine + 10);
-                psPal->sMin.y = atof(pszLine + 31);
+                psPal->sMin.x = CPLAtof(pszLine + 10);
+                psPal->sMin.y = CPLAtof(pszLine + 31);
                 /* Set psInfo->iCurItem = -1 since we still have 2 values
                  * from the header to read on the next line.
                  */
@@ -873,8 +873,8 @@ AVCPal   *AVCE00ParseNextPalLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     }
     else if (psInfo->iCurItem == -1 && nLen >= 42)
     {
-        psPal->sMax.x = atof(pszLine);
-        psPal->sMax.y = atof(pszLine + 21);
+        psPal->sMax.x = CPLAtof(pszLine);
+        psPal->sMax.y = CPLAtof(pszLine + 21);
         psInfo->iCurItem++;
     }
     else if (psInfo->iCurItem < psPal->numArcs && 
@@ -985,13 +985,13 @@ AVCCnt   *AVCE00ParseNextCntLine(AVCE00ParseInfo *psInfo, const char *pszLine)
 
             if (psInfo->nPrecision == AVC_SINGLE_PREC)
             {
-                psCnt->sCoord.x = atof(pszLine + 10);
-                psCnt->sCoord.y = atof(pszLine + 24);
+                psCnt->sCoord.x = CPLAtof(pszLine + 10);
+                psCnt->sCoord.y = CPLAtof(pszLine + 24);
             }
             else
             {
-                psCnt->sCoord.x = atof(pszLine + 10);
-                psCnt->sCoord.y = atof(pszLine + 31);
+                psCnt->sCoord.x = CPLAtof(pszLine + 10);
+                psCnt->sCoord.y = CPLAtof(pszLine + 31);
             }
 
             /* psInfo->iCurItem is the index of the last label that was read.
@@ -1085,13 +1085,13 @@ AVCLab   *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine)
 
             if (psInfo->nPrecision == AVC_SINGLE_PREC)
             {
-                psLab->sCoord1.x = atof(pszLine + 20);
-                psLab->sCoord1.y = atof(pszLine + 34);
+                psLab->sCoord1.x = CPLAtof(pszLine + 20);
+                psLab->sCoord1.y = CPLAtof(pszLine + 34);
             }
             else
             {
-                psLab->sCoord1.x = atof(pszLine + 20);
-                psLab->sCoord1.y = atof(pszLine + 41);
+                psLab->sCoord1.x = CPLAtof(pszLine + 20);
+                psLab->sCoord1.y = CPLAtof(pszLine + 41);
             }
 
             /* psInfo->iCurItem is the index of the last X,Y pair we read.
@@ -1106,24 +1106,24 @@ AVCLab   *AVCE00ParseNextLabLine(AVCE00ParseInfo *psInfo, const char *pszLine)
     else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_SINGLE_PREC &&
              nLen >= 56 )
     {
-        psLab->sCoord2.x = atof(pszLine);
-        psLab->sCoord2.y = atof(pszLine + 14);
-        psLab->sCoord3.x = atof(pszLine + 28);
-        psLab->sCoord3.y = atof(pszLine + 42);
+        psLab->sCoord2.x = CPLAtof(pszLine);
+        psLab->sCoord2.y = CPLAtof(pszLine + 14);
+        psLab->sCoord3.x = CPLAtof(pszLine + 28);
+        psLab->sCoord3.y = CPLAtof(pszLine + 42);
         psInfo->iCurItem += 2;
     }
     else if (psInfo->iCurItem == 1 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
              nLen >= 42 )
     {
-        psLab->sCoord2.x = atof(pszLine);
-        psLab->sCoord2.y = atof(pszLine + 21);
+        psLab->sCoord2.x = CPLAtof(pszLine);
+        psLab->sCoord2.y = CPLAtof(pszLine + 21);
         psInfo->iCurItem++;
     }
     else if (psInfo->iCurItem == 2 && psInfo->nPrecision == AVC_DOUBLE_PREC &&
              nLen >= 42 )
     {
-        psLab->sCoord3.x = atof(pszLine);
-        psLab->sCoord3.y = atof(pszLine + 21);
+        psLab->sCoord3.x = CPLAtof(pszLine);
+        psLab->sCoord3.y = CPLAtof(pszLine + 21);
         psInfo->iCurItem++;
     }
     else
@@ -1187,7 +1187,7 @@ AVCTol   *AVCE00ParseNextTolLine(AVCE00ParseInfo *psInfo, const char *pszLine)
         psTol->nIndex = AVCE00Str2Int(pszLine, 10);
         psTol->nFlag  = AVCE00Str2Int(pszLine + 10, 10);
 
-        psTol->dValue = atof(pszLine + 20);
+        psTol->dValue = CPLAtof(pszLine + 20);
     }
     else
     {
@@ -1426,7 +1426,7 @@ AVCTxt   *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
             if (iCurCoord < 4 && 
                 (iVertex = iCurCoord % 4) < psTxt->numVerticesLine-1)
             {
-                psTxt->pasVertices[iVertex+1].x = atof(pszLine+i*nItemSize);
+                psTxt->pasVertices[iVertex+1].x = CPLAtof(pszLine+i*nItemSize);
                 /* The first vertex is always duplicated */
                 if (iVertex == 0)
                     psTxt->pasVertices[0].x = psTxt->pasVertices[1].x;
@@ -1434,7 +1434,7 @@ AVCTxt   *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
             else if (iCurCoord >= 4 && iCurCoord < 8 &&
                      (iVertex = iCurCoord % 4) < psTxt->numVerticesLine-1)
             {
-                psTxt->pasVertices[iVertex+1].y = atof(pszLine+i*nItemSize);
+                psTxt->pasVertices[iVertex+1].y = CPLAtof(pszLine+i*nItemSize);
                 /* The first vertex is always duplicated */
                 if (iVertex == 0)
                     psTxt->pasVertices[0].y = psTxt->pasVertices[1].y;
@@ -1443,17 +1443,17 @@ AVCTxt   *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
                      (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow)
             {
                 psTxt->pasVertices[iVertex+psTxt->numVerticesLine].x =
-                                                    atof(pszLine+i*nItemSize);
+                                                    CPLAtof(pszLine+i*nItemSize);
             }
             else if (iCurCoord >= 11 && iCurCoord < 14 &&
                      (iVertex = (iCurCoord-8) % 3) < psTxt->numVerticesArrow)
             {
                 psTxt->pasVertices[iVertex+psTxt->numVerticesLine].y =
-                                                    atof(pszLine+i*nItemSize);
+                                                    CPLAtof(pszLine+i*nItemSize);
             }
             else if (iCurCoord == 14)
             {
-                psTxt->dHeight = atof(pszLine+i*nItemSize);
+                psTxt->dHeight = CPLAtof(pszLine+i*nItemSize);
             }
 
         }
@@ -1466,7 +1466,7 @@ AVCTxt   *AVCE00ParseNextTxtLine(AVCE00ParseInfo *psInfo, const char *pszLine)
         /*-------------------------------------------------------------
          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
          *------------------------------------------------------------*/
-        psTxt->f_1e2 = (float)atof(pszLine);
+        psTxt->f_1e2 = (float)CPLAtof(pszLine);
 
         psInfo->iCurItem++;
     }
@@ -1631,7 +1631,7 @@ AVCTxt   *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine)
         /*-------------------------------------------------------------
          * Line with a -1.000E+02 value, ALWAYS SINGLE PRECISION !!!
          *------------------------------------------------------------*/
-        psTxt->f_1e2 = (float)atof(pszLine);
+        psTxt->f_1e2 = (float)CPLAtof(pszLine);
         psInfo->iCurItem++;
     }
     else if (psInfo->iCurItem < psInfo->numItems && 
@@ -1640,16 +1640,16 @@ AVCTxt   *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine)
         /*-------------------------------------------------------------
          * Line with 3 values, 1st value is text height.
          *------------------------------------------------------------*/
-        psTxt->dHeight = atof(pszLine);
+        psTxt->dHeight = CPLAtof(pszLine);
         if (psInfo->nPrecision == AVC_SINGLE_PREC)
         {
-            psTxt->dV2     = atof(pszLine+14);
-            psTxt->dV3     = atof(pszLine+28);
+            psTxt->dV2     = CPLAtof(pszLine+14);
+            psTxt->dV3     = CPLAtof(pszLine+28);
         }
         else
         {
-            psTxt->dV2     = atof(pszLine+21);
-            psTxt->dV3     = atof(pszLine+42);
+            psTxt->dV2     = CPLAtof(pszLine+21);
+            psTxt->dV3     = CPLAtof(pszLine+42);
         }
 
         psInfo->iCurItem++;
@@ -1661,11 +1661,11 @@ AVCTxt   *AVCE00ParseNextTx6Line(AVCE00ParseInfo *psInfo, const char *pszLine)
          * One line for each pair of X,Y coordinates
          * (Lines 8 to 8+numVertices-1)
          *------------------------------------------------------------*/
-        psTxt->pasVertices[ psInfo->iCurItem-8 ].x = atof(pszLine);
+        psTxt->pasVertices[ psInfo->iCurItem-8 ].x = CPLAtof(pszLine);
         if (psInfo->nPrecision == AVC_SINGLE_PREC)
-            psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+14);
+            psTxt->pasVertices[ psInfo->iCurItem-8 ].y = CPLAtof(pszLine+14);
         else
-            psTxt->pasVertices[ psInfo->iCurItem-8 ].y = atof(pszLine+21);
+            psTxt->pasVertices[ psInfo->iCurItem-8 ].y = CPLAtof(pszLine+21);
 
         psInfo->iCurItem++;
     }
@@ -1963,6 +1963,7 @@ static AVCField   *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
     AVCFieldInfo *pasDef;
     AVCTableDef *psTableDef;
     int         i, nType, nSize;
+    char        szFormat[10];
     char        *pszBuf, szTmp[30];
 
     pasFields =  psInfo->cur.pasFields;
@@ -2016,8 +2017,8 @@ static AVCField   *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
              * be different from nSize, but nSize has priority since it
              * is the actual size of the field in memory.
              */
-            pszTmpStr = CPLSPrintf("%*.*f", 
-                                   nSize, pasDef[i].nFmtPrec, atof(szTmp));
+            sprintf(szFormat, "%%%d.%df", nSize, pasDef[i].nFmtPrec);
+            pszTmpStr = CPLSPrintf(szFormat, CPLAtof(szTmp));
 
             /* If value is bigger than size, then it's too bad... we 
              * truncate it... but this should never happen in clean datasets.
@@ -2045,7 +2046,7 @@ static AVCField   *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
              */
             strncpy(szTmp, pszBuf, 14);
             szTmp[14] = '\0';
-            pasFields[i].fFloat = (float)atof(szTmp);
+            pasFields[i].fFloat = (float)CPLAtof(szTmp);
             pszBuf += 14;
         }
         else if (nType == AVC_FT_BINFLOAT && pasDef[i].nSize == 8)
@@ -2056,7 +2057,7 @@ static AVCField   *_AVCE00ParseTableRecord(AVCE00ParseInfo *psInfo)
              */
             strncpy(szTmp, pszBuf, 24);
             szTmp[24] = '\0';
-            pasFields[i].dDouble = atof(szTmp);
+            pasFields[i].dDouble = CPLAtof(szTmp);
             pszBuf += 24;
         }
         else
diff --git a/ogr/ogrsf_frmts/avc/avc_e00write.c b/ogr/ogrsf_frmts/avc/avc_e00write.c
index 727e421..f3fc844 100644
--- a/ogr/ogrsf_frmts/avc/avc_e00write.c
+++ b/ogr/ogrsf_frmts/avc/avc_e00write.c
@@ -78,7 +78,7 @@
  * Accept '-' cahracter in new coverage name
  *
  * Revision 1.6  2000/01/10 02:57:44  daniel
- * Little changes to accomodate read support for "weird" coverages
+ * Little changes to accommodate read support for "weird" coverages
  *
  * Revision 1.5  1999/12/24 07:18:34  daniel
  * Added PC Arc/Info coverages support
diff --git a/ogr/ogrsf_frmts/avc/avc_misc.c b/ogr/ogrsf_frmts/avc/avc_misc.c
index fbd0f30..7f1b200 100644
--- a/ogr/ogrsf_frmts/avc/avc_misc.c
+++ b/ogr/ogrsf_frmts/avc/avc_misc.c
@@ -347,7 +347,7 @@ char *AVCAdjustCaseSensitiveFilename(char *pszFname)
      * If we get to a point where a path component does not exist then
      * we simply return the rest of the path as is.
      *----------------------------------------------------------------*/
-    while(bValidPath && strlen(pszTmpPath) < (unsigned long)nTotalLen)
+    while(bValidPath && strlen(pszTmpPath) < (size_t)nTotalLen)
     {
         char    **papszDir=NULL;
         int     iEntry, iLastPartStart;
diff --git a/ogr/ogrsf_frmts/avc/ogr_avc.h b/ogr/ogrsf_frmts/avc/ogr_avc.h
index 6f828f8..c66a936 100644
--- a/ogr/ogrsf_frmts/avc/ogr_avc.h
+++ b/ogr/ogrsf_frmts/avc/ogr_avc.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_avc.h 14784 2008-06-28 22:25:49Z warmerdam $
+ * $Id: ogr_avc.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  Arc/Info Coverage (E00 & Binary) Reader
  * Purpose:  Declarations for OGR wrapper classes for coverage access.
@@ -129,7 +129,7 @@ class OGRAVCBinLayer : public OGRAVCLayer
 
     void		ResetReading();
     OGRFeature *	GetNextFeature();
-    OGRFeature *	GetFeature( long nFID );
+    OGRFeature *	GetFeature( GIntBig nFID );
 
     int                 TestCapability( const char * );
 };
@@ -162,21 +162,6 @@ class OGRAVCBinDataSource : public OGRAVCDataSource
     AVCE00ReadPtr       GetInfo() { return psAVC; }
 };
 
-/************************************************************************/
-/*                           OGRAVCBinDriver                            */
-/************************************************************************/
-
-class OGRAVCBinDriver : public OGRSFDriver
-{
-  public:
-    		~OGRAVCBinDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    int                 TestCapability( const char * );
-};
-
 /* ==================================================================== */
 /*      E00 (ASCII) Coverage Classes                                    */
 /* ==================================================================== */
@@ -210,8 +195,8 @@ class OGRAVCE00Layer : public OGRAVCLayer
 
     void		ResetReading();
     OGRFeature *	GetNextFeature();
-    OGRFeature *GetFeature( long nFID );
-    int GetFeatureCount(int bForce);
+    OGRFeature *GetFeature( GIntBig nFID );
+    GIntBig GetFeatureCount(int bForce);
     int CheckSetupTable(AVCE00Section *psTblSectionIn);
     int AppendTableFields( OGRFeature *poFeature );
 };
@@ -245,19 +230,5 @@ class OGRAVCE00DataSource : public OGRAVCDataSource
     virtual OGRSpatialReference *GetSpatialRef();
 };
 
-/************************************************************************/
-/*                           OGRAVCE00Driver                            */
-/************************************************************************/
-
-class OGRAVCE00Driver : public OGRSFDriver
-{
-  public:
-    		~OGRAVCE00Driver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    int                 TestCapability( const char * );
-};
 
 #endif /* _OGR_AVC_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/avc/ogravcbindatasource.cpp b/ogr/ogrsf_frmts/avc/ogravcbindatasource.cpp
index 67f517d..b827555 100644
--- a/ogr/ogrsf_frmts/avc/ogravcbindatasource.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravcbindatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravcbindatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogravcbindatasource.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRAVCBinDataSource class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogravcbindatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogravcbindatasource.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /*                        OGRAVCBinDataSource()                         */
@@ -75,7 +75,7 @@ int OGRAVCBinDataSource::Open( const char * pszNewName, int bTestOpen )
 
 {
 /* -------------------------------------------------------------------- */
-/*      Open the source file.  Supress error reporting if we are in     */
+/*      Open the source file.  Suppress error reporting if we are in    */
 /*      TestOpen mode.                                                  */
 /* -------------------------------------------------------------------- */
     if( bTestOpen )
diff --git a/ogr/ogrsf_frmts/avc/ogravcbindriver.cpp b/ogr/ogrsf_frmts/avc/ogravcbindriver.cpp
index e27d51c..7a339f0 100644
--- a/ogr/ogrsf_frmts/avc/ogravcbindriver.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravcbindriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravcbindriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogravcbindriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OGR
  * Purpose:  OGRAVCBinDriver implementation (Arc/Info Binary Coverages)
@@ -29,44 +29,52 @@
 
 #include "ogr_avc.h"
 
-CPL_CVSID("$Id: ogravcbindriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
-
-/************************************************************************/
-/*                          ~OGRAVCBinDriver()                          */
-/************************************************************************/
-
-OGRAVCBinDriver::~OGRAVCBinDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRAVCBinDriver::GetName()
-
-{
-    return "AVCBin";
-}
+CPL_CVSID("$Id: ogravcbindriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRAVCBinDriver::Open( const char * pszFilename,
-                                      int bUpdate )
+static GDALDataset *OGRAVCBinDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRAVCBinDataSource	*poDS;
     OGRAVCE00DataSource *poDSE00;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update )
+        return NULL;
+    if( !poOpenInfo->bStatOK )
         return NULL;
+    if( poOpenInfo->fpL != NULL )
+    {
+        if( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "E00") )
+        {
+            /* ok */
+        }
+        else
+        {
+            char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+            if( papszSiblingFiles != NULL )
+            {
+                int i;
+                int bFoundCandidateFile = FALSE;
+                for( i = 0; papszSiblingFiles[i] != NULL; i++ )
+                {
+                    if( EQUAL(CPLGetExtension(papszSiblingFiles[i]), "ADF") )
+                    {
+                        bFoundCandidateFile = TRUE;
+                        break;
+                    }
+                }
+                if( !bFoundCandidateFile )
+                    return NULL;
+            }
+        }
+    }
 
     poDS = new OGRAVCBinDataSource();
 
-    if( poDS->Open( pszFilename, TRUE )
+    if( poDS->Open( poOpenInfo->pszFilename, TRUE )
         && poDS->GetLayerCount() > 0 )
     {
         return poDS;
@@ -75,7 +83,7 @@ OGRDataSource *OGRAVCBinDriver::Open( const char * pszFilename,
 
     poDSE00 = new OGRAVCE00DataSource();
 
-    if( poDSE00->Open( pszFilename, TRUE )
+    if( poDSE00->Open( poOpenInfo->pszFilename, TRUE )
         && poDSE00->GetLayerCount() > 0 )
     {
         return poDSE00;
@@ -86,21 +94,27 @@ OGRDataSource *OGRAVCBinDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRAVCBinDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRAVC()                           */
 /************************************************************************/
 
 void RegisterOGRAVCBin()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( 
-        new OGRAVCBinDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "AVCBin" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "AVCBin" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Arc/Info Binary Coverage" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_avcbin.html" );
+
+        poDriver->pfnOpen = OGRAVCBinDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/avc/ogravcbinlayer.cpp b/ogr/ogrsf_frmts/avc/ogravcbinlayer.cpp
index 0ec2218..b330e3d 100644
--- a/ogr/ogrsf_frmts/avc/ogravcbinlayer.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravcbinlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravcbinlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogravcbinlayer.cpp 28383 2015-01-30 15:47:59Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRAVCBinLayer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogravcbinlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogravcbinlayer.cpp 28383 2015-01-30 15:47:59Z rouault $");
 
 /************************************************************************/
 /*                           OGRAVCBinLayer()                           */
@@ -116,9 +116,12 @@ void OGRAVCBinLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRAVCBinLayer::GetFeature( long nFID )
+OGRFeature *OGRAVCBinLayer::GetFeature( GIntBig nFID )
 
 {
+    if( (GIntBig)(int)nFID != nFID )
+        return NULL;
+
 /* -------------------------------------------------------------------- */
 /*      If we haven't started yet, open the file now.                   */
 /* -------------------------------------------------------------------- */
@@ -150,7 +153,7 @@ OGRFeature *OGRAVCBinLayer::GetFeature( long nFID )
     else
     {
         bNeedReset = TRUE;
-        pFeature = AVCBinReadObject( hFile, nFID );
+        pFeature = AVCBinReadObject( hFile, (int)nFID );
     }
         
     if( pFeature == NULL )
@@ -424,7 +427,7 @@ int OGRAVCBinLayer::AppendTableFields( OGRFeature *poFeature )
     void *hRecord;
 
     if( nTableAttrIndex == -1 )
-        nRecordId = poFeature->GetFID();
+        nRecordId = (int) poFeature->GetFID();
     else
         nRecordId = poFeature->GetFieldAsInteger( nTableAttrIndex );
 
diff --git a/ogr/ogrsf_frmts/avc/ogravce00datasource.cpp b/ogr/ogrsf_frmts/avc/ogravce00datasource.cpp
index c37d202..b759c5a 100644
--- a/ogr/ogrsf_frmts/avc/ogravce00datasource.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravce00datasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravce00datasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogravce00datasource.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRAVCE00DataSource class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogravce00datasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogravce00datasource.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /************************************************************************/
 /*                        OGRAVCE00DataSource()                         */
@@ -73,7 +73,7 @@ int OGRAVCE00DataSource::Open( const char * pszNewName, int bTestOpen )
 
 {
 /* -------------------------------------------------------------------- */
-/*      Open the source file.  Supress error reporting if we are in     */
+/*      Open the source file.  Suppress error reporting if we are in    */
 /*      TestOpen mode.                                                  */
 /* -------------------------------------------------------------------- */
     int bCompressed = FALSE;
diff --git a/ogr/ogrsf_frmts/avc/ogravce00driver.cpp b/ogr/ogrsf_frmts/avc/ogravce00driver.cpp
index e0c22c9..d5d8659 100644
--- a/ogr/ogrsf_frmts/avc/ogravce00driver.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravce00driver.cpp
@@ -2,7 +2,7 @@
  * $Id: ogravcbindriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
  *
  * Project:  OGR
- * Purpose:  OGRAVCE00Driver implementation (Arc/Info Binary Coverages)
+ * Purpose:  OGRAVCE00Driver implementation (Arc/Info E00ary Coverages)
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -32,40 +32,24 @@
 CPL_CVSID("$Id: ogravcbindriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
 
 /************************************************************************/
-/*                          ~OGRAVCE00Driver()                          */
-/************************************************************************/
-
-OGRAVCE00Driver::~OGRAVCE00Driver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRAVCE00Driver::GetName()
-
-{
-    return "AVCE00";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRAVCE00Driver::Open( const char * pszFilename,
-                                      int bUpdate )
+static GDALDataset *OGRAVCE00DriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRAVCE00DataSource *poDSE00;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update )
+        return NULL;
+    if( !poOpenInfo->bStatOK )
+        return NULL;
+    if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "E00") )
         return NULL;
 
     poDSE00 = new OGRAVCE00DataSource();
 
-    if( poDSE00->Open( pszFilename, TRUE )
+    if( poDSE00->Open( poOpenInfo->pszFilename, TRUE )
         && poDSE00->GetLayerCount() > 0 )
     {
         return poDSE00;
@@ -76,21 +60,28 @@ OGRDataSource *OGRAVCE00Driver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRAVCE00Driver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRAVC()                           */
 /************************************************************************/
 
 void RegisterOGRAVCE00()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( 
-        new OGRAVCE00Driver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "AVCE00" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "AVCE00" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Arc/Info E00 (ASCII) Coverage" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "e00" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_avce00.html" );
+
+        poDriver->pfnOpen = OGRAVCE00DriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/avc/ogravce00layer.cpp b/ogr/ogrsf_frmts/avc/ogravce00layer.cpp
index acf48b3..6056e09 100644
--- a/ogr/ogrsf_frmts/avc/ogravce00layer.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravce00layer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravce00layer.cpp 23907 2012-02-04 23:04:59Z rouault $
+ * $Id: ogravce00layer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRAVCE00Layer class.
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogravce00layer.cpp 23907 2012-02-04 23:04:59Z rouault $");
+CPL_CVSID("$Id: ogravce00layer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                           OGRAVCE00Layer()                           */
@@ -135,7 +135,7 @@ void OGRAVCE00Layer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRAVCE00Layer::GetFeature( long nFID )
+OGRFeature *OGRAVCE00Layer::GetFeature( GIntBig nFID )
 
 {
 /* -------------------------------------------------------------------- */
@@ -491,7 +491,7 @@ int OGRAVCE00Layer::AppendTableFields( OGRFeature *poFeature )
     void *hRecord;
 
     if( nTableAttrIndex == -1 )
-        nRecordId = poFeature->GetFID();
+        nRecordId = (int) poFeature->GetFID();
     else
         nRecordId = poFeature->GetFieldAsInteger( nTableAttrIndex );
 
@@ -522,7 +522,7 @@ int OGRAVCE00Layer::AppendTableFields( OGRFeature *poFeature )
 }
 
 
-int OGRAVCE00Layer::GetFeatureCount(int bForce)
+GIntBig OGRAVCE00Layer::GetFeatureCount(int bForce)
 {
     if (m_poAttrQuery != NULL || m_poFilterGeom != NULL)
         return OGRAVCLayer::GetFeatureCount(bForce);
@@ -531,7 +531,7 @@ int OGRAVCE00Layer::GetFeatureCount(int bForce)
     {
         if (psSection->nFeatureCount < 0)
         {
-            nFeatureCount = OGRLayer::GetFeatureCount(bForce);
+            nFeatureCount = (int) OGRLayer::GetFeatureCount(bForce);
         }
         else
         {
diff --git a/ogr/ogrsf_frmts/avc/ogravclayer.cpp b/ogr/ogrsf_frmts/avc/ogravclayer.cpp
index baad055..9f79981 100644
--- a/ogr/ogrsf_frmts/avc/ogravclayer.cpp
+++ b/ogr/ogrsf_frmts/avc/ogravclayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogravclayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogravclayer.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OGR
  * Purpose:  Implements OGRAVCLayer class.  This is the base class for E00
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogravclayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogravclayer.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                           OGRAVCLayer()                           */
@@ -178,6 +178,8 @@ int OGRAVCLayer::SetupFeatureDefinition( const char *pszName )
         poFeatureDefn = NULL;
         return FALSE;
     }
+
+    SetDescription( pszName );
 }
 
 /************************************************************************/
@@ -590,9 +592,3 @@ int OGRAVCLayer::TranslateTableFields( OGRFeature *poFeature,
 
     return TRUE;
 }
-
-
-
-
-
-
diff --git a/ogr/ogrsf_frmts/bna/GNUmakefile b/ogr/ogrsf_frmts/bna/GNUmakefile
index 8ba39c3..3861a40 100644
--- a/ogr/ogrsf_frmts/bna/GNUmakefile
+++ b/ogr/ogrsf_frmts/bna/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrbnadriver.o ogrbnadatasource.o ogrbnalayer.o ogrbnaparser.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/bna/ogr_bna.h b/ogr/ogrsf_frmts/bna/ogr_bna.h
index 6737bd7..0a778e1 100644
--- a/ogr/ogrsf_frmts/bna/ogr_bna.h
+++ b/ogr/ogrsf_frmts/bna/ogr_bna.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_bna.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_bna.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  BNA Translator
  * Purpose:  Definition of classes for OGR .bna driver.
@@ -87,12 +87,12 @@ class OGRBNALayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
     
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK );
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
     
-    OGRFeature *        GetFeature( long nFID );
+    OGRFeature *        GetFeature( GIntBig nFID );
 
     int                 TestCapability( const char * );
 
@@ -145,7 +145,7 @@ class OGRBNADataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer*           GetLayer( int );
     
-    OGRLayer *          CreateLayer( const char * pszLayerName,
+    OGRLayer *          ICreateLayer( const char * pszLayerName,
                                     OGRSpatialReference *poSRS,
                                     OGRwkbGeometryType eType,
                                     char ** papszOptions );
@@ -153,22 +153,4 @@ class OGRBNADataSource : public OGRDataSource
     int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                             OGRBNADriver                             */
-/************************************************************************/
-
-class OGRBNADriver : public OGRSFDriver
-{
-  public:
-                ~OGRBNADriver();
-
-    const char*         GetName();
-    OGRDataSource*      Open( const char *, int );
-    OGRDataSource*      CreateDataSource( const char * pszName, char **papszOptions );
-    int                 DeleteDataSource( const char *pszFilename );
-    int                 TestCapability( const char * );
-    
-};
-
-
 #endif /* ndef _OGR_BNA_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp b/ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp
index 28508c4..2d6130a 100644
--- a/ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp
+++ b/ogr/ogrsf_frmts/bna/ogrbnadatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrbnadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrbnadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  BNA Translator
  * Purpose:  Implements OGRBNADataSource class
@@ -102,16 +102,16 @@ OGRLayer *OGRBNADataSource::GetLayer( int iLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRBNADataSource::CreateLayer( const char * pszLayerName,
-                                          CPL_UNUSED OGRSpatialReference *poSRS,
-                                          OGRwkbGeometryType eType,
-                                          CPL_UNUSED char ** papszOptions )
+OGRLayer * OGRBNADataSource::ICreateLayer( const char * pszLayerName,
+                                           CPL_UNUSED OGRSpatialReference *poSRS,
+                                           OGRwkbGeometryType eType,
+                                           CPL_UNUSED char ** papszOptions )
 {
     BNAFeatureType bnaFeatureType;
-    
+
     switch(eType)
     {
         case wkbPolygon:
@@ -156,22 +156,6 @@ int OGRBNADataSource::Open( const char * pszFilename, int bUpdateIn)
 
     pszName = CPLStrdup( pszFilename );
     bUpdate = bUpdateIn;
-
-/* -------------------------------------------------------------------- */
-/*      Determine what sort of object this is.                          */
-/* -------------------------------------------------------------------- */
-    VSIStatBufL sStatBuf;
-
-    if( VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0 )
-        return FALSE;
-    
-// -------------------------------------------------------------------- 
-//      Does this appear to be a .bna file?
-// --------------------------------------------------------------------
-    if( !(EQUAL( CPLGetExtension(pszFilename), "bna" )
-           || ((EQUALN( pszFilename, "/vsigzip/", 9) || EQUALN( pszFilename, "/vsizip/", 8)) &&
-               (strstr( pszFilename, ".bna") || strstr( pszFilename, ".BNA")))) )
-        return FALSE;
     
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     if (fp)
diff --git a/ogr/ogrsf_frmts/bna/ogrbnadriver.cpp b/ogr/ogrsf_frmts/bna/ogrbnadriver.cpp
index 167b2cf..41dbb4b 100644
--- a/ogr/ogrsf_frmts/bna/ogrbnadriver.cpp
+++ b/ogr/ogrsf_frmts/bna/ogrbnadriver.cpp
@@ -31,34 +31,28 @@
 #include "cpl_conv.h"
 
 /************************************************************************/
-/*                           ~OGRBNADriver()                            */
-/************************************************************************/
-
-OGRBNADriver::~OGRBNADriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRBNADriver::GetName()
-
-{
-    return "BNA";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRBNADriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRBNADriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+// -------------------------------------------------------------------- 
+//      Does this appear to be a .bna file?
+// --------------------------------------------------------------------
+    if( poOpenInfo->fpL == NULL ||
+        !(EQUAL( CPLGetExtension(poOpenInfo->pszFilename), "bna" )
+           || ((EQUALN( poOpenInfo->pszFilename, "/vsigzip/", 9) ||
+                EQUALN( poOpenInfo->pszFilename, "/vsizip/", 8)) &&
+               (strstr( poOpenInfo->pszFilename, ".bna") ||
+                strstr( poOpenInfo->pszFilename, ".BNA")))) )
+    {
+        return NULL;
+    }
+
     OGRBNADataSource   *poDS = new OGRBNADataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update ) )
     {
         delete poDS;
         poDS = NULL;
@@ -68,12 +62,15 @@ OGRDataSource *OGRBNADriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRBNADriver::CreateDataSource( const char * pszName,
-                                                 char **papszOptions )
-
+static GDALDataset *OGRBNADriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     OGRBNADataSource   *poDS = new OGRBNADataSource();
 
@@ -87,41 +84,68 @@ OGRDataSource *OGRBNADriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                               Delete()                               */
 /************************************************************************/
 
-OGRErr OGRBNADriver::DeleteDataSource( const char *pszFilename )
+static CPLErr OGRBNADriverDelete( const char *pszFilename )
 
 {
     if( VSIUnlink( pszFilename ) == 0 )
-        return OGRERR_NONE;
+        return CE_None;
     else
-        return OGRERR_FAILURE;
+        return CE_Failure;
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRBNADriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-
-/************************************************************************/
 /*                           RegisterOGRBNA()                           */
 /************************************************************************/
 
 void RegisterOGRBNA()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRBNADriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "BNA" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "BNA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Atlas BNA" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "bna" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_bna.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+#ifdef WIN32
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='CRLF'>"
+#else
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='LF'>"
+#endif
+"    <Value>CRLF</Value>"
+"    <Value>LF</Value>"
+"  </Option>"
+"  <Option name='MULTILINE' type='boolean' description='Whether coordinates should be put on the same line' default='NO'/>"
+"  <Option name='NB_IDS' type='string-select' description='Number of identifiers per record' default='2'>"
+"    <Value>2</Value>"
+"    <Value>3</Value>"
+"    <Value>4</Value>"
+"    <Value>NB_SOURCE_FIELDS</Value>"
+"  </Option>"
+"  <Option name='ELLIPSES_AS_ELLIPSES' type='boolean' description='Whether ellipses and circles should be recognized and written as such, instead of polygons' default='YES'/>"
+"  <Option name='NB_PAIRS_PER_LINE' type='int' description='Maximum number of coordinate pair per line in multiline format'/>"
+"  <Option name='COORDINATE_PRECISION' type='int' description='Number of decimal for coordinates' default='10'/>"
+"</CreationOptionList>");
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>");
+
+        poDriver->pfnOpen = OGRBNADriverOpen;
+        poDriver->pfnCreate = OGRBNADriverCreate;
+        poDriver->pfnDelete = OGRBNADriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/bna/ogrbnalayer.cpp b/ogr/ogrsf_frmts/bna/ogrbnalayer.cpp
index d8c171e..e1cdb33 100644
--- a/ogr/ogrsf_frmts/bna/ogrbnalayer.cpp
+++ b/ogr/ogrsf_frmts/bna/ogrbnalayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrbnalayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrbnalayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  BNA Translator
  * Purpose:  Implements OGRBNALayer class.
@@ -74,6 +74,7 @@ OGRBNALayer::OGRBNALayer( const char *pszFilename,
                                                    layerName ));
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( eLayerGeomType );
+    SetDescription( poFeatureDefn->GetName() );
     this->bnaFeatureType = bnaFeatureType;
 
     if (! bWriter )
@@ -146,6 +147,8 @@ void  OGRBNALayer::SetFeatureIndexTable(int nFeatures, OffsetAndLine* offsetAndL
 void OGRBNALayer::ResetReading()
 
 {
+    if( fpBNA == NULL )
+        return;
     eof = FALSE;
     failed = FALSE;
     curLine = 0;
@@ -164,7 +167,7 @@ OGRFeature *OGRBNALayer::GetNextFeature()
     BNARecord* record;
     int offset, line;
 
-    if (failed || eof) return NULL;
+    if (failed || eof || fpBNA == NULL) return NULL;
 
     while(1)
     {
@@ -284,10 +287,10 @@ void OGRBNALayer::WriteCoord(VSILFILE* fp, double dfX, double dfY)
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRBNALayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     int i,j,k,n;
@@ -560,7 +563,8 @@ OGRErr OGRBNALayer::CreateFeature( OGRFeature *poFeature )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRBNALayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRBNALayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     if( !bWriter || nFeatures != 0)
         return OGRERR_FAILURE;
@@ -829,16 +833,16 @@ void OGRBNALayer::FastParseUntil ( int interestFID)
 /*                           GetFeature()                               */
 /************************************************************************/
 
-OGRFeature *  OGRBNALayer::GetFeature( long nFID )
+OGRFeature *  OGRBNALayer::GetFeature( GIntBig nFID )
 {
     OGRFeature  *poFeature;
     BNARecord* record;
     int ok;
     
-    if (nFID < 0)
+    if (nFID < 0 || (GIntBig)(int)nFID != nFID)
         return NULL;
 
-    FastParseUntil(nFID);
+    FastParseUntil((int)nFID);
 
     if (nFID >= nFeatures)
         return NULL;
@@ -847,7 +851,7 @@ OGRFeature *  OGRBNALayer::GetFeature( long nFID )
     curLine = offsetAndLineFeaturesTable[nFID].line;
     record =  BNA_GetNextRecord(fpBNA, &ok, &curLine, TRUE, bnaFeatureType);
 
-    poFeature = BuildFeatureFromBNARecord(record, nFID);
+    poFeature = BuildFeatureFromBNARecord(record, (int)nFID);
 
     BNA_FreeRecord(record);
 
@@ -868,4 +872,3 @@ int OGRBNALayer::TestCapability( const char * pszCap )
     else
         return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/bna/ogrbnaparser.cpp b/ogr/ogrsf_frmts/bna/ogrbnaparser.cpp
index aef4527..17b7cc0 100644
--- a/ogr/ogrsf_frmts/bna/ogrbnaparser.cpp
+++ b/ogr/ogrsf_frmts/bna/ogrbnaparser.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrbnaparser.cpp 27710 2014-09-21 15:30:29Z goatbar $
+ * $Id: ogrbnaparser.cpp 27721 2014-09-22 12:42:28Z goatbar $
  *
  * Project:  BNA Parser
  * Purpose:  Parse a BNA record
diff --git a/ogr/ogrsf_frmts/bna/ogrbnaparser.h b/ogr/ogrsf_frmts/bna/ogrbnaparser.h
index 2ad5e7a..b7c63ad 100644
--- a/ogr/ogrsf_frmts/bna/ogrbnaparser.h
+++ b/ogr/ogrsf_frmts/bna/ogrbnaparser.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrbnaparser.h 27710 2014-09-21 15:30:29Z goatbar $
+ * $Id: ogrbnaparser.h 27721 2014-09-22 12:42:28Z goatbar $
  *
  * Project:  BNA Parser header
  * Purpose:  Definition of structures, enums and functions of BNA parser
diff --git a/ogr/ogrsf_frmts/cartodb/GNUmakefile b/ogr/ogrsf_frmts/cartodb/GNUmakefile
index 98e725e..cd4507a 100644
--- a/ogr/ogrsf_frmts/cartodb/GNUmakefile
+++ b/ogr/ogrsf_frmts/cartodb/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrcartodbdriver.o ogrcartodbdatasource.o ogrcartodblayer.o ogrcartodbtablelayer.o ogrcartodbresultlayer.o
 
-CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../..$(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. -I../pgdump $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/cartodb/drv_cartodb.html b/ogr/ogrsf_frmts/cartodb/drv_cartodb.html
index c907228..445e5ba 100644
--- a/ogr/ogrsf_frmts/cartodb/drv_cartodb.html
+++ b/ogr/ogrsf_frmts/cartodb/drv_cartodb.html
@@ -10,14 +10,17 @@
 (GDAL/OGR >= 1.11)<p>
 
 This driver can connect to the services implementing the CartoDB API.
-GDAL/OGR must be built with Curl support in order to the
+GDAL/OGR must be built with Curl support in order for the
 CartoDB driver to be compiled.<p>
 
 The driver supports read and write operations.<p>
 
 <h2>Dataset name syntax</h2>
 
-The minimal syntax to open a CartoDB datasource is : <pre>CartoDB:[account_name]</pre><p>
+The minimal syntax to open a CartoDB datasource is : <pre>CartoDB:[connection_name]</pre><p>
+
+For single-user accounts, connection name is the account name.
+For multi-user accounts, connection_name must be the user name, not the account name.
 
 Additionnal optional parameters can be specified after the ':' sign.
 Currently the following one is supported :<p>
@@ -82,16 +85,16 @@ The mapping between the operations of the CartoDB service and the OGR concepts i
 <li>OGRDataSource::DeleteLayer() <==> DROP TABLE operation</li>
 </ul>
 
-When inserting a new feature with CreateFeature(), and if the command is successfull, OGR will fetch the
+When inserting a new feature with CreateFeature(), and if the command is successful, OGR will fetch the
 returned rowid and use it as the OGR FID.<p>
 
-<h2>Write support and OGR transactions</h2>
-
 The above operations are by default issued to the server synchronously with the OGR API call. This however
 can cause performance penalties when issuing a lot of commands due to many client/server exchanges.<p>
 
-It is possible to surround the CreateFeature() operation between OGRLayer::StartTransaction() and OGRLayer::CommitTransaction().
-The operations will be stored into memory and only executed at the time CommitTransaction() is called.<p>
+So, on a newly created layer, the INSERT of CreateFeature() operations are grouped together
+in chunks until they reach 15 MB (can be changed with the CARTODB_MAX_CHUNK_SIZE
+configuration option, with a value in MB), at which point they are transfered
+to the server. By setting CARTODB_MAX_CHUNK_SIZE to 0, immediate transfer occurs.<p>
 
 <h2>SQL</h2>
 
@@ -99,6 +102,36 @@ SQL commands provided to the OGRDataSource::ExecuteSQL() call are executed on th
 dialect is specified. You can use the full power of PostgreSQL + PostGIS SQL
 capabilities.<p>
 
+<h2>Open options</h2>
+
+<p>Starting with GDAL 2.0, the following open options are available:</p>
+<ul>
+<li><b>BATCH_INSERT</b>=YES/NO: Whether to group feature insertions in a batch.
+Defaults to YES. Only apply in creation or update mode.</li>
+</ul>
+
+<h2>Layer creation options</h2>
+
+<p>The following layer creation options are available:</p>
+<ul>
+<li><b>OVERWRITE</b>=YES/NO: Whether to overwrite an existing table with the
+layer name to be created. Defaults to NO.</li>
+
+<li><b>GEOMETRY_NULLABLE</b>=YES/NO: Whether the values of the geometry column
+can be NULL. Defaults to YES.</li>
+
+<li><b>CARTODBFY</b>=YES/NO: Whether the created layer should be "CartoDBifi'ed"
+ (i.e. registered in dashboard). Defaults to YES.</li>
+
+<li> <b>LAUNDER</b>=YES/NO: This may be "YES" to force new fields created on this
+layer to have their field names "laundered" into a form more compatible with
+PostgreSQL.  This converts to lower case and converts some special characters
+like "-" and "#" to "_".  If "NO" exact names are preserved.  
+The default value is "YES".  If enabled the table (layer) name will also be laundered.</li>
+
+</ul>
+
+
 <h2>Examples</h2>
 
 <li>
@@ -118,7 +151,7 @@ ogr2ogr --config CARTODB_API_KEY abcdefghijklmnopqrstuvw -f CartoDB "CartoDB:mya
 <h2>See Also</h2>
 
 <ul>
-<li> <a href="http://developers.cartodb.com/documentation/apis-overview.htmll">CartoDB API overview</a><p>
+<li> <a href="http://docs.cartodb.com/cartodb-platform.html">CartoDB API overview</a><p>
 </ul>
 
 </body>
diff --git a/ogr/ogrsf_frmts/cartodb/makefile.vc b/ogr/ogrsf_frmts/cartodb/makefile.vc
index c9f07e4..0a7c1cd 100644
--- a/ogr/ogrsf_frmts/cartodb/makefile.vc
+++ b/ogr/ogrsf_frmts/cartodb/makefile.vc
@@ -1,7 +1,7 @@
 
 OBJ	=	ogrcartodbdriver.obj ogrcartodbdatasource.obj ogrcartodblayer.obj ogrcartodbtablelayer.obj ogrcartodbresultlayer.obj
 
-EXTRAFLAGS =	-I.. -I..\.. -I..\geojson\libjson
+EXTRAFLAGS =	-I.. -I..\.. -I..\geojson\libjson -I..\pgdump 
 
 GDAL_ROOT	=	..\..\..
 
diff --git a/ogr/ogrsf_frmts/cartodb/ogr_cartodb.h b/ogr/ogrsf_frmts/cartodb/ogr_cartodb.h
index df86ade..1ca38b2 100644
--- a/ogr/ogrsf_frmts/cartodb/ogr_cartodb.h
+++ b/ogr/ogrsf_frmts/cartodb/ogr_cartodb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_cartodb.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_cartodb.h 29003 2015-04-25 08:26:30Z rouault $
  *
  * Project:  CARTODB Translator
  * Purpose:  Definition of classes for OGR CartoDB driver.
@@ -73,13 +73,14 @@ protected:
     int                  bEOF;
     int                  nFetchedObjects;
     int                  iNextInFetchedObjects;
-    int                  iNext;
+    GIntBig              iNext;
     json_object         *poCachedObj;
 
-    OGRFeature          *GetNextRawFeature();
+    virtual OGRFeature  *GetNextRawFeature();
     OGRFeature          *BuildFeature(json_object* poRowObj);
 
-    void                 EstablishLayerDefn(const char* pszLayerName);
+    void                 EstablishLayerDefn(const char* pszLayerName,
+                                            json_object* poObjIn);
     OGRSpatialReference *GetSRS(const char* pszGeomCol, int *pnSRID);
     virtual CPLString    GetSRS_SQL(const char* pszGeomCol) = 0;
 
@@ -91,6 +92,10 @@ protected:
     virtual OGRFeature *        GetNextFeature();
 
     virtual OGRFeatureDefn *    GetLayerDefn();
+    virtual OGRFeatureDefn *    GetLayerDefnInternal(json_object* poObjIn) = 0;
+    virtual json_object*        FetchNewFeatures(GIntBig iNext);
+    
+    virtual const char*         GetFIDColumn() { return osFIDColName.c_str(); }
 
     virtual int                 TestCapability( const char * );
 
@@ -107,10 +112,17 @@ class OGRCARTODBTableLayer : public OGRCARTODBLayer
     CPLString           osName;
     CPLString           osQuery;
     CPLString           osWHERE;
+    CPLString           osSELECTWithoutWHERE;
+
+    int                 bLaunderColumnNames;
 
-    int                 bInTransaction;
-    CPLString           osTransactionSQL;
-    long                nNextFID;
+    int                 bInDeferedInsert;
+    CPLString           osDeferedInsertSQL;
+    GIntBig             nNextFID;
+    
+    int                 bDeferedCreation;
+    int                 bCartoDBify;
+    int                 nMaxChunkSize;
 
     void                BuildWhere();
 
@@ -121,19 +133,22 @@ class OGRCARTODBTableLayer : public OGRCARTODBLayer
                         ~OGRCARTODBTableLayer();
 
     virtual const char*         GetName() { return osName.c_str(); }
-    virtual OGRFeatureDefn *    GetLayerDefn();
+    virtual OGRFeatureDefn *    GetLayerDefnInternal(json_object* poObjIn);
+    virtual json_object*        FetchNewFeatures(GIntBig iNext);
 
-    virtual int                 GetFeatureCount( int bForce = TRUE );
-    virtual OGRFeature         *GetFeature( long nFeatureId );
+    virtual GIntBig             GetFeatureCount( int bForce = TRUE );
+    virtual OGRFeature         *GetFeature( GIntBig nFeatureId );
 
     virtual int                 TestCapability( const char * );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRFeature  *GetNextRawFeature();
+
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual void        SetSpatialFilter( OGRGeometry *poGeom ) { SetSpatialFilter(0, poGeom); }
     virtual void        SetSpatialFilter( int iGeomField, OGRGeometry *poGeom );
@@ -141,10 +156,18 @@ class OGRCARTODBTableLayer : public OGRCARTODBLayer
 
     virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce ) { return GetExtent(0, psExtent, bForce); }
     virtual OGRErr      GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce );
-    
-    virtual OGRErr      StartTransaction();
-    virtual OGRErr      CommitTransaction();
-    virtual OGRErr      RollbackTransaction();
+
+    void                SetLaunderFlag( int bFlag )
+                                { bLaunderColumnNames = bFlag; }
+    void                SetDeferedCreation( OGRwkbGeometryType eGType,
+                                            OGRSpatialReference* poSRS,
+                                            int bGeomNullable,
+                                            int bCartoDBify);
+    OGRErr              RunDeferedCreationIfNecessary();
+    int                 GetDeferedCreation() const { return bDeferedCreation; }
+    void                CancelDeferedCreation() { bDeferedCreation = FALSE; }
+
+    void                FlushDeferedInsert();
 };
 
 /************************************************************************/
@@ -153,6 +176,8 @@ class OGRCARTODBTableLayer : public OGRCARTODBLayer
 
 class OGRCARTODBResultLayer : public OGRCARTODBLayer
 {
+    OGRFeature          *poFirstFeature;
+
     virtual CPLString    GetSRS_SQL(const char* pszGeomCol);
 
   public:
@@ -160,7 +185,10 @@ class OGRCARTODBResultLayer : public OGRCARTODBLayer
                                                const char * pszRawStatement );
     virtual             ~OGRCARTODBResultLayer();
 
-    virtual OGRFeatureDefn *    GetLayerDefn();
+    virtual OGRFeatureDefn *GetLayerDefnInternal(json_object* poObjIn);
+    virtual OGRFeature  *GetNextRawFeature();
+    
+    int                 IsOK();
 };
 
 /************************************************************************/
@@ -172,24 +200,28 @@ class OGRCARTODBDataSource : public OGRDataSource
     char*               pszName;
     char*               pszAccount;
 
-    OGRLayer**          papoLayers;
+    OGRCARTODBTableLayer**  papoLayers;
     int                 nLayers;
 
     int                 bReadWrite;
+    int                 bBatchInsert;
 
     int                 bUseHTTPS;
 
     CPLString           osAPIKey;
 
     int                 bMustCleanPersistant;
-
-    int                 FetchSRSId( OGRSpatialReference * poSRS );
+    
+    CPLString           osCurrentSchema;
+    
+    int                 bHasOGRMetadataFunction;
 
   public:
                         OGRCARTODBDataSource();
                         ~OGRCARTODBDataSource();
 
     int                 Open( const char * pszFilename,
+                              char** papszOpenOptions,
                               int bUpdate );
 
     virtual const char* GetName() { return pszName; }
@@ -200,7 +232,7 @@ class OGRCARTODBDataSource : public OGRDataSource
 
     virtual int         TestCapability( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName,
+    virtual OGRLayer   *ICreateLayer( const char *pszName,
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
@@ -213,25 +245,20 @@ class OGRCARTODBDataSource : public OGRDataSource
 
     const char*                 GetAPIURL() const;
     int                         IsReadWrite() const { return bReadWrite; }
-    char**                      AddHTTPOptions(char** papszOptions = NULL);
+    int                         DoBatchInsert() const { return bBatchInsert; }
+    char**                      AddHTTPOptions();
     json_object*                RunSQL(const char* pszUnescapedSQL);
+    const CPLString&            GetCurrentSchema() { return osCurrentSchema; }
+    int                         FetchSRSId( OGRSpatialReference * poSRS );
 
     int                         IsAuthenticatedConnection() { return osAPIKey.size() != 0; }
-};
-
-/************************************************************************/
-/*                           OGRCARTODBDriver                           */
-/************************************************************************/
-
-class OGRCARTODBDriver : public OGRSFDriver
-{
-  public:
-                ~OGRCARTODBDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-
-    virtual int                 TestCapability( const char * ) { return FALSE; }
+    int                         HasOGRMetadataFunction() { return bHasOGRMetadataFunction; }
+    void                        SetOGRMetadataFunction(int bFlag) { bHasOGRMetadataFunction = bFlag; }
+    
+    OGRLayer *                  ExecuteSQLInternal( const char *pszSQLCommand,
+                                                    OGRGeometry *poSpatialFilter = NULL,
+                                                    const char *pszDialect = NULL,
+                                                    int bRunDeferedActions = FALSE );
 };
 
 #endif /* ndef _OGR_CARTODB_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/cartodb/ogrcartodbdatasource.cpp b/ogr/ogrsf_frmts/cartodb/ogrcartodbdatasource.cpp
index ac0f144..138aa5d 100644
--- a/ogr/ogrsf_frmts/cartodb/ogrcartodbdatasource.cpp
+++ b/ogr/ogrsf_frmts/cartodb/ogrcartodbdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcartodbdatasource.cpp 27268 2014-05-01 10:46:20Z rouault $
+ * $Id: ogrcartodbdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  CartoDB Translator
  * Purpose:  Implements OGRCARTODBDataSource class
@@ -28,8 +28,9 @@
  ****************************************************************************/
 
 #include "ogr_cartodb.h"
+#include "ogr_pgdump.h"
 
-CPL_CVSID("$Id: ogrcartodbdatasource.cpp 27268 2014-05-01 10:46:20Z rouault $");
+CPL_CVSID("$Id: ogrcartodbdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
 /************************************************************************/
 /*                        OGRCARTODBDataSource()                        */
@@ -45,9 +46,11 @@ OGRCARTODBDataSource::OGRCARTODBDataSource()
     pszAccount = NULL;
 
     bReadWrite = FALSE;
+    bBatchInsert = TRUE;
     bUseHTTPS = FALSE;
 
     bMustCleanPersistant = FALSE;
+    bHasOGRMetadataFunction = -1;
 }
 
 /************************************************************************/
@@ -63,7 +66,8 @@ OGRCARTODBDataSource::~OGRCARTODBDataSource()
 
     if (bMustCleanPersistant)
     {
-        char** papszOptions = CSLAddString(NULL, CPLSPrintf("CLOSE_PERSISTENT=CARTODB:%p", this));
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("CARTODB:%p", this));
         CPLHTTPFetch( GetAPIURL(), papszOptions);
         CSLDestroy(papszOptions);
     }
@@ -134,73 +138,154 @@ CPLString OGRCARTODBGetOptionValue(const char* pszFilename,
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRCARTODBDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRCARTODBDataSource::Open( const char * pszFilename,
+                                char** papszOpenOptions,
+                                int bUpdateIn )
 
 {
-    if (!EQUALN(pszFilename, "CARTODB:", strlen("CARTODB:")))
-        return FALSE;
-
     bReadWrite = bUpdateIn;
+    bBatchInsert = CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions, "BATCH_INSERT", "YES"));
 
     pszName = CPLStrdup( pszFilename );
-    pszAccount = CPLStrdup(pszFilename + strlen("CARTODB:"));
-    char* pchSpace = strchr(pszAccount, ' ');
-    if( pchSpace )
-        *pchSpace = '\0';
+    if( CSLFetchNameValue(papszOpenOptions, "ACCOUNT") )
+        pszAccount = CPLStrdup(CSLFetchNameValue(papszOpenOptions, "ACCOUNT"));
+    else
+    {
+        pszAccount = CPLStrdup(pszFilename + strlen("CARTODB:"));
+        char* pchSpace = strchr(pszAccount, ' ');
+        if( pchSpace )
+            *pchSpace = '\0';
+        if( pszAccount[0] == 0 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Missing account name");
+            return FALSE;
+        }
+    }
 
-    osAPIKey = CPLGetConfigOption("CARTODB_API_KEY", "");
+    osAPIKey = CSLFetchNameValueDef(papszOpenOptions, "API_KEY",
+                                    CPLGetConfigOption("CARTODB_API_KEY", ""));
 
     CPLString osTables = OGRCARTODBGetOptionValue(pszFilename, "tables");
+    
+    /*if( osTables.size() == 0 && osAPIKey.size() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "When not specifying tables option, CARTODB_API_KEY must be defined");
+        return FALSE;
+    }*/
 
     bUseHTTPS = CSLTestBoolean(CPLGetConfigOption("CARTODB_HTTPS", "YES"));
 
+    OGRLayer* poSchemaLayer = ExecuteSQLInternal("SELECT current_schema()");
+    if( poSchemaLayer )
+    {
+        OGRFeature* poFeat = poSchemaLayer->GetNextFeature();
+        if( poFeat )
+        {
+            if( poFeat->GetFieldCount() == 1 )
+            {
+                osCurrentSchema = poFeat->GetFieldAsString(0);
+            }
+            delete poFeat;
+        }
+        ReleaseResultSet(poSchemaLayer);
+    }
+    if( osCurrentSchema.size() == 0 )
+        return FALSE;
+
+    if( osAPIKey.size() && bUpdateIn )
+    {
+        ExecuteSQLInternal(
+                "DROP FUNCTION IF EXISTS ogr_table_metadata(TEXT,TEXT); "
+                "CREATE OR REPLACE FUNCTION ogr_table_metadata(schema_name TEXT, table_name TEXT) RETURNS TABLE "
+                "(attname TEXT, typname TEXT, attlen INT, format_type TEXT, "
+                "attnum INT, attnotnull BOOLEAN, indisprimary BOOLEAN, "
+                "defaultexpr TEXT, dim INT, srid INT, geomtyp TEXT, srtext TEXT) AS $$ "
+                "SELECT a.attname::text, t.typname::text, a.attlen::int, "
+                        "format_type(a.atttypid,a.atttypmod)::text, "
+                        "a.attnum::int, "
+                        "a.attnotnull::boolean, "
+                        "i.indisprimary::boolean, "
+                        "pg_get_expr(def.adbin, c.oid)::text AS defaultexpr, "
+                        "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_dims(a.atttypmod) ELSE NULL END)::int dim, "
+                        "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_srid(a.atttypmod) ELSE NULL END)::int srid, "
+                        "(CASE WHEN t.typname = 'geometry' THEN postgis_typmod_type(a.atttypmod) ELSE NULL END)::text geomtyp, "
+                        "srtext "
+                "FROM pg_class c "
+                "JOIN pg_attribute a ON a.attnum > 0 AND "
+                                        "a.attrelid = c.oid AND c.relname = $2 "
+                                        "AND c.relname IN (SELECT CDB_UserTables())"
+                "JOIN pg_type t ON a.atttypid = t.oid "
+                "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname = $1 "
+                "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
+                                        "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
+                "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
+                                            "def.adnum = a.attnum "
+                "LEFT JOIN spatial_ref_sys srs ON srs.srid = postgis_typmod_srid(a.atttypmod) "
+                "ORDER BY a.attnum "
+                "$$ LANGUAGE SQL");
+    }
+    
     if (osTables.size() != 0)
     {
         char** papszTables = CSLTokenizeString2(osTables, ",", 0);
         for(int i=0;papszTables && papszTables[i];i++)
         {
-            papoLayers = (OGRLayer**) CPLRealloc(
-                papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+            papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
+                papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
             papoLayers[nLayers ++] = new OGRCARTODBTableLayer(this, papszTables[i]);
         }
         CSLDestroy(papszTables);
         return TRUE;
     }
-    
-    if( osAPIKey.size() == 0 )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "When not specifying tables option, CARTODB_API_KEY must be defined");
-        return FALSE;
-    }
 
-    json_object* poObj = RunSQL("SELECT CDB_UserTables()");
-    if( poObj == NULL )
-        return FALSE;
-    json_object* poRows = json_object_object_get(poObj, "rows");
-    if( poRows == NULL || json_object_get_type(poRows) != json_type_array)
+    OGRLayer* poTableListLayer = ExecuteSQLInternal("SELECT CDB_UserTables()");
+    if( poTableListLayer )
     {
-        json_object_put(poObj);
-        return FALSE;
+        OGRFeature* poFeat;
+        while( (poFeat = poTableListLayer->GetNextFeature()) != NULL )
+        {
+            if( poFeat->GetFieldCount() == 1 )
+            {
+                papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
+                    papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
+                papoLayers[nLayers ++] = new OGRCARTODBTableLayer(
+                            this, poFeat->GetFieldAsString(0));
+            }
+            delete poFeat;
+        }
+        ReleaseResultSet(poTableListLayer);
     }
-    for(int i=0; i < json_object_array_length(poRows); i++)
+    else if( osCurrentSchema == "public" )
+        return FALSE;
+
+    /* There's currently a bug with CDB_UserTables() on multi-user accounts */
+    if( nLayers == 0 && osCurrentSchema != "public" )
     {
-        json_object* poTableNameObj = json_object_array_get_idx(poRows, i);
-        if( poTableNameObj != NULL &&
-            json_object_get_type(poTableNameObj) == json_type_object )
+        CPLString osSQL;
+        osSQL.Printf("SELECT c.relname FROM pg_class c, pg_namespace n "
+                     "WHERE c.relkind in ('r', 'v') AND c.relname !~ '^pg_' AND c.relnamespace=n.oid AND n.nspname = '%s'",
+                     OGRCARTODBEscapeLiteral(osCurrentSchema).c_str());
+        poTableListLayer = ExecuteSQLInternal(osSQL);
+        if( poTableListLayer )
         {
-            json_object* poVal = json_object_object_get(poTableNameObj, "cdb_usertables");
-            if( poVal != NULL &&
-                json_object_get_type(poVal) == json_type_string )
+            OGRFeature* poFeat;
+            while( (poFeat = poTableListLayer->GetNextFeature()) != NULL )
             {
-                papoLayers = (OGRLayer**) CPLRealloc(
-                    papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
-                papoLayers[nLayers ++] = new OGRCARTODBTableLayer(
-                            this, json_object_get_string(poVal));
+                if( poFeat->GetFieldCount() == 1 )
+                {
+                    papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
+                        papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
+                    papoLayers[nLayers ++] = new OGRCARTODBTableLayer(
+                                this, poFeat->GetFieldAsString(0));
+                }
+                delete poFeat;
             }
+            ReleaseResultSet(poTableListLayer);
         }
+        else
+            return FALSE;
     }
-    json_object_put(poObj);
 
     return TRUE;
 }
@@ -277,10 +362,10 @@ int OGRCARTODBDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 }
 
 /************************************************************************/
-/*                           CreateLayer()                              */
+/*                          ICreateLayer()                              */
 /************************************************************************/
 
-OGRLayer   *OGRCARTODBDataSource::CreateLayer( const char *pszName,
+OGRLayer   *OGRCARTODBDataSource::ICreateLayer( const char *pszName,
                                            OGRSpatialReference *poSpatialRef,
                                            OGRwkbGeometryType eGType,
                                            char ** papszOptions )
@@ -317,55 +402,23 @@ OGRLayer   *OGRCARTODBDataSource::CreateLayer( const char *pszName,
             }
         }
     }
-
-    int nSRID = 0;
-    if( poSpatialRef != NULL )
-        nSRID = FetchSRSId( poSpatialRef );
-
-    CPLString osGeomType;
-    if( eGType != wkbNone )
+    
+    CPLString osName(pszName);
+    if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
     {
-        osGeomType = OGRToOGCGeomType(eGType);
-        if( eGType & wkb25DBit )
-            osGeomType += "Z";
+        char* pszTmp = OGRPGCommonLaunderName(pszName);
+        osName = pszTmp;
+        CPLFree(pszTmp);
     }
 
-    CPLString osSQL;
-    osSQL.Printf("CREATE TABLE %s ( %s SERIAL, ",
-                 OGRCARTODBEscapeIdentifier(pszName).c_str(),
-                 "cartodb_id");
-    if( osGeomType.size() > 0 )
-    {
-        osSQL += CPLSPrintf("%s GEOMETRY(%s, %d), %s GEOMETRY(%s, %d),",
-                 "the_geom",
-                 osGeomType.c_str(),
-                 nSRID,
-                 "the_geom_webmercator",
-                 osGeomType.c_str(),
-                 3857);
-    }
-    osSQL += CPLSPrintf("PRIMARY KEY (%s) )", "cartodb_id");
-
-    osSQL += ";";
-    osSQL += CPLSPrintf("DROP SEQUENCE IF EXISTS %s",
-                        OGRCARTODBEscapeIdentifier(CPLSPrintf("%s_%s_seq", pszName, "cartodb_id")).c_str());
-    osSQL += ";";
-    osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1",
-                        OGRCARTODBEscapeIdentifier(CPLSPrintf("%s_%s_seq", pszName, "cartodb_id")).c_str());
-    osSQL += ";";
-    osSQL += CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')",
-                        pszName,
-                        "cartodb_id",
-                        OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", pszName, "cartodb_id")).c_str());
-
-    json_object* poObj = RunSQL(osSQL);
-    if( poObj == NULL )
-        return NULL;
-    json_object_put(poObj);
-
-    OGRCARTODBTableLayer* poLayer = new OGRCARTODBTableLayer(this, pszName);
-    papoLayers = (OGRLayer**) CPLRealloc(
-                    papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+    OGRCARTODBTableLayer* poLayer = new OGRCARTODBTableLayer(this, osName);
+    int bGeomNullable = CSLFetchBoolean(papszOptions, "GEOMETRY_NULLABLE", TRUE);
+    int bCartoDBify = CSLFetchBoolean(papszOptions, "CARTODBFY",
+                                      CSLFetchBoolean(papszOptions, "CARTODBIFY", TRUE));
+    poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
+    poLayer->SetDeferedCreation(eGType, poSpatialRef, bGeomNullable, bCartoDBify);
+    papoLayers = (OGRCARTODBTableLayer**) CPLRealloc(
+                    papoLayers, (nLayers + 1) * sizeof(OGRCARTODBTableLayer*));
     papoLayers[nLayers ++] = poLayer;
 
     return poLayer;
@@ -400,6 +453,8 @@ OGRErr OGRCARTODBDataSource::DeleteLayer(int iLayer)
 
     CPLDebug( "CARTODB", "DeleteLayer(%s)", osLayerName.c_str() );
 
+    int bDeferedCreation = papoLayers[iLayer]->GetDeferedCreation();
+    papoLayers[iLayer]->CancelDeferedCreation();
     delete papoLayers[iLayer];
     memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
              sizeof(void *) * (nLayers - iLayer - 1) );
@@ -408,14 +463,17 @@ OGRErr OGRCARTODBDataSource::DeleteLayer(int iLayer)
     if (osLayerName.size() == 0)
         return OGRERR_NONE;
 
-    CPLString osSQL;
-    osSQL.Printf("DROP TABLE %s",
-                 OGRCARTODBEscapeIdentifier(osLayerName).c_str());
+    if( !bDeferedCreation )
+    {
+        CPLString osSQL;
+        osSQL.Printf("DROP TABLE %s",
+                    OGRCARTODBEscapeIdentifier(osLayerName).c_str());
 
-    json_object* poObj = RunSQL(osSQL);
-    if( poObj == NULL )
-        return OGRERR_FAILURE;
-    json_object_put(poObj);
+        json_object* poObj = RunSQL(osSQL);
+        if( poObj == NULL )
+            return OGRERR_FAILURE;
+        json_object_put(poObj);
+    }
 
     return OGRERR_NONE;
 }
@@ -424,11 +482,11 @@ OGRErr OGRCARTODBDataSource::DeleteLayer(int iLayer)
 /*                          AddHTTPOptions()                            */
 /************************************************************************/
 
-char** OGRCARTODBDataSource::AddHTTPOptions(char** papszOptions)
+char** OGRCARTODBDataSource::AddHTTPOptions()
 {
     bMustCleanPersistant = TRUE;
 
-    return CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CARTODB:%p", this));
+    return CSLAddString(NULL, CPLSPrintf("PERSISTENT=CARTODB:%p", this));
 }
 
 /************************************************************************/
@@ -460,7 +518,9 @@ json_object* OGRCARTODBDataSource::RunSQL(const char* pszUnescapedSQL)
 /* -------------------------------------------------------------------- */
 /*      Collection the header options and execute request.              */
 /* -------------------------------------------------------------------- */
-    char** papszOptions = CSLAddString(AddHTTPOptions(), osSQL);
+    const char* pszAPIURL = GetAPIURL();
+    char** papszOptions = CSLAddString(
+        strncmp(pszAPIURL, "/vsimem/", strlen("/vsimem/")) != 0 ? AddHTTPOptions(): NULL, osSQL);
     CPLHTTPResult * psResult = CPLHTTPFetch( GetAPIURL(), papszOptions);
     CSLDestroy(papszOptions);
 
@@ -557,14 +617,12 @@ json_object* OGRCARTODBGetSingleRow(json_object* poObj)
         json_object_get_type(poRows) != json_type_array ||
         json_object_array_length(poRows) != 1 )
     {
-        json_object_put(poObj);
         return NULL;
     }
 
     json_object* poRowObj = json_object_array_get_idx(poRows, 0);
     if( poRowObj == NULL || json_object_get_type(poRowObj) != json_type_object )
     {
-        json_object_put(poObj);
         return NULL;
     }
 
@@ -580,6 +638,25 @@ OGRLayer * OGRCARTODBDataSource::ExecuteSQL( const char *pszSQLCommand,
                                         const char *pszDialect )
 
 {
+    return ExecuteSQLInternal(pszSQLCommand, poSpatialFilter, pszDialect,
+                              TRUE);
+}
+
+OGRLayer * OGRCARTODBDataSource::ExecuteSQLInternal( const char *pszSQLCommand,
+                                                     OGRGeometry *poSpatialFilter,
+                                                     const char *pszDialect,
+                                                     int bRunDeferedActions )
+
+{
+    if( bRunDeferedActions )
+    {
+        for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+        {
+            papoLayers[iLayer]->RunDeferedCreationIfNecessary();
+            papoLayers[iLayer]->FlushDeferedInsert();
+        }
+    }
+
     /* Skip leading spaces */
     while(*pszSQLCommand == ' ')
         pszSQLCommand ++;
@@ -613,15 +690,21 @@ OGRLayer * OGRCARTODBDataSource::ExecuteSQL( const char *pszSQLCommand,
         }
         return NULL;
     }
+    
+    if( !EQUALN(pszSQLCommand, "SELECT", strlen("SELECT")) &&
+        !EQUALN(pszSQLCommand, "EXPLAIN", strlen("EXPLAIN")) &&
+        !EQUALN(pszSQLCommand, "WITH", strlen("WITH")) )
+    {
+        RunSQL(pszSQLCommand);
+        return NULL;
+    }
 
     OGRCARTODBResultLayer* poLayer = new OGRCARTODBResultLayer( this, pszSQLCommand );
 
     if( poSpatialFilter != NULL )
         poLayer->SetSpatialFilter( poSpatialFilter );
 
-    CPLErrorReset();
-    poLayer->GetLayerDefn();
-    if( CPLGetLastErrorNo() != 0 )
+    if( !poLayer->IsOK() )
     {
         delete poLayer;
         return NULL;
diff --git a/ogr/ogrsf_frmts/cartodb/ogrcartodbdriver.cpp b/ogr/ogrsf_frmts/cartodb/ogrcartodbdriver.cpp
index 8ec2e0e..b15d8ea 100644
--- a/ogr/ogrsf_frmts/cartodb/ogrcartodbdriver.cpp
+++ b/ogr/ogrsf_frmts/cartodb/ogrcartodbdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcartodbdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrcartodbdriver.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  CartoDB Translator
  * Purpose:  Implements OGRCARTODBDriver.
@@ -31,42 +31,61 @@
 
 // g++ -g -Wall -fPIC -shared -o ogr_CARTODB.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/cartodb ogr/ogrsf_frmts/cartodb/*.c* -L. -lgdal -Iogr/ogrsf_frmts/geojson/libjson 
 
-CPL_CVSID("$Id: ogrcartodbdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrcartodbdriver.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
 extern "C" void RegisterOGRCartoDB();
 
 /************************************************************************/
-/*                        ~OGRCARTODBDriver()                           */
+/*                        OGRCartoDBDriverIdentify()                    */
 /************************************************************************/
 
-OGRCARTODBDriver::~OGRCARTODBDriver()
-
+static int OGRCartoDBDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
+    return EQUALN(poOpenInfo->pszFilename, "CARTODB:", strlen("CARTODB:"));
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                           OGRCartoDBDriverOpen()                     */
 /************************************************************************/
 
-const char *OGRCARTODBDriver::GetName()
+static GDALDataset *OGRCartoDBDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    return "CartoDB";
+    if( !OGRCartoDBDriverIdentify(poOpenInfo) )
+        return NULL;
+
+    OGRCARTODBDataSource   *poDS = new OGRCARTODBDataSource();
+
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions,
+                     poOpenInfo->eAccess == GA_Update ) )
+    {
+        delete poDS;
+        poDS = NULL;
+    }
+
+    return poDS;
 }
 
 /************************************************************************/
-/*                                Open()                                */
+/*                      OGRCartoDBDriverCreate()                        */
 /************************************************************************/
 
-OGRDataSource *OGRCARTODBDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRCartoDBDriverCreate( const char * pszName,
+                                            CPL_UNUSED int nBands,
+                                            CPL_UNUSED int nXSize,
+                                            CPL_UNUSED int nYSize,
+                                            CPL_UNUSED GDALDataType eDT,
+                                            CPL_UNUSED char **papszOptions )
 
 {
     OGRCARTODBDataSource   *poDS = new OGRCARTODBDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( pszName, NULL, TRUE ) )
     {
         delete poDS;
-        poDS = NULL;
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "CartoDB driver doesn't support database creation." );
+        return NULL;
     }
 
     return poDS;
@@ -79,6 +98,46 @@ OGRDataSource *OGRCARTODBDriver::Open( const char * pszFilename, int bUpdate )
 void RegisterOGRCartoDB()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRCARTODBDriver );
+    if( GDALGetDriverByName( "CartoDB" ) == NULL )
+    {
+        GDALDriver* poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "CartoDB" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                  "CartoDB" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                    "drv_cartodb.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "CARTODB:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+    "<OpenOptionList>"
+    "  <Option name='API_KEY' type='string' description='Account API key'/>"
+    "  <Option name='ACCOUNT' type='string' description='Account name' required='true'/>"
+    "  <Option name='BATCH_INSERT' type='boolean' description='Whether to group features to be inserted in a batch' default='YES'/>"
+    "</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+    "<LayerCreationOptionList>"
+    "  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+    "  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+    "  <Option name='GEOMETRY_NULLABLE' type='boolean' description='Whether the values of the geometry column can be NULL' default='YES'/>"
+    "  <Option name='CARTODBFY' alias='CARTODBIFY' type='boolean' description='Whether the created layer should be \"CartoDBifi'ed\" (i.e. registered in dashboard)' default='YES'/>"
+    "</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->pfnOpen = OGRCartoDBDriverOpen;
+        poDriver->pfnIdentify = OGRCartoDBDriverIdentify;
+        poDriver->pfnCreate = OGRCartoDBDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/cartodb/ogrcartodblayer.cpp b/ogr/ogrsf_frmts/cartodb/ogrcartodblayer.cpp
index 012154e..c72f1c4 100644
--- a/ogr/ogrsf_frmts/cartodb/ogrcartodblayer.cpp
+++ b/ogr/ogrsf_frmts/cartodb/ogrcartodblayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcartodblayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrcartodblayer.cpp 29000 2015-04-24 21:46:17Z rouault $
  *
  * Project:  CartoDB Translator
  * Purpose:  Implements OGRCARTODBLayer class.
@@ -30,7 +30,7 @@
 #include "ogr_cartodb.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrcartodblayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrcartodblayer.cpp 29000 2015-04-24 21:46:17Z rouault $");
 
 /************************************************************************/
 /*                         OGRCARTODBLayer()                            */
@@ -57,6 +57,9 @@ OGRCARTODBLayer::OGRCARTODBLayer(OGRCARTODBDataSource* poDS)
 OGRCARTODBLayer::~OGRCARTODBLayer()
 
 {
+    if( poCachedObj != NULL )
+        json_object_put(poCachedObj);
+
     if( poSRS != NULL )
         poSRS->Release();
 
@@ -86,8 +89,7 @@ void OGRCARTODBLayer::ResetReading()
 
 OGRFeatureDefn * OGRCARTODBLayer::GetLayerDefn()
 {
-    CPLAssert(poFeatureDefn);
-    return poFeatureDefn;
+    return GetLayerDefnInternal(NULL);
 }
 
 /************************************************************************/
@@ -125,12 +127,11 @@ OGRFeature *OGRCARTODBLayer::BuildFeature(json_object* poRowObj)
             {
                 if( poFeatureDefn->GetFieldDefn(i)->GetType() == OFTDateTime )
                 {
-                    int nYear, nMonth, nDay, nHour, nMinute, nTZ;
-                    float fSecond;
+                    OGRField sField;
                     if( OGRParseXMLDateTime( json_object_get_string(poVal),
-                                  &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond, &nTZ) )
+                                             &sField) )
                     {
-                        poFeature->SetField(i, nYear, nMonth, nDay, nHour, nMinute, (int)fSecond, nTZ);
+                        poFeature->SetField(i, &sField);
                     }
                 }
                 else
@@ -139,9 +140,10 @@ OGRFeature *OGRCARTODBLayer::BuildFeature(json_object* poRowObj)
                 }
             }
             else if( poVal != NULL &&
-                json_object_get_type(poVal) == json_type_int )
+                (json_object_get_type(poVal) == json_type_int ||
+                 json_object_get_type(poVal) == json_type_boolean) )
             {
-                poFeature->SetField(i, (int)json_object_get_int64(poVal));
+                poFeature->SetField(i, (GIntBig)json_object_get_int64(poVal));
             }
             else if( poVal != NULL &&
                 json_object_get_type(poVal) == json_type_double )
@@ -159,7 +161,7 @@ OGRFeature *OGRCARTODBLayer::BuildFeature(json_object* poRowObj)
                 json_object_get_type(poVal) == json_type_string )
             {
                 OGRGeometry* poGeom = OGRGeometryFromHexEWKB(
-                                        json_object_get_string(poVal), NULL);
+                                        json_object_get_string(poVal), NULL, FALSE);
                 if( poGeom != NULL )
                     poGeom->assignSpatialReference(poGeomFldDefn->GetSpatialRef());
                 poFeature->SetGeomFieldDirectly(i, poGeom);
@@ -170,6 +172,24 @@ OGRFeature *OGRCARTODBLayer::BuildFeature(json_object* poRowObj)
 }
 
 /************************************************************************/
+/*                        FetchNewFeatures()                            */
+/************************************************************************/
+
+json_object* OGRCARTODBLayer::FetchNewFeatures(GIntBig iNext)
+{
+    CPLString osSQL = osBaseSQL;
+    if( osSQL.ifind("SELECT") != std::string::npos &&
+        osSQL.ifind(" LIMIT ") == std::string::npos )
+    {
+        osSQL += " LIMIT ";
+        osSQL += CPLSPrintf("%d", GetFeaturesToFetch());
+        osSQL += " OFFSET ";
+        osSQL += CPLSPrintf(CPL_FRMT_GIB, iNext);
+    }
+    return poDS->RunSQL(osSQL);
+}
+
+/************************************************************************/
 /*                        GetNextRawFeature()                           */
 /************************************************************************/
 
@@ -186,20 +206,23 @@ OGRFeature *OGRCARTODBLayer::GetNextRawFeature()
             return NULL;
         }
 
-        CPLString osSQL = osBaseSQL;
-        if( osSQL.ifind(" LIMIT ") == std::string::npos )
+        if( poFeatureDefn == NULL && osBaseSQL.size() == 0 )
         {
-            osSQL += " LIMIT ";
-            osSQL += CPLSPrintf("%d", GetFeaturesToFetch());
-            osSQL += " OFFSET ";
-            osSQL += CPLSPrintf("%d", iNext);
+            GetLayerDefn();
         }
-        json_object* poObj = poDS->RunSQL(osSQL);
+
+        json_object* poObj = FetchNewFeatures(iNext);
         if( poObj == NULL )
         {
             bEOF = TRUE;
             return NULL;
         }
+
+        if( poFeatureDefn == NULL )
+        {
+            GetLayerDefnInternal(poObj);
+        }
+
         json_object* poRows = json_object_object_get(poObj, "rows");
         if( poRows == NULL ||
             json_object_get_type(poRows) != json_type_array ||
@@ -224,7 +247,7 @@ OGRFeature *OGRCARTODBLayer::GetNextRawFeature()
     iNextInFetchedObjects ++;
 
     OGRFeature* poFeature = BuildFeature(poRowObj);
-    iNext ++;
+    iNext = poFeature->GetFID() + 1;
 
     return poFeature;
 }
@@ -237,8 +260,6 @@ OGRFeature *OGRCARTODBLayer::GetNextFeature()
 {
     OGRFeature  *poFeature;
 
-    GetLayerDefn();
-
     while(TRUE)
     {
         poFeature = GetNextRawFeature();
@@ -273,7 +294,8 @@ int OGRCARTODBLayer::TestCapability( const char * pszCap )
 /*                          EstablishLayerDefn()                        */
 /************************************************************************/
 
-void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName)
+void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName,
+                                         json_object* poObjIn)
 {
     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
     poFeatureDefn->Reference();
@@ -294,16 +316,23 @@ void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName)
     }
     else
         osSQL.Printf("%s LIMIT 0", osBaseSQL.c_str());
-    json_object* poObj = poDS->RunSQL(osSQL);
-    if( poObj == NULL )
+    json_object* poObj;
+    if( poObjIn != NULL )
+        poObj = poObjIn;
+    else
     {
-        return;
+        poObj = poDS->RunSQL(osSQL);
+        if( poObj == NULL )
+        {
+            return;
+        }
     }
 
     json_object* poFields = json_object_object_get(poObj, "fields");
     if( poFields == NULL || json_object_get_type(poFields) != json_type_object)
     {
-        json_object_put(poObj);
+        if( poObjIn == NULL )
+            json_object_put(poObj);
         return;
     }
 
@@ -321,7 +350,8 @@ void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName)
             {
                 const char* pszType = json_object_get_string(poType);
                 CPLDebug("CARTODB", "%s : %s", pszColName, pszType);
-                if( EQUAL(pszType, "string") )
+                if( EQUAL(pszType, "string") ||
+                    EQUAL(pszType, "unknown(19)") /* name */ )
                 {
                     OGRFieldDefn oFieldDefn(pszColName, OFTString);
                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
@@ -361,9 +391,17 @@ void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName)
                         }
                     }
                 }
+                else if( EQUAL(pszType, "boolean") )
+                {
+                    OGRFieldDefn oFieldDefn(pszColName, OFTInteger);
+                    oFieldDefn.SetSubType(OFSTBoolean);
+                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
+                }
                 else
                 {
-                    CPLDebug("CARTODB", "Unhandled type: %s", pszType);
+                    CPLDebug("CARTODB", "Unhandled type: %s. Defaulting to string", pszType);
+                    OGRFieldDefn oFieldDefn(pszColName, OFTString);
+                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
                 }
             }
             else if( poType != NULL && json_object_get_type(poType) == json_type_int )
@@ -382,7 +420,8 @@ void OGRCARTODBLayer::EstablishLayerDefn(const char* pszLayerName)
             }
         }
     }
-    json_object_put(poObj);
+    if( poObjIn == NULL )
+        json_object_put(poObj);
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/cartodb/ogrcartodbresultlayer.cpp b/ogr/ogrsf_frmts/cartodb/ogrcartodbresultlayer.cpp
index 0951196..8440fa0 100644
--- a/ogr/ogrsf_frmts/cartodb/ogrcartodbresultlayer.cpp
+++ b/ogr/ogrsf_frmts/cartodb/ogrcartodbresultlayer.cpp
@@ -40,6 +40,8 @@ OGRCARTODBResultLayer::OGRCARTODBResultLayer( OGRCARTODBDataSource* poDS,
                                               OGRCARTODBLayer(poDS)
 {
     osBaseSQL = pszRawQueryIn;
+    SetDescription( "result" );
+    poFirstFeature = NULL;
 }
 
 /************************************************************************/
@@ -49,23 +51,51 @@ OGRCARTODBResultLayer::OGRCARTODBResultLayer( OGRCARTODBDataSource* poDS,
 OGRCARTODBResultLayer::~OGRCARTODBResultLayer()
 
 {
+    delete poFirstFeature;
 }
 
 /************************************************************************/
-/*                           GetLayerDefn()                             */
+/*                          GetLayerDefnInternal()                      */
 /************************************************************************/
 
-OGRFeatureDefn * OGRCARTODBResultLayer::GetLayerDefn()
+OGRFeatureDefn * OGRCARTODBResultLayer::GetLayerDefnInternal(json_object* poObjIn)
 {
     if( poFeatureDefn != NULL )
         return poFeatureDefn;
 
-    EstablishLayerDefn("result");
+    EstablishLayerDefn("result", poObjIn);
 
     return poFeatureDefn;
 }
 
 /************************************************************************/
+/*                           GetNextRawFeature()                        */
+/************************************************************************/
+
+OGRFeature  *OGRCARTODBResultLayer::GetNextRawFeature()
+{
+    if( poFirstFeature )
+    {
+        OGRFeature* poRet = poFirstFeature;
+        poFirstFeature = NULL;
+        return poRet;
+    }
+    else
+        return OGRCARTODBLayer::GetNextRawFeature();
+}
+
+/************************************************************************/
+/*                                IsOK()                                */
+/************************************************************************/
+
+int  OGRCARTODBResultLayer::IsOK()
+{
+    CPLErrorReset();
+    poFirstFeature = GetNextFeature();
+    return CPLGetLastErrorType() == 0;
+}
+
+/************************************************************************/
 /*                             GetSRS_SQL()                             */
 /************************************************************************/
 
diff --git a/ogr/ogrsf_frmts/cartodb/ogrcartodbtablelayer.cpp b/ogr/ogrsf_frmts/cartodb/ogrcartodbtablelayer.cpp
index 9564323..658858b 100644
--- a/ogr/ogrsf_frmts/cartodb/ogrcartodbtablelayer.cpp
+++ b/ogr/ogrsf_frmts/cartodb/ogrcartodbtablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcartodbtablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrcartodbtablelayer.cpp 29004 2015-04-25 08:38:29Z rouault $
  *
  * Project:  CartoDB Translator
  * Purpose:  Implements OGRCARTODBTableLayer class.
@@ -29,8 +29,9 @@
 
 #include "ogr_cartodb.h"
 #include "ogr_p.h"
+#include "ogr_pgdump.h"
 
-CPL_CVSID("$Id: ogrcartodbtablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrcartodbtablelayer.cpp 29004 2015-04-25 08:38:29Z rouault $");
 
 /************************************************************************/
 /*                    OGRCARTODBEscapeIdentifier( )                     */
@@ -84,8 +85,13 @@ OGRCARTODBTableLayer::OGRCARTODBTableLayer(OGRCARTODBDataSource* poDS,
 
 {
     osName = pszName;
-    bInTransaction = FALSE;
+    SetDescription( osName );
+    bLaunderColumnNames = TRUE;
+    bInDeferedInsert = poDS->DoBatchInsert();
     nNextFID = -1;
+    bDeferedCreation = FALSE;
+    bCartoDBify = FALSE;
+    nMaxChunkSize = atoi(CPLGetConfigOption("CARTODB_MAX_CHUNK_SIZE", "15")) * 1024 * 1024;
 }
 
 /************************************************************************/
@@ -95,31 +101,237 @@ OGRCARTODBTableLayer::OGRCARTODBTableLayer(OGRCARTODBDataSource* poDS,
 OGRCARTODBTableLayer::~OGRCARTODBTableLayer()
 
 {
+    if( bDeferedCreation ) RunDeferedCreationIfNecessary();
+    FlushDeferedInsert();
 }
 
 /************************************************************************/
-/*                           GetLayerDefn()                             */
+/*                          GetLayerDefnInternal()                      */
 /************************************************************************/
 
-OGRFeatureDefn * OGRCARTODBTableLayer::GetLayerDefn()
+OGRFeatureDefn * OGRCARTODBTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object* poObjIn)
 {
     if( poFeatureDefn != NULL )
         return poFeatureDefn;
 
-    osBaseSQL.Printf("SELECT * FROM %s",
-                     OGRCARTODBEscapeIdentifier(osName).c_str());
-    EstablishLayerDefn(osName);
+    CPLString osCommand;
+    if( poDS->IsAuthenticatedConnection() )
+    {
+        // Get everything !
+        osCommand.Printf(
+                 "SELECT a.attname, t.typname, a.attlen, "
+                        "format_type(a.atttypid,a.atttypmod), "
+                        "a.attnum, "
+                        "a.attnotnull, "
+                        "i.indisprimary, "
+                        "pg_get_expr(def.adbin, c.oid) AS defaultexpr, "
+                        "postgis_typmod_dims(a.atttypmod) dim, "
+                        "postgis_typmod_srid(a.atttypmod) srid, "
+                        "postgis_typmod_type(a.atttypmod)::text geomtyp, "
+                        "srtext "
+                 "FROM pg_class c "
+                 "JOIN pg_attribute a ON a.attnum > 0 AND "
+                                        "a.attrelid = c.oid AND c.relname = '%s' "
+                 "JOIN pg_type t ON a.atttypid = t.oid "
+                 "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname= '%s' "
+                 "LEFT JOIN pg_index i ON c.oid = i.indrelid AND "
+                                         "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) "
+                 "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND "
+                                              "def.adnum = a.attnum "
+                 "LEFT JOIN spatial_ref_sys srs ON srs.srid = postgis_typmod_srid(a.atttypmod) "
+                 "ORDER BY a.attnum",
+                 OGRCARTODBEscapeLiteral(osName).c_str(),
+                 OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str());
+    }
+    else if( poDS->HasOGRMetadataFunction() != FALSE )
+    {
+        osCommand.Printf( "SELECT * FROM ogr_table_metadata('%s', '%s')",
+                          OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
+                          OGRCARTODBEscapeLiteral(osName).c_str() );
+    }
+
+    if( osCommand.size() )
+    {
+        if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+        OGRLayer* poLyr = poDS->ExecuteSQLInternal(osCommand);
+        if( !poDS->IsAuthenticatedConnection() && poDS->HasOGRMetadataFunction() < 0 )
+        {
+            CPLPopErrorHandler();
+            if( poLyr == NULL )
+            {
+                CPLDebug("CARTODB", "ogr_table_metadata(text, text) not available");
+                CPLErrorReset();
+            }
+            else if( poLyr->GetLayerDefn()->GetFieldCount() != 12 )
+            {
+                CPLDebug("CARTODB", "ogr_table_metadata(text, text) has unexpected column count");
+                poDS->ReleaseResultSet(poLyr);
+                poLyr = NULL;
+            }
+            poDS->SetOGRMetadataFunction(poLyr != NULL);
+        }
+        if( poLyr )
+        {
+            poFeatureDefn = new OGRFeatureDefn(osName);
+            poFeatureDefn->Reference();
+            poFeatureDefn->SetGeomType(wkbNone);
+
+            OGRFeature* poFeat;
+            while( (poFeat = poLyr->GetNextFeature()) != NULL )
+            {
+                const char* pszAttname = poFeat->GetFieldAsString("attname");
+                const char* pszType = poFeat->GetFieldAsString("typname");
+                int nWidth = poFeat->GetFieldAsInteger("attlen");
+                const char* pszFormatType = poFeat->GetFieldAsString("format_type");
+                int bNotNull = poFeat->GetFieldAsInteger("attnotnull");
+                int bIsPrimary = poFeat->GetFieldAsInteger("indisprimary");
+                const char* pszDefault = (poFeat->IsFieldSet(poLyr->GetLayerDefn()->GetFieldIndex("defaultexpr"))) ?
+                            poFeat->GetFieldAsString("defaultexpr") : NULL;
+
+                if( bIsPrimary &&
+                    (EQUAL(pszType, "int2") ||
+                     EQUAL(pszType, "int4") ||
+                     EQUAL(pszType, "int8") ||
+                     EQUAL(pszType, "serial") ||
+                     EQUAL(pszType, "bigserial")) )
+                {
+                    osFIDColName = pszAttname;
+                }
+                else if( strcmp(pszAttname, "created_at") == 0 ||
+                         strcmp(pszAttname, "updated_at") == 0 ||
+                         strcmp(pszAttname, "the_geom_webmercator") == 0)
+                {
+                    /* ignored */
+                }
+                else
+                {
+                    if( EQUAL(pszType,"geometry") )
+                    {
+                        int nDim = poFeat->GetFieldAsInteger("dim");
+                        int nSRID = poFeat->GetFieldAsInteger("srid");
+                        const char* pszGeomType = poFeat->GetFieldAsString("geomtyp");
+                        const char* pszSRText = (poFeat->IsFieldSet(
+                            poLyr->GetLayerDefn()->GetFieldIndex("srtext"))) ?
+                                    poFeat->GetFieldAsString("srtext") : NULL;
+                        OGRwkbGeometryType eType = OGRFromOGCGeomType(pszGeomType);
+                        if( nDim == 3 )
+                            eType = wkbSetZ(eType);
+                        OGRCartoDBGeomFieldDefn *poFieldDefn =
+                            new OGRCartoDBGeomFieldDefn(pszAttname, eType);
+                        if( bNotNull )
+                            poFieldDefn->SetNullable(FALSE);
+                        OGRSpatialReference* poSRS = NULL;
+                        if( pszSRText != NULL )
+                        {
+                            poSRS = new OGRSpatialReference();
+                            char* pszTmp = (char* )pszSRText;
+                            if( poSRS->importFromWkt(&pszTmp) != OGRERR_NONE )
+                            {
+                                delete poSRS;
+                                poSRS = NULL;
+                            }
+                            if( poSRS != NULL )
+                            {
+                                poFieldDefn->SetSpatialRef(poSRS);
+                                poSRS->Release();
+                            }
+                        }
+                        poFieldDefn->nSRID = nSRID;
+                        poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
+                    }
+                    else
+                    {
+                        OGRFieldDefn oField(pszAttname, OFTString);
+                        if( bNotNull )
+                            oField.SetNullable(FALSE);
+                        OGRPGCommonLayerSetType(oField, pszType, pszFormatType, nWidth);
+                        if( pszDefault )
+                            OGRPGCommonLayerNormalizeDefault(&oField, pszDefault);
+
+                        poFeatureDefn->AddFieldDefn( &oField );
+                    }
+                }
+                delete poFeat;
+            }
+
+            poDS->ReleaseResultSet(poLyr);
+        }
+    }
+
+    if( poFeatureDefn == NULL )
+    {
+        osBaseSQL.Printf("SELECT * FROM %s", OGRCARTODBEscapeIdentifier(osName).c_str());
+        EstablishLayerDefn(osName, NULL);
+        osBaseSQL = "";
+    }
+
     if( osFIDColName.size() > 0 )
     {
-        osBaseSQL.Printf("SELECT * FROM %s ORDER BY %s ASC",
-                         OGRCARTODBEscapeIdentifier(osName).c_str(),
-                         OGRCARTODBEscapeIdentifier(osFIDColName).c_str());
+        osBaseSQL = "SELECT ";
+        osBaseSQL += OGRCARTODBEscapeIdentifier(osFIDColName);
+    }
+    for(int i=0; i<poFeatureDefn->GetGeomFieldCount(); i++)
+    {
+        if( osBaseSQL.size() == 0 )
+            osBaseSQL = "SELECT ";
+        else
+            osBaseSQL += ", ";
+        osBaseSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
+    }
+    for(int i=0; i<poFeatureDefn->GetFieldCount(); i++)
+    {
+        if( osBaseSQL.size() == 0 )
+            osBaseSQL = "SELECT ";
+        else
+            osBaseSQL += ", ";
+        osBaseSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
     }
+    if( osBaseSQL.size() == 0 )
+        osBaseSQL = "SELECT *";
+    osBaseSQL += " FROM ";
+    osBaseSQL += OGRCARTODBEscapeIdentifier(osName);
+
+    osSELECTWithoutWHERE = osBaseSQL;
 
     return poFeatureDefn;
 }
 
 /************************************************************************/
+/*                        FetchNewFeatures()                            */
+/************************************************************************/
+
+json_object* OGRCARTODBTableLayer::FetchNewFeatures(GIntBig iNext)
+{
+    if( osFIDColName.size() > 0 )
+    {
+        CPLString osSQL;
+        osSQL.Printf("%s WHERE %s%s >= " CPL_FRMT_GIB " ORDER BY %s ASC LIMIT %d",
+                     osSELECTWithoutWHERE.c_str(),
+                     ( osWHERE.size() ) ? CPLSPrintf("%s AND ", osWHERE.c_str()) : "",
+                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
+                     iNext,
+                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
+                     GetFeaturesToFetch());
+        return poDS->RunSQL(osSQL);
+    }
+    else
+        return OGRCARTODBLayer::FetchNewFeatures(iNext);
+}
+
+/************************************************************************/
+/*                           GetNextRawFeature()                        */
+/************************************************************************/
+
+OGRFeature  *OGRCARTODBTableLayer::GetNextRawFeature()
+{
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+    FlushDeferedInsert();
+    return OGRCARTODBLayer::GetNextRawFeature();
+}
+
+/************************************************************************/
 /*                         SetAttributeFilter()                         */
 /************************************************************************/
 
@@ -132,7 +344,9 @@ OGRErr OGRCARTODBTableLayer::SetAttributeFilter( const char *pszQuery )
         osQuery = "";
     else
     {
-        osQuery = pszQuery;
+        osQuery = "(";
+        osQuery += pszQuery;
+        osQuery += ")";
     }
 
     BuildWhere();
@@ -170,63 +384,33 @@ void OGRCARTODBTableLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeo
 }
 
 /************************************************************************/
-/*                          StartTransaction()                          */
-/************************************************************************/
-
-OGRErr OGRCARTODBTableLayer::StartTransaction()
-
-{
-    bInTransaction = TRUE;
-    osTransactionSQL = "";
-    nNextFID = -1;
-    return OGRERR_NONE;
-}
-
-/************************************************************************/
-/*                         CommitTransaction()                          */
+/*                         FlushDeferedInsert()                          */
 /************************************************************************/
 
-OGRErr OGRCARTODBTableLayer::CommitTransaction()
+void OGRCARTODBTableLayer::FlushDeferedInsert()
 
 {
-    OGRErr eRet = OGRERR_NONE;
-
-    if( bInTransaction && osTransactionSQL.size() > 0 )
+    if( bInDeferedInsert && osDeferedInsertSQL.size() > 0 )
     {
-        eRet = OGRERR_FAILURE;
-        osTransactionSQL = "BEGIN;" + osTransactionSQL + "COMMIT;";
-        json_object* poObj = poDS->RunSQL(osTransactionSQL);
+        osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
+        json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
         if( poObj != NULL )
         {
-            eRet = OGRERR_NONE;
             json_object_put(poObj);
         }
     }
 
-    bInTransaction = FALSE;
-    osTransactionSQL = "";
-    nNextFID = -1;
-    return eRet;
-}
-
-/************************************************************************/
-/*                        RollbackTransaction()                         */
-/************************************************************************/
-
-OGRErr OGRCARTODBTableLayer::RollbackTransaction()
-
-{
-    bInTransaction = FALSE;
-    osTransactionSQL = "";
+    bInDeferedInsert = FALSE;
+    osDeferedInsertSQL = "";
     nNextFID = -1;
-    return OGRERR_NONE;
 }
 
 /************************************************************************/
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRCARTODBTableLayer::CreateField( OGRFieldDefn *poFieldIn, CPL_UNUSED int bApproxOK )
+OGRErr OGRCARTODBTableLayer::CreateField( OGRFieldDefn *poFieldIn,
+                                          CPL_UNUSED int bApproxOK )
 {
     GetLayerDefn();
 
@@ -237,58 +421,63 @@ OGRErr OGRCARTODBTableLayer::CreateField( OGRFieldDefn *poFieldIn, CPL_UNUSED in
         return OGRERR_FAILURE;
     }
 
+    OGRFieldDefn oField(poFieldIn);
+    if( bLaunderColumnNames )
+    {
+        char* pszName = OGRPGCommonLaunderName(oField.GetNameRef());
+        oField.SetName(pszName);
+        CPLFree(pszName);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Create the new field.                                           */
 /* -------------------------------------------------------------------- */
 
-    const char* pszFieldType = "VARCHAR";
-    switch( poFieldIn->GetType() )
-    {
-        case OFTInteger:
-            pszFieldType = "INTEGER";
-            break;
-        case OFTReal:
-            pszFieldType = "FLOAT8";
-            break;
-        case OFTDate:
-            pszFieldType = "date";
-            break;
-        case OFTTime:
-            pszFieldType = "time";
-            break;
-        case OFTDateTime:
-            pszFieldType = "timestamp with time zone";
-            break;
-        default:
-            break;
-    }
-
-    CPLString osSQL;
-    osSQL.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
-                  OGRCARTODBEscapeIdentifier(osName).c_str(),
-                  OGRCARTODBEscapeIdentifier(poFieldIn->GetNameRef()).c_str(),
-                  pszFieldType );
+    if( !bDeferedCreation )
+    {
+        CPLString osSQL;
+        osSQL.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
+                    OGRCARTODBEscapeIdentifier(osName).c_str(),
+                    OGRCARTODBEscapeIdentifier(oField.GetNameRef()).c_str(),
+                    OGRPGCommonLayerGetType(oField, FALSE, TRUE).c_str() );
+        if( !oField.IsNullable() )
+            osSQL += " NOT NULL";
+        if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+        {
+            osSQL += " DEFAULT ";
+            osSQL += OGRPGCommonLayerGetPGDefault(&oField);
+        }
 
-    json_object* poObj = poDS->RunSQL(osSQL);
-    if( poObj == NULL )
-        return OGRERR_FAILURE;
-    json_object_put(poObj);
+        json_object* poObj = poDS->RunSQL(osSQL);
+        if( poObj == NULL )
+            return OGRERR_FAILURE;
+        json_object_put(poObj);
+    }
 
-    poFeatureDefn->AddFieldDefn( poFieldIn );
+    poFeatureDefn->AddFieldDefn( &oField );
 
     return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRCARTODBTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     int i;
-    
+
+    if( bDeferedCreation )
+    {
+        if( RunDeferedCreationIfNecessary() != OGRERR_NONE )
+            return OGRERR_FAILURE;
+    }
+
     GetLayerDefn();
+    int bHasUserFieldMatchingFID = FALSE;
+    if( osFIDColName.size() )
+        bHasUserFieldMatchingFID = poFeatureDefn->GetFieldIndex(osFIDColName) >= 0;
 
     if (!poDS->IsReadWrite())
     {
@@ -300,7 +489,7 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
     CPLString osSQL;
 
     int bHasJustGotNextFID = FALSE;
-    if( bInTransaction && nNextFID < 0 && osFIDColName.size() )
+    if( !bHasUserFieldMatchingFID && bInDeferedInsert && nNextFID < 0 && osFIDColName.size() )
     {
         osSQL.Printf("SELECT nextval('%s') AS nextid",
                      OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())).c_str());
@@ -355,7 +544,8 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
         osSQL += OGRCARTODBEscapeIdentifier(poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef());
     }
     
-    if( osFIDColName.size() && (poFeature->GetFID() != OGRNullFID || nNextFID >= 0) )
+    if( !bHasUserFieldMatchingFID &&
+        osFIDColName.size() && (poFeature->GetFID() != OGRNullFID || nNextFID >= 0) )
     {
         if( bMustComma )
             osSQL += ", ";
@@ -385,14 +575,20 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
             else
                 bMustComma = TRUE;
             
-            if( poFeatureDefn->GetFieldDefn(i)->GetType() == OFTString )
+            OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
+            if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
             {
                 osSQL += "'";
                 osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
                 osSQL += "'";
             }
+            else if( (eType == OFTInteger || eType == OFTInteger64) &&
+                     poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
+            {
+                osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
+            }
             else
-                osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
+                osSQL += poFeature->GetFieldAsString(i);
         }
         
         for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
@@ -411,50 +607,94 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
             int nSRID = poGeomFieldDefn->nSRID;
             if( nSRID == 0 )
                 nSRID = 4326;
-            char* pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID);
+            char* pszEWKB;
+            if( wkbFlatten(poGeom->getGeometryType()) == wkbPolygon &&
+                wkbFlatten(GetGeomType()) == wkbMultiPolygon )
+            {
+                OGRMultiPolygon* poNewGeom = new OGRMultiPolygon();
+                poNewGeom->addGeometry(poGeom);
+                pszEWKB = OGRGeometryToHexEWKB(poNewGeom, nSRID, FALSE);
+                delete poNewGeom;
+            }
+            else
+                pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, FALSE);
             osSQL += "'";
             osSQL += pszEWKB;
             osSQL += "'";
             CPLFree(pszEWKB);
         }
 
-        if( osFIDColName.size() && nNextFID >= 0 )
+        if( !bHasUserFieldMatchingFID )
         {
-            if( bMustComma )
-                osSQL += ", ";
-            else
-                bMustComma = TRUE;
+            if( osFIDColName.size() && nNextFID >= 0 )
+            {
+                if( bMustComma )
+                    osSQL += ", ";
+                else
+                    bMustComma = TRUE;
 
-            if( bHasJustGotNextFID )
+                if( bHasJustGotNextFID )
+                {
+                    osSQL += CPLSPrintf(CPL_FRMT_GIB, nNextFID);
+                }
+                else
+                {
+                    osSQL += CPLSPrintf("nextval('%s')",
+                            OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())).c_str());
+                }
+                poFeature->SetFID(nNextFID);
+                nNextFID ++;
+            }
+            else if( osFIDColName.size() && poFeature->GetFID() != OGRNullFID )
             {
-                osSQL += CPLSPrintf("%ld", nNextFID);
+                if( bMustComma )
+                    osSQL += ", ";
+                else
+                    bMustComma = TRUE;
+
+                osSQL += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
             }
+        }
+
+        osSQL += ")";
+    }
+
+    if( bInDeferedInsert )
+    {
+        OGRErr eRet = OGRERR_NONE;
+        if( osDeferedInsertSQL.size() != 0 &&
+            (int)osDeferedInsertSQL.size() + (int)osSQL.size() > nMaxChunkSize )
+        {
+            osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
+            json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
+            if( poObj != NULL )
+                json_object_put(poObj);
             else
             {
-                osSQL += CPLSPrintf("nextval('%s')",
-                        OGRCARTODBEscapeLiteral(CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str())).c_str());
+                bInDeferedInsert = FALSE;
+                eRet = OGRERR_FAILURE;
             }
-            poFeature->SetFID(nNextFID);
-            nNextFID ++;
+            osDeferedInsertSQL = "";
         }
-        else if( osFIDColName.size() && poFeature->GetFID() != OGRNullFID )
+
+        osDeferedInsertSQL += osSQL;
+        osDeferedInsertSQL += ";";
+
+        if( (int)osDeferedInsertSQL.size() > nMaxChunkSize )
         {
-            if( bMustComma )
-                osSQL += ", ";
+            osDeferedInsertSQL = "BEGIN;" + osDeferedInsertSQL + "COMMIT;";
+            json_object* poObj = poDS->RunSQL(osDeferedInsertSQL);
+            if( poObj != NULL )
+                json_object_put(poObj);
             else
-                bMustComma = TRUE;
-
-            osSQL += CPLSPrintf("%ld", poFeature->GetFID());
+            {
+                bInDeferedInsert = FALSE;
+                eRet = OGRERR_FAILURE;
+            }
+            osDeferedInsertSQL = "";
         }
 
-        osSQL += ")";
-    }
-
-    if( bInTransaction )
-    {
-        osTransactionSQL += osSQL;
-        osTransactionSQL += ";";
-        return OGRERR_NONE;
+        return eRet;
     }
     
     if( osFIDColName.size() )
@@ -471,7 +711,7 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
             return OGRERR_FAILURE;
         }
 
-        json_object* poID = json_object_object_get(poRowObj, "cartodb_id");
+        json_object* poID = json_object_object_get(poRowObj, osFIDColName);
         if( poID != NULL && json_object_get_type(poID) == json_type_int )
         {
             poFeature->SetFID(json_object_get_int64(poID));
@@ -505,13 +745,18 @@ OGRErr OGRCARTODBTableLayer::CreateFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                            SetFeature()                              */
+/*                            ISetFeature()                              */
 /************************************************************************/
 
-OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRCARTODBTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     int i;
+
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    FlushDeferedInsert();
+
     GetLayerDefn();
 
     if (!poDS->IsReadWrite())
@@ -545,14 +790,23 @@ OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
         {
             osSQL += "NULL";
         }
-        else if( poFeatureDefn->GetFieldDefn(i)->GetType() == OFTString )
+        else
         {
-            osSQL += "'";
-            osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
-            osSQL += "'";
+            OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
+            if( eType == OFTString || eType == OFTDateTime || eType == OFTDate || eType == OFTTime )
+            {
+                osSQL += "'";
+                osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
+                osSQL += "'";
+            }
+            else if( (eType == OFTInteger || eType == OFTInteger64) &&
+                poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean )
+            {
+                osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
+            }
+            else
+                osSQL += poFeature->GetFieldAsString(i);
         }
-        else
-            osSQL += OGRCARTODBEscapeLiteral(poFeature->GetFieldAsString(i));
     }
 
     for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++)
@@ -577,7 +831,7 @@ OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
             int nSRID = poGeomFieldDefn->nSRID;
             if( nSRID == 0 )
                 nSRID = 4326;
-            char* pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID);
+            char* pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, FALSE);
             osSQL += "'";
             osSQL += pszEWKB;
             osSQL += "'";
@@ -585,16 +839,9 @@ OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
         }
     }
 
-    osSQL += CPLSPrintf(" WHERE %s = %ld",
+    osSQL += CPLSPrintf(" WHERE %s = " CPL_FRMT_GIB,
                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
                     poFeature->GetFID());
-    
-    if( bInTransaction )
-    {
-        osTransactionSQL += osSQL;
-        osTransactionSQL += ";";
-        return OGRERR_NONE;
-    }
 
     OGRErr eRet = OGRERR_FAILURE;
     json_object* poObj = poDS->RunSQL(osSQL);
@@ -604,10 +851,12 @@ OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
         if( poTotalRows != NULL && json_object_get_type(poTotalRows) == json_type_int )
         {
             int nTotalRows = json_object_get_int(poTotalRows);
-            if( nTotalRows == 1 )
+            if( nTotalRows > 0 )
             {
                 eRet = OGRERR_NONE;
             }
+            else
+                eRet = OGRERR_NON_EXISTING_FEATURE;
         }
         json_object_put(poObj);
     }
@@ -619,9 +868,14 @@ OGRErr OGRCARTODBTableLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRCARTODBTableLayer::DeleteFeature( long nFID )
+OGRErr OGRCARTODBTableLayer::DeleteFeature( GIntBig nFID )
 
 {
+
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    FlushDeferedInsert();
+
     GetLayerDefn();
 
     if (!poDS->IsReadWrite())
@@ -635,18 +889,11 @@ OGRErr OGRCARTODBTableLayer::DeleteFeature( long nFID )
         return OGRERR_FAILURE;
     
     CPLString osSQL;
-    osSQL.Printf("DELETE FROM %s WHERE %s = %ld",
+    osSQL.Printf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
                     OGRCARTODBEscapeIdentifier(osName).c_str(),
                     OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
                     nFID);
-    
-    if( bInTransaction )
-    {
-        osTransactionSQL += osSQL;
-        osTransactionSQL += ";";
-        return OGRERR_NONE;
-    }
-    
+
     OGRErr eRet = OGRERR_FAILURE;
     json_object* poObj = poDS->RunSQL(osSQL);
     if( poObj != NULL )
@@ -655,10 +902,12 @@ OGRErr OGRCARTODBTableLayer::DeleteFeature( long nFID )
         if( poTotalRows != NULL && json_object_get_type(poTotalRows) == json_type_int )
         {
             int nTotalRows = json_object_get_int(poTotalRows);
-            if( nTotalRows == 1 )
+            if( nTotalRows > 0 )
             {
                 eRet = OGRERR_NONE;
             }
+            else
+                eRet = OGRERR_NON_EXISTING_FEATURE;
         }
         json_object_put(poObj);
     }
@@ -674,25 +923,11 @@ CPLString OGRCARTODBTableLayer::GetSRS_SQL(const char* pszGeomCol)
 {
     CPLString osSQL;
 
-    if( poDS->IsAuthenticatedConnection() )
-    {
-        /* Find_SRID needs access to geometry_columns table, whhose access */
-        /* is restricted to authenticated connections. */
-        osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
-                    "(SELECT Find_SRID('public', '%s', '%s'))",
-                    OGRCARTODBEscapeLiteral(osName).c_str(),
-                    OGRCARTODBEscapeLiteral(pszGeomCol).c_str());
-    }
-    else
-    {
-        /* Assuming that the SRID of the first non-NULL geometry applies */
-        /* to geometries of all rows. */
-        osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
-                    "(SELECT ST_SRID(%s) FROM %s WHERE %s IS NOT NULL LIMIT 1)",
-                    OGRCARTODBEscapeIdentifier(pszGeomCol).c_str(),
-                    OGRCARTODBEscapeIdentifier(osName).c_str(),
-                    OGRCARTODBEscapeIdentifier(pszGeomCol).c_str());
-    }
+    osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN "
+                "(SELECT Find_SRID('%s', '%s', '%s'))",
+                OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
+                OGRCARTODBEscapeLiteral(osName).c_str(),
+                OGRCARTODBEscapeLiteral(pszGeomCol).c_str());
 
     return osSQL;
 }
@@ -723,32 +958,32 @@ void OGRCARTODBTableLayer::BuildWhere()
         char szBox3D_2[128];
         char* pszComma;
 
-        snprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
+        CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
         while((pszComma = strchr(szBox3D_1, ',')) != NULL)
             *pszComma = '.';
-        snprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
+        CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
         while((pszComma = strchr(szBox3D_2, ',')) != NULL)
             *pszComma = '.';
-        osWHERE.Printf("WHERE %s && 'BOX3D(%s, %s)'::box3d",
+        osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)",
                        OGRCARTODBEscapeIdentifier(osGeomColumn).c_str(),
                        szBox3D_1, szBox3D_2 );
     }
 
     if( strlen(osQuery) > 0 )
     {
-        if( strlen(osWHERE) == 0 )
-            osWHERE = "WHERE ";
-        else
+        if( osWHERE.size() > 0 )
             osWHERE += " AND ";
         osWHERE += osQuery;
     }
 
-    osBaseSQL.Printf("SELECT * FROM %s",
-                     OGRCARTODBEscapeIdentifier(osName).c_str());
-    if( osWHERE.size() )
+    if( osFIDColName.size() == 0 )
     {
-        osBaseSQL += " ";
-        osBaseSQL += osWHERE;
+        osBaseSQL = osSELECTWithoutWHERE;
+        if( osWHERE.size() )
+        {
+            osBaseSQL += " WHERE ";
+            osBaseSQL += osWHERE;
+        }
     }
 }
 
@@ -756,17 +991,23 @@ void OGRCARTODBTableLayer::BuildWhere()
 /*                              GetFeature()                            */
 /************************************************************************/
 
-OGRFeature* OGRCARTODBTableLayer::GetFeature( long nFeatureId )
+OGRFeature* OGRCARTODBTableLayer::GetFeature( GIntBig nFeatureId )
 {
+
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+    FlushDeferedInsert();
+
     GetLayerDefn();
     
     if( osFIDColName.size() == 0 )
         return OGRCARTODBLayer::GetFeature(nFeatureId);
 
-    CPLString osSQL(CPLSPrintf("SELECT * FROM %s WHERE %s = %ld",
-                               OGRCARTODBEscapeIdentifier(osName).c_str(),
-                               OGRCARTODBEscapeIdentifier(osFIDColName).c_str(),
-                               nFeatureId));
+    CPLString osSQL = osSELECTWithoutWHERE;
+    osSQL += " WHERE ";
+    osSQL += OGRCARTODBEscapeIdentifier(osFIDColName).c_str();
+    osSQL += " = ";
+    osSQL += CPLSPrintf(CPL_FRMT_GIB, nFeatureId);
 
     json_object* poObj = poDS->RunSQL(osSQL);
     json_object* poRowObj = OGRCARTODBGetSingleRow(poObj);
@@ -787,15 +1028,20 @@ OGRFeature* OGRCARTODBTableLayer::GetFeature( long nFeatureId )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRCARTODBTableLayer::GetFeatureCount(int bForce)
+GIntBig OGRCARTODBTableLayer::GetFeatureCount(int bForce)
 {
+
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return 0;
+    FlushDeferedInsert();
+
     GetLayerDefn();
 
     CPLString osSQL(CPLSPrintf("SELECT COUNT(*) FROM %s",
                                OGRCARTODBEscapeIdentifier(osName).c_str()));
     if( osWHERE.size() )
     {
-        osSQL += " ";
+        osSQL += " WHERE ";
         osSQL += osWHERE;
     }
 
@@ -815,7 +1061,7 @@ int OGRCARTODBTableLayer::GetFeatureCount(int bForce)
         return OGRCARTODBLayer::GetFeatureCount(bForce);
     }
 
-    int nRet = (int)json_object_get_int64(poCount);
+    GIntBig nRet = (GIntBig)json_object_get_int64(poCount);
 
     json_object_put(poObj);
 
@@ -833,6 +1079,10 @@ OGRErr OGRCARTODBTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, i
 {
     CPLString   osSQL;
 
+    if( bDeferedCreation && RunDeferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    FlushDeferedInsert();
+
     if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
     {
@@ -945,8 +1195,149 @@ int OGRCARTODBTableLayer::TestCapability( const char * pszCap )
         return poDS->IsReadWrite();
     }
 
-    if( EQUAL(pszCap,OLCTransactions) )
-        return TRUE;
-
     return OGRCARTODBLayer::TestCapability(pszCap);
 }
+
+/************************************************************************/
+/*                        SetDeferedCreation()                          */
+/************************************************************************/
+
+void OGRCARTODBTableLayer::SetDeferedCreation (OGRwkbGeometryType eGType,
+                                               OGRSpatialReference* poSRS,
+                                               int bGeomNullable,
+                                               int bCartoDBify)
+{
+    bDeferedCreation = TRUE;
+    nNextFID = 1;
+    CPLAssert(poFeatureDefn == NULL);
+    this->bCartoDBify = bCartoDBify;
+    poFeatureDefn = new OGRFeatureDefn(osName);
+    poFeatureDefn->Reference();
+    poFeatureDefn->SetGeomType(wkbNone);
+    if( eGType == wkbPolygon )
+        eGType = wkbMultiPolygon;
+    else if( eGType == wkbPolygon25D )
+        eGType = wkbMultiPolygon25D;
+    if( eGType != wkbNone )
+    {
+        OGRCartoDBGeomFieldDefn *poFieldDefn =
+            new OGRCartoDBGeomFieldDefn("the_geom", eGType);
+        poFieldDefn->SetNullable(bGeomNullable);
+        poFeatureDefn->AddGeomFieldDefn(poFieldDefn, FALSE);
+        if( poSRS != NULL )
+        {
+            poFieldDefn->nSRID = poDS->FetchSRSId( poSRS );
+            poFeatureDefn->GetGeomFieldDefn(
+                poFeatureDefn->GetGeomFieldCount() - 1)->SetSpatialRef(poSRS);
+        }
+    }
+    osFIDColName = "cartodb_id";
+    osBaseSQL.Printf("SELECT * FROM %s",
+                     OGRCARTODBEscapeIdentifier(osName).c_str());
+}
+
+/************************************************************************/
+/*                      RunDeferedCreationIfNecessary()                 */
+/************************************************************************/
+
+OGRErr OGRCARTODBTableLayer::RunDeferedCreationIfNecessary()
+{
+    if( !bDeferedCreation )
+        return OGRERR_NONE;
+    bDeferedCreation = FALSE;
+
+    CPLString osSQL;
+    osSQL.Printf("CREATE TABLE %s ( %s SERIAL,",
+                 OGRCARTODBEscapeIdentifier(osName).c_str(),
+                 osFIDColName.c_str());
+
+    int nSRID = 0;
+    OGRwkbGeometryType eGType = GetGeomType();
+    if( eGType != wkbNone )
+    {
+        CPLString osGeomType = OGRToOGCGeomType(eGType);
+        if( wkbHasZ(eGType) )
+            osGeomType += "Z";
+
+        OGRCartoDBGeomFieldDefn *poFieldDefn =
+            (OGRCartoDBGeomFieldDefn *)poFeatureDefn->GetGeomFieldDefn(0);
+        nSRID = poFieldDefn->nSRID;
+
+        osSQL += CPLSPrintf("%s GEOMETRY(%s, %d)%s, %s GEOMETRY(%s, %d),",
+                 "the_geom",
+                 osGeomType.c_str(),
+                 nSRID,
+                 (!poFieldDefn->IsNullable()) ? " NOT NULL" : "",
+                 "the_geom_webmercator",
+                 osGeomType.c_str(),
+                 3857);
+    }
+
+    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    {
+        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(i);
+        if( strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0 )
+        {
+            osSQL += OGRCARTODBEscapeIdentifier(poFieldDefn->GetNameRef());
+            osSQL += " ";
+            osSQL += OGRPGCommonLayerGetType(*poFieldDefn, FALSE, TRUE);
+            if( !poFieldDefn->IsNullable() )
+                osSQL += " NOT NULL";
+            if( poFieldDefn->GetDefault() != NULL && !poFieldDefn->IsDefaultDriverSpecific() )
+            {
+                osSQL += " DEFAULT ";
+                osSQL += poFieldDefn->GetDefault();
+            }
+            osSQL += ",";
+        }
+    }
+
+    osSQL += CPLSPrintf("PRIMARY KEY (%s) )", osFIDColName.c_str());
+    
+    CPLString osSeqName(OGRCARTODBEscapeIdentifier(CPLSPrintf("%s_%s_seq",
+                                osName.c_str(), osFIDColName.c_str())));
+
+    osSQL += ";";
+    osSQL += CPLSPrintf("DROP SEQUENCE IF EXISTS %s CASCADE", osSeqName.c_str());
+    osSQL += ";";
+    osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1", osSeqName.c_str());
+    osSQL += ";";
+    osSQL += CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')",
+                        OGRCARTODBEscapeIdentifier(osName).c_str(),
+                        osFIDColName.c_str(), osSeqName.c_str());
+
+    json_object* poObj = poDS->RunSQL(osSQL);
+    if( poObj == NULL )
+        return OGRERR_FAILURE;
+    json_object_put(poObj);
+
+    if( bCartoDBify )
+    {
+        if( nSRID != 4326 )
+        {
+            if( eGType != wkbNone )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                        "Cannot register table in dashboard with "
+                        "cdb_cartodbfytable() since its SRS is not EPSG:4326");
+            }
+        }
+        else
+        {
+            if( poDS->GetCurrentSchema() == "public" )
+                osSQL.Printf("SELECT cdb_cartodbfytable('%s')",
+                                    OGRCARTODBEscapeLiteral(osName).c_str());
+            else
+                osSQL.Printf("SELECT cdb_cartodbfytable('%s', '%s')",
+                                    OGRCARTODBEscapeLiteral(poDS->GetCurrentSchema()).c_str(),
+                                    OGRCARTODBEscapeLiteral(osName).c_str());
+
+            poObj = poDS->RunSQL(osSQL);
+            if( poObj == NULL )
+                return OGRERR_FAILURE;
+            json_object_put(poObj);
+        }
+    }
+
+    return OGRERR_NONE;
+}
diff --git a/ogr/ogrsf_frmts/cloudant/GNUmakefile b/ogr/ogrsf_frmts/cloudant/GNUmakefile
new file mode 100644
index 0000000..bb0ea7c
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/GNUmakefile
@@ -0,0 +1,14 @@
+
+
+include ../../../GDALmake.opt
+
+OBJ	=	ogrcloudantdriver.o ogrcloudantdatasource.o ogrcloudanttablelayer.o
+
+CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. -I../geojson -I../couchdb $(GDAL_INCLUDE) $(CPPFLAGS)
+
+default:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(O_OBJ):	ogr_cloudant.h ../../swq.h ../geojson/ogrgeojsonreader.h ../geojson/ogrgeojsonwriter.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/cloudant/drv_cloudant.html b/ogr/ogrsf_frmts/cloudant/drv_cloudant.html
new file mode 100644
index 0000000..172fa55
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/drv_cloudant.html
@@ -0,0 +1,113 @@
+<html>
+<head>
+<title>CouchDB - Cloudant</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>CouchDB - Cloudant</h1>
+
+(GDAL/OGR >= 2.0.0)<p>
+
+Cloudant and CouchDB are API compatible and based on the same core technology. The geospatial extension for Cloudant
+is separate to GeoCouch. 
+
+This driver can connect to the a Cloudant service, potentially enabled with the Cloudant spatial extension.<p>
+GDAL/OGR must be built with Curl support in order to the Cloudant driver to be compiled.<p>
+The driver supports read and write operations.<p>
+
+<h2>Cloudant vs OGR concepts</h2>
+
+A Cloudant database is considered as a OGR layer. A Cloudant document is considered as a OGR feature.<p>
+
+OGR preferably handles Cloudant documents following the GeoJSON specification.<p>
+
+<h2>Dataset name syntax</h2>
+
+The syntax to open a Cloudant datasource is : <pre>cloudant:http://example.com[/layername]</pre> where
+http://example.com points to the root of a CouchDB repository and, optionaly, layername is the name of a CouchDB database.<p>
+
+It is also possible to directly open a view : <pre>cloudant:http://example.com/layername/_design/adesigndoc/_view/aview[?include_docs=true]</pre>
+The include_docs=true might be needed depending on the value returned by the emit() call in the map() function.<p>
+
+<h2>Authentication</h2>
+
+Some operations, in particular write operations, require authentication. The authentication can
+be passed with the <i>CLOUDANT_USERPWD</i> environment variable set to user:password or directly in the URL.<p>
+
+<h2>Filtering</h2>
+
+The driver will forward any spatial filter set with SetSpatialFilter() to the server when the Cloudant extension
+is available.<p>
+
+By default, the driver will try the following spatial filter function "_design/SpatialView/_geo/spatial",
+which is the valid spatial filter function for layers created by OGR. If that filter function does not exist,
+but another one exists, you can specify it with the CLOUDANT_SPATIAL_FILTER configuration option.<p>
+<p>
+
+<h2>Paging</h2>
+
+Features are retrieved from the server by chunks of 200 by default. Cloudant uses bookmarks to page through the data.
+
+<h2>Write support</h2>
+
+Table creation and deletion is possible.<p>
+
+Write support is only enabled when the datasource is opened in update mode.<p>
+
+When inserting a new feature with CreateFeature(), and if the command is successful, OGR will fetch the
+returned _id and _rev and use them.<p>
+
+<h2>Write support and OGR transactions</h2>
+
+The CreateFeature()/SetFeature() operations are by default issued to the server synchronously with the OGR API call. This however
+can cause performance penalties when issuing a lot of commands due to many client/server exchanges.<p>
+
+It is possible to surround the CreateFeature()/SetFeature() operations between OGRLayer::StartTransaction() and OGRLayer::CommitTransaction().
+The operations will be stored into memory and only executed at the time CommitTransaction() is called.<p>
+
+<h2>Layer creation options</h2>
+
+The following layer creation options are supported:
+<ul>
+<li><b>UPDATE_PERMISSIONS</b> = LOGGED_USER|ALL|ADMIN|function(...)|DEFAULT : Update permissions for the new layer.
+<ul>
+<li>If set to LOGGED_USER (the default), only logged users will be able to make changes in the layer.</li>
+<li>If set to ALL, all users will be able to make changes in the layer.</li>
+<li>If set to ADMIN, only administrators will be able to make changes in the layer.</li>
+<li>If beginning with "function(", the value of the creation option will be used as the content of the <a href="http://guide.couchdb.org/draft/validation.html">validate_doc_update function</a>.</li>
+<li>Otherwise, all users will be allowed to make changes in non-design documents.</li>
+</ul>
+</li>
+<li><b>GEOJSON</b> = YES|NO : Set to NO to avoid writting documents as GeoJSON documents. Default to YES.</li>
+<li><b>COORDINATE_PRECISION</b> = int_number : Maximum number of figures after decimal separator to write in coordinates.
+Default to 15. "Smart" truncation will occur to remove trailing zeros.
+Note: when opening a dataset in update mode, the OGR_CLOUDANT_COORDINATE_PRECISION configuration option can be set to have a similar role.</li>
+</ul>
+
+<h2>Examples</h2>
+
+<li>
+Listing the tables of a Cloudant repository:
+<pre>
+ogrinfo -ro "cloudant:http://some_account.some_cloudant_server.com"
+</pre>
+<p>
+
+<li>
+Creating and populating a table from a shapefile:
+<pre>
+ogr2ogr -f cloudant "cloudant:http://some_account.some_cloudant_server.com" shapefile.shp
+</pre>
+<p>
+
+<h2>See Also</h2>
+
+<ul>
+<li> <a href="http://wiki.apache.org/couchdb/Reference">CouchDB reference</a><p>
+<li> <a href="https://cloudant.com/product/cloudant-features/geospatial/">Cloudant Geospatial</a><p>
+<li> <a href="http://guide.couchdb.org/draft/validation.html">Documentation for 'validate_doc_update' function</a><p>
+</ul>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/cloudant/makefile.vc b/ogr/ogrsf_frmts/cloudant/makefile.vc
new file mode 100644
index 0000000..2e089b2
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/makefile.vc
@@ -0,0 +1,15 @@
+
+OBJ	=	ogrcloudantdriver.obj ogrcloudantdatasource.obj ogrcloudanttablelayer.obj
+EXTRAFLAGS =	-I.. -I..\..  -I..\geojson -I..\geojson\libjson -I..\couchdb
+
+GDAL_ROOT	=	..\..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+default:	$(OBJ)
+
+clean:
+	-del *.obj *.pdb
+
+
+
diff --git a/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h b/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h
new file mode 100644
index 0000000..45abe24
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  Cloudant Translator
+ * Purpose:  Definition of classes for OGR Cloudant driver.
+ * Author:   Norman Barker, norman at cloudant com
+ *           Based on the CouchDB driver
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Norman Barker <norman at cloudant com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGR_CLOUDANT_H_INCLUDED
+#define _OGR_CLOUDANT_H_INCLUDED
+
+#include "ogr_couchdb.h"
+
+typedef enum
+{
+    CLOUDANT_TABLE_LAYER
+} CloudantLayerType;
+
+class OGRCloudantDataSource;
+
+/************************************************************************/
+/*                      OGRCloudantTableLayer                         */
+/************************************************************************/
+
+class OGRCloudantTableLayer : public OGRCouchDBTableLayer
+{
+    int                       bHasStandardSpatial;
+    const char*               pszSpatialView;
+    char*                     pszSpatialDDoc;
+
+    protected:
+            virtual int               GetFeaturesToFetch() { 
+               return atoi(CPLGetConfigOption("CLOUDANT_PAGE_SIZE", "200"));
+            }
+
+            virtual int               RunSpatialFilterQueryIfNecessary();
+            virtual void              GetSpatialView();
+            virtual void              WriteMetadata();
+            virtual void              LoadMetadata();
+            
+    public:
+            OGRCloudantTableLayer(OGRCloudantDataSource* poDS,
+                                 const char* pszName);
+            ~OGRCloudantTableLayer();
+};
+
+/************************************************************************/
+/*                         OGRCloudantDataSource                        */
+/************************************************************************/
+
+class OGRCloudantDataSource : public OGRCouchDBDataSource
+{
+  protected:
+            OGRLayer*    OpenDatabase(const char* pszLayerName = NULL);
+  public:
+                        OGRCloudantDataSource();
+                        ~OGRCloudantDataSource();
+    virtual int Open( const char * pszFilename, int bUpdateIn);                       
+    virtual OGRLayer   *ICreateLayer( const char *pszName,
+             OGRSpatialReference *poSpatialRef = NULL,
+             OGRwkbGeometryType eGType = wkbUnknown,
+             char ** papszOptions = NULL );
+};
+
+/************************************************************************/
+/*                           OGRCloudantDriver                          */
+/************************************************************************/
+
+class OGRCloudantDriver : public OGRCouchDBDriver
+{
+  public:
+                ~OGRCloudantDriver();
+
+    virtual const char*         GetName();
+    virtual OGRDataSource*      Open( const char *, int );
+    virtual OGRDataSource*      CreateDataSource( const char * pszName,
+                                                  char **papszOptions );
+    virtual int                 TestCapability( const char * );
+
+};
+
+#endif /* ndef _OGR_CLOUDANT_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp
new file mode 100644
index 0000000..833ebe7
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp
@@ -0,0 +1,388 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  Cloudant Translator
+ * Purpose:  Definition of classes for OGR Cloudant driver.
+ * Author:   Norman Barker, norman at cloudant com
+ *           Based on the CouchDB driver
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Norman Barker <norman at cloudant com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_cloudant.h"
+#include "ogrgeojsonreader.h"
+#include "ogrgeojsonwriter.h"
+#include "swq.h"
+
+CPL_CVSID("$Id$");
+
+/************************************************************************/
+/*                        OGRCloudantDataSource()                       */
+/************************************************************************/
+
+OGRCloudantDataSource::OGRCloudantDataSource()
+
+{
+
+}
+
+/************************************************************************/
+/*                       ~OGRCloudantDataSource()                       */
+/************************************************************************/
+
+OGRCloudantDataSource::~OGRCloudantDataSource()
+
+{
+
+}
+
+/************************************************************************/
+/*                             OpenDatabase()                           */
+/************************************************************************/
+
+OGRLayer* OGRCloudantDataSource::OpenDatabase(const char* pszLayerName)
+{
+    CPLString osTableName;
+    CPLString osEscapedName;
+
+    if (pszLayerName)
+    {
+        osTableName = pszLayerName;
+        char* pszEscapedName = CPLEscapeString(pszLayerName, -1, CPLES_URL);
+        osEscapedName = pszEscapedName;
+        CPLFree(pszEscapedName);
+    }
+    else
+    {
+        char* pszURL = CPLStrdup(osURL);
+        char* pszLastSlash = strrchr(pszURL, '/');
+        if (pszLastSlash)
+        {
+            osEscapedName = pszLastSlash + 1;
+            char* pszName = CPLUnescapeString(osEscapedName, NULL, CPLES_URL);
+            osTableName = pszName;
+            CPLFree(pszName);
+            *pszLastSlash = 0;
+        }
+        osURL = pszURL;
+        CPLFree(pszURL);
+        pszURL = NULL;
+
+        if (pszLastSlash == NULL)
+            return NULL;
+    }
+
+    CPLString osURI("/");
+    osURI += osEscapedName;
+
+    json_object* poAnswerObj = GET(osURI);
+    if (poAnswerObj == NULL)
+        return NULL;
+
+    if ( !json_object_is_type(poAnswerObj, json_type_object) ||
+            json_object_object_get(poAnswerObj, "db_name") == NULL )
+    {
+        IsError(poAnswerObj, "Database opening failed");
+
+        json_object_put(poAnswerObj);
+        return NULL;
+    }
+
+    OGRCloudantTableLayer* poLayer = new OGRCloudantTableLayer(this, osTableName);
+
+    if ( json_object_object_get(poAnswerObj, "update_seq") != NULL )
+    {
+        int nUpdateSeq = json_object_get_int(json_object_object_get(poAnswerObj, "update_seq"));
+        poLayer->SetUpdateSeq(nUpdateSeq);
+    }
+
+    json_object_put(poAnswerObj);
+
+    papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+    papoLayers[nLayers ++] = poLayer;
+
+    return poLayer;
+}
+
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+int OGRCloudantDataSource::Open( const char * pszFilename, int bUpdateIn)
+
+{
+    int bHTTP = FALSE;
+    if (strncmp(pszFilename, "http://", 7) == 0 ||
+        strncmp(pszFilename, "https://", 8) == 0)
+        bHTTP = TRUE;
+    else if (!EQUALN(pszFilename, "cloudant:", 9))
+        return FALSE;
+
+    bReadWrite = bUpdateIn;
+
+    pszName = CPLStrdup( pszFilename );
+
+    if (bHTTP)
+        osURL = pszFilename;
+    else
+        osURL = pszFilename + 9;
+    if (osURL.size() > 0 && osURL[osURL.size() - 1] == '/')
+        osURL.resize(osURL.size() - 1);
+
+    const char* pszUserPwd = CPLGetConfigOption("CLOUDANT_USERPWD", NULL);
+    const char* pszSlash = "/";
+
+    if (pszUserPwd)
+        osUserPwd = pszUserPwd;
+
+    if ((strstr(osURL, "/_design/") && strstr(osURL, "/_view/")) ||
+        strstr(osURL, "/_all_docs"))
+    {
+        return OpenView() != NULL;
+    }
+
+    /* If passed with https://useraccount.cloudant.com[:port]/database, do not */
+    /* try to issue /all_dbs, but directly open the database */
+    const char* pszKnowProvider = strstr(osURL, ".cloudant.com/");
+    if (pszKnowProvider != NULL &&
+        strchr(pszKnowProvider + strlen(".cloudant.com/"), '/' ) == NULL)
+    {
+        return OpenDatabase() != NULL;
+    }
+
+
+    pszKnowProvider = strstr(osURL, "localhost");
+    if (pszKnowProvider != NULL &&
+        strstr(pszKnowProvider + strlen("localhost"), pszSlash ) != NULL)
+    {
+        return OpenDatabase() != NULL;
+    }
+
+    /* Get list of tables */
+    json_object* poAnswerObj = GET("/_all_dbs");
+
+    if ( !json_object_is_type(poAnswerObj, json_type_array) )
+    {
+        if ( json_object_is_type(poAnswerObj, json_type_object) )
+        {
+            json_object* poError = json_object_object_get(poAnswerObj, "error");
+            json_object* poReason = json_object_object_get(poAnswerObj, "reason");
+
+            const char* pszError = json_object_get_string(poError);
+            const char* pszReason = json_object_get_string(poReason);
+
+            if (pszError && pszReason && strcmp(pszError, "not_found") == 0 &&
+                strcmp(pszReason, "missing") == 0)
+            {
+                json_object_put(poAnswerObj);
+                poAnswerObj = NULL;
+
+                CPLErrorReset();
+
+                return OpenDatabase() != NULL;
+            }
+        }
+        if (poAnswerObj == NULL)
+        {
+            IsError(poAnswerObj, "Database listing failed");
+
+            json_object_put(poAnswerObj);
+            return FALSE;
+        }
+    }
+
+    int nTables = json_object_array_length(poAnswerObj);
+    
+    for(int i=0;i<nTables;i++)
+    {
+        json_object* poAnswerObjDBName = json_object_array_get_idx(poAnswerObj, i);
+        if ( json_object_is_type(poAnswerObjDBName, json_type_string) )
+        {
+            const char* pszDBName = json_object_get_string(poAnswerObjDBName);
+            if ( strcmp(pszDBName, "_users") != 0 &&
+                 strcmp(pszDBName, "_replicator") != 0 )
+            {
+                papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+                papoLayers[nLayers ++] = new OGRCouchDBTableLayer(this, pszDBName);
+            }
+        }
+    }
+
+    json_object_put(poAnswerObj);
+
+    return TRUE;
+}
+
+
+/************************************************************************/
+/*                          ICreateLayer()                              */
+/************************************************************************/
+
+OGRLayer   *OGRCloudantDataSource::ICreateLayer( const char *pszName,
+                                           OGRSpatialReference *poSpatialRef,
+                                           OGRwkbGeometryType eGType,
+                                           char ** papszOptions )
+{
+    if (!IsReadWrite())
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Operation not available in read-only mode");
+        return NULL;
+    }
+
+    char *pszLayerName = CPLStrlwr(CPLStrdup(pszName));
+    CPLString osLayerName = pszLayerName;
+    CPLFree(pszLayerName);
+
+/* -------------------------------------------------------------------- */
+/*      Do we already have this layer?  If so, should we blow it        */
+/*      away?                                                           */
+/* -------------------------------------------------------------------- */
+    int iLayer;
+
+    for( iLayer = 0; iLayer < GetLayerCount(); iLayer++ )
+    {
+        if( EQUAL(osLayerName, papoLayers[iLayer]->GetName()) )
+        {
+            if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
+                && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
+            {
+                DeleteLayer( osLayerName );
+                break;
+            }
+            else
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                          "Layer %s already exists, CreateLayer failed.\n"
+                          "Use the layer creation option OVERWRITE=YES to "
+                          "replace it.",
+                          osLayerName.c_str());
+                return NULL;
+            }
+        }
+    }
+
+    char* pszEscapedName = CPLEscapeString(osLayerName, -1, CPLES_URL);
+    CPLString osEscapedName = pszEscapedName;
+    CPLFree(pszEscapedName);
+
+/* -------------------------------------------------------------------- */
+/*      Create "database"                                               */
+/* -------------------------------------------------------------------- */
+    CPLString osURI;
+    osURI = "/";
+    osURI += osEscapedName;
+    json_object* poAnswerObj = PUT(osURI, NULL);
+
+    if (poAnswerObj == NULL)
+        return NULL;
+
+    if (!IsOK(poAnswerObj, "Layer creation failed"))
+    {
+        json_object_put(poAnswerObj);
+        return NULL;
+    }
+
+    json_object_put(poAnswerObj);
+
+/* -------------------------------------------------------------------- */
+/*      Create "spatial index"                                          */
+/* -------------------------------------------------------------------- */
+    int nUpdateSeq = 0;
+    if (eGType != wkbNone)
+    {
+        char szSrid[100];
+        bool bSrid = FALSE;
+        const char* designDoc = "_design/SpatialView";
+        osURI = "/";
+        osURI += osEscapedName;
+        osURI += "/";
+        osURI += designDoc;
+
+        if (poSpatialRef != NULL)
+        {
+            // epsg codes are supported in Cloudant
+            const char * pszEpsg = NULL;
+            const char * pszAuthName = NULL;
+            if (poSpatialRef->IsProjected())
+            {
+                pszAuthName = poSpatialRef->GetAuthorityName("PROJCS");
+                if ((pszAuthName != NULL) && (strncmp(pszAuthName, "EPSG", 4) == 0))
+                    pszEpsg = poSpatialRef->GetAuthorityCode("PROJCS");
+            }
+            else
+            {
+                pszAuthName = poSpatialRef->GetAuthorityName("GEOGCS");
+                if ((pszAuthName != NULL) && (strncmp(pszAuthName, "EPSG", 4) == 0))
+                    pszEpsg = poSpatialRef->GetAuthorityCode("GEOGCS");
+            }
+
+            if (pszEpsg != NULL)
+            {
+                const char * pszUrn = "urn:ogc:def:crs:epsg::";
+                CPLStrlcpy(szSrid, pszUrn, sizeof(szSrid));
+                if (CPLStrlcpy(szSrid + sizeof(pszUrn), pszEpsg, sizeof(szSrid)) >= sizeof(szSrid))
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined, "Unable to parse SRID");
+                    return NULL;
+                }
+                else
+                    bSrid = TRUE;
+            }
+        }
+
+        // create a spatial design document and serialize it
+        json_object* poDoc = json_object_new_object();
+        json_object* poStIndexes = json_object_new_object();
+        json_object* poSpatial = json_object_new_object();
+
+        json_object_object_add(poDoc, "_id",
+                               json_object_new_string(designDoc));
+        json_object_object_add(poStIndexes, "spatial", poSpatial);
+        json_object_object_add(poSpatial, "index", 
+            json_object_new_string("function(doc) {if (doc.geometry && doc.geometry.coordinates && doc.geometry.coordinates.length != 0){st_index(doc.geometry);}}"));
+        
+        if (bSrid)
+            json_object_object_add(poStIndexes, "srsid", json_object_new_string(szSrid));
+
+        json_object_object_add(poDoc, "st_indexes", poStIndexes);
+
+        poAnswerObj = PUT(osURI, json_object_to_json_string(poDoc));
+
+        if (IsOK(poAnswerObj, "Cloudant spatial index creation failed"))
+            nUpdateSeq ++;
+
+        json_object_put(poDoc);
+        json_object_put(poAnswerObj);
+    }
+
+    int bGeoJSONDocument = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "GEOJSON", "TRUE"));
+    int nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1"));
+
+    OGRCloudantTableLayer* poLayer = new OGRCloudantTableLayer(this, osLayerName);
+    if (nCoordPrecision != -1)
+        poLayer->SetCoordinatePrecision(nCoordPrecision);
+    poLayer->SetInfoAfterCreation(eGType, poSpatialRef, nUpdateSeq, bGeoJSONDocument);
+    papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
+    papoLayers[nLayers ++] = poLayer;
+    return poLayer;
+}   
diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp
new file mode 100644
index 0000000..0b68cd3
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp
@@ -0,0 +1,118 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  CouchDB Translator
+ * Purpose:  Implements OGRCouchDBDriver.
+ * Author:   Even Rouault, even dot rouault at mines dash paris dot org
+ *
+ ******************************************************************************
+ * Copyright (c) 2011, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_cloudant.h"
+
+CPL_CVSID("$Id$");
+
+extern "C" void RegisterOGRCloudant();
+
+/************************************************************************/
+/*                         ~OGRCloudantDriver()                          */
+/************************************************************************/
+
+OGRCloudantDriver::~OGRCloudantDriver()
+
+{
+}
+
+/************************************************************************/
+/*                              GetName()                               */
+/************************************************************************/
+
+const char *OGRCloudantDriver::GetName()
+
+{
+    return "Cloudant";
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+OGRDataSource *OGRCloudantDriver::Open( const char * pszFilename, int bUpdate )
+
+{
+    if (!EQUALN(pszFilename, "cloudant:", 9))
+        return NULL;
+
+    OGRCloudantDataSource   *poDS = new OGRCloudantDataSource();
+
+    if( !poDS->Open( pszFilename, bUpdate ) )
+    {
+        delete poDS;
+        poDS = NULL;
+    }
+
+    return poDS;
+}
+
+
+/************************************************************************/
+/*                          CreateDataSource()                          */
+/************************************************************************/
+
+OGRDataSource *OGRCloudantDriver::CreateDataSource( const char * pszName,
+                                                   CPL_UNUSED char **papszOptions )
+{
+    OGRCloudantDataSource   *poDS = new OGRCloudantDataSource();
+
+    if( !poDS->Open( pszName, TRUE ) )
+    {
+        delete poDS;
+        poDS = NULL;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRCloudantDriver::TestCapability( const char * pszCap )
+
+{
+    if (EQUAL(pszCap, ODrCCreateDataSource))
+        return TRUE;
+
+    return FALSE;
+}
+
+/************************************************************************/
+/*                         RegisterOGRCloudant()                         */
+/************************************************************************/
+
+void RegisterOGRCloudant()
+
+{
+    OGRSFDriver* poDriver = new OGRCloudantDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Cloudant / CouchDB" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
+}
diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp
new file mode 100644
index 0000000..b9829e3
--- /dev/null
+++ b/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp
@@ -0,0 +1,547 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  Cloudant Translator
+ * Purpose:  Definition of classes for OGR Cloudant driver.
+ * Author:   Norman Barker, norman at cloudant com
+ *           Based on CouchDB driver
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Norman Barker <norman at cloudant com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_cloudant.h"
+#include "ogrgeojsonreader.h"
+#include "ogrgeojsonwriter.h"
+#include "swq.h"
+
+#include <algorithm>
+
+CPL_CVSID("$Id$");
+
+/************************************************************************/
+/*                       OGRCloudantTableLayer()                         */
+/************************************************************************/
+
+OGRCloudantTableLayer::OGRCloudantTableLayer(OGRCloudantDataSource* poDS,
+                                           const char* pszName) :
+                                                        OGRCouchDBTableLayer((OGRCouchDBDataSource*) poDS, pszName)
+
+{
+    bHasStandardSpatial = -1;
+    pszSpatialView = NULL;
+    pszSpatialDDoc = NULL;
+}
+
+/************************************************************************/
+/*                      ~OGRCouchDBTableLayer()                         */
+/************************************************************************/
+
+OGRCloudantTableLayer::~OGRCloudantTableLayer()
+
+{ 
+    if( bMustWriteMetadata )
+    {
+        WriteMetadata();
+        bMustWriteMetadata = FALSE;
+    }
+
+    if (pszSpatialDDoc)
+        free((void*)pszSpatialDDoc);
+}
+
+/************************************************************************/
+/*                   RunSpatialFilterQueryIfNecessary()                 */
+/************************************************************************/
+
+int OGRCloudantTableLayer::RunSpatialFilterQueryIfNecessary()
+{
+    if (!bMustRunSpatialFilter)
+        return TRUE;
+
+    bMustRunSpatialFilter = FALSE;
+
+    CPLAssert(nOffset == 0);
+
+    aosIdsToFetch.resize(0);
+
+    if (pszSpatialView == NULL)
+        GetSpatialView();
+
+    OGREnvelope sEnvelope;
+    m_poFilterGeom->getEnvelope( &sEnvelope );
+
+    CPLString osURI("/");
+    osURI += osEscapedName;
+    osURI += "/";
+    osURI += pszSpatialView;
+    osURI += "?bbox=";
+    osURI += CPLSPrintf("%.9f,%.9f,%.9f,%.9f",
+                        sEnvelope.MinX, sEnvelope.MinY,
+                        sEnvelope.MaxX, sEnvelope.MaxY);
+
+    json_object* poAnswerObj = poDS->GET(osURI);
+    if (poAnswerObj == NULL)
+    {
+        CPLDebug("Cloudant",
+                    "Cloudant geo not working --> client-side spatial filtering");
+        bServerSideSpatialFilteringWorks = FALSE;
+        return FALSE;
+    }
+
+    if ( !json_object_is_type(poAnswerObj, json_type_object) )
+    {
+        CPLDebug("Cloudant",
+                    "Cloudant geo not working --> client-side spatial filtering");
+        bServerSideSpatialFilteringWorks = FALSE;
+        CPLError(CE_Failure, CPLE_AppDefined,
+                    "FetchNextRowsSpatialFilter() failed");
+        json_object_put(poAnswerObj);
+        return FALSE;
+    }
+
+    /* Catch error for a non cloudant geo database */
+    json_object* poError = json_object_object_get(poAnswerObj, "error");
+    json_object* poReason = json_object_object_get(poAnswerObj, "reason");
+
+    const char* pszError = json_object_get_string(poError);
+    const char* pszReason = json_object_get_string(poReason);
+
+    if (pszError && pszReason && strcmp(pszError, "not_found") == 0 &&
+        strcmp(pszReason, "Document is missing attachment") == 0)
+    {
+        CPLDebug("Cloudant",
+                    "Cloudant geo not working --> client-side spatial filtering");
+        bServerSideSpatialFilteringWorks = FALSE;
+        json_object_put(poAnswerObj);
+        return FALSE;
+    }
+
+    if (poDS->IsError(poAnswerObj, "FetchNextRowsSpatialFilter() failed"))
+    {
+        CPLDebug("Cloudant",
+                    "Cloudant geo not working --> client-side spatial filtering");
+        bServerSideSpatialFilteringWorks = FALSE;
+        json_object_put(poAnswerObj);
+        return FALSE;
+    }
+
+    json_object* poRows = json_object_object_get(poAnswerObj, "rows");
+    if (poRows == NULL ||
+        !json_object_is_type(poRows, json_type_array))
+    {
+        CPLDebug("Cloudant",
+                    "Cloudant geo not working --> client-side spatial filtering");
+        bServerSideSpatialFilteringWorks = FALSE;
+        CPLError(CE_Failure, CPLE_AppDefined,
+                    "FetchNextRowsSpatialFilter() failed");
+        json_object_put(poAnswerObj);
+        return FALSE;
+    }
+
+    int nRows = json_object_array_length(poRows);
+    for(int i=0;i<nRows;i++)
+    {
+        json_object* poRow = json_object_array_get_idx(poRows, i);
+        if ( poRow == NULL ||
+            !json_object_is_type(poRow, json_type_object) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                        "FetchNextRowsSpatialFilter() failed");
+            json_object_put(poAnswerObj);
+            return FALSE;
+        }
+
+        json_object* poId = json_object_object_get(poRow, "id");
+        const char* pszId = json_object_get_string(poId);
+        if (pszId != NULL)
+        {
+            aosIdsToFetch.push_back(pszId);
+        }
+    }
+
+    std::sort(aosIdsToFetch.begin(), aosIdsToFetch.end());
+
+    json_object_put(poAnswerObj);
+
+    return TRUE;
+}
+
+
+/************************************************************************/
+/*                          GetSpatialView()                          */
+/************************************************************************/
+
+void OGRCloudantTableLayer::GetSpatialView()
+{
+    if (pszSpatialView == NULL)
+    {
+        char **papszTokens;
+
+        if (bHasStandardSpatial < 0 || bHasStandardSpatial == FALSE)
+        {
+            pszSpatialView = CPLGetConfigOption("CLOUDANT_SPATIAL_FILTER" , NULL);
+            if (pszSpatialView)
+                bHasStandardSpatial = FALSE;
+        }
+
+        if (bHasStandardSpatial < 0)
+        {
+            // get standard cloudant geo spatial view
+            CPLString osURI("/");
+            osURI += osEscapedName;
+            osURI += "/_design/SpatialView";
+
+            json_object* poAnswerObj = poDS->GET(osURI);
+            bHasStandardSpatial = (poAnswerObj != NULL &&
+                json_object_is_type(poAnswerObj, json_type_object) &&
+                json_object_object_get(poAnswerObj, "st_indexes") != NULL);
+            json_object_put(poAnswerObj);
+        }
+
+        if (bHasStandardSpatial)
+            pszSpatialView = "_design/SpatialView/_geo/spatial";
+
+        papszTokens = 
+            CSLTokenizeString2( pszSpatialView, "/", 0);
+
+        if ((papszTokens[0] == NULL) || (papszTokens[1] == NULL))
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "GetSpatialView() failed, invalid spatial design doc.");
+            return;
+        }
+
+        pszSpatialDDoc = (char*) calloc(strlen(papszTokens[0]) + strlen(papszTokens[1]) + 2, 1);
+
+        sprintf(pszSpatialDDoc, "%s/%s", papszTokens[0], papszTokens[1]);
+
+        CSLDestroy(papszTokens);  
+
+    }
+}
+
+/************************************************************************/
+/*                          WriteMetadata()                             */
+/************************************************************************/
+
+void OGRCloudantTableLayer::WriteMetadata()
+{
+    GetLayerDefn();
+
+    if (pszSpatialDDoc == NULL)
+        GetSpatialView();
+    if( pszSpatialDDoc == NULL )
+        return;
+
+    CPLString osURI;
+    osURI = "/";
+    osURI += osEscapedName;
+    osURI += "/";
+    osURI += pszSpatialDDoc;
+
+
+   json_object* poDDocObj = poDS->GET(osURI);
+    if (poDDocObj == NULL)
+        return;
+
+    if ( !json_object_is_type(poDDocObj, json_type_object) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "WriteMetadata() failed");
+        json_object_put(poDDocObj);
+        return;
+    }
+
+    json_object* poError = json_object_object_get(poDDocObj, "error");
+    const char* pszError = json_object_get_string(poError);
+    if (pszError && strcmp(pszError, "not_found") == 0)
+    {
+        json_object_put(poDDocObj);
+        return;
+    }
+
+    if (poDS->IsError(poDDocObj, "WriteMetadata() failed"))
+    {
+        json_object_put(poDDocObj);
+        return;
+    }
+
+
+    if (poSRS)
+    {
+        // epsg codes are supported in Cloudant
+        const char * pszEpsg = NULL;
+        const char * pszAuthName = NULL;
+        char szSrid[100];
+
+        if (poSRS->IsProjected())
+        {
+            pszAuthName = poSRS->GetAuthorityName("PROJCS");
+            if ((pszAuthName != NULL) && (strncmp(pszAuthName, "EPSG", 4) == 0))
+                pszEpsg = poSRS->GetAuthorityCode("PROJCS");
+        }
+        else
+        {
+            pszAuthName = poSRS->GetAuthorityName("GEOGCS");
+            if ((pszAuthName != NULL) && (strncmp(pszAuthName, "EPSG", 4) == 0))
+                pszEpsg = poSRS->GetAuthorityCode("GEOGCS");
+        }
+
+        if (pszEpsg != NULL) 
+        {
+            const char * pszUrn = "urn:ogc:def:crs:epsg::";
+            CPLStrlcpy(szSrid, pszUrn, sizeof(szSrid));
+            if (CPLStrlcpy(szSrid + sizeof(pszUrn), pszEpsg, sizeof(szSrid)) <= sizeof(szSrid))
+            {
+                json_object_object_add(poDDocObj, "srsid",
+                                   json_object_new_string(pszUrn));
+
+            } 
+        }
+    }
+
+    if (eGeomType != wkbNone)
+    {
+        json_object_object_add(poDDocObj, "geomtype",
+                    json_object_new_string(OGRToOGCGeomType(eGeomType)));
+        if (wkbHasZ(poFeatureDefn->GetGeomType()))
+        {
+            json_object_object_add(poDDocObj, "is_25D",
+                               json_object_new_boolean(TRUE));
+        }
+    }
+    else
+    {
+        json_object_object_add(poDDocObj, "geomtype",
+                               json_object_new_string("NONE"));
+    }
+
+    json_object_object_add(poDDocObj, "geojson_documents",
+                           json_object_new_boolean(bGeoJSONDocument));
+
+    json_object* poFields = json_object_new_array();
+    json_object_object_add(poDDocObj, "fields", poFields);
+
+    for(int i=FIRST_FIELD;i<poFeatureDefn->GetFieldCount();i++)
+    {
+        json_object* poField = json_object_new_object();
+        json_object_array_add(poFields, poField);
+
+        json_object_object_add(poField, "name",
+            json_object_new_string(poFeatureDefn->GetFieldDefn(i)->GetNameRef()));
+
+        const char* pszType = NULL;
+        switch (poFeatureDefn->GetFieldDefn(i)->GetType())
+        {
+            case OFTInteger: pszType = "integer"; break;
+            case OFTReal: pszType = "real"; break;
+            case OFTString: pszType = "string"; break;
+            case OFTIntegerList: pszType = "integerlist"; break;
+            case OFTRealList: pszType = "reallist"; break;
+            case OFTStringList: pszType = "stringlist"; break;
+            default: pszType = "string"; break;
+        }
+
+        json_object_object_add(poField, "type",
+                               json_object_new_string(pszType));
+    }
+
+    json_object* poAnswerObj = poDS->PUT(osURI,
+                                         json_object_to_json_string(poDDocObj));
+
+    json_object_put(poDDocObj);
+    json_object_put(poAnswerObj);
+}
+
+/************************************************************************/
+/*                     OGRCloudantIsNumericObject()                      */
+/************************************************************************/
+
+static int OGRCloudantIsNumericObject(json_object* poObj)
+{
+    int iType = json_object_get_type(poObj);
+    return iType == json_type_int || iType == json_type_double;
+}
+
+/************************************************************************/
+/*                          LoadMetadata()                              */
+/************************************************************************/
+
+void OGRCloudantTableLayer::LoadMetadata()
+{
+    if (bHasLoadedMetadata)
+        return;
+
+    bHasLoadedMetadata = TRUE;
+
+    if (pszSpatialDDoc == NULL)
+        GetSpatialView();
+    if( pszSpatialDDoc == NULL )
+        return;
+
+    CPLString osURI("/");
+    osURI += osEscapedName;
+    osURI += "/";
+    osURI += pszSpatialDDoc;
+
+    json_object* poAnswerObj = poDS->GET(osURI);
+    if (poAnswerObj == NULL)
+        return;
+
+    if ( !json_object_is_type(poAnswerObj, json_type_object) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "LoadMetadata() failed");
+        json_object_put(poAnswerObj);
+        return;
+    }
+
+    json_object* poRev = json_object_object_get(poAnswerObj, "_rev");
+    const char* pszRev = json_object_get_string(poRev);
+    if (pszRev)
+        osMetadataRev = pszRev;
+
+    json_object* poError = json_object_object_get(poAnswerObj, "error");
+    const char* pszError = json_object_get_string(poError);
+    if (pszError && strcmp(pszError, "not_found") == 0)
+    {
+        json_object_put(poAnswerObj);
+        return;
+    }
+
+    if (poDS->IsError(poAnswerObj, "LoadMetadata() failed"))
+    {
+        json_object_put(poAnswerObj);
+        return;
+    }
+
+    json_object* poJsonSRS = json_object_object_get(poAnswerObj, "srsid");
+    const char* pszSRS = json_object_get_string(poJsonSRS);
+    if (pszSRS != NULL)
+    {
+        poSRS = new OGRSpatialReference();
+        if (poSRS->importFromURN(pszSRS) != OGRERR_NONE)
+        {
+            delete poSRS;
+            poSRS = NULL;
+        }
+    }
+
+    json_object* poGeomType = json_object_object_get(poAnswerObj, "geomtype");
+    const char* pszGeomType = json_object_get_string(poGeomType);
+
+     if (pszGeomType)
+    {
+        if (EQUAL(pszGeomType, "NONE"))
+        {
+            eGeomType = wkbNone;
+            bExtentValid = TRUE;
+        }
+        else
+        {
+            eGeomType = OGRFromOGCGeomType(pszGeomType);
+
+            json_object* poIs25D = json_object_object_get(poAnswerObj, "is_25D");
+            if (poIs25D && json_object_get_boolean(poIs25D))
+                eGeomType = wkbSetZ(eGeomType);
+
+            json_object* poExtent = json_object_object_get(poAnswerObj, "extent");
+            if (poExtent && json_object_get_type(poExtent) == json_type_object)
+            {
+                json_object* poBbox = json_object_object_get(poExtent, "bbox");
+                if (poBbox &&
+                    json_object_get_type(poBbox) == json_type_array &&
+                    json_object_array_length(poBbox) == 4 &&
+                    OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 0)) &&
+                    OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 1)) &&
+                    OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 2)) &&
+                    OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 3)))
+                {
+                    dfMinX = json_object_get_double(json_object_array_get_idx(poBbox, 0));
+                    dfMinY = json_object_get_double(json_object_array_get_idx(poBbox, 1));
+                    dfMaxX = json_object_get_double(json_object_array_get_idx(poBbox, 2));
+                    dfMaxY = json_object_get_double(json_object_array_get_idx(poBbox, 3));
+                    bExtentValid = bExtentSet = TRUE;
+                }
+            }
+        }
+    }
+
+    json_object* poGeoJSON = json_object_object_get(poAnswerObj, "geojson_documents");
+    if (poGeoJSON && json_object_is_type(poGeoJSON, json_type_boolean))
+        bGeoJSONDocument = json_object_get_boolean(poGeoJSON);
+
+    json_object* poFields = json_object_object_get(poAnswerObj, "fields");
+    if (poFields && json_object_is_type(poFields, json_type_array))
+    {
+        poFeatureDefn = new OGRFeatureDefn( osName );
+        poFeatureDefn->Reference();
+
+        poFeatureDefn->SetGeomType(eGeomType);
+        if( poFeatureDefn->GetGeomFieldCount() != 0 ) 
+            poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+
+        OGRFieldDefn oFieldId("_id", OFTString);
+        poFeatureDefn->AddFieldDefn(&oFieldId);
+
+        OGRFieldDefn oFieldRev("_rev", OFTString);
+        poFeatureDefn->AddFieldDefn(&oFieldRev);
+
+        int nFields = json_object_array_length(poFields);
+        for(int i=0;i<nFields;i++)
+        {
+            json_object* poField = json_object_array_get_idx(poFields, i);
+            if (poField && json_object_is_type(poField, json_type_object))
+            {
+                json_object* poName = json_object_object_get(poField, "name");
+                const char* pszName = json_object_get_string(poName);
+                if (pszName)
+                {
+                    json_object* poType = json_object_object_get(poField, "type");
+                    const char* pszType = json_object_get_string(poType);
+                    OGRFieldType eType = OFTString;
+                    if (pszType)
+                    {
+                        if (strcmp(pszType, "integer") == 0)
+                            eType = OFTInteger;
+                        else if (strcmp(pszType, "integerlist") == 0)
+                            eType = OFTIntegerList;
+                        else if (strcmp(pszType, "real") == 0)
+                            eType = OFTReal;
+                        else if (strcmp(pszType, "reallist") == 0)
+                            eType = OFTRealList;
+                        else if (strcmp(pszType, "string") == 0)
+                            eType = OFTString;
+                        else if (strcmp(pszType, "stringlist") == 0)
+                            eType = OFTStringList;
+                    }
+
+                    OGRFieldDefn oField(pszName, eType);
+                    poFeatureDefn->AddFieldDefn(&oField);
+                }
+            }
+        }
+    }
+
+    std::sort(aosIdsToFetch.begin(), aosIdsToFetch.end());
+
+    json_object_put(poAnswerObj);
+
+    return;
+}
diff --git a/ogr/ogrsf_frmts/couchdb/GNUmakefile b/ogr/ogrsf_frmts/couchdb/GNUmakefile
index 53a6a9b..96aea41 100644
--- a/ogr/ogrsf_frmts/couchdb/GNUmakefile
+++ b/ogr/ogrsf_frmts/couchdb/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrcouchdbdriver.o ogrcouchdbdatasource.o ogrcouchdblayer.o ogrcouchdbtablelayer.o ogrcouchdbrowslayer.o
 
-CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. -I../geojson $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. -I../geojson  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/couchdb/drv_couchdb.html b/ogr/ogrsf_frmts/couchdb/drv_couchdb.html
index 3eaa65e..a8ae415 100644
--- a/ogr/ogrsf_frmts/couchdb/drv_couchdb.html
+++ b/ogr/ogrsf_frmts/couchdb/drv_couchdb.html
@@ -56,7 +56,7 @@ Table creation and deletion is possible.<p>
 
 Write support is only enabled when the datasource is opened in update mode.<p>
 
-When inserting a new feature with CreateFeature(), and if the command is successfull, OGR will fetch the
+When inserting a new feature with CreateFeature(), and if the command is successful, OGR will fetch the
 returned _id and _rev and use them.<p>
 
 <h2>Write support and OGR transactions</h2>
diff --git a/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h b/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h
index 774106e..f543034 100644
--- a/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h
+++ b/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_couchdb.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_couchdb.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  CouchDB Translator
  * Purpose:  Definition of classes for OGR CouchDB / GeoCouch driver.
@@ -81,7 +81,7 @@ protected:
    void                         BuildFeatureDefnFromDoc(json_object* poDoc);
    int                          BuildFeatureDefnFromRows(json_object* poAnswerObj);
 
-    int                         GetFeaturesToFetch() { return atoi(CPLGetConfigOption("COUCHDB_PAGE_SIZE", "500")); }
+   virtual int                  GetFeaturesToFetch() { return atoi(CPLGetConfigOption("COUCHDB_PAGE_SIZE", "500")); }
 
   public:
                          OGRCouchDBLayer(OGRCouchDBDataSource* poDS);
@@ -96,7 +96,9 @@ protected:
 
     virtual CouchDBLayerType    GetLayerType() = 0;
 
-    virtual OGRErr              SetNextByIndex( long nIndex );
+    virtual OGRErr              SetNextByIndex( GIntBig nIndex );
+
+    virtual OGRSpatialReference * GetSpatialRef();
 };
 
 /************************************************************************/
@@ -105,33 +107,18 @@ protected:
 
 class OGRCouchDBTableLayer : public OGRCouchDBLayer
 {
-    CPLString                 osName;
-    CPLString                 osEscapedName;
-
     int                       nNextFIDForCreate;
     int                       bInTransaction;
     std::vector<json_object*> aoTransactionFeatures;
 
-    OGRwkbGeometryType        eGeomType;
-
-    int                       bHasLoadedMetadata;
-    int                       bMustWriteMetadata;
-    CPLString                 osMetadataRev;
-    void                      LoadMetadata();
-    void                      WriteMetadata();
-
     virtual int               FetchNextRows();
 
     int                       bHasOGRSpatial;
     int                       bHasGeocouchUtilsMinimalSpatialView;
-    int                       bServerSideSpatialFilteringWorks;
-    int                       bMustRunSpatialFilter;
-    std::vector<CPLString>    aosIdsToFetch;
-    int                       RunSpatialFilterQueryIfNecessary();
+    int                       bServerSideAttributeFilteringWorks;
     int                       FetchNextRowsSpatialFilter();
 
     int                       bHasInstalledAttributeFilter;
-    int                       bServerSideAttributeFilteringWorks;
     CPLString                 osURIAttributeFilter;
     std::map<CPLString, int>  oMapFilterFields;
     CPLString                 BuildAttrQueryURI(int& bOutHasStrictComparisons);
@@ -144,17 +131,34 @@ class OGRCouchDBTableLayer : public OGRCouchDBLayer
     int                       bAlwaysValid;
     int                       FetchUpdateSeq();
 
+    int                       nCoordPrecision;
+
+    OGRFeature*               GetFeature( const char* pszId );
+    OGRErr                    DeleteFeature( OGRFeature* poFeature );
+
+    protected:
+
+    CPLString                 osName;
+    CPLString                 osEscapedName;
+    int                       bMustWriteMetadata;
+    int                       bMustRunSpatialFilter;
+    std::vector<CPLString>    aosIdsToFetch;   
+    int                       bServerSideSpatialFilteringWorks;
+    int                       bHasLoadedMetadata;
+    CPLString                 osMetadataRev;
     int                       bExtentValid;
+
     int                       bExtentSet;
     double                    dfMinX;
     double                    dfMinY;
     double                    dfMaxX;
     double                    dfMaxY;
 
-    int                       nCoordPrecision;
+    OGRwkbGeometryType        eGeomType;
 
-    OGRFeature*               GetFeature( const char* pszId );
-    OGRErr                    DeleteFeature( OGRFeature* poFeature );
+    virtual void              WriteMetadata();
+    virtual void              LoadMetadata();
+    virtual int               RunSpatialFilterQueryIfNecessary();
 
     public:
             OGRCouchDBTableLayer(OGRCouchDBDataSource* poDS,
@@ -167,19 +171,19 @@ class OGRCouchDBTableLayer : public OGRCouchDBLayer
 
     virtual const char *        GetName() { return osName.c_str(); }
 
-    virtual int                 GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig             GetFeatureCount( int bForce = TRUE );
     virtual OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
-    virtual OGRFeature *        GetFeature( long nFID );
+    virtual OGRFeature *        GetFeature( GIntBig nFID );
 
     virtual void                SetSpatialFilter( OGRGeometry * );
     virtual OGRErr              SetAttributeFilter( const char * );
 
     virtual OGRErr              CreateField( OGRFieldDefn *poField,
                                             int bApproxOK = TRUE );
-    virtual OGRErr              CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr              SetFeature( OGRFeature *poFeature );
-    virtual OGRErr              DeleteFeature( long nFID );
+    virtual OGRErr              ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr              ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr              DeleteFeature( GIntBig nFID );
 
     virtual OGRErr              StartTransaction();
     virtual OGRErr              CommitTransaction();
@@ -230,6 +234,7 @@ class OGRCouchDBRowsLayer : public OGRCouchDBLayer
 
 class OGRCouchDBDataSource : public OGRDataSource
 {
+  protected:
     char*               pszName;
 
     OGRLayer**          papoLayers;
@@ -267,7 +272,7 @@ class OGRCouchDBDataSource : public OGRDataSource
 
     virtual int         TestCapability( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName,
+    virtual OGRLayer   *ICreateLayer( const char *pszName,
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
@@ -280,6 +285,7 @@ class OGRCouchDBDataSource : public OGRDataSource
 
     int                         IsReadWrite() const { return bReadWrite; }
 
+    char*                 GetETag(const char* pszURI);
     json_object*                GET(const char* pszURI);
     json_object*                PUT(const char* pszURI, const char* pszData);
     json_object*                POST(const char* pszURI, const char* pszData);
diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp
index 0fddeec..1891a34 100644
--- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp
+++ b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcouchdbdatasource.cpp 27268 2014-05-01 10:46:20Z rouault $
+ * $Id: ogrcouchdbdatasource.cpp 29101 2015-05-01 22:17:43Z rouault $
  *
  * Project:  CouchDB Translator
  * Purpose:  Implements OGRCouchDBDataSource class
@@ -30,7 +30,7 @@
 #include "ogr_couchdb.h"
 #include "swq.h"
 
-CPL_CVSID("$Id: ogrcouchdbdatasource.cpp 27268 2014-05-01 10:46:20Z rouault $");
+CPL_CVSID("$Id: ogrcouchdbdatasource.cpp 29101 2015-05-01 22:17:43Z rouault $");
 
 /************************************************************************/
 /*                        OGRCouchDBDataSource()                        */
@@ -62,8 +62,8 @@ OGRCouchDBDataSource::~OGRCouchDBDataSource()
 
     if (bMustCleanPersistant)
     {
-        char** papszOptions = CSLAddString(NULL,
-                          CPLSPrintf("CLOSE_PERSISTENT=CouchDB:%p", this));
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("CouchDB:%p", this));
         CPLHTTPFetch( osURL, papszOptions);
         CSLDestroy(papszOptions);
     }
@@ -120,6 +120,7 @@ OGRLayer* OGRCouchDBDataSource::OpenDatabase(const char* pszLayerName)
 {
     CPLString osTableName;
     CPLString osEscapedName;
+
     if (pszLayerName)
     {
         osTableName = pszLayerName;
@@ -215,7 +216,7 @@ int OGRCouchDBDataSource::Open( const char * pszFilename, int bUpdateIn)
     bReadWrite = bUpdateIn;
 
     pszName = CPLStrdup( pszFilename );
-
+ 
     if (bHTTP)
         osURL = pszFilename;
     else
@@ -253,7 +254,11 @@ int OGRCouchDBDataSource::Open( const char * pszFilename, int bUpdateIn)
     json_object* poAnswerObj = GET("/_all_dbs");
 
     if (poAnswerObj == NULL)
+    {
+        if (!EQUALN(pszFilename, "CouchDB:", 8))
+            CPLErrorReset();
         return FALSE;
+    }
 
     if ( !json_object_is_type(poAnswerObj, json_type_array) )
     {
@@ -308,10 +313,10 @@ int OGRCouchDBDataSource::Open( const char * pszFilename, int bUpdateIn)
 
 
 /************************************************************************/
-/*                           CreateLayer()                              */
+/*                          ICreateLayer()                              */
 /************************************************************************/
 
-OGRLayer   *OGRCouchDBDataSource::CreateLayer( const char *pszName,
+OGRLayer   *OGRCouchDBDataSource::ICreateLayer( const char *pszName,
                                            OGRSpatialReference *poSpatialRef,
                                            OGRwkbGeometryType eGType,
                                            char ** papszOptions )
@@ -653,7 +658,7 @@ OGRLayer * OGRCouchDBDataSource::ExecuteSQL( const char *pszSQLCommand,
             return NULL;
         }
 
-        swq_expr_node * pNode = (swq_expr_node *) oQuery.GetSWGExpr();
+        swq_expr_node * pNode = (swq_expr_node *) oQuery.GetSWQExpr();
         if (pNode->eNodeType == SNT_OPERATION &&
             pNode->nOperation == SWQ_EQ &&
             pNode->nSubExprCount == 2 &&
@@ -1016,6 +1021,57 @@ void OGRCouchDBDataSource::ReleaseResultSet( OGRLayer * poLayer )
 }
 
 /************************************************************************/
+/*                               GetETag()                                 */
+/************************************************************************/
+
+char* OGRCouchDBDataSource::GetETag(const char* pszURI)
+{
+
+    // make a head request and only return the etag response header
+    char* pszEtag = NULL;
+    char **papszTokens;
+    char** papszOptions = NULL;
+
+    bMustCleanPersistant = TRUE;
+
+    papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this));
+    papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json");
+    papszOptions = CSLAddString(papszOptions, "NO_BODY=1");
+    
+    if (osUserPwd.size())
+    {
+        CPLString osUserPwdOption("USERPWD=");
+        osUserPwdOption += osUserPwd;
+        papszOptions = CSLAddString(papszOptions, osUserPwdOption);
+    }
+
+    CPLDebug("CouchDB", "HEAD %s", pszURI);
+
+    CPLString osFullURL(osURL);
+    osFullURL += pszURI;
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+
+    CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions);
+    CPLPopErrorHandler();
+    CSLDestroy(papszOptions);
+    if (psResult == NULL)
+        return NULL;
+
+    if (CSLFetchNameValue(psResult->papszHeaders, "Etag") != NULL)
+    {
+        papszTokens = 
+            CSLTokenizeString2( CSLFetchNameValue(psResult->papszHeaders, "Etag"), "\"\r\n", 0 );
+        
+        pszEtag = CPLStrdup(papszTokens[0]);
+
+        CSLDestroy( papszTokens );
+    }
+
+    CPLHTTPDestroyResult(psResult);
+    return pszEtag;
+}
+
+/************************************************************************/
 /*                             REQUEST()                                */
 /************************************************************************/
 
@@ -1050,6 +1106,7 @@ json_object* OGRCouchDBDataSource::REQUEST(const char* pszVerb,
     CPLString osFullURL(osURL);
     osFullURL += pszURI;
     CPLPushErrorHandler(CPLQuietErrorHandler);
+
     CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions);
     CPLPopErrorHandler();
     CSLDestroy(papszOptions);
diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp
index 4317240..786337e 100644
--- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp
+++ b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcouchdbdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrcouchdbdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CouchDB Translator
  * Purpose:  Implements OGRCouchDBDriver.
@@ -31,7 +31,7 @@
 
 // g++ -g -Wall -fPIC -shared -o ogr_CouchDB.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/couchdb ogr/ogrsf_frmts/couchdb/*.c* -L. -lgdal -Iogr/ogrsf_frmts/geojson/jsonc
 
-CPL_CVSID("$Id: ogrcouchdbdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrcouchdbdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 extern "C" void RegisterOGRCouchDB();
 
@@ -61,6 +61,14 @@ const char *OGRCouchDBDriver::GetName()
 OGRDataSource *OGRCouchDBDriver::Open( const char * pszFilename, int bUpdate )
 
 {
+    if (strncmp(pszFilename, "http://", 7) == 0 ||
+        strncmp(pszFilename, "https://", 8) == 0)
+    {
+        /* ok */
+    }
+    else if (!EQUALN(pszFilename, "CouchDB:", 8))
+        return NULL;
+
     OGRCouchDBDataSource   *poDS = new OGRCouchDBDataSource();
 
     if( !poDS->Open( pszFilename, bUpdate ) )
@@ -111,6 +119,7 @@ int OGRCouchDBDriver::TestCapability( const char * pszCap )
 void RegisterOGRCouchDB()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRCouchDBDriver );
+    OGRSFDriver* poDriver = new OGRCouchDBDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "CouchDB / GeoCouch" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
 }
-
diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp
index a1156e5..a070362 100644
--- a/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp
+++ b/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcouchdblayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrcouchdblayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  CouchDB Translator
  * Purpose:  Implements OGRCouchDBLayer class.
@@ -31,7 +31,7 @@
 #include "ogrgeojsonreader.h"
 #include "ogrgeojsonutils.h"
 
-CPL_CVSID("$Id: ogrcouchdblayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrcouchdblayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRCouchDBLayer()                             */
@@ -156,12 +156,12 @@ OGRFeature *OGRCouchDBLayer::GetNextRawFeature()
 /*                          SetNextByIndex()                            */
 /************************************************************************/
 
-OGRErr OGRCouchDBLayer::SetNextByIndex( long nIndex )
+OGRErr OGRCouchDBLayer::SetNextByIndex( GIntBig nIndex )
 {
-    if (nIndex < 0)
+    if (nIndex < 0 || nIndex >= INT_MAX )
         return OGRERR_FAILURE;
     bEOF = FALSE;
-    nNextInSeq = nIndex;
+    nNextInSeq = (int)nIndex;
     return OGRERR_NONE;
 }
 
@@ -366,8 +366,9 @@ void OGRCouchDBLayer::BuildFeatureDefnFromDoc(json_object* poDoc)
         {
             if( -1 == poFeatureDefn->GetFieldIndex( it.key ) )
             {
+                OGRFieldSubType eSubType;
                 OGRFieldDefn fldDefn( it.key,
-                    GeoJSONPropertyToFieldType( it.val ) );
+                    GeoJSONPropertyToFieldType( it.val, eSubType ) );
                 poFeatureDefn->AddFieldDefn( &fldDefn );
             }
         }
@@ -383,8 +384,9 @@ void OGRCouchDBLayer::BuildFeatureDefnFromDoc(json_object* poDoc)
                 strcmp(it.key, "geometry") != 0 &&
                 -1 == poFeatureDefn->GetFieldIndex( it.key ) )
             {
+                OGRFieldSubType eSubType;
                 OGRFieldDefn fldDefn( it.key,
-                    GeoJSONPropertyToFieldType( it.val ) );
+                    GeoJSONPropertyToFieldType( it.val, eSubType ) );
                 poFeatureDefn->AddFieldDefn( &fldDefn );
             }
         }
@@ -536,3 +538,13 @@ int OGRCouchDBLayer::FetchNextRowsAnalyseDocs(json_object* poAnswerObj)
 
     return TRUE;
 }
+
+/************************************************************************/
+/*              	     GetSpatialRef()                            */
+/************************************************************************/
+
+OGRSpatialReference* OGRCouchDBLayer::GetSpatialRef()
+{
+    GetLayerDefn();
+    return poSRS;
+}
diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp
index c9a5a32..0f565cd 100644
--- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp
+++ b/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcouchdbrowslayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrcouchdbrowslayer.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  CouchDB Translator
  * Purpose:  Implements OGRCouchDBRowsLayer class.
@@ -29,7 +29,7 @@
 
 #include "ogr_couchdb.h"
 
-CPL_CVSID("$Id: ogrcouchdbrowslayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrcouchdbrowslayer.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                         OGRCouchDBRowsLayer()                        */
@@ -48,6 +48,8 @@ OGRCouchDBRowsLayer::OGRCouchDBRowsLayer(OGRCouchDBDataSource* poDS) :
     OGRFieldDefn oFieldRev("_rev", OFTString);
     poFeatureDefn->AddFieldDefn(&oFieldRev);
 
+    SetDescription( poFeatureDefn->GetName() );
+
     bAllInOne = FALSE;
 }
 
diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp
index 5ba7424..4fbbd15 100644
--- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp
+++ b/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcouchdbtablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrcouchdbtablelayer.cpp 28928 2015-04-17 10:24:19Z rouault $
  *
  * Project:  CouchDB Translator
  * Purpose:  Implements OGRCouchDBTableLayer class.
@@ -34,7 +34,7 @@
 
 #include <algorithm>
 
-CPL_CVSID("$Id: ogrcouchdbtablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrcouchdbtablelayer.cpp 28928 2015-04-17 10:24:19Z rouault $");
 
 /************************************************************************/
 /*                       OGRCouchDBTableLayer()                         */
@@ -77,6 +77,8 @@ OGRCouchDBTableLayer::OGRCouchDBTableLayer(OGRCouchDBDataSource* poDS,
     dfMaxY = 0;
 
     nCoordPrecision = atoi(CPLGetConfigOption("OGR_COUCHDB_COORDINATE_PRECISION", "-1"));
+    
+    SetDescription( osName );
 }
 
 /************************************************************************/
@@ -488,7 +490,11 @@ static CPLString OGRCouchDBGetValue(swq_field_type eType,
     }
     else if (eType == SWQ_INTEGER)
     {
-        return CPLSPrintf("%d", poNode->int_value);
+        return CPLSPrintf("%d", (int)poNode->int_value);
+    }
+    else if (eType == SWQ_INTEGER64)
+    {
+        return CPLSPrintf(CPL_FRMT_GIB, poNode->int_value);
     }
     else if (eType == SWQ_FLOAT)
     {
@@ -539,7 +545,7 @@ CPLString OGRCouchDBTableLayer::BuildAttrQueryURI(int& bOutHasStrictComparisons)
 
     int bCanHandleFilter = FALSE;
 
-    swq_expr_node * pNode = (swq_expr_node *) m_poAttrQuery->GetSWGExpr();
+    swq_expr_node * pNode = (swq_expr_node *) m_poAttrQuery->GetSWQExpr();
     if (pNode->eNodeType == SNT_OPERATION &&
         (pNode->nOperation == SWQ_EQ ||
             pNode->nOperation == SWQ_GE ||
@@ -564,7 +570,8 @@ CPLString OGRCouchDBTableLayer::BuildAttrQueryURI(int& bOutHasStrictComparisons)
             osURI += "/_all_docs?";
         }
         else if (nIndex >= FIRST_FIELD &&
-            (eType == SWQ_STRING || eType == SWQ_INTEGER || eType == SWQ_FLOAT))
+            (eType == SWQ_STRING || eType == SWQ_INTEGER ||
+             eType == SWQ_INTEGER64 || eType == SWQ_FLOAT))
         {
             int bFoundFilter = HasFilterOnFieldOrCreateIfNecessary(pszFieldName);
             if (bFoundFilter)
@@ -627,7 +634,8 @@ CPLString OGRCouchDBTableLayer::BuildAttrQueryURI(int& bOutHasStrictComparisons)
         }
         else if (nIndex0 == nIndex1 && eType0 == eType1 &&
             nIndex0 >= FIRST_FIELD &&
-            (eType0 == SWQ_STRING || eType0 == SWQ_INTEGER || eType0 == SWQ_FLOAT))
+            (eType0 == SWQ_STRING || eType0 == SWQ_INTEGER ||
+             eType0 == SWQ_INTEGER64 || eType0 == SWQ_FLOAT))
         {
             int bFoundFilter = HasFilterOnFieldOrCreateIfNecessary(pszFieldName);
             if (bFoundFilter)
@@ -687,7 +695,8 @@ CPLString OGRCouchDBTableLayer::BuildAttrQueryURI(int& bOutHasStrictComparisons)
             osURI += "/_all_docs?";
         }
         else if (nIndex >= FIRST_FIELD &&
-            (eType == SWQ_STRING || eType == SWQ_INTEGER || eType == SWQ_FLOAT))
+            (eType == SWQ_STRING || eType == SWQ_INTEGER ||
+             eType == SWQ_INTEGER64 || eType == SWQ_FLOAT))
         {
             int bFoundFilter = HasFilterOnFieldOrCreateIfNecessary(pszFieldName);
             if (bFoundFilter)
@@ -793,7 +802,7 @@ int OGRCouchDBTableLayer::FetchNextRows()
 /*                            GetFeature()                              */
 /************************************************************************/
 
-OGRFeature * OGRCouchDBTableLayer::GetFeature( long nFID )
+OGRFeature * OGRCouchDBTableLayer::GetFeature( GIntBig nFID )
 {
     GetLayerDefn();
 
@@ -885,7 +894,7 @@ OGRFeatureDefn * OGRCouchDBTableLayer::GetLayerDefn()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRCouchDBTableLayer::GetFeatureCount(int bForce)
+GIntBig OGRCouchDBTableLayer::GetFeatureCount(int bForce)
 {
     GetLayerDefn();
 
@@ -1074,18 +1083,18 @@ static json_object* OGRCouchDBWriteFeature( OGRFeature* poFeature,
                                 json_object_new_string(pszId) );
 
         if ( poFeature->GetFID() != OGRNullFID &&
-             strcmp(CPLSPrintf("%09ld", poFeature->GetFID()), pszId) != 0 )
+             strcmp(CPLSPrintf("%09ld", (long)poFeature->GetFID()), pszId) != 0 )
         {
             CPLDebug("CouchDB",
                      "_id field = %s, but FID = %09ld --> taking into account _id field only",
                      pszId,
-                     poFeature->GetFID());
+                     (long)poFeature->GetFID());
         }
     }
     else if ( poFeature->GetFID() != OGRNullFID )
     {
         json_object_object_add( poObj, "_id",
-                                json_object_new_string(CPLSPrintf("%09ld", poFeature->GetFID())) );
+                                json_object_new_string(CPLSPrintf("%09ld", (long)poFeature->GetFID())) );
     }
 
     if (poFeature->IsFieldSet(_REV_FIELD))
@@ -1230,10 +1239,10 @@ int OGRCouchDBTableLayer::GetMaximumId()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRCouchDBTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRCouchDBTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     GetLayerDefn();
@@ -1369,10 +1378,10 @@ OGRErr OGRCouchDBTableLayer::CreateFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
 
-OGRErr      OGRCouchDBTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRCouchDBTableLayer::ISetFeature( OGRFeature *poFeature )
 {
     GetLayerDefn();
 
@@ -1431,7 +1440,7 @@ OGRErr      OGRCouchDBTableLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRCouchDBTableLayer::DeleteFeature( long nFID )
+OGRErr OGRCouchDBTableLayer::DeleteFeature( GIntBig nFID )
 {
     GetLayerDefn();
 
@@ -1816,7 +1825,7 @@ void OGRCouchDBTableLayer::LoadMetadata()
 
             json_object* poIs25D = json_object_object_get(poAnswerObj, "is_25D");
             if (poIs25D && json_object_get_boolean(poIs25D))
-                eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
+                eGeomType = wkbSetZ(eGeomType);
 
             json_object* poExtent = json_object_object_get(poAnswerObj, "extent");
             if (poExtent && json_object_get_type(poExtent) == json_type_object)
@@ -1963,7 +1972,7 @@ void OGRCouchDBTableLayer::WriteMetadata()
     {
         json_object_object_add(poDoc, "geomtype",
                     json_object_new_string(OGRToOGCGeomType(eGeomType)));
-        if (poFeatureDefn->GetGeomType() & wkb25DBit)
+        if (wkbHasZ(poFeatureDefn->GetGeomType()))
         {
             json_object_object_add(poDoc, "is_25D",
                                json_object_new_boolean(TRUE));
diff --git a/ogr/ogrsf_frmts/csv/GNUmakefile b/ogr/ogrsf_frmts/csv/GNUmakefile
index 030eeb1..61a10d3 100644
--- a/ogr/ogrsf_frmts/csv/GNUmakefile
+++ b/ogr/ogrsf_frmts/csv/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrcsvdriver.o ogrcsvdatasource.o ogrcsvlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/csv/drv_csv.html b/ogr/ogrsf_frmts/csv/drv_csv.html
index e1ffedb..a358349 100644
--- a/ogr/ogrsf_frmts/csv/drv_csv.html
+++ b/ogr/ogrsf_frmts/csv/drv_csv.html
@@ -33,12 +33,17 @@ if no field type information file (with .csvt extension) is
 available.</p>
 
 <p>Limited type recognition can be done for Integer, Real, String, Date 
-(YYYY-MM-DD), Time (HH:MM:SS+nn) and DateTime (YYYY-MM-DD HH:MM:SS+nn) columns
+(YYYY-MM-DD), Time (HH:MM:SS+nn), DateTime (YYYY-MM-DD HH:MM:SS+nn) columns
 through a descriptive file with the same name as the CSV file, but a .csvt extension.
 In a single line the types for each column have to be listed with double quotes and
 be comma separated (e.g., "Integer","String"). It is also possible to specify
 explicitly the width and precision of each column, e.g. "Integer(5)","Real(10.7)","String(15)".
-The driver will then use these types as specified for the csv columns.</p>
+The driver will then use these types as specified for the csv columns.
+Starting with GDAL 2.0, subtypes can be passed between parenthesis, such as
+"Integer(Boolean)", "Integer(Int16)" and "Real(Float32)"</p>
+
+<p>Starting with GDAL 2.0, automatic field type guessing can also be done if
+specifying the open options described in the below "Open options" section.</p>
 
 <h2>Format</h2>
 
@@ -137,6 +142,37 @@ OGRFeature(test):3
   POINT (0.75 47.5 0)
 </pre>
 
+<h2>Open options</h2>
+
+Starting with GDAL 2.0, the following open options can be specified
+(typically with the -oo name=value parameters of ogrinfo or ogr2ogr):
+<ul>
+<li><b>AUTODETECT_TYPE</b>=YES/NO (defaults to NO). Setting it to YES will
+enable auto-detection of field data types. If while reading the records
+(beyond the records used for autodetection), a value is found to not correspond
+to the autodetected data type, a warning will be emitted and the field will be
+emptied.</li>
+<li><b>KEEP_SOURCE_COLUMNS</b>=YES/NO (default NO) keep a copy of the original
+columns where the guessing is active, and the guessed type is different from
+string. The name of the original columns will be suffixed with "_original".
+This flag should be used only when AUTODETECT_TYPE=YES.</li>
+<li><b>AUTODETECT_WIDTH</b>=YES/NO/STRING_ONLY (defaults to NO). Setting it to
+YES to detect the width of string and integer fields, and the width and precision
+of real fields. Setting it to STRING_ONLY restricts to string fields. Setting it
+to NO select default size and width. If while reading the records (beyond the
+records used for autodetection), a value is found to not correspond to the
+autodetected width/precision, a warning will be emitted and the field will be
+emptied.</li>
+<li><b>AUTODETECT_SIZE_LIMIT</b>=size to specify the number of bytes to inspect
+to determine the data type and width/precision. The default will be 100000.
+Setting 0 means inspecting the whole file.  Note : specifying a value over 1 MB
+(or 0 if the file is larger than 1MB) will prevent reading from standard input.</li>
+<li><b>QUOTED_FIELDS_AS_STRING</b>=YES/NO (default NO). Only used if AUTODETECT_TYPE=YES.
+Whether to enforce quoted fields as string fields when set to YES. Otherwise,
+by default, the content of quoted fields will be tested for real, integer, etc...
+data types.</li>
+</ul>
+
 <h2>Creation Issues</h2>
 
 <p>The driver supports creating new databases (as a directory
@@ -196,9 +232,10 @@ The CSV driver can also read files whose structure is close to CSV files :
 
 <p>
 <ul>
-<li>Development of the OGR CSV driver was supported by 
+<li>Initial development of the OGR CSV driver was supported by 
 <a href="http://www.dmsolutions.ca/">DM Solutions Group</a> and 
 <a href="http://www.gomoos.org/">GoMOOS</a>.
+<li><a href="https://cartodb.com/">CartoDB</a> funded field type auto-detection.</li>
 </ul>
 </p>
 
diff --git a/ogr/ogrsf_frmts/csv/ogr_csv.h b/ogr/ogrsf_frmts/csv/ogr_csv.h
index d307fd6..f136ed6 100644
--- a/ogr/ogrsf_frmts/csv/ogr_csv.h
+++ b/ogr/ogrsf_frmts/csv/ogr_csv.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_csv.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_csv.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  CSV Translator
  * Purpose:  Definition of classes for OGR .csv driver.
@@ -44,7 +44,9 @@ typedef enum
 
 class OGRCSVDataSource;
 
-char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStrings );
+char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter,
+                             int bDontHonourStrings = FALSE,
+                             int bKeepLeadingAndClosingQuotes = FALSE);
 
 /************************************************************************/
 /*                             OGRCSVLayer                              */
@@ -73,6 +75,7 @@ class OGRCSVLayer : public OGRLayer
     int                 bWriteBOM;
     char                chDelimiter;
 
+    int                 nCSVFieldCount;
     int*                panGeomFieldIndex;
     int                 bFirstFeatureAppendedDuringSession;
     int                 bHiddenWKTColumn;
@@ -87,17 +90,27 @@ class OGRCSVLayer : public OGRLayer
     int                 bIsEurostatTSV;
     int                 nEurostatDims;
 
-    int                 nTotalFeatures;
+    GIntBig             nTotalFeatures;
+
+    char              **AutodetectFieldTypes(char** papszOpenOptions, int nFieldCount);
+    
+    int                 bWarningBadTypeOrWidth;
+    int                 bKeepSourceColumns;
+    
+    char              **GetNextLineTokens();
 
   public:
     OGRCSVLayer( const char *pszName, VSILFILE *fp, const char *pszFilename,
-                 int bNew, int bInWriteMode, char chDelimiter,
-                 const char* pszNfdcRunwaysGeomField,
-                 const char* pszGeonamesGeomFieldPrefix );
-  ~OGRCSVLayer();
+                 int bNew, int bInWriteMode, char chDelimiter );
+   ~OGRCSVLayer();
+  
+    void                BuildFeatureDefn( const char* pszNfdcGeomField = NULL,
+                                          const char* pszGeonamesGeomFieldPrefix = NULL,
+                                          char** papszOpenOptions = NULL );
 
     void                ResetReading();
     OGRFeature *        GetNextFeature();
+    virtual OGRFeature* GetFeature( GIntBig nFID );
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -108,7 +121,7 @@ class OGRCSVLayer : public OGRLayer
     virtual OGRErr      CreateGeomField( OGRGeomFieldDefn *poGeomField,
                                          int bApproxOK = TRUE );
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
     void                SetCRLF(int);
     void                SetWriteGeometry(OGRwkbGeometryType eGType,
@@ -116,7 +129,7 @@ class OGRCSVLayer : public OGRLayer
     void                SetCreateCSVT(int bCreateCSVT);
     void                SetWriteBOM(int bWriteBOM);
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
 
     OGRErr              WriteHeader();
 };
@@ -143,8 +156,10 @@ class OGRCSVDataSource : public OGRDataSource
                         ~OGRCSVDataSource();
 
     int                 Open( const char * pszFilename,
-                              int bUpdate, int bForceAccept );
+                              int bUpdate, int bForceAccept,
+                              char** papszOpenOptions = NULL );
     int                 OpenTable( const char * pszFilename,
+                                   char** papszOpenOptions,
                                    const char* pszNfdcRunwaysGeomField = NULL,
                                    const char* pszGeonamesGeomFieldPrefix = NULL);
     
@@ -153,7 +168,7 @@ class OGRCSVDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName, 
+    virtual OGRLayer   *ICreateLayer( const char *pszName, 
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
@@ -170,23 +185,4 @@ class OGRCSVDataSource : public OGRDataSource
     static CPLString    GetRealExtension(CPLString osFilename);
 };
 
-/************************************************************************/
-/*                             OGRCSVDriver                             */
-/************************************************************************/
-
-class OGRCSVDriver : public OGRSFDriver
-{
-  public:
-                ~OGRCSVDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    OGRDataSource *CreateDataSource( const char *, char ** );
-    int         TestCapability( const char * );
-
-    virtual OGRErr      DeleteDataSource( const char *pszName );
-    
-};
-
-
 #endif /* ndef _OGR_CSV_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/csv/ogrcsvdatasource.cpp b/ogr/ogrsf_frmts/csv/ogrcsvdatasource.cpp
index 1fae02e..355bc66 100644
--- a/ogr/ogrsf_frmts/csv/ogrcsvdatasource.cpp
+++ b/ogr/ogrsf_frmts/csv/ogrcsvdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcsvdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrcsvdatasource.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  CSV Translator
  * Purpose:  Implements OGRCSVDataSource class
@@ -34,7 +34,7 @@
 #include "cpl_csv.h"
 #include "cpl_vsi_virtual.h"
 
-CPL_CVSID("$Id: ogrcsvdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrcsvdatasource.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                          OGRCSVDataSource()                          */
@@ -79,6 +79,8 @@ int OGRCSVDataSource::TestCapability( const char * pszCap )
         return bUpdate;
     else if( EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
         return bUpdate && bEnableGeometryFields;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
@@ -118,7 +120,7 @@ CPLString OGRCSVDataSource::GetRealExtension(CPLString osFilename)
 /************************************************************************/
 
 int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
-                            int bForceOpen )
+                            int bForceOpen, char** papszOpenOptions )
 
 {
     pszName = CPLStrdup( pszFilename );
@@ -211,14 +213,14 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
     {
         if (EQUAL(CPLGetFilename(osFilename), "NfdcFacilities.xls"))
         {
-            return OpenTable( osFilename, "ARP");
+            return OpenTable( osFilename, papszOpenOptions, "ARP");
         }
         else if (EQUAL(CPLGetFilename(osFilename), "NfdcRunways.xls"))
         {
-            OpenTable( osFilename, "BaseEndPhysical");
-            OpenTable( osFilename, "BaseEndDisplaced");
-            OpenTable( osFilename, "ReciprocalEndPhysical");
-            OpenTable( osFilename, "ReciprocalEndDisplaced");
+            OpenTable( osFilename, papszOpenOptions, "BaseEndPhysical");
+            OpenTable( osFilename, papszOpenOptions, "BaseEndDisplaced");
+            OpenTable( osFilename, papszOpenOptions, "ReciprocalEndPhysical");
+            OpenTable( osFilename, papszOpenOptions, "ReciprocalEndDisplaced");
             return nLayers != 0;
         }
         else if (bUSGeonamesFile)
@@ -229,22 +231,22 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
                 EQUALN(osBaseFilename, "ANTARCTICA_", 11) ||
                 (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_FedCodes_", 10)))
             {
-                OpenTable( osFilename, NULL, "PRIMARY");
+                OpenTable( osFilename, papszOpenOptions, NULL, "PRIMARY");
             }
             else if (EQUALN(osBaseFilename, "GOVT_UNITS_", 11) ||
                      EQUALN(osBaseFilename, "Feature_Description_History_", 28))
             {
-                OpenTable( osFilename, NULL, "");
+                OpenTable( osFilename, papszOpenOptions, NULL, "");
             }
             else
             {
-                OpenTable( osFilename, NULL, "PRIM");
-                OpenTable( osFilename, NULL, "SOURCE");
+                OpenTable( osFilename, papszOpenOptions, NULL, "PRIM");
+                OpenTable( osFilename, papszOpenOptions, NULL, "SOURCE");
             }
             return nLayers != 0;
         }
 
-        return OpenTable( osFilename );
+        return OpenTable( osFilename, papszOpenOptions );
     }
 
 /* -------------------------------------------------------------------- */
@@ -263,7 +265,7 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
         }
         osFilename = CPLFormFilename(osFilename, papszFiles[0], NULL);
         CSLDestroy(papszFiles);
-        return OpenTable( osFilename );
+        return OpenTable( osFilename, papszOpenOptions );
     }
 
 /* -------------------------------------------------------------------- */
@@ -298,7 +300,7 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
 
         if (EQUAL(CPLGetExtension(oSubFilename),"csv"))
         {
-            if( !OpenTable( oSubFilename ) )
+            if( !OpenTable( oSubFilename, papszOpenOptions ) )
             {
                 CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str());
                 nNotCSVCount++;
@@ -311,8 +313,8 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
                   EQUALN(papszNames[i]+2, "_Features_", 10) &&
                   EQUAL(CPLGetExtension(papszNames[i]), "txt") )
         {
-            int bRet = OpenTable( oSubFilename, NULL, "PRIM");
-            bRet |= OpenTable( oSubFilename, NULL, "SOURCE");
+            int bRet = OpenTable( oSubFilename, papszOpenOptions, NULL, "PRIM");
+            bRet |= OpenTable( oSubFilename, papszOpenOptions, NULL, "SOURCE");
             if ( !bRet )
             {
                 CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str());
@@ -325,7 +327,7 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
                   EQUALN(papszNames[i]+2, "_FedCodes_", 10) &&
                   EQUAL(CPLGetExtension(papszNames[i]), "txt") )
         {
-            if ( !OpenTable( oSubFilename, NULL, "PRIMARY") )
+            if ( !OpenTable( oSubFilename, papszOpenOptions, NULL, "PRIMARY") )
             {
                 CPLDebug("CSV", "Cannot open %s", oSubFilename.c_str());
                 nNotCSVCount++;
@@ -353,6 +355,7 @@ int OGRCSVDataSource::Open( const char * pszFilename, int bUpdateIn,
 /************************************************************************/
 
 int OGRCSVDataSource::OpenTable( const char * pszFilename,
+                                 char** papszOpenOptions,
                                  const char* pszNfdcRunwaysGeomField,
                                  const char* pszGeonamesGeomFieldPrefix)
 
@@ -455,21 +458,22 @@ int OGRCSVDataSource::OpenTable( const char * pszFilename,
         osLayerName = "layer";
     papoLayers[nLayers-1] = 
         new OGRCSVLayer( osLayerName, fp, pszFilename, FALSE, bUpdate,
-                         chDelimiter, pszNfdcRunwaysGeomField, pszGeonamesGeomFieldPrefix );
-
+                         chDelimiter  );
+    papoLayers[nLayers-1]->BuildFeatureDefn( pszNfdcRunwaysGeomField,
+                                             pszGeonamesGeomFieldPrefix,
+                                             papszOpenOptions );
     return TRUE;
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRCSVDataSource::CreateLayer( const char *pszLayerName, 
-                               CPL_UNUSED OGRSpatialReference *poSpatialRef,
-                               OGRwkbGeometryType eGType,
-                               char ** papszOptions  )
-
+OGRCSVDataSource::ICreateLayer( const char *pszLayerName,
+                                CPL_UNUSED OGRSpatialReference *poSpatialRef,
+                                OGRwkbGeometryType eGType,
+                                char ** papszOptions  )
 {
 /* -------------------------------------------------------------------- */
 /*      Verify we are in update mode.                                   */
@@ -558,7 +562,8 @@ OGRCSVDataSource::CreateLayer( const char *pszLayerName,
                                              sizeof(void*) * nLayers);
     
     papoLayers[nLayers-1] = new OGRCSVLayer( pszLayerName, NULL, osFilename,
-                                             TRUE, TRUE, chDelimiter, NULL, NULL );
+                                             TRUE, TRUE, chDelimiter );
+    papoLayers[nLayers-1]->BuildFeatureDefn();
 
 /* -------------------------------------------------------------------- */
 /*      Was a partiuclar CRLF order requested?                          */
diff --git a/ogr/ogrsf_frmts/csv/ogrcsvdriver.cpp b/ogr/ogrsf_frmts/csv/ogrcsvdriver.cpp
index ed47887..b3d316e 100644
--- a/ogr/ogrsf_frmts/csv/ogrcsvdriver.cpp
+++ b/ogr/ogrsf_frmts/csv/ogrcsvdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcsvdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrcsvdriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  CSV Translator
  * Purpose:  Implements OGRCSVDriver.
@@ -31,37 +31,89 @@
 #include "ogr_csv.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrcsvdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrcsvdriver.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
-/*                           ~OGRCSVDriver()                            */
+/*                         OGRCSVDriverIdentify()                       */
 /************************************************************************/
 
-OGRCSVDriver::~OGRCSVDriver()
+static int OGRCSVDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRCSVDriver::GetName()
+    if( poOpenInfo->fpL != NULL )
+    {
+        CPLString osBaseFilename = CPLGetFilename(poOpenInfo->pszFilename);
+        CPLString osExt = OGRCSVDataSource::GetRealExtension(poOpenInfo->pszFilename);
 
-{
-    return "CSV";
+        if (EQUAL(osBaseFilename, "NfdcFacilities.xls") ||
+            EQUAL(osBaseFilename, "NfdcRunways.xls") ||
+            EQUAL(osBaseFilename, "NfdcRemarks.xls") ||
+            EQUAL(osBaseFilename, "NfdcSchedules.xls"))
+        {
+            return TRUE;
+        }
+        else if ((EQUALN(osBaseFilename, "NationalFile_", 13) ||
+              EQUALN(osBaseFilename, "POP_PLACES_", 11) ||
+              EQUALN(osBaseFilename, "HIST_FEATURES_", 14) ||
+              EQUALN(osBaseFilename, "US_CONCISE_", 11) ||
+              EQUALN(osBaseFilename, "AllNames_", 9) ||
+              EQUALN(osBaseFilename, "Feature_Description_History_", 28) ||
+              EQUALN(osBaseFilename, "ANTARCTICA_", 11) ||
+              EQUALN(osBaseFilename, "GOVT_UNITS_", 11) ||
+              EQUALN(osBaseFilename, "NationalFedCodes_", 17) ||
+              EQUALN(osBaseFilename, "AllStates_", 10) ||
+              EQUALN(osBaseFilename, "AllStatesFedCodes_", 18) ||
+              (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_Features_", 10)) ||
+              (strlen(osBaseFilename) > 2 && EQUALN(osBaseFilename+2, "_FedCodes_", 10))) &&
+             (EQUAL(osExt, "txt") || EQUAL(osExt, "zip")) )
+        {
+            return TRUE;
+        }
+        else if (EQUAL(osBaseFilename, "allCountries.txt") ||
+             EQUAL(osBaseFilename, "allCountries.zip"))
+        {
+            return TRUE;
+        }
+        else if (EQUAL(osExt,"csv") || EQUAL(osExt,"tsv"))
+        {
+            return TRUE;
+        }
+        else if (strncmp(poOpenInfo->pszFilename, "/vsizip/", 8) == 0 &&
+                 EQUAL(osExt,"zip"))
+        {
+            return -1; /* unsure */
+        }
+        else
+        {
+            return FALSE;
+        }
+    }
+    else if( EQUALN(poOpenInfo->pszFilename, "CSV:", 4) )
+    {
+        return TRUE;
+    }
+    else if ( poOpenInfo->bIsDirectory )
+    {
+        return -1; /* unsure */
+    }
+    else
+        return FALSE;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRCSVDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRCSVDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( OGRCSVDriverIdentify(poOpenInfo) == FALSE )
+        return NULL;
+
     OGRCSVDataSource   *poDS = new OGRCSVDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, FALSE ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update, FALSE,
+                     poOpenInfo->papszOpenOptions ) )
     {
         delete poDS;
         poDS = NULL;
@@ -71,12 +123,15 @@ OGRDataSource *OGRCSVDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRCSVDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRCSVDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      First, ensure there isn't any such file yet.                    */
@@ -88,7 +143,7 @@ OGRDataSource *OGRCSVDriver::CreateDataSource( const char * pszName,
 
     if( VSIStatL( pszName, &sStatBuf ) == 0 )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
+        CPLError( CE_Failure, CPLE_AppDefined,
                   "It seems a file system object called '%s' already exists.",
                   pszName );
 
@@ -151,31 +206,16 @@ OGRDataSource *OGRCSVDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRCSVDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                              Delete()                                */
 /************************************************************************/
 
-OGRErr OGRCSVDriver::DeleteDataSource( const char *pszFilename )
+static CPLErr OGRCSVDriverDelete( const char *pszFilename )
 
 {
     if( CPLUnlinkTree( pszFilename ) == 0 )
-        return OGRERR_NONE;
+        return CE_None;
     else
-        return OGRERR_FAILURE;
+        return CE_Failure;
 }
 
 /************************************************************************/
@@ -185,6 +225,74 @@ OGRErr OGRCSVDriver::DeleteDataSource( const char *pszFilename )
 void RegisterOGRCSV()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRCSVDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "CSV" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "CSV" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Comma Separated Value (.csv)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "csv" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_csv.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='GEOMETRY' type='string-select' description='how to encode geometry fields'>"
+"    <Value>AS_WKT</Value>"
+"  </Option>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='SEPARATOR' type='string-select' description='field separator' default='COMMA'>"
+"    <Value>COMMA</Value>"
+"    <Value>SEMICOLON</Value>"
+"    <Value>TAB</Value>"
+"  </Option>"
+#ifdef WIN32
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='CRLF'>"
+#else
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='LF'>"
+#endif
+"    <Value>CRLF</Value>"
+"    <Value>LF</Value>"
+"  </Option>"
+"  <Option name='GEOMETRY' type='string-select' description='how to encode geometry fields'>"
+"    <Value>AS_WKT</Value>"
+"    <Value>AS_XYZ</Value>"
+"    <Value>AS_XY</Value>"
+"    <Value>AS_YX</Value>"
+"  </Option>"
+"  <Option name='CREATE_CSVT' type='boolean' description='whether to create a .csvt file' default='NO'/>"
+"  <Option name='WRITE_BOM' type='boolean' description='whether to write a UTF-8 BOM prefix' default='NO'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='AUTODETECT_TYPE' type='boolean' description='whether to guess data type from first bytes of the file' default='NO'/>"
+"  <Option name='KEEP_SOURCE_COLUMNS' type='boolean' description='whether to add original columns whose guessed data type is not String. Only used if AUTODETECT_TYPE=YES' default='NO'/>"
+"  <Option name='AUTODETECT_WIDTH' type='string-select' description='whether to auto-detect width/precision. Only used if AUTODETECT_TYPE=YES' default='NO'>"
+"    <Value>YES</Value>"
+"    <Value>NO</Value>"
+"    <Value>STRING_ONLY</Value>"
+"  </Option>"
+"  <Option name='AUTODETECT_SIZE_LIMIT' type='int' description='number of bytes to inspect for auto-detection of data type. Only used if AUTODETECT_TYPE=YES' default='1000000'/>"
+"  <Option name='QUOTED_FIELDS_AS_STRING' type='boolean' description='Only used if AUTODETECT_TYPE=YES. Whether to enforce quoted fields as string fields.' default='NO'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time" );
+
+        poDriver->pfnOpen = OGRCSVDriverOpen;
+        poDriver->pfnIdentify = OGRCSVDriverIdentify;
+        poDriver->pfnCreate = OGRCSVDriverCreate;
+        poDriver->pfnDelete = OGRCSVDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp b/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp
index 820c035..270f305 100644
--- a/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp
+++ b/ogr/ogrsf_frmts/csv/ogrcsvlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrcsvlayer.cpp 27748 2014-09-28 12:05:20Z rouault $
+ * $Id: ogrcsvlayer.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  CSV Translator
  * Purpose:  Implements OGRCSVLayer class.
@@ -34,7 +34,7 @@
 #include "cpl_csv.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrcsvlayer.cpp 27748 2014-09-28 12:05:20Z rouault $");
+CPL_CVSID("$Id: ogrcsvlayer.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 
 
@@ -47,7 +47,8 @@ CPL_CVSID("$Id: ogrcsvlayer.cpp 27748 2014-09-28 12:05:20Z rouault $");
 /*      semantics.                                                      */
 /************************************************************************/
 
-static char **CSVSplitLine( const char *pszString, char chDelimiter )
+static char **CSVSplitLine( const char *pszString, char chDelimiter,
+                            int bKeepLeadingAndClosingQuotes )
 
 {
     char        **papszRetList = NULL;
@@ -79,7 +80,8 @@ static char **CSVSplitLine( const char *pszString, char chDelimiter )
                 if( !bInString || pszString[1] != '"' )
                 {
                     bInString = !bInString;
-                    continue;
+                    if( !bKeepLeadingAndClosingQuotes )
+                        continue;
                 }
                 else  /* doubled quotes in string resolve to one quote */
                 {
@@ -124,7 +126,9 @@ static char **CSVSplitLine( const char *pszString, char chDelimiter )
 /*      result is a stringlist, in the sense of the CSL functions.      */
 /************************************************************************/
 
-char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStrings )
+char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter,
+                             int bDontHonourStrings,
+                             int bKeepLeadingAndClosingQuotes )
 
 {
     const char  *pszLine;
@@ -151,7 +155,7 @@ char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStr
 /*      Parse, and return tokens.                                       */
 /* -------------------------------------------------------------------- */
     if( strchr(pszLine,'\"') == NULL )
-        return CSVSplitLine( pszLine, chDelimiter );
+        return CSVSplitLine( pszLine, chDelimiter, bKeepLeadingAndClosingQuotes );
 
 /* -------------------------------------------------------------------- */
 /*      We must now count the quotes in our working string, and as      */
@@ -191,7 +195,7 @@ char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStr
         nWorkLineLength += nLineLen + 1;
     }
 
-    papszReturn = CSVSplitLine( pszWorkLine, chDelimiter );
+    papszReturn = CSVSplitLine( pszWorkLine, chDelimiter, bKeepLeadingAndClosingQuotes );
 
     CPLFree( pszWorkLine );
 
@@ -206,16 +210,18 @@ char **OGRCSVReadParseLineL( VSILFILE * fp, char chDelimiter, int bDontHonourStr
 /************************************************************************/
 
 OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn, 
-                          VSILFILE * fp, const char *pszFilename, int bNew, int bInWriteMode,
-                          char chDelimiter, const char* pszNfdcGeomField,
-                          const char* pszGeonamesGeomFieldPrefix)
+                          VSILFILE * fp, const char *pszFilename,
+                          int bNew, int bInWriteMode,
+                          char chDelimiter )
 
 {
     fpCSV = fp;
 
+    nCSVFieldCount = 0;
     panGeomFieldIndex = NULL;
     iNfdcLatitudeS = iNfdcLongitudeS = -1;
     iLatitudeField = iLongitudeField = -1;
+    bHasFieldNames = FALSE;
     this->bInWriteMode = bInWriteMode;
     this->bNew = bNew;
     this->pszFilename = CPLStrdup(pszFilename);
@@ -230,6 +236,7 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
     nNextFID = 1;
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerNameIn );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone );
 
@@ -241,6 +248,18 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
     nEurostatDims = 0;
 
     nTotalFeatures = -1;
+    bWarningBadTypeOrWidth = FALSE;
+    bKeepSourceColumns = FALSE;
+}
+
+/************************************************************************/
+/*                      BuildFeatureDefn()                              */
+/************************************************************************/
+
+void OGRCSVLayer::BuildFeatureDefn( const char* pszNfdcGeomField,
+                                    const char* pszGeonamesGeomFieldPrefix,
+                                    char** papszOpenOptions )
+{
 
 /* -------------------------------------------------------------------- */
 /*      If this is not a new file, read ahead to establish if it is     */
@@ -270,7 +289,6 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 /* -------------------------------------------------------------------- */
     char **papszTokens = NULL;
     int nFieldCount=0, iField;
-    CPLValueType eType;
 
     if( !bNew )
     {
@@ -290,7 +308,7 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
             }
 
             /* tokenize the strings and preserve quotes, so we can separate string from numeric */
-            /* this is only used in the test for bHasFeldNames (bug #4361) */
+            /* this is only used in the test for bHasFieldNames (bug #4361) */
             papszTokens = CSLTokenizeString2( pszLine, szDelimiter, 
                                               (CSLT_HONOURSTRINGS |
                                                CSLT_ALLOWEMPTYTOKENS |
@@ -300,7 +318,7 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 
             for( iField = 0; iField < nFieldCount && bHasFieldNames; iField++ )
             {
-                eType = CPLGetValueType(papszTokens[iField]);
+                CPLValueType eType = CPLGetValueType(papszTokens[iField]);
                 if ( (eType == CPL_VALUE_INTEGER ||
                       eType == CPL_VALUE_REAL) ) {
                     /* we have a numeric field, therefore do not consider the first line as field names */
@@ -330,8 +348,10 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
     else
         bHasFieldNames = FALSE;
 
-    if( !bNew && !bHasFieldNames )
-        VSIRewindL( fpCSV );
+    if( !bNew )
+        ResetReading();
+ 
+    nCSVFieldCount = nFieldCount;
     
     panGeomFieldIndex = (int*) CPLCalloc(nFieldCount, sizeof(int));
     for( iField = 0; iField < nFieldCount; iField++ )
@@ -400,11 +420,11 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 /* -------------------------------------------------------------------- */
     char** papszFieldTypes = NULL;
     if (!bNew) {
-        char* dname = strdup(CPLGetDirname(pszFilename));
-        char* fname = strdup(CPLGetBasename(pszFilename));
+        char* dname = CPLStrdup(CPLGetDirname(pszFilename));
+        char* fname = CPLStrdup(CPLGetBasename(pszFilename));
         VSILFILE* fpCSVT = VSIFOpenL(CPLFormFilename(dname, fname, ".csvt"), "r");
-        free(dname);
-        free(fname);
+        CPLFree(dname);
+        CPLFree(fname);
         if (fpCSVT!=NULL) {
             VSIRewindL(fpCSVT);
             papszFieldTypes = OGRCSVReadParseLineL(fpCSVT, ',', FALSE);
@@ -413,6 +433,21 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
     }
 
 /* -------------------------------------------------------------------- */
+/*      Optionaly auto-detect types                                     */
+/* -------------------------------------------------------------------- */
+    if( !bNew && papszFieldTypes == NULL &&
+        CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions,
+                                                     "AUTODETECT_TYPE", "NO")) )
+    {
+        papszFieldTypes = AutodetectFieldTypes(papszOpenOptions, nFieldCount);
+        if( papszFieldTypes != NULL )
+        {
+            bKeepSourceColumns = CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions,
+                                                     "KEEP_SOURCE_COLUMNS", "NO"));
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Build field definitions.                                        */
 /* -------------------------------------------------------------------- */
     for( iField = 0; !bIsEurostatTSV && iField < nFieldCount; iField++ )
@@ -442,7 +477,7 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
             /* in the header line */
             if( iField == 1 && nFieldCount == 2 && papszTokens[1][0] == '\0' )
             {
-                nFieldCount = 1;
+                nCSVFieldCount = nFieldCount = 1;
                 break;
             }
             pszFieldName = szFieldNameBuffer;
@@ -451,43 +486,63 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 
         OGRFieldDefn oField(pszFieldName, OFTString);
         if (papszFieldTypes!=NULL && iField<CSLCount(papszFieldTypes)) {
-
-            char* pszLeftParenthesis = strchr(papszFieldTypes[iField], '(');
-            if (pszLeftParenthesis && pszLeftParenthesis != papszFieldTypes[iField] &&
-                pszLeftParenthesis[1] >= '0' && pszLeftParenthesis[1] <= '9')
+            if (EQUAL(papszFieldTypes[iField], "Integer(Boolean)"))
+            {
+                oField.SetType(OFTInteger);
+                oField.SetSubType(OFSTBoolean);
+                oField.SetWidth(1);
+            }
+            else if (EQUAL(papszFieldTypes[iField], "Integer(Int16)"))
+            {
+                oField.SetType(OFTInteger);
+                oField.SetSubType(OFSTInt16);
+            }
+            else if (EQUAL(papszFieldTypes[iField], "Real(Float32)"))
             {
-                int nWidth = 0;
-                int nPrecision = 0;
+                oField.SetType(OFTReal);
+                oField.SetSubType(OFSTFloat32);
+            }
+            else
+            {
+                char* pszLeftParenthesis = strchr(papszFieldTypes[iField], '(');
+                if (pszLeftParenthesis && pszLeftParenthesis != papszFieldTypes[iField] &&
+                    pszLeftParenthesis[1] >= '0' && pszLeftParenthesis[1] <= '9')
+                {
+                    int nWidth = 0;
+                    int nPrecision = 0;
 
-                char* pszDot = strchr(pszLeftParenthesis, '.');
-                if (pszDot) *pszDot = 0;
-                *pszLeftParenthesis = 0;
+                    char* pszDot = strchr(pszLeftParenthesis, '.');
+                    if (pszDot) *pszDot = 0;
+                    *pszLeftParenthesis = 0;
 
-                if (pszLeftParenthesis[-1] == ' ')
-                    pszLeftParenthesis[-1] = 0;
+                    if (pszLeftParenthesis[-1] == ' ')
+                        pszLeftParenthesis[-1] = 0;
 
-                nWidth = atoi(pszLeftParenthesis+1);
-                if (pszDot)
-                    nPrecision = atoi(pszDot+1);
+                    nWidth = atoi(pszLeftParenthesis+1);
+                    if (pszDot)
+                        nPrecision = atoi(pszDot+1);
 
-                oField.SetWidth(nWidth);
-                oField.SetPrecision(nPrecision);
-            }
+                    oField.SetWidth(nWidth);
+                    oField.SetPrecision(nPrecision);
+                }
 
-            if (EQUAL(papszFieldTypes[iField], "Integer"))
-                oField.SetType(OFTInteger);
-            else if (EQUAL(papszFieldTypes[iField], "Real"))
-                oField.SetType(OFTReal);
-            else if (EQUAL(papszFieldTypes[iField], "String"))
-                oField.SetType(OFTString);
-            else if (EQUAL(papszFieldTypes[iField], "Date"))
-                oField.SetType(OFTDate); 
-            else if (EQUAL(papszFieldTypes[iField], "Time"))
-                oField.SetType(OFTTime);
-            else if (EQUAL(papszFieldTypes[iField], "DateTime"))
-                oField.SetType(OFTDateTime);
-            else
-                CPLError(CE_Warning, CPLE_NotSupported, "Unknown type : %s", papszFieldTypes[iField]);
+                if (EQUAL(papszFieldTypes[iField], "Integer"))
+                    oField.SetType(OFTInteger);
+                else if (EQUAL(papszFieldTypes[iField], "Integer64"))
+                    oField.SetType(OFTInteger64);
+                else if (EQUAL(papszFieldTypes[iField], "Real"))
+                    oField.SetType(OFTReal);
+                else if (EQUAL(papszFieldTypes[iField], "String"))
+                    oField.SetType(OFTString);
+                else if (EQUAL(papszFieldTypes[iField], "Date"))
+                    oField.SetType(OFTDate); 
+                else if (EQUAL(papszFieldTypes[iField], "Time"))
+                    oField.SetType(OFTTime);
+                else if (EQUAL(papszFieldTypes[iField], "DateTime"))
+                    oField.SetType(OFTDateTime);
+                else
+                    CPLError(CE_Warning, CPLE_NotSupported, "Unknown type : %s", papszFieldTypes[iField]);
+            }
         }
 
         if( (EQUAL(oField.GetNameRef(),"WKT") ||
@@ -502,7 +557,7 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
                 EQUAL(pszFieldName,"WKT") ? "" : CPLSPrintf("geom_%s", pszFieldName),
                 wkbUnknown );
 
-            /* Usefull hack for RFC 41 testing */
+            /* Useful hack for RFC 41 testing */
             const char* pszEPSG = strstr(pszFieldName, "_EPSG_");
             if( pszEPSG != NULL )
             {
@@ -561,6 +616,11 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 
         poFeatureDefn->AddFieldDefn( &oField );
 
+        if( bKeepSourceColumns && oField.GetType() != OFTString )
+        {
+            OGRFieldDefn oFieldOriginal( CPLSPrintf("%s_original", oField.GetNameRef()), OFTString);
+            poFeatureDefn->AddFieldDefn( &oFieldOriginal );
+        }
     }
 
     if ( iNfdcLatitudeS != -1 && iNfdcLongitudeS != -1 )
@@ -616,6 +676,325 @@ OGRCSVLayer::OGRCSVLayer( const char *pszLayerNameIn,
 }
 
 /************************************************************************/
+/*                             OGRCSVIsTrue()                           */
+/************************************************************************/
+
+static int OGRCSVIsTrue(const char* pszStr)
+{
+    return EQUAL(pszStr, "t") || EQUAL(pszStr, "true") || EQUAL(pszStr, "y") ||
+           EQUAL(pszStr, "yes") || EQUAL(pszStr, "on");
+}
+
+/************************************************************************/
+/*                            OGRCSVIsFalse()                           */
+/************************************************************************/
+
+static int OGRCSVIsFalse(const char* pszStr)
+{
+    return EQUAL(pszStr, "f") || EQUAL(pszStr, "false") || EQUAL(pszStr, "n") ||
+           EQUAL(pszStr, "no") || EQUAL(pszStr, "off");
+}
+
+/************************************************************************/
+/*                        AutodetectFieldTypes()                        */
+/************************************************************************/
+
+char** OGRCSVLayer::AutodetectFieldTypes(char** papszOpenOptions, int nFieldCount)
+{
+    int iField;
+    char** papszFieldTypes = NULL;
+
+    /* Use 1000000 as default maximum distance to be compatible with /vsistdin/ */
+    /* caching */
+    int nBytes = atoi(CSLFetchNameValueDef(papszOpenOptions,
+                                            "AUTODETECT_SIZE_LIMIT", "1000000"));
+    if( nBytes == 0 )
+    {
+        vsi_l_offset nCurPos = VSIFTellL(fpCSV);
+        VSIFSeekL(fpCSV, 0, SEEK_END);
+        vsi_l_offset nFileSize = VSIFTellL(fpCSV);
+        VSIFSeekL(fpCSV, nCurPos, SEEK_SET);
+        if( nFileSize < INT_MAX )
+            nBytes = (int)nFileSize;
+        else
+            nBytes = INT_MAX;
+    }
+    else if( nBytes < 0 || (vsi_l_offset)nBytes < VSIFTellL(fpCSV) )
+        nBytes = 1000000;
+
+    const char* pszAutodetectWidth = CSLFetchNameValueDef(papszOpenOptions,
+                                                          "AUTODETECT_WIDTH", "NO");
+    int bAutodetectWidth = FALSE;
+    int bAutodetectWidthForIntOrReal = FALSE;
+    if( EQUAL(pszAutodetectWidth, "YES") )
+        bAutodetectWidth = bAutodetectWidthForIntOrReal = TRUE;
+    else if( EQUAL(pszAutodetectWidth, "STRING_ONLY") )
+        bAutodetectWidth = TRUE;
+
+    int bQuotedFieldAsString = CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions,
+                                                      "QUOTED_FIELDS_AS_STRING", "NO"));
+
+    char* pszData = (char*) VSIMalloc( nBytes );
+    if( pszData != NULL && (vsi_l_offset)nBytes > VSIFTellL(fpCSV) )
+    {
+        int nRequested = nBytes - 1 - (int)VSIFTellL(fpCSV);
+        int nRead = VSIFReadL(pszData, 1, nRequested, fpCSV);
+        pszData[nRead] = 0;
+
+        CPLString osTmpMemFile(CPLSPrintf("/vsimem/tmp%p", this));
+        VSILFILE* fpMem = VSIFileFromMemBuffer( osTmpMemFile,
+                                                (GByte*)pszData,
+                                                nRead,
+                                                FALSE );
+
+        std::vector<OGRFieldType> aeFieldType;
+        std::vector<int> abFieldBoolean;
+        std::vector<int> abFieldSet;
+        std::vector<int> anFieldWidth;
+        std::vector<int> anFieldPrecision;
+        aeFieldType.resize(nFieldCount);
+        abFieldBoolean.resize(nFieldCount);
+        abFieldSet.resize(nFieldCount);
+        anFieldWidth.resize(nFieldCount);
+        anFieldPrecision.resize(nFieldCount);
+        int nStringFieldCount = 0;
+
+        while( !VSIFEofL(fpMem) )
+        {
+            char** papszTokens = OGRCSVReadParseLineL( fpMem, chDelimiter, FALSE,
+                                                       bQuotedFieldAsString );
+            /* Can happen if we just reach EOF while trying to read new bytes */
+            if( papszTokens == NULL )
+                break;
+
+            /* Ignore last line if it is truncated */
+            if( VSIFEofL(fpMem) && nRead == nRequested &&
+                pszData[nRead-1] != 13 && pszData[nRead-1] != 10 )
+            {
+                CSLDestroy(papszTokens);
+                break;
+            }
+
+            for( iField = 0; papszTokens[iField] != NULL &&
+                             iField < nFieldCount; iField++ )
+            {
+                int nFieldWidth = 0, nFieldPrecision = 0;
+
+                if( papszTokens[iField][0] == 0 )
+                    continue;
+                if (chDelimiter == ';')
+                {
+                    char* chComma = strchr(papszTokens[iField], ',');
+                    if (chComma)
+                        *chComma = '.';
+                }
+                CPLValueType eType = CPLGetValueType(papszTokens[iField]);
+
+                if( bAutodetectWidth )
+                {
+                    nFieldWidth = strlen(papszTokens[iField]);
+                    if( papszTokens[iField][0] == '"' && 
+                        papszTokens[iField][nFieldWidth-1] == '"' )
+                    {
+                        nFieldWidth -= 2;
+                    }
+                    if( eType == CPL_VALUE_REAL && bAutodetectWidthForIntOrReal )
+                    {
+                        const char* pszDot = strchr(papszTokens[iField], '.');
+                        if( pszDot != NULL )
+                            nFieldPrecision = strlen(pszDot + 1);
+                    }
+                }
+
+                OGRFieldType eOGRFieldType;
+                int bIsBoolean = FALSE;
+                if( eType == CPL_VALUE_INTEGER )
+                {
+                    GIntBig nVal = CPLAtoGIntBig(papszTokens[iField]);
+                    if( (GIntBig)(int)nVal != nVal )
+                        eOGRFieldType = OFTInteger64;
+                    else
+                        eOGRFieldType = OFTInteger;
+                }
+                else if( eType == CPL_VALUE_REAL )
+                {
+                    eOGRFieldType = OFTReal;
+                }
+                else if( abFieldSet[iField] && aeFieldType[iField] == OFTString )
+                {
+                    eOGRFieldType = OFTString;
+                    if( abFieldBoolean[iField] )
+                    {
+                        abFieldBoolean[iField] = OGRCSVIsTrue(papszTokens[iField]) ||
+                                                 OGRCSVIsFalse(papszTokens[iField]);
+                    }
+                }
+                else
+                {
+                    OGRField sWrkField;
+                    CPLPushErrorHandler(CPLQuietErrorHandler);
+                    int bSuccess = OGRParseDate( papszTokens[iField], &sWrkField, 0 );
+                    CPLPopErrorHandler();
+                    CPLErrorReset();
+                    if( bSuccess )
+                    {
+                        int bHasDate = strchr( papszTokens[iField], '/' ) != NULL ||
+                                       strchr( papszTokens[iField], '-' ) != NULL;
+                        int bHasTime = strchr( papszTokens[iField], ':' ) != NULL;
+                        if( bHasDate && bHasTime )
+                            eOGRFieldType = OFTDateTime;
+                        else if( bHasDate )
+                            eOGRFieldType = OFTDate;
+                        else
+                            eOGRFieldType = OFTTime;
+                    }
+                    else
+                    {
+                        eOGRFieldType = OFTString;
+                        bIsBoolean = OGRCSVIsTrue(papszTokens[iField]) ||
+                                     OGRCSVIsFalse(papszTokens[iField]);
+                    }
+                }
+
+                if( !abFieldSet[iField] )
+                {
+                    aeFieldType[iField] = eOGRFieldType;
+                    abFieldSet[iField] = TRUE;
+                    abFieldBoolean[iField] = bIsBoolean;
+                    if( eOGRFieldType == OFTString && !bIsBoolean )
+                        nStringFieldCount ++;
+                }
+                else if( aeFieldType[iField] != eOGRFieldType )
+                {
+                    /* Promotion rules */
+                    if( aeFieldType[iField] == OFTInteger )
+                    {
+                        if( eOGRFieldType == OFTInteger64 ||
+                            eOGRFieldType == OFTReal )
+                            aeFieldType[iField] = eOGRFieldType;
+                        else
+                        {
+                            aeFieldType[iField] = OFTString;
+                            nStringFieldCount ++;
+                        }
+                    }
+                    else if( aeFieldType[iField] == OFTInteger64 )
+                    {
+                        if( eOGRFieldType == OFTReal )
+                            aeFieldType[iField] = eOGRFieldType;
+                        else if( eOGRFieldType != OFTInteger )
+                        {
+                            aeFieldType[iField] = OFTString;
+                            nStringFieldCount ++;
+                        }
+                    } 
+                    else if ( aeFieldType[iField] == OFTReal )
+                    {
+                        if( eOGRFieldType != OFTInteger &&
+                            eOGRFieldType != OFTReal )
+                        {
+                            aeFieldType[iField] = OFTString;
+                            nStringFieldCount ++;
+                        }
+                    }
+                    else if( aeFieldType[iField] == OFTDate )
+                    {
+                        if( eOGRFieldType == OFTDateTime )
+                            aeFieldType[iField] = OFTDateTime;
+                        else
+                        {
+                            aeFieldType[iField] = OFTString;
+                            nStringFieldCount ++;
+                        }
+                    }
+                    else if( aeFieldType[iField] == OFTDateTime )
+                    {
+                        if( eOGRFieldType != OFTDate &&
+                            eOGRFieldType != OFTDateTime )
+                        {
+                            aeFieldType[iField] = OFTString;
+                            nStringFieldCount ++;
+                        }
+                    }
+                    else if( aeFieldType[iField] == OFTTime )
+                    {
+                        aeFieldType[iField] = OFTString;
+                        nStringFieldCount ++;
+                    }
+                }
+
+                if( nFieldWidth > anFieldWidth[iField] )
+                    anFieldWidth[iField] = nFieldWidth;
+                if( nFieldPrecision > anFieldPrecision[iField] )
+                    anFieldPrecision[iField] = nFieldPrecision;
+            }
+
+            CSLDestroy(papszTokens);
+
+            /* If all fields are String and we don't need to compute width, */
+            /* just stop auto-detection now */
+            if( nStringFieldCount == nFieldCount && bAutodetectWidth )
+                break;
+        }
+
+        papszFieldTypes = (char**) CPLCalloc( nFieldCount + 1, sizeof(char*) );
+        for(iField = 0; iField < nFieldCount; iField ++ )
+        {
+            CPLString osFieldType;
+            if( !abFieldSet[iField] )
+                osFieldType = "String";
+            else if( aeFieldType[iField] == OFTInteger )
+                osFieldType = "Integer";
+            else if( aeFieldType[iField] == OFTInteger64 )
+                osFieldType = "Integer64";
+            else if( aeFieldType[iField] == OFTReal )
+                osFieldType = "Real";
+            else if( aeFieldType[iField] == OFTDateTime  )
+                osFieldType = "DateTime";
+            else if( aeFieldType[iField] == OFTDate  )
+                osFieldType = "Date";
+            else if( aeFieldType[iField] == OFTTime  )
+                osFieldType = "Time";
+            else if( abFieldBoolean[iField] )
+                osFieldType = "Integer(Boolean)";
+            else
+                osFieldType = "String";
+
+            if( !abFieldBoolean[iField] )
+            {
+                if( anFieldWidth[iField] > 0 &&
+                    (aeFieldType[iField] == OFTString ||
+                    (bAutodetectWidthForIntOrReal &&
+                     (aeFieldType[iField] == OFTInteger ||
+                      aeFieldType[iField] == OFTInteger64))) )
+                {
+                    osFieldType += CPLSPrintf(" (%d)", anFieldWidth[iField]);
+                }
+                else if ( anFieldWidth[iField] > 0 &&
+                        bAutodetectWidthForIntOrReal &&
+                        aeFieldType[iField] == OFTReal )
+                {
+                    osFieldType += CPLSPrintf(" (%d.%d)", anFieldWidth[iField],
+                                            anFieldPrecision[iField]);
+                }
+            }
+
+            papszFieldTypes[iField] = CPLStrdup(osFieldType);
+        }
+
+        VSIFCloseL(fpMem);
+        VSIUnlink(osTmpMemFile);
+
+    }
+    VSIFree(pszData);
+
+    ResetReading();
+
+    return papszFieldTypes;
+}
+
+
+/************************************************************************/
 /*                            ~OGRCSVLayer()                            */
 /************************************************************************/
 
@@ -661,15 +1040,11 @@ void OGRCSVLayer::ResetReading()
 }
 
 /************************************************************************/
-/*                      GetNextUnfilteredFeature()                      */
+/*                        GetNextLineTokens()                           */
 /************************************************************************/
 
-OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
-
+char** OGRCSVLayer::GetNextLineTokens()
 {
-    if (fpCSV == NULL)
-        return NULL;
-    
 /* -------------------------------------------------------------------- */
 /*      Read the CSV record.                                            */
 /* -------------------------------------------------------------------- */
@@ -686,6 +1061,46 @@ OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
 
         CSLDestroy(papszTokens);
     }
+    return papszTokens;
+}
+
+/************************************************************************/
+/*                             GetFeature()                             */
+/************************************************************************/
+
+OGRFeature* OGRCSVLayer::GetFeature(GIntBig nFID)
+{
+    if( nFID < 1 || fpCSV == NULL )
+        return NULL;
+    if( nFID < nNextFID || bNeedRewindBeforeRead )
+        ResetReading();
+    while( nNextFID < nFID )
+    {
+        char **papszTokens = GetNextLineTokens();
+        if( papszTokens == NULL )
+            return NULL;
+        CSLDestroy(papszTokens);
+        nNextFID ++;
+    }
+    return GetNextUnfilteredFeature();
+}
+
+/************************************************************************/
+/*                      GetNextUnfilteredFeature()                      */
+/************************************************************************/
+
+OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
+
+{
+    if (fpCSV == NULL)
+        return NULL;
+    
+/* -------------------------------------------------------------------- */
+/*      Read the CSV record.                                            */
+/* -------------------------------------------------------------------- */
+    char **papszTokens = GetNextLineTokens();
+    if( papszTokens == NULL )
+        return NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Create the OGR feature.                                         */
@@ -698,11 +1113,11 @@ OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
 /*      Set attributes for any indicated attribute records.             */
 /* -------------------------------------------------------------------- */
     int         iAttr;
-    int         nAttrCount = MIN(CSLCount(papszTokens),
-                                 poFeatureDefn->GetFieldCount() );
+    int         iOGRField = 0;
+    int         nAttrCount = MIN(CSLCount(papszTokens), nCSVFieldCount );
     CPLValueType eType;
     
-    for( iAttr = 0; !bIsEurostatTSV && iAttr < nAttrCount; iAttr++)
+    for( iAttr = 0; !bIsEurostatTSV && iAttr < nAttrCount; iAttr++, iOGRField++)
     {
         int iGeom = panGeomFieldIndex[iAttr];
         if( iGeom >= 0 && papszTokens[iAttr][0] != '\0'&&
@@ -720,33 +1135,137 @@ OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
             }
         }
 
-        if( poFeatureDefn->GetFieldDefn(iAttr)->IsIgnored() )
-            continue;
-        OGRFieldType eFieldType = poFeatureDefn->GetFieldDefn(iAttr)->GetType();
-        if ( eFieldType == OFTReal || eFieldType == OFTInteger )
+        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(iOGRField);
+        OGRFieldType eFieldType = poFieldDefn->GetType();
+        OGRFieldSubType eFieldSubType = poFieldDefn->GetSubType();
+        if( eFieldType == OFTInteger && eFieldSubType == OFSTBoolean )
         {
-            if (chDelimiter == ';' && eFieldType == OFTReal)
+            if (papszTokens[iAttr][0] != '\0' && !poFieldDefn->IsIgnored() )
             {
-                char* chComma = strchr(papszTokens[iAttr], ',');
-                if (chComma)
-                    *chComma = '.';
+                if( OGRCSVIsTrue(papszTokens[iAttr]) ||
+                    strcmp(papszTokens[iAttr], "1") == 0 )
+                {
+                    poFeature->SetField( iOGRField, 1 );
+                }
+                else if( OGRCSVIsFalse(papszTokens[iAttr]) ||
+                    strcmp(papszTokens[iAttr], "0") == 0 )
+                {
+                    poFeature->SetField( iOGRField, 0 );
+                }
+                else if( !bWarningBadTypeOrWidth )
+                {
+                    bWarningBadTypeOrWidth = TRUE;
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                                "Invalid value type found in record %d for field %s. "
+                                "This warning will no longer be emitted",
+                                nNextFID, poFieldDefn->GetNameRef());
+                }
             }
-            eType = CPLGetValueType(papszTokens[iAttr]);
-            if ( (papszTokens[iAttr][0] != '\0')  &&
-                 ( eType == CPL_VALUE_INTEGER ||
-                   eType == CPL_VALUE_REAL ) )
+        }
+        else if( eFieldType == OFTReal || eFieldType == OFTInteger ||
+                 eFieldType == OFTInteger64 )
+        {
+            if (papszTokens[iAttr][0] != '\0' && !poFieldDefn->IsIgnored() )
             {
-                poFeature->SetField( iAttr, papszTokens[iAttr] );
+                if (chDelimiter == ';' && eFieldType == OFTReal)
+                {
+                    char* chComma = strchr(papszTokens[iAttr], ',');
+                    if (chComma)
+                        *chComma = '.';
+                }
+                eType = CPLGetValueType(papszTokens[iAttr]);
+                if ( eType == CPL_VALUE_INTEGER || eType == CPL_VALUE_REAL )
+                {
+                    poFeature->SetField( iOGRField, papszTokens[iAttr] );
+                    if( !bWarningBadTypeOrWidth &&
+                        (eFieldType == OFTInteger || eFieldType == OFTInteger64) && eType == CPL_VALUE_REAL )
+                    {
+                        bWarningBadTypeOrWidth = TRUE;
+                        CPLError(CE_Warning, CPLE_AppDefined,
+                                 "Invalid value type found in record %d for field %s. "
+                                 "This warning will no longer be emitted",
+                                 nNextFID, poFieldDefn->GetNameRef());
+                    }
+                    else if( !bWarningBadTypeOrWidth && poFieldDefn->GetWidth() > 0 &&
+                             (int)strlen(papszTokens[iAttr]) > poFieldDefn->GetWidth() )
+                    {
+                        bWarningBadTypeOrWidth = TRUE;
+                        CPLError(CE_Warning, CPLE_AppDefined,
+                                 "Value with a width greater than field width found in record %d for field %s. "
+                                 "This warning will no longer be emitted",
+                                 nNextFID, poFieldDefn->GetNameRef());
+                    }
+                    else if( !bWarningBadTypeOrWidth && eType == CPL_VALUE_REAL &&
+                             poFieldDefn->GetWidth() > 0)
+                    {
+                        const char* pszDot = strchr(papszTokens[iAttr], '.');
+                        int nPrecision = 0;
+                        if( pszDot != NULL )
+                            nPrecision = strlen(pszDot + 1);
+                        if( nPrecision > poFieldDefn->GetPrecision() )
+                        {
+                             bWarningBadTypeOrWidth = TRUE;
+                            CPLError(CE_Warning, CPLE_AppDefined,
+                                     "Value with a precision greater than field precision found in record %d for field %s. "
+                                     "This warning will no longer be emitted",
+                                     nNextFID, poFieldDefn->GetNameRef());
+                        }
+                    }
+                }
+                else
+                {
+                    if( !bWarningBadTypeOrWidth )
+                    {
+                        bWarningBadTypeOrWidth = TRUE;
+                        CPLError(CE_Warning, CPLE_AppDefined,
+                                    "Invalid value type found in record %d for field %s. "
+                                    "This warning will no longer be emitted",
+                                    nNextFID, poFieldDefn->GetNameRef());
+                    }
+                }
             }
         }
         else if (eFieldType != OFTString)
         {
-            if (papszTokens[iAttr][0] != '\0')
-                poFeature->SetField( iAttr, papszTokens[iAttr] );
+            if (papszTokens[iAttr][0] != '\0' && !poFieldDefn->IsIgnored())
+            {
+                poFeature->SetField( iOGRField, papszTokens[iAttr] );
+                if( !bWarningBadTypeOrWidth && !poFeature->IsFieldSet(iOGRField) )
+                {
+                    bWarningBadTypeOrWidth = TRUE;
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Invalid value type found in record %d for field %s. "
+                             "This warning will no longer be emitted",
+                             nNextFID, poFieldDefn->GetNameRef());
+                }
+            }
         }
         else
-            poFeature->SetField( iAttr, papszTokens[iAttr] );
+        {
+            if( !poFieldDefn->IsIgnored() )
+            {
+                poFeature->SetField( iOGRField, papszTokens[iAttr] );
+                if( !bWarningBadTypeOrWidth && poFieldDefn->GetWidth() > 0 &&
+                    (int)strlen(papszTokens[iAttr]) > poFieldDefn->GetWidth() )
+                {
+                    bWarningBadTypeOrWidth = TRUE;
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                                "Value with a width greater than field width found in record %d for field %s. "
+                                "This warning will no longer be emitted",
+                                nNextFID, poFieldDefn->GetNameRef());
+                }
+            }
+        }
 
+        if( bKeepSourceColumns && eFieldType != OFTString )
+        {
+            iOGRField ++;
+            if( papszTokens[iAttr][0] != '\0' &&
+                !poFeatureDefn->GetFieldDefn(iOGRField)->IsIgnored() )
+            {
+                poFeature->SetField( iOGRField, papszTokens[iAttr] );
+            }
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -801,10 +1320,10 @@ OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
          papszTokens[iNfdcLongitudeS][0] != 0 &&
          papszTokens[iNfdcLatitudeS][0] != 0)
     {
-        double dfLon = atof(papszTokens[iNfdcLongitudeS]) / 3600;
+        double dfLon = CPLAtof(papszTokens[iNfdcLongitudeS]) / 3600;
         if (strchr(papszTokens[iNfdcLongitudeS], 'W'))
             dfLon *= -1;
-        double dfLat = atof(papszTokens[iNfdcLatitudeS]) / 3600;
+        double dfLat = CPLAtof(papszTokens[iNfdcLatitudeS]) / 3600;
         if (strchr(papszTokens[iNfdcLatitudeS], 'S'))
             dfLat *= -1;
         if( !(poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored()) )
@@ -827,8 +1346,8 @@ OGRFeature * OGRCSVLayer::GetNextUnfilteredFeature()
             papszTokens[iLatitudeField][0] != '0' ||
             papszTokens[iLatitudeField][1] != '\0')
         {
-            double dfLon = atof(papszTokens[iLongitudeField]);
-            double dfLat = atof(papszTokens[iLatitudeField]);
+            double dfLon = CPLAtof(papszTokens[iLongitudeField]);
+            double dfLat = CPLAtof(papszTokens[iLatitudeField]);
             if( !(poFeatureDefn->GetGeomFieldDefn(0)->IsIgnored()) )
                 poFeature->SetGeometryDirectly( new OGRPoint(dfLon, dfLat) );
         }
@@ -889,13 +1408,15 @@ int OGRCSVLayer::TestCapability( const char * pszCap )
 
 {
     if( EQUAL(pszCap,OLCSequentialWrite) )
-        return bInWriteMode;
+        return bInWriteMode && !bKeepSourceColumns;
     else if( EQUAL(pszCap,OLCCreateField) )
         return bNew && !bHasFieldNames;
     else if( EQUAL(pszCap,OLCCreateGeomField) )
         return bNew && !bHasFieldNames && eGeometryFormat == OGR_CSV_GEOM_AS_WKT;
     else if( EQUAL(pszCap,OLCIgnoreFields) )
         return TRUE;
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
@@ -942,6 +1463,7 @@ OGRErr OGRCSVLayer::CreateField( OGRFieldDefn *poNewField, int bApproxOK )
     switch( poNewField->GetType() )
     {
       case OFTInteger:
+      case OFTInteger64:
       case OFTReal:
       case OFTString:
         // these types are OK.
@@ -969,6 +1491,7 @@ OGRErr OGRCSVLayer::CreateField( OGRFieldDefn *poNewField, int bApproxOK )
 /*      Seems ok, add to field list.                                    */
 /* -------------------------------------------------------------------- */
     poFeatureDefn->AddFieldDefn( poNewField );
+    nCSVFieldCount ++;
 
     panGeomFieldIndex = (int*) CPLRealloc(panGeomFieldIndex,
                                 sizeof(int) * poFeatureDefn->GetFieldCount());
@@ -984,7 +1507,6 @@ OGRErr OGRCSVLayer::CreateField( OGRFieldDefn *poNewField, int bApproxOK )
 
 OGRErr OGRCSVLayer::CreateGeomField( OGRGeomFieldDefn *poGeomField,
                                      CPL_UNUSED int bApproxOK )
-
 {
     if( !TestCapability(OLCCreateGeomField) )
     {
@@ -1003,6 +1525,7 @@ OGRErr OGRCSVLayer::CreateGeomField( OGRGeomFieldDefn *poGeomField,
 
     OGRFieldDefn oRegularFieldDefn( pszName, OFTString );
     poFeatureDefn->AddFieldDefn( &oRegularFieldDefn );
+    nCSVFieldCount ++;
 
     panGeomFieldIndex = (int*) CPLRealloc(panGeomFieldIndex,
                                 sizeof(int) * poFeatureDefn->GetFieldCount());
@@ -1120,18 +1643,47 @@ OGRErr OGRCSVLayer::WriteHeader()
 
             if (fpCSVT)
             {
+                int nWidth = poFeatureDefn->GetFieldDefn(iField)->GetWidth();
+                int nPrecision = poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
+
                 switch( poFeatureDefn->GetFieldDefn(iField)->GetType() )
                 {
-                  case OFTInteger:  VSIFPrintfL( fpCSVT, "%s", "Integer"); break;
-                  case OFTReal:     VSIFPrintfL( fpCSVT, "%s", "Real"); break;
+                  case OFTInteger:  
+                  {
+                      if( poFeatureDefn->GetFieldDefn(iField)->GetSubType() == OFSTBoolean )
+                      {
+                          nWidth = 0;
+                          VSIFPrintfL( fpCSVT, "%s", "Integer(Boolean)");
+                      }
+                      else if( poFeatureDefn->GetFieldDefn(iField)->GetSubType() == OFSTInt16 )
+                      {
+                          nWidth = 0;
+                          VSIFPrintfL( fpCSVT, "%s", "Integer(Int16)");
+                      }
+                      else
+                          VSIFPrintfL( fpCSVT, "%s", "Integer");
+                      break;
+                  }
+                  case OFTInteger64:
+                      VSIFPrintfL( fpCSVT, "%s", "Integer64");
+                      break;
+                  case OFTReal:
+                  {
+                      if( poFeatureDefn->GetFieldDefn(iField)->GetSubType() == OFSTFloat32 )
+                      {
+                          nWidth = 0;
+                          VSIFPrintfL( fpCSVT, "%s", "Real(Float32)");
+                      }
+                      else
+                          VSIFPrintfL( fpCSVT, "%s", "Real");
+                      break;
+                  }
                   case OFTDate:     VSIFPrintfL( fpCSVT, "%s", "Date"); break;
                   case OFTTime:     VSIFPrintfL( fpCSVT, "%s", "Time"); break;
                   case OFTDateTime: VSIFPrintfL( fpCSVT, "%s", "DateTime"); break;
                   default:          VSIFPrintfL( fpCSVT, "%s", "String"); break;
                 }
 
-                int nWidth = poFeatureDefn->GetFieldDefn(iField)->GetWidth();
-                int nPrecision = poFeatureDefn->GetFieldDefn(iField)->GetPrecision();
                 if (nWidth != 0)
                 {
                     if (nPrecision != 0)
@@ -1167,10 +1719,10 @@ OGRErr OGRCSVLayer::WriteHeader()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRCSVLayer::CreateFeature( OGRFeature *poNewFeature )
+OGRErr OGRCSVLayer::ICreateFeature( OGRFeature *poNewFeature )
 
 {
     int iField;
@@ -1320,10 +1872,6 @@ OGRErr OGRCSVLayer::CreateFeature( OGRFeature *poNewFeature )
         else if (poFeatureDefn->GetFieldDefn(iField)->GetType() == OFTReal)
         {
             pszEscaped = CPLStrdup(poNewFeature->GetFieldAsString(iField));
-            /* Use point as decimal separator */
-            char* pszComma = strchr(pszEscaped, ',');
-            if (pszComma)
-                *pszComma = '.';
         }
         else
         {
@@ -1403,7 +1951,7 @@ void OGRCSVLayer::SetWriteBOM(int bWriteBOM)
 /*                        GetFeatureCount()                             */
 /************************************************************************/
 
-int OGRCSVLayer::GetFeatureCount( int bForce )
+GIntBig OGRCSVLayer::GetFeatureCount( int bForce )
 {
     if (bInWriteMode || m_poFilterGeom != NULL || m_poAttrQuery != NULL)
         return OGRLayer::GetFeatureCount(bForce);
@@ -1420,12 +1968,11 @@ int OGRCSVLayer::GetFeatureCount( int bForce )
     nTotalFeatures = 0;
     while(TRUE)
     {
-        papszTokens = OGRCSVReadParseLineL( fpCSV, chDelimiter, bDontHonourStrings );
+        papszTokens = GetNextLineTokens();
         if( papszTokens == NULL )
             break;
 
-        if( papszTokens[0] != NULL )
-            nTotalFeatures ++;
+        nTotalFeatures ++;
 
         CSLDestroy(papszTokens);
     }
diff --git a/ogr/ogrsf_frmts/csw/GNUmakefile b/ogr/ogrsf_frmts/csw/GNUmakefile
new file mode 100644
index 0000000..ce881bf
--- /dev/null
+++ b/ogr/ogrsf_frmts/csw/GNUmakefile
@@ -0,0 +1,14 @@
+
+
+include ../../../GDALmake.opt
+
+OBJ	=	ogrcswdataset.o
+
+CPPFLAGS	:=	-I.. -I../.. -I../gml -I../wfs  $(CPPFLAGS)
+
+default:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(O_OBJ):	../wfs/ogr_wfs.h ../../swq.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/csw/drv_csw.html b/ogr/ogrsf_frmts/csw/drv_csw.html
new file mode 100644
index 0000000..776db96
--- /dev/null
+++ b/ogr/ogrsf_frmts/csw/drv_csw.html
@@ -0,0 +1,93 @@
+<html>
+<head>
+<title>CSW - OGC CSW (Catalog Service for the Web)</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>CSW - OGC CSW (Catalog Service for the Web)</h1>
+
+(GDAL/OGR >= 2.0)<p>
+
+This driver can connect to a OGC CSW service. It supports CSW 2.0.2 protocol.
+GDAL/OGR must be built with Curl support in order to the
+CSW driver to be compiled. And the GML driver should be set-up for read support
+(thus requiring GDAL/OGR to be built with Xerces or Expat support).<p>
+
+It retrieves records with Dublin Core metadata.<p>
+
+<h2>Dataset name syntax</h2>
+
+The minimal syntax to open a CSW datasource is : <i>CSW:</i> and the URL open option,
+or <i>CSW:http://path/to/CSW/endpoint</i><p>
+
+The following open options are available:
+<ul>
+<li><b>URL</b>: URL to the CSW server endpoint (if not specified in the connection string already)</li>
+<li><b>ELEMENTSETNAME</b>=brief/summary/full: Level of details of properties. Defaults to <i>full</i>.</li>
+<li><b>FULL_EXTENT_RECORDS_AS_NON_SPATIAL</b>=YES/NO: Whether records with
+(-180,-90,180,90) extent should be considered non-spatial. Defaults to NO.</li>
+<li><b>OUTPUT_SCHEMA</b>=URL : Value of outputSchema parameter, in the restricted
+set supported by the serve. Special value <i>gmd</i> can be used as a shortcut for
+http://www.isotc211.org/2005/gmd, <i>csw</i> for http://www.opengis.net/cat/csw/2.0.2.
+When this open option is set, a <i>raw_xml</i> field will be filled with the
+XML content of each record. Other metadata fields will remain empty.</li>
+<li><b>MAX_RECORDS</b>=value : Maximum number of records to retrieve in a single time.
+Defaults to 500. Servers might have a lower accepted value.</li>
+</ul>
+
+<h2>Filtering</h2>
+
+The driver will forward any spatial filter set with SetSpatialFilter() to
+the server. It also makes its best effort to do the same for attribute
+filters set with SetAttributeFilter() when possible
+(turning OGR SQL language into OGC filter description).<p>
+
+The <i>anytext</i> field can be queried to do a search in any text field. Note that
+we always return it as null content however in OGR side, to avoid duplicating information.<p>
+
+<h2>Issues</h2>
+
+Some servers do not respect EPSG axis order, in particular latitude, longitude
+order for WGS 84 geodetic coordinates, so it might be needed to specify
+the GML_INVERT_AXIS_ORDER_IF_LAT_LONG=NO configuration option in those cases.<p>
+
+<h2>Examples</h2>
+
+<li>
+Listing all the records of a CSW server:
+<pre>
+ogrinfo -ro -al -noextent CSW:http://catalog.data.gov/csw
+</pre>
+<p>
+
+<li>
+Listing all the records of a CSW server with spatial and an attribute filter on a give field:
+<pre>
+ogrinfo -ro -al -noextent CSW:http://catalog.data.gov/csw -spat 2 49 2 49 -where "subject LIKE '%mineralogy%'"
+</pre>
+<p>
+
+<li>
+Listing all the records of a CSW server that matches a text on any text field:
+<pre>
+ogrinfo -ro -al -q CSW:http://catalog.data.gov/csw -spat 2 49 2 49 -where "anytext LIKE '%France%'"
+</pre>
+<p>
+
+<li>
+Listing all the records of a CSW server as ISO 19115/19119:
+<pre>
+ogrinfo -ro -al -q CSW:http://catalog.data.gov/csw -oo OUTPUT_SCHEMA=gmd
+</pre>
+<p>
+
+<h2>See Also</h2>
+
+<ul>
+<li> <a href="http://www.opengeospatial.org/standards/cat">OGC CSW Standard</a><p>
+<li> <a href="drv_gml.html">GML driver documentation</a></a><p>
+</ul>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/csw/makefile.vc b/ogr/ogrsf_frmts/csw/makefile.vc
new file mode 100644
index 0000000..35fdb70
--- /dev/null
+++ b/ogr/ogrsf_frmts/csw/makefile.vc
@@ -0,0 +1,15 @@
+
+OBJ	=	ogrcswdataset.obj
+EXTRAFLAGS =	-I.. -I..\.. -I..\gml -I..\wfs
+
+GDAL_ROOT	=	..\..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+default:	$(OBJ)
+
+clean:
+	-del *.obj *.pdb
+
+
+
diff --git a/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp b/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp
new file mode 100644
index 0000000..0d5bbe3
--- /dev/null
+++ b/ogr/ogrsf_frmts/csw/ogrcswdataset.cpp
@@ -0,0 +1,1085 @@
+/******************************************************************************
+ * $Id: ogrcswdataset.cpp 29034 2015-04-27 11:53:19Z rouault $
+ *
+ * Project:  CSW Translator
+ * Purpose:  Implements OGRCSWDriver.
+ * Author:   Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogrsf_frmts.h"
+#include "cpl_conv.h"
+#include "cpl_http.h"
+#include "ogr_wfs.h"
+#include "ogr_p.h"
+#include "gmlutils.h"
+
+CPL_CVSID("$Id: ogrcswdataset.cpp 29034 2015-04-27 11:53:19Z rouault $");
+
+extern "C" void RegisterOGRCSW();
+
+/************************************************************************/
+/*                             OGRCSWLayer                              */
+/************************************************************************/
+
+class OGRCSWDataSource;
+
+class OGRCSWLayer : public OGRLayer
+{
+    OGRCSWDataSource*   poDS;
+    OGRFeatureDefn*     poFeatureDefn;
+
+    GDALDataset        *poBaseDS;
+    OGRLayer           *poBaseLayer;
+
+    int                 nPagingStartIndex;
+    int                 nFeatureRead;
+    int                 nFeaturesInCurrentPage;
+
+    CPLString           osQuery, osCSWWhere;
+
+    GDALDataset*        FetchGetRecords();
+    GIntBig             GetFeatureCountWithHits();
+    void                BuildQuery();
+
+  public:
+                        OGRCSWLayer(OGRCSWDataSource* poDS);
+                        ~OGRCSWLayer();
+
+    virtual void                ResetReading();
+    virtual OGRFeature*         GetNextFeature();
+    virtual GIntBig             GetFeatureCount(int bForce = FALSE);
+
+    virtual OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
+
+    virtual int                 TestCapability( const char * ) { return FALSE; }
+
+    virtual void                SetSpatialFilter( OGRGeometry * );
+    virtual OGRErr              SetAttributeFilter( const char * );
+};
+
+/************************************************************************/
+/*                           OGRCSWDataSource                           */
+/************************************************************************/
+
+class OGRCSWDataSource : public OGRDataSource
+{
+    char*               pszName;
+    CPLString           osBaseURL;
+    CPLString           osVersion;
+    CPLString           osElementSetName;
+    CPLString           osOutputSchema;
+    int                 nMaxRecords;
+
+    OGRCSWLayer*        poLayer;
+    int                 bFullExtentRecordsAsNonSpatial;
+
+    CPLHTTPResult*      SendGetCapabilities();
+
+  public:
+                        OGRCSWDataSource();
+                        ~OGRCSWDataSource();
+
+    int                 Open( const char * pszFilename,
+                              char** papszOpenOptions );
+
+    virtual const char*         GetName() { return pszName; }
+
+    virtual int                 GetLayerCount() { return poLayer != NULL; }
+    virtual OGRLayer*           GetLayer( int );
+
+    virtual int                 TestCapability( const char * ) { return FALSE; }
+
+    CPLHTTPResult*              HTTPFetch( const char* pszURL, const char* pszPost );
+
+    const CPLString&            GetBaseURL() { return osBaseURL; }
+    const CPLString&            GetVersion() { return osVersion; }
+    const CPLString&            GetElementSetName() { return osElementSetName; }
+    const CPLString&            GetOutputSchema() { return osOutputSchema; }
+    int                         FullExtentRecordsAsNonSpatial() { return bFullExtentRecordsAsNonSpatial; }
+    int                         GetMaxRecords() { return nMaxRecords; }
+};
+
+/************************************************************************/
+/*                           OGRCSWLayer()                              */
+/************************************************************************/
+
+OGRCSWLayer::OGRCSWLayer(OGRCSWDataSource* poDS)
+{
+    this->poDS = poDS;
+    poFeatureDefn = new OGRFeatureDefn("records");
+    SetDescription(poFeatureDefn->GetName());
+    poFeatureDefn->Reference();
+    poFeatureDefn->SetGeomType(wkbPolygon);
+    OGRSpatialReference* poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
+    poFeatureDefn->GetGeomFieldDefn(0)->SetName("boundingbox");
+    poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    {
+        OGRFieldDefn oField("identifier", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("other_identifiers", OFTStringList);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("type", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("subject", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("other_subjects", OFTStringList);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("references", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("other_references", OFTStringList);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("modified", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("abstract", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("date", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("language", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("rights", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("format", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("other_formats", OFTStringList);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("creator", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("source", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    {
+        OGRFieldDefn oField("anytext", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    if( poDS->GetOutputSchema().size() )
+    {
+        OGRFieldDefn oField("raw_xml", OFTString);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+
+    poBaseDS = NULL;
+    poBaseLayer = NULL;
+
+    nPagingStartIndex = 0;
+    nFeatureRead = 0;
+    nFeaturesInCurrentPage = 0;
+
+    poSRS->Release();
+}
+
+/************************************************************************/
+/*                          ~OGRCSWLayer()                              */
+/************************************************************************/
+
+OGRCSWLayer::~OGRCSWLayer()
+{
+    poFeatureDefn->Release();
+    GDALClose(poBaseDS);
+    CPLString osTmpDirName = CPLSPrintf("/vsimem/tempcsw_%p", this);
+    OGRWFSRecursiveUnlink(osTmpDirName);
+}
+
+/************************************************************************/
+/*                          ResetReading()                              */
+/************************************************************************/
+
+void OGRCSWLayer::ResetReading()
+{
+    nPagingStartIndex = 0;
+    nFeatureRead = 0;
+    nFeaturesInCurrentPage = 0;
+    GDALClose(poBaseDS);
+    poBaseDS = NULL;
+    poBaseLayer = NULL;
+}
+
+/************************************************************************/
+/*                          GetNextFeature()                            */
+/************************************************************************/
+
+OGRFeature* OGRCSWLayer::GetNextFeature()
+{
+    while(TRUE)
+    {
+        if (nFeatureRead == nPagingStartIndex + nFeaturesInCurrentPage)
+        {
+            nPagingStartIndex = nFeatureRead;
+
+            GDALClose(poBaseDS);
+            poBaseLayer = NULL;
+
+            poBaseDS = FetchGetRecords();
+            if (poBaseDS)
+            {
+                poBaseLayer = poBaseDS->GetLayer(0);
+                poBaseLayer->ResetReading();
+                nFeaturesInCurrentPage = (int)poBaseLayer->GetFeatureCount();
+            }
+        }
+        if (!poBaseLayer)
+            return NULL;
+
+        OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
+        if (poSrcFeature == NULL)
+            return NULL;
+        nFeatureRead ++;
+
+        OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
+
+        for(int i=0;i<poFeatureDefn->GetFieldCount();i++)
+        {
+            const char* pszFieldname = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
+            int iSrcField = poSrcFeature->GetFieldIndex(pszFieldname);
+            /* http://www.paikkatietohakemisto.fi/geonetwork/srv/en/csw returns URI ... */
+            if( iSrcField < 0 && strcmp(pszFieldname, "references") == 0 )
+                iSrcField = poSrcFeature->GetFieldIndex("URI");
+            if( iSrcField >= 0 && poSrcFeature->IsFieldSet(iSrcField) )
+            {
+                OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
+                OGRFieldType eSrcType = poSrcFeature->GetFieldDefnRef(iSrcField)->GetType();
+                if( eType == eSrcType )
+                {
+                    poNewFeature->SetField(i, poSrcFeature->GetRawFieldRef(iSrcField));
+                }
+                else
+                {
+                    if( eType == OFTString && eSrcType == OFTStringList &&
+                        strcmp(pszFieldname, "identifier") == 0 )
+                    {
+                        char** papszValues = poSrcFeature->GetFieldAsStringList(iSrcField);
+                        poNewFeature->SetField("identifier", *papszValues);
+                        if( papszValues[1] )
+                            poNewFeature->SetField("other_identifiers", papszValues + 1);
+                    }
+                    else if( eType == OFTString && eSrcType == OFTStringList &&
+                             strcmp(pszFieldname, "subject") == 0 )
+                    {
+                        char** papszValues = poSrcFeature->GetFieldAsStringList(iSrcField);
+                        poNewFeature->SetField("subject", *papszValues);
+                        if( papszValues[1] )
+                            poNewFeature->SetField("other_subjects", papszValues + 1);
+                    }
+                    else if( eType == OFTString && eSrcType == OFTStringList &&
+                             strcmp(pszFieldname, "references") == 0 )
+                    {
+                        char** papszValues = poSrcFeature->GetFieldAsStringList(iSrcField);
+                        poNewFeature->SetField("references", *papszValues);
+                        if( papszValues[1] )
+                            poNewFeature->SetField("other_references", papszValues + 1);
+                    }
+                    else if( eType == OFTString && eSrcType == OFTStringList &&
+                             strcmp(pszFieldname, "format") == 0 )
+                    {
+                        char** papszValues = poSrcFeature->GetFieldAsStringList(iSrcField);
+                        poNewFeature->SetField("format", *papszValues);
+                        if( papszValues[1] )
+                            poNewFeature->SetField("other_formats", papszValues + 1);
+                    }
+                    else
+                        poNewFeature->SetField(i, poSrcFeature->GetFieldAsString(iSrcField));
+                }
+            }
+        }
+
+        OGRGeometry* poGeom = poSrcFeature->StealGeometry();
+        if( poGeom )
+        {
+            if( poDS->FullExtentRecordsAsNonSpatial() )
+            {
+                OGREnvelope sEnvelope;
+                poGeom->getEnvelope(&sEnvelope);
+                if( sEnvelope.MinX == -180 && sEnvelope.MinY == -90 &&
+                    sEnvelope.MaxX == 180 && sEnvelope.MaxY == 90 )
+                {
+                    delete poGeom;
+                    poGeom = NULL;
+                }
+            }
+            if( poGeom )
+            {
+                poGeom->assignSpatialReference(poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef());
+                poNewFeature->SetGeometryDirectly(poGeom);
+            }
+        }
+
+        poNewFeature->SetFID(nFeatureRead);
+        delete poSrcFeature;
+
+        if( osCSWWhere.size() == 0 &&
+            m_poAttrQuery != NULL &&
+            !m_poAttrQuery->Evaluate( poNewFeature ) )
+        {
+            delete poNewFeature;
+        }
+        else
+        {
+            return poNewFeature;
+        }
+    }
+}
+
+/************************************************************************/
+/*                         GetFeatureCount()                            */
+/************************************************************************/
+
+GIntBig OGRCSWLayer::GetFeatureCount(int bForce)
+{
+    GIntBig nFeatures = GetFeatureCountWithHits();
+    if( nFeatures >= 0 )
+        return nFeatures;
+    return OGRLayer::GetFeatureCount(bForce);
+}
+
+/************************************************************************/
+/*                        GetFeatureCountWithHits()                     */
+/************************************************************************/
+
+GIntBig OGRCSWLayer::GetFeatureCountWithHits()
+{
+    CPLString osPost = CPLSPrintf(
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<csw:GetRecords resultType=\"hits\" service=\"CSW\" version=\"%s\""
+" xmlns:csw=\"http://www.opengis.net/cat/csw/2.0.2\""
+" xmlns:gml=\"http://www.opengis.net/gml\""
+" xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
+" xmlns:dct=\"http://purl.org/dc/terms/\""
+" xmlns:ogc=\"http://www.opengis.net/ogc\""
+" xmlns:ows=\"http://www.opengis.net/ows\""
+" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+" xsi:schemaLocation=\"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd\">"
+"<csw:Query typeNames=\"csw:Record\">"
+"<csw:ElementSetName>%s</csw:ElementSetName>"
+"%s"
+"</csw:Query>"
+"</csw:GetRecords>",
+            poDS->GetVersion().c_str(),
+            poDS->GetElementSetName().c_str(),
+            osQuery.c_str());
+
+    CPLHTTPResult* psResult = poDS->HTTPFetch( poDS->GetBaseURL(), osPost);
+    if (psResult == NULL)
+    {
+        return -1;
+    }
+
+    CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
+    if (psXML == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
+                psResult->pabyData);
+        CPLHTTPDestroyResult(psResult);
+        return -1;
+    }
+    CPLStripXMLNamespace( psXML, NULL, TRUE );
+    CPLHTTPDestroyResult(psResult);
+    psResult = NULL;
+
+    GIntBig nFeatures = CPLAtoGIntBig(CPLGetXMLValue(psXML,
+        "=GetRecordsResponse.SearchResults.numberOfRecordsMatched", "-1"));
+
+    CPLDestroyXMLNode(psXML);
+    return nFeatures;
+}
+
+/************************************************************************/
+/*                         FetchGetRecords()                            */
+/************************************************************************/
+
+GDALDataset* OGRCSWLayer::FetchGetRecords()
+{
+    CPLHTTPResult* psResult = NULL;
+
+    CPLString osOutputSchema = poDS->GetOutputSchema();
+    if( osOutputSchema.size() )
+        osOutputSchema = " outputSchema=\"" + osOutputSchema + "\"";
+
+    CPLString osPost = CPLSPrintf(
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<csw:GetRecords resultType=\"results\" service=\"CSW\" version=\"%s\""
+"%s"
+" startPosition=\"%d\""
+" maxRecords=\"%d\""
+" xmlns:csw=\"http://www.opengis.net/cat/csw/2.0.2\""
+" xmlns:gml=\"http://www.opengis.net/gml\""
+" xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
+" xmlns:dct=\"http://purl.org/dc/terms/\""
+" xmlns:ogc=\"http://www.opengis.net/ogc\""
+" xmlns:ows=\"http://www.opengis.net/ows\""
+" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+" xsi:schemaLocation=\"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd\">"
+"<csw:Query typeNames=\"csw:Record\">"
+"<csw:ElementSetName>%s</csw:ElementSetName>"
+"%s"
+"</csw:Query>"
+"</csw:GetRecords>",
+            poDS->GetVersion().c_str(),
+            osOutputSchema.c_str(),
+            nPagingStartIndex + 1,
+            poDS->GetMaxRecords(),
+            poDS->GetElementSetName().c_str(),
+            osQuery.c_str());
+
+    psResult = poDS->HTTPFetch( poDS->GetBaseURL(), osPost);
+    if (psResult == NULL)
+    {
+        return NULL;
+    }
+
+    CPLString osTmpDirName = CPLSPrintf("/vsimem/tempcsw_%p", this);
+    VSIMkdir(osTmpDirName, 0);
+
+    GByte *pabyData = psResult->pabyData;
+    int    nDataLen = psResult->nDataLen;
+
+    if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
+        strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
+                 pabyData);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    //CPLDebug("CSW", "%s", (const char*)pabyData);
+
+    CPLString osTmpFileName;
+
+    osTmpFileName = osTmpDirName + "/file.gfs";
+    VSIUnlink(osTmpFileName);
+
+    osTmpFileName = osTmpDirName + "/file.gml";
+
+    VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
+                                    nDataLen, TRUE);
+    VSIFCloseL(fp);
+    psResult->pabyData = NULL;
+
+    CPLHTTPDestroyResult(psResult);
+
+    GDALDataset* poBaseDS = NULL;
+
+    if( poDS->GetOutputSchema().size() )
+    {
+        GDALDriver* poDrv = (GDALDriver*)GDALGetDriverByName("Memory");
+        if( poDrv == NULL )
+            return NULL;
+        CPLXMLNode* psRoot = CPLParseXMLFile(osTmpFileName);
+        if( psRoot == NULL )
+        {
+            if( strstr((const char*)pabyData, "<csw:GetRecordsResponse") == NULL &&
+                strstr((const char*)pabyData, "<GetRecordsResponse") == NULL )
+            {
+                if (nDataLen > 1000)
+                    pabyData[1000] = 0;
+                CPLError(CE_Failure, CPLE_AppDefined,
+                        "Error: cannot parse %s", pabyData);
+            }
+            return NULL;
+        }
+        CPLXMLNode* psSearchResults = CPLGetXMLNode(psRoot, "=csw:GetRecordsResponse.csw:SearchResults");
+        if( psSearchResults == NULL )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot find GetRecordsResponse.SearchResults");
+            CPLDestroyXMLNode(psRoot);
+            return NULL;
+        }
+
+        poBaseDS = poDrv->Create("", 0, 0, 0, GDT_Unknown, NULL);
+        OGRLayer* poLyr = poBaseDS->CreateLayer("records");
+        OGRFieldDefn oField("raw_xml", OFTString);
+        poLyr->CreateField(&oField);
+        for( CPLXMLNode* psIter = psSearchResults->psChild; psIter; psIter = psIter->psNext )
+        {
+            if( psIter->eType == CXT_Element )
+            {
+                OGRFeature* poFeature = new OGRFeature(poLyr->GetLayerDefn());
+
+                CPLXMLNode* psNext = psIter->psNext;
+                psIter->psNext = NULL;
+                char* pszXML = CPLSerializeXMLTree(psIter);
+
+                const char* pszWest = NULL;
+                const char* pszEast = NULL;
+                const char* pszSouth = NULL;
+                const char* pszNorth = NULL;
+                CPLXMLNode* psBBox = CPLSearchXMLNode( psIter, "gmd:EX_GeographicBoundingBox");
+                if( psBBox )
+                {
+                    /* ISO 19115/19119: http://www.isotc211.org/2005/gmd */
+                    pszWest = CPLGetXMLValue(psBBox, "gmd:westBoundLongitude.gco:Decimal", NULL);
+                    pszEast = CPLGetXMLValue(psBBox, "gmd:eastBoundLongitude.gco:Decimal", NULL);
+                    pszSouth = CPLGetXMLValue(psBBox, "gmd:southBoundLatitude.gco:Decimal", NULL);
+                    pszNorth = CPLGetXMLValue(psBBox, "gmd:northBoundLatitude.gco:Decimal", NULL);
+                }
+                else if( (psBBox = CPLSearchXMLNode( psIter, "spdom") ) != NULL )
+                {
+                    /* FGDC: http://www.opengis.net/cat/csw/csdgm */
+                    pszWest = CPLGetXMLValue(psBBox, "bounding.westbc", NULL);
+                    pszEast = CPLGetXMLValue(psBBox, "bounding.eastbc", NULL);
+                    pszSouth = CPLGetXMLValue(psBBox, "bounding.southbc", NULL);
+                    pszNorth = CPLGetXMLValue(psBBox, "bounding.northbc", NULL);
+                }
+                if( pszWest && pszEast && pszSouth && pszNorth )
+                {
+                    double dfMinX = CPLAtof(pszWest);
+                    double dfMaxX = CPLAtof(pszEast);
+                    double dfMinY = CPLAtof(pszSouth);
+                    double dfMaxY = CPLAtof(pszNorth);
+                    OGRLinearRing* poLR = new OGRLinearRing();
+                    poLR->addPoint(dfMinX, dfMinY);
+                    poLR->addPoint(dfMinX, dfMaxY);
+                    poLR->addPoint(dfMaxX, dfMaxY);
+                    poLR->addPoint(dfMaxX, dfMinY);
+                    poLR->addPoint(dfMinX, dfMinY);
+                    OGRPolygon* poPoly = new OGRPolygon();
+                    poPoly->addRingDirectly(poLR);
+                    poFeature->SetGeometryDirectly(poPoly);
+                }
+                else if( (psBBox = CPLSearchXMLNode( psIter, "ows:BoundingBox") ) != NULL )
+                {
+                    CPLFree(psBBox->pszValue);
+                    psBBox->pszValue = CPLStrdup("gml:Envelope");
+                    CPLString osSRS = CPLGetXMLValue(psBBox, "crs", "");
+                    OGRGeometry* poGeom = GML2OGRGeometry_XMLNode( psBBox,
+                                                          FALSE,
+                                                          0, 0, FALSE, TRUE,
+                                                          FALSE );
+                    int bLatLongOrder = TRUE;
+                    if( osSRS.size() )
+                        bLatLongOrder = GML_IsSRSLatLongOrder(osSRS);
+                    if( bLatLongOrder && CSLTestBoolean(
+                            CPLGetConfigOption("GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES")) )
+                        poGeom->swapXY();
+                    poFeature->SetGeometryDirectly(poGeom);
+                }
+
+                psIter->psNext = psNext;
+
+                poFeature->SetField(0, pszXML);
+                poLyr->CreateFeature(poFeature);
+                CPLFree(pszXML);
+                delete poFeature;
+            }
+        }
+        CPLDestroyXMLNode(psRoot);
+    }
+    else
+    {
+        poBaseDS = (GDALDataset*) OGROpen(osTmpFileName, FALSE, NULL);
+        if (poBaseDS == NULL)
+        {
+            if( strstr((const char*)pabyData, "<csw:GetRecordsResponse") == NULL &&
+                strstr((const char*)pabyData, "<GetRecordsResponse") == NULL )
+            {
+                if (nDataLen > 1000)
+                    pabyData[1000] = 0;
+                CPLError(CE_Failure, CPLE_AppDefined,
+                        "Error: cannot parse %s", pabyData);
+            }
+            return NULL;
+        }
+    }
+
+    OGRLayer* poLayer = poBaseDS->GetLayer(0);
+    if (poLayer == NULL)
+    {
+        GDALClose(poBaseDS);
+        return NULL;
+    }
+
+    return poBaseDS;
+}
+
+/************************************************************************/
+/*                         SetSpatialFilter()                           */
+/************************************************************************/
+
+void OGRCSWLayer::SetSpatialFilter( OGRGeometry * poGeom )
+{
+    OGRLayer::SetSpatialFilter(poGeom);
+    ResetReading();
+    BuildQuery();
+}
+
+/************************************************************************/
+/*                         OGRCSWAddRightPrefixes()                     */
+/************************************************************************/
+
+static void OGRCSWAddRightPrefixes(swq_expr_node* poNode)
+{
+    if( poNode->eNodeType == SNT_COLUMN )
+    {
+        if( EQUAL(poNode->string_value, "identifier") ||
+            EQUAL(poNode->string_value, "title") ||
+            EQUAL(poNode->string_value, "type") ||
+            EQUAL(poNode->string_value, "subject") ||
+            EQUAL(poNode->string_value, "date") ||
+            EQUAL(poNode->string_value, "language") ||
+            EQUAL(poNode->string_value, "rights") ||
+            EQUAL(poNode->string_value, "format") ||
+            EQUAL(poNode->string_value, "creator") ||
+            EQUAL(poNode->string_value, "source") )
+        {
+            char* pszNewVal = CPLStrdup(CPLSPrintf("dc:%s", poNode->string_value));
+            CPLFree(poNode->string_value);
+            poNode->string_value = pszNewVal;
+        }
+        else if( EQUAL(poNode->string_value, "references") ||
+                 EQUAL(poNode->string_value, "modified") ||
+                 EQUAL(poNode->string_value, "abstract") )
+        {
+            char* pszNewVal = CPLStrdup(CPLSPrintf("dct:%s", poNode->string_value));
+            CPLFree(poNode->string_value);
+            poNode->string_value = pszNewVal;
+        }
+        else if( EQUAL(poNode->string_value, "other_identifiers") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("dc:identifier");
+        }
+        else if( EQUAL(poNode->string_value, "other_subjects") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("dc:subject");
+        }
+        else if( EQUAL(poNode->string_value, "other_references") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("dct:references");
+        }
+        else if( EQUAL(poNode->string_value, "other_formats") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("dc:format");
+        }
+        else if( EQUAL(poNode->string_value, "AnyText") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("csw:AnyText");
+        }
+        else if( EQUAL(poNode->string_value, "boundingbox") )
+        {
+            CPLFree(poNode->string_value);
+            poNode->string_value = CPLStrdup("ows:BoundingBox");
+        }
+    }
+    else if( poNode->eNodeType == SNT_OPERATION )
+    {
+        for(int i=0;i < poNode->nSubExprCount;i++)
+            OGRCSWAddRightPrefixes(poNode->papoSubExpr[i]);
+    }
+}
+
+/************************************************************************/
+/*                        SetAttributeFilter()                          */
+/************************************************************************/
+
+OGRErr OGRCSWLayer::SetAttributeFilter( const char * pszFilter )
+{
+    if (pszFilter != NULL && pszFilter[0] == 0)
+        pszFilter = NULL;
+
+    CPLFree(m_pszAttrQueryString);
+    m_pszAttrQueryString = (pszFilter) ? CPLStrdup(pszFilter) : NULL;
+
+    delete m_poAttrQuery;
+    m_poAttrQuery = NULL;
+    
+    if( pszFilter != NULL )
+    {
+        m_poAttrQuery = new OGRFeatureQuery();
+
+        OGRErr eErr = m_poAttrQuery->Compile( GetLayerDefn(), pszFilter, TRUE,
+                                              WFSGetCustomFuncRegistrar() );
+        if( eErr != OGRERR_NONE )
+        {
+            delete m_poAttrQuery;
+            m_poAttrQuery = NULL;
+            return eErr;
+        }
+    }
+
+    if (m_poAttrQuery != NULL )
+    {
+        swq_expr_node* poNode = (swq_expr_node*) m_poAttrQuery->GetSWQExpr();
+        swq_expr_node* poNodeClone = poNode->Clone();
+        poNodeClone->ReplaceBetweenByGEAndLERecurse();
+        OGRCSWAddRightPrefixes(poNodeClone);
+
+        int bNeedsNullCheck = FALSE;
+        if( poNode->field_type != SWQ_BOOLEAN )
+            osCSWWhere = "";
+        else
+            osCSWWhere = WFS_TurnSQLFilterToOGCFilter(poNodeClone,
+                                                      NULL,
+                                                      NULL,
+                                                      110,
+                                                      FALSE,
+                                                      FALSE,
+                                                      FALSE,
+                                                      "ogc:",
+                                                      &bNeedsNullCheck);
+        delete poNodeClone;
+    }
+    else
+        osCSWWhere = "";
+
+    if (m_poAttrQuery != NULL && osCSWWhere.size() == 0)
+    {
+        CPLDebug("CSW", "Using client-side only mode for filter \"%s\"", pszFilter);
+        OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
+        if (eErr != OGRERR_NONE)
+            return eErr;
+    }
+
+    ResetReading();
+    BuildQuery();
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                                BuildQuery()                          */
+/************************************************************************/
+
+void OGRCSWLayer::BuildQuery()
+{
+    if( m_poFilterGeom != NULL || osCSWWhere.size() != 0 )
+    {
+        osQuery = "<csw:Constraint version=\"1.1.0\">";
+        osQuery += "<ogc:Filter>";
+        if( m_poFilterGeom != NULL && osCSWWhere.size() != 0 )
+            osQuery += "<ogc:And>";
+        if( m_poFilterGeom != NULL )
+        {
+            osQuery += "<ogc:BBOX>";
+            osQuery += "<ogc:PropertyName>ows:BoundingBox</ogc:PropertyName>";
+            osQuery += "<gml:Envelope srsName=\"urn:ogc:def:crs:EPSG::4326\">";
+            OGREnvelope sEnvelope;
+            m_poFilterGeom->getEnvelope(&sEnvelope);
+            if( CSLTestBoolean(
+                    CPLGetConfigOption("GML_INVERT_AXIS_ORDER_IF_LAT_LONG", "YES")) )
+            {
+                osQuery += CPLSPrintf("<gml:lowerCorner>%.16g %.16g</gml:lowerCorner>", sEnvelope.MinY, sEnvelope.MinX);
+                osQuery += CPLSPrintf("<gml:upperCorner>%.16g %.16g</gml:upperCorner>", sEnvelope.MaxY, sEnvelope.MaxX);
+            }
+            else
+            {
+                osQuery += CPLSPrintf("<gml:lowerCorner>%.16g %.16g</gml:lowerCorner>", sEnvelope.MinX, sEnvelope.MinY);
+                osQuery += CPLSPrintf("<gml:upperCorner>%.16g %.16g</gml:upperCorner>", sEnvelope.MaxX, sEnvelope.MaxY);
+            }
+            osQuery += "</gml:Envelope>";
+            osQuery += "</ogc:BBOX>";
+        }
+        osQuery += osCSWWhere;
+        if( m_poFilterGeom != NULL && osCSWWhere.size() != 0 )
+            osQuery += "</ogc:And>";
+        osQuery += "</ogc:Filter>";
+        osQuery += "</csw:Constraint>";
+    }
+    else
+        osQuery = "";
+}
+
+/************************************************************************/
+/*                          OGRCSWDataSource()                          */
+/************************************************************************/
+
+OGRCSWDataSource::OGRCSWDataSource()
+{
+    pszName = NULL;
+    poLayer = NULL;
+    bFullExtentRecordsAsNonSpatial = FALSE;
+    nMaxRecords = 500;
+}
+
+/************************************************************************/
+/*                         ~OGRCSWDataSource()                          */
+/************************************************************************/
+
+OGRCSWDataSource::~OGRCSWDataSource()
+{
+    delete poLayer;
+    CPLFree( pszName );
+}
+
+/************************************************************************/
+/*                          SendGetCapabilities()                       */
+/************************************************************************/
+
+CPLHTTPResult* OGRCSWDataSource::SendGetCapabilities()
+{
+    CPLString osURL(osBaseURL);
+
+    osURL = CPLURLAddKVP(osURL, "SERVICE", "CSW");
+    osURL = CPLURLAddKVP(osURL, "REQUEST", "GetCapabilities");
+
+    CPLHTTPResult* psResult;
+
+    CPLDebug("CSW", "%s", osURL.c_str());
+
+    psResult = HTTPFetch( osURL, NULL);
+    if (psResult == NULL)
+    {
+        return NULL;
+    }
+
+    if (strstr((const char*)psResult->pabyData,
+                                    "<ServiceExceptionReport") != NULL ||
+        strstr((const char*)psResult->pabyData,
+                                    "<ows:ExceptionReport") != NULL ||
+        strstr((const char*)psResult->pabyData,
+                                    "<ExceptionReport") != NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
+                psResult->pabyData);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+
+    return psResult;
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+int OGRCSWDataSource::Open( const char * pszFilename,
+                            char** papszOpenOptions )
+{
+    const char* pszBaseURL = CSLFetchNameValue(papszOpenOptions, "URL");
+    if( pszBaseURL == NULL )
+    {
+        pszBaseURL = pszFilename;
+        if (EQUALN(pszFilename, "CSW:", 4))
+            pszBaseURL += 4;
+        if( pszBaseURL[0] == '\0' )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Missing URL open option");
+            return FALSE;
+        }
+    }
+    osBaseURL = pszBaseURL;
+    osElementSetName = CSLFetchNameValueDef(papszOpenOptions, "ELEMENTSETNAME",
+                                            "full");
+    bFullExtentRecordsAsNonSpatial = CSLFetchBoolean(papszOpenOptions,
+                                                     "FULL_EXTENT_RECORDS_AS_NON_SPATIAL",
+                                                     FALSE);
+    osOutputSchema = CSLFetchNameValueDef(papszOpenOptions, "OUTPUT_SCHEMA", "");
+    if( EQUAL(osOutputSchema, "gmd") )
+        osOutputSchema = "http://www.isotc211.org/2005/gmd";
+    else if( EQUAL(osOutputSchema, "csw") )
+        osOutputSchema = "http://www.opengis.net/cat/csw/2.0.2";
+    nMaxRecords = atoi(CSLFetchNameValueDef(papszOpenOptions, "MAX_RECORDS", "500"));
+
+    if (strncmp(osBaseURL, "http://", 7) != 0 &&
+        strncmp(osBaseURL, "https://", 8) != 0 &&
+        strncmp(osBaseURL, "/vsimem/", strlen("/vsimem/")) != 0)
+        return FALSE;
+
+    CPLHTTPResult* psResult = SendGetCapabilities();
+    if( psResult == NULL )
+        return FALSE;
+    
+    CPLXMLNode* psXML = CPLParseXMLString( (const char*) psResult->pabyData );
+    if (psXML == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
+                psResult->pabyData);
+        CPLHTTPDestroyResult(psResult);
+        return FALSE;
+    }
+    CPLStripXMLNamespace( psXML, NULL, TRUE );
+    CPLHTTPDestroyResult(psResult);
+    psResult = NULL;
+
+    const char* pszVersion = CPLGetXMLValue( psXML, "=Capabilities.version", NULL);
+    if( pszVersion == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find Capabilities.version");
+        CPLDestroyXMLNode(psXML);
+        return FALSE;
+    }
+    if( !EQUAL(pszVersion, "2.0.2") )
+        CPLDebug("CSW", "Presumably only work properly with 2.0.2. Reported version is %s", pszVersion);
+    osVersion = pszVersion;
+    CPLDestroyXMLNode(psXML);
+
+    poLayer = new OGRCSWLayer(this);
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *OGRCSWDataSource::GetLayer( int iLayer )
+
+{
+    if( iLayer < 0 || iLayer >= ((poLayer != NULL) ? 1 : 0) )
+        return NULL;
+    else
+        return poLayer;
+}
+
+/************************************************************************/
+/*                            HTTPFetch()                               */
+/************************************************************************/
+
+CPLHTTPResult* OGRCSWDataSource::HTTPFetch( const char* pszURL, const char* pszPost )
+{
+    char** papszOptions = NULL;
+    if( pszPost )
+    {
+        papszOptions = CSLAddNameValue(papszOptions, "POSTFIELDS", pszPost);
+        papszOptions = CSLAddNameValue(papszOptions, "HEADERS",
+                                    "Content-Type: application/xml; charset=UTF-8");
+    }
+    CPLHTTPResult* psResult = CPLHTTPFetch( pszURL, papszOptions );
+    CSLDestroy(papszOptions);
+
+    if (psResult == NULL)
+    {
+        return NULL;
+    }
+    if (psResult->nStatus != 0 || psResult->pszErrBuf != NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s (%d)",
+                 (psResult->pszErrBuf) ? psResult->pszErrBuf : "unknown", psResult->nStatus);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    if (psResult->pabyData == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    return psResult;
+}
+
+/************************************************************************/
+/*                             Identify()                               */
+/************************************************************************/
+
+static int OGRCSWDriverIdentify( GDALOpenInfo* poOpenInfo )
+
+{
+    return EQUALN(poOpenInfo->pszFilename, "CSW:", 4);
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+static GDALDataset *OGRCSWDriverOpen( GDALOpenInfo* poOpenInfo )
+
+{
+    if( !OGRCSWDriverIdentify(poOpenInfo) || poOpenInfo->eAccess == GA_Update )
+        return NULL;
+
+    OGRCSWDataSource   *poDS = new OGRCSWDataSource();
+
+    if( !poDS->Open( poOpenInfo->pszFilename,
+                     poOpenInfo->papszOpenOptions ) )
+    {
+        delete poDS;
+        poDS = NULL;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                           RegisterOGRCSW()                           */
+/************************************************************************/
+
+void RegisterOGRCSW()
+
+{
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "CSW" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "CSW" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "OGC CSW (Catalog  Service for the Web)" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_csw.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "CSW:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='URL' type='string' description='URL to the CSW server endpoint' required='true'/>"
+"  <Option name='ELEMENTSETNAME' type='string-select' description='Level of details of properties' default='full'>"
+"    <Value>brief</Value>"
+"    <Value>summary</Value>"
+"    <Value>full</Value>"
+"  </Option>"
+"  <Option name='FULL_EXTENT_RECORDS_AS_NON_SPATIAL' type='boolean' description='Whether records with (-180,-90,180,90) extent should be considered non-spatial' default='false'/>"
+"  <Option name='OUTPUT_SCHEMA' type='string' description='Value of outputSchema parameter'/>"
+"  <Option name='MAX_RECORDS' type='int' description='Maximum number of records to retrieve in a single time' default='500'/>"
+"</OpenOptionList>" );
+
+        poDriver->pfnIdentify = OGRCSWDriverIdentify;
+        poDriver->pfnOpen = OGRCSWDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
+
diff --git a/ogr/ogrsf_frmts/dgn/GNUmakefile b/ogr/ogrsf_frmts/dgn/GNUmakefile
index e34fec8..732799b 100644
--- a/ogr/ogrsf_frmts/dgn/GNUmakefile
+++ b/ogr/ogrsf_frmts/dgn/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 MIN_OBJ	=	dgnopen.o dgnread.o dgnfloat.o dgnhelp.o dgnwrite.o dgnstroke.o
 OBJ =	ogrdgndriver.o ogrdgndatasource.o ogrdgnlayer.o $(MIN_OBJ)
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 CPL_DIR	=	../../../port
 
diff --git a/ogr/ogrsf_frmts/dgn/dgndump.c b/ogr/ogrsf_frmts/dgn/dgndump.c
index 78df927..b0e4c78 100644
--- a/ogr/ogrsf_frmts/dgn/dgndump.c
+++ b/ogr/ogrsf_frmts/dgn/dgndump.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgndump.c 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: dgndump.c 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  Temporary low level DGN dumper application.
@@ -29,7 +29,7 @@
 
 #include "dgnlibp.h"
 
-CPL_CVSID("$Id: dgndump.c 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: dgndump.c 27942 2014-11-11 00:57:41Z rouault $");
 
 static void DGNDumpRawElement( DGNHandle hDGN, DGNElemCore *psCore,
                                FILE *fpOut );
@@ -74,10 +74,10 @@ int main( int argc, char ** argv )
         }
         else if( strcmp(argv[iArg],"-e") == 0 && iArg < argc-4 )
         {
-            dfSFXMin = atof(argv[iArg+1]);
-            dfSFYMin = atof(argv[iArg+2]);
-            dfSFXMax = atof(argv[iArg+3]);
-            dfSFYMax = atof(argv[iArg+4]);
+            dfSFXMin = CPLAtof(argv[iArg+1]);
+            dfSFYMin = CPLAtof(argv[iArg+2]);
+            dfSFXMax = CPLAtof(argv[iArg+3]);
+            dfSFYMax = CPLAtof(argv[iArg+4]);
             iArg += 4;
         }
         else if( strcmp(argv[iArg],"-r") == 0 && iArg < argc-1 )
diff --git a/ogr/ogrsf_frmts/dgn/dgnhelp.cpp b/ogr/ogrsf_frmts/dgn/dgnhelp.cpp
index 458454f..0a34a6d 100644
--- a/ogr/ogrsf_frmts/dgn/dgnhelp.cpp
+++ b/ogr/ogrsf_frmts/dgn/dgnhelp.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgnhelp.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: dgnhelp.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  Application visible helper functions for parsing DGN information.
@@ -29,7 +29,7 @@
 
 #include "dgnlibp.h"
 
-CPL_CVSID("$Id: dgnhelp.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: dgnhelp.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static unsigned char abyDefaultPCT[256][3] = 
 {
@@ -512,7 +512,8 @@ void DGNAsciiToRad50( const char *str, unsigned short *pRad50 )
 /*      The got name is stored in psLine.                               */
 /************************************************************************/
 
-int DGNGetLineStyleName(CPL_UNUSED DGNInfo *psDGN, DGNElemMultiPoint *psLine,
+int DGNGetLineStyleName(CPL_UNUSED DGNInfo *psDGN,
+                        DGNElemMultiPoint *psLine,
                         char szLineStyle[65] )
 {
     if (psLine->core.attr_bytes > 0 &&
@@ -1200,9 +1201,9 @@ const char *DGNTypeToName( int nType )
  * @return size of linkage in bytes, or zero. 
  */
 
-int DGNGetAttrLinkSize( CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement, 
+int DGNGetAttrLinkSize( CPL_UNUSED DGNHandle hDGN,
+                        DGNElemCore *psElement,
                         int nOffset )
-
 {
     if( psElement->attr_bytes < nOffset + 4 )
         return 0;
@@ -1371,7 +1372,6 @@ void DGNTransformPointWithQuaternionVertex( CPL_UNUSED int *quat,
                                             CPL_UNUSED DGNPoint *v1,
                                             CPL_UNUSED DGNPoint *v2 )
 {
-
 /* ==================================================================== */
 /*      Original code provided by kintel 20030819, but assumed to be    */
 /*      incomplete.                                                     */
diff --git a/ogr/ogrsf_frmts/dgn/dgnopen.cpp b/ogr/ogrsf_frmts/dgn/dgnopen.cpp
index 8e38f0a..8dd456c 100644
--- a/ogr/ogrsf_frmts/dgn/dgnopen.cpp
+++ b/ogr/ogrsf_frmts/dgn/dgnopen.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgnopen.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: dgnopen.cpp 27272 2014-05-01 23:14:58Z rouault $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  DGN Access Library file open code.
@@ -29,7 +29,7 @@
 
 #include "dgnlibp.h"
 
-CPL_CVSID("$Id: dgnopen.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: dgnopen.cpp 27272 2014-05-01 23:14:58Z rouault $");
 
 /************************************************************************/
 /*                            DGNTestOpen()                             */
@@ -48,7 +48,7 @@ int DGNTestOpen( GByte *pabyHeader, int nByteCount )
 
 {
     if( nByteCount < 4 )
-        return TRUE;
+        return FALSE;
 
     // Is it a cell library?
     if( pabyHeader[0] == 0x08
diff --git a/ogr/ogrsf_frmts/dgn/dgnread.cpp b/ogr/ogrsf_frmts/dgn/dgnread.cpp
index af307d1..aa31a4f 100644
--- a/ogr/ogrsf_frmts/dgn/dgnread.cpp
+++ b/ogr/ogrsf_frmts/dgn/dgnread.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgnread.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: dgnread.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  DGN Access Library element reading code.
@@ -29,7 +29,7 @@
 
 #include "dgnlibp.h"
 
-CPL_CVSID("$Id: dgnread.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: dgnread.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static DGNElemCore *DGNParseTCB( DGNInfo * );
 static DGNElemCore *DGNParseColorTable( DGNInfo * );
@@ -1850,4 +1850,3 @@ void DGNBuildIndex( DGNInfo *psDGN )
 
     psDGN->max_element_count = nMaxElements;
 }
-
diff --git a/ogr/ogrsf_frmts/dgn/dgnstroke.cpp b/ogr/ogrsf_frmts/dgn/dgnstroke.cpp
index 709e708..a7386de 100644
--- a/ogr/ogrsf_frmts/dgn/dgnstroke.cpp
+++ b/ogr/ogrsf_frmts/dgn/dgnstroke.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgnstroke.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: dgnstroke.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  Code to stroke Arcs/Ellipses into polylines.
@@ -30,7 +30,7 @@
 #include "dgnlibp.h"
 #include <math.h>
 
-CPL_CVSID("$Id: dgnstroke.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: dgnstroke.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 #define DEG_TO_RAD (PI/180.0)
 
@@ -72,9 +72,9 @@ static void ComputePointOnArc2D( double dfPrimary, double dfSecondary,
  * @return TRUE on success or FALSE on failure.
  */
 
-int DGNStrokeArc( CPL_UNUSED DGNHandle hFile, DGNElemArc *psArc, 
+int DGNStrokeArc( CPL_UNUSED DGNHandle hFile,
+                  DGNElemArc *psArc,
                   int nPoints, DGNPoint * pasPoints )
-
 {
     double      dfAngleStep, dfAngle;
     int         i;
@@ -127,9 +127,9 @@ int DGNStrokeArc( CPL_UNUSED DGNHandle hFile, DGNElemArc *psArc,
  * @return TRUE on success or FALSE on failure.
  */
 
-int DGNStrokeCurve( CPL_UNUSED DGNHandle hFile, DGNElemMultiPoint *psCurve, 
+int DGNStrokeCurve( CPL_UNUSED DGNHandle hFile,
+                    DGNElemMultiPoint *psCurve,
                     int nPoints, DGNPoint * pasPoints )
-
 {
     int         k, nDGNPoints, iOutPoint;
     double      *padfMx, *padfMy, *padfD, dfTotalD = 0, dfStepSize, dfD;
@@ -312,10 +312,10 @@ int main( int argc, char ** argv )
 
     double      dfX, dfY, dfPrimary, dfSecondary, dfAxisRotation, dfAngle;
 
-    dfPrimary = atof(argv[1]);
-    dfSecondary = atof(argv[2]);
-    dfAxisRotation = atof(argv[3]) / 180 * PI;
-    dfAngle = atof(argv[4]) / 180 * PI;
+    dfPrimary = CPLAtof(argv[1]);
+    dfSecondary = CPLAtof(argv[2]);
+    dfAxisRotation = CPLAtof(argv[3]) / 180 * PI;
+    dfAngle = CPLAtof(argv[4]) / 180 * PI;
 
     ComputePointOnArc2D( dfPrimary, dfSecondary, dfAxisRotation, dfAngle, 
                          &dfX, &dfY );
@@ -326,4 +326,3 @@ int main( int argc, char ** argv )
 }
 
 #endif
-
diff --git a/ogr/ogrsf_frmts/dgn/dgnwrite.cpp b/ogr/ogrsf_frmts/dgn/dgnwrite.cpp
index 3bc9a5a..4258a60 100644
--- a/ogr/ogrsf_frmts/dgn/dgnwrite.cpp
+++ b/ogr/ogrsf_frmts/dgn/dgnwrite.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: dgnwrite.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: dgnwrite.cpp 28435 2015-02-07 14:35:34Z rouault $
  *
  * Project:  Microstation DGN Access Library
  * Purpose:  DGN Access functions related to writing DGN elements.
@@ -30,7 +30,7 @@
 
 #include "dgnlibp.h"
 
-CPL_CVSID("$Id: dgnwrite.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: dgnwrite.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 static void DGNPointToInt( DGNInfo *psDGN, DGNPoint *psPoint, 
                            unsigned char *pabyTarget );
@@ -451,8 +451,10 @@ DGNHandle
  * the source element suitable to write to hDGNDst. 
  */
 
-DGNElemCore *DGNCloneElement( CPL_UNUSED DGNHandle hDGNSrc, DGNHandle hDGNDst, 
+DGNElemCore *DGNCloneElement( CPL_UNUSED DGNHandle hDGNSrc,
+                              DGNHandle hDGNDst,
                               DGNElemCore *psSrcElement )
+
 {
     DGNElemCore *psClone = NULL;
 
@@ -759,12 +761,13 @@ int DGNUpdateElemCore( DGNHandle hDGN, DGNElemCore *psElement,
  */
 
 
-int DGNUpdateElemCoreExtended( CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement )
+int DGNUpdateElemCoreExtended( CPL_UNUSED DGNHandle hDGN,
+                               DGNElemCore *psElement )
 {
     GByte *rd = psElement->raw_data;
     int   nWords = (psElement->raw_bytes / 2) - 2;
 
-    if( psElement->raw_data == NULL 
+    if( psElement->raw_data == NULL
         || psElement->raw_bytes < 36 )
     {
         CPLAssert( FALSE );
@@ -816,7 +819,8 @@ int DGNUpdateElemCoreExtended( CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement
 /*                         DGNInitializeElemCore()                      */
 /************************************************************************/
 
-static void DGNInitializeElemCore( CPL_UNUSED DGNHandle hDGN, DGNElemCore *psElement )
+static void DGNInitializeElemCore( CPL_UNUSED DGNHandle hDGN,
+                                   DGNElemCore *psElement )
 {
     memset( psElement, 0, sizeof(DGNElemCore) );
 
@@ -2410,8 +2414,7 @@ int DGNAddRawAttrLink( DGNHandle hDGN, DGNElemCore *psElement,
 /* -------------------------------------------------------------------- */
 /*      Grow the raw data, if we have rawdata.                          */
 /* -------------------------------------------------------------------- */
-    /* TODO: operation on raw_bytes may be undefined. */
-    psElement->raw_bytes = psElement->raw_bytes += nLinkSize;
+    psElement->raw_bytes += nLinkSize;
     psElement->raw_data = (unsigned char *)
         CPLRealloc( psElement->raw_data, psElement->raw_bytes );
 
diff --git a/ogr/ogrsf_frmts/dgn/drv_dgn.html b/ogr/ogrsf_frmts/dgn/drv_dgn.html
index 7e3daf8..8708e50 100644
--- a/ogr/ogrsf_frmts/dgn/drv_dgn.html
+++ b/ogr/ogrsf_frmts/dgn/drv_dgn.html
@@ -115,7 +115,7 @@ SEED option is provided.<p>
 seed file should be copied.  If not, only the first three elements (and 
 potentially the color table) will be copied.  Default is NO.<p>
 
-<li> <b>COPY_SEED_FILE_COLOR_TABLEE=</b><i>YES/NO</i>: Indicates whether the
+<li> <b>COPY_SEED_FILE_COLOR_TABLE=</b><i>YES/NO</i>: Indicates whether the
 color table should be copied from the seed file.  By default this is NO. <p>
 
 <li> <b>MASTER_UNIT_NAME=</b><i>name</i>: Override the master unit name from
diff --git a/ogr/ogrsf_frmts/dgn/ogr_dgn.h b/ogr/ogrsf_frmts/dgn/ogr_dgn.h
index 1db79bf..654d64a 100644
--- a/ogr/ogrsf_frmts/dgn/ogr_dgn.h
+++ b/ogr/ogrsf_frmts/dgn/ogr_dgn.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_dgn.h 25311 2012-12-15 12:48:14Z rouault $
+ * $Id: ogr_dgn.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  OGR Driver for DGN Reader.
@@ -70,16 +70,16 @@ class OGRDGNLayer : public OGRLayer
 
     void                ResetReading();
     OGRFeature *        GetNextFeature();
-    OGRFeature *        GetFeature( long nFeatureId );
+    OGRFeature *        GetFeature( GIntBig nFeatureId );
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
     int                 TestCapability( const char * );
 
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
 
 };
 
@@ -104,7 +104,7 @@ class OGRDGNDataSource : public OGRDataSource
     int                 Open( const char *, int bTestOpen, int bUpdate );
     int                 PreCreate( const char *, char ** );
 
-    OGRLayer           *CreateLayer( const char *, 
+    OGRLayer           *ICreateLayer( const char *, 
                                      OGRSpatialReference * = NULL,
                                      OGRwkbGeometryType = wkbUnknown,
                                      char ** = NULL );
@@ -116,21 +116,4 @@ class OGRDGNDataSource : public OGRDataSource
     int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                            OGRDGNDriver                              */
-/************************************************************************/
-
-class OGRDGNDriver : public OGRSFDriver
-{
-  public:
-                ~OGRDGNDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    OGRDataSource *CreateDataSource( const char *, char ** );
-
-    int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_DGN_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp b/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp
index 4f829d2..bdd8db0 100644
--- a/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp
+++ b/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdgndatasource.cpp 23431 2011-11-27 15:02:24Z rouault $
+ * $Id: ogrdgndatasource.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDataSource class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrdgndatasource.cpp 23431 2011-11-27 15:02:24Z rouault $");
+CPL_CVSID("$Id: ogrdgndatasource.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                         OGRDGNDataSource()                           */
@@ -165,7 +165,7 @@ OGRLayer *OGRDGNDataSource::GetLayer( int iLayer )
 /*                                                                      */
 /*      Called by OGRDGNDriver::Create() method to setup a stub         */
 /*      OGRDataSource object without the associated file created        */
-/*      yet.  It will be created by the CreateLayer() call.             */
+/*      yet.  It will be created by theICreateLayer() call.             */
 /************************************************************************/
 
 int OGRDGNDataSource::PreCreate( const char *pszFilename, 
@@ -179,10 +179,10 @@ int OGRDGNDataSource::PreCreate( const char *pszFilename,
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer *OGRDGNDataSource::CreateLayer( const char *pszLayerName, 
+OGRLayer *OGRDGNDataSource::ICreateLayer( const char *pszLayerName, 
                                          OGRSpatialReference *poSRS, 
                                          OGRwkbGeometryType eGeomType, 
                                          char **papszExtraOptions )
@@ -227,7 +227,7 @@ OGRLayer *OGRDGNDataSource::CreateLayer( const char *pszLayerName,
     papszOptions = CSLInsertStrings( papszOptions, 0, papszExtraOptions );
 
     b3DRequested = CSLFetchBoolean( papszOptions, "3D", 
-                                    (((int) eGeomType) & wkb25DBit) );
+                                    wkbHasZ(eGeomType) );
 
     pszSeed = CSLFetchNameValue( papszOptions, "SEED" );
     if( pszSeed )
@@ -287,14 +287,14 @@ OGRLayer *OGRDGNDataSource::CreateLayer( const char *pszLayerName,
         nCreationFlags &= ~DGNCF_USE_SEED_ORIGIN;
         if( CSLCount(papszTuple) == 3 )
         {
-            dfOriginX = atof(papszTuple[0]);
-            dfOriginY = atof(papszTuple[1]);
-            dfOriginZ = atof(papszTuple[2]);
+            dfOriginX = CPLAtof(papszTuple[0]);
+            dfOriginY = CPLAtof(papszTuple[1]);
+            dfOriginZ = CPLAtof(papszTuple[2]);
         }
         else if( CSLCount(papszTuple) == 2 )
         {
-            dfOriginX = atof(papszTuple[0]);
-            dfOriginY = atof(papszTuple[1]);
+            dfOriginX = CPLAtof(papszTuple[0]);
+            dfOriginY = CPLAtof(papszTuple[1]);
             dfOriginZ = 0.0;
         }
         else
diff --git a/ogr/ogrsf_frmts/dgn/ogrdgndriver.cpp b/ogr/ogrsf_frmts/dgn/ogrdgndriver.cpp
index d95ed3c..95d3092 100644
--- a/ogr/ogrsf_frmts/dgn/ogrdgndriver.cpp
+++ b/ogr/ogrsf_frmts/dgn/ogrdgndriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdgndriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrdgndriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRDGNDriver class.
@@ -30,39 +30,35 @@
 #include "ogr_dgn.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrdgndriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrdgndriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
-/*                          ~OGRDGNDriver()                             */
-/************************************************************************/
-
-OGRDGNDriver::~OGRDGNDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRDGNDriver::GetName()
+static int OGRDGNDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "DGN";
+    return poOpenInfo->fpL != NULL &&
+           poOpenInfo->nHeaderBytes >= 512 &&
+           DGNTestOpen(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes);
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRDGNDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRDGNDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRDGNDataSource    *poDS;
+    
+    if( !OGRDGNDriverIdentify(poOpenInfo) )
+        return NULL;
 
     poDS = new OGRDGNDataSource();
 
-    if( !poDS->Open( pszFilename, TRUE, bUpdate )
+    if( !poDS->Open( poOpenInfo->pszFilename, TRUE, (poOpenInfo->eAccess == GA_Update) )
         || poDS->GetLayerCount() == 0 )
     {
         delete poDS;
@@ -73,12 +69,15 @@ OGRDataSource *OGRDGNDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                              Create()                                */
 /************************************************************************/
 
-OGRDataSource *OGRDGNDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRDGNDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Return a new OGRDataSource()                                    */
@@ -86,7 +85,7 @@ OGRDataSource *OGRDGNDriver::CreateDataSource( const char * pszName,
     OGRDGNDataSource    *poDS = NULL;
 
     poDS = new OGRDGNDataSource();
-    
+
     if( !poDS->PreCreate( pszName, papszOptions ) )
     {
         delete poDS;
@@ -97,25 +96,47 @@ OGRDataSource *OGRDGNDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRDGNDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                          RegisterOGRDGN()                            */
 /************************************************************************/
 
 void RegisterOGRDGN()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRDGNDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "DGN" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "DGN" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Microstation DGN" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dgn" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_dgn.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='3D' type='boolean' description='whether 2D (seed_2d.dgn) or 3D (seed_3d.dgn) seed file should be used. This option is ignored if the SEED option is provided'/>"
+"  <Option name='SEED' type='string' description='Filename of seed file to use'/>"
+"  <Option name='COPY_WHOLE_SEED_FILE' type='boolean' description='whether the whole seed file should be copied. If not, only the first three elements (and potentially the color table) will be copied.' default='NO'/>"
+"  <Option name='COPY_SEED_FILE_COLOR_TABLE' type='boolean' description='whether the color table should be copied from the seed file.' default='NO'/>"
+"  <Option name='MASTER_UNIT_NAME' type='string' description='Override the master unit name from the seed file with the provided one or two character unit name.'/>"
+"  <Option name='SUB_UNIT_NAME' type='string' description='Override the master unit name from the seed file with the provided one or two character unit name.'/>"
+"  <Option name='MASTER_UNIT_NAME' type='string' description='Override the master unit name from the seed file with the provided one or two character unit name.'/>"
+"  <Option name='SUB_UNIT_NAME' type='string' description='Override the sub unit name from the seed file with the provided one or two character unit name.'/>"
+"  <Option name='SUB_UNITS_PER_MASTER_UNIT' type='int' description='Override the number of subunits per master unit. By default the seed file value is used.'/>"
+"  <Option name='UOR_PER_SUB_UNIT' type='int' description='Override the number of UORs (Units of Resolution) per sub unit. By default the seed file value is used.'/>"
+"  <Option name='ORIGIN' type='string' description='Value as x,y,z. Override the origin of the design plane. By default the origin from the seed file is used.'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>" );
+
+        poDriver->pfnOpen = OGRDGNDriverOpen;
+        poDriver->pfnIdentify = OGRDGNDriverIdentify;
+        poDriver->pfnCreate = OGRDGNDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/dgn/ogrdgnlayer.cpp b/ogr/ogrsf_frmts/dgn/ogrdgnlayer.cpp
index 0cfebbe..aecf85f 100644
--- a/ogr/ogrsf_frmts/dgn/ogrdgnlayer.cpp
+++ b/ogr/ogrsf_frmts/dgn/ogrdgnlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdgnlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrdgnlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRDGNLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_api.h"
 #include <list>
 
-CPL_CVSID("$Id: ogrdgnlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrdgnlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                           OGRDGNLayer()                              */
@@ -72,6 +72,7 @@ OGRDGNLayer::OGRDGNLayer( const char * pszName, DGNHandle hDGN,
 /*      Create the feature definition.                                  */
 /* -------------------------------------------------------------------- */
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     
     OGRFieldDefn        oField( "", OFTInteger );
@@ -233,13 +234,13 @@ void OGRDGNLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRDGNLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRDGNLayer::GetFeature( GIntBig nFeatureId )
 
 {
     OGRFeature *poFeature;
     DGNElemCore *psElement;
 
-    if( !DGNGotoElement( hDGN, nFeatureId ) )
+    if( nFeatureId > INT_MAX || !DGNGotoElement( hDGN, (int)nFeatureId ) )
         return NULL;
 
     // We should likely clear the spatial search region as it affects 
@@ -551,13 +552,13 @@ OGRFeature *OGRDGNLayer::ElementToFeature( DGNElemCore *psElement )
 
           // Add the size info in ground units.
           if( ABS(psText->height_mult) >= 6.0 )
-              sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%dg", 
+              CPLsprintf( pszOgrFS+strlen(pszOgrFS), ",s:%dg", 
                        (int) psText->height_mult );
           else if( ABS(psText->height_mult) > 0.1 )
-              sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.3fg", 
+              CPLsprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.3fg", 
                        psText->height_mult );
           else
-              sprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.12fg", 
+              CPLsprintf( pszOgrFS+strlen(pszOgrFS), ",s:%.12fg", 
                        psText->height_mult );
 
           // Add the font name. Name it MstnFont<FONTNUMBER> if not available
@@ -751,7 +752,7 @@ int OGRDGNLayer::TestCapability( const char * pszCap )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRDGNLayer::GetFeatureCount( int bForce )
+GIntBig OGRDGNLayer::GetFeatureCount( int bForce )
 
 {
 /* -------------------------------------------------------------------- */
@@ -808,12 +809,12 @@ OGRErr OGRDGNLayer::GetExtent( OGREnvelope *psExtent, CPL_UNUSED int bForce )
 
     if( !DGNGetExtents( hDGN, adfExtents ) )
         return OGRERR_FAILURE;
-    
+
     psExtent->MinX = adfExtents[0];
     psExtent->MinY = adfExtents[1];
     psExtent->MaxX = adfExtents[3];
     psExtent->MaxY = adfExtents[4];
-    
+
     return OGRERR_NONE;
 }
 
@@ -975,12 +976,12 @@ DGNElemCore **OGRDGNLayer::TranslateLabel( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /*                                                                      */
 /*      Create a new feature and write to file.                         */
 /************************************************************************/
 
-OGRErr OGRDGNLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRDGNLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     if( !bUpdate )
diff --git a/ogr/ogrsf_frmts/dods/GNUmakefile b/ogr/ogrsf_frmts/dods/GNUmakefile
index e298fdc..4aedbca 100644
--- a/ogr/ogrsf_frmts/dods/GNUmakefile
+++ b/ogr/ogrsf_frmts/dods/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrdodsdriver.o ogrdodsdatasource.o ogrdodslayer.o \
 		ogrdodssequencelayer.o ogrdodsfielddefn.o ogrdodsgrid.o
 
-CPPFLAGS	:=	-I.. $(GDAL_INCLUDE) $(CPPFLAGS) $(DODS_INC)
+CPPFLAGS	:=	-I..  $(CPPFLAGS) $(DODS_INC)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/dods/drv_dods.html b/ogr/ogrsf_frmts/dods/drv_dods.html
index 6b62f5a..db9cc84 100644
--- a/ogr/ogrsf_frmts/dods/drv_dods.html
+++ b/ogr/ogrsf_frmts/dods/drv_dods.html
@@ -27,7 +27,7 @@ into corresponding layers.  Sequences are (by default) treated as point
 layers with the point geometries picked up from lat and lon variables if
 available.  To provide more sophisticated translation of sequence, grid or
 array items into features it is necessary to provide additional information
-to OGR as DAS (dataset auxilary informaton) either from the remote server, 
+to OGR as DAS (dataset auxiliary informaton) either from the remote server, 
 or locally via the AIS mechanism.<p>
 
 A DAS definition for an OGR layer might look something like:
diff --git a/ogr/ogrsf_frmts/dods/ogr_dods.h b/ogr/ogrsf_frmts/dods/ogr_dods.h
index 99f269e..1a10707 100644
--- a/ogr/ogrsf_frmts/dods/ogr_dods.h
+++ b/ogr/ogrsf_frmts/dods/ogr_dods.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_dods.h 20634 2010-09-16 22:02:29Z rouault $
+ * $Id: ogr_dods.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/DODS driver.
@@ -199,9 +199,9 @@ public:
                                               AttrTable *poAttrInfo );
     virtual             ~OGRDODSSequenceLayer();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 };
 
 /************************************************************************/
@@ -287,9 +287,9 @@ public:
                                          AttrTable *poAttrInfo );
     virtual             ~OGRDODSGridLayer();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
 };
 
diff --git a/ogr/ogrsf_frmts/dods/ogrdodsdriver.cpp b/ogr/ogrsf_frmts/dods/ogrdodsdriver.cpp
index e4c9a32..9f2c5cd 100644
--- a/ogr/ogrsf_frmts/dods/ogrdodsdriver.cpp
+++ b/ogr/ogrsf_frmts/dods/ogrdodsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdodsdriver.cpp 12396 2007-10-13 10:02:17Z rouault $
+ * $Id: ogrdodsdriver.cpp 27597 2014-08-22 17:15:49Z rouault $
  *
  * Project:  OGR/DODS Interface
  * Purpose:  Implements OGRDODSDriver class.
@@ -30,7 +30,7 @@
 #include "ogr_dods.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrdodsdriver.cpp 12396 2007-10-13 10:02:17Z rouault $");
+CPL_CVSID("$Id: ogrdodsdriver.cpp 27597 2014-08-22 17:15:49Z rouault $");
 
 /************************************************************************/
 /*                            ~OGRDODSDriver()                            */
@@ -48,7 +48,7 @@ OGRDODSDriver::~OGRDODSDriver()
 const char *OGRDODSDriver::GetName()
 
 {
-    return "DODS";
+    return "OGR_DODS";
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/dods/ogrdodsgrid.cpp b/ogr/ogrsf_frmts/dods/ogrdodsgrid.cpp
index fdd6db6..aa31e97 100644
--- a/ogr/ogrsf_frmts/dods/ogrdodsgrid.cpp
+++ b/ogr/ogrsf_frmts/dods/ogrdodsgrid.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdodsgrid.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrdodsgrid.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGR/DODS Interface
  * Purpose:  Implements OGRDODSGridLayer class, which implements the
@@ -32,7 +32,7 @@
 #include "ogr_dods.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrdodsgrid.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrdodsgrid.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRDODSGridLayer()                          */
@@ -431,7 +431,7 @@ int OGRDODSGridLayer::ArrayEntryToField( Array *poArray, void *pRawData,
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRDODSGridLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRDODSGridLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( nFeatureId < 0 || nFeatureId >= nMaxRawIndex )
@@ -589,7 +589,7 @@ int OGRDODSGridLayer::ProvideDataDDS()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRDODSGridLayer::GetFeatureCount( int bForce )
+GIntBig OGRDODSGridLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom == NULL && m_poAttrQuery == NULL )
diff --git a/ogr/ogrsf_frmts/dods/ogrdodslayer.cpp b/ogr/ogrsf_frmts/dods/ogrdodslayer.cpp
index cede19c..9056a78 100644
--- a/ogr/ogrsf_frmts/dods/ogrdodslayer.cpp
+++ b/ogr/ogrsf_frmts/dods/ogrdodslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdodslayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrdodslayer.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OGR/DODS Interface
  * Purpose:  Implements OGRDODSLayer class.
@@ -30,7 +30,7 @@
 #include "ogr_dods.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrdodslayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrdodslayer.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRDODSLayer()                            */
@@ -89,10 +89,10 @@ OGRDODSLayer::OGRDODSLayer( OGRDODSDataSource *poDSIn,
         if( poLayerExt != NULL )
         {
             bKnowExtent = TRUE;
-            sExtent.MinX = atof(poLayerExt->get_attr("x_min").c_str());
-            sExtent.MaxX = atof(poLayerExt->get_attr("x_max").c_str());
-            sExtent.MinY = atof(poLayerExt->get_attr("y_min").c_str());
-            sExtent.MaxY = atof(poLayerExt->get_attr("y_max").c_str());
+            sExtent.MinX = CPLAtof(poLayerExt->get_attr("x_min").c_str());
+            sExtent.MaxX = CPLAtof(poLayerExt->get_attr("x_max").c_str());
+            sExtent.MinY = CPLAtof(poLayerExt->get_attr("y_min").c_str());
+            sExtent.MaxY = CPLAtof(poLayerExt->get_attr("y_max").c_str());
         }
 
     }
diff --git a/ogr/ogrsf_frmts/dods/ogrdodssequencelayer.cpp b/ogr/ogrsf_frmts/dods/ogrdodssequencelayer.cpp
index 2f5e7a3..e8dcd53 100644
--- a/ogr/ogrsf_frmts/dods/ogrdodssequencelayer.cpp
+++ b/ogr/ogrsf_frmts/dods/ogrdodssequencelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdodssequencelayer.cpp 15172 2008-08-20 17:37:27Z rouault $
+ * $Id: ogrdodssequencelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGR/DODS Interface
  * Purpose:  Implements OGRDODSSequenceLayer class, which implements the
@@ -32,7 +32,7 @@
 #include "ogr_dods.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrdodssequencelayer.cpp 15172 2008-08-20 17:37:27Z rouault $");
+CPL_CVSID("$Id: ogrdodssequencelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                        OGRDODSSequenceLayer()                        */
@@ -395,7 +395,7 @@ double OGRDODSSequenceLayer::BaseTypeToDouble( BaseType *poBT )
           double dfResult;
 
           poBT->buf2val( (void **) &poStrVal );
-          dfResult = atof(poStrVal->c_str());
+          dfResult = CPLAtof(poStrVal->c_str());
           delete poStrVal;
           return dfResult;
       }
@@ -430,7 +430,7 @@ double OGRDODSSequenceLayer::GetFieldValueAsDouble( OGRDODSFieldDefn *poFDefn,
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRDODSSequenceLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRDODSSequenceLayer::GetFeature( GIntBig nFeatureId )
 
 {
 /* -------------------------------------------------------------------- */
@@ -849,7 +849,7 @@ OGRFeature *OGRDODSSequenceLayer::GetFeature( long nFeatureId )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRDODSSequenceLayer::GetFeatureCount( int bForce )
+GIntBig OGRDODSSequenceLayer::GetFeatureCount( int bForce )
 
 {
     if( !bDataLoaded && !bForce )
diff --git a/ogr/ogrsf_frmts/dwg/GNUmakefile b/ogr/ogrsf_frmts/dwg/GNUmakefile
index e25c753..273a01f 100644
--- a/ogr/ogrsf_frmts/dwg/GNUmakefile
+++ b/ogr/ogrsf_frmts/dwg/GNUmakefile
@@ -35,7 +35,7 @@ OBJ	=	ogrdwgdriver.o ogrdwgdatasource.o ogrdwglayer.o \
 		ogrdwg_dimension.o ogrdwg_hatch.o ogrdwgblockslayer.o \
 		ogrdwg_blockmap.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I../dxf $(TDXXFLAGS) $(CPPFLAGS)
+CPPFLAGS	:=	 -I../dxf $(TDXXFLAGS) $(CPPFLAGS)
 
 PLUGIN_SO	=	ogr_DWG.so
 
diff --git a/ogr/ogrsf_frmts/dwg/ogrdwg_dimension.cpp b/ogr/ogrsf_frmts/dwg/ogrdwg_dimension.cpp
index ebe8a30..eec2576 100644
--- a/ogr/ogrsf_frmts/dwg/ogrdwg_dimension.cpp
+++ b/ogr/ogrsf_frmts/dwg/ogrdwg_dimension.cpp
@@ -297,7 +297,7 @@ the approach is as above in all these cases.
 /*      feature for the next feature read.                              */
 /* -------------------------------------------------------------------- */
 
-    // a single space supresses labelling.
+    // a single space suppresses labelling.
     if( osText == " " )
         return poFeature;
 
@@ -320,7 +320,7 @@ the approach is as above in all these cases.
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -329,7 +329,7 @@ the approach is as above in all these cases.
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -375,7 +375,7 @@ void OGRDWGLayer::FormatDimension( CPLString &osText, double dfValue )
     // for example.  
 
     sprintf(szFormat, "%%.%df", nPrecision );
-    snprintf(szBuffer, sizeof(szBuffer), szFormat, dfValue);
+    CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, dfValue);
     char* pszComma = strchr(szBuffer, ',');
     if (pszComma)
         *pszComma = '.';
diff --git a/ogr/ogrsf_frmts/dwg/ogrdwgdriver.cpp b/ogr/ogrsf_frmts/dwg/ogrdwgdriver.cpp
index c401a0f..8650d80 100644
--- a/ogr/ogrsf_frmts/dwg/ogrdwgdriver.cpp
+++ b/ogr/ogrsf_frmts/dwg/ogrdwgdriver.cpp
@@ -146,6 +146,12 @@ int OGRDWGDriver::TestCapability( const char * pszCap )
 void RegisterOGRDWG()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRDWGDriver );
+    OGRSFDriver* poDriver = new OGRDWGDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "AutoCAD DWG" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dwg" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_dwg.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
 }
 
diff --git a/ogr/ogrsf_frmts/dwg/ogrdwglayer.cpp b/ogr/ogrsf_frmts/dwg/ogrdwglayer.cpp
index 110462e..00c3741 100644
--- a/ogr/ogrsf_frmts/dwg/ogrdwglayer.cpp
+++ b/ogr/ogrsf_frmts/dwg/ogrdwglayer.cpp
@@ -67,6 +67,7 @@ OGRDWGLayer::OGRDWGLayer( OGRDWGDataSource *poDS )
     iNextFID = 0;
 
     poFeatureDefn = new OGRFeatureDefn( "entities" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poDS->AddStandardFields( poFeatureDefn );
@@ -396,7 +397,7 @@ void OGRDWGLayer::PrepareLineStyle( OGRFeature *poFeature )
     if( dfWeight > 0.0 )
     {
         char szBuffer[64];
-        snprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
         char* pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -496,7 +497,7 @@ OGRFeature *OGRDWGLayer::TranslateMTEXT( OdDbEntityPtr poEntity )
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -505,7 +506,7 @@ OGRFeature *OGRDWGLayer::TranslateMTEXT( OdDbEntityPtr poEntity )
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -628,7 +629,7 @@ OGRFeature *OGRDWGLayer::TranslateTEXT( OdDbEntityPtr poEntity )
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
@@ -637,7 +638,7 @@ OGRFeature *OGRDWGLayer::TranslateTEXT( OdDbEntityPtr poEntity )
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         pszComma = strchr(szBuffer, ',');
         if (pszComma)
             *pszComma = '.';
diff --git a/ogr/ogrsf_frmts/dxf/GNUmakefile b/ogr/ogrsf_frmts/dxf/GNUmakefile
index 31e8ea1..ff505e8 100644
--- a/ogr/ogrsf_frmts/dxf/GNUmakefile
+++ b/ogr/ogrsf_frmts/dxf/GNUmakefile
@@ -8,7 +8,7 @@ OBJ	=	ogrdxfdriver.o ogrdxfdatasource.o ogrdxflayer.o \
 		ogrdxfblockswriterlayer.o ogrdxf_hatch.o \
 		ogr_autocad_services.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/dxf/drv_dxf.html b/ogr/ogrsf_frmts/dxf/drv_dxf.html
index e234d8c..e4752ea 100644
--- a/ogr/ogrsf_frmts/dxf/drv_dxf.html
+++ b/ogr/ogrsf_frmts/dxf/drv_dxf.html
@@ -32,9 +32,8 @@ The following element types are supported:<p>
 <ul>
 <li> POINT: Produces a simple point geometry feature.
 <li> MTEXT, TEXT: Produces a point feature with LABEL style information.
-<li> LINE, POLYLINE, LWPOLYLINE: translated as a LINESTRING or POLYGON 
-depending on whether it is closed. Rounded polylines (those with their 
-vertices' budge attributes set) will be tesselated.
+<li> LINE, POLYLINE, LWPOLYLINE: translated as a LINESTRING. Rounded 
+polylines (those with their vertices' budge attributes set) will be tesselated.
 Single-vertex polylines are translated to POINT.
 <li> CIRCLE, ELLIPSE, ARC:  Translated as a LINESTRING, tesselating the 
 arc into line segments. 
@@ -47,6 +46,7 @@ DXF_MERGE_BLOCK_GEOMETRIES config option may be set to FALSE.
 leaders, and a feature with the dimension label.
 <li> HATCH: Line and arc boundaries are collected as a polygon geometry, but 
 no effort is currently made to represent the fill style of HATCH entities.
+<li> 3DFACE, SOLID: Translated as POLYGON.
 
 </ul>
 
@@ -118,17 +118,21 @@ on the styling information.<p>
 
 Point features without LABEL styling are written as POINT entities.<p>
 
-LineString, MultiLineString, Polygon and MultiPolygons are written as one or
-more LWPOLYLINE entities, closed in the case of polygon rings.  An effort is
+LineString and MultiLineString features are written as one or more 
+LWPOLYLINE entities, closed in the case of polygon rings.  An effort is
 made to preserve line width and color.<p>
 
+Polygon and MultiPolygon features are written as HATCH entities.
+
 The dataset creation supports the following dataset creation options:<p>
 
 <ul>
 
-<li> <b>HEADER=</b><i>filename</i>: Override the header file used - in place of header.dxf. <p>
+<li> <b>HEADER=</b><i>filename</i>: Override the header file used - in place 
+of header.dxf located in the GDAL_DATA directory.
 
-<li> <b>TRAILER=</b><i>filename</i>: Override the trailer file used - in place of trailer.dxf.<p>
+<li> <b>TRAILER=</b><i>filename</i>: Override the trailer file used - in place 
+of trailer.dxf located in the GDAL_DATA directory. <p>
 
 </ul>
 
@@ -189,5 +193,15 @@ The intention is that "dot dash" style patterns will be preserved when written
 to DXF and that specific linetypes can be predefined in the header template,
 and referenced using the Linetype field if desired.<p>
 
+<h3>Units</h2>
+
+At the moment GDAL writes DXF to report the the measurement units as "English - Inches". 
+For changing the units edit $MEASUREMENT and $INSUNITS variables in the header template.
+
+<h3>See also</h2>
+
+<a href="http://www.autodesk.com/techpubs/autocad/acad2000/dxf/">AutoCAD 2000 DXF Reference</a><p>
+
+<a href="http://www.autodesk.com/techpubs/autocad/acad2000/dxf/header_section_group_codes_dxf_02.htm">DXF header reference</a>
 </body>
 </html>
diff --git a/ogr/ogrsf_frmts/dxf/ogr_dxf.h b/ogr/ogrsf_frmts/dxf/ogr_dxf.h
index 63350b0..187fc54 100644
--- a/ogr/ogrsf_frmts/dxf/ogr_dxf.h
+++ b/ogr/ogrsf_frmts/dxf/ogr_dxf.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_dxf.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_dxf.h 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  DXF Translator
  * Purpose:  Definition of classes for OGR .dxf driver.
@@ -296,7 +296,7 @@ class OGRDXFWriterLayer : public OGRLayer
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
     int                 TestCapability( const char * );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 
@@ -323,7 +323,7 @@ class OGRDXFBlocksWriterLayer : public OGRLayer
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
     int                 TestCapability( const char * );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 
@@ -387,7 +387,7 @@ class OGRDXFWriterDS : public OGRDataSource
 
     int                 TestCapability( const char * );
 
-    OGRLayer           *CreateLayer( const char *pszName, 
+    OGRLayer           *ICreateLayer( const char *pszName, 
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
@@ -399,22 +399,4 @@ class OGRDXFWriterDS : public OGRDataSource
     void                UpdateExtent( OGREnvelope* psEnvelope );
 };
 
-/************************************************************************/
-/*                             OGRDXFDriver                             */
-/************************************************************************/
-
-class OGRDXFDriver : public OGRSFDriver
-{
-  public:
-                ~OGRDXFDriver();
-
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    int         TestCapability( const char * );
-
-    OGRDataSource      *CreateDataSource( const char *pszName,
-                                          char ** = NULL );
-};
-
-
 #endif /* ndef _OGR_DXF_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp b/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp
index 9e31d7b..717bd5d 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxf_dimension.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxf_dimension.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrdxf_dimension.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  DXF Translator
  * Purpose:  Implements translation support for DIMENSION elements as a part
@@ -32,7 +32,7 @@
 #include "ogr_dxf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrdxf_dimension.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrdxf_dimension.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 #ifndef PI
 #define PI  3.14159265358979323846
@@ -307,7 +307,7 @@ the approach is as above in all these cases.
 /*      feature for the next feature read.                              */
 /* -------------------------------------------------------------------- */
 
-    // a single space supresses labelling.
+    // a single space suppresses labelling.
     if( osText == " " )
         return poFeature;
 
@@ -324,25 +324,18 @@ the approach is as above in all these cases.
 
     CPLString osStyle;
     char szBuffer[64];
-    char* pszComma;
 
     osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",p:5",osText.c_str());
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         osStyle += CPLString().Printf(",a:%s", szBuffer);
     }
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         osStyle += CPLString().Printf(",s:%sg", szBuffer);
     }
 
@@ -376,9 +369,6 @@ void OGRDXFLayer::FormatDimension( CPLString &osText, double dfValue )
     // for example.  
 
     sprintf(szFormat, "%%.%df", nPrecision );
-    snprintf(szBuffer, sizeof(szBuffer), szFormat, dfValue);
-    char* pszComma = strchr(szBuffer, ',');
-    if (pszComma)
-        *pszComma = '.';
+    CPLsnprintf(szBuffer, sizeof(szBuffer), szFormat, dfValue);
     osText = szBuffer;
 }
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp b/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp
index 19f29ca..ab841ac 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxf_hatch.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxf_hatch.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrdxf_hatch.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  DXF Translator
  * Purpose:  Implements translation support for HATCH elements as part
@@ -35,7 +35,7 @@
 
 #include "ogrdxf_polyline_smooth.h"
 
-CPL_CVSID("$Id: ogrdxf_hatch.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrdxf_hatch.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #ifndef PI
 #define PI  3.14159265358979323846
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp
index c052fd4..3239b9d 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxfblockswriterlayer.cpp
@@ -118,13 +118,13 @@ OGRErr OGRDXFBlocksWriterLayer::CreateField( OGRFieldDefn *poField,
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /*                                                                      */
 /*      We just stash a copy of the features for later writing to       */
 /*      the blocks section of the header.                               */
 /************************************************************************/
 
-OGRErr OGRDXFBlocksWriterLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRDXFBlocksWriterLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     apoBlocks.push_back( poFeature->Clone() );
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp
index a2afab1..ece823d 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxfdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrdxfdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  DXF Translator
  * Purpose:  Implements OGRDXFDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrdxfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrdxfdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          OGRDXFDataSource()                          */
@@ -100,9 +100,6 @@ OGRLayer *OGRDXFDataSource::GetLayer( int iLayer )
 int OGRDXFDataSource::Open( const char * pszFilename, int bHeaderOnly )
 
 {
-    if( !EQUAL(CPLGetExtension(pszFilename),"dxf") )
-        return FALSE;
-
     osEncoding = CPL_ENC_ISO8859_1;
 
     osName = pszFilename;
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp
index 6b1385a..de4394f 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxfdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxfdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrdxfdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  DXF Translator
  * Purpose:  Implements OGRDXFDriver.
@@ -30,36 +30,32 @@
 #include "ogr_dxf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrdxfdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrdxfdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
-/*                          ~OGRDXFDriver()                          */
+/*                       OGRDXFDriverIdentify()                         */
 /************************************************************************/
 
-OGRDXFDriver::~OGRDXFDriver()
+static int OGRDXFDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
+    return poOpenInfo->fpL != NULL &&
+           EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"dxf");
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRDXFDriver::GetName()
+static GDALDataset *OGRDXFDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    return "DXF";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
+    if( !OGRDXFDriverIdentify(poOpenInfo) )
+        return NULL;
 
-OGRDataSource *OGRDXFDriver::Open( const char * pszFilename, CPL_UNUSED int bUpdate )
-{
     OGRDXFDataSource   *poDS = new OGRDXFDataSource();
 
-    if( !poDS->Open( pszFilename ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -69,12 +65,15 @@ OGRDataSource *OGRDXFDriver::Open( const char * pszFilename, CPL_UNUSED int bUpd
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                              Create()                                */
 /************************************************************************/
 
-OGRDataSource *OGRDXFDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRDXFDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     OGRDXFWriterDS *poDS = new OGRDXFWriterDS();
 
@@ -88,25 +87,42 @@ OGRDataSource *OGRDXFDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                           RegisterOGRDXF()                           */
 /************************************************************************/
 
-int OGRDXFDriver::TestCapability( const char * pszCap )
+void RegisterOGRDXF()
 
 {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
+    GDALDriver  *poDriver;
 
-/************************************************************************/
-/*                           RegisterOGRDXF()                           */
-/************************************************************************/
+    if( GDALGetDriverByName( "DXF" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
-void RegisterOGRDXF()
+        poDriver->SetDescription( "DXF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "AutoCAD DXF" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dxf" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_dxf.html" );
 
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRDXFDriver );
-}
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='HEADER' type='string' description='Template header file' default='header.dxf'/>"
+"  <Option name='TRAILER' type='string' description='Template trailer file' default='trailer.dxf'/>"
+"  <Option name='FIRST_ENTITY' type='int' description='Identifier of first entity'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+                                            "<LayerCreationOptionList/>" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
 
+        poDriver->pfnOpen = OGRDXFDriverOpen;
+        poDriver->pfnIdentify = OGRDXFDriverIdentify;
+        poDriver->pfnCreate = OGRDXFDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp b/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp
index 51b3f53..eea57e1 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxflayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxflayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrdxflayer.cpp 27945 2014-11-11 01:33:15Z rouault $
  *
  * Project:  DXF Translator
  * Purpose:  Implements OGRDXFLayer class.
@@ -33,7 +33,7 @@
 #include "ogrdxf_polyline_smooth.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: ogrdxflayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrdxflayer.cpp 27945 2014-11-11 01:33:15Z rouault $");
 
 #ifndef PI
 #define PI  3.14159265358979323846
@@ -63,6 +63,8 @@ OGRDXFLayer::OGRDXFLayer( OGRDXFDataSource *poDS )
         OGRFieldDefn  oBlockAngleField( "BlockAngle", OFTReal );
         poFeatureDefn->AddFieldDefn( &oBlockAngleField );
     }
+    
+    SetDescription( poFeatureDefn->GetName() );
 }
 
 /************************************************************************/
@@ -265,10 +267,7 @@ void OGRDXFLayer::PrepareLineStyle( OGRFeature *poFeature )
     if( dfWeight > 0.0 )
     {
         char szBuffer[64];
-        snprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
-        char* pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
         osStyle += CPLString().Printf( ",w:%sg", szBuffer );
     }
 
@@ -526,25 +525,18 @@ OGRFeature *OGRDXFLayer::TranslateMTEXT()
 /* -------------------------------------------------------------------- */
     CPLString osStyle;
     char szBuffer[64];
-    char* pszComma;
 
     osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         osStyle += CPLString().Printf(",a:%s", szBuffer);
     }
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         osStyle += CPLString().Printf(",s:%sg", szBuffer);
     }
 
@@ -696,25 +688,18 @@ OGRFeature *OGRDXFLayer::TranslateTEXT()
 /* -------------------------------------------------------------------- */
     CPLString osStyle;
     char szBuffer[64];
-    char* pszComma;
 
     osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
 
     if( dfAngle != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
         osStyle += CPLString().Printf(",a:%s", szBuffer);
     }
 
     if( dfHeight != 0.0 )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
-        pszComma = strchr(szBuffer, ',');
-        if (pszComma)
-            *pszComma = '.';
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
         osStyle += CPLString().Printf(",s:%sg", szBuffer);
     }
 
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp
index 6cd13de..9d61abb 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxfwriterds.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrdxfwriterds.cpp 27945 2014-11-11 01:33:15Z rouault $
  *
  * Project:  DXF Translator
  * Purpose:  Implements OGRDXFWriterDS - the OGRDataSource class used for
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrdxfwriterds.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrdxfwriterds.cpp 27945 2014-11-11 01:33:15Z rouault $");
 
 /************************************************************************/
 /*                          OGRDXFWriterDS()                          */
@@ -128,7 +128,8 @@ int OGRDXFWriterDS::TestCapability( const char * pszCap )
 
 {
     if( EQUAL(pszCap,ODsCCreateLayer) )
-        return TRUE;
+        // Unable to have more than one OGR entities layer in a DXF file, with one options blocks layer.
+        return poBlocksLayer == NULL || poLayer == NULL;
     else
         return FALSE;
 }
@@ -255,10 +256,10 @@ int OGRDXFWriterDS::Open( const char * pszFilename, char **papszOptions )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer *OGRDXFWriterDS::CreateLayer( const char *pszName, 
+OGRLayer *OGRDXFWriterDS::ICreateLayer( const char *pszName, 
                                        OGRSpatialReference *, 
                                        OGRwkbGeometryType, 
                                        char ** )
@@ -312,10 +313,7 @@ static int WriteValue( VSILFILE *fp, int nCode, double dfValue )
 {
     char szLinePair[64];
 
-    snprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue );
-    char* pszComma = strchr(szLinePair, ',');
-    if (pszComma)
-        *pszComma = '.';
+    CPLsnprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue );
     size_t nLen = strlen(szLinePair);
     if( VSIFWriteL( szLinePair, 1, nLen, fp ) != nLen )
     {
diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp
index a189760..de8c832 100644
--- a/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp
+++ b/ogr/ogrsf_frmts/dxf/ogrdxfwriterlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrdxfwriterlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrdxfwriterlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  DXF Translator
  * Purpose:  Implements OGRDXFWriterLayer - the OGRLayer class used for
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_featurestyle.h"
 
-CPL_CVSID("$Id: ogrdxfwriterlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrdxfwriterlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 #ifndef PI
 #define PI  3.14159265358979323846
@@ -189,10 +189,7 @@ int OGRDXFWriterLayer::WriteValue( int nCode, double dfValue )
 {
     char szLinePair[64];
 
-    snprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue );
-    char* pszComma = strchr(szLinePair, ',');
-    if (pszComma)
-        *pszComma = '.';
+    CPLsnprintf(szLinePair, sizeof(szLinePair), "%3d\n%.15g\n", nCode, dfValue );
     size_t nLen = strlen(szLinePair);
 
     return VSIFWriteL( szLinePair, 
@@ -215,7 +212,7 @@ OGRErr OGRDXFWriterLayer::WriteCore( OGRFeature *poFeature )
 /*      Also, for reasons I don't understand these ids seem to have     */
 /*      to start somewhere around 0x50 hex (80 decimal).                */
 /* -------------------------------------------------------------------- */
-    poFeature->SetFID( poDS->WriteEntityID(fp,poFeature->GetFID()) );
+    poFeature->SetFID( poDS->WriteEntityID(fp,(int)poFeature->GetFID()) );
 
 /* -------------------------------------------------------------------- */
 /*      For now we assign everything to the default layer - layer       */
@@ -518,7 +515,7 @@ OGRErr OGRDXFWriterLayer::WriteTEXT( OGRFeature *poFeature )
 /************************************************************************/
 /*                     PrepareLineTypeDefinition()                      */
 /************************************************************************/
-CPLString 
+CPLString
 OGRDXFWriterLayer::PrepareLineTypeDefinition( CPL_UNUSED OGRFeature *poFeature,
                                               OGRStyleTool *poTool )
 {
@@ -526,7 +523,7 @@ OGRDXFWriterLayer::PrepareLineTypeDefinition( CPL_UNUSED OGRFeature *poFeature,
     OGRStylePen *poPen = (OGRStylePen *) poTool;
     GBool  bDefault;
     const char *pszPattern;
-    
+
 /* -------------------------------------------------------------------- */
 /*      Fetch pattern.                                                  */
 /* -------------------------------------------------------------------- */
@@ -568,7 +565,7 @@ OGRDXFWriterLayer::PrepareLineTypeDefinition( CPL_UNUSED OGRFeature *poFeature,
         
         osDef += osDXFEntry;
 
-        dfTotalLength += atof(osAmount);
+        dfTotalLength += CPLAtof(osAmount);
     }
 
 /* -------------------------------------------------------------------- */
@@ -1093,10 +1090,10 @@ OGRErr OGRDXFWriterLayer::WriteHATCH( OGRFeature *poFeature,
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRDXFWriterLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRDXFWriterLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     OGRGeometry *poGeom = poFeature->GetGeometryRef();
diff --git a/ogr/ogrsf_frmts/edigeo/GNUmakefile b/ogr/ogrsf_frmts/edigeo/GNUmakefile
index 6f2cc94..7d13656 100644
--- a/ogr/ogrsf_frmts/edigeo/GNUmakefile
+++ b/ogr/ogrsf_frmts/edigeo/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogredigeodriver.o ogredigeodatasource.o ogredigeolayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/edigeo/drv_edigeo.html b/ogr/ogrsf_frmts/edigeo/drv_edigeo.html
index c6addb1..3d2ca6b 100644
--- a/ogr/ogrsf_frmts/edigeo/drv_edigeo.html
+++ b/ogr/ogrsf_frmts/edigeo/drv_edigeo.html
@@ -22,7 +22,7 @@ The driver must be provided with the .THF file describing the EDIGEO exchange an
 read the associated .DIC, .GEO, .SCD, .QAL and .VEC files.<p>
 
 In order the SRS of the layers to be correctly built, the IGNF file that contains
-the defintion of IGN SRS must be placed in the directory of PROJ.4 ressource files.<p>
+the defintion of IGN SRS must be placed in the directory of PROJ.4 resource files.<p>
 
 The whole set of files will be parsed into memory. This may be a limitation if dealing with
 big EDIGEO exchanges.<p>
@@ -56,7 +56,7 @@ according to the value of xxx=OBJ_OBJ_LNK_LAYER. This can be disabled by setting
 <ul>
 <li> <a href="http://georezo.net/wiki/main/donnees/edigeo">Introduction to the EDIGEO standard</a> (in French)
 <li> <a href="http://georezo.net/wiki/_media/main/geomatique/norme_edigeo.zip">EDIGEO standard - AFNOR NF Z 52000</a> (in French)
-<li> <a href="http://www.craig.fr/contenu/ressources/dossiers/pci/pdf/EDIGeO_PCI.pdf">Standard d'échange des objets du PCI selon la norme EDIGEO</a> (in French)
+<li> <a href="http://www.craig.fr/contenu/resources/dossiers/pci/pdf/EDIGeO_PCI.pdf">Standard d'échange des objets du PCI selon la norme EDIGEO</a> (in French)
 <li> <a href="http://www.cadastre.gouv.fr">Homepage of the French Digital Cadastral Plan</a> (in French)
 <li> <a href="http://docs.codehaus.org/pages/viewpage.action?pageId=77692976">Geotools EDIGEO module description</a> (in English)
 <li> <a href="http://svn.geotools.org/trunk/modules/unsupported/edigeo/src/test/resources/org/geotools/data/edigeo/test-data/">Sample of EDIGEO data</a>
diff --git a/ogr/ogrsf_frmts/edigeo/ogr_edigeo.h b/ogr/ogrsf_frmts/edigeo/ogr_edigeo.h
index 7ed2b9d..1a11f9c 100644
--- a/ogr/ogrsf_frmts/edigeo/ogr_edigeo.h
+++ b/ogr/ogrsf_frmts/edigeo/ogr_edigeo.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_edigeo.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_edigeo.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  EDIGEO Translator
  * Purpose:  Definition of classes for OGR .edigeo driver.
@@ -66,8 +66,8 @@ class OGREDIGEOLayer : public OGRLayer
 
     virtual void                ResetReading();
     virtual OGRFeature *        GetNextFeature();
-    virtual OGRFeature *        GetFeature(long nFID);
-    virtual int                 GetFeatureCount( int bForce );
+    virtual OGRFeature *        GetFeature(GIntBig nFID);
+    virtual GIntBig             GetFeatureCount( int bForce );
 
     virtual OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -228,8 +228,7 @@ class OGREDIGEODataSource : public OGRDataSource
                         OGREDIGEODataSource();
                         ~OGREDIGEODataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -241,19 +240,5 @@ class OGREDIGEODataSource : public OGRDataSource
     int                         HasUTF8ContentOnly() { return bHasUTF8ContentOnly; }
 };
 
-/************************************************************************/
-/*                           OGREDIGEODriver                            */
-/************************************************************************/
-
-class OGREDIGEODriver : public OGRSFDriver
-{
-  public:
-                ~OGREDIGEODriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
 
 #endif /* ndef _OGR_EDIGEO_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/edigeo/ogredigeodatasource.cpp b/ogr/ogrsf_frmts/edigeo/ogredigeodatasource.cpp
index b4669e5..0577b3b 100644
--- a/ogr/ogrsf_frmts/edigeo/ogredigeodatasource.cpp
+++ b/ogr/ogrsf_frmts/edigeo/ogredigeodatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogredigeodatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogredigeodatasource.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  EDIGEO Translator
  * Purpose:  Implements OGREDIGEODataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogredigeodatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogredigeodatasource.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 #ifndef M_PI
 # define M_PI  3.1415926535897932384626433832795
@@ -61,7 +61,7 @@ OGREDIGEODataSource::OGREDIGEODataSource()
 
     iATR = iDI3 = iDI4 = iHEI = iFON = -1;
     iATR_VAL = iANGLE = iSIZE = iOBJ_LNK = iOBJ_LNK_LAYER = -1;
-    dfSizeFactor = atof(CPLGetConfigOption("OGR_EDIGEO_FONT_SIZE_FACTOR", "2"));
+    dfSizeFactor = CPLAtof(CPLGetConfigOption("OGR_EDIGEO_FONT_SIZE_FACTOR", "2"));
     if (dfSizeFactor <= 0 || dfSizeFactor >= 100)
         dfSizeFactor = 2;
 
@@ -270,7 +270,7 @@ int OGREDIGEODataSource::ReadGEO()
             poSRS->importFromProj4("+proj=lcc +lat_1=44 +lat_2=49 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS81 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs");
         else
         {
-            CPLDebug("EDIGEO", "Cannot resolve %s SRS. Check that the IGNF file is in the directory of PROJ.4 ressource files", osREL.c_str());
+            CPLDebug("EDIGEO", "Cannot resolve %s SRS. Check that the IGNF file is in the directory of PROJ.4 resource files", osREL.c_str());
             delete poSRS;
             poSRS = NULL;
         }
@@ -316,10 +316,10 @@ int OGREDIGEODataSource::ReadGEN()
     if (CSLCount(papszTokens1) == 2 && CSLCount(papszTokens2) == 2)
     {
         bExtentValid = TRUE;
-        dfMinX = atof(papszTokens1[0]);
-        dfMinY = atof(papszTokens1[1]);
-        dfMaxX = atof(papszTokens2[0]);
-        dfMaxY = atof(papszTokens2[1]);
+        dfMinX = CPLAtof(papszTokens1[0]);
+        dfMinY = CPLAtof(papszTokens1[1]);
+        dfMaxX = CPLAtof(papszTokens2[0]);
+        dfMaxY = CPLAtof(papszTokens2[1]);
     }
     CSLDestroy(papszTokens1);
     CSLDestroy(papszTokens2);
@@ -771,8 +771,8 @@ skip_read_next_line:
             const char* pszY = strchr(pszLine+8, ';');
             if (pszY)
             {
-                double dfX = atof(pszLine + 8);
-                double dfY = atof(pszY + 1);
+                double dfX = CPLAtof(pszLine + 8);
+                double dfY = CPLAtof(pszY + 1);
                 aXY.push_back(xyPairType (dfX, dfY));
             }
         }
@@ -1349,22 +1349,11 @@ static int OGREDIGEOSortForQGIS(const void* a, const void* b)
 /*                                Open()                                */
 /************************************************************************/
 
-int OGREDIGEODataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGREDIGEODataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
-/* -------------------------------------------------------------------- */
-/*      Does this appear to be a .THF file?                             */
-/* -------------------------------------------------------------------- */
-    if( !EQUAL(CPLGetExtension(pszFilename), "thf") )
-        return FALSE;
-
     fpTHF = VSIFOpenL(pszFilename, "rb");
     if (fpTHF == NULL)
         return FALSE;
@@ -1568,4 +1557,3 @@ void OGREDIGEODataSource::CreateLabelLayers()
 
     poLayer->ResetReading();
 }
-
diff --git a/ogr/ogrsf_frmts/edigeo/ogredigeodriver.cpp b/ogr/ogrsf_frmts/edigeo/ogredigeodriver.cpp
index dd0d275..91caf42 100644
--- a/ogr/ogrsf_frmts/edigeo/ogredigeodriver.cpp
+++ b/ogr/ogrsf_frmts/edigeo/ogredigeodriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogredigeodriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogredigeodriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  EDIGEO Translator
  * Purpose:  Implements OGREDIGEODriver.
@@ -30,41 +30,37 @@
 #include "ogr_edigeo.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogredigeodriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogredigeodriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGREDIGEO();
 
 // g++ -fPIC -g -Wall ogr/ogrsf_frmts/edigeo/*.cpp -shared -o ogr_EDIGEO.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/generic -Iogr/ogrsf_frmts/edigeo -L. -lgdal
 
 /************************************************************************/
-/*                         ~OGREDIGEODriver()                           */
+/*                        OGREDIGEODriverIdentify()                     */
 /************************************************************************/
 
-OGREDIGEODriver::~OGREDIGEODriver()
+static int OGREDIGEODriverIdentify( GDALOpenInfo * poOpenInfo )
 
 {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGREDIGEODriver::GetName()
-
-{
-    return "EDIGEO";
+    return poOpenInfo->fpL != NULL &&
+           EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "thf");
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGREDIGEODriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGREDIGEODriverOpen( GDALOpenInfo * poOpenInfo )
 
 {
+    if( poOpenInfo->eAccess == GA_Update ||
+        !OGREDIGEODriverIdentify(poOpenInfo) )
+        return NULL;
+
     OGREDIGEODataSource   *poDS = new OGREDIGEODataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -74,21 +70,32 @@ OGRDataSource *OGREDIGEODriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGREDIGEODriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGREDIGEO()                        */
 /************************************************************************/
 
 void RegisterOGREDIGEO()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGREDIGEODriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "EDIGEO" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "EDIGEO" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "French EDIGEO exchange format" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "thf" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_edigeo.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGREDIGEODriverOpen;
+        poDriver->pfnIdentify = OGREDIGEODriverIdentify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/edigeo/ogredigeolayer.cpp b/ogr/ogrsf_frmts/edigeo/ogredigeolayer.cpp
index a0b988a..5d4eec7 100644
--- a/ogr/ogrsf_frmts/edigeo/ogredigeolayer.cpp
+++ b/ogr/ogrsf_frmts/edigeo/ogredigeolayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogredigeolayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogredigeolayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  EDIGEO Translator
  * Purpose:  Implements OGREDIGEOLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogredigeolayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogredigeolayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                          OGREDIGEOLayer()                            */
@@ -56,6 +56,7 @@ OGREDIGEOLayer::OGREDIGEOLayer( OGREDIGEODataSource* poDS,
     poFeatureDefn->SetGeomType( eType );
     if( poFeatureDefn->GetGeomFieldCount() != 0 )
         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    SetDescription( poFeatureDefn->GetName() );
 }
 
 /************************************************************************/
@@ -132,10 +133,10 @@ OGRFeature *OGREDIGEOLayer::GetNextRawFeature()
 /*                            GetFeature()                              */
 /************************************************************************/
 
-OGRFeature * OGREDIGEOLayer::GetFeature(long nFID)
+OGRFeature * OGREDIGEOLayer::GetFeature(GIntBig nFID)
 {
     if (nFID >= 0 && nFID < (int)aosFeatures.size())
-        return aosFeatures[nFID]->Clone();
+        return aosFeatures[(int)nFID]->Clone();
     else
         return NULL;
 }
@@ -181,7 +182,7 @@ OGRErr OGREDIGEOLayer::GetExtent(OGREnvelope *psExtent, int bForce)
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGREDIGEOLayer::GetFeatureCount( int bForce )
+GIntBig OGREDIGEOLayer::GetFeatureCount( int bForce )
 {
     if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
         return OGRLayer::GetFeatureCount(bForce);
diff --git a/ogr/ogrsf_frmts/elastic/GNUmakefile b/ogr/ogrsf_frmts/elastic/GNUmakefile
index 5dbbfc1..fe0d840 100644
--- a/ogr/ogrsf_frmts/elastic/GNUmakefile
+++ b/ogr/ogrsf_frmts/elastic/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrelasticdriver.o ogrelasticdatasource.o ogrelasticlayer.o
 
-CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/elastic/drv_elasticsearch.html b/ogr/ogrsf_frmts/elastic/drv_elasticsearch.html
index 448bc83..299125c 100644
--- a/ogr/ogrsf_frmts/elastic/drv_elasticsearch.html
+++ b/ogr/ogrsf_frmts/elastic/drv_elasticsearch.html
@@ -12,10 +12,11 @@
 Driver is <b>WRITE Only</b>
 <p>
 
-<a href="http://elasticsearch.org/">ElasticSearch</a> is an Enterprise-level search engine for a variety of data sources. It supports full-text indexing and geospatial querying of those data in a fast and effecient manor using a predefined REST API. This driver serializes all of the supported OGR file formats in to an ElasticSearch index.
-<h2>Field definitions</h2>
+<a href="http://elasticsearch.org/">ElasticSearch</a> is an Enterprise-level search engine for a variety of data sources. It supports full-text indexing and geospatial querying of those data in a fast and efficient manor using a predefined REST API. This driver serializes all of the supported OGR file formats in to an ElasticSearch index.
+<br> However, the driver is limited in the geometry it handles: even if polygons are provided as input, they are stored as <a href="http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-geo-point-type.html">geo point</a> and the "center" of the polygon is used as value of the point.
+</p><h2>Field definitions</h2>
 
-Fields are dyamically mapped from the input OGR data source. However, the driver will take advatage of advanced options within ElasticSearch as defined in a <a href="http://code.google.com/p/ogr2elasticsearch/wiki/ModifyingtheIndex">field mapping file</a>.
+Fields are dynamically mapped from the input OGR data source. However, the driver will take advantage of advanced options within ElasticSearch as defined in a <a href="http://code.google.com/p/ogr2elasticsearch/wiki/ModifyingtheIndex">field mapping file</a>.
 
 <p>
 The mapping file allows you to modify the mapping according to the <a href="http://www.elasticsearch.org/guide/reference/mapping/core-types.html">ElasticSearch field-specific types</a>. There are many options to choose from, however, most of the functionality is based on all the different things you are able to do with text fields within ElasticSearch.
diff --git a/ogr/ogrsf_frmts/elastic/ogr_elastic.h b/ogr/ogrsf_frmts/elastic/ogr_elastic.h
index 7ba1a02..0722dd1 100644
--- a/ogr/ogrsf_frmts/elastic/ogr_elastic.h
+++ b/ogr/ogrsf_frmts/elastic/ogr_elastic.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_elastic.h 26464 2013-09-13 21:06:03Z rouault $
+ * $Id: ogr_elastic.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  ElasticSearch Translator
  * Purpose:
@@ -59,14 +59,14 @@ public:
     void ResetReading();
     OGRFeature * GetNextFeature();
 
-    OGRErr CreateFeature(OGRFeature *poFeature);
+    OGRErr ICreateFeature(OGRFeature *poFeature);
     OGRErr CreateField(OGRFieldDefn *poField, int bApproxOK);
 
     OGRFeatureDefn * GetLayerDefn();
 
     int TestCapability(const char *);
 
-    int GetFeatureCount(int bForce);
+    GIntBig GetFeatureCount(int bForce);
 
     void PushIndex();
     CPLString BuildMap();
@@ -101,7 +101,7 @@ public:
     }
     OGRLayer* GetLayer(int);
 
-    OGRLayer * CreateLayer(const char * pszLayerName,
+    OGRLayer * ICreateLayer(const char * pszLayerName,
             OGRSpatialReference *poSRS,
             OGRwkbGeometryType eType,
             char ** papszOptions);
@@ -117,20 +117,5 @@ public:
     char* pszMapping;
 };
 
-/************************************************************************/
-/*                            OGRElasticDriver                          */
-/************************************************************************/
-
-class OGRElasticDriver : public OGRSFDriver {
-public:
-    ~OGRElasticDriver();
-
-    const char* GetName();
-    OGRDataSource* Open(const char *, int);
-    OGRDataSource* CreateDataSource(const char * pszName, char **papszOptions);
-    int TestCapability(const char *);
-
-};
-
 
 #endif /* ndef _OGR_Elastic_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/elastic/ogrelasticdatasource.cpp b/ogr/ogrsf_frmts/elastic/ogrelasticdatasource.cpp
index b2c8be5..2ff5210 100644
--- a/ogr/ogrsf_frmts/elastic/ogrelasticdatasource.cpp
+++ b/ogr/ogrsf_frmts/elastic/ogrelasticdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrelasticdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrelasticdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  ElasticSearch Translator
  * Purpose:
@@ -28,8 +28,8 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-/* This pragma was for what? */
-/* #pragma warning( disable : 4251 ) */
+// What was this supposed to do?
+// #pragma warning( disable : 4251 )
 
 #include "ogr_elastic.h"
 #include "cpl_conv.h"
@@ -37,7 +37,7 @@
 #include "cpl_csv.h"
 #include "cpl_http.h"
 
-CPL_CVSID("$Id: ogrelasticdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrelasticdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        OGRElasticDataSource()                        */
@@ -87,13 +87,13 @@ OGRLayer *OGRElasticDataSource::GetLayer(int iLayer) {
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRElasticDataSource::CreateLayer(const char * pszLayerName,
-                                             OGRSpatialReference *poSRS,
-                                             CPL_UNUSED OGRwkbGeometryType eType,
-                                             CPL_UNUSED char ** papszOptions) {
+OGRLayer * OGRElasticDataSource::ICreateLayer(const char * pszLayerName,
+                                              OGRSpatialReference *poSRS,
+                                              CPL_UNUSED OGRwkbGeometryType eType,
+                                              CPL_UNUSED char ** papszOptions) {
     nLayers++;
     papoLayers = (OGRElasticLayer **) CPLRealloc(papoLayers, nLayers * sizeof (OGRElasticLayer*));
     papoLayers[nLayers - 1] = new OGRElasticLayer(pszName, pszLayerName, this, poSRS, TRUE);
diff --git a/ogr/ogrsf_frmts/elastic/ogrelasticdriver.cpp b/ogr/ogrsf_frmts/elastic/ogrelasticdriver.cpp
index ddd9af6..3b2f616 100644
--- a/ogr/ogrsf_frmts/elastic/ogrelasticdriver.cpp
+++ b/ogr/ogrsf_frmts/elastic/ogrelasticdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrelasticdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrelasticdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  ElasticSearch Translator
  * Purpose:
@@ -30,38 +30,18 @@
 #include "ogr_elastic.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrelasticdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrelasticdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
-/*                         ~OGRElasticDriver()                          */
+/*                     OGRElasticSearchDriverCreate()                   */
 /************************************************************************/
-
-OGRElasticDriver::~OGRElasticDriver() {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRElasticDriver::GetName() {
-    return "ElasticSearch";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-OGRDataSource *OGRElasticDriver::Open(CPL_UNUSED const char * pszFilename,
-                                      CPL_UNUSED int bUpdate) {
-    return NULL;
-}
-
-/************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGRElasticDriver::CreateDataSource(const char * pszName,
-        char **papszOptions) {
+static GDALDataset* OGRElasticSearchDriverCreate( const char * pszName,
+                                                  CPL_UNUSED int nXSize,
+                                                  CPL_UNUSED int nYSize,
+                                                  CPL_UNUSED int nBands,
+                                                  CPL_UNUSED GDALDataType eDT,
+                                                  char ** papszOptions )
+{
     OGRElasticDataSource *poDS = new OGRElasticDataSource();
 
     if (!poDS->Create(pszName, papszOptions)) {
@@ -73,23 +53,33 @@ OGRDataSource *OGRElasticDriver::CreateDataSource(const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRElasticDriver::TestCapability(const char * pszCap) {
-    if (EQUAL(pszCap, ODrCCreateDataSource))
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                          RegisterOGRElastic()                        */
 /************************************************************************/
 
 void RegisterOGRElastic() {
     if (!GDAL_CHECK_VERSION("OGR/Elastic Search driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(new OGRElasticDriver);
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "ElasticSearch" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "ElasticSearch" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                    "Elastic Search" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                    "drv_elasticsearch.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+    "<CreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+    "<LayerCreationOptionList/>");
+
+        poDriver->pfnCreate = OGRElasticSearchDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp b/ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp
index 5c025a8..266530a 100644
--- a/ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp
+++ b/ogr/ogrsf_frmts/elastic/ogrelasticlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrelasticlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrelasticlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  ElasticSearch Translator
  * Purpose:
@@ -35,7 +35,7 @@
 #include "ogr_p.h"
 #include <json.h> // JSON-C
 
-CPL_CVSID("$Id: ogrelasticlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrelasticlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGRElasticLayer()                          */
@@ -65,6 +65,7 @@ OGRElasticLayer::OGRElasticLayer(CPL_UNUSED const char* pszFilename,
     }
 
     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poSRS = poSRSIn;
@@ -174,10 +175,10 @@ CPLString OGRElasticLayer::BuildMap() {
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRElasticLayer::CreateFeature(OGRFeature *poFeature) {
+OGRErr OGRElasticLayer::ICreateFeature(OGRFeature *poFeature) {
 
     // Check to see if the user has elected to only write out the mapping file
     // This method will only write out one layer from the vector file in cases where there are multiple layers
@@ -338,6 +339,8 @@ int OGRElasticLayer::TestCapability(const char * pszCap) {
 
     else if (EQUAL(pszCap, OLCSequentialWrite))
         return TRUE;
+    else if (EQUAL(pszCap, OLCCreateField))
+        return TRUE;
     else
         return FALSE;
 }
@@ -346,7 +349,7 @@ int OGRElasticLayer::TestCapability(const char * pszCap) {
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRElasticLayer::GetFeatureCount(CPL_UNUSED int bForce) {
+GIntBig OGRElasticLayer::GetFeatureCount(CPL_UNUSED int bForce) {
     CPLError(CE_Failure, CPLE_NotSupported,
             "Cannot read features when writing a Elastic file");
     return 0;
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbDatasource.cpp b/ogr/ogrsf_frmts/filegdb/FGdbDatasource.cpp
index d6f639a..f8742c3 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbDatasource.cpp
+++ b/ogr/ogrsf_frmts/filegdb/FGdbDatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: FGdbDatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: FGdbDatasource.cpp 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements FileGDB OGR Datasource.
@@ -9,7 +9,7 @@
  ******************************************************************************
  * Copyright (c) 2010, Ragi Yaser Burhum
  * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
- * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -37,7 +37,7 @@
 #include "FGdbUtils.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: FGdbDatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: FGdbDatasource.cpp 28601 2015-03-03 11:06:40Z rouault $");
 
 using std::vector;
 using std::wstring;
@@ -46,9 +46,10 @@ using std::wstring;
 /*                          FGdbDataSource()                           */
 /************************************************************************/
 
-FGdbDataSource::FGdbDataSource(FGdbDriver* poDriver):
+FGdbDataSource::FGdbDataSource(FGdbDriver* poDriver, 
+                               FGdbDatabaseConnection* pConnection):
 OGRDataSource(),
-m_poDriver(poDriver), m_pszName(0), m_pGeodatabase(NULL), m_bUpdate(false)
+m_poDriver(poDriver), m_pConnection(pConnection), m_pszName(0), m_pGeodatabase(NULL), m_bUpdate(false)
 {
 }
 
@@ -59,6 +60,9 @@ m_poDriver(poDriver), m_pszName(0), m_pGeodatabase(NULL), m_bUpdate(false)
 FGdbDataSource::~FGdbDataSource()
 {
     CPLMutexHolderOptionalLockD(m_poDriver->GetMutex());
+    
+    if( m_pConnection->IsLocked() )
+        CommitTransaction();
 
     size_t count = m_layers.size();
     for(size_t i = 0; i < count; ++i )
@@ -73,10 +77,10 @@ FGdbDataSource::~FGdbDataSource()
 /*                                Open()                                */
 /************************************************************************/
 
-int FGdbDataSource::Open(Geodatabase* pGeodatabase, const char * pszNewName, int bUpdate )
+int FGdbDataSource::Open(const char * pszNewName, int bUpdate )
 {
     m_pszName = CPLStrdup( pszNewName );
-    m_pGeodatabase = pGeodatabase;
+    m_pGeodatabase = m_pConnection->GetGDB();
     m_bUpdate = bUpdate;
 
     std::vector<std::wstring> typesRequested;
@@ -106,7 +110,10 @@ bool FGdbDataSource::OpenFGDBTables(const std::wstring &type,
         if (FAILED(hr = m_pGeodatabase->OpenTable(layers[i], *pTable)))
         {
             delete pTable;
-            GDBDebug(hr, "Error opening " + WStringToString(layers[i]) + ". Skipping it");
+            GDBErr(hr, "Error opening " + WStringToString(layers[i]),
+                   CE_Warning,
+                   ". Skipping it. "
+                   "Might be due to unsupported spatial reference system. Using OpenFileGDB driver should solve it");
             continue;
         }
         FGdbLayer* pLayer = new FGdbLayer();
@@ -116,7 +123,7 @@ bool FGdbDataSource::OpenFGDBTables(const std::wstring &type,
             return GDBErr(hr, "Error initializing OGRLayer for " + WStringToString(layers[i]));
         }
 
-        m_layers.push_back(new OGRMutexedLayer(pLayer, TRUE, m_poDriver->GetMutex()));
+        m_layers.push_back(pLayer);
     }
     return true;
 }
@@ -259,11 +266,11 @@ OGRErr FGdbDataSource::DeleteLayer( int iLayer )
     if( iLayer < 0 || iLayer >= static_cast<int>(m_layers.size()) )
         return OGRERR_FAILURE;
     
-    FGdbLayer* poBaseLayer = (FGdbLayer*) m_layers[iLayer]->GetBaseLayer();
+    FGdbLayer* poBaseLayer = m_layers[iLayer];
 
     // Fetch FGDBAPI Table before deleting OGR layer object
 
-    Table* pTable = poBaseLayer->GetTable();
+    //Table* pTable = poBaseLayer->GetTable();
 
     std::string name = poBaseLayer->GetLayerDefn()->GetName();
     std::wstring strPath = poBaseLayer->GetTablePath();
@@ -272,7 +279,7 @@ OGRErr FGdbDataSource::DeleteLayer( int iLayer )
     // delete OGR layer
     delete m_layers[iLayer];
 
-    pTable = NULL; // OGR Layer had ownership of FGDB Table
+    //pTable = NULL; // OGR Layer had ownership of FGDB Table
 
     m_layers.erase(m_layers.begin() + iLayer);
 
@@ -320,13 +327,13 @@ OGRLayer *FGdbDataSource::GetLayer( int iLayer )
 }
 
 /************************************************************************/
-/*                              CreateLayer()                           */
+/*                             ICreateLayer()                           */
 /*                                                                      */
 /* See FGdbLayer::Create for creation options                           */
 /************************************************************************/
 
 OGRLayer *
-FGdbDataSource::CreateLayer( const char * pszLayerName,
+FGdbDataSource::ICreateLayer( const char * pszLayerName,
                               OGRSpatialReference *poSRS,
                               OGRwkbGeometryType eType,
                               char ** papszOptions )
@@ -340,12 +347,10 @@ FGdbDataSource::CreateLayer( const char * pszLayerName,
         delete pLayer;
         return NULL;
     }
-    
-    OGRMutexedLayer* pMutexedLayer = new OGRMutexedLayer(pLayer, TRUE, m_poDriver->GetMutex());
 
-    m_layers.push_back(pMutexedLayer);
+    m_layers.push_back(pLayer);
 
-    return pMutexedLayer;  
+    return pLayer;  
 }
 
 
@@ -379,6 +384,7 @@ OGRFGdbSingleFeatureLayer::OGRFGdbSingleFeatureLayer(const char* pszLayerName,
                                                      const char *pszVal )
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     OGRFieldDefn oField( "FIELD_1", OFTString );
     poFeatureDefn->AddFieldDefn( &oField );
@@ -437,10 +443,9 @@ OGRLayer * FGdbDataSource::ExecuteSQL( const char *pszSQLCommand,
 /* -------------------------------------------------------------------- */
     if (EQUALN(pszSQLCommand, "GetLayerDefinition ", strlen("GetLayerDefinition ")))
     {
-        OGRMutexedLayer* poMutexedLayer = (OGRMutexedLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerDefinition "));
-        if (poMutexedLayer)
+        FGdbLayer* poLayer = (FGdbLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerDefinition "));
+        if (poLayer)
         {
-            FGdbLayer* poLayer = (FGdbLayer*) poMutexedLayer->GetBaseLayer();
             char* pszVal = NULL;
             poLayer->GetLayerXML(&pszVal);
             OGRLayer* poRet = new OGRFGdbSingleFeatureLayer( "LayerDefinition", pszVal );
@@ -456,10 +461,9 @@ OGRLayer * FGdbDataSource::ExecuteSQL( const char *pszSQLCommand,
 /* -------------------------------------------------------------------- */
     if (EQUALN(pszSQLCommand, "GetLayerMetadata ", strlen("GetLayerMetadata ")))
     {
-        OGRMutexedLayer* poMutexedLayer = (OGRMutexedLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerMetadata "));
-        if (poMutexedLayer)
+        FGdbLayer* poLayer = (FGdbLayer*) GetLayerByName(pszSQLCommand + strlen("GetLayerMetadata "));
+        if (poLayer)
         {
-            FGdbLayer* poLayer = (FGdbLayer*) poMutexedLayer->GetBaseLayer();
             char* pszVal = NULL;
             poLayer->GetLayerMetadataXML(&pszVal);
             OGRLayer* poRet = new OGRFGdbSingleFeatureLayer( "LayerMetadata", pszVal );
@@ -489,8 +493,20 @@ OGRLayer * FGdbDataSource::ExecuteSQL( const char *pszSQLCommand,
 /* -------------------------------------------------------------------- */
     EnumRows* pEnumRows = new EnumRows;
     long hr;
-    if (FAILED(hr = m_pGeodatabase->ExecuteSQL(
-                                StringToWString(pszSQLCommand), true, *pEnumRows)))
+    try
+    {
+        hr = m_pGeodatabase->ExecuteSQL(
+                                StringToWString(pszSQLCommand), true, *pEnumRows);
+    }
+    catch(...)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Exception occured at executing '%s'. Application may become unstable", pszSQLCommand);
+        delete pEnumRows;
+        return NULL;
+    }
+
+    if (FAILED(hr))
     {
         GDBErr(hr, CPLSPrintf("Failed at executing '%s'", pszSQLCommand));
         delete pEnumRows;
@@ -499,8 +515,7 @@ OGRLayer * FGdbDataSource::ExecuteSQL( const char *pszSQLCommand,
 
     if( EQUALN(pszSQLCommand, "SELECT ", 7) )
     {
-        OGRLayer* pLayer = new FGdbResultLayer(this, pszSQLCommand, pEnumRows);
-        return new OGRMutexedLayer(pLayer, TRUE, m_poDriver->GetMutex());
+        return new FGdbResultLayer(this, pszSQLCommand, pEnumRows);
     }
     else
     {
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbDriver.cpp b/ogr/ogrsf_frmts/filegdb/FGdbDriver.cpp
index 482380b..62cf72f 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbDriver.cpp
+++ b/ogr/ogrsf_frmts/filegdb/FGdbDriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: FGdbDriver.cpp 28412 2015-02-04 14:32:09Z rouault $
+ * $Id: FGdbDriver.cpp 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements FileGDB OGR driver.
@@ -35,9 +35,8 @@
 #include "FGdbUtils.h"
 #include "cpl_multiproc.h"
 #include "ogrmutexeddatasource.h"
-#include "ogr_api.h"
 
-CPL_CVSID("$Id: FGdbDriver.cpp 28412 2015-02-04 14:32:09Z rouault $");
+CPL_CVSID("$Id: FGdbDriver.cpp 28601 2015-03-03 11:06:40Z rouault $");
 
 extern "C" void RegisterOGRFileGDB();
 
@@ -54,6 +53,9 @@ FGdbDriver::FGdbDriver(): OGRSFDriver(), hMutex(NULL)
 FGdbDriver::~FGdbDriver()
 
 {
+    if( oMapConnections.size() != 0 )
+        CPLDebug("FileGDB", "Remaining %d connections. Bug?",
+                 (int)oMapConnections.size());
     if( hMutex != NULL )
         CPLDestroyMutex(hMutex);
     hMutex = NULL;
@@ -114,7 +116,7 @@ OGRDataSource *FGdbDriver::Open( const char* pszFilename, int bUpdate )
         if (FAILED(hr) || pGeoDatabase == NULL)
         {
             delete pGeoDatabase;
-
+            
             if( OGRGetDriverByName("OpenFileGDB") != NULL && bUpdate == FALSE )
             {
                 std::wstring fgdb_error_desc_w;
@@ -133,24 +135,33 @@ OGRDataSource *FGdbDriver::Open( const char* pszFilename, int bUpdate )
             {
                 GDBErr(hr, "Failed to open Geodatabase");
             }
+            oMapConnections.erase(pszFilename);
             return NULL;
         }
 
         CPLDebug("FileGDB", "Really opening %s", pszFilename);
-        oMapConnections[pszFilename] = new FGdbDatabaseConnection(pGeoDatabase);
+        pConnection = new FGdbDatabaseConnection(pGeoDatabase);
+        oMapConnections[pszFilename] = pConnection;
     }
 
     FGdbDataSource* pDS;
 
-    pDS = new FGdbDataSource(this);
+    pDS = new FGdbDataSource(this, pConnection);
 
-    if(!pDS->Open( pGeoDatabase, pszFilename, bUpdate ) )
+    if(!pDS->Open( pszFilename, bUpdate ) )
     {
         delete pDS;
         return NULL;
     }
     else
-        return new OGRMutexedDataSource(pDS, TRUE, hMutex);
+    {
+        OGRMutexedDataSource* poMutexedDS =
+                new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE);
+        if( bUpdate )
+            return OGRCreateEmulatedTransactionDataSourceWrapper(poMutexedDS, this, TRUE, FALSE);
+        else
+            return poMutexedDS;
+    }
 }
 
 /***********************************************************************/
@@ -207,17 +218,243 @@ OGRDataSource* FGdbDriver::CreateDataSource( const char * conn,
         return NULL;
     }
 
-    oMapConnections[conn] = new FGdbDatabaseConnection(pGeodatabase);
+    FGdbDatabaseConnection* pConnection = new FGdbDatabaseConnection(pGeodatabase);
+    oMapConnections[conn] = pConnection;
 
     /* Ready to embed the Geodatabase in an OGR Datasource */
-    FGdbDataSource* pDS = new FGdbDataSource(this);
-    if ( ! pDS->Open(pGeodatabase, conn, bUpdate) )
+    FGdbDataSource* pDS = new FGdbDataSource(this, pConnection);
+    if ( ! pDS->Open(conn, bUpdate) )
     {
         delete pDS;
         return NULL;
     }
     else
-        return new OGRMutexedDataSource(pDS, TRUE, hMutex);
+        return OGRCreateEmulatedTransactionDataSourceWrapper(
+            new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE), this,
+            TRUE, FALSE);
+}
+
+/************************************************************************/
+/*                           StartTransaction()                         */
+/************************************************************************/
+
+OGRErr FGdbDriver::StartTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS)
+{
+    CPLMutexHolderOptionalLockD(hMutex);
+
+    bOutHasReopenedDS = FALSE;
+
+    OGRMutexedDataSource* poMutexedDS = (OGRMutexedDataSource*)poDSInOut;
+    FGdbDataSource* poDS = (FGdbDataSource* )poMutexedDS->GetBaseDataSource();
+    if( !poDS->GetUpdate() )
+        return OGRERR_FAILURE;
+    FGdbDatabaseConnection* pConnection = poDS->GetConnection();
+    if( pConnection->GetRefCount() != 1 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot start transaction as database is opened in another connection");
+        return OGRERR_FAILURE;
+    }
+    if( pConnection->IsLocked() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Transaction is already in progress");
+        return OGRERR_FAILURE;
+    }
+
+    bOutHasReopenedDS = TRUE;
+
+    CPLString osName(poMutexedDS->GetName());
+    if( osName[osName.size()-1] == '/' || osName[osName.size()-1] == '\\' )
+        osName.resize(osName.size()-1);
+
+    pConnection->m_nRefCount ++;
+    delete poDSInOut;
+    poDSInOut = NULL;
+    poMutexedDS = NULL;
+    poDS = NULL;
+
+    ::CloseGeodatabase(*(pConnection->m_pGeodatabase));
+    delete pConnection->m_pGeodatabase;
+    pConnection->m_pGeodatabase = NULL;
+
+    CPLString osBackupName(osName);
+    osBackupName += ".ogrbak";
+
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    CPLUnlinkTree(osBackupName);
+    CPLPopErrorHandler();
+
+    OGRErr eErr = OGRERR_NONE;
+    if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") ||
+        CPLCopyTree( osBackupName, osName ) != 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot backup geodatabase");
+        eErr = OGRERR_FAILURE;
+    }
+
+    pConnection->m_pGeodatabase = new Geodatabase;
+    long hr = ::OpenGeodatabase(StringToWString(osName), *(pConnection->m_pGeodatabase));
+    if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE2") || FAILED(hr))
+    {
+        delete pConnection->m_pGeodatabase;
+        pConnection->m_pGeodatabase = NULL;
+        Release(osName);
+        GDBErr(hr, "Failed to re-open Geodatabase. Dataset should be closed");
+
+        return OGRERR_FAILURE;
+    }
+
+    FGdbDataSource* pDS = new FGdbDataSource(this, pConnection);
+    pDS->Open(osName, TRUE);
+    poDSInOut = new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE);
+
+    if( eErr == OGRERR_NONE )
+        pConnection->SetLocked(TRUE);
+    return eErr;
+}
+
+/************************************************************************/
+/*                           CommitTransaction()                        */
+/************************************************************************/
+
+OGRErr FGdbDriver::CommitTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS)
+{
+    CPLMutexHolderOptionalLockD(hMutex);
+
+    bOutHasReopenedDS = FALSE;
+
+    OGRMutexedDataSource* poMutexedDS = (OGRMutexedDataSource*)poDSInOut;
+    FGdbDataSource* poDS = (FGdbDataSource* )poMutexedDS->GetBaseDataSource();
+    FGdbDatabaseConnection* pConnection = poDS->GetConnection();
+    if( !pConnection->IsLocked() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "No transaction in progress");
+        return OGRERR_FAILURE;
+    }
+
+    CPLString osName(poMutexedDS->GetName());
+    if( osName[osName.size()-1] == '/' || osName[osName.size()-1] == '\\' )
+        osName.resize(osName.size()-1);
+
+    CPLString osBackupName(osName);
+    osBackupName += ".ogrbak";
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    CPLUnlinkTree(osBackupName);
+    CPLPopErrorHandler();
+
+    pConnection->SetLocked(FALSE);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           RollbackTransaction()                      */
+/************************************************************************/
+
+OGRErr FGdbDriver::RollbackTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS)
+{
+    CPLMutexHolderOptionalLockD(hMutex);
+
+    bOutHasReopenedDS = FALSE;
+
+    OGRMutexedDataSource* poMutexedDS = (OGRMutexedDataSource*)poDSInOut;
+    FGdbDataSource* poDS = (FGdbDataSource* )poMutexedDS->GetBaseDataSource();
+    FGdbDatabaseConnection* pConnection = poDS->GetConnection();
+    if( !pConnection->IsLocked() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "No transaction in progress");
+        return OGRERR_FAILURE;
+    }
+
+    pConnection->SetLocked(FALSE);
+
+    bOutHasReopenedDS = TRUE;
+
+    CPLString osName(poMutexedDS->GetName());
+    if( osName[osName.size()-1] == '/' || osName[osName.size()-1] == '\\' )
+        osName.resize(osName.size()-1);
+
+    pConnection->m_nRefCount ++;
+    delete poDSInOut;
+    poDSInOut = NULL;
+    poMutexedDS = NULL;
+    poDS = NULL;
+
+    ::CloseGeodatabase(*(pConnection->m_pGeodatabase));
+    delete pConnection->m_pGeodatabase;
+    pConnection->m_pGeodatabase = NULL;
+
+    CPLString osBackupName(osName);
+    osBackupName += ".ogrbak";
+    CPLString osTmpName(osName);
+    osTmpName += ".ogrtmp";
+    
+    /* Restore the backup copy in 3 steps : */
+    /* first rename the active directory (the one that we want to discard) in .tmp */
+    /* then rename the backup copy (the one we want to restore) under regular name */
+    /* and finally dispose the .tmp directory */
+    /* That way there's no risk definitely losing data */
+    if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE1") || 
+        VSIRename(osName, osTmpName) != 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot rename %s to %s. The original geodatabase is supposed to be in '%s'. "
+                 "Dataset should be closed",
+                 osName.c_str(), osTmpName.c_str(), osBackupName.c_str());
+        Release(osName);
+        return OGRERR_FAILURE;
+    }
+    
+    if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE2") || 
+        VSIRename(osBackupName, osName) != 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot rename %s to %s. The original geodatabase is supposed to be in '%s'. "
+                 "Dataset should be closed",
+                 osBackupName.c_str(), osName.c_str(), osBackupName.c_str());
+        Release(osName);
+        return OGRERR_FAILURE;
+    }
+
+    if( EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE3") || 
+        CPLUnlinkTree(osTmpName) != 0 )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined,
+                 "Cannot remove %s. Manual cleanup required", osTmpName.c_str());
+    }
+
+    pConnection->m_pGeodatabase = new Geodatabase;
+    long hr = ::OpenGeodatabase(StringToWString(osName), *(pConnection->m_pGeodatabase));
+    if (EQUAL(CPLGetConfigOption("FGDB_SIMUL_FAIL", ""), "CASE4") ||
+        FAILED(hr))
+    {
+        delete pConnection->m_pGeodatabase;
+        pConnection->m_pGeodatabase = NULL;
+        Release(osName);
+        GDBErr(hr, "Failed to re-open Geodatabase. Dataset should be closed");
+        return OGRERR_FAILURE;
+    }
+
+    FGdbDataSource* pDS = new FGdbDataSource(this, pConnection);
+    pDS->Open(osName, TRUE);
+    poDSInOut = new OGRMutexedDataSource(pDS, TRUE, hMutex, TRUE);
+
+    return OGRERR_NONE;
+}
+
+/***********************************************************************/
+/*                       ReadoptOldFeatureDefn()                       */
+/***********************************************************************/
+
+void FGdbDriver::ReadoptOldFeatureDefn(CPL_UNUSED OGRDataSource* poDS,
+                                       OGRLayer* poLayer,
+                                       OGRFeatureDefn* poFeatureDefn)
+{
+    FGdbLayer* poFGdbLayer = (FGdbLayer* )((OGRMutexedLayer*)poLayer)->GetBaseLayer();
+    poFGdbLayer->ReadoptOldFeatureDefn(poFeatureDefn);
 }
 
 /***********************************************************************/
@@ -236,10 +473,13 @@ void FGdbDriver::Release(const char* pszName)
                  pConnection->m_nRefCount);
         if( pConnection->m_nRefCount == 0 )
         {
-            CPLDebug("FileGDB", "Really closing %s now", pszName);
-            ::CloseGeodatabase(*(pConnection->m_pGeodatabase));
-            delete pConnection->m_pGeodatabase;
-            pConnection->m_pGeodatabase = NULL;
+            if( pConnection->m_pGeodatabase != NULL )
+            {
+                CPLDebug("FileGDB", "Really closing %s now", pszName);
+                ::CloseGeodatabase(*(pConnection->m_pGeodatabase));
+                delete pConnection->m_pGeodatabase;
+                pConnection->m_pGeodatabase = NULL;
+            }
             delete pConnection;
             oMapConnections.erase(pszName);
         }
@@ -290,6 +530,47 @@ void RegisterOGRFileGDB()
 {
     if (! GDAL_CHECK_VERSION("OGR FGDB"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new FGdbDriver );
+    OGRSFDriver* poDriver = new FGdbDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "ESRI FileGDB" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gdb" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_filegdb.html" );
+
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>" );
+
+    poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='FEATURE_DATASET' type='string' description='FeatureDataset folder into to put the new layer'/>"
+"  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column' default='SHAPE'/>"
+"  <Option name='GEOMETRY_NULLABLE' type='boolean' description='Whether the values of the geometry column can be NULL' default='YES'/>"
+"  <Option name='FID' type='string' description='Name of OID column' default='OBJECTID' deprecated_alias='OID_NAME'/>"
+"  <Option name='XYTOLERANCE' type='float' description='Snapping tolerance, used for advanced ArcGIS features like network and topology rules, on 2D coordinates, in the units of the CRS'/>"
+"  <Option name='ZTOLERANCE' type='float' description='Snapping tolerance, used for advanced ArcGIS features like network and topology rules, on Z coordinates, in the units of the CRS'/>"
+"  <Option name='XORIGIN' type='float' description='X origin of the coordinate precision grid'/>"
+"  <Option name='YORIGIN' type='float' description='Y origin of the coordinate precision grid'/>"
+"  <Option name='ZORIGIN' type='float' description='Z origin of the coordinate precision grid'/>"
+"  <Option name='XYSCALE' type='float' description='X,Y scale of the coordinate precision grid'/>"
+"  <Option name='ZSCALE' type='float' description='Z scale of the coordinate precision grid'/>"
+"  <Option name='XML_DEFINITION' type='string' description='XML definition to create the new table. The root node of such a XML definition must be a <esri:DataElement> element conformant to FileGDBAPI.xsd'/>"
+"  <Option name='CREATE_MULTIPATCH' type='boolean' description='Whether to write geometries of layers of type MultiPolygon as MultiPatch' default='NO'/>"
+"  <Option name='COLUMN_TYPES' type='string' description='A list of strings of format field_name=fgdb_filed_type (separated by comma) to force the FileGDB column type of fields to be created'/>"
+"  <Option name='CONFIGURATION_KEYWORD' type='string-select' description='Customize how data is stored. By default text in UTF-8 and data up to 1TB'>"
+"    <Value>DEFAULTS</Value>"
+"    <Value>TEXT_UTF16</Value>"
+"    <Value>MAX_FILE_SIZE_4GB</Value>"
+"    <Value>MAX_FILE_SIZE_256TB</Value>"
+"    <Value>GEOMETRY_OUTOFLINE</Value>"
+"    <Value>BLOB_OUTOFLINE</Value>"
+"    <Value>GEOMETRY_AND_BLOB_OUTOFLINE</Value>"
+"  </Option>"
+"</LayerCreationOptionList>");
+    
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Real String Date DateTime Binary" );
+    poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+    poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+    poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbLayer.cpp b/ogr/ogrsf_frmts/filegdb/FGdbLayer.cpp
index edfe1fa..0d5c8f6 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbLayer.cpp
+++ b/ogr/ogrsf_frmts/filegdb/FGdbLayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
-* $Id: FGdbLayer.cpp 27654 2014-09-09 18:28:10Z rouault $
+* $Id: FGdbLayer.cpp 29119 2015-05-02 21:38:04Z rouault $
 *
 * Project:  OpenGIS Simple Features Reference Implementation
 * Purpose:  Implements FileGDB OGR layer.
@@ -37,7 +37,7 @@
 #include "FGdbUtils.h"
 #include "cpl_minixml.h" // the only way right now to extract schema information
 
-CPL_CVSID("$Id: FGdbLayer.cpp 27654 2014-09-09 18:28:10Z rouault $");
+CPL_CVSID("$Id: FGdbLayer.cpp 29119 2015-05-02 21:38:04Z rouault $");
 
 using std::string;
 using std::wstring;
@@ -343,12 +343,12 @@ void FGdbLayer::WorkAroundExtentProblem()
 #endif // EXTENT_WORKAROUND
 
 /************************************************************************/
-/*                            CreateFeature()                           */
+/*                            ICreateFeature()                           */
 /* Create an FGDB Row and populate it from an OGRFeature.               */
 /*                                                                      */
 /************************************************************************/
 
-OGRErr FGdbLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr FGdbLayer::ICreateFeature( OGRFeature *poFeature )
 {
     Table *fgdb_table = m_pTable;
     Row fgdb_row;
@@ -372,6 +372,10 @@ OGRErr FGdbLayer::CreateFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
+    /* As we have issues with fixed values for dates, or CURRENT_xxxx isn't */
+    /* handled anyway, let's fill ourselves all unset fields with their default */
+    poFeature->FillUnsetWithDefault(FALSE, NULL);
+
     /* Populate the row with the feature content */
     if (PopulateRowWithFeature(fgdb_row, poFeature) != OGRERR_NONE)
         return OGRERR_FAILURE;
@@ -435,10 +439,14 @@ OGRErr FGdbLayer::PopulateRowWithFeature( Row& fgdb_row, OGRFeature *poFeature )
     {
         std::string field_name = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
         std::wstring wfield_name = StringToWString(field_name);
+        const std::string & strFieldType = m_vOGRFieldToESRIFieldType[i];
 
         /* Set empty fields to NULL */
         if( !poFeature->IsFieldSet( i ) )
         {
+            if( strFieldType == "esriFieldTypeGlobalID" )
+                continue;
+
             if (FAILED(hr = fgdb_row.SetNull(wfield_name)))
             {
                 GDBErr(hr, "Failed setting field to NULL.");
@@ -449,7 +457,6 @@ OGRErr FGdbLayer::PopulateRowWithFeature( Row& fgdb_row, OGRFeature *poFeature )
 
         /* Set the information using the appropriate FGDB function */
         int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
-        const std::string & strFieldType = m_vOGRFieldToESRIFieldType[i];
 
         if ( nOGRFieldType == OFTInteger )
         {
@@ -477,7 +484,7 @@ OGRErr FGdbLayer::PopulateRowWithFeature( Row& fgdb_row, OGRFeature *poFeature )
                 hr = fgdb_row.SetShort(wfield_name, (short) fldvalue);
             }
         }
-        else if ( nOGRFieldType == OFTReal )
+        else if ( nOGRFieldType == OFTReal || nOGRFieldType == OFTInteger64 )
         {
             /* Doubles (we don't handle FGDB Floats) */
             double fldvalue = poFeature->GetFieldAsDouble(i);
@@ -628,12 +635,18 @@ OGRErr FGdbLayer::PopulateRowWithFeature( Row& fgdb_row, OGRFeature *poFeature )
 /*                             GetRow()                                 */
 /************************************************************************/
 
-OGRErr FGdbLayer::GetRow( EnumRows& enumRows, Row& row, long nFID )
+OGRErr FGdbLayer::GetRow( EnumRows& enumRows, Row& row, GIntBig nFID )
 {
     long           hr;
     CPLString      osQuery;
+    
+    /* Querying a 64bit FID causes a runtime exception in FileGDB... */
+    if( (GIntBig)(int)nFID != nFID )
+    {
+        return OGRERR_FAILURE;
+    }
 
-    osQuery.Printf("%s = %ld", m_strOIDFieldName.c_str(), nFID);
+    osQuery.Printf("%s = " CPL_FRMT_GIB, m_strOIDFieldName.c_str(), nFID);
 
     if (FAILED(hr = m_pTable->Search(m_wstrSubfields, StringToWString(osQuery.c_str()), true, enumRows)))
     {
@@ -648,7 +661,7 @@ OGRErr FGdbLayer::GetRow( EnumRows& enumRows, Row& row, long nFID )
     }
 
     if (hr != S_OK)
-        return OGRERR_FAILURE; //none found - but no failure
+        return OGRERR_NON_EXISTING_FEATURE; //none found - but no failure
 
     return OGRERR_NONE;
 }
@@ -657,7 +670,7 @@ OGRErr FGdbLayer::GetRow( EnumRows& enumRows, Row& row, long nFID )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr FGdbLayer::DeleteFeature( long nFID )
+OGRErr FGdbLayer::DeleteFeature( GIntBig nFID )
 
 {
     long           hr;
@@ -669,8 +682,9 @@ OGRErr FGdbLayer::DeleteFeature( long nFID )
 
     EndBulkLoad();
 
-    if (GetRow(enumRows, row, nFID) != OGRERR_NONE)
-        return OGRERR_FAILURE;
+    OGRErr eErr = GetRow(enumRows, row, nFID);
+    if( eErr != OGRERR_NONE)
+        return eErr;
 
     if (FAILED(hr = m_pTable->Delete(row)))
     {
@@ -682,10 +696,10 @@ OGRErr FGdbLayer::DeleteFeature( long nFID )
 }
 
 /************************************************************************/
-/*                            SetFeature()                              */
+/*                            ISetFeature()                              */
 /************************************************************************/
 
-OGRErr FGdbLayer::SetFeature( OGRFeature* poFeature )
+OGRErr FGdbLayer::ISetFeature( OGRFeature* poFeature )
 
 {
     long           hr;
@@ -704,8 +718,9 @@ OGRErr FGdbLayer::SetFeature( OGRFeature* poFeature )
 
     EndBulkLoad();
 
-    if (GetRow(enumRows, row, poFeature->GetFID()) != OGRERR_NONE)
-        return OGRERR_FAILURE;
+    OGRErr eErr = GetRow(enumRows, row, poFeature->GetFID());
+    if( eErr != OGRERR_NONE)
+        return eErr;
 
     /* Populate the row with the feature content */
     if (PopulateRowWithFeature(row, poFeature) != OGRERR_NONE)
@@ -731,15 +746,22 @@ char* FGdbLayer::CreateFieldDefn(OGRFieldDefn& oField,
 {
     std::string fieldname = oField.GetNameRef();
     std::string fidname = std::string(GetFIDColumn());
-    std::string nullable = "true";
+    std::string nullable = (oField.IsNullable()) ? "true" : "false";
 
     /* Try to map the OGR type to an ESRI type */
     OGRFieldType fldtype = oField.GetType();
-    if ( ! OGRToGDBFieldType(fldtype, &gdbFieldType) )
+    if ( ! OGRToGDBFieldType(fldtype, oField.GetSubType(), &gdbFieldType) )
     {
         GDBErr(-1, "Failed converting field type.");
         return NULL;
     }
+    
+    if( oField.GetType() == OFTInteger64 && !bApproxOK )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Integer64 not supported in FileGDB");
+        return NULL;
+    }
 
     const char* pszColumnTypes = CSLFetchNameValue(m_papszOptions, "COLUMN_TYPES");
     if( pszColumnTypes != NULL )
@@ -749,7 +771,8 @@ char* FGdbLayer::CreateFieldDefn(OGRFieldDefn& oField,
         if( pszFieldType != NULL )
         {
             OGRFieldType fldtypeCheck;
-            if( GDBToOGRFieldType(pszFieldType, &fldtypeCheck) )
+            OGRFieldSubType eSubType;
+            if( GDBToOGRFieldType(pszFieldType, &fldtypeCheck, &eSubType) )
             {
                 if( fldtypeCheck != fldtype )
                 {
@@ -851,7 +874,53 @@ char* FGdbLayer::CreateFieldDefn(OGRFieldDefn& oField,
         CPLCreateXMLElementAndValue(defn_xml, "AliasName", fieldname.c_str());
     }
 
-    /* Default values are discouraged in OGR API docs */
+    if( oField.GetDefault() != NULL )
+    {
+        const char* pszDefault = oField.GetDefault();
+        /*int nYear, nMonth, nDay, nHour, nMinute;
+        float fSecond;*/
+        if( oField.GetType() == OFTString )
+        {
+            CPLString osVal = pszDefault;
+            if( osVal[0] == '\'' && osVal[osVal.size()-1] == '\'' )
+            {
+                osVal = osVal.substr(1);
+                osVal.resize(osVal.size()-1);
+                char* pszTmp = CPLUnescapeString(osVal, NULL, CPLES_SQL);
+                osVal = pszTmp;
+                CPLFree(pszTmp);
+            }
+            CPLXMLNode* psDefaultValue =
+                CPLCreateXMLElementAndValue(defn_xml, "DefaultValue", osVal);
+            FGDB_CPLAddXMLAttribute(psDefaultValue, "xsi:type", "xs:string");
+        }
+        else if( oField.GetType() == OFTInteger &&
+                 !EQUAL(gdbFieldType.c_str(), "esriFieldTypeSmallInteger") &&
+                 CPLGetValueType(pszDefault) == CPL_VALUE_INTEGER )
+        {
+            CPLXMLNode* psDefaultValue =
+                CPLCreateXMLElementAndValue(defn_xml, "DefaultValue", pszDefault);
+            FGDB_CPLAddXMLAttribute(psDefaultValue, "xsi:type", "xs:int");
+        }
+        else if( oField.GetType() == OFTReal &&
+                 !EQUAL(gdbFieldType.c_str(), "esriFieldTypeSingle") &&
+                 CPLGetValueType(pszDefault) != CPL_VALUE_STRING )
+        {
+            CPLXMLNode* psDefaultValue =
+                CPLCreateXMLElementAndValue(defn_xml, "DefaultValue", pszDefault);
+            FGDB_CPLAddXMLAttribute(psDefaultValue, "xsi:type", "xs:double");
+        }
+        /*else if( oField.GetType() == OFTDateTime &&
+                 sscanf(pszDefault, "'%d/%d/%d %d:%d:%f'", &nYear, &nMonth, &nDay,
+                        &nHour, &nMinute, &fSecond) == 6 )
+        {
+            CPLXMLNode* psDefaultValue =
+                CPLCreateXMLElementAndValue(defn_xml, "DefaultValue",
+                    CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d",
+                               nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond + 0.5)));
+            FGDB_CPLAddXMLAttribute(psDefaultValue, "xsi:type", "xs:dateTime");
+        }*/
+    }
     /* <DefaultValue xsi:type="xs:string">afternoon</DefaultValue> */
 
     /* Convert our XML tree into a string for FGDB */
@@ -1187,7 +1256,7 @@ CPLXMLNode* XMLSpatialReference(OGRSpatialReference* poSRS, char** papszOptions)
     long zscale = 1 / ztol * 10;
 
     char s_xyscale[50], s_xytol[50], s_zscale[50], s_ztol[50];
-    snprintf(s_ztol, 50, "%f", ztol);
+    CPLsnprintf(s_ztol, 50, "%f", ztol);
     snprintf(s_zscale, 50, "%ld", zscale);
     
     if ( poSRS == NULL || poSRS->IsProjected() )
@@ -1197,7 +1266,7 @@ CPLXMLNode* XMLSpatialReference(OGRSpatialReference* poSRS, char** papszOptions)
         // default scale is 10x the tolerance
         long xyscale = 1 / xytol * 10;
 
-        snprintf(s_xytol, 50, "%f", xytol);
+        CPLsnprintf(s_xytol, 50, "%f", xytol);
         snprintf(s_xyscale, 50, "%ld", xyscale);
 
         // Ideally we would use the same X/Y origins as ArcGIS, but we need the algorithm they use.
@@ -1320,7 +1389,7 @@ bool FGdbLayer::CreateFeatureDataset(FGdbDataSource* pParentDataSource,
 /* Layer creation options:                                              */
 /*   FEATURE_DATASET, nest layer inside a FeatureDataset folder         */
 /*   GEOMETRY_NAME, user-selected name for the geometry column          */
-/*   OID_NAME, user-selected name for the FID column                    */
+/*   FID/OID_NAME, user-selected name for the FID column                */
 /*   XORIGIN, YORIGIN, ZORIGIN, origin of the snapping grid             */
 /*   XYSCALE, ZSCALE, inverse resolution of the snapping grid           */
 /*   XYTOLERANCE, ZTOLERANCE, snapping tolerance for topology/networks  */
@@ -1416,7 +1485,9 @@ bool FGdbLayer::Create(FGdbDataSource* pParentDataSource,
         geometry_name = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
 
     /* Over-ride the OID name if necessary */
-    if ( CSLFetchNameValue( papszOptions, "OID_NAME") != NULL )
+    if ( CSLFetchNameValue( papszOptions, "FID") != NULL )
+        fid_name = CSLFetchNameValue( papszOptions, "FID");
+    else if ( CSLFetchNameValue( papszOptions, "OID_NAME") != NULL )
         fid_name = CSLFetchNameValue( papszOptions, "OID_NAME");
 
     /* Figure out our geometry type */
@@ -1467,6 +1538,10 @@ bool FGdbLayer::Create(FGdbDataSource* pParentDataSource,
     CPLCreateXMLElementAndValue(defn_xml,"Versioned", "false");
     CPLCreateXMLElementAndValue(defn_xml,"CanVersion", "false");
 
+    if ( CSLFetchNameValue( papszOptions, "CONFIGURATION_KEYWORD") != NULL )
+        CPLCreateXMLElementAndValue(defn_xml,"ConfigurationKeyword",
+                                    CSLFetchNameValue( papszOptions, "CONFIGURATION_KEYWORD"));
+
     /* We might need to make OID optional later, but OGR likes to have a FID */
     CPLCreateXMLElementAndValue(defn_xml,"HasOID", "true");
     CPLCreateXMLElementAndValue(defn_xml,"OIDFieldName", fid_name.c_str());
@@ -1485,7 +1560,10 @@ bool FGdbLayer::Create(FGdbDataSource* pParentDataSource,
         FGDB_CPLAddXMLAttribute(shape_xml, "xsi:type", "esri:Field");
         CPLCreateXMLElementAndValue(shape_xml, "Name", geometry_name.c_str());
         CPLCreateXMLElementAndValue(shape_xml, "Type", "esriFieldTypeGeometry");
-        CPLCreateXMLElementAndValue(shape_xml, "IsNullable", "true");
+        if( CSLFetchBoolean( papszOptions, "GEOMETRY_NULLABLE", TRUE) )
+            CPLCreateXMLElementAndValue(shape_xml, "IsNullable", "true");
+        else
+            CPLCreateXMLElementAndValue(shape_xml, "IsNullable", "false");
         CPLCreateXMLElementAndValue(shape_xml, "Length", "0");
         CPLCreateXMLElementAndValue(shape_xml, "Precision", "0");
         CPLCreateXMLElementAndValue(shape_xml, "Scale", "0");
@@ -1628,6 +1706,7 @@ bool FGdbLayer::Initialize(FGdbDataSource* pParentDataSource, Table* pTable,
     m_strName = WStringToString(wstrQueryName);
 
     m_pFeatureDefn = new OGRFeatureDefn(m_strName.c_str()); //TODO: Should I "new" an OGR smart pointer - sample says so, but it doesn't seem right
+    SetDescription( m_pFeatureDefn->GetName() );
     //as long as we use the same compiler & settings in both the ogr build and this
     //driver, we should be OK
     m_pFeatureDefn->Reference();
@@ -1809,7 +1888,7 @@ bool FGdbLayer::ParseGeometryDef(CPLXMLNode* psRoot)
             }
             else
             {
-                CPLDebug("OpenFileGDB", "Cannot import SRID %s", wkid.c_str());
+                CPLDebug("FGDB", "Cannot import SRID %s", wkid.c_str());
             }
         }
         CPLPopErrorHandler();
@@ -1846,10 +1925,12 @@ bool FGdbLayer::ParseGeometryDef(CPLXMLNode* psRoot)
 /************************************************************************/
 
 bool FGdbLayer::ParseSpatialReference(CPLXMLNode* psSpatialRefNode,
-                                      string* pOutWkt, string* pOutWKID, string* pOutLatestWKID)
+                                      string* pOutWkt, string* pOutWKID,
+                                      string* pOutLatestWKID)
 {
     *pOutWkt = "";
     *pOutWKID = "";
+    *pOutLatestWKID = "";
 
     CPLXMLNode* psSRItemNode;
 
@@ -1866,6 +1947,10 @@ bool FGdbLayer::ParseSpatialReference(CPLXMLNode* psSpatialRefNode,
             char* pszUnescaped = CPLUnescapeString(psSRItemNode->psChild->pszValue, NULL, CPLES_XML);
             *pOutWKID = pszUnescaped;
             CPLFree(pszUnescaped);
+
+            // Needed with FileGDB v1.4 with layers with empty SRS
+            if( *pOutWKID == "0" )
+                *pOutWKID = "";
         }
         /* The concept of LatestWKID is explained in http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#//02r3000000n1000000 */
         else if( psSRItemNode->eType == CXT_Element &&
@@ -1910,6 +1995,7 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
     //CPLAssert(ogrToESRIFieldMapping.size() == pOGRFeatureDef->GetFieldCount());
 
     CPLXMLNode* psFieldNode;
+    int bShouldQueryOpenFileGDB = FALSE;
 
     for( psFieldNode = psRoot->psChild;
         psFieldNode != NULL;
@@ -1927,6 +2013,8 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
             std::string fieldType;
             int nLength = 0;
             int nPrecision = 0;
+            int bNullable = TRUE;
+            std::string osDefault;
 
             // loop through all items in Field element
             //
@@ -1937,34 +2025,41 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
             {
                 if (psFieldItemNode->eType == CXT_Element)
                 {
-
-                if (EQUAL(psFieldItemNode->pszValue,"Name"))
-                {
-                    char* pszUnescaped = CPLUnescapeString(
-                        psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
-                    fieldName = pszUnescaped;
-                    CPLFree(pszUnescaped);
-                }
-                else if (EQUAL(psFieldItemNode->pszValue,"Type") )
-                {
-                    char* pszUnescaped = CPLUnescapeString(
-                        psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
-                    fieldType = pszUnescaped;
-                    CPLFree(pszUnescaped);
-                }
-                else if (EQUAL(psFieldItemNode->pszValue,"GeometryDef") )
-                {
-                    if (!ParseGeometryDef(psFieldItemNode))
-                        return false; // if we failed parsing the GeometryDef, we are done!
-                }
-                else if (EQUAL(psFieldItemNode->pszValue,"Length") )
-                {
-                    nLength = atoi(psFieldItemNode->psChild->pszValue);
-                }
-                else if (EQUAL(psFieldItemNode->pszValue,"Precision") )
-                {
-                    nPrecision = atoi(psFieldItemNode->psChild->pszValue);
-                }
+                    if (EQUAL(psFieldItemNode->pszValue,"Name"))
+                    {
+                        char* pszUnescaped = CPLUnescapeString(
+                            psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
+                        fieldName = pszUnescaped;
+                        CPLFree(pszUnescaped);
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"Type") )
+                    {
+                        char* pszUnescaped = CPLUnescapeString(
+                            psFieldItemNode->psChild->pszValue, NULL, CPLES_XML);
+                        fieldType = pszUnescaped;
+                        CPLFree(pszUnescaped);
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"GeometryDef") )
+                    {
+                        if (!ParseGeometryDef(psFieldItemNode))
+                            return false; // if we failed parsing the GeometryDef, we are done!
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"Length") )
+                    {
+                        nLength = atoi(psFieldItemNode->psChild->pszValue);
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"Precision") )
+                    {
+                        nPrecision = atoi(psFieldItemNode->psChild->pszValue);
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"IsNullable") )
+                    {
+                        bNullable = EQUAL(psFieldItemNode->psChild->pszValue, "true");
+                    }
+                    else if (EQUAL(psFieldItemNode->pszValue,"DefaultValue"))
+                    {
+                        osDefault = CPLGetXMLValue(psFieldItemNode, NULL, "");
+                    }
                 }
             }
 
@@ -1976,6 +2071,7 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
             if (fieldType == "esriFieldTypeGeometry")
             {
                 m_strShapeFieldName = fieldName;
+                m_pFeatureDefn->GetGeomFieldDefn(0)->SetNullable(bNullable);
 
                 continue; // finish here for special field - don't add as OGR fielddef
             }
@@ -1987,8 +2083,9 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
             }
 
             OGRFieldType ogrType;
+            OGRFieldSubType eSubType;
             //CPLDebug("FGDB", "name = %s, type = %s", fieldName.c_str(), fieldType.c_str() );
-            if (!GDBToOGRFieldType(fieldType, &ogrType))
+            if (!GDBToOGRFieldType(fieldType, &ogrType, &eSubType))
             {
                 // field cannot be mapped, skipping further processing
                 CPLError( CE_Warning, CPLE_AppDefined, "Skipping field: [%s] type: [%s] ",
@@ -2000,8 +2097,58 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
             //TODO: Optimization - modify m_wstrSubFields so it only fetches fields that are mapped
 
             OGRFieldDefn fieldTemplate( fieldName.c_str(), ogrType);
-            //fieldTemplate.SetWidth(nLength);
+            fieldTemplate.SetSubType(eSubType);
+            /* On creation (GDBFieldTypeToWidthPrecision) if string width is 0, we pick up */
+            /* 65535 by default to mean unlimited string length, but we don't want */
+            /* to advertize such a big number */
+            if( ogrType == OFTString && nLength < 65535 )
+                fieldTemplate.SetWidth(nLength);
             //fieldTemplate.SetPrecision(nPrecision);
+            fieldTemplate.SetNullable(bNullable);
+            if( osDefault.size() )
+            {
+                if( ogrType == OFTString )
+                {
+                    char* pszTmp = CPLEscapeString(osDefault.c_str(), -1, CPLES_SQL);
+                    osDefault = "'";
+                    osDefault += pszTmp;
+                    CPLFree(pszTmp);
+                    osDefault += "'";
+                    fieldTemplate.SetDefault(osDefault.c_str());
+                }
+                else if( ogrType == OFTInteger ||
+                         ogrType == OFTReal )
+                {
+#ifdef unreliable
+                    /* Disabling this as GDBs and the FileGDB SDK aren't reliable for numeric values */
+                    /* It often occurs that the XML definition in a00000004.gdbtable doesn't */
+                    /* match the default values (in binary) found in the field definition */
+                    /* section of the .gdbtable of the layers themselves */
+                    /* The Table::GetDefinition() API of FileGDB doesn't seem to use the */
+                    /* XML definition, but rather the values found in the field definition */
+                    /* section of the .gdbtable of the layers themselves */
+                    /* It seems that the XML definition in a00000004.gdbtable is authoritative */
+                    /* in ArcGIS, so we're screwed... */
+
+                    fieldTemplate.SetDefault(osDefault.c_str());
+#endif
+                    bShouldQueryOpenFileGDB = TRUE;
+                }
+                else if( ogrType == OFTDateTime )
+                {
+                    int nYear, nMonth, nDay, nHour, nMinute;
+                    float fSecond;
+                    if( sscanf(osDefault.c_str(), "%d-%d-%dT%d:%d:%fZ", &nYear, &nMonth, &nDay,
+                        &nHour, &nMinute, &fSecond) == 6 ||
+                        sscanf(osDefault.c_str(), "'%d-%d-%d %d:%d:%fZ'", &nYear, &nMonth, &nDay,
+                             &nHour, &nMinute, &fSecond) == 6 )
+                    {
+                        fieldTemplate.SetDefault(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
+                               nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond + 0.5)));
+                    }
+                }
+            }
+
             m_pFeatureDefn->AddFieldDefn( &fieldTemplate );
 
             m_vOGRFieldToESRIField.push_back(StringToWString(fieldName));
@@ -2012,6 +2159,33 @@ bool FGdbLayer::GDBToOGRFields(CPLXMLNode* psRoot)
         }
     }
 
+    /* Using OpenFileGDB to get reliable default values for integer/real fields */
+    if( bShouldQueryOpenFileGDB )
+    {
+        const char* apszDrivers[] = { "OpenFileGDB", NULL };
+        GDALDataset* poDS = (GDALDataset*) GDALOpenEx(m_pDS->GetName(),
+                            GDAL_OF_VECTOR, (char**)apszDrivers, NULL, NULL);
+        if( poDS != NULL )
+        {
+            OGRLayer* poLyr = poDS->GetLayerByName(GetName());
+            if( poLyr )
+            {
+                for(int i=0;i<poLyr->GetLayerDefn()->GetFieldCount();i++)
+                {
+                    OGRFieldDefn* poSrcDefn = poLyr->GetLayerDefn()->GetFieldDefn(i);
+                    if( (poSrcDefn->GetType() == OFTInteger || poSrcDefn->GetType() == OFTReal) &&
+                        poSrcDefn->GetDefault() != NULL )
+                    {
+                        int nIdxDst = m_pFeatureDefn->GetFieldIndex(poSrcDefn->GetNameRef());
+                        if( nIdxDst >= 0 )
+                            m_pFeatureDefn->GetFieldDefn(nIdxDst)->SetDefault(poSrcDefn->GetDefault());
+                    }
+                }
+            }
+            GDALClose( poDS );
+        }
+    }
+
     return true;
 }
 
@@ -2163,7 +2337,7 @@ bool FGdbBaseLayer::OGRFeatureFromGdbRow(Row* pRow, OGRFeature** ppFeature)
     {
         OGRGeometry* pOGRGeo = NULL;
 
-        if ((!GDBGeometryToOGRGeometry(m_forceMulti, &gdbGeometry, m_pSRS, &pOGRGeo)) || pOGRGeo == NULL)
+        if ((!GDBGeometryToOGRGeometry(m_forceMulti, &gdbGeometry, m_pSRS, &pOGRGeo)))
         {
             delete pOutFeature;
             return GDBErr(hr, "Failed to translate FileGDB Geometry to OGR Geometry for row " + string(CPLSPrintf("%d", (int)oid)));
@@ -2399,7 +2573,7 @@ OGRFeature* FGdbLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *FGdbLayer::GetFeature( long oid )
+OGRFeature *FGdbLayer::GetFeature( GIntBig oid )
 {
     // do query to fetch individual row
     EnumRows       enumRows;
@@ -2425,7 +2599,7 @@ OGRFeature *FGdbLayer::GetFeature( long oid )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int FGdbLayer::GetFeatureCount( int bForce )
+GIntBig FGdbLayer::GetFeatureCount( CPL_UNUSED int bForce )
 {
     long           hr;
     int32          rowCount = 0;
@@ -2654,7 +2828,7 @@ int FGdbLayer::TestCapability( const char* pszCap )
     else if (EQUAL(pszCap,OLCCreateField)) /* CreateField() */
         return m_pDS->GetUpdate();
 
-    else if (EQUAL(pszCap,OLCSequentialWrite)) /* CreateFeature() */
+    else if (EQUAL(pszCap,OLCSequentialWrite)) /* ICreateFeature() */
         return m_pDS->GetUpdate();
 
     else if (EQUAL(pszCap,OLCStringsAsUTF8)) /* Native UTF16, converted to UTF8 */
@@ -2666,7 +2840,7 @@ int FGdbLayer::TestCapability( const char* pszCap )
     else if (EQUAL(pszCap,OLCDeleteFeature)) /* DeleteFeature() */
         return m_pDS->GetUpdate();
 
-    else if (EQUAL(pszCap,OLCRandomWrite)) /* SetFeature() */
+    else if (EQUAL(pszCap,OLCRandomWrite)) /* ISetFeature() */
         return m_pDS->GetUpdate();
 
     else if (EQUAL(pszCap,OLCDeleteField)) /* DeleteField() */
@@ -2689,3 +2863,15 @@ int FGdbLayer::TestCapability( const char* pszCap )
     else 
         return FALSE;
 }
+
+/************************************************************************/
+/*                       ReadoptOldFeatureDefn()                        */
+/************************************************************************/
+
+void FGdbLayer::ReadoptOldFeatureDefn(OGRFeatureDefn* poFeatureDefn)
+{
+    CPLAssert(m_pFeatureDefn->IsSame(poFeatureDefn));
+    m_pFeatureDefn->Release();
+    m_pFeatureDefn = poFeatureDefn;
+    m_pFeatureDefn->Reference();
+}
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbResultLayer.cpp b/ogr/ogrsf_frmts/filegdb/FGdbResultLayer.cpp
index 5add04b..c1c2157 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbResultLayer.cpp
+++ b/ogr/ogrsf_frmts/filegdb/FGdbResultLayer.cpp
@@ -5,7 +5,7 @@
 * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
 *
 ******************************************************************************
- * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -42,6 +42,7 @@ FGdbResultLayer::FGdbResultLayer(FGdbDataSource* pParentDataSource,
                                  EnumRows* pEnumRows)
 {
     m_pFeatureDefn = new OGRFeatureDefn("result");
+    SetDescription( m_pFeatureDefn->GetName() );
     m_pFeatureDefn->Reference();
     m_pEnumRows = pEnumRows;
     m_pDS = pParentDataSource;
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbUtils.cpp b/ogr/ogrsf_frmts/filegdb/FGdbUtils.cpp
index 08185ef..98c38f0 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbUtils.cpp
+++ b/ogr/ogrsf_frmts/filegdb/FGdbUtils.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
-* $Id: FGdbUtils.cpp 27044 2014-03-16 23:41:27Z rouault $
+* $Id: FGdbUtils.cpp 28573 2015-02-27 18:13:19Z rouault $
 *
 * Project:  OpenGIS Simple Features Reference Implementation
 * Purpose:  Different utility functions used in FileGDB OGR driver.
@@ -9,7 +9,7 @@
 ******************************************************************************
 * Copyright (c) 2010, Ragi Yaser Burhum
 * Copyright (c) 2011, Paul Ramsey <pramsey at cleverelephant.ca>
- * Copyright (c) 2011-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2011-2014, Even Rouault <even dot rouault at mines-paris dot org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -36,7 +36,7 @@
 #include "ogr_api.h"
 #include "ogrpgeogeometry.h"
 
-CPL_CVSID("$Id: FGdbUtils.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: FGdbUtils.cpp 28573 2015-02-27 18:13:19Z rouault $");
 
 using std::string;
 
@@ -68,7 +68,7 @@ std::string WStringToString(const std::wstring& utf16string)
 /*                                GDBErr()                               */
 /*************************************************************************/
 
-bool GDBErr(long int hr, std::string desc)
+bool GDBErr(long int hr, std::string desc, CPLErr errType, const char* pszAddMsg)
 {
     std::wstring fgdb_error_desc_w;
     fgdbError er;
@@ -76,13 +76,13 @@ bool GDBErr(long int hr, std::string desc)
     if ( er == S_OK )
     {
         std::string fgdb_error_desc = WStringToString(fgdb_error_desc_w);
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Error: %s (%s)", desc.c_str(), fgdb_error_desc.c_str());
+        CPLError( errType, CPLE_AppDefined,
+                  "%s (%s)%s", desc.c_str(), fgdb_error_desc.c_str(), pszAddMsg);
     }
     else
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Error (%ld): %s", hr, desc.c_str());
+        CPLError( errType, CPLE_AppDefined,
+                  "Error (%ld): %s%s", hr, desc.c_str(), pszAddMsg);
     }
     // FIXME? EvenR: not sure if ClearErrors() is really necessary, but as it, it causes crashes in case of
     // repeated errors
@@ -239,7 +239,7 @@ bool OGRGeometryToGDB(OGRwkbGeometryType ogrType, std::string *gdbType, bool *ha
 
 // We could make this function far more robust by doing automatic coertion of types,
 // and/or skipping fields we do not know. But our purposes this works fine
-bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* pOut)
+bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* pOut, OGRFieldSubType* pSubType)
 {
     /*
     ESRI types
@@ -274,14 +274,25 @@ bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* pOut)
     /** Time *///                                   OFTTime = 10,               NO
     /** Date and Time *///                          OFTDateTime = 11            YES
 
-    if (gdbType == "esriFieldTypeSmallInteger" ||
-        gdbType == "esriFieldTypeInteger")
+    *pSubType = OFSTNone;
+    if (gdbType == "esriFieldTypeSmallInteger" )
+    {
+        *pSubType = OFSTInt16;
+        *pOut = OFTInteger;
+        return true;
+    }
+    else if (gdbType == "esriFieldTypeInteger")
     {
         *pOut = OFTInteger;
         return true;
     }
-    else if (gdbType == "esriFieldTypeSingle" ||
-        gdbType == "esriFieldTypeDouble")
+    else if (gdbType == "esriFieldTypeSingle" )
+    {
+        *pSubType = OFSTFloat32;
+        *pOut = OFTReal;
+        return true;
+    }
+    else if (gdbType == "esriFieldTypeDouble")
     {
         *pOut = OFTReal;
         return true;
@@ -321,18 +332,25 @@ bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* pOut)
 /*                            OGRToGDBFieldType()                        */
 /*************************************************************************/
 
-bool OGRToGDBFieldType(OGRFieldType ogrType, std::string* gdbType)
+bool OGRToGDBFieldType(OGRFieldType ogrType, OGRFieldSubType eSubType, std::string* gdbType)
 {
     switch(ogrType)
     {
         case OFTInteger:
         {
-            *gdbType = "esriFieldTypeInteger";
+            if( eSubType == OFSTInt16 )
+                *gdbType = "esriFieldTypeSmallInteger";
+            else
+                *gdbType = "esriFieldTypeInteger";
             break;
         }
         case OFTReal:
+        case OFTInteger64:
         {
-            *gdbType = "esriFieldTypeDouble";
+             if( eSubType == OFSTFloat32 )
+                *gdbType = "esriFieldTypeSingle";
+            else
+                *gdbType = "esriFieldTypeDouble";
             break;
         }
         case OFTString:
@@ -412,6 +430,10 @@ bool GDBFieldTypeToWidthPrecision(std::string &gdbType, int *width, int *precisi
     {
         *width = 0;
     }
+    else if(gdbType == "esriFieldTypeGlobalID" )
+    {
+        *width = 38;
+    }
     else
     {
         CPLError( CE_Warning, CPLE_AppDefined,
diff --git a/ogr/ogrsf_frmts/filegdb/FGdbUtils.h b/ogr/ogrsf_frmts/filegdb/FGdbUtils.h
index bae4bca..215eb9d 100644
--- a/ogr/ogrsf_frmts/filegdb/FGdbUtils.h
+++ b/ogr/ogrsf_frmts/filegdb/FGdbUtils.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: FGdbUtils.h 23796 2012-01-24 19:10:16Z rouault $
+ * $Id: FGdbUtils.h 28573 2015-02-27 18:13:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Various FileGDB OGR Datasource utility functions
@@ -60,8 +60,8 @@ bool GhettoGDBGeometryToOGRGeometry(bool forceMulti, FileGDBAPI::ShapeBuffer* pG
 //
 // GDB API to OGR Field Mapping
 //
-bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* ogrType);
-bool OGRToGDBFieldType(OGRFieldType ogrType, std::string* gdbType);
+bool GDBToOGRFieldType(std::string gdbType, OGRFieldType* ogrType, OGRFieldSubType* pSubType);
+bool OGRToGDBFieldType(OGRFieldType ogrType, OGRFieldSubType eSubType, std::string* gdbType);
 
 //
 // GDB Field Width defaults
@@ -71,7 +71,7 @@ bool GDBFieldTypeToWidthPrecision(std::string &gdbType, int *width, int *precisi
 //
 // GDBAPI error to OGR
 //
-bool GDBErr(long hr, std::string desc);
+bool GDBErr(long hr, std::string desc, CPLErr errType = CE_Failure, const char* pszAddMsg = "");
 bool GDBDebug(long hr, std::string desc);
 
 //
diff --git a/ogr/ogrsf_frmts/filegdb/GNUmakefile b/ogr/ogrsf_frmts/filegdb/GNUmakefile
index 6bfd44e..d1c0a74 100644
--- a/ogr/ogrsf_frmts/filegdb/GNUmakefile
+++ b/ogr/ogrsf_frmts/filegdb/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	FGdbDatasource.o FGdbDriver.o FGdbLayer.o FGdbUtils.o FGdbResultLayer.o 
 
-CPPFLAGS	:=	-I../generic $(GDAL_INCLUDE) $(FGDB_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-I../generic  $(FGDB_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/filegdb/drv_filegdb.html b/ogr/ogrsf_frmts/filegdb/drv_filegdb.html
index 150905d..149d8a8 100644
--- a/ogr/ogrsf_frmts/filegdb/drv_filegdb.html
+++ b/ogr/ogrsf_frmts/filegdb/drv_filegdb.html
@@ -9,7 +9,7 @@
 
 <p>The FileGDB driver provides read and write access to File Geodatabases (.gdb directories) created by ArcGIS 10 and above.</p>
 
-<p>Note : starting with OGR 1.11, the <a href="drv_openfilegdb.html">OpenFileGDB driver</a> driver exists as an alternative built-in 
+<p>Note : starting with OGR 1.11, the <a href="drv_openfilegdb.html">OpenFileGDB driver</a> driver exists as an alternative built-in
 i.e. not depending on a third-party library) read-only driver.</p>
 
 <h2>Requirements</h2>
@@ -40,6 +40,19 @@ SELECT statements will be run by default by the OGR SQL engine. This can be chan
 "GetLayerDefinition a_layer_name" and "GetLayerMetadata a_layer_name" can be used as special SQL requests to get
 respectively the definition and metadata of a FileGDB table as XML content.
 
+<h2>Transaction support (OGR >= 2.0)</h2>
+
+The FileGDB driver implements transactions at the database level, through an
+emulation (as per <a href="http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions">RFC 54</a>),
+since the FileGDB SDK itself does not offer it. This works by backing up the
+current state of a geodatabase when StartTransaction(force=TRUE) is called.
+If the transaction is committed, the backup copy is destroyed. If the transaction
+is rolled back, the backup copy is restored. So this might be costly when operating
+on huge geodatabases.<p>
+
+Note that this emulation has an unspecified behaviour in case of concurrent updates
+(with different connections in the same or another process).<p>
+
 <h2>Dataset Creation Options</h2>
 
 <p>None.</p>
@@ -49,7 +62,8 @@ respectively the definition and metadata of a FileGDB table as XML content.
 <ul>
 	<li><b>FEATURE_DATASET</b>: When this option is set, the new layer will be created inside the named FeatureDataset folder. If the folder does not already exist, it will be created.</li>
 	<li><b>GEOMETRY_NAME</b>: Set name of geometry column in new layer. Defaults to "SHAPE".</li>
-	<li><b>OID_NAME</b>: Name of the OID column to create. Defaults to "OBJECTID".</li>
+        <li><b>GEOMETRY_NULLABLE</b>: (GDAL >=2.0)  Whether the values of the geometry column can be NULL. Can be set to NO so that geometry is required. Default to "YES"</li>
+	<li><b>FID</b>: Name of the OID column to create. Defaults to "OBJECTID". Note: option was called OID_NAME in releases before GDAL 2</li>
 	<li><b>XYTOLERANCE, ZTOLERANCE</b>: These parameters control the snapping tolerance used for advanced ArcGIS features like network and topology rules. They won't effect any 	OGR operations, but they will by used by ArcGIS. The units of the parameters are the units of the coordinate reference system.
 		<p>ArcMap 10.0 and OGR defaults for XYTOLERANCE are 0.001m (or equivalent) for projected coordinate systems, and 0.000000008983153° for geographic coordinate systems.</p></li>
 	<li><b>XORIGIN, YORIGIN, ZORIGIN, XYSCALE, ZSCALE</b>: These parameters control the <a href="http://help.arcgis.com/en/sdk/10.0/java_ao_adf/conceptualhelp/engine/index.html#//00010000037m000000">coordinate precision grid</a>  inside the file geodatabase. The dimensions of the grid are determined by the origin, and the scale. The origin defines the location of a reference grid point in space. The scale is the reciprocal of the resolution. So, to get a grid with an origin at 0 and a resol [...]
@@ -59,6 +73,7 @@ respectively the definition and metadata of a FileGDB table as XML content.
 			<li>For projected coordinate systems: XYSCALE=10000 for the default XYTOLERANCE of 0.001m. XORIGIN and YORIGIN change based on the coordinate system, but the OGR default of -2147483647 is suitable with the default XYSCALE for all coordinate systems.</li></ul></p></li>
 	<li><b>XML_DEFINITION</b> : (GDAL >= 1.10) When this option is set, its value will be used as the XML definition to create the new table. The root node of such a XML definition must be a <esri:DataElement> element conformant to FileGDBAPI.xsd</li>
     <li><b>CREATE_MULTIPATCH</b>=YES : (GDAL >= 1.11) When this option is set, geometries of layers of type MultiPolygon will be written as MultiPatch</li>
+    <li><b>CONFIGURATION_KEYWORD</b>=DEFAULTS/TEXT_UTF16/MAX_FILE_SIZE_4GB/MAX_FILE_SIZE_256TB/GEOMETRY_OUTOFLINE/BLOB_OUTOFLINE/GEOMETRY_AND_BLOB_OUTOFLINE : (GDAL >= 2.0) Customize how data is stored. By default text in UTF-8 and data up to 1TB</li>
 </ul>
 
 <h2>Examples</h2>
@@ -87,8 +102,13 @@ respectively the definition and metadata of a FileGDB table as XML content.
 <h2>Known Issues</h2>
 
 <ul>
+        <li>The SDK is known to be unable to open layers with particular spatialy reference systems.
+            This might be the case if messages "FGDB: Error opening XXXXXXX. Skipping it (Invalid function arguments.)"
+            when running "ogrinfo --debug on the.gdb" (reported as warning in GDAL 2.0).
+            Using the OpenFileGDB driver will generally solve that issue.</li>
 	<li>Blob fields have not been implemented.</li>
 	<li>FGDB coordinate snapping will cause geometries to be altered during writing. Use the origin and scale layer creation options to control the snapping behavior.</li>
+	<li>Driver can't read data from compressed feature classes (SDC, Smart Data Compression) because operation is not supported by the ESRI SDK.</li>
 </ul>
 
 <h2>Links</h2>
diff --git a/ogr/ogrsf_frmts/filegdb/makefile.vc b/ogr/ogrsf_frmts/filegdb/makefile.vc
index 7f6ff7e..aa3332a 100644
--- a/ogr/ogrsf_frmts/filegdb/makefile.vc
+++ b/ogr/ogrsf_frmts/filegdb/makefile.vc
@@ -24,7 +24,7 @@ clean:
 plugin: $(PLUGIN_DLL)
 
 $(PLUGIN_DLL):	$(OBJ)
-	link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) $(GDAL_ROOT)/gdal_i.lib $(FGDB_LIB) ..\ogrsf_frmts.lib 
+	link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) $(GDAL_ROOT)/gdal_i.lib $(FGDB_LIB)
 	if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2
 
 
diff --git a/ogr/ogrsf_frmts/filegdb/ogr_fgdb.h b/ogr/ogrsf_frmts/filegdb/ogr_fgdb.h
index 6a0e7b3..3c4536d 100644
--- a/ogr/ogrsf_frmts/filegdb/ogr_fgdb.h
+++ b/ogr/ogrsf_frmts/filegdb/ogr_fgdb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
-* $Id: ogr_fgdb.h 27654 2014-09-09 18:28:10Z rouault $
+* $Id: ogr_fgdb.h 28601 2015-03-03 11:06:40Z rouault $
 *
 * Project:  OpenGIS Simple Features Reference Implementation
 * Purpose:  Standard includes and class definitions ArcObjects OGR driver.
@@ -7,7 +7,7 @@
 *
 ******************************************************************************
 * Copyright (c) 2009, Ragi Yaser Burhum
- * Copyright (c) 2011-2014, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2011-2014, Even Rouault <even dot rouault at mines-paris dot org>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
@@ -33,7 +33,7 @@
 
 #include <vector>
 #include "ogrsf_frmts.h"
-#include "ogrmutexedlayer.h"
+#include "ogremulatedtransaction.h"
 
 /* GDAL string utilities */
 #include "cpl_string.h"
@@ -115,7 +115,7 @@ class FGdbLayer : public FGdbBaseLayer
 
   std::vector<ByteArray*> m_apoByteArrays;
   OGRErr              PopulateRowWithFeature( Row& row, OGRFeature *poFeature );
-  OGRErr              GetRow( EnumRows& enumRows, Row& row, long nFID );
+  OGRErr              GetRow( EnumRows& enumRows, Row& row, GIntBig nFID );
 
   char              **m_papszOptions;
   
@@ -141,7 +141,7 @@ public:
 
   virtual void        ResetReading();
   virtual OGRFeature* GetNextFeature();
-  virtual OGRFeature* GetFeature( long nFeatureId );
+  virtual OGRFeature* GetFeature( GIntBig nFeatureId );
 
   Table* GetTable() { return m_pTable; }
 
@@ -154,12 +154,12 @@ public:
   virtual OGRErr      AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poNewFieldDefn, int nFlags );
 #endif
 
-  virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-  virtual OGRErr      SetFeature( OGRFeature *poFeature );
-  virtual OGRErr      DeleteFeature( long nFID );
+  virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+  virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+  virtual OGRErr      DeleteFeature( GIntBig nFID );
 
   virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce );
-  virtual int         GetFeatureCount( int bForce );
+  virtual GIntBig     GetFeatureCount( int bForce );
   virtual OGRErr      SetAttributeFilter( const char *pszQuery );
   virtual void 	      SetSpatialFilterRect (double dfMinX, double dfMinY, double dfMaxX, double dfMaxY);
   virtual void        SetSpatialFilter( OGRGeometry * );
@@ -177,11 +177,13 @@ public:
   OGRErr              GetLayerXML ( char **poXml );
   OGRErr              GetLayerMetadataXML ( char **poXmlMeta );
   
+  void                ReadoptOldFeatureDefn(OGRFeatureDefn* poFeatureDefn);
+  
 protected:
 
   bool GDBToOGRFields(CPLXMLNode* psFields);  
   bool ParseGeometryDef(CPLXMLNode* psGeometryDef);
-  bool ParseSpatialReference(CPLXMLNode* psSpatialRefNode, std::string* pOutWkt,
+  bool ParseSpatialReference(CPLXMLNode* psSpatialRefNode, std::string* pOutWkt,
                              std::string* pOutWKID, std::string* pOutLatestWKID);
 
   FGdbDataSource* m_pDS;
@@ -232,21 +234,23 @@ protected:
 /*                           FGdbDataSource                            */
 /************************************************************************/
 
+class FGdbDatabaseConnection;
+
 class FGdbDataSource : public OGRDataSource
 {
 
 public:
-  FGdbDataSource(FGdbDriver* poDriver);
+  FGdbDataSource(FGdbDriver* poDriver, FGdbDatabaseConnection* pConnection);
   virtual ~FGdbDataSource();
 
-  int         Open(Geodatabase* pGeodatabase, const char *, int );
+  int         Open(const char *, int );
 
   const char* GetName() { return m_pszName; }
   int         GetLayerCount() { return static_cast<int>(m_layers.size()); }
 
   OGRLayer*   GetLayer( int );
 
-  virtual OGRLayer* CreateLayer( const char *, OGRSpatialReference* = NULL, OGRwkbGeometryType = wkbUnknown, char** = NULL );
+  virtual OGRLayer* ICreateLayer( const char *, OGRSpatialReference* = NULL, OGRwkbGeometryType = wkbUnknown, char** = NULL );
 
   virtual OGRErr DeleteLayer( int );
 
@@ -259,6 +263,7 @@ public:
 
   Geodatabase* GetGDB() { return m_pGeodatabase; }
   bool         GetUpdate() { return m_bUpdate; }
+  FGdbDatabaseConnection* GetConnection() { return m_pConnection; }
 
   /*
   protected:
@@ -272,11 +277,11 @@ protected:
                       const std::vector<std::wstring> &layers);
 
   FGdbDriver* m_poDriver;
+  FGdbDatabaseConnection* m_pConnection;
   char* m_pszName;
-  std::vector <OGRMutexedLayer*> m_layers;
+  std::vector <FGdbLayer*> m_layers;
   Geodatabase* m_pGeodatabase;
   bool m_bUpdate;
-
 };
 
 /************************************************************************/
@@ -287,16 +292,22 @@ class FGdbDatabaseConnection
 {
 public:
     FGdbDatabaseConnection(Geodatabase* pGeodatabase) :
-        m_pGeodatabase(pGeodatabase), m_nRefCount(1) {}
+        m_pGeodatabase(pGeodatabase), m_nRefCount(1), m_bLocked(FALSE) {}
 
     Geodatabase* m_pGeodatabase;
     int          m_nRefCount;
+    int          m_bLocked;
+    
+    Geodatabase* GetGDB() { return m_pGeodatabase; }
+    void         SetLocked(int bLockedIn) { m_bLocked = bLockedIn; }
+    int          GetRefCount() const { return m_nRefCount; }
+    int          IsLocked() const { return m_bLocked; }
 };
 
-class FGdbDriver : public OGRSFDriver
+class FGdbDriver : public OGRSFDriver, public IOGRTransactionBehaviour
 {
   std::map<CPLString, FGdbDatabaseConnection*> oMapConnections;
-  void* hMutex;
+  CPLMutex* hMutex;
 
 public:
   FGdbDriver();
@@ -308,8 +319,14 @@ public:
   virtual OGRDataSource *CreateDataSource( const char *pszName, char ** = NULL);
   virtual OGRErr DeleteDataSource( const char *pszDataSource );
 
+  /* From IOGRTransactionBehaviour */
+  virtual OGRErr StartTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS);
+  virtual OGRErr CommitTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS);
+  virtual OGRErr RollbackTransaction(OGRDataSource*& poDSInOut, int& bOutHasReopenedDS);
+  virtual void   ReadoptOldFeatureDefn(OGRDataSource* poDS, OGRLayer* poLayer, OGRFeatureDefn* poFeatureDefn);
+
   void Release(const char* pszName);
-  void* GetMutex() { return hMutex; }
+  CPLMutex* GetMutex() { return hMutex; }
 
 private:
 
diff --git a/ogr/ogrsf_frmts/fme/GNUmakefile b/ogr/ogrsf_frmts/fme/GNUmakefile
index 54d30ed..8e3a8cf 100644
--- a/ogr/ogrsf_frmts/fme/GNUmakefile
+++ b/ogr/ogrsf_frmts/fme/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	ogrfmecacheindex.o ogrfmedatasource.o ogrfmedriver.o \
 		ogrfmelayer.o ogrfmelayercached.o ogrfmelayerdb.o \
 		fme2ogr_utils.o
 
-CPPFLAGS	+=	-I.. -I../.. $(GDAL_INCLUDE) $(FME_INCLUDE) \
+CPPFLAGS	+=	-I.. -I../..  $(FME_INCLUDE) \
 		-DSUPPORT_INDIRECT_FMEDLL -DSUPPORT_PERSISTENT_CACHE
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
diff --git a/ogr/ogrsf_frmts/fme/fme2ogr.h b/ogr/ogrsf_frmts/fme/fme2ogr.h
index 4cce7d4..d62915c 100644
--- a/ogr/ogrsf_frmts/fme/fme2ogr.h
+++ b/ogr/ogrsf_frmts/fme/fme2ogr.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fme2ogr.h 12123 2007-09-11 23:57:40Z warmerdam $
+ * $Id: fme2ogr.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  FMEObjects Translator
  * Purpose:  Declarations for translating IFMEFeatures to OGRFeatures.
@@ -98,7 +98,7 @@ class OGRFMELayerCached : public OGRFMELayer
                        
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int bForce );
+    virtual GIntBig     GetFeatureCount( int bForce );
 
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
     
@@ -138,7 +138,7 @@ class OGRFMELayerDB : public OGRFMELayer
     
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int bForce );
+    virtual GIntBig     GetFeatureCount( int bForce );
 
     virtual int         TestCapability( const char * );
 
diff --git a/ogr/ogrsf_frmts/fme/ogrfmedatasource.cpp b/ogr/ogrsf_frmts/fme/ogrfmedatasource.cpp
index c139280..a855747 100644
--- a/ogr/ogrsf_frmts/fme/ogrfmedatasource.cpp
+++ b/ogr/ogrsf_frmts/fme/ogrfmedatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfmedatasource.cpp 13253 2007-12-05 14:54:00Z warmerdam $
+ * $Id: ogrfmedatasource.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  FMEObjects Translator
  * Purpose:  Implementations of the OGRFMEDataSource class.
@@ -39,7 +39,7 @@
 
 const char* kPROVIDERNAME = "FME_OLEDB";
 
-CPL_CVSID("$Id: ogrfmedatasource.cpp 13253 2007-12-05 14:54:00Z warmerdam $");
+CPL_CVSID("$Id: ogrfmedatasource.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 #ifdef WIN32
 #define FMEDLL_NAME "fme.dll"
@@ -1008,7 +1008,7 @@ void OGRFMEDataSource::ClarifyGeometryClass(
 
     // Is this 3D?
     if( poFeature->getDimension() == FME_THREE_D )
-        eThisType = (OGRwkbGeometryType) (eThisType | wkb25DBit);
+        eThisType = wkbSetZ(eThisType);
     
 /* -------------------------------------------------------------------- */
 /*      Now adjust the working type.                                    */
@@ -1034,10 +1034,10 @@ void OGRFMEDataSource::ClarifyGeometryClass(
     else
         eNewBestGeomType = wkbUnknown;
 
-    if( ((eBestGeomType & wkb25DBit) || (eThisType & wkb25DBit)) 
+    if( (wkbHasZ(eBestGeomType) || wkbHasZ(eThisType)) 
         && (int) eNewBestGeomType != 500 )
     {
-        eNewBestGeomType = (OGRwkbGeometryType)(((int) eBestGeomType) | wkb25DBit);
+        eNewBestGeomType = wkbSetZ(eNewBestGeomType);
     } 
 
     eBestGeomType = eNewBestGeomType;
diff --git a/ogr/ogrsf_frmts/fme/ogrfmelayer.cpp b/ogr/ogrsf_frmts/fme/ogrfmelayer.cpp
index 01c300b..f45a45b 100644
--- a/ogr/ogrsf_frmts/fme/ogrfmelayer.cpp
+++ b/ogr/ogrsf_frmts/fme/ogrfmelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfmelayer.cpp 12123 2007-09-11 23:57:40Z warmerdam $
+ * $Id: ogrfmelayer.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  FMEObjects Translator
  * Purpose:  Implementation of the OGRFMELayer base class.  The class
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrfmelayer.cpp 12123 2007-09-11 23:57:40Z warmerdam $");
+CPL_CVSID("$Id: ogrfmelayer.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                            OGRFMELayer()                             */
@@ -105,6 +105,7 @@ int OGRFMELayer::Initialize( IFMEFeature * poSchemaFeature,
     poSchemaFeature->getFeatureType( *poFMEString );
 
     poFeatureDefn = new OGRFeatureDefn( poFMEString->data() );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poDS->GetFMESession()->destroyString( poFMEString );
@@ -274,7 +275,7 @@ int OGRFMELayer::Initialize( IFMEFeature * poSchemaFeature,
 /*      Assign the geometry type ... try to apply 3D-ness as well.      */
 /* -------------------------------------------------------------------- */
     if( poSchemaFeature->getDimension() == FME_THREE_D )
-        eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
+        eGeomType = wkbSetZ(eGeomType);
 
     poFeatureDefn->SetGeomType( eGeomType );
 
diff --git a/ogr/ogrsf_frmts/fme/ogrfmelayercached.cpp b/ogr/ogrsf_frmts/fme/ogrfmelayercached.cpp
index 1a94ccd..0bd17b6 100644
--- a/ogr/ogrsf_frmts/fme/ogrfmelayercached.cpp
+++ b/ogr/ogrsf_frmts/fme/ogrfmelayercached.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfmelayercached.cpp 14412 2008-05-09 15:02:27Z warmerdam $
+ * $Id: ogrfmelayercached.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  FMEObjects Translator
  * Purpose:  Implementation of the OGRFMELayerCached class.  This is the
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrfmelayercached.cpp 14412 2008-05-09 15:02:27Z warmerdam $");
+CPL_CVSID("$Id: ogrfmelayercached.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                         OGRFMELayerCached()                          */
@@ -248,7 +248,7 @@ void OGRFMELayerCached::ResetReading()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRFMELayerCached::GetFeatureCount( int bForce )
+GIntBig OGRFMELayerCached::GetFeatureCount( int bForce )
 
 {
     int    nResult;
diff --git a/ogr/ogrsf_frmts/fme/ogrfmelayerdb.cpp b/ogr/ogrsf_frmts/fme/ogrfmelayerdb.cpp
index a87a766..0b61a54 100644
--- a/ogr/ogrsf_frmts/fme/ogrfmelayerdb.cpp
+++ b/ogr/ogrsf_frmts/fme/ogrfmelayerdb.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrfmelayerdb.cpp 12123 2007-09-11 23:57:40Z warmerdam $
+ * $Id: ogrfmelayerdb.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  FMEObjects Translator
  * Purpose:  Implementation of the OGRFMELayerDB class.  This is the
@@ -34,7 +34,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrfmelayerdb.cpp 12123 2007-09-11 23:57:40Z warmerdam $");
+CPL_CVSID("$Id: ogrfmelayerdb.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGRFMELayerDB()                            */
@@ -431,7 +431,7 @@ int OGRFMELayerDB::CreateReader()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRFMELayerDB::GetFeatureCount( int bForce )
+GIntBig OGRFMELayerDB::GetFeatureCount( int bForce )
 
 {
     /*
diff --git a/ogr/ogrsf_frmts/generic/GNUmakefile b/ogr/ogrsf_frmts/generic/GNUmakefile
index 7c6d5fd..70a2e70 100644
--- a/ogr/ogrsf_frmts/generic/GNUmakefile
+++ b/ogr/ogrsf_frmts/generic/GNUmakefile
@@ -6,7 +6,12 @@ OBJ	=	ogrsfdriverregistrar.o ogrlayer.o ogrdatasource.o \
 		ogrsfdriver.o ogrregisterall.o ogr_gensql.o \
 		ogr_attrind.o ogr_miattrind.o ogrlayerdecorator.o \
 		ogrwarpedlayer.o ogrunionlayer.o ogrlayerpool.o \
-		ogrmutexedlayer.o ogrmutexeddatasource.o
+		ogrmutexedlayer.o ogrmutexeddatasource.o \
+		ogremulatedtransaction.o
+
+CXXFLAGS :=     $(CXXFLAGS) -DINST_DATA=\"$(INST_DATA)\"
+
+ifeq ($(OGR_ENABLED),yes)
 
 BASEFORMATS = \
 	-DAVCBIN_ENABLED \
@@ -47,9 +52,11 @@ BASEFORMATS = \
 	-DSEGY_ENABLED \
 	-DSXF_ENABLED \
 	-DOPENFILEGDB_ENABLED \
-	-DWASP_ENABLED
+	-DWASP_ENABLED \
+	-DSELAFIN_ENABLED \
+	-DJML_ENABLED
 
-CXXFLAGS :=     $(CXXFLAGS) -DINST_DATA=\"$(INST_DATA)\" $(BASEFORMATS)
+CXXFLAGS :=     $(CXXFLAGS) $(BASEFORMATS)
 
 ifeq ($(HAVE_OGDI),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DOGDI_ENABLED
@@ -149,6 +156,7 @@ endif
 
 ifeq ($(CURL_SETTING),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DWFS_ENABLED
+CXXFLAGS :=	$(CXXFLAGS) -DCSW_ENABLED
 endif
 
 ifeq ($(GEOMEDIA_SETTING),yes)
@@ -171,6 +179,10 @@ ifeq ($(CURL_SETTING),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DCOUCHDB_ENABLED
 endif
 
+ifeq ($(CURL_SETTING),yes)
+CXXFLAGS :=	$(CXXFLAGS) -DCLOUDANT_ENABLED
+endif
+
 ifeq ($(HAVE_FREEXL),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DFREEXL_ENABLED
 endif
@@ -191,10 +203,6 @@ ifeq ($(HAVE_SQLITE),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DOSM_ENABLED
 endif
 
-ifneq ($(LIBZ_SETTING),no)
-CXXFLAGS :=	$(CXXFLAGS) -DPDF_ENABLED
-endif
-
 ifeq ($(ODBC_SETTING),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DWALK_ENABLED
 endif
@@ -203,7 +211,13 @@ ifeq ($(CURL_SETTING),yes)
 CXXFLAGS :=	$(CXXFLAGS) -DCARTODB_ENABLED
 endif
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+ifeq ($(CURL_SETTING),yes)
+CXXFLAGS :=	$(CXXFLAGS) -DPLSCENES_ENABLED
+endif
+
+endif
+
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/generic/makefile.vc b/ogr/ogrsf_frmts/generic/makefile.vc
index f247a16..00de6ba 100644
--- a/ogr/ogrsf_frmts/generic/makefile.vc
+++ b/ogr/ogrsf_frmts/generic/makefile.vc
@@ -3,29 +3,24 @@ OBJ	=	ogrsfdriverregistrar.obj ogrlayer.obj ogr_gensql.obj \
 		ogrdatasource.obj ogrsfdriver.obj ogrregisterall.obj \
 		ogr_attrind.obj ogr_miattrind.obj ogrlayerdecorator.obj \
 		ogrwarpedlayer.obj ogrunionlayer.obj ogrlayerpool.obj \
-		ogrmutexedlayer.obj ogrmutexeddatasource.obj
+		ogrmutexedlayer.obj ogrmutexeddatasource.obj \
+		ogremulatedtransaction.obj
 
 
 GDAL_ROOT	=	..\..\..
 
-BASEFORMATS = -DSHAPE_ENABLED -DTAB_ENABLED -DNTF_ENABLED -DSDTS_ENABLED -DTIGER_ENABLED -DS57_ENABLED -DDGN_ENABLED -DVRT_ENABLED -DAVCBIN_ENABLED -DREC_ENABLED -DMEM_ENABLED -DCSV_ENABLED -DGML_ENABLED -DGMT_ENABLED -DBNA_ENABLED -DKML_ENABLED -DGEOJSON_ENABLED -DGPX_ENABLED -DGEOCONCEPT_ENABLED -DXPLANE_ENABLED -DGEORSS_ENABLED -DGTM_ENABLED -DDXF_ENABLED -DPGDUMP_ENABLED -DGPSBABEL_ENABLED -DSUA_ENABLED -DOPENAIR_ENABLED -DPDS_ENABLED -DHTF_ENABLED -DAERONAVFAA_ENABLED -DEDIGEO_ENABL [...]
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+!IFDEF INCLUDE_OGR_FRMTS
+
+BASEFORMATS = -DSHAPE_ENABLED -DTAB_ENABLED -DNTF_ENABLED -DSDTS_ENABLED -DTIGER_ENABLED -DS57_ENABLED -DDGN_ENABLED -DVRT_ENABLED -DAVCBIN_ENABLED -DREC_ENABLED -DMEM_ENABLED -DCSV_ENABLED -DGML_ENABLED -DGMT_ENABLED -DBNA_ENABLED -DKML_ENABLED -DGEOJSON_ENABLED -DGPX_ENABLED -DGEOCONCEPT_ENABLED -DXPLANE_ENABLED -DGEORSS_ENABLED -DGTM_ENABLED -DDXF_ENABLED -DPGDUMP_ENABLED -DGPSBABEL_ENABLED -DSUA_ENABLED -DOPENAIR_ENABLED -DPDS_ENABLED -DHTF_ENABLED -DAERONAVFAA_ENABLED -DEDIGEO_ENABL [...]
 
 EXTRAFLAGS =	-I.. -I..\.. $(OGDIDEF) $(FMEDEF) $(OCIDEF) $(PGDEF) \
 		$(ODBCDEF) $(SQLITEDEF) $(MYSQLDEF) $(ILIDEF) $(DWGDEF) \
 		$(SDEDEF) $(BASEFORMATS) $(IDBDEF) $(NASDEF) $(DODSDEF) \
-		$(PCIDSKDEF) $(LIBKMLDEF) $(WFSDEF) $(SOSIDEF) $(GFTDEF) \
-		$(COUCHDBDEF) $(FGDBDEF) $(XLSDEF) $(ODSDEF) $(XLSXDEF) $(INGRESDEF) \
-		$(ELASTICDEF) $(OSMDEF) $(VFKDEF) $(CARTODBDEF) $(GMEDEF)
-
-!INCLUDE $(GDAL_ROOT)\nmake.opt
-
-!IF "$(PCIDSK_SETTING)" == "EXTERNAL"
-PCIDSKDEF	=	-DPCIDSK_ENABLED
-!ENDIF
-
-!IF "$(PCIDSK_SETTING)" == "INTERNAL"
-PCIDSKDEF	=	-DPCIDSK_ENABLED
-!ENDIF
+		$(LIBKMLDEF) $(WFSDEF) $(SOSIDEF) $(GFTDEF) \
+		$(COUCHDBDEF) $(CLOUDANTDEF) $(FGDBDEF) $(XLSDEF) $(ODSDEF) $(XLSXDEF) $(INGRESDEF) \
+		$(ELASTICDEF) $(OSMDEF) $(VFKDEF) $(CARTODBDEF) $(GMEDEF) $(PLSCENESDEF) $(CSWDEF)
 
 !IFDEF OGDIDIR
 OGDIDEF	=	-DOGDI_ENABLED
@@ -101,6 +96,7 @@ LIBKMLDEF = -DLIBKML_ENABLED
 
 !IFDEF CURL_LIB
 WFSDEF = -DWFS_ENABLED
+CSWDEF = -DCSW_ENABLED
 !ENDIF
 
 !IFDEF SOSI_ENABLED
@@ -115,6 +111,10 @@ GFTDEF = -DGFT_ENABLED
 COUCHDBDEF = -DCOUCHDB_ENABLED
 !ENDIF
 
+!IFDEF CURL_LIB
+CLOUDANTDEF = -DCLOUDANT_ENABLED
+!ENDIF
+
 !IFDEF FGDB_LIB
 !IF "$(FGDB_PLUGIN)" != "YES"
 FGDBDEF = -DFGDB_ENABLED
@@ -150,6 +150,16 @@ CARTODBDEF = -DCARTODB_ENABLED
 GMEDEF = -DGME_ENABLED
 !ENDIF
 
+!IFDEF CURL_LIB
+PLSCENESDEF = -DPLSCENES_ENABLED
+!ENDIF
+
+!ELSE
+
+EXTRAFLAGS =	-I.. -I..\..
+
+!ENDIF
+
 default:	$(OBJ)
 
 clean:
diff --git a/ogr/ogrsf_frmts/generic/ogr_gensql.cpp b/ogr/ogrsf_frmts/generic/ogr_gensql.cpp
index e8f3cf4..f0dc888 100644
--- a/ogr/ogrsf_frmts/generic/ogr_gensql.cpp
+++ b/ogr/ogrsf_frmts/generic/ogr_gensql.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gensql.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gensql.cpp 28927 2015-04-17 08:42:26Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGenSQLResultsLayer.
@@ -36,7 +36,7 @@
 #include "cpl_time.h"
 #include <vector>
 
-CPL_CVSID("$Id: ogr_gensql.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_gensql.cpp 28927 2015-04-17 08:42:26Z rouault $");
 
 
 class OGRGenSQLGeomFieldDefn: public OGRGeomFieldDefn
@@ -84,7 +84,7 @@ int OGRGenSQLResultsLayerHasSpecialField(swq_expr_node* expr,
 /*                       OGRGenSQLResultsLayer()                        */
 /************************************************************************/
 
-OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
+OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( GDALDataset *poSrcDS,
                                               void *pSelectInfo, 
                                               OGRGeometry *poSpatFilter,
                                               const char *pszWHERE,
@@ -116,14 +116,12 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
     for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
     {
         swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
-        OGRDataSource *poTableDS = poSrcDS;
+        GDALDataset *poTableDS = poSrcDS;
 
         if( psTableDef->data_source != NULL )
         {
-            OGRSFDriverRegistrar *poReg=OGRSFDriverRegistrar::GetRegistrar();
-
-            poTableDS = 
-                poReg->OpenShared( psTableDef->data_source, FALSE, NULL );
+            poTableDS = (GDALDataset*) GDALOpenEx( psTableDef->data_source,
+                            GDAL_OF_VECTOR | GDAL_OF_SHARED, NULL, NULL, NULL );
             if( poTableDS == NULL )
             {
                 if( strlen(CPLGetLastErrorMsg()) == 0 )
@@ -134,7 +132,7 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
                 return;
             }
 
-            papoExtraDS = (OGRDataSource **)
+            papoExtraDS = (GDALDataset **)
                 CPLRealloc( papoExtraDS, sizeof(void*) * ++nExtraDSCount );
 
             papoExtraDS[nExtraDSCount-1] = poTableDS;
@@ -152,7 +150,7 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
     poSrcLayer = papoTableLayers[0];
 
 /* -------------------------------------------------------------------- */
-/*      If the user has explicitely requested a OGRSQL dialect, then    */
+/*      If the user has explicitly requested a OGRSQL dialect, then    */
 /*      we should avoid to forward the where clause to the source layer */
 /*      when there is a risk it cannot understand it (#4022)            */
 /* -------------------------------------------------------------------- */
@@ -180,6 +178,7 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
     OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
 
     poDefn = new OGRFeatureDefn( psSelectInfo->table_defs[0].table_alias );
+    SetDescription( poDefn->GetName() );
     poDefn->SetGeomType(wkbNone);
     poDefn->Reference();
 
@@ -250,21 +249,37 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
         }
         else
         {
+            CPLString osName;
+            if( psColDef->table_name[0] )
+            {
+                osName = psColDef->table_name;
+                osName += ".";
+            }
+            osName += psColDef->field_name;
+
             if( bIsGeometry )
-                oGFDefn.SetName(psColDef->field_name);
+                oGFDefn.SetName(osName);
             else
-                oFDefn.SetName( psColDef->field_name );
+                oFDefn.SetName(osName);
         }
 
         if( psColDef->col_func == SWQCF_COUNT )
-            oFDefn.SetType( OFTInteger );
+            oFDefn.SetType( OFTInteger64 );
         else if( poSrcFDefn != NULL )
         {
             if( psColDef->col_func != SWQCF_AVG ||
                 psColDef->field_type == SWQ_DATE ||
                 psColDef->field_type == SWQ_TIME ||
                 psColDef->field_type == SWQ_TIMESTAMP )
+            {
                 oFDefn.SetType( poSrcFDefn->GetType() );
+                if( psColDef->col_func == SWQCF_NONE ||
+                    psColDef->col_func == SWQCF_MIN ||
+                    psColDef->col_func == SWQCF_MAX )
+                {
+                    oFDefn.SetSubType( poSrcFDefn->GetSubType() );
+                }
+            }
             else
                 oFDefn.SetType( OFTReal );
             if( psColDef->col_func != SWQCF_AVG &&
@@ -286,6 +301,9 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
               case SWQ_INTEGER:
                 oFDefn.SetType( OFTInteger );
                 break;
+              case SWQ_INTEGER64:
+                oFDefn.SetType( OFTInteger64 );
+                break;
               case SWQ_FLOAT:
                 oFDefn.SetType( OFTReal );
                 break;
@@ -299,10 +317,18 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
             switch( psColDef->field_type )
             {
               case SWQ_INTEGER:
+                oFDefn.SetType( OFTInteger );
+                break;
+
+              case SWQ_INTEGER64:
+                oFDefn.SetType( OFTInteger64 );
+                break;
+
               case SWQ_BOOLEAN:
                 oFDefn.SetType( OFTInteger );
+                oFDefn.SetSubType( OFSTBoolean );
                 break;
-                
+
               case SWQ_FLOAT:
                 oFDefn.SetType( OFTReal );
                 break;
@@ -319,8 +345,14 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
           case SWQ_OTHER:
             break;
           case SWQ_INTEGER:
+            oFDefn.SetType( OFTInteger );
+            break;
+          case SWQ_INTEGER64:
+            oFDefn.SetType( OFTInteger64 );
+            break;
           case SWQ_BOOLEAN:
             oFDefn.SetType( OFTInteger );
+            oFDefn.SetSubType( OFSTBoolean );
             break;
           case SWQ_FLOAT:
             oFDefn.SetType( OFTReal );
@@ -345,6 +377,8 @@ OGRGenSQLResultsLayer::OGRGenSQLResultsLayer( OGRDataSource *poSrcDS,
             oFDefn.SetType( OFTString );
             break;
         }
+        if( psColDef->target_subtype != OFSTNone )
+            oFDefn.SetSubType( psColDef->target_subtype );
 
         if (psColDef->field_length > 0)
         {
@@ -483,10 +517,8 @@ OGRGenSQLResultsLayer::~OGRGenSQLResultsLayer()
 /* -------------------------------------------------------------------- */
 /*      Release any additional datasources being used in joins.         */
 /* -------------------------------------------------------------------- */
-    OGRSFDriverRegistrar *poReg=OGRSFDriverRegistrar::GetRegistrar();
-
     for( int iEDS = 0; iEDS < nExtraDSCount; iEDS++ )
-        poReg->ReleaseDataSource( papoExtraDS[iEDS] );
+        GDALClose( (GDALDatasetH)papoExtraDS[iEDS] );
 
     CPLFree( papoExtraDS );
     CPLFree( pszWHERE );
@@ -603,7 +635,7 @@ void OGRGenSQLResultsLayer::ResetReading()
 /*      ourselves in it.                                                */
 /************************************************************************/
 
-OGRErr OGRGenSQLResultsLayer::SetNextByIndex( long nIndex )
+OGRErr OGRGenSQLResultsLayer::SetNextByIndex( GIntBig nIndex )
 
 {
     swq_select *psSelectInfo = (swq_select *) pSelectInfo;
@@ -663,7 +695,7 @@ OGRErr OGRGenSQLResultsLayer::GetExtent( int iGeomField,
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRGenSQLResultsLayer::GetFeatureCount( int bForce )
+GIntBig OGRGenSQLResultsLayer::GetFeatureCount( int bForce )
 
 {
     swq_select *psSelectInfo = (swq_select *) pSelectInfo;
@@ -822,14 +854,25 @@ int OGRGenSQLResultsLayer::PrepareSummary()
 
 /* -------------------------------------------------------------------- */
 /*      We treat COUNT(*) as a special case, and fill with              */
-/*      GetFeatureCount().                                              */
+/*      GetFeatureCount().                                            */
 /* -------------------------------------------------------------------- */
 
     if( psSelectInfo->result_columns == 1 
         && psSelectInfo->column_defs[0].col_func == SWQCF_COUNT
         && psSelectInfo->column_defs[0].field_index < 0 )
     {
-        poSummaryFeature->SetField( 0, poSrcLayer->GetFeatureCount( TRUE ) );
+        GIntBig nRes = poSrcLayer->GetFeatureCount( TRUE );
+        poSummaryFeature->SetField( 0, nRes );
+
+        if( (GIntBig)(int)nRes == nRes )
+        {
+            poDefn->GetFieldDefn(0)->SetType(OFTInteger);
+            delete poSummaryFeature;
+            poSummaryFeature = new OGRFeature( poDefn );
+            poSummaryFeature->SetFID( 0 );
+            poSummaryFeature->SetField( 0, (int)nRes );
+        }
+
         poSrcLayer->GetLayerDefn()->SetGeometryIgnored(bSaveIsGeomIgnored);
         return TRUE;
     }
@@ -926,6 +969,30 @@ int OGRGenSQLResultsLayer::PrepareSummary()
             if (psSelectInfo->column_summary != NULL)
             {
                 swq_summary *psSummary = psSelectInfo->column_summary + iField;
+                if( psColDef->col_func == SWQCF_COUNT )
+                {
+                    if( (GIntBig)(int)psSummary->count == psSummary->count ) 
+                    {
+                        delete poSummaryFeature;
+                        poSummaryFeature = NULL;
+                        poDefn->GetFieldDefn(iField)->SetType(OFTInteger);
+                    }
+                }
+            }
+        }
+
+        if( poSummaryFeature == NULL )
+        {
+            poSummaryFeature = new OGRFeature( poDefn );
+            poSummaryFeature->SetFID( 0 );
+        }
+
+        for( iField = 0; iField < psSelectInfo->result_columns; iField++ )
+        {
+            swq_col_def *psColDef = psSelectInfo->column_defs + iField;
+            if (psSelectInfo->column_summary != NULL)
+            {
+                swq_summary *psSummary = psSelectInfo->column_summary + iField;
 
                 if( psColDef->col_func == SWQCF_AVG )
                 {
@@ -934,14 +1001,15 @@ int OGRGenSQLResultsLayer::PrepareSummary()
                         psColDef->field_type == SWQ_TIMESTAMP)
                     {
                         struct tm brokendowntime;
-                        CPLUnixTimeToYMDHMS((GIntBig)(psSummary->sum / psSummary->count), &brokendowntime);
+                        double dfAvg = psSummary->sum / psSummary->count;
+                        CPLUnixTimeToYMDHMS((GIntBig)dfAvg, &brokendowntime);
                         poSummaryFeature->SetField( iField,
                                                     brokendowntime.tm_year + 1900,
                                                     brokendowntime.tm_mon + 1,
                                                     brokendowntime.tm_mday,
                                                     brokendowntime.tm_hour,
                                                     brokendowntime.tm_min,
-                                                    brokendowntime.tm_sec, 0);
+                                                    brokendowntime.tm_sec + fmod(dfAvg, 1), 0);
                     }
                     else
                         poSummaryFeature->SetField( iField,
@@ -1024,6 +1092,18 @@ static swq_expr_node *OGRMultiFeatureFetcher( swq_expr_node *op,
                 poFeature->GetFieldAsInteger(op->field_index) );
         break;
 
+      case SWQ_INTEGER64:
+        if( poFeature == NULL 
+            || !poFeature->IsFieldSet(op->field_index) )
+        {
+            poRetNode = new swq_expr_node((GIntBig)0);
+            poRetNode->is_null = TRUE;
+        }
+        else
+            poRetNode = new swq_expr_node( 
+                poFeature->GetFieldAsInteger64(op->field_index) );
+        break;
+
       case SWQ_FLOAT:
         if( poFeature == NULL 
             || !poFeature->IsFieldSet(op->field_index) )
@@ -1067,6 +1147,117 @@ static swq_expr_node *OGRMultiFeatureFetcher( swq_expr_node *op,
 }
 
 /************************************************************************/
+/*                          GetFilterForJoin()                          */
+/************************************************************************/
+
+static CPLString GetFilterForJoin(swq_expr_node* poExpr, OGRFeature* poSrcFeat,
+                                  OGRLayer* poJoinLayer, int secondary_table)
+{
+    if( poExpr->eNodeType == SNT_CONSTANT )
+    {
+        char* pszRes = poExpr->Unparse(NULL, '"');
+        CPLString osRes = pszRes;
+        CPLFree(pszRes);
+        return osRes;
+    }
+
+    if( poExpr->eNodeType == SNT_COLUMN )
+    {
+        CPLAssert( poExpr->field_index != -1 );
+        CPLAssert( poExpr->table_index == 0 || poExpr->table_index == secondary_table );
+
+        if( poExpr->table_index == 0 )
+        {
+            // if source key is null, we can't do join.
+            if( !poSrcFeat->IsFieldSet( poExpr->field_index ) )
+            {
+                return "";
+            }
+            OGRFieldType ePrimaryFieldType =
+                    poSrcFeat->GetFieldDefnRef(poExpr->field_index)->GetType();
+            OGRField *psSrcField = 
+                    poSrcFeat->GetRawFieldRef(poExpr->field_index);
+
+            switch( ePrimaryFieldType )
+            {
+            case OFTInteger:
+                return CPLString().Printf("%d", psSrcField->Integer );
+                break;
+
+            case OFTInteger64:
+                return CPLString().Printf(CPL_FRMT_GIB, psSrcField->Integer64 );
+                break;
+
+            case OFTReal:
+                return CPLString().Printf("%.16g", psSrcField->Real );
+                break;
+
+            case OFTString:
+            {
+                char *pszEscaped = CPLEscapeString( psSrcField->String, 
+                                                    strlen(psSrcField->String),
+                                                    CPLES_SQL );
+                CPLString osRes = "'";
+                osRes += pszEscaped;
+                osRes += "'";
+                CPLFree( pszEscaped );
+                return osRes;
+            }
+            break;
+
+            default:
+                CPLAssert( FALSE );
+                return "";
+            }
+        }
+        
+        if(  poExpr->table_index == secondary_table )
+        {
+            OGRFieldDefn* poSecondaryFieldDefn =
+                poJoinLayer->GetLayerDefn()->GetFieldDefn(poExpr->field_index);
+            return CPLSPrintf("\"%s\"", poSecondaryFieldDefn->GetNameRef());
+        }
+
+        CPLAssert(FALSE);
+        return "";
+    }
+
+    if( poExpr->eNodeType == SNT_OPERATION )
+    {
+        /* -------------------------------------------------------------------- */
+        /*      Operation - start by unparsing all the subexpressions.          */
+        /* -------------------------------------------------------------------- */
+        std::vector<char*> apszSubExpr;
+        int i;
+
+        for( i = 0; i < poExpr->nSubExprCount; i++ )
+        {
+            CPLString osSubExpr = GetFilterForJoin(poExpr->papoSubExpr[i], poSrcFeat,
+                                                   poJoinLayer, secondary_table);
+            if( osSubExpr.size() == 0 )
+            {
+                for( --i; i >=0; i-- )
+                    CPLFree( apszSubExpr[i] );
+                return "";
+            }
+            apszSubExpr.push_back( CPLStrdup(osSubExpr) );
+        }
+
+        CPLString osExpr = poExpr->UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
+
+        /* -------------------------------------------------------------------- */
+        /*      cleanup subexpressions.                                         */
+        /* -------------------------------------------------------------------- */
+        for( i = 0; i < poExpr->nSubExprCount; i++ )
+            CPLFree( apszSubExpr[i] );
+
+        return osExpr;
+    }
+
+    return "";
+}
+
+/************************************************************************/
 /*                          TranslateFeature()                          */
 /************************************************************************/
 
@@ -1102,62 +1293,16 @@ OGRFeature *OGRGenSQLResultsLayer::TranslateFeature( OGRFeature *poSrcFeat )
 
         OGRLayer *poJoinLayer = papoTableLayers[psJoinInfo->secondary_table];
         
+        osFilter = GetFilterForJoin(psJoinInfo->poExpr, poSrcFeat, poJoinLayer, 
+                                    psJoinInfo->secondary_table);
+        //CPLDebug("OGR", "Filter = %s\n", osFilter.c_str());
+
         // if source key is null, we can't do join.
-        if( !poSrcFeat->IsFieldSet( psJoinInfo->primary_field ) )
+        if( osFilter.size() == 0 )
         {
             apoFeatures.push_back( NULL );
             continue;
         }
-        
-        OGRFieldDefn* poSecondaryFieldDefn =
-            poJoinLayer->GetLayerDefn()->GetFieldDefn( 
-                     psJoinInfo->secondary_field );
-        OGRFieldType ePrimaryFieldType = poSrcLayer->GetLayerDefn()->
-                    GetFieldDefn(psJoinInfo->primary_field )->GetType();
-        OGRFieldType eSecondaryFieldType = poSecondaryFieldDefn->GetType();
-
-        // Prepare attribute query to express fetching on the joined variable
-        
-        // If joining a (primary) numeric column with a (secondary) string column
-        // then add implicit casting of the secondary column to numeric. This behaviour
-        // worked in GDAL < 1.8, and it is consistant with how sqlite behaves too. See #4321
-        // For the reverse case, joining a string column with a numeric column, the
-        // string constant will be cast to float by SWQAutoConvertStringToNumeric (#4259)
-        if( eSecondaryFieldType == OFTString &&
-            (ePrimaryFieldType == OFTInteger || ePrimaryFieldType == OFTReal) )
-            osFilter.Printf("CAST(%s AS FLOAT) = ", poSecondaryFieldDefn->GetNameRef() );
-        else
-            osFilter.Printf("%s = ", poSecondaryFieldDefn->GetNameRef() );
-
-        OGRField *psSrcField = 
-            poSrcFeat->GetRawFieldRef(psJoinInfo->primary_field);
-
-        switch( ePrimaryFieldType )
-        {
-          case OFTInteger:
-            osFilter += CPLString().Printf("%d", psSrcField->Integer );
-            break;
-
-          case OFTReal:
-            osFilter += CPLString().Printf("%.16g", psSrcField->Real );
-            break;
-
-          case OFTString:
-          {
-              char *pszEscaped = CPLEscapeString( psSrcField->String, 
-                                                  strlen(psSrcField->String),
-                                                  CPLES_SQL );
-              osFilter += "'";
-              osFilter += pszEscaped;
-              osFilter += "'";
-              CPLFree( pszEscaped );
-          }
-          break;
-
-          default:
-            CPLAssert( FALSE );
-            continue;
-        }
 
         OGRFeature *poJoinFeature = NULL;
 
@@ -1218,7 +1363,12 @@ OGRFeature *OGRGenSQLResultsLayer::TranslateFeature( OGRFeature *poSrcFeat )
 
         switch( poResult->field_type )
         {
+          case SWQ_BOOLEAN:
           case SWQ_INTEGER:
+            poDstFeat->SetField( iRegularField++, (int)poResult->int_value );
+            break;
+
+          case SWQ_INTEGER64:
             poDstFeat->SetField( iRegularField++, poResult->int_value );
             break;
             
@@ -1306,6 +1456,9 @@ OGRFeature *OGRGenSQLResultsLayer::TranslateFeature( OGRFeature *poSrcFeat )
               case SWQ_INTEGER:
                 poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsInteger(psColDef->field_index) );
                 break;
+              case SWQ_INTEGER64:
+                poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsInteger64(psColDef->field_index) );
+                break;
               case SWQ_FLOAT:
                 poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsDouble(psColDef->field_index) );
                 break;
@@ -1322,6 +1475,10 @@ OGRFeature *OGRGenSQLResultsLayer::TranslateFeature( OGRFeature *poSrcFeat )
                 poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsInteger(psColDef->field_index) );
                 break;
 
+              case SWQ_INTEGER64:
+                poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsInteger64(psColDef->field_index) );
+                break;
+
               case SWQ_FLOAT:
                 poDstFeat->SetField( iRegularField, poSrcFeat->GetFieldAsDouble(psColDef->field_index) );
                 break;
@@ -1441,7 +1598,7 @@ OGRFeature *OGRGenSQLResultsLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRGenSQLResultsLayer::GetFeature( long nFID )
+OGRFeature *OGRGenSQLResultsLayer::GetFeature( GIntBig nFID )
 
 {
     swq_select *psSelectInfo = (swq_select *) pSelectInfo;
@@ -1530,6 +1687,23 @@ OGRGeometry *OGRGenSQLResultsLayer::GetSpatialFilter()
 OGRFeatureDefn *OGRGenSQLResultsLayer::GetLayerDefn()
 
 {
+    swq_select *psSelectInfo = (swq_select *) pSelectInfo;
+    if( psSelectInfo->query_mode == SWQM_SUMMARY_RECORD &&
+        poSummaryFeature == NULL )
+    {
+        // Run PrepareSummary() is we have a COUNT column so as to be
+        // able to downcast it from OFTInteger64 to OFTInteger
+        for( int iField = 0; iField < psSelectInfo->result_columns; iField++ )
+        {
+            swq_col_def *psColDef = psSelectInfo->column_defs + iField;
+            if( psColDef->col_func == SWQCF_COUNT )
+            {
+                PrepareSummary();
+                break;
+            }
+        }
+    }
+
     return poDefn;
 }
 
@@ -1555,8 +1729,9 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
 {
     swq_select *psSelectInfo = (swq_select *) pSelectInfo;
     OGRField *pasIndexFields;
-    int      i, nOrderItems = psSelectInfo->order_specs;
-    long     *panFIDList;
+    GIntBig      i;
+    int nOrderItems = psSelectInfo->order_specs;
+    GIntBig *panFIDList;
 
     if( ! (psSelectInfo->order_specs > 0
            && psSelectInfo->query_mode == SWQM_RECORDSET
@@ -1573,12 +1748,12 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
 /* -------------------------------------------------------------------- */
 /*      Allocate set of key values, and the output index.               */
 /* -------------------------------------------------------------------- */
-    int nFeaturesAlloc = 100;
+    size_t nFeaturesAlloc = 100;
 
     panFIDIndex = NULL;
     pasIndexFields = (OGRField *) 
         CPLCalloc(sizeof(OGRField), nOrderItems * nFeaturesAlloc);
-    panFIDList = (long *) CPLMalloc(sizeof(long) * nFeaturesAlloc);
+    panFIDList = (GIntBig *) CPLMalloc(sizeof(GIntBig) * nFeaturesAlloc);
 
 /* -------------------------------------------------------------------- */
 /*      Read in all the key values.                                     */
@@ -1590,14 +1765,24 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
     {
         int iKey;
 
-        if (nIndexSize == nFeaturesAlloc)
+        if ((size_t)nIndexSize == nFeaturesAlloc)
         {
-            int nNewFeaturesAlloc = (nFeaturesAlloc * 4) / 3;
+            GIntBig nNewFeaturesAlloc = (nFeaturesAlloc * 4) / 3;
+            if( (GIntBig)(size_t)(sizeof(OGRField) * nOrderItems * nNewFeaturesAlloc) !=
+                    (GIntBig)sizeof(OGRField) * nOrderItems * nNewFeaturesAlloc )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate pasIndexFields");
+                VSIFree(pasIndexFields);
+                VSIFree(panFIDList);
+                nIndexSize = 0;
+                return;
+            }
             OGRField* pasNewIndexFields = (OGRField *)
                 VSIRealloc(pasIndexFields,
-                           sizeof(OGRField) * nOrderItems * nNewFeaturesAlloc);
+                           sizeof(OGRField) * nOrderItems * (size_t)nNewFeaturesAlloc);
             if (pasNewIndexFields == NULL)
             {
+                CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate pasIndexFields");
                 VSIFree(pasIndexFields);
                 VSIFree(panFIDList);
                 nIndexSize = 0;
@@ -1605,8 +1790,8 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
             }
             pasIndexFields = pasNewIndexFields;
 
-            long* panNewFIDList = (long *)
-                VSIRealloc(panFIDList, sizeof(long) *  nNewFeaturesAlloc);
+            GIntBig* panNewFIDList = (GIntBig *)
+                VSIRealloc(panFIDList, sizeof(GIntBig) *  (size_t)nNewFeaturesAlloc);
             if (panNewFIDList == NULL)
             {
                 VSIFree(pasIndexFields);
@@ -1617,9 +1802,9 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
             panFIDList = panNewFIDList;
 
             memset(pasIndexFields + nFeaturesAlloc, 0,
-                   sizeof(OGRField) * nOrderItems * (nNewFeaturesAlloc - nFeaturesAlloc));
+                   sizeof(OGRField) * nOrderItems * (size_t)(nNewFeaturesAlloc - nFeaturesAlloc));
 
-            nFeaturesAlloc = nNewFeaturesAlloc;
+            nFeaturesAlloc = (size_t)nNewFeaturesAlloc;
         }
 
         for( iKey = 0; iKey < nOrderItems; iKey++ )
@@ -1640,6 +1825,10 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
                         psDstField->Integer = poSrcFeat->GetFieldAsInteger(psKeyDef->field_index);
                         break;
 
+                      case SWQ_INTEGER64:
+                        psDstField->Integer64 = poSrcFeat->GetFieldAsInteger64(psKeyDef->field_index);
+                        break;
+
                       case SWQ_FLOAT:
                         psDstField->Real = poSrcFeat->GetFieldAsDouble(psKeyDef->field_index);
                         break;
@@ -1658,6 +1847,7 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
             psSrcField = poSrcFeat->GetRawFieldRef( psKeyDef->field_index );
 
             if( poFDefn->GetType() == OFTInteger 
+                || poFDefn->GetType() == OFTInteger64 
                 || poFDefn->GetType() == OFTReal
                 || poFDefn->GetType() == OFTDate
                 || poFDefn->GetType() == OFTTime
@@ -1683,14 +1873,30 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
 /* -------------------------------------------------------------------- */
 /*      Initialize panFIDIndex                                          */
 /* -------------------------------------------------------------------- */
-    panFIDIndex = (long *) CPLMalloc(sizeof(long) * nIndexSize);
+    panFIDIndex = (GIntBig *) VSIMalloc(sizeof(GIntBig) * (size_t)nIndexSize);
+    if( panFIDIndex == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate panFIDIndex");
+        VSIFree(pasIndexFields);
+        VSIFree(panFIDList);
+        nIndexSize = 0;
+        return;
+    }
     for( i = 0; i < nIndexSize; i++ )
         panFIDIndex[i] = i;
 
 /* -------------------------------------------------------------------- */
 /*      Quick sort the records.                                         */
 /* -------------------------------------------------------------------- */
-    SortIndexSection( pasIndexFields, 0, nIndexSize );
+    if( !SortIndexSection( pasIndexFields, 0, nIndexSize ) )
+    {
+        VSIFree(pasIndexFields);
+        VSIFree(panFIDList);
+        nIndexSize = 0;
+        VSIFree(panFIDIndex);
+        panFIDIndex = NULL;
+        return;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Rework the FID map to map to real FIDs.                         */
@@ -1748,7 +1954,7 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
 
     /* If it is already sorted, then free than panFIDIndex array */
     /* so that GetNextFeature() can call a sequential GetNextFeature() */
-    /* on the source array. Very usefull for layers where random access */
+    /* on the source array. Very useful for layers where random access */
     /* is slow. */
     /* Use case: the GML result of a WFS GetFeature with a SORTBY */
     if (bAlreadySorted)
@@ -1768,27 +1974,33 @@ void OGRGenSQLResultsLayer::CreateOrderByIndex()
 /*      Sort the records in a section of the index.                     */
 /************************************************************************/
 
-void OGRGenSQLResultsLayer::SortIndexSection( OGRField *pasIndexFields, 
-                                              int nStart, int nEntries )
+int OGRGenSQLResultsLayer::SortIndexSection( OGRField *pasIndexFields, 
+                                              GIntBig nStart, GIntBig nEntries )
 
 {
     if( nEntries < 2 )
-        return;
+        return TRUE;
 
     swq_select *psSelectInfo = (swq_select *) pSelectInfo;
     int      nOrderItems = psSelectInfo->order_specs;
 
-    int nFirstGroup = nEntries / 2;
-    int nFirstStart = nStart;
-    int nSecondGroup = nEntries - nFirstGroup;
-    int nSecondStart = nStart + nFirstGroup;
-    int iMerge = 0;
-    long *panMerged;
+    GIntBig nFirstGroup = nEntries / 2;
+    GIntBig nFirstStart = nStart;
+    GIntBig nSecondGroup = nEntries - nFirstGroup;
+    GIntBig nSecondStart = nStart + nFirstGroup;
+    GIntBig iMerge = 0;
+    GIntBig *panMerged;
 
-    SortIndexSection( pasIndexFields, nFirstStart, nFirstGroup );
-    SortIndexSection( pasIndexFields, nSecondStart, nSecondGroup );
+    if( !SortIndexSection( pasIndexFields, nFirstStart, nFirstGroup ) ||
+        !SortIndexSection( pasIndexFields, nSecondStart, nSecondGroup ) )
+        return FALSE;
 
-    panMerged = (long *) CPLMalloc( sizeof(long) * nEntries );
+    panMerged = (GIntBig *) VSIMalloc( sizeof(GIntBig) * (size_t)nEntries );
+    if( panMerged == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocated panMerged");
+        return FALSE;
+    }
         
     while( iMerge < nEntries )
     {
@@ -1818,8 +2030,10 @@ void OGRGenSQLResultsLayer::SortIndexSection( OGRField *pasIndexFields,
 
     /* Copy the merge list back into the main index */
 
-    memcpy( panFIDIndex + nStart, panMerged, sizeof(long) * nEntries );
+    memcpy( panFIDIndex + nStart, panMerged, sizeof(GIntBig) * (size_t)nEntries );
     CPLFree( panMerged );
+    
+    return TRUE;
 }
 
 /************************************************************************/
@@ -1864,6 +2078,12 @@ int OGRGenSQLResultsLayer::Compare( OGRField *pasFirstTuple,
                 else if( pasFirstTuple[iKey].Integer > pasSecondTuple[iKey].Integer )
                     nResult = 1;
                 break;
+              case SWQ_INTEGER64:
+                if( pasFirstTuple[iKey].Integer64 < pasSecondTuple[iKey].Integer64 )
+                    nResult = -1;
+                else if( pasFirstTuple[iKey].Integer64 > pasSecondTuple[iKey].Integer64 )
+                    nResult = 1;
+                break;
               case SWQ_FLOAT:
                 if( pasFirstTuple[iKey].Real < pasSecondTuple[iKey].Real )
                     nResult = -1;
@@ -1888,6 +2108,14 @@ int OGRGenSQLResultsLayer::Compare( OGRField *pasFirstTuple,
                      > pasSecondTuple[iKey].Integer )
                 nResult = 1;
         }
+        else if( poFDefn->GetType() == OFTInteger64 )
+        {
+            if( pasFirstTuple[iKey].Integer64 < pasSecondTuple[iKey].Integer64 )
+                nResult = -1;
+            else if( pasFirstTuple[iKey].Integer64 
+                     > pasSecondTuple[iKey].Integer64 )
+                nResult = 1;
+        }
         else if( poFDefn->GetType() == OFTString )
             nResult = strcmp(pasFirstTuple[iKey].String,
                              pasSecondTuple[iKey].String);
@@ -1980,8 +2208,7 @@ void OGRGenSQLResultsLayer::FindAndSetIgnoredFields()
     for( int iJoin = 0; iJoin < psSelectInfo->join_count; iJoin++ )
     {
         swq_join_def *psJoinDef = psSelectInfo->join_defs + iJoin;
-        AddFieldDefnToSet(0, psJoinDef->primary_field, hSet);
-        AddFieldDefnToSet(psJoinDef->secondary_table, psJoinDef->secondary_field, hSet);
+        ExploreExprForIgnoredFields(psJoinDef->poExpr, hSet);
     }
 
     for( int iOrder = 0; iOrder < psSelectInfo->order_specs; iOrder++ )
diff --git a/ogr/ogrsf_frmts/generic/ogr_gensql.h b/ogr/ogrsf_frmts/generic/ogr_gensql.h
index ca64375..fe5fe64 100644
--- a/ogr/ogrsf_frmts/generic/ogr_gensql.h
+++ b/ogr/ogrsf_frmts/generic/ogr_gensql.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gensql.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gensql.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Classes related to generic implementation of ExecuteSQL().
@@ -52,7 +52,7 @@
 class CPL_DLL OGRGenSQLResultsLayer : public OGRLayer
 {
   private:
-    OGRDataSource *poSrcDS;
+    GDALDataset *poSrcDS;
     OGRLayer    *poSrcLayer;
     void        *pSelectInfo;
 
@@ -66,22 +66,22 @@ class CPL_DLL OGRGenSQLResultsLayer : public OGRLayer
     
     int        *panGeomFieldToSrcGeomField;
 
-    int         nIndexSize;
-    long       *panFIDIndex;
+    GIntBig     nIndexSize;
+    GIntBig    *panFIDIndex;
     int         bOrderByValid;
 
-    int         nNextIndexFID;
+    GIntBig      nNextIndexFID;
     OGRFeature  *poSummaryFeature;
 
     int         iFIDFieldIndex;
 
     int         nExtraDSCount;
-    OGRDataSource **papoExtraDS;
+    GDALDataset **papoExtraDS;
 
     OGRFeature *TranslateFeature( OGRFeature * );
     void        CreateOrderByIndex();
-    void        SortIndexSection( OGRField *pasIndexFields, 
-                                  int nStart, int nEntries );
+    int         SortIndexSection( OGRField *pasIndexFields, 
+                                  GIntBig nStart, GIntBig nEntries );
     int         Compare( OGRField *pasFirst, OGRField *pasSecond );
 
     void        ClearFilters();
@@ -98,7 +98,7 @@ class CPL_DLL OGRGenSQLResultsLayer : public OGRLayer
     int         MustEvaluateSpatialFilterOnGenSQL();
 
   public:
-                OGRGenSQLResultsLayer( OGRDataSource *poSrcDS, 
+                OGRGenSQLResultsLayer( GDALDataset *poSrcDS, 
                                        void *pSelectInfo,
                                        OGRGeometry *poSpatFilter,
                                        const char *pszWHERE,
@@ -109,12 +109,12 @@ class CPL_DLL OGRGenSQLResultsLayer : public OGRLayer
 
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
-    virtual OGRFeature *GetFeature( long nFID );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
 
     virtual OGRFeatureDefn *GetLayerDefn();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE) { return GetExtent(0, psExtent, bForce); }
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
 
diff --git a/ogr/ogrsf_frmts/generic/ogr_miattrind.cpp b/ogr/ogrsf_frmts/generic/ogr_miattrind.cpp
index f59fcfc..40bdaf2 100644
--- a/ogr/ogrsf_frmts/generic/ogr_miattrind.cpp
+++ b/ogr/ogrsf_frmts/generic/ogr_miattrind.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_miattrind.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_miattrind.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements interface to MapInfo .ID files used as attribute
@@ -33,7 +33,7 @@
 #include "mitab/mitab_priv.h"
 #include "cpl_minixml.h"
 
-CPL_CVSID("$Id: ogr_miattrind.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogr_miattrind.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRMIAttrIndex                            */
@@ -58,12 +58,12 @@ public:
                ~OGRMIAttrIndex();
 
     GByte      *BuildKey( OGRField *psKey );
-    long        GetFirstMatch( OGRField *psKey );
-    long       *GetAllMatches( OGRField *psKey );
-    long       *GetAllMatches( OGRField *psKey, long* panFIDList, int* nFIDCount, int* nLength );
+    GIntBig     GetFirstMatch( OGRField *psKey );
+    GIntBig    *GetAllMatches( OGRField *psKey );
+    GIntBig    *GetAllMatches( OGRField *psKey, GIntBig* panFIDList, int* nFIDCount, int* nLength );
 
-    OGRErr      AddEntry( OGRField *psKey, long nFID );
-    OGRErr      RemoveEntry( OGRField *psKey, long nFID );
+    OGRErr      AddEntry( OGRField *psKey, GIntBig nFID );
+    OGRErr      RemoveEntry( OGRField *psKey, GIntBig nFID );
 
     OGRErr      Clear();
 };
@@ -268,7 +268,8 @@ OGRErr OGRMILayerAttrIndex::LoadConfigFromXML(const char* pszRawXML)
 
     CPLDebug( "OGR", "Restored %d field indexes for layer %s from %s on %s.",
               nIndexCount, poLayer->GetLayerDefn()->GetName(), 
-              pszMetadataFilename, pszMIINDFilename );
+              pszMetadataFilename ? pszMetadataFilename : "--unknown--",
+              pszMIINDFilename );
 
     return OGRERR_NONE;
 }
@@ -702,7 +703,7 @@ OGRMIAttrIndex::~OGRMIAttrIndex()
 /*                              AddEntry()                              */
 /************************************************************************/
 
-OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, long nFID )
+OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, GIntBig nFID )
 
 {
     GByte *pabyKey = BuildKey( psKey );
@@ -710,7 +711,10 @@ OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, long nFID )
     if( psKey == NULL )
         return OGRERR_FAILURE;
 
-    if( poINDFile->AddEntry( iIndex, pabyKey, nFID+1 ) != 0 )
+    if( nFID >= INT_MAX )
+        return OGRERR_FAILURE;
+
+    if( poINDFile->AddEntry( iIndex, pabyKey, (int)nFID+1 ) != 0 )
         return OGRERR_FAILURE;
     else
         return OGRERR_NONE;
@@ -720,7 +724,7 @@ OGRErr OGRMIAttrIndex::AddEntry( OGRField *psKey, long nFID )
 /*                            RemoveEntry()                             */
 /************************************************************************/
 
-OGRErr OGRMIAttrIndex::RemoveEntry( OGRField * /*psKey*/, long /*nFID*/ )
+OGRErr OGRMIAttrIndex::RemoveEntry( OGRField * /*psKey*/, GIntBig /*nFID*/ )
 
 {
     return OGRERR_UNSUPPORTED_OPERATION;
@@ -739,6 +743,17 @@ GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey )
         return poINDFile->BuildKey( iIndex, psKey->Integer );
         break;
 
+      case OFTInteger64:
+      {
+        if( (GIntBig)(int)psKey->Integer64 != psKey->Integer64 )
+        {
+            CPLError(CE_Warning, CPLE_NotSupported,
+                     "64bit integer value passed to OGRMIAttrIndex::BuildKey()");
+        }
+        return poINDFile->BuildKey( iIndex, (int)psKey->Integer64 );
+        break;
+      }
+
       case OFTReal:
         return poINDFile->BuildKey( iIndex, psKey->Real );
         break;
@@ -758,11 +773,11 @@ GByte *OGRMIAttrIndex::BuildKey( OGRField *psKey )
 /*                           GetFirstMatch()                            */
 /************************************************************************/
 
-long OGRMIAttrIndex::GetFirstMatch( OGRField *psKey )
+GIntBig OGRMIAttrIndex::GetFirstMatch( OGRField *psKey )
 
 {
     GByte *pabyKey = BuildKey( psKey );
-    long nFID;
+    GIntBig nFID;
 
     nFID = poINDFile->FindFirst( iIndex, pabyKey );
     if( nFID < 1 )
@@ -775,14 +790,14 @@ long OGRMIAttrIndex::GetFirstMatch( OGRField *psKey )
 /*                           GetAllMatches()                            */
 /************************************************************************/
 
-long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey, long* panFIDList, int* nFIDCount, int* nLength )
+GIntBig *OGRMIAttrIndex::GetAllMatches( OGRField *psKey, GIntBig* panFIDList, int* nFIDCount, int* nLength )
 {
     GByte *pabyKey = BuildKey( psKey );
-    long nFID;
+    GIntBig nFID;
 
     if (panFIDList == NULL)
     {
-        panFIDList = (long *) CPLMalloc(sizeof(long) * 2);
+        panFIDList = (GIntBig *) CPLMalloc(sizeof(GIntBig) * 2);
         *nFIDCount = 0;
         *nLength = 2;
     }
@@ -793,7 +808,7 @@ long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey, long* panFIDList, int* nFI
         if( *nFIDCount >= *nLength-1 )
         {
             *nLength = (*nLength) * 2 + 10;
-            panFIDList = (long *) CPLRealloc(panFIDList, sizeof(long)* (*nLength));
+            panFIDList = (GIntBig *) CPLRealloc(panFIDList, sizeof(GIntBig)* (*nLength));
         }
         panFIDList[(*nFIDCount)++] = nFID - 1;
         
@@ -805,7 +820,7 @@ long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey, long* panFIDList, int* nFI
     return panFIDList;
 }
 
-long *OGRMIAttrIndex::GetAllMatches( OGRField *psKey )
+GIntBig *OGRMIAttrIndex::GetAllMatches( OGRField *psKey )
 {
     int nFIDCount, nLength;
     return GetAllMatches( psKey, NULL, &nFIDCount, &nLength );
diff --git a/ogr/ogrsf_frmts/generic/ogrdatasource.cpp b/ogr/ogrsf_frmts/generic/ogrdatasource.cpp
index 31b9a68..0204b12 100644
--- a/ogr/ogrsf_frmts/generic/ogrdatasource.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrdatasource.cpp
@@ -1,8 +1,8 @@
 /******************************************************************************
- * $Id: ogrdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrdatasource.cpp 28806 2015-03-28 14:37:47Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
- * Purpose:  The generic portions of the OGRDataSource class.
+ * Purpose:  The generic portions of the GDALDataset class.
  * Author:   Frank Warmerdam, warmerdam at pobox.com
  *
  ******************************************************************************
@@ -28,20 +28,11 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-#include "swq.h"
 #include "ogrsf_frmts.h"
 #include "ogr_api.h"
-#include "ogr_p.h"
-#include "ogr_gensql.h"
-#include "ogr_attrind.h"
-#include "cpl_multiproc.h"
-#include "ogrunionlayer.h"
-
-#ifdef SQLITE_ENABLED
-#include "../sqlite/ogrsqliteexecutesql.h"
-#endif
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrdatasource.cpp 28806 2015-03-28 14:37:47Z rouault $");
 
 /************************************************************************/
 /*                           ~OGRDataSource()                           */
@@ -50,27 +41,6 @@ CPL_CVSID("$Id: ogrdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
 OGRDataSource::OGRDataSource()
 
 {
-    m_poStyleTable = NULL;
-    m_nRefCount = 0;
-    m_poDriver = NULL;
-    m_hMutex = NULL;
-}
-
-/************************************************************************/
-/*                           ~OGRDataSource()                           */
-/************************************************************************/
-
-OGRDataSource::~OGRDataSource()
-
-{
-    if ( m_poStyleTable )
-    {
-        delete m_poStyleTable;
-        m_poStyleTable = NULL;
-    }
-
-    if( m_hMutex != NULL )
-        CPLDestroyMutex( m_hMutex );
 }
 
 /************************************************************************/
@@ -90,28 +60,18 @@ void OGRDataSource::DestroyDataSource( OGRDataSource *poDS )
 void OGR_DS_Destroy( OGRDataSourceH hDS )
 
 {
-    VALIDATE_POINTER0( hDS, "OGR_DS_Destroy" );
-    delete (OGRDataSource *) hDS;
-}
-
-/************************************************************************/
-/*                              Release()                               */
-/************************************************************************/
-
-OGRErr OGRDataSource::Release()
-
-{
-    return OGRSFDriverRegistrar::GetRegistrar()->ReleaseDataSource( this );
-}
-
-/************************************************************************/
-/*                             Reference()                              */
-/************************************************************************/
-
-int OGRDataSource::Reference()
-
-{
-    return ++m_nRefCount;
+    if( hDS == NULL )
+        return;
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpyPreClose(hDS);
+#endif
+    delete (GDALDataset *) hDS;
+    //VALIDATE_POINTER0( hDS, "OGR_DS_Destroy" );
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpyPostClose(hDS);
+#endif
 }
 
 /************************************************************************/
@@ -123,17 +83,7 @@ int OGR_DS_Reference( OGRDataSourceH hDataSource )
 {
     VALIDATE_POINTER1( hDataSource, "OGR_DS_Reference", 0 );
 
-    return ((OGRDataSource *) hDataSource)->Reference();
-}
-
-/************************************************************************/
-/*                            Dereference()                             */
-/************************************************************************/
-
-int OGRDataSource::Dereference()
-
-{
-    return --m_nRefCount;
+    return ((GDALDataset *) hDataSource)->Reference();
 }
 
 /************************************************************************/
@@ -145,17 +95,7 @@ int OGR_DS_Dereference( OGRDataSourceH hDataSource )
 {
     VALIDATE_POINTER1( hDataSource, "OGR_DS_Dereference", 0 );
 
-    return ((OGRDataSource *) hDataSource)->Dereference();
-}
-
-/************************************************************************/
-/*                            GetRefCount()                             */
-/************************************************************************/
-
-int OGRDataSource::GetRefCount() const
-
-{
-    return m_nRefCount;
+    return ((GDALDataset *) hDataSource)->Dereference();
 }
 
 /************************************************************************/
@@ -167,25 +107,7 @@ int OGR_DS_GetRefCount( OGRDataSourceH hDataSource )
 {
     VALIDATE_POINTER1( hDataSource, "OGR_DS_GetRefCount", 0 );
 
-    return ((OGRDataSource *) hDataSource)->GetRefCount();
-}
-
-/************************************************************************/
-/*                         GetSummaryRefCount()                         */
-/************************************************************************/
-
-int OGRDataSource::GetSummaryRefCount() const
-
-{
-    CPLMutexHolderD( (void **) &m_hMutex );
-    int nSummaryCount = m_nRefCount;
-    int iLayer;
-    OGRDataSource *poUseThis = (OGRDataSource *) this;
-
-    for( iLayer=0; iLayer < poUseThis->GetLayerCount(); iLayer++ )
-        nSummaryCount += poUseThis->GetLayer( iLayer )->GetRefCount();
-
-    return nSummaryCount;
+    return ((GDALDataset *) hDataSource)->GetRefCount();
 }
 
 /************************************************************************/
@@ -197,28 +119,7 @@ int OGR_DS_GetSummaryRefCount( OGRDataSourceH hDataSource )
 {
     VALIDATE_POINTER1( hDataSource, "OGR_DS_GetSummaryRefCount", 0 );
 
-    return ((OGRDataSource *) hDataSource)->GetSummaryRefCount();
-}
-
-/************************************************************************/
-/*                            CreateLayer()                             */
-/************************************************************************/
-
-OGRLayer *OGRDataSource::CreateLayer( const char * pszName,
-                                      OGRSpatialReference * poSpatialRef,
-                                      OGRwkbGeometryType eGType,
-                                      char **papszOptions )
-
-{
-    (void) eGType;
-    (void) poSpatialRef;
-    (void) pszName;
-    (void) papszOptions;
-
-    CPLError( CE_Failure, CPLE_NotSupported,
-              "CreateLayer() not supported by this data source." );
-              
-    return NULL;
+    return ((GDALDataset *) hDataSource)->GetSummaryRefCount();
 }
 
 /************************************************************************/
@@ -239,241 +140,15 @@ OGRLayerH OGR_DS_CreateLayer( OGRDataSourceH hDS,
         CPLError ( CE_Failure, CPLE_ObjectNull, "Name was NULL in OGR_DS_CreateLayer");
         return 0;
     }
-    return (OGRLayerH) ((OGRDataSource *)hDS)->CreateLayer( 
+    OGRLayerH hLayer = (OGRLayerH) ((GDALDataset *)hDS)->CreateLayer( 
         pszName, (OGRSpatialReference *) hSpatialRef, eType, papszOptions );
-}
-
-/************************************************************************/
-/*                             CopyLayer()                              */
-/************************************************************************/
 
-OGRLayer *OGRDataSource::CopyLayer( OGRLayer *poSrcLayer, 
-                                    const char *pszNewName, 
-                                    char **papszOptions )
-
-{
-    OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
-    OGRLayer *poDstLayer = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Create the layer.                                               */
-/* -------------------------------------------------------------------- */
-    if( !TestCapability( ODsCCreateLayer ) )
-    {
-        CPLError( CE_Failure, CPLE_NotSupported, 
-                  "This datasource does not support creation of layers." );
-        return NULL;
-    }
-
-    CPLErrorReset();
-    if( poSrcDefn->GetGeomFieldCount() > 1 &&
-        TestCapability(ODsCCreateGeomFieldAfterCreateLayer) )
-    {
-        poDstLayer = CreateLayer( pszNewName, NULL, wkbNone, papszOptions );
-    }
-    else
-    {
-        poDstLayer = CreateLayer( pszNewName, poSrcLayer->GetSpatialRef(),
-                                  poSrcDefn->GetGeomType(), papszOptions );
-    }
-    
-    if( poDstLayer == NULL )
-        return NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Add fields.  Default to copy all fields, and make sure to       */
-/*      establish a mapping between indices, rather than names, in      */
-/*      case the target datasource has altered it (e.g. Shapefile       */
-/*      limited to 10 char field names).                                */
-/* -------------------------------------------------------------------- */
-    int         nSrcFieldCount = poSrcDefn->GetFieldCount();
-    int         nDstFieldCount = 0;
-    int         iField, *panMap;
-
-    // Initialize the index-to-index map to -1's
-    panMap = (int *) CPLMalloc( sizeof(int) * nSrcFieldCount );
-    for( iField=0; iField < nSrcFieldCount; iField++)
-        panMap[iField] = -1;
-
-    /* Caution : at the time of writing, the MapInfo driver */
-    /* returns NULL until a field has been added */
-    OGRFeatureDefn* poDstFDefn = poDstLayer->GetLayerDefn();
-    if (poDstFDefn)
-        nDstFieldCount = poDstFDefn->GetFieldCount();    
-    for( iField = 0; iField < nSrcFieldCount; iField++ )
-    {
-        OGRFieldDefn* poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
-        OGRFieldDefn oFieldDefn( poSrcFieldDefn );
-
-        /* The field may have been already created at layer creation */
-        int iDstField = -1;
-        if (poDstFDefn)
-            iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
-        if (iDstField >= 0)
-        {
-            panMap[iField] = iDstField;
-        }
-        else if (poDstLayer->CreateField( &oFieldDefn ) == OGRERR_NONE)
-        {
-            /* now that we've created a field, GetLayerDefn() won't return NULL */
-            if (poDstFDefn == NULL)
-                poDstFDefn = poDstLayer->GetLayerDefn();
-
-            /* Sanity check : if it fails, the driver is buggy */
-            if (poDstFDefn != NULL &&
-                poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
-            {
-                CPLError(CE_Warning, CPLE_AppDefined,
-                         "The output driver has claimed to have added the %s field, but it did not!",
-                         oFieldDefn.GetNameRef() );
-            }
-            else
-            {
-                panMap[iField] = nDstFieldCount;
-                nDstFieldCount ++;
-            }
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Create geometry fields.                                         */
-/* -------------------------------------------------------------------- */
-    if( poSrcDefn->GetGeomFieldCount() > 1 &&
-        TestCapability(ODsCCreateGeomFieldAfterCreateLayer) )
-    {
-        int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
-        for( iField = 0; iField < nSrcGeomFieldCount; iField++ )
-        {
-            poDstLayer->CreateGeomField( poSrcDefn->GetGeomFieldDefn(iField) );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check if the destination layer supports transactions and set a  */
-/*      default number of features in a single transaction.             */
-/* -------------------------------------------------------------------- */
-    int nGroupTransactions = 0;
-    if( poDstLayer->TestCapability( OLCTransactions ) )
-        nGroupTransactions = 128;
-
-/* -------------------------------------------------------------------- */
-/*      Transfer features.                                              */
-/* -------------------------------------------------------------------- */
-    OGRFeature  *poFeature;
-
-    poSrcLayer->ResetReading();
-
-    if( nGroupTransactions <= 0 )
-    {
-      while( TRUE )
-      {
-        OGRFeature      *poDstFeature = NULL;
-
-        poFeature = poSrcLayer->GetNextFeature();
-        
-        if( poFeature == NULL )
-            break;
-
-        CPLErrorReset();
-        poDstFeature = OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
-
-        if( poDstFeature->SetFrom( poFeature, panMap, TRUE ) != OGRERR_NONE )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "Unable to translate feature %ld from layer %s.\n",
-                      poFeature->GetFID(), poSrcDefn->GetName() );
-            OGRFeature::DestroyFeature( poFeature );
-            CPLFree(panMap);
-            return poDstLayer;
-        }
-
-        poDstFeature->SetFID( poFeature->GetFID() );
-
-        OGRFeature::DestroyFeature( poFeature );
-
-        CPLErrorReset();
-        if( poDstLayer->CreateFeature( poDstFeature ) != OGRERR_NONE )
-        {
-            OGRFeature::DestroyFeature( poDstFeature );
-            CPLFree(panMap);
-            return poDstLayer;
-        }
-
-        OGRFeature::DestroyFeature( poDstFeature );
-      }
-    }
-    else
-    {
-      int i, bStopTransfer = FALSE, bStopTransaction = FALSE;
-      int nFeatCount = 0; // Number of features in the temporary array
-      int nFeaturesToAdd = 0;
-      OGRFeature **papoDstFeature =
-          (OGRFeature **)CPLCalloc(sizeof(OGRFeature *), nGroupTransactions);
-      while( !bStopTransfer )
-      {
-/* -------------------------------------------------------------------- */
-/*      Fill the array with features                                    */
-/* -------------------------------------------------------------------- */
-        for( nFeatCount = 0; nFeatCount < nGroupTransactions; nFeatCount++ )
-        {
-            poFeature = poSrcLayer->GetNextFeature();
-
-            if( poFeature == NULL )
-            {
-                bStopTransfer = 1;
-                break;
-            }
-
-            CPLErrorReset();
-            papoDstFeature[nFeatCount] =
-                        OGRFeature::CreateFeature( poDstLayer->GetLayerDefn() );
-
-            if( papoDstFeature[nFeatCount]->SetFrom( poFeature, panMap, TRUE ) != OGRERR_NONE )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined,
-                          "Unable to translate feature %ld from layer %s.\n",
-                          poFeature->GetFID(), poSrcDefn->GetName() );
-                OGRFeature::DestroyFeature( poFeature );
-                bStopTransfer = TRUE;
-                break;
-            }
-
-            papoDstFeature[nFeatCount]->SetFID( poFeature->GetFID() );
-
-            OGRFeature::DestroyFeature( poFeature );
-        }
-        nFeaturesToAdd = nFeatCount;
-
-        CPLErrorReset();
-        bStopTransaction = FALSE;
-        while( !bStopTransaction )
-        {
-            bStopTransaction = TRUE;
-            poDstLayer->StartTransaction();
-            for( i = 0; i < nFeaturesToAdd; i++ )
-            {
-                if( poDstLayer->CreateFeature( papoDstFeature[i] ) != OGRERR_NONE )
-                {
-                    nFeaturesToAdd = i;
-                    bStopTransfer = TRUE;
-                    bStopTransaction = FALSE;
-                }
-            }
-            if( bStopTransaction )
-                poDstLayer->CommitTransaction();
-            else
-                poDstLayer->RollbackTransaction();
-        }
-
-        for( i = 0; i < nFeatCount; i++ )
-            OGRFeature::DestroyFeature( papoDstFeature[i] );
-      }
-      CPLFree(papoDstFeature);
-    }
-
-    CPLFree(panMap);
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eType, papszOptions, hLayer);
+#endif
 
-    return poDstLayer;
+    return hLayer;
 }
 
 /************************************************************************/
@@ -490,25 +165,11 @@ OGRLayerH OGR_DS_CopyLayer( OGRDataSourceH hDS,
     VALIDATE_POINTER1( pszNewName, "OGR_DS_CopyLayer", NULL );
 
     return (OGRLayerH) 
-        ((OGRDataSource *) hDS)->CopyLayer( (OGRLayer *) hSrcLayer, 
+        ((GDALDataset *) hDS)->CopyLayer( (OGRLayer *) hSrcLayer, 
                                             pszNewName, papszOptions );
 }
 
 /************************************************************************/
-/*                            DeleteLayer()                             */
-/************************************************************************/
-
-OGRErr OGRDataSource::DeleteLayer( int iLayer )
-
-{
-    (void) iLayer;
-    CPLError( CE_Failure, CPLE_NotSupported,
-              "DeleteLayer() not supported by this data source." );
-              
-    return OGRERR_UNSUPPORTED_OPERATION;
-}
-
-/************************************************************************/
 /*                         OGR_DS_DeleteLayer()                         */
 /************************************************************************/
 
@@ -517,42 +178,14 @@ OGRErr OGR_DS_DeleteLayer( OGRDataSourceH hDS, int iLayer )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_DeleteLayer", OGRERR_INVALID_HANDLE );
 
-    return ((OGRDataSource *) hDS)->DeleteLayer( iLayer );
-}
-
-/************************************************************************/
-/*                           GetLayerByName()                           */
-/************************************************************************/
-
-OGRLayer *OGRDataSource::GetLayerByName( const char *pszName )
-
-{
-    CPLMutexHolderD( &m_hMutex );
-
-    if ( ! pszName )
-        return NULL;
-
-    int  i;
-
-    /* first a case sensitive check */
-    for( i = 0; i < GetLayerCount(); i++ )
-    {
-        OGRLayer *poLayer = GetLayer(i);
-
-        if( strcmp( pszName, poLayer->GetName() ) == 0 )
-            return poLayer;
-    }
-
-    /* then case insensitive */
-    for( i = 0; i < GetLayerCount(); i++ )
-    {
-        OGRLayer *poLayer = GetLayer(i);
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
+#endif
 
-        if( EQUAL( pszName, poLayer->GetName() ) )
-            return poLayer;
-    }
+    OGRErr eErr = ((GDALDataset *) hDS)->DeleteLayer( iLayer );
 
-    return NULL;
+    return eErr;
 }
 
 /************************************************************************/
@@ -564,1137 +197,14 @@ OGRLayerH OGR_DS_GetLayerByName( OGRDataSourceH hDS, const char *pszName )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_GetLayerByName", NULL );
 
-    return (OGRLayerH) ((OGRDataSource *) hDS)->GetLayerByName( pszName );
-}
-
-/************************************************************************/
-/*                       ProcessSQLCreateIndex()                        */
-/*                                                                      */
-/*      The correct syntax for creating an index in our dialect of      */
-/*      SQL is:                                                         */
-/*                                                                      */
-/*        CREATE INDEX ON <layername> USING <columnname>                */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLCreateIndex( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    if( CSLCount(papszTokens) != 6 
-        || !EQUAL(papszTokens[0],"CREATE")
-        || !EQUAL(papszTokens[1],"INDEX")
-        || !EQUAL(papszTokens[2],"ON")
-        || !EQUAL(papszTokens[4],"USING") )
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Syntax error in CREATE INDEX command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'CREATE INDEX ON <table> USING <field>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    int  i;
-    OGRLayer *poLayer = NULL;
-
-    {
-        CPLMutexHolderD( &m_hMutex );
-
-        for( i = 0; i < GetLayerCount(); i++ )
-        {
-            poLayer = GetLayer(i);
-            
-            if( EQUAL(poLayer->GetName(),papszTokens[3]) )
-                break;
-        }
-        
-        if( i >= GetLayerCount() )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "CREATE INDEX ON failed, no such layer as `%s'.",
-                      papszTokens[3] );
-            CSLDestroy( papszTokens );
-            return OGRERR_FAILURE;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Does this layer even support attribute indexes?                 */
-/* -------------------------------------------------------------------- */
-    if( poLayer->GetIndex() == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "CREATE INDEX ON not supported by this driver." );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named field.                                           */
-/* -------------------------------------------------------------------- */
-    for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
-    {
-        if( EQUAL(papszTokens[5],
-                  poLayer->GetLayerDefn()->GetFieldDefn(i)->GetNameRef()) )
-            break;
-    }
-
-    CSLDestroy( papszTokens );
-
-    if( i >= poLayer->GetLayerDefn()->GetFieldCount() )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "`%s' failed, field not found.",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Attempt to create the index.                                    */
-/* -------------------------------------------------------------------- */
-    OGRErr eErr;
-
-    eErr = poLayer->GetIndex()->CreateIndex( i );
-    if( eErr == OGRERR_NONE )
-        eErr = poLayer->GetIndex()->IndexAllFeatures( i );
-    else
-    {
-        if( strlen(CPLGetLastErrorMsg()) == 0 )
-            CPLError( CE_Failure, CPLE_AppDefined,
-                    "Cannot '%s'", pszSQLCommand);
-    }
-
-    return eErr;
-}
-
-/************************************************************************/
-/*                        ProcessSQLDropIndex()                         */
-/*                                                                      */
-/*      The correct syntax for droping one or more indexes in           */
-/*      the OGR SQL dialect is:                                         */
-/*                                                                      */
-/*          DROP INDEX ON <layername> [USING <columnname>]              */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLDropIndex( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    if( (CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6)
-        || !EQUAL(papszTokens[0],"DROP")
-        || !EQUAL(papszTokens[1],"INDEX")
-        || !EQUAL(papszTokens[2],"ON") 
-        || (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4],"USING")) )
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Syntax error in DROP INDEX command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    int  i;
-    OGRLayer *poLayer=NULL;
-
-    {
-        CPLMutexHolderD( &m_hMutex );
-
-        for( i = 0; i < GetLayerCount(); i++ )
-        {
-            poLayer = GetLayer(i);
-        
-            if( EQUAL(poLayer->GetName(),papszTokens[3]) )
-                break;
-        }
-
-        if( i >= GetLayerCount() )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "CREATE INDEX ON failed, no such layer as `%s'.",
-                      papszTokens[3] );
-            CSLDestroy( papszTokens );
-            return OGRERR_FAILURE;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Does this layer even support attribute indexes?                 */
-/* -------------------------------------------------------------------- */
-    if( poLayer->GetIndex() == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Indexes not supported by this driver." );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      If we weren't given a field name, drop all indexes.             */
-/* -------------------------------------------------------------------- */
-    OGRErr eErr;
-
-    if( CSLCount(papszTokens) == 4 )
-    {
-        for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
-        {
-            OGRAttrIndex *poAttrIndex;
-
-            poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
-            if( poAttrIndex != NULL )
-            {
-                eErr = poLayer->GetIndex()->DropIndex( i );
-                if( eErr != OGRERR_NONE )
-                {
-                    CSLDestroy(papszTokens);
-                    return eErr;
-                }
-            }
-        }
-
-        CSLDestroy(papszTokens);
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named field.                                           */
-/* -------------------------------------------------------------------- */
-    for( i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); i++ )
-    {
-        if( EQUAL(papszTokens[5],
-                  poLayer->GetLayerDefn()->GetFieldDefn(i)->GetNameRef()) )
-            break;
-    }
-
-    CSLDestroy( papszTokens );
-
-    if( i >= poLayer->GetLayerDefn()->GetFieldCount() )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "`%s' failed, field not found.",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Attempt to drop the index.                                      */
-/* -------------------------------------------------------------------- */
-    eErr = poLayer->GetIndex()->DropIndex( i );
-
-    return eErr;
-}
-
-/************************************************************************/
-/*                        ProcessSQLDropTable()                         */
-/*                                                                      */
-/*      The correct syntax for dropping a table (layer) in the OGR SQL  */
-/*      dialect is:                                                     */
-/*                                                                      */
-/*          DROP TABLE <layername>                                      */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLDropTable( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    if( CSLCount(papszTokens) != 3
-        || !EQUAL(papszTokens[0],"DROP")
-        || !EQUAL(papszTokens[1],"TABLE") )
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Syntax error in DROP TABLE command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'DROP TABLE <table>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    int  i;
-    OGRLayer *poLayer=NULL;
-
-    for( i = 0; i < GetLayerCount(); i++ )
-    {
-        poLayer = GetLayer(i);
-        
-        if( EQUAL(poLayer->GetName(),papszTokens[2]) )
-            break;
-    }
-    
-    if( i >= GetLayerCount() )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "DROP TABLE failed, no such layer as `%s'.",
-                  papszTokens[2] );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-    CSLDestroy( papszTokens );
-
-/* -------------------------------------------------------------------- */
-/*      Delete it.                                                      */
-/* -------------------------------------------------------------------- */
-
-    return DeleteLayer( i );
-}
-
-/************************************************************************/
-/*                    OGRDataSourceParseSQLType()                       */
-/************************************************************************/
-
-/* All arguments will be altered */
-static OGRFieldType OGRDataSourceParseSQLType(char* pszType, int& nWidth, int &nPrecision)
-{
-    char* pszParenthesis = strchr(pszType, '(');
-    if (pszParenthesis)
-    {
-        nWidth = atoi(pszParenthesis + 1);
-        *pszParenthesis = '\0';
-        char* pszComma = strchr(pszParenthesis + 1, ',');
-        if (pszComma)
-            nPrecision = atoi(pszComma + 1);
-    }
-
-    OGRFieldType eType = OFTString;
-    if (EQUAL(pszType, "INTEGER"))
-        eType = OFTInteger;
-    else if (EQUAL(pszType, "INTEGER[]"))
-        eType = OFTIntegerList;
-    else if (EQUAL(pszType, "FLOAT") ||
-             EQUAL(pszType, "NUMERIC") ||
-             EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
-             EQUAL(pszType, "REAL") /* unofficial alias */)
-        eType = OFTReal;
-    else if (EQUAL(pszType, "FLOAT[]") ||
-             EQUAL(pszType, "NUMERIC[]") ||
-             EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
-             EQUAL(pszType, "REAL[]") /* unofficial alias */)
-        eType = OFTRealList;
-    else if (EQUAL(pszType, "CHARACTER") ||
-             EQUAL(pszType, "TEXT") /* unofficial alias */ ||
-             EQUAL(pszType, "STRING") /* unofficial alias */ ||
-             EQUAL(pszType, "VARCHAR") /* unofficial alias */)
-        eType = OFTString;
-    else if (EQUAL(pszType, "TEXT[]") ||
-             EQUAL(pszType, "STRING[]") /* unofficial alias */||
-             EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
-        eType = OFTStringList;
-    else if (EQUAL(pszType, "DATE"))
-        eType = OFTDate;
-    else if (EQUAL(pszType, "TIME"))
-        eType = OFTTime;
-    else if (EQUAL(pszType, "TIMESTAMP") ||
-             EQUAL(pszType, "DATETIME") /* unofficial alias */ )
-        eType = OFTDateTime;
-    else
-    {
-        CPLError(CE_Warning, CPLE_NotSupported,
-                 "Unsupported column type '%s'. Defaulting to VARCHAR",
-                 pszType);
-    }
-    return eType;
-}
-
-/************************************************************************/
-/*                    ProcessSQLAlterTableAddColumn()                   */
-/*                                                                      */
-/*      The correct syntax for adding a column in the OGR SQL           */
-/*      dialect is:                                                     */
-/*                                                                      */
-/*          ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype>*/
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLAlterTableAddColumn( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    const char* pszLayerName = NULL;
-    const char* pszColumnName = NULL;
-    char* pszType = NULL;
-    int iTypeIndex = 0;
-    int nTokens = CSLCount(papszTokens);
-
-    if( nTokens >= 7
-        && EQUAL(papszTokens[0],"ALTER")
-        && EQUAL(papszTokens[1],"TABLE")
-        && EQUAL(papszTokens[3],"ADD")
-        && EQUAL(papszTokens[4],"COLUMN"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[5];
-        iTypeIndex = 6;
-    }
-    else if( nTokens >= 6
-             && EQUAL(papszTokens[0],"ALTER")
-             && EQUAL(papszTokens[1],"TABLE")
-             && EQUAL(papszTokens[3],"ADD"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[4];
-        iTypeIndex = 5;
-    }
-    else
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Syntax error in ALTER TABLE ADD COLUMN command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Merge type components into a single string if there were split  */
-/*      with spaces                                                     */
-/* -------------------------------------------------------------------- */
-    CPLString osType;
-    for(int i=iTypeIndex;i<nTokens;i++)
-    {
-        osType += papszTokens[i];
-        CPLFree(papszTokens[i]);
-    }
-    pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
-    papszTokens[iTypeIndex + 1] = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    OGRLayer *poLayer = GetLayerByName(pszLayerName);
-    if( poLayer == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such layer as `%s'.",
-                  pszSQLCommand,
-                  pszLayerName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Add column.                                                     */
-/* -------------------------------------------------------------------- */
-
-    int nWidth = 0, nPrecision = 0;
-    OGRFieldType eType = OGRDataSourceParseSQLType(pszType, nWidth, nPrecision);
-    OGRFieldDefn oFieldDefn(pszColumnName, eType);
-    oFieldDefn.SetWidth(nWidth);
-    oFieldDefn.SetPrecision(nPrecision);
-
-    CSLDestroy( papszTokens );
-
-    return poLayer->CreateField( &oFieldDefn );
-}
-
-/************************************************************************/
-/*                    ProcessSQLAlterTableDropColumn()                  */
-/*                                                                      */
-/*      The correct syntax for droping a column in the OGR SQL          */
-/*      dialect is:                                                     */
-/*                                                                      */
-/*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLAlterTableDropColumn( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    const char* pszLayerName = NULL;
-    const char* pszColumnName = NULL;
-    if( CSLCount(papszTokens) == 6
-        && EQUAL(papszTokens[0],"ALTER")
-        && EQUAL(papszTokens[1],"TABLE")
-        && EQUAL(papszTokens[3],"DROP")
-        && EQUAL(papszTokens[4],"COLUMN"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[5];
-    }
-    else if( CSLCount(papszTokens) == 5
-             && EQUAL(papszTokens[0],"ALTER")
-             && EQUAL(papszTokens[1],"TABLE")
-             && EQUAL(papszTokens[3],"DROP"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[4];
-    }
-    else
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Syntax error in ALTER TABLE DROP COLUMN command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] <columnname>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    OGRLayer *poLayer = GetLayerByName(pszLayerName);
-    if( poLayer == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such layer as `%s'.",
-                  pszSQLCommand,
-                  pszLayerName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the field.                                                 */
-/* -------------------------------------------------------------------- */
-
-    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
-    if( nFieldIndex < 0 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such field as `%s'.",
-                  pszSQLCommand,
-                  pszColumnName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-
-/* -------------------------------------------------------------------- */
-/*      Remove it.                                                      */
-/* -------------------------------------------------------------------- */
-
-    CSLDestroy( papszTokens );
-
-    return poLayer->DeleteField( nFieldIndex );
-}
-
-/************************************************************************/
-/*                 ProcessSQLAlterTableRenameColumn()                   */
-/*                                                                      */
-/*      The correct syntax for renaming a column in the OGR SQL         */
-/*      dialect is:                                                     */
-/*                                                                      */
-/*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLAlterTableRenameColumn( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    const char* pszLayerName = NULL;
-    const char* pszOldColName = NULL;
-    const char* pszNewColName = NULL;
-    if( CSLCount(papszTokens) == 8
-        && EQUAL(papszTokens[0],"ALTER")
-        && EQUAL(papszTokens[1],"TABLE")
-        && EQUAL(papszTokens[3],"RENAME")
-        && EQUAL(papszTokens[4],"COLUMN")
-        && EQUAL(papszTokens[6],"TO"))
-    {
-        pszLayerName = papszTokens[2];
-        pszOldColName = papszTokens[5];
-        pszNewColName = papszTokens[7];
-    }
-    else if( CSLCount(papszTokens) == 7
-             && EQUAL(papszTokens[0],"ALTER")
-             && EQUAL(papszTokens[1],"TABLE")
-             && EQUAL(papszTokens[3],"RENAME")
-             && EQUAL(papszTokens[5],"TO"))
-    {
-        pszLayerName = papszTokens[2];
-        pszOldColName = papszTokens[4];
-        pszNewColName = papszTokens[6];
-    }
-    else
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] <columnname> TO <newname>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    OGRLayer *poLayer = GetLayerByName(pszLayerName);
-    if( poLayer == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such layer as `%s'.",
-                  pszSQLCommand,
-                  pszLayerName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
+    OGRLayerH hLayer = (OGRLayerH) ((GDALDataset *) hDS)->GetLayerByName( pszName );
 
-/* -------------------------------------------------------------------- */
-/*      Find the field.                                                 */
-/* -------------------------------------------------------------------- */
-
-    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
-    if( nFieldIndex < 0 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such field as `%s'.",
-                  pszSQLCommand,
-                  pszOldColName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Rename column.                                                  */
-/* -------------------------------------------------------------------- */
-    OGRFieldDefn* poOldFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
-    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
-    oNewFieldDefn.SetName(pszNewColName);
-
-    CSLDestroy( papszTokens );
-
-    return poLayer->AlterFieldDefn( nFieldIndex, &oNewFieldDefn, ALTER_NAME_FLAG );
-}
-
-/************************************************************************/
-/*                 ProcessSQLAlterTableAlterColumn()                    */
-/*                                                                      */
-/*      The correct syntax for altering the type of a column in the     */
-/*      OGR SQL dialect is:                                             */
-/*                                                                      */
-/*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
-/************************************************************************/
-
-OGRErr OGRDataSource::ProcessSQLAlterTableAlterColumn( const char *pszSQLCommand )
-
-{
-    char **papszTokens = CSLTokenizeString( pszSQLCommand );
-
-/* -------------------------------------------------------------------- */
-/*      Do some general syntax checking.                                */
-/* -------------------------------------------------------------------- */
-    const char* pszLayerName = NULL;
-    const char* pszColumnName = NULL;
-    char* pszType = NULL;
-    int iTypeIndex = 0;
-    int nTokens = CSLCount(papszTokens);
-
-    if( nTokens >= 8
-        && EQUAL(papszTokens[0],"ALTER")
-        && EQUAL(papszTokens[1],"TABLE")
-        && EQUAL(papszTokens[3],"ALTER")
-        && EQUAL(papszTokens[4],"COLUMN")
-        && EQUAL(papszTokens[6],"TYPE"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[5];
-        iTypeIndex = 7;
-    }
-    else if( nTokens >= 7
-             && EQUAL(papszTokens[0],"ALTER")
-             && EQUAL(papszTokens[1],"TABLE")
-             && EQUAL(papszTokens[3],"ALTER")
-             && EQUAL(papszTokens[5],"TYPE"))
-    {
-        pszLayerName = papszTokens[2];
-        pszColumnName = papszTokens[4];
-        iTypeIndex = 6;
-    }
-    else
-    {
-        CSLDestroy( papszTokens );
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
-                  "Was '%s'\n"
-                  "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <columntype>'",
-                  pszSQLCommand );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Merge type components into a single string if there were split  */
-/*      with spaces                                                     */
-/* -------------------------------------------------------------------- */
-    CPLString osType;
-    for(int i=iTypeIndex;i<nTokens;i++)
-    {
-        osType += papszTokens[i];
-        CPLFree(papszTokens[i]);
-    }
-    pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
-    papszTokens[iTypeIndex + 1] = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Find the named layer.                                           */
-/* -------------------------------------------------------------------- */
-    OGRLayer *poLayer = GetLayerByName(pszLayerName);
-    if( poLayer == NULL )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such layer as `%s'.",
-                  pszSQLCommand,
-                  pszLayerName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Find the field.                                                 */
-/* -------------------------------------------------------------------- */
-
-    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
-    if( nFieldIndex < 0 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s failed, no such field as `%s'.",
-                  pszSQLCommand,
-                  pszColumnName );
-        CSLDestroy( papszTokens );
-        return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Alter column.                                                   */
-/* -------------------------------------------------------------------- */
-
-    OGRFieldDefn* poOldFieldDefn = poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
-    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
-
-    int nWidth = 0, nPrecision = 0;
-    OGRFieldType eType = OGRDataSourceParseSQLType(pszType, nWidth, nPrecision);
-    oNewFieldDefn.SetType(eType);
-    oNewFieldDefn.SetWidth(nWidth);
-    oNewFieldDefn.SetPrecision(nPrecision);
-
-    int nFlags = 0;
-    if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
-        nFlags |= ALTER_TYPE_FLAG;
-    if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
-        poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
-        nFlags |= ALTER_WIDTH_PRECISION_FLAG;
-
-    CSLDestroy( papszTokens );
-
-    if (nFlags == 0)
-        return OGRERR_NONE;
-    else
-        return poLayer->AlterFieldDefn( nFieldIndex, &oNewFieldDefn, nFlags );
-}
-
-/************************************************************************/
-/*                             ExecuteSQL()                             */
-/************************************************************************/
-
-OGRLayer * OGRDataSource::ExecuteSQL( const char *pszStatement,
-                                      OGRGeometry *poSpatialFilter,
-                                      const char *pszDialect )
-
-{
-    swq_select *psSelectInfo = NULL;
-
-    if( pszDialect != NULL && EQUAL(pszDialect, "SQLite") )
-    {
-#ifdef SQLITE_ENABLED
-        return OGRSQLiteExecuteSQL( this, pszStatement, poSpatialFilter, pszDialect );
-#else
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "The SQLite driver needs to be compiled to support the SQLite SQL dialect");
-        return NULL;
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
 #endif
-    }
 
-/* -------------------------------------------------------------------- */
-/*      Handle CREATE INDEX statements specially.                       */
-/* -------------------------------------------------------------------- */
-    if( EQUALN(pszStatement,"CREATE INDEX",12) )
-    {
-        ProcessSQLCreateIndex( pszStatement );
-        return NULL;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Handle DROP INDEX statements specially.                         */
-/* -------------------------------------------------------------------- */
-    if( EQUALN(pszStatement,"DROP INDEX",10) )
-    {
-        ProcessSQLDropIndex( pszStatement );
-        return NULL;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Handle DROP TABLE statements specially.                         */
-/* -------------------------------------------------------------------- */
-    if( EQUALN(pszStatement,"DROP TABLE",10) )
-    {
-        ProcessSQLDropTable( pszStatement );
-        return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Handle ALTER TABLE statements specially.                        */
-/* -------------------------------------------------------------------- */
-    if( EQUALN(pszStatement,"ALTER TABLE",11) )
-    {
-        char **papszTokens = CSLTokenizeString( pszStatement );
-        if( CSLCount(papszTokens) >= 4 &&
-            EQUAL(papszTokens[3],"ADD") )
-        {
-            ProcessSQLAlterTableAddColumn( pszStatement );
-            CSLDestroy(papszTokens);
-            return NULL;
-        }
-        else if( CSLCount(papszTokens) >= 4 &&
-                 EQUAL(papszTokens[3],"DROP") )
-        {
-            ProcessSQLAlterTableDropColumn( pszStatement );
-            CSLDestroy(papszTokens);
-            return NULL;
-        }
-        else if( CSLCount(papszTokens) >= 4 &&
-                 EQUAL(papszTokens[3],"RENAME") )
-        {
-            ProcessSQLAlterTableRenameColumn( pszStatement );
-            CSLDestroy(papszTokens);
-            return NULL;
-        }
-        else if( CSLCount(papszTokens) >= 4 &&
-                 EQUAL(papszTokens[3],"ALTER") )
-        {
-            ProcessSQLAlterTableAlterColumn( pszStatement );
-            CSLDestroy(papszTokens);
-            return NULL;
-        }
-        else
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "Unsupported ALTER TABLE command : %s",
-                      pszStatement );
-            CSLDestroy(papszTokens);
-            return NULL;
-        }
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Preparse the SQL statement.                                     */
-/* -------------------------------------------------------------------- */
-    psSelectInfo = new swq_select();
-    if( psSelectInfo->preparse( pszStatement ) != CPLE_None )
-    {
-        delete psSelectInfo;
-        return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      If there is no UNION ALL, build result layer.                   */
-/* -------------------------------------------------------------------- */
-    if( psSelectInfo->poOtherSelect == NULL )
-    {
-        return BuildLayerFromSelectInfo(psSelectInfo,
-                                        poSpatialFilter,
-                                        pszDialect);
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Build result union layer.                                       */
-/* -------------------------------------------------------------------- */
-    int nSrcLayers = 0;
-    OGRLayer** papoSrcLayers = NULL;
-
-    do
-    {
-        swq_select* psNextSelectInfo = psSelectInfo->poOtherSelect;
-        psSelectInfo->poOtherSelect = NULL;
-
-        OGRLayer* poLayer = BuildLayerFromSelectInfo(psSelectInfo,
-                                                     poSpatialFilter,
-                                                     pszDialect);
-        if( poLayer == NULL )
-        {
-            /* Each source layer owns an independant select info */
-            for(int i=0;i<nSrcLayers;i++)
-                delete papoSrcLayers[i];
-            CPLFree(papoSrcLayers);
-
-            /* So we just have to destroy the remaining select info */
-            delete psNextSelectInfo;
-
-            return NULL;
-        }
-        else
-        {
-            papoSrcLayers = (OGRLayer**) CPLRealloc(papoSrcLayers,
-                                sizeof(OGRLayer*) * (nSrcLayers + 1));
-            papoSrcLayers[nSrcLayers] = poLayer;
-            nSrcLayers ++;
-
-            psSelectInfo = psNextSelectInfo;
-        }
-    }
-    while( psSelectInfo != NULL );
-
-    return new OGRUnionLayer("SELECT",
-                                nSrcLayers,
-                                papoSrcLayers,
-                                TRUE);
-}
-
-/************************************************************************/
-/*                        BuildLayerFromSelectInfo()                    */
-/************************************************************************/
-
-OGRLayer* OGRDataSource::BuildLayerFromSelectInfo(void* psSelectInfoIn,
-                                                  OGRGeometry *poSpatialFilter,
-                                                  const char *pszDialect)
-{
-    swq_select* psSelectInfo = (swq_select*) psSelectInfoIn;
-
-    swq_field_list sFieldList;
-    int            nFIDIndex = 0;
-    OGRGenSQLResultsLayer *poResults = NULL;
-    char *pszWHERE = NULL;
-
-    memset( &sFieldList, 0, sizeof(sFieldList) );
-
-/* -------------------------------------------------------------------- */
-/*      Validate that all the source tables are recognised, count       */
-/*      fields.                                                         */
-/* -------------------------------------------------------------------- */
-    int  nFieldCount = 0, iTable, iField;
-    int  iEDS;
-    int  nExtraDSCount = 0;
-    OGRDataSource** papoExtraDS = NULL;
-    OGRSFDriverRegistrar *poReg=OGRSFDriverRegistrar::GetRegistrar();
-
-    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
-    {
-        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
-        OGRLayer *poSrcLayer;
-        OGRDataSource *poTableDS = this;
-
-        if( psTableDef->data_source != NULL )
-        {
-            poTableDS = (OGRDataSource *) 
-                OGROpenShared( psTableDef->data_source, FALSE, NULL );
-            if( poTableDS == NULL )
-            {
-                if( strlen(CPLGetLastErrorMsg()) == 0 )
-                    CPLError( CE_Failure, CPLE_AppDefined, 
-                              "Unable to open secondary datasource\n"
-                              "`%s' required by JOIN.",
-                              psTableDef->data_source );
-
-                delete psSelectInfo;
-                goto end;
-            }
-
-            /* Keep in an array to release at the end of this function */
-            papoExtraDS = (OGRDataSource** )CPLRealloc(papoExtraDS,
-                               sizeof(OGRDataSource*) * (nExtraDSCount + 1));
-            papoExtraDS[nExtraDSCount++] = poTableDS;
-        }
-
-        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );
-
-        if( poSrcLayer == NULL )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "SELECT from table %s failed, no such table/featureclass.",
-                      psTableDef->table_name );
-            delete psSelectInfo;
-            goto end;
-        }
-
-        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
-        if( iTable == 0 )
-            nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Build the field list for all indicated tables.                  */
-/* -------------------------------------------------------------------- */
-
-    sFieldList.table_count = psSelectInfo->table_count;
-    sFieldList.table_defs = psSelectInfo->table_defs;
-
-    sFieldList.count = 0;
-    sFieldList.names = (char **) CPLMalloc( sizeof(char *) * (nFieldCount+SPECIAL_FIELD_COUNT) );
-    sFieldList.types = (swq_field_type *)  
-        CPLMalloc( sizeof(swq_field_type) * (nFieldCount+SPECIAL_FIELD_COUNT) );
-    sFieldList.table_ids = (int *) 
-        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
-    sFieldList.ids = (int *) 
-        CPLMalloc( sizeof(int) * (nFieldCount+SPECIAL_FIELD_COUNT) );
-    
-    for( iTable = 0; iTable < psSelectInfo->table_count; iTable++ )
-    {
-        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
-        OGRDataSource *poTableDS = this;
-        OGRLayer *poSrcLayer;
-        
-        if( psTableDef->data_source != NULL )
-        {
-            poTableDS = (OGRDataSource *) 
-                OGROpenShared( psTableDef->data_source, FALSE, NULL );
-            CPLAssert( poTableDS != NULL );
-            poTableDS->Dereference();
-        }
-
-        poSrcLayer = poTableDS->GetLayerByName( psTableDef->table_name );
-
-        for( iField = 0; 
-             iField < poSrcLayer->GetLayerDefn()->GetFieldCount();
-             iField++ )
-        {
-            OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
-            int iOutField = sFieldList.count++;
-            sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
-            if( poFDefn->GetType() == OFTInteger )
-                sFieldList.types[iOutField] = SWQ_INTEGER;
-            else if( poFDefn->GetType() == OFTReal )
-                sFieldList.types[iOutField] = SWQ_FLOAT;
-            else if( poFDefn->GetType() == OFTString )
-                sFieldList.types[iOutField] = SWQ_STRING;
-            else if( poFDefn->GetType() == OFTTime )
-                sFieldList.types[iOutField] = SWQ_TIME;
-            else if( poFDefn->GetType() == OFTDate )
-                sFieldList.types[iOutField] = SWQ_DATE;
-            else if( poFDefn->GetType() == OFTDateTime )
-                sFieldList.types[iOutField] = SWQ_TIMESTAMP;
-            else
-                sFieldList.types[iOutField] = SWQ_OTHER;
-
-            sFieldList.table_ids[iOutField] = iTable;
-            sFieldList.ids[iOutField] = iField;
-        }
-
-        if( iTable == 0 )
-        {
-            nFIDIndex = sFieldList.count;
-
-            for( iField = 0; 
-                 iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
-                 iField++ )
-            {
-                OGRGeomFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
-                int iOutField = sFieldList.count++;
-                sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef();
-                if( *sFieldList.names[iOutField] == '\0' )
-                    sFieldList.names[iOutField] = (char*) OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME;
-                sFieldList.types[iOutField] = SWQ_GEOMETRY;
-
-                sFieldList.table_ids[iOutField] = iTable;
-                sFieldList.ids[iOutField] =
-                    GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(poSrcLayer->GetLayerDefn(), iField);
-            }
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
-/* -------------------------------------------------------------------- */
-    if( psSelectInfo->expand_wildcard( &sFieldList )  != CE_None )
-    {
-        delete psSelectInfo;
-        goto end;
-    }
-
-    for (iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
-    {
-        sFieldList.names[sFieldList.count] = (char*) SpecialFieldNames[iField];
-        sFieldList.types[sFieldList.count] = SpecialFieldTypes[iField];
-        sFieldList.table_ids[sFieldList.count] = 0;
-        sFieldList.ids[sFieldList.count] = nFIDIndex + iField;
-        sFieldList.count++;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Finish the parse operation.                                     */
-/* -------------------------------------------------------------------- */
-    if( psSelectInfo->parse( &sFieldList, 0 ) != CE_None )
-    {
-        delete psSelectInfo;
-        goto end;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Extract the WHERE expression to use separately.                 */
-/* -------------------------------------------------------------------- */
-    if( psSelectInfo->where_expr != NULL )
-    {
-        if (m_poDriver && (
-                EQUAL(m_poDriver->GetName(), "PostgreSQL") ||
-                EQUAL(m_poDriver->GetName(), "FileGDB" )) )
-            pszWHERE = psSelectInfo->where_expr->Unparse( &sFieldList, '"' );
-        else
-            pszWHERE = psSelectInfo->where_expr->Unparse( &sFieldList, '\'' );
-        //CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Everything seems OK, try to instantiate a results layer.        */
-/* -------------------------------------------------------------------- */
-
-    poResults = new OGRGenSQLResultsLayer( this, psSelectInfo,
-                                           poSpatialFilter,
-                                           pszWHERE,
-                                           pszDialect );
-
-    CPLFree( pszWHERE );
-
-    // Eventually, we should keep track of layers to cleanup.
-
-end:
-    CPLFree( sFieldList.names );
-    CPLFree( sFieldList.types );
-    CPLFree( sFieldList.table_ids );
-    CPLFree( sFieldList.ids );
-
-    /* Release the datasets we have opened with OGROpenShared() */
-    /* It is safe to do that as the 'new OGRGenSQLResultsLayer' itself */
-    /* has taken a reference on them, which it will release in its */
-    /* destructor */
-    for(iEDS = 0; iEDS < nExtraDSCount; iEDS++)
-        poReg->ReleaseDataSource( papoExtraDS[iEDS] );
-    CPLFree(papoExtraDS);
-
-    return poResults;
+    return hLayer;
 }
 
 /************************************************************************/
@@ -1709,20 +219,17 @@ OGRLayerH OGR_DS_ExecuteSQL( OGRDataSourceH hDS,
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_ExecuteSQL", NULL );
 
-    return (OGRLayerH) 
-        ((OGRDataSource *)hDS)->ExecuteSQL( pszStatement,
+    OGRLayerH hLayer = (OGRLayerH) 
+        ((GDALDataset *)hDS)->ExecuteSQL( pszStatement,
                                             (OGRGeometry *) hSpatialFilter,
                                             pszDialect );
-}
-
-/************************************************************************/
-/*                          ReleaseResultSet()                          */
-/************************************************************************/
 
-void OGRDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect, hLayer);
+#endif
 
-{
-    delete poResultsSet;
+    return hLayer;
 }
 
 /************************************************************************/
@@ -1734,7 +241,12 @@ void OGR_DS_ReleaseResultSet( OGRDataSourceH hDS, OGRLayerH hLayer )
 {
     VALIDATE_POINTER0( hDS, "OGR_DS_ReleaseResultSet" );
 
-    ((OGRDataSource *) hDS)->ReleaseResultSet( (OGRLayer *) hLayer );
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
+#endif
+
+    ((GDALDataset *) hDS)->ReleaseResultSet( (OGRLayer *) hLayer );
 }
 
 /************************************************************************/
@@ -1747,7 +259,7 @@ int OGR_DS_TestCapability( OGRDataSourceH hDS, const char *pszCap )
     VALIDATE_POINTER1( hDS, "OGR_DS_TestCapability", 0 );
     VALIDATE_POINTER1( pszCap, "OGR_DS_TestCapability", 0 );
 
-    return ((OGRDataSource *) hDS)->TestCapability( pszCap );
+    return ((GDALDataset *) hDS)->TestCapability( pszCap );
 }
 
 /************************************************************************/
@@ -1759,7 +271,12 @@ int OGR_DS_GetLayerCount( OGRDataSourceH hDS )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_GetLayerCount", 0 );
 
-    return ((OGRDataSource *)hDS)->GetLayerCount();
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_GetLayerCount(hDS);
+#endif
+
+    return ((GDALDataset *)hDS)->GetLayerCount();
 }
 
 /************************************************************************/
@@ -1771,7 +288,14 @@ OGRLayerH OGR_DS_GetLayer( OGRDataSourceH hDS, int iLayer )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_GetLayer", NULL );
 
-    return (OGRLayerH) ((OGRDataSource*)hDS)->GetLayer( iLayer );
+    OGRLayerH hLayer = (OGRLayerH) ((GDALDataset*)hDS)->GetLayer( iLayer );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
+#endif
+
+    return hLayer;
 }
 
 /************************************************************************/
@@ -1783,33 +307,7 @@ const char *OGR_DS_GetName( OGRDataSourceH hDS )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_GetName", NULL );
 
-    return ((OGRDataSource*)hDS)->GetName();
-}
-
-/************************************************************************/
-/*                             SyncToDisk()                             */
-/************************************************************************/
-
-OGRErr OGRDataSource::SyncToDisk()
-
-{
-    CPLMutexHolderD( &m_hMutex );
-    int i;
-    OGRErr eErr;
-
-    for( i = 0; i < GetLayerCount(); i++ )
-    {
-        OGRLayer *poLayer = GetLayer(i);
-
-        if( poLayer )
-        {
-            eErr = poLayer->SyncToDisk();
-            if( eErr != OGRERR_NONE )
-                return eErr;
-        }
-    }
-
-    return OGRERR_NONE;
+    return ((GDALDataset*)hDS)->GetDescription();
 }
 
 /************************************************************************/
@@ -1821,17 +319,11 @@ OGRErr OGR_DS_SyncToDisk( OGRDataSourceH hDS )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_SyncToDisk", OGRERR_INVALID_HANDLE );
 
-    return ((OGRDataSource *) hDS)->SyncToDisk();
-}
-
-/************************************************************************/
-/*                             GetDriver()                              */
-/************************************************************************/
-
-OGRSFDriver *OGRDataSource::GetDriver() const
-
-{
-    return m_poDriver;
+    ((GDALDataset *) hDS)->FlushCache();
+    if( CPLGetLastErrorType() != 0 )
+        return OGRERR_FAILURE;
+    else
+        return OGRERR_NONE;
 }
 
 /************************************************************************/
@@ -1847,48 +339,6 @@ OGRSFDriverH OGR_DS_GetDriver( OGRDataSourceH hDS )
 }
 
 /************************************************************************/
-/*                             SetDriver()                              */
-/************************************************************************/
-
-void OGRDataSource::SetDriver( OGRSFDriver *poDriver ) 
-
-{
-    m_poDriver = poDriver;
-}
-
-/************************************************************************/
-/*                            GetStyleTable()                           */
-/************************************************************************/
-
-OGRStyleTable *OGRDataSource::GetStyleTable()
-{
-    return m_poStyleTable;
-}
-
-/************************************************************************/
-/*                         SetStyleTableDirectly()                      */
-/************************************************************************/
-
-void OGRDataSource::SetStyleTableDirectly( OGRStyleTable *poStyleTable )
-{
-    if ( m_poStyleTable )
-        delete m_poStyleTable;
-    m_poStyleTable = poStyleTable;
-}
-
-/************************************************************************/
-/*                            SetStyleTable()                           */
-/************************************************************************/
-
-void OGRDataSource::SetStyleTable(OGRStyleTable *poStyleTable)
-{
-    if ( m_poStyleTable )
-        delete m_poStyleTable;
-    if ( poStyleTable )
-        m_poStyleTable = poStyleTable->Clone();
-}
-
-/************************************************************************/
 /*                         OGR_DS_GetStyleTable()                       */
 /************************************************************************/
 
@@ -1897,7 +347,7 @@ OGRStyleTableH OGR_DS_GetStyleTable( OGRDataSourceH hDS )
 {
     VALIDATE_POINTER1( hDS, "OGR_DS_GetStyleTable", NULL );
     
-    return (OGRStyleTableH) ((OGRDataSource *) hDS)->GetStyleTable( );
+    return (OGRStyleTableH) ((GDALDataset *) hDS)->GetStyleTable( );
 }
 
 /************************************************************************/
@@ -1910,7 +360,7 @@ void OGR_DS_SetStyleTableDirectly( OGRDataSourceH hDS,
 {
     VALIDATE_POINTER0( hDS, "OGR_DS_SetStyleTableDirectly" );
     
-    ((OGRDataSource *) hDS)->SetStyleTableDirectly( (OGRStyleTable *) hStyleTable);
+    ((GDALDataset *) hDS)->SetStyleTableDirectly( (OGRStyleTable *) hStyleTable);
 }
 
 /************************************************************************/
@@ -1923,16 +373,5 @@ void OGR_DS_SetStyleTable( OGRDataSourceH hDS, OGRStyleTableH hStyleTable )
     VALIDATE_POINTER0( hDS, "OGR_DS_SetStyleTable" );
     VALIDATE_POINTER0( hStyleTable, "OGR_DS_SetStyleTable" );
     
-    ((OGRDataSource *) hDS)->SetStyleTable( (OGRStyleTable *) hStyleTable);
-}
-
-/************************************************************************/
-/*                         IsGenericSQLDialect()                        */
-/************************************************************************/
-
-int OGRDataSource::IsGenericSQLDialect(const char* pszDialect)
-{
-    return ( pszDialect != NULL && (EQUAL(pszDialect,"OGRSQL") ||
-                                    EQUAL(pszDialect,"SQLITE")) );
-
+    ((GDALDataset *) hDS)->SetStyleTable( (OGRStyleTable *) hStyleTable);
 }
diff --git a/ogr/ogrsf_frmts/generic/ogremulatedtransaction.cpp b/ogr/ogrsf_frmts/generic/ogremulatedtransaction.cpp
new file mode 100644
index 0000000..0217de0
--- /dev/null
+++ b/ogr/ogrsf_frmts/generic/ogremulatedtransaction.cpp
@@ -0,0 +1,556 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  Implement OGRDataSourceWithTransaction class
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogremulatedtransaction.h"
+#include "ogrlayerdecorator.h"
+#include <map>
+#include <set>
+
+CPL_CVSID("$Id$");
+
+class OGRDataSourceWithTransaction;
+
+class OGRLayerWithTransaction: public OGRLayerDecorator
+{
+    protected:
+        friend class OGRDataSourceWithTransaction;
+
+        OGRDataSourceWithTransaction* m_poDS;
+        OGRFeatureDefn* m_poFeatureDefn;
+    
+    public:
+        
+        OGRLayerWithTransaction(OGRDataSourceWithTransaction* poDS,
+                                OGRLayer* poBaseLayer);
+       ~OGRLayerWithTransaction();
+
+    virtual const char *GetName() { return GetDescription(); }
+    virtual OGRFeatureDefn *GetLayerDefn();
+
+    virtual OGRErr      CreateField( OGRFieldDefn *poField,
+                                     int bApproxOK = TRUE );
+    virtual OGRErr      DeleteField( int iField );
+    virtual OGRErr      ReorderFields( int* panMap );
+    virtual OGRErr      AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
+};
+
+
+class OGRDataSourceWithTransaction : public OGRDataSource
+{
+  protected:
+    OGRDataSource *m_poBaseDataSource;
+    IOGRTransactionBehaviour* m_poTransactionBehaviour;
+    int            m_bHasOwnershipDataSource;
+    int            m_bHasOwnershipTransactionBehaviour;
+    int            m_bInTransaction;
+
+    std::map<CPLString, OGRLayerWithTransaction* > m_oMapLayers;
+    std::set<OGRLayerWithTransaction*> m_oSetLayers;
+    std::set<OGRLayer*> m_oSetExecuteSQLLayers;
+
+    OGRLayer*     WrapLayer(OGRLayer* poLayer);
+    void          RemapLayers();
+
+  public:
+
+                 OGRDataSourceWithTransaction(OGRDataSource* poBaseDataSource,
+                                          IOGRTransactionBehaviour* poTransactionBehaviour,
+                                          int bTakeOwnershipDataSource,
+                                          int bTakeOwnershipTransactionBehaviour);
+
+    virtual     ~OGRDataSourceWithTransaction();
+    
+    int                 IsInTransaction() const { return m_bInTransaction; }
+
+    virtual const char  *GetName();
+
+    virtual int         GetLayerCount() ;
+    virtual OGRLayer    *GetLayer(int);
+    virtual OGRLayer    *GetLayerByName(const char *);
+    virtual OGRErr      DeleteLayer(int);
+
+    virtual int         TestCapability( const char * );
+
+    virtual OGRLayer   *ICreateLayer( const char *pszName, 
+                                     OGRSpatialReference *poSpatialRef = NULL,
+                                     OGRwkbGeometryType eGType = wkbUnknown,
+                                     char ** papszOptions = NULL );
+    virtual OGRLayer   *CopyLayer( OGRLayer *poSrcLayer, 
+                                   const char *pszNewName, 
+                                   char **papszOptions = NULL );
+
+    virtual OGRStyleTable *GetStyleTable();
+    virtual void        SetStyleTableDirectly( OGRStyleTable *poStyleTable );
+                            
+    virtual void        SetStyleTable(OGRStyleTable *poStyleTable);
+
+    virtual OGRLayer *  ExecuteSQL( const char *pszStatement,
+                                    OGRGeometry *poSpatialFilter,
+                                    const char *pszDialect );
+    virtual void        ReleaseResultSet( OGRLayer * poResultsSet );
+    
+    virtual void        FlushCache();
+
+    virtual OGRErr      StartTransaction(int bForce=FALSE);
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
+
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                     const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                         const char * pszValue,
+                                         const char * pszDomain = "" );
+};
+
+/************************************************************************/
+/*                         ~IOGRTransactionBehaviour                    */
+/************************************************************************/
+
+IOGRTransactionBehaviour::~IOGRTransactionBehaviour()
+{
+}
+
+/************************************************************************/
+/*              OGRCreateEmulatedTransactionDataSourceWrapper()         */
+/************************************************************************/
+
+OGRDataSource* OGRCreateEmulatedTransactionDataSourceWrapper(
+                                OGRDataSource* poBaseDataSource,
+                                IOGRTransactionBehaviour* poTransactionBehaviour,
+                                int bTakeOwnershipDataSource,
+                                int bTakeOwnershipTransactionBehaviour)
+{
+    return new OGRDataSourceWithTransaction(poBaseDataSource,
+                                            poTransactionBehaviour,
+                                            bTakeOwnershipDataSource,
+                                            bTakeOwnershipTransactionBehaviour);
+}
+
+
+/************************************************************************/
+/*                      OGRDataSourceWithTransaction                    */
+/************************************************************************/
+
+OGRDataSourceWithTransaction::OGRDataSourceWithTransaction(
+                                OGRDataSource* poBaseDataSource,
+                                IOGRTransactionBehaviour* poTransactionBehaviour,
+                                int bTakeOwnershipDataSource,
+                                int bTakeOwnershipTransactionBehaviour) :
+            m_poBaseDataSource(poBaseDataSource),
+            m_poTransactionBehaviour(poTransactionBehaviour),
+            m_bHasOwnershipDataSource(bTakeOwnershipDataSource),
+            m_bHasOwnershipTransactionBehaviour(bTakeOwnershipTransactionBehaviour),
+            m_bInTransaction(FALSE)
+{
+}
+
+OGRDataSourceWithTransaction::~OGRDataSourceWithTransaction()
+{
+    std::set<OGRLayerWithTransaction*>::iterator oIter = m_oSetLayers.begin();
+    for(; oIter != m_oSetLayers.end(); ++oIter )
+        delete *oIter;
+
+    if( m_bHasOwnershipDataSource )
+        delete m_poBaseDataSource;
+    if( m_bHasOwnershipTransactionBehaviour )
+        delete m_poTransactionBehaviour;
+}
+
+
+OGRLayer* OGRDataSourceWithTransaction::WrapLayer(OGRLayer* poLayer)
+{
+    if( poLayer )
+    {
+        OGRLayer* poWrappedLayer = m_oMapLayers[poLayer->GetName()];
+        if( poWrappedLayer )
+            poLayer = poWrappedLayer;
+        else
+        {
+            OGRLayerWithTransaction* poWrappedLayer = new OGRLayerWithTransaction(this,poLayer);
+            m_oMapLayers[poLayer->GetName()] = poWrappedLayer;
+            m_oSetLayers.insert(poWrappedLayer);
+            poLayer = poWrappedLayer;
+        }
+    }
+    return poLayer;
+}
+
+void OGRDataSourceWithTransaction::RemapLayers()
+{
+    std::set<OGRLayerWithTransaction*>::iterator oIter = m_oSetLayers.begin();
+    for(; oIter != m_oSetLayers.end(); ++oIter )
+    {
+        OGRLayerWithTransaction* poWrappedLayer = *oIter;
+        if( m_poBaseDataSource == NULL )
+            poWrappedLayer->m_poDecoratedLayer = NULL;
+        else
+        {
+            OGRFeatureDefn* poOldFeatureDefn = poWrappedLayer->m_poFeatureDefn;
+            poWrappedLayer->m_poDecoratedLayer =
+                m_poBaseDataSource->GetLayerByName(poWrappedLayer->GetName());
+            if( poOldFeatureDefn != NULL )
+            {
+                if( poWrappedLayer->m_poDecoratedLayer != NULL )
+                {
+#ifdef DEBUG
+                    int nRefCount = poOldFeatureDefn->GetReferenceCount();
+#endif
+                    m_poTransactionBehaviour->ReadoptOldFeatureDefn(m_poBaseDataSource,
+                                                                    poWrappedLayer->m_poDecoratedLayer,
+                                                                    poOldFeatureDefn);
+#ifdef DEBUG
+                    CPLAssert(poWrappedLayer->m_poDecoratedLayer->GetLayerDefn() == poOldFeatureDefn);
+                    CPLAssert(poOldFeatureDefn->GetReferenceCount() == nRefCount + 1 );
+#endif
+                }
+            }
+        }
+    }
+    m_oMapLayers.clear();
+}
+
+const char  *OGRDataSourceWithTransaction::GetName()
+{
+    if( !m_poBaseDataSource ) return "";
+    return m_poBaseDataSource->GetName();
+}
+
+int         OGRDataSourceWithTransaction::GetLayerCount()
+{
+    if( !m_poBaseDataSource ) return 0;
+    return m_poBaseDataSource->GetLayerCount();
+}
+
+OGRLayer    *OGRDataSourceWithTransaction::GetLayer(int iIndex)
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return WrapLayer(m_poBaseDataSource->GetLayer(iIndex));
+    
+}
+
+OGRLayer    *OGRDataSourceWithTransaction::GetLayerByName(const char *pszName)
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return WrapLayer(m_poBaseDataSource->GetLayerByName(pszName));
+}
+
+OGRErr      OGRDataSourceWithTransaction::DeleteLayer(int iIndex)
+{
+    if( !m_poBaseDataSource ) return OGRERR_FAILURE;
+    OGRLayer* poLayer = GetLayer(iIndex);
+    CPLString osName;
+    if( poLayer )
+        osName = poLayer->GetName();
+    OGRErr eErr = m_poBaseDataSource->DeleteLayer(iIndex);
+    if( eErr == OGRERR_NONE && osName.size())
+    {
+        std::map<CPLString, OGRLayerWithTransaction*>::iterator oIter = m_oMapLayers.find(osName);
+        if(oIter != m_oMapLayers.end())
+        {
+            delete oIter->second;
+            m_oSetLayers.erase(oIter->second);
+            m_oMapLayers.erase(oIter);
+        }
+    }
+    return eErr;
+}
+
+int         OGRDataSourceWithTransaction::TestCapability( const char * pszCap )
+{
+    if( !m_poBaseDataSource ) return FALSE;
+
+    if( EQUAL(pszCap,ODsCEmulatedTransactions) )
+        return TRUE;
+
+    return m_poBaseDataSource->TestCapability(pszCap);
+}
+
+OGRLayer   *OGRDataSourceWithTransaction::ICreateLayer( const char *pszName, 
+                                     OGRSpatialReference *poSpatialRef,
+                                     OGRwkbGeometryType eGType,
+                                     char ** papszOptions)
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return WrapLayer(m_poBaseDataSource->CreateLayer(pszName, poSpatialRef, eGType, papszOptions));
+}
+
+OGRLayer   *OGRDataSourceWithTransaction::CopyLayer( OGRLayer *poSrcLayer, 
+                                   const char *pszNewName, 
+                                   char **papszOptions )
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return WrapLayer(m_poBaseDataSource->CopyLayer(poSrcLayer, pszNewName, papszOptions ));
+}
+
+OGRStyleTable *OGRDataSourceWithTransaction::GetStyleTable()
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return m_poBaseDataSource->GetStyleTable();
+}
+
+void        OGRDataSourceWithTransaction::SetStyleTableDirectly( OGRStyleTable *poStyleTable )
+{
+    if( !m_poBaseDataSource ) return;
+    m_poBaseDataSource->SetStyleTableDirectly(poStyleTable);
+}
+
+void        OGRDataSourceWithTransaction::SetStyleTable(OGRStyleTable *poStyleTable)
+{
+    if( !m_poBaseDataSource ) return;
+    m_poBaseDataSource->SetStyleTable(poStyleTable);
+}
+
+OGRLayer *  OGRDataSourceWithTransaction::ExecuteSQL( const char *pszStatement,
+                                    OGRGeometry *poSpatialFilter,
+                                    const char *pszDialect )
+{
+    if( !m_poBaseDataSource ) return NULL;
+    OGRLayer* poLayer = m_poBaseDataSource->ExecuteSQL(pszStatement, poSpatialFilter,
+                                                       pszDialect);
+    if( poLayer != NULL )
+        m_oSetExecuteSQLLayers.insert(poLayer);
+    return poLayer;
+}
+
+void        OGRDataSourceWithTransaction::ReleaseResultSet( OGRLayer * poResultsSet )
+{
+    if( !m_poBaseDataSource ) return;
+    m_oSetExecuteSQLLayers.erase(poResultsSet);
+    m_poBaseDataSource->ReleaseResultSet(poResultsSet);
+}
+
+void      OGRDataSourceWithTransaction::FlushCache()
+{
+    if( !m_poBaseDataSource ) return;
+    return m_poBaseDataSource->FlushCache();
+}
+
+OGRErr OGRDataSourceWithTransaction::StartTransaction(int bForce)
+{
+    if( !m_poBaseDataSource ) return OGRERR_FAILURE;
+    if( !bForce )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Transactions only supported in forced mode");
+        return OGRERR_UNSUPPORTED_OPERATION;
+    }
+    if( m_oSetExecuteSQLLayers.size() != 0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot start transaction while a layer returned by "
+                 "ExecuteSQL() hasn't been released.");
+        return OGRERR_FAILURE;
+    }
+    if( m_bInTransaction )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Transaction is already in progress");
+        return OGRERR_FAILURE;
+    }
+    int bHasReopenedDS = FALSE;
+    OGRErr eErr =
+        m_poTransactionBehaviour->StartTransaction(m_poBaseDataSource, bHasReopenedDS);
+    if( bHasReopenedDS )
+        RemapLayers();
+    if( eErr == OGRERR_NONE )
+        m_bInTransaction = TRUE;
+    return eErr;
+}
+
+OGRErr OGRDataSourceWithTransaction::CommitTransaction()
+{
+    if( !m_poBaseDataSource ) return OGRERR_FAILURE;
+    if( !m_bInTransaction )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "No transaction in progress");
+        return OGRERR_FAILURE;
+    }
+    if( m_oSetExecuteSQLLayers.size() != 0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot interrupt transaction while a layer returned by "
+                 "ExecuteSQL() hasn't been released.");
+        return OGRERR_FAILURE;
+    }
+    m_bInTransaction = FALSE;
+    int bHasReopenedDS = FALSE;
+    OGRErr eErr =
+        m_poTransactionBehaviour->CommitTransaction(m_poBaseDataSource, bHasReopenedDS);
+    if( bHasReopenedDS )
+        RemapLayers();
+    return eErr;
+}
+
+OGRErr OGRDataSourceWithTransaction::RollbackTransaction()
+{
+    if( !m_poBaseDataSource ) return OGRERR_FAILURE;
+    if( !m_bInTransaction )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "No transaction in progress");
+        return OGRERR_FAILURE;
+    }
+    if( m_oSetExecuteSQLLayers.size() != 0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot interrupt transaction while a layer returned by "
+                 "ExecuteSQL() hasn't been released.");
+        return OGRERR_FAILURE;
+    }
+    m_bInTransaction = FALSE;
+    int bHasReopenedDS = FALSE;
+    OGRErr eErr =
+        m_poTransactionBehaviour->RollbackTransaction(m_poBaseDataSource, bHasReopenedDS);
+    if( bHasReopenedDS )
+        RemapLayers();
+    return eErr;
+}
+
+char      **OGRDataSourceWithTransaction::GetMetadata( const char * pszDomain )
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return m_poBaseDataSource->GetMetadata(pszDomain);
+}
+
+CPLErr      OGRDataSourceWithTransaction::SetMetadata( char ** papszMetadata,
+                                          const char * pszDomain )
+{
+    if( !m_poBaseDataSource ) return CE_Failure;
+    return m_poBaseDataSource->SetMetadata(papszMetadata, pszDomain);
+}
+
+const char *OGRDataSourceWithTransaction::GetMetadataItem( const char * pszName,
+                                              const char * pszDomain )
+{
+    if( !m_poBaseDataSource ) return NULL;
+    return m_poBaseDataSource->GetMetadataItem(pszName, pszDomain);
+}
+
+CPLErr      OGRDataSourceWithTransaction::SetMetadataItem( const char * pszName,
+                                              const char * pszValue,
+                                              const char * pszDomain )
+{
+    if( !m_poBaseDataSource ) return CE_Failure;
+    return m_poBaseDataSource->SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+
+/************************************************************************/
+/*                       OGRLayerWithTransaction                        */
+/************************************************************************/
+
+OGRLayerWithTransaction::OGRLayerWithTransaction(
+                    OGRDataSourceWithTransaction* poDS, OGRLayer* poBaseLayer):
+    OGRLayerDecorator(poBaseLayer, FALSE),
+    m_poDS(poDS),
+    m_poFeatureDefn(NULL)
+{
+}
+
+OGRLayerWithTransaction::~OGRLayerWithTransaction()
+{
+    if( m_poFeatureDefn )
+        m_poFeatureDefn->Release();
+}
+
+OGRFeatureDefn *OGRLayerWithTransaction::GetLayerDefn()
+{
+    if( !m_poDecoratedLayer )
+    {
+        if( m_poFeatureDefn == NULL )
+        {
+            m_poFeatureDefn = new OGRFeatureDefn(GetDescription());
+            m_poFeatureDefn->Reference();
+        }
+        return m_poFeatureDefn;
+    }
+    if( m_poFeatureDefn == NULL )
+    {
+        m_poFeatureDefn = m_poDecoratedLayer->GetLayerDefn();
+        if( m_poFeatureDefn )
+            m_poFeatureDefn->Reference();
+    }
+    return m_poFeatureDefn;
+}
+
+OGRErr      OGRLayerWithTransaction::CreateField( OGRFieldDefn *poField,
+                                            int bApproxOK )
+{
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
+    if( m_poFeatureDefn != NULL && m_poDS->IsInTransaction() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Layer structural changes not allowed within emulated transaction");
+        return OGRERR_FAILURE;
+    }
+    return m_poDecoratedLayer->CreateField(poField, bApproxOK);
+}
+
+OGRErr      OGRLayerWithTransaction::DeleteField( int iField )
+{
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
+    if( m_poFeatureDefn != NULL && m_poDS->IsInTransaction() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Layer structural changes not allowed within emulated transaction");
+        return OGRERR_FAILURE;
+    }
+    return m_poDecoratedLayer->DeleteField(iField);
+}
+
+OGRErr      OGRLayerWithTransaction::ReorderFields( int* panMap )
+{
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
+    if( m_poFeatureDefn != NULL && m_poDS->IsInTransaction() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Layer structural changes not allowed within emulated transaction");
+        return OGRERR_FAILURE;
+    }
+    return m_poDecoratedLayer->ReorderFields(panMap);
+}
+
+OGRErr      OGRLayerWithTransaction::AlterFieldDefn( int iField,
+                                                     OGRFieldDefn* poNewFieldDefn,
+                                                     int nFlags )
+{
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
+    if( m_poFeatureDefn != NULL && m_poDS->IsInTransaction() )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Layer structural changes not allowed within emulated transaction");
+        return OGRERR_FAILURE;
+    }
+    return m_poDecoratedLayer->AlterFieldDefn(iField, poNewFieldDefn, nFlags);
+}
+
diff --git a/ogr/ogrsf_frmts/generic/ogremulatedtransaction.h b/ogr/ogrsf_frmts/generic/ogremulatedtransaction.h
new file mode 100644
index 0000000..0127251
--- /dev/null
+++ b/ogr/ogrsf_frmts/generic/ogremulatedtransaction.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  OpenGIS Simple Features Reference Implementation
+ * Purpose:  Defines OGRDataSourceWithTransaction class
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGREMULATEDTRANSACTION_H_INCLUDED
+#define _OGREMULATEDTRANSACTION_H_INCLUDED
+
+#include "ogrsf_frmts.h"
+
+/** IOGRTransactionBehaviour is an interface that a driver must implement
+ *  to provide emulation of transactions.
+ *
+ * @since GDAL 2.0
+ */
+class CPL_DLL IOGRTransactionBehaviour
+{
+    public:
+        virtual ~IOGRTransactionBehaviour();
+
+        /** Start a transaction.
+        *
+        * The implementation may update the poDSInOut reference by closing
+        * and reopening the datasource (or assigning it to NULL in case of error).
+        * In which case bOutHasReopenedDS must be set to TRUE.
+        *
+        * The implementation can for example backup the existing files/directories
+        * that compose the current datasource.
+        *
+        * @param poDSInOut datasource handle that may be modified
+        * @param bOutHasReopenedDS output boolean to indicate if datasource has been closed
+        * @return OGRERR_NONE in case of success
+        */
+       virtual OGRErr StartTransaction(OGRDataSource*& poDSInOut,
+                                       int& bOutHasReopenedDS) = 0;
+
+        /** Commit a transaction.
+        *
+        * The implementation may update the poDSInOut reference by closing
+        * and reopening the datasource (or assigning it to NULL in case of error).
+        * In which case bOutHasReopenedDS must be set to TRUE.
+        *
+        * The implementation can for example remove the backup it may have done
+        * at StartTransaction() time.
+        *
+        * @param poDSInOut datasource handle that may be modified
+        * @param bOutHasReopenedDS output boolean to indicate if datasource has been closed
+        * @return OGRERR_NONE in case of success
+        */
+       virtual OGRErr CommitTransaction(OGRDataSource*& poDSInOut,
+                                        int& bOutHasReopenedDS) = 0;
+
+        /** Rollback a transaction.
+        *
+        * The implementation may update the poDSInOut reference by closing
+        * and reopening the datasource (or assigning it to NULL in case of error).
+        * In which case bOutHasReopenedDS must be set to TRUE.
+        *
+        * The implementation can for example restore the backup it may have done
+        * at StartTransaction() time.
+        *
+        * @param poDSInOut datasource handle that may be modified
+        * @param bOutHasReopenedDS output boolean to indicate if datasource has been closed
+        * @return OGRERR_NONE in case of success
+        */
+       virtual OGRErr RollbackTransaction(OGRDataSource*& poDSInOut,
+                                          int& bOutHasReopenedDS) = 0;
+
+        /** Ask a layer to re-"adopt" its previous feature definition object.
+        *
+        * The aim is that the user doesn't see visible object changes.
+        *
+        * This method is called if StartTransaction(), CommitTransaction() or
+        * RollbackTransaction() has closed and reopened a datasource.
+        *
+        * The implementation os the method should drop the reference to feature
+        * definition object it may have currently, assign the poFeatureDefn as
+        * its current definition object, and take a new reference on it.
+        *
+        * The passed poFeatureDefn object is supposed to be the "same" as
+        * the one the layer has currently (as verified with IsSame()) since
+        * the emulated datasource wrapper prevents layer structural modifications
+        * in cases where the user has already called GetLayerDefn()
+        */
+        virtual void   ReadoptOldFeatureDefn(OGRDataSource* poDS,
+                                            OGRLayer* poLayer,
+                                            OGRFeatureDefn* poFeatureDefn) = 0;    
+};
+
+
+/** Returns a new datasource object that adds transactional behaviour to an existing datasource.
+ * 
+ * The provided poTransactionBehaviour object should implement driver-specific
+ * behaviour for transactions.
+ *
+ * The generic mechanisms offered by the wrapper class do not cover concurrent
+ * updates (though different datasource connections) to the same datasource files.
+ *
+ * There are restrictions on what can be accomplished. For example it is not
+ * allowed to have a unreleased layer returned by ExecuteSQL() before calling
+ * StartTransaction(), CommitTransaction() or RollbackTransaction().
+ *
+ * Layer structural changes are not allowed after StartTransaction() if the
+ * layer definition object has been returned previously with GetLayerDefn().
+ *
+ * @param poBaseDataSource the datasource to which to add transactional behaviour.
+ * @param poTransactionBehaviour an implementation of the IOGRTransactionBehaviour interface.
+ * @param bTakeOwnershipDataSource whether the returned object should own the
+ *                                 passed poBaseDataSource (and thus destroy it
+ *                                 when it is destroyed itself).
+ * @param bTakeOwnershipTransactionBehaviour whether the returned object should own
+ *                                           the passed poTransactionBehaviour
+ *                                           (and thus destroy it when
+ *                                           it is destroyed itself).
+ * @return a new datasource handle
+ * @since GDAL 2.0
+ */
+OGRDataSource CPL_DLL* OGRCreateEmulatedTransactionDataSourceWrapper(
+                                OGRDataSource* poBaseDataSource,
+                                IOGRTransactionBehaviour* poTransactionBehaviour,
+                                int bTakeOwnershipDataSource,
+                                int bTakeOwnershipTransactionBehaviour);
+
+#endif // _OGREMULATEDTRANSACTION_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/generic/ogrlayer.cpp b/ogr/ogrsf_frmts/generic/ogrlayer.cpp
index d2eca8b..dee21a0 100644
--- a/ogr/ogrsf_frmts/generic/ogrlayer.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlayer.cpp 28169 2014-12-17 16:24:25Z rouault $
+ * $Id: ogrlayer.cpp 28928 2015-04-17 10:24:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The generic portions of the OGRSFLayer class.
@@ -33,8 +33,9 @@
 #include "ogr_p.h"
 #include "ogr_attrind.h"
 #include "swq.h"
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrlayer.cpp 28169 2014-12-17 16:24:25Z rouault $");
+CPL_CVSID("$Id: ogrlayer.cpp 28928 2015-04-17 10:24:19Z rouault $");
 
 /************************************************************************/
 /*                              OGRLayer()                              */
@@ -164,14 +165,14 @@ int OGR_L_GetRefCount( OGRLayerH hLayer )
 }
 
 /************************************************************************/
-/*                          GetFeatureCount()                           */
+/*                         GetFeatureCount()                            */
 /************************************************************************/
 
-int OGRLayer::GetFeatureCount( int bForce )
+GIntBig OGRLayer::GetFeatureCount( int bForce )
 
 {
     OGRFeature     *poFeature;
-    int            nFeatureCount = 0;
+    GIntBig         nFeatureCount = 0;
 
     if( !bForce )
         return -1;
@@ -188,13 +189,18 @@ int OGRLayer::GetFeatureCount( int bForce )
 }
 
 /************************************************************************/
-/*                       OGR_L_GetFeatureCount()                        */
+/*                      OGR_L_GetFeatureCount()                         */
 /************************************************************************/
 
-int OGR_L_GetFeatureCount( OGRLayerH hLayer, int bForce )
+GIntBig OGR_L_GetFeatureCount( OGRLayerH hLayer, int bForce )
 
 {
-    VALIDATE_POINTER1( hLayer, "OGR_L_GetFeature", 0 );
+    VALIDATE_POINTER1( hLayer, "OGR_L_GetFeatureCount", 0 );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
+#endif
 
     return ((OGRLayer *) hLayer)->GetFeatureCount(bForce);
 }
@@ -267,7 +273,11 @@ OGRErr OGRLayer::GetExtentInternal(int iGeomField, OGREnvelope *psExtent, int bF
         else if (!bExtentSet)
         {
             poGeom->getEnvelope(psExtent);
-            bExtentSet = TRUE;
+            if( !(CPLIsNan(psExtent->MinX) || CPLIsNan(psExtent->MinY) ||
+                  CPLIsNan(psExtent->MaxX) || CPLIsNan(psExtent->MaxY)) )
+            {
+                bExtentSet = TRUE;
+            }
         }
         else
         {
@@ -297,6 +307,11 @@ OGRErr OGR_L_GetExtent( OGRLayerH hLayer, OGREnvelope *psExtent, int bForce )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetExtent(hLayer, bForce);
+#endif
+
     return ((OGRLayer *) hLayer)->GetExtent( psExtent, bForce );
 }
 
@@ -310,6 +325,11 @@ OGRErr OGR_L_GetExtentEx( OGRLayerH hLayer, int iGeomField,
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
+#endif
+
     return ((OGRLayer *) hLayer)->GetExtent( iGeomField, psExtent, bForce );
 }
 
@@ -396,7 +416,7 @@ int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
     if( !m_poAttrQuery )
         return FALSE;
 
-    swq_expr_node* expr = (swq_expr_node *) m_poAttrQuery->GetSWGExpr();
+    swq_expr_node* expr = (swq_expr_node *) m_poAttrQuery->GetSWQExpr();
     int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
 
     return ContainGeomSpecialField(expr, nLayerFieldCount);
@@ -411,6 +431,11 @@ OGRErr OGR_L_SetAttributeFilter( OGRLayerH hLayer, const char *pszQuery )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_SetAttributeFilter", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
+#endif
+
     return ((OGRLayer *) hLayer)->SetAttributeFilter( pszQuery );
 }
 
@@ -418,7 +443,7 @@ OGRErr OGR_L_SetAttributeFilter( OGRLayerH hLayer, const char *pszQuery )
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRLayer::GetFeature( long nFID )
+OGRFeature *OGRLayer::GetFeature( GIntBig nFID )
 
 {
     OGRFeature *poFeature;
@@ -453,11 +478,16 @@ OGRFeature *OGRLayer::GetFeature( long nFID )
 /*                          OGR_L_GetFeature()                          */
 /************************************************************************/
 
-OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, long nFeatureId )
+OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, GIntBig nFeatureId )
 
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetFeature", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
+#endif
+
     return (OGRFeatureH) ((OGRLayer *)hLayer)->GetFeature( nFeatureId );
 }
 
@@ -465,7 +495,7 @@ OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, long nFeatureId )
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr OGRLayer::SetNextByIndex( long nIndex )
+OGRErr OGRLayer::SetNextByIndex( GIntBig nIndex )
 
 {
     OGRFeature *poFeature;
@@ -490,11 +520,16 @@ OGRErr OGRLayer::SetNextByIndex( long nIndex )
 /*                        OGR_L_SetNextByIndex()                        */
 /************************************************************************/
 
-OGRErr OGR_L_SetNextByIndex( OGRLayerH hLayer, long nIndex )
+OGRErr OGR_L_SetNextByIndex( OGRLayerH hLayer, GIntBig nIndex )
 
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
+#endif
+
     return ((OGRLayer *)hLayer)->SetNextByIndex( nIndex );
 }
 
@@ -507,14 +542,52 @@ OGRFeatureH OGR_L_GetNextFeature( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetNextFeature", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetNextFeature(hLayer);
+#endif
+
     return (OGRFeatureH) ((OGRLayer *)hLayer)->GetNextFeature();
 }
 
 /************************************************************************/
+/*                    ConvertNonLinearGeomsIfNecessary()                */
+/************************************************************************/
+
+void OGRLayer::ConvertNonLinearGeomsIfNecessary( OGRFeature *poFeature )
+{
+    if( !TestCapability(OLCCurveGeometries) )
+    {
+        int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
+        for(int i=0;i<nGeomFieldCount;i++)
+        {
+            OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
+            if( poGeom != NULL && OGR_GT_IsNonLinear(poGeom->getGeometryType()) )
+            {
+                OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(poGeom->getGeometryType());
+                poFeature->SetGeomFieldDirectly(i,
+                    OGRGeometryFactory::forceTo(poFeature->StealGeometry(i), eTargetType));
+            }
+        }
+    }
+}
+
+/************************************************************************/
 /*                             SetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRLayer::SetFeature( OGRFeature * )
+OGRErr OGRLayer::SetFeature( OGRFeature *poFeature )
+
+{
+    ConvertNonLinearGeomsIfNecessary(poFeature);
+    return ISetFeature(poFeature);
+}
+
+/************************************************************************/
+/*                             ISetFeature()                            */
+/************************************************************************/
+
+OGRErr OGRLayer::ISetFeature( OGRFeature * )
 
 {
     return OGRERR_UNSUPPORTED_OPERATION;
@@ -530,6 +603,11 @@ OGRErr OGR_L_SetFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
     VALIDATE_POINTER1( hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE );
     VALIDATE_POINTER1( hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetFeature(hLayer, hFeat);
+#endif
+
     return ((OGRLayer *)hLayer)->SetFeature( (OGRFeature *) hFeat );
 }
 
@@ -537,34 +615,39 @@ OGRErr OGR_L_SetFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
 /*                           CreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRLayer::CreateFeature( OGRFeature * )
+OGRErr OGRLayer::CreateFeature( OGRFeature *poFeature )
 
 {
-    return OGRERR_UNSUPPORTED_OPERATION;
+    ConvertNonLinearGeomsIfNecessary(poFeature);
+    return ICreateFeature(poFeature);
 }
 
 /************************************************************************/
-/*                        OGR_L_CreateFeature()                         */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGR_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
+OGRErr OGRLayer::ICreateFeature( OGRFeature * )
 
 {
-    VALIDATE_POINTER1( hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
-    VALIDATE_POINTER1( hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
-
-    return ((OGRLayer *) hLayer)->CreateFeature( (OGRFeature *) hFeat );
+    return OGRERR_UNSUPPORTED_OPERATION;
 }
 
 /************************************************************************/
-/*                              GetInfo()                               */
+/*                        OGR_L_CreateFeature()                         */
 /************************************************************************/
 
-const char *OGRLayer::GetInfo( const char * pszTag )
+OGRErr OGR_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
 
 {
-    (void) pszTag;
-    return NULL;
+    VALIDATE_POINTER1( hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
+    VALIDATE_POINTER1( hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_CreateFeature(hLayer, hFeat);
+#endif
+
+    return ((OGRLayer *) hLayer)->CreateFeature( (OGRFeature *) hFeat );
 }
 
 /************************************************************************/
@@ -594,6 +677,11 @@ OGRErr OGR_L_CreateField( OGRLayerH hLayer, OGRFieldDefnH hField,
     VALIDATE_POINTER1( hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE );
     VALIDATE_POINTER1( hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
+#endif
+
     return ((OGRLayer *) hLayer)->CreateField( (OGRFieldDefn *) hField, 
                                                bApproxOK );
 }
@@ -622,6 +710,11 @@ OGRErr OGR_L_DeleteField( OGRLayerH hLayer, int iField )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_DeleteField(hLayer, iField);
+#endif
+
     return ((OGRLayer *) hLayer)->DeleteField( iField );
 }
 
@@ -649,6 +742,11 @@ OGRErr OGR_L_ReorderFields( OGRLayerH hLayer, int* panMap )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_ReorderFields(hLayer, panMap);
+#endif
+
     return ((OGRLayer *) hLayer)->ReorderFields( panMap );
 }
 
@@ -719,6 +817,11 @@ OGRErr OGR_L_ReorderField( OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
+#endif
+
     return ((OGRLayer *) hLayer)->ReorderField( iOldFieldPos, iNewFieldPos );
 }
 
@@ -751,6 +854,11 @@ OGRErr OGR_L_AlterFieldDefn( OGRLayerH hLayer, int iField, OGRFieldDefnH hNewFie
     VALIDATE_POINTER1( hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE );
     VALIDATE_POINTER1( hNewFieldDefn, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
+#endif
+
     return ((OGRLayer *) hLayer)->AlterFieldDefn( iField, (OGRFieldDefn*) hNewFieldDefn, nFlags );
 }
 
@@ -781,6 +889,11 @@ OGRErr OGR_L_CreateGeomField( OGRLayerH hLayer, OGRGeomFieldDefnH hField,
     VALIDATE_POINTER1( hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE );
     VALIDATE_POINTER1( hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
+#endif
+
     return ((OGRLayer *) hLayer)->CreateGeomField( (OGRGeomFieldDefn *) hField, 
                                                    bApproxOK );
 }
@@ -804,6 +917,11 @@ OGRErr OGR_L_StartTransaction( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_StartTransaction(hLayer);
+#endif
+
     return ((OGRLayer *)hLayer)->StartTransaction();
 }
 
@@ -826,6 +944,11 @@ OGRErr OGR_L_CommitTransaction( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_CommitTransaction(hLayer);
+#endif
+
     return ((OGRLayer *)hLayer)->CommitTransaction();
 }
 
@@ -848,6 +971,11 @@ OGRErr OGR_L_RollbackTransaction( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_RollbackTransaction", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_RollbackTransaction(hLayer);
+#endif
+
     return ((OGRLayer *)hLayer)->RollbackTransaction();
 }
 
@@ -860,6 +988,11 @@ OGRFeatureDefnH OGR_L_GetLayerDefn( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetLayerDefn", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetLayerDefn(hLayer);
+#endif
+
     return (OGRFeatureDefnH) ((OGRLayer *)hLayer)->GetLayerDefn();
 }
 
@@ -872,6 +1005,11 @@ int OGR_L_FindFieldIndex( OGRLayerH hLayer, const char *pszFieldName, int bExact
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_FindFieldIndex", -1 );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
+#endif
+
     return ((OGRLayer *)hLayer)->FindFieldIndex( pszFieldName, bExactMatch );
 }
 
@@ -905,6 +1043,11 @@ OGRSpatialReferenceH OGR_L_GetSpatialRef( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetSpatialRef", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetSpatialRef(hLayer);
+#endif
+
     return (OGRSpatialReferenceH) ((OGRLayer *) hLayer)->GetSpatialRef();
 }
 
@@ -918,6 +1061,11 @@ int OGR_L_TestCapability( OGRLayerH hLayer, const char *pszCap )
     VALIDATE_POINTER1( hLayer, "OGR_L_TestCapability", 0 );
     VALIDATE_POINTER1( pszCap, "OGR_L_TestCapability", 0 );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_TestCapability(hLayer, pszCap);
+#endif
+
     return ((OGRLayer *) hLayer)->TestCapability( pszCap );
 }
 
@@ -940,6 +1088,11 @@ OGRGeometryH OGR_L_GetSpatialFilter( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetSpatialFilter", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetSpatialFilter(hLayer);
+#endif
+
     return (OGRGeometryH) ((OGRLayer *) hLayer)->GetSpatialFilter();
 }
 
@@ -988,6 +1141,11 @@ void OGR_L_SetSpatialFilter( OGRLayerH hLayer, OGRGeometryH hGeom )
 {
     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilter" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
+#endif
+
     ((OGRLayer *) hLayer)->SetSpatialFilter( (OGRGeometry *) hGeom );
 }
 
@@ -1001,6 +1159,11 @@ void OGR_L_SetSpatialFilterEx( OGRLayerH hLayer, int iGeomField,
 {
     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterEx" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
+#endif
+
     ((OGRLayer *) hLayer)->SetSpatialFilter( iGeomField, (OGRGeometry *) hGeom );
 }
 /************************************************************************/
@@ -1049,6 +1212,11 @@ void OGR_L_SetSpatialFilterRect( OGRLayerH hLayer,
 {
     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterRect" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX, dfMaxY);
+#endif
+
     ((OGRLayer *) hLayer)->SetSpatialFilterRect( dfMinX, dfMinY, 
                                                  dfMaxX, dfMaxY );
 }
@@ -1065,6 +1233,11 @@ void OGR_L_SetSpatialFilterRectEx( OGRLayerH hLayer,
 {
     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterRectEx" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY, dfMaxX, dfMaxY);
+#endif
+
     ((OGRLayer *) hLayer)->SetSpatialFilterRect( iGeomField,
                                                  dfMinX, dfMinY, 
                                                  dfMaxX, dfMaxY );
@@ -1289,6 +1462,11 @@ void OGR_L_ResetReading( OGRLayerH hLayer )
 {
     VALIDATE_POINTER0( hLayer, "OGR_L_ResetReading" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_ResetReading(hLayer);
+#endif
+
     ((OGRLayer *) hLayer)->ResetReading();
 }
 
@@ -1334,20 +1512,24 @@ OGRErr OGRLayer::SyncToDisk()
 /*                          OGR_L_SyncToDisk()                          */
 /************************************************************************/
 
-OGRErr OGR_L_SyncToDisk( OGRLayerH hDS )
+OGRErr OGR_L_SyncToDisk( OGRLayerH hLayer )
 
 {
-    VALIDATE_POINTER1( hDS, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE );
+    VALIDATE_POINTER1( hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE );
+
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SyncToDisk(hLayer);
+#endif
 
-    return ((OGRLayer *) hDS)->SyncToDisk();
+    return ((OGRLayer *) hLayer)->SyncToDisk();
 }
 
 /************************************************************************/
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRLayer::DeleteFeature( CPL_UNUSED long nFID )
-
+OGRErr OGRLayer::DeleteFeature( CPL_UNUSED GIntBig nFID )
 {
     return OGRERR_UNSUPPORTED_OPERATION;
 }
@@ -1356,12 +1538,17 @@ OGRErr OGRLayer::DeleteFeature( CPL_UNUSED long nFID )
 /*                        OGR_L_DeleteFeature()                         */
 /************************************************************************/
 
-OGRErr OGR_L_DeleteFeature( OGRLayerH hDS, long nFID )
+OGRErr OGR_L_DeleteFeature( OGRLayerH hLayer, GIntBig nFID )
 
 {
-    VALIDATE_POINTER1( hDS, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE );
+    VALIDATE_POINTER1( hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE );
 
-    return ((OGRLayer *) hDS)->DeleteFeature( nFID );
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_DeleteFeature(hLayer, nFID);
+#endif
+
+    return ((OGRLayer *) hLayer)->DeleteFeature( nFID );
 }
 
 /************************************************************************/
@@ -1405,6 +1592,11 @@ const char *OGR_L_GetFIDColumn( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetFIDColumn", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetFIDColumn(hLayer);
+#endif
+
     return ((OGRLayer *) hLayer)->GetFIDColumn();
 }
 
@@ -1430,6 +1622,11 @@ const char *OGR_L_GetGeometryColumn( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetGeometryColumn", NULL );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetGeometryColumn(hLayer);
+#endif
+
     return ((OGRLayer *) hLayer)->GetGeometryColumn();
 }
 
@@ -1523,6 +1720,11 @@ const char* OGR_L_GetName( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetName", "" );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetName(hLayer);
+#endif
+
     return ((OGRLayer *) hLayer)->GetName();
 }
 
@@ -1532,8 +1734,15 @@ const char* OGR_L_GetName( OGRLayerH hLayer )
 
 OGRwkbGeometryType OGRLayer::GetGeomType()
 {
-    return GetLayerDefn()->GetGeomType();
+    OGRFeatureDefn* poLayerDefn = GetLayerDefn();
+    if( poLayerDefn == NULL )
+    {
+        CPLDebug("OGR", "GetLayerType() returns NULL !");
+        return wkbUnknown;
+    }
+    return poLayerDefn->GetGeomType();
 }
+
 /************************************************************************/
 /*                         OGR_L_GetGeomType()                          */
 /************************************************************************/
@@ -1543,7 +1752,17 @@ OGRwkbGeometryType OGR_L_GetGeomType( OGRLayerH hLayer )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_GetGeomType", wkbUnknown );
 
-    return ((OGRLayer *) hLayer)->GetGeomType();
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_GetGeomType(hLayer);
+#endif
+
+    OGRwkbGeometryType eType = ((OGRLayer *) hLayer)->GetGeomType();
+    if( OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag() )
+    {
+        eType = OGR_GT_GetLinear(eType);
+    }
+    return eType;
 }
 
 /************************************************************************/
@@ -1607,6 +1826,11 @@ OGRErr OGR_L_SetIgnoredFields( OGRLayerH hLayer, const char **papszFields )
 {
     VALIDATE_POINTER1( hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE );
 
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
+#endif
+
     return ((OGRLayer *) hLayer)->SetIgnoredFields( papszFields );
 }
 
@@ -1804,7 +2028,7 @@ OGRErr OGRLayer::Intersection( OGRLayer *pLayerMethod,
     int *mapMethod = NULL;
     OGREnvelope sEnvelopeMethod;
     GBool bEnvelopeSet;
-    double progress_max = GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -2069,7 +2293,7 @@ OGRErr OGRLayer::Union( OGRLayer *pLayerMethod,
     OGRGeometry *pGeometryInputFilter = NULL;
     int *mapInput = NULL;
     int *mapMethod = NULL;
-    double progress_max = GetFeatureCount(0) + pLayerMethod->GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0) + (double) pLayerMethod->GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -2413,7 +2637,7 @@ OGRErr OGRLayer::SymDifference( OGRLayer *pLayerMethod,
     OGRGeometry *pGeometryInputFilter = NULL;
     int *mapInput = NULL;
     int *mapMethod = NULL;
-    double progress_max = GetFeatureCount(0) + pLayerMethod->GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0) + (double) pLayerMethod->GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -2723,7 +2947,7 @@ OGRErr OGRLayer::Identity( OGRLayer *pLayerMethod,
     OGRGeometry *pGeometryMethodFilter = NULL;
     int *mapInput = NULL;
     int *mapMethod = NULL;
-    double progress_max = GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -2997,7 +3221,7 @@ OGRErr OGRLayer::Update( OGRLayer *pLayerMethod,
     OGRGeometry *pGeometryMethodFilter = NULL;
     int *mapInput = NULL;
     int *mapMethod = NULL;
-    double progress_max = GetFeatureCount(0) + pLayerMethod->GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0) + (double) pLayerMethod->GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -3270,7 +3494,7 @@ OGRErr OGRLayer::Clip( OGRLayer *pLayerMethod,
     OGRFeatureDefn *poDefnResult = NULL;
     OGRGeometry *pGeometryMethodFilter = NULL;
     int *mapInput = NULL;
-    double progress_max = GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
@@ -3506,7 +3730,7 @@ OGRErr OGRLayer::Erase( OGRLayer *pLayerMethod,
     OGRFeatureDefn *poDefnResult = NULL;
     OGRGeometry *pGeometryMethodFilter = NULL;
     int *mapInput = NULL;
-    double progress_max = GetFeatureCount(0);
+    double progress_max = (double) GetFeatureCount(0);
     double progress_counter = 0;
     double progress_ticker = 0;
     int bSkipFailures = CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
diff --git a/ogr/ogrsf_frmts/generic/ogrlayerdecorator.cpp b/ogr/ogrsf_frmts/generic/ogrlayerdecorator.cpp
index 604df53..b697b32 100644
--- a/ogr/ogrsf_frmts/generic/ogrlayerdecorator.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrlayerdecorator.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlayerdecorator.cpp 27588 2014-08-18 20:57:46Z rouault $
+ * $Id: ogrlayerdecorator.cpp 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRLayerDecorator class
@@ -29,13 +29,14 @@
 
 #include "ogrlayerdecorator.h"
 
-CPL_CVSID("$Id: ogrlayerdecorator.cpp 27588 2014-08-18 20:57:46Z rouault $");
+CPL_CVSID("$Id: ogrlayerdecorator.cpp 28601 2015-03-03 11:06:40Z rouault $");
 
 OGRLayerDecorator::OGRLayerDecorator(OGRLayer* poDecoratedLayer,
                                      int bTakeOwnership) :
                                         m_poDecoratedLayer(poDecoratedLayer),
                                         m_bHasOwnership(bTakeOwnership)
 {
+    SetDescription( poDecoratedLayer->GetDescription() );
     CPLAssert(poDecoratedLayer != NULL);
 }
 
@@ -48,178 +49,241 @@ OGRLayerDecorator::~OGRLayerDecorator()
 
 OGRGeometry *OGRLayerDecorator::GetSpatialFilter()
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetSpatialFilter();
 }
 
 void        OGRLayerDecorator::SetSpatialFilter( OGRGeometry * poGeom )
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetSpatialFilter(poGeom);
 }
 
 void        OGRLayerDecorator::SetSpatialFilter( int iGeomField, OGRGeometry * poGeom )
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetSpatialFilter(iGeomField, poGeom);
 }
 
 void        OGRLayerDecorator::SetSpatialFilterRect( double dfMinX, double dfMinY,
                                   double dfMaxX, double dfMaxY )
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX, dfMaxY);
 }
 
 void        OGRLayerDecorator::SetSpatialFilterRect( int iGeomField, double dfMinX, double dfMinY,
                                   double dfMaxX, double dfMaxY )
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetSpatialFilterRect(iGeomField, dfMinX, dfMinY, dfMaxX, dfMaxY);
 }
 
 OGRErr      OGRLayerDecorator::SetAttributeFilter( const char * poAttrFilter )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->SetAttributeFilter(poAttrFilter);
 }
 
 void        OGRLayerDecorator::ResetReading()
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->ResetReading();
 }
 
 OGRFeature *OGRLayerDecorator::GetNextFeature()
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetNextFeature();
 }
 
-OGRErr      OGRLayerDecorator::SetNextByIndex( long nIndex )
+OGRErr      OGRLayerDecorator::SetNextByIndex( GIntBig nIndex )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->SetNextByIndex(nIndex);
 }
 
-OGRFeature *OGRLayerDecorator::GetFeature( long nFID )
+OGRFeature *OGRLayerDecorator::GetFeature( GIntBig nFID )
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetFeature(nFID);
 }
 
-OGRErr      OGRLayerDecorator::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRLayerDecorator::ISetFeature( OGRFeature *poFeature )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->SetFeature(poFeature);
 }
 
-OGRErr      OGRLayerDecorator::CreateFeature( OGRFeature *poFeature )
+OGRErr      OGRLayerDecorator::ICreateFeature( OGRFeature *poFeature )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->CreateFeature(poFeature);
 }
 
-OGRErr      OGRLayerDecorator::DeleteFeature( long nFID )
+OGRErr      OGRLayerDecorator::DeleteFeature( GIntBig nFID )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->DeleteFeature(nFID);
 }
 
-const char *OGRLayerDecorator::GetName()
+const char* OGRLayerDecorator::GetName()
 {
+    if( !m_poDecoratedLayer ) return GetDescription();
     return m_poDecoratedLayer->GetName();
 }
 
 OGRwkbGeometryType OGRLayerDecorator::GetGeomType()
 {
+    if( !m_poDecoratedLayer ) return wkbNone;
     return m_poDecoratedLayer->GetGeomType();
 }
 
 OGRFeatureDefn *OGRLayerDecorator::GetLayerDefn()
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetLayerDefn();
 }
 
 OGRSpatialReference *OGRLayerDecorator::GetSpatialRef()
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetSpatialRef();
 }
 
-int         OGRLayerDecorator::GetFeatureCount( int bForce )
+GIntBig         OGRLayerDecorator::GetFeatureCount( int bForce )
 {
+    if( !m_poDecoratedLayer ) return 0;
     return m_poDecoratedLayer->GetFeatureCount(bForce);
 }
 
 OGRErr      OGRLayerDecorator::GetExtent(OGREnvelope *psExtent, int bForce)
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->GetExtent(psExtent, bForce);
 }
 
 OGRErr      OGRLayerDecorator::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->GetExtent(iGeomField, psExtent, bForce);
 }
 
 int         OGRLayerDecorator::TestCapability( const char * pszCapability )
 {
+    if( !m_poDecoratedLayer ) return FALSE;
     return m_poDecoratedLayer->TestCapability(pszCapability);
 }
 
 OGRErr      OGRLayerDecorator::CreateField( OGRFieldDefn *poField,
                                             int bApproxOK )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->CreateField(poField, bApproxOK);
 }
 
 OGRErr      OGRLayerDecorator::DeleteField( int iField )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->DeleteField(iField);
 }
 
 OGRErr      OGRLayerDecorator::ReorderFields( int* panMap )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->ReorderFields(panMap);
 }
 
 OGRErr      OGRLayerDecorator::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->AlterFieldDefn(iField, poNewFieldDefn, nFlags);
 }
 
 OGRErr      OGRLayerDecorator::SyncToDisk()
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->SyncToDisk();
 }
 
 OGRStyleTable *OGRLayerDecorator::GetStyleTable()
 {
+    if( !m_poDecoratedLayer ) return NULL;
     return m_poDecoratedLayer->GetStyleTable();
 }
 
 void        OGRLayerDecorator::SetStyleTableDirectly( OGRStyleTable *poStyleTable )
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetStyleTableDirectly(poStyleTable);
 }
 
 void        OGRLayerDecorator::SetStyleTable(OGRStyleTable *poStyleTable)
 {
+    if( !m_poDecoratedLayer ) return;
     m_poDecoratedLayer->SetStyleTable(poStyleTable);
 }
 
 OGRErr      OGRLayerDecorator::StartTransaction()
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->StartTransaction();
 }
 
 OGRErr      OGRLayerDecorator::CommitTransaction()
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->CommitTransaction();
 }
 
 OGRErr      OGRLayerDecorator::RollbackTransaction()
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->RollbackTransaction();
 }
 
 const char *OGRLayerDecorator::GetFIDColumn()
 {
+    if( !m_poDecoratedLayer ) return "";
     return m_poDecoratedLayer->GetFIDColumn();
 }
 
 const char *OGRLayerDecorator::GetGeometryColumn()
 {
+    if( !m_poDecoratedLayer ) return "";
     return m_poDecoratedLayer->GetGeometryColumn();
 }
 
 OGRErr      OGRLayerDecorator::SetIgnoredFields( const char **papszFields )
 {
+    if( !m_poDecoratedLayer ) return OGRERR_FAILURE;
     return m_poDecoratedLayer->SetIgnoredFields(papszFields);
 }
+
+char      **OGRLayerDecorator::GetMetadata( const char * pszDomain )
+{
+    if( !m_poDecoratedLayer ) return NULL;
+    return m_poDecoratedLayer->GetMetadata(pszDomain);
+}
+
+CPLErr      OGRLayerDecorator::SetMetadata( char ** papszMetadata,
+                                          const char * pszDomain )
+{
+    if( !m_poDecoratedLayer ) return CE_Failure;
+    return m_poDecoratedLayer->SetMetadata(papszMetadata, pszDomain);
+}
+
+const char *OGRLayerDecorator::GetMetadataItem( const char * pszName,
+                                              const char * pszDomain )
+{
+    if( !m_poDecoratedLayer ) return NULL;
+    return m_poDecoratedLayer->GetMetadataItem(pszName, pszDomain);
+}
+
+CPLErr      OGRLayerDecorator::SetMetadataItem( const char * pszName,
+                                              const char * pszValue,
+                                              const char * pszDomain )
+{
+    if( !m_poDecoratedLayer ) return CE_Failure;
+    return m_poDecoratedLayer->SetMetadataItem(pszName, pszValue, pszDomain);
+}
diff --git a/ogr/ogrsf_frmts/generic/ogrlayerdecorator.h b/ogr/ogrsf_frmts/generic/ogrlayerdecorator.h
index 182d85a..535bfcd 100644
--- a/ogr/ogrsf_frmts/generic/ogrlayerdecorator.h
+++ b/ogr/ogrsf_frmts/generic/ogrlayerdecorator.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlayerdecorator.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrlayerdecorator.h 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRLayerDecorator class
@@ -32,7 +32,7 @@
 
 #include "ogrsf_frmts.h"
 
-class OGRLayerDecorator : public OGRLayer
+class CPL_DLL OGRLayerDecorator : public OGRLayer
 {
   protected:
     OGRLayer *m_poDecoratedLayer;
@@ -56,11 +56,11 @@ class OGRLayerDecorator : public OGRLayer
 
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
-    virtual OGRFeature *GetFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual const char *GetName();
     virtual OGRwkbGeometryType GetGeomType();
@@ -68,15 +68,12 @@ class OGRLayerDecorator : public OGRLayer
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     virtual int         TestCapability( const char * );
 
-    /* Deprecated (and un-implemented method) --> we won't decorate it ! */
-    /* virtual const char *GetInfo( const char * ); */
-
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
     virtual OGRErr      DeleteField( int iField );
@@ -99,6 +96,15 @@ class OGRLayerDecorator : public OGRLayer
 
     virtual OGRErr      SetIgnoredFields( const char **papszFields );
 
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                     const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                         const char * pszValue,
+                                         const char * pszDomain = "" );
+
     OGRLayer* GetBaseLayer()    { return m_poDecoratedLayer; }
 };
 
diff --git a/ogr/ogrsf_frmts/generic/ogrlayerpool.cpp b/ogr/ogrsf_frmts/generic/ogrlayerpool.cpp
index 905bb1a..8dd789b 100644
--- a/ogr/ogrsf_frmts/generic/ogrlayerpool.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrlayerpool.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlayerpool.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrlayerpool.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRLayerPool and OGRProxiedLayer class
@@ -29,7 +29,7 @@
 
 #include "ogrlayerpool.h"
 
-CPL_CVSID("$Id: ogrlayerpool.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrlayerpool.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                      OGRAbstractProxiedLayer()                       */
@@ -217,6 +217,17 @@ void OGRProxiedLayer::CloseUnderlyingLayer()
 }
 
 /************************************************************************/
+/*                          GetUnderlyingLayer()                        */
+/************************************************************************/
+
+OGRLayer* OGRProxiedLayer::GetUnderlyingLayer()
+{
+    if( poUnderlyingLayer == NULL )
+        OpenUnderlyingLayer();
+    return poUnderlyingLayer;
+}
+
+/************************************************************************/
 /*                          GetSpatialFilter()                          */
 /************************************************************************/
 
@@ -279,7 +290,7 @@ OGRFeature *OGRProxiedLayer::GetNextFeature()
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr      OGRProxiedLayer::SetNextByIndex( long nIndex )
+OGRErr      OGRProxiedLayer::SetNextByIndex( GIntBig nIndex )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return OGRERR_FAILURE;
     return poUnderlyingLayer->SetNextByIndex(nIndex);
@@ -289,27 +300,27 @@ OGRErr      OGRProxiedLayer::SetNextByIndex( long nIndex )
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRProxiedLayer::GetFeature( long nFID )
+OGRFeature *OGRProxiedLayer::GetFeature( GIntBig nFID )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return NULL;
     return poUnderlyingLayer->GetFeature(nFID);
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr      OGRProxiedLayer::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRProxiedLayer::ISetFeature( OGRFeature *poFeature )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return OGRERR_FAILURE;
     return poUnderlyingLayer->SetFeature(poFeature);
 }
 
 /************************************************************************/
-/*                            CreateFeature()                           */
+/*                            ICreateFeature()                           */
 /************************************************************************/
 
-OGRErr      OGRProxiedLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr      OGRProxiedLayer::ICreateFeature( OGRFeature *poFeature )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return OGRERR_FAILURE;
     return poUnderlyingLayer->CreateFeature(poFeature);
@@ -319,7 +330,7 @@ OGRErr      OGRProxiedLayer::CreateFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr      OGRProxiedLayer::DeleteFeature( long nFID )
+OGRErr      OGRProxiedLayer::DeleteFeature( GIntBig nFID )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return OGRERR_FAILURE;
     return poUnderlyingLayer->DeleteFeature(nFID);
@@ -390,7 +401,7 @@ OGRSpatialReference *OGRProxiedLayer::GetSpatialRef()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int         OGRProxiedLayer::GetFeatureCount( int bForce )
+GIntBig         OGRProxiedLayer::GetFeatureCount( int bForce )
 {
     if( poUnderlyingLayer == NULL && !OpenUnderlyingLayer() ) return 0;
     return poUnderlyingLayer->GetFeatureCount(bForce);
diff --git a/ogr/ogrsf_frmts/generic/ogrlayerpool.h b/ogr/ogrsf_frmts/generic/ogrlayerpool.h
index a0bc8bf..c6e013f 100644
--- a/ogr/ogrsf_frmts/generic/ogrlayerpool.h
+++ b/ogr/ogrsf_frmts/generic/ogrlayerpool.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrlayerpool.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrlayerpool.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRLayerPool and OGRProxiedLayer class
@@ -107,6 +107,8 @@ class OGRProxiedLayer : public OGRAbstractProxiedLayer
                                         FreeUserDataFunc pfnFreeUserData,
                                         void* pUserData);
     virtual            ~OGRProxiedLayer();
+    
+    OGRLayer           *GetUnderlyingLayer();
 
     virtual OGRGeometry *GetSpatialFilter();
     virtual void        SetSpatialFilter( OGRGeometry * );
@@ -116,11 +118,11 @@ class OGRProxiedLayer : public OGRAbstractProxiedLayer
 
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
-    virtual OGRFeature *GetFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual const char *GetName();
     virtual OGRwkbGeometryType GetGeomType();
@@ -128,15 +130,12 @@ class OGRProxiedLayer : public OGRAbstractProxiedLayer
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     virtual int         TestCapability( const char * );
 
-    /* Deprecated (and un-implemented method) --> we won't decorate it ! */
-    /* virtual const char *GetInfo( const char * ); */
-
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
     virtual OGRErr      DeleteField( int iField );
diff --git a/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.cpp b/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.cpp
index fa18b3f..f186424 100644
--- a/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmutexeddatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmutexeddatasource.cpp 28602 2015-03-03 11:16:35Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMutexedDataSource class
@@ -30,19 +30,25 @@
 #include "ogrmutexeddatasource.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrmutexeddatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmutexeddatasource.cpp 28602 2015-03-03 11:16:35Z rouault $");
 
 OGRMutexedDataSource::OGRMutexedDataSource(OGRDataSource* poBaseDataSource,
                                            int bTakeOwnership,
-                                           void* hMutexIn) :
+                                           CPLMutex* hMutexIn,
+                                           int bWrapLayersInMutexedLayer) :
             m_poBaseDataSource(poBaseDataSource),
             m_bHasOwnership(bTakeOwnership),
-            m_hGlobalMutex(hMutexIn)
+            m_hGlobalMutex(hMutexIn),
+            m_bWrapLayersInMutexedLayer(bWrapLayersInMutexedLayer)
 {
 }
 
 OGRMutexedDataSource::~OGRMutexedDataSource()
 {
+    std::map<OGRLayer*, OGRMutexedLayer*>::iterator oIter = m_oMapLayers.begin();
+    for(; oIter != m_oMapLayers.end(); ++oIter )
+        delete oIter->second;
+
     if( m_bHasOwnership )
         delete m_poBaseDataSource;
 }
@@ -59,22 +65,52 @@ int         OGRMutexedDataSource::GetLayerCount()
     return m_poBaseDataSource->GetLayerCount();
 }
 
+OGRLayer* OGRMutexedDataSource::WrapLayerIfNecessary(OGRLayer* poLayer)
+{
+    if( poLayer && m_bWrapLayersInMutexedLayer )
+    {
+        OGRLayer* poWrappedLayer = m_oMapLayers[poLayer];
+        if( poWrappedLayer )
+            poLayer = poWrappedLayer;
+        else
+        {
+            OGRMutexedLayer* poWrappedLayer = new OGRMutexedLayer(poLayer, FALSE, m_hGlobalMutex);
+            m_oMapLayers[poLayer] = poWrappedLayer;
+            m_oReverseMapLayers[poWrappedLayer] = poLayer;
+            poLayer = poWrappedLayer;
+        }
+    }
+    return poLayer;
+}
+
 OGRLayer    *OGRMutexedDataSource::GetLayer(int iIndex)
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->GetLayer(iIndex);
+    return WrapLayerIfNecessary(m_poBaseDataSource->GetLayer(iIndex));
 }
 
 OGRLayer    *OGRMutexedDataSource::GetLayerByName(const char *pszName)
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->GetLayerByName(pszName);
+    return WrapLayerIfNecessary(m_poBaseDataSource->GetLayerByName(pszName));
 }
 
 OGRErr      OGRMutexedDataSource::DeleteLayer(int iIndex)
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->DeleteLayer(iIndex);
+    OGRLayer* poLayer = m_bWrapLayersInMutexedLayer ? GetLayer(iIndex) : NULL;
+    OGRErr eErr = m_poBaseDataSource->DeleteLayer(iIndex);
+    if( eErr == OGRERR_NONE && poLayer)
+    {
+        std::map<OGRLayer*, OGRMutexedLayer*>::iterator oIter = m_oMapLayers.find(poLayer);
+        if(oIter != m_oMapLayers.end())
+        {
+            delete oIter->second;
+            m_oReverseMapLayers.erase(oIter->second);
+            m_oMapLayers.erase(oIter);
+        }
+    }
+    return eErr;
 }
 
 int         OGRMutexedDataSource::TestCapability( const char * pszCap )
@@ -83,13 +119,13 @@ int         OGRMutexedDataSource::TestCapability( const char * pszCap )
     return m_poBaseDataSource->TestCapability(pszCap);
 }
 
-OGRLayer   *OGRMutexedDataSource::CreateLayer( const char *pszName, 
+OGRLayer   *OGRMutexedDataSource::ICreateLayer( const char *pszName, 
                                      OGRSpatialReference *poSpatialRef,
                                      OGRwkbGeometryType eGType,
                                      char ** papszOptions)
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->CreateLayer(pszName, poSpatialRef, eGType, papszOptions);
+    return WrapLayerIfNecessary(m_poBaseDataSource->CreateLayer(pszName, poSpatialRef, eGType, papszOptions));
 }
 
 OGRLayer   *OGRMutexedDataSource::CopyLayer( OGRLayer *poSrcLayer, 
@@ -97,7 +133,7 @@ OGRLayer   *OGRMutexedDataSource::CopyLayer( OGRLayer *poSrcLayer,
                                    char **papszOptions )
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->CopyLayer(poSrcLayer, pszNewName, papszOptions );
+    return WrapLayerIfNecessary(m_poBaseDataSource->CopyLayer(poSrcLayer, pszNewName, papszOptions ));
 }
 
 OGRStyleTable *OGRMutexedDataSource::GetStyleTable()
@@ -123,18 +159,84 @@ OGRLayer *  OGRMutexedDataSource::ExecuteSQL( const char *pszStatement,
                                     const char *pszDialect )
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->ExecuteSQL(pszStatement, poSpatialFilter,
-                                          pszDialect);
+    return WrapLayerIfNecessary(m_poBaseDataSource->ExecuteSQL(pszStatement, poSpatialFilter,
+                                          pszDialect));
 }
 
 void        OGRMutexedDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    if( poResultsSet && m_bWrapLayersInMutexedLayer )
+    {
+        std::map<OGRMutexedLayer*, OGRLayer*>::iterator oIter = m_oReverseMapLayers.find((OGRMutexedLayer*)poResultsSet);
+        CPLAssert(oIter != m_oReverseMapLayers.end());
+        delete poResultsSet;
+        poResultsSet = oIter->second;
+        m_oMapLayers.erase(poResultsSet);
+        m_oReverseMapLayers.erase(oIter);
+    }
+
     m_poBaseDataSource->ReleaseResultSet(poResultsSet);
 }
 
-OGRErr      OGRMutexedDataSource::SyncToDisk()
+void      OGRMutexedDataSource::FlushCache()
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->FlushCache();
+}
+
+OGRErr OGRMutexedDataSource::StartTransaction(int bForce)
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->StartTransaction(bForce);
+}
+
+OGRErr OGRMutexedDataSource::CommitTransaction()
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->CommitTransaction();
+}
+
+OGRErr OGRMutexedDataSource::RollbackTransaction()
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->RollbackTransaction();
+}
+
+char      **OGRMutexedDataSource::GetMetadata( const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->GetMetadata(pszDomain);
+}
+
+CPLErr      OGRMutexedDataSource::SetMetadata( char ** papszMetadata,
+                                          const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->SetMetadata(papszMetadata, pszDomain);
+}
+
+const char *OGRMutexedDataSource::GetMetadataItem( const char * pszName,
+                                              const char * pszDomain )
 {
     CPLMutexHolderOptionalLockD(m_hGlobalMutex);
-    return m_poBaseDataSource->SyncToDisk();
+    return m_poBaseDataSource->GetMetadataItem(pszName, pszDomain);
+}
+
+CPLErr      OGRMutexedDataSource::SetMetadataItem( const char * pszName,
+                                              const char * pszValue,
+                                              const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hGlobalMutex);
+    return m_poBaseDataSource->SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+#if defined(WIN32) && defined(_MSC_VER)
+// Horrible hack: for some reason MSVC doesn't export the class
+// if it is not referenced from the DLL itself
+void OGRRegisterMutexedDataSource();
+void OGRRegisterMutexedDataSource()
+{
+    delete new OGRMutexedDataSource(NULL, FALSE, NULL, FALSE);
 }
+#endif
diff --git a/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.h b/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.h
index 9321dad..e3ab8e0 100644
--- a/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.h
+++ b/ogr/ogrsf_frmts/generic/ogrmutexeddatasource.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmutexeddatasource.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmutexeddatasource.h 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRLMutexedDataSource class
@@ -31,6 +31,9 @@
 #define _OGRMUTEXEDDATASOURCELAYER_H_INCLUDED
 
 #include "ogrsf_frmts.h"
+#include "cpl_multiproc.h"
+#include "ogrmutexedlayer.h"
+#include <map>
 
 /** OGRMutexedDataSource class protects all virtual methods of OGRDataSource
  *  with a mutex.
@@ -44,17 +47,25 @@ class CPL_DLL OGRMutexedDataSource : public OGRDataSource
   protected:
     OGRDataSource *m_poBaseDataSource;
     int            m_bHasOwnership;
-    void          *m_hGlobalMutex;
+    CPLMutex      *m_hGlobalMutex;
+    int            m_bWrapLayersInMutexedLayer;
+    std::map<OGRLayer*, OGRMutexedLayer* > m_oMapLayers;
+    std::map<OGRMutexedLayer*, OGRLayer* > m_oReverseMapLayers;
+    
+    OGRLayer*           WrapLayerIfNecessary(OGRLayer* poLayer);
 
   public:
 
     /* The construction of the object isn't protected by the mutex */
                  OGRMutexedDataSource(OGRDataSource* poBaseDataSource,
                                       int bTakeOwnership,
-                                      void* hMutexIn);
+                                      CPLMutex* hMutexIn,
+                                      int bWrapLayersInMutexedLayer);
 
     /* The destruction of the object isn't protected by the mutex */
     virtual     ~OGRMutexedDataSource();
+    
+    OGRDataSource*      GetBaseDataSource() { return m_poBaseDataSource; }
 
     virtual const char  *GetName();
 
@@ -65,7 +76,7 @@ class CPL_DLL OGRMutexedDataSource : public OGRDataSource
 
     virtual int         TestCapability( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName, 
+    virtual OGRLayer   *ICreateLayer( const char *pszName, 
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
@@ -82,8 +93,21 @@ class CPL_DLL OGRMutexedDataSource : public OGRDataSource
                                     OGRGeometry *poSpatialFilter,
                                     const char *pszDialect );
     virtual void        ReleaseResultSet( OGRLayer * poResultsSet );
+    
+    virtual void        FlushCache();
 
-    virtual OGRErr      SyncToDisk();
+    virtual OGRErr      StartTransaction(int bForce=FALSE);
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
+
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                     const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                         const char * pszValue,
+                                         const char * pszDomain = "" );
 };
 
 #endif // _OGRMUTEXEDDATASOURCELAYER_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/generic/ogrmutexedlayer.cpp b/ogr/ogrsf_frmts/generic/ogrmutexedlayer.cpp
index f24481f..a127ce2 100644
--- a/ogr/ogrsf_frmts/generic/ogrmutexedlayer.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrmutexedlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmutexedlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmutexedlayer.cpp 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMutexedLayer class
@@ -30,13 +30,14 @@
 #include "ogrmutexedlayer.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrmutexedlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmutexedlayer.cpp 28601 2015-03-03 11:06:40Z rouault $");
 
 OGRMutexedLayer::OGRMutexedLayer(OGRLayer* poDecoratedLayer,
                                  int bTakeOwnership,
-                                 void* hMutex) :
+                                 CPLMutex* hMutex) :
         OGRLayerDecorator(poDecoratedLayer, bTakeOwnership), m_hMutex(hMutex)
 {
+    SetDescription( poDecoratedLayer->GetDescription() );
 }
 
 OGRMutexedLayer::~OGRMutexedLayer()
@@ -94,31 +95,31 @@ OGRFeature *OGRMutexedLayer::GetNextFeature()
     return OGRLayerDecorator::GetNextFeature();
 }
 
-OGRErr      OGRMutexedLayer::SetNextByIndex( long nIndex )
+OGRErr      OGRMutexedLayer::SetNextByIndex( GIntBig nIndex )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
     return OGRLayerDecorator::SetNextByIndex(nIndex);
 }
 
-OGRFeature *OGRMutexedLayer::GetFeature( long nFID )
+OGRFeature *OGRMutexedLayer::GetFeature( GIntBig nFID )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
     return OGRLayerDecorator::GetFeature(nFID);
 }
 
-OGRErr      OGRMutexedLayer::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRMutexedLayer::ISetFeature( OGRFeature *poFeature )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
-    return OGRLayerDecorator::SetFeature(poFeature);
+    return OGRLayerDecorator::ISetFeature(poFeature);
 }
 
-OGRErr      OGRMutexedLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr      OGRMutexedLayer::ICreateFeature( OGRFeature *poFeature )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
-    return OGRLayerDecorator::CreateFeature(poFeature);
+    return OGRLayerDecorator::ICreateFeature(poFeature);
 }
 
-OGRErr      OGRMutexedLayer::DeleteFeature( long nFID )
+OGRErr      OGRMutexedLayer::DeleteFeature( GIntBig nFID )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
     return OGRLayerDecorator::DeleteFeature(nFID);
@@ -148,7 +149,7 @@ OGRSpatialReference *OGRMutexedLayer::GetSpatialRef()
     return OGRLayerDecorator::GetSpatialRef();
 }
 
-int         OGRMutexedLayer::GetFeatureCount( int bForce )
+GIntBig         OGRMutexedLayer::GetFeatureCount( int bForce )
 {
     CPLMutexHolderOptionalLockD(m_hMutex);
     return OGRLayerDecorator::GetFeatureCount(bForce);
@@ -256,3 +257,42 @@ OGRErr      OGRMutexedLayer::SetIgnoredFields( const char **papszFields )
     CPLMutexHolderOptionalLockD(m_hMutex);
     return OGRLayerDecorator::SetIgnoredFields(papszFields);
 }
+
+char      **OGRMutexedLayer::GetMetadata( const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hMutex);
+    return OGRLayerDecorator::GetMetadata(pszDomain);
+}
+
+CPLErr      OGRMutexedLayer::SetMetadata( char ** papszMetadata,
+                                          const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hMutex);
+    return OGRLayerDecorator::SetMetadata(papszMetadata, pszDomain);
+}
+
+const char *OGRMutexedLayer::GetMetadataItem( const char * pszName,
+                                              const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hMutex);
+    return OGRLayerDecorator::GetMetadataItem(pszName, pszDomain);
+}
+
+CPLErr      OGRMutexedLayer::SetMetadataItem( const char * pszName,
+                                              const char * pszValue,
+                                              const char * pszDomain )
+{
+    CPLMutexHolderOptionalLockD(m_hMutex);
+    return OGRLayerDecorator::SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+#if defined(WIN32) && defined(_MSC_VER)
+// Horrible hack: for some reason MSVC doesn't export the class
+// if it is not referenced from the DLL itself
+void OGRRegisterMutexedLayer();
+void OGRRegisterMutexedLayer()
+{
+    CPLAssert(FALSE); // Never call this function: it will segfault
+    delete new OGRMutexedLayer(NULL, FALSE, NULL);
+}
+#endif
diff --git a/ogr/ogrsf_frmts/generic/ogrmutexedlayer.h b/ogr/ogrsf_frmts/generic/ogrmutexedlayer.h
index 5d0ffe2..451e817 100644
--- a/ogr/ogrsf_frmts/generic/ogrmutexedlayer.h
+++ b/ogr/ogrsf_frmts/generic/ogrmutexedlayer.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmutexedlayer.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmutexedlayer.h 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRLMutexedLayer class
@@ -31,6 +31,7 @@
 #define _OGRMUTEXEDLAYER_H_INCLUDED
 
 #include "ogrlayerdecorator.h"
+#include "cpl_multiproc.h"
 
 /** OGRMutexedLayer class protects all virtual methods of OGRLayer with a mutex.
  *
@@ -42,14 +43,14 @@
 class CPL_DLL OGRMutexedLayer : public OGRLayerDecorator
 {
   protected:
-        void          *m_hMutex;
+        CPLMutex          *m_hMutex;
 
   public:
 
     /* The construction of the object isn't protected by the mutex */
                        OGRMutexedLayer(OGRLayer* poDecoratedLayer,
                                        int bTakeOwnership,
-                                       void* hMutex);
+                                       CPLMutex* hMutex);
 
     /* The destruction of the object isn't protected by the mutex */
     virtual           ~OGRMutexedLayer();
@@ -66,11 +67,11 @@ class CPL_DLL OGRMutexedLayer : public OGRLayerDecorator
 
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
-    virtual OGRFeature *GetFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual const char *GetName();
     virtual OGRwkbGeometryType GetGeomType();
@@ -78,15 +79,12 @@ class CPL_DLL OGRMutexedLayer : public OGRLayerDecorator
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     virtual int         TestCapability( const char * );
 
-    /* Deprecated (and un-implemented method) --> we won't decorate it ! */
-    /* virtual const char *GetInfo( const char * ); */
-
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
     virtual OGRErr      DeleteField( int iField );
@@ -108,6 +106,15 @@ class CPL_DLL OGRMutexedLayer : public OGRLayerDecorator
     virtual const char *GetGeometryColumn();
 
     virtual OGRErr      SetIgnoredFields( const char **papszFields );
+
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                     const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                         const char * pszValue,
+                                         const char * pszDomain = "" );
 };
 
 #endif // _OGRMUTEXEDLAYER_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp
index 30d1d1c..e61cd1b 100644
--- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrregisterall.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrregisterall.cpp 29028 2015-04-26 21:19:29Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Function to register all known OGR drivers.
@@ -30,7 +30,7 @@
 
 #include "ogrsf_frmts.h"
 
-CPL_CVSID("$Id: ogrregisterall.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrregisterall.cpp 29028 2015-04-26 21:19:29Z rouault $");
 
 /************************************************************************/
 /*                           OGRRegisterAll()                           */
@@ -38,7 +38,11 @@ CPL_CVSID("$Id: ogrregisterall.cpp 27044 2014-03-16 23:41:27Z rouault $");
 
 void OGRRegisterAll()
 {
-    OGRSFDriverRegistrar::GetRegistrar()->AutoLoadDrivers();
+    GDALAllRegister();
+}
+
+void OGRRegisterAllInternal()
+{
 
 #ifdef SHAPE_ENABLED
     RegisterOGRShape();
@@ -52,9 +56,6 @@ void OGRRegisterAll()
 #ifdef SDTS_ENABLED
     RegisterOGRSDTS();
 #endif
-#ifdef TIGER_ENABLED
-    RegisterOGRTiger();
-#endif
 #ifdef S57_ENABLED
     RegisterOGRS57();
 #endif
@@ -142,9 +143,6 @@ void OGRRegisterAll()
 #ifdef INGRES_ENABLED
     RegisterOGRIngres();
 #endif
-#ifdef PCIDSK_ENABLED
-    RegisterOGRPCIDSK();
-#endif
 #ifdef SDE_ENABLED
     RegisterOGRSDE();
 #endif
@@ -158,10 +156,6 @@ void OGRRegisterAll()
 #ifdef XPLANE_ENABLED
     RegisterOGRXPlane();
 #endif
-#ifdef AVCBIN_ENABLED
-    RegisterOGRAVCBin();
-    RegisterOGRAVCE00();
-#endif
 #ifdef DWGDIRECT_ENABLED
     RegisterOGRDXFDWG();
 #endif
@@ -238,6 +232,9 @@ void OGRRegisterAll()
 #ifdef COUCHDB_ENABLED
     RegisterOGRCouchDB();
 #endif
+#ifdef CLOUDANT_ENABLED
+    RegisterOGRCloudant();
+#endif
 #ifdef IDRISI_ENABLED
     RegisterOGRIdrisi();
 #endif
@@ -262,9 +259,6 @@ void OGRRegisterAll()
 #ifdef ELASTIC_ENABLED
     RegisterOGRElastic();
 #endif
-#ifdef PDF_ENABLED
-    RegisterOGRPDF();
-#endif
 #ifdef WALK_ENABLED
     RegisterOGRWalk();
 #endif
@@ -274,4 +268,26 @@ void OGRRegisterAll()
 #ifdef SXF_ENABLED
     RegisterOGRSXF();
 #endif
+#ifdef SELAFIN_ENABLED
+    RegisterOGRSelafin();
+#endif
+#ifdef JML_ENABLED
+    RegisterOGRJML();
+#endif
+#ifdef PLSCENES_ENABLED
+    RegisterOGRPLSCENES();
+#endif
+#ifdef CSW_ENABLED
+    RegisterOGRCSW();
+#endif
+
+/* Put TIGER and AVCBIN at end since they need poOpenInfo->GetSiblingFiles() */
+#ifdef TIGER_ENABLED
+    RegisterOGRTiger();
+#endif
+#ifdef AVCBIN_ENABLED
+    RegisterOGRAVCBin();
+    RegisterOGRAVCE00();
+#endif
+
 } /* OGRRegisterAll */
diff --git a/ogr/ogrsf_frmts/generic/ogrsfdriver.cpp b/ogr/ogrsf_frmts/generic/ogrsfdriver.cpp
index 611f9df..5d3275f 100644
--- a/ogr/ogrsf_frmts/generic/ogrsfdriver.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrsfdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsfdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsfdriver.cpp 27698 2014-09-20 11:59:07Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The generic portions of the OGRSFDriver class.
@@ -31,8 +31,9 @@
 #include "ogrsf_frmts.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
+#include "ograpispy.h"
 
-CPL_CVSID("$Id: ogrsfdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsfdriver.cpp 27698 2014-09-20 11:59:07Z rouault $");
 
 /************************************************************************/
 /*                            ~OGRSFDriver()                            */
@@ -67,24 +68,19 @@ OGRDataSourceH OGR_Dr_CreateDataSource( OGRSFDriverH hDriver,
 {
     VALIDATE_POINTER1( hDriver, "OGR_Dr_CreateDataSource", NULL );
 
-    OGRSFDriver* poDriver = (OGRSFDriver *) hDriver;
-    CPLAssert( NULL != poDriver );
+    GDALDriver* poDriver = (GDALDriver*)hDriver;
 
-    OGRDataSource* poDS = NULL;
-    poDS = poDriver->CreateDataSource( pszName, papszOptions );
+    /* MapServer had the bad habit of calling with NULL name for a memory datasource */
+    if( pszName == NULL )
+        pszName = "";
 
-    /* This fix is explained in Ticket #1223 */
-    if( NULL != poDS )
-    {
-        poDS->SetDriver( poDriver );
-        CPLAssert( NULL != poDS->GetDriver() );
-    }
-    else
-    {
-        CPLDebug( "OGR", "CreateDataSource operation failed. NULL pointer returned." );
-    }
+    OGRDataSourceH hDS = (OGRDataSourceH) poDriver->Create( pszName, 0, 0, 0, GDT_Unknown, papszOptions );
+
+#ifdef OGRAPISPY_ENABLED
+    OGRAPISpyCreateDataSource(hDriver, pszName, papszOptions, (OGRDataSourceH) hDS);
+#endif
 
-    return (OGRDataSourceH) poDS;
+    return hDS;
 }
 
 /************************************************************************/
@@ -112,7 +108,11 @@ OGRErr OGR_Dr_DeleteDataSource( OGRSFDriverH hDriver,
     VALIDATE_POINTER1( hDriver, "OGR_Dr_DeleteDataSource",
                        OGRERR_INVALID_HANDLE );
 
-    return ((OGRSFDriver *) hDriver)->DeleteDataSource( pszDataSource );
+#ifdef OGRAPISPY_ENABLED
+    OGRAPISpyDeleteDataSource(hDriver, pszDataSource);
+#endif
+
+    return ((GDALDriver *) hDriver)->Delete( pszDataSource );
 }
 
 /************************************************************************/
@@ -124,7 +124,7 @@ const char *OGR_Dr_GetName( OGRSFDriverH hDriver )
 {
     VALIDATE_POINTER1( hDriver, "OGR_Dr_GetName", NULL );
 
-    return ((OGRSFDriver *) hDriver)->GetName();
+    return ((GDALDriver*)hDriver)->GetDescription();
 }
 
 /************************************************************************/
@@ -137,12 +137,23 @@ OGRDataSourceH OGR_Dr_Open( OGRSFDriverH hDriver, const char *pszName,
 {
     VALIDATE_POINTER1( hDriver, "OGR_Dr_Open", NULL );
 
-    OGRDataSource *poDS = ((OGRSFDriver *)hDriver)->Open( pszName, bUpdate );
+    const char* const apszDrivers[] = { ((GDALDriver*)hDriver)->GetDescription(),
+                                   NULL };
+
+#ifdef OGRAPISPY_ENABLED
+    int iSnapshot = OGRAPISpyOpenTakeSnapshot(pszName, bUpdate);
+#endif
+
+    GDALDatasetH hDS = GDALOpenEx(pszName,
+                                      GDAL_OF_VECTOR |
+                                      ((bUpdate) ? GDAL_OF_UPDATE: 0),
+                                      apszDrivers, NULL, NULL);
 
-    if( poDS != NULL && poDS->GetDriver() == NULL )
-        poDS->SetDriver( (OGRSFDriver *)hDriver );
+#ifdef OGRAPISPY_ENABLED
+    OGRAPISpyOpen(pszName, bUpdate, iSnapshot, &hDS);
+#endif
 
-    return (OGRDataSourceH) poDS;
+    return (OGRDataSourceH) hDS;
 }
 
 /************************************************************************/
@@ -155,29 +166,48 @@ int OGR_Dr_TestCapability( OGRSFDriverH hDriver, const char *pszCap )
     VALIDATE_POINTER1( hDriver, "OGR_Dr_TestCapability", 0 );
     VALIDATE_POINTER1( pszCap, "OGR_Dr_TestCapability", 0 );
 
-    return ((OGRSFDriver *) hDriver)->TestCapability( pszCap );
+    GDALDriver* poDriver = (GDALDriver *) hDriver;
+    if( EQUAL(pszCap, ODrCCreateDataSource) )
+    {
+        return poDriver->pfnCreate != NULL ||
+               poDriver->pfnCreateVectorOnly != NULL;
+    }
+    else if( EQUAL(pszCap, ODrCDeleteDataSource) )
+    {
+        return poDriver->pfnDelete != NULL ||
+               poDriver->pfnDeleteDataSource != NULL;
+    }
+    else
+        return FALSE;
 }
 
 /************************************************************************/
-/*                           CopyDataSource()                           */
+/*                       OGR_Dr_CopyDataSource()                        */
 /************************************************************************/
 
-OGRDataSource *OGRSFDriver::CopyDataSource( OGRDataSource *poSrcDS, 
-                                            const char *pszNewName,
-                                            char **papszOptions )
-
+OGRDataSourceH OGR_Dr_CopyDataSource( OGRSFDriverH hDriver, 
+                                      OGRDataSourceH hSrcDS, 
+                                      const char *pszNewName,
+                                      char **papszOptions )
+                                      
 {
-    if( !TestCapability( ODrCCreateDataSource ) )
+    VALIDATE_POINTER1( hDriver, "OGR_Dr_CopyDataSource", NULL );
+    VALIDATE_POINTER1( hSrcDS, "OGR_Dr_CopyDataSource", NULL );
+    VALIDATE_POINTER1( pszNewName, "OGR_Dr_CopyDataSource", NULL );
+
+    GDALDriver* poDriver = (GDALDriver*)hDriver;
+    if( !poDriver->GetMetadataItem( GDAL_DCAP_CREATE ) )
     {
         CPLError( CE_Failure, CPLE_NotSupported, 
                   "%s driver does not support data source creation.",
-                  GetName() );
+                  poDriver->GetDescription() );
         return NULL;
     }
 
-    OGRDataSource *poODS;
+    GDALDataset *poSrcDS = (GDALDataset*) hSrcDS;
+    GDALDataset *poODS;
 
-    poODS = CreateDataSource( pszNewName, papszOptions );
+    poODS = poDriver->Create( pszNewName, 0, 0, 0, GDT_Unknown, papszOptions );
     if( poODS == NULL )
         return NULL;
 
@@ -195,40 +225,6 @@ OGRDataSource *OGRSFDriver::CopyDataSource( OGRDataSource *poSrcDS,
                           papszOptions );
     }
 
-    /* Make sure that the driver is attached to the created datasource */
-    /* It is also done in OGR_Dr_CopyDataSource() C method, in case */
-    /* another C++ implementation forgets to do it. Currently (Nov 2011), */
-    /* this implementation is the only one in the OGR source tree */
-    if( poODS != NULL && poODS->GetDriver() == NULL )
-        poODS->SetDriver( this );
-
-    return poODS;
-}
-
-/************************************************************************/
-/*                       OGR_Dr_CopyDataSource()                        */
-/************************************************************************/
-
-OGRDataSourceH OGR_Dr_CopyDataSource( OGRSFDriverH hDriver, 
-                                      OGRDataSourceH hSrcDS, 
-                                      const char *pszNewName,
-                                      char **papszOptions )
-                                      
-{
-    VALIDATE_POINTER1( hDriver, "OGR_Dr_CopyDataSource", NULL );
-    VALIDATE_POINTER1( hSrcDS, "OGR_Dr_CopyDataSource", NULL );
-    VALIDATE_POINTER1( pszNewName, "OGR_Dr_CopyDataSource", NULL );
-
-    OGRDataSource* poDS =
-        ((OGRSFDriver *) hDriver)->CopyDataSource( 
-            (OGRDataSource *) hSrcDS, pszNewName, papszOptions );
-
-    /* Make sure that the driver is attached to the created datasource */
-    /* if not already done by the implementation of the CopyDataSource() */
-    /* method */
-    if( poDS != NULL && poDS->GetDriver() == NULL )
-        poDS->SetDriver( (OGRSFDriver *)hDriver );
-
-    return (OGRDataSourceH)poDS;
+    return (OGRDataSourceH)poODS;
 }
 
diff --git a/ogr/ogrsf_frmts/generic/ogrsfdriverregistrar.cpp b/ogr/ogrsf_frmts/generic/ogrsfdriverregistrar.cpp
index df1f474..7173a24 100644
--- a/ogr/ogrsf_frmts/generic/ogrsfdriverregistrar.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrsfdriverregistrar.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsfdriverregistrar.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsfdriverregistrar.cpp 28806 2015-03-28 14:37:47Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRSFDriverRegistrar class implementation.
@@ -30,21 +30,10 @@
 
 #include "ogrsf_frmts.h"
 #include "ogr_api.h"
-#include "ogr_p.h"
-#include "cpl_multiproc.h"
-#include "swq.h"
+#include "ograpispy.h"
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-CPL_CVSID("$Id: ogrsfdriverregistrar.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsfdriverregistrar.cpp 28806 2015-03-28 14:37:47Z rouault $");
 
-static void *hDRMutex = NULL;
-static OGRSFDriverRegistrar * volatile poRegistrar = NULL;
-
-static const char *pszUpdatableINST_DATA = 
-"__INST_DATA_TARGET:                                                                                                                                      ";
 /************************************************************************/
 /*                         OGRSFDriverRegistrar                         */
 /************************************************************************/
@@ -60,42 +49,6 @@ static const char *pszUpdatableINST_DATA =
 OGRSFDriverRegistrar::OGRSFDriverRegistrar()
 
 {
-    CPLAssert( poRegistrar == NULL );
-    nDrivers = 0;
-    papoDrivers = NULL;
-
-    nOpenDSCount = 0;
-    papszOpenDSRawName = NULL;
-    papoOpenDS = NULL;
-    papoOpenDSDriver = NULL;
-    panOpenDSPID = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      We want to push a location to search for data files             */
-/*      supporting GDAL/OGR such as EPSG csv files, S-57 definition     */
-/*      files, and so forth.  The static pszUpdateableINST_DATA         */
-/*      string can be updated within the shared library or              */
-/*      executable during an install to point installed data            */
-/*      directory.  If it isn't burned in here then we use the          */
-/*      INST_DATA macro (setup at configure time) if                    */
-/*      available. Otherwise we don't push anything and we hope         */
-/*      other mechanisms such as environment variables will have        */
-/*      been employed.                                                  */
-/* -------------------------------------------------------------------- */
-    if( CPLGetConfigOption( "GDAL_DATA", NULL ) != NULL )
-    {
-        CPLPushFinderLocation( CPLGetConfigOption( "GDAL_DATA", NULL ) );
-    }
-    else if( pszUpdatableINST_DATA[19] != ' ' )
-    {
-        CPLPushFinderLocation( pszUpdatableINST_DATA + 19 );
-    }
-    else
-    {
-#ifdef INST_DATA
-        CPLPushFinderLocation( INST_DATA );
-#endif
-    }
 }
 
 /************************************************************************/
@@ -105,454 +58,199 @@ OGRSFDriverRegistrar::OGRSFDriverRegistrar()
 OGRSFDriverRegistrar::~OGRSFDriverRegistrar()
 
 {
-    for( int i = 0; i < nDrivers; i++ )
-    {
-        delete papoDrivers[i];
-    }
-    nDrivers = 0;
-    CPLFree( papoDrivers );
-    papoDrivers = NULL;
-
-    poRegistrar = NULL; /* equivalent to this = NULL; */
 }
 
 /************************************************************************/
-/*                           OGRCleanupAll()                            */
+/*                           GetRegistrar()                             */
 /************************************************************************/
 
-/**
- * \brief Cleanup all OGR related resources. 
- *
- * This function will destroy the OGRSFDriverRegistrar along with all registered
- * drivers, and then cleanup long lived OSR (OGRSpatialReference) and CPL
- * resources.  This may be called in an application when OGR services are
- * no longer needed.  It is not normally required, but by freeing all
- * dynamically allocated memory it can make memory leak testing easier.
- * 
- * In addition to destroying the OGRDriverRegistrar, this function also calls:
- * - OSRCleanup()
- * - CPLFinderClean()
- * - VSICleanupFileManager()
- * - CPLFreeConfig()
- * - CPLCleanupTLS()
- */
-void OGRCleanupAll()
 
+OGRSFDriverRegistrar *OGRSFDriverRegistrar::GetRegistrar()
 {
-    {
-        // We don't want to hold the mutex while CPL level mutex services
-        // are being destroyed ... just long enough to avoid conflict while
-        // cleaning up OGR and OSR services.
-        CPLMutexHolderD( &hDRMutex );
-    
-        if( poRegistrar != NULL )
-            delete poRegistrar;
-        OSRCleanup();
-    }
-
-    CPLDestroyMutex( hDRMutex );
-    hDRMutex = NULL;
-
-    CPLFinderClean();
-    VSICleanupFileManager();
-    CPLFreeConfig();
-    CPLCleanupTLS();
+    static      OGRSFDriverRegistrar oSingleton;
+    return &oSingleton;
 }
 
-
 /************************************************************************/
-/*                            GetRegistrar()                            */
+/*                           OGRCleanupAll()                            */
 /************************************************************************/
 
+#if defined(WIN32) && defined(_MSC_VER)
+#include "ogremulatedtransaction.h"
+void OGRRegisterMutexedDataSource();
+void OGRRegisterMutexedLayer();
+int OGRwillNeverBeTrue = FALSE;
+#endif
+
 /**
- * \brief Fetch registrar.
- *
- * This static method should be used to fetch the singleton 
- * registrar.  It will create a registrar if there is not already
- * one in existance.
+ * \brief Cleanup all OGR related resources. 
  *
- * @return the current driver registrar.
+ * FIXME
  */
-
-OGRSFDriverRegistrar *OGRSFDriverRegistrar::GetRegistrar()
+void OGRCleanupAll()
 
 {
-    if( poRegistrar == NULL )
+    GDALDestroyDriverManager();
+#if defined(WIN32) && defined(_MSC_VER)
+// Horrible hack: for some reason MSVC doesn't export those classes&symbols
+// if they are not referenced from the DLL itself
+    if(OGRwillNeverBeTrue)
     {
-        CPLMutexHolderD( &hDRMutex );
-
-        if( poRegistrar == NULL )
-            poRegistrar = new OGRSFDriverRegistrar();
+        OGRRegisterMutexedDataSource();
+        OGRRegisterMutexedLayer();
+        OGRCreateEmulatedTransactionDataSourceWrapper(NULL,NULL,FALSE,FALSE);
     }
-   
-    CPLAssert( NULL != poRegistrar );
-    return poRegistrar;
+#endif
 }
 
 /************************************************************************/
-/*                                Open()                                */
+/*                              OGROpen()                               */
 /************************************************************************/
 
-OGRDataSource *OGRSFDriverRegistrar::Open( const char * pszName,
-                                           int bUpdate,
-                                           OGRSFDriver ** ppoDriver )
+OGRDataSourceH OGROpen( const char *pszName, int bUpdate,
+                        OGRSFDriverH *pahDriverList )
 
 {
-    OGRDataSource       *poDS;
-
-#ifdef HAVE_READLINK
-    char szPointerFilename[2048];
-    int  bHasRetried = FALSE;
-#endif
-
-    if( ppoDriver != NULL )
-        *ppoDriver = NULL;
-
-    GetRegistrar();
-    
-    CPLErrorReset();
-
-    CPLAcquireMutex( hDRMutex, 0.1 );
+    VALIDATE_POINTER1( pszName, "OGROpen", NULL );
 
-#ifdef HAVE_READLINK
-retry:
+#ifdef OGRAPISPY_ENABLED
+    int iSnapshot = OGRAPISpyOpenTakeSnapshot(pszName, bUpdate);
 #endif
-    for( int iDriver = 0; iDriver < poRegistrar->nDrivers; iDriver++ )
-    {
-        OGRSFDriver *poDriver = poRegistrar->papoDrivers[iDriver];
-
-        CPLReleaseMutex( hDRMutex );
-
-        poDS = poDriver->Open( pszName, bUpdate );
-        if( poDS != NULL )
-        {
-            if( ppoDriver != NULL )
-                *ppoDriver = poDriver;
-
-            poDS->Reference();
-            if( poDS->GetDriver() == NULL )
-                poDS->m_poDriver = poDriver;
-
-            CPLDebug( "OGR", "OGROpen(%s/%p) succeeded as %s.", 
-                      pszName, poDS, poDS->GetDriver()->GetName() );
-            
-            return poDS;
-        }
 
-        if( CPLGetLastErrorType() == CE_Failure )
-            return NULL;
+    GDALDatasetH hDS = GDALOpenEx(pszName, GDAL_OF_VECTOR |
+                            ((bUpdate) ? GDAL_OF_UPDATE: 0), NULL, NULL, NULL);
+    if( hDS != NULL && pahDriverList != NULL )
+        *pahDriverList = (OGRSFDriverH) GDALGetDatasetDriver(hDS);
 
-        CPLAcquireMutex( hDRMutex, 0.1 );
-    }
-
-#ifdef HAVE_READLINK
-    if (!bHasRetried)
-    {
-        /* If someone creates a file with "ln -sf /vsicurl/http://svn.osgeo.org/gdal/trunk/autotest/ogr/data/poly.shp my_remote_poly.shp" */
-        /* we will be able to open it by passing my_remote_poly.shp */
-        /* This helps a lot for OGR based readers that only provide file explorers to open datasources */
-        int nBytes = readlink(pszName, szPointerFilename, sizeof(szPointerFilename));
-        if (nBytes != -1)
-        {
-            szPointerFilename[MIN(nBytes, (int)sizeof(szPointerFilename)-1)] = 0;
-            pszName = szPointerFilename;
-            bHasRetried = TRUE;
-            goto retry;
-        }
-    }
+#ifdef OGRAPISPY_ENABLED
+    OGRAPISpyOpen(pszName, bUpdate, iSnapshot, &hDS);
 #endif
 
-    CPLReleaseMutex( hDRMutex );
-
-    CPLDebug( "OGR", "OGROpen(%s) failed.", pszName );
-            
-    return NULL;
+    return (OGRDataSourceH) hDS;
 }
 
 /************************************************************************/
-/*                              OGROpen()                               */
+/*                           OGROpenShared()                            */
 /************************************************************************/
 
-OGRDataSourceH OGROpen( const char *pszName, int bUpdate,
-                        OGRSFDriverH *pahDriverList )
+OGRDataSourceH OGROpenShared( const char *pszName, int bUpdate,
+                              OGRSFDriverH *pahDriverList )
 
 {
-    VALIDATE_POINTER1( pszName, "OGROpen", NULL );
-
-    if (poRegistrar)
-        return (OGRDataSourceH) 
-            poRegistrar->Open( pszName, bUpdate, 
-                               (OGRSFDriver **) pahDriverList );
+    VALIDATE_POINTER1( pszName, "OGROpenShared", NULL );
 
-    return NULL;
+    GDALDatasetH hDS = GDALOpenEx(pszName, GDAL_OF_VECTOR |
+            ((bUpdate) ? GDAL_OF_UPDATE: 0) | GDAL_OF_SHARED, NULL, NULL, NULL);
+    if( hDS != NULL && pahDriverList != NULL )
+        *pahDriverList = (OGRSFDriverH) GDALGetDatasetDriver(hDS);
+    return (OGRDataSourceH) hDS;
 }
 
 /************************************************************************/
-/*                             OpenShared()                             */
+/*                        OGRReleaseDataSource()                        */
 /************************************************************************/
 
-OGRDataSource *
-OGRSFDriverRegistrar::OpenShared( const char * pszName, int bUpdate,
-                                  OGRSFDriver ** ppoDriver )
+OGRErr OGRReleaseDataSource( OGRDataSourceH hDS )
 
 {
-    OGRDataSource       *poDS;
-
-    if( ppoDriver != NULL )
-        *ppoDriver = NULL;
-
-    CPLErrorReset();
-
-/* -------------------------------------------------------------------- */
-/*      First try finding an existing open dataset matching exactly     */
-/*      on the original datasource raw name used to open the            */
-/*      datasource.                                                     */
-/*                                                                      */
-/*      NOTE: It is an error, but currently we ignore the bUpdate,      */
-/*      and return whatever is open even if it is read-only and the     */
-/*      application requested update access.                            */
-/* -------------------------------------------------------------------- */
-    {
-        int iDS;
-        CPLMutexHolderD( &hDRMutex );
-        GIntBig nThisPID = CPLGetPID();
-        
-        for( iDS = 0; iDS < nOpenDSCount; iDS++ )
-        {
-            poDS = papoOpenDS[iDS];
-            
-            if( strcmp( pszName, papszOpenDSRawName[iDS]) == 0 
-                && nThisPID == panOpenDSPID[iDS] )
-            {
-                poDS->Reference();
-                
-                if( ppoDriver != NULL )
-                    *ppoDriver = papoOpenDSDriver[iDS];
-                return poDS;
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      If that doesn't match, try matching on the name returned by     */
-/*      the datasource itself.                                          */
-/* -------------------------------------------------------------------- */
-        for( iDS = 0; iDS < nOpenDSCount; iDS++ )
-        {
-            poDS = papoOpenDS[iDS];
-            
-            if( strcmp( pszName, poDS->GetName()) == 0 
-                && nThisPID == panOpenDSPID[iDS] )
-            {
-                poDS->Reference();
-                
-                if( ppoDriver != NULL )
-                    *ppoDriver = papoOpenDSDriver[iDS];
-                return poDS;
-            }
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      We don't have the datasource.  Open it normally.                */
-/* -------------------------------------------------------------------- */
-    OGRSFDriver *poTempDriver = NULL;
-
-    poDS = Open( pszName, bUpdate, &poTempDriver );
-
-    if( poDS == NULL )
-        return poDS;
-
-/* -------------------------------------------------------------------- */
-/*      We don't have this datasource already.  Grow our list to        */
-/*      hold the new datasource.                                        */
-/* -------------------------------------------------------------------- */
-    {
-        CPLMutexHolderD( &hDRMutex );
-
-        papszOpenDSRawName = (char **) 
-            CPLRealloc( papszOpenDSRawName, sizeof(char*) * (nOpenDSCount+1) );
-    
-        papoOpenDS = (OGRDataSource **) 
-            CPLRealloc( papoOpenDS, sizeof(char*) * (nOpenDSCount+1) );
-    
-        papoOpenDSDriver = (OGRSFDriver **) 
-            CPLRealloc( papoOpenDSDriver, sizeof(char*) * (nOpenDSCount+1) );
-
-        panOpenDSPID = (GIntBig *) 
-            CPLRealloc( panOpenDSPID, sizeof(GIntBig) * (nOpenDSCount+1) );
-
-        papszOpenDSRawName[nOpenDSCount] = CPLStrdup( pszName );
-        papoOpenDS[nOpenDSCount] = poDS;
-        papoOpenDSDriver[nOpenDSCount] = poTempDriver;
-        panOpenDSPID[nOpenDSCount] = CPLGetPID();
+    VALIDATE_POINTER1( hDS, "OGRReleaseDataSource", OGRERR_INVALID_HANDLE );
 
-        nOpenDSCount++;
-    }
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpyPreClose(hDS);
+#endif
+    GDALClose( (GDALDatasetH) hDS );
 
-    if( ppoDriver != NULL )
-        *ppoDriver = poTempDriver;
+#ifdef OGRAPISPY_ENABLED
+    if( bOGRAPISpyEnabled )
+        OGRAPISpyPostClose(hDS);
+#endif
 
-    return poDS;
+    return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                           OGROpenShared()                            */
+/*                           GetOpenDSCount()                           */
 /************************************************************************/
 
-OGRDataSourceH OGROpenShared( const char *pszName, int bUpdate,
-                              OGRSFDriverH *pahDriverList )
-
+int OGRSFDriverRegistrar::GetOpenDSCount()
 {
-    VALIDATE_POINTER1( pszName, "OGROpenShared", NULL );
-
-    OGRSFDriverRegistrar::GetRegistrar();
-    return (OGRDataSourceH)
-        poRegistrar->OpenShared( pszName, bUpdate, 
-                                 (OGRSFDriver **) pahDriverList );
+    CPLError(CE_Failure, CPLE_AppDefined, "Stub implementation in GDAL 2.0");
+    return 0;
 }
 
+
 /************************************************************************/
-/*                         ReleaseDataSource()                          */
+/*                         OGRGetOpenDSCount()                          */
 /************************************************************************/
 
-OGRErr OGRSFDriverRegistrar::ReleaseDataSource( OGRDataSource * poDS )
+int OGRGetOpenDSCount()
 
 {
-    {
-        CPLMutexHolderD( &hDRMutex );
-
-        int iDS;
-
-        for( iDS = 0; iDS < nOpenDSCount; iDS++ )
-        {
-            if( poDS == papoOpenDS[iDS] )
-                break;
-        }
-
-        if( iDS == nOpenDSCount )
-        {
-            CPLDebug( "OGR", 
-                      "ReleaseDataSource(%s/%p) on unshared datasource!\n"
-                      "Deleting directly.", 
-                      poDS->GetName(), poDS );
-            delete poDS;
-            return OGRERR_FAILURE;
-        }
-
-        if( poDS->GetRefCount() > 0 )
-            poDS->Dereference();
-
-        if( poDS->GetRefCount() > 0 )
-        {
-            CPLDebug( "OGR", 
-                      "ReleaseDataSource(%s/%p) ... just dereferencing.",
-                      poDS->GetName(), poDS );
-            return OGRERR_NONE;
-        }
-
-        if( poDS->GetSummaryRefCount() > 0 )
-        {
-            CPLDebug( "OGR", 
-                      "OGRSFDriverRegistrar::ReleaseDataSource(%s)\n"
-                      "Datasource reference count is now zero, but some layers\n"
-                      "are still referenced ... not closing datasource.",
-                      poDS->GetName() );
-            return OGRERR_FAILURE;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      We really want to close this file, and remove it from the       */
-/*      shared list.                                                    */
-/* -------------------------------------------------------------------- */
-        CPLDebug( "OGR", 
-                  "ReleaseDataSource(%s/%p) dereferenced and now destroying.",
-                  poDS->GetName(), poDS );
-
-        CPLFree( papszOpenDSRawName[iDS] );
-        memmove( papszOpenDSRawName + iDS, papszOpenDSRawName + iDS + 1, 
-                 sizeof(char *) * (nOpenDSCount - iDS - 1) );
-        memmove( papoOpenDS + iDS, papoOpenDS + iDS + 1, 
-                 sizeof(char *) * (nOpenDSCount - iDS - 1) );
-        memmove( papoOpenDSDriver + iDS, papoOpenDSDriver + iDS + 1, 
-                 sizeof(char *) * (nOpenDSCount - iDS - 1) );
-        memmove( panOpenDSPID + iDS, panOpenDSPID + iDS + 1, 
-                 sizeof(GIntBig) * (nOpenDSCount - iDS - 1) );
-
-        nOpenDSCount--;
-
-        if( nOpenDSCount == 0 )
-        {
-            CPLFree( papszOpenDSRawName );
-            papszOpenDSRawName = NULL;
-            CPLFree( papoOpenDS );
-            papoOpenDS = NULL;
-            CPLFree( papoOpenDSDriver );
-            papoOpenDSDriver = NULL;
-            CPLFree( panOpenDSPID );
-            panOpenDSPID = NULL;
-        }
-    }
+    return OGRSFDriverRegistrar::GetRegistrar()->GetOpenDSCount();
+}
 
-/* -------------------------------------------------------------------- */
-/*      We are careful to only do the delete poDS after adjusting       */
-/*      the table, as if it is a virtual dataset, other removals may    */
-/*      happen in the meantime.  We are also careful to do this         */
-/*      outside the mutex protected loop as destroying a dataset can    */
-/*      take quite a while.                                             */
-/* -------------------------------------------------------------------- */
-    delete poDS;
+/************************************************************************/
+/*                             GetOpenDS()                              */
+/************************************************************************/
 
-    return OGRERR_NONE;
+OGRDataSource *OGRSFDriverRegistrar::GetOpenDS( CPL_UNUSED int iDS )
+{
+    CPLError(CE_Failure, CPLE_AppDefined, "Stub implementation in GDAL 2.0");
+    return NULL;
 }
 
 /************************************************************************/
-/*                        OGRReleaseDataSource()                        */
+/*                            OGRGetOpenDS()                            */
 /************************************************************************/
 
-OGRErr OGRReleaseDataSource( OGRDataSourceH hDS )
+OGRDataSourceH OGRGetOpenDS( int iDS )
 
 {
-    VALIDATE_POINTER1( hDS, "OGRReleaseDataSource", OGRERR_INVALID_HANDLE );
-
-    OGRSFDriverRegistrar::GetRegistrar();
-    return poRegistrar->ReleaseDataSource((OGRDataSource *) hDS);
+    return (OGRDataSourceH) OGRSFDriverRegistrar::GetRegistrar()->GetOpenDS( iDS );
 }
 
 /************************************************************************/
-/*                         OGRGetOpenDSCount()                          */
+/*                          OpenWithDriverArg()                         */
 /************************************************************************/
 
-int OGRGetOpenDSCount()
-
+GDALDataset* OGRSFDriverRegistrar::OpenWithDriverArg(GDALDriver* poDriver,
+                                                 GDALOpenInfo* poOpenInfo)
 {
-    OGRSFDriverRegistrar::GetRegistrar();
-    return poRegistrar->GetOpenDSCount();
+    OGRDataSource* poDS = (OGRDataSource*)
+                ((OGRSFDriver*)poDriver)->Open(poOpenInfo->pszFilename,
+                                        poOpenInfo->eAccess == GA_Update);
+    if( poDS != NULL )
+        poDS->SetDescription( poDS->GetName() );
+    return poDS;
 }
 
 /************************************************************************/
-/*                             GetOpenDS()                              */
+/*                          CreateVectorOnly()                          */
 /************************************************************************/
 
-OGRDataSource *OGRSFDriverRegistrar::GetOpenDS( int iDS )
-
+GDALDataset* OGRSFDriverRegistrar::CreateVectorOnly( GDALDriver* poDriver,
+                                                     const char * pszName,
+                                                     char ** papszOptions )
 {
-    CPLMutexHolderD( &hDRMutex );
-
-    if( iDS < 0 || iDS >= nOpenDSCount )
-        return NULL;
-    else
-        return papoOpenDS[iDS];
+    OGRDataSource* poDS = (OGRDataSource*)
+        ((OGRSFDriver*)poDriver)->CreateDataSource(pszName, papszOptions);
+    if( poDS != NULL && poDS->GetName() != NULL )
+        poDS->SetDescription( poDS->GetName() );
+    return poDS;
 }
 
 /************************************************************************/
-/*                            OGRGetOpenDS()                            */
+/*                          DeleteDataSource()                          */
 /************************************************************************/
 
-OGRDataSourceH OGRGetOpenDS( int iDS )
-
+CPLErr OGRSFDriverRegistrar::DeleteDataSource( GDALDriver* poDriver,
+                                              const char * pszName )
 {
-    OGRSFDriverRegistrar::GetRegistrar();
-    return (OGRDataSourceH) poRegistrar->GetOpenDS( iDS );
+    if( ((OGRSFDriver*)poDriver)->DeleteDataSource(pszName) == OGRERR_NONE )
+        return CE_None;
+    else
+        return CE_Failure;
 }
 
 /************************************************************************/
@@ -562,51 +260,40 @@ OGRDataSourceH OGRGetOpenDS( int iDS )
 void OGRSFDriverRegistrar::RegisterDriver( OGRSFDriver * poDriver )
 
 {
-    CPLMutexHolderD( &hDRMutex );
-    int         iDriver;
-
-/* -------------------------------------------------------------------- */
-/*      It has no effect to register a driver more than once.           */
-/* -------------------------------------------------------------------- */
-    for( iDriver = 0; iDriver < nDrivers; iDriver++ )
+    GDALDriver* poGDALDriver = (GDALDriver*) GDALGetDriverByName( poDriver->GetName() ) ;
+    if( poGDALDriver == NULL)
     {
-        if( poDriver == papoDrivers[iDriver] )
-            return;
+        poDriver->SetDescription( poDriver->GetName() );
+        poDriver->SetMetadataItem("OGR_DRIVER", "YES");
+
+        if( poDriver->GetMetadataItem(GDAL_DMD_LONGNAME) == NULL )
+            poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, poDriver->GetName() );
+
+        poDriver->pfnOpenWithDriverArg = OpenWithDriverArg;
 
-        /* Same name but different pointer. Likely a second call to OGRRegisterAll() */
-        /* We delete the new driver */
-        if (EQUAL(poDriver->GetName(), papoDrivers[iDriver]->GetName()))
+        if( poDriver->TestCapability(ODrCCreateDataSource) )
         {
-            delete poDriver;
-            return;
+            poDriver->SetMetadataItem( GDAL_DCAP_CREATE, "YES" );
+            poDriver->pfnCreateVectorOnly = CreateVectorOnly;
         }
-    }
+        if( poDriver->TestCapability(ODrCDeleteDataSource) )
+        {
+            poDriver->pfnDeleteDataSource = DeleteDataSource;
+        }
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
 
-/* -------------------------------------------------------------------- */
-/*      Skip and destroy drivers in the black list.                     */
-/* -------------------------------------------------------------------- */
-    char** papszSkipDrivers =
-            CSLTokenizeStringComplex(CPLGetConfigOption("OGR_SKIP", ""), ",", FALSE, FALSE);
-    char** iter = papszSkipDrivers;
-    while(*iter)
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+    else
     {
-        if (strcmp(*iter, poDriver->GetName()) == 0)
+        if( poGDALDriver->GetMetadataItem("OGR_DRIVER") == NULL)
         {
-            CSLDestroy(papszSkipDrivers);
-            delete poDriver;
-            return;
+            CPLError(CE_Failure, CPLE_AppDefined,
+                    "A non OGR driver is registered with the same name: %s", poDriver->GetName());
         }
-        iter ++;
+        delete poDriver;
     }
-    CSLDestroy(papszSkipDrivers);
-
-/* -------------------------------------------------------------------- */
-/*      Add to the end of the driver list.                              */
-/* -------------------------------------------------------------------- */
-    papoDrivers = (OGRSFDriver **)
-        CPLRealloc( papoDrivers, (nDrivers+1) * sizeof(void*) );
-
-    papoDrivers[nDrivers++] = poDriver;
 }
 
 /************************************************************************/
@@ -617,36 +304,8 @@ void OGRRegisterDriver( OGRSFDriverH hDriver )
 
 {
     VALIDATE_POINTER0( hDriver, "OGRRegisterDriver" );
-
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( 
-        (OGRSFDriver *) hDriver );
-}
-
-/************************************************************************/
-/*                          DeregisterDriver()                          */
-/************************************************************************/
-
-void OGRSFDriverRegistrar::DeregisterDriver( OGRSFDriver * poDriver )
-
-{
-    CPLMutexHolderD( &hDRMutex );
-    int         i;
-
-    for( i = 0; i < nDrivers; i++ )
-    {
-        if( poDriver == papoDrivers[i] )
-            break;
-    }
-
-    if (i == nDrivers)
-        return;
-
-    while( i < nDrivers-1 )
-    {
-        papoDrivers[i] = papoDrivers[i+1];
-        i++;
-    }
-    nDrivers--;
+    
+    GetGDALDriverManager()->RegisterDriver( (GDALDriver*)hDriver );
 }
 
 /************************************************************************/
@@ -657,9 +316,8 @@ void OGRDeregisterDriver( OGRSFDriverH hDriver )
 
 {
     VALIDATE_POINTER0( hDriver, "OGRDeregisterDriver" );
-
-    OGRSFDriverRegistrar::GetRegistrar()->DeregisterDriver( 
-        (OGRSFDriver *) hDriver );
+    
+    GetGDALDriverManager()->DeregisterDriver( (GDALDriver*)hDriver );
 }
 
 /************************************************************************/
@@ -669,7 +327,17 @@ void OGRDeregisterDriver( OGRSFDriverH hDriver )
 int OGRSFDriverRegistrar::GetDriverCount()
 
 {
-    return nDrivers;
+    /* We must be careful only to return drivers that are actual OGRSFDriver* */
+    GDALDriverManager* poDriverManager = GetGDALDriverManager();
+    int nTotal = poDriverManager->GetDriverCount();
+    int nOGRDriverCount = 0;
+    for(int i=0;i<nTotal;i++)
+    {
+        GDALDriver* poDriver = poDriverManager->GetDriver(i);
+        if( poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != NULL )
+            nOGRDriverCount ++;
+    }
+    return nOGRDriverCount;
 }
 
 /************************************************************************/
@@ -679,25 +347,31 @@ int OGRSFDriverRegistrar::GetDriverCount()
 int OGRGetDriverCount()
 
 {
-    if (poRegistrar)
-        return poRegistrar->GetDriverCount();
-
-    return 0;
+    return OGRSFDriverRegistrar::GetRegistrar()->GetDriverCount();
 }
 
 /************************************************************************/
 /*                             GetDriver()                              */
 /************************************************************************/
 
-OGRSFDriver *OGRSFDriverRegistrar::GetDriver( int iDriver )
+GDALDriver *OGRSFDriverRegistrar::GetDriver( int iDriver )
 
 {
-    CPLMutexHolderD( &hDRMutex );
-
-    if( iDriver < 0 || iDriver >= nDrivers )
-        return NULL;
-    else
-        return papoDrivers[iDriver];
+    /* We must be careful only to return drivers that are actual OGRSFDriver* */
+    GDALDriverManager* poDriverManager = GetGDALDriverManager();
+    int nTotal = poDriverManager->GetDriverCount();
+    int nOGRDriverCount = 0;
+    for(int i=0;i<nTotal;i++)
+    {
+        GDALDriver* poDriver = poDriverManager->GetDriver(i);
+        if( poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) != NULL )
+        {
+            if( nOGRDriverCount == iDriver )
+                return poDriver;
+            nOGRDriverCount ++;
+        }
+    }
+    return NULL;
 }
 
 /************************************************************************/
@@ -707,28 +381,25 @@ OGRSFDriver *OGRSFDriverRegistrar::GetDriver( int iDriver )
 OGRSFDriverH OGRGetDriver( int iDriver )
 
 {
-    VALIDATE_POINTER1( poRegistrar, "OGRGetDriver", NULL );
-
-    return (OGRSFDriverH) poRegistrar->GetDriver( iDriver );
+    return (OGRSFDriverH) OGRSFDriverRegistrar::GetRegistrar()->GetDriver( iDriver );
 }
 
 /************************************************************************/
 /*                          GetDriverByName()                           */
 /************************************************************************/
 
-OGRSFDriver *OGRSFDriverRegistrar::GetDriverByName( const char * pszName )
+GDALDriver *OGRSFDriverRegistrar::GetDriverByName( const char * pszName )
 
 {
-    CPLMutexHolderD( &hDRMutex );
-
-    for( int i = 0; i < nDrivers; i++ )
-    {
-        if( papoDrivers[i] != NULL 
-            && EQUAL(papoDrivers[i]->GetName(),pszName) )
-            return papoDrivers[i];
-    }
-
-    return NULL;
+    GDALDriverManager* poDriverManager = GetGDALDriverManager();
+    GDALDriver* poGDALDriver =
+        poDriverManager->GetDriverByName(CPLSPrintf("OGR_%s", pszName));
+    if( poGDALDriver == NULL )
+        poGDALDriver = poDriverManager->GetDriverByName(pszName);
+    if( poGDALDriver == NULL ||
+        poGDALDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == NULL )
+        return NULL;
+    return poGDALDriver;
 }
 
 /************************************************************************/
@@ -743,179 +414,3 @@ OGRSFDriverH OGRGetDriverByName( const char *pszName )
     return (OGRSFDriverH) 
         OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName( pszName );
 }
-
-/************************************************************************/
-/*                          AutoLoadDrivers()                           */
-/************************************************************************/
-
-/**
- * \brief Auto-load GDAL drivers from shared libraries.
- *
- * This function will automatically load drivers from shared libraries.  It
- * searches the "driver path" for .so (or .dll) files that start with the
- * prefix "ogr_X.so".  It then tries to load them and then tries to call
- * a function within them called RegisterOGRX() where the 'X' is the same 
- * as the remainder of the shared library basename, or failing that to 
- * call GDALRegisterMe().  
- *
- * There are a few rules for the driver path.  If the GDAL_DRIVER_PATH 
- * environment variable it set, it is taken to be a list of directories to 
- * search separated by colons on unix, or semi-colons on Windows.  
- * 
- * Auto loading can be completely disabled by setting the GDAL_DRIVER_PATH
- * config option to "disable".
- *
- * If that is not set the following defaults are used:
- *
- * <ul>
- * <li> Linux/Unix: <prefix>/lib/gdalplugins is searched or
- * /usr/local/lib/gdalplugins if the install prefix is not known.
- * <li> MacOSX: <prefix>/PlugIns is searched, or /usr/local/lib/gdalplugins if
- * the install prefix is not known.  Also, the framework directory
- * /Library/Application Support/GDAL/PlugIns is searched.
- * <li> Win32: <prefix>/lib/gdalplugins if the prefix is known (normally it
- * is not), otherwise the gdalplugins subdirectory of the directory containing
- * the currently running executable is used. 
- * </ul>
- */
-
-void OGRSFDriverRegistrar::AutoLoadDrivers()
-
-{
-    char     **papszSearchPath = NULL;
-    const char *pszGDAL_DRIVER_PATH = 
-        CPLGetConfigOption( "OGR_DRIVER_PATH", NULL );
-
-    if( pszGDAL_DRIVER_PATH == NULL )
-        pszGDAL_DRIVER_PATH = 
-            CPLGetConfigOption( "GDAL_DRIVER_PATH", NULL );
-
-/* -------------------------------------------------------------------- */
-/*      Allow applications to completely disable this search by         */
-/*      setting the driver path to the special string "disable".        */
-/* -------------------------------------------------------------------- */
-    if( pszGDAL_DRIVER_PATH != NULL && EQUAL(pszGDAL_DRIVER_PATH,"disable")) 
-    {
-        CPLDebug( "GDAL", "OGRSFDriverRegistrar::AutoLoadDrivers() disabled." );
-        return;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Where should we look for stuff?                                 */
-/* -------------------------------------------------------------------- */
-    if( pszGDAL_DRIVER_PATH != NULL )
-    {
-#ifdef WIN32
-        papszSearchPath = 
-            CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ";", TRUE, FALSE );
-#else
-        papszSearchPath = 
-            CSLTokenizeStringComplex( pszGDAL_DRIVER_PATH, ":", TRUE, FALSE );
-#endif
-    }
-    else
-    {
-#ifdef GDAL_PREFIX
-        papszSearchPath = CSLAddString( papszSearchPath,
-    #ifdef MACOSX_FRAMEWORK
-                                        GDAL_PREFIX "/PlugIns");
-    #else
-                                        GDAL_PREFIX "/lib/gdalplugins" );
-    #endif
-#else
-        char szExecPath[1024];
-
-        if( CPLGetExecPath( szExecPath, sizeof(szExecPath) ) )
-        {
-            char szPluginDir[sizeof(szExecPath)+50];
-            strcpy( szPluginDir, CPLGetDirname( szExecPath ) );
-            strcat( szPluginDir, "\\gdalplugins\\" );
-            papszSearchPath = CSLAddString( papszSearchPath, szPluginDir );
-        }
-        else
-        {
-            papszSearchPath = CSLAddString( papszSearchPath, 
-                                            "/usr/local/lib/gdalplugins" );
-        }
-#endif 
-
-#ifdef MACOSX_FRAMEWORK
-#define num2str(x) str(x)
-#define str(x) #x 
-        papszSearchPath = CSLAddString( papszSearchPath, 
-                                        "/Library/Application Support/GDAL/"
-                                        num2str(GDAL_VERSION_MAJOR) "."
-                                        num2str(GDAL_VERSION_MINOR) "/PlugIns" );
-#endif
-
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Format the ABI version specific subdirectory to look in.        */
-/* -------------------------------------------------------------------- */
-    CPLString osABIVersion;
-
-    osABIVersion.Printf( "%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR );
-
-/* -------------------------------------------------------------------- */
-/*      Scan each directory looking for files starting with ogr_        */
-/* -------------------------------------------------------------------- */
-    for( int iDir = 0; iDir < CSLCount(papszSearchPath); iDir++ )
-    {
-        char **papszFiles = NULL;
-        VSIStatBufL sStatBuf;
-        CPLString osABISpecificDir =
-            CPLFormFilename( papszSearchPath[iDir], osABIVersion, NULL );
-        
-        if( VSIStatL( osABISpecificDir, &sStatBuf ) != 0 )
-            osABISpecificDir = papszSearchPath[iDir];
-
-        papszFiles = CPLReadDir( osABISpecificDir );
-
-        for( int iFile = 0; iFile < CSLCount(papszFiles); iFile++ )
-        {
-            char   *pszFuncName;
-            const char *pszFilename;
-            const char *pszExtension = CPLGetExtension( papszFiles[iFile] );
-            void   *pRegister;
-
-            if( !EQUALN(papszFiles[iFile],"ogr_",4) )
-                continue;
-
-            if( !EQUAL(pszExtension,"dll") 
-                && !EQUAL(pszExtension,"so") 
-                && !EQUAL(pszExtension,"dylib") )
-                continue;
-
-            pszFuncName = (char *) CPLCalloc(strlen(papszFiles[iFile])+20,1);
-            sprintf( pszFuncName, "RegisterOGR%s", 
-                     CPLGetBasename(papszFiles[iFile]) + 4 );
-            
-            pszFilename = 
-                CPLFormFilename( osABISpecificDir,
-                                 papszFiles[iFile], NULL );
-
-            pRegister = CPLGetSymbol( pszFilename, pszFuncName );
-            if( pRegister == NULL )
-            {
-                strcpy( pszFuncName, "GDALRegisterMe" );
-                pRegister = CPLGetSymbol( pszFilename, pszFuncName );
-            }
-            
-            if( pRegister != NULL )
-            {
-                CPLDebug( "OGR", "Auto register %s using %s.", 
-                          pszFilename, pszFuncName );
-
-                ((void (*)()) pRegister)();
-            }
-
-            CPLFree( pszFuncName );
-        }
-
-        CSLDestroy( papszFiles );
-    }
-
-    CSLDestroy( papszSearchPath );
-}
-
diff --git a/ogr/ogrsf_frmts/generic/ogrunionlayer.cpp b/ogr/ogrsf_frmts/generic/ogrunionlayer.cpp
index a633d2a..5f1b199 100644
--- a/ogr/ogrsf_frmts/generic/ogrunionlayer.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrunionlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrunionlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrunionlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRUnionLayer class
@@ -31,7 +31,7 @@
 #include "ogrwarpedlayer.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrunionlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrunionlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                      OGRUnionLayerGeomFieldDefn()                    */
@@ -86,6 +86,8 @@ OGRUnionLayer::OGRUnionLayer( const char* pszName,
                               int bTakeLayerOwnership )
 {
     CPLAssert(nSrcLayersIn > 0);
+    
+    SetDescription( pszName );
 
     osName = pszName;
     nSrcLayers = nSrcLayersIn;
@@ -225,8 +227,19 @@ static void MergeFieldDefn(OGRFieldDefn* poFieldDefn,
     if( poFieldDefn->GetType() != poSrcFieldDefn->GetType() )
     {
         if( poSrcFieldDefn->GetType() == OFTReal &&
-            poFieldDefn->GetType() == OFTInteger)
+            (poFieldDefn->GetType() == OFTInteger ||
+             poFieldDefn->GetType() == OFTInteger64) )
+            poFieldDefn->SetType(OFTReal);
+        if( poFieldDefn->GetType() == OFTReal &&
+            (poSrcFieldDefn->GetType() == OFTInteger ||
+             poSrcFieldDefn->GetType() == OFTInteger64) )
             poFieldDefn->SetType(OFTReal);
+        else if( poSrcFieldDefn->GetType() == OFTInteger64 &&
+                 poFieldDefn->GetType() == OFTInteger)
+            poFieldDefn->SetType(OFTInteger64);
+        else if( poFieldDefn->GetType() == OFTInteger64 &&
+                 poSrcFieldDefn->GetType() == OFTInteger)
+            poFieldDefn->SetType(OFTInteger64);
         else
             poFieldDefn->SetType(OFTString);
     }
@@ -632,14 +645,14 @@ void OGRUnionLayer::AutoWarpLayerIfNecessary(int iLayer)
                     (poSRS != NULL && poSRS2 == NULL) )
                 {
                     CPLError(CE_Warning, CPLE_AppDefined,
-                            "SRS of geometry field '%s' layer %s not consistant with UnionLayer SRS",
+                            "SRS of geometry field '%s' layer %s not consistent with UnionLayer SRS",
                             GetLayerDefn()->GetGeomFieldDefn(i)->GetNameRef(),
                             papoSrcLayers[iLayer]->GetName());
                 }
                 else if (poSRS != NULL && poSRS2 != NULL &&
                         poSRS != poSRS2 && !poSRS->IsSame(poSRS2))
                 {
-                    CPLDebug("VRT", "SRS of geometry field '%s' layer %s not consistant with UnionLayer SRS. "
+                    CPLDebug("VRT", "SRS of geometry field '%s' layer %s not consistent with UnionLayer SRS. "
                             "Trying auto warping",
                             GetLayerDefn()->GetGeomFieldDefn(i)->GetNameRef(),
                             papoSrcLayers[iLayer]->GetName());
@@ -707,7 +720,7 @@ OGRFeature *OGRUnionLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRUnionLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRUnionLayer::GetFeature( GIntBig nFeatureId )
 {
     OGRFeature* poFeature = NULL;
 
@@ -747,10 +760,10 @@ OGRFeature *OGRUnionLayer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                          CreateFeature()                             */
+/*                          ICreateFeature()                             */
 /************************************************************************/
 
-OGRErr OGRUnionLayer::CreateFeature( OGRFeature* poFeature )
+OGRErr OGRUnionLayer::ICreateFeature( OGRFeature* poFeature )
 {
     if( osSourceLayerFieldName.size() == 0 )
     {
@@ -799,10 +812,10 @@ OGRErr OGRUnionLayer::CreateFeature( OGRFeature* poFeature )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRUnionLayer::SetFeature( OGRFeature* poFeature )
+OGRErr OGRUnionLayer::ISetFeature( OGRFeature* poFeature )
 {
     if( !bPreserveSrcFID )
     {
@@ -943,7 +956,7 @@ void OGRUnionLayer::ApplyAttributeFilterToSrcLayer(int iSubLayer)
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRUnionLayer::GetFeatureCount( int bForce )
+GIntBig OGRUnionLayer::GetFeatureCount( int bForce )
 {
     if (nFeatureCount >= 0 &&
         m_poFilterGeom == NULL && m_poAttrQuery == NULL)
@@ -954,7 +967,7 @@ int OGRUnionLayer::GetFeatureCount( int bForce )
     if( !GetAttrFilterPassThroughValue() )
         return OGRLayer::GetFeatureCount(bForce);
 
-    int nRet = 0;
+    GIntBig nRet = 0;
     for(int i = 0; i < nSrcLayers; i++)
     {
         AutoWarpLayerIfNecessary(i);
@@ -1101,6 +1114,9 @@ int  OGRUnionLayer::TestCapability( const char * pszCap )
     if( EQUAL(pszCap, OLCIgnoreFields) )
         return TRUE;
 
+    if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
+
     return FALSE;
 }
 
diff --git a/ogr/ogrsf_frmts/generic/ogrunionlayer.h b/ogr/ogrsf_frmts/generic/ogrunionlayer.h
index 5a93946..a245958 100644
--- a/ogr/ogrsf_frmts/generic/ogrunionlayer.h
+++ b/ogr/ogrsf_frmts/generic/ogrunionlayer.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrunionlayer.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrunionlayer.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRUnionLayer class
@@ -80,7 +80,7 @@ class OGRUnionLayer : public OGRLayer
 
     int                 bPreserveSrcFID;
 
-    int                 nFeatureCount;
+    GIntBig             nFeatureCount;
 
     int                 iCurLayer;
     char               *pszAttributeFilter;
@@ -102,7 +102,7 @@ class OGRUnionLayer : public OGRLayer
   public:
                         OGRUnionLayer( const char* pszName,
                                        int nSrcLayers, /* must be >= 1 */
-                                       OGRLayer** papoSrcLayers, /* array itself ownership always transfered, layer ownership depending on bTakeLayerOwnership */
+                                       OGRLayer** papoSrcLayers, /* array itself ownership always transferred, layer ownership depending on bTakeLayerOwnership */
                                        int bTakeLayerOwnership);
 
     virtual             ~OGRUnionLayer();
@@ -123,17 +123,17 @@ class OGRUnionLayer : public OGRLayer
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
-    virtual OGRErr      CreateFeature( OGRFeature* poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature* poFeature );
 
-    virtual OGRErr      SetFeature( OGRFeature* poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature* poFeature );
 
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
diff --git a/ogr/ogrsf_frmts/generic/ogrwarpedlayer.cpp b/ogr/ogrsf_frmts/generic/ogrwarpedlayer.cpp
index 408da69..a3f0e6b 100644
--- a/ogr/ogrsf_frmts/generic/ogrwarpedlayer.cpp
+++ b/ogr/ogrsf_frmts/generic/ogrwarpedlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrwarpedlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrwarpedlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRWarpedLayer class
@@ -29,7 +29,7 @@
 
 #include "ogrwarpedlayer.h"
 
-CPL_CVSID("$Id: ogrwarpedlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrwarpedlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRWarpedLayer()                            */
@@ -47,6 +47,7 @@ OGRWarpedLayer::OGRWarpedLayer( OGRLayer* poDecoratedLayer,
                                       m_poReversedCT(poReversedCT)
 {
     CPLAssert(poCT != NULL);
+    SetDescription( poDecoratedLayer->GetDescription() );
 
     m_poFeatureDefn = NULL;
 
@@ -244,7 +245,7 @@ OGRFeature *OGRWarpedLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRWarpedLayer::GetFeature( long nFID )
+OGRFeature *OGRWarpedLayer::GetFeature( GIntBig nFID )
 {
     OGRFeature* poFeature = m_poDecoratedLayer->GetFeature(nFID);
     if( poFeature != NULL )
@@ -257,10 +258,10 @@ OGRFeature *OGRWarpedLayer::GetFeature( long nFID )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr      OGRWarpedLayer::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRWarpedLayer::ISetFeature( OGRFeature *poFeature )
 {
     OGRErr eErr;
 
@@ -276,10 +277,10 @@ OGRErr      OGRWarpedLayer::SetFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                            CreateFeature()                           */
+/*                            ICreateFeature()                           */
 /************************************************************************/
 
-OGRErr      OGRWarpedLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr      OGRWarpedLayer::ICreateFeature( OGRFeature *poFeature )
 {
     OGRErr eErr;
 
@@ -328,7 +329,7 @@ OGRSpatialReference *OGRWarpedLayer::GetSpatialRef()
 /*                           GetFeatureCount()                          */
 /************************************************************************/
 
-int OGRWarpedLayer::GetFeatureCount( int bForce )
+GIntBig OGRWarpedLayer::GetFeatureCount( int bForce )
 {
     if( m_poFilterGeom == NULL )
         return m_poDecoratedLayer->GetFeatureCount(bForce);
diff --git a/ogr/ogrsf_frmts/generic/ogrwarpedlayer.h b/ogr/ogrsf_frmts/generic/ogrwarpedlayer.h
index 755b694..7619981 100644
--- a/ogr/ogrsf_frmts/generic/ogrwarpedlayer.h
+++ b/ogr/ogrsf_frmts/generic/ogrwarpedlayer.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrwarpedlayer.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrwarpedlayer.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines OGRWarpedLayer class
@@ -73,15 +73,15 @@ class OGRWarpedLayer : public OGRLayerDecorator
                                               double dfMaxX, double dfMaxY );
 
     virtual OGRFeature *GetNextFeature();
-    virtual OGRFeature *GetFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
diff --git a/ogr/ogrsf_frmts/geoconcept/GNUmakefile b/ogr/ogrsf_frmts/geoconcept/GNUmakefile
index 6788fa7..42d3bdc 100644
--- a/ogr/ogrsf_frmts/geoconcept/GNUmakefile
+++ b/ogr/ogrsf_frmts/geoconcept/GNUmakefile
@@ -3,7 +3,7 @@ include ../../../GDALmake.opt
 OBJ	=	geoconcept.o geoconcept_syscoord.o \
 		ogrgeoconceptdriver.o ogrgeoconceptdatasource.o ogrgeoconceptlayer.o
 
-CPPFLAGS	:=	-DUSE_CPL -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-DUSE_CPL -I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept.c b/ogr/ogrsf_frmts/geoconcept/geoconcept.c
index e86b021..0273865 100644
--- a/ogr/ogrsf_frmts/geoconcept/geoconcept.c
+++ b/ogr/ogrsf_frmts/geoconcept/geoconcept.c
@@ -3964,7 +3964,7 @@ static OGRErr GCIOAPI_CALL _readConfigMap_GCIO (
             res= OGRERR_CORRUPT_DATA;
             goto onError;
           }
-          if( sscanf(k,"%lf", &r)!=1 )
+          if( CPLsscanf(k,"%lf", &r)!=1 )
           {
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Invalid Precision found : '%s'.\n",
@@ -4720,8 +4720,8 @@ GCField GCIOAPI_CALL1(*) FindFeatureField_GCIO (
 
 /* -------------------------------------------------------------------- */
 static char GCIOAPI_CALL1(*) _escapeString_GCIO (
-                                                 CPL_UNUSED GCExportFileH* H,
-                                                 const char *theString
+                                                  CPL_UNUSED GCExportFileH* H,
+                                                  const char *theString
                                                 )
 {
   int l, i, o;
diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c b/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c
index 455d788..c749ac9 100644
--- a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c
+++ b/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c
@@ -987,7 +987,7 @@ OGRSpatialReferenceH GCSRSAPI_CALL SysCoord2OGRSpatialReference_GCSRS ( GCSysCoo
                        GetInfoSpheroidID_GCSRS(ell)>=0? (f==0? 0:1/f):298.257223563,
                        "Greenwich",
                        GetSysCoordPrimeMeridian_GCSRS(syscoord),
-                       SRS_UA_DEGREE, atof(SRS_UA_DEGREE_CONV));
+                       SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV));
     /* As Geoconcept uses Molodensky, we've got only 3 out of 7 params for Bursa-Wolf : */
     /* the 4 missing Bursa-Wolf parameters have been added to the gk_asDatumList !      */
     if( GetInfoProjID_GCSRS(syscoord)>0 && GetInfoDatumID_GCSRS(datum)!=-1 )
diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp
index 69689f1..98cb67f 100644
--- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp
+++ b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp
@@ -112,15 +112,6 @@ int OGRGeoconceptDataSource::Open( const char* pszName, int bTestOpen, int bUpda
 
 {
 /* -------------------------------------------------------------------- */
-/*      We will only consider .gxt and .txt files.                      */
-/* -------------------------------------------------------------------- */
-    const char* pszExtension = CPLGetExtension(pszName);
-    if( !EQUAL(pszExtension,"gxt") && !EQUAL(pszExtension,"txt") )
-    {
-        return FALSE;
-    }
-
-/* -------------------------------------------------------------------- */
 /*      Is the given path a directory or a regular file?                */
 /* -------------------------------------------------------------------- */
     VSIStatBuf  stat;
@@ -309,7 +300,7 @@ int OGRGeoconceptDataSource::Create( const char *pszName, char** papszOptions )
 
 /* -------------------------------------------------------------------- */
 /*      Create a new single file.                                       */
-/*      OGRGeoconceptDriver::CreateLayer() will do the job.             */
+/*      OGRGeoconceptDriver::ICreateLayer() will do the job.             */
 /* -------------------------------------------------------------------- */
     _bSingleNewFile = TRUE;
 
@@ -326,13 +317,13 @@ int OGRGeoconceptDataSource::Create( const char *pszName, char** papszOptions )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /*                                                                      */
 /* Options (-lco) :                                                     */
 /*   FEATURETYPE : TYPE.SUBTYPE                                         */
 /************************************************************************/
 
-OGRLayer *OGRGeoconceptDataSource::CreateLayer( const char * pszLayerName,
+OGRLayer *OGRGeoconceptDataSource::ICreateLayer( const char * pszLayerName,
                                                 OGRSpatialReference *poSRS /* = NULL */,
                                                 OGRwkbGeometryType eType /* = wkbUnknown */,
                                                 char ** papszOptions /* = NULL */ )
diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h
index 7394eaf..bb166bf 100644
--- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h
+++ b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h
@@ -65,7 +65,7 @@ class OGRGeoconceptDataSource : public OGRDataSource
 //    OGRErr         DeleteLayer( int iLayer );
     int            TestCapability( const char* pszCap );
 
-    OGRLayer*      CreateLayer( const char* pszName, 
+    OGRLayer*      ICreateLayer( const char* pszName, 
                                 OGRSpatialReference* poSpatialRef = NULL,
                                 OGRwkbGeometryType eGType = wkbUnknown,
                                 char** papszOptions = NULL );
diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp
index 0cb909d..32c5f7a 100644
--- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp
+++ b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp
@@ -64,6 +64,15 @@ OGRDataSource *OGRGeoconceptDriver::Open( const char* pszFilename,
 {
     OGRGeoconceptDataSource  *poDS;
 
+/* -------------------------------------------------------------------- */
+/*      We will only consider .gxt and .txt files.                      */
+/* -------------------------------------------------------------------- */
+    const char* pszExtension = CPLGetExtension(pszFilename);
+    if( !EQUAL(pszExtension,"gxt") && !EQUAL(pszExtension,"txt") )
+    {
+        return NULL;
+    }
+
     poDS = new OGRGeoconceptDataSource();
 
     if( !poDS->Open( pszFilename, TRUE, bUpdate ) )
@@ -236,5 +245,22 @@ int OGRGeoconceptDriver::TestCapability( const char * pszCap )
 void RegisterOGRGeoconcept()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGeoconceptDriver );
+    OGRSFDriver* poDriver = new OGRGeoconceptDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "gxt txt" );
+
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='EXTENSION' type='string-select' description='indicates the GeoConcept export file extension. TXT was used by earlier releases of GeoConcept. GXT is currently used.' default='GXT'>"
+"    <Value>GXT</Value>"
+"    <Value>TXT</Value>"
+"  </Option>"
+"  <Option name='CONFIG' type='string' description='path to the GCT file that describes the GeoConcept types definitions.'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='FEATURETYPE' type='string' description='TYPE.SUBTYPE : defines the feature to be created. The TYPE corresponds to one of the Name found in the GCT file for a type section. The SUBTYPE corresponds to one of the Name found in the GCT file for a sub-type section within the previous type section'/>"
+"</LayerCreationOptionList>");
+
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
 }
diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp
index 0e97b18..ed22dc2 100644
--- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp
+++ b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp
@@ -88,6 +88,7 @@ OGRErr OGRGeoconceptLayer::Open( GCSubType* Subclass )
       pszln[511]='\0';
 
       _poFeatureDefn = new OGRFeatureDefn(pszln);
+      SetDescription( _poFeatureDefn->GetName() );
       _poFeatureDefn->Reference();
       _poFeatureDefn->SetGeomType(wkbUnknown);
 
@@ -178,7 +179,7 @@ OGRFeature *OGRGeoconceptLayer::GetNextFeature()
     }
 
     CPLDebug( "GEOCONCEPT",
-              "FID : %ld\n"
+              "FID : " CPL_FRMT_GIB "\n"
               "%s  : %s",
               poFeature? poFeature->GetFID():-1L,
               poFeature && poFeature->GetFieldCount()>0? poFeature->GetFieldDefnRef(0)->GetNameRef():"-",
@@ -204,10 +205,10 @@ static char* OGRGeoconceptLayer_GetCompatibleFieldName(const char* pszName)
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGeoconceptLayer::CreateFeature( OGRFeature* poFeature )
+OGRErr OGRGeoconceptLayer::ICreateFeature( OGRFeature* poFeature )
 
 {
     OGRwkbGeometryType eGt;
@@ -351,7 +352,7 @@ OGRErr OGRGeoconceptLayer::CreateFeature( OGRFeature* poFeature )
       for( iGeom= 0; iGeom<nbGeom; iGeom++ )
       {
         nextField= StartWritingFeature_GCIO(_gcFeature,
-                                            isSingle? poFeature->GetFID():OGRNullFID);
+                                            isSingle? (int)poFeature->GetFID():OGRNullFID);
         while (nextField!=WRITECOMPLETED_GCIO)
         {
           if( nextField==WRITEERROR_GCIO )
@@ -432,7 +433,7 @@ OGRSpatialReference *OGRGeoconceptLayer::GetSpatialRef()
 /*      the generic counter.  Otherwise we return the total count.      */
 /************************************************************************/
 
-int OGRGeoconceptLayer::GetFeatureCount( int bForce )
+GIntBig OGRGeoconceptLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
@@ -445,7 +446,8 @@ int OGRGeoconceptLayer::GetFeatureCount( int bForce )
 /*                             GetExtent()                              */
 /************************************************************************/
 
-OGRErr OGRGeoconceptLayer::GetExtent( OGREnvelope* psExtent, CPL_UNUSED int bForce )
+OGRErr OGRGeoconceptLayer::GetExtent( OGREnvelope* psExtent,
+                                      CPL_UNUSED int bForce )
 {
     GCExtent* theExtent;
 
@@ -500,7 +502,8 @@ int OGRGeoconceptLayer::TestCapability( const char* pszCap )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRGeoconceptLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRGeoconceptLayer::CreateField( OGRFieldDefn *poField,
+                                        CPL_UNUSED int bApproxOK )
 {
     if( GetGCMode_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature))==vReadAccess_GCIO )
     {
diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h
index 0e6aa2c..72b2f2e 100644
--- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h
+++ b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h
@@ -56,15 +56,15 @@ class OGRGeoconceptLayer : public OGRLayer
 //    OGRErr               SetAttributeFilter( const char* pszQuery );
     void                 ResetReading();
     OGRFeature*          GetNextFeature();
-//    OGRErr               SetNextByIndex( long nIndex );
+//    OGRErr               SetNextByIndex( GIntBig nIndex );
 
-//    OGRFeature*          GetFeature( long nFID );
-//    OGRErr               SetFeature( OGRFeature* poFeature );
-//    OGRErr               DeleteFeature( long nFID );
-    OGRErr               CreateFeature( OGRFeature* poFeature );
+//    OGRFeature*          GetFeature( GIntBig nFID );
+//    OGRErr               ISetFeature( OGRFeature* poFeature );
+//    OGRErr               DeleteFeature( GIntBig nFID );
+    OGRErr               ICreateFeature( OGRFeature* poFeature );
     OGRFeatureDefn*      GetLayerDefn( ) { return _poFeatureDefn; } // FIXME
     OGRSpatialReference* GetSpatialRef( );
-    int                  GetFeatureCount( int bForce = TRUE );
+    GIntBig              GetFeatureCount( int bForce = TRUE );
     OGRErr               GetExtent( OGREnvelope *psExtent, int bForce = TRUE );
     int                  TestCapability( const char* pszCap );
 //    const char*          GetInfo( const char* pszTag );
diff --git a/ogr/ogrsf_frmts/geojson/GNUmakefile b/ogr/ogrsf_frmts/geojson/GNUmakefile
index f4e4a61..9e0cd5d 100644
--- a/ogr/ogrsf_frmts/geojson/GNUmakefile
+++ b/ogr/ogrsf_frmts/geojson/GNUmakefile
@@ -19,7 +19,7 @@ OBJ = \
 	ogresrijsonreader.o \
 	ogrtopojsonreader.o
 
-CPPFLAGS	:= $(JSON_INCLUDE) -I. -I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:= $(JSON_INCLUDE) -I. -I.. -I../..  $(CPPFLAGS)
 
 default:        $(foreach d,$(SUBDIRS-yes),$(d)-target) $(O_OBJ:.o=.$(OBJ_EXT))
 
@@ -27,4 +27,4 @@ clean: $(foreach d,$(SUBDIRS-yes),$(d)-clean)
 	rm -f *.o $(O_OBJ)
 	rm -f *~
 
-$(O_OBJ):       ogr_geojson.h
+$(O_OBJ):       ogr_geojson.h ogrgeojsonreader.h
diff --git a/ogr/ogrsf_frmts/geojson/drv_geojson.html b/ogr/ogrsf_frmts/geojson/drv_geojson.html
index 6fd5630..19ddb2a 100644
--- a/ogr/ogrsf_frmts/geojson/drv_geojson.html
+++ b/ogr/ogrsf_frmts/geojson/drv_geojson.html
@@ -12,17 +12,25 @@
 <a href="http://json.org/">JavaScript Object Notation (JSON)</a>. The JSON is a lightweight 
 plain text format for data interchange and GeoJSON is nothing other than its specialization for geographic content.</p>
 
-<p>At the moment of writing this, GeoJSON is supported as output format of services implemented by 
-<a href="http://featureserver.org/">FeatureServer</a>, <a href="http://docs.codehaus.org/display/GEOSDOC/GeoJSON+Output+Format">GeoServer</a> 
-and <a href="http://exportgge.sourceforge.net/kml/">CartoWeb</a>.</p>
+<p>GeoJSON is supported as output format of a number of services :
+<a href="http://featureserver.org/">FeatureServer</a>,
+<a href="http://docs.geoserver.org/2.6.x/en/user/services/wfs/outputformats.html">GeoServer</a> ,
+<a href="http://exportgge.sourceforge.net/kml/">CartoWeb</a>, etc...</p>
 
 <p>The OGR GeoJSON driver translates a GeoJSON encoded data to objects of <a href="/ogr/ogr_arch.html">OGR Simple Features model</a>: 
 Datasource, Layer, Feature, Geometry. 
-The implementation is based on <a href="http://wiki.geojson.org/GeoJSON_draft_version_5">GeoJSON Specification draft, v5.0</a>.</p>
+The implementation is based on <a href="http://geojson.org/geojson-spec.html">GeoJSON Specification, v1.0</a>.</p>
 
 <p>Starting with OGR 1.8.0, the GeoJSON driver can read the JSON output of Feature Service request following the
 <a href="http://www.esri.com/industries/landing-pages/geoservices/geoservices.html">GeoServices REST Specification<a/>, like
-implemented by <a href="http://help.arcgis.com/en/arcgisserver/10.0/apis/rest/index.html">ArcGIS Server REST API</a></p>
+implemented by <a href="http://help.arcgis.com/en/arcgisserver/10.0/apis/rest/index.html">ArcGIS Server REST API</a>.
+And starting with OGR 2.0, the GeoJSON driver can scroll through such result sets that
+are spread over multiple pages (for ArcGIS servers >= 10.3). This is automatically enabled
+if URL does not contain an explicit <i>resultOffset</i> parameter. If it contains
+this parameter and scrolling is still desired, the FEATURE_SERVER_PAGING open option must be set to YES.
+The page size can be explicitely set with the <i>resultRecordCount</i> parameter (but
+is subject to a server limit). If it is not set, OGR will set it to the maximum
+value allowed by the server.</p>
 
 <p>Starting with OGR 1.11, the GeoJSON driver can read the <a href="https://github.com/mbostock/topojson/wiki/Specification">TopoJSON format</a></p>
 
@@ -30,7 +38,7 @@ implemented by <a href="http://help.arcgis.com/en/arcgisserver/10.0/apis/rest/in
 
 <p>The OGR GeoJSON driver accepts three types of sources of data:
 <ul>
-    <li>Uniform Resource Locator (<a href="http://en.wikipedia.org/wiki/URL">URL</a>) - a Web address to 
+<li>Uniform Resource Locator (<a href="http://en.wikipedia.org/wiki/URL">URL</a>) - a Web address to 
     perform <a href="http://en.wikipedia.org/wiki/HTTP">HTTP</a> request</li>
 <li>Plain text file with GeoJSON data - identified from the file extension .geojson or .json</li>
 <li>Text passed directly and encoded in GeoJSON</li>
@@ -65,6 +73,9 @@ have the same schema of properties. If <em>Feature</em> objects in a set defined
 object have different schema of properties, then resulting schema of fields in OGRFeatureDefn is generated as 
 <a href="http://en.wikipedia.org/wiki/Union_(set_theory)">union</a> of all <em>Feature</em> properties.</p>
 
+<p>Schema detection will recognized fields of type String, Integer, Real, StringList, IntegerList and RealList.
+Starting with GDAL 2.0, Integer(Boolean), Date, Time and DateTime fields are also recognized.</p>
+
 <p>It is possible to tell the driver to not to process attributes by setting environment variable 
 <strong>ATTRIBUTES_SKIP=YES</strong>. Default behavior is to preserve all attributes (as an union, see previous paragraph), 
 what is equal to setting <strong>ATTRIBUTES_SKIP=NO</strong>.</p>
@@ -87,6 +98,54 @@ This behavior may be controlled by setting environment variable <strong>GEOMETRY
 <li><b>ATTRIBUTES_SKIP</b> - controls translation of attributes: YES - skip all attributes</li>
 </ul>
 
+<h2>Open options</h2>
+
+<p>(GDAL >= 2.0)</p>
+
+<ul>
+<li><b>FLATTEN_NESTED_ATTRIBUTES</b> = YES/NO : Whether to
+recursively explore nested objects and produce flatten OGR attributes. Defaults to NO.</li>
+<li><b>NESTED_ATTRIBUTE_SEPARATOR</b> = character : Separator between components
+of nested attributes. Defaults to '_'</li>
+<li><b>FEATURE_SERVER_PAGING</b> = YES/NO: Whether to automatically scroll through
+results with a ArcGIS Feature Service endpoint.</li>
+</ul>
+
+<p>To explain FLATTEN_NESTED_ATTRIBUTES, consider the following GeoJSON fragment :</p>
+
+<pre>
+{
+  "type": "FeatureCollection",
+  "features" :
+  [
+    {
+      "type": "Feature",
+      "geometry": {
+        "type": "Point",
+        "coordinates": [ 2, 49 ]
+      }, 
+      "properties": {
+        "a_property": "foo", 
+        "some_object": {
+          "a_property": 1, 
+          "another_property": 2 
+        }
+      }
+    }
+  ]
+}
+</pre>
+
+<p> "ogrinfo test.json -al -oo FLATTEN_NESTED_ATTRIBUTES=yes" reports :</p>
+
+<pre>
+OGRFeature(OGRGeoJSON):0
+  a_property (String) = foo
+  some_object_a_property (Integer) = 1
+  some_object_another_property (Integer) = 2
+  POINT (2 49)
+</pre>
+
 <h2>Layer creation option</h2>
 
 <ul>
diff --git a/ogr/ogrsf_frmts/geojson/libjson/json_object.c b/ogr/ogrsf_frmts/geojson/libjson/json_object.c
index 3547245..867754e 100644
--- a/ogr/ogrsf_frmts/geojson/libjson/json_object.c
+++ b/ogr/ogrsf_frmts/geojson/libjson/json_object.c
@@ -601,7 +601,7 @@ double json_object_get_double(struct json_object *jso)
   case json_type_boolean:
     return jso->o.c_boolean;
   case json_type_string:
-    return CPLAtof(jso->o.c_string.str);
+    return CPLAtofM(jso->o.c_string.str);
   default:
     return 0.0;
   }
@@ -775,4 +775,3 @@ struct json_object* json_object_array_get_idx(struct json_object *jso,
 {
   return (struct json_object*)array_list_get_idx(jso->o.c_array, idx);
 }
-
diff --git a/ogr/ogrsf_frmts/geojson/libjson/json_object_iterator.c b/ogr/ogrsf_frmts/geojson/libjson/json_object_iterator.c
index 1a0883a..36bc285 100644
--- a/ogr/ogrsf_frmts/geojson/libjson/json_object_iterator.c
+++ b/ogr/ogrsf_frmts/geojson/libjson/json_object_iterator.c
@@ -86,7 +86,7 @@ json_object_iter_begin(struct json_object* obj)
  * ****************************************************************************
  */
 struct json_object_iterator
-json_object_iter_end(CPL_UNUSED const struct json_object* obj)
+json_object_iter_end( CPL_UNUSED const struct json_object* obj )
 {
     struct json_object_iterator iter;
 
diff --git a/ogr/ogrsf_frmts/geojson/libjson/json_util.c b/ogr/ogrsf_frmts/geojson/libjson/json_util.c
index fef9422..bd1e0ca 100644
--- a/ogr/ogrsf_frmts/geojson/libjson/json_util.c
+++ b/ogr/ogrsf_frmts/geojson/libjson/json_util.c
@@ -61,6 +61,7 @@
 #include "json_tokener.h"
 #include "json_util.h"
 
+#include "cpl_conv.h"
 static int sscanf_is_broken = 0;
 static int sscanf_is_broken_testdone = 0;
 static void sscanf_is_broken_test(void);
@@ -148,7 +149,8 @@ int json_object_to_file(char *filename, struct json_object *obj)
 
 int json_parse_double(const char *buf, double *retval)
 {
-  return (sscanf(buf, "%lf", retval)==1 ? 0 : 1);
+    *retval = CPLStrtod(buf, 0);
+    return 0;
 }
 
 /*
diff --git a/ogr/ogrsf_frmts/geojson/ogr_geojson.h b/ogr/ogrsf_frmts/geojson/ogr_geojson.h
index 9d870d0..b3c0963 100644
--- a/ogr/ogrsf_frmts/geojson/ogr_geojson.h
+++ b/ogr/ogrsf_frmts/geojson/ogr_geojson.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_geojson.h 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogr_geojson.h 29111 2015-05-02 18:06:16Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Definitions of OGR OGRGeoJSON driver types.
@@ -35,6 +35,7 @@
 
 #include <cstdio>
 #include <vector> // used by OGRGeoJSONLayer
+#include "ogrgeojsonutils.h"
 
 #define SPACE_FOR_BBOX  80
 
@@ -63,7 +64,7 @@ public:
     //
     OGRFeatureDefn* GetLayerDefn();
     
-    int GetFeatureCount( int bForce = TRUE );
+    GIntBig GetFeatureCount( int bForce = TRUE );
     void ResetReading();
     OGRFeature* GetNextFeature();
     int TestCapability( const char* pszCap );
@@ -82,8 +83,8 @@ private:
     FeaturesSeq seqFeatures_;
     FeaturesSeq::iterator iterCurrent_;
 
-    /* poDS_ retained for ABI compatibility. */
-    /* CPL_UNUSED */ OGRGeoJSONDataSource* poDS_;
+
+    // CPL_UNUSED OGRGeoJSONDataSource* poDS_;
     OGRFeatureDefn* poFeatureDefn_;
     CPLString sFIDColumn_;
 };
@@ -109,7 +110,7 @@ public:
 
     void ResetReading() { }
     OGRFeature* GetNextFeature() { return NULL; }
-    OGRErr CreateFeature( OGRFeature* poFeature );
+    OGRErr ICreateFeature( OGRFeature* poFeature );
     OGRErr CreateField(OGRFieldDefn* poField, int bApproxOK);
     int TestCapability( const char* pszCap );
 
@@ -140,11 +141,12 @@ public:
     //
     // OGRDataSource Interface
     //
-    int Open( const char* pszSource );
+    int Open( GDALOpenInfo* poOpenInfo,
+               GeoJSONSourceType nSrcType );
     const char* GetName();
     int GetLayerCount();
     OGRLayer* GetLayer( int nLayer );
-    OGRLayer* CreateLayer( const char* pszName,
+    OGRLayer* ICreateLayer( const char* pszName,
                            OGRSpatialReference* poSRS = NULL,
                            OGRwkbGeometryType eGType = wkbUnknown,
                            char** papszOptions = NULL );
@@ -176,6 +178,7 @@ public:
 
     int  GetFpOutputIsSeekable() const { return bFpOutputIsSeekable_; }
     int  GetBBOXInsertLocation() const { return nBBOXInsertLocation_; }
+    int  HasOtherPages() const { return bOtherPages_; }
 
 private:
 
@@ -184,6 +187,7 @@ private:
     //
     char* pszName_;
     char* pszGeoData_;
+    vsi_l_offset nGeoDataLen_;
     OGRLayer** papoLayers_;
     int nLayers_;
     VSILFILE* fpOut_;
@@ -193,6 +197,7 @@ private:
     // 
     GeometryTranslation flTransGeom_;
     AttributesTranslation flTransAttrs_;
+    int bOtherPages_; /* ERSI Feature Service specific */
 
     int bFpOutputIsSeekable_;
     int nBBOXInsertLocation_;
@@ -201,39 +206,10 @@ private:
     // Priavte utility functions
     //
     void Clear();
-    int ReadFromFile( const char* pszSource, VSILFILE* fpIn );
+    int ReadFromFile( GDALOpenInfo* poOpenInfo );
     int ReadFromService( const char* pszSource );
-    void LoadLayers();
+    void LoadLayers(char** papszOpenOptions);
 };
 
 
-/************************************************************************/
-/*                           OGRGeoJSONDriver                           */
-/************************************************************************/
-
-class OGRGeoJSONDriver : public OGRSFDriver
-{
-public:
-
-    OGRGeoJSONDriver();
-    ~OGRGeoJSONDriver();
-
-    //
-    // OGRSFDriver Interface
-    //
-    const char* GetName();
-    OGRDataSource* Open( const char* pszName, int bUpdate );
-    OGRDataSource* CreateDataSource( const char* pszName, char** papszOptions );
-    OGRErr DeleteDataSource( const char* pszName );
-    int TestCapability( const char* pszCap );
-
-    //
-    // OGRGeoJSONDriver Interface
-    //
-    // NOTE: New version of Open() based on Andrey's RFC 10.
-    OGRDataSource* Open( const char* pszName, int bUpdate,
-                         char** papszOptions );
-
-};
-
 #endif /* OGR_GEOJSON_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/geojson/ogresrijsonreader.cpp b/ogr/ogrsf_frmts/geojson/ogresrijsonreader.cpp
index 3bebd3f..63eed04 100644
--- a/ogr/ogrsf_frmts/geojson/ogresrijsonreader.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogresrijsonreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogresrijsonreader.cpp 28350 2015-01-23 17:53:57Z rouault $
+ * $Id: ogresrijsonreader.cpp 29120 2015-05-02 22:25:02Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRESRIJSONReader class (OGR ESRIJSON Driver)
@@ -320,15 +320,18 @@ OGRFeature* OGRESRIJSONReader::ReadFeature( json_object* poObj )
         json_object_object_foreachC( poObjProps, it )
         {
             nField = poFeature->GetFieldIndex(it.key);
-            poFieldDefn = poFeature->GetFieldDefnRef(nField);
-            if (poFieldDefn && it.val != NULL )
+            if( nField >= 0 )
             {
-                if ( EQUAL( it.key,  poLayer_->GetFIDColumn() ) )
-                    poFeature->SetFID( json_object_get_int( it.val ) );
-                if ( poLayer_->GetLayerDefn()->GetFieldDefn(nField)->GetType() == OFTReal )
-                    poFeature->SetField( nField, CPLAtofM(json_object_get_string(it.val)) );
-                else
-                    poFeature->SetField( nField, json_object_get_string(it.val) );
+                poFieldDefn = poFeature->GetFieldDefnRef(nField);
+                if (poFieldDefn && it.val != NULL )
+                {
+                    if ( EQUAL( it.key,  poLayer_->GetFIDColumn() ) )
+                        poFeature->SetFID( json_object_get_int( it.val ) );
+                    if ( poLayer_->GetLayerDefn()->GetFieldDefn(nField)->GetType() == OFTReal )
+                        poFeature->SetField( nField, CPLAtofM(json_object_get_string(it.val)) );
+                    else
+                        poFeature->SetField( nField, json_object_get_string(it.val) );
+                }
             }
         }
     }
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp
index 46b2b4d..3a2087e 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsondatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeojsondatasource.cpp 29120 2015-05-02 22:25:02Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRGeoJSONDataSource class (OGR GeoJSON Driver).
@@ -41,10 +41,11 @@ using namespace std;
 /************************************************************************/
 
 OGRGeoJSONDataSource::OGRGeoJSONDataSource()
-    : pszName_(NULL), pszGeoData_(NULL),
+    : pszName_(NULL), pszGeoData_(NULL), nGeoDataLen_(0),
         papoLayers_(NULL), nLayers_(0), fpOut_(NULL),
         flTransGeom_( OGRGeoJSONDataSource::eGeometryPreserve ),
         flTransAttrs_( OGRGeoJSONDataSource::eAtributesPreserve ),
+        bOtherPages_(FALSE),
         bFpOutputIsSeekable_( FALSE ),
         nBBOXInsertLocation_(0)
 {
@@ -70,44 +71,21 @@ OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
 /*                           Open()                                     */
 /************************************************************************/
 
-int OGRGeoJSONDataSource::Open( const char* pszName )
+int OGRGeoJSONDataSource::Open( GDALOpenInfo* poOpenInfo,
+                                GeoJSONSourceType nSrcType )
 {
-    CPLAssert( NULL != pszName );
-
-/* -------------------------------------------------------------------- */
-/*      Release resources allocated during previous request.            */
-/* -------------------------------------------------------------------- */
-    if( NULL != papoLayers_ )
-    {
-        CPLAssert( nLayers_ > 0 );
-        Clear();
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Determine type of data source: text file (.geojson, .json),     */
-/*      Web Service or text passed directly and load data.              */
-/* -------------------------------------------------------------------- */
-    GeoJSONSourceType nSrcType;
-    
-    VSILFILE* fp = NULL;
-
-    nSrcType = GeoJSONGetSourceType( pszName, &fp );
     if( eGeoJSONSourceService == nSrcType )
     {
-        if( (strstr(pszName, "SERVICE=WFS") || strstr(pszName, "service=WFS") ||
-             strstr(pszName, "service=wfs")) && !strstr(pszName, "json"))
-            return FALSE;
-
-        if( !ReadFromService( pszName ) )
+        if( !ReadFromService( poOpenInfo->pszFilename ) )
             return FALSE;
     }
     else if( eGeoJSONSourceText == nSrcType )
     {
-        pszGeoData_ = CPLStrdup( pszName );
+        pszGeoData_ = CPLStrdup( poOpenInfo->pszFilename );
     }
     else if( eGeoJSONSourceFile == nSrcType )
     {
-        if( !ReadFromFile( pszName, fp ) )
+        if( !ReadFromFile( poOpenInfo ) )
             return FALSE;
     }
     else
@@ -130,13 +108,30 @@ int OGRGeoJSONDataSource::Open( const char* pszName )
         return FALSE;
     }
 
-    LoadLayers();
+    LoadLayers(poOpenInfo->papszOpenOptions);
     if( nLayers_ == 0 )
     {
+        int bEmitError = TRUE;
+        if( eGeoJSONSourceService == nSrcType )
+        {
+            CPLString osTmpFilename = CPLSPrintf("/vsimem/%p/%s", this,
+                                        CPLGetFilename(poOpenInfo->pszFilename));
+            VSIFCloseL(VSIFileFromMemBuffer( osTmpFilename,
+                                             (GByte*)pszGeoData_,
+                                             nGeoDataLen_, 
+                                             TRUE ));
+            pszGeoData_ = NULL;
+            if( GDALIdentifyDriver(osTmpFilename, NULL) )
+                bEmitError = FALSE;
+            VSIUnlink(osTmpFilename);
+        }
         Clear();
-        
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "Failed to read GeoJSON data" );
+
+        if( bEmitError )
+        {
+            CPLError( CE_Failure, CPLE_OpenFailed, 
+                    "Failed to read GeoJSON data" );
+        }
         return FALSE;
     }
 
@@ -176,10 +171,10 @@ OGRLayer* OGRGeoJSONDataSource::GetLayer( int nLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer* OGRGeoJSONDataSource::CreateLayer( const char* pszName_,
+OGRLayer* OGRGeoJSONDataSource::ICreateLayer( const char* pszName_,
                                              OGRSpatialReference* poSRS,
                                              OGRwkbGeometryType eGType,
                                              char** papszOptions )
@@ -217,7 +212,7 @@ OGRLayer* OGRGeoJSONDataSource::CreateLayer( const char* pszName_,
         const char* pszAuthority = poSRS->GetAuthorityName(NULL);
         const char* pszAuthorityCode = poSRS->GetAuthorityCode(NULL);
         if (pszAuthority != NULL && pszAuthorityCode != NULL &&
-            strcmp(pszAuthority, "EPSG") == 0)
+            EQUAL(pszAuthority, "EPSG"))
         {
             json_object* poObjCRS = json_object_new_object();
             json_object_object_add(poObjCRS, "type",
@@ -265,7 +260,7 @@ OGRLayer* OGRGeoJSONDataSource::CreateLayer( const char* pszName_,
 int OGRGeoJSONDataSource::TestCapability( const char* pszCap )
 {
     if( EQUAL( pszCap, ODsCCreateLayer ) )
-        return fpOut_ != NULL /* && nLayers_ == 0 */;
+        return fpOut_ != NULL && nLayers_ == 0;
     else if( EQUAL( pszCap, ODsCDeleteLayer ) )
         return FALSE;
     else
@@ -357,6 +352,7 @@ void OGRGeoJSONDataSource::Clear()
 
     CPLFree( pszGeoData_ );
     pszGeoData_ = NULL;
+    nGeoDataLen_ = 0;
 
     if( NULL != fpOut_ )
     {
@@ -369,20 +365,20 @@ void OGRGeoJSONDataSource::Clear()
 /*                           ReadFromFile()                             */
 /************************************************************************/
 
-int OGRGeoJSONDataSource::ReadFromFile( const char* pszSource, VSILFILE* fpIn )
+int OGRGeoJSONDataSource::ReadFromFile( GDALOpenInfo* poOpenInfo )
 {
     GByte* pabyOut = NULL;
-    if( !VSIIngestFile( fpIn, pszSource, &pabyOut, NULL, -1) )
+    if( poOpenInfo->fpL == NULL ||
+        !VSIIngestFile( poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut, NULL, -1) )
     {
-        if( fpIn != NULL )
-            VSIFCloseL(fpIn);
         return FALSE;
     }
-    if( fpIn != NULL )
-        VSIFCloseL(fpIn);
+
+    VSIFCloseL(poOpenInfo->fpL);
+    poOpenInfo->fpL = NULL;
     pszGeoData_ = (char*) pabyOut;
 
-    pszName_ = CPLStrdup( pszSource );
+    pszName_ = CPLStrdup( poOpenInfo->pszFilename );
 
     CPLAssert( NULL != pszGeoData_ );
     return TRUE;
@@ -449,7 +445,9 @@ int OGRGeoJSONDataSource::ReadFromService( const char* pszSource )
 
     // Directly assign CPLHTTPResult::pabyData to pszGeoData_
     pszGeoData_ = (char*) pszData;
+    nGeoDataLen_ = pResult->nDataLen;
     pResult->pabyData = NULL;
+    pResult->nDataLen = 0;
 
     pszName_ = CPLStrdup( pszSource );
 
@@ -466,7 +464,7 @@ int OGRGeoJSONDataSource::ReadFromService( const char* pszSource )
 /*                           LoadLayers()                               */
 /************************************************************************/
 
-void OGRGeoJSONDataSource::LoadLayers()
+void OGRGeoJSONDataSource::LoadLayers(char** papszOpenOptions)
 {
     if( NULL == pszGeoData_ )
     {
@@ -512,6 +510,14 @@ void OGRGeoJSONDataSource::LoadLayers()
         err = reader.Parse( pszGeoData_ );
         if( OGRERR_NONE == err )
         {
+            json_object* poObj = reader.GetJSonObject();
+            if( poObj && json_object_get_type(poObj) == json_type_object )
+            {
+                json_object* poExceededTransferLimit =
+                    json_object_object_get(poObj, "exceededTransferLimit");
+                if( poExceededTransferLimit && json_object_get_type(poExceededTransferLimit) == json_type_boolean )
+                    bOtherPages_ = json_object_get_boolean(poExceededTransferLimit);
+            }
             reader.ReadLayers( this );
         }
         return;
@@ -549,12 +555,29 @@ void OGRGeoJSONDataSource::LoadLayers()
         CPLDebug( "GeoJSON", "Skip all attributes." );
     }
     
+    reader.SetFlattenNestedAttributes(
+        (bool)CSLFetchBoolean(papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES", FALSE),
+        CSLFetchNameValueDef(papszOpenOptions, "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
+
 /* -------------------------------------------------------------------- */
 /*      Parse GeoJSON and build valid OGRLayer instance.                */
 /* -------------------------------------------------------------------- */
     err = reader.Parse( pszGeoData_ );
     if( OGRERR_NONE == err )
     {
+        json_object* poObj = reader.GetJSonObject();
+        if( poObj && json_object_get_type(poObj) == json_type_object )
+        {
+            json_object* poProperties = json_object_object_get(poObj, "properties");
+            if( poProperties && json_object_get_type(poProperties) == json_type_object )
+            {
+                json_object* poExceededTransferLimit =
+                    json_object_object_get(poProperties, "exceededTransferLimit");
+                if( poExceededTransferLimit && json_object_get_type(poExceededTransferLimit) == json_type_boolean )
+                    bOtherPages_ = json_object_get_boolean(poExceededTransferLimit);
+            }
+        }
+
         reader.ReadLayers( this );
     }
 
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsondriver.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsondriver.cpp
index b222323..21c7f27 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsondriver.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsondriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsondriver.cpp 19489 2010-04-21 21:39:05Z rouault $
+ * $Id: ogrgeojsondriver.cpp 29134 2015-05-03 18:17:46Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRGeoJSONDriver class (OGR GeoJSON Driver).
@@ -28,49 +28,378 @@
  ****************************************************************************/
 #include "ogr_geojson.h"
 #include <cpl_conv.h>
+#include "cpl_http.h"
+
+class OGRESRIFeatureServiceDataset;
 
 /************************************************************************/
-/*                           OGRGeoJSONDriver()                         */
+/*                      OGRESRIFeatureServiceLayer                      */
 /************************************************************************/
 
-OGRGeoJSONDriver::OGRGeoJSONDriver()
+class OGRESRIFeatureServiceLayer: public OGRLayer
 {
+        OGRESRIFeatureServiceDataset* poDS;
+        OGRFeatureDefn* poFeatureDefn;
+        GIntBig         nFeaturesRead;
+        GIntBig         nLastFID;
+        int             bOtherPage;
+        int             bUseSequentialFID;
+
+    public:
+        OGRESRIFeatureServiceLayer(OGRESRIFeatureServiceDataset* poDS);
+       ~OGRESRIFeatureServiceLayer();
+
+        void ResetReading();
+        OGRFeature* GetNextFeature();
+        GIntBig GetFeatureCount( int bForce = TRUE );
+        OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
+        int TestCapability( const char* pszCap );
+        OGRFeatureDefn* GetLayerDefn() { return poFeatureDefn; }
+};
+
+/************************************************************************/
+/*                       OGRESRIFeatureServiceDataset                   */
+/************************************************************************/
+
+class OGRESRIFeatureServiceDataset: public GDALDataset
+{
+        CPLString              osURL;
+        GIntBig                nFirstOffset, nLastOffset;
+        OGRGeoJSONDataSource* poCurrent;
+        OGRESRIFeatureServiceLayer* poLayer;
+        
+        int                     LoadPage();
+
+    public:
+        OGRESRIFeatureServiceDataset(const CPLString &osURL,
+                                     OGRGeoJSONDataSource* poFirst);
+       ~OGRESRIFeatureServiceDataset();
+
+        int GetLayerCount() { return 1; }
+        OGRLayer* GetLayer( int nLayer ) { return (nLayer == 0) ? poLayer : NULL; }
+        
+        OGRLayer* GetUnderlyingLayer() { return poCurrent->GetLayer(0); }
+
+        int ResetReading();
+        int LoadNextPage();
+        
+        const CPLString&                GetURL() { return osURL; }
+};
+
+/************************************************************************/
+/*                       OGRESRIFeatureServiceLayer()                   */
+/************************************************************************/
+
+OGRESRIFeatureServiceLayer::OGRESRIFeatureServiceLayer(OGRESRIFeatureServiceDataset* poDS)
+{
+    this->poDS = poDS;
+    OGRFeatureDefn* poSrcFeatDefn = poDS->GetUnderlyingLayer()->GetLayerDefn();
+    poFeatureDefn = new OGRFeatureDefn(poSrcFeatDefn->GetName());
+    SetDescription(poFeatureDefn->GetName());
+    poFeatureDefn->Reference();
+    poFeatureDefn->SetGeomType(wkbNone);
+    for(int i=0;i<poSrcFeatDefn->GetFieldCount();i++)
+        poFeatureDefn->AddFieldDefn(poSrcFeatDefn->GetFieldDefn(i));
+    for(int i=0;i<poSrcFeatDefn->GetGeomFieldCount();i++)
+        poFeatureDefn->AddGeomFieldDefn(poSrcFeatDefn->GetGeomFieldDefn(i));
+    nFeaturesRead = 0;
+    nLastFID = 0;
+    bOtherPage = FALSE;
+    bUseSequentialFID = FALSE;
 }
 
 /************************************************************************/
-/*                          ~OGRGeoJSONDriver()                         */
+/*                      ~OGRESRIFeatureServiceLayer()                   */
 /************************************************************************/
 
-OGRGeoJSONDriver::~OGRGeoJSONDriver()
+OGRESRIFeatureServiceLayer::~OGRESRIFeatureServiceLayer()
 {
+    poFeatureDefn->Release();
 }
 
 /************************************************************************/
-/*                           GetName()                                  */
+/*                            ResetReading()                            */
 /************************************************************************/
 
-const char* OGRGeoJSONDriver::GetName()
+void OGRESRIFeatureServiceLayer::ResetReading()
 {
-    return "GeoJSON";
+    poDS->ResetReading();
+    nFeaturesRead = 0;
+    nLastFID = 0;
+    bOtherPage = FALSE;
+    bUseSequentialFID = FALSE;
 }
 
 /************************************************************************/
-/*                           Open()                                     */
+/*                            GetNextFeature()                          */
 /************************************************************************/
 
-OGRDataSource* OGRGeoJSONDriver::Open( const char* pszName, int bUpdate )
+OGRFeature* OGRESRIFeatureServiceLayer::GetNextFeature()
 {
-    return Open( pszName, bUpdate, NULL );
+    while( TRUE )
+    {
+        int bWasInFirstPage = !bOtherPage;
+        OGRFeature* poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
+        if( poSrcFeat == NULL )
+        {
+            if( !poDS->LoadNextPage() )
+                return NULL;
+            poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
+            if( poSrcFeat == NULL )
+                return NULL;
+            bOtherPage = TRUE;
+        }
+        if( bOtherPage && bWasInFirstPage && poSrcFeat->GetFID() == 0 &&
+            nLastFID == nFeaturesRead - 1 )
+        {
+            bUseSequentialFID = TRUE;
+        }
+
+        OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
+        poFeature->SetFrom(poSrcFeat);
+        if( bUseSequentialFID )
+            poFeature->SetFID(nFeaturesRead);
+        else
+            poFeature->SetFID(poSrcFeat->GetFID());
+        nLastFID = poFeature->GetFID();
+        nFeaturesRead ++;
+        delete poSrcFeat;
+        
+        if((m_poFilterGeom == NULL
+            || FilterGeometry( poFeature->GetGeometryRef() ) )
+        && (m_poAttrQuery == NULL
+            || m_poAttrQuery->Evaluate( poFeature )) )
+        {
+            return poFeature;
+        }
+        delete poFeature;
+    }
+}
+
+/************************************************************************/
+/*                          TestCapability()                            */
+/************************************************************************/
+
+int OGRESRIFeatureServiceLayer::TestCapability( const char* pszCap )
+{
+    if( EQUAL(pszCap, OLCFastFeatureCount) )
+        return m_poAttrQuery == NULL && m_poFilterGeom == NULL;
+    if( EQUAL(pszCap, OLCFastGetExtent) )
+        return FALSE;
+    return poDS->GetUnderlyingLayer()->TestCapability(pszCap);
+}
+
+/************************************************************************/
+/*                          GetFeatureCount()                           */
+/************************************************************************/
+
+GIntBig OGRESRIFeatureServiceLayer::GetFeatureCount( int bForce )
+{
+    GIntBig nFeatureCount = -1;
+    if( m_poAttrQuery == NULL && m_poFilterGeom == NULL ) 
+    {
+        CPLString osNewURL = CPLURLAddKVP(poDS->GetURL(), "returnCountOnly", "true");
+        CPLHTTPResult* pResult = NULL;
+        CPLErrorReset();
+        pResult = CPLHTTPFetch( osNewURL, NULL );
+        if( pResult != NULL && pResult->nDataLen != 0 && CPLGetLastErrorNo() == 0 &&
+            pResult->nStatus == 0 )
+        {
+            const char* pszCount = strstr((const char*)pResult->pabyData, "\"count\"");
+            if( pszCount )
+            {
+                pszCount = strchr(pszCount, ':');
+                if( pszCount )
+                {
+                    pszCount++;
+                    nFeatureCount = CPLAtoGIntBig(pszCount);
+                }
+            }
+        }
+        CPLHTTPDestroyResult( pResult );
+    }
+    if( nFeatureCount < 0 )
+        nFeatureCount = OGRLayer::GetFeatureCount(bForce);
+    return nFeatureCount;
+}
+
+/************************************************************************/
+/*                               GetExtent()                            */
+/************************************************************************/
+
+OGRErr OGRESRIFeatureServiceLayer::GetExtent(OGREnvelope *psExtent, int bForce)
+{
+    OGRErr eErr = OGRERR_FAILURE;
+    CPLString osNewURL = CPLURLAddKVP(poDS->GetURL(), "returnExtentOnly", "true");
+    osNewURL = CPLURLAddKVP(osNewURL, "f", "geojson");
+    CPLHTTPResult* pResult = NULL;
+    CPLErrorReset();
+    pResult = CPLHTTPFetch( osNewURL, NULL );
+    if( pResult != NULL && pResult->nDataLen != 0 && CPLGetLastErrorNo() == 0 &&
+        pResult->nStatus == 0 )
+    {
+        const char* pszBBox = strstr((const char*)pResult->pabyData, "\"bbox\"");
+        if( pszBBox )
+        {
+            pszBBox = strstr(pszBBox, ":[");
+            if( pszBBox )
+            {
+                pszBBox+=2;
+                char** papszTokens = CSLTokenizeString2(pszBBox, ",", 0);
+                if( CSLCount(papszTokens) >= 4 )
+                {
+                    psExtent->MinX = CPLAtof(papszTokens[0]);
+                    psExtent->MinY = CPLAtof(papszTokens[1]);
+                    psExtent->MaxX = CPLAtof(papszTokens[2]);
+                    psExtent->MaxY = CPLAtof(papszTokens[3]);
+                    eErr = OGRERR_NONE;
+                }
+                CSLDestroy(papszTokens);
+            }
+        }
+    }
+    CPLHTTPDestroyResult( pResult );
+    if( eErr == OGRERR_FAILURE )
+        eErr = OGRLayer::GetExtent(psExtent, bForce);
+    return eErr;
+}
+
+/************************************************************************/
+/*                      OGRESRIFeatureServiceDataset()                  */
+/************************************************************************/
+
+OGRESRIFeatureServiceDataset::OGRESRIFeatureServiceDataset(const CPLString &osURL,
+                                                           OGRGeoJSONDataSource* poFirst)
+{
+    poCurrent = poFirst;
+    poLayer = new OGRESRIFeatureServiceLayer(this);
+    this->osURL = osURL;
+    if( CPLURLGetValue(this->osURL, "resultRecordCount").size() == 0 )
+    {
+        // We assume that if the server sets the exceededTransferLimit, the
+        // and resultRecordCount is not set, the number of features returned
+        // in our first request is the maximum allowed by the server
+        // So set it for following requests
+        this->osURL = CPLURLAddKVP(this->osURL, "resultRecordCount",
+                CPLSPrintf("%d", (int)poFirst->GetLayer(0)->GetFeatureCount()));
+    }
+    else
+    {
+        int nUserSetRecordCount = atoi(CPLURLGetValue(this->osURL, "resultRecordCount"));
+        if( nUserSetRecordCount > poFirst->GetLayer(0)->GetFeatureCount() )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "Specificied resultRecordCount=%d is greater than the maximum %d supported by the server",
+                     nUserSetRecordCount, (int)poFirst->GetLayer(0)->GetFeatureCount() );
+        }
+    }
+    nFirstOffset = CPLAtoGIntBig(CPLURLGetValue(this->osURL, "resultOffset"));
+    nLastOffset = nFirstOffset;
+}
+
+/************************************************************************/
+/*                      ~OGRESRIFeatureServiceDataset()                 */
+/************************************************************************/
+
+OGRESRIFeatureServiceDataset::~OGRESRIFeatureServiceDataset()
+{
+    delete poCurrent;
+    delete poLayer;
+}
+
+/************************************************************************/
+/*                             ResetReading()                           */
+/************************************************************************/
+
+int OGRESRIFeatureServiceDataset::ResetReading()
+{
+    if( nLastOffset > nFirstOffset )
+    {
+        nLastOffset = nFirstOffset;
+        return LoadPage();
+    }
+    else
+    {
+        poCurrent->GetLayer(0)->ResetReading();
+        return TRUE;
+    }
+}
+
+/************************************************************************/
+/*                             LoadNextPage()                           */
+/************************************************************************/
+
+int OGRESRIFeatureServiceDataset::LoadNextPage()
+{
+    if( !poCurrent->HasOtherPages() )
+        return FALSE;
+    nLastOffset += poCurrent->GetLayer(0)->GetFeatureCount();
+    return LoadPage();
+}
+
+/************************************************************************/
+/*                                 LoadPage()                           */
+/************************************************************************/
+
+int OGRESRIFeatureServiceDataset::LoadPage()
+{
+    CPLString osNewURL = CPLURLAddKVP(osURL, "resultOffset",
+                                        CPLSPrintf(CPL_FRMT_GIB, nLastOffset));
+    OGRGeoJSONDataSource* poDS = NULL;
+    poDS = new OGRGeoJSONDataSource();
+    GDALOpenInfo oOpenInfo(osNewURL, GA_ReadOnly);
+    if( !poDS->Open( &oOpenInfo, GeoJSONGetSourceType( &oOpenInfo ) ) ||
+        poDS->GetLayerCount() == 0 )
+    {
+        delete poDS;
+        poDS= NULL;
+        return FALSE;
+    }
+    delete poCurrent;
+    poCurrent = poDS;
+    return TRUE;
+}
+    
+
+/************************************************************************/
+/*                        OGRGeoJSONDriverIdentify()                    */
+/************************************************************************/
+
+static int OGRGeoJSONDriverIdentifyInternal( GDALOpenInfo* poOpenInfo,
+                                     GeoJSONSourceType& nSrcType )
+{
+/* -------------------------------------------------------------------- */
+/*      Determine type of data source: text file (.geojson, .json),     */
+/*      Web Service or text passed directly and load data.              */
+/* -------------------------------------------------------------------- */
+
+    nSrcType = GeoJSONGetSourceType( poOpenInfo );
+    if( nSrcType == eGeoJSONSourceUnknown )
+        return FALSE;
+    if( nSrcType == eGeoJSONSourceService )
+        return -1;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                        OGRGeoJSONDriverIdentify()                    */
+/************************************************************************/
+
+static int OGRGeoJSONDriverIdentify( GDALOpenInfo* poOpenInfo )
+{
+    GeoJSONSourceType nSrcType;
+    return OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType);
 }
 
 /************************************************************************/
 /*                           Open()                                     */
 /************************************************************************/
 
-OGRDataSource* OGRGeoJSONDriver::Open( const char* pszName, int bUpdate,
-                                       char** papszOptions )
+static GDALDataset* OGRGeoJSONDriverOpen( GDALOpenInfo* poOpenInfo )
 {
-    UNREFERENCED_PARAM(papszOptions);
+    GeoJSONSourceType nSrcType;
+    if( OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType) == FALSE )
+        return NULL;
 
     OGRGeoJSONDataSource* poDS = NULL;
     poDS = new OGRGeoJSONDataSource();
@@ -102,29 +431,46 @@ OGRDataSource* OGRGeoJSONDriver::Open( const char* pszName, int bUpdate,
 /* -------------------------------------------------------------------- */
 /*      Open and start processing GeoJSON datasoruce to OGR objects.    */
 /* -------------------------------------------------------------------- */
-    if( !poDS->Open( pszName ) )
+    if( !poDS->Open( poOpenInfo, nSrcType ) )
     {
         delete poDS;
         poDS= NULL;
     }
 
-    if( NULL != poDS && bUpdate )
+    if( NULL != poDS && poOpenInfo->eAccess == GA_Update )
     {
         CPLError( CE_Failure, CPLE_OpenFailed, 
                   "GeoJSON Driver doesn't support update." );
         delete poDS;
         return NULL;
     }
+    
+    if( poDS != NULL && poDS->HasOtherPages() )
+    {
+        const char* pszFSP = CSLFetchNameValue(poOpenInfo->papszOpenOptions,
+                                               "FEATURE_SERVER_PAGING");
+        int bHasResultOffset = CPLURLGetValue(poOpenInfo->pszFilename, "resultOffset").size() > 0;
+        if( (!bHasResultOffset && (pszFSP == NULL || CSLTestBoolean(pszFSP))) ||
+            (bHasResultOffset && pszFSP != NULL && CSLTestBoolean(pszFSP)) )
+        {
+            return new OGRESRIFeatureServiceDataset(poOpenInfo->pszFilename,
+                                                    poDS);
+        }
+    }
 
     return poDS;
 }
 
 /************************************************************************/
-/*                           CreateDataSource()                         */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource* OGRGeoJSONDriver::CreateDataSource( const char* pszName,
-                                                   char** papszOptions )
+static GDALDataset *OGRGeoJSONDriverCreate( const char * pszName,
+                                            CPL_UNUSED int nBands,
+                                            CPL_UNUSED int nXSize,
+                                            CPL_UNUSED int nYSize,
+                                            CPL_UNUSED GDALDataType eDT,
+                                            char **papszOptions )
 {
     OGRGeoJSONDataSource* poDS = new OGRGeoJSONDataSource();
 
@@ -138,33 +484,19 @@ OGRDataSource* OGRGeoJSONDriver::CreateDataSource( const char* pszName,
 }
 
 /************************************************************************/
-/*                           DeleteDataSource()                         */
+/*                               Delete()                               */
 /************************************************************************/
 
-OGRErr OGRGeoJSONDriver::DeleteDataSource( const char* pszName )
+static CPLErr OGRGeoJSONDriverDelete( const char *pszFilename )
 {
-    if( VSIUnlink( pszName ) == 0 )
+    if( VSIUnlink( pszFilename ) == 0 )
     {
-        return OGRERR_NONE;
+        return CE_None;
     }
     
-    CPLDebug( "GeoJSON", "Failed to delete \'%s\'", pszName);
+    CPLDebug( "GeoJSON", "Failed to delete \'%s\'", pszFilename);
 
-    return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGeoJSONDriver::TestCapability( const char* pszCap )
-{
-    if( EQUAL( pszCap, ODrCCreateDataSource ) )
-        return TRUE;
-    else if( EQUAL(pszCap, ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
+    return CE_Failure;
 }
 
 /************************************************************************/
@@ -173,10 +505,47 @@ int OGRGeoJSONDriver::TestCapability( const char* pszCap )
 
 void RegisterOGRGeoJSON()
 {
-    if( GDAL_CHECK_VERSION("OGR/GeoJSON driver") )
+    if( !GDAL_CHECK_VERSION("OGR/GeoJSON driver") )
+        return;
+
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "GeoJSON" ) == NULL )
     {
-        OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( 
-            new OGRGeoJSONDriver );
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "GeoJSON" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GeoJSON" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "json geojson topojson" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_geojson.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='FLATTEN_NESTED_ATTRIBUTES' type='boolean' description='Whether to recursively explore nested objects and produce flatten OGR attributes' default='NO'/>"
+"  <Option name='NESTED_ATTRIBUTE_SEPARATOR' type='string' description='Separator between components of nested attributes' default='_'/>"
+"  <Option name='FEATURE_SERVER_PAGING' type='boolean' description='Whether to automatically scroll through results with a ArcGIS Feature Service endpoint'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='WRITE_BBOX' type='boolean' description='whether to write a bbox property with the bounding box of the geometries at the feature and feature collection level' default='NO'/>"
+"  <Option name='COORDINATE_PRECISION' type='int' description='Number of decimal for coordinates' default='10'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String IntegerList Integer64List RealList StringList" );
+
+        poDriver->pfnOpen = OGRGeoJSONDriverOpen;
+        poDriver->pfnIdentify = OGRGeoJSONDriverIdentify;
+        poDriver->pfnCreate = OGRGeoJSONDriverCreate;
+        poDriver->pfnDelete = OGRGeoJSONDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
     }
 }
-
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonlayer.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonlayer.cpp
index bf87689..6a1e073 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonlayer.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonlayer.cpp 27718 2014-09-21 16:55:01Z goatbar $
+ * $Id: ogrgeojsonlayer.cpp 29111 2015-05-02 18:06:16Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRGeoJSONLayer class (OGR GeoJSON Driver).
@@ -61,6 +61,7 @@ OGRGeoJSONLayer::OGRGeoJSONLayer( const char* pszName,
     poFeatureDefn_->SetGeomType( eGType );
     if( poFeatureDefn_->GetGeomFieldCount() != 0 )
         poFeatureDefn_->GetGeomFieldDefn(0)->SetSpatialRef(poSRSIn);
+    SetDescription( poFeatureDefn_->GetName() );
 }
 
 /************************************************************************/
@@ -91,7 +92,7 @@ OGRFeatureDefn* OGRGeoJSONLayer::GetLayerDefn()
 /*                           GetFeatureCount                            */
 /************************************************************************/
 
-int OGRGeoJSONLayer::GetFeatureCount( int bForce )
+GIntBig OGRGeoJSONLayer::GetFeatureCount( int bForce )
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
         return static_cast<int>( seqFeatures_.size() );
@@ -146,7 +147,12 @@ OGRFeature* OGRGeoJSONLayer::GetNextFeature()
 
 int OGRGeoJSONLayer::TestCapability( const char* pszCap )
 {
-    UNREFERENCED_PARAM(pszCap);
+    if( EQUAL(pszCap, OLCFastFeatureCount) ||
+        EQUAL(pszCap, OLCFastGetExtent) ||
+        EQUAL(pszCap, OLCStringsAsUTF8) )
+    {
+        return TRUE;
+    }
 
     return FALSE;
 }
@@ -199,6 +205,10 @@ void OGRGeoJSONLayer::AddFeature( OGRFeature* poFeature )
             poNewFeature->SetField( nField, nFID );
         }
     }
+    
+        
+    if( (GIntBig)(int)poNewFeature->GetFID() != poNewFeature->GetFID() )
+        SetMetadataItem(OLMD_FID64, "YES");
 
     seqFeatures_.push_back( poNewFeature );
 }
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.cpp
index 55c3f4e..0bc4047 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonreader.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrgeojsonreader.cpp 28898 2015-04-13 22:25:53Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRGeoJSONReader class (OGR GeoJSON Driver).
@@ -41,6 +41,8 @@ OGRGeoJSONReader::OGRGeoJSONReader()
     : poGJObject_( NULL ),
         bGeometryPreserve_( true ),
         bAttributesSkip_( false ),
+        bFlattenNestedAttributes_ (false),
+        chNestedAttributeSeparator_ (0),
         bFlattenGeocouchSpatiallistFormat (-1), bFoundId (false), bFoundRev(false), bFoundTypeFeature(false), bIsGeocouchSpatiallistFormat(false)
 {
     // Take a deep breath and get to work.
@@ -366,6 +368,16 @@ void OGRGeoJSONReader::SetSkipAttributes( bool bSkip )
 }
 
 /************************************************************************/
+/*                           SetSkipAttributes                          */
+/************************************************************************/
+
+void OGRGeoJSONReader::SetFlattenNestedAttributes( bool bFlatten, char chSeparator )
+{
+    bFlattenNestedAttributes_ = bFlatten;
+    chNestedAttributeSeparator_ = chSeparator;
+}
+
+/************************************************************************/
 /*                         GenerateLayerDefn()                          */
 /************************************************************************/
 
@@ -428,7 +440,7 @@ bool OGRGeoJSONReader::GenerateLayerDefn( OGRGeoJSONLayer* poLayer, json_object*
     {
         OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
         if( EQUAL( poDefn->GetNameRef(), OGRGeoJSONLayer::DefaultFIDColumn )
-            && OFTInteger == poDefn->GetType() )
+            && (OFTInteger == poDefn->GetType() || OFTInteger64 == poDefn->GetType()) )
         {
             poLayer->SetFIDColumn( poDefn->GetNameRef() );
             /* bHasFID = true; */
@@ -452,6 +464,122 @@ bool OGRGeoJSONReader::GenerateLayerDefn( OGRGeoJSONLayer* poLayer, json_object*
 }
 
 /************************************************************************/
+/*                     OGRGeoJSONReaderAddNewField()                    */
+/************************************************************************/
+
+void OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn* poDefn,
+                                      const char* pszKey,
+                                      json_object* poVal,
+                                      bool bFlattenNestedAttributes,
+                                      char chNestedAttributeSeparator)
+{
+    if( bFlattenNestedAttributes &&
+        poVal != NULL && json_object_get_type(poVal) == json_type_object )
+    {
+        json_object_iter it;
+        it.key = NULL;
+        it.val = NULL;
+        it.entry = NULL;
+        json_object_object_foreachC( poVal, it )
+        {
+            char szSeparator[2];
+            szSeparator[0] = chNestedAttributeSeparator;
+            szSeparator[1] = 0;
+            CPLString osAttrName(CPLSPrintf("%s%s%s", pszKey, szSeparator,
+                                            it.key));
+            if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
+            {
+                OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val,
+                                                 TRUE, chNestedAttributeSeparator);
+            }
+            else
+            {
+                OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val, FALSE, 0);
+            }
+        }
+        return;
+    }
+
+    int nIndex = poDefn->GetFieldIndex(pszKey);
+    if( nIndex < 0 )
+    {
+        OGRFieldSubType eSubType;
+        OGRFieldDefn fldDefn( pszKey,
+                                GeoJSONPropertyToFieldType( poVal, eSubType ) );
+        fldDefn.SetSubType(eSubType);
+        if( eSubType == OFSTBoolean )
+            fldDefn.SetWidth(1);
+        if( fldDefn.GetType() == OFTString )
+        {
+            fldDefn.SetType(GeoJSONStringPropertyToFieldType( poVal ));
+        }
+        poDefn->AddFieldDefn( &fldDefn );
+    }
+    else
+    {
+        OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nIndex);
+        OGRFieldType eType = poFDefn->GetType();
+        if( eType == OFTInteger )
+        {
+            OGRFieldSubType eSubType;
+            OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
+            if( eNewType == OFTInteger &&
+                poFDefn->GetSubType() == OFSTBoolean && eSubType != OFSTBoolean )
+            {
+                poFDefn->SetSubType(OFSTNone);
+            }
+            else if( eNewType == OFTInteger64 || eNewType == OFTReal || eNewType == OFTString )
+            {
+                poFDefn->SetType(eNewType);
+                poFDefn->SetSubType(OFSTNone);
+            }
+        }
+        else if( eType == OFTInteger64 )
+        {
+            OGRFieldSubType eSubType;
+            OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
+            if( eNewType == OFTReal || eNewType == OFTString )
+            {
+                poFDefn->SetType(eNewType);
+                poFDefn->SetSubType(OFSTNone);
+            }
+        }
+        else if( eType == OFTIntegerList || eType == OFTInteger64List )
+        {
+            OGRFieldSubType eSubType;
+            OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
+            if( eNewType == OFTInteger64List || eNewType == OFTRealList || eNewType == OFTStringList )
+                poFDefn->SetType(eNewType);
+        }
+        else if( eType == OFTRealList )
+        {
+            OGRFieldSubType eSubType;
+            OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
+            if( eNewType == OFTStringList )
+                poFDefn->SetType(eNewType);
+        }
+        else if( eType == OFTDate || eType == OFTTime || eType == OFTDateTime )
+        {
+            OGRFieldSubType eSubType;
+            OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
+            if( eNewType == OFTString )
+                eNewType = GeoJSONStringPropertyToFieldType( poVal );
+            if( eType != eNewType )
+            {
+                if( eType == OFTDate && eNewType == OFTDateTime )
+                {
+                    poFDefn->SetType(OFTDateTime);
+                }
+                else if( !(eType == OFTDateTime && eNewType == OFTDate) )
+                {
+                    poFDefn->SetType(OFTString);
+                }
+            }
+        }
+    }
+}
+
+/************************************************************************/
 /*                        GenerateFeatureDefn()                         */
 /************************************************************************/
 bool OGRGeoJSONReader::GenerateFeatureDefn( OGRGeoJSONLayer* poLayer, json_object* poObj )
@@ -466,6 +594,28 @@ bool OGRGeoJSONReader::GenerateFeatureDefn( OGRGeoJSONLayer* poLayer, json_objec
 /* -------------------------------------------------------------------- */
     json_object* poObjProps = NULL;
     poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
+
+    // If there's a top-level id of type string, and no properties.id, then
+    // declare a id field
+    if( poDefn->GetFieldIndex( "id" ) < 0 )
+    {
+        json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
+        if( poObjId && json_object_get_type(poObjId) == json_type_string )
+        {
+            int bHasRegularIdProp = FALSE;
+            if( NULL != poObjProps &&
+                json_object_get_type(poObjProps) == json_type_object )
+            {
+                bHasRegularIdProp = (json_object_object_get(poObjProps, "id") != NULL);
+            }
+            if( !bHasRegularIdProp )
+            {
+                OGRFieldDefn fldDefn( "id", OFTString );
+                poDefn->AddFieldDefn(&fldDefn);
+            }
+        }
+    }
+
     if( NULL != poObjProps &&
         json_object_get_type(poObjProps) == json_type_object )
     {
@@ -512,21 +662,10 @@ bool OGRGeoJSONReader::GenerateFeatureDefn( OGRGeoJSONLayer* poLayer, json_objec
                     }
                 }
 
-                OGRFieldDefn fldDefn( it.key,
-                                      GeoJSONPropertyToFieldType( it.val ) );
-                poDefn->AddFieldDefn( &fldDefn );
-            }
-            else
-            {
-                OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nFldIndex);
-                OGRFieldType eType = poFDefn->GetType();
-                if( eType == OFTInteger )
-                {
-                    OGRFieldType eNewType = GeoJSONPropertyToFieldType( it.val );
-                    if( eNewType == OFTReal || eNewType == OFTString )
-                        poFDefn->SetType(eNewType);
-                }
             }
+            OGRGeoJSONReaderAddOrUpdateField(poDefn, it.key, it.val,
+                                             bFlattenNestedAttributes_,
+                                             chNestedAttributeSeparator_);
         }
 
         bSuccess = true; // SUCCESS
@@ -637,6 +776,164 @@ OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
 }
 
 /************************************************************************/
+/*                OGRGeoJSONReaderSetFieldNestedAttribute()             */
+/************************************************************************/
+
+static void OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer* poLayer,
+                                                    OGRFeature* poFeature,
+                                                    const char* pszAttrPrefix,
+                                                    char chSeparator,
+                                                    json_object* poVal)
+{
+    json_object_iter it;
+    it.key = NULL;
+    it.val = NULL;
+    it.entry = NULL;
+    json_object_object_foreachC( poVal, it )
+    {
+        char szSeparator[2];
+        szSeparator[0] = chSeparator;
+        szSeparator[1] = 0;
+        CPLString osAttrName(CPLSPrintf("%s%s%s", pszAttrPrefix, szSeparator,
+                                        it.key));
+        if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
+        {
+            OGRGeoJSONReaderSetFieldNestedAttribute(poLayer, poFeature,
+                                                    osAttrName, chSeparator,
+                                                    it.val);
+        }
+        else
+        {
+            int nField = poFeature->GetFieldIndex(osAttrName);
+            OGRGeoJSONReaderSetField(poLayer, poFeature, nField,
+                                     osAttrName, it.val, FALSE, 0);
+        }
+    }
+}
+
+/************************************************************************/
+/*                   OGRGeoJSONReaderSetField()                         */
+/************************************************************************/
+
+void OGRGeoJSONReaderSetField(OGRLayer* poLayer,
+                              OGRFeature* poFeature,
+                              int nField,
+                              const char* pszAttrPrefix,
+                              json_object* poVal,
+                              bool bFlattenNestedAttributes,
+                              char chNestedAttributeSeparator)
+{
+    if( bFlattenNestedAttributes && 
+        poVal != NULL && json_object_get_type(poVal) == json_type_object )
+    {
+        OGRGeoJSONReaderSetFieldNestedAttribute(poLayer,
+                                                poFeature,
+                                                pszAttrPrefix,
+                                                chNestedAttributeSeparator,
+                                                poVal);
+        return ;
+    }
+    
+    OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField);
+    CPLAssert( NULL != poFieldDefn );
+    OGRFieldType eType = poFieldDefn->GetType();
+
+    if( poVal == NULL)
+    {
+        /* nothing to do */
+    }
+    else if( OFTInteger == eType )
+    {
+        poFeature->SetField( nField, json_object_get_int(poVal) );
+                        
+        /* Check if FID available and set correct value. */
+        if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
+            poFeature->SetFID( json_object_get_int(poVal) );
+    }
+    else if( OFTInteger64 == eType )
+    {
+        poFeature->SetField( nField, (GIntBig)json_object_get_int64(poVal) );
+        
+        /* Check if FID available and set correct value. */
+        if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
+            poFeature->SetFID( (GIntBig)json_object_get_int64(poVal) );
+    }
+    else if( OFTReal == eType )
+    {
+        poFeature->SetField( nField, json_object_get_double(poVal) );
+    }
+    else if( OFTIntegerList == eType )
+    {
+        if ( json_object_get_type(poVal) == json_type_array )
+        {
+            int nLength = json_object_array_length(poVal);
+            int* panVal = (int*)CPLMalloc(sizeof(int) * nLength);
+            for(int i=0;i<nLength;i++)
+            {
+                json_object* poRow = json_object_array_get_idx(poVal, i);
+                panVal[i] = json_object_get_int(poRow);
+            }
+            poFeature->SetField( nField, nLength, panVal );
+            CPLFree(panVal);
+        }
+    }
+    else if( OFTInteger64List == eType )
+    {
+        if ( json_object_get_type(poVal) == json_type_array )
+        {
+            int nLength = json_object_array_length(poVal);
+            GIntBig* panVal = (GIntBig*)CPLMalloc(sizeof(GIntBig) * nLength);
+            for(int i=0;i<nLength;i++)
+            {
+                json_object* poRow = json_object_array_get_idx(poVal, i);
+                panVal[i] = (GIntBig)json_object_get_int64(poRow);
+            }
+            poFeature->SetField( nField, nLength, panVal );
+            CPLFree(panVal);
+        }
+    }
+    else if( OFTRealList == eType )
+    {
+        if ( json_object_get_type(poVal) == json_type_array )
+        {
+            int nLength = json_object_array_length(poVal);
+            double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
+            for(int i=0;i<nLength;i++)
+            {
+                json_object* poRow = json_object_array_get_idx(poVal, i);
+                padfVal[i] = json_object_get_double(poRow);
+            }
+            poFeature->SetField( nField, nLength, padfVal );
+            CPLFree(padfVal);
+        }
+    }
+    else if( OFTStringList == eType )
+    {
+        if ( json_object_get_type(poVal) == json_type_array )
+        {
+            int nLength = json_object_array_length(poVal);
+            char** papszVal = (char**)CPLMalloc(sizeof(char*) * (nLength+1));
+            int i;
+            for(i=0;i<nLength;i++)
+            {
+                json_object* poRow = json_object_array_get_idx(poVal, i);
+                const char* pszVal = json_object_get_string(poRow);
+                if (pszVal == NULL)
+                    break;
+                papszVal[i] = CPLStrdup(pszVal);
+            }
+            papszVal[i] = NULL;
+            poFeature->SetField( nField, papszVal );
+            CSLDestroy(papszVal);
+        }
+    }
+    else
+    {
+        poFeature->SetField( nField, json_object_get_string(poVal) );
+    }
+}
+
+/************************************************************************/
 /*                           ReadFeature()                              */
 /************************************************************************/
 
@@ -676,7 +973,6 @@ OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object
         }
 
         int nField = -1;
-        OGRFieldDefn* poFieldDefn = NULL;
         json_object_iter it;
         it.key = NULL;
         it.val = NULL;
@@ -684,80 +980,9 @@ OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object
         json_object_object_foreachC( poObjProps, it )
         {
             nField = poFeature->GetFieldIndex(it.key);
-            poFieldDefn = poFeature->GetFieldDefnRef(nField);
-            CPLAssert( NULL != poFieldDefn );
-            OGRFieldType eType = poFieldDefn->GetType();
-
-            if( it.val == NULL)
-            {
-                /* nothing to do */
-            }
-            else if( OFTInteger == eType )
-            {
-                poFeature->SetField( nField, json_object_get_int(it.val) );
-				
-                /* Check if FID available and set correct value. */
-                if( EQUAL( it.key, poLayer->GetFIDColumn() ) )
-                    poFeature->SetFID( json_object_get_int(it.val) );
-            }
-            else if( OFTReal == eType )
-            {
-                poFeature->SetField( nField, CPLAtof(json_object_get_string(it.val)) );
-            }
-            else if( OFTIntegerList == eType )
-            {
-                if ( json_object_get_type(it.val) == json_type_array )
-                {
-                    int nLength = json_object_array_length(it.val);
-                    int* panVal = (int*)CPLMalloc(sizeof(int) * nLength);
-                    for(int i=0;i<nLength;i++)
-                    {
-                        json_object* poRow = json_object_array_get_idx(it.val, i);
-                        panVal[i] = json_object_get_int(poRow);
-                    }
-                    poFeature->SetField( nField, nLength, panVal );
-                    CPLFree(panVal);
-                }
-            }
-            else if( OFTRealList == eType )
-            {
-                if ( json_object_get_type(it.val) == json_type_array )
-                {
-                    int nLength = json_object_array_length(it.val);
-                    double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
-                    for(int i=0;i<nLength;i++)
-                    {
-                        json_object* poRow = json_object_array_get_idx(it.val, i);
-                        padfVal[i] = CPLAtof(json_object_get_string(poRow));
-                    }
-                    poFeature->SetField( nField, nLength, padfVal );
-                    CPLFree(padfVal);
-                }
-            }
-            else if( OFTStringList == eType )
-            {
-                if ( json_object_get_type(it.val) == json_type_array )
-                {
-                    int nLength = json_object_array_length(it.val);
-                    char** papszVal = (char**)CPLMalloc(sizeof(char*) * (nLength+1));
-                    int i;
-                    for(i=0;i<nLength;i++)
-                    {
-                        json_object* poRow = json_object_array_get_idx(it.val, i);
-                        const char* pszVal = json_object_get_string(poRow);
-                        if (pszVal == NULL)
-                            break;
-                        papszVal[i] = CPLStrdup(pszVal);
-                    }
-                    papszVal[i] = NULL;
-                    poFeature->SetField( nField, papszVal );
-                    CSLDestroy(papszVal);
-                }
-            }
-            else
-            {
-                poFeature->SetField( nField, json_object_get_string(it.val) );
-            }
+            OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val,
+                                     bFlattenNestedAttributes_,
+                                     chNestedAttributeSeparator_);
         }
     }
 
@@ -785,15 +1010,17 @@ OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object
     if( -1 == poFeature->GetFID() )
     {
         json_object* poObjId = NULL;
+        OGRFieldSubType eSubType;
         poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
         if( NULL != poObjId
             && EQUAL( OGRGeoJSONLayer::DefaultFIDColumn, poLayer->GetFIDColumn() )
-            && OFTInteger == GeoJSONPropertyToFieldType( poObjId ) )
+            && (OFTInteger == GeoJSONPropertyToFieldType( poObjId, eSubType ) ||
+                OFTInteger64 == GeoJSONPropertyToFieldType( poObjId, eSubType )) )
         {
-            poFeature->SetFID( json_object_get_int( poObjId ) );
+            poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
             int nField = poFeature->GetFieldIndex( poLayer->GetFIDColumn() );
             if( -1 != nField )
-                poFeature->SetField( nField, (int) poFeature->GetFID() );
+                poFeature->SetField( nField, poFeature->GetFID() );
         }
     }
 
@@ -801,7 +1028,10 @@ OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object
     {
         json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
         if (poObjId != NULL && json_object_get_type(poObjId) == json_type_int)
-            poFeature->SetFID( json_object_get_int( poObjId ) );
+            poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
+        else if (poObjId != NULL && json_object_get_type(poObjId) == json_type_string &&
+                 !poFeature->IsFieldSet(poFeature->GetFieldIndex("id")))
+            poFeature->SetField( "id", json_object_get_string(poObjId) );
     }
 
 /* -------------------------------------------------------------------- */
@@ -987,7 +1217,7 @@ OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
     // set it too.
     
     json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
-    if (poObjSrs != NULL) {
+    if (poGeometry != NULL && poObjSrs != NULL) {
         OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
         if (poSRS != NULL) {
             poGeometry->assignSpatialReference(poSRS);
@@ -1532,6 +1762,12 @@ OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
 
         OGRGeometry* poGeometry = NULL;
         poGeometry = OGRGeoJSONReadGeometry( poObj );
+
+        /* Assign WGS84 if no CRS defined on geometry */
+        if( poGeometry && poGeometry->getSpatialReference() == NULL )
+        {
+            poGeometry->assignSpatialReference(OGRSpatialReference::GetWGS84SRS());
+        }
         
         /* Release JSON tree. */
         json_object_put( poObj );
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.h b/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.h
index 789c124..d1debd3 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.h
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonreader.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonreader.h 28350 2015-01-23 17:53:57Z rouault $
+ * $Id: ogrgeojsonreader.h 29111 2015-05-02 18:06:16Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Defines GeoJSON reader within OGR OGRGeoJSON Driver.
@@ -31,6 +31,7 @@
 #define OGR_GEOJSONREADER_H_INCLUDED
 
 #include <ogr_core.h>
+#include "ogrsf_frmts.h"
 #include <json.h> // JSON-C
 
 /************************************************************************/
@@ -93,6 +94,7 @@ public:
 
     void SetPreserveGeometryType( bool bPreserve );
     void SetSkipAttributes( bool bSkip );
+    void SetFlattenNestedAttributes( bool bFlatten, char chSeparator );
 
     OGRErr Parse( const char* pszText );
     void ReadLayers( OGRGeoJSONDataSource* poDS );
@@ -100,12 +102,16 @@ public:
                     const char* pszName,
                     json_object* poObj );
 
+    json_object* GetJSonObject() { return poGJObject_; }
+
 private:
 
     json_object* poGJObject_;
 
     bool bGeometryPreserve_;
     bool bAttributesSkip_;
+    bool bFlattenNestedAttributes_;
+    char chNestedAttributeSeparator_;
 
     int bFlattenGeocouchSpatiallistFormat;
     bool bFoundId, bFoundRev, bFoundTypeFeature, bIsGeocouchSpatiallistFormat;
@@ -129,6 +135,19 @@ private:
     void ReadFeatureCollection( OGRGeoJSONLayer* poLayer, json_object* poObj );
 };
 
+void OGRGeoJSONReaderSetField(OGRLayer* poLayer,
+                              OGRFeature* poFeature,
+                              int nField,
+                              const char* pszAttrPrefix,
+                              json_object* poVal,
+                              bool bFlattenNestedAttributes,
+                              char chNestedAttributeSeparator);
+void OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn* poDefn,
+                                      const char* pszKey,
+                                      json_object* poVal,
+                                      bool bFlattenNestedAttributes,
+                                      char chNestedAttributeSeparator);
+
 /************************************************************************/
 /*                 GeoJSON Parsing Utilities                            */
 /************************************************************************/
@@ -168,6 +187,8 @@ public:
     OGRErr Parse( const char* pszText );
     void ReadLayers( OGRGeoJSONDataSource* poDS );
 
+    json_object* GetJSonObject() { return poGJObject_; }
+
 private:
 
     json_object* poGJObject_;
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.cpp
index e6f6e46..d0582dc 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonutils.cpp 27613 2014-08-30 15:55:30Z rouault $
+ * $Id: ogrgeojsonutils.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of private utilities used within OGR GeoJSON Driver.
@@ -78,50 +78,23 @@ int GeoJSONIsObject( const char* pszText )
 /************************************************************************/
 
 static
-int GeoJSONFileIsObject( const char* pszSource, VSILFILE** pfp ) 
+int GeoJSONFileIsObject( GDALOpenInfo* poOpenInfo ) 
 { 
-    CPLAssert( NULL != pszSource ); 
- 
-    VSILFILE* fp = NULL; 
-    fp = VSIFOpenL( pszSource, "rb" ); 
-    if( NULL == fp ) 
-    { 
-        return FALSE; 
-    } 
-    
     // by default read first 6000 bytes 
     // 6000 was chosen as enough bytes to  
     // enable all current tests to pass 
-    vsi_l_offset nToReadLen = 6000; 
-    vsi_l_offset nDataLen = 0; 
 
-    char* pszGeoData = (char*)VSIMalloc((size_t)(nToReadLen + 1)); 
-    if( NULL == pszGeoData ) 
+    if( poOpenInfo->fpL == NULL ||
+        !poOpenInfo->TryToIngest(6000) ) 
     { 
-        VSIFCloseL(fp); 
         return FALSE; 
     } 
 
-    nDataLen = VSIFReadL( pszGeoData, 1, (size_t)nToReadLen, fp );
-    pszGeoData[nDataLen] = '\0'; 
-    if( nDataLen == 0 ) 
-    { 
-        VSIFCloseL( fp ); 
-        CPLFree( pszGeoData ); 
-        return FALSE; 
-    }
-
-    if( !GeoJSONIsObject(pszGeoData) )
+    if( !GeoJSONIsObject((const char*)poOpenInfo->pabyHeader) )
     {
-        CPLFree( pszGeoData ); 
-        VSIFCloseL( fp ); 
         return FALSE;
     }
 
-    *pfp = fp;
-
-    CPLFree( pszGeoData ); 
-
     return TRUE; 
 } 
 
@@ -129,33 +102,37 @@ int GeoJSONFileIsObject( const char* pszSource, VSILFILE** pfp )
 /*                           GeoJSONGetSourceType()                     */
 /************************************************************************/
 
-GeoJSONSourceType GeoJSONGetSourceType( const char* pszSource, VSILFILE** pfp )
+GeoJSONSourceType GeoJSONGetSourceType( GDALOpenInfo* poOpenInfo )
 {
     GeoJSONSourceType srcType = eGeoJSONSourceUnknown;
 
-    *pfp = NULL;
-
     // NOTE: Sometimes URL ends with .geojson token, for example
     //       http://example/path/2232.geojson
     //       It's important to test beginning of source first.
-    if ( eGeoJSONProtocolUnknown != GeoJSONGetProtocolType( pszSource ) )
+    if ( eGeoJSONProtocolUnknown != GeoJSONGetProtocolType( poOpenInfo->pszFilename ) )
     {
+        if( (strstr(poOpenInfo->pszFilename, "SERVICE=WFS") ||
+             strstr(poOpenInfo->pszFilename, "service=WFS") ||
+             strstr(poOpenInfo->pszFilename, "service=wfs")) &&
+             !strstr(poOpenInfo->pszFilename, "json") )
+            return srcType;
         srcType = eGeoJSONSourceService;
     }
-    else if( EQUAL( CPLGetExtension( pszSource ), "geojson" )
-             || EQUAL( CPLGetExtension( pszSource ), "json" )
-             || EQUAL( CPLGetExtension( pszSource ), "topojson" )
-             || ((EQUALN( pszSource, "/vsigzip/", 9) || EQUALN( pszSource, "/vsizip/", 8)) &&
-                 (strstr( pszSource, ".json") || strstr( pszSource, ".JSON") ||
-                  strstr( pszSource, ".geojson") || strstr( pszSource, ".GEOJSON")) ))
+    else if( EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "geojson" )
+             || EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "json" )
+             || EQUAL( CPLGetExtension( poOpenInfo->pszFilename ), "topojson" )
+             || ((EQUALN( poOpenInfo->pszFilename, "/vsigzip/", 9) || EQUALN( poOpenInfo->pszFilename, "/vsizip/", 8)) &&
+                 (strstr( poOpenInfo->pszFilename, ".json") || strstr( poOpenInfo->pszFilename, ".JSON") ||
+                  strstr( poOpenInfo->pszFilename, ".geojson") || strstr( poOpenInfo->pszFilename, ".GEOJSON")) ))
     {
-        srcType = eGeoJSONSourceFile;
+        if( poOpenInfo->fpL != NULL )
+            srcType = eGeoJSONSourceFile;
     }
-    else if( GeoJSONIsObject( pszSource ) )
+    else if( GeoJSONIsObject( poOpenInfo->pszFilename ) )
     {
         srcType = eGeoJSONSourceText;
     }
-    else if( GeoJSONFileIsObject( pszSource, pfp ) )
+    else if( GeoJSONFileIsObject( poOpenInfo ) )
     {
         srcType = eGeoJSONSourceFile;
     }
@@ -188,43 +165,39 @@ GeoJSONProtocolType GeoJSONGetProtocolType( const char* pszSource )
 #define MY_INT64_MAX ((((GIntBig)0x7FFFFFFF) << 32) | 0xFFFFFFFF)
 #define MY_INT64_MIN ((((GIntBig)0x80000000) << 32))
 
-OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject )
+OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject,
+                                         OGRFieldSubType& eSubType )
 {
+    eSubType = OFSTNone;
+
     if (poObject == NULL) { return OFTString; }
 
     json_type type = json_object_get_type( poObject );
 
     if( json_type_boolean == type )
+    {
+        eSubType = OFSTBoolean;
         return OFTInteger;
+    }
     else if( json_type_double == type )
         return OFTReal;
     else if( json_type_int == type )
     {
         GIntBig nVal = json_object_get_int64(poObject);
-        if( nVal == MY_INT64_MIN || nVal == MY_INT64_MAX )
+        if( nVal != (GIntBig)(int) nVal )
         {
-            static int bWarned = FALSE;
-            if( !bWarned )
+            if( nVal == MY_INT64_MIN || nVal == MY_INT64_MAX )
             {
-                bWarned = TRUE;
-                CPLError(CE_Warning, CPLE_AppDefined,
-                         "Integer values ranging out of 64bit integer range "
-                         "have been found. Will be clamped to INT64_MIN/INT64_MAX");
+                static int bWarned = FALSE;
+                if( !bWarned )
+                {
+                    bWarned = TRUE;
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Integer values probably ranging out of 64bit integer range "
+                             "have been found. Will be clamped to INT64_MIN/INT64_MAX");
+                }
             }
-            return OFTString;
-        }
-        // FIXME when we have 64bit integer
-        if( nVal != (int) nVal )
-        {
-            static int bWarned = FALSE;
-            if( !bWarned )
-            {
-                bWarned = TRUE;
-                CPLDebug("GeoJSON",
-                         "64b-bit integer have been found. Will be reported as "
-                         "strings");
-            }
-            return OFTString;
+            return OFTInteger64;
         }
         else
         {
@@ -239,21 +212,32 @@ OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject )
         if (nSize == 0)
             return OFTStringList; /* we don't know, so let's assume it's a string list */
         OGRFieldType eType = OFTIntegerList;
+        int bOnlyBoolean = TRUE;
         for(int i=0;i<nSize;i++)
         {
             json_object* poRow = json_object_array_get_idx(poObject, i);
             if (poRow != NULL)
             {
                 type = json_object_get_type( poRow );
+                bOnlyBoolean &= (type == json_type_boolean);
                 if (type == json_type_string)
                     return OFTStringList;
                 else if (type == json_type_double)
                     eType = OFTRealList;
+                else if (eType == OFTIntegerList &&
+                         type == json_type_int)
+                {
+                    GIntBig nVal = json_object_get_int64(poRow);
+                    if( nVal != (GIntBig)(int)nVal )
+                        eType = OFTInteger64List;
+                }
                 else if (type != json_type_int &&
                          type != json_type_boolean)
                     return OFTString;
             }
         }
+        if( bOnlyBoolean )
+            eSubType = OFSTBoolean;
         return eType;
     }
     else
@@ -261,6 +245,35 @@ OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject )
 }
 
 /************************************************************************/
+/*                        GeoJSONStringPropertyToFieldType()            */
+/************************************************************************/
+
+OGRFieldType GeoJSONStringPropertyToFieldType( json_object* poObject )
+{
+    if (poObject == NULL) { return OFTString; }
+    const char* pszStr = json_object_get_string( poObject );
+
+    OGRField sWrkField;
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    int bSuccess = OGRParseDate( pszStr, &sWrkField, 0 );
+    CPLPopErrorHandler();
+    CPLErrorReset();
+    if( bSuccess )
+    {
+        int bHasDate = strchr( pszStr, '/' ) != NULL ||
+                        strchr( pszStr, '-' ) != NULL;
+        int bHasTime = strchr( pszStr, ':' ) != NULL;
+        if( bHasDate && bHasTime )
+            return OFTDateTime;
+        else if( bHasDate )
+            return OFTDate;
+        else
+            return OFTTime;
+    }
+    return OFTString;
+}
+
+/************************************************************************/
 /*                           OGRGeoJSONGetGeometryName()                */
 /************************************************************************/
 
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.h b/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.h
index 7cd1707..0631ddb 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.h
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonutils.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonutils.h 26296 2013-08-11 09:30:09Z rouault $
+ * $Id: ogrgeojsonutils.h 28009 2014-11-26 12:50:04Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private utilities within OGR OGRGeoJSON Driver.
@@ -32,6 +32,7 @@
 #include <ogr_core.h>
 #include <json.h> // JSON-C
 #include "cpl_vsi.h"
+#include "gdal_priv.h"
 
 class OGRGeometry;
 
@@ -47,7 +48,7 @@ enum GeoJSONSourceType
     eGeoJSONSourceService
 };
 
-GeoJSONSourceType GeoJSONGetSourceType( const char* pszSource, VSILFILE** pfp );
+GeoJSONSourceType GeoJSONGetSourceType( GDALOpenInfo* poOpenInfo );
 
 /************************************************************************/
 /*                           GeoJSONProtocolType                        */
@@ -73,7 +74,15 @@ int GeoJSONIsObject( const char* pszText );
 /*                           GeoJSONPropertyToFieldType                 */
 /************************************************************************/
 
-OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject );
+OGRFieldType GeoJSONPropertyToFieldType( json_object* poObject,
+                                         OGRFieldSubType& eSubType );
+
+
+/************************************************************************/
+/*                      GeoJSONStringPropertyToFieldType                */
+/************************************************************************/
+
+OGRFieldType GeoJSONStringPropertyToFieldType( json_object* poObject );
 
 /************************************************************************/
 /*                           OGRGeoJSONGetGeometryName                  */
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp
index 2575d30..f47b713 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonwritelayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeojsonwritelayer.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRGeoJSONWriteLayer class (OGR GeoJSON Driver).
@@ -50,6 +50,7 @@ OGRGeoJSONWriteLayer::OGRGeoJSONWriteLayer( const char* pszName,
 
     poFeatureDefn_->Reference();
     poFeatureDefn_->SetGeomType( eGType );
+    SetDescription( poFeatureDefn_->GetName() );
 
     nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1"));
 }
@@ -107,10 +108,10 @@ OGRGeoJSONWriteLayer::~OGRGeoJSONWriteLayer()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGeoJSONWriteLayer::CreateFeature( OGRFeature* poFeature )
+OGRErr OGRGeoJSONWriteLayer::ICreateFeature( OGRFeature* poFeature )
 {
     VSILFILE* fp = poDS_->GetOutputFile();
 
diff --git a/ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp b/ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
index 198b134..0e6d364 100644
--- a/ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrgeojsonwriter.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeojsonwriter.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgeojsonwriter.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of GeoJSON writer utilities (OGR GeoJSON Driver).
@@ -56,7 +56,7 @@ json_object* OGRGeoJSONWriteFeature( OGRFeature* poFeature, int bWriteBBOX, int
     if ( poFeature->GetFID() != OGRNullFID )
     {
         json_object_object_add( poObj, "id",
-                                json_object_new_int((int)poFeature->GetFID()) );
+                                json_object_new_int64(poFeature->GetFID()) );
     }
 
 /* -------------------------------------------------------------------- */
@@ -126,6 +126,7 @@ json_object* OGRGeoJSONWriteAttributes( OGRFeature* poFeature )
         OGRFieldDefn* poFieldDefn = poDefn->GetFieldDefn( nField );
         CPLAssert( NULL != poFieldDefn );
         OGRFieldType eType = poFieldDefn->GetType();
+        OGRFieldSubType eSubType = poFieldDefn->GetSubType();
 
         if( !poFeature->IsFieldSet(nField) )
         {
@@ -133,8 +134,21 @@ json_object* OGRGeoJSONWriteAttributes( OGRFeature* poFeature )
         }
         else if( OFTInteger == eType )
         {
-            poObjProp = json_object_new_int( 
-                poFeature->GetFieldAsInteger( nField ) );
+            if( eSubType == OFSTBoolean )
+                poObjProp = json_object_new_boolean( 
+                    poFeature->GetFieldAsInteger( nField ) );
+            else
+                poObjProp = json_object_new_int( 
+                    poFeature->GetFieldAsInteger( nField ) );
+        }
+        else if( OFTInteger64 == eType )
+        {
+            if( eSubType == OFSTBoolean )
+                poObjProp = json_object_new_boolean( 
+                    (json_bool)poFeature->GetFieldAsInteger64( nField ) );
+            else
+                poObjProp = json_object_new_int64( 
+                    poFeature->GetFieldAsInteger64( nField ) );
         }
         else if( OFTReal == eType )
         {
@@ -153,10 +167,29 @@ json_object* OGRGeoJSONWriteAttributes( OGRFeature* poFeature )
             poObjProp = json_object_new_array();
             for(int i=0;i<nSize;i++)
             {
-                json_object_array_add(poObjProp,
+                if( eSubType == OFSTBoolean )
+                    json_object_array_add(poObjProp,
+                            json_object_new_boolean(panList[i]));
+                else
+                    json_object_array_add(poObjProp,
                             json_object_new_int(panList[i]));
             }
         }
+        else if( OFTInteger64List == eType )
+        {
+            int nSize = 0;
+            const GIntBig* panList = poFeature->GetFieldAsInteger64List(nField, &nSize);
+            poObjProp = json_object_new_array();
+            for(int i=0;i<nSize;i++)
+            {
+                if( eSubType == OFSTBoolean )
+                    json_object_array_add(poObjProp,
+                            json_object_new_boolean((json_bool)panList[i]));
+                else
+                    json_object_array_add(poObjProp,
+                            json_object_new_int64(panList[i]));
+            }
+        }
         else if( OFTRealList == eType )
         {
             int nSize = 0;
@@ -606,13 +639,13 @@ static int OGR_json_double_with_precision_to_string(struct json_object *jso,
                                                     CPL_UNUSED int level,
                                                     CPL_UNUSED int flags)
 {
-    char szBuffer[75]; 
+    char szBuffer[75];
     int nPrecision = (int) (size_t) jso->_userdata;
-    OGRFormatDouble( szBuffer, sizeof(szBuffer), jso->o.c_double, '.', 
-                     (nPrecision < 0) ? 15 : nPrecision ); 
+    OGRFormatDouble( szBuffer, sizeof(szBuffer), jso->o.c_double, '.',
+                     (nPrecision < 0) ? 15 : nPrecision );
     if( szBuffer[0] == 't' /*oobig */ )
     {
-        snprintf(szBuffer, sizeof(szBuffer), "%.18g", jso->o.c_double);
+        CPLsnprintf(szBuffer, sizeof(szBuffer), "%.18g", jso->o.c_double);
     }
     return printbuf_memappend(pb, szBuffer, strlen(szBuffer)); 
 }
diff --git a/ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp b/ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp
index b558faa..5daeaa5 100644
--- a/ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp
+++ b/ogr/ogrsf_frmts/geojson/ogrtopojsonreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtopojsonreader.cpp 27268 2014-05-01 10:46:20Z rouault $
+ * $Id: ogrtopojsonreader.cpp 28886 2015-04-12 23:09:13Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implementation of OGRTopoJSONReader class
@@ -274,6 +274,8 @@ static void ParseObject(const char* pszId,
                         json_object* poArcsDB, ScalingParams* psParams)
 {
     json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type");
+    if( poType == NULL || json_object_get_type(poType) != json_type_string )
+        return;
     const char* pszType = json_object_get_string(poType);
 
     json_object* poArcsObj = OGRGeoJSONFindMemberByName(poObj, "arcs");
@@ -307,11 +309,15 @@ static void ParseObject(const char* pszId,
     json_object* poProperties = OGRGeoJSONFindMemberByName(poObj, "properties");
     if( poProperties != NULL && json_type_object == json_object_get_type(poProperties) )
     {
-        json_object* poName = OGRGeoJSONFindMemberByName(poProperties, "name");
-        if( poName != NULL && json_type_string == json_object_get_type(poName) )
+        int nField = -1;
+        json_object_iter it;
+        it.key = NULL;
+        it.val = NULL;
+        it.entry = NULL;
+        json_object_object_foreachC( poProperties, it )
         {
-            const char* pszName = json_object_get_string(poName);
-            poFeature->SetField("name", pszName);
+            nField = poFeature->GetFieldIndex(it.key);
+            OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val, FALSE, 0);
         }
     }
 
@@ -376,23 +382,49 @@ static void ParseObject(const char* pszId,
     delete poFeature;
 }
 
+
+/************************************************************************/
+/*                        EstablishLayerDefn()                          */
+/************************************************************************/
+
+static void EstablishLayerDefn(OGRFeatureDefn* poDefn,
+                               json_object* poObj)
+{
+    json_object* poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
+    if( NULL != poObjProps &&
+        json_object_get_type(poObjProps) == json_type_object )
+    {
+        json_object_iter it;
+        it.key = NULL;
+        it.val = NULL;
+        it.entry = NULL;
+        json_object_object_foreachC( poObjProps, it )
+        {
+            OGRGeoJSONReaderAddOrUpdateField(poDefn, it.key, it.val, FALSE, 0);
+        }
+    }
+}
+
 /************************************************************************/
 /*                        ParseObjectMain()                             */
 /************************************************************************/
 
-static void ParseObjectMain(const char* pszId, json_object* poObj,
+static int  ParseObjectMain(const char* pszId, json_object* poObj,
                             OGRGeoJSONDataSource* poDS,
                             OGRGeoJSONLayer **ppoMainLayer,
                             json_object* poArcs,
-                            ScalingParams* psParams)
+                            ScalingParams* psParams,
+                            int nPassNumber)
 {
+    int bNeedSecondPass = FALSE;
+
     if( poObj != NULL && json_type_object == json_object_get_type( poObj ) )
     {
         json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type");
         if( poType != NULL && json_type_string == json_object_get_type( poType ) )
         {
             const char* pszType = json_object_get_string(poType);
-            if( strcmp(pszType, "GeometryCollection") == 0 )
+            if( nPassNumber == 1 && strcmp(pszType, "GeometryCollection") == 0 )
             {
                 json_object* poGeometries = OGRGeoJSONFindMemberByName(poObj, "geometries");
                 if( poGeometries != NULL &&
@@ -412,16 +444,26 @@ static void ParseObjectMain(const char* pszId, json_object* poObj,
                     OGRGeoJSONLayer* poLayer = new OGRGeoJSONLayer(
                             pszId ? pszId : "TopoJSON", NULL,
                             wkbUnknown, poDS );
+                    OGRFeatureDefn* poDefn = poLayer->GetLayerDefn();
                     {
                         OGRFieldDefn fldDefn( "id", OFTString );
-                        poLayer->GetLayerDefn()->AddFieldDefn( &fldDefn );
+                        poDefn->AddFieldDefn( &fldDefn );
                     }
+
+                    int nGeometries = json_object_array_length(poGeometries);
+                    /* First pass to establish schema */
+                    for(int i=0; i<nGeometries; i++)
                     {
-                        OGRFieldDefn fldDefn( "name", OFTString );
-                        poLayer->GetLayerDefn()->AddFieldDefn( &fldDefn );
+                        json_object* poGeom =
+                            json_object_array_get_idx(poGeometries, i);
+                        if( poGeom != NULL &&
+                            json_type_object == json_object_get_type( poGeom ) )
+                        {
+                            EstablishLayerDefn(poDefn, poGeom);
+                        }
                     }
 
-                    int nGeometries = json_object_array_length(poGeometries);
+                    /* Second pass to build objects */
                     for(int i=0; i<nGeometries; i++)
                     {
                         json_object* poGeom =
@@ -443,23 +485,27 @@ static void ParseObjectMain(const char* pszId, json_object* poObj,
                      strcmp(pszType, "Polygon") == 0 ||
                      strcmp(pszType, "MultiPolygon") == 0 )
             {
-                if( *ppoMainLayer == NULL )
+                if( nPassNumber == 1 )
                 {
-                    *ppoMainLayer = new OGRGeoJSONLayer(
-                        "TopoJSON", NULL, wkbUnknown, poDS );
-                    {
-                        OGRFieldDefn fldDefn( "id", OFTString );
-                        (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn );
-                    }
+                    if( *ppoMainLayer == NULL )
                     {
-                        OGRFieldDefn fldDefn( "name", OFTString );
-                        (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn );
+                        *ppoMainLayer = new OGRGeoJSONLayer(
+                            "TopoJSON", NULL, wkbUnknown, poDS );
+                        {
+                            OGRFieldDefn fldDefn( "id", OFTString );
+                            (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn );
+                        }
                     }
+                    OGRFeatureDefn* poDefn = (*ppoMainLayer)->GetLayerDefn();
+                    EstablishLayerDefn(poDefn, poObj);
+                    bNeedSecondPass = TRUE;
                 }
-                ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams);
+                else
+                    ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams);
             }
         }
     }
+    return bNeedSecondPass;
 }
 
 /************************************************************************/
@@ -536,19 +582,40 @@ void OGRTopoJSONReader::ReadLayers( OGRGeoJSONDataSource* poDS )
         it.key = NULL;
         it.val = NULL;
         it.entry = NULL;
+        int bNeedSecondPass = FALSE;
         json_object_object_foreachC( poObjects, it )
         {
             json_object* poObj = it.val;
-            ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams);
+            bNeedSecondPass |= ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams, 1);
+        }
+        if( bNeedSecondPass )
+        {
+            it.key = NULL;
+            it.val = NULL;
+            it.entry = NULL;
+            json_object_object_foreachC( poObjects, it )
+            {
+                json_object* poObj = it.val;
+                ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams, 2);
+            }
         }
     }
     else if( json_type_array == json_object_get_type( poObjects ) )
     {
         int nObjects = json_object_array_length(poObjects);
+        int bNeedSecondPass = FALSE;
         for(int i=0; i<nObjects; i++)
         {
             json_object* poObj = json_object_array_get_idx(poObjects, i);
-            ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams);
+            bNeedSecondPass |= ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams, 1);
+        }
+        if( bNeedSecondPass )
+        {
+            for(int i=0; i<nObjects; i++)
+            {
+                json_object* poObj = json_object_array_get_idx(poObjects, i);
+                ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams, 2);
+            }
         }
     }
 
diff --git a/ogr/ogrsf_frmts/geomedia/GNUmakefile b/ogr/ogrsf_frmts/geomedia/GNUmakefile
index 7a99793..53aa63d 100644
--- a/ogr/ogrsf_frmts/geomedia/GNUmakefile
+++ b/ogr/ogrsf_frmts/geomedia/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrgeomediadatasource.o ogrgeomedialayer.o ogrgeomediadriver.o \
 		ogrgeomediatablelayer.o ogrgeomediaselectlayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I.. -I../.. -I../pgeo $(CPPFLAGS)
+CPPFLAGS	:=	 -I.. -I../.. -I../pgeo $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/geomedia/ogr_geomedia.h b/ogr/ogrsf_frmts/geomedia/ogr_geomedia.h
index 41f145b..091423e 100644
--- a/ogr/ogrsf_frmts/geomedia/ogr_geomedia.h
+++ b/ogr/ogrsf_frmts/geomedia/ogr_geomedia.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_geomedia.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_geomedia.h 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for Geomedia MDB driver.
@@ -53,7 +53,7 @@ class OGRGeomediaLayer : public OGRLayer
     OGRSpatialReference *poSRS;
     int                 nSRSId;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRGeomediaDataSource    *poDS;
 
@@ -77,7 +77,7 @@ class OGRGeomediaLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
     
@@ -111,10 +111,10 @@ class OGRGeomediaTableLayer : public OGRGeomediaLayer
                                     OGRSpatialReference* poSRS );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual int         TestCapability( const char * );
 };
@@ -138,9 +138,9 @@ class OGRGeomediaSelectLayer : public OGRGeomediaLayer
                         ~OGRGeomediaSelectLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual int         TestCapability( const char * );
 };
diff --git a/ogr/ogrsf_frmts/geomedia/ogrgeomediadatasource.cpp b/ogr/ogrsf_frmts/geomedia/ogrgeomediadatasource.cpp
index e582daa..acaaeb4 100644
--- a/ogr/ogrsf_frmts/geomedia/ogrgeomediadatasource.cpp
+++ b/ogr/ogrsf_frmts/geomedia/ogrgeomediadatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomediadatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrgeomediadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGeomediaDataSource class.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include <vector>
 
-CPL_CVSID("$Id: ogrgeomediadatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrgeomediadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                       OGRGeomediaDataSource()                        */
diff --git a/ogr/ogrsf_frmts/geomedia/ogrgeomediadriver.cpp b/ogr/ogrsf_frmts/geomedia/ogrgeomediadriver.cpp
index a378a69..14ea075 100644
--- a/ogr/ogrsf_frmts/geomedia/ogrgeomediadriver.cpp
+++ b/ogr/ogrsf_frmts/geomedia/ogrgeomediadriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomediadriver.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrgeomediadriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Personal Geodatabase driver.
@@ -31,7 +31,7 @@
 #include "ogr_geomedia.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrgeomediadriver.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrgeomediadriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          ~OGRODBCDriver()                            */
@@ -153,5 +153,11 @@ int OGRGeomediaDriver::TestCapability( CPL_UNUSED const char * pszCap )
 void RegisterOGRGeomedia()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGeomediaDriver );
+    OGRSFDriver* poDriver = new OGRGeomediaDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "Geomedia .mdb" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mdb" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_geomedia.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
diff --git a/ogr/ogrsf_frmts/geomedia/ogrgeomedialayer.cpp b/ogr/ogrsf_frmts/geomedia/ogrgeomedialayer.cpp
index ecaee4d..ad8fc20 100644
--- a/ogr/ogrsf_frmts/geomedia/ogrgeomedialayer.cpp
+++ b/ogr/ogrsf_frmts/geomedia/ogrgeomedialayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomedialayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrgeomedialayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGeomediaLayer class, code shared between
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogrgeomediageometry.h"
 
-CPL_CVSID("$Id: ogrgeomedialayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrgeomedialayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRGeomediaLayer()                          */
@@ -105,6 +105,7 @@ CPLErr OGRGeomediaLayer::BuildFeatureDefn( const char *pszLayerName,
 
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     int    nRawColumns = poStmt->GetColCount();
 
     poFeatureDefn->Reference();
@@ -306,7 +307,7 @@ OGRFeature *OGRGeomediaLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRGeomediaLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRGeomediaLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
diff --git a/ogr/ogrsf_frmts/geomedia/ogrgeomediaselectlayer.cpp b/ogr/ogrsf_frmts/geomedia/ogrgeomediaselectlayer.cpp
index b306ece..cc5a24a 100644
--- a/ogr/ogrsf_frmts/geomedia/ogrgeomediaselectlayer.cpp
+++ b/ogr/ogrsf_frmts/geomedia/ogrgeomediaselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomediaselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeomediaselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGeomediaSelectLayer class, layer access to the results
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_geomedia.h"
 
-CPL_CVSID("$Id: ogrgeomediaselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgeomediaselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                        OGRGeomediaSelectLayer()                      */
@@ -134,7 +134,7 @@ void OGRGeomediaSelectLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRGeomediaSelectLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRGeomediaSelectLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRGeomediaLayer::GetFeature( nFeatureId );
@@ -159,7 +159,7 @@ int OGRGeomediaSelectLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRGeomediaSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRGeomediaSelectLayer::GetFeatureCount( int bForce )
 
 {
     return OGRGeomediaLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/geomedia/ogrgeomediatablelayer.cpp b/ogr/ogrsf_frmts/geomedia/ogrgeomediatablelayer.cpp
index 3e09095..0cedd22 100644
--- a/ogr/ogrsf_frmts/geomedia/ogrgeomediatablelayer.cpp
+++ b/ogr/ogrsf_frmts/geomedia/ogrgeomediatablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeomediatablelayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeomediatablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGeomediaTableLayer class, access to an existing table.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "ogr_geomedia.h"
 
-CPL_CVSID("$Id: ogrgeomediatablelayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgeomediatablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRGeomediaTableLayer()                     */
@@ -205,7 +205,7 @@ void OGRGeomediaTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRGeomediaTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRGeomediaTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -218,7 +218,7 @@ OGRFeature *OGRGeomediaTableLayer::GetFeature( long nFeatureId )
     poStmt = new CPLODBCStatement( poDS->GetSession() );
     poStmt->Append( "SELECT * FROM " );
     poStmt->Append( poFeatureDefn->GetName() );
-    poStmt->Appendf( " WHERE %s = %ld", pszFIDColumn, nFeatureId );
+    poStmt->Appendf( " WHERE %s = " CPL_FRMT_GIB, pszFIDColumn, nFeatureId );
 
     if( !poStmt->ExecuteSQL() )
     {
@@ -280,7 +280,7 @@ int OGRGeomediaTableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRGeomediaTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRGeomediaTableLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL )
diff --git a/ogr/ogrsf_frmts/georss/GNUmakefile b/ogr/ogrsf_frmts/georss/GNUmakefile
index 7b810be..9b3c4f9 100644
--- a/ogr/ogrsf_frmts/georss/GNUmakefile
+++ b/ogr/ogrsf_frmts/georss/GNUmakefile
@@ -8,7 +8,7 @@ ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=   -DHAVE_EXPAT
 endif
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(EXPAT_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/georss/drv_georss.html b/ogr/ogrsf_frmts/georss/drv_georss.html
index cd9a56e..6d61669 100644
--- a/ogr/ogrsf_frmts/georss/drv_georss.html
+++ b/ogr/ogrsf_frmts/georss/drv_georss.html
@@ -61,7 +61,7 @@ Attributes of first level elements will be exposed as fields.<p>
 
 Complex content (elements inside first level elements) will be returned as an XML blob.<p>
 
-When a same element is repeated, a number will be appended at the end of the attribute name for the repetitions. This is usefull for the <category> element in RSS and Atom documents for example.<p>
+When a same element is repeated, a number will be appended at the end of the attribute name for the repetitions. This is useful for the <category> element in RSS and Atom documents for example.<p>
 
 <p>
 The following content :
diff --git a/ogr/ogrsf_frmts/georss/ogr_georss.h b/ogr/ogrsf_frmts/georss/ogr_georss.h
index 5088fd3..bb7bb8f 100644
--- a/ogr/ogrsf_frmts/georss/ogr_georss.h
+++ b/ogr/ogrsf_frmts/georss/ogr_georss.h
@@ -81,29 +81,37 @@ class OGRGeoRSSLayer : public OGRLayer
     int                bInFeature;
     int                hasFoundLat;
     int                hasFoundLon;
+#ifdef HAVE_EXPAT
     double             latVal;
     double             lonVal;
+#endif
     char*              pszSubElementName;
     char*              pszSubElementValue;
     int                nSubElementValueLen;
+#ifdef HAVE_EXPAT
     int                iCurrentField;
+#endif
     int                bInSimpleGeometry;
     int                bInGMLGeometry;
     int                bInGeoLat;
     int                bInGeoLong;
+#ifdef HAVE_EXPAT
     int                bFoundGeom;
-    OGRwkbGeometryType eGeomType;
     int                bSameSRS;
+#endif
+    OGRwkbGeometryType eGeomType;
     char*              pszGMLSRSName;
     int                bInTagWithSubTag;
     char*              pszTagWithSubTag;
     int                currentDepth;
     int                featureDepth;
     int                geometryDepth;
+#ifdef HAVE_EXPAT
     OGRFieldDefn*      currentFieldDefn;
     int                nWithoutEventCounter;
-    CPLHashSet*        setOfFoundFields;
     int                nDataHandlerCounter;
+#endif
+    CPLHashSet*        setOfFoundFields;
 
     OGRFeature*        poFeature;
     OGRFeature **      ppoFeatureTab;
@@ -127,14 +135,14 @@ class OGRGeoRSSLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
     
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK );
 
     OGRFeatureDefn *    GetLayerDefn();
     
     int                 TestCapability( const char * );
     
-    int                 GetFeatureCount( int bForce );
+    GIntBig             GetFeatureCount( int bForce );
 
     void                LoadSchema();
 
@@ -170,7 +178,9 @@ class OGRGeoRSSDataSource : public OGRDataSource
     /*  Export related */
     VSILFILE           *fpOutput; /* Virtual file API */
     
+#ifdef HAVE_EXPAT
     OGRGeoRSSValidity   validity;
+#endif
     OGRGeoRSSFormat     eFormat;
     OGRGeoRSSGeomDialect eGeomDialect;
     int                 bUseExtensions;
@@ -195,7 +205,7 @@ class OGRGeoRSSDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer*           GetLayer( int );
     
-    OGRLayer *          CreateLayer( const char * pszLayerName,
+    OGRLayer *          ICreateLayer( const char * pszLayerName,
                                     OGRSpatialReference *poSRS,
                                     OGRwkbGeometryType eType,
                                     char ** papszOptions );
@@ -213,22 +223,4 @@ class OGRGeoRSSDataSource : public OGRDataSource
 #endif
 };
 
-/************************************************************************/
-/*                             OGRGeoRSSDriver                             */
-/************************************************************************/
-
-class OGRGeoRSSDriver : public OGRSFDriver
-{
-  public:
-                ~OGRGeoRSSDriver();
-
-    const char*         GetName();
-    OGRDataSource*      Open( const char *, int );
-    OGRDataSource*      CreateDataSource( const char * pszName, char **papszOptions );
-    int                 DeleteDataSource( const char *pszFilename );
-    int                 TestCapability( const char * );
-    
-};
-
-
 #endif /* ndef _OGR_GeoRSS_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/georss/ogrgeorssdatasource.cpp b/ogr/ogrsf_frmts/georss/ogrgeorssdatasource.cpp
index 6baa9ed..209dde9 100644
--- a/ogr/ogrsf_frmts/georss/ogrgeorssdatasource.cpp
+++ b/ogr/ogrsf_frmts/georss/ogrgeorssdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeorssdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgeorssdatasource.cpp 28636 2015-03-06 19:18:43Z rouault $
  *
  * Project:  GeoRSS Translator
  * Purpose:  Implements OGRGeoRSSDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: ogrgeorssdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgeorssdatasource.cpp 28636 2015-03-06 19:18:43Z rouault $");
 
 /************************************************************************/
 /*                          OGRGeoRSSDataSource()                          */
@@ -113,13 +113,13 @@ OGRLayer *OGRGeoRSSDataSource::GetLayer( int iLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRGeoRSSDataSource::CreateLayer( const char * pszLayerName,
-                                             OGRSpatialReference *poSRS,
-                                             CPL_UNUSED OGRwkbGeometryType eType,
-                                             CPL_UNUSED char ** papszOptions )
+OGRLayer * OGRGeoRSSDataSource::ICreateLayer( const char * pszLayerName,
+                                              OGRSpatialReference *poSRS,
+                                              CPL_UNUSED OGRwkbGeometryType eType,
+                                              CPL_UNUSED char ** papszOptions )
 {
     if (fpOutput == NULL)
         return NULL;
@@ -157,7 +157,8 @@ void OGRGeoRSSDataSource::startElementValidateCbk(const char *pszName, const cha
             validity = GEORSS_VALIDITY_VALID;
             eFormat = GEORSS_RSS;
         }
-        else if (strcmp(pszName, "feed") == 0)
+        else if (strcmp(pszName, "feed") == 0 ||
+                 strcmp(pszName, "atom:feed") == 0)
         {
             validity = GEORSS_VALIDITY_VALID;
             eFormat = GEORSS_ATOM;
@@ -188,7 +189,7 @@ void OGRGeoRSSDataSource::startElementValidateCbk(const char *pszName, const cha
 /************************************************************************/
 
 void OGRGeoRSSDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data,
-                                                 CPL_UNUSED int nLen)
+                                                 CPL_UNUSED  int nLen)
 {
     nDataHandlerCounter ++;
     if (nDataHandlerCounter >= BUFSIZ)
@@ -263,7 +264,7 @@ int OGRGeoRSSDataSource::Open( const char * pszFilename, int bUpdateIn)
                 aBuf[nLen] = 0;
             else
                 aBuf[BUFSIZ-1] = 0;
-            if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<feed")))
+            if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<feed") || strstr(aBuf, "<atom:feed")))
             {
                 CPLError(CE_Failure, CPLE_AppDefined,
                         "XML parsing of GeoRSS file failed : %s at line %d, column %d",
@@ -313,7 +314,7 @@ int OGRGeoRSSDataSource::Open( const char * pszFilename, int bUpdateIn)
     {
         unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, 255, fp );
         aBuf[nLen] = 0;
-        if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<feed")))
+        if (strstr(aBuf, "<?xml") && (strstr(aBuf, "<rss") || strstr(aBuf, "<atom:feed") || strstr(aBuf, "<feed")))
         {
             CPLError(CE_Failure, CPLE_NotSupported,
                     "OGR/GeoRSS driver has not been built with read support. Expat library required");
diff --git a/ogr/ogrsf_frmts/georss/ogrgeorssdriver.cpp b/ogr/ogrsf_frmts/georss/ogrgeorssdriver.cpp
index 9cd29c1..a661123 100644
--- a/ogr/ogrsf_frmts/georss/ogrgeorssdriver.cpp
+++ b/ogr/ogrsf_frmts/georss/ogrgeorssdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeorssdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgeorssdriver.cpp 28636 2015-03-06 19:18:43Z rouault $
  *
  * Project:  GeoRSS Translator
  * Purpose:  Implements OGRGeoRSSDriver.
@@ -30,42 +30,26 @@
 #include "ogr_georss.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrgeorssdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-/************************************************************************/
-/*                           ~OGRGeoRSSDriver()                            */
-/************************************************************************/
-
-OGRGeoRSSDriver::~OGRGeoRSSDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRGeoRSSDriver::GetName()
-
-{
-    return "GeoRSS";
-}
+CPL_CVSID("$Id: ogrgeorssdriver.cpp 28636 2015-03-06 19:18:43Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGeoRSSDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRGeoRSSDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    if (bUpdate)
-    {
+    if( poOpenInfo->eAccess == GA_Update || poOpenInfo->fpL == NULL )
+        return NULL;
+
+    if( strstr((const char*)poOpenInfo->pabyHeader, "<rss") == NULL &&
+        strstr((const char*)poOpenInfo->pabyHeader, "<feed") == NULL &&
+        strstr((const char*)poOpenInfo->pabyHeader, "<atom:feed") == NULL )
         return NULL;
-    }
 
     OGRGeoRSSDataSource   *poDS = new OGRGeoRSSDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update ) )
     {
         delete poDS;
         poDS = NULL;
@@ -75,12 +59,15 @@ OGRDataSource *OGRGeoRSSDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRGeoRSSDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRGeoRSSDriverCreate( const char * pszName,
+                                           CPL_UNUSED int nBands,
+                                           CPL_UNUSED int nXSize,
+                                           CPL_UNUSED int nYSize,
+                                           CPL_UNUSED GDALDataType eDT,
+                                           char **papszOptions )
 {
     OGRGeoRSSDataSource   *poDS = new OGRGeoRSSDataSource();
 
@@ -94,34 +81,18 @@ OGRDataSource *OGRGeoRSSDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                               Delete()                               */
 /************************************************************************/
 
-OGRErr OGRGeoRSSDriver::DeleteDataSource( const char *pszFilename )
+static CPLErr OGRGeoRSSDriverDelete( const char *pszFilename )
 
 {
     if( VSIUnlink( pszFilename ) == 0 )
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGeoRSSDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
+        return CE_None;
     else
-        return FALSE;
+        return CE_Failure;
 }
 
-
 /************************************************************************/
 /*                           RegisterOGRGeoRSS()                           */
 /************************************************************************/
@@ -131,6 +102,48 @@ void RegisterOGRGeoRSS()
 {
     if (! GDAL_CHECK_VERSION("OGR/GeoRSS driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGeoRSSDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "GeoRSS" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "GeoRSS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GeoRSS" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_georss.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='FORMAT' type='string-select' description='whether the document must be in RSS 2.0 or Atom 1.0 format' default='RSS'>"
+"    <Value>RSS</Value>"
+"    <Value>ATOM</Value>"
+"  </Option>"
+"  <Option name='GEOM_DIALECT' type='string-select' description='encoding of location information' default='SIMPLE'>"
+"    <Value>SIMPLE</Value>"
+"    <Value>GML</Value>"
+"    <Value>W3C_GEO</Value>"
+"  </Option>"
+"  <Option name='USE_EXTENSIONS' type='boolean' description='Whether extension fields (that is to say fields not in the base schema of RSS or Atom documents) will be written' default='NO'/>"
+"  <Option name='WRITE_HEADER_AND_FOOTER' type='boolean' description='Whether header and footer are written' default='YES'/>"
+"  <Option name='HEADER' type='string' description='XML content that will be put between the <channel> element and the first <item> element for a RSS document, or between the xml tag and the first <entry> element for an Atom document. If it is specified, it will overload the following options'/>"
+"  <Option name='TITLE' type='string' description='value put inside the <title> element in the header'/>"
+"  <Option name='DESCRIPTION' type='string' description='(RSS only) value put inside the <description> element in the header'/>"
+"  <Option name='LINK' type='string' description='(RSS only) value put inside the <link> element in the header'/>"
+"  <Option name='UPDATED' type='string' description='(RSS only) value put inside the <updated> element in the header. Should be formatted as a XML datetime'/>"
+"  <Option name='AUTHOR_NAME' type='string' description='(ATOM only) value put inside the <author><name> element in the header'/>"
+"  <Option name='ID' type='string' description='(ATOM only) value put inside the <id> element in the header.'/>"
+"</CreationOptionList>");
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRGeoRSSDriverOpen;
+        poDriver->pfnCreate = OGRGeoRSSDriverCreate;
+        poDriver->pfnDelete = OGRGeoRSSDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/georss/ogrgeorsslayer.cpp b/ogr/ogrsf_frmts/georss/ogrgeorsslayer.cpp
index 6de0e54..66818c4 100644
--- a/ogr/ogrsf_frmts/georss/ogrgeorsslayer.cpp
+++ b/ogr/ogrsf_frmts/georss/ogrgeorsslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgeorsslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgeorsslayer.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  GeoRSS Translator
  * Purpose:  Implements OGRGeoRSSLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_api.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrgeorsslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgeorsslayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 static const char* apszAllowedATOMFieldNamesWithSubElements[] = { "author", "contributor", NULL };
 
@@ -94,6 +94,7 @@ OGRGeoRSSLayer::OGRGeoRSSLayer( const char* pszFilename,
     eFormat = poDS->GetFormat();
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poSRS = poSRSIn;
@@ -340,11 +341,16 @@ static int OGRGeoRSSLayerATOMTagHasSubElement(const char* pszName)
 void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
 {
     int bSerializeTag = FALSE;
+    const char* pszNoNSName = pszName;
+    const char* pszColon = strchr(pszNoNSName, ':');
+    if( pszColon )
+        pszNoNSName = pszColon + 1;
 
     if (bStopParsing) return;
 
-    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
-        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && !bInFeature && (currentDepth == 1 || currentDepth == 2) && strcmp(pszName, "item") == 0))
+    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszNoNSName, "entry") == 0) ||
+        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && !bInFeature &&
+        (currentDepth == 1 || currentDepth == 2) && strcmp(pszNoNSName, "item") == 0))
     {
         featureDepth = currentDepth;
 
@@ -371,7 +377,7 @@ void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
     }
     else if (bInFeature && bInTagWithSubTag && currentDepth == 3)
     {
-        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
+        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszNoNSName));
 
         CPLFree(pszSubElementName);
         pszSubElementName = NULL;
@@ -386,17 +392,17 @@ void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
         CPLFree(pszFieldName);
     }
     else if (bInFeature && eFormat == GEORSS_ATOM &&
-             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
+             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszNoNSName))
     {
         CPLFree(pszTagWithSubTag);
-        pszTagWithSubTag = CPLStrdup(pszName);
+        pszTagWithSubTag = CPLStrdup(pszNoNSName);
 
         int count = 1;
         while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
         {
             count ++;
             CPLFree(pszTagWithSubTag);
-            pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
+            pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszNoNSName, count));
         }
         CPLHashSetInsert(setOfFoundFields, CPLStrdup(pszTagWithSubTag));
 
@@ -476,6 +482,9 @@ void OGRGeoRSSLayer::startElementCbk(const char *pszName, const char **ppszAttr)
         nSubElementValueLen = 0;
         iCurrentField = -1;
 
+        if( pszName != pszNoNSName && strncmp(pszName, "atom:", 5) == 0 )
+            pszName = pszNoNSName;
+
         pszSubElementName = CPLStrdup(pszName);
         int count = 1;
         while(CPLHashSetLookup(setOfFoundFields, pszSubElementName) != NULL)
@@ -574,9 +583,14 @@ void OGRGeoRSSLayer::endElementCbk(const char *pszName)
     if (bStopParsing) return;
 
     currentDepth--;
+    const char* pszNoNSName = pszName;
+    const char* pszColon = strchr(pszNoNSName, ':');
+    if( pszColon )
+        pszNoNSName = pszColon + 1;
 
-    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
-        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && (currentDepth == 1 || currentDepth == 2) && strcmp(pszName, "item") == 0))
+    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszNoNSName, "entry") == 0) ||
+        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) &&
+         (currentDepth == 1 || currentDepth == 2) && strcmp(pszNoNSName, "item") == 0))
     {
         bInFeature = FALSE;
         bInTagWithSubTag = FALSE;
@@ -613,7 +627,7 @@ void OGRGeoRSSLayer::endElementCbk(const char *pszName)
 
     if (bInTagWithSubTag && currentDepth == 3)
     {
-        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
+        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszNoNSName));
 
         if (iCurrentField != -1 && pszSubElementName &&
             strcmp(pszFieldName, pszSubElementName) == 0 && poFeature &&
@@ -635,7 +649,7 @@ void OGRGeoRSSLayer::endElementCbk(const char *pszName)
         CPLFree(pszFieldName);
     }
     else if (bInFeature && eFormat == GEORSS_ATOM &&
-             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
+             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszNoNSName))
     {
         bInTagWithSubTag = FALSE;
     }
@@ -783,20 +797,14 @@ void OGRGeoRSSLayer::endElementCbk(const char *pszName)
             pszSubElementValue[nSubElementValueLen] = 0;
             if (poFeatureDefn->GetFieldDefn(iCurrentField)->GetType() == OFTDateTime)
             {
-                int year, month, day, hour, minute, TZ;
-                int nsecond;
-                float fsecond;
-                if (OGRParseRFC822DateTime(pszSubElementValue, &year, &month, &day,
-                                                 &hour, &minute, &nsecond, &TZ))
+                OGRField sField;
+                if (OGRParseRFC822DateTime(pszSubElementValue, &sField))
                 {
-                    poFeature->SetField(iCurrentField, year, month, day,
-                                        hour, minute, nsecond, TZ);
+                    poFeature->SetField(iCurrentField, &sField);
                 }
-                else if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day,
-                                                   &hour, &minute, &fsecond, &TZ))
+                else if (OGRParseXMLDateTime(pszSubElementValue, &sField))
                 {
-                    poFeature->SetField(iCurrentField, year, month, day,
-                                        hour, minute, (int)(fsecond + .5), TZ);
+                    poFeature->SetField(iCurrentField, &sField);
                 }
                 else
                 {
@@ -1076,12 +1084,6 @@ static void OGRGeoRSSLayerWriteSimpleElement(VSILFILE* fp,
             {
                 char* pszValue =
                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
-                if (poFeatureDefn->GetFieldDefn(iIndex)->GetType() == OFTReal)
-                {
-                    char* pszComma = strchr(pszValue, ',');
-                    if (pszComma)
-                        *pszComma = '.';
-                }
                 VSIFPrintfL(fp, " %s=\"%s\"", pszAttributeName, pszValue);
                 CPLFree(pszValue);
             }
@@ -1097,12 +1099,6 @@ static void OGRGeoRSSLayerWriteSimpleElement(VSILFILE* fp,
 
         char* pszValue =
                 OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( iIndex ));
-        if (poFeatureDefn->GetFieldDefn(iIndex)->GetType() == OFTReal)
-        {
-            char* pszComma = strchr(pszValue, ',');
-            if (pszComma)
-                *pszComma = '.';
-        }
         VSIFPrintfL(fp, "%s", pszValue);
         CPLFree(pszValue);
 
@@ -1116,10 +1112,10 @@ static void OGRGeoRSSLayerWriteSimpleElement(VSILFILE* fp,
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGeoRSSLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     VSILFILE* fp = poDS->GetOutputFP();
@@ -1219,12 +1215,6 @@ OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
 
                             char* pszValue =
                                     OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( j ));
-                            if (poFeatureDefn->GetFieldDefn(j)->GetType() == OFTReal)
-                            {
-                                char* pszComma = strchr(pszValue, ',');
-                                if (pszComma)
-                                    *pszComma = '.';
-                            }
                             VSIFPrintfL(fp, "        <%s>%s</%s>\n", pszAttributeName2, pszValue, pszAttributeName2);
                             CPLFree(pszValue);
                         }
@@ -1247,40 +1237,28 @@ OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
         else if (eFormat == GEORSS_RSS &&
             strcmp(pszName, "pubDate") == 0)
         {
-            int year, month, day, hour, minute, second, TZFlag;
-            if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
-                                                    &hour, &minute, &second, &TZFlag))
-            {
-                char* pszDate = OGRGetRFC822DateTime(year, month, day, hour, minute, second, TZFlag);
-                VSIFPrintfL(fp, "      <%s>%s</%s>\n",
-                        pszName, pszDate, pszName);
-                CPLFree(pszDate);
-            }
+            const OGRField* psField = poFeature->GetRawFieldRef(i);
+            char* pszDate = OGRGetRFC822DateTime(psField);
+            VSIFPrintfL(fp, "      <%s>%s</%s>\n",
+                    pszName, pszDate, pszName);
+            CPLFree(pszDate);
         }
         else if (eFormat == GEORSS_ATOM &&
                  (strcmp(pszName, "updated") == 0 || strcmp(pszName, "published") == 0))
         {
-            int year, month, day, hour, minute, second, TZFlag;
-            if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
-                                                    &hour, &minute, &second, &TZFlag))
-            {
-                char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
-                VSIFPrintfL(fp, "      <%s>%s</%s>\n",
-                        pszName, pszDate, pszName);
-                CPLFree(pszDate);
-            }
+            const OGRField* psField = poFeature->GetRawFieldRef(i);
+            char* pszDate = OGRGetXMLDateTime(psField);
+            VSIFPrintfL(fp, "      <%s>%s</%s>\n",
+                    pszName, pszDate, pszName);
+            CPLFree(pszDate);
         }
         else if (strcmp(pszName, "dc_date") == 0)
         {
-            int year, month, day, hour, minute, second, TZFlag;
-            if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
-                                                    &hour, &minute, &second, &TZFlag))
-            {
-                char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
-                VSIFPrintfL(fp, "      <%s>%s</%s>\n",
-                        "dc:date", pszDate, "dc:date");
-                CPLFree(pszDate);
-            }
+            const OGRField* psField = poFeature->GetRawFieldRef(i);
+            char* pszDate = OGRGetXMLDateTime(psField);
+            VSIFPrintfL(fp, "      <%s>%s</%s>\n",
+                    "dc:date", pszDate, "dc:date");
+            CPLFree(pszDate);
         }
         /* RSS fields with content and attributes */
         else if (eFormat == GEORSS_RSS &&
@@ -1426,12 +1404,6 @@ OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
             }
             char* pszValue =
                         OGRGetXML_UTF8_EscapedString(poFeature->GetFieldAsString( i ));
-            if (poFeatureDefn->GetFieldDefn(i)->GetType() == OFTReal)
-            {
-                char* pszComma = strchr(pszValue, ',');
-                if (pszComma)
-                    *pszComma = '.';
-            }
             VSIFPrintfL(fp, "      <%s>%s</%s>\n", pszTagName, pszValue, pszTagName);
             CPLFree(pszValue);
             CPLFree(pszTagName);
@@ -1634,7 +1606,8 @@ OGRErr OGRGeoRSSLayer::CreateFeature( OGRFeature *poFeature )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRGeoRSSLayer::CreateField( OGRFieldDefn *poFieldDefn, CPL_UNUSED int bApproxOK )
+OGRErr OGRGeoRSSLayer::CreateField( OGRFieldDefn *poFieldDefn,
+                                    CPL_UNUSED int bApproxOK )
 {
     const char* pszName = poFieldDefn->GetNameRef();
     if (((eFormat == GEORSS_RSS && strcmp(pszName, "pubDate") == 0) ||
@@ -1828,9 +1801,14 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
     if (bStopParsing) return;
 
     nWithoutEventCounter = 0;
+    const char* pszNoNSName = pszName;
+    const char* pszColon = strchr(pszNoNSName, ':');
+    if( pszColon )
+        pszNoNSName = pszColon + 1;
 
-    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
-        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && !bInFeature && (currentDepth == 1 || currentDepth == 2) && strcmp(pszName, "item") == 0))
+    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszNoNSName, "entry") == 0) ||
+        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && !bInFeature &&
+        (currentDepth == 1 || currentDepth == 2) && strcmp(pszNoNSName, "item") == 0))
     {
         bInFeature = TRUE;
         featureDepth = currentDepth;
@@ -1843,7 +1821,7 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
     }
     else if (bInTagWithSubTag && currentDepth == 3)
     {
-        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszName));
+        char* pszFieldName = CPLStrdup(CPLSPrintf("%s_%s", pszTagWithSubTag, pszNoNSName));
         if (poFeatureDefn->GetFieldIndex(pszFieldName) == -1)
         {
             OGRFieldDefn newFieldDefn(pszFieldName, OFTString);
@@ -1860,17 +1838,17 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
         CPLFree(pszFieldName);
     }
     else if (bInFeature && eFormat == GEORSS_ATOM &&
-             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
+             currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszNoNSName))
     {
         CPLFree(pszTagWithSubTag);
-        pszTagWithSubTag = CPLStrdup(pszName);
+        pszTagWithSubTag = CPLStrdup(pszNoNSName);
 
         int count = 1;
         while(CPLHashSetLookup(setOfFoundFields, pszTagWithSubTag) != NULL)
         {
             count ++;
             CPLFree(pszTagWithSubTag);
-            pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszName, count));
+            pszTagWithSubTag = CPLStrdup(CPLSPrintf("%s%d", pszNoNSName, count));
             if (pszTagWithSubTag[0] == 0)
             {
                 XML_StopParser(oSchemaParser, XML_FALSE);
@@ -1884,6 +1862,9 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
     }
     else if (bInFeature && currentDepth == featureDepth + 1 && !IS_GEO_ELEMENT(pszName))
     {
+        if( pszName != pszNoNSName && strncmp(pszName, "atom:", 5) == 0 )
+            pszName = pszNoNSName;
+
         CPLFree(pszSubElementName);
         pszSubElementName = CPLStrdup(pszName);
 
@@ -1903,14 +1884,14 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
         {
             currentFieldDefn = poFeatureDefn->GetFieldDefn(iField);
         }
-        else if ( ! ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && strcmp(pszName, "enclosure") == 0) &&
-                  ! (eFormat == GEORSS_ATOM && strcmp(pszName, "link") == 0) &&
-                  ! (eFormat == GEORSS_ATOM && strcmp(pszName, "category") == 0))
+        else if ( ! ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && strcmp(pszNoNSName, "enclosure") == 0) &&
+                  ! (eFormat == GEORSS_ATOM && strcmp(pszNoNSName, "link") == 0) &&
+                  ! (eFormat == GEORSS_ATOM && strcmp(pszNoNSName, "category") == 0))
         {
             OGRFieldType eFieldType;
-            if (((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && strcmp(pszName, "pubDate") == 0) ||
-                (eFormat == GEORSS_ATOM && strcmp(pszName, "updated") == 0) ||
-                (eFormat == GEORSS_ATOM && strcmp(pszName, "published") == 0) ||
+            if (((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && strcmp(pszNoNSName, "pubDate") == 0) ||
+                (eFormat == GEORSS_ATOM && strcmp(pszNoNSName, "updated") == 0) ||
+                (eFormat == GEORSS_ATOM && strcmp(pszNoNSName, "published") == 0) ||
                 strcmp(pszName, "dc:date") == 0)
                 eFieldType = OFTDateTime;
             else
@@ -2081,7 +2062,7 @@ void OGRGeoRSSLayer::startElementLoadSchemaCbk(const char *pszName, const char *
                 eGeomType = wkbUnknown;
 
             if (nDimension == 3)
-                eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
+                eGeomType = wkbSetZ(eGeomType);
         }
     }
 
@@ -2103,13 +2084,19 @@ void OGRGeoRSSLayer::endElementLoadSchemaCbk(const char *pszName)
     if (!bInFeature)
         return;
 
-    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszName, "entry") == 0) ||
-        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) && (currentDepth == 1 || currentDepth == 2) && strcmp(pszName, "item") == 0))
+    const char* pszNoNSName = pszName;
+    const char* pszColon = strchr(pszNoNSName, ':');
+    if( pszColon )
+        pszNoNSName = pszColon + 1;
+
+    if ((eFormat == GEORSS_ATOM && currentDepth == 1 && strcmp(pszNoNSName, "entry") == 0) ||
+        ((eFormat == GEORSS_RSS || eFormat == GEORSS_RSS_RDF) &&
+        (currentDepth == 1 || currentDepth == 2) && strcmp(pszNoNSName, "item") == 0))
     {
         bInFeature = FALSE;
     }
     else if (bInFeature && eFormat == GEORSS_ATOM &&
-                currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszName))
+                currentDepth == 2 && OGRGeoRSSLayerATOMTagHasSubElement(pszNoNSName))
     {
         bInTagWithSubTag = FALSE;
     }
@@ -2225,7 +2212,7 @@ int OGRGeoRSSLayer::TestCapability( const char * pszCap )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRGeoRSSLayer::GetFeatureCount( int bForce )
+GIntBig OGRGeoRSSLayer::GetFeatureCount( int bForce )
 
 {
     if (bWriteMode)
diff --git a/ogr/ogrsf_frmts/gft/GNUmakefile b/ogr/ogrsf_frmts/gft/GNUmakefile
index b50b429..5114773 100644
--- a/ogr/ogrsf_frmts/gft/GNUmakefile
+++ b/ogr/ogrsf_frmts/gft/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrgftdriver.o ogrgftdatasource.o ogrgftlayer.o ogrgfttablelayer.o ogrgftresultlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gft/drv_gft.html b/ogr/ogrsf_frmts/gft/drv_gft.html
index 7c78090..b6758f8 100644
--- a/ogr/ogrsf_frmts/gft/drv_gft.html
+++ b/ogr/ogrsf_frmts/gft/drv_gft.html
@@ -115,7 +115,7 @@ The mapping between the operations of the GFT service and the OGR concepts is th
 <li>OGRDataSource::DeleteLayer() <==> DROP TABLE operation</li>
 </ul>
 
-When inserting a new feature with CreateFeature(), and if the command is successfull, OGR will fetch the
+When inserting a new feature with CreateFeature(), and if the command is successful, OGR will fetch the
 returned rowid and use it as the OGR FID. OGR will also automatically reproject its geometry into the
 geodetic WGS84 SRS if needed (provided that the original SRS is attached to the geometry).<p>
 
diff --git a/ogr/ogrsf_frmts/gft/ogr_gft.h b/ogr/ogrsf_frmts/gft/ogr_gft.h
index 0572140..6bb6b21 100644
--- a/ogr/ogrsf_frmts/gft/ogr_gft.h
+++ b/ogr/ogrsf_frmts/gft/ogr_gft.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gft.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gft.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  GFT Translator
  * Purpose:  Definition of classes for OGR Google Fusion Tables driver.
@@ -81,7 +81,7 @@ protected:
 
     virtual int                 TestCapability( const char * );
 
-    virtual OGRErr              SetNextByIndex( long nIndex );
+    virtual OGRErr              SetNextByIndex( GIntBig nIndex );
 
     const char *        GetDefaultGeometryColumnName() { return "geometry"; }
 
@@ -137,18 +137,18 @@ class OGRGFTTableLayer : public OGRGFTLayer
     virtual OGRFeatureDefn *    GetLayerDefn();
 
     virtual const char *        GetName() { return osTableName.c_str(); }
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
 
-    virtual OGRFeature *        GetFeature( long nFID );
+    virtual OGRFeature *        GetFeature( GIntBig nFID );
 
     virtual void        SetSpatialFilter( OGRGeometry * );
     virtual OGRErr      SetAttributeFilter( const char * );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual OGRErr      StartTransaction();
     virtual OGRErr      CommitTransaction();
@@ -223,7 +223,7 @@ class OGRGFTDataSource : public OGRDataSource
 
     virtual int         TestCapability( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName,
+    virtual OGRLayer   *ICreateLayer( const char *pszName,
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
diff --git a/ogr/ogrsf_frmts/gft/ogrgftdatasource.cpp b/ogr/ogrsf_frmts/gft/ogrgftdatasource.cpp
index eaa5bc0..c0ede5f 100644
--- a/ogr/ogrsf_frmts/gft/ogrgftdatasource.cpp
+++ b/ogr/ogrsf_frmts/gft/ogrgftdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgftdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgftdatasource.cpp 28939 2015-04-17 19:01:24Z rouault $
  *
  * Project:  Google Fusion Table Translator
  * Purpose:  Implements OGRGFTDataSource class
@@ -29,7 +29,7 @@
 
 #include "ogr_gft.h"
 
-CPL_CVSID("$Id: ogrgftdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgftdatasource.cpp 28939 2015-04-17 19:01:24Z rouault $");
 
 #define GDAL_API_KEY "AIzaSyA_2h1_wXMOLHNSVeo-jf1ACME-M1XMgP0"
 #define FUSION_TABLE_SCOPE "https://www.googleapis.com/Fauth/fusiontables"
@@ -65,7 +65,8 @@ OGRGFTDataSource::~OGRGFTDataSource()
 
     if (bMustCleanPersistant)
     {
-        char** papszOptions = CSLAddString(NULL, CPLSPrintf("CLOSE_PERSISTENT=GFT:%p", this));
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("GFT:%p", this));
         CPLHTTPFetch( GetAPIURL(), papszOptions);
         CSLDestroy(papszOptions);
     }
@@ -174,9 +175,6 @@ CPLString OGRGFTGetOptionValue(const char* pszFilename,
 int OGRGFTDataSource::Open( const char * pszFilename, int bUpdateIn)
 
 {
-    if (!EQUALN(pszFilename, "GFT:", 4))
-        return FALSE;
-
     bReadWrite = bUpdateIn;
 
     pszName = CPLStrdup( pszFilename );
@@ -301,13 +299,13 @@ const char*  OGRGFTDataSource::GetAPIURL() const
 }
 
 /************************************************************************/
-/*                           CreateLayer()                              */
+/*                          ICreateLayer()                              */
 /************************************************************************/
 
-OGRLayer   *OGRGFTDataSource::CreateLayer( const char *pszName,
-                                           CPL_UNUSED OGRSpatialReference *poSpatialRef,
-                                           OGRwkbGeometryType eGType,
-                                           char ** papszOptions )
+OGRLayer   *OGRGFTDataSource::ICreateLayer( const char *pszName,
+                                            CPL_UNUSED OGRSpatialReference *poSpatialRef,
+                                            OGRwkbGeometryType eGType,
+                                            char ** papszOptions )
 {
     if (!bReadWrite)
     {
diff --git a/ogr/ogrsf_frmts/gft/ogrgftdriver.cpp b/ogr/ogrsf_frmts/gft/ogrgftdriver.cpp
index 9ddebb2..43b7b4a 100644
--- a/ogr/ogrsf_frmts/gft/ogrgftdriver.cpp
+++ b/ogr/ogrsf_frmts/gft/ogrgftdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgftdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgftdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GFT Translator
  * Purpose:  Implements OGRGFTDriver.
@@ -33,7 +33,7 @@
 
 /* http://code.google.com/intl/fr/apis/fusiontables/docs/developers_reference.html */
 
-CPL_CVSID("$Id: ogrgftdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgftdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 extern "C" void RegisterOGRGFT();
 
@@ -63,6 +63,9 @@ const char *OGRGFTDriver::GetName()
 OGRDataSource *OGRGFTDriver::Open( const char * pszFilename, int bUpdate )
 
 {
+    if (!EQUALN(pszFilename, "GFT:", 4))
+        return FALSE;
+
     OGRGFTDataSource   *poDS = new OGRGFTDataSource();
 
     if( !poDS->Open( pszFilename, bUpdate ) )
@@ -113,6 +116,10 @@ int OGRGFTDriver::TestCapability( const char * pszCap )
 void RegisterOGRGFT()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGFTDriver );
+    OGRSFDriver* poDriver = new OGRGFTDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Google Fusion Tables" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_gft.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
-
diff --git a/ogr/ogrsf_frmts/gft/ogrgftlayer.cpp b/ogr/ogrsf_frmts/gft/ogrgftlayer.cpp
index bbfed06..5338c1e 100644
--- a/ogr/ogrsf_frmts/gft/ogrgftlayer.cpp
+++ b/ogr/ogrsf_frmts/gft/ogrgftlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgftlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrgftlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  GFT Translator
  * Purpose:  Implements OGRGFTLayer class.
@@ -30,7 +30,7 @@
 #include "ogr_gft.h"
 #include "cpl_minixml.h"
 
-CPL_CVSID("$Id: ogrgftlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrgftlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRGFTLayer()                             */
@@ -222,10 +222,10 @@ static void ParseLineString(OGRLineString* poLS,
     {
         char** papszTokens = CSLTokenizeString2(papszTuples[iTuple], ",", 0);
         if (CSLCount(papszTokens) == 2)
-            poLS->addPoint(atof(papszTokens[0]), atof(papszTokens[1]));
+            poLS->addPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1]));
         else if (CSLCount(papszTokens) == 3)
-            poLS->addPoint(atof(papszTokens[0]), atof(papszTokens[1]),
-                            atof(papszTokens[2]));
+            poLS->addPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1]),
+                            CPLAtof(papszTokens[2]));
         CSLDestroy(papszTokens);
     }
     CSLDestroy(papszTuples);
@@ -244,10 +244,10 @@ static OGRGeometry* ParseKMLGeometry(/* const */ CPLXMLNode* psXML)
         {
             char** papszTokens = CSLTokenizeString2(pszCoordinates, ",", 0);
             if (CSLCount(papszTokens) == 2)
-                poGeom = new OGRPoint(atof(papszTokens[0]), atof(papszTokens[1]));
+                poGeom = new OGRPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1]));
             else if (CSLCount(papszTokens) == 3)
-                poGeom = new OGRPoint(atof(papszTokens[0]), atof(papszTokens[1]),
-                                      atof(papszTokens[2]));
+                poGeom = new OGRPoint(CPLAtof(papszTokens[0]), CPLAtof(papszTokens[1]),
+                                      CPLAtof(papszTokens[2]));
             CSLDestroy(papszTokens);
         }
     }
@@ -426,8 +426,8 @@ OGRFeature *OGRGFTLayer::BuildFeatureFromSQL(const char* pszLine)
                             CPLGetValueType(papszLatLon[0]) != CPL_VALUE_STRING &&
                             CPLGetValueType(papszLatLon[1]) != CPL_VALUE_STRING)
                         {
-                            OGRPoint* poPoint = new OGRPoint(atof( papszLatLon[1]),
-                                                            atof( papszLatLon[0]));
+                            OGRPoint* poPoint = new OGRPoint(CPLAtof( papszLatLon[1]),
+                                                            CPLAtof( papszLatLon[0]));
                             poPoint->assignSpatialReference(poSRS);
                             poFeature->SetGeometryDirectly(poPoint);
                         }
@@ -460,7 +460,7 @@ OGRFeature *OGRGFTLayer::BuildFeatureFromSQL(const char* pszLine)
                 CPLGetValueType(pszLat) != CPL_VALUE_STRING &&
                 CPLGetValueType(pszLong) != CPL_VALUE_STRING)
             {
-                OGRPoint* poPoint = new OGRPoint(atof(pszLong), atof(pszLat));
+                OGRPoint* poPoint = new OGRPoint(CPLAtof(pszLong), CPLAtof(pszLat));
                 poPoint->assignSpatialReference(poSRS);
                 poFeature->SetGeometryDirectly(poPoint);
             }
@@ -502,12 +502,12 @@ OGRFeature *OGRGFTLayer::GetNextRawFeature()
 /*                          SetNextByIndex()                            */
 /************************************************************************/
 
-OGRErr OGRGFTLayer::SetNextByIndex( long nIndex )
+OGRErr OGRGFTLayer::SetNextByIndex( GIntBig nIndex )
 {
-    if (nIndex < 0)
+    if (nIndex < 0 || nIndex >= INT_MAX )
         return OGRERR_FAILURE;
     bEOF = FALSE;
-    nNextInSeq = nIndex;
+    nNextInSeq = (int)nIndex;
     return OGRERR_NONE;
 }
 
diff --git a/ogr/ogrsf_frmts/gft/ogrgftresultlayer.cpp b/ogr/ogrsf_frmts/gft/ogrgftresultlayer.cpp
index e25fe91..37b2929 100644
--- a/ogr/ogrsf_frmts/gft/ogrgftresultlayer.cpp
+++ b/ogr/ogrsf_frmts/gft/ogrgftresultlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgftresultlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgftresultlayer.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  GFT Translator
  * Purpose:  Implements OGRGFTResultLayer class.
@@ -29,7 +29,7 @@
 
 #include "ogr_gft.h"
 
-CPL_CVSID("$Id: ogrgftresultlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgftresultlayer.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                        OGRGFTResultLayer()                           */
@@ -47,6 +47,8 @@ OGRGFTResultLayer::OGRGFTResultLayer(OGRGFTDataSource* poDS,
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbUnknown );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    
+    SetDescription( poFeatureDefn->GetName() );
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/gft/ogrgfttablelayer.cpp b/ogr/ogrsf_frmts/gft/ogrgfttablelayer.cpp
index 45bc74b..054b8e9 100644
--- a/ogr/ogrsf_frmts/gft/ogrgfttablelayer.cpp
+++ b/ogr/ogrsf_frmts/gft/ogrgfttablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgfttablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgfttablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  GFT Translator
  * Purpose:  Implements OGRGFTTableLayer class.
@@ -29,7 +29,7 @@
 
 #include "ogr_gft.h"
 
-CPL_CVSID("$Id: ogrgfttablelayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgfttablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                         OGRGFTTableLayer()                           */
@@ -51,6 +51,16 @@ OGRGFTTableLayer::OGRGFTTableLayer(OGRGFTDataSource* poDS,
 
     bFirstTokenIsFID = TRUE;
     eGTypeForCreation = wkbUnknown;
+
+    SetDescription( osTableName );
+
+    if (osTableId.size() == 0)
+    {
+        poFeatureDefn = new OGRFeatureDefn( osTableName );
+        poFeatureDefn->Reference();
+        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+        poFeatureDefn->GetGeomFieldDefn(0)->SetName(GetDefaultGeometryColumnName());
+    }
 }
 
 /************************************************************************/
@@ -396,7 +406,7 @@ int OGRGFTTableLayer::FetchNextRows()
 /*                            GetFeature()                              */
 /************************************************************************/
 
-OGRFeature * OGRGFTTableLayer::GetFeature( long nFID )
+OGRFeature * OGRGFTTableLayer::GetFeature( GIntBig nFID )
 {
     GetLayerDefn();
 
@@ -416,7 +426,7 @@ OGRFeature * OGRGFTTableLayer::GetFeature( long nFID )
     }
     osSQL += " FROM ";
     osSQL += osTableId;
-    osSQL += CPLSPrintf(" WHERE ROWID='%ld'", nFID);
+    osSQL += CPLSPrintf(" WHERE ROWID='" CPL_FRMT_GIB "'", nFID);
 
     CPLPushErrorHandler(CPLQuietErrorHandler);
     CPLHTTPResult * psResult = poDS->RunSQL(osSQL);
@@ -471,7 +481,7 @@ OGRFeatureDefn * OGRGFTTableLayer::GetLayerDefn()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRGFTTableLayer::GetFeatureCount(CPL_UNUSED int bForce)
+GIntBig OGRGFTTableLayer::GetFeatureCount(CPL_UNUSED int bForce)
 {
     GetLayerDefn();
 
@@ -524,7 +534,6 @@ int OGRGFTTableLayer::GetFeatureCount(CPL_UNUSED int bForce)
 OGRErr OGRGFTTableLayer::CreateField( OGRFieldDefn *poField,
                                       CPL_UNUSED int bApproxOK )
 {
-
     if (!poDS->IsReadWrite())
     {
         CPLError(CE_Failure, CPLE_AppDefined,
@@ -546,14 +555,6 @@ OGRErr OGRGFTTableLayer::CreateField( OGRFieldDefn *poField,
         return OGRERR_FAILURE;
     }
 
-    if (poFeatureDefn == NULL)
-    {
-        poFeatureDefn = new OGRFeatureDefn( osTableName );
-        poFeatureDefn->Reference();
-        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
-        poFeatureDefn->GetGeomFieldDefn(0)->SetName(GetDefaultGeometryColumnName());
-    }
-
     poFeatureDefn->AddFieldDefn(poField);
 
     return OGRERR_NONE;
@@ -576,15 +577,6 @@ void OGRGFTTableLayer::CreateTableIfNecessary()
 
     int i;
 
-    if (poFeatureDefn == NULL)
-    {
-        /* In case CreateField() hasn't yet been called */
-        poFeatureDefn = new OGRFeatureDefn( osTableName );
-        poFeatureDefn->Reference();
-        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
-        poFeatureDefn->GetGeomFieldDefn(0)->SetName(GetDefaultGeometryColumnName());
-    }
-
     /* If there are longitude and latitude fields, use the latitude */
     /* field as the LOCATION field */
     for(i=0;i<poFeatureDefn->GetFieldCount();i++)
@@ -699,10 +691,10 @@ void OGRGFTTableLayer::CreateTableIfNecessary()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGFTTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGFTTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     if (!poDS->IsReadWrite())
@@ -884,10 +876,10 @@ OGRErr OGRGFTTableLayer::CreateFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
 
-OGRErr      OGRGFTTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr      OGRGFTTableLayer::ISetFeature( OGRFeature *poFeature )
 {
     GetLayerDefn();
 
@@ -1015,7 +1007,7 @@ OGRErr      OGRGFTTableLayer::SetFeature( OGRFeature *poFeature )
     }
 
     osCommand += " WHERE ROWID = '";
-    osCommand += CPLSPrintf("%ld", poFeature->GetFID());
+    osCommand += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID());
     osCommand += "'";
 
     CPLHTTPResult * psResult = poDS->RunSQL(osCommand);
@@ -1050,7 +1042,7 @@ OGRErr      OGRGFTTableLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRGFTTableLayer::DeleteFeature( long nFID )
+OGRErr OGRGFTTableLayer::DeleteFeature( GIntBig nFID )
 {
     GetLayerDefn();
 
@@ -1080,7 +1072,7 @@ OGRErr OGRGFTTableLayer::DeleteFeature( long nFID )
     osCommand += "DELETE FROM ";
     osCommand += osTableId;
     osCommand += " WHERE ROWID = '";
-    osCommand += CPLSPrintf("%ld", nFID);
+    osCommand += CPLSPrintf(CPL_FRMT_GIB, nFID);
     osCommand += "'";
 
     //CPLDebug("GFT", "%s",  osCommand.c_str());
diff --git a/ogr/ogrsf_frmts/gme/GNUmakefile b/ogr/ogrsf_frmts/gme/GNUmakefile
index f3fbf39..e1dada6 100644
--- a/ogr/ogrsf_frmts/gme/GNUmakefile
+++ b/ogr/ogrsf_frmts/gme/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	\
 	ogrgmedriver.o ogrgmedatasource.o ogrgmelayer.o ogrgmejson.o
 
 CPPFLAGS	:=	$(JSON_INCLUDE) -I../geojson -I.. -I../.. \
-	$(GDAL_INCLUDE) $(CPPFLAGS)
+	 $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gme/ogr_gme.h b/ogr/ogrsf_frmts/gme/ogr_gme.h
index 47e08a5..8fbdcc6 100644
--- a/ogr/ogrsf_frmts/gme/ogr_gme.h
+++ b/ogr/ogrsf_frmts/gme/ogr_gme.h
@@ -60,7 +60,7 @@ class OGRGMELayer : public OGRLayer
     std::map<int, CPLString> omnosIdToGMEKey;
     std::map<int, OGRFeature *> omnpoUpdatedFeatures;
     std::map<int, OGRFeature *> omnpoInsertedFeatures;
-    std::vector<long> oListOfDeletedFeatures;
+    std::vector<GIntBig> oListOfDeletedFeatures;
     CPLString          osGeomColumnName;
 
     CPLString          osWhere;
@@ -122,9 +122,9 @@ class OGRGMELayer : public OGRLayer
 
     virtual OGRErr      SyncToDisk();
 
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature(long int);
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature(GIntBig);
     virtual OGRErr      CreateField( OGRFieldDefn *poField, int bApproxOK = TRUE );
 
     virtual OGRErr      StartTransaction();
@@ -175,7 +175,7 @@ class OGRGMEDataSource : public OGRDataSource
     virtual int         GetLayerCount() { return nLayers; }
     virtual OGRLayer*   GetLayer( int );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName,
+    virtual OGRLayer   *ICreateLayer( const char *pszName,
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
diff --git a/ogr/ogrsf_frmts/gme/ogrgmedatasource.cpp b/ogr/ogrsf_frmts/gme/ogrgmedatasource.cpp
index 953a798..cf9b8a4 100644
--- a/ogr/ogrsf_frmts/gme/ogrgmedatasource.cpp
+++ b/ogr/ogrsf_frmts/gme/ogrgmedatasource.cpp
@@ -70,7 +70,8 @@ OGRGMEDataSource::~OGRGMEDataSource()
 
     if (bMustCleanPersistant)
     {
-        char** papszOptions = CSLAddString(NULL, CPLSPrintf("CLOSE_PERSISTENT=GME:%p", this));
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("GME:%p", this));
         CPLHTTPFetch( GetAPIURL(), papszOptions);
         CSLDestroy(papszOptions);
     }
@@ -133,9 +134,6 @@ CPLString OGRGMEGetOptionValue(const char* pszFilename,
 int OGRGMEDataSource::Open( const char * pszFilename, int bUpdateIn)
 
 {
-    if (!EQUALN(pszFilename, "GME:", 4))
-        return FALSE;
-
     bReadWrite = bUpdateIn;
 
     pszName = CPLStrdup( pszFilename );
@@ -228,7 +226,7 @@ int OGRGMEDataSource::Open( const char * pszFilename, int bUpdateIn)
         return TRUE;
     }
     else if (osProjectId.size() != 0) {
-        CPLDebug("GME", "We have a projectId: %s. Use CreateLayer to create tables.",
+        CPLDebug("GME", "We have a projectId: %s. UseICreateLayer to create tables.",
                  osProjectId.c_str());
         return TRUE;
     }
@@ -237,13 +235,13 @@ int OGRGMEDataSource::Open( const char * pszFilename, int bUpdateIn)
 }
 
 /************************************************************************/
-/*                           CreateLayer()                              */
+/*                          ICreateLayer()                              */
 /************************************************************************/
 
-OGRLayer   *OGRGMEDataSource::CreateLayer( const char *pszName,
-                                           CPL_UNUSED OGRSpatialReference *poSpatialRef,
-                                           OGRwkbGeometryType eGType,
-                                           char ** papszOptions )
+OGRLayer   *OGRGMEDataSource::ICreateLayer( const char *pszName,
+                                            CPL_UNUSED OGRSpatialReference *poSpatialRef,
+                                            OGRwkbGeometryType eGType,
+                                            char ** papszOptions )
 {
     if (!bReadWrite)
     {
diff --git a/ogr/ogrsf_frmts/gme/ogrgmedriver.cpp b/ogr/ogrsf_frmts/gme/ogrgmedriver.cpp
index bccdeee..faeb50e 100644
--- a/ogr/ogrsf_frmts/gme/ogrgmedriver.cpp
+++ b/ogr/ogrsf_frmts/gme/ogrgmedriver.cpp
@@ -60,6 +60,9 @@ const char *OGRGMEDriver::GetName()
 OGRDataSource *OGRGMEDriver::Open( const char * pszFilename, int bUpdate )
 
 {
+    if (!EQUALN(pszFilename, "GME:", 4))
+        return NULL;
+
     OGRGMEDataSource   *poDS = new OGRGMEDataSource();
 
     if( !poDS->Open( pszFilename, bUpdate ) )
@@ -110,5 +113,10 @@ int OGRGMEDriver::TestCapability( const char * pszCap )
 void RegisterOGRGME()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGMEDriver );
+    OGRSFDriver* poDriver = new OGRGMEDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Google Maps Engine" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "http://trac.osgeo.org/gdal/wiki/GMEDriver" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
diff --git a/ogr/ogrsf_frmts/gme/ogrgmejson.cpp b/ogr/ogrsf_frmts/gme/ogrgmejson.cpp
index 6a8b0e5..c54ea49 100644
--- a/ogr/ogrsf_frmts/gme/ogrgmejson.cpp
+++ b/ogr/ogrsf_frmts/gme/ogrgmejson.cpp
@@ -60,7 +60,7 @@ json_object* OGRGMEFeatureToGeoJSON(OGRFeature* poFeature)
     pjoGeometry = OGRGMEGeometryToGeoJSON(poGeometry);
     if ( NULL == pjoGeometry ) {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "GME: NULL Geometry detected in feature %ld. Ignoring feature.",
+                  "GME: NULL Geometry detected in feature " CPL_FRMT_GIB ". Ignoring feature.",
                   poFeature->GetFID() );
         json_object_put( pjoFeature );
         return NULL;
@@ -437,10 +437,10 @@ json_object* OGRGMEAttributesToGeoJSON( OGRFeature* poFeature )
     int nGxId = poFeature->GetFieldIndex("gx_id");
     if (nGxId < 0) {
         json_object* pjoProperty = NULL;
-        long nFID = poFeature->GetFID();
+        GIntBig nFID = poFeature->GetFID();
 
         char acGxId[128];
-        snprintf(acGxId, 128, "GDAL-%ld", nFID);
+        snprintf(acGxId, 128, "GDAL-" CPL_FRMT_GIB, nFID);
         CPLDebug("GME", "gx_id is not set, so adding \"gx_id\": \"%s\" field.",
                  acGxId);
 
@@ -476,7 +476,7 @@ static int json_gme_double_to_string(json_object *pjo,
   char buf[128], *p, *q;
   int size;
 
-  size = snprintf(buf, 128, "%.8f", json_object_get_double(pjo));
+  size = CPLsnprintf(buf, 128, "%.8f", json_object_get_double(pjo));
   p = strchr(buf, ',');
   if (p) {
     *p = '.';
diff --git a/ogr/ogrsf_frmts/gme/ogrgmelayer.cpp b/ogr/ogrsf_frmts/gme/ogrgmelayer.cpp
index 19c2374..ecea24f 100644
--- a/ogr/ogrsf_frmts/gme/ogrgmelayer.cpp
+++ b/ogr/ogrsf_frmts/gme/ogrgmelayer.cpp
@@ -55,6 +55,8 @@ OGRGMELayer::OGRGMELayer(OGRGMEDataSource* poDS,
     osTableId = pszTableId;
     bInTransaction = false;
     m_poFilterGeom = NULL;
+    iGxIdField = -1;
+    SetDescription( pszTableId );
 }
 
 
@@ -75,6 +77,8 @@ OGRGMELayer::OGRGMELayer(OGRGMEDataSource* poDS,
     osProjectId = CSLFetchNameValue( papszOptions, "projectId" );
     osDraftACL = CSLFetchNameValueDef( papszOptions, "draftAccessList", "Map Editors" );
     osPublishedACL = CSLFetchNameValueDef( papszOptions, "publishedAccessList", "Map Viewers" );
+    iGxIdField = -1;
+    SetDescription( pszTableName );
     // TODO: support tags and description
 }
 
@@ -369,7 +373,7 @@ OGRFeature *OGRGMELayer::GetNextRawFeature()
     const char *gx_id = OGRGMEGetJSONString(properties_obj, "gx_id");
     if (gx_id) {
         CPLString gmeId(gx_id);
-        omnosIdToGMEKey[++m_nFeaturesRead] = gmeId;
+        omnosIdToGMEKey[(int)(++m_nFeaturesRead)] = gmeId;
         poFeature->SetFID(m_nFeaturesRead);
         CPLDebug("GME", "Mapping ids: \"%s\" to %d", gx_id, (int)m_nFeaturesRead);
     }
@@ -587,7 +591,7 @@ OGRErr OGRGMELayer::BatchDelete()
 {
     json_object *pjoBatchDelete = json_object_new_object();
     json_object *pjoGxIds = json_object_new_array();
-    std::vector<long>::const_iterator fit;
+    std::vector<GIntBig>::const_iterator fit;
     CPLDebug("GME", "BatchDelete() - <%d>", (int)oListOfDeletedFeatures.size() );
     if (oListOfDeletedFeatures.size() == 0) {
         CPLDebug("GME", "Empty list, not doing BatchDelete");
@@ -595,12 +599,12 @@ OGRErr OGRGMELayer::BatchDelete()
     }
     for ( fit = oListOfDeletedFeatures.begin(); fit != oListOfDeletedFeatures.end(); fit++)
     {
-        long nFID = *fit;
+        GIntBig nFID = *fit;
         if (nFID > 0) {
-            CPLString osGxId(omnosIdToGMEKey[nFID]);
-            CPLDebug("GME", "Deleting feature %ld -> '%s'", nFID, osGxId.c_str());
+            CPLString osGxId(omnosIdToGMEKey[(int)nFID]);
+            CPLDebug("GME", "Deleting feature " CPL_FRMT_GIB " -> '%s'", nFID, osGxId.c_str());
             json_object *pjoGxId = json_object_new_string(osGxId.c_str());
-            omnosIdToGMEKey.erase(nFID);
+            omnosIdToGMEKey.erase((int)nFID);
             json_object_array_add( pjoGxIds, pjoGxId );
         }
     }
@@ -644,9 +648,9 @@ OGRErr OGRGMELayer::BatchRequest(const char *pszMethod, std::map<int, OGRFeature
     }
     for ( fit = omnpoFeatures.begin(); fit != omnpoFeatures.end(); fit++)
     {
-        long nFID = fit->first;
+        GIntBig nFID = fit->first;
         OGRFeature *poFeature = fit->second;
-        CPLDebug("GME", "Processing feature: %ld", nFID );
+        CPLDebug("GME", "Processing feature: " CPL_FRMT_GIB, nFID );
         json_object *pjoFeature = OGRGMEFeatureToGeoJSON(poFeature);
 
         if (pjoFeature != NULL)
@@ -706,10 +710,10 @@ unsigned int OGRGMELayer::GetBatchPatchSize()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGMELayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGMELayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     if (!poFeature)
@@ -718,30 +722,38 @@ OGRErr OGRGMELayer::CreateFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
-    long nFID = ++m_nFeaturesRead;
+    GIntBig nFID = ++m_nFeaturesRead;
     poFeature->SetFID(nFID);
 
     int nGxId = poFeature->GetFieldIndex("gx_id");
     CPLDebug("GME", "gx_id is field %d", iGxIdField);
     CPLString osGxId;
-    CPLDebug("GME", "Inserting feature %ld as %s", poFeature->GetFID(), osGxId.c_str());
+    CPLDebug("GME", "Inserting feature " CPL_FRMT_GIB " as %s", poFeature->GetFID(), osGxId.c_str());
     if (nGxId >= 0) {
         iGxIdField = nGxId;
         if(poFeature->IsFieldSet(iGxIdField)) {
           osGxId = poFeature->GetFieldAsString(iGxIdField);
-          CPLDebug("GME", "Feature already has %ld gx_id='%s'", poFeature->GetFID(),
+          CPLDebug("GME", "Feature already has " CPL_FRMT_GIB " gx_id='%s'", poFeature->GetFID(),
                    osGxId.c_str());
         }
         else {
-            osGxId = CPLSPrintf("GDAL-%ld", nFID);
+            osGxId = CPLSPrintf("GDAL-" CPL_FRMT_GIB "", nFID);
             CPLDebug("GME", "Setting field %d as %s", iGxIdField, osGxId.c_str() );
             poFeature->SetField( iGxIdField, osGxId.c_str() );
         }
     }
-    omnosIdToGMEKey[poFeature->GetFID()] = osGxId;
-    omnpoInsertedFeatures[nFID] = poFeature->Clone();
 
     if (bInTransaction) {
+        unsigned int iBatchSize = GetBatchPatchSize();
+        if (omnpoInsertedFeatures.size() >= iBatchSize) {
+            CPLDebug("GME", "BatchInsert, reached BatchSize of %d", iBatchSize);
+            OGRErr iBatchInsertResult = BatchInsert();
+            if (iBatchInsertResult != OGRERR_NONE) {
+                return iBatchInsertResult;
+            }
+        }
+        omnosIdToGMEKey[(int)poFeature->GetFID()] = osGxId;
+        omnpoInsertedFeatures[(int)nFID] = poFeature->Clone();
         CPLDebug("GME", "In Transaction, added feature to memory only");
         bDirty = true;
         return OGRERR_NONE;
@@ -753,31 +765,39 @@ OGRErr OGRGMELayer::CreateFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
 
-OGRErr OGRGMELayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRGMELayer::ISetFeature( OGRFeature *poFeature )
 
 {
     if (!poFeature)
         return OGRERR_FAILURE;
-    long nFID = poFeature->GetFID();
+    GIntBig nFID = poFeature->GetFID();
     if(bInTransaction) {
         std::map<int, OGRFeature *>::const_iterator fit;
-        fit = omnpoInsertedFeatures.find(nFID);
+        fit = omnpoInsertedFeatures.find((int)nFID);
         if (fit != omnpoInsertedFeatures.end()) {
-            omnpoInsertedFeatures[nFID] = poFeature->Clone();
-            CPLDebug("GME", "Updated Feature %ld in Transaction", nFID);
+            omnpoInsertedFeatures[(int)nFID] = poFeature->Clone();
+            CPLDebug("GME", "Updated Feature " CPL_FRMT_GIB " in Transaction", nFID);
         }
         else {
+            unsigned int iBatchSize = GetBatchPatchSize();
+            if (omnpoUpdatedFeatures.size() >= iBatchSize) {
+                CPLDebug("GME", "BatchPatch, reached BatchSize of %d", iBatchSize);
+                OGRErr iBatchInsertResult = BatchPatch();
+                if (iBatchInsertResult != OGRERR_NONE) {
+                    return iBatchInsertResult;
+                }
+            }
             CPLDebug("GME", "In Transaction, add update to Transaction");
             bDirty = true;
-            omnpoUpdatedFeatures[nFID] = poFeature->Clone();
+            omnpoUpdatedFeatures[(int)nFID] = poFeature->Clone();
         }
         return OGRERR_NONE;
     }
     else {
-        omnpoUpdatedFeatures[nFID] = poFeature->Clone();
+        omnpoUpdatedFeatures[(int)nFID] = poFeature->Clone();
         CPLDebug("GME", "Not in Transaction, BatchPatch()");
         return BatchPatch();
     }
@@ -787,16 +807,24 @@ OGRErr OGRGMELayer::SetFeature( OGRFeature *poFeature )
 /*                           DeleteteFeature()                          */
 /************************************************************************/
 
-OGRErr OGRGMELayer::DeleteFeature( long nFID )
+OGRErr OGRGMELayer::DeleteFeature( GIntBig nFID )
 {
     if(bInTransaction) {
         std::map<int, OGRFeature *>::iterator fit;
-        fit = omnpoInsertedFeatures.find(nFID);
+        fit = omnpoInsertedFeatures.find((int)nFID);
         if (fit != omnpoInsertedFeatures.end()) {
             omnpoInsertedFeatures.erase(fit);
-            CPLDebug("GME", "Found %ld in omnpoInsertedFeatures", nFID);
+            CPLDebug("GME", "Found " CPL_FRMT_GIB " in omnpoInsertedFeatures", nFID);
         }
         else {
+            unsigned int iBatchSize = GetBatchPatchSize();
+            if (oListOfDeletedFeatures.size() >= iBatchSize) {
+                CPLDebug("GME", "BatchDelete, reached BatchSize of %d", iBatchSize);
+                OGRErr iBatchResult = BatchDelete();
+                if (iBatchResult != OGRERR_NONE) {
+                    return iBatchResult;
+                }
+            }
             CPLDebug("GME", "In Transaction, adding feature to List");
             bDirty = true;
             oListOfDeletedFeatures.push_back(nFID); 
@@ -813,7 +841,8 @@ OGRErr OGRGMELayer::DeleteFeature( long nFID )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRGMELayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRGMELayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     CPLDebug("GME", "create field %s of type %s, pending = %d",
              poField->GetNameRef(), OGRFieldDefn::GetFieldTypeName(poField->GetType()),
@@ -903,11 +932,16 @@ bool OGRGMELayer::CreateTableIfNotCreated()
 
     for (int iOGRField = 0; iOGRField < poFeatureDefn->GetFieldCount(); iOGRField++ )
     {
-        if (iOGRField == iGxIdField)
+        if ((iOGRField == iGxIdField) && (iGxIdField >= 0))
             continue; // don't create the gx_id field.
+        const char *pszFieldName = poFeatureDefn->GetFieldDefn(iOGRField)->GetNameRef();
+        if (EQUAL(pszFieldName, "gx_id")) {
+            iGxIdField = iOGRField;
+            continue;
+        }
         json_object *pjoColumn = json_object_new_object();
         json_object *pjoFieldName =
-            json_object_new_string( poFeatureDefn->GetFieldDefn(iOGRField)->GetNameRef() );
+            json_object_new_string( pszFieldName );
         json_object *pjoFieldType;
 
         switch(poFeatureDefn->GetFieldDefn(iOGRField)->GetType()) {
@@ -1014,7 +1048,7 @@ OGRErr OGRGMELayer::CommitTransaction()
 {
     if (!bInTransaction)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Should be in transaction");
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot commit, not in transaction");
         return OGRERR_FAILURE;
     }
     bInTransaction = FALSE;
@@ -1029,7 +1063,7 @@ OGRErr OGRGMELayer::RollbackTransaction()
 {
     if (!bInTransaction)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Should be in transaction");
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot rollback, not in transaction.");
         return OGRERR_FAILURE;
     }
     bInTransaction = FALSE;
diff --git a/ogr/ogrsf_frmts/gml/GNUmakefile b/ogr/ogrsf_frmts/gml/GNUmakefile
index 6dfe9f8..33cc883 100644
--- a/ogr/ogrsf_frmts/gml/GNUmakefile
+++ b/ogr/ogrsf_frmts/gml/GNUmakefile
@@ -10,7 +10,7 @@ OGR_OBJ =	ogrgmldriver.o ogrgmldatasource.o ogrgmllayer.o
 
 OBJ =	$(CORE_OBJ) $(OGR_OBJ)
 
-CPPFLAGS :=	-I.. -I../.. $(GDAL_INCLUDE) $(XERCES_INCLUDE) $(EXPAT_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
+CPPFLAGS :=	-I.. -I../..  $(XERCES_INCLUDE) $(EXPAT_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
 #CFLAGS	:=	$(filter-out -Wall,$(CFLAGS))
 
 ifeq ($(HAVE_XERCES),yes)
diff --git a/ogr/ogrsf_frmts/gml/drv_gml.html b/ogr/ogrsf_frmts/gml/drv_gml.html
index 4447a8f..ccfe571 100644
--- a/ogr/ogrsf_frmts/gml/drv_gml.html
+++ b/ogr/ogrsf_frmts/gml/drv_gml.html
@@ -69,7 +69,8 @@ While this approach is error prone, it has the advantage of working for GML file
 even if the associated schema (.xsd) file has been lost.<p>
 
 Starting with OGR 1.10, it is possible to specify an explicit filename for the XSD
-schema to use, by using "a_filename.gml,xsd=another_filename.xsd" as a connection string.<p>
+schema to use, by using "a_filename.gml,xsd=another_filename.xsd" as a connection string.
+Staring with GDAL 2.0, the XSD can also be specified as the value of the XSD open option.<p>
 
 The first time a GML file is opened, if the associated .xsd is absent or could not been
 parsed correctly, it is completely scanned in order to
@@ -115,6 +116,9 @@ Since OGR 1.11, the GML driver supports reading :
  <li><a href="http://www.cuzk.cz/Uvod/Produkty-a-sluzby/RUIAN/2-Poskytovani-udaju-RUIAN-ISUI-VDP/Vymenny-format-RUIAN/Vymenny-format-RUIAN-%28VFR%29.aspx">Czech RUIAN Exchange Format (VFR)</a>.</li>
 </ul>
 
+Since OGR 2.0, the GML driver supports reading responses to CSW GetRecords
+queries.<p>
+
 <h2>Geometry reading</h2>
 
 When reading a feature, the driver will by default only take into account the
@@ -126,7 +130,7 @@ fields will be reported by the GML driver according to
 <a href="http://trac.osgeo.org/gdal/wiki/rfc41_multiple_geometry_fields">RFC 41</a>.<p>
 
 Starting with OGR 1.10, in case of multiple geometry occurences, if a geometry is in a <geometry> element,
-this will be the one selected. This will make default behaviour consistant with Inspire objects.<p>
+this will be the one selected. This will make default behaviour consistent with Inspire objects.<p>
 
 
 Starting with OGR 1.8.0, the user can change the .gfs file to select the appropriate
@@ -140,7 +144,7 @@ description of the .gfs syntax below.<p>
 OGR 1.8.0 adds support to "merge" the multiple geometries found in a feature by
 setting the configuration option <b>GML_FETCH_ALL_GEOMETRIES</b> to <b>YES</b>. The geometries
 will be collected into a GeometryCollection (or Multipolygon if individual geometries
-are polygons or multipolygons). This can be usefull when reading some GML application profiles.
+are polygons or multipolygons). This can be useful when reading some GML application profiles.
 If a <GeometryElementPath> element is specified in the .gfs, the fetching will be limited
 to paths that match the value of <GeometryElementPath>.<p>
 -->
@@ -154,6 +158,15 @@ the configuration option <b>GML_GET_SECONDARY_GEOM</b> should be set to the
 value <b>YES</b>.  When this is set only the secondary geometries are
 reported.<p>
 
+Starting with GDAL 2.0, Arc, ArcString, ArcByBulge, ArcByCenterPoint, Circle
+and CircleByCenterPoints will be returned as circular string OGR geometries.
+If they are included in other GML elements such as CurveComposite, MultiCurve, Surface,
+corresponding non-linear OGR geometries will be returned as well. When
+reading GML3 application schemas, declarations of geometry fields such as
+CurvePropertyType, SurfacePropertyType, MultiCurvePropertyType or MultiSurfacePropertyType
+will be also interpreted as being potential non-linear geometries, and corresponding
+OGR geometry type will be used for the layer geometry type.<p>
+
 <h2>gml:xlink resolving</h2>
 
 OGR 1.8.0 adds support for gml:xlink resolving.  When the resolver finds an
@@ -312,7 +325,7 @@ the layers must be read in the order they appear in the file.<p>
 If no .xsd and .gfs files are found, the parser will detect the layout of layers when
 building the .gfs file. If the layers are found to be sequential, a <i><SequentialLayers>true</SequentialLayers></i>
 element will be written in the .gfs file, so that the GML_READ_MODE will be automatically
-initialized to MONOBLOCK_LAYERS if not explicitely set by the user.<p>
+initialized to MONOBLOCK_LAYERS if not explicitly set by the user.<p>
 
 Starting with OGR 1.9.0, the GML_READ_MODE configuration option can be set to INTERLEAVED_LAYERS to be able
 to read a GML file whose features from different layers are interleaved. In the case, the semantics of the
@@ -340,6 +353,17 @@ belongs to another layer. In that case, the file should be read with code simila
     } while (bInterleaved && bFoundFeature);
 </pre>
 
+<h2>Open options</h2>
+
+<ul>
+<li> <b>XSD=filename</b>: (GDAL >=2.0) to specify an explicit filename for the XSD
+application schema to use</li>.
+<li> <b>FORCE_SRS_DETECTION=YES/NO</b>: (GDAL >=2.0) Force a full scan to detect the SRS of layers.
+This option may be needed in the case where the .gml file is accompanied with
+a .xsd. Normally in that situation, OGR would not detect the SRS, because this
+requires to do a full scan of the file. Defaults to NO</li>
+</ul>
+
 <h2>Creation Issues</h2>
 
 On export all layers are written to a single GML file all in a single
@@ -372,11 +396,15 @@ the prefix of the application target namespace in the GML file.</p>
 <ul>
 <li><i>GML3</i> in order to write GML files that follow GML 3.1.1 SF-0 profile.</li>
 <li><i>GML3Deegree</i> (OGR >= 1.9.0) in order to produce a GML 3.1.1 .XSD schema,
-with a few variations with respect to what is recommanded by GML3 SF-0 profile,
+with a few variations with respect to what is recommended by GML3 SF-0 profile,
 but that will be better accepted by some software (such as Deegree 3).</li>
 <li><i>GML3.2</i>(OGR >= 1.9.0) in order to write GML files that follow GML 3.2.1 SF-0 profile.</li>
 </ul><br>
-If not specified, GML2 will be used.<br><br>
+If not specified, GML2 will be used.<br>
+Starting with GDAL 2.0, non-linear geometries can be written. This is only compatible
+with selecting on of that above GML3 format variant. Otherwise, such geometries will be
+approximating into their closest matching linear geometry.
+<br>
 Note: starting with OGR 1.11, fields of type StringList, RealList or IntegerList can be written. This
 will cause to advertize the SF-1 profile in the .XSD schema (such types are not supported by SF-0).<br>
 
@@ -388,12 +416,30 @@ In the case, if the SRS is a geographic SRS without explicit AXIS order, but tha
 imported with ImportFromEPSGA() should be treated as lat/long, then the function will take care of coordinate order swapping.
 If set to NO, SRS with EPSG authority will be written with the "EPSG:" prefix, even if they are in lat/long order.<p>
 
+<li> <b>SRSDIMENSION_LOC</b>=POSLIST/GEOMETRY/GEOMETRY,POSLIST. (Only valid for FORMAT=GML3, GDAL >= 2.0) Default to POSLIST.
+For 2.5D geometries, define the location where to attach the srsDimension attribute.
+There are diverging implementations. Some put in on the <gml:posList> element, other
+on the top geometry element.<p>
+
 <li> <b>WRITE_FEATURE_BOUNDED_BY</b>=YES/NO. (OGR >= 1.11, only valid when FORMAT=GML3/GML3Degree/GML3.2) Default to YES.
 If set to NO, the <gml:boundedBy> element will not be written for each feature.<p>
 
 <li> <b>SPACE_INDENTATION</b>=YES/NO. (OGR >= 1.8.0) Default to YES. If YES, the output will be indented with spaces
 for more readability, but at the expense of file size.<p>
 
+<li> <b>SPACE_INDENTATION</b>=YES/NO. (OGR >= 1.8.0) Default to YES. If YES, the output will be indented with spaces
+for more readability, but at the expense of file size.<p>
+on the top geometry element.<p>
+
+<li> <b>GML_ID</b>=string. (Only valid for GML 3.2, GDAL >= 2.0)
+Value of feature collection gml:id. Default value is "aFeatureCollection".<p>
+
+<li> <b>NAME</b>=string. Content of GML name element. Can also be set as the
+NAME metadata item on the dataset.<p>
+
+<li> <b>DESCRIPTION</b>=string. Content of GML description element. Can also be set as the
+DESCRIPTION metadata item on the dataset.<p>
+
 </ul>
 
 <h2>VSI Virtual File System API support</h2>
@@ -812,6 +858,79 @@ contain the following content :<p>
 <tr><td>myFeature.2</td><td>otherFeature.10</td></tr>
 </table>
 
+<h2>Reading datasets resulting from a WFS 2.0 join queries</h2>
+
+Starting with GDAL 2.0, the GML driver can read datasets resulting from a WFS 2.0 join queries.<p>
+
+Such datasets typically look like:
+<pre>
+<wfs:FeatureCollection xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    xmlns:app="http://app.com"
+    xmlns:wfs="http://www.opengis.net/wfs/2.0"
+    xmlns:gml="http://www.opengis.net/gml/3.2"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    numberMatched="unknown" numberReturned="2" timeStamp="2015-01-01T00:00:00.000Z"
+    xsi:schemaLocation="http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd 
+                        http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd">
+  <wfs:member>
+    <wfs:Tuple>
+      <wfs:member>
+        <app:table1 gml:id="table1-1">
+          <app:foo>1</app:foo>
+        </app:table1>
+      </wfs:member>
+      <wfs:member>
+        <app:table2 gml:id="table2-1">
+          <app:bar>2</app:bar>
+          <app:baz>foo</app:baz>
+          <app:geometry><gml:Point gml:id="table2-2.geom.0"><gml:pos>2 49</gml:pos></gml:Point></app:geometry>
+        </app:table2>
+      </wfs:member>
+    </wfs:Tuple>
+  </wfs:member>
+  <wfs:member>
+    <wfs:Tuple>
+      <wfs:member>
+        <app:table1 gml:id="table1-2">
+          <app:bar>2</app:bar>
+          <app:geometry><gml:Point gml:id="table1-1.geom.0"><gml:pos>3 50</gml:pos></gml:Point></app:geometry>
+        </app:table1>
+      </wfs:member>
+      <wfs:member>
+        <app:table2 gml:id="table2-2">
+          <app:bar>2</app:bar>
+          <app:baz>bar</app:baz>
+          <app:geometry><gml:Point gml:id="table2-2.geom.0"><gml:pos>2 50</gml:pos></gml:Point></app:geometry>
+        </app:table2>
+      </wfs:member>
+    </wfs:Tuple>
+  </wfs:member>
+</wfs:FeatureCollection>
+</pre>
+
+<p>OGR will group together the attributes from the layers participating to the
+join and will prefix them with the layer name. So the above example will be
+read as the following:</p>
+<pre>
+OGRFeature(join_table1_table2):0
+  table1.gml_id (String) = table1-1
+  table1.foo (Integer) = 1
+  table1.bar (Integer) = (null)
+  table2.gml_id (String) = table2-1
+  table2.bar (Integer) = 2
+  table2.baz (String) = foo
+  table2.geometry = POINT (2 49)
+
+OGRFeature(join_table1_table2):1
+  table1.gml_id (String) = table1-2
+  table1.foo (Integer) = (null)
+  table1.bar (Integer) = 2
+  table2.gml_id (String) = table2-2
+  table2.bar (Integer) = 2
+  table2.baz (String) = bar
+  table1.geometry = POINT (3 50)
+  table2.geometry = POINT (2 50)
+</pre>
 
 <h2>Examples</h2>
 
diff --git a/ogr/ogrsf_frmts/gml/gfstemplate.cpp b/ogr/ogrsf_frmts/gml/gfstemplate.cpp
index ce46c5f..3a12ee4 100644
--- a/ogr/ogrsf_frmts/gml/gfstemplate.cpp
+++ b/ogr/ogrsf_frmts/gml/gfstemplate.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gfstemplate.cpp 27132 2014-04-05 21:48:58Z rouault $
+ * $Id: gfstemplate.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GML GFS template management
@@ -36,7 +36,7 @@
 #include "gmlreaderp.h"
 #include "ogr_gml.h"
 
-CPL_CVSID("$Id: gfstemplate.cpp 27132 2014-04-05 21:48:58Z rouault $");
+CPL_CVSID("$Id: gfstemplate.cpp 28481 2015-02-13 17:11:15Z rouault $");
 
 /************************************************************************/
 /*                        GFSTemplateItem                               */
@@ -86,7 +86,7 @@ public:
         {
             poClass->SetFeatureCount( pItem->GetCount() );
             if ( pItem->GetGeomCount() != 0 && poClass->GetGeometryPropertyCount() == 0 )
-                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown ) );
+                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, TRUE ) );
             m_bValid = TRUE;
         }
         pItem = pItem->GetNext();
diff --git a/ogr/ogrsf_frmts/gml/gmlfeature.cpp b/ogr/ogrsf_frmts/gml/gmlfeature.cpp
index 544f2a9..e6356db 100644
--- a/ogr/ogrsf_frmts/gml/gmlfeature.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlfeature.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: gmlfeature.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gmlfeature.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLFeature.
@@ -168,7 +168,7 @@ void GMLFeature::SetPropertyDirectly( int iIndex, char *pszValue )
 void GMLFeature::Dump( CPL_UNUSED FILE * fp )
 {
     printf( "GMLFeature(%s):\n", m_poClass->GetName() );
-    
+
     if( m_pszFID != NULL )
         printf( "  FID = %s\n", m_pszFID );
 
diff --git a/ogr/ogrsf_frmts/gml/gmlfeatureclass.cpp b/ogr/ogrsf_frmts/gml/gmlfeatureclass.cpp
index d0427d5..9101792 100644
--- a/ogr/ogrsf_frmts/gml/gmlfeatureclass.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlfeatureclass.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: gmlfeatureclass.cpp 27132 2014-04-05 21:48:58Z rouault $
+ * $Id: gmlfeatureclass.cpp 28909 2015-04-15 12:52:53Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLFeatureClass.
@@ -30,8 +30,10 @@
 
 #include "gmlreader.h"
 #include "cpl_conv.h"
+#include "cpl_string.h"
 #include "ogr_core.h"
 #include "ogr_geometry.h"
+#include "cpl_string.h"
 
 /************************************************************************/
 /*                          GMLFeatureClass()                           */
@@ -55,7 +57,7 @@ GMLFeatureClass::GMLFeatureClass( const char *pszName )
     m_nFeatureCount = -1; // unknown
 
     m_pszSRSName = NULL;
-    m_bSRSNameConsistant = TRUE;
+    m_bSRSNameConsistent = TRUE;
 }
 
 /************************************************************************/
@@ -78,6 +80,28 @@ GMLFeatureClass::~GMLFeatureClass()
 }
 
 /************************************************************************/
+/*                         StealProperties()                            */
+/************************************************************************/
+
+void GMLFeatureClass::StealProperties()
+{
+    m_nPropertyCount = 0;
+    CPLFree( m_papoProperty );
+    m_papoProperty = NULL;
+}
+
+/************************************************************************/
+/*                       StealGeometryProperties()                      */
+/************************************************************************/
+
+void GMLFeatureClass::StealGeometryProperties()
+{
+    m_nGeometryPropertyCount = 0;
+    CPLFree( m_papoGeometryProperty );
+    m_papoGeometryProperty = NULL;
+}
+
+/************************************************************************/
 /*                            SetName()                                 */
 /************************************************************************/
 
@@ -270,10 +294,10 @@ size_t GMLFeatureClass::GetElementNameLen() const
 }
 
 /************************************************************************/
-/*                          GetFeatureCount()                           */
+/*                         GetFeatureCount()                          */
 /************************************************************************/
 
-int GMLFeatureClass::GetFeatureCount()
+GIntBig GMLFeatureClass::GetFeatureCount()
 
 {
     return m_nFeatureCount;
@@ -283,7 +307,7 @@ int GMLFeatureClass::GetFeatureCount()
 /*                          SetFeatureCount()                           */
 /************************************************************************/
 
-void GMLFeatureClass::SetFeatureCount( int nNewCount )
+void GMLFeatureClass::SetFeatureCount( GIntBig nNewCount )
 
 {
     m_nFeatureCount = nNewCount;
@@ -355,7 +379,7 @@ int GMLFeatureClass::GetExtents( double *pdfXMin, double *pdfXMax,
 void GMLFeatureClass::SetSRSName( const char* pszSRSName )
 
 {
-    m_bSRSNameConsistant = TRUE;
+    m_bSRSNameConsistent = TRUE;
     CPLFree(m_pszSRSName);
     m_pszSRSName = (pszSRSName) ? CPLStrdup(pszSRSName) : NULL;
 }
@@ -367,7 +391,7 @@ void GMLFeatureClass::SetSRSName( const char* pszSRSName )
 void GMLFeatureClass::MergeSRSName( const char* pszSRSName )
 
 {
-    if(!m_bSRSNameConsistant)
+    if(!m_bSRSNameConsistent)
         return;
 
     if( m_pszSRSName == NULL )
@@ -377,9 +401,9 @@ void GMLFeatureClass::MergeSRSName( const char* pszSRSName )
     }
     else
     {
-        m_bSRSNameConsistant = pszSRSName != NULL &&
+        m_bSRSNameConsistent = pszSRSName != NULL &&
                                   strcmp(m_pszSRSName, pszSRSName) == 0;
-        if (!m_bSRSNameConsistant)
+        if (!m_bSRSNameConsistent)
         {
             CPLFree(m_pszSRSName);
             m_pszSRSName = NULL;
@@ -445,12 +469,13 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
             const char *pszName = CPLGetXMLValue( psThis, "Name", "" );
             const char *pszElementPath = CPLGetXMLValue( psThis, "ElementPath", "" );
             const char *pszType = CPLGetXMLValue( psThis, "Type", NULL );
+            int bNullable = CSLTestBoolean(CPLGetXMLValue( psThis, "Nullable", "true") );
             nGeomType = wkbUnknown;
             if( pszType != NULL && !EQUAL(pszType, "0") )
             {
                 nGeomType = atoi(pszType);
-                int nFlattenGeomType = nGeomType & (~wkb25DBit);
-                if( nGeomType != 0 && !(nFlattenGeomType >= 0 && nFlattenGeomType <= 7) )
+                OGRwkbGeometryType nFlattenGeomType = wkbFlatten(nGeomType);
+                if( nGeomType != 0 && !(nFlattenGeomType >= wkbPoint && nFlattenGeomType <= wkbMultiSurface) )
                 {
                     nGeomType = wkbUnknown;
                     CPLError(CE_Warning, CPLE_AppDefined, "Unrecognised geometry type : %s",
@@ -460,7 +485,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
                     nGeomType = OGRFromOGCGeomType(pszType);
             }
             bHasFoundGeomElements = TRUE;
-            AddGeometryProperty( new GMLGeometryPropertyDefn( pszName, pszElementPath, nGeomType ) );
+            AddGeometryProperty( new GMLGeometryPropertyDefn( pszName, pszElementPath, nGeomType, -1, bNullable ) );
             bHasValidGeometryName = FALSE;
             bHasValidGeometryElementPath = FALSE;
             bHasFoundGeomType = FALSE;
@@ -472,7 +497,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
 
             if( bHasValidGeometryName )
             {
-                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType ) );
+                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType, -1, TRUE ) );
                 bHasValidGeometryName = FALSE;
                 bHasValidGeometryElementPath = FALSE;
                 bHasFoundGeomType = FALSE;
@@ -490,7 +515,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
 
             if( bHasValidGeometryElementPath )
             {
-                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType ) );
+                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType, -1, TRUE ) );
                 bHasValidGeometryName = FALSE;
                 bHasValidGeometryElementPath = FALSE;
                 bHasFoundGeomType = FALSE;
@@ -508,7 +533,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
 
             if( bHasFoundGeomType )
             {
-                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType ) );
+                AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType, -1, TRUE ) );
                 bHasValidGeometryName = FALSE;
                 bHasValidGeometryElementPath = FALSE;
                 bHasFoundGeomType = FALSE;
@@ -521,14 +546,14 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
             if( pszGeometryType != NULL && !EQUAL(pszGeometryType, "0") )
             {
                 nGeomType = atoi(pszGeometryType);
-                int nFlattenGeomType = nGeomType & (~wkb25DBit);
+                OGRwkbGeometryType nFlattenGeomType = wkbFlatten(nGeomType);
                 if( nGeomType == 100 || EQUAL(pszGeometryType, "NONE") )
                 {
                     bHasValidGeometryElementPath = FALSE;
                     bHasFoundGeomType = FALSE;
                     break;
                 }
-                else if( nGeomType != 0 && !(nFlattenGeomType >= 0 && nFlattenGeomType <= 7) )
+                else if( nGeomType != 0 && !(nFlattenGeomType >= wkbPoint && nFlattenGeomType <= wkbMultiSurface) )
                 {
                     nGeomType = wkbUnknown;
                     CPLError(CE_Warning, CPLE_AppDefined, "Unrecognised geometry type : %s",
@@ -546,7 +571,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
     /* a geometry field */
     if( bHasValidGeometryElementPath || bHasFoundGeomType || !bHasFoundGeomElements )
     {
-        AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType ) );
+        AddGeometryProperty( new GMLGeometryPropertyDefn( pszGName, pszGPath, nGeomType, -1, TRUE ) );
     }
 
     SetSRSName( CPLGetXMLValue( psRoot, "SRSName", NULL ) );
@@ -561,7 +586,7 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
 
         pszValue = CPLGetXMLValue( psDSI, "FeatureCount", NULL );
         if( pszValue != NULL )
-            SetFeatureCount( atoi(pszValue) );
+            SetFeatureCount( CPLAtoGIntBig(pszValue) );
 
         // Eventually we should support XML subtrees.
         pszValue = CPLGetXMLValue( psDSI, "ExtraInfo", NULL );
@@ -590,7 +615,9 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
         {
             const char *pszName = CPLGetXMLValue( psThis, "Name", NULL );
             const char *pszType = CPLGetXMLValue( psThis, "Type", "Untyped" );
+            const char *pszSubType = CPLGetXMLValue( psThis, "Subtype", "" );
             const char *pszCondition = CPLGetXMLValue( psThis, "Condition", NULL );
+            int bNullable = CSLTestBoolean(CPLGetXMLValue( psThis, "Nullable", "true") );
             GMLPropertyDefn *poPDefn;
 
             if( pszName == NULL )
@@ -604,28 +631,65 @@ int GMLFeatureClass::InitializeFromXML( CPLXMLNode *psRoot )
             poPDefn = new GMLPropertyDefn( 
                 pszName, CPLGetXMLValue( psThis, "ElementPath", NULL ) );
             
+            poPDefn->SetNullable(bNullable);
             if( EQUAL(pszType,"Untyped") )
                 poPDefn->SetType( GMLPT_Untyped );
             else if( EQUAL(pszType,"String") ) 
             {
-                poPDefn->SetType( GMLPT_String );
-                poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
+                if( EQUAL(pszSubType, "Boolean") )
+                {
+                    poPDefn->SetType( GMLPT_Boolean );
+                    poPDefn->SetWidth( 1 );
+                }
+                else
+                {
+                    poPDefn->SetType( GMLPT_String );
+                    poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
+                }
             }
             else if( EQUAL(pszType,"Integer") )
             {
-                poPDefn->SetType( GMLPT_Integer );
+                if( EQUAL(pszSubType, "Short") )
+                {
+                    poPDefn->SetType( GMLPT_Short );
+                }
+                else if( EQUAL(pszSubType, "Integer64") )
+                {
+                    poPDefn->SetType( GMLPT_Integer64 );
+                }
+                else
+                {
+                    poPDefn->SetType( GMLPT_Integer );
+                }
                 poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
             }
             else if( EQUAL(pszType,"Real") )
             {
-                poPDefn->SetType( GMLPT_Real );
+                if( EQUAL(pszSubType, "Float") )
+                {
+                    poPDefn->SetType( GMLPT_Float );
+                }
+                else
+                {
+                    poPDefn->SetType( GMLPT_Real );
+                }
                 poPDefn->SetWidth( atoi( CPLGetXMLValue( psThis, "Width", "0" ) ) );
                 poPDefn->SetPrecision( atoi( CPLGetXMLValue( psThis, "Precision", "0" ) ) );
             }
             else if( EQUAL(pszType,"StringList") ) 
-                poPDefn->SetType( GMLPT_StringList );
+            {
+                if( EQUAL(pszSubType, "Boolean") )
+                    poPDefn->SetType( GMLPT_BooleanList );
+                else
+                    poPDefn->SetType( GMLPT_StringList );
+            }
             else if( EQUAL(pszType,"IntegerList") )
-                poPDefn->SetType( GMLPT_IntegerList );
+            {
+                if( EQUAL(pszSubType, "Integer64") )
+                    poPDefn->SetType( GMLPT_Integer64List );
+                else
+                    poPDefn->SetType( GMLPT_IntegerList );
+            }
             else if( EQUAL(pszType,"RealList") )
                 poPDefn->SetType( GMLPT_RealList );
             else if( EQUAL(pszType,"Complex") )
@@ -670,7 +734,37 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
     CPLCreateXMLElementAndValue( psRoot, "Name", GetName() );
     CPLCreateXMLElementAndValue( psRoot, "ElementPath", GetElementName() );
     
-    if( m_nGeometryPropertyCount > 0 )
+    if( m_nGeometryPropertyCount > 1 )
+    {
+        for(int i=0; i < m_nGeometryPropertyCount; i++)
+        {
+            GMLGeometryPropertyDefn* poGeomFDefn = m_papoGeometryProperty[i];
+
+            CPLXMLNode *psPDefnNode;
+            psPDefnNode = CPLCreateXMLNode( psRoot, CXT_Element, "GeomPropertyDefn" );
+            if( strlen(poGeomFDefn->GetName()) > 0 )
+                CPLCreateXMLElementAndValue( psPDefnNode, "Name", 
+                                             poGeomFDefn->GetName() );
+            if( poGeomFDefn->GetSrcElement() != NULL && strlen(poGeomFDefn->GetSrcElement()) > 0 )
+                CPLCreateXMLElementAndValue( psPDefnNode, "ElementPath", 
+                                             poGeomFDefn->GetSrcElement() );
+            
+            if( poGeomFDefn->GetType() != 0 /* wkbUnknown */ )
+            {
+                char szValue[128];
+
+                OGRwkbGeometryType eType = (OGRwkbGeometryType)poGeomFDefn->GetType();
+
+                CPLString osStr(OGRToOGCGeomType(eType));
+                if( wkbHasZ(eType) ) osStr += "Z";
+                CPLCreateXMLNode( psPDefnNode, CXT_Comment, osStr.c_str() );
+
+                sprintf( szValue, "%d", eType );
+                CPLCreateXMLElementAndValue( psPDefnNode, "Type", szValue );
+            }
+        }
+    }
+    else if( m_nGeometryPropertyCount == 1 )
     {
         GMLGeometryPropertyDefn* poGeomFDefn = m_papoGeometryProperty[0];
         
@@ -686,7 +780,13 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
         {
             char szValue[128];
 
-            sprintf( szValue, "%d", poGeomFDefn->GetType() );
+            OGRwkbGeometryType eType = (OGRwkbGeometryType)poGeomFDefn->GetType();
+
+            CPLString osStr(OGRToOGCGeomType(eType));
+            if( wkbHasZ(eType) ) osStr += "Z";
+            CPLCreateXMLNode( psRoot, CXT_Comment, osStr.c_str() );
+
+            sprintf( szValue, "%d", eType );
             CPLCreateXMLElementAndValue( psRoot, "GeometryType", szValue );
         }
     }
@@ -714,7 +814,7 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
         {
             char szValue[128];
 
-            sprintf( szValue, "%d", m_nFeatureCount );
+            sprintf( szValue, CPL_FRMT_GIB, m_nFeatureCount );
             CPLCreateXMLElementAndValue( psDSI, "FeatureCount", szValue );
         }
 
@@ -726,16 +826,16 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
         {
             char szValue[128];
 
-            snprintf( szValue, sizeof(szValue), "%.5f", m_dfXMin );
+            CPLsnprintf( szValue, sizeof(szValue), "%.5f", m_dfXMin );
             CPLCreateXMLElementAndValue( psDSI, "ExtentXMin", szValue );
 
-            snprintf( szValue, sizeof(szValue), "%.5f", m_dfXMax );
+            CPLsnprintf( szValue, sizeof(szValue), "%.5f", m_dfXMax );
             CPLCreateXMLElementAndValue( psDSI, "ExtentXMax", szValue );
 
-            snprintf( szValue, sizeof(szValue), "%.5f", m_dfYMin );
+            CPLsnprintf( szValue, sizeof(szValue), "%.5f", m_dfYMin );
             CPLCreateXMLElementAndValue( psDSI, "ExtentYMin", szValue );
 
-            snprintf( szValue, sizeof(szValue), "%.5f", m_dfYMax );
+            CPLsnprintf( szValue, sizeof(szValue), "%.5f", m_dfYMax );
             CPLCreateXMLElementAndValue( psDSI, "ExtentYMax", szValue );
         }
 
@@ -764,14 +864,18 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
             break;
             
           case GMLPT_String:
+          case GMLPT_Boolean:
             pszTypeName = "String";
             break;
             
           case GMLPT_Integer:
+          case GMLPT_Short:
+          case GMLPT_Integer64:
             pszTypeName = "Integer";
             break;
             
           case GMLPT_Real:
+          case GMLPT_Float:
             pszTypeName = "Real";
             break;
             
@@ -780,6 +884,7 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
             break;
 
           case GMLPT_IntegerList:
+          case GMLPT_Integer64List:
             pszTypeName = "IntegerList";
             break;
 
@@ -788,6 +893,7 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
             break;
 
           case GMLPT_StringList:
+          case GMLPT_BooleanList:
             pszTypeName = "StringList";
             break;
 
@@ -804,6 +910,15 @@ CPLXMLNode *GMLFeatureClass::SerializeToXML()
             break;
         }
         CPLCreateXMLElementAndValue( psPDefnNode, "Type", pszTypeName );
+        if( poPDefn->GetType() == GMLPT_Boolean || poPDefn->GetType() == GMLPT_BooleanList )
+            CPLCreateXMLElementAndValue( psPDefnNode, "Subtype", "Boolean" );
+        else if( poPDefn->GetType() == GMLPT_Short )
+            CPLCreateXMLElementAndValue( psPDefnNode, "Subtype", "Short" );
+        else if( poPDefn->GetType() == GMLPT_Float )
+            CPLCreateXMLElementAndValue( psPDefnNode, "Subtype", "Float" );
+        else if( poPDefn->GetType() == GMLPT_Integer64 ||
+                 poPDefn->GetType() == GMLPT_Integer64List )
+            CPLCreateXMLElementAndValue( psPDefnNode, "Subtype", "Integer64" );
 
         if( EQUAL(pszTypeName,"String") )
         {
diff --git a/ogr/ogrsf_frmts/gml/gmlhandler.cpp b/ogr/ogrsf_frmts/gml/gmlhandler.cpp
index bbbc117..b2fc102 100644
--- a/ogr/ogrsf_frmts/gml/gmlhandler.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlhandler.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: gmlhandler.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: gmlhandler.cpp 29026 2015-04-26 14:45:00Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLHandler class.
@@ -306,8 +306,8 @@ void XMLCALL GMLExpatHandler::startElementCbk(void *pUserData, const char *pszNa
 /************************************************************************/
 /*                            endElementCbk()                           */
 /************************************************************************/
-void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData, CPL_UNUSED const char* pszName )
-
+void XMLCALL GMLExpatHandler::endElementCbk(void *pUserData,
+                                            CPL_UNUSED const char* pszName )
 {
     GMLExpatHandler* pThis = ((GMLExpatHandler*)pUserData);
     if (pThis->m_bStopParsing)
@@ -444,6 +444,7 @@ char* GMLExpatHandler::GetAttributeByIdx(void* attr, unsigned int idx, char** pp
 
 static const char* const apszGMLGeometryElements[] =
 {
+    "BoundingBox", /* ows:BoundingBox */
     "CompositeCurve",
     "CompositeSurface",
     "Curve",
@@ -638,7 +639,9 @@ OGRErr GMLHandler::dataHandler(const char *data, int nLen)
 /*                       startElementBoundedBy()                        */
 /************************************************************************/
 
-OGRErr GMLHandler::startElementBoundedBy(const char *pszName, CPL_UNUSED int nLenName, void* attr )
+OGRErr GMLHandler::startElementBoundedBy(const char *pszName,
+                                         CPL_UNUSED int nLenName,
+                                         void* attr )
 {
     if ( m_nDepth == 2 && strcmp(pszName, "Envelope") == 0 )
     {
@@ -834,8 +837,12 @@ void GMLHandler::DealWithAttributes(const char *pszName, int nLenName, void* att
         /* Should we report all attributes ? */
         else if( m_poReader->ReportAllAttributes() && !poClass->IsSchemaLocked() )
         {
+            poState->PushPath( pszName, nLenName );
+            CPLString osPropName = poState->osPath;
+            poState->PopPath();
+
             m_poReader->SetFeaturePropertyDirectly(
-                CPLSPrintf("%s@%s", pszName, pszAttrKeyNoNS ? pszAttrKeyNoNS : pszAttrKey),
+                CPLSPrintf("%s@%s", osPropName.c_str(), pszAttrKeyNoNS ? pszAttrKeyNoNS : pszAttrKey),
                 pszAttrVal, -1 );
             pszAttrVal = NULL;
         }
@@ -1064,6 +1071,28 @@ OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenNam
         {
             bReadGeometry = TRUE;
         }
+        else if( !poClass->IsSchemaLocked() && m_poReader->IsWFSJointLayer() )
+        {
+            m_nGeometryPropertyIndex = poClass->GetGeometryPropertyIndexBySrcElement( poState->osPath.c_str() );
+            if( m_nGeometryPropertyIndex < 0 )
+            {
+                const char* pszElement = poState->osPath.c_str();
+                CPLString osFieldName;
+                /* Strip member| prefix. Should always be true normally */
+                if( strncmp(pszElement, "member|", strlen("member|")) == 0 )
+                    osFieldName = pszElement + strlen("member|");
+
+                /* Replace layer|property by layer_property */
+                size_t iPos = osFieldName.find('|');
+                if( iPos != std::string::npos )
+                    osFieldName[iPos] = '.';
+
+                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
+                        osFieldName, poState->osPath.c_str(), wkbUnknown, -1, TRUE ) );
+                m_nGeometryPropertyIndex = poClass->GetGeometryPropertyCount();
+            }
+            bReadGeometry = TRUE;
+        }
         else
         {
             /* AIXM special case: for RouteSegment, we only want to read Curve geometries */
@@ -1125,6 +1154,22 @@ OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenNam
 
         return OGRERR_NONE;
     }
+    
+    else if( m_poReader->IsWFSJointLayer() && m_nDepth == m_nDepthFeature + 1 )
+    {
+    }
+
+    else if( m_poReader->IsWFSJointLayer() && m_nDepth == m_nDepthFeature + 2 )
+    {
+        const char* pszFID = GetFID(attr);
+        if( pszFID )
+        {
+            poState->PushPath( pszName, nLenName );
+            CPLString osPropPath= poState->osPath + "@id";
+            poState->PopPath();
+            m_poReader->SetFeaturePropertyDirectly( osPropPath, CPLStrdup(pszFID), -1 );
+        }
+    }
 
 /* -------------------------------------------------------------------- */
 /*      If it is (or at least potentially is) a simple attribute,       */
@@ -1188,7 +1233,9 @@ OGRErr GMLHandler::startElementFeatureAttribute(const char *pszName, int nLenNam
 /*                         startElementTop()                            */
 /************************************************************************/
 
-OGRErr GMLHandler::startElementTop(const char *pszName, CPL_UNUSED int nLenName, void* attr )
+OGRErr GMLHandler::startElementTop(const char *pszName,
+                                   CPL_UNUSED int nLenName,
+                                   void* attr )
 {
     if (strcmp(pszName, "CityModel") == 0 )
     {
@@ -1464,6 +1511,24 @@ OGRErr GMLHandler::endElementGeometry()
                 psInterestNode->pszValue = CPLStrdup("gml:Point");
             }
         }
+        else if( psInterestNode != NULL &&
+                 strcmp(psInterestNode->pszValue, "BoundingBox") == 0 )
+        {
+            CPLFree(psInterestNode->pszValue);
+            psInterestNode->pszValue = CPLStrdup("Envelope");
+            for( CPLXMLNode* psChild = psInterestNode->psChild;
+                 psChild;
+                 psChild = psChild->psNext )
+            {
+                if( psChild->eType == CXT_Attribute &&
+                    strcmp(psChild->pszValue, "crs") == 0 )
+                {
+                    CPLFree(psChild->pszValue);
+                    psChild->pszValue = CPLStrdup("srsName");
+                    break;
+                }
+            }
+        }
 
         GMLFeature* poGMLFeature = m_poReader->GetState()->m_poFeature;
         if (m_poReader->FetchAllGeometries())
@@ -1774,7 +1839,8 @@ int GMLHandler::IsGeometryElement( const char *pszElement )
             nFirst = nMiddle + 1;
     } while(nFirst <= nLast);
 
-    if (eAppSchemaType == APPSCHEMA_AIXM && strcmp( pszElement, "ElevatedPoint") == 0)
+    if (eAppSchemaType == APPSCHEMA_AIXM &&
+        strcmp( pszElement, "ElevatedPoint") == 0)
         return TRUE;
 
     if( eAppSchemaType == APPSCHEMA_MTKGML &&
diff --git a/ogr/ogrsf_frmts/gml/gmlpropertydefn.cpp b/ogr/ogrsf_frmts/gml/gmlpropertydefn.cpp
index 58da94f..6eaa094 100644
--- a/ogr/ogrsf_frmts/gml/gmlpropertydefn.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlpropertydefn.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: gmlpropertydefn.cpp 27132 2014-04-05 21:48:58Z rouault $
+ * $Id: gmlpropertydefn.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLPropertyDefn
@@ -55,6 +55,7 @@ GMLPropertyDefn::GMLPropertyDefn( const char *pszName,
     m_nWidth = 0; 
     m_nPrecision = 0;
     m_pszCondition = NULL;
+    m_bNullable = TRUE;
 }
 
 /************************************************************************/
@@ -122,6 +123,8 @@ void GMLPropertyDefn::AnalysePropertyValue( const GMLProperty* psGMLProperty,
         {
             if( m_eType == GMLPT_Integer )
                 m_eType = GMLPT_IntegerList;
+            else if( m_eType == GMLPT_Integer64 )
+                m_eType = GMLPT_Integer64List;
             else if( m_eType == GMLPT_Real )
                 m_eType = GMLPT_RealList;
             else if( m_eType == GMLPT_String )
@@ -129,6 +132,8 @@ void GMLPropertyDefn::AnalysePropertyValue( const GMLProperty* psGMLProperty,
                 m_eType = GMLPT_StringList;
                 m_nWidth = 0;
             }
+            else if( m_eType == GMLPT_Boolean )
+                m_eType = GMLPT_BooleanList;
         }
         const char* pszValue = psGMLProperty->papszSubProperties[j];
 /* -------------------------------------------------------------------- */
@@ -140,27 +145,23 @@ void GMLPropertyDefn::AnalysePropertyValue( const GMLProperty* psGMLProperty,
 
         CPLValueType valueType = CPLGetValueType(pszValue);
 
-        /* This might not fit into a int32. For now, let's */
-        /* consider this as a real value then. */
-        /* FIXME once RFC31 / 64 bit support is set, we could */
-        /* choose a different behaviour */
-        if (valueType == CPL_VALUE_INTEGER && strlen(pszValue) >= 10)
-        {
-            /* Skip leading spaces */
-            while( isspace( (unsigned char)*pszValue ) )
-                pszValue ++;
-            char szVal[32];
-            sprintf(szVal, "%d", atoi(pszValue));
-            if (strcmp(pszValue, szVal) != 0)
-                valueType = CPL_VALUE_REAL;
-        }
-
         if (valueType == CPL_VALUE_STRING
             && m_eType != GMLPT_String 
             && m_eType != GMLPT_StringList )
         {
-            if( m_eType == GMLPT_IntegerList
-                || m_eType == GMLPT_RealList )
+            if( (m_eType == GMLPT_Untyped || m_eType == GMLPT_Boolean) &&
+                (strcmp(pszValue, "true") == 0 ||
+                 strcmp(pszValue, "false") == 0) )
+                m_eType = GMLPT_Boolean;
+            else if( m_eType == GMLPT_BooleanList )
+            {
+                if( !(strcmp(pszValue, "true") == 0 ||
+                      strcmp(pszValue, "false") == 0) )
+                    m_eType = GMLPT_StringList;
+            }
+            else if( m_eType == GMLPT_IntegerList ||
+                     m_eType == GMLPT_Integer64List ||
+                     m_eType == GMLPT_RealList )
                 m_eType = GMLPT_StringList;
             else
                 m_eType = GMLPT_String;
@@ -179,17 +180,31 @@ void GMLPropertyDefn::AnalysePropertyValue( const GMLProperty* psGMLProperty,
                     SetWidth( nWidth );
             }
         }
-        else if( m_eType == GMLPT_Untyped || m_eType == GMLPT_Integer )
+        else if( m_eType == GMLPT_Untyped || m_eType == GMLPT_Integer ||
+                 m_eType == GMLPT_Integer64 )
         {
             if( bIsReal )
                 m_eType = GMLPT_Real;
-            else
-                m_eType = GMLPT_Integer;
+            else if( m_eType != GMLPT_Integer64 )
+            {
+                GIntBig nVal = CPLAtoGIntBig(pszValue);
+                if( (GIntBig)(int)nVal != nVal )
+                    m_eType = GMLPT_Integer64;
+                else
+                    m_eType = GMLPT_Integer;
+            }
         }
-        else if( m_eType == GMLPT_IntegerList && bIsReal )
+        else if( (m_eType == GMLPT_IntegerList ||
+                  m_eType == GMLPT_Integer64List) && bIsReal )
         {
             m_eType = GMLPT_RealList;
         }
+        else if( m_eType == GMLPT_IntegerList && valueType == CPL_VALUE_INTEGER )
+        {
+            GIntBig nVal = CPLAtoGIntBig(pszValue);
+            if( (GIntBig)(int)nVal != nVal )
+                m_eType = GMLPT_Integer64List;
+        }
     }
 }
 
@@ -200,13 +215,15 @@ void GMLPropertyDefn::AnalysePropertyValue( const GMLProperty* psGMLProperty,
 GMLGeometryPropertyDefn::GMLGeometryPropertyDefn( const char *pszName,
                                                   const char *pszSrcElement,
                                                   int nType,
-                                                  int nAttributeIndex )
+                                                  int nAttributeIndex,
+                                                  int bNullable )
 {
     m_pszName = (pszName == NULL || pszName[0] == '\0') ?
                         CPLStrdup(pszSrcElement) : CPLStrdup(pszName);
     m_pszSrcElement = CPLStrdup(pszSrcElement);
     m_nGeometryType = nType;
     m_nAttributeIndex = nAttributeIndex;
+    m_bNullable = bNullable;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/gml/gmlreader.cpp b/ogr/ogrsf_frmts/gml/gmlreader.cpp
index 358e825..ece3448 100644
--- a/ogr/ogrsf_frmts/gml/gmlreader.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gmlreader.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gmlreader.cpp 29094 2015-05-01 18:55:27Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLReader class.
@@ -63,11 +63,10 @@ IGMLReader::~IGMLReader()
 /*                          CreateGMLReader()                           */
 /************************************************************************/
 
-IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
-                            int bInvertAxisOrderIfLatLong,
-                            int bConsiderEPSGAsURN,
-                            int bGetSecondaryGeometryOption)
-
+IGMLReader *CreateGMLReader(CPL_UNUSED int bUseExpatParserPreferably,
+                            CPL_UNUSED int bInvertAxisOrderIfLatLong,
+                            CPL_UNUSED int bConsiderEPSGAsURN,
+                            CPL_UNUSED int bGetSecondaryGeometryOption)
 {
     CPLError( CE_Failure, CPLE_AppDefined,
               "Unable to create Xerces C++ or Expat based GML reader, Xerces or Expat support\n"
@@ -102,30 +101,29 @@ IGMLReader *CreateGMLReader(int bUseExpatParserPreferably,
 
 OGRGMLXercesState GMLReader::m_eXercesInitState = OGRGML_XERCES_UNINITIALIZED;
 int GMLReader::m_nInstanceCount = 0;
-void *GMLReader::hMutex = NULL;
+CPLMutex *GMLReader::hMutex = NULL;
 
 /************************************************************************/
 /*                             GMLReader()                              */
 /************************************************************************/
 
 GMLReader::GMLReader(
-#ifndef HAVE_XERCES
+#ifndef HAVE_EXPAT
 CPL_UNUSED
 #endif
                      int bUseExpatParserPreferably,
                      int bInvertAxisOrderIfLatLong,
                      int bConsiderEPSGAsURN,
                      int bGetSecondaryGeometryOption)
-
 {
 #ifndef HAVE_XERCES
     bUseExpatReader = TRUE;
 #else
     bUseExpatReader = FALSE;
-#  ifdef HAVE_EXPAT
+#ifdef HAVE_EXPAT
     if(bUseExpatParserPreferably)
         bUseExpatReader = TRUE;
-#  endif
+#endif
 #endif
 
 #if defined(HAVE_EXPAT) && defined(HAVE_XERCES)
@@ -189,6 +187,7 @@ CPL_UNUSED
     m_bReportAllAttributes = CSLTestBoolean(
                     CPLGetConfigOption("GML_ATTRIBUTES_TO_OGR_FIELDS", "NO"));
 
+    m_bIsWFSJointLayer = FALSE;
 }
 
 /************************************************************************/
@@ -623,6 +622,13 @@ GMLFeature *GMLReader::NextFeatureExpat()
         unsigned int nLen =
                 (unsigned int)VSIFReadL( pabyBuf, 1, PARSER_BUF_SIZE, fpGML );
         nDone = VSIFEofL(fpGML);
+
+        /* Some files, such as APT_AIXM.xml from https://nfdc.faa.gov/webContent/56DaySub/2015-03-05/aixm5.1.zip */
+        /* end with trailing nul characters. This test is not fully bullet-proof in case */
+        /* the nul characters would occur at a buffer boundary */
+        while( nDone && nLen > 0 && pabyBuf[nLen-1] == '\0' )
+            nLen --;
+
         if (XML_Parse(oParser, pabyBuf, nLen, nDone) == XML_STATUS_ERROR)
         {
             CPLError(CE_Failure, CPLE_AppDefined,
@@ -783,6 +789,28 @@ int GMLReader::GetFeatureElementIndex( const char *pszElement, int nElementLengt
         {
             /* GML answer of MapServer WMS GetFeatureInfo request */
         }
+
+        /* Begin of CSW SearchResults */
+        else if (nElementLength == strlen("BriefRecord") &&
+                 nLenLast == strlen("SearchResults") &&
+                 strcmp(pszElement, "BriefRecord") == 0 &&
+                 strcmp(pszLast, "SearchResults") == 0)
+        {
+        }
+        else if (nElementLength == strlen("SummaryRecord") &&
+                 nLenLast == strlen("SearchResults") &&
+                 strcmp(pszElement, "SummaryRecord") == 0 &&
+                 strcmp(pszLast, "SearchResults") == 0)
+        {
+        }
+        else if (nElementLength == strlen("Record") &&
+                 nLenLast == strlen("SearchResults") &&
+                 strcmp(pszElement, "Record") == 0 &&
+                 strcmp(pszLast, "SearchResults") == 0)
+        {
+        }
+        /* End of CSW SearchResults */
+
         else
         {
             if( m_bClassListLocked )
@@ -1079,7 +1107,28 @@ void GMLReader::SetFeaturePropertyDirectly( const char *pszElement,
 
             CPLString osFieldName;
 
-            if( strchr(pszElement,'|') == NULL )
+            if( IsWFSJointLayer() )
+            {
+                /* At that point the element path should be member|layer|property */
+
+                /* Strip member| prefix. Should always be true normally */
+                if( strncmp(pszElement, "member|", strlen("member|")) == 0 )
+                    osFieldName = pszElement + strlen("member|");
+
+                /* Replace layer|property by layer_property */
+                size_t iPos = osFieldName.find('|');
+                if( iPos != std::string::npos )
+                    osFieldName[iPos] = '.';
+
+                /* Special case for gml:id on layer */
+                iPos = osFieldName.find("@id");
+                if( iPos != std::string::npos )
+                {
+                    osFieldName.resize(iPos);
+                    osFieldName += ".gml_id";
+                }
+            }
+            else if( strchr(pszElement,'|') == NULL )
                 osFieldName = pszElement;
             else
             {
@@ -1313,7 +1362,9 @@ int GMLReader::SaveClasses( const char *pszFile )
 /*      looking for schema information.                                 */
 /************************************************************************/
 
-int GMLReader::PrescanForSchema( int bGetExtents, int bAnalyzeSRSPerFeature )
+int GMLReader::PrescanForSchema( int bGetExtents,
+                                 int bAnalyzeSRSPerFeature,
+                                 int bOnlyDetectSRS )
 
 {
     GMLFeature  *poFeature;
@@ -1321,9 +1372,12 @@ int GMLReader::PrescanForSchema( int bGetExtents, int bAnalyzeSRSPerFeature )
     if( m_pszFilename == NULL )
         return FALSE;
 
-    SetClassListLocked( FALSE );
+    if( !bOnlyDetectSRS )
+    {
+        SetClassListLocked( FALSE );
+        ClearClasses();
+    }
 
-    ClearClasses();
     if( !SetupParser() )
         return FALSE;
 
@@ -1352,21 +1406,21 @@ int GMLReader::PrescanForSchema( int bGetExtents, int bAnalyzeSRSPerFeature )
             poClass->SetFeatureCount( poClass->GetFeatureCount() + 1 );
 
         const CPLXMLNode* const * papsGeometry = poFeature->GetGeometryList();
-        if( papsGeometry != NULL && papsGeometry[0] != NULL )
+        if( !bOnlyDetectSRS && papsGeometry != NULL && papsGeometry[0] != NULL )
         {
             if( poClass->GetGeometryPropertyCount() == 0 )
-                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown ) );
+                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, TRUE ) );
         }
 
 #ifdef SUPPORT_GEOMETRY
-        if( bGetExtents )
+        if( bGetExtents && papsGeometry != NULL )
         {
             OGRGeometry *poGeometry = GML_BuildOGRGeometryFromList(
                 papsGeometry, TRUE, m_bInvertAxisOrderIfLatLong,
                 NULL, m_bConsiderEPSGAsURN, m_bGetSecondaryGeometryOption, 
                 hCacheSRS, m_bFaceHoleNegative );
 
-            if( poGeometry != NULL )
+            if( poGeometry != NULL && poClass->GetGeometryPropertyCount() > 0 )
             {
                 double  dfXMin, dfXMax, dfYMin, dfYMax;
                 OGREnvelope sEnvelope;
@@ -1389,8 +1443,8 @@ int GMLReader::PrescanForSchema( int bGetExtents, int bAnalyzeSRSPerFeature )
                     eGType = wkbNone;
 
                 poClass->GetGeometryProperty(0)->SetType( 
-                    (int) OGRMergeGeometryTypes(
-                        eGType, poGeometry->getGeometryType() ) );
+                    (int) OGRMergeGeometryTypesEx(
+                        eGType, poGeometry->getGeometryType(), TRUE ) );
 
                 // merge extents.
                 if (!poGeometry->IsEmpty())
diff --git a/ogr/ogrsf_frmts/gml/gmlreader.h b/ogr/ogrsf_frmts/gml/gmlreader.h
index 5e3b279..667c2ab 100644
--- a/ogr/ogrsf_frmts/gml/gmlreader.h
+++ b/ogr/ogrsf_frmts/gml/gmlreader.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gmlreader.h 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gmlreader.h 29051 2015-04-29 17:18:37Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Public Declarations for OGR free GML Reader code.
@@ -47,7 +47,13 @@ typedef enum {
     GMLPT_IntegerList = 6, 
     GMLPT_RealList = 7,
     GMLPT_FeatureProperty = 8,
-    GMLPT_FeaturePropertyList = 9
+    GMLPT_FeaturePropertyList = 9,
+    GMLPT_Boolean = 10,
+    GMLPT_BooleanList = 11,
+    GMLPT_Short = 12,
+    GMLPT_Float = 13,
+    GMLPT_Integer64 = 14,
+    GMLPT_Integer64List = 15
 } GMLPropertyType;
 
 /************************************************************************/
@@ -70,6 +76,7 @@ class CPL_DLL GMLPropertyDefn
     char             *m_pszSrcElement;
     size_t            m_nSrcElementLen;
     char             *m_pszCondition;
+    int               m_bNullable;
 
 public:
     
@@ -90,6 +97,9 @@ public:
 
     void        SetCondition( const char *pszCondition );
     const char *GetCondition() const { return m_pszCondition; }
+    
+    void        SetNullable( int bNullable ) { m_bNullable = bNullable; }
+    int         IsNullable() const { return m_bNullable; }
 
     void        AnalysePropertyValue( const GMLProperty* psGMLProperty,
                                       int bSetWidth = TRUE );
@@ -108,10 +118,12 @@ class CPL_DLL GMLGeometryPropertyDefn
     char       *m_pszSrcElement;
     int         m_nGeometryType;
     int         m_nAttributeIndex;
+    int         m_bNullable;
     
 public:
         GMLGeometryPropertyDefn( const char *pszName, const char *pszSrcElement,
-                                 int nType, int nAttributeIndex = -1 );
+                                 int nType, int nAttributeIndex,
+                                 int bNullable );
        ~GMLGeometryPropertyDefn();
 
         const char *GetName() const { return m_pszName; } 
@@ -121,6 +133,8 @@ public:
         const char *GetSrcElement() const { return m_pszSrcElement; }
         
         int GetAttributeIndex() const { return m_nAttributeIndex; }
+
+        int IsNullable() const { return m_bNullable; }
 };
 
 /************************************************************************/
@@ -140,7 +154,7 @@ class CPL_DLL GMLFeatureClass
 
     int         m_bSchemaLocked;
 
-    int         m_nFeatureCount;
+    GIntBig     m_nFeatureCount;
 
     char        *m_pszExtraInfo;
 
@@ -151,7 +165,7 @@ class CPL_DLL GMLFeatureClass
     double      m_dfYMax;
 
     char       *m_pszSRSName;
-    int         m_bSRSNameConsistant;
+    int         m_bSRSNameConsistent;
 
 public:
             GMLFeatureClass( const char *pszName = "" );
@@ -169,10 +183,12 @@ public:
     GMLPropertyDefn *GetProperty( const char *pszName ) const 
         { return GetProperty( GetPropertyIndex(pszName) ); }
     int         GetPropertyIndexBySrcElement( const char *pszElement, int nLen ) const;
-    
+    void        StealProperties();
+
     int         GetGeometryPropertyCount() const { return m_nGeometryPropertyCount; }
     GMLGeometryPropertyDefn *GetGeometryProperty( int iIndex ) const;
     int         GetGeometryPropertyIndexBySrcElement( const char *pszElement ) const;
+    void        StealGeometryProperties();
 
     int         HasFeatureProperties();
 
@@ -186,8 +202,8 @@ public:
     const char  *GetExtraInfo();
     void        SetExtraInfo( const char * );
 
-    int         GetFeatureCount();
-    void        SetFeatureCount( int );
+    GIntBig     GetFeatureCount();
+    void        SetFeatureCount( GIntBig );
 
     int         HasExtents() const { return m_bHaveExtents; }
     void        SetExtents( double dfXMin, double dfXMax, 
@@ -261,7 +277,7 @@ public:
     virtual void SetClassListLocked( int bFlag ) = 0;
 
     virtual void SetSourceFile( const char *pszFilename ) = 0;
-    virtual void SetFP( CPL_UNUSED VSILFILE* fp ) { }
+    virtual void SetFP( CPL_UNUSED VSILFILE* fp ) {}
     virtual const char* GetSourceFileName() = 0;
 
     virtual int  GetClassCount() const = 0;
@@ -286,7 +302,9 @@ public:
                                    int pbSqlitIsTempFile,
                                    int iSqliteCacheMB ) = 0;
 
-    virtual int PrescanForSchema( int bGetExtents = TRUE, int bAnalyzeSRSPerFeature = TRUE ) = 0;
+    virtual int PrescanForSchema( int bGetExtents = TRUE,
+                                  int bAnalyzeSRSPerFeature = TRUE,
+                                  int bOnlyDetectSRS = FALSE ) = 0;
     virtual int PrescanForTemplate( void ) = 0;
 
     virtual int HasStoppedParsing() = 0;
diff --git a/ogr/ogrsf_frmts/gml/gmlreaderp.h b/ogr/ogrsf_frmts/gml/gmlreaderp.h
index 4f5f695..84b2ff2 100644
--- a/ogr/ogrsf_frmts/gml/gmlreaderp.h
+++ b/ogr/ogrsf_frmts/gml/gmlreaderp.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gmlreaderp.h 27531 2014-07-14 20:33:03Z rouault $
+ * $Id: gmlreaderp.h 29051 2015-04-29 17:18:37Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Private Declarations for OGR free GML Reader code.
@@ -34,6 +34,7 @@
 #include "gmlreader.h"
 #include "ogr_api.h"
 #include "cpl_vsi.h"
+#include "cpl_multiproc.h"
 
 #include <string>
 #include <vector>
@@ -462,6 +463,8 @@ private:
     int           m_bSetWidthFlag;
     
     int           m_bReportAllAttributes;
+    
+    int           m_bIsWFSJointLayer;
 
     int           ParseXMLHugeFile( const char *pszOutputFilename, 
                                     const int bSqliteIsTempFile,
@@ -502,7 +505,9 @@ public:
                                        int pbSqliteIsTempFile,
                                        int iSqliteCacheMB );
 
-    int              PrescanForSchema(int bGetExtents = TRUE, int bAnalyzeSRSPerFeature = TRUE );
+    int              PrescanForSchema(int bGetExtents = TRUE,
+                                      int bAnalyzeSRSPerFeature = TRUE,
+                                      int bOnlyDetectSRS = FALSE );
     int              PrescanForTemplate( void );
     int              ReArrangeTemplateClasses( GFSTemplateList *pCC );
     void             ResetReading();
@@ -546,8 +551,11 @@ public:
     int         IsSequentialLayers() const { return m_bSequentialLayers == TRUE; }
     
     int         ReportAllAttributes() const { return m_bReportAllAttributes; }
+    
+    void             SetIsWFSJointLayer( int bFlag ) { m_bIsWFSJointLayer = bFlag; }
+    int              IsWFSJointLayer() const { return m_bIsWFSJointLayer; }
 
-    static void* hMutex;
+    static CPLMutex* hMutex;
 };
 
 #endif /* _CPL_GMLREADERP_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/gml/gmlutils.cpp b/ogr/ogrsf_frmts/gml/gmlutils.cpp
index 46248bb..3236b77 100644
--- a/ogr/ogrsf_frmts/gml/gmlutils.cpp
+++ b/ogr/ogrsf_frmts/gml/gmlutils.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gmlutils.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: gmlutils.cpp 27576 2014-08-06 22:23:51Z rouault $
  *
  * Project:  GML Utils
  * Purpose:  GML reader
@@ -200,7 +200,7 @@ OGRGeometry* GML_BuildOGRGeometryFromList(const CPLXMLNode* const * papsGeometry
     {
         OGRGeometry* poSubGeom = GML2OGRGeometry_XMLNode( papsGeometry[i],
                                                           bGetSecondaryGeometryOption,
-                                                          0, FALSE, TRUE,
+                                                          0, 0, FALSE, TRUE,
                                                           bFaceHoleNegative );
         if (poSubGeom)
         {
diff --git a/ogr/ogrsf_frmts/gml/hugefileresolver.cpp b/ogr/ogrsf_frmts/gml/hugefileresolver.cpp
index 87cb944..2c3c50b 100644
--- a/ogr/ogrsf_frmts/gml/hugefileresolver.cpp
+++ b/ogr/ogrsf_frmts/gml/hugefileresolver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: hugefileresolver.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: hugefileresolver.cpp 27766 2014-09-28 20:13:12Z goatbar $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLReader::HugeFileResolver() method.
@@ -47,7 +47,7 @@
 
 #include <stack>
 
-CPL_CVSID("$Id: hugefileresolver.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: hugefileresolver.cpp 27766 2014-09-28 20:13:12Z goatbar $");
 
 /****************************************************/
 /*      SQLite is absolutely required in order to   */
@@ -1462,8 +1462,9 @@ static int gmlHugeSetChild( struct huge_parent *pParent,
     return FALSE;
 }
 
-static int gmlHugeResolveEdges( struct huge_helper *helper,
-                                CPL_UNUSED CPLXMLNode *psNode, sqlite3 *hDB )
+static int gmlHugeResolveEdges( CPL_UNUSED struct huge_helper *helper,
+                                CPL_UNUSED CPLXMLNode *psNode,
+                                sqlite3 *hDB )
 {
 /* resolving GML <Edge> xlink:href */
     CPLString      osCommand;
@@ -2054,9 +2055,9 @@ int GMLReader::HugeFileResolver( const char *pszFile,
 /*    simply output an error message              */
 /**************************************************/
 
-int GMLReader::HugeFileResolver( const char *pszFile,
-                                 int bSqliteIsTempFile,
-                                 int iSqliteCacheMB )
+int GMLReader::HugeFileResolver( CPL_UNUSED const char *pszFile,
+                                 CPL_UNUSED int bSqliteIsTempFile,
+                                 CPL_UNUSED int iSqliteCacheMB )
 
 {
     CPLError( CE_Failure, CPLE_NotSupported,
@@ -2065,9 +2066,9 @@ int GMLReader::HugeFileResolver( const char *pszFile,
     return FALSE;
 }
 
-int GMLReader::ParseXMLHugeFile( const char *pszOutputFilename,
-                                 const int bSqliteIsTempFile,
-                                 const int iSqliteCacheMB )
+int GMLReader::ParseXMLHugeFile( CPL_UNUSED const char *pszOutputFilename,
+                                 CPL_UNUSED const int bSqliteIsTempFile,
+                                 CPL_UNUSED const int iSqliteCacheMB )
 {
     CPLError( CE_Failure, CPLE_NotSupported,
               "OGR was built without SQLite3 support\n"
diff --git a/ogr/ogrsf_frmts/gml/ogr_gml.h b/ogr/ogrsf_frmts/gml/ogr_gml.h
index 3b96f5e..c7deab3 100644
--- a/ogr/ogrsf_frmts/gml/ogr_gml.h
+++ b/ogr/ogrsf_frmts/gml/ogr_gml.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gml.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gml.h 29013 2015-04-25 18:12:21Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Declarations for OGR wrapper classes for GML, and GML<->OGR
@@ -52,7 +52,7 @@ class OGRGMLLayer : public OGRLayer
 {
     OGRFeatureDefn     *poFeatureDefn;
 
-    int                 iNextGMLId;
+    GIntBig             iNextGMLId;
     int                 nTotalGMLCount;
     int                 bInvalidFIDFound;
     char                *pszFIDPrefix;
@@ -70,8 +70,6 @@ class OGRGMLLayer : public OGRLayer
 
     int                 bFaceHoleNegative;
 
-    OGRGeometry        *ConvertGeomToMultiIfNecessary(OGRGeometry* poGeom);
-
   public:
                         OGRGMLLayer( const char * pszName, 
                                      int bWriter,
@@ -82,10 +80,10 @@ class OGRGMLLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    int                 GetFeatureCount( int bForce = TRUE );
+    GIntBig             GetFeatureCount( int bForce = TRUE );
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -153,21 +151,26 @@ class OGRGMLDataSource : public OGRDataSource
     GMLFeature         *poStoredGMLFeature;
     OGRGMLLayer        *poLastReadLayer;
 
-    void                FindAndParseBoundedBy(VSILFILE* fp);
+    void                FindAndParseTopElements(VSILFILE* fp);
     void                SetExtents(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY);
+    
+    void                BuildJointClassFromXSD();
+    void                BuildJointClassFromScannedSchema();
+    
+    void                WriteTopElements();
 
   public:
                         OGRGMLDataSource();
                         ~OGRGMLDataSource();
 
-    int                 Open( const char * );
+    int                 Open( GDALOpenInfo* poOpenInfo );
     int                 Create( const char *pszFile, char **papszOptions );
 
     const char          *GetName() { return pszName; }
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -204,29 +207,14 @@ class OGRGMLDataSource : public OGRDataSource
     const char         *GetAppPrefix();
     int                 RemoveAppPrefix();
     int                 WriteFeatureBoundedBy();
+    const char         *GetSRSDimensionLoc();
 
     virtual OGRLayer *          ExecuteSQL( const char *pszSQLCommand,
                                             OGRGeometry *poSpatialFilter,
                                             const char *pszDialect );
     virtual void                ReleaseResultSet( OGRLayer * poResultsSet );
-};
-
-/************************************************************************/
-/*                             OGRGMLDriver                             */
-/************************************************************************/
-
-class OGRGMLDriver : public OGRSFDriver
-{
-  public:
-                ~OGRGMLDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
     
-    int                 TestCapability( const char * );
+    static int          CheckHeader(const char* pszStr);
 };
 
 #endif /* _OGR_GML_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp b/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp
index 412c793..5b84750 100644
--- a/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp
+++ b/ogr/ogrsf_frmts/gml/ogrgmldatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgmldatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgmldatasource.cpp 29091 2015-05-01 18:20:25Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRGMLDataSource class.
@@ -43,10 +43,11 @@
 #include "gmlutils.h"
 #include "ogr_p.h"
 #include "gmlregistry.h"
+#include "gmlreaderp.h"
 
 #include <vector>
 
-CPL_CVSID("$Id: ogrgmldatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgmldatasource.cpp 29091 2015-05-01 18:20:25Z rouault $");
 
 static int ExtractSRSName(const char* pszXML, char* szSRSName,
                           size_t sizeof_szSRSName);
@@ -128,6 +129,9 @@ OGRGMLDataSource::~OGRGMLDataSource()
 
     if( fpOutput != NULL )
     {
+        if( nLayers == 0 )
+            WriteTopElements();
+
         const char* pszPrefix = GetAppPrefix();
         if( RemoveAppPrefix() )
             PrintLine( fpOutput, "</FeatureCollection>" );
@@ -245,15 +249,63 @@ OGRGMLDataSource::~OGRGMLDataSource()
 }
 
 /************************************************************************/
+/*                            CheckHeader()                             */
+/************************************************************************/
+
+int OGRGMLDataSource::CheckHeader(const char* pszStr)
+{
+    if( strstr(pszStr,"opengis.net/gml") == NULL &&
+        strstr(pszStr,"<csw:GetRecordsResponse") == NULL )
+    {
+        return FALSE;
+    }
+
+    /* Ignore .xsd schemas */
+    if( strstr(pszStr, "<schema") != NULL
+        || strstr(pszStr, "<xs:schema") != NULL
+        || strstr(pszStr, "<xsd:schema") != NULL )
+    {
+        return FALSE;
+    }
+
+    /* Ignore GeoRSS documents. They will be recognized by the GeoRSS driver */
+    if( strstr(pszStr, "<rss") != NULL && strstr(pszStr, "xmlns:georss") != NULL )
+    {
+        return FALSE;
+    }
+
+    /* Ignore OpenJUMP .jml documents. They will be recognized by the OpenJUMP driver */
+    if( strstr(pszStr, "<JCSDataFile") != NULL )
+    {
+        return FALSE;
+    }
+
+    /* Ignore OGR WFS xml description files, or WFS Capabilities results */
+    if( strstr(pszStr, "<OGRWFSDataSource>") != NULL ||
+        strstr(pszStr, "<wfs:WFS_Capabilities") != NULL )
+    {
+        return FALSE;
+    }
+
+    /* Ignore WMTS capabilities results */
+    if( strstr(pszStr, "http://www.opengis.net/wmts/1.0") != NULL )
+    {
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRGMLDataSource::Open( const char * pszNameIn )
+int OGRGMLDataSource::Open( GDALOpenInfo* poOpenInfo )
 
 {
     VSILFILE   *fp;
     char        szHeader[4096];
-    int         nNumberOfFeatures = 0;
+    GIntBig     nNumberOfFeatures = 0;
     CPLString   osWithVsiGzip;
     const char *pszSchemaLocation = NULL;
     int bCheckAuxFile = TRUE;
@@ -261,23 +313,35 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
 /* -------------------------------------------------------------------- */
 /*      Extract xsd filename from connexion string if present.          */
 /* -------------------------------------------------------------------- */
-    osFilename = pszNameIn;
-    const char *pszXSDFilenameTmp = strstr(pszNameIn, ",xsd=");
+    osFilename = poOpenInfo->pszFilename;
+    const char *pszXSDFilenameTmp = strstr(poOpenInfo->pszFilename, ",xsd=");
     if (pszXSDFilenameTmp != NULL)
     {
-        osFilename.resize(pszXSDFilenameTmp - pszNameIn);
+        osFilename.resize(pszXSDFilenameTmp - poOpenInfo->pszFilename);
         osXSDFilename = pszXSDFilenameTmp + strlen(",xsd=");
     }
+    else
+        osXSDFilename = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "XSD", "");
+
     const char *pszFilename = osFilename.c_str();
 
-    pszName = CPLStrdup( pszNameIn );
+    pszName = CPLStrdup( poOpenInfo->pszFilename );
 
 /* -------------------------------------------------------------------- */
 /*      Open the source file.                                           */
 /* -------------------------------------------------------------------- */
-    fp = VSIFOpenL( pszFilename, "r" );
-    if( fp == NULL )
-        return FALSE;
+    VSILFILE* fpToClose = NULL;
+    if( poOpenInfo->fpL != NULL )
+    {
+        fp = poOpenInfo->fpL;
+        VSIFSeekL(fp, 0, SEEK_SET);
+    }
+    else
+    {
+        fpToClose = fp = VSIFOpenL( pszFilename, "r" );
+        if( fp == NULL )
+            return FALSE;
+    }
 
     int bExpatCompatibleEncoding = FALSE;
     int bHas3D = FALSE;
@@ -294,7 +358,8 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
     size_t nRead = VSIFReadL( szHeader, 1, sizeof(szHeader)-1, fp );
     if (nRead <= 0)
     {
-        VSIFCloseL( fp );
+        if( fpToClose )
+            VSIFCloseL( fpToClose );
         return FALSE;
     }
     szHeader[nRead] = '\0';
@@ -305,20 +370,22 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
             EQUAL(CPLGetExtension(pszFilename), "gz") &&
             strncmp(pszFilename, "/vsigzip/", strlen("/vsigzip/")) != 0 )
     {
-        VSIFCloseL( fp );
+        if( fpToClose )
+            VSIFCloseL( fpToClose );
+        fpToClose = NULL;
         osWithVsiGzip = "/vsigzip/";
         osWithVsiGzip += pszFilename;
 
         pszFilename = osWithVsiGzip;
 
-        fp = VSIFOpenL( pszFilename, "r" );
+        fp = fpToClose = VSIFOpenL( pszFilename, "r" );
         if( fp == NULL )
             return FALSE;
 
         nRead = VSIFReadL( szHeader, 1, sizeof(szHeader) - 1, fp );
         if (nRead <= 0)
         {
-            VSIFCloseL( fp );
+            VSIFCloseL( fpToClose );
             return FALSE;
         }
         szHeader[nRead] = '\0';
@@ -356,35 +423,16 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
 /* -------------------------------------------------------------------- */
 /*      Here, we expect the opening chevrons of GML tree root element   */
 /* -------------------------------------------------------------------- */
-    if( szPtr[0] != '<' 
-        || strstr(szPtr,"opengis.net/gml") == NULL )
-    {
-        VSIFCloseL( fp );
-        return FALSE;
-    }
-
-    /* Ignore .xsd schemas */
-    if( strstr(szPtr, "<schema") != NULL
-        || strstr(szPtr, "<xs:schema") != NULL
-        || strstr(szPtr, "<xsd:schema") != NULL )
+    if( szPtr[0] != '<' || !CheckHeader(szPtr) )
     {
-        VSIFCloseL( fp );
+        if( fpToClose )
+            VSIFCloseL( fpToClose );
         return FALSE;
     }
 
-    /* Ignore GeoRSS documents. They will be recognized by the GeoRSS driver */
-    if( strstr(szPtr, "<rss") != NULL && strstr(szPtr, "xmlns:georss") != NULL )
-    {
-        VSIFCloseL( fp );
-        return FALSE;
-    }
-
-    /* Ignore OGR WFS xml description files */
-    if( strstr(szPtr, "<OGRWFSDataSource>") != NULL )
-    {
-        VSIFCloseL( fp );
-        return FALSE;
-    }
+    /* Now we definitely own the file descriptor */
+    if( fp == poOpenInfo->fpL )
+        poOpenInfo->fpL = NULL;
 
     /* Small optimization: if we parse a <wfs:FeatureCollection>  and */
     /* that numberOfFeatures is set, we can use it to set the FeatureCount */
@@ -409,7 +457,7 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
             char ch = pszNumberOfFeatures[0];
             if ((ch == '\'' || ch == '"') && strchr(pszNumberOfFeatures + 1, ch) != NULL)
             {
-                nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
+                nNumberOfFeatures = CPLAtoGIntBig(pszNumberOfFeatures + 1);
             }
         }
         else if ((pszNumberOfFeatures = strstr(szPtr, "numberReturned=")) != NULL) /* WFS 2.0.0 */
@@ -421,7 +469,7 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
                 /* 'unknown' might be a valid value in a corrected version of WFS 2.0 */
                 /* but it will also evaluate to 0, that is considered as unknown, so nothing */
                 /* particular to do */
-                nNumberOfFeatures = atoi(pszNumberOfFeatures + 1);
+                nNumberOfFeatures = CPLAtoGIntBig(pszNumberOfFeatures + 1);
             }
         }
     }
@@ -466,9 +514,16 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
     if (pszSchemaLocation)
         pszSchemaLocation += strlen("schemaLocation=");
 
-    if (bIsWFS && EQUALN(pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")))
+    if (strncmp(pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")) == 0)
+        bCheckAuxFile = FALSE;
+    else if (strncmp(pszFilename, "/vsicurl/", strlen("/vsicurl/")) == 0 &&
+             (strstr(pszFilename, "?SERVICE=") || strstr(pszFilename, "&SERVICE=")) )
         bCheckAuxFile = FALSE;
 
+    int bIsWFSJointLayer = bIsWFS && strstr(szPtr, "<wfs:Tuple>");
+    if( bIsWFSJointLayer )
+        bExposeGMLId = FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      We assume now that it is GML.  Instantiate a GMLReader on it.   */
 /* -------------------------------------------------------------------- */
@@ -534,12 +589,13 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
     }
 
     poReader->SetSourceFile( pszFilename );
+    ((GMLReader*)poReader)->SetIsWFSJointLayer(bIsWFSJointLayer);
 
 /* -------------------------------------------------------------------- */
-/*      Find <gml:boundedBy>                                            */
+/*      Find <gml:description>, <gml:name> and <gml:boundedBy>          */
 /* -------------------------------------------------------------------- */
 
-    FindAndParseBoundedBy(fp);
+    FindAndParseTopElements(fp);
 
     if( szSRSName[0] != '\0' )
         poReader->SetGlobalSRSName(szSRSName);
@@ -753,7 +809,9 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
                                 CPLSPrintf("xmlns:%s", oNamespace.osPrefix.c_str());
                     const char* pszURIToFind =
                                 CPLSPrintf("\"%s\"", oNamespace.osURI.c_str());
-                    if( osHeader.ifind(pszNSToFind) != std::string::npos &&
+                    /* Case sensitive comparison since below test that also */
+                    /* uses the namespace prefix is case sensitive */
+                    if( osHeader.find(pszNSToFind) != std::string::npos &&
                         strstr(szHeader, pszURIToFind) != NULL )
                     {
                         if( oNamespace.bUseGlobalSRSName )
@@ -879,6 +937,7 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
                                     CPLHTTPDestroyResult(psResult);
                                 }
                             }
+                            break;
                         }
                     }
                 }
@@ -892,7 +951,26 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
         if( bHasFoundXSD )
         {
             std::vector<GMLFeatureClass*> aosClasses;
-            bHaveSchema = GMLParseXSD( osXSDFilename, aosClasses );
+            int bFullyUnderstood = FALSE;
+            bHaveSchema = GMLParseXSD( osXSDFilename, aosClasses, bFullyUnderstood );
+            
+            if( bHaveSchema && !bFullyUnderstood && bIsWFSJointLayer )
+            {
+                CPLDebug("GML", "Schema found, but only partially understood. Cannot be used in a WFS join context");
+
+                std::vector<GMLFeatureClass*>::const_iterator iter = aosClasses.begin();
+                std::vector<GMLFeatureClass*>::const_iterator eiter = aosClasses.end();
+                while (iter != eiter)
+                {
+                    GMLFeatureClass* poClass = *iter;
+
+                    delete poClass;
+                    iter ++;
+                }
+                aosClasses.resize(0);
+                bHaveSchema = FALSE;
+            }
+
             if( bHaveSchema )
             {
                 CPLDebug("GML", "Using %s", osXSDFilename.c_str());
@@ -922,7 +1000,7 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
                     if (bHas3D && poClass->GetGeometryPropertyCount() == 1)
                     {
                         poClass->GetGeometryProperty(0)->SetType(
-                            poClass->GetGeometryProperty(0)->GetType() | wkb25DBit);
+                            wkbSetZ((OGRwkbGeometryType)poClass->GetGeometryProperty(0)->GetType()));
                     }
 
                     int bAddClass = TRUE;
@@ -977,6 +1055,11 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
 
         if (bHaveSchema && bIsWFS)
         {
+            if( bIsWFSJointLayer )
+            {
+                BuildJointClassFromXSD();
+            }
+
             /* For WFS, we can assume sequential layers */
             if (poReader->GetClassCount() > 1 && pszReadMode == NULL &&
                 !bHasFeatureProperties)
@@ -998,18 +1081,28 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
 /*      will have mechanisms for remembering the schema and related     */
 /*      information.                                                    */
 /* -------------------------------------------------------------------- */
-    if( !bHaveSchema )
+    if( !bHaveSchema ||
+        CSLFetchBoolean(poOpenInfo->papszOpenOptions, "FORCE_SRS_DETECTION", FALSE) )
     {
-        if( !poReader->PrescanForSchema( TRUE, bAnalyzeSRSPerFeature ) )
+        int bOnlyDetectSRS = bHaveSchema;
+        if( !poReader->PrescanForSchema( TRUE, bAnalyzeSRSPerFeature,
+                                         bOnlyDetectSRS ) )
         {
             // we assume an errors have been reported.
             return FALSE;
         }
-
-        if( bHasFoundXSD )
+        if( !bHaveSchema )
         {
-            CPLDebug("GML", "Generating %s file, ignoring %s",
-                     osGFSFilename.c_str(), osXSDFilename.c_str());
+            if( bIsWFSJointLayer && poReader->GetClassCount() == 1 )
+            {
+                BuildJointClassFromScannedSchema();
+            }
+
+            if( bHasFoundXSD )
+            {
+                CPLDebug("GML", "Generating %s file, ignoring %s",
+                        osGFSFilename.c_str(), osXSDFilename.c_str());
+            }
         }
     }
 
@@ -1059,7 +1152,7 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
     if (poReader->GetClassCount() == 1 && nNumberOfFeatures != 0)
     {
         GMLFeatureClass *poClass = poReader->GetClass(0);
-        int nFeatureCount = poClass->GetFeatureCount();
+        GIntBig nFeatureCount = poClass->GetFeatureCount();
         if (nFeatureCount < 0)
         {
             poClass->SetFeatureCount(nNumberOfFeatures);
@@ -1085,6 +1178,161 @@ int OGRGMLDataSource::Open( const char * pszNameIn )
 }
 
 /************************************************************************/
+/*                          BuildJointClassFromXSD()                    */
+/************************************************************************/
+
+void OGRGMLDataSource::BuildJointClassFromXSD()
+{
+    CPLString osJointClassName = "join";
+    for(int i=0;i<poReader->GetClassCount();i++)
+    {
+        osJointClassName += "_";
+        osJointClassName += poReader->GetClass(i)->GetName();
+    }
+    GMLFeatureClass* poJointClass = new GMLFeatureClass(osJointClassName);
+    poJointClass->SetElementName("Tuple");
+    for(int i=0;i<poReader->GetClassCount();i++)
+    {
+        GMLFeatureClass* poClass = poReader->GetClass(i);
+
+        CPLString osPropertyName;
+        osPropertyName.Printf("%s.%s", poClass->GetName(), "gml_id");
+        GMLPropertyDefn* poNewProperty = new GMLPropertyDefn( osPropertyName );
+        CPLString osSrcElement;
+            osSrcElement.Printf("member|%s at id",
+                                poClass->GetName());
+        poNewProperty->SetSrcElement(osSrcElement);
+        poNewProperty->SetType(GMLPT_String);
+        poJointClass->AddProperty(poNewProperty);
+
+        int iField;
+        for( iField = 0; iField < poClass->GetPropertyCount(); iField++ )
+        {
+            GMLPropertyDefn *poProperty = poClass->GetProperty( iField );
+            CPLString osPropertyName;
+            osPropertyName.Printf("%s.%s", poClass->GetName(), poProperty->GetName());
+            GMLPropertyDefn* poNewProperty = new GMLPropertyDefn( osPropertyName );
+
+            poNewProperty->SetType(poProperty->GetType());
+            CPLString osSrcElement;
+            osSrcElement.Printf("member|%s|%s",
+                                poClass->GetName(),
+                                poProperty->GetSrcElement());
+            poNewProperty->SetSrcElement(osSrcElement);
+            poNewProperty->SetWidth(poProperty->GetWidth());
+            poNewProperty->SetPrecision(poProperty->GetPrecision());
+            poNewProperty->SetNullable(poProperty->IsNullable());
+
+            poJointClass->AddProperty(poNewProperty);
+        }
+        for( iField = 0; iField < poClass->GetGeometryPropertyCount(); iField++ )
+        {
+            GMLGeometryPropertyDefn *poProperty = poClass->GetGeometryProperty( iField );
+            CPLString osPropertyName;
+            osPropertyName.Printf("%s.%s", poClass->GetName(), poProperty->GetName());
+            CPLString osSrcElement;
+            osSrcElement.Printf("member|%s|%s",
+                                poClass->GetName(),
+                                poProperty->GetSrcElement());
+            GMLGeometryPropertyDefn* poNewProperty =
+                new GMLGeometryPropertyDefn( osPropertyName, osSrcElement,
+                        poProperty->GetType(), -1, poProperty->IsNullable() );
+            poJointClass->AddGeometryProperty(poNewProperty);
+        }
+    }
+    poJointClass->SetSchemaLocked(TRUE);
+
+    poReader->ClearClasses();
+    poReader->AddClass( poJointClass );
+}
+
+/************************************************************************/
+/*                   BuildJointClassFromScannedSchema()                 */
+/************************************************************************/
+
+void OGRGMLDataSource::BuildJointClassFromScannedSchema()
+{
+    /* Make sure that all properties of a same base feature type are */
+    /* consecutive. If not, reorder */
+    std::vector< std::vector<GMLPropertyDefn*> > aapoProps;
+    GMLFeatureClass *poClass = poReader->GetClass(0);
+    CPLString osJointClassName = "join";
+
+    int iField, iSubClass;
+    for( iField = 0; iField < poClass->GetPropertyCount(); iField ++ )
+    {
+        GMLPropertyDefn* poProp = poClass->GetProperty(iField);
+        CPLString osPrefix(poProp->GetName());
+        size_t iPos = osPrefix.find('.');
+        if( iPos != std::string::npos )
+            osPrefix.resize(iPos);
+        for( iSubClass = 0; iSubClass < (int)aapoProps.size(); iSubClass ++ )
+        {
+            CPLString osPrefixClass(aapoProps[iSubClass][0]->GetName());
+            size_t iPos = osPrefixClass.find('.');
+            if( iPos != std::string::npos )
+                osPrefixClass.resize(iPos);
+            if( osPrefix == osPrefixClass )
+                break;
+        }
+        if( iSubClass == (int)aapoProps.size() )
+        {
+            osJointClassName += "_";
+            osJointClassName += osPrefix;
+            aapoProps.push_back( std::vector<GMLPropertyDefn*>() );
+        }
+        aapoProps[iSubClass].push_back(poProp);
+    }
+    poClass->SetElementName(poClass->GetName());
+    poClass->SetName(osJointClassName);
+
+    poClass->StealProperties();
+    std::vector< std::pair< CPLString, std::vector<GMLGeometryPropertyDefn*> > > aapoGeomProps;
+    for( iSubClass = 0; iSubClass < (int)aapoProps.size(); iSubClass ++ )
+    {
+        CPLString osPrefixClass(aapoProps[iSubClass][0]->GetName());
+        size_t iPos = osPrefixClass.find('.');
+        if( iPos != std::string::npos )
+            osPrefixClass.resize(iPos);
+        aapoGeomProps.push_back( std::pair< CPLString, std::vector<GMLGeometryPropertyDefn*> > 
+                (osPrefixClass, std::vector<GMLGeometryPropertyDefn*>()) );
+        for( int iField = 0; iField < (int)aapoProps[iSubClass].size(); iField ++ )
+        {
+            poClass->AddProperty(aapoProps[iSubClass][iField]);
+        }
+    }
+    aapoProps.resize(0);
+
+    // Reorder geometry fields too
+    for( iField = 0; iField < poClass->GetGeometryPropertyCount(); iField ++ )
+    {
+        GMLGeometryPropertyDefn* poProp = poClass->GetGeometryProperty(iField);
+        CPLString osPrefix(poProp->GetName());
+        size_t iPos = osPrefix.find('.');
+        if( iPos != std::string::npos )
+            osPrefix.resize(iPos);
+        int iSubClass;
+        for( iSubClass = 0; iSubClass < (int)aapoGeomProps.size(); iSubClass ++ )
+        {
+            if( osPrefix == aapoGeomProps[iSubClass].first )
+                break;
+        }
+        if( iSubClass == (int)aapoProps.size() )
+            aapoGeomProps.push_back( std::pair< CPLString, std::vector<GMLGeometryPropertyDefn*> >
+                    (osPrefix, std::vector<GMLGeometryPropertyDefn*>()) );
+        aapoGeomProps[iSubClass].second.push_back(poProp);
+    }
+    poClass->StealGeometryProperties();
+    for( iSubClass = 0; iSubClass < (int)aapoGeomProps.size(); iSubClass ++ )
+    {
+        for( iField = 0; iField < (int)aapoGeomProps[iSubClass].second.size(); iField ++ )
+        {
+            poClass->AddGeometryProperty(aapoGeomProps[iSubClass].second[iField]);
+        }
+    }
+}
+
+/************************************************************************/
 /*                         TranslateGMLSchema()                         */
 /************************************************************************/
 
@@ -1178,11 +1426,13 @@ OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
     if (bExposeGMLId)
     {
         OGRFieldDefn oField( "gml_id", OFTString );
+        oField.SetNullable(FALSE);
         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     }
     else if (bExposeFid)
     {
         OGRFieldDefn oField( "fid", OFTString );
+        oField.SetNullable(FALSE);
         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     }
 
@@ -1196,6 +1446,7 @@ OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
             oField.SetType(wkbUnknown);
         }
         oField.SetSpatialRef(poSRS);
+        oField.SetNullable(poProperty->IsNullable() );
         poLayer->GetLayerDefn()->AddGeomFieldDefn( &oField );
     }
 
@@ -1208,14 +1459,22 @@ OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
             eFType = OFTString;
         else if( poProperty->GetType() == GMLPT_String )
             eFType = OFTString;
-        else if( poProperty->GetType() == GMLPT_Integer )
+        else if( poProperty->GetType() == GMLPT_Integer ||
+                 poProperty->GetType() == GMLPT_Boolean ||
+                 poProperty->GetType() == GMLPT_Short )
             eFType = OFTInteger;
-        else if( poProperty->GetType() == GMLPT_Real )
+        else if( poProperty->GetType() == GMLPT_Integer64 )
+            eFType = OFTInteger64;
+        else if( poProperty->GetType() == GMLPT_Real ||
+                 poProperty->GetType() == GMLPT_Float )
             eFType = OFTReal;
         else if( poProperty->GetType() == GMLPT_StringList )
             eFType = OFTStringList;
-        else if( poProperty->GetType() == GMLPT_IntegerList )
+        else if( poProperty->GetType() == GMLPT_IntegerList ||
+                 poProperty->GetType() == GMLPT_BooleanList )
             eFType = OFTIntegerList;
+        else if( poProperty->GetType() == GMLPT_Integer64List )
+            eFType = OFTInteger64List;
         else if( poProperty->GetType() == GMLPT_RealList )
             eFType = OFTRealList;
         else if( poProperty->GetType() == GMLPT_FeaturePropertyList )
@@ -1230,6 +1489,14 @@ OGRGMLLayer *OGRGMLDataSource::TranslateGMLSchema( GMLFeatureClass *poClass )
             oField.SetWidth( poProperty->GetWidth() );
         if( poProperty->GetPrecision() > 0 )
             oField.SetPrecision( poProperty->GetPrecision() );
+        if( poProperty->GetType() == GMLPT_Boolean ||
+            poProperty->GetType() == GMLPT_BooleanList )
+            oField.SetSubType(OFSTBoolean);
+        else if( poProperty->GetType() == GMLPT_Short) 
+            oField.SetSubType(OFSTInt16);
+        else if( poProperty->GetType() == GMLPT_Float) 
+            oField.SetSubType(OFSTFloat32);
+        oField.SetNullable(poProperty->IsNullable() );
 
         poLayer->GetLayerDefn()->AddFieldDefn( &oField );
     }
@@ -1341,8 +1608,12 @@ int OGRGMLDataSource::Create( const char *pszFilename,
         PrintLine( fpOutput, "<%s:FeatureCollection", pszPrefix );
 
     if (IsGML32Output())
-        PrintLine( fpOutput, "%s",
-                "     gml:id=\"aFeatureCollection\"" );
+    {
+        char* pszGMLId = CPLEscapeString(
+            CSLFetchNameValueDef(papszOptions, "GML_ID", "aFeatureCollection"), -1, CPLES_XML);
+        PrintLine( fpOutput, "     gml:id=\"%s\"", pszGMLId );
+        CPLFree(pszGMLId);
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Write out schema info if provided in creation options.          */
@@ -1385,12 +1656,44 @@ int OGRGMLDataSource::Create( const char *pszFilename,
         PrintLine( fpOutput, "%s",
                     "     xmlns:gml=\"http://www.opengis.net/gml\">" );
 
+    return TRUE;
+}
+
+
+/************************************************************************/
+/*                         WriteTopElements()                           */
+/************************************************************************/
+
+void OGRGMLDataSource::WriteTopElements()
+{
+    const char* pszDescription = CSLFetchNameValueDef(papszCreateOptions,
+        "DESCRIPTION", GetMetadataItem("DESCRIPTION"));
+    if( pszDescription != NULL )
+    {
+        if (bWriteSpaceIndentation)
+            VSIFPrintfL( fpOutput, "  ");
+        char* pszTmp = CPLEscapeString(pszDescription, -1, CPLES_XML);
+        PrintLine( fpOutput, "<gml:description>%s</gml:description>", pszTmp );
+        CPLFree(pszTmp);
+    }
+
+    const char* pszName = CSLFetchNameValueDef(papszCreateOptions,
+        "NAME", GetMetadataItem("NAME"));
+    if( pszName != NULL )
+    {
+        if (bWriteSpaceIndentation)
+            VSIFPrintfL( fpOutput, "  ");
+        char* pszTmp = CPLEscapeString(pszName, -1, CPLES_XML);
+        PrintLine( fpOutput, "<gml:name>%s</gml:name>", pszTmp );
+        CPLFree(pszTmp);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Should we initialize an area to place the boundedBy element?    */
 /*      We will need to seek back to fill it in.                        */
 /* -------------------------------------------------------------------- */
     nBoundedByLocation = -1;
-    if( CSLFetchBoolean( papszOptions, "BOUNDEDBY", TRUE ))
+    if( CSLFetchBoolean( papszCreateOptions , "BOUNDEDBY", TRUE ))
     {
         if (!bFpOutputIsNonSeekable )
         {
@@ -1409,19 +1712,17 @@ int OGRGMLDataSource::Create( const char *pszFilename,
                 PrintLine( fpOutput, "<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>" );
         }
     }
-
-    return TRUE;
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRGMLDataSource::CreateLayer( const char * pszLayerName,
-                               OGRSpatialReference *poSRS,
-                               OGRwkbGeometryType eType,
-                               CPL_UNUSED char ** papszOptions )
+OGRGMLDataSource::ICreateLayer( const char * pszLayerName,
+                                OGRSpatialReference *poSRS,
+                                OGRwkbGeometryType eType,
+                                CPL_UNUSED char ** papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Verify we are in update mode.                                   */
@@ -1454,6 +1755,7 @@ OGRGMLDataSource::CreateLayer( const char * pszLayerName,
 /* -------------------------------------------------------------------- */
     if (nLayers == 0)
     {
+        WriteTopElements();
         if (poSRS)
             poWriteGlobalSRS = poSRS->Clone();
         bWriteGlobalSRS = TRUE;
@@ -1520,6 +1822,8 @@ int OGRGMLDataSource::TestCapability( const char * pszCap )
         return TRUE;
     else if( EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return bIsOutputGML3;
     else
         return FALSE;
 }
@@ -1622,6 +1926,7 @@ void OGRGMLDataSource::InsertHeader()
             OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn(iField);
 
             if( poFieldDefn->GetType() == OFTIntegerList ||
+                poFieldDefn->GetType() == OFTInteger64List ||
                 poFieldDefn->GetType() == OFTRealList ||
                 poFieldDefn->GetType() == OFTStringList )
             {
@@ -1843,20 +2148,39 @@ void OGRGMLDataSource::InsertHeader()
     /*      Define the geometry attribute.                                  */
     /* -------------------------------------------------------------------- */
             const char* pszGeometryTypeName = "GeometryPropertyType";
-            switch(wkbFlatten(poFieldDefn->GetType()))
+            const char* pszComment = "";
+            OGRwkbGeometryType eGType = wkbFlatten(poFieldDefn->GetType());
+            switch(eGType)
             {
                 case wkbPoint:
                     pszGeometryTypeName = "PointPropertyType";
                     break;
                 case wkbLineString:
+                case wkbCircularString:
+                case wkbCompoundCurve:
                     if (IsGML3Output())
+                    {
+                        if( eGType == wkbLineString )
+                            pszComment = " <!-- restricted to LineString -->";
+                        else if( eGType == wkbCircularString )
+                            pszComment = " <!-- contains CircularString -->";
+                        else if( eGType == wkbCompoundCurve )
+                            pszComment = " <!-- contains CompoundCurve -->";
                         pszGeometryTypeName = "CurvePropertyType";
+                    }
                     else
                         pszGeometryTypeName = "LineStringPropertyType";
                     break;
                 case wkbPolygon:
+                case wkbCurvePolygon:
                     if (IsGML3Output())
+                    {
+                        if( eGType == wkbPolygon )
+                            pszComment = " <!-- restricted to Polygon -->";
+                        else if( eGType == wkbCurvePolygon )
+                            pszComment = " <!-- contains CurvePolygon -->";
                         pszGeometryTypeName = "SurfacePropertyType";
+                    }
                     else
                         pszGeometryTypeName = "PolygonPropertyType";
                     break;
@@ -1864,14 +2188,28 @@ void OGRGMLDataSource::InsertHeader()
                     pszGeometryTypeName = "MultiPointPropertyType";
                     break;
                 case wkbMultiLineString:
+                case wkbMultiCurve:
                     if (IsGML3Output())
+                    {
+                        if( eGType == wkbMultiLineString )
+                            pszComment = " <!-- restricted to MultiLineString -->";
+                        else if( eGType == wkbMultiCurve )
+                            pszComment = " <!-- contains non-linear MultiCurve -->";
                         pszGeometryTypeName = "MultiCurvePropertyType";
+                    }
                     else
                         pszGeometryTypeName = "MultiLineStringPropertyType";
                     break;
                 case wkbMultiPolygon:
+                case wkbMultiSurface:
                     if (IsGML3Output())
+                    {
+                        if( eGType == wkbMultiPolygon )
+                            pszComment = " <!-- restricted to MultiPolygon -->";
+                        else if( eGType == wkbMultiSurface )
+                            pszComment = " <!-- contains non-linear MultiSurface -->";
                         pszGeometryTypeName = "MultiSurfacePropertyType";
+                    }
                     else
                         pszGeometryTypeName = "MultiPolygonPropertyType";
                     break;
@@ -1882,9 +2220,10 @@ void OGRGMLDataSource::InsertHeader()
                     break;
             }
 
+            int nMinOccurs = poFieldDefn->IsNullable() ? 0 : 1;
             PrintLine( fpSchema,
-                "        <xs:element name=\"%s\" type=\"gml:%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\"/>",
-                       poFieldDefn->GetNameRef(), pszGeometryTypeName );
+                "        <xs:element name=\"%s\" type=\"gml:%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"1\"/>%s",
+                       poFieldDefn->GetNameRef(), pszGeometryTypeName, nMinOccurs, pszComment );
         }
 
 /* -------------------------------------------------------------------- */
@@ -1899,6 +2238,7 @@ void OGRGMLDataSource::InsertHeader()
             else if( !IsGML3Output() && strcmp(poFieldDefn->GetNameRef(), "fid") == 0 )
                 continue;
 
+            int nMinOccurs = poFieldDefn->IsNullable() ? 0 : 1;
             if( poFieldDefn->GetType() == OFTInteger ||
                 poFieldDefn->GetType() == OFTIntegerList  )
             {
@@ -1909,11 +2249,56 @@ void OGRGMLDataSource::InsertHeader()
                 else
                     nWidth = 16;
 
-                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"%s\">",
-                           poFieldDefn->GetNameRef(), poFieldDefn->GetType() == OFTIntegerList ? "unbounded": "1" );
+                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"%s\">",
+                           poFieldDefn->GetNameRef(),
+                           nMinOccurs,
+                           poFieldDefn->GetType() == OFTIntegerList ? "unbounded": "1" );
                 PrintLine( fpSchema, "          <xs:simpleType>");
-                PrintLine( fpSchema, "            <xs:restriction base=\"xs:integer\">");
-                PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
+                if( poFieldDefn->GetSubType() == OFSTBoolean )
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:boolean\">");
+                }
+                else if( poFieldDefn->GetSubType() == OFSTInt16 )
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:short\">");
+                }
+                else
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:integer\">");
+                    PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
+                }
+                PrintLine( fpSchema, "            </xs:restriction>");
+                PrintLine( fpSchema, "          </xs:simpleType>");
+                PrintLine( fpSchema, "        </xs:element>");
+            }
+            else if( poFieldDefn->GetType() == OFTInteger64 ||
+                     poFieldDefn->GetType() == OFTInteger64List  )
+            {
+                int nWidth;
+
+                if( poFieldDefn->GetWidth() > 0 )
+                    nWidth = poFieldDefn->GetWidth();
+                else
+                    nWidth = 16;
+
+                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"%s\">",
+                           poFieldDefn->GetNameRef(),
+                           nMinOccurs,
+                           poFieldDefn->GetType() == OFTInteger64List ? "unbounded": "1" );
+                PrintLine( fpSchema, "          <xs:simpleType>");
+                if( poFieldDefn->GetSubType() == OFSTBoolean )
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:boolean\">");
+                }
+                else if( poFieldDefn->GetSubType() == OFSTInt16 )
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:short\">");
+                }
+                else
+                {
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:long\">");
+                    PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
+                }
                 PrintLine( fpSchema, "            </xs:restriction>");
                 PrintLine( fpSchema, "          </xs:simpleType>");
                 PrintLine( fpSchema, "        </xs:element>");
@@ -1926,10 +2311,15 @@ void OGRGMLDataSource::InsertHeader()
                 nWidth = poFieldDefn->GetWidth();
                 nDecimals = poFieldDefn->GetPrecision();
 
-                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"%s\">",
-                           poFieldDefn->GetNameRef(), poFieldDefn->GetType() == OFTRealList ? "unbounded": "1" );
+                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"%s\">",
+                           poFieldDefn->GetNameRef(),
+                           nMinOccurs,
+                           poFieldDefn->GetType() == OFTRealList ? "unbounded": "1" );
                 PrintLine( fpSchema, "          <xs:simpleType>");
-                PrintLine( fpSchema, "            <xs:restriction base=\"xs:decimal\">");
+                if( poFieldDefn->GetSubType() == OFSTFloat32 )
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:float\">");
+                else
+                    PrintLine( fpSchema, "            <xs:restriction base=\"xs:decimal\">");
                 if (nWidth > 0)
                 {
                     PrintLine( fpSchema, "              <xs:totalDigits value=\"%d\"/>", nWidth);
@@ -1942,8 +2332,10 @@ void OGRGMLDataSource::InsertHeader()
             else if( poFieldDefn->GetType() == OFTString ||
                      poFieldDefn->GetType() == OFTStringList )
             {
-                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"%s\">", 
-                           poFieldDefn->GetNameRef(), poFieldDefn->GetType() == OFTStringList ? "unbounded": "1" );
+                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"%s\">", 
+                           poFieldDefn->GetNameRef(),
+                           nMinOccurs,
+                           poFieldDefn->GetType() == OFTStringList ? "unbounded": "1" );
                 PrintLine( fpSchema, "          <xs:simpleType>");
                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
                 if( poFieldDefn->GetWidth() != 0 )
@@ -1956,7 +2348,9 @@ void OGRGMLDataSource::InsertHeader()
             }
             else if( poFieldDefn->GetType() == OFTDate || poFieldDefn->GetType() == OFTDateTime )
             {
-                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"0\" maxOccurs=\"1\">",  poFieldDefn->GetNameRef());
+                PrintLine( fpSchema, "        <xs:element name=\"%s\" nillable=\"true\" minOccurs=\"%d\" maxOccurs=\"1\">", 
+                           poFieldDefn->GetNameRef(),
+                           nMinOccurs );
                 PrintLine( fpSchema, "          <xs:simpleType>");
                 PrintLine( fpSchema, "            <xs:restriction base=\"xs:string\">");
                 PrintLine( fpSchema, "            </xs:restriction>");
@@ -2173,10 +2567,10 @@ static int ExtractSRSName(const char* pszXML, char* szSRSName,
 }
 
 /************************************************************************/
-/*                         FindAndParseBoundedBy()                      */
+/*                      FindAndParseTopElements()                       */
 /************************************************************************/
 
-void OGRGMLDataSource::FindAndParseBoundedBy(VSILFILE* fp)
+void OGRGMLDataSource::FindAndParseTopElements(VSILFILE* fp)
 {
     /* Build a shortened XML file that contain only the global */
     /* boundedBy element, so as to be able to parse it easily */
@@ -2207,6 +2601,41 @@ void OGRGMLDataSource::FindAndParseBoundedBy(VSILFILE* fp)
         }
     }
 
+    const char* pszDescription = strstr(pszXML, "<gml:description>");
+    if( pszDescription )
+    {
+        pszDescription += strlen("<gml:description>");
+        const char* pszEndDescription = strstr(pszDescription,
+                                               "</gml:description>");
+        if( pszEndDescription )
+        {
+            CPLString osTmp(pszDescription);
+            osTmp.resize(pszEndDescription-pszDescription);
+            char* pszTmp = CPLUnescapeString(osTmp, NULL, CPLES_XML);
+            if( pszTmp )
+                SetMetadataItem("DESCRIPTION", pszTmp);
+            CPLFree(pszTmp);
+        }
+    }
+
+    const char* pszName = strstr(pszXML, "<gml:name");
+    if( pszName )
+        pszName = strchr(pszName, '>');
+    if( pszName )
+    {
+        pszName ++;
+        const char* pszEndName = strstr(pszName, "</gml:name>");
+        if( pszEndName )
+        {
+            CPLString osTmp(pszName);
+            osTmp.resize(pszEndName-pszName);
+            char* pszTmp = CPLUnescapeString(osTmp, NULL, CPLES_XML);
+            if( pszTmp )
+                SetMetadataItem("NAME", pszTmp);
+            CPLFree(pszTmp);
+        }
+    }
+
     char* pszEndBoundedBy = strstr(pszXML, "</wfs:boundedBy>");
     int bWFSBoundedBy = FALSE;
     if (pszEndBoundedBy != NULL)
@@ -2349,3 +2778,12 @@ int OGRGMLDataSource::WriteFeatureBoundedBy()
     return CSLTestBoolean(CSLFetchNameValueDef(
                     papszCreateOptions, "WRITE_FEATURE_BOUNDED_BY", "TRUE"));
 }
+
+/************************************************************************/
+/*                          GetSRSDimensionLoc()                        */
+/************************************************************************/
+
+const char* OGRGMLDataSource::GetSRSDimensionLoc()
+{
+    return CSLFetchNameValue(papszCreateOptions, "SRSDIMENSION_LOC");
+}
diff --git a/ogr/ogrsf_frmts/gml/ogrgmldriver.cpp b/ogr/ogrsf_frmts/gml/ogrgmldriver.cpp
index 81309d3..34880ae 100644
--- a/ogr/ogrsf_frmts/gml/ogrgmldriver.cpp
+++ b/ogr/ogrsf_frmts/gml/ogrgmldriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgmldriver.cpp 26591 2013-11-07 20:41:38Z rouault $
+ * $Id: ogrgmldriver.cpp 29051 2015-04-29 17:18:37Z rouault $
  *
  * Project:  OGR
  * Purpose:  OGRGMLDriver implementation
@@ -32,14 +32,13 @@
 #include "cpl_multiproc.h"
 #include "gmlreaderp.h"
 
-CPL_CVSID("$Id: ogrgmldriver.cpp 26591 2013-11-07 20:41:38Z rouault $");
+CPL_CVSID("$Id: ogrgmldriver.cpp 29051 2015-04-29 17:18:37Z rouault $");
 
 /************************************************************************/
-/*                          ~OGRGMLDriver()                           */
+/*                        OGRGMLDriverUnload()                          */
 /************************************************************************/
 
-OGRGMLDriver::~OGRGMLDriver()
-
+static void OGRGMLDriverUnload(CPL_UNUSED GDALDriver* poDriver)
 {
     if( GMLReader::hMutex != NULL )
         CPLDestroyMutex( GMLReader::hMutex );
@@ -47,31 +46,68 @@ OGRGMLDriver::~OGRGMLDriver()
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                         OGRGMLDriverIdentify()                       */
 /************************************************************************/
 
-const char *OGRGMLDriver::GetName()
+static int OGRGMLDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "GML";
+    if( poOpenInfo->fpL == NULL )
+    {
+        if( strstr(poOpenInfo->pszFilename, "xsd=") != NULL )
+            return -1; /* must be later checked */
+        return FALSE;
+    }
+    /* Might be a OS-Mastermap gzipped GML, so let be nice and try to open */
+    /* it transparently with /vsigzip/ */
+    else
+    if ( poOpenInfo->pabyHeader[0] == 0x1f && poOpenInfo->pabyHeader[1] == 0x8b &&
+         EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "gz") &&
+         strncmp(poOpenInfo->pszFilename, "/vsigzip/", strlen("/vsigzip/")) != 0 )
+    {
+        return -1; /* must be later checked */
+    }
+    else
+    {
+        const char* szPtr = (const char*)poOpenInfo->pabyHeader;
+
+        if( ( (unsigned char)szPtr[0] == 0xEF )
+            && ( (unsigned char)szPtr[1] == 0xBB )
+            && ( (unsigned char)szPtr[2] == 0xBF) )
+        {
+            szPtr += 3;
+        }
+/* -------------------------------------------------------------------- */
+/*      Here, we expect the opening chevrons of GML tree root element   */
+/* -------------------------------------------------------------------- */
+        if( szPtr[0] != '<' )
+            return FALSE;
+
+        if( !poOpenInfo->TryToIngest(4096) )
+            return FALSE;
+
+        return OGRGMLDataSource::CheckHeader((const char*)poOpenInfo->pabyHeader);
+    }
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGMLDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRGMLDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRGMLDataSource    *poDS;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update )
+        return NULL;
+
+    if( OGRGMLDriverIdentify( poOpenInfo ) == FALSE )
         return NULL;
 
     poDS = new OGRGMLDataSource();
 
-    if( !poDS->Open( pszFilename ) )
+    if( !poDS->Open(  poOpenInfo ) )
     {
         delete poDS;
         return NULL;
@@ -81,12 +117,15 @@ OGRDataSource *OGRGMLDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                             Create()                                 */
 /************************************************************************/
 
-OGRDataSource *OGRGMLDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRGMLDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     OGRGMLDataSource    *poDS = new OGRGMLDataSource();
 
@@ -100,25 +139,76 @@ OGRDataSource *OGRGMLDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGMLDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRGML()                           */
 /************************************************************************/
 
 void RegisterOGRGML()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGMLDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "GML" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "GML" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Geography Markup Language (GML)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gml" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "gml xml" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_gml.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='XSD' type='string' description='Name of the related application schema file (.xsd).'/>"
+"  <Option name='FORCE_SRS_DETECTION' type='boolean' description='Force a full scan to detect the SRS of layers.' default='NO'/>"
+"</OpenOptionList>" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='XSISCHEMAURI' type='string' description='URI to be inserted as the schema location.'/>"
+"  <Option name='XSISCHEMA' type='string-select' description='where to write a .xsd application schema. INTERNAL should not normally be used' default='EXTERNAL'>"
+"    <Value>EXTERNAL</Value>"
+"    <Value>INTERNAL</Value>"
+"    <Value>OFF</Value>"
+"  </Option>"
+"  <Option name='PREFIX' type='string' description='Prefix for the application target namespace.' default='ogr'/>"
+"  <Option name='STRIP_PREFIX' type='boolean' description='Whether to avoid writing the prefix of the application target namespace in the GML file.' default='NO'/>"
+"  <Option name='TARGET_NAMESPACE' type='string' description='Application target namespace.' default='http://ogr.maptools.org/'/>"
+"  <Option name='FORMAT' type='string-select' description='Version of GML to use' default='GML2'>"
+"    <Value>GML2</Value>"
+"    <Value>GML3</Value>"
+"    <Value>GML3.2</Value>"
+"    <Value>GML3Deegree</Value>"
+"  </Option>"
+"  <Option name='GML3_LONGSRS' type='boolean' description='Whether to write SRS with \"urn:ogc:def:crs:EPSG::\" prefix with GML3* versions' default='YES'/>"
+"  <Option name='WRITE_FEATURE_BOUNDED_BY' type='boolean' description='Whether to write <gml:boundedBy> element for each feature with GML3* versions' default='YES'/>"
+"  <Option name='SPACE_INDENTATION' type='boolean' description='Whether to indentate the output for readability' default='YES'/>"
+"  <Option name='SRSDIMENSION_LOC' type='string-select' description='(only valid for FORMAT=GML3xx) Location where to put srsDimension attribute' default='POSLIST'>"
+"    <Value>POSLIST</Value>"
+"    <Value>GEOMETRY</Value>"
+"    <Value>GEOMETRY,POSLIST</Value>"
+"  </Option>"
+"  <Option name='GML_ID' type='string' description='Value of feature collection gml:id (GML 3.2 only)' default='aFeatureCollection'/>"
+"  <Option name='NAME' type='string' description='Content of GML name element'/>"
+"  <Option name='DESCRIPTION' type='string' description='Content of GML description element'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime IntegerList Integer64List RealList StringList" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->pfnOpen = OGRGMLDriverOpen;
+        poDriver->pfnIdentify = OGRGMLDriverIdentify;
+        poDriver->pfnCreate = OGRGMLDriverCreate;
+        poDriver->pfnUnloadDriver = OGRGMLDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/gml/ogrgmllayer.cpp b/ogr/ogrsf_frmts/gml/ogrgmllayer.cpp
index f631813..e757f61 100644
--- a/ogr/ogrsf_frmts/gml/ogrgmllayer.cpp
+++ b/ogr/ogrsf_frmts/gml/ogrgmllayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgmllayer.cpp 27146 2014-04-09 17:01:52Z martinl $
+ * $Id: ogrgmllayer.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRGMLLayer class.
@@ -36,7 +36,7 @@
 #include "ogr_p.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: ogrgmllayer.cpp 27146 2014-04-09 17:01:52Z martinl $");
+CPL_CVSID("$Id: ogrgmllayer.cpp 28481 2015-02-13 17:11:15Z rouault $");
 
 /************************************************************************/
 /*                           OGRGMLLayer()                              */
@@ -59,6 +59,7 @@ OGRGMLLayer::OGRGMLLayer( const char * pszName,
       poFeatureDefn = new OGRFeatureDefn( pszName+4 );
     else
       poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone );
 
@@ -137,40 +138,6 @@ void OGRGMLLayer::ResetReading()
 }
 
 /************************************************************************/
-/*                     ConvertGeomToMultiIfNecessary()                  */
-/************************************************************************/
-
-OGRGeometry* OGRGMLLayer::ConvertGeomToMultiIfNecessary(OGRGeometry* poGeom)
-{
-    OGRwkbGeometryType eType = poGeom->getGeometryType();
-    OGRwkbGeometryType eLayerType = GetGeomType();
-    OGRGeometryCollection* poNewGeom = NULL;
-    if (eType == wkbPoint && eLayerType == wkbMultiPoint)
-    {
-        poNewGeom = new OGRMultiPoint();
-    }
-    else if (eType == wkbLineString && eLayerType == wkbMultiLineString)
-    {
-        poNewGeom = new OGRMultiLineString();
-    }
-    else if (eType == wkbPolygon && eLayerType == wkbMultiPolygon)
-    {
-        poNewGeom = new OGRMultiPolygon();
-    }
-
-    if( poNewGeom != NULL )
-    {
-        OGRSpatialReference* poGeomSRS = poGeom->getSpatialReference();
-        poNewGeom->addGeometryDirectly(poGeom);
-        if( poGeomSRS != NULL )
-            poNewGeom->assignSpatialReference(poGeomSRS);
-        poGeom = poNewGeom;
-    }
-
-    return poGeom;
-}
-
-/************************************************************************/
 /*                           GetNextFeature()                           */
 /************************************************************************/
 
@@ -245,7 +212,7 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
 /*       the poDS then the fids from the poDS are ignored and are       */
 /*       assigned serially thereafter                                   */
 /* -------------------------------------------------------------------- */
-        int nFID = -1;
+        GIntBig nFID = -1;
         const char * pszGML_FID = poGMLFeature->GetFID();
         if( bInvalidFIDFound )
         {
@@ -261,17 +228,17 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
             int j = 0;
             i = strlen( pszGML_FID )-1;
             while( i >= 0 && pszGML_FID[i] >= '0'
-                          && pszGML_FID[i] <= '9' && j<8)
+                          && pszGML_FID[i] <= '9' && j<20)
                 i--, j++;
             /* i points the last character of the fid */
-            if( i >= 0 && j < 8 && pszFIDPrefix == NULL)
+            if( i >= 0 && j < 20 && pszFIDPrefix == NULL)
             {
                 pszFIDPrefix = (char *) CPLMalloc(i+2);
                 pszFIDPrefix[i+1] = '\0';
                 strncpy(pszFIDPrefix, pszGML_FID, i+1);
             }
             /* pszFIDPrefix now contains the prefix or NULL if no prefix is found */
-            if( j < 8 && sscanf(pszGML_FID+i+1, "%d", &nFID)==1)
+            if( j < 20 && sscanf(pszGML_FID+i+1, CPL_FRMT_GIB, &nFID)==1)
             {
                 if( iNextGMLId <= nFID )
                     iNextGMLId = nFID + 1;
@@ -289,8 +256,8 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
             int nLenPrefix = strlen(pszFIDPrefix_notnull);
 
             if(  strncmp(pszGML_FID, pszFIDPrefix_notnull, nLenPrefix) == 0 &&
-                 strlen(pszGML_FID+nLenPrefix) <= 9 &&
-                 sscanf(pszGML_FID+nLenPrefix, "%d", &nFID) == 1 )
+                 strlen(pszGML_FID+nLenPrefix) < 20 &&
+                 sscanf(pszGML_FID+nLenPrefix, CPL_FRMT_GIB, &nFID) == 1 )
             { /* fid with the prefix. Using its numerical part */
                 if( iNextGMLId < nFID )
                     iNextGMLId = nFID + 1;
@@ -330,10 +297,11 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
                                                   hCacheSRS,
                                                   bFaceHoleNegative );
 
-                    /* Force single geometry to multigeometry if needed to match layer geometry type */
+                    /* Do geometry type changes if needed to match layer geometry type */
                     if (poGeom != NULL)
                     {
-                        papoGeometries[i] = ConvertGeomToMultiIfNecessary(poGeom);
+                        papoGeometries[i] = OGRGeometryFactory::forceTo(poGeom,
+                                    poFeatureDefn->GetGeomFieldDefn(i)->GetType());
                         poGeom = NULL;
                     }
                     else
@@ -377,10 +345,10 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
                                                   hCacheSRS,
                                                   bFaceHoleNegative );
 
-            /* Force single geometry to multigeometry if needed to match layer geometry type */
+            /* Do geometry type changes if needed to match layer geometry type */
             if (poGeom != NULL)
             {
-                poGeom = ConvertGeomToMultiIfNecessary(poGeom);
+                poGeom = OGRGeometryFactory::forceTo(poGeom, GetGeomType());
             }
             else
             // We assume the createFromGML() function would have already
@@ -442,6 +410,19 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
               }
               break;
 
+              case GMLPT_Integer64List:
+              {
+                  int nCount = psGMLProperty->nSubProperties;
+                  GIntBig *panIntList = (GIntBig *) CPLMalloc(sizeof(GIntBig) * nCount );
+
+                  for( i = 0; i < nCount; i++ )
+                      panIntList[i] = CPLAtoGIntBig(psGMLProperty->papszSubProperties[i]);
+
+                  poOGRFeature->SetField( iDstField, nCount, panIntList );
+                  CPLFree( panIntList );
+              }
+              break;
+
               case GMLPT_RealList:
               {
                   int nCount = psGMLProperty->nSubProperties;
@@ -462,6 +443,39 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
               }
               break;
 
+              case GMLPT_Boolean:
+              {
+                  if( strcmp(psGMLProperty->papszSubProperties[0], "true") == 0 ||
+                      strcmp(psGMLProperty->papszSubProperties[0], "1") == 0 )
+                  {
+                      poOGRFeature->SetField( iDstField, 1);
+                  }
+                  else if( strcmp(psGMLProperty->papszSubProperties[0], "false") == 0 ||
+                           strcmp(psGMLProperty->papszSubProperties[0], "0") == 0 )
+                  {
+                      poOGRFeature->SetField( iDstField, 0);
+                  }
+                  else
+                      poOGRFeature->SetField( iDstField, psGMLProperty->papszSubProperties[0] );
+                  break;
+              }
+
+              case GMLPT_BooleanList:
+              {
+                  int nCount = psGMLProperty->nSubProperties;
+                  int *panIntList = (int *) CPLMalloc(sizeof(int) * nCount );
+
+                  for( i = 0; i < nCount; i++ )
+                  {
+                      panIntList[i] = ( strcmp(psGMLProperty->papszSubProperties[i], "true") == 0 ||
+                                        strcmp(psGMLProperty->papszSubProperties[i], "1") == 0 );
+                  }
+
+                  poOGRFeature->SetField( iDstField, nCount, panIntList );
+                  CPLFree( panIntList );
+                  break;
+              }
+
               default:
                 poOGRFeature->SetField( iDstField, psGMLProperty->papszSubProperties[0] );
                 break;
@@ -521,7 +535,7 @@ OGRFeature *OGRGMLLayer::GetNextFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRGMLLayer::GetFeatureCount( int bForce )
+GIntBig OGRGMLLayer::GetFeatureCount( int bForce )
 
 {
     if( poFClass == NULL )
@@ -533,7 +547,7 @@ int OGRGMLLayer::GetFeatureCount( int bForce )
     {
         /* If the schema is read from a .xsd file, we haven't read */
         /* the feature count, so compute it now */
-        int nFeatureCount = poFClass->GetFeatureCount();
+        GIntBig nFeatureCount = poFClass->GetFeatureCount();
         if (nFeatureCount < 0)
         {
             nFeatureCount = OGRLayer::GetFeatureCount(bForce);
@@ -605,10 +619,10 @@ static void GMLWriteField(OGRGMLDataSource* poDS,
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGMLLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     int bIsGML3Output = poDS->IsGML3Output();
@@ -620,6 +634,10 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
     if( !bWriter )
         return OGRERR_FAILURE;
 
+    poFeature->FillUnsetWithDefault(TRUE, NULL);
+    if( !poFeature->Validate( OGR_F_VAL_ALL & ~OGR_F_VAL_GEOM_TYPE & ~OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT, TRUE ) )
+        return OGRERR_FAILURE;
+
     if (bWriteSpaceIndentation)
         VSIFPrintfL(fp, "  ");
     if (bIsGML3Output)
@@ -670,7 +688,7 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
                              poFeatureDefn->GetName(),
                              poFeature->GetFieldAsString(nGMLIdIndex) );
         else
-            poDS->PrintLine( fp, "%s gml:id=\"%s.%ld\">",
+            poDS->PrintLine( fp, "%s gml:id=\"%s." CPL_FRMT_GIB "\">",
                              poFeatureDefn->GetName(),
                              poFeatureDefn->GetName(),
                              poFeature->GetFID() );
@@ -680,7 +698,7 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
         nGMLIdIndex = poFeatureDefn->GetFieldIndex("fid");
         if (bUseOldFIDFormat)
         {
-            poDS->PrintLine( fp, "%s fid=\"F%ld\">",
+            poDS->PrintLine( fp, "%s fid=\"F" CPL_FRMT_GIB "\">",
                              poFeatureDefn->GetName(),
                              poFeature->GetFID() );
         }
@@ -692,7 +710,7 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
         }
         else
         {
-            poDS->PrintLine( fp, "%s fid=\"%s.%ld\">",
+            poDS->PrintLine( fp, "%s fid=\"%s." CPL_FRMT_GIB "\">",
                              poFeatureDefn->GetName(),
                              poFeatureDefn->GetName(),
                              poFeature->GetFID() );
@@ -747,20 +765,31 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
             char** papszOptions = (bIsGML3Output) ? CSLAddString(NULL, "FORMAT=GML3") : NULL;
             if (bIsGML3Output && !poDS->IsLongSRSRequired())
                 papszOptions = CSLAddString(papszOptions, "GML3_LONGSRS=NO");
+            const char* pszSRSDimensionLoc = poDS->GetSRSDimensionLoc();
+            if( pszSRSDimensionLoc != NULL )
+                papszOptions = CSLSetNameValue(papszOptions, "SRSDIMENSION_LOC", pszSRSDimensionLoc);
             if (poDS->IsGML32Output())
             {
                 if( poFeatureDefn->GetGeomFieldCount() > 1 )
                     papszOptions = CSLAddString(papszOptions,
-                        CPLSPrintf("GMLID=%s.%s.%ld",
+                        CPLSPrintf("GMLID=%s.%s." CPL_FRMT_GIB,
                                    poFeatureDefn->GetName(),
                                    poFieldDefn->GetNameRef(),
                                    poFeature->GetFID()));
                 else
                     papszOptions = CSLAddString(papszOptions,
-                        CPLSPrintf("GMLID=%s.geom.%ld",
+                        CPLSPrintf("GMLID=%s.geom." CPL_FRMT_GIB,
                                    poFeatureDefn->GetName(), poFeature->GetFID()));
             }
-            pszGeometry = poGeom->exportToGML(papszOptions);
+            if( !bIsGML3Output && OGR_GT_IsNonLinear(poGeom->getGeometryType()) )
+            {
+                OGRGeometry* poGeomTmp = OGRGeometryFactory::forceTo(
+                    poGeom->clone(),OGR_GT_GetLinear(poGeom->getGeometryType()));
+                pszGeometry = poGeomTmp->exportToGML(papszOptions);
+                delete poGeomTmp;
+            }
+            else
+                pszGeometry = poGeom->exportToGML(papszOptions);
             CSLDestroy(papszOptions);
             if (bWriteSpaceIndentation)
                 VSIFPrintfL(fp, "      ");
@@ -786,7 +815,8 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
 
         if( poFeature->IsFieldSet( iField ) && iField != nGMLIdIndex )
         {
-            if (poFieldDefn->GetType() == OFTStringList )
+            OGRFieldType eType = poFieldDefn->GetType();
+            if (eType == OFTStringList )
             {
                 char ** papszIter =  poFeature->GetFieldAsStringList( iField );
                 while( papszIter != NULL && *papszIter != NULL )
@@ -799,46 +829,80 @@ OGRErr OGRGMLLayer::CreateFeature( OGRFeature *poFeature )
                     papszIter ++;
                 }
             }
-            else if (poFieldDefn->GetType() == OFTIntegerList )
+            else if (eType == OFTIntegerList )
             {
                 int nCount = 0;
                 const int* panVals = poFeature->GetFieldAsIntegerList( iField, &nCount );
-                for(int i = 0; i < nCount; i++)
+                if(  poFieldDefn->GetSubType() == OFSTBoolean )
                 {
-                    GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
-                                  bRemoveAppPrefix, poFieldDefn, CPLSPrintf("%d", panVals[i]));
+                    for(int i = 0; i < nCount; i++)
+                    {
+                        /* 0 and 1 are OK, but the canonical representation is false and true */
+                        GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
+                                      bRemoveAppPrefix, poFieldDefn,
+                                      panVals[i] ? "true" : "false");
+                    }
+                }
+                else
+                {
+                    for(int i = 0; i < nCount; i++)
+                    {
+                        GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
+                                      bRemoveAppPrefix, poFieldDefn,
+                                      CPLSPrintf("%d", panVals[i]));
+                    }
+                }
+            }
+            else if (eType == OFTInteger64List )
+            {
+                int nCount = 0;
+                const GIntBig* panVals = poFeature->GetFieldAsInteger64List( iField, &nCount );
+                if(  poFieldDefn->GetSubType() == OFSTBoolean )
+                {
+                    for(int i = 0; i < nCount; i++)
+                    {
+                        /* 0 and 1 are OK, but the canonical representation is false and true */
+                        GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
+                                      bRemoveAppPrefix, poFieldDefn,
+                                      panVals[i] ? "true" : "false");
+                    }
+                }
+                else
+                {
+                    for(int i = 0; i < nCount; i++)
+                    {
+                        GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
+                                      bRemoveAppPrefix, poFieldDefn,
+                                      CPLSPrintf(CPL_FRMT_GIB, panVals[i]));
+                    }
                 }
             }
-            else if (poFieldDefn->GetType() == OFTRealList )
+            else if (eType == OFTRealList )
             {
                 int nCount = 0;
                 const double* padfVals = poFeature->GetFieldAsDoubleList( iField, &nCount );
                 for(int i = 0; i < nCount; i++)
                 {
                     char szBuffer[80];
-                    snprintf( szBuffer, sizeof(szBuffer), "%.15g", padfVals[i]);
-                    /* Use point as decimal separator */
-                    char* pszComma = strchr(szBuffer, ',');
-                    if (pszComma)
-                        *pszComma = '.';
+                    CPLsnprintf( szBuffer, sizeof(szBuffer), "%.15g", padfVals[i]);
                     GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
                                   bRemoveAppPrefix, poFieldDefn, szBuffer);
                 }
             }
+            else if ((eType == OFTInteger || eType == OFTInteger64) &&
+                     poFieldDefn->GetSubType() == OFSTBoolean )
+            {
+                /* 0 and 1 are OK, but the canonical representation is false and true */
+                GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
+                              bRemoveAppPrefix, poFieldDefn,
+                              (poFeature->GetFieldAsInteger(iField)) ? "true" : "false");
+            }
             else
             {
                 const char *pszRaw = poFeature->GetFieldAsString( iField );
 
                 char *pszEscaped = OGRGetXML_UTF8_EscapedString( pszRaw );
 
-                if (poFieldDefn->GetType() == OFTReal)
-                {
-                    /* Use point as decimal separator */
-                    char* pszComma = strchr(pszEscaped, ',');
-                    if (pszComma)
-                        *pszComma = '.';
-                }
-
                 GMLWriteField(poDS, fp, bWriteSpaceIndentation, pszPrefix,
                               bRemoveAppPrefix, poFieldDefn, pszEscaped);
                 CPLFree( pszEscaped );
@@ -906,6 +970,9 @@ int OGRGMLLayer::TestCapability( const char * pszCap )
     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
         return TRUE;
 
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return poDS->IsGML3Output();
+
     else 
         return FALSE;
 }
diff --git a/ogr/ogrsf_frmts/gml/parsexsd.cpp b/ogr/ogrsf_frmts/gml/parsexsd.cpp
index 6a7fd7a..71c6560 100644
--- a/ogr/ogrsf_frmts/gml/parsexsd.cpp
+++ b/ogr/ogrsf_frmts/gml/parsexsd.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: parsexsd.cpp 27132 2014-04-05 21:48:58Z rouault $
+ * $Id: parsexsd.cpp 28909 2015-04-15 12:52:53Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLParseXSD()
@@ -81,9 +81,14 @@ int GetSimpleTypeProperties(CPLXMLNode *psTypeNode,
         *pnPrecision = atoi(pszPrecision);
         return TRUE;
     }
+    
+     else if( EQUAL(pszBase,"float") )
+    {
+        *pGMLType = GMLPT_Float;
+        return TRUE;
+    }
 
-    else if( EQUAL(pszBase,"float")
-                || EQUAL(pszBase,"double") )
+    else if( EQUAL(pszBase,"double") )
     {
         *pGMLType = GMLPT_Real;
         return TRUE;
@@ -99,6 +104,26 @@ int GetSimpleTypeProperties(CPLXMLNode *psTypeNode,
         return TRUE;
     }
 
+    else if( EQUAL(pszBase,"long") )
+    {
+        *pGMLType = GMLPT_Integer64;
+        const char *pszWidth =
+            CPLGetXMLValue( psTypeNode,
+                        "restriction.totalDigits.value", "0" );
+        *pnWidth = atoi(pszWidth);
+        return TRUE;
+    }
+
+    else if( EQUAL(pszBase,"long") )
+    {
+        *pGMLType = GMLPT_Integer64;
+        const char *pszWidth =
+            CPLGetXMLValue( psTypeNode,
+                        "restriction.totalDigits.value", "0" );
+        *pnWidth = atoi(pszWidth);
+        return TRUE;
+    }
+
     else if( EQUAL(pszBase,"string") )
     {
         *pGMLType = GMLPT_String;
@@ -116,6 +141,19 @@ int GetSimpleTypeProperties(CPLXMLNode *psTypeNode,
         *pGMLType = GMLPT_String;
         return TRUE;
     }
+
+    else if( EQUAL(pszBase,"boolean") )
+    {
+        *pGMLType = GMLPT_Boolean;
+        return TRUE;
+    }
+
+    else if( EQUAL(pszBase,"short") )
+    {
+        *pGMLType = GMLPT_Short;
+        return TRUE;
+    }
+
     return FALSE;
 }
 
@@ -202,10 +240,14 @@ static GMLPropertyType GetListTypeFromSingleType(GMLPropertyType eType)
 {
     if( eType == GMLPT_String )
         return GMLPT_StringList;
-    if( eType == GMLPT_Integer )
+    if( eType == GMLPT_Integer || eType == GMLPT_Short )
         return GMLPT_IntegerList;
-    if( eType == GMLPT_Real )
+    if( eType == GMLPT_Integer64 )
+        return GMLPT_Integer64List;
+    if( eType == GMLPT_Real || eType == GMLPT_Float )
         return GMLPT_RealList;
+    if( eType == GMLPT_Boolean )
+        return GMLPT_BooleanList;
     if( eType == GMLPT_FeatureProperty )
         return GMLPT_FeaturePropertyList;
     return eType;
@@ -226,14 +268,14 @@ static const AssocNameType apsPropertyTypes [] =
     {"GeometryPropertyType", wkbUnknown},
     {"PointPropertyType", wkbPoint},
     {"LineStringPropertyType", wkbLineString},
-    {"CurvePropertyType", wkbLineString},
+    {"CurvePropertyType", wkbCompoundCurve},
     {"PolygonPropertyType", wkbPolygon},
-    {"SurfacePropertyType", wkbPolygon},
+    {"SurfacePropertyType", wkbCurvePolygon},
     {"MultiPointPropertyType", wkbMultiPoint},
     {"MultiLineStringPropertyType", wkbMultiLineString},
-    {"MultiCurvePropertyType", wkbMultiLineString},
+    {"MultiCurvePropertyType", wkbMultiCurve},
     {"MultiPolygonPropertyType", wkbMultiPolygon},
-    {"MultiSurfacePropertyType", wkbMultiPolygon},
+    {"MultiSurfacePropertyType", wkbMultiSurface},
     {"MultiGeometryPropertyType", wkbGeometryCollection},
     {"GeometryAssociationType", wkbUnknown},
     {NULL, wkbUnknown},
@@ -243,11 +285,11 @@ static const AssocNameType apsPropertyTypes [] =
 static const AssocNameType apsRefTypes [] =
 {
     {"pointProperty", wkbPoint},
-    {"curveProperty", wkbLineString},
-    {"surfaceProperty", wkbPolygon},
+    {"curveProperty", wkbLineString}, /* should we promote to wkbCompoundCurve ? */
+    {"surfaceProperty", wkbPolygon},  /* should we promote to wkbCurvePolygon ? */
     {"multiPointProperty", wkbMultiPoint},
     {"multiCurveProperty", wkbMultiLineString},
-    {"multiSurfaceProperty", wkbMultiPolygon},
+    {"multiSurfaceProperty", wkbMultiPolygon}, /* should we promote to wkbMultiSurface ? */
     {NULL, wkbUnknown},
 };
 
@@ -322,6 +364,54 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
             delete poClass;
             return NULL;
         }
+        
+        /* Parse stuff like :
+        <xs:choice>
+            <xs:element ref="gml:polygonProperty"/>
+            <xs:element ref="gml:multiPolygonProperty"/>
+        </xs:choice>
+        as found in https://downloadagiv.blob.core.windows.net/overstromingsgebieden-en-oeverzones/2014_01/Overstromingsgebieden_en_oeverzones_2014_01_GML.zip
+        */
+        if( strcmp(psAttrDef->pszValue,"choice") == 0 )
+        {
+            CPLXMLNode* psChild = psAttrDef->psChild;
+            int bPolygon = FALSE;
+            int bMultiPolygon = FALSE;
+            for( ; psChild; psChild = psChild->psNext )
+            {
+                if( psChild->eType != CXT_Element )
+                    continue;
+                if( strcmp(psChild->pszValue,"element") == 0 )
+                {
+                    const char* pszRef = CPLGetXMLValue( psChild, "ref", NULL );
+                    if( pszRef != NULL )
+                    {
+                        if( strcmp(pszRef, "gml:polygonProperty") == 0 )
+                            bPolygon = TRUE;
+                        else if( strcmp(pszRef, "gml:multiPolygonProperty") == 0 )
+                            bMultiPolygon = TRUE;
+                        else
+                        {
+                            delete poClass;
+                            return NULL;
+                        }
+                    }
+                    else
+                    {
+                        delete poClass;
+                        return NULL;
+                    }
+                }
+            }
+            if( bPolygon && bMultiPolygon )
+            {
+                poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
+                    "", "", wkbMultiPolygon, nAttributeIndex, TRUE ) );
+
+                nAttributeIndex ++;
+            }
+            continue;
+        }
 
         if( !EQUAL(psAttrDef->pszValue,"element") )
             continue;
@@ -330,6 +420,7 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
         /* not as a simpleType definition */
         const char* pszType = CPLGetXMLValue( psAttrDef, "type", NULL );
         const char* pszElementName = CPLGetXMLValue( psAttrDef, "name", NULL );
+        int bNullable = EQUAL(CPLGetXMLValue( psAttrDef, "minOccurs", "1" ), "0");
         const char* pszMaxOccurs = CPLGetXMLValue( psAttrDef, "maxOccurs", NULL );
         if (pszType != NULL)
         {
@@ -338,8 +429,7 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
 
             GMLPropertyType gmlType = GMLPT_Untyped;
             if (EQUAL(pszStrippedNSType, "string") ||
-                EQUAL(pszStrippedNSType, "Character") ||
-                EQUAL(pszStrippedNSType, "boolean"))
+                EQUAL(pszStrippedNSType, "Character"))
                 gmlType = GMLPT_String;
             /* TODO: Would be nice to have a proper date type */
             else if (EQUAL(pszStrippedNSType, "date") ||
@@ -347,14 +437,19 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                 gmlType = GMLPT_String;
             else if (EQUAL(pszStrippedNSType, "real") ||
                      EQUAL(pszStrippedNSType, "double") ||
-                     EQUAL(pszStrippedNSType, "float") ||
                      EQUAL(pszStrippedNSType, "decimal"))
                 gmlType = GMLPT_Real;
-            else if (EQUAL(pszStrippedNSType, "short") ||
-                     EQUAL(pszStrippedNSType, "int") ||
-                     EQUAL(pszStrippedNSType, "integer") ||
-                     EQUAL(pszStrippedNSType, "long"))
+            else if (EQUAL(pszStrippedNSType, "float") )
+                gmlType = GMLPT_Float;
+            else if (EQUAL(pszStrippedNSType, "int") ||
+                     EQUAL(pszStrippedNSType, "integer"))
                 gmlType = GMLPT_Integer;
+            else if (EQUAL(pszStrippedNSType, "long"))
+                gmlType = GMLPT_Integer64;
+            else if (EQUAL(pszStrippedNSType, "short") )
+                gmlType = GMLPT_Short;
+            else if (EQUAL(pszStrippedNSType, "boolean") )
+                gmlType = GMLPT_Boolean;
             else if (strcmp(pszType, "gml:FeaturePropertyType") == 0 )
             {
                 gmlType = GMLPT_FeatureProperty;
@@ -366,8 +461,23 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                 {
                     if (strncmp(pszType + 4, psIter->pszName, strlen(psIter->pszName)) == 0)
                     {
+                        OGRwkbGeometryType eType = psIter->eType;
+
+                        /* Look if there's a comment restricting to subclasses */
+                        if( psAttrDef->psNext != NULL && psAttrDef->psNext->eType == CXT_Comment )
+                        {
+                            if( strstr(psAttrDef->psNext->pszValue, "restricted to Polygon") )
+                                eType = wkbPolygon;
+                            else if( strstr(psAttrDef->psNext->pszValue, "restricted to LineString") )
+                                eType = wkbLineString;
+                            else if( strstr(psAttrDef->psNext->pszValue, "restricted to MultiPolygon") )
+                                eType = wkbMultiPolygon;
+                            else if( strstr(psAttrDef->psNext->pszValue, "restricted to MultiLineString") )
+                                eType = wkbMultiLineString;
+                        }
+
                         poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                            pszElementName, pszElementName, psIter->eType, nAttributeIndex ) );
+                            pszElementName, pszElementName, eType, nAttributeIndex, bNullable ) );
 
                         nAttributeIndex ++;
 
@@ -396,7 +506,8 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                      strcmp(pszType, "gmgml:Point_MultiPointPropertyType") == 0)
             {
                 poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                    pszElementName, pszElementName, wkbMultiPoint, nAttributeIndex ) );
+                    pszElementName, pszElementName, wkbMultiPoint, nAttributeIndex,
+                    bNullable ) );
 
                 nAttributeIndex ++;
                 continue;
@@ -405,7 +516,8 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                      strcmp(pszType, "gmgml:LineString_MultiLineStringPropertyType") == 0)
             {
                 poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                    pszElementName, pszElementName, wkbMultiLineString, nAttributeIndex ) );
+                    pszElementName, pszElementName, wkbMultiLineString, nAttributeIndex,
+                    bNullable ) );
 
                 nAttributeIndex ++;
                 continue;
@@ -415,7 +527,8 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                      strcmp(pszType, "gmgml:Polygon_Surface_MultiSurface_CompositeSurfacePropertyType") == 0)
             {
                 poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                    pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex ) );
+                    pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex,
+                    bNullable ) );
 
                 nAttributeIndex ++;
                 continue;
@@ -425,7 +538,8 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
             else if (strcmp(pszType, "wfs:MixedPolygonPropertyType") == 0)
             {
                 poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                    pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex ) );
+                    pszElementName, pszElementName, wkbMultiPolygon, nAttributeIndex,
+                    bNullable) );
 
                 nAttributeIndex ++;
                 continue;
@@ -453,12 +567,13 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
             GMLPropertyDefn *poProp = new GMLPropertyDefn(
                 pszPropertyName, pszElementName );
 
-            if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "unbounded") == 0 )
+            if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "1") != 0 )
                 gmlType = GetListTypeFromSingleType(gmlType);
 
             poProp->SetType( gmlType );
             poProp->SetWidth( nWidth );
             poProp->SetPrecision( nPrecision );
+            poProp->SetNullable( bNullable );
 
             if (poClass->AddProperty( poProp ) < 0)
                 delete poProp;
@@ -500,7 +615,7 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                         else
                         {
                             poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                                pszElementName, pszElementName, psIter->eType, nAttributeIndex ) );
+                                pszElementName, pszElementName, psIter->eType, nAttributeIndex, TRUE ) );
 
                             nAttributeIndex ++;
                         }
@@ -545,7 +660,7 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
                 strcmp(CPLGetXMLValue( psComplexTypeSequenceElement, "ref", "" ), "gml:_Geometry") == 0 )
             {
                 poClass->AddGeometryProperty( new GMLGeometryPropertyDefn(
-                    pszElementName, pszElementName, wkbUnknown, nAttributeIndex ) );
+                    pszElementName, pszElementName, wkbUnknown, nAttributeIndex, bNullable ) );
 
                 nAttributeIndex ++;
 
@@ -568,12 +683,13 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
         int nWidth = 0, nPrecision = 0;
         GetSimpleTypeProperties(psSimpleType, &eType, &nWidth, &nPrecision);
 
-        if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "unbounded") == 0 )
+        if( pszMaxOccurs != NULL && strcmp(pszMaxOccurs, "1") != 0 )
             eType = GetListTypeFromSingleType(eType);
 
         poProp->SetType( eType );
         poProp->SetWidth( nWidth );
         poProp->SetPrecision( nPrecision );
+        poProp->SetNullable( bNullable );
 
         if (poClass->AddProperty( poProp ) < 0)
             delete poProp;
@@ -586,7 +702,7 @@ GMLFeatureClass* GMLParseFeatureType(CPLXMLNode *psSchemaNode,
     if( poClass->GetGeometryPropertyCount() == 0 &&
         bGotUnrecognizedType )
     {
-        poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown ) );
+        poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, TRUE ) );
     }
 
 /* -------------------------------------------------------------------- */
@@ -750,9 +866,12 @@ void CPLXMLSchemaResolveInclude( const char* pszMainSchemaLocation,
 /************************************************************************/
 
 int GMLParseXSD( const char *pszFile,
-                 std::vector<GMLFeatureClass*> & aosClasses)
+                 std::vector<GMLFeatureClass*> & aosClasses,
+                 int& bFullyUnderstood)
 
 {
+    bFullyUnderstood = FALSE;
+
     if( pszFile == NULL )
         return FALSE;
 
@@ -786,6 +905,8 @@ int GMLParseXSD( const char *pszFile,
 
     //CPLSerializeXMLTreeToFile(psSchemaNode, "/vsistdout/");
 
+    bFullyUnderstood = TRUE;
+
 /* ==================================================================== */
 /*      Process each feature class definition.                          */
 /* ==================================================================== */
@@ -843,6 +964,8 @@ int GMLParseXSD( const char *pszFile,
                         GMLParseFeatureType(psSchemaNode, pszName, psComplexType);
                 if (poClass)
                     aosClasses.push_back(poClass);
+                else
+                    bFullyUnderstood = FALSE;
             }
             continue;
         }
@@ -882,6 +1005,8 @@ int GMLParseXSD( const char *pszFile,
                 GMLParseFeatureType(psSchemaNode, pszName, pszType);
         if (poClass)
             aosClasses.push_back(poClass);
+        else
+            bFullyUnderstood = FALSE;
     }
 
     CPLDestroyXMLNode( psXSDTree );
diff --git a/ogr/ogrsf_frmts/gml/parsexsd.h b/ogr/ogrsf_frmts/gml/parsexsd.h
index 6ae0d8a..125d64a 100644
--- a/ogr/ogrsf_frmts/gml/parsexsd.h
+++ b/ogr/ogrsf_frmts/gml/parsexsd.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: parsexsd.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: parsexsd.h 28909 2015-04-15 12:52:53Z rouault $
  *
  * Project:  GML Reader
  * Purpose:  Implementation of GMLParseXSD()
@@ -35,6 +35,7 @@
 #include "gmlreader.h"
 
 int GMLParseXSD( const char *pszFile,
-                 std::vector<GMLFeatureClass*> & aosClasses);
+                 std::vector<GMLFeatureClass*> & aosClasses,
+                 int& bFullyUnderstood );
 
 #endif // _PARSEXSD_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/gmt/GNUmakefile b/ogr/ogrsf_frmts/gmt/GNUmakefile
index ed338d4..fcd40a2 100644
--- a/ogr/ogrsf_frmts/gmt/GNUmakefile
+++ b/ogr/ogrsf_frmts/gmt/GNUmakefile
@@ -3,7 +3,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrgmtdriver.o ogrgmtdatasource.o ogrgmtlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gmt/drv_gmt.html b/ogr/ogrsf_frmts/gmt/drv_gmt.html
index 014d323..e2bcede 100644
--- a/ogr/ogrsf_frmts/gmt/drv_gmt.html
+++ b/ogr/ogrsf_frmts/gmt/drv_gmt.html
@@ -14,7 +14,7 @@ Currently GMT files are only supported if they have the extension ".gmt".
 
 Old (simple) GMT files are treated as either point, or linestring files
 depending on whether a ">" line is encountered before the first vertex. 
-New style files have a variety of auxilary information including geometry
+New style files have a variety of auxiliary information including geometry
 type, layer extents, coordinate system and attribute field declarations in
 comments in the header, and for each feature can have attributes. 
 
@@ -22,7 +22,11 @@ comments in the header, and for each feature can have attributes.
 
 The driver supports creating new GMT files, and appending additional features
 to existing files, but update of existing features is not supported.  Each
-layer is created as a seperate .gmt file.<p>
+layer is created as a seperate .gmt file.
+
+If a name that ends with .gmt is not given, then the GMT driver will take
+the layer name and add the ".gmt" extension.
+<p>
 
 </body>
 </html>
diff --git a/ogr/ogrsf_frmts/gmt/ogr_gmt.h b/ogr/ogrsf_frmts/gmt/ogr_gmt.h
index a38d9e3..a5b61b3 100644
--- a/ogr/ogrsf_frmts/gmt/ogr_gmt.h
+++ b/ogr/ogrsf_frmts/gmt/ogr_gmt.h
@@ -81,7 +81,7 @@ class OGRGmtLayer : public OGRLayer
 
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce);
 
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -113,7 +113,7 @@ class OGRGmtDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
diff --git a/ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp b/ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp
index 5998ecb..ffd25e0 100644
--- a/ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp
+++ b/ogr/ogrsf_frmts/gmt/ogrgmtdatasource.cpp
@@ -106,15 +106,14 @@ int OGRGmtDataSource::Create( const char *pszDSName, char **papszOptions )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRGmtDataSource::CreateLayer( const char * pszLayerName,
-                               OGRSpatialReference *poSRS,
-                               OGRwkbGeometryType eType,
-                               CPL_UNUSED char ** papszOptions )
-
+OGRGmtDataSource::ICreateLayer( const char * pszLayerName,
+                                OGRSpatialReference *poSRS,
+                                OGRwkbGeometryType eType,
+                                CPL_UNUSED char ** papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Establish the geometry type.  Note this logic                   */
@@ -257,4 +256,3 @@ OGRLayer *OGRGmtDataSource::GetLayer( int iLayer )
     else
         return papoLayers[iLayer];
 }
-
diff --git a/ogr/ogrsf_frmts/gmt/ogrgmtdriver.cpp b/ogr/ogrsf_frmts/gmt/ogrgmtdriver.cpp
index f377dbb..f9b4c95 100644
--- a/ogr/ogrsf_frmts/gmt/ogrgmtdriver.cpp
+++ b/ogr/ogrsf_frmts/gmt/ogrgmtdriver.cpp
@@ -49,7 +49,7 @@ OGRGmtDriver::~OGRGmtDriver()
 const char *OGRGmtDriver::GetName()
 
 {
-    return "GMT";
+    return "OGR_GMT";
 }
 
 /************************************************************************/
@@ -112,6 +112,12 @@ int OGRGmtDriver::TestCapability( const char * pszCap )
 void RegisterOGRGMT()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGmtDriver );
+    OGRSFDriver* poDriver = new OGRGmtDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "GMT ASCII Vectors (.gmt)" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gmt" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_gmt.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp b/ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp
index 0878fb9..e8ca183 100644
--- a/ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp
+++ b/ogr/ogrsf_frmts/gmt/ogrgmtlayer.cpp
@@ -160,6 +160,7 @@ OGRGmtLayer::OGRGmtLayer( const char * pszFilename, int bUpdate )
 /*      known.                                                          */
 /* -------------------------------------------------------------------- */
     poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
 
@@ -522,7 +523,7 @@ OGRFeature *OGRGmtLayer::GetNextRawFeature()
         {
             // Parse point line. 
             double dfX, dfY, dfZ = 0.0;
-            int nDim = sscanf( osLine, "%lf %lf %lf", &dfX, &dfY, &dfZ );
+            int nDim = CPLsscanf( osLine, "%lf %lf %lf", &dfX, &dfY, &dfZ );
                 
             if( nDim >= 2 )
             {
@@ -808,10 +809,10 @@ OGRErr OGRGmtLayer::CompleteHeader( OGRGeometry *poThisGeom )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGmtLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGmtLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     if( !bUpdate )
diff --git a/ogr/ogrsf_frmts/gpkg/GNUmakefile b/ogr/ogrsf_frmts/gpkg/GNUmakefile
index 04f807c..d7eac6f 100644
--- a/ogr/ogrsf_frmts/gpkg/GNUmakefile
+++ b/ogr/ogrsf_frmts/gpkg/GNUmakefile
@@ -1,13 +1,19 @@
 
 include ../../../GDALmake.opt
 
-OBJ	= ogrgeopackagedriver.o ogrgeopackagedatasource.o ogrgeopackagelayer.o ogrgeopackageutility.o
+OBJ	= ogrgeopackagedriver.o ogrgeopackagedatasource.o ogrgeopackagelayer.o \
+	ogrgeopackagetablelayer.o ogrgeopackageselectlayer.o ogrgeopackageutility.o \
+	gdalgeopackagerasterband.o
+
+ifeq ($(SPATIALITE_412_OR_LATER),yes)
+CPPFLAGS +=  -DSPATIALITE_412_OR_LATER
+endif
 
 ifeq ($(SQLITE_HAS_COLUMN_METADATA),yes)
 CPPFLAGS +=  -DSQLITE_HAS_COLUMN_METADATA
 endif
 
-CPPFLAGS := -I.. $(GDAL_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
+CPPFLAGS := -I.. -I../sqlite -I../../../frmts/mem $(SQLITE_INC) $(CPPFLAGS)
 
 default: $(O_OBJ:.o=.$(OBJ_EXT))
 
@@ -15,7 +21,6 @@ default: $(O_OBJ:.o=.$(OBJ_EXT))
 clean:
 	rm -f *.o $(O_OBJ)
 
-$(O_OBJ): ogr_geopackage.h ogrgeopackageutility.h
-
+$(O_OBJ): ogr_geopackage.h ogrgeopackageutility.h ../sqlite/ogr_sqlite.h
 
 
diff --git a/ogr/ogrsf_frmts/gpkg/drv_geopackage.html b/ogr/ogrsf_frmts/gpkg/drv_geopackage.html
index 2cdc345..7f85d8b 100644
--- a/ogr/ogrsf_frmts/gpkg/drv_geopackage.html
+++ b/ogr/ogrsf_frmts/gpkg/drv_geopackage.html
@@ -1,14 +1,14 @@
 <html>
 <head>
-<title>GeoPackage</title>
+<title>GeoPackage vector</title>
 </head>
 
 <body bgcolor="#ffffff">
 
-<h1>GeoPackage</h1>
+<h1>GeoPackage vector</h1>
 
 <p>This driver implements support for access to spatial tables in the 
-<a href="http://opengis.github.io/geopackage/">OGC GeoPackage format standard</a>.
+<a href="http://www.geopackage.org/spec/">OGC GeoPackage format standard</a>.
 The GeoPackage standard uses a SQLite database file as a generic container, and the standard defines:
 </p>
 <ul>
@@ -17,13 +17,18 @@ The GeoPackage standard uses a SQLite database file as a generic container, and
   <li>Naming and conventions for extensions (extended feature types) and indexes (how to use SQLite r-tree in an interoperable manner)</li>
 </ul>
 <p>This driver reads and writes SQLite files from the file system, so it must be run by a user with read/write access to the files it is working with.</p>
+<p>Starting with GDAL 2.0, the driver also supports reading and writing the
+following non-linear geometry types :CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE and MULTISURFACE</p>
+
+<p>Starting with GDAL 2.0, GeoPackage raster/tiles are supported. See
+<a href="drv_geopackage_raster.html">GeoPackage raster</a> documentation page</p>
 
 <h2>Limitations</h2>
 
 <ul>
 <li>GeoPackage only supports one geometry column per table.</li>
-<li>This driver does not currently implement the GeoPackage index extension.</li>
-<li>GeoPackage does not currently support non-spatial tables.</li>
+<li>Before GDAL 2.0, the driver did not implement the GeoPackage spatial index extension.</li>
+<li>The core GeoPackage specification does not currently support non-spatial tables, but starting with GDAL 2.0, the driver allows creating and reading such tables via the <a href="geopackage_aspatial.html">Aspatial Support</a> (<code>gdal_aspatial</code>) extension.</li>
 </ul>
 
 <h2>SQL</h2>
@@ -32,6 +37,55 @@ The GeoPackage standard uses a SQLite database file as a generic container, and
   to provide filters in the SQLite dialect, as they will be executed directly
   against the database.
 </p>
+<p>
+  Starting with GDAL 2.0, SQL SELECT statements passed to ExecuteSQL() are
+  also executed directly against the database. If Spatialite is used, a recent
+  version (4.2.0) is needed and use of explicit cast operators AsGPB() is required
+  to transform GeoPackage geometries to Spatialite geometries (the reverse conversion
+  from Spatialite geometries is automatically done by the GPKG driver).
+  It is also possible to use with any Spatialite version, but in
+  a slower way, by specifying the "INDIRECT_SQLITE" dialect. In which case,
+  GeoPackage geometries automatically appear as Spatialite geometries after translation by OGR.
+</p>
+
+<h3>SQL functions</h3>
+
+Starting with GDAL 2.0, the following SQL functions, from the GeoPackage specification, are available :
+<ul>
+<li>ST_MinX(geom <i>Geometry</i>) : returns the minimum X coordinate of the geometry</li>
+<li>ST_MinY(geom <i>Geometry</i>) : returns the minimum Y coordinate of the geometry</li>
+<li>ST_MaxX(geom <i>Geometry</i>) : returns the maximum X coordinate of the geometry</li>
+<li>ST_MaxY(geom <i>Geometry</i>) : returns the maximum Y coordinate of the geometry</li>
+<li>ST_IsEmpty(geom <i>Geometry</i>) : returns 1 is the geometry is empty (but not null), e.g. a POINT EMPTY geometry</li>
+<li>ST_GeometryType(geom <i>Geometry</i>) : returns the geometry type : 'POINT',
+'LINESTRING', 'POLYGON', 'MULTIPOLYGON', 'MULITLINESTRING', 'MULTIPOINT', 'GEOMETRYCOLLECTION'</li>
+<li>ST_SRID(geom <i>Geometry</i>) : returns the SRID of the geometry</li>
+<li>GPKG_IsAssignable(expected_geom_type <i>String</i>, actual_geom_type <i>String</i>) : mainly, needed for the 'Geometry Type Triggers Extension'</li>
+</ul>
+
+The following functions, with identical syntax and semantics as in Spatialite, are also available :
+
+<ul>
+<li>CreateSpatialIndex(table_name <i>String</i>, geom_column_name <i>String</i>) : creates a spatial index (RTree) on the specified table/geometry column</li>
+<li>DisableSpatialIndex(table_name <i>String</i>, geom_column_name <i>String</i>) : disable an existing spatial index (RTree) on the specified table/geometry column</li>
+</ul>
+
+<h3>Link with Spatialite</h3>
+
+Starting with GDAL 2.0, if it has been compiled against Spatialite 4.2 or later, it is also possible
+to use Spatialite SQL functions. Explicit transformation from GPKG geometry binary
+encoding to/from Spatialite geometry binary encoding must be done.
+
+<pre>
+ogrinfo poly.gpkg -sql "SELECT AsGPB(ST_Buffer(CastAutomagic(geom),5)) FROM poly"
+</pre>
+
+<h2>Transaction support (GDAL >= 2.0)</h2>
+
+<p>
+The driver implements transactions at the database level, per
+<a href="http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions">RFC 54</a>
+</p>
 
 <h2>Creation Issues</h2>
 
@@ -42,18 +96,52 @@ The GeoPackage standard uses a SQLite database file as a generic container, and
 
 <h3>Dataset Creation Options</h3>
 
-<p>None</p>
+<p>None related to vector</p>
 
 <h3>Layer Creation Options</h3>
 
 <ul>
-<li><b>GEOMETRY_COLUMN</b>: Column to use for the geometry column.</li>
-<li><b>FID</b>: Column name to use for the OGR FID (primary key in the SQLite database).</li>
-<li><b>OVERWRITE</b>: If set to "YES" will delete any existing layers that have the same name as the layer being created.</li>
-<li><b>SPATIAL_INDEX</b>: [NOT IMPLEMENTED] If set to "YES" will create a spatial index for this layer.</li>
-
+<li><b>GEOMETRY_NAME</b>: Column to use for the geometry column. Default to "geom". Note: option was called GEOMETRY_COLUMN in releases before GDAL 2</li>
+<li><b>GEOMETRY_NULLABLE</b>: (GDAL >=2.0)  Whether the values of the geometry column can be NULL. Can be set to NO so that geometry is required. Default to "YES"</li>
+<li><b>FID</b>: Column name to use for the OGR FID (primary key in the SQLite database). Default to "fid"</li>
+<li><b>OVERWRITE</b>: If set to "YES" will delete any existing layers that have the same name as the layer being created. Default to NO</li>
+<li><b>SPATIAL_INDEX</b>: (GDAL >=2.0) If set to "YES" will create a spatial index for this layer. Default to YES</li>
+<li><b>PRECISION</b>: (GDAL >=2.0)  This may be "YES" to force new fields created on this
+layer to try and represent the width of text fields (in terms of UTF-8 characters, not bytes), if available
+using TEXT(width) types. If "NO" then the type TEXT will be used instead. The default is "YES".<p>
+<li><b>TRUNCATE_FIELDS</b>: (GDAL >=2.0)  This may be "YES" to force truncated of field values
+that exceed the maximum allowed width of text fields, and also to "fix" the passed string if needed
+to make it a valid UTF-8 string. If "NO" then the value is not truncated nor modified. The default is "NO".<p>
+<li><b>IDENTIFIER</b>=string: (GDAL >=2.0) Identifier of the layer, as put in the contents table.<p>
+<li><b>DESCRIPTION</b>=string: (GDAL >=2.0) Description of the layer, as put in the contents table.<p>
 </ul>
 
+<h3>Metadata</h3>
+
+<p>(GDAL >=2.0) GDAL uses the standardized <a href="http://www.geopackage.org/spec/#_metadata_table">
+<code>gpkg_metadata</code></a> and <a href="http://www.geopackage.org/spec/#_metadata_reference_table">
+<code>gpkg_metadata_reference</code></a> tables to read and write metadata,
+on the dataset and layer objects.</p>
+
+<p>GDAL metadata, from the default metadata domain and possibly other metadata
+domains, is serialized in a single XML document, conformant with the format used
+in GDAL PAM (Persistent Auxiliary Metadata) .aux.xml files, and registered with
+md_scope=dataset and md_standard_uri=http://gdal.org in gpkg_metadata.
+For the dataset, this entry is referenced in gpkg_metadata_reference with a
+reference_scope=geopackage.
+For a layer, this entry is referenced in gpkg_metadata_reference with a
+reference_scope=table and table_name={name of the table}</p>
+
+<p>Metadata not originating from GDAL can be read by the driver and will be
+exposed as metadata items with keys of the form GPKG_METADATA_ITEM_XXX and
+values the content of the <i>metadata</i> columns of the gpkg_metadata table.
+Update of such metadata is not currently supported through GDAL interfaces (
+although it can be through direct SQL commands).</p>
+
+<p>The specific DESCRIPTION and IDENTIFIER metadata item of the default metadata
+domain can be used in read/write to read from/update the corresponding columns of
+the gpkg_contents table.</p>
+
 <h3>Examples</h3>
 
 <ul>
@@ -86,19 +174,11 @@ The file <code>filename.gpkg</code> must <strong>not</strong> already exist, as
 
 </ul>
 
-<h3>FAQs</h3>
-
-<ul>
-  <li> <b>...</b><br>
-...
-</li>
-</ul>
-
-
 <h3>See Also</h3>
 
 <ul>
 <li> <a href="http://sqlite.org/">SQLite</a><p>
+<li> <a href="drv_geopackage_raster.html">GeoPackage raster</a> documentation page</li>
 </ul>
 
 </body>
diff --git a/ogr/ogrsf_frmts/gpkg/drv_geopackage_raster.html b/ogr/ogrsf_frmts/gpkg/drv_geopackage_raster.html
new file mode 100644
index 0000000..26db1ca
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/drv_geopackage_raster.html
@@ -0,0 +1,375 @@
+<!DOCTYPE HTML SYSTEM>
+<html>
+<head>
+<title>GeoPackage raster</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>GeoPackage raster</h1>
+
+<p>Starting with GDAL 2.0, this driver implements full read/creation/update of
+tables containing raster tiles in the 
+<a href="http://www.geopackage.org/spec/">OGC GeoPackage format standard</a>.
+The GeoPackage standard uses a SQLite database file as a generic container, and the standard defines:
+</p>
+<ul>
+  <li>Expected metadata tables (<code>gpkg_contents</code>,
+     <code>gpkg_spatial_ref_sys</code>, <code>gpkg_tile_matrix</code>,
+     <code>gpkg_tile_matrix_set</code>, ...)</li>
+  <li>Tile format encoding (PNG and JPEG for base specification, WebP as extension) and tiling conventions</li>
+  <li>Naming and conventions for extensions</li>
+</ul>
+<p>This driver reads and writes SQLite files from the file system, so it must be
+run by a user with read/write access to the files it is working with.</p>
+
+<p>The driver can also handle GeoPackage vectors. See
+<a href="drv_geopackage.html">GeoPackage vector</a> documentation page</p>
+
+<p>Various kind of input datasets can be converted to GeoPackage raster :
+<ul>
+<li>Single band grey level</li>
+<li>Single band with R,G,B or R,G,B,A color table</li>
+<li>Two bands: first band with grey level, second band with alpha channel</li>
+<li>Three bands: Red, Green, Blue</li>
+<li>Four band: Red, Green, Blue, Alpha</li>
+</ul>
+GeoPackage rasters only support Byte data type.
+
+<p>
+All raster extensions standardized by the GeoPackage specification are supported in read and creation :
+</p>
+<ul>
+<li><i>gpkg_webp</i>: when storing WebP tiles, provided that GDAL is compiled against libwebp.</li>
+<li><i>gpkg_zoom_other</i>: when resolution of consecutive zoom levels does not vary with a factor of 2.</li>
+</ul>
+
+<h2>Opening options</h2>
+
+<p>By default, the driver will expose a GeoPackage dataset as a four band (Red,Green,
+Blue,Alpha) dataset, which gives the maximum compatibility with the various encodings of
+tiles that can be stored. It is possible to specify an explicit number of bands
+with the BAND_COUNT opening option.</p>
+
+<p>The driver will use the geographic/projected extent indicated in the
+<a href="http://www.geopackage.org/spec/#_contents"><i>gpkg_contents</i></a> table,
+and do necessary clipping, if needed, to respect
+that extent. However that information being optional, if omitted, the driver
+will use the extent provided by the
+<a href="http://www.geopackage.org/spec/#_tile_matrix_set"><i>gpkg_tile_matrix_set</i></a>,
+which covers the extent at all zoom levels. The user can also specify the USE_TILE_EXTENT=YES
+open option to use the actual extent of tiles at the maximum zoom level. Or
+it can specify any of MINX/MINY/MAXX/MAXY to have a custom extent.<p>
+
+The following open options are available:
+<ul>
+<li><b>TABLE</b>=table_name: Name of the table containing the tiles (called
+<a href="http://www.geopackage.org/spec/#tiles_user_tables">"Tile Pyramid User Data Table"</a>
+in the GeoPackage specification language). If
+the GeoPackage dataset only contains one table, this option is not necessary.
+Otherwise, it is required.</li>
+<li><b>ZOOM_LEVEL</b>=value: Integer value between 0 and the maximum filled in
+the <i>gpkg_tile_matrix</i> table. By default, the driver will select the maximum
+zoom level, such as at least one tile at that zoom level is found in the raster table.</li>
+<li><b>BAND_COUNT</b>=1/2/3/4: Number of bands of the dataset exposed after opening.
+Some conversions will be done when possible and implemented, but this might fail
+in some cases, depending on the BAND_COUNT value and the number of bands of the tile.
+Defaults to 4 (which is the always safe value).</li>
+<li><b>MINX</b>=value: Minimum longitude/easting of the area of interest.</li>
+<li><b>MINY</b>=value: Minimum latitude/northing of the area of interest.</li>
+<li><b>MAXX</b>=value: Maximum longitude/easting of the area of interest.</li>
+<li><b>MAXY</b>=value: Maximum latitude/northing of the area of interest.</li>
+<li><b>USE_TILE_EXTENT</b>=YES/NO: Whether to use the extent of actual existing
+tiles at the zoom level of the full resolution dataset. Defaults to NO.</li>
+<li><b>TILE_FORMAT</b>=PNG_JPEG/PNG/PNG8/JPEG/WEBP: Format used to store tiles. See
+<a href="#tile_format">Tile format</a> section. Only used in update mode. Defaults to PNG_JPEG.</li>
+<li><b>QUALITY</b>=1-100: Quality setting for JPEG and WEBP compression. Only used in update mode. Default to 75.</li>
+<li><b>ZLEVEL</b>=1-9: DEFLATE compression level for PNG tiles. Only used in update mode. Default to 6.</li>
+<li><b>DITHER</b>=YES/NO: Whether to use Floyd-Steinberg dithering (for TILE_FORMAT=PNG8).
+Only used in update mode. Defaults to NO.</li>
+</ul>
+
+Note: open options are typically specified with "-oo name=value" syntax in
+most GDAL utilities, or with the GDALOpenEx() API call.
+
+<h2>Creation issues</h2>
+
+<p>Depending of the number of bands of the input dataset and the tile format
+selected, the driver will do the necessary conversions to be compatible with the
+tile format.</p>
+
+<p>To add several tile tables to a GeoPackage dataset (seen as GDAL subdatasets),
+or to add a tile table to an existing vector-only GeoPackage, the generic
+APPEND_SUBDATASET=YES creation option must be provided.</p>
+
+<p>Fully transparent tiles will not be written to the database, as allowed by
+the format.</p>
+
+<p>The driver implements the Create() and IWriteBlock() methods, so that arbitrary
+writing of raster blocks is possible, enabling the direct use of GeoPackage as
+the output dataset of utilities such as gdalwarp.</p>
+
+<p>On creation, raster blocks can be written only if the geotransformation
+matrix has been set with SetGeoTransform() This is effectively needed to determine
+the zoom level of the full resolution dataset based on the pixel resolution, dataset
+and tile dimensions.</p>
+
+<p>Technical/implementation note: when a dataset is opened with a non-default area of interest
+(i.e. use of MINX,MINY,MAXX,MAXY or USE_TILE_EXTENT open option), or when creating/
+opening a dataset with a non-custom tiling scheme, it is possible that GDAL blocks
+do not exactly match a single GeoPackage tile. In which case, each GDAL
+block will overlap four GeoPackage tiles. This is easily handled on the read side,
+but on creation/update side, such configuration could cause numerous decompression/
+recompression of tiles to be done, which might cause unnecessary quality loss when using
+lossy compression (JPEG, WebP). To avoid that, the driver will create a temporary
+database next to the main GeoPackage file to store partial GeoPackage tiles in a
+lossless (and uncompressed) way. Once a tile has received data for its four quadrants
+and for all the bands (or the dataset is closed or explicitely flushed with FlushCache()),
+those uncompressed tiles are definitely transfered to the GeoPackage file with
+the appropriate compression. All of this is transparent to the user of GDAL API/utilities</p>
+
+<h3><a id="tile_formats">Tile formats</a></h3>
+
+<p>GeoPackage can store tiles in different formats, PNG and/or JPEG for the baseline
+specification, and WebP for extended GeoPackage. Support for those tile formats
+depend if the underlying drivers are available in GDAL, which is generally the
+case for PNG and JPEG, but not necessarily for WebP since it requires GDAL to
+be compiled against the optional libwebp.<p>
+
+<p>By default, GDAL will use a mix of PNG and JPEG tiles. PNG tiles will be used
+to store tiles that are not completely opaque, either because input dataset has
+an alpha channel with non fully opaque content, or because tiles are partial due
+to clipping at the right or bottom edges of the raster, or when a dataset is opened
+with a non-default area of interest, or with a non-custom tiling scheme. On the
+contrary, for fully opaque tiles, JPEG format will be used.</p>
+
+<p>It is possible to select one unique tile format by setting the creation/open
+option TILE_FORMAT to one of PNG, JPEG or WEBP. When using JPEG, the alpha channel
+will not be stored. When using WebP, the
+<a href="http://www.geopackage.org/spec/#extension_tiles_webp"><i>gpkg_webp</i></a>
+extension will be registered. The lossy compression of WebP is used.
+Note that a recent enough libwebp
+(>=0.1.4) must be used to support alpha channel in WebP tiles.</p>
+
+<p>PNG8 can be selected to use 8-bit PNG with a color table up to 256 colors.
+On creation, an optimized color table is computed for each tile. The DITHER
+option can be set to YES to use Floyd/Steinberg dithering algorithm, which
+spreads the quantization error on neighbouring pixels for better rendering (note
+however than when zooming in, this can cause non desirable visual artifacts).
+Setting it to YES will generally cause less effective compression.
+Note that at that time, such an 8-bit PNG formulation is only used for fully opaque tiles,
+as the median-cut algorithm currently implemented to compute the optimal color
+table does not support alpha channel (even if PNG8 format would potentially allow
+color table with transparency). So when selecting PNG8, non fully opaque tiles
+will be stored as 32-bit PNG.</p>
+
+<h3><a id="tiling_schemes">Tiling schemes</a></h3>
+
+<p>
+By default, conversion to GeoPackage will create a custom tiling scheme, such
+that the input dataset can be losslessly converted, both at the pixel and
+georeferencing level (if using a lossless tile format such as PNG). That
+tiling scheme is such that its origin (<i>min_x</i>, <i>max_y</i>) in the
+<a href="http://www.geopackage.org/spec/#_tile_matrix_set"><i>gpkg_tile_matrix_set</i></a>
+table perfectly matches the top left corner of the dataset, and the selected
+resolution (<i>pixel_x_size</i>, <i>pixel_y_size</i>) at the computed maximum zoom_level of the
+<a href="http://www.geopackage.org/spec/#_tile_matrix"><i>gpkg_tile_matrix</i></a> table will
+match the pixel width and height of the raster.
+</p>
+<p>However to ease interoperability with other implementations, and enable use
+of GeoPackage with tile servicing software, it is possible to select a predefined
+tiling scheme that has world coverage. The available tiling schemes are :</p>
+<ul>
+<li><i>GoogleCRS84Quad</i>, as described in
+<a href="http://portal.opengeospatial.org/files/?artifact_id=35326">OGC 07-057r7
+WMTS 1.0</a> specification, Annex E.3. That tiling schemes consists of a single
+256x256 tile at its zoom level 0, in EPSG:4326 CRS, with extent in longitude and
+latitude in the range [-180,180]. Consequently, at zoom level 0, 64 lines are
+unused at the top and bottom of that tile. This may cause issues with some
+implementations of the specification, and there are some ambiguities about the
+exact definition of this tiling scheme. Using InspireCRS84Quad/PseudoTMS_GlobalGeodetic
+instead is therefore recommended.</li>
+<li><i>GoogleMapsCompatible</i>, as described in WMTS 1.0 specification, Annex E.4.
+That tiling schemes consists of a single 256x256 tile at its zoom level 0,
+in EPSG:3857 CRS, with extent in easting and northing in the range
+[-20037508.34,20037508.34].</li>
+<li><i>InspireCRS84Quad</i>, as described in
+<a href="http://inspire.ec.europa.eu/documents/Network_Services/TechnicalGuidance_ViewServices_v3.0.pdf">
+<i>Inspire View Services</i></a>.
+That tiling schemes consists of two 256x256 tiles at its zoom level 0, in
+EPSG:4326 CRS, with extent in longitude in the range [-180,180] and in latitude
+in the range [-90,90].</li>
+<li><i>PseudoTMS_GlobalGeodetic</i>, based on the
+<a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic">
+<i>global-geodetic</i></a> profile of OSGeo TMS (Tile Map Service) specification.
+This has exactly the same definition as <i>InspireCRS84Quad</i> tiling scheme. Note
+however that full interoperability with TMS is not
+possible due to the origin of numbering of tiles being the top left corner in
+GeoPackage (consistently with WMTS convention), whereas TMS uses the bottom left
+corner as origin.</li>
+<li><i>PseudoTMS_GlobalMercator</i>, based on the
+<a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-mercator">
+<i>global-mercator</i></a> profile of OSGeo TMS (Tile Map Service) specification.
+That tiling schemes consists of four 256x256 tiles at its zoom level 0,
+in EPSG:3857 CRS, with extent extent in easting and northing in the range
+[-20037508.34,20037508.34]. The same remark as with PseudoTMS_GlobalGeodetic applies
+regarding interoperability with TMS.</li>
+</ul>
+
+<p>In all the above tiling schemes, consecutive zoom levels defer by a resolution
+of a factor of two.</p>
+
+<h3>Creation options</h3>
+
+<p>The following creation options are available:</p>
+
+<ul>
+<li><b>RASTER_TABLE</b>=string. Name of tile user table. By default, based on
+the filename (i.e. if filename is foo.gpkg, the table will be called "foo").</li>
+<li><b>APPEND_SUBDATASET</b>=YES/NO: If set to YES, an existing GeoPackage
+will not be priorly destroyed, such as to be able to add new content to it. Defaults to NO.</li>
+<li><b>RASTER_IDENTIFIER</b>=string. Human-readable identifier (e.g. short name), put
+in the <i>identifier</i> column of the <i>gpkg_contents</i> table.</li>
+<li><b>RASTER_DESCRIPTION</b>=string. Human-readable description, put
+in the <i>description</i> column of the <i>gpkg_contents</i> table.</li>
+<li><b>BLOCKSIZE</b>=integer. Block size in width and height in pixels.
+Defaults to 256. Maximum supported is 4096. Should not be set when using a non-custom TILING_SCHEME.</li>
+<li><b>BLOCKXSIZE</b>=integer. Block width in pixels.
+Defaults to 256. Maximum supported is 4096.</li>
+<li><b>BLOCKYSIZE</b>=integer. Block height in pixels.
+Defaults to 256. Maximum supported is 4096.</li>
+<li><b>TILE_FORMAT</b>=PNG_JPEG/PNG/PNG8/JPEG/WEBP: Format used to store tiles. See
+<a href="#tile_formats">Tile formats</a> section. Defaults to PNG_JPEG.</li>
+<li><b>QUALITY</b>=1-100: Quality setting for JPEG and WEBP compression. Default to 75.</li>
+<li><b>ZLEVEL</b>=1-9: DEFLATE compression level for PNG tiles. Default to 6.</li>
+<li><b>DITHER</b>=YES/NO: Whether to use Floyd-Steinberg dithering (for TILE_FORMAT=PNG8).
+Defaults to NO.</li>
+<li><b>TILING_SCHEME</b>=CUSTOM/GoogleCRS84Quad/GoogleMapsCompatible/InspireCRS84Quad/PseudoTMS_GlobalGeodetic/PseudoTMS_GlobalMercator.
+See <a href="#tiling_schemes">Tiling schemes</a> section. Defaults to CUSTOM.</li>
+<li><b>ZOOM_LEVEL_STRATEGY</b>=AUTO/LOWER/UPPER. Strategy to determine zoom level.
+Only used for TILING_SCHEME is different from CUSTOM. LOWER will select the
+zoom level immediately below the theoretical computed non-integral zoom level,
+leading to subsampling. On the contrary, UPPER will select the immedately above
+zoom level, leading to oversampling. Defaults to AUTO which selects the closest
+zoom level.</li>
+<li><b>RESAMPLING</b>=NEAREST/BILINEAR/CUBIC/CUBICSPLINE/LANCZOS/MODE/AVERAGE.
+Resampling algorithm. Only used for TILING_SCHEME is different from CUSTOM. Defaults
+to BILINEAR.</li>
+</ul>
+
+<h2>Overviews</h2>
+
+<p>gdaladdo / BuildOverviews() can be used to compute overviews. Power-of-two
+overview factors (2,4,8,16,...) should be favored to be conformant with the
+baseline GeoPackage specification. Use of other overview factors will work with the GDAL
+driver, and cause the <a href="http://www.geopackage.org/spec/#extension_zoom_other_intervals">
+<i>gpkg_zoom_other</i></a> extension to be registered, but
+that could potentially cause interoperability problems with other
+implementations that do not support that extension.</p>
+
+<p>Overviews can also be cleared with the -clean option of gdaladdo (or
+BuildOverviews() with nOverviews=0)</p>
+
+<h2>Metadata</h2>
+
+<p>GDAL uses the standardized <a href="http://www.geopackage.org/spec/#_metadata_table">
+<code>gpkg_metadata</code></a> and <a href="http://www.geopackage.org/spec/#_metadata_reference_table">
+<code>gpkg_metadata_reference</code></a> tables to read and write metadata.</p>
+
+<p>GDAL metadata, from the default metadata domain and possibly other metadata
+domains, is serialized in a single XML document, conformant with the format used
+in GDAL PAM (Persistent Auxiliary Metadata) .aux.xml files, and registered with
+md_scope=dataset and md_standard_uri=http://gdal.org in gpkg_metadata. In
+gpkg_metadata_reference, this entry is referenced with a reference_scope=table and
+table_name={name of the raster table}</p>
+
+<p>It is possible to read and write metadata that applies to the global GeoPackage,
+and not only to the raster table, by using the <i>GEOPACKAGE</i> metadata
+domain.</p>
+
+<p>Metadata not originating from GDAL can be read by the driver and will be
+exposed as metadata items with keys of the form GPKG_METADATA_ITEM_XXX and
+values the content of the <i>metadata</i> columns of the gpkg_metadata table.
+Update of such metadata is not currently supported through GDAL interfaces (
+although it can be through direct SQL commands).</p>
+
+<p>The specific DESCRIPTION and IDENTIFIER metadata item of the default metadata
+domain can be used in read/write to read from/update the corresponding columns of
+the gpkg_contents table.</p>
+
+<h2>Examples</h2>
+
+<ul>
+<li>
+Simple translation of a GeoTIFF into GeoPackage.  The table 'byte' will
+be created with the tiles.
+<pre>
+% gdal_translate -of GPKG byte.tif byte.gpkg
+</pre>
+</li>
+
+<li>
+Translation of a GeoTIFF into GeoPackage using WebP tiles
+<pre>
+% gdal_translate -of GPKG byte.tif byte.gpkg -co TILE_FORMAT=WEBP
+</pre>
+</li>
+
+<li>
+Translation of a GeoTIFF into GeoPackage using GoogleMapsCompatible tiling scheme
+(with reprojection and resampling if needed)
+<pre>
+% gdal_translate -of GPKG byte.tif byte.gpkg -co TILING_SCHEME=GoogleMapsCompatible
+</pre>
+</li>
+
+<li>
+Building of overviews of an existing GeoPackage
+<pre>
+% gdaladdo -r cubic my.gpkg 2 4 8 16 32 64
+</pre>
+</li>
+
+<li>
+Addition of a new subdataset to an existing GeoPackage, and choose a non
+default name for the raster table.
+<pre>
+% gdal_translate -of GPKG new.tif existing.gpkg -co APPEND_SUBDATASET=YES -co RASTER_TABLE=new_table
+</pre>
+</li>
+
+<li>
+Reprojection of an input dataset to GeoPackage
+<pre>
+% gdalwarp -of GPKG in.tif out.gpkg -t_srs EPSG:3857
+</pre>
+</li>
+
+<li>
+Open a specific raster table in a GeoPackage
+<pre>
+% gdalinfo my.gpkg -oo TABLE=a_table
+</pre>
+</li>
+
+</ul>
+
+<h3>See Also</h3>
+
+<ul>
+<li> <a href="http://sqlite.org/">SQLite</a>
+<li> <a href="drv_geopackage.html">GeoPackage vector</a> documentation page</li>
+<li> <a href="frmt_various.html#PNG">PNG driver</a> documentation page</li>
+<li> <a href="frmt_jpeg.html">JPEG driver</a> documentation page</li>
+<li> <a href="frmt_webp.html">WEBP driver</a> documentation page</li>
+<li> <a href="http://portal.opengeospatial.org/files/?artifact_id=35326">OGC 07-057r7 WMTS 1.0</a> specification</li>
+<li> <a href="http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification">OSGeo TMS (Tile Map Service)</a> specification</li>
+</ul>
+
+<h3>Other notes</h3>
+
+<p>Development of raster support in the GeoPackage driver was financially supported
+by <a href="http://www.safe.com">Safe Software</a>.</p>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp b/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp
new file mode 100644
index 0000000..7877990
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/gdalgeopackagerasterband.cpp
@@ -0,0 +1,1935 @@
+/******************************************************************************
+ * $Id: gdalgeopackagerasterband.cpp 28601 2015-03-03 11:06:40Z rouault $
+ *
+ * Project:  GeoPackage Translator
+ * Purpose:  Implements GDALGeoPackageRasterBand class
+ * Author:   Even Rouault <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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 SOFpszFileNameTWARE.
+ ****************************************************************************/
+
+#include "ogr_geopackage.h"
+#include "memdataset.h"
+#include "gdal_alg_priv.h"
+
+//#define DEBUG_VERBOSE
+
+/************************************************************************/
+/*                      GDALGeoPackageRasterBand()                      */
+/************************************************************************/
+
+GDALGeoPackageRasterBand::GDALGeoPackageRasterBand(GDALGeoPackageDataset* poDS,
+                                                   int nBand,
+                                                   int nTileWidth, int nTileHeight)
+{
+    this->poDS = poDS;
+    this->nBand = nBand;
+    eDataType = GDT_Byte;
+    nBlockXSize = nTileWidth;
+    nBlockYSize = nTileHeight;
+}
+
+/************************************************************************/
+/*                              FlushCache()                            */
+/************************************************************************/
+
+CPLErr GDALGeoPackageRasterBand::FlushCache()
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( GDALPamRasterBand::FlushCache() != CE_None )
+        return CE_Failure;
+    return poGDS->FlushCacheWithErrCode();
+}
+
+/************************************************************************/
+/*                             GetColorTable()                          */
+/************************************************************************/
+
+GDALColorTable* GDALGeoPackageRasterBand::GetColorTable()
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( poGDS->nBands == 1 )
+    {
+        if( !poGDS->m_bTriedEstablishingCT )
+        {
+            poGDS->m_bTriedEstablishingCT = TRUE;
+            if( poGDS->m_poParentDS != NULL )
+            {
+                poGDS->m_poCT = poGDS->m_poParentDS->GetRasterBand(1)->GetColorTable();
+                if( poGDS->m_poCT )
+                    poGDS->m_poCT = poGDS->m_poCT->Clone();
+                return poGDS->m_poCT;
+            }
+
+            char* pszSQL = sqlite3_mprintf("SELECT tile_data FROM '%q' "
+                "WHERE zoom_level = %d LIMIT 1",
+                poGDS->m_osRasterTable.c_str(), poGDS->m_nZoomLevel);
+            sqlite3_stmt* hStmt = NULL;
+            int rc = sqlite3_prepare(poGDS->GetDB(), pszSQL, -1, &hStmt, NULL);
+            if ( rc == SQLITE_OK )
+            {
+                rc = sqlite3_step( hStmt );
+                if( rc == SQLITE_ROW && sqlite3_column_type( hStmt, 0 ) == SQLITE_BLOB )
+                {
+                    const int nBytes = sqlite3_column_bytes( hStmt, 0 );
+                    GByte* pabyRawData = (GByte*)sqlite3_column_blob( hStmt, 0 );
+                    CPLString osMemFileName;
+                    osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this);
+                    VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData,
+                                                            nBytes, FALSE);
+                    VSIFCloseL(fp);
+
+                    /* Only PNG can have color table */
+                    const char* apszDrivers[] = { "PNG", NULL };
+                    GDALDataset* poDSTile = (GDALDataset*)GDALOpenEx(osMemFileName.c_str(),
+                                                                GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                                                apszDrivers, NULL, NULL);
+                    if( poDSTile != NULL )
+                    {
+                        if( poDSTile->GetRasterCount() == 1 )
+                        {
+                            poGDS->m_poCT = poDSTile->GetRasterBand(1)->GetColorTable();
+                            if( poGDS->m_poCT != NULL )
+                                poGDS->m_poCT = poGDS->m_poCT->Clone();
+                        }
+                        GDALClose( poDSTile );
+                    }
+
+                    VSIUnlink(osMemFileName);
+                }
+            }
+            sqlite3_free(pszSQL);
+            sqlite3_finalize(hStmt);
+        }
+
+        return poGDS->m_poCT;
+    }
+    else
+        return NULL;
+}
+
+/************************************************************************/
+/*                             SetColorTable()                          */
+/************************************************************************/
+
+CPLErr GDALGeoPackageRasterBand::SetColorTable(GDALColorTable* poCT)
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( poGDS->nBands != 1 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetColorTable() only supported for a single band dataset");
+        return CE_Failure;
+    }
+    if( !poGDS->m_bNew || poGDS->m_bTriedEstablishingCT )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetColorTable() only supported on a newly created dataset");
+        return CE_Failure;
+    }
+
+    poGDS->m_bTriedEstablishingCT = TRUE;
+    delete poGDS->m_poCT;
+    if( poCT != NULL )
+        poGDS->m_poCT = poCT->Clone();
+    else
+        poGDS->m_poCT = NULL;
+    return CE_None;
+}
+
+/************************************************************************/
+/*                        GetColorInterpretation()                      */
+/************************************************************************/
+
+GDALColorInterp GDALGeoPackageRasterBand::GetColorInterpretation()
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( poGDS->nBands == 1 )
+        return GetColorTable() ? GCI_PaletteIndex : GCI_GrayIndex;
+    else if( poGDS->nBands == 2 )
+        return (nBand == 1) ? GCI_GrayIndex : GCI_AlphaBand;
+    else
+        return (GDALColorInterp) (GCI_RedBand + (nBand - 1));
+}
+
+/************************************************************************/
+/*                        SetColorInterpretation()                      */
+/************************************************************************/
+
+CPLErr GDALGeoPackageRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( eInterp == GCI_Undefined )
+        return CE_None;
+    if( poGDS->nBands == 1 && (eInterp == GCI_GrayIndex || eInterp == GCI_PaletteIndex) )
+        return CE_None;
+    if( poGDS->nBands == 2 &&
+        ((nBand == 1 && eInterp == GCI_GrayIndex) || (nBand == 2 && eInterp == GCI_AlphaBand)) )
+        return CE_None;
+    if( poGDS->nBands >= 3 && eInterp == GCI_RedBand + nBand - 1 )
+        return CE_None;
+    CPLError(CE_Warning, CPLE_NotSupported, "%s color interpretation not supported. Will be ignored",
+             GDALGetColorInterpretationName(eInterp));
+    return CE_Warning;
+}
+
+/************************************************************************/
+/*                        GPKGFindBestEntry()                           */
+/************************************************************************/
+
+static int GPKGFindBestEntry(GDALColorTable* poCT,
+                             GByte c1, GByte c2, GByte c3, GByte c4,
+                             int nTileBandCount)
+{
+    int nEntries = MIN(256, poCT->GetColorEntryCount());
+    int iBestIdx = 0;
+    int nBestDistance = 4 * 256 * 256;
+    for(int i=0;i<nEntries;i++)
+    {
+        const GDALColorEntry* psEntry = poCT->GetColorEntry(i);
+        int nDistance = (psEntry->c1 - c1) * (psEntry->c1 - c1) +
+                        (psEntry->c2 - c2) * (psEntry->c2 - c2) +
+                        (psEntry->c3 - c3) * (psEntry->c3 - c3);
+        if( nTileBandCount == 4 )
+            nDistance += (psEntry->c4 - c4) * (psEntry->c4 - c4);
+        if( nDistance < nBestDistance )
+        {
+            iBestIdx = i;
+            nBestDistance = nDistance;
+        }
+    }
+    return iBestIdx;
+}
+
+/************************************************************************/
+/*                           ReadTile()                                 */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::ReadTile(const CPLString& osMemFileName,
+                                       GByte* pabyTileData,
+                                       int* pbIsLossyFormat)
+{
+    const char* apszDrivers[] = { "JPEG", "PNG", "WEBP", NULL };
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+    GDALDataset* poDSTile = (GDALDataset*)GDALOpenEx(osMemFileName.c_str(),
+                                                     GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                                     apszDrivers, NULL, NULL);
+    if( poDSTile == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot parse tile data");
+        memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize );
+        return CE_Failure;
+    }
+
+    int nTileBandCount = poDSTile->GetRasterCount();
+
+    if( !(poDSTile->GetRasterXSize() == nBlockXSize &&
+          poDSTile->GetRasterYSize() == nBlockYSize &&
+          (nTileBandCount >= 1 && nTileBandCount <= 4)) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Inconsistent tiles characteristics");
+        GDALClose(poDSTile);
+        memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize );
+        return CE_Failure;
+    }
+
+    if( poDSTile->RasterIO(GF_Read, 0, 0, nBlockXSize, nBlockYSize,
+                        pabyTileData,
+                        nBlockXSize, nBlockYSize,
+                        GDT_Byte,
+                        poDSTile->GetRasterCount(), NULL,
+                        0, 0, 0, NULL) != CE_None )
+    {
+        GDALClose(poDSTile);
+        memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize );
+        return CE_Failure;
+    }
+
+    GDALColorTable* poCT = NULL;
+    if( nBands == 1 || nTileBandCount == 1 )
+    {
+        poCT = poDSTile->GetRasterBand(1)->GetColorTable();
+        GetRasterBand(1)->GetColorTable();
+    }
+
+    if( pbIsLossyFormat )
+        *pbIsLossyFormat = !EQUAL(poDSTile->GetDriver()->GetDescription(), "PNG") ||
+                           (poCT != NULL && poCT->GetColorEntryCount() == 256) /* PNG8 */;
+
+    /* Map RGB(A) tile to single-band color indexed */
+    if( nBands == 1 && m_poCT != NULL && nTileBandCount != 1 )
+    {
+        std::map< GUInt32, int > oMapEntryToIndex;
+        int nEntries = MIN(256, m_poCT->GetColorEntryCount());
+        for(int i=0;i<nEntries;i++)
+        {
+            const GDALColorEntry* psEntry = m_poCT->GetColorEntry(i);
+            GByte c1 = (GByte)psEntry->c1;
+            GByte c2 = (GByte)psEntry->c2;
+            GByte c3 = (GByte)psEntry->c3;
+            GUInt32 nVal = c1 + (c2 << 8) + (c3 << 16);
+            if( nTileBandCount == 4 ) nVal += ((GByte)psEntry->c4 << 24);
+            oMapEntryToIndex[nVal] = i;
+        }
+        int iBestEntryFor0 = GPKGFindBestEntry(m_poCT, 0, 0, 0, 0, nTileBandCount);
+        for(int i=0;i<nBlockXSize*nBlockYSize;i++)
+        {
+            GByte c1 = pabyTileData[i];
+            GByte c2 = pabyTileData[i + nBlockXSize * nBlockYSize];
+            GByte c3 = pabyTileData[i + 2 * nBlockXSize * nBlockYSize];
+            GByte c4 = pabyTileData[i + 3 * nBlockXSize * nBlockYSize];
+            GUInt32 nVal = c1 + (c2 << 8) + (c3 << 16);
+            if( nTileBandCount == 4 ) nVal += (c4 << 24);
+            if( nVal == 0 ) /* In most cases we will reach that point at partial tiles */
+                pabyTileData[i] = (GByte) iBestEntryFor0;
+            else
+            {
+                std::map< GUInt32, int >::iterator oMapEntryToIndexIter = oMapEntryToIndex.find(nVal);
+                if( oMapEntryToIndexIter == oMapEntryToIndex.end() )
+                    /* Could happen with JPEG tiles */
+                    pabyTileData[i] = (GByte) GPKGFindBestEntry(m_poCT, c1, c2, c3, c4, nTileBandCount);
+                else
+                    pabyTileData[i] = (GByte) oMapEntryToIndexIter->second;
+            }
+        }
+        GDALClose( poDSTile );
+        return CE_None;
+    }
+    
+    if( nBands == 1 && nTileBandCount == 1 && poCT != NULL && m_poCT != NULL &&
+             !poCT->IsSame(m_poCT) )
+    {
+        CPLError(CE_Warning, CPLE_NotSupported, "Different color tables. Unhandled for now");
+    }
+    else if( (nBands == 1 && nTileBandCount >= 3) ||
+             (nBands == 1 && nTileBandCount == 1 && m_poCT != NULL && poCT == NULL) ||
+             ((nBands == 1 || nBands == 2) && nTileBandCount == 1 && m_poCT == NULL && poCT != NULL) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Inconsistent dataset and tiles band characteristics");
+    }
+
+    if( nBands == 2 )
+    {
+        if( nTileBandCount == 1 || nTileBandCount == 3 /* assuming that the RGB is Grey,Grey,Grey */ )
+        {
+            /* Create fully opaque alpha */
+            memset(pabyTileData + 1 * nBlockXSize * nBlockYSize,
+                   255, nBlockXSize * nBlockYSize);
+        }
+        else if( nTileBandCount == 4 )
+        {
+            /* Transfer alpha band */
+            memcpy(pabyTileData + 1 * nBlockXSize * nBlockYSize,
+                   pabyTileData + 3 * nBlockXSize * nBlockYSize,
+                   nBlockXSize * nBlockYSize);
+        }
+    }
+    else if( nTileBandCount == 2 )
+    {
+        /* Do Grey+Alpha -> RGBA */
+        memcpy(pabyTileData + 3 * nBlockXSize * nBlockYSize,
+               pabyTileData + 1 * nBlockXSize * nBlockYSize,
+               nBlockXSize * nBlockYSize);
+        memcpy(pabyTileData + 1 * nBlockXSize * nBlockYSize,
+               pabyTileData, nBlockXSize * nBlockYSize);
+        memcpy(pabyTileData + 2 * nBlockXSize * nBlockYSize,
+               pabyTileData, nBlockXSize * nBlockYSize);
+    }
+    else if( nTileBandCount == 1 && !(nBands == 1 && m_poCT != NULL) )
+    {
+        /* Expand color indexed to RGB(A) */
+        if( poCT != NULL )
+        {
+            int i;
+            GByte abyCT[4*256];
+            int nEntries = MIN(256, poCT->GetColorEntryCount());
+            for(i=0;i<nEntries;i++)
+            {
+                const GDALColorEntry* psEntry = poCT->GetColorEntry(i);
+                abyCT[4*i] = (GByte)psEntry->c1;
+                abyCT[4*i+1] = (GByte)psEntry->c2;
+                abyCT[4*i+2] = (GByte)psEntry->c3;
+                abyCT[4*i+3] = (GByte)psEntry->c4;
+            }
+            for(;i<256;i++)
+            {
+                abyCT[4*i] = 0;
+                abyCT[4*i+1] = 0;
+                abyCT[4*i+2] = 0;
+                abyCT[4*i+3] = 0;
+            }
+            for(i=0;i<nBlockXSize * nBlockYSize;i++)
+            {
+                GByte byVal = pabyTileData[i];
+                pabyTileData[i] = abyCT[4*byVal];
+                pabyTileData[i + 1 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+1];
+                pabyTileData[i + 2 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+2];
+                pabyTileData[i + 3 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+3];
+            }
+        }
+        else
+        {
+            memcpy(pabyTileData + 1 * nBlockXSize * nBlockYSize,
+                pabyTileData, nBlockXSize * nBlockYSize);
+            memcpy(pabyTileData + 2 * nBlockXSize * nBlockYSize,
+                pabyTileData, nBlockXSize * nBlockYSize);
+            if( nBands == 4 )
+            {
+                memset(pabyTileData + 3 * nBlockXSize * nBlockYSize,
+                    255, nBlockXSize * nBlockYSize);
+            }
+        }
+    }
+    else if( nTileBandCount == 3 && nBands == 4 )
+    {
+        /* Create fully opaque alpha */
+        memset(pabyTileData + 3 * nBlockXSize * nBlockYSize,
+                255, nBlockXSize * nBlockYSize);
+    }
+
+    GDALClose( poDSTile );
+    
+    return CE_None;
+}
+
+/************************************************************************/
+/*                           ReadTile()                                 */
+/************************************************************************/
+
+GByte* GDALGeoPackageDataset::ReadTile(int nRow, int nCol)
+{
+    GByte* pabyData = NULL;
+
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+    if( m_nShiftXPixelsMod )
+    {
+        int i;
+        for(i = 0; i < 4; i ++)
+        {
+            if( m_asCachedTilesDesc[i].nRow == nRow &&
+                m_asCachedTilesDesc[i].nCol == nCol )
+            {
+                if( m_asCachedTilesDesc[i].nIdxWithinTileData >= 0 )
+                {
+                    return m_pabyCachedTiles +
+                        m_asCachedTilesDesc[i].nIdxWithinTileData * 4 * nBlockXSize * nBlockYSize;
+                }
+                else
+                {
+                    if( i == 0 )
+                        m_asCachedTilesDesc[i].nIdxWithinTileData =
+                            (m_asCachedTilesDesc[1].nIdxWithinTileData == 0 ) ? 1 : 0;
+                    else if( i == 1 )
+                        m_asCachedTilesDesc[i].nIdxWithinTileData =
+                            (m_asCachedTilesDesc[0].nIdxWithinTileData == 0 ) ? 1 : 0;
+                    else if( i == 2 )
+                        m_asCachedTilesDesc[i].nIdxWithinTileData =
+                            (m_asCachedTilesDesc[3].nIdxWithinTileData == 2 ) ? 3 : 2;
+                    else
+                        m_asCachedTilesDesc[i].nIdxWithinTileData =
+                            (m_asCachedTilesDesc[2].nIdxWithinTileData == 2 ) ? 3 : 2;
+                    pabyData = m_pabyCachedTiles +
+                                            m_asCachedTilesDesc[i].nIdxWithinTileData * 4 * nBlockXSize * nBlockYSize;
+                    break;
+                }
+            }
+        }
+        CPLAssert(i < 4);
+    }
+    else
+        pabyData = m_pabyCachedTiles;
+    
+    return ReadTile(nRow, nCol, pabyData);
+}
+
+/************************************************************************/
+/*                           ReadTile()                                 */
+/************************************************************************/
+
+GByte* GDALGeoPackageDataset::ReadTile(int nRow, int nCol, GByte* pabyData,
+                                       int* pbIsLossyFormat)
+{
+    int rc;
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+    
+    if( pbIsLossyFormat ) *pbIsLossyFormat = FALSE;
+
+    if( nRow < 0 || nCol < 0 || nRow >= m_nTileMatrixHeight ||
+        nCol >= m_nTileMatrixWidth )
+    {
+        memset(pabyData, 0, nBands * nBlockXSize * nBlockYSize );
+        return pabyData;
+    }
+
+    //CPLDebug("GPKG", "For block (blocky=%d, blockx=%d) request tile (row=%d, col=%d)",
+    //         nBlockYOff, nBlockXOff, nRow, nCol);
+    char* pszSQL = sqlite3_mprintf("SELECT tile_data FROM '%q' "
+        "WHERE zoom_level = %d AND tile_row = %d AND tile_column = %d%s",
+        m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol,
+        m_osWHERE.size() ? CPLSPrintf(" AND (%s)", m_osWHERE.c_str()): "");
+#ifdef DEBUG_VERBOSE
+    CPLDebug("GPKG", "%s", pszSQL);
+#endif
+    sqlite3_stmt* hStmt = NULL;
+    rc = sqlite3_prepare(GetDB(), pszSQL, -1, &hStmt, NULL);
+    if ( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL: %s", pszSQL);
+        sqlite3_free(pszSQL);
+        return NULL;
+    }
+    sqlite3_free(pszSQL);
+    rc = sqlite3_step( hStmt );
+
+    if( rc == SQLITE_ROW && sqlite3_column_type( hStmt, 0 ) == SQLITE_BLOB )
+    {
+        const int nBytes = sqlite3_column_bytes( hStmt, 0 );
+        GByte* pabyRawData = (GByte*)sqlite3_column_blob( hStmt, 0 );
+        CPLString osMemFileName;
+        osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this);
+        VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData,
+                                                nBytes, FALSE);
+        VSIFCloseL(fp);
+
+        ReadTile(osMemFileName, pabyData, pbIsLossyFormat);
+        VSIUnlink(osMemFileName);
+        sqlite3_finalize(hStmt);
+    }
+    else
+    {
+        sqlite3_finalize(hStmt);
+        hStmt = NULL;
+
+        if( m_hTempDB && (m_nShiftXPixelsMod || m_nShiftYPixelsMod) )
+        {
+            const char* pszSQLNew = CPLSPrintf(
+                "SELECT partial_flag, tile_data_band_1, tile_data_band_2, "
+                "tile_data_band_3, tile_data_band_4 FROM partial_tiles WHERE "
+                "zoom_level = %d AND tile_row = %d AND tile_column = %d",
+                m_nZoomLevel, nRow, nCol);
+#ifdef DEBUG_VERBOSE
+            CPLDebug("GPKG", "%s", pszSQLNew);
+#endif
+            rc = sqlite3_prepare_v2(m_hTempDB, pszSQLNew, strlen(pszSQLNew), &hStmt, NULL);
+            if ( rc != SQLITE_OK )
+            {
+                memset(pabyData, 0, nBands * nBlockXSize * nBlockYSize );
+                CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare(%s) failed: %s",
+                        pszSQLNew, sqlite3_errmsg( m_hTempDB ) );
+                return pabyData;
+            }
+
+            rc = sqlite3_step(hStmt);
+            if ( rc == SQLITE_ROW )
+            {
+                int nPartialFlag = sqlite3_column_int(hStmt, 0);
+                for(int iBand = 1; iBand <= nBands; iBand ++ )
+                {
+                    GByte* pabyDestBand = pabyData + (iBand - 1) * nBlockXSize * nBlockYSize;
+                    if( nPartialFlag & (((1 << 4)-1) << (4 * (iBand - 1))) )
+                    {
+                        CPLAssert( sqlite3_column_bytes(hStmt, iBand) == nBlockXSize * nBlockYSize );
+                        memcpy( pabyDestBand,
+                                sqlite3_column_blob(hStmt, iBand),
+                                nBlockXSize * nBlockYSize );
+                    }
+                    else
+                    {
+                        memset(pabyDestBand, 0, nBlockXSize * nBlockYSize );
+                    }
+                }
+            }
+            else
+            {
+                memset(pabyData, 0, nBands * nBlockXSize * nBlockYSize );
+            }
+            sqlite3_finalize(hStmt);
+        }
+        else
+        {
+            memset(pabyData, 0, nBands * nBlockXSize * nBlockYSize );
+        }
+    }
+
+    return pabyData;
+}
+
+/************************************************************************/
+/*                         IReadBlock()                                 */
+/************************************************************************/
+
+CPLErr GDALGeoPackageRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
+                                            void* pData)
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    //CPLDebug("GPKG", "IReadBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d",
+    //         nBand,nBlockXOff,nBlockYOff);
+
+    int nRowMin = nBlockYOff + poGDS->m_nShiftYTiles;
+    int nRowMax = nRowMin;
+    if( poGDS->m_nShiftYPixelsMod )
+        nRowMax ++;
+    
+    int nColMin = nBlockXOff + poGDS->m_nShiftXTiles;
+    int nColMax = nColMin;
+    if( poGDS->m_nShiftXPixelsMod )
+        nColMax ++;
+
+    /* Optimize for left to right reading at constant row */
+    if( poGDS->m_nShiftXPixelsMod )
+    {
+        if( nRowMin == poGDS->m_asCachedTilesDesc[0].nRow &&
+            nColMin == poGDS->m_asCachedTilesDesc[0].nCol + 1 &&
+            poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData >= 0 )
+        {
+            CPLAssert(nRowMin == poGDS->m_asCachedTilesDesc[1].nRow);
+            CPLAssert(nColMin == poGDS->m_asCachedTilesDesc[1].nCol);
+            CPLAssert(poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 0 ||
+                      poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 1);
+
+            /* 0 1  --> 1 -1 */
+            /* 2 3      3 -1 */
+            /* or */
+            /* 1 0  --> 0 -1 */
+            /* 3 2      2 -1 */
+            poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = poGDS->m_asCachedTilesDesc[1].nIdxWithinTileData;
+            poGDS->m_asCachedTilesDesc[2].nIdxWithinTileData = poGDS->m_asCachedTilesDesc[3].nIdxWithinTileData;
+        }
+        else
+        {
+            poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = -1;
+            poGDS->m_asCachedTilesDesc[2].nIdxWithinTileData = -1;
+        }
+        poGDS->m_asCachedTilesDesc[0].nRow = nRowMin;
+        poGDS->m_asCachedTilesDesc[0].nCol = nColMin;
+        poGDS->m_asCachedTilesDesc[1].nRow = nRowMin;
+        poGDS->m_asCachedTilesDesc[1].nCol = nColMin + 1;
+        poGDS->m_asCachedTilesDesc[2].nRow = nRowMin + 1;
+        poGDS->m_asCachedTilesDesc[2].nCol = nColMin;
+        poGDS->m_asCachedTilesDesc[3].nRow = nRowMin + 1;
+        poGDS->m_asCachedTilesDesc[3].nCol = nColMin + 1;
+        poGDS->m_asCachedTilesDesc[1].nIdxWithinTileData = -1;
+        poGDS->m_asCachedTilesDesc[3].nIdxWithinTileData = -1;
+
+    }
+
+    for(int nRow = nRowMin; nRow <= nRowMax; nRow ++)
+    {
+        for(int nCol = nColMin; nCol <= nColMax; nCol++ )
+        {
+            GByte* pabyTileData = poGDS->ReadTile(nRow, nCol);
+            if( pabyTileData == NULL )
+                return CE_Failure;
+
+            for(int iBand=1;iBand<=poGDS->nBands;iBand++)
+            {
+                GDALRasterBlock* poBlock = NULL;
+                GByte* pabyDest;
+                if( iBand == nBand )
+                {
+                    pabyDest = (GByte*)pData;
+                }
+                else
+                {
+                    poBlock =
+                        poGDS->GetRasterBand(iBand)->GetLockedBlockRef(nBlockXOff, nBlockYOff, TRUE);
+                    if( poBlock == NULL )
+                        continue;
+                    if( poBlock->GetDirty() )
+                    {
+                        poBlock->DropLock();
+                        continue;
+                    }
+                    pabyDest = (GByte*) poBlock->GetDataRef();
+                }
+
+                // Composite tile data into block data
+                if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 )
+                {
+                    memcpy(pabyDest,
+                           pabyTileData + (iBand - 1) * nBlockXSize * nBlockYSize,
+                           nBlockXSize * nBlockYSize);
+                }
+                else
+                {
+                    int nSrcXOffset, nSrcXSize, nSrcYOffset, nSrcYSize;
+                    int nDstXOffset, nDstYOffset;
+                    if( nCol == nColMin )
+                    {
+                        nSrcXOffset = poGDS->m_nShiftXPixelsMod;
+                        nSrcXSize = nBlockXSize - poGDS->m_nShiftXPixelsMod;
+                        nDstXOffset = 0;
+                    }
+                    else
+                    {
+                        nSrcXOffset = 0;
+                        nSrcXSize = poGDS->m_nShiftXPixelsMod;
+                        nDstXOffset = nBlockXSize - poGDS->m_nShiftXPixelsMod;
+                    }
+                    if( nRow == nRowMin )
+                    {
+                        nSrcYOffset = poGDS->m_nShiftYPixelsMod;
+                        nSrcYSize = nBlockYSize - poGDS->m_nShiftYPixelsMod;
+                        nDstYOffset = 0;
+                    }
+                    else
+                    {
+                        nSrcYOffset = 0;
+                        nSrcYSize = poGDS->m_nShiftYPixelsMod;
+                        nDstYOffset = nBlockYSize - poGDS->m_nShiftYPixelsMod;
+                    }
+                    //CPLDebug("GPKG", "Copy source tile x=%d,w=%d,y=%d,h=%d into buffet at x=%d,y=%d",
+                    //         nSrcXOffset, nSrcXSize, nSrcYOffset, nSrcYSize, nDstXOffset, nDstYOffset);
+                    for( int y=0; y<nSrcYSize; y++ )
+                    {
+                        GByte* pSrc = pabyTileData + (iBand - 1) * nBlockXSize * nBlockYSize +
+                                        (y + nSrcYOffset) * nBlockXSize + nSrcXOffset;
+                        GByte* pDst = pabyDest + (y + nDstYOffset) * nBlockXSize + nDstXOffset;
+                        GDALCopyWords(pSrc, GDT_Byte, 1,
+                                      pDst, GDT_Byte, 1,
+                                      nSrcXSize);
+                    }
+                }
+
+                if( poBlock )
+                    poBlock->DropLock();
+
+            }
+        }
+    }
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                       WEBPSupports4Bands()                           */
+/************************************************************************/
+
+static int WEBPSupports4Bands()
+{
+    static int bRes = -1;
+    if( bRes < 0 )
+    {
+        GDALDriver* poDrv = (GDALDriver*) GDALGetDriverByName("WEBP");
+        if( poDrv == NULL || CSLTestBoolean(CPLGetConfigOption("GPKG_SIMUL_WEBP_3BAND", "FALSE")) )
+            bRes = FALSE;
+        else
+        {
+            // LOSSLESS and RGBA support appeared in the same version
+            bRes = strstr(poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST), "LOSSLESS") != NULL;
+        }
+        if( poDrv != NULL && !bRes )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                        "The version of WEBP available does not support 4-band RGBA");
+        }
+    }
+    return bRes;
+}
+
+/************************************************************************/
+/*                         WriteTile()                                  */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::WriteTile()
+{
+    CPLAssert(!m_bInWriteTile);
+    m_bInWriteTile = TRUE;
+    CPLErr eErr = WriteTileInternal();
+    m_bInWriteTile = FALSE;
+    return eErr;
+}
+
+/* should only be called by WriteTile() */
+CPLErr GDALGeoPackageDataset::WriteTileInternal()
+{
+    if( !(bUpdate && m_asCachedTilesDesc[0].nRow >= 0 &&
+          m_asCachedTilesDesc[0].nCol >= 0 &&
+          m_asCachedTilesDesc[0].nIdxWithinTileData == 0) )
+        return CE_None;
+
+    int nRow = m_asCachedTilesDesc[0].nRow;
+    int nCol = m_asCachedTilesDesc[0].nCol;
+
+    int bAllDirty = TRUE;
+    int bAllNonDirty = TRUE;
+    int i;
+    for(i=0;i<nBands;i++)
+    {
+        if( m_asCachedTilesDesc[0].abBandDirty[i] )
+            bAllNonDirty = FALSE;
+        else
+            bAllDirty = FALSE;
+    }
+    if( bAllNonDirty )
+        return CE_None;
+
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+
+    /* If all bands for that block are not dirty/written, we need to */
+    /* fetch the missing ones if the tile exists */
+    int bIsLossyFormat = FALSE;
+    if( !bAllDirty )
+    {
+        for(i=1;i<=3;i++)
+        {
+            m_asCachedTilesDesc[i].nRow = -1;
+            m_asCachedTilesDesc[i].nCol = -1;
+            m_asCachedTilesDesc[i].nIdxWithinTileData = -1;
+        }
+        ReadTile(nRow, nCol, m_pabyCachedTiles + 4 * nBlockXSize * nBlockYSize,
+                 &bIsLossyFormat);
+        for(i=0;i<nBands;i++)
+        {
+            if( !m_asCachedTilesDesc[0].abBandDirty[i] )
+            {
+                memcpy(m_pabyCachedTiles + i * nBlockXSize * nBlockYSize,
+                       m_pabyCachedTiles + (4 + i) * nBlockXSize * nBlockYSize,
+                       nBlockXSize * nBlockYSize);
+            }
+        }
+    }
+
+    /* Compute origin of tile in GDAL raster space */
+    int nXOff = (nCol - m_nShiftXTiles) * nBlockXSize - m_nShiftXPixelsMod; 
+    int nYOff = (nRow - m_nShiftYTiles) * nBlockYSize - m_nShiftYPixelsMod;
+
+    /* Assert that the tile at least intersects some of the GDAL raster space */
+    CPLAssert(nXOff + nBlockXSize > 0);
+    CPLAssert(nYOff + nBlockYSize > 0);
+    /* Can happen if the tile of the raster is less than the block size */
+    if( nXOff >= nRasterXSize || nYOff >= nRasterYSize )
+        return CE_None;
+
+    /* Validity area of tile data in intra-tile coordinate space */
+    int iXOff = 0;
+    int iYOff = 0;
+    int iXCount = nBlockXSize;
+    int iYCount = nBlockYSize;
+
+    int bPartialTile = FALSE;
+    int nAlphaBand = (nBands == 2) ? 2 : (nBands == 4) ? 4 : 0;
+    if( nAlphaBand == 0 )
+    {
+        if( nXOff < 0 )
+        {
+            bPartialTile = TRUE;
+            iXOff = -nXOff;
+            iXCount += nXOff;
+        }
+        if( nXOff + nBlockXSize > nRasterXSize )
+        {
+            bPartialTile = TRUE;
+            iXCount -= nXOff + nBlockXSize - nRasterXSize;
+        }
+        if( nYOff < 0 )
+        {
+            bPartialTile = TRUE;
+            iYOff = -nYOff;
+            iYCount += nYOff;
+        }
+        if( nYOff + nBlockYSize > nRasterYSize )
+        {
+            bPartialTile = TRUE;
+            iYCount -= nYOff + nBlockYSize - nRasterYSize;
+        }
+        CPLAssert(iXOff >= 0);
+        CPLAssert(iYOff >= 0);
+        CPLAssert(iXCount > 0);
+        CPLAssert(iYCount > 0);
+        CPLAssert(iXOff + iXCount <= nBlockXSize);
+        CPLAssert(iYOff + iYCount <= nBlockYSize);
+    }
+
+    m_asCachedTilesDesc[0].nRow = -1;
+    m_asCachedTilesDesc[0].nCol = -1;
+    m_asCachedTilesDesc[0].nIdxWithinTileData = -1;
+    m_asCachedTilesDesc[0].abBandDirty[0] = FALSE;
+    m_asCachedTilesDesc[0].abBandDirty[1] = FALSE;
+    m_asCachedTilesDesc[0].abBandDirty[2] = FALSE;
+    m_asCachedTilesDesc[0].abBandDirty[3] = FALSE;
+
+    CPLErr eErr = CE_Failure;
+
+    int bAllOpaque = TRUE;
+    if( m_poCT == NULL && nAlphaBand != 0 )
+    {
+        GByte byFirstAlphaVal =  m_pabyCachedTiles[(nAlphaBand-1) * nBlockXSize * nBlockYSize];
+        for(i=1;i<nBlockXSize * nBlockYSize;i++)
+        {
+            if( m_pabyCachedTiles[(nAlphaBand-1) * nBlockXSize * nBlockYSize + i] != byFirstAlphaVal )
+                break;
+        }
+        if( i == nBlockXSize * nBlockYSize )
+        {
+            // If tile is fully transparent, don't serialize it and remove it if it exists
+            if( byFirstAlphaVal == 0 )
+            {
+                char* pszSQL = sqlite3_mprintf("DELETE FROM '%q' "
+                    "WHERE zoom_level = %d AND tile_row = %d AND tile_column = %d",
+                    m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol);
+#ifdef DEBUG_VERBOSE
+                CPLDebug("GPKG", "%s", pszSQL);
+#endif
+                char* pszErrMsg = NULL;
+                int rc = sqlite3_exec(GetDB(), pszSQL, NULL, NULL, &pszErrMsg);
+                if( rc == SQLITE_OK )
+                    eErr = CE_None;
+                else
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                            "Failure when deleting tile (row=%d,col=%d) at zoom_level=%d : %s",
+                            nRow, nCol, m_nZoomLevel, pszErrMsg ? pszErrMsg : "");
+                sqlite3_free(pszSQL);
+                sqlite3_free(pszErrMsg);
+                return CE_None;
+            }
+            bAllOpaque = (byFirstAlphaVal == 255);
+        }
+        else
+            bAllOpaque = FALSE;
+    }
+
+    if( bIsLossyFormat )
+    {
+        CPLDebug("GPKG", "Had to read tile (row=%d,col=%d) at zoom_level=%d, "
+                 "stored in a lossy format, before rewriting it, causing potential extra quality loss",
+                 nRow, nCol, m_nZoomLevel);
+    }
+
+    CPLString osMemFileName;
+    osMemFileName.Printf("/vsimem/gpkg_write_tile_%p", this);
+    const char* pszDriverName = "PNG";
+    int bTileDriverSupports1Band = FALSE;
+    int bTileDriverSupports2Bands = FALSE;
+    int bTileDriverSupports4Bands = FALSE;
+    int bTileDriverSupportsCT = FALSE;
+    
+    if( nBands == 1 )
+        GetRasterBand(1)->GetColorTable();
+    
+    if( m_eTF == GPKG_TF_PNG_JPEG )
+    {
+        bTileDriverSupports1Band = TRUE;
+        if( bPartialTile || (nBands == 2 && !bAllOpaque) || (nBands == 4 && !bAllOpaque) || m_poCT != NULL )
+        {
+            pszDriverName = "PNG";
+            bTileDriverSupports2Bands = TRUE;
+            bTileDriverSupports4Bands = TRUE;
+            bTileDriverSupportsCT = TRUE;
+        }
+        else
+            pszDriverName = "JPEG";
+    }
+    else if( m_eTF == GPKG_TF_PNG ||
+             m_eTF == GPKG_TF_PNG8 )
+    {
+        pszDriverName = "PNG";
+        bTileDriverSupports1Band = TRUE;
+        bTileDriverSupports2Bands = TRUE;
+        bTileDriverSupports4Bands = TRUE;
+        bTileDriverSupportsCT = TRUE;
+    }
+    else if( m_eTF == GPKG_TF_JPEG )
+    {
+        pszDriverName = "JPEG";
+        bTileDriverSupports1Band = TRUE;
+    }
+    else if( m_eTF == GPKG_TF_WEBP )
+    {
+        pszDriverName = "WEBP";
+        bTileDriverSupports4Bands = WEBPSupports4Bands();
+    }
+    else
+        CPLAssert(0);
+
+    GDALDriver* poDriver = (GDALDriver*) GDALGetDriverByName(pszDriverName);
+    if( poDriver != NULL)
+    {
+        GDALDataset* poMEMDS = MEMDataset::Create("", nBlockXSize, nBlockYSize,
+                                                  0, GDT_Byte, NULL);
+        int nTileBands = nBands;
+        if( bPartialTile && nBands == 1 && m_poCT == NULL && bTileDriverSupports2Bands )
+            nTileBands = 2;
+        else if( bPartialTile && bTileDriverSupports4Bands )
+            nTileBands = 4;
+        else if( m_eTF == GPKG_TF_PNG8 && nBands >= 3 && bAllOpaque && !bPartialTile )
+            nTileBands = 1;
+        else if( nBands == 2 )
+        {
+            if ( bAllOpaque )
+            {
+                if (bTileDriverSupports2Bands )
+                    nTileBands = 1;
+                else
+                    nTileBands = 3;
+            }
+            else if( !bTileDriverSupports2Bands )
+            {
+                if( bTileDriverSupports4Bands )
+                    nTileBands = 4;
+                else
+                    nTileBands = 3;
+            }
+        }
+        else if( nBands == 4 && (bAllOpaque || !bTileDriverSupports4Bands) )
+            nTileBands = 3;
+        else if( nBands == 1 && m_poCT != NULL && !bTileDriverSupportsCT )
+        {
+            nTileBands = 3;
+            if( bTileDriverSupports4Bands )
+            {
+                for(i=0;i<m_poCT->GetColorEntryCount();i++)
+                {
+                    const GDALColorEntry* psEntry = m_poCT->GetColorEntry(i);
+                    if( psEntry->c4 == 0 )
+                    {
+                        nTileBands = 4;
+                        break;
+                    }
+                }
+            }
+        }
+        else if( nBands == 1 && m_poCT == NULL && !bTileDriverSupports1Band )
+            nTileBands = 3;
+
+        if( bPartialTile && (nTileBands == 2 || nTileBands == 4) )
+        {
+            int nTargetAlphaBand = nTileBands;
+            memset(m_pabyCachedTiles + (nTargetAlphaBand-1) * nBlockXSize * nBlockYSize, 0,
+                  nBlockXSize * nBlockYSize);
+            for(int iY = iYOff; iY < iYOff + iYCount; iY ++)
+            {
+                memset(m_pabyCachedTiles + ((nTargetAlphaBand-1) * nBlockYSize + iY) * nBlockXSize + iXOff,
+                       255, iXCount);
+            }
+        }
+
+        for(i=0;i<nTileBands;i++)
+        {
+            char** papszOptions = NULL;
+            char szDataPointer[32];
+            int iSrc = i;
+            if( nBands == 1 && m_poCT == NULL && nTileBands == 3 )
+                iSrc = 0;
+            else if( nBands == 1 && m_poCT == NULL && bPartialTile && nTileBands == 4 )
+                iSrc = (i < 3) ? 0 : 3;
+            else if( nBands == 2 && nTileBands >= 3 )
+                iSrc = (i < 3) ? 0 : 1;
+            int nRet = CPLPrintPointer(szDataPointer,
+                                       m_pabyCachedTiles + iSrc * nBlockXSize * nBlockYSize,
+                                       sizeof(szDataPointer));
+            szDataPointer[nRet] = '\0';
+            papszOptions = CSLSetNameValue(papszOptions, "DATAPOINTER", szDataPointer);
+            poMEMDS->AddBand(GDT_Byte, papszOptions);
+            if( i == 0 && nTileBands == 1 && m_poCT != NULL )
+                poMEMDS->GetRasterBand(1)->SetColorTable(m_poCT);
+            CSLDestroy(papszOptions);
+        }
+
+        if( m_eTF == GPKG_TF_PNG8 && nTileBands == 1 && nBands >= 3 )
+        {
+            GDALDataset* poMEM_RGB_DS = MEMDataset::Create("", nBlockXSize, nBlockYSize,
+                                                  0, GDT_Byte, NULL);
+            for(i=0;i<3;i++)
+            {
+                char** papszOptions = NULL;
+                char szDataPointer[32];
+                int nRet = CPLPrintPointer(szDataPointer,
+                                        m_pabyCachedTiles + i * nBlockXSize * nBlockYSize,
+                                        sizeof(szDataPointer));
+                szDataPointer[nRet] = '\0';
+                papszOptions = CSLSetNameValue(papszOptions, "DATAPOINTER", szDataPointer);
+                poMEM_RGB_DS->AddBand(GDT_Byte, papszOptions);
+                CSLDestroy(papszOptions);
+            }
+            
+            if( m_pabyHugeColorArray == NULL )
+            {
+                if( nBlockXSize * nBlockYSize <= 65536 )
+                    m_pabyHugeColorArray = (GByte*) VSIMalloc(MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536);
+                else
+                    m_pabyHugeColorArray = (GByte*) VSIMalloc2(256 * 256 * 256, sizeof(int));
+            }
+
+            GDALColorTable* poCT = new GDALColorTable();
+            GDALComputeMedianCutPCTInternal( poMEM_RGB_DS->GetRasterBand(1),
+                                       poMEM_RGB_DS->GetRasterBand(2),
+                                       poMEM_RGB_DS->GetRasterBand(3),
+                                       /*NULL, NULL, NULL,*/
+                                       m_pabyCachedTiles,
+                                       m_pabyCachedTiles + nBlockXSize * nBlockYSize,
+                                       m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize,
+                                       NULL,
+                                       256, /* max colors */
+                                       8, /* bit depth */
+                                       (int*)m_pabyHugeColorArray, /* preallocated histogram */
+                                       poCT,
+                                       NULL, NULL );
+
+            GDALDitherRGB2PCTInternal( poMEM_RGB_DS->GetRasterBand(1),
+                               poMEM_RGB_DS->GetRasterBand(2),
+                               poMEM_RGB_DS->GetRasterBand(3),
+                               poMEMDS->GetRasterBand(1), 
+                               poCT,
+                               8, /* bit depth */
+                               (GInt16*)m_pabyHugeColorArray, /* pasDynamicColorMap */
+                               m_bDither,
+                               NULL, NULL );
+            poMEMDS->GetRasterBand(1)->SetColorTable(poCT);
+            delete poCT;
+            GDALClose( poMEM_RGB_DS );
+        }
+        else if( nBands == 1 && m_poCT != NULL && nTileBands > 1 )
+        {
+            GByte abyCT[4*256];
+            int nEntries = MIN(256, m_poCT->GetColorEntryCount());
+            for(i=0;i<nEntries;i++)
+            {
+                const GDALColorEntry* psEntry = m_poCT->GetColorEntry(i);
+                abyCT[4*i] = (GByte)psEntry->c1;
+                abyCT[4*i+1] = (GByte)psEntry->c2;
+                abyCT[4*i+2] = (GByte)psEntry->c3;
+                abyCT[4*i+3] = (GByte)psEntry->c4;
+            }
+            for(;i<256;i++)
+            {
+                abyCT[4*i] = 0;
+                abyCT[4*i+1] = 0;
+                abyCT[4*i+2] = 0;
+                abyCT[4*i+3] = 0;
+            }
+            if( iYOff > 0 )
+            {
+                memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff);
+                memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff);
+                memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff);
+                memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff);
+            }
+            for(int iY = iYOff; iY < iYOff + iYCount; iY ++)
+            {
+                if( iXOff > 0 )
+                {
+                    i = iY * nBlockXSize;
+                    memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, iXOff);
+                    memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, iXOff);
+                    memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, iXOff);
+                    memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, iXOff);
+                }
+                for(int iX = iXOff; iX < iXOff + iXCount; iX ++)
+                {
+                    i = iY * nBlockXSize + iX;
+                    GByte byVal = m_pabyCachedTiles[i];
+                    m_pabyCachedTiles[i] = abyCT[4*byVal];
+                    m_pabyCachedTiles[i + 1 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+1];
+                    m_pabyCachedTiles[i + 2 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+2];
+                    m_pabyCachedTiles[i + 3 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+3];
+                }
+                if( iXOff + iXCount < nBlockXSize )
+                {
+                    i = iY * nBlockXSize + iXOff + iXCount;
+                    memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount));
+                    memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount));
+                    memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount));
+                    memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount));
+                }
+            }
+            if( iYOff + iYCount < nBlockYSize )
+            {
+                i = (iYOff + iYCount) * nBlockXSize;
+                memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount)));
+                memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount)));
+                memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount)));
+                memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount)));
+            }
+        }
+
+        char** papszDriverOptions = CSLSetNameValue(NULL, "_INTERNAL_DATASET", "YES");
+        if( EQUAL(pszDriverName, "JPEG") || EQUAL(pszDriverName, "WEBP") )
+        {
+            papszDriverOptions = CSLSetNameValue(
+                papszDriverOptions, "QUALITY", CPLSPrintf("%d", m_nQuality));
+        }
+        else if( EQUAL(pszDriverName, "PNG") )
+        {
+            papszDriverOptions = CSLSetNameValue(
+                papszDriverOptions, "ZLEVEL", CPLSPrintf("%d", m_nZLevel));
+        }
+#ifdef DEBUG
+        VSIStatBufL sStat;
+        CPLAssert(VSIStatL(osMemFileName, &sStat) != 0);
+#endif
+        GDALDataset* poOutDS = poDriver->CreateCopy(osMemFileName, poMEMDS,
+                                                    FALSE, papszDriverOptions, NULL, NULL);
+        CSLDestroy( papszDriverOptions );
+        if( poOutDS )
+        {
+            GDALClose( poOutDS );
+            vsi_l_offset nBlobSize;
+            GByte* pabyBlob = VSIGetMemFileBuffer(osMemFileName, &nBlobSize, TRUE);
+
+            /* Create or commit and recreate transaction */
+            GDALGeoPackageDataset* poMainDS = m_poParentDS ? m_poParentDS : this;
+            if( poMainDS->m_nTileInsertionCount == 0 )
+            {
+                poMainDS->SoftStartTransaction();
+            }
+            else if( poMainDS->m_nTileInsertionCount == 1000 )
+            {
+                poMainDS->SoftCommitTransaction();
+                poMainDS->SoftStartTransaction();
+                poMainDS->m_nTileInsertionCount = 0;
+            }
+            poMainDS->m_nTileInsertionCount ++;
+
+            char* pszSQL = sqlite3_mprintf("INSERT OR REPLACE INTO '%q' "
+                "(zoom_level, tile_row, tile_column, tile_data) VALUES (%d, %d, %d, ?)",
+                m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol);
+#ifdef DEBUG_VERBOSE
+            CPLDebug("GPKG", "%s", pszSQL);
+#endif
+            sqlite3_stmt* hStmt = NULL;
+            int rc = sqlite3_prepare(GetDB(), pszSQL, -1, &hStmt, NULL);
+            if ( rc != SQLITE_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL %s: %s",
+                          pszSQL, sqlite3_errmsg(hDB) );
+                CPLFree(pabyBlob);
+            }
+            else
+            {
+                sqlite3_bind_blob( hStmt, 1, pabyBlob, (int)nBlobSize, CPLFree);
+                rc = sqlite3_step( hStmt );
+                if( rc == SQLITE_DONE )
+                    eErr = CE_None;
+                else
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                             "Failure when inserting tile (row=%d,col=%d) at zoom_level=%d : %s",
+                             nRow, nCol, m_nZoomLevel, sqlite3_errmsg(GetDB()));
+                }
+            }
+            sqlite3_finalize(hStmt);
+            sqlite3_free(pszSQL);
+        }
+
+        VSIUnlink(osMemFileName);
+        delete poMEMDS;
+    }
+    else
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot find driver %s", pszDriverName);
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                     FlushRemainingShiftedTiles()                     */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::FlushRemainingShiftedTiles()
+{
+    if( m_hTempDB == NULL )
+        return CE_None;
+
+    for(int i=0;i<=3;i++)
+    {
+        m_asCachedTilesDesc[i].nRow = -1;
+        m_asCachedTilesDesc[i].nCol = -1;
+        m_asCachedTilesDesc[i].nIdxWithinTileData = -1;
+    }
+
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+
+    CPLString osSQL = "SELECT tile_row, tile_column, partial_flag";
+    for(int nBand = 1; nBand <= nBands; nBand++ )
+    {
+        osSQL += CPLSPrintf(", tile_data_band_%d", nBand);
+    }
+    osSQL += CPLSPrintf(" FROM partial_tiles WHERE "
+                        "zoom_level = %d AND partial_flag != 0",
+                        m_nZoomLevel);
+    const char* pszSQL = osSQL.c_str();
+
+#ifdef DEBUG_VERBOSE
+    CPLDebug("GPKG", "%s", pszSQL);
+#endif
+    sqlite3_stmt* hStmt = NULL;
+    int rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL);
+    if ( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare(%s) failed: %s",
+                  pszSQL, sqlite3_errmsg( m_hTempDB ) );
+        return CE_Failure;
+    }
+
+    CPLErr eErr = CE_None;
+    int bGotPartialTiles = FALSE;
+    do
+    {
+        int rc = sqlite3_step(hStmt);
+        if ( rc == SQLITE_ROW )
+        {
+            bGotPartialTiles = TRUE;
+
+            int nRow = sqlite3_column_int(hStmt, 0);
+            int nCol = sqlite3_column_int(hStmt, 1);
+            int nPartialFlags = sqlite3_column_int(hStmt, 2);
+            for( int nBand = 1; nBand <= nBands; nBand++ )
+            {
+                if( nPartialFlags & (((1 << 4)-1) << (4*(nBand - 1))) )
+                {
+                    CPLAssert( sqlite3_column_bytes(hStmt, 2 + nBand) == nBlockXSize * nBlockYSize );
+                    memcpy( m_pabyCachedTiles + (nBand-1) * nBlockXSize * nBlockYSize,
+                            sqlite3_column_blob(hStmt, 2 + nBand),
+                            nBlockXSize * nBlockYSize );
+                }
+                else
+                {
+                    memset( m_pabyCachedTiles + (nBand-1) * nBlockXSize * nBlockYSize,
+                            0,
+                            nBlockXSize * nBlockYSize );
+                }
+            }
+
+            int nFullFlags = (1 << (4 * nBands)) - 1;
+
+            // In case the partial flags indicate that there's some quadrant
+            // missing, check in the main database if there is already a tile
+            // In which case, use the parts of that tile that aren't in the
+            // temporary database
+            if( nPartialFlags != nFullFlags )
+            {
+                char* pszNewSQL = sqlite3_mprintf("SELECT tile_data FROM '%q' "
+                        "WHERE zoom_level = %d AND tile_row = %d AND tile_column = %d%s",
+                        m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol,
+                        m_osWHERE.size() ? CPLSPrintf(" AND (%s)", m_osWHERE.c_str()): "");
+#ifdef DEBUG_VERBOSE
+                CPLDebug("GPKG", "%s", pszNewSQL);
+#endif
+                sqlite3_stmt* hNewStmt = NULL;
+                rc = sqlite3_prepare(GetDB(), pszNewSQL, -1, &hNewStmt, NULL);
+                if ( rc == SQLITE_OK )
+                {
+                    rc = sqlite3_step( hNewStmt );
+                    if( rc == SQLITE_ROW && sqlite3_column_type( hNewStmt, 0 ) == SQLITE_BLOB )
+                    {
+                        const int nBytes = sqlite3_column_bytes( hNewStmt, 0 );
+                        GByte* pabyRawData = (GByte*)sqlite3_column_blob( hNewStmt, 0 );
+                        CPLString osMemFileName;
+                        osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this);
+                        VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData,
+                                                              nBytes, FALSE);
+                        VSIFCloseL(fp);
+
+                        int bIsLossyFormat;
+                        ReadTile(osMemFileName,
+                                 m_pabyCachedTiles + 4 * nBlockXSize * nBlockYSize,
+                                 &bIsLossyFormat);
+                        VSIUnlink(osMemFileName);
+
+                        int iYQuadrantMax = ( m_nShiftYPixelsMod ) ? 1 : 0;
+                        int iXQuadrantMax = ( m_nShiftXPixelsMod ) ? 1 : 0;
+                        for( int iYQuadrant = 0; iYQuadrant <= iYQuadrantMax; iYQuadrant ++ )
+                        {
+                            for( int iXQuadrant = 0; iXQuadrant <= iXQuadrantMax; iXQuadrant ++ )
+                            {
+                                for( int nBand = 1; nBand <= nBands; nBand ++ )
+                                {
+                                    int iQuadrantFlag = 0;
+                                    if( iXQuadrant == 0 && iYQuadrant == 0 )
+                                        iQuadrantFlag |= (1 << 0);
+                                    if( iXQuadrant == iXQuadrantMax && iYQuadrant == 0  )
+                                        iQuadrantFlag |= (1 << 1);
+                                    if( iXQuadrant == 0 && iYQuadrant == iYQuadrantMax )
+                                        iQuadrantFlag |= (1 << 2);
+                                    if( iXQuadrant == iXQuadrantMax && iYQuadrant == iYQuadrantMax )
+                                        iQuadrantFlag |= (1 << 3);
+                                    int nLocalFlag = iQuadrantFlag << (4 * (nBand - 1));
+                                    if( !(nPartialFlags & nLocalFlag) )
+                                    {
+                                        int nXOff, nYOff, nXSize, nYSize;
+                                        if( iXQuadrant == 0 && m_nShiftXPixelsMod != 0 )
+                                        {
+                                            nXOff = 0;
+                                            nXSize = m_nShiftXPixelsMod;
+                                        }
+                                        else
+                                        {
+                                            nXOff = m_nShiftXPixelsMod;
+                                            nXSize = nBlockXSize - m_nShiftXPixelsMod;
+                                        }
+                                        if( iYQuadrant == 0 && m_nShiftYPixelsMod != 0 )
+                                        {
+                                            nYOff = 0;
+                                            nYSize = m_nShiftYPixelsMod;
+                                        }
+                                        else
+                                        {
+                                            nYOff = m_nShiftYPixelsMod;
+                                            nYSize = nBlockYSize - m_nShiftYPixelsMod;
+                                        }
+                                        for( int iY = nYOff; iY < nYOff + nYSize; iY ++ )
+                                        {
+                                            memcpy( m_pabyCachedTiles + ((nBand - 1) * nBlockYSize + iY) * nBlockXSize + nXOff,
+                                                    m_pabyCachedTiles + ((4 + nBand - 1) * nBlockYSize + iY) * nBlockXSize + nXOff,
+                                                    nXSize );
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    sqlite3_finalize(hNewStmt);
+                }
+                sqlite3_free(pszNewSQL);
+            }
+
+            m_asCachedTilesDesc[0].nRow = nRow;
+            m_asCachedTilesDesc[0].nCol = nCol;
+            m_asCachedTilesDesc[0].nIdxWithinTileData = 0;
+            m_asCachedTilesDesc[0].abBandDirty[0] = TRUE;
+            m_asCachedTilesDesc[0].abBandDirty[1] = TRUE;
+            m_asCachedTilesDesc[0].abBandDirty[2] = TRUE;
+            m_asCachedTilesDesc[0].abBandDirty[3] = TRUE;
+
+            eErr = WriteTile();
+        }
+        else
+            break;
+    }
+    while( eErr == CE_None);
+
+    sqlite3_finalize(hStmt);
+
+    if( bGotPartialTiles )
+    {
+        pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, "
+                            "partial_flag = 0 WHERE zoom_level = %d AND partial_flag != 0",
+                            -1-m_nZoomLevel, m_nZoomLevel);
+#ifdef DEBUG_VERBOSE
+        CPLDebug("GPKG", "%s", pszSQL);
+#endif
+        SQLCommand(m_hTempDB, pszSQL);
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                         WriteShiftedTile()                           */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::WriteShiftedTile(int nRow, int nCol, int nBand,
+                                               int nDstXOffset, int nDstYOffset,
+                                               int nDstXSize, int nDstYSize)
+{
+    CPLAssert( m_nShiftXPixelsMod || m_nShiftYPixelsMod );
+    CPLAssert( nRow >= 0 );
+    CPLAssert( nCol >= 0 );
+    CPLAssert( nRow < m_nTileMatrixHeight );
+    CPLAssert( nCol < m_nTileMatrixWidth );
+
+    if( m_hTempDB == NULL &&
+        (m_poParentDS == NULL || m_poParentDS->m_hTempDB == NULL) )
+    {
+        const char* pszBaseFilename = m_poParentDS ?
+                m_poParentDS->m_pszFilename : m_pszFilename;
+        m_osTempDBFilename = CPLResetExtension(pszBaseFilename, "gpkg.tmp");
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        VSIUnlink(m_osTempDBFilename);
+        CPLPopErrorHandler();
+        m_hTempDB = NULL;
+        sqlite3_open(m_osTempDBFilename, &m_hTempDB);
+        if( m_hTempDB == NULL )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                        "Cannot create temporary database %s",
+                        m_osTempDBFilename.c_str());
+            return CE_Failure;
+        }
+        SQLCommand(m_hTempDB, "PRAGMA synchronous = OFF");
+        SQLCommand(m_hTempDB, "PRAGMA journal_mode = OFF");
+        SQLCommand(m_hTempDB, "CREATE TABLE partial_tiles("
+                                    "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+                                    "zoom_level INTEGER NOT NULL,"
+                                    "tile_column INTEGER NOT NULL,"
+                                    "tile_row INTEGER NOT NULL,"
+                                    "tile_data_band_1 BLOB,"
+                                    "tile_data_band_2 BLOB,"
+                                    "tile_data_band_3 BLOB,"
+                                    "tile_data_band_4 BLOB,"
+                                    "partial_flag INTEGER NOT NULL,"
+                                    "UNIQUE (zoom_level, tile_column, tile_row))" );
+        SQLCommand(m_hTempDB, "CREATE INDEX partial_tiles_partial_flag_idx "
+                                "ON partial_tiles(partial_flag)");
+
+        if( m_poParentDS != NULL )
+        {
+            m_poParentDS->m_osTempDBFilename = m_osTempDBFilename;
+            m_poParentDS->m_hTempDB = m_hTempDB;
+        }
+    }
+    if( m_poParentDS != NULL )
+        m_hTempDB = m_poParentDS->m_hTempDB;
+
+    int nBlockXSize, nBlockYSize;
+    GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
+
+    int iQuadrantFlag = 0;
+    if( nDstXOffset == 0 && nDstYOffset == 0 )
+        iQuadrantFlag |= (1 << 0);
+    if( nDstXOffset + nDstXSize == nBlockXSize && nDstYOffset == 0  )
+        iQuadrantFlag |= (1 << 1);
+    if( nDstXOffset == 0 && nDstYOffset + nDstYSize == nBlockYSize )
+        iQuadrantFlag |= (1 << 2);
+    if( nDstXOffset + nDstXSize == nBlockXSize && nDstYOffset + nDstYSize == nBlockYSize )
+        iQuadrantFlag |= (1 << 3);
+    int nFlags = iQuadrantFlag << (4 * (nBand - 1));
+    int nFullFlags = (1 << (4 * nBands)) - 1;
+    int nOldFlags = 0;
+
+    for(int i=1;i<=3;i++)
+    {
+        m_asCachedTilesDesc[i].nRow = -1;
+        m_asCachedTilesDesc[i].nCol = -1;
+        m_asCachedTilesDesc[i].nIdxWithinTileData = -1;
+    }
+
+    int nExistingId = 0;
+    const char* pszSQL = CPLSPrintf("SELECT id, partial_flag, tile_data_band_%d FROM partial_tiles WHERE "
+                                    "zoom_level = %d AND tile_row = %d AND tile_column = %d",
+                                    nBand, m_nZoomLevel, nRow, nCol);
+#ifdef DEBUG_VERBOSE
+    CPLDebug("GPKG", "%s", pszSQL);
+#endif
+    sqlite3_stmt* hStmt = NULL;
+    int rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL);
+    if ( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare(%s) failed: %s",
+                  pszSQL, sqlite3_errmsg( m_hTempDB ) );
+        return CE_Failure;
+    }
+
+    rc = sqlite3_step(hStmt);
+    if ( rc == SQLITE_ROW )
+    {
+        nExistingId = sqlite3_column_int(hStmt, 0);
+#ifdef DEBUG_VERBOSE
+        CPLDebug("GPKG", "Using partial_tile id=%d", nExistingId);
+#endif
+        nOldFlags = sqlite3_column_int(hStmt, 1);
+        CPLAssert(nOldFlags != 0);
+        if( (nOldFlags & (((1 << 4)-1) << (4*(nBand - 1)))) == 0 )
+        {
+            memset( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize,
+                    0,
+                    nBlockXSize * nBlockYSize );
+        }
+        else
+        {
+            CPLAssert( sqlite3_column_bytes(hStmt, 2) == nBlockXSize * nBlockYSize );
+            memcpy( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize,
+                    sqlite3_column_blob(hStmt, 2),
+                    nBlockXSize * nBlockYSize );
+        }
+    }
+    else
+    {
+        memset( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize,
+                0,
+                nBlockXSize * nBlockYSize );
+    }
+    sqlite3_finalize(hStmt);
+    hStmt = NULL;
+
+    /* Copy the updated rectangle into the full tile */
+    for(int iY = nDstYOffset; iY < nDstYOffset + nDstYSize; iY ++ )
+    {
+        memcpy( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize +
+                    iY * nBlockXSize + nDstXOffset,
+                m_pabyCachedTiles + (nBand - 1) * nBlockXSize * nBlockYSize +
+                    iY * nBlockXSize + nDstXOffset,
+                nDstXSize );
+    }
+
+#ifdef notdef
+    static int nCounter = 1;
+    GDALDataset* poLogDS = ((GDALDriver*)GDALGetDriverByName("GTiff"))->Create(
+                CPLSPrintf("/tmp/partial_band_%d_%d.tif", 1, nCounter++),
+                nBlockXSize, nBlockYSize, nBands, GDT_Byte, NULL);
+    poLogDS->RasterIO(GF_Write, 0, 0, nBlockXSize, nBlockYSize,
+                      m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize,
+                      nBlockXSize, nBlockYSize,
+                      GDT_Byte,
+                      1, NULL,
+                      0, 0, 0, NULL);
+    GDALClose(poLogDS);
+#endif
+
+    if( (nOldFlags & nFlags) != 0 )
+    {
+        CPLDebug("GPKG",
+                 "Rewriting quadrant %d of band %d of tile (row=%d,col=%d)",
+                 iQuadrantFlag, nBand, nRow, nCol);
+    }
+
+    nFlags |= nOldFlags;
+    if( nFlags == nFullFlags )
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("GPKG", "Got all quadrants for that tile");
+#endif
+        for( int iBand = 1; iBand <= nBands; iBand ++ )
+        {
+            if( iBand != nBand && nExistingId )
+            {
+                pszSQL = CPLSPrintf("SELECT tile_data_band_%d FROM partial_tiles WHERE "
+                                    "id = %d", iBand, nExistingId);
+#ifdef DEBUG_VERBOSE
+                CPLDebug("GPKG", "%s", pszSQL);
+#endif
+                hStmt = NULL;
+                rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL);
+                if ( rc != SQLITE_OK )
+                {
+                    CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare(%s) failed: %s",
+                            pszSQL, sqlite3_errmsg( m_hTempDB ) );
+                    return CE_Failure;
+                }
+
+                rc = sqlite3_step(hStmt);
+                if ( rc == SQLITE_ROW )
+                {
+                    CPLAssert( sqlite3_column_bytes(hStmt, 0) == nBlockXSize * nBlockYSize );
+                    memcpy( m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize,
+                            sqlite3_column_blob(hStmt, 0),
+                            nBlockXSize * nBlockYSize );
+                }
+                sqlite3_finalize(hStmt);
+                hStmt = NULL;
+            }
+            else
+            {
+                memcpy( m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize,
+                        m_pabyCachedTiles + (4 + iBand - 1) * nBlockXSize * nBlockYSize,
+                        nBlockXSize * nBlockYSize );
+            }
+        }
+
+        m_asCachedTilesDesc[0].nRow = nRow;
+        m_asCachedTilesDesc[0].nCol = nCol;
+        m_asCachedTilesDesc[0].nIdxWithinTileData = 0;
+        m_asCachedTilesDesc[0].abBandDirty[0] = TRUE;
+        m_asCachedTilesDesc[0].abBandDirty[1] = TRUE;
+        m_asCachedTilesDesc[0].abBandDirty[2] = TRUE;
+        m_asCachedTilesDesc[0].abBandDirty[3] = TRUE;
+
+        pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, "
+                            "partial_flag = 0 WHERE id = %d",
+                            -1-m_nZoomLevel, nExistingId);
+        SQLCommand(m_hTempDB, pszSQL);
+#ifdef DEBUG_VERBOSE
+        CPLDebug("GPKG", "%s", pszSQL);
+#endif
+        return WriteTile();
+    }
+
+    if( nExistingId == 0 )
+    {
+        OGRErr err;
+        pszSQL = CPLSPrintf("SELECT id FROM partial_tiles WHERE "
+                            "partial_flag = 0 AND zoom_level = %d "
+                            "AND tile_column = %d AND tile_row = %d",
+                            -1-m_nZoomLevel, nRow, nCol);
+#ifdef DEBUG_VERBOSE
+        CPLDebug("GPKG", "%s", pszSQL);
+#endif
+        nExistingId = SQLGetInteger(m_hTempDB, pszSQL, &err);
+        if( nExistingId == 0 )
+        {
+            pszSQL = "SELECT id FROM partial_tiles WHERE partial_flag = 0 LIMIT 1";
+#ifdef DEBUG_VERBOSE
+            CPLDebug("GPKG", "%s", pszSQL);
+#endif
+            nExistingId = SQLGetInteger(m_hTempDB, pszSQL, &err);
+        }
+    }
+
+    if( nExistingId == 0 )
+    {
+        pszSQL = CPLSPrintf("INSERT INTO partial_tiles "
+                "(zoom_level, tile_row, tile_column, tile_data_band_%d, partial_flag) VALUES (%d, %d, %d, ?, %d)",
+                nBand, m_nZoomLevel, nRow, nCol, nFlags);
+    }
+    else
+    {
+        pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, "
+                            "tile_row = %d, tile_column = %d, "
+                            "tile_data_band_%d = ?, partial_flag = %d WHERE id = %d",
+                            m_nZoomLevel, nRow, nCol, nBand, nFlags, nExistingId);
+    }
+#ifdef DEBUG_VERBOSE
+    CPLDebug("GPKG", "%s", pszSQL);
+#endif
+
+    hStmt = NULL;
+    rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, -1, &hStmt, NULL);
+    if ( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL %s: %s",
+                    pszSQL, sqlite3_errmsg(m_hTempDB) );
+        return CE_Failure;
+    }
+
+    sqlite3_bind_blob( hStmt, 1,
+                       m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize,
+                       nBlockXSize * nBlockYSize,
+                       SQLITE_TRANSIENT );
+    rc = sqlite3_step( hStmt );
+    CPLErr eErr = CE_Failure;
+    if( rc == SQLITE_DONE )
+        eErr = CE_None;
+    else
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                    "Failure when inserting partial tile (row=%d,col=%d) at zoom_level=%d : %s",
+                    nRow, nCol, m_nZoomLevel, sqlite3_errmsg(m_hTempDB));
+    }
+
+    sqlite3_finalize(hStmt);
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                         IWriteBlock()                                */
+/************************************************************************/
+
+CPLErr GDALGeoPackageRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
+                                             void* pData)
+{
+    //CPLDebug("GPKG", "IWriteBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d",
+    //         nBand,nBlockXOff,nBlockYOff);
+
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( !poGDS->bUpdate )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "IWriteBlock() not supported on dataset opened in read-only mode");
+        return CE_Failure;
+    }
+
+    if( !poGDS->m_bGeoTransformValid || poGDS->m_nSRID == UNKNOWN_SRID )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "IWriteBlock() not supported if georeferencing not set");
+        return CE_Failure;
+    }
+
+    int nRow = nBlockYOff + poGDS->m_nShiftYTiles;
+    int nCol = nBlockXOff + poGDS->m_nShiftXTiles;
+
+    int nRowMin = nRow;
+    int nRowMax = nRowMin;
+    if( poGDS->m_nShiftYPixelsMod )
+        nRowMax ++;
+
+    int nColMin = nCol;
+    int nColMax = nColMin;
+    if( poGDS->m_nShiftXPixelsMod )
+        nColMax ++;
+
+    CPLErr eErr = CE_None;
+
+    for(nRow = nRowMin; eErr == CE_None && nRow <= nRowMax; nRow ++)
+    {
+        for(nCol = nColMin; eErr == CE_None && nCol <= nColMax; nCol++ )
+        {
+            if( nRow < 0 || nCol < 0 || nRow >= poGDS->m_nTileMatrixHeight ||
+                nCol >= poGDS->m_nTileMatrixWidth )
+            {
+                continue;
+            }
+
+            if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 )
+            {
+                if( !(nRow == poGDS->m_asCachedTilesDesc[0].nRow &&
+                    nCol == poGDS->m_asCachedTilesDesc[0].nCol &&
+                    poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 0) )
+                {
+                    eErr = poGDS->WriteTile();
+
+                    poGDS->m_asCachedTilesDesc[0].nRow = nRow;
+                    poGDS->m_asCachedTilesDesc[0].nCol = nCol;
+                    poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = 0;
+                }
+            }
+
+            // Composite block data into tile, and check if all bands for this block
+            // are dirty, and if so write the tile
+            int bAllDirty = TRUE;
+            for(int iBand=1;iBand<=poGDS->nBands;iBand++)
+            {
+                GDALRasterBlock* poBlock = NULL;
+                GByte* pabySrc;
+                if( iBand == nBand )
+                {
+                    pabySrc = (GByte*)pData;
+                }
+                else
+                {
+                    if( !(poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0) )
+                        continue;
+
+                    // If the block for this band is not dirty, it might be dirty in cache
+                    if( poGDS->m_asCachedTilesDesc[0].abBandDirty[iBand-1] )
+                        continue;
+                    else
+                    {
+                        poBlock =
+                            ((GDALGeoPackageRasterBand*)poGDS->GetRasterBand(iBand))->
+                                        TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
+                        if( poBlock && poBlock->GetDirty() )
+                        {
+                            pabySrc = (GByte*)poBlock->GetDataRef(),
+                            poBlock->MarkClean();
+                        }
+                        else
+                        {
+                            if( poBlock )
+                                poBlock->DropLock();
+                            bAllDirty = FALSE;
+                            continue;
+                        }
+                    }
+                }
+
+                if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 )
+                    poGDS->m_asCachedTilesDesc[0].abBandDirty[iBand - 1] = TRUE;
+
+                int nDstXOffset = 0, nDstXSize = nBlockXSize,
+                    nDstYOffset = 0, nDstYSize = nBlockYSize;
+                int nSrcXOffset = 0, nSrcYOffset = 0;
+                // Composite block data into tile data
+                if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 )
+                {
+                    memcpy( poGDS->m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize,
+                            pabySrc, nBlockXSize * nBlockYSize );
+                }
+                else
+                {
+                    if( nCol == nColMin )
+                    {
+                        nDstXOffset = poGDS->m_nShiftXPixelsMod;
+                        nDstXSize = nBlockXSize - poGDS->m_nShiftXPixelsMod;
+                        nSrcXOffset = 0;
+                    }
+                    else
+                    {
+                        nDstXOffset = 0;
+                        nDstXSize = poGDS->m_nShiftXPixelsMod;
+                        nSrcXOffset = nBlockXSize - poGDS->m_nShiftXPixelsMod;
+                    }
+                    if( nRow == nRowMin )
+                    {
+                        nDstYOffset = poGDS->m_nShiftYPixelsMod;
+                        nDstYSize = nBlockYSize - poGDS->m_nShiftYPixelsMod;
+                        nSrcYOffset = 0;
+                    }
+                    else
+                    {
+                        nDstYOffset = 0;
+                        nDstYSize = poGDS->m_nShiftYPixelsMod;
+                        nSrcYOffset = nBlockYSize - poGDS->m_nShiftYPixelsMod;
+                    }
+                    //CPLDebug("GPKG", "Copy source tile x=%d,w=%d,y=%d,h=%d into buffet at x=%d,y=%d",
+                    //         nDstXOffset, nDstXSize, nDstYOffset, nDstYSize, nSrcXOffset, nSrcYOffset);
+                    for( int y=0; y<nDstYSize; y++ )
+                    {
+                        GByte* pDst = poGDS->m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize +
+                                        (y + nDstYOffset) * nBlockXSize + nDstXOffset;
+                        GByte* pSrc = pabySrc + (y + nSrcYOffset) * nBlockXSize + nSrcXOffset;
+                        GDALCopyWords(pSrc, GDT_Byte, 1,
+                                    pDst, GDT_Byte, 1,
+                                    nDstXSize);
+                    }
+                }
+
+                if( poBlock )
+                    poBlock->DropLock();
+
+                if( !(poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0) )
+                {
+                    poGDS->m_asCachedTilesDesc[0].nRow = -1;
+                    poGDS->m_asCachedTilesDesc[0].nCol = -1;
+                    poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = -1;
+                    eErr = poGDS->WriteShiftedTile(nRow, nCol, iBand,
+                                                   nDstXOffset, nDstYOffset,
+                                                   nDstXSize, nDstYSize);
+                }
+            }
+
+            if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 )
+            {
+                if( bAllDirty ) 
+                {
+                    eErr = poGDS->WriteTile();
+                }
+            }
+        }
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                         GetOverviewCount()                           */
+/************************************************************************/
+
+int GDALGeoPackageRasterBand::GetOverviewCount()
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    return poGDS->m_nOverviewCount;
+}
+
+/************************************************************************/
+/*                         GetOverviewCount()                           */
+/************************************************************************/
+
+GDALRasterBand* GDALGeoPackageRasterBand::GetOverview(int nIdx)
+{
+    GDALGeoPackageDataset* poGDS = (GDALGeoPackageDataset* )poDS;
+    if( nIdx < 0 || nIdx >= poGDS->m_nOverviewCount )
+        return NULL;
+    return poGDS->m_papoOverviewDS[nIdx]->GetRasterBand(nBand);
+}
diff --git a/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html b/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html
new file mode 100644
index 0000000..97364c2
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="utf-8" />
+  <title>GeoPackage 1.0 Extension - Aspatial Support</title>
+  <style>
+    .container{width:980px;margin-right:auto;margin-left:auto}.container:before,.container:after{content:" ";display:table}.container:after{clear:both}#site-container>.container:first-child{margin-top:20px}/*! normalize.css v2.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-family:san [...]
+
+    ul.notification-routing strong{color:#000}ul.notification-routing .notification-email{float:right}ul.notification-routing .notification-email .edit-link{margin-right:10px;font-weight:bold}ul.notification-routing .notification-email input[type=text]{width:200px;padding:2px;color:#444}ul.notification-routing .notification-email form{display:none}ul.notification-routing .notification-email form .minibutton{float:none;margin:0}ul.notification-routing .notification-email.open form{display [...]
+
+    </style>
+  <style>
+    .previewPage {
+      margin: 64px auto;
+      width: 920px;
+    }
+  </style>
+</head>
+<body>
+  <div class="page">
+    <div class="previewPage">
+    <div id="readme" class="announce md">
+      <article class="markdown-body entry-content">
+        <h1>
+<a name="user-content-geopackage-10-extension" class="anchor" href="#geopackage-10-extension" aria-hidden="true"><span class="octicon octicon-link"></span></a>GeoPackage 1.0 Extension</h1>
+
+<p>Extension follows template from Annex I of the OGC <a href="http://www.geopackage.org/">GeoPackage 1.0 Specification</a>.</p>
+
+<h2>
+<a name="user-content-extension-title" class="anchor" href="#extension-title" aria-hidden="true"><span class="octicon octicon-link"></span></a>Extension Title</h2>
+
+<p>Aspatial Support</p>
+
+<h2>
+<a name="user-content-introduction" class="anchor" href="#introduction" aria-hidden="true"><span class="octicon octicon-link"></span></a>Introduction</h2>
+
+<p>Support for aspatial data (ie. SQLite tables/views without a geometry column), potentially with associated metadata.</p>
+
+<h2>
+<a name="user-content-extension-author" class="anchor" href="#extension-author" aria-hidden="true"><span class="octicon octicon-link"></span></a>Extension Author</h2>
+
+<p><a href="http://gdal.org">GDAL - Geospatial Data Abstraction Library</a>, author_name <code>gdal</code>.</p>
+
+<h2>
+<a name="user-content-extension-name-or-template" class="anchor" href="#extension-name-or-template" aria-hidden="true"><span class="octicon octicon-link"></span></a>Extension Name or Template</h2>
+
+<div class="highlight highlight-SQL"><pre><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">gpkg_extensions</span>
+  <span class="p">(</span><span class="k">table_name</span><span class="p">,</span> <span class="k">column_name</span><span class="p">,</span> <span class="n">extension_name</span><span class="p">,</span> <span class="n">definition</span><span class="p">,</span> <span class="k">scope</span><span class="p">)</span>
+<span class="k">VALUES</span>
+  <span class="p">(</span>
+    <span class="k">NULL</span><span class="p">,</span>
+    <span class="k">NULL</span><span class="p">,</span>
+    <span class="s1">'gdal_aspatial'</span><span class="p">,</span>
+    <span class="s1">'http://gdal.org/geopackage_aspatial.html'</span><span class="p">,</span>
+    <span class="s1">'read-write'</span>
+  <span class="p">);</span>
+</pre></div>
+
+<h2>
+<a name="user-content-extension-type" class="anchor" href="#extension-type" aria-hidden="true"><span class="octicon octicon-link"></span></a>Extension Type</h2>
+
+<p>Extension of Existing Requirement in Clause 2.</p>
+
+<h2>
+<a name="user-content-applicability" class="anchor" href="#applicability" aria-hidden="true"><span class="octicon octicon-link"></span></a>Applicability</h2>
+
+<p>This extension applies to any aspatial user data table or view specified in the <code>gpkg_contents</code> table with a lowercase <code>data_type</code> column value of "aspatial".</p>
+
+<h2>
+<a name="user-content-scope" class="anchor" href="#scope" aria-hidden="true"><span class="octicon octicon-link"></span></a>Scope</h2>
+
+<p>Read-write</p>
+
+<h2>
+<a name="user-content-requirements" class="anchor" href="#requirements" aria-hidden="true"><span class="octicon octicon-link"></span></a>Requirements</h2>
+
+<h3>
+<a name="user-content-geopackage" class="anchor" href="#geopackage" aria-hidden="true"><span class="octicon octicon-link"></span></a>GeoPackage</h3>
+
+<h4>
+<a name="user-content-contents-table---aspatial" class="anchor" href="#contents-table---aspatial" aria-hidden="true"><span class="octicon octicon-link"></span></a>Contents Table - Aspatial</h4>
+
+<p>The <code>gpkg_contents</code> table SHALL contain a row with a lowercase <code>data_type</code> column value of "aspatial" for each aspatial user data table or view.</p>
+
+<h4>
+<a name="user-content-user-data-tables" class="anchor" href="#user-data-tables" aria-hidden="true"><span class="octicon octicon-link"></span></a>User Data Tables</h4>
+
+<p>The second component of the SQL schema for aspatial tables in an Extended GeoPackage described in clause 'Contents Table - Aspatial' above are user tables or views that contain aspatial user data.</p>
+
+<p>An Extended GeoPackage with aspatial support is not required to contain any user data tables. User data tables MAY be empty.</p>
+
+<p>An Extended GeoPackage with aspatial support MAY contain tables or views. Every such aspatial table or view MAY have a column with column type INTEGER and PRIMARY KEY AUTOINCREMENT column constraints per EXAMPLE.</p>
+
+<table>
+<thead><tr>
+<th>Column Name</th>
+<th>Type</th>
+<th>Description</th>
+<th>Null</th>
+<th>Default</th>
+<th>Key</th>
+</tr></thead>
+<tbody>
+<tr>
+<td><code>id</code></td>
+<td>INTEGER</td>
+<td>Autoincrement primary key</td>
+<td>no</td>
+<td></td>
+<td>PK</td>
+</tr>
+<tr>
+<td><code>text_attribute</code></td>
+<td>TEXT</td>
+<td>Text attribute of row</td>
+<td>yes</td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td><code>real_attribute</code></td>
+<td>REAL</td>
+<td>Real attribute of row</td>
+<td>yes</td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td><code>boolean_attribute</code></td>
+<td>BOOLEAN</td>
+<td>Boolean attribute of row</td>
+<td>yes</td>
+<td></td>
+<td></td>
+</tr>
+<tr>
+<td><code>raster_or_photo</code></td>
+<td>BLOB</td>
+<td>Photograph</td>
+<td>yes</td>
+<td></td>
+<td></td>
+</tr>
+</tbody>
+</table><p>An integer primary key of an aspatial table or view allows features to be linked to row level metadata records in the <code>gpkg_metadata</code> table by <a href="http://www.sqlite.org/lang_createtable.html#rowid">rowid</a> values in the <code>gpkg_metadata_reference</code> table as described in clause 2.4.3 Metadata Reference Table.</p>
+
+<p>An aspatial table or view SHALL NOT have a geometry column.</p>
+
+<p>Columns in aspatial tables or views SHALL be defined using only the data types specified in Table 1 in Clause 1.1.1.1.3.</p>
+
+<h3>
+<a name="user-content-geopackage-sqlite-configuration" class="anchor" href="#geopackage-sqlite-configuration" aria-hidden="true"><span class="octicon octicon-link"></span></a>GeoPackage SQLite Configuration</h3>
+
+<p>None</p>
+
+<h3>
+<a name="user-content-geopackage-sqlite-extension" class="anchor" href="#geopackage-sqlite-extension" aria-hidden="true"><span class="octicon octicon-link"></span></a>GeoPackage SQLite Extension</h3>
+
+<p>None</p>
+      </article>
+    </div>
+  </div>
+
+  <div> </div>
+  </div><script>
+    function scrollToHash() {
+      if (location.hash && !document.querySelector(":target")) {
+        var elements = document.getElementsByName('user-content-' + location.hash.slice(1));
+        if (elements.length > 0) {
+          elements[elements.length - 1].scrollIntoView();
+        }
+      }
+    }
+    window.onhashchange = function() {
+      scrollToHash();
+    }
+    window.onload = function() {
+      scrollToHash();
+    }
+  </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.md b/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.md
new file mode 100644
index 0000000..e23c988
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/geopackage_aspatial.md
@@ -0,0 +1,80 @@
+# GeoPackage 1.0 Extension
+
+Extension follows template from Annex I of the OGC [GeoPackage 1.0 Specification](http://www.geopackage.org/).
+
+## Extension Title
+
+Aspatial Support
+
+## Introduction
+
+Support for aspatial data (ie. SQLite tables/views without a geometry column), potentially with associated metadata.
+
+## Extension Author
+
+[GDAL - Geospatial Data Abstraction Library](http://gdal.org), author_name `gdal`.
+
+## Extension Name or Template
+
+```SQL
+INSERT INTO gpkg_extensions
+  (table_name, column_name, extension_name, definition, scope)
+VALUES
+  (
+    NULL,
+    NULL,
+    'gdal_aspatial',
+    'http://gdal.org/geopackage_aspatial.html',
+    'read-write'
+  );
+```
+
+## Extension Type
+
+Extension of Existing Requirement in Clause 2.
+
+## Applicability
+
+This extension applies to any aspatial user data table or view specified in the `gpkg_contents` table with a lowercase `data_type` column value of "aspatial".
+
+## Scope
+
+Read-write
+
+## Requirements
+
+### GeoPackage
+
+#### Contents Table - Aspatial
+
+The `gpkg_contents` table SHALL contain a row with a lowercase `data_type` column value of "aspatial" for each aspatial user data table or view.
+
+#### User Data Tables
+
+The second component of the SQL schema for aspatial tables in an Extended GeoPackage described in clause 'Contents Table - Aspatial' above are user tables or views that contain aspatial user data.
+
+An Extended GeoPackage with aspatial support is not required to contain any user data tables. User data tables MAY be empty.
+
+An Extended GeoPackage with aspatial support MAY contain tables or views. Every such aspatial table or view MAY have a column with column type INTEGER and PRIMARY KEY AUTOINCREMENT column constraints per EXAMPLE.
+
+| Column Name         | Type    | Description               | Null | Default | Key |
+| ------------------- | ------- | ------------------------- | ---- | ------- | --- |
+| `id`                | INTEGER | Autoincrement primary key | no   |         | PK  |
+| `text_attribute`    | TEXT    | Text attribute of row     | yes  |         |     |
+| `real_attribute`    | REAL    | Real attribute of row     | yes  |         |     |
+| `boolean_attribute` | BOOLEAN | Boolean attribute of row  | yes  |         |     |
+| `raster_or_photo`   | BLOB    | Photograph                | yes  |         |     |
+
+An integer primary key of an aspatial table or view allows features to be linked to row level metadata records in the `gpkg_metadata` table by [rowid](http://www.sqlite.org/lang_createtable.html#rowid) values in the `gpkg_metadata_reference` table as described in clause 2.4.3 Metadata Reference Table.
+
+An aspatial table or view SHALL NOT have a geometry column.
+
+Columns in aspatial tables or views SHALL be defined using only the data types specified in Table 1 in Clause 1.1.1.1.3.
+
+### GeoPackage SQLite Configuration
+
+None
+
+### GeoPackage SQLite Extension
+
+None
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/gpkg/makefile.vc b/ogr/ogrsf_frmts/gpkg/makefile.vc
index 6cd8c0a..0a6dfb6 100644
--- a/ogr/ogrsf_frmts/gpkg/makefile.vc
+++ b/ogr/ogrsf_frmts/gpkg/makefile.vc
@@ -1,12 +1,17 @@
 
 OBJ	=	ogrgeopackagedriver.obj ogrgeopackagedatasource.obj \
-        ogrgeopackagelayer.obj ogrgeopackageutility.obj
+        ogrgeopackagelayer.obj ogrgeopackagetablelayer.obj ogrgeopackageselectlayer.obj ogrgeopackageutility.obj \
+        gdalgeopackagerasterband.obj
 
 GDAL_ROOT	=	..\..\..
 
 !INCLUDE $(GDAL_ROOT)\nmake.opt
 
-EXTRAFLAGS = -I.. -I..\.. $(SQLITE_INC) $(SPATIALITE_412_OR_LATER_EXTRAFLAGS)
+EXTRAFLAGS = -I.. -I..\.. -I..\sqlite  -I..\..\..\frmts\mem $(SQLITE_INC) $(SQLITE_HAS_COLUMN_METADATA_EXTRAFLAGS) $(SPATIALITE_412_OR_LATER_EXTRAFLAGS)
+
+!IFDEF SQLITE_HAS_COLUMN_METADATA
+SQLITE_HAS_COLUMN_METADATA_EXTRAFLAGS = -DSQLITE_HAS_COLUMN_METADATA
+!ENDIF
 
 !IFDEF SPATIALITE_412_OR_LATER
 SPATIALITE_412_OR_LATER_EXTRAFLAGS = -DSPATIALITE_412_OR_LATER
diff --git a/ogr/ogrsf_frmts/gpkg/ogr_geopackage.h b/ogr/ogrsf_frmts/gpkg/ogr_geopackage.h
index 15133fd..e86709b 100644
--- a/ogr/ogrsf_frmts/gpkg/ogr_geopackage.h
+++ b/ogr/ogrsf_frmts/gpkg/ogr_geopackage.h
@@ -31,149 +31,492 @@
 #define _OGR_GEOPACKAGE_H_INCLUDED
 
 #include "ogrsf_frmts.h"
-#include "sqlite3.h"
+#include "ogr_sqlite.h"
+#include "ogrgeopackageutility.h"
 
-#define UNDEFINED_SRID 0
+#define UNKNOWN_SRID   -2
+#define DEFAULT_SRID    0
 
 /************************************************************************/
-/*                           OGRGeoPackageDriver                        */
+/*                          GDALGeoPackageDataset                       */
 /************************************************************************/
 
-class OGRGeoPackageDriver : public OGRSFDriver
-{
-    public:
-                            ~OGRGeoPackageDriver();
-        const char*         GetName();
-        OGRDataSource*      Open( const char *, int );
-        OGRDataSource*      CreateDataSource( const char * pszFilename, char **papszOptions );
-        OGRErr              DeleteDataSource( const char * pszFilename );
-        int                 TestCapability( const char * );
-};
+class OGRGeoPackageTableLayer;
 
+typedef struct
+{
+    int     nRow;
+    int     nCol;
+    int     nIdxWithinTileData;
+    int     abBandDirty[4];
+} CachedTileDesc;
 
-/************************************************************************/
-/*                           OGRGeoPackageDataSource                    */
-/************************************************************************/
+typedef enum
+{
+    GPKG_TF_PNG_JPEG,
+    GPKG_TF_PNG,
+    GPKG_TF_PNG8,
+    GPKG_TF_JPEG,
+    GPKG_TF_WEBP
+} GPKGTileFormat;
 
-class OGRGeoPackageDataSource : public OGRDataSource
+class GDALGeoPackageDataset : public OGRSQLiteBaseDataSource
 {
-    char*               m_pszFileName;
-    OGRLayer**          m_papoLayers;
+    friend class GDALGeoPackageRasterBand;
+    friend class OGRGeoPackageTableLayer;
+
+    OGRGeoPackageTableLayer** m_papoLayers;
     int                 m_nLayers;
-    int                 m_bUpdate;
     int                 m_bUtf8;
-    sqlite3*            m_poDb;
+    void                CheckUnknownExtensions(int bCheckRasterTable = FALSE);
     
+    int                 m_bNew;
+
+    CPLString           m_osRasterTable;
+    CPLString           m_osIdentifier;
+    int                 m_bIdentifierAsCO;
+    CPLString           m_osDescription;
+    int                 m_bDescriptionAsCO;
+    int                 m_bHasReadMetadataFromStorage;
+    int                 m_bMetadataDirty;
+    char              **m_papszSubDatasets;
+    char               *m_pszProjection;
+    int                 m_bRecordInsertedInGPKGContent;
+    int                 m_bGeoTransformValid;
+    double              m_adfGeoTransform[6];
+    int                 m_nSRID;
+    double              m_dfTMSMinX;
+    double              m_dfTMSMaxY;
+    int                 m_nZoomLevel;
+    GByte              *m_pabyCachedTiles;
+    CachedTileDesc      m_asCachedTilesDesc[4];
+    int                 m_nShiftXTiles;
+    int                 m_nShiftXPixelsMod;
+    int                 m_nShiftYTiles;
+    int                 m_nShiftYPixelsMod;
+    int                 m_nTileMatrixWidth;
+    int                 m_nTileMatrixHeight;
+
+    GPKGTileFormat      m_eTF;
+    int                 m_nZLevel;
+    int                 m_nQuality;
+    int                 m_bDither;
+
+    GDALColorTable*     m_poCT;
+    int                 m_bTriedEstablishingCT;
+    GByte*              m_pabyHugeColorArray;
+
+    GDALGeoPackageDataset* m_poParentDS;
+    int                 m_nOverviewCount;
+    GDALGeoPackageDataset** m_papoOverviewDS;
+    int                 m_bZoomOther;
+
+    CPLString           m_osWHERE;
+
+    sqlite3            *m_hTempDB;
+    CPLString           m_osTempDBFilename;
     
+    int                 m_bInFlushCache;
+    
+    int                 m_nTileInsertionCount;
+
+    CPLString           m_osTilingScheme;
+
+        void            ComputeTileAndPixelShifts();
+        int             InitRaster ( GDALGeoPackageDataset* poParentDS,
+                                     const char* pszTableName,
+                                        double dfMinX,
+                                        double dfMinY,
+                                        double dfMaxX,
+                                        double dfMaxY,
+                                        const char* pszContentsMinX,
+                                        const char* pszContentsMinY,
+                                        const char* pszContentsMaxX,
+                                        const char* pszContentsMaxY,
+                                        char** papszOpenOptions,
+                                        const SQLResult& oResult,
+                                        int nIdxInResult );
+        int             InitRaster ( GDALGeoPackageDataset* poParentDS,
+                                     const char* pszTableName,
+                                        int nZoomLevel,
+                                        int nBandCount,
+                                        double dfTMSMinX,
+                                        double dfTMSMaxY,
+                                        double dfPixelXSize,
+                                        double dfPixelYSize,
+                                        int nTileWidth,
+                                        int nTileHeight,
+                                        int nTileMatrixWidth,
+                                        int nTileMatrixHeight,
+                                        double dfGDALMinX,
+                                        double dfGDALMinY,
+                                        double dfGDALMaxX,
+                                        double dfGDALMaxY );
+
+        int     OpenRaster( const char* pszTableName,
+                            const char* pszIdentifier,
+                            const char* pszDescription,
+                            int nSRSId,
+                            double dfMinX,
+                            double dfMinY,
+                            double dfMaxX,
+                            double dfMaxY,
+                            const char* pszContentsMinX,
+                            const char* pszContentsMinY,
+                            const char* pszContentsMaxX,
+                            const char* pszContentsMaxY,
+                            char** papszOptions );
+        CPLErr   FinalizeRasterRegistration();
+
+        CPLErr                  ReadTile(const CPLString& osMemFileName,
+                                         GByte* pabyTileData,
+                                         int* pbIsLossyFormat = NULL);
+        GByte*                  ReadTile(int nRow, int nCol);
+        GByte*                  ReadTile(int nRow, int nCol, GByte* pabyData,
+                                         int* pbIsLossyFormat = NULL);
+
+        int                     m_bInWriteTile;
+        CPLErr                  WriteTile();
+
+        CPLErr                  WriteTileInternal(); /* should only be called by WriteTile() */
+        CPLErr                  FlushRemainingShiftedTiles();
+        CPLErr                  WriteShiftedTile(int nRow, int nCol, int iBand,
+                                                 int nDstXOffset, int nDstYOffset,
+                                                 int nDstXSize, int nDstYSize);
+
+        int                     RegisterWebPExtension();
+        int                     RegisterZoomOtherExtension();
+        void                    ParseCompressionOptions(char** papszOptions);
+
+        int                     HasMetadataTables();
+        int                     CreateMetadataTables();
+        const char*             CheckMetadataDomain( const char* pszDomain );
+        void                    WriteMetadata(CPLXMLNode* psXMLNode, /* will be destroyed by the method /*/
+                                              const char* pszTableName);
+        CPLErr                  FlushMetadata();
+
     public:
-                            OGRGeoPackageDataSource();
-                            ~OGRGeoPackageDataSource();
+                            GDALGeoPackageDataset();
+                            ~GDALGeoPackageDataset();
+
+        virtual char **     GetMetadata( const char *pszDomain = NULL );
+        virtual const char *GetMetadataItem( const char * pszName,
+                                             const char * pszDomain = "" );
+        virtual char **     GetMetadataDomainList();
+        virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                         const char * pszDomain = "" );
+        virtual CPLErr      SetMetadataItem( const char * pszName,
+                                             const char * pszValue,
+                                             const char * pszDomain = "" );
+
+        virtual const char* GetProjectionRef();
+        virtual CPLErr      SetProjection( const char* pszProjection );
+
+        virtual CPLErr      GetGeoTransform( double* padfGeoTransform );
+        virtual CPLErr      SetGeoTransform( double* padfGeoTransform );
+
+        virtual void        FlushCache();
+        CPLErr              FlushCacheWithErrCode();
+        virtual CPLErr      IBuildOverviews( const char *, int, int *,
+                                             int, int *, GDALProgressFunc, void * );
 
-        virtual const char* GetName() { return m_pszFileName; }
         virtual int         GetLayerCount() { return m_nLayers; }
-        int                 Open( const char * pszFilename, int bUpdate );
-        int                 Create( const char * pszFilename, char **papszOptions );
+        int                 Open( GDALOpenInfo* poOpenInfo );
+        int                 Create( const char * pszFilename,
+                                    int nXSize,
+                                    int nYSize,
+                                    int nBands,
+                                    GDALDataType eDT,
+                                    char **papszOptions );
         OGRLayer*           GetLayer( int iLayer );
         int                 DeleteLayer( int iLayer );
-        OGRLayer*           CreateLayer( const char * pszLayerName,
+        OGRLayer*           ICreateLayer( const char * pszLayerName,
                                          OGRSpatialReference * poSpatialRef,
                                          OGRwkbGeometryType eGType,
                                          char **papszOptions );
         int                 TestCapability( const char * );
+        
+        virtual std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> GetLayerWithGetSpatialWhereByName( const char* pszName );
 
         virtual OGRLayer *  ExecuteSQL( const char *pszSQLCommand,
                                         OGRGeometry *poSpatialFilter,
                                         const char *pszDialect );
         virtual void        ReleaseResultSet( OGRLayer * poLayer );
 
-        int                 IsUpdatable() { return m_bUpdate; }
+        virtual OGRErr      CommitTransaction();
+        virtual OGRErr      RollbackTransaction();
+
         int                 GetSrsId( const OGRSpatialReference * poSRS );
         const char*         GetSrsName( const OGRSpatialReference * poSRS );
         OGRSpatialReference* GetSpatialRef( int iSrsId );
-        sqlite3*            GetDatabaseHandle();
         virtual int         GetUTF8() { return m_bUtf8; }
-        OGRErr              AddColumn( const char * pszTableName, 
-                                       const char * pszColumnName, 
-                                       const char * pszColumnType );
+        OGRErr              CreateExtensionsTableIfNecessary();
+        int                 HasExtensionsTable();
+        OGRErr              CreateGDALAspatialExtension();
+        void                SetMetadataDirty() { m_bMetadataDirty = TRUE; }
+
+        const char*         GetGeometryTypeString(OGRwkbGeometryType eType);
 
+        static GDALDataset* CreateCopy( const char *pszFilename,
+                                                   GDALDataset *poSrcDS, 
+                                                   int bStrict,
+                                                   char ** papszOptions,
+                                                   GDALProgressFunc pfnProgress, 
+                                                   void * pProgressData );
     private:
     
         OGRErr              PragmaCheck(const char * pszPragma, const char * pszExpected, int nRowsExpected);
-        bool                CheckApplicationId(const char * pszFileName);
         OGRErr              SetApplicationId();
-    
+        int                 OpenOrCreateDB(int flags);
+        int                 HasGDALAspatialExtension();
 };
 
+/************************************************************************/
+/*                        GDALGeoPackageRasterBand                      */
+/************************************************************************/
+
+class GDALGeoPackageRasterBand: public GDALPamRasterBand
+{
+    public:
+
+                                GDALGeoPackageRasterBand(GDALGeoPackageDataset* poDS,
+                                                         int nBand,
+                                                         int nTileWidth, int nTileHeight);
+        
+        virtual CPLErr          IReadBlock(int nBlockXOff, int nBlockYOff,
+                                           void* pData);
+        virtual CPLErr          IWriteBlock(int nBlockXOff, int nBlockYOff,
+                                           void* pData);
+        virtual CPLErr          FlushCache();
+
+        virtual GDALColorTable* GetColorTable();
+        virtual CPLErr          SetColorTable(GDALColorTable* poCT);
+
+        virtual GDALColorInterp GetColorInterpretation();
+        virtual CPLErr          SetColorInterpretation( GDALColorInterp );
+
+        virtual int             GetOverviewCount();
+        virtual GDALRasterBand* GetOverview(int nIdx);
+};
 
 /************************************************************************/
 /*                           OGRGeoPackageLayer                         */
 /************************************************************************/
 
-class OGRGeoPackageLayer : public OGRLayer
+class OGRGeoPackageLayer : public OGRLayer, public IOGRSQLiteGetSpatialWhere
+{
+  protected:
+    GDALGeoPackageDataset *m_poDS;
+
+    OGRFeatureDefn*      m_poFeatureDefn;
+    int                  iNextShapeId;
+
+    sqlite3_stmt        *m_poQueryStatement;
+    int                  bDoStep;
+
+    char                *m_pszFidColumn;
+
+    int                 iFIDCol;
+    int                 iGeomCol;
+    int                *panFieldOrdinals;
+
+    void                ClearStatement();
+    virtual OGRErr      ResetStatement() = 0;
+    
+    void                BuildFeatureDefn( const char *pszLayerName,
+                                           sqlite3_stmt *hStmt );
+
+    OGRFeature*         TranslateFeature(sqlite3_stmt* hStmt);
+
+  public:
+
+                        OGRGeoPackageLayer(GDALGeoPackageDataset* poDS);
+                        ~OGRGeoPackageLayer();
+    /************************************************************************/
+    /* OGR API methods */
+
+    OGRFeature*         GetNextFeature();
+    const char*         GetFIDColumn();
+    void                ResetReading();
+    int                 TestCapability( const char * );
+    OGRFeatureDefn*     GetLayerDefn() { return m_poFeatureDefn; }
+
+    virtual int          HasFastSpatialFilter(CPL_UNUSED int iGeomCol) { return FALSE; }
+    virtual CPLString    GetSpatialWhere(CPL_UNUSED int iGeomCol,
+                                         CPL_UNUSED OGRGeometry* poFilterGeom) { return ""; }
+
+};
+
+/************************************************************************/
+/*                        OGRGeoPackageTableLayer                       */
+/************************************************************************/
+
+class OGRGeoPackageTableLayer : public OGRGeoPackageLayer
 {
     char*                       m_pszTableName;
-    char*                       m_pszFidColumn;
     int                         m_iSrs;
-    OGRGeoPackageDataSource*    m_poDS;
     OGREnvelope*                m_poExtent;
     CPLString                   m_soColumns;
     CPLString                   m_soFilter;
+    CPLString                   osQuery;
     OGRBoolean                  m_bExtentChanged;
-    OGRFeatureDefn*             m_poFeatureDefn;
-    sqlite3_stmt*               m_poQueryStatement;
     sqlite3_stmt*               m_poUpdateStatement;
+    int                         m_bInsertStatementWithFID;
     sqlite3_stmt*               m_poInsertStatement;
-    sqlite3_stmt*               m_poFidStatement;    
+    int                         bDeferedSpatialIndexCreation;
+    int                         m_bHasSpatialIndex;
+    int                         bDropRTreeTable;
+    int                         m_anHasGeometryExtension[wkbMultiSurface+1];
+    int                         m_bPreservePrecision;
+    int                         m_bTruncateFields;
+    int                         m_bDeferredCreation;
+    int                         m_iFIDAsRegularColumnIndex;
+    
+    CPLString                   m_osIdentifierLCO;
+    CPLString                   m_osDescriptionLCO;
+    int                         m_bHasReadMetadataFromStorage;
+
+    virtual OGRErr      ResetStatement();
+    
+    void                BuildWhere(void);
+    OGRErr              RegisterGeometryColumn();
     
     public:
     
-                        OGRGeoPackageLayer( OGRGeoPackageDataSource *poDS,
+                        OGRGeoPackageTableLayer( GDALGeoPackageDataset *poDS,
                                             const char * pszTableName );
-                        ~OGRGeoPackageLayer();
+                        ~OGRGeoPackageTableLayer();
 
     /************************************************************************/
     /* OGR API methods */
                         
-    OGRFeatureDefn*     GetLayerDefn() { return m_poFeatureDefn; }
     int                 TestCapability( const char * );
     OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK = TRUE );
+    OGRErr              CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
+                                         int bApproxOK = TRUE );
     void                ResetReading();
-	OGRErr				CreateFeature( OGRFeature *poFeater );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-    OGRErr              DeleteFeature(long nFID);
+	OGRErr              ICreateFeature( OGRFeature *poFeater );
+    OGRErr              ISetFeature( OGRFeature *poFeature );
+    OGRErr              DeleteFeature(GIntBig nFID);
+    virtual void        SetSpatialFilter( OGRGeometry * );
     OGRErr              SetAttributeFilter( const char *pszQuery );
     OGRErr              SyncToDisk();
     OGRFeature*         GetNextFeature();
-    OGRFeature*         GetFeature(long nFID);
-    const char*         GetFIDColumn();	
+    OGRFeature*         GetFeature(GIntBig nFID);
     OGRErr              StartTransaction();
     OGRErr              CommitTransaction();
     OGRErr              RollbackTransaction();
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
     
     // void                SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn );
 
-    OGRErr              ReadTableDefinition();
+    OGRErr              ReadTableDefinition(int bIsSpatial);
+    void                SetCreationParameters( OGRwkbGeometryType eGType,
+                                               const char* pszGeomColumnName,
+                                               int bGeomNullable,
+                                               OGRSpatialReference* poSRS,
+                                               const char* pszFIDColumnName,
+                                               const char* pszIdentifier,
+                                               const char* pszDescription );
+    void                SetDeferedSpatialIndexCreation( int bFlag )
+                                { bDeferedSpatialIndexCreation = bFlag; }
+
+    void                CreateSpatialIndexIfNecessary();
+    int                 CreateSpatialIndex();
+    int                 DropSpatialIndex(int bCalledFromSQLFunction = FALSE);
+
+    virtual char **     GetMetadata( const char *pszDomain = NULL );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                             const char * pszDomain = "" );
+    virtual char **     GetMetadataDomainList();
+
+    virtual CPLErr      SetMetadata( char ** papszMetadata,
+                                        const char * pszDomain = "" );
+    virtual CPLErr      SetMetadataItem( const char * pszName,
+                                            const char * pszValue,
+                                            const char * pszDomain = "" );
+
+    void                RenameTo(const char* pszDstTableName);
+
+    virtual int          HasFastSpatialFilter(int iGeomCol);
+    virtual CPLString    GetSpatialWhere(int iGeomCol,
+                                         OGRGeometry* poFilterGeom);
+
+    int                 HasSpatialIndex();
+    void                SetPrecisionFlag( int bFlag )
+                                { m_bPreservePrecision = bFlag; }
+    void                SetTruncateFieldsFlag( int bFlag )
+                                { m_bTruncateFields = bFlag; }
+    OGRErr              RunDeferredCreationIfNecessary();
 
     /************************************************************************/
     /* GPKG methods */
     
     private:
     
-    OGRErr              ReadFeature( sqlite3_stmt *poQuery, OGRFeature **ppoFeature );
     OGRErr              UpdateExtent( const OGREnvelope *poExtent );
     OGRErr              SaveExtent();
     OGRErr              BuildColumns();
     OGRBoolean          IsGeomFieldSet( OGRFeature *poFeature );
     CPLString           FeatureGenerateUpdateSQL( OGRFeature *poFeature );
-    CPLString           FeatureGenerateInsertSQL( OGRFeature *poFeature );
+    CPLString           FeatureGenerateInsertSQL( OGRFeature *poFeature, int bAddFID, int bBindNullFields );
     OGRErr              FeatureBindUpdateParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt );
-    OGRErr              FeatureBindInsertParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt );
-    OGRErr              FeatureBindParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt, int *pnColCount );
+    OGRErr              FeatureBindInsertParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt, int bAddFID, int bBindNullFields );
+    OGRErr              FeatureBindParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt, int *pnColCount, int bAddFID, int bBindNullFields );
 
+    void                CheckUnknownExtensions();
+    int                 CreateGeometryExtensionIfNecessary(OGRwkbGeometryType eGType);
 };
 
+/************************************************************************/
+/*                         OGRGeoPackageSelectLayer                     */
+/************************************************************************/
+
+class OGRGeoPackageSelectLayer : public OGRGeoPackageLayer, public IOGRSQLiteSelectLayer
+{
+    OGRSQLiteSelectLayerCommonBehaviour* poBehaviour;
+
+    virtual OGRErr      ResetStatement();
+
+  public:
+                        OGRGeoPackageSelectLayer( GDALGeoPackageDataset *, 
+                                              CPLString osSQL,
+                                              sqlite3_stmt *,
+                                              int bUseStatementForGetNextFeature,
+                                              int bEmptyLayer );
+                       ~OGRGeoPackageSelectLayer();
+
+    virtual void        ResetReading();
+
+    virtual OGRFeature *GetNextFeature();
+    virtual GIntBig     GetFeatureCount( int );
+
+    virtual void        SetSpatialFilter( OGRGeometry * poGeom ) { SetSpatialFilter(0, poGeom); }
+    virtual void        SetSpatialFilter( int iGeomField, OGRGeometry * );
+    virtual OGRErr      SetAttributeFilter( const char * );
+
+    virtual int         TestCapability( const char * );
+
+    virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE) { return GetExtent(0, psExtent, bForce); }
+    virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
+
+    virtual OGRFeatureDefn *     GetLayerDefn() { return OGRGeoPackageLayer::GetLayerDefn(); }
+    virtual char*&               GetAttrQueryString() { return m_pszAttrQueryString; }
+    virtual OGRFeatureQuery*&    GetFeatureQuery() { return m_poAttrQuery; }
+    virtual OGRGeometry*&        GetFilterGeom() { return m_poFilterGeom; }
+    virtual int&                 GetIGeomFieldFilter() { return m_iGeomFieldFilter; }
+    virtual OGRSpatialReference* GetSpatialRef() { return OGRGeoPackageLayer::GetSpatialRef(); }
+    virtual int                  InstallFilter( OGRGeometry * poGeomIn ) { return OGRGeoPackageLayer::InstallFilter(poGeomIn); }
+    virtual int                  HasReadFeature() { return iNextShapeId > 0; }
+    virtual void                 BaseResetReading() { OGRGeoPackageLayer::ResetReading(); }
+    virtual OGRFeature          *BaseGetNextFeature() { return OGRGeoPackageLayer::GetNextFeature(); }
+    virtual OGRErr               BaseSetAttributeFilter(const char* pszQuery) { return OGRGeoPackageLayer::SetAttributeFilter(pszQuery); }
+    virtual GIntBig              BaseGetFeatureCount(int bForce) { return OGRGeoPackageLayer::GetFeatureCount(bForce); }
+    virtual int                  BaseTestCapability( const char *pszCap ) { return OGRGeoPackageLayer::TestCapability(pszCap); }
+    virtual OGRErr               BaseGetExtent(OGREnvelope *psExtent, int bForce) { return OGRGeoPackageLayer::GetExtent(psExtent, bForce); }
+    virtual OGRErr               BaseGetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) { return OGRGeoPackageLayer::GetExtent(iGeomField, psExtent, bForce); }
+};
 
 
-#endif /* _OGR_GEOPACKAGE_H_INCLUDED */
\ No newline at end of file
+#endif /* _OGR_GEOPACKAGE_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp
index c53b996..391b4fb 100644
--- a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedatasource.cpp
@@ -2,7 +2,7 @@
  * $Id$
  *
  * Project:  GeoPackage Translator
- * Purpose:  Implements OGRGeoPackageDataSource class
+ * Purpose:  Implements GDALGeoPackageDataset class
  * Author:   Paul Ramsey <pramsey at boundlessgeo.com>
  *
  ******************************************************************************
@@ -25,11 +25,13 @@
  * 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 SOFpszFileNameTWARE.
+ * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
 #include "ogr_geopackage.h"
-#include "ogrgeopackageutility.h"
+#include "ogr_p.h"
+#include "swq.h"
+#include "gdalwarper.h"
 
 /* 1.1.1: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) in the application id */
 /* http://opengis.github.io/geopackage/#_file_format */
@@ -40,32 +42,67 @@
 static const char aGpkgId[4] = {0x47, 0x50, 0x31, 0x30};
 static const size_t szGpkgIdPos = 68;
 
-/* Cannnot count on the "PRAGMA application_id" command existing */
-/* it is a very recent addition to SQLite. */
-bool OGRGeoPackageDataSource::CheckApplicationId(const char * pszFileName)
-{
-    CPLAssert( m_poDb == NULL );
-    
-    char aFileId[4];
-
-    VSILFILE *fp = VSIFOpenL( pszFileName, "rb" );
-
-    /* Should never happen (always called after existence check) but just in case */
-    if ( ! fp ) return FALSE;
-
-    /* application_id is 4 bytes at offset 68 in the header */
-    VSIFSeekL(fp, szGpkgIdPos, SEEK_SET);
-    VSIFReadL(aFileId, 4, 1, fp);
+/************************************************************************/
+/*                             Tiling schemes                           */
+/************************************************************************/
 
-    VSIFCloseL(fp);
-    
-    for ( int i = 0; i < 4; i++ )
-    {
-        if ( aFileId[i] != aGpkgId[i] )
-            return FALSE;
-    }
-    return TRUE;
-}
+typedef struct
+{
+    const char* pszName;
+    int         nEPSGCode;
+    double      dfMinX;
+    double      dfMaxY;
+    int         nTileXCountZoomLevel0;
+    int         nTileYCountZoomLevel0;
+    int         nTileWidth;
+    int         nTileHeight;
+    double      dfPixelXSizeZoomLevel0;
+    double      dfPixelYSizeZoomLevel0;
+} TilingSchemeDefinition;
+
+static const TilingSchemeDefinition asTilingShemes[] =
+{
+    /* See http://portal.opengeospatial.org/files/?artifact_id=35326 (WMTS 1.0), Annex E.3 */
+    { "GoogleCRS84Quad",
+      4326,
+      -180.0, 180.0,
+      1, 1,
+      256, 256,
+      360.0 / 256, 360.0 / 256 },
+
+    /* See http://portal.opengeospatial.org/files/?artifact_id=35326 (WMTS 1.0), Annex E.4 */
+    { "GoogleMapsCompatible",
+      3857,
+      -(156543.0339280410*256) /2, (156543.0339280410*256) /2,
+      1, 1,
+      256, 256,
+      156543.0339280410, 156543.0339280410 },
+
+    /* See InspireCRS84Quad at http://inspire.ec.europa.eu/documents/Network_Services/TechnicalGuidance_ViewServices_v3.0.pdf */
+    /* This is exactly the same as PseudoTMS_GlobalGeodetic */
+    { "InspireCRS84Quad",
+      4326,
+      -180.0, 90.0,
+      2, 1,
+      256, 256,
+      180.0 / 256, 180.0 / 256 },
+
+    /* See global-geodetic at http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification */
+    { "PseudoTMS_GlobalGeodetic",
+      4326,
+      -180.0, 90.0,
+      2, 1,
+      256, 256,
+      180.0 / 256, 180.0 / 256 },
+
+    /* See global-mercator at http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification */
+    { "PseudoTMS_GlobalMercator",
+      3857,
+      -20037508.34, 20037508.34,
+      2, 2,
+      256, 256,
+      78271.516, 78271.516 },
+};
 
 /* Only recent versions of SQLite will let us muck with application_id */
 /* via a PRAGMA statement, so we have to write directly into the */
@@ -73,19 +110,21 @@ bool OGRGeoPackageDataSource::CheckApplicationId(const char * pszFileName)
 /* We do this at the *end* of initialization so that there is */
 /* data to write down to a file, and we'll have a writeable file */
 /* once we close the SQLite connection */
-OGRErr OGRGeoPackageDataSource::SetApplicationId()
+OGRErr GDALGeoPackageDataset::SetApplicationId()
 {
-    CPLAssert( m_poDb != NULL );
-    CPLAssert( m_pszFileName != NULL );
+    CPLAssert( hDB != NULL );
+    CPLAssert( m_pszFilename != NULL );
 
+#ifdef SPATIALITE_412_OR_LATER
+    FinishNewSpatialite();
+#endif
     /* Have to flush the file before f***ing with the header */
-    sqlite3_close(m_poDb);
-    m_poDb = NULL;
+    CloseDB();
 
     size_t szWritten = 0;
 
     /* Open for modification, write to application id area */
-    VSILFILE *pfFile = VSIFOpenL( m_pszFileName, "rb+" );
+    VSILFILE *pfFile = VSIFOpenL( m_pszFilename, "rb+" );
     if( pfFile == NULL )
         return OGRERR_FAILURE;
     VSIFSeekL(pfFile, szGpkgIdPos, SEEK_SET);
@@ -100,7 +139,7 @@ OGRErr OGRGeoPackageDataSource::SetApplicationId()
     }
 
     /* And re-open the file */
-    if ( sqlite3_open(m_pszFileName, &m_poDb) != SQLITE_OK )
+    if (!OpenOrCreateDB(SQLITE_OPEN_READWRITE) )
         return OGRERR_FAILURE;
 
     return OGRERR_NONE;
@@ -108,7 +147,7 @@ OGRErr OGRGeoPackageDataSource::SetApplicationId()
 
 
 /* Returns the first row of first column of SQL as integer */
-OGRErr OGRGeoPackageDataSource::PragmaCheck(const char * pszPragma, const char * pszExpected, int nRowsExpected)
+OGRErr GDALGeoPackageDataset::PragmaCheck(const char * pszPragma, const char * pszExpected, int nRowsExpected)
 {
     CPLAssert( pszPragma != NULL );
     CPLAssert( pszExpected != NULL );
@@ -119,7 +158,7 @@ OGRErr OGRGeoPackageDataSource::PragmaCheck(const char * pszPragma, const char *
     char **papszResult;
 
     rc = sqlite3_get_table(
-        m_poDb,
+        hDB,
         CPLSPrintf("PRAGMA %s", pszPragma),
         &papszResult, &nRowCount, &nColCount, &pszErrMsg );
     
@@ -149,8 +188,18 @@ OGRErr OGRGeoPackageDataSource::PragmaCheck(const char * pszPragma, const char *
     return OGRERR_NONE; 
 }
 
+static OGRErr GDALGPKGImportFromEPSG(OGRSpatialReference *poSpatialRef,
+                                     int nEPSGCode)
+{
+    CPLPushErrorHandler(CPLQuietErrorHandler);
+    OGRErr eErr = poSpatialRef->importFromEPSG(nEPSGCode);
+    CPLPopErrorHandler();
+    CPLErrorReset();
+    return eErr;
+}
+
 
-OGRSpatialReference* OGRGeoPackageDataSource::GetSpatialRef(int iSrsId)
+OGRSpatialReference* GDALGeoPackageDataset::GetSpatialRef(int iSrsId)
 {
     SQLResult oResult;
     
@@ -161,9 +210,9 @@ OGRSpatialReference* OGRGeoPackageDataSource::GetSpatialRef(int iSrsId)
     }
     
     CPLString oSQL;
-    oSQL.Printf("SELECT definition FROM gpkg_spatial_ref_sys WHERE srs_id = %d", iSrsId);
+    oSQL.Printf("SELECT definition, organization, organization_coordsys_id FROM gpkg_spatial_ref_sys WHERE srs_id = %d", iSrsId);
     
-    OGRErr err = SQLQuery(m_poDb, oSQL.c_str(), &oResult);
+    OGRErr err = SQLQuery(hDB, oSQL.c_str(), &oResult);
 
     if ( err != OGRERR_NONE || oResult.nRowCount != 1 )
     {
@@ -182,21 +231,27 @@ OGRSpatialReference* OGRGeoPackageDataSource::GetSpatialRef(int iSrsId)
         return NULL;
     }
     
-    OGRSpatialReference *poSpatialRef = new OGRSpatialReference(pszWkt);
+    const char* pszOrganization = SQLResultGetValue(&oResult, 1, 0);
+    const char* pszOrganizationCoordsysID = SQLResultGetValue(&oResult, 2, 0);
     
-    if ( poSpatialRef == NULL )
+    OGRSpatialReference *poSpatialRef = new OGRSpatialReference();
+    // Try to import first from EPSG code, and then from WKT
+    if( !(pszOrganization && pszOrganizationCoordsysID && EQUAL(pszOrganization, "EPSG") &&
+          GDALGPKGImportFromEPSG(poSpatialRef, atoi(pszOrganizationCoordsysID)) == OGRERR_NONE) &&
+        poSpatialRef->SetFromUserInput(pszWkt) != OGRERR_NONE )
     {
-        SQLResultFree(&oResult);
         CPLError( CE_Warning, CPLE_AppDefined, "unable to parse srs_id '%d' well-known text '%s'",
-                  iSrsId, pszWkt);
+                iSrsId, pszWkt);
+        SQLResultFree(&oResult);
+        delete poSpatialRef;
         return NULL;
     }
-    
+
     SQLResultFree(&oResult);
     return poSpatialRef;
 }
 
-const char * OGRGeoPackageDataSource::GetSrsName(const OGRSpatialReference * poSRS)
+const char * GDALGeoPackageDataset::GetSrsName(const OGRSpatialReference * poSRS)
 {
     const OGR_SRSNode *node;
     
@@ -217,22 +272,21 @@ const char * OGRGeoPackageDataSource::GetSrsName(const OGRSpatialReference * poS
     }
 }
 
-int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
+int GDALGeoPackageDataset::GetSrsId(const OGRSpatialReference * cpoSRS)
 {
     char *pszWKT = NULL;
     char *pszSQL = NULL;
-    int nSRSId = UNDEFINED_SRID;
+    int nSRSId = DEFAULT_SRID;
     const char* pszAuthorityName;
     int nAuthorityCode = 0;
     OGRErr err;
     OGRBoolean bCanUseAuthorityCode = FALSE;
 
     if( cpoSRS == NULL )
-        return UNDEFINED_SRID;
+        return DEFAULT_SRID;
 
     OGRSpatialReference *poSRS = cpoSRS->Clone();
 
-    poSRS->morphFromESRI();
     pszAuthorityName = poSRS->GetAuthorityName(NULL);
 
     if ( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
@@ -266,7 +320,7 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
                          "upper(organization) = upper('%q') AND organization_coordsys_id = %d",
                          pszAuthorityName, nAuthorityCode );
         
-        nSRSId = SQLGetInteger(m_poDb, pszSQL, &err);
+        nSRSId = SQLGetInteger(hDB, pszSQL, &err);
         sqlite3_free(pszSQL);
         
         // Got a match? Return it!
@@ -282,8 +336,9 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
                          "srs_id = %d", nAuthorityCode );
         
         // Yep, we can!
-        if ( ! SQLGetInteger(m_poDb, pszSQL, &err) && err == OGRERR_NONE )
+        if ( ! SQLGetInteger(hDB, pszSQL, &err) && err == OGRERR_NONE )
             bCanUseAuthorityCode = TRUE;
+        sqlite3_free(pszSQL);
     }
 
     // Translate SRS to WKT.                                           
@@ -291,7 +346,7 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
     {
         delete poSRS;
         CPLFree(pszWKT);
-        return UNDEFINED_SRID;
+        return DEFAULT_SRID;
     }
 
     // Reuse the authority code number as SRS_ID if we can
@@ -303,12 +358,12 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
     else
     {
         // Get the current maximum srid in the srs table.                  
-        int nMaxSRSId = SQLGetInteger(m_poDb, "SELECT MAX(srs_id) FROM gpkg_spatial_ref_sys", &err);
+        int nMaxSRSId = SQLGetInteger(hDB, "SELECT MAX(srs_id) FROM gpkg_spatial_ref_sys", &err);
         if ( OGRERR_NONE != err )
         {
             CPLFree(pszWKT);
             delete poSRS;
-            return UNDEFINED_SRID;        
+            return DEFAULT_SRID;        
         }
 
         nSRSId = nMaxSRSId + 1;
@@ -320,7 +375,7 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
         pszSQL = sqlite3_mprintf(
                  "INSERT INTO gpkg_spatial_ref_sys "
                  "(srs_name,srs_id,organization,organization_coordsys_id,definition) "
-                 "VALUES ('%s', %d, upper('%s'), %d, '%q')",
+                 "VALUES ('%q', %d, upper('%q'), %d, '%q')",
                  GetSrsName(poSRS), nSRSId, pszAuthorityName, nAuthorityCode, pszWKT
                  );
     }
@@ -329,13 +384,13 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
         pszSQL = sqlite3_mprintf(
                  "INSERT INTO gpkg_spatial_ref_sys "
                  "(srs_name,srs_id,organization,organization_coordsys_id,definition) "
-                 "VALUES ('%s', %d, upper('%s'), %d, '%q')",
+                 "VALUES ('%q', %d, upper('%q'), %d, '%q')",
                  GetSrsName(poSRS), nSRSId, "NONE", nSRSId, pszWKT
                  );
     }
 
     // Add new row to gpkg_spatial_ref_sys
-    err = SQLCommand(m_poDb, pszSQL);
+    err = SQLCommand(hDB, pszSQL);
 
     // Free everything that was allocated.
     CPLFree(pszWKT);    
@@ -347,88 +402,159 @@ int OGRGeoPackageDataSource::GetSrsId(const OGRSpatialReference * cpoSRS)
 
 
 /************************************************************************/
-/*                        OGRGeoPackageDataSource()                     */
+/*                        GDALGeoPackageDataset()                       */
 /************************************************************************/
 
-OGRGeoPackageDataSource::OGRGeoPackageDataSource()
+GDALGeoPackageDataset::GDALGeoPackageDataset()
 {
-    m_pszFileName = NULL;
+    m_bNew = FALSE;
     m_papoLayers = NULL;
     m_nLayers = 0;
     m_bUtf8 = FALSE;
-    m_poDb = NULL;
-    m_bUpdate = FALSE;
+    m_bIdentifierAsCO = FALSE;
+    m_bDescriptionAsCO = FALSE;
+    m_bHasReadMetadataFromStorage = FALSE;
+    m_bMetadataDirty = FALSE;
+    m_papszSubDatasets = NULL;
+    m_pszProjection = NULL;
+    m_bRecordInsertedInGPKGContent = FALSE;
+    m_bGeoTransformValid = FALSE;
+    m_nSRID = -1; /* unknown cartesian */
+    m_adfGeoTransform[0] = 0.0;
+    m_adfGeoTransform[1] = 1.0;
+    m_adfGeoTransform[2] = 0.0;
+    m_adfGeoTransform[3] = 0.0;
+    m_adfGeoTransform[4] = 0.0;
+    m_adfGeoTransform[5] = 1.0;
+    m_nZoomLevel = -1;
+    m_pabyCachedTiles = NULL;
+    for(int i=0;i<4;i++)
+    {
+        m_asCachedTilesDesc[i].nRow = -1;
+        m_asCachedTilesDesc[i].nCol = -1;
+        m_asCachedTilesDesc[i].nIdxWithinTileData = -1;
+        m_asCachedTilesDesc[i].abBandDirty[0] = FALSE;
+        m_asCachedTilesDesc[i].abBandDirty[1] = FALSE;
+        m_asCachedTilesDesc[i].abBandDirty[2] = FALSE;
+        m_asCachedTilesDesc[i].abBandDirty[3] = FALSE;
+    }
+    m_nShiftXTiles = 0;
+    m_nShiftXPixelsMod = 0;
+    m_nShiftYTiles = 0;
+    m_nShiftYPixelsMod = 0;
+    m_eTF = GPKG_TF_PNG_JPEG;
+    m_nTileMatrixWidth = 0;
+    m_nTileMatrixHeight = 0;
+    m_nZLevel = 6;
+    m_nQuality = 75;
+    m_bDither = FALSE;
+    m_poParentDS = NULL;
+    m_nOverviewCount = 0;
+    m_papoOverviewDS = NULL;
+    m_bZoomOther = FALSE;
+    m_bTriedEstablishingCT = FALSE;
+    m_pabyHugeColorArray = NULL;
+    m_poCT = NULL;
+    m_bInWriteTile = FALSE;
+    m_hTempDB = NULL;
+    m_bInFlushCache = FALSE;
+    m_nTileInsertionCount = 0;
+    m_osTilingScheme = "CUSTOM";
 }
 
 /************************************************************************/
-/*                       ~OGRGeoPackageDataSource()                     */
+/*                       ~GDALGeoPackageDataset()                       */
 /************************************************************************/
 
-OGRGeoPackageDataSource::~OGRGeoPackageDataSource()
+GDALGeoPackageDataset::~GDALGeoPackageDataset()
 {
-    for( int i = 0; i < m_nLayers; i++ )
+    int i;
+    
+    SetPamFlags(0);
+
+    if( m_poParentDS == NULL && m_osRasterTable.size() &&
+        !m_bGeoTransformValid )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Raster table %s not correctly initialized due to missing call "
+                 "to SetGeoTransform()",
+                 m_osRasterTable.c_str());
+    }
+    
+    FlushCache();
+    FlushMetadata();
+
+    if( m_poParentDS != NULL )
+    {
+        hDB = NULL;
+    }
+    else if( m_hTempDB != NULL )
+    {
+        sqlite3_close(m_hTempDB);
+        m_hTempDB = NULL;
+        VSIUnlink(m_osTempDBFilename);
+    }
+
+    for( i = 0; i < m_nLayers; i++ )
         delete m_papoLayers[i];
-        
-    if ( m_poDb )
-        sqlite3_close(m_poDb);
+    for( i = 0; i < m_nOverviewCount; i++ )
+        delete m_papoOverviewDS[i];
 
     CPLFree( m_papoLayers );
-    CPLFree( m_pszFileName );
+    CPLFree( m_papoOverviewDS );
+    CSLDestroy( m_papszSubDatasets );
+    CPLFree(m_pszProjection);
+    CPLFree(m_pabyCachedTiles);
+    delete m_poCT;
+    CPLFree(m_pabyHugeColorArray);
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRGeoPackageDataSource::Open(const char * pszFilename, int bUpdate )
+int GDALGeoPackageDataset::Open( GDALOpenInfo* poOpenInfo )
 {
     int i;
     OGRErr err;
 
     CPLAssert( m_nLayers == 0 );
-    CPLAssert( m_poDb == NULL );
-    CPLAssert( m_pszFileName == NULL );
-
-    m_bUpdate = bUpdate;
-
-    /* Requirement 3: File name has to end in "gpkg" */
-    /* http://opengis.github.io/geopackage/#_file_extension_name */
-    int nLen = strlen(pszFilename);
-    if(! (nLen >= 5 && EQUAL(pszFilename + nLen - 5, ".gpkg")) )
-        return FALSE;
+    CPLAssert( hDB == NULL );
+    
+    SetDescription( poOpenInfo->pszFilename );
+    CPLString osFilename( poOpenInfo->pszFilename );
+    CPLString osSubdatasetTableName;
+    if( EQUALN(poOpenInfo->pszFilename, "GPKG:", 5) )
+    {
+        char** papszTokens = CSLTokenizeString2(poOpenInfo->pszFilename, ":", 0);
+        if( CSLCount(papszTokens) != 3 )
+        {
+            CSLDestroy(papszTokens);
+            return FALSE;
+        }
 
-    /* Check that the filename exists and is a file */
-    VSIStatBuf stat;
-    if( CPLStat( pszFilename, &stat ) != 0 || !VSI_ISREG(stat.st_mode) )
-        return FALSE;
+        osFilename = papszTokens[1];
+        osSubdatasetTableName = papszTokens[2];
 
-    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) */
-    /* in the application id */
-    /* http://opengis.github.io/geopackage/#_file_format */
-    if ( ! CheckApplicationId(pszFilename) )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, "bad application_id on '%s'", pszFilename);
-        return FALSE;
+        CSLDestroy(papszTokens);
     }
 
+    bUpdate = poOpenInfo->eAccess == GA_Update;
+    eAccess = poOpenInfo->eAccess; /* hum annoying duplication */
+    m_pszFilename = CPLStrdup( osFilename );
+
     /* See if we can open the SQLite database */
-    int rc = sqlite3_open( pszFilename, &m_poDb );
-    if ( rc != SQLITE_OK )
-    {
-        m_poDb = NULL;
-        CPLError( CE_Failure, CPLE_OpenFailed, "sqlite3_open(%s) failed: %s",
-                  pszFilename, sqlite3_errmsg( m_poDb ) );
+    if (!OpenOrCreateDB((bUpdate) ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY) )
         return FALSE;
-    }
-    
-    /* Filename is good, store it for future reference */
-    m_pszFileName = CPLStrdup( pszFilename );
 
     /* Requirement 6: The SQLite PRAGMA integrity_check SQL command SHALL return “ok” */
     /* http://opengis.github.io/geopackage/#_file_integrity */
-    if ( OGRERR_NONE != PragmaCheck("integrity_check", "ok", 1) )
+    /* Disable integrity check by default, since it is expensive on big files */
+    if( CSLTestBoolean(CPLGetConfigOption("OGR_GPKG_INTEGRITY_CHECK", "NO")) &&
+        OGRERR_NONE != PragmaCheck("integrity_check", "ok", 1) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, "pragma integrity_check on '%s' failed", pszFilename);
+        CPLError( CE_Failure, CPLE_AppDefined, "pragma integrity_check on '%s' failed",
+                  m_pszFilename);
         return FALSE;
     }
     
@@ -437,7 +563,8 @@ int OGRGeoPackageDataSource::Open(const char * pszFilename, int bUpdate )
     /* http://opengis.github.io/geopackage/#_file_integrity */
     if ( OGRERR_NONE != PragmaCheck("foreign_key_check", "", 0) ) 
     {
-        CPLError( CE_Failure, CPLE_AppDefined, "pragma foreign_key_check on '%s' failed", pszFilename);
+        CPLError( CE_Failure, CPLE_AppDefined, "pragma foreign_key_check on '%s' failed",
+                  m_pszFilename);
         return FALSE; 
     }
 
@@ -454,18 +581,16 @@ int OGRGeoPackageDataSource::Open(const char * pszFilename, int bUpdate )
     /* Check for requirement metadata tables */
     /* Requirement 10: gpkg_spatial_ref_sys must exist */
     /* Requirement 13: gpkg_contents must exist */
-    /* Requirement 21: gpkg_geometry_columns must exist */
     static std::string aosGpkgTables[] = {
-        "gpkg_geometry_columns",
         "gpkg_spatial_ref_sys",
         "gpkg_contents"
     };
     
-    for ( i = 0; i < 3; i++ )
+    for ( i = 0; i < (int)(sizeof(aosGpkgTables) / sizeof(aosGpkgTables[0])); i++ )
     {
         SQLResult oResult;
-        char *pszSQL = sqlite3_mprintf("pragma table_info('%s')", aosGpkgTables[i].c_str());
-        err = SQLQuery(m_poDb, pszSQL, &oResult);
+        char *pszSQL = sqlite3_mprintf("pragma table_info('%q')", aosGpkgTables[i].c_str());
+        err = SQLQuery(hDB, pszSQL, &oResult);
         sqlite3_free(pszSQL);
         
         if  ( err != OGRERR_NONE )
@@ -480,624 +605,3770 @@ int OGRGeoPackageDataSource::Open(const char * pszFilename, int bUpdate )
         
         SQLResultFree(&oResult);
     }
-        
-    /* Load layer definitions for all tables in gpkg_contents & gpkg_geometry_columns */
-    SQLResult oResult;
-    std::string osSQL = 
-        "SELECT c.table_name, c.identifier, c.min_x, c.min_y, c.max_x, c.max_y "
-        "FROM gpkg_geometry_columns g JOIN gpkg_contents c ON (g.table_name = c.table_name)"
-        "WHERE c.data_type = 'features'";
-        
-    err = SQLQuery(m_poDb, osSQL.c_str(), &oResult);
-    if  ( err != OGRERR_NONE )
+
+    CheckUnknownExtensions();
+
+    int bRet = FALSE;
+    int bHasGPKGGeometryColumns = FALSE;
+    if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR )
     {
+        SQLResult oResult;
+        err = SQLQuery(hDB, "pragma table_info('gpkg_geometry_columns')", &oResult);
+        bHasGPKGGeometryColumns = (err == OGRERR_NONE && oResult.nRowCount > 0);
         SQLResultFree(&oResult);
-        return FALSE;
     }
+    if( bHasGPKGGeometryColumns )
+    {
+        /* Load layer definitions for all tables in gpkg_contents & gpkg_geometry_columns */
+        /* and non-spatial tables as well */
+        std::string osSQL =
+            "SELECT c.table_name, c.identifier, 1 as is_spatial, c.min_x, c.min_y, c.max_x, c.max_y "
+            "  FROM gpkg_geometry_columns g JOIN gpkg_contents c ON (g.table_name = c.table_name)"
+            "  WHERE c.data_type = 'features' ";
+
+        if (HasGDALAspatialExtension()) {
+            osSQL +=
+                "UNION ALL "
+                "SELECT table_name, identifier, 0 as is_spatial, 0 AS xmin, 0 AS ymin, 0 AS xmax, 0 AS ymax "
+                "  FROM gpkg_contents"
+                "  WHERE data_type = 'aspatial' ";
+        }
+
+        SQLResult oResult;
+        err = SQLQuery(hDB, osSQL.c_str(), &oResult);
+        if  ( err != OGRERR_NONE )
+        {
+            SQLResultFree(&oResult);
+            return FALSE;
+        }
+
+        if ( oResult.nRowCount > 0 )
+        {
+            m_papoLayers = (OGRGeoPackageTableLayer**)CPLMalloc(sizeof(OGRGeoPackageTableLayer*) * oResult.nRowCount);
+
+            for ( i = 0; i < oResult.nRowCount; i++ )
+            {
+                const char *pszTableName = SQLResultGetValue(&oResult, 0, i);
+                if ( ! pszTableName )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined, "unable to read table name for layer(%d)", i);            
+                    continue;
+                }
+                int bIsSpatial = SQLResultGetValueAsInteger(&oResult, 2, i);
+                OGRGeoPackageTableLayer *poLayer = new OGRGeoPackageTableLayer(this, pszTableName);
+                if( OGRERR_NONE != poLayer->ReadTableDefinition(bIsSpatial) )
+                {
+                    delete poLayer;
+                    CPLError(CE_Warning, CPLE_AppDefined, "unable to read table definition for '%s'", pszTableName);            
+                    continue;
+                }
+                m_papoLayers[m_nLayers++] = poLayer;
+            }
+        }
 
-    if ( oResult.nRowCount > 0 )
+        SQLResultFree(&oResult);
+        bRet = TRUE;
+    }
+    
+    int bHasTileMatrixSet = FALSE;
+    if( poOpenInfo->nOpenFlags & GDAL_OF_RASTER )
+    {
+        SQLResult oResult;
+        err = SQLQuery(hDB, "pragma table_info('gpkg_tile_matrix_set')", &oResult);
+        bHasTileMatrixSet = (err == OGRERR_NONE && oResult.nRowCount > 0);
+        SQLResultFree(&oResult);
+    }
+    if( bHasTileMatrixSet )
     {
-        m_papoLayers = (OGRLayer**)CPLMalloc(sizeof(OGRGeoPackageLayer*) * oResult.nRowCount);
+        SQLResult oResult;
+        std::string osSQL =
+            "SELECT c.table_name, c.identifier, c.description, c.srs_id, c.min_x, c.min_y, c.max_x, c.max_y, "
+            "tms.min_x, tms.min_y, tms.max_x, tms.max_y FROM gpkg_contents c JOIN gpkg_tile_matrix_set tms ON "
+            "c.table_name = tms.table_name WHERE data_type = 'tiles'";
+        if( CSLFetchNameValue( poOpenInfo->papszOpenOptions, "TABLE") )
+            osSubdatasetTableName = CSLFetchNameValue( poOpenInfo->papszOpenOptions, "TABLE");
+        if( osSubdatasetTableName.size() )
+        {
+            char* pszTmp = sqlite3_mprintf(" AND c.table_name='%q'", osSubdatasetTableName.c_str());
+            osSQL += pszTmp;
+            sqlite3_free(pszTmp);
+            SetPhysicalFilename( osFilename.c_str() );
+        }
 
-        for ( i = 0; i < oResult.nRowCount; i++ )
+        err = SQLQuery(hDB, osSQL.c_str(), &oResult);
+        if  ( err != OGRERR_NONE )
+        {
+            SQLResultFree(&oResult);
+            return FALSE;
+        }
+
+        if( oResult.nRowCount == 0 && osSubdatasetTableName.size() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table '%s' in GeoPackage dataset",
+                     osSubdatasetTableName.c_str());
+        }
+        else if( oResult.nRowCount == 1 )
         {
-            const char *pszTableName = SQLResultGetValue(&oResult, 0, i);
-            if ( ! pszTableName )
+            const char *pszTableName = SQLResultGetValue(&oResult, 0, 0);
+            const char* pszIdentifier = SQLResultGetValue(&oResult, 1, 0);
+            const char* pszDescription = SQLResultGetValue(&oResult, 2, 0);
+            const char* pszSRSId = SQLResultGetValue(&oResult, 3, 0);
+            const char* pszMinX = SQLResultGetValue(&oResult, 4, 0);
+            const char* pszMinY = SQLResultGetValue(&oResult, 5, 0);
+            const char* pszMaxX = SQLResultGetValue(&oResult, 6, 0);
+            const char* pszMaxY = SQLResultGetValue(&oResult, 7, 0);
+            const char* pszTMSMinX = SQLResultGetValue(&oResult, 8, 0);
+            const char* pszTMSMinY = SQLResultGetValue(&oResult, 9, 0);
+            const char* pszTMSMaxX = SQLResultGetValue(&oResult, 10, 0);
+            const char* pszTMSMaxY = SQLResultGetValue(&oResult, 11, 0);
+            if( pszTableName != NULL && pszTMSMinX != NULL && pszTMSMinY != NULL &&
+                pszTMSMaxX != NULL && pszTMSMaxY != NULL )
             {
-                CPLError(CE_Warning, CPLE_AppDefined, "unable to read table name for layer(%d)", i);            
-                continue;
+                bRet = OpenRaster( pszTableName, pszIdentifier, pszDescription,
+                                   pszSRSId ? atoi(pszSRSId) : 0,
+                                   CPLAtof(pszTMSMinX), CPLAtof(pszTMSMinY),
+                                   CPLAtof(pszTMSMaxX), CPLAtof(pszTMSMaxY),
+                                   pszMinX, pszMinY, pszMaxX, pszMaxY,
+                                   poOpenInfo->papszOpenOptions );
             }
-            OGRGeoPackageLayer *poLayer = new OGRGeoPackageLayer(this, pszTableName);
-            if( OGRERR_NONE != poLayer->ReadTableDefinition() )
+        }
+        else if( oResult.nRowCount >= 1 )
+        {
+            bRet = TRUE;
+            
+            int nSDSCount = 0;
+            for ( i = 0; i < oResult.nRowCount; i++ )
             {
-                delete poLayer;
-                CPLError(CE_Warning, CPLE_AppDefined, "unable to read table definition for '%s'", pszTableName);            
-                continue;
+                const char *pszTableName = SQLResultGetValue(&oResult, 0, i);
+                const char *pszIdentifier = SQLResultGetValue(&oResult, 1, i);
+                if( pszTableName != NULL )
+                {
+                    m_papszSubDatasets = CSLSetNameValue( m_papszSubDatasets,
+                                                        CPLSPrintf("SUBDATASET_%d_NAME", nSDSCount+1),
+                                                        CPLSPrintf("GPKG:%s:%s", m_pszFilename, pszTableName) );
+                    if( pszIdentifier )
+                        m_papszSubDatasets = CSLSetNameValue( m_papszSubDatasets,
+                                                              CPLSPrintf("SUBDATASET_%d_DESC", nSDSCount+1),
+                                                              CPLSPrintf("%s - %s", pszTableName, pszIdentifier) );
+                    else
+                        m_papszSubDatasets = CSLSetNameValue( m_papszSubDatasets,
+                                                              CPLSPrintf("SUBDATASET_%d_DESC", nSDSCount+1),
+                                                              pszTableName );
+                }
+                nSDSCount ++;
             }
-            m_papoLayers[m_nLayers++] = poLayer;
         }
+
+        SQLResultFree(&oResult);
     }
-    
-    SQLResultFree(&oResult);
 
-    return TRUE;
+    return bRet;
 }
 
-
-
 /************************************************************************/
-/*                          GetDatabaseHandle()                         */
+/*                         InitRaster()                                 */
 /************************************************************************/
 
-sqlite3* OGRGeoPackageDataSource::GetDatabaseHandle()
+int GDALGeoPackageDataset::InitRaster ( GDALGeoPackageDataset* poParentDS,
+                                        const char* pszTableName,
+                                        double dfMinX,
+                                        double dfMinY,
+                                        double dfMaxX,
+                                        double dfMaxY,
+                                        const char* pszContentsMinX,
+                                        const char* pszContentsMinY,
+                                        const char* pszContentsMaxX,
+                                        const char* pszContentsMaxY,
+                                        char** papszOpenOptions,
+                                        const SQLResult& oResult,
+                                        int nIdxInResult )
 {
-    return m_poDb;
+    m_osRasterTable = pszTableName;
+    m_dfTMSMinX = dfMinX;
+    m_dfTMSMaxY = dfMaxY;
+
+    int nZoomLevel = atoi(SQLResultGetValue(&oResult, 0, nIdxInResult));
+    double dfPixelXSize = CPLAtof(SQLResultGetValue(&oResult, 1, nIdxInResult));
+    double dfPixelYSize = CPLAtof(SQLResultGetValue(&oResult, 2, nIdxInResult));
+    int nTileWidth = atoi(SQLResultGetValue(&oResult, 3, nIdxInResult));
+    int nTileHeight = atoi(SQLResultGetValue(&oResult, 4, nIdxInResult));
+    int nTileMatrixWidth = atoi(SQLResultGetValue(&oResult, 5, nIdxInResult));
+    int nTileMatrixHeight = atoi(SQLResultGetValue(&oResult, 6, nIdxInResult));
+
+    /* Use content bounds in priority over tile_matrix_set bounds */
+    double dfGDALMinX = dfMinX;
+    double dfGDALMinY = dfMinY;
+    double dfGDALMaxX = dfMaxX;
+    double dfGDALMaxY = dfMaxY;
+    pszContentsMinX = CSLFetchNameValueDef(papszOpenOptions, "MINX", pszContentsMinX);
+    pszContentsMinY = CSLFetchNameValueDef(papszOpenOptions, "MINY", pszContentsMinY);
+    pszContentsMaxX = CSLFetchNameValueDef(papszOpenOptions, "MAXX", pszContentsMaxX);
+    pszContentsMaxY = CSLFetchNameValueDef(papszOpenOptions, "MAXY", pszContentsMaxY);
+    if( pszContentsMinX != NULL && pszContentsMinY != NULL &&
+        pszContentsMaxX != NULL && pszContentsMaxY != NULL )
+    {
+        dfGDALMinX = CPLAtof(pszContentsMinX);
+        dfGDALMinY = CPLAtof(pszContentsMinY);
+        dfGDALMaxX = CPLAtof(pszContentsMaxX);
+        dfGDALMaxY = CPLAtof(pszContentsMaxY);
+    }
+    if( dfGDALMinX >= dfGDALMaxX || dfGDALMinY >= dfGDALMaxY )
+    {
+        return FALSE;
+    }
+
+    int nBandCount = atoi(CSLFetchNameValueDef(papszOpenOptions, "BAND_COUNT", "4"));
+    if( nBandCount != 1 && nBandCount != 2 && nBandCount != 3 && nBandCount != 4 )
+        nBandCount = 4;
+
+    return InitRaster(poParentDS, pszTableName, nZoomLevel, nBandCount, dfMinX, dfMaxY,
+                      dfPixelXSize, dfPixelYSize, nTileWidth, nTileHeight,
+                      nTileMatrixWidth, nTileMatrixHeight,
+                      dfGDALMinX, dfGDALMinY, dfGDALMaxX, dfGDALMaxY );
 }
 
 /************************************************************************/
-/*                                Create()                              */
+/*                      ComputeTileAndPixelShifts()                     */
 /************************************************************************/
 
-int OGRGeoPackageDataSource::Create( const char * pszFilename,
-                                     CPL_UNUSED char **papszOptions )
+void GDALGeoPackageDataset::ComputeTileAndPixelShifts()
 {
-    CPLString osCommand;
-    const char *pszSpatialRefSysRecord;
+    int nTileWidth, nTileHeight;
+    GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight);
 
-	/* The OGRGeoPackageDriver has already confirmed that the pszFilename */
-	/* is not already in use, so try to create the file */
-    int rc = sqlite3_open( pszFilename, &m_poDb );
-    if ( rc != SQLITE_OK )
-    {
-        m_poDb = NULL;
-        CPLError( CE_Failure, CPLE_OpenFailed, "sqlite3_open(%s) failed: %s",
-                  pszFilename, sqlite3_errmsg( m_poDb ) );
-        return FALSE;
-    }
-
-    m_pszFileName = CPLStrdup(pszFilename);
-    m_bUpdate = TRUE;
+    // Compute shift between GDAL origin and TileMatrixSet origin
+    int nShiftXPixels = (int)floor(0.5 + (m_adfGeoTransform[0] - m_dfTMSMinX) /  m_adfGeoTransform[1]);
+    m_nShiftXTiles = (int)floor(1.0 * nShiftXPixels / nTileWidth);
+    m_nShiftXPixelsMod = ((nShiftXPixels % nTileWidth) + nTileWidth) % nTileWidth;
+    int nShiftYPixels = (int)floor(0.5 + (m_adfGeoTransform[3] - m_dfTMSMaxY) /  m_adfGeoTransform[5]);
+    m_nShiftYTiles = (int)floor(1.0 * nShiftYPixels / nTileHeight);
+    m_nShiftYPixelsMod = ((nShiftYPixels % nTileHeight) + nTileHeight) % nTileHeight;
 
-    /* OGR UTF-8 support. If we set the UTF-8 Pragma early on, it */
-    /* will be written into the main file and supported henceforth */
-    SQLCommand(m_poDb, "PRAGMA encoding = \"UTF-8\"");
+}
 
-    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) in the application id */
-    /* http://opengis.github.io/geopackage/#_file_format */
-    const char *pszPragma = CPLSPrintf("PRAGMA application_id = %d", GPKG_APPLICATION_ID);
-    
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszPragma) )
-        return FALSE;
-        
-    /* Requirement 10: A GeoPackage SHALL include a gpkg_spatial_ref_sys table */
-    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
-    const char *pszSpatialRefSys = 
-        "CREATE TABLE gpkg_spatial_ref_sys ("
-        "srs_name TEXT NOT NULL,"
-        "srs_id INTEGER NOT NULL PRIMARY KEY,"
-        "organization TEXT NOT NULL,"
-        "organization_coordsys_id INTEGER NOT NULL,"
-        "definition  TEXT NOT NULL,"
-        "description TEXT"
-        ")";
-        
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSys) )
-        return FALSE;
+/************************************************************************/
+/*                         InitRaster()                                 */
+/************************************************************************/
 
-    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
-    /* contain a record for EPSG:4326, the geodetic WGS84 SRS */
-    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
-    pszSpatialRefSysRecord = 
-        "INSERT INTO gpkg_spatial_ref_sys ("
-        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
-        ") VALUES ("
-        "'WGS 84 geodetic', 4326, 'EPSG', 4326, '"
-        "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"
-        "', 'longitude/latitude coordinates in decimal degrees on the WGS 84 spheroid'"
-        ")";  
-          
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
+int GDALGeoPackageDataset::InitRaster ( GDALGeoPackageDataset* poParentDS,
+                                        const char* pszTableName,
+                                        int nZoomLevel,
+                                        int nBandCount,
+                                        double dfTMSMinX,
+                                        double dfTMSMaxY,
+                                        double dfPixelXSize,
+                                        double dfPixelYSize,
+                                        int nTileWidth,
+                                        int nTileHeight,
+                                        int nTileMatrixWidth,
+                                        int nTileMatrixHeight,
+                                        double dfGDALMinX,
+                                        double dfGDALMinY,
+                                        double dfGDALMaxX,
+                                        double dfGDALMaxY )
+{
+    m_osRasterTable = pszTableName;
+    m_dfTMSMinX = dfTMSMinX;
+    m_dfTMSMaxY = dfTMSMaxY;
+    m_nZoomLevel = nZoomLevel;
+    m_nTileMatrixWidth = nTileMatrixWidth;
+    m_nTileMatrixHeight = nTileMatrixHeight;
+
+    m_bGeoTransformValid = TRUE;
+    m_adfGeoTransform[0] = dfGDALMinX;
+    m_adfGeoTransform[1] = dfPixelXSize;
+    m_adfGeoTransform[3] = dfGDALMaxY;
+    m_adfGeoTransform[5] = -dfPixelYSize;
+    double dfRasterXSize = 0.5 + (dfGDALMaxX - dfGDALMinX) / dfPixelXSize;
+    double dfRasterYSize = 0.5 + (dfGDALMaxY - dfGDALMinY) / dfPixelYSize;
+    if( dfRasterXSize > INT_MAX || dfRasterYSize > INT_MAX )
         return FALSE;
+    nRasterXSize = (int)dfRasterXSize;
+    nRasterYSize = (int)dfRasterYSize;
 
-    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
-    /* contain a record with an srs_id of -1, an organization of “NONE”, */
-    /* an organization_coordsys_id of -1, and definition “undefined” */
-    /* for undefined Cartesian coordinate reference systems */
-    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
-    pszSpatialRefSysRecord = 
-        "INSERT INTO gpkg_spatial_ref_sys ("
-        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
-        ") VALUES ("
-        "'Undefined cartesian SRS', -1, 'NONE', -1, 'undefined', 'undefined cartesian coordinate reference system'"
-        ")"; 
-           
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
+    m_pabyCachedTiles = (GByte*) VSIMalloc3(4 * 4, nTileWidth, nTileHeight);
+    if( m_pabyCachedTiles == NULL )
+    {
         return FALSE;
+    }
 
-    /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
-    /* contain a record with an srs_id of 0, an organization of “NONE”, */
-    /* an organization_coordsys_id of 0, and definition “undefined” */
-    /* for undefined geographic coordinate reference systems */
-    /* http://opengis.github.io/geopackage/#spatial_ref_sys */
-    pszSpatialRefSysRecord = 
-        "INSERT INTO gpkg_spatial_ref_sys ("
-        "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
-        ") VALUES ("
-        "'Undefined geographic SRS', 0, 'NONE', 0, 'undefined', 'undefined geographic coordinate reference system'"
-        ")"; 
-           
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszSpatialRefSysRecord) )
-        return FALSE;
-    
-    /* Requirement 13: A GeoPackage file SHALL include a gpkg_contents table */
-    /* http://opengis.github.io/geopackage/#_contents */
-    const char *pszContents =
-        "CREATE TABLE gpkg_contents ("
-        "table_name TEXT NOT NULL PRIMARY KEY,"
-        "data_type TEXT NOT NULL,"
-        "identifier TEXT UNIQUE,"
-        "description TEXT DEFAULT '',"
-        "last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ',CURRENT_TIMESTAMP)),"
-        "min_x DOUBLE, min_y DOUBLE,"
-        "max_x DOUBLE, max_y DOUBLE,"
-        "srs_id INTEGER,"
-        "CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)"
-        ")";
-        
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszContents) )
-        return FALSE;
+    for(int i = 1; i <= nBandCount; i ++)
+        SetBand( i, new GDALGeoPackageRasterBand(this, i, nTileWidth, nTileHeight) );
 
-    /* Requirement 21: A GeoPackage with a gpkg_contents table row with a “features” */
-    /* data_type SHALL contain a gpkg_geometry_columns table or updateable view */
-    /* http://opengis.github.io/geopackage/#_geometry_columns */
-    const char *pszGeometryColumns =        
-        "CREATE TABLE gpkg_geometry_columns ("
-        "table_name TEXT NOT NULL,"
-        "column_name TEXT NOT NULL,"
-        "geometry_type_name TEXT NOT NULL,"
-        "srs_id INTEGER NOT NULL,"
-        "z TINYINT NOT NULL,"
-        "m TINYINT NOT NULL,"
-        "CONSTRAINT pk_geom_cols PRIMARY KEY (table_name, column_name),"
-        "CONSTRAINT uk_gc_table_name UNIQUE (table_name),"
-        "CONSTRAINT fk_gc_tn FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name),"
-        "CONSTRAINT fk_gc_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)"
-        ")";
-        
-    if ( OGRERR_NONE != SQLCommand(m_poDb, pszGeometryColumns) )
-        return FALSE;
+    ComputeTileAndPixelShifts();
 
-    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) */
-    /* in the application id field of the SQLite database header */
-    /* We have to do this after there's some content so the database file */
-    /* is not zero length */
-    SetApplicationId();
+    GDALPamDataset::SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
+    GDALPamDataset::SetMetadataItem("ZOOM_LEVEL", CPLSPrintf("%d", m_nZoomLevel));
 
+    if( poParentDS )
+    {
+        m_poParentDS = poParentDS;
+        bUpdate = poParentDS->bUpdate;
+        eAccess = poParentDS->eAccess;
+        hDB = poParentDS->hDB;
+        m_eTF = poParentDS->m_eTF;
+        m_nQuality = poParentDS->m_nQuality;
+        m_nZLevel = poParentDS->m_nZLevel;
+        m_bDither = poParentDS->m_bDither;
+        /*m_nSRID = poParentDS->m_nSRID;*/
+        m_osWHERE = poParentDS->m_osWHERE;
+        SetDescription(CPLSPrintf("%s - zoom_level=%d",
+                                  poParentDS->GetDescription(), m_nZoomLevel));
+    }
 
     return TRUE;
 }
 
-
-/************************************************************************/
-/*                              AddColumn()                             */
-/************************************************************************/
-
-OGRErr OGRGeoPackageDataSource::AddColumn(const char *pszTableName, const char *pszColumnName, const char *pszColumnType)
-{
-    char *pszSQL;
-    
-    pszSQL = sqlite3_mprintf("ALTER TABLE %s ADD COLUMN %s %s", 
-                             pszTableName, pszColumnName, pszColumnType);
-
-    OGRErr err = SQLCommand(m_poDb, pszSQL);
-    sqlite3_free(pszSQL);
-    
-    return err;
-}
-
-
 /************************************************************************/
-/*                              GetLayer()                              */
+/*                         GetTileFormat()                              */
 /************************************************************************/
 
-OGRLayer* OGRGeoPackageDataSource::GetLayer( int iLayer )
-
+static GPKGTileFormat GetTileFormat(const char* pszTF )
 {
-    if( iLayer < 0 || iLayer >= m_nLayers )
-        return NULL;
-    else
-        return m_papoLayers[iLayer];
+    GPKGTileFormat eTF = GPKG_TF_PNG_JPEG;
+    if( pszTF )
+    {
+        if( EQUAL(pszTF, "PNG_JPEG") )
+            eTF = GPKG_TF_PNG_JPEG;
+        else if( EQUAL(pszTF, "PNG") )
+            eTF = GPKG_TF_PNG;
+        else if( EQUAL(pszTF, "PNG8") )
+            eTF = GPKG_TF_PNG8;
+        else if( EQUAL(pszTF, "JPEG") )
+            eTF = GPKG_TF_JPEG;
+        else if( EQUAL(pszTF, "WEBP") )
+            eTF = GPKG_TF_WEBP;
+    }
+    return eTF;
 }
 
-
 /************************************************************************/
-/*                           CreateLayer()                              */
-/* Options:                                                             */
-/*   FID = primary key name                                             */
-/*   OVERWRITE = YES|NO, overwrite existing layer?                      */
-/*   SPATIAL_INDEX = YES|NO, TBD                                        */
+/*                         OpenRaster()                                 */
 /************************************************************************/
 
-OGRLayer* OGRGeoPackageDataSource::CreateLayer( const char * pszLayerName,
-                                      OGRSpatialReference * poSpatialRef,
-                                      OGRwkbGeometryType eGType,
-                                      char **papszOptions )
+int GDALGeoPackageDataset::OpenRaster( const char* pszTableName,
+                                       const char* pszIdentifier,
+                                       const char* pszDescription,
+                                       int nSRSId,
+                                       double dfMinX,
+                                       double dfMinY,
+                                       double dfMaxX,
+                                       double dfMaxY,
+                                       const char* pszContentsMinX,
+                                       const char* pszContentsMinY,
+                                       const char* pszContentsMaxX,
+                                       const char* pszContentsMaxY,
+                                       char** papszOpenOptions )
 {
-    int iLayer;
     OGRErr err;
-    
-    if( !m_bUpdate )
-        return NULL;
+    SQLResult oResult;
 
-    /* Read GEOMETRY_COLUMN option */
-    const char* pszGeomColumnName = CSLFetchNameValue(papszOptions, "GEOMETRY_COLUMN");
-    if (pszGeomColumnName == NULL)
-        pszGeomColumnName = "geom";
-    
-    /* Read FID option */
-    const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
-    if (pszFIDColumnName == NULL)
-        pszFIDColumnName = "fid";
+    if( dfMinX >= dfMaxX || dfMinY >= dfMaxY )
+        return FALSE;
 
-    if ( strspn(pszFIDColumnName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
+    m_bRecordInsertedInGPKGContent = TRUE;
+    m_nSRID = nSRSId;
+    if( nSRSId > 0 )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "The primary key (%s) name may not contain special characters or spaces", 
-                 pszFIDColumnName);
-        return NULL;
+        OGRSpatialReference* poSRS = GetSpatialRef( nSRSId );
+        if( poSRS )
+        {
+            poSRS->exportToWkt(&m_pszProjection);
+            delete poSRS;
+        }
     }
 
-    /* Avoiding gpkg prefixes is not an official requirement, but seems wise */
-    if (strncmp(pszLayerName, "gpkg", 4) == 0)
+    /* The NOT NULL are just in case the tables would have been built without */
+    /* the mandatory constraints */
+    char* pszQuotedTableName = sqlite3_mprintf("'%q'", pszTableName);
+    CPLString osQuotedTableName(pszQuotedTableName);
+    sqlite3_free(pszQuotedTableName);
+    char* pszSQL = sqlite3_mprintf(
+            "SELECT zoom_level, pixel_x_size, pixel_y_size, tile_width, tile_height, matrix_width, matrix_height FROM gpkg_tile_matrix tm "
+            "WHERE table_name = %s AND pixel_x_size > 0 "
+            "AND pixel_y_size > 0 AND tile_width > 0 AND tile_height > 0 AND matrix_width > 0 AND matrix_height > 0",
+            osQuotedTableName.c_str());
+    CPLString osSQL(pszSQL);
+    const char* pszZoomLevel =  CSLFetchNameValue(papszOpenOptions, "ZOOM_LEVEL");
+    if( pszZoomLevel )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "The layer name may not begin with 'gpkg' as it is a reserved geopackage prefix");
-        return NULL;
+        if( bUpdate )
+            osSQL += CPLSPrintf(" AND zoom_level <= %d", atoi(pszZoomLevel));
+        else
+        {
+            osSQL += CPLSPrintf(" AND (zoom_level = %d OR (zoom_level < %d AND EXISTS(SELECT 1 FROM %s WHERE zoom_level = tm.zoom_level LIMIT 1)))",
+                                atoi(pszZoomLevel), atoi(pszZoomLevel), osQuotedTableName.c_str());
+        }
     }
-
-    /* Pre-emptively try and avoid sqlite3 syntax errors due to  */
-    /* illegal characters */
-    if ( strspn(pszLayerName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
+    // In read-only mode, only lists non empty zoom levels
+    else if( !bUpdate )
     {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "The layer name may not contain special characters or spaces");
-        return NULL;
+        osSQL += CPLSPrintf(" AND EXISTS(SELECT 1 FROM %s WHERE zoom_level = tm.zoom_level LIMIT 1)",
+                            osQuotedTableName.c_str());
     }
+    else if( pszZoomLevel == NULL )
+    {
+        osSQL += CPLSPrintf(" AND zoom_level <= (SELECT MAX(zoom_level) FROM %s)",
+                            osQuotedTableName.c_str());
+    }
+    osSQL += " ORDER BY zoom_level DESC";
 
-    /* Check for any existing layers that already use this name */
-    for( iLayer = 0; iLayer < m_nLayers; iLayer++ )
+    err = SQLQuery(hDB, osSQL.c_str(), &oResult);
+    if( err != OGRERR_NONE || oResult.nRowCount == 0 )
     {
-        if( EQUAL(pszLayerName, m_papoLayers[iLayer]->GetName()) )
+        if( err == OGRERR_NONE && oResult.nRowCount == 0 &&
+            pszContentsMinX != NULL && pszContentsMinY != NULL &&
+            pszContentsMaxX != NULL && pszContentsMaxY != NULL )
         {
-            const char *pszOverwrite = CSLFetchNameValue(papszOptions,"OVERWRITE");
-            if( pszOverwrite != NULL && CSLTestBoolean(pszOverwrite) )
-            {
-                DeleteLayer( iLayer );
-            }
-            else
-            {
-                CPLError( CE_Failure, CPLE_AppDefined,
-                          "Layer %s already exists, CreateLayer failed.\n"
-                          "Use the layer creation option OVERWRITE=YES to "
-                          "replace it.",
-                          pszLayerName );
-                return NULL;
-            }
+            SQLResultFree(&oResult);
+            osSQL = pszSQL;
+            osSQL += " ORDER BY zoom_level DESC LIMIT 1";
+            err = SQLQuery(hDB, osSQL.c_str(), &oResult);
+        }
+        if( err != OGRERR_NONE || oResult.nRowCount == 0 )
+        {
+            SQLResultFree(&oResult);
+            sqlite3_free(pszSQL);
+            return FALSE;
         }
     }
+    sqlite3_free(pszSQL);
 
-    /* Read our SRS_ID from the OGRSpatialReference */
-    int nSRSId = UNDEFINED_SRID;
-    if( poSpatialRef != NULL )
-        nSRSId = GetSrsId( poSpatialRef );
-        
-    /* Requirement 25: The geometry_type_name value in a gpkg_geometry_columns */
-    /* row SHALL be one of the uppercase geometry type names specified in */
-    /* Geometry Types (Normative). */
-    const char *pszGeometryType = OGRToOGCGeomType(eGType);
-    
-    /* Create the table! */
-    char *pszSQL = NULL;
-    if ( eGType != wkbNone )
-    {
-        pszSQL = sqlite3_mprintf(
-            "CREATE TABLE %s ( "
-            "%s INTEGER PRIMARY KEY AUTOINCREMENT, "
-            "%s %s )",
-             pszLayerName, pszFIDColumnName, pszGeomColumnName, pszGeometryType);
-    }
-    else
+    // If USE_TILE_EXTENT=YES, then query the tile table to find which tiles
+    // actually exist.
+    CPLString osContentsMinX, osContentsMinY, osContentsMaxX, osContentsMaxY;
+    if( CSLTestBoolean(CSLFetchNameValueDef(papszOpenOptions, "USE_TILE_EXTENT", "NO")) )
     {
         pszSQL = sqlite3_mprintf(
-            "CREATE TABLE %s ( "
-            "%s INTEGER PRIMARY KEY AUTOINCREMENT )",
-             pszLayerName, pszFIDColumnName);
+            "SELECT MIN(tile_column), MIN(tile_row), MAX(tile_column), MAX(tile_row) FROM '%q' WHERE zoom_level = %d",
+            pszTableName, atoi(SQLResultGetValue(&oResult, 0, 0)));
+        SQLResult oResult2;
+        err = SQLQuery(hDB, pszSQL, &oResult2);
+        sqlite3_free(pszSQL);
+        if  ( err != OGRERR_NONE || oResult2.nRowCount == 0 )
+        {
+            SQLResultFree(&oResult);
+            SQLResultFree(&oResult2);
+            return FALSE;
+        }
+        double dfPixelXSize = CPLAtof(SQLResultGetValue(&oResult, 1, 0));
+        double dfPixelYSize = CPLAtof(SQLResultGetValue(&oResult, 2, 0));
+        int nTileWidth = atoi(SQLResultGetValue(&oResult, 3, 0));
+        int nTileHeight = atoi(SQLResultGetValue(&oResult, 4, 0));
+        osContentsMinX = CPLSPrintf("%.18g", dfMinX + dfPixelXSize * nTileWidth * atoi(SQLResultGetValue(&oResult2, 0, 0)));
+        osContentsMaxY = CPLSPrintf("%.18g", dfMaxY - dfPixelYSize * nTileHeight * atoi(SQLResultGetValue(&oResult2, 1, 0)));
+        osContentsMaxX = CPLSPrintf("%.18g", dfMinX + dfPixelXSize * nTileWidth * (1 + atoi(SQLResultGetValue(&oResult2, 2, 0))));
+        osContentsMinY = CPLSPrintf("%.18g", dfMaxY - dfPixelYSize * nTileHeight * (1 + atoi(SQLResultGetValue(&oResult2, 3, 0))));
+        pszContentsMinX = osContentsMinX.c_str();
+        pszContentsMinY = osContentsMinY.c_str();
+        pszContentsMaxX = osContentsMaxX.c_str();
+        pszContentsMaxY = osContentsMaxY.c_str();
+        SQLResultFree(&oResult2);
     }
     
-    err = SQLCommand(m_poDb, pszSQL);
-    sqlite3_free(pszSQL);
-    if ( OGRERR_NONE != err )
-        return NULL;
+    if(! InitRaster ( NULL, pszTableName, dfMinX, dfMinY, dfMaxX, dfMaxY,
+                 pszContentsMinX, pszContentsMinY, pszContentsMaxX, pszContentsMaxY,
+                 papszOpenOptions, oResult, 0) )
+    {
+        SQLResultFree(&oResult);
+        return FALSE;
+    }
+
+    CheckUnknownExtensions(TRUE);
 
-    /* Only spatial tables need to be registered in the metadata (hmmm) */
-    if ( eGType != wkbNone )
+    // Do this after CheckUnknownExtensions() so that m_eTF is set to GPKG_TF_WEBP
+    // if the table already registers the gpkg_webp extension
+    const char* pszTF = CSLFetchNameValue(papszOpenOptions, "TILE_FORMAT");
+    if( pszTF )
     {
-        /* Requirement 27: The z value in a gpkg_geometry_columns table row */
-        /* SHALL be one of 0 (none), 1 (mandatory), or 2 (optional) */
-        int bGeometryTypeHasZ = (wkb25DBit & eGType) != 0;
+        if( !bUpdate )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "DRIVER open option ignored in read-only mode");
+        }
+        else
+        {
+            GPKGTileFormat eTF = GetTileFormat(pszTF);
+            if( eTF == GPKG_TF_WEBP && m_eTF != eTF )
+            {
+                if( !RegisterWebPExtension() )
+                    return FALSE;
+            }
+            m_eTF = eTF;
+        }
+    }
 
-        /* Update gpkg_geometry_columns with the table info */
-        pszSQL = sqlite3_mprintf(
-            "INSERT INTO gpkg_geometry_columns "
-            "(table_name,column_name,geometry_type_name,srs_id,z,m)"
-            " VALUES "
-            "('%q','%q','%q',%d,%d,%d)",
-            pszLayerName,pszGeomColumnName,pszGeometryType,
-            nSRSId,bGeometryTypeHasZ,0);
-    
-        err = SQLCommand(m_poDb, pszSQL);
-        sqlite3_free(pszSQL);
-        if ( err != OGRERR_NONE )
-            return NULL;
+    ParseCompressionOptions(papszOpenOptions);
 
-        /* Update gpkg_contents with the table info */
-        pszSQL = sqlite3_mprintf(
-            "INSERT INTO gpkg_contents "
-            "(table_name,data_type,identifier,last_change,srs_id)"
-            " VALUES "
-            "('%q','features','%q',strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ',CURRENT_TIMESTAMP),%d)",
-            pszLayerName, pszLayerName, nSRSId);
-    
-        err = SQLCommand(m_poDb, pszSQL);
-        sqlite3_free(pszSQL);
-        if ( err != OGRERR_NONE )
-            return NULL;
+    m_osWHERE = CSLFetchNameValueDef(papszOpenOptions, "WHERE", "");
 
-    }
+    // Set metadata
+    if( pszIdentifier && pszIdentifier[0] )
+        GDALPamDataset::SetMetadataItem("IDENTIFIER", pszIdentifier);
+    if( pszDescription && pszDescription[0] )
+        GDALPamDataset::SetMetadataItem("DESCRIPTION", pszDescription);
 
-    /* This is where spatial index logic will go in the future */
-    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
-    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
-    if( eGType != wkbNone && bCreateSpatialIndex )
-    {
-        /* This is where spatial index logic will go in the future */
-    }
-    
-    /* The database is now all set up, so create a blank layer and read in the */
-    /* info from the database. */
-    OGRGeoPackageLayer *poLayer = new OGRGeoPackageLayer(this, pszLayerName);
-    
-    if( OGRERR_NONE != poLayer->ReadTableDefinition() )
+    // Add overviews
+    for( int i = 1; i < oResult.nRowCount; i++ )
     {
-        delete poLayer;
-        return NULL;
+        GDALGeoPackageDataset* poOvrDS = new GDALGeoPackageDataset();
+        poOvrDS->InitRaster ( this, pszTableName, dfMinX, dfMinY, dfMaxX, dfMaxY,
+                 pszContentsMinX, pszContentsMinY, pszContentsMaxX, pszContentsMaxY,
+                 papszOpenOptions, oResult, i);
+
+        m_papoOverviewDS = (GDALGeoPackageDataset**) CPLRealloc(m_papoOverviewDS,
+                        sizeof(GDALGeoPackageDataset*) * (m_nOverviewCount+1));
+        m_papoOverviewDS[m_nOverviewCount ++] = poOvrDS;
+
+        int nTileWidth, nTileHeight;
+        poOvrDS->GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight);
+        if( poOvrDS->GetRasterXSize() < nTileWidth &&
+            poOvrDS->GetRasterYSize() < nTileHeight )
+        {
+            break;
+        }
     }
 
-    m_papoLayers = (OGRLayer**)CPLRealloc(m_papoLayers,  sizeof(OGRGeoPackageLayer*) * (m_nLayers+1));
-    m_papoLayers[m_nLayers++] = poLayer;
-    return poLayer;
-}
+    SQLResultFree(&oResult);
 
+    return TRUE;
+}
 
 /************************************************************************/
-/*                            DeleteLayer()                             */
+/*                         GetProjectionRef()                           */
 /************************************************************************/
 
-int OGRGeoPackageDataSource::DeleteLayer( int iLayer )
+const char* GDALGeoPackageDataset::GetProjectionRef()
 {
-    char *pszSQL;
-
-    if( !m_bUpdate || iLayer < 0 || iLayer >= m_nLayers )
-        return OGRERR_FAILURE;
+    return (m_pszProjection) ? m_pszProjection : "";
+}
 
-    CPLString osLayerName = m_papoLayers[iLayer]->GetLayerDefn()->GetName();
+/************************************************************************/
+/*                           SetProjection()                            */
+/************************************************************************/
 
-    CPLDebug( "GPKG", "DeleteLayer(%s)", osLayerName.c_str() );
+CPLErr GDALGeoPackageDataset::SetProjection( const char* pszProjection )
+{
+    if( nBands == 0)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetProjection() not supported on a dataset with 0 band");
+        return CE_Failure;
+    }
+    if( eAccess != GA_Update )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetProjection() not supported on read-only dataset");
+        return CE_Failure;
+    }
 
-    /* Delete the layer object and remove the gap in the layers list */
-    delete m_papoLayers[iLayer];
-    memmove( m_papoLayers + iLayer, m_papoLayers + iLayer + 1,
-             sizeof(void *) * (m_nLayers - iLayer - 1) );
-    m_nLayers--;
+    int nSRID;
+    if( pszProjection == NULL || pszProjection[0] == '\0' )
+    {
+        nSRID = -1;
+    }
+    else
+    {
+        OGRSpatialReference oSRS;
+        if( oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE )
+            return CE_Failure;
+        nSRID = GetSrsId( &oSRS );
+    }
 
-    if (osLayerName.size() == 0)
-        return OGRERR_NONE;
+    for(size_t iScheme = 0;
+               iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]);
+               iScheme++ )
+    {
+        if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) )
+        {
+            if( nSRID != asTilingShemes[iScheme].nEPSGCode )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported,
+                        "Projection should be EPSG:%d for %s tiling scheme",
+                         asTilingShemes[iScheme].nEPSGCode,
+                         m_osTilingScheme.c_str());
+                return CE_Failure;
+            }
+        }
+    }
 
-    pszSQL = sqlite3_mprintf(
-            "DROP TABLE %s",
-             osLayerName.c_str());
-    
-    SQLCommand(m_poDb, pszSQL);
-    sqlite3_free(pszSQL);
+    m_nSRID = nSRID;
+    CPLFree(m_pszProjection);
+    m_pszProjection = pszProjection ? CPLStrdup(pszProjection) : CPLStrdup("");
 
-    pszSQL = sqlite3_mprintf(
-            "DELETE FROM gpkg_geometry_columns WHERE table_name = '%s'",
-             osLayerName.c_str());
-    
-    SQLCommand(m_poDb, pszSQL);
-    sqlite3_free(pszSQL);
-    
-    pszSQL = sqlite3_mprintf(
-             "DELETE FROM gpkg_contents WHERE table_name = '%s'",
-              osLayerName.c_str());
+    if( m_bRecordInsertedInGPKGContent )
+    {
+        char* pszSQL = sqlite3_mprintf("UPDATE gpkg_contents SET srs_id = %d WHERE table_name = '%q'",
+                                        m_nSRID, m_osRasterTable.c_str());
+        OGRErr eErr = SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+        if ( eErr != OGRERR_NONE )
+            return CE_Failure;
 
-    SQLCommand(m_poDb, pszSQL);
-    sqlite3_free(pszSQL);
+        pszSQL = sqlite3_mprintf("UPDATE gpkg_tile_matrix_set SET srs_id = %d WHERE table_name = '%q'",
+                                 m_nSRID, m_osRasterTable.c_str());
+        eErr = SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+        if ( eErr != OGRERR_NONE )
+            return CE_Failure;
+    }
 
-    return OGRERR_NONE;
+    return CE_None;
 }
 
+/************************************************************************/
+/*                          GetGeoTransform()                           */
+/************************************************************************/
 
+CPLErr GDALGeoPackageDataset::GetGeoTransform( double* padfGeoTransform )
+{
+    memcpy(padfGeoTransform, m_adfGeoTransform, 6 * sizeof(double));
+    if( !m_bGeoTransformValid )
+        return CE_Failure;
+    else
+        return CE_None;
+}
 
 /************************************************************************/
-/*                       TestCapability()                               */
+/*                          SetGeoTransform()                           */
 /************************************************************************/
 
-int OGRGeoPackageDataSource::TestCapability( const char * pszCap )
+CPLErr GDALGeoPackageDataset::SetGeoTransform( double* padfGeoTransform )
 {
-    if ( EQUAL(pszCap,ODsCCreateLayer) ||
-         EQUAL(pszCap,ODsCDeleteLayer) )
+    if( nBands == 0)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetGeoTransform() not supported on a dataset with 0 band");
+        return CE_Failure;
+    }
+    if( eAccess != GA_Update )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetGeoTransform() not supported on read-only dataset");
+        return CE_Failure;
+    }
+    if( m_bGeoTransformValid )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Cannot modify geotransform once set");
+        return CE_Failure;
+    }
+    if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0 ||
+        padfGeoTransform[5] > 0.0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Only north-up non rotated geotransform supported");
+        return CE_Failure;
+    }
+
+    for(size_t iScheme = 0;
+               iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]);
+               iScheme++ )
     {
-         return m_bUpdate;
+        if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) )
+        {
+            double dfPixelXSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0;
+            double dfPixelYSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelYSizeZoomLevel0;
+            for( m_nZoomLevel = 0; m_nZoomLevel < 25; m_nZoomLevel++ )
+            {
+                double dfExpectedPixelXSize = dfPixelXSizeZoomLevel0 / (1 << m_nZoomLevel);
+                double dfExpectedPixelYSize = dfPixelYSizeZoomLevel0 / (1 << m_nZoomLevel);
+                if( fabs( padfGeoTransform[1] - dfExpectedPixelXSize ) < 1e-8 * dfExpectedPixelXSize &&
+                    fabs( fabs(padfGeoTransform[5]) - dfExpectedPixelYSize ) < 1e-8 * dfExpectedPixelYSize )
+                {
+                    break;
+                }
+            }
+            if( m_nZoomLevel == 25 )
+            {
+                m_nZoomLevel = -1;
+                CPLError(CE_Failure, CPLE_NotSupported,
+                         "Could not find an appropriate zoom level of %s tiling scheme that matches raster pixel size",
+                         m_osTilingScheme.c_str());
+                return CE_Failure;
+            }
+            break;
+        }
     }
-    return FALSE;
+
+    memcpy(m_adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
+    m_bGeoTransformValid = TRUE;
+
+    return FinalizeRasterRegistration();
 }
 
 /************************************************************************/
-/*                             ExecuteSQL()                             */
+/*                      FinalizeRasterRegistration()                    */
 /************************************************************************/
 
-OGRLayer * OGRGeoPackageDataSource::ExecuteSQL( const char *pszSQLCommand,
-                                          OGRGeometry *poSpatialFilter,
-                                          const char *pszDialect )
-
+CPLErr GDALGeoPackageDataset::FinalizeRasterRegistration()
 {
-    if( EQUALN(pszSQLCommand, "SELECT ", 7) ||
-        (pszDialect != NULL && EQUAL(pszDialect,"OGRSQL")) )
-        return OGRDataSource::ExecuteSQL( pszSQLCommand, 
-                                          poSpatialFilter, 
-                                          pszDialect );
-
-/* -------------------------------------------------------------------- */
-/*      Prepare statement.                                              */
-/* -------------------------------------------------------------------- */
-    int rc;
-    sqlite3_stmt *hSQLStmt = NULL;
+    OGRErr eErr;
+    char* pszSQL;
 
-    CPLString osSQLCommand = pszSQLCommand;
+    m_dfTMSMinX = m_adfGeoTransform[0];
+    m_dfTMSMaxY = m_adfGeoTransform[3];
 
-#if 0
-    /* This will speed-up layer creation */
-    /* ORDER BY are costly to evaluate and are not necessary to establish */
-    /* the layer definition. */
-    int bUseStatementForGetNextFeature = TRUE;
-    int bEmptyLayer = FALSE;
+    int nTileWidth, nTileHeight;
+    GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight);
+    m_nTileMatrixWidth = (nRasterXSize + nTileWidth - 1) / nTileWidth;
+    m_nTileMatrixHeight = (nRasterYSize + nTileHeight - 1) / nTileHeight;
 
-    if( osSQLCommand.ifind("SELECT ") == 0 &&
-        osSQLCommand.ifind(" UNION ") == std::string::npos &&
-        osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
-        osSQLCommand.ifind(" EXCEPT ") == std::string::npos )
+    if( m_nZoomLevel < 0 )
     {
-        size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
-        if( nOrderByPos != std::string::npos )
+        m_nZoomLevel = 0;
+        while( (nRasterXSize >> m_nZoomLevel) > nTileWidth ||
+            (nRasterYSize >> m_nZoomLevel) > nTileHeight )
+            m_nZoomLevel ++;
+    }
+    
+    double dfPixelXSizeZoomLevel0 = m_adfGeoTransform[1] * (1 << m_nZoomLevel);
+    double dfPixelYSizeZoomLevel0 = fabs(m_adfGeoTransform[5]) * (1 << m_nZoomLevel);
+    int nTileXCountZoomLevel0 = ((nRasterXSize >> m_nZoomLevel) + nTileWidth - 1) / nTileWidth;
+    int nTileYCountZoomLevel0 = ((nRasterYSize >> m_nZoomLevel) + nTileHeight - 1) / nTileHeight;
+
+    for(size_t iScheme = 0;
+               iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]);
+               iScheme++ )
+    {
+        if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) )
         {
-            osSQLCommand.resize(nOrderByPos);
-            bUseStatementForGetNextFeature = FALSE;
+            CPLAssert( m_nZoomLevel >= 0 );
+            m_dfTMSMinX = asTilingShemes[iScheme].dfMinX;
+            m_dfTMSMaxY = asTilingShemes[iScheme].dfMaxY;
+            dfPixelXSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0;
+            dfPixelYSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelYSizeZoomLevel0;
+            nTileXCountZoomLevel0 = asTilingShemes[iScheme].nTileXCountZoomLevel0;
+            nTileYCountZoomLevel0 = asTilingShemes[iScheme].nTileYCountZoomLevel0;
+            m_nTileMatrixWidth = nTileXCountZoomLevel0 * (1 << m_nZoomLevel);
+            m_nTileMatrixHeight = nTileYCountZoomLevel0 * (1 << m_nZoomLevel);
+            break;
         }
     }
-#endif
 
-    rc = sqlite3_prepare( m_poDb, osSQLCommand.c_str(), osSQLCommand.size(),
-                          &hSQLStmt, NULL );
+    ComputeTileAndPixelShifts();
 
-    if( rc != SQLITE_OK )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                "In ExecuteSQL(): sqlite3_prepare(%s):\n  %s", 
-                pszSQLCommand, sqlite3_errmsg(m_poDb) );
+    double dfGDALMinX = m_adfGeoTransform[0];
+    double dfGDALMinY = m_adfGeoTransform[3] + nRasterYSize * m_adfGeoTransform[5];
+    double dfGDALMaxX = m_adfGeoTransform[0] + nRasterXSize * m_adfGeoTransform[1];
+    double dfGDALMaxY = m_adfGeoTransform[3];
 
-        if( hSQLStmt != NULL )
-        {
-            sqlite3_finalize( hSQLStmt );
-        }
+    SoftStartTransaction();
 
-        return NULL;
-    }
+    pszSQL = sqlite3_mprintf("INSERT INTO gpkg_contents "
+        "(table_name,data_type,identifier,description,min_x,min_y,max_x,max_y,srs_id) VALUES "
+        "('%q','tiles','%q','%q',%.18g,%.18g,%.18g,%.18g,%d)",
+        m_osRasterTable.c_str(),
+        m_osIdentifier.c_str(),
+        m_osDescription.c_str(),
+        dfGDALMinX, dfGDALMinY, dfGDALMaxX, dfGDALMaxY,
+        m_nSRID);
+    eErr = SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+    if ( eErr != OGRERR_NONE )
+        return CE_Failure;
+
+    double dfTMSMaxX = m_dfTMSMinX + nTileXCountZoomLevel0 * nTileWidth * dfPixelXSizeZoomLevel0;
+    double dfTMSMinY = m_dfTMSMaxY - nTileYCountZoomLevel0 * nTileHeight * dfPixelYSizeZoomLevel0;
+
+    pszSQL = sqlite3_mprintf("INSERT INTO gpkg_tile_matrix_set "
+            "(table_name,srs_id,min_x,min_y,max_x,max_y) VALUES "
+            "('%q',%d,%.18g,%.18g,%.18g,%.18g)",
+            m_osRasterTable.c_str(), m_nSRID,
+            m_dfTMSMinX,dfTMSMinY,dfTMSMaxX,m_dfTMSMaxY);
+    eErr = SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+    if ( eErr != OGRERR_NONE )
+        return CE_Failure;
 
-/* -------------------------------------------------------------------- */
-/*      Do we get a resultset?                                          */
-/* -------------------------------------------------------------------- */
-    rc = sqlite3_step( hSQLStmt );
-    if( rc != SQLITE_ROW )
+    m_papoOverviewDS = (GDALGeoPackageDataset**) CPLCalloc(sizeof(GDALGeoPackageDataset*),
+                                                           m_nZoomLevel);
+
+    for(int i=0; i<=m_nZoomLevel; i++)
     {
-        if ( rc != SQLITE_DONE )
+        double dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel;
+        int nTileMatrixWidth, nTileMatrixHeight;
+        if( EQUAL(m_osTilingScheme, "CUSTOM") )
         {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                  "In ExecuteSQL(): sqlite3_step(%s):\n  %s", 
-                  pszSQLCommand, sqlite3_errmsg(m_poDb) );
-
-            sqlite3_finalize( hSQLStmt );
-            return NULL;
+            dfPixelXSizeZoomLevel = m_adfGeoTransform[1] * (1 << (m_nZoomLevel-i));
+            dfPixelYSizeZoomLevel = fabs(m_adfGeoTransform[5]) * (1 << (m_nZoomLevel-i));
+            nTileMatrixWidth = ((nRasterXSize >> (m_nZoomLevel-i)) + nTileWidth - 1) / nTileWidth;
+            nTileMatrixHeight = ((nRasterYSize >> (m_nZoomLevel-i)) + nTileHeight - 1) / nTileHeight;
         }
-        
-        if( EQUAL(pszSQLCommand, "VACUUM") )
+        else
         {
-            sqlite3_finalize( hSQLStmt );
-            /* VACUUM rewrites the DB, so we need to reset the application id */
-            SetApplicationId();
-            return NULL;
+            dfPixelXSizeZoomLevel = dfPixelXSizeZoomLevel0 / (1 << i);
+            dfPixelYSizeZoomLevel = dfPixelYSizeZoomLevel0 / (1 << i);
+            nTileMatrixWidth = nTileXCountZoomLevel0 * (1 << i);
+            nTileMatrixHeight = nTileYCountZoomLevel0 * (1 << i);
         }
-        
-        if( EQUALN(pszSQLCommand, "ALTER TABLE ", strlen("ALTER TABLE ")) )
-        {
-            char **papszTokens = CSLTokenizeString( pszSQLCommand );
-            /* ALTER TABLE src_table RENAME TO dst_table */
-            if( CSLCount(papszTokens) == 6 && EQUAL(papszTokens[3], "RENAME") &&
-                EQUAL(papszTokens[4], "TO") )
-            {
-                const char* pszSrcTableName = papszTokens[2];
-                const char* pszDstTableName = papszTokens[5];
-                OGRLayer* poSrcLayer = GetLayerByName(pszSrcTableName);
-                if( poSrcLayer )
-                {
-                    /* We also need to update GeoPackage metadata tables */
-                    char* pszSQL;
-                    pszSQL = sqlite3_mprintf(
-                            "UPDATE gpkg_geometry_columns SET table_name = '%s' WHERE table_name = '%s'",
-                            pszDstTableName, pszSrcTableName);
-                    
-                    SQLCommand(m_poDb, pszSQL);
-                    sqlite3_free(pszSQL);
-                    
-                    pszSQL = sqlite3_mprintf(
-                            "UPDATE gpkg_contents SET table_name = '%s' WHERE table_name = '%s'",
-                            pszDstTableName, pszSrcTableName);
+        pszSQL = sqlite3_mprintf("INSERT INTO gpkg_tile_matrix "
+                "(table_name,zoom_level,matrix_width,matrix_height,tile_width,tile_height,pixel_x_size,pixel_y_size) VALUES "
+                "('%q',%d,%d,%d,%d,%d,%.18g,%.18g)",
+                m_osRasterTable.c_str(),i,nTileMatrixWidth,nTileMatrixHeight,
+                nTileWidth,nTileHeight,dfPixelXSizeZoomLevel,dfPixelYSizeZoomLevel);
+        eErr = SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+        if ( eErr != OGRERR_NONE )
+            return CE_Failure;
 
-                    SQLCommand(m_poDb, pszSQL);
-                    sqlite3_free(pszSQL);
-                }
-            }
-            CSLDestroy(papszTokens);
+        if( i < m_nZoomLevel )
+        {
+            GDALGeoPackageDataset* poOvrDS = new GDALGeoPackageDataset();
+            poOvrDS->InitRaster ( this, m_osRasterTable, i, nBands,
+                                  m_dfTMSMinX, m_dfTMSMaxY,
+                                  dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel,
+                                  nTileWidth, nTileHeight,
+                                  nTileMatrixWidth,nTileMatrixHeight,
+                                  dfGDALMinX, dfGDALMinY,
+                                  dfGDALMaxX, dfGDALMaxY );
+
+            m_papoOverviewDS[m_nZoomLevel-1-i] = poOvrDS;
         }
+    }
+    
+    SoftCommitTransaction();
 
-        if( !EQUALN(pszSQLCommand, "SELECT ", 7) )
+    m_nOverviewCount = m_nZoomLevel;
+    m_bRecordInsertedInGPKGContent = TRUE;
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                             FlushCache()                             */
+/************************************************************************/
+
+void GDALGeoPackageDataset::FlushCache()
+{
+    FlushCacheWithErrCode();
+}
+
+CPLErr GDALGeoPackageDataset::FlushCacheWithErrCode()
+
+{
+    if( m_bInFlushCache )
+        return CE_None;
+    m_bInFlushCache = TRUE;
+    // Short circuit GDALPamDataset to avoid serialization to .aux.xml
+    GDALDataset::FlushCache();
+    
+    for( int i = 0; i < m_nLayers; i++ )
+    {
+        m_papoLayers[i]->RunDeferredCreationIfNecessary();
+        m_papoLayers[i]->CreateSpatialIndexIfNecessary();
+    }
+
+    CPLErr eErr = CE_None;
+    if( bUpdate )
+    {
+        if( m_nShiftXPixelsMod || m_nShiftYPixelsMod )
         {
-            sqlite3_finalize( hSQLStmt );
-            return NULL;
+            eErr = FlushRemainingShiftedTiles();
+        }
+        else
+        {
+            eErr = WriteTile();
         }
-#if 0
-        bUseStatementForGetNextFeature = FALSE;
-        bEmptyLayer = TRUE;
-#endif
     }
 
-/* -------------------------------------------------------------------- */
-/*      Create layer.                                                   */
-/* -------------------------------------------------------------------- */
-#if 0
-    OGRSQLiteSelectLayer *poLayer = NULL;
-        
-    CPLString osSQL = pszSQLCommand;
-    poLayer = new OGRGeopackageSelectLayer( this, osSQL, hSQLStmt,
-                                        bUseStatementForGetNextFeature, bEmptyLayer, TRUE );
+    GDALGeoPackageDataset* poMainDS = m_poParentDS ? m_poParentDS : this;
+    if( poMainDS->m_nTileInsertionCount )
+    {
+        poMainDS->SoftCommitTransaction();
+        poMainDS->m_nTileInsertionCount = 0;
+    }
 
-    if( poSpatialFilter != NULL )
-        poLayer->SetSpatialFilter( 0, poSpatialFilter );
-    
-    return poLayer;
-#else
-    return OGRDataSource::ExecuteSQL( pszSQLCommand, 
-                                          poSpatialFilter, 
-                                          pszDialect );
-#endif
+    m_bInFlushCache = FALSE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                          ReleaseResultSet()                          */
+/*                          IBuildOverviews()                           */
 /************************************************************************/
 
-void OGRGeoPackageDataSource::ReleaseResultSet( OGRLayer * poLayer )
-
+static int GetFloorPowerOfTwo(int n)
 {
-    delete poLayer;
+    int p2 = 1;
+    while( (n = n >> 1) > 0 )
+    {
+        p2 <<= 1;
+    }
+    return p2;
 }
+
+CPLErr GDALGeoPackageDataset::IBuildOverviews( 
+                        const char * pszResampling, 
+                        int nOverviews, int * panOverviewList,
+                        int nBandsIn, CPL_UNUSED int * panBandList,
+                        GDALProgressFunc pfnProgress, void * pProgressData )
+{
+    if( GetAccess() != GA_Update )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Overview building not supported on a database opened in read-only mode");
+        return CE_Failure;
+    }
+    if( m_poParentDS != NULL )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Overview building not supported on overview dataset");
+        return CE_Failure;
+    }
+    
+    if( nOverviews == 0 )
+    {
+        for(int i=0;i<m_nOverviewCount;i++)
+            m_papoOverviewDS[i]->FlushCache();
+        char* pszSQL = sqlite3_mprintf("DELETE FROM '%q' WHERE zoom_level < %d",
+                                       m_osRasterTable.c_str(),
+                                       m_nZoomLevel);
+        char* pszErrMsg = NULL;
+        int ret = sqlite3_exec(hDB, pszSQL, NULL, NULL, &pszErrMsg);
+        sqlite3_free(pszSQL);
+        if( ret != SQLITE_OK )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Failure: %s",
+                     pszErrMsg ? pszErrMsg : "");
+            sqlite3_free(pszErrMsg);
+            return CE_Failure;
+        }
+        return CE_None;
+    }
+    
+    if( nBandsIn != nBands )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Generation of overviews in GPKG only"
+                  "supported when operating on all bands." );
+        return CE_Failure;
+    }
+
+    if( m_nOverviewCount == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Image too small to support overviews");
+        return CE_Failure;
+    }
+
+    FlushCache();
+    for(int i=0;i<nOverviews;i++)
+    {
+        if( panOverviewList[i] < 2 )
+        {
+            CPLError(CE_Failure, CPLE_IllegalArg, "Overview factor must be >= 2");
+            return CE_Failure;
+        }
+
+        int bFound = FALSE;
+        int jCandidate = -1;
+        int nMaxOvFactor = 0;
+        for(int j=0;j<m_nOverviewCount;j++)
+        {
+            int    nOvFactor;
+
+            GDALDataset* poODS = m_papoOverviewDS[j];
+
+            nOvFactor = (int) 
+                (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
+            nMaxOvFactor = nOvFactor;
+
+            if( nOvFactor == panOverviewList[i] 
+                || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
+                                                    GetRasterXSize(),
+                                                    GetRasterYSize() ) )
+            {
+                bFound = TRUE;
+                break;
+            }
+
+            if( jCandidate < 0 && nOvFactor > panOverviewList[i] )
+                jCandidate = j;
+        }
+
+        if( !bFound )
+        {
+            /* Mostly for debug */
+            if( !CSLTestBoolean(CPLGetConfigOption("ALLOW_GPKG_ZOOM_OTHER_EXTENSION", "YES")) )
+            {
+                CPLString osOvrList;
+                for(int j=0;j<m_nOverviewCount;j++)
+                {
+                    int    nOvFactor;
+
+                    GDALDataset* poODS = m_papoOverviewDS[j];
+
+                    /* Compute overview factor */
+                    nOvFactor = (int) 
+                        (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
+                    int nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactor);
+                    if( nODSXSize != poODS->GetRasterXSize() )
+                    {
+                        int nOvFactorPowerOfTwo = GetFloorPowerOfTwo(nOvFactor);
+                        nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactorPowerOfTwo);
+                        if( nODSXSize == poODS->GetRasterXSize() )
+                            nOvFactor = nOvFactorPowerOfTwo;
+                        else
+                        {
+                            nOvFactorPowerOfTwo <<= 1;
+                            nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactorPowerOfTwo);
+                            if( nODSXSize == poODS->GetRasterXSize() )
+                                nOvFactor = nOvFactorPowerOfTwo;
+                        }
+                    }
+                    if( j != 0 )
+                        osOvrList += " ";
+                    osOvrList += CPLSPrintf("%d", nOvFactor);
+                }
+                CPLError(CE_Failure, CPLE_NotSupported,
+                        "Only overviews %s can be computed", osOvrList.c_str());
+                return CE_Failure;
+            }
+            else
+            {
+                int nOvFactor = panOverviewList[i];
+                if( jCandidate < 0 )
+                    jCandidate = m_nOverviewCount;
+
+                int nOvXSize = GetRasterXSize() / nOvFactor;
+                int nOvYSize = GetRasterYSize() / nOvFactor;
+                if( nOvXSize < 8 || nOvYSize < 8)
+                {
+                    CPLError(CE_Failure, CPLE_NotSupported,
+                             "Too big overview factor : %d. Would result in a %dx%d overview",
+                             nOvFactor, nOvXSize, nOvYSize);
+                    return CE_Failure;
+                }
+                if( !(jCandidate == m_nOverviewCount && nOvFactor == 2 * nMaxOvFactor) &&
+                    !m_bZoomOther )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                            "Use of overview factor %d cause gpkg_zoom_other extension to be needed",
+                            nOvFactor);
+                    RegisterZoomOtherExtension();
+                    m_bZoomOther = TRUE;
+                }
+
+                SoftStartTransaction();
+
+                CPLAssert(jCandidate > 0);
+                int nNewZoomLevel = m_papoOverviewDS[jCandidate-1]->m_nZoomLevel;
+
+                char* pszSQL;
+                OGRErr eErr;
+                for(int k=0;k<=jCandidate;k++)
+                {
+                    pszSQL = sqlite3_mprintf("UPDATE gpkg_tile_matrix SET zoom_level = %d "
+                        "WHERE table_name = '%q' AND zoom_level = %d",
+                        m_nZoomLevel - k + 1,
+                        m_osRasterTable.c_str(),
+                        m_nZoomLevel - k);
+                    eErr = SQLCommand(hDB, pszSQL);
+                    sqlite3_free(pszSQL);
+                    if ( eErr != OGRERR_NONE )
+                    {
+                        SoftRollbackTransaction();
+                        return CE_Failure;
+                    }
+
+                    pszSQL = sqlite3_mprintf("UPDATE '%q' SET zoom_level = %d "
+                        "WHERE zoom_level = %d",
+                        m_osRasterTable.c_str(),
+                        m_nZoomLevel - k + 1,
+                        m_nZoomLevel - k);
+                    eErr = SQLCommand(hDB, pszSQL);
+                    sqlite3_free(pszSQL);
+                    if ( eErr != OGRERR_NONE )
+                    {
+                        SoftRollbackTransaction();
+                        return CE_Failure;
+                    }
+                }
+
+                double dfGDALMinX = m_adfGeoTransform[0];
+                double dfGDALMinY = m_adfGeoTransform[3] + nRasterYSize * m_adfGeoTransform[5];
+                double dfGDALMaxX = m_adfGeoTransform[0] + nRasterXSize * m_adfGeoTransform[1];
+                double dfGDALMaxY = m_adfGeoTransform[3];
+                double dfPixelXSizeZoomLevel = m_adfGeoTransform[1] * nOvFactor;
+                double dfPixelYSizeZoomLevel = fabs(m_adfGeoTransform[5]) * nOvFactor;
+                int nTileWidth, nTileHeight;
+                GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight);
+                int nTileMatrixWidth = (nOvXSize + nTileWidth - 1) / nTileWidth;
+                int nTileMatrixHeight = (nOvYSize + nTileHeight - 1) / nTileHeight;
+                pszSQL = sqlite3_mprintf("INSERT INTO gpkg_tile_matrix "
+                        "(table_name,zoom_level,matrix_width,matrix_height,tile_width,tile_height,pixel_x_size,pixel_y_size) VALUES "
+                        "('%q',%d,%d,%d,%d,%d,%.18g,%.18g)",
+                        m_osRasterTable.c_str(),nNewZoomLevel,nTileMatrixWidth,nTileMatrixHeight,
+                        nTileWidth,nTileHeight,dfPixelXSizeZoomLevel,dfPixelYSizeZoomLevel);
+                eErr = SQLCommand(hDB, pszSQL);
+                sqlite3_free(pszSQL);
+                if ( eErr != OGRERR_NONE )
+                {
+                    SoftRollbackTransaction();
+                    return CE_Failure;
+                }
+
+                SoftCommitTransaction();
+
+                m_nZoomLevel ++; /* this change our zoom level as well as previous overviews */
+                for(int k=0;k<jCandidate;k++)
+                    m_papoOverviewDS[k]->m_nZoomLevel ++;
+
+                GDALGeoPackageDataset* poOvrDS = new GDALGeoPackageDataset();
+                poOvrDS->InitRaster ( this, m_osRasterTable,
+                                      nNewZoomLevel, nBands,
+                                      m_dfTMSMinX, m_dfTMSMaxY,
+                                      dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel,
+                                      nTileWidth, nTileHeight,
+                                      nTileMatrixWidth,nTileMatrixHeight,
+                                      dfGDALMinX, dfGDALMinY,
+                                      dfGDALMaxX, dfGDALMaxY );
+                m_papoOverviewDS = (GDALGeoPackageDataset**) CPLRealloc(
+                    m_papoOverviewDS, sizeof(GDALGeoPackageDataset*) * (m_nOverviewCount+1));
+
+                if( jCandidate < m_nOverviewCount )
+                {
+                    memmove(m_papoOverviewDS + jCandidate + 1,
+                            m_papoOverviewDS + jCandidate,
+                            sizeof(GDALGeoPackageDataset*) * (m_nOverviewCount-jCandidate));
+                }
+                m_papoOverviewDS[jCandidate] = poOvrDS;
+                m_nOverviewCount ++;
+            }
+        }
+    }
+    
+    GDALRasterBand*** papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
+    for( int iBand = 0; iBand < nBands; iBand++ )
+    {
+        papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
+        int iCurOverview = 0;
+        for(int i=0;i<nOverviews;i++)
+        {
+            int   j;
+            for( j = 0; j < m_nOverviewCount; j++ )
+            {
+                int    nOvFactor;
+                GDALDataset* poODS = m_papoOverviewDS[j];
+
+                nOvFactor = GDALComputeOvFactor(poODS->GetRasterXSize(),
+                                                GetRasterXSize(),
+                                                poODS->GetRasterYSize(),
+                                                GetRasterYSize());
+
+                if( nOvFactor == panOverviewList[i] 
+                    || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i],
+                                                        GetRasterXSize(),
+                                                        GetRasterYSize() ) )
+                {
+                    papapoOverviewBands[iBand][iCurOverview] = poODS->GetRasterBand(iBand+1);
+                    iCurOverview++ ;
+                    break;
+                }
+            }
+            CPLAssert(j < m_nOverviewCount);
+        }
+        CPLAssert(iCurOverview == nOverviews);
+    }
+
+    CPLErr eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBands,
+                                     nOverviews, papapoOverviewBands,
+                                     pszResampling, pfnProgress, pProgressData );
+
+    for( int iBand = 0; iBand < nBands; iBand++ )
+    {
+        CPLFree(papapoOverviewBands[iBand]);
+    }
+    CPLFree(papapoOverviewBands);
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                      GetMetadataDomainList()                         */
+/************************************************************************/
+
+char **GDALGeoPackageDataset::GetMetadataDomainList()
+{
+    GetMetadata();
+    if( m_osRasterTable.size() != 0 )
+        GetMetadata("GEOPACKAGE");
+    return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(),
+                                   TRUE,
+                                   "SUBDATASETS", NULL);
+}
+
+/************************************************************************/
+/*                        CheckMetadataDomain()                         */
+/************************************************************************/
+
+const char* GDALGeoPackageDataset::CheckMetadataDomain( const char* pszDomain )
+{
+    if( pszDomain != NULL && EQUAL(pszDomain, "GEOPACKAGE") &&
+        m_osRasterTable.size() == 0 )
+    {
+        CPLError(CE_Warning, CPLE_IllegalArg,
+                 "Using GEOPACKAGE for a non-raster geopackage is not supported. "
+                 "Using default domain instead");
+        return NULL;
+    }
+    return pszDomain;
+}
+
+/************************************************************************/
+/*                           HasMetadataTables()                        */
+/************************************************************************/
+
+int GDALGeoPackageDataset::HasMetadataTables()
+{
+    OGRErr err;
+    int nCount = SQLGetInteger(hDB,
+                  "SELECT COUNT(*) FROM sqlite_master WHERE name IN "
+                  "('gpkg_metadata', 'gpkg_metadata_reference') "
+                  "AND type IN ('table', 'view')", &err);
+    return ( err == OGRERR_NONE && nCount == 2 );
+}
+
+/************************************************************************/
+/*                            GetMetadata()                             */
+/************************************************************************/
+
+char **GDALGeoPackageDataset::GetMetadata( const char *pszDomain )
+
+{
+    pszDomain = CheckMetadataDomain(pszDomain);
+    if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
+        return m_papszSubDatasets;
+
+    if( m_bHasReadMetadataFromStorage )
+        return GDALPamDataset::GetMetadata( pszDomain );
+
+    m_bHasReadMetadataFromStorage = TRUE;
+
+    if ( !HasMetadataTables() )
+        return GDALPamDataset::GetMetadata( pszDomain );
+
+    char* pszSQL;
+    if( m_osRasterTable.size() )
+    {
+        pszSQL = sqlite3_mprintf(
+            "SELECT md.metadata, md.md_standard_uri, md.mime_type, mdr.reference_scope FROM gpkg_metadata md "
+            "JOIN gpkg_metadata_reference mdr ON (md.id = mdr.md_file_id ) "
+            "WHERE mdr.reference_scope = 'geopackage' OR "
+            "(mdr.reference_scope = 'table' AND mdr.table_name = '%q') ORDER BY md.id",
+            m_osRasterTable.c_str());
+    }
+    else
+    {
+        pszSQL = sqlite3_mprintf(
+            "SELECT md.metadata, md.md_standard_uri, md.mime_type, mdr.reference_scope FROM gpkg_metadata md "
+            "JOIN gpkg_metadata_reference mdr ON (md.id = mdr.md_file_id ) "
+            "WHERE mdr.reference_scope = 'geopackage' ORDER BY md.id");
+    }
+
+    SQLResult oResult;
+    OGRErr err = SQLQuery(hDB, pszSQL, &oResult);
+    sqlite3_free(pszSQL);
+    if  ( err != OGRERR_NONE )
+    {
+        SQLResultFree(&oResult);
+        return GDALPamDataset::GetMetadata( pszDomain );
+    }
+
+    char** papszMetadata = CSLDuplicate(GDALPamDataset::GetMetadata());
+
+    /* GDAL metadata */
+    for(int i=0;i<oResult.nRowCount;i++)
+    {
+        const char *pszMetadata = SQLResultGetValue(&oResult, 0, i);
+        const char* pszMDStandardURI = SQLResultGetValue(&oResult, 1, i);
+        const char* pszMimeType = SQLResultGetValue(&oResult, 2, i);
+        const char* pszReferenceScope = SQLResultGetValue(&oResult, 3, i);
+        int bIsGPKGScope = EQUAL(pszReferenceScope, "geopackage");
+        if( pszMetadata == NULL )
+            continue;
+        if( pszMDStandardURI != NULL && EQUAL(pszMDStandardURI, "http://gdal.org") &&
+            pszMimeType != NULL && EQUAL(pszMimeType, "text/xml") )
+        {
+            CPLXMLNode* psXMLNode = CPLParseXMLString(pszMetadata);
+            if( psXMLNode )
+            {
+                GDALMultiDomainMetadata oLocalMDMD;
+                oLocalMDMD.XMLInit(psXMLNode, FALSE);
+                if( m_osRasterTable.size() && bIsGPKGScope )
+                {
+                    oMDMD.SetMetadata( oLocalMDMD.GetMetadata(), "GEOPACKAGE" );
+                }
+                else
+                {
+                    papszMetadata = CSLMerge(papszMetadata, oLocalMDMD.GetMetadata());
+                    char** papszDomainList = oLocalMDMD.GetDomainList();
+                    char** papszIter = papszDomainList;
+                    while( papszIter && *papszIter )
+                    {
+                        if( !EQUAL(*papszIter, "") && !EQUAL(*papszIter, "IMAGE_STRUCTURE") )
+                            oMDMD.SetMetadata(oLocalMDMD.GetMetadata(*papszIter), *papszIter);
+                        papszIter ++;
+                    }
+                }
+                CPLDestroyXMLNode(psXMLNode);
+            }
+        }
+    }
+
+    GDALPamDataset::SetMetadata(papszMetadata);
+    CSLDestroy(papszMetadata);
+    papszMetadata = NULL;
+
+    /* Add non-GDAL metadata now */
+    int nNonGDALMDILocal = 1;
+    int nNonGDALMDIGeopackage = 1;
+    for(int i=0;i<oResult.nRowCount;i++)
+    {
+        const char *pszMetadata = SQLResultGetValue(&oResult, 0, i);
+        const char* pszMDStandardURI = SQLResultGetValue(&oResult, 1, i);
+        const char* pszMimeType = SQLResultGetValue(&oResult, 2, i);
+        const char* pszReferenceScope = SQLResultGetValue(&oResult, 3, i);
+        int bIsGPKGScope = EQUAL(pszReferenceScope, "geopackage");
+        if( pszMetadata == NULL )
+            continue;
+        if( pszMDStandardURI != NULL && EQUAL(pszMDStandardURI, "http://gdal.org") &&
+            pszMimeType != NULL && EQUAL(pszMimeType, "text/xml") )
+            continue;
+
+        if( m_osRasterTable.size() && bIsGPKGScope )
+        {
+            oMDMD.SetMetadataItem( CPLSPrintf("GPKG_METADATA_ITEM_%d", nNonGDALMDIGeopackage),
+                                   pszMetadata,
+                                   "GEOPACKAGE" );
+            nNonGDALMDIGeopackage ++;
+        }
+        /*else if( strcmp( pszMDStandardURI, "http://www.isotc211.org/2005/gmd" ) == 0 &&
+            strcmp( pszMimeType, "text/xml" ) == 0 )
+        {
+            char* apszMD[2];
+            apszMD[0] = (char*)pszMetadata;
+            apszMD[1] = NULL;
+            oMDMD.SetMetadata(apszMD, "xml:MD_Metadata");
+        }*/
+        else
+        {
+            oMDMD.SetMetadataItem( CPLSPrintf("GPKG_METADATA_ITEM_%d", nNonGDALMDILocal),
+                                   pszMetadata );
+            nNonGDALMDILocal ++;
+        }
+    }
+
+    SQLResultFree(&oResult);
+
+    return GDALPamDataset::GetMetadata(pszDomain);
+}
+
+/************************************************************************/
+/*                            WriteMetadata()                           */
+/************************************************************************/
+
+void GDALGeoPackageDataset::WriteMetadata(CPLXMLNode* psXMLNode, /* will be destroyed by the method /*/
+                                          const char* pszTableName)
+{
+    int bIsEmpty = (psXMLNode == NULL);
+    char *pszXML = NULL;
+    if( !bIsEmpty )
+    {
+        CPLXMLNode* psMasterXMLNode = CPLCreateXMLNode( NULL, CXT_Element,
+                                                        "GDALMultiDomainMetadata" );
+        psMasterXMLNode->psChild = psXMLNode;
+        pszXML = CPLSerializeXMLTree(psMasterXMLNode);
+        CPLDestroyXMLNode(psMasterXMLNode);
+    }
+    psXMLNode = NULL;
+
+    char* pszSQL;
+    if( pszTableName && pszTableName[0] != '\0' )
+    {
+        pszSQL = sqlite3_mprintf(
+            "SELECT md.id FROM gpkg_metadata md "
+            "JOIN gpkg_metadata_reference mdr ON (md.id = mdr.md_file_id ) "
+            "WHERE md.md_scope = 'dataset' AND md.md_standard_uri='http://gdal.org' "
+            "AND md.mime_type='text/xml' AND mdr.reference_scope = 'table' AND mdr.table_name = '%q'",
+            pszTableName);
+    }
+    else
+    {
+        pszSQL = sqlite3_mprintf(
+            "SELECT md.id FROM gpkg_metadata md "
+            "JOIN gpkg_metadata_reference mdr ON (md.id = mdr.md_file_id ) "
+            "WHERE md.md_scope = 'dataset' AND md.md_standard_uri='http://gdal.org' "
+            "AND md.mime_type='text/xml' AND mdr.reference_scope = 'geopackage'");
+    }
+    OGRErr err;
+    int mdId = SQLGetInteger(hDB, pszSQL, &err);
+    if( err != OGRERR_NONE )
+        mdId = -1;
+    sqlite3_free(pszSQL);
+
+    if( bIsEmpty )
+    {
+        if( mdId >= 0 )
+        {
+            SQLCommand(hDB,
+                       CPLSPrintf("DELETE FROM gpkg_metadata_reference WHERE md_file_id = %d", mdId));
+            SQLCommand(hDB,
+                       CPLSPrintf("DELETE FROM gpkg_metadata WHERE id = %d", mdId));
+        }
+    }
+    else
+    {
+        if( mdId >= 0 )
+        {
+            pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_metadata SET metadata = '%q' WHERE id = %d",
+                pszXML, mdId);
+        }
+        else
+        {
+            pszSQL = sqlite3_mprintf(
+                "INSERT INTO gpkg_metadata (md_scope, md_standard_uri, mime_type, metadata) VALUES "
+                "('dataset','http://gdal.org','text/xml','%q')",
+                pszXML);
+        }
+        SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+
+        CPLFree(pszXML);
+
+        if( mdId < 0 )
+        {
+            const sqlite_int64 nFID = sqlite3_last_insert_rowid( hDB );
+            if( pszTableName != NULL && pszTableName[0] != '\0' )
+            {
+                pszSQL = sqlite3_mprintf(
+                    "INSERT INTO gpkg_metadata_reference (reference_scope, table_name, timestamp, md_file_id) VALUES "
+                    "('table', '%q', strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ','now'), %d)",
+                    pszTableName, (int)nFID);
+            }
+            else
+            {
+                pszSQL = sqlite3_mprintf(
+                    "INSERT INTO gpkg_metadata_reference (reference_scope, timestamp, md_file_id) VALUES "
+                    "('geopackage', strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ','now'), %d)",
+                    (int)nFID);
+            }
+        }
+        else
+        {
+            pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_metadata_reference SET timestamp = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ','now') WHERE md_file_id = %d",
+                mdId);
+        }
+        SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+    }
+}
+
+/************************************************************************/
+/*                        CreateMetadataTables()                        */
+/************************************************************************/
+
+int GDALGeoPackageDataset::CreateMetadataTables()
+{
+    int bCreateTriggers = CSLTestBoolean(CPLGetConfigOption("CREATE_TRIGGERS", "YES"));
+    
+    /* From C.10. gpkg_metadata Table 35. gpkg_metadata Table Definition SQL  */
+    const char* pszMetadata =
+        "CREATE TABLE gpkg_metadata ("
+        "id INTEGER CONSTRAINT m_pk PRIMARY KEY ASC NOT NULL UNIQUE,"
+        "md_scope TEXT NOT NULL DEFAULT 'dataset',"
+        "md_standard_uri TEXT NOT NULL,"
+        "mime_type TEXT NOT NULL DEFAULT 'text/xml',"
+        "metadata TEXT NOT NULL"
+        ")";
+        
+    if ( OGRERR_NONE != SQLCommand(hDB, pszMetadata) )
+        return FALSE;
+
+    /* From D.2. metadata Table 40. metadata Trigger Definition SQL  */
+    const char* pszMetadataTriggers =
+    "CREATE TRIGGER 'gpkg_metadata_md_scope_insert' "
+    "BEFORE INSERT ON 'gpkg_metadata' "
+    "FOR EACH ROW BEGIN "
+    "SELECT RAISE(ABORT, 'insert on table gpkg_metadata violates "
+    "constraint: md_scope must be one of undefined | fieldSession | "
+    "collectionSession | series | dataset | featureType | feature | "
+    "attributeType | attribute | tile | model | catalogue | schema | "
+    "taxonomy software | service | collectionHardware | "
+    "nonGeographicDataset | dimensionGroup') "
+    "WHERE NOT(NEW.md_scope IN "
+    "('undefined','fieldSession','collectionSession','series','dataset', "
+    "'featureType','feature','attributeType','attribute','tile','model', "
+    "'catalogue','schema','taxonomy','software','service', "
+    "'collectionHardware','nonGeographicDataset','dimensionGroup')); "
+    "END; "
+    "CREATE TRIGGER 'gpkg_metadata_md_scope_update' "
+    "BEFORE UPDATE OF 'md_scope' ON 'gpkg_metadata' "
+    "FOR EACH ROW BEGIN "
+    "SELECT RAISE(ABORT, 'update on table gpkg_metadata violates "
+    "constraint: md_scope must be one of undefined | fieldSession | "
+    "collectionSession | series | dataset | featureType | feature | "
+    "attributeType | attribute | tile | model | catalogue | schema | "
+    "taxonomy software | service | collectionHardware | "
+    "nonGeographicDataset | dimensionGroup') "
+    "WHERE NOT(NEW.md_scope IN "
+    "('undefined','fieldSession','collectionSession','series','dataset', "
+    "'featureType','feature','attributeType','attribute','tile','model', "
+    "'catalogue','schema','taxonomy','software','service', "
+    "'collectionHardware','nonGeographicDataset','dimensionGroup')); "
+    "END";
+    if ( bCreateTriggers && OGRERR_NONE != SQLCommand(hDB, pszMetadataTriggers) )
+        return FALSE;
+
+    /* From C.11. gpkg_metadata_reference Table 36. gpkg_metadata_reference Table Definition SQL */
+    const char* pszMetadataReference =
+        "CREATE TABLE gpkg_metadata_reference ("
+        "reference_scope TEXT NOT NULL,"
+        "table_name TEXT,"
+        "column_name TEXT,"
+        "row_id_value INTEGER,"
+        "timestamp DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),"
+        "md_file_id INTEGER NOT NULL,"
+        "md_parent_id INTEGER,"
+        "CONSTRAINT crmr_mfi_fk FOREIGN KEY (md_file_id) REFERENCES gpkg_metadata(id),"
+        "CONSTRAINT crmr_mpi_fk FOREIGN KEY (md_parent_id) REFERENCES gpkg_metadata(id)"
+        ")";
+        
+    if ( OGRERR_NONE != SQLCommand(hDB, pszMetadataReference) )
+        return FALSE;
+
+    /* From D.3. metadata_reference Table 41. gpkg_metadata_reference Trigger Definition SQL   */
+    const char* pszMetadataReferenceTriggers =
+        "CREATE TRIGGER 'gpkg_metadata_reference_reference_scope_insert' "
+        "BEFORE INSERT ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: reference_scope must be one of \"geopackage\", "
+        "table\", \"column\", \"row\", \"row/col\"') "
+        "WHERE NOT NEW.reference_scope IN "
+        "('geopackage','table','column','row','row/col'); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_reference_scope_update' "
+        "BEFORE UPDATE OF 'reference_scope' ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: referrence_scope must be one of \"geopackage\", "
+        "\"table\", \"column\", \"row\", \"row/col\"') "
+        "WHERE NOT NEW.reference_scope IN "
+        "('geopackage','table','column','row','row/col'); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_column_name_insert' "
+        "BEFORE INSERT ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: column name must be NULL when reference_scope "
+        "is \"geopackage\", \"table\" or \"row\"') "
+        "WHERE (NEW.reference_scope IN ('geopackage','table','row') "
+        "AND NEW.column_name IS NOT NULL); "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: column name must be defined for the specified "
+        "table when reference_scope is \"column\" or \"row/col\"') "
+        "WHERE (NEW.reference_scope IN ('column','row/col') "
+        "AND NOT NEW.table_name IN ( "
+        "SELECT name FROM SQLITE_MASTER WHERE type = 'table' "
+        "AND name = NEW.table_name "
+        "AND sql LIKE ('%' || NEW.column_name || '%'))); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' "
+        "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: column name must be NULL when reference_scope "
+        "is \"geopackage\", \"table\" or \"row\"') "
+        "WHERE (NEW.reference_scope IN ('geopackage','table','row') "
+        "AND NEW.column_nameIS NOT NULL); "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: column name must be defined for the specified "
+        "table when reference_scope is \"column\" or \"row/col\"') "
+        "WHERE (NEW.reference_scope IN ('column','row/col') "
+        "AND NOT NEW.table_name IN ( "
+        "SELECT name FROM SQLITE_MASTER WHERE type = 'table' "
+        "AND name = NEW.table_name "
+        "AND sql LIKE ('%' || NEW.column_name || '%'))); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_row_id_value_insert' "
+        "BEFORE INSERT ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: row_id_value must be NULL when reference_scope "
+        "is \"geopackage\", \"table\" or \"column\"') "
+        "WHERE NEW.reference_scope IN ('geopackage','table','column') "
+        "AND NEW.row_id_value IS NOT NULL; "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: row_id_value must exist in specified table when "
+        "reference_scope is \"row\" or \"row/col\"') "
+        "WHERE NEW.reference_scope IN ('row','row/col') "
+        "AND NOT EXISTS (SELECT rowid "
+        "FROM (SELECT NEW.table_name AS table_name) WHERE rowid = "
+        "NEW.row_id_value); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_row_id_value_update' "
+        "BEFORE UPDATE OF 'row_id_value' ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: row_id_value must be NULL when reference_scope "
+        "is \"geopackage\", \"table\" or \"column\"') "
+        "WHERE NEW.reference_scope IN ('geopackage','table','column') "
+        "AND NEW.row_id_value IS NOT NULL; "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: row_id_value must exist in specified table when "
+        "reference_scope is \"row\" or \"row/col\"') "
+        "WHERE NEW.reference_scope IN ('row','row/col') "
+        "AND NOT EXISTS (SELECT rowid "
+        "FROM (SELECT NEW.table_name AS table_name) WHERE rowid = "
+        "NEW.row_id_value); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_timestamp_insert' "
+        "BEFORE INSERT ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference "
+        "violates constraint: timestamp must be a valid time in ISO 8601 "
+        "\"yyyy-mm-ddThh:mm:ss.cccZ\" form') "
+        "WHERE NOT (NEW.timestamp GLOB "
+        "'[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9][0-9]Z' "
+        "AND strftime('%s',NEW.timestamp) NOT NULL); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_metadata_reference_timestamp_update' "
+        "BEFORE UPDATE OF 'timestamp' ON 'gpkg_metadata_reference' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference "
+        "violates constraint: timestamp must be a valid time in ISO 8601 "
+        "\"yyyy-mm-ddThh:mm:ss.cccZ\" form') "
+        "WHERE NOT (NEW.timestamp GLOB "
+        "'[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9][0-9]Z' "
+        "AND strftime('%s',NEW.timestamp) NOT NULL); "
+        "END";
+    if ( bCreateTriggers && OGRERR_NONE != SQLCommand(hDB, pszMetadataReferenceTriggers) )
+        return FALSE;
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            FlushMetadata()                           */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::FlushMetadata()
+{
+    if( !m_bMetadataDirty || m_poParentDS != NULL ||
+        !CSLTestBoolean(CPLGetConfigOption("CREATE_METADATA_TABLES", "YES")) )
+        return CE_None;
+    if( !HasMetadataTables() && !CreateMetadataTables() )
+        return CE_Failure;
+    m_bMetadataDirty = FALSE;
+
+    if( m_osRasterTable.size() )
+    {
+        const char* pszIdentifier = GetMetadataItem("IDENTIFIER");
+        const char* pszDescription = GetMetadataItem("DESCRIPTION");
+        if( !m_bIdentifierAsCO && pszIdentifier != NULL &&
+            pszIdentifier != m_osIdentifier )
+        {
+            m_osIdentifier = pszIdentifier;
+            char* pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_contents SET identifier = '%q' WHERE table_name = '%q'",
+                pszIdentifier, m_osRasterTable.c_str());
+            SQLCommand(hDB, pszSQL);
+            sqlite3_free(pszSQL);
+        }
+        if( !m_bDescriptionAsCO && pszDescription != NULL &&
+            pszDescription != m_osDescription )
+        {
+            m_osDescription = pszDescription;
+            char* pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_contents SET description = '%q' WHERE table_name = '%q'",
+                pszDescription, m_osRasterTable.c_str());
+            SQLCommand(hDB, pszSQL);
+            sqlite3_free(pszSQL);
+        }
+    }
+
+    char** papszMDDup = NULL;
+    for( char** papszIter = GetMetadata(); papszIter && *papszIter; ++papszIter )
+    {
+        if( EQUALN(*papszIter, "IDENTIFIER=", strlen("IDENTIFIER=")) )
+            continue;
+        if( EQUALN(*papszIter, "DESCRIPTION=", strlen("DESCRIPTION=")) )
+            continue;
+        if( EQUALN(*papszIter, "ZOOM_LEVEL=", strlen("ZOOM_LEVEL=")) )
+            continue;
+        if( EQUALN(*papszIter, "GPKG_METADATA_ITEM_", strlen("GPKG_METADATA_ITEM_")) )
+            continue;
+        papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter);
+    }
+
+    CPLXMLNode* psXMLNode;
+    {
+        GDALMultiDomainMetadata oLocalMDMD;
+        char** papszDomainList = oMDMD.GetDomainList();
+        char** papszIter = papszDomainList;
+        oLocalMDMD.SetMetadata(papszMDDup);
+        while( papszIter && *papszIter )
+        {
+            if( !EQUAL(*papszIter, "") && 
+                !EQUAL(*papszIter, "IMAGE_STRUCTURE") && 
+                !EQUAL(*papszIter, "GEOPACKAGE") )
+                oLocalMDMD.SetMetadata(oMDMD.GetMetadata(*papszIter), *papszIter);
+            papszIter ++;
+        }
+        psXMLNode = oLocalMDMD.Serialize();
+    }
+
+    CSLDestroy(papszMDDup);
+    papszMDDup = NULL;
+
+    WriteMetadata(psXMLNode, m_osRasterTable.c_str() );
+
+    if( m_osRasterTable.size() )
+    {
+        char** papszGeopackageMD = GetMetadata("GEOPACKAGE");
+
+        char** papszMDDup = NULL;
+        for( char** papszIter = papszGeopackageMD; papszIter && *papszIter; ++papszIter )
+        {
+            papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter);
+        }
+
+        GDALMultiDomainMetadata oLocalMDMD;
+        oLocalMDMD.SetMetadata(papszMDDup);
+        CSLDestroy(papszMDDup);
+        papszMDDup = NULL;
+        psXMLNode = oLocalMDMD.Serialize();
+
+        WriteMetadata(psXMLNode, NULL);
+    }
+
+    for(int i=0;i<m_nLayers;i++)
+    {
+        const char* pszIdentifier = m_papoLayers[i]->GetMetadataItem("IDENTIFIER");
+        const char* pszDescription = m_papoLayers[i]->GetMetadataItem("DESCRIPTION");
+        if( pszIdentifier != NULL )
+        {
+            char* pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_contents SET identifier = '%q' WHERE table_name = '%q'",
+                pszIdentifier, m_papoLayers[i]->GetName());
+            SQLCommand(hDB, pszSQL);
+            sqlite3_free(pszSQL);
+        }
+        if( pszDescription != NULL )
+        {
+            char* pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_contents SET description = '%q' WHERE table_name = '%q'",
+                pszDescription, m_papoLayers[i]->GetName());
+            SQLCommand(hDB, pszSQL);
+            sqlite3_free(pszSQL);
+        }
+
+        char** papszMDDup = NULL;
+        for( char** papszIter = m_papoLayers[i]->GetMetadata(); papszIter && *papszIter; ++papszIter )
+        {
+            if( EQUALN(*papszIter, "IDENTIFIER=", strlen("IDENTIFIER=")) )
+                continue;
+            if( EQUALN(*papszIter, "DESCRIPTION=", strlen("DESCRIPTION=")) )
+                continue;
+            if( EQUALN(*papszIter, "OLMD_FID64=", strlen("OLMD_FID64=")) )
+                continue;
+            papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter);
+        }
+
+        CPLXMLNode* psXMLNode;
+        {
+            GDALMultiDomainMetadata oLocalMDMD;
+            char** papszDomainList = m_papoLayers[i]->GetMetadataDomainList();
+            char** papszIter = papszDomainList;
+            oLocalMDMD.SetMetadata(papszMDDup);
+            while( papszIter && *papszIter )
+            {
+                if( !EQUAL(*papszIter, "") )
+                    oLocalMDMD.SetMetadata(m_papoLayers[i]->GetMetadata(*papszIter), *papszIter);
+                papszIter ++;
+            }
+            CSLDestroy(papszDomainList);
+            psXMLNode = oLocalMDMD.Serialize();
+        }
+
+        CSLDestroy(papszMDDup);
+        papszMDDup = NULL;
+
+        WriteMetadata(psXMLNode, m_papoLayers[i]->GetName() );
+    }
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                          GetMetadataItem()                           */
+/************************************************************************/
+
+const char *GDALGeoPackageDataset::GetMetadataItem( const char * pszName,
+                                                    const char * pszDomain )
+{
+    pszDomain = CheckMetadataDomain(pszDomain);
+    return CSLFetchNameValue( GetMetadata(pszDomain), pszName );
+}
+
+/************************************************************************/
+/*                            SetMetadata()                             */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::SetMetadata( char ** papszMetadata, const char * pszDomain )
+{
+    pszDomain = CheckMetadataDomain(pszDomain);
+    m_bMetadataDirty = TRUE;
+    GetMetadata(); /* force loading from storage if needed */
+    return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
+}
+
+/************************************************************************/
+/*                          SetMetadataItem()                           */
+/************************************************************************/
+
+CPLErr GDALGeoPackageDataset::SetMetadataItem( const char * pszName,
+                                               const char * pszValue,
+                                               const char * pszDomain )
+{
+    pszDomain = CheckMetadataDomain(pszDomain);
+    m_bMetadataDirty = TRUE;
+    GetMetadata(); /* force loading from storage if needed */
+    return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
+}
+
+/************************************************************************/
+/*                                Create()                              */
+/************************************************************************/
+
+int GDALGeoPackageDataset::Create( const char * pszFilename,
+                                   int nXSize,
+                                   int nYSize,
+                                   int nBands,
+                                   GDALDataType eDT,
+                                   char **papszOptions )
+{
+    CPLString osCommand;
+    const char *pszSpatialRefSysRecord;
+
+    /* First, ensure there isn't any such file yet. */
+    VSIStatBufL sStatBuf;
+
+    if( nBands != 0 )
+    {
+        if( eDT != GDT_Byte )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported, "Only Byte supported");
+            return FALSE;
+        }
+        if( nBands != 1 && nBands != 2 && nBands != 3 && nBands != 4 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Only 1 (Grey/ColorTable), 2 (Grey+Alpha), 3 (RGB) or 4 (RGBA) band dataset supported");
+            return FALSE;
+        }
+    }
+
+    int bFileExists = FALSE;
+    if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
+    {
+        bFileExists = TRUE;
+        if( nBands == 0 ||
+            !CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "APPEND_SUBDATASET", "NO")) )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "A file system object called '%s' already exists.",
+                    pszFilename );
+
+            return FALSE;
+        }
+    }
+    m_pszFilename = CPLStrdup(pszFilename);
+    m_bNew = TRUE;
+    bUpdate = TRUE;
+    eAccess = GA_Update; /* hum annoying duplication */
+
+    if (!OpenOrCreateDB(bFileExists ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE))
+        return FALSE;
+
+    /* Default to synchronous=off for performance for new file */
+    if( !bFileExists && CPLGetConfigOption("OGR_SQLITE_SYNCHRONOUS", NULL) == NULL )
+    {
+        sqlite3_exec( hDB, "PRAGMA synchronous = OFF", NULL, NULL, NULL );
+    }
+
+    /* OGR UTF-8 support. If we set the UTF-8 Pragma early on, it */
+    /* will be written into the main file and supported henceforth */
+    SQLCommand(hDB, "PRAGMA encoding = \"UTF-8\"");
+
+    SoftStartTransaction();
+
+    int bCreateTriggers = CSLTestBoolean(CPLGetConfigOption("CREATE_TRIGGERS", "YES"));
+    int bCreateGeometryColumns = CSLTestBoolean(CPLGetConfigOption("CREATE_GEOMETRY_COLUMNS", "YES"));
+    if( !bFileExists )
+    {
+        /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) in the application id */
+        /* http://opengis.github.io/geopackage/#_file_format */
+        const char *pszPragma = CPLSPrintf("PRAGMA application_id = %d", GPKG_APPLICATION_ID);
+        
+        if ( OGRERR_NONE != SQLCommand(hDB, pszPragma) )
+            return FALSE;
+            
+        /* Requirement 10: A GeoPackage SHALL include a gpkg_spatial_ref_sys table */
+        /* http://opengis.github.io/geopackage/#spatial_ref_sys */
+        const char *pszSpatialRefSys = 
+            "CREATE TABLE gpkg_spatial_ref_sys ("
+            "srs_name TEXT NOT NULL,"
+            "srs_id INTEGER NOT NULL PRIMARY KEY,"
+            "organization TEXT NOT NULL,"
+            "organization_coordsys_id INTEGER NOT NULL,"
+            "definition  TEXT NOT NULL,"
+            "description TEXT"
+            ")";
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszSpatialRefSys) )
+            return FALSE;
+
+        /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
+        /* contain a record for EPSG:4326, the geodetic WGS84 SRS */
+        /* http://opengis.github.io/geopackage/#spatial_ref_sys */
+        pszSpatialRefSysRecord = 
+            "INSERT INTO gpkg_spatial_ref_sys ("
+            "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
+            ") VALUES ("
+            "'WGS 84 geodetic', 4326, 'EPSG', 4326, '"
+            "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563,AUTHORITY[\"EPSG\",\"7030\"]],AUTHORITY[\"EPSG\",\"6326\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4326\"]]"
+            "', 'longitude/latitude coordinates in decimal degrees on the WGS 84 spheroid'"
+            ")";  
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszSpatialRefSysRecord) )
+            return FALSE;
+
+        /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
+        /* contain a record with an srs_id of -1, an organization of “NONE”, */
+        /* an organization_coordsys_id of -1, and definition “undefined” */
+        /* for undefined Cartesian coordinate reference systems */
+        /* http://opengis.github.io/geopackage/#spatial_ref_sys */
+        pszSpatialRefSysRecord = 
+            "INSERT INTO gpkg_spatial_ref_sys ("
+            "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
+            ") VALUES ("
+            "'Undefined cartesian SRS', -1, 'NONE', -1, 'undefined', 'undefined cartesian coordinate reference system'"
+            ")"; 
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszSpatialRefSysRecord) )
+            return FALSE;
+
+        /* Requirement 11: The gpkg_spatial_ref_sys table in a GeoPackage SHALL */
+        /* contain a record with an srs_id of 0, an organization of “NONE”, */
+        /* an organization_coordsys_id of 0, and definition “undefined” */
+        /* for undefined geographic coordinate reference systems */
+        /* http://opengis.github.io/geopackage/#spatial_ref_sys */
+        pszSpatialRefSysRecord = 
+            "INSERT INTO gpkg_spatial_ref_sys ("
+            "srs_name, srs_id, organization, organization_coordsys_id, definition, description"
+            ") VALUES ("
+            "'Undefined geographic SRS', 0, 'NONE', 0, 'undefined', 'undefined geographic coordinate reference system'"
+            ")"; 
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszSpatialRefSysRecord) )
+            return FALSE;
+        
+        /* Requirement 13: A GeoPackage file SHALL include a gpkg_contents table */
+        /* http://opengis.github.io/geopackage/#_contents */
+        const char *pszContents =
+            "CREATE TABLE gpkg_contents ("
+            "table_name TEXT NOT NULL PRIMARY KEY,"
+            "data_type TEXT NOT NULL,"
+            "identifier TEXT UNIQUE,"
+            "description TEXT DEFAULT '',"
+            "last_change DATETIME NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ',CURRENT_TIMESTAMP)),"
+            "min_x DOUBLE, min_y DOUBLE,"
+            "max_x DOUBLE, max_y DOUBLE,"
+            "srs_id INTEGER,"
+            "CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys(srs_id)"
+            ")";
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszContents) )
+            return FALSE;
+
+        /* Requirement 21: A GeoPackage with a gpkg_contents table row with a “features” */
+        /* data_type SHALL contain a gpkg_geometry_columns table or updateable view */
+        /* http://opengis.github.io/geopackage/#_geometry_columns */
+        const char *pszGeometryColumns =        
+            "CREATE TABLE gpkg_geometry_columns ("
+            "table_name TEXT NOT NULL,"
+            "column_name TEXT NOT NULL,"
+            "geometry_type_name TEXT NOT NULL,"
+            "srs_id INTEGER NOT NULL,"
+            "z TINYINT NOT NULL,"
+            "m TINYINT NOT NULL,"
+            "CONSTRAINT pk_geom_cols PRIMARY KEY (table_name, column_name),"
+            "CONSTRAINT uk_gc_table_name UNIQUE (table_name),"
+            "CONSTRAINT fk_gc_tn FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name),"
+            "CONSTRAINT fk_gc_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)"
+            ")";
+            
+        if ( bCreateGeometryColumns && OGRERR_NONE != SQLCommand(hDB, pszGeometryColumns) )
+            return FALSE;
+
+        /* From C.5. gpkg_tile_matrix_set Table 28. gpkg_tile_matrix_set Table Creation SQL  */
+        const char *pszTileMatrixSet =
+            "CREATE TABLE gpkg_tile_matrix_set ("
+            "table_name TEXT NOT NULL PRIMARY KEY,"
+            "srs_id INTEGER NOT NULL,"
+            "min_x DOUBLE NOT NULL,"
+            "min_y DOUBLE NOT NULL,"
+            "max_x DOUBLE NOT NULL,"
+            "max_y DOUBLE NOT NULL,"
+            "CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name),"
+            "CONSTRAINT fk_gtms_srs FOREIGN KEY (srs_id) REFERENCES gpkg_spatial_ref_sys (srs_id)"
+            ")";
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszTileMatrixSet) )
+            return FALSE;
+        
+        /* From C.6. gpkg_tile_matrix Table 29. gpkg_tile_matrix Table Creation SQL */
+        const char *pszTileMatrix =
+            "CREATE TABLE gpkg_tile_matrix ("
+            "table_name TEXT NOT NULL,"
+            "zoom_level INTEGER NOT NULL,"
+            "matrix_width INTEGER NOT NULL,"
+            "matrix_height INTEGER NOT NULL,"
+            "tile_width INTEGER NOT NULL,"
+            "tile_height INTEGER NOT NULL,"
+            "pixel_x_size DOUBLE NOT NULL,"
+            "pixel_y_size DOUBLE NOT NULL,"
+            "CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level),"
+            "CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) REFERENCES gpkg_contents(table_name)"
+            ")";
+            
+        if ( OGRERR_NONE != SQLCommand(hDB, pszTileMatrix) )
+            return FALSE;
+
+        /* From D.1. gpkg_tile_matrix Table 39. gpkg_tile_matrix Trigger Definition SQL */
+        const char* pszTileMatrixTrigger =
+        "CREATE TRIGGER 'gpkg_tile_matrix_zoom_level_insert' "
+        "BEFORE INSERT ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''gpkg_tile_matrix'' violates constraint: zoom_level cannot be less than 0') "
+        "WHERE (NEW.zoom_level < 0); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_zoom_level_update' "
+        "BEFORE UPDATE of zoom_level ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''gpkg_tile_matrix'' violates constraint: zoom_level cannot be less than 0') "
+        "WHERE (NEW.zoom_level < 0); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_matrix_width_insert' "
+        "BEFORE INSERT ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''gpkg_tile_matrix'' violates constraint: matrix_width cannot be less than 1') "
+        "WHERE (NEW.matrix_width < 1); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_matrix_width_update' "
+        "BEFORE UPDATE OF matrix_width ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''gpkg_tile_matrix'' violates constraint: matrix_width cannot be less than 1') "
+        "WHERE (NEW.matrix_width < 1); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_matrix_height_insert' "
+        "BEFORE INSERT ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''gpkg_tile_matrix'' violates constraint: matrix_height cannot be less than 1') "
+        "WHERE (NEW.matrix_height < 1); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_matrix_height_update' "
+        "BEFORE UPDATE OF matrix_height ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''gpkg_tile_matrix'' violates constraint: matrix_height cannot be less than 1') "
+        "WHERE (NEW.matrix_height < 1); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_pixel_x_size_insert' "
+        "BEFORE INSERT ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''gpkg_tile_matrix'' violates constraint: pixel_x_size must be greater than 0') "
+        "WHERE NOT (NEW.pixel_x_size > 0); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_pixel_x_size_update' "
+        "BEFORE UPDATE OF pixel_x_size ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''gpkg_tile_matrix'' violates constraint: pixel_x_size must be greater than 0') "
+        "WHERE NOT (NEW.pixel_x_size > 0); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_pixel_y_size_insert' "
+        "BEFORE INSERT ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''gpkg_tile_matrix'' violates constraint: pixel_y_size must be greater than 0') "
+        "WHERE NOT (NEW.pixel_y_size > 0); "
+        "END; "
+        "CREATE TRIGGER 'gpkg_tile_matrix_pixel_y_size_update' "
+        "BEFORE UPDATE OF pixel_y_size ON 'gpkg_tile_matrix' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''gpkg_tile_matrix'' violates constraint: pixel_y_size must be greater than 0') "
+        "WHERE NOT (NEW.pixel_y_size > 0); "
+        "END;";
+        if ( bCreateTriggers && OGRERR_NONE != SQLCommand(hDB, pszTileMatrixTrigger) )
+            return FALSE;
+
+        if( CSLTestBoolean(CPLGetConfigOption("CREATE_METADATA_TABLES", "YES")) &&
+            !CreateMetadataTables() )
+            return FALSE;
+    }
+    
+    if( nBands != 0 )
+    {
+        const char* pszTableName = CPLGetBasename(m_pszFilename);
+        m_osRasterTable = CSLFetchNameValueDef(papszOptions, "RASTER_TABLE", pszTableName);
+        m_bIdentifierAsCO = CSLFetchNameValue(papszOptions, "RASTER_IDENTIFIER" ) != NULL;
+        m_osIdentifier = CSLFetchNameValueDef(papszOptions, "RASTER_IDENTIFIER", m_osRasterTable);
+        m_bDescriptionAsCO = CSLFetchNameValue(papszOptions, "RASTER_DESCRIPTION" ) != NULL;
+        m_osDescription = CSLFetchNameValueDef(papszOptions, "RASTER_DESCRIPTION", "");
+
+        /* From C.7. sample_tile_pyramid (Informative) Table 31. EXAMPLE: tiles table Create Table SQL (Informative) */
+        char* pszSQL = sqlite3_mprintf("CREATE TABLE '%q' ("
+          "id INTEGER PRIMARY KEY AUTOINCREMENT,"
+          "zoom_level INTEGER NOT NULL,"
+          "tile_column INTEGER NOT NULL,"
+          "tile_row INTEGER NOT NULL,"
+          "tile_data BLOB NOT NULL,"
+          "UNIQUE (zoom_level, tile_column, tile_row)"
+        ")", m_osRasterTable.c_str());
+        OGRErr eErr = SQLCommand(hDB, pszSQL);
+        sqlite3_free(pszSQL);
+        if ( OGRERR_NONE != eErr )
+            return FALSE;
+
+        /* From D.5. sample_tile_pyramid Table 43. tiles table Trigger Definition SQL  */
+        char* pszSQLTriggers = sqlite3_mprintf("CREATE TRIGGER '%q_zoom_insert' "
+        "BEFORE INSERT ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''%q'' violates constraint: zoom_level not specified for table in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.zoom_level IN (SELECT zoom_level FROM gpkg_tile_matrix WHERE table_name = '%q')) ; "
+        "END; "
+        "CREATE TRIGGER '%q_zoom_update' "
+        "BEFORE UPDATE OF zoom_level ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''%q'' violates constraint: zoom_level not specified for table in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.zoom_level IN (SELECT zoom_level FROM gpkg_tile_matrix WHERE table_name = '%q')) ; "
+        "END; "
+        "CREATE TRIGGER '%q_tile_column_insert' "
+        "BEFORE INSERT ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''%q'' violates constraint: tile_column cannot be < 0') "
+        "WHERE (NEW.tile_column < 0) ; "
+        "SELECT RAISE(ABORT, 'insert on table ''%q'' violates constraint: tile_column must by < matrix_width specified for table and zoom level in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.tile_column < (SELECT matrix_width FROM gpkg_tile_matrix WHERE table_name = '%q' AND zoom_level = NEW.zoom_level)); "
+        "END; "
+        "CREATE TRIGGER '%q_tile_column_update' "
+        "BEFORE UPDATE OF tile_column ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''%q'' violates constraint: tile_column cannot be < 0') "
+        "WHERE (NEW.tile_column < 0) ; "
+        "SELECT RAISE(ABORT, 'update on table ''%q'' violates constraint: tile_column must by < matrix_width specified for table and zoom level in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.tile_column < (SELECT matrix_width FROM gpkg_tile_matrix WHERE table_name = '%q' AND zoom_level = NEW.zoom_level)); "
+        "END; "
+        "CREATE TRIGGER '%q_tile_row_insert' "
+        "BEFORE INSERT ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'insert on table ''%q'' violates constraint: tile_row cannot be < 0') "
+        "WHERE (NEW.tile_row < 0) ; "
+        "SELECT RAISE(ABORT, 'insert on table ''%q'' violates constraint: tile_row must by < matrix_height specified for table and zoom level in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.tile_row < (SELECT matrix_height FROM gpkg_tile_matrix WHERE table_name = '%q' AND zoom_level = NEW.zoom_level)); "
+        "END; "
+        "CREATE TRIGGER '%q_tile_row_update' "
+        "BEFORE UPDATE OF tile_row ON '%q' "
+        "FOR EACH ROW BEGIN "
+        "SELECT RAISE(ABORT, 'update on table ''%q'' violates constraint: tile_row cannot be < 0') "
+        "WHERE (NEW.tile_row < 0) ; "
+        "SELECT RAISE(ABORT, 'update on table ''%q'' violates constraint: tile_row must by < matrix_height specified for table and zoom level in gpkg_tile_matrix') "
+        "WHERE NOT (NEW.tile_row < (SELECT matrix_height FROM gpkg_tile_matrix WHERE table_name = '%q' AND zoom_level = NEW.zoom_level)); "
+        "END; ",
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str(),
+        m_osRasterTable.c_str()
+        );
+        if( bCreateTriggers )
+        {
+            eErr = SQLCommand(hDB, pszSQLTriggers);
+            sqlite3_free(pszSQLTriggers);
+            if ( OGRERR_NONE != eErr )
+                return FALSE;
+        }
+
+        nRasterXSize = nXSize;
+        nRasterYSize = nYSize;
+
+        const char* pszTileSize = CSLFetchNameValueDef(papszOptions, "BLOCKSIZE", "256");
+        const char* pszTileWidth = CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", pszTileSize);
+        const char* pszTileHeight = CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", pszTileSize);
+        int nTileWidth = atoi(pszTileWidth);
+        int nTileHeight = atoi(pszTileHeight);
+        if( (nTileWidth < 8 || nTileWidth > 4096 || nTileHeight < 8 || nTileHeight > 4096) &&
+            !CSLTestBoolean(CPLGetConfigOption("GPKG_ALLOW_CRAZY_SETTINGS", "NO")) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Invalid block dimensions: %dx%d",
+                     nTileWidth, nTileHeight);
+            return FALSE;
+        }
+
+        m_pabyCachedTiles = (GByte*) VSIMalloc3(4 * 4, nTileWidth, nTileHeight);
+        if( m_pabyCachedTiles == NULL )
+        {
+            return FALSE;
+        }
+
+        for(int i = 1; i <= nBands; i ++)
+            SetBand( i, new GDALGeoPackageRasterBand(this, i, nTileWidth, nTileHeight) );
+
+        GDALPamDataset::SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
+        GDALPamDataset::SetMetadataItem("IDENTIFIER", m_osIdentifier);
+        if( m_osDescription.size() )
+            GDALPamDataset::SetMetadataItem("DESCRIPTION", m_osDescription);
+
+        const char* pszTF = CSLFetchNameValue(papszOptions, "TILE_FORMAT");
+        if( pszTF )
+            m_eTF = GetTileFormat(pszTF);
+
+        ParseCompressionOptions(papszOptions);
+
+        if( m_eTF == GPKG_TF_WEBP )
+        {
+            if( !RegisterWebPExtension() )
+                return FALSE;
+        }
+
+        const char* pszTilingScheme = CSLFetchNameValue(papszOptions, "TILING_SCHEME");
+        if( pszTilingScheme )
+        {
+            m_osTilingScheme = pszTilingScheme;
+            int bFound = FALSE;
+            for(size_t iScheme = 0;
+                iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]);
+                 iScheme++ )
+            {
+                if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) )
+                {
+                    if( nTileWidth != asTilingShemes[iScheme].nTileWidth ||
+                        nTileHeight != asTilingShemes[iScheme].nTileHeight )
+                    {
+                        CPLError(CE_Failure, CPLE_NotSupported,
+                                "Tile dimension should be %dx%d for %s tiling scheme",
+                                asTilingShemes[iScheme].nTileWidth,
+                                asTilingShemes[iScheme].nTileHeight,
+                                m_osTilingScheme.c_str());
+                        return FALSE;
+                    }
+
+                    /* Implicitely sets SRS */
+                    OGRSpatialReference oSRS;
+                    if( oSRS.importFromEPSG(asTilingShemes[iScheme].nEPSGCode) != OGRERR_NONE )
+                        return FALSE;
+                    char* pszWKT = NULL;
+                    oSRS.exportToWkt(&pszWKT);
+                    SetProjection(pszWKT);
+                    CPLFree(pszWKT);
+
+                    bFound = TRUE;
+                    break;
+                }
+            }
+            if( !bFound )
+                m_osTilingScheme = "CUSTOM";
+        }
+    }
+
+    SoftCommitTransaction();
+
+    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) */
+    /* in the application id field of the SQLite database header */
+    /* We have to do this after there's some content so the database file */
+    /* is not zero length */
+    SetApplicationId();
+
+    /* Default to synchronous=off for performance for new file */
+    if( !bFileExists && CPLGetConfigOption("OGR_SQLITE_SYNCHRONOUS", NULL) == NULL )
+    {
+        sqlite3_exec( hDB, "PRAGMA synchronous = OFF", NULL, NULL, NULL );
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            CreateCopy()                              */
+/************************************************************************/
+
+typedef struct
+{
+    const char*         pszName;
+    GDALResampleAlg     eResampleAlg;
+} WarpResamplingAlg;
+
+static const WarpResamplingAlg asResamplingAlg[] =
+{
+    { "BILINEAR", GRA_Bilinear },
+    { "CUBIC", GRA_Cubic },
+    { "CUBICSPLINE", GRA_CubicSpline },
+    { "LANCZOS", GRA_Lanczos },
+    { "MODE", GRA_Mode },
+    { "AVERAGE", GRA_Average },
+};
+
+GDALDataset* GDALGeoPackageDataset::CreateCopy( const char *pszFilename,
+                                                   GDALDataset *poSrcDS, 
+                                                   int bStrict,
+                                                   char ** papszOptions,
+                                                   GDALProgressFunc pfnProgress, 
+                                                   void * pProgressData )
+{
+    const char* pszTilingScheme = 
+            CSLFetchNameValueDef(papszOptions, "TILING_SCHEME", "CUSTOM");
+
+    char** papszUpdatedOptions = CSLDuplicate(papszOptions);
+    if( CSLTestBoolean(CSLFetchNameValueDef(papszOptions, "APPEND_SUBDATASET", "NO")) &&
+        CSLFetchNameValue(papszOptions, "RASTER_TABLE") == NULL )
+    {
+        papszUpdatedOptions = CSLSetNameValue(papszUpdatedOptions,
+                                              "RASTER_TABLE",
+                                              CPLGetBasename(poSrcDS->GetDescription()));
+    }
+
+    if( EQUAL(pszTilingScheme, "CUSTOM") )
+    {
+        GDALDriver* poThisDriver = (GDALDriver*)GDALGetDriverByName("GPKG");
+        if( !poThisDriver )
+        {
+            CSLDestroy(papszUpdatedOptions);
+            return NULL;
+        }
+        GDALDataset* poDS = poThisDriver->DefaultCreateCopy(
+                                    pszFilename, poSrcDS, bStrict, 
+                                    papszUpdatedOptions, pfnProgress, pProgressData );
+        CSLDestroy(papszUpdatedOptions);
+        return poDS;
+    }
+    
+    int nBands = poSrcDS->GetRasterCount();
+    if( nBands != 1 && nBands != 2 && nBands != 3 && nBands != 4 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                    "Only 1 (Grey/ColorTable), 2 (Grey+Alpha), 3 (RGB) or 4 (RGBA) band dataset supported");
+        CSLDestroy(papszUpdatedOptions);
+        return NULL;
+    }
+
+    int bFound = FALSE;
+    int nEPSGCode = 0;
+    size_t iScheme;
+    for(iScheme = 0;
+        iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]);
+        iScheme++ )
+    {
+        if( EQUAL(pszTilingScheme, asTilingShemes[iScheme].pszName) )
+        {
+            nEPSGCode = asTilingShemes[iScheme].nEPSGCode;
+            bFound = TRUE;
+            break;
+        }
+    }
+    if( !bFound )
+    {
+        CSLDestroy(papszUpdatedOptions);
+        return NULL;
+    }
+
+    OGRSpatialReference oSRS;
+    if( oSRS.importFromEPSG(nEPSGCode) != OGRERR_NONE )
+    {
+        CSLDestroy(papszUpdatedOptions);
+        return NULL;
+    }
+    char* pszWKT = NULL;
+    oSRS.exportToWkt(&pszWKT);
+    char** papszTO = CSLSetNameValue( NULL, "DST_SRS", pszWKT );
+    void* hTransformArg = 
+            GDALCreateGenImgProjTransformer2( poSrcDS, NULL, papszTO );
+    if( hTransformArg == NULL )
+    {
+        CSLDestroy(papszUpdatedOptions);
+        CPLFree(pszWKT);
+        CSLDestroy(papszTO);
+        return NULL;
+    }
+
+    GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg;
+    double adfGeoTransform[6];
+    double adfExtent[4];
+    int    nXSize, nYSize;
+
+    if ( GDALSuggestedWarpOutput2( poSrcDS, 
+                                  psInfo->pfnTransform, hTransformArg, 
+                                  adfGeoTransform, 
+                                  &nXSize, &nYSize, 
+                                  adfExtent, 0 ) != CE_None )
+    {
+        CSLDestroy(papszUpdatedOptions);
+        CPLFree(pszWKT);
+        CSLDestroy(papszTO);
+        GDALDestroyGenImgProjTransformer( hTransformArg );
+        return NULL;
+    }
+
+    GDALDestroyGenImgProjTransformer( hTransformArg );
+    hTransformArg = NULL;
+
+    int nZoomLevel;
+    double dfComputedRes = adfGeoTransform[1];
+    double dfPrevRes = 0, dfRes = 0;
+    for(nZoomLevel = 0; nZoomLevel < 25; nZoomLevel++)
+    {
+        dfRes = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0 / (1 << nZoomLevel);
+        if( dfComputedRes > dfRes )
+            break;
+        dfPrevRes = dfRes;
+    }
+    if( nZoomLevel == 25 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Could not find an appropriate zoom level");
+        CSLDestroy(papszUpdatedOptions);
+        CPLFree(pszWKT);
+        CSLDestroy(papszTO);
+        return NULL;
+    }
+    
+    const char* pszZoomLevelStrategy = CSLFetchNameValueDef(papszOptions,
+                                                            "ZOOM_LEVEL_STRATEGY",
+                                                            "AUTO");
+    if( fabs( dfComputedRes - dfRes ) / dfRes > 1e-8 )
+    {
+        if( EQUAL(pszZoomLevelStrategy, "LOWER") )
+        {
+            if( nZoomLevel > 0 )
+                nZoomLevel --;
+        }
+        else if( EQUAL(pszZoomLevelStrategy, "UPPER") )
+        {
+            /* do nothing */
+        }
+        else if( nZoomLevel > 0 )
+        {
+            if( dfPrevRes / dfComputedRes < dfComputedRes / dfRes )
+                nZoomLevel --;
+        }
+    }
+
+    dfRes = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0 / (1 << nZoomLevel);
+
+    double dfMinX = adfExtent[0];
+    double dfMinY = adfExtent[1];
+    double dfMaxX = adfExtent[2];
+    double dfMaxY = adfExtent[3];
+
+    nXSize = (int) ( 0.5 + ( dfMaxX - dfMinX ) / dfRes );
+    nYSize = (int) ( 0.5 + ( dfMaxY - dfMinY ) / dfRes );
+    adfGeoTransform[1] = dfRes;
+    adfGeoTransform[5] = -dfRes;
+
+    int nTargetBands = nBands;
+    /* For grey level or RGB, if there's reprojection involved, add an alpha */
+    /* channel */
+    if( (nBands == 1 && poSrcDS->GetRasterBand(1)->GetColorTable() == NULL) ||
+        nBands == 3 )
+    {
+        OGRSpatialReference oSrcSRS;
+        oSrcSRS.SetFromUserInput(poSrcDS->GetProjectionRef());
+        oSrcSRS.AutoIdentifyEPSG();
+        if( oSrcSRS.GetAuthorityCode(NULL) == NULL ||
+            atoi(oSrcSRS.GetAuthorityCode(NULL)) != nEPSGCode )
+        {
+            nTargetBands ++;
+        }
+    }
+
+    GDALGeoPackageDataset* poDS = new GDALGeoPackageDataset();
+    if( !(poDS->Create( pszFilename, nXSize, nYSize, nTargetBands, GDT_Byte,
+                        papszUpdatedOptions )) )
+    {
+        delete poDS;
+        CSLDestroy(papszUpdatedOptions);
+        CPLFree(pszWKT);
+        CSLDestroy(papszTO);
+        return NULL;
+    }
+    CSLDestroy(papszUpdatedOptions);
+    papszUpdatedOptions = NULL;
+    poDS->SetGeoTransform(adfGeoTransform);
+    poDS->SetProjection(pszWKT);
+    CPLFree(pszWKT);
+    pszWKT = NULL;
+
+    hTransformArg =
+        GDALCreateGenImgProjTransformer2( poSrcDS, poDS, papszTO );
+    CSLDestroy(papszTO);
+    if( hTransformArg == NULL )
+    {
+        delete poDS;
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Warp the transformer with a linear approximator                 */
+/* -------------------------------------------------------------------- */
+    hTransformArg =
+        GDALCreateApproxTransformer( GDALGenImgProjTransform, 
+                                     hTransformArg, 0.125 );
+    GDALApproxTransformerOwnsSubtransformer(hTransformArg, TRUE);
+
+/* -------------------------------------------------------------------- */
+/*      Setup warp options.                                             */
+/* -------------------------------------------------------------------- */
+    GDALWarpOptions *psWO = GDALCreateWarpOptions();
+
+    psWO->papszWarpOptions = NULL;
+    psWO->eWorkingDataType = GDT_Byte;
+    
+    GDALResampleAlg eResampleAlg = GRA_Bilinear;
+    const char* pszResampling = CSLFetchNameValue(papszOptions, "RESAMPLING");
+    if( pszResampling )
+    {
+        for(size_t iAlg = 0; iAlg < sizeof(asResamplingAlg)/sizeof(asResamplingAlg[0]); iAlg ++)
+        {
+            if( EQUAL(pszResampling, asResamplingAlg[iAlg].pszName) )
+            {
+                eResampleAlg = asResamplingAlg[iAlg].eResampleAlg;
+                break;
+            }
+        }
+    }
+    psWO->eResampleAlg = eResampleAlg;
+
+    psWO->hSrcDS = poSrcDS;
+    psWO->hDstDS = poDS;
+
+    psWO->pfnTransformer = GDALApproxTransform;
+    psWO->pTransformerArg = hTransformArg;
+
+    psWO->pfnProgress = pfnProgress;
+    psWO->pProgressArg = pProgressData;
+
+/* -------------------------------------------------------------------- */
+/*      Setup band mapping.                                             */
+/* -------------------------------------------------------------------- */
+
+    if( nBands == 2 || nBands == 4 )
+        psWO->nBandCount = nBands - 1;
+    else
+        psWO->nBandCount = nBands;
+
+    psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+    psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int));
+
+    for( int i = 0; i < psWO->nBandCount; i++ )
+    {
+        psWO->panSrcBands[i] = i+1;
+        psWO->panDstBands[i] = i+1;
+    }
+
+    if( nBands == 2 || nBands == 4 )
+    {
+        psWO->nSrcAlphaBand = nBands;
+    }
+    if( nTargetBands == 2 || nTargetBands == 4 )
+    {
+        psWO->nDstAlphaBand = nTargetBands;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Initialize and execute the warp.                                */
+/* -------------------------------------------------------------------- */
+    GDALWarpOperation oWO;
+
+    CPLErr eErr = oWO.Initialize( psWO );
+    if( eErr == CE_None )
+    {
+        /*if( bMulti )
+            eErr = oWO.ChunkAndWarpMulti( 0, 0, nXSize, nYSize );
+        else*/
+        eErr = oWO.ChunkAndWarpImage( 0, 0, nXSize, nYSize );
+    }
+    if (eErr != CE_None)
+    {
+        delete poDS;
+        poDS = NULL;
+    }
+
+    GDALDestroyTransformer( hTransformArg );
+    GDALDestroyWarpOptions( psWO );
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                        ParseCompressionOptions()                     */
+/************************************************************************/
+
+void GDALGeoPackageDataset::ParseCompressionOptions(char** papszOptions)
+{
+    const char* pszZLevel = CSLFetchNameValue(papszOptions, "ZLEVEL");
+    if( pszZLevel )
+        m_nZLevel = atoi(pszZLevel);
+
+    const char* pszQuality = CSLFetchNameValue(papszOptions, "QUALITY");
+    if( pszQuality )
+        m_nQuality = atoi(pszQuality);
+
+    const char* pszDither = CSLFetchNameValue(papszOptions, "DITHER");
+    if( pszDither )
+        m_bDither = CSLTestBoolean(pszDither);
+}
+
+/************************************************************************/
+/*                          RegisterWebPExtension()                     */
+/************************************************************************/
+
+int GDALGeoPackageDataset::RegisterWebPExtension()
+{
+    CreateExtensionsTableIfNecessary();
+
+    char* pszSQL = sqlite3_mprintf(
+        "INSERT INTO gpkg_extensions "
+        "(table_name, column_name, extension_name, definition, scope) "
+        "VALUES "
+        "('%q', 'tile_data', 'gpkg_webp', 'GeoPackage 1.0 Specification Annex P', 'read-write')",
+        m_osRasterTable.c_str());
+    OGRErr eErr = SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+    if ( OGRERR_NONE != eErr )
+        return FALSE;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                       RegisterZoomOtherExtension()                   */
+/************************************************************************/
+
+int GDALGeoPackageDataset::RegisterZoomOtherExtension()
+{
+    CreateExtensionsTableIfNecessary();
+
+    char* pszSQL = sqlite3_mprintf(
+        "INSERT INTO gpkg_extensions "
+        "(table_name, extension_name, definition, scope) "
+        "VALUES "
+        "('%q', 'gpkg_zoom_other', 'GeoPackage 1.0 Specification Annex O', 'read-write')",
+        m_osRasterTable.c_str());
+    OGRErr eErr = SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+    if ( OGRERR_NONE != eErr )
+        return FALSE;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer* GDALGeoPackageDataset::GetLayer( int iLayer )
+
+{
+    if( iLayer < 0 || iLayer >= m_nLayers )
+        return NULL;
+    else
+        return m_papoLayers[iLayer];
+}
+
+/************************************************************************/
+/*                          ICreateLayer()                              */
+/* Options:                                                             */
+/*   FID = primary key name                                             */
+/*   OVERWRITE = YES|NO, overwrite existing layer?                      */
+/*   SPATIAL_INDEX = YES|NO, TBD                                        */
+/************************************************************************/
+
+OGRLayer* GDALGeoPackageDataset::ICreateLayer( const char * pszLayerName,
+                                      OGRSpatialReference * poSpatialRef,
+                                      OGRwkbGeometryType eGType,
+                                      char **papszOptions )
+{
+    int iLayer;
+
+/* -------------------------------------------------------------------- */
+/*      Verify we are in update mode.                                   */
+/* -------------------------------------------------------------------- */
+    if( !bUpdate )
+    {
+        CPLError( CE_Failure, CPLE_NoWriteAccess,
+                  "Data source %s opened read-only.\n"
+                  "New layer %s cannot be created.\n",
+                  m_pszFilename, pszLayerName );
+
+        return NULL;
+    }
+
+    /* Read GEOMETRY_NAME option */
+    const char* pszGeomColumnName = CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
+    if (pszGeomColumnName == NULL) /* deprecated name */
+        pszGeomColumnName = CSLFetchNameValue(papszOptions, "GEOMETRY_COLUMN");
+    if (pszGeomColumnName == NULL)
+        pszGeomColumnName = "geom";
+    int bGeomNullable = CSLFetchBoolean(papszOptions, "GEOMETRY_NULLABLE", TRUE);
+    
+    /* Read FID option */
+    const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
+    if (pszFIDColumnName == NULL)
+        pszFIDColumnName = "fid";
+
+    if ( strspn(pszFIDColumnName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "The primary key (%s) name may not contain special characters or spaces", 
+                 pszFIDColumnName);
+        return NULL;
+    }
+
+    /* Avoiding gpkg prefixes is not an official requirement, but seems wise */
+    if (strncmp(pszLayerName, "gpkg", 4) == 0)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "The layer name may not begin with 'gpkg' as it is a reserved geopackage prefix");
+        return NULL;
+    }
+
+    /* Pre-emptively try and avoid sqlite3 syntax errors due to  */
+    /* illegal characters */
+    if ( strspn(pszLayerName, "`~!@#$%^&*()+-={}|[]\\:\";'<>?,./") > 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "The layer name may not contain special characters or spaces");
+        return NULL;
+    }
+
+    /* Check for any existing layers that already use this name */
+    for( iLayer = 0; iLayer < m_nLayers; iLayer++ )
+    {
+        if( EQUAL(pszLayerName, m_papoLayers[iLayer]->GetName()) )
+        {
+            const char *pszOverwrite = CSLFetchNameValue(papszOptions,"OVERWRITE");
+            if( pszOverwrite != NULL && CSLTestBoolean(pszOverwrite) )
+            {
+                DeleteLayer( iLayer );
+            }
+            else
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                          "Layer %s already exists, CreateLayer failed.\n"
+                          "Use the layer creation option OVERWRITE=YES to "
+                          "replace it.",
+                          pszLayerName );
+                return NULL;
+            }
+        }
+    }
+
+    /* Create a blank layer. */
+    OGRGeoPackageTableLayer *poLayer = new OGRGeoPackageTableLayer(this, pszLayerName);
+
+    poLayer->SetCreationParameters( eGType, pszGeomColumnName,
+                                    bGeomNullable,
+                                    poSpatialRef,
+                                    pszFIDColumnName,
+                                    CSLFetchNameValue(papszOptions, "IDENTIFIER"),
+                                    CSLFetchNameValue(papszOptions, "DESCRIPTION") );
+
+    /* Should we create a spatial index ? */
+    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
+    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
+    if( eGType != wkbNone && bCreateSpatialIndex )
+    {
+        poLayer->SetDeferedSpatialIndexCreation(TRUE);
+    }
+
+    poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
+    poLayer->SetTruncateFieldsFlag( CSLFetchBoolean(papszOptions,"TRUNCATE_FIELDS",FALSE));
+
+    m_papoLayers = (OGRGeoPackageTableLayer**)CPLRealloc(m_papoLayers,  sizeof(OGRGeoPackageTableLayer*) * (m_nLayers+1));
+    m_papoLayers[m_nLayers++] = poLayer;
+    return poLayer;
+}
+
+
+/************************************************************************/
+/*                            DeleteLayer()                             */
+/************************************************************************/
+
+int GDALGeoPackageDataset::DeleteLayer( int iLayer )
+{
+    char *pszSQL;
+
+    if( !bUpdate || iLayer < 0 || iLayer >= m_nLayers )
+        return OGRERR_FAILURE;
+
+    CPLString osLayerName = m_papoLayers[iLayer]->GetLayerDefn()->GetName();
+
+    CPLDebug( "GPKG", "DeleteLayer(%s)", osLayerName.c_str() );
+
+    if( m_papoLayers[iLayer]->HasSpatialIndex() )
+        m_papoLayers[iLayer]->DropSpatialIndex();
+
+    /* Delete the layer object and remove the gap in the layers list */
+    delete m_papoLayers[iLayer];
+    memmove( m_papoLayers + iLayer, m_papoLayers + iLayer + 1,
+             sizeof(void *) * (m_nLayers - iLayer - 1) );
+    m_nLayers--;
+
+    if (osLayerName.size() == 0)
+        return OGRERR_NONE;
+
+    pszSQL = sqlite3_mprintf(
+            "DROP TABLE \"%s\"",
+             osLayerName.c_str());
+    
+    SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf(
+            "DELETE FROM gpkg_geometry_columns WHERE table_name = '%q'",
+             osLayerName.c_str());
+    
+    SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+    
+    pszSQL = sqlite3_mprintf(
+             "DELETE FROM gpkg_contents WHERE table_name = '%q'",
+              osLayerName.c_str());
+
+    SQLCommand(hDB, pszSQL);
+    sqlite3_free(pszSQL);
+
+    return OGRERR_NONE;
+}
+
+
+
+/************************************************************************/
+/*                       TestCapability()                               */
+/************************************************************************/
+
+int GDALGeoPackageDataset::TestCapability( const char * pszCap )
+{
+    if ( EQUAL(pszCap,ODsCCreateLayer) ||
+         EQUAL(pszCap,ODsCDeleteLayer) )
+    {
+         return bUpdate;
+    }
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
+    return OGRSQLiteBaseDataSource::TestCapability(pszCap);
+}
+
+/************************************************************************/
+/*                             ExecuteSQL()                             */
+/************************************************************************/
+
+static const char* apszFuncsWithSideEffects[] =
+{
+    "CreateSpatialIndex",
+    "DisableSpatialIndex",
+};
+
+OGRLayer * GDALGeoPackageDataset::ExecuteSQL( const char *pszSQLCommand,
+                                          OGRGeometry *poSpatialFilter,
+                                          const char *pszDialect )
+
+{
+    m_bHasReadMetadataFromStorage = FALSE;
+
+    FlushMetadata();
+    for( int i = 0; i < m_nLayers; i++ )
+    {
+        m_papoLayers[i]->RunDeferredCreationIfNecessary();
+        m_papoLayers[i]->CreateSpatialIndexIfNecessary();
+    }
+
+    if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
+        return GDALDataset::ExecuteSQL( pszSQLCommand, 
+                                          poSpatialFilter, 
+                                          pszDialect );
+    else if( pszDialect != NULL && EQUAL(pszDialect,"INDIRECT_SQLITE") )
+        return GDALDataset::ExecuteSQL( pszSQLCommand, 
+                                          poSpatialFilter, 
+                                          "SQLITE" );
+
+/* -------------------------------------------------------------------- */
+/*      Prepare statement.                                              */
+/* -------------------------------------------------------------------- */
+    int rc;
+    sqlite3_stmt *hSQLStmt = NULL;
+
+    CPLString osSQLCommand = pszSQLCommand;
+
+    /* This will speed-up layer creation */
+    /* ORDER BY are costly to evaluate and are not necessary to establish */
+    /* the layer definition. */
+    int bUseStatementForGetNextFeature = TRUE;
+    int bEmptyLayer = FALSE;
+
+    if( osSQLCommand.ifind("SELECT ") == 0 &&
+        osSQLCommand.ifind(" UNION ") == std::string::npos &&
+        osSQLCommand.ifind(" INTERSECT ") == std::string::npos &&
+        osSQLCommand.ifind(" EXCEPT ") == std::string::npos )
+    {
+        size_t nOrderByPos = osSQLCommand.ifind(" ORDER BY ");
+        if( nOrderByPos != std::string::npos )
+        {
+            osSQLCommand.resize(nOrderByPos);
+            bUseStatementForGetNextFeature = FALSE;
+        }
+    }
+
+    rc = sqlite3_prepare( hDB, osSQLCommand.c_str(), osSQLCommand.size(),
+                          &hSQLStmt, NULL );
+
+    if( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                "In ExecuteSQL(): sqlite3_prepare(%s):\n  %s", 
+                pszSQLCommand, sqlite3_errmsg(hDB) );
+
+        if( hSQLStmt != NULL )
+        {
+            sqlite3_finalize( hSQLStmt );
+        }
+
+        return NULL;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Do we get a resultset?                                          */
+/* -------------------------------------------------------------------- */
+    rc = sqlite3_step( hSQLStmt );
+    if( rc != SQLITE_ROW )
+    {
+        if ( rc != SQLITE_DONE )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                  "In ExecuteSQL(): sqlite3_step(%s):\n  %s", 
+                  pszSQLCommand, sqlite3_errmsg(hDB) );
+
+            sqlite3_finalize( hSQLStmt );
+            return NULL;
+        }
+        
+        if( EQUAL(pszSQLCommand, "VACUUM") )
+        {
+            sqlite3_finalize( hSQLStmt );
+            /* VACUUM rewrites the DB, so we need to reset the application id */
+            SetApplicationId();
+            return NULL;
+        }
+        
+        if( EQUALN(pszSQLCommand, "ALTER TABLE ", strlen("ALTER TABLE ")) )
+        {
+            char **papszTokens = CSLTokenizeString( pszSQLCommand );
+            /* ALTER TABLE src_table RENAME TO dst_table */
+            if( CSLCount(papszTokens) == 6 && EQUAL(papszTokens[3], "RENAME") &&
+                EQUAL(papszTokens[4], "TO") )
+            {
+                const char* pszSrcTableName = papszTokens[2];
+                const char* pszDstTableName = papszTokens[5];
+                OGRGeoPackageTableLayer* poSrcLayer = (OGRGeoPackageTableLayer*)GetLayerByName(pszSrcTableName);
+                if( poSrcLayer )
+                {
+                    poSrcLayer->RenameTo( pszDstTableName );
+                }
+            }
+            CSLDestroy(papszTokens);
+        }
+
+        if( !EQUALN(pszSQLCommand, "SELECT ", 7) )
+        {
+            sqlite3_finalize( hSQLStmt );
+            return NULL;
+        }
+
+        bUseStatementForGetNextFeature = FALSE;
+        bEmptyLayer = TRUE;
+    }
+    
+/* -------------------------------------------------------------------- */
+/*      Special case for some functions which must be run               */
+/*      only once                                                       */
+/* -------------------------------------------------------------------- */
+    if( EQUALN(pszSQLCommand,"SELECT ",7) )
+    {
+        unsigned int i;
+        for(i=0;i<sizeof(apszFuncsWithSideEffects)/
+                  sizeof(apszFuncsWithSideEffects[0]);i++)
+        {
+            if( EQUALN(apszFuncsWithSideEffects[i], pszSQLCommand + 7,
+                       strlen(apszFuncsWithSideEffects[i])) )
+            {
+                if (sqlite3_column_count( hSQLStmt ) == 1 &&
+                    sqlite3_column_type( hSQLStmt, 0 ) == SQLITE_INTEGER )
+                {
+                    int ret = sqlite3_column_int( hSQLStmt, 0 );
+
+                    sqlite3_finalize( hSQLStmt );
+
+                    return new OGRSQLiteSingleFeatureLayer
+                                        ( apszFuncsWithSideEffects[i], ret );
+                }
+            }
+        }
+    }
+    else if( EQUALN(pszSQLCommand,"PRAGMA ",7) )
+    {
+        if (sqlite3_column_count( hSQLStmt ) == 1 &&
+            sqlite3_column_type( hSQLStmt, 0 ) == SQLITE_INTEGER )
+        {
+            int ret = sqlite3_column_int( hSQLStmt, 0 );
+
+            sqlite3_finalize( hSQLStmt );
+
+            return new OGRSQLiteSingleFeatureLayer
+                                ( pszSQLCommand + 7, ret );
+        }
+        else if (sqlite3_column_count( hSQLStmt ) == 1 &&
+                 sqlite3_column_type( hSQLStmt, 0 ) == SQLITE_TEXT )
+        {
+            const char* pszRet = (const char*) sqlite3_column_text( hSQLStmt, 0 );
+
+            OGRLayer* poRet = new OGRSQLiteSingleFeatureLayer
+                                ( pszSQLCommand + 7, pszRet );
+
+            sqlite3_finalize( hSQLStmt );
+
+            return poRet;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Create layer.                                                   */
+/* -------------------------------------------------------------------- */
+    OGRLayer *poLayer = NULL;
+
+    CPLString osSQL = pszSQLCommand;
+    poLayer = new OGRGeoPackageSelectLayer( this, osSQL, hSQLStmt,
+                                        bUseStatementForGetNextFeature, bEmptyLayer );
+
+    if( poSpatialFilter != NULL )
+        poLayer->SetSpatialFilter( 0, poSpatialFilter );
+
+    return poLayer;
+}
+
+/************************************************************************/
+/*                          ReleaseResultSet()                          */
+/************************************************************************/
+
+void GDALGeoPackageDataset::ReleaseResultSet( OGRLayer * poLayer )
+
+{
+    delete poLayer;
+}
+
+/************************************************************************/
+/*                         HasExtensionsTable()                         */
+/************************************************************************/
+
+int GDALGeoPackageDataset::HasExtensionsTable()
+{
+    SQLResult oResultTable;
+    OGRErr err = SQLQuery(hDB,
+        "SELECT * FROM sqlite_master WHERE name = 'gpkg_extensions' "
+        "AND type IN ('table', 'view')", &oResultTable);
+    int bHasExtensionsTable = ( err == OGRERR_NONE && oResultTable.nRowCount == 1 );
+    SQLResultFree(&oResultTable);
+    return bHasExtensionsTable;
+}
+
+/************************************************************************/
+/*                    CheckUnknownExtensions()                          */
+/************************************************************************/
+
+void GDALGeoPackageDataset::CheckUnknownExtensions(int bCheckRasterTable)
+{
+    if( !HasExtensionsTable() )
+        return;
+
+    char* pszSQL;
+    if( !bCheckRasterTable)
+        pszSQL = sqlite3_mprintf(
+            "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name IS NULL AND extension_name != 'gdal_aspatial'");
+    else
+        pszSQL = sqlite3_mprintf(
+            "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name = '%q'",
+            m_osRasterTable.c_str());
+
+    SQLResult oResultTable;
+    OGRErr err = SQLQuery(GetDB(), pszSQL, &oResultTable);
+    sqlite3_free(pszSQL);
+    if ( err == OGRERR_NONE && oResultTable.nRowCount > 0 )
+    {
+        for(int i=0; i<oResultTable.nRowCount;i++)
+        {
+            const char* pszExtName = SQLResultGetValue(&oResultTable, 0, i);
+            const char* pszDefinition = SQLResultGetValue(&oResultTable, 1, i);
+            const char* pszScope = SQLResultGetValue(&oResultTable, 2, i);
+            if( pszExtName == NULL ) pszExtName = "(null)";
+            if( pszDefinition == NULL ) pszDefinition = "(null)";
+            if( pszScope == NULL ) pszScope = "(null)";
+
+            if( EQUAL(pszExtName, "gpkg_webp") )
+            {
+                if( GDALGetDriverByName("WEBP") == NULL )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "Table %s contains WEBP tiles, but GDAL configured "
+                             "without WEBP support. Data will be missing",
+                             m_osRasterTable.c_str());
+                }
+                m_eTF = GPKG_TF_WEBP;
+                continue;
+            }
+            if( EQUAL(pszExtName, "gpkg_zoom_other") )
+            {
+                m_bZoomOther = TRUE;
+                continue;
+            }
+
+            if( GetUpdate() && EQUAL(pszScope, "write-only") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Database relies on the '%s' (%s) extension that should "
+                         "be implemented for safe write-support, but is not currently. "
+                         "Update of that database are strongly discouraged to avoid corruption.",
+                         pszExtName, pszDefinition);
+            }
+            else if( GetUpdate() && EQUAL(pszScope, "read-write") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Database relies on the '%s' (%s) extension that should "
+                         "be implemented in order to read/write it safely, but is not currently. "
+                         "Some data may be missing while reading that database, and updates are strongly discouraged.",
+                         pszExtName, pszDefinition);
+            }
+            else if( EQUAL(pszScope, "read-write") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Database relies on the '%s' (%s) extension that should "
+                         "be implemented in order to read it safely, but is not currently. "
+                         "Some data may be missing while reading that database.",
+                         pszExtName, pszDefinition);
+            }
+        }
+    }
+    SQLResultFree(&oResultTable);
+}
+
+/************************************************************************/
+/*                         HasGDALAspatialExtension()                       */
+/************************************************************************/
+
+int GDALGeoPackageDataset::HasGDALAspatialExtension()
+{
+    if (!HasExtensionsTable())
+        return 0;
+
+    SQLResult oResultTable;
+    OGRErr err = SQLQuery(hDB,
+        "SELECT * FROM gpkg_extensions "
+        "WHERE extension_name = 'gdal_aspatial' "
+        "AND table_name IS NULL "
+        "AND column_name IS NULL", &oResultTable);
+    int bHasExtension = ( err == OGRERR_NONE && oResultTable.nRowCount == 1 );
+    SQLResultFree(&oResultTable);
+    return bHasExtension;
+}
+
+/************************************************************************/
+/*                  CreateGDALAspatialExtension()                       */
+/************************************************************************/
+
+OGRErr GDALGeoPackageDataset::CreateGDALAspatialExtension()
+{
+    CreateExtensionsTableIfNecessary();
+
+    if( HasGDALAspatialExtension() )
+        return OGRERR_NONE;
+
+    const char* pszCreateAspatialExtension =
+        "INSERT INTO gpkg_extensions "
+        "(table_name, column_name, extension_name, definition, scope) "
+        "VALUES "
+        "(NULL, NULL, 'gdal_aspatial', 'http://gdal.org/geopackage_aspatial.html', 'read-write')";
+
+    return SQLCommand(hDB, pszCreateAspatialExtension);
+}
+
+/************************************************************************/
+/*                  CreateExtensionsTableIfNecessary()                  */
+/************************************************************************/
+
+OGRErr GDALGeoPackageDataset::CreateExtensionsTableIfNecessary()
+{
+    /* Check if the table gpkg_extensions exists */
+    if( HasExtensionsTable() )
+        return OGRERR_NONE;
+
+    /* Requirement 79 : Every extension of a GeoPackage SHALL be registered */
+    /* in a corresponding row in the gpkg_extensions table. The absence of a */
+    /* gpkg_extensions table or the absence of rows in gpkg_extensions table */
+    /* SHALL both indicate the absence of extensions to a GeoPackage. */
+    const char* pszCreateGpkgExtensions = 
+        "CREATE TABLE gpkg_extensions ("
+        "table_name TEXT,"
+        "column_name TEXT,"
+        "extension_name TEXT NOT NULL,"
+        "definition TEXT NOT NULL,"
+        "scope TEXT NOT NULL,"
+        "CONSTRAINT ge_tce UNIQUE (table_name, column_name, extension_name)"
+        ")";
+
+    return SQLCommand(hDB, pszCreateGpkgExtensions);
+}
+
+/************************************************************************/
+/*                     OGRGeoPackageGetHeader()                         */
+/************************************************************************/
+
+static int OGRGeoPackageGetHeader(sqlite3_context* pContext,
+                                  CPL_UNUSED int argc,
+                                  sqlite3_value** argv,
+                                  GPkgHeader* psHeader,
+                                  int bNeedExtent)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_BLOB )
+    {
+        sqlite3_result_null(pContext);
+        return FALSE;
+    }
+    int nBLOBLen = sqlite3_value_bytes (argv[0]);
+    const GByte* pabyBLOB = (const GByte *) sqlite3_value_blob (argv[0]);
+    if( nBLOBLen < 4 ||
+        GPkgHeaderFromWKB(pabyBLOB, psHeader) != OGRERR_NONE )
+    {
+        sqlite3_result_null(pContext);
+        return FALSE;
+    }
+    if( psHeader->iDims == 0 && bNeedExtent )
+    {
+        OGRGeometry *poGeom = GPkgGeometryToOGR(pabyBLOB, nBLOBLen, NULL);
+        if( poGeom == NULL || poGeom->IsEmpty() )
+        {
+            sqlite3_result_null(pContext);
+            delete poGeom;
+            return FALSE;
+        }
+        OGREnvelope sEnvelope;
+        poGeom->getEnvelope(&sEnvelope);
+        psHeader->MinX = sEnvelope.MinX;
+        psHeader->MaxX = sEnvelope.MaxX;
+        psHeader->MinY = sEnvelope.MinY;
+        psHeader->MaxY = sEnvelope.MaxY;
+        delete poGeom;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                      OGRGeoPackageSTMinX()                           */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTMinX(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, TRUE) )
+        return;
+    sqlite3_result_double( pContext, sHeader.MinX );
+}
+
+/************************************************************************/
+/*                      OGRGeoPackageSTMinY()                           */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTMinY(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, TRUE) )
+        return;
+    sqlite3_result_double( pContext, sHeader.MinY );
+}
+
+/************************************************************************/
+/*                      OGRGeoPackageSTMaxX()                           */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTMaxX(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, TRUE) )
+        return;
+    sqlite3_result_double( pContext, sHeader.MaxX );
+}
+
+/************************************************************************/
+/*                      OGRGeoPackageSTMaxY()                           */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTMaxY(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, TRUE) )
+        return;
+    sqlite3_result_double( pContext, sHeader.MaxY );
+}
+
+/************************************************************************/
+/*                     OGRGeoPackageSTIsEmpty()                         */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTIsEmpty(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, FALSE) )
+        return;
+    sqlite3_result_int( pContext, sHeader.bEmpty );
+}
+
+/************************************************************************/
+/*                    OGRGeoPackageSTGeometryType()                     */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTGeometryType(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, FALSE) )
+        return;
+
+    int nBLOBLen = sqlite3_value_bytes (argv[0]);
+    const GByte* pabyBLOB = (const GByte *) sqlite3_value_blob (argv[0]);
+    OGRBoolean bIs3D;
+    OGRwkbGeometryType eGeometryType;
+    if( nBLOBLen <= (int)sHeader.szHeader )
+    {
+        sqlite3_result_null( pContext );
+        return;
+    }
+    OGRErr err = OGRReadWKBGeometryType( (GByte*)pabyBLOB + sHeader.szHeader,
+                                         wkbVariantIso, &eGeometryType, &bIs3D );
+    if( err != OGRERR_NONE )
+        sqlite3_result_null( pContext );
+    else
+        sqlite3_result_text( pContext, OGRToOGCGeomType(eGeometryType), -1, SQLITE_TRANSIENT );
+}
+
+/************************************************************************/
+/*                    OGRGeoPackageGPKGIsAssignable()                   */
+/************************************************************************/
+
+static
+void OGRGeoPackageGPKGIsAssignable(sqlite3_context* pContext,
+                                   CPL_UNUSED int argc,
+                                   sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
+        sqlite3_value_type (argv[1]) != SQLITE_TEXT )
+    {
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+
+    const char* pszExpected = (const char*)sqlite3_value_text(argv[0]);
+    const char* pszActual = (const char*)sqlite3_value_text(argv[1]);
+    int bIsAssignable = OGR_GT_IsSubClassOf( OGRFromOGCGeomType(pszActual),
+                                             OGRFromOGCGeomType(pszExpected) );
+    sqlite3_result_int( pContext, bIsAssignable );
+}
+
+/************************************************************************/
+/*                     OGRGeoPackageSTSRID()                            */
+/************************************************************************/
+
+static
+void OGRGeoPackageSTSRID(sqlite3_context* pContext,
+                        int argc, sqlite3_value** argv)
+{
+    GPkgHeader sHeader;
+    if( !OGRGeoPackageGetHeader(pContext, argc, argv, &sHeader, FALSE) )
+        return;
+    sqlite3_result_int( pContext, sHeader.iSrsId );
+}
+
+/************************************************************************/
+/*                  OGRGeoPackageCreateSpatialIndex()                   */
+/************************************************************************/
+
+static
+void OGRGeoPackageCreateSpatialIndex(sqlite3_context* pContext,
+                                     CPL_UNUSED int argc,
+                                     sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
+        sqlite3_value_type (argv[1]) != SQLITE_TEXT )
+    {
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+
+    const char* pszTableName = (const char*)sqlite3_value_text(argv[0]);
+    const char* pszGeomName = (const char*)sqlite3_value_text(argv[1]);
+    GDALGeoPackageDataset* poDS = (GDALGeoPackageDataset* )sqlite3_user_data(pContext);
+    
+    OGRGeoPackageTableLayer* poLyr = (OGRGeoPackageTableLayer*)poDS->GetLayerByName(pszTableName);
+    if( poLyr == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Unknown layer name");
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+    if( !EQUAL(poLyr->GetGeometryColumn(), pszGeomName) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Unknown geometry column name");
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+
+    sqlite3_result_int( pContext, poLyr->CreateSpatialIndex() );
+}
+
+/************************************************************************/
+/*                  OGRGeoPackageDisableSpatialIndex()                  */
+/************************************************************************/
+
+static
+void OGRGeoPackageDisableSpatialIndex(sqlite3_context* pContext,
+                                      CPL_UNUSED int argc,
+                                      sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
+        sqlite3_value_type (argv[1]) != SQLITE_TEXT )
+    {
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+
+    const char* pszTableName = (const char*)sqlite3_value_text(argv[0]);
+    const char* pszGeomName = (const char*)sqlite3_value_text(argv[1]);
+    GDALGeoPackageDataset* poDS = (GDALGeoPackageDataset* )sqlite3_user_data(pContext);
+    
+    OGRGeoPackageTableLayer* poLyr = (OGRGeoPackageTableLayer*)poDS->GetLayerByName(pszTableName);
+    if( poLyr == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Unknown layer name");
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+    if( !EQUAL(poLyr->GetGeometryColumn(), pszGeomName) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Unknown geometry column name");
+        sqlite3_result_int( pContext, 0 );
+        return;
+    }
+
+    sqlite3_result_int( pContext, poLyr->DropSpatialIndex(TRUE) );
+}
+
+/************************************************************************/
+/*                       GPKG_hstore_get_value()                        */
+/************************************************************************/
+
+static
+void GPKG_hstore_get_value(sqlite3_context* pContext,
+                           CPL_UNUSED int argc,
+                           sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
+        sqlite3_value_type (argv[1]) != SQLITE_TEXT )
+    {
+        sqlite3_result_null (pContext);
+        return;
+    }
+
+    const char* pszHStore = (const char*)sqlite3_value_text(argv[0]);
+    const char* pszSearchedKey = (const char*)sqlite3_value_text(argv[1]);
+    char* pszValue = OGRHStoreGetValue(pszHStore, pszSearchedKey);
+    if( pszValue != NULL )
+        sqlite3_result_text( pContext, pszValue, -1, CPLFree );
+    else
+        sqlite3_result_null( pContext );
+}
+
+/************************************************************************/
+/*                      GPKG_GDAL_GetMemFileFromBlob()                  */
+/************************************************************************/
+
+static CPLString GPKG_GDAL_GetMemFileFromBlob(sqlite3_value** argv)
+{
+    int nBytes = sqlite3_value_bytes (argv[0]);
+    const GByte* pabyBLOB = (const GByte *) sqlite3_value_blob (argv[0]);
+    CPLString osMemFileName;
+    osMemFileName.Printf("/vsimem/GPKG_GDAL_GetMemFileFromBlob_%p", argv);
+    VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), (GByte*)pabyBLOB,
+                                          nBytes, FALSE);
+    VSIFCloseL(fp);
+    return osMemFileName;
+}
+
+/************************************************************************/
+/*                       GPKG_GDAL_GetMimeType()                        */
+/************************************************************************/
+
+static
+void GPKG_GDAL_GetMimeType(sqlite3_context* pContext,
+                           CPL_UNUSED int argc,
+                           sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_BLOB )
+    {
+        sqlite3_result_null (pContext);
+        return;
+    }
+
+    CPLString osMemFileName(GPKG_GDAL_GetMemFileFromBlob(argv));
+    GDALDriver* poDriver = (GDALDriver*)GDALIdentifyDriver(osMemFileName, NULL);
+    if( poDriver != NULL )
+    {
+        const char* pszRes;
+        if( EQUAL(poDriver->GetDescription(), "PNG") )
+            pszRes = "image/png";
+        else if( EQUAL(poDriver->GetDescription(), "JPEG") )
+            pszRes = "image/jpeg";
+        else if( EQUAL(poDriver->GetDescription(), "WEBP") )
+            pszRes = "image/x-webp";
+        else
+            pszRes = CPLSPrintf("gdal/%s", poDriver->GetDescription());
+        sqlite3_result_text( pContext, pszRes, -1, SQLITE_TRANSIENT );
+    }
+    else
+        sqlite3_result_null (pContext);
+    VSIUnlink(osMemFileName);
+}
+
+/************************************************************************/
+/*                       GPKG_GDAL_GetBandCount()                       */
+/************************************************************************/
+
+static
+void GPKG_GDAL_GetBandCount(sqlite3_context* pContext,
+                           CPL_UNUSED int argc,
+                           sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_BLOB )
+    {
+        sqlite3_result_null (pContext);
+        return;
+    }
+
+    CPLString osMemFileName(GPKG_GDAL_GetMemFileFromBlob(argv));
+    GDALDataset* poDS = (GDALDataset*) GDALOpenEx(osMemFileName,
+                                                  GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                                  NULL, NULL, NULL);
+    if( poDS != NULL )
+    {
+        sqlite3_result_int( pContext, poDS->GetRasterCount() );
+        GDALClose( poDS );
+    }
+    else
+        sqlite3_result_null (pContext);
+    VSIUnlink(osMemFileName);
+}
+
+/************************************************************************/
+/*                       GPKG_GDAL_HasColorTable()                      */
+/************************************************************************/
+
+static
+void GPKG_GDAL_HasColorTable(sqlite3_context* pContext,
+                             CPL_UNUSED int argc,
+                             sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_BLOB )
+    {
+        sqlite3_result_null (pContext);
+        return;
+    }
+
+    CPLString osMemFileName(GPKG_GDAL_GetMemFileFromBlob(argv));
+    GDALDataset* poDS = (GDALDataset*) GDALOpenEx(osMemFileName,
+                                                  GDAL_OF_RASTER | GDAL_OF_INTERNAL,
+                                                  NULL, NULL, NULL);
+    if( poDS != NULL )
+    {
+        sqlite3_result_int( pContext,
+                            poDS->GetRasterCount() == 1 &&
+                            poDS->GetRasterBand(1)->GetColorTable() != NULL );
+        GDALClose( poDS );
+    }
+    else
+        sqlite3_result_null (pContext);
+    VSIUnlink(osMemFileName);
+}
+
+/************************************************************************/
+/*                         OpenOrCreateDB()                             */
+/************************************************************************/
+
+int GDALGeoPackageDataset::OpenOrCreateDB(int flags)
+{
+    int bSuccess = OGRSQLiteBaseDataSource::OpenOrCreateDB(flags, FALSE);
+    if( !bSuccess )
+        return FALSE;
+
+#ifdef SPATIALITE_412_OR_LATER
+    InitNewSpatialite();
+#endif
+
+    /* Used by RTree Spatial Index Extension */
+    sqlite3_create_function(hDB, "ST_MinX", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTMinX, NULL, NULL);
+    sqlite3_create_function(hDB, "ST_MinY", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTMinY, NULL, NULL);
+    sqlite3_create_function(hDB, "ST_MaxX", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTMaxX, NULL, NULL);
+    sqlite3_create_function(hDB, "ST_MaxY", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTMaxY, NULL, NULL);
+    sqlite3_create_function(hDB, "ST_IsEmpty", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTIsEmpty, NULL, NULL);
+
+    /* Used by Geometry Type Triggers Extension */
+    sqlite3_create_function(hDB, "ST_GeometryType", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTGeometryType, NULL, NULL);
+    sqlite3_create_function(hDB, "GPKG_IsAssignable", 2, SQLITE_ANY, NULL,
+                            OGRGeoPackageGPKGIsAssignable, NULL, NULL);
+
+    /* Used by Geometry SRS ID Triggers Extension */
+    sqlite3_create_function(hDB, "ST_SRID", 1, SQLITE_ANY, NULL,
+                            OGRGeoPackageSTSRID, NULL, NULL);
+
+    /* Spatialite-like functions */
+    sqlite3_create_function(hDB, "CreateSpatialIndex", 2, SQLITE_ANY, this,
+                            OGRGeoPackageCreateSpatialIndex, NULL, NULL);
+    sqlite3_create_function(hDB, "DisableSpatialIndex", 2, SQLITE_ANY, this,
+                            OGRGeoPackageDisableSpatialIndex, NULL, NULL);
+
+    // HSTORE functions
+    sqlite3_create_function(hDB, "hstore_get_value", 2, SQLITE_ANY, NULL,
+                            GPKG_hstore_get_value, NULL, NULL);
+    
+    // Debug functions
+    if( CSLTestBoolean(CPLGetConfigOption("GPKG_DEBUG", "FALSE")) )
+    {
+        sqlite3_create_function(hDB, "GDAL_GetMimeType", 1, SQLITE_ANY, NULL,
+                                GPKG_GDAL_GetMimeType, NULL, NULL);
+        sqlite3_create_function(hDB, "GDAL_GetBandCount", 1, SQLITE_ANY, NULL,
+                                GPKG_GDAL_GetBandCount, NULL, NULL);
+        sqlite3_create_function(hDB, "GDAL_HasColorTable", 1, SQLITE_ANY, NULL,
+                                GPKG_GDAL_HasColorTable, NULL, NULL);
+    }
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                   GetLayerWithGetSpatialWhereByName()                */
+/************************************************************************/
+
+std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>
+    GDALGeoPackageDataset::GetLayerWithGetSpatialWhereByName( const char* pszName )
+{
+    OGRGeoPackageLayer* poRet = (OGRGeoPackageLayer*) GetLayerByName(pszName);
+    return std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>(poRet, poRet);
+}
+
+/************************************************************************/
+/*                       CommitTransaction()                        */
+/************************************************************************/
+
+OGRErr GDALGeoPackageDataset::CommitTransaction()
+
+{
+    if( nSoftTransactionLevel == 1 )
+    {
+        FlushMetadata();
+        for( int i = 0; i < m_nLayers; i++ )
+        {
+            m_papoLayers[i]->RunDeferredCreationIfNecessary();
+        }
+    }
+
+    return OGRSQLiteBaseDataSource::CommitTransaction();
+}
+
+/************************************************************************/
+/*                     RollbackTransaction()                            */
+/************************************************************************/
+
+OGRErr GDALGeoPackageDataset::RollbackTransaction()
+
+{
+    if( nSoftTransactionLevel == 1 )
+    {
+        FlushMetadata();
+        for( int i = 0; i < m_nLayers; i++ )
+        {
+            m_papoLayers[i]->RunDeferredCreationIfNecessary();
+            m_papoLayers[i]->CreateSpatialIndexIfNecessary();
+            m_papoLayers[i]->ResetReading();
+        }
+    }
+
+    return OGRSQLiteBaseDataSource::RollbackTransaction();
+}
+
+/************************************************************************/
+/*                       GetGeometryTypeString()                        */
+/************************************************************************/
+
+const char* GDALGeoPackageDataset::GetGeometryTypeString(OGRwkbGeometryType eType)
+{
+    const char* pszGPKGGeomType = OGRToOGCGeomType(eType);
+    if( EQUAL(pszGPKGGeomType, "GEOMETRYCOLLECTION") &&
+        CSLTestBoolean(CPLGetConfigOption("OGR_GPKG_GEOMCOLLECTION", "YES")) )
+    {
+        pszGPKGGeomType = "GEOMCOLLECTION";
+    }
+    return pszGPKGGeomType;
+}
+
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedriver.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedriver.cpp
index efb3dfe..ac7a8ab 100644
--- a/ogr/ogrsf_frmts/gpkg/ogrgeopackagedriver.cpp
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagedriver.cpp
@@ -32,35 +32,60 @@
 // g++ -g -Wall -fPIC -shared -o ogr_geopackage.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/gpkg ogr/ogrsf_frmts/gpkg/*.c* -L. -lgdal 
 
 
+/* "GP10" in ASCII bytes */
+static const char aGpkgId[4] = {0x47, 0x50, 0x31, 0x30};
+// static const size_t szGpkgIdPos = 68;
 
 /************************************************************************/
-/*                        ~OGRGeoPackageDriver()                         */
+/*                       OGRGeoPackageDriverIdentify()                  */
 /************************************************************************/
 
-OGRGeoPackageDriver::~OGRGeoPackageDriver()
+static int OGRGeoPackageDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-} 
+    if( EQUALN(poOpenInfo->pszFilename, "GPKG:", 5) )
+        return TRUE;
 
+    /* Requirement 3: File name has to end in "gpkg" */
+    /* http://opengis.github.io/geopackage/#_file_extension_name */
+    if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "GPKG") )
+        return FALSE;
 
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
+    /* Check that the filename exists and is a file */
+    if( poOpenInfo->fpL == NULL)
+        return FALSE;
 
-const char *OGRGeoPackageDriver::GetName()
-{
-    return "GPKG";
-}
+    if ( poOpenInfo->nHeaderBytes < 16 ||
+        strncmp( (const char*)poOpenInfo->pabyHeader, "SQLite format 3", 15 ) != 0 )
+    {
+        return FALSE;
+    }
 
+    /* Requirement 2: A GeoPackage SHALL contain 0x47503130 ("GP10" in ASCII) */
+    /* in the application id */
+    /* http://opengis.github.io/geopackage/#_file_format */
+    /* Be tolerant since some datasets don't actually follow that requirement */
+    if( poOpenInfo->nHeaderBytes < 68 + 4 ||
+        memcmp(poOpenInfo->pabyHeader + 68, aGpkgId, 4) != 0 )
+    {
+        CPLError( CE_Warning, CPLE_AppDefined, "GPKG: bad application_id on '%s'",
+                  poOpenInfo->pszFilename);
+    }
+
+    return TRUE;
+}
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGeoPackageDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRGeoPackageDriverOpen( GDALOpenInfo* poOpenInfo )
 {
-    OGRGeoPackageDataSource   *poDS = new OGRGeoPackageDataSource();
+    if( !OGRGeoPackageDriverIdentify(poOpenInfo) )
+        return NULL;
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    GDALGeoPackageDataset   *poDS = new GDALGeoPackageDataset();
+
+    if( !poDS->Open( poOpenInfo ) )
     {
         delete poDS;
         poDS = NULL;
@@ -69,28 +94,21 @@ OGRDataSource *OGRGeoPackageDriver::Open( const char * pszFilename, int bUpdate
     return poDS;
 }
 
-
 /************************************************************************/
-/*                                CreateDataSource()                    */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRGeoPackageDriver::CreateDataSource( const char * pszFilename, char **papszOptions )
+static GDALDataset* OGRGeoPackageDriverCreate( const char * pszFilename,
+                                            int nXSize,
+                                            int nYSize,
+                                            int nBands,
+                                            GDALDataType eDT,
+                                            char **papszOptions )
 {
-	/* First, ensure there isn't any such file yet. */
-    VSIStatBufL sStatBuf;
-
-    if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "A file system object called '%s' already exists.",
-                  pszFilename );
+    GDALGeoPackageDataset   *poDS = new GDALGeoPackageDataset();
 
-        return NULL;
-    }
-	
-    OGRGeoPackageDataSource   *poDS = new OGRGeoPackageDataSource();
-
-    if( !poDS->Create( pszFilename, papszOptions ) )
+    if( !poDS->Create( pszFilename, nXSize, nYSize,
+                       nBands, eDT, papszOptions ) )
     {
         delete poDS;
         poDS = NULL;
@@ -100,40 +118,126 @@ OGRDataSource *OGRGeoPackageDriver::CreateDataSource( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                         DeleteDataSource()                           */
-/************************************************************************/
-
-OGRErr OGRGeoPackageDriver::DeleteDataSource( const char *pszFilename )
-{
-    if (VSIUnlink( pszFilename ) == 0)
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                         TestCapability()                             */
+/*                               Delete()                               */
 /************************************************************************/
 
-int OGRGeoPackageDriver::TestCapability( const char * pszCap )
+static CPLErr OGRGeoPackageDriverDelete( const char *pszFilename )
 
 {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
+    if( VSIUnlink(pszFilename) == 0 )
+        return CE_None;
     else
-        return FALSE;
+        return CE_Failure;
 }
 
-
 /************************************************************************/
 /*                         RegisterOGRGeoPackage()                       */
 /************************************************************************/
 
 void RegisterOGRGeoPackage()
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGeoPackageDriver );
-}
-
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "GPKG" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "GPKG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GeoPackage" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gpkg" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_geopackage.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" );
+
+#define COMPRESSION_OPTIONS \
+"  <Option name='TILE_FORMAT' type='string-select' description='Format to use to create tiles' default='PNG_JPEG'>" \
+"    <Value>PNG_JPEG</Value>" \
+"    <Value>PNG</Value>" \
+"    <Value>PNG8</Value>" \
+"    <Value>JPEG</Value>" \
+"    <Value>WEBP</Value>" \
+"  </Option>" \
+"  <Option name='QUALITY' type='int' min='1' max='100' description='Quality for JPEG and WEBP tiles' default='75'/>" \
+"  <Option name='ZLEVEL' type='int' min='1' max='9' description='DEFLATE compression level for PNG tiles' default='6'/>" \
+"  <Option name='DITHER' type='boolean' description='Whether to apply Floyd-Steinberg dithering (for TILE_FORMAT=PNG8)' default='NO'/>"
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, "<OpenOptionList>"
+"  <Option name='TABLE' type='string' description='Name of tile user-table'/>"
+"  <Option name='ZOOM_LEVEL' type='integer' description='Zoom level of full resolution. If not specified, maximum non-empty zoom level'/>"
+"  <Option name='BAND_COUNT' type='int' min='1' max='4' description='Number of raster bands' default='4'/>"
+"  <Option name='MINX' type='float' description='Minimum X of area of interest'/>"
+"  <Option name='MINY' type='float' description='Minimum Y of area of interest'/>"
+"  <Option name='MAXX' type='float' description='Maximum X of area of interest'/>"
+"  <Option name='MAXY' type='float' description='Maximum Y of area of interest'/>"
+"  <Option name='USE_TILE_EXTENT' type='boolean' description='Use tile extent of content to determine area of interest' default='NO'/>"
+"  <Option name='WHERE' type='string' description='SQL WHERE clause to be appended to tile requests'/>"
+COMPRESSION_OPTIONS
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList>"
+"  <Option name='RASTER_TABLE' type='string' description='Name of tile user table'/>"
+"  <Option name='APPEND_SUBDATASET' type='boolean' description='Set to YES to add a new tile user table to an existing GeoPackage instead of replacing it' default='NO'/>"
+"  <Option name='RASTER_IDENTIFIER' type='string' description='Human-readable identifier (e.g. short name)'/>"
+"  <Option name='RASTER_DESCRIPTION' type='string' description='Human-readable description'/>"
+"  <Option name='BLOCKSIZE' type='int' description='Block size in pixels' default='256' max='4096'/>"
+"  <Option name='BLOCKXSIZE' type='int' description='Block width in pixels' default='256' max='4096'/>"
+"  <Option name='BLOCKYSIZE' type='int' description='Block height in pixels' default='256' max='4096'/>"
+COMPRESSION_OPTIONS
+"  <Option name='TILING_SCHEME' type='string-select' description='Which tiling scheme to use' default='CUSTOM'>"
+"    <Value>CUSTOM</Value>"
+"    <Value>GoogleCRS84Quad</Value>"
+"    <Value>GoogleMapsCompatible</Value>"
+"    <Value>InspireCRS84Quad</Value>"
+"    <Value>PseudoTMS_GlobalGeodetic</Value>"
+"    <Value>PseudoTMS_GlobalMercator</Value>"
+"  </Option>"
+"  <Option name='ZOOM_LEVEL_STRATEGY' type='string-select' description='Strategy to determine zoom level. Only used for TILING_SCHEME != CUSTOM' default='AUTO'>"
+"    <Value>AUTO</Value>"
+"    <Value>LOWER</Value>"
+"    <Value>UPPER</Value>"
+"  </Option>"
+"  <Option name='RESAMPLING' type='string-select' description='Resampling algorithm. Only used for TILING_SCHEME != CUSTOM' default='BILINEAR'>"
+"    <Value>NEAREST</Value>"
+"    <Value>BILINEAR</Value>"
+"    <Value>CUBIC</Value>"
+"    <Value>CUBICSPLINE</Value>"
+"    <Value>LANCZOS</Value>"
+"    <Value>MODE</Value>"
+"    <Value>AVERAGE</Value>"
+"  </Option>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column.' default='geom' deprecated_alias='GEOMETRY_COLUMN'/>"
+"  <Option name='GEOMETRY_NULLABLE' type='boolean' description='Whether the values of the geometry column can be NULL' default='YES'/>"
+"  <Option name='FID' type='string' description='Name of the FID column to create' default='fid'/>"
+"  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+"  <Option name='PRECISION' type='boolean' description='Whether text fields created should keep the width' default='YES'/>"
+"  <Option name='TRUNCATE_FIELDS' type='boolean' description='Whether to truncate text content that exceeds maximum width' default='NO'/>"
+"  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
+"  <Option name='IDENTIFIER' type='string' description='Identifier of the layer, as put in the contents table'/>"
+"  <Option name='DESCRIPTION' type='string' description='Description of the layer, as put in the contents table'/>"
+"</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Binary" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->pfnOpen = OGRGeoPackageDriverOpen;
+        poDriver->pfnIdentify = OGRGeoPackageDriverIdentify;
+        poDriver->pfnCreate = OGRGeoPackageDriverCreate;
+        poDriver->pfnCreateCopy = GDALGeoPackageDataset::CreateCopy;
+        poDriver->pfnDelete = OGRGeoPackageDriverDelete;
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp
index 6886bbb..0e13c57 100644
--- a/ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagelayer.cpp
@@ -30,1101 +30,248 @@
 
 #include "ogr_geopackage.h"
 #include "ogrgeopackageutility.h"
-
-//----------------------------------------------------------------------
-// SaveExtent()
-// 
-// Write the current contents of the layer envelope down to the
-// gpkg_contents metadata table.
-//
-OGRErr OGRGeoPackageLayer::SaveExtent()
-{
-    if ( !m_poDS->IsUpdatable() || ! m_bExtentChanged || ! m_poExtent ) 
-        return OGRERR_NONE;
-
-    sqlite3* poDb = m_poDS->GetDatabaseHandle();
-
-    if ( ! poDb ) return OGRERR_FAILURE;
-
-    char *pszSQL = sqlite3_mprintf(
-                "UPDATE gpkg_contents SET "
-                "min_x = %g, min_y = %g, "
-                "max_x = %g, max_y = %g "
-                "WHERE table_name = '%q' AND "
-                "Lower(data_type) = 'features'",
-                m_poExtent->MinX, m_poExtent->MinY,
-                m_poExtent->MaxX, m_poExtent->MaxY,
-                m_pszTableName);
-
-    OGRErr err = SQLCommand(poDb, pszSQL);
-    sqlite3_free(pszSQL);
-    m_bExtentChanged = FALSE;
-    
-    return err;
-}
-
-//----------------------------------------------------------------------
-// UpdateExtent()
-// 
-// Expand the layer envelope if necessary to reflect the bounds
-// of new features being added to the layer.
-//
-OGRErr OGRGeoPackageLayer::UpdateExtent( const OGREnvelope *poExtent )
-{
-    if ( ! m_poExtent )
-    {
-        m_poExtent = new OGREnvelope( *poExtent );
-    }
-    m_poExtent->Merge( *poExtent );
-    m_bExtentChanged = TRUE;
-    return OGRERR_NONE;
-}
-
-//----------------------------------------------------------------------
-// BuildColumns()
-// 
-// Save a list of columns (fid, geometry, attributes) suitable
-// for use in a SELECT query that retrieves all fields.
-//
-OGRErr OGRGeoPackageLayer::BuildColumns()
-{
-    if ( ! m_poFeatureDefn || ! m_pszFidColumn )
-    {
-        return OGRERR_FAILURE;
-    }
-
-    /* Always start with a primary key */
-    CPLString soColumns = m_pszFidColumn;
-
-    /* Add a geometry column if there is one (just one) */
-    if ( m_poFeatureDefn->GetGeomFieldCount() )
-    {
-        soColumns += ", ";
-        soColumns += m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
-    }
-
-    /* Add all the attribute columns */
-    for( int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++ )
-    {
-        soColumns += ", ";
-        soColumns += m_poFeatureDefn->GetFieldDefn(i)->GetNameRef();
-    }
-
-    m_soColumns = soColumns;    
-    return OGRERR_NONE;    
-}
-
-//----------------------------------------------------------------------
-// ReadFeature()
-// 
-// Convert a row in a statement into an OGRFeature.
-//
-OGRErr OGRGeoPackageLayer::ReadFeature( sqlite3_stmt *poQuery, OGRFeature **ppoFeature )
-{
-    int iColOffset = 0;
-    
-    if ( ! m_poFeatureDefn )
-        return OGRERR_FAILURE;
-
-    OGRFeature *poFeature = new OGRFeature( m_poFeatureDefn );
-    
-    /* Primary key is always first column in our SQL call */
-    poFeature->SetFID(sqlite3_column_int(poQuery, iColOffset++));
-    
-    /* If a geometry column exists, it's next */
-    /* Add a geometry column if there is one (just the first one) */
-    if ( m_poFeatureDefn->GetGeomFieldCount() )
-    {
-        if ( sqlite3_column_type(poQuery, iColOffset) != SQLITE_NULL )
-        {
-            OGRSpatialReference* poSrs = m_poFeatureDefn->GetGeomFieldDefn(0)->GetSpatialRef();
-            int iGpkgSize = sqlite3_column_bytes(poQuery, iColOffset);
-            GByte *pabyGpkg = (GByte *)sqlite3_column_blob(poQuery, iColOffset);
-            OGRGeometry *poGeom = GPkgGeometryToOGR(pabyGpkg, iGpkgSize, poSrs);
-            if ( ! poGeom )
-            {
-                delete poFeature;
-                CPLError( CE_Failure, CPLE_AppDefined, "Unable to read geometry");
-                return OGRERR_FAILURE;
-            }
-            poFeature->SetGeometryDirectly( poGeom );
-        }
-        iColOffset++;
-    }
-    
-    /* Read all the attribute columns */
-    for( int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++ )
-    {
-        int j = iColOffset+i;
-
-        switch(sqlite3_column_type(poQuery, j))
-        {
-            case SQLITE_INTEGER:
-            {
-                int iVal = sqlite3_column_int(poQuery, j);
-                poFeature->SetField(i, iVal);
-                break;
-            }
-            case SQLITE_FLOAT:
-            {
-                double dVal = sqlite3_column_double(poQuery, j);
-                poFeature->SetField(i, dVal);
-                break;
-            }
-            case SQLITE_BLOB:
-            {
-                int iBlobSize = sqlite3_column_bytes(poQuery, j);
-                GByte *pabyBlob = (GByte *)sqlite3_column_blob(poQuery, j);
-                poFeature->SetField(i, iBlobSize, pabyBlob);
-                break;
-            }
-            case SQLITE_TEXT:
-            {
-                const char *pszVal = (const char *)sqlite3_column_text(poQuery, j);
-                poFeature->SetField(i, pszVal);
-                break;
-            }
-            default: /* SQLITE_NULL */
-            {
-                /* Do nothing for NULL fields */
-                break;
-            }
-        }
-    }
-    
-    /* Pass result back to the caller */
-    *ppoFeature = poFeature;
-
-    return OGRERR_NONE;
-}
-
-
-
-//----------------------------------------------------------------------
-// IsGeomFieldSet()
-// 
-// Utility method to determine if there is a non-Null geometry
-// in an OGRGeometry.
-//
-OGRBoolean OGRGeoPackageLayer::IsGeomFieldSet( OGRFeature *poFeature )
-{
-    if ( poFeature->GetDefnRef()->GetGeomFieldCount() && 
-         poFeature->GetGeomFieldRef(0) )
-    {
-        return TRUE;        
-    }
-    else
-    {
-        return FALSE;
-    }
-}
-
-OGRErr OGRGeoPackageLayer::FeatureBindParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt, int *pnColCount )
-{
-    int nColCount = 1;
-    int err;
-    
-    if ( ! (poFeature && poStmt && pnColCount) )
-        return OGRERR_FAILURE;
-
-    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
-    
-    /* Bind data values to the statement, here bind the blob for geometry */
-    if ( poFeatureDefn->GetGeomFieldCount() )
-    {
-        GByte *pabyWkb = NULL;
-
-        /* Non-NULL geometry */
-        if ( poFeature->GetGeomFieldRef(0) )
-        {
-            size_t szWkb;
-            pabyWkb = GPkgGeometryFromOGR(poFeature->GetGeomFieldRef(0), m_iSrs, &szWkb);
-            err = sqlite3_bind_blob(poStmt, nColCount++, pabyWkb, szWkb, CPLFree);
-        }
-        /* NULL geometry */
-        else
-        {
-            err = sqlite3_bind_null(poStmt, nColCount++);
-        }
-        if ( err != SQLITE_OK )
-        {
-            if ( pabyWkb )
-                CPLFree(pabyWkb);
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "failed to bind geometry to statement");        
-            return OGRERR_FAILURE;            
-        }
-    }
-
-    /* Bind the attributes using appropriate SQLite data types */
-    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
-    {
-        OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i); 
-        
-        if( poFeature->IsFieldSet(i) )
-        {
-            switch(SQLiteFieldFromOGR(poFieldDefn->GetType()))
-            {
-                case SQLITE_INTEGER:
-                {
-                    err = sqlite3_bind_int(poStmt, nColCount++, poFeature->GetFieldAsInteger(i));
-                    break;
-                }
-                case SQLITE_FLOAT:
-                {
-                    err = sqlite3_bind_double(poStmt, nColCount++, poFeature->GetFieldAsDouble(i));
-                    break;
-                }
-                case SQLITE_BLOB:
-                {
-                    int szBlob;
-                    GByte *pabyBlob = poFeature->GetFieldAsBinary(i, &szBlob);
-                    err = sqlite3_bind_blob(poStmt, nColCount++, pabyBlob, szBlob, NULL);
-                    break;
-                }
-                default:
-                {
-                    const char *pszVal = poFeature->GetFieldAsString(i);
-                    err = sqlite3_bind_text(poStmt, nColCount++, pszVal, strlen(pszVal), SQLITE_TRANSIENT);
-                    break;
-                }            
-            }            
-        }
-        else
-        {
-            err = sqlite3_bind_null(poStmt, nColCount++);
-        }
-    }
-    
-    *pnColCount = nColCount;
-    return OGRERR_NONE;
-}
-
-//----------------------------------------------------------------------
-// FeatureBindUpdateParameters()
-// 
-// Selectively bind the values of an OGRFeature to a prepared 
-// statement, prior to execution. Carefully binds exactly the 
-// same parameters that have been set up by FeatureGenerateUpdateSQL()
-// as bindable.
-//
-OGRErr OGRGeoPackageLayer::FeatureBindUpdateParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt )
-{
-
-    int nColCount;
-    OGRErr err = FeatureBindParameters( poFeature, poStmt, &nColCount );
-    if ( err != OGRERR_NONE )
-        return err;
-
-    /* Bind the FID to the "WHERE" clause */
-    err = sqlite3_bind_int(poStmt, nColCount, poFeature->GetFID());    
-    if ( err != SQLITE_OK )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "failed to bind FID '%ld' to statement", poFeature->GetFID());
-        return OGRERR_FAILURE;       
-    }
-    
-    return OGRERR_NONE;
-}
-
-
-//----------------------------------------------------------------------
-// FeatureBindInsertParameters()
-// 
-// Selectively bind the values of an OGRFeature to a prepared 
-// statement, prior to execution. Carefully binds exactly the 
-// same parameters that have been set up by FeatureGenerateInsertSQL()
-// as bindable.
-//
-OGRErr OGRGeoPackageLayer::FeatureBindInsertParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt )
-{    
-    int nColCount;
-    return FeatureBindParameters( poFeature, poStmt, &nColCount );
-}   
-
-
-//----------------------------------------------------------------------
-// FeatureGenerateInsertSQL()
-// 
-// Build a SQL INSERT statement that references all the columns in
-// the OGRFeatureDefn, then prepare it for repeated use in a prepared
-// statement. All statements start off with geometry (if it exists)
-// then reference each column in the order it appears in the OGRFeatureDefn.
-// FeatureBindParameters operates on the expectation of this
-// column ordering.
-//
-CPLString OGRGeoPackageLayer::FeatureGenerateInsertSQL( OGRFeature *poFeature )
-{
-    OGRBoolean bNeedComma = FALSE;
-    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
-
-    /* Set up our SQL string basics */
-    CPLString osSQLFront;
-    osSQLFront.Printf("INSERT INTO %s ( ", m_pszTableName);
-
-    CPLString osSQLBack;
-    osSQLBack = ") VALUES (";
-    
-    if ( poFeatureDefn->GetGeomFieldCount() )
-    {
-        osSQLFront += poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
-        osSQLBack += "?";
-        bNeedComma = TRUE;
-    }
-
-    /* Add attribute column names (except FID) to the SQL */
-    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
-    {
-        if( !bNeedComma )
-        {
-            bNeedComma = TRUE;
-        }
-        else 
-        {
-            osSQLFront += ", ";
-            osSQLBack += ", ";
-        }
-
-        osSQLFront += poFeatureDefn->GetFieldDefn(i)->GetNameRef();
-        osSQLBack += "?";        
-    }
-    
-    osSQLBack += ")";
-
-    return osSQLFront + osSQLBack;
-}
-
-
-//----------------------------------------------------------------------
-// FeatureGenerateUpdateSQL()
-// 
-// Build a SQL UPDATE statement that references all the columns in
-// the OGRFeatureDefn, then prepare it for repeated use in a prepared
-// statement. All statements start off with geometry (if it exists)
-// then reference each column in the order it appears in the OGRFeatureDefn.
-// FeatureBindParameters operates on the expectation of this
-// column ordering.
-
-//
-CPLString OGRGeoPackageLayer::FeatureGenerateUpdateSQL( OGRFeature *poFeature )
-{
-    OGRBoolean bNeedComma = FALSE;
-    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
-
-    /* Set up our SQL string basics */
-    CPLString osUpdate;
-    osUpdate.Printf("UPDATE %s SET ", m_pszTableName);
-    
-    if ( poFeatureDefn->GetGeomFieldCount() > 0 )
-    {
-        osUpdate += poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
-        osUpdate += "=?";
-        bNeedComma = TRUE;
-    }
-
-    /* Add attribute column names (except FID) to the SQL */
-    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
-    {
-        if( !bNeedComma )
-            bNeedComma = TRUE;
-        else 
-            osUpdate += ", ";
-
-        osUpdate += poFeatureDefn->GetFieldDefn(i)->GetNameRef();
-        osUpdate += "=?";
-    }
-    
-    CPLString osWhere;
-    osWhere.Printf(" WHERE %s = ?", m_pszFidColumn);
-
-    return osUpdate + osWhere;
-}
-
-
-//----------------------------------------------------------------------
-// ReadTableDefinition()
-// 
-// Initialization routine. Read all the metadata about a table, 
-// starting from just the table name. Reads information from GPKG
-// metadata tables and from SQLite table metadata. Uses it to 
-// populate OGRSpatialReference information and OGRFeatureDefn objects, 
-// among others.
-//
-OGRErr OGRGeoPackageLayer::ReadTableDefinition()
-{
-    OGRErr err;
-    SQLResult oResultTable;
-    SQLResult oResultContents;
-    SQLResult oResultGeomCols;
-    char* pszSQL;
-    OGRBoolean bReadExtent = FALSE;
-    sqlite3* poDb = m_poDS->GetDatabaseHandle();
-
-    /* Check that the table name is registered in gpkg_contents */
-    pszSQL = sqlite3_mprintf(
-                "SELECT table_name, data_type, identifier, "
-                "description, min_x, min_y, max_x, max_y, srs_id "
-                "FROM gpkg_contents "
-                "WHERE table_name = '%q' AND "
-                "Lower(data_type) = 'features'",
-                m_pszTableName);
-                
-    err = SQLQuery(poDb, pszSQL, &oResultContents);
-    sqlite3_free(pszSQL);
-    
-    /* gpkg_contents query has to work */
-    /* gpkg_contents.table_name is supposed to be unique */
-    if ( err != OGRERR_NONE || oResultContents.nRowCount != 1 )
-    {
-        if ( err != OGRERR_NONE )
-            CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultContents.pszErrMsg );
-        else if ( oResultContents.nRowCount != 1 )
-            CPLError( CE_Failure, CPLE_AppDefined, "layer '%s' is not registered in gpkg_contents", m_pszTableName );
-        else
-            CPLError( CE_Failure, CPLE_AppDefined, "error reading gpkg_contents" );
-            
-        SQLResultFree(&oResultContents);
-        return OGRERR_FAILURE;
-    }
-
-    const char *pszMinX = SQLResultGetValue(&oResultContents, 4, 0);
-    const char *pszMinY = SQLResultGetValue(&oResultContents, 5, 0);
-    const char *pszMaxX = SQLResultGetValue(&oResultContents, 6, 0);
-    const char *pszMaxY = SQLResultGetValue(&oResultContents, 7, 0);
-    
-	/* All the extrema have to be non-NULL for this to make sense */
-    OGREnvelope oExtent;
-    if ( pszMinX && pszMinY && pszMaxX && pszMaxY )
-    {
-        oExtent.MinX = atof(pszMinX);
-        oExtent.MinY = atof(pszMinY);
-        oExtent.MaxX = atof(pszMaxX);
-        oExtent.MaxY = atof(pszMaxY);
-        bReadExtent = TRUE;
-    }
-
-    /* Done with info from gpkg_contents now */
-    SQLResultFree(&oResultContents);
-
-    /* Check that the table name is registered in gpkg_geometry_columns */
-    pszSQL = sqlite3_mprintf(
-                "SELECT table_name, column_name, "
-                "geometry_type_name, srs_id, z "
-                "FROM gpkg_geometry_columns "
-                "WHERE table_name = '%q'",
-                m_pszTableName);
-                
-    err = SQLQuery(poDb, pszSQL, &oResultGeomCols);
-    sqlite3_free(pszSQL);
-
-    /* gpkg_geometry_columns query has to work */
-    /* gpkg_geometry_columns.table_name is supposed to be unique */
-    if ( err != OGRERR_NONE || oResultGeomCols.nRowCount != 1 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultGeomCols.pszErrMsg );
-        SQLResultFree(&oResultGeomCols);
-        return OGRERR_FAILURE;
-    }
-
-    /* Use the "PRAGMA TABLE_INFO()" call to get table definition */
-    /*  #|name|type|nullable|default|pk */
-    /*  0|id|integer|0||1 */
-    /*  1|name|varchar|0||0 */    
-    pszSQL = sqlite3_mprintf("pragma table_info('%q')", m_pszTableName);
-    err = SQLQuery(poDb, pszSQL, &oResultTable);
-    sqlite3_free(pszSQL);
-
-    if ( err != OGRERR_NONE || oResultTable.nRowCount == 0 )
-    {
-        if( oResultTable.pszErrMsg != NULL )
-            CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultTable.pszErrMsg );
-        else
-            CPLError( CE_Failure, CPLE_AppDefined, "Cannot find table %s", m_pszTableName );
-
-        SQLResultFree(&oResultGeomCols);
-        SQLResultFree(&oResultTable);
-        return OGRERR_FAILURE;
-    }
-    
-    /* Populate feature definition from table description */
-    m_poFeatureDefn = new OGRFeatureDefn( m_pszTableName );
-    m_poFeatureDefn->Reference();
-    
-    const char *pszGeomColsType = SQLResultGetValue(&oResultGeomCols, 2, 0);
-    int iSrsId = SQLResultGetValueAsInteger(&oResultGeomCols, 3, 0);
-    int bHasZ = SQLResultGetValueAsInteger(&oResultGeomCols, 4, 0);
-    int iRecord;
-    OGRBoolean bFidFound = FALSE;
-    m_iSrs = iSrsId;
-    
-    for ( iRecord = 0; iRecord < oResultTable.nRowCount; iRecord++ )
-    {
-        const char *pszName = SQLResultGetValue(&oResultTable, 1, iRecord);
-        const char *pszType = SQLResultGetValue(&oResultTable, 2, iRecord);
-        OGRBoolean bFid = SQLResultGetValueAsInteger(&oResultTable, 5, iRecord);
-        OGRFieldType oType = GPkgFieldToOGR(pszType);
-
-        /* Not a standard field type... */
-        if ( oType > OFTMaxType )
-        {
-            /* Maybe it's a geometry type? */
-            OGRwkbGeometryType oGeomType = GPkgGeometryTypeToWKB(pszType, bHasZ);
-            if ( oGeomType != wkbNone )
-            {
-                OGRwkbGeometryType oGeomTypeGeomCols = GPkgGeometryTypeToWKB(pszGeomColsType, bHasZ);
-                /* Enforce consistency between table and metadata */
-                if ( oGeomType != oGeomTypeGeomCols )
-                {
-                    CPLError(CE_Failure, CPLE_AppDefined, 
-                             "geometry column type in '%s.%s' is not consistent with type in gpkg_geometry_columns", 
-                             m_pszTableName, pszName);
-                    SQLResultFree(&oResultTable);
-                    SQLResultFree(&oResultGeomCols);
-                    return OGRERR_FAILURE;
-                }
-                
-                if ( m_poFeatureDefn->GetGeomFieldCount() == 0 )
-                {
-                    OGRGeomFieldDefn oGeomField(pszName, oGeomType);
-                    m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
-                }
-                else if ( m_poFeatureDefn->GetGeomFieldCount() == 1 )
-                {
-                    m_poFeatureDefn->GetGeomFieldDefn(0)->SetType(oGeomType);
-                    m_poFeatureDefn->GetGeomFieldDefn(0)->SetName(pszName);
-                    
-                    /* Read the SRS */
-                    OGRSpatialReference *poSRS = m_poDS->GetSpatialRef(iSrsId);
-                    if ( poSRS )
-                    {
-                        m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
-                        poSRS->Dereference();
-                    }
-                }
-                else
-                {
-                    CPLError(CE_Failure, CPLE_AppDefined, 
-                             "table '%s' has multiple geometry fields? not legal in gpkg", 
-                             m_pszTableName);
-                    SQLResultFree(&oResultTable);
-                    SQLResultFree(&oResultGeomCols);
-                    return OGRERR_FAILURE;
-                }
-
-            }
-            else
-            {
-                // CPLError( CE_Failure, CPLE_AppDefined, "invalid field type '%s'", pszType );
-                // SQLResultFree(&oResultTable);
-                CPLError(CE_Warning, CPLE_AppDefined, 
-                         "geometry column '%s' of type '%s' ignored", pszName, pszType);
-            }
-            
-        }
-        else
-        {
-            /* Is this the FID column? */
-            if ( bFid )
-            {
-                bFidFound = TRUE;
-                m_pszFidColumn = CPLStrdup(pszName);
-            }
-            else
-            {
-                OGRFieldDefn oField(pszName, oType);
-                m_poFeatureDefn->AddFieldDefn(&oField);
-            }
-        }
-    }
-
-    /* Wait, we didn't find a FID? */
-    /* Game over, all valid tables must have a FID */
-    if ( ! bFidFound )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined, 
-                 "no primary key defined for table '%s'", m_pszTableName);
-        return OGRERR_FAILURE;
-        
-    }
-
-    if ( bReadExtent )
-    {
-        m_poExtent = new OGREnvelope(oExtent);
-    }
-
-    SQLResultFree(&oResultTable);
-    SQLResultFree(&oResultGeomCols);
-
-    /* Update the columns string */
-    BuildColumns();
-
-    return OGRERR_NONE;
-}
-
+#include "ogr_p.h"
 
 /************************************************************************/
 /*                      OGRGeoPackageLayer()                            */
 /************************************************************************/
 
-OGRGeoPackageLayer::OGRGeoPackageLayer(
-                    OGRGeoPackageDataSource *poDS,
-                    const char * pszTableName)
+OGRGeoPackageLayer::OGRGeoPackageLayer(GDALGeoPackageDataset *poDS) : m_poDS(poDS)
 {
-    m_pszTableName = CPLStrdup(pszTableName);
-    m_pszFidColumn = NULL;
-    m_iSrs = 0;
-    m_poDS = poDS;
-    m_poExtent = NULL;
-    m_bExtentChanged = FALSE;
     m_poFeatureDefn = NULL;
+    iNextShapeId = 0;
     m_poQueryStatement = NULL;
-    m_poUpdateStatement = NULL;
-    m_poInsertStatement = NULL;
-    m_poFidStatement = NULL;
-    m_soColumns = "";
-    m_soFilter = "";
+    bDoStep = TRUE;
+    m_pszFidColumn = NULL;
+    iFIDCol = -1;
+    iGeomCol = -1;
+    panFieldOrdinals = NULL;
 }
 
-
 /************************************************************************/
 /*                      ~OGRGeoPackageLayer()                           */
 /************************************************************************/
 
 OGRGeoPackageLayer::~OGRGeoPackageLayer()
 {
-    /* Save metadata back to the database */
-    SaveExtent();
 
-    /* Clean up resources in memory */
-    if ( m_pszTableName )
-        CPLFree( m_pszTableName );
-    
-    if ( m_pszFidColumn )
-        CPLFree( m_pszFidColumn );
-    
-    if ( m_poExtent )
-        delete m_poExtent;
-    
+    CPLFree( m_pszFidColumn );
+
     if ( m_poQueryStatement )
         sqlite3_finalize(m_poQueryStatement);
 
-    if ( m_poUpdateStatement )
-        sqlite3_finalize(m_poUpdateStatement);
+    CPLFree(panFieldOrdinals);
 
-    if ( m_poInsertStatement )
-        sqlite3_finalize(m_poInsertStatement);
-    
-    if ( m_poFidStatement )
-        sqlite3_finalize(m_poFidStatement);
-        
     if ( m_poFeatureDefn )
         m_poFeatureDefn->Release();
 }
 
 
 /************************************************************************/
-/*                      CreateField()                                   */
+/*                            ResetReading()                            */
 /************************************************************************/
 
-OGRErr OGRGeoPackageLayer::CreateField( OGRFieldDefn *poField,
-                                        CPL_UNUSED int bApproxOK )
-{
-    if( !m_poDS->IsUpdatable() )
-    {
-        return OGRERR_FAILURE;
-    }
-    
-    if ( ! m_poFeatureDefn || ! m_pszTableName )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined, 
-                 "feature definition or table name is null");
-        return OGRERR_FAILURE;
-    }
-
-    OGRErr err = m_poDS->AddColumn(m_pszTableName, 
-                                   poField->GetNameRef(),
-                                   GPkgFieldFromOGR(poField->GetType()));
+void OGRGeoPackageLayer::ResetReading()
 
-    if ( err != OGRERR_NONE )
-        return err;
-    
-    m_poFeatureDefn->AddFieldDefn( poField );
-    ResetReading();
-    return OGRERR_NONE;
+{
+    ClearStatement();
+    iNextShapeId = 0;
 }
 
-
 /************************************************************************/
-/*                      CreateFeature()                                 */
+/*                           ClearStatement()                           */
 /************************************************************************/
 
-OGRErr OGRGeoPackageLayer::CreateFeature( OGRFeature *poFeature )
-{
-    if( !m_poDS->IsUpdatable() )
-    {
-        return OGRERR_FAILURE;
-    }
+void OGRGeoPackageLayer::ClearStatement()
 
-    if ( ! m_poFeatureDefn || ! m_pszTableName )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined, 
-                 "feature definition or table name is null");
-        return OGRERR_FAILURE;
-    }
-
-    if( NULL == poFeature )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "NULL pointer to OGRFeature passed to CreateFeature()" );
-        return OGRERR_FAILURE;
-    }
-
-    if ( ! m_poInsertStatement ) 
-    {
-        /* Construct a SQL INSERT statement from the OGRFeature */
-        /* Only work with fields that are set */
-        /* Do not stick values into SQL, use placeholder and bind values later */    
-        CPLString osCommand = FeatureGenerateInsertSQL(poFeature);
-        
-        /* Prepare the SQL into a statement */
-        sqlite3 *poDb = m_poDS->GetDatabaseHandle();
-        int err = sqlite3_prepare_v2(poDb, osCommand, -1, &m_poInsertStatement, NULL);
-        if ( err != SQLITE_OK )
-        {
-            m_poInsertStatement = NULL;
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "failed to prepare SQL: %s", osCommand.c_str());        
-            return OGRERR_FAILURE;
-        }        
-    }
-    
-    /* Bind values onto the statement now */
-    OGRErr errOgr = FeatureBindInsertParameters(poFeature, m_poInsertStatement);
-    if ( errOgr != OGRERR_NONE )
-        return errOgr;
-
-    /* From here execute the statement and check errors */
-    int err = sqlite3_step(m_poInsertStatement);
-    if ( ! (err == SQLITE_OK || err == SQLITE_DONE) )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "failed to execute insert");
-        return OGRERR_FAILURE; 
-    }
-
-    sqlite3_reset(m_poInsertStatement);
-    sqlite3_clear_bindings(m_poInsertStatement);
-
-    /* Update the layer extents with this new object */
-    if ( IsGeomFieldSet(poFeature) )
-    {
-        OGREnvelope oEnv;
-        poFeature->GetGeomFieldRef(0)->getEnvelope(&oEnv);
-        UpdateExtent(&oEnv);
-    }
-
-    /* Read the latest FID value */
-    int iFid;
-    if ( (iFid = sqlite3_last_insert_rowid(m_poDS->GetDatabaseHandle())) )
-    {
-        poFeature->SetFID(iFid);
-    }
-    else
+{
+    if( m_poQueryStatement != NULL )
     {
-        poFeature->SetFID(OGRNullFID);
+        CPLDebug( "GPKG", "finalize %p", m_poQueryStatement );
+        sqlite3_finalize( m_poQueryStatement );
+        m_poQueryStatement = NULL;
     }
-    
-    /* All done! */
-	return OGRERR_NONE;
 }
 
-
 /************************************************************************/
-/*                          SetFeature()                                */
+/*                           GetNextFeature()                           */
 /************************************************************************/
 
-OGRErr OGRGeoPackageLayer::SetFeature( OGRFeature *poFeature )
-{
-    if( !m_poDS->IsUpdatable() )
-    {
-        return OGRERR_FAILURE;
-    }
-    
-    if ( ! m_poFeatureDefn || ! m_pszTableName )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined, 
-                 "feature definition or table name is null");
-        return OGRERR_FAILURE;
-    }
-
-    if( NULL == poFeature )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "NULL pointer to OGRFeature passed to CreateFeature()" );
-        return OGRERR_FAILURE;
-    }
+OGRFeature *OGRGeoPackageLayer::GetNextFeature()
 
-    /* No FID? We can't set, we have to create */
-    if ( poFeature->GetFID() == OGRNullFID )
+{
+    for( ; TRUE; )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "FID required on features given to SetFeature()." );
-        return OGRERR_FAILURE;
-    }
+        OGRFeature      *poFeature;
 
-    if ( ! m_poUpdateStatement )
-    {
-        /* Construct a SQL INSERT statement from the OGRFeature */
-        /* Only work with fields that are set */
-        /* Do not stick values into SQL, use placeholder and bind values later */    
-        CPLString osCommand = FeatureGenerateUpdateSQL(poFeature);
-
-        /* Prepare the SQL into a statement */
-        int err = sqlite3_prepare_v2(m_poDS->GetDatabaseHandle(), osCommand, -1, &m_poUpdateStatement, NULL);
-        if ( err != SQLITE_OK )
+        if( m_poQueryStatement == NULL )
         {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "failed to prepare SQL: %s", osCommand.c_str());        
-            return OGRERR_FAILURE;
+            ResetStatement();
+            if (m_poQueryStatement == NULL)
+                return NULL;
         }
-    }
 
-    /* Bind values onto the statement now */
-    OGRErr errOgr = FeatureBindUpdateParameters(poFeature, m_poUpdateStatement);
-    if ( errOgr != OGRERR_NONE )
-        return errOgr;
-
-    /* From here execute the statement and check errors */
-    int err = sqlite3_step(m_poUpdateStatement);
-    if ( ! (err == SQLITE_OK || err == SQLITE_DONE) )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "failed to execute update");
-        return OGRERR_FAILURE;       
-    }
-
-    sqlite3_reset(m_poUpdateStatement);
-    sqlite3_clear_bindings(m_poUpdateStatement);
-
-    /* Only update the envelope if we changed something */
-    if (sqlite3_changes(m_poDS->GetDatabaseHandle()) )
-    {
-        /* Update the layer extents with this new object */
-        if ( IsGeomFieldSet(poFeature) )
+    /* -------------------------------------------------------------------- */
+    /*      Fetch a record (unless otherwise instructed)                    */
+    /* -------------------------------------------------------------------- */
+        if( bDoStep )
         {
-            OGREnvelope oEnv;
-            poFeature->GetGeomFieldRef(0)->getEnvelope(&oEnv);
-            UpdateExtent(&oEnv);
-        }
-    }
-
-    /* All done! */
-	return OGRERR_NONE;
-}
+            int rc;
 
+            rc = sqlite3_step( m_poQueryStatement );
+            if( rc != SQLITE_ROW )
+            {
+                if ( rc != SQLITE_DONE )
+                {
+                    sqlite3_reset(m_poQueryStatement);
+                    CPLError( CE_Failure, CPLE_AppDefined,
+                            "In GetNextRawFeature(): sqlite3_step() : %s",
+                            sqlite3_errmsg(m_poDS->GetDB()) );
+                }
 
+                ClearStatement();
 
-/************************************************************************/
-/*                         SetAttributeFilter()                         */
-/************************************************************************/
+                return NULL;
+            }
+        }
+        else
+            bDoStep = TRUE;
 
-OGRErr OGRGeoPackageLayer::SetAttributeFilter( const char *pszQuery )
+        poFeature = TranslateFeature(m_poQueryStatement);
+        if( poFeature == NULL )
+            return NULL;
 
-{
-    if( pszQuery == NULL )
-        m_soFilter.Clear();
-    else
-        m_soFilter = pszQuery;
+        if( (m_poFilterGeom == NULL
+            || FilterGeometry( poFeature->GetGeomFieldRef(m_iGeomFieldFilter) ) )
+            && (m_poAttrQuery == NULL
+                || m_poAttrQuery->Evaluate( poFeature )) )
+            return poFeature;
 
-    ResetReading();
-    return OGRERR_NONE;
+        delete poFeature;
+    }
 }
 
-
 /************************************************************************/
-/*                      ResetReading()                                  */
+/*                         TranslateFeature()                           */
 /************************************************************************/
 
-void OGRGeoPackageLayer::ResetReading()
+OGRFeature *OGRGeoPackageLayer::TranslateFeature( sqlite3_stmt* hStmt )
+
 {
-    if ( m_poQueryStatement )
-    {
-        sqlite3_finalize(m_poQueryStatement);
-        m_poQueryStatement = NULL;
-    }
 
-    if ( m_poInsertStatement )
-    {
-        sqlite3_finalize(m_poInsertStatement);
-        m_poInsertStatement = NULL;
-    }
+/* -------------------------------------------------------------------- */
+/*      Create a feature from the current result.                       */
+/* -------------------------------------------------------------------- */
+    int         iField;
+    OGRFeature *poFeature = new OGRFeature( m_poFeatureDefn );
 
-    if ( m_poUpdateStatement )
-    {
-        sqlite3_finalize(m_poUpdateStatement);
-        m_poUpdateStatement = NULL;
-    }
-    
-    if ( m_poFidStatement )
-    {
-        sqlite3_finalize(m_poFidStatement);
-        m_poFidStatement = NULL;
-    }
-    
-    BuildColumns();
-    return;
-}
+/* -------------------------------------------------------------------- */
+/*      Set FID if we have a column to set it from.                     */
+/* -------------------------------------------------------------------- */
+    if( iFIDCol >= 0 )
+        poFeature->SetFID( sqlite3_column_int64( hStmt, iFIDCol ) );
+    else
+        poFeature->SetFID( iNextShapeId );
 
+    iNextShapeId++;
 
-/************************************************************************/
-/*                        GetNextFeature()                              */
-/************************************************************************/
+    m_nFeaturesRead++;
 
-OGRFeature* OGRGeoPackageLayer::GetNextFeature()
-{
-    /* There is no active query statement set up, */
-    /* so job #1 is to prepare the statement. */
-    if ( ! m_poQueryStatement )
+/* -------------------------------------------------------------------- */
+/*      Process Geometry if we have a column.                           */
+/* -------------------------------------------------------------------- */
+    if( iGeomCol >= 0 )
     {
-        /* Append the attribute filter, if there is one */
-        CPLString soSQL;
-        if ( m_soFilter.length() > 0 )
-            soSQL.Printf("SELECT %s FROM %s WHERE %s", m_soColumns.c_str(), m_pszTableName, m_soFilter.c_str());
-        else
-            soSQL.Printf("SELECT %s FROM %s ", m_soColumns.c_str(), m_pszTableName);
-
-        int err = sqlite3_prepare(m_poDS->GetDatabaseHandle(), soSQL.c_str(), -1, &m_poQueryStatement, NULL);
-        if ( err != SQLITE_OK )
+        OGRGeomFieldDefn* poGeomFieldDefn = m_poFeatureDefn->GetGeomFieldDefn(0);
+        if ( sqlite3_column_type(hStmt, iGeomCol) != SQLITE_NULL &&
+            !poGeomFieldDefn->IsIgnored() )
         {
-            m_poQueryStatement = NULL;
-            CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL: %s", soSQL.c_str());            
-            return NULL;
+            OGRSpatialReference* poSrs = poGeomFieldDefn->GetSpatialRef();
+            int iGpkgSize = sqlite3_column_bytes(hStmt, iGeomCol);
+            GByte *pabyGpkg = (GByte *)sqlite3_column_blob(hStmt, iGeomCol);
+            OGRGeometry *poGeom = GPkgGeometryToOGR(pabyGpkg, iGpkgSize, poSrs);
+            if ( ! poGeom )
+            {
+                // Try also spatialite geometry blobs
+                if( OGRSQLiteLayer::ImportSpatiaLiteGeometry( pabyGpkg, iGpkgSize,
+                                                              &poGeom ) != OGRERR_NONE )
+                {
+                    CPLError( CE_Failure, CPLE_AppDefined, "Unable to read geometry");
+                }
+            }
+            poFeature->SetGeometryDirectly( poGeom );
         }
     }
     
-    while ( TRUE )
+/* -------------------------------------------------------------------- */
+/*      set the fields.                                                 */
+/* -------------------------------------------------------------------- */
+    for( iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++ )
     {
-        int err = sqlite3_step(m_poQueryStatement);
-        
-        /* Nothing left in statement? NULL return indicates to caller */
-        /* that there are no features left */
-        if ( err == SQLITE_DONE )
-        {
-            return NULL;
-        }
-        /* Got a row, let's read it */
-        else if ( err == SQLITE_ROW )
-        {
-            OGRFeature *poFeature;
-            
-            /* Fetch the feature */
-            if ( ReadFeature(m_poQueryStatement, &poFeature) != OGRERR_NONE )
-                return NULL;
-            
-            if( (m_poFilterGeom == NULL || FilterGeometry(poFeature->GetGeometryRef()) ) &&
-                (m_poAttrQuery  == NULL || m_poAttrQuery->Evaluate(poFeature)) )
-            {
-                return poFeature;                
-            }
+        OGRFieldDefn *poFieldDefn = m_poFeatureDefn->GetFieldDefn( iField );
+        if ( poFieldDefn->IsIgnored() )
+            continue;
 
-            /* This feature doesn't pass the filters */
-            /* So delete it and loop again to try the next row */
-            delete poFeature;
-        }
-        else 
+        int iRawField = panFieldOrdinals[iField];
+
+        if( sqlite3_column_type( hStmt, iRawField ) == SQLITE_NULL )
+            continue;
+
+        switch( poFieldDefn->GetType() )
         {
-            /* Got neither a row, nor the end of the query. */
-            /* Something terrible has happened, break out of loop */
-            /* CPLError( CE_Failure, CPLE_AppDefined, "unable to step through query statement"); */
-            return NULL;
-        }
+            case OFTInteger:
+                poFeature->SetField( iField, 
+                    sqlite3_column_int( hStmt, iRawField ) );
+                break;
 
-    }
+            case OFTInteger64:
+                poFeature->SetField( iField, 
+                    sqlite3_column_int64( hStmt, iRawField ) );
+                break;
 
-}	
+            case OFTReal:
+                poFeature->SetField( iField, 
+                    sqlite3_column_double( hStmt, iRawField ) );
+                break;
 
-/************************************************************************/
-/*                        GetFeature()                                  */
-/************************************************************************/
+            case OFTBinary:
+            {
+                const int nBytes = sqlite3_column_bytes( hStmt, iRawField );
 
-OGRFeature* OGRGeoPackageLayer::GetFeature(long nFID)
-{
-    /* No FID, no answer. */
-    if (nFID == OGRNullFID)
-        return NULL;
-    
-    /* Clear out any existing query */
-    ResetReading();
+                poFeature->SetField( iField, nBytes,
+                    (GByte*)sqlite3_column_blob( hStmt, iRawField ) );
+                break;
+            }
 
-    /* No filters apply, just use the FID */
-    CPLString soSQL;
-    soSQL.Printf("SELECT %s FROM %s WHERE %s = %ld",
-                 m_soColumns.c_str(), m_pszTableName, m_pszFidColumn, nFID);
+            case OFTDate:
+            {
+                const char* pszTxt = (const char*)sqlite3_column_text( hStmt, iRawField );
+                int nYear, nMonth, nDay;
+                if( sscanf(pszTxt, "%d-%d-%d", &nYear, &nMonth, &nDay) == 3 )
+                    poFeature->SetField(iField, nYear, nMonth, nDay, 0, 0, 0, 0);
+                break;
+            }
 
-    int err = sqlite3_prepare(m_poDS->GetDatabaseHandle(), soSQL.c_str(), -1, &m_poQueryStatement, NULL);
-    if ( err != SQLITE_OK )
-    {
-        m_poQueryStatement = NULL;
-        CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL: %s", soSQL.c_str());            
-        return NULL;
-    }
-    
-    /* Should be only one or zero results */
-    err = sqlite3_step(m_poQueryStatement);
-        
-    /* Nothing left in statement? NULL return indicates to caller */
-    /* that there are no features left */
-    if ( err == SQLITE_DONE )
-        return NULL;
-
-    /* Aha, got one */
-    if ( err == SQLITE_ROW )
-    {
-        OGRFeature *poFeature;
-        
-        /* Fetch the feature */
-        if ( ReadFeature(m_poQueryStatement, &poFeature) != OGRERR_NONE )
-            return NULL;
-            
-        if ( poFeature )
-            return poFeature;                
-        else 
-            return NULL;
-    }
-    
-    /* Error out on all other return codes */
-    return NULL;
-}
+            case OFTDateTime:
+            {
+                const char* pszTxt = (const char*)sqlite3_column_text( hStmt, iRawField );
+                OGRField sField;
+                if( OGRParseXMLDateTime(pszTxt, &sField) )
+                    poFeature->SetField(iField, &sField);
+                break;
+            }
 
-/************************************************************************/
-/*                        DeleteFeature()                               */
-/************************************************************************/
+            case OFTString:
+                poFeature->SetField( iField, 
+                        (const char *) sqlite3_column_text( hStmt, iRawField ) );
+                break;
 
-OGRErr OGRGeoPackageLayer::DeleteFeature(long nFID)	
-{
-    if( !m_poDS->IsUpdatable() )
-    {
-        return OGRERR_FAILURE;
-    }
-    
-    /* No FID, no answer. */
-    if (nFID == OGRNullFID)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, "delete feature called with null FID");
-        return OGRERR_FAILURE;
+            default:
+                break;
+        }
     }
-    
-    /* Clear out any existing query */
-    ResetReading();
-
-    /* No filters apply, just use the FID */
-    CPLString soSQL;
-    soSQL.Printf("DELETE FROM %s WHERE %s = %ld",
-                 m_pszTableName, m_pszFidColumn, nFID);
 
-    
-    return SQLCommand(m_poDS->GetDatabaseHandle(), soSQL.c_str());
+    return poFeature;
 }
 
 /************************************************************************/
@@ -1140,142 +287,182 @@ const char* OGRGeoPackageLayer::GetFIDColumn()
 }
 
 /************************************************************************/
-/*                        SyncToDisk()                                  */
+/*                      TestCapability()                                */
 /************************************************************************/
 
-OGRErr OGRGeoPackageLayer::SyncToDisk()
+int OGRGeoPackageLayer::TestCapability ( const char * pszCap )
 {
-    SaveExtent();
-    return OGRERR_NONE;
+    if( EQUAL(pszCap,OLCIgnoreFields) )
+        return TRUE; 
+    else if ( EQUAL(pszCap, OLCStringsAsUTF8) )
+        return m_poDS->GetUTF8();
+    else
+        return FALSE;
 }
 
 /************************************************************************/
-/*                        StartTransaction()                            */
+/*                          BuildFeatureDefn()                          */
+/*                                                                      */
+/*      Build feature definition from a set of column definitions       */
+/*      set on a statement.  Sift out geometry and FID fields.          */
 /************************************************************************/
 
-OGRErr OGRGeoPackageLayer::StartTransaction()
+void OGRGeoPackageLayer::BuildFeatureDefn( const char *pszLayerName,
+                                           sqlite3_stmt *hStmt )
+
 {
-    return SQLCommand(m_poDS->GetDatabaseHandle(), "BEGIN");
-}
+    m_poFeatureDefn = new OGRSQLiteFeatureDefn( pszLayerName );
+    SetDescription( m_poFeatureDefn->GetName() );
+    m_poFeatureDefn->SetGeomType(wkbNone);
+    m_poFeatureDefn->Reference();
 
+    int    nRawColumns = sqlite3_column_count( hStmt );
 
-/************************************************************************/
-/*                        CommitTransaction()                           */
-/************************************************************************/
+    panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
 
-OGRErr OGRGeoPackageLayer::CommitTransaction()
-{
-    return SQLCommand(m_poDS->GetDatabaseHandle(), "COMMIT");
-}
+    int iCol;
+    for( iCol = 0; iCol < nRawColumns; iCol++ )
+    {
+        OGRFieldDefn    oField( OGRSQLiteParamsUnquote(sqlite3_column_name( hStmt, iCol )),
+                                OFTString );
 
+        // In some cases, particularly when there is a real name for
+        // the primary key/_rowid_ column we will end up getting the
+        // primary key column appearing twice.  Ignore any repeated names.
+        if( m_poFeatureDefn->GetFieldIndex( oField.GetNameRef() ) != -1 )
+            continue;
 
-/************************************************************************/
-/*                        RollbackTransaction()                         */
-/************************************************************************/
+        if( EQUAL(oField.GetNameRef(), "FID") )
+        {
+            CPLFree(m_pszFidColumn);
+            m_pszFidColumn = CPLStrdup(oField.GetNameRef());
+            iFIDCol = iCol;
+        }
 
-OGRErr OGRGeoPackageLayer::RollbackTransaction()
-{
-    return SQLCommand(m_poDS->GetDatabaseHandle(), "ROLLBACK");
-}
+        if( m_pszFidColumn != NULL && EQUAL(m_pszFidColumn, oField.GetNameRef()))
+            continue;
 
+        // The rowid is for internal use, not a real column.
+        if( EQUAL(oField.GetNameRef(),"_rowid_") )
+            continue;
 
-/************************************************************************/
-/*                        GetFeatureCount()                             */
-/************************************************************************/
+        int nColType = sqlite3_column_type( hStmt, iCol );
+        const char * pszDeclType = sqlite3_column_decltype(hStmt, iCol);
 
-int OGRGeoPackageLayer::GetFeatureCount( int bForce )
-{
-    if( m_poFilterGeom != NULL )
-        return OGRLayer::GetFeatureCount(bForce);
-
-    /* Ignore bForce, because we always do a full count on the database */
-    OGRErr err;
-    CPLString soSQL;
-    if ( m_soFilter.length() > 0 )
-        soSQL.Printf("SELECT Count(*) FROM %s WHERE %s", m_pszTableName, m_soFilter.c_str());
-    else
-        soSQL.Printf("SELECT Count(*) FROM %s ", m_pszTableName);
+        // Recognize a geometry column from trying to build the geometry
+        // Usefull for OGRSQLiteSelectLayer
+        if( nColType == SQLITE_BLOB && m_poFeatureDefn->GetGeomFieldCount() == 0 )
+        {
+            const int nBytes = sqlite3_column_bytes( hStmt, iCol );
+            if( nBytes > 4 )
+            {
+                int iGpkgSize = sqlite3_column_bytes(hStmt, iCol);
+                const GByte* pabyGpkg = (const GByte*)sqlite3_column_blob( hStmt, iCol  );
+                GPkgHeader oHeader;
+                OGRGeometry* poGeom = NULL;
+                int nSRID;
+                if( GPkgHeaderFromWKB(pabyGpkg, &oHeader) == OGRERR_NONE )
+                {
+                    OGRGeomFieldDefn oGeomField(oField.GetNameRef(), wkbUnknown);
 
-    /* Just run the query directly and get back integer */
-    int iFeatureCount = SQLGetInteger(m_poDS->GetDatabaseHandle(), soSQL.c_str(), &err);
+                    /* Read the SRS */
+                    OGRSpatialReference *poSRS = m_poDS->GetSpatialRef(oHeader.iSrsId);
+                    if ( poSRS )
+                    {
+                        oGeomField.SetSpatialRef(poSRS);
+                        poSRS->Dereference();
+                    }
 
-    /* Generic implementation uses -1 for error condition, so we will too */
-    if ( err == OGRERR_NONE )
-        return iFeatureCount;
-    else
-        return -1;
-}
+                    OGRwkbGeometryType eGeomType = wkbUnknown;
+                    if( pszDeclType != NULL )
+                    {
+                        eGeomType = GPkgGeometryTypeToWKB(pszDeclType, (oHeader.iDims == 3));
+                        if( eGeomType != wkbNone )
+                            oGeomField.SetType( eGeomType );
+                    }
 
+#ifdef SQLITE_HAS_COLUMN_METADATA
+                    const char* pszTableName = sqlite3_column_table_name( hStmt, iCol );
+                    if( oGeomField.GetType() == wkbUnknown && pszTableName != NULL )
+                    {
+                        OGRGeoPackageLayer* poLayer = (OGRGeoPackageLayer*)
+                                        m_poDS->GetLayerByName(pszTableName);
+                        if( poLayer != NULL && poLayer->GetLayerDefn()->GetGeomFieldCount() > 0)
+                        {
+                            oGeomField.SetType( poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->GetType() );
+                        }
+                    }
+#endif
 
-/************************************************************************/
-/*                        GetExtent()                                   */
-/************************************************************************/
+                    m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
+                    iGeomCol = iCol;
+                    continue;
+                }
 
-OGRErr OGRGeoPackageLayer::GetExtent(OGREnvelope *psExtent, int bForce)
-{
-    /* Extent already calculated! We're done. */
-    if ( m_poExtent != NULL )
-    {
-        if ( psExtent )
-        {
-            *psExtent = *m_poExtent;            
+                // Try also spatialite geometry blobs
+                else if( OGRSQLiteLayer::ImportSpatiaLiteGeometry( pabyGpkg, iGpkgSize,
+                                                                   &poGeom, &nSRID ) == OGRERR_NONE )
+                {
+                    OGRGeomFieldDefn oGeomField(oField.GetNameRef(), wkbUnknown);
+
+                    /* Read the SRS */
+                    OGRSpatialReference *poSRS = m_poDS->GetSpatialRef(nSRID);
+                    if ( poSRS )
+                    {
+                        oGeomField.SetSpatialRef(poSRS);
+                        poSRS->Dereference();
+                    }
+                    delete poGeom;
+
+                    m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
+                    iGeomCol = iCol;
+                    continue;
+                }
+            }
         }
-        return OGRERR_NONE;
-    }
 
-    /* User is OK with expensive calculation, fall back to */
-    /* default implementation (scan all features) and save */
-    /* the result for later */
-    if ( bForce )
-    {
-        OGRErr err = OGRLayer::GetExtent(psExtent, bForce);
-        if ( err != OGRERR_NONE )
-            return err;
-    
-        if ( ! m_poExtent )
-            m_poExtent = new OGREnvelope( *psExtent );
-        else
-            *m_poExtent = *psExtent;
-        return SaveExtent();
-    }
+        switch( nColType )
+        {
+          case SQLITE_INTEGER:
+            if( CSLTestBoolean(CPLGetConfigOption("OGR_PROMOTE_TO_INTEGER64", "FALSE")) )
+                oField.SetType( OFTInteger64 );
+            else
+            {
+                GIntBig nVal = sqlite3_column_int64(hStmt, iCol);
+                if( (GIntBig)(int)nVal == nVal )
+                    oField.SetType( OFTInteger );
+                else
+                    oField.SetType( OFTInteger64 );
+            }
+            break;
 
-    return OGRERR_FAILURE;
-}
+          case SQLITE_FLOAT:
+            oField.SetType( OFTReal );
+            break;
 
+          case SQLITE_BLOB:
+            oField.SetType( OFTBinary );
+            break;
 
+          default:
+            /* leave it as OFTString */;
+        }
 
-/************************************************************************/
-/*                      TestCapability()                                */
-/************************************************************************/
+        if (pszDeclType != NULL)
+        {
+            OGRFieldSubType eSubType;
+            int nMaxWidth;
+            OGRFieldType eFieldType = GPkgFieldToOGR(pszDeclType, eSubType, nMaxWidth);
+            if( (int)eFieldType <= OFTMaxType )
+            {
+                oField.SetType(eFieldType);
+                oField.SetSubType(eSubType);
+                oField.SetWidth(nMaxWidth);
+            }
+        }
 
-int OGRGeoPackageLayer::TestCapability ( const char * pszCap )
-{
-    if ( EQUAL(pszCap, OLCCreateField) ||
-         EQUAL(pszCap, OLCSequentialWrite) ||
-         EQUAL(pszCap, OLCDeleteFeature) ||
-         EQUAL(pszCap, OLCRandomWrite) )
-    {
-        return m_poDS->IsUpdatable();
+        m_poFeatureDefn->AddFieldDefn( &oField );
+        panFieldOrdinals[m_poFeatureDefn->GetFieldCount() - 1] = iCol;
     }
-    else if ( EQUAL(pszCap, OLCRandomRead) ||
-              EQUAL(pszCap, OLCTransactions) )
-    {
-        return TRUE;
-    }
-    else if ( EQUAL(pszCap, OLCStringsAsUTF8) )
-    {
-        return m_poDS->GetUTF8();
-    }
-    else if ( EQUAL(pszCap, OLCFastGetExtent) )
-    {
-        if ( m_poExtent && ! m_poFilterGeom )
-            return TRUE;
-        else
-            return FALSE;
-    }
-    else
-    {
-        return FALSE;
-    }
-}
 
+}
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackageselectlayer.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackageselectlayer.cpp
new file mode 100644
index 0000000..bdb2474
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackageselectlayer.cpp
@@ -0,0 +1,161 @@
+/******************************************************************************
+ * $Id: ogrgeopackageselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
+ *
+ * Project:  GeoPackage Translator
+ * Purpose:  Implements OGRGeoPackageSelectLayer class
+ * Author:   Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geopackage.h"
+
+/************************************************************************/
+/*                        OGRGeoPackageSelectLayer()                    */
+/************************************************************************/
+
+OGRGeoPackageSelectLayer::OGRGeoPackageSelectLayer( GDALGeoPackageDataset *poDS,
+                                            CPLString osSQLIn,
+                                            sqlite3_stmt *hStmtIn,
+                                            int bUseStatementForGetNextFeature,
+                                            int bEmptyLayer ) : OGRGeoPackageLayer(poDS)
+
+{
+    poBehaviour = new OGRSQLiteSelectLayerCommonBehaviour(poDS, this, osSQLIn, bEmptyLayer);
+    BuildFeatureDefn( "SELECT", hStmtIn );
+
+    if( bUseStatementForGetNextFeature )
+    {
+        m_poQueryStatement = hStmtIn;
+        bDoStep = FALSE;
+    }
+    else
+        sqlite3_finalize( hStmtIn );
+}
+
+/************************************************************************/
+/*                       ~OGRGeoPackageSelectLayer()                    */
+/************************************************************************/
+
+OGRGeoPackageSelectLayer::~OGRGeoPackageSelectLayer()
+{
+    delete poBehaviour;
+}
+
+/************************************************************************/
+/*                            ResetReading()                            */
+/************************************************************************/
+
+void OGRGeoPackageSelectLayer::ResetReading()
+{
+    poBehaviour->ResetReading();
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature *OGRGeoPackageSelectLayer::GetNextFeature()
+{
+    return poBehaviour->GetNextFeature();
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+GIntBig OGRGeoPackageSelectLayer::GetFeatureCount( int bForce )
+{
+    return poBehaviour->GetFeatureCount(bForce);
+}
+
+/************************************************************************/
+/*                           ResetStatement()                           */
+/************************************************************************/
+
+OGRErr OGRGeoPackageSelectLayer::ResetStatement()
+
+{
+    int rc;
+
+    ClearStatement();
+
+    iNextShapeId = 0;
+    bDoStep = TRUE;
+
+#ifdef DEBUG
+    CPLDebug( "OGR_GPKG", "prepare(%s)", poBehaviour->osSQLCurrent.c_str() );
+#endif
+
+    rc = sqlite3_prepare( m_poDS->GetDB(), poBehaviour->osSQLCurrent, poBehaviour->osSQLCurrent.size(),
+                          &m_poQueryStatement, NULL );
+
+    if( rc == SQLITE_OK )
+    {
+        return OGRERR_NONE;
+    }
+    else
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "In ResetStatement(): sqlite3_prepare(%s):\n  %s", 
+                  poBehaviour->osSQLCurrent.c_str(), sqlite3_errmsg(m_poDS->GetDB()) );
+        m_poQueryStatement = NULL;
+        return OGRERR_FAILURE;
+    }
+}
+
+/************************************************************************/
+/*                         SetAttributeFilter()                         */
+/************************************************************************/
+
+OGRErr OGRGeoPackageSelectLayer::SetAttributeFilter( const char *pszQuery )
+{
+    return poBehaviour->SetAttributeFilter(pszQuery);
+}
+
+/************************************************************************/
+/*                          SetSpatialFilter()                          */
+/************************************************************************/
+
+void OGRGeoPackageSelectLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
+
+{
+    poBehaviour->SetSpatialFilter(iGeomField, poGeomIn);
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRGeoPackageSelectLayer::TestCapability( const char * pszCap )
+{
+    return poBehaviour->TestCapability(pszCap);
+}
+
+/************************************************************************/
+/*                             GetExtent()                              */
+/************************************************************************/
+
+OGRErr OGRGeoPackageSelectLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
+{
+    return poBehaviour->GetExtent(iGeomField, psExtent, bForce);
+}
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp
new file mode 100644
index 0000000..7d3e3c6
--- /dev/null
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackagetablelayer.cpp
@@ -0,0 +1,2670 @@
+/******************************************************************************
+ * $Id$
+ *
+ * Project:  GeoPackage Translator
+ * Purpose:  Implements OGRGeoPackageTableLayer class
+ * Author:   Paul Ramsey <pramsey at boundlessgeo.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2013, Paul Ramsey <pramsey at boundlessgeo.com>
+ * Copyright (c) 2014, Even Rouault <even dot rouault at mines-paris dot org>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_geopackage.h"
+#include "ogrgeopackageutility.h"
+#include "cpl_time.h"
+#include "ogr_p.h"
+
+//----------------------------------------------------------------------
+// SaveExtent()
+// 
+// Write the current contents of the layer envelope down to the
+// gpkg_contents metadata table.
+//
+OGRErr OGRGeoPackageTableLayer::SaveExtent()
+{
+    if ( !m_poDS->GetUpdate() || ! m_bExtentChanged || ! m_poExtent ) 
+        return OGRERR_NONE;
+
+    sqlite3* poDb = m_poDS->GetDB();
+
+    if ( ! poDb ) return OGRERR_FAILURE;
+
+    char *pszSQL = sqlite3_mprintf(
+                "UPDATE gpkg_contents SET "
+                "min_x = %g, min_y = %g, "
+                "max_x = %g, max_y = %g "
+                "WHERE table_name = '%q' AND "
+                "Lower(data_type) = 'features'",
+                m_poExtent->MinX, m_poExtent->MinY,
+                m_poExtent->MaxX, m_poExtent->MaxY,
+                m_pszTableName);
+
+    OGRErr err = SQLCommand(poDb, pszSQL);
+    sqlite3_free(pszSQL);
+    m_bExtentChanged = FALSE;
+    
+    return err;
+}
+
+//----------------------------------------------------------------------
+// UpdateExtent()
+// 
+// Expand the layer envelope if necessary to reflect the bounds
+// of new features being added to the layer.
+//
+OGRErr OGRGeoPackageTableLayer::UpdateExtent( const OGREnvelope *poExtent )
+{
+    if ( ! m_poExtent )
+    {
+        m_poExtent = new OGREnvelope( *poExtent );
+    }
+    m_poExtent->Merge( *poExtent );
+    m_bExtentChanged = TRUE;
+    return OGRERR_NONE;
+}
+
+//----------------------------------------------------------------------
+// BuildColumns()
+// 
+// Save a list of columns (fid, geometry, attributes) suitable
+// for use in a SELECT query that retrieves all fields.
+//
+OGRErr OGRGeoPackageTableLayer::BuildColumns()
+{
+    if ( ! m_poFeatureDefn )
+    {
+        return OGRERR_FAILURE;
+    }
+
+    CPLFree(panFieldOrdinals);
+    panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * m_poFeatureDefn->GetFieldCount() );
+
+    /* Always start with a primary key */
+    CPLString soColumns = m_pszFidColumn ? m_pszFidColumn : "_rowid_";
+    CPLString soColumn;
+    iFIDCol = 0;
+
+    /* Add a geometry column if there is one (just one) */
+    if ( m_poFeatureDefn->GetGeomFieldCount() )
+    {
+        soColumns += ", ";
+        soColumn.Printf("\"%s\"", m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef());
+        soColumns += soColumn;
+        iGeomCol = 1;
+    }
+
+    /* Add all the attribute columns */
+    for( int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++ )
+    {
+        soColumns += ", ";
+        soColumn.Printf("\"%s\"", m_poFeatureDefn->GetFieldDefn(i)->GetNameRef());
+        soColumns += soColumn;
+        panFieldOrdinals[i] = 1 + (iGeomCol >= 0) + i;
+    }
+
+    m_soColumns = soColumns;    
+    return OGRERR_NONE;    
+}
+
+//----------------------------------------------------------------------
+// IsGeomFieldSet()
+// 
+// Utility method to determine if there is a non-Null geometry
+// in an OGRGeometry.
+//
+OGRBoolean OGRGeoPackageTableLayer::IsGeomFieldSet( OGRFeature *poFeature )
+{
+    if ( poFeature->GetDefnRef()->GetGeomFieldCount() && 
+         poFeature->GetGeomFieldRef(0) )
+    {
+        return TRUE;        
+    }
+    else
+    {
+        return FALSE;
+    }
+}
+
+OGRErr OGRGeoPackageTableLayer::FeatureBindParameters( OGRFeature *poFeature,
+                                                       sqlite3_stmt *poStmt,
+                                                       int *pnColCount,
+                                                       int bAddFID,
+                                                       int bBindNullFields )
+{
+    int nColCount = 1;
+    int err;
+    
+    if ( ! (poFeature && poStmt && pnColCount) )
+        return OGRERR_FAILURE;
+
+    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
+
+    if( bAddFID )
+    {
+        err = sqlite3_bind_int64(poStmt, nColCount++, poFeature->GetFID());
+    }
+
+    /* Bind data values to the statement, here bind the blob for geometry */
+    if ( poFeatureDefn->GetGeomFieldCount() )
+    {
+        GByte *pabyWkb = NULL;
+
+        /* Non-NULL geometry */
+        OGRGeometry* poGeom = poFeature->GetGeomFieldRef(0);
+        if ( poGeom )
+        {
+            size_t szWkb;
+            pabyWkb = GPkgGeometryFromOGR(poGeom, m_iSrs, &szWkb);
+            err = sqlite3_bind_blob(poStmt, nColCount++, pabyWkb, szWkb, CPLFree);
+
+            // FIXME: in case the geometry is a GeometryCollection, we should
+            // inspect its subgeometries to see if there's non-linear ones.
+            if( OGR_GT_IsNonLinear(poGeom->getGeometryType()) )
+                CreateGeometryExtensionIfNecessary(poGeom->getGeometryType());
+        }
+        /* NULL geometry */
+        else
+        {
+            err = sqlite3_bind_null(poStmt, nColCount++);
+        }
+        if ( err != SQLITE_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "failed to bind geometry to statement");        
+            return OGRERR_FAILURE;            
+        }
+    }
+
+    /* Bind the attributes using appropriate SQLite data types */
+    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    {
+        if( i == m_iFIDAsRegularColumnIndex )
+            continue;
+        OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i); 
+        
+        if( poFeature->IsFieldSet(i) )
+        {
+            switch(SQLiteFieldFromOGR(poFieldDefn->GetType()))
+            {
+                case SQLITE_INTEGER:
+                {
+                    err = sqlite3_bind_int64(poStmt, nColCount++, poFeature->GetFieldAsInteger64(i));
+                    break;
+                }
+                case SQLITE_FLOAT:
+                {
+                    err = sqlite3_bind_double(poStmt, nColCount++, poFeature->GetFieldAsDouble(i));
+                    break;
+                }
+                case SQLITE_BLOB:
+                {
+                    int szBlob;
+                    GByte *pabyBlob = poFeature->GetFieldAsBinary(i, &szBlob);
+                    err = sqlite3_bind_blob(poStmt, nColCount++, pabyBlob, szBlob, NULL);
+                    break;
+                }
+                default:
+                {
+                    const char *pszVal = poFeature->GetFieldAsString(i);
+                    int nValLengthBytes = (int)strlen(pszVal);
+                    char szVal[32];
+                    int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
+                    CPLString osTemp;
+                    if( poFieldDefn->GetType() == OFTDate )
+                    {
+                        poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond, &nTZFlag);
+                        snprintf(szVal, sizeof(szVal), "%04d-%02d-%02d", nYear, nMonth, nDay);
+                        pszVal = szVal;
+                        nValLengthBytes = (int)strlen(pszVal);
+                    }
+                    else if( poFieldDefn->GetType() == OFTDateTime )
+                    {
+                        float fSecond;
+                        poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond, &nTZFlag);
+                        if( nTZFlag == 0 || nTZFlag == 100 )
+                        {
+                            if( OGR_GET_MS(fSecond) )
+                                snprintf(szVal, sizeof(szVal), "%04d-%02d-%02dT%02d:%02d:%06.3fZ",
+                                     nYear, nMonth, nDay, nHour, nMinute, fSecond);
+                            else
+                                snprintf(szVal, sizeof(szVal), "%04d-%02d-%02dT%02d:%02d:%02dZ",
+                                     nYear, nMonth, nDay, nHour, nMinute, (int)fSecond);
+                            pszVal = szVal;
+                            nValLengthBytes = (int)strlen(pszVal);
+                        }
+                    }
+                    else if( poFieldDefn->GetType() == OFTString &&
+                             poFieldDefn->GetWidth() > 0 )
+                    {
+                        if( !CPLIsUTF8(pszVal, -1) )
+                        {
+                            CPLError(CE_Warning, CPLE_AppDefined,
+                                     "Value of field '%s' is not a valid UTF-8 string.%s",
+                                     poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
+                                     m_bTruncateFields ? " Value will be laundered." : "");
+                            if( m_bTruncateFields )
+                            {
+                                char* pszTemp = CPLForceToASCII(pszVal, -1, '_');
+                                osTemp = pszTemp;
+                                pszVal = osTemp.c_str();
+                                CPLFree(pszTemp);
+                            }
+                        }
+
+                        if( CPLStrlenUTF8(pszVal) > poFieldDefn->GetWidth() )
+                        {
+                            CPLError(CE_Warning, CPLE_AppDefined,
+                                     "Value of field '%s' has %d characters, whereas maximum allowed is %d.%s",
+                                     poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
+                                     CPLStrlenUTF8(pszVal),
+                                     poFieldDefn->GetWidth(),
+                                     m_bTruncateFields ? " Value will be truncated." : "");
+                            if( m_bTruncateFields )
+                            {
+                                int k = 0;
+                                nValLengthBytes = 0;
+                                while (pszVal[nValLengthBytes])
+                                {
+                                    if ((pszVal[nValLengthBytes] & 0xc0) != 0x80)
+                                    {
+                                        k++;
+                                        // Stop at the start of the character just beyond the maximum accepted
+                                        if( k > poFieldDefn->GetWidth() )
+                                            break;
+                                    }
+                                    nValLengthBytes++;
+                                }
+                            }
+                        }
+                    }
+                    err = sqlite3_bind_text(poStmt, nColCount++, pszVal, nValLengthBytes, SQLITE_TRANSIENT);
+                    break;
+                }            
+            }            
+        }
+        else
+        {
+            if( bBindNullFields )
+                err = sqlite3_bind_null(poStmt, nColCount++);
+        }
+    }
+    
+    *pnColCount = nColCount;
+    return OGRERR_NONE;
+}
+
+//----------------------------------------------------------------------
+// FeatureBindUpdateParameters()
+// 
+// Selectively bind the values of an OGRFeature to a prepared 
+// statement, prior to execution. Carefully binds exactly the 
+// same parameters that have been set up by FeatureGenerateUpdateSQL()
+// as bindable.
+//
+OGRErr OGRGeoPackageTableLayer::FeatureBindUpdateParameters( OGRFeature *poFeature, sqlite3_stmt *poStmt )
+{
+
+    int nColCount;
+    OGRErr err = FeatureBindParameters( poFeature, poStmt, &nColCount, FALSE, TRUE );
+    if ( err != OGRERR_NONE )
+        return err;
+
+    /* Bind the FID to the "WHERE" clause */
+    err = sqlite3_bind_int64(poStmt, nColCount, poFeature->GetFID());    
+    if ( err != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "failed to bind FID '" CPL_FRMT_GIB "' to statement", poFeature->GetFID());
+        return OGRERR_FAILURE;       
+    }
+    
+    return OGRERR_NONE;
+}
+
+
+//----------------------------------------------------------------------
+// FeatureBindInsertParameters()
+// 
+// Selectively bind the values of an OGRFeature to a prepared 
+// statement, prior to execution. Carefully binds exactly the 
+// same parameters that have been set up by FeatureGenerateInsertSQL()
+// as bindable.
+//
+OGRErr OGRGeoPackageTableLayer::FeatureBindInsertParameters( OGRFeature *poFeature,
+                                                             sqlite3_stmt *poStmt,
+                                                             int bAddFID,
+                                                             int bBindNullFields )
+{    
+    int nColCount;
+    return FeatureBindParameters( poFeature, poStmt, &nColCount, bAddFID, bBindNullFields );
+}   
+
+
+//----------------------------------------------------------------------
+// FeatureGenerateInsertSQL()
+// 
+// Build a SQL INSERT statement that references all the columns in
+// the OGRFeatureDefn, then prepare it for repeated use in a prepared
+// statement. All statements start off with geometry (if it exists)
+// then reference each column in the order it appears in the OGRFeatureDefn.
+// FeatureBindParameters operates on the expectation of this
+// column ordering.
+//
+CPLString OGRGeoPackageTableLayer::FeatureGenerateInsertSQL( OGRFeature *poFeature,
+                                                             int bAddFID,
+                                                             int bBindNullFields )
+{
+    OGRBoolean bNeedComma = FALSE;
+    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
+
+    if( poFeatureDefn->GetFieldCount() == ((m_iFIDAsRegularColumnIndex >= 0) ? 1 : 0) &&
+        poFeatureDefn->GetGeomFieldCount() == 0 &&
+        !bAddFID )
+        return CPLSPrintf("INSERT INTO \"%s\" DEFAULT VALUES", m_pszTableName);
+
+    /* Set up our SQL string basics */
+    CPLString osSQLFront;
+    osSQLFront.Printf("INSERT INTO \"%s\" ( ", m_pszTableName);
+
+    CPLString osSQLBack;
+    osSQLBack = ") VALUES (";
+
+    CPLString osSQLColumn;
+    
+    if( bAddFID )
+    {
+        osSQLColumn.Printf("\"%s\"", GetFIDColumn());
+        osSQLFront += osSQLColumn;
+        osSQLBack += "?";
+        bNeedComma = TRUE;
+    }
+    
+    if ( poFeatureDefn->GetGeomFieldCount() )
+    {
+        if( !bNeedComma )
+        {
+            bNeedComma = TRUE;
+        }
+        else 
+        {
+            osSQLFront += ", ";
+            osSQLBack += ", ";
+        }
+
+        osSQLColumn.Printf("\"%s\"", poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef());
+        osSQLFront += osSQLColumn;
+        osSQLBack += "?";
+        bNeedComma = TRUE;
+    }
+
+    /* Add attribute column names (except FID) to the SQL */
+    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    {
+        if( i == m_iFIDAsRegularColumnIndex )
+            continue;
+        if( !bBindNullFields && !poFeature->IsFieldSet(i) )
+            continue;
+
+        if( !bNeedComma )
+        {
+            bNeedComma = TRUE;
+        }
+        else 
+        {
+            osSQLFront += ", ";
+            osSQLBack += ", ";
+        }
+
+        osSQLColumn.Printf("\"%s\"", poFeatureDefn->GetFieldDefn(i)->GetNameRef());
+        osSQLFront += osSQLColumn;
+        osSQLBack += "?";
+    }
+    
+    osSQLBack += ")";
+    
+    if( !bNeedComma )
+        return CPLSPrintf("INSERT INTO \"%s\" DEFAULT VALUES", m_pszTableName);
+
+    return osSQLFront + osSQLBack;
+}
+
+
+//----------------------------------------------------------------------
+// FeatureGenerateUpdateSQL()
+// 
+// Build a SQL UPDATE statement that references all the columns in
+// the OGRFeatureDefn, then prepare it for repeated use in a prepared
+// statement. All statements start off with geometry (if it exists)
+// then reference each column in the order it appears in the OGRFeatureDefn.
+// FeatureBindParameters operates on the expectation of this
+// column ordering.
+
+//
+CPLString OGRGeoPackageTableLayer::FeatureGenerateUpdateSQL( OGRFeature *poFeature )
+{
+    OGRBoolean bNeedComma = FALSE;
+    OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
+
+    /* Set up our SQL string basics */
+    CPLString osUpdate;
+    osUpdate.Printf("UPDATE \"%s\" SET ", m_pszTableName);
+
+    CPLString osSQLColumn;
+    
+    if ( poFeatureDefn->GetGeomFieldCount() > 0 )
+    {
+        osSQLColumn.Printf("\"%s\"", poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef());
+        osUpdate += osSQLColumn;
+        osUpdate += "=?";
+        bNeedComma = TRUE;
+    }
+
+    /* Add attribute column names (except FID) to the SQL */
+    for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    {
+        if( i == m_iFIDAsRegularColumnIndex )
+            continue;
+        if( !bNeedComma )
+            bNeedComma = TRUE;
+        else 
+            osUpdate += ", ";
+
+        osSQLColumn.Printf("\"%s\"", poFeatureDefn->GetFieldDefn(i)->GetNameRef());
+        osUpdate += osSQLColumn;
+        osUpdate += "=?";
+    }
+    
+    CPLString osWhere;
+    osWhere.Printf(" WHERE \"%s\" = ?", m_pszFidColumn);
+
+    return osUpdate + osWhere;
+}
+
+
+//----------------------------------------------------------------------
+// ReadTableDefinition()
+// 
+// Initialization routine. Read all the metadata about a table, 
+// starting from just the table name. Reads information from GPKG
+// metadata tables and from SQLite table metadata. Uses it to 
+// populate OGRSpatialReference information and OGRFeatureDefn objects, 
+// among others.
+//
+OGRErr OGRGeoPackageTableLayer::ReadTableDefinition(int bIsSpatial)
+{
+    OGRErr err;
+    SQLResult oResultTable;
+    char* pszSQL;
+    OGRBoolean bReadExtent = FALSE;
+    sqlite3* poDb = m_poDS->GetDB();
+    OGREnvelope oExtent;
+    CPLString osGeomColumnName;
+    CPLString osGeomColsType;
+    int bHasZ = FALSE;
+
+    /* Check that the table name is registered in gpkg_contents */
+    pszSQL = sqlite3_mprintf(
+                "SELECT table_name, data_type, identifier, "
+                "description, min_x, min_y, max_x, max_y, srs_id "
+                "FROM gpkg_contents "
+                "WHERE table_name = '%q'",
+                m_pszTableName);
+                
+    SQLResult oResultContents;
+    err = SQLQuery(poDb, pszSQL, &oResultContents);
+    sqlite3_free(pszSQL);
+    
+    /* gpkg_contents query has to work */
+    /* gpkg_contents.table_name is supposed to be unique */
+    if ( err != OGRERR_NONE || oResultContents.nRowCount != 1 )
+    {
+        if ( err != OGRERR_NONE )
+            CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultContents.pszErrMsg );
+        else if ( oResultContents.nRowCount != 1 )
+            CPLError( CE_Failure, CPLE_AppDefined, "layer '%s' is not registered in gpkg_contents", m_pszTableName );
+        else
+            CPLError( CE_Failure, CPLE_AppDefined, "error reading gpkg_contents" );
+            
+        SQLResultFree(&oResultContents);
+        return OGRERR_FAILURE;
+    }
+    
+    const char* pszIdentifier = SQLResultGetValue(&oResultContents, 2, 0);
+    if( pszIdentifier && strcmp(pszIdentifier, m_pszTableName) != 0 )
+        OGRLayer::SetMetadataItem("IDENTIFIER", pszIdentifier);
+    const char* pszDescription = SQLResultGetValue(&oResultContents, 3, 0);
+    if( pszDescription && pszDescription[0] )
+        OGRLayer::SetMetadataItem("DESCRIPTION", pszDescription);
+
+    if( bIsSpatial )
+    {
+        const char *pszMinX = SQLResultGetValue(&oResultContents, 4, 0);
+        const char *pszMinY = SQLResultGetValue(&oResultContents, 5, 0);
+        const char *pszMaxX = SQLResultGetValue(&oResultContents, 6, 0);
+        const char *pszMaxY = SQLResultGetValue(&oResultContents, 7, 0);
+        
+        /* All the extrema have to be non-NULL for this to make sense */
+        if ( pszMinX && pszMinY && pszMaxX && pszMaxY )
+        {
+            oExtent.MinX = CPLAtof(pszMinX);
+            oExtent.MinY = CPLAtof(pszMinY);
+            oExtent.MaxX = CPLAtof(pszMaxX);
+            oExtent.MaxY = CPLAtof(pszMaxY);
+            bReadExtent = TRUE;
+        }
+
+        /* Done with info from gpkg_contents now */
+        SQLResultFree(&oResultContents);
+
+        /* Check that the table name is registered in gpkg_geometry_columns */
+        pszSQL = sqlite3_mprintf(
+                    "SELECT table_name, column_name, "
+                    "geometry_type_name, srs_id, z "
+                    "FROM gpkg_geometry_columns "
+                    "WHERE table_name = '%q'",
+                    m_pszTableName);
+
+        SQLResult oResultGeomCols;
+        err = SQLQuery(poDb, pszSQL, &oResultGeomCols);
+        sqlite3_free(pszSQL);
+
+        /* gpkg_geometry_columns query has to work */
+        /* gpkg_geometry_columns.table_name is supposed to be unique */
+        if ( err != OGRERR_NONE || oResultGeomCols.nRowCount != 1 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultGeomCols.pszErrMsg );
+            SQLResultFree(&oResultGeomCols);
+            return OGRERR_FAILURE;
+        }
+
+        const char* pszGeomColName = SQLResultGetValue(&oResultGeomCols, 1, 0);
+        if( pszGeomColName != NULL )
+            osGeomColumnName = pszGeomColName;
+        const char* pszGeomColsType = SQLResultGetValue(&oResultGeomCols, 2, 0);
+        if( pszGeomColsType != NULL )
+            osGeomColsType = pszGeomColsType;
+        m_iSrs = SQLResultGetValueAsInteger(&oResultGeomCols, 3, 0);
+        bHasZ = SQLResultGetValueAsInteger(&oResultGeomCols, 4, 0);
+
+        SQLResultFree(&oResultGeomCols);
+    }
+    else
+        SQLResultFree(&oResultContents);
+
+    /* Use the "PRAGMA TABLE_INFO()" call to get table definition */
+    /*  #|name|type|notnull|default|pk */
+    /*  0|id|integer|0||1 */
+    /*  1|name|varchar|0||0 */    
+    pszSQL = sqlite3_mprintf("pragma table_info('%q')", m_pszTableName);
+    err = SQLQuery(poDb, pszSQL, &oResultTable);
+    sqlite3_free(pszSQL);
+
+    if ( err != OGRERR_NONE || oResultTable.nRowCount == 0 )
+    {
+        if( oResultTable.pszErrMsg != NULL )
+            CPLError( CE_Failure, CPLE_AppDefined, "%s", oResultTable.pszErrMsg );
+        else
+            CPLError( CE_Failure, CPLE_AppDefined, "Cannot find table %s", m_pszTableName );
+
+        SQLResultFree(&oResultTable);
+        return OGRERR_FAILURE;
+    }
+    
+    /* Populate feature definition from table description */
+    m_poFeatureDefn = new OGRFeatureDefn( m_pszTableName );
+    SetDescription( m_poFeatureDefn->GetName() );
+    m_poFeatureDefn->SetGeomType(wkbNone);
+    m_poFeatureDefn->Reference();
+    
+    int iRecord;
+    OGRBoolean bFidFound = FALSE;
+
+    for ( iRecord = 0; iRecord < oResultTable.nRowCount; iRecord++ )
+    {
+        const char *pszName = SQLResultGetValue(&oResultTable, 1, iRecord);
+        const char *pszType = SQLResultGetValue(&oResultTable, 2, iRecord);
+        int bNotNull = SQLResultGetValueAsInteger(&oResultTable, 3, iRecord);
+        const char* pszDefault = SQLResultGetValue(&oResultTable, 4, iRecord);
+        OGRBoolean bFid = SQLResultGetValueAsInteger(&oResultTable, 5, iRecord);
+        OGRFieldSubType eSubType;
+        int nMaxWidth;
+        OGRFieldType oType = GPkgFieldToOGR(pszType, eSubType, nMaxWidth);
+
+        /* Not a standard field type... */
+        if ( (oType > OFTMaxType && osGeomColsType.size()) || EQUAL(osGeomColumnName, pszName) )
+        {
+            /* Maybe it's a geometry type? */
+            OGRwkbGeometryType oGeomType;
+            if( oType > OFTMaxType )
+                oGeomType = GPkgGeometryTypeToWKB(pszType, bHasZ);
+            else
+                oGeomType = wkbUnknown;
+            if ( oGeomType != wkbNone )
+            {
+                OGRwkbGeometryType oGeomTypeGeomCols = GPkgGeometryTypeToWKB(osGeomColsType.c_str(), bHasZ);
+                /* Enforce consistency between table and metadata */
+                if( wkbFlatten(oGeomType) == wkbUnknown )
+                    oGeomType = oGeomTypeGeomCols;
+                if ( oGeomType != oGeomTypeGeomCols )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined, 
+                             "geometry column type in '%s.%s' is not consistent with type in gpkg_geometry_columns", 
+                             m_pszTableName, pszName);
+                }
+
+                if ( m_poFeatureDefn->GetGeomFieldCount() == 0 )
+                {
+                    OGRGeomFieldDefn oGeomField(pszName, oGeomType);
+                    if( bNotNull )
+                        oGeomField.SetNullable(FALSE);
+                    m_poFeatureDefn->AddGeomFieldDefn(&oGeomField);
+
+                    /* Read the SRS */
+                    OGRSpatialReference *poSRS = m_poDS->GetSpatialRef(m_iSrs);
+                    if ( poSRS )
+                    {
+                        m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+                        poSRS->Dereference();
+                    }
+                }
+                else
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined, 
+                             "table '%s' has multiple geometry fields? not legal in gpkg", 
+                             m_pszTableName);
+                    SQLResultFree(&oResultTable);
+                    return OGRERR_FAILURE;
+                }
+
+            }
+            else
+            {
+                // CPLError( CE_Failure, CPLE_AppDefined, "invalid field type '%s'", pszType );
+                // SQLResultFree(&oResultTable);
+                CPLError(CE_Warning, CPLE_AppDefined, 
+                         "geometry column '%s' of type '%s' ignored", pszName, pszType);
+            }
+            
+        }
+        else
+        {
+            /* Is this the FID column? */
+            if ( bFid && (oType == OFTInteger || oType == OFTInteger64) )
+            {
+                if( bFidFound )
+                {
+                    CPLDebug("GPKG", "For table %s, a new FID column has been found (%s). Keeping previous one (%s)",
+                             m_pszTableName, pszName, m_pszFidColumn);
+                }
+                else
+                {
+                    bFidFound = TRUE;
+                    m_pszFidColumn = CPLStrdup(pszName);
+                }
+            }
+            else
+            {
+                OGRFieldDefn oField(pszName, oType);
+                oField.SetSubType(eSubType);
+                oField.SetWidth(nMaxWidth);
+                if( bNotNull )
+                    oField.SetNullable(FALSE);
+                if( pszDefault != NULL )
+                {
+                    int nYear, nMonth, nDay, nHour, nMinute;
+                    float fSecond;
+                    if( oField.GetType() == OFTString &&
+                        !EQUAL(pszDefault, "NULL") &&
+                        !EQUALN(pszDefault, "CURRENT_", strlen("CURRENT_")) &&
+                        pszDefault[0] != '(' &&
+                        pszDefault[0] != '\'' &&
+                        CPLGetValueType(pszDefault) == CPL_VALUE_STRING )
+                    {
+                        CPLString osDefault("'");
+                        char* pszTmp = CPLEscapeString(pszDefault, -1, CPLES_SQL);
+                        osDefault += pszTmp;
+                        CPLFree(pszTmp);
+                        osDefault += "'";
+                        oField.SetDefault(osDefault);
+                    }
+                    else if( oType == OFTDateTime &&
+                             sscanf(pszDefault, "'%d-%d-%dT%d:%d:%fZ'", &nYear, &nMonth, &nDay,
+                                        &nHour, &nMinute, &fSecond) == 6 )
+                    {
+                        if( strchr(pszDefault, '.') == NULL )
+                            oField.SetDefault(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
+                                                      nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond+0.5)));
+                        else
+                            oField.SetDefault(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%06.3f'",
+                                                            nYear, nMonth, nDay, nHour, nMinute, fSecond));
+                    }
+                    else if( (oField.GetType() == OFTDate || oField.GetType() == OFTDateTime) &&
+                             !EQUAL(pszDefault, "NULL") &&
+                             !EQUALN(pszDefault, "CURRENT_", strlen("CURRENT_")) &&
+                             pszDefault[0] != '(' &&
+                             pszDefault[0] != '\'' &&
+                             !(pszDefault[0] >= '0' && pszDefault[0] <= '9') &&
+                            CPLGetValueType(pszDefault) == CPL_VALUE_STRING )
+                    {
+                        CPLString osDefault("(");
+                        osDefault += pszDefault;
+                        osDefault += ")";
+                        if( EQUAL(osDefault, "(strftime('%Y-%m-%dT%H:%M:%fZ','now'))") )
+                            oField.SetDefault("CURRENT_TIMESTAMP");
+                        else
+                            oField.SetDefault(osDefault);
+                    }
+                    else
+                    {
+                        oField.SetDefault(pszDefault);
+                    }
+                }
+                m_poFeatureDefn->AddFieldDefn(&oField);
+            }
+        }
+    }
+
+    /* Wait, we didn't find a FID? Some operations will not be possible */
+    if ( ! bFidFound )
+    {
+        CPLDebug("GPKG", 
+                 "no integer primary key defined for table '%s'", m_pszTableName);
+    }
+    else
+    {
+    /* -------------------------------------------------------------------- */
+    /*      Find if the FID holds 64bit values                              */
+    /* -------------------------------------------------------------------- */
+        const char* pszSQLStatic = CPLSPrintf("SELECT MAX(%s) FROM '%s'",
+                            OGRSQLiteEscape(m_pszFidColumn).c_str(),
+                            m_pszTableName);
+        sqlite3_stmt* hColStmt = NULL;
+        int rc = sqlite3_prepare( poDb, pszSQLStatic, strlen(pszSQLStatic), &hColStmt, NULL ); 
+        if( rc == SQLITE_OK )
+        {
+            rc = sqlite3_step( hColStmt );
+            if( rc == SQLITE_ROW )
+            {
+                GIntBig nMaxId = sqlite3_column_int64( hColStmt, 0 );
+                if( nMaxId > INT_MAX )
+                    OGRLayer::SetMetadataItem(OLMD_FID64, "YES");
+            }
+        }
+        sqlite3_finalize( hColStmt );
+    }
+
+    if ( bReadExtent )
+    {
+        m_poExtent = new OGREnvelope(oExtent);
+    }
+
+    SQLResultFree(&oResultTable);
+
+    /* Update the columns string */
+    BuildColumns();
+    
+    CheckUnknownExtensions();
+
+    return OGRERR_NONE;
+}
+
+
+/************************************************************************/
+/*                      OGRGeoPackageTableLayer()                       */
+/************************************************************************/
+
+OGRGeoPackageTableLayer::OGRGeoPackageTableLayer(
+                    GDALGeoPackageDataset *poDS,
+                    const char * pszTableName) : OGRGeoPackageLayer(poDS)
+{
+    m_pszTableName = CPLStrdup(pszTableName);
+    m_iSrs = 0;
+    m_poExtent = NULL;
+    m_bExtentChanged = FALSE;
+    m_poQueryStatement = NULL;
+    m_poUpdateStatement = NULL;
+    m_bInsertStatementWithFID = FALSE;
+    m_poInsertStatement = NULL;
+    m_soColumns = "";
+    m_soFilter = "";
+    bDeferedSpatialIndexCreation = FALSE;
+    m_bHasSpatialIndex = -1;
+    bDropRTreeTable = FALSE;
+    memset(m_anHasGeometryExtension, 0, sizeof(m_anHasGeometryExtension));
+    m_bPreservePrecision = TRUE;
+    m_bTruncateFields = FALSE;
+    m_bDeferredCreation = FALSE;
+    m_iFIDAsRegularColumnIndex = -1;
+    m_bHasReadMetadataFromStorage = FALSE;
+}
+
+
+/************************************************************************/
+/*                      ~OGRGeoPackageTableLayer()                      */
+/************************************************************************/
+
+OGRGeoPackageTableLayer::~OGRGeoPackageTableLayer()
+{
+    if( m_bDeferredCreation )
+        RunDeferredCreationIfNecessary();
+
+    if( bDropRTreeTable )
+    {
+        const char* pszT = m_pszTableName;
+        const char* pszC =m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+        char* pszSQL;
+        pszSQL = sqlite3_mprintf("DROP TABLE \"rtree_%s_%s\"", pszT, pszC);
+        SQLCommand(m_poDS->GetDB(), pszSQL);
+        sqlite3_free(pszSQL);
+    }
+    else
+    {
+        CreateSpatialIndexIfNecessary();
+    }
+
+    /* Save metadata back to the database */
+    SaveExtent();
+
+    /* Clean up resources in memory */
+    if ( m_pszTableName )
+        CPLFree( m_pszTableName );
+
+    if ( m_poExtent )
+        delete m_poExtent;
+
+    if ( m_poUpdateStatement )
+        sqlite3_finalize(m_poUpdateStatement);
+
+    if ( m_poInsertStatement )
+        sqlite3_finalize(m_poInsertStatement);
+}
+
+
+/************************************************************************/
+/*                      CreateField()                                   */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::CreateField( OGRFieldDefn *poField,
+                                             CPL_UNUSED int bApproxOK )
+{
+    OGRFieldDefn oFieldDefn(poField);
+    if( !m_poDS->GetUpdate() )
+    {
+        return OGRERR_FAILURE;
+    }
+    
+    int nMaxWidth = 0;
+    if( m_bPreservePrecision && poField->GetType() == OFTString )
+        nMaxWidth = poField->GetWidth();
+    else
+        oFieldDefn.SetWidth(0);
+    oFieldDefn.SetPrecision(0);
+    
+    if( m_pszFidColumn != NULL &&
+        EQUAL( oFieldDefn.GetNameRef(), m_pszFidColumn ) &&
+        oFieldDefn.GetType() != OFTInteger &&
+        oFieldDefn.GetType() != OFTInteger64 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
+                 oFieldDefn.GetNameRef());
+        return CE_Failure;
+    }
+
+    if( !m_bDeferredCreation )
+    {
+        CPLString osCommand;
+    
+        osCommand.Printf("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s", 
+                                 m_pszTableName, poField->GetNameRef(),
+                                 GPkgFieldFromOGR(poField->GetType(),
+                                                  poField->GetSubType(),
+                                                  nMaxWidth));
+        if(  !poField->IsNullable() )
+            osCommand += " NOT NULL";
+        if( poField->GetDefault() != NULL && !poField->IsDefaultDriverSpecific() )
+        {
+            osCommand += " DEFAULT ";
+            int nYear, nMonth, nDay, nHour, nMinute;
+            float fSecond;
+            if( poField->GetType() == OFTDateTime &&
+                sscanf(poField->GetDefault(), "'%d/%d/%d %d:%d:%f'", &nYear, &nMonth, &nDay,
+                                        &nHour, &nMinute, &fSecond) == 6 )
+            {
+                if( strchr(poField->GetDefault(), '.') == NULL )
+                    osCommand += CPLSPrintf("'%04d-%02d-%02dT%02d:%02d:%02dZ'",
+                                        nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond+0.5));
+                else
+                    osCommand += CPLSPrintf("'%04d-%02d-%02dT%02d:%02d:%06.3fZ'",
+                                            nYear, nMonth, nDay, nHour, nMinute, fSecond);
+            }
+            else
+                osCommand += poField->GetDefault();
+        }
+        else if( !poField->IsNullable() )
+        {
+            // This is kind of dumb, but SQLite mandates a DEFAULT value
+            // when adding a NOT NULL column in an ALTER TABLE ADD COLUMN
+            // statement, which defeats the purpose of NOT NULL,
+            // whereas it doesn't in CREATE TABLE
+            osCommand += " DEFAULT ''";
+        }
+
+        OGRErr err = SQLCommand(m_poDS->GetDB(), osCommand.c_str());
+
+        if ( err != OGRERR_NONE )
+            return err;
+    }
+
+    m_poFeatureDefn->AddFieldDefn( &oFieldDefn );
+
+    if( m_pszFidColumn != NULL &&
+        EQUAL( oFieldDefn.GetNameRef(), m_pszFidColumn ) )
+    {
+        m_iFIDAsRegularColumnIndex = m_poFeatureDefn->GetFieldCount() - 1;
+    }
+
+    if( !m_bDeferredCreation )
+    {
+        ResetReading();
+    }
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           CreateGeomField()                          */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
+                                                 CPL_UNUSED int bApproxOK )
+{
+    if( m_poFeatureDefn->GetGeomFieldCount() == 1 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot create more than on geometry field in GeoPackage");
+        return OGRERR_FAILURE;
+    }
+    
+    OGRwkbGeometryType eType = poGeomFieldIn->GetType();
+    if( eType == wkbNone )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot create geometry field of type wkbNone");
+        return OGRERR_FAILURE;
+    }
+
+    OGRGeomFieldDefn oGeomField(poGeomFieldIn);
+    if( EQUAL(oGeomField.GetNameRef(), "") )
+    {
+        oGeomField.SetName( "geom" );
+    }
+
+    OGRSpatialReference* poSRS = oGeomField.GetSpatialRef();
+    if( poSRS != NULL )
+        m_iSrs = m_poDS->GetSrsId(poSRS);
+
+/* -------------------------------------------------------------------- */
+/*      Create the new field.                                           */
+/* -------------------------------------------------------------------- */
+    if( !m_bDeferredCreation )
+    {
+        char *pszSQL;
+
+        pszSQL = sqlite3_mprintf("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s%s", 
+                                 m_pszTableName, oGeomField.GetNameRef(),
+                                 m_poDS->GetGeometryTypeString(oGeomField.GetType()),
+                                 !oGeomField.IsNullable() ? " NOT NULL DEFAULT ''" : "");
+
+        OGRErr err = SQLCommand(m_poDS->GetDB(), pszSQL);
+        sqlite3_free(pszSQL);
+
+        if ( err != OGRERR_NONE )
+            return err;
+
+        pszSQL = sqlite3_mprintf(
+            "UPDATE gpkg_contents SET data_type = 'features' WHERE table_name = '%q'",
+            GetName());
+        err = SQLCommand(m_poDS->GetDB(), pszSQL);
+        sqlite3_free(pszSQL);
+        if ( err != OGRERR_NONE )
+            return OGRERR_FAILURE;
+
+        int bHasASpatialLayers = FALSE;
+        for(int i=0;i<m_poDS->GetLayerCount();i++)
+        {
+            if( m_poDS->GetLayer(i) != this &&
+                m_poDS->GetLayer(i)->GetLayerDefn()->GetGeomFieldCount() == 0 )
+                bHasASpatialLayers = TRUE;
+        }
+        if( !bHasASpatialLayers )
+        {
+            err = SQLCommand(m_poDS->GetDB(),
+                             "DELETE FROM gpkg_extensions WHERE "
+                             "extension_name = 'gdal_aspatial' "
+                             "AND table_name IS NULL "
+                             "AND column_name IS NULL");
+            if ( err != OGRERR_NONE )
+                return OGRERR_FAILURE;
+        }
+    }
+
+    m_poFeatureDefn->AddGeomFieldDefn( &oGeomField );
+
+    if( !m_bDeferredCreation )
+    {
+        OGRErr err = RegisterGeometryColumn();
+        if ( err != OGRERR_NONE )
+            return err;
+
+        ResetReading();
+    }
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                      ICreateFeature()                                 */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::ICreateFeature( OGRFeature *poFeature )
+{
+    if( !m_poDS->GetUpdate() )
+    {
+        return OGRERR_FAILURE;
+    }
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    /* Substitute default values for null Date/DateTime fields as the standard */
+    /* format of SQLite is not the one mandated by GeoPackage */
+    poFeature->FillUnsetWithDefault(FALSE, NULL);
+    int bHasDefaultValue = FALSE;
+    int iField;
+    int nFieldCount = m_poFeatureDefn->GetFieldCount();
+    for( iField = 0; iField < nFieldCount; iField++ )
+    {
+        if( poFeature->IsFieldSet( iField ) )
+            continue;
+        const char* pszDefault = poFeature->GetFieldDefnRef(iField)->GetDefault();
+        if( pszDefault != NULL )
+        {
+            bHasDefaultValue = TRUE;
+            break;
+        }
+    }
+
+    /* In case the FID column has also been created as a regular field */
+    if( m_iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( poFeature->GetFID() == OGRNullFID )
+        {
+            if( poFeature->IsFieldSet( m_iFIDAsRegularColumnIndex ) )
+            {
+                poFeature->SetFID(
+                    poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex));
+            }
+        }
+        else
+        {
+            if( !poFeature->IsFieldSet( m_iFIDAsRegularColumnIndex ) ||
+                poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                            "Inconsistant values of FID and field of same name");
+                return CE_Failure;
+            }
+        }
+    }
+
+    /* If there's a unset field with a default value, then we must create */
+    /* a specific INSERT statement to avoid unset fields to be bound to NULL */
+    if( m_poInsertStatement && (bHasDefaultValue || m_bInsertStatementWithFID != (poFeature->GetFID() != OGRNullFID)) )
+    {
+        sqlite3_finalize(m_poInsertStatement);
+        m_poInsertStatement = NULL;
+    }
+    
+    if ( ! m_poInsertStatement ) 
+    {
+        /* Construct a SQL INSERT statement from the OGRFeature */
+        /* Only work with fields that are set */
+        /* Do not stick values into SQL, use placeholder and bind values later */    
+        m_bInsertStatementWithFID = poFeature->GetFID() != OGRNullFID;
+        CPLString osCommand = FeatureGenerateInsertSQL(poFeature, m_bInsertStatementWithFID, !bHasDefaultValue);
+        
+        /* Prepare the SQL into a statement */
+        sqlite3 *poDb = m_poDS->GetDB();
+        int err = sqlite3_prepare_v2(poDb, osCommand, -1, &m_poInsertStatement, NULL);
+        if ( err != SQLITE_OK )
+        {
+            m_poInsertStatement = NULL;
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "failed to prepare SQL: %s", osCommand.c_str());        
+            return OGRERR_FAILURE;
+        }        
+    }
+    
+    /* Bind values onto the statement now */
+    OGRErr errOgr = FeatureBindInsertParameters(poFeature, m_poInsertStatement,
+                                                m_bInsertStatementWithFID, !bHasDefaultValue);
+    if ( errOgr != OGRERR_NONE )
+    {
+        sqlite3_reset(m_poInsertStatement);
+        sqlite3_clear_bindings(m_poInsertStatement);
+        sqlite3_finalize(m_poInsertStatement);
+        m_poInsertStatement = NULL;
+        return errOgr;
+    }
+
+    /* From here execute the statement and check errors */
+    int err = sqlite3_step(m_poInsertStatement);
+    if ( ! (err == SQLITE_OK || err == SQLITE_DONE) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "failed to execute insert : %s",
+                  sqlite3_errmsg(m_poDS->GetDB()) ? sqlite3_errmsg(m_poDS->GetDB()) : "");
+        sqlite3_reset(m_poInsertStatement);
+        sqlite3_clear_bindings(m_poInsertStatement);
+        sqlite3_finalize(m_poInsertStatement);
+        m_poInsertStatement = NULL;
+        return OGRERR_FAILURE; 
+    }
+
+    sqlite3_reset(m_poInsertStatement);
+    sqlite3_clear_bindings(m_poInsertStatement);
+    
+    if( bHasDefaultValue )
+    {
+        sqlite3_finalize(m_poInsertStatement);
+        m_poInsertStatement = NULL;
+    }
+
+    /* Update the layer extents with this new object */
+    if ( IsGeomFieldSet(poFeature) )
+    {
+        OGREnvelope oEnv;
+        poFeature->GetGeomFieldRef(0)->getEnvelope(&oEnv);
+        UpdateExtent(&oEnv);
+    }
+
+    /* Read the latest FID value */
+    GIntBig nFID;
+    if ( (nFID = sqlite3_last_insert_rowid(m_poDS->GetDB())) )
+    {
+        poFeature->SetFID(nFID);
+        if( m_iFIDAsRegularColumnIndex >= 0 )
+            poFeature->SetField( m_iFIDAsRegularColumnIndex, nFID );
+    }
+    else
+    {
+        poFeature->SetFID(OGRNullFID);
+    }
+    
+    /* All done! */
+    return OGRERR_NONE;
+}
+
+
+/************************************************************************/
+/*                          ISetFeature()                                */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::ISetFeature( OGRFeature *poFeature )
+{
+    if( !m_poDS->GetUpdate() || m_pszFidColumn == NULL )
+    {
+        return OGRERR_FAILURE;
+    }
+
+    /* No FID? We can't set, we have to create */
+    if ( poFeature->GetFID() == OGRNullFID )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "FID required on features given to SetFeature()." );
+        return OGRERR_FAILURE;
+    }
+
+    /* In case the FID column has also been created as a regular field */
+    if( m_iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( !poFeature->IsFieldSet( m_iFIDAsRegularColumnIndex ) ||
+            poFeature->GetFieldAsInteger64(m_iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                        "Inconsistant values of FID and field of same name");
+            return CE_Failure;
+        }
+    }
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    /* Old version of SQLite have issues with some of the spatial index triggers */
+#if SQLITE_VERSION_NUMBER < 3007008
+    if( HasSpatialIndex() )
+    {
+        if ( ! m_poUpdateStatement )
+        {
+            /* Construct a SQL INSERT statement from the OGRFeature */
+            /* Only work with fields that are set */
+            /* Do not stick values into SQL, use placeholder and bind values later */    
+            CPLString osCommand = FeatureGenerateInsertSQL(poFeature, TRUE, TRUE);
+
+            /* Prepare the SQL into a statement */
+            int err = sqlite3_prepare_v2(m_poDS->GetDB(), osCommand, -1, &m_poUpdateStatement, NULL);
+            if ( err != SQLITE_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "failed to prepare SQL: %s", osCommand.c_str());        
+                return OGRERR_FAILURE;
+            }
+        }
+
+        sqlite3_stmt* hBackupStmt = m_poUpdateStatement;
+        m_poUpdateStatement = NULL;
+
+        OGRErr errOgr = DeleteFeature( poFeature->GetFID() );
+
+        m_poUpdateStatement = hBackupStmt;
+
+        if ( errOgr != OGRERR_NONE )
+            return errOgr;
+
+        /* Bind values onto the statement now */
+        errOgr = FeatureBindInsertParameters(poFeature, m_poUpdateStatement, TRUE, TRUE);
+        if ( errOgr != OGRERR_NONE )
+            return errOgr;
+    }
+    else
+#endif
+    {
+        if ( ! m_poUpdateStatement )
+        {
+            /* Construct a SQL UPDATE statement from the OGRFeature */
+            /* Only work with fields that are set */
+            /* Do not stick values into SQL, use placeholder and bind values later */    
+            CPLString osCommand = FeatureGenerateUpdateSQL(poFeature);
+
+            /* Prepare the SQL into a statement */
+            int err = sqlite3_prepare_v2(m_poDS->GetDB(), osCommand, -1, &m_poUpdateStatement, NULL);
+            if ( err != SQLITE_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "failed to prepare SQL: %s", osCommand.c_str());        
+                return OGRERR_FAILURE;
+            }
+        }
+        
+        /* Bind values onto the statement now */
+        OGRErr errOgr = FeatureBindUpdateParameters(poFeature, m_poUpdateStatement);
+        if ( errOgr != OGRERR_NONE )
+        {
+            sqlite3_reset(m_poUpdateStatement);
+            sqlite3_clear_bindings(m_poUpdateStatement);
+            return errOgr;
+        }
+    }
+
+    /* From here execute the statement and check errors */
+    int err = sqlite3_step(m_poUpdateStatement);
+    if ( ! (err == SQLITE_OK || err == SQLITE_DONE) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "failed to execute update : %s",
+                  sqlite3_errmsg( m_poDS->GetDB() ) );
+        sqlite3_reset(m_poUpdateStatement);
+        sqlite3_clear_bindings(m_poUpdateStatement);
+        return OGRERR_FAILURE;       
+    }
+
+    sqlite3_reset(m_poUpdateStatement);
+    sqlite3_clear_bindings(m_poUpdateStatement);
+
+    /* Only update the envelope if we changed something */
+    OGRErr eErr = (sqlite3_changes(m_poDS->GetDB()) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
+    if (eErr == OGRERR_NONE)
+    {
+        /* Update the layer extents with this new object */
+        if ( IsGeomFieldSet(poFeature) )
+        {
+            OGREnvelope oEnv;
+            poFeature->GetGeomFieldRef(0)->getEnvelope(&oEnv);
+            UpdateExtent(&oEnv);
+        }
+    }
+
+    /* All done! */
+    return eErr;
+}
+
+
+
+/************************************************************************/
+/*                         SetAttributeFilter()                         */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::SetAttributeFilter( const char *pszQuery )
+
+{
+    CPLFree(m_pszAttrQueryString);
+    m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : NULL;
+
+    if( pszQuery == NULL )
+        osQuery = "";
+    else
+        osQuery = pszQuery;
+
+    BuildWhere();
+
+    ResetReading();
+
+    return OGRERR_NONE;
+}
+
+
+/************************************************************************/
+/*                      ResetReading()                                  */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::ResetReading()
+{
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return;
+
+    OGRGeoPackageLayer::ResetReading();
+
+    if ( m_poInsertStatement )
+    {
+        sqlite3_finalize(m_poInsertStatement);
+        m_poInsertStatement = NULL;
+    }
+
+    if ( m_poUpdateStatement )
+    {
+        sqlite3_finalize(m_poUpdateStatement);
+        m_poUpdateStatement = NULL;
+    }
+
+    BuildColumns();
+    return;
+}
+
+
+/************************************************************************/
+/*                           ResetStatement()                           */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::ResetStatement()
+
+{
+    ClearStatement();
+
+    /* There is no active query statement set up, */
+    /* so job #1 is to prepare the statement. */
+    /* Append the attribute filter, if there is one */
+    CPLString soSQL;
+    if ( m_soFilter.length() > 0 )
+        soSQL.Printf("SELECT %s FROM \"%s\" WHERE %s", m_soColumns.c_str(), m_pszTableName, m_soFilter.c_str());
+    else
+        soSQL.Printf("SELECT %s FROM \"%s\" ", m_soColumns.c_str(), m_pszTableName);
+
+    int err = sqlite3_prepare(m_poDS->GetDB(), soSQL.c_str(), -1, &m_poQueryStatement, NULL);
+    if ( err != SQLITE_OK )
+    {
+        m_poQueryStatement = NULL;
+        CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL: %s", soSQL.c_str());            
+        return OGRERR_FAILURE;
+    }
+    
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature* OGRGeoPackageTableLayer::GetNextFeature()
+{
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+
+    CreateSpatialIndexIfNecessary();
+
+    OGRFeature* poFeature = OGRGeoPackageLayer::GetNextFeature();
+    if( poFeature && m_iFIDAsRegularColumnIndex >= 0 )
+    {
+        poFeature->SetField(m_iFIDAsRegularColumnIndex, poFeature->GetFID());
+    }
+    return poFeature;
+}
+
+/************************************************************************/
+/*                        GetFeature()                                  */
+/************************************************************************/
+
+OGRFeature* OGRGeoPackageTableLayer::GetFeature(GIntBig nFID)
+{
+    /* No FID, no answer. */
+    if (nFID == OGRNullFID || m_pszFidColumn == NULL )
+        return NULL;
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+
+    CreateSpatialIndexIfNecessary();
+    
+    /* Clear out any existing query */
+    ResetReading();
+
+    /* No filters apply, just use the FID */
+    CPLString soSQL;
+    soSQL.Printf("SELECT %s FROM \"%s\" WHERE \"%s\" = " CPL_FRMT_GIB,
+                 m_soColumns.c_str(), m_pszTableName, m_pszFidColumn, nFID);
+
+    int err = sqlite3_prepare(m_poDS->GetDB(), soSQL.c_str(), -1, &m_poQueryStatement, NULL);
+    if ( err != SQLITE_OK )
+    {
+        m_poQueryStatement = NULL;
+        CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL: %s", soSQL.c_str());            
+        return NULL;
+    }
+    
+    /* Should be only one or zero results */
+    err = sqlite3_step(m_poQueryStatement);
+        
+    /* Nothing left in statement? NULL return indicates to caller */
+    /* that there are no features left */
+    if ( err == SQLITE_DONE )
+        return NULL;
+
+    /* Aha, got one */
+    if ( err == SQLITE_ROW )
+    {
+        OGRFeature* poFeature = TranslateFeature(m_poQueryStatement);
+        if( poFeature && m_iFIDAsRegularColumnIndex >= 0 )
+        {
+            poFeature->SetField(m_iFIDAsRegularColumnIndex, poFeature->GetFID());
+        }
+        return poFeature;
+    }
+    
+    /* Error out on all other return codes */
+    return NULL;
+}
+
+/************************************************************************/
+/*                        DeleteFeature()                               */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::DeleteFeature(GIntBig nFID) 
+{
+    if( !m_poDS->GetUpdate() || m_pszFidColumn == NULL )
+    {
+        return OGRERR_FAILURE;
+    }
+    
+    /* No FID, no answer. */
+    if (nFID == OGRNullFID)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "delete feature called with null FID");
+        return OGRERR_FAILURE;
+    }
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    /* Clear out any existing query */
+    ResetReading();
+
+    /* No filters apply, just use the FID */
+    CPLString soSQL;
+    soSQL.Printf("DELETE FROM \"%s\" WHERE \"%s\" = " CPL_FRMT_GIB,
+                 m_pszTableName, m_pszFidColumn, nFID);
+
+    OGRErr eErr = SQLCommand(m_poDS->GetDB(), soSQL.c_str());
+    if( eErr == OGRERR_NONE )
+        eErr = (sqlite3_changes(m_poDS->GetDB()) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
+    return eErr;
+}
+
+/************************************************************************/
+/*                        SyncToDisk()                                  */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::SyncToDisk()
+{
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    SaveExtent();
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                        StartTransaction()                            */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::StartTransaction()
+{
+    return m_poDS->StartTransaction();
+}
+
+
+/************************************************************************/
+/*                        CommitTransaction()                           */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::CommitTransaction()
+{
+    return m_poDS->CommitTransaction();
+}
+
+
+/************************************************************************/
+/*                        RollbackTransaction()                         */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::RollbackTransaction()
+{
+    return m_poDS->RollbackTransaction();
+}
+
+
+/************************************************************************/
+/*                        GetFeatureCount()                             */
+/************************************************************************/
+
+GIntBig OGRGeoPackageTableLayer::GetFeatureCount( CPL_UNUSED int bForce )
+{
+    if( m_poFilterGeom != NULL && !m_bFilterIsEnvelope )
+        return OGRGeoPackageLayer::GetFeatureCount();
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return 0;
+
+    /* Ignore bForce, because we always do a full count on the database */
+    OGRErr err;
+    CPLString soSQL;
+    if ( m_soFilter.length() > 0 )
+        soSQL.Printf("SELECT Count(*) FROM \"%s\" WHERE %s", m_pszTableName, m_soFilter.c_str());
+    else
+        soSQL.Printf("SELECT Count(*) FROM \"%s\" ", m_pszTableName);
+
+    /* Just run the query directly and get back integer */
+    GIntBig iFeatureCount = SQLGetInteger64(m_poDS->GetDB(), soSQL.c_str(), &err);
+
+    /* Generic implementation uses -1 for error condition, so we will too */
+    if ( err == OGRERR_NONE )
+        return iFeatureCount;
+    else
+        return -1;
+}
+
+
+/************************************************************************/
+/*                        GetExtent()                                   */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
+{
+    /* Extent already calculated! We're done. */
+    if ( m_poExtent != NULL )
+    {
+        if ( psExtent )
+        {
+            *psExtent = *m_poExtent;            
+        }
+        return OGRERR_NONE;
+    }
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    /* User is OK with expensive calculation, fall back to */
+    /* default implementation (scan all features) and save */
+    /* the result for later */
+    if ( bForce )
+    {
+        OGRErr err = OGRLayer::GetExtent(psExtent, bForce);
+        if ( err != OGRERR_NONE )
+            return err;
+    
+        if ( ! m_poExtent )
+            m_poExtent = new OGREnvelope( *psExtent );
+        else
+            *m_poExtent = *psExtent;
+        return SaveExtent();
+    }
+
+    return OGRERR_FAILURE;
+}
+
+
+
+/************************************************************************/
+/*                      TestCapability()                                */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::TestCapability ( const char * pszCap )
+{
+    if ( EQUAL(pszCap, OLCCreateField) ||
+         EQUAL(pszCap, OLCSequentialWrite) ||
+         EQUAL(pszCap, OLCDeleteFeature) ||
+         EQUAL(pszCap, OLCRandomWrite) )
+    {
+        return m_poDS->GetUpdate();
+    }
+    else if ( EQUAL(pszCap, OLCRandomRead) ||
+              EQUAL(pszCap, OLCTransactions) )
+    {
+        return TRUE;
+    }
+    else if ( EQUAL(pszCap, OLCFastSpatialFilter) )
+    {
+        return HasSpatialIndex();
+    }
+    else if ( EQUAL(pszCap, OLCFastGetExtent) )
+    {
+        if ( m_poExtent )
+            return TRUE;
+        else
+            return FALSE;
+    }
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
+    else
+    {
+        return OGRGeoPackageLayer::TestCapability(pszCap);
+    }
+}
+
+/************************************************************************/
+/*                     CreateSpatialIndexIfNecessary()                  */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::CreateSpatialIndexIfNecessary()
+{
+    if( bDeferedSpatialIndexCreation )
+    {
+        CreateSpatialIndex();
+    }
+}
+
+/************************************************************************/
+/*                       CreateSpatialIndex()                           */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::CreateSpatialIndex()
+{
+    char* pszSQL;
+    OGRErr err;
+
+    if( m_bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return FALSE;
+
+    bDeferedSpatialIndexCreation = FALSE;
+    
+    if( m_pszFidColumn == NULL )
+        return FALSE;
+
+    if( HasSpatialIndex() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Spatial index already existing");
+        return FALSE;
+    }
+
+    if( m_poFeatureDefn->GetGeomFieldCount() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Spatial index already existing");
+        return FALSE;
+    }
+    if( m_poDS->CreateExtensionsTableIfNecessary() != OGRERR_NONE )
+        return FALSE;
+
+    const char* pszT = m_pszTableName;
+    const char* pszC = m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+    const char* pszI = GetFIDColumn();
+
+    m_poDS->SoftStartTransaction();
+
+    /* Register the table in gpkg_extensions */
+    pszSQL = sqlite3_mprintf(
+                 "INSERT INTO gpkg_extensions "
+                 "(table_name,column_name,extension_name,definition,scope) "
+                 "VALUES ('%q', '%q', 'gpkg_rtree_index', 'GeoPackage 1.0 Specification Annex L', 'write-only')",
+                 pszT, pszC );
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Create virtual table */
+    if( !bDropRTreeTable )
+    {
+        pszSQL = sqlite3_mprintf(
+                    "CREATE VIRTUAL TABLE \"rtree_%s_%s\" USING rtree(id, minx, maxx, miny, maxy)",
+                    pszT, pszC );
+        err = SQLCommand(m_poDS->GetDB(), pszSQL);
+        sqlite3_free(pszSQL);
+        if( err != OGRERR_NONE )
+        {
+            m_poDS->SoftRollbackTransaction();
+            return FALSE;
+        }
+    }
+    bDropRTreeTable = FALSE;
+
+    /* Populate the RTree */
+    pszSQL = sqlite3_mprintf(
+                 "INSERT OR REPLACE INTO \"rtree_%s_%s\" "
+                 "SELECT \"%s\", st_minx(\"%s\"), st_maxx(\"%s\"), st_miny(\"%s\"), st_maxy(\"%s\") FROM \"%s\"",
+                 pszT, pszC, pszI, pszC, pszC, pszC, pszC, pszT );
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Define Triggers to Maintain Spatial Index Values */
+
+    /* Conditions: Insertion of non-empty geometry
+       Actions   : Insert record into rtree */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_insert\" AFTER INSERT ON \"%s\" "
+                   "WHEN (new.\"%s\" NOT NULL AND NOT ST_IsEmpty(NEW.\"%s\")) "
+                   "BEGIN "
+                   "INSERT OR REPLACE INTO \"rtree_%s_%s\" VALUES ("
+                   "NEW.\"%s\","
+                   "ST_MinX(NEW.\"%s\"), ST_MaxX(NEW.\"%s\"),"
+                   "ST_MinY(NEW.\"%s\"), ST_MaxY(NEW.\"%s\")"
+                   "); "
+                   "END",
+                   pszT, pszC, pszT,
+                   pszC, pszC,
+                   pszT, pszC,
+                   pszI,
+                   pszC, pszC,
+                   pszC, pszC);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Conditions: Update of geometry column to non-empty geometry
+               No row ID change
+       Actions   : Update record in rtree */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_update1\" AFTER UPDATE OF \"%s\" ON \"%s\" "
+                   "WHEN OLD.\"%s\" = NEW.\"%s\" AND "
+                   "(NEW.\"%s\" NOTNULL AND NOT ST_IsEmpty(NEW.\"%s\")) "
+                   "BEGIN "
+                   "INSERT OR REPLACE INTO \"rtree_%s_%s\" VALUES ("
+                   "NEW.\"%s\","
+                   "ST_MinX(NEW.\"%s\"), ST_MaxX(NEW.\"%s\"),"
+                   "ST_MinY(NEW.\"%s\"), ST_MaxY(NEW.\"%s\")"
+                   "); "
+                   "END",
+                   pszT, pszC, pszC, pszT,
+                   pszI, pszI,
+                   pszC, pszC,
+                   pszT, pszC,
+                   pszI,
+                   pszC, pszC,
+                   pszC, pszC);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Conditions: Update of geometry column to empty geometry
+               No row ID change
+       Actions   : Remove record from rtree */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_update2\" AFTER UPDATE OF \"%s\" ON \"%s\" "
+                   "WHEN OLD.\"%s\" = NEW.\"%s\" AND "
+                   "(NEW.\"%s\" ISNULL OR ST_IsEmpty(NEW.\"%s\")) "
+                   "BEGIN "
+                   "DELETE FROM \"rtree_%s_%s\" WHERE id = OLD.\"%s\"; "
+                   "END",
+                   pszT, pszC, pszC, pszT,
+                   pszI, pszI,
+                   pszC, pszC,
+                   pszT, pszC, pszI);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Conditions: Update of any column
+                    Row ID change
+                    Non-empty geometry
+        Actions   : Remove record from rtree for old <i>
+                    Insert record into rtree for new <i> */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_update3\" AFTER UPDATE OF \"%s\" ON \"%s\" "
+                   "WHEN OLD.\"%s\" != NEW.\"%s\" AND "
+                   "(NEW.\"%s\" NOTNULL AND NOT ST_IsEmpty(NEW.\"%s\")) "
+                   "BEGIN "
+                   "DELETE FROM \"rtree_%s_%s\" WHERE id = OLD.\"%s\"; "
+                   "INSERT OR REPLACE INTO \"rtree_%s_%s\" VALUES ("
+                   "NEW.\"%s\","
+                   "ST_MinX(NEW.\"%s\"), ST_MaxX(NEW.\"%s\"),"
+                   "ST_MinY(NEW.\"%s\"), ST_MaxY(NEW.\"%s\")"
+                   "); "
+                   "END",
+                   pszT, pszC, pszC, pszT,
+                   pszI, pszI,
+                   pszC, pszC,
+                   pszT, pszC, pszI,
+                   pszT, pszC,
+                   pszI,
+                   pszC, pszC,
+                   pszC, pszC);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Conditions: Update of any column
+                    Row ID change
+                    Empty geometry
+        Actions   : Remove record from rtree for old and new <i> */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_update4\" AFTER UPDATE ON \"%s\" "
+                   "WHEN OLD.\"%s\" != NEW.\"%s\" AND "
+                   "(NEW.\"%s\" ISNULL OR ST_IsEmpty(NEW.\"%s\")) "
+                   "BEGIN "
+                   "DELETE FROM \"rtree_%s_%s\" WHERE id IN (OLD.\"%s\", NEW.\"%s\"); "
+                   "END",
+                   pszT, pszC, pszT,
+                   pszI, pszI,
+                   pszC, pszC,
+                   pszT, pszC, pszI, pszI);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    /* Conditions: Row deleted
+        Actions   : Remove record from rtree for old <i> */
+    pszSQL = sqlite3_mprintf(
+                   "CREATE TRIGGER \"rtree_%s_%s_delete\" AFTER DELETE ON \"%s\" "
+                   "WHEN old.\"%s\" NOT NULL "
+                   "BEGIN "
+                   "DELETE FROM \"rtree_%s_%s\" WHERE id = OLD.\"%s\"; "
+                   "END",
+                   pszT, pszC, pszT,
+                   pszC,
+                   pszT, pszC, pszI);
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if( err != OGRERR_NONE )
+    {
+        m_poDS->SoftRollbackTransaction();
+        return FALSE;
+    }
+
+    m_poDS->SoftCommitTransaction();
+
+    m_bHasSpatialIndex = TRUE;
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                    CheckUnknownExtensions()                          */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::CheckUnknownExtensions()
+{
+    if( !m_poDS->HasExtensionsTable() )
+        return;
+
+    const char* pszT = m_pszTableName;
+
+    /* We have only the SQL functions needed by the 3 following extensions */
+    /* anything else will likely cause troubles */
+    char* pszSQL;
+
+    if( m_poFeatureDefn->GetGeomFieldCount() == 0 )
+    {
+        pszSQL = sqlite3_mprintf(
+                    "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name='%q'",
+                    pszT );
+    }
+    else
+    {
+        pszSQL = sqlite3_mprintf(
+                    "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name='%q' "
+                    "AND column_name='%q' AND extension_name NOT LIKE 'gpkg_geom_%s' AND extension_name NOT IN "
+                    "('gpkg_rtree_index', 'gpkg_geometry_type_trigger', 'gpkg_srs_id_trigger')",
+                    pszT,
+                    m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef(),
+                    m_poDS->GetGeometryTypeString(m_poFeatureDefn->GetGeomFieldDefn(0)->GetType()) );
+    }
+    SQLResult oResultTable;
+    OGRErr err = SQLQuery(m_poDS->GetDB(), pszSQL, &oResultTable);
+    sqlite3_free(pszSQL);
+    if ( err == OGRERR_NONE && oResultTable.nRowCount > 0 )
+    {
+        for(int i=0; i<oResultTable.nRowCount;i++)
+        {
+            const char* pszExtName = SQLResultGetValue(&oResultTable, 0, i);
+            const char* pszDefinition = SQLResultGetValue(&oResultTable, 1, i);
+            const char* pszScope = SQLResultGetValue(&oResultTable, 2, i);
+            if( pszExtName == NULL ) pszExtName = "(null)";
+            if( pszDefinition == NULL ) pszDefinition = "(null)";
+            if( pszScope == NULL ) pszScope = "(null)";
+            if( m_poDS->GetUpdate() && EQUAL(pszScope, "write-only") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Layer %s relies on the '%s' (%s) extension that should "
+                         "be implemented for safe write-support, but is not currently. "
+                         "Update of that layer are strongly discouraged to avoid corruption.",
+                         GetName(), pszExtName, pszDefinition);
+            }
+            else if( m_poDS->GetUpdate() && EQUAL(pszScope, "read-write") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Layer %s relies on the '%s' (%s) extension that should "
+                         "be implemented in order to read/write it safely, but is not currently. "
+                         "Some data may be missing while reading that layer, and updates are strongly discouraged.",
+                         GetName(), pszExtName, pszDefinition);
+            }
+            else if( EQUAL(pszScope, "read-write") )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Layer %s relies on the '%s' (%s) extension that should "
+                         "be implemented in order to read it safely, but is not currently. "
+                         "Some data may be missing while reading that layer.",
+                         GetName(), pszExtName, pszDefinition);
+            }
+        }
+    }
+    SQLResultFree(&oResultTable);
+}
+
+/************************************************************************/
+/*                     CreateGeometryExtensionIfNecessary()             */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::CreateGeometryExtensionIfNecessary(OGRwkbGeometryType eGType)
+{
+    eGType = wkbFlatten(eGType);
+    CPLAssert(eGType <= wkbMultiSurface);
+    if( m_anHasGeometryExtension[eGType] )
+        return TRUE;
+
+    if( m_poDS->CreateExtensionsTableIfNecessary() != OGRERR_NONE )
+        return FALSE;
+
+    const char* pszT = m_pszTableName;
+    const char* pszC = m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+    const char *pszGeometryType = m_poDS->GetGeometryTypeString(eGType);
+
+    /* Register the table in gpkg_extensions */
+    char* pszSQL = sqlite3_mprintf(
+                "INSERT INTO gpkg_extensions "
+                "(table_name,column_name,extension_name,definition,scope) "
+                "VALUES ('%q', '%q', 'gpkg_geom_%s', 'GeoPackage 1.0 Specification Annex J', 'write-only')",
+                pszT, pszC, pszGeometryType);
+    OGRErr err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if ( err != OGRERR_NONE )
+        return FALSE;
+
+    m_anHasGeometryExtension[eGType] = TRUE;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                        HasSpatialIndex()                             */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::HasSpatialIndex()
+{
+    if( m_bHasSpatialIndex >= 0 )
+        return m_bHasSpatialIndex;
+    m_bHasSpatialIndex = FALSE;
+
+    if( m_poFeatureDefn->GetGeomFieldCount() == 0 ||
+        !m_poDS->HasExtensionsTable() )
+        return FALSE;
+
+    const char* pszT = m_pszTableName;
+    const char* pszC = m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+
+    /* Check into gpkg_extensions */
+    char* pszSQL = sqlite3_mprintf(
+                 "SELECT * FROM gpkg_extensions WHERE table_name='%q' "
+                 "AND column_name='%q' AND extension_name='gpkg_rtree_index'",
+                 pszT, pszC );
+    SQLResult oResultTable;
+    OGRErr err = SQLQuery(m_poDS->GetDB(), pszSQL, &oResultTable);
+    sqlite3_free(pszSQL);
+    if ( err == OGRERR_NONE && oResultTable.nRowCount == 1 )
+    {
+        m_bHasSpatialIndex = TRUE;
+    }
+    SQLResultFree(&oResultTable);
+    
+    return m_bHasSpatialIndex;
+}
+
+/************************************************************************/
+/*                        DropSpatialIndex()                            */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::DropSpatialIndex(int bCalledFromSQLFunction)
+{
+    if( !HasSpatialIndex() )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Spatial index not existing");
+        return FALSE;
+    }
+
+    const char* pszT = m_pszTableName;
+    const char* pszC =m_poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+    char* pszSQL;
+
+    pszSQL = sqlite3_mprintf("DELETE FROM gpkg_extensions WHERE table_name='%q' "
+                 "AND column_name='%q' AND extension_name='gpkg_rtree_index'",
+                 pszT, pszC );
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    if( bCalledFromSQLFunction )
+    {
+        /* We cannot drop a table from a SQLite function call, so we just */
+        /* remove the content and memorize that we will have to delete the */
+        /* table later */
+        bDropRTreeTable = TRUE;
+        pszSQL = sqlite3_mprintf("DELETE FROM \"rtree_%s_%s\"", pszT, pszC);
+    }
+    else
+    {
+        pszSQL = sqlite3_mprintf("DROP TABLE \"rtree_%s_%s\"", pszT, pszC);
+    }
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_insert\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_update1\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_update2\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_update3\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_update4\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    pszSQL = sqlite3_mprintf("DROP TRIGGER \"rtree_%s_%s_delete\"", pszT, pszC);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    m_bHasSpatialIndex = FALSE;
+    return TRUE;
+}
+
+/************************************************************************/
+/*                          RenameTo()                                  */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::RenameTo(const char* pszDstTableName)
+{
+    int bHasSpatialIndex = HasSpatialIndex();
+
+    if( bHasSpatialIndex )
+    {
+        DropSpatialIndex();
+    }
+
+    /* We also need to update GeoPackage metadata tables */
+    char* pszSQL;
+    pszSQL = sqlite3_mprintf(
+            "UPDATE gpkg_geometry_columns SET table_name = '%s' WHERE table_name = '%s'",
+            pszDstTableName, m_pszTableName);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    
+    pszSQL = sqlite3_mprintf(
+            "UPDATE gpkg_contents SET table_name = '%s' WHERE table_name = '%s'",
+            pszDstTableName, m_pszTableName);
+    SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+
+    CPLFree(m_pszTableName);
+    m_pszTableName = CPLStrdup(pszDstTableName);
+
+    if( bHasSpatialIndex )
+    {
+        CreateSpatialIndex();
+    }
+}
+
+/************************************************************************/
+/*                          SetSpatialFilter()                          */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
+
+{
+    if( InstallFilter( poGeomIn ) )
+    {
+        BuildWhere();
+
+        ResetReading();
+    }
+}
+
+/************************************************************************/
+/*                        HasFastSpatialFilter()                        */
+/************************************************************************/
+
+int OGRGeoPackageTableLayer::HasFastSpatialFilter(int iGeomCol)
+{
+    if( iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount() )
+        return FALSE;
+    return HasSpatialIndex();
+}
+
+/************************************************************************/
+/*                           GetSpatialWhere()                          */
+/************************************************************************/
+
+CPLString OGRGeoPackageTableLayer::GetSpatialWhere(int iGeomCol,
+                                               OGRGeometry* poFilterGeom)
+{
+    CPLString osSpatialWHERE;
+
+    if( iGeomCol < 0 || iGeomCol >= m_poFeatureDefn->GetGeomFieldCount() )
+        return osSpatialWHERE;
+
+    const char* pszT = m_pszTableName;
+    const char* pszC = m_poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef();
+
+    if( poFilterGeom != NULL )
+    {
+        OGREnvelope  sEnvelope;
+
+        poFilterGeom->getEnvelope( &sEnvelope );
+        
+        if( CPLIsInf(sEnvelope.MinX) || CPLIsInf(sEnvelope.MinY) ||
+            CPLIsInf(sEnvelope.MaxX) || CPLIsInf(sEnvelope.MaxY) )
+        {
+            return osSpatialWHERE;
+        }
+
+        if( HasSpatialIndex() )
+        {
+            osSpatialWHERE.Printf("ROWID IN ( SELECT id FROM \"rtree_%s_%s\" WHERE "
+                            "maxx >= %.12f AND minx <= %.12f AND maxy >= %.12f AND miny <= %.12f)",
+                            pszT, pszC,
+                            sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
+                            sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
+        }
+        else
+        {
+            /* A bit inefficient but still faster than OGR filtering */
+            osSpatialWHERE.Printf(
+                        "(ST_MaxX(\"%s\") >= %.12f AND ST_MinX(\"%s\") <= %.12f AND "
+                        "ST_MaxY(\"%s\") >= %.12f AND ST_MinY(\"%s\") <= %.12f)",
+                        pszC, sEnvelope.MinX - 1e-11,
+                        pszC, sEnvelope.MaxX + 1e-11,
+                        pszC, sEnvelope.MinY - 1e-11,
+                        pszC, sEnvelope.MaxY + 1e-11);
+        }
+    }
+
+    return osSpatialWHERE;
+}
+/************************************************************************/
+/*                             BuildWhere()                             */
+/*                                                                      */
+/*      Build the WHERE statement appropriate to the current set of     */
+/*      criteria (spatial and attribute queries).                       */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::BuildWhere()
+
+{
+    m_soFilter = "";
+
+    CPLString osSpatialWHERE = GetSpatialWhere(m_iGeomFieldFilter,
+                                               m_poFilterGeom);
+    if (osSpatialWHERE.size() != 0)
+    {
+        m_soFilter += osSpatialWHERE;
+    }
+
+    if( osQuery.size() > 0 )
+    {
+        if( m_soFilter.size() == 0 )
+        {
+            m_soFilter += osQuery;
+        }
+        else    
+        {
+            m_soFilter += " AND (";
+            m_soFilter += osQuery;
+            m_soFilter += ")";
+        }
+    }
+}
+
+/************************************************************************/
+/*                        SetCreationParameters()                       */
+/************************************************************************/
+
+void OGRGeoPackageTableLayer::SetCreationParameters( OGRwkbGeometryType eGType,
+                                                     const char* pszGeomColumnName,
+                                                     int bGeomNullable,
+                                                     OGRSpatialReference* poSRS,
+                                                     const char* pszFIDColumnName,
+                                                     const char* pszIdentifier,
+                                                     const char* pszDescription )
+{
+    m_bDeferredCreation = TRUE;
+    m_pszFidColumn = CPLStrdup(pszFIDColumnName);
+    m_poFeatureDefn = new OGRFeatureDefn( m_pszTableName );
+    SetDescription( m_poFeatureDefn->GetName() );
+    m_poFeatureDefn->SetGeomType(wkbNone);
+    m_poFeatureDefn->Reference();
+    if( eGType != wkbNone )
+    {
+        OGRGeomFieldDefn oGeomFieldDefn(pszGeomColumnName, eGType);
+        if( poSRS )
+            m_iSrs = m_poDS->GetSrsId(poSRS);
+        oGeomFieldDefn.SetSpatialRef(poSRS);
+        oGeomFieldDefn.SetNullable(bGeomNullable);
+        m_poFeatureDefn->AddGeomFieldDefn(&oGeomFieldDefn);
+    }
+    if( pszIdentifier )
+    {
+        m_osIdentifierLCO = pszIdentifier;
+        OGRLayer::SetMetadataItem("IDENTIFIER", pszIdentifier);
+    }
+    if( pszDescription )
+    {
+        m_osDescriptionLCO = pszDescription;
+        OGRLayer::SetMetadataItem("DESCRIPTION", pszDescription);
+    }
+}
+
+/************************************************************************/
+/*                      RegisterGeometryColumn()                        */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::RegisterGeometryColumn()
+{
+    OGRwkbGeometryType eGType = GetGeomType();
+    const char *pszGeometryType = m_poDS->GetGeometryTypeString(eGType);
+    /* Requirement 27: The z value in a gpkg_geometry_columns table row */
+    /* SHALL be one of 0 (none), 1 (mandatory), or 2 (optional) */
+    int bGeometryTypeHasZ = wkbHasZ(eGType);
+
+    /* Update gpkg_geometry_columns with the table info */
+    char* pszSQL = sqlite3_mprintf(
+        "INSERT INTO gpkg_geometry_columns "
+        "(table_name,column_name,geometry_type_name,srs_id,z,m)"
+        " VALUES "
+        "('%q','%q','%q',%d,%d,%d)",
+        GetName(),GetGeometryColumn(),pszGeometryType,
+        m_iSrs,bGeometryTypeHasZ,0);
+
+    OGRErr err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if ( err != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    if( OGR_GT_IsNonLinear( eGType ) )
+        CreateGeometryExtensionIfNecessary(eGType);
+    
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                      RunDeferredCreationIfNecessary()                */
+/************************************************************************/
+
+OGRErr OGRGeoPackageTableLayer::RunDeferredCreationIfNecessary()
+{
+    if( !m_bDeferredCreation )
+        return OGRERR_NONE;
+    m_bDeferredCreation = FALSE;
+
+    const char* pszLayerName = m_poFeatureDefn->GetName();
+    OGRwkbGeometryType eGType = GetGeomType();
+
+    int bIsSpatial = (eGType != wkbNone);
+
+    /* Requirement 25: The geometry_type_name value in a gpkg_geometry_columns */
+    /* row SHALL be one of the uppercase geometry type names specified in */
+    /* Geometry Types (Normative). */
+    const char *pszGeometryType = m_poDS->GetGeometryTypeString(eGType);
+
+    /* Create the table! */
+    char *pszSQL = NULL;
+    CPLString osCommand;
+
+    pszSQL = sqlite3_mprintf(
+        "CREATE TABLE \"%s\" ( "
+        "\"%s\" INTEGER PRIMARY KEY AUTOINCREMENT",
+            pszLayerName, m_pszFidColumn);
+    osCommand += pszSQL;
+    sqlite3_free(pszSQL);
+    
+    if( GetGeomType() != wkbNone )
+    {
+        pszSQL = sqlite3_mprintf(", '%q' %s",
+                                 GetGeometryColumn(), pszGeometryType);
+        osCommand += pszSQL;
+        sqlite3_free(pszSQL);
+        if( !m_poFeatureDefn->GetGeomFieldDefn(0)->IsNullable() )
+        {
+            osCommand += " NOT NULL";
+        }
+    }
+
+    for(int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++ )
+    {
+        if( i == m_iFIDAsRegularColumnIndex )
+            continue;
+        OGRFieldDefn* poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
+        pszSQL = sqlite3_mprintf(", '%q' %s",
+                                 poFieldDefn->GetNameRef(),
+                                 GPkgFieldFromOGR(poFieldDefn->GetType(),
+                                                  poFieldDefn->GetSubType(),
+                                                  poFieldDefn->GetWidth()));
+        osCommand += pszSQL;
+        sqlite3_free(pszSQL);
+        if( !poFieldDefn->IsNullable() )
+        {
+            osCommand += " NOT NULL";
+        }
+        const char* pszDefault = poFieldDefn->GetDefault();
+        if( pszDefault != NULL &&
+            (!poFieldDefn->IsDefaultDriverSpecific() ||
+             (pszDefault[0] == '(' && pszDefault[strlen(pszDefault)-1] == ')' &&
+             (EQUALN(pszDefault+1, "strftime", strlen("strftime")) ||
+              EQUALN(pszDefault+1, " strftime", strlen(" strftime"))))) )
+        {
+            osCommand += " DEFAULT ";
+            OGRField sField;
+            if( poFieldDefn->GetType() == OFTDateTime &&
+                OGRParseDate(pszDefault, &sField, 0) )
+            {
+                char* pszXML = OGRGetXMLDateTime(&sField);
+                osCommand += pszXML;
+                CPLFree(pszXML);
+            }
+            /* Make sure CURRENT_TIMESTAMP is translated into appropriate format for GeoPackage */
+            else if( poFieldDefn->GetType() == OFTDateTime &&
+                     EQUAL(pszDefault, "CURRENT_TIMESTAMP") )
+            {
+                osCommand += "(strftime('%Y-%m-%dT%H:%M:%fZ','now'))";
+            }
+            else
+            {
+                osCommand += poFieldDefn->GetDefault();
+            }
+        }
+    }
+
+    osCommand += ")";
+
+#ifdef DEBUG
+    CPLDebug( "GPKG", "exec(%s)", osCommand.c_str() );
+#endif
+    OGRErr err = SQLCommand(m_poDS->GetDB(), osCommand.c_str());
+    if ( OGRERR_NONE != err )
+        return OGRERR_FAILURE;
+
+    /* Update gpkg_contents with the table info */
+    if ( bIsSpatial )
+        err = RegisterGeometryColumn();
+    else
+        err = m_poDS->CreateGDALAspatialExtension();
+
+    if ( err != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    const char* pszIdentifier = GetMetadataItem("IDENTIFIER");
+    if( pszIdentifier == NULL )
+        pszIdentifier = pszLayerName;
+    const char* pszDescription = GetMetadataItem("DESCRIPTION");
+    if( pszDescription == NULL )
+        pszDescription = "";
+    pszSQL = sqlite3_mprintf(
+        "INSERT INTO gpkg_contents "
+        "(table_name,data_type,identifier,description,last_change,srs_id)"
+        " VALUES "
+        "('%q','%q','%q','%q',strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ',CURRENT_TIMESTAMP),%d)",
+        pszLayerName, (bIsSpatial ? "features": "aspatial"), pszIdentifier, pszDescription, m_iSrs);
+
+    err = SQLCommand(m_poDS->GetDB(), pszSQL);
+    sqlite3_free(pszSQL);
+    if ( err != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    ResetReading();
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            GetMetadata()                             */
+/************************************************************************/
+
+char **OGRGeoPackageTableLayer::GetMetadata( const char *pszDomain )
+
+{
+    if( m_bHasReadMetadataFromStorage )
+        return OGRLayer::GetMetadata( pszDomain );
+
+    m_bHasReadMetadataFromStorage = TRUE;
+
+    if ( !m_poDS->HasMetadataTables() )
+        return OGRLayer::GetMetadata( pszDomain );
+
+    char* pszSQL;
+
+    pszSQL = sqlite3_mprintf(
+        "SELECT md.metadata, md.md_standard_uri, md.mime_type, mdr.reference_scope FROM gpkg_metadata md "
+        "JOIN gpkg_metadata_reference mdr ON (md.id = mdr.md_file_id ) "
+        "WHERE mdr.table_name = '%q' ORDER BY md.id",
+        m_pszTableName);
+
+
+    SQLResult oResult;
+    OGRErr err = SQLQuery(m_poDS->GetDB(), pszSQL, &oResult);
+    sqlite3_free(pszSQL);
+    if  ( err != OGRERR_NONE )
+    {
+        SQLResultFree(&oResult);
+        return OGRLayer::GetMetadata( pszDomain );
+    }
+
+    char** papszMetadata = CSLDuplicate(OGRLayer::GetMetadata());
+
+    /* GDAL metadata */
+    for(int i=0;i<oResult.nRowCount;i++)
+    {
+        const char *pszMetadata = SQLResultGetValue(&oResult, 0, i);
+        const char* pszMDStandardURI = SQLResultGetValue(&oResult, 1, i);
+        const char* pszMimeType = SQLResultGetValue(&oResult, 2, i);
+        //const char* pszReferenceScope = SQLResultGetValue(&oResult, 3, i);
+        //int bIsGPKGScope = EQUAL(pszReferenceScope, "geopackage");
+        if( pszMetadata == NULL )
+            continue;
+        if( pszMDStandardURI != NULL && EQUAL(pszMDStandardURI, "http://gdal.org") &&
+            pszMimeType != NULL && EQUAL(pszMimeType, "text/xml") )
+        {
+            CPLXMLNode* psXMLNode = CPLParseXMLString(pszMetadata);
+            if( psXMLNode )
+            {
+                GDALMultiDomainMetadata oLocalMDMD;
+                oLocalMDMD.XMLInit(psXMLNode, FALSE);
+
+                papszMetadata = CSLMerge(papszMetadata, oLocalMDMD.GetMetadata());
+                char** papszDomainList = oLocalMDMD.GetDomainList();
+                char** papszIter = papszDomainList;
+                while( papszIter && *papszIter )
+                {
+                    if( !EQUAL(*papszIter, "") )
+                        oMDMD.SetMetadata(oLocalMDMD.GetMetadata(*papszIter), *papszIter);
+                    papszIter ++;
+                }
+
+                CPLDestroyXMLNode(psXMLNode);
+            }
+        }
+    }
+
+    OGRLayer::SetMetadata(papszMetadata);
+    CSLDestroy(papszMetadata);
+    papszMetadata = NULL;
+
+    /* Add non-GDAL metadata now */
+    int nNonGDALMDILocal = 1;
+    for(int i=0;i<oResult.nRowCount;i++)
+    {
+        const char *pszMetadata = SQLResultGetValue(&oResult, 0, i);
+        const char* pszMDStandardURI = SQLResultGetValue(&oResult, 1, i);
+        const char* pszMimeType = SQLResultGetValue(&oResult, 2, i);
+        //const char* pszReferenceScope = SQLResultGetValue(&oResult, 3, i);
+        //int bIsGPKGScope = EQUAL(pszReferenceScope, "geopackage");
+        if( pszMetadata == NULL )
+            continue;
+        if( pszMDStandardURI != NULL && EQUAL(pszMDStandardURI, "http://gdal.org") &&
+            pszMimeType != NULL && EQUAL(pszMimeType, "text/xml") )
+            continue;
+
+        /*if( strcmp( pszMDStandardURI, "http://www.isotc211.org/2005/gmd" ) == 0 &&
+            strcmp( pszMimeType, "text/xml" ) == 0 )
+        {
+            char* apszMD[2];
+            apszMD[0] = (char*)pszMetadata;
+            apszMD[1] = NULL;
+            oMDMD.SetMetadata(apszMD, "xml:MD_Metadata");
+        }
+        else*/
+        {
+            oMDMD.SetMetadataItem( CPLSPrintf("GPKG_METADATA_ITEM_%d", nNonGDALMDILocal),
+                                    pszMetadata );
+            nNonGDALMDILocal ++;
+        }
+    }
+
+    SQLResultFree(&oResult);
+
+    return OGRLayer::GetMetadata(pszDomain);
+}
+
+/************************************************************************/
+/*                          GetMetadataItem()                           */
+/************************************************************************/
+
+const char *OGRGeoPackageTableLayer::GetMetadataItem( const char * pszName,
+                                                    const char * pszDomain )
+{
+    return CSLFetchNameValue( GetMetadata(pszDomain), pszName );
+}
+
+/************************************************************************/
+/*                      GetMetadataDomainList()                         */
+/************************************************************************/
+
+char **OGRGeoPackageTableLayer::GetMetadataDomainList()
+{
+    GetMetadata();
+    return OGRLayer::GetMetadataDomainList();
+}
+
+/************************************************************************/
+/*                            SetMetadata()                             */
+/************************************************************************/
+
+CPLErr OGRGeoPackageTableLayer::SetMetadata( char ** papszMetadata, const char * pszDomain )
+{
+    GetMetadata(); /* force loading from storage if needed */
+    CPLErr eErr = OGRLayer::SetMetadata(papszMetadata, pszDomain);
+    m_poDS->SetMetadataDirty();
+    if( pszDomain == NULL || EQUAL(pszDomain, "") )
+    {
+        if( m_osIdentifierLCO.size() )
+            OGRLayer::SetMetadataItem("IDENTIFIER", m_osIdentifierLCO);
+        if( m_osDescriptionLCO.size() )
+            OGRLayer::SetMetadataItem("DESCRIPTION", m_osDescriptionLCO);
+    }
+    return eErr;
+}
+
+/************************************************************************/
+/*                          SetMetadataItem()                           */
+/************************************************************************/
+
+CPLErr OGRGeoPackageTableLayer::SetMetadataItem( const char * pszName,
+                                                 const char * pszValue,
+                                                 const char * pszDomain )
+{
+    GetMetadata(); /* force loading from storage if needed */
+    if( m_osIdentifierLCO.size() && EQUAL(pszName, "IDENTIFIER") &&
+        (pszDomain == NULL || EQUAL(pszDomain, "")) )
+        return CE_None;
+    if( m_osDescriptionLCO.size() && EQUAL(pszName, "DESCRIPTION") &&
+        (pszDomain == NULL || EQUAL(pszDomain, "")) )
+        return CE_None;
+    m_poDS->SetMetadataDirty();
+    return OGRLayer::SetMetadataItem(pszName, pszValue, pszDomain);
+}
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.cpp b/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.cpp
index 94d84ac..175afbf 100644
--- a/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.cpp
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.cpp
@@ -38,13 +38,15 @@ OGRErr SQLCommand(sqlite3 * poDb, const char * pszSQL)
     CPLAssert( pszSQL != NULL );
 
     char *pszErrMsg = NULL;
+    //CPLDebug("GPKG", "exec(%s)", pszSQL);
     int rc = sqlite3_exec(poDb, pszSQL, NULL, NULL, &pszErrMsg);
     
     if ( rc != SQLITE_OK )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "sqlite3_exec(%s) failed: %s",
-                  pszSQL, pszErrMsg );
+                  pszSQL, pszErrMsg ? pszErrMsg : "" );
+        sqlite3_free( pszErrMsg );
         return OGRERR_FAILURE;
     }
     
@@ -150,12 +152,13 @@ int SQLResultGetValueAsInteger(const SQLResult * poResult, int iColNum, int iRow
 }
 
 /* Returns the first row of first column of SQL as integer */
-int SQLGetInteger(sqlite3 * poDb, const char * pszSQL, OGRErr *err)
+GIntBig SQLGetInteger64(sqlite3 * poDb, const char * pszSQL, OGRErr *err)
 {
     CPLAssert( poDb != NULL );
     
     sqlite3_stmt *poStmt;
-    int rc, i;
+    int rc;
+    GIntBig i;
     
     /* Prepare the SQL */
     rc = sqlite3_prepare_v2(poDb, pszSQL, strlen(pszSQL), &poStmt, NULL);
@@ -172,17 +175,22 @@ int SQLGetInteger(sqlite3 * poDb, const char * pszSQL, OGRErr *err)
     if ( rc != SQLITE_ROW )
     {
         if ( err ) *err = OGRERR_FAILURE;
+        sqlite3_finalize(poStmt);
         return 0;
     }
     
     /* Read the integer from the row */
-    i = sqlite3_column_int(poStmt, 0);
+    i = sqlite3_column_int64(poStmt, 0);
     sqlite3_finalize(poStmt);
     
     if ( err ) *err = OGRERR_NONE;
     return i;
 }
 
+int SQLGetInteger(sqlite3 * poDb, const char * pszSQL, OGRErr *err)
+{
+    return (int)SQLGetInteger64(poDb, pszSQL, err);
+}
 
 /* Requirement 20: A GeoPackage SHALL store feature table geometries */
 /* with the basic simple feature geometry types (Geometry, Point, */
@@ -192,104 +200,82 @@ int SQLGetInteger(sqlite3 * poDb, const char * pszSQL, OGRErr *err)
 OGRwkbGeometryType GPkgGeometryTypeToWKB(const char *pszGpkgType, int bHasZ)
 {
     OGRwkbGeometryType oType;
-    
+
     if ( EQUAL("Geometry", pszGpkgType) )
         oType = wkbUnknown;
-    else if ( EQUAL("Point", pszGpkgType) )
-        oType =  wkbPoint;
-    else if ( EQUAL("LineString", pszGpkgType) )
-        oType =  wkbLineString;
-    else if ( EQUAL("Polygon", pszGpkgType) )
-        oType =  wkbPolygon;
-    else if ( EQUAL("MultiPoint", pszGpkgType) )
-        oType =  wkbMultiPoint;
-    else if ( EQUAL("MultiLineString", pszGpkgType) )
-        oType =  wkbMultiLineString;
-    else if ( EQUAL("MultiPolygon", pszGpkgType) )
-        oType =  wkbMultiPolygon;
-    else if ( EQUAL("GeometryCollection", pszGpkgType) )
+    /* The 1.0 spec is not completely clear on what should be used... */
+    else if ( EQUAL("GeomCollection", pszGpkgType) ||
+              EQUAL("GeometryCollection", pszGpkgType) )
         oType =  wkbGeometryCollection;
     else
-        oType =  wkbNone;
+    {
+        oType = OGRFromOGCGeomType(pszGpkgType);
+        if( oType == wkbUnknown )
+            oType = wkbNone;
+    }
 
     if ( (oType != wkbNone) && bHasZ )
     {
-        unsigned int oi = oType;
-        oi &= wkb25DBit;
-        oType = (OGRwkbGeometryType)oi;
+        oType = wkbSetZ(oType);
     }
 
     return oType;
 }
 
-/* Requirement 20: A GeoPackage SHALL store feature table geometries */
-/* with the basic simple feature geometry types (Geometry, Point, */
-/* LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, */
-/* GeomCollection) */
-/* http://opengis.github.io/geopackage/#geometry_types */
-const char* GPkgGeometryTypeFromWKB(OGRwkbGeometryType oType)
-{
-    oType = wkbFlatten(oType);
-    
-    switch(oType)
-    {
-        case wkbPoint:
-            return "point";
-        case wkbLineString:
-            return "linestring";
-        case wkbPolygon:
-            return "polygon";
-        case wkbMultiPoint:
-            return "multipoint";
-        case wkbMultiLineString:
-            return "multilinestring";
-        case wkbMultiPolygon:
-            return "multipolygon";
-        case wkbGeometryCollection:
-            return "geometrycollection";
-        default:
-            return NULL;
-    }
-}
-
 /* Requirement 5: The columns of tables in a GeoPackage SHALL only be */
 /* declared using one of the data types specified in table GeoPackage */
 /* Data Types. */
 /* http://opengis.github.io/geopackage/#table_column_data_types */
-OGRFieldType GPkgFieldToOGR(const char *pszGpkgType)
+OGRFieldType GPkgFieldToOGR(const char *pszGpkgType, OGRFieldSubType& eSubType,
+                            int& nMaxWidth)
 {
+    eSubType = OFSTNone;
+    nMaxWidth = 0;
+
     /* Integer types */
-    if ( STRNCASECMP("INTEGER", pszGpkgType, 7) == 0 )
+    if ( STRNCASECMP("INT", pszGpkgType, 3) == 0 )
+        return OFTInteger64;
+    else if ( EQUAL("MEDIUMINT", pszGpkgType) )
         return OFTInteger;
-    else if ( STRNCASECMP("INT", pszGpkgType, 3) == 0 )
-        return OFTInteger;
-    else if ( STRNCASECMP("MEDIUMINT", pszGpkgType, 9) == 0 )
-        return OFTInteger;
-    else if ( STRNCASECMP("SMALLINT", pszGpkgType, 8) == 0 )
+    else if ( EQUAL("SMALLINT", pszGpkgType) )
+    {
+        eSubType = OFSTInt16;
         return OFTInteger;
-    else if ( STRNCASECMP("TINYINT", pszGpkgType, 7) == 0 )
+    }
+    else if ( EQUAL("TINYINT", pszGpkgType) )
         return OFTInteger;
-    else if ( STRNCASECMP("BOOLEAN", pszGpkgType, 7) == 0 )
+    else if ( EQUAL("BOOLEAN", pszGpkgType) )
+    {
+        eSubType = OFSTBoolean;
         return OFTInteger;
+    }
 
     /* Real types */
-    else if ( STRNCASECMP("FLOAT", pszGpkgType, 5) == 0 )
+    else if ( EQUAL("FLOAT", pszGpkgType) )
+    {
+        eSubType = OFSTFloat32;
         return OFTReal;
-    else if ( STRNCASECMP("DOUBLE", pszGpkgType, 6) == 0 )
+    }
+    else if ( EQUAL("DOUBLE", pszGpkgType) )
         return OFTReal;
-    else if ( STRNCASECMP("REAL", pszGpkgType, 4) == 0 )
+    else if ( EQUAL("REAL", pszGpkgType) )
         return OFTReal;
         
     /* String/binary types */
     else if ( STRNCASECMP("TEXT", pszGpkgType, 4) == 0 )
+    {
+        if( pszGpkgType[4] == '(' )
+            nMaxWidth = atoi(pszGpkgType+5);
         return OFTString;
+    }
+        
     else if ( STRNCASECMP("BLOB", pszGpkgType, 4) == 0 )
         return OFTBinary;
         
     /* Date types */
-    else if ( STRNCASECMP("DATE", pszGpkgType, 4) == 0 )
+    else if ( EQUAL("DATE", pszGpkgType) )
         return OFTDate;
-    else if ( STRNCASECMP("DATETIME", pszGpkgType, 8) == 0 )
+    else if ( EQUAL("DATETIME", pszGpkgType) )
         return OFTDateTime;
 
     /* Illegal! */
@@ -301,16 +287,36 @@ OGRFieldType GPkgFieldToOGR(const char *pszGpkgType)
 /* declared using one of the data types specified in table GeoPackage */
 /* Data Types. */
 /* http://opengis.github.io/geopackage/#table_column_data_types */
-const char* GPkgFieldFromOGR(OGRFieldType nType)
+const char* GPkgFieldFromOGR(OGRFieldType nType, OGRFieldSubType eSubType,
+                             int nMaxWidth)
 {
     switch(nType)
     {
         case OFTInteger:
+        {
+            if( eSubType == OFSTBoolean )
+                return "BOOLEAN";
+            else if( eSubType == OFSTInt16 )
+                return "SMALLINT";
+            else
+                return "MEDIUMINT";
+        }
+        case OFTInteger64:
             return "INTEGER";
         case OFTReal:
-            return "REAL";
+        {
+            if( eSubType == OFSTFloat32 )
+                return "FLOAT";
+            else
+                return "REAL";
+        }
         case OFTString:
-            return "TEXT";
+        {
+            if( nMaxWidth > 0 )
+                return CPLSPrintf("TEXT(%d)", nMaxWidth);
+            else
+                return "TEXT";
+        }
         case OFTBinary:
             return "BLOB";
         case OFTDate:
@@ -318,7 +324,7 @@ const char* GPkgFieldFromOGR(OGRFieldType nType)
         case OFTDateTime:
             return "DATETIME";
         default:
-            return NULL;
+            return "TEXT";
     }
 }
 
@@ -526,7 +532,7 @@ OGRErr GPkgHeaderFromWKB(const GByte *pabyGpkg, GPkgHeader *poHeader)
     
     /* Envelope */
     double *padPtr = (double*)(pabyGpkg+8);
-    if ( poHeader->iDims == 2 )
+    if ( poHeader->iDims >= 2 )
     {
         poHeader->MinX = padPtr[0];
         poHeader->MaxX = padPtr[1];
@@ -557,7 +563,7 @@ OGRErr GPkgHeaderFromWKB(const GByte *pabyGpkg, GPkgHeader *poHeader)
     return OGRERR_NONE;
 }
 
-OGRGeometry* GPkgGeometryToOGR(GByte *pabyGpkg, size_t szGpkg, OGRSpatialReference *poSrs)
+OGRGeometry* GPkgGeometryToOGR(const GByte *pabyGpkg, size_t szGpkg, OGRSpatialReference *poSrs)
 {
     CPLAssert( pabyGpkg != NULL );
     
@@ -570,11 +576,11 @@ OGRGeometry* GPkgGeometryToOGR(GByte *pabyGpkg, size_t szGpkg, OGRSpatialReferen
         return NULL;
 
     /* WKB pointer */
-    GByte *pabyWkb = pabyGpkg + oHeader.szHeader;
+    const GByte *pabyWkb = pabyGpkg + oHeader.szHeader;
     size_t szWkb = szGpkg - oHeader.szHeader;
 
     /* Parse WKB */
-    err = OGRGeometryFactory::createFromWkb(pabyWkb, poSrs, &poGeom, szWkb);
+    err = OGRGeometryFactory::createFromWkb((GByte*)pabyWkb, poSrs, &poGeom, szWkb);
     if ( err != OGRERR_NONE )
         return NULL;
 
@@ -582,11 +588,13 @@ OGRGeometry* GPkgGeometryToOGR(GByte *pabyGpkg, size_t szGpkg, OGRSpatialReferen
 }
 
 
-OGRErr GPkgEnvelopeToOGR(GByte *pabyGpkg, CPL_UNUSED size_t szGpkg, OGREnvelope *poEnv)
+OGRErr GPkgEnvelopeToOGR(GByte *pabyGpkg,
+                         CPL_UNUSED size_t szGpkg,
+                         OGREnvelope *poEnv)
 {
     CPLAssert( poEnv != NULL );
     CPLAssert( pabyGpkg != NULL );
-    
+
     GPkgHeader oHeader;
 
     /* Read header */
diff --git a/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.h b/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.h
index 26c27fb..bad3894 100644
--- a/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.h
+++ b/ogr/ogrsf_frmts/gpkg/ogrgeopackageutility.h
@@ -56,6 +56,7 @@ typedef struct
 
 OGRErr              SQLCommand(sqlite3 *poDb, const char * pszSQL);
 int                 SQLGetInteger(sqlite3 * poDb, const char * pszSQL, OGRErr *err);
+GIntBig             SQLGetInteger64(sqlite3 * poDb, const char * pszSQL, OGRErr *err);
 
 OGRErr              SQLResultInit(SQLResult * poResult);
 OGRErr              SQLQuery(sqlite3 *poDb, const char * pszSQL, SQLResult * poResult);
@@ -66,13 +67,12 @@ OGRErr              SQLResultFree(SQLResult * poResult);
 
 int                 SQLiteFieldFromOGR(OGRFieldType nType);
 
-OGRFieldType        GPkgFieldToOGR(const char *pszGpkgType);
-const char*         GPkgFieldFromOGR(OGRFieldType nType);
+OGRFieldType        GPkgFieldToOGR(const char *pszGpkgType, OGRFieldSubType& eSubType, int& nMaxWidth);
+const char*         GPkgFieldFromOGR(OGRFieldType nType, OGRFieldSubType eSubType, int nMaxWidth);
 OGRwkbGeometryType  GPkgGeometryTypeToWKB(const char *pszGpkgType, int bHasZ);
-const char*         GPkgGeometryTypeFromWKB(OGRwkbGeometryType oType);
 
 GByte*              GPkgGeometryFromOGR(const OGRGeometry *poGeometry, int iSrsId, size_t *szWkb);
-OGRGeometry*        GPkgGeometryToOGR(GByte *pabyGpkg, size_t szGpkg, OGRSpatialReference *poSrs);
+OGRGeometry*        GPkgGeometryToOGR(const GByte *pabyGpkg, size_t szGpkg, OGRSpatialReference *poSrs);
 OGRErr              GPkgEnvelopeToOGR(GByte *pabyGpkg, size_t szGpkg, OGREnvelope *poEnv);
 
 OGRErr              GPkgHeaderFromWKB(const GByte *pabyGpkg, GPkgHeader *poHeader);
diff --git a/ogr/ogrsf_frmts/gpsbabel/GNUmakefile b/ogr/ogrsf_frmts/gpsbabel/GNUmakefile
index 4b1349d..30553fb 100644
--- a/ogr/ogrsf_frmts/gpsbabel/GNUmakefile
+++ b/ogr/ogrsf_frmts/gpsbabel/GNUmakefile
@@ -3,7 +3,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrgpsbabeldriver.o ogrgpsbabeldatasource.o ogrgpsbabelwritedatasource.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gpsbabel/ogr_gpsbabel.h b/ogr/ogrsf_frmts/gpsbabel/ogr_gpsbabel.h
index 10c5c64..570797f 100644
--- a/ogr/ogrsf_frmts/gpsbabel/ogr_gpsbabel.h
+++ b/ogr/ogrsf_frmts/gpsbabel/ogr_gpsbabel.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogr_gpsbabel.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gpsbabel.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/GPSBabel driver.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -45,19 +45,22 @@ class OGRGPSBabelDataSource : public OGRDataSource
     char               *pszGPSBabelDriverName;
     char               *pszFilename;
     CPLString           osTmpFileName;
-    OGRDataSource      *poGPXDS;
+    GDALDataset        *poGPXDS;
 
   public:
                         OGRGPSBabelDataSource();
                         ~OGRGPSBabelDataSource();
 
+    virtual int         CloseDependentDatasets();
+
     virtual const char  *GetName() { return pszName; }
     virtual int         GetLayerCount() { return nLayers; }
     virtual OGRLayer   *GetLayer( int );
 
     virtual int         TestCapability( const char * );
 
-    int                 Open ( const char* pszFilename, int bUpdateIn );
+    int                 Open ( const char* pszFilename,
+                               const char* pszGPSBabelDriverNameIn );
 
     static int          IsSpecialFile(const char* pszFilename);
     static int          IsValidDriverName(const char* pszGPSBabelDriverName);
@@ -74,7 +77,7 @@ class OGRGPSBabelWriteDataSource : public OGRDataSource
     char               *pszGPSBabelDriverName;
     char               *pszFilename;
     CPLString           osTmpFileName;
-    OGRDataSource      *poGPXDS;
+    GDALDataset        *poGPXDS;
 
     int                 Convert();
 
@@ -88,7 +91,7 @@ class OGRGPSBabelWriteDataSource : public OGRDataSource
 
     virtual int         TestCapability( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char * pszLayerName,
+    virtual OGRLayer   *ICreateLayer( const char * pszLayerName,
                                      OGRSpatialReference *poSRS,
                                      OGRwkbGeometryType eType,
                                      char ** papszOptions );
@@ -96,23 +99,5 @@ class OGRGPSBabelWriteDataSource : public OGRDataSource
     int                 Create ( const char* pszFilename, char **papszOptions );
 };
 
-/************************************************************************/
-/*                        OGRGPSBabelDriver                             */
-/************************************************************************/
-
-class OGRGPSBabelDriver : public OGRSFDriver
-{
-  public:
-                ~OGRGPSBabelDriver();
-
-    virtual const char    *GetName();
-    virtual OGRDataSource *Open( const char *, int );
-    virtual OGRDataSource *CreateDataSource( const char * pszName,
-                                             char **papszOptions );
-    virtual OGRErr         DeleteDataSource( const char *pszFilename );
-
-    virtual int            TestCapability( const char * );
-};
-
 #endif /* ndef _OGR_GPSBABEL_H_INCLUDED */
 
diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp
index 6d531b4..c57a374 100644
--- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp
+++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldatasource.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogrgpsbabeldatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgpsbabeldatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGPSBabelDataSource class.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -35,7 +35,7 @@
 
 #include <string.h>
 
-CPL_CVSID("$Id: ogrgpsbabeldatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgpsbabeldatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                      OGRGPSBabelDataSource()                         */
@@ -62,14 +62,29 @@ OGRGPSBabelDataSource::~OGRGPSBabelDataSource()
     CPLFree(pszGPSBabelDriverName);
     CPLFree(pszFilename);
     
-    if (poGPXDS)
-        OGRDataSource::DestroyDataSource(poGPXDS);
+    CloseDependentDatasets();
     
     if (osTmpFileName.size() > 0)
         VSIUnlink(osTmpFileName.c_str());
 }
 
 /************************************************************************/
+/*                     CloseDependentDatasets()                         */
+/************************************************************************/
+
+int OGRGPSBabelDataSource::CloseDependentDatasets()
+{
+    int bRet = FALSE;
+    if (poGPXDS)
+    {
+        bRet = TRUE;
+        GDALClose( (GDALDatasetH) poGPXDS );
+        poGPXDS = NULL;
+    }
+    return bRet;
+}
+
+/************************************************************************/
 /*                             GetArgv()                                */
 /************************************************************************/
 
@@ -133,58 +148,17 @@ int OGRGPSBabelDataSource::IsValidDriverName(const char* pszGPSBabelDriverName)
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRGPSBabelDataSource::Open( const char * pszDatasourceName, int bUpdateIn)
+int OGRGPSBabelDataSource::Open( const char * pszDatasourceName,
+                                 const char* pszGPSBabelDriverNameIn )
 
 {
     int bExplicitFeatures = FALSE;
     int bWaypoints = TRUE, bTracks = TRUE, bRoutes = TRUE;
-    if (bUpdateIn)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                    "OGR/GPSBabel driver does not support opening a file in update mode");
-        return FALSE;
-    }
 
     if (!EQUALN(pszDatasourceName, "GPSBABEL:", 9))
     {
-        VSILFILE* fp = VSIFOpenL(pszDatasourceName, "rb");
-        if (fp == NULL)
-            return FALSE;
-
-        char szHeader[1024 + 1];
-        memset(szHeader, 0, 1024+1);
-        VSIFReadL(szHeader, 1, 1024, fp);
-        if (memcmp(szHeader, "MsRcd", 5) == 0)
-            pszGPSBabelDriverName = CPLStrdup("mapsource");
-        else if (memcmp(szHeader, "MsRcf", 5) == 0)
-            pszGPSBabelDriverName = CPLStrdup("gdb");
-        else if (strstr(szHeader, "<osm") != NULL)
-            pszGPSBabelDriverName = CPLStrdup("osm");
-        else if (strstr(szHeader, "$GPGSA") != NULL ||
-                 strstr(szHeader, "$GPGGA") != NULL)
-            pszGPSBabelDriverName = CPLStrdup("nmea");
-        else if (EQUALN(szHeader, "OziExplorer",11))
-            pszGPSBabelDriverName = CPLStrdup("ozi");
-        else if (strstr(szHeader, "Grid") && strstr(szHeader, "Datum") && strstr(szHeader, "Header"))
-            pszGPSBabelDriverName = CPLStrdup("garmin_txt");
-        else if (szHeader[0] == 13 && szHeader[10] == 'M' && szHeader[11] == 'S' &&
-                 (szHeader[12] >= '0' && szHeader[12] <= '9') &&
-                 (szHeader[13] >= '0' && szHeader[13] <= '9') &&
-                 szHeader[12] * 10 + szHeader[13] >= 30 &&
-                 (szHeader[14] == 1 || szHeader[14] == 2) && szHeader[15] == 0 &&
-                 szHeader[16] == 0 && szHeader[17] == 0)
-            pszGPSBabelDriverName = CPLStrdup("mapsend");
-        else if (strstr(szHeader, "$PMGNWPL") != NULL ||
-                 strstr(szHeader, "$PMGNRTE") != NULL)
-            pszGPSBabelDriverName = CPLStrdup("magellan");
-
-        VSIFCloseL(fp);
-
-        if (pszGPSBabelDriverName == NULL)
-        {
-            return FALSE;
-        }
-
+        CPLAssert(pszGPSBabelDriverNameIn);
+        pszGPSBabelDriverName = CPLStrdup(pszGPSBabelDriverNameIn);
         pszFilename = CPLStrdup(pszDatasourceName);
     }
 
@@ -336,7 +310,8 @@ int OGRGPSBabelDataSource::Open( const char * pszDatasourceName, int bUpdateIn)
 
     if (bRet)
     {
-        poGPXDS = OGRSFDriverRegistrar::Open(osTmpFileName.c_str());
+        poGPXDS = (GDALDataset*) GDALOpenEx(osTmpFileName.c_str(),
+                                            GDAL_OF_VECTOR, NULL, NULL, NULL);
         if (poGPXDS)
         {
             OGRLayer* poLayer;
diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp
index 3d37c41..cce0a00 100644
--- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp
+++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabeldriver.cpp
@@ -6,7 +6,7 @@
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -35,38 +35,52 @@
 CPL_CVSID("$Id$");
 
 /************************************************************************/
-/*                         ~OGRGPSBabelDriver()                           */
-/************************************************************************/
-
-OGRGPSBabelDriver::~OGRGPSBabelDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRGPSBabelDriver::GetName()
-
-{
-    return "GPSBabel";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGPSBabelDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRGPSBabelDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    if (bUpdate)
+    if (poOpenInfo->eAccess == GA_Update)
         return NULL;
+    const char* pszGPSBabelDriverName = NULL;
+    if( !EQUALN(poOpenInfo->pszFilename, "GPSBABEL:", strlen("GPSBABEL:")) )
+    {
+        if( poOpenInfo->fpL == NULL )
+            return NULL;
+        if (memcmp(poOpenInfo->pabyHeader, "MsRcd", 5) == 0)
+            pszGPSBabelDriverName = "mapsource";
+        else if (memcmp(poOpenInfo->pabyHeader, "MsRcf", 5) == 0)
+            pszGPSBabelDriverName = "gdb";
+        else if (strstr((const char*)poOpenInfo->pabyHeader, "<osm") != NULL)
+            pszGPSBabelDriverName = "osm";
+        else if (strstr((const char*)poOpenInfo->pabyHeader, "$GPGSA") != NULL ||
+                 strstr((const char*)poOpenInfo->pabyHeader, "$GPGGA") != NULL)
+            pszGPSBabelDriverName = "nmea";
+        else if (EQUALN((const char*)poOpenInfo->pabyHeader, "OziExplorer",11))
+            pszGPSBabelDriverName = "ozi";
+        else if (strstr((const char*)poOpenInfo->pabyHeader, "Grid") &&
+                 strstr((const char*)poOpenInfo->pabyHeader, "Datum") &&
+                 strstr((const char*)poOpenInfo->pabyHeader, "Header"))
+            pszGPSBabelDriverName = "garmin_txt";
+        else if (poOpenInfo->pabyHeader[0] == 13 && poOpenInfo->pabyHeader[10] == 'M' && poOpenInfo->pabyHeader[11] == 'S' &&
+                 (poOpenInfo->pabyHeader[12] >= '0' && poOpenInfo->pabyHeader[12] <= '9') &&
+                 (poOpenInfo->pabyHeader[13] >= '0' && poOpenInfo->pabyHeader[13] <= '9') &&
+                 poOpenInfo->pabyHeader[12] * 10 + poOpenInfo->pabyHeader[13] >= 30 &&
+                 (poOpenInfo->pabyHeader[14] == 1 || poOpenInfo->pabyHeader[14] == 2) && poOpenInfo->pabyHeader[15] == 0 &&
+                 poOpenInfo->pabyHeader[16] == 0 && poOpenInfo->pabyHeader[17] == 0)
+            pszGPSBabelDriverName = "mapsend";
+        else if (strstr((const char*)poOpenInfo->pabyHeader, "$PMGNWPL") != NULL ||
+                 strstr((const char*)poOpenInfo->pabyHeader, "$PMGNRTE") != NULL)
+            pszGPSBabelDriverName = "magellan";
+
+        if( pszGPSBabelDriverName == NULL )
+            return NULL;
+    }
 
     OGRGPSBabelDataSource   *poDS = new OGRGPSBabelDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, pszGPSBabelDriverName ) )
     {
         delete poDS;
         poDS = NULL;
@@ -76,12 +90,15 @@ OGRDataSource *OGRGPSBabelDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRGPSBabelDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRGPSBabelDriverCreate( const char * pszName,
+                                             CPL_UNUSED int nBands,
+                                             CPL_UNUSED int nXSize,
+                                             CPL_UNUSED int nYSize,
+                                             CPL_UNUSED GDALDataType eDT,
+                                             char **papszOptions )
 {
     OGRGPSBabelWriteDataSource   *poDS = new OGRGPSBabelWriteDataSource();
 
@@ -94,33 +111,17 @@ OGRDataSource *OGRGPSBabelDriver::CreateDataSource( const char * pszName,
     return poDS;
 }
 
-
 /************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                               Delete()                               */
 /************************************************************************/
 
-OGRErr OGRGPSBabelDriver::DeleteDataSource( const char *pszFilename )
+static CPLErr OGRGPSBabelDriverDelete( const char *pszFilename )
 
 {
     if( VSIUnlink( pszFilename ) == 0 )
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGPSBabelDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
+        return CE_None;
     else
-        return FALSE;
+        return CE_Failure;
 }
 
 /************************************************************************/
@@ -132,6 +133,23 @@ void RegisterOGRGPSBabel()
     if (! GDAL_CHECK_VERSION("OGR/GPSBabel driver"))
         return;
 
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGPSBabelDriver );
-}
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "GPSBabel" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
+        poDriver->SetDescription( "GPSBabel" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GPSBabel" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_gpsbabel.html" );
+
+        poDriver->pfnOpen = OGRGPSBabelDriverOpen;
+        poDriver->pfnCreate = OGRGPSBabelDriverCreate;
+        poDriver->pfnDelete = OGRGPSBabelDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp
index c9affec..745f47c 100644
--- a/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp
+++ b/ogr/ogrsf_frmts/gpsbabel/ogrgpsbabelwritedatasource.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogrgpsbabelwritedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgpsbabelwritedatasource.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGPSBabelWriteDataSource class.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,7 +34,7 @@
 #include "cpl_error.h"
 #include "cpl_spawn.h"
 
-CPL_CVSID("$Id: ogrgpsbabelwritedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgpsbabelwritedatasource.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                    OGRGPSBabelWriteDataSource()                      */
@@ -57,7 +57,7 @@ OGRGPSBabelWriteDataSource::~OGRGPSBabelWriteDataSource()
 
 {
     if (poGPXDS)
-        OGRDataSource::DestroyDataSource(poGPXDS);
+        GDALClose( (GDALDatasetH) poGPXDS );
 
     Convert();
 
@@ -129,7 +129,7 @@ int OGRGPSBabelWriteDataSource::Convert()
 int OGRGPSBabelWriteDataSource::Create( const char * pszName,
                                         char **papszOptions )
 {
-    OGRSFDriver* poGPXDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("GPX");
+    GDALDriver* poGPXDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("GPX");
     if (poGPXDriver == NULL)
     {
         CPLError(CE_Failure, CPLE_AppDefined, "GPX driver is necessary for GPSBabel write support");
@@ -178,7 +178,7 @@ int OGRGPSBabelWriteDataSource::Create( const char * pszName,
     else
         osTmpFileName.Printf("/vsimem/ogrgpsbabeldatasource_%p", this);
 
-    poGPXDS = poGPXDriver->CreateDataSource(osTmpFileName.c_str(), papszOptions);
+    poGPXDS = poGPXDriver->Create(osTmpFileName.c_str(), 0, 0, 0, GDT_Unknown, papszOptions);
     if (poGPXDS == NULL)
         return FALSE;
 
@@ -188,10 +188,10 @@ int OGRGPSBabelWriteDataSource::Create( const char * pszName,
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRGPSBabelWriteDataSource::CreateLayer( const char * pszLayerName,
+OGRLayer * OGRGPSBabelWriteDataSource::ICreateLayer( const char * pszLayerName,
                                                     OGRSpatialReference *poSRS,
                                                     OGRwkbGeometryType eType,
                                                     char ** papszOptions )
diff --git a/ogr/ogrsf_frmts/gpx/GNUmakefile b/ogr/ogrsf_frmts/gpx/GNUmakefile
index b46003f..35b14ea 100644
--- a/ogr/ogrsf_frmts/gpx/GNUmakefile
+++ b/ogr/ogrsf_frmts/gpx/GNUmakefile
@@ -8,7 +8,7 @@ ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=   -DHAVE_EXPAT
 endif
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(EXPAT_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gpx/drv_gpx.html b/ogr/ogrsf_frmts/gpx/drv_gpx.html
index e128bba..4b3c80c 100644
--- a/ogr/ogrsf_frmts/gpx/drv_gpx.html
+++ b/ogr/ogrsf_frmts/gpx/drv_gpx.html
@@ -275,7 +275,7 @@ ogr2ogr -f GPX output.gpx input.shp -sql "SELECT field1 AS name, field2 AS desc
 <li>How to solve "ERROR 6: Cannot create GPX layer XXXXXX with unknown geometry type" ?<p>
 This error happens when the layer to create does not expose a precise geometry type, but just a generic
 wkbUnknown type. This is for example the case when using ogr2ogr with a SQL request to a PostgreSQL datasource.
-You must then explicitely specify -nlt POINT (or LINESTRING or MULTILINESTRING).
+You must then explicitly specify -nlt POINT (or LINESTRING or MULTILINESTRING).
 </li>
 
 
diff --git a/ogr/ogrsf_frmts/gpx/ogr_gpx.h b/ogr/ogrsf_frmts/gpx/ogr_gpx.h
index fc15ed3..586d2cb 100644
--- a/ogr/ogrsf_frmts/gpx/ogr_gpx.h
+++ b/ogr/ogrsf_frmts/gpx/ogr_gpx.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gpx.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gpx.h 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  GPX Translator
  * Purpose:  Definition of classes for OGR .gpx driver.
@@ -137,7 +137,7 @@ class OGRGPXLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
     
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK );
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
@@ -214,7 +214,7 @@ class OGRGPXDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer*           GetLayer( int );
     
-    OGRLayer *          CreateLayer( const char * pszLayerName,
+    OGRLayer *          ICreateLayer( const char * pszLayerName,
                                     OGRSpatialReference *poSRS,
                                     OGRwkbGeometryType eType,
                                     char ** papszOptions );
@@ -241,22 +241,4 @@ class OGRGPXDataSource : public OGRDataSource
     void                PrintLine(const char *fmt, ...) CPL_PRINT_FUNC_FORMAT (2, 3);
 };
 
-/************************************************************************/
-/*                             OGRGPXDriver                             */
-/************************************************************************/
-
-class OGRGPXDriver : public OGRSFDriver
-{
-  public:
-                ~OGRGPXDriver();
-
-    const char*         GetName();
-    OGRDataSource*      Open( const char *, int );
-    OGRDataSource*      CreateDataSource( const char * pszName, char **papszOptions );
-    int                 DeleteDataSource( const char *pszFilename );
-    int                 TestCapability( const char * );
-    
-};
-
-
 #endif /* ndef _OGR_GPX_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/gpx/ogrgpxdatasource.cpp b/ogr/ogrsf_frmts/gpx/ogrgpxdatasource.cpp
index b789a0c..37d80de 100644
--- a/ogr/ogrsf_frmts/gpx/ogrgpxdatasource.cpp
+++ b/ogr/ogrsf_frmts/gpx/ogrgpxdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgpxdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgpxdatasource.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  GPX Translator
  * Purpose:  Implements OGRGPXDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "cpl_csv.h"
 
-CPL_CVSID("$Id: ogrgpxdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgpxdatasource.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 #define SPACE_FOR_METADATA 160
 
@@ -91,7 +91,7 @@ OGRGPXDataSource::~OGRGPXDataSource()
             if (dfMinLon <= dfMaxLon)
             {
                 char szMetadata[SPACE_FOR_METADATA+1];
-                int nRet = snprintf(szMetadata, SPACE_FOR_METADATA,
+                int nRet = CPLsnprintf(szMetadata, SPACE_FOR_METADATA,
                          "<metadata><bounds minlat=\"%.15f\" minlon=\"%.15f\" maxlat=\"%.15f\" maxlon=\"%.15f\"/></metadata>",
                         dfMinLat, dfMinLon, dfMaxLat, dfMaxLon);
                 if (nRet < SPACE_FOR_METADATA)
@@ -141,14 +141,13 @@ OGRLayer *OGRGPXDataSource::GetLayer( int iLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRGPXDataSource::CreateLayer( const char * pszLayerName,
-                                          CPL_UNUSED OGRSpatialReference *poSRS,
-                                          OGRwkbGeometryType eType,
-                                          char ** papszOptions )
-
+OGRLayer * OGRGPXDataSource::ICreateLayer( const char * pszLayerName,
+                                           CPL_UNUSED OGRSpatialReference *poSRS,
+                                           OGRwkbGeometryType eType,
+                                           char ** papszOptions )
 {
     GPXGeometryType gpxGeomType;
     if (eType == wkbPoint || eType == wkbPoint25D)
@@ -239,7 +238,8 @@ void OGRGPXDataSource::startElementValidateCbk(const char *pszName, const char *
 /*                      dataHandlerValidateCbk()                        */
 /************************************************************************/
 
-void OGRGPXDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data, CPL_UNUSED int nLen)
+void OGRGPXDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data,
+                                              CPL_UNUSED int nLen)
 {
     nDataHandlerCounter ++;
     if (nDataHandlerCounter >= BUFSIZ)
diff --git a/ogr/ogrsf_frmts/gpx/ogrgpxdriver.cpp b/ogr/ogrsf_frmts/gpx/ogrgpxdriver.cpp
index 0bcb666..3bd09a2 100644
--- a/ogr/ogrsf_frmts/gpx/ogrgpxdriver.cpp
+++ b/ogr/ogrsf_frmts/gpx/ogrgpxdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgpxdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgpxdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GPX Translator
  * Purpose:  Implements OGRGPXDriver.
@@ -30,42 +30,24 @@
 #include "ogr_gpx.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrgpxdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-/************************************************************************/
-/*                           ~OGRGPXDriver()                            */
-/************************************************************************/
-
-OGRGPXDriver::~OGRGPXDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRGPXDriver::GetName()
-
-{
-    return "GPX";
-}
+CPL_CVSID("$Id: ogrgpxdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGPXDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRGPXDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    if (bUpdate)
-    {
+    if( poOpenInfo->eAccess == GA_Update || poOpenInfo->fpL == NULL )
+        return NULL;
+
+    if( strstr((const char*)poOpenInfo->pabyHeader, "<gpx") == NULL )
         return NULL;
-    }
 
     OGRGPXDataSource   *poDS = new OGRGPXDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, FALSE ) )
     {
         delete poDS;
         poDS = NULL;
@@ -75,12 +57,15 @@ OGRDataSource *OGRGPXDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRGPXDriver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRGPXDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        CPL_UNUSED char **papszOptions )
 {
     OGRGPXDataSource   *poDS = new OGRGPXDataSource();
 
@@ -94,34 +79,18 @@ OGRDataSource *OGRGPXDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                               Delete()                               */
 /************************************************************************/
 
-OGRErr OGRGPXDriver::DeleteDataSource( const char *pszFilename )
+static CPLErr OGRGPXDriverDelete( const char *pszFilename )
 
 {
     if( VSIUnlink( pszFilename ) == 0 )
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGPXDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
+        return CE_None;
     else
-        return FALSE;
+        return CE_Failure;
 }
 
-
 /************************************************************************/
 /*                           RegisterOGRGPX()                           */
 /************************************************************************/
@@ -131,6 +100,47 @@ void RegisterOGRGPX()
 {
     if (! GDAL_CHECK_VERSION("OGR/GPX driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGPXDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "GPX" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "GPX" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GPX" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gpx" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_gpx.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+#ifdef WIN32
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='CRLF'>"
+#else
+"  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='LF'>"
+#endif
+"    <Value>CRLF</Value>"
+"    <Value>LF</Value>"
+"  </Option>"
+"  <Option name='GPX_USE_EXTENSIONS' type='boolean' description='Whether to write non-GPX attributes in an <extensions> tag' default='NO'/>"
+"  <Option name='GPX_EXTENSIONS_NS' type='string' description='Namespace value used for extension tags' default='ogr'/>"
+"  <Option name='GPX_EXTENSIONS_NS_URL' type='string' description='Namespace URI' default='http://osgeo.org/gdal'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='FORCE_GPX_TRACK' type='boolean' description='Whether to force layers with geometries of type wkbLineString as tracks' default='NO'/>"
+"  <Option name='FORCE_GPX_ROUTE' type='boolean' description='Whether to force layers with geometries of type wkbMultiLineString (with single line string in them) as routes' default='NO'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRGPXDriverOpen;
+        poDriver->pfnCreate = OGRGPXDriverCreate;
+        poDriver->pfnDelete = OGRGPXDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/gpx/ogrgpxlayer.cpp b/ogr/ogrsf_frmts/gpx/ogrgpxlayer.cpp
index 3e76574..1cc5ecf 100644
--- a/ogr/ogrsf_frmts/gpx/ogrgpxlayer.cpp
+++ b/ogr/ogrsf_frmts/gpx/ogrgpxlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgpxlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgpxlayer.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  GPX Translator
  * Purpose:  Implements OGRGPXLayer class.
@@ -33,7 +33,7 @@
 #include "cpl_minixml.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrgpxlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrgpxlayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 #define FLD_TRACK_FID       0
 #define FLD_TRACK_SEG_ID    1
@@ -84,6 +84,7 @@ OGRGPXLayer::OGRGPXLayer( const char* pszFilename,
     int bShortNames  = CSLTestBoolean(CPLGetConfigOption("GPX_SHORT_NAMES", "NO"));
     
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     
     if (gpxGeomType == GPX_TRACK_POINT)
@@ -905,11 +906,10 @@ void OGRGPXLayer::endElementCbk(const char *pszName)
                 pszSubElementValue[nSubElementValueLen] = 0;
                 if (strcmp(pszSubElementName, "time") == 0)
                 {
-                    int year, month, day, hour, minute, TZ;
-                    float second;
-                    if (OGRParseXMLDateTime(pszSubElementValue, &year, &month, &day, &hour, &minute, &second, &TZ))
+                    OGRField sField;
+                    if (OGRParseXMLDateTime(pszSubElementValue, &sField))
                     {
-                        poFeature->SetField(iCurrentField, year, month, day, hour, minute, (int)(second + .5), TZ);
+                        poFeature->SetField(iCurrentField, &sField);
                     }
                     else
                     {
@@ -1076,7 +1076,7 @@ OGRFeature *OGRGPXLayer::GetNextFeature()
 static char* OGRGPX_GetXMLCompatibleTagName(const char* pszExtensionsNS,
                                             const char* pszName)
 {
-    /* Skip "ogr_" for example if NS is "ogr". Usefull for GPX -> GPX roundtrip */
+    /* Skip "ogr_" for example if NS is "ogr". Useful for GPX -> GPX roundtrip */
     if (strncmp(pszName, pszExtensionsNS, strlen(pszExtensionsNS)) == 0 &&
         pszName[strlen(pszExtensionsNS)] == '_')
     {
@@ -1187,15 +1187,10 @@ void OGRGPXLayer::WriteFeatureAttributes( OGRFeature *poFeature, int nIdentLevel
             const char* pszName = poFieldDefn->GetNameRef();
             if (strcmp(pszName, "time") == 0)
             {
-                int year, month, day, hour, minute, second, TZFlag;
-                if (poFeature->GetFieldAsDateTime(i, &year, &month, &day,
-                                                  &hour, &minute, &second, &TZFlag))
-                {
-                    char* pszDate = OGRGetXMLDateTime(year, month, day, hour, minute, second, TZFlag);
-                    AddIdent(fp, nIdentLevel);
-                    poDS->PrintLine("<time>%s</time>", pszDate);
-                    CPLFree(pszDate);
-                }
+                char* pszDate = OGRGetXMLDateTime(poFeature->GetRawFieldRef(i));
+                AddIdent(fp, nIdentLevel);
+                poDS->PrintLine("<time>%s</time>", pszDate);
+                CPLFree(pszDate);
             }
             else if (strncmp(pszName, "link", 4) == 0)
             {
@@ -1348,10 +1343,10 @@ OGRErr OGRGPXLayer::CheckAndFixCoordinatesValidity( double* pdfLatitude, double*
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRGPXLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGPXLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     VSILFILE* fp = poDS->GetOutputFP();
@@ -1768,7 +1763,8 @@ OGRErr OGRGPXLayer::CreateFeature( OGRFeature *poFeature )
 /************************************************************************/
 
 
-OGRErr OGRGPXLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRGPXLayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
diff --git a/ogr/ogrsf_frmts/grass/GNUmakefile b/ogr/ogrsf_frmts/grass/GNUmakefile
index 0e168a3..b12fd52 100644
--- a/ogr/ogrsf_frmts/grass/GNUmakefile
+++ b/ogr/ogrsf_frmts/grass/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrgrassdriver.o ogrgrassdatasource.o ogrgrasslayer.o
 
-CPPFLAGS	:=	-DUSE_CPL -DGRASS_GISBASE=\"$(GRASS_GISBASE)\" -I.. -I../.. $(GRASS_INCLUDE) $(GDAL_INCLUDE) $(PG_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-DUSE_CPL -DGRASS_GISBASE=\"$(GRASS_GISBASE)\" -I.. -I../.. $(GRASS_INCLUDE)  $(PG_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/grass/ogrgrass.h b/ogr/ogrsf_frmts/grass/ogrgrass.h
index 45b10e6..5abed15 100644
--- a/ogr/ogrsf_frmts/grass/ogrgrass.h
+++ b/ogr/ogrsf_frmts/grass/ogrgrass.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgrass.h 20157 2010-07-28 19:32:04Z rouault $
+ * $Id: ogrgrass.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/GRASS driver.
@@ -55,16 +55,16 @@ class OGRGRASSLayer : public OGRLayer
 
     // Layer info
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce);
     virtual OGRSpatialReference *GetSpatialRef();
     int                 TestCapability( const char * );
 
     // Reading
     void                ResetReading();
-    virtual OGRErr      SetNextByIndex( long nIndex );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
     OGRFeature *        GetNextFeature();
-    OGRFeature         *GetFeature( long nFeatureId );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
 
     // Filters
     virtual OGRErr 	SetAttributeFilter( const char *query );
@@ -72,8 +72,8 @@ class OGRGRASSLayer : public OGRLayer
 
     // Write access, not supported:
     virtual OGRErr      CreateField( OGRFieldDefn *poField, int bApproxOK = TRUE );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ISetFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     
   private:
     char		*pszName;
@@ -142,7 +142,7 @@ class OGRGRASSDataSource : public OGRDataSource
     int                 TestCapability( const char * );
 
     // Not implemented (returns NULL):
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
diff --git a/ogr/ogrsf_frmts/grass/ogrgrassdatasource.cpp b/ogr/ogrsf_frmts/grass/ogrgrassdatasource.cpp
index c95ce7e..8677c47 100644
--- a/ogr/ogrsf_frmts/grass/ogrgrassdatasource.cpp
+++ b/ogr/ogrsf_frmts/grass/ogrgrassdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgrassdatasource.cpp 28291 2015-01-05 14:45:07Z martinl $
+ * $Id: ogrgrassdatasource.cpp 28534 2015-02-21 14:34:39Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGRASSDataSource class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrgrassdatasource.cpp 28291 2015-01-05 14:45:07Z martinl $");
+CPL_CVSID("$Id: ogrgrassdatasource.cpp 28534 2015-02-21 14:34:39Z rouault $");
 
 #if GRASS_VERSION_MAJOR  >= 7
 #define G__setenv                G_setenv_nogisrc
@@ -160,7 +160,7 @@ int OGRGRASSDataSource::Open( const char * pszNewName, int bUpdate,
         static char* gisbaseEnv = NULL;
         const char *gisbase = GRASS_GISBASE;
         CPLError( CE_Warning, CPLE_AppDefined, "GRASS warning: GISBASE "
-                "enviroment variable was not set, using:\n%s", gisbase );
+                "environment variable was not set, using:\n%s", gisbase );
         char buf[2000];
         snprintf ( buf, sizeof(buf), "GISBASE=%s", gisbase );
         buf[sizeof(buf)-1] = '\0';
@@ -231,10 +231,10 @@ int OGRGRASSDataSource::Open( const char * pszNewName, int bUpdate,
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 OGRLayer *
-OGRGRASSDataSource::CreateLayer( const char * pszLayerName,
+OGRGRASSDataSource::ICreateLayer( const char * pszLayerName,
                                  OGRSpatialReference *poSRS,
                                  OGRwkbGeometryType eType,
                                  char ** papszOptions )
diff --git a/ogr/ogrsf_frmts/grass/ogrgrassdriver.cpp b/ogr/ogrsf_frmts/grass/ogrgrassdriver.cpp
index dd25405..999da00 100644
--- a/ogr/ogrsf_frmts/grass/ogrgrassdriver.cpp
+++ b/ogr/ogrsf_frmts/grass/ogrgrassdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgrassdriver.cpp 12396 2007-10-13 10:02:17Z rouault $
+ * $Id: ogrgrassdriver.cpp 28290 2015-01-05 13:16:48Z martinl $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGRASSDriver class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrgrassdriver.cpp 12396 2007-10-13 10:02:17Z rouault $");
+CPL_CVSID("$Id: ogrgrassdriver.cpp 28290 2015-01-05 13:16:48Z martinl $");
 
 /************************************************************************/
 /*                          ~OGRGRASSDriver()                           */
@@ -45,7 +45,7 @@ OGRGRASSDriver::~OGRGRASSDriver()
 /************************************************************************/
 const char *OGRGRASSDriver::GetName()
 {
-    return "GRASS";
+    return "OGR_GRASS";
 }
 
 /************************************************************************/
@@ -105,8 +105,23 @@ int OGRGRASSDriver::TestCapability( const char * pszCap )
 /************************************************************************/
 void RegisterOGRGRASS()
 {
+    OGRGRASSDriver	*poDriver;
+
     if (! GDAL_CHECK_VERSION("OGR/GRASS driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGRASSDriver );
+
+    if( GDALGetDriverByName( "OGR_GRASS" ) == NULL )
+    {
+        poDriver = new OGRGRASSDriver();
+        
+        poDriver->SetDescription( "GRASS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
+                                   "GRASS Vectors (5.7+)" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
+                                   "drv_grass.html" );
+
+        OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/grass/ogrgrasslayer.cpp b/ogr/ogrsf_frmts/grass/ogrgrasslayer.cpp
index 0e2462f..41855b3 100644
--- a/ogr/ogrsf_frmts/grass/ogrgrasslayer.cpp
+++ b/ogr/ogrsf_frmts/grass/ogrgrasslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgrasslayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrgrasslayer.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRGRASSLayer class.
@@ -32,7 +32,7 @@
 #include "ogrgrass.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrgrasslayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrgrasslayer.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 /************************************************************************/
 /*                           OGRGRASSLayer()                            */
@@ -87,6 +87,7 @@ OGRGRASSLayer::OGRGRASSLayer( int layerIndex,  struct Map_info * map )
     }
 
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     // Get type definition
@@ -116,7 +117,7 @@ OGRGRASSLayer::OGRGRASSLayer( int layerIndex,  struct Map_info * map )
     }
 
     if (Vect_is_3d(poMap))
-        poFeatureDefn->SetGeomType ( (OGRwkbGeometryType)(eGeomType | wkb25DBit) );
+        poFeatureDefn->SetGeomType ( wkbSetZ(eGeomType) );
     else
         poFeatureDefn->SetGeomType ( eGeomType );
 
@@ -277,7 +278,7 @@ bool OGRGRASSLayer::StartDbDriver()
     if ( poDriver == NULL) 
     {
 	CPLError( CE_Failure, CPLE_AppDefined, "Cannot open database %s by driver %s, "
-		  "check if GISBASE enviroment variable is set, the driver is available "
+		  "check if GISBASE environment variable is set, the driver is available "
 		  " and the database is accessible.", poLink->driver, poLink->database );
 	return false;
     } 
@@ -336,7 +337,7 @@ void OGRGRASSLayer::ResetReading()
 /*      If we already have an FID list, we can easily resposition       */
 /*      ourselves in it.                                                */
 /************************************************************************/
-OGRErr OGRGRASSLayer::SetNextByIndex( long nIndex )
+OGRErr OGRGRASSLayer::SetNextByIndex( GIntBig nIndex )
 {
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL ) 
     {
@@ -389,7 +390,7 @@ OGRErr OGRGRASSLayer::SetAttributeFilter( const char *query )
 
     paQueryMatch = (char *) CPLMalloc ( nTotalCount );
     memset ( paQueryMatch, 0x0, nTotalCount );
-    pszQuery = strdup ( query );
+    pszQuery = CPLStrdup(query);
 
     OGRLayer::SetAttributeFilter(query); // Otherwise crash on delete
 
@@ -783,7 +784,7 @@ OGRFeature *OGRGRASSLayer::GetNextFeature()
 /************************************************************************/
 /*                             GetFeature()                             */
 /************************************************************************/
-OGRFeature *OGRGRASSLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRGRASSLayer::GetFeature( GIntBig nFeatureId )
 
 {
     CPLDebug ( "GRASS", "OGRGRASSLayer::GetFeature nFeatureId = %ld", nFeatureId );
@@ -990,17 +991,17 @@ bool OGRGRASSLayer::SetAttributes ( OGRFeature *poFeature, dbTable *table )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
-OGRErr OGRGRASSLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRGRASSLayer::ISetFeature( OGRFeature *poFeature )
 {
     return OGRERR_FAILURE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
-OGRErr OGRGRASSLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRGRASSLayer::ICreateFeature( OGRFeature *poFeature )
 {
     return OGRERR_FAILURE;
 }
@@ -1013,7 +1014,7 @@ OGRErr OGRGRASSLayer::CreateFeature( OGRFeature *poFeature )
 /*      Eventually we should consider implementing a more efficient     */
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
-int OGRGRASSLayer::GetFeatureCount( int bForce )
+GIntBig OGRGRASSLayer::GetFeatureCount( int bForce )
 {
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
         return OGRLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/gtm/GNUmakefile b/ogr/ogrsf_frmts/gtm/GNUmakefile
index 1a4ce26..705b1f9 100644
--- a/ogr/ogrsf_frmts/gtm/GNUmakefile
+++ b/ogr/ogrsf_frmts/gtm/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ =	ogrgtmdriver.o ogrgtmdatasource.o ogrgtmlayer.o gtm.o gtmwaypointlayer.o gtmtracklayer.o
 
-CPPFLAGS	:=-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/gtm/gtmtracklayer.cpp b/ogr/ogrsf_frmts/gtm/gtmtracklayer.cpp
index ec6aa8e..8d9a4f0 100644
--- a/ogr/ogrsf_frmts/gtm/gtmtracklayer.cpp
+++ b/ogr/ogrsf_frmts/gtm/gtmtracklayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gtmtracklayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gtmtracklayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  GTM Driver
  * Purpose:  Implementation of GTMTrackLayer class.
@@ -36,7 +36,7 @@ GTMTrackLayer::GTMTrackLayer( const char* pszName,
                               OGRGTMDataSource* poDSIn )
 {
     poCT = NULL;
-  
+
     /* We are implementing just WGS84, although GTM supports other datum
        formats. */
     if( poSRSIn != NULL )
@@ -79,6 +79,7 @@ GTMTrackLayer::GTMTrackLayer( const char* pszName,
     nTotalFCount = poDS->getNTracks();
 
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType ( wkbLineString );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -216,9 +217,9 @@ inline void GTMTrackLayer::WriteTrackpoint( double lat, double lon, float altitu
 
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
-OGRErr GTMTrackLayer::CreateFeature (OGRFeature *poFeature)
+OGRErr GTMTrackLayer::ICreateFeature (OGRFeature *poFeature)
 {
     VSILFILE* fpTmpTrackpoints = poDS->getTmpTrackpointsFP();
     if (fpTmpTrackpoints == NULL)
@@ -348,7 +349,7 @@ OGRFeature* GTMTrackLayer::GetNextFeature()
     return NULL;
 }
 
-int GTMTrackLayer::GetFeatureCount(int bForce)
+GIntBig GTMTrackLayer::GetFeatureCount(int bForce)
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
         return poDS->getNTracks();
@@ -362,4 +363,3 @@ void GTMTrackLayer::ResetReading()
     nNextFID = 0;
     poDS->rewindTrack();
 }
-
diff --git a/ogr/ogrsf_frmts/gtm/gtmwaypointlayer.cpp b/ogr/ogrsf_frmts/gtm/gtmwaypointlayer.cpp
index d696b8a..1966d3c 100644
--- a/ogr/ogrsf_frmts/gtm/gtmwaypointlayer.cpp
+++ b/ogr/ogrsf_frmts/gtm/gtmwaypointlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gtmwaypointlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: gtmwaypointlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  GTM Driver
  * Purpose:  Implementation of gtmwaypoint class.
@@ -37,7 +37,7 @@ GTMWaypointLayer::GTMWaypointLayer( const char* pszName,
                                     OGRGTMDataSource* poDSIn )
 {
     poCT = NULL;
-  
+
     /* We are implementing just WGS84, although GTM supports other datum
        formats. */
     if( poSRSIn != NULL )
@@ -80,6 +80,7 @@ GTMWaypointLayer::GTMWaypointLayer( const char* pszName,
     nTotalFCount = poDS->getNWpts();
 
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType ( wkbPoint );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -227,9 +228,9 @@ void GTMWaypointLayer::WriteFeatureAttributes( OGRFeature *poFeature, float alti
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
-OGRErr GTMWaypointLayer::CreateFeature (OGRFeature *poFeature)
+OGRErr GTMWaypointLayer::ICreateFeature (OGRFeature *poFeature)
 {
     VSILFILE* fp = poDS->getOutputFP();
     if (fp == NULL)
@@ -347,7 +348,7 @@ OGRFeature* GTMWaypointLayer::GetNextFeature()
     return NULL;
 }
 
-int GTMWaypointLayer::GetFeatureCount(int bForce)
+GIntBig GTMWaypointLayer::GetFeatureCount(int bForce)
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
         return poDS->getNWpts();
diff --git a/ogr/ogrsf_frmts/gtm/ogr_gtm.h b/ogr/ogrsf_frmts/gtm/ogr_gtm.h
index 6b978cf..aac5796 100644
--- a/ogr/ogrsf_frmts/gtm/ogr_gtm.h
+++ b/ogr/ogrsf_frmts/gtm/ogr_gtm.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_gtm.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_gtm.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  GTM Driver
  * Purpose:  Declarations for OGR wrapper classes for GTM, and OGR->GTM
@@ -93,8 +93,8 @@ public:
     OGRFeatureDefn* GetLayerDefn();
     virtual void ResetReading() = 0;
     virtual OGRFeature* GetNextFeature() = 0;
-    virtual int GetFeatureCount(int bForce = TRUE) = 0;
-    virtual OGRErr CreateFeature (OGRFeature *poFeature) = 0;
+    virtual GIntBig GetFeatureCount(int bForce = TRUE) = 0;
+    virtual OGRErr ICreateFeature(OGRFeature *poFeature) = 0;
 
     int TestCapability( const char* pszCap );
     
@@ -128,10 +128,10 @@ public:
                       int bWriterIn,
                       OGRGTMDataSource* poDSIn );
     ~GTMWaypointLayer();
-    OGRErr CreateFeature (OGRFeature *poFeature);
+    OGRErr ICreateFeature(OGRFeature *poFeature);
     void ResetReading();
     OGRFeature* GetNextFeature();
-    int GetFeatureCount(int bForce = TRUE);
+    GIntBig GetFeatureCount(int bForce = TRUE);
 
     enum WaypointFields{NAME, COMMENT, ICON, DATE};
 private:
@@ -149,10 +149,10 @@ public:
                    int bWriterIn,
                    OGRGTMDataSource* poDSIn );
     ~GTMTrackLayer();
-    OGRErr CreateFeature (OGRFeature *poFeature);
+    OGRErr ICreateFeature(OGRFeature *poFeature);
     void ResetReading();
     OGRFeature* GetNextFeature();
-    int GetFeatureCount(int bForce = TRUE);
+    GIntBig GetFeatureCount(int bForce = TRUE);
     enum TrackFields{NAME, TYPE, COLOR};
 
 private:
@@ -181,7 +181,7 @@ public:
 
     OGRLayer* GetLayer( int );
 
-    OGRLayer* CreateLayer (const char *pszName, 
+    OGRLayer* ICreateLayer(const char *pszName, 
                            OGRSpatialReference *poSpatialRef=NULL, 
                            OGRwkbGeometryType eGType=wkbUnknown, 
                            char **papszOptions=NULL);
@@ -259,23 +259,4 @@ private:
     void WriteWaypointStyles();
 };
 
-/************************************************************************/
-/*                             OGRGTMDriver                             */
-/************************************************************************/
-
-class OGRGTMDriver : public OGRSFDriver
-{
-public:
-    ~OGRGTMDriver();
-
-    //
-    // OGRSFDriver Interface
-    //
-    const char* GetName();
-    OGRDataSource* Open( const char * pszName_, int bUpdate );
-    OGRDataSource* CreateDataSource( const char *pszName_, char** papszOptions );
-
-    int TestCapability( const char* pszCap );
-};
-
 #endif //OGR_GTM_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/gtm/ogrgtmdatasource.cpp b/ogr/ogrsf_frmts/gtm/ogrgtmdatasource.cpp
index bbb3c64..2ba2e45 100644
--- a/ogr/ogrsf_frmts/gtm/ogrgtmdatasource.cpp
+++ b/ogr/ogrsf_frmts/gtm/ogrgtmdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgtmdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgtmdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GTM Driver
  * Purpose:  Implementation of OGRGTMDataSource class.
@@ -324,7 +324,8 @@ int OGRGTMDataSource::Open(const char* pszFilename, int bUpdate)
 /*                               Create()                               */
 /************************************************************************/
 
-int OGRGTMDataSource::Create( const char* pszFilename, CPL_UNUSED char** papszOptions )
+int OGRGTMDataSource::Create( const char* pszFilename,
+                              CPL_UNUSED char** papszOptions )
 {
     CPLAssert( NULL != pszFilename );
 
@@ -447,13 +448,13 @@ OGRLayer* OGRGTMDataSource::GetLayer( int iLayer )
 
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRGTMDataSource::CreateLayer( const char * pszLayerName,
-                                          OGRSpatialReference *poSRS,
-                                          OGRwkbGeometryType eType,
-                                          CPL_UNUSED char ** papszOptions )
+OGRLayer * OGRGTMDataSource::ICreateLayer( const char * pszLayerName,
+                                           OGRSpatialReference *poSRS,
+                                           OGRwkbGeometryType eType,
+                                           CPL_UNUSED char ** papszOptions )
 {
     if (eType == wkbPoint || eType == wkbPoint25D)
     {
@@ -640,4 +641,3 @@ void OGRGTMDataSource::rewindTrack()
 
     poGTMFile->rewindTrack();
 }
-
diff --git a/ogr/ogrsf_frmts/gtm/ogrgtmdriver.cpp b/ogr/ogrsf_frmts/gtm/ogrgtmdriver.cpp
index 84b52cf..5881e5e 100644
--- a/ogr/ogrsf_frmts/gtm/ogrgtmdriver.cpp
+++ b/ogr/ogrsf_frmts/gtm/ogrgtmdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgtmdriver.cpp 17588 2009-08-27 20:52:33Z rouault $
+ * $Id: ogrgtmdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  GTM Driver
  * Purpose:  Implementation of OGRGTMDriver class.
@@ -31,36 +31,38 @@
 #include "cpl_error.h"
 
 /************************************************************************/
-/*                          ~OGRGTMDriver()                           */
-/************************************************************************/
-
-OGRGTMDriver::~OGRGTMDriver()
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRGTMDriver::GetName()
-{
-    return "GPSTrackMaker";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRGTMDriver::Open( const char * pszName, int bUpdate )
+static GDALDataset *OGRGTMDriverOpen( GDALOpenInfo* poOpenInfo )
 {
-    if (bUpdate)
-    {
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        poOpenInfo->nHeaderBytes < 13)
         return NULL;
+
+/* -------------------------------------------------------------------- */
+/*      If it looks like a GZip header, this may be a .gtz file, so     */
+/*      try opening with the /vsigzip/ prefix                           */
+/* -------------------------------------------------------------------- */
+    if (poOpenInfo->pabyHeader[0] == 0x1f && ((unsigned char*)poOpenInfo->pabyHeader)[1] == 0x8b &&
+        strncmp(poOpenInfo->pszFilename, "/vsigzip/", strlen("/vsigzip/")) != 0)
+    {
+        /* ok */
+    }
+    else
+    {
+        short version = CPL_LSBINT16PTR(poOpenInfo->pabyHeader);
+        if (version != 211 ||
+            strncmp((const char*)poOpenInfo->pabyHeader + 2, "TrackMaker", strlen("TrackMaker")) != 0 )
+        {
+            return NULL;
+        }
     }
-    
+
     OGRGTMDataSource *poDS = new OGRGTMDataSource();
 
-    if( !poDS->Open( pszName, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, FALSE ) )
     {
         delete poDS;
         poDS = NULL;
@@ -69,15 +71,19 @@ OGRDataSource *OGRGTMDriver::Open( const char * pszName, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRGTMDriver::CreateDataSource( const char* pszName,
-                                               char** papszOptions )
+static GDALDataset *OGRGTMDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     CPLAssert( NULL != pszName );
     CPLDebug( "GTM", "Attempt to create: %s", pszName );
-    
+
     OGRGTMDataSource *poDS = new OGRGTMDataSource();
 
     if( !poDS->Create( pszName, papszOptions ) )
@@ -90,24 +96,30 @@ OGRDataSource *OGRGTMDriver::CreateDataSource( const char* pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRGTMDriver::TestCapability( const char* pszCap )
-{
-    if( EQUAL(pszCap, ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRGTM()                           */
 /************************************************************************/
 
 void RegisterOGRGTM()
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRGTMDriver );
-}
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "GPSTrackMaker" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
+        poDriver->SetDescription( "GPSTrackMaker" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "GPSTrackMaker" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "gtm gtz" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_gtm.html" );
 
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRGTMDriverOpen;
+        poDriver->pfnCreate = OGRGTMDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/gtm/ogrgtmlayer.cpp b/ogr/ogrsf_frmts/gtm/ogrgtmlayer.cpp
index 726bde7..93f3de1 100644
--- a/ogr/ogrsf_frmts/gtm/ogrgtmlayer.cpp
+++ b/ogr/ogrsf_frmts/gtm/ogrgtmlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrgtmlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrgtmlayer.cpp 27884 2014-10-19 22:27:48Z rouault $
  *
  * Project:  GTM Driver
  * Purpose:  Implementation of OGRGTMLayer class.
@@ -82,6 +82,10 @@ int OGRGTMLayer::TestCapability( const char * pszCap )
     if (EQUAL(pszCap,OLCFastFeatureCount) &&
         m_poFilterGeom == NULL && m_poAttrQuery == NULL )
         return TRUE;
+    else if( EQUAL(pszCap,OLCCreateField) )
+        return poDS != NULL && poDS->getOutputFP() != NULL;
+    else if( EQUAL(pszCap,OLCSequentialWrite) )
+        return poDS != NULL && poDS->getOutputFP() != NULL;
     else
         return FALSE;
 }
@@ -132,8 +136,8 @@ OGRErr OGRGTMLayer::CheckAndFixCoordinatesValidity( double& pdfLatitude, double&
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRGTMLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
-
+OGRErr OGRGTMLayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
diff --git a/ogr/ogrsf_frmts/htf/GNUmakefile b/ogr/ogrsf_frmts/htf/GNUmakefile
index ada927e..2c1d32b 100644
--- a/ogr/ogrsf_frmts/htf/GNUmakefile
+++ b/ogr/ogrsf_frmts/htf/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrhtfdriver.o ogrhtfdatasource.o ogrhtflayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/htf/ogr_htf.h b/ogr/ogrsf_frmts/htf/ogr_htf.h
index 29db8ca..9f5017b 100644
--- a/ogr/ogrsf_frmts/htf/ogr_htf.h
+++ b/ogr/ogrsf_frmts/htf/ogr_htf.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_htf.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_htf.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  HTF Translator
  * Purpose:  Definition of classes for OGR .htf driver.
@@ -113,7 +113,7 @@ protected:
 
     virtual int                 TestCapability( const char * );
 
-    virtual int                 GetFeatureCount(int bForce = TRUE);
+    virtual GIntBig             GetFeatureCount(int bForce = TRUE);
 };
 
 /************************************************************************/
@@ -158,8 +158,7 @@ class OGRHTFDataSource : public OGRDataSource
                         OGRHTFDataSource();
                         ~OGRHTFDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -170,19 +169,4 @@ class OGRHTFDataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                             OGRHTFDriver                             */
-/************************************************************************/
-
-class OGRHTFDriver : public OGRSFDriver
-{
-  public:
-                ~OGRHTFDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_HTF_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/htf/ogrhtfdatasource.cpp b/ogr/ogrsf_frmts/htf/ogrhtfdatasource.cpp
index 959e201..3aecce3 100644
--- a/ogr/ogrsf_frmts/htf/ogrhtfdatasource.cpp
+++ b/ogr/ogrsf_frmts/htf/ogrhtfdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrhtfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrhtfdatasource.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  HTF Translator
  * Purpose:  Implements OGRHTFDataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrhtfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrhtfdatasource.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                          OGRHTFDataSource()                          */
@@ -105,14 +105,9 @@ OGRLayer* OGRHTFDataSource::GetLayerByName( const char* pszLayerName )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRHTFDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRHTFDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
 // -------------------------------------------------------------------- 
@@ -123,19 +118,6 @@ int OGRHTFDataSource::Open( const char * pszFilename, int bUpdateIn)
     if (fp == NULL)
         return FALSE;
 
-    char szBuffer[11];
-    int nbRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
-    szBuffer[nbRead] = '\0';
-
-    int bIsHTF = strcmp(szBuffer, "HTF HEADER") == 0;
-    if (!bIsHTF)
-    {
-        VSIFCloseL(fp);
-        return FALSE;
-    }
-
-    VSIFSeekL(fp, 0, SEEK_SET);
-
     const char* pszLine;
     int bEndOfHTFHeader = FALSE;
     int bIsSouth = FALSE;
@@ -199,22 +181,22 @@ int OGRHTFDataSource::Open( const char * pszFilename, int bUpdateIn)
         else if (strncmp(pszLine, "SW GRID COORDINATE - EASTING: ", 30) == 0)
         {
             bHasSWEasting = TRUE;
-            dfSWEasting = atof(pszLine + 30);
+            dfSWEasting = CPLAtof(pszLine + 30);
         }
         else if (strncmp(pszLine, "SW GRID COORDINATE - NORTHING: ", 31) == 0)
         {
             bHasSWNorthing = TRUE;
-            dfSWNorthing = atof(pszLine + 31);
+            dfSWNorthing = CPLAtof(pszLine + 31);
         }
         else if (strncmp(pszLine, "NE GRID COORDINATE - EASTING: ", 30) == 0)
         {
             bHasNEEasting = TRUE;
-            dfNEEasting = atof(pszLine + 30);
+            dfNEEasting = CPLAtof(pszLine + 30);
         }
         else if (strncmp(pszLine, "NE GRID COORDINATE - NORTHING: ", 31) == 0)
         {
             bHasNENorthing = TRUE;
-            dfNENorthing = atof(pszLine + 31);
+            dfNENorthing = CPLAtof(pszLine + 31);
         }
         else if (strncmp(pszLine, "TOTAL SOUNDINGS: ", 17) == 0)
         {
diff --git a/ogr/ogrsf_frmts/htf/ogrhtfdriver.cpp b/ogr/ogrsf_frmts/htf/ogrhtfdriver.cpp
index 877856f..a4ebf6e 100644
--- a/ogr/ogrsf_frmts/htf/ogrhtfdriver.cpp
+++ b/ogr/ogrsf_frmts/htf/ogrhtfdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrhtfdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrhtfdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  HTF Translator
  * Purpose:  Implements OGRHTFDriver.
@@ -30,39 +30,27 @@
 #include "ogr_htf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrhtfdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrhtfdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGRHTF();
 
 /************************************************************************/
-/*                           ~OGRHTFDriver()                            */
-/************************************************************************/
-
-OGRHTFDriver::~OGRHTFDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRHTFDriver::GetName()
+static GDALDataset *OGRHTFDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    return "HTF";
-}
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL )
+        return NULL;
 
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-OGRDataSource *OGRHTFDriver::Open( const char * pszFilename, int bUpdate )
+    if( strncmp((const char*)poOpenInfo->pabyHeader,  "HTF HEADER", strlen("HTF HEADER")) != 0 )
+        return NULL;
 
-{
     OGRHTFDataSource   *poDS = new OGRHTFDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -72,21 +60,30 @@ OGRDataSource *OGRHTFDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRHTFDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRHTF()                           */
 /************************************************************************/
 
 void RegisterOGRHTF()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRHTFDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "HTF" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "HTF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Hydrographic Transfer Vector" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_htf.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRHTFDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/htf/ogrhtflayer.cpp b/ogr/ogrsf_frmts/htf/ogrhtflayer.cpp
index c7ab582..295ac8a 100644
--- a/ogr/ogrsf_frmts/htf/ogrhtflayer.cpp
+++ b/ogr/ogrsf_frmts/htf/ogrhtflayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrhtflayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrhtflayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  HTF Translator
  * Purpose:  Implements OGRHTFLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogrhtflayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrhtflayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRHTFLayer()                             */
@@ -65,6 +65,7 @@ OGRHTFPolygonLayer::OGRHTFPolygonLayer( const char* pszFilename, int nZone, int
 
 {
     poFeatureDefn = new OGRFeatureDefn( "polygon" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPolygon  );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -92,6 +93,7 @@ OGRHTFSoundingLayer::OGRHTFSoundingLayer( const char* pszFilename, int nZone, in
 
 {
     poFeatureDefn = new OGRFeatureDefn( "sounding" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPoint  );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -398,8 +400,8 @@ OGRFeature *OGRHTFPolygonLayer::GetNextRawFeature()
             char** papszTokens = CSLTokenizeString(pszLine);
             if (CSLCount(papszTokens) == 4)
             {
-                double dfEasting = atof(papszTokens[2]);
-                double dfNorthing = atof(papszTokens[3]);
+                double dfEasting = CPLAtof(papszTokens[2]);
+                double dfNorthing = CPLAtof(papszTokens[3]);
                 if (!bHastFirstCoord)
                 {
                     bHastFirstCoord = TRUE;
@@ -526,7 +528,7 @@ OGRFeature *OGRHTFSoundingLayer::GetNextRawFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRHTFSoundingLayer::GetFeatureCount(int bForce)
+GIntBig OGRHTFSoundingLayer::GetFeatureCount(int bForce)
 {
     if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
         return OGRHTFLayer::GetFeatureCount(bForce);
@@ -626,6 +628,7 @@ OGRHTFMetadataLayer::OGRHTFMetadataLayer(std::vector<CPLString> aosMD)
     nNextFID = 0;
 
     poFeatureDefn = new OGRFeatureDefn( "metadata" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone  );
 
diff --git a/ogr/ogrsf_frmts/idb/GNUmakefile b/ogr/ogrsf_frmts/idb/GNUmakefile
index dcfb697..cb8e6a9 100644
--- a/ogr/ogrsf_frmts/idb/GNUmakefile
+++ b/ogr/ogrsf_frmts/idb/GNUmakefile
@@ -7,7 +7,7 @@ OBJ	=	ogridbdatasource.o ogridblayer.o ogridbdriver.o \
 
 IDB_DEFS =	-DIT_DLLIB -DIT_DO_NOT_SIMULATE_BOOL
 
-CPPFLAGS :=	-I.. -I../.. $(GDAL_INCLUDE) $(IDB_INC) $(IDB_DEFS) $(CPPFLAGS)
+CPPFLAGS :=	-I.. -I../..  $(IDB_INC) $(IDB_DEFS) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/idb/ogr_idb.h b/ogr/ogrsf_frmts/idb/ogr_idb.h
index 0cb9c84..4fc8e82 100644
--- a/ogr/ogrsf_frmts/idb/ogr_idb.h
+++ b/ogr/ogrsf_frmts/idb/ogr_idb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_idb.h 15583 2008-10-23 00:04:33Z warmerdam $
+ * $Id: ogr_idb.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIDBTableLayer class, access to an existing table
@@ -73,7 +73,7 @@ class OGRIDBLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -112,17 +112,17 @@ class OGRIDBTableLayer : public OGRIDBLayer
                                   );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
 #if 0
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 #endif    
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     virtual OGRSpatialReference *GetSpatialRef();
 
@@ -148,9 +148,9 @@ class OGRIDBSelectLayer : public OGRIDBLayer
                         ~OGRIDBSelectLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
diff --git a/ogr/ogrsf_frmts/idb/ogridblayer.cpp b/ogr/ogrsf_frmts/idb/ogridblayer.cpp
index 9e708d7..1e4f6b2 100644
--- a/ogr/ogrsf_frmts/idb/ogridblayer.cpp
+++ b/ogr/ogrsf_frmts/idb/ogridblayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogridblayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogridblayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIDBLayer class, code shared between
@@ -33,7 +33,7 @@
 #include "ogr_idb.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogridblayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogridblayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRIDBLayer()                            */
@@ -98,6 +98,7 @@ CPLErr OGRIDBLayer::BuildFeatureDefn( const char *pszLayerName,
 
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     const ITTypeInfo * poInfo = poCurr->RowType();
     int    nRawColumns = poInfo->ColumnCount();
 
@@ -389,7 +390,7 @@ OGRFeature *OGRIDBLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRIDBLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRIDBLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
diff --git a/ogr/ogrsf_frmts/idb/ogridbselectlayer.cpp b/ogr/ogrsf_frmts/idb/ogridbselectlayer.cpp
index 0850d26..fdeb777 100644
--- a/ogr/ogrsf_frmts/idb/ogridbselectlayer.cpp
+++ b/ogr/ogrsf_frmts/idb/ogridbselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogridbselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogridbselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIDBSelectLayer class, layer access to the results
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_idb.h"
 
-CPL_CVSID("$Id: ogridbselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogridbselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRIDBSelectLayer()                         */
@@ -133,7 +133,7 @@ void OGRIDBSelectLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRIDBSelectLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRIDBSelectLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRIDBLayer::GetFeature( nFeatureId );
@@ -171,7 +171,7 @@ OGRErr OGRIDBSelectLayer::GetExtent(OGREnvelope *, int )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRIDBSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRIDBSelectLayer::GetFeatureCount( int bForce )
 
 {
     return OGRIDBLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/idb/ogridbtablelayer.cpp b/ogr/ogrsf_frmts/idb/ogridbtablelayer.cpp
index 52a0b17..b67faae 100644
--- a/ogr/ogrsf_frmts/idb/ogridbtablelayer.cpp
+++ b/ogr/ogrsf_frmts/idb/ogridbtablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogridbtablelayer.cpp 26688 2013-12-02 19:07:41Z rouault $
+ * $Id: ogridbtablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIDBTableLayer class, access to an existing table
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_idb.h"
 
-CPL_CVSID("$Id: ogridbtablelayer.cpp 26688 2013-12-02 19:07:41Z rouault $");
+CPL_CVSID("$Id: ogridbtablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 /************************************************************************/
 /*                          OGRIDBTableLayer()                         */
 /************************************************************************/
@@ -316,7 +316,7 @@ void OGRIDBTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRIDBTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRIDBTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -421,7 +421,7 @@ int OGRIDBTableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRIDBTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRIDBTableLayer::GetFeatureCount( int bForce )
 
 {
     return OGRIDBLayer::GetFeatureCount( bForce );
@@ -483,7 +483,7 @@ OGRSpatialReference *OGRIDBTableLayer::GetSpatialRef()
 }
 
 #if 0
-OGRErr OGRIDBTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRIDBTableLayer::ISetFeature( OGRFeature *poFeature )
 {
     OGRErr eErr(OGRERR_FAILURE);
 
@@ -697,7 +697,7 @@ OGRErr OGRIDBTableLayer::SetFeature( OGRFeature *poFeature )
 
 #endif
 
-OGRErr OGRIDBTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRIDBTableLayer::ISetFeature( OGRFeature *poFeature )
 {
     OGRErr eErr(OGRERR_FAILURE);
 
@@ -863,7 +863,7 @@ OGRErr OGRIDBTableLayer::SetFeature( OGRFeature *poFeature )
     return OGRERR_NONE;
 }
 
-OGRErr OGRIDBTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRIDBTableLayer::ICreateFeature( OGRFeature *poFeature )
 {
     OGRErr eErr(OGRERR_FAILURE);
 
diff --git a/ogr/ogrsf_frmts/idrisi/GNUmakefile b/ogr/ogrsf_frmts/idrisi/GNUmakefile
index 3b68458..545929a 100644
--- a/ogr/ogrsf_frmts/idrisi/GNUmakefile
+++ b/ogr/ogrsf_frmts/idrisi/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogridrisidriver.o ogridrisidatasource.o ogridrisilayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../../../frmts/idrisi $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../../../frmts/idrisi  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/idrisi/ogr_idrisi.h b/ogr/ogrsf_frmts/idrisi/ogr_idrisi.h
index 4a13f04..5a0afe7 100644
--- a/ogr/ogrsf_frmts/idrisi/ogr_idrisi.h
+++ b/ogr/ogrsf_frmts/idrisi/ogr_idrisi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_idrisi.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_idrisi.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  Idrisi Translator
  * Purpose:  Definition of classes for OGR Idrisi driver.
@@ -79,7 +79,7 @@ protected:
     void SetExtent(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig         GetFeatureCount( int bForce = TRUE );
 };
 
 /************************************************************************/
@@ -97,8 +97,7 @@ class OGRIdrisiDataSource : public OGRDataSource
                         OGRIdrisiDataSource();
                         ~OGRIdrisiDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
diff --git a/ogr/ogrsf_frmts/idrisi/ogridrisidatasource.cpp b/ogr/ogrsf_frmts/idrisi/ogridrisidatasource.cpp
index 74f2015..3b81a8c 100644
--- a/ogr/ogrsf_frmts/idrisi/ogridrisidatasource.cpp
+++ b/ogr/ogrsf_frmts/idrisi/ogridrisidatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogridrisidatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogridrisidatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  Idrisi Translator
  * Purpose:  Implements OGRIdrisiDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "idrisi.h"
 
-CPL_CVSID("$Id: ogridrisidatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogridrisidatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        OGRIdrisiDataSource()                         */
@@ -87,20 +87,9 @@ OGRLayer *OGRIdrisiDataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRIdrisiDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRIdrisiDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
-// --------------------------------------------------------------------
-//      Does this appear to be a .vct file?
-// --------------------------------------------------------------------
-    if ( !EQUAL(CPLGetExtension(pszFilename), "vct") )
-        return FALSE;
-
     pszName = CPLStrdup( pszFilename );
 
     VSILFILE* fpVCT = VSIFOpenL(pszFilename, "rb");
diff --git a/ogr/ogrsf_frmts/idrisi/ogridrisidriver.cpp b/ogr/ogrsf_frmts/idrisi/ogridrisidriver.cpp
index c1ed5e5..62881c7 100644
--- a/ogr/ogrsf_frmts/idrisi/ogridrisidriver.cpp
+++ b/ogr/ogrsf_frmts/idrisi/ogridrisidriver.cpp
@@ -30,7 +30,7 @@
 #include "ogr_idrisi.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogridrisidriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogridrisidriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 // g++ ogr/ogrsf_frmts/idrisi/*.cpp -Wall -g -fPIC -shared -o ogr_Idrisi.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts/idrisi -Iogr/ogrsf_frmts -Ifrmts/idrisi
 
@@ -62,9 +62,20 @@ const char *OGRIdrisiDriver::GetName()
 OGRDataSource *OGRIdrisiDriver::Open( const char * pszFilename, int bUpdate )
 
 {
+    if (bUpdate)
+    {
+        return NULL;
+    }
+
+// --------------------------------------------------------------------
+//      Does this appear to be a .vct file?
+// --------------------------------------------------------------------
+    if ( !EQUAL(CPLGetExtension(pszFilename), "vct") )
+        return NULL;
+
     OGRIdrisiDataSource   *poDS = new OGRIdrisiDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -89,6 +100,10 @@ int OGRIdrisiDriver::TestCapability( CPL_UNUSED const char * pszCap )
 void RegisterOGRIdrisi()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRIdrisiDriver );
+    OGRSFDriver* poDriver = new OGRIdrisiDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Idrisi Vector (.vct)" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vct" );
+    poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
-
diff --git a/ogr/ogrsf_frmts/idrisi/ogridrisilayer.cpp b/ogr/ogrsf_frmts/idrisi/ogridrisilayer.cpp
index f2afdb5..ee2455e 100644
--- a/ogr/ogrsf_frmts/idrisi/ogridrisilayer.cpp
+++ b/ogr/ogrsf_frmts/idrisi/ogridrisilayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogridrisilayer.cpp 27500 2014-07-06 15:01:51Z rouault $
+ * $Id: ogridrisilayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  Idrisi Translator
  * Purpose:  Implements OGRIdrisiLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogridrisilayer.cpp 27500 2014-07-06 15:01:51Z rouault $");
+CPL_CVSID("$Id: ogridrisilayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                         OGRIdrisiLayer()                             */
@@ -62,6 +62,7 @@ OGRIdrisiLayer::OGRIdrisiLayer( const char* pszFilename,
         poSRS = NULL;
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     poFeatureDefn->SetGeomType( eGeomType );
@@ -161,7 +162,7 @@ int OGRIdrisiLayer::Detect_AVL_ADC(const char* pszFilename)
     if( pszRecords == NULL || atoi(pszRecords) != (int)nTotalFeatures )
     {
         CPLDebug("IDRISI", ".adc file found, but 'records' not found or not "
-                 "consistant with feature number declared in .vdc");
+                 "consistent with feature number declared in .vdc");
         CSLDestroy( papszADC );
         return FALSE;
     }
@@ -608,7 +609,7 @@ OGRErr OGRIdrisiLayer::GetExtent(OGREnvelope *psExtent, int bForce)
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRIdrisiLayer::GetFeatureCount( int bForce )
+GIntBig OGRIdrisiLayer::GetFeatureCount( int bForce )
 {
     if (nTotalFeatures > 0 && m_poFilterGeom == NULL && m_poAttrQuery == NULL)
         return nTotalFeatures;
diff --git a/ogr/ogrsf_frmts/ili/GNUmakefile b/ogr/ogrsf_frmts/ili/GNUmakefile
index 5959635..b513f6c 100644
--- a/ogr/ogrsf_frmts/ili/GNUmakefile
+++ b/ogr/ogrsf_frmts/ili/GNUmakefile
@@ -5,17 +5,17 @@ include ../../../GDALmake.opt
 OBJ	=	ogrili1driver.o ogrili1datasource.o ogrili1layer.o \
                 ogrili2driver.o ogrili2datasource.o ogrili2layer.o \
                 ili1reader.o ili2reader.o ili2handler.o \
-                ilihelper.o imdreader.o
+                imdreader.o
 
 ifeq ($(HAVE_GEOS),yes)
 CPPFLAGS 	:=	-DHAVE_GEOS=1 $(GEOS_CFLAGS) $(CPPFLAGS)
 endif
 
-CPPFLAGS :=	-I.. -I../.. $(GDAL_INCLUDE) $(XERCES_INCLUDE) $(CPPFLAGS)
+CPPFLAGS :=	-I.. -I../..  $(XERCES_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
 clean:
 	rm -f *.o $(O_OBJ)
 
-$(O_OBJ):	ogr_ili1.h ogr_ili2.h ilihelper.h imdreader.h ili1reader.h ili1readerp.h ili2reader.h ili2readerp.h
+$(O_OBJ):	ogr_ili1.h ogr_ili2.h imdreader.h ili1reader.h ili1readerp.h ili2reader.h ili2readerp.h
diff --git a/ogr/ogrsf_frmts/ili/drv_ili.html b/ogr/ogrsf_frmts/ili/drv_ili.html
index 25c0756..174aa42 100644
--- a/ogr/ogrsf_frmts/ili/drv_ili.html
+++ b/ogr/ogrsf_frmts/ili/drv_ili.html
@@ -20,27 +20,38 @@ With the usage of unified, documented geodata and the flexible exchange possibil
 <li>the contract-proof security and the availability of the software 
 </ul>
 
-OGR supports INTERLIS 1 and INTERLIS 2 (2.2 and 2.3).
+OGR supports INTERLIS 1 and INTERLIS 2 (2.2 and 2.3) with the following limitations:
+<ul>
+<li>Curves are converted to line segments
+<li>Embedded INTERLIS 2 structures are not supported yet
+<li>Incremental transfer is not supported
+<li>Transfer id (TID) is used as feature id
+</ul>
 
-<h2>Model</h2>
+<h2>Model support</h2>
+
+Data is read and written into transfer files which have different formats in INTERLIS 1 (.itf) and INTERLIS 2 (.xtf).
+
+Models are passed in IlisMeta format by using "a_filename.xtf,models.imd" as a connection string.<p>
+
+IlisMeta files can be be generated with the ili2c compiler. Command line example:
+<pre>
+java -jar ili2c.jar --ilidirs '%ILI_DIR;http://models.interlis.ch/;%JAR_DIR' -oIMD --out models.imd model1.ili [model2.ili ...]
+</pre>
 
-Data is read and written into transfer files which have different formats in INTERLIS 1 (.itf) and INTERLIS 2 (.xml).
-For using the INTERLIS model (.ili) a Java interpreter is needed at runtime and ili2c.jar (included in the 
-<a href="http://interlis.ch/interlis2/download23_e.php#outils">Compiler for INTERLIS 2</a>) must be in the Java path.
-The model file can be added to the transfer file seperated by a comma.<p>
 Some possible transformations using <a href="http://www.gdal.org/ogr/ogr2ogr.html">ogr2ogr</a>.<p>
 <ul>
 <li>
 Interlis 1 -> Shape:
 <pre>
-ogr2ogr -f "ESRI Shapefile" shpdir ili-bsp.itf,ili-bsp.ili
+ogr2ogr -f "ESRI Shapefile" shpdir ili-bsp.itf,Beispiel.imd
 </pre>
 </li>
 
 <li>
 Interlis 2 -> Shape:
 <pre>
-ogr2ogr -f "ESRI Shapefile" shpdir RoadsExdm2ien.xml,RoadsExdm2ben.ili,RoadsExdm2ien.ili
+ogr2ogr -f "ESRI Shapefile" shpdir RoadsExdm2ien.xml,RoadsExdm2ien.imd
 </pre>
 or without model:
 <pre>
@@ -49,24 +60,17 @@ ogr2ogr -f "ESRI Shapefile" shpdir RoadsExdm2ien.xml
 </li>
 
 <li>
-Shape -> Interlis 1:
-<pre>
-ogr2ogr -f "Interlis 1" ili-bsp.itf Bodenbedeckung__BoFlaechen_Form.shp
-</pre>
-</li>
-
-<li>
 Shape -> Interlis 2:
 <pre>
-ogr2ogr -f "Interlis 2" LandCover.xml,RoadsExdm2ben.ili RoadsExdm2ben_10.Roads.LandCover.shp
+ogr2ogr -f "Interlis 2" LandCover.xml,RoadsExdm2ien.imd RoadsExdm2ben.Roads.LandCover.shp
 </pre>
 </li>
 
 <li>
-Incremental import from Interlis 1 into PostGIS:
+Importing multiple Interlis 1 files into PostGIS:
 <pre>
-ogr2ogr -f PostgreSQL PG:dbname=warmerda av_fixpunkte_ohne_LFPNachfuehrung.itf,av.ili -lco OVERWRITE=yes
-ogr2ogr -f PostgreSQL PG:dbname=warmerda av_fixpunkte_mit_LFPNachfuehrung.itf,av.ili -append
+ogr2ogr -f PostgreSQL PG:dbname=warmerda av_fixpunkte_ohne_LFPNachfuehrung.itf,av.imd -lco OVERWRITE=yes
+ogr2ogr -f PostgreSQL PG:dbname=warmerda av_fixpunkte_mit_LFPNachfuehrung.itf,av.imd -append
 </pre>
 </li>
 </ul>
@@ -78,12 +82,18 @@ INTERLIS arc geometries are converted to polygons.<br></br>
 The interpolation angle can be changed with the environment variable ARC_DEGREES (Default: 1 degree).<br></br>
 
 
+<h3>OGR versions prior to 1.11</h3>
+
+For using the INTERLIS model (.ili) a Java interpreter is needed at runtime and ili2c.jar (included in the 
+<a href="http://interlis.ch/interlis2/download23_e.php#outils">Compiler for INTERLIS 2</a>) must be in the Java path.<p>
+
+
 <h2>Other Notes</h2>
 <ul>
-<li>More Information: <a href="http://giswiki.hsr.ch/OGR">http://giswiki.hsr.ch/OGR</a> (german)</li>
-<li> Development of the OGR INTERLIS driver was supported by 
+<li><a href="https://github.com/sourcepole/ogrtools">ogrtools</a> library includes extensions for the OGR Interlis driver</li>
+<li>Development of the OGR INTERLIS driver was supported by 
 <a href="http://www.kogis.ch/">Swiss Federal Administration</a>,  
-<a href="http://www.so.ch/de/pub/departemente/bjd/gis.htm">Canton Solothurn</a> and 
+<a href="http://www.sogis.ch/">Canton Solothurn</a> and 
 <a href="http://www.geoinformation.tg.ch/">Canton Thurgovia</a>.</li> 
 </ul>
 
diff --git a/ogr/ogrsf_frmts/ili/ili1reader.cpp b/ogr/ogrsf_frmts/ili/ili1reader.cpp
index 730d7eb..dbbd0cf 100644
--- a/ogr/ogrsf_frmts/ili/ili1reader.cpp
+++ b/ogr/ogrsf_frmts/ili/ili1reader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili1reader.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ili1reader.cpp 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 1 Reader
  * Purpose:  Implementation of ILI1Reader class.
@@ -34,7 +34,6 @@
 #include "ogr_api.h"
 #include "ogr_geos.h"
 
-#include "ilihelper.h"
 #include "ili1reader.h"
 #include "ili1readerp.h"
 
@@ -50,7 +49,7 @@
 #  endif
 #endif
 
-CPL_CVSID("$Id: ili1reader.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ili1reader.cpp 29140 2015-05-03 20:09:32Z pka $");
 
 //
 // ILI1Reader
@@ -66,7 +65,6 @@ ILI1Reader::ILI1Reader() {
   codeBlank = '_';
   codeUndefined = '@';
   codeContinue = '\\';
-  SetArcDegrees(1);
 }
 
 ILI1Reader::~ILI1Reader() {
@@ -78,10 +76,6 @@ ILI1Reader::~ILI1Reader() {
   CPLFree(papoLayers);
 }
 
-void ILI1Reader::SetArcDegrees(double arcDegrees) {
-  arcIncr = arcDegrees*PI/180;
-}
-
 /* -------------------------------------------------------------------- */
 /*      Open the source file.                                           */
 /* -------------------------------------------------------------------- */
@@ -116,9 +110,13 @@ int ILI1Reader::ReadModel(ImdReader *poImdReader, const char *pszModelFilename,
     {
       if (it2->second.geomTable)
       {
+        OGRFeatureDefn* poGeomTableDefn = it2->second.geomTable;
+        OGRGeomFieldDefn* poOGRGeomFieldDefn = poGeomTableDefn->GetGeomFieldDefn(0);
         GeomFieldInfos oGeomFieldInfos;
+        // We add iliGeomType to recognize Ili1 geom tables
+        oGeomFieldInfos[poOGRGeomFieldDefn->GetNameRef()].iliGeomType = it2->second.iliGeomType;
         //CPLDebug( "OGR_ILI", "Adding OGRILI1Layer with geometry table '%s'", it2->second.geomTable->GetName() );
-        OGRILI1Layer* geomlayer = new OGRILI1Layer(it2->second.geomTable, oGeomFieldInfos, poDS);
+        OGRILI1Layer* geomlayer = new OGRILI1Layer(poGeomTableDefn, oGeomFieldInfos, poDS);
         AddLayer(geomlayer);
       }
     }
@@ -223,30 +221,6 @@ int ILI1Reader::ReadFeatures() {
     return ret;
 }
 
-int ILI1Reader::AddIliGeom(OGRFeature *feature, int iField, long fpos)
-{
-#if defined(_WIN32) || defined(__WIN32__)
-    //Other positions on Windows !?
-#else
-    long nBlockLen = VSIFTell( fpItf )-fpos;
-    VSIFSeek( fpItf, fpos, SEEK_SET );
-
-    char *pszRawData = (char *) CPLMalloc(nBlockLen+1);
-    if( (int) VSIFRead( pszRawData, 1, nBlockLen, fpItf ) != nBlockLen )
-    {
-        CPLFree( pszRawData );
-
-        CPLError( CE_Failure, CPLE_FileIO, "Read of transfer file failed." );
-        return FALSE;
-    }
-    pszRawData[nBlockLen]= '\0';
-    feature->SetField(iField, pszRawData);
-    CPLFree( pszRawData );
-#endif
-    return TRUE;
-}
-
-
 int ILI1Reader::ReadTable(CPL_UNUSED const char *layername) {
     char **tokens = NULL;
     const char *firsttok = NULL;
@@ -258,118 +232,97 @@ int ILI1Reader::ReadTable(CPL_UNUSED const char *layername) {
     OGRFeatureDefn *featureDef = curLayer->GetLayerDefn();
     OGRFeature *feature = NULL;
 
-    long fpos = VSIFTell(fpItf);
     while (ret && (tokens = ReadParseLine()))
     {
       firsttok = CSLGetField(tokens, 0);
       if (EQUAL(firsttok, "OBJE"))
       {
-        //Check for features spread over multiple objects
-        if (featureDef->GetGeomType() == wkbPolygon) //FIXME: Multi-geom support
-        {
-          //Multiple polygon rings
-          feature = curLayer->GetFeatureRef(atol(CSLGetField(tokens, 2)));
-        }
-        else if (featureDef->GetGeomType() == wkbGeometryCollection)
-        {
-          //AREA lines spread over mutltiple objects
-        }
-        else
+        if (featureDef->GetFieldCount() == 0)
         {
-          feature = NULL;
+          CPLError(CE_Warning, CPLE_AppDefined,
+              "No field definition found for table: %s", featureDef->GetName() );
+          //Model not read - use heuristics
+          for (fIndex=1; fIndex<CSLCount(tokens); fIndex++)
+          {
+            char szFieldName[32];
+            sprintf(szFieldName, "Field%02d", fIndex);
+            OGRFieldDefn oFieldDefn(szFieldName, OFTString);
+            featureDef->AddFieldDefn(&oFieldDefn);
+          }
         }
+        //start new feature
+        feature = new OGRFeature(featureDef);
 
-        if (feature == NULL)
+        int fieldno = 0;
+        for (fIndex=1; fIndex<CSLCount(tokens) && fieldno < featureDef->GetFieldCount(); fIndex++, fieldno++)
         {
-          if (featureDef->GetFieldCount() == 0)
-          {
-            CPLError(CE_Warning, CPLE_AppDefined,
-                "No field definition found for table: %s", featureDef->GetName() );
-            //Model not read - use heuristics
-            for (fIndex=1; fIndex<CSLCount(tokens); fIndex++)
-            {
-              char szFieldName[32];
-              sprintf(szFieldName, "Field%02d", fIndex);
-              OGRFieldDefn oFieldDefn(szFieldName, OFTString);
-              featureDef->AddFieldDefn(&oFieldDefn);
+          if (!(tokens[fIndex][0] == codeUndefined && tokens[fIndex][1] == '\0')) {
+            //CPLDebug( "READ TABLE OGR_ILI", "Setting Field %d (Type %d): %s", fieldno, featureDef->GetFieldDefn(fieldno)->GetType(), tokens[fIndex]);
+            if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTString) {
+                //Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
+                char* pszRecoded = CPLRecode(tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
+                //Replace space marks
+                for(char* pszString = pszRecoded; *pszString != '\0'; pszString++ ) {
+                    if (*pszString == codeBlank) *pszString = ' ';
+                }
+                feature->SetField(fieldno, pszRecoded);
+                CPLFree(pszRecoded);
+            } else {
+              feature->SetField(fieldno, tokens[fIndex]);
             }
-          }
-          //start new feature
-          feature = new OGRFeature(featureDef);
-
-          int fieldno = 0;
-          for (fIndex=1; fIndex<CSLCount(tokens) && fieldno < featureDef->GetFieldCount(); fIndex++, fieldno++)
-          {
-            if (!(tokens[fIndex][0] == codeUndefined && tokens[fIndex][1] == '\0')) {
-              //CPLDebug( "READ TABLE OGR_ILI", "Setting Field %d (Type %d): %s", fieldno, featureDef->GetFieldDefn(fieldno)->GetType(), tokens[fIndex]);
-              if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTString) {
-                  //Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode to UTF-8
-                  char* pszRecoded = CPLRecode(tokens[fIndex], CPL_ENC_ISO8859_1, CPL_ENC_UTF8);
-                  //Replace space marks
-                  for(char* pszString = pszRecoded; *pszString != '\0'; pszString++ ) {
-                      if (*pszString == codeBlank) *pszString = ' ';
-                  }
-                  feature->SetField(fieldno, pszRecoded);
-                  CPLFree(pszRecoded);
+            if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTReal
+                && fieldno > 0
+                && featureDef->GetFieldDefn(fieldno-1)->GetType() == OFTReal) {
+              //check for Point geometry (Coord type)
+              // if there is no ili model read,
+              // we have no chance to detect the
+              // geometry column!!
+              CPLString geomfldname = featureDef->GetFieldDefn(fieldno)->GetNameRef();
+              //Check if name ends with _1
+              if (geomfldname.size() >= 2 && geomfldname[geomfldname.size()-2] == '_') {
+                geomfldname = geomfldname.substr(0, geomfldname.size()-2);
+                geomIdx = featureDef->GetGeomFieldIndex(geomfldname.c_str());
+                if (geomIdx == -1)
+                {
+                  CPLError(CE_Warning, CPLE_AppDefined,
+                      "No matching definition for field '%s' of table %s found", geomfldname.c_str(), featureDef->GetName());
+                }
               } else {
-                feature->SetField(fieldno, tokens[fIndex]);
+                geomIdx = -1;
               }
-              if (featureDef->GetFieldDefn(fieldno)->GetType() == OFTReal
-                  && fieldno > 0
-                  && featureDef->GetFieldDefn(fieldno-1)->GetType() == OFTReal) {
-                //check for Point geometry (Coord type)
-                // if there is no ili model read,
-                // we have no chance to detect the
-                // geometry column!!
-                CPLString geomfldname = featureDef->GetFieldDefn(fieldno)->GetNameRef();
-                //Check if name ends with _1
-                if (geomfldname.size() >= 2 && geomfldname[geomfldname.size()-2] == '_') {
-                  geomfldname = geomfldname.substr(0, geomfldname.size()-2);
-                  geomIdx = featureDef->GetGeomFieldIndex(geomfldname.c_str());
-                  if (geomIdx == -1)
-                  {
-                    CPLError(CE_Warning, CPLE_AppDefined,
-                        "No matching definition for field '%s' of table %s found", geomfldname.c_str(), featureDef->GetName());
-                  }
-                } else {
-                  geomIdx = -1;
-                }
-                if (geomIdx >= 0) {
-                  if (featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint) {
-                    //add Point geometry
-                    OGRPoint *ogrPoint = new OGRPoint(atof(tokens[fIndex-1]), atof(tokens[fIndex]));
-                    feature->SetGeomFieldDirectly(geomIdx, ogrPoint);
-                  } else if (featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint25D && fieldno > 1 && featureDef->GetFieldDefn(fieldno-2)->GetType() == OFTReal) {
-                    //add 3D Point geometry
-                    OGRPoint *ogrPoint = new OGRPoint(atof(tokens[fIndex-2]), atof(tokens[fIndex-1]), atof(tokens[fIndex]));
-                    feature->SetGeomFieldDirectly(geomIdx, ogrPoint);
-                  }
+              if (geomIdx >= 0) {
+                if (featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint) {
+                  //add Point geometry
+                  OGRPoint *ogrPoint = new OGRPoint(CPLAtof(tokens[fIndex-1]), CPLAtof(tokens[fIndex]));
+                  feature->SetGeomFieldDirectly(geomIdx, ogrPoint);
+                } else if (featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint25D && fieldno > 1 && featureDef->GetFieldDefn(fieldno-2)->GetType() == OFTReal) {
+                  //add 3D Point geometry
+                  OGRPoint *ogrPoint = new OGRPoint(CPLAtof(tokens[fIndex-2]), CPLAtof(tokens[fIndex-1]), CPLAtof(tokens[fIndex]));
+                  feature->SetGeomFieldDirectly(geomIdx, ogrPoint);
                 }
               }
             }
           }
-          if (!warned && featureDef->GetFieldCount() != CSLCount(tokens)-1 && !(featureDef->GetFieldCount() == CSLCount(tokens) && EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))) {
-            CPLError(CE_Warning, CPLE_AppDefined,
-                "Field count doesn't match. %d declared, %d found", featureDef->GetFieldCount(), CSLCount(tokens)-1);
-            warned = TRUE;
-          }
-          if (feature->GetFieldCount() > 0) {
-            feature->SetFID(atol(feature->GetFieldAsString(0))); //TODO: use IDENT field from model instead of TID
-          }
-          curLayer->AddFeature(feature);
-          geomIdx = -1; //Reset
         }
+        if (!warned && featureDef->GetFieldCount() != CSLCount(tokens)-1) {
+          CPLError(CE_Warning, CPLE_AppDefined,
+              "Field count of table %s doesn't match. %d declared, %d found (e.g. ignored LINEATTR)", featureDef->GetName(), featureDef->GetFieldCount(), CSLCount(tokens)-1);
+          warned = TRUE;
+        }
+        if (feature->GetFieldCount() > 0) {
+          // USE _TID as FID. TODO: respect IDENT field from model
+          feature->SetFID(feature->GetFieldAsInteger64(0));
+        }
+        curLayer->AddFeature(feature);
+        geomIdx = -1; //Reset
       }
       else if (EQUAL(firsttok, "STPT"))
       {
         //Find next non-Point geometry
-        do { geomIdx++; } while (geomIdx < featureDef->GetGeomFieldCount() && featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint);
+        if (geomIdx < 0) geomIdx = 0;
+        while (geomIdx < featureDef->GetGeomFieldCount() && featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint) { geomIdx++; }
         OGRwkbGeometryType geomType = (geomIdx < featureDef->GetGeomFieldCount()) ? featureDef->GetGeomFieldDefn(geomIdx)->GetType() : wkbNone;
         ReadGeom(tokens, geomIdx, geomType, feature);
-        if (EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))
-        {
-          AddIliGeom(feature, featureDef->GetFieldCount()-1, fpos); //TODO: append multi-OBJECT geometries
-        }
       }
       else if (EQUAL(firsttok, "ELIN"))
       {
@@ -381,16 +334,13 @@ int ILI1Reader::ReadTable(CPL_UNUSED const char *layername) {
         //Find next non-Point geometry
         do { geomIdx++; } while (geomIdx < featureDef->GetGeomFieldCount() && featureDef->GetGeomFieldDefn(geomIdx)->GetType() == wkbPoint);
         ReadGeom(tokens, geomIdx, wkbMultiLineString, feature);
-        if (EQUAL(featureDef->GetFieldDefn(featureDef->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))
-        {
-          AddIliGeom(feature, featureDef->GetFieldCount()-1, fpos);
-        }
       }
       else if (EQUAL(firsttok, "PERI"))
       {
       }
       else if (EQUAL(firsttok, "ETAB"))
       {
+        CPLDebug( "OGR_ILI", "Total features: " CPL_FRMT_GIB, curLayer->GetFeatureCount() );
         CSLDestroy(tokens);
         return TRUE;
       }
@@ -400,7 +350,6 @@ int ILI1Reader::ReadTable(CPL_UNUSED const char *layername) {
       }
 
       CSLDestroy(tokens);
-      fpos = VSIFTell(fpItf);
     }
 
     return ret;
@@ -410,84 +359,79 @@ void ILI1Reader::ReadGeom(char **stgeom, int geomIdx, OGRwkbGeometryType eType,
     char **tokens = NULL;
     const char *firsttok = NULL;
     int end = FALSE;
-    int isArc = FALSE;
+    OGRCompoundCurve *ogrCurve = NULL; //current compound curve
     OGRLineString *ogrLine = NULL; //current line
-    OGRLinearRing *ogrRing = NULL; //current ring
-    OGRPolygon *ogrPoly = NULL; //current polygon
-    OGRPoint ogrPoint, arcPoint, endPoint; //points for arc interpolation
-    OGRMultiLineString *ogrMultiLine = NULL; //current multi line
+    OGRCircularString *arc = NULL; //current arc
+    OGRCurvePolygon *ogrPoly = NULL; //current polygon
+    OGRPoint ogrPoint; //current point
+    OGRMultiCurve *ogrMultiLine = NULL; //current multi line
 
-    //CPLDebug( "OGR_ILI", "ILI1Reader::ReadGeom geomIdx: %d", geomIdx);
-    //tokens = ["STPT", "1111", "22222"]
-    ogrPoint.setX(atof(stgeom[1])); ogrPoint.setY(atof(stgeom[2]));
-    ogrLine = (eType == wkbPolygon) ? new OGRLinearRing() : new OGRLineString();
-    ogrLine->addPoint(&ogrPoint);
-
-    //Set feature geometry
-    if (eType == wkbMultiLineString)
+    //CPLDebug( "OGR_ILI", "ILI1Reader::ReadGeom geomIdx: %d OGRGeometryType: %s", geomIdx, OGRGeometryTypeToName(eType));
+    if (eType == wkbNone)
     {
-      ogrMultiLine = new OGRMultiLineString();
-      feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine);
+      CPLError(CE_Warning, CPLE_AppDefined, "Calling ILI1Reader::ReadGeom with wkbNone" );
     }
-    else if (eType == wkbGeometryCollection) //AREA
-    {
-      if (feature->GetGeometryRef())
-        ogrMultiLine = (OGRMultiLineString *)feature->GetGeometryRef();
-      else
-      {
-        ogrMultiLine = new OGRMultiLineString();
-        feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine);
-      }
-    }
-    else if (eType == wkbPolygon)
+
+    //Initialize geometry
+
+    ogrCurve = new OGRCompoundCurve();
+
+    if (eType == wkbMultiCurve || eType == wkbMultiLineString)
     {
-      if (feature->GetGeometryRef())
-      {
-        ogrPoly = (OGRPolygon *)feature->GetGeometryRef();
-        if (ogrPoly->getNumInteriorRings() > 0)
-          ogrRing = ogrPoly->getInteriorRing(ogrPoly->getNumInteriorRings()-1);
-        else
-          ogrRing = ogrPoly->getExteriorRing();
-        if (ogrRing && !ogrRing->get_IsClosed()) ogrLine = ogrRing; //SURFACE polygon spread over multiple OBJECTs
-      }
-      else
-      {
-        ogrPoly = new OGRPolygon();
-        feature->SetGeomFieldDirectly(geomIdx, ogrPoly);
-      }
+      ogrMultiLine = new OGRMultiCurve();
     }
-    else
+    else if (eType == wkbPolygon || eType == wkbCurvePolygon)
     {
-      feature->SetGeomFieldDirectly(geomIdx, ogrLine);
+      ogrPoly = new OGRCurvePolygon();
     }
 
+    //tokens = ["STPT", "1111", "22222"]
+    ogrPoint.setX(CPLAtof(stgeom[1])); ogrPoint.setY(CPLAtof(stgeom[2]));
+    ogrLine = new OGRLineString();
+    ogrLine->addPoint(&ogrPoint);
+
     //Parse geometry
     while (!end && (tokens = ReadParseLine()))
     {
       firsttok = CSLGetField(tokens, 0);
       if (EQUAL(firsttok, "LIPT"))
       {
-        if (isArc) {
-          endPoint.setX(atof(tokens[1])); endPoint.setY(atof(tokens[2]));
-          interpolateArc(ogrLine, &ogrPoint, &arcPoint, &endPoint, arcIncr);
+        ogrPoint.setX(CPLAtof(tokens[1])); ogrPoint.setY(CPLAtof(tokens[2]));
+        if (arc) {
+          arc->addPoint(&ogrPoint);
+          ogrCurve->addCurveDirectly(arc);
+          arc = NULL;
         }
-        ogrPoint.setX(atof(tokens[1])); ogrPoint.setY(atof(tokens[2])); isArc = FALSE;
         ogrLine->addPoint(&ogrPoint);
       }
       else if (EQUAL(firsttok, "ARCP"))
       {
-        isArc = TRUE;
-        arcPoint.setX(atof(tokens[1])); arcPoint.setY(atof(tokens[2]));
+        //Finish line and start arc
+        if (ogrLine->getNumPoints() > 1) {
+          ogrCurve->addCurveDirectly(ogrLine);
+          ogrLine = new OGRLineString();
+        } else {
+          ogrLine->empty();
+        }
+        arc = new OGRCircularString();
+        arc->addPoint(&ogrPoint);
+        ogrPoint.setX(CPLAtof(tokens[1])); ogrPoint.setY(CPLAtof(tokens[2]));
+        arc->addPoint(&ogrPoint);
       }
       else if (EQUAL(firsttok, "ELIN"))
       {
-        if (ogrMultiLine)
-        {
-          ogrMultiLine->addGeometryDirectly(ogrLine);
+        if (!ogrLine->IsEmpty()) {
+          ogrCurve->addCurveDirectly(ogrLine);
         }
-        if (ogrPoly && ogrLine != ogrRing)
-        {
-          ogrPoly->addRingDirectly((OGRLinearRing *)ogrLine);
+        if (!ogrCurve->IsEmpty()) {
+          if (ogrMultiLine)
+          {
+            ogrMultiLine->addGeometryDirectly(ogrCurve);
+          }
+          if (ogrPoly)
+          {
+            ogrPoly->addRingDirectly(ogrCurve);
+          }
         }
         end = TRUE;
       }
@@ -514,6 +458,30 @@ void ILI1Reader::ReadGeom(char **stgeom, int geomIdx, OGRwkbGeometryType eType,
 
       CSLDestroy(tokens);
     }
+
+    //Set feature geometry
+    if (eType == wkbMultiCurve)
+    {
+      feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine);
+    }
+    else if (eType == wkbMultiLineString)
+    {
+      feature->SetGeomFieldDirectly(geomIdx, ogrMultiLine->getLinearGeometry());
+      delete ogrMultiLine;
+    }
+    else if (eType == wkbCurvePolygon)
+    {
+      feature->SetGeomFieldDirectly(geomIdx, ogrPoly);
+    }
+    else if (eType == wkbPolygon)
+    {
+      feature->SetGeomFieldDirectly(geomIdx, ogrPoly->getLinearGeometry());
+      delete ogrPoly;
+    }
+    else
+    {
+      feature->SetGeomFieldDirectly(geomIdx, ogrCurve);
+    }
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/ili/ili1reader.h b/ogr/ogrsf_frmts/ili/ili1reader.h
index b4217cf..aa47aca 100644
--- a/ogr/ogrsf_frmts/ili/ili1reader.h
+++ b/ogr/ogrsf_frmts/ili/ili1reader.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili1reader.h 26979 2014-02-23 21:55:20Z pka $
+ * $Id: ili1reader.h 29093 2015-05-01 18:50:08Z pka $
  *
  * Project:  Interlis 1 Reader
  * Purpose:  Private Declarations for Reader code.
@@ -47,7 +47,6 @@ public:
     virtual OGRLayer *GetLayer( int ) = 0;
     virtual OGRLayer *GetLayerByName( const char* ) = 0;
     virtual int  GetLayerCount() = 0;
-    virtual void SetArcDegrees(double newArcDegrees) = 0;
 };
 
 IILI1Reader *CreateILI1Reader();
diff --git a/ogr/ogrsf_frmts/ili/ili1readerp.h b/ogr/ogrsf_frmts/ili/ili1readerp.h
index fc24265..eb1a69b 100644
--- a/ogr/ogrsf_frmts/ili/ili1readerp.h
+++ b/ogr/ogrsf_frmts/ili/ili1readerp.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili1readerp.h 26979 2014-02-23 21:55:20Z pka $
+ * $Id: ili1readerp.h 29093 2015-05-01 18:50:08Z pka $
  *
  * Project:  Interlis 1 Reader
  * Purpose:  Private Declarations for Reader code.
@@ -48,7 +48,6 @@ private:
     int          nLayers;
     OGRILI1Layer **papoLayers;
     OGRILI1Layer *curLayer;
-    double       arcIncr;
     char         codeBlank;
     char         codeUndefined;
     char         codeContinue;
@@ -57,7 +56,6 @@ public:
                  ILI1Reader();
                 ~ILI1Reader();
 
-    void         SetArcDegrees(double arcDegrees);
     int          OpenFile( const char *pszFilename );
     int          ReadModel( ImdReader *poImdReader, const char *pszModelFilename, OGRILI1DataSource *poDS );
     int          ReadFeatures();
@@ -66,7 +64,6 @@ public:
     char         **ReadParseLine();
 
     void         AddLayer( OGRILI1Layer * poNewLayer );
-    int          AddIliGeom(OGRFeature *feature, int iField, long fpos);
     OGRILI1Layer *GetLayer( int );
     OGRILI1Layer *GetLayerByName( const char* );
     int          GetLayerCount();
diff --git a/ogr/ogrsf_frmts/ili/ili2handler.cpp b/ogr/ogrsf_frmts/ili/ili2handler.cpp
index c00719b..d48dd62 100644
--- a/ogr/ogrsf_frmts/ili/ili2handler.cpp
+++ b/ogr/ogrsf_frmts/ili/ili2handler.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili2handler.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ili2handler.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  Interlis 2 Reader
  * Purpose:  Implementation of ILI2Handler class.
@@ -35,7 +35,7 @@
 #include "ili2readerp.h"
 #include <xercesc/sax2/Attributes.hpp>
 
-CPL_CVSID("$Id: ili2handler.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ili2handler.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 // 
 // constants
@@ -166,7 +166,7 @@ void ILI2Handler::characters( const XMLCh *const chars,
 /************************************************************************/
 
 void ILI2Handler::characters( const XMLCh *const chars,
-                     const unsigned int length ) {
+                     CPL_UNUSED const unsigned int length ) {
   
   // add the text element
   if (level >= 3) {
diff --git a/ogr/ogrsf_frmts/ili/ili2reader.cpp b/ogr/ogrsf_frmts/ili/ili2reader.cpp
index 39154bb..36fb7af 100644
--- a/ogr/ogrsf_frmts/ili/ili2reader.cpp
+++ b/ogr/ogrsf_frmts/ili/ili2reader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili2reader.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ili2reader.cpp 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 2 Reader
  * Purpose:  Implementation of ILI2Reader class.
@@ -32,7 +32,6 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-#include "ilihelper.h"
 #include "ili2reader.h"
 #include "ili2readerp.h"
 
@@ -41,7 +40,7 @@ char *tr_strdup( const XMLCh * );
 
 using namespace std;
 
-CPL_CVSID("$Id: ili2reader.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ili2reader.cpp 29140 2015-05-03 20:09:32Z pka $");
 
 //
 // constants
@@ -154,11 +153,11 @@ OGRPoint *getPoint(DOMElement *elem) {
     char* pszTagName = XMLString::transcode(coordElem->getTagName());
     char* pszObjValue = getObjValue(coordElem);
     if (cmpStr("C1", pszTagName) == 0)
-      pt->setX(atof(pszObjValue));
+      pt->setX(CPLAtof(pszObjValue));
     else if (cmpStr("C2", pszTagName) == 0)
-      pt->setY(atof(pszObjValue));
+      pt->setY(CPLAtof(pszObjValue));
     else if (cmpStr("C3", pszTagName) == 0)
-      pt->setZ(atof(pszObjValue));
+      pt->setZ(CPLAtof(pszObjValue));
     CPLFree(pszObjValue);
     XMLString::release(&pszTagName);
     coordElem = (DOMElement *)coordElem->getNextSibling();
@@ -167,9 +166,9 @@ OGRPoint *getPoint(DOMElement *elem) {
   return pt;
 }
 
-OGRLineString *ILI2Reader::getArc(DOMElement *elem) {
+OGRCircularString *ILI2Reader::getArc(DOMElement *elem) {
   // elem -> ARC
-  OGRLineString *ls = new OGRLineString();
+  OGRCircularString *arc = new OGRCircularString();
   // previous point -> start point
   OGRPoint *ptStart = getPoint((DOMElement *)elem->getPreviousSibling()); // COORD or ARC
   // end point
@@ -183,40 +182,37 @@ OGRLineString *ILI2Reader::getArc(DOMElement *elem) {
     char* pszTagName = XMLString::transcode(arcElem->getTagName());
     char* pszObjValue = getObjValue(arcElem);
     if (cmpStr("C1", pszTagName) == 0)
-      ptEnd->setX(atof(pszObjValue));
+      ptEnd->setX(CPLAtof(pszObjValue));
     else if (cmpStr("C2", pszTagName) == 0)
-      ptEnd->setY(atof(pszObjValue));
+      ptEnd->setY(CPLAtof(pszObjValue));
     else if (cmpStr("C3", pszTagName) == 0)
-      ptEnd->setZ(atof(pszObjValue));
+      ptEnd->setZ(CPLAtof(pszObjValue));
     else if (cmpStr("A1", pszTagName) == 0)
-      ptOnArc->setX(atof(pszObjValue));
+      ptOnArc->setX(CPLAtof(pszObjValue));
     else if (cmpStr("A2", pszTagName) == 0)
-      ptOnArc->setY(atof(pszObjValue));
+      ptOnArc->setY(CPLAtof(pszObjValue));
     else if (cmpStr("A3", pszTagName) == 0)
-      ptOnArc->setZ(atof(pszObjValue));
+      ptOnArc->setZ(CPLAtof(pszObjValue));
     else if (cmpStr("R", pszTagName) == 0) {
-      // radius = atof(pszObjValue);
+      // radius = CPLAtof(pszObjValue);
     }
     CPLFree(pszObjValue);
     XMLString::release(&pszTagName);
     arcElem = (DOMElement *)arcElem->getNextSibling();
   }
-  ptEnd->flattenTo2D();
-  ptOnArc->flattenTo2D();
-  interpolateArc(ls, ptStart, ptOnArc, ptEnd, arcIncr);
+  arc->addPoint(ptStart);
+  arc->addPoint(ptOnArc);
+  arc->addPoint(ptEnd);
   delete ptStart;
   delete ptOnArc;
   delete ptEnd;
-  return ls;
+  return arc;
 }
 
-OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) {
+OGRCompoundCurve *getPolyline(DOMElement *elem) {
   // elem -> POLYLINE
-  OGRLineString *ls;
-  if (bAsLinearRing)
-      ls = new OGRLinearRing();
-  else
-      ls = new OGRLineString();
+  OGRCompoundCurve *ogrCurve = new OGRCompoundCurve();
+  OGRLineString *ls = new OGRLineString();
 
   DOMElement *lineElem = (DOMElement *)elem->getFirstChild();
   while (lineElem != NULL) {
@@ -228,6 +224,14 @@ OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) {
       delete poPoint;
     }
     else if (cmpStr(ILI2_ARC, pszTagName) == 0) {
+      //Finish line and start arc
+      if (ls->getNumPoints() > 1) {
+        ogrCurve->addCurveDirectly(ls);
+        ls = new OGRLineString();
+      } else {
+        ls->empty();
+      }
+      OGRCircularString *arc = new OGRCircularString();
       // end point
       OGRPoint *ptEnd = new OGRPoint();
       // point on the arc
@@ -240,19 +244,19 @@ OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) {
         char* pszTagName = XMLString::transcode(arcElem->getTagName());
         char* pszObjValue = getObjValue(arcElem);
         if (cmpStr("C1", pszTagName) == 0)
-          ptEnd->setX(atof(pszObjValue));
+          ptEnd->setX(CPLAtof(pszObjValue));
         else if (cmpStr("C2", pszTagName) == 0)
-          ptEnd->setY(atof(pszObjValue));
+          ptEnd->setY(CPLAtof(pszObjValue));
         else if (cmpStr("C3", pszTagName) == 0)
-          ptEnd->setZ(atof(pszObjValue));
+          ptEnd->setZ(CPLAtof(pszObjValue));
         else if (cmpStr("A1", pszTagName) == 0)
-          ptOnArc->setX(atof(pszObjValue));
+          ptOnArc->setX(CPLAtof(pszObjValue));
         else if (cmpStr("A2", pszTagName) == 0)
-          ptOnArc->setY(atof(pszObjValue));
+          ptOnArc->setY(CPLAtof(pszObjValue));
         else if (cmpStr("A3", pszTagName) == 0)
-          ptOnArc->setZ(atof(pszObjValue));
+          ptOnArc->setZ(CPLAtof(pszObjValue));
         else if (cmpStr("R", pszTagName) == 0) {
-          // radius = atof(pszObjValue);
+          // radius = CPLAtof(pszObjValue);
         }
         CPLFree(pszObjValue);
         XMLString::release(&pszTagName);
@@ -260,10 +264,11 @@ OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) {
         arcElem = (DOMElement *)arcElem->getNextSibling();
       }
 
-      ptEnd->flattenTo2D();
-      ptOnArc->flattenTo2D();
       OGRPoint *ptStart = getPoint((DOMElement *)lineElem->getPreviousSibling()); // COORD or ARC
-      interpolateArc(ls, ptStart, ptOnArc, ptEnd, PI/180);
+      arc->addPoint(ptStart);
+      arc->addPoint(ptOnArc);
+      arc->addPoint(ptEnd);
+      ogrCurve->addCurveDirectly(arc);
 
       delete ptStart;
       delete ptEnd;
@@ -275,10 +280,13 @@ OGRLineString *getLineString(DOMElement *elem, int bAsLinearRing) {
     lineElem = (DOMElement *)lineElem->getNextSibling();
   }
 
-  return ls;
+  if (ls->getNumPoints() > 1) {
+    ogrCurve->addCurveDirectly(ls);
+  }
+  return ogrCurve;
 }
 
-OGRLinearRing *getBoundary(DOMElement *elem) {
+OGRCompoundCurve *getBoundary(DOMElement *elem) {
 
   DOMElement *lineElem = (DOMElement *)elem->getFirstChild();
   if (lineElem != NULL)
@@ -287,16 +295,16 @@ OGRLinearRing *getBoundary(DOMElement *elem) {
     if (cmpStr(ILI2_POLYLINE, pszTagName) == 0)
     {
       XMLString::release(&pszTagName);
-      return (OGRLinearRing*) getLineString(lineElem, TRUE);
+      return getPolyline(lineElem);
     }
     XMLString::release(&pszTagName);
   }
 
-  return new OGRLinearRing();
+  return new OGRCompoundCurve();
 }
 
-OGRPolygon *getPolygon(DOMElement *elem) {
-  OGRPolygon *pg = new OGRPolygon();
+OGRCurvePolygon *getPolygon(DOMElement *elem) {
+  OGRCurvePolygon *pg = new OGRCurvePolygon();
 
   DOMElement *boundaryElem = (DOMElement *)elem->getFirstChild(); // outer boundary
   while (boundaryElem != NULL) {
@@ -339,7 +347,7 @@ OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type) {
         {
           delete gm;
           XMLString::release(&pszTagName);
-          return getLineString(childElem, FALSE);
+          return getPolyline(childElem);
         }
         break;
       case ILI2_BOUNDARY_TYPE :
@@ -347,7 +355,7 @@ OGRGeometry *ILI2Reader::getGeometry(DOMElement *elem, int type) {
         {
           delete gm;
           XMLString::release(&pszTagName);
-          return getLineString(childElem, FALSE);
+          return getPolyline(childElem);
         }
         break;
       case ILI2_AREA_TYPE :
@@ -451,7 +459,17 @@ void ILI2Reader::SetFieldValues(OGRFeature *feature, DOMElement* elem) {
     } else {
       char *fName = fieldName(childElem);
       int fIndex = feature->GetGeomFieldIndex(fName);
-      feature->SetGeomFieldDirectly(fIndex, getGeometry(childElem, type));
+      OGRGeometry *geom = getGeometry(childElem, type);
+      if (fIndex == -1) { // Unkown model
+        feature->SetGeometryDirectly(geom);
+      } else {
+        OGRwkbGeometryType geomType = feature->GetGeomFieldDefnRef(fIndex)->GetType();
+        if (geomType == wkbMultiLineString || geomType == wkbPolygon) {
+          feature->SetGeomFieldDirectly(fIndex, geom->getLinearGeometry());
+        } else {
+          feature->SetGeomFieldDirectly(fIndex, geom);
+        }
+      }
       CPLFree(fName);
     }
   }
@@ -487,10 +505,6 @@ ILI2Reader::~ILI2Reader() {
     }
 }
 
-void ILI2Reader::SetArcDegrees(double arcDegrees) {
-  arcIncr = arcDegrees*PI/180;
-}
-
 void ILI2Reader::SetSourceFile( const char *pszFilename ) {
     CPLFree( m_pszFilename );
     m_pszFilename = CPLStrdup( pszFilename );
@@ -511,7 +525,7 @@ int ILI2Reader::SetupParser() {
         {
             char* msg = tr_strdup(toCatch.getMessage());
             CPLError( CE_Failure, CPLE_AppDefined,
-                      "Unable to initalize Xerces C++ based ILI2 reader. "
+                      "Unable to initialize Xerces C++ based ILI2 reader. "
                       "Error message:\n%s\n", msg );
             CPLFree(msg);
 
diff --git a/ogr/ogrsf_frmts/ili/ili2reader.h b/ogr/ogrsf_frmts/ili/ili2reader.h
index 4b7f70d..91c9034 100644
--- a/ogr/ogrsf_frmts/ili/ili2reader.h
+++ b/ogr/ogrsf_frmts/ili/ili2reader.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili2reader.h 27184 2014-04-14 22:21:56Z pka $
+ * $Id: ili2reader.h 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 2 Reader
  * Purpose:  Public Declarations for Reader code.
@@ -52,7 +52,6 @@ public:
     
     virtual std::list<OGRLayer *> GetLayers() = 0;
     virtual int GetLayerCount() = 0;
-    virtual void SetArcDegrees(double newArcDegrees) = 0;
 };
 
 IILI2Reader *CreateILI2Reader();
diff --git a/ogr/ogrsf_frmts/ili/ili2readerp.h b/ogr/ogrsf_frmts/ili/ili2readerp.h
index a8d7e78..f04e22b 100644
--- a/ogr/ogrsf_frmts/ili/ili2readerp.h
+++ b/ogr/ogrsf_frmts/ili/ili2readerp.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ili2readerp.h 27184 2014-04-14 22:21:56Z pka $
+ * $Id: ili2readerp.h 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 2 Reader
  * Purpose:  Private Declarations for Reader code.
@@ -138,7 +138,6 @@ public:
              ILI2Reader();
             ~ILI2Reader();
 
-    void     SetArcDegrees(double arcDegrees);
     void     SetSourceFile( const char *pszFilename );
     int      ReadModel( ImdReader *poImdReader, const char *modelFilename );
     int      SaveClasses( const char *pszFile );
@@ -151,7 +150,7 @@ public:
     void     SetFieldValues(OGRFeature *feature, DOMElement* elem);
     const char* GetLayerName(/*IOM_BASKET model, IOM_OBJECT table*/);
     void     AddField(OGRLayer* layer/*, IOM_BASKET model, IOM_OBJECT obj*/);
-    OGRLineString *getArc(DOMElement *elem);
+    OGRCircularString *getArc(DOMElement *elem);
     OGRGeometry *getGeometry(DOMElement *elem, int type);
     void     setFieldDefn(OGRFeatureDefn *featureDef, DOMElement* elem);
 };
diff --git a/ogr/ogrsf_frmts/ili/ilihelper.cpp b/ogr/ogrsf_frmts/ili/ilihelper.cpp
deleted file mode 100644
index d565213..0000000
--- a/ogr/ogrsf_frmts/ili/ilihelper.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/******************************************************************************
- * $Id$
- *
- * Project:  Interlis 1/2 Translator
- * Purpose:  Helper functions for Interlis reader
- * Author:   Pirmin Kalberer, Sourcepole AG
- *
- ******************************************************************************
- * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
- *
- * 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.
- ****************************************************************************/
-
-
-#include "ilihelper.h"
-
-
-CPL_CVSID("$Id$");
-
-
-OGRPoint *getARCCenter(OGRPoint *ptStart, OGRPoint *ptArc, OGRPoint *ptEnd) {
-  // FIXME precision
-  double bx = ptStart->getX(); double by = ptStart->getY();
-  double cx = ptArc->getX(); double cy = ptArc->getY();
-  double dx = ptEnd->getX(); double dy = ptEnd->getY();
-  double temp, bc, cd, det, x, y;
-
-  temp = cx*cx+cy*cy;
-  bc = (bx*bx + by*by - temp)/2.0;
-  cd = (temp - dx*dx - dy*dy)/2.0;
-  det = (bx-cx)*(cy-dy)-(cx-dx)*(by-cy);
-
-  OGRPoint *center = new OGRPoint();
-
-  if (fabs(det) < 1.0e-6) { // could not determin the determinante: too small
-    return center;
-  }
-  det = 1/det;
-  x = (bc*(cy-dy)-cd*(by-cy))*det;
-  y = ((bx-cx)*cd-(cx-dx)*bc)*det;
-
-  center->setX(x);
-  center->setY(y);
-
-  return center;
-}
-
-void interpolateArc(OGRLineString* line, OGRPoint *ptStart, OGRPoint *ptOnArc, OGRPoint *ptEnd, double arcIncr) {
-  OGRPoint *center = getARCCenter(ptStart, ptOnArc, ptEnd);
-
-  double cx = center->getX(); double cy = center->getY();
-  double px = ptOnArc->getX(); double py = ptOnArc->getY();
-  double r = sqrt((cx-px)*(cx-px)+(cy-py)*(cy-py));
-
-  //assure minimal chord length (0.002m???)
-  double myAlpha = 2.0*acos(1.0-0.002/r);      
-  if (myAlpha < arcIncr)  {
-      arcIncr = myAlpha;
-  }
-
-  double a1 = atan2(ptStart->getY() - cy, ptStart->getX() - cx);
-  double a2 = atan2(py - cy, px - cx);
-  double a3 = atan2(ptEnd->getY() - cy, ptEnd->getX() - cx);
-
-  double sweep;
-
-  // Clockwise
-  if(a1 > a2 && a2 > a3) {
-    sweep = a3 - a1;
-  }
-  // Counter-clockwise
-  else if(a1 < a2 && a2 < a3) {
-    sweep = a3 - a1;
-  }
-  // Clockwise, wrap
-  else if((a1 < a2 && a1 > a3) || (a2 < a3 && a1 > a3)) {
-    sweep = a3 - a1 + 2*PI;
-  }
-  // Counter-clockwise, wrap
-  else if((a1 > a2 && a1 < a3) || (a2 > a3 && a1 < a3)) {
-    sweep = a3 - a1 - 2*PI;
-  }
-  else {
-    sweep = 0.0;
-  }
-
-  int ptcount = ceil(fabs(sweep/arcIncr));
-
-  if(sweep < 0) arcIncr *= -1.0;
-
-  double angle = a1;
-
-  for(int i = 0; i < ptcount - 1; i++) {
-    angle += arcIncr;
-
-    if(arcIncr > 0.0 && angle > PI) angle -= 2*PI;
-    if(arcIncr < 0.0 && angle < -1*PI) angle -= 2*PI;
-
-    double x = cx + r*cos(angle);
-    double y = cy + r*sin(angle);
-   
-    line->addPoint(x, y, 0);
-
-   
-    if((angle < a2) && ((angle + arcIncr) > a2)) {
-       line->addPoint(ptOnArc);
-    }
-
-    if((angle > a2) && ((angle + arcIncr) < a2)) {
-       line->addPoint(ptOnArc);
-    }
-   
-  }
-  line->addPoint(ptEnd);
-  delete center;
-}
-
diff --git a/ogr/ogrsf_frmts/ili/ilihelper.h b/ogr/ogrsf_frmts/ili/ilihelper.h
deleted file mode 100644
index cfcc26f..0000000
--- a/ogr/ogrsf_frmts/ili/ilihelper.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/******************************************************************************
- * $Id$
- *
- * Project:  Interlis 1/2 Translator
- * Purpose:   Definition of classes for OGR Interlis 1 driver.
- * Author:   Pirmin Kalberer, Sourcepole AG
- *
- ******************************************************************************
- * Copyright (c) 2004, Pirmin Kalberer, Sourcepole AG
- *
- * 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.
- ****************************************************************************/
-
-#ifndef _ILIHELPER_H_INCLUDED
-#define _ILIHELPER_H_INCLUDED
-
-#include "ogr_geometry.h"
-
-#ifndef PI
-#define PI  3.1415926535897932384626433832795
-#endif
-
-OGRPoint *getARCCenter(OGRPoint *ptStart, OGRPoint *ptArc, OGRPoint *ptEnd);
-double getPhi(OGRPoint *center, OGRPoint *pt);
-void interpolateArc(OGRLineString* line, OGRPoint *ptStart, OGRPoint *ptOnArc, OGRPoint *ptEnd, double arcIncr);
-
-#endif /* _ILIHELPER_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/ili/imdreader.cpp b/ogr/ogrsf_frmts/ili/imdreader.cpp
index 8155ac3..89cc959 100644
--- a/ogr/ogrsf_frmts/ili/imdreader.cpp
+++ b/ogr/ogrsf_frmts/ili/imdreader.cpp
@@ -34,6 +34,7 @@
 #include "cpl_minixml.h"
 #include <set>
 #include <vector>
+#include <algorithm>
 
 
 CPL_CVSID("$Id$");
@@ -119,12 +120,12 @@ public:
         return false;
     }
     // Add additional Geometry table for Interlis 1
-    void AddGeomTable(CPLString layerName, const char* psFieldName, OGRwkbGeometryType eType)
+    void AddGeomTable(CPLString layerName, const char* psFieldName, OGRwkbGeometryType eType, bool bRefTIDField = false)
     {
         OGRFeatureDefn* poGeomTableDefn = new OGRFeatureDefn(layerName);
         OGRFieldDefn fieldDef("_TID", OFTString);
         poGeomTableDefn->AddFieldDefn(&fieldDef);
-        if (eType == wkbPolygon)
+        if (bRefTIDField)
         {
             OGRFieldDefn fieldDefRef("_RefTID", OFTString);
             poGeomTableDefn->AddFieldDefn(&fieldDefRef);
@@ -193,7 +194,7 @@ public:
         if (CSLTestBoolean(CPLGetXMLValue( node, "Abstract", "FALSE" )))
             hasDerivedClasses = true;
     }
-    void AddFieldDefinitions()
+    void AddFieldDefinitions(NodeVector oArcLineTypes)
     {
         for (NodeVector::const_iterator it = oFields.begin(); it != oFields.end(); ++it)
         {
@@ -254,32 +255,38 @@ public:
                 {
                     const char* psKind = CPLGetXMLValue( psElementNode, "Kind", NULL );
                     poGeomFieldInfos[psName].iliGeomType = psKind;
+                    bool isLinearType = (std::find(oArcLineTypes.begin(), oArcLineTypes.end(), psElementNode) == oArcLineTypes.end());
+                    bool linearGeom = isLinearType || CSLTestBoolean(CPLGetConfigOption("OGR_STROKE_CURVE", "FALSE"));
+                    OGRwkbGeometryType multiLineType = linearGeom ? wkbMultiLineString : wkbMultiCurve;
+                    OGRwkbGeometryType polyType = linearGeom ? wkbPolygon : wkbCurvePolygon;
                     if (iliVersion == 1)
                     {
                         if (EQUAL(psKind, "Area"))
                         {
-                            CPLString areaPointGeomName = psName + CPLString("__Point");
-                            AddCoord(areaPointGeomName, psElementNode);
-
                             CPLString lineLayerName = GetName() + CPLString("_") + psName;
-                            AddGeomTable(lineLayerName, psName, wkbMultiLineString);
+                            AddGeomTable(lineLayerName, psName, multiLineType);
 
                             //Add geometry field for polygonized areas
                             AddGeomField(psName, wkbPolygon);
+
+                            //We add the area helper point geometry after polygon
+                            //for better behaviour of clients with limited multi geometry support
+                            CPLString areaPointGeomName = psName + CPLString("__Point");
+                            AddCoord(areaPointGeomName, psElementNode);
                         } else if (EQUAL(psKind, "Surface"))
                         {
                             CPLString geomLayerName = GetName() + CPLString("_") + psName;
-                            AddGeomTable(geomLayerName, psName, wkbPolygon);
-                            AddGeomField(psName, wkbPolygon);
+                            AddGeomTable(geomLayerName, psName, multiLineType, true);
+                            AddGeomField(psName, polyType);
                         } else { // Polyline, DirectedPolyline
-                            AddGeomField(psName, wkbMultiLineString);
+                            AddGeomField(psName, multiLineType);
                         }
                     } else {
                         if (EQUAL(psKind, "Area") || EQUAL(psKind, "Surface"))
                         {
-                            AddGeomField(psName, wkbPolygon);
+                            AddGeomField(psName, polyType);
                         } else { // Polyline, DirectedPolyline
-                            AddGeomField(psName, wkbMultiLineString);
+                            AddGeomField(psName, multiLineType);
                         }
                     }
                 }
@@ -331,6 +338,7 @@ void ImdReader::ReadModel(const char *pszFilename) {
     StrNodeMap oTidLookup; /* for fast lookup of REF relations */
     ClassesMap oClasses;
     NodeCountMap oAxisCount;
+    NodeVector oArcLineTypes;
     const char *modelName;
 
     /* Fill TID lookup map and IliClasses lookup map */
@@ -391,7 +399,16 @@ void ImdReader::ReadModel(const char *pszFilename) {
             if (psEntry->eType != CXT_Attribute) //ignore BID
             {
                 //CPLDebug( "OGR_ILI", "Node tag: '%s'", psEntry->pszValue);
-                if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.TransferElement") && !EQUAL(modelName, "MODEL.INTERLIS"))
+                if( iliVersion == 1 && EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.Ili1TransferElement") && !EQUAL(modelName, "MODEL.INTERLIS"))
+                {
+                    const char* psClassRef = CPLGetXMLValue( psEntry, "Ili1TransferClass.REF", NULL );
+                    const char* psElementRef = CPLGetXMLValue( psEntry, "Ili1RefAttr.REF", NULL );
+                    int iOrderPos = atoi(CPLGetXMLValue( psEntry, "Ili1RefAttr.ORDER_POS", "0" ))-1;
+                    IliClass* psParentClass = oClasses[oTidLookup[psClassRef]];
+                    CPLXMLNode* psElementNode = oTidLookup[psElementRef];
+                    psParentClass->AddFieldNode(psElementNode, iOrderPos);
+                }
+                else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.TransferElement") && !EQUAL(modelName, "MODEL.INTERLIS"))
                 {
                     const char* psClassRef = CPLGetXMLValue( psEntry, "TransferClass.REF", NULL );
                     const char* psElementRef = CPLGetXMLValue( psEntry, "TransferElement.REF", NULL );
@@ -415,6 +432,15 @@ void ImdReader::ReadModel(const char *pszFilename) {
                     CPLXMLNode* psCoordTypeNode = oTidLookup[psClassRef];
                     oAxisCount[psCoordTypeNode] += 1;
                 }
+                else if( EQUAL(psEntry->pszValue, "IlisMeta07.ModelData.LinesForm") && !EQUAL(modelName, "MODEL.INTERLIS"))
+                {
+                    const char* psLineForm = CPLGetXMLValue( psEntry, "LineForm.REF", NULL );
+                    if (EQUAL(psLineForm, "INTERLIS.ARCS")) {
+                        const char* psElementRef = CPLGetXMLValue( psEntry, "LineType.REF", NULL );
+                        CPLXMLNode* psElementNode = oTidLookup[psElementRef];
+                        oArcLineTypes.push_back(psElementNode);
+                    }
+                }
             }
             psEntry = psEntry->psNext;
 
@@ -431,7 +457,7 @@ void ImdReader::ReadModel(const char *pszFilename) {
         if (psRefSuper)
             oClasses[oTidLookup[psRefSuper]]->hasDerivedClasses = true;
         it->second->InitFieldDefinitions();
-        it->second->AddFieldDefinitions();
+        it->second->AddFieldDefinitions(oArcLineTypes);
     }
 
     /* Filter relevant classes */
diff --git a/ogr/ogrsf_frmts/ili/makefile.vc b/ogr/ogrsf_frmts/ili/makefile.vc
index 14e9a47..9fa3eca 100644
--- a/ogr/ogrsf_frmts/ili/makefile.vc
+++ b/ogr/ogrsf_frmts/ili/makefile.vc
@@ -2,7 +2,7 @@
 OBJ =	ili1reader.obj ili2reader.obj ili2handler.obj \
 	ogrili1driver.obj ogrili1datasource.obj \
 	ogrili1layer.obj ogrili2driver.obj ogrili2datasource.obj \
-	ogrili2layer.obj ilihelper.obj imdreader.obj
+	ogrili2layer.obj imdreader.obj
 
 GDAL_ROOT	=	..\..\..
 
diff --git a/ogr/ogrsf_frmts/ili/ogr_ili1.h b/ogr/ogrsf_frmts/ili/ogr_ili1.h
index b39c373..ebb34f4 100644
--- a/ogr/ogrsf_frmts/ili/ogr_ili1.h
+++ b/ogr/ogrsf_frmts/ili/ogr_ili1.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_ili1.h 26979 2014-02-23 21:55:20Z pka $
+ * $Id: ogr_ili1.h 29109 2015-05-02 11:45:44Z rouault $
  *
  * Project:  Interlis 1 Translator
  * Purpose:   Definition of classes for OGR Interlis 1 driver.
@@ -44,7 +44,9 @@ class OGRILI1DataSource;
 class OGRILI1Layer : public OGRLayer
 {
 private:
+#ifdef notused
     OGRSpatialReference *poSRS;
+#endif
     OGRFeatureDefn      *poFeatureDefn;
     GeomFieldInfos      oGeomFieldInfos;
 
@@ -52,8 +54,6 @@ private:
     OGRFeature          **papoFeatures;
     int                 nFeatureIdx;
 
-    int                 bWriter;
-
     int                 bGeomsJoined;
 
     OGRILI1DataSource   *poDS;
@@ -72,12 +72,13 @@ private:
     OGRFeature *        GetNextFeatureRef();
     OGRFeature *        GetFeatureRef( long nFID );
 
-    int                 GetFeatureCount( int bForce = TRUE );
+    GIntBig             GetFeatureCount( int bForce = TRUE );
 
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     int                 GeometryAppend( OGRGeometry *poGeometry );
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
+    GeomFieldInfos      GetGeomFieldInfos() { return oGeomFieldInfos; }
 
     OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK = TRUE );
 
@@ -85,7 +86,7 @@ private:
 
   private:
     void                JoinGeomLayers();
-    void                JoinSurfaceLayer( OGRILI1Layer* poSurfacePolyLayer, int nSurfaceFieldIndex );
+    void                JoinSurfaceLayer( OGRILI1Layer* poSurfaceLineLayer, int nSurfaceFieldIndex );
     OGRMultiPolygon*    Polygonize( OGRGeometryCollection* poLines, bool fix_crossing_lines = false );
     void                PolygonizeAreaLayer( OGRILI1Layer* poAreaLineLayer, int nAreaFieldIndex, int nPointFieldIndex );
 };
@@ -109,7 +110,7 @@ class OGRILI1DataSource : public OGRDataSource
                 OGRILI1DataSource();
                ~OGRILI1DataSource();
 
-    int         Open( const char *, int bTestOpen );
+    int         Open( const char *, char** papszOpenOptions, int bTestOpen );
     int         Create( const char *pszFile, char **papszOptions );
 
     const char *GetName() { return pszName; }
@@ -119,7 +120,7 @@ class OGRILI1DataSource : public OGRDataSource
 
     FILE       *GetTransferFile() { return fpTransfer; }
 
-    virtual OGRLayer *CreateLayer( const char *,
+    virtual OGRLayer *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -127,22 +128,4 @@ class OGRILI1DataSource : public OGRDataSource
     int         TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                            OGRILI1Driver                             */
-/************************************************************************/
-
-class OGRILI1Driver : public OGRSFDriver
-{
-  public:
-                ~OGRILI1Driver();
-
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-
-    int                 TestCapability( const char * );
-};
-
 #endif /* _OGR_ILI1_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/ili/ogr_ili2.h b/ogr/ogrsf_frmts/ili/ogr_ili2.h
index 60ab5b3..1aa3676 100644
--- a/ogr/ogrsf_frmts/ili/ogr_ili2.h
+++ b/ogr/ogrsf_frmts/ili/ogr_ili2.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_ili2.h 26953 2014-02-16 17:47:12Z pka $
+ * $Id: ogr_ili2.h 29109 2015-05-02 11:45:44Z rouault $
  *
  * Project:  Interlis 2 Translator
  * Purpose:   Definition of classes for OGR Interlis 2 driver.
@@ -60,14 +60,14 @@ private:
 
                        ~OGRILI2Layer();
 
-    OGRErr              SetFeature(OGRFeature *poFeature);
+    OGRErr              ISetFeature(OGRFeature *poFeature);
     
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    int                 GetFeatureCount( int bForce = TRUE );
+    GIntBig             GetFeatureCount( int bForce = TRUE );
 
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -99,14 +99,14 @@ class OGRILI2DataSource : public OGRDataSource
                 OGRILI2DataSource();
                ~OGRILI2DataSource();
 
-    int         Open( const char *, int bTestOpen );
+    int         Open( const char *, char** papszOpenOptions, int bTestOpen );
     int         Create( const char *pszFile, char **papszOptions );
 
     const char *GetName() { return pszName; }
     int         GetLayerCount() { return listLayer.size(); }
     OGRLayer   *GetLayer( int );
 
-    virtual OGRLayer *CreateLayer( const char *, 
+    virtual OGRLayer *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -115,22 +115,4 @@ class OGRILI2DataSource : public OGRDataSource
     int         TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                            OGRILI2Driver                             */
-/************************************************************************/
-
-class OGRILI2Driver : public OGRSFDriver
-{
-  public:
-                ~OGRILI2Driver();
-
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-
-    int                 TestCapability( const char * );
-};
-
 #endif /* _OGR_ILI2_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/ili/ogrili1datasource.cpp b/ogr/ogrsf_frmts/ili/ogrili1datasource.cpp
index 8e547d5..66becbd 100644
--- a/ogr/ogrsf_frmts/ili/ogrili1datasource.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili1datasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili1datasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrili1datasource.cpp 29139 2015-05-03 20:09:20Z pka $
  *
  * Project:  Interlis 1 Translator
  * Purpose:  Implements OGRILI1DataSource class.
@@ -36,7 +36,7 @@
 
 #include <string>
 
-CPL_CVSID("$Id: ogrili1datasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrili1datasource.cpp 29139 2015-05-03 20:09:20Z pka $");
 
 /************************************************************************/
 /*                         OGRILI1DataSource()                         */
@@ -87,7 +87,7 @@ OGRILI1DataSource::~OGRILI1DataSource()
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRILI1DataSource::Open( const char * pszNewName, int bTestOpen )
+int OGRILI1DataSource::Open( const char * pszNewName, char** papszOpenOptions, int bTestOpen )
 
 {
     FILE        *fp;
@@ -98,15 +98,23 @@ int OGRILI1DataSource::Open( const char * pszNewName, int bTestOpen )
     {
         return FALSE;
     }
+    
+    if( CSLFetchNameValue(papszOpenOptions, "MODEL") != NULL )
+    {
+        osBasename = pszNewName;
+        osModelFilename = CSLFetchNameValue(papszOpenOptions, "MODEL");
+    }
+    else
+    {
+        char **filenames = CSLTokenizeString2( pszNewName, ",", 0 );
 
-    char **filenames = CSLTokenizeString2( pszNewName, ",", 0 );
-
-    osBasename = filenames[0];
+        osBasename = filenames[0];
 
-    if( CSLCount(filenames) > 1 )
-        osModelFilename = filenames[1];
+        if( CSLCount(filenames) > 1 )
+            osModelFilename = filenames[1];
 
-    CSLDestroy( filenames );
+        CSLDestroy( filenames );
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Open the source file.                                           */
@@ -165,13 +173,18 @@ int OGRILI1DataSource::Open( const char * pszNewName, int bTestOpen )
     if (osModelFilename.length() > 0 )
         poReader->ReadModel( poImdReader, osModelFilename.c_str(), this );
 
-    if( getenv( "ARC_DEGREES" ) != NULL ) {
-      //No better way to pass arguments to the reader (it could even be an -lco arg)
-      poReader->SetArcDegrees( atof( getenv("ARC_DEGREES") ) );
+    int bResetConfigOption = FALSE;
+    if (EQUAL(CPLGetConfigOption("OGR_ARC_STEPSIZE", ""), ""))
+    {
+        bResetConfigOption = TRUE;
+        CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", "0.96");
     }
 
-    //Parse model and read data - without surface joing and polygonizing
+    //Parse model and read data - without surface join and area polygonizing
     poReader->ReadFeatures();
+    
+    if( bResetConfigOption )
+        CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", NULL);
 
     return TRUE;
 }
@@ -242,14 +255,14 @@ static char *ExtractTopic(const char * pszLayerName)
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRILI1DataSource::CreateLayer( const char * pszLayerName,
-                                CPL_UNUSED OGRSpatialReference *poSRS,
-                                OGRwkbGeometryType eType,
-                                CPL_UNUSED char ** papszOptions )
+OGRILI1DataSource::ICreateLayer( const char * pszLayerName,
+                               CPL_UNUSED OGRSpatialReference *poSRS,
+                               OGRwkbGeometryType eType,
+                               CPL_UNUSED char ** papszOptions )
 {
     FeatureDefnInfo featureDefnInfo = poImdReader->GetFeatureDefnInfo(pszLayerName);
     const char *table = pszLayerName;
@@ -300,6 +313,8 @@ int OGRILI1DataSource::TestCapability( const char * pszCap )
 {
     if( EQUAL(pszCap,ODsCCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
diff --git a/ogr/ogrsf_frmts/ili/ogrili1driver.cpp b/ogr/ogrsf_frmts/ili/ogrili1driver.cpp
index efedc77..e508222 100644
--- a/ogr/ogrsf_frmts/ili/ogrili1driver.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili1driver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili1driver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrili1driver.cpp 29109 2015-05-02 11:45:44Z rouault $
  *
  * Project:  Interlis 1 Translator
  * Purpose:  Implements OGRILI1Layer class.
@@ -30,39 +30,34 @@
 #include "ogr_ili1.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrili1driver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-/************************************************************************/
-/*                          ~OGRILI1Driver()                           */
-/************************************************************************/
-
-OGRILI1Driver::~OGRILI1Driver() {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRILI1Driver::GetName() {
-    return "Interlis 1";
-}
+CPL_CVSID("$Id: ogrili1driver.cpp 29109 2015-05-02 11:45:44Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRILI1Driver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRILI1DriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRILI1DataSource    *poDS;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update ||
+        (!poOpenInfo->bStatOK && strchr(poOpenInfo->pszFilename, ',') == NULL) )
+        return NULL;
+
+    if( poOpenInfo->fpL != NULL )
+    {
+        if( strstr((const char*)poOpenInfo->pabyHeader,"SCNT") == NULL )
+        {
+            return NULL;
+        }
+    }
+    else if( poOpenInfo->bIsDirectory )
         return NULL;
 
     poDS = new OGRILI1DataSource();
 
-    if( !poDS->Open( pszFilename, TRUE )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions, TRUE )
         || poDS->GetLayerCount() == 0 )
     {
         delete poDS;
@@ -73,12 +68,15 @@ OGRDataSource *OGRILI1Driver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRILI1Driver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRILI1DriverCreate( const char * pszName,
+                                         CPL_UNUSED int nBands,
+                                         CPL_UNUSED int nXSize,
+                                         CPL_UNUSED int nYSize,
+                                         CPL_UNUSED GDALDataType eDT,
+                                         char **papszOptions )
 {
     OGRILI1DataSource    *poDS = new OGRILI1DataSource();
 
@@ -92,23 +90,32 @@ OGRDataSource *OGRILI1Driver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRILI1Driver::TestCapability( const char * pszCap ) {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return FALSE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRILI1()                           */
 /************************************************************************/
 
 void RegisterOGRILI1() {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRILI1Driver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "Interlis 1" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "Interlis 1" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Interlis 1" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_ili.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "itf ili" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='MODEL' type='string' description='Filename of the model in IlisMeta format (.imd)'/>"
+"</OpenOptionList>" );
+
+        poDriver->pfnOpen = OGRILI1DriverOpen;
+        poDriver->pfnCreate = OGRILI1DriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/ili/ogrili1layer.cpp b/ogr/ogrsf_frmts/ili/ogrili1layer.cpp
index 578e2ec..5ec9419 100644
--- a/ogr/ogrsf_frmts/ili/ogrili1layer.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili1layer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili1layer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrili1layer.cpp 29139 2015-05-03 20:09:20Z pka $
  *
  * Project:  Interlis 1 Translator
  * Purpose:  Implements OGRILI1Layer class.
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ogr_geos.h"
 
-CPL_CVSID("$Id: ogrili1layer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrili1layer.cpp 29139 2015-05-03 20:09:20Z pka $");
 
 /************************************************************************/
 /*                           OGRILI1Layer()                              */
@@ -47,6 +47,7 @@ OGRILI1Layer::OGRILI1Layer( OGRFeatureDefn* poFeatureDefnIn,
     poDS = poDSIn;
 
     poFeatureDefn = poFeatureDefnIn;
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     oGeomFieldInfos = oGeomFieldInfosIn;
 
@@ -153,7 +154,7 @@ OGRFeature *OGRILI1Layer::GetFeatureRef( long nFID )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRILI1Layer::GetFeatureCount( int bForce )
+GIntBig OGRILI1Layer::GetFeatureCount( int bForce )
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL &&
         1 /*poAreaLineLayer == NULL*/)
@@ -172,17 +173,17 @@ static char* d2str(double val)
     if( val == (int) val )
         sprintf( strbuf, "%d", (int) val );
     else if( fabs(val) < 370 )
-        sprintf( strbuf, "%.16g", val );
+        CPLsprintf( strbuf, "%.16g", val );
     else if( fabs(val) > 100000000.0  )
-        sprintf( strbuf, "%.16g", val );
+        CPLsprintf( strbuf, "%.16g", val );
     else
-        sprintf( strbuf, "%.3f", val );
+        CPLsprintf( strbuf, "%.3f", val );
     return strbuf;
 }
 
 static void AppendCoordinateList( OGRLineString *poLine, OGRILI1DataSource *poDS)
 {
-    int         b3D = (poLine->getGeometryType() & wkb25DBit);
+    int         b3D = wkbHasZ(poLine->getGeometryType());
 
     for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
     {
@@ -196,8 +197,35 @@ static void AppendCoordinateList( OGRLineString *poLine, OGRILI1DataSource *poDS
     VSIFPrintf( poDS->GetTransferFile(), "ELIN\n" );
 }
 
+static void AppendCoumpoundCurve( OGRCompoundCurve *poCC, OGRILI1DataSource *poDS)
+{
+    for( int iMember = 0; iMember < poCC->getNumCurves(); iMember++)
+    {
+        OGRCurve *poGeometry = poCC->getCurve( iMember );
+        int b3D = wkbHasZ(poGeometry->getGeometryType());
+        int bIsArc = (poGeometry->getGeometryType() == wkbCircularString
+              || poGeometry->getGeometryType() == wkbCircularStringZ );
+        OGRSimpleCurve *poLine = (OGRSimpleCurve *)poGeometry;
+        for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
+        {
+            //Skip last point in curve member
+            if (iPoint == poLine->getNumPoints()-1 && iMember < poCC->getNumCurves()-1)
+                continue;
+            if (iMember == 0 && iPoint == 0) VSIFPrintf( poDS->GetTransferFile(), "STPT" );
+            else if (bIsArc && iPoint == 1) VSIFPrintf( poDS->GetTransferFile(), "ARCP" );
+            else VSIFPrintf( poDS->GetTransferFile(), "LIPT" );
+            VSIFPrintf( poDS->GetTransferFile(), " %s", d2str(poLine->getX(iPoint)) );
+            VSIFPrintf( poDS->GetTransferFile(), " %s", d2str(poLine->getY(iPoint)) );
+            if (b3D) VSIFPrintf( poDS->GetTransferFile(), " %s", d2str(poLine->getZ(iPoint)) );
+            VSIFPrintf( poDS->GetTransferFile(), "\n" );
+        }
+    }
+    VSIFPrintf( poDS->GetTransferFile(), "ELIN\n" );
+}
+
 int OGRILI1Layer::GeometryAppend( OGRGeometry *poGeometry )
 {
+    //CPLDebug( "OGR_ILI", "OGRILI1Layer::GeometryAppend OGRGeometryType: %s", OGRGeometryTypeToName(poGeometry->getGeometryType()));
 /* -------------------------------------------------------------------- */
 /*      2D Point                                                        */
 /* -------------------------------------------------------------------- */
@@ -251,7 +279,9 @@ int OGRILI1Layer::GeometryAppend( OGRGeometry *poGeometry )
     else if( wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPolygon
              || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiLineString
              || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiPoint
-             || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection )
+             || wkbFlatten(poGeometry->getGeometryType()) == wkbGeometryCollection
+             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiCurve
+             || wkbFlatten(poGeometry->getGeometryType()) == wkbMultiCurveZ )
     {
         OGRGeometryCollection *poGC = (OGRGeometryCollection *) poGeometry;
         int             iMember;
@@ -272,24 +302,28 @@ int OGRILI1Layer::GeometryAppend( OGRGeometry *poGeometry )
         for( iMember = 0; iMember < poGC->getNumGeometries(); iMember++)
         {
             OGRGeometry *poMember = poGC->getGeometryRef( iMember );
-
             if( !GeometryAppend( poMember ) )
                 return FALSE;
         }
 
     }
-
-    else
+    else if( poGeometry->getGeometryType() == wkbCompoundCurve
+             || poGeometry->getGeometryType() == wkbCompoundCurveZ )
+    {
+        AppendCoumpoundCurve( ( OGRCompoundCurve *) poGeometry, poDS );
+    } else {
+        CPLError(CE_Warning, CPLE_AppDefined, "Skipping unknown geometry type '%s'", OGRGeometryTypeToName(poGeometry->getGeometryType()));
         return FALSE;
+    }
 
     return TRUE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRILI1Layer::CreateFeature( OGRFeature *poFeature ) {
+OGRErr OGRILI1Layer::ICreateFeature( OGRFeature *poFeature ) {
     static long tid = -1; //system generated TID (must be unique within table)
     VSIFPrintf( poDS->GetTransferFile(), "OBJE" );
 
@@ -297,7 +331,7 @@ OGRErr OGRILI1Layer::CreateFeature( OGRFeature *poFeature ) {
     {
         //Input is not generated from an Interlis 1 source
         if (poFeature->GetFID() != OGRNullFID)
-            tid = poFeature->GetFID();
+            tid = (int)poFeature->GetFID();
         else
             ++tid;
         VSIFPrintf( poDS->GetTransferFile(), " %ld", tid );
@@ -328,28 +362,25 @@ OGRErr OGRILI1Layer::CreateFeature( OGRFeature *poFeature ) {
     // Write all fields.
     for(int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
-        if ( !EQUAL(poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), "ILI_Geometry") )
+        if ( poFeature->IsFieldSet( iField ) )
         {
-          if ( poFeature->IsFieldSet( iField ) )
-          {
-              const char *pszRaw = poFeature->GetFieldAsString( iField );
-              if (poFeatureDefn->GetFieldDefn( iField )->GetType() == OFTString) {
-                  //Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
-                  char* pszString  = CPLRecode(pszRaw, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
-                  //Replace spaces
-                  for(size_t i=0; i<strlen(pszString); i++ ) {
-                      if (pszString[i] == ' ') pszString[i] = '_';
-                  }
-                  VSIFPrintf( poDS->GetTransferFile(), " %s", pszString );
-                  CPLFree( pszString );
-              } else {
-                  VSIFPrintf( poDS->GetTransferFile(), " %s", pszRaw );
+          const char *pszRaw = poFeature->GetFieldAsString( iField );
+          if (poFeatureDefn->GetFieldDefn( iField )->GetType() == OFTString) {
+              //Interlis 1 encoding is ISO 8859-1 (Latin1) -> Recode from UTF-8
+              char* pszString  = CPLRecode(pszRaw, CPL_ENC_UTF8, CPL_ENC_ISO8859_1);
+              //Replace spaces
+              for(size_t i=0; i<strlen(pszString); i++ ) {
+                  if (pszString[i] == ' ') pszString[i] = '_';
               }
+              VSIFPrintf( poDS->GetTransferFile(), " %s", pszString );
+              CPLFree( pszString );
+          } else {
+              VSIFPrintf( poDS->GetTransferFile(), " %s", pszRaw );
           }
-          else
-          {
-              VSIFPrintf( poDS->GetTransferFile(), " @" );
-          }
+        }
+        else
+        {
+          VSIFPrintf( poDS->GetTransferFile(), " @" );
         }
     }
     VSIFPrintf( poDS->GetTransferFile(), "\n" );
@@ -357,16 +388,7 @@ OGRErr OGRILI1Layer::CreateFeature( OGRFeature *poFeature ) {
     // Write out Geometry
     if( poFeature->GetGeometryRef() != NULL )
     {
-        if (EQUAL(poFeatureDefn->GetFieldDefn(poFeatureDefn->GetFieldCount()-1)->GetNameRef(), "ILI_Geometry"))
-        {
-            //Write original ILI geometry
-            VSIFPrintf( poDS->GetTransferFile(), "%s", poFeature->GetFieldAsString( poFeatureDefn->GetFieldCount()-1 ) );
-        }
-        else
-        {
-            //Convert to ILI geometry
-            GeometryAppend(poFeature->GetGeometryRef());
-        }
+        GeometryAppend(poFeature->GetGeometryRef());
     }
 
     return OGRERR_NONE;
@@ -377,7 +399,10 @@ OGRErr OGRILI1Layer::CreateFeature( OGRFeature *poFeature ) {
 /************************************************************************/
 
 int OGRILI1Layer::TestCapability( CPL_UNUSED const char * pszCap ) {
-    return FALSE;
+    if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
+    else
+        return FALSE;
 }
 
 /************************************************************************/
@@ -397,6 +422,13 @@ OGRErr OGRILI1Layer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxO
 
 void OGRILI1Layer::JoinGeomLayers()
 {
+    int bResetConfigOption = FALSE;
+    if (EQUAL(CPLGetConfigOption("OGR_ARC_STEPSIZE", ""), ""))
+    {
+        bResetConfigOption = TRUE;
+        CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", "0.96");
+    }
+
     for (GeomFieldInfos::const_iterator it = oGeomFieldInfos.begin(); it != oGeomFieldInfos.end(); ++it)
     {
         OGRFeatureDefn* geomFeatureDefn = it->second.geomTable;
@@ -418,25 +450,46 @@ void OGRILI1Layer::JoinGeomLayers()
         }
     }
     bGeomsJoined = TRUE;
+
+    if( bResetConfigOption )
+        CPLSetThreadLocalConfigOption("OGR_ARC_STEPSIZE", NULL);
 }
 
 
-void OGRILI1Layer::JoinSurfaceLayer( OGRILI1Layer* poSurfacePolyLayer, int nSurfaceFieldIndex )
+void OGRILI1Layer::JoinSurfaceLayer( OGRILI1Layer* poSurfaceLineLayer, int nSurfaceFieldIndex )
 {
     CPLDebug( "OGR_ILI", "Joining surface layer %s with geometries", GetLayerDefn()->GetName());
-    poSurfacePolyLayer->ResetReading();
-    while (OGRFeature *polyfeature = poSurfacePolyLayer->GetNextFeatureRef()) {
-        int reftid = polyfeature->GetFieldAsInteger(1);
-        OGRFeature *feature = GetFeatureRef(reftid);
+    OGRwkbGeometryType geomType = GetLayerDefn()->GetGeomFieldDefn(nSurfaceFieldIndex)->GetType();
+    poSurfaceLineLayer->ResetReading();
+    while (OGRFeature *linefeature = poSurfaceLineLayer->GetNextFeatureRef()) {
+        //OBJE entries with same _RefTID are polygon rings of same feature
+        //TODO: non-numeric _RefTID/FID is not supported yet!
+        GIntBig reftid = linefeature->GetFieldAsInteger64(1); //_RefTID
+        OGRFeature *feature = GetFeatureRef((int)reftid);
         if (feature) {
-            feature->SetGeomField(nSurfaceFieldIndex, polyfeature->GetGeomFieldRef(0));
+            OGRCurvePolygon *poly;
+            if (feature->GetGeomFieldRef(nSurfaceFieldIndex)) {
+                CPLDebug( "OGR_ILI", "Adding ring to FID " CPL_FRMT_GIB, reftid );
+                poly = (OGRCurvePolygon *)feature->GetGeomFieldRef(nSurfaceFieldIndex);
+            } else {
+                poly = (geomType == wkbPolygon) ? new OGRPolygon() : new OGRCurvePolygon();
+                feature->SetGeomFieldDirectly(nSurfaceFieldIndex, poly);
+            }
+            OGRMultiCurve *lines = (OGRMultiCurve*)linefeature->GetGeomFieldRef(0);
+            for( int i = 0; i < lines->getNumGeometries(); i++ ) {
+                OGRCurve *line = (OGRCurve*)lines->getGeometryRef(i);
+                OGRCurve *ring = (geomType == wkbPolygon) ?
+                    OGRCurve::CastToLinearRing((OGRCurve*)line->clone()) :
+                    (OGRCurve*)line->clone();
+                poly->addRingDirectly(ring);
+            }
         } else {
-            CPLDebug( "OGR_ILI", "Couldn't join feature FID %d", reftid );
+            CPLError(CE_Warning, CPLE_AppDefined, "Couldn't join feature FID " CPL_FRMT_GIB, reftid );
         }
     }
 
     ResetReading();
-    poSurfacePolyLayer = 0;
+    poSurfaceLineLayer = 0;
 }
 
 OGRMultiPolygon* OGRILI1Layer::Polygonize( OGRGeometryCollection* poLines, bool fix_crossing_lines )
@@ -509,10 +562,11 @@ void OGRILI1Layer::PolygonizeAreaLayer( OGRILI1Layer* poAreaLineLayer, int nArea
     CPLDebug( "OGR_ILI", "Resulting polygons: %d", polys->getNumGeometries());
     if (polys->getNumGeometries() != GetFeatureCount())
     {
-        CPLDebug( "OGR_ILI", "Feature count of layer %s: %d", GetLayerDefn()->GetName(), GetFeatureCount());
+        CPLDebug( "OGR_ILI", "Feature count of layer %s: " CPL_FRMT_GIB, GetLayerDefn()->GetName(), GetFeatureCount());
         CPLDebug( "OGR_ILI", "Polygonizing again with crossing line fix");
         delete polys;
         polys = Polygonize( gc, true ); //try again with crossing line fix
+        CPLDebug( "OGR_ILI", "Resulting polygons: %d", polys->getNumGeometries());
     }
     delete gc;
 
diff --git a/ogr/ogrsf_frmts/ili/ogrili2datasource.cpp b/ogr/ogrsf_frmts/ili/ogrili2datasource.cpp
index 1b135af..8d89139 100644
--- a/ogr/ogrsf_frmts/ili/ogrili2datasource.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili2datasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili2datasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrili2datasource.cpp 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 2 Translator
  * Purpose:  Implements OGRILI2DataSource class.
@@ -37,7 +37,7 @@
 using namespace std;
 
 
-CPL_CVSID("$Id: ogrili2datasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrili2datasource.cpp 29140 2015-05-03 20:09:32Z pka $");
 
 /************************************************************************/
 /*                         OGRILI2DataSource()                         */
@@ -86,16 +86,32 @@ OGRILI2DataSource::~OGRILI2DataSource()
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRILI2DataSource::Open( const char * pszNewName, int bTestOpen )
+int OGRILI2DataSource::Open( const char * pszNewName, char** papszOpenOptions, int bTestOpen )
 
 {
     FILE        *fp;
     char        szHeader[1000];
+    CPLString   osBasename;
+    CPLString   osModelFilename;
 
-    char **filenames = CSLTokenizeString2( pszNewName, ",", 0 );
-    const char *pszModelFilename = (CSLCount(filenames)>1) ? filenames[1] : NULL;
+    if( CSLFetchNameValue(papszOpenOptions, "MODEL") != NULL )
+    {
+        osBasename = pszNewName;
+        osModelFilename = CSLFetchNameValue(papszOpenOptions, "MODEL");
+    }
+    else
+    {
+        char **filenames = CSLTokenizeString2( pszNewName, ",", 0 );
 
-    pszName = CPLStrdup( filenames[0] );
+        osBasename = filenames[0];
+
+        if( CSLCount(filenames) > 1 )
+            osModelFilename = filenames[1];
+
+        CSLDestroy( filenames );
+    }
+
+    pszName = CPLStrdup( osBasename );
 
 /* -------------------------------------------------------------------- */
 /*      Open the source file.                                           */
@@ -108,7 +124,6 @@ int OGRILI2DataSource::Open( const char * pszNewName, int bTestOpen )
                       "Failed to open ILI2 file `%s'.",
                       pszNewName );
 
-        CSLDestroy( filenames );
         return FALSE;
     }
 
@@ -128,7 +143,6 @@ int OGRILI2DataSource::Open( const char * pszNewName, int bTestOpen )
             || strstr(szHeader,"interlis.ch/INTERLIS2") == NULL )
         { // "www.interlis.ch/INTERLIS2.3"
             VSIFClose( fp );
-            CSLDestroy( filenames );
             return FALSE;
         }
     }
@@ -147,17 +161,11 @@ int OGRILI2DataSource::Open( const char * pszNewName, int bTestOpen )
                   "be instantiated, likely because Xerces support wasn't\n"
                   "configured in.", 
                   pszNewName );
-        CSLDestroy( filenames );
         return FALSE;
     }
 
-    if (pszModelFilename)
-        poReader->ReadModel( poImdReader, pszModelFilename );
-
-    if( getenv( "ARC_DEGREES" ) != NULL ) {
-      //No better way to pass arguments to the reader (it could even be an -lco arg)
-      poReader->SetArcDegrees( atof( getenv("ARC_DEGREES") ) );
-    }
+    if (osModelFilename.size())
+        poReader->ReadModel( poImdReader, osModelFilename );
 
     poReader->SetSourceFile( pszName );
 
@@ -169,8 +177,6 @@ int OGRILI2DataSource::Open( const char * pszNewName, int bTestOpen )
         (*layerIt)->ResetReading();
     }
 
-    CSLDestroy( filenames );
-
     return TRUE;
 }
 
@@ -255,14 +261,14 @@ int OGRILI2DataSource::Create( const char *pszFilename,
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRILI2DataSource::CreateLayer( const char * pszLayerName,
-                                CPL_UNUSED OGRSpatialReference *poSRS,
-                                OGRwkbGeometryType eType,
-                                CPL_UNUSED char ** papszOptions )
+OGRILI2DataSource::ICreateLayer( const char * pszLayerName,
+                                 CPL_UNUSED OGRSpatialReference *poSRS,
+                                 OGRwkbGeometryType eType,
+                                 CPL_UNUSED char ** papszOptions )
 {
     if (fpOutput == NULL)
         return NULL;
@@ -294,6 +300,8 @@ int OGRILI2DataSource::TestCapability( const char * pszCap )
 {
     if( EQUAL(pszCap,ODsCCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
diff --git a/ogr/ogrsf_frmts/ili/ogrili2driver.cpp b/ogr/ogrsf_frmts/ili/ogrili2driver.cpp
index b353086..28f65d7 100644
--- a/ogr/ogrsf_frmts/ili/ogrili2driver.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili2driver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili2driver.cpp 13906 2008-03-01 13:08:28Z rouault $
+ * $Id: ogrili2driver.cpp 29109 2015-05-02 11:45:44Z rouault $
  *
  * Project:  Interlis 2 Translator
  * Purpose:  Implements OGRILI2Layer class.
@@ -30,39 +30,35 @@
 #include "ogr_ili2.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrili2driver.cpp 13906 2008-03-01 13:08:28Z rouault $");
-
-/************************************************************************/
-/*                          ~OGRILI2Driver()                           */
-/************************************************************************/
-
-OGRILI2Driver::~OGRILI2Driver() {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRILI2Driver::GetName() {
-    return "Interlis 2";
-}
+CPL_CVSID("$Id: ogrili2driver.cpp 29109 2015-05-02 11:45:44Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRILI2Driver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRILI2DriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRILI2DataSource    *poDS;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update ||
+        (!poOpenInfo->bStatOK && strchr(poOpenInfo->pszFilename, ',') == NULL) )
+        return NULL;
+
+    if( poOpenInfo->fpL != NULL )
+    {
+        if( poOpenInfo->pabyHeader[0] != '<' 
+            || strstr((const char*)poOpenInfo->pabyHeader,"interlis.ch/INTERLIS2") == NULL )
+        {
+            return NULL;
+        }
+    }
+    else if( poOpenInfo->bIsDirectory )
         return NULL;
 
     poDS = new OGRILI2DataSource();
 
-    if( !poDS->Open( pszFilename, TRUE )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions, TRUE )
         || poDS->GetLayerCount() == 0 )
     {
         delete poDS;
@@ -73,12 +69,15 @@ OGRDataSource *OGRILI2Driver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRILI2Driver::CreateDataSource( const char * pszName,
-                                               char **papszOptions )
-
+static GDALDataset *OGRILI2DriverCreate( const char * pszName,
+                                         CPL_UNUSED int nBands,
+                                         CPL_UNUSED int nXSize,
+                                         CPL_UNUSED int nYSize,
+                                         CPL_UNUSED GDALDataType eDT,
+                                         char **papszOptions )
 {
     OGRILI2DataSource    *poDS = new OGRILI2DataSource();
 
@@ -92,24 +91,32 @@ OGRDataSource *OGRILI2Driver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                           RegisterOGRILI2()                           */
 /************************************************************************/
 
-int OGRILI2Driver::TestCapability( const char * pszCap ) {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return FALSE;
-    else
-        return FALSE;
-}
+void RegisterOGRILI2() {
+    GDALDriver  *poDriver;
 
-/************************************************************************/
-/*                           RegisterOGRILI2()                           */
-/************************************************************************/
+    if( GDALGetDriverByName( "Interlis 2" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
-void RegisterOGRILI2()
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRILI2Driver );
-}
+        poDriver->SetDescription( "Interlis 2" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Interlis 2" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_ili.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "xtf xml ili" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='MODEL' type='string' description='Filename of the model in IlisMeta format (.imd)'/>"
+"</OpenOptionList>" );
 
+        poDriver->pfnOpen = OGRILI2DriverOpen;
+        poDriver->pfnCreate = OGRILI2DriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/ili/ogrili2layer.cpp b/ogr/ogrsf_frmts/ili/ogrili2layer.cpp
index ad17b9f..4e0bb61 100644
--- a/ogr/ogrsf_frmts/ili/ogrili2layer.cpp
+++ b/ogr/ogrsf_frmts/ili/ogrili2layer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrili2layer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrili2layer.cpp 29140 2015-05-03 20:09:32Z pka $
  *
  * Project:  Interlis 2 Translator
  * Purpose:  Implements OGRILI2Layer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrili2layer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrili2layer.cpp 29140 2015-05-03 20:09:32Z pka $");
 
 /************************************************************************/
 /*                           OGRILI2Layer()                              */
@@ -43,6 +43,7 @@ OGRILI2Layer::OGRILI2Layer( OGRFeatureDefn* poFeatureDefnIn,
                             OGRILI2DataSource *poDSIn )
 {
     poFeatureDefn = poFeatureDefnIn;
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     oGeomFieldInfos = oGeomFieldInfosIn;
 
@@ -70,10 +71,10 @@ OGRILI2Layer::~OGRILI2Layer()
 
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRILI2Layer::SetFeature (OGRFeature *poFeature)
+OGRErr OGRILI2Layer::ISetFeature (OGRFeature *poFeature)
 {
     listFeature.push_back(poFeature);
     return OGRERR_NONE;
@@ -112,7 +113,7 @@ OGRFeature *OGRILI2Layer::GetNextFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRILI2Layer::GetFeatureCount( int bForce )
+GIntBig OGRILI2Layer::GetFeatureCount( int bForce )
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
     {
@@ -130,17 +131,17 @@ static char* d2str(double val)
     if( val == (int) val )
         sprintf( strbuf, "%d", (int) val );
     else if( fabs(val) < 370 )
-        sprintf( strbuf, "%.16g", val );
+        CPLsprintf( strbuf, "%.16g", val );
     else if( fabs(val) > 100000000.0  )
-        sprintf( strbuf, "%.16g", val );
+        CPLsprintf( strbuf, "%.16g", val );
     else
-        sprintf( strbuf, "%.3f", val );
+        CPLsprintf( strbuf, "%.3f", val );
     return strbuf;
 }
 
 static void AppendCoordinateList( OGRLineString *poLine, VSILFILE* fp )
 {
-    int         b3D = (poLine->getGeometryType() & wkb25DBit);
+    int         b3D = wkbHasZ(poLine->getGeometryType());
 
     for( int iPoint = 0; iPoint < poLine->getNumPoints(); iPoint++ )
     {
@@ -267,10 +268,10 @@ static int OGR2ILIGeometryAppend( OGRGeometry *poGeometry, VSILFILE* fp, const c
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRILI2Layer::CreateFeature( OGRFeature *poFeature ) {
+OGRErr OGRILI2Layer::ICreateFeature( OGRFeature *poFeature ) {
     static char         szTempBuffer[80];
     const char* tid;
     int iField = 0;
@@ -281,7 +282,7 @@ OGRErr OGRILI2Layer::CreateFeature( OGRFeature *poFeature ) {
     }
     else
     {
-        sprintf( szTempBuffer, "%ld", poFeature->GetFID() );
+        sprintf( szTempBuffer, CPL_FRMT_GIB, poFeature->GetFID() );
         tid = szTempBuffer;
     }
 
@@ -326,7 +327,10 @@ OGRErr OGRILI2Layer::CreateFeature( OGRFeature *poFeature ) {
 /************************************************************************/
 
 int OGRILI2Layer::TestCapability( CPL_UNUSED const char * pszCap ) {
-    return FALSE;
+    if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
+    else
+        return FALSE;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/ingres/GNUmakefile b/ogr/ogrsf_frmts/ingres/GNUmakefile
index ce522f9..ab5d8c9 100644
--- a/ogr/ogrsf_frmts/ingres/GNUmakefile
+++ b/ogr/ogrsf_frmts/ingres/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	ogringresdriver.o ogringresstatement.o ogringresdatasource.o \
 
 #	ogringresresultlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(INGRES_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(INGRES_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/ingres/ogr_ingres.h b/ogr/ogrsf_frmts/ingres/ogr_ingres.h
index 3d749d8..6b2805e 100644
--- a/ogr/ogrsf_frmts/ingres/ogr_ingres.h
+++ b/ogr/ogrsf_frmts/ingres/ogr_ingres.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_ingres.h 19509 2010-04-23 16:49:33Z warmerdam $
+ * $Id: ogr_ingres.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Declarations for Ingres OGR Driver Classes.
@@ -117,7 +117,7 @@ class OGRIngresLayer : public OGRLayer
 
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -164,17 +164,17 @@ class OGRIngresTableLayer : public OGRIngresLayer
 
     OGRErr              Initialize(const char* pszTableName);
     
-//    virtual OGRFeature *GetFeature( long nFeatureId );
+//    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     virtual void        ResetReading();
-//    virtual int         GetFeatureCount( int );
+//    virtual GIntBig     GetFeatureCount( int );
 
     void                SetSpatialFilter( OGRGeometry * );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -213,7 +213,7 @@ class OGRIngresResultLayer : public OGRIngresLayer
 
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 };
 
 /************************************************************************/
@@ -264,7 +264,7 @@ class OGRIngresDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
diff --git a/ogr/ogrsf_frmts/ingres/ogringresdatasource.cpp b/ogr/ogrsf_frmts/ingres/ogringresdatasource.cpp
index bafcf3c..2947908 100644
--- a/ogr/ogrsf_frmts/ingres/ogringresdatasource.cpp
+++ b/ogr/ogrsf_frmts/ingres/ogringresdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogringresdatasource.cpp 26506 2013-09-30 18:17:55Z rouault $
+ * $Id: ogringresdatasource.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIngresDataSource class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogringresdatasource.cpp 26506 2013-09-30 18:17:55Z rouault $");
+CPL_CVSID("$Id: ogringresdatasource.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                            SetConnParam()                            */
@@ -853,11 +853,11 @@ int OGRIngresDataSource::DeleteLayer( int iLayer)
 
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRIngresDataSource::CreateLayer( const char * pszLayerNameIn,
+OGRIngresDataSource::ICreateLayer( const char * pszLayerNameIn,
                               OGRSpatialReference *poSRS,
                               OGRwkbGeometryType eType,
                               char ** papszOptions )
diff --git a/ogr/ogrsf_frmts/ingres/ogringreslayer.cpp b/ogr/ogrsf_frmts/ingres/ogringreslayer.cpp
index 0c6e40c..811256a 100644
--- a/ogr/ogrsf_frmts/ingres/ogringreslayer.cpp
+++ b/ogr/ogrsf_frmts/ingres/ogringreslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogringreslayer.cpp 19509 2010-04-23 16:49:33Z warmerdam $
+ * $Id: ogringreslayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIngresLayer class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogringreslayer.cpp 19509 2010-04-23 16:49:33Z warmerdam $");
+CPL_CVSID("$Id: ogringreslayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGRIngresLayer()                            */
@@ -139,8 +139,8 @@ static int ParseXY( const char **ppszNext, double *padfXY )
         }
     }
 
-    padfXY[0] = atof(pszNext);
-    padfXY[1] = atof(pszNext + iStartY);
+    padfXY[0] = CPLAtof(pszNext);
+    padfXY[1] = CPLAtof(pszNext + iStartY);
 
     int iEnd;
 
@@ -536,7 +536,7 @@ OGRFeature *OGRIngresLayer::GetNextRawFeature()
 /*      Note that we actually override this in OGRIngresTableLayer.      */
 /************************************************************************/
 
-OGRFeature *OGRIngresLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRIngresLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRLayer::GetFeature( nFeatureId );
diff --git a/ogr/ogrsf_frmts/ingres/ogringresresultlayer.cpp b/ogr/ogrsf_frmts/ingres/ogringresresultlayer.cpp
index cf3db79..bd0b022 100644
--- a/ogr/ogrsf_frmts/ingres/ogringresresultlayer.cpp
+++ b/ogr/ogrsf_frmts/ingres/ogringresresultlayer.cpp
@@ -162,7 +162,7 @@ void OGRIngresResultLayer::ResetReading()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRIngresResultLayer::GetFeatureCount( int bForce )
+GIntBig OGRIngresResultLayer::GetFeatureCount( int bForce )
 
 {
     // I wonder if we could do anything smart here...
diff --git a/ogr/ogrsf_frmts/ingres/ogringrestablelayer.cpp b/ogr/ogrsf_frmts/ingres/ogringrestablelayer.cpp
index 8af14e8..4166109 100644
--- a/ogr/ogrsf_frmts/ingres/ogringrestablelayer.cpp
+++ b/ogr/ogrsf_frmts/ingres/ogringrestablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogringrestablelayer.cpp 26688 2013-12-02 19:07:41Z rouault $
+ * $Id: ogringrestablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRIngresTableLayer class.
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include "ogr_ingres.h"
 
-CPL_CVSID("$Id: ogringrestablelayer.cpp 26688 2013-12-02 19:07:41Z rouault $");
+CPL_CVSID("$Id: ogringrestablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                         OGRIngresTableLayer()                         */
@@ -119,6 +119,7 @@ OGRFeatureDefn *OGRIngresTableLayer::ReadTableDefinition( const char *pszTable )
 /*      Parse the returned table information.                           */
 /* -------------------------------------------------------------------- */
     OGRFeatureDefn *poDefn = new OGRFeatureDefn( pszTable );
+    SetDescription( poDefn->GetName() );
     char           **papszRow;
 
     poDefn->Reference();
@@ -461,14 +462,14 @@ int OGRIngresTableLayer::TestCapability( const char * pszCap )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /*                                                                      */
 /*      SetFeature() is implemented by dropping the old copy of the     */
 /*      feature in question (if there is one) and then creating a       */
 /*      new one with the provided feature id.                           */
 /************************************************************************/
 
-OGRErr OGRIngresTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRIngresTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     OGRErr eErr;
@@ -491,7 +492,7 @@ OGRErr OGRIngresTableLayer::SetFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRIngresTableLayer::DeleteFeature( long nFID )
+OGRErr OGRIngresTableLayer::DeleteFeature( GIntBig nFID )
 
 {
     CPLString           osCommand;
@@ -809,10 +810,10 @@ OGRErr OGRIngresTableLayer::PrepareNewStyleGeometry(
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRIngresTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRIngresTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     CPLString           osCommand;
@@ -1131,7 +1132,7 @@ OGRErr OGRIngresTableLayer::CreateField( OGRFieldDefn *poFieldIn,
 /*                             GetFeature()                             */
 /************************************************************************/
 #ifdef notdef
-OGRFeature *OGRIngresTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRIngresTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -1214,7 +1215,7 @@ OGRFeature *OGRIngresTableLayer::GetFeature( long nFeatureId )
 /************************************************************************/
 
 #ifdef notdef
-int OGRIngresTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRIngresTableLayer::GetFeatureCount( int bForce )
 
 {
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogrsf_frmts/jml/GNUmakefile b/ogr/ogrsf_frmts/jml/GNUmakefile
new file mode 100644
index 0000000..3af855f
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/GNUmakefile
@@ -0,0 +1,19 @@
+
+
+include ../../../GDALmake.opt
+
+OBJ	=	ogrjmldataset.o ogrjmllayer.o ogrjmlwriterlayer.o
+
+ifeq ($(HAVE_EXPAT),yes)
+CPPFLAGS +=   -DHAVE_EXPAT
+endif
+
+CPPFLAGS	:=	-I.. -I../..  $(EXPAT_INCLUDE) $(CPPFLAGS)
+
+default:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(O_OBJ):	ogr_jml.h
+
diff --git a/ogr/ogrsf_frmts/jml/drv_jml.html b/ogr/ogrsf_frmts/jml/drv_jml.html
new file mode 100644
index 0000000..0e80aa2
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/drv_jml.html
@@ -0,0 +1,79 @@
+<html>
+<head>
+<title>OGR JML driver</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>JML: OpenJUMP JML format</h1>
+
+(Driver available in GDAL 2.0 or later)<p>
+
+OGR has support for reading and writing .JML files used by the OpenJUMP software.
+Read support is only available if GDAL is built with <i>expat</i> library support<p>
+
+.jml is a variant of GML format. There is no formal definition of the format.
+It supports a single layer per file, mixed geometry types, and for each feature,
+a geometry and several attributes of type integer, double, string, date or object.
+That object data type, used for example to store 64 bit integers, but potentially
+arbitrary serialized Java objects, is converted as string when reading.
+Contrary to GML, the definition of fields is embedded in the .jml file, at its
+beginning.<p>
+
+.jml doesn't support spatial reference systems.<p>
+
+<h2>Encoding issues</h2>
+
+Expat library supports reading the following built-in encodings :
+<ul>
+<li>US-ASCII</li>
+<li>UTF-8</li>
+<li>UTF-16</li>
+<li>ISO-8859-1</li>
+<li>Windows-1252</li>
+</ul>
+
+The content returned by OGR will be encoded in UTF-8, after the conversion from the
+encoding mentionned in the file header is. But files produced by OpenJUMP are
+always UTF-8 encoded.<p>
+
+When writing a JML file, the driver expects UTF-8 content to be passed in.<p>
+
+<h2>Styling</h2>
+
+OpenJUMP uses an optional string attribute called "R_G_B" to determine the color
+of objects. The field value is "RRGGBB" where RR, GG, BB are respectively the
+value of the red, green and blue components expressed as hexadecimal values from
+00 to FF. When reading a .jml file, OGR will translate the R_G_B attribute to
+the Feature Style encoding, unless a OGR_STYLE attribute is present. When
+writing a .jml file, OGR will extract from the Feature Style string the color of
+the PEN tool or the forecolor of the BRUSH tool to write the R_G_B attribute,
+unless the R_G_B attribute is defined in the provided feature. The addition of
+the R_G_B attribute can be disabled by setting the CREATE_R_G_B_FIELD layer
+creation option to NO.<p>
+
+<h2>Creation Issues</h2>
+
+The JML writer supports the following <i>layer</i> creation options:
+<ul>
+<li> <b>CREATE_R_G_B_FIELD</b>=YES/NO: whether the create a R_G_B field that will
+contain the color of the PEN tool or the forecolor of the BRUSH tool of the OGR
+Feature Style string. Default value : YES</li>
+<li> <b>CREATE_OGR_STYLE_FIELD</b>=YES/NO: whether the create a OGR_STYLE field that will
+contain the Feature Style string. Default value : NO</li>
+</ul>
+<p>
+
+<h2>See Also</h2>
+
+<ul>
+<li> <a href="ogr_feature_style.html">OGR - Feature Style Specification</a></li>
+</ul>
+
+<h2>Credits</h2>
+
+<p>The author wishes to thank Jukka Rahkonen for funding the development of this
+driver.</p>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/jml/makefile.vc b/ogr/ogrsf_frmts/jml/makefile.vc
new file mode 100644
index 0000000..b5662c7
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/makefile.vc
@@ -0,0 +1,18 @@
+
+OBJ	=	ogrjmldataset.obj ogrjmllayer.obj ogrjmlwriterlayer.obj
+
+GDAL_ROOT	=	..\..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+!IFDEF EXPAT_DIR
+EXTRAFLAGS =	-I.. -I..\.. $(EXPAT_INCLUDE) -DHAVE_EXPAT=1 
+!ELSE
+EXTRAFLAGS =	-I.. -I..\..
+!ENDIF
+
+default:	$(OBJ)
+
+clean:
+	-del *.obj *.pdb
+
diff --git a/ogr/ogrsf_frmts/jml/ogr_jml.h b/ogr/ogrsf_frmts/jml/ogr_jml.h
new file mode 100644
index 0000000..924b738
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/ogr_jml.h
@@ -0,0 +1,212 @@
+/******************************************************************************
+ * $Id: ogr_jml.h 27959 2014-11-14 18:29:21Z rouault $
+ *
+ * Project:  JML .jml Translator
+ * Purpose:  Definition of classes for OGR JML driver.
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGR_JML_H_INCLUDED
+#define _OGR_JML_H_INCLUDED
+
+#include "ogrsf_frmts.h"
+#include "ogr_p.h"
+
+#ifdef HAVE_EXPAT
+#include "ogr_expat.h"
+#endif
+
+#include <vector>
+
+class OGRJMLDataset;
+
+#ifdef HAVE_EXPAT
+
+/************************************************************************/
+/*                            OGRJMLColumn                              */
+/************************************************************************/
+
+class OGRJMLColumn
+{
+    public:
+        CPLString osName;
+        CPLString osType;
+        CPLString osElementName;
+        CPLString osAttributeName;
+        CPLString osAttributeValue;
+        int       bIsBody; /* if false: attribute */
+};
+
+/************************************************************************/
+/*                             OGRJMLLayer                              */
+/************************************************************************/
+
+class OGRJMLLayer : public OGRLayer
+{
+    OGRFeatureDefn     *poFeatureDefn;
+    OGRJMLDataset *poDS;
+
+    int                nNextFID;
+    VSILFILE*          fp;
+    int                bHasReadSchema;
+
+    XML_Parser         oParser;
+
+    int                currentDepth;
+    int                bStopParsing;
+    int                nWithoutEventCounter;
+    int                nDataHandlerCounter;
+    
+    int                bAccumulateElementValue;
+    char              *pszElementValue;
+    int                nElementValueLen;
+    int                nElementValueAlloc;
+
+    OGRFeature*        poFeature;
+    OGRFeature **      ppoFeatureTab;
+    int                nFeatureTabLength;
+    int                nFeatureTabIndex;
+
+    int                bSchemaFinished;
+    int                nJCSGMLInputTemplateDepth;
+    int                nCollectionElementDepth;
+    CPLString          osCollectionElement;
+    int                nFeatureElementDepth;
+    CPLString          osFeatureElement;
+    int                nGeometryElementDepth;
+    CPLString          osGeometryElement;
+    int                nColumnDepth;
+    int                nNameDepth;
+    int                nTypeDepth;
+    int                nAttributeElementDepth;
+    int                iAttr;
+    int                iRGBField;
+
+    OGRJMLColumn  oCurColumn;
+    std::vector<OGRJMLColumn> aoColumns;
+
+    void                AddStringToElementValue(const char *data, int nLen);
+    void                StopAccumulate();
+
+    void                LoadSchema();
+
+  public:
+                        OGRJMLLayer(const char *pszLayerName,
+                                         OGRJMLDataset* poDS,
+                                         VSILFILE* fp );
+                        ~OGRJMLLayer();
+
+    const char         *GetName() { return poFeatureDefn->GetName(); }
+
+    void                ResetReading();
+    OGRFeature *        GetNextFeature();
+
+    OGRFeatureDefn *    GetLayerDefn();
+    
+    int                 TestCapability( const char * );
+
+    void                startElementCbk(const char *pszName, const char **ppszAttr);
+    void                endElementCbk(const char *pszName);
+    void                dataHandlerCbk(const char *data, int nLen);
+
+    void                startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr);
+    void                endElementLoadSchemaCbk(const char *pszName);
+};
+
+#endif /* HAVE_EXPAT */
+
+/************************************************************************/
+/*                          OGRJMLWriterLayer                           */
+/************************************************************************/
+
+class OGRJMLWriterLayer : public OGRLayer
+{
+    OGRFeatureDefn     *poFeatureDefn;
+    OGRJMLDataset *poDS;
+    VSILFILE           *fp;
+    int                 bFeaturesWritten;
+    int                 bAddRGBField;
+    int                 bAddOGRStyleField;
+    int                 bClassicGML;
+    int                 nNextFID;
+
+    void                WriteColumnDeclaration( const char* pszName,
+                                                const char* pszType );
+
+  public:
+                        OGRJMLWriterLayer(const char* pszLayerName,
+                                               OGRJMLDataset* poDS,
+                                               VSILFILE* fp,
+                                               int bAddRGBField,
+                                               int bAddOGRStyleField,
+                                               int bClassicGML );
+                        ~OGRJMLWriterLayer();
+
+    void                ResetReading() {}
+    OGRFeature *        GetNextFeature() { return NULL; }
+
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
+    OGRErr              CreateField( OGRFieldDefn *poField, int bApproxOK );
+
+    OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
+
+    int                 TestCapability( const char * );
+};
+
+/************************************************************************/
+/*                            OGRJMLDataset                             */
+/************************************************************************/
+
+class OGRJMLDataset : public GDALDataset
+{
+    OGRLayer           *poLayer;
+
+    VSILFILE           *fp; /* Virtual file API */
+    int                 bWriteMode;
+
+  public:
+                        OGRJMLDataset();
+                        ~OGRJMLDataset();
+
+    int                 GetLayerCount() { return poLayer != NULL ? 1 : 0; }
+    OGRLayer*           GetLayer( int );
+    
+    OGRLayer *          ICreateLayer( const char * pszLayerName,
+                                    OGRSpatialReference *poSRS,
+                                    OGRwkbGeometryType eType,
+                                    char ** papszOptions );
+
+    int                 TestCapability( const char * );
+
+    static int          Identify( GDALOpenInfo* poOpenInfo );
+    static GDALDataset* Open( GDALOpenInfo* poOpenInfo );
+    static GDALDataset* Create( const char *pszFilename, 
+                                 int nBands,
+                                 int nXSize,
+                                 int nYSize,
+                                 GDALDataType eDT,
+                                 char **papszOptions );
+};
+
+#endif /* ndef _OGR_JML_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/jml/ogrjmldataset.cpp b/ogr/ogrsf_frmts/jml/ogrjmldataset.cpp
new file mode 100644
index 0000000..f7fb48f
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/ogrjmldataset.cpp
@@ -0,0 +1,249 @@
+/******************************************************************************
+ * $Id: ogrjmldataset.cpp 28375 2015-01-30 12:06:11Z rouault $
+ *
+ * Project:  JML Translator
+ * Purpose:  Implements OGRJMLDataset class
+ * Author:   Even Rouault, even dot rouault at spatialys dot com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_jml.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+
+extern "C" void RegisterOGRJML();
+
+// g++ -DHAVE_EXPAT -fPIC -shared -Wall -g -DDEBUG ogr/ogrsf_frmts/jml/*.cpp -o ogr_JML.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/jml -L. -lgdal
+
+CPL_CVSID("$Id: ogrjmldataset.cpp 28375 2015-01-30 12:06:11Z rouault $");
+
+/************************************************************************/
+/*                          OGRJMLDataset()                             */
+/************************************************************************/
+
+OGRJMLDataset::OGRJMLDataset()
+
+{
+    poLayer = NULL;
+
+    fp = NULL;
+
+    bWriteMode = FALSE;
+}
+
+/************************************************************************/
+/*                         ~OGRJMLDataset()                             */
+/************************************************************************/
+
+OGRJMLDataset::~OGRJMLDataset()
+
+{
+    delete poLayer;
+
+    if ( fp != NULL )
+        VSIFCloseL( fp);
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRJMLDataset::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,ODsCCreateLayer) )
+        return bWriteMode && poLayer == NULL;
+    else
+        return FALSE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *OGRJMLDataset::GetLayer( int iLayer )
+
+{
+    if( iLayer != 0 )
+        return NULL;
+    else
+        return poLayer;
+}
+
+/************************************************************************/
+/*                            Identify()                                */
+/************************************************************************/
+
+int OGRJMLDataset::Identify( GDALOpenInfo* poOpenInfo )
+{
+    return poOpenInfo->nHeaderBytes != 0 &&
+           strstr((const char*)poOpenInfo->pabyHeader, "<JCSDataFile") != NULL;
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset* OGRJMLDataset::Open( GDALOpenInfo* poOpenInfo )
+
+{
+    if( !Identify(poOpenInfo) || poOpenInfo->fpL == NULL ||
+        poOpenInfo->eAccess == GA_Update )
+        return NULL;
+
+#ifndef HAVE_EXPAT
+    CPLError(CE_Failure, CPLE_NotSupported,
+             "OGR/JML driver has not been built with read support. Expat library required");
+    return NULL;
+#else
+    OGRJMLDataset* poDS = new OGRJMLDataset();
+    poDS->SetDescription( poOpenInfo->pszFilename );
+
+    poDS->fp = poOpenInfo->fpL;
+    poOpenInfo->fpL = NULL;
+
+    poDS->poLayer = new OGRJMLLayer( CPLGetBasename(poOpenInfo->pszFilename), poDS, poDS->fp);
+
+    return poDS;
+#endif
+}
+
+/************************************************************************/
+/*                               Create()                               */
+/************************************************************************/
+
+GDALDataset* OGRJMLDataset::Create( const char *pszFilename, 
+                                CPL_UNUSED int nXSize,
+                                CPL_UNUSED int nYSize,
+                                CPL_UNUSED int nBands,
+                                CPL_UNUSED GDALDataType eDT,
+                                CPL_UNUSED char **papszOptions )
+{
+    if (strcmp(pszFilename, "/dev/stdout") == 0)
+        pszFilename = "/vsistdout/";
+
+/* -------------------------------------------------------------------- */
+/*     Do not override exiting file.                                    */
+/* -------------------------------------------------------------------- */
+    VSIStatBufL sStatBuf;
+
+    if( VSIStatL( pszFilename, &sStatBuf ) == 0 )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "You have to delete %s before being able to create it with the JML driver",
+                 pszFilename);
+        return NULL;
+    }
+
+    OGRJMLDataset* poDS = new OGRJMLDataset();
+
+/* -------------------------------------------------------------------- */
+/*      Create the output file.                                         */
+/* -------------------------------------------------------------------- */
+    poDS->bWriteMode = TRUE;
+    poDS->SetDescription( pszFilename );
+
+    poDS->fp = VSIFOpenL( pszFilename, "w" );
+    if( poDS->fp == NULL )
+    {
+        CPLError( CE_Failure, CPLE_OpenFailed, 
+                  "Failed to create JML file %s.", 
+                  pszFilename );
+        delete poDS;
+        return NULL;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                           ICreateLayer()                             */
+/************************************************************************/
+
+OGRLayer * OGRJMLDataset::ICreateLayer( const char * pszLayerName,
+                                             CPL_UNUSED OGRSpatialReference *poSRS,
+                                             CPL_UNUSED OGRwkbGeometryType eType,
+                                             char ** papszOptions )
+{
+    if (!bWriteMode || poLayer != NULL)
+        return NULL;
+
+    int bAddRGBField = CSLTestBoolean(
+        CSLFetchNameValueDef(papszOptions, "CREATE_R_G_B_FIELD", "YES"));
+    int bAddOGRStyleField = CSLTestBoolean(
+        CSLFetchNameValueDef(papszOptions, "CREATE_OGR_STYLE_FIELD", "NO"));
+    int bClassicGML = CSLTestBoolean(
+        CSLFetchNameValueDef(papszOptions, "CLASSIC_GML", "NO"));
+    poLayer = new OGRJMLWriterLayer( pszLayerName, this, fp,
+                                          bAddRGBField, bAddOGRStyleField,
+                                          bClassicGML);
+
+    return poLayer;
+}
+
+/************************************************************************/
+/*                         RegisterOGRJML()                             */
+/************************************************************************/
+
+extern "C"
+{
+
+void RegisterOGRJML()
+{
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "JML" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "JML" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "OpenJUMP JML" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jml" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_jml.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"   <Option name='CREATE_R_G_B_FIELD' type='boolean' description='Whether to create a R_G_B field' default='YES'/>"
+"   <Option name='CREATE_OGR_STYLE_FIELD' type='boolean' description='Whether to create a OGR_STYLE field' default='NO'/>"
+"</LayerCreationOptionList>" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList/>"
+);
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime" );
+
+        poDriver->pfnOpen = OGRJMLDataset::Open;
+        poDriver->pfnIdentify = OGRJMLDataset::Identify;
+        poDriver->pfnCreate = OGRJMLDataset::Create;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
+
+}
diff --git a/ogr/ogrsf_frmts/jml/ogrjmllayer.cpp b/ogr/ogrsf_frmts/jml/ogrjmllayer.cpp
new file mode 100644
index 0000000..a4bd5ad
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/ogrjmllayer.cpp
@@ -0,0 +1,785 @@
+/******************************************************************************
+ * $Id: ogrjmllayer.cpp 27906 2014-10-24 18:38:57Z rouault $
+ *
+ * Project:  JML Translator
+ * Purpose:  Implements OGRJMLLayer class.
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_jml.h"
+#include "cpl_conv.h"
+#include "ogr_p.h"
+
+CPL_CVSID("$Id: ogrjmllayer.cpp 27906 2014-10-24 18:38:57Z rouault $");
+
+#ifdef HAVE_EXPAT
+
+/************************************************************************/
+/*                              OGRJMLLayer()                           */
+/************************************************************************/
+
+OGRJMLLayer::OGRJMLLayer( const char* pszLayerName,
+                                    OGRJMLDataset* poDS,
+                                    VSILFILE* fp )
+
+{
+    nNextFID = 0;
+
+    this->poDS = poDS;
+    this->fp = fp;
+
+    poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
+    poFeatureDefn->Reference();
+
+    bAccumulateElementValue = FALSE;
+    pszElementValue = (char*)CPLCalloc(1024, 1);
+    nElementValueLen = 0;
+    nElementValueAlloc = 1024;
+
+    ppoFeatureTab = NULL;
+    nFeatureTabIndex = 0;
+    nFeatureTabLength = 0;
+
+    nWithoutEventCounter = 0;
+    nDataHandlerCounter = 0;
+    currentDepth = 0;
+    bStopParsing = FALSE;
+    bHasReadSchema = FALSE;
+    
+    bSchemaFinished = FALSE;
+    nJCSGMLInputTemplateDepth = 0;
+    nCollectionElementDepth = 0;
+    nFeatureElementDepth = 0;
+    nGeometryElementDepth = 0;
+    nColumnDepth = 0;
+    nNameDepth = 0;
+    nTypeDepth = 0;
+    nAttributeElementDepth = 0;
+    iAttr = -1;
+    iRGBField = -1;
+
+    poFeature = NULL;
+
+    oParser = NULL;
+}
+
+/************************************************************************/
+/*                             ~OGRJMLLayer()                           */
+/************************************************************************/
+
+OGRJMLLayer::~OGRJMLLayer()
+
+{
+    if (oParser)
+        XML_ParserFree(oParser);
+    poFeatureDefn->Release();
+
+    CPLFree(pszElementValue);
+
+    int i;
+    for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
+        delete ppoFeatureTab[i];
+    CPLFree(ppoFeatureTab);
+
+    if (poFeature)
+        delete poFeature;
+}
+
+
+/************************************************************************/
+/*                            GetLayerDefn()                            */
+/************************************************************************/
+
+OGRFeatureDefn * OGRJMLLayer::GetLayerDefn()
+{
+    if (!bHasReadSchema)
+        LoadSchema();
+
+    return poFeatureDefn;
+}
+
+static void XMLCALL startElementCbk(void *pUserData, const char *pszName,
+                                    const char **ppszAttr)
+{
+    ((OGRJMLLayer*)pUserData)->startElementCbk(pszName, ppszAttr);
+}
+
+static void XMLCALL endElementCbk(void *pUserData, const char *pszName)
+{
+    ((OGRJMLLayer*)pUserData)->endElementCbk(pszName);
+}
+
+static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen)
+{
+    ((OGRJMLLayer*)pUserData)->dataHandlerCbk(data, nLen);
+}
+
+/************************************************************************/
+/*                            ResetReading()                            */
+/************************************************************************/
+
+void OGRJMLLayer::ResetReading()
+
+{
+    nNextFID = 0;
+
+    VSIFSeekL( fp, 0, SEEK_SET );
+    if (oParser)
+        XML_ParserFree(oParser);
+
+    oParser = OGRCreateExpatXMLParser();
+    XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk);
+    XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
+    XML_SetUserData(oParser, this);
+
+    int i;
+    for(i=nFeatureTabIndex;i<nFeatureTabLength;i++)
+        delete ppoFeatureTab[i];
+    nFeatureTabIndex = 0;
+    nFeatureTabLength = 0;
+    delete poFeature;
+    poFeature = NULL;
+
+    currentDepth = 0;
+
+    nCollectionElementDepth = 0;
+    nFeatureElementDepth = 0;
+    nGeometryElementDepth = 0;
+    nAttributeElementDepth = 0;
+    iAttr = -1;
+
+    bAccumulateElementValue = FALSE;
+    nElementValueLen = 0;
+    pszElementValue[0] = '\0';
+}
+
+/************************************************************************/
+/*                        startElementCbk()                            */
+/************************************************************************/
+
+void OGRJMLLayer::startElementCbk(const char *pszName, const char **ppszAttr)
+{
+    if (bStopParsing) return;
+
+    nWithoutEventCounter = 0;
+    
+    if( nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
+        nGeometryElementDepth == 0 && osGeometryElement.compare(pszName) == 0 )
+    {
+        nGeometryElementDepth = currentDepth;
+        bAccumulateElementValue = TRUE;
+    }
+    else if( nFeatureElementDepth > 0 && nAttributeElementDepth == 0 &&
+             nGeometryElementDepth == 0 )
+    {
+        /* We assume that attributes are present in the order they are */
+        /* declared, so as a first guess, we can try the aoColumns[iAttr + 1] */
+        int i = (iAttr+1 < poFeatureDefn->GetFieldCount()) ? -1 : 0;
+        for(; i<(int)aoColumns.size();i++)
+        {
+            const OGRJMLColumn& oColumn =
+                (i < 0) ? aoColumns[iAttr + 1] : aoColumns[i];
+            if(oColumn.osElementName != pszName )
+                continue;
+
+            if( oColumn.bIsBody )
+            {
+                if( oColumn.osAttributeName.size() &&
+                    ppszAttr != NULL &&
+                    oColumn.osAttributeName.compare(ppszAttr[0]) == 0 &&
+                    oColumn.osAttributeValue.compare(ppszAttr[1]) == 0 )
+                {
+                    /* <osElementName osAttributeName="osAttributeValue">value</osElementName> */
+
+                    bAccumulateElementValue = TRUE;
+                    nAttributeElementDepth = currentDepth;
+                    iAttr = (i < 0) ? iAttr + 1 : i;
+                    break;
+                }
+                else if( oColumn.osAttributeName.size() == 0 )
+                {
+                    /* <osElementName>value</osElementName> */
+
+                    bAccumulateElementValue = TRUE;
+                    nAttributeElementDepth = currentDepth;
+                    iAttr = (i < 0) ? iAttr + 1 : i;
+                    break;
+                }
+            }
+            else if( oColumn.osAttributeName.size() &&
+                      ppszAttr != NULL &&
+                      oColumn.osAttributeName.compare(ppszAttr[0]) == 0 )
+            {
+                /* <osElementName osAttributeName="value"></osElementName> */
+
+                AddStringToElementValue(ppszAttr[1], strlen(ppszAttr[1]));
+
+                nAttributeElementDepth = currentDepth;
+                iAttr = (i < 0) ? iAttr + 1 : i;
+                break;
+            }
+        }
+    }
+    else if( nGeometryElementDepth > 0 )
+    {
+        AddStringToElementValue("<", 1);
+        AddStringToElementValue(pszName, (int)strlen(pszName));
+
+        const char** papszIter = ppszAttr;
+        while( papszIter && *papszIter != NULL )
+        {
+            AddStringToElementValue(" ", 1);
+            AddStringToElementValue(papszIter[0], strlen(papszIter[0]));
+            AddStringToElementValue("=\"", 2);
+            AddStringToElementValue(papszIter[1], strlen(papszIter[1]));
+            AddStringToElementValue("\"", 1);
+            papszIter += 2;
+        }
+
+        AddStringToElementValue(">", 1);
+    }
+    else if( nCollectionElementDepth > 0 &&
+             nFeatureElementDepth == 0 && osFeatureElement.compare(pszName) == 0 )
+    {
+        nFeatureElementDepth = currentDepth;
+        poFeature = new OGRFeature(poFeatureDefn);
+    }
+    else if( nCollectionElementDepth == 0 && osCollectionElement.compare(pszName) == 0 )
+    {
+        nCollectionElementDepth = currentDepth;
+    }
+
+    currentDepth++;
+}
+
+/************************************************************************/
+/*                        StopAccumulate()                              */
+/************************************************************************/
+
+void OGRJMLLayer::StopAccumulate()
+{
+    bAccumulateElementValue = FALSE;
+    nElementValueLen = 0;
+    pszElementValue[0] = '\0';
+}
+
+/************************************************************************/
+/*                           endElementCbk()                            */
+/************************************************************************/
+
+void OGRJMLLayer::endElementCbk(const char *pszName)
+{
+    if (bStopParsing) return;
+
+    nWithoutEventCounter = 0;
+    
+    currentDepth--;
+    
+    if( nAttributeElementDepth == currentDepth )
+    {
+        if( nElementValueLen )
+            poFeature->SetField(iAttr, pszElementValue);
+        nAttributeElementDepth = 0;
+        StopAccumulate();
+    }
+    else if( nGeometryElementDepth > 0 && currentDepth > nGeometryElementDepth )
+    {
+        AddStringToElementValue("</", 2);
+        AddStringToElementValue(pszName, (int)strlen(pszName));
+        AddStringToElementValue(">", 1);
+    }
+    else if( nGeometryElementDepth == currentDepth )
+    {
+        if( nElementValueLen )
+        {
+            OGRGeometry* poGeom = (OGRGeometry* )OGR_G_CreateFromGML(pszElementValue);
+            if( poGeom != NULL &&
+                poGeom->getGeometryType() == wkbGeometryCollection &&
+                poGeom->IsEmpty() )
+            {
+                delete poGeom;
+            }
+            else
+                poFeature->SetGeometryDirectly(poGeom);
+        }
+
+        nGeometryElementDepth = 0;
+        StopAccumulate();
+    }
+    else if( nFeatureElementDepth == currentDepth )
+    {
+        /* Builds a style string from R_G_B if we don't already have a */
+        /* style string */
+        OGRGeometry* poGeom = poFeature->GetGeometryRef();
+        int R, G, B;
+        if( iRGBField >= 0 && poFeature->IsFieldSet(iRGBField) &&
+            poFeature->GetStyleString() == NULL && poGeom != NULL &&
+            sscanf(poFeature->GetFieldAsString(iRGBField),
+                       "%02X%02X%02X", &R, &G, &B) == 3 )
+        {
+            OGRwkbGeometryType eGeomType = wkbFlatten(poGeom->getGeometryType());
+            if( eGeomType == wkbPoint || eGeomType == wkbMultiPoint ||
+                eGeomType == wkbLineString || eGeomType == wkbMultiLineString )
+            {
+                poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X)", R, G, B));
+            }
+            else if( eGeomType == wkbPolygon || eGeomType == wkbMultiPolygon )
+            {
+                poFeature->SetStyleString(CPLSPrintf("BRUSH(fc:#%02X%02X%02X)", R, G, B));
+            }
+        }
+
+        poFeature->SetFID(nNextFID++);
+
+        if( (m_poFilterGeom == NULL
+                || FilterGeometry( poGeom ) )
+            && (m_poAttrQuery == NULL
+                || m_poAttrQuery->Evaluate( poFeature )) )
+        {
+            ppoFeatureTab = (OGRFeature**)
+                    CPLRealloc(ppoFeatureTab,
+                                sizeof(OGRFeature*) * (nFeatureTabLength + 1));
+            ppoFeatureTab[nFeatureTabLength] = poFeature;
+            nFeatureTabLength++;
+        }
+        else
+        {
+            delete poFeature;
+        }
+        poFeature = NULL;
+        iAttr = -1;
+
+        nFeatureElementDepth = 0;
+    }
+    else if( nCollectionElementDepth == currentDepth )
+    {
+        nCollectionElementDepth = 0;
+    }
+}
+
+/************************************************************************/
+/*                        AddStringToElementValue()                     */
+/************************************************************************/
+
+void OGRJMLLayer::AddStringToElementValue(const char *data, int nLen)
+{
+    if( nElementValueLen + nLen + 1 > nElementValueAlloc )
+    {
+        char* pszNewElementValue = (char*) VSIRealloc(pszElementValue,
+                                        nElementValueLen + nLen + 1 + 1000);
+        if (pszNewElementValue == NULL)
+        {
+            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
+            XML_StopParser(oParser, XML_FALSE);
+            bStopParsing = TRUE;
+            return;
+        }
+        nElementValueAlloc =  nElementValueLen + nLen + 1 + 1000;
+        pszElementValue = pszNewElementValue;
+    }
+    memcpy(pszElementValue + nElementValueLen, data, nLen);
+    nElementValueLen += nLen;
+    pszElementValue[nElementValueLen] = '\0';
+    if (nElementValueLen > 10000000)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                    "Too much data inside one element. File probably corrupted");
+        XML_StopParser(oParser, XML_FALSE);
+        bStopParsing = TRUE;
+    }
+}
+
+/************************************************************************/
+/*                          dataHandlerCbk()                            */
+/************************************************************************/
+
+void OGRJMLLayer::dataHandlerCbk(const char *data, int nLen)
+{
+    if (bStopParsing) return;
+
+    nDataHandlerCounter ++;
+    if (nDataHandlerCounter >= BUFSIZ)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "File probably corrupted (million laugh pattern)");
+        XML_StopParser(oParser, XML_FALSE);
+        bStopParsing = TRUE;
+        return;
+    }
+
+    nWithoutEventCounter = 0;
+    
+    if (bAccumulateElementValue)
+    {
+        AddStringToElementValue(data, nLen);
+    }
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature *OGRJMLLayer::GetNextFeature()
+{
+    if (!bHasReadSchema)
+        LoadSchema();
+
+    if (bStopParsing)
+        return NULL;
+
+    if (nFeatureTabIndex < nFeatureTabLength)
+    {
+        return ppoFeatureTab[nFeatureTabIndex++];
+    }
+    
+    if (VSIFEofL(fp))
+        return NULL;
+    
+    char aBuf[BUFSIZ];
+    
+    nFeatureTabLength = 0;
+    nFeatureTabIndex = 0;
+    
+    nWithoutEventCounter = 0;
+
+    int nDone;
+    do
+    {
+        nDataHandlerCounter = 0;
+        unsigned int nLen =
+                (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
+        nDone = VSIFEofL(fp);
+        if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "XML parsing of JML file failed : %s "
+                     "at line %d, column %d",
+                     XML_ErrorString(XML_GetErrorCode(oParser)),
+                     (int)XML_GetCurrentLineNumber(oParser),
+                     (int)XML_GetCurrentColumnNumber(oParser));
+            bStopParsing = TRUE;
+        }
+        nWithoutEventCounter ++;
+    } while (!nDone && !bStopParsing && nFeatureTabLength == 0 &&
+             nWithoutEventCounter < 10);
+
+    if (nWithoutEventCounter == 10)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Too much data inside one element. File probably corrupted");
+        bStopParsing = TRUE;
+    }
+
+    return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : NULL;
+}
+
+static void XMLCALL startElementLoadSchemaCbk(void *pUserData, const char *pszName,
+                                              const char **ppszAttr)
+{
+    ((OGRJMLLayer*)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr);
+}
+
+static void XMLCALL endElementLoadSchemaCbk(void *pUserData, const char *pszName)
+{
+    ((OGRJMLLayer*)pUserData)->endElementLoadSchemaCbk(pszName);
+}
+
+/************************************************************************/
+/*                           LoadSchema()                              */
+/************************************************************************/
+
+/** This function parses the beginning of the file to detect the fields */
+void OGRJMLLayer::LoadSchema()
+{
+    if (bHasReadSchema)
+        return;
+
+    bHasReadSchema = TRUE;
+
+    oParser = OGRCreateExpatXMLParser();
+    XML_SetElementHandler(oParser, ::startElementLoadSchemaCbk,
+                          ::endElementLoadSchemaCbk);
+    XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk);
+    XML_SetUserData(oParser, this);
+
+    VSIFSeekL( fp, 0, SEEK_SET );
+
+    char aBuf[BUFSIZ];
+    int nDone;
+    do
+    {
+        nDataHandlerCounter = 0;
+        unsigned int nLen = (unsigned int)VSIFReadL( aBuf, 1, sizeof(aBuf), fp );
+        nDone = VSIFEofL(fp);
+        if (XML_Parse(oParser, aBuf, nLen, nDone) == XML_STATUS_ERROR)
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "XML parsing of JML file failed : %s at line %d, column %d",
+                     XML_ErrorString(XML_GetErrorCode(oParser)),
+                     (int)XML_GetCurrentLineNumber(oParser),
+                     (int)XML_GetCurrentColumnNumber(oParser));
+            bStopParsing = TRUE;
+        }
+        nWithoutEventCounter ++;
+    } while (!nDone && !bStopParsing && !bSchemaFinished && nWithoutEventCounter < 10);
+
+    XML_ParserFree(oParser);
+    oParser = NULL;
+
+    if (nWithoutEventCounter == 10)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Too much data inside one element. File probably corrupted");
+        bStopParsing = TRUE;
+    }
+    
+    if( osCollectionElement.size() == 0 || osFeatureElement.size() == 0 ||
+        osGeometryElement.size() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Missing CollectionElement, FeatureElement or GeometryElement");
+        bStopParsing = TRUE;
+    }
+
+    ResetReading();
+}
+
+
+/************************************************************************/
+/*                  startElementLoadSchemaCbk()                         */
+/************************************************************************/
+
+void OGRJMLLayer::startElementLoadSchemaCbk(const char *pszName,
+                                                 const char **ppszAttr)
+{
+    if (bStopParsing) return;
+
+    nWithoutEventCounter = 0;
+
+    if( nJCSGMLInputTemplateDepth == 0 &&
+        strcmp(pszName, "JCSGMLInputTemplate") == 0 )
+        nJCSGMLInputTemplateDepth = currentDepth;
+    else if( nJCSGMLInputTemplateDepth > 0 )
+    {
+        if( nCollectionElementDepth == 0 &&
+            strcmp(pszName, "CollectionElement") == 0 )
+        {
+            nCollectionElementDepth = currentDepth;
+            bAccumulateElementValue = TRUE;
+        }
+        else if( nFeatureElementDepth == 0 &&
+                strcmp(pszName, "FeatureElement") == 0 )
+        {
+            nFeatureElementDepth = currentDepth;
+            bAccumulateElementValue = TRUE;
+        }
+        else if( nGeometryElementDepth == 0 &&
+                 strcmp(pszName, "GeometryElement") == 0 )
+        {
+            nGeometryElementDepth = currentDepth;
+            bAccumulateElementValue = TRUE;
+        }
+        else  if( nColumnDepth == 0 && strcmp(pszName, "column") == 0 )
+        {
+            nColumnDepth = currentDepth;
+            oCurColumn.osName = "";
+            oCurColumn.osType = "";
+            oCurColumn.osElementName = "";
+            oCurColumn.osAttributeName = "";
+            oCurColumn.osAttributeValue = "";
+            oCurColumn.bIsBody = FALSE;
+        }
+        else if( nColumnDepth > 0 )
+        {
+            if( nNameDepth == 0 && strcmp(pszName, "name") == 0 )
+            {
+                nNameDepth = currentDepth;
+                bAccumulateElementValue = TRUE;
+            }
+            else if( nTypeDepth == 0 && strcmp(pszName, "type") == 0 )
+            {
+                nTypeDepth = currentDepth;
+                bAccumulateElementValue = TRUE;
+            }
+            else if( strcmp(pszName, "valueElement") == 0 )
+            {
+                const char** papszIter = ppszAttr;
+                while( papszIter && *papszIter != NULL )
+                {
+                    if( strcmp(*papszIter, "elementName") == 0 )
+                        oCurColumn.osElementName = papszIter[1];
+                    else if( strcmp(*papszIter, "attributeName") == 0 )
+                        oCurColumn.osAttributeName = papszIter[1];
+                    else if( strcmp(*papszIter, "attributeValue") == 0 )
+                        oCurColumn.osAttributeValue = papszIter[1];
+                    papszIter += 2;
+                }
+            }
+            else if( strcmp(pszName, "valueLocation") == 0 )
+            {
+                const char** papszIter = ppszAttr;
+                while( papszIter && *papszIter != NULL )
+                {
+                    if( strcmp(*papszIter, "position") == 0 )
+                        oCurColumn.bIsBody = strcmp(papszIter[1], "body") == 0;
+                    else if( strcmp(*papszIter, "attributeName") == 0 )
+                        oCurColumn.osAttributeName = papszIter[1];
+                    papszIter += 2;
+                }
+            }
+        }
+    }
+
+    currentDepth++;
+}
+
+/************************************************************************/
+/*                   endElementLoadSchemaCbk()                          */
+/************************************************************************/
+
+void OGRJMLLayer::endElementLoadSchemaCbk(CPL_UNUSED const char *pszName)
+{
+    if (bStopParsing) return;
+
+    nWithoutEventCounter = 0;
+
+    currentDepth--;
+
+    if( nJCSGMLInputTemplateDepth == currentDepth )
+    {
+        nJCSGMLInputTemplateDepth = 0;
+        bSchemaFinished = TRUE;
+    }
+    else if( nCollectionElementDepth == currentDepth )
+    {
+        nCollectionElementDepth = 0;
+        osCollectionElement = pszElementValue;
+        //CPLDebug("JML", "osCollectionElement = %s", osCollectionElement.c_str());
+        StopAccumulate();
+    }
+    else if( nFeatureElementDepth == currentDepth )
+    {
+        nFeatureElementDepth = 0;
+        osFeatureElement = pszElementValue;
+        //CPLDebug("JML", "osFeatureElement = %s", osFeatureElement.c_str());
+        StopAccumulate();
+    }
+    else if( nGeometryElementDepth == currentDepth )
+    {
+        nGeometryElementDepth = 0;
+        osGeometryElement = pszElementValue;
+        //CPLDebug("JML", "osGeometryElement = %s", osGeometryElement.c_str());
+        StopAccumulate();
+    }
+    else if( nColumnDepth == currentDepth )
+    {
+        int bIsOK = TRUE;
+        if( oCurColumn.osName.size() == 0 )
+            bIsOK = FALSE;
+        if( oCurColumn.osType.size() == 0 )
+            bIsOK = FALSE;
+        if( oCurColumn.osElementName.size() == 0 )
+            bIsOK = FALSE;
+        if( oCurColumn.bIsBody )
+        {
+            if( oCurColumn.osAttributeName.size() == 0 &&
+                oCurColumn.osAttributeValue.size() != 0 )
+                bIsOK = FALSE;
+            if( oCurColumn.osAttributeName.size() != 0 &&
+                oCurColumn.osAttributeValue.size() == 0 )
+                bIsOK = FALSE;
+            /* Only 2 valid possibilities : */
+            /* <osElementName osAttributeName="osAttributeValue">value</osElementName> */
+            /* <osElementName>value</osElementName> */
+        }
+        else
+        {
+            /* <osElementName osAttributeName="value"></osElementName> */
+            if( oCurColumn.osAttributeName.size() == 0 )
+                bIsOK = FALSE;
+            if( oCurColumn.osAttributeValue.size() != 0 )
+                bIsOK = FALSE;
+        }
+        
+        if( bIsOK )
+        {
+            OGRFieldType eType = OFTString;
+            if( EQUAL(oCurColumn.osType, "INTEGER") )
+                eType = OFTInteger;
+            else if( EQUAL(oCurColumn.osType, "DOUBLE") )
+                eType = OFTReal;
+            else if( EQUAL(oCurColumn.osType, "DATE") )
+                eType = OFTDateTime;
+            OGRFieldDefn oField( oCurColumn.osName, eType );
+
+            if( oCurColumn.osName == "R_G_B" && eType == OFTString )
+                iRGBField = poFeatureDefn->GetFieldCount();
+
+            poFeatureDefn->AddFieldDefn(&oField);
+            aoColumns.push_back(oCurColumn);
+        }
+        else
+        {
+            CPLDebug("JML", "Invalid column definition: name = %s, type = %s, "
+                    "elementName = %s, attributeName = %s, attributeValue = %s, bIsBody = %d", 
+                    oCurColumn.osName.c_str(),
+                    oCurColumn.osType.c_str(), 
+                    oCurColumn.osElementName.c_str(),
+                    oCurColumn.osAttributeName.c_str(), 
+                    oCurColumn.osAttributeValue.c_str(),
+                    oCurColumn.bIsBody);
+        }
+
+        nColumnDepth = 0;
+    }
+    else if( nNameDepth == currentDepth )
+    {
+        nNameDepth = 0;
+        oCurColumn.osName = pszElementValue;
+        //CPLDebug("JML", "oCurColumn.osName = %s", oCurColumn.osName.c_str());
+        StopAccumulate();
+    }
+    else if( nTypeDepth == currentDepth )
+    {
+        nTypeDepth = 0;
+        oCurColumn.osType = pszElementValue;
+        //CPLDebug("JML", "oCurColumn.osType = %s", oCurColumn.osType.c_str());
+        StopAccumulate();
+    }
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRJMLLayer::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,OLCStringsAsUTF8) )
+        return TRUE;
+    else 
+        return FALSE;
+}
+
+#endif /* HAVE_EXPAT */
diff --git a/ogr/ogrsf_frmts/jml/ogrjmlwriterlayer.cpp b/ogr/ogrsf_frmts/jml/ogrjmlwriterlayer.cpp
new file mode 100644
index 0000000..984a6b4
--- /dev/null
+++ b/ogr/ogrsf_frmts/jml/ogrjmlwriterlayer.cpp
@@ -0,0 +1,360 @@
+/******************************************************************************
+ * $Id: ogrjmlwriterlayer.cpp 28900 2015-04-14 09:40:34Z rouault $
+ *
+ * Project:  JML Translator
+ * Purpose:  Implements OGRJMLWriterLayer class.
+ *
+ ******************************************************************************
+ * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_jml.h"
+#include "cpl_conv.h"
+#include "ogr_p.h"
+
+CPL_CVSID("$Id: ogrjmlwriterlayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
+
+/************************************************************************/
+/*                           OGRJMLWriterLayer()                        */
+/************************************************************************/
+
+OGRJMLWriterLayer::OGRJMLWriterLayer( const char* pszLayerName,
+                                                OGRJMLDataset* poDS,
+                                                VSILFILE* fp,
+                                                int bAddRGBField,
+                                                int bAddOGRStyleField,
+                                                int bClassicGML )
+
+{
+    this->poDS = poDS;
+    this->fp = fp;
+    bFeaturesWritten = FALSE;
+    this->bAddRGBField = bAddRGBField;
+    this->bAddOGRStyleField = bAddOGRStyleField;
+    this->bClassicGML = bClassicGML;
+    nNextFID = 0;
+
+    poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
+    poFeatureDefn->Reference();
+    
+    VSIFPrintfL(fp, "<?xml version='1.0' encoding='UTF-8'?>\n"
+                    "<JCSDataFile xmlns:gml=\"http://www.opengis.net/gml\" "
+                    "xmlns:xsi=\"http://www.w3.org/2000/10/XMLSchema-instance\" >\n"
+                    "<JCSGMLInputTemplate>\n"
+                    "<CollectionElement>featureCollection</CollectionElement>\n"
+                    "<FeatureElement>feature</FeatureElement>\n"
+                    "<GeometryElement>geometry</GeometryElement>\n"
+                    "<ColumnDefinitions>\n");
+
+}
+
+/************************************************************************/
+/*                        ~OGRJMLWriterLayer()                          */
+/************************************************************************/
+
+OGRJMLWriterLayer::~OGRJMLWriterLayer()
+{
+    if( !bFeaturesWritten )
+        VSIFPrintfL(fp, "</ColumnDefinitions>\n</JCSGMLInputTemplate>\n<featureCollection>\n");
+    VSIFPrintfL(fp, "</featureCollection>\n</JCSDataFile>\n");
+    poFeatureDefn->Release();
+}
+
+/************************************************************************/
+/*                         WriteColumnDeclaration()                     */
+/************************************************************************/
+
+void OGRJMLWriterLayer::WriteColumnDeclaration( const char* pszName,
+                                                     const char* pszType )
+{
+    char* pszEscapedName = OGRGetXML_UTF8_EscapedString( pszName );
+    if( bClassicGML )
+    {
+        VSIFPrintfL(fp, "     <column>\n"
+                        "          <name>%s</name>\n"
+                        "          <type>%s</type>\n"
+                        "          <valueElement elementName=\"%s\"/>\n"
+                        "          <valueLocation position=\"body\"/>\n"
+                        "     </column>\n",
+                    pszEscapedName, pszType, pszEscapedName);
+    }
+    else
+    {
+        VSIFPrintfL(fp, "     <column>\n"
+                        "          <name>%s</name>\n"
+                        "          <type>%s</type>\n"
+                        "          <valueElement elementName=\"property\" attributeName=\"name\" attributeValue=\"%s\"/>\n"
+                        "          <valueLocation position=\"body\"/>\n"
+                        "     </column>\n",
+                    pszEscapedName, pszType, pszEscapedName);
+    }
+    CPLFree(pszEscapedName);
+}
+
+/************************************************************************/
+/*                           ICreateFeature()                            */
+/************************************************************************/
+
+OGRErr OGRJMLWriterLayer::ICreateFeature( OGRFeature *poFeature )
+
+{
+    /* Finish column declaration if we haven't yet created a feature */
+    if( !bFeaturesWritten )
+    {
+        if( bAddOGRStyleField && poFeatureDefn->GetFieldIndex("OGR_STYLE") < 0 )
+        {
+            WriteColumnDeclaration( "OGR_STYLE", "STRING" );
+        }
+        if( bAddRGBField && poFeatureDefn->GetFieldIndex("R_G_B") < 0 )
+        {
+            WriteColumnDeclaration( "R_G_B", "STRING" );
+        }
+        VSIFPrintfL(fp, "</ColumnDefinitions>\n</JCSGMLInputTemplate>\n<featureCollection>\n");
+        bFeaturesWritten = TRUE;
+    }
+
+    if( bClassicGML )
+        VSIFPrintfL(fp, "   <featureMember>\n");
+    VSIFPrintfL(fp, "     <feature>\n");
+
+    /* Add geometry */
+    VSIFPrintfL(fp, "          <geometry>\n");
+    OGRGeometry* poGeom = poFeature->GetGeometryRef();
+    if( poGeom != NULL )
+    {
+        char* pszGML = poGeom->exportToGML();
+        VSIFPrintfL(fp, "                %s\n", pszGML);
+        CPLFree(pszGML);
+    }
+    else
+    {
+        VSIFPrintfL(fp, "                %s\n",
+                    "<gml:MultiGeometry></gml:MultiGeometry>");
+    }
+    VSIFPrintfL(fp, "          </geometry>\n");
+
+    /* Add fields */
+    for(int i=0;i<poFeature->GetFieldCount();i++)
+    {
+        char* pszName = OGRGetXML_UTF8_EscapedString(
+                                poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
+        if( bClassicGML )
+            VSIFPrintfL(fp, "          <%s>", pszName);
+        else
+            VSIFPrintfL(fp, "          <property name=\"%s\">", pszName);
+        if( poFeature->IsFieldSet(i) )
+        {
+            OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
+            if( eType == OFTString )
+            {
+                char* pszValue = OGRGetXML_UTF8_EscapedString(
+                                            poFeature->GetFieldAsString(i) );
+                VSIFPrintfL(fp, "%s", pszValue);
+                CPLFree(pszValue);
+            }
+            else if( eType == OFTDateTime )
+            {
+                int nYear, nMonth, nDay, nHour, nMinute, nTZFlag;
+                float fSecond;
+                poFeature->GetFieldAsDateTime(i, &nYear, &nMonth, &nDay,
+                                            &nHour, &nMinute, &fSecond, &nTZFlag);
+                /* When writing time zone, OpenJUMP expects .XXX seconds */
+                /* to be written */
+                if( nTZFlag > 1 || OGR_GET_MS(fSecond) != 0 )
+                    VSIFPrintfL(fp, "%04d-%02d-%02dT%02d:%02d:%06.3f",
+                                nYear, nMonth, nDay,
+                                nHour, nMinute, fSecond);
+                else
+                    VSIFPrintfL(fp, "%04d-%02d-%02dT%02d:%02d:%02d",
+                                nYear, nMonth, nDay,
+                                nHour, nMinute, (int)fSecond);
+                if( nTZFlag > 1 )
+                {
+                    int nOffset = (nTZFlag - 100) * 15;
+                    int nHours = (int) (nOffset / 60);  // round towards zero
+                    int nMinutes = ABS(nOffset - nHours * 60);
+
+                    if( nOffset < 0 )
+                    {
+                        VSIFPrintfL(fp, "-" );
+                        nHours = ABS(nHours);
+                    }
+                    else
+                        VSIFPrintfL(fp, "+" );
+
+                    VSIFPrintfL(fp, "%02d%02d", nHours, nMinutes );
+                }
+            }
+            else
+            {
+                VSIFPrintfL(fp, "%s", poFeature->GetFieldAsString(i));
+            }
+        }
+        if( bClassicGML )
+            VSIFPrintfL(fp, "</%s>\n", pszName);
+        else
+            VSIFPrintfL(fp, "</property>\n");
+        CPLFree(pszName);
+    }
+
+    /* Add OGR_STYLE from feature style string (if asked) */
+    if( bAddOGRStyleField && poFeatureDefn->GetFieldIndex("OGR_STYLE") < 0 )
+    {
+        if( bClassicGML )
+            VSIFPrintfL(fp, "          <OGR_STYLE>");
+        else
+            VSIFPrintfL(fp, "          <property name=\"%s\">", "OGR_STYLE");
+        if( poFeature->GetStyleString() != NULL )
+        {
+            char* pszValue = OGRGetXML_UTF8_EscapedString( poFeature->GetStyleString() );
+            VSIFPrintfL(fp, "%s", pszValue);
+            CPLFree(pszValue);
+        }
+        if( bClassicGML )
+            VSIFPrintfL(fp, "</OGR_STYLE>\n");
+        else
+            VSIFPrintfL(fp, "</property>\n");
+    }
+    
+    /* Derive R_G_B field from feature style string */
+    if( bAddRGBField && poFeatureDefn->GetFieldIndex("R_G_B") < 0 )
+    {
+        if( bClassicGML )
+            VSIFPrintfL(fp, "          <R_G_B>");
+        else
+            VSIFPrintfL(fp, "          <property name=\"%s\">", "R_G_B");
+        if( poFeature->GetStyleString() != NULL )
+        {
+            OGRGeometry* poGeom = poFeature->GetGeometryRef();
+            OGRwkbGeometryType eGeomType =
+                poGeom ? wkbFlatten(poGeom->getGeometryType()) : wkbUnknown;
+            OGRStyleMgr oMgr;
+            oMgr.InitFromFeature(poFeature);
+            for(int i=0;i<oMgr.GetPartCount();i++)
+            {
+                OGRStyleTool* poTool = oMgr.GetPart(i);
+                if( poTool != NULL )
+                {
+                    const char* pszColor = NULL;
+                    if( poTool->GetType() == OGRSTCPen &&
+                        eGeomType != wkbPolygon && eGeomType != wkbMultiPolygon )
+                    {
+                        GBool bIsNull;
+                        pszColor = ((OGRStylePen*)poTool)->Color(bIsNull);
+                        if( bIsNull ) pszColor = NULL;
+                    }
+                    else if( poTool->GetType() == OGRSTCBrush )
+                    {
+                        GBool bIsNull;
+                        pszColor = ((OGRStyleBrush*)poTool)->ForeColor(bIsNull);
+                        if( bIsNull ) pszColor = NULL;
+                    }
+                    int R, G, B, A;
+                    if( pszColor != NULL &&
+                        poTool->GetRGBFromString(pszColor, R, G, B, A) && A != 0 )
+                    {
+                        VSIFPrintfL(fp, "%02X%02X%02X", R, G, B);
+                    }
+                    delete poTool;
+                }
+            }
+        }
+        if( bClassicGML )
+            VSIFPrintfL(fp, "</R_G_B>\n");
+        else
+            VSIFPrintfL(fp, "</property>\n");
+    }
+
+    VSIFPrintfL(fp, "     </feature>\n");
+    if( bClassicGML )
+        VSIFPrintfL(fp, "   </featureMember>\n");
+
+    poFeature->SetFID(nNextFID ++);
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                            CreateField()                             */
+/************************************************************************/
+
+OGRErr OGRJMLWriterLayer::CreateField( OGRFieldDefn *poFieldDefn,
+                                       int bApproxOK )
+{
+    if( bFeaturesWritten )
+        return OGRERR_FAILURE;
+    
+    if( !bAddRGBField && strcmp( poFieldDefn->GetNameRef(), "R_G_B" ) == 0 )
+        return OGRERR_FAILURE;
+
+    const char* pszType;
+    OGRFieldType eType = poFieldDefn->GetType();
+    if( eType == OFTInteger )
+        pszType = "INTEGER";
+    else if( eType == OFTInteger64 )
+        pszType = "OBJECT";
+    else if( eType == OFTReal )
+        pszType = "DOUBLE";
+    else if( eType == OFTDate || eType == OFTDateTime )
+        pszType = "DATE";
+    else
+    {
+        if( eType != OFTString )
+        {
+            if( bApproxOK )
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                        "Field of type %s unhandled natively. Converting to string",
+                        OGRFieldDefn::GetFieldTypeName(eType));
+            }
+            else
+            {
+                CPLError(CE_Warning, CPLE_AppDefined,
+                         "Field of type %s unhandled natively.",
+                         OGRFieldDefn::GetFieldTypeName(eType));
+                return OGRERR_FAILURE;
+            }
+        }
+        pszType = "STRING";
+    }
+    WriteColumnDeclaration( poFieldDefn->GetNameRef(), pszType );
+
+    poFeatureDefn->AddFieldDefn( poFieldDefn );
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRJMLWriterLayer::TestCapability( const char * pszCap )
+
+{
+    if( EQUAL(pszCap,OLCStringsAsUTF8) )
+        return TRUE;
+    else if( EQUAL(pszCap,OLCSequentialWrite) )
+        return TRUE;
+    else if( EQUAL(pszCap,OLCCreateField) )
+        return !bFeaturesWritten;
+    else 
+        return FALSE;
+}
diff --git a/ogr/ogrsf_frmts/kml/drv_kml.html b/ogr/ogrsf_frmts/kml/drv_kml.html
index 8c5de71..e50b070 100644
--- a/ogr/ogrsf_frmts/kml/drv_kml.html
+++ b/ogr/ogrsf_frmts/kml/drv_kml.html
@@ -31,10 +31,10 @@ are able to be represented in the Simple Features geometry model, you will not b
 many KML-specific attributes from within GDAL/OGR. Please try
 a few test files to get a sense of what is possible.</p>
 
-<p>When outputting KML, the OGR KML driver will translate each OGR Layer into a KML Folder.
+<p>When outputting KML, the OGR KML driver will translate each OGR Layer into a KML Folder
 (you may encounter unexpected behavior
 if you try to mix the geometry types of elements in a layer, e.g. <code>LINESTRING</code> and
-<code>POINT</code> data. </p>
+<code>POINT</code> data).</p>
 
 <p>The KML Driver will rename some layers, or source KML folder names, into new names
 it considers valid, for example '<code>Layer #0</code>', the default name of the first unnamed
@@ -71,7 +71,7 @@ for example and change accordingly the <i>encoding</i> parameter value in the XM
 When writing a KML file, the driver expects UTF-8 content to be passed in.<p>
 
 <h3>Creation Options</h3>
-<p>The following creation options are supported:
+<p>The following dataset creation options are supported:
 <ul>
 <li><b>NameField</b>: Allows you to specify the field to use for the KML <name> element. Default value : 'Name'</li>
 <pre>ogr2ogr -f KML output.kml input.shp -dsco NameField=RegionName</pre>
@@ -121,8 +121,8 @@ Here is the whole discussion about this issue on the <a href="http://groups.goog
 
 <h2>See Also</h2>
 <ul>
-<li> <a href="http://earth.google.com/kml/kml_intro.html">KML Specification</a></li>
-<li> <a href="http://www.keyhole.com/kml/kml_tut.html">KML Tutorial</a></li>
+<li> <a href="https://developers.google.com/kml/?csw=1">KML Specification</a></li>
+<li> <a href="https://developers.google.com/kml/documentation/kml_tut">KML Tutorial</a></li>
 </ul>
 
 </body>
diff --git a/ogr/ogrsf_frmts/kml/kml.cpp b/ogr/ogrsf_frmts/kml/kml.cpp
index 73d77dc..aefaa0f 100644
--- a/ogr/ogrsf_frmts/kml/kml.cpp
+++ b/ogr/ogrsf_frmts/kml/kml.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: kml.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: kml.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  KML Driver
  * Purpose:  Class for reading, parsing and handling a kmlfile.
diff --git a/ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp b/ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp
index fb25c61..2d81ca1 100644
--- a/ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp
+++ b/ogr/ogrsf_frmts/kml/ogr2kmlgeometry.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr2kmlgeometry.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr2kmlgeometry.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  KML Driver
  * Purpose:  Implementation of OGR -> KML geometries writer.
@@ -110,23 +110,23 @@ static void MakeKMLCoordinate( char *pszTarget,
         if( x == (int) x && y == (int) y )
             sprintf( pszTarget, "%d,%d", (int) x, (int) y );
         else if( fabs(x) < 370 && fabs(y) < 370 )
-            sprintf( pszTarget, "%.16g,%.16g", x, y );
+            CPLsprintf( pszTarget, "%.16g,%.16g", x, y );
         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 )
-            sprintf( pszTarget, "%.16g,%.16g", x, y );
+            CPLsprintf( pszTarget, "%.16g,%.16g", x, y );
         else
-            sprintf( pszTarget, "%.3f,%.3f", x, y );
+            CPLsprintf( pszTarget, "%.3f,%.3f", x, y );
     }
     else
     {
         if( x == (int) x && y == (int) y && z == (int) z )
             sprintf( pszTarget, "%d,%d,%d", (int) x, (int) y, (int) z );
         else if( fabs(x) < 370 && fabs(y) < 370 )
-            sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
+            CPLsprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
         else if( fabs(x) > 100000000.0 || fabs(y) > 100000000.0 
                  || fabs(z) > 100000000.0 )
-            sprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
+            CPLsprintf( pszTarget, "%.16g,%.16g,%.16g", x, y, z );
         else
-            sprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
+            CPLsprintf( pszTarget, "%.3f,%.3f,%.3f", x, y, z );
     }
 #endif
 }
@@ -171,7 +171,7 @@ static void AppendCoordinateList( OGRLineString *poLine,
 
 {
     char szCoordinate[256]= { 0 };
-    int b3D = (poLine->getGeometryType() & wkb25DBit);
+    int b3D = wkbHasZ(poLine->getGeometryType());
 
     *pnLength += strlen(*ppszText + *pnLength);
     _GrowBuffer( *pnLength + 20, ppszText, pnMaxLength );
diff --git a/ogr/ogrsf_frmts/kml/ogr_kml.h b/ogr/ogrsf_frmts/kml/ogr_kml.h
index d0a1c26..98a3110 100644
--- a/ogr/ogrsf_frmts/kml/ogr_kml.h
+++ b/ogr/ogrsf_frmts/kml/ogr_kml.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_kml.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_kml.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  KML Driver
  * Purpose:  Declarations for OGR wrapper classes for KML, and OGR->KML
@@ -60,11 +60,11 @@ public:
     // OGRLayer Interface
     //
     OGRFeatureDefn* GetLayerDefn();
-    OGRErr CreateFeature( OGRFeature* poFeature );
+    OGRErr ICreateFeature( OGRFeature* poFeature );
     OGRErr CreateField( OGRFieldDefn* poField, int bApproxOK = TRUE );
     void ResetReading();
     OGRFeature* GetNextFeature();
-    int GetFeatureCount( int bForce = TRUE );
+    GIntBig GetFeatureCount( int bForce = TRUE );
     int TestCapability( const char* pszCap );
 
     //
@@ -115,7 +115,7 @@ public:
     const char* GetName() { return pszName_; }
     int GetLayerCount() { return nLayers_; }
     OGRLayer* GetLayer( int nLayer );
-    OGRLayer* CreateLayer( const char* pszName,
+    OGRLayer* ICreateLayer( const char* pszName,
                            OGRSpatialReference* poSRS = NULL,
                            OGRwkbGeometryType eGType = wkbUnknown,
                            char** papszOptions = NULL );
@@ -166,23 +166,5 @@ private:
 	bool bIssuedCTError_;		
 };
 
-/************************************************************************/
-/*                             OGRKMLDriver                             */
-/************************************************************************/
-
-class OGRKMLDriver : public OGRSFDriver
-{
-public:
-    ~OGRKMLDriver();
-
-    //
-    // OGRSFDriver Interface
-    //
-    const char* GetName();
-    OGRDataSource* Open( const char * pszName_, int bUpdate );
-    OGRDataSource* CreateDataSource( const char *pszName_, char** papszOptions );
-    int TestCapability( const char* pszCap );
-};
-
 #endif /* OGR_KML_H_INCLUDED */
 
diff --git a/ogr/ogrsf_frmts/kml/ogrkmldatasource.cpp b/ogr/ogrsf_frmts/kml/ogrkmldatasource.cpp
index 4310db3..cfcec7f 100644
--- a/ogr/ogrsf_frmts/kml/ogrkmldatasource.cpp
+++ b/ogr/ogrsf_frmts/kml/ogrkmldatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrkmldatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrkmldatasource.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  KML Driver
  * Purpose:  Implementation of OGRKMLDataSource class.
@@ -232,7 +232,7 @@ int OGRKMLDataSource::Open( const char * pszNewName, int bTestOpen )
             poGeotype = wkbUnknown;
         
         if (poGeotype != wkbUnknown && poKMLFile_->is25D())
-            poGeotype = (OGRwkbGeometryType) (poGeotype | wkb25DBit);
+            poGeotype = wkbSetZ(poGeotype);
 
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -335,14 +335,14 @@ int OGRKMLDataSource::Create( const char* pszName, char** papszOptions )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRKMLDataSource::CreateLayer( const char * pszLayerName,
-                               OGRSpatialReference *poSRS,
-                               OGRwkbGeometryType eType,
-                               CPL_UNUSED char ** papszOptions )
+OGRKMLDataSource::ICreateLayer( const char * pszLayerName,
+                                OGRSpatialReference *poSRS,
+                                OGRwkbGeometryType eType,
+                                CPL_UNUSED char ** papszOptions )
 {
     CPLAssert( NULL != pszLayerName);
 
diff --git a/ogr/ogrsf_frmts/kml/ogrkmldriver.cpp b/ogr/ogrsf_frmts/kml/ogrkmldriver.cpp
index efb22c5..b46b29e 100644
--- a/ogr/ogrsf_frmts/kml/ogrkmldriver.cpp
+++ b/ogr/ogrsf_frmts/kml/ogrkmldriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrkmldriver.cpp 23978 2012-02-14 20:42:34Z rouault $
+ * $Id: ogrkmldriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  KML Driver
  * Purpose:  Implementation of OGRKMLDriver class.
@@ -33,39 +33,37 @@
 #include "cpl_error.h"
 
 /************************************************************************/
-/*                          ~OGRKMLDriver()                           */
+/*                         OGRKMLDriverIdentify()                       */
 /************************************************************************/
 
-OGRKMLDriver::~OGRKMLDriver()
-{
-}
+static int OGRKMLDriverIdentify( GDALOpenInfo* poOpenInfo )
 
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRKMLDriver::GetName()
 {
-    return "KML";
+    if( poOpenInfo->fpL == NULL )
+        return FALSE;
+
+    return( strstr((const char*)poOpenInfo->pabyHeader, "<kml") != NULL );
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRKMLDriver::Open( const char * pszName, int bUpdate )
+static GDALDataset *OGRKMLDriverOpen( GDALOpenInfo* poOpenInfo )
+
 {
-    CPLAssert( NULL != pszName );
+    if( poOpenInfo->eAccess == GA_Update )
+        return NULL;
+
+    if( !OGRKMLDriverIdentify(poOpenInfo) )
+        return NULL;
 
     OGRKMLDataSource* poDS = NULL;
 
 #ifdef HAVE_EXPAT
-    if( bUpdate )
-        return NULL;
-
     poDS = new OGRKMLDataSource();
 
-    if( poDS->Open( pszName, TRUE ) )
+    if( poDS->Open( poOpenInfo->pszFilename, TRUE ) )
     {
         /*if( poDS->GetLayerCount() == 0 )
         {
@@ -87,15 +85,19 @@ OGRDataSource *OGRKMLDriver::Open( const char * pszName, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRKMLDriver::CreateDataSource( const char* pszName,
-                                               char** papszOptions )
+static GDALDataset *OGRKMLDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     CPLAssert( NULL != pszName );
     CPLDebug( "KML", "Attempt to create: %s", pszName );
-    
+
     OGRKMLDataSource *poDS = new OGRKMLDataSource();
 
     if( !poDS->Create( pszName, papszOptions ) )
@@ -108,24 +110,47 @@ OGRDataSource *OGRKMLDriver::CreateDataSource( const char* pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRKMLDriver::TestCapability( const char* pszCap )
-{
-    if( EQUAL(pszCap, ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRKML()                           */
 /************************************************************************/
 
 void RegisterOGRKML()
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRKMLDriver );
-}
-
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "KML" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "KML" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Keyhole Markup Language (KML)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "kml" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_kml.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='GPX_USE_EXTENSIONS' type='boolean' description='Whether to write non-GPX attributes in an <extensions> tag' default='NO'/>"
+"  <Option name='NameField' type='string' description='Field to use to fill the KML <name> element' default='Name'/>"
+"  <Option name='DescriptionField' type='string' description='Field to use to fill the KML <description> element' default='Description'/>"
+"  <Option name='AltitudeMode' type='string-select' description='Value of the <AltitudeMode> element for 3D geometries'>"
+"    <Value>clampToGround</Value>"
+"    <Value>relativeToGround</Value>"
+"    <Value>absolute</Value>"
+"  </Option>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, "<LayerCreationOptionList/>" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Real String" );
+
+        poDriver->pfnOpen = OGRKMLDriverOpen;
+        poDriver->pfnIdentify = OGRKMLDriverIdentify;
+        poDriver->pfnCreate = OGRKMLDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/kml/ogrkmllayer.cpp b/ogr/ogrsf_frmts/kml/ogrkmllayer.cpp
index ea4a607..05603bb 100644
--- a/ogr/ogrsf_frmts/kml/ogrkmllayer.cpp
+++ b/ogr/ogrsf_frmts/kml/ogrkmllayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrkmllayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrkmllayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  KML Driver
  * Purpose:  Implementation of OGRKMLLayer class.
@@ -92,6 +92,7 @@ OGRKMLLayer::OGRKMLLayer( const char * pszName,
     poDS_ = poDSIn;
     
     poFeatureDefn_ = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn_->GetName() );
     poFeatureDefn_->Reference();
     poFeatureDefn_->SetGeomType( eReqType );
     if( poFeatureDefn_->GetGeomFieldCount() != 0 )
@@ -162,6 +163,8 @@ OGRFeature *OGRKMLLayer::GetNextFeature()
     /*      Loop till we find a feature matching our criteria.              */
     /* -------------------------------------------------------------------- */
     KML *poKMLFile = poDS_->GetKMLFile();
+    if( poKMLFile == NULL )
+        return NULL;
     poKMLFile->selectLayer(nLayerNumber_);
 
     while(TRUE)
@@ -215,7 +218,12 @@ OGRFeature *OGRKMLLayer::GetNextFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRKMLLayer::GetFeatureCount( int bForce )
+GIntBig OGRKMLLayer::GetFeatureCount(
+#ifndef HAVE_EXPAT
+CPL_UNUSED
+#endif
+                                 int bForce
+                                 )
 {
     int nCount = 0;
 
@@ -315,10 +323,10 @@ CPLString OGRKMLLayer::WriteSchema()
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRKMLLayer::CreateFeature( OGRFeature* poFeature )
+OGRErr OGRKMLLayer::ICreateFeature( OGRFeature* poFeature )
 {
     CPLAssert( NULL != poFeature );
     CPLAssert( NULL != poDS_ );
@@ -503,10 +511,6 @@ OGRErr OGRKMLLayer::CreateFeature( OGRFeature* poFeature )
             if (poFeatureDefn_->GetFieldDefn(iField)->GetType() == OFTReal)
             {
                 pszEscaped = CPLStrdup( pszRaw );
-                /* Use point as decimal separator */
-                char* pszComma = strchr(pszEscaped, ',');
-                if (pszComma)
-                    *pszComma = '.';
             }
             else
             {
@@ -599,11 +603,12 @@ int OGRKMLLayer::TestCapability( const char * pszCap )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRKMLLayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     if( !bWriter_ || iNextKMLId_ != 0 )
         return OGRERR_FAILURE;
-		  
+
 	OGRFieldDefn oCleanCopy( poField );
     poFeatureDefn_->AddFieldDefn( &oCleanCopy );
 
@@ -618,4 +623,3 @@ void OGRKMLLayer::SetLayerNumber( int nLayer )
 {
     nLayerNumber_ = nLayer;
 }
-
diff --git a/ogr/ogrsf_frmts/libkml/drv_libkml.html b/ogr/ogrsf_frmts/libkml/drv_libkml.html
index f472b57..5177f55 100644
--- a/ogr/ogrsf_frmts/libkml/drv_libkml.html
+++ b/ogr/ogrsf_frmts/libkml/drv_libkml.html
@@ -270,7 +270,7 @@
     <p>By default, layers are written as
     <a href="https://developers.google.com/kml/documentation/kmlreference#document">
     <Document></a> elements. By settings the <b>FOLDER</b> layer creation option
-    to No, it is also possible to write them as <a href="https://developers.google.com/kml/documentation/kmlreference#folder">
+    to YES, it is also possible to write them as <a href="https://developers.google.com/kml/documentation/kmlreference#folder">
     <Folder></a> elements (only in .kml files). 
     </p>
 
@@ -318,7 +318,7 @@
     camera_latitude, camera_altitude, camera_altitudemode, head and/or tilt and/or roll,
     leftfov, rightfov, bottomfov, topfov, near fields are also set. The shape field is optional.
   </p>
-  <p>In case the PhotoOverlay is a big image, it is highly recommanded to tile it and
+  <p>In case the PhotoOverlay is a big image, it is highly recommended to tile it and
      generate overview levels, as explained in the <a href="https://developers.google.com/kml/documentation/photos">
      PhotoOverlay tutorial</a>. In which case, the URL should contain the "$[level]", "$[x]" and "$[y]"
      sub-strings in the photooverlay field, and the imagepyramid_tilesize,
diff --git a/ogr/ogrsf_frmts/libkml/ogr_libkml.h b/ogr/ogrsf_frmts/libkml/ogr_libkml.h
index c403c06..15fef92 100644
--- a/ogr/ogrsf_frmts/libkml/ogr_libkml.h
+++ b/ogr/ogrsf_frmts/libkml/ogr_libkml.h
@@ -115,11 +115,11 @@ class OGRLIBKMLLayer:public OGRLayer
     OGRFeature               *GetNextRawFeature (  );
     OGRFeatureDefn           *GetLayerDefn (  ) { return m_poOgrFeatureDefn; };
     //OGRErr                    SetAttributeFilter (const char * );
-    OGRErr                    CreateFeature ( OGRFeature * poOgrFeat );
-    OGRErr                    SetFeature ( OGRFeature * poOgrFeat );
-    OGRErr                    DeleteFeature( long nFID );
+    OGRErr                    ICreateFeature( OGRFeature * poOgrFeat );
+    OGRErr                    ISetFeature( OGRFeature * poOgrFeat );
+    OGRErr                    DeleteFeature( GIntBig nFID );
 
-    int                       GetFeatureCount ( int bForce = TRUE );
+    GIntBig                   GetFeatureCount ( int bForce = TRUE );
     OGRErr                    GetExtent ( OGREnvelope * psExtent,
                                           int bForce = TRUE );
 
@@ -251,7 +251,7 @@ class OGRLIBKMLDataSource:public OGRDataSource
     OGRErr                    DeleteLayer ( int );
 
 
-    OGRLayer                 *CreateLayer ( const char *pszName,
+    OGRLayer                 *ICreateLayer( const char *pszName,
                                             OGRSpatialReference * poSpatialRef = NULL,
                                             OGRwkbGeometryType eGType = wkbUnknown,
                                             char **papszOptions = NULL );
@@ -265,7 +265,7 @@ class OGRLIBKMLDataSource:public OGRDataSource
     int                       Create ( const char *pszFilename,
                                        char **papszOptions );
 
-    OGRErr                    SyncToDisk (  );
+    void                      FlushCache (  );
     int                       TestCapability (const char * );
     
     KmlFactory               *GetKmlFactory() { return m_poKmlFactory; };
@@ -348,26 +348,4 @@ class OGRLIBKMLDataSource:public OGRDataSource
                                          int nGuess);
 };
 
-
-/******************************************************************************
-  driver class
-******************************************************************************/
-
-class OGRLIBKMLDriver:public OGRSFDriver
-{
-  public:
-    OGRLIBKMLDriver           (  );
-    ~OGRLIBKMLDriver          (  );
-
-    const char               *GetName (  );
-    OGRDataSource            *Open ( const char *pszFilename,
-                                     int bUpdate );
-    OGRDataSource            *CreateDataSource ( const char *pszFilename,
-                                                 char **papszOptions );
-
-    OGRErr                    DeleteDataSource ( const char *pszName );
-
-    int                       TestCapability ( const char * );
-};
-
 #endif
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmldatasource.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmldatasource.cpp
index 14af048..df3c186 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmldatasource.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmldatasource.cpp
@@ -174,7 +174,7 @@ static void OGRLIBKMLPostProcessOutput(std::string& oKml)
     size_t nPos = 0;
 
     /* Manually add <?xml> node since libkml does not produce it currently */
-    /* and this is usefull in some circumstances (#5407) */
+    /* and this is useful in some circumstances (#5407) */
     if( !(oKml[0] == '<' && oKml[1] == '?') )
         oKml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + oKml;
 
@@ -569,7 +569,7 @@ void OGRLIBKMLDataSource::WriteDir (
 
 ******************************************************************************/
 
-OGRErr OGRLIBKMLDataSource::SyncToDisk (
+void OGRLIBKMLDataSource::FlushCache (
      )
 {
 
@@ -592,8 +592,6 @@ OGRErr OGRLIBKMLDataSource::SyncToDisk (
 
         bUpdated = FALSE;
     }
-
-    return OGRERR_NONE;
 }
 
 /******************************************************************************
@@ -611,7 +609,7 @@ OGRLIBKMLDataSource::~OGRLIBKMLDataSource (  )
 
     /***** sync the DS to disk *****/
 
-    SyncToDisk (  );
+    FlushCache (  );
 
     CPLFree ( pszName );
 
@@ -1711,12 +1709,10 @@ void OGRLIBKMLDataSource::ParseDocumentOptions(KmlPtr poKml,
             }
             if( pszNLCExpires != NULL )
             {
-                int year, month, day, hour, minute, tz;
-                float fSecond;
-                if( OGRParseXMLDateTime( pszNLCExpires, &year, &month, &day,
-                                        &hour, &minute, &fSecond, &tz) )
+                OGRField sField;
+                if( OGRParseXMLDateTime( pszNLCExpires, &sField) )
                 {
-                    char* pszXMLDate = OGRGetXMLDateTime(year, month, day, hour, minute, (int)fSecond, tz);
+                    char* pszXMLDate = OGRGetXMLDateTime(&sField);
                     nlc->set_expires(pszXMLDate);
                     CPLFree(pszXMLDate);
                 }
@@ -2193,7 +2189,7 @@ OGRLIBKMLLayer *OGRLIBKMLDataSource::CreateLayerKmz (
 }
 
 /******************************************************************************
- CreateLayer()
+ICreateLayer()
  
  Args:          pszLayerName    name of the layer to create
                 poOgrSRS        the SRS of the layer
@@ -2204,7 +2200,7 @@ OGRLIBKMLLayer *OGRLIBKMLDataSource::CreateLayerKmz (
 
 ******************************************************************************/
 
-OGRLayer *OGRLIBKMLDataSource::CreateLayer (
+OGRLayer *OGRLIBKMLDataSource::ICreateLayer(
     const char *pszLayerName,
     OGRSpatialReference * poOgrSRS,
     OGRwkbGeometryType eGType,
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmldriver.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmldriver.cpp
index 476be8d..11cb8df 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmldriver.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmldriver.cpp
@@ -35,63 +35,55 @@
 
 using kmldom::KmlFactory;
 
-static void *hMutex = NULL;
-static KmlFactory *poKmlFactory = NULL;
-    
-/******************************************************************************
- OGRLIBKMLDriver()
-******************************************************************************/
-
-OGRLIBKMLDriver::OGRLIBKMLDriver (  )
-{
-}
+static CPLMutex *hMutex = NULL;
+static KmlFactory* m_poKmlFactory = NULL;
 
 /******************************************************************************
- ~OGRLIBKMLDriver()
+ OGRLIBKMLDriverUnload()
 ******************************************************************************/
 
-OGRLIBKMLDriver::~OGRLIBKMLDriver (  )
+static void OGRLIBKMLDriverUnload ( CPL_UNUSED GDALDriver* poDriver )
 {
     if( hMutex != NULL )
         CPLDestroyMutex(hMutex);
     hMutex = NULL;
-    poKmlFactory = NULL;
+    m_poKmlFactory = NULL;
 }
 
-/******************************************************************************
- GetName()
-******************************************************************************/
+/************************************************************************/
+/*                    OGRLIBKMLDriverIdentify()                         */
+/************************************************************************/
+
+static int OGRLIBKMLDriverIdentify( GDALOpenInfo* poOpenInfo )
 
-const char *OGRLIBKMLDriver::GetName (
-     )
 {
+    if( !poOpenInfo->bStatOK )
+        return FALSE;
+    if( poOpenInfo->bIsDirectory )
+        return -1;
 
-    return "LIBKML";
+    return( EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "kml") ||
+            EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "kmz") );
 }
 
 /******************************************************************************
  Open()
 ******************************************************************************/
 
-OGRDataSource *OGRLIBKMLDriver::Open (
-    const char *pszFilename,
-    int bUpdate )
+static GDALDataset *OGRLIBKMLDriverOpen ( GDALOpenInfo* poOpenInfo )
 {
-    VSIStatBufL sStatBuf;
-    if( !EQUAL(CPLGetExtension(pszFilename), "kml") &&
-        !EQUAL(CPLGetExtension(pszFilename), "kmz") &&
-        !(VSIStatL(pszFilename, &sStatBuf) == 0 && VSI_ISDIR(sStatBuf.st_mode)) )
+    if( OGRLIBKMLDriverIdentify(poOpenInfo) == FALSE )
         return NULL;
 
     {
         CPLMutexHolderD(&hMutex);
-        if( poKmlFactory == NULL )
-            poKmlFactory = KmlFactory::GetFactory (  );
+        if( m_poKmlFactory == NULL )
+            m_poKmlFactory = KmlFactory::GetFactory (  );
     }
 
-    OGRLIBKMLDataSource *poDS = new OGRLIBKMLDataSource ( poKmlFactory );
+    OGRLIBKMLDataSource *poDS = new OGRLIBKMLDataSource ( m_poKmlFactory );
 
-    if ( !poDS->Open ( pszFilename, bUpdate ) ) {
+    if ( !poDS->Open ( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update ) ) {
         delete poDS;
 
         poDS = NULL;
@@ -100,24 +92,28 @@ OGRDataSource *OGRLIBKMLDriver::Open (
     return poDS;
 }
 
-/******************************************************************************
- CreateDataSource()
-******************************************************************************/
 
-OGRDataSource *OGRLIBKMLDriver::CreateDataSource (
-    const char *pszName,
-    char **papszOptions )
+/************************************************************************/
+/*                               Create()                               */
+/************************************************************************/
+
+static GDALDataset *OGRLIBKMLDriverCreate( const char * pszName,
+                                           CPL_UNUSED int nBands,
+                                           CPL_UNUSED int nXSize,
+                                           CPL_UNUSED int nYSize,
+                                           CPL_UNUSED GDALDataType eDT,
+                                           char **papszOptions )
 {
     CPLAssert ( NULL != pszName );
     CPLDebug ( "LIBKML", "Attempt to create: %s", pszName );
 
     {
         CPLMutexHolderD(&hMutex);
-        if( poKmlFactory == NULL )
-            poKmlFactory = KmlFactory::GetFactory (  );
+        if( m_poKmlFactory == NULL )
+            m_poKmlFactory = KmlFactory::GetFactory (  );
     }
 
-    OGRLIBKMLDataSource *poDS = new OGRLIBKMLDataSource ( poKmlFactory );
+    OGRLIBKMLDataSource *poDS = new OGRLIBKMLDataSource ( m_poKmlFactory );
 
     if ( !poDS->Create ( pszName, papszOptions ) ) {
         delete poDS;
@@ -136,8 +132,7 @@ OGRDataSource *OGRLIBKMLDriver::CreateDataSource (
  
 ******************************************************************************/
 
-OGRErr OGRLIBKMLDriver::DeleteDataSource (
-    const char *pszName )
+static CPLErr OGRLIBKMLDriverDelete( const char *pszName )
 {
 
     /***** dir *****/
@@ -149,23 +144,23 @@ OGRErr OGRLIBKMLDriver::DeleteDataSource (
 
         if ( !( papszDirList = VSIReadDir ( pszName ) ) ) {
             if ( VSIRmdir ( pszName ) < 0 )
-                return OGRERR_FAILURE;
+                return CE_Failure;
         }
 
         int nFiles = CSLCount ( papszDirList );
         int iFile;
 
         for ( iFile = 0; iFile < nFiles; iFile++ ) {
-            if ( OGRERR_FAILURE ==
-                 this->DeleteDataSource ( papszDirList[iFile] ) ) {
+            if ( CE_Failure ==
+                 OGRLIBKMLDriverDelete ( papszDirList[iFile] ) ) {
                 CSLDestroy ( papszDirList );
-                return OGRERR_FAILURE;
+                return CE_Failure;
             }
         }
 
         if ( VSIRmdir ( pszName ) < 0 ) {
             CSLDestroy ( papszDirList );
-            return OGRERR_FAILURE;
+            return CE_Failure;
         }
 
         CSLDestroy ( papszDirList );
@@ -175,38 +170,22 @@ OGRErr OGRLIBKMLDriver::DeleteDataSource (
 
     else if ( EQUAL ( CPLGetExtension ( pszName ), "kml" ) ) {
         if ( VSIUnlink ( pszName ) < 0 )
-            return OGRERR_FAILURE;
+            return CE_Failure;
     }
 
     /***** kmz *****/
 
     else if ( EQUAL ( CPLGetExtension ( pszName ), "kmz" ) ) {
         if ( VSIUnlink ( pszName ) < 0 )
-            return OGRERR_FAILURE;
+            return CE_Failure;
     }
 
     /***** do not delete other types of files *****/
 
     else
-        return OGRERR_FAILURE;
+        return CE_Failure;
 
-    return OGRERR_NONE;
-}
-
-/******************************************************************************
- TestCapability()
-******************************************************************************/
-
-int OGRLIBKMLDriver::TestCapability (
-    const char *pszCap )
-{
-    if ( EQUAL ( pszCap, ODrCCreateDataSource ) )
-        return TRUE;
-
-    else if ( EQUAL ( pszCap, ODrCDeleteDataSource ) )
-        return TRUE;
-
-    return FALSE;
+    return CE_None;
 }
 
 /******************************************************************************
@@ -216,7 +195,153 @@ int OGRLIBKMLDriver::TestCapability (
 void RegisterOGRLIBKML (
      )
 {
-    OGRSFDriverRegistrar::GetRegistrar (  )->
-        RegisterDriver ( new OGRLIBKMLDriver );
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "LIBKML" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "LIBKML" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Keyhole Markup Language (LIBKML)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "kml kmz" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_libkml.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='AUTHOR_NAME' type='string' description='Name in <atom:Author> element'/>"
+"  <Option name='AUTHOR_URI' type='string' description='URI in <atom:Author> element'/>"
+"  <Option name='AUTHOR_EMAIL' type='string' description='Email in <atom:Author> element'/>"
+"  <Option name='LINK' type='string' description='Href of <atom:link> element'/>"
+"  <Option name='PHONENUMBER' type='string' description='Value of <phoneNumber> element'/>"
+"  <Option name='NAME' type='string' description='Value of <name> element of top container'/>"
+"  <Option name='VISIBILITY' type='integer' description='Value of <visibility> element of top container (0/1)'/>"
+"  <Option name='OPEN' type='integer' description='Value of <open> element of top container (0/1)'/>"
+"  <Option name='SNIPPET' type='string' description='Value of <snippet> element of top container'/>"
+"  <Option name='DESCRIPTION' type='string' description='Value of <description> element of top container'/>"
+"  <Option name='LISTSTYLE_TYPE' type='string-select' description='Value of <listItemType> element of top container'>"
+"    <Value>check</Value>"
+"    <Value>radioFolder</Value>"
+"    <Value>checkOffOnly</Value>"
+"    <Value>checkHideChildren</Value>"
+"  </Option>"
+"  <Option name='LISTSTYLE_ICON_HREF' type='string' description='URL of the icon to display for the main folder. Sets the href element of the <ItemIcon> element'/>"
+"  <Option name='*_BALLOONSTYLE_BGCOLOR' type='string' description='Background color of a <BallonStyle> element if a style X is defined'/>"
+"  <Option name='*_BALLOONSTYLE_TEXT' type='string' description='Text of a <BallonStyle> element if a style X is defined'/>"
+"  <Option name='NLC_MINREFRESHPERIOD' type='float' description='<minRefreshPeriod> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_MAXSESSIONLENGTH' type='float' description='<maxSessionLength> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_COOKIE' type='string' description='<cookie> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_MESSAGE' type='string' description='<message> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_LINKNAME' type='string' description='<linkName> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_LINKDESCRIPTION' type='string' description='<linkDescription> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_LINKSNIPPET' type='string' description='<linkSnippet> element of a <NetworkLinkControl> element'/>"
+"  <Option name='NLC_EXPIRES' type='string' description='Date to set in <expires> element of a <NetworkLinkControl> element'/>"
+"  <Option name='UPDATE_TARGETHREF' type='string' description='If set, a NetworkLinkControl KML file with an <Update> element will be generated'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='NAME' type='string' description='Value of <name> element of layer container'/>"
+"  <Option name='VISIBILITY' type='integer' description='Value of <visibility> element of layer container (0/1)'/>"
+"  <Option name='OPEN' type='integer' description='Value of <open> element of layer container (0/1)'/>"
+"  <Option name='SNIPPET' type='string' description='Value of <snippet> element of layer container'/>"
+"  <Option name='DESCRIPTION' type='string' description='Value of <description> element of layer container'/>"
+"  <Option name='LOOKAT_LONGITUDE' type='float' description='<longitude> of a <LookAt> element at layer level' min='-180' max='180'/>"
+"  <Option name='LOOKAT_LATITUDE' type='float' description='<latitude> of a <LookAt> element at layer level' min='-90' max='90'/>"
+"  <Option name='LOOKAT_RANGE' type='float' description='<range> of a <LookAt> element at layer level' min='0'/>"
+"  <Option name='LOOKAT_HEADING' type='float' description='<heading> of a <LookAt> element at layer level'/>"
+"  <Option name='LOOKAT_TILT' type='float' description='<tilt> of a <LookAt> element at layer level'/>"
+"  <Option name='LOOKAT_ALTITUDE' type='float' description='<altitude> of a <LookAt> element at layer level'/>"
+"  <Option name='LOOKAT_ALTITUDEMODE' type='string-select' description='<altitudeMode> of a <LookAt> element at layer level'>"
+"    <Value>clampToGround</Value>"
+"    <Value>relativeToGround</Value>"
+"    <Value>absolute</Value>"
+"    <Value>clampToSeaFloor</Value>"
+"    <Value>relativeToSeaFloor</Value>"
+"  </Option>"
+"  <Option name='CAMERA_LONGITUDE' type='float' description='<longitude> of a <Camera> element at layer level' min='-180' max='180'/>"
+"  <Option name='CAMERA_LATITUDE' type='float' description='<latitude> of a <Camera> element at layer level' min='-90' max='90'/>"
+"  <Option name='CAMERA_HEADING' type='float' description='<heading> of a <Camera> element at layer level'/>"
+"  <Option name='CAMERA_TILT' type='float' description='<tilt> of a <Camera> element at layer level'/>"
+"  <Option name='CAMERA_ROLL' type='float' description='<roll> of a <Camera> element at layer level'/>"
+"  <Option name='CAMERA_ALTITUDE' type='float' description='<altitude> of a <Camera> element at layer level'/>"
+"  <Option name='CAMERA_ALTITUDEMODE' type='string-select' description='<altitudeMode> of a <Camera> element at layer level'>"
+"    <Value>clampToGround</Value>"
+"    <Value>relativeToGround</Value>"
+"    <Value>absolute</Value>"
+"    <Value>clampToSeaFloor</Value>"
+"    <Value>relativeToSeaFloor</Value>"
+"  </Option>"
+"  <Option name='ADD_REGION' type='boolean' description='Whether to generate a <Region> element to control when objects of the layer are visible or not' default='NO'/>"
+"  <Option name='REGION_XMIN' type='float' description='West coordinate of the region' min='-180' max='180'/>"
+"  <Option name='REGION_YMIN' type='float' description='South coordinate of the region' min='-90' max='90'/>"
+"  <Option name='REGION_XMAX' type='float' description='East coordinate of the region' min='-180' max='180'/>"
+"  <Option name='REGION_YMAX' type='float' description='North coordinate of the region' min='-90' max='90'/>"
+"  <Option name='REGION_MIN_LOD_PIXELS' type='float' description='minimum size in pixels of the region so that it is displayed' default='256'/>"
+"  <Option name='REGION_MAX_LOD_PIXELS' type='float' description='maximum size in pixels of the region so that it is displayed (-1=infinite)' default='-1'/>"
+"  <Option name='REGION_MIN_FADE_EXTENT' type='float' description='distance over which the geometry fades, from fully opaque to fully transparent' default='0'/>"
+"  <Option name='REGION_MAX_FADE_EXTENT' type='float' description='distance over which the geometry fades, from fully transparent to fully opaque' default='0'/>"
+"  <Option name='SO_HREF' type='string' description='URL of the image to display in a <ScreenOverlay>'/>"
+"  <Option name='SO_NAME' type='string' description='<name> of a <ScreenOverlay>'/>"
+"  <Option name='SO_DESCRIPTION' type='string' description='<description> of a <ScreenOverlay>'/>"
+"  <Option name='SO_OVERLAY_X' type='float' description='x attribute of the <overlayXY> of a <ScreenOverlay>'/>"
+"  <Option name='SO_OVERLAY_Y' type='float' description='y attribute of the <overlayXY> of a <ScreenOverlay>'/>"
+"  <Option name='SO_OVERLAY_XUNITS' type='string-select' description='xunits attribute of the <overlayXY> of a <ScreenOverlay>'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='SO_OVERLAY_YUNITS' type='string-select' description='yunits attribute of the <overlayXY> of a <ScreenOverlay>'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='SO_SCREEN_X' type='float' description='x attribute of the <screenXY> of a <ScreenOverlay>' default='0.05'/>"
+"  <Option name='SO_SCREEN_Y' type='float' description='y attribute of the <screenXY> of a <ScreenOverlay>' default='0.05'/>"
+"  <Option name='SO_SCREEN_XUNITS' type='string-select' description='xunits attribute of the <screenXY> of a <ScreenOverlay>' default='fraction'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='SO_SCREEN_YUNITS' type='string-select' description='yunits attribute of the <screenXY> of a <ScreenOverlay>' default='fraction'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='SO_SIZE_X' type='float' description='x attribute of the <sizeXY> of a <ScreenOverlay>'/>"
+"  <Option name='SO_SIZE_Y' type='float' description='y attribute of the <sizeXY> of a <ScreenOverlay>'/>"
+"  <Option name='SO_SIZE_XUNITS' type='string-select' description='xunits attribute of the <sizeXY> of a <ScreenOverlay>'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='SO_SIZE_YUNITS' type='string-select' description='yunits attribute of the <sizeXY> of a <ScreenOverlay>'>"
+"    <Value>fraction</Value>"
+"    <Value>pixels</Value>"
+"    <Value>insetPixels</Value>"
+"  </Option>"
+"  <Option name='FOLDER' type='boolean' description='Whether to generate a <Folder> element for layers, instead of a <Document>' default='NO'/>"
+"  <Option name='LISTSTYLE_TYPE' type='string-select' description='Value of <listItemType> element of layer container'>"
+"    <Value>check</Value>"
+"    <Value>radioFolder</Value>"
+"    <Value>checkOffOnly</Value>"
+"    <Value>checkHideChildren</Value>"
+"  </Option>"
+"  <Option name='LISTSTYLE_ICON_HREF' type='string' description='URL of the icon to display for the layer folder. Sets the href element of the <ItemIcon> element'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Real String" );
+
+        poDriver->pfnOpen = OGRLIBKMLDriverOpen;
+        poDriver->pfnIdentify = OGRLIBKMLDriverIdentify;
+        poDriver->pfnCreate = OGRLIBKMLDriverCreate;
+        poDriver->pfnDelete = OGRLIBKMLDriverDelete;
+        poDriver->pfnUnloadDriver = OGRLIBKMLDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmlfeature.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmlfeature.cpp
index 49683c1..6b956ba 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmlfeature.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmlfeature.cpp
@@ -382,7 +382,7 @@ FeaturePtr feat2kml (
                     poKmlPhotoOverlay->set_shape(kmldom::SHAPE_SPHERE);
             }
 
-            ElementPtr poKmlElement = geom2kml ( poOgrGeom, -1, 0, poKmlFactory );
+            ElementPtr poKmlElement = geom2kml ( poOgrGeom, -1, poKmlFactory );
 
             poKmlPhotoOverlay->set_point ( AsPoint ( poKmlElement ) );
         }
@@ -616,7 +616,12 @@ FeaturePtr feat2kml (
                                     resourceMap = poKmlFactory->CreateResourceMap();
                                 AliasPtr alias = poKmlFactory->CreateAlias();
                                 if( bIsURL && CPLIsFilenameRelative(osImage) )
-                                    alias->set_targethref(CPLFormFilename(CPLGetPath(pszURL), osImage, NULL));
+                                {
+                                    if( strncmp(pszURL, "http", 4) == 0 )
+                                        alias->set_targethref(CPLSPrintf("%s/%s", CPLGetPath(pszURL), osImage.c_str()));
+                                    else
+                                        alias->set_targethref(CPLFormFilename(CPLGetPath(pszURL), osImage, NULL));
+                                }
                                 else
                                     alias->set_targethref(osImage);
                                 alias->set_sourcehref(osImage);
@@ -681,7 +686,7 @@ FeaturePtr feat2kml (
         PlacemarkPtr poKmlPlacemark = poKmlFactory->CreatePlacemark (  );
         poKmlFeature = poKmlPlacemark;
 
-        ElementPtr poKmlElement = geom2kml ( poOgrGeom, -1, 0, poKmlFactory );
+        ElementPtr poKmlElement = geom2kml ( poOgrGeom, -1, poKmlFactory );
 
         poKmlPlacemark->set_geometry ( AsGeometry ( poKmlElement ) );
     }
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmlfield.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmlfield.cpp
index 7ae78ab..cc1f38b 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmlfield.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmlfield.cpp
@@ -57,6 +57,7 @@ using kmldom::IconPtr;
 using kmldom::CameraPtr;
 
 using kmldom::GxTrackPtr;
+using kmldom::GxMultiTrackPtr;
 
 #include "ogr_libkml.h"
 
@@ -343,13 +344,7 @@ void field2kml (
 
         SimpleDataPtr poKmlSimpleData = NULL;
         DataPtr poKmlData = NULL;
-        int year,
-            month,
-            day,
-            hour,
-            min,
-            sec,
-            tz;
+        OGRField sFieldDT;
 
         switch ( type ) {
 
@@ -508,8 +503,7 @@ void field2kml (
         /* supported in OGR data model to have 2 fields with same name... */
         case OFTDate:          //   Date
             {
-                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
-                                                &hour, &min, &sec, &tz );
+                memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i), sizeof(OGRField));
 
                 int iTimeField;
 
@@ -527,22 +521,11 @@ void field2kml (
                            EQUAL ( name, oFC.beginfield ) ||
                            EQUAL ( name, oFC.endfield ) ) ) {
 
-                        int year2,
-                            month2,
-                            day2,
-                            hour2,
-                            min2,
-                            sec2,
-                            tz2;
-
-                        poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
-                                                        &month2, &day2, &hour2,
-                                                        &min2, &sec2, &tz2 );
-
-                        hour = hour2;
-                        min = min2;
-                        sec = sec2;
-                        tz = tz2;
+                        const OGRField* psField2 = poOgrFeat->GetRawFieldRef(iTimeField);
+                        sFieldDT.Date.Hour = psField2->Date.Hour;
+                        sFieldDT.Date.Minute = psField2->Date.Minute;
+                        sFieldDT.Date.Second = psField2->Date.Second;
+                        sFieldDT.Date.TZFlag = psField2->Date.TZFlag;
 
                         if ( 0 > iSkip1 )
                             iSkip1 = iTimeField;
@@ -560,8 +543,7 @@ void field2kml (
         /* supported in OGR data model to have 2 fields with same name... */
         case OFTTime:          //   Time
             {
-                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
-                                                &hour, &min, &sec, &tz );
+                memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i), sizeof(OGRField));
 
                 int iTimeField;
 
@@ -579,21 +561,10 @@ void field2kml (
                            EQUAL ( name, oFC.beginfield ) ||
                            EQUAL ( name, oFC.endfield ) ) ) {
 
-                        int year2,
-                            month2,
-                            day2,
-                            hour2,
-                            min2,
-                            sec2,
-                            tz2;
-
-                        poOgrFeat->GetFieldAsDateTime ( iTimeField, &year2,
-                                                        &month2, &day2, &hour2,
-                                                        &min2, &sec2, &tz2 );
-
-                        year = year2;
-                        month = month2;
-                        day = day2;
+                        const OGRField* psField2 = poOgrFeat->GetRawFieldRef(iTimeField);
+                        sFieldDT.Date.Year = psField2->Date.Year;
+                        sFieldDT.Date.Month = psField2->Date.Month;
+                        sFieldDT.Date.Day = psField2->Date.Day;
 
                         if ( 0 > iSkip1 )
                             iSkip1 = iTimeField;
@@ -608,16 +579,14 @@ void field2kml (
 
         case OFTDateTime:      //  Date and Time
             {
-                poOgrFeat->GetFieldAsDateTime ( i, &year, &month, &day,
-                                                &hour, &min, &sec, &tz );
+              memcpy(&sFieldDT, poOgrFeat->GetRawFieldRef(i), sizeof(OGRField));
 
               Do_DateTime:
                 /***** timestamp *****/
 
                 if ( EQUAL ( name, oFC.tsfield ) ) {
 
-                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
-                                                        min, sec, tz );
+                    char *timebuf = OGRGetXMLDateTime ( &sFieldDT );
 
                     TimeStampPtr poKmlTimeStamp =
                         poKmlFactory->CreateTimeStamp (  );
@@ -632,8 +601,7 @@ void field2kml (
 
                 if ( EQUAL ( name, oFC.beginfield ) ) {
 
-                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
-                                                        min, sec, tz );
+                    char *timebuf = OGRGetXMLDateTime ( &sFieldDT );
 
                     if ( !poKmlTimeSpan ) {
                         poKmlTimeSpan = poKmlFactory->CreateTimeSpan (  );
@@ -651,8 +619,7 @@ void field2kml (
 
                 else if ( EQUAL ( name, oFC.endfield ) ) {
 
-                    char *timebuf = OGRGetXMLDateTime ( year, month, day, hour,
-                                                        min, sec, tz );
+                    char *timebuf = OGRGetXMLDateTime ( &sFieldDT );
 
 
                     if ( !poKmlTimeSpan ) {
@@ -820,10 +787,6 @@ void field2kml (
             }
 
             char* pszStr = CPLStrdup( poOgrFeat->GetFieldAsString ( i ) );
-            /* Use point as decimal separator */
-            char* pszComma = strchr(pszStr, ',');
-            if (pszComma)
-                *pszComma = '.';
 
             if( bUseSimpleField )
             {
@@ -1192,20 +1155,10 @@ static void kmldatetime2ogr( OGRFeature* poOgrFeat,
     int iField = poOgrFeat->GetFieldIndex ( pszOGRField );
 
     if ( iField > -1 ) {
-        int nYear,
-            nMonth,
-            nDay,
-            nHour,
-            nMinute,
-            nTZ;
-        float fSecond;
-
-        if ( OGRParseXMLDateTime
-                ( osKmlDateTime.c_str (  ), &nYear, &nMonth, &nDay, &nHour,
-                &nMinute, &fSecond, &nTZ ) )
-            poOgrFeat->SetField ( iField, nYear, nMonth, nDay,
-                                    nHour, nMinute, ( int )fSecond,
-                                    nTZ );
+        OGRField sField;
+
+        if ( OGRParseXMLDateTime( osKmlDateTime.c_str (  ), &sField ) )
+            poOgrFeat->SetField ( iField, &sField );
     }
 }
 
@@ -1337,6 +1290,32 @@ void kml2field (
                             poKmlGxTrack->get_when_array_at ( nCoords - 1 ).c_str() );
             }
         }
+
+        /***** special case for gx:MultiTrack ******/
+        /* we set the first timestamp as begin and the last one as end */
+        else if ( poKmlGeometry->Type (  )  == kmldom::Type_GxMultiTrack && 
+             !poKmlFeature->has_timeprimitive (  ) ) {
+            GxMultiTrackPtr poKmlGxMultiTrack = AsGxMultiTrack ( poKmlGeometry );
+            size_t nGeom = poKmlGxMultiTrack->get_gx_track_array_size (  );
+            if( nGeom >= 1 )
+            {
+                GxTrackPtr poKmlGxTrack = poKmlGxMultiTrack->get_gx_track_array_at ( 0 );
+                size_t nCoords = poKmlGxTrack->get_gx_coord_array_size();
+                if( nCoords > 0 )
+                {
+                    kmldatetime2ogr(poOgrFeat, oFC.beginfield,
+                                poKmlGxTrack->get_when_array_at ( 0 ).c_str() );
+                }
+
+                poKmlGxTrack = poKmlGxMultiTrack->get_gx_track_array_at (nGeom -1);
+                nCoords = poKmlGxTrack->get_gx_coord_array_size();
+                if( nCoords > 0 )
+                {
+                    kmldatetime2ogr(poOgrFeat, oFC.endfield,
+                                poKmlGxTrack->get_when_array_at ( nCoords - 1 ).c_str() );
+                }
+            }
+        }
     }
     
     /***** camera *****/
@@ -1686,18 +1665,20 @@ void kml2FeatureDef (
             osName = poKmlSimpleField->get_name (  );
         }
 
-        if ( EQUAL ( pszType, "boolean" ) ||
+        if ( EQUAL ( pszType, "bool" ) ||
+             EQUAL ( pszType, "boolean" ) ||
              EQUAL ( pszType, "int" ) ||
              EQUAL ( pszType, "short" ) ||
              EQUAL ( pszType, "ushort" ) ) {
             OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTInteger );
             poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
         }
+        else if ( EQUAL ( pszType, "uint" ) )  {
+            OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTInteger64 );
+            poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
+        }
         else if ( EQUAL ( pszType, "float" ) ||
-                  EQUAL ( pszType, "double" ) ||
-
-                  /* a too big uint wouldn't fit in a int, so we map it to OFTReal for now ... */
-                  EQUAL ( pszType, "uint" ) ) {
+                  EQUAL ( pszType, "double" ) ) {
             OGRFieldDefn oOgrFieldName ( osName.c_str(), OFTReal );
             poOgrFeatureDefn->AddFieldDefn ( &oOgrFieldName );
         }
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.cpp
index 0e61f0b..697581e 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.cpp
@@ -46,6 +46,7 @@ using kmldom::ElementPtr;
 using kmldom::GeometryPtr;
 using kmldom::GxLatLonQuadPtr;
 using kmldom::GxTrackPtr;
+using kmldom::GxMultiTrackPtr;
 
 using kmlbase::Vec3;
 
@@ -57,7 +58,6 @@ using kmlbase::Vec3;
 args:
           poOgrGeom     the ogr geometry
           extra         used in recursion, just pass -1
-          wkb25D        used in recursion, just pass 0
           poKmlFactory  pointer to the libkml dom factory
 
 returns:
@@ -68,7 +68,6 @@ returns:
 ElementPtr geom2kml (
     OGRGeometry * poOgrGeom,
     int extra,
-    int wkb25D,
     KmlFactory * poKmlFactory )
 {
     int i;
@@ -108,8 +107,6 @@ ElementPtr geom2kml (
     int nGeom;
     OGRwkbGeometryType type = poOgrGeom->getGeometryType (  );
 
-    wkb25D = type & wkb25DBit;
-
     switch ( type ) {
 
     case wkbPoint:
@@ -317,14 +314,14 @@ ElementPtr geom2kml (
         poKmlGeometry = poKmlPolygon = poKmlFactory->CreatePolygon (  );
 
         poKmlTmpGeometry = geom2kml ( poOgrPolygon->getExteriorRing (  ),
-                                      0, wkb25D, poKmlFactory );
+                                      0, poKmlFactory );
         poKmlPolygon->
             set_outerboundaryis ( AsOuterBoundaryIs ( poKmlTmpGeometry ) );
 
         nGeom = poOgrPolygon->getNumInteriorRings (  );
         for ( i = 0; i < nGeom; i++ ) {
             poKmlTmpGeometry = geom2kml ( poOgrPolygon->getInteriorRing ( i ),
-                                          i + 1, wkb25D, poKmlFactory );
+                                          i + 1, poKmlFactory );
             poKmlPolygon->
                 add_innerboundaryis ( AsInnerBoundaryIs ( poKmlTmpGeometry ) );
         }
@@ -346,14 +343,14 @@ ElementPtr geom2kml (
         poKmlGeometry = poKmlPolygon = poKmlFactory->CreatePolygon (  );
 
         poKmlTmpGeometry = geom2kml ( poOgrPolygon->getExteriorRing (  ),
-                                      0, wkb25D, poKmlFactory );
+                                      0, poKmlFactory );
         poKmlPolygon->
             set_outerboundaryis ( AsOuterBoundaryIs ( poKmlTmpGeometry ) );
 
         nGeom = poOgrPolygon->getNumInteriorRings (  );
         for ( i = 0; i < nGeom; i++ ) {
             poKmlTmpGeometry = geom2kml ( poOgrPolygon->getInteriorRing ( i ),
-                                          i + 1, wkb25D, poKmlFactory );
+                                          i + 1, poKmlFactory );
             poKmlPolygon->
                 add_innerboundaryis ( AsInnerBoundaryIs ( poKmlTmpGeometry ) );
         }
@@ -378,7 +375,7 @@ ElementPtr geom2kml (
         {
             CPLDebug("LIBKML", "Turning multiple geometry into single geometry");
             poKmlGeometry = geom2kml( poOgrMultiGeom->getGeometryRef ( 0 ),
-                                      -1, wkb25D, poKmlFactory );
+                                      -1, poKmlFactory );
         }
         else
         {
@@ -391,7 +388,7 @@ ElementPtr geom2kml (
                 poKmlFactory->CreateMultiGeometry (  );
             for ( i = 0; i < nGeom; i++ ) {
                 poKmlTmpGeometry = geom2kml ( poOgrMultiGeom->getGeometryRef ( i ),
-                                            -1, wkb25D, poKmlFactory );
+                                            -1, poKmlFactory );
                 poKmlMultiGeometry->
                     add_geometry ( AsGeometry ( poKmlTmpGeometry ) );
             }
@@ -449,6 +446,7 @@ OGRGeometry *kml2geom_rec (
     PolygonPtr poKmlPolygon;
     MultiGeometryPtr poKmlMultiGeometry;
     GxTrackPtr poKmlGxTrack;
+    GxMultiTrackPtr poKmlGxMultiTrack;
     GeometryPtr poKmlTmpGeometry;
 
     Vec3 oKmlVec;
@@ -624,6 +622,34 @@ OGRGeometry *kml2geom_rec (
         poOgrGeometry = poOgrLineString;
         break;
 
+    case kmldom::Type_GxMultiTrack:
+    {
+        poKmlGxMultiTrack = AsGxMultiTrack ( poKmlGeometry );
+        nGeom = poKmlGxMultiTrack->get_gx_track_array_size (  );
+        poOgrMultiGeometry = new OGRMultiLineString();
+        for( size_t j = 0; j < nGeom; j++ )
+        {
+            poKmlGxTrack = poKmlGxMultiTrack->get_gx_track_array_at ( j );
+            nCoords = poKmlGxTrack->get_gx_coord_array_size();
+            poOgrLineString = new OGRLineString (  );
+            for ( i = 0; i < nCoords; i++ ) {
+                oKmlVec = poKmlGxTrack->get_gx_coord_array_at ( i );
+                if ( oKmlVec.has_altitude (  ) )
+                    poOgrLineString->
+                        addPoint ( oKmlVec.get_longitude (  ),
+                                    oKmlVec.get_latitude (  ),
+                                    oKmlVec.get_altitude (  ) );
+                else
+                    poOgrLineString->
+                        addPoint ( oKmlVec.get_longitude (  ),
+                                    oKmlVec.get_latitude (  ) );
+            }
+            poOgrMultiGeometry->addGeometryDirectly(poOgrLineString);
+        }
+        poOgrGeometry = poOgrMultiGeometry;
+        break;
+    }
+
     default:
         break;
     }
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.h b/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.h
index 5b24a98..3463bce 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.h
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmlgeometry.h
@@ -40,7 +40,6 @@ using kmldom::GxLatLonQuadPtr;
 args:
 						poOgrGeom		the ogr geometry
 						extra		used in recursion, just pass -1
-						wkb25D	used in recursion, just pass 0
 						poKmlFactory	pointer to the libkml dom factory
 
 returns:
@@ -51,7 +50,6 @@ returns:
 ElementPtr geom2kml (
     OGRGeometry * poOgrGeom,
     int extra,
-    int wkb25D,
     KmlFactory * poKmlFactory );
 
 
diff --git a/ogr/ogrsf_frmts/libkml/ogrlibkmllayer.cpp b/ogr/ogrsf_frmts/libkml/ogrlibkmllayer.cpp
index df3d0a0..b98b8c1 100644
--- a/ogr/ogrsf_frmts/libkml/ogrlibkmllayer.cpp
+++ b/ogr/ogrsf_frmts/libkml/ogrlibkmllayer.cpp
@@ -140,6 +140,7 @@ OGRLIBKMLLayer::OGRLIBKMLLayer ( const char *pszLayerName,
     m_poOgrSRS->SetWellKnownGeogCS ( "WGS84" );
 
     m_poOgrFeatureDefn = new OGRFeatureDefn ( pszLayerName );
+    SetDescription( m_poOgrFeatureDefn->GetName() );
     m_poOgrFeatureDefn->Reference (  );
     m_poOgrFeatureDefn->SetGeomType ( eGType );
     if( m_poOgrFeatureDefn->GetGeomFieldCount() != 0 )
@@ -511,7 +512,7 @@ OGRFeature *OGRLIBKMLLayer::GetNextRawFeature (
                 
 ******************************************************************************/
 
-OGRErr OGRLIBKMLLayer::CreateFeature (
+OGRErr OGRLIBKMLLayer::ICreateFeature (
     OGRFeature * poOgrFeat )
 {
 
@@ -571,12 +572,12 @@ OGRErr OGRLIBKMLLayer::CreateFeature (
             {
                 bAlreadyWarned = TRUE;
                 CPLError(CE_Warning, CPLE_AppDefined,
-                         "It is recommanded to define a FID when calling CreateFeature() in a update document");
+                         "It is recommended to define a FID when calling CreateFeature() in a update document");
             }
         }
         else
         {
-            const char* pszId = CPLSPrintf("%s.%ld",
+            const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
                     OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), poOgrFeat->GetFID());
             poOgrFeat->SetFID(nFeatures);
             poKmlFeature->set_id(pszId);
@@ -602,7 +603,7 @@ OGRErr OGRLIBKMLLayer::CreateFeature (
 
 ******************************************************************************/
 
-OGRErr OGRLIBKMLLayer::SetFeature ( OGRFeature * poOgrFeat )
+OGRErr OGRLIBKMLLayer::ISetFeature ( OGRFeature * poOgrFeat )
 {
     if( !bUpdate || m_poKmlUpdate == NULL )
         return OGRERR_UNSUPPORTED_OPERATION;
@@ -618,7 +619,7 @@ OGRErr OGRLIBKMLLayer::SetFeature ( OGRFeature * poOgrFeat )
     poChange->add_object(poKmlFeature);
     m_poKmlUpdate->add_updateoperation(poChange);
     
-    const char* pszId = CPLSPrintf("%s.%ld",
+    const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
                     OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), poOgrFeat->GetFID());
     poKmlFeature->set_targetid(pszId);
 
@@ -640,7 +641,7 @@ OGRErr OGRLIBKMLLayer::SetFeature ( OGRFeature * poOgrFeat )
 
 ******************************************************************************/
 
-OGRErr OGRLIBKMLLayer::DeleteFeature( long nFID )
+OGRErr OGRLIBKMLLayer::DeleteFeature( GIntBig nFID )
 {
     if( !bUpdate || m_poKmlUpdate == NULL )
         return OGRERR_UNSUPPORTED_OPERATION;
@@ -651,7 +652,7 @@ OGRErr OGRLIBKMLLayer::DeleteFeature( long nFID )
     PlacemarkPtr poKmlPlacemark = poKmlFactory->CreatePlacemark();
     poDelete->add_feature(poKmlPlacemark);
     
-    const char* pszId = CPLSPrintf("%s.%ld",
+    const char* pszId = CPLSPrintf("%s." CPL_FRMT_GIB,
                     OGRLIBKMLGetSanitizedNCName(GetName()).c_str(), nFID);
     poKmlPlacemark->set_targetid(pszId);
 
@@ -675,7 +676,7 @@ OGRErr OGRLIBKMLLayer::DeleteFeature( long nFID )
                 
 ******************************************************************************/
 
-int OGRLIBKMLLayer::GetFeatureCount (
+GIntBig OGRLIBKMLLayer::GetFeatureCount (
                                      int bForce )
 {
 
diff --git a/ogr/ogrsf_frmts/makefile.vc b/ogr/ogrsf_frmts/makefile.vc
index 510115b..9f9025e 100644
--- a/ogr/ogrsf_frmts/makefile.vc
+++ b/ogr/ogrsf_frmts/makefile.vc
@@ -1,18 +1,22 @@
 GDAL_ROOT	=	..\..
 
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+!IFDEF INCLUDE_OGR_FRMTS
+
 DIRLIST		=	generic geojson shape ntf sdts tiger s57 dgn mitab gml \
 			avc rec mem vrt csv gmt bna kml gpx \
 			geoconcept xplane georss gtm dxf pgdump gpsbabel \
 			sua openair pds htf aeronavfaa edigeo svg idrisi arcgen \
-			segukooa segy pdf sxf openfilegdb wasp \
+			segukooa segy sxf openfilegdb wasp selafin jml \
 			$(ARCOBJECTS_DIR) \
 			$(OGDIDIR) $(FMEDIR) $(OCIDIR) $(PG_DIR) $(DWGDIR) \
 			$(ODBCDIR) $(SQLITE_DIR) $(MYSQL_DIR) $(ILI_DIR) \
 			$(SDE_DIR) $(IDB_DIR) $(NAS_DIR) $(DODSDIR) \
-			$(PCIDSK_DIR) $(LIBKMLDIR) $(WFSDIR) $(SOSIDIR) $(GFTDIR) \
-			$(COUCHDBDIR) $(FGDB_DIR) $(XLSDIR) $(ODSDIR) $(XLSXDIR) \
+			$(LIBKMLDIR) $(WFSDIR) $(SOSIDIR) $(GFTDIR) \
+			$(COUCHDBDIR) $(CLOUDANTDIR) $(FGDB_DIR) $(XLSDIR) $(ODSDIR) $(XLSXDIR) \
 			$(INGRESDIR) $(ELASTICDIR) $(OSMDIR) $(VFKDIR) $(CARTODBDIR) \
-			$(GMEDIR)
+			$(GMEDIR) $(PLSCENESDIR) $(CSWDIR)
 
 PLUGINDIRLIST	=	$(PLUGIN_ARCOBJECTS_DIR) \
 			$(PLUGIN_DWG_DIR) \
@@ -24,17 +28,6 @@ PLUGINDIRLIST	=	$(PLUGIN_ARCOBJECTS_DIR) \
 			$(PLUGIN_INGRESDIR) \
 			$(PLUGIN_LIBKMLDIR)
 
-!INCLUDE $(GDAL_ROOT)\nmake.opt
-
-!IF "$(PCIDSK_SETTING)" == "EXTERNAL"
-PCIDSK_DIR	=	pcidsk
-PCIDSKOBJ	=	pcidsk\*.obj
-!ENDIF
-!IF "$(PCIDSK_SETTING)" == "INTERNAL"
-PCIDSK_DIR	=	pcidsk
-PCIDSKOBJ	=	pcidsk\*.obj
-!ENDIF
-
 !IFDEF OGDIDIR
 OGDIDIR	=	ogdi
 OGDIOBJ =	ogdi\*.obj
@@ -157,6 +150,8 @@ PLUGIN_LIBKMLDIR = libkml
 !IFDEF CURL_LIB
 WFSDIR = wfs
 WFS_OBJ = wfs\*.obj
+CSWDIR = csw
+CSW_OBJ = csw\*.obj
 !ENDIF
 
 !IFDEF SOSI_INC_DIR
@@ -176,6 +171,8 @@ GFT_OBJ = gft\*.obj
 !IFDEF CURL_LIB
 COUCHDBDIR = couchdb
 COUCHDB_OBJ = couchdb\*.obj
+CLOUDANTDIR = cloudant
+CLOUDANT_OBJ = cloudant\*.obj
 !ENDIF
 
 !IFDEF FREEXL_LIBS
@@ -215,6 +212,17 @@ GMEDIR = gme
 GME_OBJ = gme\*.obj
 !ENDIF
 
+!IFDEF CURL_LIB
+PLSCENESDIR = plscenes
+PLSCENES_OBJ = plscenes\*.obj
+!ENDIF
+
+!ELSE
+
+DIRLIST		=	generic mitab
+
+!ENDIF
+
 default:
 	for %d in ( $(DIRLIST) ) do \
 		cd %d \
@@ -232,14 +240,15 @@ default:
 				 dxf\*.obj pgdump\*.obj gpsbabel\*.obj \
 				 sua\*.obj openair\*.obj pds\*.obj htf\*.obj \
 				 aeronavfaa\*.obj edigeo\*.obj svg\*.obj idrisi\*.obj \
-				 arcgen\*.obj segukooa\*.obj segy\*.obj pdf\*.obj sxf\*.obj \
-				 openfilegdb\*.obj wasp\*.obj \
+				 arcgen\*.obj segukooa\*.obj segy\*.obj sxf\*.obj \
+				 openfilegdb\*.obj wasp\*.obj selafin\*.obj jml\*.obj \
 				$(OGDIOBJ) $(ODBCOBJ) $(SQLITE_OBJ) \
 				$(FMEOBJ) $(OCIOBJ) $(PG_OBJ) $(MYSQL_OBJ) \
 				$(ILI_OBJ) $(DWG_OBJ) $(SDE_OBJ) $(FGDB_OBJ) $(ARCDRIVER_OBJ) $(IDB_OBJ) \
-				$(DODS_OBJ) $(NAS_OBJ) $(PCIDSKOBJ) $(LIBKMLOBJ) $(WFS_OBJ) \
-				$(SOSI_OBJ) $(GFT_OBJ) $(COUCHDB_OBJ) $(XLS_OBJ) $(ODS_OBJ) $(XLSX_OBJ)  \
-				$(INGRESOBJ) $(ELASTIC_OBJ) $(OSM_OBJ) $(VFK_OBJ) $(CARTODB_OBJ) $(GME_OBJ)
+				$(DODS_OBJ) $(NAS_OBJ) $(LIBKMLOBJ) $(WFS_OBJ) \
+				$(SOSI_OBJ) $(GFT_OBJ) $(COUCHDB_OBJ) $(CLOUDANT_OBJ) $(XLS_OBJ) $(ODS_OBJ) $(XLSX_OBJ)  \
+				$(INGRESOBJ) $(ELASTIC_OBJ) $(OSM_OBJ) $(VFK_OBJ) $(CARTODB_OBJ) $(GME_OBJ) $(PLSCENES_OBJ) \
+				$(CSW_OBJ)
 	lib /out:ogrsf_frmts_sup.lib \
 				 ..\..\frmts\iso8211\*.obj \
 				 ..\..\frmts\sdts\sdtsattrreader.obj \
diff --git a/ogr/ogrsf_frmts/mdb/GNUmakefile b/ogr/ogrsf_frmts/mdb/GNUmakefile
index 33f7425..cdddb7f 100644
--- a/ogr/ogrsf_frmts/mdb/GNUmakefile
+++ b/ogr/ogrsf_frmts/mdb/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrmdbdatasource.o ogrmdblayer.o ogrmdbdriver.o \
 		ogrmdbjackcess.o
 
-CPPFLAGS	:=	-I.. $(GDAL_INCLUDE) $(JAVA_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-I..  $(JAVA_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/mdb/drv_mdb.html b/ogr/ogrsf_frmts/mdb/drv_mdb.html
index 94eba41..0a0317d 100644
--- a/ogr/ogrsf_frmts/mdb/drv_mdb.html
+++ b/ogr/ogrsf_frmts/mdb/drv_mdb.html
@@ -47,7 +47,7 @@
   <li>If you didn't specify --with-jvm-lib-add-rpath at configure time, set the path of the directory that contains libjvm.so in LD_LIBRARY_PATH or in /etc/ld.so.conf.</li>
   <li>Download jackcess-1.2.2.jar, commons-lang-2.4.jar and commons-logging-1.1.1.jar (other versions might work)</li>
   <li>Put the 3 JARs either in the lib/ext directory of the JRE (e.g. /usr/lib/jvm/java-6-openjdk/jre/lib/ext) or in another directory
-  and explicitely point them with the CLASSPATH environment variable.</li>
+  and explicitly point them with the CLASSPATH environment variable.</li>
   </ol>
 
   <h2>Resources</h2>
diff --git a/ogr/ogrsf_frmts/mdb/ogr_mdb.h b/ogr/ogrsf_frmts/mdb/ogr_mdb.h
index 220f0c8..3877171 100644
--- a/ogr/ogrsf_frmts/mdb/ogr_mdb.h
+++ b/ogr/ogrsf_frmts/mdb/ogr_mdb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_mdb.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_mdb.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for MDB driver.
@@ -269,11 +269,11 @@ class OGRMDBLayer : public OGRLayer
                                     OGRSpatialReference* poSRS );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int bForce );
+    virtual GIntBig     GetFeatureCount( int bForce );
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -311,7 +311,7 @@ class OGRMDBDataSource : public OGRDataSource
                         OGRMDBDataSource();
                         ~OGRMDBDataSource();
 
-    int                 Open( const char *, int bUpdate, int bTestOpen );
+    int                 Open( const char * );
     int                 OpenTable( const char *pszTableName, 
                                    const char *pszGeomCol,
                                    int bUpdate );
diff --git a/ogr/ogrsf_frmts/mdb/ogrmdbdatasource.cpp b/ogr/ogrsf_frmts/mdb/ogrmdbdatasource.cpp
index d67ddba..76a589f 100644
--- a/ogr/ogrsf_frmts/mdb/ogrmdbdatasource.cpp
+++ b/ogr/ogrsf_frmts/mdb/ogrmdbdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmdbdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmdbdatasource.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMDBDataSource class.
@@ -33,7 +33,7 @@
 #include <vector>
 #include "ogrgeomediageometry.h"
 
-CPL_CVSID("$Id: ogrmdbdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmdbdatasource.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 /************************************************************************/
 /*                         OGRMDBDataSource()                          */
@@ -286,8 +286,7 @@ int OGRMDBDataSource::OpenGeomediaWarehouse(OGRMDBTable* poGAliasTable)
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRMDBDataSource::Open( const char * pszNewName, int bUpdate,
-                              int bTestOpen )
+int OGRMDBDataSource::Open( const char * pszNewName )
 
 {
     CPLAssert( nLayers == 0 );
@@ -349,7 +348,7 @@ int OGRMDBDataSource::Open( const char * pszNewName, int bUpdate,
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGRMDBDataSource::TestCapability( const char * pszCap )
+int OGRMDBDataSource::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
diff --git a/ogr/ogrsf_frmts/mdb/ogrmdbdriver.cpp b/ogr/ogrsf_frmts/mdb/ogrmdbdriver.cpp
index 11080a2..866372b 100644
--- a/ogr/ogrsf_frmts/mdb/ogrmdbdriver.cpp
+++ b/ogr/ogrsf_frmts/mdb/ogrmdbdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmdbdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmdbdriver.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Personal Geodatabase driver.
@@ -30,7 +30,7 @@
 #include "ogr_mdb.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrmdbdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmdbdriver.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 // g++ -fPIC -g -Wall ogr/ogrsf_frmts/mdb/*.cpp -shared -o ogr_MDB.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/mdb -L. -lgdal -I/usr/lib/jvm/java-6-openjdk/include -I/usr/lib/jvm/java-6-openjdk/include/linux  -L/usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server -ljvm
 
@@ -65,6 +65,9 @@ OGRDataSource *OGRMDBDriver::Open( const char * pszFilename,
 {
     OGRMDBDataSource     *poDS;
 
+    if( bUpdate )
+        return NULL;
+
     if( EQUALN(pszFilename, "PGEO:", strlen("PGEO:")) )
         return NULL;
 
@@ -84,7 +87,7 @@ OGRDataSource *OGRMDBDriver::Open( const char * pszFilename,
     // Open data source
     poDS = new OGRMDBDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, TRUE ) )
+    if( !poDS->Open( pszFilename ) )
     {
         delete poDS;
         return NULL;
@@ -97,7 +100,7 @@ OGRDataSource *OGRMDBDriver::Open( const char * pszFilename,
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGRMDBDriver::TestCapability( const char * pszCap )
+int OGRMDBDriver::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
@@ -111,6 +114,12 @@ int OGRMDBDriver::TestCapability( const char * pszCap )
 void RegisterOGRMDB()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRMDBDriver );
+    OGRSFDriver* poDriver = new OGRMDBDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "Access MDB (PGeo and Geomedia capable)" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mdb" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_mdb.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/mdb/ogrmdblayer.cpp b/ogr/ogrsf_frmts/mdb/ogrmdblayer.cpp
index 335e21c..73d4541 100644
--- a/ogr/ogrsf_frmts/mdb/ogrmdblayer.cpp
+++ b/ogr/ogrsf_frmts/mdb/ogrmdblayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmdblayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrmdblayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMDBLayer class
@@ -33,7 +33,7 @@
 #include "ogrpgeogeometry.h"
 #include "ogrgeomediageometry.h"
 
-CPL_CVSID("$Id: ogrmdblayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrmdblayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRMDBLayer()                            */
@@ -108,6 +108,7 @@ CPLErr OGRMDBLayer::BuildFeatureDefn()
 
 {
     poFeatureDefn = new OGRFeatureDefn( poMDBTable->GetName() );
+    SetDescription( poFeatureDefn->GetName() );
 
     poFeatureDefn->Reference();
 
@@ -200,7 +201,7 @@ void OGRMDBLayer::ResetReading()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRMDBLayer::GetFeatureCount(int bForce)
+GIntBig OGRMDBLayer::GetFeatureCount(int bForce)
 {
     if (m_poFilterGeom != NULL || m_poAttrQuery != NULL)
         return OGRLayer::GetFeatureCount(bForce);
@@ -356,7 +357,7 @@ OGRFeature *OGRMDBLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMDBLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMDBLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
@@ -482,7 +483,7 @@ const char *OGRMDBLayer::GetFIDColumn()
 /*                             Initialize()                             */
 /************************************************************************/
 
-CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
+CPLErr OGRMDBLayer::Initialize( CPL_UNUSED const char *pszTableName,
                                 const char *pszGeomCol,
                                 int nShapeType,
                                 double dfExtentLeft,
@@ -557,7 +558,7 @@ CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
     }
 
     if( eOGRType != wkbUnknown && eOGRType != wkbNone && bHasZ )
-        eOGRType = (OGRwkbGeometryType)(((int) eOGRType) | wkb25DBit);
+        eOGRType = wkbSetZ(eOGRType);
 
     poFeatureDefn->SetGeomType(eOGRType);
 
@@ -569,7 +570,7 @@ CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
 /*                             Initialize()                             */
 /************************************************************************/
 
-CPLErr OGRMDBLayer::Initialize( const char *pszTableName,
+CPLErr OGRMDBLayer::Initialize( CPL_UNUSED const char *pszTableName,
                                 const char *pszGeomCol,
                                 OGRSpatialReference* poSRS )
 
diff --git a/ogr/ogrsf_frmts/mem/GNUmakefile b/ogr/ogrsf_frmts/mem/GNUmakefile
index 1367e82..c25552e 100644
--- a/ogr/ogrsf_frmts/mem/GNUmakefile
+++ b/ogr/ogrsf_frmts/mem/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrmemdriver.o ogrmemdatasource.o ogrmemlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/mem/ogr_mem.h b/ogr/ogrsf_frmts/mem/ogr_mem.h
index 4264463..0da4f56 100644
--- a/ogr/ogrsf_frmts/mem/ogr_mem.h
+++ b/ogr/ogrsf_frmts/mem/ogr_mem.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_mem.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_mem.h 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions within the OGR Memory driver.
@@ -36,17 +36,18 @@
 /************************************************************************/
 /*                             OGRMemLayer                              */
 /************************************************************************/
+class OGRMemDataSource;
 
 class OGRMemLayer : public OGRLayer
 {
     OGRFeatureDefn     *poFeatureDefn;
     
-    int                 nFeatureCount;
-    int                 nMaxFeatureCount;
+    GIntBig             nFeatureCount;
+    GIntBig             nMaxFeatureCount;
     OGRFeature        **papoFeatures;
 
-    int                 iNextReadFID;
-    int                 iNextCreateFID;
+    GIntBig             iNextReadFID;
+    GIntBig             iNextCreateFID;
 
     int                 bUpdatable;
     int                 bAdvertizeUTF8;
@@ -61,16 +62,16 @@ class OGRMemLayer : public OGRLayer
 
     void                ResetReading();
     OGRFeature *        GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
 
-    OGRFeature         *GetFeature( long nFeatureId );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
+    OGRErr              ISetFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -85,7 +86,7 @@ class OGRMemLayer : public OGRLayer
     void                SetUpdatable(int bUpdatableIn) { bUpdatable = bUpdatableIn; }
     void                SetAdvertizeUTF8(int bAdvertizeUTF8In) { bAdvertizeUTF8 = bAdvertizeUTF8In; }
 
-    int                 GetNextReadFID() { return iNextReadFID; }
+    GIntBig             GetNextReadFID() { return iNextReadFID; }
 };
 
 /************************************************************************/
@@ -107,7 +108,7 @@ class OGRMemDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
diff --git a/ogr/ogrsf_frmts/mem/ogrmemdatasource.cpp b/ogr/ogrsf_frmts/mem/ogrmemdatasource.cpp
index d18e138..30627d3 100644
--- a/ogr/ogrsf_frmts/mem/ogrmemdatasource.cpp
+++ b/ogr/ogrsf_frmts/mem/ogrmemdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmemdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrmemdatasource.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMemDataSource class.
@@ -31,13 +31,13 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrmemdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrmemdatasource.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 /************************************************************************/
 /*                          OGRMemDataSource()                          */
 /************************************************************************/
 
-OGRMemDataSource::OGRMemDataSource( const char *pszFilename, 
+OGRMemDataSource::OGRMemDataSource( const char *pszFilename,
                                     CPL_UNUSED char **papszOptions)
 {
     pszName = CPLStrdup(pszFilename);
@@ -61,14 +61,14 @@ OGRMemDataSource::~OGRMemDataSource()
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRMemDataSource::CreateLayer( const char * pszLayerName,
-                               OGRSpatialReference *poSRS,
-                               OGRwkbGeometryType eType,
-                               CPL_UNUSED char ** papszOptions )
+OGRMemDataSource::ICreateLayer( const char * pszLayerName,
+                                OGRSpatialReference *poSRS,
+                                OGRwkbGeometryType eType,
+                                CPL_UNUSED char ** papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -123,6 +123,8 @@ int OGRMemDataSource::TestCapability( const char * pszCap )
         return TRUE;
     else if( EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
@@ -139,4 +141,3 @@ OGRLayer *OGRMemDataSource::GetLayer( int iLayer )
     else
         return papoLayers[iLayer];
 }
-
diff --git a/ogr/ogrsf_frmts/mem/ogrmemdriver.cpp b/ogr/ogrsf_frmts/mem/ogrmemdriver.cpp
index 35e86dc..1e5e30b 100644
--- a/ogr/ogrsf_frmts/mem/ogrmemdriver.cpp
+++ b/ogr/ogrsf_frmts/mem/ogrmemdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmemdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrmemdriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMemDriver class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrmemdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrmemdriver.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          ~OGRMemDriver()                           */
@@ -92,6 +92,9 @@ int OGRMemDriver::TestCapability( const char * pszCap )
 void RegisterOGRMEM()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRMemDriver );
-}
+    OGRSFDriver* poDriver = new OGRMemDriver;
+    
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time IntegerList Integer64List RealList StringList Binary" );
 
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( poDriver );
+}
diff --git a/ogr/ogrsf_frmts/mem/ogrmemlayer.cpp b/ogr/ogrsf_frmts/mem/ogrmemlayer.cpp
index da7290b..4ab1676 100644
--- a/ogr/ogrsf_frmts/mem/ogrmemlayer.cpp
+++ b/ogr/ogrsf_frmts/mem/ogrmemlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmemlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrmemlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMemLayer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrmemlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrmemlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRMemLayer()                             */
@@ -50,6 +50,7 @@ OGRMemLayer::OGRMemLayer( const char * pszName, OGRSpatialReference *poSRSIn,
     papoFeatures = NULL;
 
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->SetGeomType( eReqType );
     if( eReqType != wkbNone && poSRSIn != NULL )
     {
@@ -73,12 +74,12 @@ OGRMemLayer::~OGRMemLayer()
 {
     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     {
-        CPLDebug( "Mem", "%d features read on layer '%s'.",
-                  (int) m_nFeaturesRead, 
+        CPLDebug( "Mem", CPL_FRMT_GIB " features read on layer '%s'.",
+                  m_nFeaturesRead, 
                   poFeatureDefn->GetName() );
     }
 
-    for( int i = 0; i < nMaxFeatureCount; i++ )
+    for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
     {
         if( papoFeatures[i] != NULL )
             delete papoFeatures[i];
@@ -130,7 +131,7 @@ OGRFeature *OGRMemLayer::GetNextFeature()
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr OGRMemLayer::SetNextByIndex( long nIndex )
+OGRErr OGRMemLayer::SetNextByIndex( GIntBig nIndex )
 
 {
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL || bHasHoles )
@@ -148,7 +149,7 @@ OGRErr OGRMemLayer::SetNextByIndex( long nIndex )
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMemLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMemLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( nFeatureId < 0 || nFeatureId >= nMaxFeatureCount )
@@ -160,10 +161,10 @@ OGRFeature *OGRMemLayer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRMemLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRMemLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     if (!bUpdatable)
@@ -188,19 +189,26 @@ OGRErr OGRMemLayer::SetFeature( OGRFeature *poFeature )
 
     if( poFeature->GetFID() >= nMaxFeatureCount )
     {
-        int nNewCount = MAX(2*nMaxFeatureCount+10, poFeature->GetFID() + 1 );
+        GIntBig nNewCount = MAX(2*nMaxFeatureCount+10, poFeature->GetFID() + 1 );
+        if( (GIntBig)(size_t)(sizeof(OGRFeature *) * nNewCount) !=
+                                (GIntBig)sizeof(OGRFeature *) * nNewCount )
+        {
+            CPLError(CE_Failure, CPLE_OutOfMemory,
+                     "Cannot allocate array of " CPL_FRMT_GIB " elements", nNewCount);
+            return OGRERR_FAILURE;
+        }
 
         OGRFeature** papoNewFeatures = (OGRFeature **) 
-            VSIRealloc( papoFeatures, sizeof(OGRFeature *) * nNewCount);
+            VSIRealloc( papoFeatures, (size_t)(sizeof(OGRFeature *) * nNewCount) );
         if (papoNewFeatures == NULL)
         {
             CPLError(CE_Failure, CPLE_OutOfMemory,
-                     "Cannot allocate array of %d elements", nNewCount);
+                     "Cannot allocate array of " CPL_FRMT_GIB " elements", nNewCount);
             return OGRERR_FAILURE;
         }
         papoFeatures = papoNewFeatures;
         memset( papoFeatures + nMaxFeatureCount, 0, 
-                sizeof(OGRFeature *) * (nNewCount - nMaxFeatureCount) );
+                sizeof(OGRFeature *) * (size_t)(nNewCount - nMaxFeatureCount) );
         nMaxFeatureCount = nNewCount;
     }
 
@@ -228,10 +236,10 @@ OGRErr OGRMemLayer::SetFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRMemLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRMemLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     if (!bUpdatable)
@@ -259,7 +267,7 @@ OGRErr OGRMemLayer::CreateFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRMemLayer::DeleteFeature( long nFID )
+OGRErr OGRMemLayer::DeleteFeature( GIntBig nFID )
 
 {
     if (!bUpdatable)
@@ -290,7 +298,7 @@ OGRErr OGRMemLayer::DeleteFeature( long nFID )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRMemLayer::GetFeatureCount( int bForce )
+GIntBig OGRMemLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
@@ -335,6 +343,8 @@ int OGRMemLayer::TestCapability( const char * pszCap )
     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
         return bAdvertizeUTF8;
 
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
     else 
         return FALSE;
 }
@@ -343,7 +353,8 @@ int OGRMemLayer::TestCapability( const char * pszCap )
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRMemLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRMemLayer::CreateField( OGRFieldDefn *poField,
+                                 CPL_UNUSED int bApproxOK )
 {
     if (!bUpdatable)
         return OGRERR_FAILURE;
@@ -361,7 +372,7 @@ OGRErr OGRMemLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK
 /*      Add field definition and setup remap definition.                */
 /* -------------------------------------------------------------------- */
     int  *panRemap;
-    int   i;
+    GIntBig   i;
 
     poFeatureDefn->AddFieldDefn( poField );
 
@@ -369,7 +380,7 @@ OGRErr OGRMemLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     {
         if( i < poFeatureDefn->GetFieldCount() - 1 )
-            panRemap[i] = i;
+            panRemap[i] = (int)i;
         else
             panRemap[i] = -1;
     }
@@ -409,7 +420,7 @@ OGRErr OGRMemLayer::DeleteField( int iField )
 /*      Update all the internal features.  Hopefully there aren't any   */
 /*      external features referring to our OGRFeatureDefn!              */
 /* -------------------------------------------------------------------- */
-    for( int i = 0; i < nMaxFeatureCount; i++ )
+    for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
     {
         if( papoFeatures[i] == NULL )
             continue;
@@ -454,7 +465,7 @@ OGRErr OGRMemLayer::ReorderFields( int* panMap )
 /*      Remap all the internal features.  Hopefully there aren't any    */
 /*      external features referring to our OGRFeatureDefn!              */
 /* -------------------------------------------------------------------- */
-    for( int i = 0; i < nMaxFeatureCount; i++ )
+    for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
     {
         if( papoFeatures[i] != NULL )
             papoFeatures[i]->RemapFields( NULL, panMap );
@@ -493,6 +504,25 @@ OGRErr OGRMemLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, in
         {
             /* do nothing on features */
         }
+        else if (poNewFieldDefn->GetType() == OFTInteger64 &&
+                 poFieldDefn->GetType() == OFTInteger)
+        {
+    /* -------------------------------------------------------------------- */
+    /*      Update all the internal features.  Hopefully there aren't any   */
+    /*      external features referring to our OGRFeatureDefn!              */
+    /* -------------------------------------------------------------------- */
+            for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
+            {
+                if( papoFeatures[i] == NULL )
+                    continue;
+
+                OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
+                if( papoFeatures[i]->IsFieldSet(iField) )
+                {
+                    poFieldRaw->Integer64 = poFieldRaw->Integer;
+                }
+            }
+        }
         else if (poNewFieldDefn->GetType() == OFTReal &&
                  poFieldDefn->GetType() == OFTInteger)
         {
@@ -500,7 +530,7 @@ OGRErr OGRMemLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, in
     /*      Update all the internal features.  Hopefully there aren't any   */
     /*      external features referring to our OGRFeatureDefn!              */
     /* -------------------------------------------------------------------- */
-            for( int i = 0; i < nMaxFeatureCount; i++ )
+            for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
             {
                 if( papoFeatures[i] == NULL )
                     continue;
@@ -512,6 +542,25 @@ OGRErr OGRMemLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, in
                 }
             }
         }
+        else if (poNewFieldDefn->GetType() == OFTReal &&
+                 poFieldDefn->GetType() == OFTInteger64)
+        {
+    /* -------------------------------------------------------------------- */
+    /*      Update all the internal features.  Hopefully there aren't any   */
+    /*      external features referring to our OGRFeatureDefn!              */
+    /* -------------------------------------------------------------------- */
+            for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
+            {
+                if( papoFeatures[i] == NULL )
+                    continue;
+
+                OGRField* poFieldRaw = papoFeatures[i]->GetRawFieldRef(iField);
+                if( papoFeatures[i]->IsFieldSet(iField) )
+                {
+                    poFieldRaw->Real = (double) poFieldRaw->Integer64;
+                }
+            }
+        }
         else
         {
             if (poNewFieldDefn->GetType() != OFTString)
@@ -525,7 +574,7 @@ OGRErr OGRMemLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, in
     /*      Update all the internal features.  Hopefully there aren't any   */
     /*      external features referring to our OGRFeatureDefn!              */
     /* -------------------------------------------------------------------- */
-            for( int i = 0; i < nMaxFeatureCount; i++ )
+            for( GIntBig i = 0; i < nMaxFeatureCount; i++ )
             {
                 if( papoFeatures[i] == NULL )
                     continue;
@@ -584,7 +633,7 @@ OGRErr OGRMemLayer::CreateGeomField( OGRGeomFieldDefn *poGeomField,
 /*      Add field definition and setup remap definition.                */
 /* -------------------------------------------------------------------- */
     int  *panRemap;
-    int   i;
+    GIntBig   i;
 
     poFeatureDefn->AddGeomFieldDefn( poGeomField );
 
@@ -592,7 +641,7 @@ OGRErr OGRMemLayer::CreateGeomField( OGRGeomFieldDefn *poGeomField,
     for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
     {
         if( i < poFeatureDefn->GetGeomFieldCount() - 1 )
-            panRemap[i] = i;
+            panRemap[i] = (int) i;
         else
             panRemap[i] = -1;
     }
diff --git a/ogr/ogrsf_frmts/mitab/GNUmakefile b/ogr/ogrsf_frmts/mitab/GNUmakefile
index 7943542..6f8f494 100644
--- a/ogr/ogrsf_frmts/mitab/GNUmakefile
+++ b/ogr/ogrsf_frmts/mitab/GNUmakefile
@@ -13,7 +13,7 @@ OBJ	=	mitab_rawbinblock.o mitab_mapheaderblock.o \
 		mitab_tabview.o mitab_ogr_datasource.o mitab_geometry.o \
 		mitab_tabseamless.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS) -DOGR \
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS) -DOGR \
 			-DMITAB_USE_OFTDATETIME
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
@@ -21,6 +21,8 @@ default:	$(O_OBJ:.o=.$(OBJ_EXT))
 clean:
 	rm -f *.o $(O_OBJ)
 
+$(O_OBJ):       mitab.h mitab_priv.h mitab_ogr_driver.h
+
 update:
 	copymatch.sh ~/pkg/mitab *.TXT
 	copymatch.sh ~/pkg/mitab/mitab *.cpp *.h
diff --git a/ogr/ogrsf_frmts/mitab/drv_mitab.html b/ogr/ogrsf_frmts/mitab/drv_mitab.html
index 7e449f7..05e81a6 100644
--- a/ogr/ogrsf_frmts/mitab/drv_mitab.html
+++ b/ogr/ogrsf_frmts/mitab/drv_mitab.html
@@ -12,8 +12,10 @@
 
 <p>
 MapInfo datasets in native (TAB) format and in interchange (MIF/MID) format
-are supported for reading and writing.  Update of existing files is not 
-currently supported.
+are supported for reading and writing. Starting with GDAL 2.0, update of
+existing TAB files is supported (append of new features, modifications and
+deletions of existing features, adding/renaming/deleting fields, ...).
+Update of existing MIF/MID files is not supported.
 </p>
 
 <p>
@@ -44,14 +46,12 @@ MapInfo coordinate system information is supported for reading and writing.
 
 <p>
 The TAB File format requires that the bounds (geographical extents) of a new
-file be set before writing the first feature.  However, there is currently
-no clean mechanism to set the default bounds of a new file through the 
-OGRDataSource interface.
+file be set before writing the first feature.
 </p>
 
 <p>
-We should fix the driver at some point to set valid default bounds for 
-each projection, but for the time being, the MapInfo driver sets the following
+There is currently no automated setting of valid default bounds for 
+each spatial reference system, so for the time being, the MapInfo driver sets the following
 default bounds when a new layer is created:
 </p>
 <ul>
@@ -59,10 +59,43 @@ default bounds when a new layer is created:
   <li>For any other projection: BOUNDS (-30000000, -15000000) (30000000, 15000000)</li>
 </ul>
 
+<p>
+Starting with GDAL 2.0, it is possible to override those bounds through two
+mechanisms.
+<ul>
+<li> specify a user-defined file that contain projection definitions with bounds.
+The name of this file must be specified with the MITAB_BOUNDS_FILE configuration
+option.
+This allows users to override the
+default bounds for existing projections, and to define bounds for new projections
+not listed in the hard-coded table in the driver.
+The format of the file is a simple text file with one CoordSys string
+per line.  The CoordSys lines should follow the MIF specs, and MUST 
+include the optional Bounds definition at the end of the line, e.g.
+<pre>
+# Lambert 93 French bounds
+CoordSys Earth Projection 3, 33, "m", 3, 46.5, 44, 49.00000000002, 700000, 6600000 Bounds (75000, 6000000) (1275000, 7200000)
+</pre>
+
+It is also possible to establish a mapping between a source CoordSys and a
+target CoordSys with bounds. Such a mapping is specified by adding a line starting
+with "Source = " followed by a CoordSys (spaces before or after the equal sign
+do not matter). The following line should start with "Destination = "
+followed by a CoordSys with bounds, e.g.
+<pre>
+# Map generic Lambert 93 to French Lambert 93, Europe bounds
+Source      = CoordSys Earth Projection 3, 33, "m", 3, 46.5, 44, 49, 700000, 6600000
+Destination = CoordSys Earth Projection 3, 33, "m", 3, 46.5, 44, 49.00000000001, 700000, 6600000 Bounds (-792421, 5278231) (3520778, 9741029)
+</pre>
+
+</li>
+<li>use the BOUNDS layer creation option (see below)</li>
+</ul>
+</p>
 
 <p>
 If no coordinate system is provided when creating a layer, the projection
-case is used, not geographic which can result in very low precision if
+case is used, not geographic, which can result in very low precision if
 the coordinates really are geographic.  You can add "-a_srs WGS84" to the
 <b>ogr2ogr</b> commandline during a translation to force geographic mode.
 </p>
@@ -83,20 +116,18 @@ truncated</li>
 
 <ul>
 <li><b>FORMAT=MIF</b>: To create MIF/MID instead of TAB files (TAB is the default).</li>
+<li><b>SPATIAL_INDEX_MODE=QUICK/OPTIMIZED</b>: The default is QUICK force
+"quick spatial index mode". In this mode writing files can be about 5 times faster, but
+spatial queries can be up to 30 times slower. This can be set to OPTIMIZED in
+GDAL 2.0 to generate optimized spatial index.</li>
 </ul>
 
-<H3>Layer Creation Options</h3>
+<h3>Layer Creation Options</h3>
 
 <ul>
-<li><b>SPATIAL_INDEX_MODE=QUICK</b>: Use this to turn on "quick spatial index
-mode". The default behavior of MITAB since GDAL v1.5.0 is to generate an
-optimized spatial index, but this results in slower write speed than what we
-used to get with GDAL 1.4.x and older. Applications that want faster write
-speed and do not care about the performance of spatial queries on the resulting
-file can use this option to require the creation of a non-optimal spatial index
-(actually emulating the type of spatial index produced by OGR's TAB driver
-before GDAL 1.5.0). In this mode writing files can be about 5 times faster, but
-spatial queries can be up to 30 times slower.</li>
+<li><b>BOUNDS=xmin,ymin,xmax,ymax</b>: (GDAL >=2.0) Define custom layer bounds
+to increase the accuracy of the coordinates. Note: the geometry of written features
+must be within the defined box.</li>
 </ul>
 
 <h3>Compatability</h3>
diff --git a/ogr/ogrsf_frmts/mitab/mitab.h b/ogr/ogrsf_frmts/mitab/mitab.h
index 02cd107..73c9a28 100644
--- a/ogr/ogrsf_frmts/mitab/mitab.h
+++ b/ogr/ogrsf_frmts/mitab/mitab.h
@@ -9,6 +9,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2005, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -166,19 +167,24 @@ class IMapInfoFile : public OGRLayer
   private:
 
   protected: 
-    int                 m_nCurFeatureId;
+    GIntBig             m_nCurFeatureId;
     TABFeature         *m_poCurFeature;
     GBool               m_bBoundsSet;
 
     char                *m_pszCharset;
 
+    TABFeature*         CreateTABFeature(OGRFeature *poFeature);
+
   public:
     IMapInfoFile() ;
     virtual ~IMapInfoFile();
 
     virtual TABFileClass GetFileClass() {return TABFC_IMapInfoFile;}
 
-    virtual int Open(const char *pszFname, const char *pszAccess,
+    virtual int Open(const char *pszFname, const char* pszAccess,
+                     GBool bTestOpenNoError = FALSE );
+
+    virtual int Open(const char *pszFname, TABAccess eAccess,
                      GBool bTestOpenNoError = FALSE ) = 0;
     virtual int Close() = 0;
 
@@ -190,23 +196,24 @@ class IMapInfoFile : public OGRLayer
     // Static method to detect file type, create an object to read that
     // file and open it.
     static IMapInfoFile *SmartOpen(const char *pszFname,
+                                   GBool bUpdate = FALSE,
                                    GBool bTestOpenNoError = FALSE);
 
     ///////////////
     //  OGR methods for read support
     virtual void        ResetReading() = 0;
-    virtual int         GetFeatureCount (int bForce) = 0;
+    virtual GIntBig     GetFeatureCount (int bForce) = 0;
     virtual OGRFeature *GetNextFeature();
-    virtual OGRFeature *GetFeature(long nFeatureId);
-    virtual OGRErr      CreateFeature(OGRFeature *poFeature);
+    virtual OGRFeature *GetFeature(GIntBig nFeatureId);
+    virtual OGRErr      ICreateFeature(OGRFeature *poFeature);
     virtual int         TestCapability( const char * pszCap ) =0;
     virtual int         GetExtent(OGREnvelope *psExtent, int bForce) =0;
 
     ///////////////
     // Read access specific stuff
     //
-    virtual int GetNextFeatureId(int nPrevId) = 0;
-    virtual TABFeature *GetFeatureRef(int nFeatureId) = 0;
+    virtual GIntBig GetNextFeatureId(GIntBig nPrevId) = 0;
+    virtual TABFeature *GetFeatureRef(GIntBig nFeatureId) = 0;
     virtual OGRFeatureDefn *GetLayerDefn() = 0;
 
     virtual TABFieldType GetNativeFieldType(int nFieldId) = 0;
@@ -251,6 +258,9 @@ class IMapInfoFile : public OGRLayer
     virtual int  GetProjInfo(TABProjInfo *poPI) = 0;
     virtual int  SetProjInfo(TABProjInfo *poPI) = 0;
     virtual int  SetMIFCoordSys(const char *pszMIFCoordSys) = 0;
+    
+    static int GetTABType( OGRFieldDefn *poField, TABFieldType* peTABType,
+                           int *pnWidth);
 
 #ifdef DEBUG
     virtual void Dump(FILE *fpOut = NULL) = 0;
@@ -284,9 +294,13 @@ class TABFile: public IMapInfoFile
 
     int         m_nLastFeatureId;
 
-    long        *m_panMatchingFIDs;
+    GIntBig    *m_panMatchingFIDs;
     int         m_iMatchingFID;
 
+    int         m_bNeedTABRewrite;
+
+    int         m_bLastOpWasRead;
+    int         m_bLastOpWasWrite;
     ///////////////
     // Private Read access specific stuff
     //
@@ -304,7 +318,9 @@ class TABFile: public IMapInfoFile
 
     virtual TABFileClass GetFileClass() {return TABFC_TABFile;}
 
-    virtual int Open(const char *pszFname, const char *pszAccess,
+    virtual int Open(const char *pszFname, const char* pszAccess,
+                     GBool bTestOpenNoError = FALSE ) { return IMapInfoFile::Open(pszFname, pszAccess, bTestOpenNoError); }
+    virtual int Open(const char *pszFname, TABAccess eAccess,
                      GBool bTestOpenNoError = FALSE );
     virtual int Close();
 
@@ -315,11 +331,18 @@ class TABFile: public IMapInfoFile
 
     virtual void        ResetReading();
     virtual int         TestCapability( const char * pszCap );
-    virtual int         GetFeatureCount (int bForce);
+    virtual GIntBig     GetFeatureCount (int bForce);
     virtual int         GetExtent(OGREnvelope *psExtent, int bForce);
 
     /* Implement OGRLayer's SetFeature() for random write, only with TABFile */
-    virtual OGRErr      SetFeature( OGRFeature * );
+    virtual OGRErr      ISetFeature( OGRFeature * );
+    virtual OGRErr      DeleteFeature(GIntBig nFeatureId);
+
+    virtual OGRErr      DeleteField( int iField );
+    virtual OGRErr      ReorderFields( int* panMap );
+    virtual OGRErr      AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
+    
+    virtual OGRErr      SyncToDisk();
 
     ///////////////
     // Read access specific stuff
@@ -327,8 +350,8 @@ class TABFile: public IMapInfoFile
 
     int         GetNextFeatureId_Spatial( int nPrevId );
 
-    virtual int GetNextFeatureId(int nPrevId);
-    virtual TABFeature *GetFeatureRef(int nFeatureId);
+    virtual GIntBig GetNextFeatureId(GIntBig nPrevId);
+    virtual TABFeature *GetFeatureRef(GIntBig nFeatureId);
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual TABFieldType GetNativeFieldType(int nFieldId);
@@ -338,6 +361,10 @@ class TABFile: public IMapInfoFile
                           GBool bForce = TRUE );
     
     virtual OGRSpatialReference *GetSpatialRef();
+    
+    static OGRSpatialReference* GetSpatialRefFromTABProj(const TABProjInfo& sTABProj);
+    static int                  GetTABProjFromSpatialRef(const OGRSpatialReference* poSpatialRef,
+                                                         TABProjInfo& sTABProj, int& nParmCount);
 
     virtual int GetFeatureCountByType(int &numPoints, int &numLines,
                                       int &numRegions, int &numTexts,
@@ -377,7 +404,7 @@ class TABFile: public IMapInfoFile
 
     TABMAPFile  *GetMAPFileRef() { return m_poMAPFile; }
 
-    int         WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/);
+    int         WriteFeature(TABFeature *poFeature);
 
 #ifdef DEBUG
     virtual void Dump(FILE *fpOut = NULL);
@@ -437,7 +464,9 @@ class TABView: public IMapInfoFile
 
     virtual TABFileClass GetFileClass() {return TABFC_TABView;}
 
-    virtual int Open(const char *pszFname, const char *pszAccess,
+    virtual int Open(const char *pszFname, const char* pszAccess,
+                     GBool bTestOpenNoError = FALSE ) { return IMapInfoFile::Open(pszFname, pszAccess, bTestOpenNoError); }
+    virtual int Open(const char *pszFname, TABAccess eAccess,
                      GBool bTestOpenNoError = FALSE );
     virtual int Close();
 
@@ -448,15 +477,15 @@ class TABView: public IMapInfoFile
 
     virtual void        ResetReading();
     virtual int         TestCapability( const char * pszCap );
-    virtual int         GetFeatureCount (int bForce);
+    virtual GIntBig     GetFeatureCount (int bForce);
     virtual int         GetExtent(OGREnvelope *psExtent, int bForce);
     
     ///////////////
     // Read access specific stuff
     //
 
-    virtual int GetNextFeatureId(int nPrevId);
-    virtual TABFeature *GetFeatureRef(int nFeatureId);
+    virtual GIntBig GetNextFeatureId(GIntBig nPrevId);
+    virtual TABFeature *GetFeatureRef(GIntBig nFeatureId);
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual TABFieldType GetNativeFieldType(int nFieldId);
@@ -526,8 +555,6 @@ class TABSeamless: public IMapInfoFile
     OGRFeatureDefn *m_poFeatureDefnRef;
 
     TABFile     *m_poIndexTable;
-    int         m_nIndexTableFIDBits;
-    int         m_nIndexTableFIDMask;
     int         m_nTableNameField;
     int         m_nCurBaseTableId;
     TABFile     *m_poCurBaseTable;
@@ -542,9 +569,9 @@ class TABSeamless: public IMapInfoFile
                               GBool bTestOpenNoError = FALSE);
     int         OpenBaseTable(int nTableId, GBool bTestOpenNoError = FALSE);
     int         OpenNextBaseTable(GBool bTestOpenNoError =FALSE);
-    int         EncodeFeatureId(int nTableId, int nBaseFeatureId);
-    int         ExtractBaseTableId(int nEncodedFeatureId);
-    int         ExtractBaseFeatureId(int nEncodedFeatureId);
+    GIntBig     EncodeFeatureId(int nTableId, int nBaseFeatureId);
+    int         ExtractBaseTableId(GIntBig nEncodedFeatureId);
+    int         ExtractBaseFeatureId(GIntBig nEncodedFeatureId);
 
   public:
     TABSeamless();
@@ -552,7 +579,9 @@ class TABSeamless: public IMapInfoFile
 
     virtual TABFileClass GetFileClass() {return TABFC_TABSeamless;}
 
-    virtual int Open(const char *pszFname, const char *pszAccess,
+    virtual int Open(const char *pszFname, const char* pszAccess,
+                     GBool bTestOpenNoError = FALSE ) { return IMapInfoFile::Open(pszFname, pszAccess, bTestOpenNoError); }
+    virtual int Open(const char *pszFname, TABAccess eAccess,
                      GBool bTestOpenNoError = FALSE );
     virtual int Close();
 
@@ -563,15 +592,15 @@ class TABSeamless: public IMapInfoFile
 
     virtual void        ResetReading();
     virtual int         TestCapability( const char * pszCap );
-    virtual int         GetFeatureCount (int bForce);
+    virtual GIntBig     GetFeatureCount (int bForce);
     virtual int         GetExtent(OGREnvelope *psExtent, int bForce);
     
     ///////////////
     // Read access specific stuff
     //
 
-    virtual int GetNextFeatureId(int nPrevId);
-    virtual TABFeature *GetFeatureRef(int nFeatureId);
+    virtual GIntBig GetNextFeatureId(GIntBig nPrevId);
+    virtual TABFeature *GetFeatureRef(GIntBig nFeatureId);
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual TABFieldType GetNativeFieldType(int nFieldId);
@@ -592,7 +621,7 @@ class TABSeamless: public IMapInfoFile
     ///////////////
     // Write access specific stuff
     //
-    virtual int SetBounds(CPL_UNUSED double dXMin, CPL_UNUSED double dYMin, 
+    virtual int SetBounds(CPL_UNUSED double dXMin, CPL_UNUSED double dYMin,
                           CPL_UNUSED double dXMax, CPL_UNUSED double dYMax)   {return -1;}
     virtual int SetFeatureDefn(CPL_UNUSED OGRFeatureDefn *poFeatureDefn,
                                CPL_UNUSED TABFieldType *paeMapInfoNativeFieldTypes=NULL)
@@ -601,23 +630,23 @@ class TABSeamless: public IMapInfoFile
                                CPL_UNUSED TABFieldType eMapInfoType,
                                CPL_UNUSED int nWidth=0,
                                CPL_UNUSED int nPrecision=0,
-                               CPL_UNUSED GBool bIndexed=FALSE, 
-                               CPL_UNUSED GBool bUnique=FALSE, 
-                               CPL_UNUSED int bApproxOK = TRUE)     {return -1;}
+                               CPL_UNUSED GBool bIndexed=FALSE,
+                               CPL_UNUSED GBool bUnique=FALSE,
+                               CPL_UNUSED int bApproxOK = TRUE) {return -1;}
 
     virtual int SetSpatialRef(CPL_UNUSED OGRSpatialReference *poSpatialRef) {return -1;}
 
-    virtual OGRErr CreateFeature(CPL_UNUSED TABFeature *poFeature) 
+    virtual OGRErr CreateFeature(CPL_UNUSED TABFeature *poFeature)
                                         {return OGRERR_UNSUPPORTED_OPERATION;}
 
-    virtual int SetFieldIndexed(CPL_UNUSED int nFieldId)   {return -1;}
+    virtual int SetFieldIndexed(CPL_UNUSED int nFieldId) {return -1;}
 
     ///////////////
     // semi-private.
     virtual int  GetProjInfo(TABProjInfo *poPI)
             { return m_poIndexTable?m_poIndexTable->GetProjInfo(poPI):-1; }
-    virtual int  SetProjInfo(CPL_UNUSED TABProjInfo *poPI)         { return -1; }
-    virtual int  SetMIFCoordSys(const char * /*pszMIFCoordSys*/) {return -1;};
+    virtual int SetProjInfo(CPL_UNUSED TABProjInfo *poPI)         { return -1; }
+    virtual int SetMIFCoordSys(const char * /*pszMIFCoordSys*/) {return -1;};
 
 #ifdef DEBUG
     virtual void Dump(FILE *fpOut = NULL);
@@ -682,7 +711,7 @@ class MIFFile: public IMapInfoFile
     // Private Read access specific stuff
     //
     int         ReadFeatureDefn();
-    int         ParseMIFHeader();
+    int         ParseMIFHeader(int* pbIsEmpty);
     void        PreParseFile();
     int         AddFields(const char *pszLine);
     int         GotoFeature(int nFeatureId);
@@ -703,7 +732,9 @@ class MIFFile: public IMapInfoFile
 
     virtual TABFileClass GetFileClass() {return TABFC_MIFFile;}
 
-    virtual int Open(const char *pszFname, const char *pszAccess,
+    virtual int Open(const char *pszFname, const char* pszAccess,
+                     GBool bTestOpenNoError = FALSE ) { return IMapInfoFile::Open(pszFname, pszAccess, bTestOpenNoError); }
+    virtual int Open(const char *pszFname, TABAccess eAccess,
                      GBool bTestOpenNoError = FALSE );
     virtual int Close();
 
@@ -711,7 +742,7 @@ class MIFFile: public IMapInfoFile
                            {return m_poDefn?m_poDefn->GetName():"";};
 
     virtual int         TestCapability( const char * pszCap ) ;
-    virtual int         GetFeatureCount (int bForce);
+    virtual GIntBig     GetFeatureCount (int bForce);
     virtual void        ResetReading();
     virtual int         GetExtent(OGREnvelope *psExtent, int bForce);
 
@@ -719,8 +750,8 @@ class MIFFile: public IMapInfoFile
     // Read access specific stuff
     //
     
-    virtual int GetNextFeatureId(int nPrevId);
-    virtual TABFeature *GetFeatureRef(int nFeatureId);
+    virtual GIntBig GetNextFeatureId(GIntBig nPrevId);
+    virtual TABFeature *GetFeatureRef(GIntBig nFeatureId);
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual TABFieldType GetNativeFieldType(int nFieldId);
@@ -779,62 +810,6 @@ class MIFFile: public IMapInfoFile
 #define TAB_WarningBoundsOverflow              503
 
 /*---------------------------------------------------------------------
- * Codes for the known MapInfo Geometry types
- *--------------------------------------------------------------------*/
-#define TAB_GEOM_NONE           0
-#define TAB_GEOM_SYMBOL_C       0x01
-#define TAB_GEOM_SYMBOL         0x02
-#define TAB_GEOM_LINE_C         0x04
-#define TAB_GEOM_LINE           0x05
-#define TAB_GEOM_PLINE_C        0x07
-#define TAB_GEOM_PLINE          0x08
-#define TAB_GEOM_ARC_C          0x0a
-#define TAB_GEOM_ARC            0x0b
-#define TAB_GEOM_REGION_C       0x0d
-#define TAB_GEOM_REGION         0x0e
-#define TAB_GEOM_TEXT_C         0x10
-#define TAB_GEOM_TEXT           0x11
-#define TAB_GEOM_RECT_C         0x13
-#define TAB_GEOM_RECT           0x14
-#define TAB_GEOM_ROUNDRECT_C    0x16
-#define TAB_GEOM_ROUNDRECT      0x17
-#define TAB_GEOM_ELLIPSE_C      0x19
-#define TAB_GEOM_ELLIPSE        0x1a
-#define TAB_GEOM_MULTIPLINE_C   0x25
-#define TAB_GEOM_MULTIPLINE     0x26
-#define TAB_GEOM_FONTSYMBOL_C   0x28 
-#define TAB_GEOM_FONTSYMBOL     0x29
-#define TAB_GEOM_CUSTOMSYMBOL_C 0x2b
-#define TAB_GEOM_CUSTOMSYMBOL   0x2c
-/* Version 450 object types: */
-#define TAB_GEOM_V450_REGION_C  0x2e
-#define TAB_GEOM_V450_REGION    0x2f
-#define TAB_GEOM_V450_MULTIPLINE_C 0x31
-#define TAB_GEOM_V450_MULTIPLINE   0x32
-/* Version 650 object types: */
-#define TAB_GEOM_MULTIPOINT_C   0x34
-#define TAB_GEOM_MULTIPOINT     0x35
-#define TAB_GEOM_COLLECTION_C   0x37
-#define TAB_GEOM_COLLECTION     0x38
-/* Version 800 object types: */
-#define TAB_GEOM_UNKNOWN1_C     0x3a    // ???
-#define TAB_GEOM_UNKNOWN1       0x3b    // ???
-#define TAB_GEOM_V800_REGION_C  0x3d
-#define TAB_GEOM_V800_REGION    0x3e
-#define TAB_GEOM_V800_MULTIPLINE_C 0x40
-#define TAB_GEOM_V800_MULTIPLINE   0x41
-#define TAB_GEOM_V800_MULTIPOINT_C 0x43
-#define TAB_GEOM_V800_MULTIPOINT   0x44
-#define TAB_GEOM_V800_COLLECTION_C 0x46
-#define TAB_GEOM_V800_COLLECTION   0x47
-
-#define TAB_GEOM_GET_VERSION(nGeomType)                     \
-    (((nGeomType) < TAB_GEOM_V450_REGION_C)  ? 300:         \
-     ((nGeomType) < TAB_GEOM_MULTIPOINT_C)   ? 450:         \
-     ((nGeomType) < TAB_GEOM_UNKNOWN1_C)     ? 650: 800 )
-
-
-/*---------------------------------------------------------------------
  * Codes for the feature classes
  *--------------------------------------------------------------------*/
 typedef enum
@@ -1044,7 +1019,7 @@ class ITABFeatureSymbol
 class TABFeature: public OGRFeature
 {
   protected:
-    int         m_nMapInfoType;
+    TABGeomType m_nMapInfoType;
 
     double      m_dXMin;
     double      m_dYMin;
@@ -1074,8 +1049,8 @@ class TABFeature: public OGRFeature
 
     virtual TABFeature     *CloneTABFeature(OGRFeatureDefn *pNewDefn = NULL);
     virtual TABFeatureClass GetFeatureClass() { return TABFCNoGeomFeature; };
-    virtual int             GetMapInfoType()  { return m_nMapInfoType; };
-    virtual int             ValidateMapInfoType(CPL_UNUSED TABMAPFile *poMapFile = NULL)
+    virtual TABGeomType     GetMapInfoType()  { return m_nMapInfoType; };
+    virtual TABGeomType     ValidateMapInfoType(CPL_UNUSED TABMAPFile *poMapFile = NULL)
                                                 {m_nMapInfoType=TAB_GEOM_NONE;
                                                  return m_nMapInfoType;};
     GBool       IsRecordDeleted() { return m_bDeletedFlag; };
@@ -1096,7 +1071,7 @@ class TABFeature: public OGRFeature
                                        GBool bCoordDataOnly=FALSE,
                                        TABMAPCoordBlock **ppoCoordBlock=NULL);
     GBool       ValidateCoordType(TABMAPFile * poMapFile);
-    void        ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
+    void        ForceCoordTypeAndOrigin(TABGeomType nMapInfoType, GBool bCompr,
                                         GInt32 nComprOrgX, GInt32 nComprOrgY,
                                         GInt32 nXMin, GInt32 nYMin, 
                                         GInt32 nXMax, GInt32 nYMax);
@@ -1156,7 +1131,7 @@ class TABPoint: public TABFeature,
     virtual ~TABPoint();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCPoint; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1313,7 +1288,7 @@ class TABPolyline: public TABFeature,
     virtual ~TABPolyline();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCPolyline; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1388,7 +1363,7 @@ class TABRegion: public TABFeature,
     virtual ~TABRegion();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCRegion; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1446,7 +1421,7 @@ class TABRectangle: public TABFeature,
     virtual ~TABRectangle();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCRectangle; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1507,7 +1482,7 @@ class TABEllipse: public TABFeature,
     virtual ~TABEllipse();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCEllipse; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1569,7 +1544,7 @@ class TABArc: public TABFeature,
     virtual ~TABArc();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCArc; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1648,7 +1623,7 @@ class TABText: public TABFeature,
     virtual ~TABText();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCText; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1737,7 +1712,7 @@ class TABMultiPoint: public TABFeature,
     virtual ~TABMultiPoint();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCMultiPoint; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1816,7 +1791,7 @@ class TABCollection: public TABFeature,
     virtual ~TABCollection();
 
     virtual TABFeatureClass GetFeatureClass() { return TABFCCollection; };
-    virtual int             ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
+    virtual TABGeomType     ValidateMapInfoType(TABMAPFile *poMapFile = NULL);
 
     virtual TABFeature *CloneTABFeature(OGRFeatureDefn *poNewDefn = NULL );
 
@@ -1921,22 +1896,13 @@ typedef struct
 /*---------------------------------------------------------------------
  * The following are used for coordsys bounds lookup
  *--------------------------------------------------------------------*/
-typedef struct
-{
-    TABProjInfo sProj;          /* Projection/datum definition */
-    double      dXMin;          /* Default bounds for that coordsys */
-    double      dYMin;
-    double      dXMax;
-    double      dYMax;
-} MapInfoBoundsInfo;
 
 GBool   MITABLookupCoordSysBounds(TABProjInfo *psCS,
                                   double &dXMin, double &dYMin,
-                                  double &dXMax, double &dYMax);
+                                  double &dXMax, double &dYMax,
+                                  int bOnlyUserTable = FALSE);
 int     MITABLoadCoordSysTable(const char *pszFname);
 void    MITABFreeCoordSysTable();
 GBool   MITABCoordSysTableLoaded();
 
 #endif /* _MITAB_H_INCLUDED_ */
-
-
diff --git a/ogr/ogrsf_frmts/mitab/mitab_bounds.cpp b/ogr/ogrsf_frmts/mitab/mitab_bounds.cpp
index 3f76e6d..abf9ed2 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_bounds.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_bounds.cpp
@@ -16,16 +16,16 @@
  * 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 
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  **********************************************************************
  *
@@ -59,1077 +59,1142 @@
 
 #include "mitab.h"
 
+typedef struct
+{
+    TABProjInfo sProj;          /* Projection/datum definition */
+    double      dXMin;          /* Default bounds for that coordsys */
+    double      dYMin;
+    double      dXMax;
+    double      dYMax;
+} MapInfoBoundsInfo;
+
+typedef struct
+{
+    TABProjInfo       sProjIn;
+    MapInfoBoundsInfo sBoundsInfo;
+} MapInfoRemapProjInfo;
 
 /*-----------------------------------------------------------------
  * List of known coordsys bounds.
  * 0xff in nEllipsoidId or nUnitsId fields means any value can match.
  *
- * __TODO__: nDatumId is always set to zero in this list, we'd have to 
+ * __TODO__: nDatumId is always set to zero in this list, we'd have to
  * reprocess the whole list to properly set all datum ids and accelerate
  * bounds lookups
  *----------------------------------------------------------------*/
-static MapInfoBoundsInfo **gpapsExtBoundsList = NULL;
+static MapInfoRemapProjInfo *gpasExtBoundsList = NULL;
+static int nExtBoundsListCount = -1;
+static const MapInfoBoundsInfo gasBoundsList[] = {
+{{1, 0xff, 0xff, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -1000, -1000, 1000, 1000},  /* Lat/Lon */
 
-/* TODO: Clean up the initializers! */
-static MapInfoBoundsInfo gasBoundsList[] = {
-{{1, 0xff, 0xff, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}}, -1000, -1000, 1000, 1000},  /* Lat/Lon */
-
-{{2, 29, 0, {-85.5,13,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -18500.7190263237, -4067.43878447928, 30025.7571082958, 4067.43878447928},
-{{2, 29, 0, {20,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26284.8753911183, -3963.19059194305, 23518.0464025796, 3963.19059194305},
-{{2, 7, 7, {0,30,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -34706360.1398239, -7364918.36397399, 34706360.1398239, 7364918.36397399},
-{{3, 0, 3, {-109.5,44.25,45,49,1968503.937,0}, 0,0,0,0, {0,0,0,0,0}},  -376322393.49652, -357755728.255206, 380259401.37052, 398826066.611833},
-{{3, 0, 3, {-111.5,36.6666666667,37.2166666667,38.35,1640419.948,9842519.685}, 0,0,0,0, {0,0,0,0,0}},  -281416969.95067, -245782664.730374, 284697809.84667, 320332115.066966},
-{{3, 0, 3, {-111.5,38.3333333333,39.0166666667,40.65,1640419.948,6561679.79}, 0,0,0,0, {0,0,0,0,0}},  -299820220.76226, -269235441.863424, 303101060.65826, 333685839.557096},
-{{3, 0, 3, {-111.5,40.3333333333,40.7166666667,41.7833333333,1640419.948,3280839.895}, 0,0,0,0, {0,0,0,0,0}},  -313479418.366583, -287610480.882755, 316760258.262583, 342629195.746411},
-{{3, 0, 3, {-120.5,41.6666666667,42.3333333333,44,4921259.843,0}, 0,0,0,0, {0,0,0,0,0}},  -329872743.533369, -311905915.324464, 339715263.219369, 357682091.428273},
-{{3, 0, 3, {-120.5,43.6666666667,44.3333333333,46,8202099.738,0}, 0,0,0,0, {0,0,0,0,0}},  -348623368.682272, -335442185.295993, 365027568.158272, 378208751.544552},
-{{3, 0, 3, {-81,31.8333333333,32.5,34.8333333333,2000000,0}, 0,0,0,0, {0,0,0,0,0}},  -248789436.724623, -218682485.302253, 252789436.724623, 282896388.146993},
-{{3, 0, 3, {-84.3666666667,41.5,42.1,43.6666666667,13123359.58,0}, 0,0,0,0, {0,0,0,0,0}},  -318674512.717618, -308729738.1419, 344921231.877618, 354866006.453336},
-{{3, 0, 3, {-84.3666666667,43.3166666667,44.1833333333,45.7,19685039.37,0}, 0,0,0,0, {0,0,0,0,0}},  -334588341.234808, -332680007.139814, 373958419.974808, 375866754.069803},
-{{3, 0, 3, {-87,44.7833333333,45.4833333333,47.0833333333,26246719.16,0}, 0,0,0,0, {0,0,0,0,0}},  -343541891.912548, -349200540.720143, 396035330.232548, 390376681.424953},
-{{3, 0, 7, {-100,39.8333333333,40,43,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -96293653.747449, -89392122.913416, 97293653.747449, 104195184.581482},
-{{3, 0, 7, {-100,43.8333333333,44.4166666667,45.6833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -107757768.605122, -101845373.546917, 108957768.605122, 114870163.663327},
-{{3, 0, 7, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,700000,3000000}, 0,0,0,0, {0,0,0,0,0}},  -70389655.9882633, -57319094.8848422, 71789655.9882633, 84860217.0916844},
-{{3, 0, 7, {-100.3333333333,42.3333333333,42.8333333333,44.4,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -102916158.881298, -96669936.9429582, 104116158.881298, 110362380.819638},
-{{3, 0, 7, {-100.5,45.6666666667,46.1833333333,47.4833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -114111552.091083, -108589212.496103, 115311552.091083, 120833891.686064},
-{{3, 0, 7, {-100.5,47,47.4333333333,48.7333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -118782512.590452, -113525792.131232, 119982512.590452, 125239233.049672},
-{{3, 0, 7, {-101.5,34,34.65,36.1833333333,200000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -80190916.4774175, -70255345.5878226, 80590916.4774175, 90526487.3670124},
-{{3, 0, 7, {-105.5,36.6666666667,37.2333333333,38.4333333333,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}},  -85492362.7230086, -77749948.5363837, 87321166.3808086, 95063580.5674335},
-{{3, 0, 7, {-105.5,37.8333333333,38.45,39.75,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}},  -88909656.3330413, -81520557.8132071, 90738459.9908412, 98127558.5106754},
-{{3, 0, 7, {-105.5,39.3333333333,39.7166666667,40.7833333333,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}},  -92173099.6583073, -85136649.2531605, 94001903.3161073, 101038353.721254},
-{{3, 0, 7, {-109.5,44.25,45,49,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -114703065.537737, -109043945.972187, 115903065.537737, 121562185.103287},
-{{3, 0, 7, {-111.5,36.6666666667,37.2166666667,38.35,500000,3000000}, 0,0,0,0, {0,0,0,0,0}},  -85775892.4411146, -74914556.209806, 86775892.4411146, 97637228.6724232},
-{{3, 0, 7, {-111.5,38.3333333333,39.0166666667,40.65,500000,2000000}, 0,0,0,0, {0,0,0,0,0}},  -91385203.2884872, -82062962.6799637, 92385203.2884872, 101707443.897011},
-{{3, 0, 7, {-111.5,40.3333333333,40.7166666667,41.7833333333,500000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -95548526.7182849, -87663674.5730598, 96548526.7182849, 104433378.86351},
-{{3, 0, 7, {-116.25,32.1666666667,32.7833333333,33.8833333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -73735809.4129763, -65399717.6233228, 77735809.4129763, 86071901.2026297},
-{{3, 0, 7, {-118,33.5,34.0333333333,35.4666666667,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -76848317.8487893, -69006561.7099004, 80848317.8487893, 88690073.9876782},
-{{3, 0, 7, {-119,35.3333333333,36,37.25,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -81316774.1198701, -74083546.7405704, 85316774.1198701, 92550001.4991699},
-{{3, 0, 7, {-120.5,36.5,37.0666666667,38.4333333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -84187586.7378795, -77301811.5655565, 88187586.7378795, 95073361.9102026},
-{{3, 0, 7, {-120.5,41.6666666667,42.3333333333,44,1500000,0}, 0,0,0,0, {0,0,0,0,0}},  -100545212.229117, -95068922.9908967, 103545212.229117, 109021501.467338},
-{{3, 0, 7, {-120.5,43.6666666667,44.3333333333,46,2500000,0}, 0,0,0,0, {0,0,0,0,0}},  -106260402.774499, -102242778.078219, 111260402.774499, 115278027.47078},
-{{3, 0, 7, {-120.5,45.3333333333,45.8333333333,47.3333333333,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -113297926.255298, -107613973.979824, 114297926.255298, 119981878.530772},
-{{3, 0, 7, {-120.8333333333,47,47.5,48.7333333333,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -119009737.681158, -113655959.077325, 120009737.681158, 125363516.284991},
-{{3, 0, 7, {-122,37.6666666667,38.3333333333,39.8333333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -87776918.3325266, -81257129.4018421, 91776918.3325266, 98296707.2632112},
-{{3, 0, 7, {-122,39.3333333333,40,41.6666666667,2000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -92797918.1664438, -86741363.5256259, 96797918.1664438, 102854472.807262},
-{{3, 0, 7, {-176,51,51.8333333333,53.8333333333,1000000,0}, 0,0,0,0, {0,0,0,0,0}},  -137707686.600156, -133658946.217207, 139707686.600156, 143756426.983104},
-{{3, 0, 7, {-66.4333333333,17.8333333333,18.0333333333,18.4333333333,200000,200000}, 0,0,0,0, {0,0,0,0,0}},  -56733778.1428648, -37322071.9454256, 57133778.1428648, 58748927.6361153},
-{{3, 0, 7, {-70.5,41,41.2833333333,41.4833333333,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -95953926.4298888, -89161935.9801186, 96953926.4298888, 103745916.879659},
-{{3, 0, 7, {-71.5,41,41.7166666667,42.6833333333,200000,750000}, 0,0,0,0, {0,0,0,0,0}},  -98769146.9690858, -91041445.2286386, 99169146.9690858, 106896848.709533},
-{{3, 0, 7, {-72.75,40.8333333333,41.2,41.8666666667,304800.6096,152400.3048}, 0,0,0,0, {0,0,0,0,0}},  -96604898.0590896, -89468373.8450348, 97214499.2782896, 104351023.492344},
-{{3, 0, 7, {-74,40.1666666667,40.6666666667,41.0333333333,300000,0}, 0,0,0,0, {0,0,0,0,0}},  -94551938.838961, -87389402.5378217, 95151938.838961, 102314475.1401},
-{{3, 0, 7, {-77,37.6666666667,38.3,39.45,400000,0}, 0,0,0,0, {0,0,0,0,0}},  -88804178.7516629, -81148556.0144016, 89604178.7516629, 97259801.4889241},
-{{3, 0, 7, {-77.75,39.3333333333,39.9333333333,40.9666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -93070575.1551149, -86055381.3970464, 94270575.1551149, 101285768.913183},
-{{3, 0, 7, {-77.75,40.1666666667,40.8833333333,41.95,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -95953285.96374, -89173937.5969296, 97153285.96374, 103932634.33055},
-{{3, 0, 7, {-78.5,36.3333333333,36.7666666667,37.9666666667,3500000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -81693800.1596124, -75717098.3537021, 88693800.1596124, 94670501.9655228},
-{{3, 0, 7, {-78.5,37.6666666667,38.0333333333,39.2,3500000,2000000}, 0,0,0,0, {0,0,0,0,0}},  -84998823.9067757, -78398508.2242156, 91998823.9067757, 98599139.5893358},
-{{3, 0, 7, {-79,33.75,34.3333333333,36.1666666667,609601.22,0}, 0,0,0,0, {0,0,0,0,0}},  -79389023.1316542, -70798838.7584427, 80608225.5716542, 89198409.9448658},
-{{3, 0, 7, {-79.5,38.5,39,40.25,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -90694785.2338336, -83456997.4383959, 91894785.2338336, 99132573.0292712},
-{{3, 0, 7, {-81,31.8333333333,32.5,34.8333333333,609600,0}, 0,0,0,0, {0,0,0,0,0}},  -75831020.313665, -66654421.5201266, 77050220.313665, 86226819.1072034},
-{{3, 0, 7, {-81,37,37.4833333333,38.8833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -86731868.6538258, -79080928.1042007, 87931868.6538258, 95582809.203451},
-{{3, 0, 7, {-82.5,38,38.7333333333,40.0333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -90013727.4321062, -82680858.3947178, 91213727.4321062, 98546596.4694945},
-{{3, 0, 7, {-82.5,39.6666666667,40.4333333333,41.7,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -94896218.4967998, -88010766.8984708, 96096218.4967998, 102981670.095129},
-{{3, 0, 7, {-84.25,37.5,37.9666666667,38.9666666667,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -87593445.377663, -79948138.9064763, 88593445.377663, 96238751.8488498},
-{{3, 0, 7, {-84.3666666667,41.5,42.1,43.6666666667,4000000,0}, 0,0,0,0, {0,0,0,0,0}},  -97131991.4763139, -94100824.185651, 105131991.476314, 108163158.766977},
-{{3, 0, 7, {-84.3666666667,43.3166666667,44.1833333333,45.7,6000000,0}, 0,0,0,0, {0,0,0,0,0}},  -101982526.408346, -101400866.176215, 113982526.408346, 114564186.640476},
-{{3, 0, 7, {-84.5,29,29.5833333333,30.75,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -68981040.7901211, -58469775.5831551, 70181040.7901211, 80692305.9970871},
-{{3, 0, 7, {-85.75,36.3333333333,36.7333333333,37.9333333333,500000,500000}, 0,0,0,0, {0,0,0,0,0}},  -84608108.5314714, -76125029.0762607, 85608108.5314714, 94091187.9866821},
-{{3, 0, 7, {-86,34.3333333333,35.25,36.4166666667,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -80782527.8217375, -72373896.5103859, 81982527.8217375, 90391159.1330892},
-{{3, 0, 7, {-87,44.7833333333,45.4833333333,47.0833333333,8000000,0}, 0,0,0,0, {0,0,0,0,0}},  -104711568.654913, -106436324.8115, 120711568.654913, 118986812.498326},
-{{3, 0, 7, {-90,42,42.7333333333,44.0666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -102206338.477554, -95896048.3229835, 103406338.477554, 109716628.632125},
-{{3, 0, 7, {-90,43.8333333333,44.25,45.5,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -107154105.286573, -101222137.29396, 108354105.286573, 114286073.279185},
-{{3, 0, 7, {-90,45.1666666667,45.5666666667,46.7666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -111693759.01384, -106048829.503351, 112893759.01384, 118538688.524328},
-{{3, 0, 7, {-91.3333333333,25.5,26.1666666667,27.8333333333,1000000,0}, 0,0,0,0, {0,0,0,0,0}},  -63537867.0156485, -51847003.2875935, 65537867.0156485, 77228730.7437035},
-{{3, 0, 7, {-91.3333333333,28.5,29.3,30.7,1000000,0}, 0,0,0,0, {0,0,0,0,0}},  -68286769.6701213, -58065091.5621744, 70286769.6701213, 80508447.7780682},
-{{3, 0, 7, {-92,32.6666666667,33.3,34.7666666667,400000,400000}, 0,0,0,0, {0,0,0,0,0}},  -76844795.0772024, -67240210.8482154, 77644795.0772024, 87249379.3061895},
-{{3, 0, 7, {-92,34.3333333333,34.9333333333,36.2333333333,400000,0}, 0,0,0,0, {0,0,0,0,0}},  -80385696.4806497, -71723301.2825226, 81185696.4806497, 89848091.6787767},
-{{3, 0, 7, {-92.5,30.5,31.1666666667,32.6666666667,1000000,0}, 0,0,0,0, {0,0,0,0,0}},  -71843187.1479918, -62437428.102125, 73843187.1479918, 83248946.1938587},
-{{3, 0, 7, {-93.1,46.5,47.0333333333,48.6333333333,800000,100000}, 0,0,0,0, {0,0,0,0,0}},  -117632875.188048, -112398161.714158, 119232875.188048, 124467588.661938},
-{{3, 0, 7, {-93.5,40,40.6166666667,41.7833333333,500000,0}, 0,0,0,0, {0,0,0,0,0}},  -95397349.164015, -88468304.6501118, 96397349.164015, 103326393.677918},
-{{3, 0, 7, {-93.5,41.5,42.0666666667,43.2666666667,1500000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -98941207.3645198, -92381467.3382571, 101941207.36452, 108500947.390783},
-{{3, 0, 7, {-94,43,43.7833333333,45.2166666667,800000,100000}, 0,0,0,0, {0,0,0,0,0}},  -105671574.194712, -99704447.3453072, 107271574.194712, 113238701.044116},
-{{3, 0, 7, {-94.25,45,45.6166666667,47.05,800000,100000}, 0,0,0,0, {0,0,0,0,0}},  -112092591.799175, -106546357.855489, 113692591.799175, 119238825.742861},
-{{3, 0, 7, {-98,33.3333333333,33.9333333333,35.2333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -77870984.1222039, -69071740.6080561, 79070984.1222039, 87870227.6363517},
-{{3, 0, 7, {-98,35,35.5666666667,36.7666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}},  -81588328.3763743, -73324068.4505433, 82788328.3763743, 91052588.3022054},
-{{3, 0, 7, {-98,38.3333333333,38.7166666667,39.7833333333,400000,0}, 0,0,0,0, {0,0,0,0,0}},  -89841929.3777815, -82323689.9068513, 90641929.3777815, 98160168.8487116},
-{{3, 0, 7, {-98.5,25.6666666667,26.1666666667,27.8333333333,300000,5000000}, 0,0,0,0, {0,0,0,0,0}},  -64237867.0156485, -46865470.5583462, 64837867.0156485, 82210263.4729508},
-{{3, 0, 7, {-98.5,31.6666666667,32.1333333333,33.9666666667,600000,2000000}, 0,0,0,0, {0,0,0,0,0}},  -74535881.4099808, -63171655.6562241, 75735881.4099808, 87100107.1637374},
-{{3, 0, 7, {-98.5,36.6666666667,38.5666666667,37.2666666667,400000,400000}, 0,0,0,0, {0,0,0,0,0}},  -86225535.4567815, -77888976.4101326, 87025535.4567815, 95362094.5034304},
-{{3, 0, 7, {-99,27.8333333333,28.3833333333,30.2833333333,600000,4000000}, 0,0,0,0, {0,0,0,0,0}},  -67541882.489505, -52618369.9310933, 68741882.489505, 83665395.0479167},
-{{3, 0, 8, {-100,39.8333333333,40,43,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -315923429.002755, -293280656.591766, 319204262.336755, 341847034.747745},
-{{3, 0, 8, {-100,43.8333333333,44.4166666667,45.6833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -353535279.165304, -334137696.37851, 357472279.165304, 376869861.952098},
-{{3, 0, 8, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,2296583.333,9842500}, 0,0,0,0, {0,0,0,0,0}},  -230936729.688494, -188054397.134687, 235529896.354494, 278412228.908301},
-{{3, 0, 8, {-100.3333333333,42.3333333333,42.8333333333,44.4,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -337650764.596392, -317157951.453689, 341587764.596392, 362080577.739096},
-{{3, 0, 8, {-100.5,45.6666666667,46.1833333333,47.4833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -374380983.81883, -356263107.997632, 378317983.81883, 396435859.640027},
-{{3, 0, 8, {-100.5,47,47.4333333333,48.7333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -389705626.72384, -372459203.017216, 393642626.72384, 410889050.430464},
-{{3, 0, 8, {-101.5,34,34.65,36.1833333333,656166.6667,3280833.333}, 0,0,0,0, {0,0,0,0,0}},  -263093031.809627, -230496079.649714, 264405365.143027, 297002317.30294},
-{{3, 0, 8, {-105.5,36.6666666667,37.2333333333,38.4333333333,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -280486193.367387, -255084622.823115, 286486193.367387, 311887763.911659},
-{{3, 0, 8, {-105.5,37.8333333333,38.45,39.75,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -291697764.152969, -267455363.425493, 297697764.152969, 321940164.880445},
-{{3, 0, 8, {-105.5,39.3333333333,39.7166666667,40.7833333333,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}},  -302404577.795946, -279319156.758073, 308404577.795946, 331489998.833818},
-{{3, 0, 8, {-109.5,44.25,45,49,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -376321640.851725, -357755012.743749, 380258640.851725, 398825268.9597},
-{{3, 0, 8, {-111.5,36.6666666667,37.2166666667,38.35,1640416.667,9842500}, 0,0,0,0, {0,0,0,0,0}},  -281416407.11689, -245782173.165005, 284697240.45089, 320331474.402775},
-{{3, 0, 8, {-111.5,38.3333333333,39.0166666667,40.65,1640416.667,6561666.667}, 0,0,0,0, {0,0,0,0,0}},  -299819621.121978, -269234903.392181, 303100454.455978, 333685172.185776},
-{{3, 0, 8, {-111.5,40.3333333333,40.7166666667,41.7833333333,1640416.667,3280833.333}, 0,0,0,0, {0,0,0,0,0}},  -313478791.407906, -287609905.662114, 316759624.741906, 342628510.487699},
-{{3, 0, 8, {-116.25,32.1666666667,32.7833333333,33.8833333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -241914901.382073, -214565573.568852, 255038234.716073, 282387562.529294},
-{{3, 0, 8, {-118,33.5,34.0333333333,35.4666666667,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -252126522.80857, -226399027.876232, 265249856.14257, 290977351.074907},
-{{3, 0, 8, {-119,35.3333333333,36,37.25,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -266786783.091274, -243055769.597688, 279910116.425274, 303641129.91886},
-{{3, 0, 8, {-120.5,36.5,37.0666666667,38.4333333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -276205440.822193, -253614360.110997, 289328774.156193, 311919854.86739},
-{{3, 0, 8, {-120.5,41.6666666667,42.3333333333,44,4921250,0}, 0,0,0,0, {0,0,0,0,0}},  -329872083.788362, -311905291.512634, 339714583.788362, 357681376.064091},
-{{3, 0, 8, {-120.5,43.6666666667,44.3333333333,46,8202083.333,0}, 0,0,0,0, {0,0,0,0,0}},  -348622671.436336, -335441514.411622, 365026838.102336, 378207995.127049},
-{{3, 0, 8, {-120.5,45.3333333333,45.8333333333,47.3333333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -371711613.055591, -353063512.965473, 374992446.389591, 393640546.479709},
-{{3, 0, 8, {-120.8333333333,47,47.5,48.7333333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -390451114.375266, -372886259.072857, 393731947.709266, 411296803.011675},
-{{3, 0, 8, {-122,37.6666666667,38.3333333333,39.8333333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -287981439.562298, -266591098.71221, 301104772.896298, 322495113.746385},
-{{3, 0, 8, {-122,39.3333333333,40,41.6666666667,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -304454503.184074, -284583956.833324, 317577836.518074, 337448382.868824},
-{{3, 0, 8, {-176,51,51.8333333333,53.8333333333,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}},  -451795968.454344, -438512726.047621, 458357635.120344, 471640877.527066},
-{{3, 0, 8, {-66.4333333333,17.8333333333,18.0333333333,18.4333333333,656166.6667,656166.6667}, 0,0,0,0, {0,0,0,0,0}},  -186134070.457016, -122447497.707584, 187446403.790416, 192745440.086188},
-{{3, 0, 8, {-70.5,41,41.2833333333,41.4833333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -314808840.29506, -292525451.628106, 318089673.62906, 340373062.296015},
-{{3, 0, 8, {-71.5,41,41.7166666667,42.6833333333,656166.6667,2460625}, 0,0,0,0, {0,0,0,0,0}},  -324045109.681042, -298691808.220958, 325357443.014442, 350710744.474526},
-{{3, 0, 8, {-72.75,40.8333333333,41.2,41.8666666667,1000000,500000}, 0,0,0,0, {0,0,0,0,0}},  -316944569.715526, -293530823.189916, 318944569.715526, 342358316.241135},
-{{3, 0, 8, {-74,40.1666666667,40.6666666667,41.0333333333,984250,0}, 0,0,0,0, {0,0,0,0,0}},  -310209152.674158, -286710064.82617, 312177652.674158, 335676740.522146},
-{{3, 0, 8, {-77,37.6666666667,38.3,39.45,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}},  -291351709.788081, -266234887.523916, 293976376.454081, 319093198.718245},
-{{3, 0, 8, {-77.75,39.3333333333,39.9333333333,40.9666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -305349045.321406, -282333363.800143, 309286045.321406, 332301726.842669},
-{{3, 0, 8, {-77.75,40.1666666667,40.8833333333,41.95,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -314806739.032704, -292564826.932593, 318743739.032704, 340985651.132814},
-{{3, 0, 8, {-78.5,36.3333333333,36.7666666667,37.9666666667,11482916.67,3280833.333}, 0,0,0,0, {0,0,0,0,0}},  -268023742.686995, -248415180.182438, 290989576.026995, 310598138.531553},
-{{3, 0, 8, {-78.5,37.6666666667,38.0333333333,39.2,11482916.67,6561666.667}, 0,0,0,0, {0,0,0,0,0}},  -278866974.764147, -257212439.065281, 301832808.104147, 323487343.803013},
-{{3, 0, 8, {-79,33.75,34.3333333333,36.1666666667,2000000,0}, 0,0,0,0, {0,0,0,0,0}},  -260462153.393719, -232279190.159991, 264462153.393719, 292645116.627447},
-{{3, 0, 8, {-79.5,38.5,39,40.25,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -297554474.554669, -273808499.095804, 301491474.554669, 325237450.013534},
-{{3, 0, 8, {-81,31.8333333333,32.5,34.8333333333,1999996,0}, 0,0,0,0, {0,0,0,0,0}},  -248788939.145749, -218682047.937282, 252788931.145749, 282895822.354217},
-{{3, 0, 8, {-81,37,37.4833333333,38.8833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -284552805.74176, -259451344.955198, 288489805.74176, 313591266.528322},
-{{3, 0, 8, {-82.5,38,38.7333333333,40.0333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -295320037.416835, -271262116.250003, 299257037.416835, 323314958.583666},
-{{3, 0, 8, {-82.5,39.6666666667,40.4333333333,41.7,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -311338676.851584, -288748657.732733, 315275676.851584, 337865695.970435},
-{{3, 0, 8, {-84.25,37.5,37.9666666667,38.9666666667,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -287379495.376216, -262296519.062331, 290660328.710216, 315743305.024101},
-{{3, 0, 8, {-84.3666666667,41.5,42.1,43.6666666667,13123333.33,0}, 0,0,0,0, {0,0,0,0,0}},  -318673875.371873, -308729120.682423, 344920542.031873, 354865296.721323},
-{{3, 0, 8, {-84.3666666667,43.3166666667,44.1833333333,45.7,19685000,0}, 0,0,0,0, {0,0,0,0,0}},  -334587672.058047, -332679341.779799, 373957672.058047, 375866002.336295},
-{{3, 0, 8, {-84.5,29,29.5833333333,30.75,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -226315297.992256, -191829588.725735, 230252297.992256, 264738007.258777},
-{{3, 0, 8, {-85.75,36.3333333333,36.7333333333,37.9333333333,1640416.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}},  -277585102.740002, -249753532.894032, 280865936.074002, 308697505.919973},
-{{3, 0, 8, {-86,34.3333333333,35.25,36.4166666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -265034010.028484, -237446692.134491, 268971010.028484, 296558327.922477},
-{{3, 0, 8, {-87,44.7833333333,45.4833333333,47.0833333333,26246666.67,0}, 0,0,0,0, {0,0,0,0,0}},  -343541204.825326, -349199842.319061, 396034538.165326, 390375900.67159},
-{{3, 0, 8, {-90,42,42.7333333333,44.0666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -335321962.15511, -314618951.872988, 339258962.15511, 359961972.437231},
-{{3, 0, 8, {-90,43.8333333333,44.25,45.5,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -351554760.427697, -332092962.105268, 355491760.427697, 374953558.750127},
-{{3, 0, 8, {-90,45.1666666667,45.5666666667,46.7666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -366448607.697906, -347928534.795579, 370385607.697906, 388905680.600232},
-{{3, 0, 8, {-91.3333333333,25.5,26.1666666667,27.8333333333,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}},  -208457152.034173, -170101376.61938, 215018818.700173, 253374594.114967},
-{{3, 0, 8, {-91.3333333333,28.5,29.3,30.7,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}},  -224037510.159723, -190501887.900234, 230599176.825723, 264134799.085212},
-{{3, 0, 8, {-92,32.6666666667,33.3,34.7666666667,1312333.333,1312333.333}, 0,0,0,0, {0,0,0,0,0}},  -252114965.182788, -220603925.09152, 254739631.848788, 286250671.940057},
-{{3, 0, 8, {-92,34.3333333333,34.9333333333,36.2333333333,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}},  -263732072.537265, -235312197.62441, 266356739.203265, 294776614.11612},
-{{3, 0, 8, {-92.5,30.5,31.1666666667,32.6666666667,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}},  -235705523.16837, -204846795.365055, 242267189.83437, 273125917.637685},
-{{3, 0, 8, {-93.1,46.5,47.0333333333,48.6333333333,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}},  -385933858.012454, -368759635.557233, 391183191.346454, 408357413.801674},
-{{3, 0, 8, {-93.5,40,40.6166666667,41.7833333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}},  -312982803.048606, -290249762.839575, 316263636.382606, 338996676.591636},
-{{3, 0, 8, {-93.5,41.5,42.0666666667,43.2666666667,4921250,3280833.333}, 0,0,0,0, {0,0,0,0,0}},  -324609611.161762, -303088197.425932, 334452111.161762, 355973524.897592},
-{{3, 0, 8, {-94,43,43.7833333333,45.2166666667,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}},  -346690823.003483, -327113674.332095, 351940156.337483, 371517305.008871},
-{{3, 0, 8, {-94.25,45,45.6166666667,47.05,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}},  -367757111.594128, -349560842.397585, 373006444.928128, 391202714.124671},
-{{3, 0, 8, {-98,33.3333333333,33.9333333333,35.2333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -255481720.407597, -226612868.978264, 259418720.407597, 288287571.836931},
-{{3, 0, 8, {-98,35,35.5666666667,36.7666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}},  -267677707.348155, -240564047.908157, 271614707.348155, 298728366.788152},
-{{3, 0, 8, {-98,38.3333333333,38.7166666667,39.7833333333,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}},  -294756396.633938, -270090305.969395, 297381063.299938, 322047153.964481},
-{{3, 0, 8, {-98.5,25.6666666667,26.1666666667,27.8333333333,984250,16404166.67}, 0,0,0,0, {0,0,0,0,0}},  -210753735.367173, -153757797.986841, 212722235.367173, 269718172.747506},
-{{3, 0, 8, {-98.5,31.6666666667,32.1333333333,33.9666666667,1968500,6561666.667}, 0,0,0,0, {0,0,0,0,0}},  -244539804.259245, -207255673.598462, 248476804.259245, 285760934.920029},
-{{3, 0, 8, {-98.5,36.6666666667,38.5666666667,37.2666666667,1312333.333,1312333.333}, 0,0,0,0, {0,0,0,0,0}},  -282891610.911457, -255540750.10591, 285516277.577457, 312867138.383004},
-{{3, 0, 8, {-99,27.8333333333,28.3833333333,30.2833333333,1968500,13123333.33}, 0,0,0,0, {0,0,0,0,0}},  -221593659.467651, -172632102.018929, 225530659.467651, 274492216.916373},
-{{3, 2, 7, {135,-24,-18,-36,0,0}, 0,-133,-48,148, {0,0,0,0,0}},  -63926410.6698201, -76575533.9276959, 63926410.6698201, 51277287.4119443},
-{{3, 2, 7, {145,-37,-36,-38,2500000,4500000}, 0,-133,-48,148, {0,0,0,0,0}},  -81753864.458242, -88226525.7784545, 86753864.458242, 80281203.1380295},
-{{3, 2, 7, {147,0,-32.666,-35.333,1000000,10000000}, 0,-133,-48,148, {0,0,0,0,0}},  -76161714.4889037, -80605291.2154594, 78161714.4889037, 73718137.7623481},
-{{3, 28, 7, {23,-23,-18,-32,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -61566719.246568, -72414618.8198515, 61566719.246568, 47796808.4991836},
-{{3, 29, 0, {110,10,25,40,0,0}, 0,0,0,0, {0,0,0,0,0}},  -45730.409093877, -38000.6689484435, 45730.409093877, 53460.1492393104},
-{{3, 29, 0, {132.5,-10,-21.5,-33.5,0,0}, 0,0,0,0, {0,0,0,0,0}},  -40383.2188994685, -49161.7062224971, 40383.2188994685, 31604.73157644},
-{{3, 29, 0, {25,35,40,65,0,0}, 0,0,0,0, {0,0,0,0,0}},  -84908.0213013157, -80759.383210806, 84908.0213013157, 89056.6593918254},
-{{3, 29, 0, {47.5,25,15,35,0,0}, 0,0,0,0, {0,0,0,0,0}},  -38011.5438463059, -29679.737315404, 38011.5438463059, 46069.8166618704},
-{{3, 29, 0, {95,40,20,60,0,0}, 0,0,0,0, {0,0,0,0,0}},  -55750.1705370063, -51403.1783693689, 55750.1705370063, 60097.1627046438},
-{{3, 30, 7, {0,42.165,41.560387840948,42.76766346965,234.358,185861.369}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -98847613.927946, -91608686.7437833, 98848082.643946, 106087009.828109},
-{{3, 30, 7, {0,42.165,41.560387840948,42.76766346965,234.358,4185861.369}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -98847613.927946, -87608686.7437833, 98848082.643946, 110087009.828109},
-{{3, 30, 7, {0,44.1,43.199291275544,44.996093814511,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -104503824.398662, -98311919.3139696, 105703824.398662, 111895729.483354},
-{{3, 30, 7, {0,44.1,43.199291275544,44.996093814511,600000,3200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -104503824.398662, -95311919.3139696, 105703824.398662, 114895729.483354},
-{{3, 30, 7, {0,46.8,45.898918964419,47.696014502038,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -113967455.416715, -108367759.648713, 115167455.416715, 120767151.184716},
-{{3, 30, 7, {0,46.8,45.898918964419,47.696014502038,600000,2200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -113967455.416715, -106367759.648713, 115167455.416715, 122767151.184716},
-{{3, 30, 7, {0,49.5,48.598522847174,50.395911631678,600000,1200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -124264257.877732, -118206641.203686, 125464257.877732, 131521874.551778},
-{{3, 30, 7, {0,49.5,48.598522847174,50.395911631678,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}},  -124264257.877732, -119206641.203686, 125464257.877732, 130521874.551778},
-{{3, 4, 7, {17,29.77930555,42,56,2679984.29,-484330}, 0,-87,-98,-121, {0,0,0,0,0}},  -119981631.268354, -115489555.67494, 125341599.848354, 129833675.441769},
-{{3, 4, 7, {4.3569397222,90,49.8333333333,51.1666666667,150000.01256,5400088.4378}, 0,81,120,129, {0,0,0,0,0}},  -128761663.907607, -123511575.482367, 129061663.932727, 134311752.357967},
-{{3, 4, 7, {4.367975,90,49.8333333333,51.1666666667,150000,5400000}, 0,81,120,129, {0,0,0,0,0}},  -128761663.920167, -123511663.920167, 129061663.920167, 134311663.920167},
-{{3, 6, 7, {23,-23,-18,-32,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -61564419.064164, -72412828.2264313, 61564419.064164, 47794154.9885407},
-{{3, 7, 7, {-68.5,44,46,60,0.99999912,0}, 0,-10,158,187, {0,0,0,0,0}},  -139220351.696306, -133454155.398424, 139220353.696304, 144986549.994186},
-{{3, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -89717066.7318629, -80920710.9207624, 89717066.7318629, 98513422.5429635},
-{{3, 7, 7, {-96,23,33,45,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -89295530.2887796, -79679575.056002, 89295530.2887796, 98911485.5215573},
-{{3, 7, 7, {-96,39,33,45,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -89295530.2887796, -81466209.2421514, 89295530.2887796, 97124851.3354078},
-{{3, 7, 8, {-100,41.3333333333,41.85,42.8166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -324055199.858072, -302686222.906259, 328055199.858072, 349424176.809884},
-{{3, 7, 8, {-100,43.8333333333,44.4166666667,45.6833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -353482329.11673, -334115632.201571, 357482329.11673, 376849026.031889},
-{{3, 7, 8, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -231224626.213763, -197887504.402976, 235224626.213763, 268561748.024549},
-{{3, 7, 8, {-100.3333333333,42.3333333333,42.8333333333,44.4,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -337599541.873847, -317137605.090357, 341599541.873847, 362061478.657338},
-{{3, 7, 8, {-100.5,45.6666666667,46.1833333333,47.4833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -374325734.927512, -356238757.711242, 378325734.927512, 396412712.143782},
-{{3, 7, 8, {-100.5,47,47.4333333333,48.7333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -389648664.421659, -372433148.680405, 393648664.421659, 410864180.162913},
-{{3, 7, 8, {-101.5,34,34.65,36.1833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -261737418.19268, -233764458.26155, 265737418.19268, 293710378.12381},
-{{3, 7, 8, {-105.5,36.6666666667,37.2333333333,38.4333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -281472391.565436, -256070159.37991, 285472391.565436, 310874623.750962},
-{{3, 7, 8, {-105.5,37.8333333333,38.45,39.75,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -292682801.597057, -268439748.039304, 296682801.597057, 320925855.154811},
-{{3, 7, 8, {-105.5,39.3333333333,39.7166666667,40.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -303388496.172414, -280302427.035458, 307388496.172414, 330474565.30937},
-{{3, 7, 8, {-109.5,44,44.8666666667,46.4,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -360164256.91475, -341067435.395783, 364164256.91475, 383261078.433716},
-{{3, 7, 8, {-109.5,45.8333333333,46.45,47.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -378353013.025643, -360433206.501952, 382353013.025643, 400272819.549334},
-{{3, 7, 8, {-109.5,47,47.85,48.7166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -392158606.473501, -375000733.125562, 396158606.473501, 413316479.821439},
-{{3, 7, 8, {-111.5,36.6666666667,37.2166666667,38.35,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -281043066.114894, -255610253.091634, 285043066.114894, 310475879.138154},
-{{3, 7, 8, {-111.5,38.3333333333,39.0166666667,40.65,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -299444370.803389, -275780256.64851, 303444370.803389, 327108484.958269},
-{{3, 7, 8, {-111.5,40.3333333333,40.7166666667,41.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -313102102.853289, -290872992.274509, 317102102.853289, 339331213.432069},
-{{3, 7, 8, {-116.25,32.1666666667,32.7833333333,33.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -246466336.059689, -216195067.142672, 250466336.059689, 280737604.976705},
-{{3, 7, 8, {-118,33.5,34.0333333333,35.4666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -256676923.297906, -228027497.817793, 260676923.297906, 289326348.778019},
-{{3, 7, 8, {-118.3333333333,34.1333333333,33.8666666667,34.4166666667,4186692.58,4160926.74}, 0,-8,160,176, {0,0,0,0,0}},  -250023955.862257, -219155253.035527, 258397341.022257, 289266043.848988},
-{{3, 7, 8, {-119,35.3333333333,36,37.25,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -271335689.379641, -244682757.78249, 275335689.379641, 301988620.976793},
-{{3, 7, 8, {-120.5,36.5,37.0666666667,38.4333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -280753380.155715, -255240388.034962, 284753380.155715, 310266372.276468},
-{{3, 7, 8, {-120.5,41.6666666667,42.3333333333,44,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -332774131.475311, -311885463.700041, 336774131.475311, 357662799.250581},
-{{3, 7, 8, {-120.5,43.6666666667,44.3333333333,46,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -354803161.418059, -335419308.868092, 358803161.418059, 378187013.968026},
-{{3, 7, 8, {-120.5,45.3333333333,45.8333333333,47.3333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -371328614.306844, -353039494.544633, 375328614.306844, 393617734.069055},
-{{3, 7, 8, {-120.8333333333,47,47.5,48.7333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -390066021.607763, -372860157.907014, 394066021.607763, 411271885.308512},
-{{3, 7, 8, {-122,37.6666666667,38.3333333333,39.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -292528160.248962, -268215917.695861, 296528160.248962, 320840402.802063},
-{{3, 7, 8, {-122,39.3333333333,40,41.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -308999499.517601, -286207062.905244, 312999499.517601, 335791936.129957},
-{{3, 7, 8, {-176,51,51.8333333333,53.8333333333,3000000,0}, 0,-5,135,172, {0,0,0,0,0}},  -452044058.020189, -438479429.247576, 458044058.020189, 471608686.792802},
-{{3, 7, 8, {-66.4333333333,18.4333333333,18.0333333333,18.4333333333,500000,0}, 0,-8,160,176, {0,0,0,0,0}},  -186287246.382945, -123317624.596919, 187287246.382945, 191870266.743549},
-{{3, 7, 8, {-66.4333333333,18.4333333333,18.0333333333,18.4333333333,500000,100000}, 0,-8,160,176, {0,0,0,0,0}},  -186287246.382945, -123217624.596919, 187287246.382945, 191970266.743549},
-{{3, 7, 8, {-70.5,41,41.2833333333,41.4833333333,800000,0}, 0,-8,160,176, {0,0,0,0,0}},  -315632009.889084, -292507560.721895, 317232009.889084, 340356459.056272},
-{{3, 7, 8, {-71.5,41,41.7166666667,42.6833333333,600000,0}, 0,-8,160,176, {0,0,0,0,0}},  -324083153.067583, -301133676.4023, 325283153.067583, 348232629.732865},
-{{3, 7, 8, {-72.75,40.8333333333,41.2,41.8666666667,600000,0}, 0,-8,160,176, {0,0,0,0,0}},  -317327164.550983, -294012777.09286, 318527164.550983, 341841552.009105},
-{{3, 7, 8, {-74,40.5,40.6666666667,41.0333333333,2000000,100000}, 0,-8,160,176, {0,0,0,0,0}},  -309176711.160841, -286714165.719965, 313176711.160841, 335639256.601717},
-{{3, 7, 8, {-77,37.8333333333,38.3,39.45,800000,0}, 0,-8,160,176, {0,0,0,0,0}},  -291849291.606495, -266280179.434122, 293449291.606495, 319018403.778868},
-{{3, 7, 8, {-77.75,39.3333333333,39.9333333333,40.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -305301262.728919, -282316435.790654, 309301262.728919, 332286089.667183},
-{{3, 7, 8, {-77.75,40.1666666667,40.8833333333,41.95,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -314757958.485081, -292546908.072089, 318757958.485081, 340969008.898072},
-{{3, 7, 8, {-78.5,36.3333333333,36.7666666667,37.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -277493267.234049, -251681955.591517, 281493267.234049, 307304578.87658},
-{{3, 7, 8, {-78.5,37.6666666667,38.0333333333,39.2,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -288335380.041045, -263758935.876341, 292335380.041045, 316911824.205748},
-{{3, 7, 8, {-79,33.75,34.3333333333,36.1666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -260450504.74125, -232266866.952514, 264450504.74125, 292634142.529987},
-{{3, 7, 8, {-79.5,38.5,39,40.25,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -297507509.009345, -273792382.933741, 301507509.009345, 325222635.08495},
-{{3, 7, 8, {-81,31.8333333333,32.3333333333,33.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -244165860.608621, -213488972.345334, 248165860.608621, 278842748.871908},
-{{3, 7, 8, {-81,33,33.7666666667,34.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -253843797.715595, -224716073.21255, 257843797.715595, 286971522.21864},
-{{3, 7, 8, {-81,37,37.4833333333,38.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -284507191.09272, -259436571.044567, 288507191.09272, 313577811.140872},
-{{3, 7, 8, {-82.5,38,38.7333333333,40.0333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -295273305.101978, -271246233.791215, 299273305.101978, 323300376.41274},
-{{3, 7, 8, {-82.5,39.6666666667,40.4333333333,41.7,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -311290263.635938, -288731104.977908, 315290263.635938, 337849422.293968},
-{{3, 7, 8, {-84.25,37.5,37.9666666667,38.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -287005538.125454, -262281485.830837, 291005538.125454, 315729590.42007},
-{{3, 7, 8, {-84.5,29,29.5833333333,30.75,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -226275614.557084, -191820690.371176, 230275614.557084, 264730538.742992},
-{{3, 7, 8, {-85.75,36.3333333333,36.7333333333,37.9333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -277212156.180922, -251379920.019457, 281212156.180922, 307044392.342388},
-{{3, 7, 8, {-86,34.6666666667,35.25,36.4166666667,2000000,100000}, 0,-8,160,176, {0,0,0,0,0}},  -264990397.68906, -237455247.728469, 268990397.68906, 296525547.64965},
-{{3, 7, 8, {-90,42,42.7333333333,44.0666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -335270989.964058, -314598855.147961, 339270989.964058, 359943124.780154},
-{{3, 7, 8, {-90,43.8333333333,44.25,45.5,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -351502026.802048, -332071112.456575, 355502026.802048, 374932941.147521},
-{{3, 7, 8, {-90,45.1666666667,45.5666666667,46.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -366394237.721428, -347905058.027747, 370394237.721428, 388883417.41511},
-{{3, 7, 8, {-91.3333333333,25.6666666667,26.1666666667,27.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -209731525.091816, -170154762.702282, 213731525.091816, 253308287.48135},
-{{3, 7, 8, {-91.3333333333,28.6666666667,29.3,30.67,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -225224715.171064, -190451550.801895, 229224715.171064, 263997879.540232},
-{{3, 7, 8, {-92,32.6666666667,33.3,34.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -251416565.855924, -221904841.787545, 255416565.855924, 284928289.924303},
-{{3, 7, 8, {-92,34.3333333333,34.9333333333,36.2333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -263032493.27188, -235299609.879708, 267032493.27188, 294765376.664052},
-{{3, 7, 8, {-92.5,30.6666666667,31.1666666667,32.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -236977085.666136, -204897455.65052, 240977085.666136, 273056715.681752},
-{{3, 7, 8, {-93.1,46.5,47.0333333333,48.6333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -386533413.283953, -369062013.990686, 390533413.283953, 408004812.577219},
-{{3, 7, 8, {-93.5,40,40.6166666667,41.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -312606167.17083, -290232070.277002, 316606167.17083, 338980264.064658},
-{{3, 7, 8, {-93.5,41.5,42.0666666667,43.2666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -327512222.250473, -306349761.225561, 331512222.250473, 352674683.275385},
-{{3, 7, 8, {-94,43,43.7833333333,45.2166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -347294715.331617, -327420366.588323, 351294715.331617, 371169064.074911},
-{{3, 7, 8, {-94.25,45,45.6166666667,47.05,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -368358691.706647, -349865234.580916, 372358691.706647, 390852148.832379},
-{{3, 7, 8, {-97.5,31.6666666667,32.1333333333,33.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -244498272.760526, -213806618.399239, 248498272.760526, 279189927.121813},
-{{3, 7, 8, {-98,33.3333333333,33.9333333333,35.2333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -255439079.607865, -226601046.512961, 259439079.607865, 288277112.70277},
-{{3, 7, 8, {-98,35,35.5666666667,36.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -267633825.34702, -240550993.657801, 271633825.34702, 298716657.03624},
-{{3, 7, 8, {-98,38.3333333333,38.7166666667,39.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -294053624.246013, -270074545.620282, 298053624.246013, 322032702.871744},
-{{3, 7, 8, {-98.5,25.6666666667,26.1666666667,27.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -209731525.091816, -170154762.702282, 213731525.091816, 253308287.48135},
-{{3, 7, 8, {-98.5,36.6666666667,38.5666666667,37.2666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -282190068.629093, -256838547.449771, 286190068.629093, 311541589.808415},
-{{3, 7, 8, {-99,27.8333333333,28.3833333333,30.2833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -221554461.124832, -185747019.927933, 225554461.124832, 261361902.321731},
-{{3, 7, 8, {-99.5,39.6666666667,40.2833333333,41.7166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -310633016.402964, -288042234.606454, 314633016.402964, 337223798.199475},
-{{3, 8, 8, {-84.3333333333,41.5,42.1,43.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -329791001.829521, -308721404.605132, 333791001.829521, 354860599.053909},
-{{3, 8, 8, {-84.3333333333,43.3166666667,44.1833333333,45.7,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -352264889.757925, -332670121.355321, 356264889.757925, 375859658.160529},
-{{3, 8, 8, {-87,44.7833333333,45.4833333333,47.0833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}},  -367778976.228709, -349189556.133667, 371778976.228709, 390368396.32375},
-{{4, 7, 7, {0,90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -9020145.99449487, -9020145.99449487, 9020145.99449487, 9020145.99449487},
-{{6, 2, 1, {134,-90,-18,-36,0,0}, 0,-134,-48,149, {0,0,0,0,0}},  -25412.1329074842, -30820.2630332478, 25412.1329074842, 20004.0027817205},
-{{6, 2, 1, {147,-32.5,-29.5,-35.5,0,0}, 0,-134,-48,149, {0,0,0,0,0}},  -23611.4811992266, -33623.6505009443, 23611.4811992266, 13599.3118975089},
-{{6, 2, 7, {134,-90,-18,-36,0,0}, 0,-134,-48,149, {0,0,0,0,0}},  -25412132.9074842, -30820263.0332478, 25412132.9074842, 20004002.7817205},
-{{6, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -21729866.6858831, -12546277.7889483, 21729866.6858831, 30913455.5828178},
-{{6, 7, 7, {-96,23,29.5,45.5,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -22421877.8189369, -12546277.7889483, 22421877.8189369, 32297477.8489255},
-{{7, 0, 7, {-133.6666666667,57,-36.8698976458,0.9999,5000000,-5000000}, 0,0,0,0, {0,0,0,0,0}},  715546.220413176, -14325907.9924165, 9284453.77958682, 4325907.99241646},
-{{7, 0, 8, {-133.6666666667,57,-36.8698976458,0.9999,16404166.67,-16404166.67}, 0,0,0,0, {0,0,0,0,0}},  2347587.89480556, -47000916.4751197, 30460745.4451944, 14192583.1351197},
-{{7, 7, 8, {-133.6666666667,57,-36.8698976458,0.9999,16404166.6667,-16404166.6667}, 0,-5,135,172, {0,0,0,0,0}},  2347270.72925546, -47001747.5537593, 30461062.6041445, 14193414.2203593},
-{{8, 0, 3, {-110.1666666667,31,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26361414.1707081, -44066918.5002725, 27761414.1707081, 21556214.9175316},
-{{8, 0, 3, {-111.9166666667,31,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26361414.1707081, -44066918.5002725, 27761414.1707081, 21556214.9175316},
-{{8, 0, 3, {-113.75,31,0.9999333333,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26362316.3071587, -44068387.5429912, 27762316.3071587, 21556933.5291715},
-{{8, 0, 7, {-104.3333333333,31,0.9999090909,165000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8083394.03137459, -13431718.8763978, 8413394.03137459, 6570394.04308942},
-{{8, 0, 7, {-105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-105.1666666667,40.5,0.9999375,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048628.38213008, -14486109.042394, 8448628.38213009, 5516572.17078242},
-{{8, 0, 7, {-106.25,31,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923183, -13431596.758883, 8748319.03923182, 6570334.30686364},
-{{8, 0, 7, {-107.3333333333,40.5,0.9999375,400000,100000,0}, 0,0,0,0, {0,0,0,0,0}},  -7848628.38213008, -14386109.042394, 8648628.38213008, 5616572.17078242},
-{{8, 0, 7, {-107.8333333333,31,0.9999166667,830000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7418456.52523935, -13431820.641665, 9078456.52523936, 6570443.82360611},
-{{8, 0, 7, {-108.75,40.5,0.9999375,600000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7648628.38213009, -14486109.042394, 8848628.38213009, 5516572.17078242},
-{{8, 0, 7, {-110.0833333333,40.5,0.9999375,800000,100000,0}, 0,0,0,0, {0,0,0,0,0}},  -7448628.38213009, -14386109.042394, 9048628.38213008, 5616572.17078242},
-{{8, 0, 7, {-110.1666666667,31,0.9999,213360,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8034959.03923183, -13431596.758883, 8461679.03923182, 6570334.30686364},
-{{8, 0, 7, {-111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-111.9166666667,31,0.9999,213360,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8034959.03923183, -13431596.758883, 8461679.03923182, 6570334.30686364},
-{{8, 0, 7, {-112.1666666667,41.6666666667,0.9999473684,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048709.78798227, -14615809.9655587, 8448709.78798228, 5387068.65441496},
-{{8, 0, 7, {-113.75,31,0.9999333333,213360,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8035234.01042198, -13432044.5231037, 8461954.01042198, 6570553.33969148},
-{{8, 0, 7, {-114,41.6666666667,0.9999473684,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748709.78798228, -14615809.9655587, 8748709.78798228, 5387068.65441496},
-{{8, 0, 7, {-115.5833333333,34.75,0.9999,200000,8000000,0}, 0,0,0,0, {0,0,0,0,0}},  -8048319.03923182, -5847439.17666561, 8448319.03923183, 14154491.8890811},
-{{8, 0, 7, {-115.75,41.6666666667,0.9999333333,800000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7448594.01042197, -14615604.8204071, 9048594.01042198, 5386993.0423881},
-{{8, 0, 7, {-116.6666666667,34.75,0.9999,500000,6000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923183, -7847439.17666561, 8748319.03923183, 12154491.8890811},
-{{8, 0, 7, {-117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-118.5833333333,34.75,0.9999,800000,4000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7448319.03923183, -9847439.17666561, 9048319.03923182, 10154491.8890811},
-{{8, 0, 7, {-123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
-{{8, 0, 7, {-142,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-146,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-150,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-154,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-155.5,18.8333333333,0.9999666667,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748868.98243704, -12084782.4965247, 8748868.98243704, 7918482.16531935},
-{{8, 0, 7, {-156.6666666667,20.3333333333,0.9999666667,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748868.98243704, -12250825.7354572, 8748868.98243703, 7752438.92638694},
-{{8, 0, 7, {-158,21.1666666667,0.99999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7749061.46218765, -12343372.1823083, 8749061.46218765, 7660359.23726966},
-{{8, 0, 7, {-158,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923182, -15986282.9700963, 8748319.03923182, 4015648.0956504},
-{{8, 0, 7, {-159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-159.5,21.8333333333,0.99999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7749061.46218765, -12417187.1755718, 8749061.46218765, 7586544.24400615},
-{{8, 0, 7, {-160.1666666667,21.6666666667,1,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7749143.95362718, -12398856.862762, 8749143.95362719, 7605074.59613055},
-{{8, 0, 7, {-162,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
-{{8, 0, 7, {-166,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-170,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
-{{8, 0, 7, {-171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-2,49,0.9996012717,400000,-100000,0}, 0,0,0,0, {0,0,0,0,0}},  -7845854.7864821, -15525440.3489618, 8645854.7864821, 4470514.97634689},
-{{8, 0, 7, {-21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-55.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923183, -10000965.5328733, 8553119.03923183, 10000965.5328733},
-{{8, 0, 7, {-57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-58.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
-{{8, 0, 7, {-61.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
-{{8, 0, 7, {-63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-64.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923182, -10000965.5328733, 8553119.03923182, 10000965.5328733},
-{{8, 0, 7, {-67.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
-{{8, 0, 7, {-68.5,43.6666666667,0.9999,300000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7948319.03923182, -14837267.8945768, 8548319.03923182, 5164663.17116993},
-{{8, 0, 7, {-69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-70.1666666667,42.8333333333,0.9999666667,900000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7348868.98243704, -14745678.889568, 9148868.98243704, 5257585.77227607},
-{{8, 0, 7, {-70.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
-{{8, 0, 7, {-71.5,41.0833333333,0.99999375,100000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8149092.39647748, -14551702.6314571, 8349092.39647748, 5452103.80286384},
-{{8, 0, 7, {-71.6666666667,42.5,0.9999666667,300000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7948868.98243704, -14708651.3754574, 8548868.98243704, 5294613.28638668},
-{{8, 0, 7, {-72.5,42.5,0.9999642857,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748849.34122529, -14708616.3529911, 8748849.34122528, 5294600.67949221},
-{{8, 0, 7, {-73.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
-{{8, 0, 7, {-74.5,38.8333333333,0.9999,150000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8098319.03923183, -14300537.2022438, 8398319.03923182, 5701393.86350293},
-{{8, 0, 7, {-74.5,38.8333333334,0.9999,150000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8098319.03923183, -14300537.2022549, 8398319.03923182, 5701393.86349183},
-{{8, 0, 7, {-75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-75.4166666667,38,0.999995,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8049102.70790742, -14209392.7012779, 8449102.70790742, 5794438.73795742},
-{{8, 0, 7, {-76.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
-{{8, 0, 7, {-76.5833333333,40,0.9999375,250000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7998628.38213008, -14430592.791401, 8498628.38213008, 5572088.42177536},
-{{8, 0, 7, {-78.5833333333,40,0.9999375,350000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7898628.38213008, -14430592.791401, 8598628.38213008, 5572088.42177536},
-{{8, 0, 7, {-79.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
-{{8, 0, 7, {-81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-81,24.3333333333,0.9999411765,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048658.71010783, -12693427.8789688, 8448658.71010783, 7309326.87866157},
-{{8, 0, 7, {-82,24.3333333333,0.9999411765,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048658.71010783, -12693427.8789688, 8448658.71010783, 7309326.87866157},
-{{8, 0, 7, {-82.1666666667,30,0.9999,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048319.03923182, -13320746.9194058, 8448319.03923183, 6681184.14634087},
-{{8, 0, 7, {-84.1666666667,30,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7548319.03923183, -13320746.9194058, 8948319.03923182, 6681184.14634087},
-{{8, 0, 7, {-85.6666666667,37.5,0.9999666667,100000,250000,0}, 0,0,0,0, {0,0,0,0,0}},  -8148868.98243704, -13903496.0736175, 8348868.98243704, 6099768.58822661},
-{{8, 0, 7, {-85.8333333333,30.5,0.99996,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048813.98786904, -13376972.3620314, 8448813.98786904, 6626158.9396028},
-{{8, 0, 7, {-87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-87.0833333333,37.5,0.9999666667,900000,250000,0}, 0,0,0,0, {0,0,0,0,0}},  -7348868.98243704, -13903496.0736175, 9148868.98243703, 6099768.58822661},
-{{8, 0, 7, {-87.5,30,0.9999333333,600000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7648594.01042198, -13321190.988266, 8848594.01042197, 6681406.87452919},
-{{8, 0, 7, {-88.3333333333,36.6666666667,0.999975,300000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7948937.72502834, -14061133.6597386, 8548937.72502835, 5942297.70086748},
-{{8, 0, 7, {-88.8333333333,29.5,0.99995,300000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7948731.4964295, -13265991.6727511, 8548731.4964295, 6736939.58956854},
-{{8, 0, 7, {-9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {-90.1666666667,36.6666666667,0.9999411765,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7548658.71010783, -14060658.0510941, 8948658.71010783, 5942096.70653633},
-{{8, 0, 7, {-90.3333333333,29.5,0.99995,700000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7548731.49642951, -13265991.6727511, 8948731.4964295, 6736939.58956854},
-{{8, 0, 7, {-90.5,35.8333333333,0.9999333333,250000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7998594.01042198, -13968084.2221719, 8498594.01042197, 6034513.64062328},
-{{8, 0, 7, {-92.5,35.8333333333,0.9999333333,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748594.01042198, -13968084.2221719, 8748594.01042197, 6034513.64062328},
-{{8, 0, 7, {-93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
-{{8, 0, 7, {-94.5,36.1666666667,0.9999411765,850000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7398658.71010783, -14005177.9421902, 9098658.71010783, 5997576.81544022},
-{{8, 0, 7, {-99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
-{{8, 0, 7, {111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {12,0,0.99995,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7748731.4964295, -10001465.6311598, 8748731.4964295, 10001465.6311598},
-{{8, 0, 7, {123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
-{{8, 0, 7, {129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, 2035.0568454858, 8745844.29604573, 19997964.9431545},
-{{8, 0, 7, {141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
-{{8, 0, 7, {15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {15,0,1,900000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7349143.95362719, -10001965.7294463, 9149143.95362719, 10001965.7294463},
-{{8, 0, 7, {153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604573, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 7, {9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
-{{8, 0, 7, {9.5,0,0.99995,200000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8048731.4964295, -10001465.6311598, 8448731.49642951, 10001465.6311598},
-{{8, 0, 7, {99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
-{{8, 0, 8, {-104.3333333333,31,0.9999090909,541337.5,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26520268.5846015, -44067231.0136484, 27602943.5846015, 21556367.7897025},
-{{8, 0, 8, {-105.1666666667,40.5,0.9999375,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26406208.2836718, -47526509.4165876, 27718541.6170718, 18098953.863642},
-{{8, 0, 8, {-106.25,31,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808798, -44066830.3664355, 28701776.7148797, 21556171.8051018},
-{{8, 0, 8, {-107.3333333333,40.5,0.9999375,1312333.333,328083.3333,0}, 0,0,0,0, {0,0,0,0,0}},  -25750041.6173718, -47198426.0832876, 28374708.2833718, 18427037.196942},
-{{8, 0, 8, {-107.8333333333,31,0.9999166667,2723091.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24338719.4495561, -44067564.8885294, 29784902.7835561, 21556531.111281},
-{{8, 0, 8, {-108.75,40.5,0.9999375,1968500,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25093874.9503718, -47526509.4165876, 29030874.9503718, 18098953.863642},
-{{8, 0, 8, {-110.0833333333,40.5,0.9999375,2624666.667,328083.3333,0}, 0,0,0,0, {0,0,0,0,0}},  -24437708.2833718, -47198426.0832876, 29687041.6173718, 18427037.196942},
-{{8, 0, 8, {-110.1666666667,31,0.9999,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26361361.4478798, -44066830.3664355, 27761358.6478797, 21556171.8051018},
-{{8, 0, 8, {-111.9166666667,31,0.9999,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26361361.4478797, -44066830.3664355, 27761358.6478797, 21556171.8051018},
-{{8, 0, 8, {-112.1666666667,41.6666666667,0.9999473684,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26406475.3627052, -47952036.5286703, 27718808.6961052, 17674074.4103597},
-{{8, 0, 8, {-113.75,31,0.9999333333,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26362263.5825261, -44068299.4062161, 27762260.7825261, 21556890.4153045},
-{{8, 0, 8, {-114,41.6666666667,0.9999473684,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25422225.3624052, -47952036.5286703, 28703058.6964052, 17674074.4103597},
-{{8, 0, 8, {-115.5833333333,34.75,0.9999,656166.6667,26246666.67,0}, 0,0,0,0, {0,0,0,0,0}},  -26405193.3811797, -19184473.3621104, 27717526.7145797, 46438528.8094268},
-{{8, 0, 8, {-115.75,41.6666666667,0.9999333333,2624666.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24437595.5155261, -47951363.4816189, 29686928.8495261, 17673826.3399016},
-{{8, 0, 8, {-116.6666666667,34.75,0.9999,1640416.667,19685000,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -25746140.0321104, 28701776.7148797, 39876862.1394268},
-{{8, 0, 8, {-118.5833333333,34.75,0.9999,2624666.667,13123333.33,0}, 0,0,0,0, {0,0,0,0,0}},  -24436693.3808797, -32307806.7021104, 29686026.7148797, 33315195.4694268},
-{{8, 0, 8, {-142,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-146,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-150,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-154,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-155.5,18.8333333333,0.9999666667,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25422747.6528788, -39648157.2406816, 28703580.9868788, 25979220.2373852},
-{{8, 0, 8, {-156.6666666667,20.3333333333,0.9999666667,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25422747.6528789, -40192917.4337457, 28703580.9868788, 25434460.0443211},
-{{8, 0, 8, {-158,21.1666666667,0.99999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25423379.1468606, -40496546.9014566, 28704212.4808606, 25132361.9309422},
-{{8, 0, 8, {-158,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-159.5,21.8333333333,0.99999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25423379.1468606, -40738721.5918553, 28704212.4808606, 24890187.2405435},
-{{8, 0, 8, {-160.1666666667,21.6666666667,1,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25423649.7875252, -40678582.8905784, 28704483.1215252, 24950982.2374716},
-{{8, 0, 8, {-162,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-166,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-170,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
-{{8, 0, 8, {-68.5,43.6666666667,0.9999,984250,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26077110.0478797, -48678603.0841239, 28045610.0478797, 16944399.0874133},
-{{8, 0, 8, {-70.1666666667,42.8333333333,0.9999666667,2952750,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24110414.3198788, -48378114.8235244, 30015914.3198788, 17249262.6545424},
-{{8, 0, 8, {-71.5,41.0833333333,0.99999375,328083.3333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26735813.9708099, -47741711.0500389, 27391980.6374099, 17887443.8932291},
-{{8, 0, 8, {-71.6666666667,42.5,0.9999666667,984250,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26078914.3198788, -48256633.7209798, 28047414.3198788, 17370743.757087},
-{{8, 0, 8, {-72.5,42.5,0.9999642857,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25422683.2133366, -48256518.8181048, 28703516.5473366, 17370702.3959674},
-{{8, 0, 8, {-74.5,38.8333333333,0.9999,492125,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26569235.0478797, -46917679.1376948, 27553485.0478797, 18705323.0338425},
-{{8, 0, 8, {-74.5,38.8333333334,0.9999,492125,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26569235.0478797, -46917679.1377312, 27553485.0478797, 18705323.0338061},
-{{8, 0, 8, {-75.4166666667,38,0.999995,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26407764.4674929, -46618649.2207758, 27720097.8008929, 19010587.7594486},
-{{8, 0, 8, {-76.5833333333,40,0.9999375,820208.3333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26242166.6170718, -47344369.8497883, 27882583.2836718, 18281093.4304413},
-{{8, 0, 8, {-78.5833333333,40,0.9999375,1148291.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25914083.2833718, -47344369.8497883, 28210666.6173718, 18281093.4304413},
-{{8, 0, 8, {-81,24.3333333333,0.9999411765,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26406307.7847121, -41645021.2995836, 27718641.1181121, 23980683.2677422},
-{{8, 0, 8, {-82,24.3333333333,0.9999411765,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26406307.7847121, -41645021.2995836, 27718641.1181121, 23980683.2677422},
-{{8, 0, 8, {-82.1666666667,30,0.9999,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26405193.3811797, -43703150.5180839, 27717526.7145797, 21919851.6534533},
-{{8, 0, 8, {-84.1666666667,30,0.9999,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24764776.7148797, -43703150.5180839, 29357943.3808797, 21919851.6534533},
-{{8, 0, 8, {-85.6666666667,37.5,0.9999666667,328083.3333,820208.3333,0}, 0,0,0,0, {0,0,0,0,0}},  -26735080.9865789, -45615053.3682267, 27391247.6531788, 20012324.1098401},
-{{8, 0, 8, {-85.8333333333,30.5,0.99996,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26406817.225167, -43887616.8244314, 27719150.558567, 21739323.1210135},
-{{8, 0, 8, {-87.0833333333,37.5,0.9999666667,2952750,820208.3333,0}, 0,0,0,0, {0,0,0,0,0}},  -24110414.3198788, -45615053.3682267, 30015914.3198788, 20012324.1098401},
-{{8, 0, 8, {-87.5,30,0.9999333333,1968500,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25093762.1825261, -43704607.4340027, 29030762.1825261, 21920582.3875179},
-{{8, 0, 8, {-88.3333333333,36.6666666667,0.999975,984250,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26079139.8528638, -46132236.0153258, 28047639.8528638, 19495688.373596},
-{{8, 0, 8, {-88.8333333333,29.5,0.99995,984250,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26078463.2512025, -43523507.6796842, 28046963.2512025, 22102775.9701094},
-{{8, 0, 8, {-90.1666666667,36.6666666667,0.9999411765,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24765891.1184121, -46130675.6226312, 29359057.7844121, 19495028.9446946},
-{{8, 0, 8, {-90.3333333333,29.5,0.99995,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24766129.9182025, -43523507.6796842, 29359296.5842025, 22102775.9701094},
-{{8, 0, 8, {-90.5,35.8333333333,0.9999333333,820208.3333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26242053.8492261, -45826956.318909, 27882470.5158261, 19798233.5026115},
-{{8, 0, 8, {-92.5,35.8333333333,0.9999333333,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}},  -25421845.5155261, -45826956.318909, 28702678.8495261, 19798233.5026115},
-{{8, 0, 8, {-94.5,36.1666666667,0.9999411765,2788708.333,0,0}, 0,0,0,0, {0,0,0,0,0}},  -24273766.1184121, -45948654.6320023, 29851182.7844121, 19677049.9353235},
-{{8, 10, 7, {12,0,1,4500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}},  -3748143.32560618, -10000855.7646457, 12748143.3256062, 10000855.7646457},
-{{8, 10, 7, {123,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
-{{8, 10, 7, {124,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
-{{8, 10, 7, {127.5,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
-{{8, 10, 7, {129,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
-{{8, 10, 7, {129.5,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13651876.9787944, 8247318.51127362, 6347834.37934419},
-{{8, 10, 7, {131,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -12876121.1385208, 8247318.51127362, 7123590.21961776},
-{{8, 10, 7, {131,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -13651876.9787944, 8247318.51127362, 6347834.37934419},
-{{8, 10, 7, {132.166666,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {133.5,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13651876.9787944, 8247318.51127363, 6347834.37934419},
-{{8, 10, 7, {134.333333,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {135,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
-{{8, 10, 7, {136,20,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -12211786.0141993, 8247318.51127362, 7787925.34393926},
-{{8, 10, 7, {136,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {137.166666,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {138.5,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {139.833333,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
-{{8, 10, 7, {140.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -14872697.8989466, 8247318.51127362, 5127013.45919198},
-{{8, 10, 7, {140.833333,40,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -14428497.5605602, 8247318.51127362, 5571213.7975784},
-{{8, 10, 7, {141,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827595, 9996855.42233989},
-{{8, 10, 7, {142,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
-{{8, 10, 7, {142.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -14872697.8989466, 8247318.51127362, 5127013.45919198},
-{{8, 10, 7, {144.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127363, -14872697.8989466, 8247318.51127362, 5127013.45919198},
-{{8, 10, 7, {147,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827593, 9996855.42233989},
-{{8, 10, 7, {15,0,1,5500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}},  -2748143.32560618, -10000855.7646457, 13748143.3256062, 10000855.7646457},
-{{8, 10, 7, {15.8082777778,0,1,1500000,0,0}, 0,498,-36,568, {0,0,0,0,0}},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
-{{8, 10, 7, {15.8082777778,0,1,1500000,0,0}, 0,419.3836,99.3335,591.3451, {-0.850389, -1.817277, 7.862238, -0.99496, 0}},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
-{{8, 10, 7, {153,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
-{{8, 10, 7, {154,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
-{{8, 10, 7, {159,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
-{{8, 10, 7, {3,0,1,1500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
-{{8, 10, 7, {6,0,1,2500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}},  -5748143.32560618, -10000855.7646457, 10748143.3256062, 10000855.7646457},
-{{8, 10, 7, {9,0,1,3500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}},  -4748143.32560618, -10000855.7646457, 11748143.3256062, 10000855.7646457},
-{{8, 13, 7, {-8,53.5,1.000035,200000,250000,0}, 0,506,-122,611, {0,0,0,0,0}},  -8048349.95153666, -15680948.9714353, 8448349.95153666, 4321303.19013035},
-{{8, 2, 7, {105,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {105,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {111,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {111,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {117,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {117,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {123,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {123,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {129,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {129,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {135,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {135,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {141,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491762, 19998000.5903039},
-{{8, 2, 7, {141,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491762, 19998000.5903039},
-{{8, 2, 7, {141,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
-{{8, 2, 7, {143,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409616, -5001401.27077682, 8548679.10409615, 15001401.2707768},
-{{8, 2, 7, {145,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
-{{8, 2, 7, {147,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491762, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {147,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491762, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {147,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409616, -5001401.27077682, 8548679.10409615, 15001401.2707768},
-{{8, 2, 7, {149,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
-{{8, 2, 7, {149.0092948333,0,1.000086,200000,4510193.4939,0}, 0,-133,-48,148, {0,0,0,0,0}},  -8049883.48350812, -5492668.06907988, 8449883.48350812, 14513055.0568799},
-{{8, 2, 7, {151,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
-{{8, 2, 7, {153,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {153,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {153,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409616, -5001401.27077682, 8548679.10409616, 15001401.2707768},
-{{8, 2, 7, {155,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7948679.10409615, -5001401.27077682, 8548679.10409615, 15001401.2707768},
-{{8, 2, 7, {159,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {159,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {165,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {165,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {99,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 2, 7, {99,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-33,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-39,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-45,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-51,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-51,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-57,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-57,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-63,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-63,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-69,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-69,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-75,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-75,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 24, 7, {-81,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
-{{8, 24, 7, {-81,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
-{{8, 28, 7, {-105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597413, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597413, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-15,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597413, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-171,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597413, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-177,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-21,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-27,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-3,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-3,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-33,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-39,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-45,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-51,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-57,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-63,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-69,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-75,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-8.1319061111,39.6666666667,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -8249143.95355554, -14394484.2826752, 8249143.95355554, 5609447.17638195},
-{{8, 28, 7, {-81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-81,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-87,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-9,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-93,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {-99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {-99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, -9997964.94323674, 8745844.29597413, 9997964.94323674},
-{{8, 28, 7, {141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597411, 2035.05676326129, 8745844.29597413, 19997964.9432367},
-{{8, 28, 7, {147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597411, 9997964.94323674},
-{{8, 28, 7, {147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597411, 19997964.9432367},
-{{8, 28, 7, {15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {15,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {17,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597413, 9997964.94323674},
-{{8, 28, 7, {171,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597413, 19997964.9432367},
-{{8, 28, 7, {177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {177,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {19,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {19,0,1,0,3700000,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -6301965.72952855, 8249143.95355554, 13701965.7295286},
-{{8, 28, 7, {21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {21,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {21,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {23,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {25,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {27,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {27,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {29,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {3,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {3,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {31,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
-{{8, 28, 7, {33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {33,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {39,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {45,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {51,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {57,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {6.166666667,49.83333333,1,80000,100000,0}, 0,0,0,0, {0,0,0,0,0}},  -8169143.95355554, -15424274.8616842, 8329143.95355554, 4579656.59737291},
-{{8, 28, 7, {63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {63,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {69,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {75,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {81,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {87,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {9,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {93,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 28, 7, {99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
-{{8, 28, 7, {99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
-{{8, 29, 0, {78,0,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -5125.7804133582, -6214.93337007411, 5125.7804133582, 6214.93337007411},
-{{8, 3, 7, {-171,0,1,32500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  24250718.46099, -10002137.4977586, 40749281.53901, 10002137.4977586},
-{{8, 3, 7, {-177,0,1,31500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  23250718.46099, -10002137.4977586, 39749281.53901, 10002137.4977586},
-{{8, 3, 7, {105,0,1,18500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  10250718.46099, -10002137.4977586, 26749281.53901, 10002137.4977586},
-{{8, 3, 7, {111,0,1,19500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  11250718.46099, -10002137.4977586, 27749281.53901, 10002137.4977586},
-{{8, 3, 7, {117,0,1,20500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  12250718.46099, -10002137.4977586, 28749281.53901, 10002137.4977586},
-{{8, 3, 7, {123,0,1,21500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  13250718.46099, -10002137.4977586, 29749281.53901, 10002137.4977586},
-{{8, 3, 7, {129,0,1,22500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  14250718.46099, -10002137.4977586, 30749281.53901, 10002137.4977586},
-{{8, 3, 7, {135,0,1,23500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  15250718.46099, -10002137.4977586, 31749281.53901, 10002137.4977586},
-{{8, 3, 7, {141,0,1,24500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  16250718.46099, -10002137.4977586, 32749281.53901, 10002137.4977586},
-{{8, 3, 7, {147,0,1,25500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  17250718.46099, -10002137.4977586, 33749281.53901, 10002137.4977586},
-{{8, 3, 7, {15,0,1,3500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -4749281.53900998, -10002137.4977586, 11749281.53901, 10002137.4977586},
-{{8, 3, 7, {153,0,1,26500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  18250718.46099, -10002137.4977586, 34749281.53901, 10002137.4977586},
-{{8, 3, 7, {159,0,1,27500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  19250718.46099, -10002137.4977586, 35749281.53901, 10002137.4977586},
-{{8, 3, 7, {165,0,1,28500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  20250718.46099, -10002137.4977586, 36749281.53901, 10002137.4977586},
-{{8, 3, 7, {171,0,1,29500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  21250718.46099, -10002137.4977586, 37749281.53901, 10002137.4977586},
-{{8, 3, 7, {177,0,1,30500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  22250718.46099, -10002137.4977586, 38749281.53901, 10002137.4977586},
-{{8, 3, 7, {21,0,1,4500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -3749281.53900997, -10002137.4977586, 12749281.53901, 10002137.4977586},
-{{8, 3, 7, {27,0,1,5500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -2749281.53900998, -10002137.4977586, 13749281.53901, 10002137.4977586},
-{{8, 3, 7, {3,0,1,1500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -6749281.53900998, -10002137.4977586, 9749281.53900998, 10002137.4977586},
-{{8, 3, 7, {33,0,1,6500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -1749281.53900998, -10002137.4977586, 14749281.53901, 10002137.4977586},
-{{8, 3, 7, {39,0,1,7500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -749281.539009975, -10002137.4977586, 15749281.53901, 10002137.4977586},
-{{8, 3, 7, {45,0,1,8500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  250718.460990024, -10002137.4977586, 16749281.53901, 10002137.4977586},
-{{8, 3, 7, {51,0,1,9500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  1250718.46099002, -10002137.4977586, 17749281.53901, 10002137.4977586},
-{{8, 3, 7, {57,0,1,10500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  2250718.46099002, -10002137.4977586, 18749281.53901, 10002137.4977586},
-{{8, 3, 7, {63,0,1,11500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  3250718.46099002, -10002137.4977586, 19749281.53901, 10002137.4977586},
-{{8, 3, 7, {69,0,1,12500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  4250718.46099003, -10002137.4977586, 20749281.53901, 10002137.4977586},
-{{8, 3, 7, {75,0,1,13500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  5250718.46099002, -10002137.4977586, 21749281.53901, 10002137.4977586},
-{{8, 3, 7, {81,0,1,14500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  6250718.46099003, -10002137.4977586, 22749281.53901, 10002137.4977586},
-{{8, 3, 7, {87,0,1,15500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  7250718.46099003, -10002137.4977586, 23749281.53901, 10002137.4977586},
-{{8, 3, 7, {9,0,1,2500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  -5749281.53900998, -10002137.4977586, 10749281.53901, 10002137.4977586},
-{{8, 3, 7, {93,0,1,16500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  8250718.46099003, -10002137.4977586, 24749281.53901, 10002137.4977586},
-{{8, 3, 7, {99,0,1,17500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}},  9250718.46099002, -10002137.4977586, 25749281.53901, 10002137.4977586},
-{{8, 4, 4, {171.5,-44,1,500000,500000,0}, 0,84,-22,209, {0,0,0,0,0}},  -8521796.21510011, -5108460.96074551, 9521796.2151001, 16768810.0348996},
-{{8, 4, 4, {175.5,-39,1,300000,400000,0}, 0,84,-22,209, {0,0,0,0,0}},  -8721796.2151001, -5815782.48470089, 9321796.21510011, 16061488.5109442},
-{{8, 4, 7, {-15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-3,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-33,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-39,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-45,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-51,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-51,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-57,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-57,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-63,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-63,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-69,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {-69,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-75,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
-{{8, 4, 7, {-8.1319061111,39.6666666667,1,0,0,0}, 0,-303,-62,105, {0,0,0,0,0}},  -8249530.45908754, -14394881.7325041, 8249530.45908754, 5609694.86591381},
-{{8, 4, 7, {-8.1319061111,39.6666666667,1,180.598,-86.99,0}, 0,-223,110,37, {0,0,0,0,0}},  -8249349.86108754, -14394968.7225041, 8249711.05708754, 5609607.87591381},
-{{8, 4, 7, {-8.1319061111,39.6666666667,1,200000,300000,0}, 0,-303,-62,105, {0,0,0,0,0}},  -8049530.45908754, -14094881.7325041, 8449530.45908754, 5909694.86591381},
-{{8, 4, 7, {-9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {114.178555,22.3121333,0.99995,836694.05,819069.8,0}, 0,-156,-271,-189, {0,0,0,0,0}},  -7412423.93256458, -11650990.6841779, 9085812.03256459, 8352585.68541009},
-{{8, 4, 7, {114.178555,22.3121333,1,836694.05,819069.8,0}, 0,-156,-271,-189, {0,0,0,0,0}},  -7412836.40908754, -11651614.2183788, 9086224.50908754, 8352962.38003909},
-{{8, 4, 7, {15,0,0.9996,2520000,0,0}, 0,-225,-65,9, {0,0,0,0,0}},  -5726230.6469039, -9998287.38388927, 10766230.6469039, 9998287.38388927},
-{{8, 4, 7, {15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {167.738861778,-45.563726167,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4254598.13766705, 8549530.45908754, 15749978.4607509},
-{{8, 4, 7, {168.342872,-46.600009611,1,300002.66,699999.58,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949527.79908754, -4139408.83270982, 8549533.11908754, 15865167.7657081},
-{{8, 4, 7, {168.398641194,-45.132902583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4302480.81326099, 8549530.45908754, 15702095.7851569},
-{{8, 4, 7, {168.606267,-43.977802889,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4430843.14592791, 8549530.45908754, 15573733.45249},
-{{8, 4, 7, {169.467755083,-44.735267972,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4346671.56116845, 8549530.45908754, 15657905.0372495},
-{{8, 4, 7, {170.260925833,-43.110128139,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4527247.70696346, 8549530.45908754, 15477328.8914545},
-{{8, 4, 7, {170.282589111,-45.861513361,0.99996,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949200.47786918, -4221302.42846714, 8549200.47786917, 15782473.9868868},
-{{8, 4, 7, {170.628595167,-45.816196611,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4226536.32741985, 8549530.45908754, 15778040.2709981},
-{{8, 4, 7, {170.9799935,-42.886322361,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4552111.65805664, 8549530.45908754, 15452464.9403613},
-{{8, 4, 7, {171.057250833,-44.402220361,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4383682.10598832, 8549530.45908753, 15620894.4924296},
-{{8, 4, 7, {171.360748472,-43.748711556,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4456298.18308237, 8549530.45908754, 15548278.4153355},
-{{8, 4, 7, {171.549771306,-42.333694278,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4613502.29276327, 8549530.45908753, 15391074.3056546},
-{{8, 4, 7, {171.581260056,-41.810802861,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4671584.03492437, 8549530.45908754, 15332992.5634935},
-{{8, 4, 7, {172.109028194,-41.289911528,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4729438.31462099, 8549530.45908753, 15275138.2837969},
-{{8, 4, 7, {172.6720465,-40.714759056,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4793313.13554601, 8549530.45908754, 15211263.4628719},
-{{8, 4, 7, {172.727193583,-43.590637583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4473861.66485194, 8549530.45908753, 15530714.933566},
-{{8, 4, 7, {173.010133389,-42.689116583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4574019.640636, 8549530.45908754, 15430556.9577819},
-{{8, 4, 7, {173.299316806,-41.274544722,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4731144.99254062, 8549530.45908754, 15273431.6058773},
-{{8, 4, 7, {173.802074111,-41.544486667,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4701163.86142202, 8549530.45908754, 15303412.7369959},
-{{8, 4, 7, {174.22801175,-39.135758306,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4968639.63588687, 8549530.45908754, 15035936.962531},
-{{8, 4, 7, {174.764339361,-36.879865278,0.9999,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7948705.50604163, -5218451.08592923, 8548705.50604163, 14784125.0548288},
-{{8, 4, 7, {174.776623111,-41.301319639,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4728171.29681831, 8549530.45908754, 15276405.3015996},
-{{8, 4, 7, {175.488099611,-40.241947139,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4845817.49876657, 8549530.45908754, 15158759.0996513},
-{{8, 4, 7, {175.640036806,-39.512470389,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4926815.26039816, 8549530.45908754, 15077761.3380198},
-{{8, 4, 7, {175.647349667,-40.925532639,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -4769905.95772054, 8549530.45908754, 15234670.6406974},
-{{8, 4, 7, {176.46619725,-37.761249806,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -5121221.11127107, 8549530.45908754, 14883355.4871468},
-{{8, 4, 7, {176.673680528,-39.650929306,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908753, -4911442.20418344, 8549530.45908754, 15093134.3942345},
-{{8, 4, 7, {177.885636278,-38.624702778,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}},  -7949530.45908754, -5025375.11246985, 8549530.45908753, 14979201.4859481},
-{{8, 4, 7, {21,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {21,0,1,1500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -6749530.45908754, -10002288.299209, 9749530.45908754, 10002288.299209},
-{{8, 4, 7, {24,0,1,2500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -5749530.45908754, -10002288.299209, 10749530.4590875, 10002288.299209},
-{{8, 4, 7, {27,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {27,0,1,3500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -4749530.45908754, -10002288.299209, 11749530.4590875, 10002288.299209},
-{{8, 4, 7, {3,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {30,0,1,4500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -3749530.45908754, -10002288.299209, 12749530.4590875, 10002288.299209},
-{{8, 4, 7, {33,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {39,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {45,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
-{{8, 4, 7, {9,0,0.9996,1500000,0,0}, 0,-225,-65,9, {0,0,0,0,0}},  -6746230.6469039, -9998287.38388927, 9746230.6469039, 9998287.38388927},
-{{8, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{2, 29, 0, {-85.5,13,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -18500.7190263237, -4067.43878447928, 30025.7571082958, 4067.43878447928},
+{{2, 29, 0, {20,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26284.8753911183, -3963.19059194305, 23518.0464025796, 3963.19059194305},
+{{2, 7, 7, {0,30,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -34706360.1398239, -7364918.36397399, 34706360.1398239, 7364918.36397399},
+{{3, 0, 3, {-109.5,44.25,45,49,1968503.937,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -376322393.49652, -357755728.255206, 380259401.37052, 398826066.611833},
+{{3, 0, 3, {-111.5,36.6666666667,37.2166666667,38.35,1640419.948,9842519.685}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -281416969.95067, -245782664.730374, 284697809.84667, 320332115.066966},
+{{3, 0, 3, {-111.5,38.3333333333,39.0166666667,40.65,1640419.948,6561679.79}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -299820220.76226, -269235441.863424, 303101060.65826, 333685839.557096},
+{{3, 0, 3, {-111.5,40.3333333333,40.7166666667,41.7833333333,1640419.948,3280839.895}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -313479418.366583, -287610480.882755, 316760258.262583, 342629195.746411},
+{{3, 0, 3, {-120.5,41.6666666667,42.3333333333,44,4921259.843,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -329872743.533369, -311905915.324464, 339715263.219369, 357682091.428273},
+{{3, 0, 3, {-120.5,43.6666666667,44.3333333333,46,8202099.738,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -348623368.682272, -335442185.295993, 365027568.158272, 378208751.544552},
+{{3, 0, 3, {-81,31.8333333333,32.5,34.8333333333,2000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -248789436.724623, -218682485.302253, 252789436.724623, 282896388.146993},
+{{3, 0, 3, {-84.3666666667,41.5,42.1,43.6666666667,13123359.58,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -318674512.717618, -308729738.1419, 344921231.877618, 354866006.453336},
+{{3, 0, 3, {-84.3666666667,43.3166666667,44.1833333333,45.7,19685039.37,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -334588341.234808, -332680007.139814, 373958419.974808, 375866754.069803},
+{{3, 0, 3, {-87,44.7833333333,45.4833333333,47.0833333333,26246719.16,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -343541891.912548, -349200540.720143, 396035330.232548, 390376681.424953},
+{{3, 0, 7, {-100,39.8333333333,40,43,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -96293653.747449, -89392122.913416, 97293653.747449, 104195184.581482},
+{{3, 0, 7, {-100,43.8333333333,44.4166666667,45.6833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -107757768.605122, -101845373.546917, 108957768.605122, 114870163.663327},
+{{3, 0, 7, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,700000,3000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -70389655.9882633, -57319094.8848422, 71789655.9882633, 84860217.0916844},
+{{3, 0, 7, {-100.3333333333,42.3333333333,42.8333333333,44.4,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -102916158.881298, -96669936.9429582, 104116158.881298, 110362380.819638},
+{{3, 0, 7, {-100.5,45.6666666667,46.1833333333,47.4833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -114111552.091083, -108589212.496103, 115311552.091083, 120833891.686064},
+{{3, 0, 7, {-100.5,47,47.4333333333,48.7333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -118782512.590452, -113525792.131232, 119982512.590452, 125239233.049672},
+{{3, 0, 7, {-101.5,34,34.65,36.1833333333,200000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -80190916.4774175, -70255345.5878226, 80590916.4774175, 90526487.3670124},
+{{3, 0, 7, {-105.5,36.6666666667,37.2333333333,38.4333333333,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -85492362.7230086, -77749948.5363837, 87321166.3808086, 95063580.5674335},
+{{3, 0, 7, {-105.5,37.8333333333,38.45,39.75,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -88909656.3330413, -81520557.8132071, 90738459.9908412, 98127558.5106754},
+{{3, 0, 7, {-105.5,39.3333333333,39.7166666667,40.7833333333,914401.8289,304800.6096}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -92173099.6583073, -85136649.2531605, 94001903.3161073, 101038353.721254},
+{{3, 0, 7, {-109.5,44.25,45,49,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -114703065.537737, -109043945.972187, 115903065.537737, 121562185.103287},
+{{3, 0, 7, {-111.5,36.6666666667,37.2166666667,38.35,500000,3000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -85775892.4411146, -74914556.209806, 86775892.4411146, 97637228.6724232},
+{{3, 0, 7, {-111.5,38.3333333333,39.0166666667,40.65,500000,2000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -91385203.2884872, -82062962.6799637, 92385203.2884872, 101707443.897011},
+{{3, 0, 7, {-111.5,40.3333333333,40.7166666667,41.7833333333,500000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -95548526.7182849, -87663674.5730598, 96548526.7182849, 104433378.86351},
+{{3, 0, 7, {-116.25,32.1666666667,32.7833333333,33.8833333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -73735809.4129763, -65399717.6233228, 77735809.4129763, 86071901.2026297},
+{{3, 0, 7, {-118,33.5,34.0333333333,35.4666666667,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -76848317.8487893, -69006561.7099004, 80848317.8487893, 88690073.9876782},
+{{3, 0, 7, {-119,35.3333333333,36,37.25,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -81316774.1198701, -74083546.7405704, 85316774.1198701, 92550001.4991699},
+{{3, 0, 7, {-120.5,36.5,37.0666666667,38.4333333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -84187586.7378795, -77301811.5655565, 88187586.7378795, 95073361.9102026},
+{{3, 0, 7, {-120.5,41.6666666667,42.3333333333,44,1500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -100545212.229117, -95068922.9908967, 103545212.229117, 109021501.467338},
+{{3, 0, 7, {-120.5,43.6666666667,44.3333333333,46,2500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -106260402.774499, -102242778.078219, 111260402.774499, 115278027.47078},
+{{3, 0, 7, {-120.5,45.3333333333,45.8333333333,47.3333333333,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -113297926.255298, -107613973.979824, 114297926.255298, 119981878.530772},
+{{3, 0, 7, {-120.8333333333,47,47.5,48.7333333333,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -119009737.681158, -113655959.077325, 120009737.681158, 125363516.284991},
+{{3, 0, 7, {-122,37.6666666667,38.3333333333,39.8333333333,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -87776918.3325266, -81257129.4018421, 91776918.3325266, 98296707.2632112},
+{{3, 0, 7, {-122,39.3333333333,40,41.6666666667,2000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -92797918.1664438, -86741363.5256259, 96797918.1664438, 102854472.807262},
+{{3, 0, 7, {-176,51,51.8333333333,53.8333333333,1000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -137707686.600156, -133658946.217207, 139707686.600156, 143756426.983104},
+{{3, 0, 7, {-66.4333333333,17.8333333333,18.0333333333,18.4333333333,200000,200000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -56733778.1428648, -37322071.9454256, 57133778.1428648, 58748927.6361153},
+{{3, 0, 7, {-70.5,41,41.2833333333,41.4833333333,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -95953926.4298888, -89161935.9801186, 96953926.4298888, 103745916.879659},
+{{3, 0, 7, {-71.5,41,41.7166666667,42.6833333333,200000,750000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -98769146.9690858, -91041445.2286386, 99169146.9690858, 106896848.709533},
+{{3, 0, 7, {-72.75,40.8333333333,41.2,41.8666666667,304800.6096,152400.3048}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -96604898.0590896, -89468373.8450348, 97214499.2782896, 104351023.492344},
+{{3, 0, 7, {-74,40.1666666667,40.6666666667,41.0333333333,300000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -94551938.838961, -87389402.5378217, 95151938.838961, 102314475.1401},
+{{3, 0, 7, {-77,37.6666666667,38.3,39.45,400000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -88804178.7516629, -81148556.0144016, 89604178.7516629, 97259801.4889241},
+{{3, 0, 7, {-77.75,39.3333333333,39.9333333333,40.9666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -93070575.1551149, -86055381.3970464, 94270575.1551149, 101285768.913183},
+{{3, 0, 7, {-77.75,40.1666666667,40.8833333333,41.95,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -95953285.96374, -89173937.5969296, 97153285.96374, 103932634.33055},
+{{3, 0, 7, {-78.5,36.3333333333,36.7666666667,37.9666666667,3500000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -81693800.1596124, -75717098.3537021, 88693800.1596124, 94670501.9655228},
+{{3, 0, 7, {-78.5,37.6666666667,38.0333333333,39.2,3500000,2000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -84998823.9067757, -78398508.2242156, 91998823.9067757, 98599139.5893358},
+{{3, 0, 7, {-79,33.75,34.3333333333,36.1666666667,609601.22,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -79389023.1316542, -70798838.7584427, 80608225.5716542, 89198409.9448658},
+{{3, 0, 7, {-79.5,38.5,39,40.25,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -90694785.2338336, -83456997.4383959, 91894785.2338336, 99132573.0292712},
+{{3, 0, 7, {-81,31.8333333333,32.5,34.8333333333,609600,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -75831020.313665, -66654421.5201266, 77050220.313665, 86226819.1072034},
+{{3, 0, 7, {-81,37,37.4833333333,38.8833333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -86731868.6538258, -79080928.1042007, 87931868.6538258, 95582809.203451},
+{{3, 0, 7, {-82.5,38,38.7333333333,40.0333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -90013727.4321062, -82680858.3947178, 91213727.4321062, 98546596.4694945},
+{{3, 0, 7, {-82.5,39.6666666667,40.4333333333,41.7,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -94896218.4967998, -88010766.8984708, 96096218.4967998, 102981670.095129},
+{{3, 0, 7, {-84.25,37.5,37.9666666667,38.9666666667,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -87593445.377663, -79948138.9064763, 88593445.377663, 96238751.8488498},
+{{3, 0, 7, {-84.3666666667,41.5,42.1,43.6666666667,4000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -97131991.4763139, -94100824.185651, 105131991.476314, 108163158.766977},
+{{3, 0, 7, {-84.3666666667,43.3166666667,44.1833333333,45.7,6000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -101982526.408346, -101400866.176215, 113982526.408346, 114564186.640476},
+{{3, 0, 7, {-84.5,29,29.5833333333,30.75,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -68981040.7901211, -58469775.5831551, 70181040.7901211, 80692305.9970871},
+{{3, 0, 7, {-85.75,36.3333333333,36.7333333333,37.9333333333,500000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -84608108.5314714, -76125029.0762607, 85608108.5314714, 94091187.9866821},
+{{3, 0, 7, {-86,34.3333333333,35.25,36.4166666667,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -80782527.8217375, -72373896.5103859, 81982527.8217375, 90391159.1330892},
+{{3, 0, 7, {-87,44.7833333333,45.4833333333,47.0833333333,8000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -104711568.654913, -106436324.8115, 120711568.654913, 118986812.498326},
+{{3, 0, 7, {-90,42,42.7333333333,44.0666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -102206338.477554, -95896048.3229835, 103406338.477554, 109716628.632125},
+{{3, 0, 7, {-90,43.8333333333,44.25,45.5,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -107154105.286573, -101222137.29396, 108354105.286573, 114286073.279185},
+{{3, 0, 7, {-90,45.1666666667,45.5666666667,46.7666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -111693759.01384, -106048829.503351, 112893759.01384, 118538688.524328},
+{{3, 0, 7, {-91.3333333333,25.5,26.1666666667,27.8333333333,1000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -63537867.0156485, -51847003.2875935, 65537867.0156485, 77228730.7437035},
+{{3, 0, 7, {-91.3333333333,28.5,29.3,30.7,1000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -68286769.6701213, -58065091.5621744, 70286769.6701213, 80508447.7780682},
+{{3, 0, 7, {-92,32.6666666667,33.3,34.7666666667,400000,400000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -76844795.0772024, -67240210.8482154, 77644795.0772024, 87249379.3061895},
+{{3, 0, 7, {-92,34.3333333333,34.9333333333,36.2333333333,400000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -80385696.4806497, -71723301.2825226, 81185696.4806497, 89848091.6787767},
+{{3, 0, 7, {-92.5,30.5,31.1666666667,32.6666666667,1000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -71843187.1479918, -62437428.102125, 73843187.1479918, 83248946.1938587},
+{{3, 0, 7, {-93.1,46.5,47.0333333333,48.6333333333,800000,100000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -117632875.188048, -112398161.714158, 119232875.188048, 124467588.661938},
+{{3, 0, 7, {-93.5,40,40.6166666667,41.7833333333,500000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -95397349.164015, -88468304.6501118, 96397349.164015, 103326393.677918},
+{{3, 0, 7, {-93.5,41.5,42.0666666667,43.2666666667,1500000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -98941207.3645198, -92381467.3382571, 101941207.36452, 108500947.390783},
+{{3, 0, 7, {-94,43,43.7833333333,45.2166666667,800000,100000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -105671574.194712, -99704447.3453072, 107271574.194712, 113238701.044116},
+{{3, 0, 7, {-94.25,45,45.6166666667,47.05,800000,100000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -112092591.799175, -106546357.855489, 113692591.799175, 119238825.742861},
+{{3, 0, 7, {-98,33.3333333333,33.9333333333,35.2333333333,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -77870984.1222039, -69071740.6080561, 79070984.1222039, 87870227.6363517},
+{{3, 0, 7, {-98,35,35.5666666667,36.7666666667,600000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -81588328.3763743, -73324068.4505433, 82788328.3763743, 91052588.3022054},
+{{3, 0, 7, {-98,38.3333333333,38.7166666667,39.7833333333,400000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -89841929.3777815, -82323689.9068513, 90641929.3777815, 98160168.8487116},
+{{3, 0, 7, {-98.5,25.6666666667,26.1666666667,27.8333333333,300000,5000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -64237867.0156485, -46865470.5583462, 64837867.0156485, 82210263.4729508},
+{{3, 0, 7, {-98.5,31.6666666667,32.1333333333,33.9666666667,600000,2000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -74535881.4099808, -63171655.6562241, 75735881.4099808, 87100107.1637374},
+{{3, 0, 7, {-98.5,36.6666666667,38.5666666667,37.2666666667,400000,400000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -86225535.4567815, -77888976.4101326, 87025535.4567815, 95362094.5034304},
+{{3, 0, 7, {-99,27.8333333333,28.3833333333,30.2833333333,600000,4000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -67541882.489505, -52618369.9310933, 68741882.489505, 83665395.0479167},
+{{3, 0, 8, {-100,39.8333333333,40,43,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -315923429.002755, -293280656.591766, 319204262.336755, 341847034.747745},
+{{3, 0, 8, {-100,43.8333333333,44.4166666667,45.6833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -353535279.165304, -334137696.37851, 357472279.165304, 376869861.952098},
+{{3, 0, 8, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,2296583.333,9842500}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -230936729.688494, -188054397.134687, 235529896.354494, 278412228.908301},
+{{3, 0, 8, {-100.3333333333,42.3333333333,42.8333333333,44.4,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -337650764.596392, -317157951.453689, 341587764.596392, 362080577.739096},
+{{3, 0, 8, {-100.5,45.6666666667,46.1833333333,47.4833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -374380983.81883, -356263107.997632, 378317983.81883, 396435859.640027},
+{{3, 0, 8, {-100.5,47,47.4333333333,48.7333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -389705626.72384, -372459203.017216, 393642626.72384, 410889050.430464},
+{{3, 0, 8, {-101.5,34,34.65,36.1833333333,656166.6667,3280833.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -263093031.809627, -230496079.649714, 264405365.143027, 297002317.30294},
+{{3, 0, 8, {-105.5,36.6666666667,37.2333333333,38.4333333333,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -280486193.367387, -255084622.823115, 286486193.367387, 311887763.911659},
+{{3, 0, 8, {-105.5,37.8333333333,38.45,39.75,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -291697764.152969, -267455363.425493, 297697764.152969, 321940164.880445},
+{{3, 0, 8, {-105.5,39.3333333333,39.7166666667,40.7833333333,3000000,1000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -302404577.795946, -279319156.758073, 308404577.795946, 331489998.833818},
+{{3, 0, 8, {-109.5,44.25,45,49,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -376321640.851725, -357755012.743749, 380258640.851725, 398825268.9597},
+{{3, 0, 8, {-111.5,36.6666666667,37.2166666667,38.35,1640416.667,9842500}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -281416407.11689, -245782173.165005, 284697240.45089, 320331474.402775},
+{{3, 0, 8, {-111.5,38.3333333333,39.0166666667,40.65,1640416.667,6561666.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -299819621.121978, -269234903.392181, 303100454.455978, 333685172.185776},
+{{3, 0, 8, {-111.5,40.3333333333,40.7166666667,41.7833333333,1640416.667,3280833.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -313478791.407906, -287609905.662114, 316759624.741906, 342628510.487699},
+{{3, 0, 8, {-116.25,32.1666666667,32.7833333333,33.8833333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -241914901.382073, -214565573.568852, 255038234.716073, 282387562.529294},
+{{3, 0, 8, {-118,33.5,34.0333333333,35.4666666667,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -252126522.80857, -226399027.876232, 265249856.14257, 290977351.074907},
+{{3, 0, 8, {-119,35.3333333333,36,37.25,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -266786783.091274, -243055769.597688, 279910116.425274, 303641129.91886},
+{{3, 0, 8, {-120.5,36.5,37.0666666667,38.4333333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -276205440.822193, -253614360.110997, 289328774.156193, 311919854.86739},
+{{3, 0, 8, {-120.5,41.6666666667,42.3333333333,44,4921250,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -329872083.788362, -311905291.512634, 339714583.788362, 357681376.064091},
+{{3, 0, 8, {-120.5,43.6666666667,44.3333333333,46,8202083.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -348622671.436336, -335441514.411622, 365026838.102336, 378207995.127049},
+{{3, 0, 8, {-120.5,45.3333333333,45.8333333333,47.3333333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -371711613.055591, -353063512.965473, 374992446.389591, 393640546.479709},
+{{3, 0, 8, {-120.8333333333,47,47.5,48.7333333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -390451114.375266, -372886259.072857, 393731947.709266, 411296803.011675},
+{{3, 0, 8, {-122,37.6666666667,38.3333333333,39.8333333333,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -287981439.562298, -266591098.71221, 301104772.896298, 322495113.746385},
+{{3, 0, 8, {-122,39.3333333333,40,41.6666666667,6561666.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -304454503.184074, -284583956.833324, 317577836.518074, 337448382.868824},
+{{3, 0, 8, {-176,51,51.8333333333,53.8333333333,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -451795968.454344, -438512726.047621, 458357635.120344, 471640877.527066},
+{{3, 0, 8, {-66.4333333333,17.8333333333,18.0333333333,18.4333333333,656166.6667,656166.6667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -186134070.457016, -122447497.707584, 187446403.790416, 192745440.086188},
+{{3, 0, 8, {-70.5,41,41.2833333333,41.4833333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -314808840.29506, -292525451.628106, 318089673.62906, 340373062.296015},
+{{3, 0, 8, {-71.5,41,41.7166666667,42.6833333333,656166.6667,2460625}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -324045109.681042, -298691808.220958, 325357443.014442, 350710744.474526},
+{{3, 0, 8, {-72.75,40.8333333333,41.2,41.8666666667,1000000,500000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -316944569.715526, -293530823.189916, 318944569.715526, 342358316.241135},
+{{3, 0, 8, {-74,40.1666666667,40.6666666667,41.0333333333,984250,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -310209152.674158, -286710064.82617, 312177652.674158, 335676740.522146},
+{{3, 0, 8, {-77,37.6666666667,38.3,39.45,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -291351709.788081, -266234887.523916, 293976376.454081, 319093198.718245},
+{{3, 0, 8, {-77.75,39.3333333333,39.9333333333,40.9666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -305349045.321406, -282333363.800143, 309286045.321406, 332301726.842669},
+{{3, 0, 8, {-77.75,40.1666666667,40.8833333333,41.95,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -314806739.032704, -292564826.932593, 318743739.032704, 340985651.132814},
+{{3, 0, 8, {-78.5,36.3333333333,36.7666666667,37.9666666667,11482916.67,3280833.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -268023742.686995, -248415180.182438, 290989576.026995, 310598138.531553},
+{{3, 0, 8, {-78.5,37.6666666667,38.0333333333,39.2,11482916.67,6561666.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -278866974.764147, -257212439.065281, 301832808.104147, 323487343.803013},
+{{3, 0, 8, {-79,33.75,34.3333333333,36.1666666667,2000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -260462153.393719, -232279190.159991, 264462153.393719, 292645116.627447},
+{{3, 0, 8, {-79.5,38.5,39,40.25,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -297554474.554669, -273808499.095804, 301491474.554669, 325237450.013534},
+{{3, 0, 8, {-81,31.8333333333,32.5,34.8333333333,1999996,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -248788939.145749, -218682047.937282, 252788931.145749, 282895822.354217},
+{{3, 0, 8, {-81,37,37.4833333333,38.8833333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -284552805.74176, -259451344.955198, 288489805.74176, 313591266.528322},
+{{3, 0, 8, {-82.5,38,38.7333333333,40.0333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -295320037.416835, -271262116.250003, 299257037.416835, 323314958.583666},
+{{3, 0, 8, {-82.5,39.6666666667,40.4333333333,41.7,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -311338676.851584, -288748657.732733, 315275676.851584, 337865695.970435},
+{{3, 0, 8, {-84.25,37.5,37.9666666667,38.9666666667,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -287379495.376216, -262296519.062331, 290660328.710216, 315743305.024101},
+{{3, 0, 8, {-84.3666666667,41.5,42.1,43.6666666667,13123333.33,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -318673875.371873, -308729120.682423, 344920542.031873, 354865296.721323},
+{{3, 0, 8, {-84.3666666667,43.3166666667,44.1833333333,45.7,19685000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -334587672.058047, -332679341.779799, 373957672.058047, 375866002.336295},
+{{3, 0, 8, {-84.5,29,29.5833333333,30.75,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -226315297.992256, -191829588.725735, 230252297.992256, 264738007.258777},
+{{3, 0, 8, {-85.75,36.3333333333,36.7333333333,37.9333333333,1640416.667,1640416.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -277585102.740002, -249753532.894032, 280865936.074002, 308697505.919973},
+{{3, 0, 8, {-86,34.3333333333,35.25,36.4166666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -265034010.028484, -237446692.134491, 268971010.028484, 296558327.922477},
+{{3, 0, 8, {-87,44.7833333333,45.4833333333,47.0833333333,26246666.67,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -343541204.825326, -349199842.319061, 396034538.165326, 390375900.67159},
+{{3, 0, 8, {-90,42,42.7333333333,44.0666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -335321962.15511, -314618951.872988, 339258962.15511, 359961972.437231},
+{{3, 0, 8, {-90,43.8333333333,44.25,45.5,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -351554760.427697, -332092962.105268, 355491760.427697, 374953558.750127},
+{{3, 0, 8, {-90,45.1666666667,45.5666666667,46.7666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -366448607.697906, -347928534.795579, 370385607.697906, 388905680.600232},
+{{3, 0, 8, {-91.3333333333,25.5,26.1666666667,27.8333333333,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -208457152.034173, -170101376.61938, 215018818.700173, 253374594.114967},
+{{3, 0, 8, {-91.3333333333,28.5,29.3,30.7,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -224037510.159723, -190501887.900234, 230599176.825723, 264134799.085212},
+{{3, 0, 8, {-92,32.6666666667,33.3,34.7666666667,1312333.333,1312333.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -252114965.182788, -220603925.09152, 254739631.848788, 286250671.940057},
+{{3, 0, 8, {-92,34.3333333333,34.9333333333,36.2333333333,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -263732072.537265, -235312197.62441, 266356739.203265, 294776614.11612},
+{{3, 0, 8, {-92.5,30.5,31.1666666667,32.6666666667,3280833.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -235705523.16837, -204846795.365055, 242267189.83437, 273125917.637685},
+{{3, 0, 8, {-93.1,46.5,47.0333333333,48.6333333333,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -385933858.012454, -368759635.557233, 391183191.346454, 408357413.801674},
+{{3, 0, 8, {-93.5,40,40.6166666667,41.7833333333,1640416.667,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -312982803.048606, -290249762.839575, 316263636.382606, 338996676.591636},
+{{3, 0, 8, {-93.5,41.5,42.0666666667,43.2666666667,4921250,3280833.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -324609611.161762, -303088197.425932, 334452111.161762, 355973524.897592},
+{{3, 0, 8, {-94,43,43.7833333333,45.2166666667,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -346690823.003483, -327113674.332095, 351940156.337483, 371517305.008871},
+{{3, 0, 8, {-94.25,45,45.6166666667,47.05,2624666.667,328083.3333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -367757111.594128, -349560842.397585, 373006444.928128, 391202714.124671},
+{{3, 0, 8, {-98,33.3333333333,33.9333333333,35.2333333333,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -255481720.407597, -226612868.978264, 259418720.407597, 288287571.836931},
+{{3, 0, 8, {-98,35,35.5666666667,36.7666666667,1968500,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -267677707.348155, -240564047.908157, 271614707.348155, 298728366.788152},
+{{3, 0, 8, {-98,38.3333333333,38.7166666667,39.7833333333,1312333.333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -294756396.633938, -270090305.969395, 297381063.299938, 322047153.964481},
+{{3, 0, 8, {-98.5,25.6666666667,26.1666666667,27.8333333333,984250,16404166.67}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -210753735.367173, -153757797.986841, 212722235.367173, 269718172.747506},
+{{3, 0, 8, {-98.5,31.6666666667,32.1333333333,33.9666666667,1968500,6561666.667}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -244539804.259245, -207255673.598462, 248476804.259245, 285760934.920029},
+{{3, 0, 8, {-98.5,36.6666666667,38.5666666667,37.2666666667,1312333.333,1312333.333}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -282891610.911457, -255540750.10591, 285516277.577457, 312867138.383004},
+{{3, 0, 8, {-99,27.8333333333,28.3833333333,30.2833333333,1968500,13123333.33}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -221593659.467651, -172632102.018929, 225530659.467651, 274492216.916373},
+{{3, 2, 7, {135,-24,-18,-36,0,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -63926410.6698201, -76575533.9276959, 63926410.6698201, 51277287.4119443},
+{{3, 2, 7, {145,-37,-36,-38,2500000,4500000}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -81753864.458242, -88226525.7784545, 86753864.458242, 80281203.1380295},
+{{3, 2, 7, {147,0,-32.666,-35.333,1000000,10000000}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -76161714.4889037, -80605291.2154594, 78161714.4889037, 73718137.7623481},
+{{3, 28, 7, {23,-23,-18,-32,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -61566719.246568, -72414618.8198515, 61566719.246568, 47796808.4991836},
+{{3, 29, 0, {110,10,25,40,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -45730.409093877, -38000.6689484435, 45730.409093877, 53460.1492393104},
+{{3, 29, 0, {132.5,-10,-21.5,-33.5,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -40383.2188994685, -49161.7062224971, 40383.2188994685, 31604.73157644},
+{{3, 29, 0, {25,35,40,65,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -84908.0213013157, -80759.383210806, 84908.0213013157, 89056.6593918254},
+{{3, 29, 0, {47.5,25,15,35,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -38011.5438463059, -29679.737315404, 38011.5438463059, 46069.8166618704},
+{{3, 29, 0, {95,40,20,60,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -55750.1705370063, -51403.1783693689, 55750.1705370063, 60097.1627046438},
+{{3, 30, 7, {0,42.165,41.560387840948,42.76766346965,234.358,185861.369}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -98847613.927946, -91608686.7437833, 98848082.643946, 106087009.828109},
+{{3, 30, 7, {0,42.165,41.560387840948,42.76766346965,234.358,4185861.369}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -98847613.927946, -87608686.7437833, 98848082.643946, 110087009.828109},
+{{3, 30, 7, {0,44.1,43.199291275544,44.996093814511,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -104503824.398662, -98311919.3139696, 105703824.398662, 111895729.483354},
+{{3, 30, 7, {0,44.1,43.199291275544,44.996093814511,600000,3200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -104503824.398662, -95311919.3139696, 105703824.398662, 114895729.483354},
+{{3, 30, 7, {0,46.8,45.898918964419,47.696014502038,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -113967455.416715, -108367759.648713, 115167455.416715, 120767151.184716},
+{{3, 30, 7, {0,46.8,45.898918964419,47.696014502038,600000,2200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -113967455.416715, -106367759.648713, 115167455.416715, 122767151.184716},
+{{3, 30, 7, {0,49.5,48.598522847174,50.395911631678,600000,1200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -124264257.877732, -118206641.203686, 125464257.877732, 131521874.551778},
+{{3, 30, 7, {0,49.5,48.598522847174,50.395911631678,600000,200000}, 0,-168,-60,320, {0,0,0,0,2.337229166667}, 0,0,0,0,0,0,0,0},  -124264257.877732, -119206641.203686, 125464257.877732, 130521874.551778},
+{{3, 4, 7, {17,29.77930555,42,56,2679984.29,-484330}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -119981631.268354, -115489555.67494, 125341599.848354, 129833675.441769},
+{{3, 4, 7, {4.3569397222,90,49.8333333333,51.1666666667,150000.01256,5400088.4378}, 0,81,120,129, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -128761663.907607, -123511575.482367, 129061663.932727, 134311752.357967},
+{{3, 4, 7, {4.367975,90,49.8333333333,51.1666666667,150000,5400000}, 0,81,120,129, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -128761663.920167, -123511663.920167, 129061663.920167, 134311663.920167},
+{{3, 6, 7, {23,-23,-18,-32,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -61564419.064164, -72412828.2264313, 61564419.064164, 47794154.9885407},
+{{3, 7, 7, {-68.5,44,46,60,0.99999912,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -139220351.696306, -133454155.398424, 139220353.696304, 144986549.994186},
+{{3, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -89717066.7318629, -80920710.9207624, 89717066.7318629, 98513422.5429635},
+{{3, 7, 7, {-96,23,33,45,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -89295530.2887796, -79679575.056002, 89295530.2887796, 98911485.5215573},
+{{3, 7, 7, {-96,39,33,45,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -89295530.2887796, -81466209.2421514, 89295530.2887796, 97124851.3354078},
+{{3, 7, 8, {-100,41.3333333333,41.85,42.8166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -324055199.858072, -302686222.906259, 328055199.858072, 349424176.809884},
+{{3, 7, 8, {-100,43.8333333333,44.4166666667,45.6833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -353482329.11673, -334115632.201571, 357482329.11673, 376849026.031889},
+{{3, 7, 8, {-100.3333333333,29.6666666667,30.1166666667,31.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -231224626.213763, -197887504.402976, 235224626.213763, 268561748.024549},
+{{3, 7, 8, {-100.3333333333,42.3333333333,42.8333333333,44.4,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -337599541.873847, -317137605.090357, 341599541.873847, 362061478.657338},
+{{3, 7, 8, {-100.5,45.6666666667,46.1833333333,47.4833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -374325734.927512, -356238757.711242, 378325734.927512, 396412712.143782},
+{{3, 7, 8, {-100.5,47,47.4333333333,48.7333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -389648664.421659, -372433148.680405, 393648664.421659, 410864180.162913},
+{{3, 7, 8, {-101.5,34,34.65,36.1833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -261737418.19268, -233764458.26155, 265737418.19268, 293710378.12381},
+{{3, 7, 8, {-105.5,36.6666666667,37.2333333333,38.4333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -281472391.565436, -256070159.37991, 285472391.565436, 310874623.750962},
+{{3, 7, 8, {-105.5,37.8333333333,38.45,39.75,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -292682801.597057, -268439748.039304, 296682801.597057, 320925855.154811},
+{{3, 7, 8, {-105.5,39.3333333333,39.7166666667,40.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -303388496.172414, -280302427.035458, 307388496.172414, 330474565.30937},
+{{3, 7, 8, {-109.5,44,44.8666666667,46.4,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -360164256.91475, -341067435.395783, 364164256.91475, 383261078.433716},
+{{3, 7, 8, {-109.5,45.8333333333,46.45,47.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -378353013.025643, -360433206.501952, 382353013.025643, 400272819.549334},
+{{3, 7, 8, {-109.5,47,47.85,48.7166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -392158606.473501, -375000733.125562, 396158606.473501, 413316479.821439},
+{{3, 7, 8, {-111.5,36.6666666667,37.2166666667,38.35,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -281043066.114894, -255610253.091634, 285043066.114894, 310475879.138154},
+{{3, 7, 8, {-111.5,38.3333333333,39.0166666667,40.65,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -299444370.803389, -275780256.64851, 303444370.803389, 327108484.958269},
+{{3, 7, 8, {-111.5,40.3333333333,40.7166666667,41.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -313102102.853289, -290872992.274509, 317102102.853289, 339331213.432069},
+{{3, 7, 8, {-116.25,32.1666666667,32.7833333333,33.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -246466336.059689, -216195067.142672, 250466336.059689, 280737604.976705},
+{{3, 7, 8, {-118,33.5,34.0333333333,35.4666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -256676923.297906, -228027497.817793, 260676923.297906, 289326348.778019},
+{{3, 7, 8, {-118.3333333333,34.1333333333,33.8666666667,34.4166666667,4186692.58,4160926.74}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -250023955.862257, -219155253.035527, 258397341.022257, 289266043.848988},
+{{3, 7, 8, {-119,35.3333333333,36,37.25,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -271335689.379641, -244682757.78249, 275335689.379641, 301988620.976793},
+{{3, 7, 8, {-120.5,36.5,37.0666666667,38.4333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -280753380.155715, -255240388.034962, 284753380.155715, 310266372.276468},
+{{3, 7, 8, {-120.5,41.6666666667,42.3333333333,44,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -332774131.475311, -311885463.700041, 336774131.475311, 357662799.250581},
+{{3, 7, 8, {-120.5,43.6666666667,44.3333333333,46,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -354803161.418059, -335419308.868092, 358803161.418059, 378187013.968026},
+{{3, 7, 8, {-120.5,45.3333333333,45.8333333333,47.3333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -371328614.306844, -353039494.544633, 375328614.306844, 393617734.069055},
+{{3, 7, 8, {-120.8333333333,47,47.5,48.7333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -390066021.607763, -372860157.907014, 394066021.607763, 411271885.308512},
+{{3, 7, 8, {-122,37.6666666667,38.3333333333,39.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -292528160.248962, -268215917.695861, 296528160.248962, 320840402.802063},
+{{3, 7, 8, {-122,39.3333333333,40,41.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -308999499.517601, -286207062.905244, 312999499.517601, 335791936.129957},
+{{3, 7, 8, {-176,51,51.8333333333,53.8333333333,3000000,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -452044058.020189, -438479429.247576, 458044058.020189, 471608686.792802},
+{{3, 7, 8, {-66.4333333333,18.4333333333,18.0333333333,18.4333333333,500000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -186287246.382945, -123317624.596919, 187287246.382945, 191870266.743549},
+{{3, 7, 8, {-66.4333333333,18.4333333333,18.0333333333,18.4333333333,500000,100000}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -186287246.382945, -123217624.596919, 187287246.382945, 191970266.743549},
+{{3, 7, 8, {-70.5,41,41.2833333333,41.4833333333,800000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -315632009.889084, -292507560.721895, 317232009.889084, 340356459.056272},
+{{3, 7, 8, {-71.5,41,41.7166666667,42.6833333333,600000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -324083153.067583, -301133676.4023, 325283153.067583, 348232629.732865},
+{{3, 7, 8, {-72.75,40.8333333333,41.2,41.8666666667,600000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -317327164.550983, -294012777.09286, 318527164.550983, 341841552.009105},
+{{3, 7, 8, {-74,40.5,40.6666666667,41.0333333333,2000000,100000}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -309176711.160841, -286714165.719965, 313176711.160841, 335639256.601717},
+{{3, 7, 8, {-77,37.8333333333,38.3,39.45,800000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -291849291.606495, -266280179.434122, 293449291.606495, 319018403.778868},
+{{3, 7, 8, {-77.75,39.3333333333,39.9333333333,40.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -305301262.728919, -282316435.790654, 309301262.728919, 332286089.667183},
+{{3, 7, 8, {-77.75,40.1666666667,40.8833333333,41.95,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -314757958.485081, -292546908.072089, 318757958.485081, 340969008.898072},
+{{3, 7, 8, {-78.5,36.3333333333,36.7666666667,37.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -277493267.234049, -251681955.591517, 281493267.234049, 307304578.87658},
+{{3, 7, 8, {-78.5,37.6666666667,38.0333333333,39.2,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -288335380.041045, -263758935.876341, 292335380.041045, 316911824.205748},
+{{3, 7, 8, {-79,33.75,34.3333333333,36.1666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -260450504.74125, -232266866.952514, 264450504.74125, 292634142.529987},
+{{3, 7, 8, {-79.5,38.5,39,40.25,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -297507509.009345, -273792382.933741, 301507509.009345, 325222635.08495},
+{{3, 7, 8, {-81,31.8333333333,32.3333333333,33.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -244165860.608621, -213488972.345334, 248165860.608621, 278842748.871908},
+{{3, 7, 8, {-81,33,33.7666666667,34.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -253843797.715595, -224716073.21255, 257843797.715595, 286971522.21864},
+{{3, 7, 8, {-81,37,37.4833333333,38.8833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -284507191.09272, -259436571.044567, 288507191.09272, 313577811.140872},
+{{3, 7, 8, {-82.5,38,38.7333333333,40.0333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -295273305.101978, -271246233.791215, 299273305.101978, 323300376.41274},
+{{3, 7, 8, {-82.5,39.6666666667,40.4333333333,41.7,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -311290263.635938, -288731104.977908, 315290263.635938, 337849422.293968},
+{{3, 7, 8, {-84.25,37.5,37.9666666667,38.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -287005538.125454, -262281485.830837, 291005538.125454, 315729590.42007},
+{{3, 7, 8, {-84.5,29,29.5833333333,30.75,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -226275614.557084, -191820690.371176, 230275614.557084, 264730538.742992},
+{{3, 7, 8, {-85.75,36.3333333333,36.7333333333,37.9333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -277212156.180922, -251379920.019457, 281212156.180922, 307044392.342388},
+{{3, 7, 8, {-86,34.6666666667,35.25,36.4166666667,2000000,100000}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -264990397.68906, -237455247.728469, 268990397.68906, 296525547.64965},
+{{3, 7, 8, {-90,42,42.7333333333,44.0666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -335270989.964058, -314598855.147961, 339270989.964058, 359943124.780154},
+{{3, 7, 8, {-90,43.8333333333,44.25,45.5,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -351502026.802048, -332071112.456575, 355502026.802048, 374932941.147521},
+{{3, 7, 8, {-90,45.1666666667,45.5666666667,46.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -366394237.721428, -347905058.027747, 370394237.721428, 388883417.41511},
+{{3, 7, 8, {-91.3333333333,25.6666666667,26.1666666667,27.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -209731525.091816, -170154762.702282, 213731525.091816, 253308287.48135},
+{{3, 7, 8, {-91.3333333333,28.6666666667,29.3,30.67,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -225224715.171064, -190451550.801895, 229224715.171064, 263997879.540232},
+{{3, 7, 8, {-92,32.6666666667,33.3,34.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -251416565.855924, -221904841.787545, 255416565.855924, 284928289.924303},
+{{3, 7, 8, {-92,34.3333333333,34.9333333333,36.2333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -263032493.27188, -235299609.879708, 267032493.27188, 294765376.664052},
+{{3, 7, 8, {-92.5,30.6666666667,31.1666666667,32.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -236977085.666136, -204897455.65052, 240977085.666136, 273056715.681752},
+{{3, 7, 8, {-93.1,46.5,47.0333333333,48.6333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -386533413.283953, -369062013.990686, 390533413.283953, 408004812.577219},
+{{3, 7, 8, {-93.5,40,40.6166666667,41.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -312606167.17083, -290232070.277002, 316606167.17083, 338980264.064658},
+{{3, 7, 8, {-93.5,41.5,42.0666666667,43.2666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -327512222.250473, -306349761.225561, 331512222.250473, 352674683.275385},
+{{3, 7, 8, {-94,43,43.7833333333,45.2166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -347294715.331617, -327420366.588323, 351294715.331617, 371169064.074911},
+{{3, 7, 8, {-94.25,45,45.6166666667,47.05,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -368358691.706647, -349865234.580916, 372358691.706647, 390852148.832379},
+{{3, 7, 8, {-97.5,31.6666666667,32.1333333333,33.9666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -244498272.760526, -213806618.399239, 248498272.760526, 279189927.121813},
+{{3, 7, 8, {-98,33.3333333333,33.9333333333,35.2333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -255439079.607865, -226601046.512961, 259439079.607865, 288277112.70277},
+{{3, 7, 8, {-98,35,35.5666666667,36.7666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -267633825.34702, -240550993.657801, 271633825.34702, 298716657.03624},
+{{3, 7, 8, {-98,38.3333333333,38.7166666667,39.7833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -294053624.246013, -270074545.620282, 298053624.246013, 322032702.871744},
+{{3, 7, 8, {-98.5,25.6666666667,26.1666666667,27.8333333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -209731525.091816, -170154762.702282, 213731525.091816, 253308287.48135},
+{{3, 7, 8, {-98.5,36.6666666667,38.5666666667,37.2666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -282190068.629093, -256838547.449771, 286190068.629093, 311541589.808415},
+{{3, 7, 8, {-99,27.8333333333,28.3833333333,30.2833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -221554461.124832, -185747019.927933, 225554461.124832, 261361902.321731},
+{{3, 7, 8, {-99.5,39.6666666667,40.2833333333,41.7166666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -310633016.402964, -288042234.606454, 314633016.402964, 337223798.199475},
+{{3, 8, 8, {-84.3333333333,41.5,42.1,43.6666666667,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -329791001.829521, -308721404.605132, 333791001.829521, 354860599.053909},
+{{3, 8, 8, {-84.3333333333,43.3166666667,44.1833333333,45.7,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -352264889.757925, -332670121.355321, 356264889.757925, 375859658.160529},
+{{3, 8, 8, {-87,44.7833333333,45.4833333333,47.0833333333,2000000,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -367778976.228709, -349189556.133667, 371778976.228709, 390368396.32375},
+{{4, 7, 7, {0,90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -9020145.99449487, -9020145.99449487, 9020145.99449487, 9020145.99449487},
+{{6, 2, 1, {134,-90,-18,-36,0,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25412.1329074842, -30820.2630332478, 25412.1329074842, 20004.0027817205},
+{{6, 2, 1, {147,-32.5,-29.5,-35.5,0,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -23611.4811992266, -33623.6505009443, 23611.4811992266, 13599.3118975089},
+{{6, 2, 7, {134,-90,-18,-36,0,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25412132.9074842, -30820263.0332478, 25412132.9074842, 20004002.7817205},
+{{6, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -21729866.6858831, -12546277.7889483, 21729866.6858831, 30913455.5828178},
+{{6, 7, 7, {-96,23,29.5,45.5,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -22421877.8189369, -12546277.7889483, 22421877.8189369, 32297477.8489255},
+{{7, 0, 7, {-133.6666666667,57,-36.8698976458,0.9999,5000000,-5000000}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  715546.220413176, -14325907.9924165, 9284453.77958682, 4325907.99241646},
+{{7, 0, 8, {-133.6666666667,57,-36.8698976458,0.9999,16404166.67,-16404166.67}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  2347587.89480556, -47000916.4751197, 30460745.4451944, 14192583.1351197},
+{{7, 7, 8, {-133.6666666667,57,-36.8698976458,0.9999,16404166.6667,-16404166.6667}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  2347270.72925546, -47001747.5537593, 30461062.6041445, 14193414.2203593},
+{{8, 0, 3, {-110.1666666667,31,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26361414.1707081, -44066918.5002725, 27761414.1707081, 21556214.9175316},
+{{8, 0, 3, {-111.9166666667,31,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26361414.1707081, -44066918.5002725, 27761414.1707081, 21556214.9175316},
+{{8, 0, 3, {-113.75,31,0.9999333333,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26362316.3071587, -44068387.5429912, 27762316.3071587, 21556933.5291715},
+{{8, 0, 7, {-104.3333333333,31,0.9999090909,165000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8083394.03137459, -13431718.8763978, 8413394.03137459, 6570394.04308942},
+{{8, 0, 7, {-105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-105.1666666667,40.5,0.9999375,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048628.38213008, -14486109.042394, 8448628.38213009, 5516572.17078242},
+{{8, 0, 7, {-106.25,31,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923183, -13431596.758883, 8748319.03923182, 6570334.30686364},
+{{8, 0, 7, {-107.3333333333,40.5,0.9999375,400000,100000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7848628.38213008, -14386109.042394, 8648628.38213008, 5616572.17078242},
+{{8, 0, 7, {-107.8333333333,31,0.9999166667,830000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7418456.52523935, -13431820.641665, 9078456.52523936, 6570443.82360611},
+{{8, 0, 7, {-108.75,40.5,0.9999375,600000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7648628.38213009, -14486109.042394, 8848628.38213009, 5516572.17078242},
+{{8, 0, 7, {-110.0833333333,40.5,0.9999375,800000,100000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7448628.38213009, -14386109.042394, 9048628.38213008, 5616572.17078242},
+{{8, 0, 7, {-110.1666666667,31,0.9999,213360,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8034959.03923183, -13431596.758883, 8461679.03923182, 6570334.30686364},
+{{8, 0, 7, {-111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-111.9166666667,31,0.9999,213360,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8034959.03923183, -13431596.758883, 8461679.03923182, 6570334.30686364},
+{{8, 0, 7, {-112.1666666667,41.6666666667,0.9999473684,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048709.78798227, -14615809.9655587, 8448709.78798228, 5387068.65441496},
+{{8, 0, 7, {-113.75,31,0.9999333333,213360,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8035234.01042198, -13432044.5231037, 8461954.01042198, 6570553.33969148},
+{{8, 0, 7, {-114,41.6666666667,0.9999473684,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748709.78798228, -14615809.9655587, 8748709.78798228, 5387068.65441496},
+{{8, 0, 7, {-115.5833333333,34.75,0.9999,200000,8000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048319.03923182, -5847439.17666561, 8448319.03923183, 14154491.8890811},
+{{8, 0, 7, {-115.75,41.6666666667,0.9999333333,800000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7448594.01042197, -14615604.8204071, 9048594.01042198, 5386993.0423881},
+{{8, 0, 7, {-116.6666666667,34.75,0.9999,500000,6000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923183, -7847439.17666561, 8748319.03923183, 12154491.8890811},
+{{8, 0, 7, {-117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-118.5833333333,34.75,0.9999,800000,4000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7448319.03923183, -9847439.17666561, 9048319.03923182, 10154491.8890811},
+{{8, 0, 7, {-123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
+{{8, 0, 7, {-142,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-146,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-150,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-154,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-155.5,18.8333333333,0.9999666667,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748868.98243704, -12084782.4965247, 8748868.98243704, 7918482.16531935},
+{{8, 0, 7, {-156.6666666667,20.3333333333,0.9999666667,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748868.98243704, -12250825.7354572, 8748868.98243703, 7752438.92638694},
+{{8, 0, 7, {-158,21.1666666667,0.99999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7749061.46218765, -12343372.1823083, 8749061.46218765, 7660359.23726966},
+{{8, 0, 7, {-158,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923182, -15986282.9700963, 8748319.03923182, 4015648.0956504},
+{{8, 0, 7, {-159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-159.5,21.8333333333,0.99999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7749061.46218765, -12417187.1755718, 8749061.46218765, 7586544.24400615},
+{{8, 0, 7, {-160.1666666667,21.6666666667,1,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7749143.95362718, -12398856.862762, 8749143.95362719, 7605074.59613055},
+{{8, 0, 7, {-162,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923183, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
+{{8, 0, 7, {-166,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-170,54,0.9999,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748319.03923182, -15986282.9700963, 8748319.03923183, 4015648.0956504},
+{{8, 0, 7, {-171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-2,49,0.9996012717,400000,-100000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7845854.7864821, -15525440.3489618, 8645854.7864821, 4470514.97634689},
+{{8, 0, 7, {-21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-55.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923183, -10000965.5328733, 8553119.03923183, 10000965.5328733},
+{{8, 0, 7, {-57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-58.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
+{{8, 0, 7, {-61.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
+{{8, 0, 7, {-63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-64.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923182, -10000965.5328733, 8553119.03923182, 10000965.5328733},
+{{8, 0, 7, {-67.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
+{{8, 0, 7, {-68.5,43.6666666667,0.9999,300000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948319.03923182, -14837267.8945768, 8548319.03923182, 5164663.17116993},
+{{8, 0, 7, {-69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-70.1666666667,42.8333333333,0.9999666667,900000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7348868.98243704, -14745678.889568, 9148868.98243704, 5257585.77227607},
+{{8, 0, 7, {-70.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
+{{8, 0, 7, {-71.5,41.0833333333,0.99999375,100000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8149092.39647748, -14551702.6314571, 8349092.39647748, 5452103.80286384},
+{{8, 0, 7, {-71.6666666667,42.5,0.9999666667,300000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948868.98243704, -14708651.3754574, 8548868.98243704, 5294613.28638668},
+{{8, 0, 7, {-72.5,42.5,0.9999642857,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748849.34122529, -14708616.3529911, 8748849.34122528, 5294600.67949221},
+{{8, 0, 7, {-73.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
+{{8, 0, 7, {-74.5,38.8333333333,0.9999,150000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8098319.03923183, -14300537.2022438, 8398319.03923182, 5701393.86350293},
+{{8, 0, 7, {-74.5,38.8333333334,0.9999,150000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8098319.03923183, -14300537.2022549, 8398319.03923182, 5701393.86349183},
+{{8, 0, 7, {-75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-75.4166666667,38,0.999995,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8049102.70790742, -14209392.7012779, 8449102.70790742, 5794438.73795742},
+{{8, 0, 7, {-76.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923183, -10000965.5328733, 8553119.03923182, 10000965.5328733},
+{{8, 0, 7, {-76.5833333333,40,0.9999375,250000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7998628.38213008, -14430592.791401, 8498628.38213008, 5572088.42177536},
+{{8, 0, 7, {-78.5833333333,40,0.9999375,350000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7898628.38213008, -14430592.791401, 8598628.38213008, 5572088.42177536},
+{{8, 0, 7, {-79.5,0,0.9999,304800,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943519.03923182, -10000965.5328733, 8553119.03923183, 10000965.5328733},
+{{8, 0, 7, {-81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-81,24.3333333333,0.9999411765,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048658.71010783, -12693427.8789688, 8448658.71010783, 7309326.87866157},
+{{8, 0, 7, {-82,24.3333333333,0.9999411765,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048658.71010783, -12693427.8789688, 8448658.71010783, 7309326.87866157},
+{{8, 0, 7, {-82.1666666667,30,0.9999,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048319.03923182, -13320746.9194058, 8448319.03923183, 6681184.14634087},
+{{8, 0, 7, {-84.1666666667,30,0.9999,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7548319.03923183, -13320746.9194058, 8948319.03923182, 6681184.14634087},
+{{8, 0, 7, {-85.6666666667,37.5,0.9999666667,100000,250000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8148868.98243704, -13903496.0736175, 8348868.98243704, 6099768.58822661},
+{{8, 0, 7, {-85.8333333333,30.5,0.99996,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048813.98786904, -13376972.3620314, 8448813.98786904, 6626158.9396028},
+{{8, 0, 7, {-87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-87.0833333333,37.5,0.9999666667,900000,250000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7348868.98243704, -13903496.0736175, 9148868.98243703, 6099768.58822661},
+{{8, 0, 7, {-87.5,30,0.9999333333,600000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7648594.01042198, -13321190.988266, 8848594.01042197, 6681406.87452919},
+{{8, 0, 7, {-88.3333333333,36.6666666667,0.999975,300000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948937.72502834, -14061133.6597386, 8548937.72502835, 5942297.70086748},
+{{8, 0, 7, {-88.8333333333,29.5,0.99995,300000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948731.4964295, -13265991.6727511, 8548731.4964295, 6736939.58956854},
+{{8, 0, 7, {-9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {-90.1666666667,36.6666666667,0.9999411765,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7548658.71010783, -14060658.0510941, 8948658.71010783, 5942096.70653633},
+{{8, 0, 7, {-90.3333333333,29.5,0.99995,700000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7548731.49642951, -13265991.6727511, 8948731.4964295, 6736939.58956854},
+{{8, 0, 7, {-90.5,35.8333333333,0.9999333333,250000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7998594.01042198, -13968084.2221719, 8498594.01042197, 6034513.64062328},
+{{8, 0, 7, {-92.5,35.8333333333,0.9999333333,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748594.01042198, -13968084.2221719, 8748594.01042197, 6034513.64062328},
+{{8, 0, 7, {-93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604573, 9997964.94315451},
+{{8, 0, 7, {-94.5,36.1666666667,0.9999411765,850000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7398658.71010783, -14005177.9421902, 9098658.71010783, 5997576.81544022},
+{{8, 0, 7, {-99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
+{{8, 0, 7, {111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {12,0,0.99995,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7748731.4964295, -10001465.6311598, 8748731.4964295, 10001465.6311598},
+{{8, 0, 7, {123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
+{{8, 0, 7, {129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, 2035.0568454858, 8745844.29604573, 19997964.9431545},
+{{8, 0, 7, {141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604573, 19997964.9431545},
+{{8, 0, 7, {15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {15,0,1,900000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7349143.95362719, -10001965.7294463, 9149143.95362719, 10001965.7294463},
+{{8, 0, 7, {153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604573, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 7, {9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, -9997964.94315451, 8745844.29604574, 9997964.94315451},
+{{8, 0, 7, {9.5,0,0.99995,200000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048731.4964295, -10001465.6311598, 8448731.49642951, 10001465.6311598},
+{{8, 0, 7, {99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29604574, 2035.0568454858, 8745844.29604574, 19997964.9431545},
+{{8, 0, 8, {-104.3333333333,31,0.9999090909,541337.5,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26520268.5846015, -44067231.0136484, 27602943.5846015, 21556367.7897025},
+{{8, 0, 8, {-105.1666666667,40.5,0.9999375,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26406208.2836718, -47526509.4165876, 27718541.6170718, 18098953.863642},
+{{8, 0, 8, {-106.25,31,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808798, -44066830.3664355, 28701776.7148797, 21556171.8051018},
+{{8, 0, 8, {-107.3333333333,40.5,0.9999375,1312333.333,328083.3333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25750041.6173718, -47198426.0832876, 28374708.2833718, 18427037.196942},
+{{8, 0, 8, {-107.8333333333,31,0.9999166667,2723091.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24338719.4495561, -44067564.8885294, 29784902.7835561, 21556531.111281},
+{{8, 0, 8, {-108.75,40.5,0.9999375,1968500,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25093874.9503718, -47526509.4165876, 29030874.9503718, 18098953.863642},
+{{8, 0, 8, {-110.0833333333,40.5,0.9999375,2624666.667,328083.3333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24437708.2833718, -47198426.0832876, 29687041.6173718, 18427037.196942},
+{{8, 0, 8, {-110.1666666667,31,0.9999,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26361361.4478798, -44066830.3664355, 27761358.6478797, 21556171.8051018},
+{{8, 0, 8, {-111.9166666667,31,0.9999,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26361361.4478797, -44066830.3664355, 27761358.6478797, 21556171.8051018},
+{{8, 0, 8, {-112.1666666667,41.6666666667,0.9999473684,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26406475.3627052, -47952036.5286703, 27718808.6961052, 17674074.4103597},
+{{8, 0, 8, {-113.75,31,0.9999333333,699998.6,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26362263.5825261, -44068299.4062161, 27762260.7825261, 21556890.4153045},
+{{8, 0, 8, {-114,41.6666666667,0.9999473684,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25422225.3624052, -47952036.5286703, 28703058.6964052, 17674074.4103597},
+{{8, 0, 8, {-115.5833333333,34.75,0.9999,656166.6667,26246666.67,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26405193.3811797, -19184473.3621104, 27717526.7145797, 46438528.8094268},
+{{8, 0, 8, {-115.75,41.6666666667,0.9999333333,2624666.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24437595.5155261, -47951363.4816189, 29686928.8495261, 17673826.3399016},
+{{8, 0, 8, {-116.6666666667,34.75,0.9999,1640416.667,19685000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -25746140.0321104, 28701776.7148797, 39876862.1394268},
+{{8, 0, 8, {-118.5833333333,34.75,0.9999,2624666.667,13123333.33,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24436693.3808797, -32307806.7021104, 29686026.7148797, 33315195.4694268},
+{{8, 0, 8, {-142,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-146,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-150,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-154,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-155.5,18.8333333333,0.9999666667,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25422747.6528788, -39648157.2406816, 28703580.9868788, 25979220.2373852},
+{{8, 0, 8, {-156.6666666667,20.3333333333,0.9999666667,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25422747.6528789, -40192917.4337457, 28703580.9868788, 25434460.0443211},
+{{8, 0, 8, {-158,21.1666666667,0.99999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25423379.1468606, -40496546.9014566, 28704212.4808606, 25132361.9309422},
+{{8, 0, 8, {-158,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-159.5,21.8333333333,0.99999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25423379.1468606, -40738721.5918553, 28704212.4808606, 24890187.2405435},
+{{8, 0, 8, {-160.1666666667,21.6666666667,1,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25423649.7875252, -40678582.8905784, 28704483.1215252, 24950982.2374716},
+{{8, 0, 8, {-162,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-166,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-170,54,0.9999,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25420943.3808797, -52448330.0443909, 28701776.7148797, 13174672.1271464},
+{{8, 0, 8, {-68.5,43.6666666667,0.9999,984250,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26077110.0478797, -48678603.0841239, 28045610.0478797, 16944399.0874133},
+{{8, 0, 8, {-70.1666666667,42.8333333333,0.9999666667,2952750,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24110414.3198788, -48378114.8235244, 30015914.3198788, 17249262.6545424},
+{{8, 0, 8, {-71.5,41.0833333333,0.99999375,328083.3333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26735813.9708099, -47741711.0500389, 27391980.6374099, 17887443.8932291},
+{{8, 0, 8, {-71.6666666667,42.5,0.9999666667,984250,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26078914.3198788, -48256633.7209798, 28047414.3198788, 17370743.757087},
+{{8, 0, 8, {-72.5,42.5,0.9999642857,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25422683.2133366, -48256518.8181048, 28703516.5473366, 17370702.3959674},
+{{8, 0, 8, {-74.5,38.8333333333,0.9999,492125,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26569235.0478797, -46917679.1376948, 27553485.0478797, 18705323.0338425},
+{{8, 0, 8, {-74.5,38.8333333334,0.9999,492125,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26569235.0478797, -46917679.1377312, 27553485.0478797, 18705323.0338061},
+{{8, 0, 8, {-75.4166666667,38,0.999995,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26407764.4674929, -46618649.2207758, 27720097.8008929, 19010587.7594486},
+{{8, 0, 8, {-76.5833333333,40,0.9999375,820208.3333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26242166.6170718, -47344369.8497883, 27882583.2836718, 18281093.4304413},
+{{8, 0, 8, {-78.5833333333,40,0.9999375,1148291.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25914083.2833718, -47344369.8497883, 28210666.6173718, 18281093.4304413},
+{{8, 0, 8, {-81,24.3333333333,0.9999411765,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26406307.7847121, -41645021.2995836, 27718641.1181121, 23980683.2677422},
+{{8, 0, 8, {-82,24.3333333333,0.9999411765,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26406307.7847121, -41645021.2995836, 27718641.1181121, 23980683.2677422},
+{{8, 0, 8, {-82.1666666667,30,0.9999,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26405193.3811797, -43703150.5180839, 27717526.7145797, 21919851.6534533},
+{{8, 0, 8, {-84.1666666667,30,0.9999,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24764776.7148797, -43703150.5180839, 29357943.3808797, 21919851.6534533},
+{{8, 0, 8, {-85.6666666667,37.5,0.9999666667,328083.3333,820208.3333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26735080.9865789, -45615053.3682267, 27391247.6531788, 20012324.1098401},
+{{8, 0, 8, {-85.8333333333,30.5,0.99996,656166.6667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26406817.225167, -43887616.8244314, 27719150.558567, 21739323.1210135},
+{{8, 0, 8, {-87.0833333333,37.5,0.9999666667,2952750,820208.3333,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24110414.3198788, -45615053.3682267, 30015914.3198788, 20012324.1098401},
+{{8, 0, 8, {-87.5,30,0.9999333333,1968500,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25093762.1825261, -43704607.4340027, 29030762.1825261, 21920582.3875179},
+{{8, 0, 8, {-88.3333333333,36.6666666667,0.999975,984250,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26079139.8528638, -46132236.0153258, 28047639.8528638, 19495688.373596},
+{{8, 0, 8, {-88.8333333333,29.5,0.99995,984250,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26078463.2512025, -43523507.6796842, 28046963.2512025, 22102775.9701094},
+{{8, 0, 8, {-90.1666666667,36.6666666667,0.9999411765,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24765891.1184121, -46130675.6226312, 29359057.7844121, 19495028.9446946},
+{{8, 0, 8, {-90.3333333333,29.5,0.99995,2296583.333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24766129.9182025, -43523507.6796842, 29359296.5842025, 22102775.9701094},
+{{8, 0, 8, {-90.5,35.8333333333,0.9999333333,820208.3333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26242053.8492261, -45826956.318909, 27882470.5158261, 19798233.5026115},
+{{8, 0, 8, {-92.5,35.8333333333,0.9999333333,1640416.667,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25421845.5155261, -45826956.318909, 28702678.8495261, 19798233.5026115},
+{{8, 0, 8, {-94.5,36.1666666667,0.9999411765,2788708.333,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24273766.1184121, -45948654.6320023, 29851182.7844121, 19677049.9353235},
+{{8, 10, 7, {12,0,1,4500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}, 0,0,0,0,0,0,0,0},  -3748143.32560618, -10000855.7646457, 12748143.3256062, 10000855.7646457},
+{{8, 10, 7, {123,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
+{{8, 10, 7, {124,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
+{{8, 10, 7, {127.5,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
+{{8, 10, 7, {129,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
+{{8, 10, 7, {129.5,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13651876.9787944, 8247318.51127362, 6347834.37934419},
+{{8, 10, 7, {131,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -12876121.1385208, 8247318.51127362, 7123590.21961776},
+{{8, 10, 7, {131,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -13651876.9787944, 8247318.51127362, 6347834.37934419},
+{{8, 10, 7, {132.166666,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {133.5,33,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13651876.9787944, 8247318.51127363, 6347834.37934419},
+{{8, 10, 7, {134.333333,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {135,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
+{{8, 10, 7, {136,20,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -12211786.0141993, 8247318.51127362, 7787925.34393926},
+{{8, 10, 7, {136,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {137.166666,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {138.5,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {139.833333,36,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -13984603.2178459, 8247318.51127362, 6015108.14029263},
+{{8, 10, 7, {140.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -14872697.8989466, 8247318.51127362, 5127013.45919198},
+{{8, 10, 7, {140.833333,40,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -14428497.5605602, 8247318.51127362, 5571213.7975784},
+{{8, 10, 7, {141,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827595, 9996855.42233989},
+{{8, 10, 7, {142,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
+{{8, 10, 7, {142.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -14872697.8989466, 8247318.51127362, 5127013.45919198},
+{{8, 10, 7, {144.25,44,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127363, -14872697.8989466, 8247318.51127362, 5127013.45919198},
+{{8, 10, 7, {147,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827593, 9996855.42233989},
+{{8, 10, 7, {15,0,1,5500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}, 0,0,0,0,0,0,0,0},  -2748143.32560618, -10000855.7646457, 13748143.3256062, 10000855.7646457},
+{{8, 10, 7, {15.8082777778,0,1,1500000,0,0}, 0,498,-36,568, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
+{{8, 10, 7, {15.8082777778,0,1,1500000,0,0}, 0,419.3836,99.3335,591.3451, {-0.850389, -1.817277, 7.862238, -0.99496, 0}, 0,0,0,0,0,0,0,0},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
+{{8, 10, 7, {153,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
+{{8, 10, 7, {154,26,0.9999,0,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8247318.51127362, -12876121.1385208, 8247318.51127362, 7123590.21961776},
+{{8, 10, 7, {159,0,0.9996,500000,0,0}, 0,-128,481,664, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7744844.06827594, -9996855.42233989, 8744844.06827594, 9996855.42233989},
+{{8, 10, 7, {3,0,1,1500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}, 0,0,0,0,0,0,0,0},  -6748143.32560618, -10000855.7646457, 9748143.32560618, 10000855.7646457},
+{{8, 10, 7, {6,0,1,2500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}, 0,0,0,0,0,0,0,0},  -5748143.32560618, -10000855.7646457, 10748143.3256062, 10000855.7646457},
+{{8, 10, 7, {9,0,1,3500000,0,0}, 0,582,105,414, {-1.04,-0.35,3.08,8.3,0}, 0,0,0,0,0,0,0,0},  -4748143.32560618, -10000855.7646457, 11748143.3256062, 10000855.7646457},
+{{8, 13, 7, {-8,53.5,1.000035,200000,250000,0}, 0,506,-122,611, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8048349.95153666, -15680948.9714353, 8448349.95153666, 4321303.19013035},
+{{8, 2, 7, {105,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {105,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {111,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {111,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {117,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {117,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {123,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {123,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {129,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {129,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {135,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {135,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {141,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491762, 19998000.5903039},
+{{8, 2, 7, {141,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491762, 19998000.5903039},
+{{8, 2, 7, {141,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
+{{8, 2, 7, {143,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409616, -5001401.27077682, 8548679.10409615, 15001401.2707768},
+{{8, 2, 7, {145,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
+{{8, 2, 7, {147,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491762, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {147,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491762, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {147,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409616, -5001401.27077682, 8548679.10409615, 15001401.2707768},
+{{8, 2, 7, {149,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
+{{8, 2, 7, {149.0092948333,0,1.000086,200000,4510193.4939,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8049883.48350812, -5492668.06907988, 8449883.48350812, 14513055.0568799},
+{{8, 2, 7, {151,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409615, -5001401.27077682, 8548679.10409616, 15001401.2707768},
+{{8, 2, 7, {153,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {153,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {153,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409616, -5001401.27077682, 8548679.10409616, 15001401.2707768},
+{{8, 2, 7, {155,0,0.99994,300000,5000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948679.10409615, -5001401.27077682, 8548679.10409615, 15001401.2707768},
+{{8, 2, 7, {159,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {159,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {165,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {165,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {99,0,0.9996,500000,10000000,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 2, 7, {99,0,0.9996,500000,10000000,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-33,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-39,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-45,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-51,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-51,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-57,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-57,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-63,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-63,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-69,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-69,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-75,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-75,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 24, 7, {-81,0,0.9996,500000,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393},
+{{8, 24, 7, {-81,0,0.9996,500000,10000000,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, 1999.40969607119, 8745874.38491761, 19998000.5903039},
+{{8, 28, 7, {-105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597413, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597413, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-15,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597413, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-171,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597413, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-177,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-21,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-27,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-3,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-3,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-33,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-39,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-45,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-51,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-57,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-63,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-69,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-75,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-8.1319061111,39.6666666667,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -14394484.2826752, 8249143.95355554, 5609447.17638195},
+{{8, 28, 7, {-81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-81,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-87,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-9,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-93,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {-99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {-99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {105,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {105,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {111,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {111,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {117,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {117,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {123,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {123,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {129,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {129,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {135,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {135,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {141,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, -9997964.94323674, 8745844.29597413, 9997964.94323674},
+{{8, 28, 7, {141,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597411, 2035.05676326129, 8745844.29597413, 19997964.9432367},
+{{8, 28, 7, {147,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597411, 9997964.94323674},
+{{8, 28, 7, {147,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597411, 19997964.9432367},
+{{8, 28, 7, {15,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {15,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {153,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {153,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {159,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {159,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {165,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {165,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {17,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {171,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597413, 9997964.94323674},
+{{8, 28, 7, {171,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597413, 19997964.9432367},
+{{8, 28, 7, {177,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {177,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {19,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {19,0,1,0,3700000,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -6301965.72952855, 8249143.95355554, 13701965.7295286},
+{{8, 28, 7, {21,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {21,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {21,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {23,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {25,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {27,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {27,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {27,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {29,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {3,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {3,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {31,0,1,0,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -8249143.95355554, -10001965.7295286, 8249143.95355554, 10001965.7295286},
+{{8, 28, 7, {33,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {33,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {39,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {39,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {45,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {45,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {51,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {51,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {57,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {57,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {6.166666667,49.83333333,1,80000,100000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8169143.95355554, -15424274.8616842, 8329143.95355554, 4579656.59737291},
+{{8, 28, 7, {63,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {63,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {69,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {69,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {75,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {75,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {81,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {81,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {87,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {87,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {9,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {9,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {93,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {93,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 28, 7, {99,0,0.9996,500000,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, -9997964.94323674, 8745844.29597412, 9997964.94323674},
+{{8, 28, 7, {99,0,0.9996,500000,10000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745844.29597412, 2035.05676326129, 8745844.29597412, 19997964.9432367},
+{{8, 29, 0, {78,0,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -5125.7804133582, -6214.93337007411, 5125.7804133582, 6214.93337007411},
+{{8, 3, 7, {-171,0,1,32500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  24250718.46099, -10002137.4977586, 40749281.53901, 10002137.4977586},
+{{8, 3, 7, {-177,0,1,31500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  23250718.46099, -10002137.4977586, 39749281.53901, 10002137.4977586},
+{{8, 3, 7, {105,0,1,18500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  10250718.46099, -10002137.4977586, 26749281.53901, 10002137.4977586},
+{{8, 3, 7, {111,0,1,19500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  11250718.46099, -10002137.4977586, 27749281.53901, 10002137.4977586},
+{{8, 3, 7, {117,0,1,20500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  12250718.46099, -10002137.4977586, 28749281.53901, 10002137.4977586},
+{{8, 3, 7, {123,0,1,21500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  13250718.46099, -10002137.4977586, 29749281.53901, 10002137.4977586},
+{{8, 3, 7, {129,0,1,22500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  14250718.46099, -10002137.4977586, 30749281.53901, 10002137.4977586},
+{{8, 3, 7, {135,0,1,23500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  15250718.46099, -10002137.4977586, 31749281.53901, 10002137.4977586},
+{{8, 3, 7, {141,0,1,24500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  16250718.46099, -10002137.4977586, 32749281.53901, 10002137.4977586},
+{{8, 3, 7, {147,0,1,25500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  17250718.46099, -10002137.4977586, 33749281.53901, 10002137.4977586},
+{{8, 3, 7, {15,0,1,3500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -4749281.53900998, -10002137.4977586, 11749281.53901, 10002137.4977586},
+{{8, 3, 7, {153,0,1,26500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  18250718.46099, -10002137.4977586, 34749281.53901, 10002137.4977586},
+{{8, 3, 7, {159,0,1,27500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  19250718.46099, -10002137.4977586, 35749281.53901, 10002137.4977586},
+{{8, 3, 7, {165,0,1,28500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  20250718.46099, -10002137.4977586, 36749281.53901, 10002137.4977586},
+{{8, 3, 7, {171,0,1,29500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  21250718.46099, -10002137.4977586, 37749281.53901, 10002137.4977586},
+{{8, 3, 7, {177,0,1,30500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  22250718.46099, -10002137.4977586, 38749281.53901, 10002137.4977586},
+{{8, 3, 7, {21,0,1,4500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -3749281.53900997, -10002137.4977586, 12749281.53901, 10002137.4977586},
+{{8, 3, 7, {27,0,1,5500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -2749281.53900998, -10002137.4977586, 13749281.53901, 10002137.4977586},
+{{8, 3, 7, {3,0,1,1500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -6749281.53900998, -10002137.4977586, 9749281.53900998, 10002137.4977586},
+{{8, 3, 7, {33,0,1,6500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -1749281.53900998, -10002137.4977586, 14749281.53901, 10002137.4977586},
+{{8, 3, 7, {39,0,1,7500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -749281.539009975, -10002137.4977586, 15749281.53901, 10002137.4977586},
+{{8, 3, 7, {45,0,1,8500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  250718.460990024, -10002137.4977586, 16749281.53901, 10002137.4977586},
+{{8, 3, 7, {51,0,1,9500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  1250718.46099002, -10002137.4977586, 17749281.53901, 10002137.4977586},
+{{8, 3, 7, {57,0,1,10500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  2250718.46099002, -10002137.4977586, 18749281.53901, 10002137.4977586},
+{{8, 3, 7, {63,0,1,11500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  3250718.46099002, -10002137.4977586, 19749281.53901, 10002137.4977586},
+{{8, 3, 7, {69,0,1,12500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  4250718.46099003, -10002137.4977586, 20749281.53901, 10002137.4977586},
+{{8, 3, 7, {75,0,1,13500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  5250718.46099002, -10002137.4977586, 21749281.53901, 10002137.4977586},
+{{8, 3, 7, {81,0,1,14500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  6250718.46099003, -10002137.4977586, 22749281.53901, 10002137.4977586},
+{{8, 3, 7, {87,0,1,15500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  7250718.46099003, -10002137.4977586, 23749281.53901, 10002137.4977586},
+{{8, 3, 7, {9,0,1,2500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  -5749281.53900998, -10002137.4977586, 10749281.53901, 10002137.4977586},
+{{8, 3, 7, {93,0,1,16500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  8250718.46099003, -10002137.4977586, 24749281.53901, 10002137.4977586},
+{{8, 3, 7, {99,0,1,17500000,0,0}, 0,24,-123,-94, {-0.02,0.25,0.13,1.1,0}, 0,0,0,0,0,0,0,0},  9250718.46099002, -10002137.4977586, 25749281.53901, 10002137.4977586},
+{{8, 4, 4, {171.5,-44,1,500000,500000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8521796.21510011, -5108460.96074551, 9521796.2151001, 16768810.0348996},
+{{8, 4, 4, {175.5,-39,1,300000,400000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8721796.2151001, -5815782.48470089, 9321796.21510011, 16061488.5109442},
+{{8, 4, 7, {-15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-3,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-33,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-39,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-45,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-51,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-51,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-57,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-57,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-63,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-63,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-69,0,0.9996,500000,0,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {-69,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-75,0,0.9996,500000,10000000,0}, 0,-206,172,-6, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, 1712.61611072717, 8746230.6469039, 19998287.3838893},
+{{8, 4, 7, {-8.1319061111,39.6666666667,1,0,0,0}, 0,-303,-62,105, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249530.45908754, -14394881.7325041, 8249530.45908754, 5609694.86591381},
+{{8, 4, 7, {-8.1319061111,39.6666666667,1,180.598,-86.99,0}, 0,-223,110,37, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249349.86108754, -14394968.7225041, 8249711.05708754, 5609607.87591381},
+{{8, 4, 7, {-8.1319061111,39.6666666667,1,200000,300000,0}, 0,-303,-62,105, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8049530.45908754, -14094881.7325041, 8449530.45908754, 5909694.86591381},
+{{8, 4, 7, {-9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {114.178555,22.3121333,0.99995,836694.05,819069.8,0}, 0,-156,-271,-189, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7412423.93256458, -11650990.6841779, 9085812.03256459, 8352585.68541009},
+{{8, 4, 7, {114.178555,22.3121333,1,836694.05,819069.8,0}, 0,-156,-271,-189, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7412836.40908754, -11651614.2183788, 9086224.50908754, 8352962.38003909},
+{{8, 4, 7, {15,0,0.9996,2520000,0,0}, 0,-225,-65,9, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -5726230.6469039, -9998287.38388927, 10766230.6469039, 9998287.38388927},
+{{8, 4, 7, {15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {167.738861778,-45.563726167,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4254598.13766705, 8549530.45908754, 15749978.4607509},
+{{8, 4, 7, {168.342872,-46.600009611,1,300002.66,699999.58,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949527.79908754, -4139408.83270982, 8549533.11908754, 15865167.7657081},
+{{8, 4, 7, {168.398641194,-45.132902583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4302480.81326099, 8549530.45908754, 15702095.7851569},
+{{8, 4, 7, {168.606267,-43.977802889,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4430843.14592791, 8549530.45908754, 15573733.45249},
+{{8, 4, 7, {169.467755083,-44.735267972,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4346671.56116845, 8549530.45908754, 15657905.0372495},
+{{8, 4, 7, {170.260925833,-43.110128139,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4527247.70696346, 8549530.45908754, 15477328.8914545},
+{{8, 4, 7, {170.282589111,-45.861513361,0.99996,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949200.47786918, -4221302.42846714, 8549200.47786917, 15782473.9868868},
+{{8, 4, 7, {170.628595167,-45.816196611,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4226536.32741985, 8549530.45908754, 15778040.2709981},
+{{8, 4, 7, {170.9799935,-42.886322361,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4552111.65805664, 8549530.45908754, 15452464.9403613},
+{{8, 4, 7, {171.057250833,-44.402220361,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4383682.10598832, 8549530.45908753, 15620894.4924296},
+{{8, 4, 7, {171.360748472,-43.748711556,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4456298.18308237, 8549530.45908754, 15548278.4153355},
+{{8, 4, 7, {171.549771306,-42.333694278,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4613502.29276327, 8549530.45908753, 15391074.3056546},
+{{8, 4, 7, {171.581260056,-41.810802861,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4671584.03492437, 8549530.45908754, 15332992.5634935},
+{{8, 4, 7, {172.109028194,-41.289911528,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4729438.31462099, 8549530.45908753, 15275138.2837969},
+{{8, 4, 7, {172.6720465,-40.714759056,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4793313.13554601, 8549530.45908754, 15211263.4628719},
+{{8, 4, 7, {172.727193583,-43.590637583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4473861.66485194, 8549530.45908753, 15530714.933566},
+{{8, 4, 7, {173.010133389,-42.689116583,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4574019.640636, 8549530.45908754, 15430556.9577819},
+{{8, 4, 7, {173.299316806,-41.274544722,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4731144.99254062, 8549530.45908754, 15273431.6058773},
+{{8, 4, 7, {173.802074111,-41.544486667,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4701163.86142202, 8549530.45908754, 15303412.7369959},
+{{8, 4, 7, {174.22801175,-39.135758306,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4968639.63588687, 8549530.45908754, 15035936.962531},
+{{8, 4, 7, {174.764339361,-36.879865278,0.9999,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7948705.50604163, -5218451.08592923, 8548705.50604163, 14784125.0548288},
+{{8, 4, 7, {174.776623111,-41.301319639,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4728171.29681831, 8549530.45908754, 15276405.3015996},
+{{8, 4, 7, {175.488099611,-40.241947139,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4845817.49876657, 8549530.45908754, 15158759.0996513},
+{{8, 4, 7, {175.640036806,-39.512470389,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4926815.26039816, 8549530.45908754, 15077761.3380198},
+{{8, 4, 7, {175.647349667,-40.925532639,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -4769905.95772054, 8549530.45908754, 15234670.6406974},
+{{8, 4, 7, {176.46619725,-37.761249806,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -5121221.11127107, 8549530.45908754, 14883355.4871468},
+{{8, 4, 7, {176.673680528,-39.650929306,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908753, -4911442.20418344, 8549530.45908754, 15093134.3942345},
+{{8, 4, 7, {177.885636278,-38.624702778,1,300000,700000,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7949530.45908754, -5025375.11246985, 8549530.45908753, 14979201.4859481},
+{{8, 4, 7, {21,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {21,0,1,1500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -6749530.45908754, -10002288.299209, 9749530.45908754, 10002288.299209},
+{{8, 4, 7, {24,0,1,2500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -5749530.45908754, -10002288.299209, 10749530.4590875, 10002288.299209},
+{{8, 4, 7, {27,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {27,0,1,3500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -4749530.45908754, -10002288.299209, 11749530.4590875, 10002288.299209},
+{{8, 4, 7, {3,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {30,0,1,4500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -3749530.45908754, -10002288.299209, 12749530.4590875, 10002288.299209},
+{{8, 4, 7, {33,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {39,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {45,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
+{{8, 4, 7, {9,0,0.9996,1500000,0,0}, 0,-225,-65,9, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -6746230.6469039, -9998287.38388927, 9746230.6469039, 9998287.38388927},
+{{8, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746230.6469039, -9998287.38388927, 8746230.6469039, 9998287.38388927},
 
 // Added bounds for PSAD56 (AJD, Encom 2005)
-{{8, 4, 7, {-75,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 18N (Encom 2005)
-{{8, 4, 7, {-69,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PASD56 19N (Encom 2005)
-{{8, 4, 7, {-63,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 20N (Encom 2005)
-{{8, 4, 7, {-57,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 21N (Encom 2005)
-{{8, 4, 7, {-81,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 17S (Encom 2005)
-{{8, 4, 7, {-75,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PASD56 18S (Encom 2005)
-{{8, 4, 7, {-69,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 19S (Encom 2005)
-{{8, 4, 7, {-63,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 20S (Encom 2005)
-{{8, 4, 7, {-80.5,0,0.99983008,222000,1426834.743,0}, 0,-288, 175, -376, {0,0,0,0,0}},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU WEST ZONE (Encom 2005)
-{{8, 4, 7, {-76,0,0.99932994,720000,1039979.159,0}, 0,-288, 175, -376, {0,0,0,0,0}},    -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU CENTRAL ZONE (Encom 2005)
-{{8, 4, 7, {-70.5,0,0.99952992,1324000,1040084.558,0}, 0,-288, 175, -376, {0,0,0,0,0}}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU EAST ZONE (Encom 2005)
+{{8, 4, 7, {-75,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 18N (Encom 2005)
+{{8, 4, 7, {-69,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PASD56 19N (Encom 2005)
+{{8, 4, 7, {-63,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 20N (Encom 2005)
+{{8, 4, 7, {-57,0,0.9996,500000,0,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 21N (Encom 2005)
+{{8, 4, 7, {-81,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 17S (Encom 2005)
+{{8, 4, 7, {-75,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PASD56 18S (Encom 2005)
+{{8, 4, 7, {-69,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 19S (Encom 2005)
+{{8, 4, 7, {-63,0,0.9996,500000,10000000,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PSAD56 20S (Encom 2005)
+{{8, 4, 7, {-80.5,0,0.99983008,222000,1426834.743,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU WEST ZONE (Encom 2005)
+{{8, 4, 7, {-76,0,0.99932994,720000,1039979.159,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},    -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU CENTRAL ZONE (Encom 2005)
+{{8, 4, 7, {-70.5,0,0.99952992,1324000,1040084.558,0}, 0,-288, 175, -376, {0,0,0,0,0}, 0,0,0,0,0,0,0,0}, -7745874.38491761, -9998000.59030393, 8745874.38491761, 9998000.59030393}, // PERU EAST ZONE (Encom 2005)
 
-{{8, 6, 7, {17,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {19,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {19,0,1,0,3700000,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -6301867.55187774, 8249527.70018454, 13701867.5518777},
-{{8, 6, 7, {21,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {23,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {25,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {27,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {29,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 6, 7, {31,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
-{{8, 7, 7, {-102,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-105,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-105,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-105,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-108,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-111,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-111,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-111,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-114,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-117,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-117,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-117,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-120,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-123,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-123,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-123,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-126,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-129,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-129,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-129,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-132,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-135,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-135,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-135,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-138,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-141,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
-{{8, 7, 7, {-141,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
-{{8, 7, 7, {-141,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-147,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-15,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-153,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-159,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-165,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
-{{8, 7, 7, {-171,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-177,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-21,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-27,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-33,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-39,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-45,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-51,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-53,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-55.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-56,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-57,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-58.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-61.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-63,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-64.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-67.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-69,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-69,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-70.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-73.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-75,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-75,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-76.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-79.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-81,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-81,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-81,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-82.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-84,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-87,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-87,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-87,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-9,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-90,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-93,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
-{{8, 7, 7, {-93,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
-{{8, 7, 7, {-93,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-96,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 7, {-99,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-99,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
-{{8, 7, 7, {-99,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
-{{8, 7, 8, {-104.3333333333,31,0.9999090909,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562433.5032163, -44066372.5582056, 27562433.5032163, 21556716.5402837},
-{{8, 7, 8, {-105.1666666667,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
-{{8, 7, 8, {-106.25,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
-{{8, 7, 8, {-107.3333333333,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
-{{8, 7, 8, {-107.8333333333,31,0.9999166667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562638.5414399, -44066706.4265826, 27562638.5414399, 21556879.8645045},
-{{8, 7, 8, {-108.75,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
-{{8, 7, 8, {-110.0833333333,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
-{{8, 7, 8, {-110.1666666667,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
-{{8, 7, 8, {-111.9166666667,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
-{{8, 7, 8, {-112.1666666667,41.6666666667,0.9999473684,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563469.4796944, -47951082.5341968, 27563469.4796945, 17674518.6804598},
-{{8, 7, 8, {-113.75,31,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563089.6212014, -44067440.9299605, 27563089.6212014, 21557239.1743409},
-{{8, 7, 8, {-114,41.6666666667,0.9999473684,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563469.4796945, -47951082.5341968, 27563469.4796945, 17674518.6804598},
-{{8, 7, 8, {-115.5833333333,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
-{{8, 7, 8, {-115.75,41.6666666667,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563089.6212014, -47950409.5005354, 27563089.6212014, 17674270.6037659},
-{{8, 7, 8, {-116.6666666667,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
-{{8, 7, 8, {-118.5833333333,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
-{{8, 7, 8, {-142,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-146,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-150,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-154,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-155.5,18.8333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -39647492.5170134, 27563991.7861373, 25979375.2268425},
-{{8, 7, 8, {-156.6666666667,20.3333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861374, -40192224.7269965, 27563991.7861373, 25434643.0168594},
-{{8, 7, 8, {-158,21.1666666667,0.99999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564623.2994273, -40495839.074036, 27564623.2994273, 25132560.0122577},
-{{8, 7, 8, {-158,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-159.5,21.8333333333,0.99999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564623.2994273, -40738001.9175015, 27564623.2994273, 24890397.1687922},
-{{8, 7, 8, {-160.1666666667,21.6666666667,1,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564893.9483668, -40677866.1507286, 27564893.9483668, 24951189.2261189},
-{{8, 7, 8, {-162,54,0.9999,700000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26362187.458972, -52447364.8503891, 27762187.458972, 13175127.6209207},
-{{8, 7, 8, {-166,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
-{{8, 7, 8, {-170,54,0.9999,600000,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -26462187.458972, -52447364.8503891, 27662187.458972, 13175127.6209207},
-{{8, 7, 8, {-68.5,43.8333333333,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -48738387.3899167, 27562187.458972, 16884105.0813931},
-{{8, 7, 8, {-70.1666666667,42.8333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -48377155.1233007, 27563991.7861373, 17249712.6205552},
-{{8, 7, 8, {-71.5,41.0833333333,0.99999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564724.7927796, -47740760.2162526, 27564724.7927796, 17887884.9789988},
-{{8, 7, 8, {-71.6666666667,42.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -48255675.547233, 27563991.7861373, 17371192.1966229},
-{{8, 7, 8, {-72.5,42.5,0.9999642857,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563927.3446249, -48255560.6466395, 27563927.3446248, 17371150.8344356},
-{{8, 7, 8, {-74.3333333333,40,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -47344806.5947758, 27563991.7861373, 18282061.1490801},
-{{8, 7, 8, {-74.6666666667,38.8333333333,0.999975,2000000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -25064217.3260181, -46920262.1007603, 29064217.3260181, 18707152.5497028},
-{{8, 7, 8, {-75.4166666667,38,0.999995,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564758.6238971, -46617719.2903186, 27564758.6238971, 19011007.941252},
-{{8, 7, 8, {-76.5833333333,40,0.9999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563202.392495, -47343425.6569741, 27563202.392495, 18281527.9039123},
-{{8, 7, 8, {-78.5833333333,40,0.9999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563202.392495, -47343425.6569741, 27563202.392495, 18281527.9039123},
-{{8, 7, 8, {-81,24.3333333333,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -41644259.2047719, 27563301.8965776, 23980935.6413366},
-{{8, 7, 8, {-82,24.3333333333,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -41644259.2047719, 27563301.8965776, 23980935.6413366},
-{{8, 7, 8, {-82.1666666667,30,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -43702304.8531186, 27562187.458972, 21920187.6181912},
-{{8, 7, 8, {-84.1666666667,30,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26562187.458972, -43702304.8531186, 27562187.458972, 21920187.6181912},
-{{8, 7, 8, {-85.6666666667,37.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -46434335.8091192, 27563991.7861373, 19192531.9347367},
-{{8, 7, 8, {-85.8333333333,30.5,0.99996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563811.3526089, -43886764.6396605, 27563811.3526089, 21739665.5749719},
-{{8, 7, 8, {-87.0833333333,37.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563991.7861373, -46434335.8091192, 27563991.7861373, 19192531.9347367},
-{{8, 7, 8, {-87.5,30,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563089.6212014, -43703761.7408458, 27563089.6212014, 21920918.3634556},
-{{8, 7, 8, {-88.3333333333,36.6666666667,0.999975,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564217.3260181, -46131317.1820757, 27564217.3260181, 19496097.4683874},
-{{8, 7, 8, {-88.8333333333,29.6666666667,0.999996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26564785.688791, -43585279.1789159, 27564785.688791, 22043513.6817101},
-{{8, 7, 8, {-90.1666666667,36.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -46129756.82046, 27563301.8965776, 19495438.0256486},
-{{8, 7, 8, {-90.3333333333,30.5,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -43885938.5041009, 27563301.8965776, 21739256.3420077},
-{{8, 7, 8, {-90.5,35.8333333333,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563089.6212014, -45826045.0626944, 27563089.6212014, 19798635.041607},
-{{8, 7, 8, {-92.5,35.8333333333,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563089.6212014, -45826045.0626944, 27563089.6212014, 19798635.041607},
-{{8, 7, 8, {-94.5,36.1666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -26563301.8965776, -45947740.2967367, 27563301.8965776, 19677454.5493719},
-{{8, 9, 7, {-2,49,0.9996012717,400000,-100000,0}, 0,375,-111,431, {0,0,0,0,0}},  -7845061.1011034, -15524202.1641258, 8645061.1011034, 4470074.53373206},
-{{8,  10,7, {15.808277777800001, 0.0, 1.0, 1500000, 0.0, 0.0}, 0, 419.3836, 99.3335, 591.3451, {-0.850389, -1.817277, 7.862238, -0.99496, 0}}, -1e9, -1e9, 1e9, 1e9}, // Encom 2005 (AJD) - to Support Swedish
-{{9, 2, 7, {132,0,-36,-18,0,0}, 0,-133,-48,148, {0,0,0,0,0}},  -20488603.5475955, -35940818.6722945, 20488603.5475955, 5036388.42289653},
-{{9, 2, 7, {132,0,-36,-18,0,0}, 0,-134,-48,149, {0,0,0,0,0}},  -20488603.5475955, -35940818.6722945, 20488603.5475955, 5036388.42289653},
-{{9, 28, 7, {23,-23,-18,-32,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}},  -21500589.3169017, -34197433.4604502, 21500589.3169017, 7592182.07528184},
-{{9, 29, 0, {110,10,25,40,0,0}, 0,0,0,0, {0,0,0,0,0}},  -11362.8133775181, -3609.79239961301, 11362.8133775181, 19115.8343554232},
-{{9, 29, 0, {132.5,-10,-21.5,-33.5,0,0}, 0,0,0,0, {0,0,0,0,0}},  -12557.486987589, -21368.9438624525, 12557.486987589, 3746.0301127255},
-{{9, 29, 0, {25,35,40,65,0,0}, 0,0,0,0, {0,0,0,0,0}},  -9044.42142037436, -4777.87654505631, 9044.42142037436, 13310.9662956924},
-{{9, 29, 0, {47.5,25,15,35,0,0}, 0,0,0,0, {0,0,0,0,0}},  -13390.3137726925, -4887.09300250369, 13390.3137726925, 21675.1568723853},
-{{9, 29, 0, {78,23,22,33,0,0}, 0,0,0,0, {0,0,0,0,0}},  -12554.0796051134, -4624.86888238625, 12554.0796051134, 20483.2903278405},
-{{9, 29, 0, {95,40,20,60,0,0}, 0,0,0,0, {0,0,0,0,0}},  -10369.4020979755, -5634.63503836129, 10369.4020979755, 15104.1691575898},
-{{9, 6, 7, {23,-23,-18,-32,0,0}, 0,-136,-108,-292, {0,0,0,0,0}},  -21500683.2503467, -34197901.8785539, 21500683.2503467, 7591931.73862156},
-{{9, 7, 7, {-154,50,55,65,0,0}, 0,-5,135,172, {0,0,0,0,0}},  -13752073.5330064, -8947886.69972899, 13752073.5330064, 18556260.3662838},
-{{9, 7, 7, {-157,3,8,18,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -24775369.1253827, -6004013.76934506, 34739284.1330387, 43890186.5919339},
-{{9, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -16687870.3794973, -7101873.97827787, 16687870.3794973, 26273866.7807168},
-{{9, 7, 7, {-96,23,29.5,45.5,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -16900972.6938504, -6971893.13585582, 16900972.6938504, 26830052.251845},
-{{11, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -40075452.7386388, -14691640.6260036, 40075452.7386388, 14691640.6260036},
-{{12, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -34012036.7392828, -8625248.51472, 34012036.7392828, 8625248.51472},
-{{13, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -36080583.9779795, -9020145.99431898, 36080583.9779795, 9020145.99431898},
-{{14, 29, 0, {-60,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -17523.9133905318, -5257.17401715949, 24533.4787467445, 5257.17401715949},
-{{14, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -33842774.0824052, -8460693.52060123, 33842774.0824052, 8460693.52060123},
-{{15, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -35347572.9807667, -8836893.24519168, 35347572.9807667, 8836893.24519168},
-{{16, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -40075452.7386388, -10018863.1846597, 40075452.7386388, 10018863.1846597},
-{{18, 4, 7, {173,-41,2510000,6023150,0,0}, 0,84,-22,209, {0,0,0,0,0}},  1001587.21174105, 4254077.4935345, 4082370.4786608, 7690559.24125294},
-{{20, 0, 7, {0,0,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -100000000, -100000000, 100000000, 100000000},
-{{20, 10, 7, {5.387638889,52.156160556,0.9999079,155000,463000,0}, 0,593,26,478, {0,0,0,0,0}},  -99845000, -99537000, 100155000, 100463000},
-{{20, 28, 7, {0,-90,0.994,2000000,2000000,0}, 0,0,0,0, {0,0,0,0,0}},  -98000000, -98000000, 102000000, 102000000},
-{{20, 28, 7, {0,90,0.994,2000000,2000000,0}, 0,0,0,0, {0,0,0,0,0}},  -98000000, -98000000, 102000000, 102000000},
-{{21, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -688662.0096834, -1193504.42233962, 42993.625661512, 466993.370035908},
-{{22, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -2981314.87489887, -52667593.719744, 93265053.7016014, 912774.431510712},
-{{23, 4, 7, {15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -142680.459281219, -57483.8396628927, 56778.2298793441, 142611.243106357},
-{{24, 4, 7, {21,0,1,1500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}},   1250000, 6500000, 1750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 1
-{{24, 4, 7, {24,0,1,2500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}},   2250000, 6500000, 2750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 2
-{{24, 4, 7, {27,0,1,3500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}},   2850000, 6500000, 3850000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 3
-{{24, 4, 7, {30,0,1,4500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}},   4250000, 6500000, 4750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 4
-{{25, 10, 7, {7.4395833333,46.9524055555,0,0,0,0}, 0,660.077,13.551,369.344, {0.804816,0.577692,0.952236,5.66,0}},  -100000000, -100000000, 100000000, 100000000},
-{{25, 10, 7, {7.4395833333,46.9524055555,600000,200000,0,0}, 0,660.077,13.551,369.344, {0.804816,0.577692,0.952236,5.66,0}},  -99400000, -99800000, 100600000, 100200000},
-{{26, 29, 0, {-60,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -20751.2174140408, -12383.4550682633, 29051.7043796571, 12383.4550682633},
-{{26, 29, 0, {-85.5,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -18987.3639338473, -12383.4550682633, 30815.5578598506, 12383.4550682633},
-{{26, 29, 0, {20,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -26284.8753911183, -12383.4550682633, 23518.0464025796, 12383.4550682633},
-{{26, 4, 7, {0,60,0,0,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -20089005.2889087, -9990138.39344294, 20089005.2889087, 9990138.39344294},
-{{26, 4, 7, {0,70,0,0,0,0}, 0,-87,-98,-121, {0,0,0,0,0}},  -13747868.5914983, -6836730.23471024, 13747868.5914983, 6836730.23471024},
-{{26, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -40075452.7386388, -19928981.8895549, 40075452.7386388, 19928981.8895549},
-{{27, 11, 7, {78,0,1200000,0,0,0}, 0,289,734,257, {0,0,0,0,0}},  -18834804.515364, -15340324.8240999, 21234804.515364, 15340324.8240999},
-{{27, 24, 7, {-37,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-38,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-39,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-41,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-42,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-43,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-45,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-48,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-49,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-51,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-52,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-54,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-56,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-59,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-62,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-63,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-65,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 24, 7, {-70,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
-{{27, 28, 7, {-100,40,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -20037508.3427892, -19771855.3330942, 20037508.3427892, 10912797.2721118},
-{{27, 28, 7, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -20037508.3427892, -15342326.302603, 20037508.3427892, 15342326.302603},
-{{27, 28, 7, {78,0,1200000,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -18837508.3427892, -15342326.302603, 21237508.3427892, 15342326.302603},
-{{28, 0, 7, {-100,-80,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -19889431.1404394, -20026376.3929389, 19889431.1404395, 20026376.3929385},
-{{28, 0, 7, {-100,-80,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -10014588.6119777, -10018754.1713946, 10014588.6119777, 10018754.1713946},
-{{28, 0, 7, {-100,40,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -19610690.9824974, -20026376.3936683, 19610690.9824974, 20026376.3936695},
-{{28, 0, 7, {-100,40,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -10018734.8959557, -10018754.1713946, 10018734.8959557, 10018754.1713946},
-{{28, 0, 7, {0,-60,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -19758589.084291, -20026376.393667, 19758589.084291, 20026376.3936708},
-{{28, 0, 7, {0,-60,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -10018731.6857622, -10018754.1713946, 10018731.6857622, 10018754.1713946},
-{{28, 0, 7, {0,80,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -19889431.1404395, -20026376.3929385, 19889431.1404395, 20026376.3929389},
-{{28, 0, 7, {0,80,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  -10014588.6119777, -10018754.1713946, 10014588.6119777, 10018754.1713946},
-{{28, 7, 7, {0,-90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -10018863.1846597, -10018863.1846597, 10018863.1846597, 10018863.1846597},
-{{28, 7, 7, {0,90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}},  -10018863.1846597, -10018863.1846597, 10018863.1846597, 10018863.1846597},
+{{8, 6, 7, {17,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {19,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {19,0,1,0,3700000,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -6301867.55187774, 8249527.70018454, 13701867.5518777},
+{{8, 6, 7, {21,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {23,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {25,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {27,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {29,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 6, 7, {31,0,1,0,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -8249527.70018454, -10001867.5518777, 8249527.70018454, 10001867.5518777},
+{{8, 7, 7, {-102,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-105,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-105,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-105,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-108,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-111,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-111,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-111,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-114,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-117,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-117,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-117,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-120,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-123,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-123,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-123,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-126,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-129,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-129,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-129,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-132,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-135,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-135,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-135,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-138,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-141,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
+{{8, 7, 7, {-141,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
+{{8, 7, 7, {-141,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-147,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-15,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-153,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-159,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-165,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
+{{8, 7, 7, {-171,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-177,0,0.9996,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-21,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-27,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-33,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-39,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-45,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-51,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-53,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-55.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-56,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-57,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-58.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-61.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-63,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-64.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-67.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-69,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-69,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-70.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-73.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-75,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-75,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-76.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-79.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-81,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-81,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578484, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-81,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-82.5,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-84,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-87,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-87,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-87,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463713, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-9,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-90,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-93,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
+{{8, 7, 7, {-93,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578484, 9997887.28799036},
+{{8, 7, 7, {-93,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-96,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 7, {-99,0,0.9996,500000,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-99,0,0.9996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7746096.41578485, -9997887.28799036, 8746096.41578485, 9997887.28799036},
+{{8, 7, 7, {-99,0,0.9999,304800,0,0}, 0,-10,158,187, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7943771.23463712, -10000887.8544033, 8553371.23463712, 10000887.8544033},
+{{8, 7, 8, {-104.3333333333,31,0.9999090909,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562433.5032163, -44066372.5582056, 27562433.5032163, 21556716.5402837},
+{{8, 7, 8, {-105.1666666667,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
+{{8, 7, 8, {-106.25,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
+{{8, 7, 8, {-107.3333333333,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
+{{8, 7, 8, {-107.8333333333,31,0.9999166667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562638.5414399, -44066706.4265826, 27562638.5414399, 21556879.8645045},
+{{8, 7, 8, {-108.75,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
+{{8, 7, 8, {-110.0833333333,40.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -47586452.7340335, 27563301.8965776, 18038742.112075},
+{{8, 7, 8, {-110.1666666667,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
+{{8, 7, 8, {-111.9166666667,31,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -44065971.9187976, 27562187.458972, 21556520.5525122},
+{{8, 7, 8, {-112.1666666667,41.6666666667,0.9999473684,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563469.4796944, -47951082.5341968, 27563469.4796945, 17674518.6804598},
+{{8, 7, 8, {-113.75,31,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563089.6212014, -44067440.9299605, 27563089.6212014, 21557239.1743409},
+{{8, 7, 8, {-114,41.6666666667,0.9999473684,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563469.4796945, -47951082.5341968, 27563469.4796945, 17674518.6804598},
+{{8, 7, 8, {-115.5833333333,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
+{{8, 7, 8, {-115.75,41.6666666667,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563089.6212014, -47950409.5005354, 27563089.6212014, 17674270.6037659},
+{{8, 7, 8, {-116.6666666667,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
+{{8, 7, 8, {-118.5833333333,34.75,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -45430239.3046952, 27562187.458972, 20192253.1666146},
+{{8, 7, 8, {-142,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-146,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-150,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-154,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-155.5,18.8333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -39647492.5170134, 27563991.7861373, 25979375.2268425},
+{{8, 7, 8, {-156.6666666667,20.3333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861374, -40192224.7269965, 27563991.7861373, 25434643.0168594},
+{{8, 7, 8, {-158,21.1666666667,0.99999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564623.2994273, -40495839.074036, 27564623.2994273, 25132560.0122577},
+{{8, 7, 8, {-158,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-159.5,21.8333333333,0.99999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564623.2994273, -40738001.9175015, 27564623.2994273, 24890397.1687922},
+{{8, 7, 8, {-160.1666666667,21.6666666667,1,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564893.9483668, -40677866.1507286, 27564893.9483668, 24951189.2261189},
+{{8, 7, 8, {-162,54,0.9999,700000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26362187.458972, -52447364.8503891, 27762187.458972, 13175127.6209207},
+{{8, 7, 8, {-166,54,0.9999,500000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -52447364.8503891, 27562187.458972, 13175127.6209207},
+{{8, 7, 8, {-170,54,0.9999,600000,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26462187.458972, -52447364.8503891, 27662187.458972, 13175127.6209207},
+{{8, 7, 8, {-68.5,43.8333333333,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -48738387.3899167, 27562187.458972, 16884105.0813931},
+{{8, 7, 8, {-70.1666666667,42.8333333333,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -48377155.1233007, 27563991.7861373, 17249712.6205552},
+{{8, 7, 8, {-71.5,41.0833333333,0.99999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564724.7927796, -47740760.2162526, 27564724.7927796, 17887884.9789988},
+{{8, 7, 8, {-71.6666666667,42.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -48255675.547233, 27563991.7861373, 17371192.1966229},
+{{8, 7, 8, {-72.5,42.5,0.9999642857,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563927.3446249, -48255560.6466395, 27563927.3446248, 17371150.8344356},
+{{8, 7, 8, {-74.3333333333,40,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -47344806.5947758, 27563991.7861373, 18282061.1490801},
+{{8, 7, 8, {-74.6666666667,38.8333333333,0.999975,2000000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -25064217.3260181, -46920262.1007603, 29064217.3260181, 18707152.5497028},
+{{8, 7, 8, {-75.4166666667,38,0.999995,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564758.6238971, -46617719.2903186, 27564758.6238971, 19011007.941252},
+{{8, 7, 8, {-76.5833333333,40,0.9999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563202.392495, -47343425.6569741, 27563202.392495, 18281527.9039123},
+{{8, 7, 8, {-78.5833333333,40,0.9999375,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563202.392495, -47343425.6569741, 27563202.392495, 18281527.9039123},
+{{8, 7, 8, {-81,24.3333333333,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -41644259.2047719, 27563301.8965776, 23980935.6413366},
+{{8, 7, 8, {-82,24.3333333333,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -41644259.2047719, 27563301.8965776, 23980935.6413366},
+{{8, 7, 8, {-82.1666666667,30,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -43702304.8531186, 27562187.458972, 21920187.6181912},
+{{8, 7, 8, {-84.1666666667,30,0.9999,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26562187.458972, -43702304.8531186, 27562187.458972, 21920187.6181912},
+{{8, 7, 8, {-85.6666666667,37.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -46434335.8091192, 27563991.7861373, 19192531.9347367},
+{{8, 7, 8, {-85.8333333333,30.5,0.99996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563811.3526089, -43886764.6396605, 27563811.3526089, 21739665.5749719},
+{{8, 7, 8, {-87.0833333333,37.5,0.9999666667,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563991.7861373, -46434335.8091192, 27563991.7861373, 19192531.9347367},
+{{8, 7, 8, {-87.5,30,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563089.6212014, -43703761.7408458, 27563089.6212014, 21920918.3634556},
+{{8, 7, 8, {-88.3333333333,36.6666666667,0.999975,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564217.3260181, -46131317.1820757, 27564217.3260181, 19496097.4683874},
+{{8, 7, 8, {-88.8333333333,29.6666666667,0.999996,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26564785.688791, -43585279.1789159, 27564785.688791, 22043513.6817101},
+{{8, 7, 8, {-90.1666666667,36.6666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -46129756.82046, 27563301.8965776, 19495438.0256486},
+{{8, 7, 8, {-90.3333333333,30.5,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -43885938.5041009, 27563301.8965776, 21739256.3420077},
+{{8, 7, 8, {-90.5,35.8333333333,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563089.6212014, -45826045.0626944, 27563089.6212014, 19798635.041607},
+{{8, 7, 8, {-92.5,35.8333333333,0.9999333333,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563089.6212014, -45826045.0626944, 27563089.6212014, 19798635.041607},
+{{8, 7, 8, {-94.5,36.1666666667,0.9999411765,500000,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26563301.8965776, -45947740.2967367, 27563301.8965776, 19677454.5493719},
+{{8, 9, 7, {-2,49,0.9996012717,400000,-100000,0}, 0,375,-111,431, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -7845061.1011034, -15524202.1641258, 8645061.1011034, 4470074.53373206},
+{{8,  10,7, {15.808277777800001, 0.0, 1.0, 1500000, 0.0, 0.0}, 0, 419.3836, 99.3335, 591.3451, {-0.850389, -1.817277, 7.862238, -0.99496, 0}, 0,0,0,0,0,0,0,0}, -1e9, -1e9, 1e9, 1e9}, // Encom 2005 (AJD) - to Support Swedish
+{{9, 2, 7, {132,0,-36,-18,0,0}, 0,-133,-48,148, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20488603.5475955, -35940818.6722945, 20488603.5475955, 5036388.42289653},
+{{9, 2, 7, {132,0,-36,-18,0,0}, 0,-134,-48,149, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20488603.5475955, -35940818.6722945, 20488603.5475955, 5036388.42289653},
+{{9, 28, 7, {23,-23,-18,-32,0,0}, 0,-134.73,-110.92,-292.66, {0,0,0,1,0}, 0,0,0,0,0,0,0,0},  -21500589.3169017, -34197433.4604502, 21500589.3169017, 7592182.07528184},
+{{9, 29, 0, {110,10,25,40,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -11362.8133775181, -3609.79239961301, 11362.8133775181, 19115.8343554232},
+{{9, 29, 0, {132.5,-10,-21.5,-33.5,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -12557.486987589, -21368.9438624525, 12557.486987589, 3746.0301127255},
+{{9, 29, 0, {25,35,40,65,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -9044.42142037436, -4777.87654505631, 9044.42142037436, 13310.9662956924},
+{{9, 29, 0, {47.5,25,15,35,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -13390.3137726925, -4887.09300250369, 13390.3137726925, 21675.1568723853},
+{{9, 29, 0, {78,23,22,33,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -12554.0796051134, -4624.86888238625, 12554.0796051134, 20483.2903278405},
+{{9, 29, 0, {95,40,20,60,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10369.4020979755, -5634.63503836129, 10369.4020979755, 15104.1691575898},
+{{9, 6, 7, {23,-23,-18,-32,0,0}, 0,-136,-108,-292, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -21500683.2503467, -34197901.8785539, 21500683.2503467, 7591931.73862156},
+{{9, 7, 7, {-154,50,55,65,0,0}, 0,-5,135,172, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -13752073.5330064, -8947886.69972899, 13752073.5330064, 18556260.3662838},
+{{9, 7, 7, {-157,3,8,18,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -24775369.1253827, -6004013.76934506, 34739284.1330387, 43890186.5919339},
+{{9, 7, 7, {-96,23,20,60,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -16687870.3794973, -7101873.97827787, 16687870.3794973, 26273866.7807168},
+{{9, 7, 7, {-96,23,29.5,45.5,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -16900972.6938504, -6971893.13585582, 16900972.6938504, 26830052.251845},
+{{11, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -40075452.7386388, -14691640.6260036, 40075452.7386388, 14691640.6260036},
+{{12, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -34012036.7392828, -8625248.51472, 34012036.7392828, 8625248.51472},
+{{13, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -36080583.9779795, -9020145.99431898, 36080583.9779795, 9020145.99431898},
+{{14, 29, 0, {-60,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -17523.9133905318, -5257.17401715949, 24533.4787467445, 5257.17401715949},
+{{14, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -33842774.0824052, -8460693.52060123, 33842774.0824052, 8460693.52060123},
+{{15, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -35347572.9807667, -8836893.24519168, 35347572.9807667, 8836893.24519168},
+{{16, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -40075452.7386388, -10018863.1846597, 40075452.7386388, 10018863.1846597},
+{{18, 4, 7, {173,-41,2510000,6023150,0,0}, 0,84,-22,209, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  1001587.21174105, 4254077.4935345, 4082370.4786608, 7690559.24125294},
+{{20, 0, 7, {0,0,1,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -100000000, -100000000, 100000000, 100000000},
+{{20, 10, 7, {5.387638889,52.156160556,0.9999079,155000,463000,0}, 0,593,26,478, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -99845000, -99537000, 100155000, 100463000},
+{{20, 28, 7, {0,-90,0.994,2000000,2000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -98000000, -98000000, 102000000, 102000000},
+{{20, 28, 7, {0,90,0.994,2000000,2000000,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -98000000, -98000000, 102000000, 102000000},
+{{21, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -688662.0096834, -1193504.42233962, 42993.625661512, 466993.370035908},
+{{22, 4, 7, {9,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -2981314.87489887, -52667593.719744, 93265053.7016014, 912774.431510712},
+{{23, 4, 7, {15,0,0.9996,500000,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -142680.459281219, -57483.8396628927, 56778.2298793441, 142611.243106357},
+{{24, 4, 7, {21,0,1,1500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}, 0,0,0,0,0,0,0,0},   1250000, 6500000, 1750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 1
+{{24, 4, 7, {24,0,1,2500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}, 0,0,0,0,0,0,0,0},   2250000, 6500000, 2750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 2
+{{24, 4, 7, {27,0,1,3500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}, 0,0,0,0,0,0,0,0},   2850000, 6500000, 3850000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 3
+{{24, 4, 7, {30,0,1,4500000,0,0}, 0,-96.062, -82.428, -121.754, {-4.801, -0.345, 1.376, 1.496, 0}, 0,0,0,0,0,0,0,0},   4250000, 6500000, 4750000, 8000000}, // Encom 2005 (AJD) - to support Finnish KKJ Zone 4
+{{25, 10, 7, {7.4395833333,46.9524055555,0,0,0,0}, 0,660.077,13.551,369.344, {0.804816,0.577692,0.952236,5.66,0}, 0,0,0,0,0,0,0,0},  -100000000, -100000000, 100000000, 100000000},
+{{25, 10, 7, {7.4395833333,46.9524055555,600000,200000,0,0}, 0,660.077,13.551,369.344, {0.804816,0.577692,0.952236,5.66,0}, 0,0,0,0,0,0,0,0},  -99400000, -99800000, 100600000, 100200000},
+{{26, 29, 0, {-60,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20751.2174140408, -12383.4550682633, 29051.7043796571, 12383.4550682633},
+{{26, 29, 0, {-85.5,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -18987.3639338473, -12383.4550682633, 30815.5578598506, 12383.4550682633},
+{{26, 29, 0, {20,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -26284.8753911183, -12383.4550682633, 23518.0464025796, 12383.4550682633},
+{{26, 4, 7, {0,60,0,0,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20089005.2889087, -9990138.39344294, 20089005.2889087, 9990138.39344294},
+{{26, 4, 7, {0,70,0,0,0,0}, 0,-87,-98,-121, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -13747868.5914983, -6836730.23471024, 13747868.5914983, 6836730.23471024},
+{{26, 7, 7, {0,0,0,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -40075452.7386388, -19928981.8895549, 40075452.7386388, 19928981.8895549},
+{{27, 11, 7, {78,0,1200000,0,0,0}, 0,289,734,257, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -18834804.515364, -15340324.8240999, 21234804.515364, 15340324.8240999},
+{{27, 24, 7, {-37,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-38,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-39,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-41,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-42,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-43,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-45,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-48,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-49,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-51,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-52,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-54,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-56,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-59,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-62,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-63,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-65,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 24, 7, {-70,0,0,0,0,0}, 0,-57,1,-41, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037580.5994203, -15342381.4311037, 20037580.5994203, 15342381.4311037},
+{{27, 28, 7, {-100,40,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037508.3427892, -19771855.3330942, 20037508.3427892, 10912797.2721118},
+{{27, 28, 7, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -20037508.3427892, -15342326.302603, 20037508.3427892, 15342326.302603},
+{{27, 28, 7, {78,0,1200000,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -18837508.3427892, -15342326.302603, 21237508.3427892, 15342326.302603},
+{{28, 0, 7, {-100,-80,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -19889431.1404394, -20026376.3929389, 19889431.1404395, 20026376.3929385},
+{{28, 0, 7, {-100,-80,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10014588.6119777, -10018754.1713946, 10014588.6119777, 10018754.1713946},
+{{28, 0, 7, {-100,40,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -19610690.9824974, -20026376.3936683, 19610690.9824974, 20026376.3936695},
+{{28, 0, 7, {-100,40,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10018734.8959557, -10018754.1713946, 10018734.8959557, 10018754.1713946},
+{{28, 0, 7, {0,-60,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -19758589.084291, -20026376.393667, 19758589.084291, 20026376.3936708},
+{{28, 0, 7, {0,-60,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10018731.6857622, -10018754.1713946, 10018731.6857622, 10018754.1713946},
+{{28, 0, 7, {0,80,180,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -19889431.1404395, -20026376.3929385, 19889431.1404395, 20026376.3929389},
+{{28, 0, 7, {0,80,90,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10014588.6119777, -10018754.1713946, 10014588.6119777, 10018754.1713946},
+{{28, 7, 7, {0,-90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10018863.1846597, -10018863.1846597, 10018863.1846597, 10018863.1846597},
+{{28, 7, 7, {0,90,90,0,0,0}, 0,-8,160,176, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  -10018863.1846597, -10018863.1846597, 10018863.1846597, 10018863.1846597},
 
-{{0xff, 0, 0, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}},  0, 0, 0, 0}
+{{0xff, 0, 0, {0,0,0,0,0,0}, 0,0,0,0, {0,0,0,0,0}, 0,0,0,0,0,0,0,0},  0, 0, 0, 0}
 };
 
 
-#define TAB_EQUAL(a, b) (((a)<(b) ? ((b)-(a)) : ((a)-(b))) < 1e-6)
+#define TAB_EQUAL(a, b, eps) (fabs((a)-(b)) < eps)
 
+static char szPreviousMitabBoundsFile[2048] = { 0 };
+static VSIStatBufL sStatBoundsFile;
 
 /**********************************************************************
  *                     MITABLookupCoordSysBounds()
  *
  * Lookup bounds for specified TABProjInfo struct.
  *
+ * This can modify that passed TABProjInfo struct if a match is found
+ * in an external bound file with proj remapping.
+ *
  * Returns TRUE if valid bounds were found, FALSE otherwise.
  **********************************************************************/
 GBool MITABLookupCoordSysBounds(TABProjInfo *psCS,
                                 double &dXMin, double &dYMin,
-                                double &dXMax, double &dYMax)
+                                double &dXMax, double &dYMax,
+                                int bOnlyUserTable)
 {
     GBool bFound = FALSE;
-    MapInfoBoundsInfo *psList, **ppsList;
+    const MapInfoBoundsInfo *psList;
 
     /*-----------------------------------------------------------------
-     * Lookup table... 
-     * Lookup external file if one was loaded, then lookup internal table.
-     *
-     * Note that entries in lookup table with 0xff for projId, UnitsId, 
-     * means ignore that param, and 0xff in ellipsoidId means ignore the 
-     * whole datum.
-     *----------------------------------------------------------------*/
-    ppsList = gpapsExtBoundsList;
-    for( ; !bFound && ppsList && *ppsList; ppsList++)
+    * Try to load the user defined table if not loaded yet .
+    *----------------------------------------------------------------*/
+    const char * pszMitabBoundsFile = CPLGetConfigOption("MITAB_BOUNDS_FILE", NULL);
+    if (pszMitabBoundsFile != NULL && pszMitabBoundsFile[0] != '\0' )
     {
-        TABProjInfo *p = &((*ppsList)->sProj);
-
-        if (p->nProjId == psCS->nProjId &&
-            (p->nUnitsId == 0xff || p->nUnitsId == psCS->nUnitsId) &&
-            (p->nEllipsoidId == 0xff || 
-             (p->nEllipsoidId == psCS->nEllipsoidId &&
-              ( (p->nDatumId > 0 && p->nDatumId == psCS->nDatumId) ||
-                ((p->nDatumId <= 0 || psCS->nDatumId <= 0) &&
-                 TAB_EQUAL(p->dDatumShiftX, psCS->dDatumShiftX) &&
-                 TAB_EQUAL(p->dDatumShiftY, psCS->dDatumShiftY) &&
-                 TAB_EQUAL(p->dDatumShiftZ, psCS->dDatumShiftZ) &&
-                 TAB_EQUAL(p->adDatumParams[0], psCS->adDatumParams[0]) &&
-                 TAB_EQUAL(p->adDatumParams[1], psCS->adDatumParams[1]) &&
-                 TAB_EQUAL(p->adDatumParams[2], psCS->adDatumParams[2]) &&
-                 TAB_EQUAL(p->adDatumParams[3], psCS->adDatumParams[3]) &&
-                 TAB_EQUAL(p->adDatumParams[4], psCS->adDatumParams[4]) )))) &&
-            (TAB_EQUAL(p->adProjParams[0], psCS->adProjParams[0]) &&
-             TAB_EQUAL(p->adProjParams[1], psCS->adProjParams[1]) &&
-             TAB_EQUAL(p->adProjParams[2], psCS->adProjParams[2]) &&
-             TAB_EQUAL(p->adProjParams[3], psCS->adProjParams[3]) &&
-             TAB_EQUAL(p->adProjParams[4], psCS->adProjParams[4]) &&
-             TAB_EQUAL(p->adProjParams[5], psCS->adProjParams[5]) )  )
+        if( strcmp(pszMitabBoundsFile, szPreviousMitabBoundsFile) != 0)
+        {
+            CPLStrlcpy(szPreviousMitabBoundsFile, pszMitabBoundsFile,
+                       sizeof(szPreviousMitabBoundsFile));
+            MITABLoadCoordSysTable(pszMitabBoundsFile);
+            if( VSIStatL(pszMitabBoundsFile, &sStatBoundsFile) != 0 )
+            {
+                sStatBoundsFile.st_mtime = 0;
+            }
+        }
+        else
         {
-            dXMin = (*ppsList)->dXMin;
-            dYMin = (*ppsList)->dYMin;
-            dXMax = (*ppsList)->dXMax;
-            dYMax = (*ppsList)->dYMax;
-            bFound = TRUE;
+            /* Reload file if its modification file has changed */
+            VSIStatBufL sStat;
+            if( VSIStatL(pszMitabBoundsFile, &sStat) == 0 )
+            {
+                if( sStat.st_mtime != sStatBoundsFile.st_mtime )
+                {
+                    MITABLoadCoordSysTable(pszMitabBoundsFile);
+                    memcpy(&sStatBoundsFile, &sStat, sizeof(sStat));
+                }
+            }
         }
     }
+    else if ( szPreviousMitabBoundsFile[0] != '\0' )
+    {
+        MITABFreeCoordSysTable();
+        strcpy(szPreviousMitabBoundsFile, "");
+    }
 
-    psList = gasBoundsList;
-    for( ; !bFound && psList->sProj.nProjId!=0xff; psList++)
+    for(int iLoop=0; !bFound && iLoop < 2; iLoop++)
     {
-        TABProjInfo *p = &(psList->sProj);
+        /* MapInfo uses a hack to differentiate some SRS that have the same */
+        /* definition, but different bounds, e.g. Lambet 93 France with French */
+        /* Bounds or with European bounds. It alters slightly one of the projection */
+        /* parameters, e.g. std_parallel_1 = 49.00000000001 or 49.00000000002 */
+        double eps = (iLoop == 0) ? 1e-12 : 1e-6;
 
-        if (p->nProjId == psCS->nProjId &&
-            (p->nUnitsId == 0xff || p->nUnitsId == psCS->nUnitsId) &&
-            (p->nEllipsoidId == 0xff || 
-             (p->nEllipsoidId == psCS->nEllipsoidId &&
-              ( (p->nDatumId > 0 && p->nDatumId == psCS->nDatumId) ||
-                ((p->nDatumId <= 0 || psCS->nDatumId <= 0) &&
-                 TAB_EQUAL(p->dDatumShiftX, psCS->dDatumShiftX) &&
-                 TAB_EQUAL(p->dDatumShiftY, psCS->dDatumShiftY) &&
-                 TAB_EQUAL(p->dDatumShiftZ, psCS->dDatumShiftZ) &&
-                 TAB_EQUAL(p->adDatumParams[0], psCS->adDatumParams[0]) &&
-                 TAB_EQUAL(p->adDatumParams[1], psCS->adDatumParams[1]) &&
-                 TAB_EQUAL(p->adDatumParams[2], psCS->adDatumParams[2]) &&
-                 TAB_EQUAL(p->adDatumParams[3], psCS->adDatumParams[3]) &&
-                 TAB_EQUAL(p->adDatumParams[4], psCS->adDatumParams[4]) )))) &&
-            (TAB_EQUAL(p->adProjParams[0], psCS->adProjParams[0]) &&
-             TAB_EQUAL(p->adProjParams[1], psCS->adProjParams[1]) &&
-             TAB_EQUAL(p->adProjParams[2], psCS->adProjParams[2]) &&
-             TAB_EQUAL(p->adProjParams[3], psCS->adProjParams[3]) &&
-             TAB_EQUAL(p->adProjParams[4], psCS->adProjParams[4]) &&
-             TAB_EQUAL(p->adProjParams[5], psCS->adProjParams[5]) )  )
+        /*-----------------------------------------------------------------
+        * Lookup table...
+        * Lookup external file if one was loaded, then lookup internal table.
+        *
+        * Note that entries in lookup table with 0xff for projId, UnitsId,
+        * means ignore that param, and 0xff in ellipsoidId means ignore the
+        * whole datum.
+        *----------------------------------------------------------------*/
+        for( int i = 0 ; !bFound && i < nExtBoundsListCount; i++)
         {
-            dXMin = psList->dXMin;
-            dYMin = psList->dYMin;
-            dXMax = psList->dXMax;
-            dYMax = psList->dYMax;
-            bFound = TRUE;
+            TABProjInfo *p = &(gpasExtBoundsList[i].sProjIn);
+
+            if (p->nProjId == psCS->nProjId &&
+                (p->nUnitsId == 0xff || p->nUnitsId == psCS->nUnitsId) &&
+                (p->nEllipsoidId == 0xff ||
+                (p->nEllipsoidId == psCS->nEllipsoidId &&
+                ( (p->nDatumId > 0 && p->nDatumId == psCS->nDatumId) ||
+                    ((p->nDatumId <= 0 || psCS->nDatumId <= 0) &&
+                    TAB_EQUAL(p->dDatumShiftX, psCS->dDatumShiftX, eps) &&
+                    TAB_EQUAL(p->dDatumShiftY, psCS->dDatumShiftY, eps) &&
+                    TAB_EQUAL(p->dDatumShiftZ, psCS->dDatumShiftZ, eps) &&
+                    TAB_EQUAL(p->adDatumParams[0], psCS->adDatumParams[0], eps) &&
+                    TAB_EQUAL(p->adDatumParams[1], psCS->adDatumParams[1], eps) &&
+                    TAB_EQUAL(p->adDatumParams[2], psCS->adDatumParams[2], eps) &&
+                    TAB_EQUAL(p->adDatumParams[3], psCS->adDatumParams[3], eps) &&
+                    TAB_EQUAL(p->adDatumParams[4], psCS->adDatumParams[4], eps) )))) &&
+                (TAB_EQUAL(p->adProjParams[0], psCS->adProjParams[0], eps) &&
+                TAB_EQUAL(p->adProjParams[1], psCS->adProjParams[1], eps) &&
+                TAB_EQUAL(p->adProjParams[2], psCS->adProjParams[2], eps) &&
+                TAB_EQUAL(p->adProjParams[3], psCS->adProjParams[3], eps) &&
+                TAB_EQUAL(p->adProjParams[4], psCS->adProjParams[4], eps) &&
+                TAB_EQUAL(p->adProjParams[5], psCS->adProjParams[5], eps) )  )
+            {
+                memcpy(psCS, &gpasExtBoundsList[i].sBoundsInfo.sProj,
+                       sizeof(TABProjInfo));
+                dXMin = gpasExtBoundsList[i].sBoundsInfo.dXMin;
+                dYMin = gpasExtBoundsList[i].sBoundsInfo.dYMin;
+                dXMax = gpasExtBoundsList[i].sBoundsInfo.dXMax;
+                dYMax = gpasExtBoundsList[i].sBoundsInfo.dYMax;
+                bFound = TRUE;
+            }
+        }
+
+        psList = gasBoundsList;
+        for( ; !bOnlyUserTable && !bFound && psList->sProj.nProjId!=0xff; psList++)
+        {
+            const TABProjInfo *p = &(psList->sProj);
+
+            if (p->nProjId == psCS->nProjId &&
+                (p->nUnitsId == 0xff || p->nUnitsId == psCS->nUnitsId) &&
+                (p->nEllipsoidId == 0xff ||
+                (p->nEllipsoidId == psCS->nEllipsoidId &&
+                ( (p->nDatumId > 0 && p->nDatumId == psCS->nDatumId) ||
+                    ((p->nDatumId <= 0 || psCS->nDatumId <= 0) &&
+                    TAB_EQUAL(p->dDatumShiftX, psCS->dDatumShiftX, eps) &&
+                    TAB_EQUAL(p->dDatumShiftY, psCS->dDatumShiftY, eps) &&
+                    TAB_EQUAL(p->dDatumShiftZ, psCS->dDatumShiftZ, eps) &&
+                    TAB_EQUAL(p->adDatumParams[0], psCS->adDatumParams[0], eps) &&
+                    TAB_EQUAL(p->adDatumParams[1], psCS->adDatumParams[1], eps) &&
+                    TAB_EQUAL(p->adDatumParams[2], psCS->adDatumParams[2], eps) &&
+                    TAB_EQUAL(p->adDatumParams[3], psCS->adDatumParams[3], eps) &&
+                    TAB_EQUAL(p->adDatumParams[4], psCS->adDatumParams[4], eps) )))) &&
+                (TAB_EQUAL(p->adProjParams[0], psCS->adProjParams[0], eps) &&
+                TAB_EQUAL(p->adProjParams[1], psCS->adProjParams[1], eps) &&
+                TAB_EQUAL(p->adProjParams[2], psCS->adProjParams[2], eps) &&
+                TAB_EQUAL(p->adProjParams[3], psCS->adProjParams[3], eps) &&
+                TAB_EQUAL(p->adProjParams[4], psCS->adProjParams[4], eps) &&
+                TAB_EQUAL(p->adProjParams[5], psCS->adProjParams[5], eps) )  )
+            {
+                dXMin = psList->dXMin;
+                dYMin = psList->dYMin;
+                dXMax = psList->dXMax;
+                dYMax = psList->dYMax;
+                bFound = TRUE;
+            }
         }
     }
 
@@ -1144,15 +1209,15 @@ GBool MITABLookupCoordSysBounds(TABProjInfo *psCS,
  * The entries from that table will be looked up in priority BEFORE the
  * entries from gasBoundsList[] defined above.
  *
- * This allows users to override the default bounds for existing 
+ * This allows users to override the default bounds for existing
  * projections, and to define bounds for new projections not listed in
  * the table above.
  *
  * The format of the file is a simple text file with one CoordSys string
- * per line.  The CoordSys lines should follow the MIF specs, and MUST 
+ * per line.  The CoordSys lines should follow the MIF specs, and MUST
  * include the optional Bounds definition at the end of the line.
  *
- * e.g. 
+ * e.g.
  *  CoordSys Earth Projection 8, 24, "m", -63, 0, 0.9996, 500000, 0 Bounds \
  *  (-7746230.6469039, -9998287.383889269) (8746230.6469039, 9998287.383889269)
  *
@@ -1160,30 +1225,63 @@ GBool MITABLookupCoordSysBounds(TABProjInfo *psCS,
  **********************************************************************/
 int MITABLoadCoordSysTable(const char *pszFname)
 {
-    FILE *fp;
+    VSILFILE *fp;
     int nStatus = 0, iLine = 0;
 
     MITABFreeCoordSysTable();
 
-    if ((fp = VSIFOpen(pszFname, "rt")) != NULL)
+    if ((fp = VSIFOpenL(pszFname, "rt")) != NULL)
     {
         const char *pszLine;
         int         iEntry=0, numEntries=100;
 
-        gpapsExtBoundsList = (MapInfoBoundsInfo **)CPLMalloc(numEntries*
-                                                  sizeof(MapInfoBoundsInfo *));
-        gpapsExtBoundsList[0] = NULL;
+        gpasExtBoundsList = (MapInfoRemapProjInfo *)CPLMalloc(numEntries*
+                                                  sizeof(MapInfoRemapProjInfo));
 
-        while( (pszLine = CPLReadLine(fp)) != NULL)
+        while( (pszLine = CPLReadLineL(fp)) != NULL)
         {
             double dXMin, dYMin, dXMax, dYMax;
+            int bHasProjIn = FALSE;
+            TABProjInfo sProjIn;
             TABProjInfo sProj;
 
             iLine++;
 
             if (strlen(pszLine) < 10 || EQUALN(pszLine, "#", 1))
                 continue;  // Skip empty lines/comments
- 
+
+            if( EQUALN(pszLine, "Source", strlen("Source")) )
+            {
+                const char* pszEqual = strchr(pszLine, '=');
+                if( !pszEqual )
+                {
+                    CPLError(CE_Warning, CPLE_IllegalArg, "Invalid format at line %d", iLine);
+                    break;
+                }
+                pszLine = pszEqual + 1;
+                if ((nStatus = MITABCoordSys2TABProjInfo(pszLine, &sProjIn)) != 0)
+                {
+                    break;  // Abort and return
+                }
+                if( strstr(pszLine, "Bounds") != NULL )
+                {
+                    CPLError(CE_Warning, CPLE_IllegalArg, "Unexpected Bounds paramater at line %d",
+                             iLine);
+                }
+                bHasProjIn = TRUE;
+
+                iLine++;
+                pszLine = CPLReadLineL(fp);
+                if( pszLine == NULL ||
+                    !EQUALN(pszLine, "Destination", strlen("Destination")) ||
+                    (pszEqual = strchr(pszLine, '=')) == NULL )
+                {
+                    CPLError(CE_Warning, CPLE_IllegalArg, "Invalid format at line %d", iLine);
+                        break;
+                }
+                pszLine = pszEqual + 1;
+            }
+
             if ((nStatus = MITABCoordSys2TABProjInfo(pszLine, &sProj)) != 0)
             {
                 break;  // Abort and return
@@ -1192,7 +1290,7 @@ int MITABLoadCoordSysTable(const char *pszFname)
             if (!MITABExtractCoordSysBounds(pszLine, dXMin,dYMin,dXMax,dYMax))
             {
                 CPLError(CE_Warning, CPLE_IllegalArg,
-                         "Missing Bounds parameters in line %d of %s", 
+                         "Missing Bounds parameters in line %d of %s",
                          iLine, pszFname);
                 continue;  // Just skip this line.
             }
@@ -1200,25 +1298,26 @@ int MITABLoadCoordSysTable(const char *pszFname)
             if (iEntry >= numEntries-1)
             {
                 numEntries+= 100;
-                gpapsExtBoundsList =
-                    (MapInfoBoundsInfo **)CPLRealloc(gpapsExtBoundsList,
-                                                     numEntries*
-                                                  sizeof(MapInfoBoundsInfo *));
+                gpasExtBoundsList =
+                    (MapInfoRemapProjInfo *)CPLRealloc(gpasExtBoundsList,
+                                        numEntries* sizeof(MapInfoRemapProjInfo));
             }
 
-            gpapsExtBoundsList[iEntry] = 
-                    (MapInfoBoundsInfo*)CPLMalloc(sizeof(MapInfoBoundsInfo));
-
-            gpapsExtBoundsList[iEntry]->sProj = sProj;
-            gpapsExtBoundsList[iEntry]->dXMin = dXMin;
-            gpapsExtBoundsList[iEntry]->dYMin = dYMin;
-            gpapsExtBoundsList[iEntry]->dXMax = dXMax;
-            gpapsExtBoundsList[iEntry]->dYMax = dYMax;
-
-            gpapsExtBoundsList[++iEntry] = NULL;
+            gpasExtBoundsList[iEntry].sProjIn = (bHasProjIn) ? sProjIn : sProj;
+            gpasExtBoundsList[iEntry].sBoundsInfo.sProj = sProj;
+            gpasExtBoundsList[iEntry].sBoundsInfo.dXMin = dXMin;
+            gpasExtBoundsList[iEntry].sBoundsInfo.dYMin = dYMin;
+            gpasExtBoundsList[iEntry].sBoundsInfo.dXMax = dXMax;
+            gpasExtBoundsList[iEntry].sBoundsInfo.dYMax = dYMax;
+            iEntry ++;
         }
+        nExtBoundsListCount = iEntry;
 
-        VSIFClose(fp);
+        VSIFCloseL(fp);
+    }
+    else
+    {
+        CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", pszFname);
     }
 
     return nStatus;
@@ -1232,19 +1331,9 @@ int MITABLoadCoordSysTable(const char *pszFname)
  **********************************************************************/
 void MITABFreeCoordSysTable()
 {
-    if (gpapsExtBoundsList)
-    {
-        MapInfoBoundsInfo **ppsEntry = gpapsExtBoundsList;
-        
-        while(*ppsEntry != NULL)
-        {
-            CPLFree(*ppsEntry);
-            ppsEntry++;
-        }
-
-        CPLFree(gpapsExtBoundsList);
-        gpapsExtBoundsList = NULL;
-    }
+    CPLFree(gpasExtBoundsList);
+    gpasExtBoundsList = NULL;
+    nExtBoundsListCount = -1;
 }
 
 /**********************************************************************
@@ -1254,5 +1343,5 @@ void MITABFreeCoordSysTable()
  **********************************************************************/
 GBool MITABCoordSysTableLoaded()
 {
-    return (gpapsExtBoundsList != NULL);
+    return (nExtBoundsListCount >= 0);
 }
diff --git a/ogr/ogrsf_frmts/mitab/mitab_coordsys.cpp b/ogr/ogrsf_frmts/mitab/mitab_coordsys.cpp
index c4090e7..da49191 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_coordsys.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_coordsys.cpp
@@ -35,7 +35,7 @@
  * add support for reading google mercator (#4115)
  *
  * Revision 1.41  2010-10-07 18:46:26  aboudreault
- * Fixed bad use of atof when locale setting doesn't use . for float (GDAL bug #3775)
+ * Fixed bad use of CPLAtof when locale setting doesn't use . for float (GDAL bug #3775)
  *
  * Revision 1.40  2010-09-07 16:48:08  aboudreault
  * Removed incomplete patch for affine params support in mitab. (bug 1155)
@@ -118,21 +118,8 @@
 #include "mitab.h"
 #include "mitab_utils.h"
 
-extern MapInfoDatumInfo asDatumInfoList[];
-extern MapInfoSpheroidInfo asSpheroidInfoList[];
-
-/************************************************************************/
-/*                             GetMIFParm()                             */
-/************************************************************************/
-
-static double GetMIFParm( char ** papszFields, int iField, double dfDefault )
-
-{
-    if( iField >= CSLCount(papszFields) )
-        return dfDefault;
-    else
-        return atof(papszFields[iField]);
-}
+extern const MapInfoDatumInfo asDatumInfoList[];
+extern const MapInfoSpheroidInfo asSpheroidInfoList[];
 
 /************************************************************************/
 /*                      MITABCoordSys2SpatialRef()                      */
@@ -144,660 +131,11 @@ static double GetMIFParm( char ** papszFields, int iField, double dfDefault )
 OGRSpatialReference *MITABCoordSys2SpatialRef( const char * pszCoordSys )
 
 {
-    char        **papszFields;
-    OGRSpatialReference *poSR;
-
-    if( pszCoordSys == NULL )
-        return NULL;
-    
-/* -------------------------------------------------------------------- */
-/*      Parse the passed string into words.                             */
-/* -------------------------------------------------------------------- */
-    while(*pszCoordSys == ' ') pszCoordSys++;  // Eat leading spaces
-    if( EQUALN(pszCoordSys,"CoordSys",8) )
-        pszCoordSys += 9;
-    
-    papszFields = CSLTokenizeStringComplex( pszCoordSys, " ,", TRUE, FALSE );
-
-/* -------------------------------------------------------------------- */
-/*      Clip off Bounds information.                                    */
-/* -------------------------------------------------------------------- */
-    int         iBounds = CSLFindString( papszFields, "Bounds" );
-
-    while( iBounds != -1 && papszFields[iBounds] != NULL )
-    {
-        CPLFree( papszFields[iBounds] );
-        papszFields[iBounds] = NULL;
-        iBounds++;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Create a spatialreference object to operate on.                 */
-/* -------------------------------------------------------------------- */
-    poSR = new OGRSpatialReference;
-
-/* -------------------------------------------------------------------- */
-/*      Fetch the projection.                                           */
-/* -------------------------------------------------------------------- */
-    char        **papszNextField;
-    int nProjection = 0;
-
-    if( CSLCount( papszFields ) >= 3
-        && EQUAL(papszFields[0],"Earth")
-        && EQUAL(papszFields[1],"Projection") )
-    {
-        nProjection = atoi(papszFields[2]);
-        papszNextField = papszFields + 3;
-    }
-    else if (CSLCount( papszFields ) >= 2
-             && EQUAL(papszFields[0],"NonEarth") )
-    {
-        // NonEarth Units "..." Bounds (x, y) (x, y)
-        nProjection = 0;
-        papszNextField = papszFields + 2;
-
-        if( papszNextField[0] != NULL && EQUAL(papszNextField[0],"Units") )
-            papszNextField++;
-    }
-    else
-    {
-        // Invalid projection string ???
-        if (CSLCount(papszFields) > 0)
-            CPLError(CE_Warning, CPLE_IllegalArg,
-                     "Failed parsing CoordSys: '%s'", pszCoordSys);
-        CSLDestroy(papszFields);
-        delete poSR;
+    TABProjInfo sTABProj;
+    if(MITABCoordSys2TABProjInfo(pszCoordSys, &sTABProj) < 0 )
         return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Fetch the datum information.                                    */
-/* -------------------------------------------------------------------- */
-    int         nDatum = 0;
-    double      adfDatumParm[8] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
-    int         nEllipsoid=0;
-
-    if( nProjection != 0 && CSLCount(papszNextField) > 0 )
-    {
-        nDatum = atoi(papszNextField[0]);
-        papszNextField++;
-    }
-
-    if( (nDatum == 999 || nDatum == 9999)
-        && CSLCount(papszNextField) >= 4 )
-    {
-        nEllipsoid = atoi(papszNextField[0]);
-        adfDatumParm[0] = atof(papszNextField[1]);
-        adfDatumParm[1] = atof(papszNextField[2]);
-        adfDatumParm[2] = atof(papszNextField[3]);
-        papszNextField += 4;
-    }
-
-    if( nDatum == 9999
-        && CSLCount(papszNextField) >= 5 )
-    {
-        adfDatumParm[3] = atof(papszNextField[0]);
-        adfDatumParm[4] = atof(papszNextField[1]);
-        adfDatumParm[5] = atof(papszNextField[2]);
-        adfDatumParm[6] = atof(papszNextField[3]);
-        adfDatumParm[7] = atof(papszNextField[4]);
-        papszNextField += 5;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Fetch the units string.                                         */
-/* -------------------------------------------------------------------- */
-    const char  *pszMIFUnits = NULL;
-    const char  *pszUnitsName = NULL;
-    double dfUnitsConv = 1.0;
-    
-    if( CSLCount(papszNextField) > 0 )
-    {
-        pszMIFUnits = papszNextField[0];
-        papszNextField++;
-    }
-
-    if( nProjection == 1 || pszMIFUnits == NULL )
-        /* do nothing */;
-    else if( EQUAL(pszMIFUnits,"km") )
-    {
-        pszUnitsName = "Kilometer"; 
-        dfUnitsConv = 1000.0;
-    }
-    else if( EQUAL(pszMIFUnits, "in" ) )
-    {
-        pszUnitsName = "IINCH"; 
-        dfUnitsConv = 0.0254; 
-    }
-    else if( EQUAL(pszMIFUnits, "ft" ) )
-    {
-        pszUnitsName = SRS_UL_FOOT;
-        dfUnitsConv = CPLAtof(SRS_UL_FOOT_CONV);
-    }
-    else if( EQUAL(pszMIFUnits, "yd" ) )
-    {
-        pszUnitsName = "IYARD";
-        dfUnitsConv = 0.9144;
-    }
-    else if( EQUAL(pszMIFUnits, "mm" ) )
-    {
-        pszUnitsName = "Millimeter";
-        dfUnitsConv = 0.001;
-    }
-    else if( EQUAL(pszMIFUnits, "cm" ) )
-    {
-        pszUnitsName = "Centimeter";
-        dfUnitsConv = 0.01;
-    }
-    else if( EQUAL(pszMIFUnits, "m" ) )
-    {
-        pszUnitsName = SRS_UL_METER;
-        dfUnitsConv = 1.0;
-    }   
-    else if( EQUAL(pszMIFUnits, "survey foot" )
-             || EQUAL(pszMIFUnits, "survey ft" ) )
-    {
-        pszUnitsName = SRS_UL_US_FOOT;
-        dfUnitsConv = CPLAtof(SRS_UL_US_FOOT_CONV);
-    }   
-    else if( EQUAL(pszMIFUnits, "nmi" ) )
-    {
-        pszUnitsName = SRS_UL_NAUTICAL_MILE;
-        dfUnitsConv = CPLAtof(SRS_UL_NAUTICAL_MILE_CONV);
-    }   
-    else if( EQUAL(pszMIFUnits, "li" ) )
-    {
-        pszUnitsName = SRS_UL_LINK;
-        dfUnitsConv = CPLAtof(SRS_UL_LINK_CONV);
-    }
-    else if( EQUAL(pszMIFUnits, "ch" ) )
-    {
-        pszUnitsName = SRS_UL_CHAIN;
-        dfUnitsConv = CPLAtof(SRS_UL_CHAIN_CONV);
-    }   
-    else if( EQUAL(pszMIFUnits, "rd" ) )
-    {
-        pszUnitsName = SRS_UL_ROD;
-        dfUnitsConv = CPLAtof(SRS_UL_ROD);
-    }   
-    else if( EQUAL(pszMIFUnits, "mi" ) )
-    {
-        pszUnitsName = "Mile";
-        dfUnitsConv = 1609.344;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Handle the PROJCS style projections, but add the datum          */
-/*      later.                                                          */
-/*                                                                      */
-/*      Note that per GDAL bug 1113 the false easting and north are     */
-/*      in local units, not necessarily meters.                         */
-/* -------------------------------------------------------------------- */
-    int nBaseProjection = nProjection;
-    if (nBaseProjection>=3000) nBaseProjection -=3000;
-    else if (nBaseProjection>=2000) nBaseProjection -=2000;
-    else if (nBaseProjection>=1000) nBaseProjection -=1000;
-    switch( nBaseProjection )
-    {
-        /*--------------------------------------------------------------
-         * NonEarth ... we return with an empty SpatialRef.  Eventually
-         * we might want to include the units, but not for now.
-         *
-         * __TODO__ Changed to return NULL because returning an empty
-         * SpatialRef caused confusion between Latlon and NonEarth since
-         * empty SpatialRefs do have a GEOGCS set and makes them look like
-         * Lat/Lon SpatialRefs.
-         *
-         * Ideally we would like to return a SpatialRef whith no GEGOCS
-         *-------------------------------------------------------------*/
-      case 0:
-        poSR->SetLocalCS( "Nonearth" );
-        break;
-
-        /*--------------------------------------------------------------
-         * lat/long .. just add the GEOGCS later.
-         *-------------------------------------------------------------*/
-      case 1:
-        break;
-
-        /*--------------------------------------------------------------
-         * Cylindrical Equal Area
-         *-------------------------------------------------------------*/
-      case 2:
-        poSR->SetCEA( GetMIFParm( papszNextField, 1, 0.0 ),
-                      GetMIFParm( papszNextField, 0, 0.0 ),
-                      GetMIFParm( papszNextField, 2, 0.0 ),
-                      GetMIFParm( papszNextField, 3, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Lambert Conic Conformal
-         *-------------------------------------------------------------*/
-      case 3:
-        poSR->SetLCC( GetMIFParm( papszNextField, 2, 0.0 ),
-                      GetMIFParm( papszNextField, 3, 0.0 ),
-                      GetMIFParm( papszNextField, 1, 0.0 ),
-                      GetMIFParm( papszNextField, 0, 0.0 ),
-                      GetMIFParm( papszNextField, 4, 0.0 ),
-                      GetMIFParm( papszNextField, 5, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Lambert Azimuthal Equal Area
-         *-------------------------------------------------------------*/
-      case 4: 
-      case 29:
-        poSR->SetLAEA( GetMIFParm( papszNextField, 1, 0.0 ),
-                       GetMIFParm( papszNextField, 0, 0.0 ),
-                       0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Azimuthal Equidistant 
-         *-------------------------------------------------------------*/
-      case 5:  /* polar aspect only */
-      case 28: /* all aspects */
-        poSR->SetAE( GetMIFParm( papszNextField, 1, 0.0 ),
-                     GetMIFParm( papszNextField, 0, 0.0 ),
-                     0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Equidistant Conic
-         *-------------------------------------------------------------*/
-      case 6:
-        poSR->SetEC( GetMIFParm( papszNextField, 2, 0.0 ),
-                     GetMIFParm( papszNextField, 3, 0.0 ),
-                     GetMIFParm( papszNextField, 1, 0.0 ),
-                     GetMIFParm( papszNextField, 0, 0.0 ),
-                     GetMIFParm( papszNextField, 4, 0.0 ),
-                     GetMIFParm( papszNextField, 5, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Hotine Oblique Mercator
-         *-------------------------------------------------------------*/
-      case 7:
-        poSR->SetHOM( GetMIFParm( papszNextField, 1, 0.0 ),
-                      GetMIFParm( papszNextField, 0, 0.0 ),
-                      GetMIFParm( papszNextField, 2, 0.0 ),
-                      90.0,
-                      GetMIFParm( papszNextField, 3, 1.0 ),
-                      GetMIFParm( papszNextField, 4, 0.0 ),
-                      GetMIFParm( papszNextField, 5, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Transverse Mercator
-         *-------------------------------------------------------------*/
-      case 8:
-        poSR->SetTM( GetMIFParm( papszNextField, 1, 0.0 ),
-                     GetMIFParm( papszNextField, 0, 0.0 ),
-                     GetMIFParm( papszNextField, 2, 1.0 ),
-                     GetMIFParm( papszNextField, 3, 0.0 ),
-                     GetMIFParm( papszNextField, 4, 0.0 ) );
-        break;
-
-        /*----------------------------------------------------------------
-         * Transverse Mercator,(modified for Danish System 34 Jylland-Fyn)
-         *---------------------------------------------------------------*/
-      case 21:
-        poSR->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_21,
-                            GetMIFParm( papszNextField, 1, 0.0 ),
-                            GetMIFParm( papszNextField, 0, 0.0 ),
-                            GetMIFParm( papszNextField, 2, 1.0 ),
-                            GetMIFParm( papszNextField, 3, 0.0 ),
-                            GetMIFParm( papszNextField, 4, 0.0 ));
-        break;
-
-        /*--------------------------------------------------------------
-         * Transverse Mercator,(modified for Danish System 34 Sjaelland)
-         *-------------------------------------------------------------*/
-      case 22:
-        poSR->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_22,
-                            GetMIFParm( papszNextField, 1, 0.0 ),
-                            GetMIFParm( papszNextField, 0, 0.0 ),
-                            GetMIFParm( papszNextField, 2, 1.0 ),
-                            GetMIFParm( papszNextField, 3, 0.0 ),
-                            GetMIFParm( papszNextField, 4, 0.0 ));
-        break;
-
-        /*----------------------------------------------------------------
-         * Transverse Mercator,(modified for Danish System 34/45 Bornholm)
-         *---------------------------------------------------------------*/
-      case 23:
-        poSR->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_23,
-                            GetMIFParm( papszNextField, 1, 0.0 ),
-                            GetMIFParm( papszNextField, 0, 0.0 ),
-                            GetMIFParm( papszNextField, 2, 1.0 ),
-                            GetMIFParm( papszNextField, 3, 0.0 ),
-                            GetMIFParm( papszNextField, 4, 0.0 ));
-        break;
-
-        /*--------------------------------------------------------------
-         * Transverse Mercator,(modified for Finnish KKJ)
-         *-------------------------------------------------------------*/
-      case 24:
-        poSR->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_24,
-                            GetMIFParm( papszNextField, 1, 0.0 ),
-                            GetMIFParm( papszNextField, 0, 0.0 ),
-                            GetMIFParm( papszNextField, 2, 1.0 ),
-                            GetMIFParm( papszNextField, 3, 0.0 ),
-                            GetMIFParm( papszNextField, 4, 0.0 ));
-        break;
-
-        /*--------------------------------------------------------------
-         * Albers Conic Equal Area
-         *-------------------------------------------------------------*/
-      case 9:
-        poSR->SetACEA( GetMIFParm( papszNextField, 2, 0.0 ),
-                       GetMIFParm( papszNextField, 3, 0.0 ),
-                       GetMIFParm( papszNextField, 1, 0.0 ),
-                       GetMIFParm( papszNextField, 0, 0.0 ),
-                       GetMIFParm( papszNextField, 4, 0.0 ),
-                       GetMIFParm( papszNextField, 5, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Mercator
-         *-------------------------------------------------------------*/
-      case 10:
-        poSR->SetMercator( 0.0, GetMIFParm( papszNextField, 0, 0.0 ),
-                           1.0, 0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Miller Cylindrical
-         *-------------------------------------------------------------*/
-      case 11:
-        poSR->SetMC( 0.0, GetMIFParm( papszNextField, 0, 0.0 ),
-                     0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Robinson
-         *-------------------------------------------------------------*/
-      case 12:
-        poSR->SetRobinson( GetMIFParm( papszNextField, 0, 0.0 ),
-                           0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Mollweide
-         *-------------------------------------------------------------*/
-      case 13:
-        poSR->SetMollweide( GetMIFParm( papszNextField, 0, 0.0 ),
-                            0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Eckert IV
-         *-------------------------------------------------------------*/
-      case 14:
-        poSR->SetEckertIV( GetMIFParm( papszNextField, 0, 0.0 ),
-                           0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Eckert VI
-         *-------------------------------------------------------------*/
-      case 15:
-        poSR->SetEckertVI( GetMIFParm( papszNextField, 0, 0.0 ),
-                           0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Sinusoidal
-         *-------------------------------------------------------------*/
-      case 16:
-        poSR->SetSinusoidal( GetMIFParm( papszNextField, 0, 0.0 ),
-                             0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Gall
-         *-------------------------------------------------------------*/
-      case 17:
-        poSR->SetGS( GetMIFParm( papszNextField, 0, 0.0 ),
-                     0.0, 0.0 );
-        break;
-        
-        /*--------------------------------------------------------------
-         * New Zealand Map Grid
-         *-------------------------------------------------------------*/
-      case 18:
-        poSR->SetNZMG( GetMIFParm( papszNextField, 1, 0.0 ),
-                       GetMIFParm( papszNextField, 0, 0.0 ),
-                       GetMIFParm( papszNextField, 2, 0.0 ),
-                       GetMIFParm( papszNextField, 3, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Lambert Conic Conformal (Belgium)
-         *-------------------------------------------------------------*/
-      case 19:
-        poSR->SetLCCB( GetMIFParm( papszNextField, 2, 0.0 ),
-                       GetMIFParm( papszNextField, 3, 0.0 ),
-                       GetMIFParm( papszNextField, 1, 0.0 ),
-                       GetMIFParm( papszNextField, 0, 0.0 ),
-                       GetMIFParm( papszNextField, 4, 0.0 ),
-                       GetMIFParm( papszNextField, 5, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Stereographic
-         *-------------------------------------------------------------*/
-      case 20:
-      case 31: /* double stereographic */
-        poSR->SetStereographic( 
-            GetMIFParm( papszNextField, 1, 0.0 ),
-            GetMIFParm( papszNextField, 0, 0.0 ),
-            GetMIFParm( papszNextField, 2, 1.0 ),
-            GetMIFParm( papszNextField, 3, 0.0 ),
-            GetMIFParm( papszNextField, 4, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Swiss Oblique Mercator / Cylindrical
-         *-------------------------------------------------------------*/
-      case 25:
-        poSR->SetSOC( GetMIFParm( papszNextField, 1, 0.0 ),
-                      GetMIFParm( papszNextField, 0, 0.0 ),
-                      GetMIFParm( papszNextField, 2, 0.0 ),
-                      GetMIFParm( papszNextField, 3, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Regional Mercator
-         *-------------------------------------------------------------*/
-      case 26:
-        poSR->SetMercator( GetMIFParm( papszNextField, 1, 0.0 ), 
-                           GetMIFParm( papszNextField, 0, 0.0 ),
-                           1.0, 0.0, 0.0 );
-        break;
-
-        /*--------------------------------------------------------------
-         * Polygonic
-         *-------------------------------------------------------------*/
-      case 27:
-        poSR->SetPolyconic( GetMIFParm( papszNextField, 1, 0.0 ), 
-                            GetMIFParm( papszNextField, 0, 0.0 ),
-                          GetMIFParm( papszNextField, 2, 0.0 ),
-                          GetMIFParm( papszNextField, 3, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * CassiniSoldner
-         *-------------------------------------------------------------*/
-      case 30:
-        poSR->SetCS( 
-            GetMIFParm( papszNextField, 1, 0.0 ),
-            GetMIFParm( papszNextField, 0, 0.0 ),
-            GetMIFParm( papszNextField, 2, 0.0 ),
-            GetMIFParm( papszNextField, 3, 0.0 ) );
-        break;
-
-        /*--------------------------------------------------------------
-         * Krovak
-         *-------------------------------------------------------------*/
-       case 32:
-         poSR->SetKrovak( GetMIFParm( papszNextField, 1, 0.0 ),  // dfCenterLat
-                          GetMIFParm( papszNextField, 0, 0.0 ),  // dfCenterLong
-                          GetMIFParm( papszNextField, 3, 1.0 ),  // dfAzimuth
-                          GetMIFParm( papszNextField, 2, 0.0 ),  // dfPseudoStdParallelLat
-                          1.0,									  // dfScale
-                          GetMIFParm( papszNextField, 4, 0.0 ),  // dfFalseEasting
-                          GetMIFParm( papszNextField, 5, 0.0 )); // dfFalseNorthing
-         break;
-
-      default:
-        break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Set linear units.                                               */
-/* -------------------------------------------------------------------- */
-    if( pszUnitsName != NULL )
-        poSR->SetLinearUnits( pszUnitsName, dfUnitsConv );
-
-/* -------------------------------------------------------------------- */
-/*      For Non-Earth projection, we're done at this point.             */
-/* -------------------------------------------------------------------- */
-    if (nProjection == 0)
-    {
-        CSLDestroy(papszFields);
-        return poSR;
-    }
-
-/* ==================================================================== */
-/*      Establish the GeogCS                                            */
-/* ==================================================================== */
-    const char *pszGeogName = "unnamed";
-    const char *pszSpheroidName = "GRS_1980";
-    double      dfSemiMajor = 6378137.0;
-    double      dfInvFlattening = 298.257222101;
-    const char *pszPrimeM = "Greenwich";
-    double      dfPMLongToGreenwich = 0.0;
-
-/* -------------------------------------------------------------------- */
-/*      Find the datum, and collect it's parameters if possible.        */
-/* -------------------------------------------------------------------- */
-    int         iDatum;
-    MapInfoDatumInfo *psDatumInfo = NULL;
-    
-    for( iDatum = 0; asDatumInfoList[iDatum].nMapInfoDatumID != -1; iDatum++ )
-    {
-        if( asDatumInfoList[iDatum].nMapInfoDatumID == nDatum )
-        {
-            psDatumInfo = asDatumInfoList + iDatum;
-            break;
-        }
-    }
-
-    if( asDatumInfoList[iDatum].nMapInfoDatumID == -1
-        && nDatum != 999 && nDatum != 9999 )
-    {
-        /* use WGS84 */
-        psDatumInfo = asDatumInfoList + 0;
-    }
-
-    if( psDatumInfo != NULL )
-    {
-        nEllipsoid = psDatumInfo->nEllipsoid;
-        adfDatumParm[0] =  psDatumInfo->dfShiftX;
-        adfDatumParm[1] = psDatumInfo->dfShiftY;
-        adfDatumParm[2] = psDatumInfo->dfShiftZ;
-        adfDatumParm[3] = psDatumInfo->dfDatumParm0;
-        adfDatumParm[4] = psDatumInfo->dfDatumParm1;
-        adfDatumParm[5] = psDatumInfo->dfDatumParm2;
-        adfDatumParm[6] = psDatumInfo->dfDatumParm3;
-        adfDatumParm[7] = psDatumInfo->dfDatumParm4;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Set the spheroid if it is known from the table.                 */
-/* -------------------------------------------------------------------- */
-    for( int i = 0; asSpheroidInfoList[i].nMapInfoId != -1; i++ )
-    {
-        if( asSpheroidInfoList[i].nMapInfoId == nEllipsoid )
-        {
-            dfSemiMajor = asSpheroidInfoList[i].dfA;
-            dfInvFlattening = asSpheroidInfoList[i].dfInvFlattening;
-            pszSpheroidName = asSpheroidInfoList[i].pszMapinfoName;
-            break;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      apply datum parameters.                                         */
-/* -------------------------------------------------------------------- */
-    char        szDatumName[128];
+    OGRSpatialReference* poSR = TABFile::GetSpatialRefFromTABProj(sTABProj);
 
-    if( nDatum == 999 )
-    {
-        sprintf( szDatumName,
-                 "MIF 9999,%d,%.15g,%.15g,%.15g",
-                 nEllipsoid,
-                 adfDatumParm[0],
-                 adfDatumParm[1],
-                 adfDatumParm[2] );
-    }
-    else if( nDatum == 9999 )
-    {
-        sprintf( szDatumName,
-                 "MIF 9999,%d,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g,%.15g",
-                 nEllipsoid,
-                 adfDatumParm[0],
-                 adfDatumParm[1],
-                 adfDatumParm[2],
-                 adfDatumParm[3],
-                 adfDatumParm[4],
-                 adfDatumParm[5],
-                 adfDatumParm[6],
-                 adfDatumParm[7] );
-    }
-    else if( psDatumInfo->pszOGCDatumName != NULL
-             && strlen(psDatumInfo->pszOGCDatumName) > 0 )
-    {
-        strncpy( szDatumName, psDatumInfo->pszOGCDatumName,
-                 sizeof(szDatumName) );
-    }
-    else
-    {
-        sprintf( szDatumName, "MIF %d", nDatum );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Set prime meridian for 9999 datums.                             */
-/* -------------------------------------------------------------------- */
-    if( nDatum == 9999 || adfDatumParm[7] != 0.0 )
-    {
-        pszPrimeM = "non-Greenwich";
-        dfPMLongToGreenwich = adfDatumParm[7];
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Set the GeogCS.                                                 */
-/* -------------------------------------------------------------------- */
-    poSR->SetGeogCS( pszGeogName, szDatumName, pszSpheroidName,
-                     dfSemiMajor, dfInvFlattening,
-                     pszPrimeM, dfPMLongToGreenwich,
-                     SRS_UA_DEGREE,
-                     CPLAtof(SRS_UA_DEGREE_CONV) );
-
-    poSR->SetTOWGS84( adfDatumParm[0], adfDatumParm[1], adfDatumParm[2],
-                      -adfDatumParm[3], -adfDatumParm[4], -adfDatumParm[5], 
-                      adfDatumParm[6] );
-
-    /*-----------------------------------------------------------------
-     * Special case for Google Mercator (datum=157, ellipse=54, gdal #4115)
-     *----------------------------------------------------------------*/
-
-    if( nBaseProjection == 10 && nDatum == 157 )
-    {
-        poSR->SetNode( "PROJCS", "WGS 84 / Pseudo-Mercator" );
-        poSR->SetExtension( "PROJCS", "PROJ4", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs" );
-    }
 /* -------------------------------------------------------------------- */
 /*      Report on translation.                                          */
 /* -------------------------------------------------------------------- */
@@ -812,8 +150,6 @@ OGRSpatialReference *MITABCoordSys2SpatialRef( const char * pszCoordSys )
         CPLFree( pszWKT );
     }
 
-    CSLDestroy(papszFields);
-
     return poSR;
 }
 
@@ -833,501 +169,77 @@ char *MITABSpatialRef2CoordSys( OGRSpatialReference * poSR )
     if( poSR == NULL )
         return NULL;
     
-    /*-----------------------------------------------------------------
-     * Get the linear units.
-     *----------------------------------------------------------------*/
-    double      dfLinearConv;
-    char        *pszLinearUnits;
-
-    dfLinearConv = poSR->GetLinearUnits( &pszLinearUnits );
-
-    /*-----------------------------------------------------------------
-     * Transform the projection and projection parameters.
-     *----------------------------------------------------------------*/
-    const char *pszProjection = poSR->GetAttrValue("PROJECTION");
-    double      parms[10];
-    int         nProjection = 0;
-    int         nParmCount = 0;
-
-    if( pszProjection == NULL )
-    {
-        /*--------------------------------------------------------------
-         * NULL projection.  
-         * We have 2 possibilities: CoordSys NonEarth or Lat/Lon 
-         * NonEarth ... is an empty SpatialRef.  
-         * Lat/Lon has no "PROJECTION" but GEOGCS is set
-         *-------------------------------------------------------------*/
-         if ( poSR->GetAttrValue("GEOGCS") == NULL)
-            nProjection = 0; // Non-Earth
-        else
-            nProjection = 1; // Lat/Lon
-    }
-    else if( EQUAL(pszProjection,SRS_PT_ALBERS_CONIC_EQUAL_AREA) )
-    {
-        nProjection = 9;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_AZIMUTHAL_EQUIDISTANT) )
-    {
-        nProjection = 5;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = 90.0;
-        nParmCount = 3;
-
-        if( ABS((ABS(parms[1]) - 90)) > 0.001 )
-            nProjection = 28;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_CYLINDRICAL_EQUAL_AREA) )
-    {
-        nProjection = 2;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
-        nParmCount = 2;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_ECKERT_IV) )
-    {
-        nProjection = 14;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_ECKERT_VI) )
-    {
-        nProjection = 15;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_EQUIDISTANT_CONIC) )
-    {
-        nProjection = 6;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_GALL_STEREOGRAPHIC) )
-    {
-        nProjection = 17;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_HOTINE_OBLIQUE_MERCATOR) )
-    {
-        nProjection = 7;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_AZIMUTH,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
-    {
-        nProjection = 4;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = 90.0;
-        nParmCount = 3;
-
-        if( ABS((ABS(parms[1]) - 90)) > 0.001 )
-            nProjection = 28;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) )
-    {
-        nProjection = 3;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM) )
-    {
-        nProjection = 19;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_MERCATOR_1SP) )
-    {
-        nProjection = 10;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        nParmCount = 1;
-
-        if( parms[1] != 0.0 )
-        {
-            nProjection = 26;
-            nParmCount = 2;
-        }
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_MILLER_CYLINDRICAL) )
-    {
-        nProjection = 11;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_MOLLWEIDE) )
-    {
-        nProjection = 13;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_SWISS_OBLIQUE_CYLINDRICAL) )
-    {
-        nProjection = 25;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 4;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_ROBINSON) )
-    {
-        nProjection = 12;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_SINUSOIDAL) )
-    {
-        nProjection = 16;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        nParmCount = 1;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_STEREOGRAPHIC) )
-    {
-        nProjection = 20;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 5;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR) )
-    {
-        nProjection = 8;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 5;
-    }
-
-    // Transverse Mercator,(modified for Danish System 34 Jylland-Fyn)
-    else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_21) )
-    {
-       nProjection = 21;
-       parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-       parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-       parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-       parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-       parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-       nParmCount = 5;
-    }
-
-    // Transverse Mercator,(modified for Danish System 34 Sjaelland)
-    else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_22) )
-    {
-       nProjection = 22;
-       parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-       parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-       parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-       parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-       parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-       nParmCount = 5;
-    }
-
-    // Transverse Mercator,(modified for Danish System 34/45 Bornholm)
-    else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_23) )
-    {
-       nProjection = 23;
-       parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-       parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-       parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-       parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-       parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-       nParmCount = 5;
-    }
-
-    // Transverse Mercator,(modified for Finnish KKJ)
-    else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_24) )
-    {
-       nProjection = 24;
-       parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-       parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-       parms[2] = poSR->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
-       parms[3] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-       parms[4] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-       nParmCount = 5;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_CASSINI_SOLDNER) )
-    {
-        nProjection = 30;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 4;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_NEW_ZEALAND_MAP_GRID) )
-    {
-        nProjection = 18;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 4;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_POLYCONIC) )
-    {
-        nProjection = 27;
-        parms[0] = poSR->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 4;
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_KROVAK) )
-    {
-        nProjection = 32;
-        parms[0] = poSR->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
-        parms[1] = poSR->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
-        parms[2] = poSR->GetProjParm(SRS_PP_PSEUDO_STD_PARALLEL_1,0.0);
-        parms[3] = poSR->GetProjParm(SRS_PP_AZIMUTH,0.0);
-        parms[4] = poSR->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[5] = poSR->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-        nParmCount = 6;
-    }
-
-    /* ==============================================================
-     * Translate Datum and Ellipsoid
-     * ============================================================== */
-    int         nDatum = 0;
-    double      adfDatumParm[8] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0};
-    int         nEllipsoid=0;
-    
-    int nDatumEPSGCode = -1;
-    const char *pszDatumAuthority = poSR->GetAuthorityName("DATUM");
-    const char *pszDatumCode = poSR->GetAuthorityCode("DATUM");
-    
-    if (pszDatumCode && pszDatumAuthority && EQUAL(pszDatumAuthority, "EPSG"))
-    {
-    	nDatumEPSGCode = atoi(pszDatumCode);
-    }
-    
-    const char *pszWKTDatum = poSR->GetAttrValue("DATUM");
-
-    if( pszWKTDatum == NULL )
-    {
-        nDatum = 0;
-        if( nProjection == 1 )
-            nProjection = 0;
-    }
-    
-    /*-----------------------------------------------------------------
-     * We know the MIF datum number, and need to look it up to
-     * translate into datum parameters.
-     *----------------------------------------------------------------*/
-    else if( EQUALN(pszWKTDatum,"MIF ",4)
-             && atoi(pszWKTDatum+4) != 999
-             && atoi(pszWKTDatum+4) != 9999 )
-    {
-        nDatum = atoi(pszWKTDatum+4);
-    }
+    TABProjInfo     sTABProj;
+    int             nParmCount;
+    TABFile::GetTABProjFromSpatialRef(poSR, sTABProj, nParmCount);
 
-    /*-----------------------------------------------------------------
-     * We have the MIF datum parameters, and apply those directly.
-     *----------------------------------------------------------------*/
-    else if( EQUALN(pszWKTDatum,"MIF ",4)
-             && (atoi(pszWKTDatum+4) == 999 || atoi(pszWKTDatum+4) == 9999) )
+/* -------------------------------------------------------------------- */
+/*      Do coordsys lookup                                              */
+/* -------------------------------------------------------------------- */
+    double dXMin, dYMin, dXMax, dYMax;
+    int bHasBounds = FALSE;
+    if (sTABProj.nProjId > 1 &&
+        MITABLookupCoordSysBounds(&sTABProj, dXMin, dYMin, dXMax, dYMax, TRUE) == TRUE)
     {
-        char    **papszFields;
-        
-        nDatum = atoi(pszWKTDatum+4);
-
-        papszFields =
-            CSLTokenizeStringComplex( pszWKTDatum+4, ",", FALSE, TRUE);
-
-        if( CSLCount(papszFields) >= 5 )
-        {
-            nEllipsoid = atoi(papszFields[1]);
-            adfDatumParm[0] = atof(papszFields[2]);
-            adfDatumParm[1] = atof(papszFields[3]);
-            adfDatumParm[2] = atof(papszFields[4]);
-        }
-
-        if( CSLCount(papszFields) >= 10 )
-        {
-            adfDatumParm[3] = atof(papszFields[5]);
-            adfDatumParm[4] = atof(papszFields[6]);
-            adfDatumParm[5] = atof(papszFields[7]);
-            adfDatumParm[6] = atof(papszFields[8]);
-            adfDatumParm[7] = atof(papszFields[9]);
-        }
-
-        if( CSLCount(papszFields) < 5 )
-            nDatum = 104; /* WGS84 */
-
-        CSLDestroy( papszFields );
+        bHasBounds = TRUE;
     }
-    
-    /*-----------------------------------------------------------------
-     * We have a "real" datum name, and possibly an EPSG code for the
-     * datum.  Try to look it up (using EPSG code first) and get the
-     * parameters.  If we don't find it with either just use WGS84.
-     *----------------------------------------------------------------*/
-    else 
-    {
-        int     i;
 
-        for( i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++ )
-        {
-        	if ( (nDatumEPSGCode > 0 && asDatumInfoList[i].nDatumEPSGCode == nDatumEPSGCode) ||
-        		   EQUAL(pszWKTDatum,asDatumInfoList[i].pszOGCDatumName) )
-            {
-                nDatum = asDatumInfoList[i].nMapInfoDatumID;
-                break;
-            }
-        }
-
-        if( nDatum == 0 )
-            nDatum = 104; /* WGS84 */
-    }
-    
-    /*-----------------------------------------------------------------
-     * Translate the units
-     *----------------------------------------------------------------*/
-    const char  *pszMIFUnits = "m";
-
-    if( nProjection == 1 )
-        pszMIFUnits = NULL;
-    else if( pszLinearUnits == NULL )
-        pszMIFUnits = "m";
-    else if( dfLinearConv == 1000.0 )
-        pszMIFUnits = "km";
-    else if( dfLinearConv == 0.0254 || EQUAL(pszLinearUnits,"Inch")
-             || EQUAL(pszLinearUnits,"IINCH"))
-        pszMIFUnits = "in";
-    else if( dfLinearConv == CPLAtof(SRS_UL_FOOT_CONV)
-             || EQUAL(pszLinearUnits,SRS_UL_FOOT) )
-        pszMIFUnits = "ft";
-    else if( EQUAL(pszLinearUnits,"YARD") || EQUAL(pszLinearUnits,"IYARD") 
-             || dfLinearConv == 0.9144 )
-        pszMIFUnits = "yd";
-    else if( dfLinearConv == 0.001 )
-        pszMIFUnits = "mm";
-    else if( dfLinearConv == 0.01 )
-        pszMIFUnits = "cm";
-    else if( dfLinearConv == 1.0 )
-        pszMIFUnits = "m";
-    else if( dfLinearConv == CPLAtof(SRS_UL_US_FOOT_CONV)
-             || EQUAL(pszLinearUnits,SRS_UL_US_FOOT) )
-        pszMIFUnits = "survey ft";
-    else if( EQUAL(pszLinearUnits,SRS_UL_NAUTICAL_MILE) )
-        pszMIFUnits = "nmi";
-    else if( EQUAL(pszLinearUnits,SRS_UL_LINK) 
-             || EQUAL(pszLinearUnits,"GUNTERLINK") )
-        pszMIFUnits = "li";
-    else if( EQUAL(pszLinearUnits,SRS_UL_CHAIN) 
-             || EQUAL(pszLinearUnits,"GUNTERCHAIN") )
-        pszMIFUnits = "ch";
-    else if( EQUAL(pszLinearUnits,SRS_UL_ROD) )
-        pszMIFUnits = "rd";
-    else if( EQUAL(pszLinearUnits,"Mile") 
-             || EQUAL(pszLinearUnits,"IMILE") )
-        pszMIFUnits = "mi";
+/*-----------------------------------------------------------------
+ * Translate the units
+ *----------------------------------------------------------------*/
+    const char  *pszMIFUnits = TABUnitIdToString(sTABProj.nUnitsId);
     
 /* -------------------------------------------------------------------- */
 /*      Build coordinate system definition.                             */
 /* -------------------------------------------------------------------- */
-    char        szCoordSys[256];
+    CPLString osCoordSys;
 
-    if( nProjection != 0 )
+    if( sTABProj.nProjId != 0 )
     {
-        sprintf( szCoordSys,
+        osCoordSys.Printf(
                  "Earth Projection %d",
-                 nProjection );
+                 sTABProj.nProjId );
 
     }
     else
-        sprintf( szCoordSys,
+        osCoordSys.Printf(
                  "NonEarth Units" );
 
 /* -------------------------------------------------------------------- */
 /*      Append Datum                                                    */
 /* -------------------------------------------------------------------- */
-    if( nProjection != 0 )
+    if( sTABProj.nProjId != 0 )
     {
-        sprintf( szCoordSys + strlen(szCoordSys),
+        osCoordSys += CPLSPrintf(
                  ", %d",
-                 nDatum );
+                 sTABProj.nDatumId );
 
-        if( nDatum == 999 || nDatum == 9999 )
+        if( sTABProj.nDatumId == 999 || sTABProj.nDatumId == 9999 )
         {
-            sprintf( szCoordSys + strlen(szCoordSys),
+            osCoordSys += CPLSPrintf(
                      ", %d, %.15g, %.15g, %.15g",
-                     nEllipsoid,
-                     adfDatumParm[0], adfDatumParm[1], adfDatumParm[2] );
+                     sTABProj.nEllipsoidId,
+                     sTABProj.dDatumShiftX, sTABProj.dDatumShiftY, sTABProj.dDatumShiftZ );
         }
         
-        if( nDatum == 9999 )
+        if( sTABProj.nDatumId == 9999 )
         {
-            sprintf( szCoordSys + strlen(szCoordSys),
+            osCoordSys += CPLSPrintf(
                      ", %.15g, %.15g, %.15g, %.15g, %.15g",
-                     adfDatumParm[3], adfDatumParm[4], adfDatumParm[5],
-                     adfDatumParm[6], adfDatumParm[7] );
+                     sTABProj.adDatumParams[0], sTABProj.adDatumParams[1], sTABProj.adDatumParams[2],
+                     sTABProj.adDatumParams[3], sTABProj.adDatumParams[4] );
         }
     }
 
 /* -------------------------------------------------------------------- */
 /*      Append units.                                                   */
 /* -------------------------------------------------------------------- */
-    if( nProjection != 1 && pszMIFUnits != NULL )
+    if( sTABProj.nProjId != 1 && pszMIFUnits != NULL )
     {
-        if( nProjection != 0 )
-            strcat( szCoordSys, "," );
+        if( sTABProj.nProjId != 0 )
+            osCoordSys += "," ;
         
-        sprintf( szCoordSys + strlen(szCoordSys),
+        osCoordSys += CPLSPrintf(
                  " \"%s\"",
                  pszMIFUnits );
     }
@@ -1336,9 +248,29 @@ char *MITABSpatialRef2CoordSys( OGRSpatialReference * poSR )
 /*      Append Projection Parms.                                        */
 /* -------------------------------------------------------------------- */
     for( int iParm = 0; iParm < nParmCount; iParm++ )
-        sprintf( szCoordSys + strlen(szCoordSys),
+        osCoordSys += CPLSPrintf(
                  ", %.15g",
-                 parms[iParm] );
+                 sTABProj.adProjParams[iParm] );
+
+/* -------------------------------------------------------------------- */
+/*      Append user bounds                                              */
+/* -------------------------------------------------------------------- */
+    if (bHasBounds)
+    {
+        if( fabs(dXMin - (int)floor(dXMin+0.5)) < 1e-8 &&
+            fabs(dYMin - (int)floor(dYMin+0.5)) < 1e-8 &&
+            fabs(dXMax - (int)floor(dXMax+0.5)) < 1e-8 &&
+            fabs(dYMax - (int)floor(dYMax+0.5)) < 1e-8 )
+        {
+            osCoordSys += CPLSPrintf(" Bounds (%d, %d) (%d, %d)",
+                                     (int)dXMin, (int)dYMin, (int)dXMax, (int)dYMax);
+        }
+        else
+        {
+            osCoordSys += CPLSPrintf(" Bounds (%f, %f) (%f, %f)",
+                                     dXMin, dYMin, dXMax, dYMax);
+        }
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Report on translation                                           */
@@ -1350,11 +282,11 @@ char *MITABSpatialRef2CoordSys( OGRSpatialReference * poSR )
     {
         CPLDebug( "MITAB",
                   "This WKT Projection:\n%s\n\ntranslates to:\n%s\n",
-                  pszWKT, szCoordSys );
+                  pszWKT, osCoordSys.c_str() );
         CPLFree( pszWKT );
     }
 
-    return( CPLStrdup( szCoordSys ) );
+    return( CPLStrdup( osCoordSys.c_str() ) );
 }
 
 
@@ -1381,10 +313,10 @@ GBool MITABExtractCoordSysBounds( const char * pszCoordSys,
 
     if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
     {
-        dXMin = atof(papszFields[++iBounds]);
-        dYMin = atof(papszFields[++iBounds]);
-        dXMax = atof(papszFields[++iBounds]);
-        dYMax = atof(papszFields[++iBounds]);
+        dXMin = CPLAtof(papszFields[++iBounds]);
+        dYMin = CPLAtof(papszFields[++iBounds]);
+        dXMax = CPLAtof(papszFields[++iBounds]);
+        dYMax = CPLAtof(papszFields[++iBounds]);
         CSLDestroy( papszFields );
         return TRUE;
     }
@@ -1399,11 +331,6 @@ GBool MITABExtractCoordSysBounds( const char * pszCoordSys,
  *
  * Convert a MIF COORDSYS string into a TABProjInfo structure.
  *
- * Note that it would have been possible to achieve the same by calling
- * TABFile::SetSpatialRef( MITABCoordSys2SpatialRef() ) but this would 
- * involve lots of manipulations for cases where only a simple conversion
- * is required.
- *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
 int MITABCoordSys2TABProjInfo(const char * pszCoordSys, TABProjInfo *psProj)
@@ -1447,7 +374,12 @@ int MITABCoordSys2TABProjInfo(const char * pszCoordSys, TABProjInfo *psProj)
         && EQUAL(papszFields[0],"Earth")
         && EQUAL(papszFields[1],"Projection") )
     {
-        psProj->nProjId = (GByte)atoi(papszFields[2]);
+        int nProjId = atoi(papszFields[2]);
+        if (nProjId>=3000) nProjId -=3000;
+        else if (nProjId>=2000) nProjId -=2000;
+        else if (nProjId>=1000) nProjId -=1000;
+
+        psProj->nProjId = (GByte)nProjId;
         papszNextField = papszFields + 3;
     }
     else if (CSLCount( papszFields ) >= 2
@@ -1484,20 +416,20 @@ int MITABCoordSys2TABProjInfo(const char * pszCoordSys, TABProjInfo *psProj)
     if( (nDatum == 999 || nDatum == 9999)
         && CSLCount(papszNextField) >= 4 )
     {
-        psProj->nEllipsoidId = (GByte)atoi(papszFields[0]);
-        psProj->dDatumShiftX = atof(papszNextField[1]);
-        psProj->dDatumShiftY = atof(papszNextField[2]);
-        psProj->dDatumShiftZ = atof(papszNextField[3]);
+        psProj->nEllipsoidId = (GByte)atoi(papszNextField[0]);
+        psProj->dDatumShiftX = CPLAtof(papszNextField[1]);
+        psProj->dDatumShiftY = CPLAtof(papszNextField[2]);
+        psProj->dDatumShiftZ = CPLAtof(papszNextField[3]);
         papszNextField += 4;
 
         if( nDatum == 9999
             && CSLCount(papszNextField) >= 5 )
         {
-            psProj->adDatumParams[0] = atof(papszNextField[0]);
-            psProj->adDatumParams[1] = atof(papszNextField[1]);
-            psProj->adDatumParams[2] = atof(papszNextField[2]);
-            psProj->adDatumParams[3] = atof(papszNextField[3]);
-            psProj->adDatumParams[4] = atof(papszNextField[4]);
+            psProj->adDatumParams[0] = CPLAtof(papszNextField[0]);
+            psProj->adDatumParams[1] = CPLAtof(papszNextField[1]);
+            psProj->adDatumParams[2] = CPLAtof(papszNextField[2]);
+            psProj->adDatumParams[3] = CPLAtof(papszNextField[3]);
+            psProj->adDatumParams[4] = CPLAtof(papszNextField[4]);
             papszNextField += 5;
         }
     }
@@ -1507,7 +439,7 @@ int MITABCoordSys2TABProjInfo(const char * pszCoordSys, TABProjInfo *psProj)
      * Find the datum, and collect it's parameters if possible.
      *----------------------------------------------------------------*/
         int         iDatum;
-        MapInfoDatumInfo *psDatumInfo = NULL;
+        const MapInfoDatumInfo *psDatumInfo = NULL;
         
         for(iDatum=0; asDatumInfoList[iDatum].nMapInfoDatumID != -1; iDatum++)
         {
@@ -1554,9 +486,11 @@ int MITABCoordSys2TABProjInfo(const char * pszCoordSys, TABProjInfo *psProj)
      *----------------------------------------------------------------*/
     for(int iParam=0; iParam < 6 && CSLCount(papszNextField) > 0; iParam++)
     {
-        psProj->adProjParams[iParam] = atof(papszNextField[0]);
+        psProj->adProjParams[iParam] = CPLAtof(papszNextField[0]);
         papszNextField++;         
     }
+    
+    CSLDestroy(papszFields);
 
     return 0;
 }
diff --git a/ogr/ogrsf_frmts/mitab/mitab_datfile.cpp b/ogr/ogrsf_frmts/mitab/mitab_datfile.cpp
index 261106a..d9a417c 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_datfile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_datfile.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2001, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -104,6 +105,7 @@
  **********************************************************************/
 
 #include "mitab.h"
+#include "ogr_p.h"
 
 /*=====================================================================
  *                      class TABDATFile
@@ -142,6 +144,9 @@ TABDATFile::TABDATFile()
     m_nCurRecordId = -1;
     m_bCurRecordDeletedFlag = FALSE;
     m_bWriteHeaderInitialized = FALSE;
+    m_bWriteEOF = FALSE;
+    
+    m_bUpdated = FALSE;
 }
 
 /**********************************************************************
@@ -157,6 +162,27 @@ TABDATFile::~TABDATFile()
 /**********************************************************************
  *                   TABDATFile::Open()
  *
+ * Compatibility layer with new interface.
+ * Return 0 on success, -1 in case of failure.
+ **********************************************************************/
+
+int TABDATFile::Open(const char *pszFname, const char* pszAccess, TABTableType eTableType)
+{
+    if( EQUALN(pszAccess, "r", 1) )
+        return Open(pszFname, TABRead, eTableType);
+    else if( EQUALN(pszAccess, "w", 1) )
+        return Open(pszFname, TABWrite, eTableType);
+    else
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+        return -1;
+    }
+}
+
+/**********************************************************************
+ *                   TABDATFile::Open()
+ *
  * Open a .DAT file, and initialize the structures to be ready to read
  * records from it.
  *
@@ -165,7 +191,7 @@ TABDATFile::~TABDATFile()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABDATFile::Open(const char *pszFname, const char *pszAccess,
+int TABDATFile::Open(const char *pszFname, TABAccess eAccess,
                      TABTableType eTableType /*=TABNativeTable*/)
 {
     int i;
@@ -180,29 +206,34 @@ int TABDATFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Validate access mode and make sure we use binary access.
      *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1) && (eTableType==TABTableNative ||
+    const char* pszAccess = NULL;
+    if (eAccess == TABRead && (eTableType==TABTableNative ||
                                       eTableType==TABTableDBF)  )
     {
-        m_eAccessMode = TABRead;
         pszAccess = "rb";
     }
-    else if (EQUALN(pszAccess, "w", 1) && eTableType==TABTableNative)
+    else if (eAccess == TABWrite && eTableType==TABTableNative)
+    {
+        pszAccess = "wb+";
+    }
+    else if (eAccess == TABReadWrite && eTableType==TABTableNative)
     {
-        m_eAccessMode = TABWrite;
-        pszAccess = "wb";
+        pszAccess = "rb+";
     }
     else
     {
         CPLError(CE_Failure, CPLE_FileIO,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+                 "Open() failed: access mode \"%d\" not supported with eTableType=%d",
+                 eAccess, eTableType);
         return -1;
     }
+    m_eAccessMode = eAccess;
 
     /*-----------------------------------------------------------------
      * Open file for reading
      *----------------------------------------------------------------*/
     m_pszFname = CPLStrdup(pszFname);
-    m_fp = VSIFOpen(m_pszFname, pszAccess);
+    m_fp = VSIFOpenL(m_pszFname, pszAccess);
     m_eTableType = eTableType;
 
     if (m_fp == NULL)
@@ -214,7 +245,7 @@ int TABDATFile::Open(const char *pszFname, const char *pszAccess,
         return -1;
     }
 
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite)
     {
         /*------------------------------------------------------------
          * READ ACCESS:
@@ -268,6 +299,8 @@ int TABDATFile::Open(const char *pszFname, const char *pszAccess,
         m_poRecordBlock = new TABRawBinBlock(m_eAccessMode, FALSE);
         m_poRecordBlock->InitNewBlock(m_fp, m_nBlockSize);
         m_poRecordBlock->SetFirstBlockPtr(m_nFirstRecordPtr);
+        
+        m_bWriteHeaderInitialized = TRUE;
     }
     else
     {
@@ -306,15 +339,11 @@ int TABDATFile::Close()
      * Write access: Update the header with number of records, etc.
      * and add a CTRL-Z char at the end of the file.
      *---------------------------------------------------------------*/
-    if (m_eAccessMode == TABWrite)
+    if (m_eAccessMode != TABRead )
     {
-        WriteHeader();
-
-        char cEOF = 26;
-        if (VSIFSeek(m_fp, 0L, SEEK_END) == 0)
-            VSIFWrite(&cEOF, 1, 1, m_fp);
+        SyncToDisk();
     }
-    
+
     // Delete all structures 
     if (m_poHeaderBlock)
     {
@@ -329,7 +358,7 @@ int TABDATFile::Close()
     }
 
     // Close file
-    VSIFClose(m_fp);
+    VSIFCloseL(m_fp);
     m_fp = NULL;
 
     CPLFree(m_pszFname);
@@ -345,10 +374,36 @@ int TABDATFile::Close()
     m_nRecordSize = -1;
     m_nCurRecordId = -1;
     m_bWriteHeaderInitialized = FALSE;
+    m_bWriteEOF = FALSE;
+    m_bUpdated = FALSE;
 
     return 0;
 }
 
+/************************************************************************/
+/*                            SyncToDisk()                             */
+/************************************************************************/
+
+int TABDATFile::SyncToDisk()
+{
+    if( m_eAccessMode == TABRead )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SyncToDisk() can be used only with Write access.");
+        return -1;
+    }
+    
+    if( !m_bUpdated && m_bWriteHeaderInitialized )
+        return 0;
+
+    // No need to call. CommitRecordToFile(). It is normally called by
+    // TABFeature::WriteRecordToDATFile()
+    if( WriteHeader() != 0 )
+        return -1;
+
+    m_bUpdated = FALSE;
+    return 0;
+}
 
 /**********************************************************************
  *                   TABDATFile::InitWriteHeader()
@@ -362,7 +417,7 @@ int  TABDATFile::InitWriteHeader()
 {
     int i;
 
-    if (m_eAccessMode != TABWrite || m_bWriteHeaderInitialized)
+    if (m_eAccessMode == TABRead || m_bWriteHeaderInitialized)
         return 0;
 
     /*------------------------------------------------------------
@@ -382,7 +437,7 @@ int  TABDATFile::InitWriteHeader()
     m_nBlockSize = m_nRecordSize;
 
     CPLAssert( m_poRecordBlock == NULL );
-    m_poRecordBlock = new TABRawBinBlock(m_eAccessMode, FALSE);
+    m_poRecordBlock = new TABRawBinBlock(TABReadWrite, FALSE);
     m_poRecordBlock->InitNewBlock(m_fp, m_nBlockSize);
     m_poRecordBlock->SetFirstBlockPtr(m_nFirstRecordPtr);
 
@@ -406,7 +461,7 @@ int  TABDATFile::WriteHeader()
 {
     int i;
 
-    if (m_eAccessMode != TABWrite)
+    if (m_eAccessMode == TABRead)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "WriteHeader() can be used only with Write access.");
@@ -514,8 +569,9 @@ int  TABDATFile::GetNumRecords()
 TABRawBinBlock *TABDATFile::GetRecordBlock(int nRecordId)
 {
     m_bCurRecordDeletedFlag = FALSE;
+    m_bWriteEOF = FALSE;
 
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || nRecordId <= m_numRecords)
     {
         /*-------------------------------------------------------------
          * READ ACCESS
@@ -549,7 +605,7 @@ TABRawBinBlock *TABDATFile::GetRecordBlock(int nRecordId)
             m_bCurRecordDeletedFlag = TRUE;
         }
     }
-    else if (m_eAccessMode == TABWrite && nRecordId > 0)
+    else if (nRecordId > 0)
     {
         /*-------------------------------------------------------------
          * WRITE ACCESS
@@ -565,8 +621,12 @@ TABRawBinBlock *TABDATFile::GetRecordBlock(int nRecordId)
         {
             WriteHeader();
         }
+        
+        m_bUpdated = TRUE;
 
         m_numRecords = MAX(nRecordId, m_numRecords);
+        if( nRecordId == m_numRecords )
+            m_bWriteEOF = TRUE;
 
         nFileOffset = m_nFirstRecordPtr+(nRecordId-1)*m_nRecordSize;
 
@@ -597,10 +657,73 @@ TABRawBinBlock *TABDATFile::GetRecordBlock(int nRecordId)
  **********************************************************************/
 int  TABDATFile::CommitRecordToFile()
 {
-    if (m_eAccessMode != TABWrite || m_poRecordBlock == NULL)
+    if (m_eAccessMode == TABRead || m_poRecordBlock == NULL)
         return -1;
 
-    return m_poRecordBlock->CommitToFile();
+    if (m_poRecordBlock->CommitToFile() != 0)
+        return -1;
+    
+    /* If this is the end of file, write EOF character */
+    if (m_bWriteEOF)
+    {
+        m_bWriteEOF = FALSE;
+        char cEOF = 26;
+        if (VSIFSeekL(m_fp, 0L, SEEK_END) == 0)
+            VSIFWriteL(&cEOF, 1, 1, m_fp);
+    }
+    
+    return 0;
+}
+
+/**********************************************************************
+ *                   TABDATFile::MarkAsDeleted()
+ 
+ * Returns 0 on success, -1 on error.
+ **********************************************************************/
+int TABDATFile::MarkAsDeleted()
+{
+    if (m_eAccessMode == TABRead || m_poRecordBlock == NULL)
+        return -1;
+
+    int nFileOffset;
+    nFileOffset = m_nFirstRecordPtr+(m_nCurRecordId-1)*m_nRecordSize;
+
+    if (m_poRecordBlock->GotoByteInFile(nFileOffset) != 0)
+        return -1;
+
+    m_poRecordBlock->WriteByte('*');
+
+    if (m_poRecordBlock->CommitToFile() != 0)
+        return -1;
+    
+    m_bCurRecordDeletedFlag = TRUE;
+    m_bUpdated = TRUE;
+    
+    return 0;
+}
+
+/**********************************************************************
+ *                   TABDATFile::MarkRecordAsExisting()
+ 
+ * Returns 0 on success, -1 on error.
+ **********************************************************************/
+int TABDATFile::MarkRecordAsExisting()
+{
+    if (m_eAccessMode == TABRead || m_poRecordBlock == NULL)
+        return -1;
+
+    int nFileOffset;
+    nFileOffset = m_nFirstRecordPtr+(m_nCurRecordId-1)*m_nRecordSize;
+
+    if (m_poRecordBlock->GotoByteInFile(nFileOffset) != 0)
+        return -1;
+
+    m_poRecordBlock->WriteByte(' ');
+
+    m_bCurRecordDeletedFlag = FALSE;
+    m_bUpdated = TRUE;
+    
+    return 0;
 }
 
 
@@ -629,8 +752,6 @@ int  TABDATFile::ValidateFieldInfoFromTAB(int iField, const char *pszName,
 {
     int i = iField;  // Just to make things shorter
 
-    CPLAssert(m_pasFieldDef);
-
     if (m_pasFieldDef == NULL || iField < 0 || iField >= m_numFields)
     {
         CPLError(CE_Failure, CPLE_FileIO,
@@ -686,25 +807,13 @@ int  TABDATFile::ValidateFieldInfoFromTAB(int iField, const char *pszName,
 }
 
 /**********************************************************************
- *                   TABDATFile::AddField()
- *
- * Create a new field (column) in a newly created table.  This function
- * must be called after the file has been opened, but before writing the
- * first record.
+ *                  TABDATFileSetFieldDefinition()
  *
- * Returns the new field index (a value >= 0) if OK, -1 on error.
  **********************************************************************/
-int  TABDATFile::AddField(const char *pszName, TABFieldType eType,
-                          int nWidth, int nPrecision /*=0*/)
+static int TABDATFileSetFieldDefinition(TABDATFieldDef* psFieldDef,
+                                        const char *pszName, TABFieldType eType,
+                                        int nWidth, int nPrecision)
 {
-    if (m_eAccessMode != TABWrite || m_bWriteHeaderInitialized ||
-        m_eTableType != TABTableNative)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "Addition of new table fields is not supported after the "
-                 "first data item has been written.");
-        return -1;
-    }
 
     /*-----------------------------------------------------------------
      * Validate field width... must be <= 254
@@ -725,64 +834,697 @@ int  TABDATFile::AddField(const char *pszName, TABFieldType eType,
     else if (nWidth == 0)
         nWidth=254; /* char fields */
 
-    if (m_numFields < 0)
-        m_numFields = 0;
-
-    m_numFields++;
-    m_pasFieldDef = (TABDATFieldDef*)CPLRealloc(m_pasFieldDef, 
-                                          m_numFields*sizeof(TABDATFieldDef));
-
-    strncpy(m_pasFieldDef[m_numFields-1].szName, pszName, 10);
-    m_pasFieldDef[m_numFields-1].szName[10] = '\0';
-    m_pasFieldDef[m_numFields-1].eTABType = eType;
-    m_pasFieldDef[m_numFields-1].byLength = (GByte)nWidth;
-    m_pasFieldDef[m_numFields-1].byDecimals = (GByte)nPrecision;
+    strncpy(psFieldDef->szName, pszName, 10);
+    psFieldDef->szName[10] = '\0';
+    psFieldDef->eTABType = eType;
+    psFieldDef->byLength = (GByte)nWidth;
+    psFieldDef->byDecimals = (GByte)nPrecision;
 
     switch(eType)
     {
       case TABFChar:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
+        psFieldDef->cType = 'C';
         break;
       case TABFDecimal:
-        m_pasFieldDef[m_numFields-1].cType = 'N';
+        psFieldDef->cType = 'N';
         break;
       case TABFInteger:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 4;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 4;
         break;
       case TABFSmallInt:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 2;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 2;
         break;
       case TABFFloat:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 8;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 8;
         break;
       case TABFDate:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 4;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 4;
         break;
       case TABFTime:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 4;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 4;
         break;
       case TABFDateTime:
-        m_pasFieldDef[m_numFields-1].cType = 'C';
-        m_pasFieldDef[m_numFields-1].byLength = 8;
+        psFieldDef->cType = 'C';
+        psFieldDef->byLength = 8;
         break;
       case TABFLogical:
-        m_pasFieldDef[m_numFields-1].cType = 'L';
-        m_pasFieldDef[m_numFields-1].byLength = 1;
+        psFieldDef->cType = 'L';
+        psFieldDef->byLength = 1;
         break;
       default:
         CPLError(CE_Failure, CPLE_NotSupported,
                  "Unsupported field type for field `%s'", pszName);
         return -1;
     }
+    
+    return 0;
+}
+
+/**********************************************************************
+ *                   TABDATFile::AddField()
+ *
+ * Create a new field (column) in a newly created table.  This function
+ * must be called after the file has been opened, but before writing the
+ * first record.
+ *
+ * Returns the new field index (a value >= 0) if OK, -1 on error.
+ **********************************************************************/
+int  TABDATFile::AddField(const char *pszName, TABFieldType eType,
+                          int nWidth, int nPrecision /*=0*/)
+{
+    if (m_eAccessMode == TABRead || m_eTableType != TABTableNative)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Operation not supported on read-only files or on non-native table.");
+        return -1;
+    }
+
+    TABDATFieldDef sFieldDef;
+    if( TABDATFileSetFieldDefinition(&sFieldDef, pszName, eType,
+                                     nWidth, nPrecision) < 0 )
+        return -1;
+
+    if (m_numFields < 0)
+        m_numFields = 0;
+
+    m_numFields++;
+    m_pasFieldDef = (TABDATFieldDef*)CPLRealloc(m_pasFieldDef, 
+                                          m_numFields*sizeof(TABDATFieldDef));
+    memcpy(&m_pasFieldDef[m_numFields-1], &sFieldDef, sizeof(sFieldDef));
+
+    /* If there are already records, we cannot update in place */
+    /* so create a temporary .dat.tmp in which we create the new structure */
+    /* and then copy the widen records */
+    if( m_numRecords > 0 )
+    {
+        TABDATFile oTempFile;
+        CPLString osOriginalFile(m_pszFname);
+        CPLString osTmpFile(m_pszFname);
+        osTmpFile += ".tmp";
+        if( oTempFile.Open( osTmpFile.c_str(), TABWrite ) != 0 )
+            return -1;
+
+        int i;
+        /* Create field structure */
+        for(i = 0; i < m_numFields; i++)
+        {
+            oTempFile.AddField(m_pasFieldDef[i].szName,
+                               m_pasFieldDef[i].eTABType,
+                               m_pasFieldDef[i].byLength,
+                               m_pasFieldDef[i].byDecimals);
+        }
+
+        GByte* pabyRecord = (GByte*)CPLMalloc(m_nRecordSize);
+
+        /* Copy records */
+        for(int j = 0; j < m_numRecords; j++)
+        {
+            if( GetRecordBlock(1+j) == NULL ||
+                oTempFile.GetRecordBlock(1+j) == NULL )
+            {
+                CPLFree(pabyRecord);
+                oTempFile.Close();
+                VSIUnlink(osTmpFile);
+                return -1;
+            }
+            if (m_bCurRecordDeletedFlag)
+            {
+                oTempFile.MarkAsDeleted();
+            }
+            else
+            {
+                if( m_poRecordBlock->ReadBytes(m_nRecordSize-1, pabyRecord) != 0 ||
+                    oTempFile.m_poRecordBlock->WriteBytes(m_nRecordSize-1, pabyRecord) != 0 ||
+                    oTempFile.m_poRecordBlock->WriteZeros(m_pasFieldDef[m_numFields-1].byLength) != 0 )
+                {
+                    CPLFree(pabyRecord);
+                    oTempFile.Close();
+                    VSIUnlink(osTmpFile);
+                    return -1;
+                }
+                oTempFile.CommitRecordToFile();
+            }
+        }
+
+        CPLFree(pabyRecord);
+
+        /* Close temporary file */
+        oTempFile.Close();
+
+        /* Backup field definitions as we will need to set the TABFieldType */
+        TABDATFieldDef* pasFieldDefTmp = (TABDATFieldDef*)CPLMalloc(m_numFields*sizeof(TABDATFieldDef));
+        memcpy(pasFieldDefTmp, m_pasFieldDef, m_numFields*sizeof(TABDATFieldDef));
+
+        /* Close ourselves */
+        m_numFields--; /* so that Close() doesn't see the new field */
+        Close();
+
+        /* Move temporary file as main .data file and reopen it */
+        VSIUnlink(osOriginalFile);
+        VSIRename(osTmpFile, osOriginalFile);
+        if( Open( osOriginalFile, TABReadWrite ) < 0 )
+        {
+            CPLFree(pasFieldDefTmp);
+            return -1;
+        }
+
+        /* Restore saved TABFieldType */
+        for(i = 0; i < m_numFields; i++)
+        {
+            m_pasFieldDef[i].eTABType = pasFieldDefTmp[i].eTABType;
+        }
+        CPLFree(pasFieldDefTmp);
+    }
+
+    return 0;
+}
+
+
+/************************************************************************/
+/*                            DeleteField()                             */
+/************************************************************************/
+
+int TABDATFile::DeleteField( int iField )
+{
+    if (m_eAccessMode == TABRead || m_eTableType != TABTableNative)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Operation not supported on read-only files or on non-native table.");
+        return -1;
+    }
+    
+    if( iField < 0 || iField >= m_numFields )
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg, "Invalid field index: %d", iField);
+        return -1;
+    }
+
+    /* If no records have been written, then just remove from the field */
+    /* definition array */
+    if( m_numRecords <= 0 )
+    {
+        if( iField < m_numFields-1 )
+        {
+            memmove(m_pasFieldDef + iField, m_pasFieldDef + iField + 1,
+                    (m_numFields-1-iField)*sizeof(TABDATFieldDef));
+        }
+        m_numFields --;
+        return 0;
+    }
+
+    if( m_numFields == 1 )
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg, "Cannot delete the single remaining field.");
+        return -1;
+    }
+
+    /* Otherwise we need to do a temporary file */
+    TABDATFile oTempFile;
+    CPLString osOriginalFile(m_pszFname);
+    CPLString osTmpFile(m_pszFname);
+    osTmpFile += ".tmp";
+    if( oTempFile.Open( osTmpFile.c_str(), TABWrite ) != 0 )
+        return -1;
+
+    int i;
+    /* Create field structure */
+    int nRecordSizeBefore = 0;
+    int nRecordSizeAfter = 0;
+    for(i = 0; i < m_numFields; i++)
+    {
+        if( i != iField )
+        {
+            if( i < iField ) nRecordSizeBefore += m_pasFieldDef[i].byLength;
+            else if( i > iField ) nRecordSizeAfter += m_pasFieldDef[i].byLength;
+            oTempFile.AddField(m_pasFieldDef[i].szName,
+                                m_pasFieldDef[i].eTABType,
+                                m_pasFieldDef[i].byLength,
+                                m_pasFieldDef[i].byDecimals);
+        }
+    }
+
+    CPLAssert(nRecordSizeBefore + m_pasFieldDef[iField].byLength + nRecordSizeAfter == m_nRecordSize - 1);
+
+    GByte* pabyRecord = (GByte*)CPLMalloc(m_nRecordSize);
+
+    /* Copy records */
+    for(int j = 0; j < m_numRecords; j++)
+    {
+        if( GetRecordBlock(1+j) == NULL ||
+            oTempFile.GetRecordBlock(1+j) == NULL )
+        {
+            CPLFree(pabyRecord);
+            oTempFile.Close();
+            VSIUnlink(osTmpFile);
+            return -1;
+        }
+        if (m_bCurRecordDeletedFlag)
+        {
+            oTempFile.MarkAsDeleted();
+        }
+        else
+        {
+            if( m_poRecordBlock->ReadBytes(m_nRecordSize-1, pabyRecord) != 0 ||
+                (nRecordSizeBefore > 0 && oTempFile.m_poRecordBlock->WriteBytes(nRecordSizeBefore, pabyRecord) != 0) ||
+                (nRecordSizeAfter > 0 && oTempFile.m_poRecordBlock->WriteBytes(nRecordSizeAfter,
+                    pabyRecord + nRecordSizeBefore + m_pasFieldDef[iField].byLength) != 0) )
+            {
+                CPLFree(pabyRecord);
+                oTempFile.Close();
+                VSIUnlink(osTmpFile);
+                return -1;
+            }
+            oTempFile.CommitRecordToFile();
+        }
+    }
+
+    CPLFree(pabyRecord);
+
+    /* Close temporary file */
+    oTempFile.Close();
+
+    /* Backup field definitions as we will need to set the TABFieldType */
+    TABDATFieldDef* pasFieldDefTmp = (TABDATFieldDef*)CPLMalloc(m_numFields*sizeof(TABDATFieldDef));
+    memcpy(pasFieldDefTmp, m_pasFieldDef, m_numFields*sizeof(TABDATFieldDef));
+
+    /* Close ourselves */
+    Close();
+
+    /* Move temporary file as main .data file and reopen it */
+    VSIUnlink(osOriginalFile);
+    VSIRename(osTmpFile, osOriginalFile);
+    if( Open( osOriginalFile, TABReadWrite ) < 0 )
+    {
+        CPLFree(pasFieldDefTmp);
+        return -1;
+    }
+
+    /* Restore saved TABFieldType */
+    for(i = 0; i < m_numFields; i++)
+    {
+        if( i < iField )
+            m_pasFieldDef[i].eTABType = pasFieldDefTmp[i].eTABType;
+        else
+            m_pasFieldDef[i].eTABType = pasFieldDefTmp[i+1].eTABType;
+    }
+    CPLFree(pasFieldDefTmp);
 
     return 0;
 }
 
+/************************************************************************/
+/*                           ReorderFields()                            */
+/************************************************************************/
+
+int TABDATFile::ReorderFields( int* panMap )
+{
+    if (m_eAccessMode == TABRead || m_eTableType != TABTableNative)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Operation not supported on read-only files or on non-native table.");
+        return -1;
+    }
+    
+    if( m_numFields == 0)
+        return 0;
+
+    OGRErr eErr = OGRCheckPermutation(panMap, m_numFields);
+    if (eErr != OGRERR_NONE)
+        return -1;
+    
+    /* If no records have been written, then just reorder the field */
+    /* definition array */
+    if( m_numRecords <= 0 )
+    {
+        TABDATFieldDef* pasFieldDefTmp = (TABDATFieldDef*)CPLMalloc(m_numFields*sizeof(TABDATFieldDef));
+        memcpy(pasFieldDefTmp, m_pasFieldDef, m_numFields*sizeof(TABDATFieldDef));
+        for(int i = 0; i < m_numFields; i++) 
+        {
+            memcpy(m_pasFieldDef + i, pasFieldDefTmp + panMap[i],
+                   sizeof(TABDATFieldDef));
+        }
+        CPLFree(pasFieldDefTmp);
+        return 0;
+    }
+
+    // We could theoretically update in place, but a sudden interruption
+    // would leave the file in a undefined state.
+
+    TABDATFile oTempFile;
+    CPLString osOriginalFile(m_pszFname);
+    CPLString osTmpFile(m_pszFname);
+    osTmpFile += ".tmp";
+    if( oTempFile.Open( osTmpFile.c_str(), TABWrite ) != 0 )
+        return -1;
+
+    int i;
+    /* Create field structure */
+    int* panOldOffset = (int*)CPLMalloc(m_numFields * sizeof(int));
+    for(i = 0; i < m_numFields; i++)
+    {
+        int iBefore = panMap[i];
+        if( i == 0 )
+            panOldOffset[i] = 0;
+        else
+            panOldOffset[i] = panOldOffset[i-1] + m_pasFieldDef[i-1].byLength;
+        oTempFile.AddField(m_pasFieldDef[iBefore].szName,
+                            m_pasFieldDef[iBefore].eTABType,
+                            m_pasFieldDef[iBefore].byLength,
+                            m_pasFieldDef[iBefore].byDecimals);
+    }
+
+    GByte* pabyRecord = (GByte*)CPLMalloc(m_nRecordSize);
+
+    /* Copy records */
+    for(int j = 0; j < m_numRecords; j++)
+    {
+        if( GetRecordBlock(1+j) == NULL ||
+            oTempFile.GetRecordBlock(1+j) == NULL )
+        {
+            CPLFree(pabyRecord);
+            CPLFree(panOldOffset);
+            oTempFile.Close();
+            VSIUnlink(osTmpFile);
+            return -1;
+        }
+        if (m_bCurRecordDeletedFlag)
+        {
+            oTempFile.MarkAsDeleted();
+        }
+        else
+        {
+            if( m_poRecordBlock->ReadBytes(m_nRecordSize-1, pabyRecord) != 0 )
+            {
+                CPLFree(pabyRecord);
+                CPLFree(panOldOffset);
+                oTempFile.Close();
+                VSIUnlink(osTmpFile);
+                return -1;
+            }
+            for(i = 0; i < m_numFields; i++)
+            {
+                int iBefore = panMap[i];
+                if( oTempFile.m_poRecordBlock->WriteBytes(
+                        m_pasFieldDef[iBefore].byLength, pabyRecord + panOldOffset[iBefore]) != 0 )
+                {
+                    CPLFree(pabyRecord);
+                    CPLFree(panOldOffset);
+                    oTempFile.Close();
+                    VSIUnlink(osTmpFile);
+                    return -1;
+                }
+            }
+            
+            oTempFile.CommitRecordToFile();
+        }
+    }
+
+    CPLFree(pabyRecord);
+    CPLFree(panOldOffset);
+
+    /* Close temporary file */
+    oTempFile.Close();
+
+    /* Backup field definitions as we will need to set the TABFieldType */
+    TABDATFieldDef* pasFieldDefTmp = (TABDATFieldDef*)CPLMalloc(m_numFields*sizeof(TABDATFieldDef));
+    memcpy(pasFieldDefTmp, m_pasFieldDef, m_numFields*sizeof(TABDATFieldDef));
+
+    /* Close ourselves */
+    Close();
+
+    /* Move temporary file as main .data file and reopen it */
+    VSIUnlink(osOriginalFile);
+    VSIRename(osTmpFile, osOriginalFile);
+    if( Open( osOriginalFile, TABReadWrite ) < 0 )
+    {
+        CPLFree(pasFieldDefTmp);
+        return -1;
+    }
+
+    /* Restore saved TABFieldType */
+    for(i = 0; i < m_numFields; i++)
+    {
+        int iBefore = panMap[i];
+        m_pasFieldDef[i].eTABType = pasFieldDefTmp[iBefore].eTABType;
+    }
+    CPLFree(pasFieldDefTmp);
+
+    return 0;
+}
+
+/************************************************************************/
+/*                           AlterFieldDefn()                           */
+/************************************************************************/
+
+int TABDATFile::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
+{
+    if (m_eAccessMode == TABRead || m_eTableType != TABTableNative)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Operation not supported on read-only files or on non-native table.");
+        return -1;
+    }
+
+    if( iField < 0 || iField >= m_numFields )
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg, "Invalid field index: %d", iField);
+        return -1;
+    }
+
+    TABFieldType        eTABType = m_pasFieldDef[iField].eTABType;
+    int                 nWidth = m_pasFieldDef[iField].byLength ;
+    int                 nWidthDummy;
+    if( (nFlags & ALTER_TYPE_FLAG) )
+    {
+        if( IMapInfoFile::GetTABType( poNewFieldDefn, &eTABType, &nWidthDummy ) < 0 )
+            return -1;
+    }
+    if( (nFlags & ALTER_WIDTH_PRECISION_FLAG) )
+    {
+        TABFieldType eTABTypeDummy;
+        if( IMapInfoFile::GetTABType( poNewFieldDefn, &eTABTypeDummy, &nWidth ) < 0 )
+            return -1;
+    }
+    
+    if ((nFlags & ALTER_TYPE_FLAG) &&
+        eTABType != m_pasFieldDef[iField].eTABType)
+    {
+        if ( eTABType != TABFChar )
+        {
+            CPLError( CE_Failure, CPLE_NotSupported,
+                      "Can only convert to OFTString");
+            return -1;
+        }
+        if( (nFlags & ALTER_WIDTH_PRECISION_FLAG) == 0 )
+            nWidth = 254;
+    }
+
+    if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
+    {
+        if( eTABType != TABFChar && nWidth != m_pasFieldDef[iField].byLength )
+        {
+            CPLError( CE_Failure, CPLE_NotSupported,
+                      "Resizing only supported on String fields");
+            return -1;
+        }
+    }
+
+    if (nFlags & ALTER_NAME_FLAG)
+    {
+        strncpy(m_pasFieldDef[iField].szName, poNewFieldDefn->GetNameRef(), 10);
+        m_pasFieldDef[iField].szName[10] = '\0';
+        /* If renaming is the only operation, then nothing more to do */
+        if( nFlags == ALTER_NAME_FLAG )
+        {
+            m_bUpdated = TRUE;
+            return 0;
+        }
+    }
+
+    if( m_numRecords <= 0)
+    {
+        if( (nFlags & ALTER_TYPE_FLAG) &&
+            eTABType != m_pasFieldDef[iField].eTABType)
+        {
+            TABDATFieldDef sFieldDef;
+            TABDATFileSetFieldDefinition(&sFieldDef,
+                                         m_pasFieldDef[iField].szName, eTABType,
+                                         m_pasFieldDef[iField].byLength,
+                                         m_pasFieldDef[iField].byDecimals);
+            memcpy(&m_pasFieldDef[iField], &sFieldDef, sizeof(sFieldDef));
+        }
+        if (nFlags & ALTER_WIDTH_PRECISION_FLAG)
+        {
+            m_pasFieldDef[iField].byLength = (GByte)nWidth;
+        }
+        return 0;
+    }
+
+    /* Otherwise we need to do a temporary file */
+    TABDATFile oTempFile;
+    CPLString osOriginalFile(m_pszFname);
+    CPLString osTmpFile(m_pszFname);
+    osTmpFile += ".tmp";
+    if( oTempFile.Open( osTmpFile.c_str(), TABWrite ) != 0 )
+        return -1;
+
+    int i;
+    /* Create field structure */
+    int nRecordSizeBefore = 0;
+    int nRecordSizeAfter = 0;
+    TABDATFieldDef sFieldDef;
+    TABDATFileSetFieldDefinition(&sFieldDef,
+                                 m_pasFieldDef[iField].szName,
+                                 eTABType,
+                                 nWidth,
+                                 m_pasFieldDef[iField].byDecimals);
+
+    for(i = 0; i < m_numFields; i++)
+    {
+        if( i != iField )
+        {
+            if( i < iField ) nRecordSizeBefore += m_pasFieldDef[i].byLength;
+            else if( i > iField ) nRecordSizeAfter += m_pasFieldDef[i].byLength;
+            oTempFile.AddField(m_pasFieldDef[i].szName,
+                                m_pasFieldDef[i].eTABType,
+                                m_pasFieldDef[i].byLength,
+                                m_pasFieldDef[i].byDecimals);
+        }
+        else
+        {
+            oTempFile.AddField(sFieldDef.szName,
+                               sFieldDef.eTABType,
+                               sFieldDef.byLength,
+                               sFieldDef.byDecimals);
+        }
+    }
+
+    GByte* pabyRecord = (GByte*)CPLMalloc(m_nRecordSize);
+    char* pabyNewField = (char*)CPLMalloc(sFieldDef.byLength + 1);
+
+    /* Copy records */
+    for(int j = 0; j < m_numRecords; j++)
+    {
+        if( GetRecordBlock(1+j) == NULL ||
+            oTempFile.GetRecordBlock(1+j) == NULL )
+        {
+            CPLFree(pabyRecord);
+            CPLFree(pabyNewField);
+            oTempFile.Close();
+            VSIUnlink(osTmpFile);
+            return -1;
+        }
+        if (m_bCurRecordDeletedFlag)
+        {
+            oTempFile.MarkAsDeleted();
+        }
+        else
+        {
+            if( nRecordSizeBefore > 0 && 
+                (m_poRecordBlock->ReadBytes(nRecordSizeBefore, pabyRecord) != 0 ||
+                 oTempFile.m_poRecordBlock->WriteBytes(nRecordSizeBefore, pabyRecord) != 0) )
+            {
+                CPLFree(pabyRecord);
+                CPLFree(pabyNewField);
+                oTempFile.Close();
+                VSIUnlink(osTmpFile);
+                return -1;
+            }
+
+            memset(pabyNewField, 0, sFieldDef.byLength + 1);
+            if( m_pasFieldDef[iField].eTABType == TABFChar )
+            {
+                strncpy(pabyNewField, ReadCharField(m_pasFieldDef[iField].byLength), sFieldDef.byLength);
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFInteger )
+            {
+                snprintf(pabyNewField, sFieldDef.byLength, "%d", ReadIntegerField(m_pasFieldDef[iField].byLength));
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFSmallInt )
+            {
+                snprintf(pabyNewField, sFieldDef.byLength, "%d", ReadSmallIntField(m_pasFieldDef[iField].byLength));
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFFloat )
+            {
+                CPLsnprintf(pabyNewField, sFieldDef.byLength, "%.18f", ReadFloatField(m_pasFieldDef[iField].byLength));
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFDecimal )
+            {
+                CPLsnprintf(pabyNewField, sFieldDef.byLength, "%.18f", ReadFloatField(m_pasFieldDef[iField].byLength));
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFLogical )
+            {
+                strncpy(pabyNewField, ReadLogicalField(m_pasFieldDef[iField].byLength), sFieldDef.byLength);
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFDate )
+            {
+                strncpy(pabyNewField, ReadDateField(m_pasFieldDef[iField].byLength), sFieldDef.byLength);
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFTime )
+            {
+                strncpy(pabyNewField, ReadTimeField(m_pasFieldDef[iField].byLength), sFieldDef.byLength);
+            }
+            else if( m_pasFieldDef[iField].eTABType == TABFDateTime )
+            {
+                strncpy(pabyNewField, ReadDateTimeField(m_pasFieldDef[iField].byLength), sFieldDef.byLength);
+            }
+
+            if( oTempFile.m_poRecordBlock->WriteBytes(sFieldDef.byLength, (GByte*)pabyNewField) != 0 ||
+                (nRecordSizeAfter > 0 && 
+                (m_poRecordBlock->ReadBytes(nRecordSizeAfter, pabyRecord) != 0 ||
+                 oTempFile.m_poRecordBlock->WriteBytes(nRecordSizeAfter, pabyRecord) != 0)) )
+            {
+                CPLFree(pabyRecord);
+                CPLFree(pabyNewField);
+                oTempFile.Close();
+                VSIUnlink(osTmpFile);
+                return -1;
+            }
+            oTempFile.CommitRecordToFile();
+        }
+    }
+
+    CPLFree(pabyRecord);
+    CPLFree(pabyNewField);
+
+    /* Close temporary file */
+    oTempFile.Close();
+
+    /* Backup field definitions as we will need to set the TABFieldType */
+    TABDATFieldDef* pasFieldDefTmp = (TABDATFieldDef*)CPLMalloc(m_numFields*sizeof(TABDATFieldDef));
+    memcpy(pasFieldDefTmp, m_pasFieldDef, m_numFields*sizeof(TABDATFieldDef));
+
+    /* Close ourselves */
+    Close();
+
+    /* Move temporary file as main .data file and reopen it */
+    VSIUnlink(osOriginalFile);
+    VSIRename(osTmpFile, osOriginalFile);
+    if( Open( osOriginalFile, TABReadWrite ) < 0 )
+    {
+        CPLFree(pasFieldDefTmp);
+        return -1;
+    }
+
+    /* Restore saved TABFieldType */
+    for(i = 0; i < m_numFields; i++)
+    {
+        if( i != iField )
+            m_pasFieldDef[i].eTABType = pasFieldDefTmp[i].eTABType;
+        else
+            m_pasFieldDef[i].eTABType = eTABType;
+    }
+    CPLFree(pasFieldDefTmp);
+
+    return 0;
+}
+
+
 /**********************************************************************
  *                   TABDATFile::GetFieldType()
  *
@@ -969,7 +1711,7 @@ double TABDATFile::ReadFloatField(int nWidth)
     }
 
     if (m_eTableType == TABTableDBF)
-        return atof(ReadCharField(nWidth));
+        return CPLAtof(ReadCharField(nWidth));
 
     return m_poRecordBlock->ReadDouble();
 }
@@ -1255,7 +1997,7 @@ double TABDATFile::ReadDecimalField(int nWidth)
 
     pszVal = ReadCharField(nWidth);
 
-    return atof(pszVal);
+    return CPLAtof(pszVal);
 }
 
 
@@ -1828,9 +2570,11 @@ int TABDATFile::WriteDateTimeField(int nYear, int nMonth, int nDay,
 int TABDATFile::WriteDecimalField(double dValue, int nWidth, int nPrec,
                                   TABINDFile *poINDFile, int nIndexNo)
 {
+    char szFormat[10];
     const char *pszVal;
 
-    pszVal = CPLSPrintf("%*.*f", nWidth, nPrec, dValue);
+    sprintf(szFormat, "%%%d.%df", nWidth, nPrec);
+    pszVal = CPLSPrintf(szFormat, dValue);
     if ((int)strlen(pszVal) > nWidth)
         pszVal += strlen(pszVal) - nWidth;
 
diff --git a/ogr/ogrsf_frmts/mitab/mitab_feature.cpp b/ogr/ogrsf_frmts/mitab/mitab_feature.cpp
index b58acd1..7877ce4 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_feature.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_feature.cpp
@@ -9,6 +9,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2002, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -455,8 +456,8 @@ int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
     double      dValue;
     const char *pszValue;
 #ifdef MITAB_USE_OFTDATETIME
-    int nYear, nMonth, nDay, nHour, nMin, nSec, nMS, status;
-    nYear = nMonth = nDay = nHour = nMin = nSec = nMS = 0;
+    int nYear, nMonth, nDay, nHour, nMin, nMS, status;
+    nYear = nMonth = nDay = nHour = nMin = nMS = 0;
 #endif
 
     CPLAssert(poDATFile);
@@ -502,7 +503,7 @@ int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
              if ((status = poDATFile->ReadDateField(poDATFile->GetFieldWidth(iField),
                                                     &nYear, &nMonth, &nDay)) == 0)
              {
-                SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
+                SetField(iField, nYear, nMonth, nDay, 0, 0, 0, 0);
              }
 #else
             pszValue = poDATFile->ReadDateField(poDATFile->
@@ -511,11 +512,13 @@ int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
 #endif
             break;
           case TABFTime:
+          {
 #ifdef MITAB_USE_OFTDATETIME
+             int nSec;
              if ((status = poDATFile->ReadTimeField(poDATFile->GetFieldWidth(iField),
                                                     &nHour, &nMin, &nSec, &nMS)) == 0)
              {
-                SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
+                SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f, 0);
              }
 #else
              pszValue = poDATFile->ReadTimeField(poDATFile->
@@ -523,13 +526,15 @@ int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
              SetField(iField, pszValue);
 #endif
             break;
+          }
           case TABFDateTime:
 #ifdef MITAB_USE_OFTDATETIME
+            int nSec;
             if ((status = poDATFile->ReadDateTimeField(poDATFile->GetFieldWidth(iField),
                                                        &nYear, &nMonth, &nDay,
                                                        &nHour, &nMin, &nSec, &nMS)) == 0)
             {
-               SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
+               SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f, 0);
             }
 #else
             pszValue = poDATFile->ReadDateTimeField(poDATFile->
@@ -564,8 +569,9 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
 {
     int         iField, numFields, nStatus=0;
 #ifdef MITAB_USE_OFTDATETIME
-    int         nYear, nMon, nDay, nHour, nMin, nSec, nTZFlag;
-    nYear = nMon = nDay = nHour = nMin = nSec = nTZFlag = 0;
+    int         nYear, nMon, nDay, nHour, nMin, nTZFlag;
+    nYear = nMon = nDay = nHour = nMin = nTZFlag = 0;
+    float       fSec = 0;
 #endif
 
     CPLAssert(poDATFile);
@@ -573,6 +579,8 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
 
     numFields = poDATFile->GetNumFields();
 
+    poDATFile->MarkRecordAsExisting();
+
     for(iField=0; nStatus == 0 && iField<numFields; iField++)
     {
         // Hack for "extra" introduced field.
@@ -580,7 +588,7 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
         {
             CPLAssert( poDATFile->GetFieldType(iField) == TABFInteger 
                        && iField == 0 );
-            nStatus = poDATFile->WriteIntegerField( GetFID(), poINDFile, 0 );
+            nStatus = poDATFile->WriteIntegerField( (int)GetFID(), poINDFile, 0 );
             continue;
         }
 
@@ -618,7 +626,7 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
              if (IsFieldSet(iField))
              {
                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
-                                   &nHour, &nMin, &nSec, &nTZFlag);
+                                   &nHour, &nMin, &fSec, &nTZFlag);
              }
              else
                  nYear = nMon = nDay = 0;
@@ -635,14 +643,16 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
              if (IsFieldSet(iField))
              {
                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
-                                   &nHour, &nMin, &nSec, &nTZFlag);
+                                   &nHour, &nMin, &fSec, &nTZFlag);
              }
              else
              {
-                nHour = nMin = nSec = -1;
+                nHour = nMin = 0;
+                fSec = 0;
              }
-             nStatus = poDATFile->WriteTimeField(nHour, nMin, nSec, 0,
-                                                    poINDFile, panIndexNo[iField]);
+             nStatus = poDATFile->WriteTimeField(nHour, nMin, (int)fSec,
+                                                 OGR_GET_MS(fSec),
+                                                 poINDFile, panIndexNo[iField]);
              
 #else
              nStatus = poDATFile->WriteTimeField(GetFieldAsString(iField),
@@ -654,13 +664,17 @@ int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
              if (IsFieldSet(iField))
              {
                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
-                                   &nHour, &nMin, &nSec, &nTZFlag);
+                                   &nHour, &nMin, &fSec, &nTZFlag);
              }
              else
-                 nYear = nMon = nDay = nHour = nMin = nSec = 0;
+             {
+                 nYear = nMon = nDay = nHour = nMin = 0;
+                 fSec = 0;
+             }
 
              nStatus = poDATFile->WriteDateTimeField(nYear, nMon, nDay, 
-                                                     nHour, nMin, nSec, 0,
+                                                     nHour, nMin, (int)fSec,
+                                                     OGR_GET_MS(fSec),
                                                      poINDFile, panIndexNo[iField]);
 #else
              nStatus = poDATFile->WriteDateTimeField(GetFieldAsString(iField),
@@ -793,9 +807,9 @@ GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
      * Adjust native type
      *------------------------------------------------------------*/
     if (bCompr && ((m_nMapInfoType%3) == 2))
-        m_nMapInfoType--;  // compr = 1, 4, 7, ...
+        m_nMapInfoType = (TABGeomType)(m_nMapInfoType - 1);  // compr = 1, 4, 7, ...
     else if (!bCompr && ((m_nMapInfoType%3) == 1))
-        m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
+        m_nMapInfoType = (TABGeomType)(m_nMapInfoType + 1);  // non-compr = 2, 5, 8, ...
 
     return bCompr;
 }
@@ -808,7 +822,7 @@ GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
  * to be the same. (A replacement for ValidateCoordType() for this 
  * specific case)
  **********************************************************************/
-void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
+void TABFeature::ForceCoordTypeAndOrigin(TABGeomType nMapInfoType, GBool bCompr,
                                          GInt32 nComprOrgX, GInt32 nComprOrgY,
                                          GInt32 nXMin, GInt32 nYMin, 
                                          GInt32 nXMax, GInt32 nYMax)
@@ -822,9 +836,9 @@ void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
     m_nMapInfoType = nMapInfoType;
 
     if (bCompr && ((m_nMapInfoType%3) == 2))
-        m_nMapInfoType--;  // compr = 1, 4, 7, ...
+        m_nMapInfoType = (TABGeomType)(m_nMapInfoType - 1);  // compr = 1, 4, 7, ...
     else if (!bCompr && ((m_nMapInfoType%3) == 1))
-        m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
+        m_nMapInfoType = (TABGeomType)(m_nMapInfoType + 1);  // non-compr = 2, 5, 8, ...
 
     m_nXMin = nXMin;
     m_nYMin = nYMin;
@@ -976,7 +990,7 @@ TABFeature *TABPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -1952,7 +1966,7 @@ OGRLineString *TABPolyline::GetPartRef(int nPartIndex)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry   *poGeom;
     OGRMultiLineString *poMultiLine = NULL;
@@ -2941,7 +2955,7 @@ TABFeature *TABRegion::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -3924,7 +3938,7 @@ TABFeature *TABRectangle::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -4383,7 +4397,7 @@ TABFeature *TABEllipse::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -4797,7 +4811,7 @@ TABFeature *TABArc::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -5335,7 +5349,7 @@ TABFeature *TABText::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -6402,7 +6416,7 @@ TABFeature *TABMultiPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
 
@@ -6749,8 +6763,6 @@ int TABMultiPoint::GetNumPoints()
                  "TABMultiPoint: Missing or Invalid Geometry!");
         return 0;
     }
-
-    return 0;
 }
 
 
@@ -6971,7 +6983,7 @@ TABFeature *TABCollection::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
  * is expected for this object class.
  **********************************************************************/
-int  TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
+TABGeomType TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
 {
     OGRGeometry *poGeom;
     int nRegionType=TAB_GEOM_NONE, nPLineType=TAB_GEOM_NONE, 
@@ -7277,7 +7289,7 @@ int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
         else
             oRegionHdr.m_nType = TAB_GEOM_V450_REGION;
         if (nVersion == 800)
-            oRegionHdr.m_nType += (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION);
+            oRegionHdr.m_nType = (TABGeomType)(oRegionHdr.m_nType + (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION));
 
         oRegionHdr.m_numLineSections = poCollHdr->m_nNumRegSections;
         oRegionHdr.m_nPenId = poCollHdr->m_nRegionPenId;
@@ -7340,8 +7352,8 @@ int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
         else
             oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE;
         if (nVersion == 800)
-            oPLineHdr.m_nType += (TAB_GEOM_V800_MULTIPLINE - 
-                                  TAB_GEOM_V450_MULTIPLINE);
+            oPLineHdr.m_nType = (TABGeomType) (oPLineHdr.m_nType + (TAB_GEOM_V800_MULTIPLINE - 
+                                  TAB_GEOM_V450_MULTIPLINE));
 
         oPLineHdr.m_numLineSections = poCollHdr->m_nNumPLineSections;
         oPLineHdr.m_nPenId = poCollHdr->m_nPolylinePenId;
@@ -7393,8 +7405,8 @@ int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
         else
             oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT;
         if (nVersion == 800)
-            oMPointHdr.m_nType += (TAB_GEOM_V800_MULTIPOINT - 
-                                   TAB_GEOM_MULTIPOINT);
+            oMPointHdr.m_nType = (TABGeomType) (oMPointHdr.m_nType + (TAB_GEOM_V800_MULTIPOINT - 
+                                  TAB_GEOM_MULTIPOINT));
 
         oMPointHdr.m_nNumPoints = poCollHdr->m_nNumMultiPoints;
         oMPointHdr.m_nSymbolId = poCollHdr->m_nMultiPointSymbolId;
@@ -7502,11 +7514,11 @@ int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
                   m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION_C );
 
         TABMAPObjPLine *poRegionHdr = (TABMAPObjPLine *)
-            TABMAPObjHdr::NewObj((GByte)m_poRegion->GetMapInfoType(), -1);
+            TABMAPObjHdr::NewObj(m_poRegion->GetMapInfoType(), -1);
 
         // Update count of objects by type in header
         if (!bCoordBlockDataOnly)
-            poMapFile->UpdateMapHeaderInfo((GByte)m_poRegion->GetMapInfoType());
+            poMapFile->UpdateMapHeaderInfo(m_poRegion->GetMapInfoType());
 
         // Write a placeholder for centroid/label point and MBR mini-header
         // and we'll come back later to write the real values.
@@ -7602,11 +7614,11 @@ int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
                   m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE_C );
 
         TABMAPObjPLine *poPlineHdr = (TABMAPObjPLine *)
-            TABMAPObjHdr::NewObj((GByte)m_poPline->GetMapInfoType(), -1);
+            TABMAPObjHdr::NewObj(m_poPline->GetMapInfoType(), -1);
 
         // Update count of objects by type in header
         if (!bCoordBlockDataOnly)
-            poMapFile->UpdateMapHeaderInfo((GByte)m_poPline->GetMapInfoType());
+            poMapFile->UpdateMapHeaderInfo(m_poPline->GetMapInfoType());
 
         // Write a placeholder for centroid/label point and MBR mini-header
         // and we'll come back later to write the real values.
@@ -7700,11 +7712,11 @@ int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
                   m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT_C );
 
         TABMAPObjMultiPoint *poMpointHdr = (TABMAPObjMultiPoint *)
-            TABMAPObjHdr::NewObj((GByte)m_poMpoint->GetMapInfoType(), -1);
+            TABMAPObjHdr::NewObj(m_poMpoint->GetMapInfoType(), -1);
 
         // Update count of objects by type in header
         if (!bCoordBlockDataOnly)
-            poMapFile->UpdateMapHeaderInfo((GByte)m_poMpoint->GetMapInfoType());
+            poMapFile->UpdateMapHeaderInfo(m_poMpoint->GetMapInfoType());
 
         // Write a placeholder for centroid/label point and MBR mini-header
         // and we'll come back later to write the real values.
@@ -8383,7 +8395,7 @@ const char *ITABFeaturePen::GetPenStyleString()
 void  ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
 {
     int numParts, i;
-    GBool bIsNull;
+    GBool bIsNull = 0;
 
     const char *pszPenName, *pszPenPattern;
 
@@ -8393,7 +8405,7 @@ void  ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
     const char *pszPenColor;
 
     int   nPenId;
-    char* pszPenId;
+    const char* pszPenId;
 
     // Use the Style Manager to retreive all the information we need.
     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
@@ -8470,17 +8482,22 @@ void  ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
     if(pszPenName && 
        (strstr(pszPenName, "mapinfo-pen-") || strstr(pszPenName, "ogr-pen-")) )
     {
-        if((pszPenId = (char *) strstr(pszPenName, "mapinfo-pen-")))
+        pszPenId = strstr(pszPenName, "mapinfo-pen-");
+        if( pszPenId != NULL )
         {
             nPenId = atoi(pszPenId+12);
             SetPenPattern((GByte)nPenId);
         }
-        else if((pszPenId = (char *) strstr(pszPenName, "ogr-pen-")))
+        else
         {
-            nPenId = atoi(pszPenId+8);
-            if(nPenId == 0)
-                nPenId = 2;
-            SetPenPattern((GByte)nPenId);
+            pszPenId = strstr(pszPenName, "ogr-pen-");
+            if( pszPenId != NULL )
+            {
+                nPenId = atoi(pszPenId+8);
+                if(nPenId == 0)
+                    nPenId = 2;
+                SetPenPattern((GByte)nPenId);
+            }
         }
     }
     else
@@ -8643,7 +8660,7 @@ const char *ITABFeatureBrush::GetBrushStyleString()
 void  ITABFeatureBrush::SetBrushFromStyleString(const char *pszStyleString)
 {
     int numParts, i;
-    GBool bIsNull;
+    GBool bIsNull = 0;
 
     const char *pszBrushId;
     int nBrushId;
@@ -8912,7 +8929,7 @@ const char *ITABFeatureSymbol::GetSymbolStyleString(double dfAngle)
 void ITABFeatureSymbol::SetSymbolFromStyleString(const char *pszStyleString)
 {
     int numParts, i;
-    GBool bIsNull;
+    GBool bIsNull = 0;
 
     const char *pszSymbolId;
     int nSymbolId;
diff --git a/ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp b/ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp
index d916887..c801fc3 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_feature_mif.cpp
@@ -282,7 +282,8 @@ int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
                 if (strlen(papszToken[i]) == 9)
                 {
                     sscanf(papszToken[i],"%2d%2d%2d%3d",&nHour, &nMin, &nSec, &nMS);
-                    SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
+                    SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f,
+                             0);
                 }
                 break;
             }
@@ -301,7 +302,8 @@ int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
                 {
                     sscanf(papszToken[i], "%4d%2d%2d%2d%2d%2d%3d",
                            &nYear, &nMonth, &nDay, &nHour, &nMin, &nSec, &nMS);
-                    SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
+                    SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f,
+                             0);
                 }
                 break;
             }
@@ -333,8 +335,9 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
     OGRFieldDefn        *poFDefn = NULL;
 #ifdef MITAB_USE_OFTDATETIME
     char szBuffer[20];
-    int nYear, nMonth, nDay, nHour, nMin, nSec, nMS, nTZFlag;
-    nYear = nMonth = nDay = nHour = nMin = nSec = nMS = nTZFlag = 0;
+    int nYear, nMonth, nDay, nHour, nMin, nMS, nTZFlag;
+    nYear = nMonth = nDay = nHour = nMin = nMS = nTZFlag = 0;
+    float fSec = 0.0f;
 #endif
 
     CPLAssert(fp);
@@ -346,7 +349,7 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
     for(iField=0; iField<numFields; iField++)
     {
         if (iField != 0)
-          fp->WriteLine(delimiter);
+          fp->WriteLine("%s", delimiter);
         poFDefn = GetFieldDefnRef( iField );
 
         switch(poFDefn->GetType())
@@ -396,8 +399,9 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
               else
               {
                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
-                                     &nHour, &nMin, &nSec, &nTZFlag);
-                  sprintf(szBuffer, "%2.2d%2.2d%2.2d%3.3d", nHour, nMin, nSec, nMS);
+                                     &nHour, &nMin, &fSec, &nTZFlag);
+                  sprintf(szBuffer, "%2.2d%2.2d%2.2d%3.3d", nHour, nMin,
+                          (int)fSec, OGR_GET_MS(fSec));
               }
               fp->WriteLine("%s",szBuffer);
               break;
@@ -411,7 +415,7 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
               else
               {
                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
-                                     &nHour, &nMin, &nSec, &nTZFlag);
+                                     &nHour, &nMin, &fSec, &nTZFlag);
                   sprintf(szBuffer, "%4.4d%2.2d%2.2d", nYear, nMonth, nDay);
               }
               fp->WriteLine("%s",szBuffer);
@@ -426,9 +430,10 @@ int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
               else
               {
                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
-                                     &nHour, &nMin, &nSec, &nTZFlag);
+                                     &nHour, &nMin, &fSec, &nTZFlag);
                   sprintf(szBuffer, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d%3.3d", 
-                          nYear, nMonth, nDay, nHour, nMin, nSec, nMS);
+                          nYear, nMonth, nDay, nHour, nMin,
+                          (int)fSec, OGR_GET_MS(fSec));
               }
               fp->WriteLine("%s",szBuffer);
               break;
@@ -515,8 +520,8 @@ int TABPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
         return -1;
     }
     
-    dfX = fp->GetXTrans(atof(papszToken[1]));
-    dfY = fp->GetYTrans(atof(papszToken[2]));
+    dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
+    dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
 
     CSLDestroy(papszToken);
     papszToken = NULL;
@@ -601,8 +606,8 @@ int TABFontPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
         return -1;
     }
 
-    dfX = fp->GetXTrans(atof(papszToken[1]));
-    dfY = fp->GetYTrans(atof(papszToken[2]));
+    dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
+    dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
     
     CSLDestroy(papszToken);
     
@@ -620,7 +625,7 @@ int TABFontPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
     SetSymbolSize((GInt16)atoi(papszToken[3]));
     SetFontName(papszToken[4]);
     SetFontStyleMIFValue(atoi(papszToken[5]));
-    SetSymbolAngle(atof(papszToken[6]));
+    SetSymbolAngle(CPLAtof(papszToken[6]));
 
     CSLDestroy(papszToken);
     
@@ -689,8 +694,8 @@ int TABCustomPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
         return -1;
     }
 
-    dfX = fp->GetXTrans(atof(papszToken[1]));
-    dfY = fp->GetYTrans(atof(papszToken[2]));
+    dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
+    dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
 
     CSLDestroy(papszToken);
     
@@ -785,10 +790,10 @@ int TABPolyline::ReadGeometryFromMIFFile(MIDDATAFile *fp)
 
         poLine = new OGRLineString();
         poLine->setNumPoints(2);
-        poLine->setPoint(0, fp->GetXTrans(atof(papszToken[1])),
-                         fp->GetYTrans(atof(papszToken[2])));
-        poLine->setPoint(1, fp->GetXTrans(atof(papszToken[3])),
-                         fp->GetYTrans(atof(papszToken[4])));
+        poLine->setPoint(0, fp->GetXTrans(CPLAtof(papszToken[1])),
+                         fp->GetYTrans(CPLAtof(papszToken[2])));
+        poLine->setPoint(1, fp->GetXTrans(CPLAtof(papszToken[3])),
+                         fp->GetYTrans(CPLAtof(papszToken[4])));
         SetGeometryDirectly(poLine);
         poLine->getEnvelope(&sEnvelope);
         SetMBR(sEnvelope.MinX, sEnvelope.MinY,sEnvelope.MaxX,sEnvelope.MaxY);
@@ -862,8 +867,8 @@ int TABPolyline::ReadGeometryFromMIFFile(MIDDATAFile *fp)
                     CSLDestroy(papszToken);
                     papszToken = CSLTokenizeString2(fp->GetLine(), 
                                                     " \t", CSLT_HONOURSTRINGS);
-                    poLine->setPoint(i,fp->GetXTrans(atof(papszToken[0])),
-                                     fp->GetYTrans(atof(papszToken[1])));
+                    poLine->setPoint(i,fp->GetXTrans(CPLAtof(papszToken[0])),
+                                     fp->GetYTrans(CPLAtof(papszToken[1])));
                 }
                 if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
                 {
@@ -890,8 +895,8 @@ int TABPolyline::ReadGeometryFromMIFFile(MIDDATAFile *fp)
     
                 if (CSLCount(papszToken) != 2)
                   return -1;
-                poLine->setPoint(i,fp->GetXTrans(atof(papszToken[0])),
-                                 fp->GetYTrans(atof(papszToken[1])));
+                poLine->setPoint(i,fp->GetXTrans(CPLAtof(papszToken[0])),
+                                 fp->GetYTrans(CPLAtof(papszToken[1])));
             }
             SetGeometryDirectly(poLine);
             poLine->getEnvelope(&sEnvelope);
@@ -1075,8 +1080,8 @@ int TABRegion::ReadGeometryFromMIFFile(MIDDATAFile *fp)
                                                       TRUE,FALSE);
                 if (CSLCount(papszToken) == 2)
                 {              
-                    dX = fp->GetXTrans(atof(papszToken[0]));
-                    dY = fp->GetYTrans(atof(papszToken[1]));
+                    dX = fp->GetXTrans(CPLAtof(papszToken[0]));
+                    dY = fp->GetYTrans(CPLAtof(papszToken[1]));
                     poRing->setPoint(i, dX, dY);
                 }
                 CSLDestroy(papszToken);
@@ -1154,8 +1159,8 @@ int TABRegion::ReadGeometryFromMIFFile(MIDDATAFile *fp)
             {
                 if (CSLCount(papszToken) == 3)
                 {
-                    SetCenter(fp->GetXTrans(atof(papszToken[1])),
-                              fp->GetYTrans(atof(papszToken[2])) );
+                    SetCenter(fp->GetXTrans(CPLAtof(papszToken[1])),
+                              fp->GetYTrans(CPLAtof(papszToken[2])) );
                 }
             }
         }
@@ -1271,10 +1276,10 @@ int TABRectangle::ReadGeometryFromMIFFile(MIDDATAFile *fp)
         return -1;
     }
 
-    dXMin = fp->GetXTrans(atof(papszToken[1]));
-    dXMax = fp->GetXTrans(atof(papszToken[3]));
-    dYMin = fp->GetYTrans(atof(papszToken[2]));
-    dYMax = fp->GetYTrans(atof(papszToken[4]));
+    dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
+    dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
+    dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
+    dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
     
     /*-----------------------------------------------------------------
      * Call SetMBR() and GetMBR() now to make sure that min values are
@@ -1291,14 +1296,14 @@ int TABRectangle::ReadGeometryFromMIFFile(MIDDATAFile *fp)
     {
         m_bRoundCorners = TRUE;
         if (CSLCount(papszToken) == 6)
-          m_dRoundXRadius = m_dRoundYRadius = atof(papszToken[5])/2.0;
+          m_dRoundXRadius = m_dRoundYRadius = CPLAtof(papszToken[5])/2.0;
         else
         {
             CSLDestroy(papszToken);
             papszToken = CSLTokenizeString2(fp->GetLine(), 
                                             " \t", CSLT_HONOURSTRINGS);
             if (CSLCount(papszToken) !=1 )
-              m_dRoundXRadius = m_dRoundYRadius = atof(papszToken[1])/2.0;
+              m_dRoundXRadius = m_dRoundYRadius = CPLAtof(papszToken[1])/2.0;
         }
     }
     CSLDestroy(papszToken);
@@ -1471,10 +1476,10 @@ int TABEllipse::ReadGeometryFromMIFFile(MIDDATAFile *fp)
         return -1;
     }
 
-    dXMin = fp->GetXTrans(atof(papszToken[1]));
-    dXMax = fp->GetXTrans(atof(papszToken[3]));
-    dYMin = fp->GetYTrans(atof(papszToken[2]));
-    dYMax = fp->GetYTrans(atof(papszToken[4]));
+    dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
+    dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
+    dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
+    dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
 
     CSLDestroy(papszToken);
     papszToken = NULL;
@@ -1602,10 +1607,10 @@ int TABArc::ReadGeometryFromMIFFile(MIDDATAFile *fp)
 
     if (CSLCount(papszToken) == 5)
     {
-        dXMin = fp->GetXTrans(atof(papszToken[1]));
-        dXMax = fp->GetXTrans(atof(papszToken[3]));
-        dYMin = fp->GetYTrans(atof(papszToken[2]));
-        dYMax = fp->GetYTrans(atof(papszToken[4]));
+        dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
+        dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
+        dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
+        dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
 
         CSLDestroy(papszToken);
         papszToken = CSLTokenizeString2(fp->GetLine(), 
@@ -1616,17 +1621,17 @@ int TABArc::ReadGeometryFromMIFFile(MIDDATAFile *fp)
             return -1;
         }
 
-        m_dStartAngle = atof(papszToken[0]);
-        m_dEndAngle = atof(papszToken[1]);
+        m_dStartAngle = CPLAtof(papszToken[0]);
+        m_dEndAngle = CPLAtof(papszToken[1]);
     }
     else if (CSLCount(papszToken) == 7)
     {
-        dXMin = fp->GetXTrans(atof(papszToken[1]));
-        dXMax = fp->GetXTrans(atof(papszToken[3]));
-        dYMin = fp->GetYTrans(atof(papszToken[2]));
-        dYMax = fp->GetYTrans(atof(papszToken[4]));
-        m_dStartAngle = atof(papszToken[5]);
-        m_dEndAngle = atof(papszToken[6]);
+        dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
+        dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
+        dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
+        dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
+        m_dStartAngle = CPLAtof(papszToken[5]);
+        m_dEndAngle = CPLAtof(papszToken[6]);
     }
     else
     {
@@ -1809,10 +1814,10 @@ int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
     }
     else
     {
-        dXMin = fp->GetXTrans(atof(papszToken[0]));
-        dXMax = fp->GetXTrans(atof(papszToken[2]));
-        dYMin = fp->GetYTrans(atof(papszToken[1]));
-        dYMax = fp->GetYTrans(atof(papszToken[3]));
+        dXMin = fp->GetXTrans(CPLAtof(papszToken[0]));
+        dXMax = fp->GetXTrans(CPLAtof(papszToken[2]));
+        dYMin = fp->GetYTrans(CPLAtof(papszToken[1]));
+        dYMax = fp->GetYTrans(CPLAtof(papszToken[3]));
 
         m_dHeight = dYMax - dYMin;  //SetTextBoxHeight(dYMax - dYMin);
         m_dWidth  = dXMax - dXMin;  //SetTextBoxWidth(dXMax - dXMin);
@@ -1879,14 +1884,14 @@ int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
                         if (EQUALN(papszToken[4],"simple",6))
                         {
                             SetTextLineType(TABTLSimple);
-                            SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[5])),
-                                                fp->GetYTrans(atof(papszToken[6])));
+                            SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[5])),
+                                                fp->GetYTrans(CPLAtof(papszToken[6])));
                         }
                         else if (EQUALN(papszToken[4],"arrow", 5))
                         {
                             SetTextLineType(TABTLArrow);
-                            SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[5])),
-                                                fp->GetYTrans(atof(papszToken[6])));
+                            SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[5])),
+                                                fp->GetYTrans(CPLAtof(papszToken[6])));
                         }
                     }
                 }               
@@ -1911,7 +1916,7 @@ int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
             {
                 if (CSLCount(papszToken) == 2)
                 {    
-                    SetTextAngle(atof(papszToken[1]));
+                    SetTextAngle(CPLAtof(papszToken[1]));
                 }
                 
             }
@@ -1922,14 +1927,14 @@ int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
                     if (EQUALN(papszToken[2],"simple",6))
                     {
                         SetTextLineType(TABTLSimple);
-                        SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[3])),
-                                           fp->GetYTrans(atof(papszToken[4])));
+                        SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[3])),
+                                           fp->GetYTrans(CPLAtof(papszToken[4])));
                     }
                     else if (EQUALN(papszToken[2],"arrow", 5))
                     {
                         SetTextLineType(TABTLArrow);
-                        SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[3])),
-                                           fp->GetYTrans(atof(papszToken[4])));
+                        SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[3])),
+                                           fp->GetYTrans(CPLAtof(papszToken[4])));
                     }
                 }
                 
@@ -2132,8 +2137,8 @@ int TABMultiPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
             return -1;
         }
 
-        dfX = fp->GetXTrans(atof(papszToken[0]));
-        dfY = fp->GetXTrans(atof(papszToken[1]));
+        dfX = fp->GetXTrans(CPLAtof(papszToken[0]));
+        dfY = fp->GetXTrans(CPLAtof(papszToken[1]));
         poPoint = new OGRPoint(dfX, dfY);
         if ( poMultiPoint->addGeometryDirectly( poPoint ) != OGRERR_NONE)
         {
@@ -2405,7 +2410,3 @@ int TABDebugFeature::ReadGeometryFromMIFFile(MIDDATAFile *fp)
  *
  **********************************************************************/
 int TABDebugFeature::WriteGeometryToMIFFile(CPL_UNUSED MIDDATAFile *fp){ return -1; }
-
-
-
-
diff --git a/ogr/ogrsf_frmts/mitab/mitab_idfile.cpp b/ogr/ogrsf_frmts/mitab/mitab_idfile.cpp
index 7af3ef8..4c14be3 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_idfile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_idfile.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -92,6 +93,27 @@ TABIDFile::~TABIDFile()
 /**********************************************************************
  *                   TABIDFile::Open()
  *
+ * Compatibility layer with new interface.
+ * Return 0 on success, -1 in case of failure.
+ **********************************************************************/
+
+int TABIDFile::Open(const char *pszFname, const char* pszAccess)
+{
+    if( EQUALN(pszAccess, "r", 1) )
+        return Open(pszFname, TABRead);
+    else if( EQUALN(pszAccess, "w", 1) )
+        return Open(pszFname, TABWrite);
+    else
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+        return -1;
+    }
+}
+
+/**********************************************************************
+ *                   TABIDFile::Open()
+ *
  * Open a .ID file, and initialize the structures to be ready to read
  * objects from it.
  *
@@ -100,7 +122,7 @@ TABIDFile::~TABIDFile()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABIDFile::Open(const char *pszFname, const char *pszAccess)
+int TABIDFile::Open(const char *pszFname, TABAccess eAccess)
 {
     int         nLen;
 
@@ -116,20 +138,26 @@ int TABIDFile::Open(const char *pszFname, const char *pszAccess)
      * Note that in Write mode we need TABReadWrite since we do random
      * updates in the index as data blocks are split
      *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
+    const char* pszAccess = NULL;
+    if (eAccess == TABRead)
     {
         m_eAccessMode = TABRead;
         pszAccess = "rb";
     }
-    else if (EQUALN(pszAccess, "w", 1))
+    else if (eAccess == TABWrite)
     {
         m_eAccessMode = TABReadWrite;
         pszAccess = "wb+";
     }
+    else if (eAccess == TABReadWrite)
+    {
+        m_eAccessMode = TABReadWrite;
+        pszAccess = "rb+";
+    }
     else
     {
         CPLError(CE_Failure, CPLE_FileIO,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+                 "Open() failed: access mode \"%d\" not supported", eAccess);
         return -1;
     }
 
@@ -154,7 +182,7 @@ int TABIDFile::Open(const char *pszFname, const char *pszAccess)
     /*-----------------------------------------------------------------
      * Open file
      *----------------------------------------------------------------*/
-    m_fp = VSIFOpen(m_pszFname, pszAccess);
+    m_fp = VSIFOpenL(m_pszFname, pszAccess);
 
     if (m_fp == NULL)
     {
@@ -165,14 +193,14 @@ int TABIDFile::Open(const char *pszFname, const char *pszAccess)
         return -1;
     }
 
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite)
     {
         /*-------------------------------------------------------------
          * READ access:
          * Establish the number of object IDs from the size of the file
          *------------------------------------------------------------*/
-        VSIStatBuf  sStatBuf;
-        if ( VSIStat(m_pszFname, &sStatBuf) == -1 )
+        VSIStatBufL  sStatBuf;
+        if ( VSIStatL(m_pszFname, &sStatBuf) == -1 )
         {
             CPLError(CE_Failure, CPLE_FileIO, 
                      "stat() failed for %s\n", m_pszFname);
@@ -180,7 +208,7 @@ int TABIDFile::Open(const char *pszFname, const char *pszAccess)
             return -1;
         }
 
-        m_nMaxId = sStatBuf.st_size/4;
+        m_nMaxId = (int)(sStatBuf.st_size/4);
         m_nBlockSize = MIN(1024, m_nMaxId*4);
 
         /*-------------------------------------------------------------
@@ -232,17 +260,15 @@ int TABIDFile::Close()
     /*----------------------------------------------------------------
      * Write access: commit latest changes to the file.
      *---------------------------------------------------------------*/
-    if (m_eAccessMode == TABReadWrite && m_poIDBlock)
-    {
-        m_poIDBlock->CommitToFile();
-    }
+    if (m_eAccessMode != TABRead)
+        SyncToDisk();
     
     // Delete all structures 
     delete m_poIDBlock;
     m_poIDBlock = NULL;
 
     // Close file
-    VSIFClose(m_fp);
+    VSIFCloseL(m_fp);
     m_fp = NULL;
 
     CPLFree(m_pszFname);
@@ -251,6 +277,24 @@ int TABIDFile::Close()
     return 0;
 }
 
+/************************************************************************/
+/*                            SyncToDisk()                             */
+/************************************************************************/
+
+int TABIDFile::SyncToDisk()
+{
+    if( m_eAccessMode == TABRead )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SyncToDisk() can be used only with Write access.");
+        return -1;
+    }
+
+    if( m_poIDBlock == NULL)
+        return 0;
+
+    return m_poIDBlock->CommitToFile();
+}
 
 /**********************************************************************
  *                   TABIDFile::GetObjPtr()
@@ -300,7 +344,7 @@ int TABIDFile::SetObjPtr(GInt32 nObjId, GInt32 nObjPtr)
     if (m_poIDBlock == NULL)
         return -1;
 
-    if (m_eAccessMode != TABReadWrite)
+    if (m_eAccessMode == TABRead)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "SetObjPtr() can be used only with Write access.");
diff --git a/ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp b/ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp
index da540d3..3ceb688 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_imapinfofile.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2008, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -172,6 +173,28 @@ IMapInfoFile::~IMapInfoFile()
 }
 
 /**********************************************************************
+ *                   IMapInfoFile::Open()
+ *
+ * Compatibility layer with new interface.
+ * Return 0 on success, -1 in case of failure.
+ **********************************************************************/
+
+int IMapInfoFile::Open(const char *pszFname, const char* pszAccess,
+                       GBool bTestOpenNoError)
+{
+    if( EQUALN(pszAccess, "r", 1) )
+        return Open(pszFname, TABRead, bTestOpenNoError);
+    else if( EQUALN(pszAccess, "w", 1) )
+        return Open(pszFname, TABWrite, bTestOpenNoError);
+    else
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+        return -1;
+    }
+}
+
+/**********************************************************************
  *                   IMapInfoFile::SmartOpen()
  *
  * Use this static method to automatically open any flavour of MapInfo
@@ -184,6 +207,7 @@ IMapInfoFile::~IMapInfoFile()
  * Returns the new object ptr. , or NULL if the open failed.
  **********************************************************************/
 IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname,
+                                      GBool bUpdate,
                                       GBool bTestOpenNoError /*=FALSE*/)
 {
     IMapInfoFile *poFile = NULL;
@@ -206,14 +230,14 @@ IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname,
          * .TAB file ... is it a TABFileView or a TABFile?
          * We have to read the .tab header to find out.
          *------------------------------------------------------------*/
-        FILE *fp;
+        VSILFILE *fp;
         const char *pszLine;
         char *pszAdjFname = CPLStrdup(pszFname);
         GBool bFoundFields = FALSE, bFoundView=FALSE, bFoundSeamless=FALSE;
 
         TABAdjustFilenameExtension(pszAdjFname);
-        fp = VSIFOpen(pszAdjFname, "r");
-        while(fp && (pszLine = CPLReadLine(fp)) != NULL)
+        fp = VSIFOpenL(pszAdjFname, "r");
+        while(fp && (pszLine = CPLReadLineL(fp)) != NULL)
         {
             while (isspace((unsigned char)*pszLine))  pszLine++;
             if (EQUALN(pszLine, "Fields", 6))
@@ -232,7 +256,7 @@ IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname,
             poFile = new TABFile;
 
         if (fp)
-            VSIFClose(fp);
+            VSIFCloseL(fp);
 
         CPLFree(pszAdjFname);
     }
@@ -240,7 +264,7 @@ IMapInfoFile *IMapInfoFile::SmartOpen(const char *pszFname,
     /*-----------------------------------------------------------------
      * Perform the open() call
      *----------------------------------------------------------------*/
-    if (poFile && poFile->Open(pszFname, "r", bTestOpenNoError) != 0)
+    if (poFile && poFile->Open(pszFname, bUpdate ? TABReadWrite : TABRead, bTestOpenNoError) != 0)
     {
         delete poFile;
         poFile = NULL;
@@ -267,7 +291,7 @@ OGRFeature *IMapInfoFile::GetNextFeature()
 {
     OGRFeature *poFeatureRef;
     OGRGeometry *poGeom;
-    int nFeatureId;
+    GIntBig nFeatureId;
 
     while( (nFeatureId = GetNextFeatureId(m_nCurFeatureId)) != -1 )
     {
@@ -283,6 +307,8 @@ OGRFeature *IMapInfoFile::GetNextFeature()
             // Avoid cloning feature... return the copy owned by the class
             CPLAssert(poFeatureRef == m_poCurFeature);
             m_poCurFeature = NULL;  
+            if( poFeatureRef->GetGeometryRef() != NULL )
+                poFeatureRef->GetGeometryRef()->assignSpatialReference(GetSpatialRef());
             return poFeatureRef;
         }
     }
@@ -290,17 +316,16 @@ OGRFeature *IMapInfoFile::GetNextFeature()
 }
 
 /**********************************************************************
- *                   IMapInfoFile::CreateFeature()
+ *                   IMapInfoFile::CreateTABFeature()
  *
- * Standard OGR CreateFeature implementation.  This method is used
- * to create a new feature in current dataset 
+ * Instanciate a TABFeature* from a OGRFeature* (or NULL on error)
  **********************************************************************/
-OGRErr     IMapInfoFile::CreateFeature(OGRFeature *poFeature)
+
+TABFeature* IMapInfoFile::CreateTABFeature(OGRFeature *poFeature)
 {
     TABFeature *poTABFeature;
     OGRGeometry   *poGeom;
     OGRwkbGeometryType eGType;
-    OGRErr  eErr;
     TABPoint *poTABPointFeature = NULL;
     TABRegion *poTABRegionFeature = NULL;
     TABPolyline *poTABPolylineFeature = NULL;
@@ -373,11 +398,12 @@ OGRErr     IMapInfoFile::CreateFeature(OGRFeature *poFeature)
 
           for (i=0; eStatus==OGRERR_NONE && i<poColl->getNumGeometries(); i++)
           {
+              poTmpFeature->SetFID(OGRNullFID);
               poTmpFeature->SetGeometry(poColl->getGeometryRef(i));
-              eStatus = CreateFeature(poTmpFeature);
+              eStatus = ICreateFeature(poTmpFeature);
           }
           delete poTmpFeature;
-          return eStatus;
+          return NULL;
         }
         break;
       /*-------------------------------------------------------------
@@ -397,8 +423,29 @@ OGRErr     IMapInfoFile::CreateFeature(OGRFeature *poFeature)
         poTABFeature->SetField(i,poFeature->GetRawFieldRef( i ));
     }
     
+    poTABFeature->SetFID(poFeature->GetFID());
+    
+    return poTABFeature;
+}
+
+/**********************************************************************
+ *                   IMapInfoFile::ICreateFeature()
+ *
+ * Standard OGR CreateFeature implementation.  This method is used
+ * to create a new feature in current dataset 
+ **********************************************************************/
+OGRErr     IMapInfoFile::ICreateFeature(OGRFeature *poFeature)
+{
+    TABFeature *poTABFeature;
+    OGRErr  eErr;
+
+    poTABFeature = CreateTABFeature(poFeature);
+    if( poTABFeature == NULL ) /* MultiGeometry */
+        return OGRERR_NONE;
 
     eErr = CreateFeature(poTABFeature);
+    if( eErr == OGRERR_NONE )
+        poFeature->SetFID(poTABFeature->GetFID());
 
     delete poTABFeature;
     
@@ -412,9 +459,11 @@ OGRErr     IMapInfoFile::CreateFeature(OGRFeature *poFeature)
  * to get the wanted (nFeatureId) feature, a NULL value will be 
  * returned on error.
  **********************************************************************/
-OGRFeature *IMapInfoFile::GetFeature(long nFeatureId)
+OGRFeature *IMapInfoFile::GetFeature(GIntBig nFeatureId)
 {
     OGRFeature *poFeatureRef;
+    
+    /*fprintf(stderr, "GetFeature(%ld)\n", nFeatureId);*/
 
     poFeatureRef = GetFeatureRef(nFeatureId);
     if (poFeatureRef)
@@ -430,13 +479,14 @@ OGRFeature *IMapInfoFile::GetFeature(long nFeatureId)
 }
 
 /************************************************************************/
-/*                            CreateField()                             */
+/*                            GetTABType()                              */
 /*                                                                      */
 /*      Create a native field based on a generic OGR definition.        */
 /************************************************************************/
 
-OGRErr IMapInfoFile::CreateField( OGRFieldDefn *poField, int bApproxOK )
-
+int IMapInfoFile::GetTABType( OGRFieldDefn *poField,
+                              TABFieldType* peTABType,
+                              int *pnWidth)
 {
     TABFieldType        eTABType;
     int                 nWidth = poField->GetWidth();
@@ -493,9 +543,30 @@ OGRErr IMapInfoFile::CreateField( OGRFieldDefn *poField, int bApproxOK )
                   "Note that Mapinfo files don't support list field types.\n",
                   poField->GetType() );
 
-        return OGRERR_FAILURE;
+        return -1;
     }
 
+    *peTABType = eTABType;
+    *pnWidth = nWidth;
+
+    return 0;
+}
+
+/************************************************************************/
+/*                            CreateField()                             */
+/*                                                                      */
+/*      Create a native field based on a generic OGR definition.        */
+/************************************************************************/
+
+OGRErr IMapInfoFile::CreateField( OGRFieldDefn *poField, int bApproxOK )
+
+{
+    TABFieldType        eTABType;
+    int                 nWidth;
+
+    if( GetTABType( poField, &eTABType, &nWidth ) < 0 )
+        return OGRERR_FAILURE;
+
     if( AddFieldNative( poField->GetNameRef(), eTABType,
                         nWidth, poField->GetPrecision(), FALSE, FALSE, bApproxOK ) > -1 )
         return OGRERR_NONE;
diff --git a/ogr/ogrsf_frmts/mitab/mitab_indfile.cpp b/ogr/ogrsf_frmts/mitab/mitab_indfile.cpp
index 883de44..8ec0a96 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_indfile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_indfile.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2001, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -101,6 +102,7 @@ TABINDFile::TABINDFile()
     m_numIndexes = 0;
     m_papoIndexRootNodes = NULL;
     m_papbyKeyBuffers = NULL;
+    m_oBlockManager.SetName("IND");
 }
 
 /**********************************************************************
@@ -185,7 +187,7 @@ int TABINDFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Open file
      *----------------------------------------------------------------*/
-    m_fp = VSIFOpen(m_pszFname, pszAccess);
+    m_fp = VSIFOpenL(m_pszFname, pszAccess);
 
     if (m_fp == NULL)
     {
@@ -282,7 +284,7 @@ int TABINDFile::Close()
     /*-----------------------------------------------------------------
      * Close file
      *----------------------------------------------------------------*/
-    VSIFClose(m_fp);
+    VSIFCloseL(m_fp);
     m_fp = NULL;
 
     CPLFree(m_pszFname);
@@ -309,10 +311,10 @@ int TABINDFile::ReadHeader()
     /*-----------------------------------------------------------------
      * In ReadWrite mode, we need to init BlockManager with file size
      *----------------------------------------------------------------*/
-    VSIStatBuf  sStatBuf;
-    if (m_eAccessMode == TABReadWrite && VSIStat(m_pszFname, &sStatBuf) != -1)
+    VSIStatBufL  sStatBuf;
+    if (m_eAccessMode == TABReadWrite && VSIStatL(m_pszFname, &sStatBuf) != -1)
     {
-        m_oBlockManager.SetLastPtr(((sStatBuf.st_size-1)/512)*512);
+        m_oBlockManager.SetLastPtr((int)(((sStatBuf.st_size-1)/512)*512));
     }
 
     /*-----------------------------------------------------------------
@@ -948,7 +950,7 @@ TABINDNode::~TABINDNode()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABINDNode::InitNode(FILE *fp, int nBlockPtr, 
+int TABINDNode::InitNode(VSILFILE *fp, int nBlockPtr, 
                          int nKeyLength, int nSubTreeDepth, 
                          GBool bUnique,
                          TABBinBlockManager *poBlockMgr /*=NULL*/,
@@ -2120,11 +2122,17 @@ void TABINDNode::Dump(FILE *fpOut /*=NULL*/)
               }
               else if (m_nKeyLength != 4)
               {
+                GInt32 nInt32;
+                GInt16 nInt16;
+                GUInt32 nUInt32;
+                memcpy(&nInt32, aKeyValBuf, 4);
+                memcpy(&nInt16, aKeyValBuf + 2, 2);
+                memcpy(&nUInt32, aKeyValBuf, 4);
                 nRecordPtr = ReadIndexEntry(i, aKeyValBuf);
                 fprintf(fpOut, "   nRecordPtr = %d\n", nRecordPtr);
-                fprintf(fpOut, "   Int Value = %d\n", *(GInt32*)aKeyValBuf);
-                fprintf(fpOut, "   Int16 Val= %d\n",*(GInt16*)(aKeyValBuf+2));
-                fprintf(fpOut, "   Hex Val= 0x%8.8x\n",*(GUInt32*)aKeyValBuf);
+                fprintf(fpOut, "   Int Value = %d\n", nInt32);
+                fprintf(fpOut, "   Int16 Val= %d\n",nInt16);
+                fprintf(fpOut, "   Hex Val= 0x%8.8x\n",nUInt32);
               }
               else
               {
diff --git a/ogr/ogrsf_frmts/mitab/mitab_mapcoordblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_mapcoordblock.cpp
index 5b17278..b4a36e8 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_mapcoordblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_mapcoordblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2001, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -147,11 +148,13 @@ TABMAPCoordBlock::~TABMAPCoordBlock()
 int     TABMAPCoordBlock::InitBlockFromData(GByte *pabyBuf,
                                             int nBlockSize, int nSizeUsed, 
                                             GBool bMakeCopy /* = TRUE */,
-                                            FILE *fpSrc /* = NULL */, 
+                                            VSILFILE *fpSrc /* = NULL */, 
                                             int nOffset /* = 0 */)
 {
     int nStatus;
-
+#ifdef DEBUG_VERBOSE
+    CPLDebug("MITAB", "Instanciating COORD block to/from offset %d", nOffset);
+#endif
     /*-----------------------------------------------------------------
      * First of all, we must call the base class' InitBlockFromData()
      *----------------------------------------------------------------*/
@@ -219,6 +222,12 @@ int     TABMAPCoordBlock::CommitToFile()
     }
 
     /*-----------------------------------------------------------------
+     * Nothing to do here if block has not been modified
+     *----------------------------------------------------------------*/
+    if (!m_bModified)
+        return 0;
+
+    /*-----------------------------------------------------------------
      * Make sure 8 bytes block header is up to date.
      *----------------------------------------------------------------*/
     GotoByteInBlock(0x000);
@@ -234,7 +243,12 @@ int     TABMAPCoordBlock::CommitToFile()
      * OK, call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting COORD block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+    }
 
     return nStatus;
 }
@@ -254,11 +268,13 @@ int     TABMAPCoordBlock::CommitToFile()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABMAPCoordBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABMAPCoordBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                         int nFileOffset /* = 0*/)
 {
     CPLErrorReset();
-
+#ifdef DEBUG_VERBOSE
+    CPLDebug("MITAB", "Instanciating new COORD block at offset %d", nFileOffset);
+#endif
     /*-----------------------------------------------------------------
      * Start with the default initialisation
      *----------------------------------------------------------------*/
@@ -283,7 +299,7 @@ int     TABMAPCoordBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
     m_nMaxX = -1000000000;
     m_nMaxY = -1000000000;
 
-    if (m_eAccess != TABRead)
+    if (m_eAccess != TABRead && nFileOffset != 0)
     {
         GotoByteInBlock(0x000);
 
@@ -307,6 +323,7 @@ int     TABMAPCoordBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
 void     TABMAPCoordBlock::SetNextCoordBlock(GInt32 nNextCoordBlockAddress)
 {
     m_nNextCoordBlock = nNextCoordBlockAddress;
+    m_bModified = TRUE;
 }
 
 
@@ -770,7 +787,7 @@ int  TABMAPCoordBlock::WriteBytes(int nBytesToWrite, GByte *pabySrcBuf)
             {
                 // Need to alloc a new block.
 
-                int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock();
+                int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock("COORD");
                 SetNextCoordBlock(nNewBlockOffset);
 
                 if (CommitToFile() != 0 ||
diff --git a/ogr/ogrsf_frmts/mitab/mitab_mapfile.cpp b/ogr/ogrsf_frmts/mitab/mitab_mapfile.cpp
index fbaf289..958aa0a 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_mapfile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_mapfile.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2002, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -217,10 +218,16 @@ TABMAPFile::TABMAPFile()
 
     m_poCurObjBlock = NULL;
     m_nCurObjPtr = -1;
-    m_nCurObjType = -1;
+    m_nCurObjType = TAB_GEOM_UNSET;
     m_nCurObjId = -1;
     m_poCurCoordBlock = NULL;
     m_poToolDefTable = NULL;
+    
+    m_bUpdated = FALSE;
+    m_bLastOpWasRead = FALSE;
+    m_bLastOpWasWrite = FALSE;
+    
+    m_oBlockManager.SetName("MAP");
 }
 
 /**********************************************************************
@@ -236,6 +243,27 @@ TABMAPFile::~TABMAPFile()
 /**********************************************************************
  *                   TABMAPFile::Open()
  *
+ * Compatibility layer with new interface.
+ * Return 0 on success, -1 in case of failure.
+ **********************************************************************/
+
+int TABMAPFile::Open(const char *pszFname, const char* pszAccess, GBool bNoErrorMsg)
+{
+    if( EQUALN(pszAccess, "r", 1) )
+        return Open(pszFname, TABRead, bNoErrorMsg);
+    else if( EQUALN(pszAccess, "w", 1) )
+        return Open(pszFname, TABWrite, bNoErrorMsg);
+    else
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+        return -1;
+    }
+}
+
+/**********************************************************************
+ *                   TABMAPFile::Open()
+ *
  * Open a .MAP file, and initialize the structures to be ready to read
  * objects from it.
  *
@@ -246,12 +274,12 @@ TABMAPFile::~TABMAPFile()
  * be used.  They will behave as if the .ID file contained only null
  * references, so all object will look like they have NONE geometries.
  *
- * Returns 0 on success, -1 on error.
+ * Returns 0 on success, 1 when the .map file does not exist, -1 on error.
  **********************************************************************/
-int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
+int TABMAPFile::Open(const char *pszFname, TABAccess eAccess,
                      GBool bNoErrorMsg /* = FALSE */)
 {
-    FILE        *fp=NULL;
+    VSILFILE    *fp=NULL;
     TABRawBinBlock *poBlock=NULL;
 
     if (m_fp)
@@ -267,51 +295,36 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
     m_poIdIndex = NULL;
     m_poSpIndex = NULL;
     m_poToolDefTable = NULL;
-
-    /*-----------------------------------------------------------------
-     * Validate access mode and make sure we use binary access.
-     *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
-    {
-        m_eAccessMode = TABRead;
-        pszAccess = "rb";
-    }
-    else if (EQUALN(pszAccess, "w", 1))
-    {
-        m_eAccessMode = TABWrite;
-        pszAccess = "wb+";
-    }
-    else
-    {
-        CPLError(CE_Failure, CPLE_FileIO,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
-        return -1;
-    }
+    m_eAccessMode = eAccess;
+    m_bUpdated = FALSE;
+    m_bLastOpWasRead = FALSE;
+    m_bLastOpWasWrite = FALSE;
 
     /*-----------------------------------------------------------------
      * Open file
      *----------------------------------------------------------------*/
-    fp = VSIFOpen(pszFname, pszAccess);
+    const char* pszAccess = ( eAccess == TABRead ) ? "rb" :
+                            ( eAccess == TABWrite ) ? "wb+" :
+                                                      "rb+";
+    fp = VSIFOpenL(pszFname, pszAccess);
 
-    // TODO: In Read/Write mode we should also preload the chain of deleted
-    // blocks in the blockManager. Not needed for read-only or write-only.
     m_oBlockManager.Reset();
 
-    if (fp != NULL && m_eAccessMode == TABRead)
+    if (fp != NULL && (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite))
     {
         /*-----------------------------------------------------------------
          * Read access: try to read header block
          * First try with a 512 bytes block to check the .map version.
          * If it's version 500 or more then read again a 1024 bytes block
          *----------------------------------------------------------------*/
-        poBlock = TABCreateMAPBlockFromFile(fp, 0, 512);
+        poBlock = TABCreateMAPBlockFromFile(fp, 0, 512, TRUE, m_eAccessMode);
 
         if (poBlock && poBlock->GetBlockClass() == TABMAP_HEADER_BLOCK &&
             ((TABMAPHeaderBlock*)poBlock)->m_nMAPVersionNumber >= 500)
         {
             // Version 500 or higher.  Read 1024 bytes block instead of 512
             delete poBlock;
-            poBlock = TABCreateMAPBlockFromFile(fp, 0, 1024);
+            poBlock = TABCreateMAPBlockFromFile(fp, 0, 1024, TRUE, m_eAccessMode);
         }
 
         if (poBlock==NULL || poBlock->GetBlockClass() != TABMAP_HEADER_BLOCK)
@@ -319,7 +332,7 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
             if (poBlock)
                 delete poBlock;
             poBlock = NULL;
-            VSIFClose(fp);
+            VSIFCloseL(fp);
             CPLError(CE_Failure, CPLE_FileIO,
                 "Open() failed: %s does not appear to be a valid .MAP file",
                      pszFname);
@@ -334,11 +347,13 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
          * header.  The last 512 bytes are usually all zeros.
          *----------------------------------------------------------------*/
         poBlock = new TABMAPHeaderBlock(m_eAccessMode);
-        poBlock->InitNewBlock(fp, 1024, m_oBlockManager.AllocNewBlock() );
+        poBlock->InitNewBlock(fp, 1024, m_oBlockManager.AllocNewBlock("HEADER") );
 
         // Alloc a second 512 bytes of space since oBlockManager deals 
         // with 512 bytes blocks.
-        m_oBlockManager.AllocNewBlock(); 
+        m_oBlockManager.AllocNewBlock("HEADER"); 
+
+        m_bUpdated = TRUE;
     }
     else if (bNoErrorMsg)
     {
@@ -373,7 +388,8 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
     m_pszFname = CPLStrdup(pszFname);
 
     /*-----------------------------------------------------------------
-     * Create a TABMAPObjectBlock, in READ mode only.
+     * Create a TABMAPObjectBlock, in READ mode only or in UPDATE mode
+     * if there's an object
      *
      * In WRITE mode, the object block will be created only when needed.
      * We do not create the object block in the open() call because
@@ -381,7 +397,8 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
      * object and spatial index blocks.
      *----------------------------------------------------------------*/
 
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead ||
+        (m_eAccessMode == TABReadWrite && m_poHeader->m_nFirstIndexBlock != 0 ))
     {
         m_poCurObjBlock = new TABMAPObjectBlock(m_eAccessMode);
         m_poCurObjBlock->InitNewBlock(m_fp, 512);
@@ -395,7 +412,7 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
      * Open associated .ID (object id index) file
      *----------------------------------------------------------------*/
     m_poIdIndex = new TABIDFile;
-    if (m_poIdIndex->Open(pszFname, pszAccess) != 0)
+    if (m_poIdIndex->Open(pszFname, m_eAccessMode) != 0)
     {
         // Failed... an error has already been reported
         Close();
@@ -407,7 +424,7 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
      * This is currently unused but could eventually be used to handle
      * spatial filters more efficiently.
      *----------------------------------------------------------------*/
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite)
     {
         ResetCoordFilter();
     }
@@ -422,11 +439,86 @@ int TABMAPFile::Open(const char *pszFname, const char *pszAccess,
      *----------------------------------------------------------------*/
     m_poSpIndex = NULL;
 
+    if (m_eAccessMode == TABReadWrite)
+    {
+        /* We don't allow quick mode in read/write mode */
+        m_bQuickSpatialIndexMode = FALSE;
+
+        if( m_poHeader->m_nFirstIndexBlock != 0 )
+        {
+            TABRawBinBlock *poBlock;
+            poBlock = GetIndexObjectBlock( m_poHeader->m_nFirstIndexBlock );
+            if( poBlock == NULL || (poBlock->GetBlockType() != TABMAP_INDEX_BLOCK &&
+                                    poBlock->GetBlockType() != TABMAP_OBJECT_BLOCK) )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                         "Cannot find first index block at offset %d",
+                         m_poHeader->m_nFirstIndexBlock );
+                delete poBlock;
+            }
+            else if( poBlock->GetBlockType() == TABMAP_INDEX_BLOCK )
+            {
+                m_poSpIndex = (TABMAPIndexBlock *)poBlock;
+                m_poSpIndex->SetMBR(m_poHeader->m_nXMin, m_poHeader->m_nYMin,
+                                    m_poHeader->m_nXMax, m_poHeader->m_nYMax);
+            }
+            else /* if( poBlock->GetBlockType() == TABMAP_OBJECT_BLOCK ) */
+            {
+                /* This can happen if the file created by MapInfo contains just */
+                /* a few objects */
+                delete poBlock;
+            }
+        }
+    }
+
     /*-----------------------------------------------------------------
      * Initialization of the Drawing Tools table will be done automatically
      * as Read/Write calls are done later.
      *----------------------------------------------------------------*/
     m_poToolDefTable = NULL;
+    
+    if( m_eAccessMode == TABReadWrite )
+    {
+        InitDrawingTools();
+    }
+
+    if( m_eAccessMode == TABReadWrite )
+    {
+        VSIStatBufL sStatBuf;
+        VSIStatL(m_pszFname, &sStatBuf);
+        m_oBlockManager.SetLastPtr((int)(((sStatBuf.st_size-1)/512)*512));
+
+        /* Read chain of garbage blocks */
+        if( m_poHeader->m_nFirstGarbageBlock != 0 )
+        {
+            int nCurGarbBlock = m_poHeader->m_nFirstGarbageBlock;
+            m_oBlockManager.PushGarbageBlockAsLast(nCurGarbBlock);
+            while(TRUE)
+            {
+                GUInt16 nBlockType;
+                int     nNextGarbBlockPtr;
+                if( VSIFSeekL(fp, nCurGarbBlock, SEEK_SET) != 0 ||
+                    VSIFReadL(&nBlockType, sizeof(nBlockType), 1, fp) != 1 ||
+                    VSIFReadL(&nNextGarbBlockPtr, sizeof(nNextGarbBlockPtr), 1, fp) != 1 )
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                             "Cannot read garbage block at offset %d",
+                             nCurGarbBlock);
+                    break;
+                }
+                if( nBlockType != TABMAP_GARB_BLOCK )
+                {
+                    CPLError(CE_Failure, CPLE_AppDefined,
+                             "Got block type (%d) instead of %d at offset %d",
+                             nBlockType, TABMAP_GARB_BLOCK, nCurGarbBlock);
+                }
+                if( nNextGarbBlockPtr == 0 )
+                    break;
+                nCurGarbBlock = nNextGarbBlockPtr;
+                m_oBlockManager.PushGarbageBlockAsLast(nCurGarbBlock);
+            }
+        }
+    }
 
     /*-----------------------------------------------------------------
      * Make sure all previous calls succeded.
@@ -458,56 +550,9 @@ int TABMAPFile::Close()
     /*----------------------------------------------------------------
      * Write access: commit latest changes to the file.
      *---------------------------------------------------------------*/
-    if (m_eAccessMode == TABWrite)
-    {
-        // Start by committing current object and coord blocks
-        // Nothing happens if none has been created yet.
-        CommitObjAndCoordBlocks(FALSE);
-
-        // Write the drawing tools definitions now.
-        CommitDrawingTools();
-
-        // Commit spatial index blocks
-        CommitSpatialIndex();
-
-        // Update header fields and commit
-        if (m_poHeader)
-        {
-            // OK, with V450 files, objects are not limited to 32k nodes
-            // any more, and this means that m_nMaxCoordBufSize can become
-            // huge, and actually more huge than can be held in memory.
-            // MapInfo counts m_nMaxCoordBufSize=0 for V450 objects, but 
-            // until this is cleanly implented, we will just prevent 
-            // m_nMaxCoordBufSizefrom going beyond 512k in V450 files.
-            if (m_nMinTABVersion >= 450)
-            {
-                m_poHeader->m_nMaxCoordBufSize = 
-                                 MIN(m_poHeader->m_nMaxCoordBufSize, 512*1024);
-            }
-
-            // Write Ref to beginning of the chain of garbage blocks
-            m_poHeader->m_nFirstGarbageBlock = 
-                m_oBlockManager.GetFirstGarbageBlock();
-
-            m_poHeader->CommitToFile();
-        }
-    }
-    
-    // Check for overflow of internal coordinates and produce a warning
-    // if that happened...
-    if (m_poHeader && m_poHeader->m_bIntBoundsOverflow)
+    if (m_eAccessMode != TABRead)
     {
-        double dBoundsMinX, dBoundsMinY, dBoundsMaxX, dBoundsMaxY;
-        Int2Coordsys(-1000000000, -1000000000, dBoundsMinX, dBoundsMinY);
-        Int2Coordsys(1000000000, 1000000000, dBoundsMaxX, dBoundsMaxY);
-
-        CPLError(CE_Warning, TAB_WarningBoundsOverflow,
-                 "Some objects were written outside of the file's "
-                 "predefined bounds.\n"
-                 "These objects may have invalid coordinates when the file "
-                 "is reopened.\n"
-                 "Predefined bounds: (%.15g,%.15g)-(%.15g,%.15g)\n",
-                 dBoundsMinX, dBoundsMinY, dBoundsMaxX, dBoundsMaxY );
+        SyncToDisk();
     }
 
     // Delete all structures 
@@ -527,7 +572,7 @@ int TABMAPFile::Close()
         delete m_poCurObjBlock;
         m_poCurObjBlock = NULL;
         m_nCurObjPtr = -1;
-        m_nCurObjType = -1;
+        m_nCurObjType = TAB_GEOM_UNSET;
         m_nCurObjId = -1;
     }
 
@@ -552,7 +597,7 @@ int TABMAPFile::Close()
 
     // Close file
     if (m_fp)
-        VSIFClose(m_fp);
+        VSIFCloseL(m_fp);
     m_fp = NULL;
 
     CPLFree(m_pszFname);
@@ -561,6 +606,99 @@ int TABMAPFile::Close()
     return 0;
 }
 
+/************************************************************************/
+/*                            SyncToDisk()                             */
+/************************************************************************/
+
+int TABMAPFile::SyncToDisk()
+{
+    if( m_eAccessMode == TABRead )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SyncToDisk() can be used only with Write access.");
+        return -1;
+    }
+
+    if( !m_bUpdated) 
+        return 0;
+
+    // Start by committing current object and coord blocks
+    // Nothing happens if none has been created yet.
+    if( CommitObjAndCoordBlocks(FALSE) != 0 )
+        return -1;
+
+    // Write the drawing tools definitions now.
+    if( CommitDrawingTools() != 0 )
+        return -1;
+
+    // Commit spatial index blocks
+    if( CommitSpatialIndex() != 0 )
+        return -1;
+
+    // Update header fields and commit
+    if (m_poHeader)
+    {
+        // OK, with V450 files, objects are not limited to 32k nodes
+        // any more, and this means that m_nMaxCoordBufSize can become
+        // huge, and actually more huge than can be held in memory.
+        // MapInfo counts m_nMaxCoordBufSize=0 for V450 objects, but 
+        // until this is cleanly implented, we will just prevent 
+        // m_nMaxCoordBufSizefrom going beyond 512k in V450 files.
+        if (m_nMinTABVersion >= 450)
+        {
+            m_poHeader->m_nMaxCoordBufSize = 
+                                MIN(m_poHeader->m_nMaxCoordBufSize, 512*1024);
+        }
+
+        // Write Ref to beginning of the chain of garbage blocks
+        m_poHeader->m_nFirstGarbageBlock = 
+            m_oBlockManager.GetFirstGarbageBlock();
+
+        if( m_poHeader->CommitToFile() != 0 )
+            return -1;
+    }
+
+    // Check for overflow of internal coordinates and produce a warning
+    // if that happened...
+    if (m_poHeader && m_poHeader->m_bIntBoundsOverflow)
+    {
+        double dBoundsMinX, dBoundsMinY, dBoundsMaxX, dBoundsMaxY;
+        Int2Coordsys(-1000000000, -1000000000, dBoundsMinX, dBoundsMinY);
+        Int2Coordsys(1000000000, 1000000000, dBoundsMaxX, dBoundsMaxY);
+
+        CPLError(CE_Warning, TAB_WarningBoundsOverflow,
+                 "Some objects were written outside of the file's "
+                 "predefined bounds.\n"
+                 "These objects may have invalid coordinates when the file "
+                 "is reopened.\n"
+                 "Predefined bounds: (%.15g,%.15g)-(%.15g,%.15g)\n",
+                 dBoundsMinX, dBoundsMinY, dBoundsMaxX, dBoundsMaxY );
+    }
+
+    if( m_poIdIndex != NULL && m_poIdIndex->SyncToDisk() != 0 )
+        return -1;
+
+    m_bUpdated = FALSE;
+
+    return 0;
+}
+
+/**********************************************************************
+ *                   TABMAPFile::ReOpenReadWrite()
+ **********************************************************************/
+int TABMAPFile::ReOpenReadWrite()
+{
+    char* pszFname = m_pszFname;
+    m_pszFname = NULL;
+    Close();
+    if( Open(pszFname, TABReadWrite) < 0 )
+    {
+        CPLFree(pszFname);
+        return -1;
+    }
+    CPLFree(pszFname);
+    return 0;
+}
 
 /**********************************************************************
  *                   TABMAPFile::SetQuickSpatialIndexMode()
@@ -623,6 +761,7 @@ TABRawBinBlock *TABMAPFile::PushBlock( int nFileOffset )
 
         if( m_poSpIndexLeaf == NULL )
         {
+            delete m_poSpIndex;
             m_poSpIndexLeaf = m_poSpIndex = poIndex;
         }
         else
@@ -648,7 +787,7 @@ TABRawBinBlock *TABMAPFile::PushBlock( int nFileOffset )
         m_poCurObjBlock = (TABMAPObjectBlock *) poBlock;
 
         m_nCurObjPtr = nFileOffset;
-        m_nCurObjType = 0;
+        m_nCurObjType = TAB_GEOM_NONE;
         m_nCurObjId   = -1;
     }
 
@@ -668,19 +807,27 @@ int TABMAPFile::LoadNextMatchingObjectBlock( int bFirstObject )
     // If we are just starting, verify the stack is empty.
     if( bFirstObject )
     {
-        CPLAssert( m_poSpIndex == NULL && m_poSpIndexLeaf == NULL );
+        CPLAssert( m_poSpIndexLeaf == NULL );
 
         /* m_nFirstIndexBlock set to 0 means that there is no feature */
         if ( m_poHeader->m_nFirstIndexBlock == 0 )
             return FALSE;
 
-        if( PushBlock( m_poHeader->m_nFirstIndexBlock ) == NULL )
-            return FALSE;
-
-        if( m_poSpIndex == NULL )
+        if( m_poSpIndex != NULL )
         {
-            CPLAssert( m_poCurObjBlock != NULL );
-            return TRUE;
+            m_poSpIndex->UnsetCurChild();
+            m_poSpIndexLeaf = m_poSpIndex;
+        }
+        else
+        {
+            if( PushBlock( m_poHeader->m_nFirstIndexBlock ) == NULL )
+                return FALSE;
+
+            if( m_poSpIndex == NULL )
+            {
+                CPLAssert( m_poCurObjBlock != NULL );
+                return TRUE;
+            }
         }
     }
 
@@ -691,17 +838,16 @@ int TABMAPFile::LoadNextMatchingObjectBlock( int bFirstObject )
         if( iEntry >= m_poSpIndexLeaf->GetNumEntries()-1 )
         {
             TABMAPIndexBlock *poParent = m_poSpIndexLeaf->GetParentRef();
-            delete m_poSpIndexLeaf;
+            if( m_poSpIndexLeaf == m_poSpIndex )
+                m_poSpIndex->UnsetCurChild();
+            else
+                delete m_poSpIndexLeaf;
             m_poSpIndexLeaf = poParent;
             
             if( poParent != NULL )
             {
                 poParent->SetCurChildRef( NULL, poParent->GetCurChildIndex() );
             }
-            else
-            {
-                m_poSpIndex = NULL;
-            }
             continue;
         }
 
@@ -740,12 +886,17 @@ int TABMAPFile::LoadNextMatchingObjectBlock( int bFirstObject )
 void TABMAPFile::ResetReading()
 
 {
-    if (m_poSpIndex && m_eAccessMode == TABRead )
+    if( m_bLastOpWasWrite )
+        CommitObjAndCoordBlocks( FALSE );
+
+    if (m_poSpIndex)
     {
-        delete m_poSpIndex;
-        m_poSpIndex = NULL;
-        m_poSpIndexLeaf = NULL;
+        m_poSpIndex->UnsetCurChild();
     }
+    m_poSpIndexLeaf = NULL;
+    
+    m_bLastOpWasWrite = FALSE;
+    m_bLastOpWasRead = FALSE;
 }
 
 /************************************************************************/
@@ -758,6 +909,19 @@ void TABMAPFile::ResetReading()
 int TABMAPFile::GetNextFeatureId( int nPrevId )
 
 {
+    if( m_bLastOpWasWrite )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "GetNextFeatureId() cannot be called after write operation");
+        return -1;
+    }
+    if( m_eAccessMode == TABWrite )
+    {
+        if( ReOpenReadWrite() < 0 )
+            return -1;
+    }
+    m_bLastOpWasRead = TRUE;
+
 /* -------------------------------------------------------------------- */
 /*      m_fp is NULL when all geometry are NONE and/or there's          */
 /*          no .map file and/or there's no spatial indexes              */
@@ -966,13 +1130,26 @@ GInt32 TABMAPFile::GetMaxObjId()
 int   TABMAPFile::MoveToObjId(int nObjId)
 {
     int nFileOffset;
+    
+    if( m_bLastOpWasWrite )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "MoveToObjId() cannot be called after write operation");
+        return -1;
+    }
+    if( m_eAccessMode == TABWrite )
+    {
+        if( ReOpenReadWrite() < 0 )
+            return -1;
+    }
+    m_bLastOpWasRead = TRUE;
 
     /*-----------------------------------------------------------------
-     * In read access mode, since the .MAP/.ID are optional, if the 
+     * In non creation mode, since the .MAP/.ID are optional, if the 
      * file is not opened then we can still act as if one existed and
      * make any object id look like a TAB_GEOM_NONE
      *----------------------------------------------------------------*/
-    if (m_fp == NULL && m_eAccessMode == TABRead)
+    if (m_fp == NULL && m_eAccessMode != TABWrite)
     {
         CPLAssert(m_poIdIndex == NULL && m_poCurObjBlock == NULL);
         m_nCurObjPtr = 0;
@@ -982,11 +1159,12 @@ int   TABMAPFile::MoveToObjId(int nObjId)
         return 0;
     }
 
-    if (m_poIdIndex == NULL || m_poCurObjBlock == NULL)
+    if (m_poIdIndex == NULL)
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
                  "MoveToObjId(): file not opened!");
-        m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
+        m_nCurObjPtr = m_nCurObjId = -1;
+        m_nCurObjType = TAB_GEOM_UNSET;
         return -1;
     }
 
@@ -999,6 +1177,15 @@ int   TABMAPFile::MoveToObjId(int nObjId)
     else
         nFileOffset = m_poIdIndex->GetObjPtr(nObjId);
 
+    if (nFileOffset != 0 && m_poCurObjBlock == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AssertionFailed,
+                 "MoveToObjId(): no current object block!");
+        m_nCurObjPtr = m_nCurObjId = -1;
+        m_nCurObjType = TAB_GEOM_UNSET;
+        return -1;
+    }
+
     if (nFileOffset == 0)
     {
         /*---------------------------------------------------------
@@ -1014,17 +1201,28 @@ int   TABMAPFile::MoveToObjId(int nObjId)
          * OK, it worked, read the object type and row id.
          *------------------------------------------------------------*/
         m_nCurObjPtr = nFileOffset;
-        m_nCurObjType = m_poCurObjBlock->ReadByte();
+        m_nCurObjType = (TABGeomType)m_poCurObjBlock->ReadByte();
         m_nCurObjId   = m_poCurObjBlock->ReadInt32();
 
         // Do a consistency check...
         if (m_nCurObjId != nObjId)
         {
-            CPLError(CE_Failure, CPLE_FileIO,
-                 "Object ID from the .ID file (%d) differs from the value "
-                 "in the .MAP file (%d).  File may be corrupt.",
-                 nObjId, m_nCurObjId);
-            m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
+            if( m_nCurObjId == (nObjId | 0x40000000) )
+            {
+                CPLError(CE_Failure, CPLE_FileIO,
+                    "Object %d is marked as deleted in the .MAP file but not in the .ID file."
+                    "File may be corrupt.",
+                    nObjId);
+            }
+            else
+            {
+                CPLError(CE_Failure, CPLE_FileIO,
+                    "Object ID from the .ID file (%d) differs from the value "
+                    "in the .MAP file (%d).  File may be corrupt.",
+                    nObjId, m_nCurObjId);
+            }
+            m_nCurObjPtr = m_nCurObjId = -1;
+            m_nCurObjType = TAB_GEOM_UNSET;
             return -1;
         }
     }
@@ -1033,13 +1231,51 @@ int   TABMAPFile::MoveToObjId(int nObjId)
         /*---------------------------------------------------------
          * Failed positioning input file... CPLError has been called.
          *--------------------------------------------------------*/
-        m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
+        m_nCurObjPtr = m_nCurObjId = -1;
+        m_nCurObjType = TAB_GEOM_UNSET;
         return -1;
     }
 
     return 0;
 }
 
+
+/**********************************************************************
+ *                   TABMAPFile::MarkAsDeleted()
+ 
+ * Returns 0 on success, -1 on error.
+ **********************************************************************/
+int TABMAPFile::MarkAsDeleted()
+{
+    if (m_eAccessMode == TABRead || m_poCurObjBlock == NULL)
+        return -1;
+    
+    if ( m_nCurObjPtr <= 0 )
+        return 0;
+    
+    /* Goto offset for object id */
+    if ( m_poCurObjBlock->GotoByteInFile(m_nCurObjPtr + 1, TRUE) != 0)
+        return -1;
+
+    /* Mark object as deleted */
+    m_poCurObjBlock->WriteInt32(m_nCurObjId | 0x40000000);
+
+    int ret = 0;
+    if( m_poCurObjBlock->CommitToFile() != 0 )
+        ret = -1;
+
+    /* Update index entry to reflect delete state as well */
+    if( m_poIdIndex->SetObjPtr(m_nCurObjId, 0) != 0 )
+        ret = -1;
+
+    m_nCurObjPtr = m_nCurObjId = -1;
+    m_nCurObjType = TAB_GEOM_UNSET;
+    m_bUpdated = TRUE;
+
+    return ret;
+}
+
+
 /**********************************************************************
  *                   TABMAPFile::UpdateMapHeaderInfo()
  *
@@ -1048,7 +1284,7 @@ int   TABMAPFile::MoveToObjId(int nObjId)
  *
  * Called only by PrepareNewObj() and by the TABCollection class.
  **********************************************************************/
-void  TABMAPFile::UpdateMapHeaderInfo(GByte nObjType)
+void  TABMAPFile::UpdateMapHeaderInfo(TABGeomType nObjType)
 {
     /*-----------------------------------------------------------------
      * Update count of objects by type in the header block
@@ -1148,10 +1384,10 @@ void  TABMAPFile::UpdateMapHeaderInfo(GByte nObjType)
  **********************************************************************/
 int   TABMAPFile::PrepareNewObj(TABMAPObjHdr *poObjHdr)
 {
+    m_nCurObjPtr = m_nCurObjId = -1;
+    m_nCurObjType = TAB_GEOM_UNSET;
 
-    m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
-
-    if (m_eAccessMode != TABWrite || 
+    if (m_eAccessMode == TABRead || 
         m_poIdIndex == NULL || m_poHeader == NULL)
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
@@ -1159,6 +1395,15 @@ int   TABMAPFile::PrepareNewObj(TABMAPObjHdr *poObjHdr)
         return -1;
     }
 
+    if (m_bLastOpWasRead )
+    {
+        m_bLastOpWasRead = FALSE;
+        if( m_poSpIndex)
+        {
+            m_poSpIndex->UnsetCurChild();
+        }
+    }
+
     /*-----------------------------------------------------------------
      * For objects with no geometry, we just update the .ID file and return
      *----------------------------------------------------------------*/
@@ -1227,6 +1472,9 @@ int   TABMAPFile::PrepareNewObj(TABMAPObjHdr *poObjHdr)
     if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() == CE_Failure)
         return -1;
 
+    m_bUpdated = TRUE;
+    m_bLastOpWasWrite = TRUE;
+
     return 0;
 }
 
@@ -1260,9 +1508,29 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
         m_poSpIndex = new TABMAPIndexBlock(m_eAccessMode);
 
         m_poSpIndex->InitNewBlock(m_fp, 512, 
-                                  m_oBlockManager.AllocNewBlock());
+                                  m_oBlockManager.AllocNewBlock("INDEX"));
         m_poSpIndex->SetMAPBlockManagerRef(&m_oBlockManager);
 
+        if( m_eAccessMode == TABReadWrite && m_poHeader->m_nFirstIndexBlock != 0 )
+        {
+            /* This can happen if the file created by MapInfo contains just */
+            /* a few objects */
+            TABRawBinBlock *poBlock;
+            poBlock = GetIndexObjectBlock( m_poHeader->m_nFirstIndexBlock );
+            CPLAssert( poBlock != NULL && poBlock->GetBlockType() == TABMAP_OBJECT_BLOCK);
+            delete poBlock;
+
+            if (m_poSpIndex->AddEntry(m_poHeader->m_nXMin, m_poHeader->m_nYMin,
+                                      m_poHeader->m_nXMax, m_poHeader->m_nYMax,
+                                      m_poHeader->m_nFirstIndexBlock) != 0)
+                return -1;
+
+            delete m_poCurObjBlock;
+            m_poCurObjBlock = NULL;
+            delete m_poCurCoordBlock;
+            m_poCurCoordBlock = NULL;
+        }
+
         m_poHeader->m_nFirstIndexBlock = m_poSpIndex->GetNodeBlockPtr();
 
         /* We'll also need to create an object data block (later) */
@@ -1297,7 +1565,7 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
          *------------------------------------------------------------*/
         m_poCurObjBlock = new TABMAPObjectBlock(TABReadWrite);
 
-        int nBlockOffset = m_oBlockManager.AllocNewBlock();
+        int nBlockOffset = m_oBlockManager.AllocNewBlock("OBJECT");
 
         m_poCurObjBlock->InitNewBlock(m_fp, 512, nBlockOffset);
 
@@ -1311,6 +1579,9 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
                                   m_poCurObjBlock->GetStartAddress()) != 0)
             return -1;
 
+        m_poCurObjBlock->SetMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
+                                poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
+
         m_poHeader->m_nMaxSpIndexDepth = MAX(m_poHeader->m_nMaxSpIndexDepth,
                                       (GByte)m_poSpIndex->GetCurMaxDepth()+1);
     }
@@ -1332,10 +1603,18 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
         {
             if (LoadObjAndCoordBlocks(nObjBlockForInsert) != 0)
                 return -1;
+        }
+
+        /* If we have compressed objects, we don't want to change the center  */
+        m_poCurObjBlock->LockCenter();
 
-            // The ObjBlock doesn't know its MBR. Get the value from the 
-            // index and set it
-            GInt32 nMinX, nMinY, nMaxX, nMaxY;
+        // Check if the ObjBlock know its MBR. If not (new block, or the current
+        // block was the good one but retrieved without the index), get the value
+        // from the index and set it.
+        GInt32 nMinX, nMinY, nMaxX, nMaxY;
+        m_poCurObjBlock->GetMBR(nMinX, nMinY, nMaxX, nMaxY);
+        if( nMinX > nMaxX )
+        {
             m_poSpIndex->GetCurLeafEntryMBR(m_poCurObjBlock->GetStartAddress(),
                                             nMinX, nMinY, nMaxX, nMaxY);
             m_poCurObjBlock->SetMBR(nMinX, nMinY, nMaxX, nMaxY);
@@ -1347,6 +1626,78 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
      * block for new object, update spatial index and split if necessary.
      *----------------------------------------------------------------*/
     nObjSize = m_poHeader->GetMapObjectSize(poObjHdr->m_nType);
+
+
+    /*-----------------------------------------------------------------
+     * But first check if we can recover space from this block in case
+     * there are deleted objects in it.
+     *----------------------------------------------------------------*/
+    if (m_poCurObjBlock->GetNumUnusedBytes() < nObjSize )
+    {
+        TABMAPObjHdr *poExistingObjHdr=NULL;
+        TABMAPObjHdr **papoSrcObjHdrs = NULL;
+        int i, numSrcObj = 0;
+        int nObjectSpace = 0;
+
+        /* First pass to enumerate valid objects and compute their accumulated
+           required size. */
+        m_poCurObjBlock->Rewind();
+        while ((poExistingObjHdr = TABMAPObjHdr::ReadNextObj(m_poCurObjBlock, 
+                                                    m_poHeader)) != NULL)
+        {
+            if (papoSrcObjHdrs == NULL || numSrcObj%10 == 0)
+            {
+                // Realloc the array... by steps of 10
+                papoSrcObjHdrs = (TABMAPObjHdr**)CPLRealloc(papoSrcObjHdrs, 
+                                                            (numSrcObj+10)*
+                                                            sizeof(TABMAPObjHdr*));
+            }
+            papoSrcObjHdrs[numSrcObj++] = poExistingObjHdr;
+
+            nObjectSpace += m_poHeader->GetMapObjectSize(poExistingObjHdr->m_nType);
+        }
+
+        /* Check that there's really some place that can be recovered */
+        if( nObjectSpace < 512 - 20 - m_poCurObjBlock->GetNumUnusedBytes() )
+        {
+#ifdef DEBUG_VERBOSE
+            CPLDebug("MITAB", "Compacting block at offset %d, %d objects valid, recovering %d bytes",
+                     m_poCurObjBlock->GetStartAddress(), numSrcObj,
+                     (512 - 20 - m_poCurObjBlock->GetNumUnusedBytes()) - nObjectSpace);
+#endif
+            m_poCurObjBlock->ClearObjects();
+
+            for(i=0; i<numSrcObj; i++)
+            {
+                /*-----------------------------------------------------------------
+                * Prepare and Write ObjHdr to this ObjBlock
+                *----------------------------------------------------------------*/
+                int nObjPtr = m_poCurObjBlock->PrepareNewObject(papoSrcObjHdrs[i]);
+                if (nObjPtr < 0 ||
+                    m_poCurObjBlock->CommitNewObject(papoSrcObjHdrs[i]) != 0)
+                {
+                    CPLError(CE_Failure, CPLE_FileIO,
+                            "Failed writing object header for feature id %d",
+                            papoSrcObjHdrs[i]->m_nId);
+                    return -1;
+                }
+
+                /*-----------------------------------------------------------------
+                * Update .ID Index
+                *----------------------------------------------------------------*/
+                m_poIdIndex->SetObjPtr(papoSrcObjHdrs[i]->m_nId, nObjPtr);
+            }
+        }
+
+        /* Cleanup papoSrcObjHdrs[] */
+        for(i=0; i<numSrcObj; i++)
+        {
+            delete papoSrcObjHdrs[i];
+        }
+        CPLFree(papoSrcObjHdrs);
+        papoSrcObjHdrs = NULL;
+    }
+
     if (m_poCurObjBlock->GetNumUnusedBytes() >= nObjSize )
     {
         /*-------------------------------------------------------------
@@ -1360,6 +1711,8 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
         nMinY = MIN(nMinY, poObjHdr->m_nMinY);
         nMaxX = MAX(nMaxX, poObjHdr->m_nMaxX);
         nMaxY = MAX(nMaxY, poObjHdr->m_nMaxY);
+        
+        m_poCurObjBlock->SetMBR(nMinX, nMinY, nMaxX, nMaxY);
 
         if (m_poSpIndex->UpdateLeafEntry(m_poCurObjBlock->GetStartAddress(),
                                          nMinX, nMinY, nMaxX, nMaxY) != 0)
@@ -1388,12 +1741,15 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
          *------------------------------------------------------------*/
         GInt32 nMinX, nMinY, nMaxX, nMaxY;
         m_poCurObjBlock->GetMBR(nMinX, nMinY, nMaxX, nMaxY);
+        CPLAssert(nMinX <= nMaxX);
 
         /* Need to calculate the enlarged MBR that includes new object */
         nMinX = MIN(nMinX, poObjHdr->m_nMinX);
         nMinY = MIN(nMinY, poObjHdr->m_nMinY);
         nMaxX = MAX(nMaxX, poObjHdr->m_nMaxX);
         nMaxY = MAX(nMaxY, poObjHdr->m_nMaxY);
+        
+        m_poCurObjBlock->SetMBR(nMinX, nMinY, nMaxX, nMaxY);
 
         if (m_poSpIndex->UpdateLeafEntry(m_poCurObjBlock->GetStartAddress(),
                                          nMinX, nMinY, nMaxX, nMaxY) != 0)
@@ -1403,6 +1759,7 @@ int   TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
          * Add new obj block to index
          *------------------------------------------------------------*/
         poNewObjBlock->GetMBR(nMinX, nMinY, nMaxX, nMaxY);
+        CPLAssert(nMinX <= nMaxX);
 
         if (m_poSpIndex->AddEntry(nMinX, nMinY, nMaxX, nMaxY,
                                   poNewObjBlock->GetStartAddress()) != 0)
@@ -1449,7 +1806,7 @@ int   TABMAPFile::PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr)
     {
         m_poCurObjBlock = new TABMAPObjectBlock(m_eAccessMode);
 
-        int nBlockOffset = m_oBlockManager.AllocNewBlock();
+        int nBlockOffset = m_oBlockManager.AllocNewBlock("OBJECT");
 
         m_poCurObjBlock->InitNewBlock(m_fp, 512, nBlockOffset);
 
@@ -1474,7 +1831,7 @@ int   TABMAPFile::PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr)
         CommitObjAndCoordBlocks(FALSE);
 
         if (m_poCurObjBlock->InitNewBlock(m_fp,512,
-                                  m_oBlockManager.AllocNewBlock())!=0)
+                                  m_oBlockManager.AllocNewBlock("OBJECT"))!=0)
             return -1; /* Error already reported */
 
         /*-------------------------------------------------------------
@@ -1503,6 +1860,18 @@ int   TABMAPFile::PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr)
  **********************************************************************/
 int   TABMAPFile::CommitNewObj(TABMAPObjHdr *poObjHdr)
 {
+    /* Update this now so that PrepareCoordBlock() doesn't try to old an older */
+    /* block */
+    if( m_poCurCoordBlock != NULL )
+        m_poCurObjBlock->AddCoordBlockRef(m_poCurCoordBlock->GetStartAddress());
+
+    /* So that GetExtent() is up-to-date */
+    if( m_poSpIndex != NULL )
+    {
+        m_poSpIndex->GetMBR(m_poHeader->m_nXMin, m_poHeader->m_nYMin,
+                            m_poHeader->m_nXMax, m_poHeader->m_nYMax);
+    }
+
     return m_poCurObjBlock->CommitNewObject(poObjHdr);
 }
 
@@ -1527,12 +1896,25 @@ int TABMAPFile::CommitObjAndCoordBlocks(GBool bDeleteObjects /*=FALSE*/)
     if (m_poCurObjBlock == NULL)
         return 0; 
 
-    if (m_eAccessMode != TABWrite)
+    if (m_eAccessMode == TABRead)
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
                  "CommitObjAndCoordBlocks() failed: file not opened for write access.");
         return -1;
     }
+    
+    if (!m_bLastOpWasWrite)
+    {
+        if (bDeleteObjects)
+        {
+            delete m_poCurCoordBlock;
+            m_poCurCoordBlock = NULL;
+            delete m_poCurObjBlock;
+            m_poCurObjBlock = NULL;
+        }
+        return 0;
+    }
+    m_bLastOpWasWrite = FALSE;
 
     /*-----------------------------------------------------------------
      * We need to flush the coord block if there was one
@@ -1586,7 +1968,7 @@ int TABMAPFile::CommitObjAndCoordBlocks(GBool bDeleteObjects /*=FALSE*/)
             m_poSpIndex = new TABMAPIndexBlock(m_eAccessMode);
 
             m_poSpIndex->InitNewBlock(m_fp, 512, 
-                                      m_oBlockManager.AllocNewBlock());
+                                      m_oBlockManager.AllocNewBlock("INDEX"));
             m_poSpIndex->SetMAPBlockManagerRef(&m_oBlockManager);
 
             m_poHeader->m_nFirstIndexBlock = m_poSpIndex->GetNodeBlockPtr();
@@ -1630,7 +2012,7 @@ int TABMAPFile::LoadObjAndCoordBlocks(GInt32 nBlockPtr)
     /*-----------------------------------------------------------------
      * In Write mode, if an object block is already in memory then flush it
      *----------------------------------------------------------------*/
-    if (m_eAccessMode == TABWrite && m_poCurObjBlock != NULL)
+    if (m_eAccessMode != TABRead && m_poCurObjBlock != NULL)
     {
         int nStatus = CommitObjAndCoordBlocks(TRUE);
         if (nStatus != 0)
@@ -1640,9 +2022,10 @@ int TABMAPFile::LoadObjAndCoordBlocks(GInt32 nBlockPtr)
     /*-----------------------------------------------------------------
      * Load Obj Block
      *----------------------------------------------------------------*/
-    if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
+    poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                              nBlockPtr,
-                                             512, TRUE, TABReadWrite)) &&
+                                             512, TRUE, TABReadWrite);
+    if (poBlock != NULL &&
         poBlock->GetBlockClass() == TABMAP_OBJECT_BLOCK)
     {
         m_poCurObjBlock = (TABMAPObjectBlock*)poBlock;
@@ -1662,11 +2045,13 @@ int TABMAPFile::LoadObjAndCoordBlocks(GInt32 nBlockPtr)
     if (m_poCurObjBlock->GetLastCoordBlockAddress() == 0)
     {
         m_poCurCoordBlock = NULL;
+        return 0;
     }
-    else if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
+
+    poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                    m_poCurObjBlock->GetLastCoordBlockAddress(),
-                                                  512, TRUE, TABReadWrite)) &&
-             poBlock->GetBlockClass() == TABMAP_COORD_BLOCK)
+                                                  512, TRUE, TABReadWrite);
+    if (poBlock != NULL && poBlock->GetBlockClass() == TABMAP_COORD_BLOCK)
     {
         m_poCurCoordBlock = (TABMAPCoordBlock*)poBlock;
         m_poCurCoordBlock->SetMAPBlockManagerRef(&m_oBlockManager);
@@ -1720,7 +2105,8 @@ TABMAPObjectBlock *TABMAPFile::SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
         }
         papoSrcObjHdrs[numSrcObj++] = poObjHdr;
     }
-    CPLAssert(numSrcObj > 0);
+    /* PickSeedsForSplit (reasonably) assumes at least 2 nodes */
+    CPLAssert(numSrcObj > 1);
 
     /*-----------------------------------------------------------------
      * Reset current obj and coord block 
@@ -1737,7 +2123,11 @@ TABMAPObjectBlock *TABMAPFile::SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
      * Create new obj and coord block
      *----------------------------------------------------------------*/
     TABMAPObjectBlock *poNewObjBlock = new TABMAPObjectBlock(m_eAccessMode);
-    poNewObjBlock->InitNewBlock(m_fp, 512, m_oBlockManager.AllocNewBlock());
+    poNewObjBlock->InitNewBlock(m_fp, 512, m_oBlockManager.AllocNewBlock("OBJECT"));
+
+    /* Use existing center of other block in case we have compressed objects
+       and freeze it */
+    poNewObjBlock->SetCenterFromOtherBlock(m_poCurObjBlock);
 
     /* Coord block will be alloc'd automatically*/
     TABMAPCoordBlock *poNewCoordBlock = NULL;  
@@ -1814,10 +2204,10 @@ TABMAPObjectBlock *TABMAPFile::SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
             continue;
         }
 
-
         // Decide which of the two blocks to put this entry in
         GInt32 nXMin, nYMin, nXMax, nYMax;
         m_poCurObjBlock->GetMBR(nXMin, nYMin, nXMax, nYMax);
+        CPLAssert( nXMin <= nXMax );
         double dAreaDiff1 = 
             TABMAPIndexBlock::ComputeAreaDiff(nXMin, nYMin, 
                                               nXMax, nYMax,
@@ -1827,6 +2217,7 @@ TABMAPObjectBlock *TABMAPFile::SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
                                               poObjHdr->m_nMaxY);
 
         poNewObjBlock->GetMBR(nXMin, nYMin, nXMax, nYMax);
+        CPLAssert( nXMin <= nXMax );
         double dAreaDiff2 = 
             TABMAPIndexBlock::ComputeAreaDiff(nXMin, nYMin, nXMax, nYMax,
                                               poObjHdr->m_nMinX, 
@@ -1888,7 +2279,7 @@ TABMAPObjectBlock *TABMAPFile::SplitObjBlock(TABMAPObjHdr *poObjHdrToAdd,
             if (poSrcCoordBlock->CommitAsDeleted(m_oBlockManager.
                                                  GetFirstGarbageBlock()) != 0)
                 return NULL;
-            m_oBlockManager.PushGarbageBlock(poSrcCoordBlock->GetStartAddress());
+            m_oBlockManager.PushGarbageBlockAsFirst(poSrcCoordBlock->GetStartAddress());
 
             // Advance to next
             if (nNextCoordBlock > 0)
@@ -2027,20 +2418,42 @@ int TABMAPFile::PrepareCoordBlock(int nObjType,
                                                   TABReadWrite: 
                                                   m_eAccessMode);
             (*ppoCoordBlock)->InitNewBlock(m_fp, 512, 
-                                           m_oBlockManager.AllocNewBlock());
+                                           m_oBlockManager.AllocNewBlock("COORD"));
             (*ppoCoordBlock)->SetMAPBlockManagerRef(&m_oBlockManager);
 
             // Set the references to this coord block in the MAPObjBlock
             poObjBlock->AddCoordBlockRef((*ppoCoordBlock)->GetStartAddress());
-
+        }
+        /* If we are not at the end of the chain of coordinate blocks, then */
+        /* reload us */
+        else if( (*ppoCoordBlock)->GetStartAddress() != poObjBlock->GetLastCoordBlockAddress() )
+        {
+            TABRawBinBlock* poBlock = TABCreateMAPBlockFromFile(m_fp, 
+                                    poObjBlock->GetLastCoordBlockAddress(),
+                                    512, TRUE, TABReadWrite);
+            if (poBlock != NULL && poBlock->GetBlockClass() == TABMAP_COORD_BLOCK)
+            {
+                delete *ppoCoordBlock;
+                *ppoCoordBlock = (TABMAPCoordBlock*)poBlock;
+                (*ppoCoordBlock)->SetMAPBlockManagerRef(&m_oBlockManager);
+            }
+            else
+            {
+                delete poBlock;
+                CPLError(CE_Failure, CPLE_FileIO,
+                            "LoadObjAndCoordBlocks() failed for coord block at %d.", 
+                            poObjBlock->GetLastCoordBlockAddress());
+                return -1;
+            }
         }
 
         if ((*ppoCoordBlock)->GetNumUnusedBytes() < 4)
         {
-            int nNewBlockOffset = m_oBlockManager.AllocNewBlock();
+            int nNewBlockOffset = m_oBlockManager.AllocNewBlock("COORD");
             (*ppoCoordBlock)->SetNextCoordBlock(nNewBlockOffset);
             (*ppoCoordBlock)->CommitToFile();
             (*ppoCoordBlock)->InitNewBlock(m_fp, 512, nNewBlockOffset);
+            poObjBlock->AddCoordBlockRef((*ppoCoordBlock)->GetStartAddress());
         }
 
         // Make sure read/write pointer is at the end of the block
@@ -2061,7 +2474,7 @@ int TABMAPFile::PrepareCoordBlock(int nObjType,
  *
  * Returns a value >= 0 on success, -1 on error.
  **********************************************************************/
-int TABMAPFile::GetCurObjType()
+TABGeomType TABMAPFile::GetCurObjType()
 {
     return m_nCurObjType;
 }
@@ -2125,13 +2538,11 @@ TABMAPCoordBlock *TABMAPFile::GetCurCoordBlock()
  **********************************************************************/
 TABMAPCoordBlock *TABMAPFile::GetCoordBlock(int nFileOffset)
 {
-    if (m_eAccessMode != TABRead)
-        return NULL;
-
     if (m_poCurCoordBlock == NULL)
     {
         m_poCurCoordBlock = new TABMAPCoordBlock(m_eAccessMode);
         m_poCurCoordBlock->InitNewBlock(m_fp, 512);
+        m_poCurCoordBlock->SetMAPBlockManagerRef(&m_oBlockManager);
     }
 
     /*-----------------------------------------------------------------
@@ -2205,8 +2616,8 @@ TABRawBinBlock *TABMAPFile::GetIndexObjectBlock( int nFileOffset )
      *---------------------------------------------------------------*/
     GByte abyData[512];
 
-    if (VSIFSeek(m_fp, nFileOffset, SEEK_SET) != 0 
-        || VSIFRead(abyData, sizeof(GByte), 512, m_fp) != 512 )
+    if (VSIFSeekL(m_fp, nFileOffset, SEEK_SET) != 0 
+        || VSIFReadL(abyData, sizeof(GByte), 512, m_fp) != 512 )
     {
         CPLError(CE_Failure, CPLE_FileIO,
                  "GetIndexBlock() failed reading %d bytes at offset %d.",
@@ -2221,9 +2632,13 @@ TABRawBinBlock *TABMAPFile::GetIndexObjectBlock( int nFileOffset )
     TABRawBinBlock *poBlock;
 
     if( nBlockType == TABMAP_INDEX_BLOCK )
-        poBlock = new TABMAPIndexBlock();
+    {
+        TABMAPIndexBlock* poIndexBlock = new TABMAPIndexBlock(m_eAccessMode);
+        poBlock = poIndexBlock;
+        poIndexBlock->SetMAPBlockManagerRef(&m_oBlockManager);
+    }
     else
-        poBlock = new TABMAPObjectBlock();
+        poBlock = new TABMAPObjectBlock(m_eAccessMode);
     
     if( poBlock->InitBlockFromData(abyData, 512, 512,
                                    TRUE, m_fp, nFileOffset) == -1 )
@@ -2265,11 +2680,12 @@ int TABMAPFile::InitDrawingTools()
      *------------------------------------------------------------*/
     m_poToolDefTable = new TABToolDefTable;
 
-    if (m_eAccessMode == TABRead && m_poHeader->m_nFirstToolBlock != 0)
+    if ((m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite) &&
+        m_poHeader->m_nFirstToolBlock != 0)
     {
         TABMAPToolBlock *poBlock;
 
-        poBlock = new TABMAPToolBlock(m_eAccessMode);
+        poBlock = new TABMAPToolBlock(TABRead);
         poBlock->InitNewBlock(m_fp, 512);
     
         /*-------------------------------------------------------------
@@ -2308,7 +2724,7 @@ int TABMAPFile::CommitDrawingTools()
 {
     int nStatus = 0;
 
-    if (m_eAccessMode != TABWrite || m_poHeader == NULL)
+    if (m_eAccessMode == TABRead || m_poHeader == NULL)
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
             "CommitDrawingTools() failed: file not opened for write access.");
@@ -2330,7 +2746,10 @@ int TABMAPFile::CommitDrawingTools()
     TABMAPToolBlock *poBlock;
     
     poBlock = new TABMAPToolBlock(m_eAccessMode);
-    poBlock->InitNewBlock(m_fp, 512, m_oBlockManager.AllocNewBlock());
+    if( m_poHeader->m_nFirstToolBlock != 0 )
+        poBlock->InitNewBlock(m_fp, 512, m_poHeader->m_nFirstToolBlock);
+    else
+        poBlock->InitNewBlock(m_fp, 512, m_oBlockManager.AllocNewBlock("TOOL"));
     poBlock->SetMAPBlockManagerRef(&m_oBlockManager);
 
     m_poHeader->m_nFirstToolBlock = poBlock->GetStartAddress();
@@ -2659,7 +3078,7 @@ void TABMAPFile::GetCoordFilter(TABVertex &sMin, TABVertex &sMax)
  **********************************************************************/
 int TABMAPFile::CommitSpatialIndex()
 {
-    if (m_eAccessMode != TABWrite || m_poHeader == NULL)
+    if (m_eAccessMode == TABRead || m_poHeader == NULL)
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
             "CommitSpatialIndex() failed: file not opened for write access.");
diff --git a/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp
index b8a53bd..0313ef1 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2002, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -138,6 +139,12 @@
 
 #include "mitab.h"
 
+#ifdef WIN32
+inline double round(double r) {
+    return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
+}
+#endif
+
 /*---------------------------------------------------------------------
  * Set various constants used in generating the header block.
  *--------------------------------------------------------------------*/
@@ -179,6 +186,27 @@ static GByte  gabyObjLenArray[ HDR_OBJ_LEN_ARRAY_SIZE  ] = {
 TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/):
     TABRawBinBlock(eAccessMode, TRUE)
 {
+    InitMembersWithDefaultValues();
+
+    /* We don't want to reset it once it is set */
+    m_bIntBoundsOverflow = FALSE;
+}
+
+/**********************************************************************
+ *                   TABMAPHeaderBlock::~TABMAPHeaderBlock()
+ *
+ * Destructor.
+ **********************************************************************/
+TABMAPHeaderBlock::~TABMAPHeaderBlock()
+{
+
+}
+
+/**********************************************************************
+ *            TABMAPHeaderBlock::InitMembersWithDefaultValues()
+ **********************************************************************/
+void TABMAPHeaderBlock::InitMembersWithDefaultValues()
+{
     int i;
 
     /*-----------------------------------------------------------------
@@ -207,7 +235,7 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/):
     m_nDistUnitsCode = 7;       // Meters
     m_nMaxSpIndexDepth = 0;
     m_nCoordPrecision = 3;      // ??? 3 Digits of precision
-    m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ???
+    m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant
     m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS;
     m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1;  // See gabyObjLenArray[]
     m_numPenDefs = 0;
@@ -219,10 +247,13 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/):
     m_sProj.nProjId  = 0;
     m_sProj.nEllipsoidId = 0;
     m_sProj.nUnitsId = 7;
+    m_sProj.nDatumId = 0;
     m_XScale = 1000.0;  // Default coord range (before SetCoordSysBounds()) 
     m_YScale = 1000.0;  // will be [-1000000.000 .. 1000000.000]
     m_XDispl = 0.0;
     m_YDispl = 0.0;
+    m_XPrecision = 0.0;  // not specified
+    m_YPrecision = 0.0;  // not specified
 
     for(i=0; i<6; i++)
         m_sProj.adProjParams[i] = 0.0;
@@ -243,16 +274,6 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/):
     m_sProj.dAffineParamF = 0.0;
 }
 
-/**********************************************************************
- *                   TABMAPHeaderBlock::~TABMAPHeaderBlock()
- *
- * Destructor.
- **********************************************************************/
-TABMAPHeaderBlock::~TABMAPHeaderBlock()
-{
-
-}
-
 
 /**********************************************************************
  *                   TABMAPHeaderBlock::InitBlockFromData()
@@ -266,7 +287,7 @@ TABMAPHeaderBlock::~TABMAPHeaderBlock()
 int     TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf, 
                                              int nBlockSize, int nSizeUsed, 
                                              GBool bMakeCopy /* = TRUE */,
-                                             FILE *fpSrc /* = NULL */, 
+                                             VSILFILE *fpSrc /* = NULL */, 
                                              int nOffset /* = 0 */)
 {
     int i, nStatus;
@@ -313,6 +334,11 @@ int     TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf,
     m_nYMin = ReadInt32();
     m_nXMax = ReadInt32();
     m_nYMax = ReadInt32();
+    if( m_nXMin > m_nXMax || m_nYMin > m_nYMax )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined, "Reading corrupted MBR from .map header");
+        CPLErrorReset();
+    }
 
     GotoByteInBlock(0x130);     // Skip 16 unknown bytes 
 
@@ -405,6 +431,8 @@ int     TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf,
         }
     }
 
+    UpdatePrecision();
+
     return 0;
 }
 
@@ -444,6 +472,12 @@ int TABMAPHeaderBlock::Int2Coordsys(GInt32 nX, GInt32 nY,
     else
         dY = (nY - m_YDispl) / m_YScale;
 
+    // Round coordinates to the desired precision
+    if (m_XPrecision > 0 && m_YPrecision > 0)
+    {
+        dX = round(dX*m_XPrecision)/m_XPrecision;
+        dY = round(dY*m_YPrecision)/m_YPrecision;
+    }
 //printf("Int2Coordsys: (%d, %d) -> (%.10g, %.10g)\n", nX, nY, dX, dY);
 
     return 0;
@@ -664,6 +698,8 @@ int TABMAPHeaderBlock::SetCoordsysBounds(double dXMin, double dYMin,
     m_nXMax = 1000000000;
     m_nYMax = 1000000000;
 
+    UpdatePrecision();
+
     return 0;
 }
 
@@ -823,6 +859,10 @@ int     TABMAPHeaderBlock::CommitToFile()
     WriteInt32(m_nYMin);
     WriteInt32(m_nXMax);
     WriteInt32(m_nYMax);
+    if( m_nXMin > m_nXMax || m_nYMin > m_nYMax )
+    {
+        CPLError(CE_Warning, CPLE_AppDefined, "Writing corrupted MBR into .map header");
+    }
 
     WriteZeros(16);     // ???
 
@@ -889,7 +929,12 @@ int     TABMAPHeaderBlock::CommitToFile()
      * OK, call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting HEADER block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+    }
 
     return nStatus;
 }
@@ -909,10 +954,9 @@ int     TABMAPHeaderBlock::CommitToFile()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABMAPHeaderBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                         int nFileOffset /* = 0*/)
 {
-    int i;
     /*-----------------------------------------------------------------
      * Start with the default initialisation
      *----------------------------------------------------------------*/
@@ -922,56 +966,7 @@ int     TABMAPHeaderBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
     /*-----------------------------------------------------------------
      * Set acceptable default values for member vars.
      *----------------------------------------------------------------*/
-    m_nMAPVersionNumber = HDR_VERSION_NUMBER;
-    m_nBlockSize = HDR_DATA_BLOCK_SIZE;
-
-    m_dCoordsys2DistUnits = 1.0;
-    m_nXMin = -1000000000;
-    m_nYMin = -1000000000;
-    m_nXMax = 1000000000;
-    m_nYMax = 1000000000;
-
-    m_nFirstIndexBlock = 0;
-    m_nFirstGarbageBlock = 0;
-    m_nFirstToolBlock = 0;
-
-    m_numPointObjects = 0;
-    m_numLineObjects = 0;
-    m_numRegionObjects = 0;
-    m_numTextObjects = 0;
-    m_nMaxCoordBufSize = 0;
-
-    m_nDistUnitsCode = 7;       // Meters
-    m_nMaxSpIndexDepth = 0;
-    m_nCoordPrecision = 3;      // ??? 3 digits of precision
-    m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant
-    m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS;
-    m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1;  // See gabyObjLenArray[]
-    m_numPenDefs = 0;
-    m_numBrushDefs = 0;
-    m_numSymbolDefs = 0;
-    m_numFontDefs = 0;
-    m_numMapToolBlocks = 0;
-
-    m_sProj.nProjId  = 0;
-    m_sProj.nEllipsoidId = 0;
-    m_sProj.nUnitsId = 7;
-    m_sProj.nDatumId = 0;
-    m_XScale = 1000.0;  // Default coord range (before SetCoordSysBounds()) 
-    m_YScale = 1000.0;  // will be [-1000000.000 .. 1000000.000]
-    m_XDispl = 0.0;
-    m_YDispl = 0.0;
-
-    for(i=0; i<6; i++)
-        m_sProj.adProjParams[i] = 0.0;
-
-    m_sProj.dDatumShiftX = 0.0;
-    m_sProj.dDatumShiftY = 0.0;
-    m_sProj.dDatumShiftZ = 0.0;
-    for(i=0; i<5; i++)
-        m_sProj.adDatumParams[i] = 0.0;
-
-    m_sProj.nAffineFlag = 0;
+    InitMembersWithDefaultValues();
 
     /*-----------------------------------------------------------------
      * And Set the map object length array in the buffer...
@@ -988,6 +983,17 @@ int     TABMAPHeaderBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
     return 0;
 }
 
+/**********************************************************************
+ * TABMAPHeaderBlock::UpdatePrecision()
+ *
+ * Update x and y maximum achievable precision given current scales
+ * (m_XScale and m_YScale)
+ **********************************************************************/
+void TABMAPHeaderBlock::UpdatePrecision()
+{
+    m_XPrecision = pow(10.0, round(log10(m_XScale)));
+    m_YPrecision = pow(10.0, round(log10(m_YScale)));
+}
 
 /**********************************************************************
  *                   TABMAPHeaderBlock::Dump()
diff --git a/ogr/ogrsf_frmts/mitab/mitab_mapindexblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_mapindexblock.cpp
index 7fcace7..62bc0ab 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_mapindexblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_mapindexblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -117,12 +118,23 @@ TABMAPIndexBlock::TABMAPIndexBlock(TABAccess eAccessMode /*= TABRead*/):
  **********************************************************************/
 TABMAPIndexBlock::~TABMAPIndexBlock()
 {
+    UnsetCurChild();
+}
+
+/**********************************************************************
+ *                   TABMAPIndexBlock::UnsetCurChild()
+ **********************************************************************/
+
+void TABMAPIndexBlock::UnsetCurChild()
+{
     if (m_poCurChild)
     {
         if (m_eAccess == TABWrite || m_eAccess == TABReadWrite)
             m_poCurChild->CommitToFile();
         delete m_poCurChild;
+        m_poCurChild = NULL;
     }
+    m_nCurChildIndex = -1;
 }
 
 /**********************************************************************
@@ -137,7 +149,7 @@ TABMAPIndexBlock::~TABMAPIndexBlock()
 int     TABMAPIndexBlock::InitBlockFromData(GByte *pabyBuf, 
                                             int nBlockSize, int nSizeUsed, 
                                             GBool bMakeCopy /* = TRUE */,
-                                            FILE *fpSrc /* = NULL */, 
+                                            VSILFILE *fpSrc /* = NULL */, 
                                             int nOffset /* = 0 */)
 {
     int nStatus;
@@ -242,7 +254,12 @@ int     TABMAPIndexBlock::CommitToFile()
      * OK, call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting INDEX block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+    }
 
     return nStatus;
 }
@@ -263,7 +280,7 @@ int     TABMAPIndexBlock::CommitToFile()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABMAPIndexBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABMAPIndexBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                         int nFileOffset /* = 0*/)
 {
     /*-----------------------------------------------------------------
@@ -282,7 +299,7 @@ int     TABMAPIndexBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
     m_nMaxX = -1000000000;
     m_nMaxY = -1000000000;
 
-    if (m_eAccess != TABRead)
+    if (m_eAccess != TABRead && nFileOffset != 0)
     {
         GotoByteInBlock(0x000);
 
@@ -439,6 +456,19 @@ void TABMAPIndexBlock::GetMBR(GInt32 &nXMin, GInt32 &nYMin,
 }
 
 /**********************************************************************
+ *                   TABMAPIndexBlock::SetMBR()
+ *
+ **********************************************************************/
+void TABMAPIndexBlock::SetMBR(GInt32 nXMin, GInt32 nYMin, 
+                              GInt32 nXMax, GInt32 nYMax)
+{
+    m_nMinX = nXMin;
+    m_nMinY = nYMin;
+    m_nMaxX = nXMax;
+    m_nMaxY = nYMax; 
+}
+
+/**********************************************************************
  *                   TABMAPIndexBlock::InsertEntry()
  *
  * Add a new entry to this index block.  It is assumed that there is at
@@ -616,10 +646,10 @@ GInt32  TABMAPIndexBlock::ChooseLeafForInsert(GInt32 nXMin, GInt32 nYMin,
     // Prevent error message if referred block not committed yet.
     CPLPushErrorHandler(CPLQuietErrorHandler);
 
-    if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
+    poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                     m_asEntries[nBestCandidate].nBlockPtr,
-                                    512, TRUE, TABReadWrite)) &&
-        poBlock->GetBlockClass() == TABMAP_INDEX_BLOCK)
+                                    512, TRUE, TABReadWrite);
+    if (poBlock != NULL && poBlock->GetBlockClass() == TABMAP_INDEX_BLOCK)
     {
         m_poCurChild = (TABMAPIndexBlock*)poBlock;
         poBlock = NULL;
@@ -823,10 +853,10 @@ int     TABMAPIndexBlock::AddEntry(GInt32 nXMin, GInt32 nYMin,
             // Prevent error message if referred block not committed yet.
             CPLPushErrorHandler(CPLQuietErrorHandler);
 
-            if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
+            poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                        m_asEntries[nBestCandidate].nBlockPtr,
-                                       512, TRUE, TABReadWrite)) &&
-                poBlock->GetBlockClass() == TABMAP_INDEX_BLOCK)
+                                       512, TRUE, TABReadWrite);
+            if (poBlock != NULL && poBlock->GetBlockClass() == TABMAP_INDEX_BLOCK)
             {
                 m_poCurChild = (TABMAPIndexBlock*)poBlock;
                 poBlock = NULL;
@@ -1051,8 +1081,8 @@ int  TABMAPIndexBlock::PickSeedsForSplit(TABMAPIndexEntry *pasEntries,
     // corresponding dimension
     double dX, dY;
 
-    dX = (double)(nHighestMinX - nLowestMaxX) / nSrcWidth;
-    dY = (double)(nHighestMinY - nLowestMaxY) / nSrcHeight;
+    dX = (nSrcWidth == 0) ? 0 : (double)(nHighestMinX - nLowestMaxX) / nSrcWidth;
+    dY = (nSrcHeight == 0) ? 0 : (double)(nHighestMinY - nLowestMaxY) / nSrcHeight;
 
     // Choose the pair with the greatest normalized separation along
     // any dimension
@@ -1138,7 +1168,7 @@ int     TABMAPIndexBlock::SplitNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
      *----------------------------------------------------------------*/
     TABMAPIndexBlock *poNewNode = new TABMAPIndexBlock(m_eAccess);
     if (poNewNode->InitNewBlock(m_fp, 512, 
-                                m_poBlockManagerRef->AllocNewBlock()) != 0)
+                                m_poBlockManagerRef->AllocNewBlock("INDEX")) != 0)
     {
         return -1;
     }
@@ -1321,7 +1351,7 @@ int TABMAPIndexBlock::SplitRootNode(GInt32 nNewEntryXMin, GInt32 nNewEntryYMin,
     TABMAPIndexBlock *poNewNode = new TABMAPIndexBlock(m_eAccess);
 
     if (poNewNode->InitNewBlock(m_fp, 512, 
-                                m_poBlockManagerRef->AllocNewBlock()) != 0)
+                                m_poBlockManagerRef->AllocNewBlock("INDEX")) != 0)
     {
         return -1;
     }
@@ -1550,5 +1580,3 @@ void TABMAPIndexBlock::Dump(FILE *fpOut /*=NULL*/)
     fflush(fpOut);
 }
 #endif // DEBUG
-
-
diff --git a/ogr/ogrsf_frmts/mitab/mitab_mapobjectblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_mapobjectblock.cpp
index 9c664c5..34ad29d 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_mapobjectblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_mapobjectblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2001, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -126,6 +127,7 @@
 TABMAPObjectBlock::TABMAPObjectBlock(TABAccess eAccessMode /*= TABRead*/):
     TABRawBinBlock(eAccessMode, TRUE)
 {
+    m_bLockCenter = FALSE;
 }
 
 /**********************************************************************
@@ -155,7 +157,7 @@ TABMAPObjectBlock::~TABMAPObjectBlock()
 int     TABMAPObjectBlock::InitBlockFromData(GByte *pabyBuf,
                                              int nBlockSize, int nSizeUsed, 
                                              GBool bMakeCopy /* = TRUE */,
-                                             FILE *fpSrc /* = NULL */, 
+                                             VSILFILE *fpSrc /* = NULL */, 
                                              int nOffset /* = 0 */)
 {
     int nStatus;
@@ -197,7 +199,13 @@ int     TABMAPObjectBlock::InitBlockFromData(GByte *pabyBuf,
 
     m_nCurObjectOffset = -1;
     m_nCurObjectId = -1;
-    m_nCurObjectType = -1;
+    m_nCurObjectType = TAB_GEOM_UNSET;
+
+    m_nMinX = 1000000000;
+    m_nMinY = 1000000000;
+    m_nMaxX = -1000000000;
+    m_nMaxY = -1000000000;
+    m_bLockCenter = FALSE;
 
     /*-----------------------------------------------------------------
      * Set real value for m_nSizeUsed to allow random update
@@ -208,6 +216,48 @@ int     TABMAPObjectBlock::InitBlockFromData(GByte *pabyBuf,
     return 0;
 }
 
+/************************************************************************
+ *                       ClearObjects()
+ *
+ * Cleans existing objects from the block. This method is used when
+ * compacting a page that has deleted records.
+ ************************************************************************/
+void TABMAPObjectBlock::ClearObjects()
+{
+    GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
+    WriteZeros(m_nBlockSize - MAP_OBJECT_HEADER_SIZE);
+    GotoByteInBlock(MAP_OBJECT_HEADER_SIZE);
+    m_nSizeUsed = MAP_OBJECT_HEADER_SIZE;
+    m_bModified = TRUE;
+}
+
+/************************************************************************
+ *                         LockCenter()
+ *
+ * Prevents the m_nCenterX and m_nCenterY to be adjusted by other methods.
+ * Useful when editing pages that have compressed geometries.
+ * This is a bit band-aid. Proper support of compressed geometries should
+ * handle center moves.
+ ************************************************************************/
+void TABMAPObjectBlock::LockCenter()
+{
+    m_bLockCenter = TRUE;
+}
+
+/************************************************************************
+ *                       SetCenterFromOtherBlock()
+ *
+ * Sets the m_nCenterX and m_nCenterY from the one of another block and
+ * lock them. See LockCenter() as well.
+ * Used when splitting a page.
+ ************************************************************************/
+void TABMAPObjectBlock::SetCenterFromOtherBlock(TABMAPObjectBlock* poOtherObjBlock)
+{
+    m_nCenterX = poOtherObjBlock->m_nCenterX;
+    m_nCenterY = poOtherObjBlock->m_nCenterY;
+    LockCenter();
+}
+
 /************************************************************************/
 /*                        Rewind()                                      */
 /************************************************************************/
@@ -215,7 +265,7 @@ void TABMAPObjectBlock::Rewind( )
 {
     m_nCurObjectId = -1;
     m_nCurObjectOffset = -1;
-    m_nCurObjectType = -1;
+    m_nCurObjectType = TAB_GEOM_UNSET;
 }
 
 /************************************************************************/
@@ -239,16 +289,16 @@ int TABMAPObjectBlock::AdvanceToNextObject( TABMAPHeaderBlock *poHeader )
     if( m_nCurObjectOffset + 5 < m_numDataBytes + 20 )
     {
         GotoByteInBlock( m_nCurObjectOffset );
-        m_nCurObjectType = ReadByte();
+        m_nCurObjectType = (TABGeomType)ReadByte();
     }
     else
     {
-        m_nCurObjectType = -1;
+        m_nCurObjectType = TAB_GEOM_UNSET;
     }
 
-    if( m_nCurObjectType <= 0 || m_nCurObjectType >= 0x80 )
+    if( m_nCurObjectType <= 0 || m_nCurObjectType >= TAB_GEOM_MAX_TYPE )
     {
-        m_nCurObjectType = -1;
+        m_nCurObjectType = TAB_GEOM_UNSET;
         m_nCurObjectId = -1;
         m_nCurObjectOffset = -1;
     }
@@ -294,6 +344,12 @@ int     TABMAPObjectBlock::CommitToFile()
     }
 
     /*-----------------------------------------------------------------
+     * Nothing to do here if block has not been modified
+     *----------------------------------------------------------------*/
+    if (!m_bModified)
+        return 0;
+
+    /*-----------------------------------------------------------------
      * Make sure 20 bytes block header is up to date.
      *----------------------------------------------------------------*/
     GotoByteInBlock(0x000);
@@ -315,7 +371,12 @@ int     TABMAPObjectBlock::CommitToFile()
      * Call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting OBJECT block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+    }
 
     return nStatus;
 }
@@ -335,7 +396,7 @@ int     TABMAPObjectBlock::CommitToFile()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABMAPObjectBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABMAPObjectBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                         int nFileOffset /* = 0*/)
 {
     /*-----------------------------------------------------------------
@@ -357,14 +418,14 @@ int     TABMAPObjectBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
     // Reset current object refs
     m_nCurObjectId = -1;
     m_nCurObjectOffset = -1;
-    m_nCurObjectType = -1;
+    m_nCurObjectType = TAB_GEOM_UNSET;
 
     m_numDataBytes = 0;       /* Data size excluding header */
     m_nCenterX = m_nCenterY = 0;
     m_nFirstCoordBlock = 0;
     m_nLastCoordBlock = 0;
 
-    if (m_eAccess != TABRead)
+    if (m_eAccess != TABRead && nFileOffset != 0)
     {
         GotoByteInBlock(0x000);
 
@@ -502,8 +563,11 @@ int     TABMAPObjectBlock::UpdateMBR(GInt32 nX, GInt32 nY)
     if (nY > m_nMaxY)
         m_nMaxY = nY;
     
-    m_nCenterX = (m_nMinX + m_nMaxX) /2;
-    m_nCenterY = (m_nMinY + m_nMaxY) /2;
+    if( !m_bLockCenter )
+    {
+        m_nCenterX = (m_nMinX + m_nMaxX) /2;
+        m_nCenterY = (m_nMinY + m_nMaxY) /2;
+    }
     
     return 0;
 }
@@ -525,6 +589,7 @@ void     TABMAPObjectBlock::AddCoordBlockRef(GInt32 nNewBlockAddress)
         m_nFirstCoordBlock = nNewBlockAddress;
 
     m_nLastCoordBlock = nNewBlockAddress;
+    m_bModified = TRUE;
 }
 
 /**********************************************************************
@@ -540,8 +605,11 @@ void TABMAPObjectBlock::SetMBR(GInt32 nXMin, GInt32 nYMin,
     m_nMaxX = nXMax;
     m_nMaxY = nYMax; 
 
-    m_nCenterX = (m_nMinX + m_nMaxX) /2;
-    m_nCenterY = (m_nMinY + m_nMaxY) /2;
+    if( !m_bLockCenter )
+    {
+        m_nCenterX = (m_nMinX + m_nMaxX) /2;
+        m_nCenterY = (m_nMinY + m_nMaxY) /2;
+    }
 }
 
 /**********************************************************************
@@ -587,7 +655,15 @@ int     TABMAPObjectBlock::PrepareNewObject(TABMAPObjHdr *poObjHdr)
      * CommitNewObject()
      *----------------------------------------------------------------*/
     nStartAddress = GetFirstUnusedByteOffset();
+    
+    // Backup MBR and bLockCenter as they will be reset by GotoByteInFile()
+    // that will call InitBlockFromData()
+    GInt32 nXMin, nYMin, nXMax, nYMax;
+    GetMBR(nXMin, nYMin, nXMax, nYMax);
+    int bLockCenter = m_bLockCenter;
     GotoByteInFile(nStartAddress);
+    m_bLockCenter = bLockCenter;
+    SetMBR(nXMin, nYMin, nXMax, nYMax);
     m_nCurObjectOffset = nStartAddress - GetStartAddress();
 
     m_nCurObjectType = poObjHdr->m_nType;
@@ -716,7 +792,7 @@ void TABMAPObjectBlock::Dump(FILE *fpOut, GBool bDetails)
  * Alloc a new object of specified type or NULL for NONE types or if type 
  * is not supported.
  **********************************************************************/
-TABMAPObjHdr *TABMAPObjHdr::NewObj(GByte nNewObjType, GInt32 nId /*=0*/)
+TABMAPObjHdr *TABMAPObjHdr::NewObj(TABGeomType nNewObjType, GInt32 nId /*=0*/)
 {
     TABMAPObjHdr *poObj = NULL;
 
@@ -816,7 +892,7 @@ TABMAPObjHdr *TABMAPObjHdr::ReadNextObj(TABMAPObjectBlock *poObjBlock,
 
     if (poObjBlock->AdvanceToNextObject(poHeader) != -1)
     {
-        poObjHdr=TABMAPObjHdr::NewObj((GByte)poObjBlock->GetCurObjectType());
+        poObjHdr=TABMAPObjHdr::NewObj(poObjBlock->GetCurObjectType());
         if (poObjHdr &&
             ((poObjHdr->m_nId = poObjBlock->GetCurObjectId()) == -1 ||
              poObjHdr->ReadObj(poObjBlock) != 0 ) )
@@ -852,7 +928,7 @@ GBool TABMAPObjHdr::IsCompressedType()
  **********************************************************************/
 int TABMAPObjHdr::WriteObjTypeAndId(TABMAPObjectBlock *poObjBlock)
 {
-    poObjBlock->WriteByte(m_nType);
+    poObjBlock->WriteByte((GByte)m_nType);
     return poObjBlock->WriteInt32(m_nId);
 }
 
@@ -932,7 +1008,7 @@ int TABMAPObjLine::WriteObj(TABMAPObjectBlock *poObjBlock)
 /**********************************************************************
  *                   TABMAPObjPLine::ReadObj()
  *
- * Read Object information starting after the object id which should 
+ * Read Object information starting after the object id which should
  * have been read by TABMAPObjHdr::ReadNextObj() already.
  * This function should be called only by TABMAPObjHdr::ReadNextObj().
  *
diff --git a/ogr/ogrsf_frmts/mitab/mitab_maptoolblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_maptoolblock.cpp
index ce7237e..700cae2 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_maptoolblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_maptoolblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -123,7 +124,7 @@ GBool TABMAPToolBlock::EndOfChain()
 int     TABMAPToolBlock::InitBlockFromData(GByte *pabyBuf,
                                            int nBlockSize, int nSizeUsed, 
                                            GBool bMakeCopy /* = TRUE */,
-                                           FILE *fpSrc /* = NULL */, 
+                                           VSILFILE *fpSrc /* = NULL */, 
                                            int nOffset /* = 0 */)
 {
     int nStatus;
@@ -190,6 +191,12 @@ int     TABMAPToolBlock::CommitToFile()
     }
 
     /*-----------------------------------------------------------------
+     * Nothing to do here if block has not been modified
+     *----------------------------------------------------------------*/
+    if (!m_bModified)
+        return 0;
+
+    /*-----------------------------------------------------------------
      * Make sure 8 bytes block header is up to date.
      *----------------------------------------------------------------*/
     GotoByteInBlock(0x000);
@@ -204,7 +211,12 @@ int     TABMAPToolBlock::CommitToFile()
      * OK, call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting TOOL block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+    }
 
     return nStatus;
 }
@@ -224,9 +236,13 @@ int     TABMAPToolBlock::CommitToFile()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABMAPToolBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABMAPToolBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                         int nFileOffset /* = 0*/)
 {
+#ifdef DEBUG_VERBOSE
+    CPLDebug("MITAB", "Instanciating new TOOL block at offset %d", nFileOffset);
+#endif
+
     /*-----------------------------------------------------------------
      * Start with the default initialisation
      *----------------------------------------------------------------*/
@@ -342,7 +358,7 @@ int  TABMAPToolBlock::WriteBytes(int nBytesToWrite, GByte *pabySrcBuf)
     if (m_eAccess == TABWrite && m_poBlockManagerRef &&
         (m_nBlockSize - m_nCurPos) < nBytesToWrite)
     {
-        int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock();
+        int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock("TOOL");
         SetNextToolBlock(nNewBlockOffset);
 
         if (CommitToFile() != 0 ||
@@ -392,7 +408,7 @@ int  TABMAPToolBlock::CheckAvailableSpace(int nToolType)
 
     if (GetNumUnusedBytes() < nBytesToWrite)
     {
-        int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock();
+        int nNewBlockOffset = m_poBlockManagerRef->AllocNewBlock("TOOL");
         SetNextToolBlock(nNewBlockOffset);
 
         if (CommitToFile() != 0 ||
@@ -430,7 +446,7 @@ void TABMAPToolBlock::Dump(FILE *fpOut /*=NULL*/)
     }
     else
     {
-        fprintf(fpOut,"Coordinate Block (type %d) at offset %d.\n", 
+        fprintf(fpOut,"Tool Block (type %d) at offset %d.\n", 
                                                  m_nBlockType, m_nFileOffset);
         fprintf(fpOut,"  m_numDataBytes        = %d\n", m_numDataBytes);
         fprintf(fpOut,"  m_nNextToolBlock     = %d\n", m_nNextToolBlock);
diff --git a/ogr/ogrsf_frmts/mitab/mitab_middatafile.cpp b/ogr/ogrsf_frmts/mitab/mitab_middatafile.cpp
index 5b27474..5aaae34 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_middatafile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_middatafile.cpp
@@ -152,7 +152,7 @@ int MIDDATAFile::Open(const char *pszFname, const char *pszAccess)
      * Open file for reading
      *----------------------------------------------------------------*/
     m_pszFname = CPLStrdup(pszFname);
-    m_fp = VSIFOpen(m_pszFname, pszAccess);
+    m_fp = VSIFOpenL(m_pszFname, pszAccess);
 
     if (m_fp == NULL)
     {
@@ -161,7 +161,7 @@ int MIDDATAFile::Open(const char *pszFname, const char *pszAccess)
         return -1;
     }
 
-    SetEof(VSIFEof(m_fp));
+    SetEof(FALSE);
     return 0;
 }
 
@@ -172,8 +172,8 @@ int MIDDATAFile::Rewind()
 
     else
     {
-        VSIRewind(m_fp);
-        SetEof(VSIFEof(m_fp));
+        VSIRewindL(m_fp);
+        SetEof(FALSE);
     }
     return 0;
 }
@@ -184,11 +184,11 @@ int MIDDATAFile::Close()
         return 0;
    
     // Close file
-    VSIFClose(m_fp);
+    VSIFCloseL(m_fp);
     m_fp = NULL;
 
     // clear readline buffer.
-    CPLReadLine( NULL );
+    CPLReadLineL( NULL );
 
     CPLFree(m_pszFname);
     m_pszFname = NULL;
@@ -204,12 +204,11 @@ const char *MIDDATAFile::GetLine()
     if (m_eAccessMode == TABRead)
     {
         
-        pszLine = CPLReadLine(m_fp);
-
-        SetEof(VSIFEof(m_fp));
+        pszLine = CPLReadLineL(m_fp);
 
         if (pszLine == NULL)
         {
+            SetEof(TRUE);
             m_szLastRead[0] = '\0';
         }
         else
@@ -256,7 +255,9 @@ void MIDDATAFile::WriteLine(const char *pszFormat,...)
     if (m_eAccessMode == TABWrite  && m_fp)
     {
         va_start(args, pszFormat);
-         vfprintf( m_fp, pszFormat, args );
+        CPLString osStr;
+        osStr.vPrintf( pszFormat, args );
+        VSIFWriteL( osStr.c_str(), 1, osStr.size(), m_fp);
         va_end(args);
     } 
     else
diff --git a/ogr/ogrsf_frmts/mitab/mitab_miffile.cpp b/ogr/ogrsf_frmts/mitab/mitab_miffile.cpp
index 287f918..813e7ee 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_miffile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_miffile.cpp
@@ -12,6 +12,7 @@
  **********************************************************************
  * Copyright (c) 1999-2003, Stephane Villeneuve
  * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -263,7 +264,7 @@ MIFFile::~MIFFile()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int MIFFile::Open(const char *pszFname, const char *pszAccess,
+int MIFFile::Open(const char *pszFname, TABAccess eAccess,
                   GBool bTestOpenNoError /*=FALSE*/ )
 {
     char *pszTmpFname = NULL;
@@ -282,12 +283,13 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Validate access mode
      *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
+    const char* pszAccess = NULL;
+    if (eAccess == TABRead)
     {
         m_eAccessMode = TABRead;
         pszAccess = "rt";
     }
-    else if (EQUALN(pszAccess, "w", 1))
+    else if (eAccess == TABWrite)
     {
         m_eAccessMode = TABWrite;
         pszAccess = "wt";
@@ -300,7 +302,7 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
     {
         if (!bTestOpenNoError)
             CPLError(CE_Failure, CPLE_FileIO,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+                 "Open() failed: access mode \"%d\" not supported", eAccess);
         else
             CPLErrorReset();
 
@@ -364,7 +366,8 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Read MIF File Header
      *----------------------------------------------------------------*/
-    if (m_eAccessMode == TABRead && ParseMIFHeader() != 0)
+    int bIsEmpty = FALSE;
+    if (m_eAccessMode == TABRead && ParseMIFHeader(&bIsEmpty) != 0)
     {
         Close();
 
@@ -397,16 +400,27 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
 
         if (m_poMIDFile->Open(pszTmpFname, pszAccess) !=0)
         {
-            if (!bTestOpenNoError)
-                CPLError(CE_Failure, CPLE_NotSupported,
-                        "Unable to open %s.", pszTmpFname);
-            else
-                CPLErrorReset();
+            if (m_eAccessMode == TABWrite)
+            {
+                if (!bTestOpenNoError)
+                    CPLError(CE_Failure, CPLE_NotSupported,
+                            "Unable to open %s.", pszTmpFname);
+                else
+                    CPLErrorReset();
 
-            CPLFree(pszTmpFname);
-            Close();
+                CPLFree(pszTmpFname);
+                Close();
 
-            return -1;
+                return -1;
+            }
+            else
+            {
+                CPLDebug("MITAB",
+                         "%s is not found, although %d attributes are declared",
+                         pszTmpFname, m_nAttribut);
+                delete m_poMIDFile;
+                m_poMIDFile = NULL;
+            }
         }
     }
 
@@ -423,7 +437,7 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
     }
 
     /* Put the MID file at the correct location, on the first feature */
-    if (m_eAccessMode == TABRead && (m_poMIDFile != NULL && m_poMIDFile->GetLine() == NULL))
+    if (m_eAccessMode == TABRead && (m_poMIDFile != NULL && !bIsEmpty && m_poMIDFile->GetLine() == NULL))
     {
         Close();
 
@@ -485,7 +499,7 @@ int MIFFile::Open(const char *pszFname, const char *pszAccess,
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int MIFFile::ParseMIFHeader()
+int MIFFile::ParseMIFHeader(int* pbIsEmpty)
 {  
     GBool  bColumns = FALSE, bAllColumnsRead =  FALSE;
     int    nColumns = 0;
@@ -495,6 +509,8 @@ int MIFFile::ParseMIFHeader()
     
     const char *pszLine;
     char **papszToken;
+    
+    *pbIsEmpty = FALSE;
 
     char *pszFeatureClassName = TABGetBasename(m_pszFname);
     m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
@@ -593,10 +609,10 @@ int MIFFile::ParseMIFHeader()
             int iBounds = CSLFindString( papszFields, "Bounds" );
             if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
             {
-                m_dXMin = atof(papszFields[++iBounds]);
-                m_dYMin = atof(papszFields[++iBounds]);
-                m_dXMax = atof(papszFields[++iBounds]);
-                m_dYMax = atof(papszFields[++iBounds]);
+                m_dXMin = CPLAtof(papszFields[++iBounds]);
+                m_dYMin = CPLAtof(papszFields[++iBounds]);
+                m_dXMax = CPLAtof(papszFields[++iBounds]);
+                m_dYMax = CPLAtof(papszFields[++iBounds]);
                 m_bBoundsSet = TRUE;
             }
             CSLDestroy( papszFields );
@@ -608,10 +624,10 @@ int MIFFile::ParseMIFHeader()
           
             if (CSLCount(papszToken) == 5)
             {
-                m_dfXMultiplier   = atof(papszToken[1]);
-                m_dfYMultiplier   = atof(papszToken[2]);
-                m_dfXDisplacement = atof(papszToken[3]);
-                m_dfYDisplacement = atof(papszToken[4]);
+                m_dfXMultiplier   = CPLAtof(papszToken[1]);
+                m_dfYMultiplier   = CPLAtof(papszToken[2]);
+                m_dfXDisplacement = CPLAtof(papszToken[3]);
+                m_dfYDisplacement = CPLAtof(papszToken[4]);
                 
                 if (m_dfXMultiplier == 0.0)
                   m_dfXMultiplier = 1.0;
@@ -678,6 +694,8 @@ int MIFFile::ParseMIFHeader()
     while (((pszLine = m_poMIFFile->GetLine()) != NULL) && 
            m_poMIFFile->IsValidFeature(pszLine) == FALSE)
         ;
+    
+    *pbIsEmpty = (pszLine == NULL);
 
     /*-----------------------------------------------------------------
      * Check for Unique and Indexed flags
@@ -829,7 +847,7 @@ int  MIFFile::AddFields(const char *pszLine)
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int MIFFile::GetFeatureCount (int bForce)
+GIntBig MIFFile::GetFeatureCount (int bForce)
 {
     
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
@@ -924,8 +942,8 @@ void MIFFile::PreParseFile()
             m_nPoints++;
             if (CSLCount(papszToken) == 3)
             {
-                UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])),
-                             m_poMIFFile->GetYTrans(atof(papszToken[2])));
+                UpdateExtents(m_poMIFFile->GetXTrans(CPLAtof(papszToken[1])),
+                             m_poMIFFile->GetYTrans(CPLAtof(papszToken[2])));
             }
               
         }
@@ -938,10 +956,10 @@ void MIFFile::PreParseFile()
             if (CSLCount(papszToken) == 5)
             {
                 m_nLines++;
-                UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[1])), 
-                             m_poMIFFile->GetYTrans(atof(papszToken[2])));
-                UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[3])), 
-                             m_poMIFFile->GetYTrans(atof(papszToken[4])));
+                UpdateExtents(m_poMIFFile->GetXTrans(CPLAtof(papszToken[1])), 
+                             m_poMIFFile->GetYTrans(CPLAtof(papszToken[2])));
+                UpdateExtents(m_poMIFFile->GetXTrans(CPLAtof(papszToken[3])), 
+                             m_poMIFFile->GetYTrans(CPLAtof(papszToken[4])));
             }
         }
         else if (EQUALN(pszLine,"REGION",6) )
@@ -964,8 +982,8 @@ void MIFFile::PreParseFile()
             if (CSLCount(papszToken) == 2 &&
                 strchr("-.0123456789", papszToken[0][0]) != NULL)
             {
-                UpdateExtents( m_poMIFFile->GetXTrans(atof(papszToken[0])),
-                              m_poMIFFile->GetYTrans(atof(papszToken[1])));
+                UpdateExtents( m_poMIFFile->GetXTrans(CPLAtof(papszToken[0])),
+                              m_poMIFFile->GetYTrans(CPLAtof(papszToken[1])));
             }
         }
         else if (bText == TRUE)
@@ -973,10 +991,10 @@ void MIFFile::PreParseFile()
            if (CSLCount(papszToken) == 4 &&
                 strchr("-.0123456789", papszToken[0][0]) != NULL)
             {
-                UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[0])),
-                             m_poMIFFile->GetYTrans(atof(papszToken[1])));
-                UpdateExtents(m_poMIFFile->GetXTrans(atof(papszToken[2])),
-                             m_poMIFFile->GetYTrans(atof(papszToken[3])));
+                UpdateExtents(m_poMIFFile->GetXTrans(CPLAtof(papszToken[0])),
+                             m_poMIFFile->GetYTrans(CPLAtof(papszToken[1])));
+                UpdateExtents(m_poMIFFile->GetXTrans(CPLAtof(papszToken[2])),
+                             m_poMIFFile->GetYTrans(CPLAtof(papszToken[3])));
             } 
         }
         
@@ -1238,7 +1256,7 @@ int MIFFile::Close()
  * Returns feature id that follows nPrevId, or -1 if it is the
  * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
  **********************************************************************/
-int MIFFile::GetNextFeatureId(int nPrevId)
+GIntBig MIFFile::GetNextFeatureId(GIntBig nPrevId)
 {
     if (m_eAccessMode != TABRead)
     {
@@ -1324,7 +1342,7 @@ GBool MIFFile::NextFeature()
  * error happened.  In any case, CPLError() will have been called to
  * report the reason of the failure.
  **********************************************************************/
-TABFeature *MIFFile::GetFeatureRef(int nFeatureId)
+TABFeature *MIFFile::GetFeatureRef(GIntBig nFeatureId)
 {
     const char *pszLine;
 
@@ -1346,10 +1364,10 @@ TABFeature *MIFFile::GetFeatureRef(int nFeatureId)
         return NULL;
     }
 
-    if (GotoFeature(nFeatureId)!= 0 )
+    if ( (GIntBig)(int)nFeatureId != nFeatureId || GotoFeature((int)nFeatureId)!= 0 )
     {
         CPLError(CE_Failure, CPLE_IllegalArg,
-                 "GetFeatureRef() failed: invalid feature id %d", 
+                 "GetFeatureRef() failed: invalid feature id " CPL_FRMT_GIB, 
                  nFeatureId);
         return NULL;
     }
@@ -2022,7 +2040,12 @@ int MIFFile::SetSpatialRef( OGRSpatialReference * poSpatialRef )
 {
     CPLFree( m_pszCoordSys );
 
-    m_pszCoordSys = MITABSpatialRef2CoordSys( poSpatialRef );
+    char* pszCoordSys = MITABSpatialRef2CoordSys( poSpatialRef );
+    if( pszCoordSys )
+    {
+        SetMIFCoordSys(pszCoordSys);
+        CPLFree(pszCoordSys);
+    }
 
     return( m_pszCoordSys != NULL );
 }
@@ -2054,13 +2077,16 @@ int MIFFile::SetMIFCoordSys(const char * pszMIFCoordSys)
     iBounds = CSLFindString( papszFields, "Bounds" );
     if (iBounds >= 0 && iBounds + 4 < CSLCount(papszFields))
     {
-        m_dXMin = atof(papszFields[++iBounds]);
-        m_dYMin = atof(papszFields[++iBounds]);
-        m_dXMax = atof(papszFields[++iBounds]);
-        m_dYMax = atof(papszFields[++iBounds]);
+        m_dXMin = CPLAtof(papszFields[++iBounds]);
+        m_dYMin = CPLAtof(papszFields[++iBounds]);
+        m_dXMax = CPLAtof(papszFields[++iBounds]);
+        m_dYMax = CPLAtof(papszFields[++iBounds]);
         m_bBoundsSet = TRUE;
 
-        pszCoordSys[strstr(pszCoordSys, "Bounds") - pszCoordSys] = '\0';
+        char* pszBounds = strstr(pszCoordSys, " Bounds");
+        if( pszBounds == NULL )
+            pszBounds = strstr(pszCoordSys, "Bounds");
+        pszCoordSys[pszBounds - pszCoordSys] = '\0';
     }
     CSLDestroy( papszFields );
 
diff --git a/ogr/ogrsf_frmts/mitab/mitab_ogr_datasource.cpp b/ogr/ogrsf_frmts/mitab/mitab_ogr_datasource.cpp
index b5488a1..e60f193 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_ogr_datasource.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_ogr_datasource.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Stephane Villeneuve
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -41,7 +42,7 @@
  * fixed CPLReadDir memory leak
  *
  * Revision 1.9  2004/10/15 01:52:30  fwarmerdam
- * Modified CreateLayer() to use  -1000,-1000,1000,1000 bounds for GEOGCS
+ * ModifiedICreateLayer() to use  -1000,-1000,1000,1000 bounds for GEOGCS
  * much like in mitab_bounds.cpp.  This ensures that geographic files in
  * the range 0-360 works as well as -180 to 180.
  *
@@ -60,7 +61,7 @@
  * added support for FORMAT=MIF option for creating layers
  *
  * Revision 1.4  2001/02/06 22:13:54  warmerda
- * fixed memory leak in OGRTABDataSource::CreateLayer()
+ * fixed memory leak in OGRTABDataSource::ICreateLayer()
  *
  * Revision 1.3  2001/01/22 16:03:58  warmerda
  * expanded tabs
@@ -99,7 +100,8 @@ OGRTABDataSource::OGRTABDataSource()
     m_bCreateMIF = FALSE;
     m_bSingleFile = FALSE;
     m_bSingleLayerAlreadyCreated = FALSE;
-    m_bQuickSpatialIndexMode = FALSE;
+    m_bQuickSpatialIndexMode = -1;
+    m_bUpdate = FALSE;
 }
 
 /************************************************************************/
@@ -128,13 +130,14 @@ OGRTABDataSource::~OGRTABDataSource()
 int OGRTABDataSource::Create( const char * pszName, char **papszOptions )
 
 {
-    VSIStatBuf  sStat;
+    VSIStatBufL  sStat;
     const char *pszOpt;
 
     CPLAssert( m_pszName == NULL );
     
     m_pszName = CPLStrdup( pszName );
     m_papszOptions = CSLDuplicate( papszOptions );
+    m_bUpdate = TRUE;
 
     if( (pszOpt=CSLFetchNameValue(papszOptions,"FORMAT")) != NULL 
         && EQUAL(pszOpt, "MIF") )
@@ -143,16 +146,20 @@ int OGRTABDataSource::Create( const char * pszName, char **papszOptions )
              || EQUAL(CPLGetExtension(pszName),"mid") )
         m_bCreateMIF = TRUE;
 
-    if( (pszOpt=CSLFetchNameValue(papszOptions,"SPATIAL_INDEX_MODE")) != NULL 
-        && EQUAL(pszOpt, "QUICK") )
-        m_bQuickSpatialIndexMode = TRUE;
+    if( (pszOpt=CSLFetchNameValue(papszOptions,"SPATIAL_INDEX_MODE")) != NULL )
+    {
+        if ( EQUAL(pszOpt, "QUICK") )
+            m_bQuickSpatialIndexMode = TRUE;
+        else if ( EQUAL(pszOpt, "OPTIMIZED") )
+            m_bQuickSpatialIndexMode = FALSE;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Create a new empty directory.                                   */
 /* -------------------------------------------------------------------- */
     if( strlen(CPLGetExtension(pszName)) == 0 )
     {
-        if( VSIStat( pszName, &sStat ) == 0 )
+        if( VSIStatL( pszName, &sStat ) == 0 )
         {
             if( !VSI_ISDIR(sStat.st_mode) )
             {
@@ -189,7 +196,7 @@ int OGRTABDataSource::Create( const char * pszName, char **papszOptions )
         else
             poFile = new TABFile;
 
-        if( poFile->Open( pszName, "wb", FALSE ) != 0 )
+        if( poFile->Open( m_pszName, TABWrite, FALSE ) != 0 )
         {
             delete poFile;
             return FALSE;
@@ -212,48 +219,35 @@ int OGRTABDataSource::Create( const char * pszName, char **papszOptions )
 /*      Open an existing file, or directory of files.                   */
 /************************************************************************/
 
-int OGRTABDataSource::Open( const char * pszName, int bTestOpen )
+int OGRTABDataSource::Open( GDALOpenInfo* poOpenInfo, int bTestOpen )
 
 {
-    VSIStatBuf  stat;
-
     CPLAssert( m_pszName == NULL );
-    
-    m_pszName = CPLStrdup( pszName );
-
-/* -------------------------------------------------------------------- */
-/*      Is this a file or directory?                                    */
-/* -------------------------------------------------------------------- */
-    if( VSIStat( pszName, &stat ) != 0 
-        || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
-    {
-        if( !bTestOpen )
-        {
-            CPLError( CE_Failure, CPLE_OpenFailed,
-                      "%s is not a file or directory.\n"
-                      "Unable to open as a Mapinfo dataset.\n",
-                      pszName );
-        }
 
-        return FALSE;
-    }
+    m_pszName = CPLStrdup( poOpenInfo->pszFilename );
+    m_bUpdate = (poOpenInfo->eAccess == GA_Update );
 
 /* -------------------------------------------------------------------- */
 /*      If it is a file, try to open as a Mapinfo file.                 */
 /* -------------------------------------------------------------------- */
-    if( VSI_ISREG(stat.st_mode) )
+    if( !poOpenInfo->bIsDirectory )
     {
         IMapInfoFile    *poFile;
 
-        poFile = IMapInfoFile::SmartOpen( pszName, bTestOpen );
+        poFile = IMapInfoFile::SmartOpen( m_pszName, m_bUpdate, bTestOpen );
         if( poFile == NULL )
             return FALSE;
 
+        poFile->SetDescription( poFile->GetName() );
+
         m_nLayerCount = 1;
         m_papoLayers = (IMapInfoFile **) CPLMalloc(sizeof(void*));
         m_papoLayers[0] = poFile;
 
-        m_pszDirectory = CPLStrdup( CPLGetPath(pszName) );
+        m_pszDirectory = CPLStrdup( CPLGetPath(m_pszName) );
+
+        m_bSingleFile = TRUE;
+        m_bSingleLayerAlreadyCreated = TRUE;
     }
 
 /* -------------------------------------------------------------------- */
@@ -262,9 +256,9 @@ int OGRTABDataSource::Open( const char * pszName, int bTestOpen )
 /* -------------------------------------------------------------------- */
     else
     {
-        char    **papszFileList = CPLReadDir( pszName );
+        char    **papszFileList = CPLReadDir( m_pszName );
         
-        m_pszDirectory = CPLStrdup( pszName );
+        m_pszDirectory = CPLStrdup( m_pszName );
 
         for( int iFile = 0;
              papszFileList != NULL && papszFileList[iFile] != NULL;
@@ -280,7 +274,7 @@ int OGRTABDataSource::Open( const char * pszName, int bTestOpen )
             pszSubFilename = CPLStrdup(
                 CPLFormFilename( m_pszDirectory, papszFileList[iFile], NULL ));
 
-            poFile = IMapInfoFile::SmartOpen( pszSubFilename, bTestOpen );
+            poFile = IMapInfoFile::SmartOpen( pszSubFilename, m_bUpdate, bTestOpen );
             CPLFree( pszSubFilename );
             
             if( poFile == NULL )
@@ -288,6 +282,7 @@ int OGRTABDataSource::Open( const char * pszName, int bTestOpen )
                 CSLDestroy( papszFileList );
                 return FALSE;
             }
+            poFile->SetDescription( poFile->GetName() );
 
             m_nLayerCount++;
             m_papoLayers = (IMapInfoFile **)
@@ -338,18 +333,26 @@ OGRLayer *OGRTABDataSource::GetLayer( int iLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRTABDataSource::CreateLayer( const char * pszLayerName,
+OGRTABDataSource::ICreateLayer( const char * pszLayerName,
                                OGRSpatialReference *poSRSIn,
                                OGRwkbGeometryType /* eGeomTypeIn */,
-                               char ** /* papszOptions */ )
+                               char ** papszOptions )
 
 {
     IMapInfoFile        *poFile;
     char                *pszFullFilename;
+    const char          *pszOpt = NULL;
+
+    if( !m_bUpdate )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                    "Cannot create layer on read-only dataset.");
+        return NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      If it's a single file mode file, then we may have already       */
@@ -370,9 +373,6 @@ OGRTABDataSource::CreateLayer( const char * pszLayerName,
         poFile = (IMapInfoFile *) m_papoLayers[0];
     }
 
-/* -------------------------------------------------------------------- */
-/*      We need to initially create the file, and add it as a layer.    */
-/* -------------------------------------------------------------------- */
     else
     {
         if( m_bCreateMIF )
@@ -390,7 +390,7 @@ OGRTABDataSource::CreateLayer( const char * pszLayerName,
             poFile = new TABFile;
         }
         
-        if( poFile->Open( pszFullFilename, "wb", FALSE ) != 0 )
+        if( poFile->Open( pszFullFilename, TABWrite, FALSE ) != 0 )
         {
             CPLFree( pszFullFilename );
             delete poFile;
@@ -405,12 +405,35 @@ OGRTABDataSource::CreateLayer( const char * pszLayerName,
         CPLFree( pszFullFilename );
     }
 
+    poFile->SetDescription( poFile->GetName() );
+
 /* -------------------------------------------------------------------- */
 /*      Assign the coordinate system (if provided) and set              */
 /*      reasonable bounds.                                              */
 /* -------------------------------------------------------------------- */
     if( poSRSIn != NULL )
+    {
         poFile->SetSpatialRef( poSRSIn );
+        // SetSpatialRef() has cloned the passed geometry
+        poFile->GetLayerDefn()->GetGeomFieldDefn(0)->SetSpatialRef(poFile->GetSpatialRef());
+    }
+
+    // Pull out the bounds if supplied
+    if( (pszOpt=CSLFetchNameValue(papszOptions, "BOUNDS")) != NULL ) {
+        double dfBounds[4];
+        if( CPLsscanf(pszOpt, "%lf,%lf,%lf,%lf", &dfBounds[0], 
+                                          &dfBounds[1], 
+                                          &dfBounds[2], 
+                                          &dfBounds[3]) != 4 )
+        {
+            CPLError( CE_Failure, CPLE_IllegalArg,
+                        "Invalid BOUNDS parameter, expected min_x,min_y,max_x,max_y\n" );
+        }
+        else
+        {
+            poFile->SetBounds( dfBounds[0], dfBounds[1], dfBounds[2], dfBounds[3] );
+        }
+    }
 
     if( !poFile->IsBoundsSet() && !m_bCreateMIF )
     {
@@ -421,11 +444,16 @@ OGRTABDataSource::CreateLayer( const char * pszLayerName,
             poFile->SetBounds( -30000000, -15000000, 30000000, 15000000 );
     }
 
-    if (m_bQuickSpatialIndexMode && poFile->SetQuickSpatialIndexMode() != 0)
+    if (m_bQuickSpatialIndexMode == TRUE && poFile->SetQuickSpatialIndexMode(TRUE) != 0)
     {
         CPLError( CE_Warning, CPLE_AppDefined, 
                   "Setting Quick Spatial Index Mode failed.");
     }
+    else if (m_bQuickSpatialIndexMode == FALSE && poFile->SetQuickSpatialIndexMode(FALSE) != 0)
+    {
+        CPLError( CE_Warning, CPLE_AppDefined, 
+                  "Setting Normal Spatial Index Mode failed.");
+    }
 
     return poFile;
 }
@@ -438,8 +466,73 @@ int OGRTABDataSource::TestCapability( const char * pszCap )
 
 {
     if( EQUAL(pszCap,ODsCCreateLayer) )
-        return !m_bSingleFile || !m_bSingleLayerAlreadyCreated;
+        return m_bUpdate && (!m_bSingleFile || !m_bSingleLayerAlreadyCreated);
     else
         return FALSE;
 }
 
+/************************************************************************/
+/*                            GetFileList()                             */
+/************************************************************************/
+
+char **OGRTABDataSource::GetFileList()
+{
+    VSIStatBufL sStatBuf;
+    CPLStringList osList;
+
+    VSIStatL( m_pszName, &sStatBuf );
+    if( VSI_ISDIR(sStatBuf.st_mode) )
+    {
+        static const char *apszExtensions[] = 
+            { "mif", "mid", "tab", "map", "ind", "dat", "id", NULL };
+        char **papszDirEntries = CPLReadDir( m_pszName );
+        int  iFile;
+
+        for( iFile = 0; 
+             papszDirEntries != NULL && papszDirEntries[iFile] != NULL;
+             iFile++ )
+        {
+            if( CSLFindString( (char **) apszExtensions, 
+                               CPLGetExtension(papszDirEntries[iFile])) != -1)
+            {
+                osList.AddString( CPLFormFilename( m_pszName, 
+                                            papszDirEntries[iFile], 
+                                            NULL ) );
+            }
+        }
+
+        CSLDestroy( papszDirEntries );
+    }
+    else
+    {
+        static const char* apszMIFExtensions[] = { "mif", "mid", NULL };
+        static const char* apszTABExtensions[] = { "tab", "map", "ind", "dat", "id", NULL };
+        const char** papszExtensions;
+        if( EQUAL(CPLGetExtension(m_pszName), "mif") ||
+            EQUAL(CPLGetExtension(m_pszName), "mid") )
+        {
+            papszExtensions = apszMIFExtensions;
+        }
+        else
+        {
+            papszExtensions = apszTABExtensions;
+        }
+        const char** papszIter = papszExtensions;
+        while( *papszIter )
+        {
+            const char *pszFile = CPLResetExtension(m_pszName, *papszIter );
+            if( VSIStatL( pszFile, &sStatBuf ) != 0)
+            {
+                pszFile = CPLResetExtension(m_pszName, CPLString(*papszIter).toupper() );
+                if( VSIStatL( pszFile, &sStatBuf ) != 0)
+                {
+                    pszFile = NULL;
+                }
+            }
+            if( pszFile )
+                osList.AddString( pszFile );
+            papszIter ++;
+        }
+    }
+    return osList.StealList();
+}
diff --git a/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp b/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp
index 9b452f1..5565fcf 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Stephane Villeneuve
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -75,41 +76,63 @@
 
 
 /************************************************************************/
-/*                           ~OGRTABDriver()                            */
+/*                  OGRTABDriverIdentify()                              */
 /************************************************************************/
 
-OGRTABDriver::~OGRTABDriver()
+static int OGRTABDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-}
-
-/************************************************************************/
-/*                OGRTABDriver::GetName()                               */
-/************************************************************************/
-
-const char *OGRTABDriver::GetName()
-
-{
-    return "MapInfo File";
+    /* Files not ending with .tab, .mif or .mid are not handled by this driver */
+    if( !poOpenInfo->bStatOK )
+        return FALSE;
+    if( poOpenInfo->bIsDirectory )
+        return -1; /* unsure */
+    if( poOpenInfo->fpL == NULL )
+        return FALSE;
+    if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
+        EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID") )
+    {
+        return TRUE;
+    }
+    if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "TAB") )
+    {
+        for( int i = 0; i < poOpenInfo->nHeaderBytes; i++)
+        {
+            const char* pszLine = (const char*)poOpenInfo->pabyHeader + i;
+            if (EQUALN(pszLine, "Fields", 6))
+                return TRUE;
+            else if (EQUALN(pszLine, "create view", 11))
+                return TRUE;
+            else if (EQUALN(pszLine, "\"\\IsSeamless\" = \"TRUE\"", 21))
+                return TRUE;
+        }
+    }
+    return FALSE;
 }
 
 /************************************************************************/
 /*                  OGRTABDriver::Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRTABDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRTABDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRTABDataSource    *poDS;
-    
-    if( bUpdate )
+
+    if( OGRTABDriverIdentify(poOpenInfo) == FALSE )
     {
         return NULL;
     }
 
+    if (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MIF") ||
+        EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "MID") )
+    {
+        if( poOpenInfo->eAccess == GA_Update )
+            return NULL;
+    }
+
     poDS = new OGRTABDataSource();
-    if( poDS->Open( pszFilename, TRUE ) )
+    if( poDS->Open( poOpenInfo, TRUE ) )
         return poDS;
     else
     {
@@ -120,12 +143,15 @@ OGRDataSource *OGRTABDriver::Open( const char * pszFilename,
 
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                              Create()                                */
 /************************************************************************/
 
-OGRDataSource *OGRTABDriver::CreateDataSource( const char * pszName,
-                                               char ** papszOptions )
-
+static GDALDataset *OGRTABDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        char **papszOptions )
 {
     OGRTABDataSource *poDS;
 
@@ -143,78 +169,49 @@ OGRDataSource *OGRTABDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                              Delete()                                */
 /************************************************************************/
 
-int OGRTABDriver::TestCapability( const char * pszCap )
+static CPLErr OGRTABDriverDelete( const char *pszDataSource )
 
 {
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                          DeleteDataSource()                          */
-/************************************************************************/
-
-OGRErr OGRTABDriver::DeleteDataSource( const char *pszDataSource )
-
-{
-    int iExt;
-    VSIStatBuf sStatBuf;
-    static const char *apszExtensions[] = 
-        { "mif", "mid", "tab", "map", "ind", "dat", "id", NULL };
-
-    if( VSIStat( pszDataSource, &sStatBuf ) != 0 )
+    GDALDataset* poDS;
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s does not appear to be a file or directory.",
-                  pszDataSource );
-
-        return OGRERR_FAILURE;
+        // Make sure that the file opened by GDALOpenInfo is closed
+        // when the object goes out of scope
+        GDALOpenInfo oOpenInfo(pszDataSource, GA_ReadOnly);
+        poDS = OGRTABDriverOpen(&oOpenInfo);
     }
+    if( poDS == NULL )
+        return CE_Failure;
+    char** papszFileList = poDS->GetFileList();
+    delete poDS;
 
-    if( VSI_ISREG(sStatBuf.st_mode) 
-        && (EQUAL(CPLGetExtension(pszDataSource),"mif")
-            || EQUAL(CPLGetExtension(pszDataSource),"mid")
-            || EQUAL(CPLGetExtension(pszDataSource),"tab")) )
+    char** papszIter = papszFileList;
+    while( papszIter && *papszIter )
     {
-        for( iExt=0; apszExtensions[iExt] != NULL; iExt++ )
-        {
-            const char *pszFile = CPLResetExtension(pszDataSource,
-                                                    apszExtensions[iExt] );
-            if( VSIStat( pszFile, &sStatBuf ) == 0 )
-                VSIUnlink( pszFile );
-        }
+        VSIUnlink( *papszIter );
+        papszIter ++;
     }
-    else if( VSI_ISDIR(sStatBuf.st_mode) )
-    {
-        char **papszDirEntries = CPLReadDir( pszDataSource );
-        int  iFile;
-
-        for( iFile = 0; 
-             papszDirEntries != NULL && papszDirEntries[iFile] != NULL;
-             iFile++ )
-        {
-            if( CSLFindString( (char **) apszExtensions, 
-                               CPLGetExtension(papszDirEntries[iFile])) != -1)
-            {
-                VSIUnlink( CPLFormFilename( pszDataSource, 
-                                            papszDirEntries[iFile], 
-                                            NULL ) );
-            }
-        }
-
-        CSLDestroy( papszDirEntries );
+    CSLDestroy(papszFileList);
 
+    VSIStatBufL sStatBuf;
+    if( VSIStatL( pszDataSource, &sStatBuf ) == 0 &&
+        VSI_ISDIR(sStatBuf.st_mode) )
+    {
         VSIRmdir( pszDataSource );
     }
 
-    return OGRERR_NONE;
+    return CE_None;
+}
+
+/************************************************************************/
+/*                          OGRTABDriverUnload()                        */
+/************************************************************************/
+
+static void OGRTABDriverUnload(CPL_UNUSED GDALDriver* poDriver)
+{
+    MITABFreeCoordSysTable();
 }
 
 /************************************************************************/
@@ -227,7 +224,49 @@ extern "C"
 void RegisterOGRTAB()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRTABDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "MapInfo File" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "MapInfo File" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "MapInfo File" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "tab mif mid" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_mitab.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='BOUNDS' type='string' description='Custom bounds. Expect format is xmin,ymin,xmax,ymax'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='FORMAT' type='string-select' description='type of MapInfo format'>"
+"    <Value>MIF</Value>"
+"    <Value>TAB</Value>"
+"  </Option>"
+"  <Option name='SPATIAL_INDEX_MODE' type='string-select' description='type of spatial index' default='QUICK'>"
+"    <Value>QUICK</Value>"
+"    <Value>OPTIMIZED</Value>"
+"  </Option>"
+"</CreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Real String Date DateTime Time" );
+
+        poDriver->pfnOpen = OGRTABDriverOpen;
+        poDriver->pfnIdentify = OGRTABDriverIdentify;
+        poDriver->pfnCreate = OGRTABDriverCreate;
+        poDriver->pfnDelete = OGRTABDriverDelete;
+        poDriver->pfnUnloadDriver = OGRTABDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
 }
diff --git a/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.h b/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.h
index 4733875..ad7c857 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.h
+++ b/ogr/ogrsf_frmts/mitab/mitab_ogr_driver.h
@@ -9,6 +9,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Stephane Villeneuve
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -102,12 +103,13 @@ class OGRTABDataSource : public OGRDataSource
     int                 m_bSingleFile;
     int                 m_bSingleLayerAlreadyCreated;
     GBool               m_bQuickSpatialIndexMode;
+    int                 m_bUpdate;
 
   public:
                 OGRTABDataSource();
     virtual     ~OGRTABDataSource();
 
-    int         Open( const char *pszName, int bTestOpen );
+    int         Open( GDALOpenInfo* poOpenInfo, int bTestOpen );
     int         Create( const char *pszName, char ** papszOptions );
 
     const char  *GetName() { return m_pszName; }
@@ -115,26 +117,12 @@ class OGRTABDataSource : public OGRDataSource
     OGRLayer    *GetLayer( int );
     int          TestCapability( const char * );
     
-    OGRLayer    *CreateLayer(const char *, 
+    OGRLayer    *ICreateLayer(const char *, 
                              OGRSpatialReference * = NULL,
                              OGRwkbGeometryType = wkbUnknown,
                              char ** = NULL );
-};
- 
-/************************************************************************/
-/*                             OGRTABDriver                             */
-/************************************************************************/
-
-class OGRTABDriver : public OGRSFDriver
-{
-public:
-    virtual     ~OGRTABDriver();
 
-    const char  *GetName();
-    OGRDataSource *Open ( const char *,int );
-    int         TestCapability( const char * );
-    virtual OGRDataSource *CreateDataSource( const char *, char ** = NULL );
-    virtual OGRErr DeleteDataSource( const char * );
+    char        **GetFileList();
 };
 
 void CPL_DLL RegisterOGRTAB();
diff --git a/ogr/ogrsf_frmts/mitab/mitab_priv.h b/ogr/ogrsf_frmts/mitab/mitab_priv.h
index 1096057..ff0d130 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_priv.h
+++ b/ogr/ogrsf_frmts/mitab/mitab_priv.h
@@ -9,6 +9,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2003, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -195,7 +196,7 @@ typedef enum
 {
     TABRead,
     TABWrite,
-    TABReadWrite  /* ReadWrite not implemented yet */
+    TABReadWrite
 } TABAccess;
 
 /*---------------------------------------------------------------------
@@ -238,6 +239,68 @@ typedef enum
 
 
 /*---------------------------------------------------------------------
+ * Codes for the known MapInfo Geometry types
+ *--------------------------------------------------------------------*/
+typedef enum
+{
+    TAB_GEOM_UNSET          = -1,
+
+    TAB_GEOM_NONE           = 0,
+    TAB_GEOM_SYMBOL_C       = 0x01,
+    TAB_GEOM_SYMBOL         = 0x02,
+    TAB_GEOM_LINE_C         = 0x04,
+    TAB_GEOM_LINE           = 0x05,
+    TAB_GEOM_PLINE_C        = 0x07,
+    TAB_GEOM_PLINE          = 0x08,
+    TAB_GEOM_ARC_C          = 0x0a,
+    TAB_GEOM_ARC            = 0x0b,
+    TAB_GEOM_REGION_C       = 0x0d,
+    TAB_GEOM_REGION         = 0x0e,
+    TAB_GEOM_TEXT_C         = 0x10,
+    TAB_GEOM_TEXT           = 0x11,
+    TAB_GEOM_RECT_C         = 0x13,
+    TAB_GEOM_RECT           = 0x14,
+    TAB_GEOM_ROUNDRECT_C    = 0x16,
+    TAB_GEOM_ROUNDRECT      = 0x17,
+    TAB_GEOM_ELLIPSE_C      = 0x19,
+    TAB_GEOM_ELLIPSE        = 0x1a,
+    TAB_GEOM_MULTIPLINE_C   = 0x25,
+    TAB_GEOM_MULTIPLINE     = 0x26,
+    TAB_GEOM_FONTSYMBOL_C   = 0x28, 
+    TAB_GEOM_FONTSYMBOL     = 0x29,
+    TAB_GEOM_CUSTOMSYMBOL_C = 0x2b,
+    TAB_GEOM_CUSTOMSYMBOL   = 0x2c,
+/* Version 450 object types: */
+    TAB_GEOM_V450_REGION_C  = 0x2e,
+    TAB_GEOM_V450_REGION    = 0x2f,
+    TAB_GEOM_V450_MULTIPLINE_C = 0x31,
+    TAB_GEOM_V450_MULTIPLINE   = 0x32,
+/* Version 650 object types: */
+    TAB_GEOM_MULTIPOINT_C   = 0x34,
+    TAB_GEOM_MULTIPOINT     = 0x35,
+    TAB_GEOM_COLLECTION_C   = 0x37,
+    TAB_GEOM_COLLECTION     = 0x38,
+/* Version 800 object types: */
+    TAB_GEOM_UNKNOWN1_C     = 0x3a,    // ???
+    TAB_GEOM_UNKNOWN1       = 0x3b,    // ???
+    TAB_GEOM_V800_REGION_C  = 0x3d,
+    TAB_GEOM_V800_REGION    = 0x3e,
+    TAB_GEOM_V800_MULTIPLINE_C = 0x40,
+    TAB_GEOM_V800_MULTIPLINE   = 0x41,
+    TAB_GEOM_V800_MULTIPOINT_C = 0x43,
+    TAB_GEOM_V800_MULTIPOINT   = 0x44,
+    TAB_GEOM_V800_COLLECTION_C = 0x46,
+    TAB_GEOM_V800_COLLECTION   = 0x47,
+    TAB_GEOM_MAX_TYPE /* TODo: Does this need to be 0x80? */
+} TABGeomType;
+
+#define TAB_GEOM_GET_VERSION(nGeomType)                     \
+    (((nGeomType) < TAB_GEOM_V450_REGION_C)  ? 300:         \
+     ((nGeomType) < TAB_GEOM_MULTIPOINT_C)   ? 450:         \
+     ((nGeomType) < TAB_GEOM_UNKNOWN1_C)     ? 650: 800 )
+
+
+/*---------------------------------------------------------------------
  * struct TABMAPIndexEntry - Entries found in type 1 blocks of .MAP files
  *
  * We will use this struct to rebuild the geographic index in memory
@@ -482,7 +545,7 @@ class TABMAPHeaderBlock;
 class TABMAPObjHdr
 {
   public:
-    GByte       m_nType;
+    TABGeomType m_nType;
     GInt32      m_nId;
     GInt32      m_nMinX;  /* Object MBR */
     GInt32      m_nMinY;
@@ -492,7 +555,7 @@ class TABMAPObjHdr
     TABMAPObjHdr() {};
     virtual ~TABMAPObjHdr() {};
 
-    static TABMAPObjHdr *NewObj(GByte nNewObjType, GInt32 nId=0);
+    static TABMAPObjHdr *NewObj(TABGeomType nNewObjType, GInt32 nId=0);
     static TABMAPObjHdr *ReadNextObj(TABMAPObjectBlock *poObjBlock,
                                      TABMAPHeaderBlock *poHeader);
 
@@ -754,6 +817,7 @@ class TABMAPObjCollection: public TABMAPObjHdrWithCoord
 typedef struct TABBlockRef_t
 {
     GInt32                nBlockPtr;
+    struct TABBlockRef_t *psPrev;
     struct TABBlockRef_t *psNext;
 } TABBlockRef;
 
@@ -768,19 +832,24 @@ class TABBinBlockManager
   protected:
     int         m_nBlockSize;
     GInt32      m_nLastAllocatedBlock;
-    TABBlockRef *m_psGarbageBlocks;
+    TABBlockRef *m_psGarbageBlocksFirst;
+    TABBlockRef *m_psGarbageBlocksLast;
+    char        m_szName[32]; /* for debug purposes */
 
   public:
     TABBinBlockManager(int nBlockSize=512);
     ~TABBinBlockManager();
 
-    GInt32      AllocNewBlock();
+    GInt32      AllocNewBlock(const char* pszReason = "");
     void        Reset();
     void        SetLastPtr(int nBlockPtr) {m_nLastAllocatedBlock=nBlockPtr; };
 
-    void        PushGarbageBlock(GInt32 nBlockPtr);
+    void        PushGarbageBlockAsFirst(GInt32 nBlockPtr);
+    void        PushGarbageBlockAsLast(GInt32 nBlockPtr);
     GInt32      GetFirstGarbageBlock();
     GInt32      PopGarbageBlock();
+    
+    void        SetName(const char* pszName);
 };
 
 /*---------------------------------------------------------------------
@@ -793,7 +862,7 @@ class TABBinBlockManager
 class TABRawBinBlock
 {
   protected:
-    FILE        *m_fp;          /* Associated file handle               */
+    VSILFILE    *m_fp;          /* Associated file handle               */
     TABAccess   m_eAccess;      /* Read/Write access mode               */
 
     int         m_nBlockType;
@@ -807,6 +876,7 @@ class TABRawBinBlock
     int         m_nCurPos;      /* Next byte to read from m_pabyBuf[]    */
     int         m_nFirstBlockPtr;/* Size of file header when different from */
                                  /* block size (used by GotoByteInFile())   */
+    int         m_nFileSize;
 
     int         m_bModified;     /* Used only to detect changes        */
 
@@ -815,15 +885,15 @@ class TABRawBinBlock
                    GBool bHardBlockSize = TRUE);
     virtual ~TABRawBinBlock();
 
-    virtual int ReadFromFile(FILE *fpSrc, int nOffset, int nSize = 512);
+    virtual int ReadFromFile(VSILFILE *fpSrc, int nOffset, int nSize = 512);
     virtual int CommitToFile();
     int         CommitAsDeleted(GInt32 nNextBlockPtr);
 
     virtual int InitBlockFromData(GByte *pabyBuf, 
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
 
     int         GetBlockType();
     virtual int GetBlockClass() { return TAB_RAWBIN_BLOCK; };
@@ -877,6 +947,9 @@ class TABRawBinBlock
 
 class TABMAPHeaderBlock: public TABRawBinBlock
 {
+    void        InitMembersWithDefaultValues();
+    void        UpdatePrecision();
+
   protected:
     TABProjInfo m_sProj;
 
@@ -889,8 +962,8 @@ class TABMAPHeaderBlock: public TABRawBinBlock
     virtual int InitBlockFromData(GByte *pabyBuf,
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
 
     virtual int GetBlockClass() { return TABMAP_HEADER_BLOCK; };
 
@@ -955,7 +1028,8 @@ class TABMAPHeaderBlock: public TABRawBinBlock
     double      m_YScale;
     double      m_XDispl;
     double      m_YDispl;
-    
+    double      m_XPrecision; // maximum achievable precision along X axis depending on bounds extent
+    double      m_YPrecision; // maximum achievable precision along Y axis depending on bounds extent
 };
 
 /*---------------------------------------------------------------------
@@ -996,12 +1070,14 @@ class TABMAPIndexBlock: public TABRawBinBlock
     virtual int InitBlockFromData(GByte *pabyBuf,
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
     virtual int CommitToFile();
 
     virtual int GetBlockClass() { return TABMAP_INDEX_BLOCK; };
 
+    void        UnsetCurChild();
+
     int         GetNumFreeEntries();
     int         GetNumEntries()         {return m_numEntries;};
     TABMAPIndexEntry *GetEntry( int iIndex );
@@ -1012,6 +1088,9 @@ class TABMAPIndexBlock: public TABRawBinBlock
     int         GetCurMaxDepth();
     void        GetMBR(GInt32 &nXMin, GInt32 &nYMin, 
                        GInt32 &nXMax, GInt32 &nYMax);
+    void        SetMBR(GInt32 nXMin, GInt32 nYMin, 
+                       GInt32 nXMax, GInt32 nYMax);
+
     GInt32      GetNodeBlockPtr() { return GetStartAddress();};
 
     void        SetMAPBlockManagerRef(TABBinBlockManager *poBlockMgr);
@@ -1087,7 +1166,9 @@ class TABMAPObjectBlock: public TABRawBinBlock
     // Keep track of current object either in read or read/write mode
     int         m_nCurObjectOffset; // -1 if there is no current object.
     int         m_nCurObjectId;     // -1 if there is no current object.
-    int         m_nCurObjectType;   // -1 if there is no current object.
+    TABGeomType m_nCurObjectType;   // TAB_GEOM_UNSET if there is no current object.
+    
+    int         m_bLockCenter;
 
   public:
     TABMAPObjectBlock(TABAccess eAccessMode = TABRead);
@@ -1097,8 +1178,8 @@ class TABMAPObjectBlock: public TABRawBinBlock
     virtual int InitBlockFromData(GByte *pabyBuf,
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
 
     virtual int GetBlockClass() { return TABMAP_OBJECT_BLOCK; };
 
@@ -1122,10 +1203,13 @@ class TABMAPObjectBlock: public TABRawBinBlock
                        GInt32 nXMax, GInt32 nYMax);
 
     void        Rewind();
+    void        ClearObjects();
+    void        LockCenter();
+    void        SetCenterFromOtherBlock(TABMAPObjectBlock* poOtherObjBlock);
     int         AdvanceToNextObject( TABMAPHeaderBlock * );
     int         GetCurObjectOffset() { return m_nCurObjectOffset; }
     int         GetCurObjectId() { return m_nCurObjectId; }
-    int         GetCurObjectType() { return m_nCurObjectType; }
+    TABGeomType GetCurObjectType() { return m_nCurObjectType; }
 
 #ifdef DEBUG
     virtual void Dump(FILE *fpOut = NULL) { Dump(fpOut, FALSE); };
@@ -1173,8 +1257,8 @@ class TABMAPCoordBlock: public TABRawBinBlock
     virtual int InitBlockFromData(GByte *pabyBuf,
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
     virtual int CommitToFile();
 
     virtual int GetBlockClass() { return TABMAP_COORD_BLOCK; };
@@ -1240,8 +1324,8 @@ class TABMAPToolBlock: public TABRawBinBlock
     virtual int InitBlockFromData(GByte *pabyBuf,
                                   int nBlockSize, int nSizeUsed,
                                   GBool bMakeCopy = TRUE,
-                                  FILE *fpSrc = NULL, int nOffset = 0);
-    virtual int InitNewBlock(FILE *fpSrc, int nBlockSize, int nFileOffset=0);
+                                  VSILFILE *fpSrc = NULL, int nOffset = 0);
+    virtual int InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset=0);
     virtual int CommitToFile();
 
     virtual int GetBlockClass() { return TABMAP_TOOL_BLOCK; };
@@ -1279,7 +1363,7 @@ class TABIDFile
 {
   private:
     char        *m_pszFname;
-    FILE        *m_fp;
+    VSILFILE    *m_fp;
     TABAccess   m_eAccessMode;
 
     TABRawBinBlock *m_poIDBlock;
@@ -1290,9 +1374,12 @@ class TABIDFile
     TABIDFile();
     ~TABIDFile();
 
-    int         Open(const char *pszFname, const char *pszAccess);
+    int         Open(const char *pszFname, const char* pszAccess);
+    int         Open(const char *pszFname, TABAccess eAccess);
     int         Close();
 
+    int         SyncToDisk();
+
     GInt32      GetObjPtr(GInt32 nObjId);
     int         SetObjPtr(GInt32 nObjId, GInt32 nObjPtr);
     GInt32      GetMaxObjId();
@@ -1316,7 +1403,7 @@ class TABMAPFile
   private:
     int         m_nMinTABVersion;
     char        *m_pszFname;
-    FILE        *m_fp;
+    VSILFILE    *m_fp;
     TABAccess   m_eAccessMode;
 
     TABBinBlockManager m_oBlockManager;
@@ -1335,7 +1422,7 @@ class TABMAPFile
     // Current object data block.
     TABMAPObjectBlock *m_poCurObjBlock;
     int         m_nCurObjPtr;
-    int         m_nCurObjType;
+    TABGeomType m_nCurObjType;
     int         m_nCurObjId;
     TABMAPCoordBlock *m_poCurCoordBlock;
 
@@ -1349,6 +1436,10 @@ class TABMAPFile
     GInt32      m_YMinFilter;
     GInt32      m_XMaxFilter;
     GInt32      m_YMaxFilter;
+    
+    int         m_bUpdated;
+    int         m_bLastOpWasRead;
+    int         m_bLastOpWasWrite;
 
     int         CommitObjAndCoordBlocks(GBool bDeleteObjects =FALSE);
     int         LoadObjAndCoordBlocks(GInt32 nBlockPtr);
@@ -1373,14 +1464,20 @@ class TABMAPFile
     int         LoadNextMatchingObjectBlock(int bFirstObject);
     TABRawBinBlock *PushBlock( int nFileOffset );
     
+    int         ReOpenReadWrite();
+    
   public:
     TABMAPFile();
     ~TABMAPFile();
 
-    int         Open(const char *pszFname, const char *pszAccess,
+    int         Open(const char *pszFname, const char* pszAccess,
+                     GBool bNoErrorMsg = FALSE );
+    int         Open(const char *pszFname, TABAccess eAccess,
                      GBool bNoErrorMsg = FALSE );
     int         Close();
 
+    int         SyncToDisk();
+
     int         SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode = TRUE);
 
     int         Int2Coordsys(GInt32 nX, GInt32 nY, double &dX, double &dY);
@@ -1396,7 +1493,7 @@ class TABMAPFile
 
     GInt32      GetMaxObjId();
     int         MoveToObjId(int nObjId);
-    void        UpdateMapHeaderInfo(GByte nObjType);
+    void        UpdateMapHeaderInfo(TABGeomType nObjType);
     int         PrepareNewObj(TABMAPObjHdr *poObjHdr);
     int         PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr);
     int         PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr);
@@ -1405,7 +1502,9 @@ class TABMAPFile
     void        ResetReading();
     int         GetNextFeatureId( int nPrevId );
 
-    int         GetCurObjType();
+    int         MarkAsDeleted();
+
+    TABGeomType GetCurObjType();
     int         GetCurObjId();
     TABMAPObjectBlock *GetCurObjBlock();
     TABMAPCoordBlock  *GetCurCoordBlock();
@@ -1451,7 +1550,7 @@ class TABMAPFile
 class TABINDNode
 {
   private:
-    FILE        *m_fp;
+    VSILFILE    *m_fp;
     TABAccess   m_eAccessMode;
     TABINDNode *m_poCurChildNode;
     TABINDNode *m_poParentNodeRef;
@@ -1485,7 +1584,7 @@ class TABINDNode
     TABINDNode(TABAccess eAccessMode = TABRead);
     ~TABINDNode();
 
-    int         InitNode(FILE *fp, int nBlockPtr, 
+    int         InitNode(VSILFILE *fp, int nBlockPtr, 
                          int nKeyLength, int nSubTreeDepth, GBool bUnique,
                          TABBinBlockManager *poBlockMgr=NULL,
                          TABINDNode *poParentNode=NULL,
@@ -1543,7 +1642,7 @@ class TABINDFile
 {
   private:
     char        *m_pszFname;
-    FILE        *m_fp;
+    VSILFILE    *m_fp;
     TABAccess   m_eAccessMode;
 
     TABBinBlockManager m_oBlockManager;
@@ -1594,7 +1693,7 @@ class TABDATFile
 {
   private:
     char        *m_pszFname;
-    FILE        *m_fp;
+    VSILFILE    *m_fp;
     TABAccess   m_eAccessMode;
     TABTableType m_eTableType;
 
@@ -1611,6 +1710,9 @@ class TABDATFile
     GInt32      m_numRecords;
     GInt32      m_nFirstRecordPtr;
     GBool       m_bWriteHeaderInitialized;
+    GBool       m_bWriteEOF;
+    
+    int         m_bUpdated;
 
     int         InitWriteHeader();
     int         WriteHeader();
@@ -1623,7 +1725,9 @@ class TABDATFile
     TABDATFile();
     ~TABDATFile();
 
-    int         Open(const char *pszFname, const char *pszAccess,
+    int         Open(const char *pszFname, const char* pszAccess,
+                     TABTableType eTableType =TABTableNative);
+    int         Open(const char *pszFname, TABAccess eAccess,
                      TABTableType eTableType =TABTableNative);
     int         Close();
 
@@ -1638,10 +1742,19 @@ class TABDATFile
     int         AddField(const char *pszName, TABFieldType eType,
                          int nWidth, int nPrecision=0);
 
+    int         DeleteField( int iField );
+    int         ReorderFields( int* panMap );
+    int         AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
+
+    int         SyncToDisk();
+
     GInt32      GetNumRecords();
     TABRawBinBlock *GetRecordBlock(int nRecordId);
     GBool       IsCurrentRecordDeleted() { return m_bCurRecordDeletedFlag;};
     int         CommitRecordToFile();
+    
+    int         MarkAsDeleted();
+    int         MarkRecordAsExisting();
 
     const char  *ReadCharField(int nWidth);
     GInt32      ReadIntegerField(int nWidth);
@@ -1790,7 +1903,7 @@ class MIDDATAFile
      int Rewind();
      void SaveLine(const char *pszLine);
      const char *GetSavedLine();
-     void WriteLine(const char*, ...);
+     void WriteLine(const char*, ...) CPL_PRINT_FUNC_FORMAT (2, 3);
      GBool IsValidFeature(const char *pszString);
 
 //  Translation information
@@ -1805,7 +1918,7 @@ class MIDDATAFile
      GBool GetEof();
 
      private:
-       FILE *m_fp;
+       VSILFILE *m_fp;
        const char *m_pszDelimiter;
 
        // Set limit for the length of a line
@@ -1828,7 +1941,7 @@ class MIDDATAFile
                         Function prototypes
  =====================================================================*/
 
-TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset, 
+TABRawBinBlock *TABCreateMAPBlockFromFile(VSILFILE *fpSrc, int nOffset, 
                                           int nSize = 512, 
                                           GBool bHardBlockSize = TRUE,
                                           TABAccess eAccessMode = TABRead);
diff --git a/ogr/ogrsf_frmts/mitab/mitab_rawbinblock.cpp b/ogr/ogrsf_frmts/mitab/mitab_rawbinblock.cpp
index 352288e..9b72e12 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_rawbinblock.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_rawbinblock.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999, 2000, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -90,6 +91,7 @@ TABRawBinBlock::TABRawBinBlock(TABAccess eAccessMode /*= TABRead*/,
     m_nFirstBlockPtr = 0;
     m_nBlockSize = m_nSizeUsed = m_nFileOffset = m_nCurPos = 0;
     m_bHardBlockSize = bHardBlockSize;
+    m_nFileSize = -1;
 
     m_bModified = FALSE;
 
@@ -117,7 +119,7 @@ TABRawBinBlock::~TABRawBinBlock()
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABRawBinBlock::ReadFromFile(FILE *fpSrc, int nOffset, 
+int     TABRawBinBlock::ReadFromFile(VSILFILE *fpSrc, int nOffset, 
                                      int nSize /*= 512*/)
 {
     GByte *pabyBuf;
@@ -130,6 +132,10 @@ int     TABRawBinBlock::ReadFromFile(FILE *fpSrc, int nOffset,
     }
 
     m_fp = fpSrc;
+
+    VSIFSeekL(fpSrc, 0, SEEK_END);
+    m_nFileSize = (int)VSIFTellL(m_fp);
+
     m_nFileOffset = nOffset;
     m_nCurPos = 0;
     m_bModified = FALSE;
@@ -142,8 +148,8 @@ int     TABRawBinBlock::ReadFromFile(FILE *fpSrc, int nOffset,
     /*----------------------------------------------------------------
      * Read from the file
      *---------------------------------------------------------------*/
-    if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 ||
-        (m_nSizeUsed = VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc) ) == 0 ||
+    if (VSIFSeekL(fpSrc, nOffset, SEEK_SET) != 0 ||
+        (m_nSizeUsed = VSIFReadL(pabyBuf, sizeof(GByte), nSize, fpSrc) ) == 0 ||
         (m_bHardBlockSize && m_nSizeUsed != nSize ) )
     {
         CPLError(CE_Failure, CPLE_FileIO,
@@ -198,24 +204,24 @@ int     TABRawBinBlock::CommitToFile()
     /*----------------------------------------------------------------
      * Move the output file pointer to the right position... 
      *---------------------------------------------------------------*/
-    if (VSIFSeek(m_fp, m_nFileOffset, SEEK_SET) != 0)
+    if (VSIFSeekL(m_fp, m_nFileOffset, SEEK_SET) != 0)
     {
         /*------------------------------------------------------------
          * Moving pointer failed... we may need to pad with zeros if 
          * block destination is beyond current end of file.
          *-----------------------------------------------------------*/
         int nCurPos;
-        nCurPos = VSIFTell(m_fp);
+        nCurPos = (int)VSIFTellL(m_fp);
 
         if (nCurPos < m_nFileOffset &&
-            VSIFSeek(m_fp, 0L, SEEK_END) == 0 &&
-            (nCurPos = VSIFTell(m_fp)) < m_nFileOffset)
+            VSIFSeekL(m_fp, 0L, SEEK_END) == 0 &&
+            (nCurPos = (int)VSIFTellL(m_fp)) < m_nFileOffset)
         {
             GByte cZero = 0;
 
             while(nCurPos < m_nFileOffset && nStatus == 0)
             {
-                if (VSIFWrite(&cZero, 1, 1, m_fp) != 1)
+                if (VSIFWriteL(&cZero, 1, 1, m_fp) != 1)
                 {
                     CPLError(CE_Failure, CPLE_FileIO,
                              "Failed writing 1 byte at offset %d.", nCurPos);
@@ -238,9 +244,11 @@ int     TABRawBinBlock::CommitToFile()
      * we write only the part of the block that was used.
      *---------------------------------------------------------------*/
     int numBytesToWrite = m_bHardBlockSize?m_nBlockSize:m_nSizeUsed;
+    
+    /*CPLDebug("MITAB", "Commiting to offset %d", m_nFileOffset);*/
 
     if (nStatus != 0 ||
-        VSIFWrite(m_pabyBuf,sizeof(GByte),
+        VSIFWriteL(m_pabyBuf,sizeof(GByte),
                     numBytesToWrite, m_fp) != (size_t)numBytesToWrite )
     {
         CPLError(CE_Failure, CPLE_FileIO,
@@ -248,8 +256,12 @@ int     TABRawBinBlock::CommitToFile()
                  numBytesToWrite, m_nFileOffset);
         return -1;
     }
+    if( m_nFileOffset + numBytesToWrite > m_nFileSize )
+    {
+        m_nFileSize = m_nFileOffset + numBytesToWrite;
+    }
 
-    fflush(m_fp);
+    VSIFFlushL(m_fp);
 
     m_bModified = FALSE;
 
@@ -281,6 +293,7 @@ int     TABRawBinBlock::CommitAsDeleted(GInt32 nNextBlockPtr)
      * Create deleted block header
      *----------------------------------------------------------------*/
     GotoByteInBlock(0x000);
+    WriteInt16(TABMAP_GARB_BLOCK);    // Block type code
     WriteInt32(nNextBlockPtr);
 
     if( CPLGetLastErrorType() == CE_Failure )
@@ -290,7 +303,13 @@ int     TABRawBinBlock::CommitAsDeleted(GInt32 nNextBlockPtr)
      * OK, call the base class to write the block to disk.
      *----------------------------------------------------------------*/
     if (nStatus == 0)
+    {
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "Commiting GARBAGE block to offset %d", m_nFileOffset);
+#endif
         nStatus = TABRawBinBlock::CommitToFile();
+        m_nSizeUsed = 0;
+    }
 
     return nStatus;
 }
@@ -317,7 +336,7 @@ int     TABRawBinBlock::CommitAsDeleted(GInt32 nNextBlockPtr)
 int     TABRawBinBlock::InitBlockFromData(GByte *pabyBuf, 
                                           int nBlockSize, int nSizeUsed, 
                                           GBool bMakeCopy /* = TRUE */,
-                                          FILE *fpSrc /* = NULL */, 
+                                          VSILFILE *fpSrc /* = NULL */, 
                                           int nOffset /* = 0 */)
 {
     m_fp = fpSrc;
@@ -372,7 +391,7 @@ int     TABRawBinBlock::InitBlockFromData(GByte *pabyBuf,
  * Returns 0 if succesful or -1 if an error happened, in which case 
  * CPLError() will have been called.
  **********************************************************************/
-int     TABRawBinBlock::InitNewBlock(FILE *fpSrc, int nBlockSize, 
+int     TABRawBinBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, 
                                      int nFileOffset /* = 0*/)
 {
     m_fp = fpSrc;
@@ -385,6 +404,14 @@ int     TABRawBinBlock::InitNewBlock(FILE *fpSrc, int nBlockSize,
         m_nFileOffset = nFileOffset;
     else
         m_nFileOffset = 0;
+    
+    if( m_fp != NULL && m_nFileSize < 0 && m_eAccess == TABReadWrite )
+    {
+        int nCurPos = (int)VSIFTellL(m_fp);
+        VSIFSeekL(fpSrc, 0, SEEK_END);
+        m_nFileSize = (int)VSIFTellL(m_fp);
+        VSIFSeekL(fpSrc, nCurPos, SEEK_SET);
+    }
 
     m_nBlockType = -1;
 
@@ -568,6 +595,23 @@ int     TABRawBinBlock::GotoByteInFile(int nOffset,
         }
         else
         {
+            if( !bForceReadFromFile && m_nFileSize > 0 &&
+                nOffset < m_nFileSize )
+            {
+                bForceReadFromFile = TRUE;
+                if ( !(nOffset < m_nFileOffset || 
+                       nOffset >= m_nFileOffset+m_nBlockSize) )
+                {
+                    if ( (nOffset<m_nFileOffset || nOffset>=m_nFileOffset+m_nSizeUsed) &&
+                         (CommitToFile() != 0 ||
+                          ReadFromFile(m_fp, nNewBlockPtr, m_nBlockSize) != 0) )
+                    {
+                        // Failed reading new block... error has already been reported.
+                        return -1;
+                    }
+                }
+            }
+
             if ( (nOffset < m_nFileOffset || 
                   nOffset >= m_nFileOffset+m_nBlockSize) &&
                  (CommitToFile() != 0 ||
@@ -673,13 +717,6 @@ int     TABRawBinBlock::ReadBytes(int numBytes, GByte *pabyDstBuf)
         return -1;
     }
 
-    if (m_eAccess != TABRead && m_eAccess != TABReadWrite )
-    {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "ReadBytes(): Block does not support read operations.");
-        return -1;
-    }
-
     if (m_nCurPos + numBytes > m_nSizeUsed)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
@@ -795,7 +832,7 @@ int  TABRawBinBlock::WriteBytes(int nBytesToWrite, GByte *pabySrcBuf)
         return -1;
     }
 
-    if (m_eAccess != TABWrite && m_eAccess != TABReadWrite )
+    if (m_eAccess == TABRead )
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "WriteBytes(): Block does not support write operations.");
@@ -958,9 +995,21 @@ void TABRawBinBlock::Dump(FILE *fpOut /*=NULL*/)
     }
     else
     {
-        fprintf(fpOut, "Block (type %d) size=%d bytes at offset %d in file.\n",
-                m_nBlockType, m_nBlockSize, m_nFileOffset);
-        fprintf(fpOut, "Current pointer at byte %d\n", m_nCurPos);
+        if( m_nBlockType == TABMAP_GARB_BLOCK )
+        {
+            fprintf(fpOut,"Garbage Block (type %d) at offset %d.\n", 
+                                                    m_nBlockType, m_nFileOffset);
+            int nNextGarbageBlock;
+            memcpy(&nNextGarbageBlock, m_pabyBuf + 2, 4);
+            CPL_LSBPTR32(&nNextGarbageBlock);
+            fprintf(fpOut,"  m_nNextGarbageBlock     = %d\n", nNextGarbageBlock);
+        }
+        else
+        {
+            fprintf(fpOut, "Block (type %d) size=%d bytes at offset %d in file.\n",
+                    m_nBlockType, m_nBlockSize, m_nFileOffset);
+            fprintf(fpOut, "Current pointer at byte %d\n", m_nCurPos);
+        }
     }
 
     fflush(fpOut);
@@ -978,18 +1027,16 @@ void TABRawBinBlock::DumpBytes(GInt32 nValue, int nOffset /*=0*/,
                                FILE *fpOut /*=NULL*/)
 {
     GInt32      anVal[2];
-    GInt16      *pn16Val1, *pn16Val2;
-    float       *pfValue;
+    GInt16      n16Val1, n16Val2;
+    float       fValue;
     char        *pcValue;
-    double      *pdValue;
-
+    double      dValue;
 
-    pfValue = (float*)(&nValue);
-    pcValue = (char*)(&nValue);
-    pdValue = (double*)anVal;
+    pcValue = (char*)&nValue;
+    memcpy(&fValue, &nValue, 4);
 
-    pn16Val1 = (GInt16*)(pcValue+2);
-    pn16Val2 = (GInt16*)(pcValue);
+    memcpy(&n16Val1, pcValue + 2, sizeof(GInt16));
+    memcpy(&n16Val2, pcValue, sizeof(GInt16));
 
     anVal[0] = anVal[1] = 0;
 
@@ -1003,13 +1050,14 @@ void TABRawBinBlock::DumpBytes(GInt32 nValue, int nOffset /*=0*/,
 #else
     anVal[1] = nValue;
 #endif
+    memcpy(&dValue, anVal, 8);
 
     if (fpOut == NULL)
         fpOut = stdout;
 
     fprintf(fpOut, "%d\t0x%8.8x  %-5d\t%-6d %-6d %5.3e  d=%5.3e",
                     nOffset, nValue, nValue,
-                    *pn16Val1, *pn16Val2, *pfValue, *pdValue);
+                    n16Val1, n16Val2, fValue, dValue);
 
     printf("\t[%c%c%c%c]\n", isprint(pcValue[0])?pcValue[0]:'.',
                              isprint(pcValue[1])?pcValue[1]:'.',
@@ -1028,7 +1076,7 @@ void TABRawBinBlock::DumpBytes(GInt32 nValue, int nOffset /*=0*/,
  * Returns the new object if succesful or NULL if an error happened, in 
  * which case CPLError() will have been called.
  **********************************************************************/
-TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset, 
+TABRawBinBlock *TABCreateMAPBlockFromFile(VSILFILE *fpSrc, int nOffset, 
                                           int nSize /*= 512*/, 
                                           GBool bHardBlockSize /*= TRUE */,
                                           TABAccess eAccessMode /*= TABRead*/)
@@ -1051,8 +1099,8 @@ TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset,
     /*----------------------------------------------------------------
      * Read from the file
      *---------------------------------------------------------------*/
-    if (VSIFSeek(fpSrc, nOffset, SEEK_SET) != 0 ||
-        VSIFRead(pabyBuf, sizeof(GByte), nSize, fpSrc)!=(unsigned int)nSize )
+    if (VSIFSeekL(fpSrc, nOffset, SEEK_SET) != 0 ||
+        VSIFReadL(pabyBuf, sizeof(GByte), nSize, fpSrc)!=(unsigned int)nSize )
     {
         CPLError(CE_Failure, CPLE_FileIO,
          "TABCreateMAPBlockFromFile() failed reading %d bytes at offset %d.",
@@ -1068,7 +1116,7 @@ TABRawBinBlock *TABCreateMAPBlockFromFile(FILE *fpSrc, int nOffset,
      *---------------------------------------------------------------*/
     if (nOffset == 0)
     {
-        poBlock = new TABMAPHeaderBlock;
+        poBlock = new TABMAPHeaderBlock(eAccessMode);
     }
     else
     {
@@ -1122,7 +1170,9 @@ TABBinBlockManager::TABBinBlockManager(int nBlockSize /*=512*/)
 
     m_nBlockSize=nBlockSize;
     m_nLastAllocatedBlock = -1;
-    m_psGarbageBlocks = NULL;
+    m_psGarbageBlocksFirst = NULL;
+    m_psGarbageBlocksLast = NULL;
+    m_szName[0] = '\0';
 }
 
 /**********************************************************************
@@ -1136,17 +1186,32 @@ TABBinBlockManager::~TABBinBlockManager()
 }
 
 /**********************************************************************
+ *                   TABBinBlockManager::SetName()
+ **********************************************************************/
+void TABBinBlockManager::SetName(const char* pszName)
+{
+    strncpy(m_szName, pszName, sizeof(m_szName));
+    m_szName[sizeof(m_szName)-1] = '\0';
+}
+
+/**********************************************************************
  *                   TABBinBlockManager::AllocNewBlock()
  *
- * Returns and reserves the address of the next available block, either a 
- * brand new block at end of file, or recycle a garbage block if one is 
+ * Returns and reserves the address of the next available block, either a
+ * brand new block at end of file, or recycle a garbage block if one is
  * available.
  **********************************************************************/
-GInt32  TABBinBlockManager::AllocNewBlock()
+GInt32  TABBinBlockManager::AllocNewBlock(CPL_UNUSED const char* pszReason)
 {
     // Try to reuse garbage blocks first
     if (GetFirstGarbageBlock() > 0)
-        return PopGarbageBlock();
+    {
+        int nRetValue = PopGarbageBlock();
+#ifdef DEBUG_VERBOSE
+        CPLDebug("MITAB", "AllocNewBlock(%s, %s) = %d (recycling garbage block)", m_szName, pszReason, nRetValue);
+#endif
+        return nRetValue;
+    }
 
     // ... or alloc a new block at EOF
     if (m_nLastAllocatedBlock==-1)
@@ -1154,6 +1219,9 @@ GInt32  TABBinBlockManager::AllocNewBlock()
     else
         m_nLastAllocatedBlock+=m_nBlockSize;
 
+#ifdef DEBUG_VERBOSE
+    CPLDebug("MITAB", "AllocNewBlock(%s, %s) = %d", m_szName, pszReason, m_nLastAllocatedBlock);
+#endif
     return m_nLastAllocatedBlock;
 }
 
@@ -1166,29 +1234,53 @@ void TABBinBlockManager::Reset()
     m_nLastAllocatedBlock = -1;
 
     // Flush list of garbage blocks
-    while (m_psGarbageBlocks != NULL)
+    while (m_psGarbageBlocksFirst != NULL)
     {
-        TABBlockRef *psNext = m_psGarbageBlocks->psNext;
-        CPLFree(m_psGarbageBlocks);
-        m_psGarbageBlocks = psNext;
+        TABBlockRef *psNext = m_psGarbageBlocksFirst->psNext;
+        CPLFree(m_psGarbageBlocksFirst);
+        m_psGarbageBlocksFirst = psNext;
     }
+    m_psGarbageBlocksLast = NULL;
 }
 
 /**********************************************************************
- *                   TABBinBlockManager::PushGarbageBlock()
+ *                   TABBinBlockManager::PushGarbageBlockAsFirst()
  *
  * Insert a garbage block at the head of the list of garbage blocks.
  **********************************************************************/
-void TABBinBlockManager::PushGarbageBlock(GInt32 nBlockPtr)
+void TABBinBlockManager::PushGarbageBlockAsFirst(GInt32 nBlockPtr)
 {
     TABBlockRef *psNewBlockRef = (TABBlockRef *)CPLMalloc(sizeof(TABBlockRef));
 
-    if (psNewBlockRef)
-    {
-        psNewBlockRef->nBlockPtr = nBlockPtr;
-        psNewBlockRef->psNext = m_psGarbageBlocks;
-        m_psGarbageBlocks = psNewBlockRef;
-    }
+    psNewBlockRef->nBlockPtr = nBlockPtr;
+    psNewBlockRef->psPrev = NULL;
+    psNewBlockRef->psNext = m_psGarbageBlocksFirst;
+
+    if( m_psGarbageBlocksFirst != NULL )
+        m_psGarbageBlocksFirst->psPrev = psNewBlockRef;
+    m_psGarbageBlocksFirst = psNewBlockRef;
+    if( m_psGarbageBlocksLast == NULL )
+        m_psGarbageBlocksLast = m_psGarbageBlocksFirst;
+}
+
+/**********************************************************************
+ *                   TABBinBlockManager::PushGarbageBlockAsLast()
+ *
+ * Insert a garbage block at the tail of the list of garbage blocks.
+ **********************************************************************/
+void TABBinBlockManager::PushGarbageBlockAsLast(GInt32 nBlockPtr)
+{
+    TABBlockRef *psNewBlockRef = (TABBlockRef *)CPLMalloc(sizeof(TABBlockRef));
+
+    psNewBlockRef->nBlockPtr = nBlockPtr;
+    psNewBlockRef->psPrev = m_psGarbageBlocksLast;
+    psNewBlockRef->psNext = NULL;
+
+    if( m_psGarbageBlocksLast != NULL )
+        m_psGarbageBlocksLast->psNext = psNewBlockRef;
+    m_psGarbageBlocksLast = psNewBlockRef;
+    if( m_psGarbageBlocksFirst == NULL )
+        m_psGarbageBlocksFirst = m_psGarbageBlocksLast;
 }
 
 /**********************************************************************
@@ -1199,8 +1291,8 @@ void TABBinBlockManager::PushGarbageBlock(GInt32 nBlockPtr)
  **********************************************************************/
 GInt32 TABBinBlockManager::GetFirstGarbageBlock()
 {
-    if (m_psGarbageBlocks)
-        return m_psGarbageBlocks->nBlockPtr;
+    if (m_psGarbageBlocksFirst)
+        return m_psGarbageBlocksFirst->nBlockPtr;
 
     return 0;
 }
@@ -1216,14 +1308,17 @@ GInt32 TABBinBlockManager::PopGarbageBlock()
 {
     GInt32 nBlockPtr = 0;
 
-    if (m_psGarbageBlocks)
+    if (m_psGarbageBlocksFirst)
     {
-        nBlockPtr = m_psGarbageBlocks->nBlockPtr;
-        TABBlockRef *psNext = m_psGarbageBlocks->psNext;
-        CPLFree(m_psGarbageBlocks);
-        m_psGarbageBlocks = psNext;
+        nBlockPtr = m_psGarbageBlocksFirst->nBlockPtr;
+        TABBlockRef *psNext = m_psGarbageBlocksFirst->psNext;
+        CPLFree(m_psGarbageBlocksFirst);
+        if( psNext != NULL )
+            psNext->psPrev = NULL;
+        else
+            m_psGarbageBlocksLast = NULL;
+        m_psGarbageBlocksFirst = psNext;
     }
 
     return nBlockPtr;
 }
-
diff --git a/ogr/ogrsf_frmts/mitab/mitab_spatialref.cpp b/ogr/ogrsf_frmts/mitab/mitab_spatialref.cpp
index d82b946..066b747 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_spatialref.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_spatialref.cpp
@@ -9,6 +9,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2001, Frank Warmerdam
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -34,7 +35,7 @@
  * add support for reading google mercator (#4115)
  *
  * Revision 1.54  2010-10-07 18:46:26  aboudreault
- * Fixed bad use of atof when locale setting doesn't use . for float (GDAL bug #3775)
+ * Fixed bad use of CPLAtof when locale setting doesn't use . for float (GDAL bug #3775)
  *
  * Revision 1.53  2010-09-07 16:48:08  aboudreault
  * Removed incomplete patch for affine params support in mitab. (bug 1155)
@@ -217,7 +218,10 @@
 /*      were added afterwards and may be incomplete or inaccurate.       */
 /* -------------------------------------------------------------------- */
 
-MapInfoDatumInfo asDatumInfoList[] =
+extern const MapInfoDatumInfo asDatumInfoList[];
+extern const MapInfoSpheroidInfo asSpheroidInfoList[];
+
+const MapInfoDatumInfo asDatumInfoList[] =
 {
 
 { 0,    104, "WGS_1984",                   28,0, 0, 0, 0, 0, 0, 0, 0},
@@ -259,6 +263,7 @@ MapInfoDatumInfo asDatumInfoList[] =
 { 6272, 31, "New_Zealand_Geodetic_Datum_1949",4,84, -22,  209, 0, 0, 0, 0, 0},
 { 0,    32, "GRS_67",                      21,0,    0,    0,   0, 0, 0, 0, 0},
 { 0,    33, "GRS_80",                      0, 0,    0,    0,   0, 0, 0, 0, 0},
+{ 6171, 33, "Reseau_Geodesique_Francais_1993",0, 0, 0,    0,   0, 0, 0, 0, 0},
 { 6675, 34, "Guam_1963",                   7, -100, -248, 259, 0, 0, 0, 0, 0},
 { 0,    35, "Gux_1_Astro",                 4, 252,  -209, -751,0, 0, 0, 0, 0},
 { 6254, 36, "Hito_XVIII_1963",             4, 16,   196,  93,  0, 0, 0, 0, 0},
@@ -411,7 +416,7 @@ MapInfoDatumInfo asDatumInfoList[] =
 /*      manuals.                                                        */
 /* -------------------------------------------------------------------- */
 
-MapInfoSpheroidInfo asSpheroidInfoList[] =
+const MapInfoSpheroidInfo asSpheroidInfoList[] =
 {
 { 9,"Airy 1930",                                6377563.396,    299.3249646},
 {13,"Airy 1930 (modified for Ireland 1965",     6377340.189,    299.3249646},
@@ -469,7 +474,326 @@ MapInfoSpheroidInfo asSpheroidInfoList[] =
 {54,"WGS 84 (MAPINFO Datum 157)",               6378137.01,     298.257223563},
 {-1,NULL,                                       0.0,            0.0}
 };
- 
+
+/* For LCC, standard parallel 1 and 2 can be switched indifferently */
+/* So the MapInfo order and the EPSG order are not generally identical */
+/* which may cause recognition problems when reading in MapInfo */
+/* This table contains the parameters in the order expected by MapInfo */
+typedef struct
+{
+    int    nEPSGCode;
+    int    bReverseStdP;
+    int    nMapInfoDatumID;
+    double dfCenterLong;
+    double dfCenterLat;
+    double dfStdP1;
+    double dfStdP2;
+} MapInfoLCCSRS;
+
+static const MapInfoLCCSRS asMapInfoLCCSRSList[] = {
+{2154,1,33,3,46.5,44,49},
+{2154,1,33,3,46.5,44,49.00000000001},
+{2154,1,33,3,46.5,44,49.00000000002},
+{2225,1,74,-122,39.3333333333,40,41.6666666667},
+{2226,1,74,-122,37.6666666667,38.3333333333,39.8333333333},
+{2227,1,74,-120.5,36.5,37.0666666667,38.4333333333},
+{2228,1,74,-119,35.3333333333,36,37.25},
+{2229,1,74,-118,33.5,34.0333333333,35.4666666667},
+{2230,1,74,-116.25,32.1666666667,32.7833333333,33.8833333333},
+{2231,1,74,-105.5,39.3333333333,39.7166666667,40.7833333333},
+{2232,1,74,-105.5,37.8333333333,38.45,39.75},
+{2233,1,74,-105.5,36.6666666667,37.2333333333,38.4333333333},
+{2234,1,74,-72.75,40.8333333333,41.2,41.8666666667},
+{2238,1,74,-84.5,29,29.5833333333,30.75},
+{2246,0,74,-84.25,37.5,37.9666666667,38.9666666667},
+{2247,1,74,-85.75,36.3333333333,36.7333333333,37.9333333333},
+{2248,1,74,-77,37.6666666667,38.3,39.45},
+{2249,1,74,-71.5,41,41.7166666667,42.6833333333},
+{2250,1,74,-70.5,41,41.2833333333,41.4833333333},
+{2251,1,74,-87,44.7833333333,45.4833333333,47.0833333333},
+{2252,1,74,-84.3666666667,43.3166666667,44.1833333333,45.7},
+{2253,1,74,-84.3666666667,41.5,42.1,43.6666666667},
+{2256,1,74,-109.5,44.25,45,49},
+{2263,1,74,-74,40.1666666667,40.6666666667,41.0333333333},
+{2264,1,74,-79,33.75,34.3333333333,36.1666666667},
+{2265,1,74,-100.5,47,47.4333333333,48.7333333333},
+{2266,1,74,-100.5,45.6666666667,46.1833333333,47.4833333333},
+{2267,1,74,-98,35,35.5666666667,36.7666666667},
+{2268,1,74,-98,33.3333333333,33.9333333333,35.2333333333},
+{2269,1,74,-120.5,43.6666666667,44.3333333333,46},
+{2270,1,74,-120.5,41.6666666667,42.3333333333,44},
+{2271,1,74,-77.75,40.1666666667,40.8833333333,41.95},
+{2272,1,74,-77.75,39.3333333333,39.9333333333,40.9666666667},
+{2273,1,74,-81,31.8333333333,32.5,34.8333333333},
+{2274,1,74,-86,34.3333333333,35.25,36.4166666667},
+{2275,1,74,-101.5,34,34.65,36.1833333333},
+{2276,1,74,-98.5,31.6666666667,32.1333333333,33.9666666667},
+{2277,1,74,-100.3333333333,29.6666666667,30.1166666667,31.8833333333},
+{2278,1,74,-99,27.8333333333,28.3833333333,30.2833333333},
+{2279,1,74,-98.5,25.6666666667,26.1666666667,27.8333333333},
+{2280,1,74,-111.5,40.3333333333,40.7166666667,41.7833333333},
+{2281,1,74,-111.5,38.3333333333,39.0166666667,40.65},
+{2282,1,74,-111.5,36.6666666667,37.2166666667,38.35},
+{2283,1,74,-78.5,37.6666666667,38.0333333333,39.2},
+{2284,1,74,-78.5,36.3333333333,36.7666666667,37.9666666667},
+{2285,1,74,-120.8333333333,47,47.5,48.7333333333},
+{2286,1,74,-120.5,45.3333333333,45.8333333333,47.3333333333},
+{2287,1,74,-90,45.1666666667,45.5666666667,46.7666666667},
+{2288,1,74,-90,43.8333333333,44.25,45.5},
+{2289,1,74,-90,42,42.7333333333,44.0666666667},
+{26740,1,63,-176,51,51.8333333333,53.8333333333},
+{26741,1,62,-122,39.3333333333,40,41.6666666667},
+{26742,1,62,-122,37.6666666667,38.3333333333,39.8333333333},
+{26743,1,62,-120.5,36.5,37.0666666667,38.4333333333},
+{26744,1,62,-119,35.3333333333,36,37.25},
+{26745,1,62,-118,33.5,34.0333333333,35.4666666667},
+{26746,1,62,-116.25,32.1666666667,32.7833333333,33.8833333333},
+{26747,1,62,-118.3333333333,34.1333333333,33.8666666667,34.4166666667},
+{26751,1,62,-92,34.3333333333,34.9333333333,36.2333333333},
+{26752,1,62,-92,32.6666666667,33.3,34.7666666667},
+{26753,0,62,-105.5,39.3333333333,39.7166666667,40.7833333333},
+{26754,1,62,-105.5,37.8333333333,38.45,39.75},
+{26755,1,62,-105.5,36.6666666667,37.2333333333,38.4333333333},
+{26756,1,62,-72.75,40.8333333333,41.2,41.8666666667},
+{26760,1,62,-84.5,29,29.5833333333,30.75},
+{26775,1,62,-93.5,41.5,42.0666666667,43.2666666667},
+{26776,1,62,-93.5,40,40.6166666667,41.7833333333},
+{26777,1,62,-98,38.3333333333,38.7166666667,39.7833333333},
+{26778,0,62,-98.5,36.6666666667,38.5666666667,37.2666666667},
+{26779,0,62,-84.25,37.5,37.9666666667,38.9666666667},
+{26780,0,62,-85.75,36.3333333333,36.7333333333,37.9333333333},
+{26781,0,62,-92.5,30.6666666667,31.1666666667,32.6666666667},
+{26785,0,62,-77,37.8333333333,38.3,39.45},
+{26786,0,62,-71.5,41,41.7166666667,42.6833333333},
+{26788,0,73,-87,44.7833333333,45.4833333333,47.0833333333},
+{26789,0,73,-84.3333333333,43.3166666667,44.1833333333,45.7},
+{26790,0,73,-84.3333333333,41.5,42.1,43.6666666667},
+{26791,0,62,-93.1,46.5,47.0333333333,48.6333333333},
+{26792,0,62,-94.25,45,45.6166666667,47.05},
+{26793,0,62,-94,43,43.7833333333,45.2166666667},
+{26940,1,74,-176,51,51.8333333333,53.8333333333},
+{26941,1,74,-122,39.3333333333,40,41.6666666667},
+{26942,1,74,-122,37.6666666667,38.3333333333,39.8333333333},
+{26943,1,74,-120.5,36.5,37.0666666667,38.4333333333},
+{26944,1,74,-119,35.3333333333,36,37.25},
+{26945,1,74,-118,33.5,34.0333333333,35.4666666667},
+{26946,1,74,-116.25,32.1666666667,32.7833333333,33.8833333333},
+{26951,1,74,-92,34.3333333333,34.9333333333,36.2333333333},
+{26952,1,74,-92,32.6666666667,33.3,34.7666666667},
+{26953,1,74,-105.5,39.3333333333,39.7166666667,40.7833333333},
+{26954,1,74,-105.5,37.8333333333,38.45,39.75},
+{26955,1,74,-105.5,36.6666666667,37.2333333333,38.4333333333},
+{26956,1,74,-72.75,40.8333333333,41.2,41.8666666667},
+{26960,1,74,-84.5,29,29.5833333333,30.75},
+{26975,1,74,-93.5,41.5,42.0666666667,43.2666666667},
+{26976,1,74,-93.5,40,40.6166666667,41.7833333333},
+{26977,1,74,-98,38.3333333333,38.7166666667,39.7833333333},
+{26978,0,74,-98.5,36.6666666667,38.5666666667,37.2666666667},
+{26980,1,74,-85.75,36.3333333333,36.7333333333,37.9333333333},
+{26981,1,74,-92.5,30.5,31.1666666667,32.6666666667},
+{26982,1,74,-91.3333333333,28.5,29.3,30.7},
+{26985,1,74,-77,37.6666666667,38.3,39.45},
+{26986,1,74,-71.5,41,41.7166666667,42.6833333333},
+{26987,1,74,-70.5,41,41.2833333333,41.4833333333},
+{26988,1,74,-87,44.7833333333,45.4833333333,47.0833333333},
+{26989,1,74,-84.3666666667,43.3166666667,44.1833333333,45.7},
+{26990,1,74,-84.3666666667,41.5,42.1,43.6666666667},
+{26991,1,74,-93.1,46.5,47.0333333333,48.6333333333},
+{26992,1,74,-94.25,45,45.6166666667,47.05},
+{26993,1,74,-94,43,43.7833333333,45.2166666667},
+{3111,0,116,145,-37,-36,-38},
+{31370,1,1019,4.3674866667,90,49.8333339000,51.1666672333},
+{32001,1,62,-109.5,47,47.85,48.7166666667},
+{32002,1,62,-109.5,45.8333333333,46.45,47.8833333333},
+{32003,1,62,-109.5,44,44.8666666667,46.4},
+{32005,0,62,-100,41.3333333333,41.85,42.8166666667},
+{32006,0,62,-99.5,39.6666666667,40.2833333333,41.7166666667},
+{32018,1,62,-74,40.5,40.6666666667,41.0333333333},
+{32019,0,62,-79,33.75,34.3333333333,36.1666666667},
+{32020,0,62,-100.5,47,47.4333333333,48.7333333333},
+{32021,0,62,-100.5,45.6666666667,46.1833333333,47.4833333333},
+{32022,0,62,-82.5,39.6666666667,40.4333333333,41.7},
+{32023,0,62,-82.5,38,38.7333333333,40.0333333333},
+{32024,0,62,-98,35,35.5666666667,36.7666666667},
+{32025,0,62,-98,33.3333333333,33.9333333333,35.2333333333},
+{32026,0,62,-120.5,43.6666666667,44.3333333333,46},
+{32027,0,62,-120.5,41.6666666667,42.3333333333,44},
+{32028,0,62,-77.75,40.1666666667,40.8833333333,41.95},
+{32031,0,62,-81,33,33.7666666667,34.9666666667},
+{32033,0,62,-81,31.8333333333,32.3333333333,33.6666666667},
+{32034,0,62,-100,43.8333333333,44.4166666667,45.6833333333},
+{32035,0,62,-100.3333333333,42.3333333333,42.8333333333,44.4},
+{32036,0,62,-86,34.6666666667,35.25,36.4166666667},
+{32037,0,62,-101.5,34,34.65,36.1833333333},
+{32038,0,62,-97.5,31.6666666667,32.1333333333,33.9666666667},
+{32039,0,62,-100.3333333333,29.6666666667,30.1166666667,31.8833333333},
+{32040,0,62,-99,27.8333333333,28.3833333333,30.2833333333},
+{32041,0,62,-98.5,25.6666666667,26.1666666667,27.8333333333},
+{32042,0,62,-111.5,40.3333333333,40.7166666667,41.7833333333},
+{32043,0,62,-111.5,38.3333333333,39.0166666667,40.65},
+{32044,0,62,-111.5,36.6666666667,37.2166666667,38.35},
+{32046,0,62,-78.5,37.6666666667,38.0333333333,39.2},
+{32047,0,62,-78.5,36.3333333333,36.7666666667,37.9666666667},
+{32048,0,62,-120.8333333333,47,47.5,48.7333333333},
+{32049,0,62,-120.5,45.3333333333,45.8333333333,47.3333333333},
+{32050,0,62,-79.5,38.5,39,40.25},
+{32051,0,62,-81,37,37.4833333333,38.8833333333},
+{32052,0,62,-90,45.1666666667,45.5666666667,46.7666666667},
+{32053,0,62,-90,43.8333333333,44.25,45.5},
+{32054,0,62,-90,42,42.7333333333,44.0666666667},
+{32059,0,62,-66.4333333333,18.4333333333,18.0333333333,18.4333333333},
+{32060,0,62,-66.4333333333,18.4333333333,18.0333333333,18.4333333333},
+{32100,1,74,-109.5,44.25,45,49},
+{32104,1,74,-100,39.8333333333,40,43},
+{32118,1,74,-74,40.1666666667,40.6666666667,41.0333333333},
+{32119,1,74,-79,33.75,34.3333333333,36.1666666667},
+{32120,1,74,-100.5,47,47.4333333333,48.7333333333},
+{32121,1,74,-100.5,45.6666666667,46.1833333333,47.4833333333},
+{32122,1,74,-82.5,39.6666666667,40.4333333333,41.7},
+{32123,1,74,-82.5,38,38.7333333333,40.0333333333},
+{32124,1,74,-98,35,35.5666666667,36.7666666667},
+{32125,1,74,-98,33.3333333333,33.9333333333,35.2333333333},
+{32126,1,74,-120.5,43.6666666667,44.3333333333,46},
+{32127,1,74,-120.5,41.6666666667,42.3333333333,44},
+{32128,1,74,-77.75,40.1666666667,40.8833333333,41.95},
+{32129,1,74,-77.75,39.3333333333,39.9333333333,40.9666666667},
+{32133,1,74,-81,31.8333333333,32.5,34.8333333333},
+{32134,1,74,-100,43.8333333333,44.4166666667,45.6833333333},
+{32135,1,74,-100.3333333333,42.3333333333,42.8333333333,44.4},
+{32136,1,74,-86,34.3333333333,35.25,36.4166666667},
+{32137,1,74,-101.5,34,34.65,36.1833333333},
+{32138,1,74,-98.5,31.6666666667,32.1333333333,33.9666666667},
+{32139,1,74,-100.3333333333,29.6666666667,30.1166666667,31.8833333333},
+{32140,1,74,-99,27.8333333333,28.3833333333,30.2833333333},
+{32141,1,74,-98.5,25.6666666667,26.1666666667,27.8333333333},
+{32142,1,74,-111.5,40.3333333333,40.7166666667,41.7833333333},
+{32143,1,74,-111.5,38.3333333333,39.0166666667,40.65},
+{32144,1,74,-111.5,36.6666666667,37.2166666667,38.35},
+{32146,1,74,-78.5,37.6666666667,38.0333333333,39.2},
+{32147,1,74,-78.5,36.3333333333,36.7666666667,37.9666666667},
+{32148,1,74,-120.8333333333,47,47.5,48.7333333333},
+{32149,1,74,-120.5,45.3333333333,45.8333333333,47.3333333333},
+{32150,1,74,-79.5,38.5,39,40.25},
+{32151,1,74,-81,37,37.4833333333,38.8833333333},
+{32152,1,74,-90,45.1666666667,45.5666666667,46.7666666667},
+{32153,1,74,-90,43.8333333333,44.25,45.5},
+{32154,1,74,-90,42,42.7333333333,44.0666666667},
+{32161,1,74,-66.4333333333,17.8333333333,18.0333333333,18.4333333333},
+{3300,1,115,24,57.51755394,58,59.33333333},
+{3301,1,115,24,57.51755393056,58,59.33333333},
+{3797,0,66,-70,44,50,46},
+{3798,0,74,-70,44,50,46},
+{3799,0,74,-70,44,50,46},
+{3942,0,33,3,42,41.25,42.75},
+{3943,0,33,3,43,42.25,43.75},
+{3944,0,33,3,44,43.25,44.75},
+{3945,0,33,3,45,44.25,45.75},
+{3946,0,33,3,46,45.25,46.75},
+{3947,0,33,3,47,46.25,47.75},
+{3948,0,33,3,48,47.25,48.75},
+{3949,0,33,3,49,48.25,49.75},
+{3950,0,33,3,50,49.25,50.75},
+{42101,0,104,-95,0,49,77},
+{42103,0,104,-100,0,33,45},
+{42304,0,74,-95,49,49,77},
+{0,0,0,110,10,25,40},
+{0,0,0,132.5,-10,-21.5,-33.5},
+{0,0,0,25,35,40,65},
+{0,0,0,47.5,25,15,35},
+{0,0,0,95,40,20,60},
+{0,0,1002,0,42.165,41.5603877778,42.76766333},
+{0,0,1002,0,42.165,41.5603877778,42.767663333},
+{0,0,1002,0,42.165,41.560387778,42.76766333},
+{0,0,1002,0,42.165,41.560387778,42.767663333},
+{0,0,1002,0,42.165,41.56038778,42.76766333},
+{0,0,1002,0,42.165,41.560387840948,42.76766346965},
+{0,0,1002,0,44.1,43.199291275544,44.996093814511},
+{0,0,1002,0,44.1,43.1992913889,44.99609389},
+{0,0,1002,0,44.1,43.199291389,44.99609389},
+{0,0,1002,0,44.1,43.19929139,44.99609389},
+{0,0,1002,0,46.8,45.8989188889,47.69601444},
+{0,0,1002,0,46.8,45.898918889,47.69601444},
+{0,0,1002,0,46.8,45.89891889,47.69601444},
+{0,0,1002,0,46.8,45.898918964419,47.696014502038},
+{0,0,1002,0,49.5,48.5985227778,50.39591167},
+{0,0,1002,0,49.5,48.598522778,50.39591167},
+{0,0,1002,0,49.5,48.59852278,50.39591167},
+{0,0,1002,0,49.5,48.598522847174,50.395911631678},
+{0,0,1005,23,-23,-18,-32},
+{0,0,1022,2.7,36,37.575,34.425},
+{0,0,104,13.33333333,47.5,46,49},
+{0,0,104,13.33333333,48,46,49},
+{0,0,104,-19,65,64.25,65.75},
+{0,0,104,36.0,25.0,37.5,40.5},
+{0,0,104,36,25,37.5,40.5},
+{0,0,104,70,-50,-68.5,-74.5},
+{0,0,110,4.367975,90,49.8333333333,51.1666666667},
+{0,0,115,10,52,35,45},
+{0,0,116,135,-24,-18,-36},
+{0,0,116,135,-32,-28,-36},
+{0,0,12,135,-24,-18,-36},
+{0,0,12,145,-37,-36,-38},
+{0,0,13,135,-24,-18,-36},
+{0,0,19,23,-23,-18,-32},
+{0,0,28,17,29.77930555,42,56},
+{0,0,28,19,29.77930555,42,56},
+{0,0,28,36.0,25.0,37.5,40.5},
+{0,0,33,13.5,0,52.6666666667,55.3333333333},
+{0,0,33,15,0,56.5,60.5},
+{0,0,33,15,0,58,66},
+{0,0,33,15,0,63.5,67.5},
+{0,0,33,15.5,0,56.6666666667,59.3333333333},
+{0,0,33,15.5,0,60.6666666667,63.3333333333},
+{0,0,33,16.5,0,60.6666666667,63.3333333333},
+{0,0,33,18.5,0,64.6666666667,67.3333333333},
+{0,0,33,19,0,64.6666666667,67.3333333333},
+{0,0,55,-5.4,22.5,20.9075742561,24.0921050540},
+{0,0,55,-5.4,26.1,24.5075340813,27.6921073632},
+{0,0,55,-5.4,29.7,28.1063294800,31.2932791054},
+{0,0,55,-5.4,33.3,31.72786641202,34.8717272112},
+{0,0,62,-70.5,41,41.2833333333,41.4833333333},
+{0,0,62,-77.75,39.3333333333,39.9333333333,40.9666666667},
+{0,0,62,-91.3333333333,25.6666666667,26.1666666667,27.8333333333},
+{0,0,62,-91.3333333333,28.6666666667,29.3,30.67},
+{0,0,62,-96,23,20,60},
+{0,0,62,-96,23,33,45},
+{0,0,62,-96,39,33,45},
+{0,0,66,-68.5,44,46,60},
+{0,0,74,-100.3333333333,42.3333333333,42.8333333333,44.4},
+{0,0,74,-100,39.8333333333,40,43},
+{0,0,74,-100,43.8333333333,44.4166666667,45.6833333333},
+{0,0,74,-109.5,44.25,45,49},
+{0,0,74,-111.5,36.6666666667,37.2166666667,38.35},
+{0,0,74,-111.5,38.3333333333,39.0166666667,40.65},
+{0,0,74,-111.5,40.3333333333,40.7166666667,41.7833333333},
+{0,0,74,-120.5,41.6666666667,42.3333333333,44},
+{0,0,74,-120.5,43.6666666667,44.3333333333,46},
+{0,0,74,-176,51,51.8333333333,53.8333333333},
+{0,0,74,-66.4333333333,17.8333333333,18.0333333333,18.4333333333},
+{0,0,74,-68.5,44,46,60},
+{0,0,74,-79.5,38.5,39,40.25},
+{0,0,74,-81,31.8333333333,32.5,34.8333333333},
+{0,0,74,-81,37,37.4833333333,38.8833333333},
+{0,0,74,-82.5,38,38.7333333333,40.0333333333},
+{0,0,74,-82.5,39.6666666667,40.4333333333,41.7},
+{0,0,74,-84.25,37.5,37.9666666667,38.9666666667},
+{0,0,74,-84.3666666667,41.5,42.1,43.6666666667},
+{0,0,74,-84.3666666667,43.3166666667,44.1833333333,45.7},
+{0,0,74,-87,44.7833333333,45.4833333333,47.0833333333},
+{0,0,74,-91.3333333333,25.5,26.1666666667,27.8333333333},
+{0,0,74,-91.3333333333,28.5,29.3,30.7},
+{0,0,74,-92,32.6666666667,33.3,34.7666666667},
+{0,0,74,-92,34.3333333333,34.9333333333,36.2333333333},
+{0,0,74,-92.5,30.5,31.1666666667,32.6666666667},
+{0,0,74,-93.1,46.5,47.0333333333,48.6333333333},
+{0,0,74,-93.5,40,40.6166666667,41.7833333333},
+{0,0,74,-93.5,41.5,42.0666666667,43.2666666667},
+{0,0,74,-94.25,45,45.6166666667,47.05},
+{0,0,74,-94,43,43.7833333333,45.2166666667},
+{0,0,74,-98,38.3333333333,38.7166666667,39.7833333333},
+{0,0,74,-98.5,36.6666666667,38.5666666667,37.2666666667},
+};
+
 /**********************************************************************
  *                   TABFile::GetSpatialRef()
  *
@@ -484,13 +808,6 @@ MapInfoSpheroidInfo asSpheroidInfoList[] =
  **********************************************************************/
 OGRSpatialReference *TABFile::GetSpatialRef()
 {
-    if (m_eAccessMode != TABRead)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "GetSpatialRef() can be used only with Read access.");
-        return NULL;
-    }
- 
     if (m_poMAPFile == NULL )
     {
         CPLError(CE_Failure, CPLE_AssertionFailed,
@@ -518,7 +835,17 @@ OGRSpatialReference *TABFile::GetSpatialRef()
                  "GetSpatialRef() failed reading projection parameters.");
         return NULL;
     }
+    
+    m_poSpatialRef = GetSpatialRefFromTABProj(sTABProj);
+    return m_poSpatialRef;
+}
 
+/**********************************************************************
+ *                   TABFile::GetSpatialRefFromTABProj()
+ **********************************************************************/
+
+OGRSpatialReference* TABFile::GetSpatialRefFromTABProj(const TABProjInfo& sTABProj)
+{
     /*-----------------------------------------------------------------
      * Get the units name, and translation factor.
      *----------------------------------------------------------------*/
@@ -604,7 +931,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
     /*-----------------------------------------------------------------
      * Transform them into an OGRSpatialReference.
      *----------------------------------------------------------------*/
-    m_poSpatialRef = new OGRSpatialReference;
+    OGRSpatialReference* poSpatialRef = new OGRSpatialReference;
 
     /*-----------------------------------------------------------------
      * Handle the PROJCS style projections, but add the datum later.
@@ -616,7 +943,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * we might want to include the units, but not for now.
          *-------------------------------------------------------------*/
       case 0:
-        m_poSpatialRef->SetLocalCS( "Nonearth" );
+        poSpatialRef->SetLocalCS( "Nonearth" );
         break;
 
         /*--------------------------------------------------------------
@@ -629,7 +956,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Cylindrical Equal Area
          *-------------------------------------------------------------*/
       case 2:
-        m_poSpatialRef->SetCEA( sTABProj.adProjParams[1],
+        poSpatialRef->SetCEA( sTABProj.adProjParams[1],
                                 sTABProj.adProjParams[0],
                                 sTABProj.adProjParams[2],
                                 sTABProj.adProjParams[3] );
@@ -639,7 +966,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Lambert Conic Conformal
          *-------------------------------------------------------------*/
       case 3:
-        m_poSpatialRef->SetLCC( sTABProj.adProjParams[2],
+        poSpatialRef->SetLCC( sTABProj.adProjParams[2],
                                 sTABProj.adProjParams[3],
                                 sTABProj.adProjParams[1],
                                 sTABProj.adProjParams[0],
@@ -652,7 +979,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          *-------------------------------------------------------------*/
       case 4:
       case 29:
-        m_poSpatialRef->SetLAEA( sTABProj.adProjParams[1],
+        poSpatialRef->SetLAEA( sTABProj.adProjParams[1],
                                  sTABProj.adProjParams[0],
                                  0.0, 0.0 );
         break;
@@ -662,7 +989,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          *-------------------------------------------------------------*/
       case 5:
       case 28:
-        m_poSpatialRef->SetAE( sTABProj.adProjParams[1],
+        poSpatialRef->SetAE( sTABProj.adProjParams[1],
                                sTABProj.adProjParams[0],
                                0.0, 0.0 );
         break;
@@ -671,7 +998,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Equidistant Conic
          *-------------------------------------------------------------*/
       case 6:
-        m_poSpatialRef->SetEC( sTABProj.adProjParams[2],
+        poSpatialRef->SetEC( sTABProj.adProjParams[2],
                                sTABProj.adProjParams[3],
                                sTABProj.adProjParams[1],
                                sTABProj.adProjParams[0],
@@ -683,7 +1010,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Hotine Oblique Mercator
          *-------------------------------------------------------------*/
       case 7:
-        m_poSpatialRef->SetHOM( sTABProj.adProjParams[1],
+        poSpatialRef->SetHOM( sTABProj.adProjParams[1],
                                 sTABProj.adProjParams[0], 
                                 sTABProj.adProjParams[2],
                                 90.0, 
@@ -696,7 +1023,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Transverse Mercator
          *-------------------------------------------------------------*/
       case 8:
-        m_poSpatialRef->SetTM( sTABProj.adProjParams[1],
+        poSpatialRef->SetTM( sTABProj.adProjParams[1],
                                sTABProj.adProjParams[0],
                                sTABProj.adProjParams[2],
                                sTABProj.adProjParams[3],
@@ -707,7 +1034,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Transverse Mercator,(modified for Danish System 34 Jylland-Fyn)
          *---------------------------------------------------------------*/
       case 21:
-         m_poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_21,
+         poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_21,
                                        sTABProj.adProjParams[1],
                                        sTABProj.adProjParams[0],
                                        sTABProj.adProjParams[2],
@@ -719,7 +1046,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Transverse Mercator,(modified for Danish System 34 Sjaelland)
          *-------------------------------------------------------------*/
       case 22:
-         m_poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_22,
+         poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_22,
                                        sTABProj.adProjParams[1],
                                        sTABProj.adProjParams[0],
                                        sTABProj.adProjParams[2],
@@ -731,7 +1058,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Transverse Mercator,(modified for Danish System 34/45 Bornholm)
          *---------------------------------------------------------------*/
       case 23:
-         m_poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_23,
+         poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_23,
                                        sTABProj.adProjParams[1],
                                        sTABProj.adProjParams[0],
                                        sTABProj.adProjParams[2],
@@ -743,7 +1070,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Transverse Mercator,(modified for Finnish KKJ)
          *-------------------------------------------------------------*/
       case 24:
-         m_poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_24,
+         poSpatialRef->SetTMVariant( SRS_PT_TRANSVERSE_MERCATOR_MI_24,
                                        sTABProj.adProjParams[1],
                                        sTABProj.adProjParams[0],
                                        sTABProj.adProjParams[2],
@@ -755,7 +1082,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Albers Conic Equal Area
          *-------------------------------------------------------------*/
       case 9:
-        m_poSpatialRef->SetACEA( sTABProj.adProjParams[2],
+        poSpatialRef->SetACEA( sTABProj.adProjParams[2],
                                  sTABProj.adProjParams[3],
                                  sTABProj.adProjParams[1],
                                  sTABProj.adProjParams[0],
@@ -767,7 +1094,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Mercator
          *-------------------------------------------------------------*/
       case 10:
-        m_poSpatialRef->SetMercator( 0.0, sTABProj.adProjParams[0],
+        poSpatialRef->SetMercator( 0.0, sTABProj.adProjParams[0],
                                      1.0, 0.0, 0.0 );
         break;
 
@@ -775,7 +1102,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Miller Cylindrical
          *-------------------------------------------------------------*/
       case 11:
-        m_poSpatialRef->SetMC( 0.0, sTABProj.adProjParams[0],
+        poSpatialRef->SetMC( 0.0, sTABProj.adProjParams[0],
                                0.0, 0.0 );
         break;
 
@@ -783,7 +1110,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Robinson
          *-------------------------------------------------------------*/
       case 12:
-        m_poSpatialRef->SetRobinson( sTABProj.adProjParams[0],
+        poSpatialRef->SetRobinson( sTABProj.adProjParams[0],
                                      0.0, 0.0 );
         break;
 
@@ -791,7 +1118,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Mollweide
          *-------------------------------------------------------------*/
       case 13:
-        m_poSpatialRef->SetMollweide( sTABProj.adProjParams[0],
+        poSpatialRef->SetMollweide( sTABProj.adProjParams[0],
                                       0.0, 0.0 );
         break;
 
@@ -799,21 +1126,21 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Eckert IV
          *-------------------------------------------------------------*/
       case 14:
-        m_poSpatialRef->SetEckertIV( sTABProj.adProjParams[0], 0.0, 0.0 );
+        poSpatialRef->SetEckertIV( sTABProj.adProjParams[0], 0.0, 0.0 );
         break;
 
         /*--------------------------------------------------------------
          * Eckert VI
          *-------------------------------------------------------------*/
       case 15:
-        m_poSpatialRef->SetEckertVI( sTABProj.adProjParams[0], 0.0, 0.0 );
+        poSpatialRef->SetEckertVI( sTABProj.adProjParams[0], 0.0, 0.0 );
         break;
 
         /*--------------------------------------------------------------
          * Sinusoidal
          *-------------------------------------------------------------*/
       case 16:
-        m_poSpatialRef->SetSinusoidal( sTABProj.adProjParams[0],
+        poSpatialRef->SetSinusoidal( sTABProj.adProjParams[0],
                                        0.0, 0.0 );
         break;
 
@@ -821,14 +1148,14 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Gall Stereographic
          *-------------------------------------------------------------*/
       case 17:
-        m_poSpatialRef->SetGS( sTABProj.adProjParams[0], 0.0, 0.0 );
+        poSpatialRef->SetGS( sTABProj.adProjParams[0], 0.0, 0.0 );
         break;
         
         /*--------------------------------------------------------------
          * New Zealand Map Grid
          *-------------------------------------------------------------*/
       case 18:
-        m_poSpatialRef->SetNZMG( sTABProj.adProjParams[1],
+        poSpatialRef->SetNZMG( sTABProj.adProjParams[1],
                                  sTABProj.adProjParams[0],
                                  sTABProj.adProjParams[2],
                                  sTABProj.adProjParams[3] );
@@ -838,7 +1165,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Lambert Conic Conformal (Belgium)
          *-------------------------------------------------------------*/
       case 19:
-        m_poSpatialRef->SetLCCB( sTABProj.adProjParams[2],
+        poSpatialRef->SetLCCB( sTABProj.adProjParams[2],
                                  sTABProj.adProjParams[3],
                                  sTABProj.adProjParams[1],
                                  sTABProj.adProjParams[0],
@@ -851,7 +1178,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          *-------------------------------------------------------------*/
       case 20:
       case 31: /* this is called Double Stereographic, whats the diff? */
-        m_poSpatialRef->SetStereographic( sTABProj.adProjParams[1],
+        poSpatialRef->SetStereographic( sTABProj.adProjParams[1],
                                           sTABProj.adProjParams[0],
                                           sTABProj.adProjParams[2],
                                           sTABProj.adProjParams[3],
@@ -862,7 +1189,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Swiss Oblique Mercator / Cylindrical
          *-------------------------------------------------------------*/
       case 25:
-        m_poSpatialRef->SetSOC( sTABProj.adProjParams[1],
+        poSpatialRef->SetSOC( sTABProj.adProjParams[1],
                                 sTABProj.adProjParams[0],
                                 sTABProj.adProjParams[2],
                                 sTABProj.adProjParams[3] );
@@ -872,7 +1199,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Regional Mercator (regular mercator with a latitude).
          *-------------------------------------------------------------*/
       case 26:
-        m_poSpatialRef->SetMercator( sTABProj.adProjParams[1],
+        poSpatialRef->SetMercator( sTABProj.adProjParams[1],
                                      sTABProj.adProjParams[0],
                                      1.0, 0.0, 0.0 );
         break;
@@ -881,7 +1208,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Polyconic
          *-------------------------------------------------------------*/
       case 27:
-        m_poSpatialRef->SetPolyconic( sTABProj.adProjParams[1],
+        poSpatialRef->SetPolyconic( sTABProj.adProjParams[1],
                                       sTABProj.adProjParams[0],
                                       sTABProj.adProjParams[2],
                                       sTABProj.adProjParams[3] );
@@ -891,7 +1218,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
          * Cassini/Soldner
          *-------------------------------------------------------------*/
       case 30:
-        m_poSpatialRef->SetCS( sTABProj.adProjParams[1],
+        poSpatialRef->SetCS( sTABProj.adProjParams[1],
                                sTABProj.adProjParams[0],
                                sTABProj.adProjParams[2],
                                sTABProj.adProjParams[3] );
@@ -901,7 +1228,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
       * Krovak
       *-------------------------------------------------------------*/
       case 32:
-        m_poSpatialRef->SetKrovak( sTABProj.adProjParams[1],   // dfCenterLat
+        poSpatialRef->SetKrovak( sTABProj.adProjParams[1],   // dfCenterLat
                                    sTABProj.adProjParams[0],   // dfCenterLong
                                    sTABProj.adProjParams[3],   // dfAzimuth
                                    sTABProj.adProjParams[2],   // dfPseudoStdParallelLat
@@ -910,6 +1237,16 @@ OGRSpatialReference *TABFile::GetSpatialRef()
                                    sTABProj.adProjParams[5] ); // dfFalseNorthing
         break;
 
+     /*--------------------------------------------------------------
+      * Equidistant Cylindrical / Equirectangular
+      *-------------------------------------------------------------*/
+      case 33:
+        poSpatialRef->SetEquirectangular( sTABProj.adProjParams[1],
+                                            sTABProj.adProjParams[0],
+                                            sTABProj.adProjParams[2],
+                                            sTABProj.adProjParams[3] );
+        break;
+
       default:
         break;
     }
@@ -917,11 +1254,11 @@ OGRSpatialReference *TABFile::GetSpatialRef()
     /*-----------------------------------------------------------------
      * Collect units definition.
      *----------------------------------------------------------------*/
-    if( sTABProj.nProjId != 1 && m_poSpatialRef->GetRoot() != NULL )
+    if( sTABProj.nProjId != 1 && poSpatialRef->GetRoot() != NULL )
     {
         OGR_SRSNode     *poUnits = new OGR_SRSNode("UNIT");
         
-        m_poSpatialRef->GetRoot()->AddChild(poUnits);
+        poSpatialRef->GetRoot()->AddChild(poUnits);
 
         poUnits->AddChild( new OGR_SRSNode( pszUnitsName ) );
         poUnits->AddChild( new OGR_SRSNode( pszUnitsConv ) );
@@ -932,7 +1269,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
      * so we just return from here. 
      *----------------------------------------------------------------*/
     if( sTABProj.nProjId == 0 )
-        return m_poSpatialRef;
+        return poSpatialRef;
 
     /*-----------------------------------------------------------------
      * Set the datum.  We are only given the X, Y and Z shift for
@@ -946,7 +1283,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
 #define TAB_EQUAL(a, b) (((a)<(b) ? ((b)-(a)) : ((a)-(b))) < 1e-10)
     char        szDatumName[160];
     int         iDatumInfo;
-    MapInfoDatumInfo *psDatumInfo = NULL;
+    const MapInfoDatumInfo *psDatumInfo = NULL;
 
     for( iDatumInfo = 0;
          asDatumInfoList[iDatumInfo].nMapInfoDatumID != -1;
@@ -1005,6 +1342,44 @@ OGRSpatialReference *TABFile::GetSpatialRef()
     {
         strncpy( szDatumName, psDatumInfo->pszOGCDatumName,
                  sizeof(szDatumName) );
+
+        /* For LCC, standard parallel 1 and 2 can be switched indifferently */
+        /* So the MapInfo order and the EPSG order are not generally identical */
+        /* which may cause recognition problems when reading in MapInfo */
+        if( sTABProj.nProjId == 3 )
+        {
+            double dfCenterLong = sTABProj.adProjParams[0];
+            double dfCenterLat = sTABProj.adProjParams[1];
+            double dfStdP1 = sTABProj.adProjParams[2];
+            double dfStdP2 = sTABProj.adProjParams[3];
+
+            for(size_t i=0;i<sizeof(asMapInfoLCCSRSList)/sizeof(asMapInfoLCCSRSList[0]);i++)
+            {
+                if( sTABProj.nDatumId == asMapInfoLCCSRSList[i].nMapInfoDatumID &&
+                    TAB_EQUAL( dfCenterLong, asMapInfoLCCSRSList[i].dfCenterLong ) &&
+                    TAB_EQUAL( dfCenterLat, asMapInfoLCCSRSList[i].dfCenterLat ) )
+                {
+                    if( TAB_EQUAL( dfStdP1, asMapInfoLCCSRSList[i].dfStdP1 ) &&
+                        TAB_EQUAL( dfStdP2, asMapInfoLCCSRSList[i].dfStdP2 ) )
+                    {
+                        if( asMapInfoLCCSRSList[i].bReverseStdP )
+                        {
+                            CPLDebug("MITAB", "Switching standard parallel 1 and 2");
+                            poSpatialRef->SetLCC( sTABProj.adProjParams[3],
+                                    sTABProj.adProjParams[2],
+                                    sTABProj.adProjParams[1],
+                                    sTABProj.adProjParams[0],
+                                    sTABProj.adProjParams[4],
+                                    sTABProj.adProjParams[5] );
+                        }
+                        if( asMapInfoLCCSRSList[i].nEPSGCode > 0 )
+                            poSpatialRef->SetAuthority( "PROJCS", "EPSG",
+                                        asMapInfoLCCSRSList[i].nEPSGCode );
+                        break;
+                    }
+                }
+            }
+        }
     }
     else
     {
@@ -1042,7 +1417,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
     double      dfPMOffset = 0.0;
     const char *pszPMName = "Greenwich";
     
-    if( sTABProj.adDatumParams[4] != 0.0 )
+    if( /*sTABProj.nDatumId == 9999 ||*/ sTABProj.adDatumParams[4] != 0.0 )
     {
         dfPMOffset = sTABProj.adDatumParams[4];
 
@@ -1053,7 +1428,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
      * Create a GEOGCS definition.
      *----------------------------------------------------------------*/
 
-    m_poSpatialRef->SetGeogCS( "unnamed",
+    poSpatialRef->SetGeogCS( "unnamed",
                                szDatumName,
                                pszSpheroidName,
                                dfSemiMajor, dfInvFlattening,
@@ -1062,7 +1437,7 @@ OGRSpatialReference *TABFile::GetSpatialRef()
 
     if( psDatumInfo != NULL )
     {
-        m_poSpatialRef->SetTOWGS84( psDatumInfo->dfShiftX, 
+        poSpatialRef->SetTOWGS84( psDatumInfo->dfShiftX, 
                                     psDatumInfo->dfShiftY,
                                     psDatumInfo->dfShiftZ,
                                     psDatumInfo->dfDatumParm0 == 0 ? 0 : -psDatumInfo->dfDatumParm0, /* avoids 0 to be transformed into -0 */
@@ -1070,6 +1445,16 @@ OGRSpatialReference *TABFile::GetSpatialRef()
                                     psDatumInfo->dfDatumParm2 == 0 ? 0 : -psDatumInfo->dfDatumParm2,
                                     psDatumInfo->dfDatumParm3 );
     }
+    else
+    {
+        poSpatialRef->SetTOWGS84( sTABProj.dDatumShiftX, 
+                                    sTABProj.dDatumShiftY, 
+                                    sTABProj.dDatumShiftZ, 
+                                    sTABProj.adDatumParams[0] == 0 ? 0 : -sTABProj.adDatumParams[0], 
+                                    sTABProj.adDatumParams[1] == 0 ? 0 : -sTABProj.adDatumParams[1], 
+                                    sTABProj.adDatumParams[2] == 0 ? 0 : -sTABProj.adDatumParams[2], 
+                                    sTABProj.adDatumParams[3] );
+    }
 
     /*-----------------------------------------------------------------
      * Special case for Google Mercator (datum=157, ellipse=54, gdal #4115)
@@ -1078,11 +1463,25 @@ OGRSpatialReference *TABFile::GetSpatialRef()
         && sTABProj.nDatumId == 157
         && sTABProj.nEllipsoidId == 54 )
     {
-        m_poSpatialRef->SetNode( "PROJCS", "WGS 84 / Pseudo-Mercator" );
-        m_poSpatialRef->SetExtension( "PROJCS", "PROJ4", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs" );
+        poSpatialRef->SetNode( "PROJCS", "WGS 84 / Pseudo-Mercator" );
+        poSpatialRef->SetExtension( "PROJCS", "PROJ4", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs" );
     }
 
-    return m_poSpatialRef;
+    /*-----------------------------------------------------------------
+     * Special case for France Lambert-93
+     *----------------------------------------------------------------*/
+    if( sTABProj.nProjId == 3
+        && sTABProj.nDatumId == 33
+        && sTABProj.nEllipsoidId == 0
+        && TAB_EQUAL(poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0), 3.0)
+        && TAB_EQUAL(poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0), 46.5) )
+    {
+        poSpatialRef->SetNode( "PROJCS", "RGF93 / Lambert-93" );
+        poSpatialRef->SetNode( "PROJCS|GEOGCS", "RGF93");
+        poSpatialRef->SetNode( "PROJCS|GEOGCS|DATUM", "Reseau_Geodesique_Francais_1993");
+    }
+
+    return poSpatialRef;
 }
 
 /**********************************************************************
@@ -1126,11 +1525,30 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
     
     m_poSpatialRef = poSpatialRef->Clone();
 
+    TABProjInfo     sTABProj;
+    int             nParmCount;
+    GetTABProjFromSpatialRef(poSpatialRef, sTABProj, nParmCount);
+    
     /*-----------------------------------------------------------------
-     * Initialize TABProjInfo
+     * Set the new parameters in the .MAP header.
+     * This will also trigger lookup of default bounds for the projection.
      *----------------------------------------------------------------*/
-    TABProjInfo     sTABProj;
+    if ( SetProjInfo( &sTABProj ) != 0 )
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "SetSpatialRef() failed setting projection parameters.");
+        return -1;
+    }
 
+    return 0;
+}
+
+int TABFile::GetTABProjFromSpatialRef(const OGRSpatialReference* poSpatialRef,
+                                      TABProjInfo& sTABProj, int& nParmCount)
+{
+    /*-----------------------------------------------------------------
+     * Initialize TABProjInfo
+     *----------------------------------------------------------------*/
     sTABProj.nProjId = 0;
     sTABProj.nEllipsoidId = 0; /* how will we set this? */
     sTABProj.nUnitsId = 7;
@@ -1172,8 +1590,9 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
      *----------------------------------------------------------------*/
     const char *pszProjection = poSpatialRef->GetAttrValue("PROJECTION");
     double      *parms = sTABProj.adProjParams;
+    nParmCount = 0;
 
-    if( pszProjection == NULL && poSpatialRef->GetAttrNode("LOCAL_CS") != NULL)
+    if( pszProjection == NULL && poSpatialRef->GetAttrNode("GEOGCS") == NULL)
     {
         /* nonearth */
         sTABProj.nProjId = 0;
@@ -1193,6 +1612,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_AZIMUTHAL_EQUIDISTANT) )
@@ -1201,6 +1621,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
         parms[2] = 90.0;
+        nParmCount = 3;
 
         if( ABS((ABS(parms[1]) - 90)) > 0.001 )
             sTABProj.nProjId = 28;
@@ -1211,18 +1632,21 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         sTABProj.nProjId = 2;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0);
+        nParmCount = 2;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_IV) )
     {
         sTABProj.nProjId = 14;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_ECKERT_VI) )
     {
         sTABProj.nProjId = 15;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_EQUIDISTANT_CONIC) )
@@ -1234,12 +1658,14 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_GALL_STEREOGRAPHIC) )
     {
         sTABProj.nProjId = 17;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_HOTINE_OBLIQUE_MERCATOR) )
@@ -1251,6 +1677,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) )
@@ -1259,6 +1686,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_CENTER,0.0);
         parms[2] = 90.0;
+        nParmCount = 3;
 
         if( ABS((ABS(parms[1]) - 90)) > 0.001 )
             sTABProj.nProjId = 28;
@@ -1273,6 +1701,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM) )
@@ -1284,6 +1713,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_MERCATOR_1SP) )
@@ -1292,21 +1722,27 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
+        nParmCount = 1; // FIXME for MIF export ?
 
         if( parms[1] != 0.0 )
+        {
             sTABProj.nProjId = 26;
+            nParmCount = 2; // FIXME for MIF export ?
+        }
     }
 
     else if( EQUAL(pszProjection,SRS_PT_MILLER_CYLINDRICAL) )
     {
         sTABProj.nProjId = 11;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_LONGITUDE_OF_CENTER,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_MOLLWEIDE) )
     {
         sTABProj.nProjId = 13;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_NEW_ZEALAND_MAP_GRID) )
@@ -1316,6 +1752,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 4;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_SWISS_OBLIQUE_CYLINDRICAL) )
@@ -1325,18 +1762,21 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 4;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_ROBINSON) )
     {
         sTABProj.nProjId = 12;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_SINUSOIDAL) )
     {
         sTABProj.nProjId = 16;
         parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        nParmCount = 1;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_STEREOGRAPHIC) )
@@ -1347,6 +1787,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR) )
@@ -1357,6 +1798,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_21) ) // Encom 2003
@@ -1367,6 +1809,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_22) ) // Encom 2003
@@ -1377,6 +1820,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_23) ) // Encom 2003
@@ -1387,6 +1831,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_TRANSVERSE_MERCATOR_MI_24) ) // Encom 2003
@@ -1397,6 +1842,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_SCALE_FACTOR,1.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 5;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_CASSINI_SOLDNER) )
@@ -1406,15 +1852,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
-    }
-
-    else if( EQUAL(pszProjection,SRS_PT_NEW_ZEALAND_MAP_GRID) )
-    {
-        sTABProj.nProjId = 18;
-        parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
-        parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
-        parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
-        parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 4;
     }
 
     else if( EQUAL(pszProjection,SRS_PT_POLYCONIC) )
@@ -1424,6 +1862,7 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
         parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 4;
     }
 
    else if( EQUAL(pszProjection,SRS_PT_KROVAK) )
@@ -1435,13 +1874,24 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         parms[3] = poSpatialRef->GetProjParm(SRS_PP_AZIMUTH,0.0);
         parms[4] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
         parms[5] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 6;
    }
 
+  else if( EQUAL(pszProjection,SRS_PT_EQUIRECTANGULAR) )
+  {
+        sTABProj.nProjId = 33;
+        parms[0] = poSpatialRef->GetProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0);
+        parms[1] = poSpatialRef->GetProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0);
+        parms[2] = poSpatialRef->GetProjParm(SRS_PP_FALSE_EASTING,0.0);
+        parms[3] = poSpatialRef->GetProjParm(SRS_PP_FALSE_NORTHING,0.0);
+        nParmCount = 4;
+  }
+
     /* ==============================================================
      * Translate Datum and Ellipsoid
      * ============================================================== */
     const char *pszWKTDatum = poSpatialRef->GetAttrValue("DATUM");
-    MapInfoDatumInfo *psDatumInfo = NULL;
+    const MapInfoDatumInfo *psDatumInfo = NULL;
     
     int nDatumEPSGCode = -1;
     const char *pszDatumAuthority = poSpatialRef->GetAuthorityName("DATUM");
@@ -1457,7 +1907,12 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
      *----------------------------------------------------------------*/
     if( pszWKTDatum == NULL )
     {
+        CPLDebug("MITAB", "Cannot find MapInfo datum matching %d. Defaulting to WGS 84",
+                 nDatumEPSGCode);
         psDatumInfo = asDatumInfoList+0; /* WGS 84 */
+        // From MIF export code. FIXME?
+        //if( nProjection == 1 )
+        //    nProjection = 0;
     }
 
     /*-----------------------------------------------------------------
@@ -1470,9 +1925,10 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
     {
         int     i;
 
+        int nDatum = atoi(pszWKTDatum+4);
         for( i = 0; asDatumInfoList[i].nMapInfoDatumID != -1; i++ )
         {
-            if( atoi(pszWKTDatum+4) == asDatumInfoList[i].nMapInfoDatumID )
+            if( nDatum == asDatumInfoList[i].nMapInfoDatumID )
             {
                 psDatumInfo = asDatumInfoList + i;
                 break;
@@ -1480,7 +1936,11 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         }
 
         if( psDatumInfo == NULL )
+        {
+            CPLDebug("MITAB", "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
+                     pszWKTDatum);
             psDatumInfo = asDatumInfoList+0; /* WGS 84 */
+        }
     }
 
     /*-----------------------------------------------------------------
@@ -1491,28 +1951,33 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
     {
         char **papszFields;
 
+        sTABProj.nDatumId = atoi(pszWKTDatum+4);
         papszFields =
             CSLTokenizeStringComplex( pszWKTDatum+4, ",", FALSE, TRUE);
 
         if( CSLCount(papszFields) >= 5 )
         {
             sTABProj.nEllipsoidId = (GByte)atoi(papszFields[1]);
-            sTABProj.dDatumShiftX = atof(papszFields[2]);
-            sTABProj.dDatumShiftY = atof(papszFields[3]);
-            sTABProj.dDatumShiftZ = atof(papszFields[4]);
+            sTABProj.dDatumShiftX = CPLAtof(papszFields[2]);
+            sTABProj.dDatumShiftY = CPLAtof(papszFields[3]);
+            sTABProj.dDatumShiftZ = CPLAtof(papszFields[4]);
         }
 
         if( CSLCount(papszFields) >= 10 )
         {
-            sTABProj.adDatumParams[0] = atof(papszFields[5]);
-            sTABProj.adDatumParams[1] = atof(papszFields[6]);
-            sTABProj.adDatumParams[2] = atof(papszFields[7]);
-            sTABProj.adDatumParams[3] = atof(papszFields[8]);
-            sTABProj.adDatumParams[4] = atof(papszFields[9]);
+            sTABProj.adDatumParams[0] = CPLAtof(papszFields[5]);
+            sTABProj.adDatumParams[1] = CPLAtof(papszFields[6]);
+            sTABProj.adDatumParams[2] = CPLAtof(papszFields[7]);
+            sTABProj.adDatumParams[3] = CPLAtof(papszFields[8]);
+            sTABProj.adDatumParams[4] = CPLAtof(papszFields[9]);
         }
 
         if( CSLCount(papszFields) < 5 )
-            psDatumInfo = asDatumInfoList+0; /* WKS84 */
+        {
+            CPLDebug("MITAB", "Cannot find MapInfo datum matching %s. Defaulting to WGS 84",
+                     pszWKTDatum);
+            psDatumInfo = asDatumInfoList+0; /* WGS 84 */
+        }
 
         CSLDestroy( papszFields );
     }
@@ -1536,8 +2001,12 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
             }
         }
 
-         if( psDatumInfo == NULL )
+        if( psDatumInfo == NULL )
+        {
+            CPLDebug("MITAB", "Cannot find MapInfo datum matching %s,%d. Defaulting to WGS 84",
+                     pszWKTDatum, nDatumEPSGCode);
             psDatumInfo = asDatumInfoList+0; /* WGS 84 */
+        }
     }
 
     if( psDatumInfo != NULL )
@@ -1552,6 +2021,40 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         sTABProj.adDatumParams[2] = psDatumInfo->dfDatumParm2;
         sTABProj.adDatumParams[3] = psDatumInfo->dfDatumParm3;
         sTABProj.adDatumParams[4] = psDatumInfo->dfDatumParm4;
+
+        /* For LCC, standard parallel 1 and 2 can be switched indifferently */
+        /* So the MapInfo order and the EPSG order are not generally identical */
+        /* which may cause recognition problems when reading in MapInfo */
+        if( sTABProj.nProjId == 3 )
+        {
+            double dfCenterLong = parms[0];
+            double dfCenterLat = parms[1];
+            double dfStdP1 = parms[2];
+            double dfStdP2 = parms[3];
+
+            for(size_t i=0;i<sizeof(asMapInfoLCCSRSList)/sizeof(asMapInfoLCCSRSList[0]);i++)
+            {
+                if( sTABProj.nDatumId == asMapInfoLCCSRSList[i].nMapInfoDatumID &&
+                    TAB_EQUAL( dfCenterLong, asMapInfoLCCSRSList[i].dfCenterLong ) &&
+                    TAB_EQUAL( dfCenterLat, asMapInfoLCCSRSList[i].dfCenterLat ) )
+                {
+                    if( TAB_EQUAL( dfStdP1, asMapInfoLCCSRSList[i].dfStdP1 ) &&
+                        TAB_EQUAL( dfStdP2, asMapInfoLCCSRSList[i].dfStdP2 ) )
+                    {
+                        break;
+                    }
+                    else if( TAB_EQUAL( dfStdP1, asMapInfoLCCSRSList[i].dfStdP2 ) &&
+                                TAB_EQUAL( dfStdP2, asMapInfoLCCSRSList[i].dfStdP1 ) )
+                    {
+                        CPLDebug("MITAB", "Switching standard parallel 1 and 2");
+                        double dfTmp = parms[2];
+                        parms[2] = parms[3];
+                        parms[3] = dfTmp;
+                        break;
+                    }
+                }
+            }
+        }
     }
     
     /*-----------------------------------------------------------------
@@ -1594,17 +2097,6 @@ int TABFile::SetSpatialRef(OGRSpatialReference *poSpatialRef)
         sTABProj.nUnitsId = 0;
     else
         sTABProj.nUnitsId = 7;
-    
-    /*-----------------------------------------------------------------
-     * Set the new parameters in the .MAP header.
-     * This will also trigger lookup of default bounds for the projection.
-     *----------------------------------------------------------------*/
-    if ( SetProjInfo( &sTABProj ) != 0 )
-    {
-        CPLError(CE_Failure, CPLE_FileIO,
-                 "SetSpatialRef() failed setting projection parameters.");
-        return -1;
-    }
 
     return 0;
 }
diff --git a/ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp b/ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp
index be725fd..8d4d93a 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_tabfile.cpp
@@ -11,6 +11,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2003, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -102,9 +103,12 @@
 #include "mitab.h"
 #include "mitab_utils.h"
 #include "cpl_minixml.h"
+#include "ogr_p.h"
 
 #include <ctype.h>      /* isspace() */
 
+#define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
+
 /*=====================================================================
  *                      class TABFile
  *====================================================================*/
@@ -137,6 +141,10 @@ TABFile::TABFile()
 
     m_panMatchingFIDs = NULL; 
     m_iMatchingFID = 0; 
+    
+    m_bNeedTABRewrite = FALSE;
+    m_bLastOpWasRead = FALSE;
+    m_bLastOpWasWrite = FALSE;
 }
 
 /**********************************************************************
@@ -151,9 +159,10 @@ TABFile::~TABFile()
 
 
 /************************************************************************/
-/*                          GetFeatureCount()                           */
+/*                         GetFeatureCount()                          */
 /************************************************************************/
-int TABFile::GetFeatureCount (int bForce)
+
+GIntBig TABFile::GetFeatureCount (int bForce)
 {
     
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL || bForce)
@@ -210,6 +219,9 @@ void TABFile::ResetReading()
             }
         }
     }
+
+    m_bLastOpWasRead = FALSE;
+    m_bLastOpWasWrite = FALSE;
 }
 
 /**********************************************************************
@@ -218,7 +230,8 @@ void TABFile::ResetReading()
  * Open a .TAB dataset and the associated files, and initialize the 
  * structures to be ready to read features from (or write to) it.
  *
- * Supported access modes are "r" (read-only) and "w" (create new dataset).
+ * Supported access modes are "r" (read-only) and "w" (create new dataset or
+ * update).
  *
  * Set bTestOpenNoError=TRUE to silently return -1 with no error message
  * if the file cannot be opened.  This is intended to be used in the
@@ -234,7 +247,7 @@ void TABFile::ResetReading()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABFile::Open(const char *pszFname, const char *pszAccess,
+int TABFile::Open(const char *pszFname, TABAccess eAccess,
                   GBool bTestOpenNoError /*=FALSE*/ )
 {
     char *pszTmpFname = NULL;
@@ -249,30 +262,8 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
 
         return -1;
     }
-
-    /*-----------------------------------------------------------------
-     * Validate access mode
-     *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
-    {
-        m_eAccessMode = TABRead;
-        pszAccess = "rb";
-    }
-    else if (EQUALN(pszAccess, "w", 1))
-    {
-        m_eAccessMode = TABWrite;
-        pszAccess = "wb";
-    }
-    else
-    {
-        if (!bTestOpenNoError)
-            CPLError(CE_Failure, CPLE_FileIO,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
-        else
-            CPLErrorReset();
-
-        return -1;
-    }
+    
+    m_eAccessMode = eAccess;
 
     /*-----------------------------------------------------------------
      * Make sure filename has a .TAB extension... 
@@ -317,7 +308,7 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Handle .TAB file... depends on access mode.
      *----------------------------------------------------------------*/
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite )
     {
         /*-------------------------------------------------------------
          * Open .TAB file... since it's a small text file, we will just load
@@ -376,6 +367,8 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
         m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
         m_poDefn->Reference();
         CPLFree(pszFeatureClassName);
+
+        m_bNeedTABRewrite = TRUE;
     }
 
 
@@ -403,7 +396,7 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
 
     m_poDATFile = new TABDATFile;
    
-    if ( m_poDATFile->Open(pszTmpFname, pszAccess, m_eTableType) != 0)
+    if ( m_poDATFile->Open(pszTmpFname, eAccess, m_eTableType) != 0)
     {
         // Open Failed... an error has already been reported, just return.
         CPLFree(pszTmpFname);
@@ -420,7 +413,7 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Parse .TAB file field defs and build FeatureDefn (only in read access)
      *----------------------------------------------------------------*/
-    if (m_eAccessMode == TABRead && ParseTABFileFields() != 0)
+    if ( (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite) && ParseTABFileFields() != 0)
     {
         // Failed... an error has already been reported, just return.
         CPLFree(pszTmpFname);
@@ -448,13 +441,13 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
 #endif
 
     m_poMAPFile = new TABMAPFile;
-    if (m_eAccessMode == TABRead)
+    if (m_eAccessMode == TABRead || m_eAccessMode == TABReadWrite)
     {
         /*-------------------------------------------------------------
          * Read access: .MAP/.ID are optional... try to open but return
          * no error if files do not exist.
          *------------------------------------------------------------*/
-        if (m_poMAPFile->Open(pszTmpFname, pszAccess, TRUE) < 0)
+        if (m_poMAPFile->Open(pszTmpFname, eAccess, TRUE) < 0)
         {
             // File exists, but Open Failed... 
             // we have to produce an error message
@@ -485,7 +478,7 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
             /* we leave it unknown indicating a mixture */
         }
     }
-    else if (m_poMAPFile->Open(pszTmpFname, pszAccess) != 0)
+    else if (m_poMAPFile->Open(pszTmpFname, eAccess) != 0)
     {
         // Open Failed for write... 
         // an error has already been reported, just return.
@@ -531,11 +524,8 @@ int TABFile::Open(const char *pszFname, const char *pszAccess,
     CPLFree(pszTmpFname);
     pszTmpFname = NULL;
 
-    /*-----------------------------------------------------------------
-     * __TODO__ we could probably call GetSpatialRef() here to force
-     * parsing the projection information... this would allow us to 
-     * assignSpatialReference() on the geometries that we return.
-     *----------------------------------------------------------------*/
+    if( m_poDefn != NULL && m_eAccessMode != TABWrite )
+        m_poDefn->GetGeomFieldDefn(0)->SetSpatialRef(GetSpatialRef());
 
     return 0;
 }
@@ -557,7 +547,7 @@ int TABFile::ParseTABFileFirstPass(GBool bTestOpenNoError)
     char        **papszTok=NULL;
     GBool       bInsideTableDef = FALSE, bFoundTableFields=FALSE;
 
-    if (m_eAccessMode != TABRead)
+    if (m_eAccessMode == TABWrite)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "ParseTABFile() can be used only with Read access.");
@@ -694,7 +684,7 @@ int TABFile::ParseTABFileFields()
     char        **papszTok=NULL;
     OGRFieldDefn *poFieldDefn;
 
-    if (m_eAccessMode != TABRead)
+    if (m_eAccessMode == TABWrite)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "ParseTABFile() can be used only with Read access.");
@@ -760,6 +750,7 @@ int TABFile::ParseTABFileFields()
                 numTok = CSLCount(papszTok);
                 nStatus = -1;
                 CPLAssert(m_poDefn);
+                poFieldDefn = NULL;
                 if (numTok >= 3 && EQUAL(papszTok[1], "char"))
                 {
                     /*-------------------------------------------------
@@ -902,6 +893,7 @@ int TABFile::ParseTABFileFields()
                      "Failed to parse field definition at line %d in file %s", 
                              iLine+1, m_pszFname);
                     CSLDestroy(papszTok);
+                    delete poFieldDefn;
                     return -1;
                 }
                 /*-----------------------------------------------------
@@ -957,28 +949,34 @@ int TABFile::ParseTABFileFields()
  *
  * Generate the .TAB file using mainly the attribute fields definition.
  *
- * This private method should be used only during the Close() call with
- * write access mode.
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
 int TABFile::WriteTABFile()
 {
-    FILE *fp;
+    VSILFILE *fp;
 
-    if (m_eAccessMode != TABWrite)
+    if (m_poMAPFile == NULL || m_eAccessMode == TABRead)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
                  "WriteTABFile() can be used only with Write access.");
         return -1;
     }
+    if (!m_bNeedTABRewrite )
+    {
+        return 0;
+    }
+
+    // First update file version number...
+    int nMapObjVersion = m_poMAPFile->GetMinTABFileVersion();
+    m_nVersion = MAX(m_nVersion, nMapObjVersion);
 
-    if ( (fp = VSIFOpen(m_pszFname, "wt")) != NULL)
+    if ( (fp = VSIFOpenL(m_pszFname, "wt")) != NULL)
     {
-        fprintf(fp, "!table\n");
-        fprintf(fp, "!version %d\n", m_nVersion);
-        fprintf(fp, "!charset %s\n", m_pszCharset);
-        fprintf(fp, "\n");
+        VSIFPrintfL(fp, "!table\n");
+        VSIFPrintfL(fp, "!version %d\n", m_nVersion);
+        VSIFPrintfL(fp, "!charset %s\n", m_pszCharset);
+        VSIFPrintfL(fp, "\n");
 
         if (m_poDefn && m_poDefn->GetFieldCount() > 0)
         {
@@ -986,9 +984,9 @@ int TABFile::WriteTABFile()
             OGRFieldDefn *poFieldDefn;
             const char *pszFieldType;
 
-            fprintf(fp, "Definition Table\n");
-            fprintf(fp, "  Type NATIVE Charset \"%s\"\n", m_pszCharset);
-            fprintf(fp, "  Fields %d\n", m_poDefn->GetFieldCount());
+            VSIFPrintfL(fp, "Definition Table\n");
+            VSIFPrintfL(fp, "  Type NATIVE Charset \"%s\"\n", m_pszCharset);
+            VSIFPrintfL(fp, "  Fields %d\n", m_poDefn->GetFieldCount());
 
             for(iField=0; iField<m_poDefn->GetFieldCount(); iField++)
             {
@@ -1037,18 +1035,18 @@ int TABFile::WriteTABFile()
                     // Unsupported field type!!!  This should never happen.
                     CPLError(CE_Failure, CPLE_AssertionFailed,
                              "WriteTABFile(): Unsupported field type");
-                    VSIFClose(fp);
+                    VSIFCloseL(fp);
                     return -1;
                 }
 
                 if (GetFieldIndexNumber(iField) == 0)
                 {
-                    fprintf(fp, "    %s %s ;\n", poFieldDefn->GetNameRef(), 
+                    VSIFPrintfL(fp, "    %s %s ;\n", poFieldDefn->GetNameRef(), 
                             pszFieldType );
                 }
                 else
                 {
-                    fprintf(fp, "    %s %s Index %d ;\n", 
+                    VSIFPrintfL(fp, "    %s %s Index %d ;\n", 
                             poFieldDefn->GetNameRef(), pszFieldType,
                             GetFieldIndexNumber(iField) );
                 }
@@ -1057,13 +1055,15 @@ int TABFile::WriteTABFile()
         }
         else
         {
-            fprintf(fp, "Definition Table\n");
-            fprintf(fp, "  Type NATIVE Charset \"%s\"\n", m_pszCharset);
-            fprintf(fp, "  Fields 1\n");
-            fprintf(fp, "    FID Integer ;\n" );
+            VSIFPrintfL(fp, "Definition Table\n");
+            VSIFPrintfL(fp, "  Type NATIVE Charset \"%s\"\n", m_pszCharset);
+            VSIFPrintfL(fp, "  Fields 1\n");
+            VSIFPrintfL(fp, "    FID Integer ;\n" );
         }
 
-        VSIFClose(fp);
+        VSIFCloseL(fp);
+
+        m_bNeedTABRewrite = FALSE;
     }
     else
     {
@@ -1084,15 +1084,13 @@ int TABFile::WriteTABFile()
  **********************************************************************/
 int TABFile::Close()
 {
+    CPLErrorReset();
+
     // Commit the latest changes to the file...
     
     // In Write access, it's time to write the .TAB file.
-    if (m_eAccessMode == TABWrite && m_poMAPFile)
+    if (m_eAccessMode != TABRead)
     {
-        // First update file version number...
-        int nMapObjVersion = m_poMAPFile->GetMinTABFileVersion();
-        m_nVersion = MAX(m_nVersion, nMapObjVersion);
-
         WriteTABFile();
     }
 
@@ -1123,23 +1121,12 @@ int TABFile::Close()
         m_poCurFeature = NULL;
     }
 
-    /*-----------------------------------------------------------------
-     * Note: we have to check the reference count before deleting 
-     * m_poSpatialRef and m_poDefn
-     *----------------------------------------------------------------*/
     if (m_poDefn )
-    {
-        int nRefCount = m_poDefn->Dereference();
-
-        CPLAssert( nRefCount >= 0 );
-
-        if( nRefCount == 0 )
-            delete m_poDefn;
-        m_poDefn = NULL;
-    }
+        m_poDefn->Release();
+    m_poDefn = NULL;
     
-    if (m_poSpatialRef && m_poSpatialRef->Dereference() == 0)
-        delete m_poSpatialRef;
+    if (m_poSpatialRef)
+        m_poSpatialRef->Release();
     m_poSpatialRef = NULL;
     
     CSLDestroy(m_papszTABFile);
@@ -1198,20 +1185,20 @@ int TABFile::SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode/*=TRUE*/)
  * Returns feature id that follows nPrevId, or -1 if it is the
  * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
  **********************************************************************/
-int TABFile::GetNextFeatureId(int nPrevId)
+GIntBig TABFile::GetNextFeatureId(GIntBig nPrevId)
 {
-    if (m_eAccessMode != TABRead)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "GetNextFeatureId() can be used only with Read access.");
+    if( m_bLastOpWasWrite )
+        ResetReading();
+    m_bLastOpWasRead = TRUE;
+
+    if( (GIntBig)(int)nPrevId != nPrevId )
         return -1;
-    }
 
     /*-----------------------------------------------------------------
      * Are we using spatial rather than .ID based traversal?
      *----------------------------------------------------------------*/
     if( bUseSpatialTraversal )
-        return m_poMAPFile->GetNextFeatureId( nPrevId );
+        return m_poMAPFile->GetNextFeatureId( (int)nPrevId );
 
     /*-----------------------------------------------------------------
      * Should we use an attribute index traversal?
@@ -1241,7 +1228,7 @@ int TABFile::GetNextFeatureId(int nPrevId)
     if (nPrevId <= 0 && m_nLastFeatureId > 0)
         nFeatureId = 1;       // Feature Ids start at 1
     else if (nPrevId > 0 && nPrevId < m_nLastFeatureId)
-        nFeatureId = nPrevId + 1;
+        nFeatureId = (int)nPrevId + 1;
     else
     {
         // This was the last feature
@@ -1326,17 +1313,10 @@ int TABFile::GetNextFeatureId_Spatial(int nPrevId)
  * and a warning will be produced with code TAB_WarningFeatureTypeNotSupported
  * CPLGetLastErrorNo() should be used to detect that case.
  **********************************************************************/
-TABFeature *TABFile::GetFeatureRef(int nFeatureId)
+TABFeature *TABFile::GetFeatureRef(GIntBig nFeatureId)
 {
     CPLErrorReset();
 
-    if (m_eAccessMode != TABRead)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "GetFeatureRef() can be used only with Read access.");
-        return NULL;
-    }
-
     /*-----------------------------------------------------------------
      * Make sure file is opened and Validate feature id by positioning
      * the read pointers for the .MAP and .DAT files to this feature id.
@@ -1348,10 +1328,13 @@ TABFeature *TABFile::GetFeatureRef(int nFeatureId)
         return NULL;
     }
 
+    if( m_bLastOpWasWrite )
+        ResetReading();
+    m_bLastOpWasRead = TRUE;
 
     if (nFeatureId <= 0 || nFeatureId > m_nLastFeatureId ||
-        m_poMAPFile->MoveToObjId(nFeatureId) != 0 ||
-        m_poDATFile->GetRecordBlock(nFeatureId) == NULL )
+        m_poMAPFile->MoveToObjId((int)nFeatureId) != 0 ||
+        m_poDATFile->GetRecordBlock((int)nFeatureId) == NULL )
     {
         //     CPLError(CE_Failure, CPLE_IllegalArg,
         //    "GetFeatureRef() failed: invalid feature id %d", 
@@ -1359,6 +1342,17 @@ TABFeature *TABFile::GetFeatureRef(int nFeatureId)
         return NULL;
     }
     
+    if( m_poDATFile->IsCurrentRecordDeleted() )
+    {
+        if( m_poMAPFile->GetCurObjType() != TAB_GEOM_NONE )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                    "Valid .MAP record " CPL_FRMT_GIB " found, but .DAT is marked as deleted. File likely corrupt",
+                    nFeatureId);
+        }
+        return NULL;
+    }
+    
     /*-----------------------------------------------------------------
      * Flush current feature object
      * __TODO__ try to reuse if it is already of the right type
@@ -1393,7 +1387,7 @@ TABFeature *TABFile::GetFeatureRef(int nFeatureId)
      * MoveToObjId() has already been called above...
      *----------------------------------------------------------------*/
     TABMAPObjHdr *poObjHdr = 
-        TABMAPObjHdr::NewObj((GByte)m_poMAPFile->GetCurObjType(), 
+        TABMAPObjHdr::NewObj(m_poMAPFile->GetCurObjType(), 
                              m_poMAPFile->GetCurObjId());
     // Note that poObjHdr==NULL is a valid case if geometry type is NONE
 
@@ -1418,34 +1412,80 @@ TABFeature *TABFile::GetFeatureRef(int nFeatureId)
 }
 
 /**********************************************************************
- *                   TABFile::WriteFeature()
- *
- * Write a feature to this dataset.  
- *
- * For now only sequential writes are supported (i.e. with nFeatureId=-1)
- * but eventually we should be able to do random access by specifying
- * a value through nFeatureId.
+ *                   TABFile::DeleteFeature()
  *
- * Returns the new featureId (> 0) on success, or -1 if an
- * error happened in which case, CPLError() will have been called to
- * report the reason of the failure.
+ * Standard OGR DeleteFeature implementation.
  **********************************************************************/
-int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
+OGRErr TABFile::DeleteFeature(GIntBig nFeatureId)
 {
-    if (m_eAccessMode != TABWrite)
+    CPLErrorReset();
+
+    if (m_eAccessMode == TABRead)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
-                 "WriteFeature() can be used only with Write access.");
-        return -1;
+                 "DeleteFeature() cannot be used in read-only access.");
+        return OGRERR_FAILURE;
+    }
+
+    /*-----------------------------------------------------------------
+     * Make sure file is opened and establish new feature id.
+     *----------------------------------------------------------------*/
+    if (m_poMAPFile == NULL)
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg,
+                 "DeleteFeature() failed: file is not opened!");
+        return OGRERR_FAILURE;
     }
 
-    if (nFeatureId != -1)
+    if( m_bLastOpWasWrite )
+        ResetReading();
+
+    if (nFeatureId <= 0 || nFeatureId > m_nLastFeatureId ||
+        m_poMAPFile->MoveToObjId((int)nFeatureId) != 0 ||
+        m_poDATFile->GetRecordBlock((int)nFeatureId) == NULL )
     {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "WriteFeature(): random access not implemented yet.");
-        return -1;
+        /*CPLError(CE_Failure, CPLE_IllegalArg,
+                 "DeleteFeature() failed: invalid feature id " CPL_FRMT_GIB, 
+                 nFeatureId);*/
+        return OGRERR_NON_EXISTING_FEATURE;
+    }
+    
+    if( m_poDATFile->IsCurrentRecordDeleted() )
+    {
+        /*CPLError(CE_Failure, CPLE_IllegalArg,
+                 "DeleteFeature() failed: record is already deleted!");*/
+        return OGRERR_NON_EXISTING_FEATURE;
+    }
+
+    if (m_poCurFeature)
+    {
+        delete m_poCurFeature;
+        m_poCurFeature = NULL;
+    }
+    
+    if( m_poMAPFile->MarkAsDeleted() != 0 ||
+        m_poDATFile->MarkAsDeleted() != 0 )
+    {
+        return OGRERR_FAILURE;
     }
 
+    return OGRERR_NONE;
+}
+
+/**********************************************************************
+ *                   TABFile::WriteFeature()
+ *
+ * Write a feature to this dataset.  
+ *
+ * Returns 0 on success, or -1 if an error happened in which case,
+ * CPLError() will have been called to
+ * report the reason of the failure.
+ **********************************************************************/
+int TABFile::WriteFeature(TABFeature *poFeature)
+{
+
+    m_bLastOpWasWrite = TRUE;
+
     /*-----------------------------------------------------------------
      * Make sure file is opened and establish new feature id.
      *----------------------------------------------------------------*/
@@ -1456,15 +1496,13 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
         return -1;
     }
 
-    if (m_nLastFeatureId < 1)
+    int nFeatureId;
+    if ( poFeature->GetFID() >= 0 )
+    {
+        nFeatureId = (int)poFeature->GetFID();
+    }
+    else if (m_nLastFeatureId < 1)
     {
-        /*-------------------------------------------------------------
-         * OK, this is the first feature in the dataset... make sure the
-         * .DAT schema has been initialized.
-         *------------------------------------------------------------*/
-        if (m_poDefn == NULL)
-            SetFeatureDefn(poFeature->GetDefnRef(), NULL);
-
         /*-------------------------------------------------------------
          * Special hack to write out at least one field if none are in 
          * OGRFeatureDefn.
@@ -1473,22 +1511,24 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
         {
             CPLError(CE_Warning, CPLE_IllegalArg,
                      "MapInfo tables must contain at least 1 column, adding dummy FID column.");
+            CPLErrorReset();
             m_poDATFile->AddField("FID", TABFInteger, 10, 0 );
         }
 
-        nFeatureId = m_nLastFeatureId = 1;
+        nFeatureId = 1;
     }
     else
     {
-        nFeatureId = ++ m_nLastFeatureId;
+        nFeatureId = m_nLastFeatureId + 1;
     }
 
+    poFeature->SetFID(nFeatureId);
+
 
     /*-----------------------------------------------------------------
      * Write fields to the .DAT file and update .IND if necessary
      *----------------------------------------------------------------*/
-    if (m_poDATFile == NULL ||
-        m_poDATFile->GetRecordBlock(nFeatureId) == NULL ||
+    if (m_poDATFile->GetRecordBlock(nFeatureId) == NULL ||
         poFeature->WriteRecordToDATFile(m_poDATFile, m_poINDFile,
                                         m_panIndexNo) != 0 )
     {
@@ -1503,9 +1543,19 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
      * The call to PrepareNewObj() takes care of the .ID file.
      *----------------------------------------------------------------*/
     TABMAPObjHdr *poObjHdr = 
-        TABMAPObjHdr::NewObj((GByte)poFeature->ValidateMapInfoType(m_poMAPFile),
+        TABMAPObjHdr::NewObj(poFeature->ValidateMapInfoType(m_poMAPFile),
                              nFeatureId);
-    
+
+    if ( poObjHdr == NULL || m_poMAPFile == NULL )
+    {
+        CPLError(CE_Failure, CPLE_FileIO,
+                 "Failed writing geometry for feature id %d in %s",
+                 nFeatureId, m_pszFname);
+        if (poObjHdr)
+            delete poObjHdr;
+        return -1;
+    }
+
     /*-----------------------------------------------------------------
      * ValidateMapInfoType() may have returned TAB_GEOM_NONE if feature
      * contained an invalid geometry for its class. Need to catch that
@@ -1531,8 +1581,14 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
                              poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
     }
 
-    if ( poObjHdr == NULL || m_poMAPFile == NULL ||
-         m_poMAPFile->PrepareNewObj(poObjHdr) != 0 ||
+/*
+    if( m_nCurFeatureId < m_nLastFeatureId )
+    {
+        delete GetFeatureRef(m_nLastFeatureId);
+        m_poCurFeature = NULL;
+    }*/
+
+    if ( m_poMAPFile->PrepareNewObj(poObjHdr) != 0 ||
          poFeature->WriteGeometryToMAPFile(m_poMAPFile, poObjHdr) != 0 ||
          m_poMAPFile->CommitNewObj(poObjHdr) != 0 )
     {
@@ -1543,10 +1599,13 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
             delete poObjHdr;
         return -1;
     }
+    
+    m_nLastFeatureId = MAX(m_nLastFeatureId, nFeatureId);
+    m_nCurFeatureId = nFeatureId;
 
     delete poObjHdr;
 
-    return nFeatureId;
+    return 0;
 }
 
 
@@ -1562,30 +1621,173 @@ int TABFile::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
  **********************************************************************/
 OGRErr TABFile::CreateFeature(TABFeature *poFeature)
 {
-    int nFeatureId = -1;
-
-    nFeatureId = WriteFeature(poFeature, -1);
+    CPLErrorReset();
 
-    if (nFeatureId == -1)
+    if (m_eAccessMode == TABRead)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "CreateFeature() cannot be used in read-only access.");
         return OGRERR_FAILURE;
+    }
 
-    poFeature->SetFID(nFeatureId);
+    GIntBig nFeatureId = poFeature->GetFID();
+    if (nFeatureId != OGRNullFID )
+    {
+        if (nFeatureId <= 0 || nFeatureId > m_nLastFeatureId )
+        {
+            CPLError(CE_Failure, CPLE_IllegalArg,
+                     "CreateFeature() failed: invalid feature id " CPL_FRMT_GIB, 
+                      nFeatureId);
+            return OGRERR_FAILURE;
+        }
+
+        if( m_poDATFile->GetRecordBlock((int)nFeatureId) == NULL ||
+            !m_poDATFile->IsCurrentRecordDeleted() )
+        {
+            CPLError(CE_Failure, CPLE_IllegalArg,
+                    "CreateFeature() failed: cannot re-write already existing feature " CPL_FRMT_GIB, 
+                    nFeatureId);
+            return OGRERR_FAILURE;
+        }
+    }
+
+    if (WriteFeature(poFeature) < 0)
+        return OGRERR_FAILURE;
 
     return OGRERR_NONE;
 }
 
 /**********************************************************************
- *                   TABFile::SetFeature()
+ *                   TABFile::ISetFeature()
  *
- * Implementation of OGRLayer's SetFeature(), enabled only for
- * random write access   
+ * Implementation of OGRLayer's SetFeature()
  **********************************************************************/
-OGRErr TABFile::SetFeature( CPL_UNUSED OGRFeature *poFeature )
+OGRErr TABFile::ISetFeature( OGRFeature *poFeature )
+
 {
-//TODO: See CreateFeature()
-// Need to convert OGRFeature to TABFeature, extract FID and then forward
-// forward call to SetFeature(TABFeature, fid)
-    return OGRERR_UNSUPPORTED_OPERATION;
+    CPLErrorReset();
+
+    if (m_eAccessMode == TABRead)
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetFeature() cannot be used in read-only access.");
+        return -1;
+    }
+
+    /*-----------------------------------------------------------------
+     * Make sure file is opened.
+     *----------------------------------------------------------------*/
+    if (m_poMAPFile == NULL)
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg,
+                 "SetFeature() failed: file is not opened!");
+        return OGRERR_FAILURE;
+    }
+    
+    GIntBig nFeatureId = poFeature->GetFID();
+    if (nFeatureId == OGRNullFID )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetFeature() must be used on a feature with a FID.");
+        return OGRERR_FAILURE;
+    }
+    if (nFeatureId <= 0 || nFeatureId > m_nLastFeatureId )
+    {
+        /*CPLError(CE_Failure, CPLE_IllegalArg,
+                    "SetFeature() failed: invalid feature id " CPL_FRMT_GIB, 
+                    nFeatureId);*/
+        return OGRERR_NON_EXISTING_FEATURE;
+    }
+
+    OGRGeometry* poGeom = poFeature->GetGeometryRef();
+    if( poGeom != NULL &&
+        ((wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint) ||
+         (wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)) )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "SetFeature() failed: setting MultiPoint or GeometryCollection not supported");
+        return OGRERR_FAILURE;
+    }
+
+    TABFeature* poTABFeature = CreateTABFeature(poFeature);
+    if( poTABFeature == NULL )
+        return OGRERR_FAILURE;
+
+    if( m_bLastOpWasWrite )
+        ResetReading();
+
+    if (m_poDATFile->GetRecordBlock((int)nFeatureId) == NULL )
+    {
+        /*CPLError(CE_Failure, CPLE_IllegalArg,
+                 "SetFeature() failed: invalid feature id " CPL_FRMT_GIB, 
+                 nFeatureId);*/
+        delete poTABFeature;
+        return OGRERR_NON_EXISTING_FEATURE;
+    }
+
+    /* If the object is not already deleted, delete it */
+    if( !(m_poDATFile->IsCurrentRecordDeleted()) )
+    {
+        OGRFeature* poOldFeature = GetFeature(nFeatureId);
+        if( poOldFeature != NULL )
+        {
+            /* Optimization: if old and new features are the same, do nothing */
+            if( poOldFeature->Equal(poFeature) )
+            {
+                CPLDebug("MITAB", "Un-modified object " CPL_FRMT_GIB, nFeatureId);
+                delete poTABFeature;
+                delete poOldFeature;
+                return OGRERR_NONE;
+            }
+
+            /* Optimization: if old and new geometries are the same, just */
+            /* rewrite the attributes */
+            OGRGeometry* poOldGeom = poOldFeature->GetGeometryRef();
+            OGRGeometry* poNewGeom = poFeature->GetGeometryRef();
+            if( (poOldGeom == NULL && poNewGeom == NULL ) ||
+                (poOldGeom != NULL && poNewGeom != NULL && poOldGeom->Equals(poNewGeom)) )
+            {
+                const char* pszOldStyle = poOldFeature->GetStyleString();
+                const char* pszNewStyle = poFeature->GetStyleString();
+                if( (pszOldStyle == NULL && pszNewStyle == NULL) ||
+                    (pszOldStyle != NULL && pszNewStyle != NULL && EQUAL(pszOldStyle, pszNewStyle)) )
+                {
+                    CPLDebug("MITAB", "Rewrite only attributes for object " CPL_FRMT_GIB, nFeatureId);
+                    if (poTABFeature->WriteRecordToDATFile(m_poDATFile, m_poINDFile,
+                                                        m_panIndexNo) != 0 )
+                    {
+                        CPLError(CE_Failure, CPLE_FileIO,
+                                "Failed writing attributes for feature id " CPL_FRMT_GIB " in %s",
+                                nFeatureId, m_pszFname);
+                        delete poTABFeature;
+                        delete poOldFeature;
+                        return OGRERR_FAILURE;
+                    }
+
+                    delete poTABFeature;
+                    delete poOldFeature;
+                    return OGRERR_NONE;
+                }
+            }
+
+            delete poOldFeature;
+        }
+
+        if (DeleteFeature(nFeatureId) != OGRERR_NONE)
+        {
+            delete poTABFeature;
+            return OGRERR_FAILURE;
+        }
+    }
+
+    int nStatus = WriteFeature(poTABFeature);
+    
+    delete poTABFeature;
+    
+    if (nStatus < 0)
+        return OGRERR_FAILURE;
+
+    return OGRERR_NONE;
 }
 
 
@@ -1725,8 +1927,7 @@ int TABFile::SetFeatureDefn(OGRFeatureDefn *poFeatureDefn,
  *
  * Create a new field using a native mapinfo data type... this is an 
  * alternative to defining fields through the OGR interface.
- * This function should be called after creating a new dataset, but before 
- * writing the first feature.
+ * This function should be called after creating a new dataset.
  *
  * This function will build/update the OGRFeatureDefn that will have to be
  * used when writing features to this dataset.
@@ -1747,36 +1948,14 @@ int TABFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
     char szNewFieldName[31+1]; /* 31 is the max characters for a field name*/
     int nRenameNum = 1;
 
-    if (m_eAccessMode != TABWrite)
+    if (m_eAccessMode == TABRead || m_poDATFile == NULL)
     {
         CPLError(CE_Failure, CPLE_NotSupported,
-                 "AddFieldNative() can be used only with Write access.");
-        return -1;
-    }
-
-    /*-----------------------------------------------------------------
-     * Check that call happens at the right time in dataset's life.
-     *----------------------------------------------------------------*/
-    if (m_eAccessMode != TABWrite || 
-        m_nLastFeatureId > 0 || m_poDATFile == NULL)
-    {
-        CPLError(CE_Failure, CPLE_AssertionFailed,
-                 "AddFieldNative() must be called after opening a new "
-                 "dataset, but before writing the first feature to it.");
+                 "AddFieldNative() cannot be used only with Read access.");
         return -1;
     }
 
-    /*-----------------------------------------------------------------
-     * Create new OGRFeatureDefn if not done yet...
-     *----------------------------------------------------------------*/
-    if (m_poDefn== NULL)
-    {
-        char *pszFeatureClassName = TABGetBasename(m_pszFname);
-        m_poDefn = new OGRFeatureDefn(pszFeatureClassName);
-        CPLFree(pszFeatureClassName);
-        // Ref count defaults to 0... set it to 1
-        m_poDefn->Reference();
-    }
+    m_bNeedTABRewrite = TRUE;
 
     /*-----------------------------------------------------------------
      * Validate field width... must be <= 254
@@ -1958,6 +2137,9 @@ int TABFile::AddFieldNative(const char *pszName, TABFieldType eMapInfoType,
     if (nStatus == 0 && bIndexed)
         nStatus = SetFieldIndexed(m_poDefn->GetFieldCount()-1);
 
+    if (nStatus == 0 && m_eAccessMode == TABReadWrite)
+        nStatus = WriteTABFile();
+
     CPLFree(pszCleanName);
     return nStatus;
 }
@@ -2241,7 +2423,8 @@ int TABFile::GetBounds(double &dXMin, double &dYMin,
  *
  * Returns OGRERR_NONE/OGRRERR_FAILURE.
  **********************************************************************/
-OGRErr TABFile::GetExtent (OGREnvelope *psExtent, CPL_UNUSED int bForce)
+OGRErr TABFile::GetExtent (OGREnvelope *psExtent,
+                           CPL_UNUSED int bForce)
 {
     TABMAPHeaderBlock *poHeader;
 
@@ -2401,6 +2584,17 @@ int TABFile::SetProjInfo(TABProjInfo *poPI)
     }
 
     /*-----------------------------------------------------------------
+     * Lookup default bounds and reset m_bBoundsSet flag
+     *----------------------------------------------------------------*/
+    double dXMin, dYMin, dXMax, dYMax;
+
+    m_bBoundsSet = FALSE;
+    if (MITABLookupCoordSysBounds(poPI, dXMin, dYMin, dXMax, dYMax) == TRUE)
+    {
+        SetBounds(dXMin, dYMin, dXMax, dYMax);
+    }
+
+    /*-----------------------------------------------------------------
      * Check that dataset has been created but no feature set yet.
      *----------------------------------------------------------------*/
     if (m_poMAPFile && m_nLastFeatureId < 1)
@@ -2416,20 +2610,167 @@ int TABFile::SetProjInfo(TABProjInfo *poPI)
         return -1;
     }
 
-    /*-----------------------------------------------------------------
-     * Lookup default bounds and reset m_bBoundsSet flag
-     *----------------------------------------------------------------*/
-    double dXMin, dYMin, dXMax, dYMax;
+    return 0;
+}
 
-    m_bBoundsSet = FALSE;
-    if (MITABLookupCoordSysBounds(poPI, dXMin, dYMin, dXMax, dYMax) == TRUE)
+
+/************************************************************************/
+/*                            DeleteField()                             */
+/************************************************************************/
+
+OGRErr TABFile::DeleteField( int iField )
+{
+    if( m_poDATFile == NULL || !TestCapability(OLCDeleteField) )
     {
-        SetBounds(dXMin, dYMin, dXMax, dYMax);
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  UNSUPPORTED_OP_READ_ONLY,
+                  "DeleteField");
+        return OGRERR_FAILURE;
     }
 
-    return 0;
+    if (iField < 0 || iField >= m_poDefn->GetFieldCount())
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Invalid field index");
+        return OGRERR_FAILURE;
+    }
+
+    if ( m_poDATFile->DeleteField( iField ) == 0 )
+    {
+        m_bNeedTABRewrite = TRUE;
+
+        /* Delete from the array of indexed fields */
+        if( iField < m_poDefn->GetFieldCount() - 1 )
+        {
+            memmove(m_panIndexNo + iField, m_panIndexNo + iField + 1,
+                    (m_poDefn->GetFieldCount() - 1 - iField) * sizeof(int));
+        }
+
+        m_poDefn->DeleteFieldDefn( iField );
+
+        if (m_eAccessMode == TABReadWrite)
+            WriteTABFile();
+
+        return OGRERR_NONE;
+    }
+    else
+        return OGRERR_FAILURE;
 }
 
+/************************************************************************/
+/*                           ReorderFields()                            */
+/************************************************************************/
+
+OGRErr TABFile::ReorderFields( int* panMap )
+{
+    if( m_poDATFile == NULL || !TestCapability(OLCDeleteField) )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  UNSUPPORTED_OP_READ_ONLY,
+                  "ReorderFields");
+        return OGRERR_FAILURE;
+    }
+    if (m_poDefn->GetFieldCount() == 0)
+        return OGRERR_NONE;
+
+    OGRErr eErr = OGRCheckPermutation(panMap, m_poDefn->GetFieldCount());
+    if (eErr != OGRERR_NONE)
+        return eErr;
+
+    if ( m_poDATFile->ReorderFields( panMap ) == 0 )
+    {
+        m_bNeedTABRewrite = TRUE;
+
+        int* panNewIndexedField = (int*) CPLMalloc(sizeof(int)*m_poDefn->GetFieldCount());
+        for(int i=0;i<m_poDefn->GetFieldCount();i++)
+        {
+            panNewIndexedField[i] = m_panIndexNo[panMap[i]];
+        }
+        CPLFree(m_panIndexNo);
+        m_panIndexNo = panNewIndexedField;
+
+        m_poDefn->ReorderFieldDefns( panMap );
+
+        if (m_eAccessMode == TABReadWrite)
+            WriteTABFile();
+
+        return OGRERR_NONE;
+    }
+    else
+        return OGRERR_FAILURE;
+}
+
+/************************************************************************/
+/*                           AlterFieldDefn()                           */
+/************************************************************************/
+
+OGRErr TABFile::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags )
+{
+    if( m_poDATFile == NULL || !TestCapability(OLCDeleteField) )
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  UNSUPPORTED_OP_READ_ONLY,
+                  "AlterFieldDefn");
+        return OGRERR_FAILURE;
+    }
+
+    if (iField < 0 || iField >= m_poDefn->GetFieldCount())
+    {
+        CPLError( CE_Failure, CPLE_NotSupported,
+                  "Invalid field index");
+        return OGRERR_FAILURE;
+    }
+
+    if ( m_poDATFile->AlterFieldDefn( iField, poNewFieldDefn, nFlags ) == 0 )
+    {
+        m_bNeedTABRewrite = TRUE;
+
+        OGRFieldDefn* poFieldDefn = m_poDefn->GetFieldDefn(iField);
+        if ((nFlags & ALTER_TYPE_FLAG) &&
+            poNewFieldDefn->GetType() != poFieldDefn->GetType())
+        {
+            poFieldDefn->SetType(poNewFieldDefn->GetType());
+            if( (nFlags & ALTER_WIDTH_PRECISION_FLAG) == 0 )
+                poFieldDefn->SetWidth(254);
+        }
+        if (nFlags & ALTER_NAME_FLAG)
+            poFieldDefn->SetName(poNewFieldDefn->GetNameRef());
+        if ((nFlags & ALTER_WIDTH_PRECISION_FLAG) &&
+            poFieldDefn->GetType() == OFTString)
+        {
+            poFieldDefn->SetWidth(m_poDATFile->GetFieldWidth(iField));
+        }
+
+        if (m_eAccessMode == TABReadWrite)
+            WriteTABFile();
+
+        return OGRERR_NONE;
+    }
+    else
+        return OGRERR_FAILURE;
+}
+
+/************************************************************************/
+/*                            SyncToDisk()                             */
+/************************************************************************/
+
+OGRErr TABFile::SyncToDisk()
+{
+    /* Silently return */
+    if( m_eAccessMode == TABRead )
+        return OGRERR_NONE;
+
+    if( WriteTABFile() != 0 )
+        return OGRERR_FAILURE;
+
+    if( m_poMAPFile->SyncToDisk() != 0 )
+        return OGRERR_FAILURE;
+
+    if( m_poDATFile->SyncToDisk() != 0 )
+        return OGRERR_FAILURE;
+
+    return OGRERR_NONE;
+}
 
 /************************************************************************/
 /*                           TestCapability()                           */
@@ -2442,10 +2783,13 @@ int TABFile::TestCapability( const char * pszCap )
         return TRUE;
 
     else if( EQUAL(pszCap,OLCSequentialWrite) )
-        return m_eAccessMode == TABWrite;
+        return m_eAccessMode != TABRead;
 
     else if( EQUAL(pszCap,OLCRandomWrite) )
-        return FALSE;
+        return m_eAccessMode != TABRead;
+
+    else if( EQUAL(pszCap,OLCDeleteFeature) )
+        return m_eAccessMode != TABRead;
 
     else if( EQUAL(pszCap,OLCFastFeatureCount) )
         return m_poFilterGeom == NULL
@@ -2458,7 +2802,16 @@ int TABFile::TestCapability( const char * pszCap )
         return TRUE;
 
     else if( EQUAL(pszCap,OLCCreateField) )
-        return TRUE;
+        return m_eAccessMode != TABRead;
+
+    else if( EQUAL(pszCap,OLCDeleteField) )
+        return m_eAccessMode != TABRead;
+
+    else if( EQUAL(pszCap,OLCReorderFields) )
+        return m_eAccessMode != TABRead;
+
+    else if( EQUAL(pszCap,OLCAlterFieldDefn) )
+        return m_eAccessMode != TABRead;
 
     else 
         return FALSE;
diff --git a/ogr/ogrsf_frmts/mitab/mitab_tabseamless.cpp b/ogr/ogrsf_frmts/mitab/mitab_tabseamless.cpp
index c9b9c6b..fa40e18 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_tabseamless.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_tabseamless.cpp
@@ -10,6 +10,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2004, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -82,11 +83,8 @@
  *  - Read-only
  *  - Base tables can only be of type TABFile
  *  - Feature Ids are build using the id of the base table in the main
- *    index table and the actual feature id of each object inside the base
- *    tables.  Since we are limited to 32 bits for feature ids, this implies
- *    a limit on the (number of base tables) * (features/table)
- *    The current implementation can support up to 2047 (0x7ff) base tables
- *    and a max of 1048575 (0xfffff) features per base table.
+ *    index table (upper 32 bits) and the actual feature id of each object
+ *    inside the base tables (lower 32 bits).
  *  - Only relative paths are supported for base tables names.
  *    
  *====================================================================*/
@@ -107,8 +105,6 @@ TABSeamless::TABSeamless()
     m_nCurFeatureId = -1;
     
     m_poIndexTable = NULL;
-    m_nIndexTableFIDBits = 0;
-    m_nIndexTableFIDMask = 0;
     m_nTableNameField = -1;
     m_nCurBaseTableId = -1;
     m_poCurBaseTable = NULL;
@@ -153,7 +149,7 @@ void TABSeamless::ResetReading()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABSeamless::Open(const char *pszFname, const char *pszAccess,
+int TABSeamless::Open(const char *pszFname, TABAccess eAccess,
                       GBool bTestOpenNoError /*= FALSE*/ )
 {
     char nStatus = 0;
@@ -168,7 +164,7 @@ int TABSeamless::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Validate access mode and call the right open method
      *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
+    if (eAccess == TABRead)
     {
         m_eAccessMode = TABRead;
         nStatus = (char)OpenForRead(pszFname, bTestOpenNoError);
@@ -176,7 +172,7 @@ int TABSeamless::Open(const char *pszFname, const char *pszAccess,
     else
     {
         CPLError(CE_Failure, CPLE_NotSupported,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+                 "Open() failed: access mode \"%d\" not supported", eAccess);
         return -1;
     }
 
@@ -283,7 +279,7 @@ int TABSeamless::OpenForRead(const char *pszFname,
      * should contain the path to the base table for each rectangle MBR
      *----------------------------------------------------------------*/
     m_poIndexTable = new TABFile;
-    if (m_poIndexTable->Open(m_pszFname, "rb", bTestOpenNoError) != 0)
+    if (m_poIndexTable->Open(m_pszFname, m_eAccessMode, bTestOpenNoError) != 0)
     {
         // Open Failed... an error has already been reported, just return.
         if (bTestOpenNoError)
@@ -306,13 +302,6 @@ int TABSeamless::OpenForRead(const char *pszFname,
         return -1;        
     }
 
-    /* Set the number of bits required to encode features for this index
-     * table. (Based of the number of features)
-     */
-    int s=0, numFeatures = m_poIndexTable->GetFeatureCount(FALSE);
-    do s++, numFeatures>>=1; while(numFeatures);
-    m_nIndexTableFIDBits= s+1;
-
     /*-----------------------------------------------------------------
      * We need to open the first table to get its FeatureDefn
      *----------------------------------------------------------------*/
@@ -346,8 +335,8 @@ int TABSeamless::Close()
         delete m_poIndexTable;  // Automatically closes.
     m_poIndexTable = NULL;
 
-    if (m_poFeatureDefnRef && m_poFeatureDefnRef->Dereference() == 0)
-        delete m_poFeatureDefnRef;
+    if (m_poFeatureDefnRef )
+        m_poFeatureDefnRef->Release();
     m_poFeatureDefnRef = NULL;
 
     if (m_poCurFeature)
@@ -387,7 +376,9 @@ int TABSeamless::OpenBaseTable(TABFeature *poIndexFeature,
      * Fetch table id.  We actually use the index feature's ids as the
      * base table ids.
      *----------------------------------------------------------------*/
-    int nTableId = poIndexFeature->GetFID();
+    GIntBig nTableId64 = poIndexFeature->GetFID();
+    int nTableId = (int)nTableId64;
+    CPLAssert((GIntBig)nTableId == nTableId64);
 
     if (m_nCurBaseTableId == nTableId && m_poCurBaseTable != NULL)
     {
@@ -422,7 +413,7 @@ int TABSeamless::OpenBaseTable(TABFeature *poIndexFeature,
 #endif
 
     m_poCurBaseTable = new TABFile;
-    if (m_poCurBaseTable->Open(pszFname, "rb", bTestOpenNoError) != 0)
+    if (m_poCurBaseTable->Open(pszFname, m_eAccessMode, bTestOpenNoError) != 0)
     {
         // Open Failed... an error has already been reported, just return.
         if (bTestOpenNoError)
@@ -432,32 +423,6 @@ int TABSeamless::OpenBaseTable(TABFeature *poIndexFeature,
         CPLFree(pszFname);
         return -1;
     }
-    
-    /* Set the number of bits required to encode feature id for this base
-     * table. (Based of the number of features) This will be used for
-     * encode and extract feature ID.
-     */
-    int s=0, nCurBaseTableFIDBits = 0,
-        numFeatures = m_poCurBaseTable->GetFeatureCount(FALSE);
-    do s++, numFeatures>>=1; while(numFeatures);
-    nCurBaseTableFIDBits = s;
-
-    /* Check if we can encode feature IDs in 32 bits to avoid overflow */
-    if (nCurBaseTableFIDBits + m_nIndexTableFIDBits > 32)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "Open() failed: feature ids cannot be encoded in 32 bits "
-                 "for the index table (%s) and the base table (%s).", 
-                 m_pszFname, pszName);
-        if (bTestOpenNoError)
-            CPLErrorReset();
-        delete m_poCurBaseTable;
-        m_poCurBaseTable = NULL;
-        CPLFree(pszFname);
-        return -1;
-    }
-   
-    m_nIndexTableFIDMask = (32-m_nIndexTableFIDBits);
 
     // Set the spatial filter to the new table 
     if( m_poFilterGeom != NULL &&  m_poCurBaseTable )
@@ -562,19 +527,8 @@ int TABSeamless::OpenNextBaseTable(GBool bTestOpenNoError /*=FALSE*/)
  *
  * Combine the table id + feature id into a single feature id that should
  * be unique amongst all base tables in this seamless dataset.
- *
- * We reserve some bits in the feature id for the table id based on the
- * number of features in the index table.  This reduces the available range
- * of feature ids for each base table... for instance, if the index contains
- * 65000 entries, then each base table will be limited to 65535 features.
- *
- * If the number of features in a base table exceeds the number of bits
- * available (e.g. 65535 inthe above example) then the feature ids will
- * wrap for this table and thus it will be impossible to access some of
- * the features unless the caller uses only calls to GetNextFeature() and
- * avoids calls to GetFeatureRef().
  **********************************************************************/
-int TABSeamless::EncodeFeatureId(int nTableId, int nBaseFeatureId)
+GIntBig TABSeamless::EncodeFeatureId(int nTableId, int nBaseFeatureId)
 {
     if (nTableId == -1 || nBaseFeatureId == -1)
         return -1;
@@ -582,23 +536,23 @@ int TABSeamless::EncodeFeatureId(int nTableId, int nBaseFeatureId)
     /* Feature encoding is now based on the numbers of bits on the number
        of features in the index table. */
 
-    return ((nTableId<<m_nIndexTableFIDMask) + nBaseFeatureId);
+    return (((GIntBig)nTableId<<32) + nBaseFeatureId);
 }
 
-int TABSeamless::ExtractBaseTableId(int nEncodedFeatureId)
+int TABSeamless::ExtractBaseTableId(GIntBig nEncodedFeatureId)
 {
     if (nEncodedFeatureId == -1)
         return -1;
 
-    return ((nEncodedFeatureId>>m_nIndexTableFIDMask));
+    return ((int)(nEncodedFeatureId>>32));
 }
 
-int TABSeamless::ExtractBaseFeatureId(int nEncodedFeatureId)
+int TABSeamless::ExtractBaseFeatureId(GIntBig nEncodedFeatureId)
 {
     if (nEncodedFeatureId == -1)
         return -1;
 
-    return (nEncodedFeatureId & ((1<<m_nIndexTableFIDMask) -1 ));
+    return ((int)(nEncodedFeatureId & 0xffffffff));
 }
 
 /**********************************************************************
@@ -607,7 +561,7 @@ int TABSeamless::ExtractBaseFeatureId(int nEncodedFeatureId)
  * Returns feature id that follows nPrevId, or -1 if it is the
  * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
  **********************************************************************/
-int TABSeamless::GetNextFeatureId(int nPrevId)
+GIntBig TABSeamless::GetNextFeatureId(GIntBig nPrevId)
 {
     if (m_poIndexTable == NULL)
         return -1; // File is not opened yet
@@ -621,7 +575,7 @@ int TABSeamless::GetNextFeatureId(int nPrevId)
     int nId = ExtractBaseFeatureId(nPrevId);
     do
     {
-        nId = m_poCurBaseTable->GetNextFeatureId(nId);
+        nId = (int) m_poCurBaseTable->GetNextFeatureId(nId);
         if (nId != -1)
             return EncodeFeatureId(m_nCurBaseTableId, nId);  // Found one!
         else
@@ -646,7 +600,7 @@ int TABSeamless::GetNextFeatureId(int nPrevId)
  * error happened.  In any case, CPLError() will have been called to
  * report the reason of the failure.
  **********************************************************************/
-TABFeature *TABSeamless::GetFeatureRef(int nFeatureId)
+TABFeature *TABSeamless::GetFeatureRef(GIntBig nFeatureId)
 {
     if (m_poIndexTable == NULL)
         return NULL; // File is not opened yet
@@ -664,8 +618,15 @@ TABFeature *TABSeamless::GetFeatureRef(int nFeatureId)
     {
         if (m_poCurFeature)
             delete m_poCurFeature;
+        m_poCurFeature = NULL;
+
+        TABFeature* poCurFeature = (TABFeature*)m_poCurBaseTable->GetFeature(ExtractBaseFeatureId(nFeatureId));
+        if( poCurFeature == NULL )
+            return NULL;
+        m_poCurFeature = new TABFeature(m_poFeatureDefnRef);
+        m_poCurFeature->SetFrom(poCurFeature);
+        delete poCurFeature;
 
-        m_poCurFeature = (TABFeature*)m_poCurBaseTable->GetFeature(ExtractBaseFeatureId(nFeatureId));
         m_nCurFeatureId = nFeatureId;
 
         m_poCurFeature->SetFID(nFeatureId);
@@ -799,8 +760,10 @@ OGRErr TABSeamless::GetExtent (OGREnvelope *psExtent, int bForce)
  * Returns 0 on success, or silently returns -1 (with no error) if this
  * information is not available.
  **********************************************************************/
-int TABSeamless::GetFeatureCountByType(CPL_UNUSED int &numPoints, CPL_UNUSED int &numLines,
-                                       CPL_UNUSED int &numRegions, CPL_UNUSED int &numTexts,
+int TABSeamless::GetFeatureCountByType(CPL_UNUSED int &numPoints,
+                                       CPL_UNUSED int &numLines,
+                                       CPL_UNUSED int &numRegions,
+                                       CPL_UNUSED int &numTexts,
                                        CPL_UNUSED GBool bForce /*= TRUE*/)
 {
     /*-----------------------------------------------------------------
@@ -811,7 +774,7 @@ int TABSeamless::GetFeatureCountByType(CPL_UNUSED int &numPoints, CPL_UNUSED int
     return -1;
 }
 
-int TABSeamless::GetFeatureCount(int bForce)
+GIntBig TABSeamless::GetFeatureCount(int bForce)
 {
     /*-----------------------------------------------------------------
      * __TODO__  This should be implemented to return -1 if force=false,
diff --git a/ogr/ogrsf_frmts/mitab/mitab_tabview.cpp b/ogr/ogrsf_frmts/mitab/mitab_tabview.cpp
index 4cbcd45..e1b2a1e 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_tabview.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_tabview.cpp
@@ -11,6 +11,7 @@
  *
  **********************************************************************
  * Copyright (c) 1999-2002, Daniel Morissette
+ * Copyright (c) 2014, Even Rouault <even.rouault at spatialys.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -150,7 +151,7 @@ TABView::~TABView()
 }
 
 
-int TABView::GetFeatureCount (int bForce)
+GIntBig TABView::GetFeatureCount (int bForce)
 {
 
     if (m_nMainTableIndex != -1)
@@ -183,7 +184,7 @@ void TABView::ResetReading()
  *
  * Returns 0 on success, -1 on error.
  **********************************************************************/
-int TABView::Open(const char *pszFname, const char *pszAccess,
+int TABView::Open(const char *pszFname, TABAccess eAccess,
                   GBool bTestOpenNoError /*= FALSE*/ )
 {
     char nStatus = 0;
@@ -198,12 +199,12 @@ int TABView::Open(const char *pszFname, const char *pszAccess,
     /*-----------------------------------------------------------------
      * Validate access mode and call the right open method
      *----------------------------------------------------------------*/
-    if (EQUALN(pszAccess, "r", 1))
+    if (eAccess == TABRead)
     {
         m_eAccessMode = TABRead;
         nStatus = (char)OpenForRead(pszFname, bTestOpenNoError);
     }
-    else if (EQUALN(pszAccess, "w", 1))
+    else if (eAccess == TABWrite)
     {
         m_eAccessMode = TABWrite;
         nStatus = (char)OpenForWrite(pszFname);
@@ -211,7 +212,7 @@ int TABView::Open(const char *pszFname, const char *pszAccess,
     else
     {
         CPLError(CE_Failure, CPLE_NotSupported,
-                 "Open() failed: access mode \"%s\" not supported", pszAccess);
+                 "Open() failed: access mode \"%d\" not supported", eAccess);
         return -1;
     }
 
@@ -357,7 +358,7 @@ int TABView::OpenForRead(const char *pszFname,
         m_papoTABFiles[iFile] = new TABFile;
    
         if ( m_papoTABFiles[iFile]->Open(m_papszTABFnames[iFile],
-                                         "rb", bTestOpenNoError) != 0)
+                                         m_eAccessMode, bTestOpenNoError) != 0)
         {
             // Open Failed... an error has already been reported, just return.
             if (bTestOpenNoError)
@@ -460,7 +461,7 @@ int TABView::OpenForWrite(const char *pszFname)
         
         m_papoTABFiles[iFile] = new TABFile;
    
-        if ( m_papoTABFiles[iFile]->Open(m_papszTABFnames[iFile], "wb") != 0)
+        if ( m_papoTABFiles[iFile]->Open(m_papszTABFnames[iFile], m_eAccessMode) != 0)
         {
             // Open Failed... an error has already been reported, just return.
             CPLFree(pszPath);
@@ -662,7 +663,7 @@ int TABView::ParseTABFile(const char *pszDatasetPath,
  **********************************************************************/
 int TABView::WriteTABFile()
 {
-    FILE *fp;
+    VSILFILE *fp;
 
     CPLAssert(m_eAccessMode == TABWrite);
     CPLAssert(m_numTABFiles == 2);
@@ -672,37 +673,37 @@ int TABView::WriteTABFile()
     char *pszTable1 = TABGetBasename(m_papszTABFnames[0]);
     char *pszTable2 = TABGetBasename(m_papszTABFnames[1]);
 
-    if ( (fp = VSIFOpen(m_pszFname, "wt")) != NULL)
+    if ( (fp = VSIFOpenL(m_pszFname, "wt")) != NULL)
     {
         // Version is always 100, no matter what the sub-table's version is
-        fprintf(fp, "!Table\n");
-        fprintf(fp, "!Version 100\n");
+        VSIFPrintfL(fp, "!Table\n");
+        VSIFPrintfL(fp, "!Version 100\n");
 
-        fprintf(fp, "Open Table \"%s\" Hide\n", pszTable1);
-        fprintf(fp, "Open Table \"%s\" Hide\n", pszTable2);
-        fprintf(fp, "\n");
-        fprintf(fp, "Create View %s As\n", pszTable);
-        fprintf(fp, "Select ");
+        VSIFPrintfL(fp, "Open Table \"%s\" Hide\n", pszTable1);
+        VSIFPrintfL(fp, "Open Table \"%s\" Hide\n", pszTable2);
+        VSIFPrintfL(fp, "\n");
+        VSIFPrintfL(fp, "Create View %s As\n", pszTable);
+        VSIFPrintfL(fp, "Select ");
 
         OGRFeatureDefn *poDefn = GetLayerDefn();
         for(int iField=0; iField<poDefn->GetFieldCount(); iField++)
         {
             OGRFieldDefn *poFieldDefn = poDefn->GetFieldDefn(iField);
             if (iField == 0)
-                fprintf(fp, "%s", poFieldDefn->GetNameRef());
+                VSIFPrintfL(fp, "%s", poFieldDefn->GetNameRef());
             else
-                fprintf(fp, ",%s", poFieldDefn->GetNameRef());
+                VSIFPrintfL(fp, ",%s", poFieldDefn->GetNameRef());
         }
-        fprintf(fp, "\n");
+        VSIFPrintfL(fp, "\n");
 
-        fprintf(fp, "From %s, %s\n", pszTable2, pszTable1);
-        fprintf(fp, "Where %s.%s=%s.%s\n", pszTable2, 
+        VSIFPrintfL(fp, "From %s, %s\n", pszTable2, pszTable1);
+        VSIFPrintfL(fp, "Where %s.%s=%s.%s\n", pszTable2, 
                                            m_poRelation->GetRelFieldName(),
                                            pszTable1, 
                                            m_poRelation->GetMainFieldName());
 
 
-        VSIFClose(fp);
+        VSIFCloseL(fp);
     }
     else
     {
@@ -843,7 +844,7 @@ int TABView::SetQuickSpatialIndexMode(GBool bQuickSpatialIndexMode/*=TRUE*/)
  * Returns feature id that follows nPrevId, or -1 if it is the
  * last feature id.  Pass nPrevId=-1 to fetch the first valid feature id.
  **********************************************************************/
-int TABView::GetNextFeatureId(int nPrevId)
+GIntBig TABView::GetNextFeatureId(GIntBig nPrevId)
 {
     if (m_nMainTableIndex != -1)
         return m_papoTABFiles[m_nMainTableIndex]->GetNextFeatureId(nPrevId);
@@ -865,7 +866,7 @@ int TABView::GetNextFeatureId(int nPrevId)
  * error happened.  In any case, CPLError() will have been called to
  * report the reason of the failure.
  **********************************************************************/
-TABFeature *TABView::GetFeatureRef(int nFeatureId)
+TABFeature *TABView::GetFeatureRef(GIntBig nFeatureId)
 {
     
     /*-----------------------------------------------------------------
@@ -878,13 +879,16 @@ TABFeature *TABView::GetFeatureRef(int nFeatureId)
         return NULL;
     }
 
+    if( (GIntBig)(int)nFeatureId != nFeatureId )
+        return NULL;
+
     if(m_poCurFeature)
     {
         delete m_poCurFeature;
         m_poCurFeature = NULL;
     }
 
-    m_poCurFeature = m_poRelation->GetFeature(nFeatureId);
+    m_poCurFeature = m_poRelation->GetFeature((int)nFeatureId);
     m_nCurFeatureId = nFeatureId;
     m_poCurFeature->SetFID(m_nCurFeatureId);
     return m_poCurFeature;
@@ -2070,7 +2074,7 @@ int TABRelation::WriteFeature(TABFeature *poFeature, int nFeatureId /*=-1*/)
     poMainFeature->SetField(m_nMainFieldNo, nRecordNo);
 
     if (m_poMainTable->CreateFeature(poMainFeature) != OGRERR_NONE)
-        nFeatureId = poMainFeature->GetFID();
+        nFeatureId = (int) poMainFeature->GetFID();
     else
         nFeatureId = -1;
 
diff --git a/ogr/ogrsf_frmts/mitab/mitab_utils.cpp b/ogr/ogrsf_frmts/mitab/mitab_utils.cpp
index bc30dde..16afa3a 100644
--- a/ogr/ogrsf_frmts/mitab/mitab_utils.cpp
+++ b/ogr/ogrsf_frmts/mitab/mitab_utils.cpp
@@ -215,7 +215,7 @@ GBool TABAdjustCaseSensitiveFilename(char *pszFname)
     /*-----------------------------------------------------------------
      * Unix case.
      *----------------------------------------------------------------*/
-    VSIStatBuf  sStatBuf;
+    VSIStatBufL  sStatBuf;
     char        *pszTmpPath = NULL;
     int         nTotalLen, iTmpPtr;
     GBool       bValidPath;
@@ -223,7 +223,7 @@ GBool TABAdjustCaseSensitiveFilename(char *pszFname)
     /*-----------------------------------------------------------------
      * First check if the filename is OK as is.
      *----------------------------------------------------------------*/
-    if (VSIStat(pszFname, &sStatBuf) == 0)
+    if (VSIStatL(pszFname, &sStatBuf) == 0)
     {
         return TRUE;
     }
@@ -248,7 +248,7 @@ GBool TABAdjustCaseSensitiveFilename(char *pszFname)
             pszTmpPath[--iTmpPtr] = '\0';
         }
 
-        if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) == 0)
+        if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) == 0)
             bValidPath = TRUE;
     }
 
@@ -300,7 +300,7 @@ GBool TABAdjustCaseSensitiveFilename(char *pszFname)
             }
         }
 
-        if (iTmpPtr > 0 && VSIStat(pszTmpPath, &sStatBuf) != 0)
+        if (iTmpPtr > 0 && VSIStatL(pszTmpPath, &sStatBuf) != 0)
             bValidPath = FALSE;
 
         CSLDestroy(papszDir);
@@ -345,13 +345,13 @@ GBool TABAdjustCaseSensitiveFilename(char *pszFname)
  **********************************************************************/
 GBool TABAdjustFilenameExtension(char *pszFname)
 {
-    VSIStatBuf  sStatBuf;
+    VSIStatBufL  sStatBuf;
     int         i;
     
     /*-----------------------------------------------------------------
      * First try using filename as provided
      *----------------------------------------------------------------*/
-    if (VSIStat(pszFname, &sStatBuf) == 0)
+    if (VSIStatL(pszFname, &sStatBuf) == 0)
     {
         return TRUE;
     }     
@@ -364,7 +364,7 @@ GBool TABAdjustFilenameExtension(char *pszFname)
         pszFname[i] = (char)toupper(pszFname[i]);
     }
 
-    if (VSIStat(pszFname, &sStatBuf) == 0)
+    if (VSIStatL(pszFname, &sStatBuf) == 0)
     {
         return TRUE;
     }     
@@ -377,7 +377,7 @@ GBool TABAdjustFilenameExtension(char *pszFname)
         pszFname[i] = (char)tolower(pszFname[i]);
     }
 
-    if (VSIStat(pszFname, &sStatBuf) == 0)
+    if (VSIStatL(pszFname, &sStatBuf) == 0)
     {
         return TRUE;
     }     
@@ -442,27 +442,27 @@ char *TABGetBasename(const char *pszFname)
  *
  * Load a test file into a stringlist.
  *
- * Lines are limited in length by the size fo the CPLReadLine() buffer.
+ * Lines are limited in length by the size of the CPLReadLine() buffer.
  **********************************************************************/
 char **TAB_CSLLoad(const char *pszFname)
 {
-    FILE        *fp;
+    VSILFILE    *fp;
     const char  *pszLine;
     char        **papszStrList=NULL;
 
-    fp = VSIFOpen(pszFname, "rt");
+    fp = VSIFOpenL(pszFname, "rt");
 
     if (fp)
     {
-        while(!VSIFEof(fp))
+        while(!VSIFEofL(fp))
         {
-            if ( (pszLine = CPLReadLine(fp)) != NULL )
+            if ( (pszLine = CPLReadLineL(fp)) != NULL )
             {
                 papszStrList = CSLAddString(papszStrList, pszLine);
             }
         }
 
-        VSIFClose(fp);
+        VSIFCloseL(fp);
     }
 
     return papszStrList;
@@ -499,8 +499,8 @@ char *TABUnEscapeString(char *pszString, GBool bSrcIsConst)
      * We try to work on the original buffer unless we have bSrcIsConst=TRUE
      *
      * Note that we do not worry about freeing the source buffer when we
-     * return a copy... it is up to the caller to decide if he needs to 
-     * free the source based on context and by comparing pszString with 
+     * return a copy... it is up to the caller to decide if the source needs
+     * to be freed based on context and by comparing pszString with
      * the returned pointer (pszWorkString) to see if they are identical.
      *----------------------------------------------------------------*/
     char *pszWorkString = NULL;
@@ -554,8 +554,8 @@ char *TABUnEscapeString(char *pszString, GBool bSrcIsConst)
  * be modified, or a copy that has to be freed by the caller if the
  * string had to be modified.
  *
- * It is up to the caller to decide if he needs to free the returned 
- * string by comparing the source (pszString) pointer with the returned
+ * It is up to the caller to decide if the returned string needs to be
+ * freed by comparing the source (pszString) pointer with the returned
  * pointer (pszWorkString) to see if they are identical.
  **********************************************************************/
 char *TABEscapeString(char *pszString)
@@ -700,6 +700,8 @@ static MapInfoUnitsInfo gasUnitsList[] =
     {6, "cm"},
     {7, "m"},
     {8, "survey ft"},
+    {8, "survey foot"}, // alternate
+    {13, NULL},
     {9, "nmi"},
     {30, "li"},
     {31, "ch"},
@@ -744,10 +746,14 @@ int TABUnitIdFromString(const char *pszName)
     MapInfoUnitsInfo *psList;
 
     psList = gasUnitsList;
+    
+    if( pszName == NULL )
+        return 13;
 
     while(psList->nUnitId != -1)
     {
-        if (EQUAL(psList->pszAbbrev, pszName)) 
+        if (psList->pszAbbrev != NULL &&
+            EQUAL(psList->pszAbbrev, pszName)) 
             return psList->nUnitId;
         psList++;
     }
diff --git a/ogr/ogrsf_frmts/mssqlspatial/GNUmakefile b/ogr/ogrsf_frmts/mssqlspatial/GNUmakefile
index 4647bc7..4c478ab 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/GNUmakefile
+++ b/ogr/ogrsf_frmts/mssqlspatial/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrmssqlspatialdatasource.o ogrmssqlspatiallayer.o ogrmssqlspatialtablelayer.o ogrmssqlspatialselectlayer.o ogrmssqlspatialdriver.o ogrmssqlgeometryparser.o ogrmssqlgeometryvalidator.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I.. -I../.. $(CPPFLAGS)
+CPPFLAGS	:=	 -I.. -I../.. $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/mssqlspatial/drv_mssqlspatial.html b/ogr/ogrsf_frmts/mssqlspatial/drv_mssqlspatial.html
index a5a5f41..ccdbc58 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/drv_mssqlspatial.html
+++ b/ogr/ogrsf_frmts/mssqlspatial/drv_mssqlspatial.html
@@ -7,33 +7,33 @@
 
 <h1>MSSQLSpatial - Microsoft SQL Server Spatial Database</h1>
 
-<p>This driver implements support for access to spatial tables in Microsoft SQL 
-    Server 2008+ which contains the geometry and geography data types to repesent 
-    the geometry columns.</p>
-
-<h2>Connecting to a database</h2>
-
-To connect to a MSSQL datasource, use a connection string specifying the database name,
-with additional parameters as necessary. The connection strings must be prefixed 
-    with '<i>MSSQL:</i>'.<br>
-<blockquote><pre>
-MSSQL:server=.\MSSQLSERVER2008;database=dbname;trusted_connection=yes</pre></blockquote>
-In addition to the standard parameters of the 
-    <a href="http://msdn.microsoft.com/en-us/library/ms130822.aspx">ODBC driver connection string</a> 
-    format the following custom parameters can also be used in the following syntax:
-
-<ul>
-	
-<li> <b>Tables=schema1.table1(geometry column1),schema2.table2(geometry column2)</b>: 
-    By using this parameter you can specify the subset of the layers to be used by the driver. If this parameter is not set, the layers are retrieved from the geometry_columns metadata table. You can omit specifying the schema and the geometry column portions of the syntax. </li>
-<li> <b>GeometryFormat=native|wkb|wkt</b>: 
-    The desired format in which the geometries should be retrieved from the server. The default value is 'native' in this case the native SqlGeometry and SqlGeography serialization format is used. When using the 'wkb' or 'wkt' setting the geometry representation is converted to 'Well Known Binary' and 'Well Known Text' at the server. This conversion requires a significant overhead at the server and makes the feature access slower than using the native format.</li>
-
+<p>This driver implements support for access to spatial tables in Microsoft SQL 
+    Server 2008+ which contains the geometry and geography data types to repesent 
+    the geometry columns.</p>
+
+<h2>Connecting to a database</h2>
+
+To connect to a MSSQL datasource, use a connection string specifying the database name,
+with additional parameters as necessary. The connection strings must be prefixed 
+    with '<i>MSSQL:</i>'.<br>
+<blockquote><pre>
+MSSQL:server=.\MSSQLSERVER2008;database=dbname;trusted_connection=yes</pre></blockquote>
+In addition to the standard parameters of the 
+    <a href="http://msdn.microsoft.com/en-us/library/ms130822.aspx">ODBC driver connection string</a> 
+    format the following custom parameters can also be used in the following syntax:
+
+<ul>
+	
+<li> <b>Tables=schema1.table1(geometry column1),schema2.table2(geometry column2)</b>: 
+    By using this parameter you can specify the subset of the layers to be used by the driver. If this parameter is not set, the layers are retrieved from the geometry_columns metadata table. You can omit specifying the schema and the geometry column portions of the syntax. </li>
+<li> <b>GeometryFormat=native|wkb|wkt|wkbzm</b>: 
+    The desired format in which the geometries should be retrieved from the server. The default value is 'native' in this case the native SqlGeometry and SqlGeography serialization format is used. When using the 'wkb' or 'wkt' setting the geometry representation is converted to 'Well Known Binary' and 'Well Known Text' at the server. This conversion requires a significant overhead at the server and makes the feature access slower than using the native format. The wkbzm format can only be [...]
+
 </ul>
     <p>The parameter names are not case sensitive in the connection strings.</p> 
-    <p>Specifying the <b>
+    <p>Specifying the <b>
     Database</b> parameter is required by the driver in order to select the proper database.</p> 
-    <p>The connection may contain the optional <b>
+    <p>The connection may contain the optional <b>
     Driver</b> parameter if a custom SQL server driver should be loaded (like FreeTDS). The default is <b>{SQL Server}</b></p>
 
 <h2>Layers</h2>
@@ -47,59 +47,62 @@ with no spatial data<p>
 Starting with GDAL 1.10 if the user defines the environment variable
 <i>MSSQLSPATIAL_USE_GEOMETRY_COLUMNS=NO</i> then the driver will look for all user spatial tables found in the system catalog<p>
 
-<h2>SQL statements</h2>
-
-<p>The MS SQL Spatial driver passes SQL statements directly to MS SQL by default,
-rather than evaluating them internally when using the ExecuteSQL() call on the
-OGRDataSource, or the -sql command option to ogr2ogr.  Attribute query
-expressions are also passed directly through to MSSQL. 
-It's also possible to request the OGR MSSQL driver to handle SQL commands 
-with the <a href="/ogr/ogr_sql.html">OGR SQL</a> engine, by passing <strong>"OGRSQL"</strong> 
-string to the ExecuteSQL() method, as the name of the SQL dialect.</p>
-
-<p>The MSSQL driver in OGR supports the OGRLayer::StartTrasaction(), 
-OGRLayer::CommitTransaction() and OGRLayer::RollbackTransaction()
+<h2>SQL statements</h2>
+
+<p>The MS SQL Spatial driver passes SQL statements directly to MS SQL by default,
+rather than evaluating them internally when using the ExecuteSQL() call on the
+OGRDataSource, or the -sql command option to ogr2ogr.  Attribute query
+expressions are also passed directly through to MSSQL. 
+It's also possible to request the OGR MSSQL driver to handle SQL commands 
+with the <a href="/ogr/ogr_sql.html">OGR SQL</a> engine, by passing <strong>"OGRSQL"</strong> 
+string to the ExecuteSQL() method, as the name of the SQL dialect.</p>
+
+<p>The MSSQL driver in OGR supports the OGRLayer::StartTrasaction(), 
+OGRLayer::CommitTransaction() and OGRLayer::RollbackTransaction()
 calls in the normal SQL sense.</p>
 
-<h2>Creation Issues</h2>
-
-<p>This driver doesn't support creating new databases, you might want to use the <i>Microsoft SQL Server Client Tools</i> for this purpose, but it does allow creation of new layers within an
-existing database.</P>
-
-<h3>Layer Creation Options</h3>
-
-<ul>
-<li>
-<b>GEOM_TYPE</b>: The GEOM_TYPE layer creation option can be set to 
-one of "geometry" or "geography". If this option is not specified the default value is "geometry". 
-    So as to create the geometry column with "geography" type, this parameter should 
-    be set "geography". In this case the layer must have a valid spatial referece of 
-    one of the geography coordinate systems defined in the <b>
-    sys.spatial_reference_systems</b> SQL Server metadata table. Projected 
-    coordinate systems are not supported in this case.</li>
-<li> <b>OVERWRITE</b>: This may be "YES" to force an existing layer of the
-desired name to be destroyed before creating the requested layer.</li>
-<li> <b>LAUNDER</b>: This may be "YES" to force new fields created on this
-layer to have their field names "laundered" into a form more compatible with
-MSSQL.  This converts to lower case and converts some special characters
-like "-" and "#" to "_".  If "NO" exact names are preserved.  
-The default value is "YES".  If enabled the table (layer) name will also be laundered.</li>
-<li> <b>PRECISION</b>: This may be "YES" to force new fields created on this
-layer to try and represent the width and precision information, if available
-using numeric(width,precision) or char(width) types.  If "NO" then the types
-float, int and varchar will be used instead.  The default is "YES".
-<li> <b>DIM={2,3}</b>: Control the dimension of the layer.  Defaults to 3.</li>
-<li> <b>GEOM_NAME</b>: Set the name of geometry column in the new table.  If 
-omitted it defaults to <i>ogr_geometry</i>.</li>
-<li> <b>SCHEMA</b>: Set name of schema for new table.
-If this parameter is not supported the default schema "<i>dbo"</i> is used.</li>
-<li> <b>SRID</b>: Set the spatial reference id of the new table explicitly.
-The corresponding entry should already be added to the spatial_ref_sys metadata table. If this parameter is not set the SRID is derived from the authority code of source layer SRS.</li>
-</ul>
-
+<h2>Creation Issues</h2>
+
+<p>This driver doesn't support creating new databases, you might want to use the <i>Microsoft SQL Server Client Tools</i> for this purpose, but it does allow creation of new layers within an
+existing database.</P>
+
+<h3>Layer Creation Options</h3>
+
+<ul>
+<li>
+<b>GEOM_TYPE</b>: The GEOM_TYPE layer creation option can be set to 
+one of "geometry" or "geography". If this option is not specified the default value is "geometry". 
+    So as to create the geometry column with "geography" type, this parameter should 
+    be set "geography". In this case the layer must have a valid spatial referece of 
+    one of the geography coordinate systems defined in the <b>
+    sys.spatial_reference_systems</b> SQL Server metadata table. Projected 
+    coordinate systems are not supported in this case.</li>
+<li> <b>OVERWRITE</b>: This may be "YES" to force an existing layer of the
+desired name to be destroyed before creating the requested layer.</li>
+<li> <b>LAUNDER</b>: This may be "YES" to force new fields created on this
+layer to have their field names "laundered" into a form more compatible with
+MSSQL.  This converts to lower case and converts some special characters
+like "-" and "#" to "_".  If "NO" exact names are preserved.  
+The default value is "YES".  If enabled the table (layer) name will also be laundered.</li>
+<li> <b>PRECISION</b>: This may be "YES" to force new fields created on this
+layer to try and represent the width and precision information, if available
+using numeric(width,precision) or char(width) types.  If "NO" then the types
+float, int and varchar will be used instead.  The default is "YES".</li>
+<li> <b>DIM={2,3}</b>: Control the dimension of the layer.  Defaults to 3.</li>
+<li> <b>GEOMETRY_NAME</b>: Set the name of geometry column in the new table.  If 
+omitted it defaults to <i>ogr_geometry</i>.. Note: option was called GEOM_NAME in releases before GDAL 2</li>
+<li> <b>SCHEMA</b>: Set name of schema for new table.
+If this parameter is not supported the default schema "<i>dbo"</i> is used.</li>
+<li> <b>SRID</b>: Set the spatial reference id of the new table explicitly.
+The corresponding entry should already be added to the spatial_ref_sys metadata table. If this parameter is not set the SRID is derived from the authority code of source layer SRS.</li>
+<li> <b>SPATIAL_INDEX</b>: (From GDAL 2.0.0) Boolean flag (YES/NO) to enable/disable the automatic creation of a spatial index on the newly created layers (enabled by default).</li>
+<li> <b>UPLOAD_GEOM_FORMAT</b>: (From GDAL 2.0.0) Specify the geometry format (wkb or wkt) when creating or modifying features. The default is wkb.</li>
+<li> <b>FID</b>: (From GDAL 2.0.0) Name of the FID column to create. Defaults to ogr_fid.</li>
+</ul>
+
 <h3>Spatial Index Creation</h3>
 
-<p>By default the MS SQL Spatial driver doesn't add spatial indexes to the tables during the layer creation. However you should create a spatial index by using the 
+<p>By default the MS SQL Spatial driver doesn't add spatial indexes to the tables during the layer creation. However you should create a spatial index by using the 
     following sql option:</p>
 
 <blockquote><pre>create spatial index on schema.table</pre></blockquote>
@@ -108,18 +111,25 @@ The corresponding entry should already be added to the spatial_ref_sys metadata
 
 <blockquote><pre>drop spatial index on schema.table</pre></blockquote>
 
+<h2>Transaction support (GDAL >= 2.0)</h2>
+
+<p>
+The driver implements transactions at the dataset level, per
+<a href="http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions">RFC 54</a>
+</p>
+
 <h2>Examples</h2>
 
 <p>Creating a layer from an OGR data source</p>
-<blockquote><pre>
+<blockquote><pre>
 ogr2ogr -overwrite -f MSSQLSpatial "MSSQL:server=.\MSSQLSERVER2008;database=geodb;trusted_connection=yes" "rivers.tab"</pre></blockquote>
 
 <p>Connecting to a layer and dump the contents</p>
-<blockquote><pre>
+<blockquote><pre>
 ogrinfo -al "MSSQL:server=.\MSSQLSERVER2008;database=geodb;tables=rivers;trusted_connection=yes"</pre></blockquote>
 
 <p>Creating a spatial index</p>
-<blockquote><pre>
+<blockquote><pre>
 ogrinfo -sql "create spatial index on rivers" "MSSQL:server=.\MSSQLSERVER2008;database=geodb;trusted_connection=yes"</pre></blockquote>
 
 </body>
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogr_mssqlspatial.h b/ogr/ogrsf_frmts/mssqlspatial/ogr_mssqlspatial.h
index d4756b5..652daff 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogr_mssqlspatial.h
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogr_mssqlspatial.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_mssqlspatial.h 27344 2014-05-15 21:13:54Z tamas $
+ * $Id: ogr_mssqlspatial.h 29027 2015-04-26 18:29:41Z tamas $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Definition of classes for OGR MSSQL Spatial driver.
@@ -139,7 +139,7 @@ class OGRMSSQLSpatialLayer : public OGRLayer
     OGRSpatialReference *poSRS;
     int                 nSRSId;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRMSSQLSpatialDataSource    *poDS;
 
@@ -164,7 +164,7 @@ class OGRMSSQLSpatialLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
 
@@ -190,7 +190,10 @@ class OGRMSSQLSpatialTableLayer : public OGRMSSQLSpatialLayer
     int                 bUpdateAccess;
     int                 bLaunderColumnNames;
     int                 bPreservePrecision;
+    int                 bNeedSpatialIndex;
 
+    int                 nUploadGeometryFormat;
+    
     char                *pszQuery;
 
     void		ClearStatement();
@@ -222,7 +225,7 @@ class OGRMSSQLSpatialTableLayer : public OGRMSSQLSpatialLayer
     void                DropSpatialIndex();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRFeatureDefn *GetLayerDefn();
 
@@ -230,9 +233,9 @@ class OGRMSSQLSpatialTableLayer : public OGRMSSQLSpatialLayer
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
     const char*         GetTableName() { return pszTableName; }
     const char*         GetLayerName() { return pszLayerName; }
@@ -241,7 +244,7 @@ class OGRMSSQLSpatialTableLayer : public OGRMSSQLSpatialLayer
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
    
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     virtual int         TestCapability( const char * );
 
@@ -249,8 +252,12 @@ class OGRMSSQLSpatialTableLayer : public OGRMSSQLSpatialLayer
                                 { bLaunderColumnNames = bFlag; }
     void                SetPrecisionFlag( int bFlag )
                                 { bPreservePrecision = bFlag; }
+    void                SetSpatialIndexFlag( int bFlag )
+                                { bNeedSpatialIndex = bFlag; }
+    void                SetUploadGeometryFormat( int nGeometryFormat )
+                                { nUploadGeometryFormat = nGeometryFormat; }
     void                AppendFieldValue(CPLODBCStatement *poStatement,
-                                       OGRFeature* poFeature, int i);
+                                       OGRFeature* poFeature, int i, int *bind_num, void **bind_buffer);
 
     int                 FetchSRSId();
 };
@@ -274,9 +281,9 @@ class OGRMSSQLSpatialSelectLayer : public OGRMSSQLSpatialLayer
                         ~OGRMSSQLSpatialSelectLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
@@ -335,7 +342,7 @@ class OGRMSSQLSpatialDataSource : public OGRDataSource
     int                 UseGeometryColumns() { return bUseGeometryColumns; }
 
     virtual int         DeleteLayer( int iLayer );
-    virtual OGRLayer    *CreateLayer( const char *,
+    virtual OGRLayer    *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -353,6 +360,10 @@ class OGRMSSQLSpatialDataSource : public OGRDataSource
     OGRSpatialReference* FetchSRS( int nId );
     int                 FetchSRSId( OGRSpatialReference * poSRS );
 
+    OGRErr              StartTransaction(CPL_UNUSED int bForce);
+    OGRErr              CommitTransaction();
+    OGRErr              RollbackTransaction();
+
     // Internal use
     CPLODBCSession     *GetSession() { return &oSession; }
 
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlgeometryvalidator.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlgeometryvalidator.cpp
index 2df1c72..f2e46e5 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlgeometryvalidator.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlgeometryvalidator.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlgeometryvalidator.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrmssqlgeometryvalidator.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Implements OGRMSSQLGeometryValidator class to create valid SqlGeometries.
@@ -30,7 +30,7 @@
 #include "cpl_conv.h"
 #include "ogr_mssqlspatial.h"
 
-CPL_CVSID("$Id: ogrmssqlgeometryvalidator.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrmssqlgeometryvalidator.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                   OGRMSSQLGeometryValidator()                        */
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdatasource.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdatasource.cpp
index 39c8040..54c286b 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdatasource.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlspatialdatasource.cpp 28316 2015-01-15 11:35:26Z tamas $
+ * $Id: ogrmssqlspatialdatasource.cpp 29027 2015-04-26 18:29:41Z tamas $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Implements OGRMSSQLSpatialDataSource class..
@@ -30,7 +30,7 @@
 
 #include "ogr_mssqlspatial.h"
 
-CPL_CVSID("$Id: ogrmssqlspatialdatasource.cpp 28316 2015-01-15 11:35:26Z tamas $");
+CPL_CVSID("$Id: ogrmssqlspatialdatasource.cpp 29027 2015-04-26 18:29:41Z tamas $");
 
 /************************************************************************/
 /*                          OGRMSSQLSpatialDataSource()                 */
@@ -63,14 +63,14 @@ OGRMSSQLSpatialDataSource::~OGRMSSQLSpatialDataSource()
 {
     int         i;
 
-    CPLFree( pszName );
-    CPLFree( pszCatalog );
-
     for( i = 0; i < nLayers; i++ )
         delete papoLayers[i];
     
     CPLFree( papoLayers );
 
+    CPLFree( pszName );
+    CPLFree( pszCatalog );
+
     for( i = 0; i < nKnownSRID; i++ )
     {
         if( papoSRS[i] != NULL )
@@ -87,6 +87,10 @@ OGRMSSQLSpatialDataSource::~OGRMSSQLSpatialDataSource()
 int OGRMSSQLSpatialDataSource::TestCapability( const char * pszCap )
 
 {
+#if (ODBCVER >= 0x0300)
+    if ( EQUAL(pszCap,ODsCTransactions) )
+        return TRUE;
+#endif
     if( EQUAL(pszCap,ODsCCreateLayer) || EQUAL(pszCap,ODsCDeleteLayer) )
         return TRUE;
     else
@@ -188,17 +192,23 @@ int OGRMSSQLSpatialDataSource::DeleteLayer( int iLayer )
 /*      Remove from the database.                                       */
 /* -------------------------------------------------------------------- */
 
-    oSession.BeginTransaction();
+    int bInTransaction = oSession.IsInTransaction();
+    if (!bInTransaction)
+        oSession.BeginTransaction();
     
     if( !oStmt.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                     "Error deleting layer: %s", GetSession()->GetLastError() );
 
+        if (!bInTransaction)
+            oSession.RollbackTransaction();
+
         return OGRERR_FAILURE;
     }
 
-    oSession.CommitTransaction();
+    if (!bInTransaction)
+        oSession.CommitTransaction();
 
     return OGRERR_NONE;
 }
@@ -207,7 +217,7 @@ int OGRMSSQLSpatialDataSource::DeleteLayer( int iLayer )
 /*                            CreateLayer()                             */
 /************************************************************************/
 
-OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
+OGRLayer * OGRMSSQLSpatialDataSource::ICreateLayer( const char * pszLayerName,
                                           OGRSpatialReference *poSRS,
                                           OGRwkbGeometryType eType,
                                           char ** papszOptions )
@@ -218,6 +228,7 @@ OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
     const char          *pszGeomType = NULL;
     const char          *pszGeomColumn = NULL;
     int                 nCoordDimension = 3;
+    char                *pszFIDColumnName = NULL;
 
     /* determine the dimension */
     if( eType == wkbFlatten(eType) )
@@ -319,10 +330,13 @@ OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
         }
 
         /* determine the geometry column name */
-        pszGeomColumn =  CSLFetchNameValue( papszOptions, "GEOM_NAME");
+        pszGeomColumn =  CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
+        if (!pszGeomColumn)
+            pszGeomColumn =  CSLFetchNameValue( papszOptions, "GEOM_NAME");
         if (!pszGeomColumn)
             pszGeomColumn = "ogr_geometry";
     }
+    int bGeomNullable = CSLFetchBoolean(papszOptions, "GEOMETRY_NULLABLE", TRUE);
 
 /* -------------------------------------------------------------------- */
 /*      Initialize the metadata tables                                  */
@@ -372,29 +386,49 @@ OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
         oStmt.Appendf("IF NOT EXISTS (SELECT name from sys.schemas WHERE name = '%s') EXEC sp_executesql N'CREATE SCHEMA [%s]'\n", pszSchemaName, pszSchemaName);
     }
 
+     /* determine the FID column name */
+    const char* pszFIDColumnNameIn = CSLFetchNameValueDef(papszOptions, "FID", "ogr_fid");
+    if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
+        pszFIDColumnName = LaunderName( pszFIDColumnNameIn );
+    else
+        pszFIDColumnName = CPLStrdup( pszFIDColumnNameIn );
+
+    int bFID64 = CSLFetchBoolean(papszOptions, "FID64", FALSE);
+ 	const char* pszFIDType = bFID64 ? "bigint": "int";
+
     if( eType == wkbNone ) 
     { 
-        oStmt.Appendf("CREATE TABLE [%s].[%s] ([ogr_fid] [int] IDENTITY(1,1) NOT NULL, "
-            "CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([ogr_fid] ASC))",
-            pszSchemaName, pszTableName, pszTableName);
+        oStmt.Appendf("CREATE TABLE [%s].[%s] ([%s] [%s] IDENTITY(1,1) NOT NULL, "
+            "CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([%s] ASC))",
+            pszSchemaName, pszTableName, pszFIDColumnName, pszFIDType, pszTableName, pszFIDColumnName);
     }
     else
     {
-        oStmt.Appendf("CREATE TABLE [%s].[%s] ([ogr_fid] [int] IDENTITY(1,1) NOT NULL, "
-            "[%s] [%s] NULL, CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([ogr_fid] ASC))",
-            pszSchemaName, pszTableName, pszGeomColumn, pszGeomType, pszTableName);
+        oStmt.Appendf("CREATE TABLE [%s].[%s] ([%s] [%s] IDENTITY(1,1) NOT NULL, "
+            "[%s] [%s] %s, CONSTRAINT [PK_%s] PRIMARY KEY CLUSTERED ([%s] ASC))",
+            pszSchemaName, pszTableName, pszFIDColumnName, pszFIDType, pszGeomColumn, pszGeomType,
+            bGeomNullable? "NULL":"NOT NULL", pszTableName, pszFIDColumnName);
     }
-    oSession.BeginTransaction();
+
+    CPLFree( pszFIDColumnName );
+
+    int bInTransaction = oSession.IsInTransaction();
+    if (!bInTransaction)
+        oSession.BeginTransaction();
         
     if( !oStmt.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                     "Error creating layer: %s", GetSession()->GetLastError() );
 
+        if (!bInTransaction)
+            oSession.RollbackTransaction();
+
         return NULL;
     }
 
-    oSession.CommitTransaction();
+    if (!bInTransaction)
+        oSession.CommitTransaction();
 
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -406,12 +440,28 @@ OGRLayer * OGRMSSQLSpatialDataSource::CreateLayer( const char * pszLayerName,
     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
 
+    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
+    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
+    poLayer->SetSpatialIndexFlag( bCreateSpatialIndex );
+
+    const char *pszUploadGeometryFormat = CSLFetchNameValue( papszOptions, "UPLOAD_GEOM_FORMAT" );
+    if (pszUploadGeometryFormat)
+    {
+        if (EQUALN(pszUploadGeometryFormat,"wkb",5))
+            poLayer->SetUploadGeometryFormat(MSSQLGEOMETRY_WKB);
+        else if (EQUALN(pszUploadGeometryFormat, "wkt",3))
+            poLayer->SetUploadGeometryFormat(MSSQLGEOMETRY_WKT);
+    }
+
     char *pszWKT = NULL;
     if( poSRS && poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE )
     {
         CPLFree(pszWKT);
         pszWKT = NULL;
     }
+
+    if( bFID64 )
+        poLayer->SetMetadataItem(OLMD_FID64, "YES");
     
     if (poLayer->Initialize(pszSchemaName, pszTableName, pszGeomColumn, nCoordDimension, nSRSId, pszWKT, eType) == OGRERR_FAILURE)
     {
@@ -888,7 +938,7 @@ OGRLayer * OGRMSSQLSpatialDataSource::ExecuteSQL( const char *pszSQLCommand,
 
         while( *pszLayerName == ' ' )
             pszLayerName++;
-
+        
         OGRLayer* poLayer = GetLayerByName(pszLayerName);
         
         for( int iLayer = 0; iLayer < nLayers; iLayer++ )
@@ -1034,16 +1084,23 @@ OGRErr OGRMSSQLSpatialDataSource::InitializeMetadataTables()
             "CREATE TABLE spatial_ref_sys (srid integer not null "
             "PRIMARY KEY, auth_name varchar(256), auth_srid integer, srtext varchar(2048), proj4text varchar(2048))" );
 
-        oSession.BeginTransaction();
+        int bInTransaction = oSession.IsInTransaction();
+        if (!bInTransaction)
+            oSession.BeginTransaction();
     
         if( !oStmt.ExecuteSQL() )
         {
             CPLError( CE_Failure, CPLE_AppDefined,
                         "Error initializing the metadata tables : %s", GetSession()->GetLastError() );
+            
+            if (!bInTransaction)
+                oSession.RollbackTransaction();
+
             return OGRERR_FAILURE;
         }
 
-        oSession.CommitTransaction();
+        if (!bInTransaction)
+            oSession.CommitTransaction();
     }
 
     return OGRERR_NONE;
@@ -1252,7 +1309,11 @@ int OGRMSSQLSpatialDataSource::FetchSRSId( OGRSpatialReference * poSRS)
     nSRSId = nAuthorityCode;
 
     oStmt.Clear();
-    oSession.BeginTransaction();
+    
+    int bInTransaction = oSession.IsInTransaction();
+    if (!bInTransaction)
+        oSession.BeginTransaction();
+
     if (nAuthorityCode > 0)
     {
         oStmt.Appendf("SELECT srid FROM spatial_ref_sys where srid = %d", nAuthorityCode);
@@ -1280,7 +1341,8 @@ int OGRMSSQLSpatialDataSource::FetchSRSId( OGRSpatialReference * poSRS)
     if (nSRSId == 0)
     {
         /* unable to allocate srid */
-        oSession.RollbackTransaction();
+        if (!bInTransaction)
+            oSession.RollbackTransaction();
         CPLFree( pszProj4 );
         CPLFree(pszWKT);
         return 0;
@@ -1314,9 +1376,69 @@ int OGRMSSQLSpatialDataSource::FetchSRSId( OGRSpatialReference * poSRS)
     CPLFree( pszWKT);
 
     if ( oStmt.ExecuteSQL() )
-        oSession.CommitTransaction();
+    {
+        if (!bInTransaction)
+            oSession.CommitTransaction();
+    }
     else
-        oSession.RollbackTransaction();
+    {
+        if (!bInTransaction)
+            oSession.RollbackTransaction();
+    }
 
     return nSRSId;
 }
+	
+/************************************************************************/
+/*                         StartTransaction()                           */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRMSSQLSpatialDataSource::StartTransaction(CPL_UNUSED int bForce)
+{
+    if (!oSession.BeginTransaction())
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to start transaction: %s", oSession.GetLastError() );
+        return OGRERR_FAILURE;
+    }
+    
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                         CommitTransaction()                          */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRMSSQLSpatialDataSource::CommitTransaction()
+{
+    if (!oSession.CommitTransaction())
+     {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to commit transaction: %s", oSession.GetLastError() );
+        return OGRERR_FAILURE;
+    }
+    
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                        RollbackTransaction()                         */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRMSSQLSpatialDataSource::RollbackTransaction()
+{
+    if (!oSession.RollbackTransaction())
+     {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to roll back transaction: %s", oSession.GetLastError() );
+        return OGRERR_FAILURE;
+    }
+    
+    return OGRERR_NONE;
+}
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdriver.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdriver.cpp
index 571bd47..81a129d 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdriver.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlspatialdriver.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrmssqlspatialdriver.cpp 29025 2015-04-26 11:50:20Z tamas $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Definition of classes for OGR MSSQL Spatial driver.
@@ -30,7 +30,7 @@
 #include "ogr_mssqlspatial.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrmssqlspatialdriver.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrmssqlspatialdriver.cpp 29025 2015-04-26 11:50:20Z tamas $");
 
 /************************************************************************/
 /*                           ~OGRMSSQLSpatialDriver()                   */
@@ -121,5 +121,39 @@ void RegisterOGRMSSQLSpatial()
 {
     if (! GDAL_CHECK_VERSION("OGR/MSSQLSpatial driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRMSSQLSpatialDriver );
+    OGRSFDriver* poDriver = new OGRMSSQLSpatialDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Microsoft SQL Server Spatial Database" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_mssqlspatial.html" );
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>");
+
+    poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='GEOM_TYPE' type='string-select' description='Format of geometry columns' default='geometry'>"
+"    <Value>geometry</Value>"
+"    <Value>geography</Value>"
+"  </Option>"
+"  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+"  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+"  <Option name='PRECISION' type='boolean' description='Whether fields created should keep the width and precision' default='YES'/>"
+"  <Option name='DIM' type='integer' description='Set to 2 to force the geometries to be 2D, or 3 to be 2.5D'/>"
+"  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column.' default='ogr_geometry' deprecated_alias='GEOM_NAME'/>"
+"  <Option name='SCHEMA' type='string' description='Name of schema into which to create the new table' default='dbo'/>"
+"  <Option name='SRID' type='int' description='Forced SRID of the layer'/>"
+"  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
+"  <Option name='UPLOAD_GEOM_FORMAT' type='string-select' description='Geometry format when creating or modifying features' default='wkb'>"
+"    <Value>wkb</Value>"
+"    <Value>wkt</Value>"
+"  </Option>"
+"  <Option name='FID' type='string' description='Name of the FID column to create' default='ogr_fid'/>"
+"  <Option name='FID64' type='boolean' description='Whether to create the FID column with bigint type to handle 64bit wide ids' default='NO'/>"
+"  <Option name='GEOMETRY_NULLABLE' type='boolean' description='Whether the values of the geometry column can be NULL' default='YES'/>"
+"</LayerCreationOptionList>");
+
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date Time DateTime Binary" );
+    poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+ 	poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+ 	poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatiallayer.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatiallayer.cpp
index b49ea51..a27f70a 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatiallayer.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatiallayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlspatiallayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrmssqlspatiallayer.cpp 29027 2015-04-26 18:29:41Z tamas $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Definition of classes for OGR MSSQL Spatial driver.
@@ -29,7 +29,7 @@
 
 #include "ogr_mssqlspatial.h"
 
-CPL_CVSID("$Id: ogrmssqlspatiallayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrmssqlspatiallayer.cpp 29027 2015-04-26 18:29:41Z tamas $");
 /************************************************************************/
 /*                        OGRMSSQLSpatialLayer()                        */
 /************************************************************************/
@@ -115,29 +115,58 @@ CPLErr OGRMSSQLSpatialLayer::BuildFeatureDefn( const char *pszLayerName,
             {
                 nGeomColumnType = MSSQLCOLTYPE_GEOMETRY;
                 pszGeomColumn = CPLStrdup( poStmt->GetColName(iCol) );
+                if (poFeatureDefn->GetGeomFieldCount() == 1)
+                    poFeatureDefn->GetGeomFieldDefn(0)->SetNullable( poStmt->GetColNullable(iCol) );
                 continue;
             }
             else if ( EQUAL(poStmt->GetColTypeName( iCol ), "geography") )
             {
                 nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY;
                 pszGeomColumn = CPLStrdup( poStmt->GetColName(iCol) );
+                if (poFeatureDefn->GetGeomFieldCount() == 1)
+                    poFeatureDefn->GetGeomFieldDefn(0)->SetNullable( poStmt->GetColNullable(iCol) );
                 continue;
             }
         }
         else
         {
             if( EQUAL(poStmt->GetColName(iCol),pszGeomColumn) )
+            {
+                if (poFeatureDefn->GetGeomFieldCount() == 1)
+                    poFeatureDefn->GetGeomFieldDefn(0)->SetNullable( poStmt->GetColNullable(iCol) );
                 continue;
+            }
         }
 
-        if( pszFIDColumn != NULL &&
-		    EQUAL(poStmt->GetColName(iCol), pszFIDColumn) )
+        if( pszFIDColumn != NULL)
         {
-            if ( EQUAL(poStmt->GetColTypeName( iCol ), "int identity") ||
-                 EQUAL(poStmt->GetColTypeName( iCol ), "bigint identity"))
+		    if (EQUAL(poStmt->GetColName(iCol), pszFIDColumn) )
+            {
+                if (EQUALN(poStmt->GetColTypeName( iCol ), "bigint", 6))
+                    SetMetadataItem(OLMD_FID64, "YES");
+            
+                if ( EQUAL(poStmt->GetColTypeName( iCol ), "int identity") ||
+                     EQUAL(poStmt->GetColTypeName( iCol ), "bigint identity"))
+                    bIsIdentityFid = TRUE;
+                /* skip FID */
+                continue;
+            }
+        }
+        else
+        {
+            if (EQUAL(poStmt->GetColTypeName( iCol ), "int identity"))
+            {
+                pszFIDColumn = CPLStrdup( poStmt->GetColName(iCol) );
                 bIsIdentityFid = TRUE;
-            /* skip FID */
-            continue;
+                continue;
+            }
+            else if (EQUAL(poStmt->GetColTypeName( iCol ), "bigint identity"))
+            {
+                pszFIDColumn = CPLStrdup( poStmt->GetColName(iCol) );
+                bIsIdentityFid = TRUE;
+                SetMetadataItem(OLMD_FID64, "YES");
+                continue;
+            }
         }
 
         OGRFieldDefn    oField( poStmt->GetColName(iCol), OFTString );
@@ -152,6 +181,11 @@ CPLErr OGRMSSQLSpatialLayer::BuildFeatureDefn( const char *pszLayerName,
                 oField.SetType( OFTInteger );
                 break;
 
+            case SQL_C_SBIGINT:
+            case SQL_C_UBIGINT:
+                oField.SetType( OFTInteger64 );
+                break;
+
             case SQL_C_BINARY:
                 oField.SetType( OFTBinary );
                 break;
@@ -183,6 +217,43 @@ CPLErr OGRMSSQLSpatialLayer::BuildFeatureDefn( const char *pszLayerName,
                 /* leave it as OFTString */;
         }
 
+        oField.SetNullable( poStmt->GetColNullable(iCol) );
+
+        if ( poStmt->GetColColumnDef(iCol) )
+        {         
+            /* process default value specification */
+            if ( EQUAL(poStmt->GetColColumnDef(iCol), "(getdate())") )
+                oField.SetDefault( "CURRENT_TIMESTAMP" );
+            else if ( EQUALN(poStmt->GetColColumnDef(iCol), "(CONVERT([time],getdate(),0))", 25) )
+                oField.SetDefault( "CURRENT_TIME" );
+            else if ( EQUALN(poStmt->GetColColumnDef(iCol), "(CONVERT([date],getdate(),0))", 25) )
+                oField.SetDefault( "CURRENT_DATE" );
+            else
+            {
+                char* pszDefault = CPLStrdup(poStmt->GetColColumnDef(iCol));
+                int nLen = strlen(pszDefault);
+                if (nLen >= 1 && pszDefault[0] == '(' && pszDefault[nLen-1] == ')')
+                {
+                    /* all default values are encapsulated in backets by MSSQL server */
+                    if (nLen >= 4 && pszDefault[1] == '(' && pszDefault[nLen-2] == ')')
+                    {
+                        /* for numeric values double brackets are used */
+                        pszDefault[nLen-2] = '\0';
+                        oField.SetDefault(pszDefault + 2);
+                    }
+                    else
+                    {
+                        pszDefault[nLen-1] = '\0';
+                        oField.SetDefault(pszDefault + 1);
+                    }
+                }
+                else
+                    oField.SetDefault( pszDefault );
+
+                CPLFree(pszDefault);
+            }
+        }
+
         poFeatureDefn->AddFieldDefn( &oField );
         panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol;
     }
@@ -272,7 +343,7 @@ OGRFeature *OGRMSSQLSpatialLayer::GetNextRawFeature()
 
     if( pszFIDColumn != NULL && poStmt->GetColId(pszFIDColumn) > -1 )
         poFeature->SetFID( 
-            atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
+            CPLAtoGIntBig(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
     else
         poFeature->SetFID( iNextShapeId );
 
@@ -384,7 +455,7 @@ OGRFeature *OGRMSSQLSpatialLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMSSQLSpatialLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMSSQLSpatialLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
@@ -408,7 +479,12 @@ int OGRMSSQLSpatialLayer::TestCapability( CPL_UNUSED const char * pszCap )
 OGRErr OGRMSSQLSpatialLayer::StartTransaction()
 
 {
-    poDS->GetSession()->BeginTransaction();
+    if (!poDS->GetSession()->BeginTransaction())
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to start transaction: %s", poDS->GetSession()->GetLastError() );
+        return OGRERR_FAILURE;
+    }
     return OGRERR_NONE;
 }
 
@@ -419,7 +495,12 @@ OGRErr OGRMSSQLSpatialLayer::StartTransaction()
 OGRErr OGRMSSQLSpatialLayer::CommitTransaction()
 
 {
-    poDS->GetSession()->CommitTransaction();
+    if (!poDS->GetSession()->CommitTransaction())
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to commit transaction: %s", poDS->GetSession()->GetLastError() );
+        return OGRERR_FAILURE;
+    }
     return OGRERR_NONE;
 }
 
@@ -430,7 +511,12 @@ OGRErr OGRMSSQLSpatialLayer::CommitTransaction()
 OGRErr OGRMSSQLSpatialLayer::RollbackTransaction()
 
 {
-    poDS->GetSession()->RollbackTransaction();
+    if (!poDS->GetSession()->RollbackTransaction())
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Failed to roll back transaction: %s", poDS->GetSession()->GetLastError() );
+        return OGRERR_FAILURE;
+    }
     return OGRERR_NONE;
 }
 
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialselectlayer.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialselectlayer.cpp
index 13ab025..a00c5bc 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialselectlayer.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlspatialselectlayer.cpp 27760 2014-09-28 18:31:18Z tamas $
+ * $Id: ogrmssqlspatialselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Implements OGRMSSQLSpatialSelectLayer class, layer access to the results
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "ogr_mssqlspatial.h"
 
-CPL_CVSID("$Id: ogrmssqlspatialselectlayer.cpp 27760 2014-09-28 18:31:18Z tamas $");
+CPL_CVSID("$Id: ogrmssqlspatialselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 /************************************************************************/
 /*                     OGRMSSQLSpatialSelectLayer()                     */
 /************************************************************************/
@@ -186,7 +186,7 @@ void OGRMSSQLSpatialSelectLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMSSQLSpatialSelectLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMSSQLSpatialSelectLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRMSSQLSpatialLayer::GetFeature( nFeatureId );
@@ -224,7 +224,7 @@ OGRErr OGRMSSQLSpatialSelectLayer::GetExtent(OGREnvelope *, int )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRMSSQLSpatialSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRMSSQLSpatialSelectLayer::GetFeatureCount( int bForce )
 
 {
     return OGRMSSQLSpatialLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialtablelayer.cpp b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialtablelayer.cpp
index 952c497..09aaef8 100644
--- a/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialtablelayer.cpp
+++ b/ogr/ogrsf_frmts/mssqlspatial/ogrmssqlspatialtablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmssqlspatialtablelayer.cpp 28397 2015-01-31 22:34:06Z tamas $
+ * $Id: ogrmssqlspatialtablelayer.cpp 29027 2015-04-26 18:29:41Z tamas $
  *
  * Project:  MSSQL Spatial driver
  * Purpose:  Implements OGRMSSQLSpatialTableLayer class, access to an existing table.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "ogr_mssqlspatial.h"
 
-CPL_CVSID("$Id: ogrmssqlspatialtablelayer.cpp 28397 2015-01-31 22:34:06Z tamas $");
+CPL_CVSID("$Id: ogrmssqlspatialtablelayer.cpp 29027 2015-04-26 18:29:41Z tamas $");
 
 /************************************************************************/
 /*                         OGRMSSQLAppendEscaped( )                     */
@@ -95,6 +95,9 @@ OGRMSSQLSpatialTableLayer::OGRMSSQLSpatialTableLayer( OGRMSSQLSpatialDataSource
     pszSchemaName = NULL;
 
     eGeomType = wkbNone;
+
+    bNeedSpatialIndex = FALSE;
+    nUploadGeometryFormat = MSSQLGEOMETRY_WKB;
 }
 
 /************************************************************************/
@@ -104,6 +107,12 @@ OGRMSSQLSpatialTableLayer::OGRMSSQLSpatialTableLayer( OGRMSSQLSpatialDataSource
 OGRMSSQLSpatialTableLayer::~OGRMSSQLSpatialTableLayer()
 
 {
+    if ( bNeedSpatialIndex )
+    {
+        DropSpatialIndex();
+        CreateSpatialIndex();
+    }
+    
     CPLFree( pszTableName );
     CPLFree( pszLayerName );
     CPLFree( pszSchemaName );
@@ -165,11 +174,11 @@ OGRFeatureDefn* OGRMSSQLSpatialTableLayer::GetLayerDefn()
     eErr = BuildFeatureDefn( pszLayerName, &oGetCol );
     if( eErr != CE_None )
         return NULL;
-
+        
     if (eGeomType != wkbNone)
         poFeatureDefn->SetGeomType(eGeomType);
     
-    if ( GetSpatialRef() && poFeatureDefn->GetGeomFieldCount() == 1)
+    if ( GetSpatialRef() && poFeatureDefn->GetGeomFieldCount() == 1)
         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( poSRS );
 
     if( poFeatureDefn->GetFieldCount() == 0 &&
@@ -266,6 +275,7 @@ CPLErr OGRMSSQLSpatialTableLayer::Initialize( const char *pszSchema,
         else
             this->pszLayerName = CPLStrdup(CPLSPrintf("%s.%s", pszSchemaName, pszTableName));
     }
+    SetDescription( this->pszLayerName );
 
 /* -------------------------------------------------------------------- */
 /*      Have we been provided a geometry column?                        */
@@ -279,6 +289,7 @@ CPLErr OGRMSSQLSpatialTableLayer::Initialize( const char *pszSchema,
     if (eType != wkbNone)
         eGeomType = eType;
 
+
 /* -------------------------------------------------------------------- */
 /*             Try to find out the spatial reference                    */
 /* -------------------------------------------------------------------- */
@@ -352,16 +363,21 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateSpatialIndex()
             return OGRERR_FAILURE;
         }
 
-        oStatement.Appendf("CREATE SPATIAL INDEX [ogr_%s_sidx] ON [%s].[%s] ( [%s] ) "
+        if (oExt.MinX == oExt.MaxX || oExt.MinY == oExt.MaxY)
+            return OGRERR_NONE; /* skip creating index */
+
+        oStatement.Appendf("CREATE SPATIAL INDEX [ogr_%s_%s_%s_sidx] ON [%s].[%s] ( [%s] ) "
             "USING GEOMETRY_GRID WITH (BOUNDING_BOX =(%.15g, %.15g, %.15g, %.15g))",
-                           pszGeomColumn, pszSchemaName, pszTableName, pszGeomColumn, 
+                           pszSchemaName, pszTableName, pszGeomColumn, 
+                           pszSchemaName, pszTableName, pszGeomColumn, 
                            oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY );
     }
     else if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
     {
-        oStatement.Appendf("CREATE SPATIAL INDEX [ogr_%s_sidx] ON [%s].[%s] ( [%s] ) "
+        oStatement.Appendf("CREATE SPATIAL INDEX [ogr_%s_%s_%s_sidx] ON [%s].[%s] ( [%s] ) "
             "USING GEOGRAPHY_GRID",
-                           pszGeomColumn, pszSchemaName, pszTableName, pszGeomColumn );
+                           pszSchemaName, pszTableName, pszGeomColumn, 
+                           pszSchemaName, pszTableName, pszGeomColumn );
     }
     else
     {
@@ -370,8 +386,6 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateSpatialIndex()
         return OGRERR_FAILURE;
     }
 
-    //poDS->GetSession()->BeginTransaction();
-    
     if( !oStatement.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -380,8 +394,6 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateSpatialIndex()
         return OGRERR_FAILURE;
     } 
 
-    //poDS->GetSession()->CommitTransaction();
-
     return OGRERR_NONE;
 }
 
@@ -398,13 +410,13 @@ void OGRMSSQLSpatialTableLayer::DropSpatialIndex()
     CPLODBCStatement oStatement( poDS->GetSession() );
 
     oStatement.Appendf("IF  EXISTS (SELECT * FROM sys.indexes "
-        "WHERE object_id = OBJECT_ID(N'[%s].[%s]') AND name = N'ogr_%s_sidx') "
-        "DROP INDEX [ogr_%s_sidx] ON [%s].[%s]",
+        "WHERE object_id = OBJECT_ID(N'[%s].[%s]') AND name = N'ogr_%s_%s_%s_sidx') "
+        "DROP INDEX [ogr_%s_%s_%s_sidx] ON [%s].[%s]",
+                       pszSchemaName, pszTableName, 
+                       pszSchemaName, pszTableName, pszGeomColumn, 
                        pszSchemaName, pszTableName, pszGeomColumn, 
-                       pszGeomColumn, pszSchemaName, pszTableName );
+                       pszSchemaName, pszTableName );
     
-    //poDS->GetSession()->BeginTransaction();
-
     if( !oStatement.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -412,8 +424,6 @@ void OGRMSSQLSpatialTableLayer::DropSpatialIndex()
                       poDS->GetSession()->GetLastError());
         return;
     } 
-
-    //poDS->GetSession()->CommitTransaction();
 }
 
 /************************************************************************/
@@ -618,7 +628,7 @@ void OGRMSSQLSpatialTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMSSQLSpatialTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMSSQLSpatialTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -630,7 +640,7 @@ OGRFeature *OGRMSSQLSpatialTableLayer::GetFeature( long nFeatureId )
 
     poStmt = new CPLODBCStatement( poDS->GetSession() );
     CPLString osFields = BuildFields();
-    poStmt->Appendf( "select %s from %s where %s = %ld", osFields.c_str(), 
+    poStmt->Appendf( "select %s from %s where %s = " CPL_FRMT_GIB, osFields.c_str(), 
         poFeatureDefn->GetName(), pszFIDColumn, nFeatureId );
 
     if( !poStmt->ExecuteSQL() )
@@ -707,7 +717,7 @@ int OGRMSSQLSpatialTableLayer::TestCapability( const char * pszCap )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRMSSQLSpatialTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRMSSQLSpatialTableLayer::GetFeatureCount( int bForce )
 
 {
     GetLayerDefn();
@@ -725,7 +735,7 @@ int OGRMSSQLSpatialTableLayer::GetFeatureCount( int bForce )
         return OGRMSSQLSpatialLayer::GetFeatureCount( bForce );
     }
 
-    int nRet = atoi(poStatement->GetColData( 0 ));
+    GIntBig nRet = CPLAtoGIntBig(poStatement->GetColData( 0 ));
     delete poStatement;
     return nRet;
 }
@@ -767,6 +777,13 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateField( OGRFieldDefn *poFieldIn,
         else
             strcpy( szFieldType, "int" );
     }
+    else if( oField.GetType() == OFTInteger64 )
+    {
+        if( oField.GetWidth() > 0 && bPreservePrecision )
+            sprintf( szFieldType, "numeric(%d,0)", oField.GetWidth() );
+        else
+            strcpy( szFieldType, "bigint" );
+    }
     else if( oField.GetType() == OFTReal )
     {
         if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
@@ -779,9 +796,9 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateField( OGRFieldDefn *poFieldIn,
     else if( oField.GetType() == OFTString )
     {
         if( oField.GetWidth() == 0 || !bPreservePrecision )
-            strcpy( szFieldType, "varchar(MAX)" );
+            strcpy( szFieldType, "nvarchar(MAX)" );
         else
-            sprintf( szFieldType, "varchar(%d)", oField.GetWidth() );
+            sprintf( szFieldType, "nvarchar(%d)", oField.GetWidth() );
     }
     else if( oField.GetType() == OFTDate )
     {
@@ -826,6 +843,21 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateField( OGRFieldDefn *poFieldIn,
     oStmt.Appendf( "ALTER TABLE [%s].[%s] ADD [%s] %s", 
         pszSchemaName, pszTableName, oField.GetNameRef(), szFieldType);
 
+    if ( !oField.IsNullable() )
+    {
+        oStmt.Append(" NOT NULL");
+    }
+    if ( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+    {
+        /* process default value specifications */
+        if ( EQUAL(oField.GetDefault(), "CURRENT_TIME") )
+            oStmt.Append(" DEFAULT(CONVERT([time],getdate()))");
+        else if ( EQUAL(oField.GetDefault(), "CURRENT_DATE") )
+            oStmt.Append( " DEFAULT(CONVERT([date],getdate()))" );
+        else 
+            oStmt.Appendf(" DEFAULT(%s)", oField.GetDefault());
+    }
+
     if( !oStmt.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
@@ -845,12 +877,12 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateField( OGRFieldDefn *poFieldIn,
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /*                                                                      */
 /*      SetFeature() is implemented by an UPDATE SQL command            */
 /************************************************************************/
 
-OGRErr OGRMSSQLSpatialTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRMSSQLSpatialTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     OGRErr              eErr = OGRERR_FAILURE;
@@ -895,43 +927,103 @@ OGRErr OGRMSSQLSpatialTableLayer::SetFeature( OGRFeature *poFeature )
     if (poFeature->GetGeometryRef() != poGeom)
     {
         CPLError( CE_Warning, CPLE_NotSupported,
-                  "Geometry with FID = %ld has been modified.", poFeature->GetFID() );
+                  "Geometry with FID = " CPL_FRMT_GIB " has been modified.", poFeature->GetFID() );
     }
 
+    int nFieldCount = poFeatureDefn->GetFieldCount();
+    int bind_num = 0;
+    void** bind_buffer = (void**)CPLMalloc(sizeof(void*) * nFieldCount);
+    
+
     int bNeedComma = FALSE;
-    if(pszGeomColumn != NULL)
+    if(poGeom != NULL && pszGeomColumn != NULL)
     {
-        char    *pszWKT = NULL;
-
-        if (poGeom != NULL)
-            poGeom->exportToWkt( &pszWKT );
-
         oStmt.Appendf( "[%s] = ", pszGeomColumn );
-
-        if( pszWKT != NULL && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
-            || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
+        
+        if (nUploadGeometryFormat == MSSQLGEOMETRY_WKB)
         {
-            if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+            int nWKBLen = poGeom->WkbSize();
+            GByte *pabyWKB = (GByte *) CPLMalloc(nWKBLen + 1);
+        
+            if( poGeom->exportToWkb( wkbNDR, pabyWKB ) == OGRERR_NONE && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
+                || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
             {
-                oStmt.Append( "geography::STGeomFromText(" );
-                OGRMSSQLAppendEscaped(&oStmt, pszWKT);
-                oStmt.Appendf(",%d)", nSRSId );
+                int nRetCode = SQLBindParameter(oStmt.GetStatement(), (SQLUSMALLINT)(bind_num + 1), 
+                    SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 
+                    nWKBLen, 0, (SQLPOINTER)pabyWKB, nWKBLen, (SQLLEN*)&nWKBLen);
+                if ( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
+                {
+                    if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+                    {
+                        oStmt.Append( "geography::STGeomFromWKB(?" );
+                        oStmt.Appendf(",%d)", nSRSId );
+                    }
+                    else
+                    {
+                        oStmt.Append( "geometry::STGeomFromWKB(?" );
+                        oStmt.Appendf(",%d).MakeValid()", nSRSId );
+                    }    
+                    bind_buffer[bind_num] = pabyWKB;
+                    ++bind_num;
+                }
+                else
+                {
+                    oStmt.Append( "null" );
+                    CPLFree(pabyWKB);
+                }           
+            }
+            else
+            {
+                oStmt.Append( "null" );
+                CPLFree(pabyWKB);
+            }
+        }
+        else if (nUploadGeometryFormat == MSSQLGEOMETRY_WKT)
+        {
+            char    *pszWKT = NULL;
+            if( poGeom->exportToWkt( &pszWKT ) == OGRERR_NONE && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
+                || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
+            {
+                size_t nLen = 0;
+                while(pszWKT[nLen] != '\0')
+                    nLen ++;
+                
+                int nRetCode = SQLBindParameter(oStmt.GetStatement(), (SQLUSMALLINT)(bind_num + 1), 
+                    SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 
+                    nLen, 0, (SQLPOINTER)pszWKT, 0, NULL);
+                if ( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
+                {
+                    if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+                    {
+                        oStmt.Append( "geography::STGeomFromText(?" );
+                        oStmt.Appendf(",%d)", nSRSId );
+                    }
+                    else
+                    {
+                        oStmt.Append( "geometry::STGeomFromText(?" );
+                        oStmt.Appendf(",%d).MakeValid()", nSRSId );
+                    }    
+                    bind_buffer[bind_num] = pszWKT;
+                    ++bind_num;
+                }
+                else
+                {
+                    oStmt.Append( "null" );
+                    CPLFree(pszWKT);
+                }           
             }
             else
             {
-                oStmt.Append( "geometry::STGeomFromText(" );
-                OGRMSSQLAppendEscaped(&oStmt, pszWKT);
-                oStmt.Appendf(",%d).MakeValid()", nSRSId );
+                oStmt.Append( "null" );
+                CPLFree(pszWKT);
             }
         }
         else
             oStmt.Append( "null" );
 
         bNeedComma = TRUE;
-        CPLFree(pszWKT);
     }
 
-    int nFieldCount = poFeatureDefn->GetFieldCount();
     int i;
     for( i = 0; i < nFieldCount; i++ )
     {
@@ -946,11 +1038,11 @@ OGRErr OGRMSSQLSpatialTableLayer::SetFeature( OGRFeature *poFeature )
         if( !poFeature->IsFieldSet( i ) )
             oStmt.Append( "null" );
         else
-            AppendFieldValue(&oStmt, poFeature, i);
+            AppendFieldValue(&oStmt, poFeature, i, &bind_num, bind_buffer);
     }
 
     /* Add the WHERE clause */
-    oStmt.Appendf( " WHERE [%s] = %ld" , pszFIDColumn, poFeature->GetFID());
+    oStmt.Appendf( " WHERE [%s] = " CPL_FRMT_GIB, pszFIDColumn, poFeature->GetFID());
 
 /* -------------------------------------------------------------------- */
 /*      Execute the update.                                             */
@@ -959,11 +1051,22 @@ OGRErr OGRMSSQLSpatialTableLayer::SetFeature( OGRFeature *poFeature )
     if( !oStmt.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-            "Error updating feature with FID:%ld, %s", poFeature->GetFID(), 
+            "Error updating feature with FID:" CPL_FRMT_GIB ", %s", poFeature->GetFID(), 
                     poDS->GetSession()->GetLastError() );
 
+        for( i = 0; i < bind_num; i++ )
+            CPLFree(bind_buffer[i]);
+        CPLFree(bind_buffer);
+        
         return OGRERR_FAILURE;
     }
+
+    for( i = 0; i < bind_num; i++ )
+            CPLFree(bind_buffer[i]);
+    CPLFree(bind_buffer);
+
+    if (oStmt.GetRowCountAffected() < 1)
+        return OGRERR_NON_EXISTING_FEATURE;
     
     return OGRERR_NONE;
 }
@@ -972,7 +1075,7 @@ OGRErr OGRMSSQLSpatialTableLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRMSSQLSpatialTableLayer::DeleteFeature( long nFID )
+OGRErr OGRMSSQLSpatialTableLayer::DeleteFeature( GIntBig nFID )
 
 {
     GetLayerDefn();
@@ -998,26 +1101,29 @@ OGRErr OGRMSSQLSpatialTableLayer::DeleteFeature( long nFID )
 /* -------------------------------------------------------------------- */
     CPLODBCStatement oStatement( poDS->GetSession() );
 
-    oStatement.Appendf("DELETE FROM [%s] WHERE [%s] = %ld", 
+    oStatement.Appendf("DELETE FROM [%s] WHERE [%s] = " CPL_FRMT_GIB, 
             poFeatureDefn->GetName(), pszFIDColumn, nFID);
     
     if( !oStatement.ExecuteSQL() )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Attempt to delete feature with FID %ld failed. %s", 
+                  "Attempt to delete feature with FID " CPL_FRMT_GIB " failed. %s", 
                   nFID, poDS->GetSession()->GetLastError() );
 
         return OGRERR_FAILURE;
     }
+
+    if (oStatement.GetRowCountAffected() < 1)
+        return OGRERR_NON_EXISTING_FEATURE;
     
     return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRMSSQLSpatialTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     GetLayerDefn();
@@ -1049,7 +1155,7 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
     if (poFeature->GetGeometryRef() != poGeom)
     {
         CPLError( CE_Warning, CPLE_NotSupported,
-                  "Geometry with FID = %ld has been modified.", poFeature->GetFID() );
+                  "Geometry with FID = " CPL_FRMT_GIB " has been modified.", poFeature->GetFID() );
     }
 
     int bNeedComma = FALSE;
@@ -1062,6 +1168,16 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
 
     if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
     {
+        if( (GIntBig)(int)poFeature->GetFID() != poFeature->GetFID() &&
+            GetMetadataItem(OLMD_FID64) == NULL )
+        {
+            /* MSSQL server doesn't support modifying pk columns without recreating the field */
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Failed to create feature with large integer fid. "
+                  "The FID64 layer creation option should be used." );
+            return OGRERR_FAILURE;
+        }
+        
         if (bNeedComma)
             oStatement.Appendf( ", [%s]", pszFIDColumn );
         else
@@ -1070,8 +1186,12 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
             bNeedComma = TRUE;
         }
     }
-
+  
     int nFieldCount = poFeatureDefn->GetFieldCount();
+
+    int bind_num = 0;
+    void** bind_buffer = (void**)CPLMalloc(sizeof(void*) * (nFieldCount + 1));
+    
     int i;
     for( i = 0; i < nFieldCount; i++ )
     {
@@ -1093,43 +1213,98 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
     bNeedComma = FALSE;
     if(poGeom != NULL && pszGeomColumn != NULL)
     {
-        char    *pszWKT = NULL;
-    
-        //poGeom->setCoordinateDimension( nCoordDimension );
-
-        poGeom->exportToWkt( &pszWKT );
-
-        if( pszWKT != NULL && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
-            || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
+        if (nUploadGeometryFormat == MSSQLGEOMETRY_WKB)
         {
-            if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+            int nWKBLen = poGeom->WkbSize();
+            GByte *pabyWKB = (GByte *) CPLMalloc(nWKBLen + 1);
+        
+            if( poGeom->exportToWkb( wkbNDR, pabyWKB ) == OGRERR_NONE && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
+                || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
+            {
+                int nRetCode = SQLBindParameter(oStatement.GetStatement(), (SQLUSMALLINT)(bind_num + 1), 
+                    SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, 
+                    nWKBLen, 0, (SQLPOINTER)pabyWKB, nWKBLen, (SQLLEN*)&nWKBLen);
+                if ( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
+                {
+                    if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+                    {
+                        oStatement.Append( "geography::STGeomFromWKB(?" );
+                        oStatement.Appendf(",%d)", nSRSId );
+                    }
+                    else
+                    {
+                        oStatement.Append( "geometry::STGeomFromWKB(?" );
+                        oStatement.Appendf(",%d).MakeValid()", nSRSId );
+                    }    
+                    bind_buffer[bind_num] = pabyWKB;
+                    ++bind_num;
+                }
+                else
+                {
+                    oStatement.Append( "null" );
+                    CPLFree(pabyWKB);
+                }           
+            }
+            else
+            {
+                oStatement.Append( "null" );
+                CPLFree(pabyWKB);
+            }
+        }
+        else if (nUploadGeometryFormat == MSSQLGEOMETRY_WKT)
+        {
+            char    *pszWKT = NULL;
+            if( poGeom->exportToWkt( &pszWKT ) == OGRERR_NONE && (nGeomColumnType == MSSQLCOLTYPE_GEOMETRY 
+                || nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY))
             {
-                oStatement.Append( "geography::STGeomFromText(" );
-                OGRMSSQLAppendEscaped(&oStatement, pszWKT);
-                oStatement.Appendf(",%d)", nSRSId );
+                size_t nLen = 0;
+                while(pszWKT[nLen] != '\0')
+                    nLen ++;
+                
+                int nRetCode = SQLBindParameter(oStatement.GetStatement(), (SQLUSMALLINT)(bind_num + 1), 
+                    SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 
+                    nLen, 0, (SQLPOINTER)pszWKT, 0, NULL);
+                if ( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
+                {
+                    if (nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY)
+                    {
+                        oStatement.Append( "geography::STGeomFromText(?" );
+                        oStatement.Appendf(",%d)", nSRSId );
+                    }
+                    else
+                    {
+                        oStatement.Append( "geometry::STGeomFromText(?" );
+                        oStatement.Appendf(",%d).MakeValid()", nSRSId );
+                    }    
+                    bind_buffer[bind_num] = pszWKT;
+                    ++bind_num;
+                }
+                else
+                {
+                    oStatement.Append( "null" );
+                    CPLFree(pszWKT);
+                }           
             }
             else
             {
-                oStatement.Append( "geometry::STGeomFromText(" );
-                OGRMSSQLAppendEscaped(&oStatement, pszWKT);
-                oStatement.Appendf(",%d).MakeValid()", nSRSId );
-            }     
+                oStatement.Append( "null" );
+                CPLFree(pszWKT);
+            }
         }
         else
             oStatement.Append( "null" );
 
         bNeedComma = TRUE;
-        CPLFree(pszWKT);
     }
 
     /* Set the FID */
     if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
     {
         if (bNeedComma)
-            oStatement.Appendf( ", %ld", poFeature->GetFID() );
+            oStatement.Appendf( ", " CPL_FRMT_GIB, poFeature->GetFID() );
         else
         {
-            oStatement.Appendf( "%ld", poFeature->GetFID() );
+            oStatement.Appendf( CPL_FRMT_GIB, poFeature->GetFID() );
             bNeedComma = TRUE;
         }
     }
@@ -1144,7 +1319,7 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
         else
             bNeedComma = TRUE;
 
-        AppendFieldValue(&oStatement, poFeature, i);
+        AppendFieldValue(&oStatement, poFeature, i, &bind_num, bind_buffer);
     }
 
     oStatement.Append( ");" );
@@ -1162,9 +1337,17 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
                   "INSERT command for new feature failed. %s", 
                    poDS->GetSession()->GetLastError() );
 
+        for( i = 0; i < bind_num; i++ )
+            CPLFree(bind_buffer[i]);
+        CPLFree(bind_buffer);
+
         return OGRERR_FAILURE;
     }
 
+    for( i = 0; i < bind_num; i++ )
+            CPLFree(bind_buffer[i]);
+    CPLFree(bind_buffer);
+
     return OGRERR_NONE;
 }
 
@@ -1176,7 +1359,7 @@ OGRErr OGRMSSQLSpatialTableLayer::CreateFeature( OGRFeature *poFeature )
 /************************************************************************/
 
 void OGRMSSQLSpatialTableLayer::AppendFieldValue(CPLODBCStatement *poStatement,
-                                       OGRFeature* poFeature, int i)
+                                       OGRFeature* poFeature, int i, int *bind_num, void **bind_buffer)
 {
     int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
 
@@ -1237,10 +1420,30 @@ void OGRMSSQLSpatialTableLayer::AppendFieldValue(CPLODBCStatement *poStatement,
             *pszComma = '.';
     }
 
-    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
+    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTInteger64 && nOGRFieldType != OFTReal
         && !bIsDateNull )
     {
-        OGRMSSQLAppendEscaped(poStatement, pszStrValue);
+        if (nOGRFieldType == OFTString)
+        {
+            // bind UTF8 as unicode parameter
+            wchar_t* buffer = CPLRecodeToWChar( pszStrValue, CPL_ENC_UTF8, CPL_ENC_UCS2);
+            int nRetCode = SQLBindParameter(poStatement->GetStatement(), (SQLUSMALLINT)((*bind_num) + 1), 
+                SQL_PARAM_INPUT, SQL_C_WCHAR, SQL_WVARCHAR, 
+                wcslen(buffer) + 1, 0, (SQLPOINTER)buffer, 0, NULL);
+            if ( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO )
+            {
+                poStatement->Append( "?" );
+                bind_buffer[*bind_num] = buffer;
+                ++(*bind_num);
+            }
+            else
+            {
+                OGRMSSQLAppendEscaped(poStatement, pszStrValue);
+                CPLFree(buffer);
+            }
+        }
+        else
+            OGRMSSQLAppendEscaped(poStatement, pszStrValue);
     }
     else
     {
diff --git a/ogr/ogrsf_frmts/mysql/GNUmakefile b/ogr/ogrsf_frmts/mysql/GNUmakefile
index 292ae45..e2ea885 100644
--- a/ogr/ogrsf_frmts/mysql/GNUmakefile
+++ b/ogr/ogrsf_frmts/mysql/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrmysqldriver.o ogrmysqldatasource.o \
 		ogrmysqltablelayer.o ogrmysqllayer.o ogrmysqlresultlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(MYSQL_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(MYSQL_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/mysql/drv_mysql.html b/ogr/ogrsf_frmts/mysql/drv_mysql.html
index 0eff6ff..a5d4a51 100644
--- a/ogr/ogrsf_frmts/mysql/drv_mysql.html
+++ b/ogr/ogrsf_frmts/mysql/drv_mysql.html
@@ -130,12 +130,16 @@ The MySQL driver is not transactional at this time.<p>
         The default value is "TRUE".
     </li>
     <li>
-        <b>MYSQL_GEOM_COLUMN</b>: This option specifies the name of the 
+        <b>GEOMETRY_NAME</b>: This option specifies the name of the 
         geometry column.  The default value is "SHAPE".
     </li>
     <li>
-        <b>MYSQL_FID</b>: This option specifies the name of the FID column.
-        The default value is "OGR_FID"
+        <b>FID</b>: This option specifies the name of the FID column.
+        The default value is "OGR_FID". Note: option was called MYSQL_FID in releases before GDAL 2
+    </li>
+    <li>
+        <b>FID64</b>: (GDAL >= 2.0) This may be "TRUE" to create a FID column that can support
+        64 bit identifiers. The default value is "FALSE".
     </li>
     <li>
         <b>SPATIAL_INDEX</b>: May be "NO" to stop automatic creation of 
diff --git a/ogr/ogrsf_frmts/mysql/ogr_mysql.h b/ogr/ogrsf_frmts/mysql/ogr_mysql.h
index a7ce7b7..c1d4c4d 100644
--- a/ogr/ogrsf_frmts/mysql/ogr_mysql.h
+++ b/ogr/ogrsf_frmts/mysql/ogr_mysql.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_mysql.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_mysql.h 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Declarations for MySQL OGR Driver Classes.
@@ -66,7 +66,7 @@ class OGRMySQLLayer : public OGRLayer
     OGRSpatialReference *poSRS;
     int                 nSRSId;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRMySQLDataSource    *poDS;
  
@@ -93,7 +93,7 @@ class OGRMySQLLayer : public OGRLayer
 
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -135,16 +135,16 @@ class OGRMySQLTableLayer : public OGRMySQLLayer
 
     OGRErr              Initialize(const char* pszTableName);
     
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     void                SetSpatialFilter( OGRGeometry * );
 
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
     
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -181,7 +181,7 @@ class OGRMySQLResultLayer : public OGRMySQLLayer
 
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual int         TestCapability( const char * );
 };
@@ -226,14 +226,14 @@ class OGRMySQLDataSource : public OGRDataSource
 
     OGRErr              InitializeMetadataTables();
 
-    int                 Open( const char *, int bUpdate, int bTestOpen );
-    int                 OpenTable( const char *, int bUpdate, int bTestOpen );
+    int                 Open( const char *, char** papszOpenOptions, int bUpdate );
+    int                 OpenTable( const char *, int bUpdate );
 
     const char          *GetName() { return pszName; }
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -256,23 +256,6 @@ class OGRMySQLDataSource : public OGRDataSource
     void                InterruptLongResult();
 };
 
-/************************************************************************/
-/*                            OGRMySQLDriver                            */
-/************************************************************************/
-
-class OGRMySQLDriver : public OGRSFDriver
-{
-  public:
-                ~OGRMySQLDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_MYSQL_H_INCLUDED */
 
 
diff --git a/ogr/ogrsf_frmts/mysql/ogrmysqldatasource.cpp b/ogr/ogrsf_frmts/mysql/ogrmysqldatasource.cpp
index 4dcfbb8..2b42b27 100644
--- a/ogr/ogrsf_frmts/mysql/ogrmysqldatasource.cpp
+++ b/ogr/ogrsf_frmts/mysql/ogrmysqldatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmysqldatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrmysqldatasource.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMySQLDataSource class.
@@ -37,7 +37,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrmysqldatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrmysqldatasource.cpp 29019 2015-04-25 20:34:19Z rouault $");
 /************************************************************************/
 /*                         OGRMySQLDataSource()                         */
 /************************************************************************/
@@ -109,24 +109,11 @@ void OGRMySQLDataSource::ReportError( const char *pszDescription )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRMySQLDataSource::Open( const char * pszNewName, int bUpdate,
-                              int bTestOpen )
+int OGRMySQLDataSource::Open( const char * pszNewName, char** papszOpenOptions,
+                              int bUpdate )
 
 {
     CPLAssert( nLayers == 0 );
-
-/* -------------------------------------------------------------------- */
-/*      Verify MySQL prefix.                                            */
-/* -------------------------------------------------------------------- */
-    if( !EQUALN(pszNewName,"MYSQL:",6) )
-    {
-        if( !bTestOpen )
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "%s does not conform to MySQL naming convention,"
-                      " MYSQL:dbname[, user=..][,password=..][,host=..][,port=..][tables=table;table;...]",
-                      pszNewName );
-        return FALSE;
-    }
     
 /* -------------------------------------------------------------------- */
 /*      Use options process to get .my.cnf file contents.               */
@@ -135,10 +122,40 @@ int OGRMySQLDataSource::Open( const char * pszNewName, int bUpdate,
     char **papszTableNames=NULL;
     std::string oHost, oPassword, oUser, oDB;
 
+    CPLString osNewName(pszNewName);
+    const char* apszOpenOptions[] = { "dbname", "port", "user", "password",
+                                      "host", "tables" };
+    for(int i=0; i <(int)(sizeof(apszOpenOptions)/sizeof(char*));i++)
+    {
+        const char* pszVal = CSLFetchNameValue(papszOpenOptions, apszOpenOptions[i]);
+        if( pszVal )
+        {
+            if( osNewName[osNewName.size()-1] != ':' )
+                osNewName += ",";
+            if( i > 0 )
+            {
+                osNewName += apszOpenOptions[i];
+                osNewName += "=";
+            }
+            if( EQUAL(apszOpenOptions[i], "tables") )
+            {
+                for( ; *pszVal; ++pszVal )
+                {
+                    if( *pszVal == ',' )
+                        osNewName += ";";
+                    else
+                        osNewName += *pszVal;
+                }
+            }
+            else
+                osNewName += pszVal;
+        }
+    }
+    
 /* -------------------------------------------------------------------- */
 /*      Parse out connection information.                               */
 /* -------------------------------------------------------------------- */
-    char **papszItems = CSLTokenizeString2( pszNewName+6, ",", 
+    char **papszItems = CSLTokenizeString2( osNewName+6, ",", 
                                             CSLT_HONOURSTRINGS );
 
     if( CSLCount(papszItems) < 1 )
@@ -281,7 +298,7 @@ int OGRMySQLDataSource::Open( const char * pszNewName, int bUpdate,
     {
         //  FIXME: This should be fixed to deal with tables 
         //  for which we can't open because the name is bad/ 
-        OpenTable( papszTableNames[iRecord], bUpdate, FALSE );
+        OpenTable( papszTableNames[iRecord], bUpdate );
     }
 
     CSLDestroy( papszTableNames );
@@ -293,8 +310,8 @@ int OGRMySQLDataSource::Open( const char * pszNewName, int bUpdate,
 /*                             OpenTable()                              */
 /************************************************************************/
 
-int OGRMySQLDataSource::OpenTable( const char *pszNewName, int bUpdate,
-                                   CPL_UNUSED int bTestOpen )
+int OGRMySQLDataSource::OpenTable( const char *pszNewName, int bUpdate )
+
 {
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -805,11 +822,11 @@ int OGRMySQLDataSource::DeleteLayer( int iLayer)
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRMySQLDataSource::CreateLayer( const char * pszLayerNameIn,
+OGRMySQLDataSource::ICreateLayer( const char * pszLayerNameIn,
                               OGRSpatialReference *poSRS,
                               OGRwkbGeometryType eType,
                               char ** papszOptions )
@@ -873,10 +890,15 @@ OGRMySQLDataSource::CreateLayer( const char * pszLayerNameIn,
     if (!pszGeomColumnName)
         pszGeomColumnName="SHAPE";
 
-    pszExpectedFIDName = CSLFetchNameValue( papszOptions, "MYSQL_FID" );
+    pszExpectedFIDName = CSLFetchNameValue( papszOptions, "FID" );
+    if (!pszExpectedFIDName)
+        pszExpectedFIDName = CSLFetchNameValue( papszOptions, "MYSQL_FID" );
     if (!pszExpectedFIDName)
         pszExpectedFIDName="OGR_FID";
 
+    int bFID64 = CSLFetchBoolean(papszOptions, "FID64", FALSE);
+    const char* pszFIDType = bFID64 ? "BIGINT": "INT";
+    
 
     CPLDebug("MYSQL","Geometry Column Name %s.", pszGeomColumnName);
     CPLDebug("MYSQL","FID Column Name %s.", pszExpectedFIDName);
@@ -885,16 +907,16 @@ OGRMySQLDataSource::CreateLayer( const char * pszLayerNameIn,
     {
         osCommand.Printf(
                  "CREATE TABLE `%s` ( "
-                 "   %s INT UNIQUE NOT NULL AUTO_INCREMENT )",
-                 pszLayerName, pszExpectedFIDName );
+                 "   %s %s UNIQUE NOT NULL AUTO_INCREMENT )",
+                 pszLayerName, pszExpectedFIDName, pszFIDType );
     }
     else
     {
         osCommand.Printf(
                  "CREATE TABLE `%s` ( "
-                 "   %s INT UNIQUE NOT NULL AUTO_INCREMENT, "
+                 "   %s %s UNIQUE NOT NULL AUTO_INCREMENT, "
                  "   %s GEOMETRY NOT NULL )",
-                 pszLayerName, pszExpectedFIDName, pszGeomColumnName );
+                 pszLayerName, pszExpectedFIDName, pszFIDType, pszGeomColumnName );
     }
 
     if( CSLFetchNameValue( papszOptions, "ENGINE" ) != NULL )
@@ -1051,6 +1073,8 @@ OGRMySQLDataSource::CreateLayer( const char * pszLayerNameIn,
     eErr = poLayer->Initialize(pszLayerName);
     if (eErr == OGRERR_FAILURE)
         return NULL;
+    if( eType != wkbNone )
+        poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->SetNullable(FALSE);
 
     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
diff --git a/ogr/ogrsf_frmts/mysql/ogrmysqldriver.cpp b/ogr/ogrsf_frmts/mysql/ogrmysqldriver.cpp
index 6ed5381..307133a 100644
--- a/ogr/ogrsf_frmts/mysql/ogrmysqldriver.cpp
+++ b/ogr/ogrsf_frmts/mysql/ogrmysqldriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmysqldriver.cpp 27506 2014-07-07 19:49:05Z rouault $
+ * $Id: ogrmysqldriver.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMySQLDriver class.
@@ -31,17 +31,16 @@
 #include "cpl_conv.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrmysqldriver.cpp 27506 2014-07-07 19:49:05Z rouault $");
+CPL_CVSID("$Id: ogrmysqldriver.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
-static void* hMutex = NULL;
+static CPLMutex* hMutex = NULL;
 static int   bInitialized = FALSE;
 
 /************************************************************************/
-/*                          ~OGRMySQLDriver()                           */
+/*                        OGRMySQLDriverUnload()                        */
 /************************************************************************/
 
-OGRMySQLDriver::~OGRMySQLDriver()
-
+static void OGRMySQLDriverUnload( CPL_UNUSED GDALDriver* poDriver )
 {
     if( bInitialized )
     {
@@ -56,27 +55,27 @@ OGRMySQLDriver::~OGRMySQLDriver()
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                         OGRMySQLDriverIdentify()                     */
 /************************************************************************/
 
-const char *OGRMySQLDriver::GetName()
+static int OGRMySQLDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "MySQL";
+    return EQUALN(poOpenInfo->pszFilename,"MYSQL:",6);
 }
-
+ 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRMySQLDriver::Open( const char * pszFilename,
-                                     int bUpdate )
+static GDALDataset *OGRMySQLDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRMySQLDataSource     *poDS;
- 
-    if( !EQUALN(pszFilename,"MYSQL:",6) )
+
+    if( !OGRMySQLDriverIdentify(poOpenInfo) )
         return NULL;
+ 
     {
         CPLMutexHolderD(&hMutex);
         if( !bInitialized )
@@ -92,7 +91,8 @@ OGRDataSource *OGRMySQLDriver::Open( const char * pszFilename,
 
     poDS = new OGRMySQLDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, TRUE ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions,
+                     poOpenInfo->eAccess == GA_Update ) )
     {
         delete poDS;
         return NULL;
@@ -103,19 +103,22 @@ OGRDataSource *OGRMySQLDriver::Open( const char * pszFilename,
 
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRMySQLDriver::CreateDataSource( const char * pszName,
-                                              char ** /* papszOptions */ )
-
+static GDALDataset *OGRMySQLDriverCreate( const char * pszName,
+                                          CPL_UNUSED int nBands,
+                                          CPL_UNUSED int nXSize,
+                                          CPL_UNUSED int nYSize,
+                                          CPL_UNUSED GDALDataType eDT,
+                                          CPL_UNUSED char **papszOptions )
 {
     OGRMySQLDataSource     *poDS;
 
     poDS = new OGRMySQLDataSource();
 
 
-    if( !poDS->Open( pszName, TRUE, TRUE ) )
+    if( !poDS->Open( pszName, NULL, TRUE ) )
     {
         delete poDS;
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -127,25 +130,6 @@ OGRDataSource *OGRMySQLDriver::CreateDataSource( const char * pszName,
     return poDS;
 }
 
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRMySQLDriver::TestCapability( const char * pszCap )
-
-{
-
-    if( EQUAL(pszCap,ODsCCreateLayer) )
-        return TRUE;
-    if( EQUAL(pszCap,ODsCDeleteLayer) )
-        return TRUE;     
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-        
-    return FALSE;
-}
-
 /************************************************************************/
 /*                          RegisterOGRMySQL()                          */
 /************************************************************************/
@@ -155,6 +139,55 @@ void RegisterOGRMySQL()
 {
     if (! GDAL_CHECK_VERSION("MySQL driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRMySQLDriver );
-}
+  
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "MySQL" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "MySQL" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "MySQL" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_mysql.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "MYSQL:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='DBNAME' type='string' description='Database name' required='true'/>"
+"  <Option name='PORT' type='int' description='Port'/>"
+"  <Option name='USER' type='string' description='User name'/>"
+"  <Option name='PASSWORD' type='string' description='Password'/>"
+"  <Option name='HOST' type='string' description='Server hostname'/>"
+"  <Option name='TABLES' type='string' description='Restricted set of tables to list (comma separated)'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+    "<LayerCreationOptionList>"
+    "  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+    "  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+    "  <Option name='PRECISION' type='boolean' description='Whether fields created should keep the width and precision' default='YES'/>"
+    "  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column.' default='SHAPE'/>"
+    "  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
+    "  <Option name='FID' type='string' description='Name of the FID column to create' default='OGR_FID' deprecated_alias='MYSQL_FID'/>"
+    "  <Option name='FID64' type='boolean' description='Whether to create the FID column with BIGINT type to handle 64bit wide ids' default='NO'/>"
+    "  <Option name='ENGINE' type='string' description='Database engine to use.'/>"
+    "</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time Binary" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+
+        poDriver->pfnOpen = OGRMySQLDriverOpen;
+        poDriver->pfnIdentify = OGRMySQLDriverIdentify;
+        poDriver->pfnCreate = OGRMySQLDriverCreate;
+        poDriver->pfnUnloadDriver = OGRMySQLDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/mysql/ogrmysqllayer.cpp b/ogr/ogrsf_frmts/mysql/ogrmysqllayer.cpp
index ebfaf26..4f6b020 100644
--- a/ogr/ogrsf_frmts/mysql/ogrmysqllayer.cpp
+++ b/ogr/ogrsf_frmts/mysql/ogrmysqllayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmysqllayer.cpp 26679 2013-12-01 11:35:25Z rouault $
+ * $Id: ogrmysqllayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMySQLLayer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrmysqllayer.cpp 26679 2013-12-01 11:35:25Z rouault $");
+CPL_CVSID("$Id: ogrmysqllayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGRMySQLLayer()                            */
@@ -177,7 +177,7 @@ OGRFeature *OGRMySQLLayer::RecordToFeature( char **papszRow,
                 return NULL;
             }
 
-            poFeature->SetFID( atoi(papszRow[iField]) );
+            poFeature->SetFID( CPLAtoGIntBig(papszRow[iField]) );
         }
 
         if( papszRow[iField] == NULL ) 
@@ -294,7 +294,7 @@ OGRFeature *OGRMySQLLayer::GetNextRawFeature()
 /*      Note that we actually override this in OGRMySQLTableLayer.      */
 /************************************************************************/
 
-OGRFeature *OGRMySQLLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMySQLLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRLayer::GetFeature( nFeatureId );
diff --git a/ogr/ogrsf_frmts/mysql/ogrmysqlresultlayer.cpp b/ogr/ogrsf_frmts/mysql/ogrmysqlresultlayer.cpp
index 67dafa7..1037e3a 100644
--- a/ogr/ogrsf_frmts/mysql/ogrmysqlresultlayer.cpp
+++ b/ogr/ogrsf_frmts/mysql/ogrmysqlresultlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmysqlresultlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrmysqlresultlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMySQLResultLayer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_mysql.h"
 
-CPL_CVSID("$Id: ogrmysqlresultlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrmysqlresultlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                        OGRMySQLResultLayer()                         */
@@ -79,6 +79,7 @@ OGRFeatureDefn *OGRMySQLResultLayer::ReadResultDefinition()
 /*      Parse the returned table information.                           */
 /* -------------------------------------------------------------------- */
     OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
+    SetDescription( poDefn->GetName() );
     int            iRawField;
 
     poDefn->Reference();
@@ -298,7 +299,7 @@ void OGRMySQLResultLayer::ResetReading()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRMySQLResultLayer::GetFeatureCount( int bForce )
+GIntBig OGRMySQLResultLayer::GetFeatureCount( int bForce )
 
 {
     // I wonder if we could do anything smart here...
diff --git a/ogr/ogrsf_frmts/mysql/ogrmysqltablelayer.cpp b/ogr/ogrsf_frmts/mysql/ogrmysqltablelayer.cpp
index d255239..1a6ce03 100644
--- a/ogr/ogrsf_frmts/mysql/ogrmysqltablelayer.cpp
+++ b/ogr/ogrsf_frmts/mysql/ogrmysqltablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrmysqltablelayer.cpp 27916 2014-10-30 15:38:57Z rouault $
+ * $Id: ogrmysqltablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRMySQLTableLayer class.
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include "ogr_mysql.h"
 
-CPL_CVSID("$Id: ogrmysqltablelayer.cpp 27916 2014-10-30 15:38:57Z rouault $");
+CPL_CVSID("$Id: ogrmysqltablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $");
 
 /************************************************************************/
 /*                         OGRMySQLTableLayer()                         */
@@ -57,6 +57,8 @@ OGRMySQLTableLayer::OGRMySQLTableLayer( OGRMySQLDataSource *poDSIn,
 
     poFeatureDefn = NULL;
     bLaunderColumnNames = TRUE;
+    
+    SetDescription( pszTableName );
 }
 
 /************************************************************************/
@@ -130,6 +132,7 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
     OGRFeatureDefn *poDefn = new OGRFeatureDefn( pszTable );
     char           **papszRow;
     OGRwkbGeometryType eForcedGeomType = wkbUnknown;
+    int bGeomColumnNotNullable = FALSE;
 
     poDefn->Reference();
 
@@ -217,7 +220,7 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
         }
         else if( EQUALN(pszType,"bigint",6) )
         {
-            oField.SetType( OFTInteger );
+            oField.SetType( OFTInteger64 );
         }
         else if( EQUALN(pszType,"decimal",7) )
         {
@@ -295,6 +298,7 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
             {
                 pszGeomColumn = CPLStrdup(papszRow[0]);
                 eForcedGeomType = OGRFromOGCGeomType(pszType);
+                bGeomColumnNotNullable = ( papszRow[2] != NULL && EQUAL(papszRow[2], "NO") );
             }
             else
             {
@@ -306,13 +310,54 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
         }
         // Is this an integer primary key field?
         if( !bHasFid && papszRow[3] != NULL && EQUAL(papszRow[3],"PRI") 
-            && oField.GetType() == OFTInteger )
+            && (oField.GetType() == OFTInteger || oField.GetType() == OFTInteger64) )
         {
             bHasFid = TRUE;
             pszFIDColumn = CPLStrdup(oField.GetNameRef());
+            if( oField.GetType() == OFTInteger64 )
+                SetMetadataItem(OLMD_FID64, "YES");
             continue;
         }
-
+        
+        // Is not nullable ?
+        if( papszRow[2] != NULL && EQUAL(papszRow[2], "NO") )
+            oField.SetNullable(FALSE);
+        
+        // Has default ?
+        const char* pszDefault = papszRow[4];
+        if( pszDefault != NULL )
+        {
+            if( !EQUAL(pszDefault, "NULL") &&
+                !EQUALN(pszDefault, "CURRENT_", strlen("CURRENT_")) &&
+                pszDefault[0] != '(' &&
+                pszDefault[0] != '\'' &&
+                CPLGetValueType(pszDefault) == CPL_VALUE_STRING )
+            {
+                int nYear, nMonth, nDay, nHour, nMinute;
+                float fSecond;
+                if( oField.GetType() == OFTDateTime &&
+                    sscanf(pszDefault, "%d-%d-%d %d:%d:%f", &nYear, &nMonth, &nDay,
+                                &nHour, &nMinute, &fSecond) == 6 )
+                {
+                    oField.SetDefault(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
+                                            nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond+0.5)));
+                }
+                else
+                {
+                    CPLString osDefault("'");
+                    char* pszTmp = CPLEscapeString(pszDefault, -1, CPLES_SQL);
+                    osDefault += pszTmp;
+                    CPLFree(pszTmp);
+                    osDefault += "'";
+                    oField.SetDefault(osDefault);
+                }
+            }
+            else
+            {
+                oField.SetDefault(pszDefault);
+            }
+        }
+        
         poDefn->AddFieldDefn( &oField );
     }
 
@@ -360,7 +405,7 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
             OGRwkbGeometryType nGeomType = OGRFromOGCGeomType(pszType);
 
             if( papszRow[1] != NULL && atoi(papszRow[1]) == 3 )
-                nGeomType = (OGRwkbGeometryType) (nGeomType | wkb25DBit);
+                nGeomType = wkbSetZ(nGeomType);
 
             poDefn->SetGeomType( nGeomType );
 
@@ -368,6 +413,9 @@ OGRFeatureDefn *OGRMySQLTableLayer::ReadTableDefinition( const char *pszTable )
         else if (eForcedGeomType != wkbUnknown)
             poDefn->SetGeomType(eForcedGeomType);
 
+        if( bGeomColumnNotNullable )
+            poDefn->GetGeomFieldDefn(0)->SetNullable(FALSE);
+        
         if( hResult != NULL )
             mysql_free_result( hResult );   //Free our query results for finding type.
 			hResult = NULL;
@@ -405,9 +453,6 @@ void OGRMySQLTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
 void OGRMySQLTableLayer::BuildWhere()
 
 {
-    // don't mess up decimal separator 
-    CPLLocaleC oLocaleForcer; 
-
     CPLFree( pszWHERE );
     pszWHERE = (char*)CPLMalloc(500 + ((pszQuery) ? strlen(pszQuery) : 0));
     pszWHERE[0] = '\0';
@@ -421,7 +466,7 @@ void OGRMySQLTableLayer::BuildWhere()
         //POLYGON((MINX MINY, MAXX MINY, MAXX MAXY, MINX MAXY, MINX MINY))
         m_poFilterGeom->getEnvelope( &sEnvelope );
         
-        snprintf(szEnvelope, sizeof(szEnvelope),
+        CPLsnprintf(szEnvelope, sizeof(szEnvelope),
                 "POLYGON((%.18g %.18g, %.18g %.18g, %.18g %.18g, %.18g %.18g, %.18g %.18g))",
                 sEnvelope.MinX, sEnvelope.MinY,
                 sEnvelope.MaxX, sEnvelope.MinY,
@@ -603,14 +648,14 @@ int OGRMySQLTableLayer::TestCapability( const char * pszCap )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /*                                                                      */
 /*      SetFeature() is implemented by dropping the old copy of the     */
 /*      feature in question (if there is one) and then creating a       */
 /*      new one with the provided feature id.                           */
 /************************************************************************/
 
-OGRErr OGRMySQLTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRMySQLTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     OGRErr eErr;
@@ -633,7 +678,7 @@ OGRErr OGRMySQLTableLayer::SetFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRMySQLTableLayer::DeleteFeature( long nFID )
+OGRErr OGRMySQLTableLayer::DeleteFeature( GIntBig nFID )
 
 {
     MYSQL_RES           *hResult=NULL;
@@ -647,7 +692,7 @@ OGRErr OGRMySQLTableLayer::DeleteFeature( long nFID )
     if( !bHasFid )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "DeleteFeature(%ld) failed.  Unable to delete features "
+                  "DeleteFeature(" CPL_FRMT_GIB ") failed.  Unable to delete features "
                   "in tables without\n a recognised FID column.",
                   nFID );
         return OGRERR_FAILURE;
@@ -657,7 +702,7 @@ OGRErr OGRMySQLTableLayer::DeleteFeature( long nFID )
 /* -------------------------------------------------------------------- */
 /*      Form the statement to drop the record.                          */
 /* -------------------------------------------------------------------- */
-    osCommand.Printf( "DELETE FROM `%s` WHERE `%s` = %ld",
+    osCommand.Printf( "DELETE FROM `%s` WHERE `%s` = " CPL_FRMT_GIB,
                       poFeatureDefn->GetName(), pszFIDColumn, nFID );
                       
 /* -------------------------------------------------------------------- */
@@ -675,15 +720,15 @@ OGRErr OGRMySQLTableLayer::DeleteFeature( long nFID )
         mysql_free_result( hResult );
     hResult = NULL;
     
-    return OGRERR_NONE;
+    return mysql_affected_rows( poDS->GetConn() ) > 0 ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
 }
 
 
 /************************************************************************/
-/*                       CreateFeature()                                */
+/*                       ICreateFeature()                                */
 /************************************************************************/
 
-OGRErr OGRMySQLTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRMySQLTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     MYSQL_RES           *hResult=NULL;
@@ -758,9 +803,32 @@ OGRErr OGRMySQLTableLayer::CreateFeature( OGRFeature *poFeature )
     // Set the FID 
     if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
     {
+        if( (GIntBig)(int)poFeature->GetFID() != poFeature->GetFID() &&
+            GetMetadataItem(OLMD_FID64) == NULL )
+        {
+            CPLString osCommand2;
+            osCommand2.Printf(
+                     "ALTER TABLE `%s` MODIFY COLUMN `%s` BIGINT UNIQUE NOT NULL AUTO_INCREMENT",
+                     poFeatureDefn->GetName(), pszFIDColumn );
+
+            if( mysql_query(poDS->GetConn(), osCommand2 ) )
+            {
+                poDS->ReportError( osCommand2 );
+                return OGRERR_FAILURE;
+            }
+
+            // make sure to attempt to free results of successful queries
+            hResult = mysql_store_result( poDS->GetConn() );
+            if( hResult != NULL )
+                mysql_free_result( hResult );
+            hResult = NULL;   
+
+            SetMetadataItem(OLMD_FID64, "YES");
+        }
+        
         if( bNeedComma )
             osCommand += ", ";
-        osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
+        osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID() );
         bNeedComma = TRUE;
     }
 
@@ -777,6 +845,7 @@ OGRErr OGRMySQLTableLayer::CreateFeature( OGRFeature *poFeature )
         const char *pszStrValue = poFeature->GetFieldAsString(i);
 
         if( poFeatureDefn->GetFieldDefn(i)->GetType() != OFTInteger
+                 && poFeatureDefn->GetFieldDefn(i)->GetType() != OFTInteger64 
                  && poFeatureDefn->GetFieldDefn(i)->GetType() != OFTReal
                  && poFeatureDefn->GetFieldDefn(i)->GetType() != OFTBinary )
         {
@@ -788,6 +857,7 @@ OGRErr OGRMySQLTableLayer::CreateFeature( OGRFeature *poFeature )
             for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
             {
                 if( poFeatureDefn->GetFieldDefn(i)->GetType() != OFTIntegerList
+                    && poFeatureDefn->GetFieldDefn(i)->GetType() != OFTInteger64List
                     && poFeatureDefn->GetFieldDefn(i)->GetType() != OFTRealList
                     && poFeatureDefn->GetFieldDefn(i)->GetWidth() > 0
                     && iChar == poFeatureDefn->GetFieldDefn(i)->GetWidth() )
@@ -831,6 +901,7 @@ OGRErr OGRMySQLTableLayer::CreateFeature( OGRFeature *poFeature )
 
     osCommand += ")";
     
+    //CPLDebug("MYSQL", "%s", osCommand.c_str());
     int nQueryResult = mysql_query(poDS->GetConn(), osCommand.c_str() );
     const my_ulonglong nFID = mysql_insert_id( poDS->GetConn() );
     
@@ -908,6 +979,13 @@ OGRErr OGRMySQLTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
         else
             strcpy( szFieldType, "INTEGER" );
     }
+    else if( oField.GetType() == OFTInteger64 )
+    {
+        if( oField.GetWidth() > 0 && bPreservePrecision )
+            sprintf( szFieldType, "DECIMAL(%d,0)", oField.GetWidth() );
+        else
+            strcpy( szFieldType, "BIGINT" );
+    }
     else if( oField.GetType() == OFTReal )
     {
         if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
@@ -920,16 +998,21 @@ OGRErr OGRMySQLTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
 
     else if( oField.GetType() == OFTDate )
     {
+        oField.SetDefault(NULL);
         sprintf( szFieldType, "DATE" );
     }
 
     else if( oField.GetType() == OFTDateTime )
     {
-        sprintf( szFieldType, "DATETIME" );
+        if( oField.GetDefault() != NULL && EQUAL(oField.GetDefault(), "CURRENT_TIMESTAMP") )
+            sprintf( szFieldType, "TIMESTAMP" );
+        else
+            sprintf( szFieldType, "DATETIME" );
     }
 
     else if( oField.GetType() == OFTTime )
     {
+        oField.SetDefault(NULL);
         sprintf( szFieldType, "TIME" );
     }
 
@@ -941,7 +1024,12 @@ OGRErr OGRMySQLTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
     else if( oField.GetType() == OFTString )
     {
         if( oField.GetWidth() == 0 || !bPreservePrecision )
-            strcpy( szFieldType, "TEXT" );
+        {
+            if( oField.GetDefault() != NULL )
+                strcpy( szFieldType, "VARCHAR(256)" );
+            else
+                strcpy( szFieldType, "TEXT" );
+        }
         else
             sprintf( szFieldType, "VARCHAR(%d)", oField.GetWidth() );
     }
@@ -966,8 +1054,14 @@ OGRErr OGRMySQLTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
     }
 
     osCommand.Printf(
-             "ALTER TABLE `%s` ADD COLUMN `%s` %s",
-             poFeatureDefn->GetName(), oField.GetNameRef(), szFieldType );
+             "ALTER TABLE `%s` ADD COLUMN `%s` %s%s",
+             poFeatureDefn->GetName(), oField.GetNameRef(), szFieldType,
+             (!oField.IsNullable()) ? " NOT NULL" : "");
+    if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+    {
+        osCommand += " DEFAULT ";
+        osCommand += oField.GetDefault();
+    }
 
     if( mysql_query(poDS->GetConn(), osCommand ) )
     {
@@ -991,7 +1085,7 @@ OGRErr OGRMySQLTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRMySQLTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRMySQLTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -1010,7 +1104,7 @@ OGRFeature *OGRMySQLTableLayer::GetFeature( long nFeatureId )
     CPLString    osCommand;
 
     osCommand.Printf(
-             "SELECT %s FROM `%s` WHERE `%s` = %ld", 
+             "SELECT %s FROM `%s` WHERE `%s` = " CPL_FRMT_GIB, 
              pszFieldList, poFeatureDefn->GetName(), pszFIDColumn, 
              nFeatureId );
     CPLFree( pszFieldList );
@@ -1071,7 +1165,7 @@ OGRFeature *OGRMySQLTableLayer::GetFeature( long nFeatureId )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRMySQLTableLayer::GetFeatureCount( CPL_UNUSED int bForce )
+GIntBig OGRMySQLTableLayer::GetFeatureCount( CPL_UNUSED int bForce )
 {
 /* -------------------------------------------------------------------- */
 /*      Ensure any active long result is interrupted.                   */
@@ -1104,10 +1198,10 @@ int OGRMySQLTableLayer::GetFeatureCount( CPL_UNUSED int bForce )
 /*      Capture the result.                                             */
 /* -------------------------------------------------------------------- */
     char **papszRow = mysql_fetch_row( hResult );
-    int nCount = 0;
+    GIntBig nCount = 0;
 
     if( papszRow != NULL && papszRow[0] != NULL )
-        nCount = atoi(papszRow[0]);
+        nCount = CPLAtoGIntBig(papszRow[0]);
 
     if( hResult != NULL )
         mysql_free_result( hResult );
diff --git a/ogr/ogrsf_frmts/nas/GNUmakefile b/ogr/ogrsf_frmts/nas/GNUmakefile
index 8409eaf..00e2833 100644
--- a/ogr/ogrsf_frmts/nas/GNUmakefile
+++ b/ogr/ogrsf_frmts/nas/GNUmakefile
@@ -5,7 +5,7 @@ OBJ =	ogrnasdriver.o ogrnasdatasource.o ogrnaslayer.o \
 	nashandler.o nasreader.o ogrnasrelationlayer.o
 
 CPPFLAGS :=	-I../gml -I.. -I../.. -DHAVE_XERCES=1 \
-		$(GDAL_INCLUDE) $(XERCES_INCLUDE) $(CPPFLAGS)
+		 $(XERCES_INCLUDE) $(CPPFLAGS)
 
 # By default, XML validation is disabled.  Uncomment the following line to
 # enable XML schema validation in the parser.
diff --git a/ogr/ogrsf_frmts/nas/nashandler.cpp b/ogr/ogrsf_frmts/nas/nashandler.cpp
index 36b4c7f..f8ddacf 100644
--- a/ogr/ogrsf_frmts/nas/nashandler.cpp
+++ b/ogr/ogrsf_frmts/nas/nashandler.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: nashandler.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: nashandler.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  NAS Reader
  * Purpose:  Implementation of NASHandler class.
diff --git a/ogr/ogrsf_frmts/nas/nasreader.cpp b/ogr/ogrsf_frmts/nas/nasreader.cpp
index 49e9a35..b950c74 100644
--- a/ogr/ogrsf_frmts/nas/nasreader.cpp
+++ b/ogr/ogrsf_frmts/nas/nasreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nasreader.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: nasreader.cpp 29051 2015-04-29 17:18:37Z rouault $
  *
  * Project:  NAS Reader
  * Purpose:  Implementation of NASReader class.
@@ -49,7 +49,7 @@
 #include "nasreaderp.h"
 #include "cpl_conv.h"
 
-void *NASReader::hMutex = NULL;
+CPLMutex *NASReader::hMutex = NULL;
 
 /************************************************************************/
 /*                          CreateGMLReader()                           */
@@ -854,7 +854,9 @@ int NASReader::SaveClasses( const char *pszFile )
 /*      looking for schema information.                                 */
 /************************************************************************/
 
-int NASReader::PrescanForSchema( int bGetExtents, CPL_UNUSED int bAnalyzeSRSPerFeature )
+int NASReader::PrescanForSchema( int bGetExtents,
+                                 CPL_UNUSED int bAnalyzeSRSPerFeature,
+                                 CPL_UNUSED int bOnlyDetectSRS )
 {
     GMLFeature  *poFeature;
 
@@ -887,6 +889,7 @@ int NASReader::PrescanForSchema( int bGetExtents, CPL_UNUSED int bAnalyzeSRSPerF
             if( papsGeometry[0] != NULL )
             {
                 poGeometry = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]);
+                poGeometry = ConvertGeometry(poGeometry);
             }
 
             if( poGeometry != NULL )
@@ -895,7 +898,7 @@ int NASReader::PrescanForSchema( int bGetExtents, CPL_UNUSED int bAnalyzeSRSPerF
                 OGREnvelope sEnvelope;
 
                 if( poClass->GetGeometryPropertyCount() == 0 )
-                    poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown ) );
+                    poClass->AddGeometryProperty( new GMLGeometryPropertyDefn( "", "", wkbUnknown, -1, TRUE ) );
 
                 OGRwkbGeometryType eGType = (OGRwkbGeometryType)
                     poClass->GetGeometryProperty(0)->GetType();
@@ -911,8 +914,8 @@ int NASReader::PrescanForSchema( int bGetExtents, CPL_UNUSED int bAnalyzeSRSPerF
                     eGType = wkbNone;
 
                 poClass->GetGeometryProperty(0)->SetType(
-                    (int) OGRMergeGeometryTypes(
-                        eGType, poGeometry->getGeometryType() ) );
+                    (int) OGRMergeGeometryTypesEx(
+                        eGType, poGeometry->getGeometryType(), TRUE ) );
 
                 // merge extents.
                 poGeometry->getEnvelope( &sEnvelope );
@@ -1020,8 +1023,7 @@ void NASReader::CheckForRelations( const char *pszElement,
         if( EQUALN(pszHRef,"urn:adv:oid:", 12 ) )
         {
             poFeature->AddOBProperty( pszElement, pszHRef );
-            if( ppszCurField && *ppszCurField )
-                CPLFree( *ppszCurField );
+            CPLFree( *ppszCurField );
             *ppszCurField = CPLStrdup( pszHRef + 12 );
         }
 
@@ -1078,3 +1080,20 @@ int NASReader::SetFilteredClassName(const char* pszClassName)
     m_pszFilteredClassName = (pszClassName) ? CPLStrdup(pszClassName) : NULL;
     return TRUE;
 }
+
+/************************************************************************/
+/*                         ConvertGeometry()                            */
+/************************************************************************/
+
+OGRGeometry*  NASReader::ConvertGeometry(OGRGeometry* poGeom)
+{
+    //poGeom = OGRGeometryFactory::forceToLineString( poGeom, false );
+    if( poGeom != NULL )
+    {
+        if( wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString )
+        {
+            poGeom = OGRGeometryFactory::forceTo(poGeom, wkbLineString);
+        }
+    }
+    return poGeom;
+}
diff --git a/ogr/ogrsf_frmts/nas/nasreaderp.h b/ogr/ogrsf_frmts/nas/nasreaderp.h
index 61bafc8..a577920 100644
--- a/ogr/ogrsf_frmts/nas/nasreaderp.h
+++ b/ogr/ogrsf_frmts/nas/nasreaderp.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: nasreaderp.h 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: nasreaderp.h 29051 2015-04-29 17:18:37Z rouault $
  *
  * Project:  NAS Reader
  * Purpose:  Private Declarations for OGR NAS Reader code.
@@ -34,6 +34,7 @@
 #include "gmlreader.h"
 #include "gmlreaderp.h"
 #include "ogr_api.h"
+#include "ogr_geometry.h"
 #include "cpl_string.h"
 
 IGMLReader *CreateNASReader();
@@ -187,7 +188,9 @@ public:
     int              LoadClasses( const char *pszFile = NULL );
     int              SaveClasses( const char *pszFile = NULL );
 
-    int              PrescanForSchema(int bGetExtents = TRUE, int bAnalyzeSRSPerFeature = TRUE );
+    int              PrescanForSchema(int bGetExtents = TRUE,
+                                      int bAnalyzeSRSPerFeature = TRUE,
+                                      int bOnlyDetectSRS = FALSE);
     int              PrescanForTemplate( void );
     void             ResetReading();
 
@@ -231,7 +234,9 @@ public:
     int         SetFilteredClassName(const char* pszClassName);
     const char* GetFilteredClassName() { return m_pszFilteredClassName; }
 
-    static void* hMutex;
+    static CPLMutex* hMutex;
+    
+    static      OGRGeometry* ConvertGeometry(OGRGeometry*);
 };
 
 #endif /* _CPL_NASREADERP_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/nas/ogr_nas.h b/ogr/ogrsf_frmts/nas/ogr_nas.h
index a4515c7..8762ad1 100644
--- a/ogr/ogrsf_frmts/nas/ogr_nas.h
+++ b/ogr/ogrsf_frmts/nas/ogr_nas.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_nas.h 27713 2014-09-21 15:51:47Z jef $
+ * $Id: ogr_nas.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  NAS Reader
  * Purpose:  Declarations for OGR wrapper classes for NAS, and NAS<->OGR
@@ -65,7 +65,7 @@ class OGRNASLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    int                 GetFeatureCount( int bForce = TRUE );
+    GIntBig             GetFeatureCount( int bForce = TRUE );
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
@@ -93,7 +93,7 @@ class OGRNASRelationLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    int                 GetFeatureCount( int bForce = TRUE );
+    GIntBig             GetFeatureCount( int bForce = TRUE );
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
     int                 TestCapability( const char * );
 
@@ -128,7 +128,7 @@ class OGRNASDataSource : public OGRDataSource
                         OGRNASDataSource();
                         ~OGRNASDataSource();
 
-    int                 Open( const char *, int bTestOpen );
+    int                 Open( const char * );
     int                 Create( const char *pszFile, char **papszOptions );
 
     const char          *GetName() { return pszName; }
@@ -144,19 +144,4 @@ class OGRNASDataSource : public OGRDataSource
     void                PopulateRelations();
 };
 
-/************************************************************************/
-/*                             OGRNASDriver                             */
-/************************************************************************/
-
-class OGRNASDriver : public OGRSFDriver
-{
-  public:
-                ~OGRNASDriver();
-
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    int                 TestCapability( const char * );
-};
-
 #endif /* _OGR_NAS_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/nas/ogrnasdatasource.cpp b/ogr/ogrsf_frmts/nas/ogrnasdatasource.cpp
index 8c12618..a906580 100644
--- a/ogr/ogrsf_frmts/nas/ogrnasdatasource.cpp
+++ b/ogr/ogrsf_frmts/nas/ogrnasdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrnasdatasource.cpp 28132 2014-12-11 22:31:03Z jef $
+ * $Id: ogrnasdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OGR
  * Purpose:  Implements OGRNASDataSource class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrnasdatasource.cpp 28132 2014-12-11 22:31:03Z jef $");
+CPL_CVSID("$Id: ogrnasdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static const char *apszURNNames[] =
 {
@@ -79,88 +79,9 @@ OGRNASDataSource::~OGRNASDataSource()
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRNASDataSource::Open( const char * pszNewName, int bTestOpen )
+int OGRNASDataSource::Open( const char * pszNewName )
 
 {
-    FILE        *fp;
-    char        szHeader[8192];
-
-/* -------------------------------------------------------------------- */
-/*      Open the source file.                                           */
-/* -------------------------------------------------------------------- */
-    fp = VSIFOpen( pszNewName, "r" );
-    if( fp == NULL )
-    {
-        if( !bTestOpen )
-            CPLError( CE_Failure, CPLE_OpenFailed,
-                      "Failed to open NAS file `%s'.",
-                      pszNewName );
-
-        return FALSE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      If we aren't sure it is NAS, load a header chunk and check      */
-/*      for signs it is NAS                                             */
-/* -------------------------------------------------------------------- */
-    if( bTestOpen )
-    {
-        size_t nRead = VSIFRead( szHeader, 1, sizeof(szHeader), fp );
-        if (nRead <= 0)
-        {
-            VSIFClose( fp );
-            return FALSE;
-        }
-        szHeader[MIN(nRead, sizeof(szHeader))-1] = '\0';
-
-/* -------------------------------------------------------------------- */
-/*      Check for a UTF-8 BOM and skip if found                         */
-/*                                                                      */
-/*      TODO: BOM is variable-length parameter and depends on encoding. */
-/*            Add BOM detection for other encodings.                    */
-/* -------------------------------------------------------------------- */
-
-        // Used to skip to actual beginning of XML data
-        char* szPtr = szHeader;
-
-        if( ( (unsigned char)szHeader[0] == 0xEF )
-            && ( (unsigned char)szHeader[1] == 0xBB )
-            && ( (unsigned char)szHeader[2] == 0xBF) )
-        {
-            szPtr += 3;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Here, we expect the opening chevrons of NAS tree root element   */
-/* -------------------------------------------------------------------- */
-        bool bFound = FALSE;
-        if( szPtr[0] == '<' && strstr(szPtr,"opengis.net/gml") != NULL )
-        {
-            char **papszIndicators = CSLTokenizeStringComplex( CPLGetConfigOption( "NAS_INDICATOR", "NAS-Operationen.xsd;NAS-Operationen_optional.xsd;AAA-Fachschema.xsd" ), ";", 0, 0 );
-
-            for( int i = 0; papszIndicators[i] && !bFound; i++ )
-            {
-                bFound = strstr( szPtr, papszIndicators[i] ) != NULL;
-            }
-
-            CSLDestroy( papszIndicators );
-        }
-
-        if( !bFound )
-        {
-            /*CPLDebug( "NAS",
-                      "Skipping. No chevrons of NAS found [%s]\n", szPtr );*/
-            VSIFClose( fp );
-            return FALSE;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      We assume now that it is NAS.  Close and instantiate a          */
-/*      NASReader on it.                                                */
-/* -------------------------------------------------------------------- */
-    VSIFClose( fp );
-
     poReader = CreateNASReader();
     if( poReader == NULL )
     {
diff --git a/ogr/ogrsf_frmts/nas/ogrnasdriver.cpp b/ogr/ogrsf_frmts/nas/ogrnasdriver.cpp
index 0ddbdc9..7f1f15e 100644
--- a/ogr/ogrsf_frmts/nas/ogrnasdriver.cpp
+++ b/ogr/ogrsf_frmts/nas/ogrnasdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrnasdriver.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrnasdriver.cpp 28131 2014-12-11 22:30:16Z jef $
  *
  * Project:  OGR
  * Purpose:  OGRNASDriver implementation
@@ -32,15 +32,14 @@
 #include "nasreaderp.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrnasdriver.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrnasdriver.cpp 28131 2014-12-11 22:30:16Z jef $");
 
 
 /************************************************************************/
-/*                          ~OGRNASDriver()                           */
+/*                       OGRNASDriverUnload()                           */
 /************************************************************************/
 
-OGRNASDriver::~OGRNASDriver()
-
+static void OGRNASDriverUnload(CPL_UNUSED GDALDriver* poDriver)
 {
     if( NASReader::hMutex != NULL )
         CPLDestroyMutex( NASReader::hMutex );
@@ -48,31 +47,77 @@ OGRNASDriver::~OGRNASDriver()
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                     OGRNASDriverIdentify()                           */
 /************************************************************************/
 
-const char *OGRNASDriver::GetName()
+static int OGRNASDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "NAS";
+    if( poOpenInfo->fpL == NULL )
+        return FALSE;
+
+/* -------------------------------------------------------------------- */
+/*      Check for a UTF-8 BOM and skip if found                         */
+/*                                                                      */
+/*      TODO: BOM is variable-length parameter and depends on encoding. */
+/*            Add BOM detection for other encodings.                    */
+/* -------------------------------------------------------------------- */
+
+    // Used to skip to actual beginning of XML data
+    const char* szPtr = (const char*)poOpenInfo->pabyHeader;
+
+    if( ( (unsigned char)szPtr[0] == 0xEF )
+        && ( (unsigned char)szPtr[1] == 0xBB )
+        && ( (unsigned char)szPtr[2] == 0xBF) )
+    {
+        szPtr += 3;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Here, we expect the opening chevrons of NAS tree root element   */
+/* -------------------------------------------------------------------- */
+    if( szPtr[0] != '<' )
+        return FALSE;
+
+    if( !poOpenInfo->TryToIngest(8192) )
+        return FALSE;
+    szPtr = (const char*)poOpenInfo->pabyHeader;
+
+    if( strstr(szPtr,"opengis.net/gml") == NULL )
+        return FALSE;
+
+    char **papszIndicators = CSLTokenizeStringComplex( CPLGetConfigOption( "NAS_INDICATOR", "NAS-Operationen.xsd;NAS-Operationen_optional.xsd;AAA-Fachschema.xsd" ), ";", 0, 0 );
+
+    bool bFound = FALSE;
+    for( int i = 0; papszIndicators[i] && !bFound; i++ )
+    {
+	bFound = strstr( szPtr, papszIndicators[i] ) != NULL;
+    }
+
+    CSLDestroy( papszIndicators );
+
+    return bFound;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRNASDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRNASDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRNASDataSource    *poDS;
 
-    if( bUpdate )
+    if( poOpenInfo->eAccess == GA_Update ||
+        !OGRNASDriverIdentify(poOpenInfo) )
         return NULL;
 
+    VSIFCloseL(poOpenInfo->fpL);
+    poOpenInfo->fpL = NULL;
+
     poDS = new OGRNASDataSource();
 
-    if( !poDS->Open( pszFilename, TRUE )
+    if( !poDS->Open( poOpenInfo->pszFilename )
         || poDS->GetLayerCount() == 0 )
     {
         delete poDS;
@@ -83,20 +128,30 @@ OGRDataSource *OGRNASDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRNASDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRNAS()                           */
 /************************************************************************/
 
 void RegisterOGRNAS()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRNASDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "NAS" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "NAS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "NAS - ALKIS" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xml" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_nas.html" );
+
+        poDriver->pfnOpen = OGRNASDriverOpen;
+        poDriver->pfnIdentify = OGRNASDriverIdentify;
+        poDriver->pfnUnloadDriver = OGRNASDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/nas/ogrnaslayer.cpp b/ogr/ogrsf_frmts/nas/ogrnaslayer.cpp
index 64a89fa..d268cef 100644
--- a/ogr/ogrsf_frmts/nas/ogrnaslayer.cpp
+++ b/ogr/ogrsf_frmts/nas/ogrnaslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrnaslayer.cpp 27713 2014-09-21 15:51:47Z jef $
+ * $Id: ogrnaslayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRNASLayer class.
@@ -33,7 +33,7 @@
 #include "cpl_port.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrnaslayer.cpp 27713 2014-09-21 15:51:47Z jef $");
+CPL_CVSID("$Id: ogrnaslayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGRNASLayer()                              */
@@ -59,6 +59,7 @@ OGRNASLayer::OGRNASLayer( const char * pszName,
         poFeatureDefn = new OGRFeatureDefn( pszName+4 );
     else
         poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     poFeatureDefn->SetGeomType( eReqType );
@@ -150,16 +151,8 @@ OGRFeature *OGRNASLayer::GetNextFeature()
         if (papsGeometry[0] != NULL)
         {
             poGeom = (OGRGeometry*) OGR_G_CreateFromGMLTree(papsGeometry[0]);
-
-            if( EQUAL( papsGeometry[0]->pszValue, "CompositeCurve" ) ||
-                EQUAL( papsGeometry[0]->pszValue, "MultiCurve" ) ||
-                EQUAL( papsGeometry[0]->pszValue, "LineString" ) ||
-                EQUAL( papsGeometry[0]->pszValue, "MultiLineString" ) ||
-                EQUAL( papsGeometry[0]->pszValue, "Curve" ) )
-            {
-                poGeom = OGRGeometryFactory::forceToLineString( poGeom, false );
-            }
-
+            poGeom = NASReader::ConvertGeometry(poGeom);
+            poGeom = OGRGeometryFactory::forceTo(poGeom, GetGeomType());
             // poGeom->dumpReadable( 0, "NAS: " );
 
             // We assume the OGR_G_CreateFromGMLTree() function would have already
@@ -236,6 +229,9 @@ OGRFeature *OGRNASLayer::GetNextFeature()
             }
         }
 
+        poOGRFeature->SetGeometryDirectly( poGeom );
+        poGeom = NULL;
+
 /* -------------------------------------------------------------------- */
 /*      Test against the attribute query.                               */
 /* -------------------------------------------------------------------- */
@@ -249,14 +245,6 @@ OGRFeature *OGRNASLayer::GetNextFeature()
 /* -------------------------------------------------------------------- */
 /*      Wow, we got our desired feature. Return it.                     */
 /* -------------------------------------------------------------------- */
-        if( poGeom && poOGRFeature->SetGeometryDirectly( poGeom ) != OGRERR_NONE )
-        {
-            int iId = poNASFeature->GetClass()->GetPropertyIndex( "gml_id" );
-            const GMLProperty *poIdProp = poNASFeature->GetProperty(iId);
-            CPLError( CE_Warning, CPLE_AppDefined, "NAS: could not set geometry (gml_id:%s)",
-                      poIdProp && poIdProp->nSubProperties>0 && poIdProp->papszSubProperties[0] ? poIdProp->papszSubProperties[0] : "(null)" );
-        }
-
         delete poNASFeature;
 
         return poOGRFeature;
@@ -269,7 +257,7 @@ OGRFeature *OGRNASLayer::GetNextFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRNASLayer::GetFeatureCount( int bForce )
+GIntBig OGRNASLayer::GetFeatureCount( int bForce )
 
 {
     if( poFClass == NULL )
diff --git a/ogr/ogrsf_frmts/nas/ogrnasrelationlayer.cpp b/ogr/ogrsf_frmts/nas/ogrnasrelationlayer.cpp
index f93015c..6230c7e 100644
--- a/ogr/ogrsf_frmts/nas/ogrnasrelationlayer.cpp
+++ b/ogr/ogrsf_frmts/nas/ogrnasrelationlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrnasrelationlayer.cpp 27713 2014-09-21 15:51:47Z jef $
+ * $Id: ogrnasrelationlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGR
  * Purpose:  Implements OGRNASRelationLayer class, a special layer holding all
@@ -33,7 +33,7 @@
 #include "cpl_port.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrnasrelationlayer.cpp 27713 2014-09-21 15:51:47Z jef $");
+CPL_CVSID("$Id: ogrnasrelationlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                        OGRNASRelationLayer()                         */
@@ -51,6 +51,7 @@ OGRNASRelationLayer::OGRNASRelationLayer( OGRNASDataSource *poDSIn )
 /*      Establish the layer fields.                                     */
 /* -------------------------------------------------------------------- */
     poFeatureDefn = new OGRFeatureDefn( "ALKIS_beziehungen" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone );
 
@@ -147,7 +148,7 @@ OGRFeature *OGRNASRelationLayer::GetNextFeature()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRNASRelationLayer::GetFeatureCount( int bForce )
+GIntBig OGRNASRelationLayer::GetFeatureCount( int bForce )
 
 {
     if( !bPopulated )
diff --git a/ogr/ogrsf_frmts/ntf/GNUmakefile b/ogr/ogrsf_frmts/ntf/GNUmakefile
index 38b500b..8314359 100644
--- a/ogr/ogrsf_frmts/ntf/GNUmakefile
+++ b/ogr/ogrsf_frmts/ntf/GNUmakefile
@@ -7,7 +7,7 @@ OBJ	=	ntffilereader.o ntfrecord.o ogrntfdatasource.o \
 		ogrntffeatureclasslayer.o ntf_generic.o ntf_raster.o \
 		ntf_codelist.o ntfstroke.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/ntf/ntf.h b/ogr/ogrsf_frmts/ntf/ntf.h
index e116cd6..7bcb1d3 100644
--- a/ogr/ogrsf_frmts/ntf/ntf.h
+++ b/ogr/ogrsf_frmts/ntf/ntf.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntf.h 26466 2013-09-14 09:07:46Z rouault $
+ * $Id: ntf.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  NTF Translator
  * Purpose:  Main declarations for NTF translator.
@@ -396,15 +396,15 @@ class OGRNTFLayer : public OGRLayer
     OGRFeature *        GetNextFeature();
 
 #ifdef notdef    
-    OGRFeature         *GetFeature( long nFeatureId );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
+    OGRErr              ISetFeature( OGRFeature *poFeature );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
 #endif
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
 #ifdef notdef    
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
 #endif
     
     int                 TestCapability( const char * );
@@ -436,11 +436,11 @@ class OGRNTFFeatureClassLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    OGRFeature         *GetFeature( long nFeatureId );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-    int                 GetFeatureCount( int = TRUE );
+    GIntBig             GetFeatureCount( int = TRUE );
     
     int                 TestCapability( const char * );
 };
@@ -477,11 +477,11 @@ class OGRNTFRasterLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    OGRFeature         *GetFeature( long nFeatureId );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-    int                 GetFeatureCount( int = TRUE );
+    GIntBig             GetFeatureCount( int = TRUE );
     
     int                 TestCapability( const char * );
 };
@@ -559,20 +559,6 @@ class OGRNTFDataSource : public OGRDataSource
 };
 
 /************************************************************************/
-/*                             OGRNTFDriver                             */
-/************************************************************************/
-
-class OGRNTFDriver : public OGRSFDriver
-{
-  public:
-                ~OGRNTFDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    int                 TestCapability( const char * );
-};
-
-/************************************************************************/
 /*                          Support functions.                          */
 /************************************************************************/
 int NTFArcCenterFromEdgePoints( double x_c0, double y_c0,
diff --git a/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp b/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp
index 6a4fcc9..a104bf3 100644
--- a/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp
+++ b/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntf_estlayers.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ntf_estlayers.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  NTF Translator
  * Purpose:  NTFFileReader methods related to establishing the schemas
@@ -33,7 +33,7 @@
 #include "ntf.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ntf_estlayers.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ntf_estlayers.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 #define MAX_LINK        5000
 
@@ -317,10 +317,10 @@ static OGRFeature *TranslateOscarComment( CPL_UNUSED NTFFileReader *poReader,
                                           NTFRecord **papoGroup )
 
 {
-    if( CSLCount((char **) papoGroup) != 1 
+    if( CSLCount((char **) papoGroup) != 1
         || papoGroup[0]->GetType() != NRT_COMMENT )
         return NULL;
-        
+
     OGRFeature  *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
 
     // RECORD_TYPE
@@ -1149,10 +1149,10 @@ static OGRFeature *TranslateStrategiNode( CPL_UNUSED NTFFileReader *poReader,
                                           NTFRecord **papoGroup )
 
 {
-    if( CSLCount((char **) papoGroup) != 1 
+    if( CSLCount((char **) papoGroup) != 1
         || papoGroup[0]->GetType() != NRT_NODEREC )
         return NULL;
-        
+
     OGRFeature  *poFeature = new OGRFeature( poLayer->GetLayerDefn() );
 
     // NODE_ID
@@ -1631,7 +1631,7 @@ static OGRFeature *TranslateLandlineName( NTFFileReader *poReader,
     poFeature->SetField( 5, atoi(papoGroup[1]->GetField(10,10)) );
         
     // ORIENT
-    poFeature->SetField( 6, atof(papoGroup[1]->GetField( 11, 14 )) * 0.1 );
+    poFeature->SetField( 6, CPLAtof(papoGroup[1]->GetField( 11, 14 )) * 0.1 );
 
     // TEXT_HT_GROUND
     poFeature->SetField( 7, poFeature->GetFieldAsDouble(4)
diff --git a/ogr/ogrsf_frmts/ntf/ntf_generic.cpp b/ogr/ogrsf_frmts/ntf/ntf_generic.cpp
index 0d3b872..45d5998 100644
--- a/ogr/ogrsf_frmts/ntf/ntf_generic.cpp
+++ b/ogr/ogrsf_frmts/ntf/ntf_generic.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntf_generic.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ntf_generic.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  NTF Translator
  * Purpose:  Handle NTF products that aren't recognised generically.
@@ -31,7 +31,7 @@
 #include "ntf.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ntf_generic.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ntf_generic.cpp 27959 2014-11-14 18:29:21Z rouault $");
 
 #define MAX_LINK        5000
 
@@ -861,7 +861,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
     for( int iFile = 0; iFile < nNTFFileCount; iFile++ )
     {
         NTFFileReader   *poPReader = NULL;
-        int             n3DFlag = 0;
+        int              bHasZ = FALSE;
         
         poPReader = papoNTFFileReader[iFile];
         if( poPReader->GetProductId() != NPC_UNKNOWN )
@@ -876,7 +876,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             NTFGenericClass     *poClass = aoGenericClass + iType;
         
             if( poClass->nFeatureCount > 0 && poClass->b3D )
-                n3DFlag = wkb25DBit;
+                bHasZ = TRUE;
         }
         
 /* -------------------------------------------------------------------- */
@@ -893,7 +893,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_POINT", 
-                                    (OGRwkbGeometryType) (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericPoint,
                                     NRT_POINTREC, poClass,
                                     "POINT_ID", OFTInteger, 6, 0,
@@ -903,8 +903,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_LINE", 
-                                    (OGRwkbGeometryType) 
-                                    (wkbLineString | n3DFlag),
+                                    OGR_GT_SetModifier(wkbLineString, bHasZ, FALSE),
                                     TranslateGenericLine,
                                     NRT_LINEREC, poClass,
                                     "LINE_ID", OFTInteger, 6, 0,
@@ -914,8 +913,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_TEXT", 
-                                    (OGRwkbGeometryType) 
-                                    (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericText,
                                     NRT_TEXTREC, poClass,
                                     "TEXT_ID", OFTInteger, 6, 0,
@@ -925,8 +923,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_NAME", 
-                                    (OGRwkbGeometryType) 
-                                    (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericName,
                                     NRT_NAMEREC, poClass,
                                     "NAME_ID", OFTInteger, 6, 0,
@@ -936,8 +933,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_NODE",
-                                    (OGRwkbGeometryType) 
-                                    (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericNode,
                                     NRT_NODEREC, poClass,
                                     "NODE_ID", OFTInteger, 6, 0,
@@ -962,7 +958,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_POLY", 
-                                    (OGRwkbGeometryType) (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericPoly,
                                     NRT_POLYGON, poClass,
                                     "POLY_ID", OFTInteger, 6, 0,
@@ -976,7 +972,7 @@ void OGRNTFDataSource::EstablishGenericLayers()
             {
                 poPReader->
                     EstablishLayer( "GENERIC_CPOLY", 
-                                    (OGRwkbGeometryType) (wkbPoint | n3DFlag),
+                                    OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE),
                                     TranslateGenericCPoly,
                                     NRT_CPOLY, poClass,
                                     "CPOLY_ID", OFTInteger, 6, 0,
diff --git a/ogr/ogrsf_frmts/ntf/ntf_raster.cpp b/ogr/ogrsf_frmts/ntf/ntf_raster.cpp
index 8f5155c..f77ea94 100644
--- a/ogr/ogrsf_frmts/ntf/ntf_raster.cpp
+++ b/ogr/ogrsf_frmts/ntf/ntf_raster.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntf_raster.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ntf_raster.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  NTF Translator
  * Purpose:  Handle UK Ordnance Survey Raster DTM products.  Includes some
@@ -31,7 +31,7 @@
 
 #include "ntf.h"
 
-CPL_CVSID("$Id: ntf_raster.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ntf_raster.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -346,7 +346,7 @@ OGRFeature *OGRNTFRasterLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRNTFRasterLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRNTFRasterLayer::GetFeature( GIntBig nFeatureId )
 
 {
     int         iReqColumn, iReqRow;
@@ -363,8 +363,8 @@ OGRFeature *OGRNTFRasterLayer::GetFeature( long nFeatureId )
 /* -------------------------------------------------------------------- */
 /*      Do we need to load a different column.                          */
 /* -------------------------------------------------------------------- */
-    iReqColumn = (nFeatureId - 1) / poReader->GetRasterYSize();
-    iReqRow = nFeatureId - iReqColumn * poReader->GetRasterXSize() - 1;
+    iReqColumn = ((int)nFeatureId - 1) / poReader->GetRasterYSize();
+    iReqRow = (int)nFeatureId - iReqColumn * poReader->GetRasterXSize() - 1;
     
     if( iReqColumn != iColumnOffset )
     {
@@ -401,7 +401,7 @@ OGRFeature *OGRNTFRasterLayer::GetFeature( long nFeatureId )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRNTFRasterLayer::GetFeatureCount( CPL_UNUSED int bForce )
+GIntBig OGRNTFRasterLayer::GetFeatureCount( CPL_UNUSED int bForce )
 {
     return nFeatureCount;
 }
@@ -429,5 +429,3 @@ int OGRNTFRasterLayer::TestCapability( const char * pszCap )
     else 
         return FALSE;
 }
-
-
diff --git a/ogr/ogrsf_frmts/ntf/ntffilereader.cpp b/ogr/ogrsf_frmts/ntf/ntffilereader.cpp
index 7225aed..f9fbce0 100644
--- a/ogr/ogrsf_frmts/ntf/ntffilereader.cpp
+++ b/ogr/ogrsf_frmts/ntf/ntffilereader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ntffilereader.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ntffilereader.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  NTF Translator
  * Purpose:  NTFFileReader class implementation.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogr_api.h"
 
-CPL_CVSID("$Id: ntffilereader.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ntffilereader.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 static int DefaultNTFRecordGrouper( NTFFileReader *, NTFRecord **,
                                     NTFRecord * );
@@ -421,7 +421,7 @@ int NTFFileReader::Open( const char * pszFilenameIn )
 /* -------------------------------------------------------------------- */
 /*      Classify the product type.                                      */
 /* -------------------------------------------------------------------- */
-    if( EQUALN(pszProduct,"LAND-LINE",9) && atof(pszPVName+5) < 1.3 )
+    if( EQUALN(pszProduct,"LAND-LINE",9) && CPLAtof(pszPVName+5) < 1.3 )
         nProduct = NPC_LANDLINE;
     else if( EQUALN(pszProduct,"LAND-LINE",9) )
         nProduct = NPC_LANDLINE99;
diff --git a/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp b/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp
index 49d332b..c90c546 100644
--- a/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp
+++ b/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrntfdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrntfdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  UK NTF Reader
  * Purpose:  Implements OGRNTFDriver
@@ -30,7 +30,7 @@
 #include "ntf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrntfdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrntfdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -39,50 +39,41 @@ CPL_CVSID("$Id: ogrntfdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
 /************************************************************************/
 
 /************************************************************************/
-/*                           ~OGRNTFDriver()                            */
-/************************************************************************/
-
-OGRNTFDriver::~OGRNTFDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRNTFDriver::GetName()
-
-{
-    return "UK .NTF";
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRNTFDriver::TestCapability( const char * )
-
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRNTFDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRNTFDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    OGRNTFDataSource    *poDS = new OGRNTFDataSource;
+    if( !poOpenInfo->bStatOK )
+        return NULL;
+    if( poOpenInfo->fpL != NULL )
+    {
+        if( poOpenInfo->nHeaderBytes < 80 )
+            return NULL;
+        const char* pszHeader = (const char*)poOpenInfo->pabyHeader;
+        if( !EQUALN(pszHeader,"01",2) )
+            return NULL;
+
+        int j;
+        for( j = 0; j < 80; j++ )
+        {
+            if( pszHeader[j] == 10 || pszHeader[j] == 13 )
+                break;
+        }
+
+        if( j == 80 || pszHeader[j-1] != '%' )
+            return FALSE;
+    }
 
-    if( !poDS->Open( pszFilename, TRUE ) )
+    OGRNTFDataSource    *poDS = new OGRNTFDataSource;
+    if( !poDS->Open( poOpenInfo->pszFilename, TRUE ) )
     {
         delete poDS;
         poDS = NULL;
     }
 
-    if( poDS != NULL && bUpdate )
+    if( poDS != NULL && poOpenInfo->eAccess == GA_Update )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "NTF Driver doesn't support update." );
@@ -100,6 +91,22 @@ OGRDataSource *OGRNTFDriver::Open( const char * pszFilename, int bUpdate )
 void RegisterOGRNTF()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRNTFDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "UK .NTF" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "UK .NTF" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "UK .NTF" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_ntf.html" );
+
+        poDriver->pfnOpen = OGRNTFDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp b/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp
index 65634b6..b1b5618 100644
--- a/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp
+++ b/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrntffeatureclasslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrntffeatureclasslayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  UK NTF Reader
  * Purpose:  Implements OGRNTFFeatureClassLayer class.
@@ -30,7 +30,7 @@
 #include "ntf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrntffeatureclasslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrntffeatureclasslayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                      OGRNTFFeatureClassLayer()                       */
@@ -52,6 +52,7 @@ OGRNTFFeatureClassLayer::OGRNTFFeatureClassLayer( OGRNTFDataSource *poDSIn )
 /*      Establish the schema.                                           */
 /* -------------------------------------------------------------------- */
     poFeatureDefn = new OGRFeatureDefn( "FEATURE_CLASSES" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->SetGeomType( wkbNone );
     poFeatureDefn->Reference();
 
@@ -124,7 +125,7 @@ OGRFeature *OGRNTFFeatureClassLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRNTFFeatureClassLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRNTFFeatureClassLayer::GetFeature( GIntBig nFeatureId )
 
 {
     char        *pszFCName, *pszFCId;
@@ -132,7 +133,7 @@ OGRFeature *OGRNTFFeatureClassLayer::GetFeature( long nFeatureId )
     if( nFeatureId < 0 || nFeatureId >= poDS->GetFCCount() )
         return NULL;
     
-    poDS->GetFeatureClass( nFeatureId, &pszFCId, &pszFCName );
+    poDS->GetFeatureClass( (int)nFeatureId, &pszFCId, &pszFCName );
     
 /* -------------------------------------------------------------------- */
 /*      Create a corresponding feature.                                 */
@@ -155,7 +156,7 @@ OGRFeature *OGRNTFFeatureClassLayer::GetFeature( long nFeatureId )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRNTFFeatureClassLayer::GetFeatureCount( CPL_UNUSED int bForce )
+GIntBig OGRNTFFeatureClassLayer::GetFeatureCount( CPL_UNUSED int bForce )
 {
     return poDS->GetFCCount();
 }
@@ -183,4 +184,3 @@ int OGRNTFFeatureClassLayer::TestCapability( const char * pszCap )
     else 
         return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp b/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp
index 3aa84b3..9d16f42 100644
--- a/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp
+++ b/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrntflayer.cpp 26467 2013-09-14 09:16:12Z rouault $
+ * $Id: ogrntflayer.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  UK NTF Reader
  * Purpose:  Implements OGRNTFLayer class.
@@ -30,7 +30,7 @@
 #include "ntf.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrntflayer.cpp 26467 2013-09-14 09:16:12Z rouault $");
+CPL_CVSID("$Id: ogrntflayer.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                            OGRNTFLayer()                             */
@@ -46,6 +46,7 @@ OGRNTFLayer::OGRNTFLayer( OGRNTFDataSource *poDSIn,
 {
     poDS = poDSIn;
     poFeatureDefn = poFeatureDefine;
+    SetDescription( poFeatureDefn->GetName() );
     pfnTranslator = pfnTranslatorIn;
 
     iCurrentReader = -1;
diff --git a/ogr/ogrsf_frmts/null/ogrnulldriver.cpp b/ogr/ogrsf_frmts/null/ogrnulldriver.cpp
index d76a8de..8a82dc8 100644
--- a/ogr/ogrsf_frmts/null/ogrnulldriver.cpp
+++ b/ogr/ogrsf_frmts/null/ogrnulldriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrnulldriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrnulldriver.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  NULL output driver.
@@ -27,14 +27,14 @@
  * DEALINGS IN THE SOFTWARE.
  ****************************************************************************/
 
-/* NOTE: this driver is only usefull for debugging and is not included in the build process */
+/* NOTE: this driver is only useful for debugging and is not included in the build process */
 /* To compile it as a pluing under Linux :
     g++ -Wall -DDEBUG -fPIC -g ogr/ogrsf_frmts/null/ogrnulldriver.cpp  -shared -o ogr_NULL.so -L. -lgdal -Iport -Igcore -Iogr -Iogr/ogrsf_frmts
 */
 
 #include "ogrsf_frmts.h"
 
-CPL_CVSID("$Id: ogrnulldriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrnulldriver.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 extern "C" void CPL_DLL RegisterOGRNULL();
 
@@ -61,7 +61,7 @@ class OGRNULLLayer : public OGRLayer
 
     virtual OGRFeature *GetNextFeature() { return NULL; }
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature ) { return OGRERR_NONE; }
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature ) { return OGRERR_NONE; }
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -85,7 +85,7 @@ class OGRNULLDataSource : public OGRDataSource
     virtual int         GetLayerCount() { return nLayers; }
     virtual OGRLayer   *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *pszLayerName,
+    virtual OGRLayer    *ICreateLayer( const char *pszLayerName,
                                       OGRSpatialReference *poSRS,
                                       OGRwkbGeometryType eType,
                                       char **papszOptions );
@@ -120,6 +120,7 @@ OGRNULLLayer::OGRNULLLayer( const char *pszLayerName,
                             OGRwkbGeometryType eType )
 {
     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->SetGeomType(eType);
     poFeatureDefn->Reference();
 
@@ -191,10 +192,10 @@ OGRNULLDataSource::~OGRNULLDataSource()
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer    *OGRNULLDataSource::CreateLayer( const char *pszLayerName,
+OGRLayer    *OGRNULLDataSource::ICreateLayer( const char *pszLayerName,
                                              OGRSpatialReference *poSRS,
                                              OGRwkbGeometryType eType,
                                              char **papszOptions )
diff --git a/ogr/ogrsf_frmts/oci/GNUmakefile b/ogr/ogrsf_frmts/oci/GNUmakefile
index fa5ada7..5cd9dc5 100644
--- a/ogr/ogrsf_frmts/oci/GNUmakefile
+++ b/ogr/ogrsf_frmts/oci/GNUmakefile
@@ -7,7 +7,7 @@ OBJ	=	oci_utils.o ogrocisession.o ogrocistatement.o \
 		ogrocitablelayer.o ogrociselectlayer.o ogrocistringbuf.o \
 		ogrociwritablelayer.o ogrociloaderlayer.o ogrocistroke.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(OCI_INCLUDE) $(CPPFLAGS) -fPIC
+CPPFLAGS	:=	 $(GDAL_INCLUDE) $(OCI_INCLUDE) $(CPPFLAGS) -fPIC
 
 PLUGIN_SO	=	ogr_OCI.so
 
diff --git a/ogr/ogrsf_frmts/oci/drv_oci.html b/ogr/ogrsf_frmts/oci/drv_oci.html
index ca51c95..35c42fb 100644
--- a/ogr/ogrsf_frmts/oci/drv_oci.html
+++ b/ogr/ogrsf_frmts/oci/drv_oci.html
@@ -53,23 +53,32 @@ by passing <strong>"OGRSQL"</strong> string to the ExecuteSQL() method, as name
 
 <li> The type recognition logic is currently somewhat impoverished.  No
 effort is made to preserve real width information for integer and real
-fields. <p>
+fields.</li>
 
 <li> Various types such as objects, and BLOBs in Oracle will be completely
-ignored by OGR.<p>
+ignored by OGR.</li>
 
 <li> Currently the OGR transaction semantics are not properly mapped onto
-transaction semantics in Oracle.<p>
+transaction semantics in Oracle.</li>
 
 <li> If an attribute called OGR_FID exists in the schema for tables being 
 read, it will be used as the FID.  Random (FID based) reads on tables without
 an identified (and indexed) FID field can be very slow.  To force use of a
 particular field name the OCI_FID configuration variable (ie. environment
-variable) can be set to the target field name. <p>
+variable) can be set to the target field name.</li>
 
-<li> Curved geometry types are converted to linestrings or linear rings in six degree segments when reading.  The driver has no support for writing curved geometries.
+<li> Curved geometry types are converted to linestrings or linear rings in six degree segments when reading.  The driver has no support for writing curved geometries.</li>
 
-<li> There is no support for point cloud (SDO_PC), TIN (SDO_TIN) and annotation text data types in Oracle Spatial.
+<li> There is no support for point cloud (SDO_PC), TIN (SDO_TIN) and annotation text data types in Oracle Spatial.</li>
+
+<li> It might be necessary to define the environment variable NLS_LANG to
+"American_America.UTF8" to avoid issues with floating point numbers being
+truncated to integer on non-English environments.</li>
+
+<li> For developers: when running the driver under the memory error detection
+tool Valgrind, specifying the database_instance, typically to localhost, or with
+the TWO_TASK environment variable seems to be
+compulsory, otherwise "TNS:permission denied" errors will be reported)</li>
 
 </ul>
 
@@ -111,15 +120,22 @@ NUMBER, INTEGER and VARCHAR2 will be used instead.  The default is "YES".<p>
 <li> <b>DIM</b>: This may be set to 2 or 3 to force the dimension of the
 created layer.  If not set 3 is used by default.<p>
 
-<li> <b>INDEX</b>: This may be set to OFF to disable creation of a spatial
+<li> <b>SPATIAL_INDEX</b>: This may be set to FALSE to disable creation of a spatial
 index when a layer load is complete.  By default an index is created if 
-any of the layer features have valid geometries.<p>
+any of the layer features have valid geometries. The default is "YES".
+Note: option was called INDEX in releases before GDAL 2<p>
 
 <li> <b>INDEX_PARAMETERS</b>: This may be set to pass creation parameters
 when the spatial index is created.  For instance setting INDEX_PARAMETERS to 
 SDO_LEVEL=5 would cause a 5 level tile index to be used.  By default no 
 parameters are passed causing a default R-Tree spatial index to be created.<p>
 
+<li> <b>ADD_LAYER_GTYPE</b>=YES/NO: (starting with GDAL 2.0) This may be
+set to NO to disable the constraints on the geometry type in the spatial index,
+through the layer_gtype keyword in the PARAMETERS clause of the CREATE INDEX.
+Layers of type MultiPoint, MultiLineString or MultiPolygon will also accept
+single geometry type (Point, LineString, Polygon). Defaults to YES.<p>
+
 <li> <b>DIMINFO_X</b>: This may be set to xmin,xmax,xres values to
 control the X dimension info written into the USER_SDO_GEOM_METADATA table.
 By default extents are collected from the actual data written.<p>
@@ -129,7 +145,7 @@ control the Y dimension info written into the USER_SDO_GEOM_METADATA table.
 By default extents are collected from the actual data written.<p>
 
 <li> <b>DIMINFO_Z</b>: This may be set to zmin,zmax,zres values to
-control the Y dimension info written into the USER_SDO_GEOM_METADATA table.
+control the Z dimension info written into the USER_SDO_GEOM_METADATA table.
 By default fixed values of -100000,100000,0.002 are used for layers with
 a third dimension.<p>
 
diff --git a/ogr/ogrsf_frmts/oci/ogr_oci.h b/ogr/ogrsf_frmts/oci/ogr_oci.h
index 4ebbf9f..6e8a134 100644
--- a/ogr/ogrsf_frmts/oci/ogr_oci.h
+++ b/ogr/ogrsf_frmts/oci/ogr_oci.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_oci.h 26573 2013-10-30 13:34:41Z rouault $
+ * $Id: ogr_oci.h 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Oracle Spatial OGR Driver Declarations. 
@@ -160,6 +160,8 @@ class CPL_DLL OGROCIStatement {
     OGRFeatureDefn *GetResultDefn() { return poDefn; }
 
     char       **SimpleFetchRow();
+    
+    int          GetAffectedRows() const { return nAffectedRows; }
 
   private:    
     OGROCISession *poSession;
@@ -173,6 +175,7 @@ class CPL_DLL OGROCIStatement {
 
     int           nRawColumnCount;
     int           *panFieldMap;
+    int           nAffectedRows;
 };
 
 /************************************************************************/
@@ -193,7 +196,7 @@ public:
 
     void MakeRoomFor( int );
     void Append( const char * );
-    void Appendf( int nMax, const char *pszFormat, ... );
+    void Appendf( int nMax, const char *pszFormat, ... ) CPL_PRINT_FUNC_FORMAT (3, 4);
     char *StealString();
 
     char GetLast();
@@ -364,7 +367,7 @@ class OGROCILoaderLayer : public OGROCIWritableLayer
                         ~OGROCILoaderLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry * ) {}
 
@@ -373,7 +376,7 @@ class OGROCILoaderLayer : public OGROCIWritableLayer
 
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
     
     virtual OGRSpatialReference *GetSpatialRef() { return poSRS; }
 
@@ -413,7 +416,6 @@ class OGROCITableLayer : public OGROCIWritableLayer
     OCIArray           *hElemInfoVARRAY;
 
     void                UpdateLayerExtents();
-    void                FinalizeNewLayer();
     void                CreateSpatialIndex();
 
     void                TestForSpatialIndex( const char * );
@@ -432,7 +434,7 @@ class OGROCITableLayer : public OGROCIWritableLayer
     OCIInd            **papaeWriteFieldInd;
     int                *panWriteFIDs;
 
-    int                 AllocAndBindForWrite(int eType);
+    int                 AllocAndBindForWrite();
     OGRErr              FlushPendingFeatures();
 
     OGRErr              UnboundCreateFeature( OGRFeature *poFeature );
@@ -440,23 +442,23 @@ class OGROCITableLayer : public OGROCIWritableLayer
 
   public:
                         OGROCITableLayer( OGROCIDataSource *,
-                                          const char * pszName,
+                                          const char * pszName, OGRwkbGeometryType eGType,
                                           int nSRID, int bUpdate, int bNew );
                         ~OGROCITableLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry * );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
     virtual OGRFeature *GetNextFeature();
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
     
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
@@ -513,7 +515,8 @@ class OGROCIDataSource : public OGRDataSource
 
     OGROCISession      *GetSession() { return poSession; }
 
-    int                 Open( const char *, int bUpdate, int bTestOpen );
+    int                 Open( const char *, char** papszOpenOptions,
+                              int bUpdate, int bTestOpen );
     int                 OpenTable( const char *pszTableName, 
                                    int nSRID, int bUpdate, int bTestOpen );
 
@@ -523,7 +526,7 @@ class OGROCIDataSource : public OGRDataSource
     OGRLayer            *GetLayerByName(const char * pszName);
 
     virtual OGRErr      DeleteLayer(int);
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -544,24 +547,6 @@ class OGROCIDataSource : public OGRDataSource
     OGRSpatialReference *FetchSRS( int nSRID );
 };
 
-/************************************************************************/
-/*                             OGROCIDriver                             */
-/************************************************************************/
-
-class OGROCIDriver : public OGRSFDriver
-{
-  public:
-                ~OGROCIDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    
-    int                 TestCapability( const char * );
-};
-
 /* -------------------------------------------------------------------- */
 /*      Helper functions.                                               */
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogrsf_frmts/oci/ogrocidatasource.cpp b/ogr/ogrsf_frmts/oci/ogrocidatasource.cpp
index 8b83faa..2e4159c 100644
--- a/ogr/ogrsf_frmts/oci/ogrocidatasource.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocidatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocidatasource.cpp 26506 2013-09-30 18:17:55Z rouault $
+ * $Id: ogrocidatasource.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCIDataSource class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrocidatasource.cpp 26506 2013-09-30 18:17:55Z rouault $");
+CPL_CVSID("$Id: ogrocidatasource.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
 static int anEPSGOracleMapping[] = 
 {
@@ -97,7 +97,9 @@ OGROCIDataSource::~OGROCIDataSource()
 /*                                Open()                                */
 /************************************************************************/
 
-int OGROCIDataSource::Open( const char * pszNewName, int bUpdate,
+int OGROCIDataSource::Open( const char * pszNewName,
+                            char** papszOpenOptions,
+                            int bUpdate,
                             int bTestOpen )
 
 {
@@ -126,38 +128,50 @@ int OGROCIDataSource::Open( const char * pszNewName, int bUpdate,
     char **papszTableList = NULL;
     int   i;
 
-    pszUserid = CPLStrdup( pszNewName + 4 );
-
-    // Is there a table list? 
-    for( i = strlen(pszUserid)-1; i > 1; i-- )
+    if( pszNewName[4] == '\0' )
+    {
+        pszUserid = CPLStrdup(CSLFetchNameValueDef(papszOpenOptions, "USER", ""));
+        pszPassword = CSLFetchNameValueDef(papszOpenOptions, "PASSWORD", "");
+        pszDatabase = CSLFetchNameValueDef(papszOpenOptions, "DBNAME", "");
+        const char* pszTables = CSLFetchNameValue(papszOpenOptions, "TABLES");
+        if( pszTables )
+            papszTableList = CSLTokenizeStringComplex(pszTables, ",", TRUE, FALSE );
+    }
+    else
     {
-        if( pszUserid[i] == ':' )
+        pszUserid = CPLStrdup( pszNewName + 4 );
+
+        // Is there a table list? 
+        for( i = strlen(pszUserid)-1; i > 1; i-- )
         {
-            papszTableList = CSLTokenizeStringComplex( pszUserid+i+1, ",",
-                                                       TRUE, FALSE );
-            pszUserid[i] = '\0';
-            break;
-        }
+            if( pszUserid[i] == ':' )
+            {
+                papszTableList = CSLTokenizeStringComplex( pszUserid+i+1, ",",
+                                                        TRUE, FALSE );
+                pszUserid[i] = '\0';
+                break;
+            }
 
-        if( pszUserid[i] == '/' || pszUserid[i] == '@' )
-            break;
-    }
+            if( pszUserid[i] == '/' || pszUserid[i] == '@' )
+                break;
+        }
 
-    for( i = 0; 
-         pszUserid[i] != '\0' && pszUserid[i] != '/' && pszUserid[i] != '@';
-         i++ ) {}
+        for( i = 0; 
+            pszUserid[i] != '\0' && pszUserid[i] != '/' && pszUserid[i] != '@';
+            i++ ) {}
 
-    if( pszUserid[i] == '/' )
-    {
-        pszUserid[i++] = '\0';
-        pszPassword = pszUserid + i;
-        for( ; pszUserid[i] != '\0' && pszUserid[i] != '@'; i++ ) {}
-    }
+        if( pszUserid[i] == '/' )
+        {
+            pszUserid[i++] = '\0';
+            pszPassword = pszUserid + i;
+            for( ; pszUserid[i] != '\0' && pszUserid[i] != '@'; i++ ) {}
+        }
 
-    if( pszUserid[i] == '@' )
-    {
-        pszUserid[i++] = '\0';
-        pszDatabase = pszUserid + i;
+        if( pszUserid[i] == '@' )
+        {
+            pszUserid[i++] = '\0';
+            pszDatabase = pszUserid + i;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -180,7 +194,11 @@ int OGROCIDataSource::Open( const char * pszNewName, int bUpdate,
     }
 
     if( poSession == NULL )
+    {
+        CPLFree(pszUserid);
+        CSLDestroy(papszTableList);
         return FALSE;
+    }
 
     pszName = CPLStrdup( pszNewName );
     
@@ -244,7 +262,7 @@ int OGROCIDataSource::OpenTable( const char *pszNewName,
 /* -------------------------------------------------------------------- */
     OGROCITableLayer    *poLayer;
 
-    poLayer = new OGROCITableLayer( this, pszNewName, nSRID, 
+    poLayer = new OGROCITableLayer( this, pszNewName, wkbUnknown, nSRID, 
                                     bUpdate, FALSE );
 
     if( !poLayer->IsValid() )
@@ -411,7 +429,6 @@ void OGROCIDataSource::DeleteLayer( const char *pszLayerName )
     {
         if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
         {
-            pszLayerName = CPLStrdup(papoLayers[iLayer]->GetLayerDefn()->GetName());
             break;
         }
     }
@@ -450,11 +467,11 @@ void OGROCIDataSource::TruncateLayer( const char *pszLayerName )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGROCIDataSource::CreateLayer( const char * pszLayerName,
+OGROCIDataSource::ICreateLayer( const char * pszLayerName,
                                OGRSpatialReference *poSRS,
                                OGRwkbGeometryType eType,
                                char ** papszOptions )
@@ -524,6 +541,7 @@ OGROCIDataSource::CreateLayer( const char * pszLayerName,
         CSLFetchNameValue( papszOptions, "GEOMETRY_NAME" );
     if( pszGeometryName == NULL )
         pszGeometryName = "ORA_GEOMETRY";
+    int bGeomNullable = CSLFetchBoolean(papszOptions, "GEOMETRY_NULLABLE", TRUE);
 
 /* -------------------------------------------------------------------- */
 /*      Create a basic table with the FID.  Also include the            */
@@ -544,16 +562,18 @@ OGROCIDataSource::CreateLayer( const char * pszLayerName,
         {
             sprintf( szCommand,
                      "CREATE TABLE \"%s\" ( "
-                     "%s INTEGER)",
+                     "%s INTEGER PRIMARY KEY)",
                      pszSafeLayerName, pszExpectedFIDName);
         }
         else
         {
             sprintf( szCommand,
                      "CREATE TABLE \"%s\" ( "
-                     "%s INTEGER, "
-                     "%s %s )",
-                     pszSafeLayerName, pszExpectedFIDName, pszGeometryName, SDO_GEOMETRY );
+                     "%s INTEGER PRIMARY KEY, "
+                     "%s %s%s )",
+                     pszSafeLayerName, pszExpectedFIDName,
+                     pszGeometryName, SDO_GEOMETRY,
+                     (!bGeomNullable) ? " NOT NULL":"");
         }
 
         if( oStatement.Execute( szCommand ) != CE_None )
@@ -570,7 +590,7 @@ OGROCIDataSource::CreateLayer( const char * pszLayerName,
     OGROCIWritableLayer *poLayer;
 
     if( pszLoaderFile == NULL )
-        poLayer = new OGROCITableLayer( this, pszSafeLayerName, 
+        poLayer = new OGROCITableLayer( this, pszSafeLayerName, eType,
                                         EQUAL(szSRSId,"NULL") ? -1 : atoi(szSRSId),
                                         TRUE, TRUE );
     else
@@ -590,6 +610,8 @@ OGROCIDataSource::CreateLayer( const char * pszLayerName,
         poLayer->SetDimension( atoi(CSLFetchNameValue(papszOptions,"DIM")) );
 
     poLayer->SetOptions( papszOptions );
+    if( eType != wkbNone && !bGeomNullable )
+        poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->SetNullable(FALSE);
 
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
@@ -654,7 +676,7 @@ OGRLayer * OGROCIDataSource::ExecuteSQL( const char *pszSQLCommand,
 /* -------------------------------------------------------------------- */
 /*      Ensure any pending stuff is flushed to the database.            */
 /* -------------------------------------------------------------------- */
-    SyncToDisk();
+    FlushCache();
 
     CPLDebug( "OCI", "ExecuteSQL(%s)", pszSQLCommand );
 
diff --git a/ogr/ogrsf_frmts/oci/ogrocidriver.cpp b/ogr/ogrsf_frmts/oci/ogrocidriver.cpp
index bacf73e..cde8882 100644
--- a/ogr/ogrsf_frmts/oci/ogrocidriver.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocidriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocidriver.cpp 12396 2007-10-13 10:02:17Z rouault $
+ * $Id: ogrocidriver.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCIDriver class.
@@ -29,40 +29,34 @@
 
 #include "ogr_oci.h"
 
-CPL_CVSID("$Id: ogrocidriver.cpp 12396 2007-10-13 10:02:17Z rouault $");
+CPL_CVSID("$Id: ogrocidriver.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
-/************************************************************************/
-/*                           ~OGROCIDriver()                            */
-/************************************************************************/
-
-OGROCIDriver::~OGROCIDriver()
-
-{
-}
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                        OGROCIDriverIdentify()                        */
 /************************************************************************/
 
-const char *OGROCIDriver::GetName()
-
+static int OGROCIDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-    return "OCI";
+    return EQUALN(poOpenInfo->pszFilename,"OCI:",4);
 }
 
 /************************************************************************/
-/*                                Open()                                */
+/*                          OGROCIDriverOpen()                          */
 /************************************************************************/
 
-OGRDataSource *OGROCIDriver::Open( const char * pszFilename,
-                                     int bUpdate )
+static GDALDataset *OGROCIDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( !OGROCIDriverIdentify(poOpenInfo) )
+        return NULL;
+
     OGROCIDataSource    *poDS;
 
     poDS = new OGROCIDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, TRUE ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->papszOpenOptions,
+                     poOpenInfo->eAccess == GA_Update, TRUE ) )
     {
         delete poDS;
         return NULL;
@@ -72,11 +66,15 @@ OGRDataSource *OGROCIDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                         OGROCIDriverCreate()                         */
 /************************************************************************/
 
-OGRDataSource *OGROCIDriver::CreateDataSource( const char * pszName,
-                                               char ** /* papszOptions */ )
+static GDALDataset *OGROCIDriverCreate( const char * pszName,
+                                        CPL_UNUSED int nBands,
+                                        CPL_UNUSED int nXSize,
+                                        CPL_UNUSED int nYSize,
+                                        CPL_UNUSED GDALDataType eDT,
+                                        CPL_UNUSED char **papszOptions )
 
 {
     OGROCIDataSource    *poDS;
@@ -84,7 +82,7 @@ OGRDataSource *OGROCIDriver::CreateDataSource( const char * pszName,
     poDS = new OGROCIDataSource();
 
 
-    if( !poDS->Open( pszName, TRUE, TRUE ) )
+    if( !poDS->Open( pszName, NULL, TRUE, TRUE ) )
     {
         delete poDS;
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -97,19 +95,6 @@ OGRDataSource *OGROCIDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGROCIDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGROCI()                            */
 /************************************************************************/
 
@@ -118,6 +103,58 @@ void RegisterOGROCI()
 {
     if (! GDAL_CHECK_VERSION("OCI driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGROCIDriver );
+    
+    if( GDALGetDriverByName( "OCI" ) == NULL )
+    {
+        GDALDriver* poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "OCI" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                        "Oracle Spatial" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                        "drv_oci.html" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "OCI:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='DBNAME' type='string' description='Database name'/>"
+"  <Option name='USER' type='string' description='User name'/>"
+"  <Option name='PASSWORD' type='string' description='Password'/>"
+"  <Option name='TABLES' type='string' description='Restricted set of tables to list (comma separated)'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+        "<LayerCreationOptionList>"
+        "  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='NO'/>"
+        "  <Option name='PRECISION' type='boolean' description='Whether fields created should keep the width and precision' default='YES'/>"
+        "  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+        "  <Option name='TRUNCATE' type='boolean' description='Whether to truncate an existing table' default='NO'/>"
+        "  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES' deprecated_alias='INDEX'/>"
+        "  <Option name='INDEX_PARAMETERS' type='string' description='Creation parameters when the spatial index is created'/>"
+        "  <Option name='ADD_LAYER_GTYPE' type='boolean' description='May be set to NO to disable the constraints on the geometry type in the spatial index' default='YES'/>"
+        "  <Option name='MULTI_LOAD' type='boolean' description='If enabled new features will be created in groups of 100 per SQL INSERT command' default='YES'/>"
+        "  <Option name='LOADER_FILE' type='string' description='If this option is set, all feature information will be written to a file suitable for use with SQL*Loader'/>"
+        "  <Option name='DIM' type='integer' description='Set to 2 to force the geometries to be 2D, or 3 to be 2.5D' default='3'/>"
+        "  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column.' default='ORA_GEOMETRY'/>"
+        "  <Option name='GEOMETRY_NULLABLE' type='boolean' description='Whether the values of the geometry column can be NULL' default='YES'/>"
+        "  <Option name='DIMINFO_X' type='string' description='xmin,xmax,xres values to control the X dimension info written into the USER_SDO_GEOM_METADATA table'/>"
+        "  <Option name='DIMINFO_Y' type='string' description='ymin,ymax,yres values to control the Y dimension info written into the USER_SDO_GEOM_METADATA table'/>"
+        "  <Option name='DIMINFO_Z' type='string' description='zmin,zmax,zres values to control the Z dimension info written into the USER_SDO_GEOM_METADATA table'/>"
+        "  <Option name='SRID' type='int' description='Forced SRID of the layer'/>"
+        "</LayerCreationOptionList>");
+            
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->pfnOpen = OGROCIDriverOpen;
+        poDriver->pfnIdentify = OGROCIDriverIdentify;
+        poDriver->pfnCreate = OGROCIDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/oci/ogrocilayer.cpp b/ogr/ogrsf_frmts/oci/ogrocilayer.cpp
index 529e6d5..0cfc2c8 100644
--- a/ogr/ogrsf_frmts/oci/ogrocilayer.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocilayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocilayer.cpp 24521 2012-05-31 17:02:52Z ilucena $
+ * $Id: ogrocilayer.cpp 27855 2014-10-13 14:50:21Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCILayer class.  This is layer semantics
@@ -32,7 +32,7 @@
 #include "ogr_oci.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrocilayer.cpp 24521 2012-05-31 17:02:52Z ilucena $");
+CPL_CVSID("$Id: ogrocilayer.cpp 27855 2014-10-13 14:50:21Z rouault $");
 
 /************************************************************************/
 /*                           OGROCILayer()                               */
@@ -313,6 +313,11 @@ OGRGeometry *OGROCILayer::TranslateGeometry()
         return NULL;
 
 /* -------------------------------------------------------------------- */
+/*      Establish the dimension.                                        */
+/* -------------------------------------------------------------------- */
+    int nDimension = MAX(2,(nGType / 1000));
+
+/* -------------------------------------------------------------------- */
 /*      Handle point data directly from built-in point info.            */
 /* -------------------------------------------------------------------- */
     if( ORA_GTYPE_MATCH(nGType,ORA_GTYPE_POINT)
@@ -330,15 +335,13 @@ OGRGeometry *OGROCILayer::TranslateGeometry()
             OCINumberToReal(poSession->hError, &(hLastGeom->sdo_point.z), 
                             (uword)sizeof(double), (dvoid *)&dfZ);
 
-        return new OGRPoint( dfX, dfY, dfZ );
+        if( nDimension == 3 )
+            return new OGRPoint( dfX, dfY, dfZ );
+        else
+            return new OGRPoint( dfX, dfY );
     }
 
 /* -------------------------------------------------------------------- */
-/*      Establish the dimension.                                        */
-/* -------------------------------------------------------------------- */
-    int nDimension = MAX(2,(nGType / 1000));
-
-/* -------------------------------------------------------------------- */
 /*      If this is a sort of container geometry, create the             */
 /*      container now.                                                  */
 /* -------------------------------------------------------------------- */
@@ -536,7 +539,8 @@ OGROCILayer::TranslateGeometryElement( int *piElement,
 
         poPoint->setX( dfX );
         poPoint->setY( dfY );
-        poPoint->setZ( dfZ );
+        if( nDimension == 3 )
+            poPoint->setZ( dfZ );
 
         return poPoint;
     }
@@ -557,7 +561,7 @@ OGROCILayer::TranslateGeometryElement( int *piElement,
             GetOrdinalPoint( nStartOrdinal + i*nDimension, nDimension, 
                              &dfX, &dfY, &dfZ );
 
-            OGRPoint *poPoint = new OGRPoint( dfX, dfY, dfZ );
+            OGRPoint *poPoint = (nDimension == 3) ? new OGRPoint( dfX, dfY, dfZ ):  new OGRPoint( dfX, dfY );
             poMP->addGeometryDirectly( poPoint );
         }
         return poMP;
@@ -588,7 +592,10 @@ OGROCILayer::TranslateGeometryElement( int *piElement,
 
             GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
                              &dfX, &dfY, &dfZ );
-            poLS->setPoint( i, dfX, dfY, dfZ );
+            if (nDimension == 3)
+                poLS->setPoint( i, dfX, dfY, dfZ );
+            else
+                poLS->setPoint( i, dfX, dfY );
         }
 
         return poLS;
@@ -641,7 +648,10 @@ OGROCILayer::TranslateGeometryElement( int *piElement,
 
             GetOrdinalPoint( i*nDimension + nStartOrdinal, nDimension, 
                              &dfX, &dfY, &dfZ );
-            poLS->setPoint( i, dfX, dfY, dfZ );
+            if (nDimension == 3)
+                poLS->setPoint( i, dfX, dfY, dfZ );
+            else
+                poLS->setPoint( i, dfX, dfY );
         }
 
         return poLS;
diff --git a/ogr/ogrsf_frmts/oci/ogrociloaderlayer.cpp b/ogr/ogrsf_frmts/oci/ogrociloaderlayer.cpp
index 46b1e64..d30e2d3 100644
--- a/ogr/ogrsf_frmts/oci/ogrociloaderlayer.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrociloaderlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrociloaderlayer.cpp 22346 2011-05-10 03:02:15Z warmerdam $
+ * $Id: ogrociloaderlayer.cpp 28430 2015-02-06 20:57:41Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCILoaderLayer class.  This implements
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrociloaderlayer.cpp 22346 2011-05-10 03:02:15Z warmerdam $");
+CPL_CVSID("$Id: ogrociloaderlayer.cpp 28430 2015-02-06 20:57:41Z rouault $");
 
 /************************************************************************/
 /*                         OGROCILoaderLayer()                          */
@@ -54,6 +54,7 @@ OGROCILoaderLayer::OGROCILoaderLayer( OGROCIDataSource *poDSIn,
     nLDRMode = LDRM_UNKNOWN;
 
     poFeatureDefn = new OGRFeatureDefn( pszTableName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     
     pszGeomName = CPLStrdup( pszGeomColIn );
@@ -190,6 +191,11 @@ void OGROCILoaderLayer::WriteLoaderHeader()
             VSIFPrintf( fpLoader, "    \"%s\" INTEGER EXTERNAL", 
                         poFldDefn->GetNameRef() );
         }
+        else if( poFldDefn->GetType() == OFTInteger )
+        {
+            VSIFPrintf( fpLoader, "    \"%s\" LONGINTEGER EXTERNAL", 
+                        poFldDefn->GetNameRef() );
+        }
         else if( poFldDefn->GetType() == OFTReal )
         {
             VSIFPrintf( fpLoader, "    \"%s\" FLOAT EXTERNAL", 
@@ -256,7 +262,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureStreamMode( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
 /*      Write the FID.                                                  */
 /* -------------------------------------------------------------------- */
-    VSIFPrintf( fpLoader, " %ld|", poFeature->GetFID() );
+    VSIFPrintf( fpLoader, " " CPL_FRMT_GIB "|", poFeature->GetFID() );
 
 /* -------------------------------------------------------------------- */
 /*      Set the geometry                                                */
@@ -324,6 +330,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureStreamMode( OGRFeature *poFeature )
         if( !poFeature->IsFieldSet( i ) )
         {
             if( poFldDefn->GetType() != OFTInteger 
+                && poFldDefn->GetType() != OFTInteger64
                 && poFldDefn->GetType() != OFTReal )
                 VSIFPrintf( fpLoader, "%04d", 0 );
             continue;
@@ -340,6 +347,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureStreamMode( OGRFeature *poFeature )
         nLineLen += strlen(pszStrValue);
 
         if( poFldDefn->GetType() == OFTInteger 
+            || poFldDefn->GetType() == OFTInteger64
             || poFldDefn->GetType() == OFTReal )
         {
             if( poFldDefn->GetWidth() > 0 && bPreservePrecision
@@ -392,7 +400,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureVariableMode( OGRFeature *poFeature )
 /*      Write the FID.                                                  */
 /* -------------------------------------------------------------------- */
     oLine.Append( "00000000" );
-    oLine.Appendf( 32, " %d|", poFeature->GetFID() );
+    oLine.Appendf( 32, " " CPL_FRMT_GIB "|", poFeature->GetFID() );
 
 /* -------------------------------------------------------------------- */
 /*      Set the geometry                                                */
@@ -446,6 +454,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureVariableMode( OGRFeature *poFeature )
         if( !poFeature->IsFieldSet( i ) )
         {
             if( poFldDefn->GetType() != OFTInteger 
+                && poFldDefn->GetType() != OFTInteger64
                 && poFldDefn->GetType() != OFTReal )
                 oLine.Append( "0000" );
             else
@@ -456,6 +465,7 @@ OGRErr OGROCILoaderLayer::WriteFeatureVariableMode( OGRFeature *poFeature )
         const char *pszStrValue = poFeature->GetFieldAsString(i);
 
         if( poFldDefn->GetType() == OFTInteger 
+            || poFldDefn->GetType() == OFTInteger64
             || poFldDefn->GetType() == OFTReal )
         {
             if( poFldDefn->GetWidth() > 0 && bPreservePrecision
@@ -518,10 +528,10 @@ OGRErr OGROCILoaderLayer::WriteFeatureBinaryMode( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGROCILoaderLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGROCILoaderLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     WriteLoaderHeader();
@@ -582,7 +592,7 @@ int OGROCILoaderLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGROCILoaderLayer::GetFeatureCount( int bForce )
+GIntBig OGROCILoaderLayer::GetFeatureCount( int bForce )
 
 {
     return iNextFIDToWrite - 1;
diff --git a/ogr/ogrsf_frmts/oci/ogrociselectlayer.cpp b/ogr/ogrsf_frmts/oci/ogrociselectlayer.cpp
index 2e1523f..ee9496f 100644
--- a/ogr/ogrsf_frmts/oci/ogrociselectlayer.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrociselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrociselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrociselectlayer.cpp 28407 2015-02-03 10:47:59Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCISelectLayer class.  This class 
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrociselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrociselectlayer.cpp 28407 2015-02-03 10:47:59Z rouault $");
 
 /************************************************************************/
 /*                          OGROCISelectLayer()                         */
@@ -48,6 +48,7 @@ OGROCISelectLayer::OGROCISelectLayer( OGROCIDataSource *poDSIn,
     iNextShapeId = 0;
 
     poFeatureDefn = ReadTableDefinition( poDescribedCommand );
+    SetDescription( poFeatureDefn->GetName() );
 
     pszQueryStatement = CPLStrdup(pszQuery);
     
@@ -114,6 +115,8 @@ OGROCISelectLayer::ReadTableDefinition( OGROCIStatement *poCommand )
     OGRFeatureDefn *poDefn;
 
     poDefn = poCommand->GetResultDefn();
+    if( iGeomColumn >= 0 )
+        poDefn->SetGeomType(wkbUnknown);
     poDefn->Reference();
 
 /* -------------------------------------------------------------------- */
@@ -127,5 +130,19 @@ OGROCISelectLayer::ReadTableDefinition( OGROCIStatement *poCommand )
         pszFIDName = CPLStrdup(poDefn->GetFieldDefn(iFIDColumn)->GetNameRef());
     }
 
+    if( EQUAL(pszExpectedFIDName, "OGR_FID") && pszFIDName )
+    {
+        for(int i=0;i<poDefn->GetFieldCount();i++)
+        {
+            // This is presumably a Integer since we always create Integer64 with a
+            // defined precision
+            if( poDefn->GetFieldDefn(i)->GetType() == OFTInteger64 &&
+                poDefn->GetFieldDefn(i)->GetWidth() == 0 )
+            {
+                poDefn->GetFieldDefn(i)->SetType(OFTInteger);
+            }
+        }
+    }
+
     return poDefn;
 }
diff --git a/ogr/ogrsf_frmts/oci/ogrocisession.cpp b/ogr/ogrsf_frmts/oci/ogrocisession.cpp
index 9e2b2c9..7d20a08 100644
--- a/ogr/ogrsf_frmts/oci/ogrocisession.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocisession.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocisession.cpp 27575 2014-08-06 19:40:30Z ilucena $
+ * $Id: ogrocisession.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of OGROCISession, which encapsulates much of the
@@ -31,7 +31,7 @@
 #include "ogr_oci.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrocisession.cpp 27575 2014-08-06 19:40:30Z ilucena $");
+CPL_CVSID("$Id: ogrocisession.cpp 28481 2015-02-13 17:11:15Z rouault $");
 
 /************************************************************************/
 /*                          OGRGetOCISession()                          */
@@ -286,7 +286,8 @@ int OGROCISession::EstablishSession( const char *pszUserid,
     if( oSetNLSTimeFormat.Execute( "ALTER SESSION SET NLS_DATE_FORMAT='YYYY/MM/DD' \
         NLS_TIME_FORMAT='HH24:MI:SS' NLS_TIME_TZ_FORMAT='HH24:MI:SS TZHTZM' \
         NLS_TIMESTAMP_FORMAT='YYYY/MM/DD HH24:MI:SS' \
-        NLS_TIMESTAMP_TZ_FORMAT='YYYY/MM/DD HH24:MI:SS TZHTZM'" ) != CE_None )
+        NLS_TIMESTAMP_TZ_FORMAT='YYYY/MM/DD HH24:MI:SS TZHTZM' \
+        NLS_NUMERIC_CHARACTERS = '. '" ) != CE_None )
         return OGRERR_FAILURE;
 
     return TRUE;
@@ -358,6 +359,7 @@ OGROCISession::GetParmInfo( OCIParam *hParmDesc, OGRFieldDefn *poOGRDefn,
 {
     ub2 nOCIType, nOCILen;
     ub4 nColLen;
+    ub1 bOCINull;
     char *pszColName;
     char szTermColName[128];
     
@@ -381,7 +383,13 @@ OGROCISession::GetParmInfo( OCIParam *hParmDesc, OGRFieldDefn *poOGRDefn,
                     &nColLen, OCI_ATTR_NAME, hError ), 
         "OCIAttrGet(Name)") )
         return CE_Failure;
-    
+
+    if( Failed(
+        OCIAttrGet( hParmDesc, OCI_DTYPE_PARAM, (dvoid **)&bOCINull,
+                    0, OCI_ATTR_IS_NULL, hError ), 
+        "OCIAttrGet(Null)") )
+        return CE_Failure;
+
     if( nColLen >= sizeof(szTermColName) )                              
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -395,6 +403,7 @@ OGROCISession::GetParmInfo( OCIParam *hParmDesc, OGRFieldDefn *poOGRDefn,
     szTermColName[nColLen] = '\0';
     
     poOGRDefn->SetName( szTermColName );
+    poOGRDefn->SetNullable( bOCINull );
 
 /* -------------------------------------------------------------------- */
 /*      Attempt to classify as an OGRType.                              */
@@ -444,12 +453,12 @@ OGROCISession::GetParmInfo( OCIParam *hParmDesc, OGRFieldDefn *poOGRDefn,
             }
             else if( byPrecision < 38 )
             {
-                poOGRDefn->SetType( OFTInteger );
+                poOGRDefn->SetType( (byPrecision < 10) ? OFTInteger : OFTInteger64 );
                 poOGRDefn->SetWidth( byPrecision );
             }
             else
             {
-                poOGRDefn->SetType( OFTInteger );
+                poOGRDefn->SetType( OFTInteger64 );
             }
         }
         break;
diff --git a/ogr/ogrsf_frmts/oci/ogrocistatement.cpp b/ogr/ogrsf_frmts/oci/ogrocistatement.cpp
index bdd0155..aea733c 100644
--- a/ogr/ogrsf_frmts/oci/ogrocistatement.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocistatement.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocistatement.cpp 14387 2008-05-07 16:14:03Z tamas $
+ * $Id: ogrocistatement.cpp 28809 2015-03-28 17:10:07Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of OGROCIStatement, which encapsulates the 
@@ -31,7 +31,7 @@
 #include "ogr_oci.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrocistatement.cpp 14387 2008-05-07 16:14:03Z tamas $");
+CPL_CVSID("$Id: ogrocistatement.cpp 28809 2015-03-28 17:10:07Z rouault $");
 
 /************************************************************************/
 /*                          OGROCIStatement()                           */
@@ -51,6 +51,7 @@ OGROCIStatement::OGROCIStatement( OGROCISession *poSessionIn )
     panFieldMap = NULL;
 
     pszCommandText = NULL;
+    nAffectedRows = 0;
 }
 
 /************************************************************************/
@@ -261,7 +262,17 @@ CPLErr OGROCIStatement::Execute( const char *pszSQLStatement,
         return CE_Failure;
 
     if( !bSelect )
+    {
+        ub4 row_count;
+        if( poSession->Failed( 
+            OCIAttrGet( hStatement, OCI_HTYPE_STMT,
+                        &row_count, 0, OCI_ATTR_ROW_COUNT, poSession->hError ),
+                        "OCIAttrGet(OCI_ATTR_ROW_COUNT)") )
+            return CE_Failure;
+        nAffectedRows = row_count;
+
         return CE_None;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Count the columns.                                              */
@@ -286,6 +297,7 @@ CPLErr OGROCIStatement::Execute( const char *pszSQLStatement,
 /*      defines.                                                        */
 /* ==================================================================== */
     poDefn = new OGRFeatureDefn( pszCommandText );
+    poDefn->SetGeomType(wkbNone);
     poDefn->Reference();
 
     for( int iParm = 0; iParm < nRawColumnCount; iParm++ )
@@ -310,8 +322,17 @@ CPLErr OGROCIStatement::Execute( const char *pszSQLStatement,
 
         if( oField.GetType() == OFTBinary )
         {
-            panFieldMap[iParm] = -1;
-            continue;                   
+            /* We could probably generalize that, but at least it works in that */
+            /* use case */
+            if( EQUAL(oField.GetNameRef(), "DATA_DEFAULT") && nOCIType == SQLT_LNG )
+            {
+                oField.SetType(OFTString);
+            }
+            else
+            {
+                panFieldMap[iParm] = -1;
+                continue;
+            }
         }
 
         poDefn->AddFieldDefn( &oField );
diff --git a/ogr/ogrsf_frmts/oci/ogrocistringbuf.cpp b/ogr/ogrsf_frmts/oci/ogrocistringbuf.cpp
index 1c6cfc8..2f091aa 100644
--- a/ogr/ogrsf_frmts/oci/ogrocistringbuf.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocistringbuf.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocistringbuf.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrocistringbuf.cpp 28429 2015-02-06 20:56:30Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Simple string buffer used to accumulate text of commands 
@@ -31,7 +31,7 @@
 #include "ogr_oci.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrocistringbuf.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrocistringbuf.cpp 28429 2015-02-06 20:56:30Z rouault $");
 
 /************************************************************************/
 /*                          OGROCIStringBuf()                           */
@@ -102,7 +102,7 @@ void OGROCIStringBuf::Appendf( int nMax, const char *pszFormat, ... )
         pszBuffer = szSimpleBuf;
 
     va_start(args, pszFormat);
-    vsprintf(pszBuffer, pszFormat, args);
+    CPLvsnprintf(pszBuffer, nMax, pszFormat, args);
     va_end(args);
 
     Append( pszBuffer );
diff --git a/ogr/ogrsf_frmts/oci/ogrocitablelayer.cpp b/ogr/ogrsf_frmts/oci/ogrocitablelayer.cpp
index 70d49f3..241840f 100644
--- a/ogr/ogrsf_frmts/oci/ogrocitablelayer.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrocitablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrocitablelayer.cpp 28319 2015-01-15 23:29:32Z martinl $
+ * $Id: ogrocitablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCITableLayer class.  This class provides
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrocitablelayer.cpp 28319 2015-01-15 23:29:32Z martinl $");
+CPL_CVSID("$Id: ogrocitablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $");
 
 static int nDiscarded = 0;
 static int nHits = 0;
@@ -45,7 +45,7 @@ static int nHits = 0;
 /************************************************************************/
 
 OGROCITableLayer::OGROCITableLayer( OGROCIDataSource *poDSIn, 
-                                    const char * pszTableName,
+                                    const char * pszTableName, OGRwkbGeometryType eGType,
                                     int nSRIDIn, int bUpdate, int bNewLayerIn )
 
 {
@@ -69,6 +69,9 @@ OGROCITableLayer::OGROCITableLayer( OGROCIDataSource *poDSIn,
         bHaveSpatialIndex = HSI_UNKNOWN;
 
     poFeatureDefn = ReadTableDefinition( pszTableName );
+    if( eGType != wkbUnknown && poFeatureDefn->GetGeomFieldCount() > 0 )
+        poFeatureDefn->GetGeomFieldDefn(0)->SetType(eGType);
+    SetDescription( poFeatureDefn->GetName() );
 
     nSRID = nSRIDIn;
     if( nSRID == -1 )
@@ -254,6 +257,7 @@ OGRFeatureDefn *OGROCITableLayer::ReadTableDefinition( const char * pszTable )
 /* -------------------------------------------------------------------- */
     const char *pszExpectedFIDName = 
         CPLGetConfigOption( "OCI_FID", "OGR_FID" );
+    int bGeomFieldNullable = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Parse the returned table information.                           */
@@ -283,12 +287,14 @@ OGRFeatureDefn *OGROCITableLayer::ReadTableDefinition( const char * pszTable )
                 CPLFree( pszGeomName );
                 pszGeomName = CPLStrdup( oField.GetNameRef() );
                 iGeomColumn = iRawFld;
+                bGeomFieldNullable = oField.IsNullable();
             }
             continue;                   
         }
 
         if( EQUAL(oField.GetNameRef(),pszExpectedFIDName) 
-            && oField.GetType() == OFTInteger )
+            && (oField.GetType() == OFTInteger ||
+                oField.GetType() == OFTInteger64) )
         {
             pszFIDName = CPLStrdup(oField.GetNameRef());
             continue;
@@ -297,6 +303,39 @@ OGRFeatureDefn *OGROCITableLayer::ReadTableDefinition( const char * pszTable )
         poDefn->AddFieldDefn( &oField );
     }
 
+    CPLString osSQL;
+    osSQL.Printf("SELECT COLUMN_NAME, DATA_DEFAULT FROM user_tab_columns WHERE DATA_DEFAULT IS NOT NULL AND TABLE_NAME = '%s'",
+                 CPLString(pszTable).toupper().c_str());
+    OGRLayer* poSQLLyr = poDS->ExecuteSQL(osSQL, NULL, NULL);
+    if( poSQLLyr != NULL )
+    {
+        OGRFeature* poFeature;
+        while( (poFeature = poSQLLyr->GetNextFeature()) != NULL )
+        {
+            const char* pszColName = poFeature->GetFieldAsString(0);
+            const char* pszDefault = poFeature->GetFieldAsString(1);
+            int nIdx = poDefn->GetFieldIndex(pszColName);
+            if( nIdx >= 0 )
+                poDefn->GetFieldDefn(nIdx)->SetDefault(pszDefault);
+            delete poFeature;
+        }
+        poDS->ReleaseResultSet(poSQLLyr);
+    }
+
+    if( EQUAL(pszExpectedFIDName, "OGR_FID") && pszFIDName )
+    {
+        for(int i=0;i<poDefn->GetFieldCount();i++)
+        {
+            // This is presumably a Integer since we always create Integer64 with a
+            // defined precision
+            if( poDefn->GetFieldDefn(i)->GetType() == OFTInteger64 &&
+                poDefn->GetFieldDefn(i)->GetWidth() == 0 )
+            {
+                poDefn->GetFieldDefn(i)->SetType(OFTInteger);
+            }
+        }
+    }
+    
     /* -------------------------------------------------------------------- */
     /*      Identify Geometry dimension                                     */
     /* -------------------------------------------------------------------- */
@@ -363,6 +402,58 @@ OGRFeatureDefn *OGROCITableLayer::ReadTableDefinition( const char * pszTable )
         {
             CPLDebug( "OCI", "get dim based of existing data or index failed." );
         }
+        
+        {
+            OGROCIStringBuf oDimCmd2;
+            OGROCIStatement oDimStatement2( poSession );
+            char **papszResult2;
+
+            CPLErrorReset();
+            oDimCmd2.Appendf( 1024,
+                "select m.SDO_LAYER_GTYPE "
+                "from all_sdo_index_metadata m, all_sdo_index_info i "
+                "where i.index_name = m.sdo_index_name "
+                "and i.sdo_index_owner = m.sdo_index_owner "
+                "and i.table_name = upper('%s')",
+                osTableName.c_str() );
+
+            oDimStatement2.Execute( oDimCmd2.GetString() );
+
+            papszResult2 = oDimStatement2.SimpleFetchRow();
+
+            if( CSLCount( papszResult2 ) > 0 )
+            {
+                const char* pszLayerGType = papszResult2[0];
+                OGRwkbGeometryType eGeomType = wkbUnknown;
+                if( EQUAL(pszLayerGType, "POINT") )
+                    eGeomType = wkbPoint;
+                else if( EQUAL(pszLayerGType, "LINE") )
+                    eGeomType = wkbLineString;
+                else if( EQUAL(pszLayerGType, "POLYGON") )
+                    eGeomType = wkbPolygon;
+                else if( EQUAL(pszLayerGType, "MULTIPOINT") )
+                    eGeomType = wkbMultiPoint;
+                else if( EQUAL(pszLayerGType, "MULTILINE") )
+                    eGeomType = wkbMultiLineString;
+                else if( EQUAL(pszLayerGType, "MULTIPOLYGON") )
+                    eGeomType = wkbMultiPolygon;
+                else if( !EQUAL(pszLayerGType, "COLLECTION") )
+                    CPLDebug("OCI", "LAYER_GTYPE = %s", pszLayerGType );
+                if( iDim == 3 )
+                    eGeomType = wkbSetZ(eGeomType);
+                poDefn->GetGeomFieldDefn(0)->SetType( eGeomType );
+                poDefn->GetGeomFieldDefn(0)->SetNullable( bGeomFieldNullable );
+            }
+            else
+            {
+                // we want to clear any errors to avoid confusing the application.
+                CPLErrorReset();
+            }
+        }
+    }
+    else
+    {
+        poDefn->SetGeomType(wkbNone);
     }
 
     bValidTable = TRUE;
@@ -498,7 +589,7 @@ void OGROCITableLayer::BuildFullQueryStatement()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGROCITableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGROCITableLayer::GetFeature( GIntBig nFeatureId )
 
 {
 
@@ -525,7 +616,7 @@ OGRFeature *OGROCITableLayer::GetFeature( long nFeatureId )
     oCmd.Append( poFeatureDefn->GetName() );
     oCmd.Append( " " );
     oCmd.Appendf( 50+strlen(pszFIDName), 
-                  " WHERE \"%s\" = %ld ", 
+                  " WHERE \"%s\" = " CPL_FRMT_GIB " ", 
                   pszFIDName, nFeatureId );
 
 /* -------------------------------------------------------------------- */
@@ -555,7 +646,7 @@ OGRFeature *OGROCITableLayer::GetFeature( long nFeatureId )
     if( poFeature != NULL && poFeature->GetFID() != nFeatureId )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "OGROCITableLayer::GetFeature(%ld) ... query returned feature %ld instead!",
+                  "OGROCITableLayer::GetFeature(" CPL_FRMT_GIB ") ... query returned feature " CPL_FRMT_GIB " instead!",
                   nFeatureId, poFeature->GetFID() );
         delete poFeature;
         return NULL;
@@ -698,7 +789,7 @@ OGRErr OGROCITableLayer::SetAttributeFilter( const char *pszQuery )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /*                                                                      */
 /*      We implement SetFeature() by deleting the existing row (if      */
 /*      it exists), and then using CreateFeature() to write it out      */
@@ -706,7 +797,7 @@ OGRErr OGROCITableLayer::SetAttributeFilter( const char *pszQuery )
 /*      existing FID if possible.                                       */
 /************************************************************************/
 
-OGRErr OGROCITableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGROCITableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
 /* -------------------------------------------------------------------- */
@@ -715,7 +806,7 @@ OGRErr OGROCITableLayer::SetFeature( OGRFeature *poFeature )
     if( pszFIDName == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "OGROCITableLayer::SetFeature(%ld) failed because there is "
+                  "OGROCITableLayer::ISetFeature(" CPL_FRMT_GIB ") failed because there is "
                   "no apparent FID column on table %s.",
                   poFeature->GetFID(), 
                   poFeatureDefn->GetName() );
@@ -726,27 +817,15 @@ OGRErr OGROCITableLayer::SetFeature( OGRFeature *poFeature )
     if( poFeature->GetFID() == OGRNullFID )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "OGROCITableLayer::SetFeature(%ld) failed because the feature "
+                  "OGROCITableLayer::ISetFeature(" CPL_FRMT_GIB ") failed because the feature "
                   "has no FID!", poFeature->GetFID() );
 
         return OGRERR_FAILURE;
     }
 
-/* -------------------------------------------------------------------- */
-/*      Prepare the delete command, and execute.  We don't check the    */
-/*      error result of the execute, since attempting to Set a          */
-/*      non-existing feature may be OK.                                 */
-/* -------------------------------------------------------------------- */
-    OGROCIStringBuf     oCmdText;
-    OGROCIStatement     oCmdStatement( poDS->GetSession() );
-
-    oCmdText.Appendf( strlen(poFeatureDefn->GetName())+strlen(pszFIDName)+100,
-                      "DELETE FROM %s WHERE \"%s\" = %d",
-                      poFeatureDefn->GetName(), 
-                      pszFIDName, 
-                      poFeature->GetFID() );
-
-    oCmdStatement.Execute( oCmdText.GetString() );
+    OGRErr eErr = DeleteFeature(poFeature->GetFID());
+    if( eErr != OGRERR_NONE )
+        return eErr;
 
     return CreateFeature( poFeature );
 }
@@ -755,7 +834,7 @@ OGRErr OGROCITableLayer::SetFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGROCITableLayer::DeleteFeature( long nFID )
+OGRErr OGROCITableLayer::DeleteFeature( GIntBig nFID )
 
 {
 /* -------------------------------------------------------------------- */
@@ -764,7 +843,7 @@ OGRErr OGROCITableLayer::DeleteFeature( long nFID )
     if( pszFIDName == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "OGROCITableLayer::DeleteFeature(%ld) failed because there is "
+                  "OGROCITableLayer::DeleteFeature(" CPL_FRMT_GIB ") failed because there is "
                   "no apparent FID column on table %s.",
                   nFID, 
                   poFeatureDefn->GetName() );
@@ -775,7 +854,7 @@ OGRErr OGROCITableLayer::DeleteFeature( long nFID )
     if( nFID == OGRNullFID )
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "OGROCITableLayer::DeleteFeature(%ld) failed for Null FID", 
+                  "OGROCITableLayer::DeleteFeature(" CPL_FRMT_GIB ") failed for Null FID", 
                   nFID );
 
         return OGRERR_FAILURE;
@@ -790,22 +869,22 @@ OGRErr OGROCITableLayer::DeleteFeature( long nFID )
     OGROCIStatement     oCmdStatement( poDS->GetSession() );
 
     oCmdText.Appendf( strlen(poFeatureDefn->GetName())+strlen(pszFIDName)+100,
-                      "DELETE FROM %s WHERE \"%s\" = %d",
+                      "DELETE FROM %s WHERE \"%s\" = " CPL_FRMT_GIB,
                       poFeatureDefn->GetName(), 
                       pszFIDName, 
                       nFID );
 
     if( oCmdStatement.Execute( oCmdText.GetString() ) == CE_None )
-        return OGRERR_NONE;
+        return (oCmdStatement.GetAffectedRows() > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
     else
         return OGRERR_FAILURE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGROCITableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGROCITableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
 /* -------------------------------------------------------------------- */
@@ -910,12 +989,12 @@ OGRErr OGROCITableLayer::UnboundCreateFeature( OGRFeature *poFeature )
             OGRPoint *poPoint = (OGRPoint *) poGeometry;
 
             if( nDimension == 2 )
-                sprintf( szSDO_GEOMETRY,
+                CPLsprintf( szSDO_GEOMETRY,
                          "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,0),NULL,NULL)",
                          SDO_GEOMETRY, 2001, szSRID, 
                          poPoint->getX(), poPoint->getY() );
             else
-                sprintf( szSDO_GEOMETRY, 
+                CPLsprintf( szSDO_GEOMETRY, 
                          "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,%.16g),NULL,NULL)",
                          SDO_GEOMETRY, 3001, szSRID, 
                          poPoint->getX(), poPoint->getY(), poPoint->getZ() );
@@ -951,7 +1030,7 @@ OGRErr OGROCITableLayer::UnboundCreateFeature( OGRFeature *poFeature )
 
     if( pszFIDName != NULL )
     {
-        long  nFID;
+        GIntBig  nFID;
 
         if( bNeedComma )
             strcat( pszCommand+nOffset, ", " );
@@ -969,7 +1048,7 @@ OGRErr OGROCITableLayer::UnboundCreateFeature( OGRFeature *poFeature )
             nFID = iNextFIDToWrite++;
             poFeature->SetFID( nFID );
         }
-        sprintf( pszCommand+nOffset, "%ld", nFID );
+        sprintf( pszCommand+nOffset, CPL_FRMT_GIB, nFID );
     }
 
 /* -------------------------------------------------------------------- */
@@ -996,6 +1075,7 @@ OGRErr OGROCITableLayer::UnboundCreateFeature( OGRFeature *poFeature )
         }
         
         if( poFldDefn->GetType() == OFTInteger 
+            || poFldDefn->GetType() == OFTInteger64
             || poFldDefn->GetType() == OFTReal )
         {
             if( poFldDefn->GetWidth() > 0 && bPreservePrecision
@@ -1324,7 +1404,7 @@ int OGROCITableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGROCITableLayer::GetFeatureCount( int bForce )
+GIntBig OGROCITableLayer::GetFeatureCount( int bForce )
 
 {
 /* -------------------------------------------------------------------- */
@@ -1358,7 +1438,7 @@ int OGROCITableLayer::GetFeatureCount( int bForce )
         return OGROCILayer::GetFeatureCount( bForce );
     }
     
-    return atoi(papszResult[0]);
+    return CPLAtoGIntBig(papszResult[0]);
 }
 
 /************************************************************************/
@@ -1532,95 +1612,10 @@ void OGROCITableLayer::UpdateLayerExtents()
 }
 
 /************************************************************************/
-/*                          FinalizeNewLayer()                          */
-/*                                                                      */
-/*      Our main job here is to update the USER_SDO_GEOM_METADATA       */
-/*      table to include the correct array of dimension object with     */
-/*      the appropriate extents for this layer.  We may also do         */
-/*      spatial indexing at this point.                                 */
-/************************************************************************/
-
-void OGROCITableLayer::FinalizeNewLayer()
-
-{
-    UpdateLayerExtents();
-
-/* -------------------------------------------------------------------- */
-/*      For new layers we try to create a spatial index.                */
-/* -------------------------------------------------------------------- */
-    if( bNewLayer && sExtent.IsInit() )
-    {
-/* -------------------------------------------------------------------- */
-/*      If the user has disabled INDEX support then don't create the    */
-/*      index.                                                          */
-/* -------------------------------------------------------------------- */
-        if( !CSLFetchBoolean( papszOptions, "INDEX", TRUE ) )
-            return;
-
-/* -------------------------------------------------------------------- */
-/*      Establish an index name.  For some reason Oracle 8.1.7 does     */
-/*      not support spatial index names longer than 18 characters so    */
-/*      we magic up an index name if it would be too long.              */
-/* -------------------------------------------------------------------- */
-        char  szIndexName[20];
-
-        if( strlen(poFeatureDefn->GetName()) < 15 )
-            sprintf( szIndexName, "%s_idx", poFeatureDefn->GetName() );
-        else if( strlen(poFeatureDefn->GetName()) < 17 )
-            sprintf( szIndexName, "%si", poFeatureDefn->GetName() );
-        else
-        {
-            int i, nHash = 0;
-            const char *pszSrcName = poFeatureDefn->GetName();
-
-            for( i = 0; pszSrcName[i] != '\0'; i++ )
-                nHash = (nHash + i * pszSrcName[i]) % 987651;
-        
-            sprintf( szIndexName, "OSI_%d", nHash );
-        }
-
-        poDS->GetSession()->CleanName( szIndexName );
-
-/* -------------------------------------------------------------------- */
-/*      Try creating an index on the table now.  Use a simple 5         */
-/*      level quadtree based index.  Would R-tree be a better default?  */
-/* -------------------------------------------------------------------- */
-        OGROCIStringBuf  sIndexCmd;
-        OGROCIStatement oExecStatement( poDS->GetSession() );
-    
-
-        sIndexCmd.Appendf( 10000, "CREATE INDEX \"%s\" ON %s(\"%s\") "
-                           "INDEXTYPE IS MDSYS.SPATIAL_INDEX ",
-                           szIndexName, 
-                           poFeatureDefn->GetName(), 
-                           pszGeomName );
-
-        if( CSLFetchNameValue( papszOptions, "INDEX_PARAMETERS" ) != NULL )
-        {
-            sIndexCmd.Append( " PARAMETERS( '" );
-            sIndexCmd.Append( CSLFetchNameValue(papszOptions,"INDEX_PARAMETERS") );
-            sIndexCmd.Append( "' )" );
-        }
-
-        if( oExecStatement.Execute( sIndexCmd.GetString() ) != CE_None )
-        {
-            CPLString osDropCommand;
-            osDropCommand.Printf( "DROP INDEX \"%s\"", szIndexName );
-            oExecStatement.Execute( osDropCommand );
-        }
-    }  
-}
-
-/************************************************************************/
-/*                   AllocAndBindForWrite(int eType)                    */
+/*                   AllocAndBindForWrite()                             */
 /************************************************************************/
 
-/* -------------------------------------------------------------------- */
-/*      PJH: modified with geometry type parameter so as not to         */
-/*      attempt to write geometry if there is none to write as          */
-/*      Oracle will default the value of the column to Null.            */
-/* -------------------------------------------------------------------- */
-int OGROCITableLayer::AllocAndBindForWrite(int eType)
+int OGROCITableLayer::AllocAndBindForWrite()
 
 {
     OGROCISession      *poSession = poDS->GetSession();
@@ -1644,7 +1639,7 @@ int OGROCITableLayer::AllocAndBindForWrite(int eType)
     oCmdBuf.Append( "\"(\"" );
     oCmdBuf.Append( pszFIDName );
 
-    if (eType != wkbNone)
+    if (GetGeomType() != wkbNone)
     {
        oCmdBuf.Append( "\",\"" );
        oCmdBuf.Append( pszGeomName );
@@ -1658,7 +1653,7 @@ int OGROCITableLayer::AllocAndBindForWrite(int eType)
 
     oCmdBuf.Append( "\") VALUES ( :fid " );
 
-    if (eType != wkbNone)
+    if (GetGeomType() != wkbNone)
         oCmdBuf.Append( ", :geometry" );
 
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
@@ -1678,7 +1673,7 @@ int OGROCITableLayer::AllocAndBindForWrite(int eType)
 /* -------------------------------------------------------------------- */
 /*      Setup geometry indicator information.                           */
 /* -------------------------------------------------------------------- */
-    if (eType != wkbNone)
+    if (GetGeomType() != wkbNone)
     {
         pasWriteGeomInd = (SDO_GEOMETRY_ind *)
             CPLCalloc(sizeof(SDO_GEOMETRY_ind),nWriteCacheMax);
@@ -1774,6 +1769,16 @@ int OGROCITableLayer::AllocAndBindForWrite(int eType)
                     sizeof(int), SQLT_INT, papaeWriteFieldInd[i] ) != CE_None )
                 return FALSE;
         }
+        else if( poFldDefn->GetType() == OFTInteger64 )
+        {
+            papWriteFields[i] = 
+                (void *) CPLCalloc( sizeof(GIntBig), nWriteCacheMax );
+
+            if( poBoundStatement->BindScalar( 
+                    szFieldPlaceholderName, papWriteFields[i],
+                    sizeof(GIntBig), SQLT_INT, papaeWriteFieldInd[i] ) != CE_None )
+                return FALSE;
+        }
         else if( poFldDefn->GetType() == OFTReal )
         {
             papWriteFields[i] = (void *) CPLCalloc( sizeof(double), 
@@ -1817,26 +1822,29 @@ OGRErr OGROCITableLayer::BoundCreateFeature( OGRFeature *poFeature )
     OGRErr             eErr;
     OCINumber          oci_number; 
 
+    /* If an unset field has a default value, the current implementation */
+    /* of BoundCreateFeature() doesn't work. */
+    for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    { 
+        if( !poFeature->IsFieldSet( i ) &&
+            poFeature->GetFieldDefnRef(i)->GetDefault() != NULL )
+        {
+            FlushPendingFeatures();
+            return UnboundCreateFeature(poFeature);
+        }
+    }
+
+    if( !poFeature->Validate( OGR_F_VAL_NULL | OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT, TRUE ) )
+        return OGRERR_FAILURE;
+
     iCache = nWriteCacheUsed;
 
 /* -------------------------------------------------------------------- */
-/*  PJH: Initiate the Insert, passing the geometry type as there is no  */
-/*  need to give null geometry to Oracle                                */
+/*  Initiate the Insert                                                 */
 /* -------------------------------------------------------------------- */
     if( nWriteCacheMax == 0 )
     {
-        int eType;
-        if( poFeature->GetGeometryRef() == NULL )
-        {
-            eType = wkbNone;
-        }
-        else
-        {
-            eType = 1; /* PJH: properly, this should be the gType from the geometry */
-                       /* but the actual value does not matter, so long as it is    */
-                       /* not wkbNone                                               */
-        }
-        if( !AllocAndBindForWrite(eType) )
+        if( !AllocAndBindForWrite() )
             return OGRERR_FAILURE;
     }
 
@@ -1953,6 +1961,16 @@ OGRErr OGROCITableLayer::BoundCreateFeature( OGRFeature *poFeature )
                           (uword)sizeof(int), OCI_NUMBER_SIGNED,
                           &(psGeom->sdo_gtype) );
     }
+    else if( pasWriteGeomInd != NULL )
+    {
+        SDO_GEOMETRY_ind  *psInd  = pasWriteGeomInd + iCache;
+        psInd->_atomic = OCI_IND_NULL;
+        psInd->sdo_srid = OCI_IND_NULL;
+        psInd->sdo_point._atomic = OCI_IND_NULL;
+        psInd->sdo_elem_info = OCI_IND_NULL;
+        psInd->sdo_ordinates = OCI_IND_NULL;
+        psInd->sdo_gtype = OCI_IND_NULL;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Set the FID.                                                    */
@@ -1988,6 +2006,10 @@ OGRErr OGROCITableLayer::BoundCreateFeature( OGRFeature *poFeature )
             ((int *) (papWriteFields[i]))[iCache] = 
                 poFeature->GetFieldAsInteger( i );
 
+        else if( poFldDefn->GetType() == OFTInteger64 )
+            ((GIntBig *) (papWriteFields[i]))[iCache] = 
+                poFeature->GetFieldAsInteger64( i );
+
         else if( poFldDefn->GetType() == OFTReal )
             ((double *) (papWriteFields[i]))[iCache] = 
                 poFeature->GetFieldAsDouble( i );
@@ -2074,6 +2096,8 @@ OGRErr OGROCITableLayer::SyncToDisk()
 
     CreateSpatialIndex();
 
+    bNewLayer = FALSE;
+
     return eErr;
 }
 
@@ -2093,7 +2117,8 @@ void OGROCITableLayer::CreateSpatialIndex()
 /*      If the user has disabled INDEX support then don't create the    */
 /*      index.                                                          */
 /* -------------------------------------------------------------------- */
-        if( !CSLFetchBoolean( papszOptions, "INDEX", TRUE ) )
+        if( !CSLFetchBoolean( papszOptions, "SPATIAL_INDEX", TRUE ) ||
+            !CSLFetchBoolean( papszOptions, "INDEX", TRUE ) )
             return;
 
 /* -------------------------------------------------------------------- */
@@ -2134,10 +2159,37 @@ void OGROCITableLayer::CreateSpatialIndex()
                            poFeatureDefn->GetName(),
                            pszGeomName );
 
-        if( CSLFetchNameValue( papszOptions, "INDEX_PARAMETERS" ) != NULL )
+        int bAddLayerGType = CSLTestBoolean(
+            CSLFetchNameValueDef( papszOptions, "ADD_LAYER_GTYPE", "YES") ) &&
+            GetGeomType() != wkbUnknown;
+      
+        CPLString osParams(CSLFetchNameValueDef(papszOptions,"INDEX_PARAMETERS", ""));
+        if( bAddLayerGType || osParams.size() != 0 )
         {
             sIndexCmd.Append( " PARAMETERS( '" );
-            sIndexCmd.Append( CSLFetchNameValue(papszOptions,"INDEX_PARAMETERS") );
+            if( osParams.size() != 0 )
+                sIndexCmd.Append( osParams.c_str() );
+            if( bAddLayerGType &&
+                osParams.ifind("LAYER_GTYPE") == std::string::npos )
+            {
+                if( osParams.size() != 0 )
+                    sIndexCmd.Append( ", " );
+                sIndexCmd.Append( "LAYER_GTYPE=" );
+                if( wkbFlatten(GetGeomType()) == wkbPoint )
+                    sIndexCmd.Append( "POINT" );
+                else if( wkbFlatten(GetGeomType()) == wkbLineString )
+                    sIndexCmd.Append( "LINE" );
+                else if( wkbFlatten(GetGeomType()) == wkbPolygon )
+                    sIndexCmd.Append( "POLYGON" );
+                else if( wkbFlatten(GetGeomType()) == wkbMultiPoint )
+                    sIndexCmd.Append( "MULTIPOINT" );
+                else if( wkbFlatten(GetGeomType()) == wkbMultiLineString )
+                    sIndexCmd.Append( "MULTILINE" );
+                else if( wkbFlatten(GetGeomType()) == wkbMultiPolygon )
+                    sIndexCmd.Append( "MULTIPOLYGON" );
+                else
+                    sIndexCmd.Append( "COLLECTION" );
+            }
             sIndexCmd.Append( "' )" );
         }
 
diff --git a/ogr/ogrsf_frmts/oci/ogrociwritablelayer.cpp b/ogr/ogrsf_frmts/oci/ogrociwritablelayer.cpp
index e63f103..02c2e89 100644
--- a/ogr/ogrsf_frmts/oci/ogrociwritablelayer.cpp
+++ b/ogr/ogrsf_frmts/oci/ogrociwritablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrociwritablelayer.cpp 27583 2014-08-12 16:06:37Z martinl $
+ * $Id: ogrociwritablelayer.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  Oracle Spatial Driver
  * Purpose:  Implementation of the OGROCIWritableLayer class.  This provides
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrociwritablelayer.cpp 27583 2014-08-12 16:06:37Z martinl $");
+CPL_CVSID("$Id: ogrociwritablelayer.cpp 28481 2015-02-13 17:11:15Z rouault $");
 
 /************************************************************************/
 /*                        OGROCIWritableLayer()                         */
@@ -273,6 +273,13 @@ OGRErr OGROCIWritableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK
         else
             strcpy( szFieldType, "INTEGER" );
     }
+    else if( oField.GetType() == OFTInteger64 )
+    {
+        if( bPreservePrecision && oField.GetWidth() != 0 )
+            sprintf( szFieldType, "NUMBER(%d)", oField.GetWidth() );
+        else
+            strcpy( szFieldType, "NUMBER(20)" );
+    }
     else if( oField.GetType() == OFTReal )
     {
         if( bPreservePrecision && oField.GetWidth() != 0 )
@@ -288,18 +295,22 @@ OGRErr OGROCIWritableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK
         else
             sprintf( szFieldType, "VARCHAR2(%d)", oField.GetWidth() );
     }
-    else if ( oField.GetType() == OFTDate ||
-              oField.GetType() == OFTDateTime )
+    else if ( oField.GetType() == OFTDate )
     {
         sprintf( szFieldType, "DATE" );
     }
+    else if ( oField.GetType() == OFTDateTime )
+    {
+        sprintf( szFieldType, "TIMESTAMP" );
+    }
     else if( bApproxOK )
     {
+        oField.SetDefault(NULL);
         CPLError( CE_Warning, CPLE_NotSupported,
                   "Can't create field %s with type %s on Oracle layers.  Creating as VARCHAR.",
                   oField.GetNameRef(),
                   OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
-        strcpy( szFieldType, "VARCHAR(2047)" );
+        strcpy( szFieldType, "VARCHAR2(2047)" );
     }
     else
     {
@@ -317,11 +328,12 @@ OGRErr OGROCIWritableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK
     OGROCIStringBuf     oCommand;
     OGROCIStatement     oAddField( poSession );
 
-    oCommand.MakeRoomFor( 40 + strlen(poFeatureDefn->GetName())
+    oCommand.MakeRoomFor( 70 + strlen(poFeatureDefn->GetName())
                           + strlen(oField.GetNameRef())
-                          + strlen(szFieldType) );
+                          + strlen(szFieldType)
+                          + (oField.GetDefault() ? strlen(oField.GetDefault()) : 0) );
 
-    snprintf( szFieldName, sizeof( szFieldName ), oField.GetNameRef());
+    snprintf( szFieldName, sizeof( szFieldName ), "%s", oField.GetNameRef());
     szFieldName[sizeof( szFieldName )-1] = '\0';
     if ( strlen(oField.GetNameRef()) > sizeof ( szFieldName ) )
     {
@@ -332,7 +344,15 @@ OGRErr OGROCIWritableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK
         oField.SetName(szFieldName);
     }
     sprintf( oCommand.GetString(), "ALTER TABLE %s ADD \"%s\" %s", 
-             poFeatureDefn->GetName(), szFieldName, szFieldType );
+             poFeatureDefn->GetName(), szFieldName, szFieldType);
+    if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+    {
+        sprintf( oCommand.GetString() + strlen(oCommand.GetString()),
+                 " DEFAULT %s", oField.GetDefault() );
+    }
+    if( !oField.IsNullable() )
+        strcat( oCommand.GetString(), " NOT NULL");
+    
     if( oAddField.Execute( oCommand.GetString() ) != CE_None )
         return OGRERR_FAILURE;
 
@@ -379,9 +399,9 @@ void OGROCIWritableLayer::ParseDIMINFO( const char *pszOptionName,
         return;
     }
 
-    *pdfMin = atof(papszTokens[0]);
-    *pdfMax = atof(papszTokens[1]);
-    *pdfRes = atof(papszTokens[2]);
+    *pdfMin = CPLAtof(papszTokens[0]);
+    *pdfMax = CPLAtof(papszTokens[1]);
+    *pdfRes = CPLAtof(papszTokens[2]);
 
     CSLDestroy( papszTokens );
 }
@@ -410,12 +430,12 @@ OGRErr OGROCIWritableLayer::TranslateToSDOGeometry( OGRGeometry * poGeometry,
         OGRPoint *poPoint = (OGRPoint *) poGeometry;
 
         if( nDimension == 2 )
-            sprintf( szResult, 
+            CPLsprintf( szResult, 
                      "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,0.0),NULL,NULL)",
                      SDO_GEOMETRY, 2001, szSRID, 
                      poPoint->getX(), poPoint->getY() );
         else
-            sprintf( szResult, 
+            CPLsprintf( szResult, 
                      "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,%.16g),NULL,NULL)",
                      SDO_GEOMETRY, 3001, szSRID, 
                      poPoint->getX(), poPoint->getY(), poPoint->getZ() );
diff --git a/ogr/ogrsf_frmts/odbc/GNUmakefile b/ogr/ogrsf_frmts/odbc/GNUmakefile
index 17e5421..68d724e 100644
--- a/ogr/ogrsf_frmts/odbc/GNUmakefile
+++ b/ogr/ogrsf_frmts/odbc/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrodbcdatasource.o ogrodbclayer.o ogrodbcdriver.o \
 		ogrodbctablelayer.o ogrodbcselectlayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I.. -I../.. $(CPPFLAGS)
+CPPFLAGS	:=	 -I.. -I../.. $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/odbc/ogr_odbc.h b/ogr/ogrsf_frmts/odbc/ogr_odbc.h
index cc6c80e..4b71851 100644
--- a/ogr/ogrsf_frmts/odbc/ogr_odbc.h
+++ b/ogr/ogrsf_frmts/odbc/ogr_odbc.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_odbc.h 24957 2012-09-23 17:03:30Z rouault $
+ * $Id: ogr_odbc.h 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/ODBC driver.
@@ -51,7 +51,7 @@ class OGRODBCLayer : public OGRLayer
     OGRSpatialReference *poSRS;
     int                 nSRSId;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRODBCDataSource    *poDS;
 
@@ -74,7 +74,7 @@ class OGRODBCLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -111,17 +111,17 @@ class OGRODBCTableLayer : public OGRODBCLayer
                                     const char *pszGeomCol );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 #ifdef notdef
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
     
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 #endif    
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual OGRSpatialReference *GetSpatialRef();
 
@@ -155,9 +155,9 @@ class OGRODBCSelectLayer : public OGRODBCLayer
                         ~OGRODBCSelectLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
diff --git a/ogr/ogrsf_frmts/odbc/ogrodbcdatasource.cpp b/ogr/ogrsf_frmts/odbc/ogrodbcdatasource.cpp
index 0b734bb..a746534 100644
--- a/ogr/ogrsf_frmts/odbc/ogrodbcdatasource.cpp
+++ b/ogr/ogrsf_frmts/odbc/ogrodbcdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodbcdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrodbcdatasource.cpp 28368 2015-01-27 14:25:17Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRODBCDataSource class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrodbcdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrodbcdatasource.cpp 28368 2015-01-27 14:25:17Z rouault $");
 /************************************************************************/
 /*                         OGRODBCDataSource()                          */
 /************************************************************************/
@@ -75,13 +75,60 @@ OGRODBCDataSource::~OGRODBCDataSource()
 }
 
 /************************************************************************/
+/*                  CheckDSNStringTemplate()                            */
+/* The string will be used as the formatting argument of sprintf with   */
+/* a string in vararg. So let's check there's only one '%s', and nothing*/
+/* else                                                                 */
+/************************************************************************/
+
+static int CheckDSNStringTemplate(const char* pszStr)
+{
+    int nPercentSFound = FALSE;
+    while(*pszStr)
+    {
+        if (*pszStr == '%')
+        {
+            if (pszStr[1] != 's')
+            {
+                return FALSE;
+            }
+            else
+            {
+                if (nPercentSFound)
+                    return FALSE;
+                nPercentSFound = TRUE;
+            }
+        }
+        pszStr ++;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
 /*                              OpenMDB()                               */
 /************************************************************************/
 
 int OGRODBCDataSource::OpenMDB( const char * pszNewName, int bUpdate )
 {
-    const char *pszDSNStringTemplate =
-        "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s";
+    const char* pszOptionName = "";
+    pszOptionName = "PGEO_DRIVER_TEMPLATE";
+    const char* pszDSNStringTemplate = CPLGetConfigOption( pszOptionName, NULL );
+    if( pszDSNStringTemplate == NULL )
+    {
+        pszOptionName = "MDB_DRIVER_TEMPLATE";
+        pszDSNStringTemplate = CPLGetConfigOption( pszOptionName, NULL );
+        if( pszDSNStringTemplate == NULL )
+        {
+            pszOptionName = "";
+            pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s";
+        }
+    }
+    if (!CheckDSNStringTemplate(pszDSNStringTemplate))
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "Illegal value for %s option", pszOptionName );
+        return FALSE;
+    }
     char* pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
     sprintf( pszDSN, pszDSNStringTemplate,  pszNewName );
 
@@ -92,11 +139,28 @@ int OGRODBCDataSource::OpenMDB( const char * pszNewName, int bUpdate )
 
     if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Unable to initialize ODBC connection to DSN for %s,\n"
-                  "%s", pszDSN, oSession.GetLastError() );
-        CPLFree( pszDSN );
-        return FALSE;
+        int bError = TRUE;
+        if( EQUAL(pszDSN, "") )
+        {
+            // Trying with another template (#5594)
+            pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=%s";
+            CPLFree( pszDSN );
+            pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
+            sprintf( pszDSN, pszDSNStringTemplate,  pszNewName );
+            CPLDebug( "ODBC", "EstablishSession(%s)", pszDSN );
+            if( oSession.EstablishSession( pszDSN, NULL, NULL ) )
+            {
+                bError = FALSE;
+            }
+        }
+        if( bError )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                    "Unable to initialize ODBC connection to DSN for %s,\n"
+                    "%s", pszDSN, oSession.GetLastError() );
+            CPLFree( pszDSN );
+            return FALSE;
+        }
     }
 
     CPLFree( pszDSN );
diff --git a/ogr/ogrsf_frmts/odbc/ogrodbclayer.cpp b/ogr/ogrsf_frmts/odbc/ogrodbclayer.cpp
index 3b1247a..9651982 100644
--- a/ogr/ogrsf_frmts/odbc/ogrodbclayer.cpp
+++ b/ogr/ogrsf_frmts/odbc/ogrodbclayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodbclayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrodbclayer.cpp 29014 2015-04-25 18:14:49Z tamas $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRODBCLayer class, code shared between 
@@ -32,7 +32,7 @@
 #include "ogr_odbc.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrodbclayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrodbclayer.cpp 29014 2015-04-25 18:14:49Z tamas $");
 
 /************************************************************************/
 /*                            OGRODBCLayer()                            */
@@ -104,6 +104,7 @@ CPLErr OGRODBCLayer::BuildFeatureDefn( const char *pszLayerName,
 
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     int    nRawColumns = poStmt->GetColCount();
 
     poFeatureDefn->Reference();
@@ -129,6 +130,11 @@ CPLErr OGRODBCLayer::BuildFeatureDefn( const char *pszLayerName,
                 oField.SetType( OFTInteger );
                 break;
 
+            case SQL_C_SBIGINT:
+            case SQL_C_UBIGINT:
+                oField.SetType( OFTInteger64 );
+                break;
+
             case SQL_C_BINARY:
                 oField.SetType( OFTBinary );
                 break;
@@ -332,7 +338,7 @@ OGRFeature *OGRODBCLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRODBCLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRODBCLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
diff --git a/ogr/ogrsf_frmts/odbc/ogrodbcselectlayer.cpp b/ogr/ogrsf_frmts/odbc/ogrodbcselectlayer.cpp
index 085ae64..7e99a25 100644
--- a/ogr/ogrsf_frmts/odbc/ogrodbcselectlayer.cpp
+++ b/ogr/ogrsf_frmts/odbc/ogrodbcselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodbcselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrodbcselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRODBCSelectLayer class, layer access to the results
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "ogr_odbc.h"
 
-CPL_CVSID("$Id: ogrodbcselectlayer.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
+CPL_CVSID("$Id: ogrodbcselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 /************************************************************************/
 /*                          OGRODBCSelectLayer()                         */
 /************************************************************************/
@@ -131,7 +131,7 @@ void OGRODBCSelectLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRODBCSelectLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRODBCSelectLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRODBCLayer::GetFeature( nFeatureId );
@@ -169,7 +169,7 @@ OGRErr OGRODBCSelectLayer::GetExtent(OGREnvelope *, int )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRODBCSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRODBCSelectLayer::GetFeatureCount( int bForce )
 
 {
     return OGRODBCLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/odbc/ogrodbctablelayer.cpp b/ogr/ogrsf_frmts/odbc/ogrodbctablelayer.cpp
index 73fc8a0..f74c6bd 100644
--- a/ogr/ogrsf_frmts/odbc/ogrodbctablelayer.cpp
+++ b/ogr/ogrsf_frmts/odbc/ogrodbctablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodbctablelayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrodbctablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRODBCTableLayer class, access to an existing table.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "ogr_odbc.h"
 
-CPL_CVSID("$Id: ogrodbctablelayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrodbctablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 /************************************************************************/
 /*                          OGRODBCTableLayer()                         */
 /************************************************************************/
@@ -82,6 +82,8 @@ CPLErr OGRODBCTableLayer::Initialize( const char *pszLayerName,
 
     CPLFree( pszFIDColumn );
     pszFIDColumn = NULL;
+    
+    SetDescription( pszLayerName );
 
 /* -------------------------------------------------------------------- */
 /*      Parse out schema name if present in layer.  We assume a         */
@@ -275,7 +277,7 @@ void OGRODBCTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRODBCTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRODBCTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -288,7 +290,7 @@ OGRFeature *OGRODBCTableLayer::GetFeature( long nFeatureId )
     poStmt = new CPLODBCStatement( poDS->GetSession() );
     poStmt->Append( "SELECT * FROM " );
     poStmt->Append( poFeatureDefn->GetName() );
-    poStmt->Appendf( " WHERE %s = %ld", pszFIDColumn, nFeatureId );
+    poStmt->Appendf( " WHERE %s = " CPL_FRMT_GIB, pszFIDColumn, nFeatureId );
 
     if( !poStmt->ExecuteSQL() )
     {
@@ -347,7 +349,7 @@ int OGRODBCTableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRODBCTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRODBCTableLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL )
@@ -368,7 +370,7 @@ int OGRODBCTableLayer::GetFeatureCount( int bForce )
         return OGRODBCLayer::GetFeatureCount(bForce);
     }
 
-    return atoi(oStmt.GetColData(0));
+    return CPLAtoGIntBig(oStmt.GetColData(0));
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/ods/GNUmakefile b/ogr/ogrsf_frmts/ods/GNUmakefile
index fb27648..a0884e7 100644
--- a/ogr/ogrsf_frmts/ods/GNUmakefile
+++ b/ogr/ogrsf_frmts/ods/GNUmakefile
@@ -8,7 +8,7 @@ ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=   -DHAVE_EXPAT
 endif
 
-CPPFLAGS	:=	-I.. -I../.. -I../mem $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../mem  $(EXPAT_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/ods/ods_formula_node.cpp b/ogr/ogrsf_frmts/ods/ods_formula_node.cpp
index 9619fe3..bfdb479 100644
--- a/ogr/ogrsf_frmts/ods/ods_formula_node.cpp
+++ b/ogr/ogrsf_frmts/ods/ods_formula_node.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ods_formula_node.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ods_formula_node.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Component: ODS formula Engine
  * Purpose: Implementation of the ods_formula_node class used to represent a
@@ -1157,7 +1157,7 @@ std::string ods_formula_node::TransformToString() const
     }
     else if (field_type == ODS_FIELD_TYPE_FLOAT)
     {
-        snprintf(szTmp, sizeof(szTmp), "%.16g", float_value);
+        CPLsnprintf(szTmp, sizeof(szTmp), "%.16g", float_value);
         return szTmp;
     }
     else if (field_type == ODS_FIELD_TYPE_STRING)
diff --git a/ogr/ogrsf_frmts/ods/ods_formula_parser.cpp b/ogr/ogrsf_frmts/ods/ods_formula_parser.cpp
index 96b96fa..38c2182 100644
--- a/ogr/ogrsf_frmts/ods/ods_formula_parser.cpp
+++ b/ogr/ogrsf_frmts/ods/ods_formula_parser.cpp
@@ -80,7 +80,7 @@
 #line 1 "ods_formula_parser.y"
 
 /******************************************************************************
- * $Id: ods_formula_parser.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ods_formula_parser.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Component: OGR ODS Formula Engine
  * Purpose: expression and select parser grammar.
@@ -116,16 +116,16 @@
 
 #define YYSTYPE  ods_formula_node*
 
-/* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */ 
-/* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */ 
-/* increase YYINITDEPTH instead, but this will consume memory. */ 
-/* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */ 
-/* it appears to be a non documented feature of Bison */ 
+/* Defining YYSTYPE_IS_TRIVIAL is needed because the parser is generated as a C++ file. */
+/* See http://www.gnu.org/s/bison/manual/html_node/Memory-Management.html that suggests */
+/* increase YYINITDEPTH instead, but this will consume memory. */
+/* Setting YYSTYPE_IS_TRIVIAL overcomes this limitation, but might be fragile because */
+/* it appears to be a non documented feature of Bison */
 #define YYSTYPE_IS_TRIVIAL 1
 
 static void ods_formulaerror( CPL_UNUSED ods_formula_parse_context *context, const char *msg )
 {
-    CPLError( CE_Failure, CPLE_AppDefined, 
+    CPLError( CE_Failure, CPLE_AppDefined,
               "Formula Parsing Error: %s", msg );
 }
 
@@ -2238,6 +2238,3 @@ yyreturn:
   /* Make sure YYID is used.  */
   return YYID (yyresult);
 }
-
-
-
diff --git a/ogr/ogrsf_frmts/ods/ods_formula_parser.y b/ogr/ogrsf_frmts/ods/ods_formula_parser.y
index 1f28c53..23a59a8 100644
--- a/ogr/ogrsf_frmts/ods/ods_formula_parser.y
+++ b/ogr/ogrsf_frmts/ods/ods_formula_parser.y
@@ -1,6 +1,6 @@
 %{
 /******************************************************************************
- * $Id: ods_formula_parser.y 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ods_formula_parser.y 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Component: OGR ODS Formula Engine
  * Purpose: expression and select parser grammar.
@@ -43,7 +43,8 @@
 /* it appears to be a non documented feature of Bison */ 
 #define YYSTYPE_IS_TRIVIAL 1
 
-static void ods_formulaerror( CPL_UNUSED ods_formula_parse_context *context, const char *msg )
+static void ods_formulaerror( CPL_UNUSED ods_formula_parse_context *context,
+                              const char *msg )
 {
     CPLError( CE_Failure, CPLE_AppDefined, 
               "Formula Parsing Error: %s", msg );
diff --git a/ogr/ogrsf_frmts/ods/ogr_ods.h b/ogr/ogrsf_frmts/ods/ogr_ods.h
index fb82330..86550dc 100644
--- a/ogr/ogrsf_frmts/ods/ogr_ods.h
+++ b/ogr/ogrsf_frmts/ods/ogr_ods.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_ods.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_ods.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  ODS Translator
  * Purpose:  Definition of classes for OGR OpenOfficeSpreadsheet .ods driver.
@@ -67,16 +67,16 @@ class OGRODSLayer : public OGRMemLayer
 
     /* For external usage. Mess with FID */
     virtual OGRFeature *        GetNextFeature();
-    virtual OGRFeature         *GetFeature( long nFeatureId );
-    virtual OGRErr              SetFeature( OGRFeature *poFeature );
-    virtual OGRErr              DeleteFeature( long nFID );
+    virtual OGRFeature         *GetFeature( GIntBig nFeatureId );
+    virtual OGRErr              ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr              DeleteFeature( GIntBig nFID );
 
     /* For internal usage, for cell resolver */
     OGRFeature *        GetNextFeatureWithoutFIDHack() { return OGRMemLayer::GetNextFeature(); }
-    OGRErr              SetFeatureWithoutFIDHack( OGRFeature *poFeature ) { SetUpdated(); return OGRMemLayer::SetFeature(poFeature); }
+    OGRErr              SetFeatureWithoutFIDHack( OGRFeature *poFeature ) { SetUpdated(); return OGRMemLayer::ISetFeature(poFeature); }
 
-    OGRErr              CreateFeature( OGRFeature *poFeature )
-    { SetUpdated(); return OGRMemLayer::CreateFeature(poFeature); }
+    OGRErr              ICreateFeature( OGRFeature *poFeature )
+    { SetUpdated(); return OGRMemLayer::ICreateFeature(poFeature); }
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE )
@@ -197,13 +197,13 @@ class OGRODSDataSource : public OGRDataSource
 
     virtual int                 TestCapability( const char * );
 
-    virtual OGRLayer* CreateLayer( const char * pszLayerName,
+    virtual OGRLayer* ICreateLayer( const char * pszLayerName,
                                 OGRSpatialReference *poSRS,
                                 OGRwkbGeometryType eType,
                                 char ** papszOptions );
     virtual OGRErr      DeleteLayer(int iLayer);
 
-    virtual OGRErr      SyncToDisk();
+    virtual void        FlushCache();
 
     void startElementCbk(const char *pszName, const char **ppszAttr);
     void endElementCbk(const char *pszName);
diff --git a/ogr/ogrsf_frmts/ods/ogrodsdatasource.cpp b/ogr/ogrsf_frmts/ods/ogrodsdatasource.cpp
index df2312a..74815ee 100644
--- a/ogr/ogrsf_frmts/ods/ogrodsdatasource.cpp
+++ b/ogr/ogrsf_frmts/ods/ogrodsdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodsdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrodsdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  ODS Translator
  * Purpose:  Implements OGRODSDataSource class
@@ -34,7 +34,7 @@
 #include "ods_formula.h"
 #include <set>
 
-CPL_CVSID("$Id: ogrodsdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrodsdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 
 /************************************************************************/
@@ -93,7 +93,8 @@ void OGRODSLayer::SetUpdated(int bUpdatedIn)
 
 OGRErr OGRODSLayer::SyncToDisk()
 {
-    return poDS->SyncToDisk();
+    poDS->FlushCache();
+    return OGRERR_NONE;
 }
 
 /************************************************************************/
@@ -112,7 +113,7 @@ OGRFeature* OGRODSLayer::GetNextFeature()
 /*                           GetFeature()                               */
 /************************************************************************/
 
-OGRFeature* OGRODSLayer::GetFeature( long nFeatureId )
+OGRFeature* OGRODSLayer::GetFeature( GIntBig nFeatureId )
 {
     OGRFeature* poFeature = OGRMemLayer::GetFeature(nFeatureId - (1 + bHasHeaderLine));
     if (poFeature)
@@ -121,19 +122,19 @@ OGRFeature* OGRODSLayer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
 
-OGRErr OGRODSLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRODSLayer::ISetFeature( OGRFeature *poFeature )
 {
     if (poFeature == NULL)
-        return OGRMemLayer::SetFeature(poFeature);
+        return OGRMemLayer::ISetFeature(poFeature);
 
-    long nFID = poFeature->GetFID();
+    GIntBig nFID = poFeature->GetFID();
     if (nFID != OGRNullFID)
         poFeature->SetFID(nFID - (1 + bHasHeaderLine));
     SetUpdated(); 
-    OGRErr eErr = OGRMemLayer::SetFeature(poFeature);
+    OGRErr eErr = OGRMemLayer::ISetFeature(poFeature);
     poFeature->SetFID(nFID);
     return eErr;
 }
@@ -142,7 +143,7 @@ OGRErr OGRODSLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRODSLayer::DeleteFeature( long nFID )
+OGRErr OGRODSLayer::DeleteFeature( GIntBig nFID )
 {
     SetUpdated();
     return OGRMemLayer::DeleteFeature(nFID - (1 + bHasHeaderLine));
@@ -196,7 +197,7 @@ OGRODSDataSource::OGRODSDataSource()
 OGRODSDataSource::~OGRODSDataSource()
 
 {
-    SyncToDisk();
+    FlushCache();
 
     CPLFree( pszName );
 
@@ -273,7 +274,8 @@ int OGRODSDataSource::Open( const char * pszFilename,
 /*                             Create()                                 */
 /************************************************************************/
 
-int OGRODSDataSource::Create( const char * pszFilename, CPL_UNUSED char **papszOptions )
+int OGRODSDataSource::Create( const char * pszFilename,
+                              CPL_UNUSED char **papszOptions )
 {
     bUpdated = TRUE;
     bUpdatable = TRUE;
@@ -426,7 +428,13 @@ OGRFieldType OGRODSDataSource::GetOGRFieldType(const char* pszValue,
              strcmp(pszValueType, "currency") == 0)
     {
         if (CPLGetValueType(pszValue) == CPL_VALUE_INTEGER)
-            return OFTInteger;
+        {
+            GIntBig nVal = CPLAtoGIntBig(pszValue);
+            if( (GIntBig)(int)nVal != nVal )
+                return OFTInteger64;
+            else
+                return OFTInteger;
+        }
         else
             return OFTReal;
     }
@@ -481,14 +489,10 @@ static void SetField(OGRFeature* poFeature,
     }
     else if (eType == OFTDate || eType == OFTDateTime)
     {
-        int nYear, nMonth, nDay, nHour, nMinute, nTZ;
-        float fCur;
-        if (OGRParseXMLDateTime( pszValue,
-                                 &nYear, &nMonth, &nDay,
-                                 &nHour, &nMinute, &fCur, &nTZ) )
+        OGRField sField;
+        if (OGRParseXMLDateTime( pszValue, &sField ))
         {
-            poFeature->SetField(i, nYear, nMonth, nDay,
-                                nHour, nMinute, (int)fCur, nTZ);
+            poFeature->SetField(i, &sField);
         }
     }
     else
@@ -885,10 +889,14 @@ void OGRODSDataSource::endElementRow(CPL_UNUSED const char *pszName)
                         {
                             /* ok */
                         }
-                        else if (eFieldType == OFTReal && eValType == OFTInteger)
+                        else if (eFieldType == OFTReal && (eValType == OFTInteger || eValType == OFTInteger64))
                         {
                            /* ok */;
                         }
+                        else if (eFieldType == OFTInteger64 && eValType == OFTInteger )
+                        {
+                            /* ok */;
+                        }
                         else if (eFieldType != OFTString && eValType != eFieldType)
                         {
                             OGRFieldDefn oNewFieldDefn(
@@ -896,9 +904,11 @@ void OGRODSDataSource::endElementRow(CPL_UNUSED const char *pszName)
                             if ((eFieldType == OFTDate || eFieldType == OFTTime) &&
                                    eValType == OFTDateTime)
                                 oNewFieldDefn.SetType(OFTDateTime);
-                            else if (eFieldType == OFTInteger &&
+                            else if ((eFieldType == OFTInteger || eFieldType == OFTInteger64) &&
                                      eValType == OFTReal)
                                 oNewFieldDefn.SetType(OFTReal);
+                            else if( eFieldType == OFTInteger && eValType == OFTInteger64 )
+                                oNewFieldDefn.SetType(OFTInteger64);
                             else
                                 oNewFieldDefn.SetType(OFTString);
                             poCurLayer->AlterFieldDefn(i, &oNewFieldDefn,
@@ -1203,15 +1213,14 @@ void OGRODSDataSource::AnalyseSettings()
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRODSDataSource::CreateLayer( const char * pszLayerName,
-                               CPL_UNUSED OGRSpatialReference *poSRS,
-                               CPL_UNUSED OGRwkbGeometryType eType,
-                               char ** papszOptions )
-
+OGRODSDataSource::ICreateLayer( const char * pszLayerName,
+                                CPL_UNUSED OGRSpatialReference *poSRS,
+                                CPL_UNUSED OGRwkbGeometryType eType,
+                                char ** papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Verify we are in update mode.                                   */
@@ -1427,27 +1436,46 @@ static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
                                 "office:value=\"%d\"/>\n",
                                 poFeature->GetFieldAsInteger(j));
                 }
+                else if (eType == OFTInteger64)
+                {
+                    VSIFPrintfL(fp, "<table:table-cell office:value-type=\"float\" "
+                                "office:value=\"" CPL_FRMT_GIB "\"/>\n",
+                                poFeature->GetFieldAsInteger64(j));
+                }
                 else if (eType == OFTDateTime)
                 {
-                    int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
+                    int nYear, nMonth, nDay, nHour, nMinute, nTZFlag;
+                    float fSecond;
                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
-                                                    &nHour, &nMinute, &nSecond, &nTZFlag);
-                    VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDateTime\" "
-                                "office:value-type=\"date\" "
-                                "office:date-value=\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
-                                nYear, nMonth, nDay, nHour, nMinute, nSecond);
-                    VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
-                                nDay, nMonth, nYear, nHour, nMinute, nSecond);
+                                                    &nHour, &nMinute, &fSecond, &nTZFlag );
+                    if( OGR_GET_MS(fSecond) )
+                    {
+                        VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDateTimeMilliseconds\" "
+                                    "office:value-type=\"date\" "
+                                    "office:date-value=\"%04d-%02d-%02dT%02d:%02d:%06.3f\">\n",
+                                    nYear, nMonth, nDay, nHour, nMinute, fSecond);
+                        VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%06.3f</text:p>\n",
+                                    nDay, nMonth, nYear, nHour, nMinute, fSecond);
+                    }
+                    else
+                    {
+                        VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDateTime\" "
+                                    "office:value-type=\"date\" "
+                                    "office:date-value=\"%04d-%02d-%02dT%02d:%02d:%02d\">\n",
+                                    nYear, nMonth, nDay, nHour, nMinute, (int)fSecond);
+                        VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d %02d:%02d:%02d</text:p>\n",
+                                    nDay, nMonth, nYear, nHour, nMinute, (int)fSecond);
+                    }
                     VSIFPrintfL(fp, "</table:table-cell>\n");
                 }
-                else if (eType == OFTDateTime)
+                else if (eType == OFTDate)
                 {
                     int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
                                                     &nHour, &nMinute, &nSecond, &nTZFlag);
                     VSIFPrintfL(fp, "<table:table-cell table:style-name=\"stDate\" "
                                 "office:value-type=\"date\" "
-                                "office:date-value=\"%04d-%02d-%02dT\">\n",
+                                "office:date-value=\"%04d-%02d-%02d\">\n",
                                 nYear, nMonth, nDay);
                     VSIFPrintfL(fp, "<text:p>%02d/%02d/%04d</text:p>\n",
                                 nDay, nMonth, nYear);
@@ -1498,13 +1526,13 @@ static void WriteLayer(VSILFILE* fp, OGRLayer* poLayer)
 }
 
 /************************************************************************/
-/*                            SyncToDisk()                              */
+/*                            FlushCache()                              */
 /************************************************************************/
 
-OGRErr OGRODSDataSource::SyncToDisk()
+void OGRODSDataSource::FlushCache()
 {
     if (!bUpdated)
-        return OGRERR_NONE;
+        return;
 
     CPLAssert(fpSettings == NULL);
     CPLAssert(fpContent == NULL);
@@ -1516,7 +1544,7 @@ OGRErr OGRODSDataSource::SyncToDisk()
         {
             CPLError(CE_Failure, CPLE_FileIO,
                     "Cannot delete %s", pszName);
-            return OGRERR_FAILURE;
+            return;
         }
     }
 
@@ -1526,16 +1554,25 @@ OGRErr OGRODSDataSource::SyncToDisk()
     {
         CPLError(CE_Failure, CPLE_FileIO,
                  "Cannot create %s", pszName);
-        return OGRERR_FAILURE;
+        return;
     }
 
     /* Write uncopressed mimetype */
     char** papszOptions = CSLAddString(NULL, "COMPRESSED=NO");
-    CPLCreateFileInZip(hZIP, "mimetype", papszOptions );
-    CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
-                      strlen("application/vnd.oasis.opendocument.spreadsheet"));
-    CPLCloseFileInZip(hZIP);
+    if( CPLCreateFileInZip(hZIP, "mimetype", papszOptions ) != CE_None )
+    {
+        CSLDestroy(papszOptions);
+        CPLCloseZip(hZIP);
+        return;
+    }
     CSLDestroy(papszOptions);
+    if( CPLWriteFileInZip(hZIP, "application/vnd.oasis.opendocument.spreadsheet",
+                      strlen("application/vnd.oasis.opendocument.spreadsheet")) != CE_None )
+    {
+        CPLCloseZip(hZIP);
+        return;
+    }
+    CPLCloseFileInZip(hZIP);
 
     /* Now close ZIP file */
     CPLCloseZip(hZIP);
@@ -1544,7 +1581,7 @@ OGRErr OGRODSDataSource::SyncToDisk()
     /* Re-open with VSILFILE */
     VSILFILE* fpZIP = VSIFOpenL(CPLSPrintf("/vsizip/%s", pszName), "ab");
     if (fpZIP == NULL)
-        return OGRERR_FAILURE;
+        return;
 
     VSILFILE* fp;
     int i;
@@ -1679,6 +1716,19 @@ OGRErr OGRODSDataSource::SyncToDisk()
     VSIFPrintfL(fp, "<number:text>:</number:text>\n");
     VSIFPrintfL(fp, "<number:seconds number:style=\"long\"/>\n");
     VSIFPrintfL(fp, "</number:date-style>\n");
+    VSIFPrintfL(fp, "<number:date-style style:name=\"nDateTimeMilliseconds\">\n");
+    VSIFPrintfL(fp, "<number:day number:style=\"long\"/>\n");
+    VSIFPrintfL(fp, "<number:text>/</number:text>\n");
+    VSIFPrintfL(fp, "<number:month number:style=\"long\"/>\n");
+    VSIFPrintfL(fp, "<number:text>/</number:text>\n");
+    VSIFPrintfL(fp, "<number:year number:style=\"long\"/>\n");
+    VSIFPrintfL(fp, "<number:text> </number:text>\n");
+    VSIFPrintfL(fp, "<number:hours number:style=\"long\"/>\n");
+    VSIFPrintfL(fp, "<number:text>:</number:text>\n");
+    VSIFPrintfL(fp, "<number:minutes number:style=\"long\"/>\n");
+    VSIFPrintfL(fp, "<number:text>:</number:text>\n");
+    VSIFPrintfL(fp, "<number:seconds number:style=\"long\" number:decimal-places=\"3\"/>\n");
+    VSIFPrintfL(fp, "</number:date-style>\n");
     VSIFPrintfL(fp, "<style:style style:name=\"stDate\" "
                     "style:family=\"table-cell\" "
                     "style:parent-style-name=\"Default\" "
@@ -1691,6 +1741,10 @@ OGRErr OGRODSDataSource::SyncToDisk()
                     "style:family=\"table-cell\" "
                     "style:parent-style-name=\"Default\" "
                     "style:data-style-name=\"nDateTime\"/>\n");
+    VSIFPrintfL(fp, "<style:style style:name=\"stDateTimeMilliseconds\" "
+                    "style:family=\"table-cell\" "
+                    "style:parent-style-name=\"Default\" "
+                    "style:data-style-name=\"nDateTimeMilliseconds\"/>\n");
     VSIFPrintfL(fp, "</office:automatic-styles>\n");
     VSIFPrintfL(fp, "<office:body>\n");
     VSIFPrintfL(fp, "<office:spreadsheet>\n");
@@ -1713,7 +1767,7 @@ OGRErr OGRODSDataSource::SyncToDisk()
         ((OGRODSLayer*)papoLayers[i])->SetUpdated(FALSE);
     }
 
-    return OGRERR_NONE;
+    return;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/ods/ogrodsdriver.cpp b/ogr/ogrsf_frmts/ods/ogrodsdriver.cpp
index 0986376..3cd8870 100644
--- a/ogr/ogrsf_frmts/ods/ogrodsdriver.cpp
+++ b/ogr/ogrsf_frmts/ods/ogrodsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrodsdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrodsdriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  ODS Translator
  * Purpose:  Implements OGRODSDriver.
@@ -30,7 +30,7 @@
 #include "ogr_ods.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrodsdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrodsdriver.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 extern "C" void RegisterOGRODS();
 
@@ -217,6 +217,14 @@ int OGRODSDriver::TestCapability( const char * pszCap )
 void RegisterOGRODS()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRODSDriver );
+    OGRSFDriver* poDriver = new OGRODSDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "Open Document/ LibreOffice / OpenOffice Spreadsheet " );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ods" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_ods.html" );
+    poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time Binary" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/ogdi/GNUmakefile b/ogr/ogrsf_frmts/ogdi/GNUmakefile
index 8c41d31..209bfa7 100644
--- a/ogr/ogrsf_frmts/ogdi/GNUmakefile
+++ b/ogr/ogrsf_frmts/ogdi/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrogdidriver.o ogrogdidatasource.o ogrogdilayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(OGDI_INCLUDE) $(PROJ_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	 $(OGDI_INCLUDE) $(PROJ_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdi.h b/ogr/ogrsf_frmts/ogdi/ogrogdi.h
index df38003..40597be 100644
--- a/ogr/ogrsf_frmts/ogdi/ogrogdi.h
+++ b/ogr/ogrsf_frmts/ogdi/ogrogdi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrogdi.h 26688 2013-12-02 19:07:41Z rouault $
+ * $Id: ogrogdi.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGDI Bridge
  * Purpose:  Private definitions within the OGDI driver to implement
@@ -72,11 +72,11 @@ class OGROGDILayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-    OGRFeature         *GetFeature( long nFeatureId );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
 
     OGRFeatureDefn *    GetLayerDefn() { return m_poFeatureDefn; }
 
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
 
     int                 TestCapability( const char * );
 
diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp
index 52ec817..e42041d 100644
--- a/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp
+++ b/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrogdidatasource.cpp 19711 2010-05-14 21:26:42Z rouault $
+ * $Id: ogrogdidatasource.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  OGDI Bridge
  * Purpose:  Implements OGROGDIDataSource class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrogdidatasource.cpp 19711 2010-05-14 21:26:42Z rouault $");
+CPL_CVSID("$Id: ogrogdidatasource.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 /************************************************************************/
 /*                         OGROGDIDataSource()                          */
@@ -267,7 +267,7 @@ void OGROGDIDataSource::IAddLayer( const char *pszLayerName,
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGROGDIDataSource::TestCapability( const char * pszCap )
+int OGROGDIDataSource::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp
index 89f0e6b..343ccc3 100644
--- a/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp
+++ b/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrogdidriver.cpp 16861 2009-04-26 19:22:29Z rouault $
+ * $Id: ogrogdidriver.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  OGDI Bridge
  * Purpose:  Implements OGROGDIDriver class.
@@ -31,7 +31,7 @@
 #include "ogrogdi.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrogdidriver.cpp 16861 2009-04-26 19:22:29Z rouault $");
+CPL_CVSID("$Id: ogrogdidriver.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 /************************************************************************/
 /*                           ~OGROGDIDriver()                           */
@@ -49,7 +49,7 @@ OGROGDIDriver::~OGROGDIDriver()
 const char *OGROGDIDriver::GetName()
 
 {
-    return "OGDI";
+    return "OGR_OGDI";
 }
 
 /************************************************************************/
@@ -62,6 +62,9 @@ OGRDataSource *OGROGDIDriver::Open( const char * pszFilename,
 {
     OGROGDIDataSource   *poDS;
 
+    if( !EQUALN(pszFilename,"gltp:",5) )
+        return FALSE;
+
     poDS = new OGROGDIDataSource();
 
     if( !poDS->Open( pszFilename, TRUE ) )
@@ -86,7 +89,7 @@ OGRDataSource *OGROGDIDriver::Open( const char * pszFilename,
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGROGDIDriver::TestCapability( const char * pszCap )
+int OGROGDIDriver::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
@@ -101,6 +104,11 @@ void RegisterOGROGDI()
 {
     if (! GDAL_CHECK_VERSION("OGR/OGDI driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGROGDIDriver );
+    OGRSFDriver* poDriver = new OGROGDIDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "OGDI Vectors (VPF, VMAP, DCW)" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_ogdi.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp
index 66bd3de..adad5f7 100644
--- a/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp
+++ b/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrogdilayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrogdilayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OGDI Bridge
  * Purpose:  Implements OGROGDILayer class.
@@ -57,7 +57,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrogdilayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrogdilayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                           OGROGDILayer()                            */
@@ -391,7 +391,7 @@ OGRFeature *OGROGDILayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGROGDILayer::GetFeature( long nFeatureId )
+OGRFeature *OGROGDILayer::GetFeature( GIntBig nFeatureId )
 
 {
     ecs_Result  *psResult;
@@ -451,7 +451,7 @@ OGRFeature *OGROGDILayer::GetFeature( long nFeatureId )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGROGDILayer::GetFeatureCount( int bForce )
+GIntBig OGROGDILayer::GetFeatureCount( int bForce )
 
 {
     if( m_nTotalShapeCount == -1)
@@ -553,6 +553,7 @@ void OGROGDILayer::BuildFeatureDefn()
                                                     pszGeomName ));
 
     m_poFeatureDefn = new OGRFeatureDefn(pszFeatureDefnName);
+    SetDescription( m_poFeatureDefn->GetName() );
     CPLFree(pszFeatureDefnName);
     pszFeatureDefnName = NULL;
     
diff --git a/ogr/ogrsf_frmts/ogr_attrind.h b/ogr/ogrsf_frmts/ogr_attrind.h
index f509ae2..b2d8f2d 100644
--- a/ogr/ogrsf_frmts/ogr_attrind.h
+++ b/ogr/ogrsf_frmts/ogr_attrind.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_attrind.h 20101 2010-07-18 15:20:35Z tamas $
+ * $Id: ogr_attrind.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Classes related to generic implementation of attribute indexing.
@@ -46,12 +46,12 @@ protected:
 public:
     virtual     ~OGRAttrIndex();
 
-    virtual long   GetFirstMatch( OGRField *psKey ) = 0;
-    virtual long  *GetAllMatches( OGRField *psKey ) = 0;
-    virtual long  *GetAllMatches( OGRField *psKey, long* panFIDList, int* nFIDCount, int* nLength ) = 0;
+    virtual GIntBig   GetFirstMatch( OGRField *psKey ) = 0;
+    virtual GIntBig  *GetAllMatches( OGRField *psKey ) = 0;
+    virtual GIntBig  *GetAllMatches( OGRField *psKey, GIntBig* panFIDList, int* nFIDCount, int* nLength ) = 0;
     
-    virtual OGRErr AddEntry( OGRField *psKey, long nFID ) = 0;
-    virtual OGRErr RemoveEntry( OGRField *psKey, long nFID ) = 0;
+    virtual OGRErr AddEntry( OGRField *psKey, GIntBig nFID ) = 0;
+    virtual OGRErr RemoveEntry( OGRField *psKey, GIntBig nFID ) = 0;
 
     virtual OGRErr Clear() = 0;
 };
diff --git a/ogr/ogrsf_frmts/ogr_formats.html b/ogr/ogrsf_frmts/ogr_formats.html
index dd8eca5..6abd9bc 100644
--- a/ogr/ogrsf_frmts/ogr_formats.html
+++ b/ogr/ogrsf_frmts/ogr_formats.html
@@ -80,11 +80,12 @@
 </td><td> No, needs libcurl
 </td></tr>
 
-<tr><td> <a href="drv_csv.html">Comma Separated Value (.csv)</a>
-</td><td> CSV
+
+<tr><td><a href="drv_cloudant.html">Cloudant / CouchDB</a>
+</td><td> Cloudant
 </td><td> Yes
-</td><td> No
 </td><td> Yes
+</td><td> No, needs libcurl
 </td></tr>
 
 <tr><td> <a href="drv_couchdb.html">CouchDB / GeoCouch</a>
@@ -94,6 +95,20 @@
 </td><td> No, needs libcurl
 </td></tr>
 
+<tr><td> <a href="drv_csv.html">Comma Separated Value (.csv)</a>
+</td><td> CSV
+</td><td> Yes
+</td><td> No
+</td><td> Yes
+</td></tr>
+
+<tr><td> <a href="drv_csw.html">OGC CSW (Catalog Service for the Web)</a>
+</td><td> CSW
+</td><td> No
+</td><td> Yes
+</td><td> No, needs libcurl
+</td></tr>
+
 <tr><td> <a href="drv_vfk.html">Czech Cadastral Exchange Data Format</a>
 </td><td> VFK
 </td><td> No
@@ -274,7 +289,7 @@
 </td><td> "Interlis 1" and "Interlis 2"
 </td><td> Yes
 </td><td> Yes
-</td><td> No, needs Xerces (INTERLIS model reading needs ili2c.jar)
+</td><td> No, needs Xerces
 </td></tr>
 
 <tr><td> <a href="drv_ingres.html">INGRES</a>
@@ -284,6 +299,13 @@
 </td><td> No, needs INGRESS
 </td></tr>
 
+<tr><td> <a href="drv_jml.html">JML</a>
+</td><td> OpenJUMP .jml
+</td><td> Yes
+</td><td> No
+</td><td> Yes (read support needs libexpat)
+</td></tr>
+
 <tr><td> <a href="drv_kml.html">KML</a>
 </td><td> KML
 </td><td> Yes
@@ -396,14 +418,14 @@
 </td><td> No, needs libsqlite3 (and libexpat for OSM XML)
 </td></tr>
 
-<tr><td> PCI Geomatics Database File
+<tr><td> <a href="../frmt_pcidsk.html">PCI Geomatics Database File</a>
 </td><td> PCIDSK
-</td><td> No
-</td><td> No
+</td><td> Yes
+</td><td> Yes
 </td><td> Yes, using internal PCIDSK SDK (from GDAL 1.7.0)
 </td></tr>
 
-<tr><td> <a href="drv_pdf.html">Geospatial PDF</a>
+<tr><td> <a href="../frmt_pdf.html">Geospatial PDF</a>
 </td><td> PDF
 </td><td> Yes
 </td><td> Yes
@@ -417,6 +439,13 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> <a href="drv_plscenes.html">Planet Labs Scenes API</a>
+</td><td> PLScenes
+</td><td> No
+</td><td> Yes
+</td><td> No, needs libcurl
+</td></tr>
+
 <tr><td> <a href="drv_pgdump.html">PostgreSQL SQL dump</a>
 </td><td> PGDump
 </td><td> Yes
@@ -466,6 +495,13 @@
 </td><td> Yes
 </td></tr>
 
+<tr><td> <a href="drv_selafin.html">Selafin/Seraphin format</a>
+</td><td> Selafin
+</td><td> Yes
+</td><td> Partial (only EPSG code)
+</td><td> Yes
+</td></tr>
+
 <tr><td> <a href="http://trac.osgeo.org/gdal/ticket/3638">Norwegian SOSI Standard</a>
 </td><td> SOSI
 </td><td> No
diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.dox b/ogr/ogrsf_frmts/ogrsf_frmts.dox
index cdfc864..1d22ff1 100644
--- a/ogr/ogrsf_frmts/ogrsf_frmts.dox
+++ b/ogr/ogrsf_frmts/ogrsf_frmts.dox
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsf_frmts.dox 27110 2014-03-28 21:29:20Z rouault $
+ * $Id: ogrsf_frmts.dox 29035 2015-04-27 12:38:54Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Documentation for ogrsf_frmts.h classes.
@@ -33,66 +33,13 @@
 
 /**
  
-  \fn OGRDataSource *OGRSFDriverRegistrar::Open( const char *pszName, int bUpdate = FALSE, OGRSFDriver **ppoDriver=NULL);
-
-  \brief Open a file / data source with one of the registered drivers.
-
-  This method loops through all the drivers registered with the driver
-  manager trying each until one succeeds with the given data source.  This
-  method is static.  Applications don't normally need to use any other
-  OGRSFDriverRegistrar methods directly, nor do they normally need to have
-  a pointer to an OGRSFDriverRegistrar instance.
-
-  If this method fails, CPLGetLastErrorMsg() can be used to check if there
-  is an error message explaining why.
-
-  For drivers supporting the VSI virtual file API, it is possible to open
-  a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive
-  (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler())
- 
-  This method is the same as the C function OGROpen().
-
-  @param pszName the name of the file, or data source to open. UTF-8 encoded.
-  @param bUpdate FALSE for read-only access (the default) or TRUE for 
-         read-write access.
-  @param ppoDriver if non-NULL, this argument will be updated with a 
-         pointer to the driver which was used to open the data source.
-
-  @return NULL on error or if the pass name is not supported by this driver,
-  otherwise a pointer to an OGRDataSource.  This OGRDataSource should be
-  closed by deleting the object when it is no longer needed.
-
-  <b>Example:</b>
-
-  <pre>
-    OGRDataSource	*poDS;
-
-    poDS = OGRSFDriverRegistrar::Open( "polygon.shp" );
-    if( poDS == NULL )
-    {
-        return;
-    }
-
-    ... use the data source ...
-
-    OGRDataSource::DestroyDataSource(poDS);
-  </pre>
-
-*/
-
-
-/**
- 
   \fn OGRDataSourceH OGROpen( const char *pszName, int bUpdate,
                         OGRSFDriverH *pahDriverList );
 
   \brief Open a file / data source with one of the registered drivers.
 
   This function loops through all the drivers registered with the driver
-  manager trying each until one succeeds with the given data source.  This
-  function is static.  Applications don't normally need to use any other
-  OGRSFDriverRegistrar function, not do they normally need to have
-  a pointer to an OGRSFDriverRegistrar instance.
+  manager trying each until one succeeds with the given data source.
 
   If this function fails, CPLGetLastErrorMsg() can be used to check if there
   is an error message explaining why.
@@ -101,7 +48,12 @@
   a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive
   (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler())
 
-  This function is the same as the C++ method OGRSFDriverRegistrar::Open().
+  NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned handle to
+  OGRDataSource*. If a C++ object is needed, the handle should be cast to GDALDataset*.
+  Similarly, the returned OGRSFDriverH handle should be cast to GDALDriver*, and
+  *NOT* OGRSFDriver*.
+
+  @deprecated Use GDALOpenEx() in GDAL 2.0
 
   @param pszName the name of the file, or data source to open.
   @param bUpdate FALSE for read-only access (the default) or TRUE for 
@@ -110,7 +62,7 @@
          pointer to the driver which was used to open the data source.
 
   @return NULL on error or if the pass name is not supported by this driver,
-  otherwise an handle to an OGRDataSource.  This OGRDataSource should be
+  otherwise an handle to a GDALDataset.  This GDALDataset should be
   closed by deleting the object when it is no longer needed.
 
   <b>Example:</b>
@@ -133,93 +85,12 @@
 */
 
 /**
-  \fn OGRSFDriverRegistrar *OGRSFDriverRegistrar::GetRegistrar();
-
-  \brief Return the driver manager, creating one if none exist. 
-
-  @return the driver manager.
-
-*/
-
-/** 
-  \fn void OGRSFDriverRegistrar::RegisterDriver( OGRSFDriver * poDriver );
-  
-  \brief Add a driver to the list of registered drivers.
-
-  If the passed driver is already registered (based on pointer comparison) 
-  then the driver isn't registered.  New drivers are added at the end of
-  the list of registered drivers.
-
-  This method is the same as the C function OGRRegisterDriver().
-
-  @param poDriver the driver to add.
-
-*/
-
-
-/** 
-  \fn void OGRRegisterDriver( OGRSFDriverH hDriver );
-  
-  \brief Add a driver to the list of registered drivers.
-
-  If the passed driver is already registered (based on handle comparison) 
-  then the driver isn't registered.  New drivers are added at the end of
-  the list of registered drivers.
-
-  This function is the same as the C++ method 
-  OGRSFDriverRegistrar::RegisterDriver().
-
-  @param hDriver handle to the driver to add.
-
-*/
-
-
-/** 
-  \fn void OGRSFDriverRegistrar::DeregisterDriver( OGRSFDriver * poDriver );
-  
-  \brief Remove the passed driver from the list of registered drivers.
-
-  This method is the same as the C function OGRDeregisterDriver().
-
-  @param poDriver the driver to deregister.
-
-  @since GDAL 1.8.0
-*/
-
-
-/** 
-  \fn void OGRDeregisterDriver( OGRSFDriverH hDriver );
-  
-  \brief Remove the passed driver from the list of registered drivers.
-
-  This function is the same as the C++ method 
-  OGRSFDriverRegistrar::DeregisterDriver().
-
-  @param hDriver handle to the driver to deregister.
-
-  @since GDAL 1.8.0
-*/
-
-/**
-
-  \fn int OGRSFDriverRegistrar::GetDriverCount();
-
-  \brief Fetch the number of registered drivers.
-
-  This method is the same as the C function OGRGetDriverCount().
-
-  @return the drivers count.
-
-*/
-
-/**
 
   \fn int OGRGetDriverCount();
 
   \brief Fetch the number of registered drivers.
 
-  This function is the same as the C++ method 
-  OGRSFDriverRegistrar::GetDriverCount().
+  @deprecated Use GDALGetDriverCount() in GDAL 2.0
 
   @return the drivers count.
 
@@ -227,26 +98,14 @@
 
 /**
  
-  \fn OGRSFDriver *OGRSFDriverRegistrar::GetDriver( int iDriver );
-
-  \brief Fetch the indicated driver.
-
-  This method is the same as the C function OGRGetDriver().
-
-  @param iDriver the driver index, from 0 to GetDriverCount()-1.
-
-  @return the driver, or NULL if iDriver is out of range.
-
-*/
-
-/**
- 
   \fn OGRSFDriverH OGRGetDriver( int iDriver );
 
   \brief Fetch the indicated driver.
 
-  This function is the same as the C++ method 
-  OGRSFDriverRegistrar::GetDriver().
+  NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned handle to
+  OGRSFDriver*. If a C++ object is needed, the handle should be cast to GDALDriver*.
+
+  @deprecated Use GDALGetDriver() in GDAL 2.0
 
   @param iDriver the driver index, from 0 to GetDriverCount()-1.
 
@@ -255,23 +114,14 @@
 */
 
 /**
-  \fn OGRSFDriver *OGRSFDriverRegistrar::GetDriverByName( const char * pszName );
-
-  \brief Fetch the indicated driver.
-
-  This method is the same as the C function OGRGetDriverByName
-
-  @param pszName the driver name
-
-  @return the driver, or NULL if no driver with that name is found
-*/
-
-/**
   \fn OGRSFDriverH OGRGetDriverByName( const char *pszName );
 
   \brief Fetch the indicated driver.
 
-  This function is the same as the C++ method OGRSFDriverRegistrar::GetDriverByName()
+  NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned handle to
+  OGRSFDriver*. If a C++ object is needed, the handle should be cast to GDALDriver*.
+
+  @deprecated Use GDALGetDriverByName() in GDAL 2.0
 
   @param pszName the driver name
 
@@ -279,74 +129,18 @@
 */
 
 /**
-  \fn int OGRSFDriverRegistrar::GetOpenDSCount();
-
-  \brief Return the number of opened datasources.
-
-  This method is the same as the C function OGRGetOpenDSCount()
-
-  @return the number of opened datasources.
-*/
-
-/**
-  \fn int OGRGetOpenDSCount();
-
-  \brief Return the number of opened datasources.
-
-  This function is the same as the C++ method OGRSFDriverRegistrar::GetOpenDSCount()
-
-  @return the number of opened datasources.
-*/
-
-/**
-  \fn OGRDataSource *OGRSFDriverRegistrar::GetOpenDS( int iDS )
-
-  \brief Return the iDS th datasource opened.
-
-  This method is the same as the C function OGRGetOpenDS().
-
-  @param iDS the index of the dataset to return (between 0 and GetOpenDSCount() - 1)
-*/
-
-/**
-  \fn OGRDataSourceH OGRGetOpenDS( int iDS )
-
-  \brief Return the iDS th datasource opened.
-
-  This function is the same as the C++ method OGRSFDriverRegistrar::GetOpenDS.
-
-  @param iDS the index of the dataset to return (between 0 and GetOpenDSCount() - 1)
-*/
-
-/**
 
   \fn int OGRRegisterAll();
 
   \brief Register all drivers.
 
+   @deprecated Use GDALAllRegister() in GDAL 2.0
 */
 
 /************************************************************************/
 /*                             OGRSFDriver                              */
 /************************************************************************/
 
-
-/** 
-
-  \fn const char *OGRSFDriver::GetName();
-
-  \brief Fetch name of driver (file format).
-  This name should be relatively short
-  (10-40 characters), and should reflect the underlying file format.  For
-  instance "ESRI Shapefile".
-
-  This method is the same as the C function OGR_Dr_GetName().
-
-  @return driver name.  This is an internal string and should not be modified
-  or freed. 
-*/
-
-
 /** 
 
   \fn const char *OGR_Dr_GetName( OGRSFDriverH hDriver );
@@ -365,44 +159,17 @@
 
 /**
 
-  \fn OGRDataSource *OGRSFDriver::Open( const char *pszName, int bUpdate );
-
-  \brief Attempt to open file with this driver. 
-
-  This method is what OGRSFDriverRegistrar uses to implement its Open() 
-  method.  See it for more details.
-
-  Note, drivers do not normally set their own m_poDriver value, so a direct
-  call to this method (instead of indirectly via OGRSFDriverRegistrar) will
-  usually result in a datasource that does not know what driver it relates to
-  if GetDriver() is called on the datasource.  The application may directly
-  call SetDriver() after opening with this method to avoid this problem.
-
-  For drivers supporting the VSI virtual file API, it is possible to open
-  a file in a .zip archive (see VSIInstallZipFileHandler()), in a .tar/.tar.gz/.tgz archive
-  (see VSIInstallTarFileHandler()) or on a HTTP / FTP server (see VSIInstallCurlFileHandler())
-
-  This method is the same as the C function OGR_Dr_Open().
-
-  @param pszName the name of the file, or data source to try and open.
-  @param bUpdate TRUE if update access is required, otherwise FALSE (the
-  default).
-
-  @return NULL on error or if the pass name is not supported by this driver,
-  otherwise a pointer to an OGRDataSource.  This OGRDataSource should be
-  closed by deleting the object when it is no longer needed.
-
-*/
-
-
-/**
-
   \fn OGRDataSourceH OGR_Dr_Open( OGRSFDriverH hDriver, const char *pszName, 
                             int bUpdate );
 
   \brief Attempt to open file with this driver. 
 
-  This function is the same as the C++ method OGRSFDriver::Open().
+  NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned handle to
+  OGRDataSource*. If a C++ object is needed, the handle should be cast to GDALDataset*.
+  Similarly, the returned OGRSFDriverH handle should be cast to GDALDriver*, and
+  *NOT* OGRSFDriver*.
+
+  @deprecated Use GDALOpenEx() in GDAL 2.0
 
   @param hDriver handle to the driver that is used to open file.
   @param pszName the name of the file, or data source to try and open.
@@ -410,37 +177,12 @@
   default).
 
   @return NULL on error or if the pass name is not supported by this driver,
-  otherwise an handle to an OGRDataSource.  This OGRDataSource should be
+  otherwise an handle to a GDALDataset.  This GDALDataset should be
   closed by deleting the object when it is no longer needed.
 
 */
 
 /**
- \fn int OGRSFDriver::TestCapability( const char *pszCapability );
-
- \brief Test if capability is available.
-
- One of the following data source capability names can be passed into this
- method, and a TRUE or FALSE value will be returned indicating whether or not
- the capability is available for this object.
-
- <ul>
-  <li> <b>ODrCCreateDataSource</b>: True if this driver can support creating data sources.<p>
-  <li> <b>ODrCDeleteDataSource</b>: True if this driver supports deleting data sources.<p>
- </ul>
-
- The \#define macro forms of the capability names should be used in preference
- to the strings themselves to avoid mispelling.
-
- This method is the same as the C function OGR_Dr_TestCapability().
-
- @param pszCapability the capability to test.
-
- @return TRUE if capability available otherwise FALSE.
-*/ 
-
-
-/**
  \fn int OGR_Dr_TestCapability( OGRSFDriverH hDriver, const char *pszCap );
 
  \brief Test if capability is available.
@@ -457,7 +199,7 @@
  The \#define macro forms of the capability names should be used in preference
  to the strings themselves to avoid mispelling.
 
- This function is the same as the C++ method OGRSFDriver::TestCapability().
+ @deprecated Use GDALGetMetadataItem(hDriver, GDAL_DCAP_CREATE) in GDAL 2.0
 
  @param hDriver handle to the driver to test the capability against.
  @param pszCap the capability to test.
@@ -467,25 +209,6 @@
 */ 
 
 /**
- \fn OGRErr OGRSFDriver::DeleteDataSource( const char *pszDataSource );
-
- \brief Delete a datasource.
-
- Delete (from the disk, in the database, ...) the named datasource.
- Normally it would be safest if the datasource was not open at the time. 
-
- Whether this is a supported operation on this driver case be tested
- using TestCapability() on ODrCDeleteDataSource.
-
- This method is the same as the C function OGR_Dr_DeleteDataSource().
-
- @param pszDataSource the name of the datasource to delete. 
-
- @return OGRERR_NONE on success, and OGRERR_UNSUPPORTED_OPERATION if this
- is not supported by this driver. 
-*/
-
-/**
  \fn OGRErr OGR_Dr_DeleteDataSource( OGRSFDriverH hDriver, 
                                 const char *pszDataSource )
 
@@ -497,7 +220,7 @@
  Whether this is a supported operation on this driver case be tested
  using TestCapability() on ODrCDeleteDataSource.
 
- This method is the same as the C++ method OGRSFDriver::DeleteDataSource().
+ @deprecated Use GDALDeleteDataset() in GDAL 2
 
  @param hDriver handle to the driver on which data source deletion is
 based.
@@ -509,36 +232,6 @@ based.
 
 */
 
-/**
- \fn OGRDataSource *OGRSFDriver::CreateDataSource( const char *pszName, 
-                                        char ** papszOptions );
-
- \brief This method attempts to create a new data source based on the passed driver.
-
- The papszOptions argument can be used to control driver specific
- creation options.  These options are normally documented in the format
- specific documentation. 
-
- It is important to call OGRDataSource::DestroyDataSource() when the datasource is no longer
- used to ensure that all data has been properly flushed to disk.
-
- This method is the same as the C function OGR_Dr_CreateDataSource().
-
- \note This method does <strong>NOT</strong> attach driver instance to the 
- returned  data source, so caller should expect that OGRDataSource::GetDriver()
- will return NULL pointer. In order to attach driver to the returned data 
- source, it is required to use C function OGR_Dr_CreateDataSource.
- This behavior is related to fix of issue reported in <a href="http://trac.osgeo.org/gdal/ticket/1223">Ticket #1233</a>. 
-
- @param pszName the name for the new data source. UTF-8 encoded.
- @param papszOptions a StringList of name=value options.  Options are driver
-specific, and driver information can be found at the following url:  
-http://www.gdal.org/ogr/ogr_formats.html 
-
- @return NULL is returned on failure, or a new OGRDataSource on 
-success. 
-*/
-
 /** 
 
   \fn OGRDataSourceH OGR_Dr_CreateDataSource( OGRSFDriverH hDriver,
@@ -554,7 +247,7 @@ success.
  It is important to call OGR_DS_Destroy() when the datasource is no longer
  used to ensure that all data has been properly flushed to disk.
 
- This function is the same as the C++ method OGRSFDriver::CreateDataSource().
+ @deprecated Use GDALCreate() in GDAL 2.0
 
  @param hDriver handle to the driver on which data source creation is
 based.
@@ -567,30 +260,6 @@ http://www.gdal.org/ogr/ogr_formats.html
 success. 
 */
 
-
-/**
-
-   \fn OGRDataSource *OGRSFDriver::CopyDataSource( OGRDataSource *poSrcDS, 
-                                            const char *pszNewName,
-                                            char **papszOptions )
-
-   \brief This method creates a new datasource by copying all the layers from the source datasource.
-
-   It is important to call OGRDataSource::DestroyDataSource() when the datasource is no longer
-   used to ensure that all data has been properly flushed to disk.
-
-   This method is the same as the C function OGR_Dr_CopyDataSource().
-
- @param poSrcDS source datasource
- @param pszNewName the name for the new data source. UTF-8 encoded.
- @param papszOptions a StringList of name=value options.  Options are driver
-specific, and driver information can be found at the following url:  
-http://www.gdal.org/ogr/ogr_formats.html 
-
- @return NULL is returned on failure, or a new OGRDataSource handle on 
-success. 
-*/
-
 /**
 
    \fn OGRDataSourceH OGR_Dr_CopyDataSource( OGRSFDriverH hDriver, 
@@ -603,7 +272,7 @@ success.
    It is important to call OGR_DS_Destroy() when the datasource is no longer
    used to ensure that all data has been properly flushed to disk.
 
-   This function is the same as the C++ method OGRSFDriver::CopyDataSource().
+   @deprecated Use GDALCreateCopy() in GDAL 2.0
 
  @param hDriver handle to the driver on which data source creation is
 based.
@@ -628,24 +297,9 @@ success.
 
    This method is the same as the C++ method OGRDataSource::DestroyDataSource().
 
-  @param hDataSource handle to allocated datasource object.
-*/
-
-/** 
- \fn const char *OGRDataSource::GetName();
-
- \brief Returns the name of the data source.
-
- This string should be sufficient to
- open the data source if passed to the same OGRSFDriver that this data
- source was opened with, but it need not be exactly the same string that
- was used to open the data source.  Normally this is a filename. 
-
- This method is the same as the C function OGR_DS_GetName().
-
- @return pointer to an internal name string which should not be modified
- or freed by the caller.
+  @deprecated Use GDALClose() in GDAL 2.0
 
+  @param hDataSource handle to allocated datasource object.
 */
 
 /** 
@@ -658,7 +312,7 @@ success.
  source was opened with, but it need not be exactly the same string that
  was used to open the data source.  Normally this is a filename. 
 
- This function is the same as the C++ method OGRDataSource::GetName().
+ @deprecated Use GDALGetDescription() in GDAL 2.0
 
  @param hDS handle to the data source to get the name from.
  @return pointer to an internal name string which should not be modified
@@ -666,24 +320,13 @@ success.
 
 */
 
-/**
- \fn int OGRDataSource::GetLayerCount();
-
- \brief Get the number of layers in this data source.
-
- This method is the same as the C function OGR_DS_GetLayerCount().
-
- @return layer count.
-
-*/
-
 
 /**
  \fn int OGR_DS_GetLayerCount( OGRDataSourceH hDS );
 
  \brief Get the number of layers in this data source.
 
- This function is the same as the C++ method OGRDataSource::GetLayerCount().
+ @deprecated Use GDALDatasetGetLayerCount() in GDAL 2.0
 
  @param hDS handle to the data source from which to get the number of layers.
  @return layer count.
@@ -691,23 +334,6 @@ success.
 */
 
 /**
- \fn OGRLayer *OGRDataSource::GetLayer(int iLayer);
-
- \brief Fetch a layer by index.
-
- The returned layer remains owned by the 
- OGRDataSource and should not be deleted by the application.
-
- This method is the same as the C function OGR_DS_GetLayer().
-
- @param iLayer a layer number between 0 and GetLayerCount()-1.
-
- @return the layer, or NULL if iLayer is out of range or an error occurs.
-
-*/
-
-
-/**
  \fn OGRLayerH OGR_DS_GetLayer( OGRDataSourceH hDS, int iLayer );
 
  \brief Fetch a layer by index.
@@ -715,7 +341,7 @@ success.
  The returned layer remains owned by the 
  OGRDataSource and should not be deleted by the application.
 
- This function is the same as the C++ method OGRDataSource::GetLayer().
+ @deprecated Use GDALDatasetGetLayer() in GDAL 2.0
 
  @param hDS handle to the data source from which to get the layer.
  @param iLayer a layer number between 0 and OGR_DS_GetLayerCount()-1.
@@ -726,23 +352,6 @@ success.
 */
 
 /**
- \fn OGRLayer *OGRDataSource::GetLayerByName(const char *pszLayerName);
-
- \brief Fetch a layer by name.
-
- The returned layer remains owned by the 
- OGRDataSource and should not be deleted by the application.
-
- This method is the same as the C function OGR_DS_GetLayerByName().
-
- @param pszLayerName the layer name of the layer to fetch.
-
- @return the layer, or NULL if Layer is not found or an error occurs.
-
-*/
-
-
-/**
  \fn OGRLayerH OGR_DS_GetLayerByName(OGRDataSourceH hDS, 
                                      const char *pszLayerName );
 
@@ -751,7 +360,7 @@ success.
  The returned layer remains owned by the 
  OGRDataSource and should not be deleted by the application.
 
- This function is the same as the C++ method OGRDataSource::GetLayerByName().
+ @deprecated Use GDALDatasetGetLayerByName() in GDAL 2.0
 
  @param hDS handle to the data source from which to get the layer.
  @param pszLayerName Layer the layer name of the layer to fetch.
@@ -762,30 +371,6 @@ success.
 */
 
 /**
- \fn OGRLayer *OGRDataSource::CopyLayer( OGRLayer *poSrcLayer, 
-                                    const char *pszNewName, 
-                                    char **papszOptions )
-
- \brief Duplicate an existing layer.
-
- This method creates a new layer, duplicate the field definitions of the
- source layer and then duplicate each features of the source layer.
- The papszOptions argument
- can be used to control driver specific creation options.  These options are
- normally documented in the format specific documentation.
- The source layer may come from another dataset.
-
- This method is the same as the C function OGR_DS_CopyLayer().
-
- @param poSrcLayer source layer.
- @param pszNewName the name of the layer to create.
- @param papszOptions a StringList of name=value options.  Options are driver
-                     specific.
-
- @return an handle to the layer, or NULL if an error occurs.
-*/
-
-/**
  \fn OGRLayerH OGR_DS_CopyLayer( OGRDataSourceH hDS, 
                             OGRLayerH hSrcLayer, const char *pszNewName,
                             char **papszOptions )
@@ -799,7 +384,7 @@ success.
  normally documented in the format specific documentation.
  The source layer may come from another dataset.
 
- This function is the same as the C++ method OGRDataSource::CopyLayer
+ @deprecated Use GDALDatasetCopyLayer() in GDAL 2.0
 
  @param hDS handle to the data source where to create the new layer
  @param hSrcLayer handle to the source layer.
@@ -807,119 +392,27 @@ success.
  @param papszOptions a StringList of name=value options.  Options are driver
                      specific.
 
- @return an handle to the layer, or NULL if an error occurs.
-*/
-
-/**
- \fn OGRErr OGRDataSource::DeleteLayer(int iLayer);
-
- \brief Delete the indicated layer from the datasource.
-
- If this method is supported
- the ODsCDeleteLayer capability will test TRUE on the OGRDataSource.
-
- This method is the same as the C function OGR_DS_DeleteLayer().
-
- @param iLayer the index of the layer to delete. 
-
- @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
- layers is not supported for this datasource.
-
-*/
-
-/**
- \fn OGRErr OGR_DS_DeleteLayer(OGRDataSourceH hDS, int iLayer);
-
- \brief Delete the indicated layer from the datasource.
-
- If this method is supported
- the ODsCDeleteLayer capability will test TRUE on the OGRDataSource.
-
- This method is the same as the C++ method OGRDataSource::DeleteLayer().
-
- @param hDS handle to the datasource
- @param iLayer the index of the layer to delete. 
-
- @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
- layers is not supported for this datasource.
-
-*/
-
-/**
- \fn  void OGRDataSource::GetStyleTable();
-
- \brief Returns data source style table.
- 
- This method is the same as the C function OGR_DS_GetStyleTable().
- 
- @return pointer to a style table which should not be modified or freed by the
- caller.
-*/
-
-/**
- \fn  void OGRDataSource::SetStyleTable(OGRStyleTable *poStyleTable);
-
- \brief Set data source style table.
- 
- This method operate exactly as OGRDataSource::SetStyleTableDirectly() except
- that it does not assume ownership of the passed table.
- 
- This method is the same as the C function OGR_DS_SetStyleTable().
- 
- @param poStyleTable pointer to style table to set
-
-*/
-
-/**
- \fn  void OGRDataSource::SetStyleTableDirectly(OGRStyleTable *poStyleTable);
-
- \brief Set data source style table.
- 
- This method operate exactly as OGRDataSource::SetStyleTable() except that it
- assumes ownership of the passed table.
- 
- This method is the same as the C function OGR_DS_SetStyleTableDirectly().
- 
- @param poStyleTable pointer to style table to set
-
+ @return an handle to the layer, or NULL if an error occurs.
 */
 
 /**
- \fn OGRLayer *OGRDataSource::ExecuteSQL(const char *pszStatement,
-				         OGRGeometry *poSpatialFilter, 
-				         const char *pszDialect );
-
- \brief Execute an SQL statement against the data store. 
-
- The result of an SQL query is either NULL for statements that are in error,
- or that have no results set, or an OGRLayer pointer representing a results
- set from the query.  Note that this OGRLayer is in addition to the layers
- in the data store and must be destroyed with 
- OGRDataSource::ReleaseResultSet() before the data source is closed
- (destroyed).  
+ \fn OGRErr OGR_DS_DeleteLayer(OGRDataSourceH hDS, int iLayer);
 
- This method is the same as the C function OGR_DS_ExecuteSQL().
+ \brief Delete the indicated layer from the datasource.
 
- For more information on the SQL dialect supported internally by OGR
- review the <a href="ogr_sql.html">OGR SQL</a> document.  Some drivers (ie.
- Oracle and PostGIS) pass the SQL directly through to the underlying RDBMS.
+ If this method is supported
+ the ODsCDeleteLayer capability will test TRUE on the OGRDataSource.
 
- Starting with OGR 1.10, the <a href="ogr_sql_sqlite.html">SQLITE dialect</a>
- can also be used.
+ @deprecated Use GDALDatasetDeleteLayer() in GDAL 2.0
 
- @param pszStatement the SQL statement to execute. 
- @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
- @param pszDialect allows control of the statement dialect. If set to NULL, the
-OGR SQL engine will be used, except for RDBMS drivers that will use their dedicated SQL engine,
-unless OGRSQL is explicitely passed as the dialect. Starting with OGR 1.10, the SQLITE dialect
-can also be used.
+ @param hDS handle to the datasource
+ @param iLayer the index of the layer to delete. 
 
- @return an OGRLayer containing the results of the query.  Deallocate with
- ReleaseResultSet().
+ @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
+ layers is not supported for this datasource.
 
 */
 
-
 /**
  \fn OGRLayerH OGR_DS_ExecuteSQL( OGRDataSourceH hDS, 
                              const char *pszSQLCommand,
@@ -942,14 +435,14 @@ can also be used.
  Starting with OGR 1.10, the <a href="ogr_sql_sqlite.html">SQLITE dialect</a>
  can also be used.
 
- This function is the same as the C++ method OGRDataSource::ExecuteSQL();
+ @deprecated Use GDALDatasetExecuteSQL() in GDAL 2.0
 
  @param hDS handle to the data source on which the SQL query is executed.
  @param pszSQLCommand the SQL statement to execute. 
  @param hSpatialFilter handle to a geometry which represents a spatial filter. Can be NULL.
  @param pszDialect allows control of the statement dialect. If set to NULL, the
 OGR SQL engine will be used, except for RDBMS drivers that will use their dedicated SQL engine,
-unless OGRSQL is explicitely passed as the dialect. Starting with OGR 1.10, the SQLITE dialect
+unless OGRSQL is explicitly passed as the dialect. Starting with OGR 1.10, the SQLITE dialect
 can also be used.
 
  @return an handle to a OGRLayer containing the results of the query.  
@@ -957,21 +450,6 @@ can also be used.
 
 */
 
-/**
- \fn void OGRDataSource::ReleaseResultSet(OGRLayer *poResultsSet);
-
- \brief Release results of ExecuteSQL().
-
- This method should only be used to deallocate OGRLayers resulting from
- an ExecuteSQL() call on the same OGRDataSource.  Failure to deallocate a
- results set before destroying the OGRDataSource may cause errors. 
-
- This method is the same as the C function OGR_L_ReleaseResultSet().
-
- @param poResultsSet the result of a previous ExecuteSQL() call.
-
-*/ 
-
 
 /**
  \fn void OGR_DS_ReleaseResultSet( OGRDataSourceH hDS, OGRLayerH hLayer );
@@ -983,8 +461,7 @@ can also be used.
  Failure to deallocate a results set before destroying the OGRDataSource 
  may cause errors. 
 
- This function is the same as the C++ method 
- OGRDataSource::ReleaseResultSet().
+ @deprecated Use GDALDatasetReleaseResultSet() in GDAL 2.0
 
  @param hDS an handle to the data source on which was executed an 
  SQL query.
@@ -992,35 +469,6 @@ can also be used.
 
 */ 
 
-
-/**
- \fn int OGRDataSource::TestCapability( const char *pszCapability );
-
- \brief Test if capability is available.
-
- One of the following data source capability names can be passed into this
- method, and a TRUE or FALSE value will be returned indicating whether or not
- the capability is available for this object.
-
- <ul>
-  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
-  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing layers.<p>
-  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
-        datasource support CreateGeomField() just after layer creation.<p>
- </ul>
-
- The \#define macro forms of the capability names should be used in preference
- to the strings themselves to avoid mispelling.
-
- This method is the same as the C function OGR_DS_TestCapability().
-
- @param pszCapability the capability to test.
-
- @return TRUE if capability available otherwise FALSE.
-
-*/ 
-
-
 /**
  \fn int OGR_DS_TestCapability( OGRDataSourceH hDS, const char *pszCapability );
 
@@ -1035,13 +483,15 @@ can also be used.
   <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing layers.<p>
   <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
         datasource support CreateGeomField() just after layer creation.<p>
+  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports writing curve geometries. (GDAL 2.0).
+                                   In that case, OLCCurveGeometries must also be declared in layers of that dataset.<p>
   <p>
  </ul>
 
  The \#define macro forms of the capability names should be used in preference
  to the strings themselves to avoid mispelling.
 
- This function is the same as the C++ method OGRDataSource::TestCapability().
+ @deprecated Use GDALDatasetTestCapability() in GDAL 2.0
 
  @param hDS handle to the data source against which to test the capability.
  @param pszCapability the capability to test.
@@ -1051,57 +501,6 @@ can also be used.
 */ 
 
 /**
- \fn OGRLayer *OGRDataSource::CreateLayer( const char *pszName, 
-                                OGRSpatialReference *poSpatialRef = NULL,
-                                OGRwkbGeometryType eGType = wkbUnknown,
-                                char ** papszOptions = NULL );
-
-\brief This method attempts to create a new layer on the data source with the indicated name, coordinate system, geometry type.
-
-The papszOptions argument
-can be used to control driver specific creation options.  These options are
-normally documented in the format specific documentation. 
-
- @param pszName the name for the new layer.  This should ideally not 
-match any existing layer on the datasource.
- @param poSpatialRef the coordinate system to use for the new layer, or NULL if
-no coordinate system is available. 
- @param eGType the geometry type for the layer.  Use wkbUnknown if there
-are no constraints on the types geometry to be written. 
- @param papszOptions a StringList of name=value options.  Options are driver
-specific.
-
- @return NULL is returned on failure, or a new OGRLayer handle on success. 
-
-<b>Example:</b>
-
-\code
-#include "ogrsf_frmts.h" 
-#include "cpl_string.h"
-
-...
-
-        OGRLayer *poLayer;
-        char     **papszOptions;
-
-        if( !poDS->TestCapability( ODsCCreateLayer ) )
-        {
-        ...
-        }
-
-        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
-        poLayer = poDS->CreateLayer( "NewLayer", NULL, wkbUnknown,
-                                     papszOptions );
-        CSLDestroy( papszOptions );
-
-        if( poLayer == NULL )
-        {
-            ...
-        }        
-\endcode
-*/
-
-/**
  \fn OGRLayerH OGR_DS_CreateLayer( OGRDataSourceH hDS, 
                               const char * pszName,
                               OGRSpatialReferenceH hSpatialRef,
@@ -1114,7 +513,7 @@ The papszOptions argument
 can be used to control driver specific creation options.  These options are
 normally documented in the format specific documentation. 
 
-This function is the same as the C++ method OGRDataSource::CreateLayer().
+ at deprecated Use GDALDatasetCreateLayer() in GDAL 2.0
 
  @param hDS The dataset handle.
  @param pszName the name for the new layer.  This should ideally not 
@@ -1158,60 +557,6 @@ http://www.gdal.org/ogr/ogr_formats.html
 */
 
 /**
- \fn int OGRDataSource::Reference();
-
-\brief Increment datasource reference count.
-
-This method is the same as the C function OGR_DS_Reference().
-
- at return the reference count after incrementing.
-*/
-				         
-/**
- \fn int OGRDataSource::Dereference();
-
-\brief Decrement datasource reference count.
-
-This method is the same as the C function OGR_DS_Dereference().
-
- at return the reference count after decrementing.
-*/
-				         
-/**
- \fn int OGRDataSource::GetRefCount() const;
-
-\brief Fetch reference count.
-
-This method is the same as the C function OGR_DS_GetRefCount().
-
- at return the current reference count for the datasource object itself.
-*/
-				         
-/**
- \fn int OGRDataSource::GetSummaryRefCount() const;
-
-\brief Fetch reference count of datasource and all owned layers.
-
-This method is the same as the C function OGR_DS_GetSummaryRefCount().
-
- at return the current summary reference count for the datasource and its layers.
-*/
-
-/**
- \fn OGRErr OGRDataSource::Release();
-
-\brief Drop a reference to this datasource, and if the reference count drops to zero close (destroy) the datasource.
-
-Internally this actually calls
-the OGRSFDriverRegistrar::ReleaseDataSource() method.  This method is
-essentially a convenient alias. 
-
-This method is the same as the C function OGRReleaseDataSource().
-
- at return OGRERR_NONE on success or an error code. 
-*/
-
-/**
   \fn OGRErr OGRReleaseDataSource( OGRDataSourceH hDS )
 
 \brief Drop a reference to this datasource, and if the reference count drops to zero close (destroy) the datasource.
@@ -1220,7 +565,7 @@ Internally this actually calls
 the OGRSFDriverRegistrar::ReleaseDataSource() method.  This method is
 essentially a convenient alias. 
 
-This method is the same as the C++ method OGRDataSource::Release()
+ at deprecated Use GDALClose() in GDAL 2.0
 
 @param hDS handle to the data source to release
 
@@ -1228,110 +573,20 @@ This method is the same as the C++ method OGRDataSource::Release()
 */
 
 /**
- \fn void OGRDataSource::DestroyDataSource(OGRDataSource* poDS);
-
- \brief Closes opened datasource and releases allocated resources.
-
- This static method will close and destroy a datasource.  It is
- equivelent to calling delete on the object, but it ensures that the
- deallocation is properly executed within the GDAL libraries heap on
- platforms where this can matter (win32).  
-
- This method is the same as the C function OGR_DS_Destroy().
-
-  @param poDS pointer to allocated datasource object.
-*/
-
-/**
- \fn OGRErr OGRDataSource::SyncToDisk();
-
-\brief Flush pending changes to disk.
-
-This call is intended to force the datasource to flush any pending writes to
-disk, and leave the disk file in a consistent state.  It would not normally
-have any effect on read-only datasources. 
-
-Some data sources do not implement this method, and will still return 
-OGRERR_NONE.  An error is only returned if an error occurs while attempting
-to flush to disk.  
-
-The default implementation of this method just calls the SyncToDisk() method
-on each of the layers.  Conceptionally, calling SyncToDisk() on a datasource
-should include any work that might be accomplished by calling SyncToDisk()
-on layers in that data source.
-
-In any event, you should always close any opened datasource with
-OGRDataSource::DestroyDataSource() that will ensure all data is correctly flushed.
-
-This method is the same as the C function OGR_DS_SyncToDisk().
-
- at return OGRERR_NONE if no error occurs (even if nothing is done) or an
-error code.
-*/
-
-/**
- \fn OGRErr OGR_DS_SyncToDisk(OGRDataSourceH hDS);
-
-\brief Flush pending changes to disk.
-
-This call is intended to force the datasource to flush any pending writes to
-disk, and leave the disk file in a consistent state.  It would not normally
-have any effect on read-only datasources. 
-
-Some data sources do not implement this method, and will still return 
-OGRERR_NONE.  An error is only returned if an error occurs while attempting
-to flush to disk.  
-
-The default implementation of this method just calls the SyncToDisk() method
-on each of the layers.  Conceptionally, calling SyncToDisk() on a datasource
-should include any work that might be accomplished by calling SyncToDisk()
-on layers in that data source.
-
-In any event, you should always close any opened datasource with
-OGR_DS_Destroy() that will ensure all data is correctly flushed.
-
-This method is the same as the C++ method OGRDataSource::SyncToDisk()
-
- at param hDS handle to the data source
-
- at return OGRERR_NONE if no error occurs (even if nothing is done) or an
-error code.
-*/
-
-/**
- \fn OGRSFDriver *OGRDataSource::GetDriver() const;
-
-\brief Returns the driver that the dataset was opened with. 
-
-This method is the same as the C function OGR_DS_GetDriver().
-
- at return NULL if driver info is not available, or pointer to a driver owned
-by the OGRSFDriverManager.
-*/
-
-/**
  \fn OGRSFDriverH OGR_DS_GetDriver( OGRDataSourceH hDS );
 
 \brief Returns the driver that the dataset was opened with. 
 
-This method is the same as the C++ method OGRDataSource::GetDriver() 
+NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the returned handle to
+OGRSFDriver*. If a C++ object is needed, the handle should be cast to GDALDriver*.
+
+ at deprecated Use GDALGetDatasetDriver() in GDAL 2.0
 
 @param hDS handle to the datasource
 @return NULL if driver info is not available, or pointer to a driver owned
 by the OGRSFDriverManager.
 */
 
-/**
- \fn void OGRDataSource::SetDriver( OGRSFDriver *poDriver );
-
-\brief Sets the driver that the dataset was created or opened with. 
-
-\note This method is not exposed as the OGR C API function.
- 
- at param poDriver pointer to driver instance associated with the data source.
-
-*/
-
 /************************************************************************/
 /*                               OGRLayer                               */
 /************************************************************************/
@@ -1341,14 +596,14 @@ by the OGRSFDriverManager.
 
  \brief Return the layer name.
 
- This returns the same content as GetLayerDefn()->GetName(), but for a
+ This returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName(), but for a
  few drivers, calling GetName() directly can avoid lengthy layer
  definition initialization.
 
  This method is the same as the C function OGR_L_GetName().
 
  If this method is derived in a driver, it must be done such that it
- returns the same content as GetLayerDefn()->GetName().
+ returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName().
 
  @return the layer name (must not been freed)
  @since OGR 1.8.0
@@ -1377,14 +632,19 @@ by the OGRSFDriverManager.
 
  \brief Return the layer geometry type.
 
- This returns the same result as GetLayerDefn()->GetGeomType(), but for a
+ This returns the same result as GetLayerDefn()->OGRFeatureDefn::GetGeomType(), but for a
  few drivers, calling GetGeomType() directly can avoid lengthy layer
  definition initialization.
 
+ For layers with multiple geometry fields, this method only returns the geometry
+ type of the first geometry column. For other columns, use
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetType().
+ For layers without any geometry field, this method returns wkbNone.
+
  This method is the same as the C function OGR_L_GetGeomType().
 
  If this method is derived in a driver, it must be done such that it
- returns the same content as GetLayerDefn()->GetGeomType().
+ returns the same content as GetLayerDefn()->OGRFeatureDefn::GetGeomType().
 
  @return the geometry type
  @since OGR 1.8.0
@@ -1400,6 +660,11 @@ by the OGRSFDriverManager.
  but for a few drivers, calling OGR_L_GetGeomType() directly can avoid lengthy
  layer definition initialization.
 
+ For layers with multiple geometry fields, this method only returns the geometry
+ type of the first geometry column. For other columns, use
+ OGR_GFld_GetType(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
+ For layers without any geometry field, this method returns wkbNone.
+
  This function is the same as the C++ method OGRLayer::GetGeomType().
 
  @param hLayer handle to the layer.
@@ -1448,6 +713,15 @@ by the OGRSFDriverManager.
  This method implements sequential access to the features of a layer.  The
  ResetReading() method can be used to start at the beginning again.  
 
+ Features returned by GetNextFeature() may or may not be affected by concurrent
+ modifications depending on drivers. A guaranteed way of seing modifications in
+ effect is to call ResetReading() on layers where GetNextFeature() has been called,
+ before reading again.
+ Structural changes in layers (field addition, deletion, ...) when a read is in
+ progress may or may not be possible depending on drivers.
+ If a transaction is committed/aborted, the current sequential reading may or may not be
+ valid after that operation and a call to ResetReading() might be needed.
+
  This method is the same as the C function OGR_L_GetNextFeature().
 
  @return a feature, or NULL if no more features are available. 
@@ -1472,6 +746,15 @@ by the OGRSFDriverManager.
  The OGR_L_ResetReading() function can be used to start at the beginning 
  again.
 
+ Features returned by OGR_GetNextFeature() may or may not be affected by concurrent
+ modifications depending on drivers. A guaranteed way of seing modifications in
+ effect is to call OGR_L_ResetReading() on layers where OGR_GetNextFeature() has been called,
+ before reading again.
+ Structural changes in layers (field addition, deletion, ...) when a read is in
+ progress may or may not be possible depending on drivers.
+ If a transaction is committed/aborted, the current sequential reading may or may not be
+ valid after that operation and a call to OGR_L_ResetReading() might be needed.
+
  This function is the same as the C++ method OGRLayer::GetNextFeature().
 
  @param hLayer handle to the layer from which feature are read.
@@ -1481,7 +764,7 @@ by the OGRSFDriverManager.
 
 /**
 
- \fn int OGRLayer::GetFeatureCount( int bForce = TRUE );
+ \fn GIntBig OGRLayer::GetFeatureCount( int bForce = TRUE );
 
  \brief Fetch the feature count in this layer. 
 
@@ -1497,6 +780,8 @@ by the OGRSFDriverManager.
  of the layer.
 
  This method is the same as the C function OGR_L_GetFeatureCount().
+ 
+ Note: since GDAL 2.0, this method returns a GIntBig (previously a int)
 
  @param bForce Flag indicating whether the count should be computed even
  if it is expensive.
@@ -1506,7 +791,7 @@ by the OGRSFDriverManager.
 */
 
 /**
- \fn int OGR_L_GetFeatureCount( OGRLayerH hLayer, int bForce );
+ \fn GIntBig OGR_L_GetFeatureCount( OGRLayerH hLayer, int bForce );
 
  \brief Fetch the feature count in this layer. 
 
@@ -1523,6 +808,8 @@ by the OGRSFDriverManager.
 
  This function is the same as the CPP OGRLayer::GetFeatureCount().
 
+ Note: since GDAL 2.0, this method returns a GIntBig (previously a int)
+
  @param hLayer handle to the layer that owned the features.
  @param bForce Flag indicating whether the count should be computed even
  if it is expensive.
@@ -1813,7 +1100,7 @@ by the OGRSFDriverManager.
 
  For the time being the passed filter geometry should be in the same
  SRS as the geometry field definition it corresponds to (as returned by
- GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
  future this may be generalized.
 
  Note that only the last spatial filter set is applied, even if several
@@ -1857,7 +1144,7 @@ by the OGRSFDriverManager.
 
  For the time being the passed filter geometry should be in the same
  SRS as the geometry field definition it corresponds to (as returned by
- GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()).  In the
  future this may be generalized.
 
  Note that only the last spatial filter set is applied, even if several
@@ -1889,7 +1176,7 @@ by the OGRSFDriverManager.
 
  The x/y values should be in the same coordinate system as as the geometry
  field definition it corresponds to (as returned by
- GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this 
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this 
  method is normally implemented as creating a 5 vertex closed rectangular
  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
  a convenience. 
@@ -1923,7 +1210,7 @@ by the OGRSFDriverManager.
 
  The x/y values should be in the same coordinate system as as the geometry
  field definition it corresponds to (as returned by
- GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this 
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this 
  method is normally implemented as creating a 5 vertex closed rectangular
  polygon and passing it to OGRLayer::SetSpatialFilter().  It exists as
  a convenience. 
@@ -2119,7 +1406,7 @@ by the OGRSFDriverManager.
  feature definition. Each geometry field can have its own spatial reference
  system, which is returned by OGRGeomFieldDefn::GetSpatialRef().
  OGRLayer::GetSpatialRef() is equivalent to
- GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef()
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(0)->GetSpatialRef()
 
  This method is the same as the C function OGR_L_GetSpatialRef().
 
@@ -2146,7 +1433,7 @@ by the OGRSFDriverManager.
 
 /**
 
- \fn OGRFeature *OGRLayer::GetFeature( long nFID );
+ \fn OGRFeature *OGRLayer::GetFeature( GIntBig nFID );
 
  \brief Fetch a feature by its identifier.
 
@@ -2180,7 +1467,7 @@ by the OGRSFDriverManager.
 
 /**
 
- \fn OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, long nFeatureId );
+ \fn OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, GIntBig nFeatureId );
 
  \brief Fetch a feature by its identifier.
 
@@ -2225,12 +1512,35 @@ by the OGRSFDriverManager.
  Use OGRLayer::TestCapability(OLCRandomWrite) to establish if this layer
  supports random access writing via SetFeature().
 
+ Starting with GDAL 2.0, drivers should specialize the ISetFeature() method,
+ since SetFeature() is no longer virtual.
+
  This method is the same as the C function OGR_L_SetFeature().
 
  @param poFeature the feature to write.
 
  @return OGRERR_NONE if the operation works, otherwise an appropriate error
- code.
+ code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
+
+*/
+
+/**
+ 
+ \fn OGRErr OGRLayer::ISetFeature( OGRFeature * poFeature );
+
+ \brief Rewrite an existing feature.
+
+ This method is implemented by drivers and not called directly. User code should
+ use SetFeature() instead.
+
+ This method will write a feature to the layer, based on the feature id
+ within the OGRFeature.   
+
+ @param poFeature the feature to write.
+
+ @return OGRERR_NONE if the operation works, otherwise an appropriate error
+ code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
+ @since GDAL 2.0
 
 */
 
@@ -2252,7 +1562,7 @@ by the OGRSFDriverManager.
  @param hFeat the feature to write.
 
  @return OGRERR_NONE if the operation works, otherwise an appropriate error
- code.
+ code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
 
 */
 
@@ -2268,6 +1578,9 @@ by the OGRSFDriverManager.
  of the new feature, but not necessarily.  Upon successful return the 
  passed feature will have been updated with the new feature id. 
 
+ Starting with GDAL 2.0, drivers should specialize the ICreateFeature() method,
+ since CreateFeature() is no longer virtual.
+
  This method is the same as the C function OGR_L_CreateFeature().
 
  @param poFeature the feature to write to disk. 
@@ -2278,6 +1591,28 @@ by the OGRSFDriverManager.
 
 /**
 
+ \fn OGRErr OGRLayer::ICreateFeature( OGRFeature * poFeature );
+
+ \brief Create and write a new feature within a layer.
+
+ This method is implemented by drivers  and not called directly. User code should
+ use CreateFeature() instead.
+
+ The passed feature is written to the layer as a new feature, rather than
+ overwriting an existing one.  If the feature has a feature id other than
+ OGRNullFID, then the native implementation may use that as the feature id
+ of the new feature, but not necessarily.  Upon successful return the 
+ passed feature will have been updated with the new feature id. 
+
+ @param poFeature the feature to write to disk. 
+
+ @return OGRERR_NONE on success.
+ @since GDAL 2.0
+
+*/
+
+/**
+
  \fn OGRErr OGR_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat );
 
  \brief Create and write a new feature within a layer.
@@ -2299,7 +1634,7 @@ by the OGRSFDriverManager.
 
 /**
 
- \fn OGRErr OGRLayer::DeleteFeature( long nFID );
+ \fn OGRErr OGRLayer::DeleteFeature( GIntBig nFID );
 
  \brief Delete feature from layer.
 
@@ -2313,13 +1648,14 @@ by the OGRSFDriverManager.
 
  @param nFID the feature id to be deleted from the layer 
 
- @return OGRERR_NONE on success.
+ @return OGRERR_NONE if the operation works, otherwise an appropriate error
+ code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
 
 */
 
 /**
 
- \fn OGRErr OGR_L_DeleteFeature( OGRLayerH hLayer, long nFID );
+ \fn OGRErr OGR_L_DeleteFeature( OGRLayerH hLayer, GIntBig nFID );
 
  \brief Delete feature from layer.
 
@@ -2334,8 +1670,8 @@ by the OGRSFDriverManager.
  @param hLayer handle to the layer
  @param nFID the feature id to be deleted from the layer 
 
- @return OGRERR_NONE on success.
-
+ @return OGRERR_NONE if the operation works, otherwise an appropriate error
+ code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
 
 */
 
@@ -2419,6 +1755,9 @@ otherwise FALSE.<p>
 <li> <b>OLCIgnoreFields</b> / "IgnoreFields": TRUE if fields, geometry and style
 will be omitted when fetching features as set by SetIgnoredFields() method.
 
+<li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
+writing curve geometries or may return such geometries. (GDAL 2.0).
+
 <p>
 
 </ul>
@@ -2510,6 +1849,9 @@ is uncertain, though it might still be UTF-8.<p>
 CommitTransaction() and RollbackTransaction() methods work in a meaningful way,
 otherwise FALSE.<p>
 
+<li> <b>OLCCurveGeometries</b> / "CurveGeometries": TRUE if this layer supports
+writing curve geometries or may return such geometries. (GDAL 2.0).
+
 <p>
 
 </ul>
@@ -2525,29 +1867,6 @@ OGRLayers will return FALSE for any unrecognised capabilities.<p>
 */
 
 /**
- \fn const char *OGRLayer::GetInfo( const char *pszTag );
-
- \brief Fetch metadata from layer.
-
- This method can be used to fetch various kinds of metadata or layer 
- specific information encoded as a string.  It is anticipated that various
- tag values will be defined with well known semantics, while other tags will
- be used for driver/application specific purposes.  
-
- This method is deprecated and will be replaced with a more general 
- metadata model in the future. At this time no drivers return information
- via the GetInfo() call. 
-
- @param pszTag the tag for which information is being requested.
-
- @return the value of the requested tag, or NULL if that tag does not
- have a value, or is unknown.
-
- @deprecated
-
-*/
-
-/**
  \fn OGRErr OGRLayer::SyncToDisk();
 
 \brief Flush pending changes to disk.
@@ -2594,7 +1913,7 @@ error code.
 */
 
 /**
- \fn OGRErr OGRLayer::SetNextByIndex( long nIndex );
+ \fn OGRErr OGRLayer::SetNextByIndex( GIntBig nIndex );
 
  \brief Move read cursor to the nIndex'th feature in the current resultset. 
 
@@ -2622,7 +1941,7 @@ error code.
 
 
 /**
- \fn OGRErr OGR_L_SetNextByIndex( OGRLayerH hLayer, long nIndex );
+ \fn OGRErr OGR_L_SetNextByIndex( OGRLayerH hLayer, GIntBig nIndex );
 
  \brief Move read cursor to the nIndex'th feature in the current resultset. 
 
@@ -2698,6 +2017,9 @@ with the OLCCreateField capability. Some drivers may only support this method wh
 there are still no features in the layer. When it is supported, the existings features of the
 backing file/database should be updated accordingly.
 
+Drivers may or may not support not-null constraints. If they support creating
+fields with not-null constraints, this is generally before creating any feature to the layer.
+
 This function is the same as the C function OGR_L_CreateField().
 
 @param poField field definition to write to disk. 
@@ -2727,6 +2049,9 @@ with the OLCCreateField capability. Some drivers may only support this method wh
 there are still no features in the layer. When it is supported, the existings features of the
 backing file/database should be updated accordingly.
 
+Drivers may or may not support not-null constraints. If they support creating
+fields with not-null constraints, this is generally before creating any feature to the layer.
+
  This function is the same as the C++ method OGRLayer::CreateField().
 
  @param hLayer handle to the layer to write the field definition.
@@ -2820,8 +2145,8 @@ backing file/database should be updated accordingly.
 
 This function is the same as the C function OGR_L_ReorderFields().
 
- at param panMap an array of GetLayerDefn()->GetFieldCount() elements which
-is a permutation of [0, GetLayerDefn()->GetFieldCount()-1].
+ at param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
+is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
 
 @return OGRERR_NONE on success.
 
@@ -2856,8 +2181,8 @@ backing file/database should be updated accordingly.
 This function is the same as the C++ method OGRLayer::ReorderFields().
 
 @param hLayer handle to the layer.
- at param panMap an array of GetLayerDefn()->GetFieldCount() elements which
-is a permutation of [0, GetLayerDefn()->GetFieldCount()-1].
+ at param panMap an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount() elements which
+is a permutation of [0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1].
 
 @return OGRERR_NONE on success.
 
@@ -2962,8 +2287,9 @@ This function is the same as the C function OGR_L_AlterFieldDefn().
 
 @param iField index of the field whose definition must be altered.
 @param poNewFieldDefn new field definition
- at param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG and ALTER_WIDTH_PRECISION_FLAG
-to indicate which of the name and/or type and/or width and precision fields from the new field
+ at param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
+ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
+to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
 definition must be taken into account.
 
 @return OGRERR_NONE on success.
@@ -2995,8 +2321,9 @@ This function is the same as the C++ method OGRLayer::AlterFieldDefn().
 @param hLayer handle to the layer.
 @param iField index of the field whose definition must be altered.
 @param hNewFieldDefn new field definition
- at param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG and ALTER_WIDTH_PRECISION_FLAG
-to indicate which of the name and/or type and/or width and precision fields from the new field
+ at param nFlags combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG, ALTER_WIDTH_PRECISION_FLAG,
+ALTER_NULLABLE_FLAG and ALTER_DEFAULT_FLAG
+to indicate which of the name and/or type and/or width and precision fields and/or nullability from the new field
 definition must be taken into account.
 
 @return OGRERR_NONE on success.
@@ -3024,6 +2351,9 @@ with the OLCCreateGeomField capability. Some drivers may only support this metho
 there are still no features in the layer. When it is supported, the existings features of the
 backing file/database should be updated accordingly.
 
+Drivers may or may not support not-null constraints. If they support creating
+fields with not-null constraints, this is generally before creating any feature to the layer.
+
 This function is the same as the C function OGR_L_CreateGeomField().
 
 @param poField geometry field definition to write to disk. 
@@ -3055,6 +2385,9 @@ with the OLCCreateField capability. Some drivers may only support this method wh
 there are still no features in the layer. When it is supported, the existings features of the
 backing file/database should be updated accordingly.
 
+Drivers may or may not support not-null constraints. If they support creating
+fields with not-null constraints, this is generally before creating any feature to the layer.
+
  This function is the same as the C++ method OGRLayer::CreateField().
 
  @param hLayer handle to the layer to write the field definition.
@@ -3115,6 +2448,11 @@ form depending on the limitations of the format driver.
  If starting the transaction fails, will return 
  OGRERR_FAILURE. Datasources which do not support transactions will 
  always return OGRERR_NONE. 
+
+ Note: as of GDAL 2.0, use of this API is discouraged when the dataset offers
+ dataset level transaction with GDALDataset::StartTransaction(). The reason is
+ that most drivers can only offer transactions at dataset level, and not layer level.
+ Very few drivers really support transactions at layer scope.
  
  This function is the same as the C++ method OGRLayer::StartTransaction().
 
@@ -3187,6 +2525,10 @@ form depending on the limitations of the format driver.
 
  \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
 
+ For layers with multiple geometry fields, this method only returns the name
+ of the first geometry column. For other columns, use
+ GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetNameRef().
+
  This method is the same as the C function OGR_L_GetGeometryColumn().
 
  @return geometry column name.
@@ -3198,6 +2540,10 @@ form depending on the limitations of the format driver.
 
  \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
 
+ For layers with multiple geometry fields, this method only returns the geometry
+ type of the first geometry column. For other columns, use
+ OGR_GFld_GetNameRef(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
+
  This method is the same as the C++ method OGRLayer::GetGeometryColumn()
 
  @param hLayer handle to the layer
diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h
index 0ff6c23..8a00307 100644
--- a/ogr/ogrsf_frmts/ogrsf_frmts.h
+++ b/ogr/ogrsf_frmts/ogrsf_frmts.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsf_frmts.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsf_frmts.h 29035 2015-04-27 12:38:54Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Classes related to format registration, and file opening.
@@ -34,6 +34,7 @@
 #include "cpl_progress.h"
 #include "ogr_feature.h"
 #include "ogr_featurestyle.h"
+#include "gdal_priv.h"
 
 /**
  * \file ogrsf_frmts.h
@@ -41,6 +42,12 @@
  * Classes related to registration of format support, and opening datasets.
  */
 
+#if !defined(GDAL_COMPILATION) && !defined(SUPPRESS_DEPRECATION_WARNINGS)
+#define OGR_DEPRECATED(x) CPL_WARN_DEPRECATED(x)
+#else
+#define OGR_DEPRECATED(x) 
+#endif
+
 class OGRLayerAttrIndex;
 class OGRSFDriver;
 
@@ -56,8 +63,11 @@ class OGRSFDriver;
 /* Note: any virtual method added to this class must also be added in the */
 /* OGRLayerDecorator and OGRMutexedLayer classes. */
 
-class CPL_DLL OGRLayer
+class CPL_DLL OGRLayer : public GDALMajorObject
 {
+  private:
+    void         ConvertNonLinearGeomsIfNecessary( OGRFeature *poFeature );
+
   protected:
     int          m_bFilterIsEnvelope;
     OGRGeometry *m_poFilterGeom;
@@ -72,6 +82,9 @@ class CPL_DLL OGRLayer
     
     OGRErr       GetExtentInternal(int iGeomField, OGREnvelope *psExtent, int bForce );
 
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+
   public:
     OGRLayer();
     virtual     ~OGRLayer();
@@ -90,11 +103,13 @@ class CPL_DLL OGRLayer
 
     virtual void        ResetReading() = 0;
     virtual OGRFeature *GetNextFeature() = 0;
-    virtual OGRErr      SetNextByIndex( long nIndex );
-    virtual OGRFeature *GetFeature( long nFID );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
+    virtual OGRFeature *GetFeature( GIntBig nFID );
+
+    OGRErr      SetFeature( OGRFeature *poFeature );
+    OGRErr      CreateFeature( OGRFeature *poFeature );
+
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual const char *GetName();
     virtual OGRwkbGeometryType GetGeomType();
@@ -103,20 +118,18 @@ class CPL_DLL OGRLayer
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent,
                                   int bForce = TRUE);
 
     virtual int         TestCapability( const char * ) = 0;
 
-    virtual const char *GetInfo( const char * );
-
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
     virtual OGRErr      DeleteField( int iField );
     virtual OGRErr      ReorderFields( int* panMap );
-    virtual OGRErr      AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
+    virtual OGRErr      AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlagsIn );
 
     virtual OGRErr      CreateGeomField( OGRGeomFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -199,12 +212,14 @@ class CPL_DLL OGRLayer
     GIntBig              m_nFeaturesRead;
 };
 
-
 /************************************************************************/
 /*                            OGRDataSource                             */
 /************************************************************************/
 
 /**
+ * LEGACY class. Use GDALDataset in your new code ! This class may be
+ * removed in a later release.
+ * 
  * This class represents a data source.  A data source potentially
  * consists of many layers (OGRLayer).  A data source normally consists
  * of one, or a related set of files, though the name doesn't have to be
@@ -212,77 +227,22 @@ class CPL_DLL OGRLayer
  *
  * When an OGRDataSource is destroyed, all it's associated OGRLayers objects
  * are also destroyed.
+ *
+ * NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the handle of
+ * a C function that returns a OGRDataSourceH to a OGRDataSource*. If a C++ object
+ * is needed, the handle should be cast to GDALDataset*.
+ *
+ * @deprecated
  */ 
 
-class CPL_DLL OGRDataSource
+class CPL_DLL OGRDataSource : public GDALDataset
 {
-    friend class OGRSFDriverRegistrar;
-
-    void        *m_hMutex;
-
-    OGRLayer*       BuildLayerFromSelectInfo(void* psSelectInfo,
-                                             OGRGeometry *poSpatialFilter,
-                                             const char *pszDialect);
-
-  public:
-
-    OGRDataSource();
-    virtual     ~OGRDataSource();
-    static void         DestroyDataSource( OGRDataSource * );
-
-    virtual const char  *GetName() = 0;
-
-    virtual int         GetLayerCount() = 0;
-    virtual OGRLayer    *GetLayer(int) = 0;
-    virtual OGRLayer    *GetLayerByName(const char *);
-    virtual OGRErr      DeleteLayer(int);
-
-    virtual int         TestCapability( const char * ) = 0;
-
-    virtual OGRLayer   *CreateLayer( const char *pszName, 
-                                     OGRSpatialReference *poSpatialRef = NULL,
-                                     OGRwkbGeometryType eGType = wkbUnknown,
-                                     char ** papszOptions = NULL );
-    virtual OGRLayer   *CopyLayer( OGRLayer *poSrcLayer, 
-                                   const char *pszNewName, 
-                                   char **papszOptions = NULL );
-
-    virtual OGRStyleTable *GetStyleTable();
-    virtual void        SetStyleTableDirectly( OGRStyleTable *poStyleTable );
-                            
-    virtual void        SetStyleTable(OGRStyleTable *poStyleTable);
+public:
+                        OGRDataSource();
 
-    virtual OGRLayer *  ExecuteSQL( const char *pszStatement,
-                                    OGRGeometry *poSpatialFilter,
-                                    const char *pszDialect );
-    virtual void        ReleaseResultSet( OGRLayer * poResultsSet );
+    virtual const char  *GetName() OGR_DEPRECATED("Use GDALDataset class instead") = 0;
 
-    virtual OGRErr      SyncToDisk();
-
-    int                 Reference();
-    int                 Dereference();
-    int                 GetRefCount() const;
-    int                 GetSummaryRefCount() const;
-    OGRErr              Release();
-
-    OGRSFDriver        *GetDriver() const;
-    void                SetDriver( OGRSFDriver *poDriver );
-    
-    static int          IsGenericSQLDialect(const char* pszDialect);
-
-  protected:
-
-    OGRErr              ProcessSQLCreateIndex( const char * );
-    OGRErr              ProcessSQLDropIndex( const char * );
-    OGRErr              ProcessSQLDropTable( const char * );
-    OGRErr              ProcessSQLAlterTableAddColumn( const char * );
-    OGRErr              ProcessSQLAlterTableDropColumn( const char * );
-    OGRErr              ProcessSQLAlterTableAlterColumn( const char * );
-    OGRErr              ProcessSQLAlterTableRenameColumn( const char * );
-
-    OGRStyleTable      *m_poStyleTable;
-    int                 m_nRefCount;
-    OGRSFDriver        *m_poDriver;
+    static void         DestroyDataSource( OGRDataSource * ) OGR_DEPRECATED("Use GDALDataset class instead");
 };
 
 /************************************************************************/
@@ -290,32 +250,37 @@ class CPL_DLL OGRDataSource
 /************************************************************************/
 
 /**
+ * LEGACY class. Use GDALDriver in your new code ! This class may be
+ * removed in a later release.
+ *
  * Represents an operational format driver.
  *
  * One OGRSFDriver derived class will normally exist for each file format
  * registered for use, regardless of whether a file has or will be opened.
  * The list of available drivers is normally managed by the
  * OGRSFDriverRegistrar.
+ *
+ * NOTE: Starting with GDAL 2.0, it is *NOT* safe to cast the handle of
+ * a C function that returns a OGRSFDriverH to a OGRSFDriver*. If a C++ object
+ * is needed, the handle should be cast to GDALDriver*.
+ *
+ * @deprecated
  */
 
-class CPL_DLL OGRSFDriver
+class CPL_DLL OGRSFDriver : public GDALDriver
 {
   public:
     virtual     ~OGRSFDriver();
 
-    virtual const char  *GetName() = 0;
-
-    virtual OGRDataSource *Open( const char *pszName, int bUpdate=FALSE ) = 0;
+    virtual const char  *GetName() OGR_DEPRECATED("Use GDALDriver class instead") = 0;
 
-    virtual int         TestCapability( const char * ) = 0;
+    virtual OGRDataSource *Open( const char *pszName, int bUpdate=FALSE ) OGR_DEPRECATED("Use GDALDriver class instead") = 0;
+    
+    virtual int            TestCapability( const char *pszCap ) OGR_DEPRECATED("Use GDALDriver class instead") = 0;
 
     virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    virtual OGRErr      DeleteDataSource( const char *pszName );
-
-    virtual OGRDataSource *CopyDataSource( OGRDataSource *poSrcDS, 
-                                           const char *pszNewName, 
-                                           char **papszOptions = NULL );
+                                             char ** = NULL ) OGR_DEPRECATED("Use GDALDriver class instead");
+    virtual OGRErr      DeleteDataSource( const char *pszName ) OGR_DEPRECATED("Use GDALDriver class instead");
 };
 
 
@@ -324,49 +289,44 @@ class CPL_DLL OGRSFDriver
 /************************************************************************/
 
 /**
+ * LEGACY class. Use GDALDriverManager in your new code ! This class may be
+ * removed in a later release.
+ *
  * Singleton manager for OGRSFDriver instances that will be used to try
  * and open datasources.  Normally the registrar is populated with 
  * standard drivers using the OGRRegisterAll() function and does not need
  * to be directly accessed.  The driver registrar and all registered drivers
  * may be cleaned up on shutdown using OGRCleanupAll().
+ *
+ * @deprecated
  */
 
 class CPL_DLL OGRSFDriverRegistrar
 {
-    int         nDrivers;
-    OGRSFDriver **papoDrivers;
 
                 OGRSFDriverRegistrar();
-
-    int         nOpenDSCount;
-    char        **papszOpenDSRawName;
-    OGRDataSource **papoOpenDS;
-    OGRSFDriver **papoOpenDSDriver;
-    GIntBig     *panOpenDSPID;
-
-  public:
-
                 ~OGRSFDriverRegistrar();
 
-    static OGRSFDriverRegistrar *GetRegistrar();
-    static OGRDataSource *Open( const char *pszName, int bUpdate=FALSE,
-                                OGRSFDriver ** ppoDriver = NULL );
+    static GDALDataset* OpenWithDriverArg(GDALDriver* poDriver,
+                                                 GDALOpenInfo* poOpenInfo);
+    static GDALDataset* CreateVectorOnly( GDALDriver* poDriver,
+                                          const char * pszName,
+                                          char ** papszOptions );
+    static CPLErr       DeleteDataSource( GDALDriver* poDriver,
+                                          const char * pszName );
 
-    OGRDataSource *OpenShared( const char *pszName, int bUpdate=FALSE,
-                               OGRSFDriver ** ppoDriver = NULL );
-    OGRErr      ReleaseDataSource( OGRDataSource * );
+  public:
 
-    void        RegisterDriver( OGRSFDriver * poDriver );
-    void        DeregisterDriver( OGRSFDriver * poDriver );
+    static OGRSFDriverRegistrar *GetRegistrar() OGR_DEPRECATED("Use GDALDriverManager class instead");
 
-    int         GetDriverCount( void );
-    OGRSFDriver *GetDriver( int iDriver );
-    OGRSFDriver *GetDriverByName( const char * );
+    void        RegisterDriver( OGRSFDriver * poDriver ) OGR_DEPRECATED("Use GDALDriverManager class instead");
 
-    int         GetOpenDSCount() { return nOpenDSCount; } 
-    OGRDataSource *GetOpenDS( int );
+    int         GetDriverCount( void ) OGR_DEPRECATED("Use GDALDriverManager class instead");
+    GDALDriver *GetDriver( int iDriver ) OGR_DEPRECATED("Use GDALDriverManager class instead");
+    GDALDriver *GetDriverByName( const char * ) OGR_DEPRECATED("Use GDALDriverManager class instead");
 
-    void        AutoLoadDrivers();
+    int         GetOpenDSCount() OGR_DEPRECATED("Use GDALDriverManager class instead");
+    OGRDataSource *GetOpenDS( int ) OGR_DEPRECATED("Use GDALDriverManager class instead");
 };
 
 /* -------------------------------------------------------------------- */
@@ -374,6 +334,7 @@ class CPL_DLL OGRSFDriverRegistrar
 /* -------------------------------------------------------------------- */
 CPL_C_START
 void CPL_DLL OGRRegisterAll();
+void OGRRegisterAllInternal();
 
 void CPL_DLL RegisterOGRFileGDB();
 void CPL_DLL RegisterOGRShape();
@@ -418,7 +379,6 @@ void CPL_DLL RegisterOGRBNA();
 void CPL_DLL RegisterOGRGPX();
 void CPL_DLL RegisterOGRGeoconcept();
 void CPL_DLL RegisterOGRIngres();
-void CPL_DLL RegisterOGRPCIDSK();
 void CPL_DLL RegisterOGRXPlane();
 void CPL_DLL RegisterOGRNAS();
 void CPL_DLL RegisterOGRGeoRSS();
@@ -441,6 +401,7 @@ void CPL_DLL RegisterOGRGFT();
 void CPL_DLL RegisterOGRGME();
 void CPL_DLL RegisterOGRSVG();
 void CPL_DLL RegisterOGRCouchDB();
+void CPL_DLL RegisterOGRCloudant();
 void CPL_DLL RegisterOGRIdrisi();
 void CPL_DLL RegisterOGRARCGEN();
 void CPL_DLL RegisterOGRSEGUKOOA();
@@ -450,11 +411,14 @@ void CPL_DLL RegisterOGRODS();
 void CPL_DLL RegisterOGRXLSX();
 void CPL_DLL RegisterOGRElastic();
 void CPL_DLL RegisterOGRGeoPackage();
-void CPL_DLL RegisterOGRPDF();
 void CPL_DLL RegisterOGRWalk();
 void CPL_DLL RegisterOGRCartoDB();
 void CPL_DLL RegisterOGRSXF();
 void CPL_DLL RegisterOGROpenFileGDB();
+void CPL_DLL RegisterOGRSelafin();
+void CPL_DLL RegisterOGRJML();
+void CPL_DLL RegisterOGRPLSCENES();
+void CPL_DLL RegisterOGRCSW();
 CPL_C_END
 
 
diff --git a/ogr/ogrsf_frmts/openair/GNUmakefile b/ogr/ogrsf_frmts/openair/GNUmakefile
index 5eefe8b..58773f9 100644
--- a/ogr/ogrsf_frmts/openair/GNUmakefile
+++ b/ogr/ogrsf_frmts/openair/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogropenairdriver.o ogropenairdatasource.o ogropenairlayer.o ogropenairlabellayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../xplane $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../xplane  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/openair/ogr_openair.h b/ogr/ogrsf_frmts/openair/ogr_openair.h
index e261d3b..fa7d963 100644
--- a/ogr/ogrsf_frmts/openair/ogr_openair.h
+++ b/ogr/ogrsf_frmts/openair/ogr_openair.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_openair.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_openair.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenAir Translator
  * Purpose:  Definition of classes for OGR .sua driver.
@@ -120,8 +120,7 @@ class OGROpenAirDataSource : public OGRDataSource
                         OGROpenAirDataSource();
                         ~OGROpenAirDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -131,20 +130,6 @@ class OGROpenAirDataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                           OGROpenAirDriver                           */
-/************************************************************************/
-
-class OGROpenAirDriver : public OGRSFDriver
-{
-  public:
-                ~OGROpenAirDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
 int OGROpenAirGetLatLon(const char* pszStr, double& dfLat, double& dfLon);
 
 #endif /* ndef _OGR_OPENAIR_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/openair/ogropenairdatasource.cpp b/ogr/ogrsf_frmts/openair/ogropenairdatasource.cpp
index 24a53d6..1af84d0 100644
--- a/ogr/ogrsf_frmts/openair/ogropenairdatasource.cpp
+++ b/ogr/ogrsf_frmts/openair/ogropenairdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenairdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogropenairdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenAir Translator
  * Purpose:  Implements OGROpenAirDataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogropenairdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogropenairdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        OGROpenAirDataSource()                        */
@@ -86,50 +86,30 @@ OGRLayer *OGROpenAirDataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGROpenAirDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGROpenAirDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
-// -------------------------------------------------------------------- 
-//      Does this appear to be an openair file?
-// --------------------------------------------------------------------
-
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     if (fp == NULL)
         return FALSE;
 
-    char szBuffer[10000];
-    int nbRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
-    szBuffer[nbRead] = '\0';
-
-    int bIsOpenAir = (strstr(szBuffer, "\nAC ") != NULL &&
-                  strstr(szBuffer, "\nAN ") != NULL &&
-                  strstr(szBuffer, "\nAL ") != NULL &&
-                  strstr(szBuffer, "\nAH") != NULL);
-
-    if (bIsOpenAir)
+    VSILFILE* fp2 = VSIFOpenL(pszFilename, "rb");
+    if (fp2)
     {
-        VSIFSeekL( fp, 0, SEEK_SET );
-
-        VSILFILE* fp2 = VSIFOpenL(pszFilename, "rb");
-        if (fp2)
-        {
-            nLayers = 2;
-            papoLayers = (OGRLayer**) CPLMalloc(2 * sizeof(OGRLayer*));
-            papoLayers[0] = new OGROpenAirLayer(fp);
-            papoLayers[1] = new OGROpenAirLabelLayer(fp2);
-        }
+        nLayers = 2;
+        papoLayers = (OGRLayer**) CPLMalloc(2 * sizeof(OGRLayer*));
+        papoLayers[0] = new OGROpenAirLayer(fp);
+        papoLayers[1] = new OGROpenAirLabelLayer(fp2);
     }
     else
+    {
         VSIFCloseL(fp);
+        return FALSE;
+    }
 
-    return bIsOpenAir;
+    return TRUE;
 }
 
 
diff --git a/ogr/ogrsf_frmts/openair/ogropenairdriver.cpp b/ogr/ogrsf_frmts/openair/ogropenairdriver.cpp
index 5c89b59..b54403c 100644
--- a/ogr/ogrsf_frmts/openair/ogropenairdriver.cpp
+++ b/ogr/ogrsf_frmts/openair/ogropenairdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenairdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogropenairdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenAir Translator
  * Purpose:  Implements OGROpenAirDriver.
@@ -30,39 +30,32 @@
 #include "ogr_openair.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogropenairdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogropenairdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGROpenAir();
 
 /************************************************************************/
-/*                         ~OGROpenAirDriver()                          */
-/************************************************************************/
-
-OGROpenAirDriver::~OGROpenAirDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGROpenAirDriver::GetName()
-
-{
-    return "OpenAir";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGROpenAirDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGROpenAirDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        !poOpenInfo->TryToIngest(10000) )
+        return NULL;
+
+    int bIsOpenAir = (strstr((const char*)poOpenInfo->pabyHeader, "\nAC ") != NULL &&
+                  strstr((const char*)poOpenInfo->pabyHeader, "\nAN ") != NULL &&
+                  strstr((const char*)poOpenInfo->pabyHeader, "\nAL ") != NULL &&
+                  strstr((const char*)poOpenInfo->pabyHeader, "\nAH") != NULL);
+    if( !bIsOpenAir )
+        return NULL;
+
     OGROpenAirDataSource   *poDS = new OGROpenAirDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -72,21 +65,30 @@ OGRDataSource *OGROpenAirDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                         RegisterOGROpenAir()                         */
 /************************************************************************/
 
-int OGROpenAirDriver::TestCapability( CPL_UNUSED const char * pszCap )
+void RegisterOGROpenAir()
+
 {
-    return FALSE;
-}
+    GDALDriver  *poDriver;
 
-/************************************************************************/
-/*                           RegisterOGROpenAir()                           */
-/************************************************************************/
+    if( GDALGetDriverByName( "OpenAir" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
-void RegisterOGROpenAir()
+        poDriver->SetDescription( "OpenAir" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "OpenAir" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_openair.html" );
 
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGROpenAirDriver );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGROpenAirDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/openair/ogropenairlabellayer.cpp b/ogr/ogrsf_frmts/openair/ogropenairlabellayer.cpp
index 85a84f9..495966c 100644
--- a/ogr/ogrsf_frmts/openair/ogropenairlabellayer.cpp
+++ b/ogr/ogrsf_frmts/openair/ogropenairlabellayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenairlabellayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogropenairlabellayer.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenAir Translator
  * Purpose:  Implements OGROpenAirLabelLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogropenairlabellayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogropenairlabellayer.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                      OGROpenAirLabelLayer()                          */
@@ -48,6 +48,7 @@ OGROpenAirLabelLayer::OGROpenAirLabelLayer( VSILFILE* fp )
     poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
 
     poFeatureDefn = new OGRFeatureDefn( "labels"  );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPoint );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -188,4 +189,3 @@ int OGROpenAirLabelLayer::TestCapability( CPL_UNUSED const char * pszCap )
 {
     return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/openair/ogropenairlayer.cpp b/ogr/ogrsf_frmts/openair/ogropenairlayer.cpp
index 2c3d3ae..005b6e3 100644
--- a/ogr/ogrsf_frmts/openair/ogropenairlayer.cpp
+++ b/ogr/ogrsf_frmts/openair/ogropenairlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenairlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogropenairlayer.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  OpenAir Translator
  * Purpose:  Implements OGROpenAirLayer class.
@@ -34,7 +34,7 @@
 #include "ogr_xplane_geo_utils.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogropenairlayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogropenairlayer.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                         OGROpenAirLayer()                            */
@@ -51,6 +51,7 @@ OGROpenAirLayer::OGROpenAirLayer( VSILFILE* fp )
     poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
 
     poFeatureDefn = new OGRFeatureDefn( "airspaces" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPolygon );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -284,9 +285,9 @@ OGRFeature *OGROpenAirLayer::GetNextRawFeature()
             char** papszTokens = CSLTokenizeString2(pszLine, ",", 0);
             if (bHasCenter && CSLCount(papszTokens) == 3)
             {
-                double dfRadius = atof(papszTokens[0]) * 1852;
-                double dfStartAngle = atof(papszTokens[1]);
-                double dfEndAngle = atof(papszTokens[2]);
+                double dfRadius = CPLAtof(papszTokens[0]) * 1852;
+                double dfStartAngle = CPLAtof(papszTokens[1]);
+                double dfEndAngle = CPLAtof(papszTokens[2]);
 
                 if (bClockWise && dfEndAngle < dfStartAngle)
                     dfEndAngle += 360;
@@ -380,7 +381,7 @@ OGRFeature *OGROpenAirLayer::GetNextRawFeature()
             {
                 pszLine += 3;
 
-                double dfRADIUS = atof(pszLine) * 1852;
+                double dfRADIUS = CPLAtof(pszLine) * 1852;
 
                 double dfAngle;
                 double dfLat, dfLon;
diff --git a/ogr/ogrsf_frmts/openfilegdb/GNUmakefile b/ogr/ogrsf_frmts/openfilegdb/GNUmakefile
index ba849e7..ddfa4e5 100644
--- a/ogr/ogrsf_frmts/openfilegdb/GNUmakefile
+++ b/ogr/ogrsf_frmts/openfilegdb/GNUmakefile
@@ -4,11 +4,11 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogropenfilegdbdriver.o ogropenfilegdbdatasource.o ogropenfilegdblayer.o filegdbtable.o filegdbindex.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../mem $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../mem  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
 clean:
 	rm -f *.o $(O_OBJ)
 
-$(O_OBJ):	ogr_openfilegdb.h filegdbtable.h filegdbtable_priv.h ../mem/ogr_mem.h
+$(O_OBJ):	ogr_openfilegdb.h filegdbtable.h filegdbtable_priv.h ../../swq.h ../mem/ogr_mem.h
diff --git a/ogr/ogrsf_frmts/openfilegdb/drv_openfilegdb.html b/ogr/ogrsf_frmts/openfilegdb/drv_openfilegdb.html
index ae325b0..e0c0ce4 100644
--- a/ogr/ogrsf_frmts/openfilegdb/drv_openfilegdb.html
+++ b/ogr/ogrsf_frmts/openfilegdb/drv_openfilegdb.html
@@ -73,6 +73,7 @@ Drawbacks of the OpenFileGDB driver:
 <ul>
 <li>Read-only.</li>
 <li>Cannot use spatial indexes.</li>
+<li>Cannot read data from compressed feature classes (SDC, Smart Data Compression). Nor can can FileGDB driver because the ESRI FileGDB SDK lacks also this feature.</li>
 </ul>
 
 <h2>Examples</h2>
diff --git a/ogr/ogrsf_frmts/openfilegdb/filegdbindex.cpp b/ogr/ogrsf_frmts/openfilegdb/filegdbindex.cpp
index 96bfb30..8b958f3 100644
--- a/ogr/ogrsf_frmts/openfilegdb/filegdbindex.cpp
+++ b/ogr/ogrsf_frmts/openfilegdb/filegdbindex.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: filegdbindex.cpp 27751 2014-09-28 16:33:48Z rouault $
+ * $Id: filegdbindex.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements reading of FileGDB indexes
@@ -731,7 +731,7 @@ static const char* FileGDBValueToStr(OGRFieldType eOGRFieldType,
                                             psValue->Date.Day,
                                             psValue->Date.Hour,
                                             psValue->Date.Minute,
-                                            psValue->Date.Second);
+                                            (int)psValue->Date.Second);
         case OFTDate: return CPLSPrintf("%04d/%02d/%02d",
                                             psValue->Date.Year,
                                             psValue->Date.Month,
@@ -739,7 +739,7 @@ static const char* FileGDBValueToStr(OGRFieldType eOGRFieldType,
         case OFTTime: return CPLSPrintf("%02d:%02d:%02d",
                                             psValue->Date.Hour,
                                             psValue->Date.Minute,
-                                            psValue->Date.Second);
+                                            (int)psValue->Date.Second);
         default:
             break;
     }
diff --git a/ogr/ogrsf_frmts/openfilegdb/filegdbtable.cpp b/ogr/ogrsf_frmts/openfilegdb/filegdbtable.cpp
index 2c0fabb..e477dba 100644
--- a/ogr/ogrsf_frmts/openfilegdb/filegdbtable.cpp
+++ b/ogr/ogrsf_frmts/openfilegdb/filegdbtable.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: filegdbtable.cpp 27727 2014-09-23 18:41:36Z rouault $
+ * $Id: filegdbtable.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements reading of FileGDB tables
@@ -87,6 +87,7 @@ void FileGDBTable::Init()
     osFilename = "";
     fpTable = NULL;
     fpTableX = NULL;
+    nFileSize = 0;
     memset(&sCurField, 0, sizeof(sCurField));
     bError = FALSE;
     nCurRow = -1;
@@ -116,6 +117,8 @@ void FileGDBTable::Init()
     nTablxOffsetSize = 0;
     anFeatureOffsets.resize(0);
     nOffsetHeaderEnd = 0;
+    bHasDeletedFeaturesListed = FALSE;
+    bIsDeleted = FALSE;
 }
 
 /************************************************************************/
@@ -266,8 +269,7 @@ static void ReadVarUInt64NoCheck(GByte*& pabyIter, GUIntBig& nOutVal)
 /*                      IsLikelyFeatureAtOffset()                       */
 /************************************************************************/
 
-int FileGDBTable::IsLikelyFeatureAtOffset(vsi_l_offset nFileSize,
-                                          vsi_l_offset nOffset,
+int FileGDBTable::IsLikelyFeatureAtOffset(vsi_l_offset nOffset,
                                           GUInt32* pnSize,
                                           int* pbDeletedRecord)
 {
@@ -445,11 +447,17 @@ int FileGDBTable::IsLikelyFeatureAtOffset(vsi_l_offset nFileSize,
 /*                      GuessFeatureLocations()                         */
 /************************************************************************/
 
+#define MARK_DELETED(x)  ((x) | (((GIntBig)1) << 63))
+#define IS_DELETED(x)    (((x) & (((GIntBig)1) << 63)) != 0)
+#define GET_OFFSET(x)    ((x) & ~(((GIntBig)1) << 63))
+
 int FileGDBTable::GuessFeatureLocations()
 {
-    vsi_l_offset nFileSize;
     VSIFSeekL(fpTable, 0, SEEK_END);
     nFileSize = VSIFTellL(fpTable);
+    
+    int bReportDeletedFeatures =
+        CSLTestBoolean(CPLGetConfigOption("OPENFILEGDB_REPORT_DELETED_FEATURES", "NO"));
 
     vsi_l_offset nOffset = 40 + nFieldDescLength;
     
@@ -480,7 +488,7 @@ int FileGDBTable::GuessFeatureLocations()
     {
         GUInt32 nSize;
         int bDeletedRecord;
-        if( !IsLikelyFeatureAtOffset(nFileSize, nOffset, &nSize, &bDeletedRecord) )
+        if( !IsLikelyFeatureAtOffset(nOffset, &nSize, &bDeletedRecord) )
         {
             nOffset ++;
         }
@@ -490,8 +498,16 @@ int FileGDBTable::GuessFeatureLocations()
                      nOffset, nSize);*/
             if( bDeletedRecord )
             {
-                nInvalidRecords ++;
-                anFeatureOffsets.push_back(0);
+                if( bReportDeletedFeatures )
+                {
+                    bHasDeletedFeaturesListed = TRUE;
+                    anFeatureOffsets.push_back(MARK_DELETED(nOffset));
+                }
+                else
+                {
+                    nInvalidRecords ++;
+                    anFeatureOffsets.push_back(0);
+                }
             }
             else
                 anFeatureOffsets.push_back(nOffset);
@@ -501,10 +517,13 @@ int FileGDBTable::GuessFeatureLocations()
     nTotalRecordCount = (int) anFeatureOffsets.size();
     if( nTotalRecordCount - nInvalidRecords > nValidRecordCount )
     {
-        CPLError(CE_Warning, CPLE_AppDefined,
-                 "More features found (%d) than declared number of valid features (%d). "
-                 "So deleted features will likely be reported.",
-                 nTotalRecordCount - nInvalidRecords, nValidRecordCount);
+        if( !bHasDeletedFeaturesListed )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                    "More features found (%d) than declared number of valid features (%d). "
+                    "So deleted features will likely be reported.",
+                    nTotalRecordCount - nInvalidRecords, nValidRecordCount);
+        }
         nValidRecordCount = nTotalRecordCount - nInvalidRecords;
     }
 
@@ -584,15 +603,25 @@ int FileGDBTable::ReadTableXHeader()
 /*                                 Open()                               */
 /************************************************************************/
 
-int FileGDBTable::Open(const char* pszFilename)
+int FileGDBTable::Open(const char* pszFilename,
+                       const char* pszLayerName)
 {
     const int errorRetValue = FALSE;
     CPLAssert(fpTable == NULL);
 
     osFilename = pszFilename;
+    CPLString osFilenameWithLayerName(osFilename);
+    if( pszLayerName )
+        osFilenameWithLayerName += CPLSPrintf(" (layer %s)", pszLayerName);
 
     fpTable = VSIFOpenL( pszFilename, "rb" );
-    returnErrorIf(fpTable == NULL );
+    if( fpTable == NULL )
+    {
+        CPLError(CE_Failure, CPLE_OpenFailed,
+                 "Cannot open %s: %s", osFilenameWithLayerName.c_str(),
+                 VSIStrerror(errno));
+        return FALSE;
+    }
 
     // Read .gdtable file header
     GByte abyHeader[40];
@@ -600,12 +629,13 @@ int FileGDBTable::Open(const char* pszFilename)
     nValidRecordCount = GetInt32(abyHeader + 4, 0);
     returnErrorIf(nValidRecordCount < 0 );
 
+    CPLString osTableXName;
     if( nValidRecordCount > 0 &&
         !CSLTestBoolean(CPLGetConfigOption("OPENFILEGDB_IGNORE_GDBTABLX", "FALSE")) )
     {
-        const char* pszTableXName = CPLFormFilename(CPLGetPath(pszFilename),
+        osTableXName = CPLFormFilename(CPLGetPath(pszFilename),
                                         CPLGetBasename(pszFilename), "gdbtablx");
-        fpTableX = VSIFOpenL( pszTableXName, "rb" );
+        fpTableX = VSIFOpenL( osTableXName, "rb" );
         if( fpTableX == NULL )
         {
             const char* pszIgnoreGDBTablXAbsence =
@@ -614,7 +644,7 @@ int FileGDBTable::Open(const char* pszFilename)
             {
                 CPLError(CE_Warning, CPLE_AppDefined, "%s could not be found. "
                         "Trying to guess feature locations, but this might fail or "
-                        "return incorrect results", pszTableXName);
+                        "return incorrect results", osTableXName.c_str());
             }
             else if( !CSLTestBoolean(pszIgnoreGDBTablXAbsence) )
             {
@@ -627,10 +657,35 @@ int FileGDBTable::Open(const char* pszFilename)
 
     if( fpTableX != NULL )
     {
-        returnErrorIf(nValidRecordCount > nTotalRecordCount );
+        if(nValidRecordCount > nTotalRecordCount )
+        {
+            if( CSLTestBoolean(CPLGetConfigOption("OPENFILEGDB_USE_GDBTABLE_RECORD_COUNT", "FALSE")) )
+            {
+                /* Potentially unsafe. See #5842 */
+                CPLDebug("OpenFileGDB", "%s: nTotalRecordCount (was %d) forced to nValidRecordCount=%d",
+                        osFilenameWithLayerName.c_str(),
+                        nTotalRecordCount, nValidRecordCount);
+                nTotalRecordCount = nValidRecordCount;
+            }
+            else
+            {
+                /* By default err on the safe side */
+                CPLError(CE_Warning, CPLE_AppDefined,
+                        "File %s declares %d valid records, but %s declares "
+                        "only %d total records. Using that later value for safety "
+                        "(this possibly ignoring features). "
+                        "You can also try setting OPENFILEGDB_IGNORE_GDBTABLX=YES to "
+                        "completely ignore the .gdbtablx file (but possibly retrieving "
+                        "deleted features), or set OPENFILEGDB_USE_GDBTABLE_RECORD_COUNT=YES "
+                        "(but that setting can potentially cause crashes)",
+                        osFilenameWithLayerName.c_str(), nValidRecordCount,
+                        osTableXName.c_str(), nTotalRecordCount);
+                nValidRecordCount = nTotalRecordCount;
+            }
+        }
 
 #ifdef DEBUG_VERBOSE
-        if( nTotalRecordCount != nValidRecordCount )
+        else if( nTotalRecordCount != nValidRecordCount )
         {
             CPLDebug("OpenFileGDB", "%s: nTotalRecordCount=%d nValidRecordCount=%d",
                     pszFilename,
@@ -754,11 +809,47 @@ int FileGDBTable::Open(const char* pszFilename)
                     break;
             }
 
+            OGRField sDefault;
+            sDefault.Set.nMarker1 = OGRUnsetMarker;
+            sDefault.Set.nMarker2 = OGRUnsetMarker;
             if( (flags & 4) != 0 )
             {
                 /* Default value */
                 /* Found on PreNIS.gdb/a0000000d.gdbtable */
                 returnErrorIf(nRemaining < defaultValueLength );
+                if( defaultValueLength )
+                {
+                    if( eType == FGFT_STRING )
+                    {
+                        sDefault.String = (char*)CPLMalloc(defaultValueLength+1);
+                        memcpy(sDefault.String, pabyIter, defaultValueLength);
+                        sDefault.String[defaultValueLength] = 0;
+                    }
+                    else if( eType == FGFT_INT16 && defaultValueLength == 2 )
+                    {
+                        sDefault.Integer = GetInt16(pabyIter, 0);
+                        sDefault.Set.nMarker2 = 0;
+                    }
+                    else if( eType == FGFT_INT32 && defaultValueLength == 4 )
+                    {
+                        sDefault.Integer = GetInt32(pabyIter, 0);
+                        sDefault.Set.nMarker2 = 0;
+                    }
+                    else if( eType == FGFT_FLOAT32 && defaultValueLength == 4 )
+                    {
+                        sDefault.Real = GetFloat32(pabyIter, 0);
+                    }
+                    else if( eType == FGFT_FLOAT64 && defaultValueLength == 8 )
+                    {
+                        sDefault.Real = GetFloat64(pabyIter, 0);
+                    }
+                    else if( eType == FGFT_DATETIME && defaultValueLength == 8 )
+                    {
+                        double dfVal = GetFloat64(pabyIter, 0);
+                        FileGDBDoubleDateToOGRDate(dfVal, &sDefault);
+                    }
+                }
+
                 pabyIter += defaultValueLength;
                 nRemaining -= defaultValueLength;
             }
@@ -776,6 +867,7 @@ int FileGDBTable::Open(const char* pszFilename)
             poField->eType = eType;
             poField->bNullable = (flags & 1);
             poField->nMaxWidth = nMaxWidth;
+            poField->sDefault = sDefault;
             apoFields.push_back(poField);
         }
         else
@@ -838,40 +930,44 @@ int FileGDBTable::Open(const char* pszFilename)
             nRemaining --;
             poField->bHasM = (abyGeomFlags & 2) != 0;
             poField->bHasZ = (abyGeomFlags & 4) != 0;
-            returnErrorIf(
-                    nRemaining < (GUInt32)(sizeof(double) * ( 8 + (poField->bHasM + poField->bHasZ) * 3 )) );
 
-#define READ_DOUBLE(field) do { \
-    field = GetFloat64(pabyIter, 0); \
-    pabyIter += sizeof(double); \
-    nRemaining -= sizeof(double); } while(0)
+            if( eType == FGFT_GEOMETRY || abyGeomFlags > 0 )
+            {
+                returnErrorIf(
+                        nRemaining < (GUInt32)(sizeof(double) * ( 4 + (( eType == FGFT_GEOMETRY ) ? 4 : 0) + (poField->bHasM + poField->bHasZ) * 3 )) );
 
-            READ_DOUBLE(poField->dfXOrigin);
-            READ_DOUBLE(poField->dfYOrigin);
-            READ_DOUBLE(poField->dfXYScale);
+    #define READ_DOUBLE(field) do { \
+        field = GetFloat64(pabyIter, 0); \
+        pabyIter += sizeof(double); \
+        nRemaining -= sizeof(double); } while(0)
 
-            if( poField->bHasM )
-            {
-                READ_DOUBLE(poField->dfMOrigin);
-                READ_DOUBLE(poField->dfMScale);
-            }
+                READ_DOUBLE(poField->dfXOrigin);
+                READ_DOUBLE(poField->dfYOrigin);
+                READ_DOUBLE(poField->dfXYScale);
 
-            if( poField->bHasZ )
-            {
-                READ_DOUBLE(poField->dfZOrigin);
-                READ_DOUBLE(poField->dfZScale);
-            }
+                if( poField->bHasM )
+                {
+                    READ_DOUBLE(poField->dfMOrigin);
+                    READ_DOUBLE(poField->dfMScale);
+                }
 
-            READ_DOUBLE(poField->dfXYTolerance);
+                if( poField->bHasZ )
+                {
+                    READ_DOUBLE(poField->dfZOrigin);
+                    READ_DOUBLE(poField->dfZScale);
+                }
 
-            if( poField->bHasM )
-            {
-                READ_DOUBLE(poField->dfMTolerance);
-            }
+                READ_DOUBLE(poField->dfXYTolerance);
 
-            if( poField->bHasZ )
-            {
-                READ_DOUBLE(poField->dfZTolerance);
+                if( poField->bHasM )
+                {
+                    READ_DOUBLE(poField->dfMTolerance);
+                }
+
+                if( poField->bHasZ )
+                {
+                    READ_DOUBLE(poField->dfZTolerance);
+                }
             }
 
             if( eType == FGFT_RASTER )
@@ -889,6 +985,10 @@ int FileGDBTable::Open(const char* pszFilename)
                 READ_DOUBLE(poField->dfYMax);
 
                 /* Purely empiric logic ! */
+                /* Well, it seems that in practice there are 1 or 3 doubles */
+                /* here. When there are 3, the first one is zmin and the second */
+                /* one is zmax */
+                int nCountDoubles = 0;
                 while( TRUE )
                 {
                     returnErrorIf(nRemaining < 5 );
@@ -900,6 +1000,7 @@ int FileGDBTable::Open(const char* pszFilename)
                         pabyIter += 5;
                         nRemaining -= 5;
                         returnErrorIf(nRemaining < (GUInt32)(nToSkip * 8) );
+                        nCountDoubles += nToSkip;
                         pabyIter += nToSkip * 8;
                         nRemaining -= nToSkip * 8;
                         break;
@@ -909,8 +1010,11 @@ int FileGDBTable::Open(const char* pszFilename)
                         returnErrorIf(nRemaining < 8 );
                         pabyIter += 8;
                         nRemaining -= 8;
+                        nCountDoubles ++;
                     }
                 }
+                if( nCountDoubles == 3 )
+                    poField->bHas3D = TRUE;
             }
         }
 
@@ -1002,8 +1106,12 @@ vsi_l_offset FileGDBTable::GetOffsetInTableForRow(int iRow)
     const int errorRetValue = 0;
     returnErrorIf(iRow < 0 || iRow >= nTotalRecordCount );
 
+    bIsDeleted = FALSE;
     if( fpTableX == NULL )
-        return anFeatureOffsets[iRow];
+    {
+        bIsDeleted = IS_DELETED(anFeatureOffsets[iRow]);
+        return GET_OFFSET(anFeatureOffsets[iRow]);
+    }
 
     if( pabyTablXBlockMap != NULL )
     {
@@ -1070,6 +1178,11 @@ int FileGDBTable::SelectRow(int iRow)
                 VSIFReadL(abyBuffer, 4, 1, fpTable) != 1, nCurRow = -1 );
 
         nRowBlobLength = GetUInt32(abyBuffer, 0);
+        if( bIsDeleted )
+        {
+            nRowBlobLength = (GUInt32)(-(int)nRowBlobLength);
+        }
+
         if( !(apoFields.size() == 0 && nRowBlobLength == 0) )
         {
             /* CPLDebug("OpenFileGDB", "nRowBlobLength = %u", nRowBlobLength); */
@@ -1079,6 +1192,18 @@ int FileGDBTable::SelectRow(int iRow)
 
             if( nRowBlobLength > nBufferMaxSize )
             {
+                /* For suspicious row blob length, check if we don't go beyond file size */
+                if( nRowBlobLength > 100 * 1024 * 1024 )
+                {
+                    if( nFileSize == 0 )
+                    {
+                        VSIFSeekL(fpTable, 0, SEEK_END);
+                        nFileSize = VSIFTellL(fpTable);
+                        VSIFSeekL(fpTable, nOffsetTable + 4, SEEK_SET);
+                    }
+                    returnErrorAndCleanupIf( nOffsetTable + 4 + nRowBlobLength > nFileSize, nCurRow = -1 );
+                }
+
                 GByte* pabyNewBuffer = (GByte*) VSIRealloc( pabyBuffer,
                                 nRowBlobLength + ZEROES_AFTER_END_OF_BUFFER );
                 returnErrorAndCleanupIf(pabyNewBuffer == NULL, nCurRow = -1 );
@@ -1123,8 +1248,9 @@ int FileGDBDoubleDateToOGRDate(double dfVal, OGRField* psField)
     psField->Date.Day = (GByte)brokendowntime.tm_mday;
     psField->Date.Hour = (GByte)brokendowntime.tm_hour;
     psField->Date.Minute = (GByte)brokendowntime.tm_min;
-    psField->Date.Second = (GByte)brokendowntime.tm_sec;
+    psField->Date.Second = (float)brokendowntime.tm_sec;
     psField->Date.TZFlag = 0;
+    psField->Date.Reserved = 0;
 
     return TRUE;
 }
@@ -1798,6 +1924,8 @@ FileGDBField::FileGDBField(FileGDBTable* poParent) :
     poParent(poParent), eType(FGFT_UNDEFINED), bNullable(FALSE),
     nMaxWidth(0), poIndex(NULL)
 {
+    sDefault.Set.nMarker1 = OGRUnsetMarker;
+    sDefault.Set.nMarker2 = OGRUnsetMarker;
 }
 
 /************************************************************************/
@@ -1806,6 +1934,10 @@ FileGDBField::FileGDBField(FileGDBTable* poParent) :
 
 FileGDBField::~FileGDBField()
 {
+    if( eType == FGFT_STRING &&
+        !(sDefault.Set.nMarker1 == OGRUnsetMarker &&
+          sDefault.Set.nMarker2 == OGRUnsetMarker) )
+        CPLFree(sDefault.String);
 }
 
 
@@ -1838,7 +1970,7 @@ FileGDBGeomField::FileGDBGeomField(FileGDBTable* poParent) :
     dfXOrigin(0.0), dfYOrigin(0.0), dfXYScale(0.0), dfMOrigin(0.0),
     dfMScale(0.0), dfZOrigin(0.0), dfZScale(0.0), dfXYTolerance(0.0),
     dfMTolerance(0.0), dfZTolerance(0.0), dfXMin(0.0), dfYMin(0.0),
-    dfXMax(0.0), dfYMax(0.0)
+    dfXMax(0.0), dfYMax(0.0), bHas3D(FALSE)
 {
 }
 
diff --git a/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h b/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h
index 41cc496..c250ae6 100644
--- a/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h
+++ b/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: filegdbtable.h 27640 2014-09-06 15:32:09Z rouault $
+ * $Id: filegdbtable.h 28880 2015-04-09 15:18:43Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements reading of FileGDB tables
@@ -98,6 +98,8 @@ class FileGDBField
         int               bNullable;
         int               nMaxWidth; /* for string */
 
+        OGRField          sDefault;
+
         FileGDBIndex*     poIndex;
 
     public:
@@ -110,6 +112,7 @@ class FileGDBField
         FileGDBFieldType    GetType() const { return eType; }
         int                 IsNullable() const { return bNullable; }
         int                 GetMaxWidth() const { return nMaxWidth; }
+        const OGRField     *GetDefault() const { return &sDefault; }
 
         int                 HasIndex();
         FileGDBIndex       *GetIndex();
@@ -140,6 +143,7 @@ class FileGDBGeomField: public FileGDBField
         double            dfYMin;
         double            dfXMax;
         double            dfYMax;
+        int               bHas3D;
 
     public:
                           FileGDBGeomField(FileGDBTable* poParent);
@@ -167,6 +171,8 @@ class FileGDBGeomField: public FileGDBField
         double             GetMOrigin() const { return dfMOrigin; }
         double             GetMScale() const { return dfMScale; }
         double             GetMTolerance() const { return dfMTolerance; }
+        
+        int                Has3D() const { return bHas3D; }
 };
 
 /************************************************************************/
@@ -213,6 +219,8 @@ class FileGDBTable
 {
         VSILFILE                   *fpTable;
         VSILFILE                   *fpTableX;
+        vsi_l_offset                nFileSize; /* only read when needed */
+
         std::string                 osFilename;
         std::vector<FileGDBField*>  apoFields;
         std::string                 osObjectIdColName;
@@ -224,7 +232,7 @@ class FileGDBTable
         GUInt32                     nFieldDescLength;
 
         GUInt32                     nTablxOffsetSize;
-        std::vector<vsi_l_offset>   anFeatureOffsets;
+        std::vector<vsi_l_offset>   anFeatureOffsets; /* MSb set marks deleted feature */
 
         GByte*                      pabyTablXBlockMap;
 
@@ -233,6 +241,8 @@ class FileGDBTable
 
         int                         bError;
         int                         nCurRow;
+        int                         bHasDeletedFeaturesListed;
+        int                         bIsDeleted;
         int                         nLastCol;
         GByte*                      pabyIterVals;
         int                         iAccNullable;
@@ -257,7 +267,7 @@ class FileGDBTable
         GUInt32                     nOffsetHeaderEnd;
 
         int                         ReadTableXHeader();
-        int                         IsLikelyFeatureAtOffset(vsi_l_offset nFileSize,
+        int                         IsLikelyFeatureAtOffset(
                                                 vsi_l_offset nOffset, GUInt32* pnSize,
                                                 int* pbDeletedRecord);
         int                         GuessFeatureLocations();
@@ -267,7 +277,8 @@ class FileGDBTable
                                 FileGDBTable();
                                ~FileGDBTable();
 
-       int                      Open(const char* pszFilename);
+       int                      Open(const char* pszFilename,
+                                     const char* pszLayerName = NULL);
        void                     Close();
 
        const std::string&       GetFilename() const { return osFilename; }
@@ -286,11 +297,14 @@ class FileGDBTable
        const FileGDBIndex*      GetIndex(int i) const { return apoIndexes[i]; }
 
        vsi_l_offset             GetOffsetInTableForRow(int iRow);
+       
+       int                      HasDeletedFeaturesListed() const { return bHasDeletedFeaturesListed; }
 
        /* Next call to SelectRow() or GetFieldValue() invalidates previously returned values */
        int                      SelectRow(int iRow);
        int                      HasGotError() const { return bError; }
        int                      GetCurRow() const { return nCurRow; }
+       int                      IsCurRowDeleted() const { return bIsDeleted; }
        const OGRField*          GetFieldValue(int iCol);
 
        int                      GetFeatureExtent(const OGRField* psGeomField,
diff --git a/ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h b/ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h
index 4280654..fac7ec5 100644
--- a/ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h
+++ b/ogr/ogrsf_frmts/openfilegdb/ogr_openfilegdb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
-* $Id: ogr_openfilegdb.h 27771 2014-09-30 22:45:12Z rouault $
+* $Id: ogr_openfilegdb.h 28967 2015-04-21 11:01:15Z rouault $
 *
 * Project:  OpenGIS Simple Features Reference Implementation
 * Purpose:  Implements Open FileGDB OGR driver.
@@ -68,7 +68,6 @@ class OGROpenFileGDBLayer : public OGRLayer
     int               m_iCurFeat;
     std::string       m_osDefinition;
     std::string       m_osDocumentation;
-    std::string       m_osFIDName;
     OGRwkbGeometryType m_eGeomType;
     int               m_bValidLayerDefn;
     int               m_bEOF;
@@ -116,9 +115,10 @@ public:
   int                   HasIndexForField(const char* pszFieldName);
   FileGDBIterator*      BuildIndex(const char* pszFieldName,
                                    int bAscending,
-                                   swq_op op,
+                                   int op,
                                    swq_expr_node* poValue);
   SPIState              GetSpatialIndexState() const { return m_eSpatialIndexState; }
+  int                   IsValidLayerDefn() { return BuildLayerDefinition(); }
 
   virtual const char* GetName() { return m_osName.c_str(); }
   virtual OGRwkbGeometryType GetGeomType();
@@ -127,10 +127,10 @@ public:
 
   virtual void        ResetReading();
   virtual OGRFeature* GetNextFeature();
-  virtual OGRFeature* GetFeature( long nFeatureId );
-  virtual OGRErr      SetNextByIndex( long nIndex );
+  virtual OGRFeature* GetFeature( GIntBig nFeatureId );
+  virtual OGRErr      SetNextByIndex( GIntBig nIndex );
 
-  virtual int         GetFeatureCount( int bForce = TRUE );
+  virtual GIntBig     GetFeatureCount( int bForce = TRUE );
   virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
   virtual OGRFeatureDefn* GetLayerDefn();
@@ -192,20 +192,8 @@ public:
   virtual void        ReleaseResultSet( OGRLayer * poResultsSet );
 
   virtual int         TestCapability( const char * );
-};
-
-/************************************************************************/
-/*                        OGROpenFileGDBDriver                          */
-/************************************************************************/
-
-class OGROpenFileGDBDriver : public OGRSFDriver
-{
-public:
-  virtual ~OGROpenFileGDBDriver();
-
-  virtual const char *GetName();
-  virtual OGRDataSource *Open( const char *, int );
-  virtual int TestCapability( const char * );
+  
+  virtual char      **GetFileList();
 };
 
 int OGROpenFileGDBIsComparisonOp(int op);
diff --git a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdatasource.cpp b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdatasource.cpp
index ae243cb..a06a2b7 100644
--- a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdatasource.cpp
+++ b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenfilegdbdatasource.cpp 27771 2014-09-30 22:45:12Z rouault $
+ * $Id: ogropenfilegdbdatasource.cpp 29024 2015-04-26 10:42:08Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Open FileGDB OGR driver.
@@ -151,9 +151,10 @@ int OGROpenFileGDBDataSource::Open( const char* pszFilename )
             OGROpenFileGDBLayer* poLayer = new OGROpenFileGDBLayer(
                                 m_pszName, pszLyrName, "", "");
             const char* pszTablX = CPLResetExtension(m_pszName, "gdbtablx");
-            if( !FileExists(pszTablX) &&
-                poLayer->GetLayerDefn()->GetFieldCount() == 0 &&
-                poLayer->GetFeatureCount() == 0 )
+            if( (!FileExists(pszTablX) &&
+                 poLayer->GetLayerDefn()->GetFieldCount() == 0 &&
+                 poLayer->GetFeatureCount() == 0) ||
+                !poLayer->IsValidLayerDefn() )
             {
                 delete poLayer;
                 return FALSE;
@@ -426,6 +427,7 @@ int OGROpenFileGDBDataSource::OpenFileGDBv9(int iGDBFeatureClasses,
                 /* Is it a non-spatial table ? */
                 if( strcmp(psField->String, "{7A566981-C114-11D2-8A28-006097AFF44E}") == 0 )
                 {
+                    aosName.push_back( "" );
                     AddLayer( osName, nInterestTable, nCandidateLayers, nLayersSDC,
                               "", "", NULL, wkbNone );
                 }
@@ -596,6 +598,7 @@ OGROpenFileGDBSingleFeatureLayer::OGROpenFileGDBSingleFeatureLayer(const char* p
                                                                    const char *pszVal )
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     OGRFieldDefn oField( "FIELD_1", OFTString );
     poFeatureDefn->AddFieldDefn( &oField );
@@ -651,13 +654,13 @@ class OGROpenFileGDBSimpleSQLLayer: public OGRLayer
 
        virtual void        ResetReading();
        virtual OGRFeature* GetNextFeature();
-       virtual OGRFeature* GetFeature( long nFeatureId );
+       virtual OGRFeature* GetFeature( GIntBig nFeatureId );
        virtual OGRFeatureDefn* GetLayerDefn() { return poFeatureDefn; }
        virtual int         TestCapability( const char * );
        virtual const char* GetFIDColumn() { return poBaseLayer->GetFIDColumn(); }
        virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce )
                             { return poBaseLayer->GetExtent(psExtent, bForce); }
-       virtual int         GetFeatureCount(int bForce);
+       virtual GIntBig     GetFeatureCount(int bForce);
 };
 
 /***********************************************************************/
@@ -702,6 +705,7 @@ OGROpenFileGDBSimpleSQLLayer::OGROpenFileGDBSimpleSQLLayer(
             }
         }
     }
+    SetDescription( poFeatureDefn->GetName() );
     ResetReading();
 }
 
@@ -731,7 +735,7 @@ void OGROpenFileGDBSimpleSQLLayer::ResetReading()
 /*                          GetFeature()                               */
 /***********************************************************************/
 
-OGRFeature* OGROpenFileGDBSimpleSQLLayer::GetFeature( long nFeatureId )
+OGRFeature* OGROpenFileGDBSimpleSQLLayer::GetFeature( GIntBig nFeatureId )
 {
     OGRFeature* poSrcFeature = poBaseLayer->GetFeature(nFeatureId);
     if( poSrcFeature == NULL )
@@ -780,7 +784,7 @@ OGRFeature* OGROpenFileGDBSimpleSQLLayer::GetNextFeature()
 /*                         GetFeatureCount()                           */
 /***********************************************************************/
 
-int OGROpenFileGDBSimpleSQLLayer::GetFeatureCount( int bForce )
+GIntBig OGROpenFileGDBSimpleSQLLayer::GetFeatureCount( int bForce )
 {
 
     /* No filter */
@@ -924,7 +928,8 @@ OGRLayer* OGROpenFileGDBDataSource::ExecuteSQL( const char *pszSQLCommand,
 /*      MIN/MAX/SUM/AVG/COUNT optimization                              */
 /* -------------------------------------------------------------------- */
         if( oSelect.join_count == 0 && oSelect.poOtherSelect == NULL &&
-            oSelect.table_count == 1 && oSelect.order_specs == 0 )
+            oSelect.table_count == 1 && oSelect.order_specs == 0 &&
+            oSelect.query_mode != SWQM_DISTINCT_LIST )
         {
             OGROpenFileGDBLayer* poLayer = 
                 (OGROpenFileGDBLayer*)GetLayerByName( oSelect.table_defs[0].table_name);
@@ -1054,7 +1059,8 @@ OGRLayer* OGROpenFileGDBDataSource::ExecuteSQL( const char *pszSQLCommand,
 /*      ORDER BY optimization                                           */
 /* -------------------------------------------------------------------- */
         if( oSelect.join_count == 0 && oSelect.poOtherSelect == NULL &&
-            oSelect.table_count == 1 && oSelect.order_specs == 1 )
+            oSelect.table_count == 1 && oSelect.order_specs == 1 &&
+            oSelect.query_mode != SWQM_DISTINCT_LIST )
         {
             OGROpenFileGDBLayer* poLayer = 
                 (OGROpenFileGDBLayer*)GetLayerByName( oSelect.table_defs[0].table_name);
@@ -1105,11 +1111,11 @@ OGRLayer* OGROpenFileGDBDataSource::ExecuteSQL( const char *pszSQLCommand,
                 }
                 if( eErr == OGRERR_NONE )
                 {
-                    swq_op op = SWQ_UNKNOWN;
+                    int op = -1;
                     swq_expr_node* poValue = NULL;
                     if( oSelect.where_expr != NULL )
                     {
-                        op = (swq_op)oSelect.where_expr->nOperation;
+                        op = oSelect.where_expr->nOperation;
                         poValue = oSelect.where_expr->papoSubExpr[1];
                     }
 
@@ -1151,3 +1157,36 @@ void OGROpenFileGDBDataSource::ReleaseResultSet( OGRLayer * poResultsSet )
 {
     delete poResultsSet;
 }
+
+/***********************************************************************/
+/*                           GetFileList()                             */
+/***********************************************************************/
+
+char** OGROpenFileGDBDataSource::GetFileList()
+{
+    int nInterestTable = -1;
+    const char* pszFilenameWithoutPath = CPLGetFilename(m_pszName);
+    CPLString osFilenameRadix;
+    if( strlen(pszFilenameWithoutPath) == strlen("a00000000.gdbtable") &&
+        pszFilenameWithoutPath[0] == 'a' &&
+        sscanf(pszFilenameWithoutPath, "a%08x.gdbtable", &nInterestTable) == 1 )
+    {
+        osFilenameRadix = CPLSPrintf("a%08x.", nInterestTable);
+    }
+
+    char** papszFiles = VSIReadDir(m_osDirName);
+    CPLStringList osStringList;
+    char** papszIter = papszFiles;
+    for( ; papszIter != NULL && *papszIter != NULL ; papszIter ++ )
+    {
+        if( strcmp(*papszIter, ".") == 0 || strcmp(*papszIter, "..") == 0 )
+            continue;
+        if( osFilenameRadix.size() == 0 ||
+            strncmp(*papszIter, osFilenameRadix, osFilenameRadix.size()) == 0 )
+        {
+            osStringList.AddString(CPLFormFilename(m_osDirName, *papszIter, NULL));
+        }
+    }
+    CSLDestroy(papszFiles);
+    return osStringList.StealList();
+}
diff --git a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdriver.cpp b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdriver.cpp
index aac9604..ea4a23c 100644
--- a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdriver.cpp
+++ b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenfilegdbdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogropenfilegdbdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Open FileGDB OGR driver.
@@ -35,37 +35,17 @@ CPL_CVSID("$Id");
 
 extern "C" void RegisterOGROpenFileGDB();
 
-/************************************************************************/
-/*                     ~OGROpenFileGDBDriver()                          */
-/************************************************************************/
-OGROpenFileGDBDriver::~OGROpenFileGDBDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGROpenFileGDBDriver::GetName()
-
-{
-    return "OpenFileGDB";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
 
 #define ENDS_WITH(str, strLen, end) \
     (strLen >= strlen(end) && EQUAL(str + strLen - strlen(end), end))
 
-OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate )
+/************************************************************************/
+/*                         OGROpenFileGDBDriverIdentify()               */
+/************************************************************************/
 
+static int OGROpenFileGDBDriverIdentifyInternal( GDALOpenInfo* poOpenInfo,
+                                         const char*& pszFilename )
 {
-    VSIStatBufL stat;
-    if( bUpdate )
-        return NULL;
 #ifdef FOR_FUSIL
     CPLString osOrigFilename(pszFilename);
 #endif
@@ -81,15 +61,18 @@ OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate
         /* (http://trac.osgeo.org/osgeo4w/ticket/245) */
         if( strncmp(pszFilename, "/vsicurl/https://github.com/",
                     strlen("/vsicurl/https://github.com/")) == 0 ||
-            VSIStatL( pszFilename, &stat ) != 0 || !VSI_ISDIR(stat.st_mode) )
+            !poOpenInfo->bStatOK ||
+            !poOpenInfo->bIsDirectory )
         {
             /* In case we don't manage to list the directory, try to stat one file */
+            VSIStatBufL stat;
             if( !(strncmp(pszFilename, "/vsicurl/", strlen("/vsicurl/")) == 0 &&
                   VSIStatL( CPLFormFilename(pszFilename, "a00000001", "gdbtable"), &stat ) == 0) )
             {
-                return NULL;
+                return FALSE;
             }
         }
+        return TRUE;
     }
     /* We also accept zipped GDB */
     else if( ENDS_WITH(pszFilename, nLen, ".gdb.zip") ||
@@ -99,12 +82,12 @@ OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate
               (strstr(pszFilename, "_gdb") != NULL ||
                strstr(pszFilename, "_GDB") != NULL)) )
     {
-
+        return TRUE;
     }
     /* We also accept tables themselves */
     else if( ENDS_WITH(pszFilename, nLen, ".gdbtable") )
     {
-
+        return TRUE;
     }
 #ifdef FOR_FUSIL
     /* To be able to test fuzzer on any auxiliary files used (indexes, etc.) */
@@ -114,6 +97,7 @@ OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate
         pszFilename = CPLFormFilename(CPLGetPath(pszFilename),
                                       CPLGetBasename(pszFilename),
                                       "gdbtable");
+        return TRUE;
     }
     else if( strlen(CPLGetBasename(CPLGetBasename(pszFilename))) == 9 &&
              CPLGetBasename(CPLGetBasename(pszFilename))[0] == 'a' )
@@ -121,12 +105,36 @@ OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate
         pszFilename = CPLFormFilename(CPLGetPath(pszFilename),
                                       CPLGetBasename(CPLGetBasename(pszFilename)),
                                       "gdbtable");
+        return TRUE;
     }
 #endif
     else
     {
-        return NULL;
+        return FALSE;
     }
+}
+
+static int OGROpenFileGDBDriverIdentify( GDALOpenInfo* poOpenInfo )
+{
+    const char* pszFilename = poOpenInfo->pszFilename;
+    return OGROpenFileGDBDriverIdentifyInternal( poOpenInfo, pszFilename );
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+static GDALDataset* OGROpenFileGDBDriverOpen( GDALOpenInfo* poOpenInfo )
+
+{
+    if( poOpenInfo->eAccess == GA_Update )
+        return NULL;
+    const char* pszFilename = poOpenInfo->pszFilename;
+#ifdef FOR_FUSIL
+    CPLString osOrigFilename(pszFilename);
+#endif
+    if( OGROpenFileGDBDriverIdentifyInternal( poOpenInfo, pszFilename ) == FALSE )
+        return NULL;
 
 #ifdef FOR_FUSIL
     const char* pszSrcDir = CPLGetConfigOption("FUSIL_SRC_DIR", NULL);
@@ -163,16 +171,6 @@ OGRDataSource *OGROpenFileGDBDriver::Open( const char* pszFilename, int bUpdate
 }
 
 /***********************************************************************/
-/*                         TestCapability()                            */
-/***********************************************************************/
-
-int OGROpenFileGDBDriver::TestCapability( const char * pszCap )
-{
-    (void)pszCap;
-    return FALSE;
-}
-
-/***********************************************************************/
 /*                       RegisterOGROpenFileGDB()                      */
 /***********************************************************************/
 
@@ -181,5 +179,25 @@ void RegisterOGROpenFileGDB()
 {
     if (! GDAL_CHECK_VERSION("OGR OpenFileGDB"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGROpenFileGDBDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "OpenFileGDB" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "OpenFileGDB" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "ESRI FileGDB" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gdb" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_openfilegdb.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGROpenFileGDBDriverOpen;
+        poDriver->pfnIdentify = OGROpenFileGDBDriverIdentify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdblayer.cpp b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdblayer.cpp
index 33e916f..ce8ebcd 100644
--- a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdblayer.cpp
+++ b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdblayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogropenfilegdblayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogropenfilegdblayer.cpp 28967 2015-04-21 11:01:15Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Open FileGDB OGR driver.
@@ -98,6 +98,32 @@ class OGROpenFileGDBFeatureDefn: public OGRFeatureDefn
             }
             return nFieldCount;
         }
+
+        virtual int GetGeomFieldCount()
+        {
+            /* FileGDB v9 case */
+            if( !m_bHasBuildFieldDefn &&
+                m_poLayer != NULL && m_poLayer->m_eGeomType != wkbNone &&
+                m_poLayer->m_osDefinition.size() == 0 )
+            {
+                m_bHasBuildFieldDefn = TRUE;
+                (void) m_poLayer->BuildLayerDefinition();
+            }
+            return nGeomFieldCount;
+        }
+
+        virtual OGRGeomFieldDefn* GetGeomFieldDefn( int i )
+        {
+            /* FileGDB v9 case */
+            if( !m_bHasBuildFieldDefn &&
+                m_poLayer != NULL && m_poLayer->m_eGeomType != wkbNone &&
+                m_poLayer->m_osDefinition.size() == 0 )
+            {
+                m_bHasBuildFieldDefn = TRUE;
+                (void) m_poLayer->BuildLayerDefinition();
+            }
+            return OGRFeatureDefn::GetGeomFieldDefn(i);
+        }
 };
 
 /************************************************************************/
@@ -108,7 +134,7 @@ OGROpenFileGDBLayer::OGROpenFileGDBLayer(const char* pszGDBFilename,
                                          const char* pszName,
                                          const std::string& osDefinition,
                                          const std::string& osDocumentation,
-                                         const char* pszGeomName,
+                                         CPL_UNUSED const char* pszGeomName,
                                          OGRwkbGeometryType eGeomType) :
             m_osGDBFilename(pszGDBFilename),
             m_osName(pszName),
@@ -118,7 +144,7 @@ OGROpenFileGDBLayer::OGROpenFileGDBLayer(const char* pszGDBFilename,
             m_iCurFeat(0),
             m_osDefinition(osDefinition),
             m_osDocumentation(osDocumentation),
-            m_eGeomType(eGeomType),
+            m_eGeomType(wkbNone),
             m_bValidLayerDefn(-1),
             m_bEOF(FALSE),
             m_poGeomConverter(NULL),
@@ -132,17 +158,15 @@ OGROpenFileGDBLayer::OGROpenFileGDBLayer(const char* pszGDBFilename,
             m_nFilteredFeatureCount(-1)
 {
     m_poFeatureDefn = new OGROpenFileGDBFeatureDefn(this, pszName);
+    SetDescription( m_poFeatureDefn->GetName() );
     m_poFeatureDefn->SetGeomType(wkbNone);
     m_poFeatureDefn->Reference();
 
-    if( m_osDefinition.size() && BuildGeometryColumnGDBv10() )
-    {
-        ;
-    }
-    else if( eGeomType != wkbNone )
+    m_eGeomType = eGeomType;
+
+    if( m_osDefinition.size() )
     {
-        m_poFeatureDefn->AddGeomFieldDefn(
-            new OGROpenFileGDBGeomFieldDefn(this, pszGeomName, eGeomType), FALSE);
+        (void) BuildGeometryColumnGDBv10();
     }
 }
 
@@ -200,7 +224,7 @@ int OGROpenFileGDBLayer::BuildGeometryColumnGDBv10()
         m_eGeomType =
             FileGDBOGRGeometryConverter::GetGeometryTypeFromESRI(pszShapeType);
         if( bHasZ )
-            m_eGeomType = (OGRwkbGeometryType)( m_eGeomType | wkb25DBit );
+            m_eGeomType = wkbSetZ( m_eGeomType );
 
         const char* pszWKT = CPLGetXMLValue( psInfo, "SpatialReference.WKT", NULL );
         int nWKID = atoi(CPLGetXMLValue( psInfo, "SpatialReference.WKID", "0" ));
@@ -210,6 +234,24 @@ int OGROpenFileGDBLayer::BuildGeometryColumnGDBv10()
         OGROpenFileGDBGeomFieldDefn* poGeomFieldDefn =
             new OGROpenFileGDBGeomFieldDefn(NULL, pszShapeFieldName, m_eGeomType);
 
+        CPLXMLNode* psGPFieldInfoExs = CPLGetXMLNode(psInfo, "GPFieldInfoExs");
+        if( psGPFieldInfoExs )
+        {
+            for(CPLXMLNode* psChild = psGPFieldInfoExs->psChild;
+                            psChild != NULL;
+                            psChild = psChild->psNext )
+            {
+                if( psChild->eType != CXT_Element )
+                    continue;
+                if( EQUAL(psChild->pszValue, "GPFieldInfoEx") &&
+                    EQUAL(CPLGetXMLValue(psChild, "Name", ""), pszShapeFieldName) )
+                {
+                    poGeomFieldDefn->SetNullable( CSLTestBoolean(CPLGetXMLValue( psChild, "IsNullable", "TRUE" )) );
+                    break;
+                }
+            }
+        }
+
         OGRSpatialReference* poSRS = NULL;
         if( nWKID > 0 || nLatestWKID > 0 )
         {
@@ -281,7 +323,7 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
         return m_bValidLayerDefn;
 
     m_poLyrTable = new FileGDBTable();
-    if( !(m_poLyrTable->Open(m_osGDBFilename)) )
+    if( !(m_poLyrTable->Open(m_osGDBFilename, GetDescription())) )
     {
         delete m_poLyrTable;
         m_poLyrTable = NULL;
@@ -318,6 +360,7 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
 
     if( m_osDefinition.size() == 0 && m_iGeomFieldIdx >= 0 )
     {
+        /* FileGDB v9 case */
         FileGDBGeomField* poGDBGeomField =
             (FileGDBGeomField* )m_poLyrTable->GetField(m_iGeomFieldIdx);
         const char* pszName = poGDBGeomField->GetName().c_str();
@@ -333,27 +376,24 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
             case FGTGT_POLYGON: eGeomType = wkbMultiPolygon; break;
             case FGTGT_MULTIPATCH: eGeomType = wkbMultiPolygon; break;
         }
-        if( m_eGeomType == wkbUnknown )
-            m_eGeomType = eGeomType;
-        if( eGeomType != m_eGeomType )
+
+        if( wkbFlatten(eGeomType) != wkbFlatten(m_eGeomType) )
         {
             CPLError(CE_Warning, CPLE_AppDefined,
                      "Inconsistency for layer geometry type");
         }
 
+        m_eGeomType = eGeomType;
+        if( poGDBGeomField->Has3D() )
+            m_eGeomType = wkbSetZ(m_eGeomType);
+
         OGROpenFileGDBGeomFieldDefn* poGeomFieldDefn;
-        if( m_poFeatureDefn->GetGeomFieldCount() == 0 )
-        {
-            poGeomFieldDefn =
-                    new OGROpenFileGDBGeomFieldDefn(NULL, pszName, m_eGeomType);
-            m_poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
-        }
-        else
-        {
-            poGeomFieldDefn = (OGROpenFileGDBGeomFieldDefn*)
-                                        m_poFeatureDefn->GetGeomFieldDefn(0);
-            poGeomFieldDefn->SetType(m_eGeomType);
-        }
+
+        poGeomFieldDefn =
+                new OGROpenFileGDBGeomFieldDefn(NULL, pszName, m_eGeomType);
+        poGeomFieldDefn->SetNullable(poGDBGeomField->IsNullable());
+
+        m_poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
 
         OGRSpatialReference* poSRS = NULL;
         if( poGDBGeomField->GetWKT().size() && 
@@ -372,6 +412,13 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
             poSRS->Dereference();
         }
     }
+    else if( m_osDefinition.size() == 0 && m_iGeomFieldIdx < 0 )
+    {
+        m_eGeomType = wkbNone;
+    }
+
+    CPLXMLNode* psTree = NULL;
+    CPLXMLNode* psGPFieldInfoExs = NULL;
 
     for(int i=0;i<m_poLyrTable->GetFieldCount();i++)
     {
@@ -380,14 +427,21 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
 
         const FileGDBField* poGDBField = m_poLyrTable->GetField(i);
         OGRFieldType eType = OFTString;
-        /* int nWidth = 0; */
+        OGRFieldSubType eSubType = OFSTNone;
+        int nWidth = poGDBField->GetMaxWidth();
         switch( poGDBField->GetType() )
         {
             case FGFT_INT16:
+                eType = OFTInteger;
+                eSubType = OFSTInt16;
+                break;
             case FGFT_INT32:
                 eType = OFTInteger;
                 break;
             case FGFT_FLOAT32:
+                eType = OFTReal;
+                eSubType = OFSTFloat32;
+                break;
             case FGFT_FLOAT64:
                 eType = OFTReal;
                 break;
@@ -425,10 +479,118 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
             }
         }
         OGRFieldDefn oFieldDefn(poGDBField->GetName().c_str(), eType);
-        /* oFieldDefn.SetWidth(nWidth); */
+        oFieldDefn.SetSubType(eSubType);
+        /* On creation in the FileGDB driver (GDBFieldTypeToWidthPrecision) if string width is 0, we pick up */
+        /* 65535 by default to mean unlimited string length, but we don't want */
+        /* to advertize such a big number */
+        if( eType == OFTString && nWidth < 65535 )
+            oFieldDefn.SetWidth(nWidth);
+        oFieldDefn.SetNullable(poGDBField->IsNullable());
+        const OGRField* psDefault = poGDBField->GetDefault();
+        if( !(psDefault->Set.nMarker1 == OGRUnsetMarker &&
+              psDefault->Set.nMarker2 == OGRUnsetMarker) )
+        {
+            if( eType == OFTString )
+            {
+                CPLString osDefault("'");
+                char* pszTmp = CPLEscapeString(psDefault->String, -1, CPLES_SQL);
+                osDefault += pszTmp;
+                CPLFree(pszTmp);
+                osDefault += "'";
+                oFieldDefn.SetDefault(osDefault);
+            }
+            else if( eType == OFTInteger || eType == OFTReal )
+            {
+                /* GDBs and the FileGDB SDK aren't always reliable for numeric values */
+                /* It often occurs that the XML definition in a00000004.gdbtable doesn't */
+                /* match the default values (in binary) found in the field definition */
+                /* section of the .gdbtable of the layers themselves */
+                /* So check consistency */
+                if( m_osDefinition.size() && psTree == NULL )
+                {
+                    psTree = CPLParseXMLString(m_osDefinition.c_str());
+                    if( psTree != NULL )
+                    {
+                        CPLStripXMLNamespace( psTree, NULL, TRUE );
+                        CPLXMLNode* psInfo = CPLSearchXMLNode( psTree, "=DEFeatureClassInfo" );
+                        if( psInfo == NULL )
+                            psInfo = CPLSearchXMLNode( psTree, "=DETableInfo" );
+                        if( psInfo != NULL )
+                            psGPFieldInfoExs = CPLGetXMLNode(psInfo, "GPFieldInfoExs");
+                    }
+                }
+                const char* pszDefaultValue = NULL;
+                if( psGPFieldInfoExs != NULL )
+                {
+                    for(CPLXMLNode* psChild = psGPFieldInfoExs->psChild;
+                                    psChild != NULL;
+                                    psChild = psChild->psNext )
+                    {
+                        if( psChild->eType != CXT_Element )
+                            continue;
+                        if( EQUAL(psChild->pszValue, "GPFieldInfoEx") &&
+                            EQUAL(CPLGetXMLValue(psChild, "Name", ""), poGDBField->GetName().c_str()) )
+                        {
+                            /* From ArcGIS this is called DefaultValueNumeric for integer and real */
+                            /* From FileGDB API this is called DefaultValue xsi:type=xs:int for integer and DefaultValueNumeric for real ... */
+                            pszDefaultValue = CPLGetXMLValue( psChild, "DefaultValueNumeric", NULL );
+                            if( pszDefaultValue == NULL )
+                                pszDefaultValue = CPLGetXMLValue( psChild, "DefaultValue", NULL );
+                            break;
+                        }
+                    }
+                }
+                if( pszDefaultValue != NULL )
+                {
+                    if( eType == OFTInteger )
+                    {
+                        if ( atoi(pszDefaultValue) != psDefault->Integer)
+                        {
+                            CPLDebug("OpenFileGDB", "For field %s, XML definition mentions %s "
+                                     "as default value whereas .gdbtable header mentions %d. Using %s",
+                                     poGDBField->GetName().c_str(),
+                                     pszDefaultValue,
+                                     psDefault->Integer,
+                                     pszDefaultValue);
+                        }
+                        oFieldDefn.SetDefault(pszDefaultValue);
+                    }
+                    else if( eType == OFTReal )
+                    {
+                        if( fabs(CPLAtof(pszDefaultValue) -  psDefault->Real) > 1e-15 )
+                        {
+                            CPLDebug("OpenFileGDB", "For field %s, XML definition mentions %s "
+                                     "as default value whereas .gdbtable header mentions %.18g. Using %s",
+                                     poGDBField->GetName().c_str(),
+                                     pszDefaultValue,
+                                     psDefault->Real,
+                                     pszDefaultValue);
+                        }
+                        oFieldDefn.SetDefault(pszDefaultValue);
+                    }
+                }
+            }
+            else if( eType == OFTDateTime )
+                oFieldDefn.SetDefault(CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
+                                                 psDefault->Date.Year,
+                                                 psDefault->Date.Month,
+                                                 psDefault->Date.Day,
+                                                 psDefault->Date.Hour,
+                                                 psDefault->Date.Minute,
+                                                 (int)psDefault->Date.Second));
+        }
         m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
     }
 
+    if( m_poLyrTable->HasDeletedFeaturesListed() )
+    {
+        OGRFieldDefn oFieldDefn("_deleted_", OFTInteger);
+        m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
+    }
+
+    if( psTree != NULL )
+        CPLDestroyXMLNode(psTree);
+
     return TRUE;
 }
 
@@ -438,7 +600,8 @@ int OGROpenFileGDBLayer::BuildLayerDefinition()
 
 OGRwkbGeometryType OGROpenFileGDBLayer::GetGeomType()
 {
-    if( m_eGeomType == wkbUnknown )
+    if( m_eGeomType == wkbUnknown ||
+        m_osDefinition.size() == 0 /* FileGDB v9 case */ )
     {
         (void) BuildLayerDefinition();
     }
@@ -461,9 +624,6 @@ OGRFeatureDefn* OGROpenFileGDBLayer::GetLayerDefn()
 
 const char* OGROpenFileGDBLayer::GetFIDColumn()
 {
-    if( m_osFIDName.size() )
-        return m_osFIDName.c_str();
-
     if( !BuildLayerDefinition() )
         return "";
     return m_poLyrTable->GetObjectIdColName().c_str();
@@ -562,11 +722,11 @@ static int CompValues(OGRFieldDefn* poFieldDefn,
             if (poValue1->field_type == SWQ_FLOAT)
                 n1 = (int) poValue1->float_value;
             else
-                n1 = poValue1->int_value;
+                n1 = (int) poValue1->int_value;
             if (poValue2->field_type == SWQ_FLOAT)
                 n2 = (int) poValue2->float_value;
             else
-                n2 = poValue2->int_value;
+                n2 = (int) poValue2->int_value;
             if( n1 < n2 )
                 return -1;
             if( n1 == n2 )
@@ -725,7 +885,7 @@ int FillTargetValueFromSrcExpr( OGRFieldDefn* poFieldDefn,
             if (poSrcValue->field_type == SWQ_FLOAT)
                 poTargetValue->Integer = (int) poSrcValue->float_value;
             else
-                poTargetValue->Integer = poSrcValue->int_value;
+                poTargetValue->Integer = (int) poSrcValue->int_value;
             break;
 
         case OFTReal:
@@ -758,6 +918,7 @@ int FillTargetValueFromSrcExpr( OGRFieldDefn* poFieldDefn,
                     poTargetValue->Date.Minute = (GByte)nMin;
                     poTargetValue->Date.Second = (GByte)nSec;
                     poTargetValue->Date.TZFlag = 0;
+                    poTargetValue->Date.Reserved = 0;
                 }
                 else
                     return FALSE;
@@ -818,7 +979,7 @@ FileGDBIterator* OGROpenFileGDBLayer::BuildIteratorFromExprNode(swq_expr_node* p
         poNode->nOperation == SWQ_AND && poNode->nSubExprCount == 2 )
     {
         /* Even if there's only one branch of the 2 that results to an iterator, */
-        /* it is usefull. Of course, the iterator will not be sufficient to evaluate */
+        /* it is useful. Of course, the iterator will not be sufficient to evaluate */
         /* the filter, but it will be a super-set of the features */
         FileGDBIterator* poIter1 = BuildIteratorFromExprNode(poNode->papoSubExpr[0]);
 
@@ -971,47 +1132,6 @@ FileGDBIterator* OGROpenFileGDBLayer::BuildIteratorFromExprNode(swq_expr_node* p
         }
     }
     else if( poNode->eNodeType == SNT_OPERATION &&
-        poNode->nOperation == SWQ_BETWEEN && poNode->nSubExprCount == 3 )
-    {
-        swq_expr_node *poColumn = poNode->papoSubExpr[0];
-        swq_expr_node *poValue1 = poNode->papoSubExpr[1];
-        swq_expr_node *poValue2 = poNode->papoSubExpr[2];
-        if( poColumn->eNodeType == SNT_COLUMN &&
-            poColumn->field_index < GetLayerDefn()->GetFieldCount() &&
-            poValue1->eNodeType == SNT_CONSTANT &&
-            poValue2->eNodeType == SNT_CONSTANT )
-        {
-            OGRFieldDefn *poFieldDefn;
-            poFieldDefn = GetLayerDefn()->GetFieldDefn(poColumn->field_index);
-
-            int nTableColIdx = m_poLyrTable->GetFieldIdx(poFieldDefn->GetNameRef());
-            if( nTableColIdx >= 0 && m_poLyrTable->GetField(nTableColIdx)->HasIndex() )
-            {
-                OGRField sValue1, sValue2;
-
-                if( FillTargetValueFromSrcExpr(poFieldDefn, &sValue1, poValue1) &&
-                    FillTargetValueFromSrcExpr(poFieldDefn, &sValue2, poValue2) )
-                {
-                    FileGDBIterator* poIter1 = FileGDBIterator::Build(
-                                            m_poLyrTable, nTableColIdx, TRUE,
-                                            FGSO_GE,
-                                            poFieldDefn->GetType(), &sValue1);
-                    FileGDBIterator* poIter2 = FileGDBIterator::Build(
-                                            m_poLyrTable, nTableColIdx, TRUE,
-                                            FGSO_LE,
-                                            poFieldDefn->GetType(), &sValue2);
-                    if( poIter1 != NULL && poIter2 != NULL )
-                    {
-                        m_bIteratorSufficientToEvaluateFilter = TRUE;
-                        return FileGDBIterator::BuildAnd(poIter1, poIter2);
-                    }
-                    delete poIter1;
-                    delete poIter2;
-                }
-            }
-        }
-    }
-    else if( poNode->eNodeType == SNT_OPERATION &&
              poNode->nOperation == SWQ_IN && poNode->nSubExprCount >= 2 )
     {
         swq_expr_node *poColumn = poNode->papoSubExpr[0];
@@ -1110,7 +1230,8 @@ OGRErr OGROpenFileGDBLayer::SetAttributeFilter( const char* pszFilter )
 
     if( m_poAttrQuery != NULL && m_nFilteredFeatureCount < 0 )
     {
-        swq_expr_node* poNode = (swq_expr_node*) m_poAttrQuery->GetSWGExpr();
+        swq_expr_node* poNode = (swq_expr_node*) m_poAttrQuery->GetSWQExpr();
+        poNode->ReplaceBetweenByGEAndLERecurse();
         m_bIteratorSufficientToEvaluateFilter = -1;
         m_poIterator = BuildIteratorFromExprNode(poNode);
         if( m_poIterator != NULL && m_eSpatialIndexState == SPI_IN_BUILDING )
@@ -1208,6 +1329,13 @@ OGRFeature* OGROpenFileGDBLayer::GetCurrentFeature()
 
     if( poFeature == NULL )
         poFeature = new OGRFeature(m_poFeatureDefn);
+    
+    if( m_poLyrTable->HasDeletedFeaturesListed() )
+    {
+        poFeature->SetField(poFeature->GetFieldCount() - 1,
+                            m_poLyrTable->IsCurRowDeleted());
+    }
+
     poFeature->SetFID(iRow + 1);
     return poFeature;
 }
@@ -1312,7 +1440,7 @@ OGRFeature* OGROpenFileGDBLayer::GetNextFeature()
 /*                          GetFeature()                               */
 /***********************************************************************/
 
-OGRFeature* OGROpenFileGDBLayer::GetFeature( long nFeatureId )
+OGRFeature* OGROpenFileGDBLayer::GetFeature( GIntBig nFeatureId )
 {
     if( !BuildLayerDefinition() )
         return NULL;
@@ -1343,7 +1471,7 @@ OGRFeature* OGROpenFileGDBLayer::GetFeature( long nFeatureId )
 /*                         SetNextByIndex()                            */
 /***********************************************************************/
 
-OGRErr OGROpenFileGDBLayer::SetNextByIndex( long nIndex )
+OGRErr OGROpenFileGDBLayer::SetNextByIndex( GIntBig nIndex )
 {
     if( m_poIterator != NULL )
         return OGRLayer::SetNextByIndex(nIndex);
@@ -1358,14 +1486,14 @@ OGRErr OGROpenFileGDBLayer::SetNextByIndex( long nIndex )
     {
         if( nIndex < 0 || nIndex >= m_nFilteredFeatureCount )
             return OGRERR_FAILURE;
-        m_iCurFeat = nIndex;
+        m_iCurFeat = (int) nIndex;
         return OGRERR_NONE;
     }
     else if( m_poLyrTable->GetValidRecordCount() == m_poLyrTable->GetTotalRecordCount() )
     {
         if( nIndex < 0 || nIndex >= m_poLyrTable->GetValidRecordCount() )
             return OGRERR_FAILURE;
-        m_iCurFeat = nIndex;
+        m_iCurFeat = (int) nIndex;
         return OGRERR_NONE;
     }
     else
@@ -1401,7 +1529,7 @@ OGRErr OGROpenFileGDBLayer::GetExtent( OGREnvelope *psExtent, int bForce )
 /*                         GetFeatureCount()                           */
 /***********************************************************************/
 
-int OGROpenFileGDBLayer::GetFeatureCount( int bForce )
+GIntBig OGROpenFileGDBLayer::GetFeatureCount( int bForce )
 {
     if( !BuildLayerDefinition() )
         return 0;
@@ -1561,7 +1689,7 @@ int OGROpenFileGDBLayer::HasIndexForField(const char* pszFieldName)
 
 FileGDBIterator* OGROpenFileGDBLayer::BuildIndex(const char* pszFieldName,
                                                  int bAscending,
-                                                 swq_op op,
+                                                 int op,
                                                  swq_expr_node* poValue)
 {
     if( !BuildLayerDefinition() )
@@ -1575,7 +1703,7 @@ FileGDBIterator* OGROpenFileGDBLayer::BuildIndex(const char* pszFieldName,
     int nTableColIdx = m_poLyrTable->GetFieldIdx(pszFieldName);
     if( nTableColIdx >= 0 && m_poLyrTable->GetField(nTableColIdx)->HasIndex() )
     {
-        if( op == SWQ_UNKNOWN )
+        if( op < 0 )
             return FileGDBIterator::BuildIsNotNull(m_poLyrTable, nTableColIdx, bAscending);
         else
         {
diff --git a/ogr/ogrsf_frmts/osm/GNUmakefile b/ogr/ogrsf_frmts/osm/GNUmakefile
index e738159..622b8b7 100644
--- a/ogr/ogrsf_frmts/osm/GNUmakefile
+++ b/ogr/ogrsf_frmts/osm/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ =	ogrosmdriver.o ogrosmdatasource.o ogrosmlayer.o osm_parser.o
 
-CPPFLAGS :=	-I.. -I../.. -I../sqlite -I../generic $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
+CPPFLAGS :=	-I.. -I../.. -I../sqlite -I../generic  $(EXPAT_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
 
 ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=  -DHAVE_EXPAT
diff --git a/ogr/ogrsf_frmts/osm/drv_osm.html b/ogr/ogrsf_frmts/osm/drv_osm.html
index 0c11e35..bf82d1b 100644
--- a/ogr/ogrsf_frmts/osm/drv_osm.html
+++ b/ogr/ogrsf_frmts/osm/drv_osm.html
@@ -27,12 +27,16 @@ The driver will categorize features into 5 layers :
 
 <h3>Configuration</h3>
 
-In the <i>data</i> folder of the GDAL distribution, you can find a <i>osmconf.ini</i> file that can be
+In the <i>data</i> folder of the GDAL distribution, you can find a
+<i><a href="http://svn.osgeo.org/gdal/trunk/gdal/data/osmconf.ini">osmconf.ini</a></i> file that can be
 customized to fit your needs. You can also define an alternate path with the OSM_CONFIG_FILE configuration
 option.<p>
 
 The customization is essentially which OSM attributes and keys should be translated into OGR layer fields.<p>
 
+Starting with GDAL 2.0, fields can be computed with SQL expressions (evaluated by SQLite engine)
+from other fields/tags. For example to compute the z_order attribute.<p>
+
 <h3>"other_tags" field</h3>
 
 When keys are not strictly identified in the <i>osmconf.ini</i> file, the key/value pair is appended
@@ -65,7 +69,7 @@ situations (non increasing node ids, or node ids not in expected range), it migh
 output an error message suggesting to relaunch by defining the OSM_USE_CUSTOM_INDEXING configuration option to NO.<p>
 
 When custom indexing is used (default case), the OSM_COMPRESS_NODES configuration option can be set to YES (the
-default is ON). This option might be turned on to improve performances when I/O access is the limiting factor (typically
+default is NO). This option might be turned on to improve performances when I/O access is the limiting factor (typically
 the case of rotational disk), and will be mostly efficient for country-sized OSM extracts where compression rate can
 go up to a factor of 3 or 4, and help keep the node DB to a size that fit in the OS I/O caches. For whole planet file, the
 effect of this option will be less efficient. This option consumes addionnal 60 MB of RAM.<p>
diff --git a/ogr/ogrsf_frmts/osm/gpb.h b/ogr/ogrsf_frmts/osm/gpb.h
index c624fc1..5f9dd91 100644
--- a/ogr/ogrsf_frmts/osm/gpb.h
+++ b/ogr/ogrsf_frmts/osm/gpb.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gpb.h 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: gpb.h 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
@@ -140,7 +140,7 @@ static unsigned int ReadVarUInt32(GByte** ppabyData)
 #define READ_SIZE(pabyData, pabyDataLimit, nSize) \
     { \
         READ_VARUINT32(pabyData, pabyDataLimit, nSize); \
-        if (CHECK_OOB && nSize > pabyDataLimit - pabyData) GOTO_END_ERROR; \
+        if (CHECK_OOB && nSize > (unsigned int)(pabyDataLimit - pabyData)) GOTO_END_ERROR; \
     }
 
 /************************************************************************/
@@ -226,7 +226,6 @@ static void SkipVarInt(GByte** ppabyData)
 /*                         SkipUnknownField()                           */
 /************************************************************************/
 
-/* TODO: Move static function into the cpp file where it is used. */
 #define SKIP_UNKNOWN_FIELD_INLINE(pabyData, pabyDataLimit, verbose) \
         int nWireType = GET_WIRETYPE(nKey); \
         if (verbose) \
@@ -267,8 +266,9 @@ static void SkipVarInt(GByte** ppabyData)
 static
 int SkipUnknownField(int nKey, GByte* pabyData, GByte* pabyDataLimit, int verbose) CPL_NO_INLINE;
 
+/* Putting statics in headers is trouble. */
 static
-/* CPL_UNUSED */
+CPL_UNUSED
 int SkipUnknownField(int nKey, GByte* pabyData, GByte* pabyDataLimit, int verbose)
 {
     GByte* pabyDataBefore = pabyData;
diff --git a/ogr/ogrsf_frmts/osm/ogr_osm.h b/ogr/ogrsf_frmts/osm/ogr_osm.h
index a441bc7..26def96 100644
--- a/ogr/ogrsf_frmts/osm/ogr_osm.h
+++ b/ogr/ogrsf_frmts/osm/ogr_osm.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_osm.h 27138 2014-04-07 20:32:14Z rouault $
+ * $Id: ogr_osm.h 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/OpenStreeMap driver.
@@ -53,6 +53,21 @@ class ConstCharComp
         }
 };
 
+class OGROSMComputedAttribute
+{
+    public:
+        CPLString    osName;
+        int          nIndex;
+        OGRFieldType eType;
+        CPLString    osSQL;
+        sqlite3_stmt  *hStmt;
+        std::vector<CPLString> aosAttrToBind;
+        std::vector<int> anIndexToBind;
+
+        OGROSMComputedAttribute() : nIndex(-1), eType(OFTString), hStmt(NULL) {}
+        OGROSMComputedAttribute(const char* pszName) : osName(pszName), nIndex(-1), eType(OFTString), hStmt(NULL) {}
+};
+
 /************************************************************************/
 /*                           OGROSMLayer                                */
 /************************************************************************/
@@ -71,6 +86,8 @@ class OGROSMLayer : public OGRLayer
 
     std::vector<char*>   apszNames;
     std::map<const char*, int, ConstCharComp> oMapFieldNameToIndex;
+    
+    std::vector<OGROSMComputedAttribute> oComputedAttributes;
 
     int                  bResetReadingAllowed;
     
@@ -126,7 +143,7 @@ class OGROSMLayer : public OGRLayer
     virtual int         TestCapability( const char * );
                                      
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int bForce );
+    virtual GIntBig     GetFeatureCount( int bForce );
         
     virtual OGRErr      SetAttributeFilter( const char* pszAttrQuery );
 
@@ -185,6 +202,10 @@ class OGROSMLayer : public OGRLayer
 
     void                AddIgnoreKey(const char* pszK);
     void                AddWarnKey(const char* pszK);
+
+    void                AddComputedAttribute(const char* pszName,
+                                             OGRFieldType eType,
+                                             const char* pszSQL);
 };
 
 /************************************************************************/
@@ -282,6 +303,8 @@ class OGROSMDataSource : public OGRDataSource
     sqlite3_stmt       *hSelectPolygonsStandaloneStmt;
     int                 bHasRowInPolygonsStandalone;
 
+    sqlite3            *hDBForComputedAttributes;
+
     int                 nMaxSizeForInMemoryDBInMB;
     int                 bInMemoryTmpDB;
     int                 bMustUnlink;
@@ -396,8 +419,8 @@ class OGROSMDataSource : public OGRDataSource
                                  LonLat* pasLonLatPairs, int nPairs,
                                  OSMInfo* psInfo);
 
-    int                 StartTransaction();
-    int                 CommitTransaction();
+    int                 StartTransactionCacheDB();
+    int                 CommitTransactionCacheDB();
 
     int                 FindNode(GIntBig nID);
     void                ProcessWaysBatch();
@@ -423,6 +446,9 @@ class OGROSMDataSource : public OGRDataSource
     int                 AllocBucket(int iBucket);
     int                 AllocMoreBuckets(int nNewBucketIdx, int bAllocBucket = FALSE);
 
+    void                AddComputedAttributes(int iCurLayer,
+                                             const std::vector<OGROSMComputedAttribute>& oAttributes);
+
   public:
                         OGROSMDataSource();
                         ~OGROSMDataSource();
@@ -439,7 +465,7 @@ class OGROSMDataSource : public OGRDataSource
     virtual void        ReleaseResultSet( OGRLayer * poLayer );
 
 
-    int                 Open ( const char* pszFilename, int bUpdateIn );
+    int                 Open ( const char* pszFilename );
 
     int                 ResetReading();
     int                 ParseNextChunk(int nIdxLayer);
@@ -460,22 +486,5 @@ class OGROSMDataSource : public OGRDataSource
     int                 DoesAttributeNameLaundering() const { return bAttributeNameLaundering; }
 };
 
-/************************************************************************/
-/*                            OGROSMDriver                              */
-/************************************************************************/
-
-class OGROSMDriver : public OGRSFDriver
-{
-  public:
-                ~OGROSMDriver();
-
-    virtual const char    *GetName();
-    virtual OGRDataSource *Open( const char *, int );
-    virtual OGRDataSource *CreateDataSource( const char * pszName,
-                                             char **papszOptions );
-
-    virtual int            TestCapability( const char * );
-};
-
 #endif /* ndef _OGR_OSM_H_INCLUDED */
 
diff --git a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp
index b8bbf2b..58a5d2a 100644
--- a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp
+++ b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrosmdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrosmdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGROSMDataSource class.
@@ -88,7 +88,7 @@
 #define PAGE_SIZE   4096
 
 /* compressSize should not be greater than 512, so COMPRESS_SIZE_TO_BYTE() fits on a byte */
-#define COMPRESS_SIZE_TO_BYTE(nCompressSize)  (((nCompressSize) - 8) / 2)
+#define COMPRESS_SIZE_TO_BYTE(nCompressSize)  (GByte)(((nCompressSize) - 8) / 2)
 #define ROUND_COMPRESS_SIZE(nCompressSize)    (((nCompressSize) + 1) / 2) * 2;
 #define COMPRESS_SIZE_FROM_BYTE(byte_on_size) ((byte_on_size) * 2 + 8)
 
@@ -121,7 +121,7 @@ size_t GetMaxTotalAllocs();
 static void WriteVarInt64(GUIntBig nSVal, GByte** ppabyData);
 static void WriteVarSInt64(GIntBig nSVal, GByte** ppabyData);
 
-CPL_CVSID("$Id: ogrosmdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrosmdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 class DSToBeOpened
 {
@@ -131,7 +131,7 @@ class DSToBeOpened
         CPLString               osInterestLayers;
 };
 
-static void                      *hMutex = NULL;
+static CPLMutex                  *hMutex = NULL;
 static std::vector<DSToBeOpened>  oListDSToBeOpened;
 
 /************************************************************************/
@@ -180,6 +180,7 @@ OGROSMDataSource::OGROSMDataSource()
     nLayers = 0;
     papoLayers = NULL;
     pszName = NULL;
+    bExtentValid = FALSE;
     bInterleavedReading = -1;
     poCurrentLayer = NULL;
     psParser = NULL;
@@ -195,6 +196,9 @@ OGROSMDataSource::OGROSMDataSource()
     hDeletePolygonsStandaloneStmt = NULL;
     hSelectPolygonsStandaloneStmt = NULL;
     bHasRowInPolygonsStandalone = FALSE;
+
+    hDBForComputedAttributes = NULL;
+
     nNodesInTransaction = 0;
     bInTransaction = FALSE;
     pahSelectNodeStmt = NULL;
@@ -288,6 +292,9 @@ OGROSMDataSource::~OGROSMDataSource()
     if( hDB != NULL )
         CloseDB();
 
+    if( hDBForComputedAttributes != NULL )
+        sqlite3_close(hDBForComputedAttributes);
+
 #ifdef HAVE_SQLITE_VFS
     if (pMyVFS)
     {
@@ -425,7 +432,7 @@ void OGROSMDataSource::CloseDB()
     }
 
     if( bInTransaction )
-        CommitTransaction();
+        CommitTransactionCacheDB();
 
     sqlite3_close(hDB);
     hDB = NULL;
@@ -860,8 +867,10 @@ void OGROSMDataSource::NotifyNodes(unsigned int nNodes, OSMNode* pasNodes)
     }
 }
 
-static void OGROSMNotifyNodes (unsigned int nNodes, OSMNode* pasNodes,
-                               CPL_UNUSED OSMContext* psOSMContext, void* user_data)
+static void OGROSMNotifyNodes (unsigned int nNodes,
+                               OSMNode* pasNodes,
+                               CPL_UNUSED OSMContext* psOSMContext,
+                               void* user_data)
 {
     ((OGROSMDataSource*) user_data)->NotifyNodes(nNodes, pasNodes);
 }
@@ -1044,8 +1053,8 @@ static int DecompressSector(GByte* pabyIn, int nSectorSize, GByte* pabyOut)
         {
             if( bLastValid )
             {
-                pasLonLatOut[i].nLon = nLastLon + ReadVarSInt64(&pabyPtr);
-                pasLonLatOut[i].nLat = nLastLat + ReadVarSInt64(&pabyPtr);
+                pasLonLatOut[i].nLon = (int)(nLastLon + ReadVarSInt64(&pabyPtr));
+                pasLonLatOut[i].nLat = (int)(nLastLat + ReadVarSInt64(&pabyPtr));
             }
             else
             {
@@ -1547,8 +1556,8 @@ int OGROSMDataSource::UncompressWay( int nBytes, GByte* pabyCompressedWay,
     int nPoints = 1;
     do
     {
-        pasCoords[nPoints].nLon = pasCoords[nPoints-1].nLon + ReadVarSInt64(&pabyPtr);
-        pasCoords[nPoints].nLat = pasCoords[nPoints-1].nLat + ReadVarSInt64(&pabyPtr);
+        pasCoords[nPoints].nLon = (int)(pasCoords[nPoints-1].nLon + ReadVarSInt64(&pabyPtr));
+        pasCoords[nPoints].nLat = (int)(pasCoords[nPoints-1].nLat + ReadVarSInt64(&pabyPtr));
 
         nPoints ++;
     } while (pabyPtr < pabyCompressedWay + nBytes);
@@ -1920,18 +1929,16 @@ void OGROSMDataSource::NotifyWay (OSMWay* psWay)
                     psWay->sInfo.ts.nTimeStamp;
             else
             {
-                int year, month, day, hour, minute, TZ;
-                float second;
-                if (OGRParseXMLDateTime(psWay->sInfo.ts.pszTimeStamp, &year, &month, &day,
-                                        &hour, &minute, &second, &TZ))
+                OGRField sField;
+                if (OGRParseXMLDateTime(psWay->sInfo.ts.pszTimeStamp, &sField))
                 {
                     struct tm brokendown;
-                    brokendown.tm_year = year - 1900;
-                    brokendown.tm_mon = month - 1;
-                    brokendown.tm_mday = day;
-                    brokendown.tm_hour = hour;
-                    brokendown.tm_min = minute;
-                    brokendown.tm_sec = (int)(second + .5);
+                    brokendown.tm_year = sField.Date.Year - 1900;
+                    brokendown.tm_mon = sField.Date.Month - 1;
+                    brokendown.tm_mday = sField.Date.Day;
+                    brokendown.tm_hour = sField.Date.Hour;
+                    brokendown.tm_min = sField.Date.Minute;
+                    brokendown.tm_sec = (int)(sField.Date.Second + .5);
                     psWayFeaturePairs->sInfo.ts.nTimeStamp =
                         CPLYMDHMSToUnixTime(&brokendown);
                 }
@@ -2004,7 +2011,7 @@ void OGROSMDataSource::NotifyWay (OSMWay* psWay)
                 psKD = oIterK->second;
             psKD->nOccurences ++;
 
-            pasAccumulatedTags[nAccumulatedTags].nKeyIndex = psKD->nKeyIndex;
+            pasAccumulatedTags[nAccumulatedTags].nKeyIndex = (short)psKD->nKeyIndex;
 
             /* to fit in 2 bytes, the theoretical limit would be 127 * 128 + 127 */
             if( psKD->asValues.size() < 1024 )
@@ -2070,7 +2077,9 @@ void OGROSMDataSource::NotifyWay (OSMWay* psWay)
     nUnsortedReqIds += (psWay->nRefs - bIsArea);
 }
 
-static void OGROSMNotifyWay (OSMWay* psWay, CPL_UNUSED OSMContext* psOSMContext, void* user_data)
+static void OGROSMNotifyWay (OSMWay* psWay,
+                             CPL_UNUSED OSMContext* psOSMContext,
+                             void* user_data)
 {
     ((OGROSMDataSource*) user_data)->NotifyWay(psWay);
 }
@@ -2519,7 +2528,8 @@ void OGROSMDataSource::NotifyRelation (OSMRelation* psRelation)
 }
 
 static void OGROSMNotifyRelation (OSMRelation* psRelation,
-                                  CPL_UNUSED OSMContext* psOSMContext, void* user_data)
+                                  CPL_UNUSED OSMContext* psOSMContext,
+                                  void* user_data)
 {
     ((OGROSMDataSource*) user_data)->NotifyRelation(psRelation);
 }
@@ -2640,7 +2650,8 @@ void OGROSMDataSource::NotifyBounds (double dfXMin, double dfYMin,
 
 static void OGROSMNotifyBounds( double dfXMin, double dfYMin,
                                 double dfXMax, double dfYMax,
-                                CPL_UNUSED OSMContext* psCtxt, void* user_data )
+                                CPL_UNUSED OSMContext* psCtxt,
+                                void* user_data )
 {
     ((OGROSMDataSource*) user_data)->NotifyBounds(dfXMin, dfYMin,
                                                   dfXMax, dfYMax);
@@ -2650,17 +2661,9 @@ static void OGROSMNotifyBounds( double dfXMin, double dfYMin,
 /*                                Open()                                */
 /************************************************************************/
 
-int OGROSMDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGROSMDataSource::Open( const char * pszFilename )
 
 {
-    const char* pszExt = CPLGetExtension(pszFilename);
-    if( !EQUAL(pszExt, "pbf") &&
-        !EQUAL(pszExt, "osm") &&
-        !EQUALN(pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")) &&
-        strcmp(pszFilename, "/vsistdin/") != 0 &&
-        strcmp(pszFilename, "/dev/stdin/") != 0 )
-        return FALSE;
-
     pszName = CPLStrdup( pszFilename );
 
     psParser = OSM_Open( pszName,
@@ -2672,14 +2675,7 @@ int OGROSMDataSource::Open( const char * pszFilename, int bUpdateIn)
     if( psParser == NULL )
         return FALSE;
 
-    if (bUpdateIn)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                 "OGR/OSM driver does not support opening a file in update mode");
-        return FALSE;
-    }
-
-    /* The following 4 config options are only usefull for debugging */
+    /* The following 4 config options are only useful for debugging */
     bIndexPoints = CSLTestBoolean(CPLGetConfigOption("OSM_INDEX_POINTS", "YES"));
     bUsePointsIndex = CSLTestBoolean(CPLGetConfigOption("OSM_USE_POINTS_INDEX", "YES"));
     bIndexWays = CSLTestBoolean(CPLGetConfigOption("OSM_INDEX_WAYS", "YES"));
@@ -3007,7 +3003,7 @@ int OGROSMDataSource::SetDBOptions()
     if( !SetCacheSize() )
         return FALSE;
 
-    if( !StartTransaction() )
+    if( !StartTransactionCacheDB() )
         return FALSE;
 
     return TRUE;
@@ -3180,10 +3176,10 @@ int OGROSMDataSource::CreatePreparedStatements()
 }
 
 /************************************************************************/
-/*                           StartTransaction()                         */
+/*                      StartTransactionCacheDB()                       */
 /************************************************************************/
 
-int OGROSMDataSource::StartTransaction()
+int OGROSMDataSource::StartTransactionCacheDB()
 {
     if( bInTransaction )
         return FALSE;
@@ -3204,10 +3200,10 @@ int OGROSMDataSource::StartTransaction()
 }
 
 /************************************************************************/
-/*                           CommitTransaction()                        */
+/*                        CommitTransactionCacheDB()                    */
 /************************************************************************/
 
-int OGROSMDataSource::CommitTransaction()
+int OGROSMDataSource::CommitTransactionCacheDB()
 {
     if( !bInTransaction )
         return FALSE;
@@ -3228,6 +3224,24 @@ int OGROSMDataSource::CommitTransaction()
 }
 
 /************************************************************************/
+/*                     AddComputedAttributes()                          */
+/************************************************************************/
+
+void OGROSMDataSource::AddComputedAttributes(int iCurLayer,
+                                             const std::vector<OGROSMComputedAttribute>& oAttributes)
+{
+    for(size_t i=0; i<oAttributes.size();i++)
+    {
+        if( oAttributes[i].osSQL.size() )
+        {
+            papoLayers[iCurLayer]->AddComputedAttribute(oAttributes[i].osName,
+                                                        oAttributes[i].eType,
+                                                        oAttributes[i].osSQL);
+        }
+    }
+}
+
+/************************************************************************/
 /*                           ParseConf()                                */
 /************************************************************************/
 
@@ -3248,13 +3262,20 @@ int OGROSMDataSource::ParseConf()
 
     const char* pszLine;
     int iCurLayer = -1;
+    std::vector<OGROSMComputedAttribute> oAttributes;
 
     int i;
 
     while((pszLine = CPLReadLine2L(fpConf, -1, NULL)) != NULL)
     {
+        if(pszLine[0] == '#')
+            continue;
         if(pszLine[0] == '[' && pszLine[strlen(pszLine)-1] == ']' )
         {
+            if( iCurLayer >= 0 )
+                AddComputedAttributes(iCurLayer, oAttributes);
+            oAttributes.resize(0);
+
             iCurLayer = -1;
             pszLine ++;
             ((char*)pszLine)[strlen(pszLine)-1] = '\0'; /* Evil but OK */
@@ -3435,10 +3456,101 @@ int OGROSMDataSource::ParseConf()
                 }
                 CSLDestroy(papszTokens2);
             }
+            else if ( CSLCount(papszTokens) == 2 && strcmp(papszTokens[0], "computed_attributes") == 0 )
+            {
+                char** papszTokens2 = CSLTokenizeString2(papszTokens[1], ",", 0);
+                oAttributes.resize(0);
+                for(int i=0;papszTokens2[i] != NULL;i++)
+                {
+                    oAttributes.push_back(OGROSMComputedAttribute(papszTokens2[i]));
+                }
+                CSLDestroy(papszTokens2);
+            }
+            else if ( CSLCount(papszTokens) == 2 && strlen(papszTokens[0]) >= 5 &&
+                      strcmp(papszTokens[0] + strlen(papszTokens[0]) - 5, "_type") == 0 )
+            {
+                CPLString osName(papszTokens[0]);
+                osName.resize(strlen(papszTokens[0]) - 5);
+                const char* pszType = papszTokens[1];
+                int bFound = FALSE;
+                 OGRFieldType eType = OFTString;
+                if( EQUAL(pszType, "Integer") )
+                    eType = OFTInteger;
+                else if( EQUAL(pszType, "Integer64") )
+                    eType = OFTInteger64;
+                else if( EQUAL(pszType, "Real") )
+                    eType = OFTReal;
+                else if( EQUAL(pszType, "String") )
+                    eType = OFTString;
+                else if( EQUAL(pszType, "DateTime") )
+                    eType = OFTDateTime;
+                else
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                                "Unhandled type (%s) for attribute %s",
+                                pszType, osName.c_str());
+                for(size_t i = 0; i < oAttributes.size(); i++ )
+                {
+                    if( oAttributes[i].osName == osName )
+                    {
+                        bFound = TRUE;
+                        oAttributes[i].eType = eType;
+                        break;
+                    }
+                }
+                if( !bFound )
+                {
+                    int idx = papoLayers[iCurLayer]->GetLayerDefn()->GetFieldIndex(osName);
+                    if( idx >= 0 )
+                    {
+                        papoLayers[iCurLayer]->GetLayerDefn()->GetFieldDefn(idx)->SetType(eType);
+                        bFound = TRUE;
+                    }
+                }
+                if( !bFound )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined, "Undeclared attribute : %s",
+                             osName.c_str());
+                }
+            }
+            else if ( CSLCount(papszTokens) >= 2 && strlen(papszTokens[0]) >= 4 &&
+                      strcmp(papszTokens[0] + strlen(papszTokens[0]) - 4, "_sql") == 0 )
+            {
+                CPLString osName(papszTokens[0]);
+                osName.resize(strlen(papszTokens[0]) - 4);
+                size_t i;
+                for(i = 0; i < oAttributes.size(); i++ )
+                {
+                    if( oAttributes[i].osName == osName )
+                    {
+                        const char* pszSQL = strchr(pszLine, '=') + 1;
+                        while( *pszSQL == ' ' )
+                            pszSQL ++;
+                        int bInQuotes = FALSE;
+                        if( *pszSQL == '"' )
+                        {
+                            bInQuotes = TRUE;
+                            pszSQL ++;
+                        }
+                        oAttributes[i].osSQL = pszSQL;
+                        if( bInQuotes && oAttributes[i].osSQL.size() > 1 &&
+                            oAttributes[i].osSQL[oAttributes[i].osSQL.size()-1] == '"' )
+                            oAttributes[i].osSQL.resize(oAttributes[i].osSQL.size()-1);
+                        break;
+                    }
+                }
+                if( i == oAttributes.size() )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined, "Undeclared attribute : %s",
+                             osName.c_str());
+                }
+            }
             CSLDestroy(papszTokens);
         }
     }
 
+    if( iCurLayer >= 0 )
+        AddComputedAttributes(iCurLayer, oAttributes);
+
     for(i=0;i<nLayers;i++)
     {
         if( papoLayers[i]->HasAllTags() )
@@ -3648,7 +3760,7 @@ int OGROSMDataSource::TransferToDiskIfNecesserary()
             CPLString osNewTmpDBName;
             osNewTmpDBName = CPLGenerateTempFilename("osm_tmp_nodes");
 
-            CPLDebug("OSM", "%s too big for RAM. Transfering it onto disk in %s",
+            CPLDebug("OSM", "%s too big for RAM. Transferring it onto disk in %s",
                      osNodesFilename.c_str(), osNewTmpDBName.c_str());
 
             if( CPLCopyFile( osNewTmpDBName, osNodesFilename ) != 0 )
@@ -3727,7 +3839,7 @@ int OGROSMDataSource::TransferToDiskIfNecesserary()
 
             osNewTmpDBName = CPLGenerateTempFilename("osm_tmp");
 
-            CPLDebug("OSM", "%s too big for RAM. Transfering it onto disk in %s",
+            CPLDebug("OSM", "%s too big for RAM. Transferring it onto disk in %s",
                      osTmpDBName.c_str(), osNewTmpDBName.c_str());
 
             if( CPLCopyFile( osNewTmpDBName, osTmpDBName ) != 0 )
@@ -3932,7 +4044,7 @@ class OGROSMResultLayerDecorator : public OGRLayerDecorator
                                         osDSName(osDSName),
                                         osInterestLayers(osInterestLayers) {}
 
-        virtual int         GetFeatureCount( int bForce = TRUE )
+        virtual GIntBig     GetFeatureCount( int bForce = TRUE )
         {
             /* When we run GetFeatureCount() with SQLite SQL dialect, */
             /* the OSM dataset will be re-opened. Make sure that it is */
@@ -4111,7 +4223,7 @@ OGRLayer * OGROSMDataSource::ExecuteSQL( const char *pszSQLCommand,
                                                             poSpatialFilter,
                                                             pszDialect );
 
-            /* If the user explicitely run a COUNT() request, then do it ! */
+            /* If the user explicitly run a COUNT() request, then do it ! */
             if( poResultSetLayer )
             {
                 if( pszDialect != NULL && EQUAL(pszDialect, "SQLITE") )
diff --git a/ogr/ogrsf_frmts/osm/ogrosmdriver.cpp b/ogr/ogrsf_frmts/osm/ogrosmdriver.cpp
index 6f322ad..acc2fbe 100644
--- a/ogr/ogrsf_frmts/osm/ogrosmdriver.cpp
+++ b/ogr/ogrsf_frmts/osm/ogrosmdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrosmdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrosmdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGROSMDriver class.
@@ -34,41 +34,43 @@
 
 extern "C" void CPL_DLL RegisterOGROSM();
 
-CPL_CVSID("$Id: ogrosmdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrosmdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
-/*                         ~OGROSMDriver()                           */
+/*                      OGROSMDriverIdentify()                          */
 /************************************************************************/
 
-OGROSMDriver::~OGROSMDriver()
+static int OGROSMDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGROSMDriver::GetName()
-
-{
-    return "OSM";
+    if (poOpenInfo->fpL == NULL )
+        return FALSE;
+    const char* pszExt = CPLGetExtension(poOpenInfo->pszFilename);
+    if( EQUAL(pszExt, "pbf") ||
+        EQUAL(pszExt, "osm") )
+        return TRUE;
+    if( EQUALN(poOpenInfo->pszFilename, "/vsicurl_streaming/", strlen("/vsicurl_streaming/")) ||
+        strcmp(poOpenInfo->pszFilename, "/vsistdin/") == 0 ||
+        strcmp(poOpenInfo->pszFilename, "/dev/stdin/") == 0 )
+        return -1;
+    return FALSE;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGROSMDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGROSMDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    if (bUpdate)
+    if (poOpenInfo->eAccess == GA_Update )
+        return NULL;
+    if( OGROSMDriverIdentify(poOpenInfo) == FALSE )
         return NULL;
 
     OGROSMDataSource   *poDS = new OGROSMDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -78,25 +80,6 @@ OGRDataSource *OGROSMDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGROSMDriver::CreateDataSource( CPL_UNUSED const char * pszName,
-                                               CPL_UNUSED char **papszOptions )
-{
-    return NULL;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGROSMDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                        RegisterOGROSM()                           */
 /************************************************************************/
 
@@ -104,7 +87,26 @@ void RegisterOGROSM()
 {
     if (! GDAL_CHECK_VERSION("OGR/OSM driver"))
         return;
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "OSM" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "OSM" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "OpenStreetMap XML and PBF" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "osm pbf" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_osm.html" );
 
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGROSMDriver );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGROSMDriverOpen;
+        poDriver->pfnIdentify = OGROSMDriverIdentify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp b/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
index a32c3a6..d598c9d 100644
--- a/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
+++ b/ogr/ogrsf_frmts/osm/ogrosmlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrosmlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrosmlayer.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGROSMLayer class
@@ -33,7 +33,7 @@
 #include "cpl_time.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrosmlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrosmlayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 #define SWITCH_THRESHOLD   10000
 #define MAX_THRESHOLD      100000
@@ -51,6 +51,7 @@ OGROSMLayer::OGROSMLayer(OGROSMDataSource* poDS, int nIdxLayer, const char* pszN
     this->nIdxLayer = nIdxLayer;
 
     poFeatureDefn = new OGRFeatureDefn( pszName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poSRS = new OGRSpatialReference();
@@ -115,6 +116,11 @@ OGROSMLayer::~OGROSMLayer()
     for(i=0;i<(int)apszIgnoreKeys.size();i++)
         CPLFree(apszIgnoreKeys[i]);
     
+    for(i=0; i<(int)oComputedAttributes.size();i++)
+    {
+        sqlite3_finalize(oComputedAttributes[i].hStmt);
+    }
+    
     CPLFree(pszAllTags);
 
     CPLFree(papoFeatures);
@@ -186,7 +192,7 @@ OGRErr OGROSMLayer::SetAttributeFilter( const char* pszAttrQuery )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGROSMLayer::GetFeatureCount( int bForce )
+GIntBig OGROSMLayer::GetFeatureCount( int bForce )
 {
     if( poDS->IsFeatureCountEnabled() )
         return OGRLayer::GetFeatureCount(bForce);
@@ -400,7 +406,8 @@ int  OGROSMLayer::AddFeature(OGRFeature* poFeature,
 /*                             GetExtent()                              */
 /************************************************************************/
 
-OGRErr OGROSMLayer::GetExtent( OGREnvelope *psExtent, CPL_UNUSED int bForce )
+OGRErr OGROSMLayer::GetExtent( OGREnvelope *psExtent,
+                               CPL_UNUSED int bForce )
 {
     if (poDS->GetExtent(psExtent) == OGRERR_NONE)
         return OGRERR_NONE;
@@ -538,8 +545,7 @@ void OGROSMLayer::SetFieldsFromTags(OGRFeature* poFeature,
 {
     if( !bIsWayID )
     {
-        if( (long)nID == nID )
-            poFeature->SetFID( (long)nID ); /* Will not work with 32bit GDAL if id doesn't fit into 32 bits */
+        poFeature->SetFID( nID );
 
         if( bHasOSMId )
         {
@@ -550,8 +556,7 @@ void OGROSMLayer::SetFieldsFromTags(OGRFeature* poFeature,
     }
     else
     {
-        if( (long)nID == nID )
-            poFeature->SetFID( (long)nID ); /* Will not work with 32bit GDAL if id doesn't fit into 32 bits */
+        poFeature->SetFID( nID );
 
         if( nIndexOSMWayId >= 0 )
         {
@@ -569,13 +574,10 @@ void OGROSMLayer::SetFieldsFromTags(OGRFeature* poFeature,
     {
         if( psInfo->bTimeStampIsStr )
         {
-            int year, month, day, hour, minute, TZ;
-            float second;
-            if (OGRParseXMLDateTime(psInfo->ts.pszTimeStamp, &year, &month, &day,
-                                    &hour, &minute, &second, &TZ))
+            OGRField sField;
+            if (OGRParseXMLDateTime(psInfo->ts.pszTimeStamp, &sField))
             {
-                poFeature->SetField("osm_timestamp", year, month, day, hour,
-                                    minute, (int)(second + .5), TZ);
+                poFeature->SetField("osm_timestamp", &sField);
             }
         }
         else
@@ -668,6 +670,79 @@ void OGROSMLayer::SetFieldsFromTags(OGRFeature* poFeature,
         else
             poFeature->SetField(nIndexOtherTags, pszAllTags);
     }
+
+    for(size_t i=0; i<oComputedAttributes.size();i++)
+    {
+        const OGROSMComputedAttribute& oAttr = oComputedAttributes[i];
+        for(size_t j=0;j<oAttr.anIndexToBind.size();j++)
+        {
+            if( oAttr.anIndexToBind[j] >= 0 )
+            {
+                if( !poFeature->IsFieldSet(oAttr.anIndexToBind[j]) )
+                {
+                    sqlite3_bind_null( oAttr.hStmt, j + 1 );
+                }
+                else
+                {
+                    OGRFieldType eType = poFeatureDefn->GetFieldDefn(oAttr.anIndexToBind[j])->GetType();
+                    if( eType == OFTInteger )
+                        sqlite3_bind_int( oAttr.hStmt, j + 1,
+                                          poFeature->GetFieldAsInteger(oAttr.anIndexToBind[j]) );
+                    else if( eType == OFTInteger64 )
+                        sqlite3_bind_int64( oAttr.hStmt, j + 1,
+                                          poFeature->GetFieldAsInteger64(oAttr.anIndexToBind[j]) );
+                    else if( eType == OFTReal )
+                        sqlite3_bind_double( oAttr.hStmt, j + 1,
+                                             poFeature->GetFieldAsDouble(oAttr.anIndexToBind[j]) );
+                    else
+                        sqlite3_bind_text( oAttr.hStmt, j + 1,
+                                        poFeature->GetFieldAsString(oAttr.anIndexToBind[j]),
+                                        -1, SQLITE_TRANSIENT);
+                }
+            }
+            else
+            {
+                int bTagFound = FALSE;
+                for(unsigned int k = 0; k < nTags; k++)
+                {
+                    const char* pszK = pasTags[k].pszK;
+                    const char* pszV = pasTags[k].pszV;
+                    if( strcmp(pszK, oAttr.aosAttrToBind[j]) == 0 )
+                    {
+                        sqlite3_bind_text( oAttr.hStmt, j + 1, pszV, -1, SQLITE_TRANSIENT);
+                        bTagFound = TRUE;
+                        break;
+                    }
+                }
+                if( !bTagFound )
+                    sqlite3_bind_null( oAttr.hStmt, j + 1 );
+            }
+        }
+
+        if( sqlite3_step( oAttr.hStmt ) == SQLITE_ROW &&
+            sqlite3_column_count( oAttr.hStmt ) == 1 )
+        {
+            switch( sqlite3_column_type( oAttr.hStmt, 0 ) )
+            {
+                case SQLITE_INTEGER:
+                    poFeature->SetField( oAttr.nIndex,
+                            (GIntBig)sqlite3_column_int64(oAttr.hStmt, 0) );
+                    break;
+                case SQLITE_FLOAT:
+                    poFeature->SetField( oAttr.nIndex,
+                            sqlite3_column_double(oAttr.hStmt, 0) );
+                    break;
+                case SQLITE_TEXT:
+                    poFeature->SetField( oAttr.nIndex,
+                            (const char*)sqlite3_column_text(oAttr.hStmt, 0) );
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        sqlite3_reset( oAttr.hStmt );
+    }
 }
 
 /************************************************************************/
@@ -712,3 +787,91 @@ void OGROSMLayer::AddWarnKey(const char* pszK)
 {
     aoSetWarnKeys.insert(pszK);
 }
+
+/************************************************************************/
+/*                           AddWarnKey()                               */
+/************************************************************************/
+
+void OGROSMLayer::AddComputedAttribute(const char* pszName,
+                                       OGRFieldType eType,
+                                       const char* pszSQL)
+{
+    if( poDS->hDBForComputedAttributes == NULL )
+    {
+        int rc;
+#ifdef HAVE_SQLITE_VFS
+        rc = sqlite3_open_v2( ":memory:", &(poDS->hDBForComputedAttributes),
+                              SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX, NULL );
+#else
+        rc = sqlite3_open( ":memory:", &(poDS->hDBForComputedAttributes) );
+#endif
+        if( rc != SQLITE_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Cannot open temporary sqlite DB" );
+            return;
+        }
+    }
+
+    if( poFeatureDefn->GetFieldIndex(pszName) >= 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "A field with same name %s already exists", pszName );
+        return;
+    }
+
+    CPLString osSQL(pszSQL);
+    std::vector<CPLString> aosAttrToBind;
+    std::vector<int> anIndexToBind;
+    size_t nStartSearch = 0;
+    while(TRUE)
+    {
+        size_t nPos = osSQL.find("[", nStartSearch);
+        if( nPos == std::string::npos )
+            break;
+        nStartSearch = nPos + 1;
+        if( nPos > 0 && osSQL[nPos-1] != '\\' )
+        {
+            CPLString osAttr = osSQL.substr(nPos + 1);
+            size_t nPos2 = osAttr.find("]");
+            if( nPos2 == std::string::npos )
+                break;
+            osAttr.resize(nPos2);
+
+            osSQL = osSQL.substr(0, nPos) + "?" + osSQL.substr(nPos + 1 + nPos2+1);
+
+            aosAttrToBind.push_back(osAttr);
+            anIndexToBind.push_back(poFeatureDefn->GetFieldIndex(osAttr));
+        }
+    }
+    while(TRUE)
+    {
+        size_t nPos = osSQL.find("\\");
+        if( nPos == std::string::npos || nPos == osSQL.size() - 1 )
+            break;
+        osSQL = osSQL.substr(0, nPos) + osSQL.substr(nPos + 1);
+    }
+
+    CPLDebug("OSM", "SQL : \"%s\"", osSQL.c_str());
+
+    sqlite3_stmt  *hStmt;
+    int rc = sqlite3_prepare( poDS->hDBForComputedAttributes, osSQL, -1,
+                              &hStmt, NULL );
+    if( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                  "sqlite3_prepare() failed :  %s",
+                  sqlite3_errmsg(poDS->hDBForComputedAttributes) );
+        return;
+    }
+
+    OGRFieldDefn oField(pszName, eType);
+    poFeatureDefn->AddFieldDefn(&oField);
+    oComputedAttributes.push_back(OGROSMComputedAttribute(pszName));
+    oComputedAttributes[oComputedAttributes.size()-1].eType = eType;
+    oComputedAttributes[oComputedAttributes.size()-1].nIndex = poFeatureDefn->GetFieldCount() - 1;
+    oComputedAttributes[oComputedAttributes.size()-1].osSQL = pszSQL;
+    oComputedAttributes[oComputedAttributes.size()-1].hStmt = hStmt;
+    oComputedAttributes[oComputedAttributes.size()-1].aosAttrToBind = aosAttrToBind;
+    oComputedAttributes[oComputedAttributes.size()-1].anIndexToBind = anIndexToBind;
+}
diff --git a/ogr/ogrsf_frmts/osm/osm_parser.cpp b/ogr/ogrsf_frmts/osm/osm_parser.cpp
index dae4ec0..afb5a63 100644
--- a/ogr/ogrsf_frmts/osm/osm_parser.cpp
+++ b/ogr/ogrsf_frmts/osm/osm_parser.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: osm_parser.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: osm_parser.cpp 28435 2015-02-07 14:35:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
@@ -45,7 +45,7 @@
 
 #define XML_BUFSIZE 64*1024
 
-CPL_CVSID("$Id: osm_parser.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: osm_parser.cpp 28435 2015-02-07 14:35:34Z rouault $");
 
 /************************************************************************/
 /*                            INIT_INFO()                               */
@@ -338,14 +338,11 @@ int ReadOSMHeader(GByte* pabyData, GByte* pabyDataLimit,
         }
         else if (nKey == MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_TIMESTAMP, WT_VARINT))
         {
-            /* TODO: Do something with nVal or change this to a seek forward. */
-            GIntBig nVal;
-            READ_VARINT64(pabyData, pabyDataLimit, nVal);
+            SKIP_VARINT(pabyData, pabyDataLimit);
         }
         else if (nKey == MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_SEQ_NUMBER, WT_VARINT))
         {
-            GIntBig nVal;
-            READ_VARINT64(pabyData, pabyDataLimit, nVal);
+            SKIP_VARINT(pabyData, pabyDataLimit);
         }
         else if (nKey == MAKE_KEY(OSMHEADER_IDX_OSMOSIS_REPLICATION_BASE_URL, WT_DATA))
         {
@@ -382,11 +379,11 @@ int ReadStringTable(GByte* pabyData, GByte* pabyDataLimit,
 
     psCtxt->pszStrBuf = pszStrBuf;
 
-    if (pabyDataLimit - pabyData > psCtxt->nStrAllocated)
+    if ((unsigned int)(pabyDataLimit - pabyData) > psCtxt->nStrAllocated)
     {
         int* panStrOffNew;
         psCtxt->nStrAllocated = MAX(psCtxt->nStrAllocated * 2,
-                                          pabyDataLimit - pabyData);
+                                          (unsigned int)(pabyDataLimit - pabyData));
         panStrOffNew = (int*) VSIRealloc(
             panStrOff, psCtxt->nStrAllocated * sizeof(int));
         if( panStrOffNew == NULL )
@@ -769,8 +766,9 @@ int ReadOSMInfo(GByte* pabyData, GByte* pabyDataLimit,
         }
         else if (nKey == MAKE_KEY(INFO_IDX_VISIBLE, WT_VARINT))
         {
-            int nVisible;
-            READ_VARINT32(pabyData, pabyDataLimit, /*psInfo->*/nVisible);
+            SKIP_VARINT(pabyData, pabyDataLimit);
+            //int nVisible;
+            //READ_VARINT32(pabyData, pabyDataLimit, /*psInfo->*/nVisible);
         }
         else
         {
@@ -874,11 +872,12 @@ int ReadNode(GByte* pabyData, GByte* pabyDataLimit,
         }
         else if (nKey == MAKE_KEY(NODE_IDX_VALS, WT_DATA))
         {
-            unsigned int nSize;
+            //unsigned int nSize;
             unsigned int nIter = 0;
             if (sNode.nTags == 0)
                 GOTO_END_ERROR;
-            READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            //READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            SKIP_VARINT(pabyData, pabyDataLimit);
 
             for(; nIter < sNode.nTags; nIter ++)
             {
@@ -999,11 +998,12 @@ int ReadWay(GByte* pabyData, GByte* pabyDataLimit,
         }
         else if (nKey == MAKE_KEY(WAY_IDX_VALS, WT_DATA))
         {
-            unsigned int nSize;
+            //unsigned int nSize;
             unsigned int nIter = 0;
             if (sWay.nTags == 0)
                 GOTO_END_ERROR;
-            READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            //READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            SKIP_VARINT(pabyData, pabyDataLimit);
 
             for(; nIter < sWay.nTags; nIter ++)
             {
@@ -1162,11 +1162,12 @@ int ReadRelation(GByte* pabyData, GByte* pabyDataLimit,
         }
         else if (nKey == MAKE_KEY(RELATION_IDX_VALS, WT_DATA))
         {
-            unsigned int nSize;
+            //unsigned int nSize;
             unsigned int nIter = 0;
             if (sRelation.nTags == 0)
                 GOTO_END_ERROR;
-            READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            //READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            SKIP_VARINT(pabyData, pabyDataLimit);
 
             for(; nIter < sRelation.nTags; nIter ++)
             {
@@ -1233,10 +1234,11 @@ int ReadRelation(GByte* pabyData, GByte* pabyDataLimit,
         {
             unsigned int nIter = 0;
             GIntBig nMemID = 0;
-            unsigned int nSize;
+            //unsigned int nSize;
             if (sRelation.nMembers == 0)
                 GOTO_END_ERROR;
-            READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            //READ_VARUINT32(pabyData, pabyDataLimit, nSize);
+            SKIP_VARINT(pabyData, pabyDataLimit);
 
             for(; nIter < sRelation.nMembers; nIter++)
             {
@@ -1588,8 +1590,10 @@ end_error:
 /*                        EmptyNotifyNodesFunc()                        */
 /************************************************************************/
 
-static void EmptyNotifyNodesFunc(CPL_UNUSED unsigned int nNodes, CPL_UNUSED OSMNode* pasNodes,
-                                 CPL_UNUSED OSMContext* psCtxt, CPL_UNUSED void* user_data)
+static void EmptyNotifyNodesFunc(CPL_UNUSED unsigned int nNodes,
+                                 CPL_UNUSED OSMNode* pasNodes,
+                                 CPL_UNUSED OSMContext* psCtxt,
+                                 CPL_UNUSED void* user_data)
 {
 }
 
@@ -1599,7 +1603,8 @@ static void EmptyNotifyNodesFunc(CPL_UNUSED unsigned int nNodes, CPL_UNUSED OSMN
 /************************************************************************/
 
 static void EmptyNotifyWayFunc(CPL_UNUSED OSMWay* psWay,
-                               CPL_UNUSED OSMContext* psCtxt, CPL_UNUSED void* user_data)
+                               CPL_UNUSED OSMContext* psCtxt,
+                               CPL_UNUSED void* user_data)
 {
 }
 
@@ -1608,7 +1613,8 @@ static void EmptyNotifyWayFunc(CPL_UNUSED OSMWay* psWay,
 /************************************************************************/
 
 static void EmptyNotifyRelationFunc(CPL_UNUSED OSMRelation* psRelation,
-                                    CPL_UNUSED OSMContext* psCtxt, CPL_UNUSED void* user_data)
+                                    CPL_UNUSED OSMContext* psCtxt,
+                                    CPL_UNUSED void* user_data)
 {
 }
 
@@ -1616,9 +1622,12 @@ static void EmptyNotifyRelationFunc(CPL_UNUSED OSMRelation* psRelation,
 /*                         EmptyNotifyBoundsFunc()                      */
 /************************************************************************/
 
-static void EmptyNotifyBoundsFunc( CPL_UNUSED double dfXMin, CPL_UNUSED double dfYMin,
-                                   CPL_UNUSED double dfXMax, CPL_UNUSED double dfYMax,
-                                   CPL_UNUSED OSMContext* psCtxt, CPL_UNUSED void* user_data )
+static void EmptyNotifyBoundsFunc( CPL_UNUSED double dfXMin,
+                                   CPL_UNUSED double dfYMin,
+                                   CPL_UNUSED double dfXMax,
+                                   CPL_UNUSED double dfYMax,
+                                   CPL_UNUSED OSMContext* psCtxt,
+                                   CPL_UNUSED void* user_data )
 {
 }
 
@@ -1908,7 +1917,7 @@ static void XMLCALL OSM_XML_startElementCbk(void *pUserData, const char *pszName
     else if( psCtxt->bInRelation &&
              strcmp(pszName, "member") == 0 )
     {
-        /* 300 is the recommanded value, but there are files with more than 2000 so we should be able */
+        /* 300 is the recommended value, but there are files with more than 2000 so we should be able */
         /* to realloc over that value */
         if (psCtxt->sRelation.nMembers >= psCtxt->nMembersAllocated)
         {
@@ -2249,7 +2258,7 @@ OSMContext* OSM_Open( const char* pszFilename,
         psCtxt->nTagsAllocated = 256;
         psCtxt->pasTags = (OSMTag*) VSIMalloc(sizeof(OSMTag) * psCtxt->nTagsAllocated);
 
-        /* 300 is the recommanded value, but there are files with more than 2000 so we should be able */
+        /* 300 is the recommended value, but there are files with more than 2000 so we should be able */
         /* to realloc over that value */
         psCtxt->nMembersAllocated = 2000;
         psCtxt->pasMembers = (OSMMember*) VSIMalloc(sizeof(OSMMember) * psCtxt->nMembersAllocated);
diff --git a/ogr/ogrsf_frmts/pcidsk/GNUmakefile b/ogr/ogrsf_frmts/pcidsk/GNUmakefile
deleted file mode 100644
index d23e4c8..0000000
--- a/ogr/ogrsf_frmts/pcidsk/GNUmakefile
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-include ../../../GDALmake.opt
-
-OBJ	=	ogrpcidskdriver.o ogrpcidskdatasource.o ogrpcidsklayer.o
-
-ifeq ($(PCIDSK_SETTING),internal)
-PCIDSK_INCLUDE = -I../../../frmts/pcidsk/sdk
-endif
-
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(PCIDSK_INCLUDE) $(CPPFLAGS)
-
-default:	$(O_OBJ:.o=.$(OBJ_EXT))
-
-clean:
-	rm -f *.o $(O_OBJ)
-
-$(O_OBJ):	ogr_pcidsk.h
diff --git a/ogr/ogrsf_frmts/pcidsk/makefile.vc b/ogr/ogrsf_frmts/pcidsk/makefile.vc
deleted file mode 100644
index c8ce90b..0000000
--- a/ogr/ogrsf_frmts/pcidsk/makefile.vc
+++ /dev/null
@@ -1,16 +0,0 @@
-
-OBJ	=	ogrpcidskdriver.obj ogrpcidskdatasource.obj ogrpcidsklayer.obj
-
-EXTRAFLAGS =	-I.. -I..\.. $(PCIDSK_INC) -I..\..\..\frmts\pcidsk\sdk
-
-GDAL_ROOT	=	..\..\..
-
-!INCLUDE $(GDAL_ROOT)\nmake.opt
-
-default:	$(OBJ)
-
-clean:
-	-del *.obj *.pdb
-
-
-
diff --git a/ogr/ogrsf_frmts/pcidsk/ogr_pcidsk.h b/ogr/ogrsf_frmts/pcidsk/ogr_pcidsk.h
deleted file mode 100644
index 3fc7720..0000000
--- a/ogr/ogrsf_frmts/pcidsk/ogr_pcidsk.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/******************************************************************************
- * $Id: ogr_csv.h 17495 2009-08-02 11:44:13Z rouault $
- *
- * Project:  PCIDSK Translator
- * Purpose:  Definition of classes for PCIDSK vector segment driver.
- * Author:   Frank Warmerdam, warmerdam at pobox.com
- *
- ******************************************************************************
- * Copyright (c) 2009,  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.
- ****************************************************************************/
-
-#ifndef _OGR_PCIDSK_H_INCLUDED
-#define _OGR_PCIDSK_H_INCLUDED
-
-#include "ogrsf_frmts.h"
-#include "pcidsk.h"
-#include "pcidsk_vectorsegment.h"
-
-class OGRPCIDSKDataSource;
-
-/************************************************************************/
-/*                             OGRPCIDSKLayer                              */
-/************************************************************************/
-
-class OGRPCIDSKLayer : public OGRLayer
-{
-    PCIDSK::PCIDSKVectorSegment *poVecSeg;
-    PCIDSK::PCIDSKSegment       *poSeg;
-
-    OGRFeatureDefn     *poFeatureDefn;
-
-    OGRFeature *        GetNextUnfilteredFeature();
-
-    int                 iRingStartField;
-    PCIDSK::ShapeId     hLastShapeId;
-
-    bool                bUpdateAccess;
-
-    OGRSpatialReference *poSRS;
-
-  public:
-    OGRPCIDSKLayer( PCIDSK::PCIDSKSegment*, bool bUpdate );
-    ~OGRPCIDSKLayer();
-
-    void                ResetReading();
-    OGRFeature *        GetNextFeature();
-    OGRFeature         *GetFeature( long nFeatureId );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-
-    OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
-
-    int                 TestCapability( const char * );
-
-    OGRErr              DeleteFeature( long nFID );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateField( OGRFieldDefn *poField,
-                                     int bApproxOK = TRUE );
-
-    int                 GetFeatureCount( int );
-    OGRErr              GetExtent( OGREnvelope *psExtent, int bForce );
-};
-
-/************************************************************************/
-/*                           OGRPCIDSKDataSource                           */
-/************************************************************************/
-
-class OGRPCIDSKDataSource : public OGRDataSource
-{
-    CPLString           osName;
-
-    std::vector<OGRPCIDSKLayer*> apoLayers;
-
-    bool                bUpdate;
-
-    PCIDSK::PCIDSKFile  *poFile;
-    
-  public:
-                        OGRPCIDSKDataSource();
-                        ~OGRPCIDSKDataSource();
-
-    int                 Open( const char * pszFilename, int bUpdate);
-    
-    const char          *GetName() { return osName; }
-
-    int                 GetLayerCount() { return (int) apoLayers.size(); }
-    OGRLayer            *GetLayer( int );
-
-    int                 TestCapability( const char * );
-
-    OGRLayer           *CreateLayer( const char *, OGRSpatialReference *,
-                                     OGRwkbGeometryType, char ** );
-};
-
-/************************************************************************/
-/*                           OGRPCIDSKDriver                            */
-/************************************************************************/
-
-class OGRPCIDSKDriver : public OGRSFDriver
-{
-  public:
-                ~OGRPCIDSKDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    OGRDataSource *CreateDataSource( const char *pszName, 
-                                     char **papszOptions );
-    int         TestCapability( const char * );
-};
-
-
-#endif /* ndef _OGR_PCIDSK_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/pcidsk/ogrpcidskdatasource.cpp b/ogr/ogrsf_frmts/pcidsk/ogrpcidskdatasource.cpp
deleted file mode 100644
index 3f409a8..0000000
--- a/ogr/ogrsf_frmts/pcidsk/ogrpcidskdatasource.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/******************************************************************************
- * $Id: ogrcsvdatasource.cpp 17806 2009-10-13 17:27:54Z rouault $
- *
- * Project:  PCIDSK Translator
- * Purpose:  Implements OGRPCIDSKDataSource class
- * Author:   Frank Warmerdam, warmerdam at pobox.com
- *
- ******************************************************************************
- * Copyright (c) 2009, Frank Warmerdam <warmerdam at pobox.com>
- *
- * 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.
- ****************************************************************************/
-
-#include "ogr_pcidsk.h"
-#include "cpl_conv.h"
-#include "cpl_string.h"
-#include "cpl_csv.h"
-
-CPL_CVSID("$Id: ogrcsvdatasource.cpp 17806 2009-10-13 17:27:54Z rouault $");
-
-const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
-
-/************************************************************************/
-/*                        OGRPCIDSKDataSource()                         */
-/************************************************************************/
-
-OGRPCIDSKDataSource::OGRPCIDSKDataSource()
-
-{
-    poFile = NULL;
-    bUpdate = FALSE;
-}
-
-/************************************************************************/
-/*                        ~OGRPCIDSKDataSource()                        */
-/************************************************************************/
-
-OGRPCIDSKDataSource::~OGRPCIDSKDataSource()
-
-{
-    while( apoLayers.size() > 0 )
-    {
-        delete apoLayers.back();
-        apoLayers.pop_back();
-    }
-    
-    if( poFile != NULL )
-    {
-        delete poFile;
-        poFile = NULL;
-    }
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPCIDSKDataSource::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODsCCreateLayer) )
-        return bUpdate;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                              GetLayer()                              */
-/************************************************************************/
-
-OGRLayer *OGRPCIDSKDataSource::GetLayer( int iLayer )
-
-{
-    if( iLayer < 0 || iLayer >= (int) apoLayers.size() )
-        return NULL;
-    else
-        return apoLayers[iLayer];
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-int OGRPCIDSKDataSource::Open( const char * pszFilename, int bUpdateIn )
-
-{
-    if( !EQUAL(CPLGetExtension(pszFilename),"pix") )
-        return FALSE;
-
-    osName = pszFilename;
-    if( bUpdateIn )
-        bUpdate = true;
-    else
-        bUpdate = false;
-
-/* -------------------------------------------------------------------- */
-/*      Open the file, and create layer for each vector segment.        */
-/* -------------------------------------------------------------------- */
-    try 
-    {
-        PCIDSK::PCIDSKSegment *segobj;
-        const char *pszAccess = "r";
-
-        if( bUpdateIn )
-            pszAccess = "r+";
-
-        poFile = PCIDSK::Open( pszFilename, pszAccess,
-                               PCIDSK2GetInterfaces() );
-
-        for( segobj = poFile->GetSegment( PCIDSK::SEG_VEC, "" );
-             segobj != NULL;
-             segobj = poFile->GetSegment( PCIDSK::SEG_VEC, "",
-                                          segobj->GetSegmentNumber() ) )
-        {
-            apoLayers.push_back( new OGRPCIDSKLayer( segobj, bUpdate ) );
-        }
-
-        /* Check if this is a raster-only PCIDSK file */
-        if ( !bUpdate && apoLayers.size() == 0 && poFile->GetChannels() != 0 )
-            return FALSE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return FALSE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-/************************************************************************/
-/*                            CreateLayer()                             */
-/************************************************************************/
-
-OGRLayer *
-OGRPCIDSKDataSource::CreateLayer( const char * pszLayerName,
-                                  OGRSpatialReference *poSRS,
-                                  OGRwkbGeometryType eType,
-                                  CPL_UNUSED char ** papszOptions )
-{
-/* -------------------------------------------------------------------- */
-/*      Verify we are in update mode.                                   */
-/* -------------------------------------------------------------------- */
-    if( !bUpdate )
-    {
-        CPLError( CE_Failure, CPLE_NoWriteAccess,
-                  "Data source %s opened read-only.\n"
-                  "New layer %s cannot be created.\n",
-                  osName.c_str(), pszLayerName );
-        
-        return NULL;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Figure out what type of layer we need.                          */
-/* -------------------------------------------------------------------- */
-    std::string osLayerType;
-
-    switch( wkbFlatten(eType) )
-    {
-      case wkbPoint:
-        osLayerType = "POINTS";
-        break;
-    
-      case wkbLineString:
-        osLayerType = "ARCS";
-        break;
-
-      case wkbPolygon:
-        osLayerType = "WHOLE_POLYGONS";
-        break;
-        
-      case wkbNone:
-        osLayerType = "TABLE";
-        break;
-
-      default:
-        break;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Create the segment.                                             */
-/* -------------------------------------------------------------------- */
-    int     nSegNum = poFile->CreateSegment( pszLayerName, "", 
-                                             PCIDSK::SEG_VEC, 0L );
-    PCIDSK::PCIDSKSegment *poSeg = poFile->GetSegment( nSegNum );
-    PCIDSK::PCIDSKVectorSegment *poVecSeg = 
-        dynamic_cast<PCIDSK::PCIDSKVectorSegment*>( poSeg );
-
-    if( osLayerType != "" )
-        poSeg->SetMetadataValue( "LAYER_TYPE", osLayerType );
-
-/* -------------------------------------------------------------------- */
-/*      Do we need to apply a coordinate system?                        */
-/* -------------------------------------------------------------------- */
-    char *pszGeosys = NULL;
-    char *pszUnits = NULL;
-    double *padfPrjParams = NULL;
-
-    if( poSRS != NULL 
-        && poSRS->exportToPCI( &pszGeosys, &pszUnits, 
-                               &padfPrjParams ) == OGRERR_NONE )
-    {
-        try
-        {
-            std::vector<double> adfPCIParameters;
-            int i;
-
-            for( i = 0; i < 17; i++ )
-                adfPCIParameters.push_back( padfPrjParams[i] );
-            
-            if( EQUALN(pszUnits,"FOOT",4) )
-                adfPCIParameters.push_back( 
-                    (double)(int) PCIDSK::UNIT_US_FOOT );
-            else if( EQUALN(pszUnits,"INTL FOOT",9) )
-                adfPCIParameters.push_back( 
-                    (double)(int) PCIDSK::UNIT_INTL_FOOT );
-            else if( EQUALN(pszUnits,"DEGREE",6) )
-                adfPCIParameters.push_back( 
-                    (double)(int) PCIDSK::UNIT_DEGREE );
-            else 
-                adfPCIParameters.push_back( 
-                    (double)(int) PCIDSK::UNIT_METER );
-            
-            poVecSeg->SetProjection( pszGeosys, adfPCIParameters );
-        }
-        catch( PCIDSK::PCIDSKException ex )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "%s", ex.what() );
-        }
-        
-        CPLFree( pszGeosys );
-        CPLFree( pszUnits );
-        CPLFree( padfPrjParams );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Create the layer object.                                        */
-/* -------------------------------------------------------------------- */
-    apoLayers.push_back( new OGRPCIDSKLayer( poSeg, TRUE ) );
-
-    return apoLayers[apoLayers.size()-1];
-}
-
diff --git a/ogr/ogrsf_frmts/pcidsk/ogrpcidskdriver.cpp b/ogr/ogrsf_frmts/pcidsk/ogrpcidskdriver.cpp
deleted file mode 100644
index 5f1c4fc..0000000
--- a/ogr/ogrsf_frmts/pcidsk/ogrpcidskdriver.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/******************************************************************************
- * $Id: ogrcsvdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
- *
- * Project:  PCIDSK Translator
- * Purpose:  Implements OGRPCIDSKDriver.
- * Author:   Frank Warmerdam, warmerdam at pobox.com
- *
- ******************************************************************************
- * Copyright (c) 2009, Frank Warmerdam <warmerdam at pobox.com>
- *
- * 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.
- ****************************************************************************/
-
-#include "ogr_pcidsk.h"
-#include "cpl_conv.h"
-
-CPL_CVSID("$Id: ogrcsvdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-const PCIDSK::PCIDSKInterfaces *PCIDSK2GetInterfaces(void);
-
-/************************************************************************/
-/*                          ~OGRPCIDSKDriver()                          */
-/************************************************************************/
-
-OGRPCIDSKDriver::~OGRPCIDSKDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRPCIDSKDriver::GetName()
-
-{
-    return "PCIDSK";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-OGRDataSource *OGRPCIDSKDriver::Open( const char * pszFilename, int bUpdate )
-
-{
-    OGRPCIDSKDataSource   *poDS = new OGRPCIDSKDataSource();
-
-    if( !poDS->Open( pszFilename, bUpdate ) )
-    {
-        delete poDS;
-        poDS = NULL;
-    }
-
-    return poDS;
-}
-
-/************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGRPCIDSKDriver::CreateDataSource( const char * pszName,
-                                                  CPL_UNUSED char **papszOptions )
-{
-/* -------------------------------------------------------------------- */
-/*      Try creation.                                                   */
-/* -------------------------------------------------------------------- */
-    try {
-        PCIDSK::PCIDSKFile *poFile;
-
-        // at some point we should use gdal/frmts/pcidsk io interface.
-        poFile = PCIDSK::Create( pszName, 512, 512, 0, NULL, "BAND", 
-                                 PCIDSK2GetInterfaces() );
-        delete poFile;
-
-        // TODO: should we ensure this driver gets used?
-
-        return Open( pszName, TRUE );
-    }
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions.                                                */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s", ex.what() );
-        return NULL;
-    }
-    catch( ... )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "PCIDSK::Create() failed, unexpected exception." );
-        return NULL;
-    }
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPCIDSKDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                         RegisterOGRPCIDSK()                          */
-/************************************************************************/
-
-void RegisterOGRPCIDSK()
-
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPCIDSKDriver );
-}
-
diff --git a/ogr/ogrsf_frmts/pcidsk/ogrpcidsklayer.cpp b/ogr/ogrsf_frmts/pcidsk/ogrpcidsklayer.cpp
deleted file mode 100644
index ef5e848..0000000
--- a/ogr/ogrsf_frmts/pcidsk/ogrpcidsklayer.cpp
+++ /dev/null
@@ -1,833 +0,0 @@
-/******************************************************************************
- * $Id: ogrcsvlayer.cpp 17496 2009-08-02 11:54:23Z rouault $
- *
- * Project:  PCIDSK Translator
- * Purpose:  Implements OGRPCIDSKLayer class.
- * Author:   Frank Warmerdam <warmerdam at pobox.com>
- *
- ******************************************************************************
- * Copyright (c) 2009, Frank Warmerdam <warmerdam at pobox.com>
- * Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * 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.
- ****************************************************************************/
-
-#include "ogr_pcidsk.h"
-
-CPL_CVSID("$Id: ogrcsvlayer.cpp 17496 2009-08-02 11:54:23Z rouault $");
-
-/************************************************************************/
-/*                           OGRPCIDSKLayer()                           */
-/************************************************************************/
-
-OGRPCIDSKLayer::OGRPCIDSKLayer( PCIDSK::PCIDSKSegment *poSegIn,
-                                bool bUpdate )
-
-{
-    poSRS = NULL;
-    bUpdateAccess = bUpdate;
-    poSeg = poSegIn;
-    poVecSeg = dynamic_cast<PCIDSK::PCIDSKVectorSegment*>( poSeg );
-
-    poFeatureDefn = new OGRFeatureDefn( poSeg->GetName().c_str() );
-    poFeatureDefn->Reference();
-
-    hLastShapeId = PCIDSK::NullShapeId;
-
-/* -------------------------------------------------------------------- */
-/*      Attempt to assign a geometry type.                              */
-/* -------------------------------------------------------------------- */
-    try {
-        std::string osLayerType = poSeg->GetMetadataValue( "LAYER_TYPE" );
-        
-        if( osLayerType == "WHOLE_POLYGONS" )
-            poFeatureDefn->SetGeomType( wkbPolygon25D );
-        else if( osLayerType == "ARCS" || osLayerType == "TOPO_ARCS" )
-            poFeatureDefn->SetGeomType( wkbLineString25D );
-        else if( osLayerType == "POINTS" || osLayerType == "TOPO_NODES" )
-            poFeatureDefn->SetGeomType( wkbPoint25D );
-        else if( osLayerType == "TABLE" )
-            poFeatureDefn->SetGeomType( wkbNone );
-    } catch(...) {}
-
-
-/* -------------------------------------------------------------------- */
-/*      Build field definitions.                                        */
-/* -------------------------------------------------------------------- */
-    try
-    {
-        iRingStartField = -1;
-
-        for( int iField = 0; iField < poVecSeg->GetFieldCount(); iField++ )
-        {
-            OGRFieldDefn oField( poVecSeg->GetFieldName(iField).c_str(), OFTString);
-            
-            switch( poVecSeg->GetFieldType(iField) )
-            {
-              case PCIDSK::FieldTypeFloat:
-              case PCIDSK::FieldTypeDouble:
-                oField.SetType( OFTReal );
-                break;
-                
-              case PCIDSK::FieldTypeInteger:
-                oField.SetType( OFTInteger );
-                break;
-                
-              case PCIDSK::FieldTypeString:
-                oField.SetType( OFTString );
-                break;
-                
-              case PCIDSK::FieldTypeCountedInt:
-                oField.SetType( OFTIntegerList );
-                break;
-                
-              default:
-                CPLAssert( FALSE );
-                break;
-            }
-            
-            // we ought to try and extract some width/precision information
-            // from the format string at some point.
-            
-            // If the last field is named RingStart we treat it specially.
-            if( EQUAL(oField.GetNameRef(),"RingStart")
-                && oField.GetType() == OFTIntegerList 
-                && iField == poVecSeg->GetFieldCount()-1 )
-                iRingStartField = iField;
-            else
-                poFeatureDefn->AddFieldDefn( &oField );
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Look for a coordinate system.                                   */
-/* -------------------------------------------------------------------- */
-        CPLString osGeosys;
-        const char *pszUnits = NULL;
-        std::vector<double> adfParameters;
-
-        adfParameters = poVecSeg->GetProjection( osGeosys );
-
-        if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
-            == PCIDSK::UNIT_DEGREE )
-            pszUnits = "DEGREE";
-        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
-                 == PCIDSK::UNIT_METER )
-            pszUnits = "METER";
-        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
-                 == PCIDSK::UNIT_US_FOOT )
-            pszUnits = "FOOT";
-        else if( ((PCIDSK::UnitCode)(int)adfParameters[16]) 
-                 == PCIDSK::UNIT_INTL_FOOT )
-            pszUnits = "INTL FOOT";
-
-        poSRS = new OGRSpatialReference();
-
-        if( poSRS->importFromPCI( osGeosys, pszUnits, 
-                                  &(adfParameters[0]) ) != OGRERR_NONE )
-        {
-            delete poSRS;
-            poSRS = NULL;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Trap pcidsk exceptions.                                         */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() );
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." );
-    }
-    
-    if( poFeatureDefn->GetGeomFieldCount() > 0 )
-        poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
-}
-
-/************************************************************************/
-/*                          ~OGRPCIDSKLayer()                           */
-/************************************************************************/
-
-OGRPCIDSKLayer::~OGRPCIDSKLayer()
-
-{
-    if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
-    {
-        CPLDebug( "PCIDSK", "%d features read on layer '%s'.",
-                  (int) m_nFeaturesRead, 
-                  poFeatureDefn->GetName() );
-    }
-
-    poFeatureDefn->Release();
-
-    if (poSRS)
-        poSRS->Release();
-}
-
-/************************************************************************/
-/*                            ResetReading()                            */
-/************************************************************************/
-
-void OGRPCIDSKLayer::ResetReading()
-
-{
-    hLastShapeId = PCIDSK::NullShapeId;
-}
-
-/************************************************************************/
-/*                           GetNextFeature()                           */
-/************************************************************************/
-
-OGRFeature *OGRPCIDSKLayer::GetNextFeature()
-
-{
-    OGRFeature  *poFeature = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Read features till we find one that satisfies our current       */
-/*      spatial criteria.                                               */
-/* -------------------------------------------------------------------- */
-    while( TRUE )
-    {
-        poFeature = GetNextUnfilteredFeature();
-        if( poFeature == NULL )
-            break;
-
-        if( (m_poFilterGeom == NULL
-            || FilterGeometry( poFeature->GetGeometryRef() ) )
-            && (m_poAttrQuery == NULL
-                || m_poAttrQuery->Evaluate( poFeature )) )
-            break;
-
-        delete poFeature;
-    }
-
-    return poFeature;
-}
-
-/************************************************************************/
-/*                      GetNextUnfilteredFeature()                      */
-/************************************************************************/
-
-OGRFeature * OGRPCIDSKLayer::GetNextUnfilteredFeature()
-
-{
-/* -------------------------------------------------------------------- */
-/*      Get the next shapeid.                                           */
-/* -------------------------------------------------------------------- */
-    if( hLastShapeId == PCIDSK::NullShapeId )
-        hLastShapeId = poVecSeg->FindFirst();
-    else
-        hLastShapeId = poVecSeg->FindNext( hLastShapeId );
-
-    if( hLastShapeId == PCIDSK::NullShapeId )
-        return NULL;
-
-    return GetFeature( hLastShapeId );
-}
-
-/************************************************************************/
-/*                             GetFeature()                             */
-/************************************************************************/
-
-OGRFeature *OGRPCIDSKLayer::GetFeature( long nFID )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Create the OGR feature.                                         */
-/* -------------------------------------------------------------------- */
-    OGRFeature *poFeature;
-
-    poFeature = new OGRFeature( poFeatureDefn );
-    poFeature->SetFID( (int) nFID );
-
-/* -------------------------------------------------------------------- */
-/*      Set attributes for any indicated attribute records.             */
-/* -------------------------------------------------------------------- */
-    try {
-        std::vector<PCIDSK::ShapeField> aoFields;
-        unsigned int i;
-
-        poVecSeg->GetFields( (int) nFID, aoFields );
-        for( i=0; i < aoFields.size(); i++ )
-        {
-            if( (int) i == iRingStartField )
-                continue;
-
-            switch( aoFields[i].GetType() )
-            {
-              case PCIDSK::FieldTypeNone:
-                // null field value.
-                break;
-
-              case PCIDSK::FieldTypeInteger:
-                poFeature->SetField( i, aoFields[i].GetValueInteger() );
-                break;
-                                 
-              case PCIDSK::FieldTypeFloat:
-                poFeature->SetField( i, aoFields[i].GetValueFloat() );
-                break;
-                                 
-              case PCIDSK::FieldTypeDouble:
-                poFeature->SetField( i, aoFields[i].GetValueDouble() );
-                break;
-                                 
-              case PCIDSK::FieldTypeString:
-                poFeature->SetField( i, aoFields[i].GetValueString().c_str() );
-                break;
-                                 
-              case PCIDSK::FieldTypeCountedInt:
-                std::vector<PCIDSK::int32> list = aoFields[i].GetValueCountedInt();
-            
-                poFeature->SetField( i, list.size(), &(list[0]) );
-                break;
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Translate the geometry.                                         */
-/* -------------------------------------------------------------------- */
-        std::vector<PCIDSK::ShapeVertex> aoVertices;
-
-        poVecSeg->GetVertices( (int) nFID, aoVertices );
-
-/* -------------------------------------------------------------------- */
-/*      Point                                                           */
-/* -------------------------------------------------------------------- */
-        if( poFeatureDefn->GetGeomType() == wkbPoint25D 
-            || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown 
-                && aoVertices.size() == 1) )
-        {
-            if( aoVertices.size() == 1 )
-            {
-                OGRPoint* poPoint =
-                    new OGRPoint( aoVertices[0].x,
-                                  aoVertices[0].y, 
-                                  aoVertices[0].z );
-                if (poSRS)
-                    poPoint->assignSpatialReference(poSRS);
-                poFeature->SetGeometryDirectly(poPoint);
-            }
-            else
-            {
-                // report issue?
-            }
-        }    
-
-/* -------------------------------------------------------------------- */
-/*      LineString                                                      */
-/* -------------------------------------------------------------------- */
-        else if( poFeatureDefn->GetGeomType() == wkbLineString25D 
-                 || (wkbFlatten(poFeatureDefn->GetGeomType()) == wkbUnknown 
-                     && aoVertices.size() > 1) )
-        {
-            // We should likely be applying ringstart to break things into 
-            // a multilinestring in some cases.
-            if( aoVertices.size() > 1 )
-            {
-                OGRLineString *poLS = new OGRLineString();
-
-                poLS->setNumPoints( aoVertices.size() );
-            
-                for( i = 0; i < aoVertices.size(); i++ )
-                    poLS->setPoint( i,
-                                    aoVertices[i].x, 
-                                    aoVertices[i].y, 
-                                    aoVertices[i].z );
-                if (poSRS)
-                    poLS->assignSpatialReference(poSRS);
-
-                poFeature->SetGeometryDirectly( poLS );
-            }
-            else
-            {
-                // report issue?
-            }
-        }    
-
-/* -------------------------------------------------------------------- */
-/*      Polygon - Currently we have no way to recognise if we are       */
-/*      dealing with a multipolygon when we have more than one          */
-/*      ring.  Also, PCIDSK allows the rings to be in arbitrary         */
-/*      order, not necessarily outside first which we are not yet       */
-/*      ready to address in the following code.                         */
-/* -------------------------------------------------------------------- */
-        else if( poFeatureDefn->GetGeomType() == wkbPolygon25D )
-        {
-            std::vector<PCIDSK::int32> anRingStart;
-            OGRPolygon *poPoly = new OGRPolygon();
-            unsigned int iRing;
-
-            if( iRingStartField != -1 )
-                anRingStart = aoFields[iRingStartField].GetValueCountedInt();
-
-            for( iRing = 0; iRing < anRingStart.size()+1; iRing++ )
-            {
-                int iStartVertex, iEndVertex, iVertex;
-                OGRLinearRing *poRing = new OGRLinearRing();
-
-                if( iRing == 0 )
-                    iStartVertex = 0;
-                else
-                    iStartVertex = anRingStart[iRing-1];
-
-                if( iRing == anRingStart.size() )
-                    iEndVertex = aoVertices.size() - 1;
-                else
-                    iEndVertex = anRingStart[iRing] - 1;
-
-                poRing->setNumPoints( iEndVertex - iStartVertex + 1 );
-                for( iVertex = iStartVertex; iVertex <= iEndVertex; iVertex++ )
-                {
-                    poRing->setPoint( iVertex - iStartVertex,
-                                      aoVertices[iVertex].x, 
-                                      aoVertices[iVertex].y, 
-                                      aoVertices[iVertex].z );
-                }
-
-                poPoly->addRingDirectly( poRing );
-            }
-
-            if (poSRS)
-                poPoly->assignSpatialReference(poSRS);
-
-            poFeature->SetGeometryDirectly( poPoly );
-        }    
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        delete poFeature;
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return NULL;
-    }
-    catch(...)
-    {
-        delete poFeature;
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return NULL;
-    }
-
-    m_nFeaturesRead++;
-
-    return poFeature;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPCIDSKLayer::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,OLCRandomRead) )
-        return TRUE;
-
-    else if( EQUAL(pszCap,OLCFastFeatureCount) )
-        return m_poFilterGeom == NULL && m_poAttrQuery == NULL;
-
-    else if( EQUAL(pszCap,OLCSequentialWrite) 
-             || EQUAL(pszCap,OLCRandomWrite) )
-        return bUpdateAccess;
-
-    else if( EQUAL(pszCap,OLCDeleteFeature) )
-        return bUpdateAccess;
-
-    else if( EQUAL(pszCap,OLCCreateField) )
-        return bUpdateAccess;
-
-    else 
-        return FALSE;
-}
-
-/************************************************************************/
-/*                          GetFeatureCount()                           */
-/************************************************************************/
-
-int OGRPCIDSKLayer::GetFeatureCount( int bForce )
-
-{
-    if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
-        return OGRLayer::GetFeatureCount( bForce );
-    else
-    {
-        try {
-            return poVecSeg->GetShapeCount();
-        } catch(...) {
-            return 0;
-        }
-    }
-}
-
-/************************************************************************/
-/*                             GetExtent()                              */
-/************************************************************************/
-
-OGRErr OGRPCIDSKLayer::GetExtent (OGREnvelope *psExtent, int bForce)
-
-{
-    if( !bForce )
-        return OGRERR_FAILURE;
-    
-/* -------------------------------------------------------------------- */
-/*      Loop over all features, but just read the geometry.  This is    */
-/*      a fair amount quicker than actually processing all the          */
-/*      attributes, forming features and then exaimining the            */
-/*      geometries as the default implemntation would do.               */
-/* -------------------------------------------------------------------- */
-    try
-    {
-        bool bHaveExtent = FALSE;
-
-        std::vector<PCIDSK::ShapeVertex> asVertices;
-
-        for( PCIDSK::ShapeIterator oIt = poVecSeg->begin(); 
-             oIt != poVecSeg->end();
-             oIt++ )
-        {
-            unsigned int i;
-
-            poVecSeg->GetVertices( *oIt, asVertices );
-
-            for( i = 0; i < asVertices.size(); i++ )
-            {
-                if( !bHaveExtent )
-                {
-                    psExtent->MinX = psExtent->MaxX = asVertices[i].x;
-                    psExtent->MinY = psExtent->MaxY = asVertices[i].y;
-                    bHaveExtent = true;
-                }
-                else
-                {
-                    psExtent->MinX = MIN(psExtent->MinX,asVertices[i].x);
-                    psExtent->MaxX = MAX(psExtent->MaxX,asVertices[i].x);
-                    psExtent->MinY = MIN(psExtent->MinY,asVertices[i].y);
-                    psExtent->MaxY = MAX(psExtent->MaxY,asVertices[i].y);
-                }
-            }
-        }
-
-        if( bHaveExtent )
-            return OGRERR_NONE;
-        else
-            return OGRERR_FAILURE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Trap pcidsk exceptions.                                         */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "PCIDSK Exception while initializing layer, operation likely impaired.\n%s", ex.what() );
-        return OGRERR_FAILURE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped while initializing layer, operation likely impaired." );
-        return OGRERR_FAILURE;
-    }
-}
-
-/************************************************************************/
-/*                           DeleteFeature()                            */
-/************************************************************************/
-
-OGRErr OGRPCIDSKLayer::DeleteFeature( long nFID )
-
-{
-    try {
-
-        poVecSeg->DeleteShape( (PCIDSK::ShapeId) nFID );
-
-        return OGRERR_NONE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return OGRERR_FAILURE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return OGRERR_FAILURE;
-    }
-}
-
-/************************************************************************/
-/*                           CreateFeature()                            */
-/************************************************************************/
-
-OGRErr OGRPCIDSKLayer::CreateFeature( OGRFeature *poFeature )
-
-{
-    try {
-
-        PCIDSK::ShapeId id = poVecSeg->CreateShape( 
-            (PCIDSK::ShapeId) poFeature->GetFID() );
-
-        poFeature->SetFID( (long) id );
-
-        return SetFeature( poFeature );
-    }
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return OGRERR_FAILURE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return OGRERR_FAILURE;
-    }
-    
-}
-
-/************************************************************************/
-/*                             SetFeature()                             */
-/************************************************************************/
-
-OGRErr OGRPCIDSKLayer::SetFeature( OGRFeature *poFeature )
-
-{
-    PCIDSK::ShapeId id = (PCIDSK::ShapeId) poFeature->GetFID();
-    
-/* -------------------------------------------------------------------- */
-/*      Translate attribute fields.                                     */
-/* -------------------------------------------------------------------- */
-    try {
-
-        int iPCI;
-        std::vector<PCIDSK::ShapeField>  aoPCIFields;
-
-        aoPCIFields.resize(poVecSeg->GetFieldCount());
-
-        for( iPCI = 0; iPCI < poVecSeg->GetFieldCount(); iPCI++ )
-        {
-            int iOGR;
-
-            iOGR = poFeatureDefn->GetFieldIndex(
-                poVecSeg->GetFieldName(iPCI).c_str() );
-
-            if( iOGR == -1 )
-                continue;
-
-            switch( poVecSeg->GetFieldType(iPCI) )
-            {
-              case PCIDSK::FieldTypeInteger:
-                aoPCIFields[iPCI].SetValue(
-                    poFeature->GetFieldAsInteger( iOGR ) );
-                break;
-
-              case PCIDSK::FieldTypeFloat:
-                aoPCIFields[iPCI].SetValue(
-                    (float) poFeature->GetFieldAsDouble( iOGR ) );
-                break;
-
-              case PCIDSK::FieldTypeDouble:
-                aoPCIFields[iPCI].SetValue(
-                    (double) poFeature->GetFieldAsDouble( iOGR ) );
-                break;
-
-              case PCIDSK::FieldTypeString:
-                aoPCIFields[iPCI].SetValue(
-                    poFeature->GetFieldAsString( iOGR ) );
-                break;
-
-              case PCIDSK::FieldTypeCountedInt:
-              {
-                  int nCount;
-                  const int *panList = 
-                      poFeature->GetFieldAsIntegerList( iOGR, &nCount );
-                  std::vector<PCIDSK::int32> anList;
-                  
-                  anList.resize( nCount );
-                  memcpy( &(anList[0]), panList, 4 * anList.size() );
-                  aoPCIFields[iPCI].SetValue( anList );
-              }
-              break;
-
-              default:
-                CPLAssert( FALSE );
-                break;
-            }
-        }
-
-        if( poVecSeg->GetFieldCount() > 0 )
-            poVecSeg->SetFields( id, aoPCIFields );
-
-/* -------------------------------------------------------------------- */
-/*      Translate the geometry.                                         */
-/* -------------------------------------------------------------------- */
-        std::vector<PCIDSK::ShapeVertex> aoVertices;
-        OGRGeometry *poGeometry = poFeature->GetGeometryRef();
-
-        if( poGeometry == NULL )
-        {
-        }
-
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
-        {
-            OGRPoint *poPoint = (OGRPoint *) poGeometry;
-
-            aoVertices.resize(1);
-            aoVertices[0].x = poPoint->getX();
-            aoVertices[0].y = poPoint->getY();
-            aoVertices[0].z = poPoint->getZ();
-        }
-
-        else if( wkbFlatten(poGeometry->getGeometryType()) == wkbLineString )
-        {
-            OGRLineString *poLS = (OGRLineString *) poGeometry;
-            unsigned int i;
-
-            aoVertices.resize(poLS->getNumPoints());
-
-            for( i = 0; i < aoVertices.size(); i++ )
-            {
-                aoVertices[i].x = poLS->getX(i);
-                aoVertices[i].y = poLS->getY(i);
-                aoVertices[i].z = poLS->getZ(i);
-            }
-        }
-
-        else
-        {
-            CPLDebug( "PCIDSK", "Unsupported geometry type in SetFeature(): %s",
-                      poGeometry->getGeometryName() );
-        }
-
-        poVecSeg->SetVertices( id, aoVertices );
-
-    } /* try */
-
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return OGRERR_FAILURE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return OGRERR_FAILURE;
-    }
-
-    return OGRERR_NONE;
-}
-
-/************************************************************************/
-/*                            CreateField()                             */
-/************************************************************************/
-
-OGRErr OGRPCIDSKLayer::CreateField( OGRFieldDefn *poFieldDefn,
-                                    int bApproxOK )
-
-{
-    try {
-        
-        if( poFieldDefn->GetType() == OFTInteger )
-        {
-            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
-                                PCIDSK::FieldTypeInteger, 
-                                "", "" );
-            poFeatureDefn->AddFieldDefn( poFieldDefn );
-        }
-        else if( poFieldDefn->GetType() == OFTReal )
-        {
-            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
-                                PCIDSK::FieldTypeDouble, 
-                                "", "" );
-            poFeatureDefn->AddFieldDefn( poFieldDefn );
-        }
-        else if( poFieldDefn->GetType() == OFTString )
-        {
-            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
-                                PCIDSK::FieldTypeString, 
-                                "", "" );
-            poFeatureDefn->AddFieldDefn( poFieldDefn );
-        }
-        else if( poFieldDefn->GetType() == OFTIntegerList )
-        {
-            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
-                                PCIDSK::FieldTypeCountedInt, 
-                                "", "" );
-            poFeatureDefn->AddFieldDefn( poFieldDefn );
-        }
-        else if( bApproxOK )
-        {
-            // Fallback to treating everything else as a string field.
-            OGRFieldDefn oModFieldDefn(poFieldDefn);
-            oModFieldDefn.SetType( OFTString );
-            poVecSeg->AddField( poFieldDefn->GetNameRef(), 
-                                PCIDSK::FieldTypeString, 
-                                "", "" );
-            poFeatureDefn->AddFieldDefn( &oModFieldDefn );
-        }
-        else
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "Attempt to create field '%s' of unsupported data type.",
-                      poFieldDefn->GetNameRef() );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Trap exceptions and report as CPL errors.                       */
-/* -------------------------------------------------------------------- */
-    catch( PCIDSK::PCIDSKException ex )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "%s", ex.what() );
-        return OGRERR_FAILURE;
-    }
-    catch(...)
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Non-PCIDSK exception trapped." );
-        return OGRERR_FAILURE;
-    }
-
-    return OGRERR_NONE;
-}
diff --git a/ogr/ogrsf_frmts/pdf/GNUmakefile b/ogr/ogrsf_frmts/pdf/GNUmakefile
deleted file mode 100644
index 2b8f522..0000000
--- a/ogr/ogrsf_frmts/pdf/GNUmakefile
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-include ../../../GDALmake.opt
-
-OBJ	=	ogrpdfdriver.o ogrpdfdatasource.o
-
-CPPFLAGS	:=	-I.. -I../.. -I../mem -I../../../frmts/mem -I../../../frmts/pdf $(GDAL_INCLUDE) $(CPPFLAGS)
-
-default:	$(O_OBJ:.o=.$(OBJ_EXT))
-
-clean:
-	rm -f *.o $(O_OBJ)
-
-$(O_OBJ):	ogr_pdf.h ../../../frmts/pdf/pdfobject.h ../../../frmts/pdf/pdfcreatecopy.h ../mem/ogr_mem.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/pdf/drv_pdf.html b/ogr/ogrsf_frmts/pdf/drv_pdf.html
deleted file mode 100644
index ab7209e..0000000
--- a/ogr/ogrsf_frmts/pdf/drv_pdf.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<html>
-<head>
-<meta http-equiv="content-type" content="text/html; charset=utf-8" />
-<title>PDF - Geospatial PDF</title>
-</head>
-
-<body bgcolor="#ffffff">
-
-<h1>PDF - Geospatial PDF</h1>
-
-(GDAL/OGR >= 1.10.0)<p>
-
-This driver can rean and write geospatial PDF with vector features.<p>
-
-Read support requires linking to podofo or poppler libraries, but write support does not.<p>
-
-The driver can read vector features encoded according to PDF's logical structure facilities (as described by "§10.6 - Logical Structure" of PDF spec),
-or retrieve only vector geometries for other vector PDF files.<p>
-
-<h2>Feature style support</h2>
-
-For write support, the driver has partial support for the style information attached to features,
-encoded according to the <a href="ogr_feature_style.html">OGR Feature Style Specification</a>.<p>
-
-The following tools are recognized :
-<ul>
-<li>For points, LABEL and SYMBOL.</li>
-<li>For lines, PEN.</li>
-<li>For polygons, PEN and BRUSH.</li>
-</ul>
-
-The supported attributes for each tool are summed up in the following table :<p>
-
-<table border="1">
-
-<tr>
-<th>Tool</th>
-<th>Supported attributes</th>
-<th>Example</th>
-</tr>
-
-<tr><td>PEN</td><td>color, width and dash pattern</td><td>PEN(c:#FF0000,w:5px)</td></tr>
-<tr><td>BRUSH</td><td>foreground color</td><td>BRUSH(fc:#0000FF)</td></tr>
-<tr><td>LABEL</td><td>text (limited to ASCII strings), foreground color, size, x and y offsets, and angle</td><td>LABEL(c:#000000,t:"Hello World!",s:5)</td></tr>
-<tr><td>SYMBOL</td><td>id (ogr-sym-0 to ogr-sym-9, and filenames for raster symbols), color and size</td>
-<td>SYMBOL(c:#00FF00,id:"ogr-sym-3",s:10)<br>SYMBOL(c:#00000080,id:"a_symbol.png")</td></tr>
-</table>
-<p>
-
-Alpha values are supported for colors to control the opacity. If not specified, for BRUSH, it is set at 50% opaque.<p>
-
-For SYMBOL with a bitmap name, only the alpha value of the color specified with 'c' is taken into account.<p>
-
-<h2>Dataset creation options</h2>
-
-<ul>
-
-<li><p><b>STREAM_COMPRESS=[NONE/DEFLATE]</b>:
-Set the compression to use for stream objects. DEFLATE is the default.</p></li>
-
-<li><p><b>DPI=value</b>:
-Set the DPI to use. Default to 72.</p></li>
-
-<li><p><b>EXTRA_STREAM=content</b>: A PDF content stream to draw after the vector content, typically to add some text. It may refer
-the /FTimesRoman and /FTimesBold fonts.</p></li>
-
-<li><p><b>EXTRA_IMAGES=image_file_name,x,y,scale[,link=some_url] (possibly repeated)</b>: A list of (ungeoreferenced) images to insert into
-the page as extra content. This is usefull to insert logos, legends, etc...
-x and y are in user units from the lower left corner of the page, and the anchor point is the lower left pixel of the image.
-scale is a magnifying ratio (use 1 if unsure). If link=some_url is specified, the image will be selectable and its selection
-will cause a web browser to be opened on the specified URL.</p></li>
-
-<li><p><b>EXTRA_LAYER_NAME=name</b>: Name for layer where the extra content specified with EXTRA_CONTENT_STREAM is placed.</p></li>
-
-<li><p><b>MARGIN/LEFT_MARGIN/RIGHT_MARGIN/TOP_MARGIN/BOTTOM_MARGIN=value</b>: Margin around image in user units.</p></li>
-
-<li><p><b>GEO_ENCODING=[NONE/ISO32000/OGC_BP/BOTH]</b>:
-Set the Geo encoding method to use. ISO32000 is the default.</p></li>
-
-<li><p><b>NEATLINE=polygon_definition_in_wkt</b>:
-Set the NEATLINE to use.</p></li>
-
-<li><p><b>AUTHOR</b>, <b>CREATOR</b>, <b>CREATION_DATE</b>, <b>KEYWORDS</b>, <b>PRODUCER</b>,
-    <b>SUBJECT</b>, <b>TITLE</b> : metadata that can be written into the PDF Info block.</p></li>
-
-<li><p><b>OGR_DISPLAY_FIELD=name</b> : Name of the field (matching the name of a field from the OGR layer definition)
-to use to build the label of features that appear in the "Model Tree" UI component of a well-known PDF viewer.
-For example, if the OGR layer has a field called "ID", this can be used as the value for that option : features
-in the "Model Tree" will be labelled from their value for the "ID" field.
-If not specified, sequential generic labels will be used ("feature1", "feature2", etc... ).</li>
-
-<li><p><b>OGR_DISPLAY_LAYER_NAMES=names</b> : Comma separated list of names to display for the OGR layers in the "Model Tree".
-This option is useful to provide custom names, instead of OGR layer name that are used when this option is not specified.
-When specified, the number of names should be the same as the number of OGR layers written (and in the order they are written). </li>
-
-<li><p><b>OGR_WRITE_ATTRIBUTES=YES/NO</b> : Whether to write attributes of OGR features. Defaults to YES</li>
-
-<li><p><b>OGR_LINK_FIELD=name</b> : Name of the field (matching the name of a field from the OGR layer definition)
-to use to cause clicks on OGR features to open a web browser on the URL specified by the field value.</p></li>
-
-<li><p><b>OFF_LAYERS=name (possibly repeated)</b>: Comma separated list of layer names that should be initially hidden.
-By default, all layers are visible. The layer names can come from EXTRA_LAYER_NAME and OGR_DISPLAY_LAYER_NAMES.</p></li>
-
-<li><p><b>EXCLUSIVE_LAYERS=name (possibly repeated)</b>:
-Comma separated list of layer names, such that only one of those layers can be visible at a time.
-This is the behaviour of radio-buttons in a graphical user interface.
- he layer names can come from EXTRA_LAYER_NAME and OGR_DISPLAY_LAYER_NAMES.
-</p></li>
-
-<li><p><b>JAVASCRIPT=script</b>: Javascript content to run at document opening. See
-<a href="http://partners.adobe.com/public/developer/en/acrobat/sdk/AcroJS.pdf">Acrobat(R) JavaScript Scripting Reference</a>.</p></li>
-
-<li><p><b>JAVASCRIPT_FILE=script_filename</b>: Name of Javascript file to embed and run at document opening. See
-<a href="http://partners.adobe.com/public/developer/en/acrobat/sdk/AcroJS.pdf">Acrobat(R) JavaScript Scripting Reference</a>.</p></li>
-
-</ul>
-
-<h2>See also</h2>
-
-Specifications :
-
-<ul>
-<li><a href="ogr_feature_style.html">OGR Feature Style Specification</a></li>
-<li><a href="http://portal.opengeospatial.org/files/?artifact_id=40537">OGC GeoPDF Encoding Best Practice Version 2.2 (08-139r3)</a></li>
-<li><a href="http://www.adobe.com/devnet/acrobat/pdfs/adobe_supplement_iso32000.pdf">Adobe Supplement to ISO 32000</a></li>
-<li><a href="http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf">PDF Reference, version 1.7</a></li>
-</ul>
-
-Also:
-<ul>
-<li><a href="../frmt_pdf.html">GDAL PDF driver</a></li>
-</ul>
-
-</body>
-</html>
diff --git a/ogr/ogrsf_frmts/pdf/makefile.vc b/ogr/ogrsf_frmts/pdf/makefile.vc
deleted file mode 100644
index 3159303..0000000
--- a/ogr/ogrsf_frmts/pdf/makefile.vc
+++ /dev/null
@@ -1,16 +0,0 @@
-
-OBJ	=	ogrpdfdriver.obj ogrpdfdatasource.obj
-
-GDAL_ROOT	=	..\..\..
-
-!INCLUDE $(GDAL_ROOT)\nmake.opt
-
-EXTRAFLAGS =	-I.. -I..\.. -I..\mem -I..\..\..\frmts\mem -I..\..\..\frmts\pdf
-
-default:	$(OBJ)
-
-clean:
-	-del *.obj *.pdb
-
-
-
diff --git a/ogr/ogrsf_frmts/pdf/ogr_pdf.h b/ogr/ogrsf_frmts/pdf/ogr_pdf.h
deleted file mode 100644
index 72126ed..0000000
--- a/ogr/ogrsf_frmts/pdf/ogr_pdf.h
+++ /dev/null
@@ -1,170 +0,0 @@
-/******************************************************************************
- * $Id: ogr_pdf.h 27044 2014-03-16 23:41:27Z rouault $
- *
- * Project:  PDF Translator
- * Purpose:  Definition of classes for OGR .pdf driver.
- * Author:   Even Rouault, even dot rouault at mines dash paris dot org
- *
- ******************************************************************************
- * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * 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.
- ****************************************************************************/
-
-#ifndef _OGR_PDF_H_INCLUDED
-#define _OGR_PDF_H_INCLUDED
-
-#include "ogrsf_frmts.h"
-
-#include "ogr_mem.h"
-#include "gdal_priv.h"
-#include "pdfobject.h"
-
-#include <map>
-#include <stack>
-
-/************************************************************************/
-/*                             OGRPDFLayer                              */
-/************************************************************************/
-
-class OGRPDFDataSource;
-
-class OGRPDFLayer : public OGRMemLayer
-{
-    OGRPDFDataSource* poDS;
-    int               bGeomTypeSet;
-    int               bGeomTypeMixed;
-
-public:
-        OGRPDFLayer(OGRPDFDataSource* poDS,
-                    const char * pszName,
-                    OGRSpatialReference *poSRS,
-                    OGRwkbGeometryType eGeomType);
-
-    void                Fill( GDALPDFArray* poArray );
-
-    virtual int                 TestCapability( const char * );
-    virtual OGRErr              CreateFeature( OGRFeature *poFeature );
-};
-
-/************************************************************************/
-/*                           OGRPDFDataSource                           */
-/************************************************************************/
-
-#define MAX_TOKEN_SIZE 256
-#define TOKEN_STACK_SIZE 8
-
-class OGRPDFDataSource : public OGRDataSource
-{
-    char*               pszName;
-    char**              papszOptions;
-
-    int                 nLayers;
-    OGRLayer          **papoLayers;
-
-    int                 bWritable;
-    int                 bModified;
-
-    GDALDataset        *poGDAL_DS;
-    GDALPDFObject      *poPageObj;
-    GDALPDFObject      *poCatalogObj;
-    int                 nXSize;
-    int                 nYSize;
-    double              adfGeoTransform[6];
-    double              dfPageWidth;
-    double              dfPageHeight;
-    void                PDFCoordsToSRSCoords(double x, double y,
-                                             double& X, double &Y);
-
-    std::map<int,OGRGeometry*> oMapMCID;
-    void                CleanupIntermediateResources();
-
-    std::map<CPLString, int> oMapOperators;
-    void                InitMapOperators();
-    
-    int                 bSetStyle;
-
-    void                ExploreTree(GDALPDFObject* poObj, int nRecLevel);
-    void                ExploreContents(GDALPDFObject* poObj, GDALPDFObject* poResources);
-
-    void                ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
-                                                             GDALPDFObject* poResources,
-                                                             std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer);
-    void                ExploreContentsNonStructured(GDALPDFObject* poObj, GDALPDFObject* poResources);
-
-    int                 UnstackTokens(const char* pszToken,
-                                      int nRequiredArgs,
-                                      char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
-                                      int& nTokenStackSize,
-                                      double* adfCoords);
-    OGRGeometry*        ParseContent(const char* pszContent,
-                                     GDALPDFObject* poResources,
-                                     int bInitBDCStack,
-                                     int bMatchQ,
-                                     std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
-                                     OGRPDFLayer* poCurLayer);
-    OGRGeometry*        BuildGeometry(std::vector<double>& oCoords,
-                                      int bHasFoundFill,
-                                      int bHasMultiPart);
-
-  public:
-                        OGRPDFDataSource();
-                        ~OGRPDFDataSource();
-
-    int                 Open( const char * pszName );
-    int                 Create( const char * pszName, char **papszOptions );
-
-    virtual const char*         GetName() { return pszName; }
-
-    virtual int                 GetLayerCount();
-    virtual OGRLayer*           GetLayer( int );
-
-    virtual int                 TestCapability( const char * );
-
-    virtual OGRLayer* CreateLayer( const char * pszLayerName,
-                                OGRSpatialReference *poSRS,
-                                OGRwkbGeometryType eType,
-                                char ** papszOptions );
-
-    virtual OGRErr      SyncToDisk();
-
-    void                SetModified() { bModified = TRUE; }
-    OGRGeometry        *GetGeometryFromMCID(int nMCID);
-};
-
-/************************************************************************/
-/*                             OGRPDFDriver                              */
-/************************************************************************/
-
-class OGRPDFDriver : public OGRSFDriver
-{
-  public:
-                ~OGRPDFDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    virtual OGRErr DeleteDataSource( const char *pszName );
-};
-
-
-#endif /* ndef _OGR_PDF_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/pdf/ogrpdfdatasource.cpp b/ogr/ogrsf_frmts/pdf/ogrpdfdatasource.cpp
deleted file mode 100644
index 79c0349..0000000
--- a/ogr/ogrsf_frmts/pdf/ogrpdfdatasource.cpp
+++ /dev/null
@@ -1,2159 +0,0 @@
-/******************************************************************************
- * $Id: ogrpdfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
- *
- * Project:  PDF Translator
- * Purpose:  Implements OGRPDFDataSource class
- * Author:   Even Rouault, even dot rouault at mines dash paris dot org
- *
- ******************************************************************************
- * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * 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.
- ****************************************************************************/
-
-#include "ogr_pdf.h"
-#include "ogr_p.h"
-#include "cpl_conv.h"
-
-#include "pdfdataset.h"
-#include "pdfcreatecopy.h"
-
-#include "memdataset.h"
-
-#define SQUARE(x) ((x)*(x))
-#define EPSILON 1e-5
-
-CPL_CVSID("$Id: ogrpdfdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
-
-/************************************************************************/
-/*                            OGRPDFLayer()                             */
-/************************************************************************/
-
-OGRPDFLayer::OGRPDFLayer( OGRPDFDataSource* poDS,
-                          const char * pszName,
-                          OGRSpatialReference *poSRS,
-                          OGRwkbGeometryType eGeomType ) :
-                                OGRMemLayer(pszName, poSRS, eGeomType )
-{
-    this->poDS = poDS;
-    bGeomTypeSet = FALSE;
-    bGeomTypeMixed = FALSE;
-}
-
-/************************************************************************/
-/*                            CreateFeature()                           */
-/************************************************************************/
-
-OGRErr OGRPDFLayer::CreateFeature( OGRFeature *poFeature )
-{
-    OGRGeometry* poGeom = poFeature->GetGeometryRef();
-    if( !bGeomTypeMixed && poGeom != NULL )
-    {
-        if (!bGeomTypeSet)
-        {
-            bGeomTypeSet = TRUE;
-            GetLayerDefn()->SetGeomType(poGeom->getGeometryType());
-        }
-        else if (GetLayerDefn()->GetGeomType() != poGeom->getGeometryType())
-        {
-            bGeomTypeMixed = TRUE;
-            GetLayerDefn()->SetGeomType(wkbUnknown);
-        }
-    }
-
-    poDS->SetModified();
-    return OGRMemLayer::CreateFeature(poFeature);
-}
-
-/************************************************************************/
-/*                              Fill()                                  */
-/************************************************************************/
-
-void OGRPDFLayer::Fill( GDALPDFArray* poArray )
-{
-    for(int i=0;i<poArray->GetLength();i++)
-    {
-        GDALPDFObject* poFeatureObj = poArray->Get(i);
-        if (poFeatureObj->GetType() != PDFObjectType_Dictionary)
-            continue;
-
-        GDALPDFObject* poA = poFeatureObj->GetDictionary()->Get("A");
-        if (!(poA != NULL && poA->GetType() == PDFObjectType_Dictionary))
-            continue;
-
-        GDALPDFObject* poP = poA->GetDictionary()->Get("P");
-        if (!(poP != NULL && poP->GetType() == PDFObjectType_Array))
-            continue;
-
-        GDALPDFObject* poK = poFeatureObj->GetDictionary()->Get("K");
-        int nK = -1;
-        if (poK != NULL && poK->GetType() == PDFObjectType_Int)
-            nK = poK->GetInt();
-
-        GDALPDFArray* poPArray = poP->GetArray();
-        int j;
-        for(j = 0;j<poPArray->GetLength();j++)
-        {
-            GDALPDFObject* poKV = poPArray->Get(j);
-            if (poKV->GetType() == PDFObjectType_Dictionary)
-            {
-                GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
-                GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
-                if (poN != NULL && poN->GetType() == PDFObjectType_String &&
-                    poV != NULL)
-                {
-                    int nIdx = GetLayerDefn()->GetFieldIndex( poN->GetString().c_str() );
-                    OGRFieldType eType = OFTString;
-                    if (poV->GetType() == PDFObjectType_Int)
-                        eType = OFTInteger;
-                    else if (poV->GetType() == PDFObjectType_Real)
-                        eType = OFTReal;
-                    if (nIdx < 0)
-                    {
-                        OGRFieldDefn oField(poN->GetString().c_str(), eType);
-                        CreateField(&oField);
-                    }
-                    else if (GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != eType &&
-                                GetLayerDefn()->GetFieldDefn(nIdx)->GetType() != OFTString)
-                    {
-                        OGRFieldDefn oField(poN->GetString().c_str(), OFTString);
-                        AlterFieldDefn( nIdx, &oField, ALTER_TYPE_FLAG );
-                    }
-                }
-            }
-        }
-
-        OGRFeature* poFeature = new OGRFeature(GetLayerDefn());
-        for(j = 0;j<poPArray->GetLength();j++)
-        {
-            GDALPDFObject* poKV = poPArray->Get(j);
-            if (poKV->GetType() == PDFObjectType_Dictionary)
-            {
-                GDALPDFObject* poN = poKV->GetDictionary()->Get("N");
-                GDALPDFObject* poV = poKV->GetDictionary()->Get("V");
-                if (poN != NULL && poN->GetType() == PDFObjectType_String &&
-                    poV != NULL)
-                {
-                    if (poV->GetType() == PDFObjectType_String)
-                        poFeature->SetField(poN->GetString().c_str(), poV->GetString().c_str());
-                    else if (poV->GetType() == PDFObjectType_Int)
-                        poFeature->SetField(poN->GetString().c_str(), poV->GetInt());
-                    else if (poV->GetType() == PDFObjectType_Real)
-                        poFeature->SetField(poN->GetString().c_str(), poV->GetReal());
-                }
-            }
-        }
-
-        if (nK >= 0)
-        {
-            OGRGeometry* poGeom = poDS->GetGeometryFromMCID(nK);
-            if (poGeom)
-            {
-                poGeom->assignSpatialReference(GetSpatialRef());
-                poFeature->SetGeometry(poGeom);
-            }
-        }
-
-        CreateFeature(poFeature);
-
-        delete poFeature;
-    }
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPDFLayer::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,OLCStringsAsUTF8) )
-        return TRUE;
-    else
-        return OGRMemLayer::TestCapability(pszCap);
-}
-
-/************************************************************************/
-/*                          OGRPDFDataSource()                          */
-/************************************************************************/
-
-OGRPDFDataSource::OGRPDFDataSource()
-
-{
-    pszName = NULL;
-    papszOptions = NULL;
-
-    nLayers = 0;
-    papoLayers = NULL;
-
-    bModified = FALSE;
-    bWritable = FALSE;
-
-    poGDAL_DS = NULL;
-    poPageObj = NULL;
-    poCatalogObj = NULL;
-    dfPageWidth = dfPageHeight = 0;
-
-    bSetStyle = CSLTestBoolean(CPLGetConfigOption("OGR_PDF_SET_STYLE", "YES"));
-
-    InitMapOperators();
-}
-
-/************************************************************************/
-/*                         ~OGRPDFDataSource()                          */
-/************************************************************************/
-
-OGRPDFDataSource::~OGRPDFDataSource()
-
-{
-    SyncToDisk();
-
-    CleanupIntermediateResources();
-
-    CPLFree( pszName );
-    CSLDestroy( papszOptions );
-
-    for(int i=0;i<nLayers;i++)
-        delete papoLayers[i];
-    CPLFree( papoLayers );
-}
-
-/************************************************************************/
-/*                   CleanupIntermediateResources()                     */
-/************************************************************************/
-
-void OGRPDFDataSource::CleanupIntermediateResources()
-{
-    std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.begin();
-    for( ; oMapIter != oMapMCID.end(); ++oMapIter)
-        delete oMapIter->second;
-    oMapMCID.erase(oMapMCID.begin(), oMapMCID.end());
-
-    delete poGDAL_DS;
-    poGDAL_DS = NULL;
-
-    poPageObj = NULL;
-    poCatalogObj = NULL;
-}
-
-/************************************************************************/
-/*                          InitMapOperators()                          */
-/************************************************************************/
-
-typedef struct
-{
-    char        szOpName[4];
-    int         nArgs;
-} PDFOperator;
-
-static const PDFOperator asPDFOperators [] =
-{
-    { "b", 0 },
-    { "B", 0 },
-    { "b*", 0 },
-    { "B*", 0 },
-    { "BDC", 2 },
-    // BI
-    { "BMC", 1 },
-    // BT
-    { "BX", 0 },
-    { "c", 6 },
-    { "cm", 6 },
-    { "CS", 1 },
-    { "cs", 1 },
-    { "d", 1 }, /* we have ignored the first arg */
-    // d0
-    // d1
-    { "Do", 1 },
-    { "DP", 2 },
-    // EI
-    { "EMC", 0 },
-    // ET
-    { "EX", 0 },
-    { "f", 0 },
-    { "F", 0 },
-    { "f*", 0 },
-    { "G", 1 },
-    { "g", 1 },
-    { "gs", 1 },
-    { "h", 0 },
-    { "i", 1 },
-    // ID
-    { "j", 1 },
-    { "J", 1 },
-    { "K", 4 },
-    { "k", 4 },
-    { "l", 2 },
-    { "m", 2 },
-    { "M", 1 },
-    { "MP", 1 },
-    { "n", 0 },
-    { "q", 0 },
-    { "Q", 0 },
-    { "re", 4 },
-    { "RG", 3 },
-    { "rg", 3 },
-    { "ri", 1 },
-    { "s", 0 },
-    { "S", 0 },
-    { "SC", -1 },
-    { "sc", -1 },
-    { "SCN", -1 },
-    { "scn", -1 },
-    { "sh", 1 },
-    // T*
-    { "Tc", 1},
-    { "Td", 2},
-    { "TD", 2},
-    { "Tf", 1},
-    { "Tj", 1},
-    { "TJ", 1},
-    { "TL", 1},
-    { "Tm", 6},
-    { "Tr", 1},
-    { "Ts", 1},
-    { "Tw", 1},
-    { "Tz", 1},
-    { "v", 4 },
-    { "w", 1 },
-    { "W", 0 },
-    { "W*", 0 },
-    { "y", 4 },
-    // '
-    // "
-};
-
-void OGRPDFDataSource::InitMapOperators()
-{
-    for(size_t i=0;i<sizeof(asPDFOperators) / sizeof(asPDFOperators[0]); i++)
-        oMapOperators[asPDFOperators[i].szOpName] = asPDFOperators[i].nArgs;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPDFDataSource::TestCapability( const char * pszCap )
-
-{
-    if( bWritable && EQUAL(pszCap,ODsCCreateLayer) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                              GetLayer()                              */
-/************************************************************************/
-
-OGRLayer *OGRPDFDataSource::GetLayer( int iLayer )
-
-{
-    if (iLayer < 0 || iLayer >= nLayers)
-        return NULL;
-
-    return papoLayers[iLayer];
-}
-
-/************************************************************************/
-/*                            GetLayerCount()                           */
-/************************************************************************/
-
-int OGRPDFDataSource::GetLayerCount()
-{
-    return nLayers;
-}
-
-/************************************************************************/
-/*                            ExploreTree()                             */
-/************************************************************************/
-
-void OGRPDFDataSource::ExploreTree(GDALPDFObject* poObj, int nRecLevel)
-{
-    if (nRecLevel == 16)
-        return;
-
-    if (poObj->GetType() != PDFObjectType_Dictionary)
-        return;
-
-    GDALPDFDictionary* poDict = poObj->GetDictionary();
-
-    GDALPDFObject* poS = poDict->Get("S");
-    CPLString osS;
-    if (poS != NULL && poS->GetType() == PDFObjectType_Name)
-    {
-        osS = poS->GetName();
-    }
-
-    GDALPDFObject* poT = poDict->Get("T");
-    CPLString osT;
-    if (poT != NULL && poT->GetType() == PDFObjectType_String)
-    {
-        osT = poT->GetString();
-    }
-
-    GDALPDFObject* poK = poDict->Get("K");
-    if (poK == NULL)
-        return;
-
-    if (poK->GetType() == PDFObjectType_Array)
-    {
-        GDALPDFArray* poArray = poK->GetArray();
-        if (poArray->GetLength() > 0 &&
-            poArray->Get(0)->GetType() == PDFObjectType_Dictionary &&
-            poArray->Get(0)->GetDictionary()->Get("K") != NULL &&
-            poArray->Get(0)->GetDictionary()->Get("K")->GetType() == PDFObjectType_Int)
-        {
-            CPLString osLayerName;
-            if (osT.size())
-                osLayerName = osT;
-            else
-            {
-                if (osS.size())
-                    osLayerName = osS;
-                else
-                    osLayerName = CPLSPrintf("Layer%d", nLayers + 1);
-            }
-
-            const char* pszWKT = poGDAL_DS->GetProjectionRef();
-            OGRSpatialReference* poSRS = NULL;
-            if (pszWKT && pszWKT[0] != '\0')
-            {
-                poSRS = new OGRSpatialReference();
-                poSRS->importFromWkt((char**) &pszWKT);
-            }
-
-            OGRPDFLayer* poLayer =
-                new OGRPDFLayer(this, osLayerName.c_str(), poSRS, wkbUnknown);
-            delete poSRS;
-
-            poLayer->Fill(poArray);
-
-            papoLayers = (OGRLayer**)
-                CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
-            papoLayers[nLayers] = poLayer;
-            nLayers ++;
-        }
-        else
-        {
-            for(int i=0;i<poArray->GetLength();i++)
-                ExploreTree(poArray->Get(i), nRecLevel + 1);
-        }
-    }
-    else if (poK->GetType() == PDFObjectType_Dictionary)
-    {
-        ExploreTree(poK, nRecLevel + 1);
-    }
-}
-
-/************************************************************************/
-/*                        GetGeometryFromMCID()                         */
-/************************************************************************/
-
-OGRGeometry* OGRPDFDataSource::GetGeometryFromMCID(int nMCID)
-{
-    std::map<int,OGRGeometry*>::iterator oMapIter = oMapMCID.find(nMCID);
-    if (oMapIter != oMapMCID.end())
-        return oMapIter->second;
-    else
-        return NULL;
-}
-
-/************************************************************************/
-/*                            GraphicState                              */
-/************************************************************************/
-
-class GraphicState
-{
-    public:
-        double adfCM[6];
-        double adfStrokeColor[3];
-        double adfFillColor[3];
-
-        GraphicState()
-        {
-            adfCM[0] = 1;
-            adfCM[1] = 0;
-            adfCM[2] = 0;
-            adfCM[3] = 1;
-            adfCM[4] = 0;
-            adfCM[5] = 0;
-            adfStrokeColor[0] = 0.0;
-            adfStrokeColor[1] = 0.0;
-            adfStrokeColor[2] = 0.0;
-            adfFillColor[0] = 1.0;
-            adfFillColor[1] = 1.0;
-            adfFillColor[2] = 1.0;
-        }
-
-        void MultiplyBy(double adfMatrix[6])
-        {
-            /*
-            [ a b 0 ]     [ a' b' 0]     [ aa' + bc'       ab' + bd'       0 ]
-            [ c d 0 ]  *  [ c' d' 0]  =  [ ca' + dc'       cb' + dd'       0 ]
-            [ e f 1 ]     [ e' f' 1]     [ ea' + fc' + e'  eb' + fd' + f'  1 ]
-            */
-
-            double a = adfCM[0];
-            double b = adfCM[1];
-            double c = adfCM[2];
-            double d = adfCM[3];
-            double e = adfCM[4];
-            double f = adfCM[5];
-            double ap = adfMatrix[0];
-            double bp = adfMatrix[1];
-            double cp = adfMatrix[2];
-            double dp = adfMatrix[3];
-            double ep = adfMatrix[4];
-            double fp = adfMatrix[5];
-            adfCM[0] = a*ap + b*cp;
-            adfCM[1] = a*bp + b*dp;
-            adfCM[2] = c*ap + d*cp;
-            adfCM[3] = c*bp + d*dp;
-            adfCM[4] = e*ap + f*cp + ep;
-            adfCM[5] = e*bp + f*dp + fp;
-        }
-
-        void ApplyMatrix(double adfCoords[2])
-        {
-            double x = adfCoords[0];
-            double y = adfCoords[1];
-
-            adfCoords[0] = x * adfCM[0] + y * adfCM[2] + adfCM[4];
-            adfCoords[1] = x * adfCM[1] + y * adfCM[3] + adfCM[5];
-        }
-};
-
-/************************************************************************/
-/*                         PDFCoordsToSRSCoords()                       */
-/************************************************************************/
-
-void OGRPDFDataSource::PDFCoordsToSRSCoords(double x, double y,
-                                            double& X, double &Y)
-{
-    x = x / dfPageWidth * nXSize;
-    y = (1 - y / dfPageHeight) * nYSize;
-
-    X = adfGeoTransform[0] + x * adfGeoTransform[1] + y * adfGeoTransform[2];
-    Y = adfGeoTransform[3] + x * adfGeoTransform[4] + y * adfGeoTransform[5];
-
-    if( fabs(X - (int)floor(X + 0.5)) < 1e-8 )
-        X = (int)floor(X + 0.5);
-    if( fabs(Y - (int)floor(Y + 0.5)) < 1e-8 )
-        Y = (int)floor(Y + 0.5);
-}
-
-/************************************************************************/
-/*                         PDFGetCircleCenter()                         */
-/************************************************************************/
-
-/* Return the center of a circle, or NULL if it is not recognized */
-
-static OGRPoint* PDFGetCircleCenter(OGRLineString* poLS)
-{
-    if (poLS == NULL || poLS->getNumPoints() != 5)
-        return NULL;
-
-    if (poLS->getY(0) == poLS->getY(2) &&
-        poLS->getX(1) == poLS->getX(3) &&
-        fabs((poLS->getX(0) + poLS->getX(2)) / 2 - poLS->getX(1)) < EPSILON &&
-        fabs((poLS->getY(1) + poLS->getY(3)) / 2 - poLS->getY(0)) < EPSILON)
-    {
-        return new OGRPoint((poLS->getX(0) + poLS->getX(2)) / 2,
-                            (poLS->getY(1) + poLS->getY(3)) / 2);
-    }
-    return NULL;
-}
-
-/************************************************************************/
-/*                         PDFGetSquareCenter()                         */
-/************************************************************************/
-
-/* Return the center of a square, or NULL if it is not recognized */
-
-static OGRPoint* PDFGetSquareCenter(OGRLineString* poLS)
-{
-    if (poLS == NULL || poLS->getNumPoints() < 4 || poLS->getNumPoints() > 5)
-        return NULL;
-
-    if (poLS->getX(0) == poLS->getX(3) &&
-        poLS->getY(0) == poLS->getY(1) &&
-        poLS->getX(1) == poLS->getX(2) &&
-        poLS->getY(2) == poLS->getY(3) &&
-        fabs(fabs(poLS->getX(0) - poLS->getX(1)) - fabs(poLS->getY(0) - poLS->getY(3))) < EPSILON)
-    {
-        return new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
-                            (poLS->getY(0) + poLS->getY(3)) / 2);
-    }
-    return NULL;
-}
-
-/************************************************************************/
-/*                        PDFGetTriangleCenter()                        */
-/************************************************************************/
-
-/* Return the center of a equilateral triangle, or NULL if it is not recognized */
-
-static OGRPoint* PDFGetTriangleCenter(OGRLineString* poLS)
-{
-    if (poLS == NULL || poLS->getNumPoints() < 3 || poLS->getNumPoints() > 4)
-        return NULL;
-
-    double dfSqD1 = SQUARE(poLS->getX(0) - poLS->getX(1)) + SQUARE(poLS->getY(0) - poLS->getY(1));
-    double dfSqD2 = SQUARE(poLS->getX(1) - poLS->getX(2)) + SQUARE(poLS->getY(1) - poLS->getY(2));
-    double dfSqD3 = SQUARE(poLS->getX(0) - poLS->getX(2)) + SQUARE(poLS->getY(0) - poLS->getY(2));
-    if (fabs(dfSqD1 - dfSqD2) < EPSILON && fabs(dfSqD2 - dfSqD3) < EPSILON)
-    {
-        return new OGRPoint((poLS->getX(0) + poLS->getX(1) + poLS->getX(2)) / 3,
-                            (poLS->getY(0) + poLS->getY(1) + poLS->getY(2)) / 3);
-    }
-    return NULL;
-}
-
-/************************************************************************/
-/*                          PDFGetStarCenter()                          */
-/************************************************************************/
-
-/* Return the center of a 5-point star, or NULL if it is not recognized */
-
-static OGRPoint* PDFGetStarCenter(OGRLineString* poLS)
-{
-    if (poLS == NULL || poLS->getNumPoints() < 10 || poLS->getNumPoints() > 11)
-        return NULL;
-
-    double dfSqD01 = SQUARE(poLS->getX(0) - poLS->getX(1)) +
-                     SQUARE(poLS->getY(0) - poLS->getY(1));
-    double dfSqD02 = SQUARE(poLS->getX(0) - poLS->getX(2)) +
-                       SQUARE(poLS->getY(0) - poLS->getY(2));
-    double dfSqD13 = SQUARE(poLS->getX(1) - poLS->getX(3)) +
-                      SQUARE(poLS->getY(1) - poLS->getY(3));
-    const double dfSin18divSin126 = 0.38196601125;
-    int bOK = fabs(dfSqD13 / dfSqD02 - SQUARE(dfSin18divSin126)) < EPSILON;
-    for(int i=1;i<10 && bOK;i++)
-    {
-        double dfSqDiip1 = SQUARE(poLS->getX(i) - poLS->getX((i+1)%10)) +
-                           SQUARE(poLS->getY(i) - poLS->getY((i+1)%10));
-        if (fabs(dfSqDiip1 - dfSqD01) > EPSILON)
-        {
-            bOK = FALSE;
-        }
-        double dfSqDiip2 = SQUARE(poLS->getX(i) - poLS->getX((i+2)%10)) +
-                           SQUARE(poLS->getY(i) - poLS->getY((i+2)%10));
-        if ( (i%2) == 1 && fabs(dfSqDiip2 - dfSqD13) > EPSILON )
-        {
-            bOK = FALSE;
-        }
-        if ( (i%2) == 0 && fabs(dfSqDiip2 - dfSqD02) > EPSILON )
-        {
-            bOK = FALSE;
-        }
-    }
-    if (bOK)
-    {
-        return new OGRPoint((poLS->getX(0) + poLS->getX(2) + poLS->getX(4) +
-                             poLS->getX(6) + poLS->getX(8)) / 5,
-                            (poLS->getY(0) + poLS->getY(2) + poLS->getY(4) +
-                             poLS->getY(6) + poLS->getY(8)) / 5);
-    }
-    return NULL;
-}
-
-/************************************************************************/
-/*                            UnstackTokens()                           */
-/************************************************************************/
-
-int OGRPDFDataSource::UnstackTokens(const char* pszToken,
-                                    int nRequiredArgs,
-                                    char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE],
-                                    int& nTokenStackSize,
-                                    double* adfCoords)
-{
-    if (nTokenStackSize < nRequiredArgs)
-    {
-        CPLDebug("PDF", "not enough arguments for %s", pszToken);
-        return FALSE;
-    }
-    nTokenStackSize -= nRequiredArgs;
-    for(int i=0;i<nRequiredArgs;i++)
-    {
-        adfCoords[i] = atof(aszTokenStack[nTokenStackSize+i]);
-    }
-    return TRUE;
-}
-
-/************************************************************************/
-/*                           ParseContent()                             */
-/************************************************************************/
-
-#define NEW_SUBPATH -99
-#define CLOSE_SUBPATH -98
-#define FILL_SUBPATH -97
-
-OGRGeometry* OGRPDFDataSource::ParseContent(const char* pszContent,
-                                            GDALPDFObject* poResources,
-                                            int bInitBDCStack,
-                                            int bMatchQ,
-                                            std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer,
-                                            OGRPDFLayer* poCurLayer)
-{
-
-#define PUSH(aszTokenStack, str, strlen) \
-    do \
-    { \
-        if(nTokenStackSize < TOKEN_STACK_SIZE) \
-            memcpy(aszTokenStack[nTokenStackSize ++], str, strlen + 1); \
-        else \
-        { \
-            CPLError(CE_Failure, CPLE_AppDefined, "Max token stack size reached");\
-            return NULL; \
-        }; \
-    } while(0)
-
-#define ADD_CHAR(szToken, c) \
-    do \
-    { \
-        if(nTokenSize < MAX_TOKEN_SIZE-1) \
-        { \
-            szToken[nTokenSize ++ ] = c; \
-            szToken[nTokenSize ] = '\0'; \
-        } \
-        else \
-        { \
-            CPLError(CE_Failure, CPLE_AppDefined, "Max token size reached");\
-            return NULL; \
-        }; \
-    } while(0)
-
-    char szToken[MAX_TOKEN_SIZE];
-    int nTokenSize = 0;
-    char ch;
-    char aszTokenStack[TOKEN_STACK_SIZE][MAX_TOKEN_SIZE];
-    int nTokenStackSize = 0;
-    int bInString = FALSE;
-    int nBDCLevel = 0;
-    int nParenthesisLevel = 0;
-    int nArrayLevel = 0;
-    int nBTLevel = 0;
-    
-    int bCollectAllObjects = poResources != NULL && !bInitBDCStack && !bMatchQ;
-
-    GraphicState oGS;
-    std::stack<GraphicState> oGSStack;
-    std::stack<OGRPDFLayer*> oLayerStack;
-
-    std::vector<double> oCoords;
-    int bHasFoundFill = FALSE;
-    int bHasMultiPart = FALSE;
-    
-    szToken[0] = '\0';
-
-    if (bInitBDCStack)
-    {
-        PUSH(aszTokenStack, "dummy", 5);
-        PUSH(aszTokenStack, "dummy", 5);
-        oLayerStack.push(NULL);
-    }
-
-    while((ch = *pszContent) != '\0')
-    {
-        int bPushToken = FALSE;
-
-        if (!bInString && ch == '%')
-        {
-            /* Skip comments until end-of-line */
-            while((ch = *pszContent) != '\0')
-            {
-                if (ch == '\r' || ch == '\n')
-                    break;
-                pszContent ++;
-            }
-            if (ch == 0)
-                break;
-        }
-        else if (!bInString && (ch == ' ' || ch == '\r' || ch == '\n'))
-        {
-            bPushToken = TRUE;
-        }
-
-        /* Ignore arrays */
-        else if (!bInString && nTokenSize == 0 && ch == '[')
-        {
-            nArrayLevel ++;
-        }
-        else if (!bInString && nArrayLevel && nTokenSize == 0 && ch == ']')
-        {
-            nArrayLevel --;
-        }
-
-        else if (!bInString && nTokenSize == 0 && ch == '(')
-        {
-            bInString = TRUE;
-            nParenthesisLevel ++;
-            ADD_CHAR(szToken, ch);
-        }
-        else if (bInString && ch == '(')
-        {
-            nParenthesisLevel ++;
-            ADD_CHAR(szToken, ch);
-        }
-        else if (bInString && ch == ')')
-        {
-            nParenthesisLevel --;
-            ADD_CHAR(szToken, ch);
-            if (nParenthesisLevel == 0)
-            {
-                bInString = FALSE;
-                bPushToken = TRUE;
-            }
-        }
-        else if (ch == '<' && pszContent[1] == '<' && nTokenSize == 0)
-        {
-            int nDictDepth = 0;
-
-            while(*pszContent != '\0')
-            {
-                if (pszContent[0] == '<' && pszContent[1] == '<')
-                {
-                    ADD_CHAR(szToken, '<');
-                    ADD_CHAR(szToken, '<');
-                    nDictDepth ++;
-                    pszContent += 2;
-                }
-                else if (pszContent[0] == '>' && pszContent[1] == '>')
-                {
-                    ADD_CHAR(szToken, '>');
-                    ADD_CHAR(szToken, '>');
-                    nDictDepth --;
-                    pszContent += 2;
-                    if (nDictDepth == 0)
-                        break;
-                }
-                else
-                {
-                    ADD_CHAR(szToken, *pszContent);
-                    pszContent ++;
-                }
-            }
-            if (nDictDepth == 0)
-            {
-                bPushToken = TRUE;
-                pszContent --;
-            }
-            else
-                break;
-        }
-        else
-        {
-            ADD_CHAR(szToken, ch);
-        }
-
-        pszContent ++;
-        if (pszContent[0] == '\0')
-            bPushToken = TRUE;
-
-#define EQUAL1(szToken, s) (szToken[0] == s[0] && szToken[1] == '\0')
-#define EQUAL2(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == '\0')
-#define EQUAL3(szToken, s) (szToken[0] == s[0] && szToken[1] == s[1] && szToken[2] == s[2] && szToken[3] == '\0')
-
-        if (bPushToken && nTokenSize)
-        {
-            if (EQUAL2(szToken, "BI"))
-            {
-                while(*pszContent != '\0')
-                {
-                    if( pszContent[0] == 'E' && pszContent[1] == 'I' && pszContent[2] == ' ' )
-                    {
-                        break;
-                    }
-                    pszContent ++;
-                }
-                if( pszContent[0] == 'E' )
-                    pszContent += 3;
-                else
-                    return NULL;
-            }
-            else if (EQUAL3(szToken, "BDC"))
-            {
-                if (nTokenStackSize < 2)
-                {
-                    CPLDebug("PDF",
-                                "not enough arguments for %s",
-                                szToken);
-                    return NULL;
-                }
-                nTokenStackSize -= 2;
-                const char* pszOC = aszTokenStack[nTokenStackSize];
-                const char* pszOCGName = aszTokenStack[nTokenStackSize+1];
-
-                nBDCLevel ++;
-
-                if( EQUAL3(pszOC, "/OC") && pszOCGName[0] == '/' )
-                {
-                    std::map<CPLString, OGRPDFLayer*>::iterator oIter =
-                        oMapPropertyToLayer.find(pszOCGName + 1);
-                    if( oIter != oMapPropertyToLayer.end() )
-                    {
-                        poCurLayer = oIter->second;
-                        //CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
-                    }
-                }
-
-                oLayerStack.push(poCurLayer);
-                //CPLDebug("PDF", "%s %s BDC", osOC.c_str(), osOCGName.c_str());
-            }
-            else if (EQUAL3(szToken, "EMC"))
-            {
-                //CPLDebug("PDF", "EMC");
-                if( !oLayerStack.empty() )
-                {
-                    oLayerStack.pop();
-                    if( !oLayerStack.empty() )
-                        poCurLayer = oLayerStack.top();
-                    else
-                        poCurLayer = NULL;
-
-                    /*if (poCurLayer)
-                    {
-                        CPLDebug("PDF", "Cur layer : %s", poCurLayer->GetName());
-                    }*/
-                }
-                else
-                {
-                    CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                    poCurLayer = NULL;
-                    //return NULL;
-                }
-
-                nBDCLevel --;
-                if (nBDCLevel == 0 && bInitBDCStack)
-                    break;
-            }
-
-            /* Ignore any text stuff */
-            else if (EQUAL2(szToken, "BT"))
-                nBTLevel ++;
-            else if (EQUAL2(szToken, "ET"))
-            {
-                nBTLevel --;
-                if (nBTLevel < 0)
-                {
-                    CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                    return NULL;
-                }
-            }
-            else if (!nArrayLevel && !nBTLevel)
-            {
-                int bEmitFeature = FALSE;
-
-                if( szToken[0] < 'A' )
-                {
-                    PUSH(aszTokenStack, szToken, nTokenSize);
-                }
-                else if (EQUAL1(szToken, "q"))
-                {
-                    oGSStack.push(oGS);
-                }
-                else if (EQUAL1(szToken, "Q"))
-                {
-                    if (oGSStack.empty())
-                    {
-                        CPLDebug("PDF", "not enough arguments for %s", szToken);
-                        return NULL;
-                    }
-
-                    oGS = oGSStack.top();
-                    oGSStack.pop();
-
-                    if (oGSStack.empty() && bMatchQ)
-                        break;
-                }
-                else if (EQUAL2(szToken, "cm"))
-                {
-                    double adfMatrix[6];
-                    if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfMatrix))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    oGS.MultiplyBy(adfMatrix);
-                }
-                else if (EQUAL1(szToken, "b") || /* closepath, fill, stroke */
-                         EQUAL2(szToken, "b*")   /* closepath, eofill, stroke */)
-                {
-                    if (!(oCoords.size() > 0 &&
-                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
-                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
-                    {
-                        oCoords.push_back(CLOSE_SUBPATH);
-                        oCoords.push_back(CLOSE_SUBPATH);
-                    }
-                    oCoords.push_back(FILL_SUBPATH);
-                    oCoords.push_back(FILL_SUBPATH);
-                    bHasFoundFill = TRUE;
-
-                    bEmitFeature = TRUE;
-                }
-                else if (EQUAL1(szToken, "B") ||  /* fill, stroke */
-                         EQUAL2(szToken, "B*") || /* eofill, stroke */
-                         EQUAL1(szToken, "f") ||  /* fill */
-                         EQUAL1(szToken, "F") ||  /* fill */
-                         EQUAL2(szToken, "f*")    /* eofill */ )
-                {
-                    oCoords.push_back(FILL_SUBPATH);
-                    oCoords.push_back(FILL_SUBPATH);
-                    bHasFoundFill = TRUE;
-
-                    bEmitFeature = TRUE;
-                }
-                else if (EQUAL1(szToken, "h")) /* close subpath */
-                {
-                    if (!(oCoords.size() > 0 &&
-                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
-                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
-                    {
-                        oCoords.push_back(CLOSE_SUBPATH);
-                        oCoords.push_back(CLOSE_SUBPATH);
-                    }
-                }
-                else if (EQUAL1(szToken, "n")) /* new subpath without stroking or filling */
-                {
-                    oCoords.resize(0);
-                }
-                else if (EQUAL1(szToken, "s")) /* close and stroke */
-                {
-                    if (!(oCoords.size() > 0 &&
-                          oCoords[oCoords.size() - 2] == CLOSE_SUBPATH &&
-                          oCoords[oCoords.size() - 1] == CLOSE_SUBPATH))
-                    {
-                        oCoords.push_back(CLOSE_SUBPATH);
-                        oCoords.push_back(CLOSE_SUBPATH);
-                    }
-
-                    bEmitFeature = TRUE;
-                }
-                else if (EQUAL1(szToken, "S")) /* stroke */
-                {
-                    bEmitFeature = TRUE;
-                }
-                else if (EQUAL1(szToken, "m") || EQUAL1(szToken, "l"))
-                {
-                    double adfCoords[2];
-                    if (!UnstackTokens(szToken, 2, aszTokenStack, nTokenStackSize, adfCoords))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    if (EQUAL1(szToken, "m"))
-                    {
-                        if (oCoords.size() != 0)
-                            bHasMultiPart = TRUE;
-                        oCoords.push_back(NEW_SUBPATH);
-                        oCoords.push_back(NEW_SUBPATH);
-                    }
-
-                    oGS.ApplyMatrix(adfCoords);
-                    oCoords.push_back(adfCoords[0]);
-                    oCoords.push_back(adfCoords[1]);
-                }
-                else if (EQUAL1(szToken, "c")) /* Bezier curve */
-                {
-                    double adfCoords[6];
-                    if (!UnstackTokens(szToken, 6, aszTokenStack, nTokenStackSize, adfCoords))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    oGS.ApplyMatrix(adfCoords + 4);
-                    oCoords.push_back(adfCoords[4]);
-                    oCoords.push_back(adfCoords[5]);
-                }
-                else if (EQUAL1(szToken, "v") || EQUAL1(szToken, "y")) /* Bezier curve */
-                {
-                    double adfCoords[4];
-                    if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    oGS.ApplyMatrix(adfCoords + 2);
-                    oCoords.push_back(adfCoords[2]);
-                    oCoords.push_back(adfCoords[3]);
-                }
-                else if (EQUAL2(szToken, "re")) /* Rectangle */
-                {
-                    double adfCoords[4];
-                    if (!UnstackTokens(szToken, 4, aszTokenStack, nTokenStackSize, adfCoords))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    adfCoords[2] += adfCoords[0];
-                    adfCoords[3] += adfCoords[1];
-
-                    oGS.ApplyMatrix(adfCoords);
-                    oGS.ApplyMatrix(adfCoords + 2);
-
-                    if (oCoords.size() != 0)
-                        bHasMultiPart = TRUE;
-                    oCoords.push_back(NEW_SUBPATH);
-                    oCoords.push_back(NEW_SUBPATH);
-                    oCoords.push_back(adfCoords[0]);
-                    oCoords.push_back(adfCoords[1]);
-                    oCoords.push_back(adfCoords[2]);
-                    oCoords.push_back(adfCoords[1]);
-                    oCoords.push_back(adfCoords[2]);
-                    oCoords.push_back(adfCoords[3]);
-                    oCoords.push_back(adfCoords[0]);
-                    oCoords.push_back(adfCoords[3]);
-                    oCoords.push_back(CLOSE_SUBPATH);
-                    oCoords.push_back(CLOSE_SUBPATH);
-                }
-
-                else if (EQUAL2(szToken, "Do"))
-                {
-                    if (nTokenStackSize == 0)
-                    {
-                        CPLDebug("PDF",
-                                 "not enough arguments for %s",
-                                 szToken);
-                        return NULL;
-                    }
-
-                    CPLString osObjectName = aszTokenStack[--nTokenStackSize];
-
-                    if (osObjectName[0] != '/')
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-
-                    if (poResources == NULL)
-                    {
-                        if (osObjectName.find("/SymImage") == 0)
-                        {
-                            oCoords.push_back(oGS.adfCM[4] + oGS.adfCM[0] / 2);
-                            oCoords.push_back(oGS.adfCM[5] + oGS.adfCM[3] / 2);
-
-                            szToken[0] = '\0';
-                            nTokenSize = 0;
-
-                            if( poCurLayer != NULL)
-                                bEmitFeature = TRUE;
-                            else
-                                continue;
-                        }
-                        else
-                        {
-                            //CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                            return NULL;
-                        }
-                    }
-
-                    if( !bEmitFeature )
-                    {
-                        GDALPDFObject* poXObject =
-                            poResources->GetDictionary()->Get("XObject");
-                        if (poXObject == NULL ||
-                            poXObject->GetType() != PDFObjectType_Dictionary)
-                        {
-                            CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                            return NULL;
-                        }
-
-                        GDALPDFObject* poObject =
-                            poXObject->GetDictionary()->Get(osObjectName.c_str() + 1);
-                        if (poObject == NULL)
-                        {
-                            CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                            return NULL;
-                        }
-
-                        int bParseStream = TRUE;
-                        /* Check if the object is an image. If so, no need to try to parse */
-                        /* it. */
-                        if (poObject->GetType() == PDFObjectType_Dictionary)
-                        {
-                            GDALPDFObject* poSubtype = poObject->GetDictionary()->Get("Subtype");
-                            if (poSubtype != NULL &&
-                                poSubtype->GetType() == PDFObjectType_Name &&
-                                poSubtype->GetName() == "Image" )
-                            {
-                                bParseStream = FALSE;
-                            }
-                        }
-
-                        if( bParseStream )
-                        {
-                            GDALPDFStream* poStream = poObject->GetStream();
-                            if (!poStream)
-                            {
-                                CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                                return NULL;
-                            }
-
-                            char* pszStr = poStream->GetBytes();
-                            if( pszStr )
-                            {
-                                OGRGeometry* poGeom = ParseContent(pszStr, NULL, FALSE, FALSE,
-                                                                oMapPropertyToLayer, poCurLayer);
-                                CPLFree(pszStr);
-                                if (poGeom && !bCollectAllObjects)
-                                    return poGeom;
-                                delete poGeom;
-                            }
-                        }
-                    }
-                }
-                else if( EQUAL2(szToken, "RG") || EQUAL2(szToken, "rg") )
-                {
-                    double* padf = ( EQUAL2(szToken, "RG") ) ? oGS.adfStrokeColor : oGS.adfFillColor;
-                    if (!UnstackTokens(szToken, 3, aszTokenStack, nTokenStackSize, padf))
-                    {
-                        CPLDebug("PDF", "Should not happen at line %d", __LINE__);
-                        return NULL;
-                    }
-                }
-                else if (oMapOperators.find(szToken) != oMapOperators.end())
-                {
-                    int nArgs = oMapOperators[szToken];
-                    if (nArgs < 0)
-                    {
-                        while( nTokenStackSize != 0 )
-                        {
-                            CPLString osTopToken = aszTokenStack[--nTokenStackSize];
-                            if (oMapOperators.find(osTopToken) != oMapOperators.end())
-                                break;
-                        }
-                    }
-                    else
-                    {
-                        if( nArgs > nTokenStackSize )
-                        {
-                            CPLDebug("PDF",
-                                    "not enough arguments for %s",
-                                    szToken);
-                            return NULL;
-                        }
-                        nTokenStackSize -= nArgs;
-                    }
-                }
-                else
-                {
-                    PUSH(aszTokenStack, szToken, nTokenSize);
-                }
-
-                if( bEmitFeature && poCurLayer != NULL)
-                {
-                    OGRGeometry* poGeom = BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
-                    bHasFoundFill = bHasMultiPart = FALSE;
-                    if (poGeom)
-                    {
-                        OGRFeature* poFeature = new OGRFeature(poCurLayer->GetLayerDefn());
-                        if( bSetStyle )
-                        {
-                            OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
-                            if( eType == wkbLineString || eType == wkbMultiLineString )
-                            {
-                                poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X)",
-                                                                    (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
-                                                                    (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
-                                                                    (int)(oGS.adfStrokeColor[2] * 255 + 0.5)));
-                            }
-                            else if( eType == wkbPolygon || eType == wkbMultiPolygon )
-                            {
-                                poFeature->SetStyleString(CPLSPrintf("PEN(c:#%02X%02X%02X);BRUSH(fc:#%02X%02X%02X)",
-                                                                    (int)(oGS.adfStrokeColor[0] * 255 + 0.5),
-                                                                    (int)(oGS.adfStrokeColor[1] * 255 + 0.5),
-                                                                    (int)(oGS.adfStrokeColor[2] * 255 + 0.5),
-                                                                    (int)(oGS.adfFillColor[0] * 255 + 0.5),
-                                                                    (int)(oGS.adfFillColor[1] * 255 + 0.5),
-                                                                    (int)(oGS.adfFillColor[2] * 255 + 0.5)));
-                            }
-                        }
-                        poGeom->assignSpatialReference(poCurLayer->GetSpatialRef());
-                        poFeature->SetGeometryDirectly(poGeom);
-                        poCurLayer->CreateFeature(poFeature);
-                        delete poFeature;
-                    }
-
-                    oCoords.resize(0);
-                }
-            }
-
-            szToken[0] = '\0';
-            nTokenSize = 0;
-        }
-    }
-
-    if (nTokenStackSize != 0)
-    {
-        while(nTokenStackSize != 0)
-        {
-            nTokenStackSize--;
-            CPLDebug("PDF",
-                     "Remaing values in stack : %s",
-                     aszTokenStack[nTokenStackSize]);
-        }
-        return  NULL;
-    }
-
-    if (bCollectAllObjects)
-        return NULL;
-
-    return BuildGeometry(oCoords, bHasFoundFill, bHasMultiPart);
-}
-
-/************************************************************************/
-/*                           BuildGeometry()                            */
-/************************************************************************/
-
-OGRGeometry* OGRPDFDataSource::BuildGeometry(std::vector<double>& oCoords,
-                                             int bHasFoundFill,
-                                             int bHasMultiPart)
-{
-    OGRGeometry* poGeom = NULL;
-
-    if (!oCoords.size())
-        return NULL;
-
-    if (oCoords.size() == 2)
-    {
-        double X, Y;
-        PDFCoordsToSRSCoords(oCoords[0], oCoords[1], X, Y);
-        poGeom = new OGRPoint(X, Y);
-    }
-    else if (!bHasFoundFill)
-    {
-        OGRLineString* poLS = NULL;
-        OGRMultiLineString* poMLS = NULL;
-        if (bHasMultiPart)
-        {
-            poMLS = new OGRMultiLineString();
-            poGeom = poMLS;
-        }
-
-        for(size_t i=0;i<oCoords.size();i+=2)
-        {
-            if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
-            {
-                poLS = new OGRLineString();
-                if (poMLS)
-                    poMLS->addGeometryDirectly(poLS);
-                else
-                    poGeom = poLS;
-            }
-            else if (oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH)
-            {
-                if (poLS && poLS->getNumPoints() >= 2 &&
-                    !(poLS->getX(0) == poLS->getX(poLS->getNumPoints()-1) &&
-                        poLS->getY(0) == poLS->getY(poLS->getNumPoints()-1)))
-                {
-                    poLS->addPoint(poLS->getX(0), poLS->getY(0));
-                }
-            }
-            else if (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH)
-            {
-                /* Should not happen */
-            }
-            else
-            {
-                if (poLS)
-                {
-                    double X, Y;
-                    PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
-
-                    poLS->addPoint(X, Y);
-                }
-            }
-        }
-
-        /* Recognize points as outputed by GDAL (ogr-sym-2 : circle (not filled)) */
-        OGRGeometry* poCenter = NULL;
-        if (poCenter == NULL && poLS != NULL && poLS->getNumPoints() == 5)
-        {
-            poCenter = PDFGetCircleCenter(poLS);
-        }
-
-        /* Recognize points as outputed by GDAL (ogr-sym-4: square (not filled)) */
-        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 4 || poLS->getNumPoints() == 5))
-        {
-            poCenter = PDFGetSquareCenter(poLS);
-        }
-
-        /* Recognize points as outputed by GDAL (ogr-sym-6: triangle (not filled)) */
-        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 3 || poLS->getNumPoints() == 4))
-        {
-            poCenter = PDFGetTriangleCenter(poLS);
-        }
-
-        /* Recognize points as outputed by GDAL (ogr-sym-8: star (not filled)) */
-        if (poCenter == NULL && poLS != NULL && (poLS->getNumPoints() == 10 || poLS->getNumPoints() == 11))
-        {
-            poCenter = PDFGetStarCenter(poLS);
-        }
-
-        if (poCenter == NULL && poMLS != NULL && poMLS->getNumGeometries() == 2)
-        {
-            OGRLineString* poLS1 = (OGRLineString* )poMLS->getGeometryRef(0);
-            OGRLineString* poLS2 = (OGRLineString* )poMLS->getGeometryRef(1);
-
-            /* Recognize points as outputed by GDAL (ogr-sym-0: cross (+) ) */
-            if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
-                poLS1->getY(0) == poLS1->getY(1) &&
-                poLS2->getX(0) == poLS2->getX(1) &&
-                fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS2->getY(0) - poLS2->getY(1))) < EPSILON &&
-                fabs((poLS1->getX(0) + poLS1->getX(1)) / 2 - poLS2->getX(0)) < EPSILON &&
-                fabs((poLS2->getY(0) + poLS2->getY(1)) / 2 - poLS1->getY(0)) < EPSILON)
-            {
-                poCenter = new OGRPoint(poLS2->getX(0), poLS1->getY(0));
-            }
-            /* Recognize points as outputed by GDAL (ogr-sym-1: diagcross (X) ) */
-            else if (poLS1->getNumPoints() == 2 && poLS2->getNumPoints() == 2 &&
-                     poLS1->getX(0) == poLS2->getX(0) &&
-                     poLS1->getY(0) == poLS2->getY(1) &&
-                     poLS1->getX(1) == poLS2->getX(1) &&
-                     poLS1->getY(1) == poLS2->getY(0) &&
-                     fabs(fabs(poLS1->getX(0) - poLS1->getX(1)) - fabs(poLS1->getY(0) - poLS1->getY(1))) < EPSILON)
-            {
-                poCenter = new OGRPoint((poLS1->getX(0) + poLS1->getX(1)) / 2,
-                                        (poLS1->getY(0) + poLS1->getY(1)) / 2);
-            }
-        }
-
-        if (poCenter)
-        {
-            delete poGeom;
-            poGeom = poCenter;
-        }
-    }
-    else
-    {
-        OGRLinearRing* poLS = NULL;
-        int nPolys = 0;
-        OGRGeometry** papoPoly = NULL;
-
-        for(size_t i=0;i<oCoords.size();i+=2)
-        {
-            if (oCoords[i] == NEW_SUBPATH && oCoords[i+1] == NEW_SUBPATH)
-            {
-                delete poLS;
-                poLS = new OGRLinearRing();
-            }
-            else if ((oCoords[i] == CLOSE_SUBPATH && oCoords[i+1] == CLOSE_SUBPATH) ||
-                        (oCoords[i] == FILL_SUBPATH && oCoords[i+1] == FILL_SUBPATH))
-            {
-                if (poLS)
-                {
-                    poLS->closeRings();
-
-                    OGRPoint* poCenter = NULL;
-
-                    if (nPolys == 0 &&
-                        poLS &&
-                        poLS->getNumPoints() == 5)
-                    {
-                        /* Recognize points as outputed by GDAL (ogr-sym-3 : circle (filled)) */
-                        poCenter = PDFGetCircleCenter(poLS);
-
-                        /* Recognize points as outputed by GDAL (ogr-sym-5: square (filled)) */
-                        if (poCenter == NULL)
-                            poCenter = PDFGetSquareCenter(poLS);
-
-                        /* ESRI points */
-                        if (poCenter == NULL &&
-                            oCoords.size() == 14 &&
-                            poLS->getY(0) == poLS->getY(1) &&
-                            poLS->getX(1) == poLS->getX(2) &&
-                            poLS->getY(2) == poLS->getY(3) &&
-                            poLS->getX(3) == poLS->getX(0))
-                        {
-                            poCenter = new OGRPoint((poLS->getX(0) + poLS->getX(1)) / 2,
-                                                    (poLS->getY(0) + poLS->getY(2)) / 2);
-                        }
-                    }
-                    /* Recognize points as outputed by GDAL (ogr-sym-7: triangle (filled)) */
-                    else if (nPolys == 0 &&
-                             poLS &&
-                             poLS->getNumPoints() == 4)
-                    {
-                        poCenter = PDFGetTriangleCenter(poLS);
-                    }
-                    /* Recognize points as outputed by GDAL (ogr-sym-9: star (filled)) */
-                    else if (nPolys == 0 &&
-                             poLS &&
-                             poLS->getNumPoints() == 11)
-                    {
-                        poCenter = PDFGetStarCenter(poLS);
-                    }
-
-                    if (poCenter)
-                    {
-                        poGeom = poCenter;
-                        break;
-                    }
-
-                    if (poLS->getNumPoints() >= 3)
-                    {
-                        OGRPolygon* poPoly =  new OGRPolygon();
-                        poPoly->addRingDirectly(poLS);
-                        poLS = NULL;
-
-                        papoPoly = (OGRGeometry**) CPLRealloc(papoPoly, (nPolys + 1) * sizeof(OGRGeometry*));
-                        papoPoly[nPolys ++] = poPoly;
-                    }
-                    else
-                    {
-                        delete poLS;
-                        poLS = NULL;
-                    }
-                }
-            }
-            else
-            {
-                if (poLS)
-                {
-                    double X, Y;
-                    PDFCoordsToSRSCoords(oCoords[i], oCoords[i+1], X, Y);
-
-                    poLS->addPoint(X, Y);
-                }
-            }
-        }
-
-        delete poLS;
-
-        int bIsValidGeometry;
-        if (nPolys == 2 &&
-            ((OGRPolygon*)papoPoly[0])->getNumInteriorRings() == 0 &&
-            ((OGRPolygon*)papoPoly[1])->getNumInteriorRings() == 0)
-        {
-            OGRLinearRing* poRing0 = ((OGRPolygon*)papoPoly[0])->getExteriorRing();
-            OGRLinearRing* poRing1 = ((OGRPolygon*)papoPoly[1])->getExteriorRing();
-            if (poRing0->getNumPoints() == poRing1->getNumPoints())
-            {
-                int bSameRing = TRUE;
-                for(int i=0;i<poRing0->getNumPoints();i++)
-                {
-                    if (poRing0->getX(i) != poRing1->getX(i))
-                    {
-                        bSameRing = FALSE;
-                        break;
-                    }
-                    if (poRing0->getY(i) != poRing1->getY(i))
-                    {
-                        bSameRing = FALSE;
-                        break;
-                    }
-                }
-
-                /* Just keep on ring if they are identical */
-                if (bSameRing)
-                {
-                    delete papoPoly[1];
-                    nPolys = 1;
-                }
-            }
-        }
-        if (nPolys)
-        {
-            poGeom = OGRGeometryFactory::organizePolygons(
-                    papoPoly, nPolys, &bIsValidGeometry, NULL);
-        }
-        CPLFree(papoPoly);
-    }
-
-    return poGeom;
-}
-
-/************************************************************************/
-/*                          ExploreContents()                           */
-/************************************************************************/
-
-void OGRPDFDataSource::ExploreContents(GDALPDFObject* poObj,
-                                       GDALPDFObject* poResources)
-{
-    std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
-
-    if (poObj->GetType() == PDFObjectType_Array)
-    {
-        GDALPDFArray* poArray = poObj->GetArray();
-        for(int i=0;i<poArray->GetLength();i++)
-            ExploreContents(poArray->Get(i), poResources);
-    }
-
-    if (poObj->GetType() != PDFObjectType_Dictionary)
-        return;
-
-    GDALPDFStream* poStream = poObj->GetStream();
-    if (!poStream)
-        return;
-
-    char* pszStr = poStream->GetBytes();
-    if (!pszStr)
-        return;
-
-    const char* pszMCID = (const char*) pszStr;
-    while((pszMCID = strstr(pszMCID, "/MCID")) != NULL)
-    {
-        const char* pszBDC = strstr(pszMCID, "BDC");
-        if (pszBDC)
-        {
-            /* Hack for http://www.avenza.com/sites/default/files/spatialpdf/US_County_Populations.pdf */
-            /* FIXME: that logic is too fragile. */
-            const char* pszStartParsing = pszBDC;
-            const char* pszAfterBDC = pszBDC + 3;
-            int bMatchQ = FALSE;
-            while (pszAfterBDC[0] == ' ' || pszAfterBDC[0] == '\r' || pszAfterBDC[0] == '\n')
-                pszAfterBDC ++;
-            if (strncmp(pszAfterBDC, "0 0 m", 5) == 0)
-            {
-                const char* pszLastq = pszBDC;
-                while(pszLastq > pszStr && *pszLastq != 'q')
-                    pszLastq --;
-
-                if (pszLastq > pszStr && *pszLastq == 'q' &&
-                    (pszLastq[-1] == ' ' || pszLastq[-1] == '\r' || pszLastq[-1] == '\n') &&
-                    (pszLastq[1] == ' ' || pszLastq[1] == '\r' || pszLastq[1] == '\n'))
-                {
-                    pszStartParsing = pszLastq;
-                    bMatchQ = TRUE;
-                }
-            }
-
-            int nMCID = atoi(pszMCID + 6);
-            if (GetGeometryFromMCID(nMCID) == NULL)
-            {
-                OGRGeometry* poGeom = ParseContent(pszStartParsing, poResources,
-                                                   !bMatchQ, bMatchQ, oMapPropertyToLayer, NULL);
-                if( poGeom != NULL )
-                {
-                    /* Save geometry in map */
-                    oMapMCID[nMCID] = poGeom;
-                }
-            }
-        }
-        pszMCID += 5;
-    }
-    CPLFree(pszStr);
-}
-
-/************************************************************************/
-/*                           PDFSanitizeLayerName()                     */
-/************************************************************************/
-
-static
-CPLString PDFSanitizeLayerName(const char* pszName)
-{
-    CPLString osName;
-    for(int i=0; pszName[i] != '\0'; i++)
-    {
-        if (pszName[i] == ' ' || pszName[i] == '.' || pszName[i] == ',')
-            osName += "_";
-        else
-            osName += pszName[i];
-    }
-    return osName;
-}
-
-/************************************************************************/
-/*                   ExploreContentsNonStructured()                     */
-/************************************************************************/
-
-void OGRPDFDataSource::ExploreContentsNonStructuredInternal(GDALPDFObject* poContents,
-                                                            GDALPDFObject* poResources,
-                                                            std::map<CPLString, OGRPDFLayer*>& oMapPropertyToLayer)
-{
-    if (poContents->GetType() == PDFObjectType_Array)
-    {
-        GDALPDFArray* poArray = poContents->GetArray();
-        char* pszConcatStr = NULL;
-        int nConcatLen = 0;
-        for(int i=0;i<poArray->GetLength();i++)
-        {
-            GDALPDFObject* poObj = poArray->Get(i);
-            if( poObj->GetType() != PDFObjectType_Dictionary)
-                break;
-            GDALPDFStream* poStream = poObj->GetStream();
-            if (!poStream)
-                break;
-            char* pszStr = poStream->GetBytes();
-            if (!pszStr)
-                break;
-            int nLen = (int)strlen(pszStr);
-            char* pszConcatStrNew = (char*)CPLRealloc(pszConcatStr, nConcatLen + nLen + 1);
-            if( pszConcatStrNew == NULL )
-            {
-                CPLFree(pszStr);
-                break;
-            }
-            pszConcatStr = pszConcatStrNew;
-            memcpy(pszConcatStr + nConcatLen, pszStr, nLen+1);
-            nConcatLen += nLen;
-            CPLFree(pszStr);
-        }
-        if( pszConcatStr )
-            ParseContent(pszConcatStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
-        CPLFree(pszConcatStr);
-        return;
-    }
-
-    if (poContents->GetType() != PDFObjectType_Dictionary)
-        return;
-
-    GDALPDFStream* poStream = poContents->GetStream();
-    if (!poStream)
-        return;
-
-    char* pszStr = poStream->GetBytes();
-    if( !pszStr )
-        return;
-    ParseContent(pszStr, poResources, FALSE, FALSE, oMapPropertyToLayer, NULL);
-    CPLFree(pszStr);
-}
-
-void OGRPDFDataSource::ExploreContentsNonStructured(GDALPDFObject* poContents,
-                                                    GDALPDFObject* poResources)
-{
-    std::map<CPLString, OGRPDFLayer*> oMapPropertyToLayer;
-    if (poResources != NULL &&
-        poResources->GetType() == PDFObjectType_Dictionary)
-    {
-        GDALPDFObject* poProperties =
-            poResources->GetDictionary()->Get("Properties");
-        if (poProperties != NULL &&
-            poProperties->GetType() == PDFObjectType_Dictionary)
-        {
-            CPLAssert(poGDAL_DS != NULL);
-            char** papszLayersWithRef = poGDAL_DS->GetMetadata("LAYERS_WITH_REF");
-            char** papszIter = papszLayersWithRef;
-            std::map< std::pair<int, int>, OGRPDFLayer *> oMapNumGenToLayer;
-            while(papszIter && *papszIter)
-            {
-                char** papszTokens = CSLTokenizeString(*papszIter);
-
-                if( CSLCount(papszTokens) != 3 ) {
-                    CSLDestroy(papszTokens);
-                    CPLDebug("PDF", "Ignore '%s', unparsable.", *papszIter);
-                    papszIter ++;
-                    continue;
-                }
-
-                const char* pszLayerName = papszTokens[0];
-                int nNum = atoi(papszTokens[1]);
-                int nGen = atoi(papszTokens[2]);
-
-                CPLString osSanitizedName(PDFSanitizeLayerName(pszLayerName));
-
-                OGRPDFLayer* poLayer = (OGRPDFLayer*) GetLayerByName(osSanitizedName.c_str());
-                if (poLayer == NULL)
-                {
-                    const char* pszWKT = poGDAL_DS->GetProjectionRef();
-                    OGRSpatialReference* poSRS = NULL;
-                    if (pszWKT && pszWKT[0] != '\0')
-                    {
-                        poSRS = new OGRSpatialReference();
-                        poSRS->importFromWkt((char**) &pszWKT);
-                    }
-
-                    poLayer =
-                        new OGRPDFLayer(this, osSanitizedName.c_str(), poSRS, wkbUnknown);
-                    delete poSRS;
-
-                    papoLayers = (OGRLayer**)
-                        CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
-                    papoLayers[nLayers] = poLayer;
-                    nLayers ++;
-                }
-
-                oMapNumGenToLayer[ std::pair<int,int>(nNum, nGen) ] = poLayer;
-
-                CSLDestroy(papszTokens);
-                papszIter ++;
-            }
-
-            std::map<CPLString, GDALPDFObject*>& oMap =
-                                    poProperties->GetDictionary()->GetValues();
-            std::map<CPLString, GDALPDFObject*>::iterator oIter = oMap.begin();
-            std::map<CPLString, GDALPDFObject*>::iterator oEnd = oMap.end();
-
-            for(; oIter != oEnd; ++oIter)
-            {
-                const char* pszKey = oIter->first.c_str();
-                GDALPDFObject* poObj = oIter->second;
-                if( poObj->GetRefNum() != 0 )
-                {
-                    std::map< std::pair<int, int>, OGRPDFLayer *>::iterator
-                        oIterNumGenToLayer = oMapNumGenToLayer.find(
-                            std::pair<int,int>(poObj->GetRefNum(), poObj->GetRefGen()) );
-                    if( oIterNumGenToLayer != oMapNumGenToLayer.end() )
-                    {
-                        oMapPropertyToLayer[pszKey] = oIterNumGenToLayer->second;
-                    }
-                }
-            }
-        }
-    }
-
-    if( nLayers == 0 )
-        return;
-
-    ExploreContentsNonStructuredInternal(poContents,
-                                         poResources,
-                                         oMapPropertyToLayer);
-
-    /* Remove empty layers */
-    int i = 0;
-    while(i < nLayers)
-    {
-        if (papoLayers[i]->GetFeatureCount() == 0)
-        {
-            delete papoLayers[i];
-            if (i < nLayers - 1)
-            {
-                memmove(papoLayers + i, papoLayers + i + 1,
-                        (nLayers - 1 - i) * sizeof(OGRPDFLayer*));
-            }
-            nLayers --;
-        }
-        else
-            i ++;
-    }
-}
-
-/************************************************************************/
-/*                               Open()                                 */
-/************************************************************************/
-
-int OGRPDFDataSource::Open( const char * pszName)
-{
-    this->pszName = CPLStrdup(pszName);
-
-    poGDAL_DS = GDALPDFOpen(pszName, GA_ReadOnly);
-    if (poGDAL_DS == NULL)
-        return FALSE;
-
-    const char* pszPageObj = poGDAL_DS->GetMetadataItem("PDF_PAGE_OBJECT");
-    if (pszPageObj)
-        sscanf(pszPageObj, "%p", &poPageObj);
-    if (poPageObj == NULL || poPageObj->GetType() != PDFObjectType_Dictionary)
-        return FALSE;
-
-    GDALPDFObject* poMediaBox = poPageObj->GetDictionary()->Get("MediaBox");
-    if (poMediaBox == NULL || poMediaBox->GetType() != PDFObjectType_Array ||
-        poMediaBox->GetArray()->GetLength() != 4)
-        return FALSE;
-
-    if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Real)
-        dfPageWidth = poMediaBox->GetArray()->Get(2)->GetReal();
-    else if (poMediaBox->GetArray()->Get(2)->GetType() == PDFObjectType_Int)
-        dfPageWidth = poMediaBox->GetArray()->Get(2)->GetInt();
-    else
-        return FALSE;
-
-    if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Real)
-        dfPageHeight = poMediaBox->GetArray()->Get(3)->GetReal();
-    else if (poMediaBox->GetArray()->Get(3)->GetType() == PDFObjectType_Int)
-        dfPageHeight = poMediaBox->GetArray()->Get(3)->GetInt();
-    else
-        return FALSE;
-
-    GDALPDFObject* poContents = poPageObj->GetDictionary()->Get("Contents");
-    if (poContents == NULL)
-        return FALSE;
-
-    if (poContents->GetType() != PDFObjectType_Dictionary &&
-        poContents->GetType() != PDFObjectType_Array)
-        return FALSE;
-
-    GDALPDFObject* poResources = poPageObj->GetDictionary()->Get("Resources");
-    if (poResources == NULL || poResources->GetType() != PDFObjectType_Dictionary)
-        return FALSE;
-    
-    const char* pszCatalog = poGDAL_DS->GetMetadataItem("PDF_CATALOG_OBJECT");
-    if (pszCatalog)
-        sscanf(pszCatalog, "%p", &poCatalogObj);
-    if (poCatalogObj == NULL || poCatalogObj->GetType() != PDFObjectType_Dictionary)
-        return FALSE;
-
-    nXSize = poGDAL_DS->GetRasterXSize();
-    nYSize = poGDAL_DS->GetRasterYSize();
-    poGDAL_DS->GetGeoTransform(adfGeoTransform);
-
-
-    GDALPDFObject* poStructTreeRoot = poCatalogObj->GetDictionary()->Get("StructTreeRoot");
-    if (CSLTestBoolean(CPLGetConfigOption("OGR_PDF_READ_NON_STRUCTURED", "NO")) ||
-        poStructTreeRoot == NULL ||
-        poStructTreeRoot->GetType() != PDFObjectType_Dictionary)
-    {
-        ExploreContentsNonStructured(poContents, poResources);
-    }
-    else
-    {
-        ExploreContents(poContents, poResources);
-        ExploreTree(poStructTreeRoot, 0);
-    }
-
-    CleanupIntermediateResources();
-
-    int bEmptyDS = TRUE;
-    for(int i=0;i<nLayers;i++)
-    {
-        if (papoLayers[i]->GetFeatureCount() != 0)
-        {
-            bEmptyDS = FALSE;
-            break;
-        }
-    }
-    if (bEmptyDS)
-        return FALSE;
-
-    return TRUE;
-}
-
-/************************************************************************/
-/*                               Create()                               */
-/************************************************************************/
-
-int OGRPDFDataSource::Create( const char * pszName, char **papszOptions )
-{
-    this->pszName = CPLStrdup(pszName);
-    this->papszOptions = CSLDuplicate(papszOptions);
-    bWritable = TRUE;
-
-    return TRUE;
-}
-
-/************************************************************************/
-/*                            CreateLayer()                             */
-/************************************************************************/
-
-OGRLayer *
-OGRPDFDataSource::CreateLayer( const char * pszLayerName,
-                               OGRSpatialReference *poSRS,
-                               OGRwkbGeometryType eType,
-                               CPL_UNUSED char ** papszOptions )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Create the layer object.                                        */
-/* -------------------------------------------------------------------- */
-    OGRLayer* poLayer = new OGRPDFLayer(this, pszLayerName, poSRS, eType);
-
-    papoLayers = (OGRLayer**)CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*));
-    papoLayers[nLayers] = poLayer;
-    nLayers ++;
-
-    return poLayer;
-}
-
-/************************************************************************/
-/*                            SyncToDisk()                              */
-/************************************************************************/
-
-OGRErr OGRPDFDataSource::SyncToDisk()
-{
-    if (nLayers == 0 || !bModified || !bWritable)
-        return OGRERR_NONE;
-
-    bModified = FALSE;
-
-    OGREnvelope sGlobalExtent;
-    int bHasExtent = FALSE;
-    for(int i=0;i<nLayers;i++)
-    {
-        OGREnvelope sExtent;
-        if (papoLayers[i]->GetExtent(&sExtent) == OGRERR_NONE)
-        {
-            bHasExtent = TRUE;
-            sGlobalExtent.Merge(sExtent);
-        }
-    }
-    if (!bHasExtent ||
-        sGlobalExtent.MinX == sGlobalExtent.MaxX ||
-        sGlobalExtent.MinY == sGlobalExtent.MaxY)
-    {
-        CPLError(CE_Failure, CPLE_AppDefined,
-                 "Cannot compute spatial extent of features");
-        return OGRERR_FAILURE;
-    }
-
-    PDFCompressMethod eStreamCompressMethod = COMPRESS_DEFLATE;
-    const char* pszStreamCompressMethod = CSLFetchNameValue(papszOptions, "STREAM_COMPRESS");
-    if (pszStreamCompressMethod)
-    {
-        if( EQUAL(pszStreamCompressMethod, "NONE") )
-            eStreamCompressMethod = COMPRESS_NONE;
-        else if( EQUAL(pszStreamCompressMethod, "DEFLATE") )
-            eStreamCompressMethod = COMPRESS_DEFLATE;
-        else
-        {
-            CPLError( CE_Warning, CPLE_NotSupported,
-                    "Unsupported value for STREAM_COMPRESS.");
-        }
-    }
-
-    const char* pszGEO_ENCODING =
-        CSLFetchNameValueDef(papszOptions, "GEO_ENCODING", "ISO32000");
-
-    double dfDPI = atof(CSLFetchNameValueDef(papszOptions, "DPI", "72"));
-    if (dfDPI < 72.0)
-        dfDPI = 72.0;
-
-    const char* pszNEATLINE = CSLFetchNameValue(papszOptions, "NEATLINE");
-
-    int nMargin = atoi(CSLFetchNameValueDef(papszOptions, "MARGIN", "0"));
-
-    PDFMargins sMargins;
-    sMargins.nLeft = nMargin;
-    sMargins.nRight = nMargin;
-    sMargins.nTop = nMargin;
-    sMargins.nBottom = nMargin;
-
-    const char* pszLeftMargin = CSLFetchNameValue(papszOptions, "LEFT_MARGIN");
-    if (pszLeftMargin) sMargins.nLeft = atoi(pszLeftMargin);
-
-    const char* pszRightMargin = CSLFetchNameValue(papszOptions, "RIGHT_MARGIN");
-    if (pszRightMargin) sMargins.nRight = atoi(pszRightMargin);
-
-    const char* pszTopMargin = CSLFetchNameValue(papszOptions, "TOP_MARGIN");
-    if (pszTopMargin) sMargins.nTop = atoi(pszTopMargin);
-
-    const char* pszBottomMargin = CSLFetchNameValue(papszOptions, "BOTTOM_MARGIN");
-    if (pszBottomMargin) sMargins.nBottom = atoi(pszBottomMargin);
-
-    const char* pszExtraImages = CSLFetchNameValue(papszOptions, "EXTRA_IMAGES");
-    const char* pszExtraStream = CSLFetchNameValue(papszOptions, "EXTRA_STREAM");
-    const char* pszExtraLayerName = CSLFetchNameValue(papszOptions, "EXTRA_LAYER_NAME");
-
-    const char* pszOGRDisplayField = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_FIELD");
-    const char* pszOGRDisplayLayerNames = CSLFetchNameValue(papszOptions, "OGR_DISPLAY_LAYER_NAMES");
-    int bWriteOGRAttributes = CSLFetchBoolean(papszOptions, "OGR_WRITE_ATTRIBUTES", TRUE);
-    const char* pszOGRLinkField = CSLFetchNameValue(papszOptions, "OGR_LINK_FIELD");
-
-    const char* pszOffLayers = CSLFetchNameValue(papszOptions, "OFF_LAYERS");
-    const char* pszExclusiveLayers = CSLFetchNameValue(papszOptions, "EXCLUSIVE_LAYERS");
-
-    const char* pszJavascript = CSLFetchNameValue(papszOptions, "JAVASCRIPT");
-    const char* pszJavascriptFile = CSLFetchNameValue(papszOptions, "JAVASCRIPT_FILE");
-
-/* -------------------------------------------------------------------- */
-/*      Create file.                                                    */
-/* -------------------------------------------------------------------- */
-    VSILFILE* fp = VSIFOpenL(pszName, "wb");
-    if( fp == NULL )
-    {
-        CPLError( CE_Failure, CPLE_OpenFailed,
-                  "Unable to create PDF file %s.\n",
-                  pszName );
-        return OGRERR_FAILURE;
-    }
-
-    GDALPDFWriter oWriter(fp);
-
-    double dfRatio = (sGlobalExtent.MaxY - sGlobalExtent.MinY) / (sGlobalExtent.MaxX - sGlobalExtent.MinX);
-
-    int nWidth, nHeight;
-
-    if (dfRatio < 1)
-    {
-        nWidth = 1024;
-        nHeight = nWidth * dfRatio;
-    }
-    else
-    {
-        nHeight = 1024;
-        nWidth = nHeight / dfRatio;
-    }
-
-    GDALDataset* poSrcDS = MEMDataset::Create( "MEM:::", nWidth, nHeight, 0, GDT_Byte, NULL );
-
-    double adfGeoTransform[6];
-    adfGeoTransform[0] = sGlobalExtent.MinX;
-    adfGeoTransform[1] = (sGlobalExtent.MaxX - sGlobalExtent.MinX) / nWidth;
-    adfGeoTransform[2] = 0;
-    adfGeoTransform[3] = sGlobalExtent.MaxY;
-    adfGeoTransform[4] = 0;
-    adfGeoTransform[5] = - (sGlobalExtent.MaxY - sGlobalExtent.MinY) / nHeight;
-
-    poSrcDS->SetGeoTransform(adfGeoTransform);
-
-    OGRSpatialReference* poSRS = papoLayers[0]->GetSpatialRef();
-    if (poSRS)
-    {
-        char* pszWKT = NULL;
-        poSRS->exportToWkt(&pszWKT);
-        poSrcDS->SetProjection(pszWKT);
-        CPLFree(pszWKT);
-    }
-
-    oWriter.SetInfo(poSrcDS, papszOptions);
-
-    oWriter.StartPage(poSrcDS,
-                      dfDPI,
-                      pszGEO_ENCODING,
-                      pszNEATLINE,
-                      &sMargins,
-                      eStreamCompressMethod,
-                      bWriteOGRAttributes);
-
-    int iObj = 0;
-    
-    char** papszLayerNames = CSLTokenizeString2(pszOGRDisplayLayerNames,",",0);
-
-    for(int i=0;i<nLayers;i++)
-    {
-        CPLString osLayerName;
-        if (CSLCount(papszLayerNames) < nLayers)
-            osLayerName = papoLayers[i]->GetName();
-        else
-            osLayerName = papszLayerNames[i];
-
-        oWriter.WriteOGRLayer((OGRDataSourceH)this,
-                              i,
-                              pszOGRDisplayField,
-                              pszOGRLinkField,
-                              osLayerName,
-                              bWriteOGRAttributes,
-                              iObj);
-    }
-
-    CSLDestroy(papszLayerNames);
-
-    oWriter.EndPage(pszExtraImages,
-                    pszExtraStream,
-                    pszExtraLayerName,
-                    pszOffLayers,
-                    pszExclusiveLayers);
-
-    if (pszJavascript)
-        oWriter.WriteJavascript(pszJavascript);
-    else if (pszJavascriptFile)
-        oWriter.WriteJavascriptFile(pszJavascriptFile);
-
-    oWriter.Close();
-
-    delete poSrcDS;
-
-    return OGRERR_NONE;
-}
diff --git a/ogr/ogrsf_frmts/pdf/ogrpdfdriver.cpp b/ogr/ogrsf_frmts/pdf/ogrpdfdriver.cpp
deleted file mode 100644
index 83b6c40..0000000
--- a/ogr/ogrsf_frmts/pdf/ogrpdfdriver.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/******************************************************************************
- * $Id: ogrpdfdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
- *
- * Project:  PDF Translator
- * Purpose:  Implements OGRPDFDriver.
- * Author:   Even Rouault, even dot rouault at mines dash paris dot org
- *
- ******************************************************************************
- * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
- *
- * 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.
- ****************************************************************************/
-
-#include "ogr_pdf.h"
-#include "cpl_conv.h"
-
-CPL_CVSID("$Id: ogrpdfdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-extern "C" void RegisterOGRPDF();
-
-// g++ -g -Wall -fPIC ogr/ogrsf_frmts/pdf/*.cpp -shared -o ogr_PDF.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/mem -Iogr/ogrsf_frmts/pdf -Ifrmts/pdf -L. -lgdal
-
-/************************************************************************/
-/*                           ~OGRPDFDriver()                            */
-/************************************************************************/
-
-OGRPDFDriver::~OGRPDFDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRPDFDriver::GetName()
-
-{
-    return "PDF";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-OGRDataSource *OGRPDFDriver::Open( const char * pszFilename, int bUpdate )
-
-{
-    if( !EQUAL(CPLGetExtension(pszFilename), "pdf") || bUpdate )
-        return NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Try to create datasource.                                       */
-/* -------------------------------------------------------------------- */
-    OGRPDFDataSource     *poDS;
-
-    poDS = new OGRPDFDataSource();
-
-    if( !poDS->Open( pszFilename ) )
-    {
-        delete poDS;
-        return NULL;
-    }
-    else
-        return poDS;
-}
-
-/************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGRPDFDriver::CreateDataSource( const char * pszName,
-                                                char **papszOptions )
-
-{
-/* -------------------------------------------------------------------- */
-/*      First, ensure there isn't any such file yet.                    */
-/* -------------------------------------------------------------------- */
-    VSIStatBufL sStatBuf;
-
-    if( VSIStatL( pszName, &sStatBuf ) == 0 )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "It seems a file system object called '%s' already exists.",
-                  pszName );
-
-        return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Try to create datasource.                                       */
-/* -------------------------------------------------------------------- */
-    OGRPDFDataSource     *poDS;
-
-    poDS = new OGRPDFDataSource();
-
-    if( !poDS->Create( pszName, papszOptions ) )
-    {
-        delete poDS;
-        return NULL;
-    }
-    else
-        return poDS;
-}
-
-/************************************************************************/
-/*                         DeleteDataSource()                           */
-/************************************************************************/
-
-OGRErr OGRPDFDriver::DeleteDataSource( const char *pszName )
-{
-    if (VSIUnlink( pszName ) == 0)
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPDFDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                           RegisterOGRPDF()                           */
-/************************************************************************/
-
-void RegisterOGRPDF()
-
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPDFDriver );
-}
-
diff --git a/ogr/ogrsf_frmts/pds/GNUmakefile b/ogr/ogrsf_frmts/pds/GNUmakefile
index 32aeb5b..f43bd13 100644
--- a/ogr/ogrsf_frmts/pds/GNUmakefile
+++ b/ogr/ogrsf_frmts/pds/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrpdsdriver.o ogrpdsdatasource.o ogrpdslayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../../../frmts/pds $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../../../frmts/pds  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/pds/ogr_pds.h b/ogr/ogrsf_frmts/pds/ogr_pds.h
index 277b00c..f56692e 100644
--- a/ogr/ogrsf_frmts/pds/ogr_pds.h
+++ b/ogr/ogrsf_frmts/pds/ogr_pds.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_pds.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_pds.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  PDS Translator
  * Purpose:  Definition of classes for OGR .pdstable driver.
@@ -93,11 +93,11 @@ class OGRPDSLayer : public OGRLayer
 
     virtual int                 TestCapability( const char * );
 
-    virtual int                 GetFeatureCount(int bForce = TRUE );
+    virtual GIntBig             GetFeatureCount(int bForce = TRUE );
 
-    virtual OGRFeature         *GetFeature( long nFID );
+    virtual OGRFeature         *GetFeature( GIntBig nFID );
 
-    virtual OGRErr              SetNextByIndex( long nIndex );
+    virtual OGRErr              SetNextByIndex( GIntBig nIndex );
 };
 
 /************************************************************************/
@@ -126,8 +126,7 @@ class OGRPDSDataSource : public OGRDataSource
                         OGRPDSDataSource();
                         ~OGRPDSDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -139,19 +138,4 @@ class OGRPDSDataSource : public OGRDataSource
     static void         CleanString( CPLString &osInput );
 };
 
-/************************************************************************/
-/*                              OGRPDSDriver                            */
-/************************************************************************/
-
-class OGRPDSDriver : public OGRSFDriver
-{
-  public:
-                ~OGRPDSDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_PDS_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/pds/ogrpdsdatasource.cpp b/ogr/ogrsf_frmts/pds/ogrpdsdatasource.cpp
index 29e84eb..0f999b5 100644
--- a/ogr/ogrsf_frmts/pds/ogrpdsdatasource.cpp
+++ b/ogr/ogrsf_frmts/pds/ogrpdsdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpdsdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrpdsdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  PDS Translator
  * Purpose:  Implements OGRPDSDataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrpdsdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrpdsdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                           OGRPDSDataSource()                         */
@@ -273,14 +273,9 @@ int OGRPDSDataSource::LoadTable(const char* pszFilename,
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRPDSDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRPDSDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
 // --------------------------------------------------------------------
diff --git a/ogr/ogrsf_frmts/pds/ogrpdsdriver.cpp b/ogr/ogrsf_frmts/pds/ogrpdsdriver.cpp
index 751f2e5..ae4d032 100644
--- a/ogr/ogrsf_frmts/pds/ogrpdsdriver.cpp
+++ b/ogr/ogrsf_frmts/pds/ogrpdsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpdsdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrpdsdriver.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  PDS Translator
  * Purpose:  Implements OGRPDSDriver.
@@ -30,39 +30,27 @@
 #include "ogr_pds.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrpdsdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrpdsdriver.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 extern "C" void RegisterOGRPDS();
 
 /************************************************************************/
-/*                            ~OGRPDSDriver()                           */
-/************************************************************************/
-
-OGRPDSDriver::~OGRPDSDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRPDSDriver::GetName()
+static GDALDataset *OGRPDSDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    return "PDS";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL )
+        return NULL;
 
-OGRDataSource *OGRPDSDriver::Open( const char * pszFilename, int bUpdate )
+    if( strstr((const char*)poOpenInfo->pabyHeader, "PDS_VERSION_ID") == NULL )
+        return NULL;
 
-{
     OGRPDSDataSource   *poDS = new OGRPDSDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -71,14 +59,6 @@ OGRDataSource *OGRPDSDriver::Open( const char * pszFilename, int bUpdate )
     return poDS;
 }
 
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPDSDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
 
 /************************************************************************/
 /*                           RegisterOGRPDS()                      */
@@ -87,6 +67,24 @@ int OGRPDSDriver::TestCapability( CPL_UNUSED const char * pszCap )
 void RegisterOGRPDS()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPDSDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "OGR_PDS" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "OGR_PDS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Planetary Data Systems TABLE" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_pds.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRPDSDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/pds/ogrpdslayer.cpp b/ogr/ogrsf_frmts/pds/ogrpdslayer.cpp
index e4806b0..1f0fab6 100644
--- a/ogr/ogrsf_frmts/pds/ogrpdslayer.cpp
+++ b/ogr/ogrsf_frmts/pds/ogrpdslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpdslayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpdslayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  PDS Translator
  * Purpose:  Implements OGRPDSLayer class.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrpdslayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpdslayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                           OGRPDSLayer()                              */
@@ -56,6 +56,7 @@ OGRPDSLayer::OGRPDSLayer(   CPLString osTableID,
     nLatitudeIndex = -1;
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone );
 
@@ -701,7 +702,7 @@ int OGRPDSLayer::TestCapability( const char * pszCap )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRPDSLayer::GetFeatureCount(int bForce )
+GIntBig OGRPDSLayer::GetFeatureCount(int bForce )
 {
     if (TestCapability(OLCFastFeatureCount))
         return nRecords;
@@ -713,12 +714,12 @@ int OGRPDSLayer::GetFeatureCount(int bForce )
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRPDSLayer::GetFeature( long nFID )
+OGRFeature *OGRPDSLayer::GetFeature( GIntBig nFID )
 {
     if (nFID < 0 || nFID >= nRecords)
         return NULL;
 
-    nNextFID = nFID;
+    nNextFID = (int)nFID;
     VSIFSeekL( fpPDS, nStartBytes + nNextFID * nRecordSize, SEEK_SET );
     return GetNextRawFeature();
 }
@@ -727,7 +728,7 @@ OGRFeature *OGRPDSLayer::GetFeature( long nFID )
 /*                         SetNextByIndex()                             */
 /************************************************************************/
 
-OGRErr OGRPDSLayer::SetNextByIndex( long nIndex )
+OGRErr OGRPDSLayer::SetNextByIndex( GIntBig nIndex )
 {
     if (!TestCapability(OLCFastSetNextByIndex))
         return OGRLayer::SetNextByIndex( nIndex );
@@ -735,7 +736,7 @@ OGRErr OGRPDSLayer::SetNextByIndex( long nIndex )
     if (nIndex < 0 || nIndex >= nRecords)
         return OGRERR_FAILURE;
 
-    nNextFID = nIndex;
+    nNextFID = (int)nIndex;
     VSIFSeekL( fpPDS, nStartBytes + nNextFID * nRecordSize, SEEK_SET );
     return OGRERR_NONE;
 }
diff --git a/ogr/ogrsf_frmts/pg/GNUmakefile b/ogr/ogrsf_frmts/pg/GNUmakefile
index e393d6e..4d333ab 100644
--- a/ogr/ogrsf_frmts/pg/GNUmakefile
+++ b/ogr/ogrsf_frmts/pg/GNUmakefile
@@ -5,11 +5,11 @@ include ../../../GDALmake.opt
 OBJ	=	ogrpgdriver.o ogrpgdatasource.o ogrpglayer.o ogrpgtablelayer.o\
 		ogrpgresultlayer.o ogrpgutility.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(PG_INC) $(CPPFLAGS)
+CPPFLAGS	:=	 $(PG_INC) -I../pgdump $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
 clean:
 	rm -f *.o $(O_OBJ)
 
-$(O_OBJ):	ogr_pg.h
\ No newline at end of file
+$(O_OBJ):	ogr_pg.h ogrpgutility.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/pg/drv_pg.html b/ogr/ogrsf_frmts/pg/drv_pg.html
index 386ccda..05bcb15 100644
--- a/ogr/ogrsf_frmts/pg/drv_pg.html
+++ b/ogr/ogrsf_frmts/pg/drv_pg.html
@@ -40,7 +40,10 @@ all regular user tables and named views will be treated as layers.<p>
 
 Starting with GDAL 1.7.0, the driver also supports the
 <a href="http://postgis.refractions.net/documentation/manual-svn/ch04.html#PostGIS_Geography"><i>geography</i></a>
-column type introduced in PostGIS 1.5.
+column type introduced in PostGIS 1.5.<p>
+
+Starting with GDAL 2.0, the driver also supports reading and writing the
+following non-linear geometry types :CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE and MULTISURFACE<p>
 
 <h2>SQL statements</h2>
 
@@ -80,6 +83,15 @@ An alternate way of setting the client encoding is to issue the following SQL co
 with ExecuteSQL() : "SET client_encoding TO encoding_name" where encoding_name is LATIN1, etc.
 Errors can be catched by enclosing this command with a CPLPushErrorHandler()/CPLPopErrorHandler() pair.<p>
 
+<h3>Dataset open options</h3>
+
+(GDAL >= 2.0)
+
+<ul>
+<li> <b>LIST_ALL_TABLES</b>=YES/NO: This may be "YES" to force all tables,
+including non-spatial ones, to be listed.<p>
+</ul>
+
 <h3>Dataset Creation Options</h3>
 
 None<p>
@@ -112,13 +124,17 @@ Using the same layer name in different schemas is supported, but not in the publ
 using the -overwrite option of ogr2ogr and -lco SCHEMA= option at the same time will not work, as the ogr2ogr utility
 will not understand that the existing layer must be destroyed in the specified schema. Use the -nln option of ogr2ogr instead,
 or better the active_schema connection string. See below example.<p>
-<li> <b>SPATIAL_INDEX</b>: (From GDAL 1.6.0) Set to ON by default. Creates a spatial index on the geometry column
-to speed up queries. Set to OFF to disable. (Has effect only when PostGIS is available).<p>
+<li> <b>SPATIAL_INDEX</b>: (From GDAL 1.6.0) Set to YES by default. Creates a spatial index (GiST) on the geometry column
+to speed up queries. Set to FALSE to disable. (Has effect only when PostGIS is available).<p>
 <li> <b>TEMPORARY</b>: (From GDAL 1.8.0) Set to OFF by default. Creates a temporary table instead of a permanent one.<p>
+<li> <b>UNLOGGED</b>: (From GDAL 2.0) Set to OFF by default. Whether to create the table as a unlogged one.
+Unlogged tables are only supported since PostgreSQL 9.1, and GiST indexes used for spatial indexing since PostgreSQL 9.3.<p>
 <li> <b>NONE_AS_UNKNOWN</b>: (From GDAL 1.8.1) Can bet set to TRUE to force non-spatial layers (wkbNone) to be created as
 spatial tables of type GEOMETRY (wkbUnknown), which was the behaviour prior to GDAL 1.8.0. Defaults to NO, in which case
 a regular table is created and not recorded in the PostGIS geometry_columns table.<p>
 <li> <b>FID</b>: (From GDAL 1.9.0) Name of the FID column to create. Defaults to 'ogc_fid'.<p>
+<li> <b>FID64</b>: (From GDAL 2.0) This may be "TRUE" to create a FID column that can support
+64 bit identifiers. The default value is "FALSE".</li>
 <li> <b>EXTRACT_SCHEMA_FROM_LAYER_NAME</b>: (From GDAL 1.9.0) Can be set to NO to avoid considering the dot character
 as the separator between the schema and the table name. Defaults to YES.<p>
 <li> <b>COLUMN_TYPES</b>: (From GDAL 1.10) A list of strings of format field_name=pg_field_type (separated by comma)
@@ -134,13 +150,14 @@ Options</a> which help control the behavior of this driver.<p>
 
 <ul>
 <li><b>PG_USE_COPY</b>: This may be "YES" for using COPY for inserting data to Postgresql.
-COPY is significantly faster than INSERT.</li><p>
+COPY is significantly faster than INSERT. Starting with GDAL 2.0, COPY is used by
+default when inserting from a table that has just been created.</li><p>
 <li><b>PGSQL_OGR_FID</b>: Set name of primary key instead of 'ogc_fid'. Only used when opening a layer whose primary key cannot be autodetected.
 Ignored by CreateLayer() that uses the FID creation option.</li><p>
 <!-- Little interest to advertize PG_USE_TEXT... Just to keep it mind it exists for example for debugging -->
 <!-- <li><b>PG_USE_TEXT</b>: (GDAL >= 1.8.0) If set to "YES", geometries will be fetched as text instead of their default HEXEWKB form.</li></p> -->
 <li><b>PG_USE_BASE64</b>: (GDAL >= 1.8.0) If set to "YES", geometries will be fetched as BASE64 encoded EWKB instead of canonical HEX encoded EWKB.
-This reduces the amount of data to be transfered from 2 N to 1.333 N, where N is the size of EWKB data. However, it might be a
+This reduces the amount of data to be transferred from 2 N to 1.333 N, where N is the size of EWKB data. However, it might be a
 bit slower than fetching in canonical form when the client and the server are on the same machine, so the default is NO.</li><p>
 <li><b>OGR_TRUNCATE</b>: (GDAL >= 1.11) If set to "YES", the content of the table will be first erased with the SQL TRUNCATE command before
 inserting the first feature. This is an alternative to using the -overwrite flag of ogr2ogr,
diff --git a/ogr/ogrsf_frmts/pg/drv_pg_advanced.html b/ogr/ogrsf_frmts/pg/drv_pg_advanced.html
index d66e590..6ac9127 100644
--- a/ogr/ogrsf_frmts/pg/drv_pg_advanced.html
+++ b/ogr/ogrsf_frmts/pg/drv_pg_advanced.html
@@ -116,7 +116,7 @@ mode, will be retrieved from the database and can be obtained with GetFID(). One
 new behaviour is that you must be careful if you re-use the same feature object in a loop that makes
 insertions. After the first iteration, the FID will be set to a non-null value, so at the second iteration,
 CreateFeature() will try to insert the new feature with the FID of the previous feature, which will fail as
-you cannot insert 2 features with same FID. So in that case you must explicitely reset the FID before calling CreateFeature(),
+you cannot insert 2 features with same FID. So in that case you must explicitly reset the FID before calling CreateFeature(),
 or use a fresh feature object.<p>
 
 Snippet example in Python :
@@ -139,24 +139,133 @@ or :
 OGR < 1.8.0 behaviour can be obtained by setting the configuration option OGR_PG_RETRIEVE_FID to FALSE.<p>
 
 
-<h2>Caveats</h2>
+<h2>Issues with transactions</h2>
+
+<p>Note: this section mostly applies to GDAL 2.0, that implements
+<a href="http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions">RFC 54 - Dataset transactions</a>
+Previous versions had different behaviour which made it impractical to handle
+both reading and writing with the same OGR datasource. Reading several layers
+in a interleaved way was also not working properly. The new below behaviour should
+enable more powerful uses, but might cause subtle problems for existing code
+that relied on implicit transactions being regularly flushed by the PG driver in GDAL 1.X</p>
+
+<p>Efficient sequential reading in PostgreSQL requires to be done within a transaction
+(technically this is a CURSOR WITHOUT HOLD).
+So the PG driver will implicitely open such a transaction if none is currently
+opened as soon as a feature is retrieved. This transaction will be released if
+ResetReading() is called (provided that no other layer is still being read).</p>
+
+<p>If within such an implicit transaction, an explicit dataset level StartTransaction()
+is issued, the PG driver will use a SAVEPOINT to emulate properly the transaction
+behaviour while making the active cursor on the read layer still opened.</p>
+
+<p>If an explicit transaction is opened with dataset level StartTransaction()
+before reading a layer, this transaction will be used for the cursor that iterates
+over the layer. When explicitly committing or rolling back the transaction, the
+cursor will become invalid, and ResetReading() should be issued again to restart
+reading from the beginning.</p>
+
+<p>As calling SetAttributeFilter() or SetSpatialFilter() implies an implicit
+ResetReading(), they have the same effect as ResetReading(). That is to say,
+while an implict transaction is in progress, the transaction will be committed
+(if no other layer is being read), and a new one will be started again at the next
+GetNextFeature() call. On the contrary, if they are called within an explicit
+transaction, the transaction is maintained.</p>
+
+<p>With the above rules, the below examples show the SQL instructions that are
+run when using the OGR API in different scenarios.</p>
+<pre>
 
-<ul>
+lyr1->GetNextFeature()             BEGIN (implict)
+                                   DECLARE cur1 CURSOR FOR SELECT * FROM lyr1
+                                   FETCH 1 IN cur1
 
-<li> The type recognition logic is currently somewhat impoverished.
-The types "INT*" and "NUMERIC(width,0)" are mapped to integer, the types
-"FLOAT*" and "NUMERIC(width,precision>0)" are mapped to real, date, time,
-timestamp and datetime are handled as date types and all other
-types are just treated as strings. <p>
+lyr1->SetAttributeFilter('xxx')
+     --> lyr1->ResetReading()      CLOSE cur1
+                                   COMMIT (implicit)
 
-<li> A sequence object called <tablename>_ogc_fid_seq is created for new
-tables (layer)<p>
+lyr1->GetNextFeature()             BEGIN (implict)
+                                   DECLARE cur1 CURSOR  FOR SELECT * FROM lyr1 WHERE xxx
+                                   FETCH 1 IN cur1
 
-<li> Sequential reading is done within a single transaction.  Any attempts
-to write to a layer within a sequential read will likely result in a "BEGIN"
-while already within a transaction type of error message.<p>
+lyr2->GetNextFeature()             DECLARE cur2 CURSOR  FOR SELECT * FROM lyr2
+                                   FETCH 1 IN cur2
 
-</ul>
+lyr1->GetNextFeature()             FETCH 1 IN cur1
+
+lyr2->GetNextFeature()             FETCH 1 IN cur2
+
+lyr1->CreateFeature(f)             INSERT INTO cur1 ...
+
+lyr1->SetAttributeFilter('xxx')
+     --> lyr1->ResetReading()      CLOSE cur1
+                                   COMMIT (implicit)
+
+lyr1->GetNextFeature()             DECLARE cur1 CURSOR  FOR SELECT * FROM lyr1 WHERE xxx
+                                   FETCH 1 IN cur1
+
+lyr1->ResetReading()               CLOSE cur1
+
+lyr2->ResetReading()               CLOSE cur2
+                                   COMMIT (implicit)
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ds->StartTransaction()             BEGIN
+
+lyr1->GetNextFeature()             DECLARE cur1 CURSOR FOR SELECT * FROM lyr1
+                                   FETCH 1 IN cur1
+
+lyr2->GetNextFeature()             DECLARE cur2 CURSOR FOR SELECT * FROM lyr2
+                                   FETCH 1 IN cur2
+
+lyr1->CreateFeature(f)             INSERT INTO cur1 ...
+
+lyr1->SetAttributeFilter('xxx')
+     --> lyr1->ResetReading()      CLOSE cur1
+                                   COMMIT (implicit)
+
+lyr1->GetNextFeature()             DECLARE cur1 CURSOR  FOR SELECT * FROM lyr1 WHERE xxx
+                                   FETCH 1 IN cur1
+
+lyr1->ResetReading()               CLOSE cur1
+
+lyr2->ResetReading()               CLOSE cur2
+
+ds->CommitTransaction()            COMMIT
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ds->StartTransaction()             BEGIN
+
+lyr1->GetNextFeature()             DECLARE cur1 CURSOR FOR SELECT * FROM lyr1
+                                   FETCH 1 IN cur1
+
+lyr1->CreateFeature(f)             INSERT INTO cur1 ...
+
+ds->CommitTransaction()            CLOSE cur1 (implicit)
+                                   COMMIT
+
+lyr1->GetNextFeature()             FETCH 1 IN cur1      ==> Error since the cursor was closed with the commit. Explicit ResetReading() required before
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+lyr1->GetNextFeature()             BEGIN (implicit)
+                                   DECLARE cur1 CURSOR FOR SELECT * FROM lyr1
+                                   FETCH 1 IN cur1
+
+ds->StartTransaction()             SAVEPOINT savepoint
+
+lyr1->CreateFeature(f)             INSERT INTO cur1 ...
+
+ds->CommitTransaction()            RELEASE SAVEPOINT savepoint
+
+lyr1->ResetReading()               CLOSE cur1
+                                   COMMIT (implicit)
+</pre>
+
+<p>Note: in reality, the PG drivers fetches 500 features at once. The FETCH 1
+is for clarity of the explanation.</p>
 
 
 <h3>Advanced Examples</h3>
@@ -251,4 +360,4 @@ ogr2ogr -overwrite -f PostgreSQL "PG:dbname=warmerda active_schema=apt200810" ap
 <li> <a href="drv_pg.html">OGR PostgreSQL driver Information</a><p>
 </ul>
 
-</html>
\ No newline at end of file
+</html>
diff --git a/ogr/ogrsf_frmts/pg/makefile.vc b/ogr/ogrsf_frmts/pg/makefile.vc
index 4cf0608..446b6f0 100644
--- a/ogr/ogrsf_frmts/pg/makefile.vc
+++ b/ogr/ogrsf_frmts/pg/makefile.vc
@@ -8,7 +8,7 @@ GDAL_ROOT	=	..\..\..
 
 !INCLUDE $(GDAL_ROOT)\nmake.opt
 
-EXTRAFLAGS = -I.. -I..\.. -I$(PG_INC_DIR)
+EXTRAFLAGS = -I.. -I..\.. -I..\pgdump -I$(PG_INC_DIR)
 
 default:	$(OBJ)
 
diff --git a/ogr/ogrsf_frmts/pg/ogr_pg.h b/ogr/ogrsf_frmts/pg/ogr_pg.h
index e0aefc2..a35d14e 100644
--- a/ogr/ogrsf_frmts/pg/ogr_pg.h
+++ b/ogr/ogrsf_frmts/pg/ogr_pg.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_pg.h 27106 2014-03-28 11:59:57Z rouault $
+ * $Id: ogr_pg.h 28988 2015-04-24 11:58:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/PostgreSQL driver.
@@ -36,6 +36,7 @@
 #include "cpl_string.h"
 
 #include "ogrpgutility.h"
+#include "ogr_pgdump.h"
 
 /* These are the OIDs for some builtin types, as returned by PQftype(). */
 /* They were copied from pg_type.h in src/include/catalog/pg_type.h */
@@ -57,10 +58,12 @@
 #define OIDVECTOROID            30
 #define FLOAT4OID               700
 #define FLOAT8OID               701
+#define BOOLARRAYOID            1000
 #define INT4ARRAYOID            1007
 #define TEXTARRAYOID            1009
 #define BPCHARARRAYOID          1014
 #define VARCHARARRAYOID         1015
+#define INT8ARRAYOID            1016
 #define FLOAT4ARRAYOID          1021
 #define FLOAT8ARRAYOID          1022
 #define BPCHAROID		1042
@@ -97,6 +100,7 @@ typedef struct
     int   nCoordDimension;
     int   nSRID;
     PostgisType   ePostgisType;
+    int   bNullable;
 } PGGeomColumnDesc;
 
 /************************************************************************/
@@ -159,12 +163,13 @@ class OGRPGLayer : public OGRLayer
   protected:
     OGRPGFeatureDefn   *poFeatureDefn;
 
-    int                 iNextShapeId;
+    int                 nCursorPage;
+    GIntBig             iNextShapeId;
 
     static char        *GByteArrayToBYTEA( const GByte* pabyData, int nLen);
-    static char        *GeometryToBYTEA( OGRGeometry * );
+    static char        *GeometryToBYTEA( OGRGeometry *, int bIsPostGIS1 );
     static GByte       *BYTEAToGByteArray( const char *pszBytea, int* pnLength );
-    static OGRGeometry *BYTEAToGeometry( const char * );
+    static OGRGeometry *BYTEAToGeometry( const char *, int bIsPostGIS1 );
     Oid                 GeometryToOID( OGRGeometry * );
     OGRGeometry        *OIDToGeometry( Oid );
 
@@ -174,17 +179,17 @@ class OGRPGLayer : public OGRLayer
 
     char               *pszCursorName;
     PGresult           *hCursorResult;
+    int                 bInvalidated;
 
     int                 nResultOffset;
 
     int                 bWkbAsOid;
 
-    int                 bHasFid;
     char                *pszFIDColumn;
 
     int                 bCanUseBinaryCursor;
-    int                *panMapFieldNameToIndex;
-    int                *panMapFieldNameToGeomIndex;
+    int                *m_panMapFieldNameToIndex;
+    int                *m_panMapFieldNameToGeomIndex;
 
     int                 ParsePGDate( const char *, OGRField * );
 
@@ -193,12 +198,18 @@ class OGRPGLayer : public OGRLayer
 
     virtual CPLString   GetFromClauseForGetExtent() = 0;
     OGRErr              RunGetExtentRequest( OGREnvelope *psExtent, int bForce,
-                                             CPLString osCommand);
-    void                CreateMapFromFieldNameToIndex();
+                                             CPLString osCommand, int bErrorAsDebug );
+    static void         CreateMapFromFieldNameToIndex(PGresult* hResult,
+                                                      OGRFeatureDefn* poFeatureDefn,
+                                                      int*& panMapFieldNameToIndex,
+                                                      int*& panMapFieldNameToGeomIndex);
 
     int                 ReadResultDefinition(PGresult *hInitialResultIn);
 
-    OGRFeature         *RecordToFeature( int iRecord );
+    OGRFeature         *RecordToFeature( PGresult* hResult,
+                                         const int* panMapFieldNameToIndex,
+                                         const int* panMapFieldNameToGeomIndex,
+                                         int iRecord );
     OGRFeature         *GetNextRawFeature();
 
   public:
@@ -217,9 +228,11 @@ class OGRPGLayer : public OGRLayer
     virtual OGRErr      CommitTransaction();
     virtual OGRErr      RollbackTransaction();
 
+    void                InvalidateCursor();
+
     virtual const char *GetFIDColumn();
 
-    virtual OGRErr      SetNextByIndex( long nIndex );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
     
     OGRPGDataSource    *GetDS() { return poDS; }
 
@@ -264,11 +277,8 @@ class OGRPGTableLayer : public OGRPGLayer
 
     OGRErr		CreateFeatureViaCopy( OGRFeature *poFeature );
     OGRErr		CreateFeatureViaInsert( OGRFeature *poFeature );
-    CPLString           BuildCopyFields(int bSetFID);
+    CPLString           BuildCopyFields();
 
-    void                AppendFieldValue(PGconn *hPGConn, CPLString& osCommand,
-                                         OGRFeature* poFeature, int i);
-                  
     int                 bHasWarnedIncompatibleGeom;
     void                CheckGeomTypeCompatibility(int iGeomField, OGRGeometry* poGeom);
 
@@ -280,8 +290,19 @@ class OGRPGTableLayer : public OGRPGLayer
     int                 nForcedDimension;
     int                 bCreateSpatialIndexFlag;
     int                 bInResetReading;
+    
+    int                 bAutoFIDOnCreateViaCopy;
+    int                 bUseCopyByDefault;
+    
+    int                 bDifferedCreation;
+    CPLString           osCreateTable;
+    
+    int                 iFIDAsRegularColumnIndex;
 
     virtual CPLString   GetFromClauseForGetExtent() { return pszSqlTableName; }
+    
+    OGRErr              RunAddGeometryColumn( OGRPGGeomFieldDefn *poGeomField );
+    OGRErr              RunCreateSpatialIndex( OGRPGGeomFieldDefn *poGeomField );
 
 public:
                         OGRPGTableLayer( OGRPGDataSource *,
@@ -295,19 +316,19 @@ public:
     void                SetGeometryInformation(PGGeomColumnDesc* pasDesc,
                                                int nGeomFieldCount);
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry *poGeom ) { SetSpatialFilter(0, poGeom); }
     virtual void        SetSpatialFilter( int iGeomField, OGRGeometry *poGeom );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
@@ -334,11 +355,17 @@ public:
 
     void                SetOverrideColumnTypes( const char* pszOverrideColumnTypes );
 
-    virtual OGRErr      StartCopy(int bSetFID);
-    virtual OGRErr      EndCopy();
+    OGRErr              StartCopy();
+    OGRErr              EndCopy();
 
     int                 ReadTableDefinition();
     int                 HasGeometryInformation() { return bGeometryInformationSet; }
+    void                SetTableDefinition(const char* pszFIDColumnName,
+                                           const char* pszGFldName,
+                                           OGRwkbGeometryType eType,
+                                           const char* pszGeomType,
+                                           int nSRSId,
+                                           int nCoordDimension);
 
     void                SetForcedSRSId( int nForcedSRSIdIn )
                                 { nForcedSRSId = nForcedSRSIdIn; }
@@ -346,6 +373,11 @@ public:
                                 { nForcedDimension = nForcedDimensionIn; }
     void                SetCreateSpatialIndexFlag( int bFlag )
                                 { bCreateSpatialIndexFlag = bFlag; }
+    void                AllowAutoFIDOnCreateViaCopy() { bAutoFIDOnCreateViaCopy = TRUE; }
+    void                SetUseCopy() { bUseCopy = TRUE; bUseCopyByDefault = TRUE; }
+
+    void                SetDifferedCreation(int bDifferedCreationIn, CPLString osCreateTable);
+    OGRErr              RunDifferedCreationIfNecessary();
 
     virtual void        ResolveSRID(OGRPGGeomFieldDefn* poGFldDefn);
 };
@@ -376,7 +408,7 @@ class OGRPGResultLayer : public OGRPGLayer
     virtual             ~OGRPGResultLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry *poGeom ) { SetSpatialFilter(0, poGeom); }
     virtual void        SetSpatialFilter( int iGeomField, OGRGeometry *poGeom );
@@ -410,6 +442,8 @@ class OGRPGDataSource : public OGRDataSource
     int                 bHavePostGIS;
     int                 bHaveGeography;
 
+    int                 bUserTransactionActive;
+    int                 bSavePointActive;
     int                 nSoftTransactionLevel;
 
     PGconn              *hPGConn;
@@ -433,6 +467,18 @@ class OGRPGDataSource : public OGRDataSource
     CPLString           GetCurrentSchema();
 
     int                 nUndefinedSRID;
+    
+    char               *pszForcedTables;
+    char              **papszSchemaList;
+    int                 bHasLoadTables;
+    CPLString           osActiveSchema;
+    int                 bListAllTables;
+    void                LoadTables();
+
+    CPLString           osDebugLastTransactionCommand;
+    OGRErr              DoTransactionCommand(const char* pszCommand);
+
+    OGRErr              FlushSoftTransaction();
 
   public:
     PGver               sPostgreSQLVersion;
@@ -454,7 +500,8 @@ class OGRPGDataSource : public OGRDataSource
     OGRSpatialReference *FetchSRS( int nSRSId );
     OGRErr              InitializeMetadataTables();
 
-    int                 Open( const char *, int bUpdate, int bTestOpen );
+    int                 Open( const char *, int bUpdate, int bTestOpen,
+                              char** papszOpenOptions );
     OGRPGTableLayer*    OpenTable( CPLString& osCurrentSchema,
                                    const char * pszTableName,
                                    const char * pszSchemaName,
@@ -462,22 +509,26 @@ class OGRPGDataSource : public OGRDataSource
                                    int bUpdate, int bTestOpen );
 
     const char          *GetName() { return pszName; }
-    int                 GetLayerCount() { return nLayers; }
+    int                 GetLayerCount();
     OGRLayer            *GetLayer( int );
     OGRLayer            *GetLayerByName(const char * pszName);
+    
+    virtual void        FlushCache(void);
 
-    virtual OGRLayer    *CreateLayer( const char *,
+    virtual OGRLayer    *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
 
     int                 TestCapability( const char * );
 
-    OGRErr              SoftStartTransaction();
-    OGRErr              SoftCommit();
-    OGRErr              SoftRollback();
+    virtual OGRErr      StartTransaction(int bForce = FALSE);
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
 
-    OGRErr              FlushSoftTransaction();
+    OGRErr              SoftStartTransaction();
+    OGRErr              SoftCommitTransaction();
+    OGRErr              SoftRollbackTransaction();
 
     Oid                 GetGeometryOID() { return nGeometryOID; }
     Oid                 GetGeographyOID() { return nGeographyOID; }
@@ -487,30 +538,12 @@ class OGRPGDataSource : public OGRDataSource
                                     const char *pszDialect );
     virtual void        ReleaseResultSet( OGRLayer * poLayer );
 
-    char               *LaunderName( const char * );
+    virtual const char* GetMetadataItem(const char* pszKey,
+                                             const char* pszDomain);
 
     int                 UseCopy();
     void                StartCopy( OGRPGTableLayer *poPGLayer );
     OGRErr              EndCopy( );
-    int                 CopyInProgress( );
-};
-
-/************************************************************************/
-/*                             OGRPGDriver                              */
-/************************************************************************/
-
-class OGRPGDriver : public OGRSFDriver
-{
-  public:
-                ~OGRPGDriver();
-
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-
-    int                 TestCapability( const char * );
 };
 
 #endif /* ndef _OGR_PG_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp b/ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp
index a4e01ef..deccd70 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDataSource class.
@@ -37,7 +37,7 @@
 
 #define PQexec this_is_an_error
 
-CPL_CVSID("$Id: ogrpgdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgdatasource.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
 static void OGRPGNoticeProcessor( void *arg, const char * pszMessage );
 
@@ -56,6 +56,8 @@ OGRPGDataSource::OGRPGDataSource()
     bHavePostGIS = FALSE;
     bHaveGeography = FALSE;
     bUseBinaryCursor = FALSE;
+    bUserTransactionActive = FALSE;
+    bSavePointActive = FALSE;
     nSoftTransactionLevel = 0;
     bBinaryTimeFormatIsInt8 = FALSE;
     bUseEscapeStringSyntax = FALSE;
@@ -69,6 +71,11 @@ OGRPGDataSource::OGRPGDataSource()
 
     poLayerInCopyMode = NULL;
     nUndefinedSRID = -1; /* actual value will be autotected if PostGIS >= 2.0 detected */
+
+    pszForcedTables = NULL;
+    papszSchemaList = NULL;
+    bListAllTables = FALSE;
+    bHasLoadTables = FALSE;
 }
 
 /************************************************************************/
@@ -84,6 +91,8 @@ OGRPGDataSource::~OGRPGDataSource()
 
     CPLFree( pszName );
     CPLFree( pszDBName );
+    CPLFree( pszForcedTables );
+    CSLDestroy( papszSchemaList );
 
     for( i = 0; i < nLayers; i++ )
         delete papoLayers[i];
@@ -109,6 +118,19 @@ OGRPGDataSource::~OGRPGDataSource()
 }
 
 /************************************************************************/
+/*                              FlushCache()                            */
+/************************************************************************/
+
+void OGRPGDataSource::FlushCache(void)
+{
+    EndCopy();
+    for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+    {
+        papoLayers[iLayer]->RunDifferedCreationIfNecessary();
+    }
+}
+
+/************************************************************************/
 /*                         GetCurrentSchema()                           */
 /************************************************************************/
 
@@ -221,7 +243,8 @@ static void OGRPGTableEntryAddGeomColumn(PGTableEntry* psTableEntry,
                                          const char* pszGeomType = NULL,
                                          int nCoordDimension = 0,
                                          int nSRID = UNDETERMINED_SRID,
-                                         PostgisType ePostgisType = GEOM_TYPE_UNKNOWN)
+                                         PostgisType ePostgisType = GEOM_TYPE_UNKNOWN,
+                                         int bNullable = TRUE)
 {
     psTableEntry->pasGeomColumns = (PGGeomColumnDesc*)
         CPLRealloc(psTableEntry->pasGeomColumns,
@@ -233,6 +256,7 @@ static void OGRPGTableEntryAddGeomColumn(PGTableEntry* psTableEntry,
     /* the SRID is truly set to 0, but also when there's no constraint */
     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].nSRID = nSRID > 0 ? nSRID : UNDETERMINED_SRID;
     psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].ePostgisType = ePostgisType;
+    psTableEntry->pasGeomColumns[psTableEntry->nGeomColumnCount].bNullable = bNullable;
     psTableEntry->nGeomColumnCount ++;
 }
 
@@ -244,7 +268,8 @@ static void OGRPGTableEntryAddGeomColumn(PGTableEntry* psTableEntry,
                                  psGeomColumnDesc->pszGeomType,
                                  psGeomColumnDesc->nCoordDimension,
                                  psGeomColumnDesc->nSRID,
-                                 psGeomColumnDesc->ePostgisType);
+                                 psGeomColumnDesc->ePostgisType,
+                                 psGeomColumnDesc->bNullable);
 }
 
 static void OGRPGFreeTableEntry(void * _psTableEntry)
@@ -290,7 +315,7 @@ static PGTableEntry* OGRPGAddTableEntry(CPLHashSet* hSetTables,
 /************************************************************************/
 
 int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
-                              int bTestOpen )
+                           int bTestOpen, char** papszOpenOptions )
 
 {
     CPLAssert( nLayers == 0 );
@@ -314,14 +339,31 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
     }
 
     pszName = CPLStrdup( pszNewName );
-    char* pszConnectionName = CPLStrdup(pszName);
+    
+    CPLString osConnectionName(pszName);
+    const char* apszOpenOptions[] = { "dbname", "port", "user", "password",
+                                      "host", "active_schema", "schemas", "tables" };
+    for(int i=0; i <(int)(sizeof(apszOpenOptions)/sizeof(char*));i++)
+    {
+        const char* pszVal = CSLFetchNameValue(papszOpenOptions, apszOpenOptions[i]);
+        if( pszVal )
+        {
+            if( osConnectionName[osConnectionName.size()-1] != ':' )
+                osConnectionName += " ";
+            osConnectionName += apszOpenOptions[i];
+            osConnectionName += "=";
+            osConnectionName += pszVal;
+        }
+    }
+    
+    char* pszConnectionName = CPLStrdup(osConnectionName);
+    
 
 /* -------------------------------------------------------------------- */
 /*      Determine if the connection string contains an optional         */
 /*      ACTIVE_SCHEMA portion. If so, parse it out.                     */
 /* -------------------------------------------------------------------- */
     char             *pszActiveSchemaStart;
-    CPLString         osActiveSchema;
     pszActiveSchemaStart = strstr(pszConnectionName, "active_schema=");
     if (pszActiveSchemaStart == NULL)
         pszActiveSchemaStart = strstr(pszConnectionName, "ACTIVE_SCHEMA=");
@@ -354,7 +396,6 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
 /*      SCHEMAS portion. If so, parse it out.                           */
 /* -------------------------------------------------------------------- */
     char             *pszSchemasStart;
-    char            **papszSchemaList = NULL;
     pszSchemasStart = strstr(pszConnectionName, "schemas=");
     if (pszSchemasStart == NULL)
         pszSchemasStart = strstr(pszConnectionName, "SCHEMAS=");
@@ -395,8 +436,6 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
 /*      We must also strip this information from the connection         */
 /*      string; PQconnectdb() does not like unknown directives          */
 /* -------------------------------------------------------------------- */
-    PGTableEntry **papsTables = NULL;
-    int            nTableCount = 0;
 
     char             *pszTableStart;
     pszTableStart = strstr(pszConnectionName, "tables=");
@@ -405,12 +444,9 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
 
     if( pszTableStart != NULL )
     {
-        char          **papszTableList;
-        char           *pszTableSpec;
         const char     *pszEnd = NULL;
-        int             i;
 
-        pszTableSpec = CPLStrdup( pszTableStart + 7 );
+        pszForcedTables = CPLStrdup( pszTableStart + 7 );
 
         pszEnd = strchr(pszTableStart, ' ');
         if( pszEnd == NULL )
@@ -419,64 +455,12 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         // Remove TABLES=xxxxx from pszConnectionName string
         memmove( pszTableStart, pszEnd, strlen(pszEnd) + 1 );
 
-        pszTableSpec[pszEnd - pszTableStart - 7] = '\0';
-        papszTableList = CSLTokenizeString2( pszTableSpec, ",", 0 );
-
-        for( i = 0; i < CSLCount(papszTableList); i++ )
-        {
-            char      **papszQualifiedParts;
-
-            // Get schema and table name
-            papszQualifiedParts = CSLTokenizeString2( papszTableList[i],
-                                                      ".", 0 );
-            int nParts = CSLCount( papszQualifiedParts );
-
-            if( nParts == 1 || nParts == 2 )
-            {
-                /* Find the geometry column name if specified */
-                char* pszGeomColumnName = NULL;
-                char* pos = strchr(papszQualifiedParts[CSLCount( papszQualifiedParts ) - 1], '(');
-                if (pos != NULL)
-                {
-                    *pos = '\0';
-                    pszGeomColumnName = pos+1;
-                    int len = strlen(pszGeomColumnName);
-                    if (len > 0)
-                        pszGeomColumnName[len - 1] = '\0';
-                }
-
-                papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
-                papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
-                if (pszGeomColumnName)
-                    OGRPGTableEntryAddGeomColumn(papsTables[nTableCount], pszGeomColumnName);
-
-                if( nParts == 2 )
-                {
-                    papsTables[nTableCount]->pszSchemaName = CPLStrdup( papszQualifiedParts[0] );
-                    papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[1] );
-                }
-                else
-                {
-                    papsTables[nTableCount]->pszSchemaName = CPLStrdup( osActiveSchema.c_str());
-                    papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[0] );
-                }
-                nTableCount ++;
-            }
-
-            CSLDestroy(papszQualifiedParts);
-        }
-
-        CSLDestroy(papszTableList);
-        CPLFree(pszTableSpec);
+        pszForcedTables[pszEnd - pszTableStart - 7] = '\0';
     }
 
 
     CPLString      osCurrentSchema;
-    CPLHashSet    *hSetTables = NULL;
-    int            bRet = FALSE;
-    int            bListAllTables = CSLTestBoolean(CPLGetConfigOption("PG_LIST_ALL_TABLES", "NO"));
     PGresult      *hResult = NULL;
-    std::set<CPLString> osRegisteredLayers;
 
 /* -------------------------------------------------------------------- */
 /*      Try to establish connection.                                    */
@@ -494,7 +478,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         PQfinish(hPGConn);
         hPGConn = NULL;
 
-        goto end;
+        return FALSE;
     }
 
     bDSUpdate = bUpdate;
@@ -566,7 +550,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
                 CPLError( CE_Failure, CPLE_AppDefined,
                         "%s", PQerrorMessage(hPGConn) );
 
-                goto end;
+                return FALSE;
             }
         }
 
@@ -672,7 +656,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         hResult = OGRPG_PQexec(hPGConn, "CLOSE gettimebinaryformat");
         OGRPGClearResult( hResult );
 
-        SoftCommit();
+        SoftCommitTransaction();
     }
 #endif
 
@@ -778,60 +762,267 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
     else
         nUndefinedSRID = -1;
 
+    osCurrentSchema = GetCurrentSchema();
+
+    bListAllTables = CSLTestBoolean(CSLFetchNameValueDef(
+        papszOpenOptions, "LIST_ALL_TABLES",
+        CPLGetConfigOption("PG_LIST_ALL_TABLES", "NO")));
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                            LoadTables()                              */
+/************************************************************************/
+
+void OGRPGDataSource::LoadTables()
+{
+    if( bHasLoadTables )
+        return;
+    bHasLoadTables = TRUE;
+
+    PGresult            *hResult;
+    PGTableEntry **papsTables = NULL;
+    int            nTableCount = 0;
+    CPLHashSet    *hSetTables = NULL;
+    std::set<CPLString> osRegisteredLayers;
+
+    int i;
+    for( i = 0; i < nLayers; i++) 
+    {
+        osRegisteredLayers.insert(papoLayers[i]->GetName());
+    }
+
+    if( pszForcedTables )
+    {
+        char          **papszTableList;
+
+        papszTableList = CSLTokenizeString2( pszForcedTables, ",", 0 );
+
+        for( i = 0; i < CSLCount(papszTableList); i++ )
+        {
+            char      **papszQualifiedParts;
+
+            // Get schema and table name
+            papszQualifiedParts = CSLTokenizeString2( papszTableList[i],
+                                                      ".", 0 );
+            int nParts = CSLCount( papszQualifiedParts );
+
+            if( nParts == 1 || nParts == 2 )
+            {
+                /* Find the geometry column name if specified */
+                char* pszGeomColumnName = NULL;
+                char* pos = strchr(papszQualifiedParts[CSLCount( papszQualifiedParts ) - 1], '(');
+                if (pos != NULL)
+                {
+                    *pos = '\0';
+                    pszGeomColumnName = pos+1;
+                    int len = strlen(pszGeomColumnName);
+                    if (len > 0)
+                        pszGeomColumnName[len - 1] = '\0';
+                }
+
+                papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
+                papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
+                if (pszGeomColumnName)
+                    OGRPGTableEntryAddGeomColumn(papsTables[nTableCount], pszGeomColumnName);
+
+                if( nParts == 2 )
+                {
+                    papsTables[nTableCount]->pszSchemaName = CPLStrdup( papszQualifiedParts[0] );
+                    papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[1] );
+                }
+                else
+                {
+                    papsTables[nTableCount]->pszSchemaName = CPLStrdup( osActiveSchema.c_str());
+                    papsTables[nTableCount]->pszTableName = CPLStrdup( papszQualifiedParts[0] );
+                }
+                nTableCount ++;
+            }
+
+            CSLDestroy(papszQualifiedParts);
+        }
+
+        CSLDestroy(papszTableList);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Get a list of available tables if they have not been            */
 /*      specified through the TABLES connection string param           */
 /* -------------------------------------------------------------------- */
+    const char* pszAllowedRelations;
+    if( CSLTestBoolean(CPLGetConfigOption("PG_SKIP_VIEWS", "NO")) )
+        pszAllowedRelations = "'r'";
+    else
+        pszAllowedRelations = "'r','v','m','f'";
 
     hSetTables = CPLHashSetNew(OGRPGHashTableEntry, OGRPGEqualTableEntry, OGRPGFreeTableEntry);
 
-    if (nTableCount == 0)
+    if( nTableCount == 0 && bHavePostGIS && sPostGISVersion.nMajor >= 2 &&
+        !bListAllTables &&
+        /* Config option mostly for comparison/debugging/etc... */
+        CSLTestBoolean(CPLGetConfigOption("PG_USE_POSTGIS2_OPTIM", "YES")) )
     {
+/* -------------------------------------------------------------------- */
+/*      With PostGIS 2.0, the geometry_columns and geography_columns    */
+/*      are views, based on the catalog system, that can be slow to     */
+/*      query, so query directly the catalog system.                    */
+/*      See http://trac.osgeo.org/postgis/ticket/3092                   */
+/* -------------------------------------------------------------------- */
         CPLString osCommand;
-        const char* pszAllowedRelations;
-        if( CSLTestBoolean(CPLGetConfigOption("PG_SKIP_VIEWS", "NO")) )
-            pszAllowedRelations = "'r'";
-        else
-            pszAllowedRelations = "'r','v'";
-        
-        hResult = OGRPG_PQexec(hPGConn, "BEGIN");
+        osCommand.Printf(
+              "SELECT c.relname, n.nspname, c.relkind, a.attname, t.typname, "
+              "postgis_typmod_dims(a.atttypmod) dim, "
+              "postgis_typmod_srid(a.atttypmod) srid, "
+              "postgis_typmod_type(a.atttypmod)::text geomtyp, "
+              "array_agg(s.consrc)::text att_constraints, a.attnotnull "
+              "FROM pg_class c JOIN pg_attribute a ON a.attrelid=c.oid "
+              "JOIN pg_namespace n ON c.relnamespace = n.oid "
+              "AND c.relkind in (%s) AND NOT ( n.nspname = 'public' AND c.relname = 'raster_columns' ) "
+              "JOIN pg_type t ON a.atttypid = t.oid AND (t.typname = 'geometry'::name OR t.typname = 'geography'::name) "
+              "LEFT JOIN pg_constraint s ON s.connamespace = n.oid AND s.conrelid = c.oid "
+              "AND a.attnum = ANY (s.conkey) "
+              "AND (s.consrc LIKE '%%geometrytype(%% = %%' OR s.consrc LIKE '%%ndims(%% = %%' OR s.consrc LIKE '%%srid(%% = %%') "
+              "GROUP BY c.relname, n.nspname, c.relkind, a.attname, t.typname, dim, srid, geomtyp, a.attnotnull, c.oid, a.attnum "
+              "ORDER BY c.oid, a.attnum",
+              pszAllowedRelations);
+        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
 
-        if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
+        if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
         {
             OGRPGClearResult( hResult );
 
-            /* Caution : in PostGIS case, the result has 3 columns, whereas in the */
-            /* non-PostGIS case it has only 2 columns */
-            if ( bHavePostGIS && !bListAllTables )
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s", PQerrorMessage(hPGConn) );
+            goto end;
+        }
+    /* -------------------------------------------------------------------- */
+    /*      Parse the returned table list                                   */
+    /* -------------------------------------------------------------------- */
+        for( int iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
+        {
+            const char *pszTable = PQgetvalue(hResult, iRecord, 0);
+            const char *pszSchemaName = PQgetvalue(hResult, iRecord, 1);
+            const char *pszGeomColumnName = PQgetvalue(hResult, iRecord, 3);
+            const char *pszGeomOrGeography = PQgetvalue(hResult, iRecord, 4);
+            const char *pszDim = PQgetvalue(hResult, iRecord, 5);
+            const char *pszSRID = PQgetvalue(hResult, iRecord, 6);
+            const char *pszGeomType = PQgetvalue(hResult, iRecord, 7);
+            const char *pszConstraint = PQgetvalue(hResult, iRecord, 8);
+            const char *pszNotNull = PQgetvalue(hResult, iRecord, 9);
+            /*const char *pszRelkind = PQgetvalue(hResult, iRecord, 2);
+            CPLDebug("PG", "%s %s %s %s %s %s %s %s %s %s",
+                     pszTable, pszSchemaName, pszRelkind,
+                     pszGeomColumnName, pszGeomOrGeography, pszDim,
+                     pszSRID, pszGeomType, pszConstraint, pszNotNull);*/
+
+            int bNullable = EQUAL(pszNotNull, "f");
+
+            PostgisType ePostgisType = GEOM_TYPE_UNKNOWN;
+            if( EQUAL(pszGeomOrGeography, "geometry") )
+                ePostgisType = GEOM_TYPE_GEOMETRY;
+            else if( EQUAL(pszGeomOrGeography, "geography") )
+                ePostgisType = GEOM_TYPE_GEOGRAPHY;
+
+            int nGeomCoordDimension = atoi(pszDim);
+            int nSRID = atoi(pszSRID);
+
+            /* Analyze constraints that might override geometrytype, */
+            /* coordinate dimension and SRID */
+            CPLString osConstraint(pszConstraint);
+            osConstraint = osConstraint.tolower();
+            pszConstraint = osConstraint.c_str();
+            const char* pszNeedle = strstr(pszConstraint, "geometrytype(");
+            CPLString osGeometryType;
+            if( pszNeedle )
+            {
+                pszNeedle = strchr(pszNeedle, '\'');
+                if( pszNeedle )
+                {
+                    pszNeedle ++;
+                    const char* pszEnd = strchr(pszNeedle, '\'');
+                    if( pszEnd )
+                    {
+                        osGeometryType = pszNeedle;
+                        osGeometryType.resize(pszEnd - pszNeedle);
+                        pszGeomType = osGeometryType.c_str();
+                    }
+                }
+            }
+
+            pszNeedle = strstr(pszConstraint, "srid(");
+            if( pszNeedle )
             {
-                osCommand.Printf("DECLARE mycursor CURSOR for "
-                                 "SELECT c.relname, n.nspname, c.relkind, g.f_geometry_column, g.type, g.coord_dimension, g.srid, %d, c.oid as oid, a.attnum as attnum FROM pg_class c, pg_namespace n, geometry_columns g, pg_attribute a "
-                                 "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
-                                 "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema AND a.attname = g.f_geometry_column AND a.attrelid = c.oid) ",
-                                 GEOM_TYPE_GEOMETRY, pszAllowedRelations);
-
-                if (bHaveGeography)
-                    osCommand += CPLString().Printf(
-                                     "UNION SELECT c.relname, n.nspname, c.relkind, g.f_geography_column, g.type, g.coord_dimension, g.srid, %d, c.oid as oid, a.attnum as attnum FROM pg_class c, pg_namespace n, geography_columns g, pg_attribute a "
-                                     "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
-                                     "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema AND a.attname = g.f_geography_column AND a.attrelid = c.oid)",
-                                     GEOM_TYPE_GEOGRAPHY, pszAllowedRelations);
-                osCommand += " ORDER BY oid, attnum";
+                pszNeedle = strchr(pszNeedle, '=');
+                if( pszNeedle )
+                {
+                    pszNeedle ++;
+                    nSRID = atoi(pszNeedle);
+                }
             }
-            else
-                osCommand.Printf("DECLARE mycursor CURSOR for "
-                                 "SELECT c.relname, n.nspname, c.relkind FROM pg_class c, pg_namespace n "
-                                 "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid)",
-                                 pszAllowedRelations);
-                                
-            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+
+            pszNeedle = strstr(pszConstraint, "ndims(");
+            if( pszNeedle )
+            {
+                pszNeedle = strchr(pszNeedle, '=');
+                if( pszNeedle )
+                {
+                    pszNeedle ++;
+                    nGeomCoordDimension = atoi(pszNeedle);
+                }
+            }
+
+            papsTables = (PGTableEntry**)CPLRealloc(papsTables, sizeof(PGTableEntry*) * (nTableCount + 1));
+            papsTables[nTableCount] = (PGTableEntry*) CPLCalloc(1, sizeof(PGTableEntry));
+            papsTables[nTableCount]->pszTableName = CPLStrdup( pszTable );
+            papsTables[nTableCount]->pszSchemaName = CPLStrdup( pszSchemaName );
+
+            OGRPGTableEntryAddGeomColumn(papsTables[nTableCount],
+                                            pszGeomColumnName,
+                                            pszGeomType, nGeomCoordDimension,
+                                            nSRID, ePostgisType, bNullable);
+            nTableCount ++;
+
+            PGTableEntry* psEntry = OGRPGFindTableEntry(hSetTables, pszTable, pszSchemaName);
+            if (psEntry == NULL)
+                psEntry = OGRPGAddTableEntry(hSetTables, pszTable, pszSchemaName);
+            OGRPGTableEntryAddGeomColumn(psEntry,
+                                            pszGeomColumnName,
+                                            pszGeomType,
+                                            nGeomCoordDimension,
+                                            nSRID, ePostgisType, bNullable);
         }
 
-        if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
+        OGRPGClearResult( hResult );
+    }
+    else if (nTableCount == 0)
+    {
+        CPLString osCommand;
+
+        /* Caution : in PostGIS case, the result has 11 columns, whereas in the */
+        /* non-PostGIS case it has only 3 columns */
+        if ( bHavePostGIS && !bListAllTables )
         {
-            OGRPGClearResult( hResult );
-            hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
+            osCommand.Printf(   "SELECT c.relname, n.nspname, c.relkind, g.f_geometry_column, g.type, g.coord_dimension, g.srid, %d, a.attnotnull, c.oid as oid, a.attnum as attnum FROM pg_class c, pg_namespace n, geometry_columns g, pg_attribute a "
+                                "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
+                                "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema AND a.attname = g.f_geometry_column AND a.attrelid = c.oid) ",
+                                GEOM_TYPE_GEOMETRY, pszAllowedRelations);
+
+            if (bHaveGeography)
+                osCommand += CPLString().Printf(
+                                    "UNION SELECT c.relname, n.nspname, c.relkind, g.f_geography_column, g.type, g.coord_dimension, g.srid, %d, a.attnotnull, c.oid as oid, a.attnum as attnum FROM pg_class c, pg_namespace n, geography_columns g, pg_attribute a "
+                                    "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid "
+                                    "AND c.relname::TEXT = g.f_table_name::TEXT AND n.nspname = g.f_table_schema AND a.attname = g.f_geography_column AND a.attrelid = c.oid)",
+                                    GEOM_TYPE_GEOGRAPHY, pszAllowedRelations);
+            osCommand += " ORDER BY oid, attnum";
         }
+        else
+            osCommand.Printf(
+                                "SELECT c.relname, n.nspname, c.relkind FROM pg_class c, pg_namespace n "
+                                "WHERE (c.relkind in (%s) AND c.relname !~ '^pg_' AND c.relnamespace=n.oid)",
+                                pszAllowedRelations);
+                            
+        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
 
         if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
         {
@@ -854,6 +1045,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
             const char *pszGeomType = NULL;
             int nGeomCoordDimension = 0;
             int nSRID = 0;
+            int bNullable = TRUE;
             PostgisType ePostgisType = GEOM_TYPE_UNKNOWN;
             if (bHavePostGIS && !bListAllTables)
             {
@@ -862,6 +1054,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
                 nGeomCoordDimension = atoi(PQgetvalue(hResult, iRecord, 5));
                 nSRID = atoi(PQgetvalue(hResult, iRecord, 6));
                 ePostgisType = (PostgisType) atoi(PQgetvalue(hResult, iRecord, 7));
+                bNullable = EQUAL(PQgetvalue(hResult, iRecord, 8), "f");
 
                 /* We cannot reliably find geometry columns of a view that is */
                 /* based on a table that inherits from another one, wit that */
@@ -887,7 +1080,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
                 OGRPGTableEntryAddGeomColumn(papsTables[nTableCount],
                                              pszGeomColumnName,
                                              pszGeomType, nGeomCoordDimension,
-                                             nSRID, ePostgisType);
+                                             nSRID, ePostgisType, bNullable);
             nTableCount ++;
 
             PGTableEntry* psEntry = OGRPGFindTableEntry(hSetTables, pszTable, pszSchemaName);
@@ -898,7 +1091,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
                                              pszGeomColumnName,
                                              pszGeomType,
                                              nGeomCoordDimension,
-                                             nSRID, ePostgisType);
+                                             nSRID, ePostgisType, bNullable);
         }
 
     /* -------------------------------------------------------------------- */
@@ -906,37 +1099,20 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
     /* -------------------------------------------------------------------- */
         OGRPGClearResult( hResult );
 
-        hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
-        OGRPGClearResult( hResult );
-
-        hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-        OGRPGClearResult( hResult );
-
         /* With PostGIS 2.0, we don't need to query base tables of inherited */
         /* tables */
         if ( bHavePostGIS && !bListAllTables && sPostGISVersion.nMajor < 2 )
         {
-            hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-
-            OGRPGClearResult( hResult );
-
         /* -------------------------------------------------------------------- */
         /*      Fetch inherited tables                                          */
         /* -------------------------------------------------------------------- */
             hResult = OGRPG_PQexec(hPGConn,
-                                "DECLARE mycursor CURSOR for "
                                 "SELECT c1.relname AS derived, c2.relname AS parent, n.nspname "
                                 "FROM pg_class c1, pg_class c2, pg_namespace n, pg_inherits i "
                                 "WHERE i.inhparent = c2.oid AND i.inhrelid = c1.oid AND c1.relnamespace=n.oid "
                                 "AND c1.relkind in ('r', 'v') AND c1.relnamespace=n.oid AND c2.relkind in ('r','v') "
                                 "AND c2.relname !~ '^pg_' AND c2.relnamespace=n.oid");
 
-            if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
-            {
-                OGRPGClearResult( hResult );
-                hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
-            }
-
             if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
             {
                 OGRPGClearResult( hResult );
@@ -1008,19 +1184,9 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         /*      Cleanup                                                         */
         /* -------------------------------------------------------------------- */
             OGRPGClearResult( hResult );
-
-            hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
-            OGRPGClearResult( hResult );
-
-            hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-            OGRPGClearResult( hResult );
-
         }
-
     }
 
-    osCurrentSchema = GetCurrentSchema();
-
 /* -------------------------------------------------------------------- */
 /*      Register the available tables.                                  */
 /* -------------------------------------------------------------------- */
@@ -1056,7 +1222,7 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         OGRPGTableLayer* poLayer;
         poLayer = OpenTable( osCurrentSchema, papsTables[iRecord]->pszTableName,
             papsTables[iRecord]->pszSchemaName,
-            NULL, bUpdate, FALSE );
+            NULL, bDSUpdate, FALSE );
         if( psEntry != NULL )
         {
             if( psEntry->nGeomColumnCount > 0 )
@@ -1075,18 +1241,13 @@ int OGRPGDataSource::Open( const char * pszNewName, int bUpdate,
         }
     }
 
-    bRet = TRUE;
-
 end:
     if (hSetTables)
         CPLHashSetDestroy(hSetTables);
-    CSLDestroy( papszSchemaList );
 
     for(int i=0;i<nTableCount;i++)
         OGRPGFreeTableEntry(papsTables[i]);
     CPLFree(papsTables);
-
-    return bRet;
 }
 
 /************************************************************************/
@@ -1132,6 +1293,8 @@ OGRPGTableLayer* OGRPGDataSource::OpenTable( CPLString& osCurrentSchema,
 int OGRPGDataSource::DeleteLayer( int iLayer )
 
 {
+    /* Force loading of all registered tables */
+    GetLayerCount();
     if( iLayer < 0 || iLayer >= nLayers )
         return OGRERR_FAILURE;
 
@@ -1159,8 +1322,7 @@ int OGRPGDataSource::DeleteLayer( int iLayer )
     PGresult            *hResult;
     CPLString            osCommand;
 
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
+    SoftStartTransaction();
 
     if( bHavePostGIS  && sPostGISVersion.nMajor < 2)
     {
@@ -1180,18 +1342,17 @@ int OGRPGDataSource::DeleteLayer( int iLayer )
     hResult = OGRPG_PQexec( hPGConn, osCommand.c_str() );
     OGRPGClearResult( hResult );
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
+    SoftCommitTransaction();
 
     return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRPGDataSource::CreateLayer( const char * pszLayerName,
+OGRPGDataSource::ICreateLayer( const char * pszLayerName,
                               OGRSpatialReference *poSRS,
                               OGRwkbGeometryType eType,
                               char ** papszOptions )
@@ -1207,15 +1368,17 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
     if (pszLayerName == NULL)
         return NULL;
 
+    EndCopy();
+
     const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
     CPLString osFIDColumnName;
     if (pszFIDColumnName == NULL)
-        osFIDColumnName = "OGC_FID";
+        osFIDColumnName = "ogc_fid";
     else
     {
         if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
         {
-            char* pszLaunderedFid = LaunderName(pszFIDColumnName);
+            char* pszLaunderedFid = OGRPGCommonLaunderName(pszFIDColumnName, "PG");
             osFIDColumnName += OGRPGEscapeColumnName(pszLaunderedFid);
             CPLFree(pszLaunderedFid);
         }
@@ -1265,7 +1428,7 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
       pszSchemaName[length] = '\0';
       
       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
-          pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
+          pszTableName = OGRPGCommonLaunderName( pszDotPos + 1, "PG" ); //skip "."
       else
           pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
     }
@@ -1273,7 +1436,7 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
     {
       pszSchemaName = NULL;
       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
-          pszTableName = LaunderName( pszLayerName ); //skip "."
+          pszTableName = OGRPGCommonLaunderName( pszLayerName, "PG" ); //skip "."
       else
           pszTableName = CPLStrdup( pszLayerName ); //skip "."
     }
@@ -1298,8 +1461,6 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
 /* -------------------------------------------------------------------- */
     int iLayer;
 
-    FlushSoftTransaction();
-
     CPLString osSQLLayerName;
     if (pszSchemaName == NULL || (strlen(osCurrentSchema) > 0 && EQUAL(pszSchemaName, osCurrentSchema.c_str())))
         osSQLLayerName = pszTableName;
@@ -1319,6 +1480,8 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
     CPLPopErrorHandler();
     CPLErrorReset();
 
+    /* Force loading of all registered tables */
+    GetLayerCount();
     for( iLayer = 0; iLayer < nLayers; iLayer++ )
     {
         if( EQUAL(osSQLLayerName.c_str(),papoLayers[iLayer]->GetName()) )
@@ -1353,16 +1516,32 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
         else
             pszGeomType = "bytea";
     }
-    
-    if( eType != wkbNone && EQUAL(pszGeomType, "geography") && !bHaveGeography )
+
+    const char *pszGFldName = NULL;
+    if( eType != wkbNone && EQUAL(pszGeomType, "geography") )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "GEOM_TYPE=geography is only supported in PostGIS >= 1.5.\n"
-                  "Creation of layer %s has failed.",
-                  pszLayerName );
-        CPLFree( pszTableName );
-        CPLFree( pszSchemaName );
-        return NULL;
+        if( !bHaveGeography )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "GEOM_TYPE=geography is only supported in PostGIS >= 1.5.\n"
+                    "Creation of layer %s has failed.",
+                    pszLayerName );
+            CPLFree( pszTableName );
+            CPLFree( pszSchemaName );
+            return NULL;
+        }
+
+        if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
+            pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
+        else
+            pszGFldName = "the_geog";
+    }
+    else if ( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType, "geography") )
+    {
+        if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
+            pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
+        else
+            pszGFldName = "wkb_geometry";
     }
 
     if( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType,"geometry") &&
@@ -1394,18 +1573,20 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
         nSRSId = FetchSRSId( poSRS );
         
     const char *pszGeometryType = OGRToOGCGeomType(eType);
-/* -------------------------------------------------------------------- */
+
+    int bDifferedCreation = CSLTestBoolean(CPLGetConfigOption( "OGR_PG_DIFFERED_CREATION", "YES" ));
+    if( !bHavePostGIS )
+        bDifferedCreation = FALSE;  /* to avoid unnecessary implementation and testing burden */
+    
+/* -------------------------------------------------------------------- */
 /*      Create a basic table with the FID.  Also include the            */
 /*      geometry if this is not a PostGIS enabled table.                */
 /* -------------------------------------------------------------------- */
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
-    
-    const char *pszGFldName = NULL;
-    
+    int bFID64 = CSLFetchBoolean(papszOptions, "FID64", FALSE);
+    const char* pszSerialType = bFID64 ? "BIGSERIAL": "SERIAL";
+
     CPLString osCreateTable;
-    int bTemporary = CSLFetchNameValue( papszOptions, "TEMPORARY" ) != NULL &&
-                     CSLTestBoolean(CSLFetchNameValue( papszOptions, "TEMPORARY" ));
+    int bTemporary = CSLFetchBoolean( papszOptions, "TEMPORARY", FALSE );
     if (bTemporary)
     {
         CPLFree(pszSchemaName);
@@ -1414,177 +1595,196 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
                              OGRPGEscapeColumnName(pszTableName).c_str());
     }
     else
-        osCreateTable.Printf("CREATE TABLE %s.%s",
+        osCreateTable.Printf("CREATE%s TABLE %s.%s",
+                             CSLFetchBoolean( papszOptions, "UNLOGGED", FALSE ) ? " UNLOGGED": "",
                              OGRPGEscapeColumnName(pszSchemaName).c_str(), 
                              OGRPGEscapeColumnName(pszTableName).c_str());
     
     if( eType != wkbNone && !bHavePostGIS )
     {
+        pszGFldName = "wkb_geometry";
         osCommand.Printf(
                  "%s ( "
-                 "    %s SERIAL, "
-                 "   WKB_GEOMETRY %s, "
-                 "   PRIMARY KEY (%s) )",
+                 "    %s %s, "
+                 "   %s %s, "
+                 "   PRIMARY KEY (%s)",
                  osCreateTable.c_str(),
                  pszFIDColumnName,
+                 pszSerialType,
+                 pszGFldName,
                  pszGeomType,
                  pszFIDColumnName);
     }
-    else if ( eType != wkbNone && EQUAL(pszGeomType, "geography") )
+    else if ( !bDifferedCreation && eType != wkbNone && EQUAL(pszGeomType, "geography") )
     {
-        if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
-            pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
-        else
-            pszGFldName = "the_geog";
-        
-        if (nSRSId)
-            osCommand.Printf(
-                     "%s ( %s SERIAL, %s geography(%s%s,%d), PRIMARY KEY (%s) )",
-                     osCreateTable.c_str(),
-                     pszFIDColumnName,
-                     OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
-                     nDimension == 2 ? "" : "Z", nSRSId, 
-                     pszFIDColumnName);
-        else
-            osCommand.Printf(
-                     "%s ( %s SERIAL, %s geography(%s%s), PRIMARY KEY (%s) )",
-                     osCreateTable.c_str(),
-                     pszFIDColumnName,
-                     OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
-                     nDimension == 2 ? "" : "Z", 
-                     pszFIDColumnName);
+        osCommand.Printf(
+                    "%s ( %s %s, %s geography(%s%s%s), PRIMARY KEY (%s)",
+                    osCreateTable.c_str(),
+                    pszFIDColumnName,
+                    pszSerialType,
+                    OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
+                    nDimension == 2 ? "" : "Z",
+                    nSRSId ? CPLSPrintf(",%d", nSRSId) : "", 
+                    pszFIDColumnName);
+    }
+    else if ( !bDifferedCreation && eType != wkbNone && !EQUAL(pszGeomType, "geography") &&
+              sPostGISVersion.nMajor >= 2 )
+    {
+        osCommand.Printf(
+                    "%s ( %s %s, %s geometry(%s%s%s), PRIMARY KEY (%s)",
+                    osCreateTable.c_str(),
+                    pszFIDColumnName,
+                    pszSerialType,
+                    OGRPGEscapeColumnName(pszGFldName).c_str(), pszGeometryType,
+                    nDimension == 2 ? "" : "Z",
+                    nSRSId ? CPLSPrintf(",%d", nSRSId) : "", 
+                    pszFIDColumnName);
     }
     else
     {
         osCommand.Printf(
-                 "%s ( %s SERIAL, PRIMARY KEY (%s) )",
+                 "%s ( %s %s, PRIMARY KEY (%s)",
                  osCreateTable.c_str(),
                  pszFIDColumnName,
+                 pszSerialType,
                  pszFIDColumnName );
     }
+    osCreateTable = osCommand;
 
-    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
-    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
+    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
+    if( eType != wkbNone &&
+        pszSI == NULL &&
+        CSLFetchBoolean( papszOptions, "UNLOGGED", FALSE ) &&
+        !(sPostgreSQLVersion.nMajor > 9 ||
+         (sPostgreSQLVersion.nMajor == 9 && sPostgreSQLVersion.nMinor >= 3)) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s\n%s", osCommand.c_str(), PQerrorMessage(hPGConn) );
-        CPLFree( pszTableName );
-        CPLFree( pszSchemaName );
-
-        OGRPGClearResult( hResult );
-        hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
-        OGRPGClearResult( hResult );
-        return NULL;
+        CPLError(CE_Warning, CPLE_NotSupported,
+                 "GiST index only supported since Postgres 9.3 on unlogged table");
+        bCreateSpatialIndex = FALSE;
     }
 
-    OGRPGClearResult( hResult );
-
     CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn, pszTableName);
     const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
     CPLString osEscapedSchemaNameSingleQuote = OGRPGEscapeString(hPGConn, pszSchemaName);
     const char* pszEscapedSchemaNameSingleQuote = osEscapedSchemaNameSingleQuote.c_str();
 
-/* -------------------------------------------------------------------- */
-/*      Eventually we should be adding this table to a table of         */
-/*      "geometric layers", capturing the WKT projection, and           */
-/*      perhaps some other housekeeping.                                */
-/* -------------------------------------------------------------------- */
-    if( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType, "geography"))
+    if( eType != wkbNone && bHavePostGIS && sPostGISVersion.nMajor <= 1 )
     {
-        if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
-            pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
-        else
-            pszGFldName = "wkb_geometry";
-
-        if (sPostGISVersion.nMajor <= 1)
-        {
-            /* Sometimes there is an old cruft entry in the geometry_columns
-            * table if things were not properly cleaned up before.  We make
-            * an effort to clean out such cruft.
-            * Note: PostGIS 2.0 defines geometry_columns as a view (no clean up is needed)
-            */
-            osCommand.Printf(
-                    "DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = %s",
-                    pszEscapedTableNameSingleQuote, pszEscapedSchemaNameSingleQuote );
-
-            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
-            OGRPGClearResult( hResult );
-        }
-
+        /* Sometimes there is an old cruft entry in the geometry_columns
+        * table if things were not properly cleaned up before.  We make
+        * an effort to clean out such cruft.
+        * Note: PostGIS 2.0 defines geometry_columns as a view (no clean up is needed)
+        */
         osCommand.Printf(
-                 "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s',%d)",
-                 pszEscapedSchemaNameSingleQuote, pszEscapedTableNameSingleQuote,
-                 OGRPGEscapeString(hPGConn, pszGFldName).c_str(),
-                 nSRSId, pszGeometryType, nDimension );
+                "DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = %s",
+                pszEscapedTableNameSingleQuote, pszEscapedSchemaNameSingleQuote );
 
         hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+        OGRPGClearResult( hResult );
+    }
+    
+    if( !bDifferedCreation )
+    {
+        SoftStartTransaction();
 
-        if( !hResult
-            || PQresultStatus(hResult) != PGRES_TUPLES_OK )
+        osCommand = osCreateTable;
+        osCommand += " )";
+
+        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
         {
             CPLError( CE_Failure, CPLE_AppDefined,
-                      "AddGeometryColumn failed for layer %s, layer creation has failed.",
-                      pszLayerName );
-
+                    "%s\n%s", osCommand.c_str(), PQerrorMessage(hPGConn) );
             CPLFree( pszTableName );
             CPLFree( pszSchemaName );
 
             OGRPGClearResult( hResult );
 
-            hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
-            OGRPGClearResult( hResult );
-
+            SoftRollbackTransaction();
             return NULL;
         }
 
         OGRPGClearResult( hResult );
-    }
-    
-    const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
-    int bCreateSpatialIndex = ( pszSI == NULL || CSLTestBoolean(pszSI) );
-    if( eType != wkbNone && bHavePostGIS && bCreateSpatialIndex )
-    {
-/* -------------------------------------------------------------------- */
-/*      Create the spatial index.                                       */
-/*                                                                      */
-/*      We're doing this before we add geometry and record to the table */
-/*      so this may not be exactly the best way to do it.               */
-/* -------------------------------------------------------------------- */
 
-        osCommand.Printf("CREATE INDEX %s ON %s.%s USING GIST (%s)",
-                         OGRPGEscapeColumnName(
-                            CPLSPrintf("%s_%s_geom_idx", pszTableName, pszGFldName)).c_str(),
-                         OGRPGEscapeColumnName(pszSchemaName).c_str(),
-                         OGRPGEscapeColumnName(pszTableName).c_str(),
-                         OGRPGEscapeColumnName(pszGFldName).c_str());
+    /* -------------------------------------------------------------------- */
+    /*      Eventually we should be adding this table to a table of         */
+    /*      "geometric layers", capturing the WKT projection, and           */
+    /*      perhaps some other housekeeping.                                */
+    /* -------------------------------------------------------------------- */
+        if( eType != wkbNone && bHavePostGIS && !EQUAL(pszGeomType, "geography") &&
+            sPostGISVersion.nMajor <= 1 )
+        {
+            osCommand.Printf(
+                    "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s',%d)",
+                    pszEscapedSchemaNameSingleQuote, pszEscapedTableNameSingleQuote,
+                    OGRPGEscapeString(hPGConn, pszGFldName).c_str(),
+                    nSRSId, pszGeometryType, nDimension );
 
-        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
 
-        if( !hResult
-            || PQresultStatus(hResult) != PGRES_COMMAND_OK )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                    "'%s' failed for layer %s, index creation has failed.",
-                    osCommand.c_str(), pszLayerName );
+            if( !hResult
+                || PQresultStatus(hResult) != PGRES_TUPLES_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "AddGeometryColumn failed for layer %s, layer creation has failed.",
+                        pszLayerName );
 
-            CPLFree( pszTableName );
-            CPLFree( pszSchemaName );
+                CPLFree( pszTableName );
+                CPLFree( pszSchemaName );
 
-            OGRPGClearResult( hResult );
+                OGRPGClearResult( hResult );
+
+                SoftRollbackTransaction();
+
+                return NULL;
+            }
 
-            hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
             OGRPGClearResult( hResult );
+        }
+        
+        if( eType != wkbNone && bHavePostGIS && bCreateSpatialIndex )
+        {
+    /* -------------------------------------------------------------------- */
+    /*      Create the spatial index.                                       */
+    /*                                                                      */
+    /*      We're doing this before we add geometry and record to the table */
+    /*      so this may not be exactly the best way to do it.               */
+    /* -------------------------------------------------------------------- */
 
-            return NULL;
+            osCommand.Printf("CREATE INDEX %s ON %s.%s USING GIST (%s)",
+                            OGRPGEscapeColumnName(
+                                CPLSPrintf("%s_%s_geom_idx", pszTableName, pszGFldName)).c_str(),
+                            OGRPGEscapeColumnName(pszSchemaName).c_str(),
+                            OGRPGEscapeColumnName(pszTableName).c_str(),
+                            OGRPGEscapeColumnName(pszGFldName).c_str());
+
+            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+
+            if( !hResult
+                || PQresultStatus(hResult) != PGRES_COMMAND_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "'%s' failed for layer %s, index creation has failed.",
+                        osCommand.c_str(), pszLayerName );
+
+                CPLFree( pszTableName );
+                CPLFree( pszSchemaName );
+
+                OGRPGClearResult( hResult );
+
+                SoftRollbackTransaction();
+
+                return NULL;
+            }
+            OGRPGClearResult( hResult );
         }
-        OGRPGClearResult( hResult );
-    }
 
-/* -------------------------------------------------------------------- */
-/*      Complete, and commit the transaction.                           */
-/* -------------------------------------------------------------------- */
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
+    /* -------------------------------------------------------------------- */
+    /*      Complete, and commit the transaction.                           */
+    /* -------------------------------------------------------------------- */
+        SoftCommitTransaction();
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -1593,19 +1793,15 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
 
     poLayer = new OGRPGTableLayer( this, osCurrentSchema, pszTableName,
                                    pszSchemaName, NULL, TRUE );
-    if( !(poLayer->ReadTableDefinition()) )
-    {
-        CPLFree( pszTableName );
-        CPLFree( pszSchemaName );
-        delete poLayer;
-        return NULL;
-    }
-
+    poLayer->SetTableDefinition(pszFIDColumnName, pszGFldName, eType,
+                                pszGeomType, nSRSId, nDimension);
     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
     //poLayer->SetForcedSRSId(nForcedSRSId);
     poLayer->SetForcedDimension(nForcedDimension);
     poLayer->SetCreateSpatialIndexFlag(bCreateSpatialIndex);
+    poLayer->SetDifferedCreation(bDifferedCreation, osCreateTable);
+    
 
     /* HSTORE_COLUMNS existed at a time during GDAL 1.10dev */
     const char* pszHSTOREColumns = CSLFetchNameValue( papszOptions, "HSTORE_COLUMNS" );
@@ -1615,6 +1811,13 @@ OGRPGDataSource::CreateLayer( const char * pszLayerName,
     const char* pszOverrideColumnTypes = CSLFetchNameValue( papszOptions, "COLUMN_TYPES" );
     poLayer->SetOverrideColumnTypes(pszOverrideColumnTypes);
 
+    poLayer->AllowAutoFIDOnCreateViaCopy();
+    if( CSLTestBoolean(CPLGetConfigOption("PG_USE_COPY", "YES")) )
+        poLayer->SetUseCopy();
+
+    if( bFID64 )
+        poLayer->SetMetadataItem(OLMD_FID64, "YES");
+
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
 /* -------------------------------------------------------------------- */
@@ -1640,18 +1843,33 @@ int OGRPGDataSource::TestCapability( const char * pszCap )
         || EQUAL(pszCap,ODsCDeleteLayer)
         || EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
+    else if( EQUAL(pszCap,ODsCTransactions) )
+        return TRUE;
     else
         return FALSE;
 }
 
 /************************************************************************/
+/*                           GetLayerCount()                            */
+/************************************************************************/
+
+int OGRPGDataSource::GetLayerCount()
+{
+    LoadTables();
+    return nLayers;
+}
+
+/************************************************************************/
 /*                              GetLayer()                              */
 /************************************************************************/
 
 OGRLayer *OGRPGDataSource::GetLayer( int iLayer )
 
 {
-    if( iLayer < 0 || iLayer >= nLayers )
+    /* Force loading of all registered tables */
+    if( iLayer < 0 || iLayer >= GetLayerCount() )
         return NULL;
     else
         return papoLayers[iLayer];
@@ -1673,9 +1891,9 @@ OGRLayer *OGRPGDataSource::GetLayerByName( const char *pszName )
 
     int  i;
     
-    int count = GetLayerCount();
     /* first a case sensitive check */
-    for( i = 0; i < count; i++ )
+    /* do NOT force loading of all registered tables */
+    for( i = 0; i < nLayers; i++ )
     {
         OGRPGTableLayer *poLayer = papoLayers[i];
 
@@ -1686,7 +1904,7 @@ OGRLayer *OGRPGDataSource::GetLayerByName( const char *pszName )
     }
         
     /* then case insensitive */
-    for( i = 0; i < count; i++ )
+    for( i = 0; i < nLayers; i++ )
     {
         OGRPGTableLayer *poLayer = papoLayers[i];
 
@@ -1730,10 +1948,26 @@ OGRLayer *OGRPGDataSource::GetLayerByName( const char *pszName )
     }
     else
     {
+        EndCopy();
+
+        CPLString osTableName(pszTableName);
+        CPLString osTableNameLower(pszTableName);
+        osTableNameLower.tolower();
+        if( osTableName != osTableNameLower )
+            CPLPushErrorHandler(CPLQuietErrorHandler);
         poLayer = OpenTable( osCurrentSchema, pszTableName,
                              pszSchemaName,
                              pszGeomColumnName,
                              bDSUpdate, TRUE );
+        if( osTableName != osTableNameLower )
+            CPLPopErrorHandler();
+        if( poLayer == NULL && osTableName != osTableNameLower )
+        {
+            poLayer = OpenTable( osCurrentSchema, osTableNameLower,
+                                pszSchemaName,
+                                pszGeomColumnName,
+                                bDSUpdate, TRUE );
+        }
     }
 
     CPLFree(pszTableName);
@@ -1792,6 +2026,8 @@ OGRSpatialReference *OGRPGDataSource::FetchSRS( int nId )
             return papoSRS[i];
     }
 
+    EndCopy();
+
 /* -------------------------------------------------------------------- */
 /*      Try looking up in spatial_ref_sys table.                        */
 /* -------------------------------------------------------------------- */
@@ -1799,8 +2035,6 @@ OGRSpatialReference *OGRPGDataSource::FetchSRS( int nId )
     CPLString        osCommand;
     OGRSpatialReference *poSRS = NULL;
 
-    SoftStartTransaction();
-
     osCommand.Printf(
              "SELECT srtext FROM spatial_ref_sys "
              "WHERE srid = %d",
@@ -1828,7 +2062,6 @@ OGRSpatialReference *OGRPGDataSource::FetchSRS( int nId )
     }
 
     OGRPGClearResult( hResult );
-    SoftCommit();
 
 /* -------------------------------------------------------------------- */
 /*      Add to the cache.                                               */
@@ -1888,35 +2121,34 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
         }
     }
 /* -------------------------------------------------------------------- */
-/*      Check whether the EPSG authority code is already mapped to a    */
+/*      Check whether the authority name/code is already mapped to a    */
 /*      SRS ID.                                                         */
 /* -------------------------------------------------------------------- */
-    if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
+    int nAuthorityCode = 0;
+    if( pszAuthorityName != NULL )
     {
-        int             nAuthorityCode;
-
-        /* For the root authority name 'EPSG', the authority code
-         * should always be integral
-         */
+        /* Check that the authority code is integral */
         nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
+        if( nAuthorityCode > 0 )
+        {
+            osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
+                            "auth_name = '%s' AND auth_srid = %d",
+                            pszAuthorityName,
+                            nAuthorityCode );
+            hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
 
-        osCommand.Printf("SELECT srid FROM spatial_ref_sys WHERE "
-                         "auth_name = '%s' AND auth_srid = %d",
-                         pszAuthorityName,
-                         nAuthorityCode );
-        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+            if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
+                && PQntuples(hResult) > 0 )
+            {
+                nSRSId = atoi(PQgetvalue( hResult, 0, 0 ));
 
-        if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK
-            && PQntuples(hResult) > 0 )
-        {
-            nSRSId = atoi(PQgetvalue( hResult, 0, 0 ));
+                OGRPGClearResult( hResult );
 
-            OGRPGClearResult( hResult );
+                return nSRSId;
+            }
 
-            return nSRSId;
+            OGRPGClearResult( hResult );
         }
-
-        OGRPGClearResult( hResult );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1931,9 +2163,6 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 /* -------------------------------------------------------------------- */
 /*      Try to find in the existing table.                              */
 /* -------------------------------------------------------------------- */
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
-
     CPLString osWKT = OGRPGEscapeString(hPGConn, pszWKT, -1, "spatial_ref_sys", "srtext");
     osCommand.Printf(
              "SELECT srid FROM spatial_ref_sys WHERE srtext = %s",
@@ -1952,9 +2181,6 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 
         OGRPGClearResult( hResult );
 
-        hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-        OGRPGClearResult( hResult );
-
         return nSRSId;
     }
 
@@ -1969,9 +2195,6 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 
     OGRPGClearResult( hResult );
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
-
     if( bTableMissing )
     {
         if( InitializeMetadataTables() != OGRERR_NONE )
@@ -1981,9 +2204,6 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 /* -------------------------------------------------------------------- */
 /*      Get the current maximum srid in the srs table.                  */
 /* -------------------------------------------------------------------- */
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
-
     hResult = OGRPG_PQexec(hPGConn, "SELECT MAX(srid) FROM spatial_ref_sys" );
 
     if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK )
@@ -2008,10 +2228,8 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
 
     CPLString osProj4 = OGRPGEscapeString(hPGConn, pszProj4, -1, "spatial_ref_sys", "proj4text");
 
-    if( pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG") )
+    if( pszAuthorityName != NULL && nAuthorityCode > 0)
     {
-        int             nAuthorityCode;
-
         nAuthorityCode = atoi( oSRS.GetAuthorityCode(NULL) );
 
         osCommand.Printf(
@@ -2034,13 +2252,144 @@ int OGRPGDataSource::FetchSRSId( OGRSpatialReference * poSRS )
     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
     OGRPGClearResult( hResult );
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
-
     return nSRSId;
 }
 
 /************************************************************************/
+/*                         StartTransaction()                           */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRPGDataSource::StartTransaction(CPL_UNUSED int bForce)
+{
+    if( bUserTransactionActive )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Transaction already established");
+        return OGRERR_FAILURE;
+    }
+
+    CPLAssert(!bSavePointActive);
+    EndCopy();
+
+    if( nSoftTransactionLevel == 0 )
+    {
+        OGRErr eErr = DoTransactionCommand("BEGIN");
+        if( eErr != OGRERR_NONE )
+            return eErr;
+    }
+    else
+    {
+        OGRErr eErr = DoTransactionCommand("SAVEPOINT ogr_savepoint");
+        if( eErr != OGRERR_NONE )
+            return eErr;
+
+        bSavePointActive = TRUE;
+    }
+
+    nSoftTransactionLevel++;
+    bUserTransactionActive = TRUE;
+
+    /*CPLDebug("PG", "poDS=%p StartTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                         CommitTransaction()                          */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRPGDataSource::CommitTransaction()
+{
+    if( !bUserTransactionActive )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
+        return OGRERR_FAILURE;
+    }
+
+    /*CPLDebug("PG", "poDS=%p CommitTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
+
+    FlushCache();
+
+    nSoftTransactionLevel--;
+    bUserTransactionActive = FALSE;
+
+    OGRErr eErr;
+    if( bSavePointActive )
+    {
+        CPLAssert(nSoftTransactionLevel > 0);
+        bSavePointActive = FALSE;
+        
+        eErr = DoTransactionCommand("RELEASE SAVEPOINT ogr_savepoint");
+    }
+    else
+    {
+        if( nSoftTransactionLevel > 0 )
+        {
+            // This means we have cursors still in progress
+            for(int i=0;i<nLayers;i++)
+                papoLayers[i]->InvalidateCursor();
+            CPLAssert( nSoftTransactionLevel == 0 );
+        }
+
+        eErr = DoTransactionCommand("COMMIT");
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                        RollbackTransaction()                         */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRPGDataSource::RollbackTransaction()
+{
+    if( !bUserTransactionActive )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
+        return OGRERR_FAILURE;
+    }
+
+    /*CPLDebug("PG", "poDS=%p RollbackTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
+
+    FlushCache();
+
+    nSoftTransactionLevel--;
+    bUserTransactionActive = FALSE;
+
+    OGRErr eErr;
+    if( bSavePointActive )
+    {
+        CPLAssert(nSoftTransactionLevel > 0);
+        bSavePointActive = FALSE;
+
+        eErr = DoTransactionCommand("ROLLBACK TO SAVEPOINT ogr_savepoint");
+    }
+    else
+    {
+        if( nSoftTransactionLevel > 0 )
+        {
+            // This means we have cursors still in progress
+            for(int i=0;i<nLayers;i++)
+                papoLayers[i]->InvalidateCursor();
+            CPLAssert( nSoftTransactionLevel == 0 );
+        }
+
+        eErr = DoTransactionCommand("ROLLBACK");
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
 /*                        SoftStartTransaction()                        */
 /*                                                                      */
 /*      Create a transaction scope.  If we already have a               */
@@ -2052,135 +2401,139 @@ OGRErr OGRPGDataSource::SoftStartTransaction()
 
 {
     nSoftTransactionLevel++;
+    /*CPLDebug("PG", "poDS=%p SoftStartTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
 
+    OGRErr eErr = OGRERR_NONE;
     if( nSoftTransactionLevel == 1 )
     {
-        PGresult    *hResult = NULL;
-        PGconn      *hPGConn = GetPGConn();
-
-        //CPLDebug( "PG", "BEGIN Transaction" );
-        hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-
-        if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
-        {
-            OGRPGClearResult( hResult );
-
-            CPLDebug( "PG", "BEGIN Transaction failed:\n%s",
-                      PQerrorMessage( hPGConn ) );
-            return OGRERR_FAILURE;
-        }
-
-        OGRPGClearResult( hResult );
+        eErr = DoTransactionCommand("BEGIN");
     }
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                             SoftCommit()                             */
+/*                     SoftCommitTransaction()                          */
 /*                                                                      */
 /*      Commit the current transaction if we are at the outer           */
 /*      scope.                                                          */
 /************************************************************************/
 
-OGRErr OGRPGDataSource::SoftCommit()
+OGRErr OGRPGDataSource::SoftCommitTransaction()
 
 {
     EndCopy();
+    
+    /*CPLDebug("PG", "poDS=%p SoftCommitTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
 
     if( nSoftTransactionLevel <= 0 )
     {
-        CPLDebug( "PG", "SoftCommit() with no transaction active." );
+        CPLAssert(FALSE);
         return OGRERR_FAILURE;
     }
 
+    OGRErr eErr = OGRERR_NONE;
     nSoftTransactionLevel--;
-
     if( nSoftTransactionLevel == 0 )
     {
-        PGresult    *hResult = NULL;
-        PGconn      *hPGConn = GetPGConn();
-
-        //CPLDebug( "PG", "COMMIT Transaction" );
-        hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-
-        if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
-        {
-            OGRPGClearResult( hResult );
+        CPLAssert( !bSavePointActive );
 
-            CPLDebug( "PG", "COMMIT Transaction failed:\n%s",
-                      PQerrorMessage( hPGConn ) );
-            return OGRERR_FAILURE;
-        }
-        
-        OGRPGClearResult( hResult );
+        eErr = DoTransactionCommand("COMMIT");
     }
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                            SoftRollback()                            */
+/*                  SoftRollbackTransaction()                           */
 /*                                                                      */
-/*      Force a rollback of the current transaction if there is one,    */
-/*      even if we are nested several levels deep.                      */
+/*      Do a rollback of the current transaction if we are at the 1st   */
+/*      level                                                           */
 /************************************************************************/
 
-OGRErr OGRPGDataSource::SoftRollback()
+OGRErr OGRPGDataSource::SoftRollbackTransaction()
 
 {
     EndCopy();
+    
+    /*CPLDebug("PG", "poDS=%p SoftRollbackTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
 
     if( nSoftTransactionLevel <= 0 )
     {
-        CPLDebug( "PG", "SoftRollback() with no transaction active." );
+        CPLAssert(FALSE);
         return OGRERR_FAILURE;
     }
 
-    nSoftTransactionLevel = 0;
-
-    PGresult    *hResult = NULL;
-    PGconn      *hPGConn = GetPGConn();
-
-    hResult = OGRPG_PQexec(hPGConn, "ROLLBACK");
-
-    if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    OGRErr eErr = OGRERR_NONE;
+    nSoftTransactionLevel--;
+    if( nSoftTransactionLevel == 0 )
     {
-        OGRPGClearResult( hResult );
+        CPLAssert( !bSavePointActive );
 
-        return OGRERR_FAILURE;
+        eErr = DoTransactionCommand("ROLLBACK");
     }
 
-    OGRPGClearResult( hResult );
-
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
 /*                        FlushSoftTransaction()                        */
 /*                                                                      */
-/*      Force the unwinding of any active transaction, and it's         */
-/*      commit.                                                         */
+/*      Force the unwinding of any active transaction, and its          */
+/*      commit. Should only be used by datasource destructor            */
 /************************************************************************/
 
 OGRErr OGRPGDataSource::FlushSoftTransaction()
 
 {
-    /* This must come first because of ogr2ogr.  If you want
-       to use ogr2ogr with COPY support, then you must specify
-       that ogr2ogr does not use transactions.  Thus, 
-       nSoftTransactionLevel will always be zero, so this has
-       to come first. */
-    EndCopy(); 
+    FlushCache(); 
+    
+    /*CPLDebug("PG", "poDS=%p FlushSoftTransaction() nSoftTransactionLevel=%d",
+             this, nSoftTransactionLevel);*/
 
     if( nSoftTransactionLevel <= 0 )
         return OGRERR_NONE;
 
-    nSoftTransactionLevel = 1;
+    for(int i=0;i<nLayers;i++)
+        papoLayers[i]->InvalidateCursor();
+    bSavePointActive = FALSE;
 
-    return SoftCommit();
+    OGRErr eErr = OGRERR_NONE;
+    if( nSoftTransactionLevel > 0 )
+    {
+        CPLAssert(nSoftTransactionLevel == 1 );
+        nSoftTransactionLevel = 0;
+        eErr = DoTransactionCommand("COMMIT");
+    }
+    return eErr;
 }
 
+/************************************************************************/
+/*                          DoTransactionCommand()                      */
+/************************************************************************/
+
+OGRErr OGRPGDataSource::DoTransactionCommand(const char* pszCommand)
+
+{
+    OGRErr      eErr = OGRERR_NONE;
+    PGresult    *hResult = NULL;
+    PGconn      *hPGConn = GetPGConn();
+
+    hResult = OGRPG_PQexec(hPGConn, pszCommand);
+    osDebugLastTransactionCommand = pszCommand;
+
+    if( !hResult || PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    {
+        eErr = OGRERR_FAILURE;
+    }
+
+    OGRPGClearResult( hResult );
+
+    return eErr;
+}
 
 /************************************************************************/
 /*                     OGRPGNoResetResultLayer                          */
@@ -2215,7 +2568,10 @@ OGRPGNoResetResultLayer::OGRPGNoResetResultLayer( OGRPGDataSource *poDSIn,
     poDS = poDSIn;
     ReadResultDefinition(hResultIn);
     hCursorResult = hResultIn;
-    CreateMapFromFieldNameToIndex();
+    CreateMapFromFieldNameToIndex(hCursorResult,
+                                  poFeatureDefn,
+                                  m_panMapFieldNameToIndex,
+                                  m_panMapFieldNameToGeomIndex);
 }
 
 /************************************************************************/
@@ -2249,7 +2605,10 @@ OGRFeature *OGRPGNoResetResultLayer::GetNextFeature()
     {
         return NULL;
     }
-    return RecordToFeature(iNextShapeId ++);
+    return RecordToFeature(hCursorResult,
+                           m_panMapFieldNameToIndex,
+                           m_panMapFieldNameToGeomIndex,
+                           iNextShapeId ++);
 }
 
 /************************************************************************/
@@ -2259,11 +2618,11 @@ OGRFeature *OGRPGNoResetResultLayer::GetNextFeature()
 class OGRPGMemLayerWrapper : public OGRLayer
 {
   private:
-      OGRDataSource  *poMemDS;
+      GDALDataset  *poMemDS;
       OGRLayer       *poMemLayer;
 
   public:
-                        OGRPGMemLayerWrapper( OGRDataSource  *poMemDSIn )
+                        OGRPGMemLayerWrapper( GDALDataset  *poMemDSIn )
                         {
                             poMemDS = poMemDSIn;
                             poMemLayer = poMemDS->GetLayer(0);
@@ -2278,6 +2637,37 @@ class OGRPGMemLayerWrapper : public OGRLayer
 };
 
 /************************************************************************/
+/*                           GetMetadataItem()                          */
+/************************************************************************/
+
+const char* OGRPGDataSource::GetMetadataItem(const char* pszKey,
+                                             const char* pszDomain)
+{
+    /* Only used by ogr_pg.py to check inner working */
+    if( pszDomain != NULL && EQUAL(pszDomain, "_debug_") &&
+        pszKey != NULL )
+    {
+        if( EQUAL(pszKey, "bHasLoadTables") )
+            return CPLSPrintf("%d", bHasLoadTables);
+        if( EQUAL(pszKey, "nSoftTransactionLevel") )
+            return CPLSPrintf("%d", nSoftTransactionLevel);
+        if( EQUAL(pszKey, "bSavePointActive") )
+            return CPLSPrintf("%d", bSavePointActive);
+        if( EQUAL(pszKey, "bUserTransactionActive") )
+            return CPLSPrintf("%d", bUserTransactionActive);
+        if( EQUAL(pszKey, "osDebugLastTransactionCommand") )
+        {
+            const char* pszRet = CPLSPrintf("%s", osDebugLastTransactionCommand.c_str());
+            osDebugLastTransactionCommand = "";
+            return pszRet;
+        }
+            
+    }
+    return OGRDataSource::GetMetadataItem(pszKey, pszDomain);
+}
+
+
+/************************************************************************/
 /*                             ExecuteSQL()                             */
 /************************************************************************/
 
@@ -2290,6 +2680,8 @@ OGRLayer * OGRPGDataSource::ExecuteSQL( const char *pszSQLCommand,
     while(*pszSQLCommand == ' ')
         pszSQLCommand ++;
 
+    FlushCache();
+
 /* -------------------------------------------------------------------- */
 /*      Use generic implementation for recognized dialects              */
 /* -------------------------------------------------------------------- */
@@ -2308,6 +2700,7 @@ OGRLayer * OGRPGDataSource::ExecuteSQL( const char *pszSQLCommand,
         while( *pszLayerName == ' ' )
             pszLayerName++;
         
+        GetLayerCount();
         for( int iLayer = 0; iLayer < nLayers; iLayer++ )
         {
             if( EQUAL(papoLayers[iLayer]->GetName(), 
@@ -2325,65 +2718,72 @@ OGRLayer * OGRPGDataSource::ExecuteSQL( const char *pszSQLCommand,
 /* -------------------------------------------------------------------- */
     PGresult    *hResult = NULL;
 
-    FlushSoftTransaction();
-
-    if( EQUALN(pszSQLCommand,"VACUUM",6) 
-        || SoftStartTransaction() == OGRERR_NONE  )
+    if (EQUALN(pszSQLCommand, "SELECT", 6) == FALSE ||
+        (strstr(pszSQLCommand, "from") == NULL && strstr(pszSQLCommand, "FROM") == NULL))
     {
-        if (EQUALN(pszSQLCommand, "SELECT", 6) == FALSE ||
-            (strstr(pszSQLCommand, "from") == NULL && strstr(pszSQLCommand, "FROM") == NULL))
+        /* For something that is not a select or a select without table, do not */
+        /* run under transaction (CREATE DATABASE, VACCUUM don't like transactions) */
+
+        hResult = OGRPG_PQexec(hPGConn, pszSQLCommand, TRUE /* multiple allowed */ );
+        if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK)
         {
-            hResult = OGRPG_PQexec(hPGConn, pszSQLCommand, TRUE /* multiple allowed */ );
-            if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK)
-            {
-                CPLDebug( "PG", "Command Results Tuples = %d", PQntuples(hResult) );
-                FlushSoftTransaction();
+            CPLDebug( "PG", "Command Results Tuples = %d", PQntuples(hResult) );
 
-                OGRSFDriver* poMemDriver = OGRSFDriverRegistrar::GetRegistrar()->
-                                GetDriverByName("Memory");
-                if (poMemDriver)
-                {
-                    OGRPGLayer* poResultLayer = new OGRPGNoResetResultLayer( this, hResult );
-                    OGRDataSource* poMemDS = poMemDriver->CreateDataSource("");
-                    poMemDS->CopyLayer(poResultLayer, "sql_statement");
-                    OGRPGMemLayerWrapper* poResLayer = new OGRPGMemLayerWrapper(poMemDS);
-                    delete poResultLayer;
-                    return poResLayer;
-                }
-                else
-                    return NULL;
+            GDALDriver* poMemDriver = OGRSFDriverRegistrar::GetRegistrar()->
+                            GetDriverByName("Memory");
+            if (poMemDriver)
+            {
+                OGRPGLayer* poResultLayer = new OGRPGNoResetResultLayer( this, hResult );
+                GDALDataset* poMemDS = poMemDriver->Create("", 0, 0, 0, GDT_Unknown, NULL);
+                poMemDS->CopyLayer(poResultLayer, "sql_statement");
+                OGRPGMemLayerWrapper* poResLayer = new OGRPGMemLayerWrapper(poMemDS);
+                delete poResultLayer;
+                return poResLayer;
             }
+            else
+                return NULL;
         }
-        else
-        {
-            CPLString osCommand;
-            osCommand.Printf( "DECLARE %s CURSOR for %s",
-                                "executeSQLCursor", pszSQLCommand );
+    }
+    else
+    {
+        SoftStartTransaction();
 
-            hResult = OGRPG_PQexec(hPGConn, osCommand );
+        CPLString osCommand;
+        osCommand.Printf( "DECLARE %s CURSOR for %s",
+                            "executeSQLCursor", pszSQLCommand );
+
+        hResult = OGRPG_PQexec(hPGConn, osCommand );
 
 /* -------------------------------------------------------------------- */
 /*      Do we have a tuple result? If so, instantiate a results         */
 /*      layer for it.                                                   */
 /* -------------------------------------------------------------------- */
-            if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
-            {
-                OGRPGResultLayer *poLayer = NULL;
+        if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
+        {
+            OGRPGResultLayer *poLayer = NULL;
 
-                OGRPGClearResult( hResult );
+            OGRPGClearResult( hResult );
 
-                osCommand.Printf( "FETCH 0 in %s", "executeSQLCursor" );
-                hResult = OGRPG_PQexec(hPGConn, osCommand );
+            osCommand.Printf( "FETCH 0 in %s", "executeSQLCursor" );
+            hResult = OGRPG_PQexec(hPGConn, osCommand );
 
-                poLayer = new OGRPGResultLayer( this, pszSQLCommand, hResult );
+            poLayer = new OGRPGResultLayer( this, pszSQLCommand, hResult );
 
-                OGRPGClearResult( hResult );
+            OGRPGClearResult( hResult );
+            
+            osCommand.Printf( "CLOSE %s", "executeSQLCursor" );
+            hResult = OGRPG_PQexec(hPGConn, osCommand );
+            
+            SoftCommitTransaction();
 
-                if( poSpatialFilter != NULL )
-                    poLayer->SetSpatialFilter( poSpatialFilter );
+            if( poSpatialFilter != NULL )
+                poLayer->SetSpatialFilter( poSpatialFilter );
 
-                return poLayer;
-            }
+            return poLayer;
+        }
+        else
+        {
+            SoftRollbackTransaction();
         }
     }
 
@@ -2400,8 +2800,6 @@ OGRLayer * OGRPGDataSource::ExecuteSQL( const char *pszSQLCommand,
 
     OGRPGClearResult( hResult );
 
-    FlushSoftTransaction();
-
     return NULL;
 }
 
@@ -2416,40 +2814,22 @@ void OGRPGDataSource::ReleaseResultSet( OGRLayer * poLayer )
 }
 
 /************************************************************************/
-/*                            LaunderName()                             */
-/************************************************************************/
-
-char *OGRPGDataSource::LaunderName( const char *pszSrcName )
-
-{
-    char    *pszSafeName = CPLStrdup( pszSrcName );
-
-    for( int i = 0; pszSafeName[i] != '\0'; i++ )
-    {
-        pszSafeName[i] = (char) tolower( pszSafeName[i] );
-        if( pszSafeName[i] == '\'' || pszSafeName[i] == '-' || pszSafeName[i] == '#' )
-            pszSafeName[i] = '_';
-    }
-
-    if( strcmp(pszSrcName,pszSafeName) != 0 )
-        CPLDebug("PG","LaunderName('%s') -> '%s'", 
-                 pszSrcName, pszSafeName);
-
-    return pszSafeName;
-}
-
-/************************************************************************/
 /*                             StartCopy()                              */
 /************************************************************************/
+
 void OGRPGDataSource::StartCopy( OGRPGTableLayer *poPGLayer )
 {
+    if( poLayerInCopyMode == poPGLayer )
+        return;
     EndCopy();
     poLayerInCopyMode = poPGLayer;
+    poLayerInCopyMode->StartCopy();
 }
 
 /************************************************************************/
 /*                              EndCopy()                               */
 /************************************************************************/
+
 OGRErr OGRPGDataSource::EndCopy( )
 {
     if( poLayerInCopyMode != NULL )
@@ -2463,10 +2843,3 @@ OGRErr OGRPGDataSource::EndCopy( )
         return OGRERR_NONE;
 }
 
-/************************************************************************/
-/*                           CopyInProgress()                           */
-/************************************************************************/
-int OGRPGDataSource::CopyInProgress( )
-{
-    return ( poLayerInCopyMode != NULL );
-}
diff --git a/ogr/ogrsf_frmts/pg/ogrpgdriver.cpp b/ogr/ogrsf_frmts/pg/ogrpgdriver.cpp
index 758c67a..7d04ee8 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgdriver.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpgdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgdriver.cpp 12396 2007-10-13 10:02:17Z rouault $
+ * $Id: ogrpgdriver.cpp 29019 2015-04-25 20:34:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDriver class.
@@ -30,40 +30,38 @@
 #include "ogr_pg.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrpgdriver.cpp 12396 2007-10-13 10:02:17Z rouault $");
+CPL_CVSID("$Id: ogrpgdriver.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
-/************************************************************************/
-/*                            ~OGRPGDriver()                            */
-/************************************************************************/
-
-OGRPGDriver::~OGRPGDriver()
-
-{
-}
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                              Identify()                              */
 /************************************************************************/
 
-const char *OGRPGDriver::GetName()
-
+static int OGRPGDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-    return "PostgreSQL";
+    if( !EQUALN(poOpenInfo->pszFilename,"PGB:",4) &&
+        !EQUALN(poOpenInfo->pszFilename,"PG:",3) )
+        return FALSE;
+    return TRUE;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRPGDriver::Open( const char * pszFilename,
-                                     int bUpdate )
+static GDALDataset *OGRPGDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRPGDataSource     *poDS;
 
+    if( !OGRPGDriverIdentify(poOpenInfo) )
+        return NULL;
+
     poDS = new OGRPGDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, TRUE ) )
+    if( !poDS->Open( poOpenInfo->pszFilename,
+                     poOpenInfo->eAccess == GA_Update, TRUE,
+                     poOpenInfo->papszOpenOptions ) )
     {
         delete poDS;
         return NULL;
@@ -76,16 +74,19 @@ OGRDataSource *OGRPGDriver::Open( const char * pszFilename,
 /*                          CreateDataSource()                          */
 /************************************************************************/
 
-OGRDataSource *OGRPGDriver::CreateDataSource( const char * pszName,
-                                              char ** /* papszOptions */ )
+static GDALDataset *OGRPGDriverCreate( const char * pszName,
+                                          CPL_UNUSED int nBands,
+                                          CPL_UNUSED int nXSize,
+                                          CPL_UNUSED int nYSize,
+                                          CPL_UNUSED GDALDataType eDT,
+                                          CPL_UNUSED char **papszOptions )
 
 {
     OGRPGDataSource     *poDS;
 
     poDS = new OGRPGDataSource();
 
-
-    if( !poDS->Open( pszName, TRUE, TRUE ) )
+    if( !poDS->Open( pszName, TRUE, TRUE, NULL ) )
     {
         delete poDS;
         CPLError( CE_Failure, CPLE_AppDefined, 
@@ -98,19 +99,6 @@ OGRDataSource *OGRPGDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPGDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRPG()                            */
 /************************************************************************/
 
@@ -119,6 +107,70 @@ void RegisterOGRPG()
 {
     if (! GDAL_CHECK_VERSION("PG driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPGDriver );
+    
+    if( GDALGetDriverByName( "PostgreSQL" ) == NULL )
+    {
+        GDALDriver* poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "PostgreSQL" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                  "PostgreSQL/PostGIS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                    "drv_pg.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "PG:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='DBNAME' type='string' description='Database name'/>"
+"  <Option name='PORT' type='int' description='Port'/>"
+"  <Option name='USER' type='string' description='User name'/>"
+"  <Option name='PASSWORD' type='string' description='Password'/>"
+"  <Option name='HOST' type='string' description='Server hostname'/>"
+"  <Option name='ACTIVE_SCHEMA' type='string' description='Active schema'/>"
+"  <Option name='SCHEMAS' type='string' description='Restricted sets of schemas to explore (comma separated)'/>"
+"  <Option name='TABLES' type='string' description='Restricted set of tables to list (comma separated)'/>"
+"  <Option name='LIST_ALL_TABLES' type='boolean' description='Whether all tables, including non-spatial ones, should be listed' default='NO'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='GEOM_TYPE' type='string-select' description='Format of geometry columns' default='geometry'>"
+"    <Value>geometry</Value>"
+"    <Value>geography</Value>"
+"    <Value>BYTEA</Value>"
+"    <Value>OID</Value>"
+"  </Option>"
+"  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+"  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+"  <Option name='PRECISION' type='boolean' description='Whether fields created should keep the width and precision' default='YES'/>"
+"  <Option name='DIM' type='integer' description='Set to 2 to force the geometries to be 2D, or 3 to be 2.5D'/>"
+"  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column. Defaults to wkb_geometry for GEOM_TYPE=geometry or the_geog for GEOM_TYPE=geography'/>"
+"  <Option name='SCHEMA' type='string' description='Name of schema into which to create the new table'/>"
+"  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
+"  <Option name='TEMPORARY' type='boolean' description='Whether to a temporary table instead of a permanent one' default='NO'/>"
+"  <Option name='UNLOGGED' type='boolean' description='Whether to create the table as a unlogged one' default='NO'/>"
+"  <Option name='NONE_AS_UNKNOWN' type='boolean' description='Whether to force non-spatial layers to be created as spatial tables' default='NO'/>"
+"  <Option name='FID' type='string' description='Name of the FID column to create' default='ogc_fid'/>"
+"  <Option name='FID64' type='boolean' description='Whether to create the FID column with BIGSERIAL type to handle 64bit wide ids' default='NO'/>"
+"  <Option name='EXTRACT_SCHEMA_FROM_LAYER_NAME' type='boolean' description='Whether a dot in a layer name should be considered as the separator for the schema and table name' default='YES'/>"
+"  <Option name='COLUMN_TYPES' type='string' description='A list of strings of format field_name=pg_field_type (separated by comma) to force the PG column type of fields to be created'/>"
+"</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time IntegerList Integer64List RealList StringList Binary" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->pfnOpen = OGRPGDriverOpen;
+        poDriver->pfnIdentify = OGRPGDriverIdentify;
+        poDriver->pfnCreate = OGRPGDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/pg/ogrpglayer.cpp b/ogr/ogrsf_frmts/pg/ogrpglayer.cpp
index 76abb29..4e39306 100644
--- a/ogr/ogrsf_frmts/pg/ogrpglayer.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpglayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpglayer.cpp 28445 2015-02-09 18:17:24Z rouault $
+ * $Id: ogrpglayer.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGLayer class  which implements shared handling
@@ -65,9 +65,7 @@ PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
 #define PQexec this_is_an_error
 
-CPL_CVSID("$Id: ogrpglayer.cpp 28445 2015-02-09 18:17:24Z rouault $");
-
-#define CURSOR_PAGE     500
+CPL_CVSID("$Id: ogrpglayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 // These originally are defined in libpq-fs.h.
 
@@ -88,21 +86,22 @@ OGRPGLayer::OGRPGLayer()
     bWkbAsOid = FALSE;
     pszQueryStatement = NULL;
 
-    bHasFid = FALSE;
     pszFIDColumn = NULL;
 
+    nCursorPage = atoi(CPLGetConfigOption("OGR_PG_CURSOR_PAGE", "500"));
     iNextShapeId = 0;
     nResultOffset = 0;
 
     pszCursorName = CPLStrdup(CPLSPrintf("OGRPGLayerReader%p", this));
 
     hCursorResult = NULL;
+    bInvalidated = FALSE;
 
     bCanUseBinaryCursor = TRUE;
 
     poFeatureDefn = NULL;
-    panMapFieldNameToIndex = NULL;
-    panMapFieldNameToGeomIndex = NULL;
+    m_panMapFieldNameToIndex = NULL;
+    m_panMapFieldNameToGeomIndex = NULL;
 }
 
 /************************************************************************/
@@ -123,8 +122,8 @@ OGRPGLayer::~OGRPGLayer()
 
     CPLFree( pszFIDColumn );
     CPLFree( pszQueryStatement );
-    CPLFree( panMapFieldNameToIndex );
-    CPLFree( panMapFieldNameToGeomIndex );
+    CPLFree( m_panMapFieldNameToIndex );
+    CPLFree( m_panMapFieldNameToGeomIndex );
     CPLFree( pszCursorName );
 
     if( poFeatureDefn )
@@ -149,16 +148,29 @@ void OGRPGLayer::CloseCursor()
         CPLString    osCommand;
         osCommand.Printf("CLOSE %s", pszCursorName );
 
-        hCursorResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+        /* In case of interleaving read in different layers we might have */
+        /* close the transaction, and thus implicitely the cursor, so be */
+        /* quiet about errors. This is potentially an issue by the way */
+        hCursorResult = OGRPG_PQexec(hPGConn, osCommand.c_str(), FALSE, TRUE);
         OGRPGClearResult( hCursorResult );
 
-        poDS->FlushSoftTransaction();
+        poDS->SoftCommitTransaction();
 
         hCursorResult = NULL;
     }
 }
 
 /************************************************************************/
+/*                       InvalidateCursor()                             */
+/************************************************************************/
+
+void OGRPGLayer::InvalidateCursor()
+{
+    CloseCursor();
+    bInvalidated = TRUE;
+}
+
+/************************************************************************/
 /*                            ResetReading()                            */
 /************************************************************************/
 
@@ -170,6 +182,7 @@ void OGRPGLayer::ResetReading()
     iNextShapeId = 0;
 
     CloseCursor();
+    bInvalidated = FALSE;
 }
 
 /************************************************************************/
@@ -400,11 +413,12 @@ do { \
 
 static
 int OGRPGTimeStamp2DMYHMS(GIntBig dt, int *year, int *month, int *day,
-                                      int* hour, int* min, int* sec)
+                                      int* hour, int* min, double* pdfSec)
 {
         GIntBig date;
 	GIntBig time;
-        double fsec;
+        int nSec;
+        double dfSec;
 
         time = dt;
 	TMODULO(time, date, USECS_PER_DAY);
@@ -423,7 +437,8 @@ int OGRPGTimeStamp2DMYHMS(GIntBig dt, int *year, int *month, int *day,
 		return -1;
 
 	OGRPGj2date((int) date, year, month, day);
-	OGRPGdt2timeInt8(time, hour, min, sec, &fsec);
+	OGRPGdt2timeInt8(time, hour, min, &nSec, &dfSec);
+        *pdfSec += nSec + dfSec;
 
         return 0;
 }
@@ -559,7 +574,10 @@ static char ** OGRPGTokenizeStringListFromText(const char* pszText)
 /*      a feature.                                                      */
 /************************************************************************/
 
-OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
+OGRFeature *OGRPGLayer::RecordToFeature( PGresult* hResult,
+                                         const int* panMapFieldNameToIndex,
+                                         const int* panMapFieldNameToGeomIndex,
+                                         int iRecord )
 
 {
 /* -------------------------------------------------------------------- */
@@ -575,32 +593,40 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
 /*      Transfer all result fields we can.                              */
 /* ==================================================================== */
     for( iField = 0;
-         iField < PQnfields(hCursorResult);
+         iField < PQnfields(hResult);
          iField++ )
     {
         int     iOGRField;
 
 #if !defined(PG_PRE74)
-        int nTypeOID = PQftype(hCursorResult, iField);
+        int nTypeOID = PQftype(hResult, iField);
 #endif
-        const char* pszFieldName = PQfname(hCursorResult,iField);
+        const char* pszFieldName = PQfname(hResult,iField);
 
 /* -------------------------------------------------------------------- */
 /*      Handle FID.                                                     */
 /* -------------------------------------------------------------------- */
-        if( bHasFid && EQUAL(pszFieldName,pszFIDColumn) )
+        if( pszFIDColumn != NULL && EQUAL(pszFieldName,pszFIDColumn) )
         {
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data representation
             {
                 if ( nTypeOID == INT4OID)
                 {
                     int nVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
-                    memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(int));
+                    memcpy( &nVal, PQgetvalue( hResult, iRecord, iField ), sizeof(int) );
                     CPL_MSBPTR32(&nVal);
                     poFeature->SetFID( nVal );
                 }
+                else if ( nTypeOID == INT8OID)
+                {
+                    GIntBig nVal;
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(GIntBig));
+                    memcpy( &nVal, PQgetvalue( hResult, iRecord, iField ), sizeof(GIntBig) );
+                    CPL_MSBPTR64(&nVal);
+                    poFeature->SetFID( nVal );
+                }
                 else
                 {
                     CPLDebug("PG", "FID. Unhandled OID %d.", nTypeOID );
@@ -610,10 +636,10 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             else
 #endif /* notdef PG_PRE74 */
             {
-                char* pabyData = PQgetvalue(hCursorResult,iRecord,iField);
+                char* pabyData = PQgetvalue(hResult,iRecord,iField);
                 /* ogr_pg_20 may crash if PostGIS is unavailable and we don't test pabyData */
                 if (pabyData)
-                    poFeature->SetFID( atoi(pabyData) );
+                    poFeature->SetFID( CPLAtoGIntBig(pabyData) );
                 else
                     continue;
             }
@@ -633,10 +659,10 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             if ( !poDS->bUseBinaryCursor &&
                  EQUALN(pszFieldName,"BinaryBase64", strlen("BinaryBase64")) )
             {
-                GByte* pabyData = (GByte*)PQgetvalue( hCursorResult,
+                GByte* pabyData = (GByte*)PQgetvalue( hResult,
                                                         iRecord, iField);
 
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
+                int nLength = PQgetlength(hResult, iRecord, iField);
 
                 /* No geometry */
                 if (nLength == 0)
@@ -644,7 +670,8 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
 
                 nLength = CPLBase64DecodeInPlace(pabyData);
                 OGRGeometry * poGeom = NULL;
-                OGRGeometryFactory::createFromWkb( pabyData, NULL, &poGeom, nLength );
+                OGRGeometryFactory::createFromWkb( pabyData, NULL, &poGeom, nLength,
+                                                   (poDS->sPostGISVersion.nMajor < 2) ? wkbVariantPostGIS1 : wkbVariantOldOgc );
 
                 if( poGeom != NULL )
                 {
@@ -657,11 +684,11 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             else if ( EQUALN(pszFieldName,"ST_AsBinary", strlen("ST_AsBinary")) ||
                       EQUALN(pszFieldName,"AsBinary", strlen("AsBinary")) )
             {
-                GByte* pabyVal = (GByte*) PQgetvalue( hCursorResult,
+                GByte* pabyVal = (GByte*) PQgetvalue( hResult,
                                              iRecord, iField);
                 const char* pszVal = (const char*) pabyVal;
 
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
+                int nLength = PQgetlength(hResult, iRecord, iField);
 
                 /* No geometry */
                 if (nLength == 0)
@@ -674,10 +701,11 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                     /* hex bytea data (PostgreSQL >= 9.0) */
                      strncmp(pszVal, "\\x00",4) == 0 || strncmp(pszVal, "\\x01",4) == 0) )
                 {
-                    poGeom = BYTEAToGeometry(pszVal);
+                    poGeom = BYTEAToGeometry(pszVal, (poDS->sPostGISVersion.nMajor < 2));
                 }
                 else
-                    OGRGeometryFactory::createFromWkb( pabyVal, NULL, &poGeom, nLength );
+                    OGRGeometryFactory::createFromWkb( pabyVal, NULL, &poGeom, nLength,
+                                                       (poDS->sPostGISVersion.nMajor < 2) ? wkbVariantPostGIS1 : wkbVariantOldOgc );
                 
                 if( poGeom != NULL )
                 {
@@ -690,17 +718,18 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             else if ( !poDS->bUseBinaryCursor &&
                       EQUALN(pszFieldName,"EWKBBase64",strlen("EWKBBase64")) )
             {
-                GByte* pabyData = (GByte*)PQgetvalue( hCursorResult,
+                GByte* pabyData = (GByte*)PQgetvalue( hResult,
                                                         iRecord, iField);
 
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
+                int nLength = PQgetlength(hResult, iRecord, iField);
 
                 /* No geometry */
                 if (nLength == 0)
                     continue;
 
                 nLength = CPLBase64DecodeInPlace(pabyData);
-                OGRGeometry * poGeom = OGRGeometryFromEWKB(pabyData, nLength, NULL);
+                OGRGeometry * poGeom = OGRGeometryFromEWKB(pabyData, nLength, NULL,
+                                                           poDS->sPostGISVersion.nMajor < 2);
 
                 if( poGeom != NULL )
                 {
@@ -715,10 +744,10 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                       EQUAL(pszFieldName,"AsEWKB") )
             {
                 /* Handle HEX result or EWKB binary cursor result */
-                char * pabyData = PQgetvalue( hCursorResult,
+                char * pabyData = PQgetvalue( hResult,
                                                         iRecord, iField);
 
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
+                int nLength = PQgetlength(hResult, iRecord, iField);
 
                 /* No geometry */
                 if (nLength == 0)
@@ -731,16 +760,19 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                      strncmp(pabyData, "\\000",4) == 0 || strncmp(pabyData, "\\001",4) == 0) )
                 {
                     GByte* pabyEWKB = BYTEAToGByteArray(pabyData, &nLength);
-                    poGeom = OGRGeometryFromEWKB(pabyEWKB, nLength, NULL);
+                    poGeom = OGRGeometryFromEWKB(pabyEWKB, nLength, NULL,
+                                                 poDS->sPostGISVersion.nMajor < 2);
                     CPLFree(pabyEWKB);
                 }
                 else if( nLength >= 2 && (EQUALN(pabyData,"00",2) || EQUALN(pabyData,"01",2)) )
                 {
-                    poGeom = OGRGeometryFromHexEWKB(pabyData, NULL);
+                    poGeom = OGRGeometryFromHexEWKB(pabyData, NULL,
+                                                    poDS->sPostGISVersion.nMajor < 2);
                 }
                 else
                 {
-                    poGeom = OGRGeometryFromEWKB((GByte*)pabyData, nLength, NULL);
+                    poGeom = OGRGeometryFromEWKB((GByte*)pabyData, nLength, NULL,
+                                                 poDS->sPostGISVersion.nMajor < 2);
                 }
 
                 if( poGeom != NULL )
@@ -761,7 +793,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 char        *pszPostSRID;
                 OGRGeometry *poGeometry = NULL;
 
-                pszWKT = PQgetvalue( hCursorResult, iRecord, iField );
+                pszWKT = PQgetvalue( hResult, iRecord, iField );
                 pszPostSRID = pszWKT;
 
                 // optionally strip off PostGIS SRID identifier.  This
@@ -776,7 +808,8 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
 
                 if( EQUALN(pszPostSRID,"00",2) || EQUALN(pszPostSRID,"01",2) )
                 {
-                    poGeometry = OGRGeometryFromHexEWKB( pszWKT, NULL );
+                    poGeometry = OGRGeometryFromHexEWKB( pszWKT, NULL,
+                                                         poDS->sPostGISVersion.nMajor < 2 );
                 }
                 else
                     OGRGeometryFactory::createFromWkt( &pszPostSRID, NULL,
@@ -798,7 +831,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                  poGeomFieldDefn->ePostgisType == GEOM_TYPE_WKB )
         {
             OGRGeometry *poGeometry = NULL;
-            GByte* pabyData = (GByte*) PQgetvalue( hCursorResult, iRecord, iField);
+            GByte* pabyData = (GByte*) PQgetvalue( hResult, iRecord, iField);
 
             if( bWkbAsOid )
             {
@@ -809,16 +842,18 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             {
                 if (poDS->bUseBinaryCursor
 #if !defined(PG_PRE74)
-                    && PQfformat( hCursorResult, iField ) == 1 
+                    && PQfformat( hResult, iField ) == 1 
 #endif
                    )
                 {
-                    int nLength = PQgetlength(hCursorResult, iRecord, iField);
-                    poGeometry = OGRGeometryFromEWKB(pabyData, nLength, NULL);
+                    int nLength = PQgetlength(hResult, iRecord, iField);
+                    poGeometry = OGRGeometryFromEWKB(pabyData, nLength, NULL,
+                                                     poDS->sPostGISVersion.nMajor < 2 );
                 }
                 if (poGeometry == NULL)
                 {
-                    poGeometry = BYTEAToGeometry( (const char*)pabyData );
+                    poGeometry = BYTEAToGeometry( (const char*)pabyData,
+                                                  (poDS->sPostGISVersion.nMajor < 2) );
                 }
             }
 
@@ -839,7 +874,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
         if( iOGRField < 0 )
             continue;
 
-        if( PQgetisnull( hCursorResult, iRecord, iField ) )
+        if( PQgetisnull( hResult, iRecord, iField ) )
             continue;
 
         OGRFieldType eOGRType = 
@@ -850,11 +885,11 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             int *panList, nCount, i;
 
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data representation
             {
                 if (nTypeOID == INT4ARRAYOID)
                 {
-                    char * pData = PQgetvalue( hCursorResult, iRecord, iField );
+                    char * pData = PQgetvalue( hResult, iRecord, iField );
 
                     // goto number of array elements
                     pData += 3 * sizeof(int);
@@ -893,14 +928,93 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             {
                 char **papszTokens;
                 papszTokens = CSLTokenizeStringComplex(
-                    PQgetvalue( hCursorResult, iRecord, iField ),
+                    PQgetvalue( hResult, iRecord, iField ),
                     "{,}", FALSE, FALSE );
 
                 nCount = CSLCount(papszTokens);
                 panList = (int *) CPLCalloc(sizeof(int),nCount);
 
-                for( i = 0; i < nCount; i++ )
-                    panList[i] = atoi(papszTokens[i]);
+                if( poFeatureDefn->GetFieldDefn(iOGRField)->GetSubType() == OFSTBoolean )
+                {
+                    for( i = 0; i < nCount; i++ )
+                        panList[i] = EQUAL(papszTokens[i], "t");
+                }
+                else
+                {
+                    for( i = 0; i < nCount; i++ )
+                        panList[i] = atoi(papszTokens[i]);
+                }
+                CSLDestroy( papszTokens );
+            }
+            poFeature->SetField( iOGRField, nCount, panList );
+            CPLFree( panList );
+        }
+
+        else if( eOGRType == OFTInteger64List)
+        {
+            GIntBig *panList;
+            int nCount, i;
+
+#if !defined(PG_PRE74)
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data representation
+            {
+                if (nTypeOID == INT8ARRAYOID)
+                {
+                    char * pData = PQgetvalue( hResult, iRecord, iField );
+
+                    // goto number of array elements
+                    pData += 3 * sizeof(int);
+                    memcpy( &nCount, pData, sizeof(int) );
+                    CPL_MSBPTR32( &nCount );
+
+                    panList = (GIntBig *) CPLCalloc(sizeof(GIntBig),nCount);
+
+                    // goto first array element
+                    pData += 2 * sizeof(int);
+
+                    for( i = 0; i < nCount; i++ )
+                    {
+                        // get element size
+                        int nSize = *(int *)(pData);
+                        CPL_MSBPTR32( &nSize );
+
+                        CPLAssert( nSize == sizeof(GIntBig) );
+
+                        pData += sizeof(int);
+
+                        memcpy( &panList[i], pData, nSize );
+                        CPL_MSBPTR64(&panList[i]);
+
+                        pData += nSize;
+                    }
+                }
+                else
+                {
+                    CPLDebug("PG", "Field %d: Incompatible OID (%d) with OFTInteger64List.", iOGRField, nTypeOID );
+                    continue;
+                }
+            }
+            else
+#endif /* notdef PG_PRE74 */
+            {
+                char **papszTokens;
+                papszTokens = CSLTokenizeStringComplex(
+                    PQgetvalue( hResult, iRecord, iField ),
+                    "{,}", FALSE, FALSE );
+
+                nCount = CSLCount(papszTokens);
+                panList = (GIntBig *) CPLCalloc(sizeof(GIntBig),nCount);
+
+                if( poFeatureDefn->GetFieldDefn(iOGRField)->GetSubType() == OFSTBoolean )
+                {
+                    for( i = 0; i < nCount; i++ )
+                        panList[i] = EQUAL(papszTokens[i], "t");
+                }
+                else
+                {
+                    for( i = 0; i < nCount; i++ )
+                        panList[i] = CPLAtoGIntBig(papszTokens[i]);
+                }
                 CSLDestroy( papszTokens );
             }
             poFeature->SetField( iOGRField, nCount, panList );
@@ -913,11 +1027,11 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             double *padfList;
 
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data representation
             {
                 if (nTypeOID == FLOAT8ARRAYOID || nTypeOID == FLOAT4ARRAYOID)
                 {
-                    char * pData = PQgetvalue( hCursorResult, iRecord, iField );
+                    char * pData = PQgetvalue( hResult, iRecord, iField );
 
                     // goto number of array elements
                     pData += 3 * sizeof(int);
@@ -969,7 +1083,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             {
                 char **papszTokens;
                 papszTokens = CSLTokenizeStringComplex(
-                    PQgetvalue( hCursorResult, iRecord, iField ),
+                    PQgetvalue( hResult, iRecord, iField ),
                     "{,}", FALSE, FALSE );
 
                 nCount = CSLCount(papszTokens);
@@ -989,9 +1103,9 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             char **papszTokens = 0;
 
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data representation
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data representation
             {
-                char * pData = PQgetvalue( hCursorResult, iRecord, iField );
+                char * pData = PQgetvalue( hResult, iRecord, iField );
                 int nCount, i;
 
                 // goto number of array elements
@@ -1033,7 +1147,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
 #endif /* notdef PG_PRE74 */
             {
                 papszTokens =
-                        OGRPGTokenizeStringListFromText(PQgetvalue(hCursorResult, iRecord, iField ));
+                        OGRPGTokenizeStringListFromText(PQgetvalue(hResult, iRecord, iField ));
             }
 
             if ( papszTokens )
@@ -1048,13 +1162,13 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                  || eOGRType == OFTDateTime )
         {
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 ) // Binary data
+            if ( PQfformat( hResult, iField ) == 1 ) // Binary data
             {
                 if ( nTypeOID == DATEOID )
                 {
                     int nVal, nYear, nMonth, nDay;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
-                    memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(int));
+                    memcpy( &nVal, PQgetvalue( hResult, iRecord, iField ), sizeof(int) );
                     CPL_MSBPTR32(&nVal);
                     OGRPGj2date(nVal + POSTGRES_EPOCH_JDATE, &nYear, &nMonth, &nDay);
                     poFeature->SetField( iOGRField, nYear, nMonth, nDay);
@@ -1064,12 +1178,12 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                     int nHour, nMinute, nSecond;
                     char szTime[32];
                     double dfsec;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == 8);
                     if (poDS->bBinaryTimeFormatIsInt8)
                     {
                         unsigned int nVal[2];
                         GIntBig llVal;
-                        memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
+                        memcpy( nVal, PQgetvalue( hResult, iRecord, iField ), 8 );
                         CPL_MSBPTR32(&nVal[0]);
                         CPL_MSBPTR32(&nVal[1]);
                         llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
@@ -1078,7 +1192,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                     else
                     {
                         double dfVal;
-                        memcpy( &dfVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
+                        memcpy( &dfVal, PQgetvalue( hResult, iRecord, iField ), 8 );
                         CPL_MSBPTR64(&dfVal);
                         OGRPGdt2timeFloat8(dfVal, &nHour, &nMinute, &nSecond, &dfsec);
                     }
@@ -1089,20 +1203,21 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 {
                     unsigned int nVal[2];
                     GIntBig llVal;
-                    int nYear, nMonth, nDay, nHour, nMinute, nSecond;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
-                    memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
+                    int nYear, nMonth, nDay, nHour, nMinute;
+                    double dfSecond;
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == 8);
+                    memcpy( nVal, PQgetvalue( hResult, iRecord, iField ), 8 );
                     CPL_MSBPTR32(&nVal[0]);
                     CPL_MSBPTR32(&nVal[1]);
                     llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
-                    if (OGRPGTimeStamp2DMYHMS(llVal, &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond) == 0)
-                        poFeature->SetField( iOGRField, nYear, nMonth, nDay, nHour, nMinute, nSecond);
+                    if (OGRPGTimeStamp2DMYHMS(llVal, &nYear, &nMonth, &nDay, &nHour, &nMinute, &dfSecond) == 0)
+                        poFeature->SetField( iOGRField, nYear, nMonth, nDay, nHour, nMinute, (float)dfSecond, 100);
                 }
                 else if ( nTypeOID == TEXTOID )
                 {
                     OGRField  sFieldValue;
 
-                    if( OGRParseDate( PQgetvalue( hCursorResult, iRecord, iField ),
+                    if( OGRParseDate( PQgetvalue( hResult, iRecord, iField ),
                                     &sFieldValue, 0 ) )
                     {
                         poFeature->SetField( iOGRField, &sFieldValue );
@@ -1118,7 +1233,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
             {
                 OGRField  sFieldValue;
 
-                if( OGRParseDate( PQgetvalue( hCursorResult, iRecord, iField ),
+                if( OGRParseDate( PQgetvalue( hResult, iRecord, iField ),
                                   &sFieldValue, 0 ) )
                 {
                     poFeature->SetField( iOGRField, &sFieldValue );
@@ -1128,17 +1243,17 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
         else if( eOGRType == OFTBinary )
         {
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1)
+            if ( PQfformat( hResult, iField ) == 1)
             {
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
-                GByte* pabyData = (GByte*) PQgetvalue( hCursorResult, iRecord, iField );
+                int nLength = PQgetlength(hResult, iRecord, iField);
+                GByte* pabyData = (GByte*) PQgetvalue( hResult, iRecord, iField );
                 poFeature->SetField( iOGRField, nLength, pabyData );
             }
             else
 #endif  /* notdef PG_PRE74 */
             {
-                int nLength = PQgetlength(hCursorResult, iRecord, iField);
-                const char* pszBytea = (const char*) PQgetvalue( hCursorResult, iRecord, iField );
+                int nLength = PQgetlength(hResult, iRecord, iField);
+                const char* pszBytea = (const char*) PQgetvalue( hResult, iRecord, iField );
                 GByte* pabyData = BYTEAToGByteArray( pszBytea, &nLength );
                 poFeature->SetField( iOGRField, nLength, pabyData );
                 CPLFree(pabyData);
@@ -1147,21 +1262,21 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
         else
         {
 #if !defined(PG_PRE74)
-            if ( PQfformat( hCursorResult, iField ) == 1 &&
+            if ( PQfformat( hResult, iField ) == 1 &&
                  eOGRType != OFTString ) // Binary data
             {
                 if ( nTypeOID == BOOLOID )
                 {
                     char cVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(char));
-                    cVal = *PQgetvalue( hCursorResult, iRecord, iField );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(char));
+                    cVal = *PQgetvalue( hResult, iRecord, iField );
                     poFeature->SetField( iOGRField, cVal );
                 }
                 else if ( nTypeOID == NUMERICOID )
                 {
                     unsigned short sLen, sSign, sDscale;
                     short sWeight;
-                    char* pabyData = PQgetvalue( hCursorResult, iRecord, iField );
+                    char* pabyData = PQgetvalue( hResult, iRecord, iField );
                     memcpy( &sLen, pabyData, sizeof(short));
                     pabyData += sizeof(short);
                     CPL_MSBPTR16(&sLen);
@@ -1174,7 +1289,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                     memcpy( &sDscale, pabyData, sizeof(short));
                     pabyData += sizeof(short);
                     CPL_MSBPTR16(&sDscale);
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == (int)((4 + sLen) * sizeof(short)));
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == (int)((4 + sLen) * sizeof(short)));
 
                     NumericVar var;
                     var.ndigits = sLen;
@@ -1189,16 +1304,16 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 else if ( nTypeOID == INT2OID )
                 {
                     short sVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(short));
-                    memcpy( &sVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(short) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(short));
+                    memcpy( &sVal, PQgetvalue( hResult, iRecord, iField ), sizeof(short) );
                     CPL_MSBPTR16(&sVal);
                     poFeature->SetField( iOGRField, sVal );
                 }
                 else if ( nTypeOID == INT4OID )
                 {
                     int nVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(int));
-                    memcpy( &nVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(int) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(int));
+                    memcpy( &nVal, PQgetvalue( hResult, iRecord, iField ), sizeof(int) );
                     CPL_MSBPTR32(&nVal);
                     poFeature->SetField( iOGRField, nVal );
                 }
@@ -1206,33 +1321,34 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 {
                     unsigned int nVal[2];
                     GIntBig llVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == 8);
-                    memcpy( nVal, PQgetvalue( hCursorResult, iRecord, iField ), 8 );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == 8);
+                    memcpy( nVal, PQgetvalue( hResult, iRecord, iField ), 8 );
                     CPL_MSBPTR32(&nVal[0]);
                     CPL_MSBPTR32(&nVal[1]);
                     llVal = (GIntBig) ((((GUIntBig)nVal[0]) << 32) | nVal[1]);
-                    /* FIXME : 64bit -> 32bit conversion */
-                    poFeature->SetField( iOGRField, (int)llVal );
+                    poFeature->SetField( iOGRField, llVal );
                 }
                 else if ( nTypeOID == FLOAT4OID )
                 {
                     float fVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(float));
-                    memcpy( &fVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(float) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(float));
+                    memcpy( &fVal, PQgetvalue( hResult, iRecord, iField ), sizeof(float) );
                     CPL_MSBPTR32(&fVal);
                     poFeature->SetField( iOGRField, fVal );
                 }
                 else if ( nTypeOID == FLOAT8OID )
                 {
                     double dfVal;
-                    CPLAssert(PQgetlength(hCursorResult, iRecord, iField) == sizeof(double));
-                    memcpy( &dfVal, PQgetvalue( hCursorResult, iRecord, iField ), sizeof(double) );
+                    CPLAssert(PQgetlength(hResult, iRecord, iField) == sizeof(double));
+                    memcpy( &dfVal, PQgetvalue( hResult, iRecord, iField ), sizeof(double) );
                     CPL_MSBPTR64(&dfVal);
                     poFeature->SetField( iOGRField, dfVal );
                 }
                 else
                 {
-                    CPLDebug("PG", "Field %d: Incompatible OID (%d) with %s.", iOGRField, nTypeOID,
+                    CPLDebug("PG", "Field %d(%s): Incompatible OID (%d) with %s.",
+                             iOGRField, poFeatureDefn->GetFieldDefn(iOGRField)->GetNameRef(),
+                             nTypeOID,
                              OGRFieldDefn::GetFieldTypeName( eOGRType ));
                     continue;
                 }
@@ -1243,7 +1359,7 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 if ( eOGRType == OFTInteger &&
                      poFeatureDefn->GetFieldDefn(iOGRField)->GetWidth() == 1)
                 {
-                    char* pabyData = PQgetvalue( hCursorResult, iRecord, iField );
+                    char* pabyData = PQgetvalue( hResult, iRecord, iField );
                     if (EQUALN(pabyData, "T", 1))
                         poFeature->SetField( iOGRField, 1);
                     else if (EQUALN(pabyData, "F", 1))
@@ -1254,12 +1370,12 @@ OGRFeature *OGRPGLayer::RecordToFeature( int iRecord )
                 else if ( eOGRType == OFTReal )
                 {
                     poFeature->SetField( iOGRField,
-                                CPLAtof(PQgetvalue( hCursorResult, iRecord, iField )) );
+                                CPLAtof(PQgetvalue( hResult, iRecord, iField )) );
                 }
                 else
                 {
                     poFeature->SetField( iOGRField,
-                                        PQgetvalue( hCursorResult, iRecord, iField ) );
+                                        PQgetvalue( hResult, iRecord, iField ) );
                 }
             }
         }
@@ -1294,23 +1410,26 @@ static int OGRPGIsKnownGeomFuncPrefix(const char* pszFieldName)
 /* expensive if the layer has many fields (total complexity of O(n^2) where */
 /* n is the number of fields), so it is valuable to compute the map from */
 /* the fetched fields to the OGR field index */
-void OGRPGLayer::CreateMapFromFieldNameToIndex()
+void OGRPGLayer::CreateMapFromFieldNameToIndex(PGresult* hResult,
+                                               OGRFeatureDefn* poFeatureDefn,
+                                               int*& panMapFieldNameToIndex,
+                                               int*& panMapFieldNameToGeomIndex)
 {
     CPLFree(panMapFieldNameToIndex);
     panMapFieldNameToIndex = NULL;
     CPLFree(panMapFieldNameToGeomIndex);
     panMapFieldNameToGeomIndex = NULL;
-    if ( PQresultStatus(hCursorResult)  == PGRES_TUPLES_OK )
+    if ( PQresultStatus(hResult)  == PGRES_TUPLES_OK )
     {
         panMapFieldNameToIndex =
-                (int*)CPLMalloc(sizeof(int) * PQnfields(hCursorResult));
+                (int*)CPLMalloc(sizeof(int) * PQnfields(hResult));
         panMapFieldNameToGeomIndex =
-                (int*)CPLMalloc(sizeof(int) * PQnfields(hCursorResult));
+                (int*)CPLMalloc(sizeof(int) * PQnfields(hResult));
         for( int iField = 0;
-            iField < PQnfields(hCursorResult);
+            iField < PQnfields(hResult);
             iField++ )
         {
-            const char* pszName = PQfname(hCursorResult,iField);
+            const char* pszName = PQfname(hResult,iField);
             panMapFieldNameToIndex[iField] =
                     poFeatureDefn->GetFieldIndex(pszName);
             if( panMapFieldNameToIndex[iField] < 0 )
@@ -1347,15 +1466,6 @@ void OGRPGLayer::SetInitialQueryCursor()
 
     CPLAssert( pszQueryStatement != NULL );
 
-    poDS->FlushSoftTransaction();
-
-    // Workaround a bug in tables= mode where the spatial ref
-    // hasn't yet been resolved. Doing so later during the FETCH transaction
-    // will fail due to the BEGIN / COMMIT involved in SRS resolution
-    // Ultimately we should reconsider all this transaction logic
-    for(int i=0;i<poFeatureDefn->GetGeomFieldCount();i++)
-        poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef();
-
     poDS->SoftStartTransaction();
 
     if ( poDS->bUseBinaryCursor && bCanUseBinaryCursor )
@@ -1370,13 +1480,17 @@ void OGRPGLayer::SetInitialQueryCursor()
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "%s", PQerrorMessage( hPGConn ) );
+        poDS->SoftRollbackTransaction();
     }
     OGRPGClearResult( hCursorResult );
 
-    osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
+    osCommand.Printf( "FETCH %d in %s", nCursorPage, pszCursorName );
     hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
 
-    CreateMapFromFieldNameToIndex();
+    CreateMapFromFieldNameToIndex(hCursorResult,
+                                  poFeatureDefn,
+                                  m_panMapFieldNameToIndex,
+                                  m_panMapFieldNameToGeomIndex);
 
     nResultOffset = 0;
 }
@@ -1391,6 +1505,14 @@ OGRFeature *OGRPGLayer::GetNextRawFeature()
     PGconn      *hPGConn = poDS->GetPGConn();
     CPLString   osCommand;
 
+    if( bInvalidated )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cursor used to read layer has been closed due to a COMMIT. "
+                 "ResetReading() must be explicitely called to restart reading");
+        return NULL;
+    }
+    
 /* -------------------------------------------------------------------- */
 /*      Do we need to establish an initial query?                       */
 /* -------------------------------------------------------------------- */
@@ -1419,12 +1541,12 @@ OGRFeature *OGRPGLayer::GetNextRawFeature()
 
     /* We test for PQntuples(hCursorResult) == 1 in the case the previous */
     /* request was a SetNextByIndex() */
-    if( (PQntuples(hCursorResult) == 1 || PQntuples(hCursorResult) == CURSOR_PAGE) &&
+    if( (PQntuples(hCursorResult) == 1 || PQntuples(hCursorResult) == nCursorPage) &&
         nResultOffset == PQntuples(hCursorResult) )
     {
         OGRPGClearResult( hCursorResult );
         
-        osCommand.Printf( "FETCH %d in %s", CURSOR_PAGE, pszCursorName );
+        osCommand.Printf( "FETCH %d in %s", nCursorPage, pszCursorName );
         hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
 
         nResultOffset = 0;
@@ -1447,7 +1569,10 @@ OGRFeature *OGRPGLayer::GetNextRawFeature()
 /* -------------------------------------------------------------------- */
 /*      Create a feature from the current result.                       */
 /* -------------------------------------------------------------------- */
-    OGRFeature *poFeature = RecordToFeature( nResultOffset );
+    OGRFeature *poFeature = RecordToFeature( hCursorResult,
+                                             m_panMapFieldNameToIndex,
+                                             m_panMapFieldNameToGeomIndex,
+                                             nResultOffset );
 
     nResultOffset++;
     iNextShapeId++;
@@ -1459,7 +1584,7 @@ OGRFeature *OGRPGLayer::GetNextRawFeature()
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr OGRPGLayer::SetNextByIndex( long nIndex )
+OGRErr OGRPGLayer::SetNextByIndex( GIntBig nIndex )
 
 {
     GetLayerDefn();
@@ -1494,14 +1619,14 @@ OGRErr OGRPGLayer::SetNextByIndex( long nIndex )
     
     OGRPGClearResult( hCursorResult );
     
-    osCommand.Printf( "FETCH ABSOLUTE %ld in %s", nIndex+1, pszCursorName );
+    osCommand.Printf( "FETCH ABSOLUTE " CPL_FRMT_GIB " in %s", nIndex+1, pszCursorName );
     hCursorResult = OGRPG_PQexec(hPGConn, osCommand );
 
     if (PQresultStatus(hCursorResult) != PGRES_TUPLES_OK ||
         PQntuples(hCursorResult) != 1)
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to read feature at invalid index (%ld).", nIndex );
+                  "Attempt to read feature at invalid index (" CPL_FRMT_GIB ").", nIndex );
 
         CloseCursor();
 
@@ -1577,7 +1702,7 @@ GByte* OGRPGLayer::BYTEAToGByteArray( const char *pszBytea, int* pnLength )
 /*                          BYTEAToGeometry()                           */
 /************************************************************************/
 
-OGRGeometry *OGRPGLayer::BYTEAToGeometry( const char *pszBytea )
+OGRGeometry *OGRPGLayer::BYTEAToGeometry( const char *pszBytea, int bIsPostGIS1 )
 
 {
     GByte       *pabyWKB;
@@ -1590,7 +1715,8 @@ OGRGeometry *OGRPGLayer::BYTEAToGeometry( const char *pszBytea )
     pabyWKB = BYTEAToGByteArray(pszBytea, &nLen);
 
     poGeometry = NULL;
-    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLen );
+    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nLen,
+                                       (bIsPostGIS1) ? wkbVariantPostGIS1 : wkbVariantOldOgc );
 
     CPLFree( pabyWKB );
     return poGeometry;
@@ -1629,7 +1755,7 @@ char* OGRPGLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
 /*                          GeometryToBYTEA()                           */
 /************************************************************************/
 
-char *OGRPGLayer::GeometryToBYTEA( OGRGeometry * poGeometry )
+char *OGRPGLayer::GeometryToBYTEA( OGRGeometry * poGeometry, int bIsPostGIS1 )
 
 {
     int         nWkbSize = poGeometry->WkbSize();
@@ -1637,7 +1763,8 @@ char *OGRPGLayer::GeometryToBYTEA( OGRGeometry * poGeometry )
     char        *pszTextBuf;
 
     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
-    if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
+    if( poGeometry->exportToWkb( wkbNDR, pabyWKB,
+                                 (bIsPostGIS1) ? wkbVariantPostGIS1 : wkbVariantOldOgc ) != OGRERR_NONE )
     {
         CPLFree(pabyWKB);
         return CPLStrdup("");
@@ -1675,7 +1802,8 @@ OGRGeometry *OGRPGLayer::OIDToGeometry( Oid oid )
     lo_close( hPGConn, fd );
 
     poGeometry = NULL;
-    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nBytes );
+    OGRGeometryFactory::createFromWkb( pabyWKB, NULL, &poGeometry, nBytes,
+                                       (poDS->sPostGISVersion.nMajor < 2) ? wkbVariantPostGIS1 : wkbVariantOldOgc );
 
     CPLFree( pabyWKB );
 
@@ -1696,7 +1824,8 @@ Oid OGRPGLayer::GeometryToOID( OGRGeometry * poGeometry )
     int         fd, nBytesWritten;
 
     pabyWKB = (GByte *) CPLMalloc(nWkbSize);
-    if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
+    if( poGeometry->exportToWkb( wkbNDR, pabyWKB,
+                                 (poDS->sPostGISVersion.nMajor < 2) ? wkbVariantPostGIS1 : wkbVariantOldOgc ) != OGRERR_NONE )
         return 0;
 
     oid = lo_creat( hPGConn, INV_READ|INV_WRITE );
@@ -1724,7 +1853,7 @@ Oid OGRPGLayer::GeometryToOID( OGRGeometry * poGeometry )
 OGRErr OGRPGLayer::StartTransaction()
 
 {
-    return poDS->SoftStartTransaction();
+    return poDS->StartTransaction();
 }
 
 /************************************************************************/
@@ -1734,7 +1863,7 @@ OGRErr OGRPGLayer::StartTransaction()
 OGRErr OGRPGLayer::CommitTransaction()
 
 {
-    return poDS->SoftCommit();
+    return poDS->CommitTransaction();
 }
 
 /************************************************************************/
@@ -1744,7 +1873,7 @@ OGRErr OGRPGLayer::CommitTransaction()
 OGRErr OGRPGLayer::RollbackTransaction()
 
 {
-    return poDS->SoftRollback();
+    return poDS->RollbackTransaction();
 }
 
 /************************************************************************/
@@ -1812,7 +1941,7 @@ OGRErr OGRPGLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce
 
     if( osCommand.size() != 0 )
     {
-        if( RunGetExtentRequest(psExtent, bForce, osCommand) == OGRERR_NONE )
+        if( RunGetExtentRequest(psExtent, bForce, osCommand, FALSE) == OGRERR_NONE )
             return OGRERR_NONE;
     }
     if( iGeomField == 0 )
@@ -1827,7 +1956,8 @@ OGRErr OGRPGLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce
 
 OGRErr OGRPGLayer::RunGetExtentRequest( OGREnvelope *psExtent,
                                         CPL_UNUSED int bForce,
-                                        CPLString osCommand)
+                                        CPLString osCommand,
+                                        int bErrorAsDebug )
 {
     if ( psExtent == NULL )
         return OGRERR_FAILURE;
@@ -1835,7 +1965,7 @@ OGRErr OGRPGLayer::RunGetExtentRequest( OGREnvelope *psExtent,
     PGconn      *hPGConn = poDS->GetPGConn();
     PGresult    *hResult = NULL;
 
-    hResult = OGRPG_PQexec( hPGConn, osCommand );
+    hResult = OGRPG_PQexec( hPGConn, osCommand, FALSE, bErrorAsDebug );
     if( ! hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK || PQgetisnull(hResult,0,0) )
     {
         OGRPGClearResult( hResult );
@@ -1918,6 +2048,7 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
 /*      Parse the returned table information.                           */
 /* -------------------------------------------------------------------- */
     poFeatureDefn = new OGRPGFeatureDefn( "sql_statement" );
+    SetDescription( poFeatureDefn->GetName() );
     int            iRawField;
 
     poFeatureDefn->Reference();
@@ -1932,12 +2063,11 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
         int iGeomFuncPrefix;
         if( EQUAL(oField.GetNameRef(),"ogc_fid") )
         {
-            if (bHasFid)
+            if (pszFIDColumn)
             {
                 CPLError(CE_Warning, CPLE_AppDefined,
                          "More than one ogc_fid column was found in the result of the SQL request. Only last one will be used");
             }
-            bHasFid = TRUE;
             CPLFree(pszFIDColumn);
             pszFIDColumn = CPLStrdup(oField.GetNameRef());
             continue;
@@ -1976,6 +2106,8 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
             poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
             continue;
         }
+            
+        //CPLDebug("PG", "Field %s, oid %d", oField.GetNameRef(), nTypeOID);
 
         if( nTypeOID == BYTEAOID )
         {
@@ -2000,11 +2132,13 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
         else if( nTypeOID == BOOLOID )
         {
             oField.SetType( OFTInteger );
+            oField.SetSubType( OFSTBoolean );
             oField.SetWidth( 1 );
         }
         else if (nTypeOID == INT2OID )
         {
             oField.SetType( OFTInteger );
+            oField.SetSubType( OFSTInt16 );
             oField.SetWidth( 5 );
         }
         else if (nTypeOID == INT4OID )
@@ -2013,11 +2147,14 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
         }
         else if ( nTypeOID == INT8OID )
         {
-            /* FIXME: OFTInteger can not handle 64bit integers */
-            oField.SetType( OFTInteger );
+            oField.SetType( OFTInteger64 );
+        }
+        else if( nTypeOID == FLOAT4OID )
+        {
+            oField.SetType( OFTReal );
+            oField.SetSubType( OFSTFloat32 );
         }
-        else if( nTypeOID == FLOAT4OID ||
-                 nTypeOID == FLOAT8OID )
+        else if( nTypeOID == FLOAT8OID )
         {
             oField.SetType( OFTReal );
         }
@@ -2045,10 +2182,20 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
             else
                 oField.SetType( OFTReal );
         }
+        else if ( nTypeOID == BOOLARRAYOID )
+        {
+            oField.SetType ( OFTIntegerList );
+            oField.SetSubType( OFSTBoolean );
+            oField.SetWidth( 1 );
+        }
         else if ( nTypeOID == INT4ARRAYOID )
         {
             oField.SetType ( OFTIntegerList );
         }
+        else if ( nTypeOID == INT8ARRAYOID )
+        {
+            oField.SetType ( OFTInteger64List );
+        }
         else if ( nTypeOID == FLOAT4ARRAYOID ||
                   nTypeOID == FLOAT8ARRAYOID )
         {
@@ -2080,7 +2227,8 @@ int OGRPGLayer::ReadResultDefinition(PGresult *hInitialResultIn)
         }
         else /* unknown type */
         {
-            CPLDebug("PG", "Unhandled OID (%d) for column %d. Defaulting to String.", nTypeOID, iRawField);
+            CPLDebug("PG", "Unhandled OID (%d) for column %s. Defaulting to String.",
+                     nTypeOID, oField.GetNameRef());
             oField.SetType( OFTString );
         }
 
diff --git a/ogr/ogrsf_frmts/pg/ogrpgresultlayer.cpp b/ogr/ogrsf_frmts/pg/ogrpgresultlayer.cpp
index 7e2b19f..88e50f9 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgresultlayer.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpgresultlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgresultlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpgresultlayer.cpp 28481 2015-02-13 17:11:15Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGResultLayer class, access the resultset from
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_pg.h"
 
-CPL_CVSID("$Id: ogrpgresultlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpgresultlayer.cpp 28481 2015-02-13 17:11:15Z rouault $");
 
 #define PQexec this_is_an_error
 
@@ -60,19 +60,60 @@ OGRPGResultLayer::OGRPGResultLayer( OGRPGDataSource *poDSIn,
     pszGeomTableSchemaName = NULL;
 
     /* Find at which index the geometry column is */
+    /* and prepare a request to identify not-nullable fields */
     int iGeomCol = -1;
-    if (poFeatureDefn->GetGeomFieldCount() == 1)
+    CPLString osRequest;
+    std::map< std::pair<int,int>, int> oMapAttributeToFieldIndex;
+
+    int iRawField;
+    for( iRawField = 0; iRawField < PQnfields(hInitialResultIn); iRawField++ )
     {
-        int iRawField;
-        for( iRawField = 0; iRawField < PQnfields(hInitialResultIn); iRawField++ )
+        if( poFeatureDefn->GetGeomFieldCount() == 1 &&
+            strcmp(PQfname(hInitialResultIn,iRawField),
+                poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef()) == 0 )
+        {
+            iGeomCol = iRawField;
+        }
+
+        Oid tableOID = PQftable(hInitialResultIn, iRawField);
+        int tableCol = PQftablecol(hInitialResultIn, iRawField);
+        if( tableOID != InvalidOid && tableCol > 0 )
         {
-            if( strcmp(PQfname(hInitialResultIn,iRawField),
-                    poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef()) == 0 )
+            if( osRequest.size() )
+                osRequest += " OR ";
+            osRequest += "(attrelid = ";
+            osRequest += CPLSPrintf("%d", tableOID); 
+            osRequest += " AND attnum = ";
+            osRequest += CPLSPrintf("%d)", tableCol); 
+            oMapAttributeToFieldIndex[std::pair<int,int>(tableOID,tableCol)] = iRawField;
+        }
+    }
+
+    if( osRequest.size() )
+    {
+        osRequest = "SELECT attnum, attrelid FROM pg_attribute WHERE attnotnull = 't' AND (" + osRequest + ")";
+        PGresult* hResult = OGRPG_PQexec(poDS->GetPGConn(), osRequest );
+        if( hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK)
+        {
+            int iCol;
+            for( iCol = 0; iCol < PQntuples(hResult); iCol++ )
             {
-                iGeomCol = iRawField;
-                break;
+                const char* pszAttNum = PQgetvalue(hResult,iCol,0);
+                const char* pszAttRelid = PQgetvalue(hResult,iCol,1);
+                int iRawField = oMapAttributeToFieldIndex[std::pair<int,int>(atoi(pszAttRelid),atoi(pszAttNum))];
+                const char* pszFieldname = PQfname(hInitialResultIn,iRawField);
+                int iFieldIdx = poFeatureDefn->GetFieldIndex(pszFieldname);
+                if( iFieldIdx >= 0 )
+                    poFeatureDefn->GetFieldDefn(iFieldIdx)->SetNullable(FALSE);
+                else
+                {
+                    iFieldIdx = poFeatureDefn->GetGeomFieldIndex(pszFieldname);
+                    if( iFieldIdx >= 0 )
+                        poFeatureDefn->GetGeomFieldDefn(iFieldIdx)->SetNullable(FALSE);
+                }
             }
         }
+        OGRPGClearResult( hResult );
     }
 
 #ifndef PG_PRE74
@@ -149,7 +190,7 @@ void OGRPGResultLayer::ResetReading()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRPGResultLayer::GetFeatureCount( int bForce )
+GIntBig OGRPGResultLayer::GetFeatureCount( int bForce )
 
 {
     if( TestCapability(OLCFastFeatureCount) == FALSE )
@@ -286,7 +327,6 @@ void OGRPGResultLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn
             {
                 char szBox3D_1[128];
                 char szBox3D_2[128];
-                char* pszComma;
                 OGREnvelope  sEnvelope;
 
                 m_poFilterGeom->getEnvelope( &sEnvelope );
@@ -301,12 +341,8 @@ void OGRPGResultLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn
                     if( sEnvelope.MaxY > 90.0 )
                         sEnvelope.MaxY = 90.0;
                 }
-                snprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
-                while((pszComma = strchr(szBox3D_1, ',')) != NULL)
-                    *pszComma = '.';
-                snprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
-                while((pszComma = strchr(szBox3D_2, ',')) != NULL)
-                    *pszComma = '.';
+                CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
+                CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
                 osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
                                OGRPGEscapeColumnName(poGeomFieldDefn->GetNameRef()).c_str(),
                                (poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
diff --git a/ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp b/ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp
index 5013e80..d4034a0 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpgtablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgtablelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgtablelayer.cpp 28995 2015-04-24 15:56:15Z rouault $
 
  *
  * Project:  OpenGIS Simple Features Reference Implementation
@@ -37,12 +37,10 @@
 
 #define PQexec this_is_an_error
 
-CPL_CVSID("$Id: ogrpgtablelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgtablelayer.cpp 28995 2015-04-24 15:56:15Z rouault $");
 
 
 #define USE_COPY_UNSET  -10
-static CPLString OGRPGEscapeStringList(PGconn *hPGConn,
-                                       char** papszItems, int bForInsertOrUpdate);
 
 #define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
 
@@ -137,24 +135,21 @@ OGRPGTableLayer::OGRPGTableLayer( OGRPGDataSource *poDSIn,
 
     bUpdateAccess = bUpdate;
 
-    iNextShapeId = 0;
-
     bGeometryInformationSet = FALSE;
 
     bLaunderColumnNames = TRUE;
     bPreservePrecision = TRUE;
     bCopyActive = FALSE;
     bUseCopy = USE_COPY_UNSET;  // unknown
+    bUseCopyByDefault = FALSE;
     bFIDColumnInCopyFields = FALSE;
     bFirstInsertion = TRUE;
 
     pszTableName = CPLStrdup( pszTableNameIn );
     if (pszSchemaNameIn)
         pszSchemaName = CPLStrdup( pszSchemaNameIn );
-    else if (strlen(osCurrentSchema))
-        pszSchemaName = CPLStrdup( osCurrentSchema );
     else
-        pszSchemaName = NULL;
+        pszSchemaName = CPLStrdup( osCurrentSchema );
     this->pszGeomColForced =
         pszGeomColForced ? CPLStrdup(pszGeomColForced) : NULL;
 
@@ -200,7 +195,13 @@ OGRPGTableLayer::OGRPGTableLayer( OGRPGDataSource *poDSIn,
     bInResetReading = FALSE;
 
     poFeatureDefn = new OGRPGTableFeatureDefn( this, osDefnName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
+    
+    bAutoFIDOnCreateViaCopy = FALSE;
+    
+    bDifferedCreation = FALSE;
+    iFIDAsRegularColumnIndex = -1;
 }
 
 //************************************************************************/
@@ -210,7 +211,8 @@ OGRPGTableLayer::OGRPGTableLayer( OGRPGDataSource *poDSIn,
 OGRPGTableLayer::~OGRPGTableLayer()
 
 {
-    EndCopy();
+    if( bDifferedCreation ) RunDifferedCreationIfNecessary();
+    if ( bCopyActive ) EndCopy();
     CPLFree( pszSqlTableName );
     CPLFree( pszTableName );
     CPLFree( pszSqlGeomParentTableName );
@@ -233,6 +235,7 @@ void  OGRPGTableLayer::SetGeometryInformation(PGGeomColumnDesc* pasDesc,
     {
         OGRPGGeomFieldDefn* poGeomFieldDefn =
             new OGRPGGeomFieldDefn(this, pasDesc[i].pszName);
+        poGeomFieldDefn->SetNullable(pasDesc[i].bNullable);
         poGeomFieldDefn->nSRSId = pasDesc[i].nSRID;
         poGeomFieldDefn->nCoordDimension = pasDesc[i].nCoordDimension;
         poGeomFieldDefn->ePostgisType = pasDesc[i].ePostgisType;
@@ -240,7 +243,7 @@ void  OGRPGTableLayer::SetGeometryInformation(PGGeomColumnDesc* pasDesc,
         {
             OGRwkbGeometryType eGeomType = OGRFromOGCGeomType(pasDesc[i].pszGeomType);
             if( poGeomFieldDefn->nCoordDimension == 3 && eGeomType != wkbUnknown )
-                eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
+                eGeomType = wkbSetZ(eGeomType);
             poGeomFieldDefn->SetType(eGeomType);
         }
         poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
@@ -266,18 +269,25 @@ int OGRPGTableLayer::ReadTableDefinition()
         return bTableDefinitionValid;
     bTableDefinitionValid = FALSE;
 
-    poDS->FlushSoftTransaction();
-
     CPLString osSchemaClause;
-    if( pszSchemaName )
-        osSchemaClause.Printf("AND n.nspname=%s",
+    osSchemaClause.Printf("AND n.nspname=%s",
                               OGRPGEscapeString(hPGConn, pszSchemaName).c_str());
 
     const char* pszTypnameEqualsAnyClause;
     if (poDS->sPostgreSQLVersion.nMajor == 7 && poDS->sPostgreSQLVersion.nMinor <= 3)
-        pszTypnameEqualsAnyClause = "ANY(SELECT '{int2, int4, serial}')";
+        pszTypnameEqualsAnyClause = "ANY(SELECT '{int2, int4, int8, serial, bigserial}')";
+    else
+        pszTypnameEqualsAnyClause = "ANY(ARRAY['int2','int4','int8','serial','bigserial'])";
+    
+    const char* pszAttnumEqualAnyIndkey;
+    if( poDS->sPostgreSQLVersion.nMajor > 8 || (
+        poDS->sPostgreSQLVersion.nMajor == 8 && poDS->sPostgreSQLVersion.nMinor >= 2) )
+        pszAttnumEqualAnyIndkey = "a.attnum = ANY(i.indkey)";
     else
-        pszTypnameEqualsAnyClause = "ANY(ARRAY['int2','int4','serial'])";
+        pszAttnumEqualAnyIndkey = "(i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
+              "OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
+              "OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
+              "OR i.indkey[9]=a.attnum)";
 
     CPLString osEscapedTableNameSingleQuote = OGRPGEscapeString(hPGConn, pszTableName);
     const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
@@ -290,11 +300,9 @@ int OGRPGTableLayer::ReadTableDefinition()
               "AND a.atttypid = t.oid AND c.relnamespace = n.oid "
               "AND c.oid = i.indrelid AND i.indisprimary = 't' "
               "AND t.typname !~ '^geom' AND c.relname = %s "
-              "AND (i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
-              "OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
-              "OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
-              "OR i.indkey[9]=a.attnum) %s ORDER BY a.attnum",
-              pszTypnameEqualsAnyClause, pszEscapedTableNameSingleQuote, osSchemaClause.c_str() );
+              "AND %s %s ORDER BY a.attnum",
+              pszTypnameEqualsAnyClause, pszEscapedTableNameSingleQuote,
+              pszAttnumEqualAnyIndkey, osSchemaClause.c_str() );
      
     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
 
@@ -302,12 +310,16 @@ int OGRPGTableLayer::ReadTableDefinition()
     {
         if ( PQntuples( hResult ) == 1 && PQgetisnull( hResult,0,0 ) == false )
         {
-            /* Check if single-field PK can be represented as 32-bit integer. */
+            /* Check if single-field PK can be represented as integer. */
             CPLString osValue(PQgetvalue(hResult, 0, 3));
             if( osValue == "t" )
             {
                 osPrimaryKey.Printf( "%s", PQgetvalue(hResult,0,0) );
-                CPLDebug( "PG", "Primary key name (FID): %s", osPrimaryKey.c_str() );
+                const char* pszFIDType = PQgetvalue(hResult, 0, 2);
+                CPLDebug( "PG", "Primary key name (FID): %s, type : %s",
+                          osPrimaryKey.c_str(), pszFIDType );
+                if( EQUAL(pszFIDType, "int8") )
+                    SetMetadataItem(OLMD_FID64, "YES");
             }
         }
         else if ( PQntuples( hResult ) > 1 )
@@ -329,33 +341,19 @@ int OGRPGTableLayer::ReadTableDefinition()
 /* -------------------------------------------------------------------- */
 /*      Fire off commands to get back the columns of the table.          */
 /* -------------------------------------------------------------------- */
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-
-    if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
-    {
-        OGRPGClearResult( hResult );
-
-        osCommand.Printf(
-                 "DECLARE mycursor CURSOR for "
-                 "SELECT DISTINCT a.attname, t.typname, a.attlen,"
-                 "       format_type(a.atttypid,a.atttypmod), a.attnum "
-                 "FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n "
-                 "WHERE c.relname = %s "
-                 "AND a.attnum > 0 AND a.attrelid = c.oid "
-                 "AND a.atttypid = t.oid "
-                 "AND c.relnamespace=n.oid "
-                 "%s "
-                 "ORDER BY a.attnum",
-                 pszEscapedTableNameSingleQuote, osSchemaClause.c_str());
-
-        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
-    }
+    osCommand.Printf(
+                "SELECT DISTINCT a.attname, t.typname, a.attlen,"
+                "       format_type(a.atttypid,a.atttypmod), a.attnum, a.attnotnull, a.atthasdef "
+                "FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n "
+                "WHERE c.relname = %s "
+                "AND a.attnum > 0 AND a.attrelid = c.oid "
+                "AND a.atttypid = t.oid "
+                "AND c.relnamespace=n.oid "
+                "%s "
+                "ORDER BY a.attnum",
+                pszEscapedTableNameSingleQuote, osSchemaClause.c_str());
 
-    if( hResult && PQresultStatus(hResult) == PGRES_COMMAND_OK )
-    {
-        OGRPGClearResult( hResult );
-        hResult = OGRPG_PQexec(hPGConn, "FETCH ALL in mycursor" );
-    }
+    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
 
     if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
     {
@@ -370,13 +368,7 @@ int OGRPGTableLayer::ReadTableDefinition()
     {
         OGRPGClearResult( hResult );
 
-        hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
-        OGRPGClearResult( hResult );
-
-        hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-        OGRPGClearResult( hResult );
-
-        CPLError( CE_Failure, CPLE_AppDefined,
+        CPLDebug( "PG",
                   "No field definitions found for '%s', is it a table?",
                   pszTableName );
         return bTableDefinitionValid;
@@ -386,19 +378,28 @@ int OGRPGTableLayer::ReadTableDefinition()
 /*      Parse the returned table information.                           */
 /* -------------------------------------------------------------------- */
     int            iRecord;
-
+    int            bHasDefault = FALSE;
     for( iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
     {
         const char      *pszType = NULL;
         const char      *pszFormatType = NULL;
+        const char      *pszNotNull = NULL;
+        const char      *pszHasDef = NULL;
         OGRFieldDefn    oField( PQgetvalue( hResult, iRecord, 0 ), OFTString);
 
         pszType = PQgetvalue(hResult, iRecord, 1 );
+        int nWidth = atoi(PQgetvalue(hResult,iRecord,2));
         pszFormatType = PQgetvalue(hResult,iRecord,3);
+        pszNotNull = PQgetvalue(hResult,iRecord,5);
+        pszHasDef = PQgetvalue(hResult,iRecord,6);
+
+        if( pszNotNull && EQUAL(pszNotNull, "t") )
+            oField.SetNullable(FALSE);
+        if( pszHasDef && EQUAL(pszHasDef, "t") )
+            bHasDefault = TRUE;
 
         if( EQUAL(oField.GetNameRef(),osPrimaryKey) )
         {
-            bHasFid = TRUE;
             pszFIDColumn = CPLStrdup(oField.GetNameRef());
             CPLDebug("PG","Using column '%s' as FID for table '%s'", pszFIDColumn, pszTableName );
             continue;
@@ -435,134 +436,58 @@ int OGRPGTableLayer::ReadTableDefinition()
                     if( EQUAL(pszType,"OID") )
                         bWkbAsOid = TRUE;
                 }
+                poGeomFieldDefn->SetNullable(oField.IsNullable());
                 if( !bGeometryInformationSet )
                     poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
             }
             continue;
         }
 
-        if( EQUAL(pszType,"text") )
-        {
-            oField.SetType( OFTString );
-        }
-        else if( EQUAL(pszType,"_bpchar") ||
-                 EQUAL(pszType,"_varchar") ||
-                 EQUAL(pszType,"_text"))
-        {
-            oField.SetType( OFTStringList );
-        }
-        else if( EQUAL(pszType,"bpchar") || EQUAL(pszType,"varchar") )
-        {
-            int nWidth;
+        OGRPGCommonLayerSetType(oField, pszType, pszFormatType, nWidth);
 
-            nWidth = atoi(PQgetvalue(hResult,iRecord,2));
-            if( nWidth == -1 )
-            {
-                if( EQUALN(pszFormatType,"character(",10) )
-                    nWidth = atoi(pszFormatType+10);
-                else if( EQUALN(pszFormatType,"character varying(",18) )
-                    nWidth = atoi(pszFormatType+18);
-                else
-                    nWidth = 0;
-            }
-            oField.SetType( OFTString );
-            oField.SetWidth( nWidth );
-        }
-        else if( EQUAL(pszType,"bool") )
-        {
-            oField.SetType( OFTInteger );
-            oField.SetWidth( 1 );
-        }
-        else if( EQUAL(pszType,"numeric") )
-        {
-            const char *pszFormatName = PQgetvalue(hResult,iRecord,3);
-            if( EQUAL(pszFormatName, "numeric") )
-                oField.SetType( OFTReal );
-            else
-            {
-                const char *pszPrecision = strstr(pszFormatName,",");
-                int    nWidth, nPrecision = 0;
+        //CPLDebug("PG", "name=%s, type=%s", oField.GetNameRef(), pszType);
+        poFeatureDefn->AddFieldDefn( &oField );
+    }
 
-                nWidth = atoi(pszFormatName + 8);
-                if( pszPrecision != NULL )
-                    nPrecision = atoi(pszPrecision+1);
+    OGRPGClearResult( hResult );
 
-                if( nPrecision == 0 )
-                {
-                    // FIXME : If nWidth > 10, OFTInteger may not be large enough */
-                    oField.SetType( OFTInteger );
-                }
-                else
-                    oField.SetType( OFTReal );
+    if( bHasDefault )
+    {
+        osCommand.Printf(
+                 "SELECT a.attname, pg_get_expr(def.adbin, c.oid) "
+                 "FROM pg_attrdef def, pg_class c, pg_attribute a, pg_type t, pg_namespace n "
+                 "WHERE c.relname = %s AND a.attnum > 0 AND a.attrelid = c.oid "
+                 "AND a.atttypid = t.oid AND c.relnamespace=n.oid AND "
+                 "def.adrelid = c.oid AND def.adnum = a.attnum "
+                 "%s "
+                 "ORDER BY a.attnum",
+                 pszEscapedTableNameSingleQuote, osSchemaClause.c_str());
 
-                oField.SetWidth( nWidth );
-                oField.SetPrecision( nPrecision );
-            }
-        }
-        else if( EQUAL(pszFormatType,"integer[]") )
-        {
-            oField.SetType( OFTIntegerList );
-        }
-        else if( EQUAL(pszFormatType, "float[]") ||
-                 EQUAL(pszFormatType, "real[]") ||
-                 EQUAL(pszFormatType, "double precision[]") )
-        {
-            oField.SetType( OFTRealList );
-        }
-        else if( EQUAL(pszType,"int2") )
-        {
-            oField.SetType( OFTInteger );
-            oField.SetWidth( 5 );
-        }
-        else if( EQUAL(pszType,"int8") )
-        {
-            /* FIXME: OFTInteger can not handle 64bit integers */
-            oField.SetType( OFTInteger );
-        }
-        else if( EQUALN(pszType,"int",3) )
-        {
-            oField.SetType( OFTInteger );
-        }
-        else if( EQUALN(pszType,"float",5) ||
-                 EQUALN(pszType,"double",6) ||
-                 EQUAL(pszType,"real") )
-        {
-            oField.SetType( OFTReal );
-        }
-        else if( EQUALN(pszType, "timestamp",9) )
-        {
-            oField.SetType( OFTDateTime );
-        }
-        else if( EQUALN(pszType, "date",4) )
-        {
-            oField.SetType( OFTDate );
-        }
-        else if( EQUALN(pszType, "time",4) )
-        {
-            oField.SetType( OFTTime );
-        }
-        else if( EQUAL(pszType,"bytea") )
+        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
+        if( !hResult || PQresultStatus(hResult) != PGRES_TUPLES_OK )
         {
-            oField.SetType( OFTBinary );
+            OGRPGClearResult( hResult );
+
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s", PQerrorMessage(hPGConn) );
+            return bTableDefinitionValid;
         }
 
-        else
+        for( iRecord = 0; iRecord < PQntuples(hResult); iRecord++ )
         {
-            CPLDebug( "PG", "Field %s is of unknown format type %s (type=%s).", 
-                      oField.GetNameRef(), pszFormatType, pszType );
+            const char      *pszName = PQgetvalue( hResult, iRecord, 0 );
+            const char      *pszDefault = PQgetvalue( hResult, iRecord, 1 );
+            int nIdx = poFeatureDefn->GetFieldIndex(pszName);
+            if( nIdx >= 0 )
+            {
+                OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(nIdx);
+                OGRPGCommonLayerNormalizeDefault(poFieldDefn, pszDefault);
+            }
         }
 
-        poFeatureDefn->AddFieldDefn( &oField );
+        OGRPGClearResult( hResult );
     }
 
-    OGRPGClearResult( hResult );
-
-    hResult = OGRPG_PQexec(hPGConn, "CLOSE mycursor");
-    OGRPGClearResult( hResult );
-
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
-
     bTableDefinitionValid = TRUE;
 
     ResetReading();
@@ -602,11 +527,8 @@ int OGRPGTableLayer::ReadTableDefinition()
             (bHasPostGISGeometry) ? "f_geometry_column" : "f_geography_column",
             OGRPGEscapeString(hPGConn,poGeomFieldDefn->GetNameRef()).c_str());
 
-        if (pszSchemaName)
-        {
-            osCommand += CPLString().Printf(" AND f_table_schema = %s",
+        osCommand += CPLString().Printf(" AND f_table_schema = %s",
                                             OGRPGEscapeString(hPGConn,pszSchemaName).c_str());
-        }
 
         hResult = OGRPG_PQexec(hPGConn,osCommand);
 
@@ -614,7 +536,7 @@ int OGRPGTableLayer::ReadTableDefinition()
         {
             const char* pszType = PQgetvalue(hResult,0,0);
 
-            int nCoordDimension = MAX(2,MIN(3,atoi(PQgetvalue(hResult,0,1))));
+            int nCoordDimension = atoi(PQgetvalue(hResult,0,1));
 
             int nSRSId = atoi(PQgetvalue(hResult,0,2));
 
@@ -623,7 +545,7 @@ int OGRPGTableLayer::ReadTableDefinition()
                 poGeomFieldDefn->nSRSId = nSRSId;
             OGRwkbGeometryType eGeomType = OGRFromOGCGeomType(pszType);
             if( poGeomFieldDefn->nCoordDimension == 3 && eGeomType != wkbUnknown )
-                eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
+                eGeomType = wkbSetZ(eGeomType);
             poGeomFieldDefn->SetType(eGeomType);
 
             bGoOn = FALSE;
@@ -631,21 +553,11 @@ int OGRPGTableLayer::ReadTableDefinition()
         else
         {
             /* Fetch the name of the parent table */
-            if (pszSchemaName)
-            {
-                osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
-                                "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
-                                "(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = %s AND c.relnamespace=n.oid AND n.nspname = %s))",
-                                pszEscapedTableNameSingleQuote,
-                                OGRPGEscapeString(hPGConn, pszSchemaName).c_str() );
-            }
-            else
-            {
-                osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
-                                "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
-                                "(SELECT pg_class.oid FROM pg_class WHERE relname = %s))",
-                                pszEscapedTableNameSingleQuote );
-            }
+            osCommand.Printf("SELECT pg_class.relname FROM pg_class WHERE oid = "
+                            "(SELECT pg_inherits.inhparent FROM pg_inherits WHERE inhrelid = "
+                            "(SELECT c.oid FROM pg_class c, pg_namespace n WHERE c.relname = %s AND c.relnamespace=n.oid AND n.nspname = %s))",
+                            pszEscapedTableNameSingleQuote,
+                            OGRPGEscapeString(hPGConn, pszSchemaName).c_str() );
 
             OGRPGClearResult( hResult );
             hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
@@ -670,6 +582,54 @@ int OGRPGTableLayer::ReadTableDefinition()
 }
 
 /************************************************************************/
+/*                         SetTableDefinition()                         */
+/************************************************************************/
+
+void OGRPGTableLayer::SetTableDefinition(const char* pszFIDColumnName,
+                                           const char* pszGFldName,
+                                           OGRwkbGeometryType eType,
+                                           const char* pszGeomType,
+                                           int nSRSId,
+                                           int nCoordDimension)
+{
+    bTableDefinitionValid = TRUE;
+    bGeometryInformationSet = TRUE;
+    if( pszFIDColumnName[0] == '"' &&
+             pszFIDColumnName[strlen(pszFIDColumnName)-1] == '"')
+    {
+        pszFIDColumn = CPLStrdup(pszFIDColumnName + 1);
+        pszFIDColumn[strlen(pszFIDColumn)-1] = '\0';
+    }
+    else
+        pszFIDColumn = CPLStrdup(pszFIDColumnName);
+    poFeatureDefn->SetGeomType(wkbNone);
+    if( eType != wkbNone )
+    {
+        OGRPGGeomFieldDefn* poGeomFieldDefn = new OGRPGGeomFieldDefn(this, pszGFldName);
+        poGeomFieldDefn->SetType(eType);
+        poGeomFieldDefn->nCoordDimension = nCoordDimension;
+
+        if( EQUAL(pszGeomType,"geometry") )
+        {
+            poGeomFieldDefn->ePostgisType = GEOM_TYPE_GEOMETRY;
+            poGeomFieldDefn->nSRSId = nSRSId;
+        }
+        else if( EQUAL(pszGeomType,"geography") )
+        {
+            poGeomFieldDefn->ePostgisType = GEOM_TYPE_GEOGRAPHY;
+            poGeomFieldDefn->nSRSId = 4326;
+        }
+        else
+        {
+            poGeomFieldDefn->ePostgisType = GEOM_TYPE_WKB;
+            if( EQUAL(pszGeomType,"OID") )
+                bWkbAsOid = TRUE;
+        }
+        poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
+    }
+}
+
+/************************************************************************/
 /*                          SetSpatialFilter()                          */
 /************************************************************************/
 
@@ -711,13 +671,13 @@ void OGRPGTableLayer::BuildWhere()
     if( poFeatureDefn->GetGeomFieldCount() != 0 )
         poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(m_iGeomFieldFilter);
 
-    if( m_poFilterGeom != NULL && poGeomFieldDefn != NULL && (
+    if( m_poFilterGeom != NULL && poGeomFieldDefn != NULL &&
+        poDS->sPostGISVersion.nMajor >= 0 && (
             poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY ||
             poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY) )
     {
         char szBox3D_1[128];
         char szBox3D_2[128];
-        char* pszComma;
         OGREnvelope  sEnvelope;
 
         m_poFilterGeom->getEnvelope( &sEnvelope );
@@ -732,12 +692,8 @@ void OGRPGTableLayer::BuildWhere()
             if( sEnvelope.MaxY > 90.0 )
                 sEnvelope.MaxY = 90.0;
         }
-        snprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
-        while((pszComma = strchr(szBox3D_1, ',')) != NULL)
-            *pszComma = '.';
-        snprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
-        while((pszComma = strchr(szBox3D_2, ',')) != NULL)
-            *pszComma = '.';
+        CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.18g %.18g", sEnvelope.MinX, sEnvelope.MinY);
+        CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.18g %.18g", sEnvelope.MaxX, sEnvelope.MaxY);
         osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
                        OGRPGEscapeColumnName(poGeomFieldDefn->GetNameRef()).c_str(),
                        (poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
@@ -791,7 +747,9 @@ void OGRPGTableLayer::ResetReading()
         return;
     bInResetReading = TRUE;
 
-    bUseCopy = USE_COPY_UNSET;
+    if( bDifferedCreation ) RunDifferedCreationIfNecessary();
+    poDS->EndCopy();
+    bUseCopyByDefault = FALSE;
 
     BuildFullQueryStatement();
 
@@ -807,6 +765,16 @@ void OGRPGTableLayer::ResetReading()
 OGRFeature *OGRPGTableLayer::GetNextFeature()
 
 {
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+    poDS->EndCopy();
+
+    if( pszQueryStatement == NULL )
+        ResetReading();
+
+    if( pszQueryStatement == NULL )
+        ResetReading();
+
     OGRPGGeomFieldDefn* poGeomFieldDefn = NULL;
     if( poFeatureDefn->GetGeomFieldCount() != 0 )
         poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(m_iGeomFieldFilter);
@@ -829,7 +797,13 @@ OGRFeature *OGRPGTableLayer::GetNextFeature()
             || poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY
             || poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY
             || FilterGeometry( poFeature->GetGeomFieldRef(m_iGeomFieldFilter) )  )
+        {
+            if( poFeature && iFIDAsRegularColumnIndex >= 0 )
+            {
+                poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
+            }
             return poFeature;
+        }
 
         delete poFeature;
     }
@@ -850,7 +824,7 @@ CPLString OGRPGTableLayer::BuildFields()
 
     poFeatureDefn->GetFieldCount();
 
-    if( bHasFid && poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
+    if( pszFIDColumn != NULL && poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
     {
         osFieldList += OGRPGEscapeColumnName(pszFIDColumn);
     }
@@ -867,7 +841,7 @@ CPLString OGRPGTableLayer::BuildFields()
 
         if( poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY )
         {
-            if ( poDS->bUseBinaryCursor )
+            if ( poDS->sPostGISVersion.nMajor < 0 || poDS->bUseBinaryCursor )
             {
                 osFieldList += osEscapedGeom;
             }
@@ -1001,7 +975,7 @@ OGRErr OGRPGTableLayer::SetAttributeFilter( const char *pszQuery )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
+OGRErr OGRPGTableLayer::DeleteFeature( GIntBig nFID )
 
 {
     PGconn      *hPGConn = poDS->GetPGConn();
@@ -1018,14 +992,19 @@ OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
         return OGRERR_FAILURE;
     }
 
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    poDS->EndCopy();
+    bAutoFIDOnCreateViaCopy = FALSE;
+
 /* -------------------------------------------------------------------- */
 /*      We can only delete features if we have a well defined FID       */
 /*      column to target.                                               */
 /* -------------------------------------------------------------------- */
-    if( !bHasFid )
+    if( pszFIDColumn == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "DeleteFeature(%ld) failed.  Unable to delete features in tables without\n"
+                  "DeleteFeature(" CPL_FRMT_GIB ") failed.  Unable to delete features in tables without\n"
                   "a recognised FID column.",
                   nFID );
         return OGRERR_FAILURE;
@@ -1035,7 +1014,7 @@ OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
 /* -------------------------------------------------------------------- */
 /*      Form the statement to drop the record.                          */
 /* -------------------------------------------------------------------- */
-    osCommand.Printf( "DELETE FROM %s WHERE %s = %ld",
+    osCommand.Printf( "DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
                       pszSqlTableName, OGRPGEscapeColumnName(pszFIDColumn).c_str(), nFID );
 
 /* -------------------------------------------------------------------- */
@@ -1043,10 +1022,6 @@ OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
 /* -------------------------------------------------------------------- */
     OGRErr eErr;
 
-    eErr = poDS->SoftStartTransaction();
-    if( eErr != OGRERR_NONE )
-        return eErr;
-
     hResult = OGRPG_PQexec(hPGConn, osCommand);
 
     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
@@ -1055,172 +1030,28 @@ OGRErr OGRPGTableLayer::DeleteFeature( long nFID )
                   "DeleteFeature() DELETE statement failed.\n%s",
                   PQerrorMessage(hPGConn) );
 
-        OGRPGClearResult( hResult );
-
-        poDS->SoftRollback();
         eErr = OGRERR_FAILURE;
     }
     else
     {
-        OGRPGClearResult( hResult );
-
-        eErr = poDS->SoftCommit();
-    }
-
-    return eErr;
-}
-
-/************************************************************************/
-/*                          AppendFieldValue()                          */
-/*                                                                      */
-/* Used by CreateFeatureViaInsert() and SetFeature() to format a        */
-/* non-empty field value                                                */
-/************************************************************************/
-
-void OGRPGTableLayer::AppendFieldValue(PGconn *hPGConn, CPLString& osCommand,
-                                       OGRFeature* poFeature, int i)
-{
-    int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
-
-    // We need special formatting for integer list values.
-    if(  nOGRFieldType == OFTIntegerList )
-    {
-        int nCount, nOff = 0, j;
-        const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
-        char *pszNeedToFree = NULL;
-
-        pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
-        strcpy( pszNeedToFree, "'{" );
-        for( j = 0; j < nCount; j++ )
-        {
-            if( j != 0 )
-                strcat( pszNeedToFree+nOff, "," );
-
-            nOff += strlen(pszNeedToFree+nOff);
-            sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
-        }
-        strcat( pszNeedToFree+nOff, "}'" );
-
-        osCommand += pszNeedToFree;
-        CPLFree(pszNeedToFree);
-
-        return;
-    }
-
-    // We need special formatting for real list values.
-    else if( nOGRFieldType == OFTRealList )
-    {
-        int nCount, nOff = 0, j;
-        const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
-        char *pszNeedToFree = NULL;
-
-        pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
-        strcpy( pszNeedToFree, "'{" );
-        for( j = 0; j < nCount; j++ )
-        {
-            if( j != 0 )
-                strcat( pszNeedToFree+nOff, "," );
-
-            nOff += strlen(pszNeedToFree+nOff);
-            //Check for special values. They need to be quoted.
-            if( CPLIsNan(padfItems[j]) )
-                sprintf( pszNeedToFree+nOff, "NaN" );
-            else if( CPLIsInf(padfItems[j]) )
-                sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
-            else
-                sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
-
-            char* pszComma = strchr(pszNeedToFree+nOff, ',');
-            if (pszComma)
-                *pszComma = '.';
-        }
-        strcat( pszNeedToFree+nOff, "}'" );
-
-        osCommand += pszNeedToFree;
-        CPLFree(pszNeedToFree);
-
-        return;
-    }
-
-    // We need special formatting for string list values.
-    else if( nOGRFieldType == OFTStringList )
-    {
-        char **papszItems = poFeature->GetFieldAsStringList(i);
-
-        osCommand += OGRPGEscapeStringList(hPGConn, papszItems, TRUE);
-
-        return;
-    }
-
-    // Binary formatting
-    else if( nOGRFieldType == OFTBinary )
-    {
-        if (poDS->bUseEscapeStringSyntax)
-            osCommand += "E";
-
-        osCommand += "'";
-
-        int nLen = 0;
-        GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
-        char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
-
-        osCommand += pszBytea;
-
-        CPLFree(pszBytea);
-        osCommand += "'";
-
-        return;
+        if( EQUAL(PQcmdStatus(hResult), "DELETE 0") )
+            eErr = OGRERR_NON_EXISTING_FEATURE;
+        else
+            eErr = OGRERR_NONE;
     }
 
-    // Flag indicating NULL or not-a-date date value
-    // e.g. 0000-00-00 - there is no year 0
-    OGRBoolean bIsDateNull = FALSE;
-
-    const char *pszStrValue = poFeature->GetFieldAsString(i);
-
-    // Check if date is NULL: 0000-00-00
-    if( nOGRFieldType == OFTDate )
-    {
-        if( EQUALN( pszStrValue, "0000", 4 ) )
-        {
-            pszStrValue = "NULL";
-            bIsDateNull = TRUE;
-        }
-    }
-    else if ( nOGRFieldType == OFTReal )
-    {
-        char* pszComma = strchr((char*)pszStrValue, ',');
-        if (pszComma)
-            *pszComma = '.';
-        //Check for special values. They need to be quoted.
-        double dfVal = poFeature->GetFieldAsDouble(i);
-        if( CPLIsNan(dfVal) )
-            pszStrValue = "'NaN'";
-        else if( CPLIsInf(dfVal) )
-            pszStrValue = (dfVal > 0) ? "'Infinity'" : "'-Infinity'";
-    }
+    OGRPGClearResult( hResult );
 
-    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
-        && !bIsDateNull )
-    {
-        osCommand += OGRPGEscapeString(hPGConn, pszStrValue,
-                                        poFeatureDefn->GetFieldDefn(i)->GetWidth(),
-                                        poFeatureDefn->GetName(),
-                                        poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
-    }
-    else
-    {
-        osCommand += pszStrValue;
-    }
+    return eErr;
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /*                                                                      */
 /*      SetFeature() is implemented by an UPDATE SQL command            */
 /************************************************************************/
 
-OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRPGTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     PGconn              *hPGConn = poDS->GetPGConn();
@@ -1240,6 +1071,10 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    poDS->EndCopy();
+
     if( NULL == poFeature )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
@@ -1254,7 +1089,7 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
         return eErr;
     }
 
-    if( !bHasFid )
+    if( pszFIDColumn == NULL )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
                   "Unable to update features in tables without\n"
@@ -1263,10 +1098,16 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
 
     }
 
-    eErr = poDS->SoftStartTransaction();
-    if( eErr != OGRERR_NONE )
+    /* In case the FID column has also been created as a regular field */
+    if( iFIDAsRegularColumnIndex >= 0 )
     {
-        return eErr;
+        if( !poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) ||
+            poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                        "Inconsistant values of FID and field of same name");
+            return CE_Failure;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1293,7 +1134,7 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
             {
                 if( !bWkbAsOid  )
                 {
-                    char    *pszBytea = GeometryToBYTEA( poGeom );
+                    char    *pszBytea = GeometryToBYTEA( poGeom, poDS->sPostGISVersion.nMajor < 2 );
 
                     if( pszBytea != NULL )
                     {
@@ -1340,7 +1181,8 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
             {
                 if ( poGeom != NULL )
                 {
-                    char* pszHexEWKB = OGRGeometryToHexEWKB( poGeom, poGeomFieldDefn->nSRSId );
+                    char* pszHexEWKB = OGRGeometryToHexEWKB( poGeom, poGeomFieldDefn->nSRSId,
+                                                             poDS->sPostGISVersion.nMajor < 2 );
                     if ( poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY )
                         osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
                     else
@@ -1383,6 +1225,8 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
 
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     {
+        if( iFIDAsRegularColumnIndex == i )
+            continue;
         if( bNeedComma )
             osCommand += ", ";
         else
@@ -1397,14 +1241,15 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
         }
         else
         {
-            AppendFieldValue(hPGConn, osCommand, poFeature, i);
+            OGRPGCommonAppendFieldValue(osCommand, poFeature, i,
+                                        (OGRPGCommonEscapeStringCbk)OGRPGEscapeString, hPGConn);
         }
     }
 
     /* Add the WHERE clause */
     osCommand += " WHERE ";
     osCommand = osCommand + OGRPGEscapeColumnName(pszFIDColumn) + " = ";
-    osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
+    osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID() );
 
 /* -------------------------------------------------------------------- */
 /*      Execute the update.                                             */
@@ -1413,26 +1258,29 @@ OGRErr OGRPGTableLayer::SetFeature( OGRFeature *poFeature )
     if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
     {
         CPLError( CE_Failure, CPLE_AppDefined,
-                  "UPDATE command for feature %ld failed.\n%s\nCommand: %s",
+                  "UPDATE command for feature " CPL_FRMT_GIB " failed.\n%s\nCommand: %s",
                   poFeature->GetFID(), PQerrorMessage(hPGConn), osCommand.c_str() );
 
         OGRPGClearResult( hResult );
 
-        poDS->SoftRollback();
-
         return OGRERR_FAILURE;
     }
 
+    if( EQUAL(PQcmdStatus(hResult), "UPDATE 0") )
+        eErr = OGRERR_NON_EXISTING_FEATURE;
+    else
+        eErr = OGRERR_NONE;
+
     OGRPGClearResult( hResult );
 
-    return poDS->SoftCommit();
+    return eErr;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRPGTableLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRPGTableLayer::ICreateFeature( OGRFeature *poFeature )
 {
     GetLayerDefn()->GetFieldCount();
 
@@ -1451,6 +1299,61 @@ OGRErr OGRPGTableLayer::CreateFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    /* In case the FID column has also been created as a regular field */
+    if( iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( poFeature->GetFID() == OGRNullFID )
+        {
+            if( poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) )
+            {
+                poFeature->SetFID(
+                    poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex));
+            }
+        }
+        else
+        {
+            if( !poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) ||
+                poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                            "Inconsistant values of FID and field of same name");
+                return CE_Failure;
+            }
+        }
+    }
+
+    /* Auto-promote FID column to 64bit if necessary */
+    if( pszFIDColumn != NULL &&
+        (GIntBig)(int)poFeature->GetFID() != poFeature->GetFID() &&
+        GetMetadataItem(OLMD_FID64) == NULL )
+    {
+        poDS->EndCopy();
+
+        CPLString osCommand;
+        osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s TYPE INT8",
+                        pszSqlTableName,
+                        OGRPGEscapeColumnName(pszFIDColumn).c_str() );
+        PGconn              *hPGConn = poDS->GetPGConn();
+        PGresult* hResult = OGRPG_PQexec(hPGConn, osCommand);
+        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s\n%s",
+                    osCommand.c_str(),
+                    PQerrorMessage(hPGConn) );
+
+            OGRPGClearResult( hResult );
+
+            return OGRERR_FAILURE;
+        }
+        OGRPGClearResult( hResult );
+        
+        SetMetadataItem(OLMD_FID64, "YES");
+    }
+
     if( bFirstInsertion )
     {
         bFirstInsertion = FALSE;
@@ -1470,23 +1373,71 @@ OGRErr OGRPGTableLayer::CreateFeature( OGRFeature *poFeature )
     if( bUseCopy == USE_COPY_UNSET )
         bUseCopy = CSLTestBoolean( CPLGetConfigOption( "PG_USE_COPY", "NO") );
 
+    OGRErr eErr;
     if( !bUseCopy )
     {
-        return CreateFeatureViaInsert( poFeature );
+        eErr = CreateFeatureViaInsert( poFeature );
     }
     else
     {
-        if ( !bCopyActive )
+        /* If there's a unset field with a default value, then we must use */
+        /* a specific INSERT statement to avoid unset fields to be bound to NULL */
+        int bHasDefaultValue = FALSE;
+        int iField;
+        int nFieldCount = poFeatureDefn->GetFieldCount();
+        for( iField = 0; iField < nFieldCount; iField++ )
         {
-            /* This is a heuristics. If the first feature to be copied has a */
-            /* FID set (and that a FID column has been identified), then we will */
-            /* try to copy FID values from features. Otherwise, we will not */
-            /* do and assume that the FID column is an autoincremented column. */
-            StartCopy(poFeature->GetFID() != OGRNullFID);
-        }
+            if( !poFeature->IsFieldSet( iField ) &&
+                poFeature->GetFieldDefnRef(iField)->GetDefault() != NULL )
+            {
+                bHasDefaultValue = TRUE;
+                break;
+            }
+        }
+        if( bHasDefaultValue )
+        {
+            eErr = CreateFeatureViaInsert( poFeature );
+        }
+        else
+        {
+            int bFIDSet = (pszFIDColumn != NULL && poFeature->GetFID() != OGRNullFID);
+            if( bCopyActive && bFIDSet != bFIDColumnInCopyFields )
+            {
+                eErr = CreateFeatureViaInsert( poFeature );
+            }
+            else if( !bCopyActive && poFeatureDefn->GetFieldCount() == 0 &&
+                     poFeatureDefn->GetGeomFieldCount() == 0 && !bFIDSet )
+            {
+                eErr = CreateFeatureViaInsert( poFeature );
+            }
+            else
+            {
+                if ( !bCopyActive )
+                {
+                    /* This is a heuristics. If the first feature to be copied has a */
+                    /* FID set (and that a FID column has been identified), then we will */
+                    /* try to copy FID values from features. Otherwise, we will not */
+                    /* do and assume that the FID column is an autoincremented column. */
+                    bFIDColumnInCopyFields = bFIDSet;
+                }
+
+                eErr = CreateFeatureViaCopy( poFeature );
+                if( bFIDSet )
+                    bAutoFIDOnCreateViaCopy = FALSE;
+                if( eErr == CE_None && bAutoFIDOnCreateViaCopy )
+                {
+                    poFeature->SetFID( ++iNextShapeId );
+                }
+            }
+        }
+    }
 
-        return CreateFeatureViaCopy( poFeature );
+    if( eErr == CE_None && iFIDAsRegularColumnIndex >= 0 )
+    {
+        poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
     }
+
+    return eErr;
 }
 
 /************************************************************************/
@@ -1535,13 +1486,19 @@ CPLString OGRPGEscapeString(PGconn *hPGConn,
         CPLDebug( "PG",
                   "Truncated %s.%s field value '%s' to %d characters.",
                   pszTableName, pszFieldName, pszStrValue, nMaxLength );
-        nSrcLen = nSrcLen * nMaxLength / nSrcLenUTF;
 
-        
-        while( nSrcLen > 0 && ((unsigned char *) pszStrValue)[nSrcLen-1] > 127 )
+        int iUTF8Char = 0;
+        for(int iChar = 0; iChar < nSrcLen; iChar++ )
         {
-            CPLDebug( "PG", "Backup to start of multi-byte character." );
-            nSrcLen--;
+            if( (((unsigned char *) pszStrValue)[iChar] & 0xc0) != 0x80 )
+            {
+                if( iUTF8Char == nMaxLength )
+                {
+                    nSrcLen = iChar;
+                    break;
+                }
+                iUTF8Char ++;
+            }
         }
     }
 
@@ -1576,65 +1533,6 @@ CPLString OGRPGEscapeString(PGconn *hPGConn,
     return osCommand;
 }
 
-
-/************************************************************************/
-/*                       OGRPGEscapeStringList( )                         */
-/************************************************************************/
-
-static CPLString OGRPGEscapeStringList(PGconn *hPGConn,
-                                       char** papszItems, int bForInsertOrUpdate)
-{
-    int bFirstItem = TRUE;
-    CPLString osStr;
-    if (bForInsertOrUpdate)
-        osStr += "ARRAY[";
-    else
-        osStr += "{";
-    while(papszItems && *papszItems)
-    {
-        if (!bFirstItem)
-        {
-            osStr += ',';
-        }
-
-        char* pszStr = *papszItems;
-        if (*pszStr != '\0')
-        {
-            if (bForInsertOrUpdate)
-                osStr += OGRPGEscapeString(hPGConn, pszStr);
-            else
-            {
-                osStr += '"';
-
-                while(*pszStr)
-                {
-                    if (*pszStr == '"' )
-                        osStr += "\\";
-                    osStr += *pszStr;
-                    pszStr++;
-                }
-
-                osStr += '"';
-            }
-        }
-        else
-            osStr += "NULL";
-
-        bFirstItem = FALSE;
-
-        papszItems++;
-    }
-    if (bForInsertOrUpdate)
-    {
-        osStr += "]";
-        if( papszItems == NULL )
-            osStr += "::varchar[]";
-    }
-    else
-        osStr += "}";
-    return osStr;
-}
-
 /************************************************************************/
 /*                       CreateFeatureViaInsert()                       */
 /************************************************************************/
@@ -1647,16 +1545,11 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
     CPLString           osCommand;
     int                 i;
     int                 bNeedComma = FALSE;
-    OGRErr              eErr;
-
-    eErr = poDS->SoftStartTransaction();
-    if( eErr != OGRERR_NONE )
-    {
-        return eErr;
-    }
 
     int bEmptyInsert = FALSE;
 
+    poDS->EndCopy();
+
 /* -------------------------------------------------------------------- */
 /*      Form the INSERT command.                                        */
 /* -------------------------------------------------------------------- */
@@ -1689,6 +1582,8 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
     int nFieldCount = poFeatureDefn->GetFieldCount();
     for( i = 0; i < nFieldCount; i++ )
     {
+        if( iFIDAsRegularColumnIndex == i )
+            continue;
         if( !poFeature->IsFieldSet( i ) )
             continue;
 
@@ -1732,7 +1627,8 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
 
             if ( !CSLTestBoolean(CPLGetConfigOption("PG_USE_TEXT", "NO")) )
             {
-                char    *pszHexEWKB = OGRGeometryToHexEWKB( poGeom, nSRSId );
+                char    *pszHexEWKB = OGRGeometryToHexEWKB( poGeom, nSRSId,
+                                                            poDS->sPostGISVersion.nMajor < 2 );
                 if ( poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY )
                     osCommand += CPLString().Printf("'%s'::GEOGRAPHY", pszHexEWKB);
                 else
@@ -1767,7 +1663,7 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
         }
         else if( !bWkbAsOid )
         {
-            char    *pszBytea = GeometryToBYTEA( poGeom );
+            char    *pszBytea = GeometryToBYTEA( poGeom, poDS->sPostGISVersion.nMajor < 2 );
 
             if( pszBytea != NULL )
             {
@@ -1797,13 +1693,15 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
     {
         if( bNeedComma )
             osCommand += ", ";
-        osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
+        osCommand += CPLString().Printf( CPL_FRMT_GIB " ", poFeature->GetFID() );
         bNeedComma = TRUE;
     }
 
 
     for( i = 0; i < nFieldCount; i++ )
     {
+        if( iFIDAsRegularColumnIndex == i )
+            continue;
         if( !poFeature->IsFieldSet( i ) )
             continue;
 
@@ -1812,7 +1710,8 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
         else
             bNeedComma = TRUE;
 
-        AppendFieldValue(hPGConn, osCommand, poFeature, i);
+        OGRPGCommonAppendFieldValue(osCommand, poFeature, i,
+                                    (OGRPGCommonEscapeStringCbk)OGRPGEscapeString, hPGConn);
     }
 
     osCommand += ")";
@@ -1841,8 +1740,7 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
         PQntuples(hResult) == 1 && PQnfields(hResult) == 1 )
     {
         const char* pszFID = PQgetvalue(hResult, 0, 0 );
-        long nFID = atol(pszFID);
-        poFeature->SetFID(nFID);
+        poFeature->SetFID(CPLAtoGIntBig(pszFID));
     }
     else if( bReturnRequested || PQresultStatus(hResult) != PGRES_COMMAND_OK )
     {
@@ -1863,14 +1761,12 @@ OGRErr OGRPGTableLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
 
         OGRPGClearResult( hResult );
 
-        poDS->SoftRollback();
-
         return OGRERR_FAILURE;
     }
 
     OGRPGClearResult( hResult );
 
-    return poDS->SoftCommit();
+    return OGRERR_NONE;
 }
 
 /************************************************************************/
@@ -1883,6 +1779,9 @@ OGRErr OGRPGTableLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
     CPLString            osCommand;
     int                  i;
 
+    /* Tell the datasource we are now planning to copy data */
+    poDS->StartCopy( this ); 
+
     /* First process geometry */
     for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
     {
@@ -1899,9 +1798,10 @@ OGRErr OGRPGTableLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
             poGeom->setCoordinateDimension( poGeomFieldDefn->nCoordDimension );
 
             if( poGeomFieldDefn->ePostgisType == GEOM_TYPE_WKB )
-                pszGeom = GeometryToBYTEA( poGeom );
+                pszGeom = GeometryToBYTEA( poGeom, poDS->sPostGISVersion.nMajor < 2 );
             else
-                pszGeom = OGRGeometryToHexEWKB( poGeom, poGeomFieldDefn->nSRSId );
+                pszGeom = OGRGeometryToHexEWKB( poGeom, poGeomFieldDefn->nSRSId,
+                                                poDS->sPostGISVersion.nMajor < 2 );
         }
 
         if (osCommand.size() > 0)
@@ -1918,185 +1818,12 @@ OGRErr OGRPGTableLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
         }
     }
     
-    /* Next process the field id column */
-    int nFIDIndex = -1;
-    if( bFIDColumnInCopyFields )
-    {
-        if (osCommand.size() > 0)
-            osCommand += "\t";
-
-        nFIDIndex = poFeatureDefn->GetFieldIndex( pszFIDColumn );
-
-        /* Set the FID */
-        if( poFeature->GetFID() != OGRNullFID )
-        {
-            osCommand += CPLString().Printf("%ld ", poFeature->GetFID());
-        }
-        else
-        {
-            osCommand += "\\N" ;
-        }
-    }
-
-
-    /* Now process the remaining fields */
-
-    int nFieldCount = poFeatureDefn->GetFieldCount();
-    int bAddTab = osCommand.size() > 0;
-
-    for( i = 0; i < nFieldCount;  i++ )
-    {
-        if (i == nFIDIndex)
-            continue;
-
-        const char *pszStrValue = poFeature->GetFieldAsString(i);
-        char *pszNeedToFree = NULL;
-
-        if (bAddTab)
-            osCommand += "\t";
-        bAddTab = TRUE;
-
-        if( !poFeature->IsFieldSet( i ) )
-        {
-            osCommand += "\\N" ;
-
-            continue;
-        }
-
-        int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
-
-        // We need special formatting for integer list values.
-        if( nOGRFieldType == OFTIntegerList )
-        {
-            int nCount, nOff = 0, j;
-            const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
-
-            pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
-            strcpy( pszNeedToFree, "{" );
-            for( j = 0; j < nCount; j++ )
-            {
-                if( j != 0 )
-                    strcat( pszNeedToFree+nOff, "," );
-
-                nOff += strlen(pszNeedToFree+nOff);
-                sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
-            }
-            strcat( pszNeedToFree+nOff, "}" );
-            pszStrValue = pszNeedToFree;
-        }
-
-        // We need special formatting for real list values.
-        else if( nOGRFieldType == OFTRealList )
-        {
-            int nCount, nOff = 0, j;
-            const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
-
-            pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
-            strcpy( pszNeedToFree, "{" );
-            for( j = 0; j < nCount; j++ )
-            {
-                if( j != 0 )
-                    strcat( pszNeedToFree+nOff, "," );
-
-                nOff += strlen(pszNeedToFree+nOff);
-                //Check for special values. They need to be quoted.
-                if( CPLIsNan(padfItems[j]) )
-                    sprintf( pszNeedToFree+nOff, "NaN" );
-                else if( CPLIsInf(padfItems[j]) )
-                    sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
-                else
-                    sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
-
-                char* pszComma = strchr(pszNeedToFree+nOff, ',');
-                if (pszComma)
-                    *pszComma = '.';
-            }
-            strcat( pszNeedToFree+nOff, "}" );
-            pszStrValue = pszNeedToFree;
-        }
-
-
-        // We need special formatting for string list values.
-        else if( nOGRFieldType == OFTStringList )
-        {
-            CPLString osStr;
-            char **papszItems = poFeature->GetFieldAsStringList(i);
-
-            pszStrValue = pszNeedToFree = CPLStrdup(OGRPGEscapeStringList(hPGConn, papszItems, FALSE));
-        }
-
-        // Binary formatting
-        else if( nOGRFieldType == OFTBinary )
-        {
-            int nLen = 0;
-            GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
-            char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
-
-            pszStrValue = pszNeedToFree = pszBytea;
-        }
-
-        else if( nOGRFieldType == OFTReal )
-        {
-            char* pszComma = strchr((char*)pszStrValue, ',');
-            if (pszComma)
-                *pszComma = '.';
-            //Check for special values. They need to be quoted.
-            double dfVal = poFeature->GetFieldAsDouble(i);
-            if( CPLIsNan(dfVal) )
-                pszStrValue = "NaN";
-            else if( CPLIsInf(dfVal) )
-                pszStrValue = (dfVal > 0) ? "Infinity" : "-Infinity";
-        }
-
-        if( nOGRFieldType != OFTIntegerList &&
-            nOGRFieldType != OFTRealList &&
-            nOGRFieldType != OFTInteger &&
-            nOGRFieldType != OFTReal &&
-            nOGRFieldType != OFTBinary )
-        {
-            int         iChar;
-            int         iUTFChar = 0;
-
-            for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
-            {
-
-                if( poFeatureDefn->GetFieldDefn(i)->GetWidth() > 0
-                    && iUTFChar == poFeatureDefn->GetFieldDefn(i)->GetWidth() )
-                {
-                    CPLDebug( "PG",
-                              "Truncated %s.%s field value '%s' to %d characters.",
-                              poFeatureDefn->GetName(),
-                              poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
-                              pszStrValue,
-                              poFeatureDefn->GetFieldDefn(i)->GetWidth() );
-                    break;
-                }
-
-                //count of utf chars
-                if ((pszStrValue[iChar] & 0xc0) != 0x80) 
-                    iUTFChar++;
-
-                /* Escape embedded \, \t, \n, \r since they will cause COPY
-                   to misinterpret a line of text and thus abort */
-                if( pszStrValue[iChar] == '\\' || 
-                    pszStrValue[iChar] == '\t' || 
-                    pszStrValue[iChar] == '\r' || 
-                    pszStrValue[iChar] == '\n'   )
-                {
-                    osCommand += '\\';
-                }
-
-                osCommand += pszStrValue[iChar];
-            }
-        }
-        else
-        {
-            osCommand += pszStrValue;
-        }
-
-        if( pszNeedToFree )
-            CPLFree( pszNeedToFree );
-    }
+    OGRPGCommonAppendCopyFieldsExceptGeom(osCommand,
+                                          poFeature,
+                                          pszFIDColumn,
+                                          bFIDColumnInCopyFields,
+                                          (OGRPGCommonEscapeStringCbk)OGRPGEscapeString,
+                                          hPGConn);
 
     /* Add end of line marker */
     osCommand += "\n";
@@ -2111,7 +1838,9 @@ OGRErr OGRPGTableLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
     /* This is for postgresql  7.4 and higher */
 #if !defined(PG_PRE74)
     int copyResult = PQputCopyData(hPGConn, osCommand.c_str(), strlen(osCommand.c_str()));
-    //CPLDebug("PG", "PQputCopyData(%s)", osCommand.c_str());
+#ifdef DEBUG_VERBOSE
+    CPLDebug("PG", "PQputCopyData(%s)", osCommand.c_str());
+#endif
 
     switch (copyResult)
     {
@@ -2158,14 +1887,14 @@ int OGRPGTableLayer::TestCapability( const char * pszCap )
                  EQUAL(pszCap,OLCDeleteFeature) )
         {
             GetLayerDefn()->GetFieldCount();
-            return bHasFid;
+            return pszFIDColumn != NULL;
         }
     }
 
     if( EQUAL(pszCap,OLCRandomRead) )
     {
         GetLayerDefn()->GetFieldCount();
-        return bHasFid;
+        return pszFIDColumn != NULL;
     }
 
     else if( EQUAL(pszCap,OLCFastFeatureCount) ||
@@ -2177,8 +1906,9 @@ int OGRPGTableLayer::TestCapability( const char * pszCap )
         if( poFeatureDefn->GetGeomFieldCount() > 0 )
             poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(m_iGeomFieldFilter);
         return poGeomFieldDefn == NULL ||
-               poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY ||
-               poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY;
+               (poDS->sPostGISVersion.nMajor >= 0 &&
+                (poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY ||
+                 poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY));
     }
 
     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
@@ -2187,8 +1917,9 @@ int OGRPGTableLayer::TestCapability( const char * pszCap )
         if( poFeatureDefn->GetGeomFieldCount() > 0 )
             poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(m_iGeomFieldFilter);
         return poGeomFieldDefn == NULL ||
-               poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY ||
-               poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY;
+               (poDS->sPostGISVersion.nMajor >= 0 &&
+               (poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY ||
+                poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOGRAPHY));
     }
 
     else if( EQUAL(pszCap,OLCTransactions) )
@@ -2200,98 +1931,18 @@ int OGRPGTableLayer::TestCapability( const char * pszCap )
         if( poFeatureDefn->GetGeomFieldCount() > 0 )
             poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(0);
         return poGeomFieldDefn != NULL &&
+               poDS->sPostGISVersion.nMajor >= 0 &&
                poGeomFieldDefn->ePostgisType == GEOM_TYPE_GEOMETRY;
     }
 
     else if( EQUAL(pszCap,OLCStringsAsUTF8) )
         return TRUE;
 
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                        OGRPGTableLayerGetType()                      */
-/************************************************************************/
-
-static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
-                                        int bPreservePrecision,
-                                        int bApproxOK)
-{
-    char                szFieldType[256];
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
 
-/* -------------------------------------------------------------------- */
-/*      Work out the PostgreSQL type.                                   */
-/* -------------------------------------------------------------------- */
-    if( oField.GetType() == OFTInteger )
-    {
-        if( oField.GetWidth() > 0 && bPreservePrecision )
-            sprintf( szFieldType, "NUMERIC(%d,0)", oField.GetWidth() );
-        else
-            strcpy( szFieldType, "INTEGER" );
-    }
-    else if( oField.GetType() == OFTReal )
-    {
-        if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
-            && bPreservePrecision )
-            sprintf( szFieldType, "NUMERIC(%d,%d)",
-                     oField.GetWidth(), oField.GetPrecision() );
-        else
-            strcpy( szFieldType, "FLOAT8" );
-    }
-    else if( oField.GetType() == OFTString )
-    {
-        if (oField.GetWidth() > 0 &&  bPreservePrecision )
-            sprintf( szFieldType, "VARCHAR(%d)",  oField.GetWidth() );
-        else
-            strcpy( szFieldType, "VARCHAR");
-    }
-    else if( oField.GetType() == OFTIntegerList )
-    {
-        strcpy( szFieldType, "INTEGER[]" );
-    }
-    else if( oField.GetType() == OFTRealList )
-    {
-        strcpy( szFieldType, "FLOAT8[]" );
-    }
-    else if( oField.GetType() == OFTStringList )
-    {
-        strcpy( szFieldType, "varchar[]" );
-    }
-    else if( oField.GetType() == OFTDate )
-    {
-        strcpy( szFieldType, "date" );
-    }
-    else if( oField.GetType() == OFTTime )
-    {
-        strcpy( szFieldType, "time" );
-    }
-    else if( oField.GetType() == OFTDateTime )
-    {
-        strcpy( szFieldType, "timestamp with time zone" );
-    }
-    else if( oField.GetType() == OFTBinary )
-    {
-        strcpy( szFieldType, "bytea" );
-    }
-    else if( bApproxOK )
-    {
-        CPLError( CE_Warning, CPLE_NotSupported,
-                  "Can't create field %s with type %s on PostgreSQL layers.  Creating as VARCHAR.",
-                  oField.GetNameRef(),
-                  OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
-        strcpy( szFieldType, "VARCHAR" );
-    }
     else
-    {
-        CPLError( CE_Failure, CPLE_NotSupported,
-                  "Can't create field %s with type %s on PostgreSQL layers.",
-                  oField.GetNameRef(),
-                  OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
-        strcpy( szFieldType, "");
-    }
-
-    return szFieldType;
+        return FALSE;
 }
 
 /************************************************************************/
@@ -2316,14 +1967,24 @@ OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
                   "CreateField");
         return OGRERR_FAILURE;
     }
-
+    
+    if( pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) &&
+        oField.GetType() != OFTInteger &&
+        oField.GetType() != OFTInteger64 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
+                 oField.GetNameRef());
+        return CE_Failure;
+    }
+    
 /* -------------------------------------------------------------------- */
 /*      Do we want to "launder" the column names into Postgres          */
 /*      friendly format?                                                */
 /* -------------------------------------------------------------------- */
     if( bLaunderColumnNames )
     {
-        char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
+        char    *pszSafeName = OGRPGCommonLaunderName( oField.GetNameRef(), "PG" );
 
         oField.SetName( pszSafeName );
         CPLFree( pszSafeName );
@@ -2342,43 +2003,147 @@ OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
         osFieldType = pszOverrideType;
     else
     {
-        osFieldType = OGRPGTableLayerGetType(oField, bPreservePrecision, bApproxOK);
+        osFieldType = OGRPGCommonLayerGetType(oField, bPreservePrecision, bApproxOK);
         if (osFieldType.size() == 0)
             return OGRERR_FAILURE;
     }
 
+    CPLString osNotNullDefault;
+    if( !oField.IsNullable() )
+        osNotNullDefault += " NOT NULL";
+    if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+    {
+        osNotNullDefault += " DEFAULT ";
+        osNotNullDefault += OGRPGCommonLayerGetPGDefault(&oField);
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Create the new field.                                           */
 /* -------------------------------------------------------------------- */
-    poDS->FlushSoftTransaction();
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
-
-    osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
-                      pszSqlTableName, OGRPGEscapeColumnName(oField.GetNameRef()).c_str(),
-                      osFieldType.c_str() );
-    hResult = OGRPG_PQexec(hPGConn, osCommand);
-    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    if( bDifferedCreation )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "%s\n%s", 
-                  osCommand.c_str(), 
-                  PQerrorMessage(hPGConn) );
+        if( !(pszFIDColumn != NULL && EQUAL(pszFIDColumn,oField.GetNameRef())) )
+        {
+            osCreateTable += ", ";
+            osCreateTable += OGRPGEscapeColumnName(oField.GetNameRef());
+            osCreateTable += " ";
+            osCreateTable += osFieldType;
+            osCreateTable += osNotNullDefault;
+        }
+    }
+    else
+    {
+        poDS->EndCopy();
+
+        osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
+                        pszSqlTableName, OGRPGEscapeColumnName(oField.GetNameRef()).c_str(),
+                        osFieldType.c_str() );
+        osCommand += osNotNullDefault;
+        
+        hResult = OGRPG_PQexec(hPGConn, osCommand);
+        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s\n%s", 
+                    osCommand.c_str(), 
+                    PQerrorMessage(hPGConn) );
+
+            OGRPGClearResult( hResult );
+
+            return OGRERR_FAILURE;
+        }
 
         OGRPGClearResult( hResult );
+    }
+
+    poFeatureDefn->AddFieldDefn( &oField );
+
+    if( pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) )
+    {
+        iFIDAsRegularColumnIndex = poFeatureDefn->GetFieldCount() - 1;
+    }
+
+    return OGRERR_NONE;
+}
+
+
+/************************************************************************/
+/*                        RunAddGeometryColumn()                        */
+/************************************************************************/
+
+OGRErr OGRPGTableLayer::RunAddGeometryColumn( OGRPGGeomFieldDefn *poGeomField )
+{
+    PGconn              *hPGConn = poDS->GetPGConn();
+    PGresult            *hResult;
+    CPLString            osCommand;
+
+    const char *pszGeometryType = OGRToOGCGeomType(poGeomField->GetType());
+    osCommand.Printf(
+            "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s',%d)",
+            OGRPGEscapeString(hPGConn, pszSchemaName).c_str(),
+            OGRPGEscapeString(hPGConn, pszTableName).c_str(),
+            OGRPGEscapeString(hPGConn, poGeomField->GetNameRef()).c_str(),
+            poGeomField->nSRSId, pszGeometryType, poGeomField->nCoordDimension );
+
+    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+
+    if( !hResult
+        || PQresultStatus(hResult) != PGRES_TUPLES_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "AddGeometryColumn failed for layer %s.",
+                  GetName());
 
-        hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
         OGRPGClearResult( hResult );
 
         return OGRERR_FAILURE;
     }
 
     OGRPGClearResult( hResult );
+    
+    if( !poGeomField->IsNullable() )
+    {
+        osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s SET NOT NULL",
+                          pszSqlTableName,
+                          OGRPGEscapeColumnName(poGeomField->GetNameRef()).c_str() );
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
+        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+        OGRPGClearResult( hResult );
+    }
 
-    poFeatureDefn->AddFieldDefn( &oField );
+    return OGRERR_NONE;
+}
+
+
+/************************************************************************/
+/*                        RunCreateSpatialIndex()                       */
+/************************************************************************/
+
+OGRErr OGRPGTableLayer::RunCreateSpatialIndex( OGRPGGeomFieldDefn *poGeomField )
+{
+    PGconn              *hPGConn = poDS->GetPGConn();
+    PGresult            *hResult;
+    CPLString            osCommand;
+
+    osCommand.Printf("CREATE INDEX %s ON %s USING GIST (%s)",
+                    OGRPGEscapeColumnName(
+                        CPLSPrintf("%s_%s_geom_idx", pszTableName, poGeomField->GetNameRef())).c_str(),
+                    pszSqlTableName,
+                    OGRPGEscapeColumnName(poGeomField->GetNameRef()).c_str());
+
+    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+
+    if( !hResult
+        || PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "CREATE INDEX failed for layer %s.", GetName());
+
+        OGRPGClearResult( hResult );
+
+        return OGRERR_FAILURE;
+    }
+
+    OGRPGClearResult( hResult );
 
     return OGRERR_NONE;
 }
@@ -2390,8 +2155,6 @@ OGRErr OGRPGTableLayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
 OGRErr OGRPGTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
                                          CPL_UNUSED int bApproxOK )
 {
-    PGconn              *hPGConn = poDS->GetPGConn();
-    PGresult            *hResult;
     OGRwkbGeometryType eType = poGeomFieldIn->GetType();
     if( eType == wkbNone )
     {
@@ -2400,9 +2163,16 @@ OGRErr OGRPGTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
         return OGRERR_FAILURE;
     }
     
-    CPLString               osCommand;
     OGRPGGeomFieldDefn *poGeomField =
         new OGRPGGeomFieldDefn( this, poGeomFieldIn->GetNameRef() );
+    if( EQUAL(poGeomField->GetNameRef(), "") )
+    {
+        if( poFeatureDefn->GetGeomFieldCount() == 0 )
+            poGeomField->SetName( "wkb_geometry" );
+        else
+            poGeomField->SetName(
+                CPLSPrintf("wkb_geometry%d", poFeatureDefn->GetGeomFieldCount()+1) );
+    }
     poGeomField->SetSpatialRef(poGeomFieldIn->GetSpatialRef());
 
 /* -------------------------------------------------------------------- */
@@ -2411,7 +2181,7 @@ OGRErr OGRPGTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
 /* -------------------------------------------------------------------- */
     if( bLaunderColumnNames )
     {
-        char    *pszSafeName = poDS->LaunderName( poGeomField->GetNameRef() );
+        char    *pszSafeName = OGRPGCommonLaunderName( poGeomField->GetNameRef(), "PG" );
 
         poGeomField->SetName( pszSafeName );
         CPLFree( pszSafeName );
@@ -2430,12 +2200,10 @@ OGRErr OGRPGTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
     if( nForcedDimension > 0 )
     {
         nDimension = nForcedDimension;
-        if( nDimension == 2 )
-            eType = (OGRwkbGeometryType)( eType & ~wkb25DBit );
-        else
-            eType = (OGRwkbGeometryType)( eType | wkb25DBit );
+        eType = OGR_GT_SetModifier(eType, nDimension == 3, FALSE);
     }
     poGeomField->SetType(eType);
+    poGeomField->SetNullable( poGeomFieldIn->IsNullable() );
     poGeomField->nSRSId = nSRSId;
     poGeomField->nCoordDimension = nDimension;
     poGeomField->ePostgisType = GEOM_TYPE_GEOMETRY;
@@ -2443,53 +2211,26 @@ OGRErr OGRPGTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
 /* -------------------------------------------------------------------- */
 /*      Create the new field.                                           */
 /* -------------------------------------------------------------------- */
-    poDS->FlushSoftTransaction();
-    
-    const char *pszGeometryType = OGRToOGCGeomType(poGeomField->GetType());
-    osCommand.Printf(
-            "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s',%d)",
-            OGRPGEscapeString(hPGConn, pszSchemaName).c_str(),
-            OGRPGEscapeString(hPGConn, poFeatureDefn->GetName()).c_str(),
-            OGRPGEscapeString(hPGConn, poGeomField->GetNameRef()).c_str(),
-            nSRSId, pszGeometryType, nDimension );
-
-    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
-
-    if( !hResult
-        || PQresultStatus(hResult) != PGRES_TUPLES_OK )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, "AddGeometryColumn failed." );
-
-        OGRPGClearResult( hResult );
-        delete poGeomField;
-
-        return OGRERR_FAILURE;
-    }
-
-    OGRPGClearResult( hResult );
-
-    if( bCreateSpatialIndexFlag )
+    if( !bDifferedCreation )
     {
-        osCommand.Printf("CREATE INDEX %s ON %s USING GIST (%s)",
-                        OGRPGEscapeColumnName(
-                            CPLSPrintf("%s_%s_geom_idx", GetName(), poGeomField->GetNameRef())).c_str(),
-                        pszSqlTableName,
-                        OGRPGEscapeColumnName(poGeomField->GetNameRef()).c_str());
+        poDS->EndCopy();
 
-        hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
-
-        if( !hResult
-            || PQresultStatus(hResult) != PGRES_COMMAND_OK )
+        if( RunAddGeometryColumn(poGeomField) != OGRERR_NONE )
         {
-            CPLError( CE_Failure, CPLE_AppDefined, "CREATE INDEX failed." );
-
-            OGRPGClearResult( hResult );
             delete poGeomField;
 
             return OGRERR_FAILURE;
         }
-        
-        OGRPGClearResult( hResult );
+
+        if( bCreateSpatialIndexFlag )
+        {
+            if( RunCreateSpatialIndex(poGeomField) != OGRERR_NONE )
+            {
+                delete poGeomField;
+
+                return OGRERR_FAILURE;
+            }
+        }
     }
 
     poFeatureDefn->AddGeomFieldDefn( poGeomField, FALSE );
@@ -2524,10 +2265,9 @@ OGRErr OGRPGTableLayer::DeleteField( int iField )
         return OGRERR_FAILURE;
     }
 
-    poDS->FlushSoftTransaction();
-
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    poDS->EndCopy();
 
     osCommand.Printf( "ALTER TABLE %s DROP COLUMN %s",
                       pszSqlTableName,
@@ -2542,17 +2282,11 @@ OGRErr OGRPGTableLayer::DeleteField( int iField )
 
         OGRPGClearResult( hResult );
 
-        hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
-        OGRPGClearResult( hResult );
-
         return OGRERR_FAILURE;
     }
 
     OGRPGClearResult( hResult );
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
-
     return poFeatureDefn->DeleteFieldDefn( iField );
 }
 
@@ -2583,13 +2317,14 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
         return OGRERR_FAILURE;
     }
 
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    poDS->EndCopy();
+
     OGRFieldDefn       *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
     OGRFieldDefn        oField( poNewFieldDefn );
 
-    poDS->FlushSoftTransaction();
-
-    hResult = OGRPG_PQexec(hPGConn, "BEGIN");
-    OGRPGClearResult( hResult );
+    poDS->SoftStartTransaction();
 
     if (!(nFlags & ALTER_TYPE_FLAG))
         oField.SetType(poFieldDefn->GetType());
@@ -2603,13 +2338,12 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
     if ((nFlags & ALTER_TYPE_FLAG) ||
         (nFlags & ALTER_WIDTH_PRECISION_FLAG))
     {
-        CPLString osFieldType = OGRPGTableLayerGetType(oField,
+        CPLString osFieldType = OGRPGCommonLayerGetType(oField,
                                                        bPreservePrecision,
                                                        TRUE);
         if (osFieldType.size() == 0)
         {
-            hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
-            OGRPGClearResult( hResult );
+            poDS->SoftRollbackTransaction();
 
             return OGRERR_FAILURE;
         }
@@ -2618,6 +2352,7 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
                         pszSqlTableName,
                         OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
                         osFieldType.c_str() );
+
         hResult = OGRPG_PQexec(hPGConn, osCommand);
         if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
         {
@@ -2628,20 +2363,84 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
 
             OGRPGClearResult( hResult );
 
-            hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
+            poDS->SoftRollbackTransaction();
+
+            return OGRERR_FAILURE;
+        }
+        OGRPGClearResult( hResult );
+    }
+
+    if( (nFlags & ALTER_NULLABLE_FLAG) &&
+        poFieldDefn->IsNullable() != poNewFieldDefn->IsNullable() )
+    {
+        oField.SetNullable(poNewFieldDefn->IsNullable());
+
+        if( poNewFieldDefn->IsNullable() )
+            osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s DROP NOT NULL",
+                    pszSqlTableName,
+                    OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str() );
+        else
+            osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s SET NOT NULL",
+                    pszSqlTableName,
+                    OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str() );
+
+        hResult = OGRPG_PQexec(hPGConn, osCommand);
+        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s\n%s",
+                    osCommand.c_str(),
+                    PQerrorMessage(hPGConn) );
+
             OGRPGClearResult( hResult );
 
+            poDS->SoftRollbackTransaction();
+
             return OGRERR_FAILURE;
         }
         OGRPGClearResult( hResult );
     }
+    
+    if( (nFlags & ALTER_DEFAULT_FLAG) &&
+        ((poFieldDefn->GetDefault() == NULL && poNewFieldDefn->GetDefault() != NULL) ||
+         (poFieldDefn->GetDefault() != NULL && poNewFieldDefn->GetDefault() == NULL) ||
+         (poFieldDefn->GetDefault() != NULL && poNewFieldDefn->GetDefault() != NULL &&
+          strcmp(poFieldDefn->GetDefault(), poNewFieldDefn->GetDefault()) != 0)) )
+    {
+        oField.SetDefault(poNewFieldDefn->GetDefault());
+
+        if( poNewFieldDefn->GetDefault() == NULL )
+            osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT",
+                    pszSqlTableName,
+                    OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str() );
+        else
+            osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s",
+                    pszSqlTableName,
+                    OGRPGEscapeColumnName(poFieldDefn->GetNameRef()).c_str(),
+                    OGRPGCommonLayerGetPGDefault(poNewFieldDefn).c_str());
+
+        hResult = OGRPG_PQexec(hPGConn, osCommand);
+        if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined,
+                    "%s\n%s",
+                    osCommand.c_str(),
+                    PQerrorMessage(hPGConn) );
 
+            OGRPGClearResult( hResult );
+
+            poDS->SoftRollbackTransaction();
+
+            return OGRERR_FAILURE;
+        }
+        OGRPGClearResult( hResult );
+    }
 
     if( (nFlags & ALTER_NAME_FLAG) )
     {
         if (bLaunderColumnNames)
         {
-            char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
+            char    *pszSafeName = OGRPGCommonLaunderName( oField.GetNameRef(), "PG" );
             oField.SetName( pszSafeName );
             CPLFree( pszSafeName );
         }
@@ -2669,8 +2468,7 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
 
                 OGRPGClearResult( hResult );
 
-                hResult = OGRPG_PQexec( hPGConn, "ROLLBACK" );
-                OGRPGClearResult( hResult );
+                poDS->SoftRollbackTransaction();
 
                 return OGRERR_FAILURE;
             }
@@ -2678,8 +2476,7 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
         }
     }
 
-    hResult = OGRPG_PQexec(hPGConn, "COMMIT");
-    OGRPGClearResult( hResult );
+    poDS->SoftCommitTransaction();
 
     if (nFlags & ALTER_NAME_FLAG)
         poFieldDefn->SetName(oField.GetNameRef());
@@ -2690,6 +2487,10 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
         poFieldDefn->SetWidth(oField.GetWidth());
         poFieldDefn->SetPrecision(oField.GetPrecision());
     }
+    if (nFlags & ALTER_NULLABLE_FLAG)
+        poFieldDefn->SetNullable(oField.IsNullable());
+    if (nFlags & ALTER_DEFAULT_FLAG)
+        poFieldDefn->SetDefault(oField.GetDefault());
 
     return OGRERR_NONE;
 
@@ -2699,7 +2500,7 @@ OGRErr OGRPGTableLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRPGTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     GetLayerDefn()->GetFieldCount();
@@ -2708,11 +2509,6 @@ OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
         return OGRLayer::GetFeature( nFeatureId );
 
 /* -------------------------------------------------------------------- */
-/*      Discard any existing resultset.                                 */
-/* -------------------------------------------------------------------- */
-    ResetReading();
-
-/* -------------------------------------------------------------------- */
 /*      Issue query for a single record.                                */
 /* -------------------------------------------------------------------- */
     OGRFeature  *poFeature = NULL;
@@ -2721,12 +2517,12 @@ OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
     CPLString    osFieldList = BuildFields();
     CPLString    osCommand;
 
-    poDS->FlushSoftTransaction();
+    poDS->EndCopy();
     poDS->SoftStartTransaction();
 
     osCommand.Printf(
              "DECLARE getfeaturecursor %s for "
-             "SELECT %s FROM %s WHERE %s = %ld",
+             "SELECT %s FROM %s WHERE %s = " CPL_FRMT_GIB,
               ( poDS->bUseBinaryCursor ) ? "BINARY CURSOR" : "CURSOR",
              osFieldList.c_str(), pszSqlTableName, OGRPGEscapeColumnName(pszFIDColumn).c_str(),
              nFeatureId );
@@ -2744,22 +2540,34 @@ OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
             int nRows = PQntuples(hResult);
             if (nRows > 0)
             {
-                hCursorResult = hResult;
-                CreateMapFromFieldNameToIndex();
-                poFeature = RecordToFeature( 0 );
-                hCursorResult = NULL;
+                int* panTempMapFieldNameToIndex = NULL;
+                int* panTempMapFieldNameToGeomIndex = NULL;
+                CreateMapFromFieldNameToIndex(hResult,
+                                              poFeatureDefn,
+                                              panTempMapFieldNameToIndex,
+                                              panTempMapFieldNameToGeomIndex);
+                poFeature = RecordToFeature(hResult,
+                                            panTempMapFieldNameToIndex,
+                                            panTempMapFieldNameToGeomIndex,
+                                            0 );
+                CPLFree(panTempMapFieldNameToIndex);
+                CPLFree(panTempMapFieldNameToGeomIndex);
+                if( poFeature && iFIDAsRegularColumnIndex >= 0 )
+                {
+                    poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
+                }
 
                 if (nRows > 1)
                 {
                     CPLError(CE_Warning, CPLE_AppDefined,
-                             "%d rows in response to the WHERE %s = %ld clause !",
+                             "%d rows in response to the WHERE %s = " CPL_FRMT_GIB " clause !",
                              nRows, pszFIDColumn, nFeatureId );
                 }
             }
             else
             {
                  CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to read feature with unknown feature id (%ld).", nFeatureId );
+                  "Attempt to read feature with unknown feature id (" CPL_FRMT_GIB ").", nFeatureId );
             }
         }
     }
@@ -2777,7 +2585,7 @@ OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
     hResult = OGRPG_PQexec(hPGConn, "CLOSE getfeaturecursor");
     OGRPGClearResult( hResult );
 
-    poDS->FlushSoftTransaction();
+    poDS->SoftCommitTransaction();
 
     return poFeature;
 }
@@ -2786,9 +2594,13 @@ OGRFeature *OGRPGTableLayer::GetFeature( long nFeatureId )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRPGTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRPGTableLayer::GetFeatureCount( int bForce )
 
 {
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return 0;
+    poDS->EndCopy();
+
     if( TestCapability(OLCFastFeatureCount) == FALSE )
         return OGRPGLayer::GetFeatureCount( bForce );
 
@@ -2801,7 +2613,7 @@ int OGRPGTableLayer::GetFeatureCount( int bForce )
     PGconn              *hPGConn = poDS->GetPGConn();
     PGresult            *hResult = NULL;
     CPLString           osCommand;
-    int                 nCount = 0;
+    GIntBig              nCount = 0;
 
     osCommand.Printf(
         "SELECT count(*) FROM %s %s",
@@ -2809,7 +2621,7 @@ int OGRPGTableLayer::GetFeatureCount( int bForce )
 
     hResult = OGRPG_PQexec(hPGConn, osCommand);
     if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
-        nCount = atoi(PQgetvalue(hResult,0,0));
+        nCount = CPLAtoGIntBig(PQgetvalue(hResult,0,0));
     else
         CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
     OGRPGClearResult( hResult );
@@ -2837,11 +2649,8 @@ void OGRPGTableLayer::ResolveSRID(OGRPGGeomFieldDefn* poGFldDefn)
                 OGRPGEscapeString(hPGConn, pszTableName).c_str(),
                 OGRPGEscapeString(hPGConn, poGFldDefn->GetNameRef()).c_str());
 
-    if (pszSchemaName)
-    {
-        osCommand += CPLString().Printf(" AND f_table_schema = %s",
-                                        OGRPGEscapeString(hPGConn, pszSchemaName).c_str());
-    }
+    osCommand += CPLString().Printf(" AND f_table_schema = %s",
+                                    OGRPGEscapeString(hPGConn, pszSchemaName).c_str());
 
     hResult = OGRPG_PQexec(hPGConn, osCommand.c_str() );
 
@@ -2857,7 +2666,8 @@ void OGRPGTableLayer::ResolveSRID(OGRPGGeomFieldDefn* poGFldDefn)
     /* With PostGIS 2.0, SRID = 0 can also mean that there's no constraint */
     /* so we need to fetch from values */
     /* We assume that all geometry of this column have identical SRID */
-    if( nSRSId <= 0 && poGFldDefn->ePostgisType == GEOM_TYPE_GEOMETRY )
+    if( nSRSId <= 0 && poGFldDefn->ePostgisType == GEOM_TYPE_GEOMETRY &&
+        poDS->sPostGISVersion.nMajor >= 0 )
     {
         CPLString osGetSRID;
 
@@ -2893,13 +2703,12 @@ void OGRPGTableLayer::ResolveSRID(OGRPGGeomFieldDefn* poGFldDefn)
 /*                             StartCopy()                              */
 /************************************************************************/
 
-OGRErr OGRPGTableLayer::StartCopy(int bSetFID)
+OGRErr OGRPGTableLayer::StartCopy()
 
 {
-    /* Tell the datasource we are now planning to copy data */
-    poDS->StartCopy( this ); 
+    /*CPLDebug("PG", "OGRPGDataSource(%p)::StartCopy(%p)", poDS, this);*/
 
-    CPLString osFields = BuildCopyFields(bSetFID);
+    CPLString osFields = BuildCopyFields();
 
     int size = strlen(osFields) +  strlen(pszSqlTableName) + 100;
     char *pszCommand = (char *) CPLMalloc(size);
@@ -2934,6 +2743,7 @@ OGRErr OGRPGTableLayer::EndCopy()
 {
     if( !bCopyActive )
         return OGRERR_NONE;
+    /*CPLDebug("PG", "OGRPGDataSource(%p)::EndCopy(%p)", poDS, this);*/
 
     /* This method is called from the datasource when
        a COPY operation is ended */
@@ -2985,7 +2795,8 @@ OGRErr OGRPGTableLayer::EndCopy()
 
     OGRPGClearResult( hResult );
 
-    bUseCopy = USE_COPY_UNSET;
+    if( !bUseCopyByDefault )
+        bUseCopy = USE_COPY_UNSET;
 
     return result;
 }
@@ -2994,7 +2805,7 @@ OGRErr OGRPGTableLayer::EndCopy()
 /*                          BuildCopyFields()                           */
 /************************************************************************/
 
-CPLString OGRPGTableLayer::BuildCopyFields(int bSetFID)
+CPLString OGRPGTableLayer::BuildCopyFields()
 {
     int     i = 0;
     int     nFIDIndex = -1;
@@ -3009,7 +2820,6 @@ CPLString OGRPGTableLayer::BuildCopyFields(int bSetFID)
         osFieldList += OGRPGEscapeColumnName(poGeomFieldDefn->GetNameRef());
     }
 
-    bFIDColumnInCopyFields = (pszFIDColumn != NULL && bSetFID);
     if( bFIDColumnInCopyFields )
     {
         if( osFieldList.size() > 0 )
@@ -3137,6 +2947,10 @@ OGRErr OGRPGTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bF
         return OGRERR_FAILURE;
     }
 
+    if( bDifferedCreation && RunDifferedCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+    poDS->EndCopy();
+
     OGRPGGeomFieldDefn* poGeomFieldDefn =
         poFeatureDefn->myGetGeomFieldDefn(iGeomField);
 
@@ -3162,7 +2976,9 @@ OGRErr OGRPGTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bF
                         OGRPGEscapeString(hPGConn, pszTableName).c_str(),
                         OGRPGEscapeString(hPGConn, poGeomFieldDefn->GetNameRef()).c_str() );
 
-        if( RunGetExtentRequest(psExtent, bForce, osCommand) == OGRERR_NONE )
+        /* Quiet error: ST_Estimated_Extent may return an error if statistics */
+        /* have not been computed */
+        if( RunGetExtentRequest(psExtent, bForce, osCommand, TRUE) == OGRERR_NONE )
             return OGRERR_NONE;
 
         CPLDebug("PG","Unable to get extimated extent by PostGIS. Trying real extent.");
@@ -3170,3 +2986,101 @@ OGRErr OGRPGTableLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bF
 
     return OGRPGLayer::GetExtent( iGeomField, psExtent, bForce );
 }
+
+/************************************************************************/
+/*                        SetDifferedCreation()                         */
+/************************************************************************/
+
+void OGRPGTableLayer::SetDifferedCreation(int bDifferedCreationIn, CPLString osCreateTableIn)
+{
+    bDifferedCreation = bDifferedCreationIn;
+    osCreateTable = osCreateTableIn;
+}
+
+/************************************************************************/
+/*                      RunDifferedCreationIfNecessary()                */
+/************************************************************************/
+
+OGRErr OGRPGTableLayer::RunDifferedCreationIfNecessary()
+{
+    if( !bDifferedCreation )
+        return OGRERR_NONE;
+    bDifferedCreation = FALSE;
+
+    poDS->EndCopy();
+
+    int i;
+
+    for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
+    {
+        OGRPGGeomFieldDefn *poGeomField = (OGRPGGeomFieldDefn*) poFeatureDefn->GetGeomFieldDefn(i);
+
+        if (poDS->sPostGISVersion.nMajor >= 2 ||
+            poGeomField->ePostgisType == GEOM_TYPE_GEOGRAPHY)
+        {
+            const char *pszGeometryType = OGRToOGCGeomType(poGeomField->GetType());
+
+            osCreateTable += ", ";
+            osCreateTable += OGRPGEscapeColumnName(poGeomField->GetNameRef());
+            osCreateTable += " ";
+            if( poGeomField->ePostgisType == GEOM_TYPE_GEOMETRY )
+                osCreateTable += "geometry(";
+            else
+                osCreateTable += "geography(";
+            osCreateTable += pszGeometryType;
+            if( poGeomField->nCoordDimension == 3 )
+                osCreateTable += "Z";
+            if( poGeomField->nSRSId > 0 )
+                osCreateTable += CPLSPrintf(",%d", poGeomField->nSRSId);
+            osCreateTable += ")";
+            if( !poGeomField->IsNullable() )
+                osCreateTable += " NOT NULL";
+        }
+    }
+
+    osCreateTable += " )";
+    CPLString osCommand(osCreateTable);
+    
+    PGresult            *hResult;
+    PGconn              *hPGConn = poDS->GetPGConn();
+    
+    hResult = OGRPG_PQexec(hPGConn, osCommand.c_str());
+    if( PQresultStatus(hResult) != PGRES_COMMAND_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                "%s\n%s", osCommand.c_str(), PQerrorMessage(hPGConn) );
+
+        OGRPGClearResult( hResult );
+        return OGRERR_FAILURE;
+    }
+
+    OGRPGClearResult( hResult );
+
+    // For PostGIS 1.X, use AddGeometryColumn() to create geometry columns
+    if (poDS->sPostGISVersion.nMajor < 2)
+    {
+        for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
+        {
+            OGRPGGeomFieldDefn *poGeomField = (OGRPGGeomFieldDefn*) poFeatureDefn->GetGeomFieldDefn(i);
+            if( poGeomField->ePostgisType == GEOM_TYPE_GEOMETRY &&
+                RunAddGeometryColumn(poGeomField) != OGRERR_NONE )
+            {
+                return OGRERR_FAILURE;
+            }
+        }
+    }
+    
+    if( bCreateSpatialIndexFlag )
+    {
+        for( i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
+        {
+            OGRPGGeomFieldDefn *poGeomField = (OGRPGGeomFieldDefn*) poFeatureDefn->GetGeomFieldDefn(i);
+            if( RunCreateSpatialIndex(poGeomField) != OGRERR_NONE )
+            {
+                return OGRERR_FAILURE;
+            }
+        }
+    }
+
+    return OGRERR_NONE;
+}
diff --git a/ogr/ogrsf_frmts/pg/ogrpgutility.cpp b/ogr/ogrsf_frmts/pg/ogrpgutility.cpp
index d228491..a982e1e 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgutility.cpp
+++ b/ogr/ogrsf_frmts/pg/ogrpgutility.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgutility.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpgutility.cpp 27784 2014-10-02 15:43:18Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Utility methods
@@ -30,13 +30,14 @@
 #include "ogr_pg.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrpgutility.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpgutility.cpp 27784 2014-10-02 15:43:18Z rouault $");
 
 /************************************************************************/
 /*                         OGRPG_PQexec()                               */
 /************************************************************************/
 
-PGresult *OGRPG_PQexec(PGconn *conn, const char *query, int bMultipleCommandAllowed)
+PGresult *OGRPG_PQexec(PGconn *conn, const char *query, int bMultipleCommandAllowed,
+                       int bErrorAsDebug)
 {
     PGresult* hResult;
 #if defined(PG_PRE74)
@@ -77,6 +78,7 @@ PGresult *OGRPG_PQexec(PGconn *conn, const char *query, int bMultipleCommandAllo
         CPLDebug("PG", "PQexec(%s) = %s%s", query, pszRetCode, szNTuples);
     else
         CPLDebug("PG", "PQexecParams(%s) = %s%s", query, pszRetCode, szNTuples);
+#endif
 
 /* -------------------------------------------------------------------- */
 /*      Generate an error report if an error occured.                   */
@@ -84,9 +86,11 @@ PGresult *OGRPG_PQexec(PGconn *conn, const char *query, int bMultipleCommandAllo
     if ( !hResult || (PQresultStatus(hResult) == PGRES_NONFATAL_ERROR ||
                       PQresultStatus(hResult) == PGRES_FATAL_ERROR ) )
     {
-        CPLDebug( "PG", "%s", PQerrorMessage( conn ) );
+        if( bErrorAsDebug )
+            CPLDebug("PG", "%s", PQerrorMessage( conn ) );
+        else
+            CPLError( CE_Failure, CPLE_AppDefined, "%s", PQerrorMessage( conn ) );
     }
-#endif
 
     return hResult;
 }
diff --git a/ogr/ogrsf_frmts/pg/ogrpgutility.h b/ogr/ogrsf_frmts/pg/ogrpgutility.h
index de6a1a3..2371fe1 100644
--- a/ogr/ogrsf_frmts/pg/ogrpgutility.h
+++ b/ogr/ogrsf_frmts/pg/ogrpgutility.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgutility.h 22450 2011-05-28 21:25:11Z rouault $
+ * $Id: ogrpgutility.h 27784 2014-10-02 15:43:18Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private utilities for OGR/PostgreSQL driver.
@@ -33,7 +33,8 @@
 #include "libpq-fe.h"
 
 PGresult *OGRPG_PQexec(PGconn *conn, const char *query,
-                       int bMultipleCommandAllowed = FALSE);
+                       int bMultipleCommandAllowed = FALSE,
+                       int bErrorAsDebug = FALSE);
 
 /************************************************************************/
 /*                            OGRPGClearResult                          */
diff --git a/ogr/ogrsf_frmts/pgdump/GNUmakefile b/ogr/ogrsf_frmts/pgdump/GNUmakefile
index 6e5a975..cce818e 100644
--- a/ogr/ogrsf_frmts/pgdump/GNUmakefile
+++ b/ogr/ogrsf_frmts/pgdump/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrpgdumpdriver.o ogrpgdumpdatasource.o ogrpgdumplayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/pgdump/drv_pgdump.html b/ogr/ogrsf_frmts/pgdump/drv_pgdump.html
index b2e7d13..4b39a7a 100644
--- a/ogr/ogrsf_frmts/pgdump/drv_pgdump.html
+++ b/ogr/ogrsf_frmts/pgdump/drv_pgdump.html
@@ -60,26 +60,30 @@ omitted it defaults to <i>wkb_geometry</i> for GEOM_TYPE=geometry, or <i>the_geo
 Using the same layer name in different schemas is supported, but not in the public schema and others.<p>
 <li> <b>CREATE_SCHEMA</b>: (OGR >= 1.8.1) To be used in combination with SCHEMA. Set to ON by default so that
 the CREATE SCHEMA instruction is emitted. Turn to OFF to prevent CREATE SCHEMA from being emitted.<p>
-<li> <b>SPATIAL_INDEX</b>:  Set to ON by default. Creates a spatial index on the geometry column
+<li> <b>SPATIAL_INDEX</b>:  Set to ON by default. Creates a spatial index (GiST) on the geometry column
 to speed up queries. Set to OFF to disable. (Has effect only when PostGIS is available).<p>
 <li> <b>TEMPORARY</b>: Set to OFF by default. Creates a temporary table instead of a permanent one.<p>
+<li> <b>UNLOGGED</b>: (From GDAL 2.0) Set to OFF by default. Whether to create the table as a unlogged one.
+Unlogged tables are only supported since PostgreSQL 9.1, and GiST indexes used for spatial indexing since PostgreSQL 9.3.<p>
 <li> <b>WRITE_EWKT_GEOM</b>: Set to OFF by default. Turn to ON to write EWKT geometries instead of HEX geometries.
 This option will have no effect if PG_USE_COPY environment variable is to YES.<p>
 <li> <b>CREATE_TABLE</b>: Set to ON by default so that tables are recreated if necessary. Turn to OFF to disable this and use existing table structure.<p>
-<li> <b>DROP_TABLE</b>: (OGR >= 1.8.1) Set to ON by default so that tables are destroyed before being recreated.
-Set to OFF to prevent DROP TABLE from being emitted. Set to IF_EXISTS in order DROP TABLE IF EXISTS to be emitted (needs PostgreSQL >= 8.2)<p>
+<li> <b>DROP_TABLE</b>=ON/OFF/IF_EXISTS: (OGR >= 1.8.1) Set to ON so that tables are destroyed before being recreated.
+Set to OFF to prevent DROP TABLE from being emitted. Set to IF_EXISTS (default in GDAL 2.0) in order DROP TABLE IF EXISTS to be emitted (needs PostgreSQL >= 8.2)<p>
 <li> <b>SRID</b>: Set the SRID of the geometry. Defaults to -1, unless a SRS is associated with the layer. In the case, if the EPSG code is mentionned, it will be used as the SRID. (Note: the spatial_ref_sys table must be correctly populated with the specified SRID) <p>
 <li> <b>NONE_AS_UNKNOWN</b>: (From GDAL 1.9.0) Can bet set to TRUE to force non-spatial layers (wkbNone) to be created as
 spatial tables of type GEOMETRY (wkbUnknown), which was the behaviour prior to GDAL 1.8.0. Defaults to NO, in which case
 a regular table is created and not recorded in the PostGIS geometry_columns table.<p>
 <li> <b>FID</b>: (From GDAL 1.9.0) Name of the FID column to create. Defaults to 'ogc_fid'.<p>
+<li> <b>FID64</b>: (From GDAL 2.0) This may be "TRUE" to create a FID column that can support
+64 bit identifiers. The default value is "FALSE".</li>
 <li> <b>EXTRACT_SCHEMA_FROM_LAYER_NAME</b>: (From GDAL 1.9.0) Can be set to NO to avoid considering the dot character
 as the separator between the schema and the table name. Defaults to YES.<p>
 <li> <b>COLUMN_TYPES</b>: (From GDAL 1.10) A list of strings of format field_name=pg_field_type (separated by comma)
 that should be use when CreateField() is invoked on them. This will override the default choice that OGR would have made.
 This can for example be used to create a column of type <a href="http://www.postgresql.org/docs/9.0/static/hstore.html">HSTORE</a>.<p>
-<li> <b>POSTGIS_VERSION</b>: (From GDAL 1.9.0) Can be set to 2.0 for PostGIS 2.0 compatibility. For now, it is not
-critical to set it. Its effect is just to avoid a few warnings.<p>
+<li> <b>POSTGIS_VERSION</b>: (From GDAL 1.9.0) Can be set to 2.0 for PostGIS 2.0 compatibility. Starting with GDAL 2.0,
+it is important to set it correctly when dealing with non-linear geometry types.<p>
 </ul>
 
 <h3>Environment variables</h3>
diff --git a/ogr/ogrsf_frmts/pgdump/ogr_pgdump.h b/ogr/ogrsf_frmts/pgdump/ogr_pgdump.h
index 11849f0..226cf92 100644
--- a/ogr/ogrsf_frmts/pgdump/ogr_pgdump.h
+++ b/ogr/ogrsf_frmts/pgdump/ogr_pgdump.h
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogr_pgdump.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_pgdump.h 28988 2015-04-24 11:58:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/PostgreSQL dump driver.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -36,7 +36,35 @@
 CPLString OGRPGDumpEscapeColumnName(const char* pszColumnName);
 CPLString OGRPGDumpEscapeString(   const char* pszStrValue, int nMaxLength = -1,
                                    const char* pszFieldName = "");
-
+CPLString CPL_DLL OGRPGCommonLayerGetType(OGRFieldDefn& oField,
+                                          int bPreservePrecision,
+                                          int bApproxOK);
+int CPL_DLL OGRPGCommonLayerSetType(OGRFieldDefn& oField,
+                                    const char* pszType,
+                                    const char* pszFormatType,
+                                    int nWidth);
+void CPL_DLL OGRPGCommonLayerNormalizeDefault(OGRFieldDefn* poFieldDefn,
+                                              const char* pszDefault);
+CPLString CPL_DLL OGRPGCommonLayerGetPGDefault(OGRFieldDefn* poFieldDefn);
+
+typedef CPLString (*OGRPGCommonEscapeStringCbk)(void* userdata,
+                                                const char* pszValue, 
+                                                int nWidth,
+                                                const char* pszLayerName,
+                                                const char* pszFieldRef);
+void CPL_DLL OGRPGCommonAppendCopyFieldsExceptGeom(CPLString& osCommand,
+                                           OGRFeature* poFeature,
+                                           const char* pszFIDColumn,
+                                           int bFIDColumnInCopyFields,
+                                           OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                           void* userdata);
+void CPL_DLL OGRPGCommonAppendFieldValue(CPLString& osCommand,
+                                 OGRFeature* poFeature, int i,
+                                 OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                 void* userdata);
+
+char CPL_DLL *OGRPGCommonLaunderName( const char *pszSrcName,
+                                      const char* pszDebugPrefix = "OGR" );
 
 /************************************************************************/
 /*                        OGRPGDumpGeomFieldDefn                        */
@@ -68,7 +96,6 @@ class OGRPGDumpLayer : public OGRLayer
     char                *pszFIDColumn;
     OGRFeatureDefn      *poFeatureDefn;
     OGRPGDumpDataSource *poDS;
-    int                 nFeatures;
     int                 bLaunderColumnNames;
     int                 bPreservePrecision;
     int                 bUseCopy;
@@ -79,12 +106,14 @@ class OGRPGDumpLayer : public OGRLayer
     int                 nUnknownSRSId;
     int                 nForcedSRSId;
     int                 bCreateSpatialIndexFlag;
+    int                 bPostGIS2;
 
-    char              **papszOverrideColumnTypes;
+    int                 iNextShapeId;
+    int                 iFIDAsRegularColumnIndex;
+    int                 bAutoFIDOnCreateViaCopy;
+    int                 bCopyStatementWithFID;
 
-    void                AppendFieldValue(CPLString& osCommand,
-                                       OGRFeature* poFeature, int i);
-    char*               GByteArrayToBYTEA( const GByte* pabyData, int nLen);
+    char              **papszOverrideColumnTypes;
 
     OGRErr              StartCopy(int bSetFID);
     CPLString           BuildCopyFields(int bSetFID);
@@ -99,11 +128,12 @@ class OGRPGDumpLayer : public OGRLayer
     virtual             ~OGRPGDumpLayer();
 
     virtual OGRFeatureDefn *GetLayerDefn() {return poFeatureDefn;}
+    virtual const char* GetFIDColumn() { return pszFIDColumn; }
     
     virtual void        ResetReading()  { }
     virtual int         TestCapability( const char * );
     
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
     virtual OGRErr      CreateFeatureViaInsert( OGRFeature *poFeature );
     virtual OGRErr      CreateFeatureViaCopy( OGRFeature *poFeature );
 
@@ -127,7 +157,11 @@ class OGRPGDumpLayer : public OGRLayer
                                 { nForcedSRSId = nForcedSRSIdIn; }
     void                SetCreateSpatialIndexFlag( int bFlag )
                                 { bCreateSpatialIndexFlag = bFlag; }
+    void                SetPostGIS2( int bFlag )
+                                { bPostGIS2 = bFlag; }
     OGRErr              EndCopy();
+
+    static char*        GByteArrayToBYTEA( const GByte* pabyData, int nLen);
 };
 
 /************************************************************************/
@@ -148,45 +182,26 @@ class OGRPGDumpDataSource : public OGRDataSource
                         OGRPGDumpDataSource(const char* pszName,
                                             char** papszOptions);
                         ~OGRPGDumpDataSource();
-                        
-    char               *LaunderName( const char *pszSrcName );
-    void                Log(const char* pszStr, int bAddSemiColumn = TRUE);
+
+    int                 Log(const char* pszStr, int bAddSemiColumn = TRUE);
 
     virtual const char  *GetName() { return pszName; }
     virtual int         GetLayerCount() { return nLayers; }
     virtual OGRLayer   *GetLayer( int );
 
-    virtual OGRLayer    *CreateLayer( const char *,
+    virtual OGRLayer    *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
 
     virtual int         TestCapability( const char * );
 
-    void                StartTransaction();
-    void                Commit();
+    void                LogStartTransaction();
+    void                LogCommit();
 
     void                StartCopy( OGRPGDumpLayer *poPGLayer );
     OGRErr              EndCopy( );
 };
 
-/************************************************************************/
-/*                             OGRPGDriver                              */
-/************************************************************************/
-
-class OGRPGDumpDriver : public OGRSFDriver
-{
-  public:
-                ~OGRPGDumpDriver();
-
-    virtual const char    *GetName();
-    virtual OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-
-    virtual int            TestCapability( const char * );
-};
-
 #endif /* ndef _OGR_PGDUMP_H_INCLUDED */
 
diff --git a/ogr/ogrsf_frmts/pgdump/ogrpgdumpdatasource.cpp b/ogr/ogrsf_frmts/pgdump/ogrpgdumpdatasource.cpp
index 542b3d5..7df03bd 100644
--- a/ogr/ogrsf_frmts/pgdump/ogrpgdumpdatasource.cpp
+++ b/ogr/ogrsf_frmts/pgdump/ogrpgdumpdatasource.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogrpgdumpdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpgdumpdatasource.cpp 28988 2015-04-24 11:58:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDumpDataSource class.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrpgdumpdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpgdumpdatasource.cpp 28988 2015-04-24 11:58:49Z rouault $");
 
 /************************************************************************/
 /*                      OGRPGDumpDataSource()                           */
@@ -90,7 +90,7 @@ OGRPGDumpDataSource::~OGRPGDumpDataSource()
 
     if (fp)
     {
-        Commit();
+        LogCommit();
         VSIFCloseL(fp);
         fp = NULL;
     }
@@ -102,10 +102,10 @@ OGRPGDumpDataSource::~OGRPGDumpDataSource()
 }
 
 /************************************************************************/
-/*                         StartTransaction()                           */
+/*                         LogStartTransaction()                        */
 /************************************************************************/
 
-void OGRPGDumpDataSource::StartTransaction()
+void OGRPGDumpDataSource::LogStartTransaction()
 {
     if (bInTransaction)
         return;
@@ -114,10 +114,10 @@ void OGRPGDumpDataSource::StartTransaction()
 }
 
 /************************************************************************/
-/*                              Commit()                                */
+/*                             LogCommit()                              */
 /************************************************************************/
 
-void OGRPGDumpDataSource::Commit()
+void OGRPGDumpDataSource::LogCommit()
 {
     EndCopy();
 
@@ -128,10 +128,10 @@ void OGRPGDumpDataSource::Commit()
 }
 
 /************************************************************************/
-/*                            LaunderName()                             */
+/*                         OGRPGCommonLaunderName()                     */
 /************************************************************************/
 
-char *OGRPGDumpDataSource::LaunderName( const char *pszSrcName )
+char *OGRPGCommonLaunderName( const char *pszSrcName, const char* pszDebugPrefix )
 
 {
     char    *pszSafeName = CPLStrdup( pszSrcName );
@@ -144,18 +144,18 @@ char *OGRPGDumpDataSource::LaunderName( const char *pszSrcName )
     }
 
     if( strcmp(pszSrcName,pszSafeName) != 0 )
-        CPLDebug("PG","LaunderName('%s') -> '%s'", 
+        CPLDebug(pszDebugPrefix,"LaunderName('%s') -> '%s'", 
                  pszSrcName, pszSafeName);
 
     return pszSafeName;
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
+OGRPGDumpDataSource::ICreateLayer( const char * pszLayerName,
                                   OGRSpatialReference *poSRS,
                                   OGRwkbGeometryType eType,
                                   char ** papszOptions )
@@ -167,26 +167,26 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
     char                *pszSchemaName = NULL;
     int                  nDimension = 3;
     int                  bHavePostGIS = TRUE;
-    
-    if( nLayers == 0 )
-         Log("SET standard_conforming_strings = OFF");
 
-    const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
-    CPLString osFIDColumnName;
-    if (pszFIDColumnName == NULL)
-        osFIDColumnName = "OGC_FID";
+    const char* pszFIDColumnNameIn = CSLFetchNameValue(papszOptions, "FID");
+    CPLString osFIDColumnName, osFIDColumnNameEscaped;
+    if (pszFIDColumnNameIn == NULL)
+        osFIDColumnNameEscaped = osFIDColumnName = "OGC_FID";
     else
     {
         if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
         {
-            char* pszLaunderedFid = LaunderName(pszFIDColumnName);
-            osFIDColumnName += OGRPGDumpEscapeColumnName(pszLaunderedFid);
+            char* pszLaunderedFid = OGRPGCommonLaunderName(pszFIDColumnNameIn, "PGDump");
+            osFIDColumnName = pszLaunderedFid;
+            osFIDColumnNameEscaped = OGRPGDumpEscapeColumnName(osFIDColumnName);
             CPLFree(pszLaunderedFid);
         }
         else
-            osFIDColumnName += OGRPGDumpEscapeColumnName(pszFIDColumnName);
+        {
+            osFIDColumnName = pszFIDColumnNameIn;
+            osFIDColumnNameEscaped = OGRPGDumpEscapeColumnName(osFIDColumnName);
+        }
     }
-    pszFIDColumnName = osFIDColumnName.c_str();
 
     if (strncmp(pszLayerName, "pg", 2) == 0)
     {
@@ -198,7 +198,7 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
 
     int bCreateTable = CSLFetchBoolean(papszOptions,"CREATE_TABLE", TRUE);
     int bCreateSchema = CSLFetchBoolean(papszOptions,"CREATE_SCHEMA", TRUE);
-    const char* pszDropTable = CSLFetchNameValueDef(papszOptions,"DROP_TABLE", "YES");
+    const char* pszDropTable = CSLFetchNameValueDef(papszOptions,"DROP_TABLE", "IF_EXISTS");
 
     if( wkbFlatten(eType) == eType )
         nDimension = 2;
@@ -232,7 +232,7 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
       pszSchemaName[length] = '\0';
 
       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
-          pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
+          pszTableName = OGRPGCommonLaunderName( pszDotPos + 1, "PGDump" ); //skip "."
       else
           pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
     }
@@ -240,12 +240,12 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
     {
       pszSchemaName = NULL;
       if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
-          pszTableName = LaunderName( pszLayerName ); //skip "."
+          pszTableName = OGRPGCommonLaunderName( pszLayerName, "PGDump" ); //skip "."
       else
           pszTableName = CPLStrdup( pszLayerName ); //skip "."
     }
 
-    Commit();
+    LogCommit();
 
 /* -------------------------------------------------------------------- */
 /*      Set the default schema for the layers.                          */
@@ -323,8 +323,12 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
 /* -------------------------------------------------------------------- */
     int nUnknownSRSId = -1;
     const char* pszPostgisVersion = CSLFetchNameValue( papszOptions, "POSTGIS_VERSION" );
+    int bPostGIS2 = FALSE;
     if( pszPostgisVersion != NULL && atoi(pszPostgisVersion) >= 2 )
+    {
+        bPostGIS2 = TRUE;
         nUnknownSRSId = 0;
+    }
 
     int nSRSId = nUnknownSRSId;
     int nForcedSRSId = -2;
@@ -381,16 +385,17 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
     }
 
 
-    StartTransaction();
+    LogStartTransaction();
 
 /* -------------------------------------------------------------------- */
 /*      Create a basic table with the FID.  Also include the            */
 /*      geometry if this is not a PostGIS enabled table.                */
 /* -------------------------------------------------------------------- */
+    int bFID64 = CSLFetchBoolean(papszOptions, "FID64", FALSE);
+    const char* pszSerialType = bFID64 ? "BIGSERIAL": "SERIAL";
     
     CPLString osCreateTable;
-    int bTemporary = CSLFetchNameValue( papszOptions, "TEMPORARY" ) != NULL &&
-                     CSLTestBoolean(CSLFetchNameValue( papszOptions, "TEMPORARY" ));
+    int bTemporary = CSLFetchBoolean( papszOptions, "TEMPORARY", FALSE );
     if (bTemporary)
     {
         CPLFree(pszSchemaName);
@@ -398,23 +403,25 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
         osCreateTable.Printf("CREATE TEMPORARY TABLE \"%s\"", pszTableName);
     }
     else
-        osCreateTable.Printf("CREATE TABLE \"%s\".\"%s\"", pszSchemaName, pszTableName);
+        osCreateTable.Printf("CREATE TABLE%s \"%s\".\"%s\"",
+                             CSLFetchBoolean( papszOptions, "UNLOGGED", FALSE ) ? " UNLOGGED": "",
+                             pszSchemaName, pszTableName);
 
     if( !bHavePostGIS )
     {
         if (eType == wkbNone)
             osCommand.Printf(
                     "%s ( "
-                    "   %s SERIAL, "
+                    "   %s %s, "
                     "   CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
-                    osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
+                    osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszTableName, osFIDColumnNameEscaped.c_str() );
         else
             osCommand.Printf(
                     "%s ( "
-                    "   %s SERIAL, "
+                    "   %s %s, "
                     "   WKB_GEOMETRY %s, "
                     "   CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
-                    osCreateTable.c_str(), pszFIDColumnName, pszGeomType, pszTableName, pszFIDColumnName );
+                    osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGeomType, pszTableName, osFIDColumnNameEscaped.c_str() );
     }
     else if ( EQUAL(pszGeomType, "geography") )
     {
@@ -425,18 +432,18 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
 
         if (nSRSId)
             osCommand.Printf(
-                     "%s ( %s SERIAL, \"%s\" geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
-                     osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", nSRSId, pszTableName, pszFIDColumnName );
+                     "%s ( %s %s, \"%s\" geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
+                     osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", nSRSId, pszTableName, osFIDColumnNameEscaped.c_str() );
         else
             osCommand.Printf(
-                     "%s ( %s SERIAL, \"%s\" geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
-                     osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", pszTableName, pszFIDColumnName );
+                     "%s ( %s %s, \"%s\" geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
+                     osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", pszTableName, osFIDColumnNameEscaped.c_str() );
     }
     else
     {
         osCommand.Printf(
-                 "%s ( %s SERIAL, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
-                 osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
+                 "%s ( %s %s, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
+                 osCreateTable.c_str(), osFIDColumnNameEscaped.c_str(), pszSerialType, pszTableName, osFIDColumnNameEscaped.c_str() );
     }
 
     if (bCreateTable)
@@ -482,7 +489,7 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
     int bWriteAsHex = !CSLFetchBoolean(papszOptions,"WRITE_EWKT_GEOM",FALSE);
 
     poLayer = new OGRPGDumpLayer( this, pszSchemaName, pszTableName,
-                                  pszFIDColumnName, bWriteAsHex, bCreateTable );
+                                  osFIDColumnName, bWriteAsHex, bCreateTable );
     poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
     poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
 
@@ -491,6 +498,7 @@ OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
     poLayer->SetUnknownSRSId(nUnknownSRSId);
     poLayer->SetForcedSRSId(nForcedSRSId);
     poLayer->SetCreateSpatialIndexFlag(bCreateSpatialIndex);
+    poLayer->SetPostGIS2(bPostGIS2);
 
     if( bHavePostGIS )
     {
@@ -527,6 +535,8 @@ int OGRPGDumpDataSource::TestCapability( const char * pszCap )
         return TRUE;
     else if( EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) )
         return TRUE;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     else
         return FALSE;
 }
@@ -548,18 +558,18 @@ OGRLayer *OGRPGDumpDataSource::GetLayer( int iLayer )
 /*                                  Log()                               */
 /************************************************************************/
 
-void  OGRPGDumpDataSource::Log(const char* pszStr, int bAddSemiColumn)
+int  OGRPGDumpDataSource::Log(const char* pszStr, int bAddSemiColumn)
 {
     if (fp == NULL)
     {
         if (bTriedOpen)
-            return;
+            return FALSE;
         bTriedOpen = TRUE;
         fp = VSIFOpenL(pszName, "wb");
         if (fp == NULL)
         {
             CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszName);
-            return;
+            return FALSE;
         }
     }
 
@@ -567,6 +577,7 @@ void  OGRPGDumpDataSource::Log(const char* pszStr, int bAddSemiColumn)
         VSIFPrintfL(fp, "%s;%s", pszStr, pszEOL);
     else
         VSIFPrintfL(fp, "%s%s", pszStr, pszEOL);
+    return TRUE;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/pgdump/ogrpgdumpdriver.cpp b/ogr/ogrsf_frmts/pgdump/ogrpgdumpdriver.cpp
index 46b2ddd..dd8aaae 100644
--- a/ogr/ogrsf_frmts/pgdump/ogrpgdumpdriver.cpp
+++ b/ogr/ogrsf_frmts/pgdump/ogrpgdumpdriver.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogrpgdumpdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrpgdumpdriver.cpp 28908 2015-04-15 09:01:01Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDumpDriver class.
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2011, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2011, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -30,45 +30,18 @@
 #include "ogr_pgdump.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrpgdumpdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrpgdumpdriver.cpp 28908 2015-04-15 09:01:01Z rouault $");
 
 /************************************************************************/
-/*                         ~OGRPGDumpDriver()                           */
+/*                         OGRPGDumpDriverCreate()                      */
 /************************************************************************/
 
-OGRPGDumpDriver::~OGRPGDumpDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRPGDumpDriver::GetName()
-
-{
-    return "PGDump";
-}
-
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
-
-OGRDataSource *OGRPGDumpDriver::Open( CPL_UNUSED const char * pszFilename,
-                                      CPL_UNUSED int bUpdate )
-
-{
-    return NULL;
-}
-
-/************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGRPGDumpDriver::CreateDataSource( const char * pszName,
-                                                  char ** papszOptions )
-
+static GDALDataset* OGRPGDumpDriverCreate( const char * pszName,
+                                           CPL_UNUSED int nXSize,
+                                           CPL_UNUSED int nYSize,
+                                           CPL_UNUSED int nBands,
+                                           CPL_UNUSED GDALDataType eDT,
+                                           char ** papszOptions )
 {
     OGRPGDumpDataSource     *poDS;
 
@@ -76,30 +49,92 @@ OGRDataSource *OGRPGDumpDriver::CreateDataSource( const char * pszName,
         pszName = "/vsistdout/";
 
     poDS = new OGRPGDumpDataSource(pszName, papszOptions);
+    if( !poDS->Log("SET standard_conforming_strings = OFF") )
+    {
+        delete poDS;
+        return NULL;
+    }
 
     return poDS;
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRPGDumpDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                        RegisterOGRPGDump()                           */
 /************************************************************************/
 
 void RegisterOGRPGDump()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPGDumpDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "PGDUMP" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "PGDUMP" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                    "PostgreSQL SQL dump" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                    "drv_pgdump.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sql" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+    "<CreationOptionList>"
+    #ifdef WIN32
+    "  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='CRLF'>"
+    #else
+    "  <Option name='LINEFORMAT' type='string-select' description='end-of-line sequence' default='LF'>"
+    #endif
+    "    <Value>CRLF</Value>"
+    "    <Value>LF</Value>"
+    "  </Option>"
+    "</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+    "<LayerCreationOptionList>"
+    "  <Option name='GEOM_TYPE' type='string-select' description='Format of geometry columns' default='geometry'>"
+    "    <Value>geometry</Value>"
+    "    <Value>geography</Value>"
+    "  </Option>"
+    "  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+    "  <Option name='PRECISION' type='boolean' description='Whether fields created should keep the width and precision' default='YES'/>"
+    "  <Option name='DIM' type='integer' description='Set to 2 to force the geometries to be 2D, or 3 to be 2.5D'/>"
+    "  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column. Defaults to wkb_geometry for GEOM_TYPE=geometry or the_geog for GEOM_TYPE=geography'/>"
+    "  <Option name='SCHEMA' type='string' description='Name of schema into which to create the new table'/>"
+    "  <Option name='CREATE_SCHEMA' type='boolean' description='Whether to explictely emit the CREATE SCHEMA statement to create the specified schema' default='YES'/>"
+    "  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index' default='YES'/>"
+    "  <Option name='TEMPORARY' type='boolean' description='Whether to a temporary table instead of a permanent one' default='NO'/>"
+    "  <Option name='UNLOGGED' type='boolean' description='Whether to create the table as a unlogged one' default='NO'/>"
+    "  <Option name='WRITE_EWKT_GEOM' type='boolean' description='Whether to write EWKT geometries instead of HEX geometrie' default='NO'/>"
+    "  <Option name='CREATE_TABLE' type='boolean' description='Whether to explictely recreate the table if necessary' default='YES'/>"
+    "  <Option name='DROP_TABLE' type='string-select' description='Whether to explictely destroy tables before recreating them' default='YES'>"
+    "    <Value>YES</Value>"
+    "    <Value>ON</Value>"
+    "    <Value>TRUE</Value>"
+    "    <Value>NO</Value>"
+    "    <Value>OFF</Value>"
+    "    <Value>FALSE</Value>"
+    "    <Value>IF_EXISTS</Value>"
+    "  </Option>"
+    "  <Option name='SRID' type='int' description='Forced SRID of the layer'/>"
+    "  <Option name='NONE_AS_UNKNOWN' type='boolean' description='Whether to force non-spatial layers to be created as spatial tables' default='NO'/>"
+    "  <Option name='FID' type='string' description='Name of the FID column to create' default='ogc_fid'/>"
+    "  <Option name='FID64' type='boolean' description='Whether to create the FID column with BIGSERIAL type to handle 64bit wide ids' default='NO'/>"
+    "  <Option name='EXTRACT_SCHEMA_FROM_LAYER_NAME' type='boolean' description='Whether a dot in a layer name should be considered as the separator for the schema and table name' default='YES'/>"
+    "  <Option name='COLUMN_TYPES' type='string' description='A list of strings of format field_name=pg_field_type (separated by comma) to force the PG column type of fields to be created'/>"
+    "  <Option name='POSTGIS_VERSION' type='string' description='Can be set to 2.0 for PostGIS 2.0 compatibility. Important to set it correctly if using non-linear geometry types'/>"
+    "</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time IntegerList Integer64List RealList StringList Binary" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnCreate = OGRPGDumpDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
-
diff --git a/ogr/ogrsf_frmts/pgdump/ogrpgdumplayer.cpp b/ogr/ogrsf_frmts/pgdump/ogrpgdumplayer.cpp
index 178ab74..2939322 100644
--- a/ogr/ogrsf_frmts/pgdump/ogrpgdumplayer.cpp
+++ b/ogr/ogrsf_frmts/pgdump/ogrpgdumplayer.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: ogrpgdumplayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrpgdumplayer.cpp 28988 2015-04-24 11:58:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGDumpLayer class
  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
  *
  ******************************************************************************
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -32,12 +32,22 @@
 #include "cpl_string.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrpgdumplayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrpgdumplayer.cpp 28988 2015-04-24 11:58:49Z rouault $");
 
 #define USE_COPY_UNSET -1
 
 static CPLString OGRPGDumpEscapeStringList(
-                                       char** papszItems, int bForInsertOrUpdate);
+                                       char** papszItems, int bForInsertOrUpdate,
+                                       OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                       void* userdata);
+
+static CPLString OGRPGDumpEscapeStringWithUserData(   void* user_data,
+                                   const char* pszStrValue, int nMaxLength,
+                                   const char* pszLayerName,
+                                   const char* pszFieldName)
+{
+    return OGRPGDumpEscapeString(pszStrValue, nMaxLength, pszFieldName);
+}
 
 /************************************************************************/
 /*                        OGRPGDumpLayer()                              */
@@ -52,9 +62,9 @@ OGRPGDumpLayer::OGRPGDumpLayer(OGRPGDumpDataSource* poDS,
 {
     this->poDS = poDS;
     poFeatureDefn = new OGRFeatureDefn( pszTableName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->SetGeomType(wkbNone);
     poFeatureDefn->Reference();
-    nFeatures = 0;
     pszSqlTableName = CPLStrdup(CPLString().Printf("%s.%s",
                                OGRPGDumpEscapeColumnName(pszSchemaName).c_str(),
                                OGRPGDumpEscapeColumnName(pszTableName).c_str() ));
@@ -71,6 +81,11 @@ OGRPGDumpLayer::OGRPGDumpLayer(OGRPGDumpDataSource* poDS,
     nUnknownSRSId = -1;
     nForcedSRSId = -2;
     bCreateSpatialIndexFlag = TRUE;
+    bPostGIS2 = FALSE;
+    iNextShapeId = 0;
+    iFIDAsRegularColumnIndex = -1;
+    bAutoFIDOnCreateViaCopy = TRUE;
+    bCopyStatementWithFID = FALSE;
 }
 
 /************************************************************************/
@@ -106,7 +121,8 @@ int OGRPGDumpLayer::TestCapability( const char * pszCap )
 {
     if( EQUAL(pszCap,OLCSequentialWrite) ||
         EQUAL(pszCap,OLCCreateField) ||
-        EQUAL(pszCap,OLCCreateGeomField) )
+        EQUAL(pszCap,OLCCreateGeomField) ||
+        EQUAL(pszCap,OLCCurveGeometries) )
         return TRUE;
     else
         return FALSE;
@@ -116,7 +132,7 @@ int OGRPGDumpLayer::TestCapability( const char * pszCap )
 /*                           GetNextFeature()                           */
 /************************************************************************/
 
-OGRErr OGRPGDumpLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRPGDumpLayer::ICreateFeature( OGRFeature *poFeature )
 {
     if( NULL == poFeature )
     {
@@ -125,29 +141,98 @@ OGRErr OGRPGDumpLayer::CreateFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
-    nFeatures ++;
+    /* In case the FID column has also been created as a regular field */
+    if( iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( poFeature->GetFID() == OGRNullFID )
+        {
+            if( poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) )
+            {
+                poFeature->SetFID(
+                    poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex));
+            }
+        }
+        else
+        {
+            if( !poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) ||
+                poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                            "Inconsistant values of FID and field of same name");
+                return CE_Failure;
+            }
+        }
+    }
+
+    if( !poFeature->Validate(OGR_F_VAL_ALL & ~OGR_F_VAL_WIDTH, TRUE ) )
+        return OGRERR_FAILURE;
 
     // We avoid testing the config option too often. 
     if( bUseCopy == USE_COPY_UNSET )
         bUseCopy = CSLTestBoolean( CPLGetConfigOption( "PG_USE_COPY", "NO") );
 
+    OGRErr eErr;
     if( !bUseCopy )
     {
-        return CreateFeatureViaInsert( poFeature );
+        eErr = CreateFeatureViaInsert( poFeature );
     }
     else
     {
-        if ( !bCopyActive )
+        /* If there's a unset field with a default value, then we must use */
+        /* a specific INSERT statement to avoid unset fields to be bound to NULL */
+        int bHasDefaultValue = FALSE;
+        int iField;
+        int nFieldCount = poFeatureDefn->GetFieldCount();
+        for( iField = 0; iField < nFieldCount; iField++ )
+        {
+            if( !poFeature->IsFieldSet( iField ) &&
+                poFeature->GetFieldDefnRef(iField)->GetDefault() != NULL )
+            {
+                bHasDefaultValue = TRUE;
+                break;
+            }
+        }
+        if( bHasDefaultValue )
         {
-            /* This is a heuristics. If the first feature to be copied has a */ 
-            /* FID set (and that a FID column has been identified), then we will */ 
-            /* try to copy FID values from features. Otherwise, we will not */ 
-            /* do and assume that the FID column is an autoincremented column. */ 
-            StartCopy(poFeature->GetFID() != OGRNullFID); 
+            EndCopy();
+            eErr = CreateFeatureViaInsert( poFeature );
+        }
+        else
+        {
+            int bFIDSet = (poFeature->GetFID() != OGRNullFID);
+            if( bCopyActive && bFIDSet != bCopyStatementWithFID )
+            {
+                EndCopy();
+                eErr = CreateFeatureViaInsert( poFeature );
+            }
+            else
+            {
+                if ( !bCopyActive )
+                {
+                    /* This is a heuristics. If the first feature to be copied has a */
+                    /* FID set (and that a FID column has been identified), then we will */
+                    /* try to copy FID values from features. Otherwise, we will not */
+                    /* do and assume that the FID column is an autoincremented column. */
+                    StartCopy(bFIDSet);
+                    bCopyStatementWithFID = bFIDSet;
+                }
+
+                eErr = CreateFeatureViaCopy( poFeature );
+                if( bFIDSet )
+                    bAutoFIDOnCreateViaCopy = FALSE;
+                if( eErr == CE_None && bAutoFIDOnCreateViaCopy )
+                {
+                    poFeature->SetFID( ++iNextShapeId );
+                }
+            }
         }
+    }
 
-        return CreateFeatureViaCopy( poFeature );
+    if( eErr == CE_None && iFIDAsRegularColumnIndex >= 0 )
+    {
+        poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
     }
+    return eErr;
 }
 
 /************************************************************************/
@@ -200,6 +285,8 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
 
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     {
+        if( i == iFIDAsRegularColumnIndex )
+            continue;
         if( !poFeature->IsFieldSet( i ) )
             continue;
 
@@ -237,7 +324,8 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
 
             if( bWriteAsHex )
             {
-                char* pszHex = OGRGeometryToHexEWKB( poGeom, poGFldDefn->nSRSId );
+                char* pszHex = OGRGeometryToHexEWKB( poGeom, poGFldDefn->nSRSId,
+                                                     bPostGIS2 );
                 osCommand += "'";
                 if (pszHex)
                     osCommand += pszHex;
@@ -268,13 +356,15 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
     {
         if( bNeedComma )
             osCommand += ", ";
-        osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
+        osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID() );
         bNeedComma = TRUE;
     }
 
 
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     {
+        if( i == iFIDAsRegularColumnIndex )
+            continue;
         if( !poFeature->IsFieldSet( i ) )
             continue;
 
@@ -283,7 +373,8 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
         else
             bNeedComma = TRUE;
 
-        AppendFieldValue(osCommand, poFeature, i);
+        OGRPGCommonAppendFieldValue(osCommand, poFeature, i,
+                                    OGRPGDumpEscapeStringWithUserData, NULL);
     }
 
     osCommand += ")";
@@ -296,6 +387,9 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
     poDS->Log(osCommand);
 
+    if( poFeature->GetFID() == OGRNullFID )
+        poFeature->SetFID( ++iNextShapeId );
+
     return OGRERR_NONE;
 }
 
@@ -327,7 +421,8 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
             /*if (bHasWkb)
                 pszGeom = GeometryToBYTEA( poGeometry );
             else*/
-                pszGeom = OGRGeometryToHexEWKB( poGeometry, poGFldDefn->nSRSId );
+                pszGeom = OGRGeometryToHexEWKB( poGeometry, poGFldDefn->nSRSId,
+                                                bPostGIS2 );
         }
     
         if (osCommand.size() > 0)
@@ -342,7 +437,43 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
             osCommand += "\\N";
         }
     }
+    
+    OGRPGCommonAppendCopyFieldsExceptGeom(osCommand,
+                                          poFeature,
+                                          pszFIDColumn,
+                                          bFIDColumnInCopyFields,
+                                          OGRPGDumpEscapeStringWithUserData,
+                                          NULL);
+
+    /* Add end of line marker */
+    //osCommand += "\n";
+
+
+    /* ------------------------------------------------------------ */
+    /*      Execute the copy.                                       */
+    /* ------------------------------------------------------------ */
+
+    OGRErr result = OGRERR_NONE;
+
+    poDS->Log(osCommand, FALSE);
+
+    return result;
+}
+
+/************************************************************************/
+/*                OGRPGCommonAppendCopyFieldsExceptGeom()               */
+/************************************************************************/
 
+void OGRPGCommonAppendCopyFieldsExceptGeom(CPLString& osCommand,
+                                           OGRFeature* poFeature,
+                                           const char* pszFIDColumn,
+                                           int bFIDColumnInCopyFields,
+                                           OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                           void* userdata)
+{
+    int i;
+    OGRFeatureDefn* poFeatureDefn = poFeature->GetDefnRef();
+    
     /* Next process the field id column */
     int nFIDIndex = -1;
     if( bFIDColumnInCopyFields )
@@ -355,7 +486,7 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
         /* Set the FID */
         if( poFeature->GetFID() != OGRNullFID )
         {
-            osCommand += CPLString().Printf("%ld ", poFeature->GetFID());
+            osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID());
         }
         else
         {
@@ -409,6 +540,25 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
             strcat( pszNeedToFree+nOff, "}" );
             pszStrValue = pszNeedToFree;
         }
+        
+        else if( nOGRFieldType == OFTInteger64List )
+        {
+            int nCount, nOff = 0, j;
+            const GIntBig *panItems = poFeature->GetFieldAsInteger64List(i,&nCount);
+
+            pszNeedToFree = (char *) CPLMalloc(nCount * 26 + 10);
+            strcpy( pszNeedToFree, "{" );
+            for( j = 0; j < nCount; j++ )
+            {
+                if( j != 0 )
+                    strcat( pszNeedToFree+nOff, "," );
+
+                nOff += strlen(pszNeedToFree+nOff);
+                sprintf( pszNeedToFree+nOff, CPL_FRMT_GIB, panItems[j] );
+            }
+            strcat( pszNeedToFree+nOff, "}" );
+            pszStrValue = pszNeedToFree;
+        }
 
         // We need special formatting for real list values.
         else if( nOGRFieldType == OFTRealList )
@@ -430,7 +580,7 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
                 else if( CPLIsInf(padfItems[j]) )
                     sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
                 else
-                    sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
+                    CPLsprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
 
             }
             strcat( pszNeedToFree+nOff, "}" );
@@ -444,7 +594,9 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
             CPLString osStr;
             char **papszItems = poFeature->GetFieldAsStringList(i);
 
-            pszStrValue = pszNeedToFree = CPLStrdup(OGRPGDumpEscapeStringList(papszItems, FALSE));
+            pszStrValue = pszNeedToFree = CPLStrdup(
+                OGRPGDumpEscapeStringList(papszItems, FALSE,
+                                          pfnEscapeString, userdata));
         }
 
         // Binary formatting
@@ -452,16 +604,13 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
         {
             int nLen = 0;
             GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
-            char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
+            char* pszBytea = OGRPGDumpLayer::GByteArrayToBYTEA( pabyData, nLen);
 
             pszStrValue = pszNeedToFree = pszBytea;
         }
 
         else if( nOGRFieldType == OFTReal )
         {
-            char* pszComma = strchr((char*)pszStrValue, ',');
-            if (pszComma)
-                *pszComma = '.';
             //Check for special values. They need to be quoted.
             double dfVal = poFeature->GetFieldAsDouble(i);
             if( CPLIsNan(dfVal) )
@@ -471,22 +620,30 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
         }
 
         if( nOGRFieldType != OFTIntegerList &&
+            nOGRFieldType != OFTInteger64List &&
             nOGRFieldType != OFTRealList &&
             nOGRFieldType != OFTInteger &&
+            nOGRFieldType != OFTInteger64 &&
             nOGRFieldType != OFTReal &&
             nOGRFieldType != OFTBinary )
         {
             int         iChar;
+            int         iUTFChar = 0;
+            int         nMaxWidth = poFeatureDefn->GetFieldDefn(i)->GetWidth();
 
             for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
             {
-                if( poFeatureDefn->GetFieldDefn(i)->GetWidth() > 0
-                    && iChar == poFeatureDefn->GetFieldDefn(i)->GetWidth() )
+                //count of utf chars
+                if ((pszStrValue[iChar] & 0xc0) != 0x80) 
                 {
-                    CPLDebug( "PG",
-                              "Truncated %s field value, it was too long.",
-                              poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
-                    break;
+                    if( nMaxWidth > 0 && iUTFChar == nMaxWidth )
+                    {
+                        CPLDebug( "PG",
+                                "Truncated %s field value, it was too long.",
+                                poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
+                        break;
+                    }
+                    iUTFChar++;
                 }
 
                 /* Escape embedded \, \t, \n, \r since they will cause COPY
@@ -510,20 +667,6 @@ OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
         if( pszNeedToFree )
             CPLFree( pszNeedToFree );
     }
-
-    /* Add end of line marker */
-    //osCommand += "\n";
-
-
-    /* ------------------------------------------------------------ */
-    /*      Execute the copy.                                       */
-    /* ------------------------------------------------------------ */
-
-    OGRErr result = OGRERR_NONE;
-
-    poDS->Log(osCommand, FALSE);
-
-    return result;
 }
 
 /************************************************************************/
@@ -647,7 +790,7 @@ CPLString OGRPGDumpEscapeColumnName(const char* pszColumnName)
 /*                             EscapeString( )                          */
 /************************************************************************/
 
-CPLString OGRPGDumpEscapeString(
+CPLString OGRPGDumpEscapeString(   
                                    const char* pszStrValue, int nMaxLength,
                                    const char* pszFieldName)
 {
@@ -657,17 +800,26 @@ CPLString OGRPGDumpEscapeString(
     osCommand += "'";
 
     int nSrcLen = strlen(pszStrValue);
-    if (nMaxLength > 0 && nSrcLen > nMaxLength)
+    int nSrcLenUTF = CPLStrlenUTF8(pszStrValue);
+
+    if (nMaxLength > 0 && nSrcLenUTF > nMaxLength)
     {
         CPLDebug( "PG",
                   "Truncated %s field value, it was too long.",
                   pszFieldName );
-        nSrcLen = nMaxLength;
-        
-        while( nSrcLen > 0 && ((unsigned char *) pszStrValue)[nSrcLen-1] > 127 )
+
+        int iUTF8Char = 0;
+        for(int iChar = 0; iChar < nSrcLen; iChar++ )
         {
-            CPLDebug( "PG", "Backup to start of multi-byte character." );
-            nSrcLen--;
+            if( (((unsigned char *) pszStrValue)[iChar] & 0xc0) != 0x80 )
+            {
+                if( iUTF8Char == nMaxLength )
+                {
+                    nSrcLen = iChar;
+                    break;
+                }
+                iUTF8Char ++;
+            }
         }
     }
 
@@ -704,7 +856,7 @@ CPLString OGRPGDumpEscapeString(
         }
         /* FIXME: at some point (when we drop PostgreSQL < 9.1 support, remove
            the escaping of backslash and remove 'SET standard_conforming_strings = OFF'
-           in CreateLayer() */
+           inICreateLayer() */
         else if (pszStrValue[i] == '\\')
         {
             pszDestStr[j++] = '\\';
@@ -730,7 +882,9 @@ CPLString OGRPGDumpEscapeString(
 /************************************************************************/
 
 static CPLString OGRPGDumpEscapeStringList(
-                                       char** papszItems, int bForInsertOrUpdate)
+                                       char** papszItems, int bForInsertOrUpdate,
+                                       OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                       void* userdata)
 {
     int bFirstItem = TRUE;
     CPLString osStr;
@@ -749,7 +903,7 @@ static CPLString OGRPGDumpEscapeStringList(
         if (*pszStr != '\0')
         {
             if (bForInsertOrUpdate)
-                osStr += OGRPGDumpEscapeString(pszStr);
+                osStr += pfnEscapeString(userdata, pszStr, 0, "", "");
             else
             {
                 osStr += '"';
@@ -790,10 +944,14 @@ static CPLString OGRPGDumpEscapeStringList(
 /* non-empty field value                                                */
 /************************************************************************/
 
-void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
-                                       OGRFeature* poFeature, int i)
+void OGRPGCommonAppendFieldValue(CPLString& osCommand,
+                                 OGRFeature* poFeature, int i,
+                                 OGRPGCommonEscapeStringCbk pfnEscapeString,
+                                 void* userdata)
 {
-    int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
+    OGRFeatureDefn* poFeatureDefn = poFeature->GetDefnRef();
+    OGRFieldType nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
+    OGRFieldSubType eSubType = poFeatureDefn->GetFieldDefn(i)->GetSubType();
 
     // We need special formatting for integer list values.
     if(  nOGRFieldType == OFTIntegerList )
@@ -819,6 +977,30 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
 
         return;
     }
+    
+    else if(  nOGRFieldType == OFTInteger64List )
+    {
+        int nCount, nOff = 0, j;
+        const GIntBig *panItems = poFeature->GetFieldAsInteger64List(i,&nCount);
+        char *pszNeedToFree = NULL;
+
+        pszNeedToFree = (char *) CPLMalloc(nCount * 26 + 10);
+        strcpy( pszNeedToFree, "'{" );
+        for( j = 0; j < nCount; j++ )
+        {
+            if( j != 0 )
+                strcat( pszNeedToFree+nOff, "," );
+
+            nOff += strlen(pszNeedToFree+nOff);
+            sprintf( pszNeedToFree+nOff, CPL_FRMT_GIB, panItems[j] );
+        }
+        strcat( pszNeedToFree+nOff, "}'" );
+
+        osCommand += pszNeedToFree;
+        CPLFree(pszNeedToFree);
+
+        return;
+    }
 
     // We need special formatting for real list values.
     else if( nOGRFieldType == OFTRealList )
@@ -841,7 +1023,7 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
             else if( CPLIsInf(padfItems[j]) )
                 sprintf( pszNeedToFree+nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
             else
-                sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
+                CPLsprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
 
         }
         strcat( pszNeedToFree+nOff, "}'" );
@@ -857,7 +1039,8 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
     {
         char **papszItems = poFeature->GetFieldAsStringList(i);
 
-        osCommand += OGRPGDumpEscapeStringList(papszItems, TRUE);
+        osCommand += OGRPGDumpEscapeStringList(papszItems, TRUE,
+                                               pfnEscapeString, userdata);
 
         return;
     }
@@ -869,7 +1052,7 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
 
         int nLen = 0;
         GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
-        char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
+        char* pszBytea = OGRPGDumpLayer::GByteArrayToBYTEA( pabyData, nLen);
 
         osCommand += pszBytea;
 
@@ -896,9 +1079,6 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
     }
     else if ( nOGRFieldType == OFTReal )
     {
-        char* pszComma = strchr((char*)pszStrValue, ',');
-        if (pszComma)
-            *pszComma = '.';
         //Check for special values. They need to be quoted.
         double dfVal = poFeature->GetFieldAsDouble(i);
         if( CPLIsNan(dfVal) )
@@ -906,13 +1086,18 @@ void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
         else if( CPLIsInf(dfVal) )
             pszStrValue = (dfVal > 0) ? "'Infinity'" : "'-Infinity'";
     }
+    else if ( (nOGRFieldType == OFTInteger ||
+               nOGRFieldType == OFTInteger64) && eSubType == OFSTBoolean )
+        pszStrValue = poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
 
-    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
+    if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTInteger64 && 
+        nOGRFieldType != OFTReal
         && !bIsDateNull )
     {
-        osCommand += OGRPGDumpEscapeString( pszStrValue,
-                                        poFeatureDefn->GetFieldDefn(i)->GetWidth(),
-                                        poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
+        osCommand += pfnEscapeString( userdata, pszStrValue,
+                                      poFeatureDefn->GetFieldDefn(i)->GetWidth(),
+                                      poFeatureDefn->GetName(),
+                                      poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
     }
     else
     {
@@ -950,12 +1135,12 @@ char* OGRPGDumpLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
 }
 
 /************************************************************************/
-/*                        OGRPGTableLayerGetType()                      */
+/*                       OGRPGCommonLayerGetType()                      */
 /************************************************************************/
 
-static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
-                                        int bPreservePrecision,
-                                        int bApproxOK)
+CPLString OGRPGCommonLayerGetType(OGRFieldDefn& oField,
+                                  int bPreservePrecision,
+                                  int bApproxOK)
 {
     char                szFieldType[256];
 
@@ -964,14 +1149,27 @@ static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
 /* -------------------------------------------------------------------- */
     if( oField.GetType() == OFTInteger )
     {
-        if( oField.GetWidth() > 0 && bPreservePrecision )
+        if( oField.GetSubType() == OFSTBoolean )
+            strcpy( szFieldType, "BOOLEAN" );
+        else if( oField.GetSubType() == OFSTInt16 )
+            strcpy( szFieldType, "SMALLINT" );
+        else if( oField.GetWidth() > 0 && bPreservePrecision )
             sprintf( szFieldType, "NUMERIC(%d,0)", oField.GetWidth() );
         else
             strcpy( szFieldType, "INTEGER" );
     }
+    else if( oField.GetType() == OFTInteger64 )
+    {
+        if( oField.GetWidth() > 0 && bPreservePrecision )
+            sprintf( szFieldType, "NUMERIC(%d,0)", oField.GetWidth() );
+        else
+            strcpy( szFieldType, "INT8" );
+    }
     else if( oField.GetType() == OFTReal )
     {
-        if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
+        if( oField.GetSubType() == OFSTFloat32 )
+            strcpy( szFieldType, "REAL" );
+        else if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
             && bPreservePrecision )
             sprintf( szFieldType, "NUMERIC(%d,%d)",
                      oField.GetWidth(), oField.GetPrecision() );
@@ -987,7 +1185,14 @@ static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
     }
     else if( oField.GetType() == OFTIntegerList )
     {
-        strcpy( szFieldType, "INTEGER[]" );
+        if( oField.GetSubType() == OFSTBoolean )
+            strcpy( szFieldType, "BOOLEAN[]" );
+        else
+            strcpy( szFieldType, "INTEGER[]" );
+    }
+    else if( oField.GetType() == OFTInteger64List )
+    {
+        strcpy( szFieldType, "INT8[]" );
     }
     else if( oField.GetType() == OFTRealList )
     {
@@ -1034,6 +1239,214 @@ static CPLString OGRPGTableLayerGetType(OGRFieldDefn& oField,
 }
 
 /************************************************************************/
+/*                         OGRPGCommonLayerSetType()                    */
+/************************************************************************/
+
+int OGRPGCommonLayerSetType(OGRFieldDefn& oField,
+                            const char* pszType,
+                            const char* pszFormatType,
+                            int nWidth)
+{
+    if( EQUAL(pszType,"text") )
+    {
+        oField.SetType( OFTString );
+    }
+    else if( EQUAL(pszType,"_bpchar") ||
+            EQUAL(pszType,"_varchar") ||
+            EQUAL(pszType,"_text"))
+    {
+        oField.SetType( OFTStringList );
+    }
+    else if( EQUAL(pszType,"bpchar") || EQUAL(pszType,"varchar") )
+    {
+        if( nWidth == -1 )
+        {
+            if( EQUALN(pszFormatType,"character(",10) )
+                nWidth = atoi(pszFormatType+10);
+            else if( EQUALN(pszFormatType,"character varying(",18) )
+                nWidth = atoi(pszFormatType+18);
+            else
+                nWidth = 0;
+        }
+        oField.SetType( OFTString );
+        oField.SetWidth( nWidth );
+    }
+    else if( EQUAL(pszType,"bool") )
+    {
+        oField.SetType( OFTInteger );
+        oField.SetSubType( OFSTBoolean );
+        oField.SetWidth( 1 );
+    }
+    else if( EQUAL(pszType,"numeric") )
+    {
+        if( EQUAL(pszFormatType, "numeric") )
+            oField.SetType( OFTReal );
+        else
+        {
+            const char *pszPrecision = strstr(pszFormatType,",");
+            int    nWidth, nPrecision = 0;
+
+            nWidth = atoi(pszFormatType + 8);
+            if( pszPrecision != NULL )
+                nPrecision = atoi(pszPrecision+1);
+
+            if( nPrecision == 0 )
+            {
+                if( nWidth >= 10 )
+                    oField.SetType( OFTInteger64 );
+                else
+                    oField.SetType( OFTInteger );
+            }
+            else
+                oField.SetType( OFTReal );
+
+            oField.SetWidth( nWidth );
+            oField.SetPrecision( nPrecision );
+        }
+    }
+    else if( EQUAL(pszFormatType,"integer[]") )
+    {
+        oField.SetType( OFTIntegerList );
+    }
+    else if( EQUAL(pszFormatType,"boolean[]") )
+    {
+        oField.SetType( OFTIntegerList );
+        oField.SetSubType( OFSTBoolean );
+    }
+    else if( EQUAL(pszFormatType, "float[]") ||
+            EQUAL(pszFormatType, "real[]") )
+    {
+        oField.SetType( OFTRealList );
+        oField.SetSubType( OFSTFloat32 );
+    }
+    else if( EQUAL(pszFormatType, "double precision[]") )
+    {
+        oField.SetType( OFTRealList );
+    }
+    else if( EQUAL(pszType,"int2") )
+    {
+        oField.SetType( OFTInteger );
+        oField.SetSubType( OFSTInt16 );
+        oField.SetWidth( 5 );
+    }
+    else if( EQUAL(pszType,"int8") )
+    {
+        oField.SetType( OFTInteger64 );
+    }
+    else if( EQUAL(pszFormatType,"bigint[]") )
+    {
+        oField.SetType( OFTInteger64List );
+    }
+    else if( EQUALN(pszType,"int",3) )
+    {
+        oField.SetType( OFTInteger );
+    }
+    else if( EQUAL(pszType,"float4")  )
+    {
+        oField.SetType( OFTReal );
+        oField.SetSubType( OFSTFloat32 );
+    }
+    else if( EQUALN(pszType,"float",5) ||
+            EQUALN(pszType,"double",6) ||
+            EQUAL(pszType,"real") )
+    {
+        oField.SetType( OFTReal );
+    }
+    else if( EQUALN(pszType, "timestamp",9) )
+    {
+        oField.SetType( OFTDateTime );
+    }
+    else if( EQUALN(pszType, "date",4) )
+    {
+        oField.SetType( OFTDate );
+    }
+    else if( EQUALN(pszType, "time",4) )
+    {
+        oField.SetType( OFTTime );
+    }
+    else if( EQUAL(pszType,"bytea") )
+    {
+        oField.SetType( OFTBinary );
+    }
+    else
+    {
+        CPLDebug( "PGCommon", "Field %s is of unknown format type %s (type=%s).", 
+                oField.GetNameRef(), pszFormatType, pszType );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                  OGRPGCommonLayerNormalizeDefault()                  */
+/************************************************************************/
+
+void OGRPGCommonLayerNormalizeDefault(OGRFieldDefn* poFieldDefn,
+                                      const char* pszDefault)
+{
+    if(pszDefault==NULL)
+        return;
+    CPLString osDefault(pszDefault);
+    size_t nPos = osDefault.find("::character varying");
+    if( nPos != std::string::npos )
+        osDefault.resize(nPos);
+    else if( strcmp(osDefault, "now()") == 0 )
+        osDefault = "CURRENT_TIMESTAMP";
+    else if( strcmp(osDefault, "('now'::text)::date") == 0 )
+        osDefault = "CURRENT_DATE";
+    else if( strcmp(osDefault, "('now'::text)::time with time zone") == 0 )
+        osDefault = "CURRENT_TIME";
+    else
+    {
+        nPos = osDefault.find("::timestamp with time zone");
+        if( poFieldDefn->GetType() == OFTDateTime && nPos != std::string::npos )
+        {
+            osDefault.resize(nPos);
+            nPos = osDefault.find("'+");
+            if( nPos != std::string::npos )
+            {
+                osDefault.resize(nPos);
+                osDefault += "'";
+            }
+            int nYear, nMonth, nDay, nHour, nMinute;
+            float fSecond;
+            if( sscanf(osDefault, "'%d-%d-%d %d:%d:%f'", &nYear, &nMonth, &nDay,
+                                &nHour, &nMinute, &fSecond) == 6 ||
+                sscanf(osDefault, "'%d-%d-%d %d:%d:%f+00'", &nYear, &nMonth, &nDay,
+                                &nHour, &nMinute, &fSecond) == 6)
+            {
+                if( osDefault.find('.') == std::string::npos )
+                    osDefault = CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
+                                            nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond+0.5));
+                else
+                    osDefault = CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%06.3f'",
+                                                    nYear, nMonth, nDay, nHour, nMinute, fSecond);
+            }
+        }
+    }
+    poFieldDefn->SetDefault(osDefault);
+}
+
+/************************************************************************/
+/*                     OGRPGCommonLayerGetPGDefault()                   */
+/************************************************************************/
+
+CPLString OGRPGCommonLayerGetPGDefault(OGRFieldDefn* poFieldDefn)
+{
+    CPLString osRet = poFieldDefn->GetDefault();
+    int nYear, nMonth, nDay, nHour, nMinute;
+    float fSecond;
+    if( sscanf(osRet, "'%d/%d/%d %d:%d:%f'",
+                &nYear, &nMonth, &nDay,
+                &nHour, &nMinute, &fSecond) == 6 )
+    {
+        osRet.resize(osRet.size()-1);
+        osRet += "+00'::timestamp with time zone";
+    }
+    return osRet;
+}
+
+/************************************************************************/
 /*                           GetNextFeature()                           */
 /************************************************************************/
 
@@ -1043,6 +1456,20 @@ OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
     CPLString           osCommand;
     CPLString           osFieldType;
     OGRFieldDefn        oField( poFieldIn );
+    
+    // Can be set to NO to test ogr2ogr default behaviour
+    int bAllowCreationOfFieldWithFIDName =
+        CSLTestBoolean(CPLGetConfigOption("PGDUMP_DEBUG_ALLOW_CREATION_FIELD_WITH_FID_NAME", "YES"));
+
+    if( bAllowCreationOfFieldWithFIDName && pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) &&
+        oField.GetType() != OFTInteger &&
+        oField.GetType() != OFTInteger64 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
+                 oField.GetNameRef());
+        return CE_Failure;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Do we want to "launder" the column names into Postgres          */
@@ -1050,7 +1477,7 @@ OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
 /* -------------------------------------------------------------------- */
     if( bLaunderColumnNames )
     {
-        char    *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
+        char    *pszSafeName = OGRPGCommonLaunderName( oField.GetNameRef(), "PGDump" );
 
         oField.SetName( pszSafeName );
         CPLFree( pszSafeName );
@@ -1068,7 +1495,7 @@ OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
         osFieldType = pszOverrideType;
     else
     {
-        osFieldType = OGRPGTableLayerGetType(oField, bPreservePrecision, bApproxOK);
+        osFieldType = OGRPGCommonLayerGetType(oField, bPreservePrecision, bApproxOK);
         if (osFieldType.size() == 0)
             return OGRERR_FAILURE;
     }
@@ -1079,11 +1506,27 @@ OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
     osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
                       pszSqlTableName, OGRPGDumpEscapeColumnName(oField.GetNameRef()).c_str(),
                       osFieldType.c_str() );
-    if (bCreateTable)
-        poDS->Log(osCommand);
+    if( !oField.IsNullable() )
+        osCommand += " NOT NULL";
+    if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+    {
+        osCommand += " DEFAULT ";
+        osCommand += OGRPGCommonLayerGetPGDefault(&oField);
+    }
 
     poFeatureDefn->AddFieldDefn( &oField );
-    
+
+    if( bAllowCreationOfFieldWithFIDName && pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) )
+    {
+        iFIDAsRegularColumnIndex = poFeatureDefn->GetFieldCount() - 1;
+    }
+    else
+    {
+        if( bCreateTable )
+            poDS->Log(osCommand);
+    }
+
     return OGRERR_NONE;
 }
 
@@ -1101,7 +1544,7 @@ OGRErr OGRPGDumpLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
                  "Cannot create geometry field of type wkbNone");
         return OGRERR_FAILURE;
     }
-    
+
     CPLString               osCommand;
     OGRPGDumpGeomFieldDefn *poGeomField =
         new OGRPGDumpGeomFieldDefn( poGeomFieldIn );
@@ -1112,7 +1555,7 @@ OGRErr OGRPGDumpLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
 /* -------------------------------------------------------------------- */
     if( bLaunderColumnNames )
     {
-        char    *pszSafeName = poDS->LaunderName( poGeomField->GetNameRef() );
+        char    *pszSafeName = OGRPGCommonLaunderName( poGeomField->GetNameRef(), "PGDump" );
 
         poGeomField->SetName( pszSafeName );
         CPLFree( pszSafeName );
@@ -1159,6 +1602,15 @@ OGRErr OGRPGDumpLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
         
         poDS->Log(osCommand);
 
+        if( !poGeomField->IsNullable() )
+        {
+            osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s SET NOT NULL",
+                              OGRPGDumpEscapeColumnName(poFeatureDefn->GetName()).c_str(),
+                              OGRPGDumpEscapeColumnName(poGeomField->GetNameRef()).c_str() );
+
+            poDS->Log(osCommand);
+        }
+
         if( bCreateSpatialIndexFlag )
         {
             osCommand.Printf("CREATE INDEX %s ON %s USING GIST (%s)",
diff --git a/ogr/ogrsf_frmts/pgeo/GNUmakefile b/ogr/ogrsf_frmts/pgeo/GNUmakefile
index 89bcb27..13864a3 100644
--- a/ogr/ogrsf_frmts/pgeo/GNUmakefile
+++ b/ogr/ogrsf_frmts/pgeo/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrpgeodatasource.o ogrpgeolayer.o ogrpgeodriver.o \
 		ogrpgeotablelayer.o ogrpgeoselectlayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) -I.. -I../.. $(CPPFLAGS)
+CPPFLAGS	:=	 -I.. -I../.. $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/pgeo/ogr_pgeo.h b/ogr/ogrsf_frmts/pgeo/ogr_pgeo.h
index 9d16339..f60c6ba 100644
--- a/ogr/ogrsf_frmts/pgeo/ogr_pgeo.h
+++ b/ogr/ogrsf_frmts/pgeo/ogr_pgeo.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_pgeo.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_pgeo.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for Personal Geodatabase driver.
@@ -52,7 +52,7 @@ class OGRPGeoLayer : public OGRLayer
     OGRSpatialReference *poSRS;
     int                 nSRSId;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRPGeoDataSource    *poDS;
 
@@ -76,7 +76,7 @@ class OGRPGeoLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
@@ -118,10 +118,10 @@ class OGRPGeoTableLayer : public OGRPGeoLayer
                                     int bHasZ );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual int         TestCapability( const char * );
 
@@ -147,9 +147,9 @@ class OGRPGeoSelectLayer : public OGRPGeoLayer
                         ~OGRPGeoSelectLayer();
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual int         TestCapability( const char * );
 };
diff --git a/ogr/ogrsf_frmts/pgeo/ogrpgeodatasource.cpp b/ogr/ogrsf_frmts/pgeo/ogrpgeodatasource.cpp
index 35b9aba..5d38f07 100644
--- a/ogr/ogrsf_frmts/pgeo/ogrpgeodatasource.cpp
+++ b/ogr/ogrsf_frmts/pgeo/ogrpgeodatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeodatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgeodatasource.cpp 28368 2015-01-27 14:25:17Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGeoDataSource class.
@@ -33,7 +33,7 @@
 #include "cpl_string.h"
 #include <vector>
 
-CPL_CVSID("$Id: ogrpgeodatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgeodatasource.cpp 28368 2015-01-27 14:25:17Z rouault $");
 
 /************************************************************************/
 /*                         OGRPGeoDataSource()                          */
@@ -110,12 +110,19 @@ int OGRPGeoDataSource::Open( const char * pszNewName, int bUpdate,
 /*                                                                      */
 /* -------------------------------------------------------------------- */
     char *pszDSN;
+    const char* pszOptionName = "";
+    const char* pszDSNStringTemplate = NULL;
     if( EQUALN(pszNewName,"PGEO:",5) )
         pszDSN = CPLStrdup( pszNewName + 5 );
     else
     {
-        const char *pszDSNStringTemplate = NULL;
-        pszDSNStringTemplate = CPLGetConfigOption( "PGEO_DRIVER_TEMPLATE", "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s");
+        pszOptionName = "PGEO_DRIVER_TEMPLATE";
+        pszDSNStringTemplate = CPLGetConfigOption( pszOptionName, NULL );
+        if( pszDSNStringTemplate == NULL )
+        {
+            pszOptionName = "";
+            pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s";
+        }
         if (!CheckDSNStringTemplate(pszDSNStringTemplate))
         {
             CPLError( CE_Failure, CPLE_AppDefined,
@@ -133,11 +140,28 @@ int OGRPGeoDataSource::Open( const char * pszNewName, int bUpdate,
 
     if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Unable to initialize ODBC connection to DSN for %s,\n"
-                  "%s", pszDSN, oSession.GetLastError() );
-        CPLFree( pszDSN );
-        return FALSE;
+        int bError = TRUE;
+        if( !EQUALN(pszNewName,"PGEO:",5) )
+        {
+            // Trying with another template (#5594)
+            pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb, *.accdb);DBQ=%s";
+            CPLFree( pszDSN );
+            pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
+            sprintf( pszDSN, pszDSNStringTemplate,  pszNewName );
+            CPLDebug( "PGeo", "EstablishSession(%s)", pszDSN );
+            if( oSession.EstablishSession( pszDSN, NULL, NULL ) )
+            {
+                bError = FALSE;
+            }
+        }
+        if( bError )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                    "Unable to initialize ODBC connection to DSN for %s,\n"
+                    "%s", pszDSN, oSession.GetLastError() );
+            CPLFree( pszDSN );
+            return FALSE;
+        }
     }
 
     CPLFree( pszDSN );
@@ -192,10 +216,10 @@ int OGRPGeoDataSource::Open( const char * pszNewName, int bUpdate,
         if( poLayer->Initialize( papszRecord[0],         // TableName
                                  papszRecord[1],         // FieldName
                                  atoi(papszRecord[2]),   // ShapeType
-                                 atof(papszRecord[3]),   // ExtentLeft
-                                 atof(papszRecord[4]),   // ExtentRight
-                                 atof(papszRecord[5]),   // ExtentBottom
-                                 atof(papszRecord[6]),   // ExtentTop
+                                 CPLAtof(papszRecord[3]),   // ExtentLeft
+                                 CPLAtof(papszRecord[4]),   // ExtentRight
+                                 CPLAtof(papszRecord[5]),   // ExtentBottom
+                                 CPLAtof(papszRecord[6]),   // ExtentTop
                                  atoi(papszRecord[7]),   // SRID
                                  atoi(papszRecord[8]))  // HasZ
             != CE_None )
diff --git a/ogr/ogrsf_frmts/pgeo/ogrpgeodriver.cpp b/ogr/ogrsf_frmts/pgeo/ogrpgeodriver.cpp
index afd7de9..24ee679 100644
--- a/ogr/ogrsf_frmts/pgeo/ogrpgeodriver.cpp
+++ b/ogr/ogrsf_frmts/pgeo/ogrpgeodriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeodriver.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgeodriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements Personal Geodatabase driver.
@@ -31,7 +31,7 @@
 #include "ogr_pgeo.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrpgeodriver.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgeodriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                            ~OGRODBCDriver()                            */
@@ -294,5 +294,11 @@ bool OGRODBCMDBDriver::LibraryExists(const char* pszLibPath)
 void RegisterOGRPGeo()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRPGeoDriver );
+    OGRSFDriver* poDriver = new OGRPGeoDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "ESRI Personal GeoDatabase" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "mdb" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_pgeo.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
diff --git a/ogr/ogrsf_frmts/pgeo/ogrpgeolayer.cpp b/ogr/ogrsf_frmts/pgeo/ogrpgeolayer.cpp
index 804d1f7..6baedf8 100644
--- a/ogr/ogrsf_frmts/pgeo/ogrpgeolayer.cpp
+++ b/ogr/ogrsf_frmts/pgeo/ogrpgeolayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeolayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgeolayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGeoLayer class, code shared between 
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "ogrpgeogeometry.h"
 
-CPL_CVSID("$Id: ogrpgeolayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgeolayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRPGeoLayer()                            */
@@ -105,6 +105,7 @@ CPLErr OGRPGeoLayer::BuildFeatureDefn( const char *pszLayerName,
 
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     int    nRawColumns = poStmt->GetColCount();
 
     poFeatureDefn->Reference();
@@ -312,7 +313,7 @@ OGRFeature *OGRPGeoLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRPGeoLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRPGeoLayer::GetFeature( GIntBig nFeatureId )
 
 {
     /* This should be implemented directly! */
diff --git a/ogr/ogrsf_frmts/pgeo/ogrpgeoselectlayer.cpp b/ogr/ogrsf_frmts/pgeo/ogrpgeoselectlayer.cpp
index 08cda7e..b104b18 100644
--- a/ogr/ogrsf_frmts/pgeo/ogrpgeoselectlayer.cpp
+++ b/ogr/ogrsf_frmts/pgeo/ogrpgeoselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeoselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrpgeoselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGeoSelectLayer class, layer access to the results
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "ogr_pgeo.h"
 
-CPL_CVSID("$Id: ogrpgeoselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrpgeoselectlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRPGeoSelectLayer()                        */
@@ -149,7 +149,7 @@ void OGRPGeoSelectLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRPGeoSelectLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRPGeoSelectLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRPGeoLayer::GetFeature( nFeatureId );
@@ -174,7 +174,7 @@ int OGRPGeoSelectLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRPGeoSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRPGeoSelectLayer::GetFeatureCount( int bForce )
 
 {
     return OGRPGeoLayer::GetFeatureCount( bForce );
diff --git a/ogr/ogrsf_frmts/pgeo/ogrpgeotablelayer.cpp b/ogr/ogrsf_frmts/pgeo/ogrpgeotablelayer.cpp
index 2ad23d4..200a2cd 100644
--- a/ogr/ogrsf_frmts/pgeo/ogrpgeotablelayer.cpp
+++ b/ogr/ogrsf_frmts/pgeo/ogrpgeotablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrpgeotablelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrpgeotablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRPGeoTableLayer class, access to an existing table.
@@ -32,7 +32,7 @@
 #include "ogr_pgeo.h"
 #include "ogrpgeogeometry.h"
 
-CPL_CVSID("$Id: ogrpgeotablelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrpgeotablelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                          OGRPGeoTableLayer()                         */
@@ -78,6 +78,8 @@ CPLErr OGRPGeoTableLayer::Initialize( const char *pszTableName,
 
 {
     CPLODBCSession *poSession = poDS->GetSession();
+    
+    SetDescription( pszTableName );
 
     CPLFree( pszGeomColumn );
     if( pszGeomCol == NULL )
@@ -130,7 +132,7 @@ CPLErr OGRPGeoTableLayer::Initialize( const char *pszTableName,
     }
 
     if( eOGRType != wkbUnknown && eOGRType != wkbNone && bHasZ )
-        eOGRType = (OGRwkbGeometryType)(((int) eOGRType) | wkb25DBit);
+        eOGRType = wkbSetZ(eOGRType);
 
 /* -------------------------------------------------------------------- */
 /*      Do we have a simple primary key?                                */
@@ -268,7 +270,7 @@ void OGRPGeoTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRPGeoTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRPGeoTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -281,7 +283,7 @@ OGRFeature *OGRPGeoTableLayer::GetFeature( long nFeatureId )
     poStmt = new CPLODBCStatement( poDS->GetSession() );
     poStmt->Append( "SELECT * FROM " );
     poStmt->Append( poFeatureDefn->GetName() );
-    poStmt->Appendf( " WHERE %s = %ld", pszFIDColumn, nFeatureId );
+    poStmt->Appendf( " WHERE %s = " CPL_FRMT_GIB, pszFIDColumn, nFeatureId );
 
     if( !poStmt->ExecuteSQL() )
     {
@@ -346,7 +348,7 @@ int OGRPGeoTableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRPGeoTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRPGeoTableLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL )
@@ -367,7 +369,7 @@ int OGRPGeoTableLayer::GetFeatureCount( int bForce )
         return OGRPGeoLayer::GetFeatureCount(bForce);
     }
 
-    return atoi(oStmt.GetColData(0));
+    return CPLAtoGIntBig(oStmt.GetColData(0));
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/plscenes/GNUmakefile b/ogr/ogrsf_frmts/plscenes/GNUmakefile
new file mode 100644
index 0000000..9a88649
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/GNUmakefile
@@ -0,0 +1,14 @@
+
+
+include ../../../GDALmake.opt
+
+OBJ	=	ogrplscenesdataset.o ogrplsceneslayer.o
+
+CPPFLAGS	:=	$(JSON_INCLUDE) -I.. -I../.. -I../geojson  $(CPPFLAGS)
+
+default:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(O_OBJ):	ogr_plscenes.h ../../swq.h ../geojson/ogrgeojsonreader.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/plscenes/drv_plscenes.html b/ogr/ogrsf_frmts/plscenes/drv_plscenes.html
new file mode 100644
index 0000000..861194b
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/drv_plscenes.html
@@ -0,0 +1,194 @@
+<html>
+<head>
+<title>PLScenes (Planet Labs Scenes API)</title>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>PLScenes (Planet Labs Scenes API)</h1>
+
+(GDAL/OGR >= 2.0)<p>
+
+This driver can connect to Planet Labs Scenes API.
+GDAL/OGR must be built with Curl support in order for the
+PLScenes driver to be compiled.<p>
+
+The driver supports read-only operations to list scenes and their metadata
+as a vector layer (currently only "ortho"). It can also access raster scenes.<p>
+
+<h2>Dataset name syntax</h2>
+
+The minimal syntax to open a datasource is : <pre>PLScenes:[options]</pre><p>
+
+Additionnal optional parameters can be specified after the ':' sign.
+Currently the following one is supported :<p>
+
+<ul>
+<li> <b>api_key</b>=value: To specify the Planet API KEY. It is mandatory, unless
+it is supplied through the open option API_KEY, or the configuration option PL_API_KEY.</li>
+<li> <b>scene</b>=scene_id: To specify the scene ID, when accessing raster data.
+Optional for vector layer access.</li>
+<li> <b>product_type</b>=value: To specify the product type: 'visual', 'analytic' or 'thumb'
+(for raster fetching). Default is "visual". Optional for vector layer access.</li>
+</ul>
+
+If several parameters are specified, they must be separated by a comma.<p>
+
+<h2>Open options</h2>
+
+The following open options are available :
+<ul>
+<li><b>API_KEY</b>=value: To specify the Planet API KEY.</li>
+<li><b>SCENE</b>=scene_id: To specify the scene ID, when accessing raster data.
+Optional for vector layer access.</li>
+<li><b>PRODUCT_TYPE</b>=value: To specify the product type: 'visual', 'analytic' or 'thumb
+(for raster fetching). Default is "visual". Optional for vector layer access.</li>
+<li><b>RANDOM_ACCESS</b>=YES/NO: Whether raster should be accessed in random access mode
+(but with potentially not optimal throughput). If NO, in-memory ingestion is done.
+Default is YES.</li>
+</ul>
+
+<h2>Configuration options</h2>
+
+The following configuration options are available :
+<ul>
+<li><b>PL_API_KEY</b>=value: To specify the Planet API KEY.</li>
+</ul>
+
+<h2>Attributes</h2>
+
+The <a href="https://www.planet.com/docs/v0/scenes/#metadata">scene metadata</a>
+are retrieved into the following feature fields :<p>
+
+<table border="1">
+<tr><th>Name</th><th>Type</th><th>Description</th></tr>
+
+<tr><td>id</td><td>String</td><td>Scene unique identifier.</td></tr>
+<tr><td>acquired</td><td>DateTime</td><td>The time that image was taken in UTC.</td></tr>
+<tr><td>camera.bit_depth</td><td>Integer</td><td>Bit depth with which the image was taken onboard the satellite. Currently 8 or 12.</td></tr>
+<tr><td>camera.color_mode</td><td>String</td><td>The color mode of the image as taken by the satellite. Currently "RGB" or "Monochromatic".</td></tr>
+<tr><td>camera.exposure_time</td><td>Integer</td><td>The exposure time in microseconds.</td></tr>
+<tr><td>camera.gain</td><td>Integer</td><td>The analog gain with which the image was taken.</td></tr>
+<tr><td>camera.tdi_pulses</td><td>Integer</td><td>The number of pulses used for time delay and integration on the CCD. Currently 0 (if TDI was not used), 4, 6, or 12.</td></tr>
+<tr><td>cloud_cover.estimated</td><td>Real</td><td>The estimated percentage of the image covered by clouds. Decimal 0-100.</td></tr>
+<tr><td>data.products.analytic.full</td><td>String</td><td>URL to download scene GeoTIFF of the "analytic" product.</td></tr>
+<tr><td>data.products.visual.full</td><td>String</td><td>URL to download scene GeoTIFF of the "visual" product.</td></tr>
+<tr><td>file_size</td><td>Integer</td><td>The size of the full image in bytes.</td></tr>
+<tr><td>image_statistics.gsd</td><td>Real</td><td>The ground sample distance (distance between pixel centers measured on the ground) of the image in meters.</td></tr>
+<tr><td>image_statistics.image_quality</td><td>String</td><td>Image quality category for scene. One of 'test', 'standard', or 'target'.</td></tr>
+<tr><td>image_statistics.snr</td><td>Real</td><td>The estimated signal to noise ratio. Decimal > 0. Values greater than or equal to 50 are considered excellent quality. Values less than 50 and greater than or equal to 20 are considered adequate quality. Values less than 20 are considered poor quality.</td></tr>
+<tr><td>links.full</td><td>String</td><td>URL to download scene GeoTIFF (same content as data.products.visual.full currently)</td></tr>
+<tr><td>links.self</td><td>String</td><td>URL to scene information</td></tr>
+<tr><td>links.square_thumbnail</td><td>String</td><td>URL to image thumbnail</td></tr>
+<tr><td>links.thumbnail</td><td>String</td><td>Link to image square thumbnail</td></tr>
+<tr><td>sat.alt</td><td>Real</td><td>The altitude of the satellite when the image was taken in kilometers.</td></tr>
+<tr><td>sat.id</td><td>String</td><td>A unique identifier for the satellite that captured this image.</td></tr>
+<tr><td>sat.lat</td><td>Real</td><td>The latitude of the satellite when the image was taken in degrees.</td></tr>
+<tr><td>sat.lng</td><td>Real</td><td>The longitude of the satellite when the image was taken in degrees.</td></tr>
+<tr><td>sat.off_nadir</td><td>Real</td><td>The angle off nadir in degrees at which the image was taken.</td></tr>
+<tr><td>strip_id</td><td>Real</td><td>A unique float identifier for the set of images taken sequentially be the same satellite.</td></tr>
+<tr><td>sun.altitude</td><td>Real</td><td>The altitude (angle above horizon) of the sun from the imaged location at the time of capture in degrees.</td></tr>
+<tr><td>sun.azimuth</td><td>Real</td><td>The azimuth (angle clockwise from north) of the sun from the imaged location at the time of capture in degrees.</td></tr>
+<tr><td>sun.local_time_of_day</td><td>Real</td><td>The local sun time at the imaged location at the time of capture (0-24).</td></tr>
+</table>
+
+<h3>Geometry</h3>
+
+The footprint of each scene is reported as a MultiPolygon with a longitude/latitude
+WGS84 coordinate system (EPSG:4326).
+
+<h3>Filtering</h3>
+
+The driver will forward any spatial filter set with SetSpatialFilter() to
+the server. It also makes the same for simple attribute filters set with
+SetAttributeFilter(). Note that not all attributes support all comparison
+operators. Refer to comparator column in <a href="https://www.planet.com/docs/v0/scenes/#metadata">Metadata properties</a> <p>
+
+<h3>Paging</h3>
+
+Features are retrieved from the server by chunks of 1000 by default (and this
+is the maximum value accepted by the server).
+This number can be altered with the PLSCENES_PAGE_SIZE
+configuration option.<p>
+
+<h3>Vector layer (scene metadata) examples</h3>
+
+<li>
+Listing all scenes available (with the rights of the account) :
+<pre>
+ogrinfo -ro -al "PLScenes:" -oo API_KEY=some_value
+</pre>
+or
+<pre>
+ogrinfo -ro -al "PLScenes:api_key=some_value"
+</pre>
+or
+<pre>
+ogrinfo -ro -al "PLScenes:" --config PL_API_KEY some_value
+</pre>
+<p>
+
+<li>
+Listing all scenes available under a point of (lat,lon)=(40,-100) :
+<pre>
+ogrinfo -ro -al "PLScenes:" -oo API_KEY=some_value -spat -100,40,-100,40
+</pre>
+<p>
+
+<li>
+Listing all scenes available within a bounding box (lat,lon)=(40,-100) to (lat,lon)=(39,-99)
+<pre>
+ogrinfo -ro -al "PLScenes:" -oo API_KEY=some_value -spat -100,40,-99,39
+</pre>
+<p>
+
+<li>
+Listing all scenes available matching critera :
+<pre>
+ogrinfo -ro -al "PLScenes:" -oo API_KEY=some_value -where "acquired >= '2015/03/26 00:00:00' AND \"cloud_cover.estimated\" < 10"
+</pre>
+<p>
+
+<h2>Raster access</h2>
+
+<p>Scenes and their thumbnails can be accessed as raster datasets, provided
+that the scene ID is specified with the 'scene' parameter / SCENE open option.
+The product type (visual, analytic or thumb) can be specified with the
+'product_type' parameter / PRODUCT_TYPE open option. The scene id is the
+content of the value of the 'id' field of the features of the 'ortho' vector layer </p>
+
+<p>This functionality is a conveniency wrapper of the
+<a href="https://www.planet.com/docs/v0/scenes/#get-scene-full">API for fetching the scene GeoTIFF</a>
+</p>
+
+<h3>Raster access examples</h3>
+
+<li>
+Displaying raster metadata :
+
+<pre>
+gdalinfo "PLScenes:scene=scene_id,product_type=analytic" -oo API_KEY=some_value
+</pre>
+or
+<pre>
+gdalinfo "PLScenes:" -oo API_KEY=some_value -oo SCENE=scene_id -oo PRODUCT_TYPE=analytic
+</pre>
+
+<li>
+Converting/downloading a whole file:
+
+<pre>
+gdal_translate "PLScenes:" -oo API_KEY=some_value -oo SCENE=scene_id \
+                -oo PRODUCT_TYPE=analytic -oo RANDOM_ACCESS=NO out.tif
+</pre>
+
+<h2>See Also</h2>
+
+<ul>
+<li> <a href="https://www.planet.com/docs/v0/scenes/">Documentation of Planet Scenes API</a><p>
+<li> <a href="https://www.planet.com/docs/v0/general-concepts/#authentication">API Authentication</a><p>
+<li> <a href="frmt_plmosaic.html">Raster PLMosaic / Planet Mosaics API driver</a><p>
+</ul>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/plscenes/makefile.vc b/ogr/ogrsf_frmts/plscenes/makefile.vc
new file mode 100644
index 0000000..2840008
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/makefile.vc
@@ -0,0 +1,15 @@
+
+OBJ	=	ogrplscenesdataset.obj ogrplsceneslayer.obj
+EXTRAFLAGS =	-I.. -I..\..  -I..\geojson -I..\geojson\libjson
+
+GDAL_ROOT	=	..\..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+default:	$(OBJ)
+
+clean:
+	-del *.obj *.pdb
+
+
+
diff --git a/ogr/ogrsf_frmts/plscenes/ogr_plscenes.h b/ogr/ogrsf_frmts/plscenes/ogr_plscenes.h
new file mode 100644
index 0000000..d771b00
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/ogr_plscenes.h
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * $Id: ogr_plscenes.h 28963 2015-04-20 19:55:40Z rouault $
+ *
+ * Project:  PlanetLabs scene driver
+ * Purpose:  PLScenes driver interface
+ * Author:   Even Rouault, even dot rouault at spatialys.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Planet Labs
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGR_PLSCENES_H_INCLUDED
+#define _OGR_PLSCENES_H_INCLUDED
+
+#include "gdal_priv.h"
+#include "ogrsf_frmts.h"
+#include "ogr_srs_api.h"
+#include "cpl_http.h"
+#include <json.h>
+#include "ogr_geojson.h"
+#include "ogrgeojsonreader.h"
+#include "swq.h"
+#include <map>
+
+class OGRPLScenesLayer;
+class OGRPLScenesDataset: public GDALDataset
+{
+        int             bMustCleanPersistant;
+        CPLString       osBaseURL;
+        CPLString       osAPIKey;
+        
+        int             nLayers;
+        OGRPLScenesLayer  **papoLayers;
+        std::map<OGRLayer*, OGRPLScenesLayer*> oMapResultSetToSourceLayer;
+        
+        char             **GetBaseHTTPOptions();
+        GDALDataset       *OpenRasterScene(GDALOpenInfo* poOpenInfo,
+                                           CPLString osScene,
+                                           char** papszOptions);
+
+    public:
+                            OGRPLScenesDataset();
+                           ~OGRPLScenesDataset();
+
+        virtual int         GetLayerCount() { return nLayers; }
+        virtual OGRLayer   *GetLayer(int idx);
+        virtual OGRLayer   *ExecuteSQL( const char *pszSQLCommand,
+                                        OGRGeometry *poSpatialFilter,
+                                        const char *pszDialect );
+        virtual void        ReleaseResultSet( OGRLayer * poLayer );
+
+        json_object        *RunRequest(const char* pszURL,
+                                       int bQuiet404Error = FALSE);
+
+        static int          Identify(GDALOpenInfo* poOpenInfo);
+        static GDALDataset* Open(GDALOpenInfo* poOpenInfo);
+};
+
+class OGRPLScenesLayer: public OGRLayer
+{
+            friend class OGRPLScenesDataset;
+
+            OGRPLScenesDataset* poDS;
+            CPLString       osBaseURL;
+            OGRFeatureDefn* poFeatureDefn;
+            OGRSpatialReference* poSRS;
+            int             bEOF;
+            GIntBig         nNextFID;
+            GIntBig         nFeatureCount;
+            CPLString       osNextURL;
+            CPLString       osRequestURL;
+            CPLString       osQuery;
+            
+            OGRGeoJSONDataSource *poGeoJSONDS;
+            OGRLayer             *poGeoJSONLayer;
+            
+            OGRGeometry    *poMainFilter;
+            
+            int             nPageSize;
+            int             bStillInFirstPage;
+            int             bAcquiredAscending;
+            
+            int             bFilterMustBeClientSideEvaluated;
+            CPLString       osFilterURLPart;
+
+            OGRFeature     *GetNextRawFeature();
+            CPLString       BuildURL(int nFeatures);
+            int             GetNextPage();
+            CPLString       BuildFilter(swq_expr_node* poNode);
+
+    public:
+                            OGRPLScenesLayer(OGRPLScenesDataset* poDS,
+                                         const char* pszName,
+                                         const char* pszBaseURL);
+                           ~OGRPLScenesLayer();
+
+        virtual void            ResetReading();
+        virtual GIntBig         GetFeatureCount(int bForce = FALSE);
+        virtual OGRFeature     *GetNextFeature();
+        virtual int             TestCapability(const char*);
+        virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
+
+        virtual void        SetSpatialFilter( OGRGeometry *poGeom );
+        virtual OGRErr      SetAttributeFilter( const char * );
+        
+        virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce );
+        
+        void                SetMainFilterRect(double dfMinX, double dfMinY,
+                                              double dfMaxX, double dfMaxY);
+        void                SetAcquiredOrderingFlag(int bAcquiredAscendingIn)
+                                { bAcquiredAscending = bAcquiredAscendingIn; }
+};
+
+#endif /* ndef _OGR_PLSCENES_H_INCLUDED */
+
diff --git a/ogr/ogrsf_frmts/plscenes/ogrplscenesdataset.cpp b/ogr/ogrsf_frmts/plscenes/ogrplscenesdataset.cpp
new file mode 100644
index 0000000..85e9241
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/ogrplscenesdataset.cpp
@@ -0,0 +1,577 @@
+/******************************************************************************
+ * $Id: ogrplscenesdataset.cpp 29085 2015-04-30 19:40:11Z rouault $
+ *
+ * Project:  PlanetLabs scene driver
+ * Purpose:  Implements OGRPLScenesDataset
+ * Author:   Even Rouault, even dot rouault at spatialys.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Planet Labs
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_plscenes.h"
+
+// g++ -g -Wall -fPIC -shared -o ogr_PLSCENES.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/plscene ogr/ogrsf_frmts/plscenes/*.c* -L. -lgdal -Iogr/ogrsf_frmts/geojson -Iogr/ogrsf_frmts/geojson/libjson 
+
+CPL_CVSID("$Id: ogrplscenesdataset.cpp 29085 2015-04-30 19:40:11Z rouault $");
+
+extern "C" void RegisterOGRPLSCENES();
+
+/************************************************************************/
+/*                         OGRPLScenesDataset()                         */
+/************************************************************************/
+
+OGRPLScenesDataset::OGRPLScenesDataset()
+{
+    bMustCleanPersistant = FALSE;
+    nLayers = 0;
+    papoLayers = NULL;
+}
+
+/************************************************************************/
+/*                         ~OGRPLScenesDataset()                        */
+/************************************************************************/
+
+OGRPLScenesDataset::~OGRPLScenesDataset()
+{
+    for(int i=0;i<nLayers;i++)
+        delete papoLayers[i];
+    CPLFree(papoLayers);
+
+    if (bMustCleanPersistant)
+    {
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("PLSCENES:%p", this));
+        CPLHTTPFetch( osBaseURL, papszOptions);
+        CSLDestroy(papszOptions);
+    }
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *OGRPLScenesDataset::GetLayer(int idx)
+{
+    if( idx < 0 || idx >= nLayers )
+        return NULL;
+    return papoLayers[idx];
+}
+
+/***********************************************************************/
+/*                            ExecuteSQL()                             */
+/***********************************************************************/
+
+OGRLayer* OGRPLScenesDataset::ExecuteSQL( const char *pszSQLCommand,
+                                          OGRGeometry *poSpatialFilter,
+                                          const char *pszDialect )
+{
+    if( EQUALN(pszSQLCommand, "SELECT ", strlen("SELECT ")) )
+    {
+        swq_select oSelect;
+        CPLString osSQLCommand(pszSQLCommand);
+        size_t nLimitPos = osSQLCommand.ifind(" limit ");
+        if( nLimitPos != std::string::npos )
+            osSQLCommand.resize(nLimitPos);
+
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        OGRErr eErr = oSelect.preparse(osSQLCommand);
+        CPLPopErrorHandler();
+        if( eErr != OGRERR_NONE )
+            return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
+
+/* -------------------------------------------------------------------- */
+/*      ORDER BY optimization on acquired field                         */
+/* -------------------------------------------------------------------- */
+        if( oSelect.join_count == 0 && oSelect.poOtherSelect == NULL &&
+            oSelect.table_count == 1 && oSelect.order_specs == 1 &&
+            strcmp(oSelect.order_defs[0].field_name, "acquired") == 0 )
+        {
+            int idx;
+            OGRPLScenesLayer* poLayer = NULL;
+            for(idx = 0; idx < nLayers; idx ++ )
+            {
+                if( strcmp( papoLayers[idx]->GetName(),
+                            oSelect.table_defs[0].table_name) == 0 )
+                {
+                    poLayer = papoLayers[idx];
+                    break;
+                }
+            }
+            if( poLayer != NULL )
+            {
+                poLayer->SetAcquiredOrderingFlag(
+                                        oSelect.order_defs[0].ascending_flag);
+                OGRLayer* poRet = GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
+                if( poRet )
+                    oMapResultSetToSourceLayer[poRet] = poLayer;
+                return poRet;
+            }
+        }
+    }
+    return GDALDataset::ExecuteSQL(pszSQLCommand, poSpatialFilter, pszDialect);
+}
+
+/***********************************************************************/
+/*                           ReleaseResultSet()                        */
+/***********************************************************************/
+
+void OGRPLScenesDataset::ReleaseResultSet( OGRLayer * poResultsSet )
+{
+    if( poResultsSet )
+    {
+        OGRPLScenesLayer* poSrcLayer = oMapResultSetToSourceLayer[poResultsSet];
+        // Reset the acquired ordering to its default
+        if( poSrcLayer )
+        {
+            poSrcLayer->SetAcquiredOrderingFlag(-1);
+            oMapResultSetToSourceLayer.erase(poResultsSet);
+        }
+        delete poResultsSet;
+    }
+}
+
+/************************************************************************/
+/*                             Identify()                               */
+/************************************************************************/
+
+int OGRPLScenesDataset::Identify(GDALOpenInfo* poOpenInfo)
+{
+    return EQUALN(poOpenInfo->pszFilename, "PLSCENES:", strlen("PLSCENES:"));
+}
+
+/************************************************************************/
+/*                          GetBaseHTTPOptions()                         */
+/************************************************************************/
+
+char** OGRPLScenesDataset::GetBaseHTTPOptions()
+{
+    bMustCleanPersistant = TRUE;
+
+    char** papszOptions = NULL;
+    papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=PLSCENES:%p", this));
+    papszOptions = CSLAddString(papszOptions, CPLSPrintf("HEADERS=Authorization: api-key %s", osAPIKey.c_str()));
+    return papszOptions;
+}
+
+/************************************************************************/
+/*                               RunRequest()                           */
+/************************************************************************/
+
+json_object* OGRPLScenesDataset::RunRequest(const char* pszURL,
+                                            int bQuiet404Error)
+{
+    char** papszOptions = CSLAddString(GetBaseHTTPOptions(), NULL);
+    CPLHTTPResult * psResult;
+    if( strncmp(osBaseURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
+        strncmp(pszURL, "/vsimem/", strlen("/vsimem/")) == 0 )
+    {
+        CPLDebug("PLSCENES", "Fetching %s", pszURL);
+        psResult = (CPLHTTPResult*) CPLCalloc(1, sizeof(CPLHTTPResult));
+        vsi_l_offset nDataLength = 0;
+        CPLString osURL(pszURL);
+        if( osURL[osURL.size()-1 ] == '/' )
+            osURL.resize(osURL.size()-1);
+        GByte* pabyBuf = VSIGetMemFileBuffer(osURL, &nDataLength, FALSE); 
+        if( pabyBuf )
+        {
+            psResult->pabyData = (GByte*) VSIMalloc(1 + nDataLength);
+            if( psResult->pabyData )
+            {
+                memcpy(psResult->pabyData, pabyBuf, nDataLength);
+                psResult->pabyData[nDataLength] = 0;
+            }
+        }
+        else
+        {
+            psResult->pszErrBuf =
+                CPLStrdup(CPLSPrintf("Error 404. Cannot find %s", pszURL));
+        }
+    }
+    else
+    {
+        if( bQuiet404Error )
+            CPLPushErrorHandler(CPLQuietErrorHandler);
+        psResult = CPLHTTPFetch( pszURL, papszOptions);
+        if( bQuiet404Error )
+            CPLPopErrorHandler();
+    }
+    CSLDestroy(papszOptions);
+    
+    if( psResult->pszErrBuf != NULL )
+    {
+        if( !(bQuiet404Error && strstr(psResult->pszErrBuf, "404")) )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "%s",
+                    psResult->pabyData ? (const char*) psResult->pabyData :
+                    psResult->pszErrBuf);
+        }
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    
+    if( psResult->pabyData == NULL )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Empty content returned by server");
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+
+    json_tokener* jstok = NULL;
+    json_object* poObj = NULL;
+
+    jstok = json_tokener_new();
+    poObj = json_tokener_parse_ex(jstok, (const char*) psResult->pabyData, -1);
+    if( jstok->err != json_tokener_success)
+    {
+        CPLError( CE_Failure, CPLE_AppDefined,
+                    "JSON parsing error: %s (at offset %d)",
+                    json_tokener_error_desc(jstok->err), jstok->char_offset);
+        json_tokener_free(jstok);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+    json_tokener_free(jstok);
+
+    CPLHTTPDestroyResult(psResult);
+
+    if( json_object_get_type(poObj) != json_type_object )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, "Return is not a JSON dictionary");
+        json_object_put(poObj);
+        poObj = NULL;
+    }
+    
+    return poObj;
+}
+
+/************************************************************************/
+/*                            OpenRasterScene()                         */
+/************************************************************************/
+
+GDALDataset* OGRPLScenesDataset::OpenRasterScene(GDALOpenInfo* poOpenInfo,
+                                                 CPLString osScene,
+                                                 char** papszOptions)
+{
+    if( !(poOpenInfo->nOpenFlags & GDAL_OF_RASTER) )
+    {
+        return NULL;
+    }
+
+    for( char** papszIter = papszOptions; papszIter && *papszIter; papszIter ++ )
+    {
+        char* pszKey;
+        const char* pszValue = CPLParseNameValue(*papszIter, &pszKey);
+        if( pszValue != NULL )
+        {
+            if( !EQUAL(pszKey, "api_key") &&
+                !EQUAL(pszKey, "scene") &&
+                !EQUAL(pszKey, "product_type") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported, "Unsupported option %s", pszKey);
+                CPLFree(pszKey);
+                return NULL;
+            }
+            CPLFree(pszKey);
+        }
+    }
+
+    const char* pszProductType = CSLFetchNameValueDef(papszOptions, "product_type",
+                CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "PRODUCT_TYPE", "visual"));
+
+    CPLString osRasterURL;
+    osRasterURL = osBaseURL;
+    osRasterURL += "ortho/";
+    osRasterURL += osScene;
+    json_object* poObj = RunRequest( osRasterURL );
+    if( poObj == NULL )
+        return NULL;
+    json_object* poProperties = json_object_object_get(poObj, "properties");
+    if( poProperties == NULL || json_object_get_type(poProperties) != json_type_object )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find properties object");
+        json_object_put(poObj);
+        return NULL;
+    }
+
+    const char* pszLink = NULL;
+    if( EQUAL(pszProductType, "thumb") )
+    {
+        json_object* poLinks = json_object_object_get(poProperties, "links");
+        if( poLinks != NULL && json_object_get_type(poLinks) == json_type_object )
+        {
+            json_object* poThumbnail = json_object_object_get(poLinks, "thumbnail");
+            if( poThumbnail && json_object_get_type(poThumbnail) == json_type_string )
+                pszLink = json_object_get_string(poThumbnail);
+        }
+    }
+    else
+    {
+        json_object* poData = json_object_object_get(poProperties, "data");
+        if( poData != NULL && json_object_get_type(poData) == json_type_object )
+        {
+            json_object* poProducts = json_object_object_get(poData, "products");
+            if( poProducts != NULL && json_object_get_type(poProducts) == json_type_object )
+            {
+                json_object* poProduct = json_object_object_get(poProducts, pszProductType);
+                if( poProduct != NULL && json_object_get_type(poProduct) == json_type_object )
+                {
+                    json_object* poFull = json_object_object_get(poProduct, "full");
+                    if( poFull && json_object_get_type(poFull) == json_type_string )
+                        pszLink = json_object_get_string(poFull);
+                }
+            }
+        }
+    }
+    osRasterURL = pszLink ? pszLink : "";
+    json_object_put(poObj);
+    if( osRasterURL.size() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find link to scene %s",
+                 osScene.c_str());
+        return NULL;
+    }
+    
+    if( strncmp(osRasterURL, "http://", strlen("http://")) == 0 )
+    {
+        osRasterURL = "http://" + osAPIKey + ":@" + osRasterURL.substr(strlen("http://"));
+    }
+    else if( strncmp(osRasterURL, "https://", strlen("https://")) == 0 )
+    {
+        osRasterURL = "https://" + osAPIKey + ":@" + osRasterURL.substr(strlen("https://"));
+    }
+
+    CPLString osOldHead(CPLGetConfigOption("CPL_VSIL_CURL_USE_HEAD", ""));
+    CPLString osOldExt(CPLGetConfigOption("CPL_VSIL_CURL_ALLOWED_EXTENSIONS", ""));
+
+    int bUseVSICURL = CSLFetchBoolean(poOpenInfo->papszOpenOptions, "RANDOM_ACCESS", TRUE);
+    if( bUseVSICURL && !(strncmp(osBaseURL, "/vsimem/", strlen("/vsimem/")) == 0) )
+    {
+        CPLSetThreadLocalConfigOption("CPL_VSIL_CURL_USE_HEAD", "NO");
+        CPLSetThreadLocalConfigOption("CPL_VSIL_CURL_ALLOWED_EXTENSIONS", "{noext}");
+
+        VSIStatBufL sStat;
+        if( VSIStatL(("/vsicurl/" + osRasterURL).c_str(), &sStat) == 0 &&
+            sStat.st_size > 0 )
+        {
+            osRasterURL = "/vsicurl/" + osRasterURL;
+        }
+        else
+        {
+            CPLDebug("PLSCENES", "Cannot use random access for that file");
+        }
+    }
+
+    GDALDataset* poOutDS = (GDALDataset*) GDALOpen(osRasterURL, GA_ReadOnly);
+    if( poOutDS )
+    {
+        poOutDS->SetDescription(poOpenInfo->pszFilename);
+        poOutDS->GetFileList(); /* so as to probe all auxiliary files before reseting the allowed extensions */
+
+        if( !EQUAL(pszProductType, "thumb") )
+        {
+            OGRPLScenesLayer* poLayer = new OGRPLScenesLayer(this, "ortho",
+                                            (osBaseURL + "ortho/").c_str());
+            papoLayers = (OGRPLScenesLayer**) CPLRealloc(papoLayers,
+                                        sizeof(OGRPLScenesLayer*) * (nLayers + 1));
+            papoLayers[nLayers ++] = poLayer;
+
+            /* Attach scene matadata */
+            poLayer->SetAttributeFilter(CPLSPrintf("id = '%s'", osScene.c_str()));
+            OGRFeature* poFeat = poLayer->GetNextFeature();
+            if( poFeat )
+            {
+                for(int i=0;i<poFeat->GetFieldCount();i++)
+                {
+                    if( poFeat->IsFieldSet(i) )
+                    {
+                        const char* pszKey = poFeat->GetFieldDefnRef(i)->GetNameRef();
+                        const char* pszVal = poFeat->GetFieldAsString(i);
+                        if( strstr(pszKey, "file_size") == NULL &&
+                            strstr(pszVal, "https://") == NULL )
+                        {
+                            poOutDS->SetMetadataItem(pszKey, pszVal);
+                        }
+                    }
+                }
+            }
+            delete poFeat;
+        }
+    }
+    
+    if( bUseVSICURL )
+    {
+        CPLSetThreadLocalConfigOption("CPL_VSIL_CURL_USE_HEAD",
+                                    osOldHead.size() ? osOldHead.c_str(): NULL);
+        CPLSetThreadLocalConfigOption("CPL_VSIL_CURL_ALLOWED_EXTENSIONS",
+                                    osOldExt.size() ? osOldExt.c_str(): NULL);
+    }
+
+    return poOutDS;
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+
+GDALDataset* OGRPLScenesDataset::Open(GDALOpenInfo* poOpenInfo)
+{
+    if( !Identify(poOpenInfo) || poOpenInfo->eAccess == GA_Update )
+        return NULL;
+
+    OGRPLScenesDataset* poDS = new OGRPLScenesDataset();
+
+    poDS->osBaseURL = CPLGetConfigOption("PL_URL", "https://api.planet.com/v0/scenes/");
+
+    char** papszOptions = CSLTokenizeStringComplex(
+            poOpenInfo->pszFilename+strlen("PLScenes:"), ",", TRUE, FALSE );
+
+    poDS->osAPIKey = CSLFetchNameValueDef(papszOptions, "api_key",
+        CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "API_KEY",
+                                CPLGetConfigOption("PL_API_KEY","")) );
+    if( poDS->osAPIKey.size() == 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Missing PL_API_KEY configuration option or API_KEY open option");
+        delete poDS;
+        CSLDestroy(papszOptions);
+        return NULL;
+    }
+
+    const char* pszScene = CSLFetchNameValueDef(papszOptions, "scene",
+                CSLFetchNameValue(poOpenInfo->papszOpenOptions, "SCENE"));
+    if( pszScene )
+    {
+        GDALDataset* poRasterDS = poDS->OpenRasterScene(poOpenInfo, pszScene,
+                                                        papszOptions);
+        delete poDS;
+        CSLDestroy(papszOptions);
+        return poRasterDS;
+    }
+
+    for( char** papszIter = papszOptions; papszIter && *papszIter; papszIter ++ )
+    {
+        char* pszKey;
+        const char* pszValue = CPLParseNameValue(*papszIter, &pszKey);
+        if( pszValue != NULL )
+        {
+            if( !EQUAL(pszKey, "api_key") &&
+                !EQUAL(pszKey, "spat") )
+            {
+                CPLError(CE_Failure, CPLE_NotSupported, "Unsupported option %s", pszKey);
+                CPLFree(pszKey);
+                delete poDS;
+                CSLDestroy(papszOptions);
+                return NULL;
+            }
+            CPLFree(pszKey);
+        }
+    }
+
+    json_object* poObj = poDS->RunRequest(poDS->osBaseURL);
+    if( poObj == NULL )
+    {
+        delete poDS;
+        CSLDestroy(papszOptions);
+        return NULL;
+    }
+    
+    json_object_iter it;
+    it.key = NULL;
+    it.val = NULL;
+    it.entry = NULL;
+    json_object_object_foreachC( poObj, it )
+    {
+        if( it.val != NULL && json_object_get_type(it.val) == json_type_string )
+        {
+            OGRPLScenesLayer* poLayer = new OGRPLScenesLayer(poDS, it.key,
+                                                     json_object_get_string(it.val));
+            poDS->papoLayers = (OGRPLScenesLayer**) CPLRealloc(poDS->papoLayers,
+                                        sizeof(OGRPLScenesLayer*) * (poDS->nLayers + 1));
+            poDS->papoLayers[poDS->nLayers ++] = poLayer;
+            
+            const char* pszSpat = CSLFetchNameValue(papszOptions, "spat");
+            if( pszSpat )
+            {
+                char** papszTokens = CSLTokenizeString2(pszSpat, " ", 0);
+                if( CSLCount(papszTokens) >= 4 )
+                {
+                    poLayer->SetMainFilterRect(CPLAtof(papszTokens[0]),
+                                               CPLAtof(papszTokens[1]),
+                                               CPLAtof(papszTokens[2]),
+                                               CPLAtof(papszTokens[3]));
+                }
+                CSLDestroy(papszTokens);
+            }
+        }
+    }
+
+    json_object_put(poObj);
+
+    CSLDestroy(papszOptions);
+
+    if( !(poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) )
+    {
+        delete poDS;
+        return NULL;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                        RegisterOGRPLSCENES()                         */
+/************************************************************************/
+
+void RegisterOGRPLSCENES()
+
+{
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "PLSCENES" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+        
+        poDriver->SetDescription( "PLSCENES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
+                                   "Planet Labs Scenes API" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
+                                   "drv_plscenes.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "PLSCENES:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='API_KEY' type='string' description='Account API key' required='true'/>"
+"  <Option name='SCENE' type='string' description='Scene id (for raster fetching)'/>"
+"  <Option name='PRODUCT_TYPE' type='string' description='Product type: visual, analytic or thumb (for raster fetching)' default='visual'/>"
+"  <Option name='RANDOM_ACCESS' type='boolean' description='Whether raster should be accessed in random access mode (but with potentially not optimal throughput). If no, in-memory ingestion is done' default='YES'/>"
+"</OpenOptionList>");
+
+        poDriver->pfnOpen = OGRPLScenesDataset::Open;
+        poDriver->pfnIdentify = OGRPLScenesDataset::Identify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
+
diff --git a/ogr/ogrsf_frmts/plscenes/ogrplsceneslayer.cpp b/ogr/ogrsf_frmts/plscenes/ogrplsceneslayer.cpp
new file mode 100644
index 0000000..4383ad3
--- /dev/null
+++ b/ogr/ogrsf_frmts/plscenes/ogrplsceneslayer.cpp
@@ -0,0 +1,676 @@
+/******************************************************************************
+ * $Id: ogrplsceneslayer.cpp 28928 2015-04-17 10:24:19Z rouault $
+ *
+ * Project:  PlanetLabs scene driver
+ * Purpose:  Implements OGRPLScenesLayer
+ * Author:   Even Rouault, even dot rouault at spatialys.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Planet Labs
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_plscenes.h"
+
+CPL_CVSID("$Id: ogrplsceneslayer.cpp 28928 2015-04-17 10:24:19Z rouault $");
+
+typedef struct
+{
+    const char* pszName;
+    OGRFieldType eType;
+} PLAttribute;
+
+static const PLAttribute apsAttrs[] = {
+    { "id",                     OFTString },
+    { "acquired",               OFTDateTime },
+    { "camera.bit_depth",       OFTInteger },
+    { "camera.color_mode",      OFTString },
+    { "camera.exposure_time",   OFTInteger },
+    { "camera.gain",            OFTInteger },
+    { "camera.tdi_pulses",      OFTInteger },
+    { "cloud_cover.estimated",  OFTReal },
+    { "data.products.analytic.full",      OFTString },
+    { "data.products.visual.full",        OFTString },
+    { "file_size",                        OFTInteger },
+    { "image_statistics.gsd",             OFTReal },
+    { "image_statistics.image_quality",   OFTString },
+    { "image_statistics.snr",             OFTReal },
+    { "links.full",                       OFTString },
+    { "links.self",                       OFTString },
+    { "links.square_thumbnail",           OFTString },
+    { "links.thumbnail",                  OFTString },
+    { "sat.alt",                          OFTReal },
+    { "sat.id",                           OFTString },
+    { "sat.lat",                          OFTReal },
+    { "sat.lng",                          OFTReal },
+    { "sat.off_nadir",                    OFTReal },
+    { "strip_id",                         OFTReal },
+    { "sun.altitude",                     OFTReal },
+    { "sun.azimuth",                      OFTReal },
+    { "sun.local_time_of_day",            OFTReal },
+};
+
+/************************************************************************/
+/*                           OGRPLScenesLayer()                         */
+/************************************************************************/
+
+OGRPLScenesLayer::OGRPLScenesLayer(OGRPLScenesDataset* poDS,
+                           const char* pszName,
+                           const char* pszBaseURL)
+{
+    this->poDS = poDS;
+    osBaseURL = pszBaseURL;
+    SetDescription(pszName);
+    poFeatureDefn = new OGRFeatureDefn(pszName);
+    poFeatureDefn->SetGeomType(wkbMultiPolygon);
+    for(int i = 0; i < (int)sizeof(apsAttrs) / (int)sizeof(apsAttrs[0]); i++)
+    {
+        OGRFieldDefn oField(apsAttrs[i].pszName, apsAttrs[i].eType);
+        poFeatureDefn->AddFieldDefn(&oField);
+    }
+    poFeatureDefn->Reference();
+    poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
+    poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    bEOF = FALSE;
+    nFeatureCount = -1;
+    nNextFID = 1;
+    poGeoJSONDS = NULL;
+    poGeoJSONLayer = NULL;
+    poMainFilter = NULL;
+    nPageSize = atoi(CPLGetConfigOption("PLSCENES_PAGE_SIZE", "1000"));
+    bStillInFirstPage = FALSE;
+    bAcquiredAscending = -1;
+    bFilterMustBeClientSideEvaluated = FALSE;
+    ResetReading();
+}
+
+/************************************************************************/
+/*                           ~OGRPLScenesLayer()                        */
+/************************************************************************/
+
+OGRPLScenesLayer::~OGRPLScenesLayer()
+{
+    poFeatureDefn->Release();
+    poSRS->Release();
+    delete poGeoJSONDS;
+    delete poMainFilter;
+}
+
+/************************************************************************/
+/*                             BuildFilter()                            */
+/************************************************************************/
+
+CPLString OGRPLScenesLayer::BuildFilter(swq_expr_node* poNode)
+{
+    if( poNode->eNodeType == SNT_OPERATION )
+    {
+        if( poNode->nOperation == SWQ_AND && poNode->nSubExprCount == 2 )
+        {
+            // For AND, we can deal with a failure in one of the branch 
+            // since client-side will do that extra filtering
+            CPLString osFilter1 = BuildFilter(poNode->papoSubExpr[0]);
+            CPLString osFilter2 = BuildFilter(poNode->papoSubExpr[1]);
+            if( osFilter1.size() && osFilter2.size() )
+                return osFilter1 + "&" + osFilter2;
+            else if( osFilter1.size() )
+                return osFilter1;
+            else
+                return osFilter2;
+        }
+        else if( (poNode->nOperation == SWQ_EQ ||
+                  poNode->nOperation == SWQ_NE ||
+                  poNode->nOperation == SWQ_LT ||
+                  poNode->nOperation == SWQ_LE ||
+                  poNode->nOperation == SWQ_GT ||
+                  poNode->nOperation == SWQ_GE) && poNode->nSubExprCount == 2 &&
+                  poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+                  poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
+                  poNode->papoSubExpr[0]->field_index != poFeatureDefn->GetFieldIndex("id") &&
+                  poNode->papoSubExpr[0]->field_index < poFeatureDefn->GetFieldCount() )
+        {
+            OGRFieldDefn *poFieldDefn;
+            poFieldDefn = poFeatureDefn->GetFieldDefn(poNode->papoSubExpr[0]->field_index);
+
+            CPLString osFilter(poFieldDefn->GetNameRef());
+
+            int bDateTimeParsed = FALSE;
+            int nYear = 0, nMonth = 0, nDay = 0, nHour = 0, nMinute = 0, nSecond = 0;
+            if( poNode->papoSubExpr[1]->field_type == SWQ_TIMESTAMP )
+            {
+                if( sscanf(poNode->papoSubExpr[1]->string_value,"%04d/%02d/%02d %02d:%02d:%02d",
+                           &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond) >= 3 ||
+                    sscanf(poNode->papoSubExpr[1]->string_value,"%04d-%02d-%02dT%02d:%02d:%02d",
+                           &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond) >= 3 )
+                    bDateTimeParsed = TRUE;
+            }
+
+            osFilter += ".";
+            if( poNode->nOperation == SWQ_EQ )
+            {
+                if( bDateTimeParsed )
+                    osFilter += "gte";
+                else
+                    osFilter += "eq";
+            }
+            else if( poNode->nOperation == SWQ_NE )
+                osFilter += "neq";
+            else if( poNode->nOperation == SWQ_LT )
+                osFilter += "lt";
+            else if( poNode->nOperation == SWQ_LE )
+                osFilter += "lte";
+            else if( poNode->nOperation == SWQ_GT )
+                osFilter += "gt";
+            else if( poNode->nOperation == SWQ_GE )
+                osFilter += "gte";
+            osFilter += "=";
+
+            if (poNode->papoSubExpr[1]->field_type == SWQ_FLOAT)
+                osFilter += CPLSPrintf("%.8f", poNode->papoSubExpr[1]->float_value);
+            else if (poNode->papoSubExpr[1]->field_type == SWQ_INTEGER)
+                osFilter += CPLSPrintf(CPL_FRMT_GIB, poNode->papoSubExpr[1]->int_value);
+            else if (poNode->papoSubExpr[1]->field_type == SWQ_STRING)
+                osFilter += poNode->papoSubExpr[1]->string_value;
+            else if (poNode->papoSubExpr[1]->field_type == SWQ_TIMESTAMP)
+            {
+                if( bDateTimeParsed )
+                {
+                    osFilter += CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d",
+                                           nYear, nMonth, nDay, nHour, nMinute, nSecond);
+                    if( poNode->nOperation == SWQ_EQ )
+                    {
+                        osFilter += "&";
+                        osFilter += poFieldDefn->GetNameRef();
+                        osFilter += ".lt=";
+                        nSecond ++;
+                        if( nSecond == 60 ) { nSecond = 0; nMinute ++; }
+                        if( nMinute == 60 ) { nMinute = 0; nHour ++; }
+                        if( nHour == 24 ) { nHour = 0; nDay ++; }
+                        osFilter += CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d",
+                                               nYear, nMonth, nDay, nHour, nMinute, nSecond);
+                    }
+                }
+                else
+                    osFilter += poNode->papoSubExpr[1]->string_value;
+            }
+            return osFilter;
+        }
+    }
+    if( !bFilterMustBeClientSideEvaluated )
+    {
+        bFilterMustBeClientSideEvaluated = TRUE;
+        CPLDebug("PLSCENES",
+                 "Part or full filter will have to be evaluated on client side.");
+    }
+    return "";
+}
+
+/************************************************************************/
+/*                             ResetReading()                           */
+/************************************************************************/
+
+void OGRPLScenesLayer::ResetReading()
+{
+    bEOF = FALSE;
+    if( poGeoJSONLayer && bStillInFirstPage )
+        poGeoJSONLayer->ResetReading();
+    else
+        poGeoJSONLayer = NULL;
+    nNextFID = 1;
+    bStillInFirstPage = TRUE;
+    osRequestURL = BuildURL(nPageSize);
+}
+
+/************************************************************************/
+/*                             BuildURL()                               */
+/************************************************************************/
+
+CPLString OGRPLScenesLayer::BuildURL(int nFeatures)
+{
+    CPLString osURL = osBaseURL + CPLSPrintf("?count=%d", nFeatures);
+
+    if( bAcquiredAscending == 1 )
+        osURL += "&order_by=acquired%20asc";
+    else if( bAcquiredAscending == 0 )
+        osURL += "&order_by=acquired%20desc";
+    
+    if( m_poFilterGeom != NULL || poMainFilter != NULL )
+    {
+        OGRGeometry* poIntersection = NULL;
+        OGRGeometry* poFilterGeom = m_poFilterGeom;
+        if( poFilterGeom ) 
+        {
+            OGREnvelope sEnvelope;
+            poFilterGeom->getEnvelope(&sEnvelope);
+            if( sEnvelope.MinX <= -180 && sEnvelope.MinY <= -90 &&
+                sEnvelope.MaxX >= 180 && sEnvelope.MaxY >= 90 )
+                poFilterGeom = NULL;
+        }
+
+        if( poFilterGeom && poMainFilter )
+            poIntersection = poFilterGeom->Intersection(poMainFilter);
+        else if( poFilterGeom )
+            poIntersection = poFilterGeom; 
+        else if( poMainFilter )
+            poIntersection = poMainFilter;
+        if( poIntersection )
+        {
+            char* pszWKT = NULL;
+            OGREnvelope sEnvelope;
+            poIntersection->getEnvelope(&sEnvelope);
+            if( sEnvelope.MinX == sEnvelope.MaxX && sEnvelope.MinY == sEnvelope.MaxY )
+            {
+                pszWKT = CPLStrdup(CPLSPrintf("POINT(%.18g %.18g)",
+                                            sEnvelope.MinX, sEnvelope.MinY));
+            }
+            else
+                poIntersection->exportToWkt(&pszWKT);
+
+            osURL += "&intersects=";
+            char* pszWKTEscaped = CPLEscapeString(pszWKT, -1, CPLES_URL);
+            osURL += pszWKTEscaped;
+            CPLFree(pszWKTEscaped);
+            CPLFree(pszWKT);
+        }
+        if( poIntersection != m_poFilterGeom && poIntersection != poMainFilter  )
+            delete poIntersection;
+    }
+
+    if( osFilterURLPart.size() )
+    {
+        if( osFilterURLPart[0] == '&' )
+            osURL += osFilterURLPart;
+        else
+            osURL = osBaseURL + osFilterURLPart;
+    }
+
+    return osURL;
+}
+
+/************************************************************************/
+/*                              GetNextPage()                           */
+/************************************************************************/
+
+int OGRPLScenesLayer::GetNextPage()
+{
+    delete poGeoJSONDS;
+    poGeoJSONLayer = NULL;
+    poGeoJSONDS = NULL;
+
+    if( osRequestURL.size() == 0 )
+    {
+        bEOF = TRUE;
+        if( !bFilterMustBeClientSideEvaluated && nFeatureCount < 0 )
+            nFeatureCount = 0;
+        return FALSE;
+    }
+    // In the case of a "id = 'foo'" filter, a non existing resource 
+    // will cause a 404 error, which we want to be silent
+    int bQuiet404Error = ( osRequestURL.find('?') == std::string::npos );
+    json_object* poObj = poDS->RunRequest(osRequestURL, bQuiet404Error);
+    if( poObj == NULL )
+    {
+        bEOF = TRUE;
+        if( !bFilterMustBeClientSideEvaluated && nFeatureCount < 0 )
+            nFeatureCount = 0;
+        return FALSE;
+    }
+
+    if( !bFilterMustBeClientSideEvaluated && nFeatureCount < 0 )
+    {
+        json_object* poType = json_object_object_get(poObj, "type");
+        if( poType && json_object_get_type(poType) == json_type_string &&
+            strcmp(json_object_get_string(poType), "Feature") == 0 )
+        {
+            nFeatureCount = 1;
+        }
+        else
+        {
+            json_object* poCount = json_object_object_get(poObj, "count");
+            if( poCount == NULL )
+            {
+                json_object_put(poObj);
+                bEOF = TRUE;
+                nFeatureCount = 0;
+                return FALSE;
+            }
+            nFeatureCount = MAX(0, json_object_get_int64(poCount));
+        }
+    }
+
+    // Parse the Feature/FeatureCollection with the GeoJSON reader
+    poGeoJSONDS = new OGRGeoJSONDataSource();
+    OGRGeoJSONReader oReader;
+    oReader.SetFlattenNestedAttributes(true, '.');
+    oReader.ReadLayer( poGeoJSONDS, "layer", poObj);
+    poGeoJSONLayer = poGeoJSONDS->GetLayer(0);
+    
+    // Get URL of next page
+    osNextURL = "";
+    if( poGeoJSONLayer )
+    {
+        json_object* poLinks = json_object_object_get(poObj, "links");
+        if( poLinks && json_object_get_type(poLinks) == json_type_object )
+        {
+            json_object* poNext = json_object_object_get(poLinks, "next");
+            if( poNext && json_object_get_type(poNext) == json_type_string )
+            {
+                osNextURL = json_object_get_string(poNext);
+            }
+        }
+    }
+
+    json_object_put(poObj);
+    return poGeoJSONLayer != NULL;
+}
+
+/************************************************************************/
+/*                          SetSpatialFilter()                          */
+/************************************************************************/
+
+void OGRPLScenesLayer::SetSpatialFilter(  OGRGeometry *poGeomIn )
+{
+    nFeatureCount = -1;
+    poGeoJSONLayer = NULL;
+
+    if( poGeomIn )
+    {
+        OGREnvelope sEnvelope;
+        poGeomIn->getEnvelope(&sEnvelope);
+        if( sEnvelope.MinX == sEnvelope.MaxX && sEnvelope.MinY == sEnvelope.MaxY )
+        {
+            OGRPoint p(sEnvelope.MinX, sEnvelope.MinY);
+            InstallFilter(&p);
+        }
+        else
+            InstallFilter( poGeomIn );
+    }
+    else
+        InstallFilter( poGeomIn );
+
+    ResetReading();
+}
+
+/************************************************************************/
+/*                         SetAttributeFilter()                         */
+/************************************************************************/
+
+OGRErr OGRPLScenesLayer::SetAttributeFilter( const char *pszQuery )
+
+{
+    if( pszQuery == NULL )
+        osQuery = "";
+    else
+        osQuery = pszQuery;
+
+    nFeatureCount = -1;
+    poGeoJSONLayer = NULL;
+
+    OGRErr eErr = OGRLayer::SetAttributeFilter(pszQuery);
+
+    osFilterURLPart = "";
+    bFilterMustBeClientSideEvaluated = FALSE;
+    if( m_poAttrQuery != NULL )
+    {
+        swq_expr_node* poNode = (swq_expr_node*) m_poAttrQuery->GetSWQExpr();
+
+        poNode->ReplaceBetweenByGEAndLERecurse();
+
+        if( poNode->eNodeType == SNT_OPERATION &&
+            poNode->nOperation == SWQ_EQ && poNode->nSubExprCount == 2 &&
+            poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+            poNode->papoSubExpr[0]->field_index == poFeatureDefn->GetFieldIndex("id") &&
+            poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
+            poNode->papoSubExpr[1]->field_type == SWQ_STRING )
+        {
+            osFilterURLPart = poNode->papoSubExpr[1]->string_value;
+        }
+        else
+        {
+            CPLString osFilter = BuildFilter(poNode);
+            if( osFilter.size() )
+            {
+                osFilterURLPart = "&";
+                osFilterURLPart += osFilter;
+            }
+        }
+    }
+
+    ResetReading();
+
+    return eErr;
+}
+  
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature *OGRPLScenesLayer::GetNextFeature()
+{
+    if( !bFilterMustBeClientSideEvaluated )
+        return GetNextRawFeature();
+
+    OGRFeature  *poFeature;
+
+    while(TRUE)
+    {
+        poFeature = GetNextRawFeature();
+        if (poFeature == NULL)
+            return NULL;
+
+        if((m_poFilterGeom == NULL
+            || FilterGeometry( poFeature->GetGeometryRef() ) )
+        && (m_poAttrQuery == NULL
+            || m_poAttrQuery->Evaluate( poFeature )) )
+        {
+            return poFeature;
+        }
+        else
+            delete poFeature;
+    }
+}
+
+/************************************************************************/
+/*                            GetNextRawFeature()                       */
+/************************************************************************/
+
+OGRFeature* OGRPLScenesLayer::GetNextRawFeature()
+{
+    if( bEOF ||
+        (!bFilterMustBeClientSideEvaluated && nFeatureCount >= 0 && nNextFID > nFeatureCount) )
+        return NULL;
+
+    if( poGeoJSONLayer == NULL )
+    {
+        if( !GetNextPage() )
+            return NULL;
+    }
+
+#ifdef notdef
+    if( CSLTestBoolean(CPLGetConfigOption("OGR_LIMIT_TOO_MANY_FEATURES", "FALSE")) &&
+        nFeatureCount > nPageSize )
+    {
+        bEOF = TRUE;
+        OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
+        OGRGeometry* poGeom;
+        const char* pszWKT = "MULTIPOLYGON(((-180 90,180 90,180 -90,-180 -90,-180 90)))";
+        OGRGeometryFactory::createFromWkt((char**)&pszWKT, poSRS, &poGeom);
+        poFeature->SetGeometryDirectly(poGeom);
+        return poFeature;
+    }
+#endif
+
+    OGRFeature* poGeoJSONFeature = poGeoJSONLayer->GetNextFeature();
+    if( poGeoJSONFeature == NULL )
+    {
+        osRequestURL = osNextURL;
+        bStillInFirstPage = FALSE;
+        if( !GetNextPage() )
+            return NULL;
+        poGeoJSONFeature = poGeoJSONLayer->GetNextFeature();
+        if( poGeoJSONFeature == NULL )
+        {
+            bEOF = TRUE;
+            return NULL;
+        }
+    }
+    OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
+    poFeature->SetFID(nNextFID++);
+
+    OGRGeometry* poGeom = poGeoJSONFeature->StealGeometry();
+    if( poGeom != NULL )
+    {
+        if( poGeom->getGeometryType() == wkbPolygon )
+        {
+            OGRMultiPolygon* poMP = new OGRMultiPolygon();
+            poMP->addGeometryDirectly(poGeom);
+            poGeom = poMP;
+        }
+        poGeom->assignSpatialReference(poSRS);
+        poFeature->SetGeometryDirectly(poGeom);
+    }
+    
+    for(int i=0;i<poFeatureDefn->GetFieldCount();i++)
+    {
+        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(i);
+        OGRFieldType eType = poFieldDefn->GetType();
+        int iSrcField = poGeoJSONFeature->GetFieldIndex(poFieldDefn->GetNameRef());
+        if( iSrcField >= 0 )
+        {
+            if( eType == OFTInteger )
+                poFeature->SetField(i,
+                    poGeoJSONFeature->GetFieldAsInteger(iSrcField));
+            else if( eType == OFTReal )
+                poFeature->SetField(i,
+                    poGeoJSONFeature->GetFieldAsDouble(iSrcField));
+            else
+                poFeature->SetField(i,
+                    poGeoJSONFeature->GetFieldAsString(iSrcField));
+        }
+    }
+
+    delete poGeoJSONFeature;
+
+    return poFeature;
+}
+
+/************************************************************************/
+/*                          GetFeatureCount()                           */
+/************************************************************************/
+
+GIntBig OGRPLScenesLayer::GetFeatureCount(int bForce)
+{
+    if( nFeatureCount < 0 )
+    {
+        CPLString osURL(BuildURL(1));
+        if( bFilterMustBeClientSideEvaluated )
+        {
+            nFeatureCount = OGRLayer::GetFeatureCount(bForce);
+        }
+        else if( osURL.find('?') == std::string::npos )
+        {
+            /* Case of a "id = XXXXX" filter: we get directly a Feature, */
+            /* not a FeatureCollection */
+            GetNextPage();
+        }
+        else
+        {
+            nFeatureCount = 0;
+            json_object* poObj = poDS->RunRequest(osURL);
+            if( poObj != NULL )
+            {
+                json_object* poCount = json_object_object_get(poObj, "count");
+                if( poCount != NULL )
+                    nFeatureCount = MAX(0, json_object_get_int64(poCount));
+
+                // Small optimization, if the feature count is actually 1
+                // then we can fetch it as the full layer
+                if( nFeatureCount == 1 )
+                {
+                    delete poGeoJSONDS;
+                    // Parse the Feature/FeatureCollection with the GeoJSON reader
+                    poGeoJSONDS = new OGRGeoJSONDataSource();
+                    OGRGeoJSONReader oReader;
+                    oReader.SetFlattenNestedAttributes(true, '.');
+                    oReader.ReadLayer( poGeoJSONDS, "layer", poObj);
+                    poGeoJSONLayer = poGeoJSONDS->GetLayer(0);
+                    osNextURL = "";
+                }
+                json_object_put(poObj);
+            }
+        }
+    }
+
+    return nFeatureCount;
+}
+
+/************************************************************************/
+/*                                GetExtent()                           */
+/************************************************************************/
+
+OGRErr OGRPLScenesLayer::GetExtent( OGREnvelope *psExtent, int bForce )
+{
+    GetFeatureCount();
+    if( nFeatureCount > 0 && nFeatureCount < nPageSize )
+        return OGRLayer::GetExtentInternal(0, psExtent, bForce);
+    
+    psExtent->MinX = -180;
+    psExtent->MinY = -90;
+    psExtent->MaxX = 180;
+    psExtent->MaxY = 90;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                              SetMainFilterRect()                     */
+/************************************************************************/
+
+void OGRPLScenesLayer::SetMainFilterRect(double dfMinX, double dfMinY,
+                                        double dfMaxX, double dfMaxY)
+{
+    delete poMainFilter;
+    if( dfMinX == dfMaxX && dfMinY == dfMaxY )
+        poMainFilter = new OGRPoint(dfMinX, dfMinY);
+    else
+    {
+        OGRPolygon* poPolygon = new OGRPolygon();
+        poMainFilter = poPolygon;
+        OGRLinearRing* poLR = new OGRLinearRing;
+        poPolygon->addRingDirectly(poLR);
+        poLR->addPoint(dfMinX, dfMinY);
+        poLR->addPoint(dfMinX, dfMaxY);
+        poLR->addPoint(dfMaxX, dfMaxY);
+        poLR->addPoint(dfMaxX, dfMinY);
+        poLR->addPoint(dfMinX, dfMinY);
+    }
+    ResetReading();
+}
+
+/************************************************************************/
+/*                              TestCapability()                        */
+/************************************************************************/
+
+int OGRPLScenesLayer::TestCapability(const char* pszCap)
+{
+    if( EQUAL(pszCap, OLCFastFeatureCount) )
+        return !bFilterMustBeClientSideEvaluated;
+    if( EQUAL(pszCap, OLCStringsAsUTF8) )
+        return TRUE;
+    return FALSE;
+}
diff --git a/ogr/ogrsf_frmts/rec/GNUmakefile b/ogr/ogrsf_frmts/rec/GNUmakefile
index 4c090c4..62765e3 100644
--- a/ogr/ogrsf_frmts/rec/GNUmakefile
+++ b/ogr/ogrsf_frmts/rec/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrrecdriver.o ogrrecdatasource.o ogrreclayer.o ll_recio.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/rec/ogr_rec.h b/ogr/ogrsf_frmts/rec/ogr_rec.h
index b4e290e..b27ff06 100644
--- a/ogr/ogrsf_frmts/rec/ogr_rec.h
+++ b/ogr/ogrsf_frmts/rec/ogr_rec.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_rec.h 15583 2008-10-23 00:04:33Z warmerdam $
+ * $Id: ogr_rec.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  Epi .REC Translator
  * Purpose:  Definition of classes for OGR .REC support.
@@ -104,19 +104,4 @@ class OGRRECDataSource : public OGRDataSource
     int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                             OGRRECDriver                             */
-/************************************************************************/
-
-class OGRRECDriver : public OGRSFDriver
-{
-  public:
-                ~OGRRECDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    int         TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_REC_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/rec/ogrrecdriver.cpp b/ogr/ogrsf_frmts/rec/ogrrecdriver.cpp
index f7cca15..a8cd38d 100644
--- a/ogr/ogrsf_frmts/rec/ogrrecdriver.cpp
+++ b/ogr/ogrsf_frmts/rec/ogrrecdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrrecdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrrecdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  REC Translator
  * Purpose:  Implements EpiInfo .REC driver.
@@ -30,53 +30,31 @@
 #include "ogr_rec.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrrecdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-/************************************************************************/
-/*                           ~OGRRECDriver()                            */
-/************************************************************************/
-
-OGRRECDriver::~OGRRECDriver()
-
-{
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRRECDriver::TestCapability( const char * )
-
-{
-    return FALSE;
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRRECDriver::GetName()
-
-{
-    return "REC";
-}
+CPL_CVSID("$Id: ogrrecdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRRECDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRRECDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    OGRRECDataSource   *poDS = new OGRRECDataSource();
+    OGRRECDataSource   *poDS;
 
-    if( !poDS->Open( pszFilename ) )
+    if( poOpenInfo->fpL == NULL ||
+        !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "REC") )
+    {
+        return NULL;
+    }
+
+    poDS = new OGRRECDataSource();
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
     }
 
-    if( poDS != NULL && bUpdate )
+    if( poDS != NULL && poOpenInfo->eAccess == GA_Update )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "REC Driver doesn't support update." );
@@ -94,6 +72,21 @@ OGRDataSource *OGRRECDriver::Open( const char * pszFilename, int bUpdate )
 void RegisterOGRREC()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRRECDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "REC" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "REC" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rec" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "EPIInfo .REC " );
+
+        poDriver->pfnOpen = OGRRECDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/rec/ogrreclayer.cpp b/ogr/ogrsf_frmts/rec/ogrreclayer.cpp
index ba885e3..3648261 100644
--- a/ogr/ogrsf_frmts/rec/ogrreclayer.cpp
+++ b/ogr/ogrsf_frmts/rec/ogrreclayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrreclayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrreclayer.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  EPIInfo .REC Reader
  * Purpose:  Implements OGRRECLayer class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrreclayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrreclayer.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                            OGRRECLayer()                             */
@@ -51,6 +51,7 @@ OGRRECLayer::OGRRECLayer( const char *pszLayerNameIn,
     nNextFID = 1;
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerNameIn );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     nFieldCount = 0;
@@ -305,4 +306,3 @@ int OGRRECLayer::TestCapability( CPL_UNUSED const char * pszCap )
 {
     return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/s57/GNUmakefile b/ogr/ogrsf_frmts/s57/GNUmakefile
index 7eec819..c4faacc 100644
--- a/ogr/ogrsf_frmts/s57/GNUmakefile
+++ b/ogr/ogrsf_frmts/s57/GNUmakefile
@@ -10,7 +10,7 @@ OBJ	=	ogrs57driver.o ogrs57datasource.o ogrs57layer.o \
 		s57classregistrar.o s57filecollector.o \
 	        s57featuredefns.o
 
-CPPFLAGS	:=	-I.. -I../.. -I$(ISODIR) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I$(ISODIR)  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/s57/drv_s57.html b/ogr/ogrsf_frmts/s57/drv_s57.html
index eb72a3b..a225f06 100644
--- a/ogr/ogrsf_frmts/s57/drv_s57.html
+++ b/ogr/ogrsf_frmts/s57/drv_s57.html
@@ -124,6 +124,10 @@ feature record will have the same AGEN, FIDN, FIDS and LNAM value.<p>
 There are several control options which can be used to alter the behavior of
 the S-57 reader.  Users can set these by appending them in the 
 OGR_S57_OPTIONS environment variable. 
+<p>
+Starting with GDAL 2.0, they can also be specified independantly as open options
+to the driver.
+<p>
 
 <ul>
 
@@ -151,7 +155,7 @@ when translated S-57 to S-57 losslessly.  Default is OFF. <p>
 
 <li> <b>LNAM_REFS</b>=ON/OFF: Should LNAM and LNAM_REFS fields be 
 attached to features capturing the feature to feature relationships in the
-FFPT group of the S-57 file.  Default is OFF.<p>
+FFPT group of the S-57 file.  Default is ON.<p>
 
 <li> <b>RETURN_LINKAGES</b>=ON/OFF: Should additional attributes 
 relating features to their underlying geometric primtives be attached.  These
@@ -180,13 +184,41 @@ support S-57 to S-57 conversion via OGR.<p>
 set OGR_S57_OPTIONS = "RETURN_PRIMITIVES=ON,RETURN_LINKAGES=ON,LNAM_REFS=ON"
 </pre>
 
+Since GDAL/OGR X.Y.Z, the following dataset creation options are supported to
+supply basic information for the S-57 data set descriptive records (DSID and
+DSPM, see the S-57 standard for a more detailed description):
+
+<ul>
+<li> <B>S57_EXPP</B>: Exchange purpose. Default is 1. <p>
+<li> <B>S57_INTU</B>: Intended usage. Default is 4. <p>
+<li> <B>S57_EDTN</B>: Edition number. Default is 2. <p>
+<li> <B>S57_UPDN</B>: Update number. Default is 0. <p>
+<li> <B>S57_UADT</B>: Update application date. Default is 20030801. <p>
+<li> <B>S57_ISDT</B>: Issue date. Default is 20030801. <p>
+<li> <B>S57_STED</B>: Edition number of S-57. Default is 03.1. <p>
+<li> <B>S57_AGEN</B>: Producing agency. Default is 540. <p>
+<li> <B>S57_COMT</B>: Comment. <p>
+<li> <B>S57_NOMR</B>: Number of meta records (objects with acronym starting with "M_"). Default is 0. <p>
+<li> <B>S57_NOGR</B>: Number of geo records. Default is 0. <p>
+<li> <B>S57_NOLR</B>: Number of collection records. Default is 0. <p>
+<li> <B>S57_NOIN</B>: Number of isolated node records. Default is 0. <p>
+<li> <B>S57_NOCN</B>: Number of connected node records. Default is 0. <p>
+<li> <B>S57_NOED</B>: Number of edge records. Default is 0. <p>
+<li> <B>S57_HDAT</B>: Horizontal geodetic datum. Default is 2. <p>
+<li> <B>S57_VDAT</B>: Vertical datum. Default is 17. <p>
+<li> <B>S57_SDAT</B>: Sounding datum. Default is 23. <p>
+<li> <B>S57_CSCL</B>: Compilation scale of data (1:X). Default is 52000. <p>
+</ul>
+
+
 <h3>See Also</h3>
 
 <ul>
 
-<li> <a href="http://www.s-57.com/">S-57 Online Object/Attribute Catalog</a>
-<li> <a href="http://home.gdal.org/projects/s57/index.html">Frank's S-57
-Page</a>: Links to other resources, and sample datasts.<p>
+<li> <a href="http://www.s-57.com/">S-57 Online Object/Attribute Catalog</a><p>
+<li> <a href="https://web.archive.org/web/20130730111701/http://home.gdal.org/projects/s57/index.html">Frank's S-57
+Page (at archive.org)</a>: Links to other resources, and sample datasts.<p>
+<li> <a href="http://www.iho.int/iho_pubs/standard/S-57Ed3.1/31Main.pdf">IHO S-57 Edition 3.1 (main)<p>
 
 </ul>
 
diff --git a/ogr/ogrsf_frmts/s57/ogr_s57.h b/ogr/ogrsf_frmts/s57/ogr_s57.h
index 3f79d7e..9c0a479 100644
--- a/ogr/ogrsf_frmts/s57/ogr_s57.h
+++ b/ogr/ogrsf_frmts/s57/ogr_s57.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_s57.h 26465 2013-09-13 21:18:16Z rouault $
+ * $Id: ogr_s57.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Declarations for classes binding S57 support onto OGRLayer,
@@ -63,14 +63,14 @@ class OGRS57Layer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
     OGRFeature *        GetNextUnfilteredFeature();
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
     int                 TestCapability( const char * );
 };
 
@@ -100,13 +100,13 @@ class OGRS57DataSource : public OGRDataSource
     OGREnvelope         oExtents;
     
   public:
-                        OGRS57DataSource();
+                        OGRS57DataSource(char** papszOpenOptions = NULL);
                         ~OGRS57DataSource();
 
     void                SetOptionList( char ** );
     const char         *GetOption( const char * );
     
-    int                 Open( const char * pszName, int bTestOpen = FALSE );
+    int                 Open( const char * pszName );
     int                 Create( const char *pszName, char **papszOptions );
 
     const char          *GetName() { return pszName; }
@@ -128,7 +128,7 @@ class OGRS57DataSource : public OGRDataSource
 /*                            OGRS57Driver                              */
 /************************************************************************/
 
-class OGRS57Driver : public OGRSFDriver
+class OGRS57Driver : public GDALDriver
 {
     static S57ClassRegistrar *poRegistrar;
 
@@ -136,11 +136,10 @@ class OGRS57Driver : public OGRSFDriver
                  OGRS57Driver();
                 ~OGRS57Driver();
                 
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    int                 TestCapability( const char * );
+    static GDALDataset *Open( GDALOpenInfo* poOpenInfo );
+    static GDALDataset *Create( const char * pszName,
+                                int nBands, int nXSize, int nYSize, GDALDataType eDT,
+                                char **papszOptions );
 
     static S57ClassRegistrar *GetS57Registrar();
 };
diff --git a/ogr/ogrsf_frmts/s57/ogrs57datasource.cpp b/ogr/ogrsf_frmts/s57/ogrs57datasource.cpp
index 0018002..169a756 100644
--- a/ogr/ogrsf_frmts/s57/ogrs57datasource.cpp
+++ b/ogr/ogrsf_frmts/s57/ogrs57datasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrs57datasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrs57datasource.cpp 28348 2015-01-23 15:27:13Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements OGRS57DataSource class
@@ -32,13 +32,13 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrs57datasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrs57datasource.cpp 28348 2015-01-23 15:27:13Z rouault $");
 
 /************************************************************************/
 /*                          OGRS57DataSource()                          */
 /************************************************************************/
 
-OGRS57DataSource::OGRS57DataSource()
+OGRS57DataSource::OGRS57DataSource(char** papszOpenOptions)
 
 {
     nLayers = 0;
@@ -60,22 +60,29 @@ OGRS57DataSource::OGRS57DataSource()
 /* -------------------------------------------------------------------- */
 /*      Allow initialization of options from the environment.           */
 /* -------------------------------------------------------------------- */
-    const char *pszOptString = CPLGetConfigOption( "OGR_S57_OPTIONS", NULL );
-    papszOptions = NULL;
-
-    if ( pszOptString )
+    if( papszOpenOptions != NULL )
     {
-        char    **papszCurOption;
-
-        papszOptions = 
-            CSLTokenizeStringComplex( pszOptString, ",", FALSE, FALSE );
+        papszOptions = CSLDuplicate(papszOpenOptions);
+    }
+    else
+    {
+        const char *pszOptString = CPLGetConfigOption( "OGR_S57_OPTIONS", NULL );
+        papszOptions = NULL;
 
-        if ( papszOptions && *papszOptions )
+        if ( pszOptString )
         {
-            CPLDebug( "S57", "The following S57 options are being set:" );
-            papszCurOption = papszOptions;
-            while( *papszCurOption )
-                CPLDebug( "S57", "    %s", *papszCurOption++ );
+            char    **papszCurOption;
+
+            papszOptions = 
+                CSLTokenizeStringComplex( pszOptString, ",", FALSE, FALSE );
+
+            if ( papszOptions && *papszOptions )
+            {
+                CPLDebug( "S57", "The following S57 options are being set:" );
+                papszCurOption = papszOptions;
+                while( *papszCurOption )
+                    CPLDebug( "S57", "    %s", *papszCurOption++ );
+            }
         }
     }
 }
@@ -147,43 +154,12 @@ int OGRS57DataSource::TestCapability( const char * )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRS57DataSource::Open( const char * pszFilename, int bTestOpen )
+int OGRS57DataSource::Open( const char * pszFilename )
 
 {
     int         iModule;
     
     pszName = CPLStrdup( pszFilename );
-    
-/* -------------------------------------------------------------------- */
-/*      Check a few bits of the header to see if it looks like an       */
-/*      S57 file (really, if it looks like an ISO8211 file).            */
-/* -------------------------------------------------------------------- */
-    if( bTestOpen )
-    {
-        VSILFILE    *fp;
-        char    pachLeader[10];
-
-        VSIStatBufL sStatBuf;
-        if (VSIStatExL( pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 ||
-            VSI_ISDIR(sStatBuf.st_mode))
-            return FALSE;
-
-        fp = VSIFOpenL( pszFilename, "rb" );
-        if( fp == NULL )
-            return FALSE;
-        
-        if( VSIFReadL( pachLeader, 1, 10, fp ) != 10
-            || (pachLeader[5] != '1' && pachLeader[5] != '2'
-                && pachLeader[5] != '3' )
-            || pachLeader[6] != 'L'
-            || (pachLeader[8] != '1' && pachLeader[8] != ' ') )
-        {
-            VSIFCloseL( fp );
-            return FALSE;
-        }
-
-        VSIFCloseL( fp );
-    }
 
 /* -------------------------------------------------------------------- */
 /*      Setup reader options.                                           */
@@ -193,8 +169,14 @@ int OGRS57DataSource::Open( const char * pszFilename, int bTestOpen )
 
     poModule = new S57Reader( pszFilename );
 
-    papszReaderOptions = CSLSetNameValue(papszReaderOptions, 
+    if( GetOption(S57O_LNAM_REFS) == NULL )
+        papszReaderOptions = CSLSetNameValue(papszReaderOptions, 
                                          S57O_LNAM_REFS, "ON" );
+    else
+        papszReaderOptions = 
+            CSLSetNameValue( papszReaderOptions, S57O_LNAM_REFS, 
+                             GetOption(S57O_LNAM_REFS));
+
     if( GetOption(S57O_UPDATES) != NULL )
         papszReaderOptions = 
             CSLSetNameValue( papszReaderOptions, S57O_UPDATES, 
@@ -235,8 +217,14 @@ int OGRS57DataSource::Open( const char * pszFilename, int bTestOpen )
             CSLSetNameValue( papszReaderOptions, S57O_RECODE_BY_DSSI,
                              GetOption(S57O_RECODE_BY_DSSI) );
 
-    poModule->SetOptions( papszReaderOptions );
+    int bRet = poModule->SetOptions( papszReaderOptions );
     CSLDestroy( papszReaderOptions );
+    
+    if( !bRet )
+    {
+        delete poModule;
+        return FALSE;
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Try opening.                                                    */
@@ -244,7 +232,7 @@ int OGRS57DataSource::Open( const char * pszFilename, int bTestOpen )
 /*      Eventually this should check for catalogs, and if found         */
 /*      instantiate a whole series of modules.                          */
 /* -------------------------------------------------------------------- */
-    if( !poModule->Open( bTestOpen ) )
+    if( !poModule->Open( TRUE ) )
     {
         delete poModule;
 
@@ -477,14 +465,15 @@ OGRErr OGRS57DataSource::GetDSExtent( OGREnvelope *psExtent, int bForce )
 /*      Create a new S57 file, and represent it as a datasource.        */
 /************************************************************************/
 
-int OGRS57DataSource::Create( const char *pszFilename, CPL_UNUSED char **papszOptions )
+int OGRS57DataSource::Create( const char *pszFilename,
+                              char **papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      Instantiate the class registrar if possible.                    */
 /* -------------------------------------------------------------------- */
     if( OGRS57Driver::GetS57Registrar() == NULL )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
+        CPLError( CE_Failure, CPLE_AppDefined,
                   "Unable to load s57objectclasses.csv, unable to continue." );
         return FALSE;
     }
@@ -541,9 +530,52 @@ int OGRS57DataSource::Create( const char *pszFilename, CPL_UNUSED char **papszOp
 /* -------------------------------------------------------------------- */
 /*      Write out "header" records.                                     */
 /* -------------------------------------------------------------------- */
-    poWriter->WriteDSID( pszFilename, "20010409", "03.1", 540, "" );
-
-    poWriter->WriteDSPM();
+    int nEXPP = 1, nINTU = 4, nAGEN = 540, nNOMR = 0, nNOGR = 0,
+        nNOLR = 0, nNOIN = 0, nNOCN = 0, nNOED = 0;
+    const char
+        *pszEXPP = CSLFetchNameValue(papszOptions, "S57_EXPP"),
+        *pszINTU = CSLFetchNameValue(papszOptions, "S57_INTU"),
+        *pszEDTN = CSLFetchNameValue(papszOptions, "S57_EDTN"),
+        *pszUPDN = CSLFetchNameValue(papszOptions, "S57_UPDN"),
+        *pszUADT = CSLFetchNameValue(papszOptions, "S57_UADT"),
+        *pszISDT = CSLFetchNameValue(papszOptions, "S57_ISDT"),
+        *pszSTED = CSLFetchNameValue(papszOptions, "S57_STED"),
+        *pszAGEN = CSLFetchNameValue(papszOptions, "S57_AGEN"),
+        *pszCOMT = CSLFetchNameValue(papszOptions, "S57_COMT"),
+        *pszNOMR = CSLFetchNameValue(papszOptions, "S57_NOMR"),
+        *pszNOGR = CSLFetchNameValue(papszOptions, "S57_NOGR"),
+        *pszNOLR = CSLFetchNameValue(papszOptions, "S57_NOLR"),
+        *pszNOIN = CSLFetchNameValue(papszOptions, "S57_NOIN"),
+        *pszNOCN = CSLFetchNameValue(papszOptions, "S57_NOCN"),
+        *pszNOED = CSLFetchNameValue(papszOptions, "S57_NOED");
+    if (pszEXPP) nEXPP = atoi(pszEXPP);
+    if (pszINTU) nINTU = atoi(pszINTU);
+    if (pszAGEN) nAGEN = atoi(pszAGEN);
+    if (pszNOMR) nNOMR = atoi(pszNOMR);
+    if (pszNOGR) nNOGR = atoi(pszNOGR);
+    if (pszNOLR) nNOLR = atoi(pszNOLR);
+    if (pszNOIN) nNOIN = atoi(pszNOIN);
+    if (pszNOCN) nNOCN = atoi(pszNOCN);
+    if (pszNOED) nNOED = atoi(pszNOED);
+    poWriter->WriteDSID( nEXPP, nINTU, CPLGetFilename( pszFilename ),
+                         pszEDTN, pszUPDN, pszUADT, pszISDT, pszSTED, nAGEN,
+                         pszCOMT, nNOMR, nNOGR, nNOLR, nNOIN, nNOCN, nNOED );
+
+    int nHDAT = 2, nVDAT = 17, nSDAT = 23, nCSCL = 52000;
+    const char
+        *pszHDAT = CSLFetchNameValue(papszOptions, "S57_HDAT"),
+        *pszVDAT = CSLFetchNameValue(papszOptions, "S57_VDAT"),
+        *pszSDAT = CSLFetchNameValue(papszOptions, "S57_SDAT"),
+        *pszCSCL = CSLFetchNameValue(papszOptions, "S57_CSCL");
+    if (pszHDAT)
+        nHDAT = atoi(pszHDAT);
+    if (pszVDAT)
+        nVDAT = atoi(pszVDAT);
+    if (pszSDAT)
+        nSDAT = atoi(pszSDAT);
+    if (pszCSCL)
+        nCSCL = atoi(pszCSCL);
+    poWriter->WriteDSPM(nHDAT, nVDAT, nSDAT, nCSCL);
 
 
     return TRUE;
diff --git a/ogr/ogrsf_frmts/s57/ogrs57driver.cpp b/ogr/ogrsf_frmts/s57/ogrs57driver.cpp
index 0a2244a..a407d8e 100644
--- a/ogr/ogrsf_frmts/s57/ogrs57driver.cpp
+++ b/ogr/ogrsf_frmts/s57/ogrs57driver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrs57driver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrs57driver.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements OGRS57Driver
@@ -32,10 +32,10 @@
 #include "cpl_conv.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrs57driver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrs57driver.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 S57ClassRegistrar *OGRS57Driver::poRegistrar = NULL;
-static void* hS57RegistrarMutex = NULL;
+static CPLMutex* hS57RegistrarMutex = NULL;
 
 /************************************************************************/
 /*                            OGRS57Driver()                            */
@@ -67,32 +67,45 @@ OGRS57Driver::~OGRS57Driver()
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                          OGRS57DriverIdentify()                      */
 /************************************************************************/
 
-const char *OGRS57Driver::GetName()
+static int OGRS57DriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "S57";
+    if( poOpenInfo->nHeaderBytes < 10 )
+        return FALSE;
+    const char* pachLeader = (const char* )poOpenInfo->pabyHeader;
+    if( (pachLeader[5] != '1' && pachLeader[5] != '2'
+                && pachLeader[5] != '3' )
+            || pachLeader[6] != 'L'
+            || (pachLeader[8] != '1' && pachLeader[8] != ' ') )
+    {
+        return FALSE;
+    }
+    return strstr( pachLeader, "DSID") != NULL;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRS57Driver::Open( const char * pszFilename, int bUpdate )
+GDALDataset *OGRS57Driver::Open( GDALOpenInfo* poOpenInfo )
 
 {
     OGRS57DataSource    *poDS;
 
-    poDS = new OGRS57DataSource;
-    if( !poDS->Open( pszFilename, TRUE ) )
+    if( !OGRS57DriverIdentify(poOpenInfo) )
+        return NULL;
+
+    poDS = new OGRS57DataSource(poOpenInfo->papszOpenOptions);
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
     }
 
-    if( poDS && bUpdate )
+    if( poDS && poOpenInfo->eAccess == GA_Update )
     {
         delete poDS;
         CPLError( CE_Failure, CPLE_OpenFailed,
@@ -104,12 +117,15 @@ OGRDataSource *OGRS57Driver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                              Create()                                */
 /************************************************************************/
 
-OGRDataSource *OGRS57Driver::CreateDataSource( const char *pszName, 
-                                               char **papszOptions )
-
+GDALDataset *OGRS57Driver::Create( const char * pszName,
+                                   CPL_UNUSED int nBands,
+                                   CPL_UNUSED int nXSize,
+                                   CPL_UNUSED int nYSize,
+                                   CPL_UNUSED GDALDataType eDT,
+                                   char **papszOptions )
 {
     OGRS57DataSource *poDS = new OGRS57DataSource();
 
@@ -123,19 +139,6 @@ OGRDataSource *OGRS57Driver::CreateDataSource( const char *pszName,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRS57Driver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
 /*                          GetS57Registrar()                           */
 /************************************************************************/
 
@@ -168,7 +171,63 @@ S57ClassRegistrar *OGRS57Driver::GetS57Registrar()
 void RegisterOGRS57()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRS57Driver );
-}
-
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "S57" ) == NULL )
+    {
+        poDriver = new OGRS57Driver();
+
+        poDriver->SetDescription( "S57" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "IHO S-57 (ENC)" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "000" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_s57.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='" S57O_UPDATES "' type='string-select' description='Should update files be incorporated into the base data on the fly' default='APPLY'>"
+"    <Value>APPLY</Value>"
+"    <Value>IGNORE</Value>"
+"  </Option>"
+"  <Option name='" S57O_SPLIT_MULTIPOINT "' type='boolean' description='Should multipoint soundings be split into many single point sounding features' default='NO'/>"
+"  <Option name='" S57O_ADD_SOUNDG_DEPTH "' type='boolean' description='Should a DEPTH attribute be added on SOUNDG features and assign the depth of the sounding' default='NO'/>"
+"  <Option name='" S57O_RETURN_PRIMITIVES "' type='boolean' description='Should all the low level geometry primitives be returned as special IsolatedNode, ConnectedNode, Edge and Face layers' default='NO'/>"
+"  <Option name='" S57O_PRESERVE_EMPTY_NUMBERS "' type='boolean' description='If enabled, numeric attributes assigned an empty string as a value will be preserved as a special numeric value' default='NO'/>"
+"  <Option name='" S57O_LNAM_REFS "' type='boolean' description='Should LNAM and LNAM_REFS fields be attached to features capturing the feature to feature relationships in the FFPT group of the S-57 file' default='YES'/>"
+"  <Option name='" S57O_RETURN_LINKAGES "' type='boolean' description='Should additional attributes relating features to their underlying geometric primtives be attached' default='NO'/>"
+"  <Option name='" S57O_RECODE_BY_DSSI "' type='boolean' description='Should attribute values be recoded to UTF-8 from the character encoding specified in the S57 DSSI record.' default='NO'/>"
+"</OpenOptionList>");
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, 
+"<CreationOptionList>"
+"   <Option name='S57_EXPP' type='int' description='Exchange purpose' default='1'/>"
+"   <Option name='S57_INTU' type='int' description='Intended usage' default='4'/>"
+"   <Option name='S57_EDTN' type='string' description='Edition number' default='2'/>"
+"   <Option name='S57_UPDN' type='string' description='Update number' default='0'/>"
+"   <Option name='S57_UADT' type='string' description='Update application date' default='20030801'/>"
+"   <Option name='S57_ISDT' type='string' description='Issue date' default='20030801'/>"
+"   <Option name='S57_STED' type='string' description='Edition number of S-57' default='03.1'/>"
+"   <Option name='S57_AGEN' type='int' description='Producing agency' default='540'/>"
+"   <Option name='S57_COMT' type='string' description='Comment' default=''/>"
+"   <Option name='S57_NOMR' type='int' description='Number of meta records (objects with acronym starting with \"M_\")' default='0'/>"
+"   <Option name='S57_NOGR' type='int' description='Number of geo records' default='0'/>"
+"   <Option name='S57_NOLR' type='int' description='Number of collection records' default='0'/>"
+"   <Option name='S57_NOIN' type='int' description='Number of isolated node records' default='0'/>"
+"   <Option name='S57_NOCN' type='int' description='Number of connected node records' default='0'/>"
+"   <Option name='S57_NOED' type='int' description='Number of edge records' default='0'/>"
+"   <Option name='S57_HDAT' type='int' description='Horizontal geodetic datum' default='2'/>"
+"   <Option name='S57_VDAT' type='int' description='Vertical datum' default='17'/>"
+"   <Option name='S57_SDAT' type='int' description='Sounding datum' default='23'/>"
+"   <Option name='S57_CSCL' type='int' description='Compilation scale of data (1:X)' default='52000'/>"
+"</CreationOptionList>" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRS57Driver::Open;
+        poDriver->pfnIdentify = OGRS57DriverIdentify;
+        poDriver->pfnCreate = OGRS57Driver::Create;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/s57/ogrs57layer.cpp b/ogr/ogrsf_frmts/s57/ogrs57layer.cpp
index bedfb03..c40dc22 100644
--- a/ogr/ogrsf_frmts/s57/ogrs57layer.cpp
+++ b/ogr/ogrsf_frmts/s57/ogrs57layer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrs57layer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrs57layer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements OGRS57Layer class.
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrs57layer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrs57layer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRS57Layer()                             */
@@ -52,6 +52,7 @@ OGRS57Layer::OGRS57Layer( OGRS57DataSource *poDSIn,
     nFeatureCount = nFeatureCountIn;
 
     poFeatureDefn = poDefnIn;
+    SetDescription( poFeatureDefn->GetName() );
     if( poFeatureDefn->GetGeomFieldCount() > 0 )
         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->GetSpatialRef());
 
@@ -240,7 +241,7 @@ OGRErr OGRS57Layer::GetExtent( OGREnvelope *psExtent, int bForce )
 /************************************************************************/
 /*                          GetFeatureCount()                           */
 /************************************************************************/
-int OGRS57Layer::GetFeatureCount (int bForce)
+GIntBig OGRS57Layer::GetFeatureCount (int bForce)
 {
     
     if( !TestCapability(OLCFastFeatureCount) )
@@ -253,16 +254,16 @@ int OGRS57Layer::GetFeatureCount (int bForce)
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRS57Layer::GetFeature( long nFeatureId )
+OGRFeature *OGRS57Layer::GetFeature( GIntBig nFeatureId )
 
 {
     S57Reader   *poReader = poDS->GetModule(0); // not multi-reader aware
 
-    if( poReader != NULL )
+    if( poReader != NULL && nFeatureId <= INT_MAX )
     {
         OGRFeature      *poFeature;
 
-        poFeature = poReader->ReadFeature( nFeatureId, poFeatureDefn );
+        poFeature = poReader->ReadFeature( (int)nFeatureId, poFeatureDefn );
         if( poFeature != NULL &&  poFeature->GetGeometryRef() != NULL )
             poFeature->GetGeometryRef()->assignSpatialReference(
                 GetSpatialRef() );
@@ -273,10 +274,10 @@ OGRFeature *OGRS57Layer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRS57Layer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRS57Layer::ICreateFeature( OGRFeature *poFeature )
 
 {
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogrsf_frmts/s57/s57.h b/ogr/ogrsf_frmts/s57/s57.h
index dcfe372..74f5d07 100644
--- a/ogr/ogrsf_frmts/s57/s57.h
+++ b/ogr/ogrsf_frmts/s57/s57.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: s57.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: s57.h 28348 2015-01-23 15:27:13Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Declarations for S-57 translator not including the
@@ -321,7 +321,7 @@ class CPL_DLL S57Reader
                        ~S57Reader();
 
     void                SetClassBased( S57ClassRegistrar *, S57ClassContentExplorer* );
-    void                SetOptions( char ** );
+    int                 SetOptions( char ** );
     int                 GetOptionFlags() { return nOptionFlags; }
 
     int                 Open( int bTestOpen );
@@ -371,12 +371,24 @@ public:
     int                 WriteATTF( DDFRecord *, OGRFeature * );
     int                 WritePrimitive( OGRFeature *poFeature );
     int                 WriteCompleteFeature( OGRFeature *poFeature );
-    int                 WriteDSID( const char *pszDSNM = NULL, 
-                                   const char *pszISDT = NULL, 
+    int                 WriteDSID( int nEXPP = 1,
+                                   int nINTU = 4,
+                                   const char *pszDSNM = NULL,
+                                   const char *pszEDTN = NULL,
+                                   const char *pszUPDN = NULL,
+                                   const char *pszUADT = NULL,
+                                   const char *pszISDT = NULL,
                                    const char *pszSTED = NULL,
                                    int nAGEN = 0,
-                                   const char *pszCOMT = NULL );
-    int                 WriteDSPM( int nScale = 0 );
+                                   const char *pszCOMT = NULL,
+                                   int nNOMR = 0, int nNOGR = 0,
+                                   int nNOLR = 0, int nNOIN = 0,
+                                   int nNOCN = 0, int nNOED = 0
+                                 );
+    int                 WriteDSPM( int nHDAT = 0,
+                                   int nVDAT = 0,
+                                   int nSDAT = 0,
+                                   int nCSCL = 0 );
 
 // semi-private - for sophisticated writers.
     DDFRecord           *MakeRecord();
diff --git a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp
index 6343e43..d2ab8ce 100644
--- a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp
+++ b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: s57classregistrar.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: s57classregistrar.cpp 27885 2014-10-19 22:56:48Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements S57ClassRegistrar class for keeping track of
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: s57classregistrar.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: s57classregistrar.cpp 27885 2014-10-19 22:56:48Z rouault $");
 
 
 #ifdef S57_BUILTIN_CLASSES
@@ -58,6 +58,10 @@ S57ClassRegistrar::~S57ClassRegistrar()
 
 {
     nClasses = 0;
+    for(size_t i=0;i<aoAttrInfos.size();i++)
+        delete aoAttrInfos[i];
+    aoAttrInfos.resize(0);
+    nAttrCount = 0;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/s57/s57featuredefns.cpp b/ogr/ogrsf_frmts/s57/s57featuredefns.cpp
index ea3ea75..a52934e 100644
--- a/ogr/ogrsf_frmts/s57/s57featuredefns.cpp
+++ b/ogr/ogrsf_frmts/s57/s57featuredefns.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: s57featuredefns.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: s57featuredefns.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements methods to create OGRFeatureDefns for various
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: s57featuredefns.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: s57featuredefns.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 
 /************************************************************************/
@@ -220,10 +220,11 @@ OGRFeatureDefn *S57GenerateGeomFeatureDefn( OGRwkbGeometryType eGType,
 /************************************************************************/
 
 OGRFeatureDefn *
-S57GenerateVectorPrimitiveFeatureDefn( int nRCNM, CPL_UNUSED int nOptionFlags )
+S57GenerateVectorPrimitiveFeatureDefn( int nRCNM,
+                                       CPL_UNUSED int nOptionFlags )
 {
     OGRFeatureDefn      *poFDefn = NULL;
- 
+
     if( nRCNM == RCNM_VI )
     {
         poFDefn = new OGRFeatureDefn( OGRN_VI );
@@ -531,4 +532,3 @@ void S57GenerateStandardAttributes( OGRFeatureDefn *poFDefn, int nOptionFlags )
         poFDefn->AddFieldDefn( &oField );
     }
 }
-
diff --git a/ogr/ogrsf_frmts/s57/s57reader.cpp b/ogr/ogrsf_frmts/s57/s57reader.cpp
index d3bbec1..9142910 100644
--- a/ogr/ogrsf_frmts/s57/s57reader.cpp
+++ b/ogr/ogrsf_frmts/s57/s57reader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: s57reader.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: s57reader.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements S57Reader class.
@@ -36,7 +36,7 @@
 #include <string>
 #include <fstream>
 
-CPL_CVSID("$Id: s57reader.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: s57reader.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #ifndef PI
 #define PI  3.14159265358979323846
@@ -348,7 +348,7 @@ OGRFeature *S57Reader::NextPendingMultiPoint()
 /*                             SetOptions()                             */
 /************************************************************************/
 
-void S57Reader::SetOptions( char ** papszOptionsIn )
+int S57Reader::SetOptions( char ** papszOptionsIn )
 
 {
     const char * pszOptionValue;
@@ -357,22 +357,27 @@ void S57Reader::SetOptions( char ** papszOptionsIn )
     papszOptions = CSLDuplicate( papszOptionsIn );
 
     pszOptionValue = CSLFetchNameValue( papszOptions, S57O_SPLIT_MULTIPOINT );
-    if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
+    if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
         nOptionFlags |= S57M_SPLIT_MULTIPOINT;
     else
         nOptionFlags &= ~S57M_SPLIT_MULTIPOINT;
 
     pszOptionValue = CSLFetchNameValue( papszOptions, S57O_ADD_SOUNDG_DEPTH );
-    if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
+    if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
         nOptionFlags |= S57M_ADD_SOUNDG_DEPTH;
     else
         nOptionFlags &= ~S57M_ADD_SOUNDG_DEPTH;
 
-    CPLAssert( ! (nOptionFlags & S57M_ADD_SOUNDG_DEPTH)
-               || (nOptionFlags & S57M_SPLIT_MULTIPOINT) );
+    if( (nOptionFlags & S57M_ADD_SOUNDG_DEPTH) &&
+        !(nOptionFlags & S57M_SPLIT_MULTIPOINT) )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Inconsistent options : ADD_SOUNDG_DEPTH should only be enabled if SPLIT_MULTIPOINT is also enabled");
+        return FALSE;
+    }
 
     pszOptionValue = CSLFetchNameValue( papszOptions, S57O_LNAM_REFS );
-    if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
+    if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
         nOptionFlags |= S57M_LNAM_REFS;
     else
         nOptionFlags &= ~S57M_LNAM_REFS;
@@ -387,7 +392,7 @@ void S57Reader::SetOptions( char ** papszOptionsIn )
 
     pszOptionValue = CSLFetchNameValue(papszOptions, 
                                        S57O_PRESERVE_EMPTY_NUMBERS);
-    if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
+    if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
         nOptionFlags |= S57M_PRESERVE_EMPTY_NUMBERS;
     else
         nOptionFlags &= ~S57M_PRESERVE_EMPTY_NUMBERS;
@@ -411,11 +416,12 @@ void S57Reader::SetOptions( char ** papszOptionsIn )
         nOptionFlags &= ~S57M_RETURN_DSID;
 
     pszOptionValue = CSLFetchNameValue( papszOptions, S57O_RECODE_BY_DSSI );
-    if( pszOptionValue != NULL && !EQUAL(pszOptionValue,"OFF") )
+    if( pszOptionValue != NULL && CSLTestBoolean(pszOptionValue) )
         nOptionFlags |= S57M_RECODE_BY_DSSI;
     else
         nOptionFlags &= ~S57M_RECODE_BY_DSSI;
 
+    return TRUE;
 }
 
 /************************************************************************/
diff --git a/ogr/ogrsf_frmts/s57/s57writer.cpp b/ogr/ogrsf_frmts/s57/s57writer.cpp
index abd55b6..54750c5 100644
--- a/ogr/ogrsf_frmts/s57/s57writer.cpp
+++ b/ogr/ogrsf_frmts/s57/s57writer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: s57writer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: s57writer.cpp 28348 2015-01-23 15:27:13Z rouault $
  *
  * Project:  S-57 Translator
  * Purpose:  Implements S57Writer class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: s57writer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: s57writer.cpp 28348 2015-01-23 15:27:13Z rouault $");
 
 /************************************************************************/
 /*                             S57Writer()                              */
@@ -274,7 +274,7 @@ int S57Writer::CreateS57File( const char *pszFilename )
     poFDefn = new DDFFieldDefn();
 
     poFDefn->Create( "SG2D", "2-D coordinate field", "*",
-                     dsc_array, dtc_mixed_data_type );
+                     dsc_array, dtc_bit_string );
 
     poFDefn->AddSubfield( "YCOO", "b24" );
     poFDefn->AddSubfield( "XCOO", "b24" );
@@ -287,7 +287,7 @@ int S57Writer::CreateS57File( const char *pszFilename )
     poFDefn = new DDFFieldDefn();
 
     poFDefn->Create( "SG3D", "3-D coordinate (sounding array) field", "*",
-                     dsc_array, dtc_mixed_data_type );
+                     dsc_array, dtc_bit_string );
 
     poFDefn->AddSubfield( "YCOO", "b24" );
     poFDefn->AddSubfield( "XCOO", "b24" );
@@ -427,9 +427,13 @@ int S57Writer::CreateS57File( const char *pszFilename )
 /*                             WriteDSID()                              */
 /************************************************************************/
 
-int S57Writer::WriteDSID( const char *pszDSNM, const char *pszISDT, 
-                          const char *pszSTED, int nAGEN, 
-                          const char *pszCOMT )
+int S57Writer::WriteDSID( int nEXPP /*1*/, int nINTU /*4*/,
+                          const char *pszDSNM, const char *pszEDTN,
+                          const char *pszUPDN, const char *pszUADT,
+                          const char *pszISDT, const char *pszSTED,
+                          int nAGEN, const char *pszCOMT,
+                          int nNOMR, int nNOGR, int nNOLR, int nNOIN,
+                          int nNOCN, int nNOED )
 
 {
 /* -------------------------------------------------------------------- */
@@ -437,8 +441,14 @@ int S57Writer::WriteDSID( const char *pszDSNM, const char *pszISDT,
 /* -------------------------------------------------------------------- */
     if( pszDSNM == NULL )
         pszDSNM = "";
+    if( pszEDTN == NULL )
+        pszEDTN = "2";
+    if( pszUPDN == NULL )
+        pszUPDN = "0";
     if( pszISDT == NULL )
         pszISDT = "20030801";
+    if( pszUADT == NULL )
+        pszUADT = pszISDT;
     if( pszSTED == NULL )
         pszSTED = "03.1";
     if( pszCOMT == NULL )
@@ -454,12 +464,12 @@ int S57Writer::WriteDSID( const char *pszDSNM, const char *pszISDT,
 
     poRec->SetIntSubfield   ( "DSID", 0, "RCNM", 0, 10 );
     poRec->SetIntSubfield   ( "DSID", 0, "RCID", 0, 1 );
-    poRec->SetIntSubfield   ( "DSID", 0, "EXPP", 0, 1 );
-    poRec->SetIntSubfield   ( "DSID", 0, "INTU", 0, 4 );
+    poRec->SetIntSubfield   ( "DSID", 0, "EXPP", 0, nEXPP );
+    poRec->SetIntSubfield   ( "DSID", 0, "INTU", 0, nINTU );
     poRec->SetStringSubfield( "DSID", 0, "DSNM", 0, pszDSNM );
-    poRec->SetStringSubfield( "DSID", 0, "EDTN", 0, "2" );
-    poRec->SetStringSubfield( "DSID", 0, "UPDN", 0, "0" );
-    poRec->SetStringSubfield( "DSID", 0, "UADT", 0, pszISDT );
+    poRec->SetStringSubfield( "DSID", 0, "EDTN", 0, pszEDTN );
+    poRec->SetStringSubfield( "DSID", 0, "UPDN", 0, pszUPDN );
+    poRec->SetStringSubfield( "DSID", 0, "UADT", 0, pszUADT );
     poRec->SetStringSubfield( "DSID", 0, "ISDT", 0, pszISDT );
     poRec->SetStringSubfield( "DSID", 0, "STED", 0, pszSTED );
     poRec->SetIntSubfield   ( "DSID", 0, "PRSP", 0, 1 );
@@ -475,17 +485,17 @@ int S57Writer::WriteDSID( const char *pszDSNM, const char *pszISDT,
 /* -------------------------------------------------------------------- */
     /* poField = */ poRec->AddField( poModule->FindFieldDefn( "DSSI" ) );
 
-    poRec->SetIntSubfield   ( "DSSI", 0, "DSTR", 0, 2 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "AALL", 0, 1 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NALL", 0, 1 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOMR", 0, 0 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOCR", 0, 0 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOGR", 0, 3 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOLR", 0, 0 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOIN", 0, 3 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOCN", 0, 0 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOED", 0, 0 );
-    poRec->SetIntSubfield   ( "DSSI", 0, "NOFA", 0, 0 );
+    poRec->SetIntSubfield   ( "DSSI", 0, "DSTR", 0, 2 ); // "Chain node"
+    poRec->SetIntSubfield   ( "DSSI", 0, "AALL", 0, 0 );
+    poRec->SetIntSubfield   ( "DSSI", 0, "NALL", 0, 0 );
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOMR", 0, nNOMR ); // Meta records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOCR", 0, 0 ); // Cartographic records are not permitted in ENC
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOGR", 0, nNOGR ); // Geo records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOLR", 0, nNOLR ); // Collection records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOIN", 0, nNOIN ); // Isolated node records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOCN", 0, nNOCN ); // Connected node records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOED", 0, nNOED ); // Edge records
+    poRec->SetIntSubfield   ( "DSSI", 0, "NOFA", 0, 0 ); // Face are not permitted in chain node structure
 
 /* -------------------------------------------------------------------- */
 /*      Write out the record.                                           */
@@ -500,11 +510,17 @@ int S57Writer::WriteDSID( const char *pszDSNM, const char *pszISDT,
 /*                             WriteDSPM()                              */
 /************************************************************************/
 
-int S57Writer::WriteDSPM( int nScale )
+int S57Writer::WriteDSPM( int nHDAT, int nVDAT, int nSDAT, int nCSCL )
 
 {
-    if( nScale == 0 )
-        nScale = 52000;
+    if( nHDAT == 0 )
+        nHDAT = 2;
+    if( nVDAT == 0 )
+        nVDAT = 17;
+    if( nSDAT == 0 )
+        nSDAT = 23;
+    if( nCSCL == 0 )
+        nCSCL = 52000;
 
 /* -------------------------------------------------------------------- */
 /*      Add the DSID field.                                             */
@@ -516,10 +532,10 @@ int S57Writer::WriteDSPM( int nScale )
 
     poRec->SetIntSubfield   ( "DSPM", 0, "RCNM", 0, 20 );
     poRec->SetIntSubfield   ( "DSPM", 0, "RCID", 0, 1 );
-    poRec->SetIntSubfield   ( "DSPM", 0, "HDAT", 0, 2 );
-    poRec->SetIntSubfield   ( "DSPM", 0, "VDAT", 0, 17 );
-    poRec->SetIntSubfield   ( "DSPM", 0, "SDAT", 0, 23 );
-    poRec->SetIntSubfield   ( "DSPM", 0, "CSCL", 0, nScale );
+    poRec->SetIntSubfield   ( "DSPM", 0, "HDAT", 0, nHDAT ); // Must be 2 for ENC
+    poRec->SetIntSubfield   ( "DSPM", 0, "VDAT", 0, nVDAT );
+    poRec->SetIntSubfield   ( "DSPM", 0, "SDAT", 0, nSDAT );
+    poRec->SetIntSubfield   ( "DSPM", 0, "CSCL", 0, nCSCL );
     poRec->SetIntSubfield   ( "DSPM", 0, "DUNI", 0, 1 );
     poRec->SetIntSubfield   ( "DSPM", 0, "HUNI", 0, 1 );
     poRec->SetIntSubfield   ( "DSPM", 0, "PUNI", 0, 1 );
@@ -548,14 +564,13 @@ DDFRecord *S57Writer::MakeRecord()
 {
     DDFRecord *poRec = new DDFRecord( poModule );
     DDFField *poField;
-    unsigned char abyData[3];
+    unsigned char abyData[2];
 
     abyData[0] = nNext0001Index % 256;
     abyData[1] = (unsigned char) (nNext0001Index / 256); 
-    abyData[2] = DDF_FIELD_TERMINATOR;
 
     poField = poRec->AddField( poModule->FindFieldDefn( "0001" ) );
-    poRec->SetFieldRaw( poField, 0, (const char *) abyData, 3 );
+    poRec->SetFieldRaw( poField, 0, (const char *) abyData, 2 );
 
     nNext0001Index++;
 
@@ -581,12 +596,11 @@ int S57Writer::WriteGeometry( DDFRecord *poRec, int nVertCount,
     poField = poRec->AddField( poModule->FindFieldDefn( pszFieldName ) );
 
     if( padfZ )
-        nRawDataSize = 12 * nVertCount + 1;
+        nRawDataSize = 12 * nVertCount;
     else
-        nRawDataSize = 8 * nVertCount + 1;
+        nRawDataSize = 8 * nVertCount;
 
     pabyRawData = (unsigned char *) CPLMalloc(nRawDataSize);
-    pabyRawData[nRawDataSize-1] = DDF_UNIT_TERMINATOR;
 
     for( i = 0; i < nVertCount; i++ )
     {
@@ -715,7 +729,8 @@ int S57Writer::WritePrimitive( OGRFeature *poFeature )
             padfY[i] = poLS->getY(i);
         }
 
-        WriteGeometry( poRec, nVCount, padfX, padfY, NULL );
+        if (nVCount)
+            WriteGeometry( poRec, nVCount, padfX, padfY, NULL );
 
         CPLFree( padfX );
         CPLFree( padfY );
@@ -888,9 +903,8 @@ int S57Writer::WriteCompleteFeature( OGRFeature *poFeature )
 
         CPLAssert( sizeof(int) == sizeof(GInt32) );
 
-        nRawDataSize = nItemCount * 8 + 1;
+        nRawDataSize = nItemCount * 8;
         pabyRawData = (unsigned char *) CPLMalloc(nRawDataSize);
-        pabyRawData[nRawDataSize-1] = DDF_UNIT_TERMINATOR;
 
         for( i = 0; i < nItemCount; i++ )
         {
diff --git a/ogr/ogrsf_frmts/sde/GNUmakefile b/ogr/ogrsf_frmts/sde/GNUmakefile
index 69d6df3..30ba239 100644
--- a/ogr/ogrsf_frmts/sde/GNUmakefile
+++ b/ogr/ogrsf_frmts/sde/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrsdedriver.o ogrsdedatasource.o ogrsdelayer.o
 
-CPPFLAGS	:=	$(GDAL_INCLUDE) $(SDE_INC) $(CPPFLAGS)
+CPPFLAGS	:=	 $(SDE_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sde/ogr_sde.h b/ogr/ogrsf_frmts/sde/ogr_sde.h
index 460d932..3ed9746 100644
--- a/ogr/ogrsf_frmts/sde/ogr_sde.h
+++ b/ogr/ogrsf_frmts/sde/ogr_sde.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_sde.h 22263 2011-04-30 02:51:52Z warmerdam $
+ * $Id: ogr_sde.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR SDE driver.
@@ -122,18 +122,18 @@ class OGRSDELayer : public OGRLayer
     OGRErr              ResetStream();
 
     virtual OGRFeature *GetNextFeature();
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     virtual OGRErr      GetExtent( OGREnvelope *psExtent, int bForce );
-    virtual int         GetFeatureCount( int bForce );
+    virtual GIntBig     GetFeatureCount( int bForce );
 
     virtual OGRErr      SetAttributeFilter( const char *pszQuery );
     
     virtual OGRErr      CreateField( OGRFieldDefn *poFieldIn,
                                      int bApproxOK );
 
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
     
@@ -185,7 +185,7 @@ class OGRSDEDataSource : public OGRDataSource
     int                 GetLayerCount() { return nLayers; }
     OGRLayer            *GetLayer( int );
     
-    virtual OGRLayer    *CreateLayer( const char *,
+    virtual OGRLayer    *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
diff --git a/ogr/ogrsf_frmts/sde/ogrsdedatasource.cpp b/ogr/ogrsf_frmts/sde/ogrsdedatasource.cpp
index 8dd9e77..42f2f60 100644
--- a/ogr/ogrsf_frmts/sde/ogrsdedatasource.cpp
+++ b/ogr/ogrsf_frmts/sde/ogrsdedatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsdedatasource.cpp 22470 2011-05-31 18:18:26Z warmerdam $
+ * $Id: ogrsdedatasource.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSDEDataSource class.
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include "gdal.h"
 
-CPL_CVSID("$Id: ogrsdedatasource.cpp 22470 2011-05-31 18:18:26Z warmerdam $");
+CPL_CVSID("$Id: ogrsdedatasource.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                          OGRSDEDataSource()                           */
@@ -820,11 +820,11 @@ void OGRSDEDataSource::CleanupLayerCreation(const char* pszLayerName)
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRSDEDataSource::CreateLayer( const char * pszLayerName,
+OGRSDEDataSource::ICreateLayer( const char * pszLayerName,
                                OGRSpatialReference *poSRS,
                                OGRwkbGeometryType eType,
                                char ** papszOptions )
@@ -1333,7 +1333,7 @@ void OGRSDEDataSource::EnumerateSpatialTables()
 
     for( iTable = 0; iTable < nTableListCount; iTable++ )
     {
-        CreateLayerFromRegInfo( ahTableList[iTable] );
+       ICreateLayerFromRegInfo( ahTableList[iTable] );
     }
 
     SE_registration_free_info_list( nTableListCount, ahTableList );
@@ -1363,14 +1363,14 @@ void OGRSDEDataSource::OpenSpatialTable( const char* pszTableName )
     }
     else
     {
-        CreateLayerFromRegInfo( tableinfo );
+       ICreateLayerFromRegInfo( tableinfo );
     }
 
     SE_reginfo_free( tableinfo );
 }
 
 /************************************************************************/
-/*                       CreateLayerFromRegInfo()                       */
+/*                      ICreateLayerFromRegInfo()                       */
 /************************************************************************/
 
 void OGRSDEDataSource::CreateLayerFromRegInfo( SE_REGINFO& reginfo )
diff --git a/ogr/ogrsf_frmts/sde/ogrsdelayer.cpp b/ogr/ogrsf_frmts/sde/ogrsdelayer.cpp
index 954f5da..1ae7016 100644
--- a/ogr/ogrsf_frmts/sde/ogrsdelayer.cpp
+++ b/ogr/ogrsf_frmts/sde/ogrsdelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsdelayer.cpp 26688 2013-12-02 19:07:41Z rouault $
+ * $Id: ogrsdelayer.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSDELayer class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrsdelayer.cpp 26688 2013-12-02 19:07:41Z rouault $");
+CPL_CVSID("$Id: ogrsdelayer.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
 /************************************************************************/
 /*                            OGRSDELayer()                             */
@@ -118,19 +118,19 @@ int OGRSDELayer::Initialize( const char *pszTableName,
 /*      Determine DBMS table owner name and the table name part         */
 /*      from pszTableName which is a fully-qualified table name         */
 /* -------------------------------------------------------------------- */
-    char               *pszTableNameCopy = strdup( pszTableName );
+    char               *pszTableNameCopy = CPLStrdup( pszTableName );
     char               *pszPeriodPtr;
     
     if( (pszPeriodPtr = strstr( pszTableNameCopy,"." )) != NULL )
     {
         *pszPeriodPtr  = '\0';
-        pszOwnerName   = strdup( pszTableNameCopy );
-        pszDbTableName = strdup( pszPeriodPtr+1 );
+        pszOwnerName = CPLStrdup(pszTableNameCopy);
+        pszDbTableName = CPLStrdup(pszPeriodPtr + 1);
     }
     else
     {
         pszOwnerName   = NULL;
-        pszDbTableName = strdup( pszTableName );
+        pszDbTableName = CPLStrdup(pszTableName);
     }
     
     CPLFree( pszTableNameCopy );
@@ -174,6 +174,7 @@ int OGRSDELayer::Initialize( const char *pszTableName,
     }
 
     poFeatureDefn = new OGRFeatureDefn( pszTableName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
 /* -------------------------------------------------------------------- */
@@ -1077,7 +1078,7 @@ OGRErr OGRSDELayer::TranslateOGRGeometry( OGRGeometry *poGeom,
 /* -------------------------------------------------------------------- */    
     int                 b3D = FALSE;
     
-    b3D = poGeom->getGeometryType() & wkb25DBit;
+    b3D = wkbHasZ(poGeom->getGeometryType());
     
 /* -------------------------------------------------------------------- */
 /*      Translate POINT/MULTIPOINT type.                                */
@@ -2063,7 +2064,7 @@ OGRFeature *OGRSDELayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRSDELayer::GetFeature( long nFeatureId )
+OGRFeature *OGRSDELayer::GetFeature( GIntBig nFeatureId )
 
 {
     int nSDEErr;
@@ -2186,7 +2187,7 @@ OGRErr OGRSDELayer::ResetStream()
 /*      operator in the database.                                       */
 /************************************************************************/
 
-int OGRSDELayer::GetFeatureCount( int bForce )
+GIntBig OGRSDELayer::GetFeatureCount( int bForce )
 
 {
 /* -------------------------------------------------------------------- */
@@ -2405,9 +2406,9 @@ OGRErr OGRSDELayer::CreateField( OGRFieldDefn *poFieldIn, int bApproxOK )
 
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
-OGRErr OGRSDELayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRSDELayer::ISetFeature( OGRFeature *poFeature )
 
 {
     LONG                nSDEErr;
@@ -2443,9 +2444,9 @@ OGRErr OGRSDELayer::SetFeature( OGRFeature *poFeature )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
-OGRErr OGRSDELayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRSDELayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     LONG                nSDEErr;
@@ -2503,7 +2504,7 @@ OGRErr OGRSDELayer::CreateFeature( OGRFeature *poFeature )
 /************************************************************************/
 /*                           DeleteFeature()                            */
 /************************************************************************/
-OGRErr OGRSDELayer::DeleteFeature( long nFID )
+OGRErr OGRSDELayer::DeleteFeature( GIntBig nFID )
 
 {
     LONG                nSDEErr;
diff --git a/ogr/ogrsf_frmts/sdts/GNUmakefile b/ogr/ogrsf_frmts/sdts/GNUmakefile
index 80d0c42..bd21ccc 100644
--- a/ogr/ogrsf_frmts/sdts/GNUmakefile
+++ b/ogr/ogrsf_frmts/sdts/GNUmakefile
@@ -12,7 +12,7 @@ ISOLIB  =	$(ISODIR)/libiso8211.a
 SDTSDIR = 	../../../frmts/sdts
 SDTSLIB =	$(SDTSDIR)/libsdts_al.a
 
-CPPFLAGS :=	-I.. -I../.. -I$(SDTSDIR) -I$(ISODIR) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS :=	-I.. -I../.. -I$(SDTSDIR) -I$(ISODIR)  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sdts/ogr_sdts.h b/ogr/ogrsf_frmts/sdts/ogr_sdts.h
index 90a0ef2..f14a7e9 100644
--- a/ogr/ogrsf_frmts/sdts/ogr_sdts.h
+++ b/ogr/ogrsf_frmts/sdts/ogr_sdts.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_sdts.h 26466 2013-09-14 09:07:46Z rouault $
+ * $Id: ogr_sdts.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  STS Translator
  * Purpose:  Definition of classes finding SDTS support into OGRDriver
@@ -62,11 +62,11 @@ class OGRSDTSLayer : public OGRLayer
     void                ResetReading();
     OGRFeature *        GetNextFeature();
 
-//    OGRFeature         *GetFeature( long nFeatureId );
+//    OGRFeature         *GetFeature( GIntBig nFeatureId );
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-//    int                 GetFeatureCount( int );
+//    GIntBig             GetFeatureCount( int );
     
     int                 TestCapability( const char * );
 };
@@ -99,19 +99,4 @@ class OGRSDTSDataSource : public OGRDataSource
     OGRSpatialReference *GetSpatialRef() { return poSRS; }
 };
 
-/************************************************************************/
-/*                            OGRSDTSDriver                             */
-/************************************************************************/
-
-class OGRSDTSDriver : public OGRSFDriver
-{
-  public:
-                ~OGRSDTSDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    int         TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_SDTS_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp b/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp
index 3e49ab9..098ddc5 100644
--- a/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp
+++ b/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsdtsdriver.cpp 12396 2007-10-13 10:02:17Z rouault $
+ * $Id: ogrsdtsdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SDTS Translator
  * Purpose:  Implements OGRSDTSDriver
@@ -30,53 +30,36 @@
 #include "ogr_sdts.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsdtsdriver.cpp 12396 2007-10-13 10:02:17Z rouault $");
-
-/************************************************************************/
-/*                           ~OGRSDTSDriver()                           */
-/************************************************************************/
-
-OGRSDTSDriver::~OGRSDTSDriver()
-
-{
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRSDTSDriver::TestCapability( const char * )
-
-{
-    return FALSE;
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRSDTSDriver::GetName()
-
-{
-    return "SDTS";
-}
+CPL_CVSID("$Id: ogrsdtsdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRSDTSDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRSDTSDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    OGRSDTSDataSource   *poDS = new OGRSDTSDataSource();
+    if( !EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "DDF") )
+        return NULL;
+    if( poOpenInfo->nHeaderBytes < 10 )
+        return NULL;
+    const char* pachLeader = (const char* )poOpenInfo->pabyHeader;
+    if( (pachLeader[5] != '1' && pachLeader[5] != '2'
+                && pachLeader[5] != '3' )
+            || pachLeader[6] != 'L'
+            || (pachLeader[8] != '1' && pachLeader[8] != ' ') )
+    {
+        return NULL;
+    }
 
-    if( !poDS->Open( pszFilename, TRUE ) )
+    OGRSDTSDataSource   *poDS = new OGRSDTSDataSource();
+    if( !poDS->Open( poOpenInfo->pszFilename, TRUE ) )
     {
         delete poDS;
         poDS = NULL;
     }
 
-    if( poDS != NULL && bUpdate )
+    if( poDS != NULL && poOpenInfo->eAccess == GA_Update )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "SDTS Driver doesn't support update." );
@@ -94,8 +77,21 @@ OGRDataSource *OGRSDTSDriver::Open( const char * pszFilename, int bUpdate )
 void RegisterOGRSDTS()
 
 {
-    if (! GDAL_CHECK_VERSION("SDTS driver"))
-        return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSDTSDriver );
-}
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "OGR_SDTS" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
+        poDriver->SetDescription( "OGR_SDTS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "SDTS" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_sdts.html" );
+
+        poDriver->pfnOpen = OGRSDTSDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp b/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp
index b358aa3..cfac5af 100644
--- a/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp
+++ b/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsdtslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsdtslayer.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SDTSReader
  * Purpose:  Implements OGRSDTSLayer class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrsdtslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsdtslayer.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                            OGRSDTSLayer()                            */
@@ -58,6 +58,7 @@ OGRSDTSLayer::OGRSDTSLayer( SDTSTransfer * poTransferIn, int iLayerIn,
     
     poFeatureDefn =
         new OGRFeatureDefn(poTransfer->GetCATD()->GetEntryModule(iCATDEntry));
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->GetSpatialRef());
 
@@ -219,14 +220,15 @@ void OGRSDTSLayer::ResetReading()
 /************************************************************************/
 
 static void
-AssignAttrRecordToFeature( OGRFeature * poFeature, CPL_UNUSED SDTSTransfer * poTransfer,
+AssignAttrRecordToFeature( OGRFeature * poFeature,
+                           CPL_UNUSED SDTSTransfer * poTransfer,
                            DDFField * poSR )
 {
 /* -------------------------------------------------------------------- */
 /*      Process each subfield in the record.                            */
 /* -------------------------------------------------------------------- */
     DDFFieldDefn        *poFDefn = poSR->GetFieldDefn();
-        
+
     for( int iSF=0; iSF < poFDefn->GetSubfieldCount(); iSF++ )
     {
         DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield( iSF );
diff --git a/ogr/ogrsf_frmts/segukooa/GNUmakefile b/ogr/ogrsf_frmts/segukooa/GNUmakefile
index 5138434..84115ed 100644
--- a/ogr/ogrsf_frmts/segukooa/GNUmakefile
+++ b/ogr/ogrsf_frmts/segukooa/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrsegukooadriver.o ogrsegukooadatasource.o ogrsegukooalayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/segukooa/ogr_segukooa.h b/ogr/ogrsf_frmts/segukooa/ogr_segukooa.h
index 99ec92e..c422018 100644
--- a/ogr/ogrsf_frmts/segukooa/ogr_segukooa.h
+++ b/ogr/ogrsf_frmts/segukooa/ogr_segukooa.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_segukooa.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_segukooa.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SEG-P1 / UKOOA P1-90 Translator
  * Purpose:  Definition of classes for OGR SEG-P1 / UKOOA P1-90 driver.
@@ -144,8 +144,7 @@ class OGRSEGUKOOADataSource : public OGRDataSource
                         OGRSEGUKOOADataSource();
                         ~OGRSEGUKOOADataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -155,19 +154,4 @@ class OGRSEGUKOOADataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                          OGRSEGUKOOADriver                           */
-/************************************************************************/
-
-class OGRSEGUKOOADriver : public OGRSFDriver
-{
-  public:
-                ~OGRSEGUKOOADriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_SEGUKOOA_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/segukooa/ogrsegukooadatasource.cpp b/ogr/ogrsf_frmts/segukooa/ogrsegukooadatasource.cpp
index e134d89..c8fbbca 100644
--- a/ogr/ogrsf_frmts/segukooa/ogrsegukooadatasource.cpp
+++ b/ogr/ogrsf_frmts/segukooa/ogrsegukooadatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegukooadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsegukooadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SEG-P1 / UKOOA P1-90 Translator
  * Purpose:  Implements OGRSEGUKOOADataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrsegukooadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsegukooadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        OGRSEGUKOOADataSource()                       */
@@ -86,14 +86,9 @@ OGRLayer *OGRSEGUKOOADataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRSEGUKOOADataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRSEGUKOOADataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
diff --git a/ogr/ogrsf_frmts/segukooa/ogrsegukooadriver.cpp b/ogr/ogrsf_frmts/segukooa/ogrsegukooadriver.cpp
index 61f790f..266d75d 100644
--- a/ogr/ogrsf_frmts/segukooa/ogrsegukooadriver.cpp
+++ b/ogr/ogrsf_frmts/segukooa/ogrsegukooadriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegukooadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsegukooadriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SEG-P1 / UKOOA P1-90 Translator
  * Purpose:  Implements OGRSEGUKOOADriver.
@@ -30,39 +30,26 @@
 #include "ogr_segukooa.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsegukooadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsegukooadriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGRSEGUKOOA();
 
 /************************************************************************/
-/*                         ~OGRSEGUKOOADriver()                         */
-/************************************************************************/
-
-OGRSEGUKOOADriver::~OGRSEGUKOOADriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRSEGUKOOADriver::GetName()
-
-{
-    return "SEGUKOOA";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRSEGUKOOADriver::Open( const char * pszFilename, int bUpdate )
-
+static GDALDataset *OGRSEGUKOOADriverOpen( GDALOpenInfo* poOpenInfo )
 {
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        poOpenInfo->pabyHeader[0] != 'H' )
+    {
+        return NULL;
+    }
+
     OGRSEGUKOOADataSource   *poDS = new OGRSEGUKOOADataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -72,21 +59,30 @@ OGRDataSource *OGRSEGUKOOADriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                           RegisterOGRSEGUKOOA()                       */
 /************************************************************************/
 
-int OGRSEGUKOOADriver::TestCapability( CPL_UNUSED const char * pszCap )
+void RegisterOGRSEGUKOOA()
+
 {
-    return FALSE;
-}
+    GDALDriver  *poDriver;
 
-/************************************************************************/
-/*                           RegisterOGRSEGUKOOA()                           */
-/************************************************************************/
+    if( GDALGetDriverByName( "SEGUKOOA" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
-void RegisterOGRSEGUKOOA()
+        poDriver->SetDescription( "SEGUKOOA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "SEG-P1 / UKOOA P1/90" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_segukooa.html" );
 
-{
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSEGUKOOADriver );
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSEGUKOOADriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/segukooa/ogrsegukooalayer.cpp b/ogr/ogrsf_frmts/segukooa/ogrsegukooalayer.cpp
index 175279f..4c4ebcd 100644
--- a/ogr/ogrsf_frmts/segukooa/ogrsegukooalayer.cpp
+++ b/ogr/ogrsf_frmts/segukooa/ogrsegukooalayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegukooalayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsegukooalayer.cpp 28849 2015-04-05 14:05:18Z goatbar $
  *
  * Project:  SEG-P1 / UKOOA P1-90 Translator
  * Purpose:  Implements OGRUKOOAP190Layer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogrsegukooalayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsegukooalayer.cpp 28849 2015-04-05 14:05:18Z goatbar $");
 
 /************************************************************************/
 /*                            ExtractField()                            */
@@ -123,6 +123,7 @@ OGRUKOOAP190Layer::OGRUKOOAP190Layer( const char* pszFilename,
     nYear = 0;
 
     poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPoint );
 
@@ -209,13 +210,13 @@ void OGRUKOOAP190Layer::ParseHeaders()
                 ExtractField(aszParams[i], pszLine, 33 - 1 + i * 6, 6);
             }
             ExtractField(szZ, pszLine, 33 - 1 + 6 * 6, 10);
-            poSRS->SetTOWGS84(atof(aszParams[0]),
-                              atof(aszParams[1]),
-                              atof(aszParams[2]),
-                              atof(aszParams[3]),
-                              atof(aszParams[4]),
-                              atof(aszParams[5]),
-                              atof(szZ));
+            poSRS->SetTOWGS84(CPLAtof(aszParams[0]),
+                              CPLAtof(aszParams[1]),
+                              CPLAtof(aszParams[2]),
+                              CPLAtof(aszParams[3]),
+                              CPLAtof(aszParams[4]),
+                              CPLAtof(aszParams[5]),
+                              CPLAtof(szZ));
         }
         else if (strncmp(pszLine, "H0200", 5) == 0)
         {
@@ -337,7 +338,7 @@ OGRFeature *OGRUKOOAP190Layer::GetNextRawFeature()
         ExtractField(szDeg, pszLine, 26-1, 2);
         ExtractField(szMin, pszLine, 26+2-1, 2);
         ExtractField(szSec, pszLine, 26+2+2-1, 5);
-        double dfLat = atoi(szDeg) + atoi(szMin) / 60.0 + atof(szSec) / 3600.0;
+        double dfLat = atoi(szDeg) + atoi(szMin) / 60.0 + CPLAtof(szSec) / 3600.0;
         if (pszLine[26+2+2+5-1] == 'S')
             dfLat = -dfLat;
         poFeature->SetField(FIELD_LATITUDE, dfLat);
@@ -345,7 +346,7 @@ OGRFeature *OGRUKOOAP190Layer::GetNextRawFeature()
         ExtractField(szDeg, pszLine, 36-1, 3);
         ExtractField(szMin, pszLine, 36+3-1, 2);
         ExtractField(szSec, pszLine, 36+3+2-1, 5);
-        double dfLon = atoi(szDeg) + atoi(szMin) / 60.0 + atof(szSec) / 3600.0;
+        double dfLon = atoi(szDeg) + atoi(szMin) / 60.0 + CPLAtof(szSec) / 3600.0;
         if (pszLine[36+3+2+5-1] == 'W')
             dfLon = -dfLon;
         poFeature->SetField(FIELD_LONGITUDE, dfLon);
@@ -358,12 +359,12 @@ OGRFeature *OGRUKOOAP190Layer::GetNextRawFeature()
         {
             char szEasting[9+1];
             ExtractField(szEasting, pszLine, 47-1, 9);
-            double dfEasting = atof(szEasting);
+            double dfEasting = CPLAtof(szEasting);
             poFeature->SetField(FIELD_EASTING, dfEasting);
 
             char szNorthing[9+1];
             ExtractField(szNorthing, pszLine, 56-1, 9);
-            double dfNorthing = atof(szNorthing);
+            double dfNorthing = CPLAtof(szNorthing);
             poFeature->SetField(FIELD_NORTHING, dfNorthing);
 
             if (bUseEastingNorthingAsGeometry)
@@ -381,7 +382,7 @@ OGRFeature *OGRUKOOAP190Layer::GetNextRawFeature()
         {
             char szDepth[6+1];
             ExtractField(szDepth, pszLine, 65-1, 6);
-            double dfDepth = atof(szDepth);
+            double dfDepth = CPLAtof(szDepth);
             poFeature->SetField(FIELD_DEPTH, dfDepth);
         }
 
@@ -480,6 +481,7 @@ OGRSEGP1Layer::OGRSEGP1Layer( const char* pszFilename,
     poSRS = NULL;
 
     poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPoint );
 
@@ -624,12 +626,12 @@ OGRFeature *OGRSEGP1Layer::GetNextRawFeature()
             {
                 char szEasting[8+1];
                 ExtractField(szEasting, pszLine, 46-1, 8);
-                double dfEasting = atof(szEasting);
+                double dfEasting = CPLAtof(szEasting);
                 poFeature->SetField(SEGP1_FIELD_EASTING, dfEasting);
 
                 char szNorthing[8+1];
                 ExtractField(szNorthing, pszLine, 54-1, 8);
-                double dfNorthing = atof(szNorthing);
+                double dfNorthing = CPLAtof(szNorthing);
                 poFeature->SetField(SEGP1_FIELD_NORTHING, dfNorthing);
 
                 if (bUseEastingNorthingAsGeometry)
@@ -640,7 +642,7 @@ OGRFeature *OGRSEGP1Layer::GetNextRawFeature()
             {
                 char szDepth[5+1];
                 ExtractField(szDepth, pszLine, 62-1, 5);
-                double dfDepth = atof(szDepth);
+                double dfDepth = CPLAtof(szDepth);
                 poFeature->SetField(SEGP1_FIELD_DEPTH, dfDepth);
             }
         }
@@ -691,7 +693,7 @@ char* OGRSEGP1Layer::ExpandTabs(const char* pszLine)
 
 /* Some SEG-P1 files have unusual offsets for latitude/longitude, so */
 /* we try our best to identify it even in case of non-standard layout */
-/* Return non-0 if detection is successfull (column number starts at 1) */
+/* Return non-0 if detection is successful (column number starts at 1) */
 
 int OGRSEGP1Layer::DetectLatitudeColumn(const char* pszLine)
 {
diff --git a/ogr/ogrsf_frmts/segy/GNUmakefile b/ogr/ogrsf_frmts/segy/GNUmakefile
index f457ee7..7118832 100644
--- a/ogr/ogrsf_frmts/segy/GNUmakefile
+++ b/ogr/ogrsf_frmts/segy/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrsegydriver.o ogrsegydatasource.o ogrsegylayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/segy/ogr_segy.h b/ogr/ogrsf_frmts/segy/ogr_segy.h
index 5613c1a..6e495ea 100644
--- a/ogr/ogrsf_frmts/segy/ogr_segy.h
+++ b/ogr/ogrsf_frmts/segy/ogr_segy.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_segy.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_segy.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SEG-Y Translator
  * Purpose:  Definition of classes for OGR SEG-Y driver.
@@ -118,7 +118,7 @@ class OGRSEGYHeaderLayer: public OGRLayer
   public:
                         OGRSEGYHeaderLayer(const char* pszLayerName,
                                            SEGYBinaryFileHeader* psBFH,
-                                           char* pszHeaderText);
+                                           const char* pszHeaderText);
                         ~OGRSEGYHeaderLayer();
 
     virtual OGRFeature *        GetNextFeature();
@@ -145,8 +145,7 @@ class OGRSEGYDataSource : public OGRDataSource
                         OGRSEGYDataSource();
                         ~OGRSEGYDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename, const char* pszHeaderText );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -156,19 +155,4 @@ class OGRSEGYDataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                            OGRSEGYDriver                             */
-/************************************************************************/
-
-class OGRSEGYDriver : public OGRSFDriver
-{
-  public:
-                ~OGRSEGYDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_SEGY_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/segy/ogrsegydatasource.cpp b/ogr/ogrsf_frmts/segy/ogrsegydatasource.cpp
index d3bc539..2f759d1 100644
--- a/ogr/ogrsf_frmts/segy/ogrsegydatasource.cpp
+++ b/ogr/ogrsf_frmts/segy/ogrsegydatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegydatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsegydatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SEG-Y Translator
  * Purpose:  Implements OGRSEGYDataSource class.
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrsegydatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsegydatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        OGRSEGYDataSource()                       */
@@ -107,103 +107,22 @@ GInt32 SEGYReadMSBInt32(const GByte* pabyVal)
 }
 
 /************************************************************************/
-/*                           EBCDICToASCII                              */
-/************************************************************************/
-
-static const GByte EBCDICToASCII[] =
-{
-0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
-0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
-0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
-0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
-0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
-0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
-0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
-0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F,
-};
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRSEGYDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRSEGYDataSource::Open( const char * pszFilename, const char* pszASCIITextHeader)
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     if (fp == NULL)
         return FALSE;
 
+    VSIFSeekL(fp, 3200, SEEK_SET);
 
 // --------------------------------------------------------------------
-//      Read the first 3200 bytes, where the Textual File Header is
-//      located
-// --------------------------------------------------------------------
-
-    GByte* pabyTextHeader = (GByte*) CPLMalloc(3200 + 1);
-    GByte* pabyASCIITextHeader = (GByte*) CPLMalloc(3200 + 40 + 1);
-    if ((int)VSIFReadL(pabyTextHeader, 1, 3200, fp) != 3200 ||
-        EQUALN((const char*)pabyTextHeader, "%PDF", 4))
-    {
-        VSIFCloseL(fp);
-        CPLFree(pabyTextHeader);
-        CPLFree(pabyASCIITextHeader);
-        return FALSE;
-    }
-
-// --------------------------------------------------------------------
-//      Try to decode the header encoded as EBCDIC and then ASCII
-// --------------------------------------------------------------------
-
-    int i, j, k;
-    for( k=0; k<2; k++)
-    {
-        for( i=0, j=0;i<3200;i++)
-        {
-            GByte chASCII = (k == 0) ? EBCDICToASCII[pabyTextHeader[i]] :
-                                       pabyTextHeader[i];
-            if (chASCII < 32 && chASCII != '\t' &&
-                chASCII != '\n' && chASCII != '\r')
-            {
-                break;
-            }
-            pabyASCIITextHeader[j++] = chASCII;
-            if (chASCII != '\n' && ((i + 1) % 80) == 0)
-                pabyASCIITextHeader[j++] = '\n';
-        }
-        pabyASCIITextHeader[j] = '\0';
-
-        if (i == 3200)
-            break;
-        if (k == 1)
-        {
-            VSIFCloseL(fp);
-            CPLFree(pabyTextHeader);
-            CPLFree(pabyASCIITextHeader);
-            return FALSE;
-        }
-    }
-
-    CPLDebug("SIGY", "Header = \n%s", pabyASCIITextHeader);
-    CPLFree(pabyTextHeader);
-
-
-// --------------------------------------------------------------------
-//      SEGYRead the next 400 bytes, where the Binary File Header is
+//      Read the next 400 bytes, where the Binary File Header is
 //      located
 // --------------------------------------------------------------------
 
@@ -211,35 +130,9 @@ int OGRSEGYDataSource::Open( const char * pszFilename, int bUpdateIn)
     if ((int)VSIFReadL(abyFileHeader, 1, 400, fp) != 400)
     {
         VSIFCloseL(fp);
-        CPLFree(pabyASCIITextHeader);
         return FALSE;
     }
 
-// --------------------------------------------------------------------
-//      First check that this binary header is not EBCDIC nor ASCII
-// --------------------------------------------------------------------
-    for( k=0;k<2;k++ )
-    {
-        for( i=0;i<400;i++)
-        {
-            GByte chASCII = (k == 0) ? abyFileHeader[i] :
-                                       EBCDICToASCII[abyFileHeader[i]];
-            /* A translated 0 value, when source value is not 0, means an invalid */
-            /* EBCDIC value. Bail out also for control characters */
-            if (chASCII < 32 && chASCII != '\t' &&
-                chASCII != '\n' && chASCII != '\r')
-            {
-                break;
-            }
-        }
-        if (i == 400)
-        {
-            VSIFCloseL(fp);
-            CPLFree(pabyASCIITextHeader);
-            return FALSE;
-        }
-    }
-
     SEGYBinaryFileHeader sBFH;
 
     sBFH.nJobIdNumber = SEGYReadMSBInt32(abyFileHeader + 0);
@@ -315,7 +208,7 @@ int OGRSEGYDataSource::Open( const char * pszFilename, int bUpdateIn)
     nLayers = 2;
     papoLayers = (OGRLayer**) CPLMalloc(nLayers * sizeof(OGRLayer*));
     papoLayers[0] = new OGRSEGYLayer(pszName, fp, &sBFH);
-    papoLayers[1] = new OGRSEGYHeaderLayer(CPLSPrintf("%s_header", CPLGetBasename(pszName)), &sBFH, (char*) pabyASCIITextHeader);
+    papoLayers[1] = new OGRSEGYHeaderLayer(CPLSPrintf("%s_header", CPLGetBasename(pszName)), &sBFH, pszASCIITextHeader);
 
     return TRUE;
 }
diff --git a/ogr/ogrsf_frmts/segy/ogrsegydriver.cpp b/ogr/ogrsf_frmts/segy/ogrsegydriver.cpp
index 197d219..0a95620 100644
--- a/ogr/ogrsf_frmts/segy/ogrsegydriver.cpp
+++ b/ogr/ogrsf_frmts/segy/ogrsegydriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegydriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsegydriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SEG-Y Translator
  * Purpose:  Implements OGRSEGYDriver class.
@@ -30,61 +30,156 @@
 #include "ogr_segy.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsegydriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsegydriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
-/*                           ~OGRSEGYDriver()                           */
+/*                           EBCDICToASCII                              */
 /************************************************************************/
 
-OGRSEGYDriver::~OGRSEGYDriver()
-
+static const GByte EBCDICToASCII[] =
 {
-}
+0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F,
+0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07,
+0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A,
+0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC,
+0x2D, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x5C, 0x00, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F,
+};
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                                Open()                                */
 /************************************************************************/
 
-const char *OGRSEGYDriver::GetName()
-
+static GDALDataset *OGRSEGYDriverOpen( GDALOpenInfo* poOpenInfo )
 {
-    return "SEGY";
-}
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        !poOpenInfo->TryToIngest(3200+400) ||
+        poOpenInfo->nHeaderBytes < 3200+400 )
+    {
+        return NULL;
+    }
+    if( EQUALN((const char*)poOpenInfo->pabyHeader, "%PDF", 4))
+    {
+        return NULL;
+    }
 
-/************************************************************************/
-/*                                Open()                                */
-/************************************************************************/
+// --------------------------------------------------------------------
+//      Try to decode the header encoded as EBCDIC and then ASCII
+// --------------------------------------------------------------------
+
+    int i, j, k;
+    const GByte* pabyTextHeader = poOpenInfo->pabyHeader;
+    GByte* pabyASCIITextHeader = (GByte*) CPLMalloc(3200 + 40 + 1);
+    for( k=0; k<2; k++)
+    {
+        for( i=0, j=0;i<3200;i++)
+        {
+            GByte chASCII = (k == 0) ? EBCDICToASCII[pabyTextHeader[i]] :
+                                       pabyTextHeader[i];
+            if (chASCII < 32 && chASCII != '\t' &&
+                chASCII != '\n' && chASCII != '\r')
+            {
+                break;
+            }
+            pabyASCIITextHeader[j++] = chASCII;
+            if (chASCII != '\n' && ((i + 1) % 80) == 0)
+                pabyASCIITextHeader[j++] = '\n';
+        }
+        pabyASCIITextHeader[j] = '\0';
+
+        if (i == 3200)
+            break;
+        if (k == 1)
+        {
+            CPLFree(pabyASCIITextHeader);
+            return FALSE;
+        }
+    }
 
-OGRDataSource *OGRSEGYDriver::Open( const char * pszFilename, int bUpdate )
+    CPLDebug("SIGY", "Header = \n%s", pabyASCIITextHeader);
+    CPLFree(pabyASCIITextHeader);
+    pabyASCIITextHeader = NULL;
+
+// --------------------------------------------------------------------
+//      Read the next 400 bytes, where the Binary File Header is
+//      located
+// --------------------------------------------------------------------
+
+    const GByte* abyFileHeader = poOpenInfo->pabyHeader + 3200;
+
+// --------------------------------------------------------------------
+//      First check that this binary header is not EBCDIC nor ASCII
+// --------------------------------------------------------------------
+    for( k=0;k<2;k++ )
+    {
+        for( i=0;i<400;i++)
+        {
+            GByte chASCII = (k == 0) ? abyFileHeader[i] :
+                                       EBCDICToASCII[abyFileHeader[i]];
+            /* A translated 0 value, when source value is not 0, means an invalid */
+            /* EBCDIC value. Bail out also for control characters */
+            if (chASCII < 32 && chASCII != '\t' &&
+                chASCII != '\n' && chASCII != '\r')
+            {
+                break;
+            }
+        }
+        if (i == 400)
+        {
+            CPLFree(pabyASCIITextHeader);
+            return NULL;
+        }
+    }
 
-{
     OGRSEGYDataSource   *poDS = new OGRSEGYDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, (const char*)pabyASCIITextHeader ) )
     {
+        CPLFree(pabyASCIITextHeader);
         delete poDS;
         poDS = NULL;
     }
 
+    CPLFree(pabyASCIITextHeader);
     return poDS;
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRSEGYDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRSEGY()                           */
 /************************************************************************/
 
 void RegisterOGRSEGY()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSEGYDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "SEGY" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "SEGY" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "SEG-Y" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_segy.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSEGYDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/segy/ogrsegylayer.cpp b/ogr/ogrsf_frmts/segy/ogrsegylayer.cpp
index 297ecbf..0182446 100644
--- a/ogr/ogrsf_frmts/segy/ogrsegylayer.cpp
+++ b/ogr/ogrsf_frmts/segy/ogrsegylayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsegylayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsegylayer.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SEG-Y Translator
  * Purpose:  Implements OGRSEGYLayer class.
@@ -33,7 +33,7 @@
 #include "ogr_p.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogrsegylayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsegylayer.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 #define DT_IBM_4BYTES_FP         1
 #define DT_4BYTES_INT            2
@@ -805,14 +805,15 @@ static const FieldDesc SEGYHeaderFields[] =
 
 OGRSEGYHeaderLayer::OGRSEGYHeaderLayer( const char* pszLayerName,
                                         SEGYBinaryFileHeader* psBFH,
-                                        char* pszHeaderTextIn )
+                                        const char* pszHeaderTextIn )
 
 {
     bEOF = FALSE;
     memcpy(&sBFH, psBFH, sizeof(sBFH));
-    pszHeaderText = pszHeaderTextIn;
+    pszHeaderText = CPLStrdup(pszHeaderTextIn);
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbNone );
 
diff --git a/ogr/ogrsf_frmts/selafin/GNUmakefile b/ogr/ogrsf_frmts/selafin/GNUmakefile
new file mode 100644
index 0000000..7344dbe
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/GNUmakefile
@@ -0,0 +1,15 @@
+
+
+include ../../../GDALmake.opt
+
+OBJ	=	ogrselafindriver.o ogrselafindatasource.o ogrselafinlayer.o io_selafin.o
+
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS) 
+
+default:	$(O_OBJ:.o=.$(OBJ_EXT))
+
+clean:
+	rm -f *.o $(O_OBJ)
+
+$(O_OBJ):	ogr_selafin.h io_selafin.h
+
diff --git a/ogr/ogrsf_frmts/selafin/drv_selafin.html b/ogr/ogrsf_frmts/selafin/drv_selafin.html
new file mode 100644
index 0000000..024cede
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/drv_selafin.html
@@ -0,0 +1,259 @@
+<html>
+<head>
+<title>Selafin files</title>
+<style type="text/css">
+<!--
+#tableslots {width:100%; border-collapse:collapse}
+#tableslots tr {border-width: thin; border-style:solid; width:20px;}
+#tableslots > * > tr > td {padding-top:10px; padding-bottom:10px;}
+#tablesexamples {border-collapse:collapse}
+#tablesexamples td {border-width: thin; border-style:solid;}
+#tableoperations {width:100%; border-width:medium; border-style:solid; border-collapse:collapse}
+#tableoperations td {border-width: thin; border-style:solid}
+#tableoperations th {border-width: thin; border-style:solid}
+#tableoperations thead tr {border-width: medium; border-style:solid}
+.slots td {text-align:center; background-color:rgb(220,220,220); margin:0px; padding:0px; width: 20px}
+-->
+</style>
+</head>
+
+<body bgcolor="#ffffff">
+
+<h1>Selafin files</h1>
+
+<p>OGR supports reading from 2D Selafin/Seraphin files. Selafin/Seraphin is the generic output and input format of geographical files in the open-source <a href="http://www.opentelemac.org">Telemac hydraulic model</a>. The file format is suited to the description of numerical attributes for a set of point features at different time steps. Those features usually correspond to the nodes in a finite-element model. The file also holds a connectivity table which describes the elements formed  [...]
+
+<p>The driver supports the use of VSI virtual files as Selafin datasources.</p>
+
+<p>The driver offers full read-write support on Selafin files. However, due to the particular nature of Selafin files where element (polygon) features and node (point) features are closely related, writing on Selafin layers can lead to counter-intuitive results. In a general way, writing on any layer of a Selafin data-source will cause side effects on all the other layers. Also, it is very important <b>not to open the same datasource more than once in update mode</b>. Having two processe [...]
+
+<h2>Magic bytes</h2>
+
+<p>There is no generic extension to Selafin files. The adequate format is tested by looking at a dozen of magic bytes at the beginning of the file:
+<ul>
+<li>The first four bytes of the file should contain the values (in hexadecimal): 00 00 00 50. This actually indicates the start of a string of length 80 in the file.</li>
+<li>At position 84 in the file, the eight next bytes should read (in hexadecimal): 00 00 00 50 00 00 00 04.</li>
+</ul>
+</p>
+
+<p>Files which match those two criterias are considered to be Selafin files and the driver will report it has opened them successfully.</p>
+
+<h2><a id="format">Format</a></h2>
+
+<p>Selafin format is designed to hold data structures in a portable and compact way, and to allow efficient random access to the data. To this purpose, Selafin files are binary files with a generic structure.</p>
+
+<h3>Elements</h3>
+<p>Selafin files are made of the juxtaposition of elements. Elements have one of the following types:
+<ul>
+	<li>integer,</li>
+	<li>string,</li>
+	<li>floating point values,</li>
+	<li>arrays of integers,</li>
+	<li>arrays of floating point values.</li>
+</ul></p>
+
+<table id="tableslots">
+	<tr>
+		<th>Element</th>
+		<th>Internal representation</th>
+		<th>Comments</th>
+	</tr>
+	<tr>
+		<td>Integer</td>
+		<td> <table class="slots"><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr></table> </td>
+		<td>Integers are stored on 4 bytes in big-endian format (most significant byte first). The value of the integer is 2<sup>24</sup>.a+2<sup>16</sup>.b+2<sup>8</sup>.c+d.</td>
+	</tr>
+	<tr>
+		<td>Floating point</td>
+		<td> <table class="slots"><tr><td>a</td><td>b</td><td>c</td><td>d</td></tr></table> </td>
+		<td>Floating point values are stored on 4 bytes in IEEE 754 format and under big-endian convention (most significant byte first). Endianness is detected at run time only once when the first floating point value is read.</td>
+	</tr>
+	<tr>
+		<td>String</td>
+		<td> <table class="slots"><tr><td style="width:80px">Length</td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td><td>...</td><td style="width: 80px">Length</td></tr></table> </td>
+		<td>Strings are stored in three parts:
+			<ul>
+				<li>an integer holding the length (in characters) of the string, over 4 bytes;</li>
+				<li>the sequence of characters of the string, each character on one byte;</li>
+				<li>the same integer with the length of the string repeated</li>
+			</ul>
+		</td>
+	</tr>
+	<tr>
+		<td>Array of integers</td>
+		<td> <table class="slots"><tr><td style="width:80px;">Length</td><td style="width:80px">1</td><td style="width:80px">2</td><td style="width:80px">3</td><td style="width:80px">...</td><td style="width: 80px">Length</td></tr></table> </td>
+		<td>Arrays of integers are stored in three parts:
+			<ul>
+				<li>an integer holding the length (in bytes, thus 4 times the number of elements) of the array, over 4 bytes;</li>
+				<li>the sequence of integers in the array, each integer on 4 bytes as described earlier;</li>
+				<li>the same integer with the length of the array repeated</li>
+			</ul>
+		</td>
+	</tr>
+	<tr>
+		<td>Array of floating point values</td>
+		<td> <table class="slots"><tr><td style="width:80px;">Length</td><td style="width:80px">1</td><td style="width:80px">2</td><td style="width:80px">3</td><td style="width:80px">...</td><td style="width: 80px">Length</td></tr></table> </td>
+		<td>Arrays of floating point values are stored in three parts:
+			<ul>
+				<li>an integer holding the length (in bytes, thus 4 times the number of elements) of the array, over 4 bytes;</li>
+				<li>the sequence of floating point values in the array, each one on 4 bytes as described earlier;</li>
+				<li>the same integer with the length of the array repeated</li>
+			</ul>
+		</td>
+	</tr>
+</table>
+
+<h3>Full structure</h3>
+<p>The header of a Selafin file holds the following elements in that exact order:
+<ul>
+	<li>a <em>string</em> of 80 characters with the title of the study; the last 8 characters shall be "SERAPHIN" or "SERAFIN" or "SERAFIND";</li>
+	<li>an <em>array of integers</em> of exactly 2 elements, the first one being the number of variables (attributes) <i>nVar</i>, and the second is ignored;</li>
+	<li><em><i>nVar</i> strings</em> with the names of the variables, each one with length 32;</li>
+	<li>an <em>array of integers</em> of exactly 10 elements:
+		<ul>
+			<li>the third element is the x-coordinate of the origin of the model;</li>
+			<li>the fourth element is the y-coordinate of the origin of the model;</li>
+			<li>the tenth element <i>isDate</i> indicates if the date of the model has to be read (see later);</li>
+                        <li>in addition, the second element being unused by hydraulic software at the moment, it is used by the driver to store the spatial reference system of the datasource, in the form of a single integer with the EPSG number of the projection;</li>
+		</ul></li>
+	<li>if <i>isDate</i>=1, an <em>array of integers</em> of exactly 6 elements, with the starting date of the model (year, month, day, hour, minute, second);</li>
+	<li>an <em>array of integers</em> of exactly 4 elements:
+		<ul>
+			<li>the first element is the number of elements <i>nElements</i>,
+			<li>the second element is the number of points <i>nPoints</i>,
+			<li>the third element is the number of points per element<i>nPointsPerElement</i>,
+			<li>the fourth element must be 1;</li>
+		</ul></li>
+	<li>an <em>array of integers</em> of exactly <i>nElements*nPointsPerElement</i> elements, with each successive set of <i>nPointsPerElement</i> being the list of the number of the points  (number starting with 1) constituting an element;</li>
+	<li>an <em>array of integers</em> of exactly <i>nPoints</i> elements ignored by the driver (the elements shall be 0 for inner points and another value for the border points where a limit condition is applied);</li>
+	<li>an <em>array of floating point values</em> of exactly <i>nPoints</i> elements with the x-coordinates of the points;</li>
+	<li>an <em>array of floating point values</em> of exactly <i>nPoints</i> elements with the y-coordinates of the points;</li>
+</ul></p>
+
+<p>The rest of the file actually holds the data for each successive time step. A time step contains the following elements:
+<ul>
+	<li>a <em>array of floating point values</em> of exactly 1 element, being the date of the time step relative to the starting date of the simulation (usually in seconds);</li>
+	<li><em><i>nVar</i> array of floating point values</em>, each with exactly <i>nPoints</i> elements, with the values of each attribute for each point at the current time step.</li>
+</ul></p>
+
+<h2>Mapping between file and layers</h2>
+
+<h3>Layers in a Selafin datasource</h3>
+<p>The Selafin driver accepts only Selafin files as data sources.</p>
+
+<p>Each Selafin file can hold one or several time steps. All the time steps are read by the driver and two layers are generated for each time step:
+<ul>
+	<li>one layer with the nodes (points) and their attributes: its name is the base name of the data source, followed by "_p" (for Points);</li>
+	<li>one layer with the elements (polygons) and their attributes calculated as the averages of the values of the attributes of their vertices: its name is the base name of the data source, followed by "_e" (for Elements).</li>
+</ul></p>
+
+<p>Finally, either the number of the time step, or the calculated date of the time step (based on the starting date and the number of seconds elapsed), is added to the name. A data source in a file called Results may therefore be read as several layers:
+<ul>
+	<li><tt>Results_p2014_05_01_20_00_00</tt>, meaning that the layers holds the attributes for the nodes and that the results hold for the time step at 8:00 PM, on May 1st, 2014;</li>
+	<li><tt>Results_e2014_05_01_20_00_00</tt>, meaning that the layers holds the attributes for the elements and that the results hold for the time step at 8:00 PM, on May 1st, 2014;</li>
+	<li><tt>Results_p2014_05_01_20_15_00</tt>, meaning that the layers holds the attributes for the elements and that the results hold for the time step at 8:15 PM, on May 1st, 2014;</li>
+	<li>...</li>
+</ul>
+</p>
+
+<h3>Constraints on layers</h3>
+<p>Because of the <a href="#format">format of the Selafin file</a>, the layers in a single Selafin datasource are not independent from each other. Changing one layer will most certainly have side effects on all other layers. The driver updates all the layers to match the constraints:
+<ul>
+	<li>All the point layers have the same number of features. When a feature is added or removed in one layer, it is also added or removed in all other layers.</li>
+	<li>Features in different point layers share the same geometry. When the position of one point is changed, it is also changed in all other layers.</li>
+	<li>All the element layers have the same number of features. When a feature is added or removed in one layer, it is also added or removed in all other layers.</li>
+	<li>All the polygons in element layers have the same number of vertices. The number of vertices is fixed when the first feature is added to an element layer, and can not be changed afterwards without recreating the datasource from scratch.</li>
+	<li>Features in different element layers share the same geometry. When an element is added or removed in one layer, it is also added or removed in all other layers.</li>
+	<li>Every vertex of every feature in an element layer has a corresponding point feature in the point layers. When an element feature is added, if its vertices do not exist yet, they are created in the point layers.</li>
+	<li>Points and elements layers only support attributes of type "REAL". The format of real numbers (width and precision) can not be changed.</li>
+</ul></p>
+
+<h2>Layer filtering specification</h2>
+<p>As a single Selafin files may hold millions of layers, and the user is generally interested in only a few of them, the driver supports syntactic sugar to filter the layers before they are read.</p>
+
+<p>When the datasource is specified, it may be followed immediatly by a <em>layer filtering specification.</em>, as in <tt>Results[0:10]</tt>. The effects of the layer filtering specification is to indicate which time steps shall be loaded from all Selafin files.</p>
+
+<p>The layer filtering specification is a comma-separated sequence of range specifications, delimited by square brackets and maybe preceded by the character 'e' or 'p'. The effect of characters 'e' and 'p' is to select respectively either only elements or only nodes. If no character is added, both nodes and elements are selected.
+Each range specification is:
+<ul>
+	<li>either a single number, representing one single time step (whose numbers start with 0),</li>
+	<li>or a set of two numbers separated by a colon: in that case, all the time steps between and including those two numbers are selected; if the first number is missing, the range starts from the beginning of the file (first time step); if the second number is missing, the range goes to the end of the file (last time step);</li>
+</ul>
+Numbers can also be negative. In this case, they are counted from the end of the file, -1 being the last time step.</p>
+
+<p>Some examples of layer filtering specifications:
+<table id="tablesexamples">
+<tr><td style="font-family:courier">[0]</td><td>First time step only, but return both points and elements</td></tr>
+<tr><td style="font-family:courier">[e:9]</td><td>First 10 time steps only, and only layers with elements</td></tr>
+<tr><td style="font-family:courier">[p-4:]</td><td>Last 4 time steps only, and only layers with nodes</td></tr>
+<tr><td style="font-family:courier">[3,10,-2:-1]</td><td>4<sup>th</sup>, 11<sup>th</sup>, and last two time steps, for both nodes and elements</td></tr>
+</table></p>
+
+<h2><a id="DCO">Datasource creation options</a></h2>
+<p>Datasource creation options can be specified with the "<tt>-dsco</tt>" flag in ogr2ogr.</p>
+<dl>
+	<dt>TITLE</dt>
+	<dd>Title of the datasource, stored in the Selafin file. The title must not hold more than 72 characters. If it is longer, it will be truncated to fit in the file.</dd>
+	<dt>DATE</dt>
+	<dd>Starting date of the simulation. Each layer in a Selafin file is characterized by a date, counted in seconds since a reference date. This option allows to provide the reference date. The format of this field must be YYYY-MM-DD_hh:mm:ss. The format does not mention the time zone.</dd>
+</dl>
+
+<p>An example of datasource creation option is: <tt>-dsco TITLE="My simulation" -dsco DATE=2014-05-01_10:00:00</tt>.
+
+<h2>Layer creation options</h2>
+<p>Layer creation options can be specified with the "<tt>-lco</tt>" flag in ogr2ogr.</p>
+<dl>
+	<dt>DATE</dt>
+	<dd>Date of the time step relative to the starting date of the simulation (see <a href="#DCO">Datasource creation options</a>). This is a single floating-point value giving the number of seconds since the starting date.</dd>
+</dl>
+
+<p>An example of datasource creation option is: <tt>-lco DATE=24000</tt>. 
+
+<h2>Notes about the creation and the update of a Selafin datasource</h2>
+<p>The driver supports creating and writing to Selafin datasources, but there are some caveats when doing so.</p>
+
+<p>When a new datasource is created, it does not contain any layer, feature or attribute.</p>
+
+<p>When a new layer is created, it automatically inherits the same number of features and attributes as the other layers of the same type (points or elements) already in the datasource. The features inherit the same geometry as their corresponding ones in other layers. The attributes are set to 0. If there was no layer in the datasource yet, the new layer is created with no feature and attribute.In any case, when a new layer is created, two layers are actually added: one for points and o [...]
+
+<p>New features and attributes can be added to the layers or removed. The behaviour depends on the type of layer (points or elements). The following table explains the behaviour of the driver in the different cases.</p>
+
+<table id="tableoperations">
+	<thead><tr><th>Operation</th><th>Points layers</th><th>Element layers</th></tr></thead>
+	<tbody>
+		<tr>
+			<td>Change the geometry of a feature</td>
+			<td>The coordinates of the point are changed in the current layer and all other layers in the datasource.</td>
+			<td>The coordinates of all the vertices of the element are changed in the current layer and all other layers in the datasource. It is not possible to change the number of vertices. The order of the vertices matters.</td>
+		</tr>
+		<tr>
+			<td>Change the attributes of a feature</td>
+			<td>The attributes of the point are changed in the current layer only.</td>
+			<td>No effect.</td>
+		</tr>
+		<tr>
+			<td>Add a new feature</td>
+			<td>A new point is added at the end of the list of features, for this layer and all other layers. Its attributes are set to the values of the new feature.</td>
+			<td>The operation is only allowed if the new feature has the same number of vertices as the other features in the layer. The vertices are checked to see if they currently exist in the set of points. A vertex is considered equal to a point if its distance is less than some maximum distance, approximately equal to 1/1000<sup>th</sup> of the average distance between two points in the points layers. When a corresponding point is found, it is used as a vertex for the element. If no point i [...]
+		</tr>
+		<tr>
+			<td>Delete a feature</td>
+			<td>The point is removed from the current layer and all point layers in the datasource. All elements using this point as a vertex are also removed from all element layers in the datasource.</td>
+			<td>The element is removed from the current layer and all element layers in the datasource.</td>
+		</tr>
+	</tbody>
+</table>
+
+<p>Typically, this implementation of operations is exactly what you'll expect. For example, ogr2ogr can be used to reproject the file without changing the inner link between points and elements.</p>
+
+<p>It should be noted that update operations on Selafin datasources are very slow. This is because the format does no allow for quick insertions or deletion of features and the file must be recreated for each operation.</p>
+
+<h2>VSI Virtual File System API support</h2>
+
+<p>The driver supports reading and writing to files managed by VSI Virtual File System API, which include "regular" files, as well as files in the /vsizip/ (read-write) , /vsigzip/ (read-only) , /vsicurl/ (read-only) domains.</p> 
+
+<h2>Other notes</h2>
+<p>There is no SRS specification in the Selafin standard. The implementation of SRS is an addition of the driver and stores the SRS in an unused data field in the file. Future software using the Selafin standard may use this field and break the SRS specification. In this case, Selafin files will still be readable by the driver, but their writing will overwrite a value which may have another purpose.</p>
+
+</body>
+</html>
diff --git a/ogr/ogrsf_frmts/selafin/io_selafin.cpp b/ogr/ogrsf_frmts/selafin/io_selafin.cpp
new file mode 100644
index 0000000..33bd190
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/io_selafin.cpp
@@ -0,0 +1,666 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Implementation of functions for reading records in Selafin files
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "io_selafin.h"
+#include "cpl_vsi.h"
+#include "cpl_conv.h"
+#include "cpl_port.h"
+#include "cpl_error.h"
+#include "cpl_quad_tree.h"
+
+namespace Selafin {
+
+    const char SELAFIN_ERROR_MESSAGE[]="Error when reading Selafin file\n";
+
+    struct Point {
+        long nIndex;
+        const Header *poHeader;
+    };
+
+    void GetBoundsFunc(const void *hFeature,CPLRectObj *poBounds) {
+        const Point *poPoint=(const Point*)hFeature;
+        poBounds->minx=poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
+        poBounds->maxx=poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
+        poBounds->miny=poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
+        poBounds->maxy=poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
+    }
+
+    int DumpFeatures(void *pElt,
+                     CPL_UNUSED void *pUserData) {
+        Point *poPoint=(Point*)pElt;
+        delete poPoint;
+        return TRUE;
+    }
+
+
+    /****************************************************************/
+    /*                         Header                               */
+    /****************************************************************/
+    Header::Header():nMinxIndex(-1),nMaxxIndex(-1),nMinyIndex(-1),nMaxyIndex(-1),bTreeUpdateNeeded(true),fp(0),pszFilename(0),pszTitle(0),papszVariables(0),nPointsPerElement(0),panConnectivity(0),poTree(0),panBorder(0),panStartDate(0),nEpsg(0) {
+        paadfCoords[0]=0;
+        paadfCoords[1]=0;
+        for (size_t i=0;i<7;++i) anUnused[i]=0;
+    } 
+
+    Header::~Header() {
+        if (pszFilename!=0) CPLFree(pszFilename);
+        if (pszTitle!=0) CPLFree(pszTitle);
+        if (papszVariables!=0) {
+            for (int i=0;i<nVar;++i) if (papszVariables[i]!=0) CPLFree(papszVariables[i]);
+            CPLFree(papszVariables);
+        }
+        if (panConnectivity!=0) CPLFree(panConnectivity);
+        if (panBorder!=0) CPLFree(panBorder);
+        if (poTree!=0) {
+            CPLQuadTreeForeach(poTree,DumpFeatures,0);
+            CPLQuadTreeDestroy(poTree);
+        }
+        if (panStartDate!=0) CPLFree(panStartDate);
+        for (size_t i=0;i<2;++i) if (paadfCoords[i]!=0) CPLFree(paadfCoords[i]);
+        if (fp!=0) VSIFCloseL(fp);
+    }
+
+    void Header::setUpdated() {
+        nHeaderSize=88+16+nVar*40+12*4+((panStartDate==0)?0:32)+24+(nElements*nPointsPerElement+2)*4+(nPoints+2)*12;
+        nStepSize=12+nVar*(nPoints+2)*4;
+    }
+
+    long Header::getPosition(long nStep,long nFeature,long nAttribute) const {
+        long a=(nFeature!=-1 || nAttribute!=-1)?(12+nAttribute*(nPoints+2)*4+4+nFeature*4):0;
+        long b=nStep*nStepSize;
+        return nHeaderSize+b+a;
+    }
+
+    CPLRectObj *Header::getBoundingBox() const {
+        CPLRectObj *poBox=new CPLRectObj;
+        poBox->minx=paadfCoords[0][nMinxIndex];
+        poBox->maxx=paadfCoords[0][nMaxxIndex];
+        poBox->miny=paadfCoords[1][nMinyIndex];
+        poBox->maxy=paadfCoords[1][nMaxyIndex];
+        return poBox;
+    }
+
+    void Header::updateBoundingBox() {
+        if (nPoints>0) {
+            nMinxIndex=0;
+            for (long i=1;i<nPoints;++i) if (paadfCoords[0][i]<paadfCoords[0][nMinxIndex]) nMinxIndex=i;
+            nMaxxIndex=0;
+            for (long i=1;i<nPoints;++i) if (paadfCoords[0][i]>paadfCoords[0][nMaxxIndex]) nMaxxIndex=i;
+            nMinyIndex=0;
+            for (long i=1;i<nPoints;++i) if (paadfCoords[1][i]<paadfCoords[1][nMinyIndex]) nMinyIndex=i;
+            nMaxyIndex=0;
+            for (long i=1;i<nPoints;++i) if (paadfCoords[1][i]>paadfCoords[1][nMaxyIndex]) nMaxyIndex=i;
+        }
+    }
+
+    long Header::getClosestPoint(const double &dfx,const double &dfy,const double &dfMax) {
+        // If there is no quad-tree of the points, build it now
+        if (bTreeUpdateNeeded) {
+            if (poTree!=0) {
+                CPLQuadTreeForeach(poTree,DumpFeatures,0);
+                CPLQuadTreeDestroy(poTree);
+            }
+        }
+        if (bTreeUpdateNeeded || poTree==0) {
+            bTreeUpdateNeeded=false;
+            CPLRectObj *poBB=getBoundingBox();
+            poTree=CPLQuadTreeCreate(poBB,GetBoundsFunc);
+            delete poBB;
+            CPLQuadTreeSetBucketCapacity(poTree,2);
+            for (long i=0;i<nPoints;++i) {
+                Point *poPoint=new Point;
+                poPoint->poHeader=this;
+                poPoint->nIndex=i;
+                CPLQuadTreeInsert(poTree,(void*)poPoint);
+            }
+        }
+        // Now we can look for the nearest neighbour using this tree
+        long nIndex=-1;
+        double dfMin;
+        CPLRectObj poObj;
+        poObj.minx=dfx-dfMax;
+        poObj.maxx=dfx+dfMax;
+        poObj.miny=dfy-dfMax;
+        poObj.maxy=dfy+dfMax;
+        int nFeatureCount;
+        void **phResults=CPLQuadTreeSearch(poTree,&poObj,&nFeatureCount);
+        if (nFeatureCount<=0) return -1;
+        double dfa,dfb,dfc;
+        dfMin=dfMax*dfMax;
+        for (long i=0;i<nFeatureCount;++i) {
+            Point *poPoint=(Point*)(phResults[i]);
+            dfa=dfx-poPoint->poHeader->paadfCoords[0][poPoint->nIndex];
+            dfa*=dfa;
+            if (dfa>=dfMin) continue;
+            dfb=dfy-poPoint->poHeader->paadfCoords[1][poPoint->nIndex];
+            dfc=dfa+dfb*dfb;
+            if (dfc<dfMin) {
+                dfMin=dfc;
+                nIndex=poPoint->nIndex;
+            }
+        }
+        CPLFree(phResults);
+        return nIndex;
+    }
+
+    void Header::addPoint(const double &dfx,const double &dfy) {
+        // We add the point to all the tables
+        nPoints++;
+        for (size_t i=0;i<2;++i) paadfCoords[i]=(double*)CPLRealloc(paadfCoords[i],sizeof(double)*nPoints);
+        paadfCoords[0][nPoints-1]=dfx;
+        paadfCoords[1][nPoints-1]=dfy;
+        panBorder=(long*)CPLRealloc(panBorder,sizeof(long)*nPoints);
+        panBorder[nPoints-1]=0;
+        // We update the bounding box
+        if (nMinxIndex==-1 || dfx<paadfCoords[0][nMinxIndex]) nMinxIndex=nPoints-1;
+        if (nMaxxIndex==-1 || dfx>paadfCoords[0][nMaxxIndex]) nMaxxIndex=nPoints-1;
+        if (nMinyIndex==-1 || dfy<paadfCoords[1][nMinyIndex]) nMinyIndex=nPoints-1;
+        if (nMaxyIndex==-1 || dfy>paadfCoords[1][nMaxyIndex]) nMaxyIndex=nPoints-1;
+        // We update some parameters of the header
+        bTreeUpdateNeeded=true;
+        setUpdated();
+    }
+
+    void Header::removePoint(long nIndex) {
+        // We remove the point from all the tables
+        nPoints--;
+        for (size_t i=0;i<2;++i) {
+            for (long j=nIndex;j<nPoints;++j) paadfCoords[i][j]=paadfCoords[i][j+1];
+            paadfCoords[i]=(double*)CPLRealloc(paadfCoords[i],sizeof(double)*nPoints);
+        }
+        for (long j=nIndex;j<nPoints;++j) panBorder[j]=panBorder[j+1];
+        panBorder=(long*)CPLRealloc(panBorder,sizeof(long)*nPoints);
+
+        // We must also remove all the elements referencing the deleted feature, otherwise the file will not be consistent any longer
+        long nOldElements=nElements;
+        for (long i=0;i<nElements;++i) {
+            bool bReferencing=false;
+            long *panTemp=panConnectivity+i*nPointsPerElement;
+            for (long j=0;j<nPointsPerElement;++j) bReferencing |= (panTemp[j]==nIndex+1);
+            if (bReferencing) {
+                nElements--;
+                for (long j=i;j<nElements;++j) 
+                    for (long k=0;k<nPointsPerElement;++k) panConnectivity[j*nPointsPerElement+k]=panConnectivity[(j+1)*nPointsPerElement+k];
+                --i;
+            }
+        }
+        if (nOldElements!=nElements) panConnectivity=(long*)CPLRealloc(panConnectivity,sizeof(long)*nElements*nPointsPerElement);
+
+        // Now we update the bounding box if needed
+        if (nPoints==0) {nMinxIndex=-1;nMaxxIndex=-1;nMinyIndex=-1;nMaxyIndex=-1;} else {
+            if (nIndex==nMinxIndex) {
+                nMinxIndex=0;
+                for (long i=1;i<nPoints;++i) if (paadfCoords[0][i]<paadfCoords[0][nMinxIndex]) nMinxIndex=i;
+            }
+            if (nIndex==nMaxxIndex) {
+                nMaxxIndex=0;
+                for (long i=1;i<nPoints;++i) if (paadfCoords[0][i]>paadfCoords[0][nMaxxIndex]) nMaxxIndex=i;
+            }
+            if (nIndex==nMinyIndex) {
+                nMinyIndex=0;
+                for (long i=1;i<nPoints;++i) if (paadfCoords[1][i]<paadfCoords[1][nMinyIndex]) nMinyIndex=i;
+            }
+            if (nIndex==nMaxyIndex) {
+                nMaxyIndex=0;
+                for (long i=1;i<nPoints;++i) if (paadfCoords[1][i]>paadfCoords[1][nMaxyIndex]) nMaxyIndex=i;
+            }
+        }
+
+        // We update some parameters of the header
+        bTreeUpdateNeeded=true;
+        setUpdated();
+    }
+
+#ifdef notdef
+    /****************************************************************/
+    /*                         TimeStep                             */
+    /****************************************************************/
+    TimeStep::TimeStep(long nRecordsP,long nFieldsP):nFields(nFieldsP) {
+        papadfData=(double**)VSIMalloc2(sizeof(double*),nFieldsP);
+        for (long i=0;i<nFieldsP;++i) papadfData[i]=(double*)VSIMalloc2(sizeof(double),nRecordsP);
+    }
+    
+    TimeStep::~TimeStep() {
+        for (long i=0;i<nFields;++i) CPLFree(papadfData[i]);
+        CPLFree(papadfData);
+    }
+
+    /****************************************************************/
+    /*                       TimeStepList                           */
+    /****************************************************************/
+    TimeStepList::~TimeStepList() {
+        TimeStepList *poFirst=this;
+        TimeStepList *poTmp;
+        while (poFirst!=0) {
+            poTmp=poFirst->poNext;
+            delete poFirst->poStep;
+            delete poFirst;
+            poFirst=poTmp;
+        }
+    }
+#endif
+
+    /****************************************************************/
+    /*                     General functions                        */
+    /****************************************************************/
+    int read_integer(VSILFILE *fp,long &nData,bool bDiscard) {
+        unsigned char anb[4];
+        if (VSIFReadL(anb,1,4,fp)<4) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        };
+        if (!bDiscard) {
+            nData=0;
+            for (size_t i=0;i<4;++i) nData=(nData*0x100)+anb[i];
+        }
+        return 1;
+    }
+
+    int write_integer(VSILFILE *fp,long nData) {
+        unsigned char anb[4];
+        for (int i=3;i>=0;--i) {
+            anb[i]=nData%0x100;
+            nData/=0x100;
+        }
+        if (VSIFWriteL(anb,1,4,fp)<4) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        };
+        return 1;
+    }
+    
+    long read_string(VSILFILE *fp,char *&pszData,bool bDiscard) {
+        long nLength=0;
+        read_integer(fp,nLength);
+        if (nLength<=0 || nLength+1<=0) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        }
+        if (bDiscard) {
+            if (VSIFSeekL(fp,nLength+4,SEEK_CUR)!=0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return 0;
+            }
+        }
+        else {
+            pszData=(char*)CPLMalloc(sizeof(char)*(nLength+1));
+            if ((long)VSIFReadL(pszData,1,nLength,fp)<(long)nLength) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return 0;
+            }
+            pszData[nLength]=0;
+            if (VSIFSeekL(fp,4,SEEK_CUR)!=0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return 0;
+            }
+        }
+        return nLength;
+    }
+
+    int write_string(VSILFILE *fp,char *pszData,size_t nLength) {
+        if (nLength==0) nLength=strlen(pszData);
+        if (write_integer(fp,nLength)==0) return 0;
+        if (VSIFWriteL(pszData,1,nLength,fp)<nLength) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        }
+        if (write_integer(fp,nLength)==0) return 0;
+        return 1;
+    }
+
+    long read_intarray(VSILFILE *fp,long *&panData,bool bDiscard) {
+        long nLength=0;
+        read_integer(fp,nLength);
+        if (nLength<0 || nLength+1<=0) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return -1;
+        }
+        if (bDiscard) {
+            if (VSIFSeekL(fp,nLength+4,SEEK_CUR)!=0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+        }
+        else {
+            if (nLength==0) panData=0; else {
+                panData=(long *)VSIMalloc2(nLength/4,sizeof(long));
+                if (panData==0) return -1;
+            }
+            for (long i=0;i<nLength/4;++i) if (read_integer(fp,panData[i])==0) {
+                CPLFree(panData);
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+            if (VSIFSeekL(fp,4,SEEK_CUR)!=0) {
+                if (panData!=0) CPLFree(panData);
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+        }
+        return nLength/4;
+    }
+
+    int write_intarray(VSILFILE *fp,long *panData,size_t nLength) {
+        if (write_integer(fp,nLength*4)==0) return 0;
+        for (size_t i=0;i<nLength;++i) {
+            if (write_integer(fp,panData[i])==0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return 0;
+            }
+        }
+        if (write_integer(fp,nLength*4)==0) return 0;
+        return 1;
+    }
+
+    int read_float(VSILFILE *fp,double &dfData,bool bDiscard) {
+        float dfVal;
+        if (VSIFReadL(&dfVal,1,4,fp)<4) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        };
+        if (!bDiscard) {
+            CPL_MSBPTR32(&dfVal);
+            dfData=dfVal;
+        }
+        return 1;
+    }
+
+    int write_float(VSILFILE *fp,double dfData) {
+        float dfVal=(float)dfData;
+        CPL_MSBPTR32(&dfVal);
+        if (VSIFWriteL(&dfVal,1,4,fp)<4) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return 0;
+        };
+        return 1;
+    }
+
+    long read_floatarray(VSILFILE *fp,double **papadfData,bool bDiscard) {
+        long nLength=0;
+        read_integer(fp,nLength);
+        if (nLength<0 || nLength+1<=0) {
+            CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+            return -1;
+        }
+        if (bDiscard) {
+            if (VSIFSeekL(fp,nLength+4,SEEK_CUR)!=0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+        }
+        else {
+            if (nLength==0) *papadfData=0; else {
+                *papadfData=(double*)VSIMalloc2(sizeof(double),nLength/4);
+                if (papadfData==0) return -1;
+            }
+            for (long i=0;i<nLength/4;++i) if (read_float(fp,(*papadfData)[i])==0) {
+                CPLFree(*papadfData);
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+            if (VSIFSeekL(fp,4,SEEK_CUR)!=0) {
+                if (*papadfData!=0) CPLFree(*papadfData);
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return -1;
+            }
+        }
+        return nLength/4;
+    }
+
+    int write_floatarray(VSILFILE *fp,double *papadfData,size_t nLength) {
+        if (write_integer(fp,nLength*4)==0) return 0;
+        for (size_t i=0;i<nLength;++i) {
+            if (write_float(fp,papadfData[i])==0) {
+                CPLError(CE_Failure,CPLE_FileIO,"%s",SELAFIN_ERROR_MESSAGE);
+                return 0;
+            }
+        }
+        if (write_integer(fp,nLength*4)==0) return 0;
+        return 1;
+    }
+
+    Header *read_header(VSILFILE *fp,const char *pszFilename) {
+        // Get the total file size (used later to estimate the number of time steps)
+        long nFileSize;
+        VSIFSeekL(fp,0,SEEK_END);
+        nFileSize=(long)VSIFTellL(fp);
+        VSIRewindL(fp);
+        // Save the filename
+        long nLength;
+        Header *poHeader=new Header();
+        poHeader->fp=fp;
+        poHeader->pszFilename=CPLStrdup(pszFilename);
+        long *panTemp;
+        // Read the title
+        nLength=read_string(fp,poHeader->pszTitle);
+        if (nLength==0) {
+            delete poHeader;
+            return 0;
+        }
+        // Read the array of 2 integers, with the number of variables at the first position
+        nLength=read_intarray(fp,panTemp);
+        if (nLength!=2) {
+            delete poHeader;
+            CPLFree(panTemp);
+            return 0;
+        }
+        poHeader->nVar=panTemp[0];
+        poHeader->anUnused[0]=panTemp[1];
+        CPLFree(panTemp);
+        if (poHeader->nVar<0) {
+            delete poHeader;
+            return 0;
+        }
+        // For each variable, read its name as a string of 32 characters
+        poHeader->papszVariables=(char**)VSIMalloc2(sizeof(char*),poHeader->nVar);
+        for (long i=0;i<poHeader->nVar;++i) {
+            nLength=read_string(fp,poHeader->papszVariables[i]);
+            if (nLength==0) {
+                delete poHeader;
+                return 0;
+            }
+            // We eliminate quotes in the names of the variables because SQL requests don't seem to appreciate them
+            char *pszc=poHeader->papszVariables[i];
+            while (*pszc!=0) {
+                if (*pszc=='\'') *pszc=' ';
+                pszc++;
+            }
+        }
+        // Read an array of 10 integers
+        nLength=read_intarray(fp,panTemp);
+        if (nLength<10) {
+            delete poHeader;
+            CPLFree(panTemp);
+            return 0;
+        }
+        poHeader->anUnused[1]=panTemp[0];
+        poHeader->nEpsg=panTemp[1];
+        poHeader->adfOrigin[0]=panTemp[2];
+        poHeader->adfOrigin[1]=panTemp[3];
+        for (size_t i=4;i<9;++i) poHeader->anUnused[i-2]=panTemp[i];
+        // If the last integer was 1, read an array of 6 integers with the starting date
+        if (panTemp[9]==1) {
+            nLength=read_intarray(fp,poHeader->panStartDate);
+            if (nLength<6) {
+                delete poHeader;
+                CPLFree(panTemp);
+                return 0;
+            }
+        }
+        CPLFree(panTemp);
+        // Read an array of 4 integers with the number of elements, points and points per element
+        nLength=read_intarray(fp,panTemp);
+        if (nLength<4) {
+            delete poHeader;
+            CPLFree(panTemp);
+            return 0;
+        }
+        poHeader->nElements=panTemp[0];
+        poHeader->nPoints=panTemp[1];
+        poHeader->nPointsPerElement=panTemp[2];
+        if (poHeader->nElements<0 || poHeader->nPoints<0 || poHeader->nPointsPerElement<0 || panTemp[3]!=1) {
+            delete poHeader;
+            CPLFree(panTemp);
+            return 0;
+        }
+        CPLFree(panTemp);
+        // Read the connectivity table as an array of nPointsPerElement*nElements integers, and check if all point numbers are valid
+        nLength=read_intarray(fp,poHeader->panConnectivity);
+        if (nLength!=poHeader->nElements*poHeader->nPointsPerElement) {
+            delete poHeader;
+            return 0;
+        }
+        for (long i=0;i<poHeader->nElements*poHeader->nPointsPerElement;++i) {
+            if (poHeader->panConnectivity[i]<=0 || poHeader->panConnectivity[i]>poHeader->nPoints) {
+                delete poHeader;
+                return 0;
+            }
+        }
+        // Read the array of nPoints integers with the border points
+        nLength=read_intarray(fp,poHeader->panBorder);
+        if (nLength!=poHeader->nPoints) {
+            delete poHeader;
+            return 0;
+        }
+        // Read two arrays of nPoints floats with the coordinates of each point
+        for (size_t i=0;i<2;++i) {
+            read_floatarray(fp,poHeader->paadfCoords+i);
+            if (nLength<poHeader->nPoints) {
+                delete poHeader;
+                return 0;
+            }
+            for (long j=0;j<poHeader->nPoints;++j) poHeader->paadfCoords[i][j]+=poHeader->adfOrigin[i];
+        }
+        // Update the boundinx box
+        poHeader->updateBoundingBox();
+        // Update the size of the header and calculate the number of time steps
+        poHeader->setUpdated();
+        long nPos=poHeader->getPosition(0);
+        poHeader->nSteps=(nFileSize-nPos)/(poHeader->getPosition(1)-nPos);
+        return poHeader;
+    }
+
+    int write_header(VSILFILE *fp,Header *poHeader) {
+        VSIRewindL(fp);
+        if (write_string(fp,poHeader->pszTitle,80)==0) return 0;
+        long anTemp[10]={0};
+        anTemp[0]=poHeader->nVar;
+        anTemp[1]=poHeader->anUnused[0];
+        if (write_intarray(fp,anTemp,2)==0) return 0;
+        for (long i=0;i<poHeader->nVar;++i) if (write_string(fp,poHeader->papszVariables[i],32)==0) return 0;
+        anTemp[0]=poHeader->anUnused[1];
+        anTemp[1]=poHeader->nEpsg;
+        anTemp[2]=(long)poHeader->adfOrigin[0];
+        anTemp[3]=(long)poHeader->adfOrigin[1];
+        for (size_t i=4;i<9;++i) anTemp[i]=poHeader->anUnused[i-2];
+        anTemp[9]=(poHeader->panStartDate!=0)?1:0;
+        if (write_intarray(fp,anTemp,10)==0) return 0;
+        if (poHeader->panStartDate!=0 && write_intarray(fp,poHeader->panStartDate,6)==0) return 0;
+        anTemp[0]=poHeader->nElements;
+        anTemp[1]=poHeader->nPoints;
+        anTemp[2]=poHeader->nPointsPerElement;
+        anTemp[3]=1;
+        if (write_intarray(fp,anTemp,4)==0) return 0;
+        if (write_intarray(fp,poHeader->panConnectivity,poHeader->nElements*poHeader->nPointsPerElement)==0) return 0;
+        if (write_intarray(fp,poHeader->panBorder,poHeader->nPoints)==0) return 0;
+        double *dfVals;
+        dfVals=(double*)VSIMalloc2(sizeof(double),poHeader->nPoints);
+        if (poHeader->nPoints>0 && dfVals==0) return 0;
+        for (size_t i=0;i<2;++i) {
+            for (long j=0;j<poHeader->nPoints;++j) dfVals[j]=poHeader->paadfCoords[i][j]-poHeader->adfOrigin[i];
+            if (write_floatarray(fp,dfVals,poHeader->nPoints)==0) {
+                CPLFree(dfVals);
+                return 0;
+            }
+        }
+        CPLFree(dfVals);
+        return 1;
+    }
+
+#ifdef notdef
+    int read_step(VSILFILE *fp,const Header *poHeader,TimeStep *&poStep) {
+        poStep=new TimeStep(poHeader->nPoints,poHeader->nVar);
+        long nLength;
+        if (read_integer(fp,nLength)==0 || nLength!=1) {
+            delete poStep;
+            return 0;
+        }
+        if (read_float(fp,poStep->dfDate)==0) {
+            delete poStep;
+            return 0;
+        }
+        if (read_integer(fp,nLength)==0 || nLength!=1) {
+            delete poStep;
+            return 0;
+        }
+        for (long i=0;i<poHeader->nVar;++i) {
+            nLength=read_floatarray(fp,&(poStep->papadfData[i]));
+            if (nLength!=poHeader->nPoints) {
+                delete poStep;
+                return 0;
+            }
+        }
+        return 1;
+    }
+
+    
+    int write_step(VSILFILE *fp,const Header *poHeader,const TimeStep *poStep) {
+        if (write_integer(fp,1)==0) return 0;
+        if (write_float(fp,poStep->dfDate)==0) return 0;
+        if (write_integer(fp,1)==0) return 0;
+        for (long i=0;i<poHeader->nVar;++i) {
+            if (write_floatarray(fp,poStep->papadfData[i])==0) return 0;
+        }
+        return 1;
+    }
+
+    int read_steps(VSILFILE *fp,const Header *poHeader,TimeStepList *&poSteps) {
+        poSteps=0;
+        TimeStepList *poCur,*poNew;
+        for (long i=0;i<poHeader->nSteps;++i) {
+            poNew=new TimeStepList(0,0);
+            if (read_step(fp,poHeader,poNew->poStep)==0) {
+                delete poSteps;
+                return 0;
+            }
+            if (poSteps==0) poSteps=poNew; else poCur->poNext=poNew;
+            poCur=poNew;
+        }
+        return 1;
+    }
+
+    int write_steps(VSILFILE *fp,const Header *poHeader,const TimeStepList *poSteps) {
+        const TimeStepList *poCur=poSteps;
+        while (poCur!=0) {
+            if (write_step(fp,poHeader,poCur->poStep)==0) return 0;
+            poCur=poCur->poNext;
+        }
+        return 1;
+    }
+#endif
+    
+}
diff --git a/ogr/ogrsf_frmts/selafin/io_selafin.h b/ogr/ogrsf_frmts/selafin/io_selafin.h
new file mode 100644
index 0000000..d7205ed
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/io_selafin.h
@@ -0,0 +1,358 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Definition of functions for reading records in Selafin files
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+
+#ifndef  IO_SELAFIN_H_INC
+#define  IO_SELAFIN_H_INC
+
+#include "cpl_vsi.h"
+#include "cpl_quad_tree.h"
+
+namespace Selafin {
+    /**
+     * \brief Data structure holding general information about a Selafin file
+     */
+    class Header {
+        private:
+            long nHeaderSize; //!< Size (in bytes) of the header of the file (seeking to this location brings to the first "feature")
+            long nStepSize;    //!< Size (in bytes) of one feature in the file
+            long nMinxIndex;    //!< Index of the point at the western border of the bounding box
+            long nMaxxIndex;    //!< Index of the point at the eastern border of the bounding box
+            long nMinyIndex;    //!< Index of the point at the southern border of the bounding box
+            long nMaxyIndex;    //!< Index of the point at the northern border of the bounding box
+            bool bTreeUpdateNeeded;  //!< Tell if the quad tree has to be updated
+        public:
+            //size_t nRefCount;   //!< Number of references to this object
+            VSILFILE *fp;   //!< Pointer to the file with the layers
+            char *pszFilename;  //!< Name of the Selafin file
+            char *pszTitle; //!< Title of the simulation
+            long nVar;   //!< Number of variables
+            char **papszVariables;  //!< Name of the variables
+            long nPoints;    //!< Total number of points
+            long nElements;  //!< Total number of elements
+            long nPointsPerElement;  //!< Number of points per element
+            long *panConnectivity;   //!< Connectivity table of elements: first nPointsPerElement elements are the indices of the points making the first element, and so on. In the Selafin file, the first point has index 1.
+            double *paadfCoords[2]; //!< Table of coordinates of points: x then y
+            CPLQuadTree *poTree;    //!< Quad-tree for spatially indexing points in the array paadfCoords. The tree will mostly contain a Null value, until a request is made to find a closest neighbour, in which case it will be built and maintained
+            double adfOrigin[2];  //!< Table of coordinates of the origin of the axis
+            long *panBorder;    //!< Array of integers defining border points (0 for an inner point, and the index of the border point otherwise). This table is not used by the driver but stored to allow to rewrite the header if needed
+            long *panStartDate;    //!< Table with the starting date of the simulation (may be 0 if date is not defined). Date is registered as a set of six elements: year, month, day, hour, minute, second.
+            long nSteps;    //!< Number of steps in the Selafin file
+            long nEpsg; //!< EPSG of the file
+            long anUnused[7];   //!< Array of integers for storing the eight values read from the header but not actually used by the driver. These values are merely saved to rewrite them in the file if it is changed.
+
+            Header(); //!< Standard constructor
+            ~Header();  //!< Destructor of structure
+
+            /**
+             * \brief Return the position of a particular data in the Selafin file
+             *
+             * This function returns the position in the Selafin file of a particular element, characterized by the number of the time step, the index of the feature and the index of the attribute. If both nFeature and nAttribute are equal to -1 (default value), the function returns the position of the start of this time step. If nFeature is -1 but nAttribute is greater than 0, the function returns the position of the table for the given attribute (compatible with Selafin::read_floatarray)
+             * \param nStep Number of the time step, starting with 0
+             * \param nFeature Index of the feature (point), starting with 0
+             * \param nAttribute Index of the attribute, starting with 0
+             * \return Position (in bytes) from the start of the file
+             */
+            long getPosition(long nStep,long nFeature=-1,long nAttribute=-1) const; // {return nHeaderSize+nStep*nStepSize+(nFeature!=-1)?(12+nAttribute*(nPoints+2)*4+4+nFeature*4):0;}
+
+            /**
+             * \brief Return the bounding box of the points
+             *
+             * This function returns the bounding box of the set of points. The bounding box is stored in memory for quicker access.
+             * \return Pointer to the bounding box. The calling program is responsible for destroying it
+             */
+            CPLRectObj *getBoundingBox() const;
+
+            /**
+             * \brief Update the bounding box of the points
+             *
+             * This function calculates the bounding box of the set of points and stores it in the class.
+             */
+            void updateBoundingBox();
+
+            /**
+             * \brief Return the index of the point closest to the given coordinates
+             *
+             * This function searches the point in the array which is the closest to the one given by the user in arguments, but no farther than distance dfMax.
+             * \param dfx x-coordinate of the reference point
+             * \param dfy y-coordinate of the reference point
+             * \param dfMax Maximum distance allowed to the point
+             * \return Index of the closest point in the array, -1 if there was no point at all in the array closer than distance dfMax
+             */
+            long getClosestPoint(const double &dfx,const double &dfy,const double &dfMax);
+
+            /**
+             * \brief Tells that the header has been changed
+             *
+             * This function must be used whenever one of the member of the structure was changed. It forces the recalculation of some variables (header size and step size).
+             */
+            void setUpdated();
+
+            /**
+             * \brief Add a new point at the end of point list
+             *
+             * This function add a new point at the end of the array. If the arrays of coordinates are too small, they may be resized. The bounding box is updated.
+             * \param dfx x-coordinate of the new point
+             * \param dfy y-coordinate of the new point
+             */
+            void addPoint(const double &dfx,const double &dfy);
+
+            /**
+             * \brief Remove a point from the point list
+             *
+             * This function removes a point at position nIndex from the array of points. The bounding box is updated. All the elements which referenced this point are also removed.
+             * \param nIndex Index of the point which has to be removed
+             */
+            void removePoint(long nIndex);
+
+    };
+
+#ifdef notdef
+    /**
+     * \brief Data structure holding the attributes of all nodes for one time step
+     */
+    class TimeStep {
+        private:
+            //long nRecords;  //!< Number of records (first index) in the TimeStep::papadfData array, which should correspond to the number of features (either points or elements) in a Selafin layer
+            long nFields;   //!< Number of fields for each record (second index) in the TimeStep::papadfData array, which should correspond to the number of attributes in a Selafin layer
+        public:
+            double dfDate;  //!< Date of the time step (usually in seconds after the starting date)
+            double **papadfData;    //!< Double-indexed array with values of all atributes for all features. The first index is the number of the attribute, the second is the number of the feature.
+
+            /**
+             * \brief Constructor of the structure
+             *
+             * This function allocates the TimeStep::papadfData array based on the dimensions provided in argument.
+             * \param nRecords Number of records (first index) in the TimeStep::papadfData array, which should correspond to the number of features (either points or elements) in a Selafin layer
+             * \param nFields Number of fields for each record (second index) in the TimeStep::papadfData array, which should correspond to the number of attributes in a Selafin layer
+             */
+            TimeStep(long nRecordsP,long nFieldsP);
+
+            ~TimeStep();    //!< Standard destructor
+    };
+
+    /**
+     * \brief Structure holding a chained list of time steps (of class TimeStep)
+     */
+    class TimeStepList {
+        public:
+            TimeStep *poStep;   //!< Pointer to the time step structure
+            TimeStepList *poNext;   //!< Pointer to the next element in the list
+
+            TimeStepList(TimeStep *poStepP,TimeStepList *poNextP):poStep(poStepP),poNext(poNextP) {}    //!< Standard constructor
+            ~TimeStepList();    //!< Standard destructor
+    };
+#endif
+
+    /**
+     * \brief Read an integer from a Selafin file
+     *
+     * This function reads an integer from an opened file. In Selafin files, integers are stored on 4 bytes in big-endian format (most significant byte first).
+     * \param fp Pointer to an open file
+     * \param nData After the execution, contains the value read
+     * \param bDiscard If true, the function does not attempt to save the value read in the variable nData, but only advances in the file as it should. Default value is false.
+     * \return 1 if the integer was successfully read, 0 otherwise
+     */
+    int read_integer(VSILFILE *fp,long &nData,bool bDiscard=false);
+
+    /**
+     * \brief Write an integer to a Selafin file
+     *
+     * This function writes an integer to an opened file. See also Selafin::read_integer for additional information about how integers are stored in a Selafin file.
+     * \param fp Pointer to an open file
+     * \param nData Value to be written to the file
+     * \return 1 if the integer was successfully written, 0 otherwise
+     */
+    int write_integer(VSILFILE *fp,long nData);
+
+    /**
+     * \brief Read a string from a Selafin file
+     *
+     * This function reads a string from an opened file. In Selafin files, strings are stored in three parts:
+     *   - an integer \a n (therefore on 4 bytes) with the length of the string
+     *   - the \a n bytes of the string, preferably in ASCII format
+     *   - once again the integer \a n (on 4 bytes)
+     * The function does not check if the last integer is the same as the first one. 
+     * \param fp Pointer to an open file
+     * \param pszData After the execution, contains the value read. The structure is allocated by the function.
+     * \param bDiscard If true, the function does not attempt to save the value read in the variable nData, but only advances in the file as it should. Default value is false.
+     * \return Number of characters in string read
+     */
+    long read_string(VSILFILE *fp,char *&pszData,bool bDiscard=false);
+
+    /**
+     * \brief Write a string to a Selafin file
+     *
+     * This function writes a string to an opened file. See also Selafin::read_string for additional information about how strings are stored in a Selafin file.
+     * \param fp Pointer to an open file
+     * \param pszData String to be written to the file
+     * \param nLength Length of the string. If the value is 0, the length is automatically calculated. It is recommended to provide this value to avoid an additional strlen call. However, providing a value larger than the actual size of the string will result in an overflow read access and most likely in a segmentation fault.
+     * \return 1 if the string was successfully written, 0 otherwise
+     */
+    int write_string(VSILFILE *fp,char *pszData,size_t nLength=0);
+
+    /**
+     * \brief Read an array of integers from a Selafin file
+     *
+     * This function reads an array of integers from an opened file. In Selafin files, arrays of integers are stored in three parts:
+     *   - an integer \a n with the \e size of the array (therefore 4 times the number of elements)
+     *   - the \f$ \frac{n}{4} \f$ elements of the array, each on 4 bytes
+     *   - once again the integer \a n (on 4 bytes)
+     * The function does not check if the last integer is the same as the first one.
+     * \param fp Pointer to an open file
+     * \param panData After the execution, contains the array read. The structure is allocated by the function.
+     * \param bDiscard If true, the function does not attempt to save the value read in the variable nData, but only advances in the file as it should. Default value is false.
+     * \return Number of elements in array read, -1 if an error occurred
+     */
+    long read_intarray(VSILFILE *fp,long *&panData,bool bDiscard=false);
+
+    /**
+     * \brief Write an array of integers to a Selafin file
+     *
+     * This function writes an array of integers to an opened file. See also Selafin::read_intarray for additional information about how arrays of integers are stored in a Selafin file.
+     * \param fp Pointer to an open file
+     * \param panData Array to be written to the file
+     * \param nLength Number of elements in the array
+     * \return 1 if the array was successfully written, 0 otherwise
+     */
+    int write_intarray(VSILFILE *fp,long *panData,size_t nLength);
+
+    /**
+     * \brief Read a floating point number from a Selafin file
+     *
+     * This function reads a floating point value from an opened file. In Selafin files, floats are stored on 4 bytes in big-endian format (most significant byte first).
+     * \param fp Pointer to an open file
+     * \param dfData After the execution, contains the value read
+     * \param bDiscard If true, the function does not attempt to save the value read in the variable nData, but only advances in the file as it should. Default value is false.
+     * \return 1 if the floating point number was successfully read, 0 otherwise
+     */
+    int read_float(VSILFILE *fp,double &dfData,bool bDiscard=false);
+
+    /**
+     * \brief Write a floating point number to a Selafin file
+     *
+     * This function writes a floating point value from an opened file. See also Selafin::read_float for additional information about how floating point numbers are stored in a Selafin file.
+     * \param fp Pointer to an open file
+     * \param dfData Floating point number to be written to the file
+     * \return 1 if the floating point number was successfully written, 0 otherwise
+     */
+    int write_float(VSILFILE *fp,double dfData);
+
+    /**
+     * \brief Read an array of floats from a Selafin file
+     *
+     * This function reads an array of floats from an opened file. In Selafin files, arrays of floats are stored in three parts:
+     *   - an integer \a n with the \e size of the array (therefore 4 times the number of elements)
+     *   - the \f$ \frac{n}{4} \f$ elements of the array, each on 4 bytes
+     *   - once again the integer \a n (on 4 bytes)
+     * The function does not check if the last integer is the same as the first one.
+     * \param fp Pointer to an open file
+     * \param papadfData After the execution, contains the array read. The structure is allocated by the function.
+     * \param bDiscard If true, the function does not attempt to save the value read in the variable nData, but only advances in the file as it should. Default value is false.
+     * \return Number of elements in array read, -1 if an error occurred
+     */
+    long read_floatarray(VSILFILE *fp,double **papadfData,bool bDiscard=false);
+        
+    /**
+     * \brief Write an array of floats to a Selafin file
+     *
+     * This function writes an array of floats from an opened file. See also Selafin::read_floatarray for additional information about how arrays of floating point numbers are stored in a Selafin file.
+     * \param fp Pointer to an open file
+     * \param padfData Pointer to the array of floating point numbers to be written to the file
+     * \param nLength Number of elements in the array
+     * \return 1 if the array was successfully written, 0 otherwise
+     */
+    int write_floatarray(VSILFILE *fp,double *padfData,size_t nLength);
+
+    /**
+     * \brief Read the header of a Selafin file
+     *
+     * This function reads the whole header of a Selafin file (that is everything before the first time step) and stores it in a Selafin::Header structure. The file pointer is moved at the beginning of the file before reading.
+     * \param fp Pointer to an open file
+     * \param pszFilename Name of the file
+     * \return Pointer to a newly-allocated header structure, 0 if the function failed to read the whole header
+     */
+    Header *read_header(VSILFILE *fp,const char* pszFilename);
+
+    /**
+     * \brief Write the header to a file
+     *
+     * This function writes the header to an opened file. The file pointer is moved at the beginning of the file and the content is overwritten.
+     * \param fp Pointer to an open file with write access
+     * \return 1 if the header was successfully written, 0 otherwise
+     */
+    int write_header(VSILFILE *fp,Header *poHeader);
+
+#ifdef notdef
+    /**
+     * \brief Read one time step from a Selafin file
+     *
+     * This function reads a single time step, with all the field values, from an open Selafin file at the current position.
+     * \param fp Pointer to an open file
+     * \param poHeader Pointer to the header structure. This should be read before the call to the function because some of its members are used to determine the format of the time step.
+     * \param poStep After the execution, holds the data for the current step. The variable is allocated by the function
+     * \return 1 if the time step was successfully read, 0 otherwise
+     */
+    int read_step(VSILFILE *fp,const Header *poHeader,TimeStep *&poStep);
+
+    /**
+     * \brief Write one time step to a Selafin file
+     *
+     * This function writes a single time step, with all the field values, to an open Selafin file at the current position.
+     * \param fp Pointer to an open file with write access
+     * \param poHeader Pointer to the header structure. This should be read before the call to the function because some of its members are used to determine the format of the time step.
+     * \param poStep Data of current step
+     * \return 1 if the time step was successfully written, 0 otherwise
+     */
+    int write_step(VSILFILE *fp,const Header *poHeader,const TimeStep *poStep);
+
+    /**
+     * \brief Read all time steps from a Selafin file
+     *
+     * This function reads all time steps, with all the field values, from an open Selafin file at the current position.
+     * \param fp Pointer to an open file
+     * \param poHeader Pointer to the header structure. This should be read before the call to the function because some of its members are used to determine the format of the time step.
+     * \param poSteps After the execution, holds the list of time steps. The variable is allocated by the function
+     * \return 1 if the time steps were successfully read, 0 otherwise
+     */
+    int read_steps(VSILFILE *fp,const Header *poHeader,TimeStepList *&poSteps);
+
+    /**
+     * \brief Write one time step to a Selafin file
+     *
+     * This function writes a single time step, with all the field values, to an open Selafin file at the current position.
+     * \param fp Pointer to an open file with write access
+     * \param poHeader Pointer to the header structure. This should be read before the call to the function because some of its members are used to determine the format of the time step.
+     * \param poSteps List of all steps
+     * \return 1 if the time steps were successfully written, 0 otherwise
+     */
+    int write_steps(VSILFILE *fp,const Header *poHeader,const TimeStepList *poSteps);
+#endif
+
+}
+
+#endif   /* ----- #ifndef IO_SELAFIN_H_INC  ----- */
diff --git a/ogr/ogrsf_frmts/selafin/makefile.vc b/ogr/ogrsf_frmts/selafin/makefile.vc
new file mode 100644
index 0000000..d3eb50d
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/makefile.vc
@@ -0,0 +1,15 @@
+
+OBJ	=	ogrselafindriver.obj ogrselafindatasource.obj ogrselafinlayer.obj io_selafin.obj
+EXTRAFLAGS =	-I.. -I..\..
+
+GDAL_ROOT	=	..\..\..
+
+!INCLUDE $(GDAL_ROOT)\nmake.opt
+
+default:	$(OBJ)
+
+clean:
+	-del *.obj *.pdb
+
+
+
diff --git a/ogr/ogrsf_frmts/selafin/ogr_selafin.h b/ogr/ogrsf_frmts/selafin/ogr_selafin.h
new file mode 100644
index 0000000..3ccf613
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/ogr_selafin.h
@@ -0,0 +1,130 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Definition of classes for OGR driver for Selafin files.
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#ifndef _OGR_SELAFIN_H_INCLUDED
+#define _OGR_SELAFIN_H_INCLUDED
+
+#include "io_selafin.h"
+#include "ogrsf_frmts.h"
+
+class OGRSelafinDataSource;
+
+typedef enum {POINTS,ELEMENTS,ALL} SelafinTypeDef;
+
+/************************************************************************/
+/*                             Range                                    */
+/************************************************************************/
+class Range {
+    private:
+        typedef struct List {
+            SelafinTypeDef eType;
+            long nMin,nMax;
+            List *poNext;
+            List():poNext(0) {}
+            List(SelafinTypeDef eTypeP,long nMinP,long nMaxP,List *poNextP):eType(eTypeP),nMin(nMinP),nMax(nMaxP),poNext(poNextP) {}
+        } List;
+        List *poVals,*poActual;
+        long nMaxValue;
+        static void sortList(List *&poList,List *poEnd=0);
+        static void deleteList(List *poList);
+    public:
+        Range():poVals(0),poActual(0),nMaxValue(0) {}
+        void setRange(const char *pszStr);
+        ~Range();
+        void setMaxValue(long nMaxValueP);
+        bool contains(SelafinTypeDef eType,long nValue) const;
+        size_t getSize() const;
+};
+
+
+/************************************************************************/
+/*                             OGRSelafinLayer                          */
+/************************************************************************/
+
+class OGRSelafinLayer : public OGRLayer {
+    private:
+        SelafinTypeDef eType;
+        int bUpdate;
+        long nStepNumber;
+        Selafin::Header *poHeader;
+        OGRFeatureDefn *poFeatureDefn;
+        OGRSpatialReference *poSpatialRef;
+        GIntBig nCurrentId;
+    public:
+        OGRSelafinLayer( const char *pszLayerNameP, int bUpdateP,OGRSpatialReference *poSpatialRefP,Selafin::Header *poHeaderP,int nStepNumberP,SelafinTypeDef eTypeP);
+        ~OGRSelafinLayer();
+        OGRSpatialReference *GetSpatialRef() {return poSpatialRef;}
+        long GetStepNumber() {return nStepNumber;}
+        OGRFeature *GetNextFeature();
+        OGRFeature *GetFeature(GIntBig nFID);
+        void ResetReading();
+        OGRErr SetNextByIndex(GIntBig nIndex);
+        OGRFeatureDefn *GetLayerDefn() {return poFeatureDefn;}
+        int TestCapability(const char *pszCap);
+        GIntBig GetFeatureCount(int bForce=TRUE);
+        OGRErr GetExtent(OGREnvelope *psExtent,int bForce=TRUE);
+        OGRErr ISetFeature(OGRFeature *poFeature);
+        OGRErr ICreateFeature(OGRFeature *poFeature);
+        OGRErr CreateField(OGRFieldDefn *poField,int bApproxOK=TRUE);
+        OGRErr DeleteField(int iField);
+        OGRErr ReorderFields(int *panMap);
+        OGRErr AlterFieldDefn(int iField,OGRFieldDefn *poNewFieldDefn,int nFlags);
+        OGRErr DeleteFeature(GIntBig nFID);
+};
+
+/************************************************************************/
+/*                           OGRSelafinDataSource                       */
+/************************************************************************/
+
+class OGRSelafinDataSource : public OGRDataSource {
+    private:
+        char *pszName;
+        char *pszLockName;
+        OGRSelafinLayer **papoLayers;
+        Range poRange;
+        int nLayers;
+        int bUpdate;
+        Selafin::Header *poHeader;
+        CPLString osDefaultSelafinName;
+        OGRSpatialReference *poSpatialRef;
+        int TakeLock(const char *pszFilename);
+        void ReleaseLock();
+    public:
+        OGRSelafinDataSource();
+        ~OGRSelafinDataSource();
+        int Open(const char * pszFilename, int bUpdate, int bCreate);
+        int OpenTable(const char * pszFilename);
+        const char *GetName() { return pszName; }
+        int GetLayerCount() { return nLayers; }
+        OGRLayer *GetLayer( int );
+        virtual OGRLayer *ICreateLayer( const char *pszName, OGRSpatialReference *poSpatialRefP = NULL, OGRwkbGeometryType eGType = wkbUnknown, char ** papszOptions = NULL );
+        virtual OGRErr DeleteLayer(int); 
+        int TestCapability( const char * );
+        void SetDefaultSelafinName( const char *pszName ) { osDefaultSelafinName = pszName; }
+};
+
+#endif /* ndef _OGR_SELAFIN_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/selafin/ogrselafindatasource.cpp b/ogr/ogrsf_frmts/selafin/ogrselafindatasource.cpp
new file mode 100644
index 0000000..dedbcbf
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/ogrselafindatasource.cpp
@@ -0,0 +1,592 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Implementation of OGRSelafinDataSource class.
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_selafin.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "cpl_vsi_virtual.h"
+#include "cpl_vsi.h"
+#include "io_selafin.h"
+
+#include <ctime>
+
+/************************************************************************/
+/*                          Range                                       */
+/************************************************************************/
+Range::~Range() {
+    deleteList(poVals);
+    deleteList(poActual);
+}
+
+void Range::deleteList(Range::List *poList) {
+    if (poList==0) return;
+    Range::List *pol=poList;
+    while (pol!=0) {
+        poList=poList->poNext;
+        delete pol;
+        pol=poList;
+    }
+}
+
+void Range::setRange(const char *pszStr) {
+    deleteList(poVals);
+    deleteList(poActual);
+    poVals=0;
+    Range::List *poEnd=0;
+    if (pszStr==NULL || pszStr[0]!='[') {
+        CPLError( CE_Warning, CPLE_IllegalArg, "Invalid range specified\n");
+        return;
+    }
+    const char *pszc=pszStr;
+    char *psze;
+    long nMin,nMax;
+    SelafinTypeDef eType;
+    while (*pszc!=0 && *pszc!=']') {
+        pszc++;
+        if (*pszc=='p' || *pszc=='P') {
+            eType=POINTS;
+            pszc++;
+        } else if (*pszc=='e' || *pszc=='E') {
+            eType=ELEMENTS;
+            pszc++;
+        } else eType=ALL;
+        if (*pszc==':') {
+            nMin=0;
+        } else {
+            nMin=strtol(pszc,&psze,10);
+            if (*psze!=':' && *psze!=',' && *psze!=']') {
+                CPLError( CE_Warning, CPLE_IllegalArg, "Invalid range specified\n");
+                deleteList(poVals);
+                poVals=0;
+                return;
+            }
+            pszc=psze;
+        }
+        if (*pszc==':') {
+            ++pszc;
+            if (*pszc==',' || *pszc==']') {
+                nMax=-1; 
+            } else {
+                nMax=strtol(pszc,&psze,10);
+                if (*psze!=',' && *psze!=']') {
+                    CPLError( CE_Warning, CPLE_IllegalArg, "Invalid range specified\n");
+                    deleteList(poVals);
+                    poVals=0;
+                    return;
+                }
+                pszc=psze;
+            }
+        } else nMax=nMin;
+        Range::List *poNew;
+        if (eType!=ALL) poNew=new Range::List(eType,nMin,nMax,NULL); else poNew=new Range::List(POINTS,nMin,nMax,new Range::List(ELEMENTS,nMin,nMax,NULL));
+        if (poVals==0) {
+            poVals=poNew;
+            poEnd=poNew;
+        } else {
+            poEnd->poNext=poNew;
+            poEnd=poNew;
+        }
+        if (poEnd->poNext!=NULL) poEnd=poEnd->poNext;
+    }
+    if (*pszc!=']') {
+        CPLError( CE_Warning, CPLE_IllegalArg, "Invalid range specified\n");
+        deleteList(poVals);
+        poVals=0;
+    }
+}
+
+bool Range::contains(SelafinTypeDef eType,long nValue) const {
+    if (poVals==0) return true;
+    Range::List *poCur=poActual;
+    while (poCur!=0) {
+        if (poCur->eType==eType && nValue>=poCur->nMin && nValue<=poCur->nMax) return true;
+        poCur=poCur->poNext;
+    }
+    return false;
+}
+
+void Range::sortList(Range::List *&poList,Range::List *poEnd) {
+    if (poList==0 || poList==poEnd) return;
+    Range::List *pol=poList;
+    Range::List *poBefore=0;
+    Range::List *poBeforeEnd=0;
+    // poList plays the role of the pivot value. Values greater and smaller are sorted on each side of it.
+    // The order relation here is POINTS ranges first, then sorted by nMin value.
+    while (pol->poNext!=poEnd) {
+        if ((pol->eType==ELEMENTS && (pol->poNext->eType==POINTS || pol->poNext->nMin<pol->nMin)) || (pol->eType==POINTS && pol->poNext->eType==POINTS && pol->poNext->nMin<pol->nMin)) {
+            if (poBefore==0) {
+                poBefore=pol->poNext;
+                poBeforeEnd=poBefore;
+            } else {
+                poBeforeEnd->poNext=pol->poNext;
+                poBeforeEnd=poBeforeEnd->poNext;
+            }
+            pol->poNext=pol->poNext->poNext;
+        } else pol=pol->poNext;
+    }
+    if (poBefore!=0) poBeforeEnd->poNext=poList;
+    // Now, poList is well placed. We do the same for the sublists before and after poList
+    Range::sortList(poBefore,poList);
+    Range::sortList(poList->poNext,poEnd);
+    // Finally, we restore the right starting point of the list
+    if (poBefore!=0) poList=poBefore;
+}
+
+void Range::setMaxValue(long nMaxValueP) {
+    nMaxValue=nMaxValueP;
+    if (poVals==0) return;
+    // We keep an internal private copy of the list where the range is "resolved", that is simplified to a union of disjoint intervals
+    deleteList(poActual);
+    poActual=0;
+    Range::List *pol=poVals;
+    Range::List *poActualEnd=0;
+    long nMinT,nMaxT;
+    while (pol!=0) {
+        if (pol->nMin<0) nMinT=pol->nMin+nMaxValue; else nMinT=pol->nMin;
+        if (pol->nMin<0) pol->nMin=0;
+        if (pol->nMin>=nMaxValue) pol->nMin=nMaxValue-1;
+        if (pol->nMax<0) nMaxT=pol->nMax+nMaxValue; else nMaxT=pol->nMax;
+        if (pol->nMax<0) pol->nMax=0;
+        if (pol->nMax>=nMaxValue) pol->nMax=nMaxValue-1;
+        if (nMaxT<nMinT) continue;
+        if (poActual==0) {
+            poActual=new Range::List(pol->eType,nMinT,nMaxT,0);
+            poActualEnd=poActual;
+        } else {
+            poActualEnd->poNext=new Range::List(pol->eType,nMinT,nMaxT,0);
+            poActualEnd=poActualEnd->poNext;
+        }
+        pol=pol->poNext;
+    }
+    sortList(poActual);
+    // Now we merge successive ranges when they intersect or are consecutive
+    if (poActual!=0) {
+        pol=poActual;
+        while (pol->poNext!=0) {
+            if (pol->poNext->eType==pol->eType && pol->poNext->nMin<=pol->nMax+1) {
+                if (pol->poNext->nMax>pol->nMax) pol->nMax=pol->poNext->nMax;
+                poActualEnd=pol->poNext->poNext;
+                delete pol->poNext;
+                pol->poNext=poActualEnd;
+            } else pol=pol->poNext;
+        }
+    }
+}
+
+size_t Range::getSize() const {
+    if (poVals==0) return nMaxValue*2;
+    Range::List *pol=poActual;
+    size_t nSize=0;
+    while (pol!=0) {
+        nSize+=(pol->nMax-pol->nMin+1);
+        pol=pol->poNext;
+    }
+    return nSize;
+}
+
+/************************************************************************/
+/*                          OGRSelafinDataSource()                      */
+/************************************************************************/
+
+OGRSelafinDataSource::OGRSelafinDataSource() {
+    papoLayers = NULL;
+    nLayers = 0;
+    pszName = NULL;
+    poHeader=0;
+    pszLockName=0;
+    poSpatialRef=0;
+}
+
+/************************************************************************/
+/*                         ~OGRSelafinDataSource()                      */
+/************************************************************************/
+
+OGRSelafinDataSource::~OGRSelafinDataSource() {
+    //CPLDebug("Selafin","~OGRSelafinDataSource(%s)",pszName);
+    for( int i = 0; i < nLayers; i++ ) delete papoLayers[i];
+    CPLFree( papoLayers );
+    CPLFree( pszName );
+    ReleaseLock();
+    delete poHeader;
+    if (poSpatialRef!=0) poSpatialRef->Release();
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRSelafinDataSource::TestCapability( const char * pszCap ) {
+    if( EQUAL(pszCap,ODsCCreateLayer) ) return TRUE;
+    else if( EQUAL(pszCap,ODsCDeleteLayer) ) return TRUE;
+    else if( EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer) ) return FALSE;
+    else return FALSE;
+}
+
+/************************************************************************/
+/*                              GetLayer()                              */
+/************************************************************************/
+
+OGRLayer *OGRSelafinDataSource::GetLayer( int iLayer ) {
+    if( iLayer < 0 || iLayer >= nLayers ) return NULL;
+    else return papoLayers[iLayer];
+}
+
+/************************************************************************/
+/*                                Open()                                */
+/************************************************************************/
+int OGRSelafinDataSource::Open(const char * pszFilename, int bUpdateIn, int bCreate) {
+    // Check if a range is set and extract it and the filename
+    const char *pszc=pszFilename;
+    if (*pszFilename==0) return FALSE;
+    while (*pszc) ++pszc;
+    if (*(pszc-1)==']') {
+        --pszc;
+        while (pszc!=pszFilename && *pszc!='[') pszc--;
+        if (pszc==pszFilename) return FALSE;
+        poRange.setRange(pszc);
+    }
+    pszName = CPLStrdup( pszFilename );
+    pszName[pszc-pszFilename]=0;
+    bUpdate = bUpdateIn;
+    if (bCreate && EQUAL(pszName, "/vsistdout/")) return TRUE;
+    /* For writable /vsizip/, do nothing more */
+    if (bCreate && strncmp(pszName, "/vsizip/", 8) == 0) return TRUE;
+    CPLString osFilename(pszName);
+    CPLString osBaseFilename = CPLGetFilename(pszName);
+    // Determine what sort of object this is.
+    VSIStatBufL sStatBuf;
+    if (VSIStatExL( osFilename, &sStatBuf, VSI_STAT_NATURE_FLAG ) != 0) return FALSE;
+
+    // Is this a single Selafin file?
+    if (VSI_ISREG(sStatBuf.st_mode)) return OpenTable( pszName );
+
+    // Is this a single a ZIP file with only a Selafin file inside ?
+    if( strncmp(osFilename, "/vsizip/", 8) == 0 && VSI_ISREG(sStatBuf.st_mode) ) {
+        char** papszFiles = VSIReadDir(osFilename);
+        if (CSLCount(papszFiles) != 1) {
+            CSLDestroy(papszFiles);
+            return FALSE;
+        }
+        osFilename = CPLFormFilename(osFilename, papszFiles[0], NULL);
+        CSLDestroy(papszFiles);
+        return OpenTable( osFilename );
+    }
+
+#ifdef notdef
+    // Otherwise it has to be a directory.
+    if( !VSI_ISDIR(sStatBuf.st_mode) ) return FALSE;
+
+    // Scan through for entries which look like Selafin files
+    int nNotSelafinCount = 0, i;
+    char **papszNames = CPLReadDir( osFilename );
+    for( i = 0; papszNames != NULL && papszNames[i] != NULL; i++ ) {
+        CPLString oSubFilename = CPLFormFilename( osFilename, papszNames[i], NULL );
+        if( EQUAL(papszNames[i],".") || EQUAL(papszNames[i],"..") ) continue;
+        if( VSIStatL( oSubFilename, &sStatBuf ) != 0 || !VSI_ISREG(sStatBuf.st_mode) ) {
+            nNotSelafinCount++;
+            continue;
+        }
+        if( !OpenTable( oSubFilename ) ) {
+            CPLDebug("Selafin", "Cannot open %s", oSubFilename.c_str());
+            nNotSelafinCount++;
+            continue;
+        }
+    }
+    CSLDestroy( papszNames );
+
+    // We presume that this is indeed intended to be a Selafin datasource if over half the files were Selafin files. 
+    return nNotSelafinCount < nLayers;
+#else
+    return FALSE;
+#endif
+}
+
+/************************************************************************/
+/*                              TakeLock()                              */
+/************************************************************************/
+int OGRSelafinDataSource::TakeLock(CPL_UNUSED const char *pszFilename) {
+#ifdef notdef
+    // Ideally, we should implement a locking mechanism for Selafin layers because different layers share the same header and file on disk. If two layers are modified at the same time,
+    // this would most likely result in data corruption. However, locking the data source causes other problems in QGis which always tries to open the datasource twice, a first time
+    // in Update mode, and the second time for the layer inside in Read-only mode (because the lock is taken), and layers therefore can't be changed in QGis.
+    // For now, this procedure is deactivated and a warning message is issued when a datasource is opened in update mode.
+    //CPLDebug("Selafin","TakeLock(%s)",pszFilename);
+    if (pszLockName!=0) CPLFree(pszLockName);
+    VSILFILE *fpLock;
+    size_t nLen=strlen(pszFilename)+4;
+    pszLockName=(char*)CPLMalloc(sizeof(char)*nLen);
+    CPLStrlcpy(pszLockName,pszFilename,nLen-3);
+    CPLStrlcat(pszLockName,"~~~",nLen);
+    fpLock=VSIFOpenL(pszLockName,"rb+");
+    // This is not thread-safe but I'm not quite sure how to open a file in exclusive mode and in a portable way
+    if (fpLock!=NULL) {
+        VSIFCloseL(fpLock);
+        return 0;
+    }
+    fpLock=VSIFOpenL(pszLockName,"wb");
+    VSIFCloseL(fpLock);
+#endif
+    return 1;
+}
+
+/************************************************************************/
+/*                            ReleaseLock()                             */
+/************************************************************************/
+void OGRSelafinDataSource::ReleaseLock() {
+#ifdef notdef
+    if (pszLockName==0) return;
+    VSIUnlink(pszLockName);
+    CPLFree(pszLockName);
+#endif
+}
+
+/************************************************************************/
+/*                              OpenTable()                             */
+/************************************************************************/
+int OGRSelafinDataSource::OpenTable(const char * pszFilename) {
+    //CPLDebug("Selafin","OpenTable(%s,%i)",pszFilename,bUpdate);
+    // Open the file
+    VSILFILE * fp;
+    if( bUpdate ) {
+        // We have to implement this locking feature for write access because the same file may hold several layers, and some programs (like QGIS) open each layer in a single datasource,
+        // so the same file might be opened several times for write access
+        if (TakeLock(pszFilename)==0) {
+            CPLError(CE_Failure,CPLE_OpenFailed,"Failed to open %s for write access, lock file found %s.",pszFilename,pszLockName);
+            return FALSE;
+        }
+        fp = VSIFOpenL( pszFilename, "rb+" );
+    } else fp = VSIFOpenL( pszFilename, "rb" );
+    if( fp == NULL ) {
+        CPLError( CE_Warning, CPLE_OpenFailed, "Failed to open %s, %s.", pszFilename, VSIStrerror( errno ) );
+        return FALSE;
+    } 
+    if( !bUpdate && strstr(pszFilename, "/vsigzip/") == NULL && strstr(pszFilename, "/vsizip/") == NULL ) fp = (VSILFILE*) VSICreateBufferedReaderHandle((VSIVirtualHandle*)fp);
+
+    // Quickly check if the file is in Selafin format, before actually starting to read to make it faster
+    char szBuf[9];
+    VSIFReadL(szBuf,1,4,fp);
+    if (szBuf[0]!=0 || szBuf[1]!=0 || szBuf[2]!=0 || szBuf[3]!=0x50) {
+        VSIFCloseL(fp);
+        return FALSE;
+    }
+    VSIFSeekL(fp,84,SEEK_SET);
+    VSIFReadL(szBuf,1,8,fp);
+    if (szBuf[0]!=0 || szBuf[1]!=0 || szBuf[2]!=0 || szBuf[3]!=0x50 || szBuf[4]!=0 || szBuf[5]!=0 || szBuf[6]!=0 || szBuf[7]!=8) {
+        VSIFCloseL(fp);
+        return FALSE;
+    }
+    /* VSIFSeekL(fp,76,SEEK_SET);
+    VSIFReadL(szBuf,1,8,fp);
+    if (STRNCASECMP(szBuf,"Seraphin",8)!=0 && STRNCASECMP(szBuf,"Serafin",7)!=0) {
+        VSIFCloseL(fp);
+        return FALSE;
+    } */
+
+    // Get layer base name
+    CPLString osBaseLayerName = CPLGetBasename(pszFilename);
+    CPLString osExt = CPLGetExtension(pszFilename);
+    if( strncmp(pszFilename, "/vsigzip/", 9) == 0 && EQUAL(osExt, "gz") ) {
+        size_t nPos=std::string::npos;
+        if (strlen(pszFilename)>3) nPos=osExt.find_last_of('.',strlen(pszFilename)-4);
+        if (nPos!=std::string::npos) {
+            osExt=osExt.substr(nPos+1,strlen(pszFilename)-4-nPos); 
+            osBaseLayerName=osBaseLayerName.substr(0,nPos);
+        } else {
+            osExt="";
+        }
+    }
+
+    // Read header of file to get common information for all layers
+    poHeader=Selafin::read_header(fp,pszFilename);
+    if (poHeader==0) {
+        VSIFCloseL(fp);
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open %s, wrong format.\n", pszFilename);
+        return FALSE;
+    }
+    if (poHeader->nEpsg!=0) {
+        poSpatialRef=new OGRSpatialReference();
+        if (poSpatialRef->importFromEPSG(poHeader->nEpsg)!=OGRERR_NONE) {
+            CPLError( CE_Warning, CPLE_AppDefined, "EPSG %li not found. Could not set datasource SRS.\n", poHeader->nEpsg);
+            delete poSpatialRef;
+            poSpatialRef=0;
+        }
+    }
+
+    // Create two layers for each selected time step: one for points, the other for elements
+    int nNewLayers;
+    poRange.setMaxValue(poHeader->nSteps);
+    nNewLayers=poRange.getSize();
+    if (EQUAL(pszFilename, "/vsistdin/")) osBaseLayerName = "layer";
+    CPLString osLayerName;
+    papoLayers = (OGRSelafinLayer **) CPLRealloc(papoLayers, sizeof(void*) * (nLayers+nNewLayers));
+    for (size_t j=0;j<2;++j) {
+        SelafinTypeDef eType=(j==0)?POINTS:ELEMENTS;
+        for (long i=0;i<poHeader->nSteps;++i) {
+            if (poRange.contains(eType,i)) {
+                char szTemp[30];
+                double dfTime;
+                if (VSIFSeekL(fp,poHeader->getPosition(i)+4,SEEK_SET)!=0 || Selafin::read_float(fp,dfTime)==0) {
+                    VSIFCloseL(fp);
+                    CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open %s, wrong format.\n", pszFilename);
+                    return FALSE;
+                }
+                if (poHeader->panStartDate==0) snprintf(szTemp,29,"%li",i); else {
+                    struct tm sDate={0};
+                    sDate.tm_year=poHeader->panStartDate[0]-1900;
+                    sDate.tm_mon=poHeader->panStartDate[1]-1;
+                    sDate.tm_mday=poHeader->panStartDate[2];
+                    sDate.tm_hour=poHeader->panStartDate[3];
+                    sDate.tm_min=poHeader->panStartDate[4];
+                    sDate.tm_sec=poHeader->panStartDate[5]+(int)dfTime;
+                    mktime(&sDate);
+                    strftime(szTemp,29,"%Y_%m_%d_%H_%M_%S",&sDate);
+                }
+                if (eType==POINTS) osLayerName=osBaseLayerName+"_p"+szTemp; else osLayerName=osBaseLayerName+"_e"+szTemp;
+                papoLayers[nLayers++] = new OGRSelafinLayer( osLayerName, bUpdate, poSpatialRef, poHeader,i,eType);
+                //poHeader->nRefCount++;
+            }
+        }
+    }
+    
+    // Free allocated variables and exit
+    return TRUE;
+}
+
+/************************************************************************/
+/*                           ICreateLayer()                             */
+/************************************************************************/
+
+OGRLayer *OGRSelafinDataSource::ICreateLayer( const char *pszLayerName, OGRSpatialReference *poSpatialRefP, OGRwkbGeometryType eGType, char ** papszOptions  ) {
+    CPLDebug("Selafin","CreateLayer(%s,%s)",pszLayerName,(eGType==wkbPoint)?"wkbPoint":"wkbPolygon");
+    // Verify we are in update mode.
+    if (!bUpdate) {
+        CPLError( CE_Failure, CPLE_NoWriteAccess, "Data source %s opened read-only.\n" "New layer %s cannot be created.\n", pszName, pszLayerName );
+        return NULL;
+    }
+    // Check that new layer is a point or polygon layer
+    if (eGType!=wkbPoint) {
+        CPLError( CE_Failure, CPLE_NoWriteAccess, "Selafin format can only handle %s layers whereas input is %s\n.", OGRGeometryTypeToName(wkbPoint),OGRGeometryTypeToName(eGType));
+        return NULL;
+    }
+    // Parse options
+    double dfDate;
+    const char *pszTemp=CSLFetchNameValue(papszOptions,"DATE");
+    if (pszTemp!=0) dfDate=CPLAtof(pszTemp); else dfDate=0.0;
+    // Set the SRS of the datasource if this is the first layer
+    if (nLayers==0 && poSpatialRefP!=0) {
+        poSpatialRef=poSpatialRefP;
+        poSpatialRef->Reference();
+        const char* szEpsg=poSpatialRef->GetAttrValue("GEOGCS|AUTHORITY",1);
+        long nEpsg=0;
+        if (szEpsg!=0) nEpsg=strtol(szEpsg,0,10);
+        if (nEpsg==0) {
+            CPLError(CE_Warning,CPLE_AppDefined,"Could not find EPSG code for SRS. The SRS won't be saved in the datasource.");
+        } else {
+            poHeader->nEpsg=nEpsg;
+        }
+    }
+    // Create the new layer in the Selafin file by adding a "time step" at the end
+    // Beware, as the new layer shares the same header, it automatically contains the same number of features and fields as the existing ones. This may not be intuitive for the user.
+    if (VSIFSeekL(poHeader->fp,0,SEEK_END)!=0) return NULL;
+    if (Selafin::write_integer(poHeader->fp,4)==0 ||
+        Selafin::write_float(poHeader->fp,dfDate)==0 ||
+        Selafin::write_integer(poHeader->fp,4)==0) {
+        CPLError( CE_Failure, CPLE_FileIO, "Could not write to Selafin file %s.\n",pszName);
+        return NULL;
+    }
+    double *pdfValues=0;
+    if (poHeader->nPoints>0) pdfValues=(double*)VSIMalloc2(sizeof(double),poHeader->nPoints);
+    for (long i=0;i<poHeader->nVar;++i) {
+        if (Selafin::write_floatarray(poHeader->fp,pdfValues,poHeader->nPoints)==0) {
+            CPLError( CE_Failure, CPLE_FileIO, "Could not write to Selafin file %s.\n",pszName);
+            CPLFree(pdfValues);
+            return NULL;
+        }
+    }
+    CPLFree(pdfValues);
+    VSIFFlushL(poHeader->fp);
+    poHeader->nSteps++;
+    // Create two layers as usual, one for points and one for elements
+    nLayers+=2;
+    papoLayers = (OGRSelafinLayer **) CPLRealloc(papoLayers, sizeof(void*) * nLayers);
+    CPLString szName=pszLayerName;
+    CPLString szNewLayerName=szName+"_p";
+    papoLayers[nLayers-2] = new OGRSelafinLayer( szNewLayerName, bUpdate, poSpatialRef, poHeader,poHeader->nSteps-1,POINTS);
+    szNewLayerName=szName+"_e";
+    papoLayers[nLayers-1] = new OGRSelafinLayer( szNewLayerName, bUpdate, poSpatialRef, poHeader,poHeader->nSteps-1,ELEMENTS);
+    return papoLayers[nLayers-2];
+}
+
+/************************************************************************/
+/*                            DeleteLayer()                             */
+/************************************************************************/
+OGRErr OGRSelafinDataSource::DeleteLayer( int iLayer ) {
+    // Verify we are in update mode.
+    if( !bUpdate ) {
+        CPLError( CE_Failure, CPLE_NoWriteAccess, "Data source %s opened read-only.\n" "Layer %d cannot be deleted.\n", pszName, iLayer );
+        return OGRERR_FAILURE;
+    }
+    if( iLayer < 0 || iLayer >= nLayers ) {
+        CPLError( CE_Failure, CPLE_AppDefined, "Layer %d not in legal range of 0 to %d.", iLayer, nLayers-1 );
+        return OGRERR_FAILURE;
+    }
+    // Delete layer in file. Here we don't need to create a copy of the file because we only update values and it can't get corrupted even if the system crashes during the operation
+    long nNum=papoLayers[iLayer]->GetStepNumber();
+    double dfTime;
+    double *dfValues=0;
+    long nTemp;
+    for (long i=nNum;i<poHeader->nSteps-1;++i) {
+        if (VSIFSeekL(poHeader->fp,poHeader->getPosition(i+1)+4,SEEK_SET)!=0 ||
+            Selafin::read_float(poHeader->fp,dfTime)==0 || 
+            VSIFSeekL(poHeader->fp,poHeader->getPosition(i)+4,SEEK_SET)!=0 ||
+            Selafin::write_float(poHeader->fp,dfTime)==0) {
+            CPLError( CE_Failure, CPLE_FileIO, "Could not update Selafin file %s.\n",pszName);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar;++j) {
+            if (VSIFSeekL(poHeader->fp,poHeader->getPosition(i+1)+12,SEEK_SET)!=0 ||
+                (nTemp=Selafin::read_floatarray(poHeader->fp,&dfValues)) !=poHeader->nPoints ||
+                VSIFSeekL(poHeader->fp,poHeader->getPosition(i)+12,SEEK_SET)!=0 ||
+                Selafin::write_floatarray(poHeader->fp,dfValues,poHeader->nPoints)==0) {
+                CPLError( CE_Failure, CPLE_FileIO, "Could not update Selafin file %s.\n",pszName);
+                CPLFree(dfValues);
+                return OGRERR_FAILURE;
+            }
+            CPLFree(dfValues);
+        }
+    }
+    // Delete all layers with the same step number in layer list. Usually there are two of them: one for points and one for elements, but we can't rely on that because of possible layer filtering specifications
+    for (long i=0;i<nLayers;++i) {
+        if (papoLayers[i]->GetStepNumber()==nNum) {
+            delete papoLayers[i];
+            nLayers--;
+            for (long j=i;j<nLayers;++j) papoLayers[j]=papoLayers[j+1];
+            --i;
+        }
+    }
+    return OGRERR_NONE;
+}
diff --git a/ogr/ogrsf_frmts/selafin/ogrselafindriver.cpp b/ogr/ogrsf_frmts/selafin/ogrselafindriver.cpp
new file mode 100644
index 0000000..fc5fa76
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/ogrselafindriver.cpp
@@ -0,0 +1,201 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Implementation of OGR driver for Selafin files.
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_selafin.h"
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "io_selafin.h"
+
+/************************************************************************/
+/*                     OGRSelafinDriverIdentify()                       */
+/************************************************************************/
+
+static int OGRSelafinDriverIdentify( GDALOpenInfo* poOpenInfo ) {
+
+    if( poOpenInfo->fpL != NULL )
+    {
+        if( poOpenInfo->nHeaderBytes < 84 + 8 )
+            return FALSE;
+        if (poOpenInfo->pabyHeader[0]!=0 || poOpenInfo->pabyHeader[1]!=0 ||
+            poOpenInfo->pabyHeader[2]!=0 || poOpenInfo->pabyHeader[3]!=0x50)
+            return FALSE;
+
+        if (poOpenInfo->pabyHeader[84+0]!=0 || poOpenInfo->pabyHeader[84+1]!=0 ||
+            poOpenInfo->pabyHeader[84+2]!=0 || poOpenInfo->pabyHeader[84+3]!=0x50 ||
+            poOpenInfo->pabyHeader[84+4]!=0 || poOpenInfo->pabyHeader[84+5]!=0 ||
+            poOpenInfo->pabyHeader[84+6]!=0 || poOpenInfo->pabyHeader[84+7]!=8)
+            return FALSE;
+
+        return TRUE;
+    }
+    return -1;
+}
+
+/************************************************************************/
+/*                      OGRSelafinDriverOpen()                          */
+/************************************************************************/
+
+static GDALDataset *OGRSelafinDriverOpen( GDALOpenInfo* poOpenInfo ) {
+
+    if( OGRSelafinDriverIdentify(poOpenInfo) == 0 )
+        return NULL;
+    
+    OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
+    if( !poDS->Open(poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update, FALSE) ) {
+        delete poDS;
+        poDS = NULL;
+    }
+    return poDS;
+}
+
+/************************************************************************/
+/*                       OGRSelafinDriverCreate()                       */
+/************************************************************************/
+
+static GDALDataset *OGRSelafinDriverCreate( const char * pszName,
+                                            CPL_UNUSED int nXSize,
+                                            CPL_UNUSED int nYSize,
+                                            CPL_UNUSED int nBands,
+                                            CPL_UNUSED GDALDataType eDT,
+                                            char **papszOptions ) {
+    // First, ensure there isn't any such file yet.
+    VSIStatBufL sStatBuf;
+    if (strcmp(pszName, "/dev/stdout") == 0) pszName = "/vsistdout/";
+    if( VSIStatL( pszName, &sStatBuf ) == 0 ) {
+        CPLError(CE_Failure, CPLE_AppDefined,"It seems a file system object called '%s' already exists.",pszName);
+        return NULL;
+    }
+    // Parse options
+    const char *pszTemp=CSLFetchNameValue(papszOptions,"TITLE");
+    char pszTitle[81];
+    long pnDate[6]={-1,0};
+    if (pszTemp!=0) strncpy(pszTitle,pszTemp,72); else memset(pszTitle,' ',72);
+    pszTemp=CSLFetchNameValue(papszOptions,"DATE");
+    if (pszTemp!=0) {
+        const char* pszErrorMessage="Wrong format for date parameter: must be \"%%Y-%%m-%%d_%%H:%%M:%%S\", ignored";
+        const char *pszc=pszTemp;
+        pnDate[0]=atoi(pszTemp);
+        if (pnDate[0]<=0) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage); else {
+            if (pnDate[0]<100) pnDate[0]+=2000; 
+        }
+        while (*pszc!=0 && *pszc!='-') ++pszc;
+        pnDate[1]=atoi(pszc);
+        if (pnDate[1]<0 || pnDate[1]>12) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage);
+        while (*pszc!=0 && *pszc!='_') ++pszc;
+        pnDate[2]=atoi(pszc);
+        if (pnDate[2]<0 || pnDate[2]>59) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage);
+        while (*pszc!=0 && *pszc!='_') ++pszc;
+        pnDate[3]=atoi(pszc);
+        if (pnDate[3]<0 || pnDate[3]>23) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage);
+        while (*pszc!=0 && *pszc!=':') ++pszc;
+        pnDate[4]=atoi(pszc);
+        if (pnDate[4]<0 || pnDate[4]>59) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage);
+        while (*pszc!=0 && *pszc!=':') ++pszc;
+        pnDate[5]=atoi(pszc);
+        if (pnDate[5]<0 || pnDate[5]>59) CPLError(CE_Warning, CPLE_AppDefined,"%s",pszErrorMessage);
+    }
+    // Create the skeleton of a Selafin file
+    VSILFILE *fp=VSIFOpenL(pszName,"wb");
+    if (fp==NULL) {
+        CPLError(CE_Failure, CPLE_AppDefined,"Unable to open %s with write access.",pszName);
+        return NULL;
+    }
+    strncpy(pszTitle+72,"SERAPHIN",9);
+    bool bError=false;
+    if (Selafin::write_string(fp,pszTitle,80)==0) bError=true;
+    long pnTemp[10]={0};
+    if (Selafin::write_intarray(fp,pnTemp,2)==0) bError=true;
+    if (pnDate[0]>=0) pnTemp[9]=1;
+    if (Selafin::write_intarray(fp,pnTemp,10)==0) bError=true;
+    if (pnDate[0]>=0) {
+        if (Selafin::write_intarray(fp,pnTemp,6)==0) bError=true;
+    }
+    pnTemp[3]=1;
+    if (Selafin::write_intarray(fp,pnTemp,4)==0) bError=true;
+    if (Selafin::write_intarray(fp,pnTemp,0)==0) bError=true;
+    if (Selafin::write_intarray(fp,pnTemp,0)==0) bError=true;
+    if (Selafin::write_floatarray(fp,0,0)==0) bError=true;
+    if (Selafin::write_floatarray(fp,0,0)==0) bError=true;
+    VSIFCloseL(fp);
+    if (bError) {
+        CPLError(CE_Failure, CPLE_AppDefined,"Error writing to file %s.",pszName);
+        return NULL;
+    }
+    // Force it to open as a datasource
+    OGRSelafinDataSource *poDS = new OGRSelafinDataSource();
+    if( !poDS->Open( pszName, TRUE, TRUE ) ) {
+        delete poDS;
+        return NULL;
+    }
+    return poDS;
+}
+
+/************************************************************************/
+/*                      OGRSelafinDriverDelete()                        */
+/************************************************************************/
+static CPLErr OGRSelafinDriverDelete( const char *pszFilename ) {
+    if( CPLUnlinkTree( pszFilename ) == 0 ) return CE_None;
+    else return CE_Failure;
+}
+
+/************************************************************************/
+/*                           RegisterOGRSelafin()                       */
+/************************************************************************/
+void RegisterOGRSelafin() {
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "Selafin" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "Selafin" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "Selafin" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Selafin" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_selafin.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+"  <Option name='TITLE' type='string' description='Title of the datasource, stored in the Selafin file. The title must not hold more than 72 characters.'/>"
+"  <Option name='DATE' type='string' description='Starting date of the simulation. Each layer in a Selafin file is characterized by a date, counted in seconds since a reference date. This option allows to provide the reference date. The format of this field must be YYYY-MM-DD_hh:mm:ss'/>"
+"</CreationOptionList>");
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='DATE' type='float' description='Date of the time step, in seconds, relative to the starting date of the simulation.'/>"
+"</LayerCreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSelafinDriverOpen;
+        poDriver->pfnIdentify = OGRSelafinDriverIdentify;
+        poDriver->pfnCreate = OGRSelafinDriverCreate;
+        poDriver->pfnDelete = OGRSelafinDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/selafin/ogrselafinlayer.cpp b/ogr/ogrsf_frmts/selafin/ogrselafinlayer.cpp
new file mode 100644
index 0000000..0423daa
--- /dev/null
+++ b/ogr/ogrsf_frmts/selafin/ogrselafinlayer.cpp
@@ -0,0 +1,719 @@
+/******************************************************************************
+ * Project:  Selafin importer
+ * Purpose:  Implementation of OGRSelafinLayer class.
+ * Author:   François Hissel, francois.hissel at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2014,  François Hissel <francois.hissel at gmail.com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include <cstdlib>
+#include "cpl_conv.h"
+#include "cpl_string.h"
+#include "ogr_p.h"
+#include "io_selafin.h"
+#include "ogr_selafin.h"
+#include "cpl_error.h"
+#include "cpl_quad_tree.h"
+
+/************************************************************************/
+/*                           Utilities functions                        */
+/************************************************************************/
+void MoveOverwrite(VSILFILE *fpDest,VSILFILE *fpSource) {
+    VSIRewindL(fpSource);
+    VSIRewindL(fpDest);
+    VSIFTruncateL(fpDest,0);
+    char anBuf[0x10000];
+    while (!VSIFEofL(fpSource)) {
+        size_t nSize=VSIFReadL(anBuf,1,0x10000,fpSource);
+        size_t nLeft=nSize;
+        while (nLeft>0) nLeft-=VSIFWriteL(anBuf+nSize-nLeft,1,nLeft,fpDest);
+    }
+    VSIFCloseL(fpSource);
+    VSIFFlushL(fpDest);
+}
+
+/************************************************************************/
+/*                            OGRSelafinLayer()                         */
+/*       Note that no operation on OGRSelafinLayer is thread-safe       */
+/************************************************************************/
+
+OGRSelafinLayer::OGRSelafinLayer( const char *pszLayerNameP, int bUpdateP,OGRSpatialReference *poSpatialRefP,Selafin::Header *poHeaderP,int nStepNumberP,SelafinTypeDef eTypeP):eType(eTypeP),bUpdate(bUpdateP),nStepNumber(nStepNumberP),poHeader(poHeaderP),poSpatialRef(poSpatialRefP),nCurrentId(-1) {
+    //CPLDebug("Selafin","Opening layer %s",pszLayerNameP);
+    poFeatureDefn = new OGRFeatureDefn( CPLGetBasename( pszLayerNameP ) );
+    SetDescription( poFeatureDefn->GetName() );
+    poFeatureDefn->Reference();
+    if (eType==POINTS) poFeatureDefn->SetGeomType( wkbPoint );
+    else poFeatureDefn->SetGeomType(wkbPolygon);
+    for (int i=0;i<poHeader->nVar;++i) {
+        OGRFieldDefn oFieldDefn(poHeader->papszVariables[i],OFTReal);
+        poFeatureDefn->AddFieldDefn(&oFieldDefn);
+    }
+}
+
+
+/************************************************************************/
+/*                           ~OGRSelafinLayer()                         */
+/************************************************************************/
+OGRSelafinLayer::~OGRSelafinLayer() {
+    //CPLDebug("Selafin","Closing layer %s",GetName());
+    poFeatureDefn->Release();
+    //poHeader->nRefCount--;  
+    //if (poHeader->nRefCount==0) delete poHeader; 
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+OGRFeature *OGRSelafinLayer::GetNextFeature() {
+    //CPLDebug("Selafin","GetNextFeature(%li)",nCurrentId+1);
+    while (true) {
+        OGRFeature *poFeature=GetFeature(++nCurrentId);
+        if (poFeature==NULL) return NULL;
+        if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) return poFeature;
+        delete poFeature;
+    }
+}
+
+/************************************************************************/
+/*                            ResetReading()                            */
+/************************************************************************/
+void OGRSelafinLayer::ResetReading() {
+    //CPLDebug("Selafin","ResetReading()");
+    nCurrentId=-1;
+}
+
+/************************************************************************/
+/*                           SetNextByIndex()                           */
+/************************************************************************/
+OGRErr OGRSelafinLayer::SetNextByIndex(GIntBig nIndex) {
+    //CPLDebug("Selafin","SetNexByIndex(%li)",nIndex);
+    if (nIndex<0 || nIndex>=poHeader->nPoints) return OGRERR_FAILURE;
+    nCurrentId=nIndex-1;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+int OGRSelafinLayer::TestCapability(const char *pszCap) {
+    //CPLDebug("Selafin","TestCapability(%s)",pszCap);
+    if (EQUAL(pszCap,OLCRandomRead)) return TRUE;
+    if (EQUAL(pszCap,OLCSequentialWrite)) return (bUpdate);
+    if (EQUAL(pszCap,OLCRandomWrite)) return (bUpdate);
+    if (EQUAL(pszCap,OLCFastSpatialFilter)) return FALSE;
+    if (EQUAL(pszCap,OLCFastFeatureCount)) return TRUE;
+    if (EQUAL(pszCap,OLCFastGetExtent)) return TRUE;
+    if (EQUAL(pszCap,OLCFastSetNextByIndex)) return TRUE;
+    if (EQUAL(pszCap,OLCCreateField)) return (bUpdate);
+    if (EQUAL(pszCap,OLCCreateGeomField)) return FALSE;
+    if (EQUAL(pszCap,OLCDeleteField)) return (bUpdate);
+    if (EQUAL(pszCap,OLCReorderFields)) return (bUpdate);
+    if (EQUAL(pszCap,OLCAlterFieldDefn)) return (bUpdate);
+    if (EQUAL(pszCap,OLCDeleteFeature)) return (bUpdate);
+    if (EQUAL(pszCap,OLCStringsAsUTF8)) return FALSE;
+    if (EQUAL(pszCap,OLCTransactions)) return FALSE;
+    if (EQUAL(pszCap,OLCIgnoreFields)) return FALSE;
+    return FALSE;
+}
+
+/************************************************************************/
+/*                            GetFeature()                              */
+/************************************************************************/
+OGRFeature* OGRSelafinLayer::GetFeature(GIntBig nFID) {
+    CPLDebug("Selafin","GetFeature(" CPL_FRMT_GIB ")",nFID);
+    if (nFID<0) return NULL;
+    if (eType==POINTS) {
+        if (nFID>=poHeader->nPoints) return NULL;
+        double nData;
+        OGRFeature *poFeature=new OGRFeature(poFeatureDefn);
+        poFeature->SetGeometryDirectly(new OGRPoint(poHeader->paadfCoords[0][nFID],poHeader->paadfCoords[1][nFID]));
+        poFeature->SetFID(nFID);
+        for (int i=0;i<poHeader->nVar;++i) {
+            VSIFSeekL(poHeader->fp,poHeader->getPosition(nStepNumber,(long)nFID,i),SEEK_SET);
+            if (Selafin::read_float(poHeader->fp,nData)==1) poFeature->SetField(i,nData);
+        }
+        return poFeature;
+    } else {
+        if (nFID>=poHeader->nElements) return NULL;
+        double *anData;
+        anData=(double*)VSIMalloc2(sizeof(double),poHeader->nVar);
+        if (poHeader->nVar>0 && anData==0) return NULL;
+        for (long i=0;i<poHeader->nVar;++i) anData[i]=0;
+        double nData;
+        OGRFeature *poFeature=new OGRFeature(poFeatureDefn);
+        poFeature->SetFID(nFID);
+        OGRPolygon *poPolygon=new OGRPolygon();
+        OGRLinearRing *poLinearRing=new OGRLinearRing();
+        for (long j=0;j<poHeader->nPointsPerElement;++j) {
+            long nPointNum=poHeader->panConnectivity[nFID*poHeader->nPointsPerElement+j]-1;
+            poLinearRing->addPoint(poHeader->paadfCoords[0][nPointNum],poHeader->paadfCoords[1][nPointNum]);
+            for (long i=0;i<poHeader->nVar;++i) {
+                VSIFSeekL(poHeader->fp,poHeader->getPosition(nStepNumber,nPointNum,i),SEEK_SET);
+                if (Selafin::read_float(poHeader->fp,nData)==1) anData[i]+=nData;
+            }
+        }
+        poPolygon->addRingDirectly(poLinearRing);
+        poPolygon->closeRings();
+        poFeature->SetGeometryDirectly(poPolygon);
+        for (long i=0;i<poHeader->nVar;++i) poFeature->SetField(i,anData[i]/poHeader->nPointsPerElement);
+        CPLFree(anData);
+        return poFeature;
+    }
+}
+
+
+/************************************************************************/
+/*                           GetFeatureCount()                          */
+/************************************************************************/
+GIntBig OGRSelafinLayer::GetFeatureCount(int bForce) {
+    //CPLDebug("Selafin","GetFeatureCount(%i)",bForce);
+    if (m_poFilterGeom==NULL && m_poAttrQuery==NULL) return (eType==POINTS)?poHeader->nPoints:poHeader->nElements;
+    if (bForce==FALSE) return -1;
+    long i=0;
+    int nFeatureCount=0;
+    long nMax=(eType==POINTS)?poHeader->nPoints:poHeader->nElements;
+    while (i<nMax) {
+        OGRFeature *poFeature=GetFeature(i++);
+        if( (m_poFilterGeom == NULL || FilterGeometry( poFeature->GetGeometryRef() ) ) && (m_poAttrQuery == NULL || m_poAttrQuery->Evaluate( poFeature )) ) ++nFeatureCount;
+        delete poFeature;
+    }
+    return nFeatureCount;
+}
+
+/************************************************************************/
+/*                             GetExtent()                              */
+/************************************************************************/
+OGRErr OGRSelafinLayer::GetExtent(OGREnvelope *psExtent,
+                                  CPL_UNUSED int bForce) {
+    //CPLDebug("Selafin","GetExtent(%i)",bForce);
+    if (poHeader->nPoints==0) return OGRERR_NONE;
+    CPLRectObj *poObj=poHeader->getBoundingBox();
+    psExtent->MinX=poObj->minx;
+    psExtent->MaxX=poObj->maxx;
+    psExtent->MinY=poObj->miny;
+    psExtent->MaxY=poObj->maxy;
+    delete poObj;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                             ISetFeature()                             */
+/************************************************************************/
+OGRErr OGRSelafinLayer::ISetFeature(OGRFeature *poFeature) {
+    OGRGeometry *poGeom=poFeature->GetGeometryRef();
+    if (poGeom==0) return OGRERR_FAILURE;
+    if (eType==POINTS) {
+        // If it's a point layer, it's the "easy" case: we change the coordinates and attributes of the feature and update the file
+        if (poGeom->getGeometryType()!=wkbPoint) {
+            CPLError( CE_Failure, CPLE_AppDefined, "The new feature should be of the same Point geometry as the existing ones in the layer.");
+            return OGRERR_FAILURE;
+        }
+        OGRPoint *poPoint=(OGRPoint*)poGeom;
+        GIntBig nFID=poFeature->GetFID();
+        poHeader->paadfCoords[0][nFID]=poPoint->getX();
+        poHeader->paadfCoords[1][nFID]=poPoint->getY();
+        CPLDebug("Selafin","SetFeature(" CPL_FRMT_GIB ",%f,%f)",nFID,poHeader->paadfCoords[0][nFID],poHeader->paadfCoords[1][nFID]);
+        if (VSIFSeekL(poHeader->fp,88+16+40*poHeader->nVar+48+((poHeader->panStartDate!=0)?32:0)+24+(poHeader->nElements*poHeader->nPointsPerElement+2)*4+(poHeader->nPoints+2)*4+4+nFID*4,SEEK_SET)!=0) return OGRERR_FAILURE;
+        CPLDebug("Selafin","Write_float(" CPL_FRMT_GUIB ",%f)",VSIFTellL(poHeader->fp),poHeader->paadfCoords[0][nFID]-poHeader->adfOrigin[0]);
+        if (Selafin::write_float(poHeader->fp,poHeader->paadfCoords[0][nFID]-poHeader->adfOrigin[0])==0) return OGRERR_FAILURE;
+        if (VSIFSeekL(poHeader->fp,88+16+40*poHeader->nVar+48+((poHeader->panStartDate!=0)?32:0)+24+(poHeader->nElements*poHeader->nPointsPerElement+2)*4+(poHeader->nPoints+2)*4+(poHeader->nPoints+2)*4+4+nFID*4,SEEK_SET)!=0) return OGRERR_FAILURE;
+        CPLDebug("Selafin","Write_float(" CPL_FRMT_GUIB ",%f)",VSIFTellL(poHeader->fp),poHeader->paadfCoords[1][nFID]-poHeader->adfOrigin[1]);
+        if (Selafin::write_float(poHeader->fp,poHeader->paadfCoords[1][nFID]-poHeader->adfOrigin[1])==0) return OGRERR_FAILURE;
+        for (long i=0;i<poHeader->nVar;++i) {
+            double nData=poFeature->GetFieldAsDouble(i);
+            if (VSIFSeekL(poHeader->fp,poHeader->getPosition(nStepNumber,(long)nFID,i),SEEK_SET)!=0) return OGRERR_FAILURE;
+            if (Selafin::write_float(poHeader->fp,nData)==0) return OGRERR_FAILURE;
+        }
+    } else {
+        // Else, we have a layer of polygonal elements. Here we consider that the vertices are moved when we change the geometry (which will also lead to a modification in the corresponding point layer). The attributes table can't be changed, because attributes are calculated from those of the vertices.
+        // First we check that the new feature is a polygon with the right number of vertices
+        if (poGeom->getGeometryType()!=wkbPolygon) {
+            CPLError( CE_Failure, CPLE_AppDefined, "The new feature should be of the same Polygon geometry as the existing ones in the layer.");
+            return OGRERR_FAILURE;
+        }
+        OGRLinearRing *poLinearRing=((OGRPolygon*)poGeom)->getExteriorRing();
+        if (poLinearRing->getNumPoints()!=poHeader->nPointsPerElement+1) {
+            CPLError( CE_Failure, CPLE_AppDefined, "The new feature should have the same number of vertices %li as the existing ones in the layer.",poHeader->nPointsPerElement);
+            return OGRERR_FAILURE;
+        }
+        CPLError(CE_Warning,CPLE_AppDefined,"The attributes of elements layer in Selafin files can't be updated.");
+        CPLDebug("Selafin","SetFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",poFeature->GetFID(),poLinearRing->getX(0),poLinearRing->getY(0),poLinearRing->getX(1),poLinearRing->getY(1),poLinearRing->getX(2),poLinearRing->getY(2));   //!< This is not safe as we can't be sure there are at least three vertices in the linear ring, but we can assume that for a debug mode
+        long nFID=poFeature->GetFID();
+        // Now we change the coordinates of points in the layer based on the vertices of the new polygon. We don't look at the order of points and we assume that it is the same as in the original layer.
+        for (long i=0;i<poHeader->nPointsPerElement;++i) {
+            long nPointId=poHeader->panConnectivity[nFID*poHeader->nPointsPerElement+i]-1;
+            poHeader->paadfCoords[0][nPointId]=poLinearRing->getX(i);
+            poHeader->paadfCoords[1][nPointId]=poLinearRing->getY(i);
+            if (VSIFSeekL(poHeader->fp,88+16+40*poHeader->nVar+48+((poHeader->panStartDate!=0)?32:0)+24+(poHeader->nElements*poHeader->nPointsPerElement+2)*4+(poHeader->nPoints+2)*4+4+nPointId*4,SEEK_SET)!=0) return OGRERR_FAILURE;
+            CPLDebug("Selafin","Write_float(" CPL_FRMT_GUIB ",%f)",VSIFTellL(poHeader->fp),poHeader->paadfCoords[0][nPointId]-poHeader->adfOrigin[0]);
+            if (Selafin::write_float(poHeader->fp,poHeader->paadfCoords[0][nPointId]-poHeader->adfOrigin[0])==0) return OGRERR_FAILURE;
+            if (VSIFSeekL(poHeader->fp,88+16+40*poHeader->nVar+48+((poHeader->panStartDate!=0)?32:0)+24+(poHeader->nElements*poHeader->nPointsPerElement+2)*4+(poHeader->nPoints+2)*4+(poHeader->nPoints+2)*4+4+nPointId*4,SEEK_SET)!=0) return OGRERR_FAILURE;
+            CPLDebug("Selafin","Write_float(" CPL_FRMT_GUIB ",%f)",VSIFTellL(poHeader->fp),poHeader->paadfCoords[1][nPointId]-poHeader->adfOrigin[1]);
+            if (Selafin::write_float(poHeader->fp,poHeader->paadfCoords[1][nPointId]-poHeader->adfOrigin[1])==0) return OGRERR_FAILURE;
+        }
+    }
+    VSIFFlushL(poHeader->fp);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           ICreateFeature()                            */
+/************************************************************************/
+OGRErr OGRSelafinLayer::ICreateFeature(OGRFeature *poFeature) {
+    OGRGeometry *poGeom=poFeature->GetGeometryRef();
+    if (poGeom==0) return OGRERR_FAILURE;
+    if (VSIFSeekL(poHeader->fp,poHeader->getPosition(0),SEEK_SET)!=0) return OGRERR_FAILURE;
+    if (eType==POINTS) {
+        // If it's a point layer, it's the "easy" case: we add a new point feature and update the file
+        if (poGeom->getGeometryType()!=wkbPoint) {
+            CPLError( CE_Failure, CPLE_AppDefined, "The new feature should be of the same Point geometry as the existing ones in the layer.");
+            return OGRERR_FAILURE;
+        }
+        OGRPoint *poPoint=(OGRPoint*)poGeom;
+        poFeature->SetFID(poHeader->nPoints);
+        CPLDebug("Selafin","CreateFeature(%li,%f,%f)",poHeader->nPoints,poPoint->getX(),poPoint->getY());
+        // Change the header to add the new feature
+        poHeader->addPoint(poPoint->getX(),poPoint->getY());
+    } else {
+        // This is the most difficult case. The user wants to add a polygon element. First we check that it has the same number of vertices as the other polygon elements in the file. If there is no other element, then we define the number of vertices.
+        // Every vertex in the layer should have a corresponding point in the corresponding point layer. So if we add a polygon element, we also have to add points in the corresponding layer.
+        // The function tries to add as few new points as possible, reusing already existing points. This is generally what the user will expect.
+
+        // First we check that we have the required geometry
+        if (poGeom->getGeometryType()!=wkbPolygon) {
+            CPLError( CE_Failure, CPLE_AppDefined, "The new feature should be of the same Polygon geometry as the existing ones in the layer.");
+            return OGRERR_FAILURE;
+        }
+
+        // Now we check that we have the right number of vertices, or if this number was not defined yet (0), we define it at once
+        OGRLinearRing *poLinearRing=((OGRPolygon*)poGeom)->getExteriorRing();
+        poFeature->SetFID(poHeader->nElements);
+        CPLDebug("Selafin","CreateFeature(" CPL_FRMT_GIB ",%f,%f,%f,%f,%f,%f)",poFeature->GetFID(),poLinearRing->getX(0),poLinearRing->getY(0),poLinearRing->getX(1),poLinearRing->getY(1),poLinearRing->getX(2),poLinearRing->getY(2));   //!< This is not safe as we can't be sure there are at least three vertices in the linear ring, but we can assume that for a debug mode
+        int nNum=poLinearRing->getNumPoints();
+        if (poHeader->nPointsPerElement==0) {
+            if (nNum<4) {
+                CPLError( CE_Failure, CPLE_AppDefined, "The new feature should have at least 3 vertices.");
+                return OGRERR_FAILURE;
+            }
+            poHeader->nPointsPerElement=nNum-1;
+            if (poHeader->nElements>0) {
+                poHeader->panConnectivity=(long*)CPLRealloc(poHeader->panConnectivity,poHeader->nElements*poHeader->nPointsPerElement);
+                if (poHeader->panConnectivity==0) return OGRERR_FAILURE;
+            }
+        } else {
+            if (poLinearRing->getNumPoints()!=poHeader->nPointsPerElement+1) {
+                CPLError( CE_Failure, CPLE_AppDefined, "The new feature should have the same number of vertices %li as the existing ones in the layer.",poHeader->nPointsPerElement);
+                return OGRERR_FAILURE;
+            }
+        }
+
+        // Now we look for vertices that are already referenced as points in the file
+        int *anMap;
+        anMap=(int*)VSIMalloc2(sizeof(int),poHeader->nPointsPerElement);
+        if (anMap==0) {
+            CPLError(CE_Failure,CPLE_AppDefined,"%s","Not enough memory for operation");
+            return OGRERR_FAILURE;
+        }
+        for (long i=0;i<poHeader->nPointsPerElement;++i) anMap[i]=-1;
+        if (poHeader->nPoints>0) {
+            CPLRectObj *poBB=poHeader->getBoundingBox();
+            double dfMaxDist=(poBB->maxx-poBB->minx)/sqrt((double)(poHeader->nPoints))/1000.0;   //!< Heuristic approach to estimate a maximum distance such that two points are considered equal if they are closer from each other
+            dfMaxDist*=dfMaxDist;
+            delete poBB;
+            for (long i=0;i<poHeader->nPointsPerElement;++i) anMap[i]=poHeader->getClosestPoint(poLinearRing->getX(i),poLinearRing->getY(i),dfMaxDist);
+        }
+
+        // We add new points if needed only
+        for (long i=0;i<poHeader->nPointsPerElement;++i) if (anMap[i]==-1) {
+            poHeader->addPoint(poLinearRing->getX(i),poLinearRing->getY(i));
+            anMap[i]=poHeader->nPoints-1;
+        }
+
+        // And we update the connectivity table to add the new element
+        poHeader->nElements++;
+        poHeader->panConnectivity=(long*)CPLRealloc(poHeader->panConnectivity,sizeof(long)*poHeader->nPointsPerElement*poHeader->nElements);
+        for (long i=0;i<poHeader->nPointsPerElement;++i) {
+            poHeader->panConnectivity[poHeader->nPointsPerElement*(poHeader->nElements-1)+i]=anMap[i]+1;
+        }
+        poHeader->setUpdated();
+        CPLFree(anMap);
+        
+    }
+
+    // Now comes the real insertion. Since values have to be inserted nearly everywhere in the file and we don't want to store everything in memory to overwrite it, we create a new copy of it where we write the new values
+    VSILFILE *fpNew;
+    const char *pszTempfile=CPLGenerateTempFilename(0);
+    fpNew=VSIFOpenL(pszTempfile,"wb+");
+    if( fpNew == NULL ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open temporary file %s with write access, %s.",pszTempfile, VSIStrerror( errno ) );
+        return OGRERR_FAILURE;
+    } 
+    if (Selafin::write_header(fpNew,poHeader)==0) {
+        VSIFCloseL(fpNew);
+        VSIUnlink(pszTempfile);
+        return OGRERR_FAILURE;
+    }
+    long nLen;
+    double dfDate;
+    double *padfValues;
+    for (long i=0;i<poHeader->nSteps;++i) {
+        if (Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::read_float(poHeader->fp,dfDate)==0 ||
+                Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::write_integer(fpNew,4)==0 ||
+                Selafin::write_float(fpNew,dfDate)==0 ||
+                Selafin::write_integer(fpNew,4)==0) {
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar;++j) {
+            if (Selafin::read_floatarray(poHeader->fp,&padfValues)==-1) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            padfValues=(double*)CPLRealloc(padfValues,sizeof(double)*poHeader->nPoints);
+            if (padfValues==NULL) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            if (eType==POINTS) padfValues[poHeader->nPoints-1]=poFeature->GetFieldAsDouble(j);
+            else padfValues[poHeader->nPoints-1]=0;
+            if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+                CPLFree(padfValues);
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            CPLFree(padfValues);   
+        }
+    }
+
+    // If everything went fine, we overwrite the new file with the content of the old one. This way, even if something goes bad, we can still recover the layer. The copy process is format-agnostic.
+    MoveOverwrite(poHeader->fp,fpNew);
+    VSIUnlink(pszTempfile);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           CreateField()                              */
+/************************************************************************/
+OGRErr OGRSelafinLayer::CreateField(OGRFieldDefn *poField,
+                                    CPL_UNUSED int bApproxOK) {
+    CPLDebug("Selafin","CreateField(%s,%s)",poField->GetNameRef(),OGRFieldDefn::GetFieldTypeName(poField->GetType()));
+    // Test if the field does not exist yet
+    if (poFeatureDefn->GetFieldIndex(poField->GetNameRef())!=-1) {
+        // Those two lines are copied from CSV driver, but I am not quite sure what they actually do
+        if (poFeatureDefn->GetGeomFieldIndex(poField->GetNameRef())!=-1) return OGRERR_NONE;
+        if (poFeatureDefn->GetGeomFieldIndex(CPLSPrintf("geom_%s",poField->GetNameRef()))!=-1) return OGRERR_NONE;
+        CPLError(CE_Failure,CPLE_AppDefined,"Attempt to create field %s, but a field with this name already exists.",poField->GetNameRef());
+        return OGRERR_FAILURE;
+    }
+    // Test if the field type is legal (only double precision values are allowed)
+    if (poField->GetType()!=OFTReal) {
+        CPLError(CE_Failure,CPLE_AppDefined,"Attempt to create field of type %s, but this is not supported for Selafin files (only double precision fields are allowed).",poField->GetFieldTypeName(poField->GetType()));
+        return OGRERR_FAILURE;
+    }
+    if (VSIFSeekL(poHeader->fp,poHeader->getPosition(0),SEEK_SET)!=0) return OGRERR_FAILURE;
+    // Change the header to add the new field
+    poHeader->nVar++;
+    poHeader->setUpdated();
+    poHeader->papszVariables=(char**)CPLRealloc(poHeader->papszVariables,sizeof(char*)*poHeader->nVar);
+    poHeader->papszVariables[poHeader->nVar-1]=(char*)VSIMalloc2(sizeof(char),33);
+    strncpy(poHeader->papszVariables[poHeader->nVar-1],poField->GetNameRef(),32);
+    poHeader->papszVariables[poHeader->nVar-1][32]=0;
+    poFeatureDefn->AddFieldDefn(poField);
+
+    // Now comes the real insertion. Since values have to be inserted nearly everywhere in the file and we don't want to store everything in memory to overwrite it, we create a new copy of it where we write the new values
+    VSILFILE *fpNew;
+    const char *pszTempfile=CPLGenerateTempFilename(0);
+    fpNew=VSIFOpenL(pszTempfile,"wb+");
+    if( fpNew == NULL ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open temporary file %s with write access, %s.",pszTempfile, VSIStrerror( errno ) );
+        return OGRERR_FAILURE;
+    } 
+    if (Selafin::write_header(fpNew,poHeader)==0) {
+        VSIFCloseL(fpNew);
+        VSIUnlink(pszTempfile);
+        return OGRERR_FAILURE;
+    }
+    long nLen;
+    double dfDate;
+    double *padfValues;
+    for (long i=0;i<poHeader->nSteps;++i) {
+        if (Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::read_float(poHeader->fp,dfDate)==0 ||
+                Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::write_integer(fpNew,4)==0 ||
+                Selafin::write_float(fpNew,dfDate)==0 ||
+                Selafin::write_integer(fpNew,4)==0) {
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar-1;++j) {
+            if (Selafin::read_floatarray(poHeader->fp,&padfValues)==-1) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+                CPLFree(padfValues);
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            CPLFree(padfValues);   
+        }
+        padfValues=(double*)VSIMalloc2(sizeof(double),poHeader->nPoints);
+        for (long k=0;k<poHeader->nPoints;++k) padfValues[k]=0;
+        if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+            CPLFree(padfValues);
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        CPLFree(padfValues);   
+    }
+    MoveOverwrite(poHeader->fp,fpNew);
+    VSIUnlink(pszTempfile);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           DeleteField()                              */
+/************************************************************************/
+OGRErr OGRSelafinLayer::DeleteField(int iField) {
+    CPLDebug("Selafin","DeleteField(%i)",iField);
+    if (VSIFSeekL(poHeader->fp,poHeader->getPosition(0),SEEK_SET)!=0) return OGRERR_FAILURE;
+    // Change the header to remove the field
+    poHeader->nVar--;
+    poHeader->setUpdated();
+    CPLFree(poHeader->papszVariables[iField]);
+    for (long i=iField;i<poHeader->nVar;++i) poHeader->papszVariables[i]=poHeader->papszVariables[i+1];
+    poHeader->papszVariables=(char**)CPLRealloc(poHeader->papszVariables,sizeof(char*)*poHeader->nVar);
+    poFeatureDefn->DeleteFieldDefn(iField);
+    
+    // Now comes the real deletion. Since values have to be deleted nearly everywhere in the file and we don't want to store everything in memory to overwrite it, we create a new copy of it where we write the new values
+    VSILFILE *fpNew;
+    const char *pszTempfile=CPLGenerateTempFilename(0);
+    fpNew=VSIFOpenL(pszTempfile,"wb+");
+    if( fpNew == NULL ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open temporary file %s with write access, %s.",pszTempfile, VSIStrerror( errno ) );
+        return OGRERR_FAILURE;
+    } 
+    if (Selafin::write_header(fpNew,poHeader)==0) {
+        VSIFCloseL(fpNew);
+        VSIUnlink(pszTempfile);
+        return OGRERR_FAILURE;
+    }
+    long nLen;
+    double dfDate;
+    double *padfValues;
+    for (long i=0;i<poHeader->nSteps;++i) {
+        if (Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::read_float(poHeader->fp,dfDate)==0 ||
+                Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::write_integer(fpNew,4)==0 ||
+                Selafin::write_float(fpNew,dfDate)==0 ||
+                Selafin::write_integer(fpNew,4)==0) {
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar;++j) {
+            if (Selafin::read_floatarray(poHeader->fp,&padfValues)==-1) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            if (j!=iField) {
+                if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+                    CPLFree(padfValues);
+                    VSIFCloseL(fpNew);
+                    VSIUnlink(pszTempfile);
+                    return OGRERR_FAILURE;
+                }
+            }
+            CPLFree(padfValues);   
+        }
+    }
+    MoveOverwrite(poHeader->fp,fpNew);
+    VSIUnlink(pszTempfile);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                          ReorderFields()                             */
+/************************************************************************/
+OGRErr OGRSelafinLayer::ReorderFields(int *panMap) {
+    CPLDebug("Selafin","ReorderFields()");
+    if (VSIFSeekL(poHeader->fp,poHeader->getPosition(0),SEEK_SET)!=0) return OGRERR_FAILURE;
+    // Change the header according to the map
+    char **papszNew=(char**)VSIMalloc2(sizeof(char*),poHeader->nVar);
+    for (long i=0;i<poHeader->nVar;++i) papszNew[i]=poHeader->papszVariables[panMap[i]];
+    CPLFree(poHeader->papszVariables);
+    poHeader->papszVariables=papszNew;
+    poFeatureDefn->ReorderFieldDefns(panMap);
+
+    // Now comes the real change.
+    VSILFILE *fpNew;
+    const char *pszTempfile=CPLGenerateTempFilename(0);
+    fpNew=VSIFOpenL(pszTempfile,"wb+");
+    if( fpNew == NULL ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open temporary file %s with write access, %s.",pszTempfile, VSIStrerror( errno ) );
+        return OGRERR_FAILURE;
+    } 
+    if (Selafin::write_header(fpNew,poHeader)==0) {
+        VSIFCloseL(fpNew);
+        VSIUnlink(pszTempfile);
+        return OGRERR_FAILURE;
+    }
+    long nLen;
+    double dfDate;
+    double *padfValues=0;
+    for (long i=0;i<poHeader->nSteps;++i) {
+        if (Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::read_float(poHeader->fp,dfDate)==0 ||
+                Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::write_integer(fpNew,4)==0 ||
+                Selafin::write_float(fpNew,dfDate)==0 ||
+                Selafin::write_integer(fpNew,4)==0) {
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar;++j) {
+            if (VSIFSeekL(poHeader->fp,poHeader->getPosition(i,-1,panMap[j]),SEEK_SET)!=0 || Selafin::read_floatarray(poHeader->fp,&padfValues)==-1) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+                CPLFree(padfValues);
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            CPLFree(padfValues);
+        }
+    }
+    MoveOverwrite(poHeader->fp,fpNew);
+    VSIUnlink(pszTempfile);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                         AlterFieldDefn()                             */
+/************************************************************************/
+OGRErr OGRSelafinLayer::AlterFieldDefn(int iField,
+                                       OGRFieldDefn *poNewFieldDefn,
+                                       CPL_UNUSED int nFlags) {
+    CPLDebug("Selafin","AlterFieldDefn(%i,%s,%s)",iField,poNewFieldDefn->GetNameRef(),OGRFieldDefn::GetFieldTypeName(poNewFieldDefn->GetType()));
+    // Test if the field type is legal (only double precision values are allowed)
+    if (poNewFieldDefn->GetType()!=OFTReal) {
+        CPLError(CE_Failure,CPLE_AppDefined,"Attempt to update field with type %s, but this is not supported for Selafin files (only double precision fields are allowed).",poNewFieldDefn->GetFieldTypeName(poNewFieldDefn->GetType()));
+        return OGRERR_FAILURE;
+    }
+    // Since the field type can't change, only the field name is changed. We change it in the header
+    CPLFree(poHeader->papszVariables[iField]);
+    poHeader->papszVariables[iField]=(char*)VSIMalloc2(sizeof(char),33);
+    strncpy(poHeader->papszVariables[iField],poNewFieldDefn->GetNameRef(),32);
+    poHeader->papszVariables[iField][32]=0;
+    // And we update the file
+    if (VSIFSeekL(poHeader->fp,88+16+40*iField,SEEK_SET)!=0) return OGRERR_FAILURE;
+    if (Selafin::write_string(poHeader->fp,poHeader->papszVariables[iField],32)==0) return OGRERR_FAILURE;
+    VSIFFlushL(poHeader->fp);
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                          DeleteFeature()                             */
+/************************************************************************/
+OGRErr OGRSelafinLayer::DeleteFeature(GIntBig nFID) {
+    CPLDebug("Selafin","DeleteFeature(" CPL_FRMT_GIB ")",nFID);
+    if (VSIFSeekL(poHeader->fp,poHeader->getPosition(0),SEEK_SET)!=0) return OGRERR_FAILURE;
+    // Change the header to delete the feature
+    if (eType==POINTS) poHeader->removePoint((long)nFID); else {
+        // For elements layer, we only delete the element and not the vertices
+        poHeader->nElements--;
+        for (long i=(long)nFID;i<poHeader->nElements;++i)
+            for (long j=0;j<poHeader->nPointsPerElement;++j)
+                poHeader->panConnectivity[poHeader->nPointsPerElement*i+j]=poHeader->panConnectivity[poHeader->nPointsPerElement*(i+1)+j];
+        poHeader->panConnectivity=(long*)CPLRealloc(poHeader->panConnectivity,sizeof(long)*poHeader->nPointsPerElement*poHeader->nElements);
+        poHeader->setUpdated();
+    }
+
+    // Now we perform the deletion by creating a new temporary layer
+    VSILFILE *fpNew;
+    const char *pszTempfile=CPLGenerateTempFilename(0);
+    fpNew=VSIFOpenL(pszTempfile,"wb+");
+    if( fpNew == NULL ) {
+        CPLError( CE_Failure, CPLE_OpenFailed, "Failed to open temporary file %s with write access, %s.",pszTempfile, VSIStrerror( errno ) );
+        return OGRERR_FAILURE;
+    } 
+    if (Selafin::write_header(fpNew,poHeader)==0) {
+        VSIFCloseL(fpNew);
+        VSIUnlink(pszTempfile);
+        return OGRERR_FAILURE;
+    }
+    long nLen;
+    double dfDate;
+    double *padfValues;
+    for (long i=0;i<poHeader->nSteps;++i) {
+        if (Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::read_float(poHeader->fp,dfDate)==0 ||
+                Selafin::read_integer(poHeader->fp,nLen,true)==0 ||
+                Selafin::write_integer(fpNew,4)==0 ||
+                Selafin::write_float(fpNew,dfDate)==0 ||
+                Selafin::write_integer(fpNew,4)==0) {
+            VSIFCloseL(fpNew);
+            VSIUnlink(pszTempfile);
+            return OGRERR_FAILURE;
+        }
+        for (long j=0;j<poHeader->nVar;++j) {
+            if (Selafin::read_floatarray(poHeader->fp,&padfValues)==-1) {
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            if (eType==POINTS) {
+                for (long k=(long)nFID;k<=poHeader->nPoints;++k) padfValues[k-1]=padfValues[k];
+            }
+            if (Selafin::write_floatarray(fpNew,padfValues,poHeader->nPoints)==0) {
+                CPLFree(padfValues);
+                VSIFCloseL(fpNew);
+                VSIUnlink(pszTempfile);
+                return OGRERR_FAILURE;
+            }
+            CPLFree(padfValues);   
+        }
+    }
+
+    // If everything went fine, we overwrite the new file with the content of the old one. This way, even if something goes bad, we can still recover the layer. The copy process is format-agnostic.
+    MoveOverwrite(poHeader->fp,fpNew);
+    VSIUnlink(pszTempfile);
+    return OGRERR_NONE;
+    
+}
diff --git a/ogr/ogrsf_frmts/shape/GNUmakefile b/ogr/ogrsf_frmts/shape/GNUmakefile
index 71d35a8..b1a8650 100644
--- a/ogr/ogrsf_frmts/shape/GNUmakefile
+++ b/ogr/ogrsf_frmts/shape/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	shape2ogr.o shpopen.o dbfopen.o shptree.o sbnsearch.o shp_vsi.o \
 		ogrshapedriver.o ogrshapedatasource.o ogrshapelayer.o
 
 CPPFLAGS :=	-DSAOffset=vsi_l_offset -DUSE_CPL \
-		-I.. -I../.. -I../generic $(GDAL_INCLUDE) $(CPPFLAGS) 
+		-I.. -I../.. -I../generic  $(CPPFLAGS) 
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/shape/dbfopen.c b/ogr/ogrsf_frmts/shape/dbfopen.c
index c38debf..95aa57a 100644
--- a/ogr/ogrsf_frmts/shape/dbfopen.c
+++ b/ogr/ogrsf_frmts/shape/dbfopen.c
@@ -164,6 +164,12 @@
 #include <ctype.h>
 #include <string.h>
 
+#ifdef USE_CPL
+#include "cpl_string.h"
+#else
+#define CPLsprintf sprintf
+#endif
+
 SHP_CVSID("$Id: dbfopen.c,v 1.89 2011-07-24 05:59:25 fwarmerdam Exp $")
 
 #ifndef FALSE
@@ -215,10 +221,10 @@ static void DBFWriteHeader(DBFHandle psDBF)
 
     abyHeader[0] = 0x03;		/* memo field? - just copying 	*/
 
-    /* write out a dummy date */
-    abyHeader[1] = 95;			/* YY */
-    abyHeader[2] = 7;			/* MM */
-    abyHeader[3] = 26;			/* DD */
+    /* write out update date */
+    abyHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyHeader[3] = (unsigned char) psDBF->nUpdateDay;
 
     /* record count preset at zero */
 
@@ -346,6 +352,9 @@ DBFUpdateHeader( DBFHandle psDBF )
     psDBF->sHooks.FSeek( psDBF->fp, 0, 0 );
     psDBF->sHooks.FRead( abyFileHeader, 32, 1, psDBF->fp );
     
+    abyFileHeader[1] = (unsigned char) psDBF->nUpdateYearSince1900;
+    abyFileHeader[2] = (unsigned char) psDBF->nUpdateMonth;
+    abyFileHeader[3] = (unsigned char) psDBF->nUpdateDay;
     abyFileHeader[4] = (unsigned char) (psDBF->nRecords % 256);
     abyFileHeader[5] = (unsigned char) ((psDBF->nRecords/256) % 256);
     abyFileHeader[6] = (unsigned char) ((psDBF->nRecords/(256*256)) % 256);
@@ -358,6 +367,18 @@ DBFUpdateHeader( DBFHandle psDBF )
 }
 
 /************************************************************************/
+/*                       DBFSetLastModifiedDate()                       */
+/************************************************************************/
+
+void SHPAPI_CALL
+DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD )
+{
+    psDBF->nUpdateYearSince1900 = nYYSince1900;
+    psDBF->nUpdateMonth = nMM;
+    psDBF->nUpdateDay = nDD;
+}
+
+/************************************************************************/
 /*                              DBFOpen()                               */
 /*                                                                      */
 /*      Open a .dbf file.                                               */
@@ -466,6 +487,8 @@ DBFOpenLL( const char * pszFilename, const char * pszAccess, SAHooks *psHooks )
         free( psDBF );
         return NULL;
     }
+    
+    DBFSetLastModifiedDate(psDBF, pabyBuf[1], pabyBuf[2], pabyBuf[3]);
 
     psDBF->nRecords = 
      pabyBuf[4] + pabyBuf[5]*256 + pabyBuf[6]*256*256 + pabyBuf[7]*256*256*256;
@@ -760,6 +783,7 @@ DBFCreateLL( const char * pszFilename, const char * pszCodePage, SAHooks *psHook
         psDBF->pszCodePage = (char * ) malloc( strlen(pszCodePage) + 1 );
         strcpy( psDBF->pszCodePage, pszCodePage );
     }
+    DBFSetLastModifiedDate(psDBF, 95, 7, 26); /* dummy date */
 
     return( psDBF );
 }
@@ -947,6 +971,7 @@ DBFAddNativeFieldType(DBFHandle psDBF, const char * pszFieldName,
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return( psDBF->nFields-1 );
 }
@@ -1242,7 +1267,7 @@ DBFGetFieldInfo( DBFHandle psDBF, int iField, char * pszFieldName,
              || psDBF->pachFieldType[iField] == 'F' )
     {
 	if( psDBF->panFieldDecimals[iField] > 0 
-            || psDBF->panFieldSize[iField] > 10 )
+            || psDBF->panFieldSize[iField] >= 10 )
 	    return( FTDouble );
 	else
 	    return( FTInteger );
@@ -1332,7 +1357,7 @@ static int DBFWriteAttribute(DBFHandle psDBF, int hEntity, int iField,
 
         sprintf( szFormat, "%%%d.%df", 
                     nWidth, psDBF->panFieldDecimals[iField] );
-        sprintf(szSField, szFormat, *((double *) pValue) );
+        CPLsprintf(szSField, szFormat, *((double *) pValue) );
         if( (int) strlen(szSField) > psDBF->panFieldSize[iField] )
         {
             szSField[psDBF->panFieldSize[iField]] = '\0';
@@ -1882,6 +1907,7 @@ DBFDeleteField(DBFHandle psDBF, int iField)
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
@@ -1992,6 +2018,7 @@ DBFReorderFields( DBFHandle psDBF, int* panMap )
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
@@ -2211,6 +2238,7 @@ DBFAlterFieldDefn( DBFHandle psDBF, int iField, const char * pszFieldName,
 
     psDBF->nCurrentRecord = -1;
     psDBF->bCurrentRecordModified = FALSE;
+    psDBF->bUpdated = TRUE;
 
     return TRUE;
 }
diff --git a/ogr/ogrsf_frmts/shape/drv_shapefile.html b/ogr/ogrsf_frmts/shape/drv_shapefile.html
index 90d0151..40cfd6d 100644
--- a/ogr/ogrsf_frmts/shape/drv_shapefile.html
+++ b/ogr/ogrsf_frmts/shape/drv_shapefile.html
@@ -50,6 +50,23 @@ configuration option</a> may be used to override the encoding interpretation
 of the shapefile with any encoding supported by CPLRecode or to "" to avoid
 any recoding. (Recoding support is new for GDAL/OGR 1.9.0)</p>
 
+<h2>Open options</h2>
+
+<p>Starting with GDAL 2.0, the following open options are available.</p>
+<ul>
+<li><b>ENCODING</b>=encoding_name: to override the encoding interpretation of the
+sshapefile with any encoding supported by CPLRecode or to "" to avoid any
+recoding</li>
+<li><b>DBF_DATE_LAST_UPDATE=</b><i>YYYY-MM-DD</i>: Modification
+date to write in DBF header with year-month-day format. If not specified, current date is used.</li>
+<li><b>ADJUST_TYPE</b>=YES/NO: Set to YES (default is NO) to read the whole .dbf to adjust 
+Real->Integer/Integer64 or Integer64->Integer field types when possible. This
+can be used when field widths are ambiguous and that by default OGR would select
+the larger data type. For example, a numeric column with 0 decimal figures and with
+width of 10/11 character may hold Integer or Integer64, and with width 19/20 may
+hold Integer64 or larger integer (hold as Real)</li>
+</ul>
+
 <h2>Spatial and Attribute Indexing</h2>
 
 <p>The OGR Shapefile driver supports spatial indexing and a limited form of
@@ -126,7 +143,7 @@ with a serial number from 1 to 99. </p><p>For example:</p>
 <li>abcdefghijk → abcdefghij, abcdefghijkl → abcdefgh_1</li></ul>
 </li>
 
-<li><p> Only Integer, Real, String and Date (not DateTime, just year/month/day)
+<li><p> Only Integer, Integer64, Real, String and Date (not DateTime, just year/month/day)
 field types are supported.  The various list, and binary field types cannot
 be created.</p></li>
 
@@ -135,7 +152,11 @@ size in the .dbf file.  This means that strings longer than the field
 width, or numbers that don't fit into the indicated field format will suffer
 truncation.</p></li>
 
-<li><p> Integer fields without an explicit width are treated as width 11.</p></li>
+<li><p> Integer fields without an explicit width are treated as width 9, and
+extended to 10 or 11 if needed.</p></li>
+
+<li><p> Integer64 fields without an explicit width are treated as width 18, and
+extended to 19 or 20 if needed.</p></li>
 
 <li><p> Real (floating point) fields without an explicit width are treated as
 width 24 with 15 decimal places of precision.</p></li>
@@ -153,11 +174,14 @@ as well as deleting shapes.  Deleted shapes are marked for deletion in
 the .dbf file, and then ignored by OGR.  To actually remove them permanently
 (resulting in renumbering of FIDs) invoke the SQL 'REPACK <tablename>' via
 the datasource ExecuteSQL() method.</p>
+<p>Starting with GDAL 2.0, REPACK will also result in .shp being rewritten if
+a feature geometry has been modified with SetFeature() and resulted in a change
+of the size the binary encoding of the geometry in the .shp file.</p>
 
 <h2>Field sizes</h2>
 
 <p>Starting with GDAL/OGR 1.10, the driver knows to auto-extend string and integer fields
-(up to the 255 bytes limit imposed by the DBF format) to dynamically accomodate for
+(up to the 255 bytes limit imposed by the DBF format) to dynamically accommodate for
 the length of the data to be inserted.</p>
 
 <p>It is also possible to force a resize of the fields to the optimal width by issuing a
@@ -218,6 +242,12 @@ size. See above "Field sizes" section. Defaults to NO.</li>
 <li> <b>2GB_LIMIT=</b><i>YES/NO</i>: (OGR >= 1.11) set the YES to enforce the 2GB file size
 for .SHP or .DBF files. Defaults to NO.</li>
 
+<li> <b>SPATIAL_INDEX=</b><i>YES/NO</i>: (OGR >= 2.0) set the YES to create a spatial index (.qix). Defaults to NO.</li>
+
+<li> <b>DBF_DATE_LAST_UPDATE=</b><i>YYYY-MM-DD</i>: (OGR >= 2.0) Modification
+date to write in DBF header with year-month-day format. If not specified, current date is used.
+Note: behaviour of past GDAL releases was to write 1995-07-26</li>
+
 </ul>
 
 <h3>VSI Virtual File System API support</h3>
@@ -258,6 +288,18 @@ find existing layers and append the features being copied.</p>
 
 </ul>
 
+<h3>Advanced topics</h3>
+
+<p>
+(GDAL >= 2.0) The SHAPE_REWIND_ON_WRITE configuration option/environment
+variable can be set to NO to prevent the shapefile writer to correct the
+winding order of exterior/interior rings to be conformant with the one mandated
+by the Shapefile specification. This can be useful in some situations where
+a MultiPolygon passed to the shapefile writer is not really a compliant Single
+Feature polygon, but originates from example from a MultiPatch object (from
+a Shapefile/FileGDB/PGeo datasource).
+</p>
+
 <h3>See Also</h3>
 
 <ul>
diff --git a/ogr/ogrsf_frmts/shape/ogrshape.h b/ogr/ogrsf_frmts/shape/ogrshape.h
index 299b696..1238720 100644
--- a/ogr/ogrsf_frmts/shape/ogrshape.h
+++ b/ogr/ogrsf_frmts/shape/ogrshape.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrshape.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrshape.h 28775 2015-03-25 16:24:02Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions within the Shapefile driver to implement
@@ -53,11 +53,40 @@ OGRFeature *SHPReadOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
 OGRGeometry *SHPReadOGRObject( SHPHandle hSHP, int iShape, SHPObject *psShape );
 OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
                                        SHPHandle hSHP, DBFHandle hDBF,
-                                       const char *pszSHPEncoding );
+                                       const char *pszSHPEncoding,
+                                       int bAdjustType );
 OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                            OGRFeatureDefn *poFeatureDefn,
                            OGRFeature *poFeature, const char *pszSHPEncoding,
-                           int* pbTruncationWarningEmitted );
+                           int* pbTruncationWarningEmitted,
+                           int bRewind );
+
+/************************************************************************/
+/*                         OGRShapeGeomFieldDefn                        */
+/************************************************************************/
+
+class OGRShapeGeomFieldDefn: public OGRGeomFieldDefn
+{
+    char* pszFullName;
+    int   bSRSSet;
+    CPLString osPrjFile;
+
+    public:
+        OGRShapeGeomFieldDefn(const char* pszFullNameIn, OGRwkbGeometryType eType,
+                              int bSRSSetIn, OGRSpatialReference *poSRSIn) :
+            OGRGeomFieldDefn("", eType),
+            pszFullName(CPLStrdup(pszFullNameIn)),
+            bSRSSet(bSRSSetIn)
+        {
+            poSRS = poSRSIn;
+        }
+
+        virtual ~OGRShapeGeomFieldDefn() { CPLFree(pszFullName); }
+
+        virtual OGRSpatialReference* GetSpatialRef();
+
+        const CPLString& GetPrjFilename() { return osPrjFile; }
+};
 
 /************************************************************************/
 /*                            OGRShapeLayer                             */
@@ -85,7 +114,7 @@ class OGRShapeLayer : public OGRAbstractProxiedLayer
 
     int                 ScanIndices();
 
-    long               *panMatchingFIDs;
+    GIntBig            *panMatchingFIDs;
     int                 iMatchingFID;
     void                ClearMatchingFIDs();
 
@@ -95,6 +124,7 @@ class OGRShapeLayer : public OGRAbstractProxiedLayer
     void                ClearSpatialFIDs();
 
     int                 bHeaderDirty;
+    int                 bSHPNeedsRepack;
 
     int                 bCheckedForQIX;
     SHPTreeDiskHandle   hQIX;
@@ -120,6 +150,9 @@ class OGRShapeLayer : public OGRAbstractProxiedLayer
     int                 bResizeAtClose;
 
     void                TruncateDBF();
+    
+    int                 bCreateSpatialIndexAtClose;
+    int                 bRewindOnWrite;
 
   protected:
 
@@ -148,23 +181,24 @@ class OGRShapeLayer : public OGRAbstractProxiedLayer
                                        const char * pszName,
                                        SHPHandle hSHP, DBFHandle hDBF,
                                        OGRSpatialReference *poSRS, int bSRSSet,
-                                       int bUpdate, 
-                                       OGRwkbGeometryType eReqType );
+                                       int bUpdate,
+                                       OGRwkbGeometryType eReqType,
+                                       char ** papszCreateOptions = NULL);
                         ~OGRShapeLayer();
 
     void                ResetReading();
     OGRFeature *        GetNextFeature();
-    virtual OGRErr      SetNextByIndex( long nIndex );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
 
-    OGRFeature         *GetFeature( long nFeatureId );
-    OGRErr              SetFeature( OGRFeature *poFeature );
-    OGRErr              DeleteFeature( long nFID );
-    OGRErr              CreateFeature( OGRFeature *poFeature );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
+    OGRErr              ISetFeature( OGRFeature *poFeature );
+    OGRErr              DeleteFeature( GIntBig nFID );
+    OGRErr              ICreateFeature( OGRFeature *poFeature );
     OGRErr              SyncToDisk();
     
     OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
 
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce);
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
@@ -176,6 +210,10 @@ class OGRShapeLayer : public OGRAbstractProxiedLayer
     virtual int         TestCapability( const char * );
     virtual void        SetSpatialFilter( OGRGeometry * );
     virtual OGRErr      SetAttributeFilter( const char * );
+    
+    void                AddToFileList( CPLStringList& oFileList );
+    void                CreateSpatialIndexAtClose( int bFlag ) { bCreateSpatialIndexAtClose = bFlag; }
+    void                SetModificationDate(const char* pszStr);
 };
 
 /************************************************************************/
@@ -200,6 +238,8 @@ class OGRShapeDataSource : public OGRDataSource
     std::vector<CPLString> oVectorLayerName;
     
     int                 b2GBLimit;
+    
+    char              **papszOpenOptions;
 
   public:
                         OGRShapeDataSource();
@@ -207,7 +247,7 @@ class OGRShapeDataSource : public OGRDataSource
 
     OGRLayerPool       *GetPool() { return poPool; }
 
-    int                 Open( const char *, int bUpdate, int bTestOpen,
+    int                 Open( GDALOpenInfo* poOpenInfo, int bTestOpen,
                               int bForceSingleFileDataSource = FALSE );
     int                 OpenFile( const char *, int bUpdate, int bTestOpen );
 
@@ -217,7 +257,7 @@ class OGRShapeDataSource : public OGRDataSource
     virtual OGRLayer    *GetLayer( int );
     virtual OGRLayer    *GetLayerByName(const char *);
 
-    virtual OGRLayer    *CreateLayer( const char *, 
+    virtual OGRLayer    *ICreateLayer( const char *, 
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
@@ -229,31 +269,14 @@ class OGRShapeDataSource : public OGRDataSource
     virtual int          TestCapability( const char * );
     virtual OGRErr       DeleteLayer( int iLayer );
 
+    virtual char      **GetFileList(void);
+
     void                 SetLastUsedLayer( OGRShapeLayer* poLayer );
     void                 UnchainLayer( OGRShapeLayer* poLayer );
 
     SHPHandle            DS_SHPOpen( const char * pszShapeFile, const char * pszAccess );
     DBFHandle            DS_DBFOpen( const char * pszDBFFile, const char * pszAccess );
+    char               **GetOpenOptions() { return papszOpenOptions; }
 };
 
-/************************************************************************/
-/*                            OGRShapeDriver                            */
-/************************************************************************/
-
-class OGRShapeDriver : public OGRSFDriver
-{
-  public:
-                ~OGRShapeDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    OGRErr              DeleteDataSource( const char *pszDataSource );
-    
-    int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGRSHAPE_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp b/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp
index 1e62ff2..8dec7f7 100644
--- a/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp
+++ b/ogr/ogrsf_frmts/shape/ogrshapedatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrshapedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrshapedatasource.cpp 28585 2015-03-01 19:42:37Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRShapeDataSource class.
@@ -35,7 +35,7 @@
 
 //#define IMMEDIATE_OPENING 1
 
-CPL_CVSID("$Id: ogrshapedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrshapedatasource.cpp 28585 2015-03-01 19:42:37Z rouault $");
 
 
 /************************************************************************/
@@ -44,6 +44,10 @@ CPL_CVSID("$Id: ogrshapedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
 
 SHPHandle OGRShapeDataSource::DS_SHPOpen( const char * pszShapeFile, const char * pszAccess )
 {
+    /* Do lazy shx loading for /vsicurl/ */
+    if( strncmp(pszShapeFile, "/vsicurl/", strlen("/vsicurl/")) == 0 &&
+        strcmp(pszAccess, "r") == 0 )
+        pszAccess = "rl";
     SHPHandle hSHP = SHPOpenLL( pszShapeFile, pszAccess, (SAHooks*) VSI_SHP_GetHook(b2GBLimit) );
     if( hSHP != NULL )
         SHPSetFastModeReadObject( hSHP, TRUE );
@@ -73,8 +77,10 @@ OGRShapeDataSource::OGRShapeDataSource()
     bSingleFileDataSource = FALSE;
     poPool = new OGRLayerPool();
     b2GBLimit = CSLTestBoolean(CPLGetConfigOption("SHAPE_2GB_LIMIT", "FALSE"));
+    papszOpenOptions = NULL;
 }
 
+
 /************************************************************************/
 /*                        ~OGRShapeDataSource()                         */
 /************************************************************************/
@@ -94,20 +100,23 @@ OGRShapeDataSource::~OGRShapeDataSource()
     delete poPool;
 
     CPLFree( papoLayers );
+    CSLDestroy( papszOpenOptions );
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
+int OGRShapeDataSource::Open( GDALOpenInfo* poOpenInfo,
                               int bTestOpen, int bForceSingleFileDataSource )
 
 {
-    VSIStatBufL  stat;
-    
     CPLAssert( nLayers == 0 );
     
+    const char * pszNewName = poOpenInfo->pszFilename;
+    int bUpdate = poOpenInfo->eAccess == GA_Update;
+    papszOpenOptions = CSLDuplicate( poOpenInfo->papszOpenOptions );
+    
     pszName = CPLStrdup( pszNewName );
 
     bDSUpdate = bUpdate;
@@ -119,7 +128,7 @@ int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
 /*      This is only utilized when the OGRShapeDriver::Create()         */
 /*      method wants to create a stub OGRShapeDataSource for a          */
 /*      single shapefile.  The driver will take care of creating the    */
-/*      file by calling CreateLayer().                                  */
+/*      file by callingICreateLayer().                                  */
 /* -------------------------------------------------------------------- */
     if( bSingleFileDataSource )
         return TRUE;
@@ -127,8 +136,7 @@ int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
 /* -------------------------------------------------------------------- */
 /*      Is the given path a directory or a regular file?                */
 /* -------------------------------------------------------------------- */
-    if( VSIStatExL( pszNewName, &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG ) != 0 
-        || (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode)) )
+    if( !poOpenInfo->bStatOK )
     {
         if( !bTestOpen )
             CPLError( CE_Failure, CPLE_AppDefined,
@@ -141,7 +149,7 @@ int OGRShapeDataSource::Open( const char * pszNewName, int bUpdate,
 /* -------------------------------------------------------------------- */
 /*      Build a list of filenames we figure are Shape files.            */
 /* -------------------------------------------------------------------- */
-    if( VSI_ISREG(stat.st_mode) )
+    if( !poOpenInfo->bIsDirectory )
     {
         if( !OpenFile( pszNewName, bUpdate, bTestOpen ) )
         {
@@ -381,6 +389,8 @@ int OGRShapeDataSource::OpenFile( const char *pszNewName, int bUpdate,
 
     poLayer = new OGRShapeLayer( this, pszNewName, hSHP, hDBF, NULL, FALSE, bUpdate,
                                  wkbNone );
+    poLayer->SetModificationDate(
+            CSLFetchNameValue( papszOpenOptions, "DBF_DATE_LAST_UPDATE" ) );
 
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
@@ -414,11 +424,11 @@ void OGRShapeDataSource::AddLayer(OGRShapeLayer* poLayer)
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRShapeDataSource::CreateLayer( const char * pszLayerName,
+OGRShapeDataSource::ICreateLayer( const char * pszLayerName,
                                  OGRSpatialReference *poSRS,
                                  OGRwkbGeometryType eType,
                                  char ** papszOptions )
@@ -689,6 +699,9 @@ OGRShapeDataSource::CreateLayer( const char * pszLayerName,
     CPLFree( pszFilename );
 
     poLayer->SetResizeAtClose( CSLFetchBoolean( papszOptions, "RESIZE", FALSE ) );
+    poLayer->CreateSpatialIndexAtClose( CSLFetchBoolean( papszOptions, "SPATIAL_INDEX", FALSE ) );
+    poLayer->SetModificationDate(
+        CSLFetchNameValue( papszOptions, "DBF_DATE_LAST_UPDATE" ) );
 
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
@@ -1078,3 +1091,19 @@ void OGRShapeDataSource::SetLastUsedLayer( OGRShapeLayer* poLayer )
 
     poPool->SetLastUsedLayer(poLayer);
 }
+
+/************************************************************************/
+/*                            GetFileList()                             */
+/************************************************************************/
+
+char** OGRShapeDataSource::GetFileList()
+{
+    CPLStringList       oFileList;
+    GetLayerCount();
+    for(int i=0;i<nLayers;i++)
+    {
+        OGRShapeLayer* poLayer = papoLayers[i];
+        poLayer->AddToFileList(oFileList);
+    }
+    return oFileList.StealList();
+}
diff --git a/ogr/ogrsf_frmts/shape/ogrshapedriver.cpp b/ogr/ogrsf_frmts/shape/ogrshapedriver.cpp
index 45f029b..21f460c 100644
--- a/ogr/ogrsf_frmts/shape/ogrshapedriver.cpp
+++ b/ogr/ogrsf_frmts/shape/ogrshapedriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrshapedriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrshapedriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRShapeDriver class.
@@ -31,40 +31,60 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrshapedriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrshapedriver.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
-/*                          ~OGRShapeDriver()                           */
+/*                              Identify()                              */
 /************************************************************************/
 
-OGRShapeDriver::~OGRShapeDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRShapeDriver::GetName()
-
+static int OGRShapeDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-    return "ESRI Shapefile";
+    /* Files not ending with .shp, .shx or .dbf are not handled by this driver */
+    if( !poOpenInfo->bStatOK )
+        return FALSE;
+    if( poOpenInfo->bIsDirectory )
+        return -1; /* unsure */
+    if( poOpenInfo->fpL != NULL &&
+        (EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "SHP") ||
+         EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "SHX")) )
+    {
+        return memcmp(poOpenInfo->pabyHeader, "\x00\x00\x27\x0A", 4) == 0 ||
+               memcmp(poOpenInfo->pabyHeader, "\x00\x00\x27\x0D", 4) == 0;
+    }
+    if( poOpenInfo->fpL != NULL && EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "DBF") )
+    {
+        if( poOpenInfo->nHeaderBytes < 32 )
+            return FALSE;
+        const GByte* pabyBuf = poOpenInfo->pabyHeader;
+        unsigned int nHeadLen = pabyBuf[8] + pabyBuf[9]*256;
+        unsigned int nRecordLength = pabyBuf[10] + pabyBuf[11]*256;
+        if( nHeadLen < 32 )
+            return FALSE;
+        if( (nHeadLen % 32) != 0 && (nHeadLen % 32) != 1 )
+            return FALSE;
+        unsigned int nFields = (nHeadLen - 32) / 32;
+        if( nRecordLength < nFields )
+            return FALSE;
+        return TRUE;
+    }
+    return FALSE;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRShapeDriver::Open( const char * pszFilename,
-                                     int bUpdate )
+static GDALDataset *OGRShapeDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
     OGRShapeDataSource  *poDS;
 
+    if( OGRShapeDriverIdentify(poOpenInfo) == FALSE )
+        return NULL;
+
     poDS = new OGRShapeDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate, TRUE ) )
+    if( !poDS->Open( poOpenInfo, TRUE ) )
     {
         delete poDS;
         return NULL;
@@ -74,11 +94,15 @@ OGRDataSource *OGRShapeDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRShapeDriver::CreateDataSource( const char * pszName,
-                                                 CPL_UNUSED char **papszOptions )
+static GDALDataset *OGRShapeDriverCreate( const char * pszName,
+                                          CPL_UNUSED int nBands,
+                                          CPL_UNUSED int nXSize,
+                                          CPL_UNUSED int nYSize,
+                                          CPL_UNUSED GDALDataType eDT,
+                                          CPL_UNUSED char **papszOptions )
 {
     VSIStatBuf  stat;
     int         bSingleNewFile = FALSE;
@@ -131,7 +155,8 @@ OGRDataSource *OGRShapeDriver::CreateDataSource( const char * pszName,
 
     poDS = new OGRShapeDataSource();
     
-    if( !poDS->Open( pszName, TRUE, FALSE, bSingleNewFile ) )
+    GDALOpenInfo oOpenInfo( pszName, GA_Update );
+    if( !poDS->Open( &oOpenInfo, FALSE, bSingleNewFile ) )
     {
         delete poDS;
         return NULL;
@@ -141,10 +166,10 @@ OGRDataSource *OGRShapeDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                          DeleteDataSource()                          */
+/*                           Delete()                                   */
 /************************************************************************/
 
-OGRErr OGRShapeDriver::DeleteDataSource( const char *pszDataSource )
+static CPLErr OGRShapeDriverDelete( const char *pszDataSource )
 
 {
     int iExt;
@@ -159,7 +184,7 @@ OGRErr OGRShapeDriver::DeleteDataSource( const char *pszDataSource )
                   "%s does not appear to be a file or directory.",
                   pszDataSource );
 
-        return OGRERR_FAILURE;
+        return CE_Failure;
     }
 
     if( VSI_ISREG(sStatBuf.st_mode) 
@@ -198,23 +223,7 @@ OGRErr OGRShapeDriver::DeleteDataSource( const char *pszDataSource )
         VSIRmdir( pszDataSource );
     }
 
-    return OGRERR_NONE;
-}
-
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRShapeDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
-    else
-        return FALSE;
+    return CE_None;
 }
 
 /************************************************************************/
@@ -224,6 +233,59 @@ int OGRShapeDriver::TestCapability( const char * pszCap )
 void RegisterOGRShape()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRShapeDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "ESRI Shapefile" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "ESRI Shapefile" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "ESRI Shapefile" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "shp" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "shp dbf" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_shape.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='ENCODING' type='string' description='to override the encoding interpretation of the DBF with any encoding supported by CPLRecode or to \"\" to avoid any recoding'/>"
+"  <Option name='DBF_DATE_LAST_UPDATE' type='string' description='Modification date to write in DBF header with YYYY-MM-DD format'/>"
+"  <Option name='ADJUST_TYPE' type='boolean' description='Whether to read whole .dbf to adjust Real->Integer/Integer64 or Integer64->Integer field types if possible' default='NO'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, "<CreationOptionList/>" );
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='SHPT' type='string-select' description='type of shape' default='automatically detected'>"
+"    <Value>POINT</Value>"
+"    <Value>ARC</Value>"
+"    <Value>POLYGON</Value>"
+"    <Value>MULTIPOINT</Value>"
+"    <Value>POINTZ</Value>"
+"    <Value>ARCZ</Value>"
+"    <Value>POLYGONZ</Value>"
+"    <Value>MULTIPOINTZ</Value>"
+"    <Value>NONE</Value>"
+"    <Value>NULL</Value>"
+"  </Option>"
+"  <Option name='2GB_LIMIT' type='boolean' description='Restrict .shp and .dbf to 2GB' default='NO'/>"
+"  <Option name='ENCODING' type='string' description='DBF encoding' default='LDID/87'/>"
+"  <Option name='RESIZE' type='boolean' description='To resize fields to their optimal size.' default='NO'/>"
+"  <Option name='SPATIAL_INDEX' type='boolean' description='To create a spatial index.' default='NO'/>"
+"  <Option name='DBF_DATE_LAST_UPDATE' type='string' description='Modification date to write in DBF header with YYYY-MM-DD format'/>"
+"</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRShapeDriverOpen;
+        poDriver->pfnIdentify = OGRShapeDriverIdentify;
+        poDriver->pfnCreate = OGRShapeDriverCreate;
+        poDriver->pfnDelete = OGRShapeDriverDelete;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp b/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp
index 6ad8e79..c172754 100644
--- a/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp
+++ b/ogr/ogrsf_frmts/shape/ogrshapelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrshapelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrshapelayer.cpp 29066 2015-04-30 08:50:05Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRShapeLayer class.
@@ -32,6 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 #include "ogr_p.h"
+#include "cpl_time.h"
 
 #if defined(_WIN32_WCE)
 #  include <wce_errno.h>
@@ -43,28 +44,7 @@
 
 #define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
 
-CPL_CVSID("$Id: ogrshapelayer.cpp 27741 2014-09-26 19:20:02Z goatbar $");
-
-
-class OGRShapeGeomFieldDefn: public OGRGeomFieldDefn
-{
-    char* pszFullName;
-    int   bSRSSet;
-
-    public:
-        OGRShapeGeomFieldDefn(const char* pszFullNameIn, OGRwkbGeometryType eType,
-                              int bSRSSetIn, OGRSpatialReference *poSRSIn) :
-            OGRGeomFieldDefn("", eType),
-            pszFullName(CPLStrdup(pszFullNameIn)),
-            bSRSSet(bSRSSetIn)
-        {
-            poSRS = poSRSIn;
-        }
-
-        virtual ~OGRShapeGeomFieldDefn() { CPLFree(pszFullName); }
-
-        virtual OGRSpatialReference* GetSpatialRef();
-};
+CPL_CVSID("$Id: ogrshapelayer.cpp 29066 2015-04-30 08:50:05Z rouault $");
 
 /************************************************************************/
 /*                           OGRShapeLayer()                            */
@@ -75,7 +55,8 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
                               SHPHandle hSHPIn, DBFHandle hDBFIn, 
                               OGRSpatialReference *poSRSIn, int bSRSSetIn,
                               int bUpdate,
-                              OGRwkbGeometryType eReqType ) :
+                              OGRwkbGeometryType eReqType,
+                              char ** papszCreateOptions ) :
                                 OGRAbstractProxiedLayer(poDSIn->GetPool())
 
 {
@@ -88,6 +69,7 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
     bUpdateAccess = bUpdate;
 
     iNextShapeId = 0;
+    iMatchingFID = 0;
     panMatchingFIDs = NULL;
 
     nSpatialFIDCount = 0;
@@ -103,13 +85,14 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
     bSbnSbxDeleted = FALSE;
 
     bHeaderDirty = FALSE;
+    bSHPNeedsRepack = FALSE;
 
     if( hSHP != NULL )
     {
         nTotalShapeCount = hSHP->nRecords;
         if( hDBF != NULL && hDBF->nRecords != nTotalShapeCount )
         {
-            CPLDebug("Shape", "Inconsistant record number in .shp (%d) and in .dbf (%d)",
+            CPLDebug("Shape", "Inconsistent record number in .shp (%d) and in .dbf (%d)",
                      hSHP->nRecords, hDBF->nRecords);
         }
     }
@@ -126,6 +109,7 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
     TouchLayer();
 
     bResizeAtClose = FALSE;
+    bCreateSpatialIndexAtClose = FALSE;
 
     if( hDBF != NULL && hDBF->pszCodePage != NULL )
     {
@@ -136,8 +120,30 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
         osEncoding = ConvertCodePage( hDBF->pszCodePage );
     }
     
-    if( CPLGetConfigOption( "SHAPE_ENCODING", NULL ) != NULL )
-        osEncoding = CPLGetConfigOption( "SHAPE_ENCODING", "" );
+    if( hDBF != NULL )
+    {
+        if( !(hDBF->nUpdateYearSince1900 == 95 &&
+              hDBF->nUpdateMonth == 7 &&
+              hDBF->nUpdateDay == 26) )
+        {
+            SetMetadataItem( "DBF_DATE_LAST_UPDATE", CPLSPrintf("%04d-%02d-%02d",
+                            hDBF->nUpdateYearSince1900 + 1900,
+                            hDBF->nUpdateMonth, hDBF->nUpdateDay) );
+        }
+        struct tm tm;
+        CPLUnixTimeToYMDHMS(time(NULL), &tm);
+        DBFSetLastModifiedDate( hDBF, tm.tm_year,
+                                tm.tm_mon + 1, tm.tm_mday );
+    }
+    
+    const char* pszShapeEncoding = NULL;
+    pszShapeEncoding = CSLFetchNameValue(poDS->GetOpenOptions(), "ENCODING");
+    if( pszShapeEncoding == NULL && osEncoding == "")
+        pszShapeEncoding = CSLFetchNameValue( papszCreateOptions, "ENCODING" );
+    if( pszShapeEncoding == NULL )
+        pszShapeEncoding = CPLGetConfigOption( "SHAPE_ENCODING", NULL );
+    if( pszShapeEncoding != NULL )
+        osEncoding = pszShapeEncoding;
 
     if( osEncoding != "" )
     {
@@ -151,7 +157,8 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
     }
 
     poFeatureDefn = SHPReadOGRFeatureDefn( CPLGetBasename(pszFullName),
-                                           hSHP, hDBF, osEncoding );
+                                           hSHP, hDBF, osEncoding,
+               CSLFetchBoolean(poDS->GetOpenOptions(), "ADJUST_TYPE", FALSE) );
 
     /* To make sure that GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef() == GetSpatialRef() */
     OGRwkbGeometryType eGeomType = poFeatureDefn->GetGeomType();
@@ -164,6 +171,8 @@ OGRShapeLayer::OGRShapeLayer( OGRShapeDataSource* poDSIn,
     }
     else if( bSRSSetIn && poSRSIn != NULL )
         poSRSIn->Release();
+    SetDescription( poFeatureDefn->GetName() );
+    bRewindOnWrite = CSLTestBoolean(CPLGetConfigOption( "SHAPE_REWIND_ON_WRITE", "YES" ));
 }
 
 /************************************************************************/
@@ -177,6 +186,10 @@ OGRShapeLayer::~OGRShapeLayer()
     {
         ResizeDBF();
     }
+    if( bCreateSpatialIndexAtClose && hSHP != NULL )
+    {
+        CreateSpatialIndex(0);
+    }
 
     if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
     {
@@ -206,6 +219,26 @@ OGRShapeLayer::~OGRShapeLayer()
         SBNCloseDiskTree( hSBN );
 }
 
+
+/************************************************************************/
+/*                       SetModificationDate()                          */
+/************************************************************************/
+
+void OGRShapeLayer::SetModificationDate(const char* pszStr)
+{
+    if( hDBF && pszStr )
+    {
+        int year, month, day;
+        if ((sscanf(pszStr, "%04d-%02d-%02d", &year, &month, &day) == 3 ||
+             sscanf(pszStr, "%04d/%02d/%02d", &year, &month, &day) == 3) &&
+            (year >= 1900 && year <= 1900 + 255 && month >= 1 && month <= 12 &&
+             day >= 1 && day <= 31))
+        {
+            DBFSetLastModifiedDate( hDBF, year - 1900, month, day );
+        }
+    }
+}
+
 /************************************************************************/
 /*                          ConvertCodePage()                           */
 /************************************************************************/
@@ -476,10 +509,10 @@ int OGRShapeLayer::ScanIndices()
         {
             int i;
 
-            panMatchingFIDs = (long *)
-                CPLMalloc(sizeof(long) * (nSpatialFIDCount+1) );
+            panMatchingFIDs = (GIntBig *)
+                CPLMalloc(sizeof(GIntBig) * (nSpatialFIDCount+1) );
             for( i = 0; i < nSpatialFIDCount; i++ )
-                panMatchingFIDs[i] = (long) panSpatialFIDs[i];
+                panMatchingFIDs[i] = (GIntBig) panSpatialFIDs[i];
             panMatchingFIDs[nSpatialFIDCount] = OGRNullFID;
         }
 
@@ -584,7 +617,7 @@ void OGRShapeLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
     {
         /* We clear the spatialFIDs only if we have a new non-NULL */
         /* spatial filter, otherwise we keep the previous result */
-        /* cached. This can be usefull when several SQL layers */
+        /* cached. This can be useful when several SQL layers */
         /* rely on the same table layer, and use the same spatial */
         /* filters. But as there is in the destructor of OGRGenSQLResultsLayer */
         /* a clearing of the spatial filter of the table layer, we */
@@ -613,13 +646,13 @@ OGRErr OGRShapeLayer::SetAttributeFilter( const char * pszAttributeFilter )
 /*      ourselves in it.                                                */
 /************************************************************************/
 
-OGRErr OGRShapeLayer::SetNextByIndex( long nIndex )
+OGRErr OGRShapeLayer::SetNextByIndex( GIntBig nIndex )
 
 {
     if (!TouchLayer())
         return OGRERR_FAILURE;
 
-    if( nIndex < 0 )
+    if( nIndex < 0 || nIndex > INT_MAX )
         return OGRERR_FAILURE;
 
     // Eventually we should try to use panMatchingFIDs list 
@@ -627,7 +660,7 @@ OGRErr OGRShapeLayer::SetNextByIndex( long nIndex )
     if( m_poFilterGeom != NULL || m_poAttrQuery != NULL )
         return OGRLayer::SetNextByIndex( nIndex );
 
-    iNextShapeId = nIndex;
+    iNextShapeId = (int)nIndex;
 
     return OGRERR_NONE;
 }
@@ -729,7 +762,7 @@ OGRFeature *OGRShapeLayer::GetNextFeature()
             
             // Check the shape object's geometry, and if it matches
             // any spatial filter, return it.  
-            poFeature = FetchShape(panMatchingFIDs[iMatchingFID] /*, &oShapeExtent*/);
+            poFeature = FetchShape((int)panMatchingFIDs[iMatchingFID] /*, &oShapeExtent*/);
             
             iMatchingFID++;
 
@@ -781,14 +814,14 @@ OGRFeature *OGRShapeLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRShapeLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRShapeLayer::GetFeature( GIntBig nFeatureId )
 
 {
-    if (!TouchLayer())
+    if (!TouchLayer() || nFeatureId > INT_MAX )
         return NULL;
 
     OGRFeature *poFeature = NULL;
-    poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn, nFeatureId, NULL,
+    poFeature = SHPReadOGRFeature( hSHP, hDBF, poFeatureDefn, (int)nFeatureId, NULL,
                                    osEncoding );
 
     if( poFeature != NULL )
@@ -810,10 +843,10 @@ OGRFeature *OGRShapeLayer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRShapeLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRShapeLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     if (!TouchLayer())
@@ -827,33 +860,50 @@ OGRErr OGRShapeLayer::SetFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
-    long nFID = poFeature->GetFID();
+    GIntBig nFID = poFeature->GetFID();
     if( nFID < 0
         || (hSHP != NULL && nFID >= hSHP->nRecords)
         || (hDBF != NULL && nFID >= hDBF->nRecords) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Attempt to set shape with feature id (%ld) which does "
-                  "not exist.", nFID );
-        return OGRERR_FAILURE;
+        return OGRERR_NON_EXISTING_FEATURE;
     }
 
     bHeaderDirty = TRUE;
     if( CheckForQIX() || CheckForSBN() )
         DropSpatialIndex();
 
-    return SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature,
-                               osEncoding, &bTruncationWarningEmitted );
+    unsigned int nOffset = 0;
+    unsigned int nSize = 0;
+    if( hSHP != NULL )
+    {
+        nOffset = hSHP->panRecOffset[nFID];
+        nSize = hSHP->panRecSize[nFID];
+    }
+
+    OGRErr eErr = SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature,
+                                      osEncoding, &bTruncationWarningEmitted,
+                                      bRewindOnWrite );
+
+    if( hSHP != NULL )
+    {
+        if( nOffset != hSHP->panRecOffset[nFID] ||
+            nSize != hSHP->panRecSize[nFID] )
+        {
+            bSHPNeedsRepack = TRUE;
+        }
+    }
+
+    return eErr;
 }
 
 /************************************************************************/
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRShapeLayer::DeleteFeature( long nFID )
+OGRErr OGRShapeLayer::DeleteFeature( GIntBig nFID )
 
 {
-    if (!TouchLayer())
+    if (!TouchLayer() || nFID > INT_MAX )
         return OGRERR_FAILURE;
 
     if( !bUpdateAccess )
@@ -868,10 +918,7 @@ OGRErr OGRShapeLayer::DeleteFeature( long nFID )
         || (hSHP != NULL && nFID >= hSHP->nRecords)
         || (hDBF != NULL && nFID >= hDBF->nRecords) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Attempt to delete shape with feature id (%ld) which does "
-                  "not exist.", nFID );
-        return OGRERR_FAILURE;
+        return OGRERR_NON_EXISTING_FEATURE;
     }
 
     if( !hDBF )
@@ -883,15 +930,12 @@ OGRErr OGRShapeLayer::DeleteFeature( long nFID )
         return OGRERR_FAILURE;
     }
 
-    if( DBFIsRecordDeleted( hDBF, nFID ) )
+    if( DBFIsRecordDeleted( hDBF, (int)nFID ) )
     {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Attempt to delete shape with feature id (%ld), but it is marked deleted already.",
-                  nFID );
-        return OGRERR_FAILURE;
+        return OGRERR_NON_EXISTING_FEATURE;
     }
 
-    if( !DBFMarkRecordDeleted( hDBF, nFID, TRUE ) )
+    if( !DBFMarkRecordDeleted( hDBF, (int)nFID, TRUE ) )
         return OGRERR_FAILURE;
 
     bHeaderDirty = TRUE;
@@ -902,10 +946,10 @@ OGRErr OGRShapeLayer::DeleteFeature( long nFID )
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRShapeLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRShapeLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     OGRErr eErr;
@@ -998,7 +1042,8 @@ OGRErr OGRShapeLayer::CreateFeature( OGRFeature *poFeature )
     }
     
     eErr = SHPWriteOGRFeature( hSHP, hDBF, poFeatureDefn, poFeature, 
-                               osEncoding, &bTruncationWarningEmitted );
+                               osEncoding, &bTruncationWarningEmitted,
+                               bRewindOnWrite );
 
     if( hSHP != NULL )
         nTotalShapeCount = hSHP->nRecords;
@@ -1050,7 +1095,7 @@ int OGRShapeLayer::GetFeatureCountWithSpatialFilterOnly()
 
         if( panMatchingFIDs != NULL )
         {
-            iShape = panMatchingFIDs[iLocalMatchingFID];
+            iShape = (int)panMatchingFIDs[iLocalMatchingFID];
             if( iShape == OGRNullFID )
                 break;
             iLocalMatchingFID++;
@@ -1072,7 +1117,8 @@ int OGRShapeLayer::GetFeatureCountWithSpatialFilterOnly()
         }
 
         /* Read full shape for point layers */
-        if (bExpectPoints)
+        if (bExpectPoints ||
+            hSHP->panRecOffset[iShape] == 0 /* lazy shx loading case */ )
             psShape = SHPReadObject( hSHP, iShape);
 
 /* -------------------------------------------------------------------- */
@@ -1219,7 +1265,7 @@ int OGRShapeLayer::GetFeatureCountWithSpatialFilterOnly()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRShapeLayer::GetFeatureCount( int bForce )
+GIntBig OGRShapeLayer::GetFeatureCount( int bForce )
 
 {
     /* Check if the spatial filter is non-trivial */
@@ -1266,7 +1312,7 @@ int OGRShapeLayer::GetFeatureCount( int bForce )
         if (!AttributeFilterEvaluationNeedsGeometry())
             poFeatureDefn->SetGeometryIgnored(TRUE);
 
-        int nRet = OGRLayer::GetFeatureCount( bForce );
+        GIntBig nRet = OGRLayer::GetFeatureCount( bForce );
 
         poFeatureDefn->SetGeometryIgnored(bSaveGeometryIgnored);
         return nRet;
@@ -1304,6 +1350,26 @@ OGRErr OGRShapeLayer::GetExtent (OGREnvelope *psExtent, int bForce)
     psExtent->MinY = adMin[1];
     psExtent->MaxX = adMax[0];
     psExtent->MaxY = adMax[1];
+    
+    if( CPLIsNan(adMin[0]) || CPLIsNan(adMin[1]) ||
+        CPLIsNan(adMax[0]) || CPLIsNan(adMax[1]) )
+    {
+        CPLDebug("SHAPE", "Invalid extent in shape header");
+        OGRErr eErr;
+
+        /* Disable filters to avoid infinite recursion in GetNextFeature() */
+        /* that calls ScanIndices() that call GetExtent... */
+        OGRFeatureQuery* poAttrQuery = m_poAttrQuery;
+        m_poAttrQuery = NULL;
+        OGRGeometry* poFilterGeom = m_poFilterGeom;
+        m_poFilterGeom = NULL;
+        
+        eErr = OGRLayer::GetExtent(psExtent, bForce);
+        
+        m_poAttrQuery = poAttrQuery;
+        m_poFilterGeom = poFilterGeom;
+        return eErr;
+    }
 
     return OGRERR_NONE;
 }
@@ -1548,7 +1614,13 @@ OGRErr OGRShapeLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
         case OFTInteger:
             chType = 'N';
             nWidth = oModFieldDefn.GetWidth();
-            if (nWidth == 0) nWidth = 10;
+            if (nWidth == 0) nWidth = 9;
+            break;
+
+        case OFTInteger64:
+            chType = 'N';
+            nWidth = oModFieldDefn.GetWidth();
+            if (nWidth == 0) nWidth = 18;
             break;
 
         case OFTReal:
@@ -1610,6 +1682,12 @@ OGRErr OGRShapeLayer::CreateField( OGRFieldDefn *poFieldDefn, int bApproxOK )
         return OGRERR_FAILURE;
     }
 
+    /* Suppress the dummy FID field if we have created it just before */
+    if( DBFGetFieldCount( hDBF ) == 1 && poFeatureDefn->GetFieldCount() == 0 )
+    {
+        DBFDeleteField( hDBF, 0 );
+    }
+
     iNewField =
         DBFAddNativeFieldType( hDBF, szNewFieldName,
                                chType, nWidth, nDecimals );
@@ -1743,7 +1821,11 @@ OGRErr OGRShapeLayer::AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn,
     if ((nFlags & ALTER_TYPE_FLAG) &&
         poNewFieldDefn->GetType() != poFieldDefn->GetType())
     {
-        if (poNewFieldDefn->GetType() != OFTString)
+        if (poNewFieldDefn->GetType() == OFTInteger64 && poFieldDefn->GetType() == OFTInteger )
+        {
+            eType = poNewFieldDefn->GetType();
+        }
+        else if (poNewFieldDefn->GetType() != OFTString)
         {
             CPLError( CE_Failure, CPLE_NotSupported,
                       "Can only convert to OFTString");
@@ -1836,7 +1918,17 @@ OGRSpatialReference *OGRShapeGeomFieldDefn::GetSpatialRef()
 
     if( papszLines != NULL )
     {
+        osPrjFile = pszPrjFile;
+
         poSRS = new OGRSpatialReference();
+        /* Remove UTF-8 BOM if found */
+        /* http://lists.osgeo.org/pipermail/gdal-dev/2014-July/039527.html */
+        if( ((unsigned char)papszLines[0][0] == 0xEF) &&
+            ((unsigned char)papszLines[0][1] == 0xBB) &&
+            ((unsigned char)papszLines[0][2] == 0xBF) )
+        {
+            memmove(papszLines[0], papszLines[0] + 3, strlen(papszLines[0] + 3) + 1);
+        }
         if( poSRS->importFromESRI( papszLines ) != OGRERR_NONE )
         {
             delete poSRS;
@@ -1946,7 +2038,9 @@ OGRErr OGRShapeLayer::SyncToDisk()
     }
 
     if( hDBF != NULL )
+    {
         hDBF->sHooks.FFlush( hDBF->fp );
+    }
 
     return OGRERR_NONE;
 }
@@ -2104,54 +2198,50 @@ OGRErr OGRShapeLayer::Repack()
                   "Repack");
         return OGRERR_FAILURE;
     }
-    
-    if( hDBF == NULL )
-    {
-        CPLError( CE_Failure, CPLE_NotSupported, 
-                  "Attempt to repack a shapefile with no .dbf file not supported.");
-        return OGRERR_FAILURE;
-    }
-    
+
 /* -------------------------------------------------------------------- */
 /*      Build a list of records to be dropped.                          */
 /* -------------------------------------------------------------------- */
-    int *panRecordsToDelete = NULL;
-    int nDeleteCount = 0, nDeleteCountAlloc = 0;
+    int *panRecordsToDelete = (int*) CPLMalloc(sizeof(int)*128);
+    int nDeleteCount = 0, nDeleteCountAlloc = 128;
     int iShape = 0;
     OGRErr eErr = OGRERR_NONE;
 
-    for( iShape = 0; iShape < nTotalShapeCount; iShape++ )
+    if( hDBF != NULL )
     {
-        if( DBFIsRecordDeleted( hDBF, iShape ) )
+        for( iShape = 0; iShape < nTotalShapeCount; iShape++ )
         {
-            if( nDeleteCount == nDeleteCountAlloc )
+            if( DBFIsRecordDeleted( hDBF, iShape ) )
             {
-                int nDeleteCountAllocNew =
-                    nDeleteCountAlloc + nDeleteCountAlloc / 3 + 32;
-                if( nDeleteCountAlloc >= (INT_MAX - 32) / 4 * 3 ||
-                    nDeleteCountAllocNew > INT_MAX / (int)sizeof(int) )
-                {
-                    CPLError( CE_Failure, CPLE_AppDefined,
-                              "Too many features to delete : %d", nDeleteCount );
-                    CPLFree( panRecordsToDelete );
-                    return OGRERR_FAILURE;
-                }
-                nDeleteCountAlloc = nDeleteCountAllocNew;
-                int* panRecordsToDeleteNew = (int*) VSIRealloc(
-                    panRecordsToDelete, nDeleteCountAlloc * sizeof(int) );
-                if( panRecordsToDeleteNew == NULL )
+                if( nDeleteCount == nDeleteCountAlloc )
                 {
-                    CPLFree( panRecordsToDelete );
-                    return OGRERR_FAILURE;
+                    int nDeleteCountAllocNew =
+                        nDeleteCountAlloc + nDeleteCountAlloc / 3 + 32;
+                    if( nDeleteCountAlloc >= (INT_MAX - 32) / 4 * 3 ||
+                        nDeleteCountAllocNew > INT_MAX / (int)sizeof(int) )
+                    {
+                        CPLError( CE_Failure, CPLE_AppDefined,
+                                "Too many features to delete : %d", nDeleteCount );
+                        CPLFree( panRecordsToDelete );
+                        return OGRERR_FAILURE;
+                    }
+                    nDeleteCountAlloc = nDeleteCountAllocNew;
+                    int* panRecordsToDeleteNew = (int*) VSIRealloc(
+                        panRecordsToDelete, nDeleteCountAlloc * sizeof(int) );
+                    if( panRecordsToDeleteNew == NULL )
+                    {
+                        CPLFree( panRecordsToDelete );
+                        return OGRERR_FAILURE;
+                    }
+                    panRecordsToDelete = panRecordsToDeleteNew;
                 }
-                panRecordsToDelete = panRecordsToDeleteNew;
+                panRecordsToDelete[nDeleteCount++] = iShape;
+            }
+            if( VSIFEofL(VSI_SHP_GetVSIL(hDBF->fp)) )
+            {
+                CPLFree( panRecordsToDelete );
+                return OGRERR_FAILURE; /* There's an I/O error */
             }
-            panRecordsToDelete[nDeleteCount++] = iShape;
-        }
-        if( VSIFEofL(VSI_SHP_GetVSIL(hDBF->fp)) )
-        {
-            CPLFree( panRecordsToDelete );
-            return OGRERR_FAILURE; /* There's an I/O error */
         }
     }
 
@@ -2159,7 +2249,7 @@ OGRErr OGRShapeLayer::Repack()
 /*      If there are no records marked for deletion, we take no         */
 /*      action.                                                         */
 /* -------------------------------------------------------------------- */
-    if( nDeleteCount == 0 )
+    if( nDeleteCount == 0 && !bSHPNeedsRepack )
     {
         CPLFree( panRecordsToDelete );
         return OGRERR_NONE;
@@ -2202,7 +2292,7 @@ OGRErr OGRShapeLayer::Repack()
     CSLDestroy(papszCandidates);
     papszCandidates = NULL;
     
-    if (osDBFName.size() == 0)
+    if( hDBF != NULL && osDBFName.size() == 0)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "Cannot find the filename of the DBF file, but we managed to open it before !");
@@ -2239,88 +2329,93 @@ OGRErr OGRShapeLayer::Repack()
 /* -------------------------------------------------------------------- */
 /*      Create a new dbf file, matching the old.                        */
 /* -------------------------------------------------------------------- */
-    DBFHandle hNewDBF = NULL;
-    
-    CPLString oTempFile(CPLFormFilename(osDirname, osBasename, NULL));
-    oTempFile += "_packed.dbf";
+    int bMustReopenDBF = FALSE;
 
-    hNewDBF = DBFCloneEmpty( hDBF, oTempFile );
-    if( hNewDBF == NULL )
+    if( hDBF != NULL && nDeleteCount > 0 )
     {
-        CPLFree( panRecordsToDelete );
+        bMustReopenDBF = TRUE;
 
-        CPLError( CE_Failure, CPLE_OpenFailed, 
-                  "Failed to create temp file %s.", 
-                  oTempFile.c_str() );
-        return OGRERR_FAILURE;
-    }
+        CPLString oTempFile(CPLFormFilename(osDirname, osBasename, NULL));
+        oTempFile += "_packed.dbf";
 
-    /* Delete temporary .cpg file if existing */
-    if( osCPGName.size() )
-    {
-        CPLString oCPGTempFile = CPLFormFilename(osDirname, osBasename, NULL);
-        oCPGTempFile += "_packed.cpg";
-        if( VSIUnlink( oCPGTempFile ) != 0 )
+        DBFHandle hNewDBF = DBFCloneEmpty( hDBF, oTempFile );
+        if( hNewDBF == NULL )
         {
-            CPLDebug( "Shape", "Did not manage to remove temporary .cpg file: %s",
-                      VSIStrerror( errno ) );
+            CPLFree( panRecordsToDelete );
+
+            CPLError( CE_Failure, CPLE_OpenFailed, 
+                    "Failed to create temp file %s.", 
+                    oTempFile.c_str() );
+            return OGRERR_FAILURE;
+        }
+
+        /* Delete temporary .cpg file if existing */
+        if( osCPGName.size() )
+        {
+            CPLString oCPGTempFile = CPLFormFilename(osDirname, osBasename, NULL);
+            oCPGTempFile += "_packed.cpg";
+            if( VSIUnlink( oCPGTempFile ) != 0 )
+            {
+                CPLDebug( "Shape", "Did not manage to remove temporary .cpg file: %s",
+                        VSIStrerror( errno ) );
+            }
         }
-    }
 
 /* -------------------------------------------------------------------- */
 /*      Copy over all records that are not deleted.                     */
 /* -------------------------------------------------------------------- */
-    int iDestShape = 0;
-    int iNextDeletedShape = 0;
+        int iDestShape = 0;
+        int iNextDeletedShape = 0;
 
-    for( iShape = 0; 
-         iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
-         iShape++ )
-    {
-        if( panRecordsToDelete[iNextDeletedShape] == iShape )
-            iNextDeletedShape++;
-        else
+        for( iShape = 0; 
+            iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
+            iShape++ )
         {
-            void *pTuple = (void *) DBFReadTuple( hDBF, iShape );
-            if( pTuple == NULL )
-                eErr = OGRERR_FAILURE;
-            else if( !DBFWriteTuple( hNewDBF, iDestShape++, pTuple ) )
-                eErr = OGRERR_FAILURE;
-        }                           
-    }
+            if( panRecordsToDelete[iNextDeletedShape] == iShape )
+                iNextDeletedShape++;
+            else
+            {
+                void *pTuple = (void *) DBFReadTuple( hDBF, iShape );
+                if( pTuple == NULL )
+                    eErr = OGRERR_FAILURE;
+                else if( !DBFWriteTuple( hNewDBF, iDestShape++, pTuple ) )
+                    eErr = OGRERR_FAILURE;
+            }                           
+        }
 
-    if( eErr != OGRERR_NONE )
-    {
-        CPLFree( panRecordsToDelete );
-        VSIUnlink( oTempFile );
-        DBFClose( hNewDBF );
-        return eErr;
-    }
+        if( eErr != OGRERR_NONE )
+        {
+            CPLFree( panRecordsToDelete );
+            VSIUnlink( oTempFile );
+            DBFClose( hNewDBF );
+            return eErr;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Cleanup the old .dbf and rename the new one.                    */
 /* -------------------------------------------------------------------- */
-    DBFClose( hDBF );
-    DBFClose( hNewDBF );
-    hDBF = hNewDBF = NULL;
+        DBFClose( hDBF );
+        DBFClose( hNewDBF );
+        hDBF = hNewDBF = NULL;
 
-    if( VSIUnlink( osDBFName ) != 0 )
-    {
-        CPLDebug( "Shape", "Failed to delete DBF file: %s", VSIStrerror( errno ) );
-        CPLFree( panRecordsToDelete );
+        if( VSIUnlink( osDBFName ) != 0 )
+        {
+            CPLDebug( "Shape", "Failed to delete DBF file: %s", VSIStrerror( errno ) );
+            CPLFree( panRecordsToDelete );
 
-        hDBF = poDS->DS_DBFOpen ( osDBFName, bUpdateAccess ? "r+" : "r" );
+            hDBF = poDS->DS_DBFOpen ( osDBFName, bUpdateAccess ? "r+" : "r" );
 
-        VSIUnlink( oTempFile );
+            VSIUnlink( oTempFile );
 
-        return OGRERR_FAILURE;
-    }
-        
-    if( VSIRename( oTempFile, osDBFName ) != 0 )
-    {
-        CPLDebug( "Shape", "Can not rename DBF file: %s", VSIStrerror( errno ) );
-        CPLFree( panRecordsToDelete );
-        return OGRERR_FAILURE;
+            return OGRERR_FAILURE;
+        }
+            
+        if( VSIRename( oTempFile, osDBFName ) != 0 )
+        {
+            CPLDebug( "Shape", "Can not rename DBF file: %s", VSIStrerror( errno ) );
+            CPLFree( panRecordsToDelete );
+            return OGRERR_FAILURE;
+        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -2332,7 +2427,7 @@ OGRErr OGRShapeLayer::Repack()
     {
         SHPHandle hNewSHP = NULL;
 
-        oTempFile = CPLFormFilename(osDirname, osBasename, NULL);
+        CPLString oTempFile = CPLFormFilename(osDirname, osBasename, NULL);
         oTempFile += "_packed.shp";
 
         hNewSHP = SHPCreate( oTempFile, hSHP->nShapeType );
@@ -2345,7 +2440,7 @@ OGRErr OGRShapeLayer::Repack()
 /* -------------------------------------------------------------------- */
 /*      Copy over all records that are not deleted.                     */
 /* -------------------------------------------------------------------- */
-        iNextDeletedShape = 0;
+        int iNextDeletedShape = 0;
 
         for( iShape = 0; 
              iShape < nTotalShapeCount && eErr == OGRERR_NONE; 
@@ -2415,8 +2510,6 @@ OGRErr OGRShapeLayer::Repack()
 /* If all operations above succeeded, then all necessery files are      */
 /* in the right place and accessible.                                   */
 /* -------------------------------------------------------------------- */
-    CPLAssert( NULL == hSHP );
-    CPLAssert( NULL == hDBF && NULL == hNewDBF );
     
     const char* pszAccess = NULL;
     if( bUpdateAccess )
@@ -2426,15 +2519,17 @@ OGRErr OGRShapeLayer::Repack()
     
     if( bMustReopenSHP )
         hSHP = poDS->DS_SHPOpen ( osSHPName , pszAccess );
-    hDBF = poDS->DS_DBFOpen ( osDBFName , pszAccess );
+    if( bMustReopenDBF )
+        hDBF = poDS->DS_DBFOpen ( osDBFName , pszAccess );
 
-    if( (bMustReopenSHP && NULL == hSHP) || NULL == hDBF )
+    if( (bMustReopenSHP && NULL == hSHP) || (bMustReopenDBF && NULL == hDBF) )
         return OGRERR_FAILURE;
 
 /* -------------------------------------------------------------------- */
 /*      Update total shape count.                                       */
 /* -------------------------------------------------------------------- */
     nTotalShapeCount = hDBF->nRecords;
+    bSHPNeedsRepack = FALSE;
 
     return OGRERR_NONE;
 }
@@ -2476,7 +2571,8 @@ OGRErr OGRShapeLayer::ResizeDBF()
     for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
     {
         if( poFeatureDefn->GetFieldDefn(i)->GetType() == OFTString ||
-            poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger )
+            poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger ||
+            poFeatureDefn->GetFieldDefn(i)->GetType() == OFTInteger64 )
         {
             panColMap[nStringCols] = i;
             panBestWidth[nStringCols] = 1;
@@ -2764,3 +2860,55 @@ void OGRShapeLayer::CloseUnderlyingLayer()
 
     eFileDescriptorsState = FD_CLOSED;
 }
+
+/************************************************************************/
+/*                            AddToFileList()                           */
+/************************************************************************/
+
+void OGRShapeLayer::AddToFileList( CPLStringList& oFileList )
+{
+    if (!TouchLayer())
+        return;
+    if( hSHP )
+    {
+        const char* pszSHPFilename = VSI_SHP_GetFilename( hSHP->fpSHP );
+        oFileList.AddString(pszSHPFilename);
+        const char* pszSHPExt = CPLGetExtension(pszSHPFilename);
+        const char* pszSHXFilename = CPLResetExtension( pszSHPFilename,
+                                        (pszSHPExt[0] == 's') ? "shx" : "SHX" );
+        oFileList.AddString(pszSHXFilename);
+    }
+    if( hDBF )
+    {
+        const char* pszDBFFilename = VSI_SHP_GetFilename( hDBF->fp );
+        oFileList.AddString(pszDBFFilename);
+        if( hDBF->pszCodePage != NULL && hDBF->iLanguageDriver == 0 )
+        {
+            const char* pszDBFExt = CPLGetExtension(pszDBFFilename);
+            const char* pszCPGFilename = CPLResetExtension( pszDBFFilename,
+                                       (pszDBFExt[0] == 'd') ? "cpg" : "CPG"  );
+            oFileList.AddString(pszCPGFilename);
+        }
+    }
+    if( hSHP )
+    {
+        if( GetSpatialRef() != NULL )
+        {
+            OGRShapeGeomFieldDefn* poGeomFieldDefn =
+                (OGRShapeGeomFieldDefn*)GetLayerDefn()->GetGeomFieldDefn(0);
+            oFileList.AddString(poGeomFieldDefn->GetPrjFilename());
+        }
+        if( CheckForQIX() )
+        {
+            const char* pszQIXFilename = CPLResetExtension( pszFullName, "qix" );
+            oFileList.AddString(pszQIXFilename);
+        }
+        else if( CheckForSBN() )
+        {
+            const char* pszSBNFilename = CPLResetExtension( pszFullName, "sbn" );
+            oFileList.AddString(pszSBNFilename);
+            const char* pszSBXFilename = CPLResetExtension( pszFullName, "sbx" );
+            oFileList.AddString(pszSBXFilename);
+        }
+    }
+}
diff --git a/ogr/ogrsf_frmts/shape/sbnsearch.c b/ogr/ogrsf_frmts/shape/sbnsearch.c
index 8592c06..727f9a8 100644
--- a/ogr/ogrsf_frmts/shape/sbnsearch.c
+++ b/ogr/ogrsf_frmts/shape/sbnsearch.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: sbnsearch.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: sbnsearch.c 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  Shapelib
  * Purpose:  Implementation of search in ESRI SBN spatial index.
@@ -40,7 +40,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-SHP_CVSID("$Id: sbnsearch.c 27044 2014-03-16 23:41:27Z rouault $")
+SHP_CVSID("$Id: sbnsearch.c 28039 2014-11-30 18:24:59Z rouault $")
 
 #ifndef TRUE
 #  define TRUE 1
@@ -328,7 +328,7 @@ SBNSearchHandle SBNOpenDiskTree( const char* pszSBNFilename,
         if ((nBinStart > 0 && nNodeShapeCount == 0) ||
             nNodeShapeCount < 0 || nNodeShapeCount > nShapeCount)
         {
-            hSBN->sHooks.Error( "Inconsistant shape count in bin" );
+            hSBN->sHooks.Error( "Inconsistent shape count in bin" );
             SBNCloseDiskTree(hSBN);
             return NULL;
         }
@@ -637,7 +637,7 @@ static int SBNSearchDiskInternal( SearchStruct* psSearch,
             {
                 free(psNode->pabyShapeDesc);
                 psNode->pabyShapeDesc = NULL;
-                hSBN->sHooks.Error( "Inconsistant shape count for bin" );
+                hSBN->sHooks.Error( "Inconsistent shape count for bin" );
                 return FALSE;
             }
 
@@ -684,7 +684,7 @@ static int SBNSearchDiskInternal( SearchStruct* psSearch,
 #ifdef sanity_checks
 /* -------------------------------------------------------------------- */
 /*      Those tests only check that the shape bounding box in the bin   */
-/*      are consistant (self-consistant and consistant with the node    */
+/*      are consistent (self-consistent and consistent with the node    */
 /*      they are attached to). They are optional however (as far as     */
 /*      the safety of runtime is concerned at least).                   */
 /* -------------------------------------------------------------------- */
@@ -737,7 +737,7 @@ static int SBNSearchDiskInternal( SearchStruct* psSearch,
         {
             free(psNode->pabyShapeDesc);
             psNode->pabyShapeDesc = NULL;
-            hSBN->sHooks.Error( "Inconsistant shape count for bin" );
+            hSBN->sHooks.Error( "Inconsistent shape count for bin" );
             return FALSE;
         }
 
diff --git a/ogr/ogrsf_frmts/shape/shape2ogr.cpp b/ogr/ogrsf_frmts/shape/shape2ogr.cpp
index 93f98e0..4898dd7 100644
--- a/ogr/ogrsf_frmts/shape/shape2ogr.cpp
+++ b/ogr/ogrsf_frmts/shape/shape2ogr.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: shape2ogr.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: shape2ogr.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements translation of Shapefile shapes into OGR
@@ -32,7 +32,7 @@
 #include "ogrshape.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: shape2ogr.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: shape2ogr.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 /************************************************************************/
 /*                        RingStartEnd                                  */
@@ -460,7 +460,8 @@ OGRGeometry *SHPReadOGRObject( SHPHandle hSHP, int iShape, SHPObject *psShape )
 /*                         SHPWriteOGRObject()                          */
 /************************************************************************/
 
-OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom )
+OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom,
+                          int bRewind)
 
 {
     int nReturnedShapeID;
@@ -846,7 +847,8 @@ OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom )
         psShape = SHPCreateObject( hSHP->nShapeType, iShape, nRings,
                                    panRingStart, NULL,
                                    nVertex, padfX, padfY, padfZ, NULL );
-        SHPRewindObject( hSHP, psShape );
+        if( bRewind )
+            SHPRewindObject( hSHP, psShape );
         nReturnedShapeID = SHPWriteObject( hSHP, iShape, psShape );
         SHPDestroyObject( psShape );
         
@@ -873,19 +875,20 @@ OGRErr SHPWriteOGRObject( SHPHandle hSHP, int iShape, OGRGeometry *poGeom )
 
 OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
                                        SHPHandle hSHP, DBFHandle hDBF,
-                                       const char* pszSHPEncoding )
+                                       const char* pszSHPEncoding,
+                                       int bAdjustType )
 
 {
     OGRFeatureDefn      *poDefn = new OGRFeatureDefn( pszName );
     int                 iField;
+    int                 nAdjustableFields = 0;
+    int                 nFieldCount = (hDBF) ? DBFGetFieldCount(hDBF) : 0;
 
     poDefn->Reference();
 
-    for( iField = 0; 
-         hDBF != NULL && iField < DBFGetFieldCount( hDBF ); 
-         iField++ )
+    for( iField = 0; iField < nFieldCount; iField++ )
     {
-        char            szFieldName[20];
+        char            szFieldName[12] = {};
         int             nWidth, nPrecision;
         DBFFieldType    eDBFType;
         OGRFieldDefn    oField("", OFTInteger);
@@ -921,7 +924,13 @@ OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
             oField.SetType( OFTDate );
         }
         else if( eDBFType == FTDouble )
-            oField.SetType( OFTReal );
+        {
+            nAdjustableFields += (nPrecision == 0);
+            if( nPrecision == 0 && nWidth < 19 )
+                oField.SetType( OFTInteger64 );
+            else
+                oField.SetType( OFTReal );
+        }
         else if( eDBFType == FTInteger )
             oField.SetType( OFTInteger );
         else
@@ -929,6 +938,73 @@ OGRFeatureDefn *SHPReadOGRFeatureDefn( const char * pszName,
 
         poDefn->AddFieldDefn( &oField );
     }
+    
+    /* Do an optional past if requested and needed to demote Integer64->Integer */
+    /* or Real->Integer64/Integer */
+    if( nAdjustableFields && bAdjustType )
+    {
+        int* panAdjustableField = (int*)CPLCalloc(sizeof(int), nFieldCount);
+        for( iField = 0; iField < nFieldCount; iField++ )
+        {
+            OGRFieldType eType = poDefn->GetFieldDefn(iField)->GetType();
+            if( poDefn->GetFieldDefn(iField)->GetPrecision() == 0 &&
+               (eType == OFTInteger64 || eType == OFTReal) )
+            {
+                panAdjustableField[iField] = TRUE;
+                poDefn->GetFieldDefn(iField)->SetType(OFTInteger);
+                //poDefn->GetFieldDefn(iField)->SetWidth(0);
+            }
+        }
+       
+        int nRowCount = DBFGetRecordCount(hDBF);
+        for( int iRow = 0; iRow < nRowCount && nAdjustableFields; iRow ++ )
+        {
+           for( iField = 0; iField < nFieldCount; iField++ )
+           {
+               if( panAdjustableField[iField] )
+               {
+                   const char* pszValue = DBFReadStringAttribute( hDBF, iRow, iField );
+                   int nValueLength = (int)strlen(pszValue);
+                   //if( nValueLength >= poDefn->GetFieldDefn(iField)->GetWidth())
+                   //    poDefn->GetFieldDefn(iField)->SetWidth(nValueLength);
+                   if( nValueLength >= 10 )
+                   {
+                       int bOverflow;
+                       GIntBig nVal = CPLAtoGIntBigEx(pszValue, FALSE, &bOverflow);
+                       if( bOverflow )
+                       {
+                           poDefn->GetFieldDefn(iField)->SetType(OFTReal);
+                           panAdjustableField[iField] = FALSE;
+                           nAdjustableFields --;
+                           
+                           /*char            szFieldName[12] = {};
+                           int             nWidth, nPrecision;
+                           DBFGetFieldInfo( hDBF, iField, szFieldName,
+                                            &nWidth, &nPrecision );
+                           poDefn->GetFieldDefn(iField)->SetWidth(nWidth);*/
+                       }
+                       else if( (GIntBig)(int)nVal != nVal )
+                       {
+                           poDefn->GetFieldDefn(iField)->SetType(OFTInteger64);
+                           if( poDefn->GetFieldDefn(iField)->GetWidth() <= 18 )
+                           {
+                               panAdjustableField[iField] = FALSE;
+                               nAdjustableFields --;
+                               
+                               /*char            szFieldName[12] = {};
+                               int             nWidth, nPrecision;
+                               DBFGetFieldInfo( hDBF, iField, szFieldName,
+                                                &nWidth, &nPrecision );
+                               poDefn->GetFieldDefn(iField)->SetWidth(nWidth);*/
+                           }
+                       }
+                   }
+               }
+           }
+        }
+        
+        CPLFree(panAdjustableField);
+    }
 
     if( hSHP == NULL )
         poDefn->SetGeomType( wkbNone );
@@ -1066,17 +1142,11 @@ OGRFeature *SHPReadOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
           break;
 
           case OFTInteger:
-
-            if( !DBFIsAttributeNULL( hDBF, iShape, iField ) )
-                poFeature->SetField( iField,
-                                    DBFReadIntegerAttribute( hDBF, iShape,
-                                                             iField ) );
-            break;
-
+          case OFTInteger64:
           case OFTReal:
             if( !DBFIsAttributeNULL( hDBF, iShape, iField ) )
                 poFeature->SetField( iField,
-                                    DBFReadDoubleAttribute( hDBF, iShape,
+                                    DBFReadStringAttribute( hDBF, iShape,
                                                             iField ) );
             break;
 
@@ -1134,7 +1204,7 @@ OGRFeature *SHPReadOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
 static OGRErr GrowField(DBFHandle hDBF, int iField, OGRFieldDefn* poFieldDefn,
                         int nNewSize)
 {
-    char            szFieldName[20];
+    char            szFieldName[20] = {};
     int             nOriWidth, nPrecision;
     char            chNativeType;
     /* DBFFieldType    eDBFType; */
@@ -1172,7 +1242,8 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                            OGRFeatureDefn * poDefn, 
                            OGRFeature * poFeature,
                            const char *pszSHPEncoding,
-                           int* pbTruncationWarningEmitted )
+                           int* pbTruncationWarningEmitted,
+                           int bRewind )
 
 {
 #ifdef notdef
@@ -1196,8 +1267,8 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
 
     if( hSHP != NULL )
     {
-        eErr = SHPWriteOGRObject( hSHP, poFeature->GetFID(),
-                                  poFeature->GetGeometryRef() );
+        eErr = SHPWriteOGRObject( hSHP, (int)poFeature->GetFID(),
+                                  poFeature->GetGeometryRef(), bRewind );
         if( eErr != OGRERR_NONE )
             return eErr;
     }
@@ -1240,8 +1311,8 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
 /* -------------------------------------------------------------------- */
     if( DBFGetFieldCount( hDBF ) == 1 && poDefn->GetFieldCount() == 0 )
     {
-        DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), 0, 
-                                  poFeature->GetFID() );
+        DBFWriteIntegerAttribute( hDBF, (int)poFeature->GetFID(), 0, 
+                                  (int)poFeature->GetFID() );
     }
 
 /* -------------------------------------------------------------------- */
@@ -1251,7 +1322,7 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
     {
         if( !poFeature->IsFieldSet( iField ) )
         {
-            DBFWriteNULLAttribute( hDBF, poFeature->GetFID(), iField );
+            DBFWriteNULLAttribute( hDBF, (int)poFeature->GetFID(), iField );
             continue;
         }
 
@@ -1283,7 +1354,27 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                             poFieldDefn->GetNameRef(),
                             OGR_DBF_MAX_FIELD_WIDTH);
                 }
+
                 nStrLen = OGR_DBF_MAX_FIELD_WIDTH;
+
+                if(EQUAL(pszSHPEncoding, CPL_ENC_UTF8))
+                {
+                    const char *p = pszStr + nStrLen;
+                    int byteCount = nStrLen;
+                    while(byteCount > 0)
+                    {
+                        if( (*p & 0xc0) != 0x80 )
+                        {
+                            nStrLen = byteCount;
+                            break;
+                        }
+
+                        byteCount--;
+                        p--;
+                    }
+
+                    pszEncoded[nStrLen] = 0;
+                }
               }
 
               if ( nStrLen > poFieldDefn->GetWidth() )
@@ -1295,7 +1386,7 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                   }
               }
 
-              DBFWriteStringAttribute( hDBF, poFeature->GetFID(), iField,
+              DBFWriteStringAttribute( hDBF, (int)poFeature->GetFID(), iField,
                                               pszStr );
 
               CPLFree( pszEncoded );
@@ -1303,12 +1394,13 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
           break;
 
           case OFTInteger:
+          case OFTInteger64:
           {
               char szFormat[20];
               char szValue[32];
               int nFieldWidth = poFieldDefn->GetWidth();
-              sprintf(szFormat, "%%%dd", MIN(nFieldWidth, (int)sizeof(szValue)-1));
-              sprintf(szValue, szFormat, poFeature->GetFieldAsInteger(iField) );
+              sprintf(szFormat, "%%%d" CPL_FRMT_GB_WITHOUT_PREFIX "d", MIN(nFieldWidth, (int)sizeof(szValue)-1));
+              sprintf(szValue, szFormat, poFeature->GetFieldAsInteger64(iField) );
               int nStrLen = strlen(szValue);
               if( nStrLen > nFieldWidth )
               {
@@ -1318,7 +1410,7 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                   }
               }
 
-              DBFWriteAttributeDirectly( hDBF, poFeature->GetFID(), iField, 
+              DBFWriteAttributeDirectly( hDBF, (int)poFeature->GetFID(), iField, 
                                          szValue );
 
               break;
@@ -1334,18 +1426,18 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
                 if( nCounter <= 10 )
                 {
                     CPLError(CE_Warning, CPLE_AppDefined,
-                             "Value %.18g of field %s with 0 decimal of feature %ld is bigger than 2^53. Precision loss likely occured or going to happen.%s",
+                             "Value %.18g of field %s with 0 decimal of feature " CPL_FRMT_GIB " is bigger than 2^53. Precision loss likely occured or going to happen.%s",
                              dfVal, poFieldDefn->GetNameRef(), poFeature->GetFID(),
                              (nCounter == 10) ? " This warning will not be emitted anymore." : "");
                     nCounter ++;
                 }
             }
-            int ret = DBFWriteDoubleAttribute( hDBF, poFeature->GetFID(), iField, 
+            int ret = DBFWriteDoubleAttribute( hDBF, (int)poFeature->GetFID(), iField, 
                                                dfVal );
             if( !ret )
             {
                 CPLError(CE_Warning, CPLE_AppDefined,
-                         "Value %.18g of field %s of feature %ld not successfully written. "
+                         "Value %.18g of field %s of feature " CPL_FRMT_GIB " not successfully written. "
                          "Possibly due to too larger number with respect to field width",
                          dfVal, poFieldDefn->GetNameRef(), poFeature->GetFID());
             }
@@ -1354,20 +1446,16 @@ OGRErr SHPWriteOGRFeature( SHPHandle hSHP, DBFHandle hDBF,
 
           case OFTDate:
           {
-              int  nYear, nMonth, nDay;
+              const OGRField* psField = poFeature->GetRawFieldRef(iField);
 
-              if( poFeature->GetFieldAsDateTime( iField, &nYear, &nMonth, &nDay,
-                                                 NULL, NULL, NULL, NULL ) )
+              if( psField->Date.Year < 0 || psField->Date.Year > 9999 )
               {
-                  if( nYear < 0 || nYear > 9999 )
-                  {
-                      CPLError(CE_Warning, CPLE_NotSupported,
-                               "Year < 0 or > 9999 is not a valid date for shapefile");
-                  }
-                  else
-                      DBFWriteIntegerAttribute( hDBF, poFeature->GetFID(), iField, 
-                                            nYear*10000 + nMonth*100 + nDay );
+                  CPLError(CE_Warning, CPLE_NotSupported,
+                          "Year < 0 or > 9999 is not a valid date for shapefile");
               }
+              else
+                  DBFWriteIntegerAttribute( hDBF, (int)poFeature->GetFID(), iField, 
+                                            psField->Date.Year*10000 + psField->Date.Month*100 + psField->Date.Day );
           }
           break;
 
diff --git a/ogr/ogrsf_frmts/shape/shapefil.h b/ogr/ogrsf_frmts/shape/shapefil.h
index 3232f14..fc78b07 100644
--- a/ogr/ogrsf_frmts/shape/shapefil.h
+++ b/ogr/ogrsf_frmts/shape/shapefil.h
@@ -2,7 +2,7 @@
 #define SHAPEFILE_H_INCLUDED
 
 /******************************************************************************
- * $Id: shapefil.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: shapefil.h 28337 2015-01-21 21:10:33Z rouault $
  *
  * Project:  Shapelib
  * Purpose:  Primary include file for Shapelib.
@@ -583,6 +583,10 @@ typedef	struct
 
     int         iLanguageDriver;
     char        *pszCodePage;
+    
+    int         nUpdateYearSince1900; /* 0-255 */
+    int         nUpdateMonth; /* 1-12 */
+    int         nUpdateDay; /* 1-31 */
 } DBFInfo;
 
 typedef DBFInfo * DBFHandle;
@@ -690,6 +694,9 @@ char    SHPAPI_CALL
 const char SHPAPI_CALL1(*)
       DBFGetCodePage(DBFHandle psDBF );
 
+void SHPAPI_CALL
+    DBFSetLastModifiedDate( DBFHandle psDBF, int nYYSince1900, int nMM, int nDD );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ogr/ogrsf_frmts/shape/shp_vsi.c b/ogr/ogrsf_frmts/shape/shp_vsi.c
index a6f0ab1..4dda3f7 100644
--- a/ogr/ogrsf_frmts/shape/shp_vsi.c
+++ b/ogr/ogrsf_frmts/shape/shp_vsi.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: shp_vsi.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: shp_vsi.c 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  IO Redirection via VSI services for shp/dbf io.
@@ -32,7 +32,7 @@
 #include "cpl_error.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: shp_vsi.c 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: shp_vsi.c 27384 2014-05-24 12:28:12Z rouault $");
 
 typedef struct
 {
@@ -54,6 +54,16 @@ VSILFILE* VSI_SHP_GetVSIL( SAFile file )
 }
 
 /************************************************************************/
+/*                        VSI_SHP_GetFilename()                         */
+/************************************************************************/
+
+const char* VSI_SHP_GetFilename( SAFile file )
+{
+    OGRSHPDBFFile* pFile = (OGRSHPDBFFile*) file;
+    return pFile->pszFilename;
+}
+
+/************************************************************************/
 /*                         VSI_SHP_OpenInternal()                       */
 /************************************************************************/
 
diff --git a/ogr/ogrsf_frmts/shape/shp_vsi.h b/ogr/ogrsf_frmts/shape/shp_vsi.h
index 5cec121..839e0d8 100644
--- a/ogr/ogrsf_frmts/shape/shp_vsi.h
+++ b/ogr/ogrsf_frmts/shape/shp_vsi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: shp_vsi.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: shp_vsi.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  IO Redirection via VSI services for shp/dbf io.
@@ -39,6 +39,7 @@ CPL_C_START
 const SAHooks* VSI_SHP_GetHook(int b2GBLimit);
 
 VSILFILE* VSI_SHP_GetVSIL( SAFile file );
+const char* VSI_SHP_GetFilename( SAFile file );
 int VSI_SHP_WriteMoreDataOK( SAFile file, SAOffset nExtraBytes );
 
 CPL_C_END
diff --git a/ogr/ogrsf_frmts/shape/shpopen.c b/ogr/ogrsf_frmts/shape/shpopen.c
index d9fe682..3387025 100644
--- a/ogr/ogrsf_frmts/shape/shpopen.c
+++ b/ogr/ogrsf_frmts/shape/shpopen.c
@@ -504,6 +504,7 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
     uchar		*pabyBuf;
     int			i;
     double		dValue;
+    int         bLazySHXLoading = FALSE;
     
 /* -------------------------------------------------------------------- */
 /*      Ensure the access string is one of the legal ones.  We          */
@@ -514,7 +515,10 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         || strcmp(pszAccess,"r+") == 0 )
         pszAccess = "r+b";
     else
+    {
+        bLazySHXLoading = strchr(pszAccess, 'l') != NULL;
         pszAccess = "rb";
+    }
     
 /* -------------------------------------------------------------------- */
 /*	Establish the byte order on this machine.			*/
@@ -701,11 +705,14 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
     psSHP->panRecSize = (unsigned int *)
         malloc(sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
-    pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
+    if( bLazySHXLoading )
+        pabyBuf = NULL;
+    else
+        pabyBuf = (uchar *) malloc(8 * MAX(1,psSHP->nRecords) );
 
     if (psSHP->panRecOffset == NULL ||
         psSHP->panRecSize == NULL ||
-        pabyBuf == NULL)
+        (!bLazySHXLoading && pabyBuf == NULL))
     {
         char szError[200];
 
@@ -723,6 +730,13 @@ SHPOpenLL( const char * pszLayer, const char * pszAccess, SAHooks *psHooks )
         return( NULL );
     }
 
+    if( bLazySHXLoading )
+    {
+        memset(psSHP->panRecOffset, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        memset(psSHP->panRecSize, 0, sizeof(unsigned int) * MAX(1,psSHP->nMaxRecords) );
+        return( psSHP );
+    }
+
     if( (int) psSHP->sHooks.FRead( pabyBuf, 8, psSHP->nRecords, psSHP->fpSHX ) 
         != psSHP->nRecords )
     {
@@ -1677,6 +1691,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
     SHPObject           *psShape;
     char                 szErrorMsg[128];
     int                  nSHPType;
+    int                  nBytesRead;
 
 /* -------------------------------------------------------------------- */
 /*      Validate the record/entity number.                              */
@@ -1685,6 +1700,32 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         return( NULL );
 
 /* -------------------------------------------------------------------- */
+/*      Read offset/length from SHX loading if necessary.               */
+/* -------------------------------------------------------------------- */
+    if( psSHP->panRecOffset[hEntity] == 0 && psSHP->fpSHX != NULL )
+    {
+        int32       nOffset, nLength;
+
+        if( psSHP->sHooks.FSeek( psSHP->fpSHX, 100 + 8 * hEntity, 0 ) != 0 ||
+            psSHP->sHooks.FRead( &nOffset, 1, 4, psSHP->fpSHX ) != 4 ||
+            psSHP->sHooks.FRead( &nLength, 1, 4, psSHP->fpSHX ) != 4 )
+        {
+            char str[128];
+            sprintf( str,
+                    "Error in fseek()/fread() reading object from .shx file at offset %d",
+                    100 + 8 * hEntity);
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+        if( !bBigEndian ) SwapWord( 4, &nOffset );
+        if( !bBigEndian ) SwapWord( 4, &nLength );
+
+        psSHP->panRecOffset[hEntity] = nOffset*2;
+        psSHP->panRecSize[hEntity] = nLength*2;
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Ensure our record buffer is large enough.                       */
 /* -------------------------------------------------------------------- */
     nEntitySize = psSHP->panRecSize[hEntity]+8;
@@ -1695,7 +1736,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             char szError[200];
 
-            /* Reallocate previous successfull size for following features */
+            /* Reallocate previous successful size for following features */
             psSHP->pabyRec = (uchar *) malloc(psSHP->nBufSize);
 
             sprintf( szError, 
@@ -1705,7 +1746,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
             return NULL;
         }
 
-        /* Only set new buffer size after successfull alloc */
+        /* Only set new buffer size after successful alloc */
         psSHP->nBufSize = nEntitySize;
     }
 
@@ -1733,7 +1774,32 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         return NULL;
     }
 
-    if( psSHP->sHooks.FRead( psSHP->pabyRec, nEntitySize, 1, psSHP->fpSHP ) != 1 )
+    nBytesRead = psSHP->sHooks.FRead( psSHP->pabyRec, 1, nEntitySize, psSHP->fpSHP );
+
+    /* Special case for a shapefile whose .shx content length field is not equal */
+    /* to the content length field of the .shp, which is a violation of "The */
+    /* content length stored in the index record is the same as the value stored in the main */
+    /* file record header." (http://www.esri.com/library/whitepapers/pdfs/shapefile.pdf, page 24) */
+    /* Actually in that case the .shx content length is equal to the .shp content length + */
+    /* 4 (16 bit words), representing the 8 bytes of the record header... */
+    if( nBytesRead == nEntitySize - 8 )
+    {
+        /* Do a sanity check */
+        int nSHPContentLength;
+        memcpy( &nSHPContentLength, psSHP->pabyRec + 4, 4 );
+        if( !bBigEndian ) SwapWord( 4, &(nSHPContentLength) );
+        if( 2 * nSHPContentLength + 8 != nBytesRead )
+        {
+            char str[128];
+            sprintf( str,
+                    "Sanity check failed when trying to recover from inconsistant .shx/.shp with shape %d",
+                    hEntity );
+
+            psSHP->sHooks.Error( str );
+            return NULL;
+        }
+    }
+    else if( nBytesRead != nEntitySize )
     {
         /*
          * TODO - mloskot: Consider detailed diagnostics of shape file,
@@ -1946,7 +2012,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
 
             nOffset += 4*nParts;
         }
-        
+
 /* -------------------------------------------------------------------- */
 /*      Copy out the vertices from the record.                          */
 /* -------------------------------------------------------------------- */
@@ -1975,10 +2041,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
+
             for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
@@ -2003,10 +2069,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
+
             for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
@@ -2109,7 +2175,7 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         }
 
         nOffset = 48 + 16*nPoints;
-        
+
 /* -------------------------------------------------------------------- */
 /*	Get the X/Y bounds.						*/
 /* -------------------------------------------------------------------- */
@@ -2130,10 +2196,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfZMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfZMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfZMax) );
-            
+
             for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfZ + i,
@@ -2156,10 +2222,10 @@ SHPReadObject( SHPHandle psSHP, int hEntity )
         {
             memcpy( &(psShape->dfMMin), psSHP->pabyRec + nOffset, 8 );
             memcpy( &(psShape->dfMMax), psSHP->pabyRec + nOffset + 8, 8 );
-            
+
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMin) );
             if( bBigEndian ) SwapWord( 8, &(psShape->dfMMax) );
-            
+
             for( i = 0; (int32)i < nPoints; i++ )
             {
                 memcpy( psShape->padfM + i,
@@ -2387,7 +2453,8 @@ SHPDestroyObject( SHPObject * psShape )
 /************************************************************************/
 
 int SHPAPI_CALL
-SHPRewindObject( CPL_UNUSED SHPHandle hSHP, SHPObject * psObject )
+SHPRewindObject( CPL_UNUSED SHPHandle hSHP,
+                 SHPObject * psObject )
 {
     int  iOpRing, bAltered = 0;
 
diff --git a/ogr/ogrsf_frmts/shape/shptree.c b/ogr/ogrsf_frmts/shape/shptree.c
index aade7ef..ab98c61 100644
--- a/ogr/ogrsf_frmts/shape/shptree.c
+++ b/ogr/ogrsf_frmts/shape/shptree.c
@@ -911,13 +911,13 @@ SHPSearchDiskTreeNode( SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, doubl
 /* -------------------------------------------------------------------- */
     if(numshapes > 0) 
     {
-        if( (int)(*pnResultCount + numshapes) > *pnBufferMax )
+        if( *pnResultCount + numshapes > (unsigned int)*pnBufferMax )
         {
             int* pNewBuffer;
 
             *pnBufferMax = (*pnResultCount + numshapes + 100) * 5 / 4;
 
-            if( (unsigned int)*pnBufferMax > INT_MAX / sizeof(int) )
+            if( (size_t)*pnBufferMax > INT_MAX / sizeof(int) )
                 *pnBufferMax = *pnResultCount + numshapes;
 
             pNewBuffer = (int *)
diff --git a/ogr/ogrsf_frmts/sosi/GNUmakefile b/ogr/ogrsf_frmts/sosi/GNUmakefile
index 29f8dc0..0b81095 100644
--- a/ogr/ogrsf_frmts/sosi/GNUmakefile
+++ b/ogr/ogrsf_frmts/sosi/GNUmakefile
@@ -5,7 +5,7 @@ include ../../../GDALmake.opt
 OBJ	=	ogrsosidriver.o ogrsosidatasource.o ogrsosilayer.o
 # ogrsosidatatypes.o 
 
-CPPFLAGS	:=-DLINUX -DUNIX -I.. -I../.. $(GDAL_INCLUDE) $(SOSI_INC) $(CPPFLAGS)
+CPPFLAGS	:=-DLINUX -DUNIX -I.. -I../..  $(SOSI_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sosi/fyba_melding.cpp b/ogr/ogrsf_frmts/sosi/fyba_melding.cpp
index 4048ca3..7edb976 100644
--- a/ogr/ogrsf_frmts/sosi/fyba_melding.cpp
+++ b/ogr/ogrsf_frmts/sosi/fyba_melding.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: fyba_melding.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: fyba_melding.cpp 27897 2014-10-23 12:20:01Z jef $
  *
  * Project:  FYBA Callbacks
  * Purpose:  Needed by FYBA - however we do not want to display most messages
@@ -49,10 +49,6 @@ void LC_Error(short feil_nr, const char *logtx, const char *vartx)
       case 4:  sprintf(szErrMsg,"%s","Alvorlig feil avslutt programmet! \n\n");break;
       default: szErrMsg[0]='\0';
    }
-
-   if (strategi > 2) {
-      Beep(100,500);
-   }
 }
 
 
diff --git a/ogr/ogrsf_frmts/sosi/ogr_sosi.h b/ogr/ogrsf_frmts/sosi/ogr_sosi.h
index 7583869..d2ea0ca 100644
--- a/ogr/ogrsf_frmts/sosi/ogr_sosi.h
+++ b/ogr/ogrsf_frmts/sosi/ogr_sosi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_sosi.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_sosi.h 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  SOSI Translator
  * Purpose:  Implements OGRSOSIDriver.
@@ -44,25 +44,6 @@ class ORGSOSILayer;      /* defined below */
 class OGRSOSIDataSource; /* defined below */
 
 /************************************************************************
- *                           OGRSOSIDriver                              *
- * OGRSOSIDriver is the main driver class. It does not much, except     *
- * reporting on its capabilities and opening a single data source       *
- * currently                                                            *
- ************************************************************************/
-
-class OGRSOSIDriver : public OGRSFDriver {
-public:
-
-    OGRSOSIDriver();
-    ~OGRSOSIDriver();
-
-    const char    *GetName();
-    OGRDataSource *Open( const char *, int );
-    int            TestCapability( const char * );
-    OGRDataSource *CreateDataSource( const char *pszName, char **papszOptions = NULL);
-};
-
-/************************************************************************
  *                           OGRSOSILayer                               *
  * OGRSOSILayer reports all the OGR Features generated by the data      *
  * source, in an orderly fashion.                                       *
@@ -88,7 +69,7 @@ public:
     OGRFeature *        GetNextFeature();
     OGRFeatureDefn *    GetLayerDefn();
     OGRErr              CreateField(OGRFieldDefn *poField, int bApproxOK=TRUE);
-    OGRErr              CreateFeature(OGRFeature *poFeature);
+    OGRErr              ICreateFeature(OGRFeature *poFeature);
     int                 TestCapability( const char * );
 };
 
@@ -138,7 +119,7 @@ public:
         return nLayers;
     }
     OGRLayer            *GetLayer( int );
-    OGRLayer            *CreateLayer( const char *pszName, OGRSpatialReference  *poSpatialRef=NULL, OGRwkbGeometryType eGType=wkbUnknown, char **papszOptions=NULL);
+    OGRLayer            *ICreateLayer( const char *pszName, OGRSpatialReference  *poSpatialRef=NULL, OGRwkbGeometryType eGType=wkbUnknown, char **papszOptions=NULL);
     int                 TestCapability( const char * );
 };
 
diff --git a/ogr/ogrsf_frmts/sosi/ogrsosidatasource.cpp b/ogr/ogrsf_frmts/sosi/ogrsosidatasource.cpp
index d10e338..9f4b39f 100644
--- a/ogr/ogrsf_frmts/sosi/ogrsosidatasource.cpp
+++ b/ogr/ogrsf_frmts/sosi/ogrsosidatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsosidatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsosidatasource.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  SOSI Data Source
  * Purpose:  Provide SOSI Data to OGR.
@@ -498,10 +498,13 @@ int  OGRSOSIDataSource::Create( const char *pszFilename ) {
 }
 
 /************************************************************************/
-/*                              CreateLayer()                           */
+/*                             ICreateLayer()                           */
 /************************************************************************/
 
-OGRLayer *OGRSOSIDataSource::CreateLayer( const char *pszName, OGRSpatialReference  *poSpatialRef, OGRwkbGeometryType eGType, char **papszOptions ) {
+OGRLayer *OGRSOSIDataSource::ICreateLayer( const char *pszName,
+                                           OGRSpatialReference  *poSpatialRef,
+                                           OGRwkbGeometryType eGType,
+                                           CPL_UNUSED char **papszOptions ) {
     /* SOSI does not really support layers - so let's first see that the global settings are consistent */
     if (poSRS == NULL) {
         if (poSpatialRef!=NULL) {
diff --git a/ogr/ogrsf_frmts/sosi/ogrsosidriver.cpp b/ogr/ogrsf_frmts/sosi/ogrsosidriver.cpp
index 4d5536a..c31510a 100644
--- a/ogr/ogrsf_frmts/sosi/ogrsosidriver.cpp
+++ b/ogr/ogrsf_frmts/sosi/ogrsosidriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsosidriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsosidriver.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  SOSI Translator
  * Purpose:  Implements OGRSOSIDriver.
@@ -30,50 +30,39 @@
 
 #include "ogr_sosi.h"
 
-void RegisterOGRSOSI() {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSOSIDriver );
-}
-
-static int nFYBAInitCounter = 0;
+static int bFYBAInit = FALSE;
 
 /************************************************************************/
-/*                           OGRSOSIDriver()                           */
+/*                        OGRSOSIDriverUnload()                         */
 /************************************************************************/
-OGRSOSIDriver::OGRSOSIDriver() {
-    if ( nFYBAInitCounter == 0 )
-    {
-        LC_Init();  /* Init FYBA */
-    }
-    nFYBAInitCounter++;
-}
 
-/************************************************************************/
-/*                           ~OGRSOSIDriver()                           */
-/************************************************************************/
+static void OGRSOSIDriverUnload(CPL_UNUSED GDALDriver* poDriver) {
 
-OGRSOSIDriver::~OGRSOSIDriver() {
-    nFYBAInitCounter--;
-    if ( nFYBAInitCounter == 0 )
+    if ( bFYBAInit )
     {
         LC_Close(); /* Close FYBA */
+        bFYBAInit = FALSE;
     }
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                              Open()                                  */
 /************************************************************************/
 
-const char *OGRSOSIDriver::GetName() {
-    return "SOSI";
-}
+static GDALDataset *OGRSOSIDriverOpen( GDALOpenInfo* poOpenInfo )
+{
+    if( poOpenInfo->fpL == NULL ||
+        strstr((const char*)poOpenInfo->pabyHeader, ".HODE") == NULL )
+        return NULL;
 
-/************************************************************************/
-/*                              Open()                                  */
-/************************************************************************/
+    if ( !bFYBAInit )
+    {
+        LC_Init();  /* Init FYBA */
+        bFYBAInit = TRUE;
+    }
 
-OGRDataSource *OGRSOSIDriver::Open( const char * pszFilename, int bUpdate ) {
     OGRSOSIDataSource   *poDS = new OGRSOSIDataSource();
-    if ( !poDS->Open( pszFilename, 0 ) ) {
+    if ( !poDS->Open( poOpenInfo->pszFilename, 0 ) ) {
         delete poDS;
         return NULL;
     }
@@ -82,9 +71,20 @@ OGRDataSource *OGRSOSIDriver::Open( const char * pszFilename, int bUpdate ) {
 }
 
 /************************************************************************/
-/*                              CreateDataSource()                      */
+/*                              Create()                                */
 /************************************************************************/
-OGRDataSource *OGRSOSIDriver::CreateDataSource( const char *pszName, char **papszOptions) {
+
+static GDALDataset *OGRSOSIDriverCreate( const char * pszName,
+                                         CPL_UNUSED int nBands, CPL_UNUSED int nXSize,
+                                         CPL_UNUSED int nYSize, CPL_UNUSED GDALDataType eDT,
+                                         CPL_UNUSED char **papszOptions )
+{
+    
+    if ( !bFYBAInit )
+    {
+        LC_Init();  /* Init FYBA */
+        bFYBAInit = TRUE;
+    }
     OGRSOSIDataSource   *poDS = new OGRSOSIDataSource();
     if ( !poDS->Create( pszName ) ) {
         delete poDS;
@@ -93,16 +93,28 @@ OGRDataSource *OGRSOSIDriver::CreateDataSource( const char *pszName, char **paps
     return poDS;
 }
 
-
 /************************************************************************/
-/*                              TestCapability()                        */
+/*                         RegisterOGRSOSI()                            */
 /************************************************************************/
 
-int OGRSOSIDriver::TestCapability( const char * pszCap ) {
-    if (strcmp("CreateDataSource",pszCap) == 0) {
-        return TRUE; 
-    } else {
-        CPLDebug( "[TestCapability]","Capability %s not supported by SOSI driver", pszCap);
+void RegisterOGRSOSI() {
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "SOSI" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "SOSI" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Norwegian SOSI Standard" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_sosi.html" );
+
+        poDriver->pfnOpen = OGRSOSIDriverOpen;
+        poDriver->pfnCreate = OGRSOSIDriverCreate;
+        poDriver->pfnUnloadDriver = OGRSOSIDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
     }
-    return FALSE;
 }
diff --git a/ogr/ogrsf_frmts/sosi/ogrsosilayer.cpp b/ogr/ogrsf_frmts/sosi/ogrsosilayer.cpp
index 4d9f8f5..0f68c4b 100644
--- a/ogr/ogrsf_frmts/sosi/ogrsosilayer.cpp
+++ b/ogr/ogrsf_frmts/sosi/ogrsosilayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsosilayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsosilayer.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  SOSI Translator
  * Purpose:  Implements OGRSOSILayer.
@@ -43,6 +43,7 @@ OGRSOSILayer::OGRSOSILayer( OGRSOSIDataSource *poPar, OGRFeatureDefn *poFeatDefn
     nNextFID      = 0;
     poNextSerial  = NULL;
     
+    SetDescription( poFeatureDefn->GetName() );
     if( poFeatureDefn->GetGeomFieldCount() > 0 )
         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poParent->poSRS);
 
@@ -66,15 +67,15 @@ OGRFeatureDefn *OGRSOSILayer::GetLayerDefn() {
 /************************************************************************/
 /*                           CreateField()                              */
 /************************************************************************/
-OGRErr OGRSOSILayer::CreateField (OGRFieldDefn *poField, int bApproxOK) {
+OGRErr OGRSOSILayer::CreateField (OGRFieldDefn *poField, CPL_UNUSED int bApproxOK) {
     poFeatureDefn->AddFieldDefn( poField );
     return OGRERR_NONE; /* We'll just gladly accept any "field" we find */
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
-OGRErr OGRSOSILayer::CreateFeature(OGRFeature *poFeature) {
+OGRErr OGRSOSILayer::ICreateFeature(OGRFeature *poFeature) {
     short nNavn;
     long nSerial;
     
diff --git a/ogr/ogrsf_frmts/sqlite/GNUmakefile b/ogr/ogrsf_frmts/sqlite/GNUmakefile
index bd6c393..fb795c5 100644
--- a/ogr/ogrsf_frmts/sqlite/GNUmakefile
+++ b/ogr/ogrsf_frmts/sqlite/GNUmakefile
@@ -26,7 +26,7 @@ ifeq ($(SQLITE_HAS_COLUMN_METADATA),yes)
 CPPFLAGS +=  -DSQLITE_HAS_COLUMN_METADATA
 endif
 
-CPPFLAGS	:=	-I.. $(GDAL_INCLUDE) $(SQLITE_INC) $(SPATIALITE_INC) $(CPPFLAGS)
+CPPFLAGS	:=	-I..  $(SQLITE_INC) $(SPATIALITE_INC) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sqlite/drv_sqlite.html b/ogr/ogrsf_frmts/sqlite/drv_sqlite.html
index f66ce79..8b8b0fe 100644
--- a/ogr/ogrsf_frmts/sqlite/drv_sqlite.html
+++ b/ogr/ogrsf_frmts/sqlite/drv_sqlite.html
@@ -63,13 +63,23 @@ Attributes queries may be fast, especially if indexes are built for
 appropriate attribute columns using the "CREATE INDEX <indexname> 
 ON <tablename> ( <columnname> )" SQL command.</p>
 
-<h2>Tables with multiple geometries</h2>
+<p>Starting with GDAL 2.0, the driver also supports reading and writing the
+following non-linear geometry types :CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON, MULTICURVE and MULTISURFACE.
+Note: this is not true for Spatialite databases, since those geometry types
+are not supported by current Spatialite versions.</p>
 
-Starting with OGR 1.10, tables that have multiple geometry columns registered in geometry_columns can be used by OGR.
-For such tables, there are as many OGR layers exposed as there are geometry columns. They are named
-"table_name(geometry_column_name)".<p>
+<h2>Tables with multiple geometry columns</h2>
 
-Note: this support is limited to read-only operations.<p>
+<p>
+Starting with GDAL 2.0, layers with multiple geometry columns can be created,
+modified or read, following new API described in <a href="http://trac.osgeo.org/gdal/wiki/rfc41_multiple_geometry_fields">RFC 41</a>
+</p>
+
+<p>
+In GDAL 1.10, such support was read-only and there were as many OGR layers exposed
+as there are geometry columns. They were named "table_name(geometry_column_name)".
+Such syntax is still possible with GDAL 2.0 when explictely querying a layer
+with GetLayerByName()</p>
 
 <h2>REGEXP operator</h2>
 
@@ -192,17 +202,37 @@ Refer to the <a href="ogr_sql_sqlite.html">SQLite SQL</a> dialect for an overvie
 tables to existing ones.  Note that a new database file cannot be
 created over an existing file.</p>
 
+<h3>Transaction support (GDAL >= 2.0)</h3>
+
+<p>
+The driver implements transactions at the database level, per
+<a href="http://trac.osgeo.org/gdal/wiki/rfc54_dataset_transactions">RFC 54</a>
+</p>
+
+<h3>Dataset open options</h3>
+
+(GDAL >= 2.0)
+
+<ul>
+<li> <b>LIST_ALL_TABLES</b>=YES/NO: This may be "YES" to force all tables,
+including non-spatial ones, to be listed.<p>
+
+<li> <b>LIST_VIRTUAL_OGR</b>=YES/NO: This may be "YES" to force VirtualOGR virtual
+tables to be listed. This should only be enabled on trusted datasources to avoid
+potential safety issues.<p>
+</ul>
+
 <h3>Database Creation Options</h3>
 
 <ul>
 
-<li><p><b>METADATA=yes/no</b>: This can be used to avoid creating the 
+<li><p><b>METADATA=YES/NO</b>: This can be used to avoid creating the 
 geometry_columns and spatial_ref_sys tables in a new database.  By default
 these metadata tables are created when a new database is created.</p></li>
 
-<li><p><b>SPATIALITE=yes/no</b>: (Starting with GDAL 1.7.0) Create the SpatiaLite flavour of the metadata
+<li><p><b>SPATIALITE=YES/NO</b>: (Starting with GDAL 1.7.0) Create the SpatiaLite flavour of the metadata
 tables, which are a bit differ from the metadata used by this OGR driver and
-from OGC specifications. Implies <b>METADATA=yes</b>.<br>
+from OGC specifications. Implies <b>METADATA=YES</b>.<br>
 Please note: (Starting with GDAL 1.9.0) OGR must be linked against <i>libspatialite</i> in order to support
 insert/write on SpatiaLite; if not, <i>read-only</i> mode is enforced.<br>
 Attempting to perform any insert/write on SpatiaLite skipping the appropriate library support simply produces broken (corrupted) DB-files.<br>
@@ -210,9 +240,9 @@ Important notice: when the underlaying <i>libspatialite</i> is v.2.3.1 (or any p
 version) any Geometry will be casted to 2D [XY], because earlier versions of this library
 are simply able to support 2D [XY] dimensions. Version 2.4.0 (or any subsequent) is required in order to support 2.5D [XYZ].</p></li>
 
-<li><p><b>INIT_WITH_EPSG=yes/no</b>: (Starting with GDAL 1.8.0) Insert the content of the EPSG CSV files
+<li><p><b>INIT_WITH_EPSG=YES/NO</b>: (Starting with GDAL 1.8.0) Insert the content of the EPSG CSV files
 into the spatial_ref_sys table. Defaults to NO for regular SQLite databases</b>.<br>
-Please note: if <b>SPATIALITE=yes</b> and the underlaying <i>libspatialite</i> is v2.4 or v3.X,
+Please note: if <b>SPATIALITE=YES</b> and the underlaying <i>libspatialite</i> is v2.4 or v3.X,
 <b>INIT_WITH_EPSG</b> is ignored; those library versions will unconditionally load the EPSG 
 dataset into the spatial_ref_sys table when creating a new DB (<i>self-initialization</i>). Starting
 with libspatialite 4.0, INIT_WITH_EPSG defaults to YES, but can be set to NO.</p></li>
@@ -229,21 +259,25 @@ generally more space and processing efficient, but harder to inspect or use in
 simple applications than WKT (Well Known Text). SpatiaLite extension uses its
 own binary format to store geometries and you can choose it as well. It will
 be selected automatically when SpatiaLite database is opened or created with
-<b>SPATIALITE=yes</b> option. SPATIALITE value is available starting with GDAL 1.7.0.</p></li>
+<b>SPATIALITE=YES</b> option. SPATIALITE value is available starting with GDAL 1.7.0.</p></li>
+
+<li><p><b>GEOMETRY_NAME</b>: (Starting with GDAL 2.0) By default OGR creates new tables with the 
+geometry column named GEOMETRY (or WKT_GEOMETRY if FORMAT=WKT). If you wish to use a different name, 
+it can be supplied with the GEOMETRY_NAME layer creation option.</p></li>
 
-<li><p><b>LAUNDER=yes/no</b>: Controls whether layer and field names will be 
+<li><p><b>LAUNDER=YES/NO</b>: Controls whether layer and field names will be 
 laundered for easier use in SQLite.  Laundered names will be convered to lower 
 case and some special characters(' - #) will be changed to underscores. Default
-to yes.</p></li>
+to YES.</p></li>
 
-<li><p><b>SPATIAL_INDEX=yes/no</b>: (Starting with GDAL 1.7.0) If the database is
+<li><p><b>SPATIAL_INDEX=YES/NO</b>: (Starting with GDAL 1.7.0) If the database is
 of the SpatiaLite flavour, and if OGR is linked against libspatialite, this option
-can be used to control if a spatial index must be created. Default to yes.</p></li>
+can be used to control if a spatial index must be created. Default to YES.</p></li>
 
-<li><p><b>COMPRESS_GEOM=yes/no</b>: (Starting with GDAL 1.9.0) If the format of the
+<li><p><b>COMPRESS_GEOM=YES/NO</b>: (Starting with GDAL 1.9.0) If the format of the
 geometry BLOB is of the SpatiaLite flavour, this option can be used to control
 if the compressed format for geometries (LINESTRINGs, POLYGONs) must be used. This
-format is understood by Spatialite v2.4 (or any subsequent version). Default to no.
+format is understood by Spatialite v2.4 (or any subsequent version). Default to NO.
 Note: when updating an existing Spatialite DB, the COMPRESS_GEOM configuration option
 can be set to produce similar results for appended/overwritten features.</p></li>
 
@@ -262,6 +296,8 @@ With OGR, when inserting, modifying or queryings compressed columns, compression
 However, such columns cannot be (easily) queried with an attribute filter or WHERE clause.
 Note: in table definition, such columns have the "VARCHAR_deflate" declaration type.</p></li>
 
+<li><p><b>FID=fid_name</b>: (From GDAL 2.0) Name of the FID column to create. Defaults to OGC_FID.</p></li>
+
 </ul>
 
 <h2>Other Configuration Options</h2>
@@ -308,7 +344,7 @@ ogrinfo db.sqlite -sql "SELECT CreateSpatialIndex('the_table','GEOMETRY')"
 </pre>
 <p>
 
-If a database has gone through editing operations, it might be usefull to run a
+If a database has gone through editing operations, it might be useful to run a
 <a href="https://sqlite.org/lang_vacuum.html">VACUUM</a> query to compact and optimize it.
 <pre>ogrinfo db.sqlite -sql "VACUUM"</pre>
 <p>
diff --git a/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h b/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h
index 36e9966..19f19d5 100644
--- a/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h
+++ b/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_sqlite.h 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogr_sqlite.h 28808 2015-03-28 15:01:36Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/SQLite driver.
@@ -32,6 +32,7 @@
 #define _OGR_SQLITE_H_INCLUDED
 
 #include "ogrsf_frmts.h"
+#include "gdal_pam.h"
 #include "cpl_error.h"
 #include <map>
 #include <set>
@@ -155,8 +156,10 @@ class OGRSQLiteGeomFieldDefn : public OGRGeomFieldDefn
 {
     public:
         OGRSQLiteGeomFieldDefn( const char* pszName, int iGeomColIn ) :
-            OGRGeomFieldDefn(pszName, wkbUnknown), nSRSId(UNINITIALIZED_SRID),
-            iCol(iGeomColIn), bTriedAsSpatiaLite(FALSE), eGeomFormat(OSGF_None)
+            OGRGeomFieldDefn(pszName, wkbUnknown), nSRSId(-1),
+            iCol(iGeomColIn), bTriedAsSpatiaLite(FALSE), eGeomFormat(OSGF_None),
+            bHasM(FALSE), bCachedExtentIsValid(FALSE), bHasSpatialIndex(FALSE),
+            bHasCheckedSpatialIndexTable(FALSE)
             {
             }
 
@@ -164,6 +167,12 @@ class OGRSQLiteGeomFieldDefn : public OGRGeomFieldDefn
         int iCol; /* ordinal of geometry field in SQL statement */
         int bTriedAsSpatiaLite;
         OGRSQLiteGeomFormat eGeomFormat;
+        int bHasM;
+        OGREnvelope         oCachedExtent;
+        int                 bCachedExtentIsValid;
+        int                 bHasSpatialIndex;
+        int                 bHasCheckedSpatialIndexTable;
+        std::vector< std::pair<CPLString,CPLString> > aosDisabledTriggers;
 };
 
 /************************************************************************/
@@ -190,8 +199,16 @@ class OGRSQLiteFeatureDefn : public OGRFeatureDefn
 /************************************************************************/
 
 class OGRSQLiteDataSource;
-    
-class OGRSQLiteLayer : public OGRLayer
+
+class IOGRSQLiteGetSpatialWhere
+{
+  public:
+    virtual int           HasFastSpatialFilter(int iGeomCol) = 0;
+    virtual CPLString     GetSpatialWhere(int iGeomCol,
+                                          OGRGeometry* poFilterGeom) = 0;
+};
+
+class OGRSQLiteLayer : public OGRLayer, public IOGRSQLiteGetSpatialWhere
 {
   private:
     static OGRErr       createFromSpatialiteInternal(const GByte *pabyData,
@@ -221,7 +238,7 @@ class OGRSQLiteLayer : public OGRLayer
   protected:
     OGRSQLiteFeatureDefn *poFeatureDefn;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     sqlite3_stmt        *hStmt;
     int                  bDoStep;
@@ -233,15 +250,12 @@ class OGRSQLiteLayer : public OGRLayer
     int                *panFieldOrdinals;
     int                 iFIDCol;
 
-    int                 bHasSpatialIndex;
-    int                 bHasM;
-
     int                 bIsVirtualShape;
 
     void                BuildFeatureDefn( const char *pszLayerName,
                                           sqlite3_stmt *hStmt,
-                                          const char *pszExpectedGeomCol,
-                                          const std::set<CPLString>& aosGeomCols);
+                                          const std::set<CPLString>& aosGeomCols,
+                                          const std::set<CPLString>& aosIgnoredCols);
 
     void                ClearStatement();
     virtual OGRErr      ResetStatement() = 0;
@@ -252,6 +266,14 @@ class OGRSQLiteLayer : public OGRLayer
 
     int                 bAllowMultipleGeomFields;
 
+    CPLString           FormatSpatialFilterFromRTree(OGRGeometry* poFilterGeom,
+                                                       const char* pszRowIDName,
+                                                       const char* pszEscapedTable,
+                                                       const char* pszEscapedGeomCol);
+    CPLString           FormatSpatialFilterFromMBR(OGRGeometry* poFilterGeom,
+                                                   const char* pszEscapedGeomColName);
+
+
   public:
                         OGRSQLiteLayer();
     virtual             ~OGRSQLiteLayer();
@@ -262,7 +284,7 @@ class OGRSQLiteLayer : public OGRLayer
     virtual OGRFeature *GetNextRawFeature();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual OGRFeatureDefn *GetLayerDefn() { return poFeatureDefn; }
     virtual OGRSQLiteFeatureDefn *myGetLayerDefn() { return poFeatureDefn; }
@@ -279,8 +301,9 @@ class OGRSQLiteLayer : public OGRLayer
 
     virtual int          IsTableLayer() { return FALSE; }
 
-    virtual int          HasSpatialIndex() { return bHasSpatialIndex; }
+    virtual int          HasSpatialIndex(CPL_UNUSED int iGeomField) { return FALSE; }
 
+    virtual int           HasFastSpatialFilter(CPL_UNUSED int iGeomCol) { return FALSE; }
     virtual CPLString     GetSpatialWhere(CPL_UNUSED int iGeomCol,
                                           CPL_UNUSED OGRGeometry* poFilterGeom) { return ""; }
 
@@ -305,24 +328,17 @@ class OGRSQLiteTableLayer : public OGRSQLiteLayer
 
     CPLString           osWHERE;
     CPLString           osQuery;
-    int                 bHasCheckedSpatialIndexTable;
-    int                 bDeferedSpatialIndexCreation;
-
-    OGRwkbGeometryType  eGeomType;
+    int                 bDeferredSpatialIndexCreation;
 
     char               *pszTableName;
     char               *pszEscapedTableName;
-    CPLString           osLayerName;
 
     int                 bLayerDefnError;
 
     sqlite3_stmt       *hInsertStmt;
     CPLString           osLastInsertStmt;
 
-    OGRSQLiteGeomFormat eGeomFormat;
-    char                *pszGeomCol;
-    int                 nSRSId;
-    OGRSpatialReference *poSRS;
+    int                 bHasCheckedTriggers;
 
     void                ClearInsertStmt();
 
@@ -333,6 +349,8 @@ class OGRSQLiteTableLayer : public OGRSQLiteLayer
     OGRErr              RecomputeOrdinals();
 
     OGRErr              AddColumnAncientMethod( OGRFieldDefn& oField);
+    void                AddColumnDef(char* pszNewFieldList,
+                                     OGRFieldDefn* poFldDefn);
 
     void                InitFieldListForRecrerate(char* & pszNewFieldList,
                                                   char* & pszFieldListForSelect,
@@ -344,71 +362,81 @@ class OGRSQLiteTableLayer : public OGRSQLiteLayer
                                         sqlite3_stmt* hStmt,
                                         int bBindNullValues );
 
-    int                 CheckSpatialIndexTable();
+    int                 CheckSpatialIndexTable(int iGeomCol);
 
-    CPLErr              EstablishFeatureDefn();
+    CPLErr              EstablishFeatureDefn(const char* pszGeomCol);
 
     int                 bStatisticsNeedsToBeFlushed;
-    OGREnvelope         oCachedExtent;
-    int                 bCachedExtentIsValid;
     GIntBig             nFeatureCount; /* if -1, means not up-to-date */
 
     void                LoadStatistics();
     void                LoadStatisticsSpatialite4DB();
 
     CPLString           FieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn );
+    
+    int                 bDeferredCreation;
+    OGRErr              RunAddGeometryColumn( OGRSQLiteGeomFieldDefn *poGeomField,
+                                              int bAddColumnsForNonSpatialite );
+
+    char               *pszCreationGeomFormat;
+    int                 iFIDAsRegularColumnIndex;
 
   public:
                         OGRSQLiteTableLayer( OGRSQLiteDataSource * );
                         ~OGRSQLiteTableLayer();
 
     CPLErr              Initialize( const char *pszTableName, 
-                                    const char *pszGeomCol,
-                                    int bMustIncludeGeomColName,
-                                    OGRwkbGeometryType eGeomType,
-                                    const char *pszGeomFormat,
-                                    OGRSpatialReference *poSRS,
-                                    int nSRSId = UNINITIALIZED_SRID,
-                                    int bHasSpatialIndex = FALSE,
-                                    int bHasM = FALSE,
-                                    int bIsVirtualShapeIn = FALSE);
-
+                                    int bIsVirtualShapeIn,
+                                    int bDeferredCreation);
+    void                SetCreationParameters( const char *pszFIDColumnName,
+                                               OGRwkbGeometryType eGeomType,
+                                               const char *pszGeomFormat,
+                                               const char *pszGeometryName,
+                                               OGRSpatialReference *poSRS,
+                                               int nSRSId );
     virtual const char* GetName();
-    virtual OGRwkbGeometryType GetGeomType() { return (eGeomType != wkbUnknown) ? eGeomType : OGRLayer::GetGeomType(); }
 
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce);
+    virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce);
 
     virtual OGRFeatureDefn *GetLayerDefn();
     int                 HasLayerDefnError() { GetLayerDefn(); return bLayerDefnError; }
 
     virtual void        SetSpatialFilter( OGRGeometry * );
+    virtual void        SetSpatialFilter( int iGeomField, OGRGeometry * );
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
+    virtual OGRErr      CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
+                                         int bApproxOK = TRUE );
     virtual OGRErr      DeleteField( int iField );
     virtual OGRErr      ReorderFields( int* panMap );
     virtual OGRErr      AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlags );
 
     virtual OGRFeature *GetNextFeature();
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     virtual int         TestCapability( const char * );
 
+    virtual char      **GetMetadata( const char * pszDomain = "" );
+    virtual const char *GetMetadataItem( const char * pszName,
+                                         const char * pszDomain = "" );
+
     // follow methods are not base class overrides
     void                SetLaunderFlag( int bFlag ) 
                                 { bLaunderColumnNames = bFlag; }
     void                SetUseCompressGeom( int bFlag )
                                 { bUseComprGeom = bFlag; }
-    void                SetDeferedSpatialIndexCreation( int bFlag )
-                                { bDeferedSpatialIndexCreation = bFlag; }
+    void                SetDeferredSpatialIndexCreation( int bFlag )
+                                { bDeferredSpatialIndexCreation = bFlag; }
     void                SetCompressedColumns( const char* pszCompressedColumns );
 
-    int                 CreateSpatialIndex();
+    int                 CreateSpatialIndex(int iGeomCol);
 
     void                CreateSpatialIndexIfNecessary();
 
@@ -422,10 +450,12 @@ class OGRSQLiteTableLayer : public OGRSQLiteLayer
 
     virtual int          IsTableLayer() { return TRUE; }
 
-    virtual int          HasSpatialIndex();
-
+    virtual int          HasSpatialIndex(int iGeomField);
+    virtual int          HasFastSpatialFilter(int iGeomCol);
     virtual CPLString    GetSpatialWhere(int iGeomCol,
                                          OGRGeometry* poFilterGeom);
+
+    OGRErr               RunDeferredCreationIfNecessary();
 };
 
 /************************************************************************/
@@ -440,7 +470,8 @@ class OGRSQLiteViewLayer : public OGRSQLiteLayer
 
     OGRSQLiteGeomFormat eGeomFormat;
     CPLString           osGeomColumn;
-    
+    int                 bHasSpatialIndex;
+
     char               *pszViewName;
     char               *pszEscapedTableName;
     char               *pszEscapedUnderlyingTableName;
@@ -476,37 +507,90 @@ class OGRSQLiteViewLayer : public OGRSQLiteLayer
     int                 HasLayerDefnError() { GetLayerDefn(); return bLayerDefnError; }
 
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry * );
     virtual OGRErr      SetAttributeFilter( const char * );
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
     virtual int         TestCapability( const char * );
 
+    virtual int          HasSpatialIndex(CPL_UNUSED int iGeomField) { return bHasSpatialIndex; }
     virtual CPLString    GetSpatialWhere(int iGeomCol,
                                          OGRGeometry* poFilterGeom);
 };
 
 /************************************************************************/
-/*                         OGRSQLiteSelectLayer                         */
+/*                         IOGRSQLiteSelectLayer                        */
+/************************************************************************/
+
+class IOGRSQLiteSelectLayer
+{
+    public:
+        virtual char*&               GetAttrQueryString() = 0;
+        virtual OGRFeatureQuery*&    GetFeatureQuery() = 0;
+        virtual OGRGeometry*&        GetFilterGeom() = 0;
+        virtual int&                 GetIGeomFieldFilter() = 0;
+        virtual OGRSpatialReference* GetSpatialRef() = 0;
+        virtual OGRFeatureDefn      *GetLayerDefn() = 0;
+        virtual int                  InstallFilter( OGRGeometry * ) = 0;
+        virtual int                  HasReadFeature() = 0;
+        virtual void                 BaseResetReading() = 0;
+        virtual OGRFeature          *BaseGetNextFeature() = 0;
+        virtual OGRErr               BaseSetAttributeFilter(const char* pszQuery) = 0;
+        virtual GIntBig              BaseGetFeatureCount(int bForce) = 0;
+        virtual int                  BaseTestCapability( const char * ) = 0;
+        virtual OGRErr               BaseGetExtent(OGREnvelope *psExtent, int bForce) = 0;
+        virtual OGRErr               BaseGetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) = 0;
+};
+
+/************************************************************************/
+/*                   OGRSQLiteSelectLayerCommonBehaviour                */
 /************************************************************************/
 
-class OGRSQLiteSelectLayer : public OGRSQLiteLayer
+class OGRSQLiteBaseDataSource;
+class OGRSQLiteSelectLayerCommonBehaviour
 {
+    OGRSQLiteBaseDataSource *poDS;
+    IOGRSQLiteSelectLayer   *poLayer;
+
     CPLString           osSQLBase;
-    CPLString           osSQLCurrent;
 
     int                 bEmptyLayer;
+    int                 bAllowResetReadingEvenIfIndexAtZero;
     int                 bSpatialFilterInSQL;
 
-    virtual OGRErr      ResetStatement();
-
-    OGRSQLiteLayer     *GetBaseLayer(size_t& i);
+    std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> GetBaseLayer(size_t& i);
     int                 BuildSQL();
 
-    int                 bAllowResetReadingEvenIfIndexAtZero;
+  public:
+
+    CPLString           osSQLCurrent;
+
+        OGRSQLiteSelectLayerCommonBehaviour(OGRSQLiteBaseDataSource* poDS,
+                                            IOGRSQLiteSelectLayer* poBaseLayer,
+                                            CPLString osSQL,
+                                            int bEmptyLayer);
+
+    void        ResetReading();
+    OGRFeature *GetNextFeature();
+    GIntBig     GetFeatureCount( int );
+    void        SetSpatialFilter( int iGeomField, OGRGeometry * );
+    OGRErr      SetAttributeFilter( const char * );
+    int         TestCapability( const char * );
+    OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce);
+};
+
+/************************************************************************/
+/*                         OGRSQLiteSelectLayer                         */
+/************************************************************************/
+
+class OGRSQLiteSelectLayer : public OGRSQLiteLayer, public IOGRSQLiteSelectLayer
+{
+    OGRSQLiteSelectLayerCommonBehaviour* poBehaviour;
+
+    virtual OGRErr      ResetStatement();
  
   public:
                         OGRSQLiteSelectLayer( OGRSQLiteDataSource *, 
@@ -515,11 +599,12 @@ class OGRSQLiteSelectLayer : public OGRSQLiteLayer
                                               int bUseStatementForGetNextFeature,
                                               int bEmptyLayer,
                                               int bAllowMultipleGeomFields );
+                       ~OGRSQLiteSelectLayer();
 
     virtual void        ResetReading();
 
     virtual OGRFeature *GetNextFeature();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual void        SetSpatialFilter( OGRGeometry * poGeom ) { SetSpatialFilter(0, poGeom); }
     virtual void        SetSpatialFilter( int iGeomField, OGRGeometry * );
@@ -529,6 +614,22 @@ class OGRSQLiteSelectLayer : public OGRSQLiteLayer
 
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE) { return GetExtent(0, psExtent, bForce); }
     virtual OGRErr      GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce = TRUE);
+
+    virtual OGRFeatureDefn *     GetLayerDefn() { return OGRSQLiteLayer::GetLayerDefn(); }
+    virtual char*&               GetAttrQueryString() { return m_pszAttrQueryString; }
+    virtual OGRFeatureQuery*&    GetFeatureQuery() { return m_poAttrQuery; }
+    virtual OGRGeometry*&        GetFilterGeom() { return m_poFilterGeom; }
+    virtual int&                 GetIGeomFieldFilter() { return m_iGeomFieldFilter; }
+    virtual OGRSpatialReference* GetSpatialRef() { return OGRSQLiteLayer::GetSpatialRef(); }
+    virtual int                  InstallFilter( OGRGeometry * poGeomIn ) { return OGRSQLiteLayer::InstallFilter(poGeomIn); }
+    virtual int                  HasReadFeature() { return iNextShapeId > 0; }
+    virtual void                 BaseResetReading() { OGRSQLiteLayer::ResetReading(); }
+    virtual OGRFeature          *BaseGetNextFeature() { return OGRSQLiteLayer::GetNextFeature(); }
+    virtual OGRErr               BaseSetAttributeFilter(const char* pszQuery) { return OGRSQLiteLayer::SetAttributeFilter(pszQuery); }
+    virtual GIntBig              BaseGetFeatureCount(int bForce) { return OGRSQLiteLayer::GetFeatureCount(bForce); }
+    virtual int                  BaseTestCapability( const char *pszCap ) { return OGRSQLiteLayer::TestCapability(pszCap); }
+    virtual OGRErr               BaseGetExtent(OGREnvelope *psExtent, int bForce) { return OGRSQLiteLayer::GetExtent(psExtent, bForce); }
+    virtual OGRErr               BaseGetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) { return OGRSQLiteLayer::GetExtent(iGeomField, psExtent, bForce); }
 };
 
 /************************************************************************/
@@ -557,62 +658,106 @@ class OGRSQLiteSingleFeatureLayer : public OGRLayer
 };
 
 /************************************************************************/
-/*                         OGRSQLiteDataSource                          */
+/*                       OGRSQLiteBaseDataSource                        */
 /************************************************************************/
 
-class OGRSQLiteDataSource : public OGRDataSource
+/* Used by both OGRSQLiteDataSource and OGRGeoPackageDataSource */
+class OGRSQLiteBaseDataSource : public GDALPamDataset
 {
-    OGRSQLiteLayer    **papoLayers;
-    int                 nLayers;
-    
-    char               *pszName;
+  protected:
+    char               *m_pszFilename;
 
     sqlite3             *hDB;
     int                 bUpdate;
 
+#ifdef HAVE_SQLITE_VFS
+    sqlite3_vfs*        pMyVFS;
+#endif
+
+    VSILFILE*           fpMainFile; /* Set by the VFS layer when it opens the DB */
+                                    /* Must *NOT* be closed by the datasource explicitely. */
+
+    int                 OpenOrCreateDB(int flags, int bRegisterOGR2SQLiteExtensions);
+    int                 SetSynchronous();
+    int                 SetCacheSize();
+
+    void                CloseDB();
+
+    std::map<CPLString, OGREnvelope> oMapSQLEnvelope;
+
+#ifdef SPATIALITE_412_OR_LATER
+    void               *hSpatialiteCtxt;
+    int                 InitNewSpatialite();
+    void                FinishNewSpatialite();
+#endif
+
+    int                 bUserTransactionActive;
     int                 nSoftTransactionLevel;
+    
+    OGRErr              DoTransactionCommand(const char* pszCommand);
+
+  public:
+                        OGRSQLiteBaseDataSource();
+                        ~OGRSQLiteBaseDataSource();
+
+    sqlite3            *GetDB() { return hDB; }
+    int                 GetUpdate() const { return bUpdate; }
+
+    void                NotifyFileOpened (const char* pszFilename,
+                                          VSILFILE* fp);
+
+    const OGREnvelope*  GetEnvelopeFromSQL(const CPLString& osSQL);
+    void                SetEnvelopeForSQL(const CPLString& osSQL, const OGREnvelope& oEnvelope);
+
+    virtual std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> GetLayerWithGetSpatialWhereByName( const char* pszName ) = 0;
+
+    virtual OGRErr      StartTransaction(int bForce = FALSE);
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
+    
+    virtual int         TestCapability( const char * );
+
+    OGRErr              SoftStartTransaction();
+    OGRErr              SoftCommitTransaction();
+    OGRErr              SoftRollbackTransaction();
+};
+
+/************************************************************************/
+/*                         OGRSQLiteDataSource                          */
+/************************************************************************/
+
+class OGRSQLiteDataSource : public OGRSQLiteBaseDataSource
+{
+    OGRSQLiteLayer    **papoLayers;
+    int                 nLayers;
 
     // We maintain a list of known SRID to reduce the number of trips to
     // the database to get SRSes. 
     int                 nKnownSRID;
     int                *panSRID;
     OGRSpatialReference **papoSRS;
+
+    char              **papszOpenOptions;
+
     void                AddSRIDToCache(int nId, OGRSpatialReference * poSRS );
 
     int                 bHaveGeometryColumns;
     int                 bIsSpatiaLiteDB;
     int                 bSpatialite4Layout;
 
-#ifdef SPATIALITE_412_OR_LATER
-    void               *hSpatialiteCtxt;
-    int                 InitNewSpatialite();
-    void                FinishNewSpatialite();
-#endif
-
     int                 nUndefinedSRID;
 
     virtual void        DeleteLayer( const char *pszLayer );
 
     const char*         GetSRTEXTColName();
 
-    int                 OpenOrCreateDB(int flags);
     int                 InitWithEPSG();
-    int                 SetSynchronous();
-    int                 SetCacheSize();
 
     int                 OpenVirtualTable(const char* pszName, const char* pszSQL);
 
-#ifdef HAVE_SQLITE_VFS
-    sqlite3_vfs*        pMyVFS;
-#endif
-
-    VSILFILE*           fpMainFile; /* Set by the VFS layer when it opens the DB */
-                                    /* Must *NOT* be closed by the datasource explicitely. */
     GIntBig             nFileTimestamp;
     int                 bLastSQLCommandIsUpdateLayerStatistics;
 
-    std::map<CPLString, OGREnvelope> oMapSQLEnvelope;
-
     std::map< CPLString, std::set<CPLString> > aoMapTableToSetOfGeomCols;
 
     void                SaveStatistics();
@@ -621,18 +766,10 @@ class OGRSQLiteDataSource : public OGRDataSource
                         OGRSQLiteDataSource();
                         ~OGRSQLiteDataSource();
 
-    int                 Open( const char *, int bUpdateIn );
+    int                 Open( const char *, int bUpdateIn, char** papszOpenOptions );
     int                 Create( const char *, char **papszOptions );
 
     int                 OpenTable( const char *pszTableName, 
-                                   const char *pszGeomCol = NULL,
-                                   int bMustIncludeGeomColName = FALSE,
-                                   OGRwkbGeometryType eGeomType = wkbUnknown,
-                                   const char *pszGeomFormat = NULL,
-                                   OGRSpatialReference *poSRS = NULL,
-                                   int nSRID = UNINITIALIZED_SRID,
-                                   int bHasSpatialIndex = FALSE,
-                                   int bHasM = FALSE,
                                    int bIsVirtualShapeIn = FALSE );
     int                  OpenView( const char *pszViewName,
                                    const char *pszViewGeometry,
@@ -640,12 +777,12 @@ class OGRSQLiteDataSource : public OGRDataSource
                                    const char *pszTableName,
                                    const char *pszGeometryColumn);
 
-    virtual const char *GetName() { return pszName; }
     virtual int         GetLayerCount() { return nLayers; }
     virtual OGRLayer   *GetLayer( int );
     virtual OGRLayer   *GetLayerByName( const char* );
+    virtual std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> GetLayerWithGetSpatialWhereByName( const char* pszName );
 
-    virtual OGRLayer    *CreateLayer( const char *pszLayerName, 
+    virtual OGRLayer    *ICreateLayer( const char *pszLayerName, 
                                       OGRSpatialReference *poSRS, 
                                       OGRwkbGeometryType eType, 
                                       char **papszOptions );
@@ -658,29 +795,19 @@ class OGRSQLiteDataSource : public OGRDataSource
                                     const char *pszDialect );
     virtual void        ReleaseResultSet( OGRLayer * poLayer );
 
-    OGRErr              SoftStartTransaction();
-    OGRErr              SoftCommit();
-    OGRErr              SoftRollback();
+    virtual void        FlushCache();
     
-    OGRErr              FlushSoftTransaction();
-
-    sqlite3            *GetDB() { return hDB; }
+    virtual OGRErr      CommitTransaction();
+    virtual OGRErr      RollbackTransaction();
 
     char               *LaunderName( const char * );
     int                 FetchSRSId( OGRSpatialReference * poSRS );
     OGRSpatialReference*FetchSRS( int nSRID );
 
-    int                 GetUpdate() const { return bUpdate; }
     void                SetUpdate(int bUpdateIn) { bUpdate = bUpdateIn; }
 
     void                SetName(const char* pszNameIn);
 
-    void                NotifyFileOpened (const char* pszFilename,
-                                          VSILFILE* fp);
-
-    const OGREnvelope*  GetEnvelopeFromSQL(const CPLString& osSQL);
-    void                SetEnvelopeForSQL(const CPLString& osSQL, const OGREnvelope& oEnvelope);
-
     const std::set<CPLString>& GetGeomColsForTable(const char* pszTableName)
             { return aoMapTableToSetOfGeomCols[pszTableName]; }
 
@@ -693,29 +820,11 @@ class OGRSQLiteDataSource : public OGRDataSource
     int                 HasSpatialite4Layout() const { return bSpatialite4Layout; }
 
     int                 GetUndefinedSRID() const { return nUndefinedSRID; }
+    int                 HasGeometryColumns() const { return bHaveGeometryColumns; }
 
     void                ReloadLayers();
 };
 
-/************************************************************************/
-/*                           OGRSQLiteDriver                            */
-/************************************************************************/
-
-class OGRSQLiteDriver : public OGRSFDriver
-{
-  public:
-                ~OGRSQLiteDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-    virtual OGRErr      DeleteDataSource( const char *pszName );
-    
-    int                 TestCapability( const char * );
-};
-
 /* To escape literals. The returned string doesn't contain the surrounding single quotes */
 CPLString OGRSQLiteEscape( const char *pszLiteral );
 
@@ -724,7 +833,8 @@ CPLString OGRSQLiteEscapeName( const char* pszName );
 
 CPLString OGRSQLiteParamsUnquote(const char* pszVal);
 
-CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn );
+CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn,
+                                               int bSQLiteDialectInternalUse );
 
 int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
                                     const char* pszValue );
@@ -737,5 +847,3 @@ sqlite3_vfs* OGRSQLiteCreateVFS(pfnNotifyFileOpenedType pfn, void* pfnUserData);
 void OGRSQLiteRegisterInflateDeflate(sqlite3* hDB);
 
 #endif /* ndef _OGR_SQLITE_H_INCLUDED */
-
-
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp
index 14e6f4c..1d94574 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqlitedatasource.cpp 29060 2015-04-29 21:49:46Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteDataSource class.
@@ -50,7 +50,7 @@
 static int bSpatialiteGlobalLoaded = FALSE;
 #endif
 
-CPL_CVSID("$Id: ogrsqlitedatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsqlitedatasource.cpp 29060 2015-04-29 21:49:46Z rouault $");
 
 /************************************************************************/
 /*                      OGRSQLiteInitOldSpatialite()                    */
@@ -79,10 +79,11 @@ static int OGRSQLiteInitOldSpatialite()
 /*                          InitNewSpatialite()                         */
 /************************************************************************/
 
-int OGRSQLiteDataSource::InitNewSpatialite()
+int OGRSQLiteBaseDataSource::InitNewSpatialite()
 {
     if( CSLTestBoolean(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")) )
     {
+        CPLAssert(hSpatialiteCtxt == NULL);
         hSpatialiteCtxt = spatialite_alloc_connection();
         if( hSpatialiteCtxt != NULL )
         {
@@ -97,11 +98,12 @@ int OGRSQLiteDataSource::InitNewSpatialite()
 /*                         FinishNewSpatialite()                        */
 /************************************************************************/
 
-void OGRSQLiteDataSource::FinishNewSpatialite()
+void OGRSQLiteBaseDataSource::FinishNewSpatialite()
 {
     if( hSpatialiteCtxt != NULL )
     {
         spatialite_cleanup_ex(hSpatialiteCtxt);
+        hSpatialiteCtxt = NULL;
     }
 }
 
@@ -130,25 +132,85 @@ int OGRSQLiteDataSource::GetSpatialiteVersionNumber()
 #ifdef HAVE_SPATIALITE
     if( IsSpatialiteLoaded() )
     {
-        v = (int)(( atof( spatialite_version() ) + 0.001 )  * 10.0);
+        v = (int)(( CPLAtof( spatialite_version() ) + 0.001 )  * 10.0);
     }
 #endif
     return v;
 }
 
 /************************************************************************/
+/*                       OGRSQLiteBaseDataSource()                      */
+/************************************************************************/
+
+OGRSQLiteBaseDataSource::OGRSQLiteBaseDataSource()
+
+{
+    m_pszFilename = NULL;
+    hDB = NULL;
+    bUpdate = FALSE;
+
+#ifdef HAVE_SQLITE_VFS
+    pMyVFS = NULL;
+#endif
+
+    fpMainFile = NULL; /* Do not close ! The VFS layer will do it for us */
+
+#ifdef SPATIALITE_412_OR_LATER
+    hSpatialiteCtxt = NULL;
+#endif
+
+    bUserTransactionActive = FALSE;
+    nSoftTransactionLevel = 0;
+}
+
+/************************************************************************/
+/*                      ~OGRSQLiteBaseDataSource()                      */
+/************************************************************************/
+
+OGRSQLiteBaseDataSource::~OGRSQLiteBaseDataSource()
+
+{
+#ifdef SPATIALITE_412_OR_LATER
+    FinishNewSpatialite();
+#endif
+
+    CloseDB();
+    CPLFree(m_pszFilename);
+}
+
+/************************************************************************/
+/*                               CloseDB()                              */
+/************************************************************************/
+
+void OGRSQLiteBaseDataSource::CloseDB()
+{
+    if( hDB != NULL )
+    {
+        sqlite3_close( hDB );
+        hDB = NULL;
+    }
+
+#ifdef HAVE_SQLITE_VFS
+    if (pMyVFS)
+    {
+        sqlite3_vfs_unregister(pMyVFS);
+        CPLFree(pMyVFS->pAppData);
+        CPLFree(pMyVFS);
+        pMyVFS = NULL;
+    }
+#endif
+}
+
+/************************************************************************/
 /*                        OGRSQLiteDataSource()                         */
 /************************************************************************/
 
 OGRSQLiteDataSource::OGRSQLiteDataSource()
 
 {
-    pszName = NULL;
     papoLayers = NULL;
     nLayers = 0;
 
-    nSoftTransactionLevel = 0;
-
     nKnownSRID = 0;
     panSRID = NULL;
     papoSRS = NULL;
@@ -156,23 +218,12 @@ OGRSQLiteDataSource::OGRSQLiteDataSource()
     bHaveGeometryColumns = FALSE;
     bIsSpatiaLiteDB = FALSE;
     bSpatialite4Layout = FALSE;
-    bUpdate = FALSE;
-
-#ifdef SPATIALITE_412_OR_LATER
-    hSpatialiteCtxt = NULL;
-#endif
 
     nUndefinedSRID = -1; /* will be changed to 0 if Spatialite >= 4.0 detected */
 
-    hDB = NULL;
-
-#ifdef HAVE_SQLITE_VFS
-    pMyVFS = NULL;
-#endif
-
-    fpMainFile = NULL; /* Do not close ! The VFS layer will do it for us */
     nFileTimestamp = 0;
     bLastSQLCommandIsUpdateLayerStatistics = FALSE;
+    papszOpenOptions = NULL;
 }
 
 /************************************************************************/
@@ -184,19 +235,18 @@ OGRSQLiteDataSource::~OGRSQLiteDataSource()
 {
     int         i;
 
-    for( i = 0; i < nLayers; i++ )
+    for( int iLayer = 0; iLayer < nLayers; iLayer++ )
     {
-        if( papoLayers[i]->IsTableLayer() )
+        if( papoLayers[iLayer]->IsTableLayer() )
         {
-            OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[i];
+            OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+            poLayer->RunDeferredCreationIfNecessary();
             poLayer->CreateSpatialIndexIfNecessary();
         }
     }
 
     SaveStatistics();
 
-    CPLFree( pszName );
-
     for( i = 0; i < nLayers; i++ )
         delete papoLayers[i];
     
@@ -209,22 +259,7 @@ OGRSQLiteDataSource::~OGRSQLiteDataSource()
     }
     CPLFree( panSRID );
     CPLFree( papoSRS );
-
-#ifdef SPATIALITE_412_OR_LATER
-    FinishNewSpatialite();
-#endif
-
-    if( hDB != NULL )
-        sqlite3_close( hDB );
-
-#ifdef HAVE_SQLITE_VFS
-    if (pMyVFS)
-    {
-        sqlite3_vfs_unregister(pMyVFS);
-        CPLFree(pMyVFS->pAppData);
-        CPLFree(pMyVFS);
-    }
-#endif
+    CSLDestroy( papszOpenOptions );
 }
 
 /************************************************************************/
@@ -324,7 +359,7 @@ void OGRSQLiteDataSource::SaveStatistics()
 /*                              SetSynchronous()                        */
 /************************************************************************/
 
-int OGRSQLiteDataSource::SetSynchronous()
+int OGRSQLiteBaseDataSource::SetSynchronous()
 {
     int rc;
     const char* pszSqliteSync = CPLGetConfigOption("OGR_SQLITE_SYNCHRONOUS", NULL);
@@ -362,7 +397,7 @@ int OGRSQLiteDataSource::SetSynchronous()
 /*                              SetCacheSize()                          */
 /************************************************************************/
 
-int OGRSQLiteDataSource::SetCacheSize()
+int OGRSQLiteBaseDataSource::SetCacheSize()
 {
     int rc;
     const char* pszSqliteCacheMB = CPLGetConfigOption("OGR_SQLITE_CACHE", NULL);
@@ -418,15 +453,15 @@ int OGRSQLiteDataSource::SetCacheSize()
 }
 
 /************************************************************************/
-/*                 OGRSQLiteDataSourceNotifyFileOpened()                */
+/*               OGRSQLiteBaseDataSourceNotifyFileOpened()              */
 /************************************************************************/
 
 static
-void OGRSQLiteDataSourceNotifyFileOpened (void* pfnUserData,
+void OGRSQLiteBaseDataSourceNotifyFileOpened (void* pfnUserData,
                                               const char* pszFilename,
                                               VSILFILE* fp)
 {
-    ((OGRSQLiteDataSource*)pfnUserData)->NotifyFileOpened(pszFilename, fp);
+    ((OGRSQLiteBaseDataSource*)pfnUserData)->NotifyFileOpened(pszFilename, fp);
 }
 
 
@@ -434,43 +469,120 @@ void OGRSQLiteDataSourceNotifyFileOpened (void* pfnUserData,
 /*                          NotifyFileOpened()                          */
 /************************************************************************/
 
-void OGRSQLiteDataSource::NotifyFileOpened(const char* pszFilename,
+void OGRSQLiteBaseDataSource::NotifyFileOpened(const char* pszFilename,
                                            VSILFILE* fp)
 {
-    if (strcmp(pszFilename, pszName) == 0)
+    if (strcmp(pszFilename, m_pszFilename) == 0)
     {
         fpMainFile = fp;
     }
 }
 
+#ifdef USE_SQLITE_DEBUG_MEMALLOC
+
+/* DMA9 */
+#define DMA_SIGNATURE 0x444D4139
+
+static void* OGRSQLiteDMA_Malloc(int size)
+{
+    int* ret = (int*) CPLMalloc(size + 8);
+    ret[0] = size;
+    ret[1] = DMA_SIGNATURE;
+    return ret + 2;
+}
+
+static void* OGRSQLiteDMA_Realloc(void* old_ptr, int size)
+{
+    CPLAssert(((int*)old_ptr)[-1] == DMA_SIGNATURE);
+    int* ret = (int*) CPLRealloc(old_ptr ? (int*)old_ptr - 2 : NULL, size + 8);
+    ret[0] = size;
+    ret[1] = DMA_SIGNATURE;
+    return ret + 2;
+}
+
+static void OGRSQLiteDMA_Free(void* ptr)
+{
+    if( ptr )
+    {
+        CPLAssert(((int*)ptr)[-1] == DMA_SIGNATURE);
+        ((int*)ptr)[-1] = 0;
+        CPLFree((int*)ptr - 2);
+    }
+}
+
+static int OGRSQLiteDMA_Size (void* ptr)
+{
+    if( ptr )
+    {
+        CPLAssert(((int*)ptr)[-1] == DMA_SIGNATURE);
+        return ((int*)ptr)[-2];
+    }
+    else
+        return 0;
+}
+
+static int OGRSQLiteDMA_Roundup( int size )
+{
+    return (size + 7) & (~7);
+}
+
+static int OGRSQLiteDMA_Init(void *)
+{
+    return SQLITE_OK;
+}
+
+static void OGRSQLiteDMA_Shutdown(void *)
+{
+}
+
+const struct sqlite3_mem_methods sDebugMemAlloc =
+{
+    OGRSQLiteDMA_Malloc,
+    OGRSQLiteDMA_Free,
+    OGRSQLiteDMA_Realloc,
+    OGRSQLiteDMA_Size,
+    OGRSQLiteDMA_Roundup,
+    OGRSQLiteDMA_Init,
+    OGRSQLiteDMA_Shutdown,
+    NULL
+};
+
+#endif // USE_SQLITE_DEBUG_MEMALLOC
+
 /************************************************************************/
 /*                            OpenOrCreateDB()                          */
 /************************************************************************/
 
-int OGRSQLiteDataSource::OpenOrCreateDB(int flags)
+int OGRSQLiteBaseDataSource::OpenOrCreateDB(int flags, int bRegisterOGR2SQLiteExtensions)
 {
     int rc;
-    
+
+#ifdef USE_SQLITE_DEBUG_MEMALLOC
+    if( CSLTestBoolean(CPLGetConfigOption("USE_SQLITE_DEBUG_MEMALLOC", "NO")) )
+        sqlite3_config(SQLITE_CONFIG_MALLOC, &sDebugMemAlloc);
+#endif
+
 #ifdef HAVE_SQLITE_VFS
-    OGR2SQLITE_Register();
+    if( bRegisterOGR2SQLiteExtensions )
+        OGR2SQLITE_Register();
 
     int bUseOGRVFS = CSLTestBoolean(CPLGetConfigOption("SQLITE_USE_OGR_VFS", "NO"));
-    if (bUseOGRVFS || strncmp(pszName, "/vsi", 4) == 0)
+    if (bUseOGRVFS || strncmp(m_pszFilename, "/vsi", 4) == 0)
     {
-        pMyVFS = OGRSQLiteCreateVFS(OGRSQLiteDataSourceNotifyFileOpened, this);
+        pMyVFS = OGRSQLiteCreateVFS(OGRSQLiteBaseDataSourceNotifyFileOpened, this);
         sqlite3_vfs_register(pMyVFS, 0);
-        rc = sqlite3_open_v2( pszName, &hDB, flags, pMyVFS->zName );
+        rc = sqlite3_open_v2( m_pszFilename, &hDB, flags, pMyVFS->zName );
     }
     else
-        rc = sqlite3_open_v2( pszName, &hDB, flags, NULL );
+        rc = sqlite3_open_v2( m_pszFilename, &hDB, flags, NULL );
 #else
-    rc = sqlite3_open( pszName, &hDB );
+    rc = sqlite3_open( m_pszFilename, &hDB );
 #endif
     if( rc != SQLITE_OK )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "sqlite3_open(%s) failed: %s",
-                  pszName, sqlite3_errmsg( hDB ) );
+                  m_pszFilename, sqlite3_errmsg( hDB ) );
         return FALSE;
     }
 
@@ -495,7 +607,7 @@ int OGRSQLiteDataSource::OpenOrCreateDB(int flags)
         {
             CPLError( CE_Failure, CPLE_OpenFailed, "%s", 
                 "A trigger and/or view calls a OGR extension SQL function that could be used to "
-                "steal data, or use network bandwith, without your consent.\n"
+                "steal data, or use network bandwidth, without your consent.\n"
                 "The database will not be opened unless the ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW "
                 "configuration option to YES.");
             return FALSE;
@@ -571,7 +683,7 @@ int OGRSQLiteDataSource::Create( const char * pszNameIn, char **papszOptions )
     CPLString osCommand;
     char *pszErrMsg = NULL;
 
-    pszName = CPLStrdup( pszNameIn );
+    m_pszFilename = CPLStrdup( pszNameIn );
 
 /* -------------------------------------------------------------------- */
 /*      Check that spatialite extensions are loaded if required to      */
@@ -606,11 +718,7 @@ int OGRSQLiteDataSource::Create( const char * pszNameIn, char **papszOptions )
 /* -------------------------------------------------------------------- */
 /*      Create the database file.                                       */
 /* -------------------------------------------------------------------- */
-#ifdef HAVE_SQLITE_VFS
-    if (!OpenOrCreateDB(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE))
-#else
-    if (!OpenOrCreateDB(0))
-#endif
+    if (!OpenOrCreateDB(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, TRUE))
         return FALSE;
 
 /* -------------------------------------------------------------------- */
@@ -713,7 +821,7 @@ int OGRSQLiteDataSource::Create( const char * pszNameIn, char **papszOptions )
             return FALSE;
     }
 
-    return Open(pszName, TRUE);
+    return Open(m_pszFilename, TRUE, NULL);
 }
 
 /************************************************************************/
@@ -723,7 +831,6 @@ int OGRSQLiteDataSource::Create( const char * pszNameIn, char **papszOptions )
 int OGRSQLiteDataSource::InitWithEPSG()
 {
     CPLString osCommand;
-    char* pszErrMsg = NULL;
 
     if ( bIsSpatiaLiteDB )
     {
@@ -735,19 +842,13 @@ int OGRSQLiteDataSource::InitWithEPSG()
         if ( iSpatialiteVersion >= 24 )
             return TRUE;
     }
-
-    int rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
-    if( rc != SQLITE_OK )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                "Unable to insert into spatial_ref_sys: %s",
-                pszErrMsg );
-        sqlite3_free( pszErrMsg );
+    
+    if( SoftStartTransaction() != OGRERR_NONE )
         return FALSE;
-    }
 
     FILE* fp;
     int i;
+    int rc = SQLITE_OK;
     for(i=0;i<2 && rc == SQLITE_OK;i++)
     {
         const char* pszFilename = (i == 0) ? "gcs.csv" : "pcs.csv";
@@ -923,20 +1024,17 @@ int OGRSQLiteDataSource::InitWithEPSG()
         VSIFClose(fp);
     }
 
-    if (rc == SQLITE_OK)
-        rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
+    if( rc == SQLITE_OK )
+    {
+        if( SoftCommitTransaction() != OGRERR_NONE )
+            return FALSE;
+        return TRUE;
+    }
     else
-        rc = sqlite3_exec( hDB, "ROLLBACK", NULL, NULL, &pszErrMsg );
-
-    if( rc != SQLITE_OK )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                "Unable to insert into spatial_ref_sys: %s",
-                pszErrMsg );
-        sqlite3_free( pszErrMsg );
+        SoftRollbackTransaction();
+        return FALSE;
     }
-
-    return (rc == SQLITE_OK);
 }
 
 /************************************************************************/
@@ -951,34 +1049,46 @@ void OGRSQLiteDataSource::ReloadLayers()
     papoLayers = NULL;
     nLayers = 0;
 
-    Open(pszName, bUpdate);
+    Open(m_pszFilename, bUpdate, NULL);
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRSQLiteDataSource::Open( const char * pszNewName, int bUpdateIn )
+int OGRSQLiteDataSource::Open( const char * pszNewName, int bUpdateIn,
+                               char** papszOpenOptionsIn)
 
 {
     CPLAssert( nLayers == 0 );
 
-    if (pszName == NULL)
-        pszName = CPLStrdup( pszNewName );
+    if (m_pszFilename == NULL)
+        m_pszFilename = CPLStrdup( pszNewName );
+    SetDescription(m_pszFilename);
     bUpdate = bUpdateIn;
 
     VSIStatBufL sStat;
-    if( VSIStatL( pszName, &sStat ) == 0 )
+    if( VSIStatL( m_pszFilename, &sStat ) == 0 )
     {
         nFileTimestamp = sStat.st_mtime;
     }
-
-    int bListAllTables = CSLTestBoolean(CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO"));
+    
+    if( papszOpenOptionsIn )
+    {
+        CSLDestroy(papszOpenOptions);
+        papszOpenOptions = CSLDuplicate(papszOpenOptionsIn);
+    }
+    
+    int bListAllTables = CSLTestBoolean(CSLFetchNameValueDef(
+        papszOpenOptions, "LIST_ALL_TABLES",
+        CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO")));
 
     // Don't list by default: there might be some security implications
     // if a user is provided with a file and doesn't know that there are
     // virtual OGR tables in it.
-    int bListVirtualOGRLayers = CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_LIST_VIRTUAL_OGR", "NO"));
+    int bListVirtualOGRLayers = CSLTestBoolean(CSLFetchNameValueDef(
+        papszOpenOptions, "LIST_VIRTUAL_OGR",
+        CPLGetConfigOption("OGR_SQLITE_LIST_VIRTUAL_OGR", "NO")));
 
 /* -------------------------------------------------------------------- */
 /*      Try to open the sqlite database properly now.                   */
@@ -989,11 +1099,7 @@ int OGRSQLiteDataSource::Open( const char * pszNewName, int bUpdateIn )
         OGRSQLiteInitOldSpatialite();
 #endif
 
-#ifdef HAVE_SQLITE_VFS
-        if (!OpenOrCreateDB((bUpdateIn) ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY) )
-#else
-        if (!OpenOrCreateDB(0))
-#endif
+        if (!OpenOrCreateDB((bUpdateIn) ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY, TRUE) )
             return FALSE;
 
 #ifdef SPATIALITE_412_OR_LATER
@@ -1033,38 +1139,22 @@ int OGRSQLiteDataSource::Open( const char * pszNewName, int bUpdateIn )
             if( pszTableName == NULL || pszGeomCol == NULL )
                 continue;
 
-            aoMapTableToSetOfGeomCols[pszTableName].insert(pszGeomCol);
+            aoMapTableToSetOfGeomCols[pszTableName].insert(CPLString(pszGeomCol).tolower());
         }
 
         for( iRow = 0; iRow < nRowCount; iRow++ )
         {
             char **papszRow = papszResult + iRow * 6 + 6;
-            OGRwkbGeometryType eGeomType = wkbUnknown;
-            int nSRID = 0;
             const char* pszTableName = papszRow[0];
-            const char* pszGeomCol = papszRow[1];
 
-            if (pszTableName == NULL ||
-                pszGeomCol == NULL ||
-                papszRow[2] == NULL ||
-                papszRow[3] == NULL)
+            if (pszTableName == NULL)
                 continue;
 
-            eGeomType = (OGRwkbGeometryType) atoi(papszRow[2]);
-
-            if( atoi(papszRow[3]) > 2 )
-                eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
-
-            if( papszRow[5] != NULL )
-                nSRID = atoi(papszRow[5]);
+            if( GDALDataset::GetLayerByName(pszTableName) == NULL )
+                OpenTable( pszTableName );
 
-            int nOccurences = (int)aoMapTableToSetOfGeomCols[pszTableName].size();
-
-            OpenTable( pszTableName, pszGeomCol, nOccurences > 1, eGeomType, papszRow[4],
-                       FetchSRS( nSRID ) );
-                       
             if (bListAllTables)
-                CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
+                CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
         }
 
         sqlite3_free_table(papszResult);
@@ -1186,72 +1276,21 @@ int OGRSQLiteDataSource::Open( const char * pszNewName, int bUpdateIn )
             if( pszTableName == NULL || pszGeomCol == NULL )
                 continue;
 
-            aoMapTableToSetOfGeomCols[pszTableName].insert(pszGeomCol);
+            aoMapTableToSetOfGeomCols[pszTableName].insert(CPLString(pszGeomCol).tolower());
         }
 
         for ( iRow = 0; iRow < nRowCount; iRow++ )
         {
             char **papszRow = papszResult + iRow * 6 + 6;
-            OGRwkbGeometryType eGeomType = wkbUnknown;
-            int nSRID = 0;
-            int bHasM = FALSE;
-            int bHasSpatialIndex = FALSE;
             const char* pszTableName = papszRow[0];
-            const char* pszGeomCol = papszRow[1];
 
-            if (pszTableName == NULL ||
-                pszGeomCol == NULL ||
-                papszRow[2] == NULL ||
-                papszRow[3] == NULL)
+            if (pszTableName == NULL )
                 continue;
 
-            if( bSpatialite4Layout )
-            {
-                int nGeomType = atoi(papszRow[2]);
-
-                if( nGeomType >= 0 && nGeomType <= 7 ) /* XY */
-                    eGeomType = (OGRwkbGeometryType) nGeomType;
-                else if( nGeomType >= 1000 && nGeomType <= 1007 ) /* XYZ */
-                    eGeomType = (OGRwkbGeometryType) ((nGeomType - 1000) | wkb25DBit);
-                else if( nGeomType >= 2000 && nGeomType <= 2007 ) /* XYM */
-                {
-                    eGeomType = (OGRwkbGeometryType) (nGeomType - 2000);
-                    bHasM = TRUE;
-                }
-                else if( nGeomType >= 3000 && nGeomType <= 3007 ) /* XYZM */
-                {
-                    eGeomType = (OGRwkbGeometryType) ((nGeomType - 3000) | wkb25DBit);
-                    bHasM = TRUE;
-                }
-            }
-            else
-            {
-                eGeomType = OGRFromOGCGeomType(papszRow[2]);
-
-                if( strcmp ( papszRow[3], "XYZ" ) == 0 ||
-                    strcmp ( papszRow[3], "XYZM" ) == 0 ||
-                    strcmp ( papszRow[3], "3" ) == 0) // SpatiaLite's own 3D geometries
-                    eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
-
-                if( strcmp ( papszRow[3], "XYM" ) == 0 ||
-                    strcmp ( papszRow[3], "XYZM" ) == 0 ) // M coordinate declared
-                    bHasM = TRUE;
-            }
-
-
-            if( papszRow[4] != NULL )
-                nSRID = atoi(papszRow[4]);
-
-            if( papszRow[5] != NULL )
-                bHasSpatialIndex = atoi(papszRow[5]);
-
-            int nOccurences = (int)aoMapTableToSetOfGeomCols[pszTableName].size();
-
-            OpenTable( pszTableName, pszGeomCol, nOccurences > 1, eGeomType, "SpatiaLite",
-                       FetchSRS( nSRID ), nSRID, bHasSpatialIndex, bHasM );
-                       
+            if( GDALDataset::GetLayerByName(pszTableName) == NULL )
+                OpenTable( pszTableName);
             if (bListAllTables)
-                CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
+                CPLHashSetInsert(hSet, CPLStrdup(pszTableName));
         }
 
         sqlite3_free_table(papszResult);
@@ -1402,12 +1441,21 @@ int OGRSQLiteDataSource::OpenVirtualTable(const char* pszName, const char* pszSQ
         }
     }
 
-    if (OpenTable(pszName, NULL, FALSE, wkbUnknown, NULL,
-                 (nSRID > 0) ? FetchSRS( nSRID ) : NULL, nSRID,
-                  FALSE, FALSE,
-                  pszVirtualShape != NULL))
+    if (OpenTable(pszName, pszVirtualShape != NULL))
     {
         OGRSQLiteLayer* poLayer = papoLayers[nLayers-1];
+        if( poLayer->GetLayerDefn()->GetGeomFieldCount() == 1 )
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+                    poLayer->myGetLayerDefn()->myGetGeomFieldDefn(0);
+            poGeomFieldDefn->eGeomFormat = OSGF_SpatiaLite;
+            if( nSRID > 0 )
+            {
+                poGeomFieldDefn->nSRSId = nSRID;
+                poGeomFieldDefn->SetSpatialRef( FetchSRS( nSRID ) );
+            }
+        }
+
         OGRFeature* poFeature = poLayer->GetNextFeature();
         if (poFeature)
         {
@@ -1419,6 +1467,7 @@ int OGRSQLiteDataSource::OpenVirtualTable(const char* pszName, const char* pszSQ
         poLayer->ResetReading();
         return TRUE;
     }
+
     return FALSE;
 }
 
@@ -1427,12 +1476,6 @@ int OGRSQLiteDataSource::OpenVirtualTable(const char* pszName, const char* pszSQ
 /************************************************************************/
 
 int OGRSQLiteDataSource::OpenTable( const char *pszTableName,
-                                    const char *pszGeomCol,
-                                    int bMustIncludeGeomColName,
-                                    OGRwkbGeometryType eGeomType,
-                                    const char *pszGeomFormat,
-                                    OGRSpatialReference *poSRS, int nSRID,
-                                    int bHasSpatialIndex, int bHasM, 
                                     int bIsVirtualShapeIn )
 
 {
@@ -1442,12 +1485,7 @@ int OGRSQLiteDataSource::OpenTable( const char *pszTableName,
     OGRSQLiteTableLayer  *poLayer;
 
     poLayer = new OGRSQLiteTableLayer( this );
-
-    if( poLayer->Initialize( pszTableName, pszGeomCol, bMustIncludeGeomColName,
-                             eGeomType, pszGeomFormat,
-                             poSRS, nSRID, bHasSpatialIndex, 
-                             bHasM,
-                             bIsVirtualShapeIn) != CE_None )
+    if( poLayer->Initialize( pszTableName, bIsVirtualShapeIn, FALSE) != CE_None )
     {
         delete poLayer;
         return FALSE;
@@ -1509,8 +1547,24 @@ int OGRSQLiteDataSource::TestCapability( const char * pszCap )
         return bUpdate;
     else if( EQUAL(pszCap,ODsCDeleteLayer) )
         return bUpdate;
+    else if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return !bIsSpatiaLiteDB;
+    else if EQUAL(pszCap,ODsCCreateGeomFieldAfterCreateLayer)
+        return bUpdate;
     else
-        return FALSE;
+        return OGRSQLiteBaseDataSource::TestCapability(pszCap);
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRSQLiteBaseDataSource::TestCapability( const char * pszCap )
+{
+    if EQUAL(pszCap,ODsCTransactions)
+        return TRUE;
+    else
+        return GDALPamDataset::TestCapability(pszCap);
 }
 
 /************************************************************************/
@@ -1533,7 +1587,7 @@ OGRLayer *OGRSQLiteDataSource::GetLayer( int iLayer )
 OGRLayer *OGRSQLiteDataSource::GetLayerByName( const char* pszLayerName )
 
 {
-    OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszLayerName);
+    OGRLayer* poLayer = GDALDataset::GetLayerByName(pszLayerName);
     if( poLayer != NULL )
         return poLayer;
 
@@ -1557,6 +1611,35 @@ OGRLayer *OGRSQLiteDataSource::GetLayerByName( const char* pszLayerName )
 }
 
 /************************************************************************/
+/*                   GetLayerWithGetSpatialWhereByName()                */
+/************************************************************************/
+
+std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>
+    OGRSQLiteDataSource::GetLayerWithGetSpatialWhereByName( const char* pszName )
+{
+    OGRSQLiteLayer* poRet = (OGRSQLiteLayer*) GetLayerByName(pszName);
+    return std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>(poRet, poRet);
+}
+
+/************************************************************************/
+/*                              FlushCache()                            */
+/************************************************************************/
+
+void OGRSQLiteDataSource::FlushCache()
+{
+    for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+    {
+        if( papoLayers[iLayer]->IsTableLayer() )
+        {
+            OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+            poLayer->RunDeferredCreationIfNecessary();
+            poLayer->CreateSpatialIndexIfNecessary();
+        }
+    }
+    GDALDataset::FlushCache();
+}
+
+/************************************************************************/
 /*                             ExecuteSQL()                             */
 /************************************************************************/
 
@@ -1579,8 +1662,18 @@ OGRLayer * OGRSQLiteDataSource::ExecuteSQL( const char *pszSQLCommand,
                                           const char *pszDialect )
 
 {
+    for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+    {
+        if( papoLayers[iLayer]->IsTableLayer() )
+        {
+            OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+            poLayer->RunDeferredCreationIfNecessary();
+            poLayer->CreateSpatialIndexIfNecessary();
+        }
+    }
+
     if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
-        return OGRDataSource::ExecuteSQL( pszSQLCommand, 
+        return GDALDataset::ExecuteSQL( pszSQLCommand, 
                                           poSpatialFilter, 
                                           pszDialect );
 
@@ -1808,11 +1901,11 @@ void OGRSQLiteDataSource::ReleaseResultSet( OGRLayer * poLayer )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
+OGRSQLiteDataSource::ICreateLayer( const char * pszLayerNameIn,
                                   OGRSpatialReference *poSRS,
                                   OGRwkbGeometryType eType,
                                   char ** papszOptions )
@@ -1821,7 +1914,7 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
     char                *pszLayerName;
     const char          *pszGeomFormat;
     int                  bImmediateSpatialIndexCreation = FALSE;
-    int                  bDeferedSpatialIndexCreation = FALSE;
+    int                  bDeferredSpatialIndexCreation = FALSE;
 
 /* -------------------------------------------------------------------- */
 /*      Verify we are in update mode.                                   */
@@ -1831,19 +1924,36 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
         CPLError( CE_Failure, CPLE_NoWriteAccess,
                   "Data source %s opened read-only.\n"
                   "New layer %s cannot be created.\n",
-                  pszName, pszLayerNameIn );
+                  m_pszFilename, pszLayerNameIn );
 
         return NULL;
     }
 
+    for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+    {
+        if( papoLayers[iLayer]->IsTableLayer() )
+        {
+            OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+            poLayer->RunDeferredCreationIfNecessary();
+        }
+    }
+
+    CPLString osFIDColumnName;
+    const char* pszFIDColumnNameIn = CSLFetchNameValueDef(papszOptions, "FID", "OGC_FID");
+    if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
+    {
+        char* pszFIDColumnName = LaunderName(pszFIDColumnNameIn);
+        osFIDColumnName = pszFIDColumnName;
+        CPLFree(pszFIDColumnName);
+    }
+    else
+        osFIDColumnName = pszFIDColumnNameIn;
+
     if( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) )
         pszLayerName = LaunderName( pszLayerNameIn );
     else
         pszLayerName = CPLStrdup( pszLayerNameIn );
 
-    CPLString osEscapedLayerName = OGRSQLiteEscape(pszLayerName);
-    const char* pszEscapedLayerName = osEscapedLayerName.c_str();
-    
     pszGeomFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
     if( pszGeomFormat == NULL )
     {
@@ -1863,6 +1973,24 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
         CPLFree( pszLayerName );
         return NULL;
     }
+    
+    CPLString osGeometryName;
+    const char* pszGeometryNameIn = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME" );
+    if( pszGeometryNameIn == NULL )
+    {
+        osGeometryName = ( EQUAL(pszGeomFormat,"WKT") ) ? "WKT_GEOMETRY" : "GEOMETRY";
+    }
+    else
+    {
+        if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
+        {
+            char* pszGeometryName = LaunderName(pszGeometryNameIn);
+            osGeometryName = pszGeometryName;
+            CPLFree(pszGeometryName);
+        }
+        else
+            osGeometryName = pszGeometryNameIn;
+    }
 
     if (bIsSpatiaLiteDB && !EQUAL(pszGeomFormat, "SpatiaLite") )
     {
@@ -1936,189 +2064,9 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
     else if( poSRS != NULL )
         nSRSId = FetchSRSId( poSRS );
 
-/* -------------------------------------------------------------------- */
-/*      Create a basic table with the FID.  Also include the            */
-/*      geometry if this is not a PostGIS enabled table.                */
-/* -------------------------------------------------------------------- */
-    int rc;
-    char *pszErrMsg;
-    const char *pszGeomCol = NULL;
-    CPLString osCommand;
-
-    if( eType == wkbNone )
-        osCommand.Printf( 
-            "CREATE TABLE '%s' ( OGC_FID INTEGER PRIMARY KEY )", 
-            pszEscapedLayerName );
-    else
-    {
-        if( EQUAL(pszGeomFormat,"WKT") )
-        {
-            pszGeomCol = "WKT_GEOMETRY";
-            osCommand.Printf(
-                "CREATE TABLE '%s' ( "
-                "  OGC_FID INTEGER PRIMARY KEY,"
-                "  '%s' VARCHAR )", 
-                pszEscapedLayerName,
-                OGRSQLiteEscape(pszGeomCol).c_str() );
-        }
-        else
-        {
-            pszGeomCol = "GEOMETRY";
-
-            /* Only if was created as a SpatiaLite DB */
-            if ( bIsSpatiaLiteDB )
-            {
-                /* 
-                / SpatiaLite full support: we must create the 
-                / Geometry in a second time using AddGeometryColumn()
-                /
-                / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
-                / to directly creating some Geometry column 
-                / [by-passing AddGeometryColumn() as absolutely required]
-                / will severely [and irremediably] corrupt the DB !!!
-                */
-                osCommand.Printf( "CREATE TABLE '%s' ( "
-                                  "  OGC_FID INTEGER PRIMARY KEY)",
-                                  pszEscapedLayerName);
-            }
-            else
-            {
-                osCommand.Printf( "CREATE TABLE '%s' ( "
-                                  "  OGC_FID INTEGER PRIMARY KEY,"
-                                  "  '%s' BLOB )", 
-                                  pszEscapedLayerName,
-                                  OGRSQLiteEscape(pszGeomCol).c_str() );
-            }
-        }
-    }
-
-#ifdef DEBUG
-    CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
-#endif
-
-    rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
-    if( rc != SQLITE_OK )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined, 
-                  "Unable to create table %s: %s",
-                  pszLayerName, pszErrMsg );
-        sqlite3_free( pszErrMsg );
-        return FALSE;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Eventually we should be adding this table to a table of         */
-/*      "geometric layers", capturing the WKT projection, and           */
-/*      perhaps some other housekeeping.                                */
-/* -------------------------------------------------------------------- */
+    const char* pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
     if( bHaveGeometryColumns && eType != wkbNone )
     {
-        int nCoordDim;
-
-        /* Sometimes there is an old cruft entry in the geometry_columns
-         * table if things were not properly cleaned up before.  We make
-         * an effort to clean out such cruft.
-         */
-        osCommand.Printf(
-            "DELETE FROM geometry_columns WHERE f_table_name = '%s'", 
-            pszEscapedLayerName );
-                 
-#ifdef DEBUG
-        CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
-#endif
-
-        rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
-        if( rc != SQLITE_OK )
-        {
-            sqlite3_free( pszErrMsg );
-            return FALSE;
-        }
-        
-        if( eType == wkbFlatten(eType) )
-            nCoordDim = 2;
-        else
-            nCoordDim = 3;
-        
-        if ( bIsSpatiaLiteDB )
-        {
-            /*
-            / SpatiaLite full support: calling AddGeometryColumn()
-            /
-            / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
-            / to directly INSERT a row into GEOMETRY_COLUMNS
-            / [by-passing AddGeometryColumn() as absolutely required]
-            / will severely [and irremediably] corrupt the DB !!!
-            */
-            const char *pszType = OGRToOGCGeomType(eType);
-            if (pszType[0] == '\0')
-                pszType = "GEOMETRY";
-
-            /*
-            / SpatiaLite v.2.4.0 (or any subsequent) is required
-            / to support 2.5D: if an obsolete version of the library
-            / is found we'll unconditionally activate 2D casting mode
-            */
-            int iSpatialiteVersion = GetSpatialiteVersionNumber();
-            if ( iSpatialiteVersion < 24 && nCoordDim == 3 )
-            {
-                CPLDebug("SQLITE", "Spatialite < 2.4.0 --> 2.5D geometry not supported. Casting to 2D");
-                nCoordDim = 2;
-            }
-
-            osCommand.Printf( "SELECT AddGeometryColumn("
-                              "'%s', '%s', %d, '%s', %d)",
-                              pszEscapedLayerName,
-                              OGRSQLiteEscape(pszGeomCol).c_str(), nSRSId,
-                              pszType, nCoordDim );
-        }
-        else
-        {
-            if( nSRSId > 0 )
-            {
-                osCommand.Printf(
-                    "INSERT INTO geometry_columns "
-                    "(f_table_name, f_geometry_column, geometry_format, "
-                    "geometry_type, coord_dimension, srid) VALUES "
-                    "('%s','%s','%s', %d, %d, %d)", 
-                    pszEscapedLayerName,
-                    OGRSQLiteEscape(pszGeomCol).c_str(), pszGeomFormat,
-                    (int) wkbFlatten(eType), nCoordDim, nSRSId );
-            }
-            else
-            {
-                osCommand.Printf(
-                    "INSERT INTO geometry_columns "
-                    "(f_table_name, f_geometry_column, geometry_format, "
-                    "geometry_type, coord_dimension) VALUES "
-                    "('%s','%s','%s', %d, %d)",
-                    pszEscapedLayerName,
-                    OGRSQLiteEscape(pszGeomCol).c_str(), pszGeomFormat,
-                    (int) wkbFlatten(eType), nCoordDim );
-            }
-        }
-
-#ifdef DEBUG
-        CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
-#endif
-
-        rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
-        if( rc != SQLITE_OK )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "Unable to add %s table to geometry_columns:\n%s",
-                      pszLayerName, pszErrMsg );
-            sqlite3_free( pszErrMsg );
-            return FALSE;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Create the spatial index.                                       */
-/*                                                                      */
-/*      We're doing this before we add geometry and record to the table */
-/*      so this may not be exactly the best way to do it.               */
-/* -------------------------------------------------------------------- */
-
-        const char* pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
         if ( pszSI != NULL && CSLTestBoolean(pszSI) &&
              (bIsSpatiaLiteDB || EQUAL(pszGeomFormat, "SpatiaLite")) && !IsSpatialiteLoaded() )
         {
@@ -2139,10 +2087,17 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
             }
             else if( pszSI == NULL || CSLTestBoolean(pszSI) )
             {
-                bDeferedSpatialIndexCreation = TRUE;
+                bDeferredSpatialIndexCreation = TRUE;
             }
         }
     }
+    else if( bHaveGeometryColumns )
+    {
+#ifdef HAVE_SPATIALITE
+        if( bIsSpatiaLiteDB && IsSpatialiteLoaded() && (pszSI == NULL || CSLTestBoolean(pszSI)) )
+            bDeferredSpatialIndexCreation = TRUE;
+#endif
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Create the layer object.                                        */
@@ -2151,30 +2106,9 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
 
     poLayer = new OGRSQLiteTableLayer( this );
 
-    if ( poLayer->Initialize( pszLayerName, pszGeomCol, FALSE, eType, pszGeomFormat,
-                              FetchSRS(nSRSId), nSRSId, FALSE, FALSE,
-                              FALSE ) != CE_None )
-    {
-        delete poLayer;
-        CPLFree( pszLayerName );
-        return NULL;
-    }
-
-    poLayer->InitFeatureCount();
-    poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
-    if ( CSLFetchBoolean(papszOptions,"COMPRESS_GEOM",FALSE) )
-        poLayer->SetUseCompressGeom( TRUE );
-    if( bImmediateSpatialIndexCreation )
-        poLayer->CreateSpatialIndex();
-    else if( bDeferedSpatialIndexCreation )
-        poLayer->SetDeferedSpatialIndexCreation( TRUE );
-    poLayer->SetCompressedColumns( CSLFetchNameValue(papszOptions,"COMPRESS_COLUMNS") );
-
-    if( bIsSpatiaLiteDB && nLayers == 0)
-    {
-        /* To create the layer_statistics and spatialite_history tables */
-        sqlite3_exec( hDB, "SELECT UpdateLayerStatistics()", NULL, NULL, NULL );
-    }
+    poLayer->Initialize( pszLayerName, FALSE, TRUE ) ;
+    poLayer->SetCreationParameters( osFIDColumnName, eType, pszGeomFormat,
+                                    osGeometryName, poSRS, nSRSId );
 
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
@@ -2184,6 +2118,16 @@ OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
     
     papoLayers[nLayers++] = poLayer;
 
+    poLayer->InitFeatureCount();
+    poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
+    if ( CSLFetchBoolean(papszOptions,"COMPRESS_GEOM",FALSE) )
+        poLayer->SetUseCompressGeom( TRUE );
+    if( bImmediateSpatialIndexCreation )
+        poLayer->CreateSpatialIndex(0);
+    else if( bDeferredSpatialIndexCreation )
+        poLayer->SetDeferredSpatialIndexCreation( TRUE );
+    poLayer->SetCompressedColumns( CSLFetchNameValue(papszOptions,"COMPRESS_COLUMNS") );
+
     CPLFree( pszLayerName );
 
     return poLayer;
@@ -2287,7 +2231,7 @@ void OGRSQLiteDataSource::DeleteLayer( const char *pszLayerName )
         CPLError( CE_Failure, CPLE_NoWriteAccess,
                   "Data source %s opened read-only.\n"
                   "Layer %s cannot be deleted.\n",
-                  pszName, pszLayerName );
+                  m_pszFilename, pszLayerName );
 
         return;
     }
@@ -2407,6 +2351,112 @@ OGRErr OGRSQLiteDataSource::DeleteLayer(int iLayer)
     return OGRERR_NONE;
 }
 
+
+/************************************************************************/
+/*                         StartTransaction()                           */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRSQLiteBaseDataSource::StartTransaction(CPL_UNUSED int bForce)
+{
+    if( bUserTransactionActive || nSoftTransactionLevel != 0 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Transaction already established");
+        return OGRERR_FAILURE;
+    }
+
+    OGRErr eErr = SoftStartTransaction();
+    if( eErr != OGRERR_NONE )
+        return eErr;
+
+    bUserTransactionActive = TRUE;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                         CommitTransaction()                          */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRSQLiteBaseDataSource::CommitTransaction()
+{
+    if( !bUserTransactionActive )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
+        return OGRERR_FAILURE;
+    }
+
+    bUserTransactionActive = FALSE;
+    CPLAssert( nSoftTransactionLevel == 1 );
+    return SoftCommitTransaction();
+}
+
+OGRErr OGRSQLiteDataSource::CommitTransaction()
+
+{
+    if( nSoftTransactionLevel == 1 )
+    {
+        for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+        {
+            if( papoLayers[iLayer]->IsTableLayer() )
+            {
+                OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+                poLayer->RunDeferredCreationIfNecessary();
+                //poLayer->CreateSpatialIndexIfNecessary();
+            }
+        }
+    }
+
+    return OGRSQLiteBaseDataSource::CommitTransaction();
+}
+
+/************************************************************************/
+/*                        RollbackTransaction()                         */
+/*                                                                      */
+/* Should only be called by user code. Not driver internals.            */
+/************************************************************************/
+
+OGRErr OGRSQLiteBaseDataSource::RollbackTransaction()
+{
+    if( !bUserTransactionActive )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Transaction not established");
+        return OGRERR_FAILURE;
+    }
+
+    bUserTransactionActive = FALSE;
+    CPLAssert( nSoftTransactionLevel == 1 );
+    return SoftRollbackTransaction();
+}
+
+OGRErr OGRSQLiteDataSource::RollbackTransaction()
+
+{
+    if( nSoftTransactionLevel == 1 )
+    {
+        for( int iLayer = 0; iLayer < nLayers; iLayer++ )
+        {
+            if( papoLayers[iLayer]->IsTableLayer() )
+            {
+                OGRSQLiteTableLayer* poLayer = (OGRSQLiteTableLayer*) papoLayers[iLayer];
+                poLayer->RunDeferredCreationIfNecessary();
+                poLayer->CreateSpatialIndexIfNecessary();
+            }
+        }
+
+        for(int i = 0; i < nLayers; i++)
+        {
+            papoLayers[i]->InvalidateCachedFeatureCountAndExtent();
+            papoLayers[i]->ResetReading();
+        }
+    }
+
+    return OGRSQLiteBaseDataSource::RollbackTransaction();
+}
+
 /************************************************************************/
 /*                        SoftStartTransaction()                        */
 /*                                                                      */
@@ -2415,136 +2465,110 @@ OGRErr OGRSQLiteDataSource::DeleteLayer(int iLayer)
 /*      an increment to the scope count.                                */
 /************************************************************************/
 
-OGRErr OGRSQLiteDataSource::SoftStartTransaction()
+OGRErr OGRSQLiteBaseDataSource::SoftStartTransaction()
 
 {
     nSoftTransactionLevel++;
 
+    OGRErr eErr = OGRERR_NONE;
     if( nSoftTransactionLevel == 1 )
     {
-        int rc;
-        char *pszErrMsg;
-        
-#ifdef DEBUG
-        CPLDebug( "OGR_SQLITE", "BEGIN Transaction" );
-#endif
-
-        rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
-        if( rc != SQLITE_OK )
-        {
-            nSoftTransactionLevel--;
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "BEGIN transaction failed: %s",
-                      pszErrMsg );
-            sqlite3_free( pszErrMsg );
-            return OGRERR_FAILURE;
-        }
+        eErr = DoTransactionCommand("BEGIN");
     }
+    
+    //CPLDebug("SQLite", "%p->SoftStartTransaction() : %d",
+    //         this, nSoftTransactionLevel);
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                             SoftCommit()                             */
+/*                     SoftCommitTransaction()                          */
 /*                                                                      */
 /*      Commit the current transaction if we are at the outer           */
 /*      scope.                                                          */
 /************************************************************************/
 
-OGRErr OGRSQLiteDataSource::SoftCommit()
+OGRErr OGRSQLiteBaseDataSource::SoftCommitTransaction()
 
 {
+    //CPLDebug("SQLite", "%p->SoftCommitTransaction() : %d",
+    //         this, nSoftTransactionLevel);
+
     if( nSoftTransactionLevel <= 0 )
     {
-        CPLDebug( "OGR_SQLITE", "SoftCommit() with no transaction active." );
+        CPLAssert(FALSE);
         return OGRERR_FAILURE;
     }
 
+    OGRErr eErr = OGRERR_NONE;
     nSoftTransactionLevel--;
-
     if( nSoftTransactionLevel == 0 )
     {
-        int rc;
-        char *pszErrMsg;
-        
-#ifdef DEBUG
-        CPLDebug( "OGR_SQLITE", "COMMIT Transaction" );
-#endif
-
-        rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
-        if( rc != SQLITE_OK )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "COMMIT transaction failed: %s",
-                      pszErrMsg );
-            sqlite3_free( pszErrMsg );
-            return OGRERR_FAILURE;
-        }
+        eErr = DoTransactionCommand("COMMIT");
     }
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                            SoftRollback()                            */
+/*                  SoftRollbackTransaction()                           */
 /*                                                                      */
-/*      Force a rollback of the current transaction if there is one,    */
-/*      even if we are nested several levels deep.                      */
+/*      Do a rollback of the current transaction if we are at the 1st   */
+/*      level                                                           */
 /************************************************************************/
 
-OGRErr OGRSQLiteDataSource::SoftRollback()
+OGRErr OGRSQLiteBaseDataSource::SoftRollbackTransaction()
 
 {
+    //CPLDebug("SQLite", "%p->SoftRollbackTransaction() : %d",
+    //         this, nSoftTransactionLevel);
+
     if( nSoftTransactionLevel <= 0 )
     {
-        CPLDebug( "OGR_SQLITE", "SoftRollback() with no transaction active." );
+        CPLAssert(FALSE);
         return OGRERR_FAILURE;
     }
 
-    nSoftTransactionLevel = 0;
+    OGRErr eErr = OGRERR_NONE;
+    nSoftTransactionLevel--;
+    if( nSoftTransactionLevel == 0 )
+    {
+        eErr = DoTransactionCommand("ROLLBACK");
+    }
+
+    return eErr;
+}
+
+/************************************************************************/
+/*                          DoTransactionCommand()                      */
+/************************************************************************/
 
+OGRErr OGRSQLiteBaseDataSource::DoTransactionCommand(const char* pszCommand)
+
+{
     int rc;
     char *pszErrMsg;
-    
+
 #ifdef DEBUG
-    CPLDebug( "OGR_SQLITE", "ROLLBACK Transaction" );
+    CPLDebug( "OGR_SQLITE", "%s Transaction", pszCommand );
 #endif
 
-    rc = sqlite3_exec( hDB, "ROLLBACK", NULL, NULL, &pszErrMsg );
+    rc = sqlite3_exec( hDB, pszCommand, NULL, NULL, &pszErrMsg );
     if( rc != SQLITE_OK )
     {
+        nSoftTransactionLevel--;
         CPLError( CE_Failure, CPLE_AppDefined, 
-                  "ROLLBACK transaction failed: %s",
-                  pszErrMsg );
+                  "%s transaction failed: %s",
+                  pszCommand, pszErrMsg );
         sqlite3_free( pszErrMsg );
         return OGRERR_FAILURE;
     }
 
-    for(int i = 0; i < nLayers; i++)
-        papoLayers[i]->InvalidateCachedFeatureCountAndExtent();
-
     return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                        FlushSoftTransaction()                        */
-/*                                                                      */
-/*      Force the unwinding of any active transaction, and it's         */
-/*      commit.                                                         */
-/************************************************************************/
-
-OGRErr OGRSQLiteDataSource::FlushSoftTransaction()
-
-{
-    if( nSoftTransactionLevel <= 0 )
-        return OGRERR_NONE;
-
-    nSoftTransactionLevel = 1;
-
-    return SoftCommit();
-}
-
-/************************************************************************/
 /*                          GetSRTEXTColName()                        */
 /************************************************************************/
 
@@ -3205,15 +3229,15 @@ OGRSpatialReference *OGRSQLiteDataSource::FetchSRS( int nId )
 
 void OGRSQLiteDataSource::SetName(const char* pszNameIn)
 {
-    CPLFree(pszName);
-    pszName = CPLStrdup(pszNameIn);
+    CPLFree(m_pszFilename);
+    m_pszFilename = CPLStrdup(pszNameIn);
 }
 
 /************************************************************************/
 /*                       GetEnvelopeFromSQL()                           */
 /************************************************************************/
 
-const OGREnvelope* OGRSQLiteDataSource::GetEnvelopeFromSQL(const CPLString& osSQL)
+const OGREnvelope* OGRSQLiteBaseDataSource::GetEnvelopeFromSQL(const CPLString& osSQL)
 {
     std::map<CPLString, OGREnvelope>::iterator oIter = oMapSQLEnvelope.find(osSQL);
     if (oIter != oMapSQLEnvelope.end())
@@ -3226,7 +3250,7 @@ const OGREnvelope* OGRSQLiteDataSource::GetEnvelopeFromSQL(const CPLString& osSQ
 /*                         SetEnvelopeForSQL()                          */
 /************************************************************************/
 
-void OGRSQLiteDataSource::SetEnvelopeForSQL(const CPLString& osSQL,
+void OGRSQLiteBaseDataSource::SetEnvelopeForSQL(const CPLString& osSQL,
                                             const OGREnvelope& oEnvelope)
 {
     oMapSQLEnvelope[osSQL] = oEnvelope;
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitedriver.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitedriver.cpp
index bc14ee1..441271f 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitedriver.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitedriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitedriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqlitedriver.cpp 28612 2015-03-04 15:22:08Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteDriver class.
@@ -42,14 +42,13 @@
 #include "spatialite.h"
 #endif
 
-CPL_CVSID("$Id: ogrsqlitedriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsqlitedriver.cpp 28612 2015-03-04 15:22:08Z rouault $");
 
 /************************************************************************/
-/*                            ~OGRSQLiteDriver()                        */
+/*                          OGRSQLiteDriverUnload()                     */
 /************************************************************************/
 
-OGRSQLiteDriver::~OGRSQLiteDriver()
-
+static void OGRSQLiteDriverUnload(CPL_UNUSED GDALDriver* poDriver)
 {
 #ifdef SPATIALITE_412_OR_LATER
     spatialite_shutdown();
@@ -57,30 +56,47 @@ OGRSQLiteDriver::~OGRSQLiteDriver()
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                     OGRSQLiteDriverIdentify()                        */
 /************************************************************************/
 
-const char *OGRSQLiteDriver::GetName()
+static int OGRSQLiteDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-    return "SQLite";
+    int nLen = (int) strlen(poOpenInfo->pszFilename);
+    if (EQUALN(poOpenInfo->pszFilename, "VirtualShape:", strlen( "VirtualShape:" )) &&
+        nLen > 4 && EQUAL(poOpenInfo->pszFilename + nLen - 4, ".SHP"))
+    {
+        return TRUE;
+    }
+
+    if( EQUAL(poOpenInfo->pszFilename, ":memory:") )
+        return TRUE;
+/* -------------------------------------------------------------------- */
+/*      Verify that the target is a real file, and has an               */
+/*      appropriate magic string at the beginning.                      */
+/* -------------------------------------------------------------------- */
+    if( poOpenInfo->nHeaderBytes < 16 )
+        return FALSE;
+
+    return( strncmp( (const char*)poOpenInfo->pabyHeader, "SQLite format 3", 15 ) == 0 );
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRSQLiteDriver::Open( const char * pszFilename,
-                                     int bUpdate )
+static GDALDataset *OGRSQLiteDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( !OGRSQLiteDriverIdentify(poOpenInfo) )
+        return NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Check VirtualShape:xxx.shp syntax                               */
 /* -------------------------------------------------------------------- */
-    int nLen = (int) strlen(pszFilename);
-    if (EQUALN(pszFilename, "VirtualShape:", strlen( "VirtualShape:" )) &&
-        nLen > 4 && EQUAL(pszFilename + nLen - 4, ".SHP"))
+    int nLen = (int) strlen(poOpenInfo->pszFilename);
+    if (EQUALN(poOpenInfo->pszFilename, "VirtualShape:", strlen( "VirtualShape:" )) &&
+        nLen > 4 && EQUAL(poOpenInfo->pszFilename + nLen - 4, ".SHP"))
     {
         OGRSQLiteDataSource     *poDS;
 
@@ -88,7 +104,7 @@ OGRDataSource *OGRSQLiteDriver::Open( const char * pszFilename,
 
         char** papszOptions = CSLAddString(NULL, "SPATIALITE=YES");
         int nRet = poDS->Create( ":memory:", papszOptions );
-        poDS->SetName(pszFilename);
+        poDS->SetDescription(poOpenInfo->pszFilename);
         CSLDestroy(papszOptions);
         if (!nRet)
         {
@@ -96,65 +112,33 @@ OGRDataSource *OGRSQLiteDriver::Open( const char * pszFilename,
             return NULL;
         }
 
-        char* pszShapeFilename = CPLStrdup(pszFilename + strlen( "VirtualShape:" ));
-        OGRDataSource* poShapeDS = OGRSFDriverRegistrar::Open(pszShapeFilename);
-        if (poShapeDS == NULL)
+        char* pszSQLiteFilename = CPLStrdup(poOpenInfo->pszFilename + strlen( "VirtualShape:" ));
+        GDALDataset* poSQLiteDS = (GDALDataset*) GDALOpenEx(pszSQLiteFilename,
+                                            GDAL_OF_VECTOR, NULL, NULL, NULL);
+        if (poSQLiteDS == NULL)
         {
-            CPLFree(pszShapeFilename);
+            CPLFree(pszSQLiteFilename);
             delete poDS;
             return NULL;
         }
-        delete poShapeDS;
+        delete poSQLiteDS;
 
-        char* pszLastDot = strrchr(pszShapeFilename, '.');
+        char* pszLastDot = strrchr(pszSQLiteFilename, '.');
         if (pszLastDot)
             *pszLastDot = '\0';
 
-        const char* pszTableName = CPLGetBasename(pszShapeFilename);
+        const char* pszTableName = CPLGetBasename(pszSQLiteFilename);
 
         char* pszSQL = CPLStrdup(CPLSPrintf("CREATE VIRTUAL TABLE %s USING VirtualShape(%s, CP1252, -1)",
-                                            pszTableName, pszShapeFilename));
+                                            pszTableName, pszSQLiteFilename));
         poDS->ExecuteSQL(pszSQL, NULL, NULL);
         CPLFree(pszSQL);
-        CPLFree(pszShapeFilename);
+        CPLFree(pszSQLiteFilename);
+        poDS->SetUpdate(FALSE);
         return poDS;
     }
 
 /* -------------------------------------------------------------------- */
-/*      Verify that the target is a real file, and has an               */
-/*      appropriate magic string at the beginning.                      */
-/* -------------------------------------------------------------------- */
-    if( !EQUAL(pszFilename, ":memory:") )
-    {
-        char szHeader[16];
-
-#ifdef HAVE_SQLITE_VFS
-        VSILFILE *fpDB;
-        fpDB = VSIFOpenL( pszFilename, "rb" );
-        if( fpDB == NULL )
-            return NULL;
-        
-        if( VSIFReadL( szHeader, 1, 16, fpDB ) != 16 )
-            memset( szHeader, 0, 16 );
-        
-        VSIFCloseL( fpDB );
-#else
-        FILE *fpDB;
-        fpDB = VSIFOpen( pszFilename, "rb" );
-        if( fpDB == NULL )
-            return NULL;
-
-        if( VSIFRead( szHeader, 1, 16, fpDB ) != 16 )
-            memset( szHeader, 0, 16 );
-
-        VSIFClose( fpDB );
-#endif
-    
-        if( strncmp( szHeader, "SQLite format 3", 15 ) != 0 )
-            return NULL;
-    }
-
-/* -------------------------------------------------------------------- */
 /*      We think this is really an SQLite database, go ahead and try    */
 /*      and open it.                                                    */
 /* -------------------------------------------------------------------- */
@@ -162,7 +146,8 @@ OGRDataSource *OGRSQLiteDriver::Open( const char * pszFilename,
 
     poDS = new OGRSQLiteDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update,
+                     poOpenInfo->papszOpenOptions ) )
     {
         delete poDS;
         return NULL;
@@ -172,12 +157,15 @@ OGRDataSource *OGRSQLiteDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                          CreateDataSource()                          */
+/*                               Create()                               */
 /************************************************************************/
 
-OGRDataSource *OGRSQLiteDriver::CreateDataSource( const char * pszName,
-                                                  char **papszOptions )
-
+static GDALDataset *OGRSQLiteDriverCreate( const char * pszName,
+                                           CPL_UNUSED int nBands,
+                                           CPL_UNUSED int nXSize,
+                                           CPL_UNUSED int nYSize,
+                                           CPL_UNUSED GDALDataType eDT,
+                                           char **papszOptions )
 {
 /* -------------------------------------------------------------------- */
 /*      First, ensure there isn't any such file yet.                    */
@@ -210,30 +198,15 @@ OGRDataSource *OGRSQLiteDriver::CreateDataSource( const char * pszName,
 }
 
 /************************************************************************/
-/*                         DeleteDataSource()                           */
+/*                             Delete()                                 */
 /************************************************************************/
 
-OGRErr OGRSQLiteDriver::DeleteDataSource( const char *pszName )
+CPLErr OGRSQLiteDriverDelete( const char *pszName )
 {
     if (VSIUnlink( pszName ) == 0)
-        return OGRERR_NONE;
-    else
-        return OGRERR_FAILURE;
-}
-
-/************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRSQLiteDriver::TestCapability( const char * pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else if( EQUAL(pszCap,ODrCDeleteDataSource) )
-        return TRUE;
+        return CE_None;
     else
-        return FALSE;
+        return CE_Failure;
 }
 
 /************************************************************************/
@@ -245,6 +218,69 @@ void RegisterOGRSQLite()
 {
     if (! GDAL_CHECK_VERSION("SQLite driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSQLiteDriver );
-}
+    GDALDriver  *poDriver;
 
+    if( GDALGetDriverByName( "SQLite" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "SQLite" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "SQLite / Spatialite" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_sqlite.html" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "sqlite db" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='LIST_ALL_TABLES' type='boolean' description='Whether all tables, including non-spatial ones, should be listed' default='NO'/>"
+"  <Option name='LIST_VIRTUAL_OGR' type='boolean' description='Whether VirtualOGR virtual tables should be listed. Should only be enabled on trusted datasources to avoid potential safety issues' default='NO'/>"
+"</OpenOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
+"<CreationOptionList>"
+#ifdef HAVE_SPATIALITE
+"  <Option name='SPATIALITE' type='boolean' description='Whether to create a Spatialite database' default='NO'/>"
+#endif
+"  <Option name='METADATA' type='boolean' description='Whether to create the geometry_columns and spatial_ref_sys tables' default='YES'/>"
+"  <Option name='INIT_WITH_EPSG' type='boolean' description='Whether to insert the content of the EPSG CSV files into the spatial_ref_sys table ' default='NO'/>"
+"</CreationOptionList>");
+
+        poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
+"<LayerCreationOptionList>"
+"  <Option name='FORMAT' type='string-select' description='Format of geometry columns'>"
+"    <Value>WKB</Value>"
+"    <Value>WKT</Value>"
+#ifdef HAVE_SPATIALITE
+"    <Value>SPATIALITE</Value>"
+#endif
+"  </Option>"
+"  <Option name='GEOMETRY_NAME' type='string' description='Name of geometry column. Defaults to WKT_GEOMETRY for FORMAT=WKT or GEOMETRY otherwise'/>"
+"  <Option name='LAUNDER' type='boolean' description='Whether layer and field names will be laundered' default='YES'/>"
+#ifdef HAVE_SPATIALITE
+"  <Option name='SPATIAL_INDEX' type='boolean' description='Whether to create a spatial index for Spatialite databases' default='YES'/>"
+"  <Option name='COMPRESS_GEOM' type='boolean' description='Whether to use compressed format of Spatialite geometries' default='NO'/>"
+#endif
+"  <Option name='SRID' type='int' description='Forced SRID of the layer'/>"
+"  <Option name='COMPRESS_COLUMNS' type='string' description='=column_name1[,column_name2, ...].  list of (String) columns that must be compressed with ZLib DEFLATE algorithm'/>"
+"  <Option name='OVERWRITE' type='boolean' description='Whether to overwrite an existing table with the layer name to be created' default='NO'/>"
+"  <Option name='FID' type='string' description='Name of the FID column to create' default='OGC_FID'/>"
+"</LayerCreationOptionList>");
+        
+        poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time Binary" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_DEFAULT_FIELDS, "YES" );
+        poDriver->SetMetadataItem( GDAL_DCAP_NOTNULL_GEOMFIELDS, "YES" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSQLiteDriverOpen;
+        poDriver->pfnIdentify = OGRSQLiteDriverIdentify;
+        poDriver->pfnCreate = OGRSQLiteDriverCreate;
+        poDriver->pfnDelete = OGRSQLiteDriverDelete;
+        poDriver->pfnUnloadDriver = OGRSQLiteDriverUnload;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp
index 7333a45..2f001e1 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqliteexecutesql.cpp 27730 2014-09-24 00:59:45Z goatbar $
+ * $Id: ogrsqliteexecutesql.cpp 28612 2015-03-04 15:22:08Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Run SQL requests with SQLite SQL engine
@@ -467,7 +467,6 @@ static void OGR2SQLITEGetPotentialLayerNames(const char *pszSQLCommand,
 /*               OGR2SQLITE_IgnoreAllFieldsExceptGeometry()             */
 /************************************************************************/
 
-#if defined(HAVE_SPATIALITE)
 static
 void OGR2SQLITE_IgnoreAllFieldsExceptGeometry(OGRLayer* poLayer)
 {
@@ -482,7 +481,6 @@ void OGR2SQLITE_IgnoreAllFieldsExceptGeometry(OGRLayer* poLayer)
     poLayer->SetIgnoredFields((const char**)papszIgnored);
     CSLDestroy(papszIgnored);
 }
-#endif  // HAVE_SPATIALITE
 
 
 /************************************************************************/
@@ -496,13 +494,7 @@ int OGR2SQLITEDealWithSpatialColumn(OGRLayer* poLayer,
                                     OGRSQLiteDataSource* poSQLiteDS,
                                     sqlite3* hDB,
                                     int bSpatialiteDB,
-#ifndef HAVE_SPATIALITE
-CPL_UNUSED
-#endif
                                     const std::set<LayerDesc>& oSetLayers,
-#ifndef HAVE_SPATIALITE
-CPL_UNUSED
-#endif
                                     const std::set<CPLString>& oSetSpatialIndex
                                    )
 {
@@ -536,9 +528,7 @@ CPL_UNUSED
         nSRSId = poSQLiteDS->FetchSRSId(poSRS);
 
     CPLString osSQL;
-#ifdef HAVE_SPATIALITE
     int bCreateSpatialIndex = FALSE;
-#endif
     if( !bSpatialiteDB )
     {
         osSQL.Printf("INSERT INTO geometry_columns (f_table_name, "
@@ -548,7 +538,7 @@ CPL_UNUSED
                     pszLayerNameEscaped,
                     pszGeomColEscaped,
                         (int) wkbFlatten(poLayer->GetGeomType()),
-                    ( poLayer->GetGeomType() & wkb25DBit ) ? 3 : 2,
+                    wkbHasZ( poLayer->GetGeomType() ) ? 3 : 2,
                     nSRSId);
     }
 #ifdef HAVE_SPATIALITE
@@ -590,7 +580,7 @@ CPL_UNUSED
         {
             int nGeomType = poLayer->GetGeomType();
             int nCoordDimension = 2;
-            if( nGeomType & wkb25DBit )
+            if( wkbHasZ((OGRwkbGeometryType)nGeomType) )
             {
                 nGeomType += 1000;
                 nCoordDimension = 3;
@@ -617,7 +607,7 @@ CPL_UNUSED
                         "VALUES ('%s','%s','%s','%s',%d, %d)",
                         pszLayerNameEscaped,
                         pszGeomColEscaped, pszGeometryType,
-                        ( poLayer->GetGeomType() & wkb25DBit ) ? "XYZ" : "XY",
+                        wkbHasZ( poLayer->GetGeomType() ) ? "XYZ" : "XY",
                         nSRSId, bCreateSpatialIndex );
         }
     }
@@ -716,7 +706,7 @@ CPL_UNUSED
 /*                          OGRSQLiteExecuteSQL()                       */
 /************************************************************************/
 
-OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
+OGRLayer * OGRSQLiteExecuteSQL( GDALDataset* poDS,
                                 const char *pszStatement,
                                 OGRGeometry *poSpatialFilter,
                                 CPL_UNUSED const char *pszDialect )
@@ -751,7 +741,7 @@ OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
     static vsi_l_offset nEmptyDBSize = 0;
     static GByte* pabyEmptyDB = NULL;
     {
-        static void* hMutex = NULL;
+        static CPLMutex* hMutex = NULL;
         CPLMutexHolder oMutexHolder(&hMutex);
         static int bTried = FALSE;
         if( !bTried &&
@@ -774,7 +764,7 @@ OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
         }
     }
 
-    /* The following configuration option is usefull mostly for debugging/testing */
+    /* The following configuration option is useful mostly for debugging/testing */
     if( pabyEmptyDB != NULL && CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_DIALECT_USE_SPATIALITE", "YES")) )
     {
         GByte* pabyEmptyDBClone = (GByte*)VSIMalloc(nEmptyDBSize);
@@ -788,7 +778,7 @@ OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
 
         poSQLiteDS = new OGRSQLiteDataSource();
         CPLSetThreadLocalConfigOption("OGR_SQLITE_STATIC_VIRTUAL_OGR", "NO");
-        nRet = poSQLiteDS->Open( pszTmpDBName, TRUE );
+        nRet = poSQLiteDS->Open( pszTmpDBName, TRUE, NULL );
         CPLSetThreadLocalConfigOption("OGR_SQLITE_STATIC_VIRTUAL_OGR", pszOldVal);
         if( !nRet )
         {
@@ -1062,7 +1052,7 @@ std::set<LayerDesc> OGRSQLiteGetReferencedLayers(const char* pszStatement)
 OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
                                 const char *pszStatement,
                                 OGRGeometry *poSpatialFilter,
-                                CPL_UNUSED const char *pszDialect )
+                                const char *pszDialect )
 {
     CPLError(CE_Failure, CPLE_NotSupported,
                 "The SQLite version is to old to support the SQLite SQL dialect");
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.h b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.h
index 45f5a29..fa34bc8 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.h
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteexecutesql.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqliteexecutesql.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqliteexecutesql.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Run SQL requests with SQLite SQL engine
@@ -34,7 +34,7 @@
 #include "ogrsf_frmts.h"
 #include <set>
 
-OGRLayer * OGRSQLiteExecuteSQL( OGRDataSource* poDS,
+OGRLayer * OGRSQLiteExecuteSQL( GDALDataset* poDS,
                                 const char *pszStatement,
                                 OGRGeometry *poSpatialFilter,
                                 const char *pszDialect );
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitelayer.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitelayer.cpp
index c6db77f..4eb5f85 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitelayer.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitelayer.cpp 28178 2014-12-19 21:14:05Z rouault $
+ * $Id: ogrsqlitelayer.cpp 29080 2015-04-30 15:30:33Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteLayer class, code shared between 
@@ -42,7 +42,7 @@
 #include "ogr_sqlite.h"
 #include <cassert>
 
-CPL_CVSID("$Id: ogrsqlitelayer.cpp 28178 2014-12-19 21:14:05Z rouault $");
+CPL_CVSID("$Id: ogrsqlitelayer.cpp 29080 2015-04-30 15:30:33Z rouault $");
 
 /************************************************************************/
 /*                           OGRSQLiteLayer()                           */
@@ -58,14 +58,12 @@ OGRSQLiteLayer::OGRSQLiteLayer()
     hStmt = NULL;
     bDoStep = TRUE;
 
+    poFeatureDefn = NULL;
     iNextShapeId = 0;
 
     panFieldOrdinals = NULL;
     iFIDCol = -1;
 
-    bHasSpatialIndex = FALSE;
-    bHasM = FALSE;
-
     bIsVirtualShape = FALSE;
 
     bUseComprGeom = CSLTestBoolean(CPLGetConfigOption("COMPRESS_GEOM", "FALSE"));
@@ -128,7 +126,8 @@ void OGRSQLiteLayer::Finalize()
 /************************************************************************/
 
 static
-int OGRIsBinaryGeomCol( sqlite3_stmt *hStmt, int iCol,
+int OGRIsBinaryGeomCol( sqlite3_stmt *hStmt,
+                        int iCol,
                         CPL_UNUSED OGRFieldDefn& oField,
                         OGRSQLiteGeomFormat& eGeomFormat )
 {
@@ -174,8 +173,8 @@ int OGRIsBinaryGeomCol( sqlite3_stmt *hStmt, int iCol,
 
 void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
                                        sqlite3_stmt *hStmt,
-                                       const char* pszExpectedGeomCol,
-                                       const std::set<CPLString>& aosGeomCols )
+                                       const std::set<CPLString>& aosGeomCols,
+                                       const std::set<CPLString>& aosIgnoredCols )
 
 {
     poFeatureDefn = new OGRSQLiteFeatureDefn( pszLayerName );
@@ -211,32 +210,99 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
 
         //oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
 
-        if( pszExpectedGeomCol != NULL
-            && EQUAL(oField.GetNameRef(),pszExpectedGeomCol) )
+        if( aosIgnoredCols.find( CPLString(oField.GetNameRef()).tolower() ) != aosIgnoredCols.end() )
+        {
+            continue;
+        }
+        if( aosGeomCols.find( CPLString(oField.GetNameRef()).tolower() ) != aosGeomCols.end() )
         {
             OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
                 new OGRSQLiteGeomFieldDefn(oField.GetNameRef(), iCol);
             poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
             continue;
         }
-        if( aosGeomCols.find( oField.GetNameRef() ) != aosGeomCols.end() )
-            continue;
 
         int nColType = sqlite3_column_type( hStmt, iCol );
+        switch( nColType )
+        {
+          case SQLITE_INTEGER:
+            if( CSLTestBoolean(CPLGetConfigOption("OGR_PROMOTE_TO_INTEGER64", "FALSE")) )
+                oField.SetType( OFTInteger64 );
+            else
+            {
+                GIntBig nVal = sqlite3_column_int64(hStmt, iCol);
+                if( (GIntBig)(int)nVal == nVal )
+                    oField.SetType( OFTInteger );
+                else
+                    oField.SetType( OFTInteger64 );
+            }
+            break;
+
+          case SQLITE_FLOAT:
+            oField.SetType( OFTReal );
+            break;
+
+          case SQLITE_BLOB:
+            oField.SetType( OFTBinary );
+            break;
+
+          default:
+            /* leave it as OFTString */;
+        }
+        
         const char * pszDeclType = sqlite3_column_decltype(hStmt, iCol);
         //CPLDebug("SQLITE", "decltype(%s) = %s",
         //         oField.GetNameRef(), pszDeclType ? pszDeclType : "null");
         OGRFieldType eFieldType = OFTString;
         if (pszDeclType != NULL)
         {
-            if (EQUAL(pszDeclType, "INTEGER"))
-                nColType = SQLITE_INTEGER;
+            if (EQUAL(pszDeclType, "INTEGER_BOOLEAN"))
+            {
+                oField.SetType(OFTInteger);
+                oField.SetSubType(OFSTBoolean);
+            }
+            else if (EQUAL(pszDeclType, "INTEGER_INT16"))
+            {
+                oField.SetType(OFTInteger);
+                oField.SetSubType(OFSTInt16);
+            }
+            else if (EQUAL(pszDeclType, "INTEGERLIST"))
+            {
+                oField.SetType(OFTIntegerList);
+            }
+            else if (EQUAL(pszDeclType, "INTEGER64LIST"))
+            {
+                oField.SetType(OFTInteger64List);
+            }
+            else if (EQUAL(pszDeclType, "REALLIST"))
+            {
+                oField.SetType(OFTRealList);
+            }
+            else if (EQUAL(pszDeclType, "STRINGLIST"))
+            {
+                oField.SetType(OFTStringList);
+            }
+            else if (EQUAL(pszDeclType, "BIGINT") || EQUAL(pszDeclType, "INT8"))
+            {
+                oField.SetType(OFTInteger64);
+            }
+            else if (EQUALN(pszDeclType, "INTEGER", strlen("INTEGER")))
+            {
+                oField.SetType(OFTInteger);
+            }
+            else if (EQUAL(pszDeclType, "FLOAT_FLOAT32"))
+            {
+                oField.SetType(OFTReal);
+                oField.SetSubType(OFSTFloat32);
+            }
             else if (EQUAL(pszDeclType, "FLOAT") ||
                      EQUAL(pszDeclType, "DECIMAL"))
-                nColType = SQLITE_FLOAT;
+            {
+                oField.SetType(OFTReal);
+            }
             else if (EQUALN(pszDeclType, "BLOB", 4))
             {
-                nColType = SQLITE_BLOB;
+                oField.SetType( OFTBinary );
                 /* Parse format like BLOB_POINT_25D_4326 created by */
                 /* OGRSQLiteExecuteSQL() */
                 if( pszDeclType[4] == '_' )
@@ -262,8 +328,7 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
                         OGRwkbGeometryType eGeomType =
                             OGRFromOGCGeomType(pszGeomType);
                         if( EQUAL(pszCoordDimension, "25D") )
-                            eGeomType = (OGRwkbGeometryType)
-                                (eGeomType | wkb25DBit);
+                            eGeomType = wkbSetZ(eGeomType);
                         OGRSpatialReference* poSRS = poDS->FetchSRS(nSRID);
                         OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
                             new OGRSQLiteGeomFieldDefn(oField.GetNameRef(), iCol);
@@ -280,7 +345,7 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
             else if (EQUAL(pszDeclType, "TEXT") ||
                      EQUALN(pszDeclType, "VARCHAR", 7))
             {
-                nColType = SQLITE_TEXT;
+                oField.SetType( OFTString );
                 if( strstr(pszDeclType, "_deflate") != NULL )
                 {
                     if( CSLFindString(papszCompressedColumns,
@@ -294,13 +359,13 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
             }
             else if ((EQUAL(pszDeclType, "TIMESTAMP") ||
                       EQUAL(pszDeclType, "DATETIME")) &&
-                     (nColType == SQLITE_TEXT || nColType == SQLITE_NULL))
+                     (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT || nColType == SQLITE_NULL))
                 eFieldType = OFTDateTime;
             else if (EQUAL(pszDeclType, "DATE") &&
-                     (nColType == SQLITE_TEXT || nColType == SQLITE_NULL))
+                     (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT || nColType == SQLITE_NULL))
                 eFieldType = OFTDate;
             else if (EQUAL(pszDeclType, "TIME") &&
-                     (nColType == SQLITE_TEXT || nColType == SQLITE_NULL))
+                     (nColType == SQLITE_TEXT || nColType == SQLITE_FLOAT || nColType == SQLITE_NULL))
                 eFieldType = OFTTime;
         }
         else if( nColType == SQLITE_TEXT &&
@@ -395,7 +460,7 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
         }
 
         // Recognize a geometry column from trying to build the geometry
-        // Usefull for OGRSQLiteSelectLayer
+        // Useful for OGRSQLiteSelectLayer
         if( nColType == SQLITE_BLOB && 
             (bAllowMultipleGeomFields || poFeatureDefn->GetGeomFieldCount() == 0) )
         {
@@ -420,24 +485,6 @@ void OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
         if( EQUAL(oField.GetNameRef(),"OGC_FID") )
             continue;
 
-        switch( nColType )
-        {
-          case SQLITE_INTEGER:
-            oField.SetType( OFTInteger );
-            break;
-
-          case SQLITE_FLOAT:
-            oField.SetType( OFTReal );
-            break;
-
-          case SQLITE_BLOB:
-            oField.SetType( OFTBinary );
-            break;
-
-          default:
-            /* leave it as OFTString */;
-        }
-        
         /* config option just in case we wouldn't want that in some cases */
         if( (eFieldType == OFTTime || eFieldType == OFTDate ||
              eFieldType == OFTDateTime) &&
@@ -662,21 +709,36 @@ OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
 
         int iRawField = panFieldOrdinals[iField];
 
-        if( sqlite3_column_type( hStmt, iRawField ) == SQLITE_NULL )
+        int nSQLite3Type = sqlite3_column_type( hStmt, iRawField );
+        if( nSQLite3Type == SQLITE_NULL )
             continue;
 
         switch( poFieldDefn->GetType() )
         {
         case OFTInteger:
-            //FIXME use int64 when OGR has 64bit integer support
-            poFeature->SetField( iField, 
-                sqlite3_column_int( hStmt, iRawField ) );
+        case OFTInteger64:
+        {
+            /* Possible since SQLite3 has no strong typing */
+            if( nSQLite3Type == SQLITE_TEXT )
+                poFeature->SetField( iField, 
+                        (const char *)sqlite3_column_text( hStmt, iRawField ) );
+            else
+                poFeature->SetField( iField, 
+                    sqlite3_column_int64( hStmt, iRawField ) );
             break;
+        }
 
         case OFTReal:
-            poFeature->SetField( iField, 
-                sqlite3_column_double( hStmt, iRawField ) );
+        {
+            /* Possible since SQLite3 has no strong typing */
+            if( nSQLite3Type == SQLITE_TEXT )
+                poFeature->SetField( iField, 
+                        (const char *)sqlite3_column_text( hStmt, iRawField ) );
+            else
+                poFeature->SetField( iField, 
+                    sqlite3_column_double( hStmt, iRawField ) );
             break;
+        }
 
         case OFTBinary:
             {
@@ -688,6 +750,10 @@ OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
             break;
 
         case OFTString:
+        case OFTIntegerList:
+        case OFTInteger64List:
+        case OFTRealList:
+        case OFTStringList:
         {
             if( CSLFindString(papszCompressedColumns,
                               poFeatureDefn->GetFieldDefn(iField)->GetNameRef()) >= 0 )
@@ -727,6 +793,20 @@ OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
                     sqlite3_column_text( hStmt, iRawField );
                 OGRSQLITEStringToDateTimeField( poFeature, iField, pszValue );
             }
+            else if( sqlite3_column_type( hStmt, iRawField ) == SQLITE_FLOAT )
+            {
+                // Try converting from Julian day
+                char** papszResult = NULL;
+                sqlite3_get_table( poDS->GetDB(),
+                                   CPLSPrintf("SELECT strftime('%%Y-%%m-%%d %%H:%%M:%%S', %.16g)",
+                                               sqlite3_column_double(hStmt, iRawField)),
+                                   &papszResult, NULL, NULL, NULL );
+                if( papszResult && papszResult[0] && papszResult[1] )
+                {
+                    OGRSQLITEStringToDateTimeField( poFeature, iField,  papszResult[1] );
+                }
+                sqlite3_free_table(papszResult);
+            }
             break;
         }
 
@@ -742,7 +822,7 @@ OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRSQLiteLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRSQLiteLayer::GetFeature( GIntBig nFeatureId )
 
 {
     return OGRLayer::GetFeature( nFeatureId );
@@ -2362,8 +2442,29 @@ OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry( const GByte *pabyData,
         *pnSRID = nSRID;
     }
 
-    return createFromSpatialiteInternal(pabyData + 39, ppoGeometry,
-                                        nBytes - 39, eByteOrder, NULL, 0);
+    int nBytesConsumed = 0;
+    OGRErr eErr = createFromSpatialiteInternal(pabyData + 39, ppoGeometry,
+                                        nBytes - 39, eByteOrder, &nBytesConsumed, 0);
+    if( eErr == OGRERR_NONE )
+    {
+        /* This is a hack: in OGR2SQLITE_ExportGeometry(), we may have added */
+        /* the original curve geometry after the spatialite blob, so in case */
+        /* we detect that there's still binary */
+        /* content after the spatialite blob, this may be our original geometry */
+        if( pabyData[39 + nBytesConsumed] == 0xFE && 39 + nBytesConsumed + 1 < nBytes )
+        {
+            OGRGeometry* poOriginalGeometry = NULL;
+            eErr = OGRGeometryFactory::createFromWkb(
+                    (unsigned char*)(pabyData + 39 + nBytesConsumed + 1),
+                    NULL, &poOriginalGeometry, nBytes - (39 + nBytesConsumed + 1 + 1));
+            if( eErr == OGRERR_NONE )
+            {
+                delete *ppoGeometry;
+                *ppoGeometry = poOriginalGeometry;
+            }
+        }
+    }
+    return eErr;
 }
 
 /************************************************************************/
@@ -2918,10 +3019,16 @@ OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry( const OGRGeometry *poGeometry,
                                                  int *pnDataLenght )
 
 {
+    /* Spatialite does not support curve geometries */
+    const OGRGeometry* poWorkGeom;
+    if( poGeometry->hasCurveGeometry() )
+        poWorkGeom = poGeometry->getLinearGeometry();
+    else
+        poWorkGeom = poGeometry;
+    
+    bUseComprGeom = bUseComprGeom && !bSpatialite2D && CanBeCompressedSpatialiteGeometry(poWorkGeom);
 
-    bUseComprGeom = bUseComprGeom && !bSpatialite2D && CanBeCompressedSpatialiteGeometry(poGeometry);
-
-    int     nDataLen = 44 + ComputeSpatiaLiteGeometrySize( poGeometry,
+    int     nDataLen = 44 + ComputeSpatiaLiteGeometrySize( poWorkGeom,
                                                            bHasM, 
                                                            bSpatialite2D,
                                                            bUseComprGeom );
@@ -2944,7 +3051,7 @@ OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry( const OGRGeometry *poGeometry,
 
     (*ppabyData)[38] = 0x7C;
 
-    int nCode = GetSpatialiteGeometryCode(poGeometry,
+    int nCode = GetSpatialiteGeometryCode(poWorkGeom,
                                           bHasM, bSpatialite2D,
                                           bUseComprGeom, TRUE);
     if (nCode == 0)
@@ -2952,15 +3059,18 @@ OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry( const OGRGeometry *poGeometry,
         CPLFree(*ppabyData);
         *ppabyData = NULL;
         *pnDataLenght = 0;
+        if( poWorkGeom != poGeometry ) delete poWorkGeom;
         return CE_Failure;
     }
     memcpy( *ppabyData + 39, &nCode, 4 );
 
-    int nWritten = ExportSpatiaLiteGeometryInternal(poGeometry, 
+    int nWritten = ExportSpatiaLiteGeometryInternal(poWorkGeom, 
                                                     eByteOrder, 
                                                     bHasM, bSpatialite2D,
                                                     bUseComprGeom,
                                                     *ppabyData + 43);
+    if( poWorkGeom != poGeometry ) delete poWorkGeom;
+
     if (nWritten == 0)
     {
         CPLFree(*ppabyData);
@@ -3019,7 +3129,7 @@ int OGRSQLiteLayer::TestCapability( const char * pszCap )
 OGRErr OGRSQLiteLayer::StartTransaction()
 
 {
-    return poDS->SoftStartTransaction();
+    return poDS->StartTransaction();
 }
 
 /************************************************************************/
@@ -3029,7 +3139,7 @@ OGRErr OGRSQLiteLayer::StartTransaction()
 OGRErr OGRSQLiteLayer::CommitTransaction()
 
 {
-    return poDS->SoftCommit();
+    return poDS->CommitTransaction();
 }
 
 /************************************************************************/
@@ -3039,7 +3149,7 @@ OGRErr OGRSQLiteLayer::CommitTransaction()
 OGRErr OGRSQLiteLayer::RollbackTransaction()
 
 {
-    return poDS->SoftRollback();
+    return poDS->RollbackTransaction();
 }
 
 /************************************************************************/
@@ -3072,11 +3182,13 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     nYear = 0; nMonth = 0; nDay = 0; nHour = 0;
     nMinute = 0; fSecond = 0;
     if( sscanf(pszValue, "%04d-%02d-%02d %02d:%02d:%f",
+                &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond) == 6 ||
+        sscanf(pszValue, "%04d/%02d/%02d %02d:%02d:%f",
                 &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond) == 6 )
     {
         if( poFeature )
             poFeature->SetField( iField, nYear, nMonth,
-                                nDay, nHour, nMinute, (int)(fSecond + 0.5), 0 );
+                                 nDay, nHour, nMinute, fSecond, 0);
         return OFTDateTime;
     }
 
@@ -3084,11 +3196,13 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     nYear = 0; nMonth = 0; nDay = 0; nHour = 0;
     nMinute = 0;
     if( sscanf(pszValue, "%04d-%02d-%02d %02d:%02d",
+                &nYear, &nMonth, &nDay, &nHour, &nMinute) == 5 ||
+        sscanf(pszValue, "%04d/%02d/%02d %02d:%02d",
                 &nYear, &nMonth, &nDay, &nHour, &nMinute) == 5 )
     {
         if( poFeature )
             poFeature->SetField( iField, nYear, nMonth,
-                                nDay, nHour, nMinute, 0, 0 );
+                                 nDay, nHour, nMinute, 0, 0);
         return OFTDateTime;
     }
 
@@ -3100,7 +3214,7 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     {
         if( poFeature )
             poFeature->SetField( iField, nYear, nMonth, nDay,
-                                nHour, nMinute, (int)(fSecond + 0.5), 0 );
+                                 nHour, nMinute, fSecond, 0);
         return OFTDateTime;
     }
 
@@ -3112,18 +3226,20 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     {
         if( poFeature )
             poFeature->SetField( iField, nYear, nMonth, nDay,
-                                nHour, nMinute, 0, 0 );
+                                 nHour, nMinute, 0, 0);
         return OFTDateTime;
     }
 
     /* YYYY-MM-DD */
     nYear = 0; nMonth = 0; nDay = 0;
     if( sscanf(pszValue, "%04d-%02d-%02d",
+                &nYear, &nMonth, &nDay) == 3 ||
+        sscanf(pszValue, "%04d/%02d/%02d",
                 &nYear, &nMonth, &nDay) == 3 )
     {
         if( poFeature )
             poFeature->SetField( iField, nYear, nMonth, nDay,
-                                0, 0, 0, 0 );
+                                 0, 0, 0, 0 );
         return OFTDate;
     }
 
@@ -3134,7 +3250,7 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     {
         if( poFeature )
             poFeature->SetField( iField, 0, 0, 0,
-                                nHour, nMinute, (int)(fSecond + 0.5), 0 );
+                                 nHour, nMinute, fSecond, 0 );
         return OFTTime;
     }
 
@@ -3144,9 +3260,73 @@ int OGRSQLITEStringToDateTimeField( OGRFeature* poFeature, int iField,
     {
         if( poFeature )
             poFeature->SetField( iField, 0, 0, 0,
-                                nHour, nMinute, 0, 0 );
+                                 nHour, nMinute, 0, 0 );
         return OFTTime;
     }
 
     return FALSE;
 }
+
+/************************************************************************/
+/*                     FormatSpatialFilterFromRTree()                   */
+/************************************************************************/
+
+CPLString OGRSQLiteLayer::FormatSpatialFilterFromRTree(OGRGeometry* poFilterGeom,
+                                                       const char* pszRowIDName,
+                                                       const char* pszEscapedTable,
+                                                       const char* pszEscapedGeomCol)
+{
+    CPLString osSpatialWHERE;
+    OGREnvelope  sEnvelope;
+
+    poFilterGeom->getEnvelope( &sEnvelope );
+
+    if( CPLIsInf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
+        CPLIsInf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
+        CPLIsInf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
+        CPLIsInf(sEnvelope.MaxY) && sEnvelope.MaxY > 0 )
+        return "";
+
+    osSpatialWHERE.Printf("%s IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
+                    "xmax >= %s AND xmin <= %s AND ymax >= %s AND ymin <= %s)",
+                    pszRowIDName,
+                    pszEscapedTable,
+                    pszEscapedGeomCol,
+                    // Insure that only Decimal.Points are used, never local settings such as Decimal.Comma.
+                    CPLString().FormatC(sEnvelope.MinX - 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MaxX + 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MinY - 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MaxY + 1e-11,"%.12f").c_str());
+
+    return osSpatialWHERE;
+}
+
+/************************************************************************/
+/*                     FormatSpatialFilterFromMBR()                     */
+/************************************************************************/
+
+CPLString OGRSQLiteLayer::FormatSpatialFilterFromMBR(OGRGeometry* poFilterGeom,
+                                                     const char* pszEscapedGeomColName)
+{
+    CPLString osSpatialWHERE;
+    OGREnvelope  sEnvelope;
+
+    poFilterGeom->getEnvelope( &sEnvelope );
+
+    if( CPLIsInf(sEnvelope.MinX) && sEnvelope.MinX < 0 &&
+        CPLIsInf(sEnvelope.MinY) && sEnvelope.MinY < 0 &&
+        CPLIsInf(sEnvelope.MaxX) && sEnvelope.MaxX > 0 &&
+        CPLIsInf(sEnvelope.MaxY) && sEnvelope.MaxY > 0 )
+        return "";
+
+    /* A bit inefficient but still faster than OGR filtering */
+    osSpatialWHERE.Printf("MBRIntersects(\"%s\", BuildMBR(%s, %s, %s, %s))",
+                    pszEscapedGeomColName,
+                    // Insure that only Decimal.Points are used, never local settings such as Decimal.Comma.
+                    CPLString().FormatC(sEnvelope.MinX - 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MinY - 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MaxX + 1e-11,"%.12f").c_str(),
+                    CPLString().FormatC(sEnvelope.MaxY + 1e-11,"%.12f").c_str());
+
+    return osSpatialWHERE;
+}
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp
index 81f5d81..19a9366 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteregexp.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqliteregexp.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrsqliteregexp.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  SQLite REGEXP function
@@ -167,11 +167,7 @@ void OGRSQLiteREGEXPFunction(sqlite3_context *ctx, CPL_UNUSED int argc, sqlite3_
 /************************************************************************/
 
 static
-void* OGRSQLiteRegisterRegExpFunction(
-#ifndef HAVE_PCRE
-CPL_UNUSED
-#endif
-                                      sqlite3* hDB)
+void* OGRSQLiteRegisterRegExpFunction(sqlite3* hDB)
 {
 #ifdef HAVE_PCRE
 
@@ -205,11 +201,7 @@ CPL_UNUSED
 /************************************************************************/
 
 static
-void OGRSQLiteFreeRegExpCache(
-#ifndef HAVE_PCRE
-CPL_UNUSED
-#endif
-                              void* hRegExpCache)
+void OGRSQLiteFreeRegExpCache(void* hRegExpCache)
 {
 #ifdef HAVE_PCRE
     if( hRegExpCache == NULL )
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp
index 5a8d36a..ca64c55 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteselectlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqliteselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqliteselectlayer.cpp 28928 2015-04-17 10:24:19Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteSelectLayer class, layer access to the results
@@ -34,7 +34,23 @@
 #include "swq.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrsqliteselectlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsqliteselectlayer.cpp 28928 2015-04-17 10:24:19Z rouault $");
+
+/************************************************************************/
+/*                   OGRSQLiteSelectLayerCommonBehaviour()              */
+/************************************************************************/
+
+OGRSQLiteSelectLayerCommonBehaviour::OGRSQLiteSelectLayerCommonBehaviour(OGRSQLiteBaseDataSource* poDS,
+                                            IOGRSQLiteSelectLayer* poLayer,
+                                            CPLString osSQL,
+                                            int bEmptyLayer) :
+            poDS(poDS), poLayer(poLayer), osSQLBase(osSQL),
+            bEmptyLayer(bEmptyLayer), osSQLCurrent(osSQL)
+{
+    bAllowResetReadingEvenIfIndexAtZero = FALSE;
+    bSpatialFilterInSQL = TRUE;
+}
+
 /************************************************************************/
 /*                        OGRSQLiteSelectLayer()                        */
 /************************************************************************/
@@ -47,15 +63,14 @@ OGRSQLiteSelectLayer::OGRSQLiteSelectLayer( OGRSQLiteDataSource *poDSIn,
                                             int bAllowMultipleGeomFields )
 
 {
+    poBehaviour = new OGRSQLiteSelectLayerCommonBehaviour(poDSIn, this, osSQLIn, bEmptyLayer);
     poDS = poDSIn;
 
-    iNextShapeId = 0;
-    poFeatureDefn = NULL;
-    bAllowResetReadingEvenIfIndexAtZero = FALSE;
     this->bAllowMultipleGeomFields = bAllowMultipleGeomFields;
 
     std::set<CPLString> aosEmpty;
-    BuildFeatureDefn( "SELECT", hStmtIn, NULL, aosEmpty );
+    BuildFeatureDefn( "SELECT", hStmtIn, aosEmpty, aosEmpty );
+    SetDescription( "SELECT" );
 
     if( bUseStatementForGetNextFeature )
     {
@@ -125,11 +140,15 @@ OGRSQLiteSelectLayer::OGRSQLiteSelectLayer( OGRSQLiteDataSource *poDSIn,
     }
     else
         sqlite3_finalize( hStmtIn );
+}
 
-    osSQLBase = osSQLIn;
-    osSQLCurrent = osSQLIn;
-    this->bEmptyLayer = bEmptyLayer;
-    bSpatialFilterInSQL = TRUE;
+/************************************************************************/
+/*                       ~OGRSQLiteSelectLayer()                        */
+/************************************************************************/
+
+OGRSQLiteSelectLayer::~OGRSQLiteSelectLayer()
+{
+    delete poBehaviour;
 }
 
 /************************************************************************/
@@ -137,11 +156,15 @@ OGRSQLiteSelectLayer::OGRSQLiteSelectLayer( OGRSQLiteDataSource *poDSIn,
 /************************************************************************/
 
 void OGRSQLiteSelectLayer::ResetReading()
+{
+    return poBehaviour->ResetReading();
+}
 
+void OGRSQLiteSelectLayerCommonBehaviour::ResetReading()
 {
-    if( iNextShapeId > 0 || bAllowResetReadingEvenIfIndexAtZero )
+    if( poLayer->HasReadFeature() || bAllowResetReadingEvenIfIndexAtZero )
     {
-        OGRSQLiteLayer::ResetReading();
+        poLayer->BaseResetReading();
         bAllowResetReadingEvenIfIndexAtZero = FALSE;
     }
 }
@@ -152,10 +175,15 @@ void OGRSQLiteSelectLayer::ResetReading()
 
 OGRFeature *OGRSQLiteSelectLayer::GetNextFeature()
 {
+    return poBehaviour->GetNextFeature();
+}
+
+OGRFeature *OGRSQLiteSelectLayerCommonBehaviour::GetNextFeature()
+{
     if( bEmptyLayer )
         return NULL;
 
-    return OGRSQLiteLayer::GetNextFeature();
+    return poLayer->BaseGetNextFeature();
 }
 
 /************************************************************************/
@@ -189,13 +217,19 @@ int HasSpecialFields(swq_expr_node* expr, int nMinIndexForSpecialField)
 /************************************************************************/
 
 OGRErr OGRSQLiteSelectLayer::SetAttributeFilter( const char *pszQuery )
+{
+    return poBehaviour->SetAttributeFilter(pszQuery);
+}
+
+OGRErr OGRSQLiteSelectLayerCommonBehaviour::SetAttributeFilter( const char *pszQuery )
 
 {
-    if( m_pszAttrQueryString == NULL && pszQuery == NULL )
+    char*& m_pszAttrQuertyString = poLayer->GetAttrQueryString();
+    if( m_pszAttrQuertyString == NULL && pszQuery == NULL )
         return OGRERR_NONE;
 
-    CPLFree(m_pszAttrQueryString);
-    m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : NULL;
+    CPLFree(m_pszAttrQuertyString);
+    m_pszAttrQuertyString = (pszQuery) ? CPLStrdup(pszQuery) : NULL;
 
     bAllowResetReadingEvenIfIndexAtZero = TRUE;
 
@@ -203,13 +237,13 @@ OGRErr OGRSQLiteSelectLayer::SetAttributeFilter( const char *pszQuery )
 
     CPLPushErrorHandler(CPLQuietErrorHandler);
     int bHasSpecialFields = (pszQuery != NULL && pszQuery[0] != '\0' &&
-        oQuery.Compile( GetLayerDefn(), pszQuery ) == OGRERR_NONE &&
-        HasSpecialFields((swq_expr_node*)oQuery.GetSWGExpr(), GetLayerDefn()->GetFieldCount()) );
+        oQuery.Compile( poLayer->GetLayerDefn(), pszQuery ) == OGRERR_NONE &&
+        HasSpecialFields((swq_expr_node*)oQuery.GetSWQExpr(), poLayer->GetLayerDefn()->GetFieldCount()) );
     CPLPopErrorHandler();
 
     if( bHasSpecialFields || !BuildSQL() )
     {
-        return OGRSQLiteLayer::SetAttributeFilter(pszQuery);
+        return poLayer->BaseSetAttributeFilter(pszQuery);
     }
 
     ResetReading();
@@ -221,12 +255,17 @@ OGRErr OGRSQLiteSelectLayer::SetAttributeFilter( const char *pszQuery )
 /*                           GetNextFeature()                           */
 /************************************************************************/
 
-int OGRSQLiteSelectLayer::GetFeatureCount( int bForce )
+GIntBig OGRSQLiteSelectLayer::GetFeatureCount( int bForce )
+{
+    return poBehaviour->GetFeatureCount(bForce);
+}
+
+GIntBig OGRSQLiteSelectLayerCommonBehaviour::GetFeatureCount( int bForce )
 {
     if( bEmptyLayer )
         return 0;
 
-    if( m_poAttrQuery == NULL &&
+    if( poLayer->GetFeatureQuery() == NULL &&
         EQUALN(osSQLCurrent, "SELECT COUNT(*) FROM", strlen("SELECT COUNT(*) FROM")) &&
         osSQLCurrent.ifind(" GROUP BY ") == std::string::npos &&
         osSQLCurrent.ifind(" UNION ") == std::string::npos &&
@@ -234,8 +273,8 @@ int OGRSQLiteSelectLayer::GetFeatureCount( int bForce )
         osSQLCurrent.ifind(" EXCEPT ") == std::string::npos )
         return 1;
 
-    if( m_poAttrQuery != NULL || (m_poFilterGeom != NULL && !bSpatialFilterInSQL) )
-        return OGRLayer::GetFeatureCount(bForce);
+    if( poLayer->GetFeatureQuery() != NULL || (poLayer->GetFilterGeom() != NULL && !bSpatialFilterInSQL) )
+        return poLayer->BaseGetFeatureCount(bForce);
 
     CPLString osFeatureCountSQL("SELECT COUNT(*) FROM (");
     osFeatureCountSQL += osSQLCurrent;
@@ -256,7 +295,7 @@ int OGRSQLiteSelectLayer::GetFeatureCount( int bForce )
     {
         CPLDebug("SQLITE", "Error: %s", pszErrMsg);
         sqlite3_free(pszErrMsg);
-        return OGRLayer::GetFeatureCount(bForce);
+        return poLayer->BaseGetFeatureCount(bForce);
     }
 
     if( nRowCount == 1 && nColCount == 1 )
@@ -284,10 +323,10 @@ OGRErr OGRSQLiteSelectLayer::ResetStatement()
     bDoStep = TRUE;
 
 #ifdef DEBUG
-    CPLDebug( "OGR_SQLITE", "prepare(%s)", osSQLCurrent.c_str() );
+    CPLDebug( "OGR_SQLITE", "prepare(%s)", poBehaviour->osSQLCurrent.c_str() );
 #endif
 
-    rc = sqlite3_prepare( poDS->GetDB(), osSQLCurrent, osSQLCurrent.size(),
+    rc = sqlite3_prepare( poDS->GetDB(), poBehaviour->osSQLCurrent, poBehaviour->osSQLCurrent.size(),
                           &hStmt, NULL );
 
     if( rc == SQLITE_OK )
@@ -298,7 +337,7 @@ OGRErr OGRSQLiteSelectLayer::ResetStatement()
     {
         CPLError( CE_Failure, CPLE_AppDefined, 
                   "In ResetStatement(): sqlite3_prepare(%s):\n  %s", 
-                  osSQLCurrent.c_str(), sqlite3_errmsg(poDS->GetDB()) );
+                  poBehaviour->osSQLCurrent.c_str(), sqlite3_errmsg(poDS->GetDB()) );
         hStmt = NULL;
         return OGRERR_FAILURE;
     }
@@ -311,11 +350,17 @@ OGRErr OGRSQLiteSelectLayer::ResetStatement()
 void OGRSQLiteSelectLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
 
 {
-    if( iGeomField == 0 && poGeomIn == NULL && GetLayerDefn()->GetGeomFieldCount() == 0 )
+    poBehaviour->SetSpatialFilter(iGeomField, poGeomIn);
+}
+
+void OGRSQLiteSelectLayerCommonBehaviour::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
+
+{
+    if( iGeomField == 0 && poGeomIn == NULL && poLayer->GetLayerDefn()->GetGeomFieldCount() == 0 )
     {
         /* do nothing */
     }
-    else if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() )
+    else if( iGeomField < 0 || iGeomField >= poLayer->GetLayerDefn()->GetGeomFieldCount() )
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                     "Invalid geometry field index : %d", iGeomField);
@@ -324,8 +369,9 @@ void OGRSQLiteSelectLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeo
 
     bAllowResetReadingEvenIfIndexAtZero = TRUE;
 
+    int& m_iGeomFieldFilter = poLayer->GetIGeomFieldFilter();
     m_iGeomFieldFilter = iGeomField;
-    if( InstallFilter( poGeomIn ) )
+    if( poLayer->InstallFilter( poGeomIn ) )
     {
         BuildSQL();
 
@@ -337,7 +383,7 @@ void OGRSQLiteSelectLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeo
 /*                            GetBaseLayer()                            */
 /************************************************************************/
 
-OGRSQLiteLayer* OGRSQLiteSelectLayer::GetBaseLayer(size_t& i)
+std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> OGRSQLiteSelectLayerCommonBehaviour::GetBaseLayer(size_t& i)
 {
     char** papszTokens = CSLTokenizeString(osSQLBase.c_str());
     int bCanInsertFilter = TRUE;
@@ -364,13 +410,13 @@ OGRSQLiteLayer* OGRSQLiteSelectLayer::GetBaseLayer(size_t& i)
     if (!(bCanInsertFilter && nCountSelect == 1 && nCountFrom == 1 && nCountWhere <= 1))
     {
         CPLDebug("SQLITE", "SQL expression too complex to analyse");
-        return NULL;
+        return std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>((OGRLayer*)NULL, (IOGRSQLiteGetSpatialWhere*)NULL);
     }
 
     size_t nFromPos = osSQLBase.ifind(" from ");
     if (nFromPos == std::string::npos)
     {
-        return NULL;
+        return std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>((OGRLayer*)NULL, (IOGRSQLiteGetSpatialWhere*)NULL);
     }
 
     char chQuote = osSQLBase[nFromPos + 6];
@@ -396,44 +442,44 @@ OGRSQLiteLayer* OGRSQLiteSelectLayer::GetBaseLayer(size_t& i)
             osBaseLayerName += osSQLBase[i];
     }
 
-    OGRSQLiteLayer* poUnderlyingLayer = NULL;
+    std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> oPair;
     if( strchr(osBaseLayerName, '(') == NULL &&
-        poFeatureDefn->GetGeomFieldCount() != 0 )
+        poLayer->GetLayerDefn()->GetGeomFieldCount() != 0 )
     {
         CPLString osNewUnderlyingTableName;
         osNewUnderlyingTableName.Printf("%s(%s)",
                                         osBaseLayerName.c_str(),
-                                        poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef());
-        poUnderlyingLayer =
-            (OGRSQLiteLayer*) poDS->GetLayerByName(osNewUnderlyingTableName);
+                                        poLayer->GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef());
+        oPair = poDS->GetLayerWithGetSpatialWhereByName(osNewUnderlyingTableName);
     }
-    if( poUnderlyingLayer == NULL )
-        poUnderlyingLayer = (OGRSQLiteLayer*) poDS->GetLayerByName(osBaseLayerName);
+    if( oPair.first == NULL )
+        oPair = poDS->GetLayerWithGetSpatialWhereByName(osBaseLayerName);
 
-    if( poUnderlyingLayer != NULL && GetSpatialRef() != NULL &&
-        poUnderlyingLayer->GetSpatialRef() != NULL &&
-        GetSpatialRef() != poUnderlyingLayer->GetSpatialRef() &&
-        !GetSpatialRef()->IsSame(poUnderlyingLayer->GetSpatialRef()) )
+    if( oPair.first != NULL && poLayer->GetSpatialRef() != NULL &&
+        oPair.first->GetSpatialRef() != NULL &&
+        poLayer->GetSpatialRef() != oPair.first->GetSpatialRef() &&
+        !poLayer->GetSpatialRef()->IsSame(oPair.first->GetSpatialRef()) )
     {
         CPLDebug("SQLITE", "Result layer and base layer don't have the same SRS.");
-        return NULL;
+        return std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*>((OGRLayer*)NULL, (IOGRSQLiteGetSpatialWhere*)NULL);
     }
 
-    return poUnderlyingLayer;
+    return oPair;
 }
 
 /************************************************************************/
 /*                             BuildSQL()                               */
 /************************************************************************/
 
-int OGRSQLiteSelectLayer::BuildSQL()
+int OGRSQLiteSelectLayerCommonBehaviour::BuildSQL()
 
 {
     osSQLCurrent = osSQLBase;
     bSpatialFilterInSQL = TRUE;
 
     size_t i = 0;
-    OGRSQLiteLayer* poBaseLayer = GetBaseLayer(i);
+    std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> oPair = GetBaseLayer(i);
+    OGRLayer* poBaseLayer = oPair.first;
     if (poBaseLayer == NULL)
     {
         CPLDebug("SQLITE", "Cannot find base layer");
@@ -442,10 +488,10 @@ int OGRSQLiteSelectLayer::BuildSQL()
     }
 
     CPLString osSpatialWhere;
-    if (m_poFilterGeom != NULL)
+    if (poLayer->GetFilterGeom() != NULL)
     {
         const char* pszGeomCol =
-            poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef();
+            poLayer->GetLayerDefn()->GetGeomFieldDefn(poLayer->GetIGeomFieldFilter())->GetNameRef();
         int nIdx = poBaseLayer->GetLayerDefn()->GetGeomFieldIndex(pszGeomCol);
         if( nIdx < 0 )
         {
@@ -454,7 +500,7 @@ int OGRSQLiteSelectLayer::BuildSQL()
         }
         else
         {
-            osSpatialWhere = poBaseLayer->GetSpatialWhere(nIdx, m_poFilterGeom);
+            osSpatialWhere = oPair.second->GetSpatialWhere(nIdx, poLayer->GetFilterGeom());
             if (osSpatialWhere.size() == 0)
             {
                 CPLDebug("SQLITE", "Cannot get spatial where clause");
@@ -468,11 +514,11 @@ int OGRSQLiteSelectLayer::BuildSQL()
     {
         osCustomWhere = osSpatialWhere;
     }
-    if( m_pszAttrQueryString != NULL && m_pszAttrQueryString[0] != '\0' )
+    if( poLayer->GetAttrQueryString() != NULL && poLayer->GetAttrQueryString()[0] != '\0' )
     {
         if( osSpatialWhere.size() != 0)
             osCustomWhere += " AND (";
-        osCustomWhere += m_pszAttrQueryString;
+        osCustomWhere += poLayer->GetAttrQueryString();
         if( osSpatialWhere.size() != 0)
             osCustomWhere += ")";
     }
@@ -540,30 +586,27 @@ int OGRSQLiteSelectLayer::BuildSQL()
 /************************************************************************/
 
 int OGRSQLiteSelectLayer::TestCapability( const char * pszCap )
+{
+    return poBehaviour->TestCapability(pszCap);
+}
+
+int OGRSQLiteSelectLayerCommonBehaviour::TestCapability( const char * pszCap )
 
 {
     if (EQUAL(pszCap,OLCFastSpatialFilter))
     {
-        if (osSQLCurrent != osSQLBase)
-            return TRUE;
-
         size_t i = 0;
-        OGRSQLiteLayer* poBaseLayer = GetBaseLayer(i);
-        if (poBaseLayer == NULL)
+        std::pair<OGRLayer*, IOGRSQLiteGetSpatialWhere*> oPair = GetBaseLayer(i);
+        if (oPair.first == NULL)
         {
             CPLDebug("SQLITE", "Cannot find base layer");
             return FALSE;
         }
 
-        OGRPolygon oFakePoly;
-        const char* pszWKT = "POLYGON((0 0,0 1,1 1,1 0,0 0))";
-        oFakePoly.importFromWkt((char**) &pszWKT);
-        CPLString    osSpatialWhere = poBaseLayer->GetSpatialWhere(0, &oFakePoly);
-
-        return osSpatialWhere.size() != 0;
+        return oPair.second->HasFastSpatialFilter(0);
     }
     else
-        return OGRSQLiteLayer::TestCapability( pszCap );
+        return poLayer->BaseTestCapability( pszCap );
 }
 
 /************************************************************************/
@@ -572,8 +615,13 @@ int OGRSQLiteSelectLayer::TestCapability( const char * pszCap )
 
 OGRErr OGRSQLiteSelectLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
 {
-    if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
-        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
+    return poBehaviour->GetExtent(iGeomField, psExtent, bForce);
+}
+
+OGRErr OGRSQLiteSelectLayerCommonBehaviour::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
+{
+    if( iGeomField < 0 || iGeomField >= poLayer->GetLayerDefn()->GetGeomFieldCount() ||
+        poLayer->GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
     {
         if( iGeomField != 0 )
         {
@@ -621,9 +669,9 @@ OGRErr OGRSQLiteSelectLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, in
 
     OGRErr eErr;
     if( iGeomField == 0 )
-        eErr = OGRSQLiteLayer::GetExtent(psExtent, bForce);
+        eErr = poLayer->BaseGetExtent(psExtent, bForce);
     else
-        eErr = OGRSQLiteLayer::GetExtent(iGeomField, psExtent, bForce);
+        eErr = poLayer->BaseGetExtent(iGeomField, psExtent, bForce);
     if (iGeomField == 0 && eErr == OGRERR_NONE && poDS->GetUpdate() == FALSE)
         poDS->SetEnvelopeForSQL(osSQLBase, *psExtent);
     return eErr;
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitesinglefeaturelayer.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitesinglefeaturelayer.cpp
index 008c092..b204536 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitesinglefeaturelayer.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitesinglefeaturelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitesinglefeaturelayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqlitesinglefeaturelayer.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteSingleFeatureLayer class.
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include "ogr_sqlite.h"
 
-CPL_CVSID("$Id: ogrsqlitesinglefeaturelayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsqlitesinglefeaturelayer.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 /************************************************************************/
 /*                    OGRSQLiteSingleFeatureLayer()                     */
@@ -42,6 +42,7 @@ OGRSQLiteSingleFeatureLayer::OGRSQLiteSingleFeatureLayer(
                                                      int nVal )
 {
     poFeatureDefn = new OGRFeatureDefn( "SELECT" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     OGRFieldDefn oField( pszLayerName, OFTInteger );
     poFeatureDefn->AddFieldDefn( &oField );
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitesqlfunctions.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitesqlfunctions.cpp
index 2884bba..d3bfab1 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitesqlfunctions.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitesqlfunctions.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitesqlfunctions.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsqlitesqlfunctions.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Extension SQL functions
@@ -37,6 +37,7 @@
 #include "ogr_geocoding.h"
 
 #include "ogrsqliteregexp.cpp" /* yes the .cpp file, to make it work on Windows with load_extension('gdalXX.dll') */
+#include "swq.h"
 
 #ifndef HAVE_SPATIALITE
 #define MINIMAL_SPATIAL_FUNCTIONS
@@ -334,6 +335,9 @@ void OGR2SQLITE_ogr_geocode_set_result(sqlite3_context* pContext,
             if( eType == OFTInteger )
                 sqlite3_result_int(pContext,
                                    poFeature->GetFieldAsInteger(nIdx));
+            else if( eType == OFTInteger64 )
+                sqlite3_result_int64(pContext,
+                                   poFeature->GetFieldAsInteger64(nIdx));
             else if( eType == OFTReal )
                 sqlite3_result_double(pContext,
                                       poFeature->GetFieldAsDouble(nIdx));
@@ -426,7 +430,7 @@ static double OGR2SQLITE_GetValAsDouble(sqlite3_value* val, int* pbGotVal)
 
         case SQLITE_INTEGER:
             if( pbGotVal ) *pbGotVal = TRUE;
-            return sqlite3_value_int64(val);
+            return (double) sqlite3_value_int64(val);
 
         default:
             if( pbGotVal ) *pbGotVal = FALSE;
@@ -439,7 +443,8 @@ static double OGR2SQLITE_GetValAsDouble(sqlite3_value* val, int* pbGotVal)
 /************************************************************************/
 
 static OGRGeometry* OGR2SQLITE_GetGeom(CPL_UNUSED sqlite3_context* pContext,
-                                       CPL_UNUSED int argc, sqlite3_value** argv,
+                                       CPL_UNUSED int argc,
+                                       sqlite3_value** argv,
                                        int* pnSRSId)
 {
     if( sqlite3_value_type (argv[0]) != SQLITE_BLOB )
@@ -1038,6 +1043,32 @@ void OGR2SQLITE_ST_MakePoint(sqlite3_context* pContext,
 
 #endif // #ifdef MINIMAL_SPATIAL_FUNCTIONS
 
+
+/************************************************************************/
+/*                     OGRSQLITE_hstore_get_value()                     */
+/************************************************************************/
+
+static
+void OGRSQLITE_hstore_get_value(sqlite3_context* pContext,
+                                CPL_UNUSED int argc,
+                                sqlite3_value** argv)
+{
+    if( sqlite3_value_type (argv[0]) != SQLITE_TEXT ||
+        sqlite3_value_type (argv[1]) != SQLITE_TEXT )
+    {
+        sqlite3_result_null (pContext);
+        return;
+    }
+
+    const char* pszHStore = (const char*)sqlite3_value_text(argv[0]);
+    const char* pszSearchedKey = (const char*)sqlite3_value_text(argv[1]);
+    char* pszValue = OGRHStoreGetValue(pszHStore, pszSearchedKey);
+    if( pszValue != NULL )
+        sqlite3_result_text( pContext, pszValue, -1, CPLFree );
+    else
+        sqlite3_result_null( pContext );
+}
+
 /************************************************************************/
 /*                   OGRSQLiteRegisterSQLFunctions()                    */
 /************************************************************************/
@@ -1089,6 +1120,10 @@ void* OGRSQLiteRegisterSQLFunctions(sqlite3* hDB)
     sqlite3_create_function(hDB, "Transform3", 3, SQLITE_ANY, pData,
                             OGR2SQLITE_Transform, NULL, NULL);
 
+    // HSTORE functions
+    sqlite3_create_function(hDB, "hstore_get_value", 2, SQLITE_ANY, NULL,
+                            OGRSQLITE_hstore_get_value, NULL, NULL);
+
 #ifdef MINIMAL_SPATIAL_FUNCTIONS
     /* Check if spatialite is available */
     int rc = sqlite3_exec(hDB, "SELECT spatialite_version()", NULL, NULL, NULL);
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp
index f87c086..5c4391f 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitetablelayer.cpp 27770 2014-09-30 11:57:38Z rouault $
+ * $Id: ogrsqlitetablelayer.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteTableLayer class, access to an existing table.
@@ -37,7 +37,7 @@
 
 #define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
 
-CPL_CVSID("$Id: ogrsqlitetablelayer.cpp 27770 2014-09-30 11:57:38Z rouault $");
+CPL_CVSID("$Id: ogrsqlitetablelayer.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 /************************************************************************/
 /*                        OGRSQLiteTableLayer()                         */
@@ -62,22 +62,21 @@ OGRSQLiteTableLayer::OGRSQLiteTableLayer( OGRSQLiteDataSource *poDSIn )
     pszTableName = NULL;
     pszEscapedTableName = NULL;
 
-    bHasCheckedSpatialIndexTable = FALSE;
-    bDeferedSpatialIndexCreation = FALSE;
+    bDeferredSpatialIndexCreation = FALSE;
 
     hInsertStmt = NULL;
 
-    eGeomType = wkbUnknown;
     bLayerDefnError = FALSE;
 
     bStatisticsNeedsToBeFlushed = FALSE;
-    bCachedExtentIsValid = FALSE;
     nFeatureCount = -1;
 
-    eGeomFormat = OSGF_None;
-    pszGeomCol = NULL;
-    nSRSId = UNINITIALIZED_SRID;
-    poSRS = NULL;
+    int bDisableInsertTriggers = CSLTestBoolean(CPLGetConfigOption(
+                            "OGR_SQLITE_DISABLE_INSERT_TRIGGERS", "YES"));
+    bHasCheckedTriggers = !bDisableInsertTriggers;
+    bDeferredCreation = FALSE;
+    pszCreationGeomFormat = NULL;
+    iFIDAsRegularColumnIndex = -1;
 }
 
 /************************************************************************/
@@ -90,15 +89,43 @@ OGRSQLiteTableLayer::~OGRSQLiteTableLayer()
     ClearStatement();
     ClearInsertStmt();
 
-    CPLFree(pszGeomCol);
-    if( poSRS != NULL )
+    char* pszErrMsg = NULL;
+    int nGeomFieldCount = (poFeatureDefn) ? poFeatureDefn->GetGeomFieldCount() : 0;
+    for(int i=0;i<nGeomFieldCount; i++)
     {
-        poSRS->Release();
-        poSRS = NULL;
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(i);
+        // Restore temporarily disabled triggers
+        for(int j = 0; j < (int)poGeomFieldDefn->aosDisabledTriggers.size(); j++ )
+        {
+            CPLDebug("SQLite", "Restoring trigger %s",
+                     poGeomFieldDefn->aosDisabledTriggers[j].first.c_str());
+            // This may fail since CreateSpatialIndex() reinstalls triggers, so
+            // don't check result
+            sqlite3_exec( poDS->GetDB(),
+                          poGeomFieldDefn->aosDisabledTriggers[j].second.c_str(),
+                          NULL, NULL, &pszErrMsg );
+            if( pszErrMsg )
+                sqlite3_free( pszErrMsg );
+            pszErrMsg = NULL;
+        }
+    
+        // Update geometry_columns_time
+        if( poGeomFieldDefn->aosDisabledTriggers.size() != 0 )
+        {
+            char* pszSQL3 = sqlite3_mprintf(
+                "UPDATE geometry_columns_time SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+                "WHERE Lower(f_table_name) = Lower('%q') AND Lower(f_geometry_column) = Lower('%q')",
+                pszTableName, poGeomFieldDefn->GetNameRef());
+            sqlite3_exec( poDS->GetDB(), pszSQL3, NULL, NULL, &pszErrMsg );
+            if( pszErrMsg )
+                sqlite3_free( pszErrMsg );
+            pszErrMsg = NULL;
+        }
     }
 
     CPLFree(pszTableName);
     CPLFree(pszEscapedTableName);
+    CPLFree(pszCreationGeomFormat);
 }
 
 /************************************************************************/
@@ -107,9 +134,11 @@ OGRSQLiteTableLayer::~OGRSQLiteTableLayer()
 
 void OGRSQLiteTableLayer::CreateSpatialIndexIfNecessary()
 {
-    if( bDeferedSpatialIndexCreation )
+    if( bDeferredSpatialIndexCreation )
     {
-        CreateSpatialIndex();
+        for(int iGeomCol = 0; iGeomCol < poFeatureDefn->GetGeomFieldCount(); iGeomCol ++)
+            CreateSpatialIndex(iGeomCol);
+        bDeferredSpatialIndexCreation = FALSE;
     }
 }
 
@@ -132,19 +161,57 @@ void OGRSQLiteTableLayer::ClearInsertStmt()
 /************************************************************************/
 
 CPLErr OGRSQLiteTableLayer::Initialize( const char *pszTableName, 
-                                        const char *pszGeomCol,
-                                        int bMustIncludeGeomColName,
-                                        OGRwkbGeometryType eGeomType,
-                                        const char *pszGeomFormat,
-                                        OGRSpatialReference *poSRS,
-                                        int nSRSId,
-                                        int bHasSpatialIndex,
-                                        int bHasM,
-                                        int bIsVirtualShapeIn )
+                                        int bIsVirtualShapeIn,
+                                        int bDeferredCreation )
 {
-    /* int rc; */
-    sqlite3 *hDB = poDS->GetDB();
+    SetDescription( pszTableName );
+
+    this->bIsVirtualShape = bIsVirtualShapeIn;
+    this->pszTableName = CPLStrdup(pszTableName);
+    this->bDeferredCreation = bDeferredCreation;
+    pszEscapedTableName = CPLStrdup(OGRSQLiteEscape(pszTableName));
+
+    if( strchr(pszTableName, '(') != NULL &&
+        pszTableName[strlen(pszTableName)-1] == ')' )
+    {
+        char* pszErrMsg = NULL;
+        int nRowCount = 0, nColCount = 0;
+        char** papszResult = NULL;
+        const char* pszSQL = CPLSPrintf("SELECT * FROM sqlite_master WHERE name = '%s'",
+                                        pszEscapedTableName);
+        int rc = sqlite3_get_table( poDS->GetDB(),
+                                pszSQL,
+                                &papszResult, &nRowCount, 
+                                &nColCount, &pszErrMsg );
+        int bFound = ( rc == SQLITE_OK && nRowCount == 1 );
+        sqlite3_free_table(papszResult);
+        sqlite3_free( pszErrMsg );
+
+        if( !bFound )
+        {
+            char* pszGeomCol = CPLStrdup(strchr(pszTableName, '(')+1);
+            pszGeomCol[strlen(pszGeomCol)-1] = 0;
+            *strchr(this->pszTableName, '(') = 0;
+            pszTableName = this->pszTableName;
+            CPLFree(pszEscapedTableName),
+            pszEscapedTableName = CPLStrdup(OGRSQLiteEscape(pszTableName));
+            EstablishFeatureDefn(pszGeomCol);
+            CPLFree(pszGeomCol);
+            if( poFeatureDefn->GetGeomFieldCount() == 0 )
+                return CE_Failure;
+        }
+    }
+
+    return CE_None;
+}
+
+/************************************************************************/
+/*                            GetGeomFormat()                           */
+/************************************************************************/
 
+static OGRSQLiteGeomFormat GetGeomFormat( const char* pszGeomFormat )
+{
+    OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
     if( pszGeomFormat )
     {
         if ( EQUAL(pszGeomFormat, "WKT") )
@@ -156,79 +223,76 @@ CPLErr OGRSQLiteTableLayer::Initialize( const char *pszTableName,
         else if( EQUAL(pszGeomFormat,"SpatiaLite") )
             eGeomFormat = OSGF_SpatiaLite;
     }
+    return eGeomFormat;
+}
 
-    CPLFree( pszFIDColumn );
-    pszFIDColumn = NULL;
-
-    if( nSRSId == UNINITIALIZED_SRID )
-        nSRSId = poDS->GetUndefinedSRID();
-
-    this->poSRS = poSRS;
-    this->nSRSId = nSRSId;
-    this->bHasSpatialIndex = bHasSpatialIndex;
-    this->bHasM = bHasM;
-    this->bIsVirtualShape = bIsVirtualShapeIn;
-    this->pszTableName = CPLStrdup(pszTableName);
-    this->pszGeomCol = (pszGeomCol) ? CPLStrdup(pszGeomCol) : NULL;
-    this->eGeomType = eGeomType;
-
-    if( bMustIncludeGeomColName )
-        osLayerName.Printf("%s(%s)", pszTableName, pszGeomCol);
-    else
-        osLayerName = pszTableName;
-
-    pszEscapedTableName = CPLStrdup(OGRSQLiteEscape(pszTableName));
-
-    // sqlite3_stmt *hColStmt = NULL;
-    const char *pszSQL;
-
-    if ( eGeomFormat == OSGF_SpatiaLite &&
-         poDS->IsSpatialiteLoaded() &&
-         poDS->GetSpatialiteVersionNumber() < 24 && poDS->GetUpdate() )
-    {
-        // we need to test version required by Spatialite TRIGGERs
-        // hColStmt = NULL;
-        pszSQL = CPLSPrintf( "SELECT sql FROM sqlite_master WHERE type = 'trigger' AND tbl_name = '%s' AND sql LIKE '%%RTreeAlign%%'",
-            pszEscapedTableName );
-
-        int nRowTriggerCount, nColTriggerCount;
-        char **papszTriggerResult, *pszErrMsg;
+/************************************************************************/
+/*                         SetCreationParameters()                      */
+/************************************************************************/
 
-        /* rc = */ sqlite3_get_table( hDB, pszSQL, &papszTriggerResult,
-            &nRowTriggerCount, &nColTriggerCount, &pszErrMsg );
-        if( nRowTriggerCount >= 1 )
-        {
-        // obsolete library version not supporting new triggers
-        // enforcing ReadOnly mode
-            CPLDebug("SQLITE", "Enforcing ReadOnly mode : obsolete library version not supporting new triggers");
-            poDS->SetUpdate(FALSE);
-        }
+void OGRSQLiteTableLayer::SetCreationParameters( const char *pszFIDColumnName,
+                                                 OGRwkbGeometryType eGeomType,
+                                                 const char *pszGeomFormat,
+                                                 const char *pszGeometryName,
+                                                 OGRSpatialReference *poSRS,
+                                                 int nSRSId )
 
-        sqlite3_free_table( papszTriggerResult );
+{
+    pszFIDColumn = CPLStrdup(pszFIDColumnName);
+    poFeatureDefn = new OGRSQLiteFeatureDefn(pszTableName);
+    poFeatureDefn->SetGeomType(wkbNone);
+    poFeatureDefn->Reference();
+    pszCreationGeomFormat = (pszGeomFormat) ? CPLStrdup(pszGeomFormat) : NULL;
+    if( eGeomType != wkbNone )
+    {
+        if( nSRSId == UNINITIALIZED_SRID )
+            nSRSId = poDS->GetUndefinedSRID();
+        OGRSQLiteGeomFormat eGeomFormat = GetGeomFormat(pszGeomFormat);
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+            new OGRSQLiteGeomFieldDefn(pszGeometryName, -1);
+        poGeomFieldDefn->SetType(eGeomType);
+        poGeomFieldDefn->nSRSId = nSRSId;
+        poGeomFieldDefn->eGeomFormat = eGeomFormat;
+        poGeomFieldDefn->SetSpatialRef(poSRS);
+        poFeatureDefn->AddGeomFieldDefn(poGeomFieldDefn, FALSE);
     }
+}
+
+/************************************************************************/
+/*                               GetName()                              */
+/************************************************************************/
 
-    if( poSRS )
-        poSRS->Reference();
+const char* OGRSQLiteTableLayer::GetName()
+{
+    return GetDescription();
+}
 
-    LoadStatistics();
+/************************************************************************/
+/*                             GetMetadata()                            */
+/************************************************************************/
 
-    return CE_None;
+char** OGRSQLiteTableLayer::GetMetadata( const char * pszDomain )
+{
+    GetLayerDefn();
+    return OGRSQLiteLayer::GetMetadata(pszDomain);
 }
 
 /************************************************************************/
-/*                               GetName()                              */
+/*                           GetMetadataItem()                          */
 /************************************************************************/
 
-const char* OGRSQLiteTableLayer::GetName()
+const char * OGRSQLiteTableLayer::GetMetadataItem( const char * pszName,
+                                                   const char * pszDomain )
 {
-    return osLayerName.c_str();
+    GetLayerDefn();
+    return OGRSQLiteLayer::GetMetadataItem(pszName, pszDomain);
 }
 
 /************************************************************************/
 /*                         EstablishFeatureDefn()                       */
 /************************************************************************/
 
-CPLErr OGRSQLiteTableLayer::EstablishFeatureDefn()
+CPLErr OGRSQLiteTableLayer::EstablishFeatureDefn(const char* pszGeomCol)
 {
     sqlite3 *hDB = poDS->GetDB();
     int rc;
@@ -278,23 +342,253 @@ CPLErr OGRSQLiteTableLayer::EstablishFeatureDefn()
 /* -------------------------------------------------------------------- */
 /*      Collect the rest of the fields.                                 */
 /* -------------------------------------------------------------------- */
-    BuildFeatureDefn( osLayerName, hColStmt, pszGeomCol, poDS->GetGeomColsForTable(pszTableName) );
+    if( pszGeomCol )
+    {
+        std::set<CPLString> aosGeomCols;
+        aosGeomCols.insert(pszGeomCol);
+        std::set<CPLString> aosIgnoredCols(poDS->GetGeomColsForTable(pszTableName));
+        aosIgnoredCols.erase(pszGeomCol);
+        BuildFeatureDefn( GetDescription(), hColStmt, aosGeomCols, aosIgnoredCols);
+    }
+    else
+    {
+        std::set<CPLString> aosIgnoredCols;
+        BuildFeatureDefn( GetDescription(), hColStmt,
+                          poDS->GetGeomColsForTable(pszTableName), aosIgnoredCols );
+    }
     sqlite3_finalize( hColStmt );
 
 /* -------------------------------------------------------------------- */
+/*      Find if the FID holds 64bit values                              */
+/* -------------------------------------------------------------------- */
+    pszSQL = CPLSPrintf("SELECT MAX(%s) FROM '%s'",
+                        OGRSQLiteEscape(pszFIDColumn).c_str(),
+                        pszEscapedTableName);
+    hColStmt = NULL;
+    rc = sqlite3_prepare( hDB, pszSQL, strlen(pszSQL), &hColStmt, NULL ); 
+    if( rc == SQLITE_OK )
+    {
+        rc = sqlite3_step( hColStmt );
+        if( rc == SQLITE_ROW )
+        {
+            GIntBig nMaxId = sqlite3_column_int64( hColStmt, 0 );
+            if( nMaxId > INT_MAX )
+                SetMetadataItem(OLMD_FID64, "YES");
+        }
+    }
+    sqlite3_finalize( hColStmt );
+        
+/* -------------------------------------------------------------------- */
 /*      Set the properties of the geometry column.                      */
 /* -------------------------------------------------------------------- */
-    if( poFeatureDefn->GetGeomFieldCount() != 0 )
+    int bHasSpatialiteCol = FALSE;
+    for(int i=0; i<poFeatureDefn->GetGeomFieldCount(); i++ )
     {
-        poFeatureDefn->SetGeomType( eGeomType );
         OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
-            poFeatureDefn->myGetGeomFieldDefn(0);
-        if( pszGeomCol == NULL )
-            pszGeomCol = CPLStrdup( poGeomFieldDefn->GetNameRef() );
-        poGeomFieldDefn->nSRSId = nSRSId;
-        if( eGeomFormat != OSGF_None )
-            poGeomFieldDefn->eGeomFormat = eGeomFormat;
-        poGeomFieldDefn->SetSpatialRef(poSRS);
+            poFeatureDefn->myGetGeomFieldDefn(i);
+        poGeomFieldDefn->nSRSId = poDS->GetUndefinedSRID();
+
+        if( poDS->IsSpatialiteDB() )
+        {
+            if( poDS->HasSpatialite4Layout() )
+            {
+                pszSQL = CPLSPrintf("SELECT srid, geometry_type, coord_dimension, spatial_index_enabled FROM geometry_columns WHERE lower(f_table_name) = lower('%s') AND lower(f_geometry_column) = lower('%s')",
+                                    pszEscapedTableName,
+                                    OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
+            }
+            else
+            {
+                pszSQL = CPLSPrintf("SELECT srid, type, coord_dimension, spatial_index_enabled FROM geometry_columns WHERE lower(f_table_name) = lower('%s') AND lower(f_geometry_column) = lower('%s')",
+                                    pszEscapedTableName,
+                                    OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
+            }
+        }
+        else
+        {
+            pszSQL = CPLSPrintf("SELECT srid, geometry_type, coord_dimension, geometry_format FROM geometry_columns WHERE lower(f_table_name) = lower('%s') AND lower(f_geometry_column) = lower('%s')",
+                                pszEscapedTableName,
+                                OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
+        }
+        char* pszErrMsg = NULL;
+        int nRowCount = 0, nColCount = 0;
+        char** papszResult = NULL;
+        rc = sqlite3_get_table( hDB,
+                                pszSQL,
+                                &papszResult, &nRowCount, 
+                                &nColCount, &pszErrMsg );
+        OGRwkbGeometryType eGeomType = wkbUnknown;
+        OGRSQLiteGeomFormat eGeomFormat = OSGF_None;
+        if( rc == SQLITE_OK && nRowCount == 1 )
+        {
+            char **papszRow = papszResult + nColCount;
+            if( papszRow[1] == NULL || papszRow[2] == NULL )
+            {
+                CPLDebug("SQLite", "Did not get expected col value");
+                continue;
+            }
+            if( papszRow[0] != NULL )
+                poGeomFieldDefn->nSRSId = atoi(papszRow[0]);
+            if( poDS->IsSpatialiteDB() )
+            {
+                int bHasM = FALSE;
+                if( papszRow[3] != NULL )
+                    poGeomFieldDefn->bHasSpatialIndex = atoi(papszRow[3]);
+                if( poDS->HasSpatialite4Layout() )
+                {
+                    int nGeomType = atoi(papszRow[1]);
+
+                    if( nGeomType >= 0 && nGeomType <= 7 ) /* XY */
+                        eGeomType = (OGRwkbGeometryType) nGeomType;
+                    else if( nGeomType >= 1000 && nGeomType <= 1007 ) /* XYZ */
+                        eGeomType = wkbSetZ(wkbFlatten(nGeomType));
+                    else if( nGeomType >= 2000 && nGeomType <= 2007 ) /* XYM */
+                    {
+                        eGeomType = wkbFlatten(nGeomType);
+                        bHasM = TRUE;
+                    }
+                    else if( nGeomType >= 3000 && nGeomType <= 3007 ) /* XYZM */
+                    {
+                        eGeomType = wkbSetZ(wkbFlatten(nGeomType));
+                        bHasM = TRUE;
+                    }
+                }
+                else
+                {
+                    eGeomType = OGRFromOGCGeomType(papszRow[1]);
+
+                    if( strcmp ( papszRow[2], "XYZ" ) == 0 ||
+                        strcmp ( papszRow[2], "XYZM" ) == 0 ||
+                        strcmp ( papszRow[2], "3" ) == 0) // SpatiaLite's own 3D geometries
+                        eGeomType = wkbSetZ(eGeomType);
+
+                    if( strcmp ( papszRow[2], "XYM" ) == 0 ||
+                        strcmp ( papszRow[2], "XYZM" ) == 0 ) // M coordinate declared
+                        bHasM = TRUE;
+                }
+                poGeomFieldDefn->bHasM = bHasM;
+                eGeomFormat = OSGF_SpatiaLite;
+            }
+            else
+            {
+                eGeomType = (OGRwkbGeometryType) atoi(papszRow[1]);
+                if( atoi(papszRow[2]) > 2 )
+                    eGeomType = wkbSetZ(eGeomType);
+                eGeomFormat = GetGeomFormat( papszRow[3] );
+            }
+        }
+        sqlite3_free_table(papszResult);
+        sqlite3_free( pszErrMsg );
+
+        poGeomFieldDefn->eGeomFormat = eGeomFormat;
+        poGeomFieldDefn->SetType( eGeomType );
+        poGeomFieldDefn->SetSpatialRef(poDS->FetchSRS(poGeomFieldDefn->nSRSId));
+
+        if( eGeomFormat == OSGF_SpatiaLite )
+            bHasSpatialiteCol = TRUE;
+    }
+
+    if ( bHasSpatialiteCol &&
+        poDS->IsSpatialiteLoaded() &&
+        poDS->GetSpatialiteVersionNumber() < 24 && poDS->GetUpdate() )
+    {
+        // we need to test version required by Spatialite TRIGGERs
+        // hColStmt = NULL;
+        const char *pszSQL = CPLSPrintf( "SELECT sql FROM sqlite_master WHERE type = 'trigger' AND tbl_name = '%s' AND sql LIKE '%%RTreeAlign%%'",
+            pszEscapedTableName );
+
+        int nRowTriggerCount, nColTriggerCount;
+        char **papszTriggerResult, *pszErrMsg;
+
+        /* rc = */ sqlite3_get_table( hDB, pszSQL, &papszTriggerResult,
+            &nRowTriggerCount, &nColTriggerCount, &pszErrMsg );
+        if( nRowTriggerCount >= 1 )
+        {
+        // obsolete library version not supporting new triggers
+        // enforcing ReadOnly mode
+            CPLDebug("SQLITE", "Enforcing ReadOnly mode : obsolete library version not supporting new triggers");
+            poDS->SetUpdate(FALSE);
+        }
+
+        sqlite3_free_table( papszTriggerResult );
+    }
+/* -------------------------------------------------------------------- */
+/*      Check if there are default values and nullable status           */
+/* -------------------------------------------------------------------- */
+
+    char **papszResult;
+    int nRowCount, nColCount;
+    char *pszErrMsg = NULL;
+    /*  #|name|type|notnull|default|pk */
+    char* pszSQL3 = sqlite3_mprintf("PRAGMA table_info('%q')", pszTableName);
+    rc = sqlite3_get_table( hDB, pszSQL3, &papszResult, &nRowCount,
+                            &nColCount, &pszErrMsg );
+    sqlite3_free( pszSQL3 );
+    if( rc != SQLITE_OK )
+    {
+        sqlite3_free( pszErrMsg );
+    }
+    else
+    {
+        if( nColCount == 6 )
+        {
+            for(int i=0;i<nRowCount;i++)
+            {
+                const char* pszName = papszResult[(i+1)*6+1];
+                const char* pszNotNull = papszResult[(i+1)*6+3];
+                const char* pszDefault = papszResult[(i+1)*6+4];
+                if( pszDefault != NULL )
+                {
+                    int idx = poFeatureDefn->GetFieldIndex(pszName);
+                    if( idx >= 0 )
+                    {
+                        OGRFieldDefn* poFieldDefn =  poFeatureDefn->GetFieldDefn(idx);
+                        if( poFieldDefn->GetType() == OFTString &&
+                            !EQUAL(pszDefault, "NULL") &&
+                            !EQUALN(pszDefault, "CURRENT_", strlen("CURRENT_")) &&
+                            pszDefault[0] != '(' &&
+                            pszDefault[0] != '\'' &&
+                            CPLGetValueType(pszDefault) == CPL_VALUE_STRING )
+                        {
+                            CPLString osDefault("'");
+                            char* pszTmp = CPLEscapeString(pszDefault, -1, CPLES_SQL);
+                            osDefault += pszTmp;
+                            CPLFree(pszTmp);
+                            osDefault += "'";
+                            poFieldDefn->SetDefault(osDefault);
+                        }
+                        else if( (poFieldDefn->GetType() == OFTDate || poFieldDefn->GetType() == OFTDateTime) &&
+                             !EQUAL(pszDefault, "NULL") &&
+                             !EQUALN(pszDefault, "CURRENT_", strlen("CURRENT_")) &&
+                             pszDefault[0] != '(' &&
+                             pszDefault[0] != '\'' &&
+                             !(pszDefault[0] >= '0' && pszDefault[0] <= '9') &&
+                            CPLGetValueType(pszDefault) == CPL_VALUE_STRING )
+                        {
+                            CPLString osDefault("(");
+                            osDefault += pszDefault;
+                            osDefault += ")";
+                            poFieldDefn->SetDefault(osDefault);
+                        }
+                        else
+                            poFieldDefn->SetDefault(pszDefault);
+                    }
+                }
+                if( pszName != NULL && pszNotNull != NULL &&
+                    EQUAL(pszNotNull, "1") )
+                {
+                    int idx = poFeatureDefn->GetFieldIndex(pszName);
+                    if( idx >= 0 )
+                        poFeatureDefn->GetFieldDefn(idx)->SetNullable(0);
+                    else
+                    {
+                        idx = poFeatureDefn->GetGeomFieldIndex(pszName);
+                        if( idx >= 0 )
+                            poFeatureDefn->GetGeomFieldDefn(idx)->SetNullable(0);
+                    }
+                }
+            }
+        }
+        sqlite3_free_table(papszResult);
     }
 
     return CE_None;
@@ -351,6 +645,16 @@ OGRErr OGRSQLiteTableLayer::RecomputeOrdinals()
         CPLString osName =
             OGRSQLiteParamsUnquote(sqlite3_column_name( hColStmt, iCol ));
         int nIdx = poFeatureDefn->GetFieldIndex(osName);
+        if( pszFIDColumn != NULL && strcmp(osName, pszFIDColumn) == 0 )
+        {
+            if( iFIDCol < 0 )
+            {
+                iFIDCol = iCol;
+                if( nIdx >= 0 ) /* in case it has also been created as a regular field */
+                    nCountFieldOrdinals ++;
+            }
+            continue;
+        }
         if( nIdx >= 0 )
         {
             panFieldOrdinals[nIdx] = iCol;
@@ -366,13 +670,11 @@ OGRErr OGRSQLiteTableLayer::RecomputeOrdinals()
                 poGeomFieldDefn->iCol = iCol;
                 nCountGeomFieldOrdinals ++;
             }
-            else if( pszFIDColumn != NULL && strcmp(osName, pszFIDColumn) == 0 )
-                iFIDCol = iCol;
         }
     }
     CPLAssert(nCountFieldOrdinals == poFeatureDefn->GetFieldCount() );
     CPLAssert(nCountGeomFieldOrdinals == poFeatureDefn->GetGeomFieldCount() );
-    CPLAssert(pszFIDColumn == NULL || iFIDCol > 0 );
+    CPLAssert(pszFIDColumn == NULL || iFIDCol >= 0 );
 
     sqlite3_finalize( hColStmt );
 
@@ -388,15 +690,17 @@ OGRFeatureDefn* OGRSQLiteTableLayer::GetLayerDefn()
     if (poFeatureDefn)
         return poFeatureDefn;
 
-    EstablishFeatureDefn();
+    EstablishFeatureDefn(NULL);
 
     if (poFeatureDefn == NULL)
     {
         bLayerDefnError = TRUE;
 
-        poFeatureDefn = new OGRSQLiteFeatureDefn( osLayerName );
+        poFeatureDefn = new OGRSQLiteFeatureDefn( GetDescription() );
         poFeatureDefn->Reference();
     }
+    else
+        LoadStatistics();
 
     return poFeatureDefn;
 }
@@ -410,6 +714,8 @@ OGRErr OGRSQLiteTableLayer::ResetStatement()
 {
     int rc;
     CPLString osSQL;
+    
+    if( bDeferredCreation ) RunDeferredCreationIfNecessary();
 
     ClearStatement();
 
@@ -449,19 +755,30 @@ OGRErr OGRSQLiteTableLayer::ResetStatement()
 OGRFeature *OGRSQLiteTableLayer::GetNextFeature()
 
 {
+    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+
     if (HasLayerDefnError())
         return NULL;
 
-    return OGRSQLiteLayer::GetNextFeature();
+    OGRFeature* poFeature = OGRSQLiteLayer::GetNextFeature();
+    if( poFeature && iFIDAsRegularColumnIndex >= 0 )
+    {
+        poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
+    }
+    return poFeature;
 }
 
 /************************************************************************/
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRSQLiteTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRSQLiteTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
+    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return NULL;
+
     if (HasLayerDefnError())
         return NULL;
 
@@ -482,7 +799,7 @@ OGRFeature *OGRSQLiteTableLayer::GetFeature( long nFeatureId )
 
     iNextShapeId = nFeatureId;
 
-    osSQL.Printf( "SELECT _rowid_, * FROM '%s' WHERE \"%s\" = %ld",
+    osSQL.Printf( "SELECT _rowid_, * FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
                   pszEscapedTableName, 
                   OGRSQLiteEscape(pszFIDColumn).c_str(), nFeatureId );
 
@@ -537,9 +854,30 @@ OGRErr OGRSQLiteTableLayer::SetAttributeFilter( const char *pszQuery )
 /*                          SetSpatialFilter()                          */
 /************************************************************************/
 
-void OGRSQLiteTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
+void OGRSQLiteTableLayer::SetSpatialFilter(  OGRGeometry * poGeomIn )
+{
+    SetSpatialFilter(0,poGeomIn);
+}
+
+void OGRSQLiteTableLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
 
 {
+    if( iGeomField == 0 )
+    {
+        m_iGeomFieldFilter = 0;
+    }
+    else
+    {
+        if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "Invalid geometry field index : %d", iGeomField);
+            return;
+        }
+
+        m_iGeomFieldFilter = iGeomField;
+    }
+
     if( InstallFilter( poGeomIn ) )
     {
         BuildWhere();
@@ -552,11 +890,15 @@ void OGRSQLiteTableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
 /*                        CheckSpatialIndexTable()                      */
 /************************************************************************/
 
-int OGRSQLiteTableLayer::CheckSpatialIndexTable()
+int OGRSQLiteTableLayer::CheckSpatialIndexTable(int iGeomCol)
 {
-    if (HasSpatialIndex() && !bHasCheckedSpatialIndexTable)
+    GetLayerDefn();
+    if( iGeomCol < 0 || iGeomCol >= poFeatureDefn->GetGeomFieldCount() )
+        return FALSE;
+    OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
+    if (HasSpatialIndex(iGeomCol) && !poGeomFieldDefn->bHasCheckedSpatialIndexTable)
     {
-        bHasCheckedSpatialIndexTable = TRUE;
+        poGeomFieldDefn->bHasCheckedSpatialIndexTable = TRUE;
         char **papszResult;
         int nRowCount, nColCount;
         char *pszErrMsg = NULL;
@@ -565,7 +907,7 @@ int OGRSQLiteTableLayer::CheckSpatialIndexTable()
 
         /* This will ensure that RTree support is available */
         osSQL.Printf("SELECT pkid FROM 'idx_%s_%s' WHERE xmax > 0 AND xmin < 0 AND ymax > 0 AND ymin < 0",
-                     pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
+                     pszEscapedTableName, OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
 
         int  rc = sqlite3_get_table( poDS->GetDB(), osSQL.c_str(),
                                     &papszResult, &nRowCount,
@@ -574,9 +916,9 @@ int OGRSQLiteTableLayer::CheckSpatialIndexTable()
         if( rc != SQLITE_OK )
         {
             CPLDebug("SQLITE", "Count not find or use idx_%s_%s layer (%s). Disabling spatial index",
-                        pszEscapedTableName, pszGeomCol, pszErrMsg);
+                        pszEscapedTableName, poGeomFieldDefn->GetNameRef(), pszErrMsg);
             sqlite3_free( pszErrMsg );
-            bHasSpatialIndex = FALSE;
+            poGeomFieldDefn->bHasSpatialIndex = FALSE;
         }
         else
         {
@@ -584,7 +926,20 @@ int OGRSQLiteTableLayer::CheckSpatialIndexTable()
         }
     }
 
-    return bHasSpatialIndex;
+    return poGeomFieldDefn->bHasSpatialIndex;
+}
+
+/************************************************************************/
+/*                         HasFastSpatialFilter()                       */
+/************************************************************************/
+
+int OGRSQLiteTableLayer::HasFastSpatialFilter(int iGeomCol)
+{
+    OGRPolygon oFakePoly;
+    const char* pszWKT = "POLYGON((0 0,0 1,1 1,1 0,0 0))";
+    oFakePoly.importFromWkt((char**) &pszWKT);
+    CPLString    osSpatialWhere = GetSpatialWhere(iGeomCol, &oFakePoly);
+    return osSpatialWhere.find("ROWID") == 0;
 }
 
 /************************************************************************/
@@ -594,46 +949,26 @@ int OGRSQLiteTableLayer::CheckSpatialIndexTable()
 CPLString OGRSQLiteTableLayer::GetSpatialWhere(int iGeomCol,
                                                OGRGeometry* poFilterGeom)
 {
-    CPLString osSpatialWHERE;
-
-    if( !poDS->IsSpatialiteDB() || poFeatureDefn == NULL ||
-        iGeomCol < 0 || iGeomCol >= poFeatureDefn->GetGeomFieldCount() )
-        return osSpatialWHERE;
+    if( !poDS->IsSpatialiteDB() ||
+        iGeomCol < 0 || iGeomCol >= GetLayerDefn()->GetGeomFieldCount() )
+        return "";
 
-    if( poFilterGeom != NULL && CheckSpatialIndexTable() )
+    OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iGeomCol);
+    if( poFilterGeom != NULL && CheckSpatialIndexTable(iGeomCol) )
     {
-        OGREnvelope  sEnvelope;
-
-        CPLLocaleC  oLocaleEnforcer;
-
-        poFilterGeom->getEnvelope( &sEnvelope );
-
-        osSpatialWHERE.Printf("ROWID IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
-                        "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f)",
-                        pszEscapedTableName,
-                        OGRSQLiteEscape(poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()).c_str(),
-                        sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
-                        sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
+        return FormatSpatialFilterFromRTree(poFilterGeom, "ROWID",
+            pszEscapedTableName,
+            OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
     }
 
     if( poFilterGeom != NULL &&
-        poDS->IsSpatialiteLoaded() && !bHasSpatialIndex )
+        poDS->IsSpatialiteLoaded() && !poGeomFieldDefn->bHasSpatialIndex )
     {
-        OGREnvelope  sEnvelope;
-
-        CPLLocaleC  oLocaleEnforcer;
-
-        poFilterGeom->getEnvelope( &sEnvelope );
-
-        /* A bit inefficient but still faster than OGR filtering */
-        osSpatialWHERE.Printf("MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f, %d))",
-                       OGRSQLiteEscapeName(poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()).c_str(),
-                       sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11,
-                       sEnvelope.MaxX + 1e-11, sEnvelope.MaxY + 1e-11,
-                       nSRSId);
+        return FormatSpatialFilterFromMBR(poFilterGeom,
+            OGRSQLiteEscapeName(poGeomFieldDefn->GetNameRef()).c_str());
     }
 
-    return osSpatialWHERE;
+    return "";
 }
 
 /************************************************************************/
@@ -680,14 +1015,16 @@ int OGRSQLiteTableLayer::TestCapability( const char * pszCap )
 
 {
     if (EQUAL(pszCap,OLCFastFeatureCount))
-        return m_poFilterGeom == NULL || pszGeomCol == NULL ||
-               HasSpatialIndex();
+        return m_poFilterGeom == NULL || HasSpatialIndex(0);
 
     else if (EQUAL(pszCap,OLCFastSpatialFilter))
-        return HasSpatialIndex();
+        return HasSpatialIndex(0);
 
     else if( EQUAL(pszCap,OLCFastGetExtent) )
-        return bCachedExtentIsValid;
+    {
+        return GetLayerDefn()->GetGeomFieldCount() >= 1 &&
+               myGetLayerDefn()->myGetGeomFieldDefn(0)->bCachedExtentIsValid;
+    }
 
     else if( EQUAL(pszCap,OLCRandomRead) )
         return pszFIDColumn != NULL;
@@ -703,7 +1040,8 @@ int OGRSQLiteTableLayer::TestCapability( const char * pszCap )
         return poDS->GetUpdate() && pszFIDColumn != NULL;
     }
 
-    else if( EQUAL(pszCap,OLCCreateField) )
+    else if( EQUAL(pszCap,OLCCreateField) ||
+             EQUAL(pszCap,OLCCreateGeomField) )
         return poDS->GetUpdate();
 
     else if( EQUAL(pszCap,OLCDeleteField) )
@@ -715,6 +1053,9 @@ int OGRSQLiteTableLayer::TestCapability( const char * pszCap )
     else if( EQUAL(pszCap,OLCReorderFields) )
         return poDS->GetUpdate();
 
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return poDS->TestCapability(ODsCCurveGeometries);
+
     else 
         return OGRSQLiteLayer::TestCapability( pszCap );
 }
@@ -723,7 +1064,7 @@ int OGRSQLiteTableLayer::TestCapability( const char * pszCap )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRSQLiteTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRSQLiteTableLayer::GetFeatureCount( int bForce )
 
 {
     if (HasLayerDefnError())
@@ -743,17 +1084,20 @@ int OGRSQLiteTableLayer::GetFeatureCount( int bForce )
 /* -------------------------------------------------------------------- */
     const char *pszSQL;
 
-    if (m_poFilterGeom != NULL && CheckSpatialIndexTable() &&
+    if (m_poFilterGeom != NULL && CheckSpatialIndexTable(m_iGeomFieldFilter) &&
         strlen(osQuery) == 0)
     {
         OGREnvelope  sEnvelope;
 
         m_poFilterGeom->getEnvelope( &sEnvelope );
+        const char* pszGeomCol = poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef();
         pszSQL = CPLSPrintf("SELECT count(*) FROM 'idx_%s_%s' WHERE "
                             "xmax >= %.12f AND xmin <= %.12f AND ymax >= %.12f AND ymin <= %.12f",
                             pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str(),
-                            sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
-                            sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
+                            sEnvelope.MinX - 1e-11,
+                            sEnvelope.MaxX + 1e-11,
+                            sEnvelope.MinY - 1e-11,
+                            sEnvelope.MaxY + 1e-11);
     }
     else
     {
@@ -768,7 +1112,7 @@ int OGRSQLiteTableLayer::GetFeatureCount( int bForce )
 /* -------------------------------------------------------------------- */
     char **papszResult, *pszErrMsg;
     int nRowCount, nColCount;
-    int nResult = -1;
+    GIntBig nResult = -1;
 
     if( sqlite3_get_table( poDS->GetDB(), pszSQL, &papszResult, 
                            &nRowCount, &nColCount, &pszErrMsg ) != SQLITE_OK )
@@ -776,7 +1120,7 @@ int OGRSQLiteTableLayer::GetFeatureCount( int bForce )
 
     if( nRowCount == 1 && nColCount == 1 )
     {
-        nResult = atoi(papszResult[1]);
+        nResult = CPLAtoGIntBig(papszResult[1]);
 
         if( m_poFilterGeom == NULL && osQuery.size() == 0 )
         {
@@ -796,25 +1140,43 @@ int OGRSQLiteTableLayer::GetFeatureCount( int bForce )
 
 OGRErr OGRSQLiteTableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
 {
+    return GetExtent(0, psExtent, bForce);
+}
+
+OGRErr OGRSQLiteTableLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
+{
     if (HasLayerDefnError())
         return OGRERR_FAILURE;
 
-    if (GetGeomType() == wkbNone)
+/* -------------------------------------------------------------------- */
+/*      If this layer has a none geometry type, then we can             */
+/*      reasonably assume there are not extents available.              */
+/* -------------------------------------------------------------------- */
+    if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
+        GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
+    {
+        if( iGeomField != 0 )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                     "Invalid geometry field index : %d", iGeomField);
+        }
         return OGRERR_FAILURE;
+    }
 
-    if (bCachedExtentIsValid)
+    OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iGeomField);
+    if (poGeomFieldDefn->bCachedExtentIsValid)
     {
-        memcpy(psExtent, &oCachedExtent, sizeof(oCachedExtent));
+        memcpy(psExtent, &poGeomFieldDefn->oCachedExtent, sizeof(poGeomFieldDefn->oCachedExtent));
         return OGRERR_NONE;
     }
 
-    if (CheckSpatialIndexTable() &&
+    if (CheckSpatialIndexTable(iGeomField) &&
         !CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_EXACT_EXTENT", "NO")))
     {
         const char* pszSQL;
 
         pszSQL = CPLSPrintf("SELECT MIN(xmin), MIN(ymin), MAX(xmax), MAX(ymax) FROM 'idx_%s_%s'",
-                            pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
+                            pszEscapedTableName, OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str());
 
         CPLDebug("SQLITE", "Running %s", pszSQL);
 
@@ -836,17 +1198,17 @@ OGRErr OGRSQLiteTableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
             papszResult[4+2] != NULL &&
             papszResult[4+3] != NULL)
         {
-            psExtent->MinX = atof(papszResult[4+0]);
-            psExtent->MinY = atof(papszResult[4+1]);
-            psExtent->MaxX = atof(papszResult[4+2]);
-            psExtent->MaxY = atof(papszResult[4+3]);
+            psExtent->MinX = CPLAtof(papszResult[4+0]);
+            psExtent->MinY = CPLAtof(papszResult[4+1]);
+            psExtent->MaxX = CPLAtof(papszResult[4+2]);
+            psExtent->MaxY = CPLAtof(papszResult[4+3]);
             eErr = OGRERR_NONE;
 
             if( m_poFilterGeom == NULL && osQuery.size() == 0 )
             {
-                bCachedExtentIsValid = TRUE;
+                poGeomFieldDefn->bCachedExtentIsValid = TRUE;
                 bStatisticsNeedsToBeFlushed = TRUE;
-                memcpy(&oCachedExtent, psExtent, sizeof(oCachedExtent));
+                memcpy(&poGeomFieldDefn->oCachedExtent, psExtent, sizeof(poGeomFieldDefn->oCachedExtent));
             }
         }
 
@@ -856,12 +1218,16 @@ OGRErr OGRSQLiteTableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
             return eErr;
     }
 
-    OGRErr eErr = OGRSQLiteLayer::GetExtent(psExtent, bForce);
+    OGRErr eErr;
+    if( iGeomField == 0 )
+        eErr = OGRSQLiteLayer::GetExtent(psExtent, bForce);
+    else
+        eErr = OGRSQLiteLayer::GetExtent(iGeomField, psExtent, bForce);
     if( eErr == OGRERR_NONE && m_poFilterGeom == NULL && osQuery.size() == 0 )
     {
-        bCachedExtentIsValid = TRUE;
+        poGeomFieldDefn->bCachedExtentIsValid = TRUE;
         bStatisticsNeedsToBeFlushed = TRUE;
-        memcpy(&oCachedExtent, psExtent, sizeof(oCachedExtent));
+        memcpy(&poGeomFieldDefn->oCachedExtent, psExtent, sizeof(poGeomFieldDefn->oCachedExtent));
     }
     return eErr;
 }
@@ -870,12 +1236,27 @@ OGRErr OGRSQLiteTableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
 /*                  OGRSQLiteFieldDefnToSQliteFieldDefn()               */
 /************************************************************************/
 
-CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn )
+CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn,
+                                               int bSQLiteDialectInternalUse )
 {
     switch( poFieldDefn->GetType() )
     {
-        case OFTInteger: return "INTEGER"; break;
-        case OFTReal   : return "FLOAT"; break;
+        case OFTInteger:
+            if (poFieldDefn->GetSubType() == OFSTBoolean) 
+                return "INTEGER_BOOLEAN";
+            else if (poFieldDefn->GetSubType() == OFSTInt16 ) 
+                return "INTEGER_INT16";
+            else
+                return "INTEGER";
+            break;
+        case OFTInteger64:
+            return "BIGINT";
+        case OFTReal:
+            if (bSQLiteDialectInternalUse && poFieldDefn->GetSubType() == OFSTFloat32) 
+                return "FLOAT_FLOAT32";
+            else
+                return "FLOAT";
+            break;
         case OFTBinary : return "BLOB"; break;
         case OFTString :
         {
@@ -888,6 +1269,30 @@ CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn )
         case OFTDateTime: return "TIMESTAMP"; break;
         case OFTDate    : return "DATE"; break;
         case OFTTime    : return "TIME"; break;
+        case OFTIntegerList:
+            if (bSQLiteDialectInternalUse )
+                return "INTEGERLIST";
+            else
+                return "VARCHAR";
+            break;
+        case OFTInteger64List:
+            if (bSQLiteDialectInternalUse )
+                return "INTEGER64LIST";
+            else
+                return "VARCHAR";
+            break;
+        case OFTRealList:
+            if (bSQLiteDialectInternalUse )
+                return "REALLIST";
+            else
+                return "VARCHAR";
+            break;
+        case OFTStringList:
+            if (bSQLiteDialectInternalUse )
+                return "STRINGLIST";
+            else
+                return "VARCHAR";
+            break;
         default         : return "VARCHAR"; break;
     }
 }
@@ -898,7 +1303,7 @@ CPLString OGRSQLiteFieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn )
 
 CPLString OGRSQLiteTableLayer::FieldDefnToSQliteFieldDefn( OGRFieldDefn* poFieldDefn )
 {
-    CPLString osRet = OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn);
+    CPLString osRet = OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn, FALSE);
     if( poFieldDefn->GetType() == OFTString &&
         CSLFindString(papszCompressedColumns, poFieldDefn->GetNameRef()) >= 0 )
         osRet += "_deflate";
@@ -910,7 +1315,7 @@ CPLString OGRSQLiteTableLayer::FieldDefnToSQliteFieldDefn( OGRFieldDefn* poField
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRSQLiteTableLayer::CreateField( OGRFieldDefn *poFieldIn, 
+OGRErr OGRSQLiteTableLayer::CreateField( OGRFieldDefn *poFieldIn,
                                          CPL_UNUSED int bApproxOK )
 {
     OGRFieldDefn        oField( poFieldIn );
@@ -918,8 +1323,6 @@ OGRErr OGRSQLiteTableLayer::CreateField( OGRFieldDefn *poFieldIn,
     if (HasLayerDefnError())
         return OGRERR_FAILURE;
 
-    ResetReading();
-
     if (!poDS->GetUpdate())
     {
         CPLError( CE_Failure, CPLE_NotSupported,
@@ -927,6 +1330,16 @@ OGRErr OGRSQLiteTableLayer::CreateField( OGRFieldDefn *poFieldIn,
                   "CreateField");
         return OGRERR_FAILURE;
     }
+    
+    if( pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) &&
+        oField.GetType() != OFTInteger &&
+        oField.GetType() != OFTInteger64 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
+                 oField.GetNameRef());
+        return CE_Failure;
+    }
 
     ClearInsertStmt();
     
@@ -959,50 +1372,286 @@ OGRErr OGRSQLiteTableLayer::CreateField( OGRFieldDefn *poFieldIn,
         oField.SetType(OFTString);
     }
 
-    /* ADD COLUMN only avaliable since sqlite 3.1.3 */
-    if (CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_USE_ADD_COLUMN", "YES")) &&
-        sqlite3_libversion_number() > 3 * 1000000 + 1 * 1000 + 3)
+    if( !bDeferredCreation )
     {
-        int rc;
-        char *pszErrMsg = NULL;
-        sqlite3 *hDB = poDS->GetDB();
-        CPLString osCommand;
+        /* ADD COLUMN only avaliable since sqlite 3.1.3 */
+        if (CSLTestBoolean(CPLGetConfigOption("OGR_SQLITE_USE_ADD_COLUMN", "YES")) &&
+            sqlite3_libversion_number() > 3 * 1000000 + 1 * 1000 + 3)
+        {
+            int rc;
+            char *pszErrMsg = NULL;
+            sqlite3 *hDB = poDS->GetDB();
+            CPLString osCommand;
+
+            CPLString osFieldType(FieldDefnToSQliteFieldDefn(&oField));
+            osCommand.Printf("ALTER TABLE '%s' ADD COLUMN '%s' %s",
+                            pszEscapedTableName,
+                            OGRSQLiteEscape(oField.GetNameRef()).c_str(),
+                            osFieldType.c_str());
+            if( !oField.IsNullable() )
+            {
+                osCommand += " NOT NULL";
+            }
+            if( oField.GetDefault() != NULL && !oField.IsDefaultDriverSpecific() )
+            {
+                osCommand += " DEFAULT ";
+                osCommand += oField.GetDefault();
+            }
+            else if( !oField.IsNullable() )
+            {
+                // This is kind of dumb, but SQLite mandates a DEFAULT value
+                // when adding a NOT NULL column in an ALTER TABLE ADD COLUMN
+                // statement, which defeats the purpose of NOT NULL,
+                // whereas it doesn't in CREATE TABLE
+                osCommand += " DEFAULT ''";
+            }
 
-        CPLString osFieldType(FieldDefnToSQliteFieldDefn(&oField));
-        osCommand.Printf("ALTER TABLE '%s' ADD COLUMN '%s' %s",
-                        pszEscapedTableName,
-                        OGRSQLiteEscape(oField.GetNameRef()).c_str(),
-                        osFieldType.c_str());
+        #ifdef DEBUG
+            CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
+        #endif
 
-    #ifdef DEBUG
+            rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
+            if( rc != SQLITE_OK )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "Failed to add field %s to table %s:\n %s",
+                        oField.GetNameRef(), poFeatureDefn->GetName(), 
+                        pszErrMsg );
+                sqlite3_free( pszErrMsg );
+                return OGRERR_FAILURE;
+            }
+        }
+        else
+        {
+            OGRErr eErr = AddColumnAncientMethod(oField);
+            if (eErr != OGRERR_NONE)
+                return eErr;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Add the field to the OGRFeatureDefn.                            */
+/* -------------------------------------------------------------------- */
+    poFeatureDefn->AddFieldDefn( &oField );
+
+    if( pszFIDColumn != NULL &&
+        EQUAL( oField.GetNameRef(), pszFIDColumn ) )
+    {
+        iFIDAsRegularColumnIndex = poFeatureDefn->GetFieldCount() - 1;
+    }
+
+    if( !bDeferredCreation )
+        RecomputeOrdinals();
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           CreateGeomField()                          */
+/************************************************************************/
+
+OGRErr OGRSQLiteTableLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
+                                             CPL_UNUSED int bApproxOK )
+{
+    OGRwkbGeometryType eType = poGeomFieldIn->GetType();
+    if( eType == wkbNone )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined,
+                 "Cannot create geometry field of type wkbNone");
+        return OGRERR_FAILURE;
+    }
+    
+    OGRSQLiteGeomFieldDefn *poGeomField =
+        new OGRSQLiteGeomFieldDefn( poGeomFieldIn->GetNameRef(), -1 );
+    if( EQUAL(poGeomField->GetNameRef(), "") )
+    {
+        if( poFeatureDefn->GetGeomFieldCount() == 0 )
+            poGeomField->SetName( "GEOMETRY" );
+        else
+            poGeomField->SetName(
+                CPLSPrintf("GEOMETRY%d", poFeatureDefn->GetGeomFieldCount()+1) );
+    }
+    poGeomField->SetSpatialRef(poGeomFieldIn->GetSpatialRef());
+
+/* -------------------------------------------------------------------- */
+/*      Do we want to "launder" the column names into Postgres          */
+/*      friendly format?                                                */
+/* -------------------------------------------------------------------- */
+    if( bLaunderColumnNames )
+    {
+        char    *pszSafeName = poDS->LaunderName( poGeomField->GetNameRef() );
+
+        poGeomField->SetName( pszSafeName );
+        CPLFree( pszSafeName );
+    }
+
+    OGRSpatialReference* poSRS = poGeomField->GetSpatialRef();
+    int nSRSId = -1;
+    if( poSRS != NULL )
+        nSRSId = poDS->FetchSRSId( poSRS );
+
+    poGeomField->SetType(eType);
+    poGeomField->SetNullable( poGeomFieldIn->IsNullable() );
+    poGeomField->nSRSId = nSRSId;
+    if( poDS->IsSpatialiteDB() )
+        poGeomField->eGeomFormat = OSGF_SpatiaLite;
+    else if( pszCreationGeomFormat )
+        poGeomField->eGeomFormat = GetGeomFormat(pszCreationGeomFormat);
+    else
+        poGeomField->eGeomFormat = OSGF_WKB ;
+
+/* -------------------------------------------------------------------- */
+/*      Create the new field.                                           */
+/* -------------------------------------------------------------------- */
+    if( !bDeferredCreation )
+    {
+        if( RunAddGeometryColumn(poGeomField, TRUE) != OGRERR_NONE )
+        {
+            delete poGeomField;
+
+            return OGRERR_FAILURE;
+        }
+    }
+
+    poFeatureDefn->AddGeomFieldDefn( poGeomField, FALSE );
+
+    if( !bDeferredCreation )
+        RecomputeOrdinals();
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                        RunAddGeometryColumn()                        */
+/************************************************************************/
+
+OGRErr OGRSQLiteTableLayer::RunAddGeometryColumn( OGRSQLiteGeomFieldDefn *poGeomFieldDefn,
+                                                  int bAddColumnsForNonSpatialite )
+{
+    OGRwkbGeometryType eType = poGeomFieldDefn->GetType();
+    int nCoordDim;
+    const char* pszGeomCol = poGeomFieldDefn->GetNameRef();
+    int nSRSId = poGeomFieldDefn->nSRSId;
+    CPLString osCommand;
+    char* pszErrMsg = NULL;
+
+    if( eType == wkbFlatten(eType) )
+        nCoordDim = 2;
+    else
+        nCoordDim = 3;
+
+    if( bAddColumnsForNonSpatialite && !poDS->IsSpatialiteDB() )
+    {
+        osCommand = CPLSPrintf("ALTER TABLE '%s' ADD COLUMN ",
+                               pszEscapedTableName );
+        if( poGeomFieldDefn->eGeomFormat == OSGF_WKT )
+        {
+            osCommand += CPLSPrintf(" '%s' VARCHAR", 
+                OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str() );
+        }
+        else
+        {
+            osCommand += CPLSPrintf(" '%s' BLOB", 
+                OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str() );
+        }
+        if( !poGeomFieldDefn->IsNullable() )
+            osCommand += " NOT NULL DEFAULT ''";
+
+#ifdef DEBUG
         CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
-    #endif
+#endif
 
-        rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
+        int rc = sqlite3_exec( poDS->GetDB(), osCommand, NULL, NULL, &pszErrMsg );
         if( rc != SQLITE_OK )
         {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                      "Failed to add field %s to table %s:\n %s",
-                      oField.GetNameRef(), poFeatureDefn->GetName(), 
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "Unable to geometry field:\n%s",
                       pszErrMsg );
             sqlite3_free( pszErrMsg );
             return OGRERR_FAILURE;
         }
     }
+
+    if ( poDS->IsSpatialiteDB() )
+    {
+        /*
+        / SpatiaLite full support: calling AddGeometryColumn()
+        /
+        / IMPORTANT NOTICE: on SpatiaLite any attempt aimed
+        / to directly INSERT a row into GEOMETRY_COLUMNS
+        / [by-passing AddGeometryColumn() as absolutely required]
+        / will severely [and irremediably] corrupt the DB !!!
+        */
+        const char *pszType = OGRToOGCGeomType(eType);
+        if (pszType[0] == '\0')
+            pszType = "GEOMETRY";
+
+        /*
+        / SpatiaLite v.2.4.0 (or any subsequent) is required
+        / to support 2.5D: if an obsolete version of the library
+        / is found we'll unconditionally activate 2D casting mode
+        */
+        int iSpatialiteVersion = poDS->GetSpatialiteVersionNumber();
+        if ( iSpatialiteVersion < 24 && nCoordDim == 3 )
+        {
+            CPLDebug("SQLITE", "Spatialite < 2.4.0 --> 2.5D geometry not supported. Casting to 2D");
+            nCoordDim = 2;
+        }
+
+        osCommand.Printf( "SELECT AddGeometryColumn("
+                        "'%s', '%s', %d, '%s', %d",
+                        pszEscapedTableName,
+                        OGRSQLiteEscape(pszGeomCol).c_str(), nSRSId,
+                        pszType, nCoordDim );
+        if( iSpatialiteVersion >= 30 && !poGeomFieldDefn->IsNullable() )
+            osCommand += ", 1";
+        osCommand += ")";
+    }
     else
     {
-        OGRErr eErr = AddColumnAncientMethod(oField);
-        if (eErr != OGRERR_NONE)
-            return eErr;
+        const char* pszGeomFormat =
+            (poGeomFieldDefn->eGeomFormat == OSGF_WKT ) ? "WKT" :
+            (poGeomFieldDefn->eGeomFormat == OSGF_WKB ) ? "WKB" :
+            (poGeomFieldDefn->eGeomFormat == OSGF_FGF ) ? "FGF" :
+                                                            "Spatialite";
+        if( nSRSId > 0 )
+        {
+            osCommand.Printf(
+                "INSERT INTO geometry_columns "
+                "(f_table_name, f_geometry_column, geometry_format, "
+                "geometry_type, coord_dimension, srid) VALUES "
+                "('%s','%s','%s', %d, %d, %d)", 
+                pszEscapedTableName,
+                OGRSQLiteEscape(pszGeomCol).c_str(), pszGeomFormat,
+                (int) wkbFlatten(eType), nCoordDim, nSRSId );
+        }
+        else
+        {
+            osCommand.Printf(
+                "INSERT INTO geometry_columns "
+                "(f_table_name, f_geometry_column, geometry_format, "
+                "geometry_type, coord_dimension) VALUES "
+                "('%s','%s','%s', %d, %d)",
+                pszEscapedTableName,
+                OGRSQLiteEscape(pszGeomCol).c_str(), pszGeomFormat,
+                (int) wkbFlatten(eType), nCoordDim );
+        }
     }
 
-/* -------------------------------------------------------------------- */
-/*      Add the field to the OGRFeatureDefn.                            */
-/* -------------------------------------------------------------------- */
-    poFeatureDefn->AddFieldDefn( &oField );
-
-    RecomputeOrdinals();
+#ifdef DEBUG
+    CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
+#endif
 
+    int rc = sqlite3_exec( poDS->GetDB(), osCommand, NULL, NULL, &pszErrMsg );
+    if( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Unable to geometry field:\n%s",
+                  pszErrMsg );
+        sqlite3_free( pszErrMsg );
+        return OGRERR_FAILURE;
+    }
+    
     return OGRERR_NONE;
 }
 
@@ -1018,14 +1667,17 @@ void OGRSQLiteTableLayer::InitFieldListForRecrerate(char* & pszNewFieldList,
 
     for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
+        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
         nFieldListLen +=
-            2 * strlen(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()) + 50;
+            2 * strlen(poFieldDefn->GetNameRef()) + 70;
+        if( poFieldDefn->GetDefault() != NULL )
+            nFieldListLen += 10 + strlen( poFieldDefn->GetDefault() );
     }
 
     nFieldListLen += 50 + (pszFIDColumn ? 2 * strlen(pszFIDColumn) : strlen("OGC_FID"));
-    if( poFeatureDefn->GetGeomType() != wkbNone )
+    for( iField = 0; iField < poFeatureDefn->GetGeomFieldCount(); iField++ )
     {
-        nFieldListLen += 50 + 2 * strlen(pszGeomCol);
+        nFieldListLen += 70 + 2 * strlen(poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
     }
 
     pszFieldListForSelect = (char *) CPLCalloc(1,nFieldListLen);
@@ -1037,23 +1689,45 @@ void OGRSQLiteTableLayer::InitFieldListForRecrerate(char* & pszNewFieldList,
     sprintf( pszFieldListForSelect, "\"%s\"", pszFIDColumn ? OGRSQLiteEscapeName(pszFIDColumn).c_str() : "OGC_FID" );
     sprintf( pszNewFieldList, "\"%s\" INTEGER PRIMARY KEY",pszFIDColumn ? OGRSQLiteEscapeName(pszFIDColumn).c_str() : "OGC_FID" );
 
-    if( poFeatureDefn->GetGeomType() != wkbNone )
+    for( iField = 0; iField < poFeatureDefn->GetGeomFieldCount(); iField++ )
     {
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iField);
         strcat( pszFieldListForSelect, "," );
         strcat( pszNewFieldList, "," );
 
         strcat( pszFieldListForSelect, "\"");
-        strcat( pszFieldListForSelect, OGRSQLiteEscapeName(pszGeomCol) );
+        strcat( pszFieldListForSelect, OGRSQLiteEscapeName(poGeomFieldDefn->GetNameRef()) );
         strcat( pszFieldListForSelect, "\"");
         
         strcat( pszNewFieldList, "\"");
-        strcat( pszNewFieldList, OGRSQLiteEscapeName(pszGeomCol) );
+        strcat( pszNewFieldList, OGRSQLiteEscapeName(poGeomFieldDefn->GetNameRef()) );
         strcat( pszNewFieldList, "\"");
 
-        if ( eGeomFormat == OSGF_WKT )
+        if ( poGeomFieldDefn->eGeomFormat == OSGF_WKT )
             strcat( pszNewFieldList, " VARCHAR" );
         else
             strcat( pszNewFieldList, " BLOB" );
+        if( !poGeomFieldDefn->IsNullable() )
+            strcat( pszNewFieldList, " NOT NULL" );
+    }
+}
+
+/************************************************************************/
+/*                         AddColumnDef()                               */
+/************************************************************************/
+
+void OGRSQLiteTableLayer::AddColumnDef(char* pszNewFieldList,
+                                       OGRFieldDefn* poFldDefn)
+{
+    sprintf( pszNewFieldList+strlen(pszNewFieldList), 
+             ", '%s' %s", OGRSQLiteEscape(poFldDefn->GetNameRef()).c_str(),
+             FieldDefnToSQliteFieldDefn(poFldDefn).c_str() );
+    if( !poFldDefn->IsNullable() )
+        sprintf( pszNewFieldList+strlen(pszNewFieldList), " NOT NULL" );
+    if( poFldDefn->GetDefault() != NULL && !poFldDefn->IsDefaultDriverSpecific() )
+    {
+        sprintf( pszNewFieldList+strlen(pszNewFieldList), " DEFAULT %s",
+                 poFldDefn->GetDefault() );
     }
 }
 
@@ -1079,10 +1753,7 @@ OGRErr OGRSQLiteTableLayer::AddColumnAncientMethod( OGRFieldDefn& oField)
 
     int iNextOrdinal = 3; /* _rowid_ is 1, OGC_FID is 2 */
 
-    if( poFeatureDefn->GetGeomType() != wkbNone )
-    {
-        iNextOrdinal++;
-    }
+    iNextOrdinal += poFeatureDefn->GetGeomFieldCount();
 
     for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
@@ -1095,9 +1766,7 @@ OGRErr OGRSQLiteTableLayer::AddColumnAncientMethod( OGRFieldDefn& oField)
         sprintf( pszOldFieldList+strlen(pszOldFieldList), 
                  ", \"%s\"", OGRSQLiteEscapeName(poFldDefn->GetNameRef()).c_str() );
 
-        sprintf( pszNewFieldList+strlen(pszNewFieldList), 
-                 ", '%s' %s", OGRSQLiteEscape(poFldDefn->GetNameRef()).c_str(),
-                 FieldDefnToSQliteFieldDefn(poFldDefn).c_str() );
+        AddColumnDef(pszNewFieldList, poFldDefn);
 
         iNextOrdinal++;
     }
@@ -1105,10 +1774,7 @@ OGRErr OGRSQLiteTableLayer::AddColumnAncientMethod( OGRFieldDefn& oField)
 /* -------------------------------------------------------------------- */
 /*      Add the new field.                                              */
 /* -------------------------------------------------------------------- */
-
-    sprintf( pszNewFieldList+strlen(pszNewFieldList), 
-             ", '%s' %s", OGRSQLiteEscape(oField.GetNameRef()).c_str(),
-             FieldDefnToSQliteFieldDefn(&oField).c_str() );
+    AddColumnDef(pszNewFieldList, &oField);
 
 /* ==================================================================== */
 /*      Backup, destroy, recreate and repopulate the table.  SQLite     */
@@ -1224,7 +1890,7 @@ OGRErr OGRSQLiteTableLayer::AddColumnAncientMethod( OGRFieldDefn& oField)
 
     if( rc == SQLITE_OK )
     {
-        poDS->SoftCommit();
+        poDS->SoftCommitTransaction();
     }
     else
     {
@@ -1234,7 +1900,7 @@ OGRErr OGRSQLiteTableLayer::AddColumnAncientMethod( OGRFieldDefn& oField)
                   pszErrMsg );
         sqlite3_free( pszErrMsg );
 
-        poDS->SoftRollback();
+        poDS->SoftRollbackTransaction();
 
         return OGRERR_FAILURE;
     }
@@ -1335,7 +2001,7 @@ OGRErr OGRSQLiteTableLayer::RecreateTable(const char* pszFieldListForSelect,
 
     if( rc == SQLITE_OK )
     {
-        poDS->SoftCommit();
+        poDS->SoftCommitTransaction();
 
         return OGRERR_NONE;
     }
@@ -1347,7 +2013,7 @@ OGRErr OGRSQLiteTableLayer::RecreateTable(const char* pszFieldListForSelect,
                   pszErrMsg );
         sqlite3_free( pszErrMsg );
 
-        poDS->SoftRollback();
+        poDS->SoftRollbackTransaction();
 
         return OGRERR_FAILURE;
     }
@@ -1396,9 +2062,7 @@ OGRErr OGRSQLiteTableLayer::DeleteField( int iFieldToDelete )
         sprintf( pszFieldListForSelect+strlen(pszFieldListForSelect),
                  ", \"%s\"", OGRSQLiteEscapeName(poFldDefn->GetNameRef()).c_str() );
 
-        sprintf( pszNewFieldList+strlen(pszNewFieldList),
-                 ", '%s' %s", OGRSQLiteEscape(poFldDefn->GetNameRef()).c_str(),
-                 FieldDefnToSQliteFieldDefn(poFldDefn).c_str() );
+        AddColumnDef(pszNewFieldList, poFldDefn);
     }
 
 /* -------------------------------------------------------------------- */
@@ -1462,7 +2126,10 @@ OGRErr OGRSQLiteTableLayer::AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poN
     int iField;
     char *pszNewFieldList, *pszFieldListForSelect;
     InitFieldListForRecrerate(pszNewFieldList, pszFieldListForSelect,
-                              strlen(poNewFieldDefn->GetNameRef()));
+                              strlen(poNewFieldDefn->GetNameRef()) +
+                              50 +
+                              (poNewFieldDefn->GetDefault() ? strlen(poNewFieldDefn->GetDefault()) : 0)
+                              );
 
     for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
     {
@@ -1483,6 +2150,14 @@ OGRErr OGRSQLiteTableLayer::AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poN
                 oTmpFieldDefn.SetWidth(poNewFieldDefn->GetWidth());
                 oTmpFieldDefn.SetPrecision(poNewFieldDefn->GetPrecision());
             }
+            if( (nFlags & ALTER_NULLABLE_FLAG) )
+            {
+                oTmpFieldDefn.SetNullable(poNewFieldDefn->IsNullable());
+            }
+            if( (nFlags & ALTER_DEFAULT_FLAG) )
+            {
+                oTmpFieldDefn.SetDefault(poNewFieldDefn->GetDefault());
+            }
 
             sprintf( pszNewFieldList+strlen(pszNewFieldList),
                     ", '%s' %s",
@@ -1494,12 +2169,17 @@ OGRErr OGRSQLiteTableLayer::AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poN
             {
                 sprintf( pszNewFieldList+strlen(pszNewFieldList), "_deflate");
             }
+            if( !oTmpFieldDefn.IsNullable() )
+                sprintf( pszNewFieldList+strlen(pszNewFieldList), " NOT NULL" );
+            if( oTmpFieldDefn.GetDefault() )
+            {
+                sprintf( pszNewFieldList+strlen(pszNewFieldList), " DEFAULT %s",
+                         oTmpFieldDefn.GetDefault());
+            }
         }
         else
         {
-            sprintf( pszNewFieldList+strlen(pszNewFieldList),
-                    ", '%s' %s", OGRSQLiteEscape(poFldDefn->GetNameRef()).c_str(),
-                    FieldDefnToSQliteFieldDefn(poFldDefn).c_str() );
+            AddColumnDef(pszNewFieldList, poFldDefn);
         }
     }
 
@@ -1556,6 +2236,11 @@ OGRErr OGRSQLiteTableLayer::AlterFieldDefn( int iFieldToAlter, OGRFieldDefn* poN
         poFieldDefn->SetWidth(poNewFieldDefn->GetWidth());
         poFieldDefn->SetPrecision(poNewFieldDefn->GetPrecision());
     }
+    if (nFlags & ALTER_NULLABLE_FLAG)
+        poFieldDefn->SetNullable(poNewFieldDefn->IsNullable());
+    if (nFlags & ALTER_DEFAULT_FLAG)
+        poFieldDefn->SetDefault(poNewFieldDefn->GetDefault());
+
     return OGRERR_NONE;
 }
 
@@ -1600,9 +2285,7 @@ OGRErr OGRSQLiteTableLayer::ReorderFields( int* panMap )
         sprintf( pszFieldListForSelect+strlen(pszFieldListForSelect),
                  ", \"%s\"", OGRSQLiteEscapeName(poFldDefn->GetNameRef()).c_str() );
 
-        sprintf( pszNewFieldList+strlen(pszNewFieldList),
-                ", '%s' %s", OGRSQLiteEscape(poFldDefn->GetNameRef()).c_str(),
-                FieldDefnToSQliteFieldDefn(poFldDefn).c_str() );
+        AddColumnDef(pszNewFieldList, poFldDefn);
     }
 
 /* -------------------------------------------------------------------- */
@@ -1651,11 +2334,16 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
 /*      Bind the geometry                                               */
 /* -------------------------------------------------------------------- */
     int nBindField = 1;
-
-    if( poFeatureDefn->GetGeomFieldCount() != 0 &&
-        eGeomFormat != OSGF_FGF )
+    int iField;
+    int nFieldCount = poFeatureDefn->GetGeomFieldCount();
+    for( iField = 0; iField < nFieldCount; iField++ )
     {
-        OGRGeometry* poGeom = poFeature->GetGeometryRef();
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+            poFeatureDefn->myGetGeomFieldDefn(iField);
+        OGRSQLiteGeomFormat eGeomFormat = poGeomFieldDefn->eGeomFormat;
+        if( eGeomFormat == OSGF_FGF )
+            continue;
+        OGRGeometry* poGeom = poFeature->GetGeomFieldRef(iField);
         if ( poGeom != NULL )
         {
             if ( eGeomFormat == OSGF_WKT )
@@ -1677,9 +2365,8 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
                 int     nBLOBLen;
                 GByte   *pabySLBLOB;
 
-                if( nSRSId == UNINITIALIZED_SRID )
-                    nSRSId = poDS->GetUndefinedSRID();
-
+                int nSRSId = poGeomFieldDefn->nSRSId;
+                int bHasM = poGeomFieldDefn->bHasM;
                 ExportSpatiaLiteGeometry( poGeom, nSRSId, wkbNDR, bHasM,
                                         bSpatialite2D, bUseComprGeom, &pabySLBLOB, &nBLOBLen );
                 rc = sqlite3_bind_blob( hStmt, nBindField++, pabySLBLOB,
@@ -1711,11 +2398,12 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
 /* -------------------------------------------------------------------- */
 /*      Bind field values.                                              */
 /* -------------------------------------------------------------------- */
-    int iField;
-    int nFieldCount = poFeatureDefn->GetFieldCount();
+    nFieldCount = poFeatureDefn->GetFieldCount();
     for( iField = 0; iField < nFieldCount; iField++ )
     {
         const char *pszRawValue;
+        if( iField == iFIDAsRegularColumnIndex )
+            continue;
 
         if( !poFeature->IsFieldSet( iField ) )
         {
@@ -1726,7 +2414,8 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
         }
         else
         {
-            switch( poFeatureDefn->GetFieldDefn(iField)->GetType() )
+            OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
+            switch( poFieldDefn->GetType() )
             {
                 case OFTInteger:
                 {
@@ -1734,6 +2423,13 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
                     rc = sqlite3_bind_int(hStmt, nBindField++, nFieldVal);
                     break;
                 }
+                
+                case OFTInteger64:
+                {
+                    GIntBig nFieldVal = poFeature->GetFieldAsInteger64( iField );
+                    rc = sqlite3_bind_int64(hStmt, nBindField++, nFieldVal);
+                    break;
+                }
 
                 case OFTReal:
                 {
@@ -1754,14 +2450,10 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
 
                 case OFTDateTime:
                 {
-                    int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ;
-                    poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
-                                                &nHour, &nMinute, &nSecond, &nTZ);
-                    char szBuffer[64];
-                    sprintf(szBuffer, "%04d-%02d-%02dT%02d:%02d:%02d",
-                            nYear, nMonth, nDay, nHour, nMinute, nSecond);
+                    char* pszStr = OGRGetXMLDateTime(poFeature->GetRawFieldRef(iField));
                     rc = sqlite3_bind_text(hStmt, nBindField++,
-                                           szBuffer, -1, SQLITE_TRANSIENT);
+                                           pszStr, -1, SQLITE_TRANSIENT);
+                    CPLFree(pszStr);
                     break;
                 }
 
@@ -1779,11 +2471,15 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
 
                 case OFTTime:
                 {
-                    int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ;
+                    int nYear, nMonth, nDay, nHour, nMinute, nTZ;
+                    float fSecond;
                     poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
-                                                &nHour, &nMinute, &nSecond, &nTZ);
+                                                &nHour, &nMinute, &fSecond, &nTZ );
                     char szBuffer[64];
-                    sprintf(szBuffer, "%02d:%02d:%02d", nHour, nMinute, nSecond);
+                    if( OGR_GET_MS(fSecond) != 0 )
+                        sprintf(szBuffer, "%02d:%02d:%06.3f", nHour, nMinute, fSecond);
+                    else
+                        sprintf(szBuffer, "%02d:%02d:%02d", nHour, nMinute, (int)fSecond);
                     rc = sqlite3_bind_text(hStmt, nBindField++,
                                            szBuffer, -1, SQLITE_TRANSIENT);
                     break;
@@ -1851,10 +2547,10 @@ OGRErr OGRSQLiteTableLayer::BindValues( OGRFeature *poFeature,
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRSQLiteTableLayer::ISetFeature( OGRFeature *poFeature )
 
 {
     if (HasLayerDefnError())
@@ -1882,6 +2578,21 @@ OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
+    /* In case the FID column has also been created as a regular field */
+    if( iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( !poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) ||
+            poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined,
+                        "Inconsistant values of FID and field of same name");
+            return CE_Failure;
+        }
+    }
+
+    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
     sqlite3 *hDB = poDS->GetDB();
     CPLString      osCommand;
     int            bNeedComma = FALSE;
@@ -1896,11 +2607,17 @@ OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
 /*      Add geometry field name.                                        */
 /* -------------------------------------------------------------------- */
-    if( poFeatureDefn->GetGeomFieldCount() != 0 &&
-        eGeomFormat != OSGF_FGF )
+    int iField;
+    int nFieldCount = poFeatureDefn->GetGeomFieldCount();
+    for( iField = 0; iField < nFieldCount; iField++ )
     {
+        OGRSQLiteGeomFormat eGeomFormat =
+            poFeatureDefn->myGetGeomFieldDefn(iField)->eGeomFormat;
+        if( eGeomFormat == OSGF_FGF )
+            continue;
+
         osCommand += "\"";
-        osCommand += OGRSQLiteEscapeName(pszGeomCol);
+        osCommand += OGRSQLiteEscapeName( poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
         osCommand += "\" = ?";
 
         bNeedComma = TRUE;
@@ -1909,11 +2626,11 @@ OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
 /*      Add field names.                                                */
 /* -------------------------------------------------------------------- */
-    int iField;
-    int nFieldCount = poFeatureDefn->GetFieldCount();
-
+    nFieldCount = poFeatureDefn->GetFieldCount();
     for( iField = 0; iField < nFieldCount; iField++ )
     {
+        if( iField == iFIDAsRegularColumnIndex )
+            continue;
         if( bNeedComma )
             osCommand += ",";
 
@@ -1932,7 +2649,7 @@ OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
     osCommand += " WHERE \"";
     osCommand += OGRSQLiteEscapeName(pszFIDColumn);
-    osCommand += CPLSPrintf("\" = %ld", poFeature->GetFID());
+    osCommand += CPLSPrintf("\" = " CPL_FRMT_GIB, poFeature->GetFID());
 
 /* -------------------------------------------------------------------- */
 /*      Prepare the statement.                                          */
@@ -1981,29 +2698,59 @@ OGRErr OGRSQLiteTableLayer::SetFeature( OGRFeature *poFeature )
 
     sqlite3_finalize( hUpdateStmt );
 
-    OGRGeometry *poGeom = poFeature->GetGeometryRef();
-    if( bCachedExtentIsValid &&
-        poGeom != NULL && !poGeom->IsEmpty() )
+    eErr = (sqlite3_changes(hDB) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
+    if( eErr == OGRERR_NONE )
     {
-        OGREnvelope sGeomEnvelope;
-        poGeom->getEnvelope(&sGeomEnvelope);
-        oCachedExtent.Merge(sGeomEnvelope);
+        nFieldCount = poFeatureDefn->GetGeomFieldCount();
+        for( iField = 0; iField < nFieldCount; iField++ )
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn = 
+                poFeatureDefn->myGetGeomFieldDefn(iField);
+            OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
+            if( poGeomFieldDefn->bCachedExtentIsValid &&
+                poGeom != NULL && !poGeom->IsEmpty() )
+            {
+                OGREnvelope sGeomEnvelope;
+                poGeom->getEnvelope(&sGeomEnvelope);
+                poGeomFieldDefn->oCachedExtent.Merge(sGeomEnvelope);
+            }
+        }
+        bStatisticsNeedsToBeFlushed = TRUE;
     }
-    bStatisticsNeedsToBeFlushed = TRUE;
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                          AreTriggersSimilar                          */
 /************************************************************************/
 
-OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
+static int AreTriggersSimilar(const char* pszExpectedTrigger,
+                              const char* pszTriggerSQL)
+{
+    int i;
+    for(i=0; pszTriggerSQL[i] != '\0' && pszExpectedTrigger[i] != '\0'; i++)
+    {
+        if( pszTriggerSQL[i] == pszExpectedTrigger[i] )
+            continue;
+        if( pszTriggerSQL[i] == '\n' && pszExpectedTrigger[i] == ' ' )
+            continue;
+        if( pszTriggerSQL[i] == ' ' && pszExpectedTrigger[i] == '\n' )
+            continue;
+        return FALSE;
+    }
+    return pszTriggerSQL[i] == '\0' && pszExpectedTrigger[i] == '\0';
+}
+
+/************************************************************************/
+/*                          ICreateFeature()                            */
+/************************************************************************/
+
+OGRErr OGRSQLiteTableLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     sqlite3 *hDB = poDS->GetDB();
     CPLString      osCommand;
-    CPLString      osValues;
     int            bNeedComma = FALSE;
 
     if (HasLayerDefnError())
@@ -2017,102 +2764,298 @@ OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
         return OGRERR_FAILURE;
     }
 
+    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    // For speed-up, disable Spatialite triggers that :
+    // * check the geometry type
+    // * update the last_insert columns in geometry_columns_time and the spatial index
+    // We do that only if there's no spatial index currently active
+    // We'll check ourselves the first constraint and update last_insert
+    // at layer closing
+    if( !bHasCheckedTriggers &&
+        poDS->HasSpatialite4Layout() && poFeatureDefn->GetGeomFieldCount() > 0 )
+    {
+        bHasCheckedTriggers = TRUE;
+
+        char* pszErrMsg = NULL;
+
+        // Backup INSERT ON triggers
+        int nRowCount = 0, nColCount = 0;
+        char **papszResult = NULL;
+        char* pszSQL3 = sqlite3_mprintf("SELECT name, sql FROM sqlite_master WHERE "
+            "tbl_name = '%q' AND type = 'trigger' AND (name LIKE 'ggi_%%' OR name LIKE 'tmi_%%')",
+            pszTableName);
+        sqlite3_get_table( poDS->GetDB(),
+                           pszSQL3,
+                           &papszResult,
+                           &nRowCount, &nColCount, &pszErrMsg );
+        sqlite3_free(pszSQL3);
+
+        if( pszErrMsg )
+            sqlite3_free( pszErrMsg );
+        pszErrMsg = NULL;
+
+        for(int j=0;j<poFeatureDefn->GetGeomFieldCount();j++)
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+                                        poFeatureDefn->myGetGeomFieldDefn(j);
+            if( !((bDeferredSpatialIndexCreation || !poGeomFieldDefn->bHasSpatialIndex) &&
+                  !poGeomFieldDefn->bHasM) )
+                continue;
+            const char* pszGeomCol = poGeomFieldDefn->GetNameRef();
+
+            for(int i=0;i<nRowCount;i++)
+            {
+                const char* pszTriggerName = papszResult[2*(i+1)+0];
+                const char* pszTriggerSQL = papszResult[2*(i+1)+1];
+                if( pszTriggerName!= NULL && pszTriggerSQL != NULL &&
+                    CPLString(pszTriggerName).tolower().find(CPLString(pszGeomCol).tolower()) != std::string::npos )
+                {
+                    const char* pszExpectedTrigger = 0;
+                    if( strncmp(pszTriggerName, "ggi_", 4) == 0 )
+                    {
+                        pszExpectedTrigger = CPLSPrintf(
+                        "CREATE TRIGGER \"ggi_%s_%s\" BEFORE INSERT ON \"%s\" "
+                        "FOR EACH ROW BEGIN "
+                        "SELECT RAISE(ROLLBACK, '%s.%s violates Geometry constraint [geom-type or SRID not allowed]') "
+                        "WHERE (SELECT geometry_type FROM geometry_columns "
+                        "WHERE Lower(f_table_name) = Lower('%s') AND Lower(f_geometry_column) = Lower('%s') "
+                        "AND GeometryConstraints(NEW.\"%s\", geometry_type, srid) = 1) IS NULL; "
+                        "END",
+                        pszTableName, pszGeomCol, pszTableName,
+                        pszTableName, pszGeomCol,
+                        pszTableName, pszGeomCol,
+                        pszGeomCol);
+                    }
+                    else if( strncmp(pszTriggerName, "tmi_", 4) == 0 )
+                    {
+                        pszExpectedTrigger = CPLSPrintf(
+                        "CREATE TRIGGER \"tmi_%s_%s\" AFTER INSERT ON \"%s\" "
+                        "FOR EACH ROW BEGIN "
+                        "UPDATE geometry_columns_time SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+                        "WHERE Lower(f_table_name) = Lower('%s') AND Lower(f_geometry_column) = Lower('%s'); "
+                        "END",
+                        pszTableName, pszGeomCol, pszTableName,
+                        pszTableName, pszGeomCol);
+                    }
+                    /* Cannot happen due to the tests that lead to that code path */
+                    /* that check there's no spatial index active */
+                    /* A further potential optimization would be to rebuild the spatial index */
+                    /* afterwards... */
+                    /*else if( strncmp(pszTriggerName, "gii_", 4) == 0 )
+                    {
+                        pszExpectedTrigger = CPLSPrintf(
+                        "CREATE TRIGGER \"gii_%s_%s\" AFTER INSERT ON \"%s\" "
+                        "FOR EACH ROW BEGIN "
+                        "UPDATE geometry_columns_time SET last_insert = strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ', 'now') "
+                        "WHERE Lower(f_table_name) = Lower('%s') AND Lower(f_geometry_column) = Lower('%s'); "
+                        "DELETE FROM \"idx_%s_%s\" WHERE pkid=NEW.ROWID; "
+                        "SELECT RTreeAlign('idx_%s_%s', NEW.ROWID, NEW.\"%s\"); "
+                        "END",
+                        pszTableName, pszGeomCol, pszTableName,
+                        pszTableName, pszGeomCol,
+                        pszTableName, pszGeomCol,
+                        pszTableName, pszGeomCol, pszGeomCol);
+                    }*/
+
+                    if( AreTriggersSimilar(pszExpectedTrigger, pszTriggerSQL) )
+                    {
+                        // And drop them
+                        pszSQL3 = sqlite3_mprintf("DROP TRIGGER %s", pszTriggerName);
+                        int rc = sqlite3_exec( poDS->GetDB(), pszSQL3, NULL, NULL, &pszErrMsg );
+                        if( rc != SQLITE_OK )
+                            CPLDebug("SQLITE", "Error %s", pszErrMsg ? pszErrMsg : "");
+                        else
+                        {
+                            CPLDebug("SQLite", "Dropping trigger %s", pszTriggerName);
+                            poGeomFieldDefn->aosDisabledTriggers.push_back(std::pair<CPLString,CPLString>(pszTriggerName, pszTriggerSQL));
+                        }
+                        sqlite3_free(pszSQL3);
+                        if( pszErrMsg )
+                            sqlite3_free( pszErrMsg );
+                        pszErrMsg = NULL;
+                    }
+                    else
+                    {
+                        CPLDebug("SQLite", "Cannot drop %s trigger. Doesn't match expected definition",
+                                pszTriggerName);
+                    }
+                }
+            }
+        }
+
+        sqlite3_free_table( papszResult );
+    }
+
     ResetReading();
 
+    for(int j=0;j<poFeatureDefn->GetGeomFieldCount();j++)
+    {
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+                                        poFeatureDefn->myGetGeomFieldDefn(j);
+        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(j);
+        if( poGeomFieldDefn->aosDisabledTriggers.size() != 0  && poGeom != NULL )
+        {
+            OGRwkbGeometryType eGeomType = poGeomFieldDefn->GetType();
+            if( eGeomType != wkbUnknown && poGeom->getGeometryType() != eGeomType )
+            {
+                CPLError( CE_Failure, CPLE_AppDefined,
+                          "Cannot insert feature with geometry of type %s%s in column %s. Type %s%s expected",
+                          OGRToOGCGeomType(poGeom->getGeometryType()),
+                          (wkbFlatten(poGeom->getGeometryType()) != poGeom->getGeometryType()) ? "Z" :"",
+                          poGeomFieldDefn->GetNameRef(),
+                          OGRToOGCGeomType(eGeomType),
+                          (wkbFlatten(eGeomType) != eGeomType) ? "Z": "" );
+                return OGRERR_FAILURE;
+            }
+        }
+    }
+
+    int bReuseStmt = FALSE;
+
+    /* If there's a unset field with a default value, then we must create */
+    /* a specific INSERT statement to avoid unset fields to be bound to NULL */
+    int bHasDefaultValue = FALSE;
+    int iField;
+    int nFieldCount = poFeatureDefn->GetFieldCount();
+    for( iField = 0; iField < nFieldCount; iField++ )
+    {
+        if( !poFeature->IsFieldSet( iField ) &&
+            poFeature->GetFieldDefnRef(iField)->GetDefault() != NULL )
+        {
+            bHasDefaultValue = TRUE;
+            break;
+        }
+    }
+
+    /* In case the FID column has also been created as a regular field */
+    if( iFIDAsRegularColumnIndex >= 0 )
+    {
+        if( poFeature->GetFID() == OGRNullFID )
+        {
+            if( poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) )
+            {
+                poFeature->SetFID(
+                    poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex));
+            }
+        }
+        else
+        {
+            if( !poFeature->IsFieldSet( iFIDAsRegularColumnIndex ) ||
+                poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
+            {
+                CPLError(CE_Failure, CPLE_AppDefined,
+                            "Inconsistant values of FID and field of same name");
+                return CE_Failure;
+            }
+        }
+    }
+
+    int bTemporaryStatement = (poFeature->GetFID() != OGRNullFID || bHasDefaultValue);
+    if( hInsertStmt == NULL || bTemporaryStatement )
+    {
+        CPLString      osValues;
+
 /* -------------------------------------------------------------------- */
 /*      Form the INSERT command.                                        */
 /* -------------------------------------------------------------------- */
-    osCommand += CPLSPrintf( "INSERT INTO '%s' (", pszEscapedTableName );
+        osCommand += CPLSPrintf( "INSERT INTO '%s' (", pszEscapedTableName );
 
 /* -------------------------------------------------------------------- */
 /*      Add FID if we have a cleartext FID column.                      */
 /* -------------------------------------------------------------------- */
-    if( pszFIDColumn != NULL // && !EQUAL(pszFIDColumn,"OGC_FID") 
-        && poFeature->GetFID() != OGRNullFID )
-    {
-        osCommand += "\"";
-        osCommand += OGRSQLiteEscapeName(pszFIDColumn);
-        osCommand += "\"";
+        if( pszFIDColumn != NULL
+            && poFeature->GetFID() != OGRNullFID )
+        {
+            osCommand += "\"";
+            osCommand += OGRSQLiteEscapeName(pszFIDColumn);
+            osCommand += "\"";
 
-        osValues += CPLSPrintf( "%ld", poFeature->GetFID() );
-        bNeedComma = TRUE;
-    }
+            osValues += CPLSPrintf( CPL_FRMT_GIB, poFeature->GetFID() );
+            bNeedComma = TRUE;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Add geometry.                                                   */
 /* -------------------------------------------------------------------- */
-    OGRGeometry *poGeom = poFeature->GetGeometryRef();
-
-    if( poFeatureDefn->GetGeomFieldCount() != 0 &&
-        poGeom != NULL &&
-        eGeomFormat != OSGF_FGF )
-    {
-
-        if( bNeedComma )
+        nFieldCount = poFeatureDefn->GetGeomFieldCount();
+        for( iField = 0; iField < nFieldCount; iField++ )
         {
-            osCommand += ",";
-            osValues += ",";
-        }
+            OGRSQLiteGeomFormat eGeomFormat =
+                poFeatureDefn->myGetGeomFieldDefn(iField)->eGeomFormat;
+            if( eGeomFormat == OSGF_FGF )
+                continue;
+            if( bHasDefaultValue && poFeature->GetGeomFieldRef(iField) == NULL )
+                continue;
+            if( bNeedComma )
+            {
+                osCommand += ",";
+                osValues += ",";
+            }
 
-        osCommand += "\"";
-        osCommand += OGRSQLiteEscapeName(pszGeomCol);
-        osCommand += "\"";
+            osCommand += "\"";
+            osCommand += OGRSQLiteEscapeName(poFeatureDefn->GetGeomFieldDefn(iField)->GetNameRef());
+            osCommand += "\"";
 
-        osValues += "?";
+            osValues += "?";
 
-        bNeedComma = TRUE;
-    }
+            bNeedComma = TRUE;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Add field values.                                               */
 /* -------------------------------------------------------------------- */
-    int iField;
-    int nFieldCount = poFeatureDefn->GetFieldCount();
-
-    for( iField = 0; iField < nFieldCount; iField++ )
-    {
-        if( !poFeature->IsFieldSet( iField ) )
-            continue;
-
-        if( bNeedComma )
+        nFieldCount = poFeatureDefn->GetFieldCount();
+        for( iField = 0; iField < nFieldCount; iField++ )
         {
-            osCommand += ",";
-            osValues += ",";
-        }
+            if( iField == iFIDAsRegularColumnIndex )
+                continue;
+            if( bHasDefaultValue && !poFeature->IsFieldSet( iField ) )
+                continue;
 
-        osCommand += "\"";
-        osCommand += OGRSQLiteEscapeName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
-        osCommand += "\"";
+            if( bNeedComma )
+            {
+                osCommand += ",";
+                osValues += ",";
+            }
 
-        osValues += "?";
+            osCommand += "\"";
+            osCommand += OGRSQLiteEscapeName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef());
+            osCommand += "\"";
 
-        bNeedComma = TRUE;
-    }
+            osValues += "?";
+
+            bNeedComma = TRUE;
+        }
 
 /* -------------------------------------------------------------------- */
 /*      Merge final command.                                            */
 /* -------------------------------------------------------------------- */
-    osCommand += ") VALUES (";
-    osCommand += osValues;
-    osCommand += ")";
+        osCommand += ") VALUES (";
+        osCommand += osValues;
+        osCommand += ")";
 
-    if (bNeedComma == FALSE)
-        osCommand = CPLSPrintf( "INSERT INTO '%s' DEFAULT VALUES", pszEscapedTableName );
+        if (bNeedComma == FALSE)
+            osCommand = CPLSPrintf( "INSERT INTO '%s' DEFAULT VALUES", pszEscapedTableName );
+    }
+    else
+        bReuseStmt = TRUE;
 
 /* -------------------------------------------------------------------- */
 /*      Prepare the statement.                                          */
 /* -------------------------------------------------------------------- */
     int rc;
 
-    if (hInsertStmt == NULL ||
-        osCommand != osLastInsertStmt)
+    if( !bReuseStmt && (hInsertStmt == NULL || osCommand != osLastInsertStmt) )
     {
     #ifdef DEBUG
         CPLDebug( "OGR_SQLITE", "prepare(%s)", osCommand.c_str() );
     #endif
 
         ClearInsertStmt();
-        osLastInsertStmt = osCommand;
+        if( poFeature->GetFID() == OGRNullFID )
+            osLastInsertStmt = osCommand;
 
 #ifdef HAVE_SQLITE3_PREPARE_V2
         rc = sqlite3_prepare_v2( hDB, osCommand, -1, &hInsertStmt, NULL );
@@ -2133,7 +3076,7 @@ OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
 /* -------------------------------------------------------------------- */
 /*      Bind values.                                                   */
 /* -------------------------------------------------------------------- */
-    OGRErr eErr = BindValues( poFeature, hInsertStmt, FALSE );
+    OGRErr eErr = BindValues( poFeature, hInsertStmt, !bHasDefaultValue );
     if (eErr != OGRERR_NONE)
     {
         sqlite3_reset( hInsertStmt );
@@ -2151,6 +3094,7 @@ OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
                   "sqlite3_step() failed:\n  %s (%d)", 
                   sqlite3_errmsg(hDB), rc );
         sqlite3_reset( hInsertStmt );
+        ClearInsertStmt();
         return OGRERR_FAILURE;
     }
 
@@ -2160,20 +3104,34 @@ OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
     const sqlite_int64 nFID = sqlite3_last_insert_rowid( hDB );
     if(nFID > 0)
     {
-        poFeature->SetFID( (long)nFID ); /* Possible truncation if nFID is 64bit */
+        poFeature->SetFID( nFID );
+        if( iFIDAsRegularColumnIndex >= 0 )
+            poFeature->SetField( iFIDAsRegularColumnIndex, nFID );
     }
 
     sqlite3_reset( hInsertStmt );
+    
+    if( bTemporaryStatement )
+        ClearInsertStmt();
 
-    if( (bCachedExtentIsValid || nFeatureCount == 0) &&
-        poGeom != NULL && !poGeom->IsEmpty() )
+    nFieldCount = poFeatureDefn->GetGeomFieldCount();
+    for( iField = 0; iField < nFieldCount; iField++ )
     {
-        OGREnvelope sGeomEnvelope;
-        poGeom->getEnvelope(&sGeomEnvelope);
-        oCachedExtent.Merge(sGeomEnvelope);
-        bCachedExtentIsValid = TRUE;
-        bStatisticsNeedsToBeFlushed = TRUE;
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn = 
+            poFeatureDefn->myGetGeomFieldDefn(iField);
+        OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iField);
+        
+        if( (poGeomFieldDefn->bCachedExtentIsValid || nFeatureCount == 0) &&
+            poGeom != NULL && !poGeom->IsEmpty() )
+        {
+            OGREnvelope sGeomEnvelope;
+            poGeom->getEnvelope(&sGeomEnvelope);
+            poGeomFieldDefn->oCachedExtent.Merge(sGeomEnvelope);
+            poGeomFieldDefn->bCachedExtentIsValid = TRUE;
+            bStatisticsNeedsToBeFlushed = TRUE;
+        }
     }
+
     if( nFeatureCount >= 0 )
     {
         bStatisticsNeedsToBeFlushed = TRUE;
@@ -2187,7 +3145,7 @@ OGRErr OGRSQLiteTableLayer::CreateFeature( OGRFeature *poFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRSQLiteTableLayer::DeleteFeature( long nFID )
+OGRErr OGRSQLiteTableLayer::DeleteFeature( GIntBig nFID )
 
 {
     CPLString      osSQL;
@@ -2212,9 +3170,12 @@ OGRErr OGRSQLiteTableLayer::DeleteFeature( long nFID )
         return OGRERR_FAILURE;
     }
 
+    if( bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
     ResetReading();
 
-    osSQL.Printf( "DELETE FROM '%s' WHERE \"%s\" = %ld",
+    osSQL.Printf( "DELETE FROM '%s' WHERE \"%s\" = " CPL_FRMT_GIB,
                   pszEscapedTableName,
                   OGRSQLiteEscapeName(pszFIDColumn).c_str(), nFID );
 
@@ -2230,31 +3191,39 @@ OGRErr OGRSQLiteTableLayer::DeleteFeature( long nFID )
         return OGRERR_FAILURE;
     }
 
-    int nChanged = sqlite3_changes( poDS->GetDB() );
-
-    if( nChanged == 1 )
+    OGRErr eErr = (sqlite3_changes(poDS->GetDB()) > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
+    if( eErr == OGRERR_NONE )
     {
-        bCachedExtentIsValid = FALSE;
+        int nFieldCount = poFeatureDefn->GetGeomFieldCount();
+        for( int iField = 0; iField < nFieldCount; iField++ )
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn = 
+                poFeatureDefn->myGetGeomFieldDefn(iField);
+            poGeomFieldDefn->bCachedExtentIsValid = FALSE;
+        }
         nFeatureCount --;
         bStatisticsNeedsToBeFlushed = TRUE;
     }
 
-    return OGRERR_NONE;
+    return eErr;
 }
 
 /************************************************************************/
 /*                         CreateSpatialIndex()                         */
 /************************************************************************/
 
-int OGRSQLiteTableLayer::CreateSpatialIndex()
+int OGRSQLiteTableLayer::CreateSpatialIndex(int iGeomCol)
 {
     CPLString osCommand;
 
-    if( pszGeomCol == NULL )
+    if( bDeferredCreation ) RunDeferredCreationIfNecessary();
+
+    if( iGeomCol < 0 || iGeomCol >= poFeatureDefn->GetGeomFieldCount() )
         return FALSE;
 
     osCommand.Printf("SELECT CreateSpatialIndex('%s', '%s')",
-                     pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
+                     pszEscapedTableName,
+                     OGRSQLiteEscape(poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()).c_str());
 
     char* pszErrMsg = NULL;
     sqlite3 *hDB = poDS->GetDB();
@@ -2270,23 +3239,156 @@ int OGRSQLiteTableLayer::CreateSpatialIndex()
         return FALSE;
     }
 
-    bHasSpatialIndex = TRUE;
+    poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->bHasSpatialIndex = TRUE;
     return TRUE;
 }
 
+
 /************************************************************************/
-/*                           HasSpatialIndex()                          */
+/*                      RunDeferredCreationIfNecessary()                */
 /************************************************************************/
 
-int OGRSQLiteTableLayer::HasSpatialIndex()
+OGRErr OGRSQLiteTableLayer::RunDeferredCreationIfNecessary()
 {
-    if( bDeferedSpatialIndexCreation )
+    if( !bDeferredCreation )
+        return OGRERR_NONE;
+    bDeferredCreation = FALSE;
+
+    const char* pszLayerName = poFeatureDefn->GetName();
+
+    int rc;
+    char *pszErrMsg;
+    CPLString osCommand;
+    
+    osCommand.Printf( "CREATE TABLE '%s' ( %s INTEGER PRIMARY KEY", 
+                      pszEscapedTableName,
+                      pszFIDColumn );
+
+    int i;
+    if ( !poDS->IsSpatialiteDB() )
     {
-        bDeferedSpatialIndexCreation = FALSE;
-        bHasSpatialIndex = CreateSpatialIndex();
+        for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+                poFeatureDefn->myGetGeomFieldDefn(i);
+
+            if( poGeomFieldDefn->eGeomFormat == OSGF_WKT )
+            {
+                osCommand += CPLSPrintf(", '%s' VARCHAR", 
+                    OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str() );
+            }
+            else
+            {
+                osCommand += CPLSPrintf(", '%s' BLOB", 
+                    OGRSQLiteEscape(poGeomFieldDefn->GetNameRef()).c_str() );
+            }
+            if( !poGeomFieldDefn->IsNullable() )
+            {
+                osCommand += " NOT NULL";
+            }
+        }
+    }
+
+    for(i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
+    {
+        OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn(i);
+        if( i == iFIDAsRegularColumnIndex )
+            continue;
+        CPLString osFieldType(FieldDefnToSQliteFieldDefn(poFieldDefn));
+        osCommand += CPLSPrintf(", '%s' %s",
+                        OGRSQLiteEscape(poFieldDefn->GetNameRef()).c_str(),
+                        osFieldType.c_str());
+        if( !poFieldDefn->IsNullable() )
+        {
+            osCommand += " NOT NULL";
+        }
+        const char* pszDefault = poFieldDefn->GetDefault();
+        if( pszDefault != NULL &&
+            (!poFieldDefn->IsDefaultDriverSpecific() ||
+             (pszDefault[0] == '(' && pszDefault[strlen(pszDefault)-1] == ')' &&
+             (EQUALN(pszDefault+1, "strftime", strlen("strftime")) ||
+              EQUALN(pszDefault+1, " strftime", strlen(" strftime"))))) )
+        {
+            osCommand += " DEFAULT ";
+            osCommand += poFieldDefn->GetDefault();
+        }
+    }
+    osCommand += ")";
+
+#ifdef DEBUG
+    CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
+#endif
+
+    rc = sqlite3_exec( poDS->GetDB(), osCommand, NULL, NULL, &pszErrMsg );
+    if( rc != SQLITE_OK )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Unable to create table %s: %s",
+                  pszLayerName, pszErrMsg );
+        sqlite3_free( pszErrMsg );
+        return OGRERR_FAILURE;
+    }
+
+/* -------------------------------------------------------------------- */
+/*      Eventually we should be adding this table to a table of         */
+/*      "geometric layers", capturing the WKT projection, and           */
+/*      perhaps some other housekeeping.                                */
+/* -------------------------------------------------------------------- */
+    if( poDS->HasGeometryColumns() )
+    {
+        /* Sometimes there is an old cruft entry in the geometry_columns
+        * table if things were not properly cleaned up before.  We make
+        * an effort to clean out such cruft.
+        */
+        osCommand.Printf(
+            "DELETE FROM geometry_columns WHERE f_table_name = '%s'", 
+            pszEscapedTableName );
+
+#ifdef DEBUG
+        CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
+#endif
+
+        rc = sqlite3_exec( poDS->GetDB(), osCommand, NULL, NULL, &pszErrMsg );
+        if( rc != SQLITE_OK )
+        {
+            sqlite3_free( pszErrMsg );
+            return FALSE;
+        }
+
+        for(i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
+        {
+            OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
+                poFeatureDefn->myGetGeomFieldDefn(i);
+            RunAddGeometryColumn(poGeomFieldDefn, FALSE);
+        }
+    }
+
+    if (RecomputeOrdinals() != OGRERR_NONE )
+        return OGRERR_FAILURE;
+
+    if( poDS->IsSpatialiteDB() && poDS->GetLayerCount() == 1)
+    {
+        /* To create the layer_statistics and spatialite_history tables */
+        sqlite3_exec( poDS->GetDB(), "SELECT UpdateLayerStatistics()", NULL, NULL, NULL );
     }
 
-    return bHasSpatialIndex;
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           HasSpatialIndex()                          */
+/************************************************************************/
+
+int OGRSQLiteTableLayer::HasSpatialIndex(int iGeomCol)
+{
+    GetLayerDefn();
+    if( iGeomCol < 0 || iGeomCol >= poFeatureDefn->GetGeomFieldCount() )
+        return FALSE;
+    OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iGeomCol);    
+    
+    CreateSpatialIndexIfNecessary();
+
+    return poGeomFieldDefn->bHasSpatialIndex;
 }
 
 /************************************************************************/
@@ -2306,7 +3408,8 @@ void OGRSQLiteTableLayer::InitFeatureCount()
 void OGRSQLiteTableLayer::InvalidateCachedFeatureCountAndExtent()
 {
     nFeatureCount = -1;
-    bCachedExtentIsValid = FALSE;
+    for(int iGeomCol=0;iGeomCol<GetLayerDefn()->GetGeomFieldCount();iGeomCol++)
+        poFeatureDefn->myGetGeomFieldDefn(iGeomCol)->bCachedExtentIsValid = FALSE;
     bStatisticsNeedsToBeFlushed = TRUE;
 }
 
@@ -2345,98 +3448,102 @@ int OGRSQLiteTableLayer::AreStatisticsValid()
 
 void OGRSQLiteTableLayer::LoadStatisticsSpatialite4DB()
 {
-    if( pszGeomCol == NULL )
-        return;
-
-    CPLString osSQL;
-    CPLString osLastEvtDate;
-    osSQL.Printf("SELECT MAX(last_insert, last_update, last_delete) FROM geometry_columns_time WHERE "
-                 "f_table_name = '%s' AND f_geometry_column = '%s'",
-                 pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
-
-    sqlite3 *hDB = poDS->GetDB();
-    int nRowCount = 0, nColCount = 0;
-    char **papszResult = NULL;
+    for(int iCol = 0; iCol < GetLayerDefn()->GetGeomFieldCount(); iCol++ )
+    {
+        OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(iCol);
+        const char* pszGeomCol = poGeomFieldDefn->GetNameRef();
 
-    sqlite3_get_table( hDB, osSQL.c_str(), &papszResult,
-                       &nRowCount, &nColCount, NULL );
+        CPLString osSQL;
+        CPLString osLastEvtDate;
+        osSQL.Printf("SELECT MAX(last_insert, last_update, last_delete) FROM geometry_columns_time WHERE "
+                    "f_table_name = '%s' AND f_geometry_column = '%s'",
+                    pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
 
-    /* Make it a Unix timestamp */
-    int nYear, nMonth, nDay, nHour, nMinute;
-    float fSecond;
-    if( nRowCount == 1 && nColCount == 1 && papszResult[1] != NULL &&
-        sscanf( papszResult[1], "%04d-%02d-%02dT%02d:%02d:%f",
-                &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond ) == 6 )
-    {
-        osLastEvtDate = papszResult[1];
-    }
+        sqlite3 *hDB = poDS->GetDB();
+        int nRowCount = 0, nColCount = 0;
+        char **papszResult = NULL;
 
-    sqlite3_free_table( papszResult );
-    papszResult = NULL;
+        sqlite3_get_table( hDB, osSQL.c_str(), &papszResult,
+                        &nRowCount, &nColCount, NULL );
+
+        /* Make it a Unix timestamp */
+        int nYear, nMonth, nDay, nHour, nMinute;
+        float fSecond;
+        if( nRowCount == 1 && nColCount == 1 && papszResult[1] != NULL &&
+            sscanf( papszResult[1], "%04d-%02d-%02dT%02d:%02d:%f",
+                    &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond ) == 6 )
+        {
+            osLastEvtDate = papszResult[1];
+        }
 
-    if( osLastEvtDate.size() == 0 )
-        return;
+        sqlite3_free_table( papszResult );
+        papszResult = NULL;
 
-    osSQL.Printf("SELECT last_verified, row_count, extent_min_x, extent_min_y, "
-                 "extent_max_x, extent_max_y FROM geometry_columns_statistics WHERE "
-                 "f_table_name = '%s' AND f_geometry_column = '%s'",
-                 pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
+        if( osLastEvtDate.size() == 0 )
+            return;
 
-    nRowCount = 0;
-    nColCount = 0;
-    sqlite3_get_table( hDB, osSQL.c_str(), &papszResult,
-                       &nRowCount, &nColCount, NULL );
+        osSQL.Printf("SELECT last_verified, row_count, extent_min_x, extent_min_y, "
+                    "extent_max_x, extent_max_y FROM geometry_columns_statistics WHERE "
+                    "f_table_name = '%s' AND f_geometry_column = '%s'",
+                    pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str());
 
-    if( nRowCount == 1 && nColCount == 6 && papszResult[6] != NULL &&
-        sscanf( papszResult[6], "%04d-%02d-%02dT%02d:%02d:%f",
-                &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond ) == 6 )
-    {
-        CPLString osLastVerified(papszResult[6]);
+        nRowCount = 0;
+        nColCount = 0;
+        sqlite3_get_table( hDB, osSQL.c_str(), &papszResult,
+                        &nRowCount, &nColCount, NULL );
 
-        /* Check that the information in geometry_columns_statistics is more */
-        /* recent than geometry_columns_time */
-        if( osLastVerified.compare(osLastEvtDate) > 0 )
+        if( nRowCount == 1 && nColCount == 6 && papszResult[6] != NULL &&
+            sscanf( papszResult[6], "%04d-%02d-%02dT%02d:%02d:%f",
+                    &nYear, &nMonth, &nDay, &nHour, &nMinute, &fSecond ) == 6 )
         {
-            char **papszRow = papszResult + 6;
-            const char* pszRowCount = papszRow[1];
-            const char* pszMinX = papszRow[2];
-            const char* pszMinY = papszRow[3];
-            const char* pszMaxX = papszRow[4];
-            const char* pszMaxY = papszRow[5];
-
-            CPLDebug("SQLITE",  "Loading statistics for %s", pszTableName);
+            CPLString osLastVerified(papszResult[6]);
 
-            if( pszRowCount != NULL )
+            /* Check that the information in geometry_columns_statistics is more */
+            /* recent than geometry_columns_time */
+            if( osLastVerified.compare(osLastEvtDate) > 0 )
             {
-                nFeatureCount = (GIntBig) CPLScanUIntBig( pszRowCount, 32 );
-                if( nFeatureCount == 0)
+                char **papszRow = papszResult + 6;
+                const char* pszRowCount = papszRow[1];
+                const char* pszMinX = papszRow[2];
+                const char* pszMinY = papszRow[3];
+                const char* pszMaxX = papszRow[4];
+                const char* pszMaxY = papszRow[5];
+
+                CPLDebug("SQLITE",  "Loading statistics for %s,%s", pszTableName,
+                         pszGeomCol);
+
+                if( pszRowCount != NULL )
                 {
-                    nFeatureCount = -1;
-                    pszMinX = NULL;
+                    nFeatureCount = CPLAtoGIntBig( pszRowCount );
+                    if( nFeatureCount == 0)
+                    {
+                        nFeatureCount = -1;
+                        pszMinX = NULL;
+                    }
+                    else
+                    {
+                        CPLDebug("SQLite", "Layer %s feature count : " CPL_FRMT_GIB,
+                                    pszTableName, nFeatureCount);
+                    }
                 }
-                else
+
+                if( pszMinX != NULL && pszMinY != NULL &&
+                    pszMaxX != NULL && pszMaxY != NULL )
                 {
-                    CPLDebug("SQLite", "Layer %s feature count : " CPL_FRMT_GIB,
-                                pszTableName, nFeatureCount);
+                    poGeomFieldDefn->bCachedExtentIsValid = TRUE;
+                    poGeomFieldDefn->oCachedExtent.MinX = CPLAtof(pszMinX);
+                    poGeomFieldDefn->oCachedExtent.MinY = CPLAtof(pszMinY);
+                    poGeomFieldDefn->oCachedExtent.MaxX = CPLAtof(pszMaxX);
+                    poGeomFieldDefn->oCachedExtent.MaxY = CPLAtof(pszMaxY);
+                    CPLDebug("SQLite", "Layer %s extent : %s,%s,%s,%s",
+                                pszTableName, pszMinX,pszMinY,pszMaxX,pszMaxY);
                 }
             }
-
-            if( pszMinX != NULL && pszMinY != NULL &&
-                pszMaxX != NULL && pszMaxY != NULL )
-            {
-                bCachedExtentIsValid = TRUE;
-                oCachedExtent.MinX = CPLAtof(pszMinX);
-                oCachedExtent.MinY = CPLAtof(pszMinY);
-                oCachedExtent.MaxX = CPLAtof(pszMaxX);
-                oCachedExtent.MaxY = CPLAtof(pszMaxY);
-                CPLDebug("SQLite", "Layer %s extent : %s,%s,%s,%s",
-                            pszTableName, pszMinX,pszMinY,pszMaxX,pszMaxY);
-            }
         }
-    }
 
-    sqlite3_free_table( papszResult );
-    papszResult = NULL;
+        sqlite3_free_table( papszResult );
+        papszResult = NULL;
+    }
 }
 
 /************************************************************************/
@@ -2445,7 +3552,7 @@ void OGRSQLiteTableLayer::LoadStatisticsSpatialite4DB()
 
 void OGRSQLiteTableLayer::LoadStatistics()
 {
-    if( !poDS->IsSpatialiteDB() || !poDS->IsSpatialiteLoaded() || pszGeomCol == NULL )
+    if( !poDS->IsSpatialiteDB() || !poDS->IsSpatialiteLoaded() )
         return;
 
     if( poDS->HasSpatialite4Layout() )
@@ -2454,6 +3561,10 @@ void OGRSQLiteTableLayer::LoadStatistics()
         return;
     }
 
+    if( GetLayerDefn()->GetGeomFieldCount() != 1 )
+        return;
+    const char* pszGeomCol = poFeatureDefn->GetGeomFieldDefn(0)->GetNameRef();
+
     GIntBig nFileTimestamp = poDS->GetFileTimestamp();
     if( nFileTimestamp == 0 )
         return;
@@ -2520,7 +3631,7 @@ void OGRSQLiteTableLayer::LoadStatistics()
 
             if( pszRowCount != NULL )
             {
-                nFeatureCount = (GIntBig) CPLScanUIntBig( pszRowCount, 32 );
+                nFeatureCount = CPLAtoGIntBig( pszRowCount );
                 CPLDebug("SQLite", "Layer %s feature count : " CPL_FRMT_GIB,
                             pszTableName, nFeatureCount);
             }
@@ -2528,11 +3639,12 @@ void OGRSQLiteTableLayer::LoadStatistics()
             if( pszMinX != NULL && pszMinY != NULL &&
                 pszMaxX != NULL && pszMaxY != NULL )
             {
-                bCachedExtentIsValid = TRUE;
-                oCachedExtent.MinX = CPLAtof(pszMinX);
-                oCachedExtent.MinY = CPLAtof(pszMinY);
-                oCachedExtent.MaxX = CPLAtof(pszMaxX);
-                oCachedExtent.MaxY = CPLAtof(pszMaxY);
+                OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(0);
+                poGeomFieldDefn->bCachedExtentIsValid = TRUE;
+                poGeomFieldDefn->oCachedExtent.MinX = CPLAtof(pszMinX);
+                poGeomFieldDefn->oCachedExtent.MinY = CPLAtof(pszMinY);
+                poGeomFieldDefn->oCachedExtent.MaxX = CPLAtof(pszMaxX);
+                poGeomFieldDefn->oCachedExtent.MaxY = CPLAtof(pszMaxY);
                 CPLDebug("SQLite", "Layer %s extent : %s,%s,%s,%s",
                             pszTableName, pszMinX,pszMinY,pszMaxX,pszMaxY);
             }
@@ -2551,8 +3663,13 @@ void OGRSQLiteTableLayer::LoadStatistics()
 
 int OGRSQLiteTableLayer::SaveStatistics()
 {
-    if( !bStatisticsNeedsToBeFlushed || !poDS->IsSpatialiteDB()  || !poDS->IsSpatialiteLoaded() || pszGeomCol == NULL )
+    if( !bStatisticsNeedsToBeFlushed || !poDS->IsSpatialiteDB()  ||
+        !poDS->IsSpatialiteLoaded() || poDS->HasSpatialite4Layout() )
+        return -1;
+    if( GetLayerDefn()->GetGeomFieldCount() != 1 )
         return -1;
+    OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(0);
+    const char* pszGeomCol = poGeomFieldDefn->GetNameRef();
 
     CPLString osSQL;
     sqlite3 *hDB = poDS->GetDB();
@@ -2561,16 +3678,19 @@ int OGRSQLiteTableLayer::SaveStatistics()
     if( nFeatureCount >= 0 )
     {
         /* Update or add entry in the layer_statistics table */
-        if( bCachedExtentIsValid )
+        if( poGeomFieldDefn->bCachedExtentIsValid )
         {
             osSQL.Printf("INSERT OR REPLACE INTO layer_statistics (raster_layer, "
                             "table_name, geometry_column, row_count, extent_min_x, "
                             "extent_min_y, extent_max_x, extent_max_y) VALUES ("
-                            "0, '%s', '%s', " CPL_FRMT_GIB ", %.18g, %.18g, %.18g, %.18g)",
+                            "0, '%s', '%s', " CPL_FRMT_GIB ", %s, %s, %s, %s)",
                             pszEscapedTableName, OGRSQLiteEscape(pszGeomCol).c_str(),
                             nFeatureCount,
-                            oCachedExtent.MinX, oCachedExtent.MinY,
-                            oCachedExtent.MaxX, oCachedExtent.MaxY);
+                            // Insure that only Decimal.Points are used, never local settings such as Decimal.Comma.
+                            CPLString().FormatC(poGeomFieldDefn->oCachedExtent.MinX,"%.18g").c_str(),
+                            CPLString().FormatC(poGeomFieldDefn->oCachedExtent.MinY,"%.18g").c_str(),
+                            CPLString().FormatC(poGeomFieldDefn->oCachedExtent.MaxX,"%.18g").c_str(),
+                            CPLString().FormatC(poGeomFieldDefn->oCachedExtent.MaxY,"%.18g").c_str());
         }
         else
         {
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp
index e3c126f..5089e21 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitevfs.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitevfs.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrsqlitevfs.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements SQLite VFS
@@ -30,7 +30,13 @@
 #include "cpl_atomic_ops.h"
 #include "ogr_sqlite.h"
 
-CPL_CVSID("$Id: ogrsqlitevfs.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrsqlitevfs.cpp 27745 2014-09-27 16:38:57Z goatbar $");
+
+#ifdef DEBUG_IO
+# define DEBUG_ONLY
+#else
+# define DEBUG_ONLY CPL_UNUSED
+#endif
 
 //#define DEBUG_IO 1
 
@@ -109,15 +115,7 @@ static int OGRSQLiteIOTruncate(sqlite3_file* pFile, sqlite3_int64 size)
     return (nRet == 0) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
 }
 
-static int OGRSQLiteIOSync(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                           sqlite3_file* pFile,
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                           int flags)
+static int OGRSQLiteIOSync(DEBUG_ONLY sqlite3_file* pFile, DEBUG_ONLY int flags)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -139,15 +137,7 @@ static int OGRSQLiteIOFileSize(sqlite3_file* pFile, sqlite3_int64 *pSize)
     return SQLITE_OK;
 }
 
-static int OGRSQLiteIOLock(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                           sqlite3_file* pFile,
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                           int flags)
+static int OGRSQLiteIOLock(DEBUG_ONLY sqlite3_file* pFile, DEBUG_ONLY int flags)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -156,7 +146,7 @@ CPL_UNUSED
     return SQLITE_OK;
 }
 
-static int OGRSQLiteIOUnlock(CPL_UNUSED sqlite3_file* pFile, CPL_UNUSED int flags)
+static int OGRSQLiteIOUnlock(DEBUG_ONLY sqlite3_file* pFile, DEBUG_ONLY int flags)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -165,15 +155,8 @@ static int OGRSQLiteIOUnlock(CPL_UNUSED sqlite3_file* pFile, CPL_UNUSED int flag
     return SQLITE_OK;
 }
 
-static int OGRSQLiteIOCheckReservedLock(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                        sqlite3_file* pFile,
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                        int *pResOut)
+static int OGRSQLiteIOCheckReservedLock(DEBUG_ONLY sqlite3_file* pFile,
+                                        DEBUG_ONLY int *pResOut)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -183,19 +166,9 @@ CPL_UNUSED
     return SQLITE_OK;
 }
 
-static int OGRSQLiteIOFileControl(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                  sqlite3_file* pFile,
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                  int op,
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                  void *pArg)
+static int OGRSQLiteIOFileControl(DEBUG_ONLY sqlite3_file* pFile,
+                           DEBUG_ONLY int op,
+                           DEBUG_ONLY void *pArg)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -204,11 +177,7 @@ CPL_UNUSED
     return SQLITE_NOTFOUND;
 }
 
-static int OGRSQLiteIOSectorSize(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                 sqlite3_file* pFile)
+static int OGRSQLiteIOSectorSize(DEBUG_ONLY sqlite3_file* pFile)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -217,11 +186,7 @@ CPL_UNUSED
     return 0;
 }
 
-static int OGRSQLiteIODeviceCharacteristics(
-#ifndef DEBUG_IO
-CPL_UNUSED 
-#endif
-                                            sqlite3_file* pFile)
+static int OGRSQLiteIODeviceCharacteristics(DEBUG_ONLY sqlite3_file* pFile)
 {
 #ifdef DEBUG_IO
     OGRSQLiteFileStruct* pMyFile = (OGRSQLiteFileStruct*) pFile;
@@ -245,15 +210,6 @@ static const sqlite3_io_methods OGRSQLiteIOMethods =
     OGRSQLiteIOFileControl,
     OGRSQLiteIOSectorSize,
     OGRSQLiteIODeviceCharacteristics
-#if 0
-    // TODO: These are in sqlite3.
-    , 0, // xShmMap
-    0, // xShmLock
-    0, // xShmBarrier
-    0, // xShmUnmap
-    0, // xFetch
-    0 // xUnfetch
-#endif
 };
 
 static int OGRSQLiteVFSOpen(sqlite3_vfs* pVFS,
@@ -310,9 +266,8 @@ static int OGRSQLiteVFSOpen(sqlite3_vfs* pVFS,
     return SQLITE_OK;
 }
 
-static int OGRSQLiteVFSDelete(CPL_UNUSED sqlite3_vfs* pVFS,
-                              const char *zName,
-                              CPL_UNUSED int syncDir)
+static int OGRSQLiteVFSDelete(DEBUG_ONLY sqlite3_vfs* pVFS,
+                           const char *zName, int DEBUG_ONLY syncDir)
 {
 #ifdef DEBUG_IO
     CPLDebug("SQLITE", "OGRSQLiteVFSDelete(%s)", zName);
@@ -321,7 +276,10 @@ static int OGRSQLiteVFSDelete(CPL_UNUSED sqlite3_vfs* pVFS,
     return SQLITE_OK;
 }
 
-static int OGRSQLiteVFSAccess (CPL_UNUSED sqlite3_vfs* pVFS, const char *zName, int flags, int *pResOut)
+static int OGRSQLiteVFSAccess (DEBUG_ONLY sqlite3_vfs* pVFS,
+                               const char *zName,
+                               int flags,
+                               int *pResOut)
 {
 #ifdef DEBUG_IO
     CPLDebug("SQLITE", "OGRSQLiteVFSAccess(%s, %d)", zName, flags);
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp
index 8a21166..feb7108 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqliteviewlayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqliteviewlayer.cpp 28386 2015-01-30 17:04:25Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRSQLiteViewLayer class, access to an existing spatialite view.
@@ -32,7 +32,7 @@
 #include "ogr_sqlite.h"
 #include <string>
 
-CPL_CVSID("$Id: ogrsqliteviewlayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrsqliteviewlayer.cpp 28386 2015-01-30 17:04:25Z rouault $");
 
 /************************************************************************/
 /*                        OGRSQLiteViewLayer()                         */
@@ -49,6 +49,7 @@ OGRSQLiteViewLayer::OGRSQLiteViewLayer( OGRSQLiteDataSource *poDSIn )
     pszViewName = NULL;
     pszEscapedTableName = NULL;
     pszEscapedUnderlyingTableName = NULL;
+    bHasSpatialIndex = FALSE;
 
     bHasCheckedSpatialIndexTable = FALSE;
 
@@ -80,6 +81,7 @@ CPLErr OGRSQLiteViewLayer::Initialize( const char *pszViewName,
 
 {
     this->pszViewName = CPLStrdup(pszViewName);
+    SetDescription( pszViewName );
 
     osGeomColumn = pszViewGeometry;
     eGeomFormat = OSGF_SpatiaLite;
@@ -188,19 +190,18 @@ CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn()
         return CE_Failure;
     }
 
-    const char* pszRealUnderlyingGeometryColumn = poUnderlyingLayer->GetGeometryColumn();
-    if ( pszRealUnderlyingGeometryColumn == NULL ||
-         !EQUAL(pszRealUnderlyingGeometryColumn, osUnderlyingGeometryColumn.c_str()) )
+    int nUnderlyingLayerGeomFieldIndex =
+        poUnderlyingLayer->GetLayerDefn()->GetGeomFieldIndex(osUnderlyingGeometryColumn);
+    if ( nUnderlyingLayerGeomFieldIndex < 0 )
     {
         CPLError(CE_Failure, CPLE_AppDefined,
-                 "Underlying layer %s for view %s has not expected geometry column name (%s instead of %s)",
+                 "Underlying layer %s for view %s has not expected geometry column name %s",
                  osUnderlyingTableName.c_str(), pszViewName,
-                 pszRealUnderlyingGeometryColumn ? pszRealUnderlyingGeometryColumn : "(null)",
                  osUnderlyingGeometryColumn.c_str());
         return CE_Failure;
     }
 
-    this->bHasSpatialIndex = poUnderlyingLayer->HasSpatialIndex();
+    this->bHasSpatialIndex = poUnderlyingLayer->HasSpatialIndex(nUnderlyingLayerGeomFieldIndex);
 
 /* -------------------------------------------------------------------- */
 /*      Get the column definitions for this table.                      */
@@ -233,8 +234,10 @@ CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn()
 /* -------------------------------------------------------------------- */
 /*      Collect the rest of the fields.                                 */
 /* -------------------------------------------------------------------- */
-    std::set<CPLString> aosEmpty;
-    BuildFeatureDefn( pszViewName, hColStmt, osGeomColumn, aosEmpty );
+    std::set<CPLString> aosGeomCols;
+    std::set<CPLString> aosIgnoredCols;
+    aosGeomCols.insert(osGeomColumn);
+    BuildFeatureDefn( pszViewName, hColStmt, aosGeomCols, aosIgnoredCols );
     sqlite3_finalize( hColStmt );
 
 /* -------------------------------------------------------------------- */
@@ -242,12 +245,13 @@ CPLErr OGRSQLiteViewLayer::EstablishFeatureDefn()
 /* -------------------------------------------------------------------- */
     if( poFeatureDefn->GetGeomFieldCount() != 0 )
     {
-        poFeatureDefn->SetGeomType( poUnderlyingLayer->GetGeomType() );
+        OGRSQLiteGeomFieldDefn* poSrcGeomFieldDefn =
+            poUnderlyingLayer->myGetLayerDefn()->myGetGeomFieldDefn(nUnderlyingLayerGeomFieldIndex);
         OGRSQLiteGeomFieldDefn* poGeomFieldDefn =
             poFeatureDefn->myGetGeomFieldDefn(0);
-        poGeomFieldDefn->SetSpatialRef(poUnderlyingLayer->GetSpatialRef());
-        poGeomFieldDefn->nSRSId = poUnderlyingLayer->myGetLayerDefn()->
-            myGetGeomFieldDefn(0)->nSRSId;
+        poGeomFieldDefn->SetType(poSrcGeomFieldDefn->GetType());
+        poGeomFieldDefn->SetSpatialRef(poSrcGeomFieldDefn->GetSpatialRef());
+        poGeomFieldDefn->nSRSId = poSrcGeomFieldDefn->nSRSId;
         if( eGeomFormat != OSGF_None )
             poGeomFieldDefn->eGeomFormat = eGeomFormat;
     }
@@ -308,7 +312,7 @@ OGRFeature *OGRSQLiteViewLayer::GetNextFeature()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRSQLiteViewLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRSQLiteViewLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if (HasLayerDefnError())
@@ -403,8 +407,6 @@ void OGRSQLiteViewLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
 CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
                                               OGRGeometry* poFilterGeom)
 {
-    CPLString osSpatialWHERE;
-
     if (HasLayerDefnError() || poFeatureDefn == NULL ||
         iGeomCol < 0 || iGeomCol >= poFeatureDefn->GetGeomFieldCount())
         return "";
@@ -453,13 +455,10 @@ CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
 
         if (bHasSpatialIndex)
         {
-            osSpatialWHERE.Printf("\"%s\" IN ( SELECT pkid FROM 'idx_%s_%s' WHERE "
-                           "xmax > %.12f AND xmin < %.12f AND ymax > %.12f AND ymin < %.12f)",
-                            OGRSQLiteEscapeName(pszFIDColumn).c_str(),
-                            pszEscapedUnderlyingTableName,
-                            OGRSQLiteEscape(osUnderlyingGeometryColumn).c_str(),
-                            sEnvelope.MinX - 1e-11, sEnvelope.MaxX + 1e-11,
-                            sEnvelope.MinY - 1e-11, sEnvelope.MaxY + 1e-11);
+            return FormatSpatialFilterFromRTree(poFilterGeom,
+                CPLSPrintf("\"%s\"", OGRSQLiteEscapeName(pszFIDColumn).c_str()),
+                pszEscapedUnderlyingTableName,
+                OGRSQLiteEscape(osUnderlyingGeometryColumn).c_str());
         }
         else
         {
@@ -469,20 +468,13 @@ CPLString OGRSQLiteViewLayer::GetSpatialWhere(int iGeomCol,
 
     }
 
-    if( poFilterGeom != NULL && poDS->IsSpatialiteLoaded() && !bHasSpatialIndex )
+    if( poFilterGeom != NULL && poDS->IsSpatialiteLoaded() )
     {
-        OGREnvelope  sEnvelope;
-
-        poFilterGeom->getEnvelope( &sEnvelope );
-
-        /* A bit inefficient but still faster than OGR filtering */
-        osSpatialWHERE.Printf("MBRIntersects(\"%s\", BuildMBR(%.12f, %.12f, %.12f, %.12f))",
-                       OGRSQLiteEscapeName(poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()).c_str(),
-                       sEnvelope.MinX - 1e-11, sEnvelope.MinY - 1e-11,
-                       sEnvelope.MaxX + 1e-11, sEnvelope.MaxY + 1e-11);
+        return FormatSpatialFilterFromMBR(poFilterGeom,
+            OGRSQLiteEscapeName(poFeatureDefn->GetGeomFieldDefn(iGeomCol)->GetNameRef()).c_str());
     }
 
-    return osSpatialWHERE;
+    return "";
 }
 
 /************************************************************************/
@@ -551,7 +543,7 @@ int OGRSQLiteViewLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRSQLiteViewLayer::GetFeatureCount( int bForce )
+GIntBig OGRSQLiteViewLayer::GetFeatureCount( int bForce )
 
 {
     if (HasLayerDefnError())
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.cpp b/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.cpp
index b1cb666..9a66f00 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.cpp
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitevirtualogr.cpp 27950 2014-11-11 10:02:20Z rouault $
+ * $Id: ogrsqlitevirtualogr.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  SQLite Virtual Table module using OGR layers
@@ -30,6 +30,7 @@
 #include "ogrsqlitevirtualogr.h"
 #include "ogr_api.h"
 #include "swq.h"
+#include "ogr_p.h"
 #include <map>
 #include <vector>
 
@@ -89,7 +90,7 @@ class OGR2SQLITEModule
 #endif
     sqlite3* hDB; /* *NOT* to be freed */
 
-    OGRDataSource* poDS; /* *NOT* to be freed */
+    GDALDataset* poDS; /* *NOT* to be freed */
     std::vector<OGRDataSource*> apoExtraDS; /* each datasource to be freed */
 
     OGRSQLiteDataSource* poSQLiteDS;  /* *NOT* to be freed, might be NULL */
@@ -102,11 +103,11 @@ class OGR2SQLITEModule
                                  OGR2SQLITEModule();
                                 ~OGR2SQLITEModule();
 
-    int                          Setup(OGRDataSource* poDS,
+    int                          Setup(GDALDataset* poDS,
                                        OGRSQLiteDataSource* poSQLiteDS);
     int                          Setup(sqlite3* hDB);
 
-    OGRDataSource*               GetDS() { return poDS; }
+    GDALDataset*               GetDS() { return poDS; }
 
     int                          AddExtraDS(OGRDataSource* poDS);
     OGRDataSource               *GetExtraDS(int nIndex);
@@ -184,7 +185,7 @@ OGRDataSource* OGR2SQLITEModule::GetExtraDS(int nIndex)
 /*                                Setup()                               */
 /************************************************************************/
 
-int OGR2SQLITEModule::Setup(OGRDataSource* poDSIn,
+int OGR2SQLITEModule::Setup(GDALDataset* poDSIn,
                             OGRSQLiteDataSource* poSQLiteDSIn)
 {
     CPLAssert(poDS == NULL);
@@ -292,7 +293,7 @@ typedef struct
     /* Extension fields */
     char                 *pszVTableName;
     OGR2SQLITEModule     *poModule;
-    OGRDataSource        *poDS;
+    GDALDataset          *poDS;
     int                   bCloseDS;
     OGRLayer             *poLayer;
     int                   nMyRef;
@@ -316,9 +317,9 @@ typedef struct
     /* In which case nNextWishedIndex and nCurFeatureIndex */
     /* will be used to avoid useless GetNextFeature() */
     /* Helps in SELECT COUNT(*) FROM xxxx scenarios */
-    int            nFeatureCount;
-    int            nNextWishedIndex;
-    int            nCurFeatureIndex;
+    GIntBig        nFeatureCount;
+    GIntBig        nNextWishedIndex;
+    GIntBig        nCurFeatureIndex;
 
     GByte         *pabyGeomBLOB;
     int            nGeomBLOBLen;
@@ -438,7 +439,7 @@ int OGR2SQLITE_ConnectCreate(sqlite3* hDB, void *pAux,
 {
     OGR2SQLITEModule* poModule = (OGR2SQLITEModule*) pAux;
     OGRLayer* poLayer = NULL;
-    OGRDataSource* poDS = NULL;
+    GDALDataset* poDS = NULL;
     int bExposeOGR_STYLE = FALSE;
     int bCloseDS = FALSE;
     int bInternalUse = FALSE;
@@ -483,7 +484,7 @@ int OGR2SQLITE_ConnectCreate(sqlite3* hDB, void *pAux,
         if( poLayer == NULL )
         {
             *pzErr = sqlite3_mprintf( "Cannot find layer '%s' in '%s'",
-                                      osLayerName.c_str(), poDS->GetName() );
+                                      osLayerName.c_str(), poDS->GetDescription() );
             return SQLITE_ERROR;
         }
 
@@ -545,7 +546,7 @@ int OGR2SQLITE_ConnectCreate(sqlite3* hDB, void *pAux,
 
             if( poDS->GetLayerCount() > 1 )
             {
-                *pzErr = sqlite3_mprintf( "Datasource '%s' has more than one layers, and none was explicitely selected.",
+                *pzErr = sqlite3_mprintf( "Datasource '%s' has more than one layers, and none was explicitly selected.",
                                           osDSName.c_str() );
                 poDS->Release();
                 return SQLITE_ERROR;
@@ -605,7 +606,8 @@ int OGR2SQLITE_ConnectCreate(sqlite3* hDB, void *pAux,
         osSQL += OGRSQLiteEscapeName(poFieldDefn->GetNameRef());
         osSQL += "\"";
         osSQL += " ";
-        osSQL += OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn);
+        osSQL += OGRSQLiteFieldDefnToSQliteFieldDefn(poFieldDefn,
+                                                     bInternalUse);
     }
 
     if( bAddComma )
@@ -639,7 +641,7 @@ int OGR2SQLITE_ConnectCreate(sqlite3* hDB, void *pAux,
             osSQL += "_";
             osSQL += OGRToOGCGeomType(poFieldDefn->GetType());
             osSQL += "_";
-            osSQL += (poFieldDefn->GetType() & wkb25DBit) ? "25D" : "2D";
+            osSQL += wkbHasZ(poFieldDefn->GetType()) ? "25D" : "2D";
             OGRSpatialReference* poSRS = poFieldDefn->GetSpatialRef();
             if( poSRS == NULL && i == 0 )
                 poSRS = poLayer->GetSpatialRef();
@@ -829,7 +831,7 @@ int OGR2SQLITE_Open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
     else
     {
         poDupDataSource =
-            (OGRDataSource*) OGROpen(pMyVTab->poDS->GetName(), FALSE, NULL);
+            (OGRDataSource*) OGROpen(pMyVTab->poDS->GetDescription(), FALSE, NULL);
         if( poDupDataSource == NULL )
             return SQLITE_ERROR;
         poLayer = poDupDataSource->GetLayerByName(
@@ -898,8 +900,10 @@ int OGR2SQLITE_Close(sqlite3_vtab_cursor* pCursor)
 
 static
 int OGR2SQLITE_Filter(sqlite3_vtab_cursor* pCursor,
-                      CPL_UNUSED int idxNum, const char *idxStr,
-                      int argc, sqlite3_value **argv)
+                      CPL_UNUSED int idxNum,
+                      const char *idxStr,
+                      int argc,
+                      sqlite3_value **argv)
 {
     OGR2SQLITE_vtab_cursor* pMyCursor = (OGR2SQLITE_vtab_cursor*) pCursor;
 #ifdef DEBUG_OGR2SQLITE
@@ -945,24 +949,9 @@ int OGR2SQLITE_Filter(sqlite3_vtab_cursor* pCursor,
 
             if( bNeedsQuoting )
             {
-                /* FIXME: we would need some virtual method */
-                OGRSFDriver* poDriver = pMyCursor->pVTab->poDS->GetDriver();
-                char chQuote;
-
-                if (poDriver && (
-                    EQUAL(poDriver->GetName(), "PostgreSQL") ||
-                    EQUAL(poDriver->GetName(), "SQLite") ||
-                    EQUAL(poDriver->GetName(), "FileGDB" )) )
-                    chQuote = '"';
-                else
-                    chQuote = '\'';
-
-                osAttributeFilter += chQuote;
-                if( chQuote == '"' )
-                    osAttributeFilter += OGRSQLiteEscapeName(pszFieldName);
-                else
-                    osAttributeFilter += OGRSQLiteEscape(pszFieldName);
-                osAttributeFilter += chQuote;
+                osAttributeFilter += '"';
+                osAttributeFilter += OGRSQLiteEscapeName(pszFieldName);
+                osAttributeFilter += '"';
             }
             else
             {
@@ -995,7 +984,7 @@ int OGR2SQLITE_Filter(sqlite3_vtab_cursor* pCursor,
                 CPLSPrintf(CPL_FRMT_GIB, sqlite3_value_int64 (argv[i]));
         }
         else if (sqlite3_value_type (argv[i]) == SQLITE_FLOAT)
-        {
+        { // Insure that only Decimal.Points are used, never local settings such as Decimal.Comma.
             osAttributeFilter +=
                 CPLSPrintf("%.18g", sqlite3_value_double (argv[i]));
         }
@@ -1042,8 +1031,8 @@ int OGR2SQLITE_Filter(sqlite3_vtab_cursor* pCursor,
     {
         pMyCursor->poFeature = pMyCursor->poLayer->GetNextFeature();
 #ifdef DEBUG_OGR2SQLITE
-        CPLDebug("OGR2SQLITE", "GetNextFeature() --> %d",
-            pMyCursor->poFeature ? (int)pMyCursor->poFeature->GetFID() : -1);
+        CPLDebug("OGR2SQLITE", "GetNextFeature() --> " CPL_FRMT_GIB,
+            pMyCursor->poFeature ? pMyCursor->poFeature->GetFID() : -1);
 #endif
     }
 
@@ -1076,8 +1065,8 @@ int OGR2SQLITE_Next(sqlite3_vtab_cursor* pCursor)
         pMyCursor->nGeomBLOBLen = -1;
 
 #ifdef DEBUG_OGR2SQLITE
-        CPLDebug("OGR2SQLITE", "GetNextFeature() --> %d",
-            pMyCursor->poFeature ? (int)pMyCursor->poFeature->GetFID() : -1);
+        CPLDebug("OGR2SQLITE", "GetNextFeature() --> " CPL_FRMT_GIB,
+            pMyCursor->poFeature ? pMyCursor->poFeature->GetFID() : -1);
 #endif
     }
     return SQLITE_OK;
@@ -1122,8 +1111,8 @@ static void OGR2SQLITE_GoToWishedIndex(OGR2SQLITE_vtab_cursor* pMyCursor)
                 delete pMyCursor->poFeature;
                 pMyCursor->poFeature = pMyCursor->poLayer->GetNextFeature();
 #ifdef DEBUG_OGR2SQLITE
-                CPLDebug("OGR2SQLITE", "GetNextFeature() --> %d",
-                    pMyCursor->poFeature ? (int)pMyCursor->poFeature->GetFID() : -1);
+                CPLDebug("OGR2SQLITE", "GetNextFeature() --> " CPL_FRMT_GIB,
+                    pMyCursor->poFeature ? pMyCursor->poFeature->GetFID() : -1);
 #endif
             }
             while( pMyCursor->nCurFeatureIndex < pMyCursor->nNextWishedIndex );
@@ -1136,6 +1125,36 @@ static void OGR2SQLITE_GoToWishedIndex(OGR2SQLITE_vtab_cursor* pMyCursor)
 }
 
 /************************************************************************/
+/*                    OGR2SQLITE_ExportGeometry()                       */
+/************************************************************************/
+
+static void OGR2SQLITE_ExportGeometry(OGRGeometry* poGeom, int nSRSId,
+                                      GByte*& pabyGeomBLOB,
+                                      int& nGeomBLOBLen)
+{
+    if( OGRSQLiteLayer::ExportSpatiaLiteGeometry(
+            poGeom, nSRSId, wkbNDR, FALSE, FALSE, FALSE,
+            &pabyGeomBLOB,
+            &nGeomBLOBLen ) != CE_None )
+    {
+        nGeomBLOBLen = 0;
+    }
+    /* This is a hack: we add the original curve geometry after */
+    /* the spatialite blob */
+    else if( poGeom->hasCurveGeometry() )
+    {
+        int nWkbSize = poGeom->WkbSize();
+
+        pabyGeomBLOB = (GByte*) CPLRealloc(pabyGeomBLOB,
+                                nGeomBLOBLen + nWkbSize + 1);
+        poGeom->exportToWkb(wkbNDR, pabyGeomBLOB + nGeomBLOBLen);
+        /* Sheat a bit and add a end-of-blob spatialite marker */
+        pabyGeomBLOB[nGeomBLOBLen + nWkbSize] = 0xFE;
+        nGeomBLOBLen += nWkbSize + 1;
+    }
+}
+
+/************************************************************************/
 /*                         OGR2SQLITE_Column()                          */
 /************************************************************************/
 
@@ -1182,13 +1201,9 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
                 OGRSpatialReference* poSRS = poGeom->getSpatialReference();
                 int nSRSId = pMyCursor->pVTab->poModule->FetchSRSId(poSRS);
 
-                if( OGRSQLiteLayer::ExportSpatiaLiteGeometry(
-                        poGeom, nSRSId, wkbNDR, FALSE, FALSE, FALSE,
-                        &pMyCursor->pabyGeomBLOB,
-                        &pMyCursor->nGeomBLOBLen ) != CE_None )
-                {
-                    pMyCursor->nGeomBLOBLen = 0;
-                }
+                OGR2SQLITE_ExportGeometry(poGeom, nSRSId,
+                                          pMyCursor->pabyGeomBLOB,
+                                          pMyCursor->nGeomBLOBLen);
             }
         }
 
@@ -1223,12 +1238,7 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
 
             GByte* pabyGeomBLOB = NULL;
             int nGeomBLOBLen = 0;
-            if( OGRSQLiteLayer::ExportSpatiaLiteGeometry(
-                    poGeom, nSRSId, wkbNDR, FALSE, FALSE, FALSE,
-                    &pabyGeomBLOB, &nGeomBLOBLen ) != CE_None )
-            {
-                nGeomBLOBLen = 0;
-            }
+            OGR2SQLITE_ExportGeometry(poGeom, nSRSId, pabyGeomBLOB, nGeomBLOBLen);
 
             if( nGeomBLOBLen == 0 )
             {
@@ -1259,6 +1269,11 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
                                poFeature->GetFieldAsInteger(nCol));
             break;
 
+        case OFTInteger64:
+            sqlite3_result_int64(pContext,
+                               poFeature->GetFieldAsInteger64(nCol));
+            break;
+
         case OFTReal:
             sqlite3_result_double(pContext,
                                   poFeature->GetFieldAsDouble(nCol));
@@ -1274,15 +1289,9 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
 
         case OFTDateTime:
         {
-            int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ;
-            poFeature->GetFieldAsDateTime(nCol, &nYear, &nMonth, &nDay,
-                                          &nHour, &nMinute, &nSecond, &nTZ);
-            char szBuffer[64];
-            sprintf(szBuffer, "%04d-%02d-%02dT%02d:%02d:%02d",
-                    nYear, nMonth, nDay, nHour, nMinute, nSecond);
-            sqlite3_result_text(pContext,
-                                szBuffer,
-                                -1, SQLITE_TRANSIENT);
+            char* pszStr = OGRGetXMLDateTime(poFeature->GetRawFieldRef(nCol));
+            sqlite3_result_text(pContext, pszStr, -1, SQLITE_TRANSIENT);
+            CPLFree(pszStr);
             break;
         }
 
@@ -1292,7 +1301,7 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
             poFeature->GetFieldAsDateTime(nCol, &nYear, &nMonth, &nDay,
                                           &nHour, &nMinute, &nSecond, &nTZ);
             char szBuffer[64];
-            sprintf(szBuffer, "%04d-%02d-%02dT", nYear, nMonth, nDay);
+            sprintf(szBuffer, "%04d-%02d-%02d", nYear, nMonth, nDay);
             sqlite3_result_text(pContext,
                                 szBuffer,
                                 -1, SQLITE_TRANSIENT);
@@ -1301,11 +1310,15 @@ int OGR2SQLITE_Column(sqlite3_vtab_cursor* pCursor,
 
         case OFTTime:
         {
-            int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ;
+            int nYear, nMonth, nDay, nHour, nMinute, nTZ;
+            float fSecond;
             poFeature->GetFieldAsDateTime(nCol, &nYear, &nMonth, &nDay,
-                                          &nHour, &nMinute, &nSecond, &nTZ);
+                                        &nHour, &nMinute, &fSecond, &nTZ );
             char szBuffer[64];
-            sprintf(szBuffer, "%02d:%02d:%02d", nHour, nMinute, nSecond);
+            if( OGR_GET_MS(fSecond) != 0 )
+                sprintf(szBuffer, "%02d:%02d:%06.3f", nHour, nMinute, fSecond);
+            else
+                sprintf(szBuffer, "%02d:%02d:%02d", nHour, nMinute, (int)fSecond);
             sqlite3_result_text(pContext,
                                 szBuffer,
                                 -1, SQLITE_TRANSIENT);
@@ -1398,8 +1411,7 @@ static OGRFeature* OGR2SQLITE_FeatureFromArgs(OGRLayer* poLayer,
         switch( sqlite3_value_type(argv[2 + i]) )
         {
             case SQLITE_INTEGER:
-                //FIXME use int64 when OGR has 64bit integer support
-                poFeature->SetField(i, sqlite3_value_int(argv[2 + i]));
+                poFeature->SetField(i, sqlite3_value_int64(argv[2 + i]));
                 break;
             case SQLITE_FLOAT:
                 poFeature->SetField(i, sqlite3_value_double(argv[2 + i]));
@@ -1453,7 +1465,16 @@ static OGRFeature* OGR2SQLITE_FeatureFromArgs(OGRLayer* poLayer,
             if( OGRSQLiteLayer::ImportSpatiaLiteGeometry(
                             pabyBlob, nLen, &poGeom ) == CE_None )
             {
-                poFeature->SetGeomFieldDirectly(i, poGeom);
+/*                OGRwkbGeometryType eGeomFieldType =
+                    poFeature->GetDefnRef()->GetGeomFieldDefn(i)->GetType();
+                if( OGR_GT_IsCurve(eGeomFieldType) && !OGR_GT_IsCurve(poGeom->getGeometryType()) )
+                {
+                    OGRGeometry* poCurveGeom = poGeom->getCurveGeometry();
+                    poFeature->SetGeomFieldDirectly(i, poCurveGeom);
+                    delete poCurveGeom;
+                }
+                else*/
+                    poFeature->SetGeomFieldDirectly(i, poGeom);
             }
         }
     }
@@ -1710,7 +1731,7 @@ void OGR2SQLITE_ogr_layer_GeometryType(sqlite3_context* pContext,
     }
 
     const char* psz2DName = OGRToOGCGeomType(eType);
-    if( eType & wkb25DBit )
+    if( wkbHasZ(eType) )
         sqlite3_result_text( pContext, CPLSPrintf("%s Z", psz2DName), -1, SQLITE_TRANSIENT );
     else
         sqlite3_result_text( pContext, psz2DName, -1, SQLITE_TRANSIENT );
@@ -2209,7 +2230,7 @@ int OGR2SQLITESpatialIndex_Column(sqlite3_vtab_cursor* pCursor,
 
     if( nCol == 0 )
     {
-        CPLDebug("OGR2SQLITE", "--> FID = %ld", poFeature->GetFID());
+        CPLDebug("OGR2SQLITE", "--> FID = " CPL_FRMT_GIB, poFeature->GetFID());
         sqlite3_result_int64(pContext, poFeature->GetFID());
         return SQLITE_OK;
     }
@@ -2363,7 +2384,7 @@ int OGR2SQLITEModule::Setup(sqlite3* hDB)
 /*                        OGR2SQLITE_Setup()                            */
 /************************************************************************/
 
-OGR2SQLITEModule* OGR2SQLITE_Setup(OGRDataSource* poDS,
+OGR2SQLITEModule* OGR2SQLITE_Setup(GDALDataset* poDS,
                                    OGRSQLiteDataSource* poSQLiteDS)
 {
     OGR2SQLITEModule* poModule = new OGR2SQLITEModule();
diff --git a/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.h b/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.h
index b5f1994..2bf1433 100644
--- a/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.h
+++ b/ogr/ogrsf_frmts/sqlite/ogrsqlitevirtualogr.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsqlitevirtualogr.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrsqlitevirtualogr.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  SQLite Virtual Table module using OGR layers
@@ -36,7 +36,7 @@
 
 class OGR2SQLITEModule;
 
-OGR2SQLITEModule* OGR2SQLITE_Setup(OGRDataSource* poDS,
+OGR2SQLITEModule* OGR2SQLITE_Setup(GDALDataset* poDS,
                                    OGRSQLiteDataSource* poSQLiteDS);
 
 int OGR2SQLITE_AddExtraDS(OGR2SQLITEModule* poModule, OGRDataSource* poDS);
diff --git a/ogr/ogrsf_frmts/sua/GNUmakefile b/ogr/ogrsf_frmts/sua/GNUmakefile
index 4ec0f3f..98262f0 100644
--- a/ogr/ogrsf_frmts/sua/GNUmakefile
+++ b/ogr/ogrsf_frmts/sua/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrsuadriver.o ogrsuadatasource.o ogrsualayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../xplane $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../xplane  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sua/ogr_sua.h b/ogr/ogrsf_frmts/sua/ogr_sua.h
index 221924f..a6b3a75 100644
--- a/ogr/ogrsf_frmts/sua/ogr_sua.h
+++ b/ogr/ogrsf_frmts/sua/ogr_sua.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_sua.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_sua.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SUA Translator
  * Purpose:  Definition of classes for OGR .sua driver.
@@ -78,8 +78,7 @@ class OGRSUADataSource : public OGRDataSource
                         OGRSUADataSource();
                         ~OGRSUADataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -89,19 +88,4 @@ class OGRSUADataSource : public OGRDataSource
     virtual int                 TestCapability( const char * );
 };
 
-/************************************************************************/
-/*                             OGRSUADriver                             */
-/************************************************************************/
-
-class OGRSUADriver : public OGRSFDriver
-{
-  public:
-                ~OGRSUADriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
-};
-
-
 #endif /* ndef _OGR_SUA_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/sua/ogrsuadatasource.cpp b/ogr/ogrsf_frmts/sua/ogrsuadatasource.cpp
index 71d3406..2425836 100644
--- a/ogr/ogrsf_frmts/sua/ogrsuadatasource.cpp
+++ b/ogr/ogrsf_frmts/sua/ogrsuadatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsuadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsuadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SUA Translator
  * Purpose:  Implements OGRSUADataSource class
@@ -31,7 +31,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrsuadatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsuadatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          OGRSUADataSource()                          */
@@ -86,42 +86,18 @@ OGRLayer *OGRSUADataSource::GetLayer( int iLayer )
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRSUADataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRSUADataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        return FALSE;
-    }
-
     pszName = CPLStrdup( pszFilename );
 
-// -------------------------------------------------------------------- 
-//      Does this appear to be a .sua file?
-// --------------------------------------------------------------------
-
     VSILFILE* fp = VSIFOpenL(pszFilename, "rb");
     if (fp == NULL)
         return FALSE;
 
-    char szBuffer[10000];
-    int nbRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
-    szBuffer[nbRead] = '\0';
-
-    int bIsSUA = (strstr(szBuffer, "\nTYPE=") != NULL &&
-                  strstr(szBuffer, "\nTITLE=") != NULL &&
-                  (strstr(szBuffer, "\nPOINT=") != NULL ||
-                   strstr(szBuffer, "\nCIRCLE ") != NULL));
-
-    if (bIsSUA)
-    {
-        VSIFSeekL( fp, 0, SEEK_SET );
-        nLayers = 1;
-        papoLayers = (OGRLayer**) CPLMalloc(sizeof(OGRLayer*));
-        papoLayers[0] = new OGRSUALayer(fp);
-    }
-    else
-        VSIFCloseL(fp);
+    nLayers = 1;
+    papoLayers = (OGRLayer**) CPLMalloc(sizeof(OGRLayer*));
+    papoLayers[0] = new OGRSUALayer(fp);
 
-    return bIsSUA;
+    return TRUE;
 }
diff --git a/ogr/ogrsf_frmts/sua/ogrsuadriver.cpp b/ogr/ogrsf_frmts/sua/ogrsuadriver.cpp
index 50160f0..5f92368 100644
--- a/ogr/ogrsf_frmts/sua/ogrsuadriver.cpp
+++ b/ogr/ogrsf_frmts/sua/ogrsuadriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsuadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsuadriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SUA Translator
  * Purpose:  Implements OGRSUADriver.
@@ -30,39 +30,32 @@
 #include "ogr_sua.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsuadriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsuadriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 extern "C" void RegisterOGRSUA();
 
 /************************************************************************/
-/*                           ~OGRSUADriver()                            */
-/************************************************************************/
-
-OGRSUADriver::~OGRSUADriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRSUADriver::GetName()
-
-{
-    return "SUA";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRSUADriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRSUADriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( poOpenInfo->eAccess == GA_Update ||
+        poOpenInfo->fpL == NULL ||
+        !poOpenInfo->TryToIngest(10000) )
+        return NULL;
+
+    int bIsSUA = ( strstr((const char*)poOpenInfo->pabyHeader, "\nTYPE=") != NULL &&
+            strstr((const char*)poOpenInfo->pabyHeader, "\nTITLE=") != NULL &&
+            (strstr((const char*)poOpenInfo->pabyHeader, "\nPOINT=") != NULL ||
+            strstr((const char*)poOpenInfo->pabyHeader, "\nCIRCLE ") != NULL));
+    if( !bIsSUA )
+        return NULL;
+
     OGRSUADataSource   *poDS = new OGRSUADataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -72,21 +65,30 @@ OGRDataSource *OGRSUADriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRSUADriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRSUA()                           */
 /************************************************************************/
 
 void RegisterOGRSUA()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSUADriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "SUA" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "SUA" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Tim Newport-Peace's Special Use Airspace Format" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_sua.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSUADriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/sua/ogrsualayer.cpp b/ogr/ogrsf_frmts/sua/ogrsualayer.cpp
index 1966d53..a3df456 100644
--- a/ogr/ogrsf_frmts/sua/ogrsualayer.cpp
+++ b/ogr/ogrsf_frmts/sua/ogrsualayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsualayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsualayer.cpp 27942 2014-11-11 00:57:41Z rouault $
  *
  * Project:  SUA Translator
  * Purpose:  Implements OGRSUALayer class.
@@ -34,7 +34,7 @@
 #include "ogr_xplane_geo_utils.h"
 #include "ogr_srs_api.h"
 
-CPL_CVSID("$Id: ogrsualayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsualayer.cpp 27942 2014-11-11 00:57:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRSUALayer()                             */
@@ -51,6 +51,7 @@ OGRSUALayer::OGRSUALayer( VSILFILE* fp )
     poSRS = new OGRSpatialReference(SRS_WKT_WGS84);
 
     poFeatureDefn = new OGRFeatureDefn( "layer" );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     poFeatureDefn->SetGeomType( wkbPolygon );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
@@ -256,7 +257,7 @@ OGRFeature *OGRSUALayer::GetNextRawFeature()
             /*const char* pszRADIUS = strstr(pszLine, "RADIUS=");
             if (pszRADIUS == NULL)
                 continue;
-            double dfRADIUS = atof(pszRADIUS + 7) * 1852;*/
+            double dfRADIUS = CPLAtof(pszRADIUS + 7) * 1852;*/
 
             const char* pszCENTRE = strstr(pszLine, "CENTRE=");
             if (pszCENTRE == NULL)
@@ -307,7 +308,7 @@ OGRFeature *OGRSUALayer::GetNextRawFeature()
             const char* pszRADIUS = strstr(pszLine, "RADIUS=");
             if (pszRADIUS == NULL)
                 continue;
-            double dfRADIUS = atof(pszRADIUS + 7) * 1852;
+            double dfRADIUS = CPLAtof(pszRADIUS + 7) * 1852;
 
             const char* pszCENTRE = strstr(pszLine, "CENTRE=");
             if (pszCENTRE == NULL)
@@ -365,4 +366,3 @@ int OGRSUALayer::TestCapability( CPL_UNUSED const char * pszCap )
 {
     return FALSE;
 }
-
diff --git a/ogr/ogrsf_frmts/svg/GNUmakefile b/ogr/ogrsf_frmts/svg/GNUmakefile
index 1c4ba60..e9144b5 100644
--- a/ogr/ogrsf_frmts/svg/GNUmakefile
+++ b/ogr/ogrsf_frmts/svg/GNUmakefile
@@ -8,7 +8,7 @@ ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=   -DHAVE_EXPAT
 endif
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(EXPAT_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/svg/ogr_svg.h b/ogr/ogrsf_frmts/svg/ogr_svg.h
index a741616..5fe49ee 100644
--- a/ogr/ogrsf_frmts/svg/ogr_svg.h
+++ b/ogr/ogrsf_frmts/svg/ogr_svg.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_svg.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_svg.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  SVG Translator
  * Purpose:  Definition of classes for OGR .svg driver.
@@ -80,10 +80,12 @@ class OGRSVGLayer : public OGRLayer
     int                inInterestingElement;
 
     int                bStopParsing;
+#ifdef HAVE_EXPAT
     int                nWithoutEventCounter;
     int                nDataHandlerCounter;
 
     OGRSVGLayer       *poCurLayer;
+#endif
 
   private:
     void               LoadSchema();
@@ -101,7 +103,7 @@ class OGRSVGLayer : public OGRLayer
     virtual const char*         GetName() { return osLayerName.c_str(); }
     virtual OGRwkbGeometryType  GetGeomType();
 
-    virtual int                 GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig             GetFeatureCount( int bForce = TRUE );
 
     virtual OGRFeatureDefn *    GetLayerDefn();
     
@@ -136,7 +138,9 @@ class OGRSVGDataSource : public OGRDataSource
     OGRSVGLayer**       papoLayers;
     int                 nLayers;
 
+#ifdef HAVE_EXPAT
     OGRSVGValidity      eValidity;
+#endif
     int                 bIsCloudmade;
 
 #ifdef HAVE_EXPAT
@@ -148,8 +152,7 @@ class OGRSVGDataSource : public OGRDataSource
                         OGRSVGDataSource();
                         ~OGRSVGDataSource();
 
-    int                 Open( const char * pszFilename,
-                              int bUpdate );
+    int                 Open( const char * pszFilename );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -165,19 +168,4 @@ class OGRSVGDataSource : public OGRDataSource
 #endif
 };
 
-/************************************************************************/
-/*                             OGRSVGDriver                             */
-/************************************************************************/
-
-class OGRSVGDriver : public OGRSFDriver
-{
-  public:
-                ~OGRSVGDriver();
-
-    const char*         GetName();
-    OGRDataSource*      Open( const char *, int );
-
-    virtual int                 TestCapability( const char * );
-};
-
 #endif /* ndef _OGR_SVG_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp b/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp
index 47665c3..51a57f5 100644
--- a/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp
+++ b/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsvgdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsvgdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  SVG Translator
  * Purpose:  Implements OGRSVGDataSource class
@@ -30,7 +30,7 @@
 #include "ogr_svg.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsvgdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsvgdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          OGRSVGDataSource()                          */
@@ -110,7 +110,8 @@ void OGRSVGDataSource::startElementValidateCbk(const char *pszName,
 /*                      dataHandlerValidateCbk()                        */
 /************************************************************************/
 
-void OGRSVGDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data, CPL_UNUSED int nLen)
+void OGRSVGDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data,
+                                              CPL_UNUSED int nLen)
 {
     nDataHandlerCounter ++;
     if (nDataHandlerCounter >= BUFSIZ)
@@ -140,15 +141,9 @@ static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, in
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRSVGDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRSVGDataSource::Open( const char * pszFilename )
 
 {
-    if (bUpdateIn)
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-                    "OGR/SVG driver does not support opening a file in update mode");
-        return FALSE;
-    }
 #ifdef HAVE_EXPAT
     pszName = CPLStrdup( pszFilename );
 
diff --git a/ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp b/ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp
index 2591fee..fd929e3 100644
--- a/ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp
+++ b/ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsvgdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsvgdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  SVG Translator
  * Purpose:  Implements OGRSVGDriver.
@@ -30,7 +30,7 @@
 #include "ogr_svg.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsvgdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsvgdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
 CPL_C_START
 void RegisterOGRSVG();
@@ -39,39 +39,21 @@ CPL_C_END
 // g++ -g -Wall -fPIC ogr/ogrsf_frmts/svg/*.c* -shared -o ogr_SVG.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/svg -L. -lgdal -DHAVE_EXPAT
 
 /************************************************************************/
-/*                           ~OGRSVGDriver()                            */
-/************************************************************************/
-
-OGRSVGDriver::~OGRSVGDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRSVGDriver::GetName()
-
-{
-    return "SVG";
-}
-
-/************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRSVGDriver::Open( const char * pszFilename, int bUpdate )
+GDALDataset *OGRSVGDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
-    if (bUpdate)
-    {
+    if( poOpenInfo->eAccess == GA_Update || poOpenInfo->fpL == NULL )
+        return NULL;
+
+    if( strstr((const char*)poOpenInfo->pabyHeader, "<svg") == NULL )
         return NULL;
-    }
 
     OGRSVGDataSource   *poDS = new OGRSVGDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename ) )
     {
         delete poDS;
         poDS = NULL;
@@ -81,15 +63,6 @@ OGRDataSource *OGRSVGDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                            TestCapability()                          */
-/************************************************************************/
-
-int OGRSVGDriver::TestCapability( CPL_UNUSED const char *pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRSVG()                           */
 /************************************************************************/
 
@@ -98,6 +71,25 @@ void RegisterOGRSVG()
 {
     if (! GDAL_CHECK_VERSION("OGR/SVG driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSVGDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "SVG" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "SVG" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Scalable Vector Graphics" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "svg" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_svg.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRSVGDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp b/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp
index 2ad5283..a6ef58f 100644
--- a/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp
+++ b/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsvglayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrsvglayer.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  SVG Translator
  * Purpose:  Implements OGRSVGLayer class.
@@ -30,7 +30,7 @@
 #include "ogr_svg.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrsvglayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrsvglayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRSVGLayer()                             */
@@ -47,6 +47,7 @@ OGRSVGLayer::OGRSVGLayer( const char* pszFilename,
     this->poDS = poDS;
     this->svgGeomType = svgGeomType;
     osLayerName = pszLayerName;
+    SetDescription( pszLayerName );
 
     poFeatureDefn = NULL;
 
@@ -777,7 +778,8 @@ void OGRSVGLayer::endElementLoadSchemaCbk(CPL_UNUSED const char *pszName)
 /*                   dataHandlerLoadSchemaCbk()                         */
 /************************************************************************/
 
-void OGRSVGLayer::dataHandlerLoadSchemaCbk(CPL_UNUSED const char *data, CPL_UNUSED int nLen)
+void OGRSVGLayer::dataHandlerLoadSchemaCbk(CPL_UNUSED const char *data,
+                                           CPL_UNUSED int nLen)
 {
     if (bStopParsing) return;
 
@@ -831,7 +833,7 @@ OGRwkbGeometryType OGRSVGLayer::GetGeomType()
 /*                           GetGeomType()                              */
 /************************************************************************/
 
-int OGRSVGLayer::GetFeatureCount( int bForce )
+GIntBig OGRSVGLayer::GetFeatureCount( int bForce )
 {
     if (m_poAttrQuery != NULL || m_poFilterGeom != NULL)
         return OGRLayer::GetFeatureCount(bForce);
diff --git a/ogr/ogrsf_frmts/sxf/GNUmakefile b/ogr/ogrsf_frmts/sxf/GNUmakefile
index f13c8c0..51d15e2 100644
--- a/ogr/ogrsf_frmts/sxf/GNUmakefile
+++ b/ogr/ogrsf_frmts/sxf/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrsxfdriver.o ogrsxfdatasource.o ogrsxflayer.o
 
-CPPFLAGS	:=	-I.. -I../..  $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..   $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/sxf/ogr_sxf.h b/ogr/ogrsf_frmts/sxf/ogr_sxf.h
index c76649e..4dcf01d 100644
--- a/ogr/ogrsf_frmts/sxf/ogr_sxf.h
+++ b/ogr/ogrsf_frmts/sxf/ogr_sxf.h
@@ -60,7 +60,7 @@ protected:
     std::set<GUInt16> snAttributeCodes;
     int m_nSXFFormatVer;
     CPLString sFIDColumn_;
-    void            **m_hIOMutex;
+    CPLMutex            **m_hIOMutex;
     double              m_dfCoeff;
     virtual OGRFeature *       GetNextRawFeature(long nFID);
 
@@ -75,25 +75,25 @@ protected:
     OGRFeature *TranslateLine(const SXFRecordDescription& certifInfo, const char * psBuff, GUInt32 nBufLen);
     OGRFeature *TranslateVetorAngle(const SXFRecordDescription& certifInfo, const char * psBuff, GUInt32 nBufLen);
 public:
-    OGRSXFLayer(VSILFILE* fp, void** hIOMutex, GByte nID, const char* pszLayerName, int nVer, const SXFMapDescription&  sxfMapDesc);
+    OGRSXFLayer(VSILFILE* fp, CPLMutex** hIOMutex, GByte nID, const char* pszLayerName, int nVer, const SXFMapDescription&  sxfMapDesc);
     ~OGRSXFLayer();
 
 	virtual void                ResetReading();
     virtual OGRFeature         *GetNextFeature();
-    virtual OGRErr              SetNextByIndex(long nIndex);
-    virtual OGRFeature         *GetFeature(long nFID);
+    virtual OGRErr              SetNextByIndex(GIntBig nIndex);
+    virtual OGRFeature         *GetFeature(GIntBig nFID);
     virtual OGRFeatureDefn     *GetLayerDefn() { return poFeatureDefn;}
 
     virtual int                 TestCapability( const char * );
 
-    virtual int         GetFeatureCount(int bForce = TRUE);
+    virtual GIntBig     GetFeatureCount(int bForce = TRUE);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
     virtual OGRSpatialReference *GetSpatialRef();
     virtual const char* GetFIDColumn();
 
     virtual GByte GetId() const { return nLayerID; };
     virtual void AddClassifyCode(unsigned nClassCode, const char *szName = NULL);
-    virtual int AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset, bool bHasSemantic, int nSemanticsSize);
+    virtual int AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset, bool bHasSemantic, size_t nSemanticsSize);
 };
 
 
@@ -111,7 +111,7 @@ class OGRSXFDataSource : public OGRDataSource
     size_t              nLayers;
 
     VSILFILE* fpSXF;    
-
+    CPLMutex  *hIOMutex;
     void FillLayers(void);
     void CreateLayers();
     void CreateLayers(VSILFILE* fpRSC);
diff --git a/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp b/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp
index 3c5c22b..be15e01 100644
--- a/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp
+++ b/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp
@@ -42,8 +42,6 @@
 
 CPL_CVSID("$Id: ogrsxfdatasource.cpp  $");
 
-static void  *hIOMutex = NULL;
-
 static const long aoVCS[] =
 {
     0,
@@ -89,6 +87,7 @@ OGRSXFDataSource::OGRSXFDataSource()
     nLayers = 0;
 
     fpSXF = NULL;
+    hIOMutex = NULL;
 
     oSXFPassport.stMapDescription.pSpatRef = NULL;
 }
@@ -198,7 +197,7 @@ int OGRSXFDataSource::Open( const char * pszFilename, int bUpdateIn)
         oSXFPassport.version = stSXFFileHeader.nFormatVersion[1];
     }
 
-    if ( oSXFPassport.version == 0 )
+    if ( oSXFPassport.version < 3 )
     {
         CPLError(CE_Failure, CPLE_NotSupported , "SXF File version not supported");
         CloseFile();
@@ -246,30 +245,52 @@ int OGRSXFDataSource::Open( const char * pszFilename, int bUpdateIn)
 
 /*---------------- TRY READ THE RSC FILE HEADER  -----------------------*/
 
-    CPLString pszRSCRileName = CPLGetConfigOption("SXF_RSC_FILENAME", "");
-    if (CPLCheckForFile((char *)pszRSCRileName.c_str(), NULL) == FALSE)
+    CPLString soRSCRileName;
+    const char* pszRSCRileName = CPLGetConfigOption("SXF_RSC_FILENAME", "");
+    if (CPLCheckForFile((char *)pszRSCRileName, NULL) == TRUE)
+    {
+        soRSCRileName = pszRSCRileName;
+    }
+
+    if(soRSCRileName.empty())
     {
         pszRSCRileName = CPLResetExtension(pszFilename, "rsc");
-        if (CPLCheckForFile((char *)pszRSCRileName.c_str(), NULL) == FALSE)
+        if (CPLCheckForFile((char *)pszRSCRileName, NULL) == TRUE)
+        {
+            soRSCRileName = pszRSCRileName;
+        }
+    }
+
+    if(soRSCRileName.empty())
+    {
+        pszRSCRileName = CPLResetExtension(pszFilename, "RSC");
+        if (CPLCheckForFile((char *)pszRSCRileName, NULL) == TRUE)
         {
-            CPLError(CE_Warning, CPLE_None, "RSC file %s not exist", pszRSCRileName.c_str());
-            pszRSCRileName.Clear();
+            soRSCRileName = pszRSCRileName;
         }
     }
 
+
     //1. Create layers from RSC file or create default set of layers from osm.rsc
 
-    if (!pszRSCRileName.empty())
+    if (soRSCRileName.empty())
+    { 
+        CPLError(CE_Warning, CPLE_None, "RSC file for %s not exist", pszFilename);
+    }
+    else
     {
         VSILFILE* fpRSC;
 
-        fpRSC = VSIFOpenL(pszRSCRileName, "rb");
+        fpRSC = VSIFOpenL(soRSCRileName, "rb");
         if (fpRSC == NULL)
         {
-            CPLError(CE_Warning, CPLE_OpenFailed, "RSC open file %s failed", pszFilename);
+            CPLError(CE_Warning, CPLE_OpenFailed, "RSC file %s open failed",
+                     soRSCRileName.c_str());
         }
         else
         {
+            CPLDebug( "OGRSXFDataSource", "RSC Filename: %s",
+                      soRSCRileName.c_str() );
             CreateLayers(fpRSC);
             VSIFCloseL(fpRSC);
         }
@@ -457,8 +478,7 @@ void OGRSXFDataSource::SetVertCS(const long iVCS, SXFPassport& passport)
 
     if (nEPSG == 0)
     {
-        CPLError( CE_Warning, CPLE_NotSupported,
-                  CPLString().Printf("SXF. Vertical coordinate system (SXF index %ld) not supported", iVCS) );
+        CPLError(CE_Warning, CPLE_NotSupported, "SXF. Vertical coordinate system (SXF index %ld) not supported", iVCS);
         return;
     }
 
@@ -466,15 +486,13 @@ void OGRSXFDataSource::SetVertCS(const long iVCS, SXFPassport& passport)
     OGRErr eImportFromEPSGErr = sr->importFromEPSG(nEPSG);
     if (eImportFromEPSGErr != OGRERR_NONE)
     {
-        CPLError( CE_Warning, CPLE_None,
-                  CPLString().Printf("SXF. Vertical coordinate system (SXF index %ld, EPSG %ld) import from EPSG error", iVCS, nEPSG) );
+        CPLError( CE_Warning, CPLE_None, "SXF. Vertical coordinate system (SXF index %ld, EPSG %ld) import from EPSG error", iVCS, nEPSG);
         return;
     }
 
     if (sr->IsVertical() != 1)
     {
-        CPLError( CE_Warning, CPLE_None,
-                  CPLString().Printf("SXF. Coordinate system (SXF index %ld, EPSG %ld) is not Vertical", iVCS, nEPSG) );
+        CPLError( CE_Warning, CPLE_None, "SXF. Coordinate system (SXF index %ld, EPSG %ld) is not Vertical", iVCS, nEPSG);
         return;
     }
 
@@ -482,14 +500,13 @@ void OGRSXFDataSource::SetVertCS(const long iVCS, SXFPassport& passport)
     OGRErr eSetVertCSErr = passport.stMapDescription.pSpatRef->SetVertCS(sr->GetAttrValue("VERT_CS"), sr->GetAttrValue("VERT_DATUM"));
     if (eSetVertCSErr != OGRERR_NONE)
     {
-        CPLError( CE_Warning, CPLE_None,
-                  CPLString().Printf("SXF. Vertical coordinate system (SXF index %ld, EPSG %ld) set error", iVCS, nEPSG) );
+        CPLError(CE_Warning, CPLE_None, "SXF. Vertical coordinate system (SXF index %ld, EPSG %ld) set error", iVCS, nEPSG);
         return;
     }
 }
 OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE* fpSXF, SXFPassport& passport)
 {
-    /* int nObjectsRead; */
+    /* int nObjectsRead;*/
     int i;
     passport.stMapDescription.Env.MaxX = -100000000;
     passport.stMapDescription.Env.MinX = 100000000;
@@ -733,7 +750,7 @@ OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE* fpSXF, SXFPassport& pas
     {
         double dfCenterLongEnv = passport.stMapDescription.stGeoCoords[1] + fabs(passport.stMapDescription.stGeoCoords[5] - passport.stMapDescription.stGeoCoords[1]) / 2;
 
-        int nZoneEnv = (dfCenterLongEnv + 3.0) / 6.0 + 0.5;
+        int nZoneEnv = (int)( (dfCenterLongEnv + 3.0) / 6.0 + 0.5 );
 
         if (nZoneEnv > 1 && nZoneEnv < 33)
         {
@@ -759,7 +776,7 @@ OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE* fpSXF, SXFPassport& pas
     else if (iEllips == 9 && iProjSys == 17) // WGS84 / UTM
     {
         double dfCenterLongEnv = passport.stMapDescription.stGeoCoords[1] + fabs(passport.stMapDescription.stGeoCoords[5] - passport.stMapDescription.stGeoCoords[1]) / 2;
-        int nZoneEnv = 30 + (dfCenterLongEnv + 3.0) / 6.0 + 0.5;
+        int nZoneEnv = (int)(30 + (dfCenterLongEnv + 3.0) / 6.0 + 0.5);
         bool bNorth = passport.stMapDescription.stGeoCoords[6] + (passport.stMapDescription.stGeoCoords[2] - passport.stMapDescription.stGeoCoords[6]) / 2 < 0;
         int nEPSG;
         if (bNorth)
@@ -782,10 +799,12 @@ OGRErr OGRSXFDataSource::ReadSXFMapDescription(VSILFILE* fpSXF, SXFPassport& pas
         SetVertCS(iVCS, passport);
         return eErr;
     }
-    else if (iEllips == 9 && iProjSys == 34) //Miller 54003
+    else if (iEllips == 9 && iProjSys == 34) //Miller 54003 on sphere wgs84
     {
-        passport.stMapDescription.pSpatRef = new OGRSpatialReference();
-        OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(54003);
+        passport.stMapDescription.pSpatRef = new OGRSpatialReference("PROJCS[\"World_Miller_Cylindrical\",GEOGCS[\"GCS_GLOBE\", DATUM[\"GLOBE\", SPHEROID[\"GLOBE\", 6367444.6571, 0.0]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]],PROJECTION[\"Miller_Cylindrical\"],PARAMETER[\"False_Easting\",0],PARAMETER[\"False_Northing\",0],PARAMETER[\"Central_Meridian\",0],UNIT[\"Meter\",1],AUTHORITY[\"EPSG\",\"54003\"]]");
+        OGRErr eErr = OGRERR_NONE; //passport.stMapDescription.pSpatRef->importFromEPSG(3395);
+        //OGRErr eErr = passport.stMapDescription.pSpatRef->importFromEPSG(54003);
+
         SetVertCS(iVCS, passport);
         return eErr;
     }
@@ -818,11 +837,11 @@ void OGRSXFDataSource::FillLayers()
     CPLDebug("SXF","Create layers");
 
     //2. Read all records (only classify code and offset) and add this to correspondence layer
-    long nFID;
+    GUInt32 nFID;
     int nObjectsRead = 0;
     size_t i;
     vsi_l_offset nOffset = 0, nOffsetSemantic;
-    int nDeletedLayerIndex;
+    size_t nDeletedLayerIndex;
 
     //get record count
     GUInt32 nRecordCountMax = 0;
@@ -855,7 +874,7 @@ void OGRSXFDataSource::FillLayers()
 
         if (nObjectsRead != 1 || buff[0] != IDSXFOBJ)
         {
-            CPLError(CE_Failure, CPLE_FileIO, "Read record %ld failed", nFID);
+            CPLError(CE_Failure, CPLE_FileIO, "Read record %d failed", nFID);
             return;
         }
 
@@ -893,7 +912,7 @@ void OGRSXFDataSource::FillLayers()
         {
             delete pOGRSXFLayer;
             nDeletedLayerIndex = i;
-            while (nDeletedLayerIndex < (int)(nLayers - 1))
+            while (nDeletedLayerIndex < nLayers - 1)
             {
                 papoLayers[nDeletedLayerIndex] = papoLayers[nDeletedLayerIndex + 1];
                 nDeletedLayerIndex++;
@@ -1202,7 +1221,7 @@ void OGRSXFDataSource::CreateLayers(VSILFILE* fpRSC)
         GUInt16 nSematicCount;
     };
 
-    int i;
+    GUInt32 i;
     size_t nLayerStructSize = sizeof(_layer);
 
     VSIFSeekL(fpRSC, stRSCFileHeader.Layers.nOffset - sizeof(szLayersID), SEEK_SET);
@@ -1210,7 +1229,7 @@ void OGRSXFDataSource::CreateLayers(VSILFILE* fpRSC)
     vsi_l_offset nOffset = stRSCFileHeader.Layers.nOffset;
     _layer LAYER;
 
-    for (i = 0; (GUInt32)i < stRSCFileHeader.Layers.nRecordCount; ++i)
+    for (i = 0; i < stRSCFileHeader.Layers.nRecordCount; ++i)
     {
         VSIFReadL(&LAYER, nLayerStructSize, 1, fpRSC);
 
diff --git a/ogr/ogrsf_frmts/sxf/ogrsxfdriver.cpp b/ogr/ogrsf_frmts/sxf/ogrsxfdriver.cpp
index 8f06ce4..92a3a80 100644
--- a/ogr/ogrsf_frmts/sxf/ogrsxfdriver.cpp
+++ b/ogr/ogrsf_frmts/sxf/ogrsxfdriver.cpp
@@ -92,7 +92,7 @@ OGRErr OGRSXFDriver::DeleteDataSource(const char* pszName)
 {
     int iExt;
     //TODO: add more extensions if aplicable
-    static const char *apszExtensions[] = { "szf", "rsc", NULL }; 
+    static const char *apszExtensions[] = { "szf", "rsc", "SZF", "RSC", NULL };
 
     VSIStatBufL sStatBuf;
     if (VSIStatL(pszName, &sStatBuf) != 0)
@@ -133,7 +133,13 @@ int OGRSXFDriver::TestCapability( const char * pszCap )
 /************************************************************************/
 void RegisterOGRSXF()
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRSXFDriver );   
+    OGRSFDriver* poDriver = new OGRSXFDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "Storage and eXchange Format" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_sxf.html" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sxf" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
 
diff --git a/ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp b/ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp
index 12baf40..5459cc5 100644
--- a/ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp
+++ b/ogr/ogrsf_frmts/sxf/ogrsxflayer.cpp
@@ -45,7 +45,7 @@ CPL_CVSID("$Id: ogrsxflayer.cpp $");
 /*                        OGRSXFLayer()                                 */
 /************************************************************************/
 
-OGRSXFLayer::OGRSXFLayer(VSILFILE* fp, void** hIOMutex, GByte nID, const char* pszLayerName, int nVer, const SXFMapDescription&  sxfMapDesc) : OGRLayer()
+OGRSXFLayer::OGRSXFLayer(VSILFILE* fp, CPLMutex** hIOMutex, GByte nID, const char* pszLayerName, int nVer, const SXFMapDescription&  sxfMapDesc) : OGRLayer()
 {
     sFIDColumn_ = "ogc_fid";
     fpSXF = fp;
@@ -57,6 +57,7 @@ OGRSXFLayer::OGRSXFLayer(VSILFILE* fp, void** hIOMutex, GByte nID, const char* p
     m_hIOMutex = hIOMutex;
     m_dfCoeff = stSXFMapDescription.dfScale / stSXFMapDescription.nResolution;
     poFeatureDefn = new OGRFeatureDefn(pszLayerName);
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
     
     poFeatureDefn->SetGeomType(wkbUnknown);
@@ -124,7 +125,7 @@ void OGRSXFLayer::AddClassifyCode(unsigned nClassCode, const char *szName)
 /*                         AddRecord()                               */
 /************************************************************************/
 
-int OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset, bool bHasSemantic, int nSemanticsSize)
+int OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset, bool bHasSemantic, size_t nSemanticsSize)
 {
     if (mnClassificators.empty() || mnClassificators.find(nClassCode) != mnClassificators.end())
     {
@@ -134,7 +135,7 @@ int OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset,
         {
             size_t offset = 0;
 
-            while (offset < (size_t)nSemanticsSize)
+            while (offset < nSemanticsSize)
             {
                 SXFRecordAttributeInfo stAttrInfo;
                 bool bAddField = false;
@@ -234,7 +235,7 @@ int OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset,
                             oField.SetWidth(255);
                             poFeatureDefn->AddFieldDefn(&oField);
                         }
-                        unsigned nLen = unsigned(stAttrInfo.nScale) + 1;
+                        unsigned nLen = (unsigned(stAttrInfo.nScale) + 1) * 2;
                         offset += nLen;
                         nCurrOff = nLen;
                         break;
@@ -274,9 +275,9 @@ int OGRSXFLayer::AddRecord(long nFID, unsigned nClassCode, vsi_l_offset nOffset,
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr OGRSXFLayer::SetNextByIndex(long nIndex)
+OGRErr OGRSXFLayer::SetNextByIndex(GIntBig nIndex)
 {
-  if (nIndex < 0 || (size_t)nIndex > mnRecordDesc.size())
+    if (nIndex < 0 || nIndex > (long)mnRecordDesc.size())
         return OGRERR_FAILURE;
 
     oNextIt = mnRecordDesc.begin();
@@ -289,7 +290,7 @@ OGRErr OGRSXFLayer::SetNextByIndex(long nIndex)
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRSXFLayer::GetFeature(long nFID)
+OGRFeature *OGRSXFLayer::GetFeature(GIntBig nFID)
 {
     std::map<long, vsi_l_offset>::const_iterator IT = mnRecordDesc.find(nFID);
     if (IT != mnRecordDesc.end())
@@ -340,7 +341,7 @@ OGRErr OGRSXFLayer::GetExtent(OGREnvelope *psExtent, int bForce)
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRSXFLayer::GetFeatureCount(int bForce)
+GIntBig OGRSXFLayer::GetFeatureCount(int bForce)
 {
     if (m_poFilterGeom == NULL && m_poAttrQuery == NULL)
         return static_cast<int>(mnRecordDesc.size());
@@ -369,7 +370,7 @@ OGRFeature *OGRSXFLayer::GetNextFeature()
     while (oNextIt != mnRecordDesc.end())
     {
         VSIFSeekL(fpSXF, oNextIt->second, SEEK_SET);
-        OGRFeature  *poFeature = GetNextRawFeature(oNextIt->first);	
+        OGRFeature  *poFeature = GetNextRawFeature(oNextIt->first);
 
         ++oNextIt;
 
@@ -385,7 +386,7 @@ OGRFeature *OGRSXFLayer::GetNextFeature()
             {
                 poFeature->GetGeometryRef()->assignSpatialReference(GetSpatialRef());
             }
-	    
+
             return poFeature;
         }
 
@@ -411,7 +412,7 @@ int OGRSXFLayer::TestCapability( const char * pszCap )
         return TRUE;
     else if (EQUAL(pszCap, OLCFastSetNextByIndex))
         return TRUE;
-        
+
     return FALSE;
 }
 
@@ -419,7 +420,7 @@ int OGRSXFLayer::TestCapability( const char * pszCap )
 /*                                TranslateXYH()                        */
 /************************************************************************/
 /****
- * TODO : Take into account informations given in the passport 
+ * TODO : Take into account informations given in the passport
  * like unit of mesurement, type and dimensions (integer, float, double) of coordinate,
  * the vector format ....
  */
@@ -430,7 +431,7 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
 {
     //Xp, Yp(м) = Xo, Yo(м) + (Xd, Yd / R * S), (1)
 
-	int offset = 0;
+    int offset = 0;
     switch (certifInfo.eValType)
     {
     case SXF_VT_SHORT:
@@ -438,29 +439,28 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
         if( nBufLen < 4 )
             return 0;
         GInt16 x, y;
-        memcpy(&x, psBuff, 2);
-        CPL_LSBINT16PTR(&x);
-        memcpy(&y, psBuff + 2, 2);
+        memcpy(&y, psBuff, 2);
         CPL_LSBINT16PTR(&y);
-
+        memcpy(&x, psBuff + 2, 2);
+        CPL_LSBINT16PTR(&x);
 
         if (stSXFMapDescription.bIsRealCoordinates)
         {
-            *dfX = (double)y;
-            *dfY = (double)x;
+            *dfX = (double)x;
+            *dfY = (double)y;
         }
         else
         {
             if (m_nSXFFormatVer == 3)
             {
-                *dfX = stSXFMapDescription.dfXOr + (double)y * m_dfCoeff;
-                *dfY = stSXFMapDescription.dfYOr + (double)x * m_dfCoeff;
+                *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
+                *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
             }
             else if (m_nSXFFormatVer == 4)
             {
                 //TODO: check on real data
-                *dfX = stSXFMapDescription.dfXOr + (double)y * m_dfCoeff;
-                *dfY = stSXFMapDescription.dfYOr + (double)x * m_dfCoeff;
+                *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
+                *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
             }
         }
 
@@ -481,9 +481,9 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
         break;
     case SXF_VT_FLOAT:
     {
-        float x, y;
         if( nBufLen < 8 )
             return 0;
+        float x, y;
         memcpy(&y, psBuff, 4);
         CPL_LSBPTR32(&y);
         memcpy(&x, psBuff + 4, 4);
@@ -491,8 +491,8 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
 
         if (stSXFMapDescription.bIsRealCoordinates)
         {
-            *dfX = (double)y;
-            *dfY = (double)x;
+            *dfX = (double)x;
+            *dfY = (double)y;
         }
         else
         {
@@ -527,21 +527,21 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
 
         if (stSXFMapDescription.bIsRealCoordinates)
         {
-            *dfX = (double)y;
-            *dfY = (double)x;
+            *dfX = (double)x;
+            *dfY = (double)y;
         }
         else
         {
             //TODO: check on real data
             if (m_nSXFFormatVer == 3)
             {
-                *dfX = stSXFMapDescription.dfXOr + (double)y * m_dfCoeff;
-                *dfY = stSXFMapDescription.dfYOr + (double)x * m_dfCoeff;
+                *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
+                *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
             }
             else if (m_nSXFFormatVer == 4)
             {
-                *dfX = stSXFMapDescription.dfXOr + (double)y * m_dfCoeff;
-                *dfY = stSXFMapDescription.dfYOr + (double)x * m_dfCoeff;
+                *dfX = stSXFMapDescription.dfXOr + (double)x * m_dfCoeff;
+                *dfY = stSXFMapDescription.dfYOr + (double)y * m_dfCoeff;
             }
         }
         offset += 8;
@@ -571,8 +571,8 @@ GUInt32 OGRSXFLayer::TranslateXYH(const SXFRecordDescription& certifInfo,
 
         if (stSXFMapDescription.bIsRealCoordinates)
         {
-            *dfY = y;
             *dfX = x;
+            *dfY = y;
         }
         else
         {
@@ -617,8 +617,9 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
         return NULL;
     }
 
-    SXFGeometryType eGeomType;
-    GByte code;
+    SXFGeometryType eGeomType = SXF_GT_Unknown;
+    GByte code = 0;
+
     if (m_nSXFFormatVer == 3)
     {
         if (CHECK_BIT(stRecordHeader.nRef[2], 3))
@@ -630,7 +631,7 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
             }
             else
             {
-                code = 0x21; 
+                code = 0x21;
                 stRecordHeader.nSubObjectCount = 0;
             }
         }
@@ -688,10 +689,11 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
     }
     else if (code == 0x05) // xxxx0101
         eGeomType = SXF_GT_TextTemplate;
-    else if (code == 0x21) 
+    else if (code == 0x21)
         eGeomType = SXF_GT_VectorAngle;
-    else if (code == 0x22) 
+    else if (code == 0x22)
         eGeomType = SXF_GT_VectorScaled;
+
     bool bHasAttributes = CHECK_BIT(stRecordHeader.nRef[1], 1);
     bool bHasRefVector = CHECK_BIT(stRecordHeader.nRef[1], 3);
     if (bHasRefVector == true)
@@ -791,16 +793,18 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
         poFeature = TranslateVetorAngle(stCertInfo, recordCertifBuf,
             stRecordHeader.nGeometryLength);
     }
-    else if (eGeomType == SXF_GT_Vector ) 
+    else if (eGeomType == SXF_GT_Vector )
     {
       CPLError( CE_Warning, CPLE_NotSupported,
       "SXF. Geometry type Vector do not support." );
+      CPLFree(recordCertifBuf);
       return NULL;
     }
     else if (eGeomType == SXF_GT_TextTemplate ) // TODO realise this
     {
       CPLError( CE_Warning, CPLE_NotSupported,
       "SXF. Geometry type Text Template do not support." );
+      CPLFree(recordCertifBuf);
       return NULL;
     }
     else
@@ -810,7 +814,7 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
         CPLFree(recordCertifBuf);
         return NULL;
     }
-    
+
     if( poFeature == NULL )
     {
         CPLFree(recordCertifBuf);
@@ -920,7 +924,7 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
                     }
                     memcpy(&nTmpVal, psSemanticsdBuf + offset, sizeof(GInt16));
                     nVal = double(CPL_LSBWORD16(nTmpVal)) * pow(10.0, (double)stAttInfo.nScale);
-   
+
                     poFeature->SetField(oFieldName, nVal);
                     offset += 2;
                     break;
@@ -978,16 +982,35 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
                 }
                 case SXF_RAT_UNICODE:
                 {
-                    unsigned nLen = unsigned(stAttInfo.nScale) + 1;
-                    if( nLen > nSemanticsSize || nSemanticsSize - nLen < offset )
+                    unsigned nLen = (unsigned(stAttInfo.nScale) + 1) * 2;
+                    if(nLen < 2 || nLen > nSemanticsSize || nSemanticsSize - nLen < offset )
                     {
                         nSemanticsSize = 0;
                         break;
                     }
-                    char * value = (char*)CPLMalloc(nLen);
-                    memcpy(value, psSemanticsdBuf + offset, nLen);
+                    char* value = (char*)CPLMalloc(nLen);
+                    memcpy(value, psSemanticsdBuf + offset, nLen - 2);
                     value[nLen-1] = 0;
-                    poFeature->SetField(oFieldName, value);
+                    value[nLen-2] = 0;
+                    char* dst = (char*)CPLMalloc(nLen);
+                    int nCount = 0;
+                    for(int i = 0; (unsigned)i < nLen; i += 2)
+                    {
+                         unsigned char ucs = value[i];
+
+                         if (ucs < 0x80U)
+                         {
+                             dst[nCount++] = ucs;
+                         }
+                         else
+                         {
+                             dst[nCount++] = 0xc0 | (ucs >> 6);
+                             dst[nCount++] = 0x80 | (ucs & 0x3F);
+                         }
+                    }
+
+                    poFeature->SetField(oFieldName, dst);
+                    CPLFree(dst);
                     CPLFree(value);
 
                     offset += nLen;
@@ -1028,10 +1051,10 @@ OGRFeature *OGRSXFLayer::GetNextRawFeature(long nFID)
                     return NULL;
                 }
             }
-            CPLFree(psSemanticsdBufOrig);
         }
-    }    
-   
+        CPLFree(psSemanticsdBufOrig);
+     }
+
     poFeature->SetFID(nFID);
 
     CPLFree(recordCertifBuf);
@@ -1048,27 +1071,30 @@ OGRFeature *OGRSXFLayer::TranslatePoint(const SXFRecordDescription& certifInfo,
 {
     double dfX = 1.0;
     double dfY = 1.0;
+    double dfZ = 0.0;
     GUInt32 nOffset = 0;
+    GUInt32 nDelta = 0;
+
+    if (certifInfo.bDim == 1)
+    {
+        nDelta = TranslateXYH( certifInfo, psRecordBuf , nBufLen, &dfX, &dfY, &dfZ );
+    }
+    else
+    {
+        nDelta = TranslateXYH( certifInfo, psRecordBuf , nBufLen, &dfX, &dfY );
+    }
 
-    GUInt32 nDelta = TranslateXYH( certifInfo, psRecordBuf , nBufLen, &dfX, &dfY );
     if( nDelta == 0 )
         return NULL;
     nOffset += nDelta;
 
-	//OGRFeatureDefn *fd = poFeatureDefn->Clone();
-	//fd->SetGeomType( wkbMultiPoint );
+    //OGRFeatureDefn *fd = poFeatureDefn->Clone();
+    //fd->SetGeomType( wkbMultiPoint );
  //   OGRFeature *poFeature = new OGRFeature(fd);
     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     OGRMultiPoint* poMPt = new OGRMultiPoint();
 
-    if (certifInfo.bDim == 1) // TODO realise this
-	{
-		CPLError( CE_Failure, CPLE_NotSupported, 
-				"SXF. 3D metrics do not support." );
-	}
-
-
-    poMPt->addGeometryDirectly( new OGRPoint( dfX, dfY ) );
+    poMPt->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
 
 /*---------------------- Reading SubObjects --------------------------------*/
 
@@ -1091,18 +1117,27 @@ OGRFeature *OGRSXFLayer::TranslatePoint(const SXFRecordDescription& certifInfo,
         {
             const char * psCoords = psRecordBuf + nOffset ;
 
-            nDelta = TranslateXYH( certifInfo, psCoords , nBufLen - nOffset, &dfX, &dfY ) ;
+            if (certifInfo.bDim == 1)
+            {
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+            }
+            else
+            {
+                dfZ = 0.0;
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+            }
+
             if( nDelta == 0 )
                 break;
             nOffset +=  nDelta;
 
-            poMPt->addGeometryDirectly( new OGRPoint( dfX, dfY ) );
-        } 
+            poMPt->addGeometryDirectly( new OGRPoint( dfX, dfY, dfZ ) );
+        }
     }
 
 /*****
- * TODO : 
- *          - Translate graphics 
+ * TODO :
+ *          - Translate graphics
  *          - Translate 3D vector
  */
 
@@ -1120,11 +1155,13 @@ OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription& certifInfo,
 {
     double dfX = 1.0;
     double dfY = 1.0;
-
+    double dfZ = 0.0;
     GUInt32 nOffset = 0;
+    GUInt32 count;
+    GUInt32 nDelta = 0;
 
-	//OGRFeatureDefn *fd = poFeatureDefn->Clone();
-	//fd->SetGeomType( wkbMultiLineString );
+    //OGRFeatureDefn *fd = poFeatureDefn->Clone();
+    //fd->SetGeomType( wkbMultiLineString );
  //   OGRFeature *poFeature = new OGRFeature(fd);
 
     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
@@ -1134,21 +1171,25 @@ OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription& certifInfo,
 
     OGRLineString* poLS = new OGRLineString();
 
-    if (certifInfo.bDim == 1) // TODO realise this
-	{
-		 CPLError( CE_Failure, CPLE_NotSupported, 
-                  "SXF. 3D metrics do not support." );
-	}
-
-    for(int count=0 ; (GUInt32)count <  certifInfo.nPointCount ; count++)
+    for(count=0 ; count <  certifInfo.nPointCount ; count++)
     {
         const char * psCoords = psRecordBuf + nOffset ;
-        GUInt32 nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+
+        if (certifInfo.bDim == 1)
+        {
+            nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+        }
+        else
+        {
+            dfZ = 0.0;
+            nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+        }
+
         if( nDelta == 0 )
             break;
         nOffset += nDelta;
 
-        poLS->addPoint( dfX  , dfY );
+        poLS->addPoint( dfX, dfY, dfZ );
     }
 
     poMLS->addGeometry( poLS );
@@ -1175,13 +1216,21 @@ OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription& certifInfo,
         for (int i=0; i < nCoords ; i++)
         {
             const char * psCoords = psRecordBuf + nOffset ;
+            if (certifInfo.bDim == 1)
+            {
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+            }
+            else
+            {
+                dfZ = 0.0;
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+            }
 
-            GUInt32 nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
             if( nDelta == 0 )
                 break;
             nOffset += nDelta;
 
-            poLS->addPoint( dfX  , dfY );
+            poLS->addPoint( dfX, dfY, dfZ );
         }
 
         poMLS->addGeometry( poLS );
@@ -1191,8 +1240,8 @@ OGRFeature *OGRSXFLayer::TranslateLine(const SXFRecordDescription& certifInfo,
     poFeature->SetGeometryDirectly( poMLS );
 
 /*****
- * TODO : 
- *          - Translate graphics 
+ * TODO :
+ *          - Translate graphics
  *          - Translate 3D vector
  */
 
@@ -1215,8 +1264,10 @@ OGRFeature *OGRSXFLayer::TranslateVetorAngle(const SXFRecordDescription& certifI
 
     double dfX = 1.0;
     double dfY = 1.0;
-
+    double dfZ = 0.0;
     GUInt32 nOffset = 0;
+    GUInt32 count;
+    GUInt32 nDelta = 0;
 
     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     OGRPoint *poPT = new OGRPoint();
@@ -1225,21 +1276,24 @@ OGRFeature *OGRSXFLayer::TranslateVetorAngle(const SXFRecordDescription& certifI
 
     OGRLineString* poLS = new OGRLineString();
 
-    if (certifInfo.bDim == 1) // TODO realise this
-    {
-        CPLError(CE_Failure, CPLE_NotSupported,
-            "SXF. 3D metrics do not support.");
-    }
-
-    for (int count = 0; (GUInt32)count < certifInfo.nPointCount; count++)
+    for (count = 0; count < certifInfo.nPointCount; count++)
     {
         const char * psCoords = psRecordBuf + nOffset;
-        GUInt32 nDelta = TranslateXYH(certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY);
+
+        if (certifInfo.bDim == 1)
+        {
+            nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+        }
+        else
+        {
+            dfZ = 0.0;
+            nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+        }
         if (nDelta == 0)
             break;
         nOffset += nDelta;
 
-        poLS->addPoint(dfX, dfY);
+        poLS->addPoint(dfX, dfY, dfZ);
     }
 
     poLS->StartPoint(poPT);
@@ -1272,33 +1326,33 @@ OGRFeature *OGRSXFLayer::TranslatePolygon(const SXFRecordDescription& certifInfo
 {
     double dfX = 1.0;
     double dfY = 1.0;
+    double dfZ = 0.0;
     GUInt32 nOffset = 0;
-
-	//OGRFeatureDefn *fd = poFeatureDefn->Clone();
-	//fd->SetGeomType( wkbMultiPolygon );
- //   OGRFeature *poFeature = new OGRFeature(fd);
+    GUInt32 count;
+    GUInt32 nDelta = 0;
 
     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     OGRPolygon *poPoly = new OGRPolygon();
     OGRLineString* poLS = new OGRLineString();
 
 /*---------------------- Reading Primary Polygon --------------------------------*/
-
-    if (certifInfo.bDim == 1) // TODO realise this
-	{
-			CPLError( CE_Failure, CPLE_NotSupported, 
-					"SXF. 3D metrics do not support." );
-	}
-
-    for(int count=0 ; (GUInt32)count <  certifInfo.nPointCount ; count++)
+    for(count=0 ; count <  certifInfo.nPointCount ; count++)
     {
-        const char * psBuf = psRecordBuf + nOffset ;
+        const char * psBuf = psRecordBuf + nOffset;
+        if (certifInfo.bDim == 1)
+        {
+            nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+        }
+        else
+        {
+            dfZ = 0.0;
+            nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY );
+        }
 
-        GUInt32 nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY );
         if( nDelta == 0 )
             break;
         nOffset += nDelta;
-        poLS->addPoint( dfX  , dfY );
+        poLS->addPoint( dfX, dfY, dfZ );
 
     }    // for
 
@@ -1330,13 +1384,21 @@ OGRFeature *OGRSXFLayer::TranslatePolygon(const SXFRecordDescription& certifInfo
         for (i=0; i < nCoords ; i++)
         {
             const char * psCoords = psRecordBuf + nOffset ;
+            if (certifInfo.bDim == 1)
+            {
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+            }
+            else
+            {
+                dfZ = 0.0;
+                nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
+            }
 
-            GUInt32 nDelta = TranslateXYH( certifInfo, psCoords, nBufLen - nOffset, &dfX, &dfY );
             if( nDelta == 0 )
                 break;
             nOffset += nDelta;
 
-            poLS->addPoint( dfX  , dfY );
+            poLS->addPoint( dfX, dfY, dfZ );
         }
 
         OGRLinearRing *poLR = new OGRLinearRing();
@@ -1364,8 +1426,10 @@ OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription& certifInfo,
 {
     double dfX = 1.0;
     double dfY = 1.0;
+    double dfZ = 0.0;
     GUInt32 nOffset = 0;
-
+    GUInt32 count;
+    GUInt32 nDelta = 0;
 	//OGRFeatureDefn *fd = poFeatureDefn->Clone();
 	//fd->SetGeomType( wkbLineString );
  //   OGRFeature *poFeature = new OGRFeature(fd);
@@ -1373,20 +1437,23 @@ OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription& certifInfo,
     OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
     OGRLineString* poLS = new OGRLineString();
 
-    if (certifInfo.bDim == 1) // TODO realise this
-	{
-			CPLError( CE_Failure, CPLE_NotSupported, 
-					"SXF. 3D metrics do not support." );
-	}
-
-    for(int count=0 ; (GUInt32)count <  certifInfo.nPointCount ; count++)
+    for(count=0 ; count <  certifInfo.nPointCount ; count++)
     {
         const char * psBuf = psRecordBuf + nOffset;
-        GUInt32 nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY );
+        if (certifInfo.bDim == 1)
+        {
+            nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY, &dfZ );
+        }
+        else
+        {
+            dfZ = 0.0;
+            nDelta = TranslateXYH( certifInfo, psBuf, nBufLen - nOffset, &dfX, &dfY );
+        }
         if( nDelta == 0 )
             break;
+
         nOffset += nDelta;
-        poLS->addPoint( dfX  , dfY );
+        poLS->addPoint( dfX, dfY, dfZ );
     }
 
     poFeature->SetGeometryDirectly( poLS );
@@ -1409,7 +1476,7 @@ OGRFeature *OGRSXFLayer::TranslateText(const SXFRecordDescription& certifInfo,
 
         //TODO: Check encoding from sxf
         poFeature->SetField("TEXT", pszTextBuf);
- 
+
         CPLFree( pszTextBuf );
     }
 
diff --git a/ogr/ogrsf_frmts/sxf/org_sxf_defs.h b/ogr/ogrsf_frmts/sxf/org_sxf_defs.h
index b24b09e..22ddba2 100644
--- a/ogr/ogrsf_frmts/sxf/org_sxf_defs.h
+++ b/ogr/ogrsf_frmts/sxf/org_sxf_defs.h
@@ -227,6 +227,7 @@ enum SXFCoordinateType
  */
 enum SXFGeometryType
 {
+    SXF_GT_Unknown = -1,
     SXF_GT_Line    = 0,     /* MultiLineString geometric object                  */
     SXF_GT_Polygon = 1,     /* Polygon geometric object                          */
     SXF_GT_Point = 2,       /* MultiPoint geometric object                       */
diff --git a/ogr/ogrsf_frmts/tiger/GNUmakefile b/ogr/ogrsf_frmts/tiger/GNUmakefile
index 74537e1..a8c43b0 100644
--- a/ogr/ogrsf_frmts/tiger/GNUmakefile
+++ b/ogr/ogrsf_frmts/tiger/GNUmakefile
@@ -29,7 +29,7 @@ OBJ     =  ogrtigerdriver.o           \
 
 
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 LIBS	:=	$(GDAL_LIB) $(LIBS)
 
diff --git a/ogr/ogrsf_frmts/tiger/ogr_tiger.h b/ogr/ogrsf_frmts/tiger/ogr_tiger.h
index e353574..a95ec09 100644
--- a/ogr/ogrsf_frmts/tiger/ogr_tiger.h
+++ b/ogr/ogrsf_frmts/tiger/ogr_tiger.h
@@ -1,6 +1,6 @@
 /*-*-C++-*-*/
 /******************************************************************************
- * $Id: ogr_tiger.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_tiger.h 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Main declarations for Tiger translator.
@@ -83,7 +83,7 @@ const char * TigerVersionString( TigerVersion );
 /*****************************************************************************/
 /* The TigerFieldInfo and TigerRecordInfo structures hold information about  */
 /* the schema of a TIGER record type.  In each layer implementation file     */
-/* there are statically initalized variables of these types that describe    */
+/* there are statically initialized variables of these types that describe    */
 /* the record types associated with that layer.  In the case where different */
 /* TIGER versions have different schemas, there is a                         */
 /* TigerFieldInfo/TigerRecordInfo for each version, and the constructor      */
@@ -517,15 +517,15 @@ class OGRTigerLayer : public OGRLayer
 
     void                ResetReading();
     OGRFeature *        GetNextFeature();
-    OGRFeature         *GetFeature( long nFeatureId );
+    OGRFeature         *GetFeature( GIntBig nFeatureId );
 
     OGRFeatureDefn *    GetLayerDefn();
 
-    int                 GetFeatureCount( int );
+    GIntBig             GetFeatureCount( int );
 
     int                 TestCapability( const char * );
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
                                      int bApproxOK = TRUE );
 };
@@ -596,29 +596,10 @@ class OGRTigerDataSource : public OGRDataSource
 
     void                DeleteModuleFiles( const char *pszModule );
 
-    virtual OGRLayer    *CreateLayer( const char *,
+    virtual OGRLayer    *ICreateLayer( const char *,
                                       OGRSpatialReference * = NULL,
                                       OGRwkbGeometryType = wkbUnknown,
                                       char ** = NULL );
 };
 
-/************************************************************************/
-/*                            OGRTigerDriver                            */
-/************************************************************************/
-
-class OGRTigerDriver : public OGRSFDriver
-{
-  public:
-                ~OGRTigerDriver();
-
-    const char *GetName();
-
-    OGRDataSource *Open( const char *, int );
-
-    virtual OGRDataSource *CreateDataSource( const char *pszName,
-                                             char ** = NULL );
-
-    int         TestCapability( const char * );
-};
-
 #endif /* ndef _OGR_TIGER_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp
index 6a22a33..ae5caf6 100644
--- a/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp
+++ b/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtigerdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrtigerdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements OGRTigerDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include <ctype.h>
 
-CPL_CVSID("$Id: ogrtigerdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrtigerdatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                        TigerClassifyVersion()                        */
@@ -239,6 +239,7 @@ OGRTigerDataSource::~OGRTigerDataSource()
 void OGRTigerDataSource::AddLayer( OGRTigerLayer * poNewLayer )
 
 {
+    poNewLayer->SetDescription( poNewLayer->GetName() );
     papoLayers = (OGRTigerLayer **)
         CPLRealloc( papoLayers, sizeof(void*) * ++nLayers );
     
@@ -815,22 +816,21 @@ int OGRTigerDataSource::Create( const char *pszNameIn, char **papszOptions )
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
-OGRLayer *OGRTigerDataSource::CreateLayer( const char *pszLayerName, 
-                                           OGRSpatialReference *poSpatRef, 
-                                           CPL_UNUSED OGRwkbGeometryType eGType, 
-                                           CPL_UNUSED char **papszOptions )
-
+OGRLayer *OGRTigerDataSource::ICreateLayer( const char *pszLayerName,
+                                            OGRSpatialReference *poSpatRef,
+                                            CPL_UNUSED OGRwkbGeometryType eGType,
+                                            CPL_UNUSED char **papszOptions )
 {
     OGRTigerLayer       *poLayer = NULL;
 
     if( GetLayer( pszLayerName ) != NULL )
         return GetLayer( pszLayerName );
 
-    if( poSpatRef != NULL && 
-        (!poSpatRef->IsGeographic() 
+    if( poSpatRef != NULL &&
+        (!poSpatRef->IsGeographic()
          || !EQUAL(poSpatRef->GetAttrValue("DATUM"),
                    "North_American_Datum_1983")) )
     {
diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp
index 6cd59e5..9651160 100644
--- a/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp
+++ b/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtigerdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $
+ * $Id: ogrtigerdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements OGRTigerDriver
@@ -30,73 +30,66 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrtigerdriver.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-/************************************************************************/
-/*                           ~OGRNTFDriver()                            */
-/************************************************************************/
-
-OGRTigerDriver::~OGRTigerDriver()
-
-{
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRTigerDriver::GetName()
-
-{
-    return "TIGER";
-}
+CPL_CVSID("$Id: ogrtigerdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRTigerDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRTigerDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( !poOpenInfo->bStatOK )
+        return NULL;
+    char** papszSiblingFiles = poOpenInfo->GetSiblingFiles();
+    if( papszSiblingFiles != NULL )
+    {
+        int i;
+        int bFoundCompatibleFile = FALSE;
+        for( i = 0; papszSiblingFiles[i] != NULL; i++ )
+        {
+            int nLen = (int)strlen(papszSiblingFiles[i]);
+            if( nLen > 4 &&
+                papszSiblingFiles[i][nLen-4] == '.' &&
+                papszSiblingFiles[i][nLen-1] == '1' )
+            {
+                bFoundCompatibleFile = TRUE;
+                break;
+            }
+        }
+        if( !bFoundCompatibleFile )
+            return FALSE;
+    }
+ 
     OGRTigerDataSource  *poDS = new OGRTigerDataSource;
 
-    if( !poDS->Open( pszFilename, TRUE ) )
+    if( !poDS->Open( poOpenInfo->pszFilename, TRUE ) )
     {
         delete poDS;
         poDS = NULL;
     }
 
-    if( poDS != NULL && bUpdate )
+    if( poDS != NULL && poOpenInfo->eAccess == GA_Update )
     {
         CPLError( CE_Failure, CPLE_OpenFailed,
                   "Tiger Driver doesn't support update." );
         delete poDS;
         poDS = NULL;
     }
-    
+
     return poDS;
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
+/*                              Create()                                */
 /************************************************************************/
 
-int OGRTigerDriver::TestCapability( const char *pszCap )
-
-{
-    if( EQUAL(pszCap,ODrCCreateDataSource) )
-        return TRUE;
-    else
-        return FALSE;
-}
-
-/************************************************************************/
-/*                          CreateDataSource()                          */
-/************************************************************************/
-
-OGRDataSource *OGRTigerDriver::CreateDataSource( const char *pszName,
-                                                 char **papszOptions )
-
+static GDALDataset *OGRTigerDriverCreate( const char * pszName,
+                                          CPL_UNUSED int nBands,
+                                          CPL_UNUSED int nXSize,
+                                          CPL_UNUSED int nYSize,
+                                          CPL_UNUSED GDALDataType eDT,
+                                          char **papszOptions )
 {
     OGRTigerDataSource *poDS;
 
@@ -118,7 +111,24 @@ OGRDataSource *OGRTigerDriver::CreateDataSource( const char *pszName,
 void RegisterOGRTiger()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRTigerDriver );
-}
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "TIGER" ) == NULL )
+    {
+        poDriver = new GDALDriver();
 
+        poDriver->SetDescription( "TIGER" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "U.S. Census TIGER/Line" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_tiger.html" );
 
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRTigerDriverOpen;
+        poDriver->pfnCreate = OGRTigerDriverCreate;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
+}
diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp
index 78b7ac4..adbfdae 100644
--- a/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp
+++ b/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtigerlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrtigerlayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements OGRTigerLayer class.
@@ -29,7 +29,7 @@
 
 #include "ogr_tiger.h"
 
-CPL_CVSID("$Id: ogrtigerlayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrtigerlayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                           OGRTigerLayer()                            */
@@ -118,7 +118,7 @@ void OGRTigerLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRTigerLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRTigerLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( nFeatureId < 1 || nFeatureId > nFeatureCount )
@@ -149,7 +149,7 @@ OGRFeature *OGRTigerLayer::GetFeature( long nFeatureId )
     OGRFeature  *poFeature;
 
     poFeature =
-        poReader->GetFeature( nFeatureId-panModuleOffset[iLastModule]-1 );
+        poReader->GetFeature( (int)nFeatureId-panModuleOffset[iLastModule]-1 );
 
     if( poFeature != NULL )
     {
@@ -245,17 +245,19 @@ OGRFeatureDefn *OGRTigerLayer::GetLayerDefn()
 /*                            CreateField()                             */
 /************************************************************************/
 
-OGRErr OGRTigerLayer::CreateField( CPL_UNUSED OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRTigerLayer::CreateField( CPL_UNUSED OGRFieldDefn *poField,
+                                   CPL_UNUSED int bApproxOK )
 {
     /* notdef/TODO: I should add some checking here eventually. */
+
     return OGRERR_NONE;
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                          ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRTigerLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRTigerLayer::ICreateFeature( OGRFeature *poFeature )
 
 {
     return poReader->CreateFeature( poFeature );
@@ -265,7 +267,7 @@ OGRErr OGRTigerLayer::CreateFeature( OGRFeature *poFeature )
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRTigerLayer::GetFeatureCount( int bForce )
+GIntBig OGRTigerLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom == NULL && m_poAttrQuery == NULL )
diff --git a/ogr/ogrsf_frmts/tiger/tigeraltname.cpp b/ogr/ogrsf_frmts/tiger/tigeraltname.cpp
index 8d1b340..68ccdfe 100644
--- a/ogr/ogrsf_frmts/tiger/tigeraltname.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigeraltname.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigeraltname.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigeraltname.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerAltName, providing access to RT4 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigeraltname.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigeraltname.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "4"
 
@@ -58,7 +58,8 @@ static const TigerRecordInfo rt4_info =
 /************************************************************************/
 
 TigerAltName::TigerAltName( OGRTigerDataSource * poDSIn,
-                            CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rt4_info, FILE_CODE)
+                            CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rt4_info, FILE_CODE)
 {
     OGRFieldDefn        oField("",OFTInteger);
 
diff --git a/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp b/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp
index be84dc1..a071697 100644
--- a/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerarealandmarks.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerarealandmarks.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerAreaLandmarks, providing access to .RT8 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerarealandmarks.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerarealandmarks.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "8"
 
@@ -57,7 +57,8 @@ static const TigerRecordInfo rt8_info =
 /************************************************************************/
 
 TigerAreaLandmarks::TigerAreaLandmarks( OGRTigerDataSource * poDSIn,
-                                        CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rt8_info, FILE_CODE)
+                                        CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rt8_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "AreaLandmarks" );
diff --git a/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp b/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp
index 65f719f..4f349fb 100644
--- a/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigercompletechain.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigercompletechain.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerCompleteChain, providing access to RT1 and
@@ -31,7 +31,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigercompletechain.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigercompletechain.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 static const TigerFieldInfo rt1_2002_fields[] = {
   // fieldname    fmt  type OFTType      beg  end  len  bDefine bSet bWrite
@@ -364,7 +364,7 @@ int TigerCompleteChain::SetModule( const char * pszModule )
                           pszFilename );
         }
         else
-            panShapeRecordId = (int *)CPLCalloc(sizeof(int),GetFeatureCount());
+            panShapeRecordId = (int *)CPLCalloc(sizeof(int),(size_t)GetFeatureCount());
         
         CPLFree( pszFilename );
     }
@@ -482,7 +482,8 @@ OGRFeature *TigerCompleteChain::GetFeature( int nRecordId )
 /************************************************************************/
 
 int TigerCompleteChain::AddShapePoints( int nTLID, int nRecordId,
-                                        OGRLineString * poLine, CPL_UNUSED int nSeqNum )
+                                        OGRLineString * poLine,
+                                        CPL_UNUSED int nSeqNum )
 {
     int         nShapeRecId;
 
diff --git a/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp b/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp
index 92da158..b818547 100644
--- a/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerentitynames.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerentitynames.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerEntityNames, providing access to .RTC files.
@@ -31,7 +31,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerentitynames.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerentitynames.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "C"
 
@@ -120,7 +120,8 @@ static const TigerRecordInfo rtC_info =
 /************************************************************************/
 
 TigerEntityNames::TigerEntityNames( OGRTigerDataSource * poDSIn,
-                                    CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(NULL, FILE_CODE)
+                                    CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(NULL, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "EntityNames" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp b/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp
index f21a41a..8a4550e 100644
--- a/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerfeatureids.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerfeatureids.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerFeatureIds, providing access to .RT5 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerfeatureids.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerfeatureids.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "5"
 
@@ -76,7 +76,8 @@ static const TigerRecordInfo rt5_info =
 /************************************************************************/
 
 TigerFeatureIds::TigerFeatureIds( OGRTigerDataSource * poDSIn,
-                                  CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(NULL, FILE_CODE)
+                                  CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(NULL, FILE_CODE)
 {
   poDS = poDSIn;
   poFeatureDefn = new OGRFeatureDefn( "FeatureIds" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp b/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp
index 0be5361..15fe77e 100644
--- a/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerfilebase.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerfilebase.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerBaseFile class, providing common services to all
@@ -34,7 +34,7 @@
 #include "cpl_error.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: tigerfilebase.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerfilebase.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                           TigerFileBase()                            */
@@ -394,7 +394,8 @@ int TigerFileBase::WriteRecord( char *pachRecord, int nRecLen,
 /*      Setup our access to be to the module indicated in the feature.  */
 /************************************************************************/
 
-int TigerFileBase::SetWriteModule( const char *pszExtension, CPL_UNUSED int nRecLen,
+int TigerFileBase::SetWriteModule( const char *pszExtension,
+                                   CPL_UNUSED int nRecLen,
                                    OGRFeature *poFeature )
 {
 /* -------------------------------------------------------------------- */
diff --git a/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp b/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp
index 78b9132..cf87a5b 100644
--- a/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigeridhistory.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigeridhistory.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerIDHistory, providing access to .RTH files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigeridhistory.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigeridhistory.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "H"
 
@@ -60,7 +60,8 @@ static const TigerRecordInfo rtH_info =
 /************************************************************************/
 
 TigerIDHistory::TigerIDHistory( OGRTigerDataSource * poDSIn,
-                                CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rtH_info, FILE_CODE)
+                                CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtH_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "IDHistory" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp b/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp
index 20474e9..50fe037 100644
--- a/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerkeyfeatures.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerkeyfeatures.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerKeyFeatures, providing access to .RT9 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerkeyfeatures.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerkeyfeatures.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "9"
 
@@ -63,7 +63,8 @@ static const TigerRecordInfo rt9_info =
 /************************************************************************/
 
 TigerKeyFeatures::TigerKeyFeatures( OGRTigerDataSource * poDSIn,
-                                    CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rt9_info, FILE_CODE)
+                                    CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rt9_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "KeyFeatures" );
@@ -75,4 +76,5 @@ TigerKeyFeatures::TigerKeyFeatures( OGRTigerDataSource * poDSIn,
     /* -------------------------------------------------------------------- */
 
     AddFieldDefns( psRTInfo, poFeatureDefn );
+
 }
diff --git a/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp b/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp
index 13327ca..d5b8d32 100644
--- a/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerlandmarks.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerlandmarks.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerLandmarks, providing access to .RT7 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerlandmarks.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerlandmarks.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "7"
 
diff --git a/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp b/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp
index c65b8a0..62c109c 100644
--- a/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigeroverunder.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigeroverunder.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerOverUnder, providing access to .RTU files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigeroverunder.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigeroverunder.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE       "U"
 
@@ -60,8 +60,8 @@ static const TigerRecordInfo rtU_info =
 /************************************************************************/
 
 TigerOverUnder::TigerOverUnder( OGRTigerDataSource * poDSIn,
-                                CPL_UNUSED const char * pszPrototypeModule )
-  : TigerPoint(TRUE, &rtU_info, FILE_CODE)
+                                CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerPoint(TRUE, &rtU_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "OverUnder" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerpip.cpp b/ogr/ogrsf_frmts/tiger/tigerpip.cpp
index 491c88f..9ab8312 100644
--- a/ogr/ogrsf_frmts/tiger/tigerpip.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerpip.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerpip.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerpip.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerPIP, providing access to .RTP files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerpip.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerpip.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "P"
 
@@ -73,7 +73,7 @@ static const TigerRecordInfo rtP_info =
 /************************************************************************/
 
 TigerPIP::TigerPIP( OGRTigerDataSource * poDSIn,
-                    CPL_UNUSED const char * pszPrototypeModule ) 
+                    CPL_UNUSED const char * pszPrototypeModule )
   : TigerPoint(TRUE, NULL, FILE_CODE)
 {
     poDS = poDSIn;
@@ -101,4 +101,3 @@ OGRErr TigerPIP::CreateFeature( OGRFeature *poFeature )
   return TigerPoint::CreateFeature( poFeature, 
                                     26 );
 }
-
diff --git a/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp b/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp
index 7584e2b..4992025 100644
--- a/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerpolychainlink.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerpolychainlink.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerPolyChainLink, providing access to .RTI files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerpolychainlink.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerpolychainlink.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "I"
 
@@ -84,8 +84,8 @@ static const TigerRecordInfo rtI_info =
 /************************************************************************/
 
 TigerPolyChainLink::TigerPolyChainLink( OGRTigerDataSource * poDSIn,
-                                        CPL_UNUSED const char * pszPrototypeModule )
-  : TigerFileBase(NULL, FILE_CODE)
+                                        CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(NULL, FILE_CODE)
 {
     OGRFieldDefn        oField("",OFTInteger);
 
diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp
index ae8d7f2..fcd3905 100644
--- a/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerpolygon.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerpolygon.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerPolygon, providing access to .RTA files.
@@ -31,7 +31,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerpolygon.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerpolygon.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static const TigerFieldInfo rtA_2002_fields[] = {
   // fieldname    fmt  type OFTType      beg  end  len  bDefine bSet bWrite
@@ -627,4 +627,3 @@ OGRErr TigerPolygon::CreateFeature( OGRFeature *poFeature )
 
     return OGRERR_NONE;
 }
-
diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp
index d57a129..ca82341 100644
--- a/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerpolygoncorrections.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerpolygoncorrections.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerPolygonCorrections, providing access to .RTB files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerpolygoncorrections.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerpolygoncorrections.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE       "B"
 
@@ -70,7 +70,8 @@ static const TigerRecordInfo rtB_info =
 /************************************************************************/
 
 TigerPolygonCorrections::TigerPolygonCorrections( OGRTigerDataSource * poDSIn,
-                                                  CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rtB_info, FILE_CODE)
+                                                  CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtB_info, FILE_CODE)
 {
     OGRFieldDefn        oField("",OFTInteger);
 
diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp
index 7654d35..c9e8fd1 100644
--- a/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerpolygoneconomic.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerpolygoneconomic.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerPolygonEconomic, providing access to .RTE files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerpolygoneconomic.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerpolygoneconomic.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE       "E"
 
@@ -84,7 +84,8 @@ static const TigerRecordInfo rtE_info =
 /************************************************************************/
 
 TigerPolygonEconomic::TigerPolygonEconomic( OGRTigerDataSource * poDSIn,
-                                            CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rtE_info, FILE_CODE)
+                                            CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtE_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "PolygonEconomic" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp b/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp
index 5c3e085..d917c52 100644
--- a/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerspatialmetadata.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerspatialmetadata.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerSpatialMetadata, providing access to .RTM files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerspatialmetadata.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerspatialmetadata.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "M"
 
@@ -58,8 +58,9 @@ static const TigerRecordInfo rtM_info =
 /************************************************************************/
 
 TigerSpatialMetadata::TigerSpatialMetadata( OGRTigerDataSource * poDSIn,
-                                            CPL_UNUSED const char * pszPrototypeModule )
-  : TigerFileBase(&rtM_info, FILE_CODE)
+                                            CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtM_info, FILE_CODE)
+
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "SpatialMetadata" );
diff --git a/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp b/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp
index 0559757..86e74cd 100644
--- a/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigertlidrange.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigertlidrange.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerTLIDRange, providing access to .RTR files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigertlidrange.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigertlidrange.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "R"
 
@@ -78,8 +78,8 @@ static const TigerRecordInfo rtR_info =
 /************************************************************************/
 
 TigerTLIDRange::TigerTLIDRange( OGRTigerDataSource * poDSIn,
-                                CPL_UNUSED const char * pszPrototypeModule )
-  : TigerFileBase(NULL, FILE_CODE)
+                                CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(NULL, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "TLIDRange" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp b/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp
index c69c264..a96d055 100644
--- a/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerzerocellid.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerzerocellid.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerZeroCellID, providing access to .RTT files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerzerocellid.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerzerocellid.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE       "T"
 
@@ -54,8 +54,8 @@ static const TigerRecordInfo rtT_info =
 /************************************************************************/
 
 TigerZeroCellID::TigerZeroCellID( OGRTigerDataSource * poDSIn,
-                                  CPL_UNUSED const char * pszPrototypeModule )
-  : TigerFileBase(&rtT_info, FILE_CODE)
+                                  CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtT_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "ZeroCellID" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp b/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp
index 9722f93..face12a 100644
--- a/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerzipcodes.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerzipcodes.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerZipCodes, providing access to .RT6 files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerzipcodes.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerzipcodes.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE "6"
 
@@ -62,7 +62,9 @@ static const TigerRecordInfo rt6_info =
 /************************************************************************/
 
 TigerZipCodes::TigerZipCodes( OGRTigerDataSource * poDSIn,
-                              CPL_UNUSED const char * pszPrototypeModule ) : TigerFileBase(&rt6_info, FILE_CODE)
+                              CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rt6_info, FILE_CODE)
+
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "ZipCodes" );
diff --git a/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp b/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp
index 5a6bc82..c180513 100644
--- a/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp
+++ b/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: tigerzipplus4.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: tigerzipplus4.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  TIGER/Line Translator
  * Purpose:  Implements TigerZipPlus4, providing access to .RTZ files.
@@ -30,7 +30,7 @@
 #include "ogr_tiger.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: tigerzipplus4.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: tigerzipplus4.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 #define FILE_CODE       "Z"
 
@@ -54,8 +54,8 @@ static const TigerRecordInfo rtZ_info =
 /************************************************************************/
 
 TigerZipPlus4::TigerZipPlus4( OGRTigerDataSource * poDSIn,
-                              CPL_UNUSED const char * pszPrototypeModule )
-  : TigerFileBase(&rtZ_info, FILE_CODE)
+                              CPL_UNUSED const char * pszPrototypeModule ) :
+    TigerFileBase(&rtZ_info, FILE_CODE)
 {
     poDS = poDSIn;
     poFeatureDefn = new OGRFeatureDefn( "ZipPlus4" );
diff --git a/ogr/ogrsf_frmts/vfk/GNUmakefile b/ogr/ogrsf_frmts/vfk/GNUmakefile
index 5f696b5..900699a 100644
--- a/ogr/ogrsf_frmts/vfk/GNUmakefile
+++ b/ogr/ogrsf_frmts/vfk/GNUmakefile
@@ -11,7 +11,7 @@ OGR_OBJ = ogrvfkdriver.o ogrvfkdatasource.o ogrvfklayer.o
 
 OBJ = $(CORE_OBJ) $(OGR_OBJ)
 
-CPPFLAGS := -I.. -I../.. $(GDAL_INCLUDE) $(SQLITE_INC) $(CPPFLAGS)
+CPPFLAGS := -I.. -I../..  $(SQLITE_INC) $(CPPFLAGS)
 
 default: $(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/vfk/drv_vfk.html b/ogr/ogrsf_frmts/vfk/drv_vfk.html
index fd787d1..9fd5dee 100644
--- a/ogr/ogrsf_frmts/vfk/drv_vfk.html
+++ b/ogr/ogrsf_frmts/vfk/drv_vfk.html
@@ -9,8 +9,7 @@
 
 This driver reads VFK files, ie. data in the <em>Czech cadastral
 exchange data format</em>. The VFK file is recognized as an OGR
-datasource with zero or more OGR layers. The filenames must end with
-".vfk" extension.
+datasource with zero or more OGR layers.
 
 <p>
 Note: starting with OGR 1.10, the driver is compiled only if GDAL
@@ -25,13 +24,13 @@ used. Feature types cannot be mixed in one layer.
 
 Starting with OGR 1.9, the driver reads and writes VFK data from/to
 internal SQLite database. Default name of the database is
-"<input_vfk_file>.db". Since OGR 1.10, you can define
-an alternative DB name with <tt>OGR_VFK_DB_NAME</tt> configuration
-option. If <tt>OGR_VFK_DB_OVERWRITE=YES</tt> configuration option is
+"input_vfk_file.db". Since OGR 1.10, you can define
+an alternative DB name with <b>OGR_VFK_DB_NAME</b> configuration
+option. If <b>OGR_VFK_DB_OVERWRITE=YES</b> configuration option is
 given, than the driver overwrites existing SQLite database and reads
 data from original input VFK file. By default, the internal SQLite
 database is not automatically deleted. Since OGR 1.11, the internal
-database is deleted if <tt>OGR_VFK_DB_DELETE=YES</tt> configuration
+database is deleted if <b>OGR_VFK_DB_DELETE=YES</b> configuration
 option is given.
 
 <p>
@@ -40,7 +39,7 @@ database. It means that geometries are resolved only once when
 building SQLite database from original VFK data. Geometries are stored
 in WKB format. Note that GDAL doesn't need to be built with SpatiaLite
 support. Geometries are not stored in DB
-when <tt>OGR_VFK_DB_SPATIAL=NO</tt> configuration option is given. In
+when <b>OGR_VFK_DB_SPATIAL=NO</b> configuration option is given. In
 this case the geometries are resolved from DB.
 
 <h3>Internal working and performance tweaking</h3>
@@ -53,7 +52,7 @@ original VFK file).
 
 <p>
 Since OGR 1.11, the driver reads by default all data blocks. When
-configuration option <tt>OGR_VFK_DB_READ_ALL_BLOCKS=NO</tt> is given
+configuration option <b>OGR_VFK_DB_READ_ALL_BLOCKS=NO</b> is given
 than the driver reads only data blocks which are requested by the
 user.
 
@@ -61,6 +60,10 @@ user.
 
 Datasource name is a full path to the VFK file.
 
+<p>The driver supports reading files managed by VSI Virtual File
+System API, which include "regular" files, as well as files in the
+/vsizip/, /vsigzip/, and /vsicurl/ read-only domains.
+
 <h2>Layer names</h2>
 
 VFK data blocks are used as layer names.
@@ -83,7 +86,7 @@ done once when the spatial filter is set.
 <ul>
 <li> <a href="http://geo.fsv.cvut.cz/~landa/publications/2010/gis-ostrava-2010/paper/landa-ogr-vfk.pdf">OGR
 VFK Driver Implementation Issues</a></li>
-<li> <a href="http://grass.fsv.cvut.cz/gwiki/VFK">Open Source Tools for VFK format</a> (in Czech)</li>
+<li> <a href="http://freegis.fsv.cvut.cz/gwiki/VFK">Open Source Tools for VFK format</a> (in Czech)</li>
 <li> <a href="http://www.cuzk.cz/Dokument.aspx?PRARESKOD=998&MENUID=0&AKCE=DOC:10-VF_ISKNTEXT">Czech
 cadastral exchange data format documentation</a> (in Czech)</li>
 </ul>
diff --git a/ogr/ogrsf_frmts/vfk/ogr_vfk.h b/ogr/ogrsf_frmts/vfk/ogr_vfk.h
index abdcaed..a8bf048 100644
--- a/ogr/ogrsf_frmts/vfk/ogr_vfk.h
+++ b/ogr/ogrsf_frmts/vfk/ogr_vfk.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_vfk.h 26468 2013-09-14 09:46:19Z rouault $
+ * $Id: ogr_vfk.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/VFK driver.
@@ -72,7 +72,7 @@ public:
     ~OGRVFKLayer();
 
     OGRFeature          *GetNextFeature();
-    OGRFeature          *GetFeature(long);
+    OGRFeature          *GetFeature(GIntBig);
 
     OGRFeatureDefn      *GetLayerDefn() { return poFeatureDefn; }
 
@@ -80,7 +80,7 @@ public:
     
     int                  TestCapability(const char *);
 
-    int                  GetFeatureCount(int = TRUE);
+    GIntBig              GetFeatureCount(int = TRUE);
 };
 
 /************************************************************************/
@@ -117,18 +117,4 @@ public:
     IVFKReader    *GetReader() const { return poReader; }
 };
 
-/************************************************************************/
-/*                            OGRVFKDriver                              */
-/************************************************************************/
-class OGRVFKDriver:public OGRSFDriver
-{
-public:
-    ~OGRVFKDriver();
-                
-    const char    *GetName();
-    OGRDataSource *Open(const char *, int);
-    
-    int            TestCapability(const char *);
-};
-
 #endif // GDAL_OGR_VFK_H_INCLUDED
diff --git a/ogr/ogrsf_frmts/vfk/ogrvfkdriver.cpp b/ogr/ogrsf_frmts/vfk/ogrvfkdriver.cpp
index 91423e9..5c73bab 100644
--- a/ogr/ogrsf_frmts/vfk/ogrvfkdriver.cpp
+++ b/ogr/ogrsf_frmts/vfk/ogrvfkdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrvfkdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrvfkdriver.cpp 27384 2014-05-24 12:28:12Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRVFKDriver class.
@@ -33,43 +33,30 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrvfkdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrvfkdriver.cpp 27384 2014-05-24 12:28:12Z rouault $");
 
-/************************************************************************/
-/*                          ~OGRVFKDriver()                             */
-/************************************************************************/
-OGRVFKDriver::~OGRVFKDriver()
+static int OGRVFKDriverIdentify(GDALOpenInfo* poOpenInfo)
 {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-const char *OGRVFKDriver::GetName()
-{
-    return "VFK";
+    return ( poOpenInfo->fpL != NULL &&
+             poOpenInfo->nHeaderBytes >= 2 &&
+             strncmp((const char*)poOpenInfo->pabyHeader, "&H", 2) == 0 );
 }
 
 /*
   \brief Open existing data source
-  
-  \param pszFilename data source name to be open
-  \param pUpdate non-zero for update, zero for read-only
-
-  \return pointer to OGRDataSource instance
   \return NULL on failure
 */
-OGRDataSource *OGRVFKDriver::Open(const char * pszFilename,
-                                  int bUpdate)
+static GDALDataset *OGRVFKDriverOpen(GDALOpenInfo* poOpenInfo)
 {
     OGRVFKDataSource *poDS;
 
-    if (bUpdate)
+    if( poOpenInfo->eAccess == GA_Update ||
+        !OGRVFKDriverIdentify(poOpenInfo) )
         return NULL;
-    
+
     poDS = new OGRVFKDataSource();
 
-    if(!poDS->Open(pszFilename, TRUE) || poDS->GetLayerCount() == 0) {
+    if(!poDS->Open(poOpenInfo->pszFilename, TRUE) || poDS->GetLayerCount() == 0) {
         delete poDS;
         return NULL;
     }
@@ -77,17 +64,6 @@ OGRDataSource *OGRVFKDriver::Open(const char * pszFilename,
         return poDS;
 }
 
-/*!
-  \brief Test driver capability
-
-  \param pszCap capability
-
-  \return TRUE on success or FALSE on failure
-*/
-int OGRVFKDriver::TestCapability(CPL_UNUSED const char *pszCap)
-{
-    return FALSE;
-}
 
 /*!
   \brief Register VFK driver
@@ -96,5 +72,23 @@ void RegisterOGRVFK()
 {
     if (!GDAL_CHECK_VERSION("OGR/VFK driver"))
         return;
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(new OGRVFKDriver);
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "VFK" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "VFK" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "Czech Cadastral Exchange Data Format" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vfk" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_vfk.html" );
+
+        poDriver->pfnOpen = OGRVFKDriverOpen;
+        poDriver->pfnIdentify = OGRVFKDriverIdentify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/vfk/ogrvfklayer.cpp b/ogr/ogrsf_frmts/vfk/ogrvfklayer.cpp
index e448009..7cfce19 100644
--- a/ogr/ogrsf_frmts/vfk/ogrvfklayer.cpp
+++ b/ogr/ogrsf_frmts/vfk/ogrvfklayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrvfklayer.cpp 26596 2013-11-08 17:59:47Z martinl $
+ * $Id: ogrvfklayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRVFKLayer class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrvfklayer.cpp 26596 2013-11-08 17:59:47Z martinl $");
+CPL_CVSID("$Id: ogrvfklayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /*!
   \brief OGRVFKLayer constructor
@@ -50,30 +50,9 @@ OGRVFKLayer::OGRVFKLayer(const char *pszName,
 {
     /* set spatial reference */
     if( poSRSIn == NULL ) {
-        /* default is S-JTSK 
-        const char *wktString = "PROJCS[\"Krovak\","
-            "GEOGCS[\"GCS_Bessel 1841\","
-            "DATUM[\"D_unknown\","
-            "SPHEROID[\"bessel\","
-            "6377397.155,299.1528128]],"
-            "PRIMEM[\"Greenwich\",0],"
-            "UNIT[\"Degree\",0.017453292519943295]],"
-            "PROJECTION[\"Krovak\"],"
-            "PARAMETER[\"latitude_of_center\",49.5],"
-            "PARAMETER[\"longitude_of_center\",24.83333333333333],"
-            "PARAMETER[\"azimuth\",0],"
-            "PARAMETER[\"pseudo_standard_parallel_1\",0],"
-            "PARAMETER[\"scale_factor\",0.9999],"
-            "PARAMETER[\"false_easting\",0],"
-            "PARAMETER[\"false_northing\",0],"
-            "UNIT[\"Meter\",1]]";
-        */
-        
+        /* default is S-JTSK (EPSG: 5514) */
         poSRS = new OGRSpatialReference();
-        /*
-        if (poSRS->importFromWkt((char **)&wktString) != OGRERR_NONE) {
-        */
-        if (poSRS->importFromEPSG(2065) != OGRERR_NONE) {
+        if (poSRS->importFromEPSG(5514) != OGRERR_NONE) {
             delete poSRS;
             poSRS = NULL;
         }
@@ -87,6 +66,7 @@ OGRVFKLayer::OGRVFKLayer(const char *pszName,
 
     /* feature definition */
     poFeatureDefn = new OGRFeatureDefn(pszName);
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
 
     poFeatureDefn->Reference();
@@ -148,24 +128,26 @@ OGRGeometry *OGRVFKLayer::CreateGeometry(IVFKFeature * poVfkFeature)
 /*!
   \brief Get feature count
 
-  This method overwrites OGRLayer::GetFeatureCount(), 
+  This method overwrites OGRLayer::GetFeatureCount(),
 
   \param bForce skip (return -1)
 
   \return number of features
 */
-int OGRVFKLayer::GetFeatureCount(int bForce)
+GIntBig OGRVFKLayer::GetFeatureCount(CPL_UNUSED int bForce)
 {
     int nfeatures;
 
-    if (m_poFilterGeom || m_poAttrQuery || bForce)
-        nfeatures = OGRLayer::GetFeatureCount(bForce);
-    else
-        nfeatures = poDataBlock->GetFeatureCount();
-    
+    /* note that 'nfeatures' is 0 when data are not read from DB */
+    nfeatures = (int)poDataBlock->GetFeatureCount();
+    if (m_poFilterGeom || m_poAttrQuery || nfeatures < 1) {
+        /* force real feature count */
+        nfeatures = (int)OGRLayer::GetFeatureCount();
+    }
+
     CPLDebug("OGR-VFK", "OGRVFKLayer::GetFeatureCount(): name=%s -> n=%d",
              GetName(), nfeatures);
-    
+
     return nfeatures;
 }
 
@@ -215,7 +197,7 @@ OGRFeature *OGRVFKLayer::GetNextFeature()
 
   \return pointer to OGRFeature or NULL not found
 */
-OGRFeature *OGRVFKLayer::GetFeature(long nFID)
+OGRFeature *OGRVFKLayer::GetFeature(GIntBig nFID)
 {
     IVFKFeature *poVFKFeature;
 
@@ -225,7 +207,7 @@ OGRFeature *OGRVFKLayer::GetFeature(long nFID)
         return NULL;
 
     CPLAssert(nFID == poVFKFeature->GetFID());
-    CPLDebug("OGR-VFK", "OGRVFKLayer::GetFeature(): name=%s fid=%ld", GetName(), nFID);
+    CPLDebug("OGR-VFK", "OGRVFKLayer::GetFeature(): name=%s fid=" CPL_FRMT_GIB, GetName(), nFID);
     
     return GetFeature(poVFKFeature);
 }
diff --git a/ogr/ogrsf_frmts/vfk/vfkdatablock.cpp b/ogr/ogrsf_frmts/vfk/vfkdatablock.cpp
index 51b9fde..d65a66a 100644
--- a/ogr/ogrsf_frmts/vfk/vfkdatablock.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkdatablock.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkdatablock.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vfkdatablock.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  VFK Reader - Data block definition
  * Purpose:  Implements VFKDataBlock class.
@@ -186,7 +186,12 @@ int IVFKDataBlock::AddProperty(const char *pszName, const char *pszType)
     return m_nPropertyCount;
 }
 
-int IVFKDataBlock::GetFeatureCount()
+/*!
+  \brief Get number of features for given data block
+  
+  \return number of features
+*/
+GIntBig IVFKDataBlock::GetFeatureCount()
 {
     if (m_nFeatureCount < 0) {
         m_poReader->ReadDataRecords(this); /* read VFK data records */
@@ -398,7 +403,7 @@ IVFKFeature *IVFKDataBlock::GetFeatureByIndex(int iIndex) const
 
   \return pointer to feature definition or NULL on failure (not found)
 */
-IVFKFeature *IVFKDataBlock::GetFeature(long nFID)
+IVFKFeature *IVFKDataBlock::GetFeature(GIntBig nFID)
 {
     if (m_nFeatureCount < 0) {
         m_poReader->ReadDataRecords(this);
@@ -471,7 +476,7 @@ int IVFKDataBlock::LoadGeometry()
 
     if (nInvalid > 0) {
         CPLError(CE_Warning, CPLE_AppDefined, 
-                 "%s: %d features with invalid or empty geometry found", m_pszName, nInvalid);
+                 "%s: %d features with invalid or empty geometry", m_pszName, nInvalid);
     }
 
 #ifdef DEBUG_TIMING
@@ -593,7 +598,7 @@ void IVFKDataBlock::AddFeature(IVFKFeature *poNewFeature)
 */
 int IVFKDataBlock::GetRecordCount(RecordType iRec) const
 {
-    return m_nRecordCount[iRec];
+    return (int) m_nRecordCount[iRec];
 }
 
 /*!
@@ -714,7 +719,7 @@ VFKFeatureList VFKDataBlock::GetFeatures(int idx1, int idx2, GUIntBig value)
 
   \return number of features or -1 on error
 */
-int VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
+GIntBig VFKDataBlock::GetFeatureCount(const char *pszName, const char *pszValue)
 {
     int nfeatures, propIdx;
     VFKFeature *poVFKFeature;
diff --git a/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp b/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp
index 70f2ca0..3c073ac 100644
--- a/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkdatablocksqlite.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkdatablocksqlite.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: vfkdatablocksqlite.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  VFK Reader - Data block definition (SQLite)
  * Purpose:  Implements VFKDataBlockSQLite
@@ -105,14 +105,110 @@ int VFKDataBlockSQLite::LoadGeometryPoint()
 }
 
 /*!
+  \brief Set geometry for linestrings
+
+  \param poLine VFK feature
+  \param oOGRLine line geometry
+  \param[in,out] bValid TRUE when feature's geometry is valid
+  \param[in,out] rowIdFeat list of row ids which forms linestring
+  \param[in,out] nGeometries number of features with valid geometry
+*/
+bool VFKDataBlockSQLite::SetGeometryLineString(VFKFeatureSQLite *poLine, OGRLineString *oOGRLine,
+                                               bool& bValid, const char *ftype,
+                                               std::vector<int>& rowIdFeat, int& nGeometries)
+{
+    int              npoints;
+    VFKReaderSQLite *poReader;
+
+    poReader  = (VFKReaderSQLite*) m_poReader;
+
+    oOGRLine->setCoordinateDimension(2); /* force 2D */
+
+    /* check also VFK validity */
+    if (bValid) {
+        /* Feature types
+           
+           - '3'    - line       (2 points)
+           - '4'    - linestring (at least 2 points)
+           - '11'   - curve      (at least 2 points)
+           - '15'   - circle     (3 points)
+           - '15 r' - circle     (center point & radius)
+           - '16'   - arc        (3 points)
+        */
+
+        npoints = oOGRLine->getNumPoints();
+        if (EQUAL(ftype, "3") && npoints > 2) {
+            /* be less pedantic, just inform user about data
+             * inconsistency
+
+               bValid = FALSE;
+            */
+            CPLDebug("OGR-VFK", 
+                     "Line (fid=" CPL_FRMT_GIB ") defined by more than two vertices",
+                     poLine->GetFID());
+        }
+        else if (EQUAL(ftype, "11") && npoints < 2) { 
+            bValid = FALSE;
+            CPLError(CE_Warning, CPLE_AppDefined, 
+                     "Curve (fid=" CPL_FRMT_GIB ") defined by less than two vertices",
+                     poLine->GetFID());
+        }
+        else if (EQUAL(ftype, "15") && npoints != 3) {
+            bValid = FALSE;
+            CPLError(CE_Warning, CPLE_AppDefined, 
+                     "Circle (fid=" CPL_FRMT_GIB ") defined by invalid number of vertices (%d)",
+                     poLine->GetFID(), oOGRLine->getNumPoints());
+        }
+        else if (strlen(ftype) > 2 && EQUALN(ftype, "15", 2) && npoints != 1) {
+            bValid = FALSE;
+            CPLError(CE_Warning, CPLE_AppDefined, 
+                     "Circle (fid=" CPL_FRMT_GIB ") defined by invalid number of vertices (%d)",
+                     poLine->GetFID(), oOGRLine->getNumPoints());
+        }
+        else if (EQUAL(ftype, "16") && npoints != 3) {
+            bValid = FALSE;
+            CPLError(CE_Warning, CPLE_AppDefined, 
+                     "Arc (fid=" CPL_FRMT_GIB ") defined by invalid number of vertices (%d)",
+                     poLine->GetFID(), oOGRLine->getNumPoints());
+        }
+    }
+
+    /* set geometry (NULL for invalid features) */
+    if (bValid) {
+        if (!poLine->SetGeometry(oOGRLine, ftype)) {
+            bValid = FALSE;
+        }
+    }
+    else {
+        poLine->SetGeometry(NULL);
+    }
+    
+    /* update fid column */
+    UpdateFID(poLine->GetFID(), rowIdFeat);        
+    
+    /* store also geometry in DB */
+    CPLAssert(0 != rowIdFeat.size());
+    if (bValid && poReader->IsSpatial() &&
+        SaveGeometryToDB(bValid ? poLine->GetGeometry() : NULL,
+                         rowIdFeat[0]) != OGRERR_FAILURE)
+        nGeometries++;
+
+    rowIdFeat.clear();
+    oOGRLine->empty(); /* restore line */
+
+    return bValid;
+}
+
+/*!
   \brief Load geometry (linestring SBP layer)
 
   \return number of invalid features
 */
 int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
 {
-    int      nInvalid, nGeometries, rowId;
-    long int iFID;
+    int       nInvalid, nGeometries, rowId, iIdx;
+    CPLString szFType, szFTypeLine;
+    
     GUIntBig id, ipcb;
     bool     bValid;
     
@@ -138,23 +234,23 @@ int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
     }
     
     poDataBlockPoints->LoadGeometry();
-    
+
     if (LoadGeometryFromDB()) /* try to load geometry from DB */
 	return 0;
 
     osSQL.Printf("UPDATE %s SET %s = -1", m_pszName, FID_COLUMN);
     poReader->ExecuteSQL(osSQL.c_str());
     bValid = TRUE;
-    iFID = 1;
+    iIdx = 0;
     for (int i = 0; i < 2; i++) {
 	/* first collect linestrings related to HP, OB or DPM
 	   then collect rest of linestrings */
         if (i == 0)
-            osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,_rowid_ FROM '%s' WHERE "
+            osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ FROM '%s' WHERE "
                          "HP_ID IS NOT NULL OR OB_ID IS NOT NULL OR DPM_ID IS NOT NULL "
                          "ORDER BY HP_ID,OB_ID,DPM_ID,PORADOVE_CISLO_BODU", m_pszName);
         else
-            osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,_rowid_ FROM '%s' WHERE "
+            osSQL.Printf("SELECT BP_ID,PORADOVE_CISLO_BODU,PARAMETRY_SPOJENI,_rowid_ FROM '%s' WHERE "
                          "OB_ID IS NULL AND HP_ID IS NULL AND DPM_ID IS NULL "
                          "ORDER BY ID,PORADOVE_CISLO_BODU", m_pszName);
 	
@@ -167,43 +263,24 @@ int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
             // read values
             id    = sqlite3_column_double(hStmt, 0);
             ipcb  = sqlite3_column_double(hStmt, 1);
-            rowId = sqlite3_column_int(hStmt, 2);
+            szFType = (char *) sqlite3_column_text(hStmt, 2);
+            rowId = sqlite3_column_int(hStmt, 3);
 
             if (ipcb == 1) {
-                /* add feature to the array */
-                poFeature = new VFKFeatureSQLite(this, rowId, iFID);
-                CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
-                AddFeature(poFeature);
+                poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(iIdx);
+                CPLAssert(NULL != poFeature);
+                poFeature->SetRowId(rowId);
                 
-                if (poLine) {
-                    oOGRLine.setCoordinateDimension(2); /* force 2D */
-		    if (bValid) {
-			if (!poLine->SetGeometry(&oOGRLine)) {
-                            bValid = FALSE;
-			    nInvalid++;
-                        }
-		    }
-		    else {
-			poLine->SetGeometry(NULL);
-			nInvalid++;
-		    }
-                    
-		    /* update fid column */
-		    UpdateFID(poLine->GetFID(), rowIdFeat);        
-
-		    /* store also geometry in DB */
-		    CPLAssert(0 != rowIdFeat.size());
-		    if (bValid && poReader->IsSpatial() &&
-			SaveGeometryToDB(bValid ? &oOGRLine : NULL,
-					 rowIdFeat[0]) != OGRERR_FAILURE)
-			nGeometries++;
-		    
-		    rowIdFeat.clear();
-                    oOGRLine.empty(); /* restore line */
+                /* set geometry & reset */
+                if (poLine && !SetGeometryLineString(poLine, &oOGRLine,
+                                                     bValid, szFTypeLine, rowIdFeat, nGeometries)) {
+                    nInvalid++;
                 }
+                
 		bValid = TRUE;
                 poLine = poFeature;
-                iFID++;
+                szFTypeLine = szFType;
+                iIdx++;
             }
             
             poPoint = (VFKFeatureSQLite *) poDataBlockPoints->GetFeature("ID", id);
@@ -230,30 +307,11 @@ int VFKDataBlockSQLite::LoadGeometryLineStringSBP()
         }
 
         /* add last line */
-        if (poLine) {
-	    oOGRLine.setCoordinateDimension(2); /* force 2D */
-	    if (bValid) {
-		if (!poLine->SetGeometry(&oOGRLine))
-		    nInvalid++;
-	    }
-	    else {
-		poLine->SetGeometry(NULL);
-		nInvalid++;
-	    }
-            
-	    /* update fid column */
-	    UpdateFID(poLine->GetFID(), rowIdFeat);        
-	    
-	    /* store also geometry in DB */
-	    CPLAssert(0 != rowIdFeat.size());
-	    if (poReader->IsSpatial() &&
-		SaveGeometryToDB(bValid ? &oOGRLine : NULL,
-				 rowIdFeat[0]) != OGRERR_FAILURE && bValid)
-		nGeometries++;
+        if (poLine && !SetGeometryLineString(poLine, &oOGRLine,
+                                             bValid, szFType.c_str(), rowIdFeat, nGeometries)) {
+            nInvalid++;
         }
 	poLine = NULL;
-	rowIdFeat.clear();
-        oOGRLine.empty(); /* restore line */
 
 	if (poReader->IsSpatial())
 	    poReader->ExecuteSQL("COMMIT");
@@ -621,7 +679,7 @@ int VFKDataBlockSQLite::LoadGeometryPolygon()
 
   \return pointer to feature definition or NULL on failure (not found)
 */
-IVFKFeature *VFKDataBlockSQLite::GetFeature(long nFID)
+IVFKFeature *VFKDataBlockSQLite::GetFeature(GIntBig nFID)
 {
     int rowId;
     CPLString osSQL;
@@ -642,7 +700,7 @@ IVFKFeature *VFKDataBlockSQLite::GetFeature(long nFID)
     
     poReader = (VFKReaderSQLite*) m_poReader;
     
-    osSQL.Printf("SELECT rowid FROM %s WHERE %s = %ld",
+    osSQL.Printf("SELECT rowid FROM %s WHERE %s = " CPL_FRMT_GIB,
                  m_pszName, FID_COLUMN, nFID);
     if (EQUAL(m_pszName, "SBP")) {
         osSQL += " AND PORADOVE_CISLO_BODU = 1";
@@ -842,18 +900,20 @@ OGRErr VFKDataBlockSQLite::SaveGeometryToDB(const OGRGeometry *poGeom, int iRowI
 bool VFKDataBlockSQLite::LoadGeometryFromDB()
 {
     int nInvalid, nGeometries, nGeometriesCount, nBytes, rowId;
+#ifdef DEBUG
     long iFID;
-    bool bAddFeature, bSkipInvalid;
-    
+#endif
+    bool bSkipInvalid;
+
     CPLString osSQL;
-    
+
     OGRGeometry      *poGeometry;
-    
+
     VFKFeatureSQLite *poFeature;
     VFKReaderSQLite  *poReader;
-    
+
     sqlite3_stmt *hStmt;
-    
+
     poReader = (VFKReaderSQLite*) m_poReader;
 
     if (!poReader->IsSpatial())   /* check if DB is spatial */
@@ -870,9 +930,8 @@ bool VFKDataBlockSQLite::LoadGeometryFromDB()
     if (nGeometries < 1)
 	return FALSE;
     
-    bAddFeature = EQUAL(m_pszName, "SBP");
     bSkipInvalid = EQUAL(m_pszName, "OB") || EQUAL(m_pszName, "OP") || EQUAL(m_pszName, "OBBP");
-    
+
     /* load geometry from DB */
     nInvalid = nGeometriesCount = 0;
     osSQL.Printf("SELECT %s,rowid,%s FROM %s ",
@@ -883,20 +942,17 @@ bool VFKDataBlockSQLite::LoadGeometryFromDB()
     osSQL += FID_COLUMN;
     hStmt = poReader->PrepareStatement(osSQL.c_str());
 
+    rowId = 0;
     while(poReader->ExecuteSQL(hStmt) == OGRERR_NONE) {
-        rowId = sqlite3_column_int(hStmt, 1);
-        iFID = sqlite3_column_double(hStmt, 2);
+        rowId++; // =sqlite3_column_int(hStmt, 1);
+#ifdef DEBUG
+        iFID =
+#endif
+            sqlite3_column_double(hStmt, 2);
 
-        if (bAddFeature) {
-            /* add feature to the array */
-            poFeature = new VFKFeatureSQLite(this, rowId, iFID);
-            AddFeature(poFeature);
-        }
-        else {
-            poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
-        }
+        poFeature = (VFKFeatureSQLite *) GetFeatureByIndex(rowId - 1);
         CPLAssert(NULL != poFeature && poFeature->GetFID() == iFID);
-        
+
         // read geometry from DB
 	nBytes = sqlite3_column_bytes(hStmt, 0);
 	if (nBytes > 0 &&
@@ -924,7 +980,7 @@ bool VFKDataBlockSQLite::LoadGeometryFromDB()
 
     if (nInvalid > 0 && !bSkipInvalid) {
 	CPLError(CE_Warning, CPLE_AppDefined, 
-                 "%s: %d features with invalid or empty geometry found",
+                 "%s: %d features with invalid or empty geometry",
 		 m_pszName, nInvalid);
     }
 
@@ -937,18 +993,27 @@ bool VFKDataBlockSQLite::LoadGeometryFromDB()
   \param nGeometries number of geometries to update
 */
 void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries) {
+    int nFeatCount;
     CPLString osSQL;
     
     VFKReaderSQLite  *poReader;
     
     poReader = (VFKReaderSQLite*) m_poReader;
 
+    /* update number of features in VFK_DB_TABLE table */    
+    nFeatCount = (int)GetFeatureCount();
+    if (nFeatCount > 0) {
+        osSQL.Printf("UPDATE %s SET num_features = %d WHERE table_name = '%s'",
+                     VFK_DB_TABLE, nFeatCount, m_pszName);
+        poReader->ExecuteSQL(osSQL.c_str());
+    }
+
+    /* update number of geometries in VFK_DB_TABLE table */    
     if (nGeometries > 0) {
         CPLDebug("OGR-VFK", 
                  "VFKDataBlockSQLite::UpdateVfkBlocks(): name=%s -> "
                  "%d geometries saved to internal DB", m_pszName, nGeometries);
         
-	/* update number of geometries in VFK_DB_TABLE table */
 	osSQL.Printf("UPDATE %s SET num_geometries = %d WHERE table_name = '%s'",
 		     VFK_DB_TABLE, nGeometries, m_pszName);
 	poReader->ExecuteSQL(osSQL.c_str());
@@ -961,7 +1026,7 @@ void VFKDataBlockSQLite::UpdateVfkBlocks(int nGeometries) {
   \param iFID feature id to set up
   \param rowId list of rows to update
 */
-void VFKDataBlockSQLite::UpdateFID(long int iFID, std::vector<int> rowId)
+void VFKDataBlockSQLite::UpdateFID(GIntBig iFID, std::vector<int> rowId)
 {
     CPLString osSQL, osValue;
     VFKReaderSQLite  *poReader;
@@ -969,7 +1034,7 @@ void VFKDataBlockSQLite::UpdateFID(long int iFID, std::vector<int> rowId)
     poReader = (VFKReaderSQLite*) m_poReader;
     
     /* update number of geometries in VFK_DB_TABLE table */
-    osSQL.Printf("UPDATE %s SET %s = %ld WHERE rowid IN (",
+    osSQL.Printf("UPDATE %s SET %s = " CPL_FRMT_GIB " WHERE rowid IN (",
                  m_pszName, FID_COLUMN, iFID);
     for (size_t i = 0; i < rowId.size(); i++) {
 	if (i > 0)
diff --git a/ogr/ogrsf_frmts/vfk/vfkfeature.cpp b/ogr/ogrsf_frmts/vfk/vfkfeature.cpp
index 4d8183a..1d39a34 100644
--- a/ogr/ogrsf_frmts/vfk/vfkfeature.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkfeature.cpp
@@ -1,12 +1,12 @@
 /******************************************************************************
- * $Id: vfkfeature.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vfkfeature.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  VFK Reader - Feature definition
  * Purpose:  Implements IVFKFeature/VFKFeature class.
  * Author:   Martin Landa, landa.martin gmail.com
  *
  ******************************************************************************
- * Copyright (c) 2009-2010, 2012-2013, Martin Landa <landa.martin gmail.com>
+ * Copyright (c) 2009-2010, 2012-2015, Martin Landa <landa.martin gmail.com>
  * Copyright (c) 2012, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person
@@ -79,7 +79,7 @@ void IVFKFeature::SetGeometryType(OGRwkbGeometryType nGeomType)
   
   \param nFID feature id
 */
-void IVFKFeature::SetFID(long nFID)
+void IVFKFeature::SetFID(GIntBig nFID)
 {
     if (m_nFID > 0) {
         m_nFID = nFID;
@@ -95,10 +95,11 @@ void IVFKFeature::SetFID(long nFID)
   Also checks if given geometry is valid
 
   \param poGeom pointer to OGRGeometry
+  \param ftype geometry VFK type
 
   \return TRUE on valid feature or otherwise FALSE
 */
-bool IVFKFeature::SetGeometry(OGRGeometry *poGeom)
+bool IVFKFeature::SetGeometry(OGRGeometry *poGeom, const char *ftype)
 {
     m_bGeometry = TRUE;
 
@@ -112,8 +113,9 @@ bool IVFKFeature::SetGeometry(OGRGeometry *poGeom)
 
     /* check empty geometries */
     if (m_nGeometryType == wkbNone && poGeom->IsEmpty()) {
-	CPLDebug("OGR-VFK", "%s: empty geometry fid = %ld",
-		 m_poDataBlock->GetName(), m_nFID);
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "%s: empty geometry fid = " CPL_FRMT_GIB,
+                     m_poDataBlock->GetName(), m_nFID);
         m_bValid = FALSE;
     }
     
@@ -124,33 +126,165 @@ bool IVFKFeature::SetGeometry(OGRGeometry *poGeom)
         y = ((OGRPoint *) poGeom)->getY();
         if (x > -430000 || x < -910000 ||
             y > -930000 || y < -1230000) {
-            CPLDebug("OGR-VFK", "%s: invalid point fid = %ld",
+            CPLDebug("OGR-VFK", "%s: invalid point fid = " CPL_FRMT_GIB,
                      m_poDataBlock->GetName(), m_nFID);
             m_bValid = FALSE;
         }
     }
 
-    /* check degenerated linestrings */
-    if (m_nGeometryType == wkbLineString &&
-        ((OGRLineString *) poGeom)->getNumPoints() < 2) {
-        CPLDebug("OGR-VFK", "%s: invalid linestring fid = %ld",
-		 m_poDataBlock->GetName(), m_nFID);
-        m_bValid = FALSE;
-    }
-    
     /* check degenerated polygons */
     if (m_nGeometryType == wkbPolygon) {
         OGRLinearRing *poRing;
         poRing = ((OGRPolygon *) poGeom)->getExteriorRing();
         if (!poRing || poRing->getNumPoints() < 3) {
-	    CPLDebug("OGR-VFK", "%s: invalid polygon fid = %ld",
+	    CPLDebug("OGR-VFK", "%s: invalid polygon fid = " CPL_FRMT_GIB,
 		     m_poDataBlock->GetName(), m_nFID);
             m_bValid = FALSE;
 	}
     }
 
-    if (m_bValid)
-        m_paGeom = (OGRGeometry *) poGeom->clone(); /* make copy */
+    if (m_bValid) {
+        if (ftype) {
+            OGRPoint pt;
+            OGRGeometry *poGeomCurved;
+            OGRCircularString poGeomString;
+                
+            poGeomCurved = NULL;
+            if (EQUAL(ftype, "15") || EQUAL(ftype, "16")) {         /* -> circle or arc */
+                int npoints;
+                
+                npoints = ((OGRLineString *) poGeom)->getNumPoints();
+                for (int i = 0; i < npoints; i++) {
+                    ((OGRLineString *) poGeom)->getPoint(i, &pt);
+                    poGeomString.addPoint(&pt);
+                }
+                if (EQUAL(ftype, "15")) {
+                    /* compute center and radius of a circle */
+                    double x[3], y[3];
+                    double m1, n1, m2, n2, c1, c2, mx;
+                    double c_x, c_y;
+                    
+                    for (int i = 0; i < npoints; i++) {
+                        ((OGRLineString *) poGeom)->getPoint(i, &pt);
+                        x[i] = pt.getX();
+                        y[i] = pt.getY();
+                    }
+                                        
+                    m1 = (x[0] + x[1]) / 2.0;
+                    n1 = (y[0] + y[1]) / 2.0;
+
+                    m2 = (x[0] + x[2]) / 2.0;
+                    n2 = (y[0] + y[2]) / 2.0;
+
+                    c1 = (x[1] - x[0]) * m1 + (y[1] - y[0]) * n1;
+                    c2 = (x[2] - x[0]) * m2 + (y[2] - y[0]) * n2;
+
+                    mx = (x[1] - x[0]) * (y[2] - y[0]) + (y[1] - y[0]) * (x[0] - x[2]);
+
+                    c_x = (c1 * (y[2] - y[0]) + c2 * (y[0] - y[1])) / mx;
+                    c_y = (c1 * (x[0] - x[2]) + c2 * (x[1] - x[0])) / mx;
+   
+                    /* compute a new intermediate point */
+                    pt.setX(c_x - (x[1] - c_x));
+                    pt.setY(c_y - (y[1] - c_y));
+                    poGeomString.addPoint(&pt);
+
+                    /* add last point */
+                    ((OGRLineString *) poGeom)->getPoint(0, &pt);
+                    poGeomString.addPoint(&pt);
+
+                }
+            }
+            else if (strlen(ftype) > 2 && EQUALN(ftype, "15", 2)) { /* -> circle with radius */
+                float r;
+                char s[3]; /* 15 */
+
+                r = 0;
+                if (2 != sscanf(ftype, "%s %f", s, &r) || r < 0) {
+                    CPLDebug("OGR-VFK", "%s: invalid circle (unknown or negative radius) "
+                             "fid = " CPL_FRMT_GIB, m_poDataBlock->GetName(), m_nFID);
+                    m_bValid = FALSE;
+                }
+                else {
+                    double c_x, c_y;
+                    
+                    ((OGRLineString *) poGeom)->getPoint(0, &pt);
+                    c_x = pt.getX();
+                    c_y = pt.getY();
+
+                    /* define first point on a circle */
+                    pt.setX(c_x + r);
+                    pt.setY(c_y);
+                    poGeomString.addPoint(&pt);
+
+                    /* define second point on a circle */
+                    pt.setX(c_x);
+                    pt.setY(c_y + r);
+                    poGeomString.addPoint(&pt);
+
+                    /* define third point on a circle */
+                    pt.setX(c_x - r);
+                    pt.setY(c_y);
+                    poGeomString.addPoint(&pt);
+
+                    /* define fourth point on a circle */
+                    pt.setX(c_x);
+                    pt.setY(c_y - r);
+                    poGeomString.addPoint(&pt);
+
+                    /* define last point (=first) on a circle */
+                    pt.setX(c_x + r);
+                    pt.setY(c_y);
+                    poGeomString.addPoint(&pt);
+                }
+
+            }
+            else if (EQUAL(ftype, "11")) {                          /* curve */
+                int npoints;
+
+                npoints = ((OGRLineString *) poGeom)->getNumPoints();
+                if (npoints > 2) { /* circular otherwise line string */
+                    for (int i = 0; i < npoints; i++) {
+                        ((OGRLineString *) poGeom)->getPoint(i, &pt);
+                        poGeomString.addPoint(&pt);
+                    }
+                }
+            }
+
+            if (!poGeomString.IsEmpty())
+                poGeomCurved = poGeomString.CurveToLine();
+            
+            if (poGeomCurved) {
+                int npoints;
+                
+                npoints = ((OGRLineString *) poGeomCurved)->getNumPoints();
+                CPLDebug("OGR-VFK", "%s: curve (type=%s) to linestring (npoints=%d) fid = " CPL_FRMT_GIB,
+                         m_poDataBlock->GetName(), ftype,
+                         npoints, m_nFID);
+                if (npoints > 1)
+                    m_paGeom = (OGRGeometry *) poGeomCurved->clone();
+                delete poGeomCurved;
+            }
+        }
+
+        if (!m_paGeom) {
+            /* check degenerated linestrings */
+            if (m_nGeometryType == wkbLineString) {
+                int npoints;
+                
+                npoints = ((OGRLineString *) poGeom)->getNumPoints();
+                if (npoints < 2) {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "%s: invalid linestring (%d vertices) fid = " CPL_FRMT_GIB,
+                             m_poDataBlock->GetName(), npoints, m_nFID);
+                    m_bValid = FALSE;
+                }
+            }
+
+            if (m_bValid)
+                m_paGeom = (OGRGeometry *) poGeom->clone(); /* make copy */
+        }
+    }
 
     return m_bValid;
 }
@@ -177,7 +311,6 @@ OGRGeometry *IVFKFeature::GetGeometry()
 bool IVFKFeature::LoadGeometry()
 {
     const char *pszName;
-    CPLString osSQL;
     
     if (m_bGeometry)
         return TRUE;
@@ -217,7 +350,7 @@ bool IVFKFeature::LoadGeometry()
 
   \param poDataBlock pointer to VFKDataBlock instance
 */
-VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, long iFID) : IVFKFeature(poDataBlock)
+VFKFeature::VFKFeature(IVFKDataBlock *poDataBlock, GIntBig iFID) : IVFKFeature(poDataBlock)
 {
     m_nFID = iFID;
     m_propertyList.assign(poDataBlock->GetPropertyCount(), VFKProperty());
@@ -245,7 +378,7 @@ bool VFKFeature::SetProperties(const char *pszLine)
     for (poChar = pszLine; *poChar != '\0' && *poChar != ';'; poChar++)
         /* skip data block name */
         ;
-    if (poChar == '\0')
+    if (*poChar == '\0')
         return FALSE; /* nothing to read */
 
     poChar++; /* skip ';' after data block name*/
@@ -261,7 +394,7 @@ bool VFKFeature::SetProperties(const char *pszLine)
             inString = inString ? FALSE : TRUE;
             if (inString) {
                 poProp = poChar;
-                if (*poChar == '"') { 
+                if (*poChar == '"' && (*(poChar+1) == ';' || *(poChar+1) == '\0')) { 
                     poChar++;
                     inString = FALSE;
                 }
@@ -297,7 +430,8 @@ bool VFKFeature::SetProperties(const char *pszLine)
     /* set properties from the list */
     if (oPropList.size() != (size_t) m_poDataBlock->GetPropertyCount()) {
         /* try to read also invalid records */
-        CPLDebug("OGR-VFK", "%s: invalid number of properties %d should be %d",
+        CPLError(CE_Warning, CPLE_AppDefined, 
+                 "%s: invalid number of properties %d should be %d",
                  m_poDataBlock->GetName(),
 		 (int) oPropList.size(), m_poDataBlock->GetPropertyCount());
         return FALSE;
diff --git a/ogr/ogrsf_frmts/vfk/vfkfeaturesqlite.cpp b/ogr/ogrsf_frmts/vfk/vfkfeaturesqlite.cpp
index 1fa5707..b666300 100644
--- a/ogr/ogrsf_frmts/vfk/vfkfeaturesqlite.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkfeaturesqlite.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkfeaturesqlite.cpp 26343 2013-08-20 14:51:07Z martinl $
+ * $Id: vfkfeaturesqlite.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  VFK Reader - Feature definition (SQLite)
  * Purpose:  Implements VFKFeatureSQLite class.
@@ -45,7 +45,7 @@
 VFKFeatureSQLite::VFKFeatureSQLite(IVFKDataBlock *poDataBlock) : IVFKFeature(poDataBlock)
 {
     m_hStmt  = NULL;
-    m_iRowId = m_poDataBlock->GetFeatureCount() + 1; /* starts at 1 */
+    m_iRowId = (int)m_poDataBlock->GetFeatureCount() + 1; /* starts at 1 */
 
     /* set FID from DB */
     SetFIDFromDB(); /* -> m_nFID */
@@ -58,7 +58,7 @@ VFKFeatureSQLite::VFKFeatureSQLite(IVFKDataBlock *poDataBlock) : IVFKFeature(poD
   \param iRowId feature DB rowid (starts at 1)
   \param nFID feature id
 */
-VFKFeatureSQLite::VFKFeatureSQLite(IVFKDataBlock *poDataBlock, int iRowId, long nFID) : IVFKFeature(poDataBlock)
+VFKFeatureSQLite::VFKFeatureSQLite(IVFKDataBlock *poDataBlock, int iRowId, GIntBig nFID) : IVFKFeature(poDataBlock)
 {
     m_hStmt  = NULL;
     m_iRowId = iRowId;
@@ -85,6 +85,16 @@ OGRErr VFKFeatureSQLite::SetFIDFromDB()
 }
 
 /*!
+  \brief Set DB row id
+
+  \param iRowId row id to be set
+*/
+void VFKFeatureSQLite::SetRowId(int iRowId)
+{
+    m_iRowId = iRowId;
+}
+
+/*!
   \brief Finalize SQL statement
 */
 void VFKFeatureSQLite::FinalizeSQL()
@@ -146,7 +156,7 @@ VFKFeatureSQLite::VFKFeatureSQLite(const VFKFeature *poVFKFeature) : IVFKFeature
 {
     m_nFID   = poVFKFeature->m_nFID;
     m_hStmt  = NULL;
-    m_iRowId = m_poDataBlock->GetFeatureCount() + 1; /* starts at 1 */
+    m_iRowId = (int)m_poDataBlock->GetFeatureCount() + 1; /* starts at 1 */
 }
 
 /*!
diff --git a/ogr/ogrsf_frmts/vfk/vfkproperty.cpp b/ogr/ogrsf_frmts/vfk/vfkproperty.cpp
index d113653..d39d2e3 100644
--- a/ogr/ogrsf_frmts/vfk/vfkproperty.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkproperty.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkproperty.cpp 25702 2013-03-07 17:17:54Z martinl $
+ * $Id: vfkproperty.cpp 27995 2014-11-21 20:14:07Z rouault $
  *
  * Project:  VFK Reader - Property definition
  * Purpose:  Implements VFKProperty class.
@@ -104,3 +104,27 @@ VFKProperty& VFKProperty::operator=(VFKProperty const& other)
     }
     return *this;
 }
+
+/*!
+  \brief Get string property
+  
+  \param escape TRUE to escape characters for SQL
+  
+  \return string buffer
+*/
+const char *VFKProperty::GetValueS(bool escape) const
+{
+    size_t ipos;
+
+    if (!escape)
+        return m_strValue.c_str();
+
+    CPLString strValue(m_strValue);
+    ipos = 0;
+    while (std::string::npos != (ipos = strValue.find("'", ipos))) {
+        strValue.replace(ipos, 1, "\'\'", 2);
+        ipos += 2;
+    }
+
+    return CPLSPrintf("%s", strValue.c_str());
+}
diff --git a/ogr/ogrsf_frmts/vfk/vfkreader.cpp b/ogr/ogrsf_frmts/vfk/vfkreader.cpp
index e321edb..251a9e0 100644
--- a/ogr/ogrsf_frmts/vfk/vfkreader.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkreader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkreader.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: vfkreader.cpp 27973 2014-11-16 17:40:22Z martinl $
  *
  * Project:  VFK Reader
  * Purpose:  Implements VFKReader class.
@@ -269,24 +269,25 @@ int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
             pszBlockName = GetDataBlockName(pszLine);
             
             if (pszBlockName && (!pszName || EQUAL(pszBlockName, pszName))) {
-                /* merge lines if needed */
-                if (pszLine[nLength - 2] == '\302' &&
-                    pszLine[nLength - 1] == '\244') {
-                    
-                    /* remove 0302 0244 (currency sign) from string */
-                    pszLine[nLength - 2] = '\0';
+                /* merge lines if needed
+
+                   See http://en.wikipedia.org/wiki/ISO/IEC_8859
+                   - \244 - general currency sign
+                */
+                if (pszLine[nLength - 1] == '\244') {
+                    /* remove \244 (currency sign) from string */
+                    pszLine[nLength - 1] = '\0';
                     
                     pszMultiLine.clear();
                     pszMultiLine = pszLine;
                     CPLFree(pszLine);
                     
                     while ((pszLine = ReadLine()) != NULL &&
-                           pszLine[strlen(pszLine) - 2] == '\302' &&
                            pszLine[strlen(pszLine) - 1] == '\244') {
                         /* append line */
                         pszMultiLine += pszLine;
-                        /* remove 0302 0244 (currency sign) from string */
-                        pszMultiLine[strlen(pszLine) - 2] = '\0';
+                        /* remove 0244 (currency sign) from string */
+                        pszMultiLine.erase(pszMultiLine.size() - 1);
 
                         CPLFree(pszLine);
                     } 
@@ -306,8 +307,7 @@ int VFKReader::ReadDataRecords(IVFKDataBlock *poDataBlock)
                         osBlockNameLast = CPLString(pszBlockName);
                     }
                 }
-                if (!poDataBlockCurrent)
-                {
+                if (!poDataBlockCurrent) {
                     CPLFree(pszBlockName);
                     continue; // assert ?
                 }
@@ -380,10 +380,11 @@ IVFKDataBlock *VFKReader::CreateDataBlock(const char *pszBlockName)
   \param poNewDataBlock pointer to VFKDataBlock instance
   \param pszDefn unused (FIXME ?)
 */
-void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock, CPL_UNUSED const char *pszDefn)
+void VFKReader::AddDataBlock(IVFKDataBlock *poNewDataBlock,
+                             CPL_UNUSED const char *pszDefn)
 {
     m_nDataBlockCount++;
-    
+
     m_papoDataBlock = (IVFKDataBlock **)
         CPLRealloc(m_papoDataBlock, sizeof (IVFKDataBlock *) * m_nDataBlockCount);
     m_papoDataBlock[m_nDataBlockCount-1] = poNewDataBlock;
diff --git a/ogr/ogrsf_frmts/vfk/vfkreader.h b/ogr/ogrsf_frmts/vfk/vfkreader.h
index 42593c0..99fc968 100644
--- a/ogr/ogrsf_frmts/vfk/vfkreader.h
+++ b/ogr/ogrsf_frmts/vfk/vfkreader.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkreader.h 26907 2014-01-31 17:54:09Z martinl $
+ * $Id: vfkreader.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  VFK Reader
  * Purpose:  Public Declarations for OGR free VFK Reader code.
@@ -86,7 +86,7 @@ public:
     bool                    IsNull()    const { return m_bIsNull; }
     int                     GetValueI() const { return m_nValue; }
     double                  GetValueD() const { return m_dValue; }
-    const char             *GetValueS() const { return m_strValue.c_str(); }
+    const char             *GetValueS(bool = FALSE) const;
 };
 
 /************************************************************************/
@@ -96,7 +96,7 @@ class CPL_DLL IVFKFeature
 {
 protected:
     IVFKDataBlock            *m_poDataBlock;
-    long                      m_nFID;
+    GIntBig                   m_nFID;
     OGRwkbGeometryType        m_nGeometryType;
     bool                      m_bGeometry;
     bool                      m_bValid;
@@ -111,15 +111,15 @@ public:
     IVFKFeature(IVFKDataBlock *);
     virtual ~IVFKFeature();
 
-    long                 GetFID() const { return m_nFID; }
-    void                 SetFID(long);
+    GIntBig              GetFID() const { return m_nFID; }
+    void                 SetFID(GIntBig);
     void                 SetGeometryType(OGRwkbGeometryType);
 
     bool                 IsValid() const { return m_bValid; }
     
     IVFKDataBlock       *GetDataBlock() const { return m_poDataBlock; }
     OGRwkbGeometryType   GetGeometryType() const { return m_nGeometryType; }
-    bool                 SetGeometry(OGRGeometry *);
+    bool                 SetGeometry(OGRGeometry *, const char * = NULL);
     OGRGeometry         *GetGeometry();
 
     bool                 LoadGeometry();
@@ -146,7 +146,7 @@ private:
     bool                 LoadGeometryPolygon();
 
 public:
-    VFKFeature(IVFKDataBlock *, long);
+    VFKFeature(IVFKDataBlock *, GIntBig);
     
     bool                 SetProperties(const char *);
     const VFKProperty   *GetProperty(int) const;
@@ -177,10 +177,11 @@ private:
 
 public:
     VFKFeatureSQLite(IVFKDataBlock *);
-    VFKFeatureSQLite(IVFKDataBlock *, int, long);
+    VFKFeatureSQLite(IVFKDataBlock *, int, GIntBig);
     VFKFeatureSQLite(const VFKFeature *);
 
     OGRErr               LoadProperties(OGRFeature *);
+    void                 SetRowId(int);
 };
 
 /************************************************************************/
@@ -239,7 +240,7 @@ protected:
 
     IVFKReader        *m_poReader;
 
-    long               m_nRecordCount[3];
+    GIntBig            m_nRecordCount[3];
     
     bool               AppendLineToRing(PointListArray *, const OGRLineString *, bool, bool = FALSE);
     int                LoadData();
@@ -260,10 +261,10 @@ public:
     void               SetProperties(const char *);
     int                GetPropertyIndex(const char *) const;
 
-    int                GetFeatureCount();
+    GIntBig            GetFeatureCount();
     void               SetFeatureCount(int, bool = FALSE);
     IVFKFeature       *GetFeatureByIndex(int) const;
-    IVFKFeature       *GetFeature(long);
+    IVFKFeature       *GetFeature(GIntBig);
     void               AddFeature(IVFKFeature *);
 
     void               ResetReading(int iIdx = -1);
@@ -301,7 +302,7 @@ public:
     VFKFeatureList     GetFeatures(int, GUIntBig);
     VFKFeatureList     GetFeatures(int, int, GUIntBig);
 
-    int                GetFeatureCount(const char *, const char *);
+    GIntBig            GetFeatureCount(const char *, const char *);
 };
 
 /************************************************************************/
@@ -310,6 +311,10 @@ public:
 class CPL_DLL VFKDataBlockSQLite : public IVFKDataBlock
 {
 private:
+    bool                 SetGeometryLineString(VFKFeatureSQLite *, OGRLineString *,
+                                               bool&, const char *,
+                                               std::vector<int>&, int&);
+
     int                  LoadGeometryPoint();
     int                  LoadGeometryLineStringSBP();
     int                  LoadGeometryLineStringHP();
@@ -320,13 +325,13 @@ private:
 
     bool                 IsRingClosed(const OGRLinearRing *);
     void                 UpdateVfkBlocks(int);
-    void                 UpdateFID(long int, std::vector<int>);
+    void                 UpdateFID(GIntBig, std::vector<int>);
 
 public:
     VFKDataBlockSQLite(const char *pszName, const IVFKReader *poReader) : IVFKDataBlock(pszName, poReader) {}
 
     const char          *GetKey() const;
-    IVFKFeature         *GetFeature(long);
+    IVFKFeature         *GetFeature(GIntBig);
     VFKFeatureSQLite    *GetFeature(const char *, GUIntBig, bool = FALSE);
     VFKFeatureSQLite    *GetFeature(const char **, GUIntBig *, int, bool = FALSE);
     VFKFeatureSQLiteList GetFeatures(const char **, GUIntBig *, int);
diff --git a/ogr/ogrsf_frmts/vfk/vfkreadersqlite.cpp b/ogr/ogrsf_frmts/vfk/vfkreadersqlite.cpp
index e6c2a46..c62ef9b 100644
--- a/ogr/ogrsf_frmts/vfk/vfkreadersqlite.cpp
+++ b/ogr/ogrsf_frmts/vfk/vfkreadersqlite.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vfkreadersqlite.cpp 27206 2014-04-16 21:23:33Z martinl $
+ * $Id: vfkreadersqlite.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  VFK Reader (SQLite)
  * Purpose:  Implements VFKReaderSQLite class.
@@ -121,7 +121,8 @@ VFKReaderSQLite::VFKReaderSQLite(const char *pszFilename) : VFKReader(pszFilenam
     if (m_bNewDb) {
         /* new DB, create support metadata tables */
         osCommand.Printf("CREATE TABLE %s (file_name text, table_name text, num_records integer, "
-                         "num_geometries integer, table_defn text)", VFK_DB_TABLE);
+                         "num_features integer, num_geometries integer, table_defn text)",
+                         VFK_DB_TABLE);
         ExecuteSQL(osCommand.c_str());
 
         /* header table */
@@ -247,6 +248,7 @@ int VFKReaderSQLite::ReadDataRecords(IVFKDataBlock *poDataBlock)
     if (nDataRecords > -1) {        /* read records from DB */
         /* read from  DB */
         long iFID;
+        int  iRowId;
         VFKFeatureSQLite *poNewFeature = NULL;
 
         poDataBlockCurrent = NULL;
@@ -259,18 +261,38 @@ int VFKReaderSQLite::ReadDataRecords(IVFKDataBlock *poDataBlock)
             poDataBlockCurrent->SetFeatureCount(0); /* avoid recursive call */
             
             pszName = poDataBlockCurrent->GetName();
-            if (pszName && EQUAL(pszName, "SBP")) {
-                continue; /* see LoadGeometry() */
-            }
-            
-            osSQL.Printf("SELECT %s FROM %s", FID_COLUMN, pszName);
+            CPLAssert(NULL != pszName);
+
+            osSQL.Printf("SELECT %s,_rowid_ FROM %s ",
+                         FID_COLUMN, pszName);
+            if (EQUAL(pszName, "SBP"))
+              osSQL += "WHERE PORADOVE_CISLO_BODU = 1 ";
+            osSQL += "ORDER BY ";
+            osSQL += FID_COLUMN;
             hStmt = PrepareStatement(osSQL.c_str());
-            nDataRecords = 1;
+            nDataRecords = 0;
             while (ExecuteSQL(hStmt) == OGRERR_NONE) {
                 iFID = sqlite3_column_int(hStmt, 0);
-                poNewFeature = new VFKFeatureSQLite(poDataBlockCurrent, nDataRecords++, iFID);
+                iRowId = sqlite3_column_int(hStmt, 1);
+                poNewFeature = new VFKFeatureSQLite(poDataBlockCurrent, iRowId, iFID);
                 poDataBlockCurrent->AddFeature(poNewFeature);
+                nDataRecords++;
+            }
+
+            /* check DB consistency */
+            osSQL.Printf("SELECT num_features FROM %s WHERE table_name = '%s'",
+                         VFK_DB_TABLE, pszName);
+            hStmt = PrepareStatement(osSQL.c_str());
+            if (ExecuteSQL(hStmt) == OGRERR_NONE) {
+                int nFeatDB;
+
+                nFeatDB = sqlite3_column_int(hStmt, 0);
+                if (nFeatDB > 0 && nFeatDB != poDataBlockCurrent->GetFeatureCount())
+                    CPLError(CE_Failure, CPLE_AppDefined, 
+                             "%s: Invalid number of features " CPL_FRMT_GIB " (should be %d)",
+                             pszName, poDataBlockCurrent->GetFeatureCount(), nFeatDB);
             }
+            sqlite3_finalize(hStmt);
         }
     }
     else {                          /* read from VFK file and insert records into DB */
@@ -446,8 +468,8 @@ void VFKReaderSQLite::AddDataBlock(IVFKDataBlock *poDataBlock, const char *pszDe
         
         /* update VFK_DB_TABLE meta-table */
         osCommand.Printf("INSERT INTO %s (file_name, table_name, "
-                         "num_records, num_geometries, table_defn) VALUES "
-			 "('%s', '%s', -1, 0, '%s')",
+                         "num_records, num_features, num_geometries, table_defn) VALUES "
+			 "('%s', '%s', -1, 0, 0, '%s')",
 			 VFK_DB_TABLE, m_pszFilename, pszBlockName, pszDefn);
 	
         ExecuteSQL(osCommand.c_str());
@@ -540,7 +562,7 @@ OGRErr VFKReaderSQLite::ExecuteSQL(const char *pszSQLCommand, bool bQuiet)
                      "In ExecuteSQL(%s): %s",
                      pszSQLCommand, pszErrMsg);
         else
-            CPLDebug("OGR-VFK", 
+            CPLError(CE_Warning, CPLE_AppDefined, 
                      "In ExecuteSQL(%s): %s",
                      pszSQLCommand, pszErrMsg);
         
@@ -567,6 +589,8 @@ OGRErr VFKReaderSQLite::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFea
 
     const VFKProperty *poProperty;
 
+    VFKFeatureSQLite *poNewFeature;
+    
     pszBlockName = poDataBlock->GetName();
     osCommand.Printf("INSERT INTO '%s' VALUES(", pszBlockName);
     
@@ -589,7 +613,7 @@ OGRErr VFKReaderSQLite::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFea
                 if (poDataBlock->GetProperty(i)->IsIntBig())
 		    osValue.Printf("%s", poProperty->GetValueS());
                 else
-                    osValue.Printf("'%s'", poProperty->GetValueS());
+                    osValue.Printf("'%s'", poProperty->GetValueS(TRUE));
                 break;
             default:
                 osValue.Printf("'%s'", poProperty->GetValueS());
@@ -598,7 +622,7 @@ OGRErr VFKReaderSQLite::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFea
         }
         osCommand += osValue;
     }
-    osValue.Printf(",%lu", poFeature->GetFID());
+    osValue.Printf("," CPL_FRMT_GIB, poFeature->GetFID());
     if (poDataBlock->GetGeometryType() != wkbNone) {
 	osValue += ",NULL";
     }
@@ -608,13 +632,16 @@ OGRErr VFKReaderSQLite::AddFeature(IVFKDataBlock *poDataBlock, VFKFeature *poFea
     if (ExecuteSQL(osCommand.c_str(), TRUE) != OGRERR_NONE)
         return OGRERR_FAILURE;
     
-    if (!EQUAL(pszBlockName, "SBP")) { /* SBP features are added when building geometry */
-        VFKFeatureSQLite *poNewFeature;
-        
-        poNewFeature = new VFKFeatureSQLite(poDataBlock, poDataBlock->GetFeatureCount() + 1,
-                                            poFeature->GetFID());
-        poDataBlock->AddFeature(poNewFeature);
+    if (EQUAL(pszBlockName, "SBP")) {
+        poProperty = poFeature->GetProperty("PORADOVE_CISLO_BODU");
+        CPLAssert(NULL != poProperty);
+        if (!EQUAL(poProperty->GetValueS(), "1"))
+            return OGRERR_NONE;
     }
+        
+    poNewFeature = new VFKFeatureSQLite(poDataBlock, poDataBlock->GetRecordCount(RecordValid) + 1,
+                                        poFeature->GetFID());
+    poDataBlock->AddFeature(poNewFeature);
     
     return OGRERR_NONE;
 }
diff --git a/ogr/ogrsf_frmts/vrt/GNUmakefile b/ogr/ogrsf_frmts/vrt/GNUmakefile
index 04e6ae8..33cdbbb 100644
--- a/ogr/ogrsf_frmts/vrt/GNUmakefile
+++ b/ogr/ogrsf_frmts/vrt/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrvrtdatasource.o ogrvrtlayer.o ogrvrtdriver.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../generic $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../generic  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/vrt/drv_vrt.html b/ogr/ogrsf_frmts/vrt/drv_vrt.html
index f38e0a1..fde681e 100644
--- a/ogr/ogrsf_frmts/vrt/drv_vrt.html
+++ b/ogr/ogrsf_frmts/vrt/drv_vrt.html
@@ -34,13 +34,23 @@ is to say, the <i>FID</i> element is not specified</li>
 
 The root element of the XML control file is <b>OGRVRTDataSource</b>.  It has
 an <b>OGRVRTLayer</b> (or <b>OGRVRTWarpedLayer</b> or <b>OGRVRTUnionLayer</b> starting
-with GDAL 1.10.0) child for each layer in the virtual datasource.<p>
+with GDAL 1.10.0) child for each layer in the virtual datasource, and a
+<b>Metadata</b> element.<p>
 
 A <a href="http://svn.osgeo.org/gdal/trunk/gdal/data/ogrvrt.xsd">XML schema of the OGR VRT format</a>
 is available. Starting with GDAL 1.11, when GDAL is configured with libXML2 support, that
 schema will be used to validate the VRT documents. Non-conformities will be reported only as
 warnings. That validation can be disabled by setting the GDAL_XML_VALIDATION configuration option to NO.<p>
 
+<p>
+<b>Metadata</b> (optional): (GDAL >= 2.0) This element contains a list of metadata name/value 
+pairs associated with the dataset as a whole. It has
+<MDI> (metadata item) subelements which have a "key" attribute and the value
+as the data of the element. The Metadata element can be repeated multiple times,
+in which case it must be accompanied with a "domain" attribute to indicate the
+name of the metadata domain.
+</p>
+
 A <b>OGRVRTLayer</b> element should have a <b>name</b> attribute with the layer name, and may have the
 following subelements:
 
@@ -55,6 +65,21 @@ datasource should be opened in shared mode. Defaults to OFF for SrcLayer use and
 
 <br>
 
+<li> <b>OpenOptions</b> (optional): (GDAL >= 2.0) This element may list a number of open
+options as child elements of the form <OOI key="key_name">value_name</OOI></li>
+
+<br>
+
+<li> <b>Metadata</b> (optional): (GDAL >= 2.0) This element contains a list of metadata name/value 
+pairs associated with the layer as a whole. It has
+<MDI> (metadata item) subelements which have a "key" attribute and the value
+as the data of the element. The Metadata element can be repeated multiple times,
+in which case it must be accompanied with a "domain" attribute to indicate the
+name of the metadata domain.
+</li>
+
+<br>
+
 <li> <b>SrcLayer</b> (optional): The value is the name of the layer on the
 source data source from which this virtual layer should be derived.  If this
 element isn't provided, then the SrcSQL element must be provided.</li>
@@ -74,7 +99,10 @@ the default dialect of the datasource will be used.</li>
 
 <li> <b>FID</b> (optional): Name of the attribute column from which the 
 FID of features should be derived.  If not provided, the FID of the source
-features will be used directly.</li>
+features will be used directly. The layer will report the FID column name only
+if it is also reported as a regular field. Starting with GDAL 2.0, a "name"
+attribute can be specified on the FID element so that the FID column name is
+always reported.</li>
 
 <br>
 
@@ -120,13 +148,17 @@ If set to FALSE, the source geometry fields will only be used to build the geome
 <p>
 Starting with OGR 1.11, the GeometryField element can be repeated as many times
 as necessary to create multiple geometry fields. It accepts a <b>name</b>
-attribute (recommanded) that will be used to define the VRT geometry field name. When <b>encoding</b> is
+attribute (recommended) that will be used to define the VRT geometry field name. When <b>encoding</b> is
 not specified, the <b>field</b> attribute will be used to determine the corresponding
 geometry field name in the source layer. If neither <b>encoding</b> nor <b>field</b>
 are specified, it is assumed that the name of source geometry field is the value
 of the <b>name</b> attribute.
 </p>
 <p>
+Starting with GDAL 2.0, the optional <b>nullable</b> attribute can be used to specify
+whether the geometry field is nullable. It defaults to "true".</li>
+</p>
+<p>
 When several geometry fields are used, the following child elements of <b>GeometryField</b>
 can be defined to explicitely set the geometry type, SRS, source region, or extent.
 <ul>
@@ -146,7 +178,7 @@ element to wkbNone.
 
 <li> <b>SrcRegion</b> (optionnal, from GDAL 1.7.0) : This element is used
 to define an initial spatial filter for the source features. This spatial
-filter will be combined with any spatial filter explicitely set on the VRT
+filter will be combined with any spatial filter explicitly set on the VRT
 layer with the SetSpatialFilter() method. The value of the element must be
 a valid WKT string defining a polygon. An optional <b>clip</b> attribute
 can be set to "TRUE" to clip the geometries to the source region, otherwise
@@ -163,10 +195,14 @@ may have the following attributes:
 <li> <b>type</b>: the field type, one of "Integer", "IntegerList", 
 "Real", "RealList", "String", "StringList", "Binary", "Date", "Time", 
 or "DateTime". Defaults to "String".
+<li> <b>subtype</b>: (GDAL >= 2.0) the field subtype, one of "None", "Boolean", 
+"Int16", "Float32". Defaults to "None".
 <li> <b>width</b>: the field width. Defaults to unknown.
 <li> <b>precision</b>: the field width. Defaults to zero.
 <li> <b>src</b>: the name of the source field to be copied to this one.
 Defaults to the value of "name".
+<li> <b>nullable</b> (GDAL >= 2.0) can be used to specify
+whether the field is nullable. It defaults to "true".</li>
 </ul>
 </li>
 
@@ -174,12 +210,12 @@ Defaults to the value of "name".
 
 <li> <b>FeatureCount</b> (optional, from GDAL 1.10.0) : This element is used
 to define the feature count of the layer (when no spatial or attribute filter is set).
-This can be usefull on static data, when getting the feature count from the source layer is slow.</li>
+This can be useful on static data, when getting the feature count from the source layer is slow.</li>
 
 <br>
 
 <li> <b>ExtentXMin</b>, <b>ExtentYMin</b>, <b>ExtentXMax</b> and <b>ExtentXMax</b> (optional, from GDAL 1.10.0) :
-Those elements are used to define the extent of the layer. This can be usefull on static data, when
+Those elements are used to define the extent of the layer. This can be useful on static data, when
 getting the extent from the source layer is slow.</li>
 
 <br>
@@ -207,7 +243,7 @@ reference to use for the layer after reprojection. </li>
 <br>
 
 <li> <b>ExtentXMin</b>, <b>ExtentYMin</b>, <b>ExtentXMax</b> and <b>ExtentXMax</b> (optional, from GDAL 1.10.0) :
-Those elements are used to define the extent of the layer. This can be usefull on static data, when
+Those elements are used to define the extent of the layer. This can be useful on static data, when
 getting the extent from the source layer is slow.</li>
 <br>
 
@@ -292,7 +328,7 @@ the layer as a point layer, and as being in the WGS84 coordinate system.<p>
 
 <h2>Example: Renaming attributes</h2>
 
-It can be usefull in some circumstances to be able to rename the field names 
+It can be useful in some circumstances to be able to rename the field names
 from a source layer to other names. This is particularly true when you want 
 to transcode to a format whose schema is fixed, such as GPX 
 (<name>, <desc&gt, etc.).  This can be accomplished using
diff --git a/ogr/ogrsf_frmts/vrt/ogr_vrt.h b/ogr/ogrsf_frmts/vrt/ogr_vrt.h
index 12b59b7..bd4ccfc 100644
--- a/ogr/ogrsf_frmts/vrt/ogr_vrt.h
+++ b/ogr/ogrsf_frmts/vrt/ogr_vrt.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_vrt.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_vrt.h 28522 2015-02-18 14:16:40Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Private definitions for OGR/VRT driver.
@@ -75,6 +75,8 @@ class OGRVRTGeomFieldProps
         int                 bUseSpatialSubquery;
 
         OGREnvelope         sStaticEnvelope;
+        
+        int                 bNullable;
 
                         OGRVRTGeomFieldProps();
                        ~OGRVRTGeomFieldProps();
@@ -99,7 +101,7 @@ class OGRVRTLayer : public OGRLayer
 
     OGRFeatureDefn      *poFeatureDefn;
 
-    OGRDataSource       *poSrcDS;
+    GDALDataset         *poSrcDS;
     OGRLayer            *poSrcLayer;
     OGRFeatureDefn      *poSrcFeatureDefn;
     int                 bNeedReset;
@@ -110,6 +112,7 @@ class OGRVRTLayer : public OGRLayer
     char                *pszAttrFilter;
 
     int                 iFIDField; // -1 means pass through. 
+    CPLString           osFIDFieldName;
     int                 iStyleField; // -1 means pass through.
 
     // Attribute Mapping
@@ -128,7 +131,7 @@ class OGRVRTLayer : public OGRLayer
     OGRFeatureDefn     *GetSrcLayerDefn();
     void                ClipAndAssignSRS(OGRFeature* poFeature);
 
-    int                 nFeatureCount;
+    GIntBig             nFeatureCount;
 
     int                 bError;
 
@@ -155,15 +158,15 @@ class OGRVRTLayer : public OGRLayer
     virtual void        ResetReading();
     virtual OGRFeature *GetNextFeature();
 
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
 
-    virtual OGRErr      SetNextByIndex( long nIndex );
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex );
 
     virtual OGRFeatureDefn *GetLayerDefn();
 
     virtual OGRSpatialReference *GetSpatialRef();
 
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
@@ -176,11 +179,11 @@ class OGRVRTLayer : public OGRLayer
     virtual void        SetSpatialFilter( OGRGeometry * poGeomIn );
     virtual void        SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn );
 
-    virtual OGRErr      CreateFeature( OGRFeature* poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature* poFeature );
 
-    virtual OGRErr      SetFeature( OGRFeature* poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature* poFeature );
 
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual OGRErr      SyncToDisk();
 
@@ -191,15 +194,25 @@ class OGRVRTLayer : public OGRLayer
     virtual OGRErr      RollbackTransaction();
 
     virtual OGRErr      SetIgnoredFields( const char **papszFields );
+
+    GDALDataset*        GetSrcDataset();
 };
 
 /************************************************************************/
 /*                           OGRVRTDataSource                            */
 /************************************************************************/
 
+typedef enum
+{
+    OGR_VRT_PROXIED_LAYER,
+    OGR_VRT_LAYER,
+    OGR_VRT_OTHER_LAYER,
+} OGRLayerType;
+
 class OGRVRTDataSource : public OGRDataSource
 {
     OGRLayer          **papoLayers;
+    OGRLayerType       *paeLayerType;
     int                 nLayers;
     
     char               *pszName;
@@ -225,7 +238,7 @@ class OGRVRTDataSource : public OGRDataSource
     int                 bRecursionDetected;
 
   public:
-                        OGRVRTDataSource();
+                        OGRVRTDataSource(GDALDriver* poDriver);
                         ~OGRVRTDataSource();
 
     OGRLayer*           InstanciateLayer(CPLXMLNode *psLTree,
@@ -247,6 +260,8 @@ class OGRVRTDataSource : public OGRDataSource
 
     int                 TestCapability( const char * );
 
+    virtual char      **GetFileList();
+
     /* Anti-recursion mechanism for standard Open */
     void                SetCallLevel(int nCallLevelIn) { nCallLevel = nCallLevelIn; }
     int                 GetCallLevel() { return nCallLevel; }
@@ -262,20 +277,6 @@ class OGRVRTDataSource : public OGRDataSource
     int                 IsInForbiddenNames(const char* pszOtherDSName);
 };
 
-/************************************************************************/
-/*                             OGRVRTDriver                             */
-/************************************************************************/
-
-class OGRVRTDriver : public OGRSFDriver
-{
-  public:
-                ~OGRVRTDriver();
-                
-    const char *GetName();
-    OGRDataSource *Open( const char *, int );
-    int         TestCapability( const char * );
-};
-
 OGRwkbGeometryType OGRVRTGetGeometryType(const char* pszGType, int* pbError);
 
 #endif /* ndef _OGR_VRT_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/vrt/ogrvrtdatasource.cpp b/ogr/ogrsf_frmts/vrt/ogrvrtdatasource.cpp
index 45b652e..9ff2349 100644
--- a/ogr/ogrsf_frmts/vrt/ogrvrtdatasource.cpp
+++ b/ogr/ogrsf_frmts/vrt/ogrvrtdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrvrtdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrvrtdatasource.cpp 28950 2015-04-18 23:24:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRVRTDataSource class.
@@ -34,7 +34,7 @@
 #include "ogrwarpedlayer.h"
 #include "ogrunionlayer.h"
 
-CPL_CVSID("$Id: ogrvrtdatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrvrtdatasource.cpp 28950 2015-04-18 23:24:49Z rouault $");
 
 /************************************************************************/
 /*                       OGRVRTGetGeometryType()                        */
@@ -55,6 +55,11 @@ static const OGRGeomTypeName asGeomTypeNames[] = { /* 25D versions are implicit
     { wkbMultiLineString, "wkbMultiLineString" },
     { wkbMultiPolygon, "wkbMultiPolygon" },
     { wkbGeometryCollection, "wkbGeometryCollection" },
+    { wkbCircularString, "wkbCircularString" },
+    { wkbCompoundCurve, "wkbCompoundCurve" },
+    { wkbCurvePolygon, "wkbCurvePolygon" },
+    { wkbGeometryCollection, "wkbMultiCurve" },
+    { wkbMultiSurface, "wkbMultiSurface" },
     { wkbNone, "wkbNone" },
     { wkbNone, NULL }
 };
@@ -74,8 +79,8 @@ OGRwkbGeometryType OGRVRTGetGeometryType(const char* pszGType, int* pbError)
         {
             eGeomType = asGeomTypeNames[iType].eType;
 
-            if( strstr(pszGType,"25D") != NULL )
-                eGeomType = (OGRwkbGeometryType) (eGeomType | wkb25DBit);
+            if( strstr(pszGType,"25D") != NULL || strstr(pszGType,"Z") != NULL )
+                eGeomType = wkbSetZ(eGeomType);
             break;
         }
     }
@@ -93,17 +98,19 @@ OGRwkbGeometryType OGRVRTGetGeometryType(const char* pszGType, int* pbError)
 /*                          OGRVRTDataSource()                          */
 /************************************************************************/
 
-OGRVRTDataSource::OGRVRTDataSource()
+OGRVRTDataSource::OGRVRTDataSource(GDALDriver* poDriver)
 
 {
     pszName = NULL;
     papoLayers = NULL;
+    paeLayerType = NULL;
     nLayers = 0;
     psTree = NULL;
     nCallLevel = 0;
     poLayerPool = NULL;
     poParentDS = NULL;
     bRecursionDetected = FALSE;
+    this->poDriver = poDriver;
 }
 
 /************************************************************************/
@@ -121,6 +128,7 @@ OGRVRTDataSource::~OGRVRTDataSource()
         delete papoLayers[i];
     
     CPLFree( papoLayers );
+    CPLFree( paeLayerType );
 
     if( psTree != NULL)
         CPLDestroyXMLNode( psTree );
@@ -839,6 +847,11 @@ int OGRVRTDataSource::Initialize( CPLXMLNode *psTree, const char *pszNewName,
         poLayerPool = new OGRLayerPool(nMaxSimultaneouslyOpened);
 
 /* -------------------------------------------------------------------- */
+/*      Apply any dataset level metadata.                               */
+/* -------------------------------------------------------------------- */
+    oMDMD.XMLInit( psVRTDSXML, TRUE );
+
+/* -------------------------------------------------------------------- */
 /*      Look for layers.                                                */
 /* -------------------------------------------------------------------- */
     CPLXMLNode *psLTree;
@@ -858,9 +871,25 @@ int OGRVRTDataSource::Initialize( CPLXMLNode *psTree, const char *pszNewName,
 /* -------------------------------------------------------------------- */
 /*      Add layer to data source layer list.                            */
 /* -------------------------------------------------------------------- */
+        nLayers ++;
         papoLayers = (OGRLayer **)
-            CPLRealloc( papoLayers,  sizeof(OGRLayer *) * (nLayers+1) );
-        papoLayers[nLayers++] = poLayer;
+            CPLRealloc( papoLayers,  sizeof(OGRLayer *) * nLayers );
+        papoLayers[nLayers-1] = poLayer;
+
+        paeLayerType = (OGRLayerType*)
+            CPLRealloc( paeLayerType,  sizeof(int) * nLayers );
+        if( poLayerPool != NULL && EQUAL(psLTree->pszValue,"OGRVRTLayer"))
+        {
+            paeLayerType[nLayers - 1] = OGR_VRT_PROXIED_LAYER;
+        }
+        else if( EQUAL(psLTree->pszValue,"OGRVRTLayer") )
+        {
+            paeLayerType[nLayers - 1] = OGR_VRT_LAYER;
+        }
+        else
+        {
+            paeLayerType[nLayers - 1] = OGR_VRT_OTHER_LAYER;
+        }
     }
 
     return TRUE;
@@ -870,8 +899,10 @@ int OGRVRTDataSource::Initialize( CPLXMLNode *psTree, const char *pszNewName,
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGRVRTDataSource::TestCapability( CPL_UNUSED const char * pszCap )
+int OGRVRTDataSource::TestCapability( const char * pszCap )
 {
+    if( EQUAL(pszCap,ODsCCurveGeometries) )
+        return TRUE;
     return FALSE;
 }
 
@@ -905,3 +936,45 @@ int OGRVRTDataSource::IsInForbiddenNames(const char* pszOtherDSName)
 {
     return aosOtherDSNameSet.find(pszOtherDSName) != aosOtherDSNameSet.end();
 }
+
+/************************************************************************/
+/*                             GetFileList()                             */
+/************************************************************************/
+
+char **OGRVRTDataSource::GetFileList()
+{
+    CPLStringList oList;
+    oList.AddString( GetName() );
+    for(int i=0; i<nLayers; i++ )
+    {
+        OGRLayer* poLayer = papoLayers[i];
+        OGRVRTLayer* poVRTLayer = NULL;
+        switch( paeLayerType[nLayers - 1] )
+        {
+            case OGR_VRT_PROXIED_LAYER:
+                poVRTLayer = (OGRVRTLayer*) ((OGRProxiedLayer*)poLayer)->GetUnderlyingLayer();
+                break;
+            case OGR_VRT_LAYER:
+                poVRTLayer = (OGRVRTLayer*) poLayer;
+                break;
+            default:
+                break;
+        }
+        if( poVRTLayer != NULL )
+        {
+            GDALDataset* poSrcDS = poVRTLayer->GetSrcDataset();
+            if( poSrcDS != NULL )
+            {
+                char** papszFileList = poSrcDS->GetFileList();
+                char** papszIter = papszFileList;
+                for(; papszIter != NULL && *papszIter != NULL; papszIter++ )
+                {
+                    if( oList.FindString(*papszIter) < 0 )
+                        oList.AddString(*papszIter);
+                }
+                CSLDestroy(papszFileList);
+            }
+        }
+    }
+    return oList.StealList();
+}
diff --git a/ogr/ogrsf_frmts/vrt/ogrvrtdriver.cpp b/ogr/ogrsf_frmts/vrt/ogrvrtdriver.cpp
index a71188d..3f121ed 100644
--- a/ogr/ogrsf_frmts/vrt/ogrvrtdriver.cpp
+++ b/ogr/ogrsf_frmts/vrt/ogrvrtdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrvrtdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrvrtdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRVRTDriver class.
@@ -31,52 +31,65 @@
 #include "ogr_vrt.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrvrtdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrvrtdriver.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
-/*                            ~OGRVRTDriver()                            */
+/*                           OGRVRTErrorHandler()                       */
 /************************************************************************/
 
-OGRVRTDriver::~OGRVRTDriver()
+static void CPL_STDCALL OGRVRTErrorHandler(CPL_UNUSED CPLErr eErr,
+                                           CPL_UNUSED int nType,
+                                           const char* pszMsg)
 {
+    std::vector<CPLString>* paosErrors = (std::vector<CPLString>* )CPLGetErrorHandlerUserData();
+    paosErrors->push_back(pszMsg);
 }
 
 /************************************************************************/
-/*                              GetName()                               */
+/*                         OGRVRTDriverIdentify()                       */
 /************************************************************************/
 
-const char *OGRVRTDriver::GetName()
+static int OGRVRTDriverIdentify( GDALOpenInfo* poOpenInfo )
 {
-    return "VRT";
-}
-
-/************************************************************************/
-/*                           OGRVRTErrorHandler()                       */
-/************************************************************************/
+    if( !poOpenInfo->bStatOK )
+    {
+/* -------------------------------------------------------------------- */
+/*      Are we being passed the XML definition directly?                */
+/*      Skip any leading spaces/blanks.                                 */
+/* -------------------------------------------------------------------- */
+        const char *pszTestXML = poOpenInfo->pszFilename;
+        while( *pszTestXML != '\0' && isspace( (unsigned char)*pszTestXML ) )
+            pszTestXML++;
+        if( EQUALN(pszTestXML,"<OGRVRTDataSource>",18) )
+        {
+            return TRUE;
+        }
+        return FALSE;
+    }
 
-static void CPL_STDCALL OGRVRTErrorHandler(CPL_UNUSED CPLErr eErr,
-                                           CPL_UNUSED int nType,
-                                           const char* pszMsg)
-{
-    std::vector<CPLString>* paosErrors = (std::vector<CPLString>* )CPLGetErrorHandlerUserData();
-    paosErrors->push_back(pszMsg);
+    return ( poOpenInfo->fpL != NULL &&
+             strstr((const char*)poOpenInfo->pabyHeader,"<OGRVRTDataSource") != NULL );
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRVRTDriver::Open( const char * pszFilename,
-                                   int bUpdate )
+static GDALDataset *OGRVRTDriverOpen( GDALOpenInfo* poOpenInfo )
+
 {
     OGRVRTDataSource     *poDS;
+
+    if( !OGRVRTDriverIdentify(poOpenInfo) )
+        return NULL;
+
     char *pszXML = NULL;
 
 /* -------------------------------------------------------------------- */
 /*      Are we being passed the XML definition directly?                */
 /*      Skip any leading spaces/blanks.                                 */
 /* -------------------------------------------------------------------- */
-    const char *pszTestXML = pszFilename;
+    const char *pszTestXML = poOpenInfo->pszFilename;
     while( *pszTestXML != '\0' && isspace( (unsigned char)*pszTestXML ) )
         pszTestXML++;
 
@@ -90,29 +103,11 @@ OGRDataSource *OGRVRTDriver::Open( const char * pszFilename,
 /* -------------------------------------------------------------------- */
     else
     {
-        VSILFILE *fp;
-        char achHeader[512];
-
-        fp = VSIFOpenL( pszFilename, "rb" );
-
-        if( fp == NULL )
-            return NULL;
-
-        memset( achHeader, 0, sizeof(achHeader) );
-        VSIFReadL( achHeader, 1, sizeof(achHeader)-1, fp );
-
-        if( strstr(achHeader,"<OGRVRTDataSource") == NULL )
-        {
-            VSIFCloseL( fp );
-            return NULL;
-        }
-
         VSIStatBufL sStatBuf;
-        if ( VSIStatL( pszFilename, &sStatBuf ) != 0 ||
+        if ( VSIStatL( poOpenInfo->pszFilename, &sStatBuf ) != 0 ||
              sStatBuf.st_size > 1024 * 1024 )
         {
             CPLDebug( "VRT", "Unreasonable long file, not likely really VRT" );
-            VSIFCloseL( fp );
             return NULL;
         }
 
@@ -121,23 +116,19 @@ OGRDataSource *OGRVRTDriver::Open( const char * pszFilename,
 /* -------------------------------------------------------------------- */
         int nLen = (int) sStatBuf.st_size;
 
-        VSIFSeekL( fp, 0, SEEK_SET );
-
         pszXML = (char *) VSIMalloc(nLen+1);
         if (pszXML == NULL)
-        {
-            VSIFCloseL( fp );
             return NULL;
-        }
+
         pszXML[nLen] = '\0';
-        if( ((int) VSIFReadL( pszXML, 1, nLen, fp )) != nLen )
+        VSIFSeekL( poOpenInfo->fpL, 0, SEEK_SET );
+        if( ((int) VSIFReadL( pszXML, 1, nLen, poOpenInfo->fpL )) != nLen )
         {
             CPLFree( pszXML );
-            VSIFCloseL( fp );
-
             return NULL;
         }
-        VSIFCloseL( fp );
+        VSIFCloseL( poOpenInfo->fpL );
+        poOpenInfo->fpL = NULL;
     }
 
 /* -------------------------------------------------------------------- */
@@ -182,10 +173,11 @@ OGRDataSource *OGRVRTDriver::Open( const char * pszFilename,
 /* -------------------------------------------------------------------- */
 /*      Create a virtual datasource configured based on this XML input. */
 /* -------------------------------------------------------------------- */
-    poDS = new OGRVRTDataSource();
-    poDS->SetDriver(this);
+    poDS = new OGRVRTDataSource((GDALDriver*)GDALGetDriverByName( "OGR_VRT" ));
+
     /* psTree is owned by poDS */
-    if( !poDS->Initialize( psTree, pszFilename, bUpdate ) )
+    if( !poDS->Initialize( psTree, poOpenInfo->pszFilename,
+                           poOpenInfo->eAccess == GA_Update ) )
     {
         delete poDS;
         return NULL;
@@ -195,19 +187,31 @@ OGRDataSource *OGRVRTDriver::Open( const char * pszFilename,
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRVRTDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRVRT()                           */
 /************************************************************************/
 
 void RegisterOGRVRT()
+
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRVRTDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "OGR_VRT" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "OGR_VRT" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "VRT - Virtual Datasource" );
+        poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vrt" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_vrt.html" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnOpen = OGRVRTDriverOpen;
+        poDriver->pfnIdentify = OGRVRTDriverIdentify;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
diff --git a/ogr/ogrsf_frmts/vrt/ogrvrtlayer.cpp b/ogr/ogrsf_frmts/vrt/ogrvrtlayer.cpp
index 4a30ecd..cb8e485 100644
--- a/ogr/ogrsf_frmts/vrt/ogrvrtlayer.cpp
+++ b/ogr/ogrsf_frmts/vrt/ogrvrtlayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrvrtlayer.cpp 28159 2014-12-17 11:04:07Z rouault $
+ * $Id: ogrvrtlayer.cpp 28950 2015-04-18 23:24:49Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Implements OGRVRTLayer class.
@@ -34,7 +34,7 @@
 #include "ogrpgeogeometry.h"
 #include <string>
 
-CPL_CVSID("$Id: ogrvrtlayer.cpp 28159 2014-12-17 11:04:07Z rouault $");
+CPL_CVSID("$Id: ogrvrtlayer.cpp 28950 2015-04-18 23:24:49Z rouault $");
 
 #define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource."
 
@@ -53,6 +53,7 @@ OGRVRTGeomFieldProps::OGRVRTGeomFieldProps()
     bSrcClip = FALSE;
     poSrcRegion = NULL;
     bReportSrcColumn = TRUE;
+    bNullable = TRUE;
 }
 
 /************************************************************************/
@@ -128,10 +129,7 @@ OGRVRTLayer::~OGRVRTLayer()
         if( bSrcLayerFromSQL && poSrcLayer )
             poSrcDS->ReleaseResultSet( poSrcLayer );
 
-        if( bSrcDSShared )
-            OGRSFDriverRegistrar::GetRegistrar()->ReleaseDataSource( poSrcDS );
-        else
-            delete poSrcDS;
+        GDALClose( (GDALDatasetH) poSrcDS );
     }
 
     if( poFeatureDefn )
@@ -183,6 +181,7 @@ int OGRVRTLayer::FastInitialize( CPLXMLNode *psLTree, const char *pszVRTDirector
     }
 
     osName = pszLayerName;
+    SetDescription( pszLayerName );
 
 /* -------------------------------------------------------------------- */
 /*      Do we have a fixed geometry type?  If so use it                 */
@@ -239,7 +238,7 @@ int OGRVRTLayer::FastInitialize( CPLXMLNode *psLTree, const char *pszVRTDirector
      const char* pszFeatureCount = CPLGetXMLValue( psLTree, "FeatureCount", NULL );
      if( pszFeatureCount != NULL )
      {
-         nFeatureCount = atoi(pszFeatureCount);
+         nFeatureCount = CPLAtoGIntBig(pszFeatureCount);
      }
 
 /* -------------------------------------------------------------------- */
@@ -498,6 +497,8 @@ int OGRVRTLayer::ParseGeometryField(CPLXMLNode* psNode,
          poProps->sStaticEnvelope.MaxY = CPLAtof(pszExtentYMax);
      }
 
+    poProps->bNullable = CSLTestBoolean(CPLGetXMLValue( psNode, "nullable", "TRUE" ));
+
     return TRUE;
 }
 
@@ -510,7 +511,7 @@ int OGRVRTLayer::FullInitialize()
 {
     const char *pszSharedSetting = NULL;
     const char *pszSQL = NULL;
-    const char *pszFIDFieldName = NULL;
+    const char *pszSrcFIDFieldName = NULL;
     const char *pszStyleFieldName = NULL;
     CPLXMLNode *psChild = NULL;
     int bFoundGeometryField = FALSE;
@@ -530,7 +531,6 @@ int OGRVRTLayer::FullInitialize()
 /*      Figure out the data source name.  It may be treated relative    */
 /*      to vrt filename, but normally it is used directly.              */
 /* -------------------------------------------------------------------- */
-    OGRSFDriverRegistrar *poReg = OGRSFDriverRegistrar::GetRegistrar();
     char *pszSrcDSName = (char *) CPLGetXMLValue(psLTree,"SrcDataSource",NULL);
 
     if( pszSrcDSName == NULL )
@@ -604,10 +604,10 @@ try_again:
     CPLErrorReset();
     if( EQUAL(pszSrcDSName,"@dummy@") )
     {
-        OGRSFDriver *poMemDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
+        GDALDriver *poMemDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
         if (poMemDriver != NULL)
         {
-            poSrcDS = poMemDriver->CreateDataSource( "@dummy@" );
+            poSrcDS = poMemDriver->Create( "@dummy@", 0, 0, 0, GDT_Unknown, NULL );
             poSrcDS->CreateLayer( "@dummy@" );
         }
     }
@@ -620,7 +620,12 @@ try_again:
         }
         else
         {
-            poSrcDS = poReg->OpenShared( pszSrcDSName, bUpdate, NULL );
+            char** papszOpenOptions = GDALDeserializeOpenOptionsFromXML(psLTree);
+            int nFlags = GDAL_OF_VECTOR | GDAL_OF_SHARED;
+            if( bUpdate ) nFlags |= GDAL_OF_UPDATE;
+            poSrcDS = (GDALDataset*) GDALOpenEx( pszSrcDSName, nFlags, NULL,
+                                (const char* const* )papszOpenOptions, NULL );
+            CSLDestroy(papszOpenOptions);
             /* Is it a VRT datasource ? */
             if (poSrcDS != NULL && poSrcDS->GetDriver() == poDS->GetDriver())
             {
@@ -633,7 +638,12 @@ try_again:
     {
         if (poDS->GetCallLevel() < 32)
         {
-            poSrcDS = poReg->Open( pszSrcDSName, bUpdate, NULL );
+            char** papszOpenOptions = GDALDeserializeOpenOptionsFromXML(psLTree);
+            int nFlags = GDAL_OF_VECTOR;
+            if( bUpdate ) nFlags |= GDAL_OF_UPDATE;
+            poSrcDS = (GDALDataset*) GDALOpenEx( pszSrcDSName, nFlags, NULL,
+                                (const char* const* )papszOpenOptions, NULL );
+            CSLDestroy(papszOpenOptions);
             /* Is it a VRT datasource ? */
             if (poSrcDS != NULL && poSrcDS->GetDriver() == poDS->GetDriver())
             {
@@ -676,6 +686,11 @@ try_again:
     }
 
 /* -------------------------------------------------------------------- */
+/*      Apply any metadata.                                             */
+/* -------------------------------------------------------------------- */
+    oMDMD.XMLInit( psLTree, TRUE );
+
+/* -------------------------------------------------------------------- */
 /*      Is this layer derived from an SQL query result?                 */
 /* -------------------------------------------------------------------- */
     pszSQL = CPLGetXMLValue( psLTree, "SrcSQL", NULL );
@@ -726,16 +741,16 @@ try_again:
         /* GeometryField elements */
         for( psChild = psLTree->psChild; psChild != NULL; psChild=psChild->psNext )
         {
-        if( psChild->eType == CXT_Element &&
-            EQUAL(psChild->pszValue,"GeometryField") )
-        {
-            if( !bFoundGeometryField )
+            if( psChild->eType == CXT_Element &&
+                EQUAL(psChild->pszValue,"GeometryField") )
             {
-                bFoundGeometryField = TRUE;
+                if( !bFoundGeometryField )
+                {
+                    bFoundGeometryField = TRUE;
+                }
+                else
+                    apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
             }
-            else
-                apoGeomFieldProps.push_back(new OGRVRTGeomFieldProps());
-        }
         }
 
         if( !bFoundGeometryField )
@@ -760,6 +775,7 @@ try_again:
                     if( poFDefn->GetSpatialRef() != NULL )
                     poProps->poSRS = poFDefn->GetSpatialRef()->Clone();
                     poProps->iGeomField = iGeomField;
+                    poProps->bNullable = poFDefn->IsNullable();
                 }
             }
 
@@ -795,6 +811,7 @@ try_again:
             OGRGeomFieldDefn oFieldDefn( apoGeomFieldProps[i]->osName,
                                         apoGeomFieldProps[i]->eGeomType );
             oFieldDefn.SetSpatialRef( apoGeomFieldProps[i]->poSRS );
+            oFieldDefn.SetNullable( apoGeomFieldProps[i]->bNullable );
             poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
         }
 
@@ -808,19 +825,23 @@ try_again:
 /* -------------------------------------------------------------------- */
 /*      Figure out what should be used as an FID.                       */
 /* -------------------------------------------------------------------- */
-     pszFIDFieldName = CPLGetXMLValue( psLTree, "FID", NULL );
+     pszSrcFIDFieldName = CPLGetXMLValue( psLTree, "FID", NULL );
 
-     if( pszFIDFieldName != NULL )
+     if( pszSrcFIDFieldName != NULL )
      {
          iFIDField =
-             GetSrcLayerDefn()->GetFieldIndex( pszFIDFieldName );
+             GetSrcLayerDefn()->GetFieldIndex( pszSrcFIDFieldName );
          if( iFIDField == -1 )
          {
              CPLError( CE_Failure, CPLE_AppDefined, 
                        "Unable to identify FID field '%s'.",
-                       pszFIDFieldName );
+                       pszSrcFIDFieldName );
              goto error;
          }
+
+         // User facing FID column name. If not defined we will report the
+         // source FID column name only if it is exposed as a field too (#4637)
+         osFIDFieldName = CPLGetXMLValue( psLTree, "FID.name", "" );
      }
 
 /* -------------------------------------------------------------------- */
@@ -891,6 +912,44 @@ try_again:
              }
 
 /* -------------------------------------------------------------------- */
+/*      Subtype                                                         */
+/* -------------------------------------------------------------------- */
+             pszArg = CPLGetXMLValue( psChild, "subtype", NULL );
+             if( pszArg != NULL )
+             {
+                 int iType;
+                 OGRFieldSubType eSubType = OFSTNone;
+
+                 for( iType = 0; iType <= (int) OFSTMaxSubType; iType++ )
+                 {
+                     if( EQUAL(pszArg,OGRFieldDefn::GetFieldSubTypeName(
+                                   (OGRFieldSubType)iType)) )
+                     {
+                         eSubType = (OGRFieldSubType) iType;
+                         break;
+                     }
+                 }
+
+                 if( iType > (int) OFSTMaxSubType )
+                 {
+                     CPLError( CE_Failure, CPLE_AppDefined, 
+                               "Unable to identify Field subtype '%s'.",
+                               pszArg );
+                     goto error;
+                 }
+
+                 if( !OGR_AreTypeSubTypeCompatible(oFieldDefn.GetType(), eSubType) )
+                 {
+                     CPLError( CE_Failure, CPLE_AppDefined, 
+                               "Invalid subtype '%s' for type '%s'.",
+                               pszArg, OGRFieldDefn::GetFieldTypeName(oFieldDefn.GetType()) );
+                     goto error;
+                 }
+
+                 oFieldDefn.SetSubType( eSubType );
+             }
+
+/* -------------------------------------------------------------------- */
 /*      Width and precision.                                            */
 /* -------------------------------------------------------------------- */
              int nWidth = atoi(CPLGetXMLValue( psChild, "width", "0" ));
@@ -914,6 +973,17 @@ try_again:
              oFieldDefn.SetPrecision(nPrecision);
 
 /* -------------------------------------------------------------------- */
+/*      Nullable attribute.                                             */
+/* -------------------------------------------------------------------- */
+             int bNullable = CSLTestBoolean(CPLGetXMLValue( psChild, "nullable", "true" ));
+             oFieldDefn.SetNullable(bNullable);
+
+/* -------------------------------------------------------------------- */
+/*      Default attribute.                                              */
+/* -------------------------------------------------------------------- */
+             oFieldDefn.SetDefault(CPLGetXMLValue( psChild, "default",NULL));
+
+/* -------------------------------------------------------------------- */
 /*      Create the field.                                               */
 /* -------------------------------------------------------------------- */
              poFeatureDefn->AddFieldDefn( &oFieldDefn );
@@ -1088,7 +1158,8 @@ int OGRVRTLayer::ResetSourceReading()
             {
                 OGRFieldType xType = poXField->GetType();
                 OGRFieldType yType = poYField->GetType();
-                if (!((xType == OFTReal || xType == OFTInteger) && (yType == OFTReal || yType == OFTInteger)))
+                if (!((xType == OFTReal || xType == OFTInteger || xType == OFTInteger64) &&
+                      (yType == OFTReal || yType == OFTInteger || yType == OFTInteger64)))
                 {
                     CPLError(CE_Warning, CPLE_AppDefined,
                             "The '%s' and/or '%s' fields of the source layer are not declared as numeric fields,\n"
@@ -1168,9 +1239,6 @@ int OGRVRTLayer::ResetSourceReading()
                 if( osFilter.size() != 0 )
                 {
                     pszFilter = CPLStrdup(osFilter);
-                    char* pszComma;
-                    while((pszComma = strchr(pszFilter, ',')) != NULL)
-                        *pszComma = '.';
                 }
             }
 
@@ -1359,7 +1427,7 @@ retry:
     if( iFIDField == -1 )
         poDstFeat->SetFID( poSrcFeat->GetFID() );
     else
-        poDstFeat->SetFID( poSrcFeat->GetFieldAsInteger( iFIDField ) );
+        poDstFeat->SetFID( poSrcFeat->GetFieldAsInteger64( iFIDField ) );
     
 /* -------------------------------------------------------------------- */
 /*      Handle style string.                                            */
@@ -1553,7 +1621,7 @@ retry:
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRVRTLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRVRTLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if (!bHasFullInitialized) FullInitialize();
@@ -1578,7 +1646,7 @@ OGRFeature *OGRVRTLayer::GetFeature( long nFeatureId )
         char* pszFIDQuery = (char*)CPLMalloc(strlen(pszFID) + 64);
 
         poSrcLayer->ResetReading();
-        sprintf( pszFIDQuery, "%s = %ld", pszFID, nFeatureId );
+        sprintf( pszFIDQuery, "%s = " CPL_FRMT_GIB, pszFID, nFeatureId );
         poSrcLayer->SetSpatialFilter( NULL );
         poSrcLayer->SetAttributeFilter( pszFIDQuery );
         CPLFree(pszFIDQuery);
@@ -1610,7 +1678,7 @@ OGRFeature *OGRVRTLayer::GetFeature( long nFeatureId )
 /*                          SetNextByIndex()                            */
 /************************************************************************/
 
-OGRErr OGRVRTLayer::SetNextByIndex( long nIndex )
+OGRErr OGRVRTLayer::SetNextByIndex( GIntBig nIndex )
 {
     if (!bHasFullInitialized) FullInitialize();
     if (!poSrcLayer || poDS->GetRecursionDetected()) return OGRERR_FAILURE;
@@ -1790,10 +1858,10 @@ OGRFeature* OGRVRTLayer::TranslateVRTFeatureToSrcFeature( OGRFeature* poVRTFeatu
 }
 
 /************************************************************************/
-/*                           CreateFeature()                            */
+/*                           ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRVRTLayer::CreateFeature( OGRFeature* poVRTFeature )
+OGRErr OGRVRTLayer::ICreateFeature( OGRFeature* poVRTFeature )
 {
     if (!bHasFullInitialized) FullInitialize();
     if (!poSrcLayer || poDS->GetRecursionDetected()) return OGRERR_FAILURE;
@@ -1828,10 +1896,10 @@ OGRErr OGRVRTLayer::CreateFeature( OGRFeature* poVRTFeature )
 }
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRVRTLayer::SetFeature( OGRFeature* poVRTFeature )
+OGRErr OGRVRTLayer::ISetFeature( OGRFeature* poVRTFeature )
 {
     if (!bHasFullInitialized) FullInitialize();
     if (!poSrcLayer || poDS->GetRecursionDetected()) return OGRERR_FAILURE;
@@ -1864,7 +1932,7 @@ OGRErr OGRVRTLayer::SetFeature( OGRFeature* poVRTFeature )
 /*                           DeleteFeature()                            */
 /************************************************************************/
 
-OGRErr OGRVRTLayer::DeleteFeature( long nFID )
+OGRErr OGRVRTLayer::DeleteFeature( GIntBig nFID )
 
 {
     if (!bHasFullInitialized) FullInitialize();
@@ -1990,6 +2058,9 @@ int OGRVRTLayer::TestCapability( const char * pszCap )
     else if( EQUAL(pszCap,OLCIgnoreFields) )
         return poSrcLayer->TestCapability(pszCap);
 
+    else if( EQUAL(pszCap,OLCCurveGeometries) )
+        return TRUE;
+
     return FALSE;
 }
 
@@ -2065,7 +2136,7 @@ OGRErr OGRVRTLayer::GetExtent( int iGeomField, OGREnvelope *psExtent, int bForce
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRVRTLayer::GetFeatureCount( int bForce )
+GIntBig OGRVRTLayer::GetFeatureCount( int bForce )
 
 {
     if (nFeatureCount >= 0 &&
@@ -2170,6 +2241,9 @@ const char * OGRVRTLayer::GetFIDColumn()
     if (!bHasFullInitialized) FullInitialize();
     if (!poSrcLayer || poDS->GetRecursionDetected()) return "";
 
+    if( osFIDFieldName.size() )
+        return osFIDFieldName;
+
     const char* pszFIDColumn;
     if (iFIDField == -1)
     {
@@ -2389,3 +2463,14 @@ OGRErr OGRVRTLayer::SetIgnoredFields( const char **papszFields )
 
     return eErr;
 }
+
+/************************************************************************/
+/*                          GetSrcDataset()                             */
+/************************************************************************/
+
+GDALDataset* OGRVRTLayer::GetSrcDataset()
+{
+    if (!bHasFullInitialized) FullInitialize();
+    if (!poSrcLayer || poDS->GetRecursionDetected()) return NULL;
+    return poSrcDS;
+}
diff --git a/ogr/ogrsf_frmts/walk/GNUmakefile b/ogr/ogrsf_frmts/walk/GNUmakefile
index 418fdc0..140ca8d 100644
--- a/ogr/ogrsf_frmts/walk/GNUmakefile
+++ b/ogr/ogrsf_frmts/walk/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrwalkdriver.o ogrwalkdatasource.o ogrwalklayer.o ogrwalktablelayer.o ogrwalkselectlayer.o ogrwalktool.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../generic -I../pgeo $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../generic -I../pgeo  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/walk/ogrwalk.h b/ogr/ogrsf_frmts/walk/ogrwalk.h
index a6e3136..57be465 100644
--- a/ogr/ogrsf_frmts/walk/ogrwalk.h
+++ b/ogr/ogrsf_frmts/walk/ogrwalk.h
@@ -60,7 +60,7 @@ protected:
     // Layer spatial reference system
     OGRSpatialReference *poSRS;
 
-    int                 iNextShapeId;
+    GIntBig             iNextShapeId;
 
     OGRWalkDataSource    *poDS;
 
@@ -120,10 +120,10 @@ public:
                                     const char *pszMemo );
 
     virtual void        ResetReading();
-    virtual int         GetFeatureCount( int );
+    virtual GIntBig     GetFeatureCount( int );
 
     virtual OGRErr      SetAttributeFilter( const char * );
-    virtual OGRFeature *GetFeature( long nFeatureId );
+    virtual OGRFeature *GetFeature( GIntBig nFeatureId );
     
     virtual int         TestCapability( const char * );
 
diff --git a/ogr/ogrsf_frmts/walk/ogrwalkdatasource.cpp b/ogr/ogrsf_frmts/walk/ogrwalkdatasource.cpp
index 105503f..3ad1726 100644
--- a/ogr/ogrsf_frmts/walk/ogrwalkdatasource.cpp
+++ b/ogr/ogrsf_frmts/walk/ogrwalkdatasource.cpp
@@ -150,10 +150,10 @@ int OGRWalkDataSource::Open( const char * pszNewName, int bUpdate )
 
         if( poLayer->Initialize( papszRecord[0],        // LayerName
                                  "Geometry",            // Geometry Column Name
-                                 atof(papszRecord[1]),  // Extent MinE
-                                 atof(papszRecord[2]),  // Extent MaxE
-                                 atof(papszRecord[3]),  // Extent MinN
-                                 atof(papszRecord[4]),  // Extent MaxN
+                                 CPLAtof(papszRecord[1]),  // Extent MinE
+                                 CPLAtof(papszRecord[2]),  // Extent MaxE
+                                 CPLAtof(papszRecord[3]),  // Extent MinN
+                                 CPLAtof(papszRecord[4]),  // Extent MaxN
                                  papszRecord[5])        // Memo for SpatialRef
             != CE_None )
         {
diff --git a/ogr/ogrsf_frmts/walk/ogrwalklayer.cpp b/ogr/ogrsf_frmts/walk/ogrwalklayer.cpp
index 3ddd3a7..385d537 100644
--- a/ogr/ogrsf_frmts/walk/ogrwalklayer.cpp
+++ b/ogr/ogrsf_frmts/walk/ogrwalklayer.cpp
@@ -87,6 +87,7 @@ CPLErr OGRWalkLayer::BuildFeatureDefn( const char *pszLayerName,
 
 {
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     int    nRawColumns = poStmt->GetColCount();
 
     poFeatureDefn->Reference();
@@ -113,6 +114,11 @@ CPLErr OGRWalkLayer::BuildFeatureDefn( const char *pszLayerName,
                 oField.SetType( OFTInteger );
                 break;
 
+            case SQL_C_SBIGINT:
+            case SQL_C_UBIGINT:
+                oField.SetType( OFTInteger64 );
+                break;
+
             case SQL_C_BINARY:
                 oField.SetType( OFTBinary );
                 break;
diff --git a/ogr/ogrsf_frmts/walk/ogrwalktablelayer.cpp b/ogr/ogrsf_frmts/walk/ogrwalktablelayer.cpp
index 93eb964..cb95a05 100644
--- a/ogr/ogrsf_frmts/walk/ogrwalktablelayer.cpp
+++ b/ogr/ogrsf_frmts/walk/ogrwalktablelayer.cpp
@@ -71,6 +71,8 @@ CPLErr OGRWalkTableLayer::Initialize( const char *pszLayerName,
                                       const char *pszMemo)
 
 {
+    SetDescription( pszLayerName );
+
     CPLODBCSession *poSession = poDS->GetSession();
 
     CPLFree( pszFIDColumn );
@@ -251,7 +253,7 @@ void OGRWalkTableLayer::ResetReading()
 /*                             GetFeature()                             */
 /************************************************************************/
 
-OGRFeature *OGRWalkTableLayer::GetFeature( long nFeatureId )
+OGRFeature *OGRWalkTableLayer::GetFeature( GIntBig nFeatureId )
 
 {
     if( pszFIDColumn == NULL )
@@ -265,7 +267,7 @@ OGRFeature *OGRWalkTableLayer::GetFeature( long nFeatureId )
     poStmt->Append( "SELECT * FROM " );
     poStmt->Append( poFeatureDefn->GetName() );
     poStmt->Append( "Features" );
-    poStmt->Appendf( " WHERE %s = %ld", pszFIDColumn, nFeatureId );
+    poStmt->Appendf( " WHERE %s = " CPL_FRMT_GIB, pszFIDColumn, nFeatureId );
 
     if( !poStmt->ExecuteSQL() )
     {
@@ -324,7 +326,7 @@ int OGRWalkTableLayer::TestCapability( const char * pszCap )
 /*      way of counting features matching a spatial query.              */
 /************************************************************************/
 
-int OGRWalkTableLayer::GetFeatureCount( int bForce )
+GIntBig OGRWalkTableLayer::GetFeatureCount( int bForce )
 
 {
     if( m_poFilterGeom != NULL )
diff --git a/ogr/ogrsf_frmts/wasp/GNUmakefile b/ogr/ogrsf_frmts/wasp/GNUmakefile
index 8c0f477..891ff22 100644
--- a/ogr/ogrsf_frmts/wasp/GNUmakefile
+++ b/ogr/ogrsf_frmts/wasp/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrwaspdriver.o ogrwaspdatasource.o ogrwasplayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
diff --git a/ogr/ogrsf_frmts/wasp/drv_wasp.html b/ogr/ogrsf_frmts/wasp/drv_wasp.html
index b6d44a5..56633ce 100644
--- a/ogr/ogrsf_frmts/wasp/drv_wasp.html
+++ b/ogr/ogrsf_frmts/wasp/drv_wasp.html
@@ -7,7 +7,7 @@
 
 <h1>WAsP - WAsP .map format</h1>
 
-(GDAL/OGR <= 1.11.0)<p>
+(GDAL/OGR >= 1.11.0)<p>
 
 This driver writes .map files to be used with WAsP. The only allowed geometries are linestrings.<p>
 
@@ -15,9 +15,11 @@ This driver writes .map files to be used with WAsP. The only allowed geometries
 
 <ul>
     <li>WASP_FIELDS : a coma separated list of fields. For elevation, the name of the height field. For rouhgness, the name of the left and right roughness fields resp.</li>
-    <li>WASP_MERGE : this may be set to "NO". Used only when generating roughness from polygons. All polygon boundaries will be output (including those with the same left and righ roughness). This is usefull (along with option -skipfailures) for debugging incorect input geometries.</li>
+    <li>WASP_MERGE : this may be set to "NO". Used only when generating roughness from polygons. All polygon boundaries will be output (including those with the same left and righ roughness). This is useful (along with option -skipfailures) for debugging incorect input geometries.</li>
     <li>WASP_GEOM_FIELD : in case input has several geometry columns and the first one (default) is not the right one.</li>
-    <li>WASP_TOLERANCE : specify a tolerance for line simplification of output.</li>
+    <li>WASP_TOLERANCE : specify a tolerance for line simplification of output (calls geos).</li>
+    <li>WASP_ADJ_TOLER : points that are less than tolerance appart from previous point on x and on y are ommited.</li>
+    <li>WASP_POINT_TO_CIRCLE_RADIUS : lines that became points du to simplification are replaces by 8 point circles (octogons).</li>
 </ul>
 
 <p>
diff --git a/ogr/ogrsf_frmts/wasp/ogrwasp.h b/ogr/ogrsf_frmts/wasp/ogrwasp.h
index 49260e0..2bdd41e 100644
--- a/ogr/ogrsf_frmts/wasp/ogrwasp.h
+++ b/ogr/ogrsf_frmts/wasp/ogrwasp.h
@@ -90,6 +90,8 @@ class OGRWAsPLayer : public OGRLayer
     OpenMode              eMode;
 
     std::auto_ptr<double> pdfTolerance;
+    std::auto_ptr<double> pdfAdjacentPointTolerance;
+    std::auto_ptr<double> pdfPointToCircleRadius;
 
     OGRErr                WriteRoughness( OGRLineString *,
                                           const double & dfZleft,
@@ -107,6 +109,21 @@ class OGRWAsPLayer : public OGRLayer
     static double AvgZ( OGRPolygon * poGeom );
     static double AvgZ( OGRGeometryCollection * poGeom );
     static double AvgZ( OGRGeometry * poGeom );
+
+    /* return a simplified line (caller is responsible for resource )
+     *
+     * if pdfTolerance is not NULL, 
+     *     calls GEOS symplify
+     *
+     * if pdfAdjacentPointTolerance is not NULL, 
+     *     remove consecutive points that are less than torelance appart 
+     *     in x and y
+     *
+     * if pdfPointToCircleRadius is not NULL,
+     *     lines that have been simplified to a point are converted to a 8 pt circle
+     * */
+    OGRLineString * Simplify( const OGRLineString & line ) const;
+    
   public:
                         /* For writing */
                         /* Takes ownership of poTolerance */
@@ -117,7 +134,9 @@ class OGRWAsPLayer : public OGRLayer
                                       const CPLString & sSecondField,
                                       const CPLString & sGeomField,
                                       bool bMerge,
-                                      double * poTolerance );
+                                      double * pdfTolerance,
+                                      double * pdfAdjacentPointTolerance,
+                                      double * pdfPointToCircleRadius );
 
                         /* For reading */
                         OGRWAsPLayer( const char * pszName, 
@@ -136,7 +155,7 @@ class OGRWAsPLayer : public OGRLayer
     virtual OGRErr      CreateGeomField( OGRGeomFieldDefn *poGeomField,
                                          int bApproxOK = TRUE );
 
-    virtual OGRErr      CreateFeature( OGRFeature * poFeature );
+    virtual OGRErr      ICreateFeature( OGRFeature * poFeature );
 
     virtual OGRFeature *GetNextFeature();
     OGRFeature *GetNextRawFeature();
@@ -170,7 +189,7 @@ class OGRWAsPDataSource : public OGRDataSource
     virtual OGRLayer   *GetLayer( int );
     virtual OGRLayer   *GetLayerByName( const char * );
 
-    virtual OGRLayer   *CreateLayer( const char *pszName, 
+    virtual OGRLayer   *ICreateLayer( const char *pszName, 
                                      OGRSpatialReference *poSpatialRef = NULL,
                                      OGRwkbGeometryType eGType = wkbUnknown,
                                      char ** papszOptions = NULL );
diff --git a/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp b/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp
index 1365c69..874aab9 100644
--- a/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp
+++ b/ogr/ogrsf_frmts/wasp/ogrwaspdatasource.cpp
@@ -64,7 +64,7 @@ OGRWAsPDataSource::~OGRWAsPDataSource()
 int OGRWAsPDataSource::TestCapability( const char * pszCap )
 
 {
-    return EQUAL(pszCap,ODsCCreateLayer) ;
+    return EQUAL(pszCap,ODsCCreateLayer) && oLayer.get() == NULL;
 }
 
 /************************************************************************/
@@ -176,10 +176,10 @@ OGRLayer *OGRWAsPDataSource::GetLayer( int iLayer )
 
 
 /************************************************************************/
-/*                              CreateLayer()                           */
+/*                             ICreateLayer()                           */
 /************************************************************************/
 
-OGRLayer *OGRWAsPDataSource::CreateLayer(const char *pszName, 
+OGRLayer *OGRWAsPDataSource::ICreateLayer(const char *pszName, 
                                      OGRSpatialReference *poSpatialRef,
                                      OGRwkbGeometryType eGType,
                                      char ** papszOptions)
@@ -245,26 +245,59 @@ OGRLayer *OGRWAsPDataSource::CreateLayer(const char *pszName,
 
     const bool bMerge = CSLTestBoolean(CSLFetchNameValueDef( papszOptions, "WASP_MERGE", "YES" ));
 
-    double * pdfTolerance = NULL;
-    const char *pszToler = CSLFetchNameValue( papszOptions, "WASP_TOLERANCE" );
+    std::auto_ptr<double> pdfTolerance;
+    {
+        const char *pszToler = CSLFetchNameValue( papszOptions, "WASP_TOLERANCE" );
+
+        if (pszToler)
+        {
+            if ( !OGRGeometryFactory::haveGEOS() )
+            {
+                CPLError( CE_Warning, 
+                        CPLE_IllegalArg, 
+                        "GEOS support not enabled, ignoring option WASP_TOLERANCE" );
+            }
+            else
+            {
+                pdfTolerance.reset( new double );
+                if (!(std::istringstream( pszToler ) >> *pdfTolerance ))
+                {
+                    CPLError( CE_Failure, 
+                            CPLE_IllegalArg, 
+                            "cannot set tolerance from %s", pszToler );
+                    return NULL;
+                }
+            }
+        }
+    }
 
-    if (pszToler)
+    std::auto_ptr<double> pdfAdjacentPointTolerance;
     {
-        if ( !OGRGeometryFactory::haveGEOS() )
+        const char *pszAdjToler = CSLFetchNameValue( papszOptions, "WASP_ADJ_TOLER" );
+        if ( pszAdjToler )
         {
-            CPLError( CE_Warning, 
-                    CPLE_IllegalArg, 
-                    "GEOS support not enabled, ignoring option WASP_TOLERANCE" );
+            pdfAdjacentPointTolerance.reset( new double );
+            if (!(std::istringstream( pszAdjToler ) >> *pdfAdjacentPointTolerance ))
+            {
+                CPLError( CE_Failure, 
+                        CPLE_IllegalArg, 
+                        "cannot set tolerance from %s", pszAdjToler );
+                return NULL;
+            }
         }
-        else
+    }
+
+    std::auto_ptr<double> pdfPointToCircleRadius;
+    {
+        const char *pszPtToCircRad = CSLFetchNameValue( papszOptions, "WASP_POINT_TO_CIRCLE_RADIUS" );
+        if ( pszPtToCircRad )
         {
-            pdfTolerance = new double;
-            if (!(std::istringstream( pszToler ) >> *pdfTolerance ))
+            pdfPointToCircleRadius.reset( new double );
+            if (!(std::istringstream( pszPtToCircRad ) >> *pdfPointToCircleRadius ))
             {
-                delete pdfTolerance;
                 CPLError( CE_Failure, 
                         CPLE_IllegalArg, 
-                        "cannot set tolerance from %s", pszToler );
+                        "cannot set tolerance from %s", pszPtToCircRad );
                 return NULL;
             }
         }
@@ -277,7 +310,9 @@ OGRLayer *OGRWAsPDataSource::CreateLayer(const char *pszName,
                                     sSecondField,
                                     sGeomField,
                                     bMerge,
-                                    pdfTolerance ) );
+                                    pdfTolerance.release(),
+                                    pdfAdjacentPointTolerance.release(),
+                                    pdfPointToCircleRadius.release() ) );
 
     char * ppszWktSpatialRef = NULL ;
     if ( poSpatialRef 
@@ -291,9 +326,9 @@ OGRLayer *OGRWAsPDataSource::CreateLayer(const char *pszName,
         VSIFPrintfL( hFile, "no spatial ref sys\n" );
     }
 
-    VSIFPrintfL( hFile, "    0.0 0.0 0.0 0.0\n" );
-    VSIFPrintfL( hFile, "    1.0 0.0 1.0 0.0\n" );
-    VSIFPrintfL( hFile, "    1.0 0.0\n" );
+    VSIFPrintfL( hFile, "  0.0 0.0 0.0 0.0\n" );
+    VSIFPrintfL( hFile, "  1.0 0.0 1.0 0.0\n" );
+    VSIFPrintfL( hFile, "  1.0 0.0\n" );
     return oLayer.get();
 }
 
diff --git a/ogr/ogrsf_frmts/wasp/ogrwaspdriver.cpp b/ogr/ogrsf_frmts/wasp/ogrwaspdriver.cpp
index 7b0bc76..d41b4d1 100644
--- a/ogr/ogrsf_frmts/wasp/ogrwaspdriver.cpp
+++ b/ogr/ogrsf_frmts/wasp/ogrwaspdriver.cpp
@@ -106,6 +106,14 @@ OGRErr OGRWAsPDriver::DeleteDataSource (const char *pszName)
 void RegisterOGRWAsP()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRWAsPDriver );
+    OGRSFDriver* poDriver = new OGRWAsPDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "WAsP .map format" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "map" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_wasp.html" );
+
+    poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/wasp/ogrwasplayer.cpp b/ogr/ogrsf_frmts/wasp/ogrwasplayer.cpp
index 73b28b9..34891ab 100644
--- a/ogr/ogrsf_frmts/wasp/ogrwasplayer.cpp
+++ b/ogr/ogrsf_frmts/wasp/ogrwasplayer.cpp
@@ -35,6 +35,10 @@
 #include <sstream>
 #include <map>
 
+#ifndef M_PI
+# define M_PI  3.1415926535897932384626433832795
+#endif
+
 /************************************************************************/
 /*                            OGRWAsPLayer()                             */
 /************************************************************************/
@@ -55,6 +59,7 @@ OGRWAsPLayer::OGRWAsPLayer( const char * pszName,
     , eMode( READ_ONLY )
 
 {
+    SetDescription( poLayerDefn->GetName() );
     poLayerDefn->Reference();
     poLayerDefn->SetGeomType( wkbLineString25D );
     poLayerDefn->GetGeomFieldDefn(0)->SetType( wkbLineString25D );
@@ -69,7 +74,9 @@ OGRWAsPLayer::OGRWAsPLayer( const char * pszName,
                             const CPLString & sSecondFieldParam,
                             const CPLString & sGeomFieldParam,
                             bool bMergeParam,
-                            double * pdfToleranceParam )
+                            double * pdfToleranceParam,
+                            double * pdfAdjacentPointToleranceParam,
+                            double * pdfPointToCircleRadiusParam )
     : bMerge( bMergeParam )
     , iFeatureCount(0)
     , sName( pszName )
@@ -85,7 +92,8 @@ OGRWAsPLayer::OGRWAsPLayer( const char * pszName,
     , iOffsetFeatureBegin( VSIFTellL( hFile ) ) /* avoids coverity warning */
     , eMode( WRITE_ONLY )
     , pdfTolerance( pdfToleranceParam )
-
+    , pdfAdjacentPointTolerance( pdfAdjacentPointToleranceParam )
+    , pdfPointToCircleRadius( pdfPointToCircleRadiusParam )
 {
     poLayerDefn->Reference();
     if (poSpatialReference) poSpatialReference->Reference();
@@ -255,30 +263,136 @@ OGRWAsPLayer::~OGRWAsPLayer()
 }
 
 /************************************************************************/
+/*                            Simplify()                                */
+/************************************************************************/
+OGRLineString * OGRWAsPLayer::Simplify( const OGRLineString & line ) const
+{
+    if ( !line.getNumPoints() ) 
+        return  static_cast<OGRLineString *>( line.clone() );
+
+    std::auto_ptr< OGRLineString > poLine( 
+        static_cast<OGRLineString *>(
+            pdfTolerance.get() && *pdfTolerance > 0
+            ? line.Simplify( *pdfTolerance ) 
+            : line.clone() ) );
+
+    OGRPoint startPt, endPt;
+    poLine->StartPoint( &startPt );
+    poLine->EndPoint( &endPt );
+    const bool isRing = startPt.Equals( &endPt );
+
+    if ( pdfAdjacentPointTolerance.get() && *pdfAdjacentPointTolerance > 0)
+    {
+        /* remove consecutive points that are too close */
+        std::auto_ptr< OGRLineString > newLine( new OGRLineString );
+        const double dist = *pdfAdjacentPointTolerance;
+        OGRPoint pt;
+        poLine->StartPoint( &pt );
+        newLine->addPoint( &pt );
+        const int iNumPoints= poLine->getNumPoints();
+        unsigned rem = 0;
+        for (int v=1; v<iNumPoints; v++)
+        {
+            if ( fabs(poLine->getX(v) - pt.getX()) > dist ||
+                 fabs(poLine->getY(v) - pt.getY()) > dist )
+            {
+                poLine->getPoint( v, &pt );
+                newLine->addPoint( &pt );
+            }
+            else
+            {
+                ++rem;
+            }
+        }
+
+        /* force closed loop if initially closed */
+        if ( isRing )
+            newLine->setPoint( newLine->getNumPoints() - 1, &startPt );
+
+        poLine.reset( newLine.release() );
+    }
+
+    if ( pdfPointToCircleRadius.get() && *pdfPointToCircleRadius > 0 )
+    {
+        const double radius = *pdfPointToCircleRadius;
+
+#undef WASP_EXPERIMENTAL_CODE      
+#ifdef WASP_EXPERIMENTAL_CODE
+        if ( 3 == poLine->getNumPoints() && isRing )
+        {
+            OGRPoint p0, p1;
+            poLine->getPoint( 0, &p0 );
+            poLine->getPoint( 1, &p1 );
+            const double dir[2] = { 
+                p1.getX() - p0.getX(),
+                p1.getY() - p0.getY() };
+            const double dirNrm = sqrt( dir[0]*dir[0] + dir[1]*dir[1] );
+            if ( dirNrm > radius )
+            { 
+                /* convert to rectangle by finding the direction */
+                /* and offsetting */
+                const double ortho[2] = {-radius*dir[1]/dirNrm, radius*dir[0]/dirNrm};
+                poLine->setNumPoints(5);
+                poLine->setPoint(0, p0.getX() - ortho[0], p0.getY() - ortho[1]);  
+                poLine->setPoint(1, p1.getX() - ortho[0], p1.getY() - ortho[1]);  
+                poLine->setPoint(2, p1.getX() + ortho[0], p1.getY() + ortho[1]);  
+                poLine->setPoint(3, p0.getX() + ortho[0], p0.getY() + ortho[1]);  
+                poLine->setPoint(4, p0.getX() - ortho[0], p0.getY() - ortho[1]);  
+            }
+            else
+            {
+                /* reduce to a point to be dealt with just after*/
+                poLine->setNumPoints(1);
+                poLine->setPoint(0, 
+                        0.5*(p0.getX()+p1.getX()),
+                        0.5*(p0.getY()+p1.getY()));
+            }
+        }
+#endif
+
+        if ( 1 == poLine->getNumPoints() )
+        {
+            const int nbPt = 8;
+            const double cx = poLine->getX(0);
+            const double cy = poLine->getY(0);
+            poLine->setNumPoints( nbPt + 1 );
+            for ( int v = 0; v<=nbPt; v++ )
+            {
+                /* the % is necessary to make sure the ring */
+                /* is really closed and not open due to     */
+                /* roundoff error of cos(2pi) and sin(2pi)  */
+                poLine->setPoint(v, 
+                        cx + radius*cos((v%nbPt)*(2*M_PI/nbPt)), 
+                        cy + radius*sin((v%nbPt)*(2*M_PI/nbPt)) );
+            }
+        }
+
+    }
+
+    return poLine.release();
+}
+
+/************************************************************************/
 /*                            WriteElevation()                          */
 /************************************************************************/
 
 OGRErr OGRWAsPLayer::WriteElevation( OGRLineString * poGeom, const double & dfZ )
 
 {
-    OGRLineString * poLine = pdfTolerance.get() 
-        ? static_cast<OGRLineString *>(poGeom->Simplify( *pdfTolerance )) 
-        : poGeom; 
-
+    std::auto_ptr< OGRLineString > poLine( Simplify( *poGeom ) );
+    
     const int iNumPoints = poLine->getNumPoints();
     if ( !iNumPoints ) return OGRERR_NONE; /* empty geom */
 
-    VSIFPrintfL( hFile, "    %g %d", dfZ, iNumPoints );
+    VSIFPrintfL( hFile, "%11.3f %11d", dfZ, iNumPoints );
 
     for (int v=0; v<iNumPoints; v++)
     {
-        if (!(v%3)) VSIFPrintfL( hFile, "\n  " );
-        VSIFPrintfL( hFile, "%.16g %.16g ", poLine->getX(v), poLine->getY(v) );
+        if (!(v%3)) VSIFPrintfL( hFile, "\n" );
+        VSIFPrintfL( hFile, "%11.1f %11.1f ", poLine->getX(v), poLine->getY(v) );
     }
     VSIFPrintfL( hFile, "\n" );
 
-    if ( poLine != poGeom ) delete poLine;
-
     return OGRERR_NONE;
 }
 
@@ -439,24 +553,20 @@ OGRErr OGRWAsPLayer::WriteRoughness( OGRPolygon * poGeom, const double & dfZ )
 OGRErr OGRWAsPLayer::WriteRoughness( OGRLineString * poGeom, const double & dfZleft,  const double & dfZright )
 
 {
-    OGRLineString * poLine = pdfTolerance.get() 
-        ? static_cast<OGRLineString *>(poGeom->Simplify( *pdfTolerance ))
-        : poGeom; 
+    std::auto_ptr< OGRLineString > poLine( Simplify( *poGeom ) );
 
     const int iNumPoints = poLine->getNumPoints();
     if ( !iNumPoints ) return OGRERR_NONE; /* empty geom */
 
-    VSIFPrintfL( hFile, "    %g %g %d", dfZleft, dfZright, iNumPoints );
+    VSIFPrintfL( hFile, "%11.3f %11.3f %11d", dfZleft, dfZright, iNumPoints );
 
     for (int v=0; v<iNumPoints; v++)
     {
         if (!(v%3)) VSIFPrintfL( hFile, "\n  " );
-        VSIFPrintfL( hFile, "%.16g %.16g ", poLine->getX(v), poLine->getY(v) );
+        VSIFPrintfL( hFile, "%11.1f %11.1f ", poLine->getX(v), poLine->getY(v) );
     }
     VSIFPrintfL( hFile, "\n" );
 
-    if ( poGeom != poLine ) delete poLine;
-
     return OGRERR_NONE;
 }
 
@@ -496,10 +606,10 @@ OGRErr OGRWAsPLayer::WriteRoughness( OGRGeometry * poGeom, const double & dfZlef
 }
 
 /************************************************************************/
-/*                            CreateFeature()                            */
+/*                            ICreateFeature()                            */
 /************************************************************************/
 
-OGRErr OGRWAsPLayer::CreateFeature( OGRFeature * poFeature )
+OGRErr OGRWAsPLayer::ICreateFeature( OGRFeature * poFeature )
 
 {
     if ( WRITE_ONLY != eMode)
@@ -582,10 +692,11 @@ OGRErr OGRWAsPLayer::CreateFeature( OGRFeature * poFeature )
 /*                            CreateField()                            */
 /************************************************************************/
 
-OGRErr OGRWAsPLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
+OGRErr OGRWAsPLayer::CreateField( OGRFieldDefn *poField,
+                                  CPL_UNUSED int bApproxOK )
 {
     poLayerDefn->AddFieldDefn( poField );
-    
+
     /* Update field indexes */
     if ( -1 == iFirstFieldIdx && ! sFirstField.empty() )
         iFirstFieldIdx = poLayerDefn->GetFieldIndex( sFirstField.c_str() );
@@ -823,4 +934,3 @@ double OGRWAsPLayer::AvgZ( OGRGeometry * poGeom )
 //    // Return the result
 //    return ResultList[]
 //}
-
diff --git a/ogr/ogrsf_frmts/wfs/GNUmakefile b/ogr/ogrsf_frmts/wfs/GNUmakefile
index 6a136af..b19766f 100644
--- a/ogr/ogrsf_frmts/wfs/GNUmakefile
+++ b/ogr/ogrsf_frmts/wfs/GNUmakefile
@@ -2,13 +2,13 @@
 
 include ../../../GDALmake.opt
 
-OBJ	=	ogrwfsdriver.o ogrwfsdatasource.o ogrwfslayer.o ogrwfsfilter.o
+OBJ	=	ogrwfsdriver.o ogrwfsdatasource.o ogrwfslayer.o ogrwfsfilter.o ogrwfsjoinlayer.o
 
-CPPFLAGS	:=	-I.. -I../.. -I../gml $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../gml  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
 clean:
 	rm -f *.o $(O_OBJ)
 
-$(O_OBJ):	ogr_wfs.h ../../swq.h ../gml/gmlreader.h
\ No newline at end of file
+$(O_OBJ):	ogr_wfs.h ../../swq.h ../gml/gmlreader.h ../gml/parsexsd.h
\ No newline at end of file
diff --git a/ogr/ogrsf_frmts/wfs/drv_wfs.html b/ogr/ogrsf_frmts/wfs/drv_wfs.html
index 327cc70..1a4a016 100644
--- a/ogr/ogrsf_frmts/wfs/drv_wfs.html
+++ b/ogr/ogrsf_frmts/wfs/drv_wfs.html
@@ -7,7 +7,7 @@
 
 <h1>WFS - OGC WFS service</h1>
 
-(GDAL/OGR >= 1.8.0)<p>
+(GDAL/OGR >= 1.8.0)<p>
 
 This driver can connect to a OGC WFS service. It supports WFS 1.0.0 and WFS 1.1.0 protocols. GDAL/OGR must be built with Curl support in order to the
 WFS driver to be compiled. Usually WFS requests return results in GML format, so the GML driver should generally be set-up for read support
@@ -51,13 +51,14 @@ userid and password to the remote server.
 <li> <b>PagingAllowed</b>: Set to ON if paging must be enabled. See "Request paging" section.
 <li> <b>PageSize</b>: Page size when paging is enabled. See "Request paging" section.
 <li> <b>BaseStartIndex</b>: (OGR >= 1.10) Base start index when paging is enabled. See "Request paging" section.
+<li> <b>COOKIE</b>: HTTP cookies that are passed in HTTP requests, formatted as COOKIE1=VALUE1; COOKIE2=VALUE2
 </ul>
 
 <h2>Request paging</h2>
 
 Before OGR 1.10, when reading the first feature from a layer, the whole layer content will be fetched from the server.<p>
 
-Some servers (such as MapServer >= 6.0) support a vendor specific option, STARTINDEX, that allow to do the requests per "page",
+Some servers (such as MapServer >= 6.0) support a vendor specific option, STARTINDEX, that allow to do the requests per "page",
 and thus to avoid downloading the whole content of the layer in a single request. The OGR WFS client will use paging when the OGR_WFS_PAGING_ALLOWED
 configuration option is set to ON. The page size (number of features fetched in a single request) is limited to 100 by default.
 It can be changed by setting the OGR_WFS_PAGE_SIZE configuration option.<br>
@@ -75,12 +76,57 @@ When streaming is enabled, GZip compression is also requested. It has been obser
 compression, will cache on their side the whole content to be sent before sending the first bytes on the wire. To avoid this,
 you can set the CPL_CURL_GZIP configuration option to NO.<p>
 
+Starting with GDAL 2.0, the WFS driver will automatically detect if server supports
+paging, when requesting a WFS 2.0 server.<p>
+
 <h2>Filtering</h2>
 
 The driver will forward any spatial filter set with SetSpatialFilter() to the server. It also makes its best effort to do the same for attribute
 filters set with SetAttributeFilter() when possible (turning OGR SQL language into OGC filter description). When this is not possible,
 it will default to client-side only filtering, which can be a slow operation because involving fetching all the features from the servers.<p>
 
+Starting with GDAL 2.0, the following spatial functions can be used :
+<ul>
+<li>the 8 spatial binary predicate: <b>ST_Equals, ST_Disjoint, ST_Touches,
+ST_Contains, ST_Intersects, ST_Within, ST_Crosses and ST_Overlaps</b> that take
+2 geometry arguments. Typically the geometry column name, and a constant geometry such
+as built with ST_MakeEnvelope or ST_GeomFromText.</li>
+<li><b>ST_DWithin(geom1,geom2,distance_in_meters)</b></li>
+<li><b>ST_Beyond(geom1,geom2,distance_in_meters)</b></li>
+<li><b>ST_MakeEnvelope(xmin,ymin,xmax,ymax[,srs])</b>: to build an envelope. srs
+can be an integer (an EPSG code), or a string directly set as the srsName attribute
+of the gml:Envelope. GDAL will take care of needed axis swapping, so coordinates
+should be expressed in the "natural GIS order" (for example long,lat for geodetic
+systems)</li>
+<li><b>ST_GeomFromText(wkt,[srs])</b>: to build a geometry from its WKT representation.</li>
+</ul>
+Note that those spatial functions are only supported as server-side filters.<p>
+
+<h2>Layer joins</h2>
+
+<p>
+Starting with GDAL 2.0, and for WFS 2.0 servers that support joins, SELECT
+statements that involve joins will be run on server side. Spatial joins can
+also be done by using the above mentionned spatial functions, if the server
+supports spatial joins.</p>
+
+<p>There might be restrictions set by server on the complexity of the joins.
+The OGR WFS driver also restricts column selection to be column names, potentially
+with aliases and type casts, but not expressions. The ON and WHERE clauses must
+also be evaluated on server side, so no OGR special fields are allowed for example.
+ORDER BY clauses are supported, but the fields must belong to the primary table.</p>
+
+<p>
+Example of valid statement :
+<pre>
+SELECT t1.id, t1.val1, t1.geom, t2.val1 FROM my_table AS t1 JOIN another_table AS t2 ON t1.id = t2.t1id
+</pre>
+or
+<pre>
+SELECT * FROM my_table AS t1 JOIN another_table AS t2 ON ST_Intersects(t1.geom, t2.geom)
+</pre>
+</p>
+
 <h2>Write support / WFS-T</h2>
 
 The WFS-T protocol only eanbles the user to operate at feature level. No datasource, layer or field creations are possible.<p>
@@ -100,7 +146,7 @@ There are a few caveouts to keep in mind. OGR feature ID (FID) is an integer bas
 gml:id attribute is a string. Thus it is not always possible to match both values. The WFS driver exposes
 then the gml:id attribute of a feature as a 'gml_id' field.<p>
 
-When inserting a new feature with CreateFeature(), and if the command is successfull, OGR will fetch the
+When inserting a new feature with CreateFeature(), and if the command is successful, OGR will fetch the
 returned gml:id and set the 'gml_id' field of the feature accordingly. It will also try to set the OGR FID
 if the gml:id is of the form layer_name.numeric_value. Otherwise the FID will be left to its unset default value.<p>
 
@@ -146,7 +192,7 @@ interfaces.<p>
 
 <h2>Special layer : WFSLayerMetadata</h2>
 
-<p>(OGR >= 1.9.0)</p>
+<p>(OGR >= 1.9.0)</p>
 
 <p>A "hidden" layer called "WFSLayerMetadata" is filled with records with metadata for each WFS layer.</p>
 
@@ -156,12 +202,20 @@ interfaces.<p>
 
 <h2>Special layer : WFSGetCapabilities</h2>
 
-<p>(OGR >= 1.9.0)</p>
+<p>(OGR >= 1.9.0)</p>
 
 <p>A "hidden" layer called "WFSGetCapabilities" is filled with the raw XML result of the GetCapabilities request.</p>
 
 <p>That layer is returned through GetLayerByName("WFSGetCapabilities").</p>
 
+<h2>Open options (GDAL >= 2.0)</h2>
+
+The following options are available:
+<ul>
+<li><b>TRUST_CAPABILITIES_BOUNDS</b>=YES/NO: Whether to trust layer bounds
+declared in GetCapabilities response, for faster GetExtent() runtime. Defaults to NO</li>
+</ul>
+
 <h2>Examples</h2>
 
 <li>
@@ -191,13 +245,14 @@ ogrinfo "WFS:http://www.tinyows.org/cgi-bin/tinyows" tows:world -ro -al -where "
 </pre>
 
 <li>
-Display layer metadata (OGR >= 1.9.0):
+Display layer metadata (OGR >= 1.9.0):
 <pre>
 ogrinfo -ro -al "WFS:http://v2.suite.opengeo.org/geoserver/ows" WFSLayerMetadata
 </pre>
 
 <p>
 
+
 <h2>See Also</h2>
 
 <ul>
diff --git a/ogr/ogrsf_frmts/wfs/makefile.vc b/ogr/ogrsf_frmts/wfs/makefile.vc
index 75861dc..56872f5 100644
--- a/ogr/ogrsf_frmts/wfs/makefile.vc
+++ b/ogr/ogrsf_frmts/wfs/makefile.vc
@@ -1,5 +1,5 @@
 
-OBJ	=	ogrwfsdriver.obj ogrwfsdatasource.obj ogrwfslayer.obj ogrwfsfilter.obj
+OBJ	=	ogrwfsdriver.obj ogrwfsdatasource.obj ogrwfslayer.obj ogrwfsfilter.obj ogrwfsjoinlayer.obj
 EXTRAFLAGS =	-I.. -I..\.. -I..\gml
 
 GDAL_ROOT	=	..\..\..
diff --git a/ogr/ogrsf_frmts/wfs/ogr_wfs.h b/ogr/ogrsf_frmts/wfs/ogr_wfs.h
index cc822d3..c5ac0a7 100644
--- a/ogr/ogrsf_frmts/wfs/ogr_wfs.h
+++ b/ogr/ogrsf_frmts/wfs/ogr_wfs.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_wfs.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_wfs.h 29028 2015-04-26 21:19:29Z rouault $
  *
  * Project:  WFS Translator
  * Purpose:  Definition of classes for OGR WFS driver.
@@ -38,15 +38,20 @@
 #include "ogrsf_frmts.h"
 #include "gmlreader.h"
 #include "cpl_http.h"
+#include "swq.h"
 
 CPLXMLNode* WFSFindNode(CPLXMLNode* psXML, const char* pszRootName);
-CPLString WFS_TurnSQLFilterToOGCFilter( const char * pszFilter,
+void OGRWFSRecursiveUnlink( const char *pszName );
+CPLString WFS_TurnSQLFilterToOGCFilter( const swq_expr_node* poExpr,
+                                        OGRDataSource* poDS,
                                         OGRFeatureDefn* poFDefn,
                                         int nVersion,
                                         int bPropertyIsNotEqualToSupported,
                                         int bUseFeatureId,
                                         int bGmlObjectIdNeedsGMLPrefix,
-                                        int* pbOutNeedsNullCheck );
+                                        const char* pszNSPrefix,
+                                        int* pbOutNeedsNullCheck);
+swq_custom_func_registrar* WFSGetCustomFuncRegistrar();
 
 const char* FindSubStringInsensitive(const char* pszStr,
                                      const char* pszSubStr);
@@ -54,6 +59,16 @@ const char* FindSubStringInsensitive(const char* pszStr,
 CPLString WFS_EscapeURL(const char* pszURL);
 CPLString WFS_DecodeURL(const CPLString &osSrc);
 
+class OGRWFSSortDesc
+{
+    public:
+        CPLString osColumn;
+        int       bAsc;
+        
+        OGRWFSSortDesc(const CPLString& osColumn, int bAsc) : osColumn(osColumn), bAsc(bAsc) {}
+        OGRWFSSortDesc(const OGRWFSSortDesc& other) : osColumn(other.osColumn), bAsc(other.bAsc) {}
+};
+
 /************************************************************************/
 /*                             OGRWFSLayer                              */
 /************************************************************************/
@@ -77,23 +92,23 @@ class OGRWFSLayer : public OGRLayer
     char*               pszNSVal;
 
     int                 bStreamingDS;
-    OGRDataSource      *poBaseDS;
+    GDALDataset        *poBaseDS;
     OGRLayer           *poBaseLayer;
     int                 bHasFetched;
     int                 bReloadNeeded;
 
     CPLString           osGeometryColumnName;
     OGRwkbGeometryType  eGeomType;
-    int                 nFeatures;
+    GIntBig             nFeatures;
     int                 bCountFeaturesInGetNextFeature;
 
     int                 CanRunGetFeatureCountAndGetExtentTogether();
 
     CPLString           MakeGetFeatureURL(int nMaxFeatures, int bRequestHits);
     int                 MustRetryIfNonCompliantServer(const char* pszServerAnswer);
-    OGRDataSource*      FetchGetFeature(int nMaxFeatures);
+    GDALDataset*        FetchGetFeature(int nMaxFeatures);
     OGRFeatureDefn*     DescribeFeatureType();
-    int                 ExecuteGetFeatureResultTypeHits();
+    GIntBig             ExecuteGetFeatureResultTypeHits();
 
     double              dfMinX, dfMinY, dfMaxX, dfMaxY;
     int                 bHasExtents;
@@ -125,8 +140,7 @@ class OGRWFSLayer : public OGRLayer
 
     char                *pszRequiredOutputFormat;
 
-    CPLString            osFieldToSort;
-    int                  bAscFlag;
+    std::vector<OGRWFSSortDesc> aoSortColumns;
 
   public:
                         OGRWFSLayer(OGRWFSDataSource* poDS,
@@ -146,7 +160,7 @@ class OGRWFSLayer : public OGRLayer
 
     virtual void                ResetReading();
     virtual OGRFeature*         GetNextFeature();
-    virtual OGRFeature*         GetFeature(long nFID);
+    virtual OGRFeature*         GetFeature(GIntBig nFID);
 
     virtual OGRFeatureDefn *    GetLayerDefn();
 
@@ -156,14 +170,14 @@ class OGRWFSLayer : public OGRLayer
 
     virtual OGRErr      SetAttributeFilter( const char * );
 
-    virtual int         GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig     GetFeatureCount( int bForce = TRUE );
 
     void                SetExtents(double dfMinX, double dfMinY, double dfMaxX, double dfMaxY);
     virtual OGRErr      GetExtent(OGREnvelope *psExtent, int bForce = TRUE);
 
-    virtual OGRErr      CreateFeature( OGRFeature *poFeature );
-    virtual OGRErr      SetFeature( OGRFeature *poFeature );
-    virtual OGRErr      DeleteFeature( long nFID );
+    virtual OGRErr      ICreateFeature( OGRFeature *poFeature );
+    virtual OGRErr      ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr      DeleteFeature( GIntBig nFID );
 
     virtual OGRErr      StartTransaction();
     virtual OGRErr      CommitTransaction();
@@ -184,8 +198,68 @@ class OGRWFSLayer : public OGRLayer
 
     const char         *GetRequiredOutputFormat() { return pszRequiredOutputFormat; };
 
-    void                SetOrderBy(const char* pszFieldToSort, int bAscFlag);
+    void                SetOrderBy(const std::vector<OGRWFSSortDesc>& aoSortColumnsIn);
     int                 HasGotApproximateLayerDefn() { GetLayerDefn(); return bGotApproximateLayerDefn; }
+    
+    const char*         GetNamespacePrefix() { return pszNS; }
+    const char*         GetNamespaceName() { return pszNSVal; }
+};
+
+/************************************************************************/
+/*                          OGRWFSJoinLayer                             */
+/************************************************************************/
+
+class OGRWFSJoinLayer : public OGRLayer
+{
+    OGRWFSDataSource   *poDS;
+    OGRFeatureDefn     *poFeatureDefn;
+
+    CPLString           osGlobalFilter;
+    CPLString           osSortBy;
+    int                 bDistinct;
+    std::set<CPLString> aoSetMD5;
+
+    std::vector<OGRWFSLayer*> apoLayers;
+
+    GDALDataset        *poBaseDS;
+    OGRLayer           *poBaseLayer;
+    int                 bReloadNeeded;
+    int                 bHasFetched;
+
+    int                 bPagingActive;
+    int                 nPagingStartIndex;
+    int                 nFeatureRead;
+    int                 nFeatureCountRequested;
+    
+    std::vector<CPLString> aoSrcFieldNames, aoSrcGeomFieldNames;
+    
+    CPLString           osFeatureTypes;
+
+                        OGRWFSJoinLayer(OGRWFSDataSource* poDS,
+                                        const swq_select* psSelectInfo,
+                                        const CPLString& osGlobalFilter);
+    CPLString           MakeGetFeatureURL(int bRequestHits = FALSE);
+    GDALDataset*        FetchGetFeature();
+    GIntBig             ExecuteGetFeatureResultTypeHits();
+
+    public:
+
+    static OGRWFSJoinLayer* Build(OGRWFSDataSource* poDS,
+                                  const swq_select* psSelectInfo);
+                       ~OGRWFSJoinLayer();
+
+    virtual void                ResetReading();
+    virtual OGRFeature*         GetNextFeature();
+
+    virtual OGRFeatureDefn *    GetLayerDefn();
+
+    virtual int                 TestCapability( const char * );
+    
+    virtual GIntBig             GetFeatureCount( int bForce = TRUE );
+
+    virtual void        SetSpatialFilter( OGRGeometry * );
+
+    virtual OGRErr      SetAttributeFilter( const char * );
 };
 
 /************************************************************************/
@@ -231,8 +305,10 @@ class OGRWFSDataSource : public OGRDataSource
     int                 bPagingAllowed;
     int                 nPageSize;
     int                 nBaseStartIndex;
+    int                 DetectSupportPagingWFS2(CPLXMLNode* psRoot);
 
-    int                 bIsGEOSERVER;
+    int                 bStandardJoinsWFS2;
+    int                 DetectSupportStandardJoinsWFS2(CPLXMLNode* psRoot);
 
     int                 bLoadMultipleLayerDefn;
     std::set<CPLString> aoSetAlreadyTriedLayers;
@@ -243,7 +319,8 @@ class OGRWFSDataSource : public OGRDataSource
     OGRLayer           *poLayerMetadataLayer;
 
     CPLString           osGetCapabilities;
-    OGRDataSource      *poLayerGetCapabilitiesDS;
+    const char         *apszGetCapabilities[2];
+    GDALDataset        *poLayerGetCapabilitiesDS;
     OGRLayer           *poLayerGetCapabilitiesLayer;
 
     int                 bKeepLayerNamePrefix;
@@ -258,7 +335,8 @@ class OGRWFSDataSource : public OGRDataSource
                         ~OGRWFSDataSource();
 
     int                 Open( const char * pszFilename,
-                              int bUpdate );
+                              int bUpdate,
+                              char** papszOpenOptions );
 
     virtual const char*         GetName() { return pszName; }
 
@@ -305,21 +383,10 @@ class OGRWFSDataSource : public OGRDataSource
                                                       char* pszNS, char* pszNSVal);
 
     int                         GetKeepLayerNamePrefix() { return bKeepLayerNamePrefix; }
-};
-
-/************************************************************************/
-/*                             OGRWFSDriver                             */
-/************************************************************************/
+    const CPLString&            GetBaseURL() { return osBaseURL; }
 
-class OGRWFSDriver : public OGRSFDriver
-{
-  public:
-                ~OGRWFSDriver();
-
-    virtual const char*         GetName();
-    virtual OGRDataSource*      Open( const char *, int );
-    virtual int                 TestCapability( const char * );
+    virtual char**              GetMetadataDomainList();
+    virtual char**              GetMetadata( const char * pszDomain = "" );
 };
 
-
 #endif /* ndef _OGR_WFS_H_INCLUDED */
diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp
index 197c03c..03a66ea 100644
--- a/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp
+++ b/ogr/ogrsf_frmts/wfs/ogrwfsdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrwfsdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $
+ * $Id: ogrwfsdatasource.cpp 29028 2015-04-26 21:19:29Z rouault $
  *
  * Project:  WFS Translator
  * Purpose:  Implements OGRWFSDataSource class
@@ -37,11 +37,26 @@
 #include "swq.h"
 #include "ogr_p.h"
 
-CPL_CVSID("$Id: ogrwfsdatasource.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogrwfsdatasource.cpp 29028 2015-04-26 21:19:29Z rouault $");
 
 #define DEFAULT_BASE_START_INDEX     0
 #define DEFAULT_PAGE_SIZE            100
 
+typedef struct
+{
+    const char* pszPath;
+    const char* pszMDI;
+} MetadataItem;
+
+static const MetadataItem asMetadata[] =
+{
+    {  "Service.Title", "TITLE" }, /*1.0 */
+    {  "ServiceIdentification.Title", "TITLE" }, /* 1.1 or 2.0 */
+    {  "Service.Abstract", "ABSTRACT" }, /* 1.0 */
+    {  "ServiceIdentification.Abstract", "ABSTRACT" }, /* 1.1 or 2.0 */
+    {  "ServiceProvider.ProviderName", "PROVIDER_NAME" }, /* 1.1 or 2.0 */
+};
+
 /************************************************************************/
 /*                            WFSFindNode()                             */
 /************************************************************************/
@@ -90,11 +105,11 @@ CPLXMLNode* WFSFindNode(CPLXMLNode* psXML, const char* pszRootName)
 
 class OGRWFSWrappedResultLayer : public OGRLayer
 {
-    OGRDataSource *poDS;
+    GDALDataset *poDS;
     OGRLayer      *poLayer;
 
     public:
-        OGRWFSWrappedResultLayer(OGRDataSource* poDS, OGRLayer* poLayer)
+        OGRWFSWrappedResultLayer(GDALDataset* poDS, OGRLayer* poLayer)
         {
             this->poDS = poDS;
             this->poLayer = poLayer;
@@ -106,10 +121,10 @@ class OGRWFSWrappedResultLayer : public OGRLayer
 
         virtual void        ResetReading() { poLayer->ResetReading(); }
         virtual OGRFeature *GetNextFeature() { return poLayer->GetNextFeature(); }
-        virtual OGRErr      SetNextByIndex( long nIndex ) { return poLayer->SetNextByIndex(nIndex); }
-        virtual OGRFeature *GetFeature( long nFID ) { return poLayer->GetFeature(nFID); }
+        virtual OGRErr      SetNextByIndex( GIntBig nIndex ) { return poLayer->SetNextByIndex(nIndex); }
+        virtual OGRFeature *GetFeature( GIntBig nFID ) { return poLayer->GetFeature(nFID); }
         virtual OGRFeatureDefn *GetLayerDefn() { return poLayer->GetLayerDefn(); }
-        virtual int         GetFeatureCount( int bForce = TRUE ) { return poLayer->GetFeatureCount(bForce); }
+        virtual GIntBig     GetFeatureCount( int bForce = TRUE ) { return poLayer->GetFeatureCount(bForce); }
         virtual int         TestCapability( const char * pszCap )  { return poLayer->TestCapability(pszCap); }
 };
 
@@ -164,7 +179,7 @@ OGRWFSDataSource::OGRWFSDataSource()
             nBaseStartIndex = atoi(pszOption);
     }
 
-    bIsGEOSERVER = FALSE;
+    bStandardJoinsWFS2 = FALSE;
 
     bLoadMultipleLayerDefn = CSLTestBoolean(CPLGetConfigOption("OGR_WFS_LOAD_MULTIPLE_LAYER_DEFN", "TRUE"));
 
@@ -175,6 +190,8 @@ OGRWFSDataSource::OGRWFSDataSource()
     poLayerGetCapabilitiesLayer = NULL;
 
     bKeepLayerNamePrefix = FALSE;
+    apszGetCapabilities[0] = NULL;
+    apszGetCapabilities[1] = NULL;
 }
 
 /************************************************************************/
@@ -262,14 +279,14 @@ OGRLayer* OGRWFSDataSource::GetLayerByName(const char* pszName)
         if (poLayerGetCapabilitiesLayer != NULL)
             return poLayerGetCapabilitiesLayer;
 
-        OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
+        GDALDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
         if (poMEMDrv == NULL)
         {
             CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
             return NULL;
         }
 
-        poLayerGetCapabilitiesDS = poMEMDrv->CreateDataSource("WFSGetCapabilities", NULL);
+        poLayerGetCapabilitiesDS = poMEMDrv->Create("WFSGetCapabilities", 0, 0, 0, GDT_Unknown, NULL);
         poLayerGetCapabilitiesLayer = poLayerGetCapabilitiesDS->CreateLayer("WFSGetCapabilities", NULL, wkbNone, NULL);
         OGRFieldDefn oFDefn("content", OFTString);
         poLayerGetCapabilitiesLayer->CreateField(&oFDefn);
@@ -288,6 +305,32 @@ OGRLayer* OGRWFSDataSource::GetLayerByName(const char* pszName)
         return papoLayers[nIndex];
 }
 
+/************************************************************************/
+/*                        GetMetadataDomainList()                       */
+/************************************************************************/
+
+char** OGRWFSDataSource::GetMetadataDomainList()
+{
+    return BuildMetadataDomainList(GDALDataset::GetMetadataDomainList(),
+                                   TRUE,
+                                   "", "xml:capabilities", NULL);
+
+}
+
+/************************************************************************/
+/*                           GetMetadata()                              */
+/************************************************************************/
+
+char** OGRWFSDataSource::GetMetadata( const char * pszDomain )
+{
+    if( pszDomain != NULL && EQUAL(pszDomain, "xml:capabilities") )
+    {
+        apszGetCapabilities[0] = osGetCapabilities.c_str();
+        apszGetCapabilities[1] = NULL;
+        return (char**) apszGetCapabilities;
+    }
+    return GDALDataset::GetMetadata(pszDomain);
+}
 
 /************************************************************************/
 /*                          GetLayerIndex()                             */
@@ -571,6 +614,126 @@ int OGRWFSDataSource::DetectTransactionSupport(CPLXMLNode* psRoot)
 }
 
 /************************************************************************/
+/*                    DetectSupportPagingWFS2()                         */
+/************************************************************************/
+
+int OGRWFSDataSource::DetectSupportPagingWFS2(CPLXMLNode* psRoot)
+{
+    const char* pszPagingAllowed = CPLGetConfigOption("OGR_WFS_PAGING_ALLOWED", NULL);
+    if( pszPagingAllowed != NULL && !CSLTestBoolean(pszPagingAllowed) )
+        return FALSE;
+
+    CPLXMLNode* psOperationsMetadata =
+        CPLGetXMLNode(psRoot, "OperationsMetadata");
+    if (!psOperationsMetadata)
+    {
+        return FALSE;
+    }
+
+    CPLXMLNode* psChild = psOperationsMetadata->psChild;
+    while(psChild)
+    {
+        if (psChild->eType == CXT_Element &&
+            strcmp(psChild->pszValue, "Constraint") == 0 &&
+            strcmp(CPLGetXMLValue(psChild, "name", ""), "ImplementsResultPaging") == 0)
+        {
+            if( !EQUAL(CPLGetXMLValue(psChild, "DefaultValue", ""), "TRUE") )
+            {
+                psChild = NULL;
+                break;
+            }
+            break;
+        }
+        psChild = psChild->psNext;
+    }
+    if (!psChild)
+    {
+        CPLDebug("WFS", "No paging support");
+        return FALSE;
+    }
+
+    psChild = psOperationsMetadata->psChild;
+    while(psChild)
+    {
+        if (psChild->eType == CXT_Element &&
+            strcmp(psChild->pszValue, "Operation") == 0 &&
+            strcmp(CPLGetXMLValue(psChild, "name", ""), "GetFeature") == 0)
+        {
+            break;
+        }
+        psChild = psChild->psNext;
+    }
+    if (psChild && CPLGetConfigOption("OGR_WFS_PAGE_SIZE", NULL) == NULL)
+    {
+        psChild = psChild->psChild;
+        while(psChild)
+        {
+            if (psChild->eType == CXT_Element &&
+                strcmp(psChild->pszValue, "Constraint") == 0 &&
+                strcmp(CPLGetXMLValue(psChild, "name", ""), "CountDefault") == 0)
+            {
+                int nVal = atoi(CPLGetXMLValue(psChild, "DefaultValue", "0"));
+                if( nVal > 0 )
+                    nPageSize = nVal;
+
+                break;
+            }
+            psChild = psChild->psNext;
+        }
+    }
+    const char* pszOption = CPLGetConfigOption("OGR_WFS_PAGE_SIZE", NULL);
+    if( pszOption != NULL )
+    {
+        nPageSize = atoi(pszOption);
+        if (nPageSize <= 0)
+            nPageSize = DEFAULT_PAGE_SIZE;
+    }
+
+    CPLDebug("WFS", "Paging support with page size %d", nPageSize);
+    bPagingAllowed = TRUE;
+
+    return TRUE;
+}
+
+/************************************************************************/
+/*                   DetectSupportStandardJoinsWFS2()                   */
+/************************************************************************/
+
+int OGRWFSDataSource::DetectSupportStandardJoinsWFS2(CPLXMLNode* psRoot)
+{
+    CPLXMLNode* psOperationsMetadata =
+        CPLGetXMLNode(psRoot, "OperationsMetadata");
+    if (!psOperationsMetadata)
+    {
+        return FALSE;
+    }
+
+    CPLXMLNode* psChild = psOperationsMetadata->psChild;
+    while(psChild)
+    {
+        if (psChild->eType == CXT_Element &&
+            strcmp(psChild->pszValue, "Constraint") == 0 &&
+            strcmp(CPLGetXMLValue(psChild, "name", ""), "ImplementsStandardJoins") == 0)
+        {
+            if( !EQUAL(CPLGetXMLValue(psChild, "DefaultValue", ""), "TRUE") )
+            {
+                psChild = NULL;
+                break;
+            }
+            break;
+        }
+        psChild = psChild->psNext;
+    }
+    if (!psChild)
+    {
+        CPLDebug("WFS", "No ImplementsStandardJoins support");
+        return FALSE;
+    }
+    bStandardJoinsWFS2 = TRUE;
+    return TRUE;
+}
+
+/************************************************************************/
 /*                      FindComparisonOperator()                        */
 /************************************************************************/
 
@@ -723,7 +886,8 @@ CPLHTTPResult* OGRWFSDataSource::SendGetCapabilities(const char* pszBaseURL,
 /*                                Open()                                */
 /************************************************************************/
 
-int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
+int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn,
+                            char** papszOpenOptions )
 
 {
     bUpdate = bUpdateIn;
@@ -743,14 +907,19 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
             return FALSE;
         }
 
-        pszBaseURL = pszFilename;
-        if (EQUALN(pszFilename, "WFS:", 4))
-            pszBaseURL += 4;
+        pszBaseURL = CSLFetchNameValue(papszOpenOptions, "URL");
+        if( pszBaseURL == NULL )
+        {
+            pszBaseURL = pszFilename;
+            if (EQUALN(pszFilename, "WFS:", 4))
+                pszBaseURL += 4;
+        }
 
         osBaseURL = pszBaseURL;
 
         if (strncmp(pszBaseURL, "http://", 7) != 0 &&
-            strncmp(pszBaseURL, "https://", 8) != 0)
+            strncmp(pszBaseURL, "https://", 8) != 0 &&
+            strncmp(pszBaseURL, "/vsimem/", strlen("/vsimem/")) != 0)
             return FALSE;
 
         CPLString strOriginalTypeName = "";
@@ -835,6 +1004,12 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
                 CSLSetNameValue( papszHttpOptions,
                                 "USERPWD", pszParm );
 
+        pszParm = CPLGetXMLValue( psRoot, "COOKIE", NULL );
+        if( pszParm )
+            papszHttpOptions =
+                CSLSetNameValue( papszHttpOptions,
+                                "COOKIE", pszParm );
+
         pszParm = CPLGetXMLValue( psRoot, "Version", NULL );
         if( pszParm )
             osVersion = pszParm;
@@ -902,7 +1077,7 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
             CPLDestroyXMLNode( psXML2 );
 
             if (bOK)
-                return Open(pszFilename, bUpdate);
+                return Open(pszFilename, bUpdate, papszOpenOptions);
             else
                 return FALSE;
         }
@@ -950,6 +1125,7 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
         {
             CPLError(CE_Failure, CPLE_AppDefined,
                         "Cannot find base URL");
+            if (!psFileXML) CPLDestroyXMLNode( psXML );
             CPLDestroyXMLNode( psStrippedXML );
             return FALSE;
         }
@@ -959,6 +1135,13 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
 
     pszBaseURL = NULL;
 
+    for(int i=0; i < (int)(sizeof(asMetadata) / sizeof(asMetadata[0])); i++ )
+    {
+        const char* pszVal = CPLGetXMLValue( psWFSCapabilities, asMetadata[i].pszPath, NULL );
+        if( pszVal )
+            SetMetadataItem(asMetadata[i].pszMDI, pszVal);
+    }
+
     if (osVersion.size() == 0)
         osVersion = CPLGetXMLValue(psWFSCapabilities, "version", "1.0.0");
     if (strcmp(osVersion.c_str(), "1.0.0") == 0)
@@ -989,30 +1172,13 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
                 osBaseURL = CPLURLAddKVP(osBaseURL, "COUNT", osMaxFeatures);
             }
         }
+
+        DetectSupportPagingWFS2(psWFSCapabilities);
+        DetectSupportStandardJoinsWFS2(psWFSCapabilities);
     }
 
     DetectTransactionSupport(psWFSCapabilities);
 
-    /* Detect if server is GEOSERVER */
-    CPLXMLNode* psKeywords = CPLGetXMLNode(psWFSCapabilities, "ServiceIdentification.Keywords");
-    if (psKeywords)
-    {
-        CPLXMLNode* psKeyword = psKeywords->psChild;
-        for(;psKeyword != NULL;psKeyword=psKeyword->psNext)
-        {
-            if (psKeyword->eType == CXT_Element &&
-                psKeyword->pszValue != NULL &&
-                EQUAL(psKeyword->pszValue, "Keyword") &&
-                psKeyword->psChild != NULL &&
-                psKeyword->psChild->pszValue != NULL &&
-                EQUALN(psKeyword->psChild->pszValue, "GEOSERVER", 9))
-            {
-                bIsGEOSERVER = TRUE;
-                break;
-            }
-        }
-    }
-
     if (bUpdate && !bTransactionSupport)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
@@ -1291,28 +1457,55 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
                 if (osOutputFormat.size())
                     poLayer->SetRequiredOutputFormat(osOutputFormat);
 
+                if( pszTitle )
+                    poLayer->SetMetadataItem("TITLE", pszTitle);
+                if( pszAbstract )
+                    poLayer->SetMetadataItem("ABSTRACT", pszAbstract);
+                CPLXMLNode* psKeywords = CPLGetXMLNode(psChildIter, "Keywords");
+                if( psKeywords )
+                {
+                    int nKeywordCounter = 1;
+                    for( CPLXMLNode* psKeyword = psKeywords->psChild;
+                         psKeyword != NULL; psKeyword = psKeyword->psNext )
+                    {
+                        if( psKeyword->eType == CXT_Element )
+                        {
+                            poLayer->SetMetadataItem(CPLSPrintf("KEYWORD_%d", nKeywordCounter),
+                                                     psKeyword->psChild->pszValue);
+                            nKeywordCounter ++;
+                        }
+                        else if( psKeyword->eType == CXT_Text )
+                        {
+                            poLayer->SetMetadataItem("KEYWORDS",
+                                                     psKeyword->pszValue);
+                        }
+                    }
+                }
+
                 if (poSRS)
                 {
                     char* pszProj4 = NULL;
                     if (poSRS->exportToProj4(&pszProj4) == OGRERR_NONE)
                     {
                         /* See http://trac.osgeo.org/gdal/ticket/4041 */
-                        /* For now, we restrict to GEOSERVER as apparently the order is always longitude,latitude */
-                        /* other servers might also qualify, so this should be relaxed */
-                        /* Also accept when <wfs:DefaultCRS>urn:ogc:def:crs:OGC:1.3:CRS84</wfs:DefaultCRS> */
-                        if ((bIsGEOSERVER &&
+                        int bTrustBounds =
+                            CSLFetchBoolean(papszOpenOptions, "TRUST_CAPABILITIES_BOUNDS",
+                                CSLTestBoolean(CPLGetConfigOption("OGR_WFS_TRUST_CAPABILITIES_BOUNDS", "FALSE")));
+
+                        if (((bTrustBounds || (dfMinX == -180 && dfMinY == -90 && dfMaxX == 180 && dfMaxY == 90)) &&
                             (strcmp(pszProj4, "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs ") == 0 ||
                              strcmp(pszProj4, "+proj=longlat +datum=WGS84 +no_defs ") == 0)) ||
                             strcmp(pszDefaultSRS, "urn:ogc:def:crs:OGC:1.3:CRS84") == 0)
                         {
                             poLayer->SetExtents(dfMinX, dfMinY, dfMaxX, dfMaxY);
                         }
-#if 0
-                        else
+
+                        else if( bTrustBounds )
                         {
                             OGRSpatialReference oWGS84;
                             oWGS84.SetWellKnownGeogCS("WGS84");
                             OGRCoordinateTransformation* poCT;
+                            CPLPushErrorHandler(CPLQuietErrorHandler);
                             poCT = OGRCreateCoordinateTransformation(&oWGS84, poSRS);
                             if (poCT)
                             {
@@ -1353,8 +1546,10 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
                                 }
                             }
                             delete poCT;
+                            CPLPopErrorHandler();
+                            CPLErrorReset();
                         }
-#endif
+
                     }
                     CPLFree(pszProj4);
                 }
@@ -1406,9 +1601,6 @@ int OGRWFSDataSource::Open( const char * pszFilename, int bUpdateIn)
 void OGRWFSDataSource::LoadMultipleLayerDefn(const char* pszLayerName,
                                              char* pszNS, char* pszNSVal)
 {
-    /*if (!bIsGEOSERVER)
-        return;*/
-
     if (!bLoadMultipleLayerDefn)
         return;
 
@@ -1592,7 +1784,8 @@ void OGRWFSDataSource::LoadMultipleLayerDefn(const char* pszLayerName,
     CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
 
     std::vector<GMLFeatureClass*> aosClasses;
-    GMLParseXSD( osTmpFileName, aosClasses );
+    int bFullyUnderstood = FALSE;
+    GMLParseXSD( osTmpFileName, aosClasses, bFullyUnderstood );
 
     int nLayersFound = 0;
     if ((int)aosClasses.size() > 0)
@@ -1857,6 +2050,7 @@ CPLHTTPResult* OGRWFSDataSource::HTTPFetch( const char* pszURL, char** papszOpti
         {
             CPLDebug("WFS", "Probably buggy remote server. Retrying with HTTP 1.0 protocol");
             bUseHttp10 = TRUE;
+            CPLHTTPDestroyResult(psResult);
             return HTTPFetch(pszURL, papszOptions);
         }
 
@@ -1883,14 +2077,18 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
                                         const char *pszDialect )
 
 {
+    swq_select_parse_options oParseOptions;
+    oParseOptions.poCustomFuncRegistrar = WFSGetCustomFuncRegistrar();
+
 /* -------------------------------------------------------------------- */
 /*      Use generic implementation for recognized dialects              */
 /* -------------------------------------------------------------------- */
     if( IsGenericSQLDialect(pszDialect) )
     {
-        OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
-                                                          poSpatialFilter,
-                                                          pszDialect );
+        OGRLayer* poResLayer = GDALDataset::ExecuteSQL( pszSQLCommand,
+                                                        poSpatialFilter,
+                                                        pszDialect,
+                                                        &oParseOptions );
         oMap[poResLayer] = NULL;
         return poResLayer;
     }
@@ -1914,14 +2112,14 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
             return NULL;
         }
 
-        OGRSFDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
+        GDALDriver* poMEMDrv = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName("Memory");
         if (poMEMDrv == NULL)
         {
             CPLError(CE_Failure, CPLE_AppDefined, "Cannot load 'Memory' driver");
             return NULL;
         }
 
-        OGRDataSource* poMEMDS = poMEMDrv->CreateDataSource("dummy_name", NULL);
+        GDALDataset* poMEMDS = poMEMDrv->Create("dummy_name", 0, 0, 0, GDT_Unknown, NULL);
         OGRLayer* poMEMLayer = poMEMDS->CreateLayer("FID_LIST", NULL, wkbNone, NULL);
         OGRFieldDefn oFDefn("gml_id", OFTString);
         poMEMLayer->CreateField(&oFDefn);
@@ -1990,12 +2188,16 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
         /* Now turn this into OGC Filter language if possible */
         int bNeedsNullCheck = FALSE;
         int nVersion = (strcmp(GetVersion(),"1.0.0") == 0) ? 100 : 110;
-        CPLString osOGCFilter = WFS_TurnSQLFilterToOGCFilter(pszQuery,
+        swq_expr_node* poNode = (swq_expr_node*) oQuery.GetSWQExpr();
+        poNode->ReplaceBetweenByGEAndLERecurse();
+        CPLString osOGCFilter = WFS_TurnSQLFilterToOGCFilter(poNode,
+                                                             NULL,
                                                              poLayer->GetLayerDefn(),
                                                              nVersion,
                                                              bPropertyIsNotEqualToSupported,
                                                              bUseFeatureId,
                                                              bGmlObjectIdNeedsGMLPrefix,
+                                                             "",
                                                              &bNeedsNullCheck);
         if (bNeedsNullCheck && !HasNullCheck())
             osOGCFilter = "";
@@ -2017,7 +2219,7 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
     if (EQUALN(pszSQLCommand, "SELECT", 6))
     {
         swq_select* psSelectInfo = new swq_select();
-        if( psSelectInfo->preparse( pszSQLCommand ) != CPLE_None )
+        if( psSelectInfo->preparse( pszSQLCommand, TRUE ) != CPLE_None )
         {
             delete psSelectInfo;
             return NULL;
@@ -2028,21 +2230,38 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
             psSelectInfo->table_defs[0].data_source == NULL &&
             (iLayer = GetLayerIndex( psSelectInfo->table_defs[0].table_name )) >= 0 &&
             psSelectInfo->join_count == 0 &&
-            psSelectInfo->order_specs == 1 )
+            psSelectInfo->order_specs > 0 &&
+            psSelectInfo->poOtherSelect == NULL )
         {
             OGRWFSLayer* poSrcLayer = papoLayers[iLayer];
-            int nFieldIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(
-                                        psSelectInfo->order_defs[0].field_name);
-            if (!poSrcLayer->HasGotApproximateLayerDefn() && nFieldIndex >= 0)
+            std::vector<OGRWFSSortDesc> aoSortColumns;
+            int i;
+            for(i=0;i<psSelectInfo->order_specs;i++)
             {
-                OGRWFSLayer* poDupLayer = poSrcLayer->Clone(); 
+                int nFieldIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(
+                                        psSelectInfo->order_defs[i].field_name);
+                if (poSrcLayer->HasGotApproximateLayerDefn() || nFieldIndex < 0)
+                    break;
 
                 /* Make sure to have the right case */
-                const char* pszFieldName = poDupLayer->GetLayerDefn()->
+                const char* pszFieldName = poSrcLayer->GetLayerDefn()->
                     GetFieldDefn(nFieldIndex)->GetNameRef();
 
-                poDupLayer->SetOrderBy(pszFieldName,
-                                       psSelectInfo->order_defs[0].ascending_flag);
+                OGRWFSSortDesc oSortDesc(pszFieldName, 
+                                    psSelectInfo->order_defs[i].ascending_flag);
+                aoSortColumns.push_back(oSortDesc);
+            }
+
+            if( i == psSelectInfo->order_specs )
+            {
+                OGRWFSLayer* poDupLayer = poSrcLayer->Clone(); 
+
+                poDupLayer->SetOrderBy(aoSortColumns);
+                int nBackup = psSelectInfo->order_specs;
+                psSelectInfo->order_specs = 0;
+                char* pszSQLWithoutOrderBy = psSelectInfo->Unparse();
+                CPLDebug("WFS", "SQL without ORDER BY: %s", pszSQLWithoutOrderBy);
+                psSelectInfo->order_specs = nBackup;
                 delete psSelectInfo;
                 psSelectInfo = NULL;
 
@@ -2050,10 +2269,14 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
                 /* base ExecuteSQL(), so that the OGRGenSQLResultsLayer references */
                 /* that temporary layer */
                 papoLayers[iLayer] = poDupLayer;
-                OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
-                                                                  poSpatialFilter,
-                                                                  pszDialect );
+                
+                OGRLayer* poResLayer = GDALDataset::ExecuteSQL( pszSQLWithoutOrderBy,
+                                                                poSpatialFilter,
+                                                                pszDialect,
+                                                                &oParseOptions );
                 papoLayers[iLayer] = poSrcLayer;
+                
+                CPLFree(pszSQLWithoutOrderBy);
 
                 if (poResLayer != NULL)
                     oMap[poResLayer] = poDupLayer;
@@ -2062,13 +2285,45 @@ OGRLayer * OGRWFSDataSource::ExecuteSQL( const char *pszSQLCommand,
                 return poResLayer;
             }
         }
+        else if( bStandardJoinsWFS2 &&
+                 psSelectInfo->join_count > 0 &&
+                 psSelectInfo->poOtherSelect == NULL )
+        {
+            // Just to make sure everything is valid, but we won't use
+            // that one as we want to run the join on server-side
+            oParseOptions.bAllowFieldsInSecondaryTablesInWhere = TRUE;
+            oParseOptions.bAddSecondaryTablesGeometryFields = TRUE;
+            oParseOptions.bAlwaysPrefixWithTableName = TRUE;
+            oParseOptions.bAllowDistinctOnGeometryField = TRUE;
+            oParseOptions.bAllowDistinctOnMultipleFields = TRUE;
+            GDALSQLParseInfo* psParseInfo = BuildParseInfo(psSelectInfo,
+                                                           &oParseOptions);
+            oParseOptions.bAllowFieldsInSecondaryTablesInWhere = FALSE;
+            oParseOptions.bAddSecondaryTablesGeometryFields = FALSE;
+            oParseOptions.bAlwaysPrefixWithTableName = FALSE;
+            oParseOptions.bAllowDistinctOnGeometryField = FALSE;
+            oParseOptions.bAllowDistinctOnMultipleFields = FALSE;
+            int bOK = psParseInfo != NULL;
+            DestroyParseInfo(psParseInfo);
+
+            OGRLayer* poResLayer = NULL;
+            if( bOK )
+            {
+                poResLayer = OGRWFSJoinLayer::Build(this, psSelectInfo);
+                oMap[poResLayer] = NULL;
+            }
+
+            delete psSelectInfo;
+            return poResLayer;
+        }
 
         delete psSelectInfo;
     }
 
     OGRLayer* poResLayer = OGRDataSource::ExecuteSQL( pszSQLCommand,
                                                       poSpatialFilter,
-                                                      pszDialect );
+                                                      pszDialect,
+                                                      &oParseOptions );
     oMap[poResLayer] = NULL;
     return poResLayer;
 }
diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsdriver.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsdriver.cpp
index bd85925..9d7f8d0 100644
--- a/ogr/ogrsf_frmts/wfs/ogrwfsdriver.cpp
+++ b/ogr/ogrsf_frmts/wfs/ogrwfsdriver.cpp
@@ -32,39 +32,46 @@
 
 // g++ -fPIC -g -Wall ogr/ogrsf_frmts/wfs/*.cpp -shared -o ogr_WFS.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/gml -Iogr/ogrsf_frmts/wfs -L. -lgdal
 
-CPL_CVSID("$Id: ogrwfsdriver.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrwfsdriver.cpp 29019 2015-04-25 20:34:19Z rouault $");
 
 extern "C" void RegisterOGRWFS();
 
 /************************************************************************/
-/*                           ~OGRWFSDriver()                            */
+/*                             Identify()                               */
 /************************************************************************/
 
-OGRWFSDriver::~OGRWFSDriver()
+static int OGRWFSDriverIdentify( GDALOpenInfo* poOpenInfo )
 
 {
-}
-
-/************************************************************************/
-/*                              GetName()                               */
-/************************************************************************/
-
-const char *OGRWFSDriver::GetName()
-
-{
-    return "WFS";
+    if( !EQUALN(poOpenInfo->pszFilename, "WFS:", 4) )
+    {
+        if( poOpenInfo->fpL == NULL )
+            return FALSE;
+        if( !EQUALN((const char*)poOpenInfo->pabyHeader,"<OGRWFSDataSource>",18) &&
+            strstr((const char*)poOpenInfo->pabyHeader,"<WFS_Capabilities") == NULL &&
+            strstr((const char*)poOpenInfo->pabyHeader,"<wfs:WFS_Capabilities") == NULL)
+        {
+            return FALSE;
+        }
+    }
+    return TRUE;
 }
 
 /************************************************************************/
 /*                                Open()                                */
 /************************************************************************/
 
-OGRDataSource *OGRWFSDriver::Open( const char * pszFilename, int bUpdate )
+static GDALDataset *OGRWFSDriverOpen( GDALOpenInfo* poOpenInfo )
 
 {
+    if( !OGRWFSDriverIdentify(poOpenInfo) )
+        return NULL;
+
     OGRWFSDataSource   *poDS = new OGRWFSDataSource();
 
-    if( !poDS->Open( pszFilename, bUpdate ) )
+    if( !poDS->Open( poOpenInfo->pszFilename,
+                     poOpenInfo->eAccess == GA_Update,
+                     poOpenInfo->papszOpenOptions ) )
     {
         delete poDS;
         poDS = NULL;
@@ -74,21 +81,39 @@ OGRDataSource *OGRWFSDriver::Open( const char * pszFilename, int bUpdate )
 }
 
 /************************************************************************/
-/*                           TestCapability()                           */
-/************************************************************************/
-
-int OGRWFSDriver::TestCapability( CPL_UNUSED const char * pszCap )
-{
-    return FALSE;
-}
-
-/************************************************************************/
 /*                           RegisterOGRWFS()                           */
 /************************************************************************/
 
 void RegisterOGRWFS()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRWFSDriver );
+    GDALDriver  *poDriver;
+
+    if( GDALGetDriverByName( "WFS" ) == NULL )
+    {
+        poDriver = new GDALDriver();
+
+        poDriver->SetDescription( "WFS" );
+        poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
+        poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                   "OGC WFS (Web Feature Service)" );
+        poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                   "drv_wfs.html" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "WFS:" );
+
+        poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
+"<OpenOptionList>"
+"  <Option name='URL' type='string' description='URL to the WFS server endpoint' required='true'/>"
+"  <Option name='TRUST_CAPABILITIES_BOUNDS' type='boolean' description='Whether to trust layer bounds declared in GetCapabilities response' default='NO'/>"
+"</OpenOptionList>" );
+
+        poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+
+        poDriver->pfnIdentify = OGRWFSDriverIdentify;
+        poDriver->pfnOpen = OGRWFSDriverOpen;
+
+        GetGDALDriverManager()->RegisterDriver( poDriver );
+    }
 }
 
diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsfilter.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsfilter.cpp
index f5eb724..cfb91b7 100644
--- a/ogr/ogrsf_frmts/wfs/ogrwfsfilter.cpp
+++ b/ogr/ogrsf_frmts/wfs/ogrwfsfilter.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrwfsfilter.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrwfsfilter.cpp 29029 2015-04-26 21:22:57Z rouault $
  *
  * Project:  WFS Translator
  * Purpose:  Implements OGR SQL into OGC Filter translation.
@@ -28,198 +28,38 @@
  ****************************************************************************/
 
 #include "ogr_wfs.h"
+#include "ogr_p.h"
 
-#include "cpl_list.h"
+CPL_CVSID("$Id: ogrwfsfilter.cpp 29029 2015-04-26 21:22:57Z rouault $");
 
-CPL_CVSID("$Id: ogrwfsfilter.cpp 27044 2014-03-16 23:41:27Z rouault $");
-
-typedef enum
-{
-    TOKEN_GREATER_OR_EQUAL,
-    TOKEN_GREATER,
-    TOKEN_LESSER_OR_EQUAL,
-    TOKEN_LESSER,
-    TOKEN_LIKE,
-    TOKEN_EQUAL,
-    TOKEN_NOT_EQUAL,
-    TOKEN_NOT,
-    TOKEN_AND,
-    TOKEN_OR,
-    TOKEN_VAR_NAME,
-    TOKEN_LITERAL
-} TokenType;
-
-typedef struct _Expr Expr;
-
-struct _Expr
-{
-    TokenType eType;
-    char*     pszVal;
-    Expr*     expr1;
-    Expr*     expr2;
-};
-
-/************************************************************************/
-/*                      WFS_ExprGetPriority()                           */
-/************************************************************************/
-
-static int WFS_ExprGetPriority(const Expr* expr)
-{
-    if (expr->eType == TOKEN_NOT)
-        return 9;
-    else if (expr->eType == TOKEN_GREATER_OR_EQUAL ||
-             expr->eType == TOKEN_GREATER ||
-             expr->eType == TOKEN_LESSER_OR_EQUAL ||
-             expr->eType == TOKEN_LESSER)
-        return 6;
-    else if (expr->eType == TOKEN_EQUAL ||
-             expr->eType == TOKEN_LIKE ||
-             expr->eType == TOKEN_NOT_EQUAL)
-        return 5;
-    else if (expr->eType == TOKEN_AND)
-        return 4;
-    else if (expr->eType == TOKEN_OR)
-        return 3;
-    else
-        return 0;
-}
-
-/************************************************************************/
-/*                          WFS_ExprFree()                              */
-/************************************************************************/
-
-static void WFS_ExprFree(Expr* expr)
-{
-    if (expr == NULL) return;
-    if (expr->expr1)
-        WFS_ExprFree(expr->expr1);
-    if (expr->expr2)
-        WFS_ExprFree(expr->expr2);
-    CPLFree(expr->pszVal);
-    CPLFree(expr);
-}
-
-/************************************************************************/
-/*                        WFS_ExprFreeList()                            */
-/************************************************************************/
-
-static void WFS_ExprFreeList(CPLList* psExprList)
-{
-    CPLList* psIterList = psExprList;
-    while(psIterList)
-    {
-        WFS_ExprFree((Expr*)psIterList->pData);
-        psIterList = psIterList->psNext;
-    }
-    CPLListDestroy(psExprList);
-}
-
-/************************************************************************/
-/*                    WFS_ExprBuildVarName()                            */
-/************************************************************************/
-
-static Expr* WFS_ExprBuildVarName(const char* pszVal)
-{
-    Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
-    expr->eType = TOKEN_VAR_NAME;
-    expr->pszVal = CPLStrdup(pszVal);
-    return expr;
-}
-
-/************************************************************************/
-/*                      WFS_ExprBuildValue()                            */
-/************************************************************************/
-
-static Expr* WFS_ExprBuildValue(const char* pszVal)
-{
-    Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
-    expr->eType = TOKEN_LITERAL;
-    expr->pszVal = CPLStrdup(pszVal);
-    return expr;
-}
-
-/************************************************************************/
-/*                    WFS_ExprBuildOperator()                           */
-/************************************************************************/
-
-static Expr* WFS_ExprBuildOperator(TokenType eType)
-{
-    Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
-    expr->eType = eType;
-    return expr;
-}
-
-/************************************************************************/
-/*                     WFS_ExprBuildBinary()                            */
-/************************************************************************/
-
-static Expr* WFS_ExprBuildBinary(TokenType eType, Expr* expr1, Expr* expr2)
-{
-    Expr* expr = (Expr*)CPLCalloc(1, sizeof(Expr));
-    expr->eType = eType;
-    expr->expr1 = expr1;
-    expr->expr2 = expr2;
-    return expr;
-}
-
-#ifdef notdef
-
-/************************************************************************/
-/*                          WFS_ExprDump()                              */
-/************************************************************************/
-
-static void WFS_ExprDump(FILE* fp, const Expr* expr)
+typedef struct
 {
-    switch(expr->eType)
-    {
-        case TOKEN_VAR_NAME:
-        case TOKEN_LITERAL:
-            fprintf(fp, "%s", expr->pszVal);
-            break;
-
-        case TOKEN_NOT:
-            fprintf(fp, "NOT (");
-            WFS_ExprDump(fp, expr->expr1);
-            fprintf(fp, ")");
-            break;
-
-        default:
-            fprintf(fp, "(");
-            WFS_ExprDump(fp, expr->expr1);
-            switch(expr->eType)
-            {
-                case TOKEN_EQUAL:           fprintf(fp, " = "); break;
-                case TOKEN_LIKE:            fprintf(fp, " LIKE "); break;
-                case TOKEN_NOT_EQUAL:       fprintf(fp, " != "); break;
-                case TOKEN_LESSER_OR_EQUAL: fprintf(fp, " <= "); break;
-                case TOKEN_LESSER:          fprintf(fp, " < "); break;
-                case TOKEN_GREATER_OR_EQUAL:fprintf(fp, " >= "); break;
-                case TOKEN_GREATER:         fprintf(fp, " > "); break;
-                case TOKEN_AND:             fprintf(fp, " AND "); break;
-                case TOKEN_OR:              fprintf(fp, " OR "); break;
-                default: break;
-            }
-            WFS_ExprDump(fp, expr->expr2);
-            fprintf(fp, ")");
-            break;
-    }
-}
-#endif
+    int nVersion;
+    int bPropertyIsNotEqualToSupported;
+    int bOutNeedsNullCheck;
+    OGRDataSource* poDS;
+    OGRFeatureDefn* poFDefn;
+    int nUniqueGeomGMLId;
+    OGRSpatialReference* poSRS;
+    const char* pszNSPrefix;
+} ExprDumpFilterOptions;
 
 /************************************************************************/
 /*                WFS_ExprDumpGmlObjectIdFilter()                       */
 /************************************************************************/
 
 static int WFS_ExprDumpGmlObjectIdFilter(CPLString& osFilter,
-                                         const Expr* expr,
+                                         const swq_expr_node* poExpr,
                                          int bUseFeatureId,
                                          int bGmlObjectIdNeedsGMLPrefix,
                                          int nVersion)
 {
-    if (expr->eType == TOKEN_EQUAL &&
-        expr->expr1->eType == TOKEN_VAR_NAME &&
-        EQUAL(expr->expr1->pszVal, "gml_id") &&
-        expr->expr2->eType == TOKEN_LITERAL)
+    if (poExpr->eNodeType == SNT_OPERATION &&
+        poExpr->nOperation == SWQ_EQ &&
+        poExpr->nSubExprCount == 2 &&
+        poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+        strcmp(poExpr->papoSubExpr[0]->string_value, "gml_id") == 0 &&
+        poExpr->papoSubExpr[1]->eNodeType == SNT_CONSTANT)
     {
         if (bUseFeatureId)
             osFilter += "<FeatureId fid=\"";
@@ -229,638 +69,744 @@ static int WFS_ExprDumpGmlObjectIdFilter(CPLString& osFilter,
             osFilter += "<GmlObjectId id=\"";
         else
             osFilter += "<GmlObjectId gml:id=\"";
-        if (expr->expr2->pszVal[0] == '\'' || expr->expr2->pszVal[0] == '"')
+        if( poExpr->papoSubExpr[1]->field_type == SWQ_INTEGER ||
+            poExpr->papoSubExpr[1]->field_type == SWQ_INTEGER64 )
+            osFilter += CPLSPrintf(CPL_FRMT_GIB, poExpr->papoSubExpr[1]->int_value);
+        else if( poExpr->papoSubExpr[1]->field_type == SWQ_STRING )
         {
-            CPLString osVal(expr->expr2->pszVal + 1);
-            osVal.resize(osVal.size() - 1);
-            osFilter += osVal;
+            char* pszXML = CPLEscapeString(poExpr->papoSubExpr[1]->string_value, -1, CPLES_XML);
+            osFilter += pszXML;
+            CPLFree(pszXML);
         }
         else
-            osFilter += expr->expr2->pszVal;
+            return FALSE;
         osFilter += "\"/>";
         return TRUE;
     }
-    else if (expr->eType == TOKEN_OR)
+    else if (poExpr->eNodeType == SNT_OPERATION &&
+             poExpr->nOperation == SWQ_OR &&
+             poExpr->nSubExprCount == 2 )
     {
-        return WFS_ExprDumpGmlObjectIdFilter(osFilter, expr->expr1,
+        return WFS_ExprDumpGmlObjectIdFilter(osFilter, poExpr->papoSubExpr[0],
                                              bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion) &&
-               WFS_ExprDumpGmlObjectIdFilter(osFilter, expr->expr2,
+               WFS_ExprDumpGmlObjectIdFilter(osFilter, poExpr->papoSubExpr[1],
                                              bUseFeatureId, bGmlObjectIdNeedsGMLPrefix, nVersion);
     }
     return FALSE;
 }
 
 /************************************************************************/
-/*                     WFS_ExprDumpAsOGCFilter()                        */
+/*                     WFS_ExprDumpRawLitteral()                        */
 /************************************************************************/
 
-typedef struct
+static int WFS_ExprDumpRawLitteral(CPLString& osFilter,
+                                   const swq_expr_node* poExpr)
 {
-    int nVersion;
-    int bPropertyIsNotEqualToSupported;
-    int bOutNeedsNullCheck;
-    OGRFeatureDefn* poFDefn;
-} ExprDumpFilterOptions;
-
-static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter,
-                                   const Expr* expr,
-                                   int bExpectBinary,
-                                   ExprDumpFilterOptions* psOptions)
-{
-    switch(expr->eType)
+    if( poExpr->field_type == SWQ_INTEGER ||
+        poExpr->field_type == SWQ_INTEGER64 )
+        osFilter += CPLSPrintf(CPL_FRMT_GIB, poExpr->int_value);
+    else if( poExpr->field_type == SWQ_FLOAT )
+        osFilter += CPLSPrintf("%.16g", poExpr->float_value);
+    else if( poExpr->field_type == SWQ_STRING )
     {
-        case TOKEN_VAR_NAME:
-        {
-            if (bExpectBinary)
-                return FALSE;
-
-            /* Special fields not understood by server */
-            if (EQUAL(expr->pszVal, "gml_id") ||
-                EQUAL(expr->pszVal, "FID") ||
-                EQUAL(expr->pszVal, "OGR_GEOMETRY") ||
-                EQUAL(expr->pszVal, "OGR_GEOM_WKT") ||
-                EQUAL(expr->pszVal, "OGR_GEOM_AREA") ||
-                EQUAL(expr->pszVal, "OGR_STYLE"))
-            {
-                CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot use server-side filtering");
-                return FALSE;
-            }
-
-            const char* pszFieldname;
-            CPLString osVal;
-            if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
-            {
-                osVal = expr->pszVal + 1;
-                osVal.resize(osVal.size() - 1);
-                pszFieldname = osVal.c_str();
-            }
-            else
-                pszFieldname = expr->pszVal;
-
-            if (psOptions->poFDefn->GetFieldIndex(pszFieldname) == -1)
-            {
-                CPLDebug("WFS", "Field '%s' unknown. Cannot use server-side filtering",
-                         pszFieldname);
-                return FALSE;
-            }
-
-            if (psOptions->nVersion >= 200)
-                osFilter += "<ValueReference>";
-            else
-                osFilter += "<PropertyName>";
-            char* pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML);
-            osFilter += pszFieldnameXML;
-            CPLFree(pszFieldnameXML);
-            if (psOptions->nVersion >= 200)
-                osFilter += "</ValueReference>";
-            else
-                osFilter += "</PropertyName>";
-            break;
-        }
-
-        case TOKEN_LITERAL:
-        {
-            if (bExpectBinary)
-                return FALSE;
-
-            const char* pszLiteral;
-            CPLString osVal;
-            if (expr->pszVal[0] == '\'' || expr->pszVal[0] == '"')
-            {
-                osVal = expr->pszVal + 1;
-                osVal.resize(osVal.size() - 1);
-                pszLiteral = osVal.c_str();
-            }
-            else
-                pszLiteral = expr->pszVal;
-
-            osFilter += "<Literal>";
-            char* pszLiteralXML = CPLEscapeString(pszLiteral, -1, CPLES_XML);
-            osFilter += pszLiteralXML;
-            CPLFree(pszLiteralXML);
-            osFilter += "</Literal>";
-
-            break;
-        }
+        char* pszXML = CPLEscapeString(poExpr->string_value, -1, CPLES_XML);
+        osFilter += pszXML;
+        CPLFree(pszXML);
+    }
+    else if( poExpr->field_type == SWQ_TIMESTAMP )
+    {
+        OGRField sDate;
+        if( !OGRParseDate(poExpr->string_value, &sDate, 0) )
+            return FALSE;
+        char* pszDate = OGRGetXMLDateTime(&sDate);
+        osFilter += pszDate;
+        CPLFree(pszDate);
+    }
+    else
+        return FALSE;
+    return TRUE;
+}
 
-        case TOKEN_NOT:
-            osFilter += "<Not>";
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
-                return FALSE;
-            osFilter += "</Not>";
-            break;
+/************************************************************************/
+/*                       WFS_ExprGetSRSName()                          */
+/************************************************************************/
 
-        case TOKEN_LIKE:
+static const char* WFS_ExprGetSRSName( const swq_expr_node* poExpr,
+                                       int iSubArgIndex,
+                                       ExprDumpFilterOptions* psOptions,
+                                       OGRSpatialReference& oSRS )
+{
+    if( poExpr->nSubExprCount == iSubArgIndex + 1 &&
+        poExpr->papoSubExpr[iSubArgIndex]->field_type == SWQ_STRING )
+    {
+        if( oSRS.SetFromUserInput(poExpr->papoSubExpr[iSubArgIndex]->string_value) == OGRERR_NONE )
         {
-            CPLString osVal;
-            char ch;
-            char firstCh = 0;
-            int i;
-            if (psOptions->nVersion == 100)
-                osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escape='!'>";
-            else
-                osFilter += "<PropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>";
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
-                return FALSE;
-            if (expr->expr2->eType != TOKEN_LITERAL)
-                return FALSE;
-            osFilter += "<Literal>";
-
-            /* Escape value according to above special characters */
-            /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */
-            i = 0;
-            ch = expr->expr2->pszVal[i];
-            if (ch == '\'' || ch == '"')
-            {
-                firstCh = ch;
-                i ++;
-            }
-            for(;(ch = expr->expr2->pszVal[i]) != '\0';i++)
-            {
-                if (ch == '%')
-                    osVal += "*";
-                else if (ch == '!')
-                    osVal += "!!";
-                else if (ch == '*')
-                    osVal += "!*";
-                else if (ch == firstCh && expr->expr2->pszVal[i + 1] == 0)
-                    break;
-                else
-                {
-                    char ach[2];
-                    ach[0] = ch;
-                    ach[1] = 0;
-                    osVal += ach;
-                }
-            }
-            osFilter += osVal;
-            osFilter += "</Literal>";
-            osFilter += "</PropertyIsLike>";
-            break;
+            return poExpr->papoSubExpr[iSubArgIndex]->string_value;
         }
-
-        case TOKEN_EQUAL:
-        case TOKEN_NOT_EQUAL:
-        case TOKEN_LESSER_OR_EQUAL:
-        case TOKEN_LESSER:
-        case TOKEN_GREATER_OR_EQUAL:
-        case TOKEN_GREATER:
+    }
+    else if ( poExpr->nSubExprCount == iSubArgIndex + 1 &&
+              poExpr->papoSubExpr[iSubArgIndex]->field_type == SWQ_INTEGER )
+    {
+        if( oSRS.importFromEPSGA((int)poExpr->papoSubExpr[iSubArgIndex]->int_value) == OGRERR_NONE )
         {
-            if (expr->eType == TOKEN_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
-                EQUAL(expr->expr2->pszVal, "NULL"))
-            {
-                osFilter += "<PropertyIsNull>";
-                if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
-                    return FALSE;
-                osFilter += "</PropertyIsNull>";
-                psOptions->bOutNeedsNullCheck = TRUE;
-                break;
-            }
-            if (expr->eType == TOKEN_NOT_EQUAL && expr->expr2->eType == TOKEN_LITERAL &&
-                EQUAL(expr->expr2->pszVal, "NULL"))
-            {
-                osFilter += "<Not><PropertyIsNull>";
-                if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
-                    return FALSE;
-                osFilter += "</PropertyIsNull></Not>";
-                psOptions->bOutNeedsNullCheck = TRUE;
-                break;
-            }
-            TokenType eType = expr->eType;
-            int bAddClosingNot = FALSE;
-            if (!psOptions->bPropertyIsNotEqualToSupported && eType == TOKEN_NOT_EQUAL)
-            {
-                osFilter += "<Not>";
-                eType = TOKEN_EQUAL;
-                bAddClosingNot = TRUE;
-            }
-
-            const char* pszName = NULL;
-            switch(eType)
-            {
-                case TOKEN_EQUAL:           pszName = "PropertyIsEqualTo"; break;
-                case TOKEN_NOT_EQUAL:       pszName = "PropertyIsNotEqualTo"; break;
-                case TOKEN_LESSER_OR_EQUAL: pszName = "PropertyIsLessThanOrEqualTo"; break;
-                case TOKEN_LESSER:          pszName = "PropertyIsLessThan"; break;
-                case TOKEN_GREATER_OR_EQUAL:pszName = "PropertyIsGreaterThanOrEqualTo"; break;
-                case TOKEN_GREATER:         pszName = "PropertyIsGreaterThan"; break;
-                default: break;
-            }
-            osFilter += "<";
-            osFilter += pszName;
-            osFilter += ">";
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, FALSE, psOptions))
-                return FALSE;
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, FALSE, psOptions))
-                return FALSE;
-            osFilter += "</";
-            osFilter += pszName;
-            osFilter += ">";
-            if (bAddClosingNot)
-                osFilter += "</Not>";
-            break;
+            return CPLSPrintf("urn:ogc:def:crs:EPSG::%d", (int)poExpr->papoSubExpr[iSubArgIndex]->int_value);
         }
-
-        case TOKEN_AND:
-        case TOKEN_OR:
+    }
+    else if( poExpr->nSubExprCount == iSubArgIndex &&
+             psOptions->poSRS != NULL )
+    {
+        if( psOptions->poSRS->GetAuthorityName(NULL) &&
+            EQUAL(psOptions->poSRS->GetAuthorityName(NULL), "EPSG") &&
+            psOptions->poSRS->GetAuthorityCode(NULL) &&
+            oSRS.importFromEPSGA(atoi(psOptions->poSRS->GetAuthorityCode(NULL))) == OGRERR_NONE )
         {
-            const char* pszName = (expr->eType == TOKEN_AND) ? "And" : "Or";
-            osFilter += "<";
-            osFilter += pszName;
-            osFilter += ">";
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr1, TRUE, psOptions))
-                return FALSE;
-            if (!WFS_ExprDumpAsOGCFilter(osFilter, expr->expr2, TRUE, psOptions))
-                return FALSE;
-            osFilter += "</";
-            osFilter += pszName;
-            osFilter += ">";
-
-            break;
+            return CPLSPrintf("urn:ogc:def:crs:EPSG::%s", psOptions->poSRS->GetAuthorityCode(NULL));
         }
-
-        default:
-            return FALSE;
     }
-
-    return TRUE;
+    return NULL;
 }
 
 /************************************************************************/
-/*                      WFS_ExprBuildInternal()                         */
+/*                     WFS_ExprDumpAsOGCFilter()                        */
 /************************************************************************/
 
-typedef struct
-{
-    int bExpectVarName;
-    int bExpectComparisonOperator;
-    int bExpectLogicalOperator;
-    int bExpectValue;
-    int nParenthesisLevel;
-} ExprBuildContext;
-
-static Expr* WFS_ExprBuildInternal(char*** ppapszTokens,
-                                   ExprBuildContext* psBuildContext)
+static int WFS_ExprDumpAsOGCFilter(CPLString& osFilter,
+                                   const swq_expr_node* poExpr,
+                                   int bExpectBinary,
+                                   ExprDumpFilterOptions* psOptions)
 {
-    Expr* expr = NULL;
-    Expr* op = NULL;
-    Expr* val1 = NULL;
-    Expr* val2 = NULL;
-    CPLList* psValExprList = NULL;
-    CPLList* psOpExprList = NULL;
-    char** papszTokens = *ppapszTokens;
-    char* pszToken = NULL;
-
-#define PEEK_OP(my_op) my_op = (Expr*)CPLListGetData(psOpExprList)
-#define PUSH_OP(my_op) psOpExprList = CPLListInsert(psOpExprList, my_op, 0)
-#define POP_OP(my_op) do { my_op = (Expr*)CPLListGetData(psOpExprList);  \
-                           if (my_op != NULL) { \
-                                CPLList* psNext = psOpExprList->psNext; \
-                                CPLFree(psOpExprList); \
-                                psOpExprList = psNext; \
-                           } \
-                      } while(0)
-#define PUSH_VAL(my_val) psValExprList = CPLListInsert(psValExprList, my_val, 0)
-#define POP_VAL(my_val) do { my_val = (Expr*)CPLListGetData(psValExprList); \
-                           if (my_val != NULL) { \
-                                CPLList* psNext = psValExprList->psNext; \
-                                CPLFree(psValExprList); \
-                                psValExprList = psNext; \
-                           } \
-                      } while(0)
-    while(TRUE)
-    {
-        pszToken = *papszTokens;
-        if (pszToken == NULL)
-            break;
-        papszTokens ++;
-
-        if (EQUAL(pszToken, "("))
-        {
-            char** papszSub = papszTokens;
-            psBuildContext->nParenthesisLevel ++;
-            Expr* expr = WFS_ExprBuildInternal(&papszSub, psBuildContext);
-            psBuildContext->nParenthesisLevel --;
-            if (expr == NULL)
-                goto invalid_expr;
-            PUSH_VAL(expr);
-            papszTokens = papszSub;
-            if (*papszTokens == NULL)
-                break;
+    if( poExpr->eNodeType == SNT_COLUMN )
+    {
+        if (bExpectBinary)
+            return FALSE;
 
-            continue;
-        }
-        else if (EQUAL(pszToken, ")"))
+        /* Special fields not understood by server */
+        if (EQUAL(poExpr->string_value, "gml_id") ||
+            EQUAL(poExpr->string_value, "FID") ||
+            EQUAL(poExpr->string_value, "OGR_GEOMETRY") ||
+            EQUAL(poExpr->string_value, "OGR_GEOM_WKT") ||
+            EQUAL(poExpr->string_value, "OGR_GEOM_AREA") ||
+            EQUAL(poExpr->string_value, "OGR_STYLE"))
         {
-            if (psBuildContext->nParenthesisLevel > 0)
-                break;
-            else
-                goto invalid_expr;
+            CPLDebug("WFS", "Attribute refers to a OGR special field. Cannot use server-side filtering");
+            return FALSE;
         }
 
-        if (psBuildContext->bExpectVarName)
+        const char* pszFieldname = NULL;
+        int nIndex;
+        int bSameTable = psOptions->poFDefn != NULL &&
+                         ( poExpr->table_name == NULL ||
+                           EQUAL(poExpr->table_name, psOptions->poFDefn->GetName()) );
+        if( bSameTable )
         {
-            if (EQUAL(pszToken, "NOT"))
-                op = WFS_ExprBuildOperator(TOKEN_NOT);
-            else
+            if( (nIndex = psOptions->poFDefn->GetFieldIndex(poExpr->string_value)) >= 0 )
             {
-                PUSH_VAL(WFS_ExprBuildVarName(pszToken));
-                psBuildContext->bExpectVarName = FALSE;
-                psBuildContext->bExpectComparisonOperator = TRUE;
+                pszFieldname = psOptions->poFDefn->GetFieldDefn(nIndex)->GetNameRef();
+            }
+            else if( (nIndex = psOptions->poFDefn->GetGeomFieldIndex(poExpr->string_value)) >= 0 )
+            {
+                pszFieldname = psOptions->poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef();
             }
         }
-        else if (psBuildContext->bExpectComparisonOperator)
+        else if( psOptions->poDS != NULL )
         {
-            psBuildContext->bExpectComparisonOperator = FALSE;
-            psBuildContext->bExpectValue = TRUE;
-            if (EQUAL(pszToken, "IS"))
+            OGRLayer* poLayer = psOptions->poDS->GetLayerByName(poExpr->table_name);
+            if( poLayer )
             {
-                if (*papszTokens != NULL && EQUAL(*papszTokens, "NOT"))
+                OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
+                if( (nIndex = poFDefn->GetFieldIndex(poExpr->string_value)) >= 0 )
                 {
-                    op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
-                    papszTokens ++;
+                    pszFieldname = CPLSPrintf("%s/%s",
+                                              poLayer->GetName(),
+                                              poFDefn->GetFieldDefn(nIndex)->GetNameRef());
+                }
+                else if( (nIndex = poFDefn->GetGeomFieldIndex(poExpr->string_value)) >= 0 )
+                {
+                    pszFieldname = CPLSPrintf("%s/%s",
+                                              poLayer->GetName(),
+                                              poFDefn->GetGeomFieldDefn(nIndex)->GetNameRef());
                 }
-                else
-                    op = WFS_ExprBuildOperator(TOKEN_EQUAL);
             }
-            else if (EQUAL(pszToken, "="))
-                op = WFS_ExprBuildOperator(TOKEN_EQUAL);
-            else if (EQUAL(pszToken, "LIKE") || EQUAL(pszToken, "ILIKE"))
-                op = WFS_ExprBuildOperator(TOKEN_LIKE);
-            else if (EQUAL(pszToken, "!=") || EQUAL(pszToken, "<>"))
-                op = WFS_ExprBuildOperator(TOKEN_NOT_EQUAL);
-            else if (EQUAL(pszToken, "<"))
-                op = WFS_ExprBuildOperator(TOKEN_LESSER);
-            else if (EQUAL(pszToken, "<="))
-                op = WFS_ExprBuildOperator(TOKEN_LESSER_OR_EQUAL);
-            else if (EQUAL(pszToken, ">"))
-                op = WFS_ExprBuildOperator(TOKEN_GREATER);
-            else if (EQUAL(pszToken, ">="))
-                op = WFS_ExprBuildOperator(TOKEN_GREATER_OR_EQUAL);
-            else
-                goto invalid_expr;
         }
-        else if (psBuildContext->bExpectLogicalOperator)
+        
+        if( psOptions->poFDefn == NULL && psOptions->poDS == NULL )
+            pszFieldname = poExpr->string_value;
+
+        if( pszFieldname == NULL )
         {
-            psBuildContext->bExpectLogicalOperator = FALSE;
-            psBuildContext->bExpectVarName = TRUE;
-            if (EQUAL(pszToken, "AND"))
-                op = WFS_ExprBuildOperator(TOKEN_AND);
-            else if (EQUAL(pszToken, "OR"))
-                op = WFS_ExprBuildOperator(TOKEN_OR);
-            else if (EQUAL(pszToken, "NOT"))
-                op = WFS_ExprBuildOperator(TOKEN_NOT);
+            if( poExpr->table_name != NULL )
+                CPLDebug("WFS", "Field \"%s\".\"%s\" unknown. Cannot use server-side filtering",
+                         poExpr->table_name, poExpr->string_value);
             else
-                goto invalid_expr;
-        }
-        else if (psBuildContext->bExpectValue)
-        {
-            PUSH_VAL(WFS_ExprBuildValue(pszToken));
-            psBuildContext->bExpectValue = FALSE;
-            psBuildContext->bExpectLogicalOperator = TRUE;
+                CPLDebug("WFS", "Field \"%s\" unknown. Cannot use server-side filtering",
+                         poExpr->string_value);
+            return FALSE;
         }
-        else
-            goto invalid_expr;
-
-        if (op != NULL)
-        {
-            Expr* prevOp;
 
-            while(TRUE)
-            {
-                PEEK_OP(prevOp);
+        if (psOptions->nVersion >= 200)
+            osFilter += CPLSPrintf("<%sValueReference>", psOptions->pszNSPrefix);
+        else
+            osFilter += CPLSPrintf("<%sPropertyName>", psOptions->pszNSPrefix);
+        char* pszFieldnameXML = CPLEscapeString(pszFieldname, -1, CPLES_XML);
+        osFilter += pszFieldnameXML;
+        CPLFree(pszFieldnameXML);
+        if (psOptions->nVersion >= 200)
+            osFilter += CPLSPrintf("</%sValueReference>", psOptions->pszNSPrefix);
+        else
+            osFilter += CPLSPrintf("</%sPropertyName>", psOptions->pszNSPrefix);
 
-                if (prevOp != NULL &&
-                    (WFS_ExprGetPriority(op) <= WFS_ExprGetPriority(prevOp)))
-                {
-                    if (prevOp->eType != TOKEN_NOT)
-                    {
-                        POP_VAL(val2);
-                        if (val2 == NULL) goto invalid_expr;
-                    }
-                    POP_VAL(val1);
-                    if (val1 == NULL) goto invalid_expr;
+        return TRUE;
+    }
 
-                    PUSH_VAL(WFS_ExprBuildBinary(prevOp->eType, val1, val2));
-                    POP_OP(prevOp);
-                    WFS_ExprFree(prevOp);
-                    val1 = val2 = NULL;
-                }
-                else
-                    break;
-            }
+    if( poExpr->eNodeType == SNT_CONSTANT )
+    {
+        if (bExpectBinary)
+            return FALSE;
 
-            PUSH_OP(op);
-            op = NULL;
-        }
+        osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix);
+        if( !WFS_ExprDumpRawLitteral(osFilter, poExpr) )
+            return FALSE;
+        osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix);
 
+        return TRUE;
     }
+    
+    if( poExpr->eNodeType != SNT_OPERATION )
+        return FALSE; /* shouldn't happen */
 
-    *ppapszTokens = papszTokens;
-
-    while(TRUE)
+    if( poExpr->nOperation == SWQ_NOT )
     {
-        POP_OP(op);
-        if (op == NULL)
-            break;
-        if (op->eType != TOKEN_NOT)
-        {
-            POP_VAL(val2);
-            if (val2 == NULL) goto invalid_expr;
-        }
-        POP_VAL(val1);
-        if (val1 == NULL) goto invalid_expr;
-        PUSH_VAL(WFS_ExprBuildBinary(op->eType, val1, val2));
-        val1 = val2 = NULL;
-
-        WFS_ExprFree(op);
-        op = NULL;
+        osFilter +=  CPLSPrintf("<%sNot>", psOptions->pszNSPrefix);
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE, psOptions))
+            return FALSE;
+        osFilter +=  CPLSPrintf("</%sNot>", psOptions->pszNSPrefix);
+        return TRUE;
     }
 
-    POP_VAL(expr);
-    return expr;
-
-invalid_expr:
-    WFS_ExprFree(op);
-    WFS_ExprFree(val1);
-    WFS_ExprFree(val2);
-    WFS_ExprFreeList(psValExprList);
-    WFS_ExprFreeList(psOpExprList);
-
-    return NULL;
-}
-
-/************************************************************************/
-/*                         WFS_ExprTokenize()                           */
-/************************************************************************/
-
-static char** WFS_ExprTokenize(const char* pszFilter)
-{
-    const char* pszIter = pszFilter;
-    CPLString osToken;
-    char** papszTokens = NULL;
-    int bLastCharWasSep = TRUE;
-    char prevCh = 0;
-    char ch;
-    int bInQuote = FALSE;
-    char chQuoteChar = 0;
-
-    if (pszFilter == NULL)
-        return NULL;
-
-    while((ch = *pszIter) != '\0')
+    if( poExpr->nOperation == SWQ_LIKE )
     {
-        if (bInQuote)
-        {
-            osToken += ch;
-            if (ch == chQuoteChar)
-            {
-                papszTokens = CSLAddString(papszTokens, osToken.c_str());
-                osToken = "";
-                bInQuote = FALSE;
-            }
-
-            prevCh = ch;
-            pszIter ++;
-            continue;
-        }
+        CPLString osVal;
+        char ch;
+        char firstCh = 0;
+        int i;
+        if (psOptions->nVersion == 100)
+            osFilter += CPLSPrintf("<%sPropertyIsLike wildCard='*' singleChar='_' escape='!'>", psOptions->pszNSPrefix);
+        else
+            osFilter += CPLSPrintf("<%sPropertyIsLike wildCard='*' singleChar='_' escapeChar='!'>", psOptions->pszNSPrefix);
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions))
+            return FALSE;
+        if (poExpr->papoSubExpr[1]->eNodeType != SNT_CONSTANT &&
+            poExpr->papoSubExpr[1]->field_type != SWQ_STRING)
+            return FALSE;
+        osFilter += CPLSPrintf("<%sLiteral>", psOptions->pszNSPrefix);
 
-        if (ch == ' ')
+        /* Escape value according to above special characters */
+        /* For URL compatibility reason, we remap the OGR SQL '%' wildchard into '*' */
+        i = 0;
+        ch = poExpr->papoSubExpr[1]->string_value[i];
+        if (ch == '\'' || ch == '"')
         {
-            if (!bLastCharWasSep)
-            {
-                if (osToken.size())
-                    papszTokens = CSLAddString(papszTokens, osToken.c_str());
-                osToken = "";
-            }
-            bLastCharWasSep = TRUE;
-        }
-        else if (ch == '(' || ch == ')' )
-        {
-            if (osToken.size())
-                papszTokens = CSLAddString(papszTokens, osToken.c_str());
-            char ach[2];
-            ach[0] = ch;
-            ach[1] = 0;
-            papszTokens = CSLAddString(papszTokens, ach);
-            osToken = "";
+            firstCh = ch;
+            i ++;
         }
-        else if (ch == '<' || ch == '>' || ch == '!')
+        for(;(ch = poExpr->papoSubExpr[1]->string_value[i]) != '\0';i++)
         {
-            if (ch == '>' && prevCh == '<')
-            {
-                osToken += ch;
-                papszTokens = CSLAddString(papszTokens, osToken.c_str());
-                osToken = "";
-            }
+            if (ch == '%')
+                osVal += "*";
+            else if (ch == '!')
+                osVal += "!!";
+            else if (ch == '*')
+                osVal += "!*";
+            else if (ch == firstCh && poExpr->papoSubExpr[1]->string_value[i + 1] == 0)
+                break;
             else
             {
-                if (osToken.size())
-                    papszTokens = CSLAddString(papszTokens, osToken.c_str());
                 char ach[2];
                 ach[0] = ch;
                 ach[1] = 0;
-                osToken = ach;
+                osVal += ach;
             }
         }
-        else if (ch == '=')
+        char* pszXML = CPLEscapeString(osVal, -1, CPLES_XML);
+        osFilter += pszXML;
+        CPLFree(pszXML);
+        osFilter += CPLSPrintf("</%sLiteral>", psOptions->pszNSPrefix);
+        osFilter += CPLSPrintf("</%sPropertyIsLike>", psOptions->pszNSPrefix);
+        return TRUE;
+    }
+
+    if( poExpr->nOperation == SWQ_ISNULL )
+    {
+        osFilter += CPLSPrintf("<%sPropertyIsNull>", psOptions->pszNSPrefix);
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions))
+            return FALSE;
+        osFilter += CPLSPrintf("</%sPropertyIsNull>", psOptions->pszNSPrefix);
+        psOptions->bOutNeedsNullCheck = TRUE;
+        return TRUE;
+    }
+
+    if( poExpr->nOperation == SWQ_EQ ||
+        poExpr->nOperation == SWQ_NE ||
+        poExpr->nOperation == SWQ_LE ||
+        poExpr->nOperation == SWQ_LT ||
+        poExpr->nOperation == SWQ_GE ||
+        poExpr->nOperation == SWQ_GT )
+    {
+        int nOperation = poExpr->nOperation;
+        int bAddClosingNot = FALSE;
+        if (!psOptions->bPropertyIsNotEqualToSupported && nOperation == SWQ_NE)
         {
-            if (prevCh == '<' || prevCh == '>' || prevCh == '!')
-                osToken += ch;
-            else if (prevCh == '=')
-                ;
-            else
-            {
-                if (osToken.size())
-                    papszTokens = CSLAddString(papszTokens, osToken.c_str());
-                osToken = "=";
-            }
+            osFilter += CPLSPrintf("<%sNot>", psOptions->pszNSPrefix);
+            nOperation = SWQ_EQ;
+            bAddClosingNot = TRUE;
         }
-        else if (ch == '\'' || ch == '"')
+
+        const char* pszName = NULL;
+        switch(nOperation)
         {
-            if (osToken.size())
-                papszTokens = CSLAddString(papszTokens, osToken.c_str());
-            osToken = "'";
-            bInQuote = TRUE;
-            chQuoteChar = ch;
+            case SWQ_EQ:  pszName = "PropertyIsEqualTo"; break;
+            case SWQ_NE:  pszName = "PropertyIsNotEqualTo"; break;
+            case SWQ_LE:  pszName = "PropertyIsLessThanOrEqualTo"; break;
+            case SWQ_LT:  pszName = "PropertyIsLessThan"; break;
+            case SWQ_GE:  pszName = "PropertyIsGreaterThanOrEqualTo"; break;
+            case SWQ_GT:  pszName = "PropertyIsGreaterThan"; break;
+            default: break;
         }
-        else
+        osFilter += "<";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], FALSE, psOptions))
+            return FALSE;
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], FALSE, psOptions))
+            return FALSE;
+        osFilter += "</";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        if (bAddClosingNot)
+            osFilter += CPLSPrintf("</%sNot>", psOptions->pszNSPrefix);
+        return TRUE;
+    }
+
+    if( poExpr->nOperation == SWQ_AND ||
+        poExpr->nOperation == SWQ_OR )
+    {
+        const char* pszName = (poExpr->nOperation == SWQ_AND) ? "And" : "Or";
+        osFilter += "<";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[0], TRUE, psOptions))
+            return FALSE;
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[1], TRUE, psOptions))
+            return FALSE;
+        osFilter += "</";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        return TRUE;
+    }
+    
+    if( poExpr->nOperation == SWQ_CUSTOM_FUNC &&
+        EQUAL(poExpr->string_value, "ST_MakeEnvelope") )
+    {
+        OGRSpatialReference oSRS;
+        const char* pszSRSName = WFS_ExprGetSRSName( poExpr, 4, psOptions, oSRS );
+        int bAxisSwap = FALSE;
+
+        osFilter += "<gml:Envelope";
+        if( pszSRSName )
         {
-            if (prevCh == '<' || prevCh == '>' || prevCh == '!' || prevCh == '=')
+            osFilter += " srsName=\"";
+            osFilter += pszSRSName;
+            osFilter += "\"";
+            if( oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting() )
+                bAxisSwap = TRUE;
+        }
+        osFilter += ">";
+        osFilter += "<gml:lowerCorner>";
+        if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 1 : 0]))
+            return FALSE;
+        osFilter += " ";
+        if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 0 : 1]))
+            return FALSE;
+        osFilter += "</gml:lowerCorner>";
+        osFilter += "<gml:upperCorner>";
+        if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 3 : 2]))
+            return FALSE;
+        osFilter += " ";
+        if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[(bAxisSwap) ? 2 : 3]))
+            return FALSE;
+        osFilter += "</gml:upperCorner>";
+        osFilter += "</gml:Envelope>";
+        return TRUE;
+    }
+
+    if( poExpr->nOperation == SWQ_CUSTOM_FUNC &&
+        EQUAL(poExpr->string_value, "ST_GeomFromText") )
+    {
+        OGRSpatialReference oSRS;
+        const char* pszSRSName = WFS_ExprGetSRSName( poExpr, 1, psOptions, oSRS );
+        OGRGeometry* poGeom = NULL;
+        char* pszWKT = (char*)poExpr->papoSubExpr[0]->string_value;
+        OGRGeometryFactory::createFromWkt(&pszWKT, NULL, &poGeom);
+        char** papszOptions = NULL;
+        papszOptions = CSLSetNameValue(papszOptions, "FORMAT", "GML3");
+        if( pszSRSName != NULL )
+        {
+            if( oSRS.EPSGTreatsAsLatLong() || oSRS.EPSGTreatsAsNorthingEasting() )
             {
-                if (osToken.size())
-                    papszTokens = CSLAddString(papszTokens, osToken.c_str());
-                osToken = "";
+                OGR_SRSNode *poGEOGCS = oSRS.GetAttrNode( "GEOGCS" );
+                if( poGEOGCS != NULL )
+                    poGEOGCS->StripNodes( "AXIS" );
+
+                OGR_SRSNode *poPROJCS = oSRS.GetAttrNode( "PROJCS" );
+                if (poPROJCS != NULL && oSRS.EPSGTreatsAsNorthingEasting())
+                    poPROJCS->StripNodes( "AXIS" );
             }
-            osToken += ch;
-        }
 
-        bLastCharWasSep = (ch == ' ');
+            if( EQUALN(pszSRSName, "urn:ogc:def:crs:EPSG::", strlen("urn:ogc:def:crs:EPSG::")) )
+                papszOptions = CSLSetNameValue(papszOptions, "GML3_LONGSRS", "YES");
+            else
+                papszOptions = CSLSetNameValue(papszOptions, "GML3_LONGSRS", "NO");
 
-        prevCh = ch;
-        pszIter ++;
+            poGeom->assignSpatialReference(&oSRS);
+        }
+        papszOptions = CSLSetNameValue(papszOptions, "GMLID",
+                                       CPLSPrintf("id%d", psOptions->nUniqueGeomGMLId ++));
+        char* pszGML = OGR_G_ExportToGMLEx( (OGRGeometryH)poGeom, papszOptions );
+        osFilter += pszGML;
+        CSLDestroy(papszOptions);
+        delete poGeom;
+        CPLFree(pszGML);
+        return TRUE;
     }
-    if (osToken.size())
-        papszTokens = CSLAddString(papszTokens, osToken.c_str());
 
-    if (bInQuote)
+    if( poExpr->nOperation == SWQ_CUSTOM_FUNC )
     {
-        CSLDestroy(papszTokens);
-        papszTokens = NULL;
+        const char* pszName =
+            EQUAL(poExpr->string_value, "ST_Equals") ? "Equals" :
+            EQUAL(poExpr->string_value, "ST_Disjoint") ? "Disjoint" :
+            EQUAL(poExpr->string_value, "ST_Touches") ? "Touches" :
+            EQUAL(poExpr->string_value, "ST_Contains") ? "Contains" :
+            EQUAL(poExpr->string_value, "ST_Intersects") ? "Intersects" :
+            EQUAL(poExpr->string_value, "ST_Within") ? "Within" :
+            EQUAL(poExpr->string_value, "ST_Crosses") ? "Crosses" :
+            EQUAL(poExpr->string_value, "ST_Overlaps") ? "Overlaps" :
+            EQUAL(poExpr->string_value, "ST_DWithin") ? "DWithin" :
+            EQUAL(poExpr->string_value, "ST_Beyond") ? "Beyond" :
+            NULL;
+        if( pszName == NULL )
+            return FALSE;
+        osFilter += "<";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        for(int i=0;i<2;i++)
+        {
+            if( i == 1 && poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+                poExpr->papoSubExpr[1]->eNodeType == SNT_OPERATION &&
+                poExpr->papoSubExpr[1]->nOperation == SWQ_CUSTOM_FUNC &&
+                (EQUAL(poExpr->papoSubExpr[1]->string_value, "ST_GeomFromText") ||
+                 EQUAL(poExpr->papoSubExpr[1]->string_value, "ST_MakeEnvelope")) )
+            {
+                int bSameTable = psOptions->poFDefn != NULL &&
+                                ( poExpr->papoSubExpr[0]->table_name == NULL ||
+                                EQUAL(poExpr->papoSubExpr[0]->table_name, psOptions->poFDefn->GetName()) );
+                if( bSameTable )
+                {
+                    int nIndex;
+                    if( (nIndex = psOptions->poFDefn->GetGeomFieldIndex(poExpr->papoSubExpr[0]->string_value)) >= 0 )
+                    {
+                        psOptions->poSRS = psOptions->poFDefn->GetGeomFieldDefn(nIndex)->GetSpatialRef();
+                    }
+                }
+                else if( psOptions->poDS != NULL )
+                {
+                    OGRLayer* poLayer = psOptions->poDS->GetLayerByName(poExpr->papoSubExpr[0]->table_name);
+                    if( poLayer )
+                    {
+                        OGRFeatureDefn* poFDefn = poLayer->GetLayerDefn();
+                        int nIndex;
+                        if( (nIndex = poFDefn->GetGeomFieldIndex(poExpr->papoSubExpr[0]->string_value)) >= 0 )
+                        {
+                            psOptions->poSRS = poFDefn->GetGeomFieldDefn(nIndex)->GetSpatialRef();
+                        }
+                    }
+                }
+            }
+            int bRet = WFS_ExprDumpAsOGCFilter(osFilter, poExpr->papoSubExpr[i], FALSE, psOptions);
+            psOptions->poSRS = NULL;
+            if( !bRet )
+                return FALSE;
+        }
+        if( poExpr->nSubExprCount > 2 )
+        {
+            osFilter += CPLSPrintf("<%sDistance unit=\"m\">", psOptions->pszNSPrefix);
+            if (!WFS_ExprDumpRawLitteral(osFilter, poExpr->papoSubExpr[2]) )
+                return FALSE;
+            osFilter += CPLSPrintf("</%sDistance>", psOptions->pszNSPrefix);
+        }
+        osFilter += "</";
+        osFilter += psOptions->pszNSPrefix;
+        osFilter += pszName;
+        osFilter += ">";
+        return TRUE;
     }
 
-    return papszTokens;
+    return FALSE;
 }
 
 /************************************************************************/
 /*               WFS_TurnSQLFilterToOGCFilter()                         */
 /************************************************************************/
 
-CPLString WFS_TurnSQLFilterToOGCFilter( const char * pszFilter,
+CPLString WFS_TurnSQLFilterToOGCFilter( const swq_expr_node* poExpr,
+                                        OGRDataSource* poDS,
                                         OGRFeatureDefn* poFDefn,
                                         int nVersion,
                                         int bPropertyIsNotEqualToSupported,
                                         int bUseFeatureId,
                                         int bGmlObjectIdNeedsGMLPrefix,
+                                        const char* pszNSPrefix,
                                         int* pbOutNeedsNullCheck )
 {
-    char** papszTokens = WFS_ExprTokenize(pszFilter);
-
-    if (papszTokens == NULL)
-        return "";
-
-    char** papszTokens2 = papszTokens;
-
-    ExprBuildContext sBuildContext;
-    sBuildContext.bExpectVarName = TRUE;
-    sBuildContext.bExpectComparisonOperator = FALSE;
-    sBuildContext.bExpectLogicalOperator = FALSE;
-    sBuildContext.bExpectValue = FALSE;
-    sBuildContext.nParenthesisLevel = 0;
-    Expr* expr = WFS_ExprBuildInternal(&papszTokens2, &sBuildContext);
-    CSLDestroy(papszTokens);
-
-    if (expr == NULL)
-        return "";
-
     CPLString osFilter;
     /* If the filter is only made of querying one or several gml_id */
     /* (with OR operator), we turn this to <GmlObjectId> list */
-    if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, expr, bUseFeatureId,
+    if (!WFS_ExprDumpGmlObjectIdFilter(osFilter, poExpr, bUseFeatureId,
                                        bGmlObjectIdNeedsGMLPrefix, nVersion))
     {
         ExprDumpFilterOptions sOptions;
         sOptions.nVersion = nVersion;
         sOptions.bPropertyIsNotEqualToSupported = bPropertyIsNotEqualToSupported;
         sOptions.bOutNeedsNullCheck = FALSE;
+        sOptions.poDS = poDS;
         sOptions.poFDefn = poFDefn;
+        sOptions.nUniqueGeomGMLId = 1;
+        sOptions.poSRS = NULL;
+        sOptions.pszNSPrefix = pszNSPrefix;
         osFilter = "";
-        if (!WFS_ExprDumpAsOGCFilter(osFilter, expr, TRUE, &sOptions))
+        if (!WFS_ExprDumpAsOGCFilter(osFilter, poExpr, TRUE, &sOptions))
             osFilter = "";
+        /*else
+            CPLDebug("WFS", "Filter %s", osFilter.c_str());*/
         *pbOutNeedsNullCheck = sOptions.bOutNeedsNullCheck;
     }
 
-    WFS_ExprFree(expr);
-
     return osFilter;
 }
+
+/************************************************************************/
+/*                  OGRWFSSpatialBooleanPredicateChecker()              */
+/************************************************************************/
+
+static swq_field_type OGRWFSSpatialBooleanPredicateChecker( swq_expr_node *op,
+                                               CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
+{
+    if( op->nSubExprCount != 2 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong number of arguments for %s",
+                 op->string_value);
+        return SWQ_ERROR;
+    }
+    for(int i=0;i<op->nSubExprCount;i++)
+    {
+        if( op->papoSubExpr[i]->field_type != SWQ_GEOMETRY )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                     i+1, op->string_value);
+            return SWQ_ERROR;
+        }
+    }
+    return SWQ_BOOLEAN;
+}
+
+/************************************************************************/
+/*                           OGRWFSCheckSRIDArg()                       */
+/************************************************************************/
+
+static int OGRWFSCheckSRIDArg( swq_expr_node *op, int iSubArgIndex ) 
+{
+    if( op->papoSubExpr[iSubArgIndex]->field_type == SWQ_INTEGER )
+    {
+        OGRSpatialReference oSRS;
+        if( oSRS.importFromEPSGA((int)op->papoSubExpr[iSubArgIndex]->int_value) != OGRERR_NONE )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Wrong value for argument %d of %s",
+                     iSubArgIndex + 1, op->string_value);
+            return FALSE;
+        }
+    }
+    else if( op->papoSubExpr[iSubArgIndex]->field_type == SWQ_STRING )
+    {
+        OGRSpatialReference oSRS;
+        if( oSRS.SetFromUserInput(op->papoSubExpr[iSubArgIndex]->string_value) != OGRERR_NONE )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Wrong value for argument %d of %s",
+                     iSubArgIndex + 1, op->string_value);
+            return FALSE;
+        }
+    }
+    else
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                 iSubArgIndex + 1, op->string_value);
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/************************************************************************/
+/*                   OGRWFSMakeEnvelopeChecker()                        */
+/************************************************************************/
+
+static swq_field_type OGRWFSMakeEnvelopeChecker( swq_expr_node *op,
+                                                 CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
+{
+    if( op->nSubExprCount != 4 && op->nSubExprCount != 5 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong number of arguments for %s",
+                 op->string_value);
+        return SWQ_ERROR;
+    }
+    for(int i=0;i<4;i++)
+    {
+        if( op->papoSubExpr[i]->field_type != SWQ_INTEGER &&
+            op->papoSubExpr[i]->field_type != SWQ_INTEGER64 &&
+            op->papoSubExpr[i]->field_type != SWQ_FLOAT )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                     i+1, op->string_value);
+            return SWQ_ERROR;
+        }
+    }
+    if( op->nSubExprCount == 5 )
+    {
+        if( !OGRWFSCheckSRIDArg( op, 4 ) )
+            return SWQ_ERROR;
+    }
+    return SWQ_GEOMETRY;
+}
+
+/************************************************************************/
+/*                   OGRWFSGeomFromTextChecker()                        */
+/************************************************************************/
+
+static swq_field_type OGRWFSGeomFromTextChecker( swq_expr_node *op,
+                                                 CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
+{
+    if( op->nSubExprCount != 1&& op->nSubExprCount != 2 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong number of arguments for %s",
+                 op->string_value);
+        return SWQ_ERROR;
+    }
+    if( op->papoSubExpr[0]->field_type != SWQ_STRING )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                    1, op->string_value);
+        return SWQ_ERROR;
+    }
+    OGRGeometry* poGeom = NULL;
+    char* pszWKT = (char*)op->papoSubExpr[0]->string_value;
+    if( OGRGeometryFactory::createFromWkt(&pszWKT, NULL, &poGeom) != OGRERR_NONE )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong value for argument %d of %s",
+                  1, op->string_value);
+        return SWQ_ERROR;
+    }
+    delete poGeom;
+    if( op->nSubExprCount == 2 )
+    {
+        if( !OGRWFSCheckSRIDArg( op, 1 ) )
+            return SWQ_ERROR;
+    }
+    return SWQ_GEOMETRY;
+}
+
+/************************************************************************/
+/*                      OGRWFSDWithinBeyondChecker()                    */
+/************************************************************************/
+
+static swq_field_type OGRWFSDWithinBeyondChecker( swq_expr_node *op,
+                            CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
+{
+    if( op->nSubExprCount != 3 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong number of arguments for %s",
+                 op->string_value);
+        return SWQ_ERROR;
+    }
+    for(int i=0;i<2;i++)
+    {
+        if( op->papoSubExpr[i]->field_type != SWQ_GEOMETRY )
+        {
+            CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                     i+1, op->string_value);
+            return SWQ_ERROR;
+        }
+    }
+    if( op->papoSubExpr[2]->field_type != SWQ_INTEGER &&
+        op->papoSubExpr[2]->field_type != SWQ_INTEGER64 &&
+        op->papoSubExpr[2]->field_type != SWQ_FLOAT )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for argument %d of %s",
+                    2+1, op->string_value);
+        return SWQ_ERROR;
+    }
+    return SWQ_BOOLEAN;
+}
+
+/************************************************************************/
+/*                   OGRWFSCustomFuncRegistrar                          */
+/************************************************************************/
+
+class OGRWFSCustomFuncRegistrar: public swq_custom_func_registrar
+{
+    public:
+        OGRWFSCustomFuncRegistrar() {};
+        virtual const swq_operation *GetOperator( const char * ) ;
+};
+
+/************************************************************************/
+/*                  WFSGetCustomFuncRegistrar()                         */
+/************************************************************************/
+
+swq_custom_func_registrar* WFSGetCustomFuncRegistrar()
+{
+    static OGRWFSCustomFuncRegistrar obj;
+    return &obj;
+}
+
+/************************************************************************/
+/*                           GetOperator()                              */
+/************************************************************************/
+
+static const swq_operation OGRWFSSpatialOps[] = {
+{ "ST_Equals", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_Disjoint", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_Touches", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_Contains", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+/*{ "ST_Covers", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },*/
+{ "ST_Intersects", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_Within", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+/*{ "ST_CoveredBy", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },*/
+{ "ST_Crosses", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_Overlaps", SWQ_CUSTOM_FUNC, NULL, OGRWFSSpatialBooleanPredicateChecker },
+{ "ST_DWithin", SWQ_CUSTOM_FUNC, NULL, OGRWFSDWithinBeyondChecker },
+{ "ST_Beyond", SWQ_CUSTOM_FUNC, NULL, OGRWFSDWithinBeyondChecker },
+{ "ST_MakeEnvelope", SWQ_CUSTOM_FUNC, NULL, OGRWFSMakeEnvelopeChecker },
+{ "ST_GeomFromText", SWQ_CUSTOM_FUNC, NULL, OGRWFSGeomFromTextChecker }
+};
+
+const swq_operation *OGRWFSCustomFuncRegistrar::GetOperator( const char * pszName )
+{
+    for(int i=0; i< (int)(sizeof(OGRWFSSpatialOps)/sizeof(OGRWFSSpatialOps[0]));i++)
+    {
+        if( EQUAL(OGRWFSSpatialOps[i].pszName, pszName) )
+            return &OGRWFSSpatialOps[i];
+    }
+    return NULL;
+}
diff --git a/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp b/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp
new file mode 100644
index 0000000..3c655ec
--- /dev/null
+++ b/ogr/ogrsf_frmts/wfs/ogrwfsjoinlayer.cpp
@@ -0,0 +1,801 @@
+/******************************************************************************
+ * $Id: ogrwfsjoinlayer.cpp 29064 2015-04-30 08:04:34Z rouault $
+ *
+ * Project:  WFS Translator
+ * Purpose:  Implements OGRWFSJoinLayer class.
+ * Author:   Even Rouault, <even dot rouault at spatialys dot com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
+ *
+ * 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.
+ ****************************************************************************/
+
+#include "ogr_wfs.h"
+#include "../../frmts/wms/md5.h"
+
+CPL_CVSID("$Id: ogrwfsjoinlayer.cpp 29064 2015-04-30 08:04:34Z rouault $");
+
+/************************************************************************/
+/*                          OGRWFSJoinLayer()                           */
+/************************************************************************/
+
+OGRWFSJoinLayer::OGRWFSJoinLayer(OGRWFSDataSource* poDS,
+                                 const swq_select* psSelectInfo,
+                                 const CPLString& osGlobalFilter)
+{
+    this->poDS = poDS;
+    this->osGlobalFilter = osGlobalFilter;
+    poFeatureDefn = NULL;
+    bPagingActive = FALSE;
+    nPagingStartIndex = 0;
+    nFeatureRead = 0;
+    nFeatureCountRequested = 0;
+    poBaseDS = NULL;
+    poBaseLayer = NULL;
+    bReloadNeeded = FALSE;
+    bHasFetched = FALSE;
+    bDistinct = (psSelectInfo->query_mode == SWQM_DISTINCT_LIST);
+
+    CPLString osName("join_");
+    CPLString osLayerName;
+    osLayerName = psSelectInfo->table_defs[0].table_name;
+    apoLayers.push_back((OGRWFSLayer*)poDS->GetLayerByName(osLayerName));
+    osName += osLayerName;
+    for(int i=0;i<psSelectInfo->join_count;i++)
+    {
+        osName += "_";
+        osLayerName = psSelectInfo->table_defs[
+                        psSelectInfo->join_defs[i].secondary_table].table_name;
+        apoLayers.push_back((OGRWFSLayer*)poDS->GetLayerByName(osLayerName));
+        osName += osLayerName;
+    }
+    
+    osFeatureTypes = "(";
+    for(int i=0;i<(int)apoLayers.size();i++)
+    {
+        if( i > 0 )
+            osFeatureTypes += ",";
+        osFeatureTypes += apoLayers[i]->GetName();
+    }
+    osFeatureTypes += ")";
+
+    SetDescription(osName);
+
+    poFeatureDefn = new OGRFeatureDefn(GetDescription());
+    poFeatureDefn->Reference();
+    poFeatureDefn->SetGeomType(wkbNone);
+
+    for( int i = 0; i < psSelectInfo->result_columns; i++ )
+    {
+        swq_col_def *def = psSelectInfo->column_defs + i;
+        int table_index;
+        if( def->table_index >= 0 )
+            table_index = def->table_index;
+        else
+        {
+            CPLAssert(def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST);
+            table_index = def->expr->papoSubExpr[0]->table_index;
+        }
+        OGRWFSLayer* poLayer = apoLayers[table_index];
+        const char* pszTableAlias = psSelectInfo->table_defs[table_index].table_alias;
+        const char* pszTablePrefix = pszTableAlias ? pszTableAlias : poLayer->GetShortName();
+        int idx = poLayer->GetLayerDefn()->GetFieldIndex(def->field_name);
+        if( idx >= 0 )
+        {
+            OGRFieldDefn oFieldDefn(poLayer->GetLayerDefn()->GetFieldDefn(idx));
+            const char* pszSrcFieldname = CPLSPrintf("%s.%s",
+                                                     poLayer->GetShortName(),
+                                                     oFieldDefn.GetNameRef());
+            const char* pszFieldname = CPLSPrintf("%s.%s",
+                                                     pszTablePrefix,
+                                                     oFieldDefn.GetNameRef());
+            aoSrcFieldNames.push_back(pszSrcFieldname);
+            oFieldDefn.SetName(def->field_alias ? def->field_alias : pszFieldname);
+            if( def->expr && def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST)
+            {
+                switch( def->field_type )
+                {
+                    case SWQ_INTEGER: oFieldDefn.SetType(OFTInteger); break;
+                    case SWQ_INTEGER64: oFieldDefn.SetType(OFTInteger64); break;
+                    case SWQ_FLOAT: oFieldDefn.SetType(OFTReal); break;
+                    case SWQ_STRING: oFieldDefn.SetType(OFTString); break;
+                    case SWQ_BOOLEAN: oFieldDefn.SetType(OFTInteger); oFieldDefn.SetSubType(OFSTBoolean); break;
+                    case SWQ_DATE: oFieldDefn.SetType(OFTDate); break;
+                    case SWQ_TIME: oFieldDefn.SetType(OFTTime); break;
+                    case SWQ_TIMESTAMP: oFieldDefn.SetType(OFTDateTime); break;
+                    default: break;
+                }
+            }
+            poFeatureDefn->AddFieldDefn(&oFieldDefn);
+        }
+        else
+        {
+            idx = poLayer->GetLayerDefn()->GetGeomFieldIndex(def->field_name);
+            if (idx >= 0 )
+            {
+                OGRGeomFieldDefn oFieldDefn(poLayer->GetLayerDefn()->GetGeomFieldDefn(idx));
+                const char* pszSrcFieldname = CPLSPrintf("%s.%s",
+                                                     poLayer->GetShortName(),
+                                                     oFieldDefn.GetNameRef());
+                const char* pszFieldname = CPLSPrintf("%s.%s",
+                                                     pszTablePrefix,
+                                                     oFieldDefn.GetNameRef());
+                aoSrcGeomFieldNames.push_back(pszSrcFieldname);
+                oFieldDefn.SetName(def->field_alias ? def->field_alias : pszFieldname);
+                poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
+            }
+        }
+    }
+
+    for(int i=0;i<psSelectInfo->order_specs;i++)
+    {
+        int nFieldIndex = apoLayers[0]->GetLayerDefn()->GetFieldIndex(
+                                psSelectInfo->order_defs[i].field_name);
+        if (nFieldIndex < 0)
+            break;
+
+        /* Make sure to have the right case */
+        const char* pszFieldName = apoLayers[0]->GetLayerDefn()->
+            GetFieldDefn(nFieldIndex)->GetNameRef();
+        if( osSortBy.size() )
+            osSortBy += ",";
+        osSortBy += pszFieldName;
+        if( !psSelectInfo->order_defs[i].ascending_flag )
+            osSortBy += " DESC";
+    }
+
+    CPLXMLNode* psGlobalSchema = CPLCreateXMLNode( NULL, CXT_Element, "Schema" );
+    for(int i=0;i<(int)apoLayers.size();i++)
+    {
+        CPLString osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", apoLayers[i]);
+        CPLPushErrorHandler(CPLQuietErrorHandler);
+        CPLXMLNode* psSchema = CPLParseXMLFile(osTmpFileName);
+        CPLPopErrorHandler();
+        if( psSchema == NULL )
+        {
+            CPLDestroyXMLNode(psGlobalSchema);
+            psGlobalSchema = NULL;
+            break;
+        }
+        CPLXMLNode* psIter;
+        for(psIter = psSchema->psChild; psIter != NULL; psIter = psIter->psNext )
+        {
+            if( psIter->eType == CXT_Element )
+                break;
+        }
+        CPLAddXMLChild(psGlobalSchema, CPLCloneXMLTree(psIter));
+        CPLDestroyXMLNode(psSchema);
+    }
+    if( psGlobalSchema )
+    {
+        CPLString osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
+        CPLSerializeXMLTreeToFile(psGlobalSchema, osTmpFileName);
+        CPLDestroyXMLNode(psGlobalSchema);
+    }
+}
+
+/************************************************************************/
+/*                          ~OGRWFSJoinLayer()                          */
+/************************************************************************/
+
+OGRWFSJoinLayer::~OGRWFSJoinLayer()
+{
+    if( poFeatureDefn != NULL )
+        poFeatureDefn->Release();
+    if( poBaseDS != NULL )
+        GDALClose(poBaseDS);
+
+    CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
+    OGRWFSRecursiveUnlink(osTmpDirName);
+}
+
+/************************************************************************/
+/*                    OGRWFSRemoveReferenceToTableAlias()               */
+/************************************************************************/
+
+static void OGRWFSRemoveReferenceToTableAlias(swq_expr_node* poNode,
+                                              const swq_select* psSelectInfo)
+{
+    if( poNode->eNodeType == SNT_COLUMN )
+    {
+        if( poNode->table_name != NULL )
+        {
+            for(int i=0;i < psSelectInfo->table_count;i++)
+            {
+                if( psSelectInfo->table_defs[i].table_alias != NULL &&
+                    EQUAL(poNode->table_name, psSelectInfo->table_defs[i].table_alias) )
+                {
+                    CPLFree(poNode->table_name);
+                    poNode->table_name = CPLStrdup(psSelectInfo->table_defs[i].table_name);
+                    break;
+                }
+            }
+        }
+    }
+    else if( poNode->eNodeType == SNT_OPERATION )
+    {
+        for(int i=0;i < poNode->nSubExprCount;i++)
+            OGRWFSRemoveReferenceToTableAlias(poNode->papoSubExpr[i],
+                                              psSelectInfo);
+    }
+}
+
+/************************************************************************/
+/*                             Build()                                  */
+/************************************************************************/
+
+OGRWFSJoinLayer* OGRWFSJoinLayer::Build(OGRWFSDataSource* poDS,
+                                        const swq_select* psSelectInfo)
+{
+    CPLString osGlobalFilter;
+    
+    for( int i = 0; i < psSelectInfo->result_columns; i++ )
+    {
+        swq_col_def *def = psSelectInfo->column_defs + i;
+        if( !(def->col_func == SWQCF_NONE &&
+              (def->expr == NULL ||
+               def->expr->eNodeType == SNT_COLUMN ||
+               (def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST))) )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Only column names supported in column selection");
+            return NULL;
+        }
+    }
+
+    if( psSelectInfo->join_count > 1 || psSelectInfo->where_expr != NULL )
+        osGlobalFilter += "<And>";
+    for(int i=0;i<psSelectInfo->join_count;i++)
+    {
+        OGRWFSRemoveReferenceToTableAlias(psSelectInfo->join_defs[i].poExpr,
+                                          psSelectInfo);
+        int bOutNeedsNullCheck;
+        CPLString osFilter = WFS_TurnSQLFilterToOGCFilter(
+                                      psSelectInfo->join_defs[i].poExpr,
+                                      poDS,
+                                      NULL,
+                                      200,
+                                      TRUE, /* bPropertyIsNotEqualToSupported */
+                                      FALSE, /* bUseFeatureId */
+                                      FALSE, /* bGmlObjectIdNeedsGMLPrefix */
+                                      "",
+                                      &bOutNeedsNullCheck);
+        if( osFilter.size() == 0 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Unsupported JOIN clause");
+            return NULL;
+        }
+        osGlobalFilter += osFilter;
+    }
+    if( psSelectInfo->where_expr != NULL )
+    {
+        OGRWFSRemoveReferenceToTableAlias(psSelectInfo->where_expr,
+                                          psSelectInfo);
+        int bOutNeedsNullCheck;
+        CPLString osFilter = WFS_TurnSQLFilterToOGCFilter(
+                                      psSelectInfo->where_expr,
+                                      poDS,
+                                      NULL,
+                                      200,
+                                      TRUE, /* bPropertyIsNotEqualToSupported */
+                                      FALSE, /* bUseFeatureId */
+                                      FALSE, /* bGmlObjectIdNeedsGMLPrefix */
+                                      "",
+                                      &bOutNeedsNullCheck);
+        if( osFilter.size() == 0 )
+        {
+            CPLError(CE_Failure, CPLE_NotSupported,
+                     "Unsupported WHERE clause");
+            return NULL;
+        }
+        osGlobalFilter += osFilter;
+    }
+    if( psSelectInfo->join_count > 1 || psSelectInfo->where_expr != NULL )
+        osGlobalFilter += "</And>";
+    CPLDebug("WFS", "osGlobalFilter = %s", osGlobalFilter.c_str());
+
+    OGRWFSJoinLayer* poLayer = new OGRWFSJoinLayer(poDS, psSelectInfo,
+                                                   osGlobalFilter);
+    return poLayer;
+}
+
+/************************************************************************/
+/*                            ResetReading()                            */
+/************************************************************************/
+
+void OGRWFSJoinLayer::ResetReading()
+{
+    if (bPagingActive)
+        bReloadNeeded = TRUE;
+    nPagingStartIndex = 0;
+    nFeatureRead = 0;
+    nFeatureCountRequested = 0;
+    if (bReloadNeeded)
+    {
+        GDALClose(poBaseDS);
+        poBaseDS = NULL;
+        poBaseLayer = NULL;
+        bHasFetched = FALSE;
+        bReloadNeeded = FALSE;
+    }
+    if (poBaseLayer)
+        poBaseLayer->ResetReading();
+    aoSetMD5.clear();
+}
+
+/************************************************************************/
+/*                       MakeGetFeatureURL()                            */
+/************************************************************************/
+
+CPLString OGRWFSJoinLayer::MakeGetFeatureURL(int bRequestHits)
+{
+    CPLString osURL(poDS->GetBaseURL());
+    osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
+    osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
+    osURL = CPLURLAddKVP(osURL, "REQUEST", "GetFeature");
+    osURL = CPLURLAddKVP(osURL, "TYPENAMES", WFS_EscapeURL(osFeatureTypes));
+
+    int nRequestMaxFeatures = 0;
+    if (poDS->IsPagingAllowed() && !bRequestHits &&
+        CPLURLGetValue(osURL, "COUNT").size() == 0 )
+    {
+        osURL = CPLURLAddKVP(osURL, "STARTINDEX",
+            CPLSPrintf("%d", nPagingStartIndex +
+                                poDS->GetBaseStartIndex()));
+        nRequestMaxFeatures = poDS->GetPageSize();
+        nFeatureCountRequested = nRequestMaxFeatures;
+        bPagingActive = TRUE;
+    }
+
+    if (nRequestMaxFeatures)
+    {
+        osURL = CPLURLAddKVP(osURL,
+                             "COUNT",
+                             CPLSPrintf("%d", nRequestMaxFeatures));
+    }
+
+    CPLString osFilter;
+    osFilter = "<Filter xmlns=\"http://www.opengis.net/fes/2.0\"";
+    
+    std::map<CPLString, CPLString> oMapNS;
+    for(int i=0;i<(int)apoLayers.size();i++)
+    {
+        const char* pszNS = apoLayers[i]->GetNamespacePrefix();
+        const char* pszNSVal = apoLayers[i]->GetNamespaceName();
+        if( pszNS && pszNSVal )
+            oMapNS[pszNS] = pszNSVal;
+    }
+    std::map<CPLString, CPLString>::iterator oIter = oMapNS.begin();
+    for(; oIter != oMapNS.end(); ++oIter )
+    {
+        osFilter += " xmlns:";
+        osFilter += oIter->first;
+        osFilter += "=\"";
+        osFilter += oIter->second;
+        osFilter += "\"";
+    }
+    osFilter += " xmlns:gml=\"http://www.opengis.net/gml/3.2\">";
+    osFilter += osGlobalFilter;
+    osFilter += "</Filter>";
+
+    osURL = CPLURLAddKVP(osURL, "FILTER", WFS_EscapeURL(osFilter));
+
+    if (bRequestHits)
+    {
+        osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
+    }
+    else if( osSortBy.size() )
+    {
+        osURL = CPLURLAddKVP(osURL, "SORTBY", WFS_EscapeURL(osSortBy));
+    }
+
+    return osURL;
+}
+
+/************************************************************************/
+/*                         FetchGetFeature()                            */
+/************************************************************************/
+
+GDALDataset* OGRWFSJoinLayer::FetchGetFeature()
+{
+
+    CPLString osURL = MakeGetFeatureURL();
+    CPLDebug("WFS", "%s", osURL.c_str());
+
+    CPLHTTPResult* psResult = NULL;
+
+    /* Try streaming when the output format is GML and that we have a .xsd */
+    /* that we are able to understand */
+    CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
+    VSIStatBufL sBuf;
+    if (CSLTestBoolean(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) &&
+        VSIStatL(osXSDFileName, &sBuf) == 0 && GDALGetDriverByName("GML") != NULL)
+    {
+        const char* pszStreamingName = CPLSPrintf("/vsicurl_streaming/%s",
+                                                    osURL.c_str());
+        if( strncmp(osURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
+            CSLTestBoolean(CPLGetConfigOption("CPL_CURL_ENABLE_VSIMEM", "FALSE")) )
+        {
+            pszStreamingName = osURL.c_str();
+        }
+
+        const char* const apszAllowedDrivers[] = { "GML", NULL };
+        const char* apszOpenOptions[2] = { NULL, NULL };
+        apszOpenOptions[0] = CPLSPrintf("XSD=%s", osXSDFileName.c_str());
+        GDALDataset* poGML_DS = (GDALDataset*)
+                GDALOpenEx(pszStreamingName, GDAL_OF_VECTOR, apszAllowedDrivers,
+                           apszOpenOptions, NULL);
+        if (poGML_DS)
+        {
+            //bStreamingDS = TRUE;
+            return poGML_DS;
+        }
+
+        /* In case of failure, read directly the content to examine */
+        /* it, if it is XML error content */
+        char szBuffer[2048];
+        int nRead = 0;
+        VSILFILE* fp = VSIFOpenL(pszStreamingName, "rb");
+        if (fp)
+        {
+            nRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
+            szBuffer[nRead] = '\0';
+            VSIFCloseL(fp);
+        }
+
+        if (nRead != 0)
+        {
+            if (strstr(szBuffer, "<ServiceExceptionReport") != NULL ||
+                strstr(szBuffer, "<ows:ExceptionReport") != NULL)
+            {
+                CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
+                            szBuffer);
+                return NULL;
+            }
+        }
+    }
+
+    //bStreamingDS = FALSE;
+    psResult = poDS->HTTPFetch( osURL, NULL);
+    if (psResult == NULL)
+    {
+        return NULL;
+    }
+
+    CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
+    VSIMkdir(osTmpDirName, 0);
+
+    GByte *pabyData = psResult->pabyData;
+    int    nDataLen = psResult->nDataLen;
+
+    if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
+        strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
+                 pabyData);
+        CPLHTTPDestroyResult(psResult);
+        return NULL;
+    }
+
+    CPLString osTmpFileName;
+
+    osTmpFileName = osTmpDirName + "/file.gfs";
+    VSIUnlink(osTmpFileName);
+
+    osTmpFileName = osTmpDirName + "/file.gml";
+
+    VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
+                                    nDataLen, TRUE);
+    VSIFCloseL(fp);
+    psResult->pabyData = NULL;
+
+    CPLHTTPDestroyResult(psResult);
+
+    OGRDataSource* poDS;
+
+    poDS = (OGRDataSource*) OGROpen(osTmpFileName, FALSE, NULL);
+    if (poDS == NULL)
+    {
+        if( strstr((const char*)pabyData, "<wfs:FeatureCollection") == NULL &&
+            strstr((const char*)pabyData, "<gml:FeatureCollection") == NULL)
+        {
+            if (nDataLen > 1000)
+                pabyData[1000] = 0;
+            CPLError(CE_Failure, CPLE_AppDefined,
+                    "Error: cannot parse %s", pabyData);
+        }
+        return NULL;
+    }
+
+    OGRLayer* poLayer = poDS->GetLayer(0);
+    if (poLayer == NULL)
+    {
+        OGRDataSource::DestroyDataSource(poDS);
+        return NULL;
+    }
+
+    return poDS;
+}
+
+/************************************************************************/
+/*                           GetNextFeature()                           */
+/************************************************************************/
+
+OGRFeature* OGRWFSJoinLayer::GetNextFeature()
+{
+    while(TRUE)
+    {
+        if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
+        {
+            bReloadNeeded = TRUE;
+            nPagingStartIndex = nFeatureRead;
+        }
+        if (bReloadNeeded)
+        {
+            GDALClose(poBaseDS);
+            poBaseDS = NULL;
+            poBaseLayer = NULL;
+            bHasFetched = FALSE;
+            bReloadNeeded = FALSE;
+        }
+        if (poBaseDS == NULL && !bHasFetched)
+        {
+            bHasFetched = TRUE;
+            poBaseDS = FetchGetFeature();
+            if (poBaseDS)
+            {
+                poBaseLayer = poBaseDS->GetLayer(0);
+                poBaseLayer->ResetReading();
+            }
+        }
+        if (!poBaseLayer)
+            return NULL;
+
+        OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
+        if (poSrcFeature == NULL)
+            return NULL;
+        nFeatureRead ++;
+
+        OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
+
+        struct cvs_MD5Context sMD5Context;
+        if( bDistinct )
+            cvs_MD5Init(&sMD5Context);
+
+        for(int i=0;i<(int)aoSrcFieldNames.size();i++)
+        {
+            int iSrcField = poSrcFeature->GetFieldIndex(aoSrcFieldNames[i]);
+            if( iSrcField >= 0 && poSrcFeature->IsFieldSet(iSrcField) )
+            {
+                OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
+                if( eType == poSrcFeature->GetFieldDefnRef(iSrcField)->GetType() )
+                {
+                    poNewFeature->SetField(i, poSrcFeature->GetRawFieldRef(iSrcField));
+                }
+                else if( eType == OFTString )
+                    poNewFeature->SetField(i, poSrcFeature->GetFieldAsString(iSrcField));
+                else if( eType == OFTInteger )
+                    poNewFeature->SetField(i, poSrcFeature->GetFieldAsInteger(iSrcField));
+                else if( eType == OFTInteger64 )
+                    poNewFeature->SetField(i, poSrcFeature->GetFieldAsInteger64(iSrcField));
+                else if( eType == OFTReal )
+                    poNewFeature->SetField(i, poSrcFeature->GetFieldAsDouble(iSrcField));
+                else
+                    poNewFeature->SetField(i, poSrcFeature->GetFieldAsString(iSrcField));
+                if( bDistinct )
+                {
+                    if( eType == OFTInteger )
+                    {
+                        int nVal = poNewFeature->GetFieldAsInteger(i);
+                        cvs_MD5Update( &sMD5Context, (const GByte*)&nVal, sizeof(nVal));
+                    }
+                    else if( eType == OFTInteger64 )
+                    {
+                        GIntBig nVal = poNewFeature->GetFieldAsInteger64(i);
+                        cvs_MD5Update( &sMD5Context, (const GByte*)&nVal, sizeof(nVal));
+                    }
+                    else if( eType == OFTReal )
+                    {
+                        double dfVal = poNewFeature->GetFieldAsDouble(i);
+                        cvs_MD5Update( &sMD5Context, (const GByte*)&dfVal, sizeof(dfVal));
+                    }
+                    else
+                    {
+                        const char* pszStr = poNewFeature->GetFieldAsString(i);
+                        cvs_MD5Update( &sMD5Context, (const GByte*)pszStr, strlen(pszStr));
+                    }
+                }
+            }
+        }
+        for(int i=0;i<(int)aoSrcGeomFieldNames.size();i++)
+        {
+            int iSrcField = poSrcFeature->GetGeomFieldIndex(aoSrcGeomFieldNames[i]);
+            if( iSrcField >= 0)
+            {
+                OGRGeometry* poGeom = poSrcFeature->StealGeometry(iSrcField);
+                if( poGeom )
+                {
+                    poGeom->assignSpatialReference(poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef());
+                    poNewFeature->SetGeomFieldDirectly(i, poGeom);
+
+                    if( bDistinct )
+                    {
+                        int nSize = poGeom->WkbSize();
+                        GByte* pabyGeom = (GByte*)CPLMalloc(nSize);
+                        poGeom->exportToWkb(wkbNDR, pabyGeom);
+                        cvs_MD5Update( &sMD5Context, (const GByte*)pabyGeom, nSize);
+                        CPLFree(pabyGeom);
+                    }
+                }
+            }
+        }
+
+        poNewFeature->SetFID(nFeatureRead);
+        delete poSrcFeature;
+
+        if( bDistinct )
+        {
+            CPLString osDigest = "0123456789abcdef";
+            cvs_MD5Final((unsigned char*)osDigest.c_str(), &sMD5Context);
+            if( aoSetMD5.find(osDigest) == aoSetMD5.end() )
+            {
+                aoSetMD5.insert(osDigest);
+                return poNewFeature;
+            }
+            else
+                delete poNewFeature;
+        }
+        else
+            return poNewFeature;
+    }
+}
+
+/************************************************************************/
+/*                  ExecuteGetFeatureResultTypeHits()                   */
+/************************************************************************/
+
+GIntBig OGRWFSJoinLayer::ExecuteGetFeatureResultTypeHits()
+{
+    char* pabyData = NULL;
+    CPLString osURL = MakeGetFeatureURL(TRUE);
+    CPLDebug("WFS", "%s", osURL.c_str());
+
+    CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
+    if (psResult == NULL)
+    {
+        return -1;
+    }
+
+    pabyData = (char*) psResult->pabyData;
+    psResult->pabyData = NULL;
+
+    if (strstr(pabyData, "<ServiceExceptionReport") != NULL ||
+        strstr(pabyData, "<ows:ExceptionReport") != NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
+                 pabyData);
+        CPLHTTPDestroyResult(psResult);
+        CPLFree(pabyData);
+        return -1;
+    }
+
+    CPLXMLNode* psXML = CPLParseXMLString( pabyData );
+    if (psXML == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
+                pabyData);
+        CPLHTTPDestroyResult(psResult);
+        CPLFree(pabyData);
+        return -1;
+    }
+
+    CPLStripXMLNamespace( psXML, NULL, TRUE );
+    CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=FeatureCollection" );
+    if (psRoot == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <FeatureCollection>");
+        CPLDestroyXMLNode( psXML );
+        CPLHTTPDestroyResult(psResult);
+        CPLFree(pabyData);
+        return -1;
+    }
+
+    const char* pszValue = CPLGetXMLValue(psRoot, "numberMatched", NULL); /* WFS 2.0.0 */
+    if (pszValue == NULL)
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "Cannot find numberMatched");
+        CPLDestroyXMLNode( psXML );
+        CPLHTTPDestroyResult(psResult);
+        CPLFree(pabyData);
+        return -1;
+    }
+
+    GIntBig nFeatures = CPLAtoGIntBig(pszValue);
+
+    CPLDestroyXMLNode( psXML );
+    CPLHTTPDestroyResult(psResult);
+    CPLFree(pabyData);
+
+    return nFeatures;
+}
+
+/************************************************************************/
+/*                           GetFeatureCount()                          */
+/************************************************************************/
+
+GIntBig OGRWFSJoinLayer::GetFeatureCount( int bForce )
+{
+    GIntBig nFeatures;
+
+    if( !bDistinct )
+    {
+        nFeatures = ExecuteGetFeatureResultTypeHits();
+        if (nFeatures >= 0)
+            return nFeatures;
+    }
+
+    nFeatures = OGRLayer::GetFeatureCount(bForce);
+    return nFeatures;
+}
+
+/************************************************************************/
+/*                            GetLayerDefn()                            */
+/************************************************************************/
+
+OGRFeatureDefn* OGRWFSJoinLayer::GetLayerDefn()
+{
+    return poFeatureDefn;
+}
+
+/************************************************************************/
+/*                           TestCapability()                           */
+/************************************************************************/
+
+int OGRWFSJoinLayer::TestCapability( const char * )
+{
+    return FALSE;
+}
+
+/************************************************************************/
+/*                          SetSpatialFilter()                          */
+/************************************************************************/
+
+void OGRWFSJoinLayer::SetSpatialFilter( OGRGeometry * poGeom )
+{
+    if( poGeom != NULL )
+        CPLError(CE_Failure, CPLE_NotSupported,
+                "Setting a spatial filter on a layer resulting from a WFS join is unsupported");
+}
+
+/************************************************************************/
+/*                          SetAttributeFilter()                        */
+/************************************************************************/
+
+OGRErr OGRWFSJoinLayer::SetAttributeFilter( const char *pszFilter )
+{
+    if( pszFilter != NULL )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                "Setting an attribute filter on a layer resulting from a WFS join is unsupported");
+        return OGRERR_FAILURE;
+    }
+    return OGRERR_NONE;
+}
diff --git a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp
index 3426677..32a89d7 100644
--- a/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp
+++ b/ogr/ogrsf_frmts/wfs/ogrwfslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrwfslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrwfslayer.cpp 29028 2015-04-26 21:19:29Z rouault $
  *
  * Project:  WFS Translator
  * Purpose:  Implements OGRWFSLayer class.
@@ -34,14 +34,14 @@
 #include "cpl_http.h"
 #include "parsexsd.h"
 
-CPL_CVSID("$Id: ogrwfslayer.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrwfslayer.cpp 29028 2015-04-26 21:19:29Z rouault $");
 
 
 /************************************************************************/
 /*                      OGRWFSRecursiveUnlink()                         */
 /************************************************************************/
 
-static void OGRWFSRecursiveUnlink( const char *pszName )
+void OGRWFSRecursiveUnlink( const char *pszName )
 
 {
     char **papszFileList;
@@ -97,6 +97,8 @@ OGRWFSLayer::OGRWFSLayer( OGRWFSDataSource* poDS,
     this->pszNS = pszNS ? CPLStrdup(pszNS) : NULL;
     this->pszNSVal = pszNSVal ? CPLStrdup(pszNSVal) : NULL;
 
+    SetDescription( pszName );
+
     poFeatureDefn = NULL;
     poGMLFeatureClass = NULL;
     bGotApproximateLayerDefn = FALSE;
@@ -124,8 +126,6 @@ OGRWFSLayer::OGRWFSLayer( OGRWFSDataSource* poDS,
     nFeatureCountRequested = 0;
 
     pszRequiredOutputFormat = NULL;
-
-    bAscFlag = TRUE;
 }
 
 /************************************************************************/
@@ -143,7 +143,6 @@ OGRWFSLayer* OGRWFSLayer::Clone()
     poDupLayer->bGotApproximateLayerDefn = bGotApproximateLayerDefn;
     poDupLayer->eGeomType = poDupLayer->poFeatureDefn->GetGeomType();
     poDupLayer->pszRequiredOutputFormat = pszRequiredOutputFormat ? CPLStrdup(pszRequiredOutputFormat) : NULL;
-    poDupLayer->bAscFlag = bAscFlag;
 
     /* Copy existing schema file if already found */
     CPLString osSrcFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
@@ -175,7 +174,7 @@ OGRWFSLayer::~OGRWFSLayer()
     CPLFree(pszNS);
     CPLFree(pszNSVal);
 
-    OGRDataSource::DestroyDataSource(poBaseDS);
+    GDALClose(poBaseDS);
 
     delete poFetchedFilterGeom;
 
@@ -287,7 +286,8 @@ OGRFeatureDefn* OGRWFSLayer::ParseSchema(CPLXMLNode* psSchema)
     CPLSerializeXMLTreeToFile(psSchema, osTmpFileName);
 
     std::vector<GMLFeatureClass*> aosClasses;
-    int bHaveSchema = GMLParseXSD( osTmpFileName, aosClasses );
+    int bFullyUnderstood = FALSE;
+    int bHaveSchema = GMLParseXSD( osTmpFileName, aosClasses, bFullyUnderstood );
 
     if (bHaveSchema && aosClasses.size() == 1)
     {
@@ -319,14 +319,18 @@ OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poC
     this->poGMLFeatureClass = poClass;
 
     OGRFeatureDefn* poFDefn = new OGRFeatureDefn( pszName );
-    poFDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    poFDefn->SetGeomType(wkbNone);
     if( poGMLFeatureClass->GetGeometryPropertyCount() > 0 )
+    {
         poFDefn->SetGeomType( (OGRwkbGeometryType)poGMLFeatureClass->GetGeometryProperty(0)->GetType() );
+        poFDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Added attributes (properties).                                  */
 /* -------------------------------------------------------------------- */
     OGRFieldDefn oField( "gml_id", OFTString );
+    oField.SetNullable(FALSE);
     poFDefn->AddFieldDefn( &oField );
 
     for( int iField = 0; iField < poGMLFeatureClass->GetPropertyCount(); iField++ )
@@ -338,14 +342,22 @@ OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poC
             eFType = OFTString;
         else if( poProperty->GetType() == GMLPT_String )
             eFType = OFTString;
-        else if( poProperty->GetType() == GMLPT_Integer )
+        else if( poProperty->GetType() == GMLPT_Integer ||
+                 poProperty->GetType() == GMLPT_Boolean ||
+                 poProperty->GetType() == GMLPT_Short  )
             eFType = OFTInteger;
-        else if( poProperty->GetType() == GMLPT_Real )
+        else if( poProperty->GetType() == GMLPT_Integer64 )
+            eFType = OFTInteger64;
+        else if( poProperty->GetType() == GMLPT_Real ||
+                 poProperty->GetType() == GMLPT_Float )
             eFType = OFTReal;
         else if( poProperty->GetType() == GMLPT_StringList )
             eFType = OFTStringList;
-        else if( poProperty->GetType() == GMLPT_IntegerList )
+        else if( poProperty->GetType() == GMLPT_IntegerList ||
+                 poProperty->GetType() == GMLPT_BooleanList )
             eFType = OFTIntegerList;
+        else if( poProperty->GetType() == GMLPT_Integer64List )
+            eFType = OFTInteger64List;
         else if( poProperty->GetType() == GMLPT_RealList )
             eFType = OFTRealList;
         else
@@ -358,6 +370,14 @@ OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poC
             oField.SetWidth( poProperty->GetWidth() );
         if( poProperty->GetPrecision() > 0 )
             oField.SetPrecision( poProperty->GetPrecision() );
+        if( poProperty->GetType() == GMLPT_Boolean ||
+            poProperty->GetType() == GMLPT_BooleanList )
+            oField.SetSubType(OFSTBoolean);
+        else if( poProperty->GetType() == GMLPT_Short) 
+            oField.SetSubType(OFSTInt16);
+        else if( poProperty->GetType() == GMLPT_Float) 
+            oField.SetSubType(OFSTFloat32);
+        oField.SetNullable(poProperty->IsNullable());
 
         poFDefn->AddFieldDefn( &oField );
     }
@@ -369,7 +389,10 @@ OGRFeatureDefn* OGRWFSLayer::BuildLayerDefnFromFeatureClass(GMLFeatureClass* poC
         {
             osGeometryColumnName = pszGeometryColumnName;
             if( poFDefn->GetGeomFieldCount() > 0 )
+            {
+                poFDefn->GetGeomFieldDefn(0)->SetNullable(poGMLFeatureClass->GetGeometryProperty(0)->IsNullable());
                 poFDefn->GetGeomFieldDefn(0)->SetName(pszGeometryColumnName);
+            }
         }
     }
 
@@ -449,8 +472,6 @@ CPLString OGRWFSLayer::MakeGetFeatureURL(int nRequestMaxFeatures, int bRequestHi
         else
             osGeomFilter += "</PropertyName>";
 
-        CPLLocaleC  oLocaleEnforcer;
-
         if ( atoi(poDS->GetVersion()) >= 2 )
         {
             osGeomFilter += "<gml:Envelope";
@@ -545,15 +566,21 @@ CPLString OGRWFSLayer::MakeGetFeatureURL(int nRequestMaxFeatures, int bRequestHi
     {
         osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
     }
-    else if (osFieldToSort.size() != 0)
+    else if (aoSortColumns.size() != 0)
     {
-        CPLString osSortBy(osFieldToSort);
-        if (!bAscFlag)
+        CPLString osSortBy;
+        for( int i=0; i < (int)aoSortColumns.size(); i++)
         {
-            if (atoi(poDS->GetVersion()) >= 2)
-                osSortBy += " DESC";
-            else
-                osSortBy += " D";
+            if( i > 0 )
+                osSortBy += ",";
+            osSortBy += aoSortColumns[i].osColumn;
+            if( !aoSortColumns[i].bAsc )
+            {
+                if (atoi(poDS->GetVersion()) >= 2)
+                    osSortBy += " DESC";
+                else
+                    osSortBy += " D";
+            }
         }
         osURL = CPLURLAddKVP(osURL, "SORTBY", WFS_EscapeURL(osSortBy));
     }
@@ -684,7 +711,7 @@ int OGRWFSLayer::MustRetryIfNonCompliantServer(const char* pszServerAnswer)
 /*                         FetchGetFeature()                            */
 /************************************************************************/
 
-OGRDataSource* OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures)
+GDALDataset* OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures)
 {
 
     CPLString osURL = MakeGetFeatureURL(nRequestMaxFeatures, FALSE);
@@ -698,17 +725,24 @@ OGRDataSource* OGRWFSLayer::FetchGetFeature(int nRequestMaxFeatures)
     /* that we are able to understand */
     CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
     VSIStatBufL sBuf;
-    OGRSFDriverH hGMLDrv = OGRGetDriverByName("GML");
     if (CSLTestBoolean(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) &&
         (osOutputFormat.size() == 0 || osOutputFormat.ifind("GML") != std::string::npos) &&
-        VSIStatL(osXSDFileName, &sBuf) == 0 && hGMLDrv != NULL)
+        VSIStatL(osXSDFileName, &sBuf) == 0 && GDALGetDriverByName("GML") != NULL)
     {
         const char* pszStreamingName = CPLSPrintf("/vsicurl_streaming/%s",
                                                     osURL.c_str());
-        const char* pszStreamingNameWithXSD = CPLSPrintf("%s,xsd=%s",
-                                            pszStreamingName, osXSDFileName.c_str());
-        OGRDataSource* poGML_DS = (OGRDataSource*)
-                OGR_Dr_Open(hGMLDrv, pszStreamingNameWithXSD, FALSE);
+        if( strncmp(osURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
+            CSLTestBoolean(CPLGetConfigOption("CPL_CURL_ENABLE_VSIMEM", "FALSE")) )
+        {
+            pszStreamingName = osURL.c_str();
+        }
+
+        const char* const apszAllowedDrivers[] = { "GML", NULL };
+        const char* apszOpenOptions[2] = { NULL, NULL };
+        apszOpenOptions[0] = CPLSPrintf("XSD=%s", osXSDFileName.c_str());
+        GDALDataset* poGML_DS = (GDALDataset*)
+                GDALOpenEx(pszStreamingName, GDAL_OF_VECTOR, apszAllowedDrivers,
+                           apszOpenOptions, NULL);
         if (poGML_DS)
         {
             bStreamingDS = TRUE;
@@ -985,7 +1019,7 @@ OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
     poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
     poFeatureDefn->Reference();
 
-    OGRDataSource* poDS = NULL;
+    GDALDataset* poDS = NULL;
 
     if (poSrcFDefn == NULL)
         poSrcFDefn = DescribeFeatureType();
@@ -1007,6 +1041,8 @@ OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
 
     int i;
     poFeatureDefn->SetGeomType(poSrcFDefn->GetGeomType());
+    if( poSrcFDefn->GetGeomFieldCount() > 0 )
+        poFeatureDefn->GetGeomFieldDefn(0)->SetName(poSrcFDefn->GetGeomFieldDefn(0)->GetNameRef());
     for(i=0;i<poSrcFDefn->GetFieldCount();i++)
     {
         if (pszPropertyName[0] != 0)
@@ -1030,7 +1066,7 @@ OGRFeatureDefn * OGRWFSLayer::BuildLayerDefn(OGRFeatureDefn* poSrcFDefn)
     }
 
     if (poDS)
-        OGRDataSource::DestroyDataSource(poDS);
+        GDALClose(poDS);
     else
         delete poSrcFDefn;
 
@@ -1052,7 +1088,7 @@ void OGRWFSLayer::ResetReading()
     nFeatureCountRequested = 0;
     if (bReloadNeeded)
     {
-        OGRDataSource::DestroyDataSource(poBaseDS);
+        GDALClose(poBaseDS);
         poBaseDS = NULL;
         poBaseLayer = NULL;
         bHasFetched = FALSE;
@@ -1070,54 +1106,55 @@ void OGRWFSLayer::ResetReading()
 OGRFeature *OGRWFSLayer::GetNextFeature()
 {
     GetLayerDefn();
-    if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
-    {
-        bReloadNeeded = TRUE;
-        nPagingStartIndex = nFeatureRead;
-    }
-    if (bReloadNeeded)
-    {
-        OGRDataSource::DestroyDataSource(poBaseDS);
-        poBaseDS = NULL;
-        poBaseLayer = NULL;
-        bHasFetched = FALSE;
-        bReloadNeeded = FALSE;
-    }
-    if (poBaseDS == NULL && !bHasFetched)
+
+    while(TRUE)
     {
-        bHasFetched = TRUE;
-        poBaseDS = FetchGetFeature(0);
-        if (poBaseDS)
+        if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
         {
-            poBaseLayer = poBaseDS->GetLayer(0);
-            poBaseLayer->ResetReading();
-
-            /* Check that the layer field definition is consistant with the one */
-            /* we got in BuildLayerDefn() */
-            if (poFeatureDefn->GetFieldCount() != poBaseLayer->GetLayerDefn()->GetFieldCount())
-                bGotApproximateLayerDefn = TRUE;
-            else
+            bReloadNeeded = TRUE;
+            nPagingStartIndex = nFeatureRead;
+        }
+        if (bReloadNeeded)
+        {
+            GDALClose(poBaseDS);
+            poBaseDS = NULL;
+            poBaseLayer = NULL;
+            bHasFetched = FALSE;
+            bReloadNeeded = FALSE;
+        }
+        if (poBaseDS == NULL && !bHasFetched)
+        {
+            bHasFetched = TRUE;
+            poBaseDS = FetchGetFeature(0);
+            if (poBaseDS)
             {
-                int iField;
-                for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
+                poBaseLayer = poBaseDS->GetLayer(0);
+                poBaseLayer->ResetReading();
+
+                /* Check that the layer field definition is consistent with the one */
+                /* we got in BuildLayerDefn() */
+                if (poFeatureDefn->GetFieldCount() != poBaseLayer->GetLayerDefn()->GetFieldCount())
+                    bGotApproximateLayerDefn = TRUE;
+                else
                 {
-                    OGRFieldDefn* poFDefn1 = poFeatureDefn->GetFieldDefn(iField);
-                    OGRFieldDefn* poFDefn2 = poBaseLayer->GetLayerDefn()->GetFieldDefn(iField);
-                    if (strcmp(poFDefn1->GetNameRef(), poFDefn2->GetNameRef()) != 0 ||
-                        poFDefn1->GetType() != poFDefn2->GetType())
+                    int iField;
+                    for(iField = 0;iField < poFeatureDefn->GetFieldCount(); iField++)
                     {
-                        bGotApproximateLayerDefn = TRUE;
-                        break;
+                        OGRFieldDefn* poFDefn1 = poFeatureDefn->GetFieldDefn(iField);
+                        OGRFieldDefn* poFDefn2 = poBaseLayer->GetLayerDefn()->GetFieldDefn(iField);
+                        if (strcmp(poFDefn1->GetNameRef(), poFDefn2->GetNameRef()) != 0 ||
+                            poFDefn1->GetType() != poFDefn2->GetType())
+                        {
+                            bGotApproximateLayerDefn = TRUE;
+                            break;
+                        }
                     }
                 }
             }
         }
-    }
-    if (!poBaseLayer)
-        return NULL;
+        if (!poBaseLayer)
+            return NULL;
 
-    while(TRUE)
-    {
         OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
         if (poSrcFeature == NULL)
             return NULL;
@@ -1176,7 +1213,7 @@ OGRFeature *OGRWFSLayer::GetNextFeature()
         /* apparently this is not correct : http://jira.codehaus.org/browse/GEOS-3657 */
         if (poGeom != NULL &&
             bAxisOrderAlreadyInverted &&
-            strcmp(poBaseDS->GetDriver()->GetName(), "GML") != 0)
+            strcmp(poBaseDS->GetDriverName(), "GML") != 0)
         {
             poGeom->swapXY();
         }
@@ -1229,33 +1266,63 @@ OGRErr OGRWFSLayer::SetAttributeFilter( const char * pszFilter )
     if (pszFilter != NULL && pszFilter[0] == 0)
         pszFilter = NULL;
 
-    OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
-    if (eErr != CE_None)
-        return eErr;
-
     CPLString osOldWFSWhere(osWFSWhere);
-    if (poDS->HasMinOperators() && pszFilter != NULL)
+
+    CPLFree(m_pszAttrQueryString);
+    m_pszAttrQueryString = (pszFilter) ? CPLStrdup(pszFilter) : NULL;
+
+    delete m_poAttrQuery;
+    m_poAttrQuery = NULL;
+    
+    if( pszFilter != NULL )
+    {
+        m_poAttrQuery = new OGRFeatureQuery();
+
+        OGRErr eErr = m_poAttrQuery->Compile( GetLayerDefn(), pszFilter, TRUE,
+                                              WFSGetCustomFuncRegistrar() );
+        if( eErr != OGRERR_NONE )
+        {
+            delete m_poAttrQuery;
+            m_poAttrQuery = NULL;
+            return eErr;
+        }
+    }
+    
+    if (poDS->HasMinOperators() && m_poAttrQuery != NULL )
     {
+        swq_expr_node* poNode = (swq_expr_node*) m_poAttrQuery->GetSWQExpr();
+        poNode->ReplaceBetweenByGEAndLERecurse();
+
         int bNeedsNullCheck = FALSE;
         int nVersion = (strcmp(poDS->GetVersion(),"1.0.0") == 0) ? 100 :
                        (atoi(poDS->GetVersion()) >= 2) ? 200 : 110;
-        osWFSWhere = WFS_TurnSQLFilterToOGCFilter(pszFilter,
+        if( poNode->field_type != SWQ_BOOLEAN )
+            osWFSWhere = "";
+        else
+            osWFSWhere = WFS_TurnSQLFilterToOGCFilter(poNode,
+                                                      NULL,
                                                   GetLayerDefn(),
                                                   nVersion,
                                                   poDS->PropertyIsNotEqualToSupported(),
                                                   poDS->UseFeatureId() || bUseFeatureIdAtLayerLevel,
                                                   poDS->DoesGmlObjectIdNeedGMLPrefix(),
+                                                  "",
                                                   &bNeedsNullCheck);
         if (bNeedsNullCheck && !poDS->HasNullCheck())
             osWFSWhere = "";
-        if (osWFSWhere.size() == 0)
-        {
-            CPLDebug("WFS", "Using client-side only mode for filter \"%s\"", pszFilter);
-        }
     }
     else
         osWFSWhere = "";
 
+    if (m_poAttrQuery != NULL && osWFSWhere.size() == 0)
+    {
+        CPLDebug("WFS", "Using client-side only mode for filter \"%s\"", pszFilter);
+        OGRErr eErr = OGRLayer::SetAttributeFilter(pszFilter);
+        if (eErr != OGRERR_NONE)
+            return eErr;
+    }
+    ResetReading();
+
     osSQLWhere = (pszFilter) ? pszFilter : "";
 
     if (osWFSWhere != osOldWFSWhere)
@@ -1264,7 +1331,7 @@ OGRErr OGRWFSLayer::SetAttributeFilter( const char * pszFilter )
         bReloadNeeded = FALSE;
     nFeatures = -1;
 
-    return CE_None;
+    return OGRERR_NONE;
 }
 
 /************************************************************************/
@@ -1280,7 +1347,8 @@ int OGRWFSLayer::TestCapability( const char * pszCap )
             return TRUE;
 
         return poBaseLayer != NULL && m_poFilterGeom == NULL &&
-               m_poAttrQuery == NULL &&  poBaseLayer->TestCapability(pszCap);
+               m_poAttrQuery == NULL && poBaseLayer->TestCapability(pszCap) &&
+               (!poDS->IsPagingAllowed() && poBaseLayer->GetFeatureCount() < poDS->GetPageSize());
     }
 
     else if( EQUAL(pszCap,OLCFastGetExtent) )
@@ -1319,7 +1387,7 @@ int OGRWFSLayer::TestCapability( const char * pszCap )
 /*                  ExecuteGetFeatureResultTypeHits()                   */
 /************************************************************************/
 
-int OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
+GIntBig OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
 {
     char* pabyData = NULL;
     CPLString osURL = MakeGetFeatureURL(0, TRUE);
@@ -1436,16 +1504,17 @@ int OGRWFSLayer::ExecuteGetFeatureResultTypeHits()
         return -1;
     }
 
-    int nFeatures = atoi(pszValue);
+    GIntBig nFeatures = CPLAtoGIntBig(pszValue);
     /* Hum, http://deegree3-testing.deegree.org:80/deegree-inspire-node/services?MAXFEATURES=10&SERVICE=WFS&VERSION=1.1.0&REQUEST=GetFeature&TYPENAME=ad:Address&OUTPUTFORMAT=text/xml;%20subtype=gml/3.2.1&RESULTTYPE=hits */
     /* returns more than MAXFEATURES features... So truncate to MAXFEATURES */
     CPLString osMaxFeatures = CPLURLGetValue(osURL, atoi(poDS->GetVersion()) >= 2 ? "COUNT" : "MAXFEATURES");
     if (osMaxFeatures.size() != 0)
     {
-        int nMaxFeatures = atoi(osMaxFeatures);
+        GIntBig nMaxFeatures = CPLAtoGIntBig(osMaxFeatures);
         if (nFeatures > nMaxFeatures)
         {
-            CPLDebug("WFS", "Truncating result from %d to %d", nFeatures, nMaxFeatures);
+            CPLDebug("WFS", "Truncating result from " CPL_FRMT_GIB " to " CPL_FRMT_GIB,
+                     nFeatures, nMaxFeatures);
             nFeatures = nMaxFeatures;
         }
     }
@@ -1476,7 +1545,7 @@ int OGRWFSLayer::CanRunGetFeatureCountAndGetExtentTogether()
 /*                           GetFeatureCount()                          */
 /************************************************************************/
 
-int OGRWFSLayer::GetFeatureCount( int bForce )
+GIntBig OGRWFSLayer::GetFeatureCount( int bForce )
 {
     if (nFeatures >= 0)
         return nFeatures;
@@ -1640,10 +1709,10 @@ CPLString OGRWFSLayer::GetPostHeader()
 }
 
 /************************************************************************/
-/*                          CreateFeature()                             */
+/*                          ICreateFeature()                             */
 /************************************************************************/
 
-OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
+OGRErr OGRWFSLayer::ICreateFeature( OGRFeature *poFeature )
 {
     if (!TestCapability(OLCSequentialWrite))
     {
@@ -1689,8 +1758,6 @@ OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
     osPost += "    <feature:"; osPost += pszShortName; osPost += " xmlns:feature=\"";
     osPost += osTargetNamespace; osPost += "\">\n";
 
-    CPLLocaleC  oLocaleEnforcer;
-
     int i;
     for(i=1; i <= poFeature->GetFieldCount(); i++)
     {
@@ -1728,6 +1795,8 @@ OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
             osPost += ">";
             if (poFDefn->GetType() == OFTInteger)
                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
+            else if (poFDefn->GetType() == OFTInteger64)
+                osPost += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFieldAsInteger64(i));
             else if (poFDefn->GetType() == OFTReal)
                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
             else
@@ -1869,15 +1938,11 @@ OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
     if (strncmp(pszFID, pszShortName, strlen(pszShortName)) == 0 &&
         pszFID[strlen(pszShortName)] == '.')
     {
-        int nFID = atoi(pszFID + strlen(pszShortName) + 1);
-        char szTemp[12];
-        sprintf(szTemp, "%d", nFID);
-        /* Check that it fits on a int32 */
-        if (strcmp(szTemp, pszFID + strlen(pszShortName) + 1) == 0)
-            poFeature->SetFID(nFID);
+        GIntBig nFID = CPLAtoGIntBig(pszFID + strlen(pszShortName) + 1);
+        poFeature->SetFID(nFID);
     }
 
-    CPLDebug("WFS", "Got FID = %ld", poFeature->GetFID());
+    CPLDebug("WFS", "Got FID = " CPL_FRMT_GIB, poFeature->GetFID());
 
     CPLDestroyXMLNode( psXML );
     CPLHTTPDestroyResult(psResult);
@@ -1892,10 +1957,10 @@ OGRErr OGRWFSLayer::CreateFeature( OGRFeature *poFeature )
 
 
 /************************************************************************/
-/*                             SetFeature()                             */
+/*                             ISetFeature()                             */
 /************************************************************************/
 
-OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRWFSLayer::ISetFeature( OGRFeature *poFeature )
 {
     if (!TestCapability(OLCRandomWrite))
     {
@@ -1936,8 +2001,6 @@ OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
     osPost += "  <wfs:Update typeName=\"feature:"; osPost += pszShortName; osPost +=  "\" xmlns:feature=\"";
     osPost += osTargetNamespace; osPost += "\">\n";
 
-    CPLLocaleC  oLocaleEnforcer;
-
     OGRGeometry* poGeom = poFeature->GetGeometryRef();
     if ( osGeometryColumnName.size() != 0 )
     {
@@ -1976,6 +2039,8 @@ OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
             osPost += "      <wfs:Value>";
             if (poFDefn->GetType() == OFTInteger)
                 osPost += CPLSPrintf("%d", poFeature->GetFieldAsInteger(i));
+            else if (poFDefn->GetType() == OFTInteger64)
+                osPost += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFieldAsInteger64(i));
             else if (poFDefn->GetType() == OFTReal)
                 osPost += CPLSPrintf("%.16g", poFeature->GetFieldAsDouble(i));
             else
@@ -2083,7 +2148,7 @@ OGRErr OGRWFSLayer::SetFeature( OGRFeature *poFeature )
 /*                               GetFeature()                           */
 /************************************************************************/
 
-OGRFeature* OGRWFSLayer::GetFeature(long nFID)
+OGRFeature* OGRWFSLayer::GetFeature(GIntBig nFID)
 {
     GetLayerDefn();
     if (poBaseLayer == NULL && poFeatureDefn->GetFieldIndex("gml_id") == 0)
@@ -2091,7 +2156,7 @@ OGRFeature* OGRWFSLayer::GetFeature(long nFID)
         /* This is lovely hackish. We assume that then gml_id will be */
         /* layer_name.number. This is actually what we can observe with */
         /* GeoServer and TinyOWS */
-        CPLString osVal = CPLSPrintf("gml_id = '%s.%ld'", GetShortName(), nFID);
+        CPLString osVal = CPLSPrintf("gml_id = '%s." CPL_FRMT_GIB "'", GetShortName(), nFID);
         CPLString osOldSQLWhere(osSQLWhere);
         SetAttributeFilter(osVal);
         OGRFeature* poFeature = GetNextFeature();
@@ -2220,7 +2285,7 @@ OGRErr OGRWFSLayer::DeleteFromFilter( CPLString osOGCFilter )
 /*                            DeleteFeature()                           */
 /************************************************************************/
 
-OGRErr OGRWFSLayer::DeleteFeature( long nFID )
+OGRErr OGRWFSLayer::DeleteFeature( GIntBig nFID )
 {
     if (!TestCapability(OLCDeleteFeature))
     {
@@ -2244,7 +2309,7 @@ OGRErr OGRWFSLayer::DeleteFeature( long nFID )
     if (poFeature == NULL)
     {
         CPLError(CE_Failure, CPLE_AppDefined,
-                 "Cannot find feature %ld", nFID);
+                 "Cannot find feature " CPL_FRMT_GIB, nFID);
         return OGRERR_FAILURE;
     }
 
@@ -2458,7 +2523,7 @@ OGRErr OGRWFSLayer::CommitTransaction()
             if ((int)aosFIDList.size() != nGotInserted)
             {
                 CPLError(CE_Failure, CPLE_AppDefined,
-                        "Inconsistant InsertResults: did not get expected FID count");
+                        "Inconsistent InsertResults: did not get expected FID count");
                 CPLDestroyXMLNode( psXML );
                 CPLHTTPDestroyResult(psResult);
                 return OGRERR_FAILURE;
@@ -2528,8 +2593,7 @@ void  OGRWFSLayer::SetRequiredOutputFormat(const char* pszRequiredOutputFormatIn
 /*                            SetOrderBy()                              */
 /************************************************************************/
 
-void OGRWFSLayer::SetOrderBy(const char* pszFieldToSort, int bAscFlag)
+void OGRWFSLayer::SetOrderBy(const std::vector<OGRWFSSortDesc>& aoSortColumnsIn)
 {
-    osFieldToSort = pszFieldToSort ? pszFieldToSort : "";
-    this->bAscFlag = bAscFlag;
+    aoSortColumns = aoSortColumnsIn;
 }
diff --git a/ogr/ogrsf_frmts/xls/GNUmakefile b/ogr/ogrsf_frmts/xls/GNUmakefile
index 8eb4fdc..732182c 100644
--- a/ogr/ogrsf_frmts/xls/GNUmakefile
+++ b/ogr/ogrsf_frmts/xls/GNUmakefile
@@ -4,7 +4,7 @@ include ../../../GDALmake.opt
 
 OBJ	=	ogrxlsdriver.o ogrxlsdatasource.o ogrxlslayer.o
 
-CPPFLAGS	:=	-I.. -I../.. $(FREEXL_INCLUDE) $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. $(FREEXL_INCLUDE)  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/xls/ogr_xls.h b/ogr/ogrsf_frmts/xls/ogr_xls.h
index 3271f1c..7e972f7 100644
--- a/ogr/ogrsf_frmts/xls/ogr_xls.h
+++ b/ogr/ogrsf_frmts/xls/ogr_xls.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_xls.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_xls.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  XLS Translator
  * Purpose:  Definition of classes for OGR .xls driver.
@@ -70,7 +70,7 @@ class OGRXLSLayer : public OGRLayer
     virtual OGRFeature *        GetNextFeature();
 
     virtual OGRFeatureDefn *    GetLayerDefn();
-    virtual int                 GetFeatureCount( int bForce = TRUE );
+    virtual GIntBig             GetFeatureCount( int bForce = TRUE );
 
     virtual const char         *GetName() { return pszName; }
     virtual OGRwkbGeometryType  GetGeomType() { return wkbNone; }
diff --git a/ogr/ogrsf_frmts/xls/ogrxlsdatasource.cpp b/ogr/ogrsf_frmts/xls/ogrxlsdatasource.cpp
index dc945f4..23ec9cb 100644
--- a/ogr/ogrsf_frmts/xls/ogrxlsdatasource.cpp
+++ b/ogr/ogrsf_frmts/xls/ogrxlsdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrxlsdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrxlsdatasource.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  XLS Translator
  * Purpose:  Implements OGRXLSDataSource class
@@ -37,7 +37,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrxlsdatasource.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrxlsdatasource.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                          OGRXLSDataSource()                          */
@@ -75,7 +75,7 @@ OGRXLSDataSource::~OGRXLSDataSource()
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGRXLSDataSource::TestCapability( const char * pszCap )
+int OGRXLSDataSource::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
@@ -127,7 +127,7 @@ int OGRXLSDataSource::Open( const char * pszFilename, int bUpdateIn)
     if (freexl_get_info (xlshandle, FREEXL_BIFF_SHEET_COUNT, &nSheets) != FREEXL_OK)
         return FALSE;
 
-    for(int i=0; i<(int)nSheets; i++)
+    for(unsigned short i=0; i<(unsigned short)nSheets; i++)
     {
         freexl_select_active_worksheet(xlshandle, i);
 
diff --git a/ogr/ogrsf_frmts/xls/ogrxlsdriver.cpp b/ogr/ogrsf_frmts/xls/ogrxlsdriver.cpp
index abd7529..9071ab1 100644
--- a/ogr/ogrsf_frmts/xls/ogrxlsdriver.cpp
+++ b/ogr/ogrsf_frmts/xls/ogrxlsdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrxlsdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrxlsdriver.cpp 27794 2014-10-04 10:13:46Z rouault $
  *
  * Project:  XLS Translator
  * Purpose:  Implements OGRXLSDriver.
@@ -30,7 +30,7 @@
 #include "ogr_xls.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrxlsdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrxlsdriver.cpp 27794 2014-10-04 10:13:46Z rouault $");
 
 /************************************************************************/
 /*                           ~OGRXLSDriver()                            */
@@ -83,7 +83,7 @@ OGRDataSource *OGRXLSDriver::Open( const char * pszFilename, int bUpdate )
 /*                           TestCapability()                           */
 /************************************************************************/
 
-int OGRXLSDriver::TestCapability( const char * pszCap )
+int OGRXLSDriver::TestCapability( CPL_UNUSED const char * pszCap )
 
 {
     return FALSE;
@@ -96,6 +96,12 @@ int OGRXLSDriver::TestCapability( const char * pszCap )
 void RegisterOGRXLS()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRXLSDriver );
+    OGRSFDriver* poDriver = new OGRXLSDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "MS Excel format" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xls" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_xls.html" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/xls/ogrxlslayer.cpp b/ogr/ogrsf_frmts/xls/ogrxlslayer.cpp
index 4840110..1fdd936 100644
--- a/ogr/ogrsf_frmts/xls/ogrxlslayer.cpp
+++ b/ogr/ogrsf_frmts/xls/ogrxlslayer.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrxlslayer.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrxlslayer.cpp 28382 2015-01-30 15:29:41Z rouault $
  *
  * Project:  XLS Translator
  * Purpose:  Implements OGRXLSLayer class.
@@ -33,7 +33,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: ogrxlslayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrxlslayer.cpp 28382 2015-01-30 15:29:41Z rouault $");
 
 /************************************************************************/
 /*                            OGRXLSLayer()                             */
@@ -54,6 +54,7 @@ OGRXLSLayer::OGRXLSLayer( OGRXLSDataSource* poDSIn,
     pszName = CPLStrdup(pszSheetname);
     nRows = nRowsIn;
     nCols = nColsIn;
+    SetDescription( pszName );
 }
 
 /************************************************************************/
@@ -209,7 +210,7 @@ OGRFeatureDefn * OGRXLSLayer::GetLayerDefn()
     if (xlshandle == NULL)
         return poFeatureDefn;
 
-    freexl_select_active_worksheet(xlshandle, iSheet);
+    freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
 
     if (nRows > 0)
     {
@@ -263,7 +264,7 @@ OGRFeatureDefn * OGRXLSLayer::GetLayerDefn()
 /*                          GetFeatureCount()                           */
 /************************************************************************/
 
-int OGRXLSLayer::GetFeatureCount( int bForce )
+GIntBig OGRXLSLayer::GetFeatureCount( int bForce )
 {
     if  ( m_poAttrQuery == NULL /* && m_poFilterGeom == NULL */ )
     {
@@ -319,7 +320,7 @@ OGRFeature *OGRXLSLayer::GetNextRawFeature()
     if (xlshandle == NULL)
         return NULL;
 
-    freexl_select_active_worksheet(xlshandle, iSheet);
+    freexl_select_active_worksheet(xlshandle, (unsigned short)iSheet);
 
     OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
 
diff --git a/ogr/ogrsf_frmts/xlsx/GNUmakefile b/ogr/ogrsf_frmts/xlsx/GNUmakefile
index 34e7311..97fb547 100644
--- a/ogr/ogrsf_frmts/xlsx/GNUmakefile
+++ b/ogr/ogrsf_frmts/xlsx/GNUmakefile
@@ -8,7 +8,7 @@ ifeq ($(HAVE_EXPAT),yes)
 CPPFLAGS +=   -DHAVE_EXPAT
 endif
 
-CPPFLAGS	:=	-I.. -I../.. -I../mem $(GDAL_INCLUDE) $(EXPAT_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../.. -I../mem  $(EXPAT_INCLUDE) $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/xlsx/ogr_xlsx.h b/ogr/ogrsf_frmts/xlsx/ogr_xlsx.h
index eab13e1..abefe67 100644
--- a/ogr/ogrsf_frmts/xlsx/ogr_xlsx.h
+++ b/ogr/ogrsf_frmts/xlsx/ogr_xlsx.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_xlsx.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogr_xlsx.h 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  XLSX Translator
  * Purpose:  Definition of classes for OGR OpenOfficeSpreadsheet .xlsx driver.
@@ -75,20 +75,20 @@ class OGRXLSXLayer : public OGRMemLayer
 
     /* For external usage. Mess with FID */
     virtual OGRFeature *        GetNextFeature();
-    virtual OGRFeature         *GetFeature( long nFeatureId );
-    virtual OGRErr              SetFeature( OGRFeature *poFeature );
-    virtual OGRErr              DeleteFeature( long nFID );
+    virtual OGRFeature         *GetFeature( GIntBig nFeatureId );
+    virtual OGRErr              ISetFeature( OGRFeature *poFeature );
+    virtual OGRErr              DeleteFeature( GIntBig nFID );
 
-    virtual OGRErr      SetNextByIndex( long nIndex )
+    virtual OGRErr      SetNextByIndex( GIntBig nIndex )
     { Init(); return OGRMemLayer::SetNextByIndex(nIndex); }
 
-    OGRErr              CreateFeature( OGRFeature *poFeature )
-    { Init(); SetUpdated(); return OGRMemLayer::CreateFeature(poFeature); }
+    OGRErr              ICreateFeature( OGRFeature *poFeature )
+    { Init(); SetUpdated(); return OGRMemLayer::ICreateFeature(poFeature); }
 
     OGRFeatureDefn *    GetLayerDefn()
     { Init(); return OGRMemLayer::GetLayerDefn(); }
 
-    int                 GetFeatureCount( int bForce )
+    GIntBig                 GetFeatureCount( int bForce )
     { Init(); return OGRMemLayer::GetFeatureCount(bForce); }
 
     virtual OGRErr      CreateField( OGRFieldDefn *poField,
@@ -135,6 +135,18 @@ typedef struct
     int               nBeginDepth;
 } HandlerState;
 
+class XLSXFieldTypeExtended
+{
+public:
+    OGRFieldType      eType;
+    int               bHasMS;
+
+                    XLSXFieldTypeExtended() : eType(OFTMaxType), bHasMS(FALSE) {}
+                    XLSXFieldTypeExtended(OGRFieldType eType,
+                                          int bHasMS = FALSE) :
+                                    eType(eType), bHasMS(bHasMS) {}
+};
+
 class OGRXLSXDataSource : public OGRDataSource
 {
     char*               pszName;
@@ -176,8 +188,8 @@ class OGRXLSXDataSource : public OGRDataSource
     std::vector<std::string>  apoCurLineTypes;
 
     int                        bInCellXFS;
-    std::map<int,OGRFieldType> apoMapStyleFormats;
-    std::vector<OGRFieldType>  apoStyles;
+    std::map<int,XLSXFieldTypeExtended> apoMapStyleFormats;
+    std::vector<XLSXFieldTypeExtended>  apoStyles;
 
     void                PushState(HandlerStateEnum eVal);
     void                startElementDefault(const char *pszName, const char **ppszAttr);
@@ -214,13 +226,13 @@ class OGRXLSXDataSource : public OGRDataSource
 
     virtual int                 TestCapability( const char * );
 
-    virtual OGRLayer* CreateLayer( const char * pszLayerName,
+    virtual OGRLayer* ICreateLayer( const char * pszLayerName,
                                 OGRSpatialReference *poSRS,
                                 OGRwkbGeometryType eType,
                                 char ** papszOptions );
     virtual OGRErr      DeleteLayer(int iLayer);
 
-    virtual OGRErr      SyncToDisk();
+    virtual void        FlushCache();
 
     void                startElementCbk(const char *pszName, const char **ppszAttr);
     void                endElementCbk(const char *pszName);
diff --git a/ogr/ogrsf_frmts/xlsx/ogrxlsxdatasource.cpp b/ogr/ogrsf_frmts/xlsx/ogrxlsxdatasource.cpp
index ac63bf5..8a6add2 100644
--- a/ogr/ogrsf_frmts/xlsx/ogrxlsxdatasource.cpp
+++ b/ogr/ogrsf_frmts/xlsx/ogrxlsxdatasource.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrxlsxdatasource.cpp 28181 2014-12-20 17:22:45Z rouault $
+ * $Id: ogrxlsxdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  XLSX Translator
  * Purpose:  Implements OGRXLSXDataSource class
@@ -32,7 +32,7 @@
 #include "cpl_conv.h"
 #include "cpl_time.h"
 
-CPL_CVSID("$Id: ogrxlsxdatasource.cpp 28181 2014-12-20 17:22:45Z rouault $");
+CPL_CVSID("$Id: ogrxlsxdatasource.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 /************************************************************************/
 /*                            OGRXLSXLayer()                            */
@@ -88,7 +88,8 @@ void OGRXLSXLayer::SetUpdated(int bUpdatedIn)
 
 OGRErr OGRXLSXLayer::SyncToDisk()
 {
-    return poDS->SyncToDisk();
+    poDS->FlushCache();
+    return OGRERR_NONE;
 }
 
 /************************************************************************/
@@ -108,7 +109,7 @@ OGRFeature* OGRXLSXLayer::GetNextFeature()
 /*                           GetFeature()                               */
 /************************************************************************/
 
-OGRFeature* OGRXLSXLayer::GetFeature( long nFeatureId )
+OGRFeature* OGRXLSXLayer::GetFeature( GIntBig nFeatureId )
 {
     Init();
     OGRFeature* poFeature = OGRMemLayer::GetFeature(nFeatureId - (1 + bHasHeaderLine));
@@ -118,20 +119,20 @@ OGRFeature* OGRXLSXLayer::GetFeature( long nFeatureId )
 }
 
 /************************************************************************/
-/*                           SetFeature()                               */
+/*                           ISetFeature()                               */
 /************************************************************************/
 
-OGRErr OGRXLSXLayer::SetFeature( OGRFeature *poFeature )
+OGRErr OGRXLSXLayer::ISetFeature( OGRFeature *poFeature )
 {
     Init();
     if (poFeature == NULL)
-        return OGRMemLayer::SetFeature(poFeature);
+        return OGRMemLayer::ISetFeature(poFeature);
 
-    long nFID = poFeature->GetFID();
+    GIntBig nFID = poFeature->GetFID();
     if (nFID != OGRNullFID)
         poFeature->SetFID(nFID - (1 + bHasHeaderLine));
     SetUpdated();
-    OGRErr eErr = OGRMemLayer::SetFeature(poFeature);
+    OGRErr eErr = OGRMemLayer::ISetFeature(poFeature);
     poFeature->SetFID(nFID);
     return eErr;
 }
@@ -140,7 +141,7 @@ OGRErr OGRXLSXLayer::SetFeature( OGRFeature *poFeature )
 /*                          DeleteFeature()                             */
 /************************************************************************/
 
-OGRErr OGRXLSXLayer::DeleteFeature( long nFID )
+OGRErr OGRXLSXLayer::DeleteFeature( GIntBig nFID )
 {
     Init();
     SetUpdated();
@@ -189,7 +190,7 @@ OGRXLSXDataSource::OGRXLSXDataSource()
 OGRXLSXDataSource::~OGRXLSXDataSource()
 
 {
-    SyncToDisk();
+    FlushCache();
 
     CPLFree( pszName );
 
@@ -273,7 +274,8 @@ int OGRXLSXDataSource::Open( const char * pszFilename,
 /*                             Create()                                 */
 /************************************************************************/
 
-int OGRXLSXDataSource::Create( const char * pszFilename, CPL_UNUSED char **papszOptions )
+int OGRXLSXDataSource::Create( const char * pszFilename,
+                               CPL_UNUSED char **papszOptions )
 {
     bUpdated = TRUE;
     bUpdatable = TRUE;
@@ -427,11 +429,18 @@ OGRFieldType OGRXLSXDataSource::GetOGRFieldType(const char* pszValue,
         if (eValueType == CPL_VALUE_STRING)
             return OFTString;
         else if (eValueType == CPL_VALUE_INTEGER)
-            return OFTInteger;
+        {
+            GIntBig nVal = CPLAtoGIntBig(pszValue);
+            if( (GIntBig)(int)nVal != nVal )
+                return OFTInteger64;
+            else
+                return OFTInteger;
+        }
         else
             return OFTReal;
     }
-    else if (strcmp(pszValueType, "datetime") == 0)
+    else if (strcmp(pszValueType, "datetime") == 0 ||
+             strcmp(pszValueType, "datetime_ms") == 0)
     {
         return OFTDateTime;
     }
@@ -463,10 +472,11 @@ static void SetField(OGRFeature* poFeature,
 
     if (strcmp(pszCellType, "time") == 0 ||
         strcmp(pszCellType, "date") == 0 ||
-        strcmp(pszCellType, "datetime") == 0)
+        strcmp(pszCellType, "datetime") == 0 ||
+        strcmp(pszCellType, "datetime_ms") == 0)
     {
         struct tm sTm;
-        double dfNumberOfDaysSince1900 = atof(pszValue);
+        double dfNumberOfDaysSince1900 = CPLAtof(pszValue);
 #define NUMBER_OF_DAYS_BETWEEN_1900_AND_1970        25569
 #define NUMBER_OF_SECONDS_PER_DAY                   86400
         GIntBig nUnixTime = (GIntBig)((dfNumberOfDaysSince1900 -
@@ -476,8 +486,9 @@ static void SetField(OGRFeature* poFeature,
 
         if (eType == OFTTime || eType == OFTDate || eType == OFTDateTime)
         {
+            double fFracSec = fmod(fmod(dfNumberOfDaysSince1900,1) * 3600 * 24, 1);
             poFeature->SetField(i, sTm.tm_year + 1900, sTm.tm_mon + 1, sTm.tm_mday,
-                                sTm.tm_hour, sTm.tm_min, sTm.tm_sec, 0);
+                                sTm.tm_hour, sTm.tm_min, sTm.tm_sec + fFracSec, 0 );
         }
         else if (strcmp(pszCellType, "time") == 0)
         {
@@ -491,9 +502,10 @@ static void SetField(OGRFeature* poFeature,
         }
         else /* if (strcmp(pszCellType, "datetime") == 0) */
         {
-            poFeature->SetField(i, CPLSPrintf("%04d/%02d/%02d %02d:%02d:%02d",
+            double fFracSec = fmod(fmod(dfNumberOfDaysSince1900,1) * 3600 * 24, 1);
+            poFeature->SetField(i,
                                 sTm.tm_year + 1900, sTm.tm_mon + 1, sTm.tm_mday,
-                                sTm.tm_hour, sTm.tm_min, sTm.tm_sec));
+                                sTm.tm_hour, sTm.tm_min, sTm.tm_sec + fFracSec, 0);
         }
     }
     else
@@ -681,12 +693,17 @@ void OGRXLSXDataSource::startElementRow(const char *pszName,
         int nS = atoi(pszS);
         if (nS >= 0 && nS < (int)apoStyles.size())
         {
-            OGRFieldType eType = apoStyles[nS];
-            if (eType == OFTDateTime)
-                osValueType = "datetime";
-            else if (eType == OFTDate)
+            XLSXFieldTypeExtended eType = apoStyles[nS];
+            if (eType.eType == OFTDateTime)
+            {
+                if( eType.bHasMS )
+                    osValueType = "datetime_ms";
+                else
+                    osValueType = "datetime";
+            }
+            else if (eType.eType == OFTDate)
                 osValueType = "date";
-            else if (eType == OFTTime)
+            else if (eType.eType == OFTTime)
                 osValueType = "time";
         }
         else if (nS != -1)
@@ -816,10 +833,14 @@ void OGRXLSXDataSource::endElementRow(CPL_UNUSED const char *pszName)
                         {
                             /* ok */
                         }
-                        else if (eFieldType == OFTReal && eValType == OFTInteger)
+                        else if (eFieldType == OFTReal && (eValType == OFTInteger || eValType == OFTInteger64))
                         {
                            /* ok */;
                         }
+                        else if (eFieldType == OFTInteger64 && eValType == OFTInteger )
+                        {
+                            /* ok */;
+                        }
                         else if (eFieldType != OFTString && eValType != eFieldType)
                         {
                             OGRFieldDefn oNewFieldDefn(
@@ -827,9 +848,11 @@ void OGRXLSXDataSource::endElementRow(CPL_UNUSED const char *pszName)
                             if ((eFieldType == OFTDate || eFieldType == OFTTime) &&
                                    eValType == OFTDateTime)
                                 oNewFieldDefn.SetType(OFTDateTime);
-                            else if (eFieldType == OFTInteger &&
+                            else if ((eFieldType == OFTInteger || eFieldType == OFTInteger64) &&
                                      eValType == OFTReal)
                                 oNewFieldDefn.SetType(OFTReal);
+                            else if( eFieldType == OFTInteger && eValType == OFTInteger64 )
+                                oNewFieldDefn.SetType(OFTInteger64);
                             else
                                 oNewFieldDefn.SetType(OFTString);
                             poCurLayer->AlterFieldDefn(i, &oNewFieldDefn,
@@ -1243,13 +1266,14 @@ void OGRXLSXDataSource::startElementStylesCbk(const char *pszName,
                            strstr(pszFormatCode, "YY") != NULL;
             int bHasTime = strstr(pszFormatCode, "HH") != NULL;
             if (bHasDate && bHasTime)
-                apoMapStyleFormats[nNumFmtId] = OFTDateTime;
+                apoMapStyleFormats[nNumFmtId] = XLSXFieldTypeExtended(OFTDateTime,
+                                        strstr(pszFormatCode, "SS.000") != NULL );
             else if (bHasDate)
-                apoMapStyleFormats[nNumFmtId] = OFTDate;
+                apoMapStyleFormats[nNumFmtId] = XLSXFieldTypeExtended(OFTDate);
             else if (bHasTime)
-                apoMapStyleFormats[nNumFmtId] = OFTTime;
+                apoMapStyleFormats[nNumFmtId] = XLSXFieldTypeExtended(OFTTime);
             else
-                apoMapStyleFormats[nNumFmtId] = OFTReal;
+                apoMapStyleFormats[nNumFmtId] = XLSXFieldTypeExtended(OFTReal);
         }
     }
     else if (strcmp(pszName,"cellXfs") == 0)
@@ -1260,22 +1284,22 @@ void OGRXLSXDataSource::startElementStylesCbk(const char *pszName,
     {
         const char* pszNumFmtId = GetAttributeValue(ppszAttr, "numFmtId", "-1");
         int nNumFmtId = atoi(pszNumFmtId);
-        OGRFieldType eType = OFTReal;
+        XLSXFieldTypeExtended eType(OFTReal);
         if (nNumFmtId >= 0)
         {
             if (nNumFmtId < 164)
             {
                 // From http://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/thread/e27aaf16-b900-4654-8210-83c5774a179c/
                 if (nNumFmtId >= 14 && nNumFmtId <= 17)
-                    eType = OFTDate;
+                    eType = XLSXFieldTypeExtended(OFTDate);
                 else if (nNumFmtId >= 18 && nNumFmtId <= 21)
-                    eType = OFTTime;
+                    eType = XLSXFieldTypeExtended(OFTTime);
                 else if (nNumFmtId == 22)
-                    eType = OFTDateTime;
+                    eType = XLSXFieldTypeExtended(OFTDateTime);
             }
             else
             {
-                std::map<int, OGRFieldType>::iterator oIter = apoMapStyleFormats.find(nNumFmtId);
+                std::map<int, XLSXFieldTypeExtended>::iterator oIter = apoMapStyleFormats.find(nNumFmtId);
                 if (oIter != apoMapStyleFormats.end())
                     eType = oIter->second;
                 else
@@ -1363,14 +1387,14 @@ void OGRXLSXDataSource::AnalyseStyles(VSILFILE* fpStyles)
 }
 
 /************************************************************************/
-/*                            CreateLayer()                             */
+/*                           ICreateLayer()                             */
 /************************************************************************/
 
 OGRLayer *
-OGRXLSXDataSource::CreateLayer( const char * pszLayerName,
-                                CPL_UNUSED OGRSpatialReference *poSRS,
-                                CPL_UNUSED OGRwkbGeometryType eType,
-                                char ** papszOptions )
+OGRXLSXDataSource::ICreateLayer( const char * pszLayerName,
+                                 CPL_UNUSED OGRSpatialReference *poSRS,
+                                 CPL_UNUSED OGRwkbGeometryType eType,
+                                 char ** papszOptions )
 
 {
 /* -------------------------------------------------------------------- */
@@ -1677,7 +1701,7 @@ static void WriteLayer(const char* pszName, OGRLayer* poLayer, int iLayer,
     {
         int nWidth = 15;
         if (poFDefn->GetFieldDefn(j)->GetType() == OFTDateTime)
-            nWidth = 25;
+            nWidth = 29;
         VSIFPrintfL(fp, "<col min=\"%d\" max=\"%d\" width=\"%d\"/>\n",
                     j+1, 1024, nWidth);
 
@@ -1742,13 +1766,18 @@ static void WriteLayer(const char* pszName, OGRLayer* poLayer, int iLayer,
                     VSIFPrintfL(fp, "<v>%d</v>\n", poFeature->GetFieldAsInteger(j));
                     VSIFPrintfL(fp, "</c>\n");
                 }
+                else if (eType == OFTInteger64)
+                {
+                    VSIFPrintfL(fp, "<c r=\"%s%d\">\n", szCol, iRow);
+                    VSIFPrintfL(fp, "<v>" CPL_FRMT_GIB "</v>\n", poFeature->GetFieldAsInteger64(j));
+                    VSIFPrintfL(fp, "</c>\n");
+                }
                 else if (eType == OFTDate || eType == OFTDateTime || eType == OFTTime)
                 {
-                    VSIFPrintfL(fp, "<c r=\"%s%d\" s=\"%d\">\n", szCol, iRow,
-                                (eType == OFTDate) ? 1 : (eType == OFTDateTime) ? 2 : 3);
-                    int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
+                    int nYear, nMonth, nDay, nHour, nMinute, nTZFlag;
+                    float fSecond;
                     poFeature->GetFieldAsDateTime(j, &nYear, &nMonth, &nDay,
-                                                    &nHour, &nMinute, &nSecond, &nTZFlag);
+                                                    &nHour, &nMinute, &fSecond, &nTZFlag );
                     struct tm brokendowntime;
                     memset(&brokendowntime, 0, sizeof(brokendowntime));
                     brokendowntime.tm_year = (eType == OFTTime) ? 70 : nYear - 1900;
@@ -1756,9 +1785,14 @@ static void WriteLayer(const char* pszName, OGRLayer* poLayer, int iLayer,
                     brokendowntime.tm_mday = (eType == OFTTime) ? 1 : nDay;
                     brokendowntime.tm_hour = nHour;
                     brokendowntime.tm_min = nMinute;
-                    brokendowntime.tm_sec = nSecond;
+                    brokendowntime.tm_sec = (int)fSecond;
                     GIntBig nUnixTime = CPLYMDHMSToUnixTime(&brokendowntime);
                     double dfNumberOfDaysSince1900 = (1.0 * nUnixTime / NUMBER_OF_SECONDS_PER_DAY);
+                    dfNumberOfDaysSince1900 += fmod(fSecond,1) / NUMBER_OF_SECONDS_PER_DAY;
+                    int s = (eType == OFTDate) ? 1 : (eType == OFTDateTime) ? 2 : 3;
+                    if( eType == OFTDateTime && OGR_GET_MS(fSecond) )
+                        s = 4;
+                    VSIFPrintfL(fp, "<c r=\"%s%d\" s=\"%d\">\n", szCol, iRow, s);
                     if (eType != OFTTime)
                         dfNumberOfDaysSince1900 += NUMBER_OF_DAYS_BETWEEN_1900_AND_1970;
                     if (eType == OFTDate)
@@ -1840,6 +1874,7 @@ static void WriteStyles(const char* pszName)
     VSIFPrintfL(fp, "<numFmt formatCode=\"DD/MM/YY\" numFmtId=\"165\"/>\n");
     VSIFPrintfL(fp, "<numFmt formatCode=\"DD/MM/YYYY\\ HH:MM:SS\" numFmtId=\"166\"/>\n");
     VSIFPrintfL(fp, "<numFmt formatCode=\"HH:MM:SS\" numFmtId=\"167\"/>\n");
+    VSIFPrintfL(fp, "<numFmt formatCode=\"DD/MM/YYYY\\ HH:MM:SS.000\" numFmtId=\"168\"/>\n");
     VSIFPrintfL(fp, "</numFmts>\n");
     VSIFPrintfL(fp, "<fonts count=\"1\">\n");
     VSIFPrintfL(fp, "<font>\n");
@@ -1866,11 +1901,12 @@ static void WriteStyles(const char* pszName)
     VSIFPrintfL(fp, "<xf numFmtId=\"164\">\n");
     VSIFPrintfL(fp, "</xf>\n");
     VSIFPrintfL(fp, "</cellStyleXfs>\n");
-    VSIFPrintfL(fp, "<cellXfs count=\"4\">\n");
+    VSIFPrintfL(fp, "<cellXfs count=\"5\">\n");
     VSIFPrintfL(fp, "<xf numFmtId=\"164\" xfId=\"0\"/>\n");
     VSIFPrintfL(fp, "<xf numFmtId=\"165\" xfId=\"0\"/>\n");
     VSIFPrintfL(fp, "<xf numFmtId=\"166\" xfId=\"0\"/>\n");
     VSIFPrintfL(fp, "<xf numFmtId=\"167\" xfId=\"0\"/>\n");
+    VSIFPrintfL(fp, "<xf numFmtId=\"168\" xfId=\"0\"/>\n");
     VSIFPrintfL(fp, "</cellXfs>\n");
     VSIFPrintfL(fp, "<cellStyles count=\"1\">\n");
     VSIFPrintfL(fp, "<cellStyle builtinId=\"0\" customBuiltin=\"false\" name=\"Normal\" xfId=\"0\"/>\n");
@@ -1921,15 +1957,15 @@ static void WriteDotRels(const char* pszName)
 }
 
 /************************************************************************/
-/*                            SyncToDisk()                              */
+/*                            FlushCache()                              */
 /************************************************************************/
 
-OGRErr OGRXLSXDataSource::SyncToDisk()
+void OGRXLSXDataSource::FlushCache()
 {
     int i;
 
     if (!bUpdated)
-        return OGRERR_NONE;
+        return;
 
     VSIStatBufL sStat;
     if (VSIStatL(pszName, &sStat) == 0)
@@ -1938,7 +1974,7 @@ OGRErr OGRXLSXDataSource::SyncToDisk()
         {
             CPLError(CE_Failure, CPLE_FileIO,
                     "Cannot delete %s", pszName);
-            return OGRERR_FAILURE;
+            return;
         }
     }
 
@@ -1954,7 +1990,7 @@ OGRErr OGRXLSXDataSource::SyncToDisk()
     {
         CPLError(CE_Failure, CPLE_FileIO,
                  "Cannot create %s", pszName);
-        return OGRERR_FAILURE;
+        return;
     }
 
     WriteContentTypes(pszName, nLayers);
@@ -1994,5 +2030,5 @@ OGRErr OGRXLSXDataSource::SyncToDisk()
         ((OGRXLSXLayer*)papoLayers[i])->SetUpdated(FALSE);
     }
 
-    return OGRERR_NONE;
+    return;
 }
diff --git a/ogr/ogrsf_frmts/xlsx/ogrxlsxdriver.cpp b/ogr/ogrsf_frmts/xlsx/ogrxlsxdriver.cpp
index ee8af9f..e37813f 100644
--- a/ogr/ogrsf_frmts/xlsx/ogrxlsxdriver.cpp
+++ b/ogr/ogrsf_frmts/xlsx/ogrxlsxdriver.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrxlsxdriver.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrxlsxdriver.cpp 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  XLSX Translator
  * Purpose:  Implements OGRXLSXDriver.
@@ -30,7 +30,7 @@
 #include "ogr_xlsx.h"
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: ogrxlsxdriver.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrxlsxdriver.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 extern "C" void RegisterOGRXLSX();
 
@@ -192,6 +192,14 @@ int OGRXLSXDriver::TestCapability( const char * pszCap )
 void RegisterOGRXLSX()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRXLSXDriver );
+    OGRSFDriver* poDriver = new OGRXLSXDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "MS Office Open XML spreadsheet" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xlsx" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_xlsx.html" );
+    poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+    poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, "Integer Integer64 Real String Date DateTime Time" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
 
diff --git a/ogr/ogrsf_frmts/xplane/GNUmakefile b/ogr/ogrsf_frmts/xplane/GNUmakefile
index 35186b3..e68dfce 100644
--- a/ogr/ogrsf_frmts/xplane/GNUmakefile
+++ b/ogr/ogrsf_frmts/xplane/GNUmakefile
@@ -6,7 +6,7 @@ OBJ	=	ogrxplanedriver.o ogrxplanedatasource.o ogrxplanelayer.o ogr_xplane_geo_ut
 		ogr_xplane_reader.o ogr_xplane_apt_reader.o ogr_xplane_nav_reader.o \
  		ogr_xplane_fix_reader.o ogr_xplane_awy_reader.o
 
-CPPFLAGS	:=	-I.. -I../.. $(GDAL_INCLUDE) $(CPPFLAGS)
+CPPFLAGS	:=	-I.. -I../..  $(CPPFLAGS)
 
 default:	$(O_OBJ:.o=.$(OBJ_EXT))
 
diff --git a/ogr/ogrsf_frmts/xplane/ogr_xplane.h b/ogr/ogrsf_frmts/xplane/ogr_xplane.h
index 693179d..8d74a35 100644
--- a/ogr/ogrsf_frmts/xplane/ogr_xplane.h
+++ b/ogr/ogrsf_frmts/xplane/ogr_xplane.h
@@ -70,9 +70,9 @@ class OGRXPlaneLayer : public OGRLayer
 
     virtual void              ResetReading();
     virtual OGRFeature *      GetNextFeature();
-    virtual OGRFeature *      GetFeature( long nFID );
-    virtual OGRErr            SetNextByIndex( long nIndex );
-    virtual int               GetFeatureCount( int bForce = TRUE );
+    virtual OGRFeature *      GetFeature( GIntBig nFID );
+    virtual OGRErr            SetNextByIndex( GIntBig nIndex );
+    virtual GIntBig           GetFeatureCount( int bForce = TRUE );
 
     virtual OGRFeatureDefn *  GetLayerDefn();
     virtual int               TestCapability( const char * pszCap );
diff --git a/ogr/ogrsf_frmts/xplane/ogr_xplane_apt_reader.cpp b/ogr/ogrsf_frmts/xplane/ogr_xplane_apt_reader.cpp
index 83e9611..c73ab53 100644
--- a/ogr/ogrsf_frmts/xplane/ogr_xplane_apt_reader.cpp
+++ b/ogr/ogrsf_frmts/xplane/ogr_xplane_apt_reader.cpp
@@ -30,7 +30,7 @@
 #include "ogr_xplane_apt_reader.h"
 #include "ogr_xplane_geo_utils.h"
 
-CPL_CVSID("$Id: ogr_xplane_apt_reader.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogr_xplane_apt_reader.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                   OGRXPlaneCreateAptFileReader                       */
diff --git a/ogr/ogrsf_frmts/xplane/ogr_xplane_nav_reader.cpp b/ogr/ogrsf_frmts/xplane/ogr_xplane_nav_reader.cpp
index fe3b1e6..1712aad 100644
--- a/ogr/ogrsf_frmts/xplane/ogr_xplane_nav_reader.cpp
+++ b/ogr/ogrsf_frmts/xplane/ogr_xplane_nav_reader.cpp
@@ -29,7 +29,7 @@
 
 #include "ogr_xplane_nav_reader.h"
 
-CPL_CVSID("$Id: ogr_xplane_nav_reader.cpp 27741 2014-09-26 19:20:02Z goatbar $");
+CPL_CVSID("$Id: ogr_xplane_nav_reader.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                   OGRXPlaneCreateNavFileReader                       */
diff --git a/ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp b/ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp
index f430933..0442ed7 100644
--- a/ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp
+++ b/ogr/ogrsf_frmts/xplane/ogrxplanedatasource.cpp
@@ -30,7 +30,7 @@
 #include "ogr_xplane.h"
 #include "ogr_xplane_reader.h"
 
-CPL_CVSID("$Id: ogrxplanedatasource.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrxplanedatasource.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                          OGRXPlaneDataSource()                          */
diff --git a/ogr/ogrsf_frmts/xplane/ogrxplanedriver.cpp b/ogr/ogrsf_frmts/xplane/ogrxplanedriver.cpp
index bf2d52a..131e706 100644
--- a/ogr/ogrsf_frmts/xplane/ogrxplanedriver.cpp
+++ b/ogr/ogrsf_frmts/xplane/ogrxplanedriver.cpp
@@ -49,9 +49,12 @@ OGRDataSource *OGRXPlaneDriver::Open( const char * pszFilename, int bUpdate )
 {
     if ( bUpdate )
     {
-        return FALSE;
+        return NULL;
     }
 
+    if( !EQUAL(CPLGetExtension(pszFilename), "dat") )
+        return NULL;
+
     OGRXPlaneDataSource   *poDS = new OGRXPlaneDataSource();
 
     int bReadWholeFile = CSLTestBoolean(CPLGetConfigOption("OGR_XPLANE_READ_WHOLE_FILE", "TRUE"));
@@ -81,6 +84,12 @@ int OGRXPlaneDriver::TestCapability( CPL_UNUSED const char * pszCap )
 void RegisterOGRXPlane()
 
 {
-    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new OGRXPlaneDriver );
+    OGRSFDriver* poDriver = new OGRXPlaneDriver;
+    poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
+                                "X-Plane/Flightgear aeronautical data" );
+    poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "dat" );
+    poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
+                                "drv_xplane.html" );
+    poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
+    OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver(poDriver);
 }
-
diff --git a/ogr/ogrsf_frmts/xplane/ogrxplanelayer.cpp b/ogr/ogrsf_frmts/xplane/ogrxplanelayer.cpp
index fa93cea..a742dbf 100644
--- a/ogr/ogrsf_frmts/xplane/ogrxplanelayer.cpp
+++ b/ogr/ogrsf_frmts/xplane/ogrxplanelayer.cpp
@@ -31,7 +31,7 @@
 #include "ogr_xplane_geo_utils.h"
 #include "ogr_xplane_reader.h"
 
-CPL_CVSID("$Id: ogrxplanelayer.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrxplanelayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
 
 /************************************************************************/
 /*                            OGRXPlaneLayer()                          */
@@ -48,6 +48,7 @@ OGRXPlaneLayer::OGRXPlaneLayer( const char* pszLayerName )
     poDS = NULL;
 
     poFeatureDefn = new OGRFeatureDefn( pszLayerName );
+    SetDescription( poFeatureDefn->GetName() );
     poFeatureDefn->Reference();
 
     poSRS = new OGRSpatialReference();
@@ -224,7 +225,7 @@ OGRFeature *OGRXPlaneLayer::GetNextFeature()
 /*                           GetFeature()                               */
 /************************************************************************/
 
-OGRFeature *  OGRXPlaneLayer::GetFeature( long nFID )
+OGRFeature *  OGRXPlaneLayer::GetFeature( GIntBig nFID )
 {
     if (poReader)
         return OGRLayer::GetFeature(nFID);
@@ -245,7 +246,7 @@ OGRFeature *  OGRXPlaneLayer::GetFeature( long nFID )
 /*                      GetFeatureCount()                               */
 /************************************************************************/
 
-int  OGRXPlaneLayer::GetFeatureCount( int bForce )
+GIntBig  OGRXPlaneLayer::GetFeatureCount( int bForce )
 {
     if (poReader == NULL && m_poFilterGeom == NULL && m_poAttrQuery == NULL)
     {
@@ -261,7 +262,7 @@ int  OGRXPlaneLayer::GetFeatureCount( int bForce )
 /*                           SetNextByIndex()                           */
 /************************************************************************/
 
-OGRErr OGRXPlaneLayer::SetNextByIndex( long nIndex )
+OGRErr OGRXPlaneLayer::SetNextByIndex( GIntBig nIndex )
 {
     if (poReader == NULL && m_poFilterGeom == NULL && m_poAttrQuery == NULL)
     {
diff --git a/ogr/ogrspatialreference.cpp b/ogr/ogrspatialreference.cpp
index 5f7e498..44627fa 100644
--- a/ogr/ogrspatialreference.cpp
+++ b/ogr/ogrspatialreference.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrspatialreference.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: ogrspatialreference.cpp 29104 2015-05-02 01:44:39Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRSpatialReference class.
@@ -33,8 +33,9 @@
 #include "cpl_csv.h"
 #include "cpl_http.h"
 #include "cpl_atomic_ops.h"
+#include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: ogrspatialreference.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: ogrspatialreference.cpp 29104 2015-05-02 01:44:39Z rouault $");
 
 // The current opinion is that WKT longitudes like central meridian
 // should be relative to greenwich, not the prime meridian in use. 
@@ -49,7 +50,7 @@ CPL_CVSID("$Id: ogrspatialreference.cpp 27044 2014-03-16 23:41:27Z rouault $");
 void OGRPrintDouble( char * pszStrBuf, double dfValue )
 
 {
-    sprintf( pszStrBuf, "%.16g", dfValue );
+    CPLsprintf( pszStrBuf, "%.16g", dfValue );
 
     int nLen = strlen(pszStrBuf);
 
@@ -59,7 +60,7 @@ void OGRPrintDouble( char * pszStrBuf, double dfValue )
         && (strcmp(pszStrBuf+nLen-6,"999999") == 0
             || strcmp(pszStrBuf+nLen-6,"000001") == 0) )
     {
-        sprintf( pszStrBuf, "%.15g", dfValue );
+        CPLsprintf( pszStrBuf, "%.15g", dfValue );
     }
 
     // force to user periods regardless of locale.
@@ -2279,6 +2280,8 @@ OGRErr OGRSpatialReference::importFromURNPart(const char* pszAuthority,
         return SetWellKnownGeogCS( pszCode );
     else if( EQUALN(pszCode,"CRS27",5) )
         return SetWellKnownGeogCS( pszCode );
+    else if( EQUALN(pszCode,"84",2) ) /* urn:ogc:def:crs:OGC:2:84 */
+        return SetWellKnownGeogCS( "CRS84" );
 
 /* -------------------------------------------------------------------- */
 /*      Handle auto codes.  We need to convert from format              */
@@ -2889,10 +2892,7 @@ double OGRSpatialReference::GetSemiMinor( OGRErr * pnErr ) const
     dfSemiMajor = GetSemiMajor( pnErr );
     dfInvFlattening = GetInvFlattening( pnErr );
 
-    if( ABS(dfInvFlattening) < 0.000000000001 )
-        return dfSemiMajor;
-    else
-        return dfSemiMajor * (1.0 - 1.0/dfInvFlattening);
+    return OSRCalcSemiMinorFromInvFlattening(dfSemiMajor, dfInvFlattening);
 }
 
 /************************************************************************/
@@ -5696,6 +5696,34 @@ OGRErr OSRSetWagner( OGRSpatialReferenceH hSRS,
 }
 
 /************************************************************************/
+/*                            SetQSC()                     */
+/************************************************************************/
+
+OGRErr OGRSpatialReference::SetQSC( double dfCenterLat, double dfCenterLong )
+
+{
+    SetProjection( SRS_PT_QSC );
+    SetNormProjParm( SRS_PP_LATITUDE_OF_ORIGIN, dfCenterLat );
+    SetNormProjParm( SRS_PP_CENTRAL_MERIDIAN, dfCenterLong );
+
+    return OGRERR_NONE;
+}
+
+/************************************************************************/
+/*                           OSRSetQSC()                   */
+/************************************************************************/
+
+OGRErr OSRSetQSC( OGRSpatialReferenceH hSRS,
+                       double dfCenterLat, double dfCenterLong )
+
+{
+    VALIDATE_POINTER1( hSRS, "OSRSetQSC", CE_Failure );
+
+    return ((OGRSpatialReference *) hSRS)->SetQSC(
+        dfCenterLat, dfCenterLong );
+}
+
+/************************************************************************/
 /*                            SetAuthority()                            */
 /************************************************************************/
 
@@ -7104,6 +7132,7 @@ OGRErr OGRSpatialReference::SetExtension( const char *pszTargetKey,
 CPL_C_START 
 void CleanupESRIDatumMappingTable();
 CPL_C_END
+static void CleanupSRSWGS84Thread();
 
 /**
  * \brief Cleanup cached SRS related memory.
@@ -7117,6 +7146,7 @@ void OSRCleanup( void )
     CleanupESRIDatumMappingTable();
     CSVDeaccess( NULL );
     OCTCleanupProjMutex();
+    CleanupSRSWGS84Thread();
 }
 
 /************************************************************************/
@@ -7478,3 +7508,98 @@ OGRErr OGRSpatialReference::importFromMICoordSys( const char *pszCoordSys )
     return OGRERR_UNSUPPORTED_OPERATION;
 #endif    
 }
+
+/************************************************************************/
+/*                        OSRCalcInvFlattening()                        */
+/************************************************************************/
+
+/**
+ * \brief Compute inverse flattening from semi-major and semi-minor axis
+ *
+ * @param dfSemiMajor Semi-major axis length.
+ * @param dfSemiMinor Semi-minor axis length.
+ *
+ * @return inverse flattening, or 0 if both axis are equal.
+ * @since GDAL 2.0
+ */
+
+double OSRCalcInvFlattening( double dfSemiMajor, double dfSemiMinor )
+{
+    if( fabs(dfSemiMajor-dfSemiMinor) < 1e-1 )
+        return 0;
+    else if( dfSemiMajor <= 0 || dfSemiMinor <= 0 || dfSemiMinor > dfSemiMajor )
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg,
+                 "OSRCalcInvFlattening(): Wrong input values");
+        return 0;
+    }
+    else
+        return dfSemiMajor / (dfSemiMajor - dfSemiMinor);
+}
+
+/************************************************************************/
+/*                        OSRCalcInvFlattening()                        */
+/************************************************************************/
+
+/**
+ * \brief Compute semi-minor axis from semi-major axis and inverse flattening.
+ *
+ * @param dfSemiMajor Semi-major axis length.
+ * @param dfInvFlattening Inverse flattening or 0 for sphere.
+ *
+ * @return semi-minor axis
+ * @since GDAL 2.0
+ */
+
+double OSRCalcSemiMinorFromInvFlattening( double dfSemiMajor, double dfInvFlattening )
+{
+    if( fabs(dfInvFlattening) < 0.000000000001 )
+        return dfSemiMajor;
+    else if( dfSemiMajor <= 0.0 || dfInvFlattening <= 1.0 )
+    {
+        CPLError(CE_Failure, CPLE_IllegalArg,
+                 "OSRCalcSemiMinorFromInvFlattening(): Wrong input values");
+        return dfSemiMajor;
+    }
+    else
+        return dfSemiMajor * (1.0 - 1.0/dfInvFlattening);
+}
+
+/************************************************************************/
+/*                        GetWGS84SRS()                                 */
+/************************************************************************/
+
+static OGRSpatialReference* poSRSWGS84 = NULL;
+static CPLMutex* hMutex = NULL;
+
+/**
+ * \brief Returns an instance of a SRS object with WGS84 WKT.
+ *
+ * The reference counter of the returned object is not increased by this operation.
+ *
+ * @return instance.
+ * @since GDAL 2.0
+ */
+
+OGRSpatialReference* OGRSpatialReference::GetWGS84SRS()
+{
+    CPLMutexHolderD(&hMutex);
+    if( poSRSWGS84 == NULL )
+        poSRSWGS84 = new OGRSpatialReference(SRS_WKT_WGS84);
+    return poSRSWGS84;
+}
+
+/************************************************************************/
+/*                        CleanupSRSWGS84Thread()                       */
+/************************************************************************/
+
+static void CleanupSRSWGS84Thread()
+{
+    if( hMutex != NULL )
+    {
+        poSRSWGS84->Release();
+        poSRSWGS84 = NULL;
+        CPLDestroyMutex(hMutex);
+        hMutex = NULL;
+    }
+}
diff --git a/ogr/ogrsurface.cpp b/ogr/ogrsurface.cpp
index 657da28..ee0b99d 100644
--- a/ogr/ogrsurface.cpp
+++ b/ogr/ogrsurface.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrsurface.cpp 19399 2010-04-13 18:35:24Z rouault $
+ * $Id: ogrsurface.cpp 27959 2014-11-14 18:29:21Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  The OGRSurface class.
@@ -55,3 +55,43 @@
  *
  * @return OGRERR_NONE if it succeeds or OGRERR_FAILURE otherwise. 
  */
+
+/************************************************************************/
+/*                          CastToPolygon()                             */
+/************************************************************************/
+
+/**
+ * \brief Cast to polygon
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poSurface the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRPolygon* OGRSurface::CastToPolygon(OGRSurface* poSurface)
+{
+    OGRSurfaceCasterToPolygon pfn = poSurface->GetCasterToPolygon();
+    return pfn(poSurface);
+}
+
+/************************************************************************/
+/*                          CastToCurvePolygon()                        */
+/************************************************************************/
+
+/**
+ * \brief Cast to curve polygon
+ *
+ * The passed in geometry is consumed and a new one returned (or NULL in case
+ * of failure)
+ * 
+ * @param poSurface the input geometry - ownership is passed to the method.
+ * @return new geometry.
+ */
+
+OGRCurvePolygon* OGRSurface::CastToCurvePolygon(OGRSurface* poSurface)
+{
+    OGRSurfaceCasterToCurvePolygon pfn = poSurface->GetCasterToCurvePolygon();
+    return pfn(poSurface);
+}
diff --git a/ogr/ogrutils.cpp b/ogr/ogrutils.cpp
index 2a6d043..54215e7 100644
--- a/ogr/ogrutils.cpp
+++ b/ogr/ogrutils.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrutils.cpp 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: ogrutils.cpp 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Utility functions for OGR classes, including some related to
@@ -41,7 +41,7 @@
 # include "ogrsf_frmts.h"
 #endif /* OGR_ENABLED */
 
-CPL_CVSID("$Id: ogrutils.cpp 27729 2014-09-24 00:40:16Z goatbar $");
+CPL_CVSID("$Id: ogrutils.cpp 28900 2015-04-14 09:40:34Z rouault $");
 
 /************************************************************************/
 /*                        OGRFormatDouble()                             */
@@ -54,11 +54,11 @@ void OGRFormatDouble( char *pszBuffer, int nBufferLen, double dfVal, char chDeci
     char szFormat[16];
     sprintf(szFormat, "%%.%df", nPrecision);
 
-    int ret = snprintf(pszBuffer, nBufferLen, szFormat, dfVal);
+    int ret = CPLsnprintf(pszBuffer, nBufferLen, szFormat, dfVal);
     /* Windows CRT doesn't conform with C99 and return -1 when buffer is truncated */
     if (ret >= nBufferLen || ret == -1)
     {
-        snprintf(pszBuffer, nBufferLen, "%s", "too_big");
+        CPLsnprintf(pszBuffer, nBufferLen, "%s", "too_big");
         return;
     }
 
@@ -133,7 +133,7 @@ void OGRFormatDouble( char *pszBuffer, int nBufferLen, double dfVal, char chDeci
                 nPrecision --;
                 nTruncations ++;
                 sprintf(szFormat, "%%.%df", nPrecision);
-                snprintf(pszBuffer, nBufferLen, szFormat, dfVal);
+                CPLsnprintf(pszBuffer, nBufferLen, szFormat, dfVal);
                 continue;
             }
             else if (i - 9 > iDotPos && /*pszBuffer[i-1] == '9' && */
@@ -149,7 +149,7 @@ void OGRFormatDouble( char *pszBuffer, int nBufferLen, double dfVal, char chDeci
                 nPrecision --;
                 nTruncations ++;
                 sprintf(szFormat, "%%.%df", nPrecision);
-                snprintf(pszBuffer, nBufferLen, szFormat, dfVal);
+                CPLsnprintf(pszBuffer, nBufferLen, szFormat, dfVal);
                 continue;
             }
         }
@@ -489,6 +489,7 @@ void OGRFree( void * pMemory )
  *  
  *  --version: report version of GDAL in use. 
  *  --license: report GDAL license info.
+ *  --format [format]: report details of one format driver. 
  *  --formats: report all format drivers configured.
  *  --optfile filename: expand an option file into the argument list. 
  *  --config key value: set system configuration option. 
@@ -504,7 +505,7 @@ void OGRFree( void * pMemory )
  *
  *  int main( int argc, char ** argv )
  *  { 
- *    OGRAllRegister();
+ *    OGRRegisterAll();
  *
  *    argc = OGRGeneralCmdLineProcessor( argc, &argv, 0 );
  *    if( argc < 1 )
@@ -521,260 +522,8 @@ void OGRFree( void * pMemory )
 int OGRGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
 
 {
-    char **papszReturn = NULL;
-    int  iArg;
-    char **papszArgv = *ppapszArgv;
-
     (void) nOptions;
-    
-/* -------------------------------------------------------------------- */
-/*      Preserve the program name.                                      */
-/* -------------------------------------------------------------------- */
-    papszReturn = CSLAddString( papszReturn, papszArgv[0] );
-
-/* ==================================================================== */
-/*      Loop over all arguments.                                        */
-/* ==================================================================== */
-    for( iArg = 1; iArg < nArgc; iArg++ )
-    {
-/* -------------------------------------------------------------------- */
-/*      --version                                                       */
-/* -------------------------------------------------------------------- */
-        if( EQUAL(papszArgv[iArg],"--version") )
-        {
-            printf( "%s\n", GDALVersionInfo( "--version" ) );
-            CSLDestroy( papszReturn );
-            return 0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --license                                                       */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--license") )
-        {
-            printf( "%s\n", GDALVersionInfo( "LICENSE" ) );
-            CSLDestroy( papszReturn );
-            return 0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --config                                                        */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--config") )
-        {
-            if( iArg + 2 >= nArgc )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "--config option given without a key and value argument." );
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-
-            CPLSetConfigOption( papszArgv[iArg+1], papszArgv[iArg+2] );
-
-            iArg += 2;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --mempreload                                                    */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--mempreload") )
-        {
-            int i;
-
-            if( iArg + 1 >= nArgc )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "--mempreload option given without directory path.");
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-            
-            char **papszFiles = CPLReadDir( papszArgv[iArg+1] );
-            if( CSLCount(papszFiles) == 0 )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "--mempreload given invalid or empty directory.");
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-                
-            for( i = 0; papszFiles[i] != NULL; i++ )
-            {
-                CPLString osOldPath, osNewPath;
-                VSIStatBufL sStatBuf;
-                
-                if( EQUAL(papszFiles[i],".") || EQUAL(papszFiles[i],"..") )
-                    continue;
-
-                osOldPath = CPLFormFilename( papszArgv[iArg+1], 
-                                             papszFiles[i], NULL );
-                osNewPath.Printf( "/vsimem/%s", papszFiles[i] );
-
-                if( VSIStatL( osOldPath, &sStatBuf ) != 0
-                    || VSI_ISDIR( sStatBuf.st_mode ) )
-                {
-                    CPLDebug( "VSI", "Skipping preload of %s.", 
-                              osOldPath.c_str() );
-                    continue;
-                }
-
-                CPLDebug( "VSI", "Preloading %s to %s.", 
-                          osOldPath.c_str(), osNewPath.c_str() );
-
-                if( CPLCopyFile( osNewPath, osOldPath ) != 0 )
-                    return -1;
-            }
-            
-            CSLDestroy( papszFiles );
-            iArg += 1;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --debug                                                         */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--debug") )
-        {
-            if( iArg + 1 >= nArgc )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "--debug option given without debug level." );
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-
-            CPLSetConfigOption( "CPL_DEBUG", papszArgv[iArg+1] );
-            iArg += 1;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --optfile                                                       */
-/*                                                                      */
-/*      Annoyingly the options inserted by --optfile will *not* be      */
-/*      processed properly if they are general options.                 */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--optfile") )
-        {
-            const char *pszLine;
-            FILE *fpOptFile;
-
-            if( iArg + 1 >= nArgc )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "--optfile option given without filename." );
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-
-            fpOptFile = VSIFOpen( papszArgv[iArg+1], "rb" );
-
-            if( fpOptFile == NULL )
-            {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                          "Unable to open optfile '%s'.\n%s",
-                          papszArgv[iArg+1], VSIStrerror( errno ) );
-                CSLDestroy( papszReturn );
-                return -1;
-            }
-            
-            while( (pszLine = CPLReadLine( fpOptFile )) != NULL )
-            {
-                char **papszTokens;
-                int i;
-
-                if( pszLine[0] == '#' || strlen(pszLine) == 0 )
-                    continue;
-
-                papszTokens = CSLTokenizeString( pszLine );
-                for( i = 0; papszTokens != NULL && papszTokens[i] != NULL; i++)
-                    papszReturn = CSLAddString( papszReturn, papszTokens[i] );
-                CSLDestroy( papszTokens );
-            }
-
-            VSIFClose( fpOptFile );
-                
-            iArg += 1;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --formats                                                       */
-/* -------------------------------------------------------------------- */
-#ifdef OGR_ENABLED
-        else if( EQUAL(papszArgv[iArg], "--formats") )
-        {
-            int iDr;
-
-            printf( "Supported Formats:\n" );
-
-            OGRSFDriverRegistrar *poR = OGRSFDriverRegistrar::GetRegistrar();
-        
-            for( iDr = 0; iDr < poR->GetDriverCount(); iDr++ )
-            {
-                OGRSFDriver *poDriver = poR->GetDriver(iDr);
-
-                if( poDriver->TestCapability( ODrCCreateDataSource ) )
-                    printf( "  -> \"%s\" (read/write)\n", 
-                            poDriver->GetName() );
-                else
-                    printf( "  -> \"%s\" (readonly)\n", 
-                            poDriver->GetName() );
-            }
-
-            CSLDestroy( papszReturn );
-            return 0;
-        }
-#endif /* OGR_ENABLED */
-
-/* -------------------------------------------------------------------- */
-/*      --locale                                                        */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--locale") && iArg < nArgc-1 )
-        {
-            CPLsetlocale( LC_ALL, papszArgv[++iArg] );
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --pause - "hit enter" pause useful to connect a debugger.       */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--pause") )
-        {
-            printf( "Hit <ENTER> to Continue.\n" );
-            CPLReadLine( stdin );
-        }
-
-/* -------------------------------------------------------------------- */
-/*      --help-general                                                  */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(papszArgv[iArg],"--help-general") )
-        {
-            printf( "Generic GDAL/OGR utility command options:\n" );
-            printf( "  --version: report version of GDAL/OGR in use.\n" );
-            printf( "  --license: report GDAL/OGR license info.\n" );
-#ifdef OGR_ENABLED
-            printf( "  --formats: report all configured format drivers.\n" );
-#endif /* OGR_ENABLED */
-            printf( "  --optfile filename: expand an option file into the argument list.\n" );
-            printf( "  --config key value: set system configuration option.\n" );
-            printf( "  --debug [on/off/value]: set debug level.\n" );
-            printf( "  --pause: wait for user input, time to attach debugger\n" );
-            printf( "  --locale [locale]: install locale for debugging (ie. en_US.UTF-8)\n" );
-            printf( "  --help-general: report detailed help on general options.\n" );
-            CSLDestroy( papszReturn );
-            return 0;
-        }
-
-/* -------------------------------------------------------------------- */
-/*      carry through unrecognised options.                             */
-/* -------------------------------------------------------------------- */
-        else
-        {
-            papszReturn = CSLAddString( papszReturn, papszArgv[iArg] );
-        }
-    }
-
-    *ppapszArgv = papszReturn;
-
-    return CSLCount( *ppapszArgv );
+    return GDALGeneralCmdLineProcessor( nArgc, ppapszArgv, GDAL_OF_VECTOR );
 }
 
 /************************************************************************/
@@ -790,10 +539,11 @@ int OGRGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
  * into the OGRField.Date format suitable for use with OGR.  Generally 
  * speaking this function is expecting values like:
  * 
- *   YYYY-MM-DD HH:MM:SS+nn
+ *   YYYY-MM-DD HH:MM:SS[.sss]+nn
+ *   or YYYY-MM-DDTHH:MM:SS[.sss]Z (ISO 8601 format)
  *
  * The seconds may also have a decimal portion (which is ignored).  And
- * just dates (YYYY-MM-DD) or just times (HH:MM:SS) are also supported. 
+ * just dates (YYYY-MM-DD) or just times (HH:MM:SS[.sss]) are also supported. 
  * The date may also be in YYYY/MM/DD format.  If the year is less than 100
  * and greater than 30 a "1900" century value will be set.  If it is less than
  * 30 and greater than -1 then a "2000" century value will be set.  In 
@@ -802,16 +552,18 @@ int OGRGeneralCmdLineProcessor( int nArgc, char ***ppapszArgv, int nOptions )
  * a reasonable default form of processing.
  *
  * The value of psField will be indeterminate if the function fails (returns
- * FALSE).  
+ * FALSE).
  *
  * @param pszInput the input date string.
  * @param psField the OGRField that will be updated with the parsed result.
- * @param nOptions parsing options, for now always 0. 
+ * @param nOptions parsing options, for now always 0.
  *
  * @return TRUE if apparently successful or FALSE on failure.
  */
 
-int OGRParseDate( const char *pszInput, OGRField *psField, CPL_UNUSED int nOptions )
+int OGRParseDate( const char *pszInput,
+                  OGRField *psField,
+                  CPL_UNUSED int nOptions )
 {
     int bGotSomething = FALSE;
 
@@ -822,7 +574,8 @@ int OGRParseDate( const char *pszInput, OGRField *psField, CPL_UNUSED int nOptio
     psField->Date.Minute = 0;
     psField->Date.Second = 0;
     psField->Date.TZFlag = 0;
-    
+    psField->Date.Reserved = 0;
+
 /* -------------------------------------------------------------------- */
 /*      Do we have a date?                                              */
 /* -------------------------------------------------------------------- */
@@ -870,6 +623,10 @@ int OGRParseDate( const char *pszInput, OGRField *psField, CPL_UNUSED int nOptio
             pszInput++;
 
         bGotSomething = TRUE;
+        
+        /* If ISO 8601 format */
+        if( *pszInput == 'T' )
+            pszInput ++;
     }
 
 /* -------------------------------------------------------------------- */
@@ -897,18 +654,26 @@ int OGRParseDate( const char *pszInput, OGRField *psField, CPL_UNUSED int nOptio
 
         while( *pszInput >= '0' && *pszInput <= '9' ) 
             pszInput++;
-        if( *pszInput != ':' )
-            return FALSE;
-        else 
+        if( *pszInput == ':' )
+        {
             pszInput++;
 
-        psField->Date.Second = (GByte)atoi(pszInput);
-        if( psField->Date.Second > 59 )
-            return FALSE;
+            psField->Date.Second = (float)CPLAtof(pszInput);
+            if( psField->Date.Second > 61 )
+                return FALSE;
 
-        while( (*pszInput >= '0' && *pszInput <= '9')
-               || *pszInput == '.' )
-            pszInput++;
+            while( (*pszInput >= '0' && *pszInput <= '9')
+                || *pszInput == '.' )
+            {
+                pszInput++;
+            }
+
+            /* If ISO 8601 format */
+            if( *pszInput == 'Z' )
+            {
+                psField->Date.TZFlag = 100;
+            }
+        }
 
         bGotSomething = TRUE;
     }
@@ -971,8 +736,7 @@ int OGRParseDate( const char *pszInput, OGRField *psField, CPL_UNUSED int nOptio
 /************************************************************************/
 
 int OGRParseXMLDateTime( const char* pszXMLDateTime,
-                               int *pnYear, int *pnMonth, int *pnDay,
-                               int *pnHour, int *pnMinute, float* pfSecond, int *pnTZ)
+                         OGRField* psField)
 {
     int year = 0, month = 0, day = 0, hour = 0, minute = 0, TZHour, TZMinute;
     float second = 0;
@@ -1011,13 +775,14 @@ int OGRParseXMLDateTime( const char* pszXMLDateTime,
 
     if (bRet)
     {
-        if (pnYear) *pnYear = year;
-        if (pnMonth) *pnMonth = month;
-        if (pnDay) *pnDay = day;
-        if (pnHour) *pnHour = hour;
-        if (pnMinute) *pnMinute = minute;
-        if (pfSecond) *pfSecond = second;
-        if (pnTZ) *pnTZ = TZ;
+        psField->Date.Year = (GInt16)year;
+        psField->Date.Month = (GByte)month;
+        psField->Date.Day = (GByte)day;
+        psField->Date.Hour = (GByte)hour;
+        psField->Date.Minute = (GByte)minute;
+        psField->Date.Second = second;
+        psField->Date.TZFlag = (GByte)TZ;
+        psField->Date.Reserved = 0;
     }
 
     return bRet;
@@ -1030,9 +795,7 @@ int OGRParseXMLDateTime( const char* pszXMLDateTime,
 static const char* aszMonthStr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
 
-int OGRParseRFC822DateTime( const char* pszRFC822DateTime,
-                                  int *pnYear, int *pnMonth, int *pnDay,
-                                  int *pnHour, int *pnMinute, int *pnSecond, int *pnTZ)
+int OGRParseRFC822DateTime( const char* pszRFC822DateTime, OGRField* psField )
 {
     /* Following http://asg.web.cmu.edu/rfc/rfc822.html#sec-5 : [Fri,] 28 Dec 2007 05:24[:17] GMT */
     char** papszTokens = CSLTokenizeStringComplex( pszRFC822DateTime, " ,:", TRUE, FALSE );
@@ -1115,13 +878,14 @@ int OGRParseRFC822DateTime( const char* pszRFC822DateTime,
                 }
             }
 
-            if (pnYear) *pnYear = year;
-            if (pnMonth) *pnMonth = month;
-            if (pnDay) *pnDay = day;
-            if (pnHour) *pnHour = hour;
-            if (pnMinute) *pnMinute = minute;
-            if (pnSecond) *pnSecond = second;
-            if (pnTZ) *pnTZ = TZ;
+            psField->Date.Year = (GInt16)year;
+            psField->Date.Month = (GByte)month;
+            psField->Date.Day = (GByte)day;
+            psField->Date.Hour = (GByte)hour;
+            psField->Date.Minute = (GByte)minute;
+            psField->Date.Second = second;
+            psField->Date.TZFlag = (GByte)TZ;
+            psField->Date.Reserved = 0;
         }
     }
     CSLDestroy(papszTokens);
@@ -1162,16 +926,19 @@ int OGRGetDayOfWeek(int day, int month, int year)
 /*                         OGRGetRFC822DateTime()                       */
 /************************************************************************/
 
-char* OGRGetRFC822DateTime(int year, int month, int day, int hour, int minute, int second, int TZFlag)
+char* OGRGetRFC822DateTime(const OGRField* psField)
 {
     char* pszTZ = NULL;
     const char* aszDayOfWeek[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
 
-    int dayofweek = OGRGetDayOfWeek(day, month, year);
+    int dayofweek = OGRGetDayOfWeek(psField->Date.Day, psField->Date.Month,
+                                    psField->Date.Year);
 
+    int month = psField->Date.Month;
     if (month < 1 || month > 12)
         month = 1;
 
+    int TZFlag = psField->Date.TZFlag;
     if (TZFlag == 0 || TZFlag == 100)
     {
         pszTZ = CPLStrdup("GMT");
@@ -1185,7 +952,9 @@ char* OGRGetRFC822DateTime(int year, int month, int day, int hour, int minute, i
                                         TZHour, TZMinute));
     }
     char* pszRet = CPLStrdup(CPLSPrintf("%s, %02d %s %04d %02d:%02d:%02d %s",
-                     aszDayOfWeek[dayofweek], day, aszMonthStr[month - 1], year, hour, minute, second, pszTZ));
+                     aszDayOfWeek[dayofweek], psField->Date.Day, aszMonthStr[month - 1],
+                     psField->Date.Year, psField->Date.Hour,
+                     psField->Date.Minute, (int)psField->Date.Second, pszTZ));
     CPLFree(pszTZ);
     return pszRet;
 }
@@ -1194,22 +963,38 @@ char* OGRGetRFC822DateTime(int year, int month, int day, int hour, int minute, i
 /*                            OGRGetXMLDateTime()                       */
 /************************************************************************/
 
-char* OGRGetXMLDateTime(int year, int month, int day, int hour, int minute, int second, int TZFlag)
+char* OGRGetXMLDateTime(const OGRField* psField)
 {
     char* pszRet;
+    int year = psField->Date.Year;
+    int month = psField->Date.Month;
+    int day = psField->Date.Day;
+    int hour = psField->Date.Hour;
+    int minute = psField->Date.Minute;
+    float second = psField->Date.Second;
+    int TZFlag = psField->Date.TZFlag;
     if (TZFlag == 0 || TZFlag == 100)
     {
-        pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
-                           year, month, day, hour, minute, second));
+        if( OGR_GET_MS(second) )
+            pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%06.3fZ",
+                                    year, month, day, hour, minute, second));
+        else
+            pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02dZ",
+                                    year, month, day, hour, minute, (int)second));
     }
     else
     {
         int TZOffset = ABS(TZFlag - 100) * 15;
         int TZHour = TZOffset / 60;
         int TZMinute = TZOffset - TZHour * 60;
-        pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+        if( OGR_GET_MS(second) )
+            pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%06.3f%c%02d:%02d",
                            year, month, day, hour, minute, second,
                            (TZFlag > 100) ? '+' : '-', TZHour, TZMinute));
+        else
+            pszRet = CPLStrdup(CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+                            year, month, day, hour, minute, (int)second,
+                            (TZFlag > 100) ? '+' : '-', TZHour, TZMinute));
     }
     return pszRet;
 }
@@ -1294,10 +1079,10 @@ int OGRCompareDate(   OGRField *psFirstTuple,
 /*                        OGRFastAtof()                                 */
 /************************************************************************/
 
-/* On Windows, atof() is very slow if the number */
+/* On Windows, CPLAtof() is very slow if the number */
 /* is followed by other long content. */
 /* So we just extract the number into a short string */
-/* before calling atof() on it */
+/* before calling CPLAtof() on it */
 static
 double OGRCallAtofOnShortString(const char* pszStr)
 {
@@ -1314,16 +1099,16 @@ double OGRCallAtofOnShortString(const char* pszStr)
     {
         szTemp[nCounter++] = *(p++);
         if (nCounter == 127)
-            return atof(pszStr);
+            return CPLAtof(pszStr);
     }
     szTemp[nCounter] = '\0';
-    return atof(szTemp);
+    return CPLAtof(szTemp);
 }
 
 /** Same contract as CPLAtof, except than it doesn't always call the
- *  system atof() that may be slow on some platforms. For simple but
+ *  system CPLAtof() that may be slow on some platforms. For simple but
  *  common strings, it'll use a faster implementation (up to 20x faster
- *  than atof() on MS runtime libraries) that has no garanty to return
+ *  than CPLAtof() on MS runtime libraries) that has no garanty to return
  *  exactly the same floating point number.
  */
  
@@ -1426,7 +1211,8 @@ OGRErr OGRCheckPermutation(int* panPermutation, int nSize)
 }
 
 
-OGRErr OGRReadWKBGeometryType( unsigned char * pabyData, OGRwkbGeometryType *peGeometryType, OGRBoolean *pbIs3D )
+OGRErr OGRReadWKBGeometryType( unsigned char * pabyData, OGRwkbVariant eWkbVariant,
+                               OGRwkbGeometryType *peGeometryType, OGRBoolean *pbIs3D )
 {
     if ( ! (peGeometryType && pbIs3D) )
         return OGRERR_FAILURE;
@@ -1453,33 +1239,116 @@ OGRErr OGRReadWKBGeometryType( unsigned char * pabyData, OGRwkbGeometryType *peG
     }
     
     /* Old-style OGC z-bit is flipped? */
-    if ( wkb25DBit & iRawType )
+    if ( wkb25DBitInternalUse & iRawType )
     {
         /* Clean off top 3 bytes */
         iRawType &= 0x000000FF;
         bIs3D = TRUE;        
     }
     
-    /* ISO SQL/MM style Z types (between 1001 and 1007)? */
-    if ( iRawType >= 1001 && iRawType <= 1007 )
+    /* ISO SQL/MM style Z types (between 1001 and 1012)? */
+    if ( iRawType >= 1001 && iRawType <= (int)wkbMultiSurfaceZ )
     {
         /* Remove the ISO padding */
         iRawType -= 1000;
         bIs3D = TRUE;
     }
     
+    /*  ISO SQL/MM Part3 draft -> Deprecated */
+    /* See http://jtc1sc32.org/doc/N1101-1150/32N1107-WD13249-3--spatial.pdf  */
+    if (iRawType == 1000001)
+        iRawType = wkbCircularString;
+    else if (iRawType == 1000002)
+        iRawType = wkbCompoundCurve;
+    else if (iRawType == 1000003)
+        iRawType = wkbCurvePolygon;
+    else if (iRawType == 1000004)
+        iRawType = wkbMultiCurve;
+    else if (iRawType == 1000005)
+        iRawType = wkbMultiSurface;
+    else if (iRawType == 3000001)
+    {
+        iRawType = wkbPoint;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000002)
+    {
+        iRawType = wkbLineString;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000003)
+    {
+        iRawType = wkbCircularString;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000004)
+    {
+        iRawType = wkbCompoundCurve;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000005)
+    {
+        iRawType = wkbPolygon;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000006)
+    {
+        iRawType = wkbCurvePolygon;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000007)
+    {
+        iRawType = wkbMultiPoint;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000008)
+    {
+        iRawType = wkbMultiCurve;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000009)
+    {
+        iRawType = wkbMultiLineString;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000010)
+    {
+        iRawType = wkbMultiSurface;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000011)
+    {
+        iRawType = wkbMultiPolygon;
+        bIs3D = TRUE;
+    }
+    else if (iRawType == 3000012)
+    {
+        iRawType = wkbGeometryCollection;
+        bIs3D = TRUE;
+    }
+    
     /* Sometimes the Z flag is in the 2nd byte? */
-    if ( iRawType & (wkb25DBit >> 16) )
+    if ( iRawType & (wkb25DBitInternalUse >> 16) )
     {
         /* Clean off top 3 bytes */
         iRawType &= 0x000000FF;
         bIs3D = TRUE;        
     }
+    
+    if( eWkbVariant == wkbVariantPostGIS1 )
+    {
+        if( iRawType == POSTGIS15_CURVEPOLYGON )
+            iRawType = wkbCurvePolygon;
+        else if( iRawType == POSTGIS15_MULTICURVE )
+            iRawType = wkbMultiCurve;
+        else if( iRawType == POSTGIS15_MULTISURFACE )
+            iRawType = wkbMultiSurface;
+    }
 
     /* Nothing left but (hopefully) basic 2D types */
 
     /* What if what we have is still out of range? */
-    if ( iRawType < 1 || iRawType > (int)wkbGeometryCollection )
+    if ( iRawType < 1 || iRawType > (int)wkbMultiSurface )
     {
         CPLError(CE_Failure, CPLE_NotSupported, "Unsupported WKB type %d", iRawType);            
         return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
diff --git a/ogr/osr_cs_wkt.c b/ogr/osr_cs_wkt.c
index ac83385..f84d4bf 100644
--- a/ogr/osr_cs_wkt.c
+++ b/ogr/osr_cs_wkt.c
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: osr_cs_wkt.c 27729 2014-09-24 00:40:16Z goatbar $
+ * $Id: osr_cs_wkt.c 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  CS WKT parser
@@ -101,7 +101,8 @@ static const osr_cs_wkt_tokens tokens[] =
 /*                         osr_cs_wkt_lex()                             */
 /************************************************************************/
 
-int osr_cs_wkt_lex(CPL_UNUSED YYSTYPE* pNode, osr_cs_wkt_parse_context *context)
+int osr_cs_wkt_lex(CPL_UNUSED YYSTYPE* pNode,
+                   osr_cs_wkt_parse_context *context)
 {
     size_t i;
     const char *pszInput = context->pszNext;
diff --git a/ogr/osr_cs_wkt_grammar.y b/ogr/osr_cs_wkt_grammar.y
index ff13f31..a2e939d 100644
--- a/ogr/osr_cs_wkt_grammar.y
+++ b/ogr/osr_cs_wkt_grammar.y
@@ -1,6 +1,6 @@
 %{
 /******************************************************************************
- * $Id: osr_cs_wkt_grammar.y 26439 2013-09-11 11:10:48Z rouault $
+ * $Id: osr_cs_wkt_grammar.y 27975 2014-11-17 12:37:48Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  CS WKT parser grammar
@@ -135,7 +135,7 @@ horz_cs:
 /* opt_extension is an extension of the CT spec */
 projected_cs:
     T_PROJCS begin_node_name ',' geographic_cs ',' projection ','
-                    opt_parameter_list_linear_unit opt_twin_axis_authority_extension end_node
+                    opt_parameter_list_linear_unit opt_twin_axis_extension_authority end_node
 
 opt_parameter_list_linear_unit:
     linear_unit
@@ -145,13 +145,13 @@ parameter_list_linear_unit:
     parameter ',' parameter_list_linear_unit
   | parameter ',' linear_unit
 
-opt_twin_axis_authority_extension:
-    | ',' twin_axis opt_authority_extension
-    | ',' authority opt_extension
-    | ',' extension
+opt_twin_axis_extension_authority:
+    | ',' twin_axis opt_extension_authority
+    | ',' extension opt_authority
+    | ',' authority
 
-opt_extension:
-    | ',' extension
+opt_authority:
+    | ',' authority
 
 extension:
     T_EXTENSION begin_node_name ',' T_STRING end_node
@@ -159,20 +159,17 @@ extension:
 projection:
     T_PROJECTION begin_node_name opt_authority end_node
 
-opt_authority:
-    | ',' authority
-
 geographic_cs:
     T_GEOGCS begin_node_name',' datum ',' prime_meridian ','
-                    angular_unit opt_twin_axis_authority_extension end_node
+                    angular_unit opt_twin_axis_extension_authority end_node
 
 datum:
     T_DATUM begin_node_name ',' spheroid opt_towgs84_authority_extension end_node
 
 opt_towgs84_authority_extension:
-    | ',' towgs84 opt_authority_extension
-    | ',' authority opt_extension
-    | ',' extension
+    | ',' towgs84 opt_extension_authority
+    | ',' extension opt_authority
+    | ',' authority
 
 spheroid:
     T_SPHEROID begin_node_name ',' semi_major_axis ','
@@ -224,17 +221,17 @@ opt_axis_authority:
     | ',' authority
 
 vert_datum:
-    T_VERT_DATUM begin_node_name ',' datum_type opt_authority_extension end_node
+    T_VERT_DATUM begin_node_name ',' datum_type opt_extension_authority end_node
 
-opt_authority_extension:
-    | ',' authority opt_extension
-    | ',' extension
+opt_extension_authority:
+    | ',' extension opt_authority
+    | ',' authority
 
 datum_type:
     T_NUMBER
 
 compd_cs:
-    T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_authority_extension end_node
+    T_COMPD_CS begin_node_name ',' head_cs ',' tail_cs opt_extension_authority end_node
 
 head_cs:
     coordinate_system
diff --git a/ogr/osr_cs_wkt_parser.c b/ogr/osr_cs_wkt_parser.c
index b0c1021..68dacd3 100644
--- a/ogr/osr_cs_wkt_parser.c
+++ b/ogr/osr_cs_wkt_parser.c
@@ -3,7 +3,6 @@
 /* Bison implementation for Yacc-like parsers in C
 
    Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
- * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -72,7 +71,7 @@
 
 
 /******************************************************************************
- * $Id: osr_cs_wkt_parser.c 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: osr_cs_wkt_parser.c 27975 2014-11-17 12:37:48Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  CS WKT parser grammar
@@ -406,16 +405,16 @@ union yyalloc
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  27
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   198
+#define YYLAST   197
 
 /* YYNTOKENS -- Number of terminals.  */
 #define YYNTOKENS  32
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  67
+#define YYNNTS  66
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  98
+#define YYNRULES  96
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  254
+#define YYNSTATES  252
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
@@ -468,12 +467,12 @@ static const yytype_uint16 yyrline[] =
      101,   104,   107,   108,   111,   113,   114,   115,   118,   121,
      125,   130,   130,   130,   130,   130,   130,   133,   133,   137,
      141,   142,   145,   146,   148,   149,   150,   151,   153,   154,
-     157,   160,   162,   163,   166,   170,   172,   173,   174,   175,
-     178,   182,   185,   188,   191,   194,   197,   200,   203,   206,
-     209,   210,   211,   214,   217,   220,   222,   223,   224,   227,
-     229,   230,   231,   234,   237,   240,   243,   245,   248,   253,
-     256,   258,   261,   264,   267,   270,   273,   276,   279,   282,
-     285,   288,   291,   294,   297,   299,   300,   301,   304
+     157,   160,   163,   167,   169,   170,   171,   172,   175,   179,
+     182,   185,   188,   191,   194,   197,   200,   203,   206,   207,
+     208,   211,   214,   217,   219,   220,   221,   224,   226,   227,
+     228,   231,   234,   237,   240,   242,   245,   250,   253,   255,
+     258,   261,   264,   267,   270,   273,   276,   279,   282,   285,
+     288,   291,   294,   296,   297,   298,   301
 };
 #endif
 
@@ -494,13 +493,13 @@ static const char *const yytname[] =
   "opt_parameter_list", "concat_mt", "opt_math_transform_list", "inv_mt",
   "passthrough_mt", "integer", "coordinate_system", "horz_cs",
   "projected_cs", "opt_parameter_list_linear_unit",
-  "parameter_list_linear_unit", "opt_twin_axis_authority_extension",
-  "opt_extension", "extension", "projection", "opt_authority",
-  "geographic_cs", "datum", "opt_towgs84_authority_extension", "spheroid",
-  "semi_major_axis", "inverse_flattening", "prime_meridian", "longitude",
-  "angular_unit", "linear_unit", "unit", "conversion_factor",
-  "geocentric_cs", "opt_three_axis_authority", "three_axis", "authority",
-  "vert_cs", "opt_axis_authority", "vert_datum", "opt_authority_extension",
+  "parameter_list_linear_unit", "opt_twin_axis_extension_authority",
+  "opt_authority", "extension", "projection", "geographic_cs", "datum",
+  "opt_towgs84_authority_extension", "spheroid", "semi_major_axis",
+  "inverse_flattening", "prime_meridian", "longitude", "angular_unit",
+  "linear_unit", "unit", "conversion_factor", "geocentric_cs",
+  "opt_three_axis_authority", "three_axis", "authority", "vert_cs",
+  "opt_axis_authority", "vert_datum", "opt_extension_authority",
   "datum_type", "compd_cs", "head_cs", "tail_cs", "twin_axis", "axis",
   "towgs84", "towgs84_parameters", "three_parameters", "seven_parameters",
   "dx", "dy", "dz", "ex", "ey", "ez", "ppm", "fitted_cs", "to_base",
@@ -520,10 +519,10 @@ static const yytype_uint16 yytoknum[] =
 };
 # endif
 
-#define YYPACT_NINF -148
+#define YYPACT_NINF -114
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-148)))
+  (!!((Yystate) == (-114)))
 
 #define YYTABLE_NINF -1
 
@@ -534,32 +533,32 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-      80,    -5,    -5,    -5,    -5,    -5,    -5,    -5,    27,  -148,
-    -148,  -148,  -148,  -148,  -148,  -148,  -148,  -148,  -148,     3,
-      -1,    11,    28,    34,    35,    39,    41,  -148,  -148,    49,
-      63,    63,    58,    80,   116,    54,    50,    -5,    57,    61,
-      -5,    64,  -148,    66,    -5,    -5,    -5,    -5,  -148,  -148,
-    -148,  -148,  -148,    68,    -5,    73,    72,    74,    95,    95,
-      77,    98,    80,    82,   116,   116,    87,    80,    92,    98,
-      -5,    93,   114,    -5,    96,    99,   104,    -5,   101,  -148,
-    -148,   102,   113,   108,   116,   108,  -148,   109,  -148,   108,
-     104,   112,   118,    10,    -5,   119,   120,    98,    98,  -148,
-     102,   121,    36,   108,    16,   108,    -5,    82,  -148,  -148,
-     122,   108,  -148,   116,  -148,   118,   126,   124,   108,   123,
-     125,  -148,  -148,   127,    37,   108,   128,   125,  -148,   129,
-     108,   130,    -5,    -5,  -148,   118,  -148,    -5,  -148,   131,
-    -148,   132,  -148,   116,  -148,   108,   108,   133,  -148,  -148,
-      10,    13,   108,   134,    -5,  -148,   131,   102,  -148,  -148,
-     118,   108,    36,   108,  -148,  -148,   118,   135,   136,  -148,
-     137,   140,  -148,   142,  -148,  -148,  -148,    36,   108,  -148,
-    -148,  -148,   131,   102,   139,  -148,  -148,   141,   144,  -148,
-    -148,   108,  -148,   118,  -148,   143,  -148,   108,   147,   148,
-     149,  -148,   108,  -148,   133,  -148,  -148,  -148,   126,   150,
-    -148,   108,  -148,  -148,   151,  -148,  -148,   126,  -148,   108,
-     108,   108,  -148,  -148,  -148,  -148,   118,  -148,   152,   153,
-    -148,  -148,  -148,   108,  -148,   154,   126,  -148,   156,  -148,
-    -148,   155,   160,  -148,   157,   162,  -148,   159,   164,  -148,
-     161,   166,  -148,  -148
+     131,    -2,    -2,    -2,    -2,    -2,    -2,    -2,    28,  -114,
+    -114,  -114,  -114,  -114,  -114,  -114,  -114,  -114,  -114,    10,
+      19,    21,    24,    33,    35,    37,    40,  -114,  -114,    63,
+      65,    65,    56,   131,    91,    59,    53,    -2,    54,    55,
+      -2,    57,  -114,    58,    -2,    -2,    -2,    -2,  -114,  -114,
+    -114,  -114,  -114,    68,    -2,    69,    93,    72,    92,    92,
+      75,    94,   131,    77,    91,    91,    82,   131,    81,    94,
+      -2,    83,   102,    -2,    85,    87,    95,    -2,    88,  -114,
+    -114,    89,   101,    96,    91,    96,  -114,    98,  -114,    96,
+      95,   100,   104,    11,    -2,   108,   112,    94,    94,  -114,
+      89,   113,    38,    96,    14,    96,    -2,    77,  -114,  -114,
+     117,    96,  -114,    91,  -114,   104,   132,   135,    96,   123,
+     124,  -114,  -114,   125,    31,    96,   130,   124,  -114,   127,
+      96,   133,    -2,    -2,  -114,   104,  -114,    -2,   104,  -114,
+    -114,   128,  -114,    91,  -114,    96,    96,   134,  -114,  -114,
+      11,     0,    96,   136,    -2,   104,  -114,    89,  -114,  -114,
+     104,    96,    38,    96,  -114,  -114,   104,   137,   138,  -114,
+     139,  -114,   140,  -114,  -114,  -114,    38,    96,  -114,  -114,
+     104,  -114,    89,   141,  -114,  -114,   142,   144,  -114,  -114,
+      96,  -114,   104,  -114,   143,  -114,    96,   149,    99,   150,
+      96,  -114,   134,  -114,  -114,  -114,   132,   151,  -114,    96,
+    -114,  -114,   146,  -114,  -114,   132,  -114,    96,    96,    96,
+    -114,  -114,  -114,  -114,   104,  -114,   152,   153,  -114,  -114,
+    -114,    96,  -114,   154,   132,  -114,   155,  -114,  -114,   156,
+     159,  -114,   157,   162,  -114,   160,   163,  -114,   161,   166,
+    -114,  -114
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -571,40 +570,40 @@ static const yytype_uint8 yydefact[] =
       21,    28,    27,    22,    23,    24,    25,    26,     3,     0,
        0,     0,     0,     0,     0,     0,     0,     1,     4,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    75,     0,     0,     0,     0,     0,    92,     6,
+       0,     0,    73,     0,     0,     0,     0,     0,    90,     6,
        7,     8,     9,     0,     0,     0,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    66,    56,
-      76,    70,     0,     0,    15,     0,    20,     0,    93,     0,
-       0,     0,    42,     0,     0,    46,     0,     0,     0,    73,
-      70,     0,     0,     0,     0,     0,     0,    12,     5,    10,
-      16,     0,    18,     0,    91,    42,     0,     0,     0,     0,
-      34,    31,    30,     0,     0,     0,     0,    34,    55,    60,
-       0,     0,     0,     0,    68,    42,    65,     0,    72,    38,
-      74,     0,    13,    15,    14,     0,     0,    95,    43,    41,
-       0,     0,     0,     0,     0,    49,    38,    70,    45,    54,
-      42,     0,     0,     0,    69,    58,    42,     0,     0,    67,
-       0,     0,    71,     0,    17,    19,    98,     0,     0,    32,
-      33,    37,    38,    70,     0,    29,    51,     0,     0,    48,
-      47,     0,    44,    42,    62,     0,    59,     0,     0,     0,
-       0,    39,     0,    96,    95,    94,    36,    35,     0,     0,
-      84,     0,    81,    80,     0,    53,    61,     0,    57,     0,
-       0,     0,    11,    97,    77,    52,    42,    79,     0,     0,
-      64,    78,    40,     0,    85,     0,     0,    50,     0,    63,
-      86,    82,     0,    87,     0,     0,    88,     0,     0,    89,
-       0,     0,    90,    83
+       0,     0,     0,     0,     0,     0,     0,     0,    64,    54,
+      74,    68,     0,     0,    15,     0,    20,     0,    91,     0,
+       0,     0,    38,     0,     0,    44,     0,     0,     0,    71,
+      68,     0,     0,     0,     0,     0,     0,    12,     5,    10,
+      16,     0,    18,     0,    89,    38,     0,     0,     0,     0,
+      34,    31,    30,     0,     0,     0,     0,    34,    53,    58,
+       0,     0,     0,     0,    66,    38,    63,     0,    38,    70,
+      72,     0,    13,    15,    14,     0,     0,    93,    39,    41,
+       0,     0,     0,     0,     0,    38,    47,    68,    43,    52,
+      38,     0,     0,     0,    67,    56,    38,     0,     0,    65,
+       0,    69,     0,    17,    19,    96,     0,     0,    32,    33,
+      38,    37,    68,     0,    29,    49,     0,     0,    46,    45,
+       0,    42,    38,    60,     0,    57,     0,     0,     0,     0,
+       0,    94,    93,    92,    36,    35,     0,     0,    82,     0,
+      79,    78,     0,    51,    59,     0,    55,     0,     0,     0,
+      11,    95,    75,    50,    38,    77,     0,     0,    62,    76,
+      40,     0,    83,     0,     0,    48,     0,    61,    84,    80,
+       0,    85,     0,     0,    86,     0,     0,    87,     0,     0,
+      88,    81
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -148,  -148,   -44,     9,   -85,   -28,  -148,    65,    52,  -148,
-      38,  -148,  -148,  -148,   -23,  -148,  -148,  -148,    30,    51,
-    -147,  -103,  -148,  -110,   165,   167,  -148,  -148,  -148,  -148,
-     138,  -148,  -148,   -76,   -50,  -148,  -148,  -148,  -148,   -33,
-    -148,  -148,  -148,   -93,   105,  -148,  -148,  -148,  -148,  -108,
-    -148,  -148,  -148,  -148,  -148,  -148,  -148,  -148,  -148,  -148,
-    -148,  -148,  -148,  -148,  -148,    -8,  -148
+    -114,  -114,   -24,     4,   -85,   -33,  -114,    79,    73,  -114,
+      23,  -114,  -114,  -114,   -20,  -114,  -114,  -114,    12,    67,
+    -101,  -108,  -114,   167,   164,  -114,  -114,  -114,  -114,   105,
+    -114,  -114,   -81,   -67,  -114,  -114,  -114,  -114,   -34,  -114,
+    -114,  -114,   -95,   107,  -114,  -114,  -114,  -114,  -113,  -114,
+    -114,  -114,  -114,  -114,  -114,  -114,  -114,  -114,  -114,  -114,
+    -114,  -114,  -114,  -114,   -21,  -114
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
@@ -612,11 +611,11 @@ static const yytype_int16 yydefgoto[] =
 {
       -1,     8,    19,    20,   109,   110,    49,   119,    83,    50,
      111,    51,    52,    87,     9,    10,    11,   120,   121,   152,
-     172,   138,    71,   118,    12,    38,   125,    95,   187,   226,
-      74,   160,   127,    78,    79,   166,    13,   163,   193,   134,
-      14,   103,    41,   105,   100,    15,    43,    81,   183,   135,
-     157,   211,   212,   213,   214,   235,   241,   244,   247,   250,
-     253,    16,    53,    89,    17,   178,    55
+     118,   138,    71,    12,    38,   125,    95,   186,   224,    74,
+     160,   127,    78,    79,   166,    13,   163,   192,   134,    14,
+     103,    41,   105,   100,    15,    43,    81,   182,   135,   157,
+     209,   210,   211,   212,   233,   239,   242,   245,   248,   251,
+      16,    53,    89,    17,   177,    55
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -624,50 +623,50 @@ static const yytype_int16 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-     112,    64,    65,    66,   114,   146,    48,   130,   147,   189,
-      42,    21,    22,    23,    24,    25,    26,   122,   136,    91,
-     140,   155,   129,    77,    18,   169,   144,    27,   132,    28,
-      29,   132,   133,   149,   106,   206,    84,    85,   137,    80,
-     158,   137,    30,   184,    88,   164,    57,   128,   181,    60,
-     191,   132,   132,    63,   195,   133,   197,   154,     2,    31,
-     175,   176,   137,    68,   190,    32,    33,   185,   201,   204,
-      34,   139,    35,    37,   180,    40,   192,    54,   196,    92,
-      70,    56,    96,   216,   148,   145,   101,     1,    58,     2,
-     207,   156,    59,   205,     3,    61,     4,    62,     5,    67,
-     224,     6,     7,   123,    69,    72,   215,    73,    76,   229,
-     188,    77,   218,    82,    86,   141,   233,   222,   182,    44,
-      45,    46,    47,    90,    93,    94,   227,    97,   239,   194,
-      98,    99,   102,   104,   230,   231,   232,   106,   108,   132,
-     113,   167,   168,   116,   203,   133,   170,   107,   237,   117,
-     124,   126,   131,   143,   150,   159,   151,   165,   153,   142,
-     162,   186,   171,   173,   177,   137,   198,   199,   200,   202,
-     208,   210,   209,   219,   217,   221,   220,   225,   161,   234,
-     179,   174,   228,   240,   236,   238,   242,   243,   245,   246,
-     248,   249,   251,   252,    36,   115,   223,    75,    39
+     112,    48,    91,   147,   114,   130,    21,    22,    23,    24,
+      25,    26,   122,    42,   146,   132,   155,   129,   136,   133,
+     140,    64,    65,    66,    77,   137,   144,    18,    27,   132,
+     128,    84,    85,   149,   169,   106,    28,   171,   183,   137,
+     158,    57,    80,   180,    60,   164,   132,    88,    63,   194,
+      29,   154,    30,   132,   188,    31,   137,   133,    68,   190,
+     174,   175,   189,   202,    32,   196,    33,   184,    34,   179,
+     139,    35,     2,    40,    92,    37,   191,    96,   195,   204,
+     145,   101,    54,   148,    56,    58,    59,   205,    61,    62,
+     156,   214,   203,   222,    44,    45,    46,    47,   123,    67,
+      69,    70,   227,    72,    73,   213,    76,    77,    82,    86,
+     141,   216,    90,    94,    93,   220,    97,   181,    98,   102,
+     104,   237,    99,   231,   225,   106,   108,   218,   193,   113,
+     187,   116,   228,   229,   230,   117,   167,   168,     1,   124,
+       2,   170,   201,   126,   131,     3,   235,     4,   143,     5,
+     132,   133,     6,     7,   150,   151,   153,   159,   162,   172,
+     165,   107,   178,   185,    75,   176,   173,   200,   197,   198,
+     199,   208,   206,   207,   215,   217,   219,   226,   223,   232,
+     142,   221,   238,     0,   234,   236,   241,   240,   243,   244,
+     247,   246,   249,   250,   161,    39,    36,   115
 };
 
-static const yytype_uint8 yycheck[] =
+static const yytype_int16 yycheck[] =
 {
-      85,    45,    46,    47,    89,   115,    34,   100,   116,   156,
-      33,     2,     3,     4,     5,     6,     7,    93,   103,    69,
-     105,   124,    98,    13,    29,   135,   111,     0,    15,    26,
-      31,    15,    19,   118,    24,   182,    64,    65,    25,    62,
-     125,    25,    31,   151,    67,   130,    37,    97,   151,    40,
-     160,    15,    15,    44,   162,    19,   166,    20,     9,    31,
-     145,   146,    25,    54,   157,    31,    31,   152,   171,   177,
-      31,   104,    31,    10,   150,    17,   161,    23,   163,    70,
-       8,    31,    73,   193,   117,   113,    77,     7,    31,     9,
-     183,   124,    31,   178,    14,    31,    16,    31,    18,    31,
-     208,    21,    22,    94,    31,    31,   191,    12,    31,   217,
-     154,    13,   197,    31,    27,   106,   226,   202,   151,     3,
-       4,     5,     6,    31,    31,    11,   211,    31,   236,   162,
-      31,    27,    31,    31,   219,   220,   221,    24,    30,    15,
-      31,   132,   133,    31,   177,    19,   137,    82,   233,    31,
-      31,    31,    31,    31,    31,    27,    31,    27,    31,   107,
-      31,    27,    31,    31,    31,    25,    31,    31,    31,    27,
-      31,    27,    31,    26,    31,    26,    28,    27,   127,    27,
-     150,   143,    31,    27,    31,    31,    31,    27,    31,    27,
-      31,    27,    31,    27,    29,    90,   204,    59,    31
+      85,    34,    69,   116,    89,   100,     2,     3,     4,     5,
+       6,     7,    93,    33,   115,    15,   124,    98,   103,    19,
+     105,    45,    46,    47,    13,    25,   111,    29,     0,    15,
+      97,    64,    65,   118,   135,    24,    26,   138,   151,    25,
+     125,    37,    62,   151,    40,   130,    15,    67,    44,   162,
+      31,    20,    31,    15,   155,    31,    25,    19,    54,   160,
+     145,   146,   157,   176,    31,   166,    31,   152,    31,   150,
+     104,    31,     9,    17,    70,    10,   161,    73,   163,   180,
+     113,    77,    23,   117,    31,    31,    31,   182,    31,    31,
+     124,   192,   177,   206,     3,     4,     5,     6,    94,    31,
+      31,     8,   215,    31,    12,   190,    31,    13,    31,    27,
+     106,   196,    31,    11,    31,   200,    31,   151,    31,    31,
+      31,   234,    27,   224,   209,    24,    30,    28,   162,    31,
+     154,    31,   217,   218,   219,    31,   132,   133,     7,    31,
+       9,   137,   176,    31,    31,    14,   231,    16,    31,    18,
+      15,    19,    21,    22,    31,    31,    31,    27,    31,    31,
+      27,    82,   150,    27,    59,    31,   143,    27,    31,    31,
+      31,    27,    31,    31,    31,    26,    26,    31,    27,    27,
+     107,   202,    27,    -1,    31,    31,    27,    31,    31,    27,
+      27,    31,    31,    27,   127,    31,    29,    90
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
@@ -675,31 +674,31 @@ static const yytype_uint8 yycheck[] =
 static const yytype_uint8 yystos[] =
 {
        0,     7,     9,    14,    16,    18,    21,    22,    33,    46,
-      47,    48,    56,    68,    72,    77,    93,    96,    29,    34,
+      47,    48,    55,    67,    71,    76,    92,    95,    29,    34,
       35,    35,    35,    35,    35,    35,    35,     0,    26,    31,
-      31,    31,    31,    31,    31,    31,    56,    10,    57,    57,
-      17,    74,    46,    78,     3,     4,     5,     6,    37,    38,
-      41,    43,    44,    94,    23,    98,    31,    35,    31,    31,
+      31,    31,    31,    31,    31,    31,    55,    10,    56,    56,
+      17,    73,    46,    77,     3,     4,     5,     6,    37,    38,
+      41,    43,    44,    93,    23,    97,    31,    35,    31,    31,
       35,    31,    31,    35,    34,    34,    34,    31,    35,    31,
-       8,    54,    31,    12,    62,    62,    31,    13,    65,    66,
-      46,    79,    31,    40,    37,    37,    27,    45,    46,    95,
-      31,    66,    35,    31,    11,    59,    35,    31,    31,    27,
-      76,    35,    31,    73,    31,    75,    24,    39,    30,    36,
-      37,    42,    36,    31,    36,    76,    31,    31,    55,    39,
-      49,    50,    65,    35,    31,    58,    31,    64,    66,    65,
-      75,    31,    15,    19,    71,    81,    36,    25,    53,    71,
-      36,    35,    40,    31,    36,    37,    55,    81,    71,    36,
-      31,    31,    51,    31,    20,    53,    71,    82,    36,    27,
-      63,    51,    31,    69,    36,    27,    67,    35,    35,    55,
-      35,    31,    52,    31,    42,    36,    36,    31,    97,    50,
-      65,    53,    71,    80,    81,    36,    27,    60,    34,    52,
-      75,    55,    36,    70,    71,    81,    36,    55,    31,    31,
-      31,    53,    27,    71,    81,    36,    52,    75,    31,    31,
-      27,    83,    84,    85,    86,    36,    55,    31,    36,    26,
-      28,    26,    36,    97,    81,    27,    61,    36,    31,    81,
-      36,    36,    36,    55,    27,    87,    31,    36,    31,    81,
-      27,    88,    31,    27,    89,    31,    27,    90,    31,    27,
-      91,    31,    27,    92
+       8,    54,    31,    12,    61,    61,    31,    13,    64,    65,
+      46,    78,    31,    40,    37,    37,    27,    45,    46,    94,
+      31,    65,    35,    31,    11,    58,    35,    31,    31,    27,
+      75,    35,    31,    72,    31,    74,    24,    39,    30,    36,
+      37,    42,    36,    31,    36,    75,    31,    31,    52,    39,
+      49,    50,    64,    35,    31,    57,    31,    63,    65,    64,
+      74,    31,    15,    19,    70,    80,    36,    25,    53,    70,
+      36,    35,    40,    31,    36,    37,    52,    80,    70,    36,
+      31,    31,    51,    31,    20,    53,    70,    81,    36,    27,
+      62,    51,    31,    68,    36,    27,    66,    35,    35,    52,
+      35,    52,    31,    42,    36,    36,    31,    96,    50,    64,
+      53,    70,    79,    80,    36,    27,    59,    34,    52,    74,
+      52,    36,    69,    70,    80,    36,    52,    31,    31,    31,
+      27,    70,    80,    36,    52,    74,    31,    31,    27,    82,
+      83,    84,    85,    36,    52,    31,    36,    26,    28,    26,
+      36,    96,    80,    27,    60,    36,    31,    80,    36,    36,
+      36,    52,    27,    86,    31,    36,    31,    80,    27,    87,
+      31,    27,    88,    31,    27,    89,    31,    27,    90,    31,
+      27,    91
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
@@ -709,12 +708,12 @@ static const yytype_uint8 yyr1[] =
       38,    39,    40,    40,    41,    42,    42,    42,    43,    44,
       45,    46,    46,    46,    46,    46,    46,    47,    47,    48,
       49,    49,    50,    50,    51,    51,    51,    51,    52,    52,
-      53,    54,    55,    55,    56,    57,    58,    58,    58,    58,
-      59,    60,    61,    62,    63,    64,    65,    66,    67,    68,
-      69,    69,    69,    70,    71,    72,    73,    73,    73,    74,
-      75,    75,    75,    76,    77,    78,    79,    80,    81,    82,
-      83,    83,    84,    85,    86,    87,    88,    89,    90,    91,
-      92,    93,    94,    95,    96,    97,    97,    97,    98
+      53,    54,    55,    56,    57,    57,    57,    57,    58,    59,
+      60,    61,    62,    63,    64,    65,    66,    67,    68,    68,
+      68,    69,    70,    71,    72,    72,    72,    73,    74,    74,
+      74,    75,    76,    77,    78,    79,    80,    81,    82,    82,
+      83,    84,    85,    86,    87,    88,    89,    90,    91,    92,
+      93,    94,    95,    96,    96,    96,    97
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
@@ -724,12 +723,12 @@ static const yytype_uint8 yyr2[] =
        4,     5,     2,     3,     5,     0,     1,     3,     4,     6,
        1,     1,     1,     1,     1,     1,     1,     1,     1,    10,
        1,     1,     3,     3,     0,     3,     3,     2,     0,     2,
-       5,     4,     0,     2,    10,     6,     0,     3,     3,     2,
-       8,     1,     1,     6,     1,     1,     1,     6,     1,    10,
-       0,     3,     2,     5,     5,     8,     0,     3,     2,     6,
-       0,     3,     2,     1,     8,     1,     1,     3,     5,     4,
-       1,     1,     5,    13,     1,     1,     1,     1,     1,     1,
-       1,     7,     1,     1,    10,     0,     2,     3,     6
+       5,     4,    10,     6,     0,     3,     3,     2,     8,     1,
+       1,     6,     1,     1,     1,     6,     1,    10,     0,     3,
+       2,     5,     5,     8,     0,     3,     2,     6,     0,     3,
+       2,     1,     8,     1,     1,     3,     5,     4,     1,     1,
+       5,    13,     1,     1,     1,     1,     1,     1,     1,     7,
+       1,     1,    10,     0,     2,     3,     6
 };
 
 
diff --git a/ogr/osr_cs_wkt_parser.h b/ogr/osr_cs_wkt_parser.h
index 412c907..c467805 100644
--- a/ogr/osr_cs_wkt_parser.h
+++ b/ogr/osr_cs_wkt_parser.h
@@ -3,7 +3,6 @@
 /* Bison interface for Yacc-like parsers in C
 
    Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
- * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
diff --git a/ogr/osr_tutorial.dox b/ogr/osr_tutorial.dox
index 5b408e4..4565afa 100644
--- a/ogr/osr_tutorial.dox
+++ b/ogr/osr_tutorial.dox
@@ -27,7 +27,7 @@ is projected (such as UTM - positions are measured in meters or feet).
 
 A Geographic coordinate system contains information on the datum (which implies
 an spheroid described by a semi-major axis, and inverse flattening), prime 
-meridian(normally Greenwich), and an angular units type which is normally 
+meridian (normally Greenwich), and an angular units type which is normally 
 degrees.  The following code initializes a geographic coordinate system 
 on supplying all this information along with a user visible name for the
 geographic coordinate system. 
@@ -64,7 +64,7 @@ be set by it's GCS code number if the EPSG database is available.
 	oSRS.SetWellKnownGeogCS( "EPSG:4326" );
 \endcode
 
-For serializization, and transmission of projection definitions to other
+For serialization, and transmission of projection definitions to other
 packages, the OpenGIS Well Known Text format for coordinate systems is
 used.  An OGRSpatialReference can be initialized from well known text, or
 converted back into well known text.
@@ -112,7 +112,7 @@ A projected coordinate system (such as UTM, Lambert Conformal Conic, etc)
 requires and underlying geographic coordinate system as well as a definition
 for the projection transform used to translate between linear positions
 (in meters or feet) and angular long/lat positions.  The following code
-defines a UTM zone 17 projected coordinate system with and underlying 
+defines a UTM zone 17 projected coordinate system with an underlying 
 geographic coordinate system (datum) of WGS84.
 
 \code
diff --git a/ogr/style_pen1.gif b/ogr/style_pen1.gif
new file mode 100644
index 0000000..35b66ac
Binary files /dev/null and b/ogr/style_pen1.gif differ
diff --git a/ogr/style_pen2.gif b/ogr/style_pen2.gif
new file mode 100644
index 0000000..0640e22
Binary files /dev/null and b/ogr/style_pen2.gif differ
diff --git a/ogr/style_pen3.gif b/ogr/style_pen3.gif
new file mode 100644
index 0000000..cb62da2
Binary files /dev/null and b/ogr/style_pen3.gif differ
diff --git a/ogr/style_textanchor.gif b/ogr/style_textanchor.gif
new file mode 100644
index 0000000..dd9352b
Binary files /dev/null and b/ogr/style_textanchor.gif differ
diff --git a/ogr/swq.cpp b/ogr/swq.cpp
index f8af473..c7d0fe3 100644
--- a/ogr/swq.cpp
+++ b/ogr/swq.cpp
@@ -99,6 +99,8 @@ int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
         char chQuote = *pszInput;
         int bFoundEndQuote = FALSE;
 
+        int nRet = *pszInput == '"' ? SWQT_IDENTIFIER : SWQT_STRING;
+
         pszInput++;
 
         token = (char *) CPLMalloc(strlen(pszInput)+1);
@@ -106,11 +108,11 @@ int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
 
         while( *pszInput != '\0' )
         {
-            if( *pszInput == '\\' && pszInput[1] == '"' )
+            if( chQuote == '"' && *pszInput == '\\' && pszInput[1] == '"' )
                 pszInput++;
-            else if( *pszInput == '\\' && pszInput[1] == '\'' )
+            else if( chQuote == '\'' && *pszInput == '\\' && pszInput[1] == '\'' )
                 pszInput++;
-            else if( *pszInput == '\'' && pszInput[1] == '\'' )
+            else if( chQuote == '\'' && *pszInput == '\'' && pszInput[1] == '\'' )
                 pszInput++;
             else if( *pszInput == chQuote )
             {
@@ -136,7 +138,7 @@ int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
 
         context->pszNext = pszInput;
 
-        return SWQT_STRING;
+        return nRet;
     }
 
 /* -------------------------------------------------------------------- */
@@ -182,7 +184,11 @@ int swqlex( YYSTYPE *ppNode, swq_parse_context *context )
         }
         else
         {
-            *ppNode = new swq_expr_node( atoi(osToken) );
+            GIntBig nVal = CPLAtoGIntBig(osToken);
+            if( (GIntBig)(int)nVal == nVal )
+                *ppNode = new swq_expr_node( (int)nVal );
+            else
+                *ppNode = new swq_expr_node( nVal );
             return SWQT_INTEGER_NUMBER;
         }
     }
@@ -337,7 +343,7 @@ swq_select_summarize( swq_select *select_info,
     
     if( def->distinct_flag )
     {
-        int  i;
+        GIntBig  i;
 
         /* This should be implemented with a much more complicated
            data structure to achieve any sort of efficiency. */
@@ -358,9 +364,9 @@ swq_select_summarize( swq_select *select_info,
             char  **old_list = summary->distinct_list;
             
             summary->distinct_list = (char **) 
-                CPLMalloc(sizeof(char *) * (summary->count+1));
+                CPLMalloc(sizeof(char *) * (size_t)(summary->count+1));
             memcpy( summary->distinct_list, old_list, 
-                    sizeof(char *) * summary->count );
+                    sizeof(char *) * (size_t)summary->count );
             summary->distinct_list[(summary->count)++] = 
                 (value != NULL) ? CPLStrdup( value ) : NULL;
 
@@ -424,9 +430,12 @@ swq_select_summarize( swq_select *select_info,
                def->field_type == SWQ_TIME ||
                def->field_type == SWQ_TIMESTAMP)
             {
-                int nYear, nMonth, nDay, nHour, nMin, nSec;
-                if( sscanf(value, "%04d/%02d/%02d %02d:%02d:%02d",
-                           &nYear, &nMonth, &nDay, &nHour, &nMin, &nSec) == 6 )
+                int nYear, nMonth, nDay, nHour = 0, nMin = 0;
+                float fSec = 0 ;
+                if( sscanf(value, "%04d/%02d/%02d %02d:%02d:%f",
+                           &nYear, &nMonth, &nDay, &nHour, &nMin, &fSec) == 6 ||
+                    sscanf(value, "%04d/%02d/%02d",
+                           &nYear, &nMonth, &nDay) == 3 )
                 {
                     struct tm brokendowntime;
                     brokendowntime.tm_year = nYear - 1900;
@@ -434,9 +443,10 @@ swq_select_summarize( swq_select *select_info,
                     brokendowntime.tm_mday = nDay;
                     brokendowntime.tm_hour = nHour;
                     brokendowntime.tm_min = nMin;
-                    brokendowntime.tm_sec = nSec;
+                    brokendowntime.tm_sec = (int)fSec;
                     summary->count++;
                     summary->sum += CPLYMDHMSToUnixTime(&brokendowntime);
+                    summary->sum += fmod((double)fSec, 1);
                 }
             }
             else
@@ -470,7 +480,7 @@ swq_select_summarize( swq_select *select_info,
 
 static int FORCE_CDECL swq_compare_int( const void *item1, const void *item2 )
 {
-    int  v1, v2;
+    GIntBig  v1, v2;
 
     const char* pszStr1 = *((const char **) item1);
     const char* pszStr2 = *((const char **) item2);
@@ -479,8 +489,8 @@ static int FORCE_CDECL swq_compare_int( const void *item1, const void *item2 )
     else if (pszStr2 == NULL)
         return 1;
 
-    v1 = atoi(pszStr1);
-    v2 = atoi(pszStr2);
+    v1 = CPLAtoGIntBig(pszStr1);
+    v2 = CPLAtoGIntBig(pszStr2);
 
     if( v1 < v2 )
         return -1;
@@ -535,7 +545,7 @@ const char *swq_select_finish_summarize( swq_select *select_info )
 
 {
     int (FORCE_CDECL *compare_func)(const void *, const void*);
-    int count = 0;
+    GIntBig count = 0;
     char **distinct_list = NULL;
 
     if( select_info->query_mode != SWQM_DISTINCT_LIST 
@@ -552,7 +562,8 @@ const char *swq_select_finish_summarize( swq_select *select_info )
     if( select_info->column_summary == NULL )
         return NULL;
 
-    if( select_info->column_defs[0].field_type == SWQ_INTEGER )
+    if( select_info->column_defs[0].field_type == SWQ_INTEGER ||
+        select_info->column_defs[0].field_type == SWQ_INTEGER64 )
         compare_func = swq_compare_int;
     else if( select_info->column_defs[0].field_type == SWQ_FLOAT )
         compare_func = swq_compare_real;
@@ -562,7 +573,7 @@ const char *swq_select_finish_summarize( swq_select *select_info )
     distinct_list = select_info->column_summary[0].distinct_list;
     count = select_info->column_summary[0].count;
 
-    qsort( distinct_list, count, sizeof(char *), compare_func );
+    qsort( distinct_list, (size_t)count, sizeof(char *), compare_func );
 
 /* -------------------------------------------------------------------- */
 /*      Do we want the list ascending in stead of descending?           */
@@ -570,7 +581,7 @@ const char *swq_select_finish_summarize( swq_select *select_info )
     if( !select_info->order_defs[0].ascending_flag )
     {
         char *saved;
-        int i;
+        GIntBig i;
 
         for( i = 0; i < count/2; i++ )
         {
@@ -596,17 +607,29 @@ void swq_select_free( swq_select *select_info )
 /************************************************************************/
 /*                         swq_identify_field()                         */
 /************************************************************************/
-static 
-int swq_identify_field_internal( const char *field_token, const char* table_name,
+int swq_identify_field_internal( const char* table_name, const char *field_token, 
                                  swq_field_list *field_list,
-                                 swq_field_type *this_type, int *table_id, int tables_enabled );
+                                 swq_field_type *this_type, int *table_id,
+                                 int bOneMoreTimeOK );
 
-int swq_identify_field( const char *token, swq_field_list *field_list,
-                        swq_field_type *this_type, int *table_id )
+int swq_identify_field( const char* table_name, const char *field_token, 
+                                 swq_field_list *field_list,
+                                 swq_field_type *this_type, int *table_id )
 
 {
-    CPLString osTableName;
-    const char *field_token = token;
+    return swq_identify_field_internal(table_name, field_token, field_list,
+                                       this_type, table_id, TRUE);
+}
+
+int swq_identify_field_internal( const char* table_name, const char *field_token, 
+                                 swq_field_list *field_list,
+                                 swq_field_type *this_type, int *table_id,
+                                 int bOneMoreTimeOK )
+
+{
+    int i;
+    if( table_name == NULL ) table_name = "";
+
     int   tables_enabled;
 
     if( field_list->table_count > 0 && field_list->table_ids != NULL )
@@ -615,75 +638,6 @@ int swq_identify_field( const char *token, swq_field_list *field_list,
         tables_enabled = FALSE;
 
 /* -------------------------------------------------------------------- */
-/*      Parse out table name if present, and table support enabled.     */
-/* -------------------------------------------------------------------- */
-    if( tables_enabled && strchr(token, '.') != NULL )
-    {
-        int dot_offset = (int)(strchr(token,'.') - token);
-
-        osTableName = token;
-        osTableName.resize(dot_offset);
-        field_token = token + dot_offset + 1;
-
-#ifdef notdef
-        /* We try to detect if a.b is the a.b field */
-        /* of the main table, or the b field of the a table */
-        /* If both exists, report an error. */
-        /* This works, but I'm not sure this is a good idea to */
-        /* enable that. It is a sign that our SQL grammar is somewhat */
-        /* ambiguous */
-
-        swq_field_type eTypeWithTablesEnabled;
-        int            nTableIdWithTablesEnabled;
-        int nRetWithTablesEnabled = swq_identify_field_internal(
-            field_token, osTableName.c_str(), field_list,
-            &eTypeWithTablesEnabled, &nTableIdWithTablesEnabled, TRUE);
-
-        swq_field_type eTypeWithTablesDisabled;
-        int            nTableIdWithTablesDisabled;
-        int nRetWithTablesDisabled = swq_identify_field_internal(
-            token, "", field_list,
-            &eTypeWithTablesDisabled, &nTableIdWithTablesDisabled, FALSE);
-
-        if( nRetWithTablesEnabled >= 0 && nRetWithTablesDisabled >= 0 )
-        {
-            CPLError(CE_Failure, CPLE_AppDefined,
-                        "Ambiguous situation. Both %s exists as a field in "
-                        "main table and %s exists as a field in %s table",
-                        token, osTableName.c_str(), field_token);
-            return -1;
-        }
-        else if( nRetWithTablesEnabled >= 0 )
-        {
-            if( this_type != NULL ) *this_type = eTypeWithTablesEnabled;
-            if( table_id != NULL ) *table_id = nTableIdWithTablesEnabled;
-            return nRetWithTablesEnabled;
-        }
-        else if( nRetWithTablesDisabled >= 0 )
-        {
-            if( this_type != NULL ) *this_type = eTypeWithTablesDisabled;
-            if( table_id != NULL ) *table_id = nTableIdWithTablesDisabled;
-            return nRetWithTablesDisabled;
-        }
-        else
-        {
-            return -1;
-        }
-#endif
-    }
-
-    return swq_identify_field_internal(field_token, osTableName.c_str(), field_list,
-                                       this_type, table_id, tables_enabled);
-}
-
-
-int swq_identify_field_internal( const char *field_token, const char* table_name,
-                                 swq_field_list *field_list,
-                                 swq_field_type *this_type, int *table_id, int tables_enabled )
-
-{
-    int i;
-/* -------------------------------------------------------------------- */
 /*      Search for matching field.                                      */
 /* -------------------------------------------------------------------- */
     for( i = 0; i < field_list->count; i++ )
@@ -704,6 +658,8 @@ int swq_identify_field_internal( const char *field_token, const char* table_name
 //            if( t_id != 0 && table_name[0] == '\0' )
 //                continue;
         }
+        else if( table_name[0] != '\0' )
+            break;
 
         /* We have a match, return various information */
         if( this_type != NULL )
@@ -724,6 +680,70 @@ int swq_identify_field_internal( const char *field_token, const char* table_name
     }
 
 /* -------------------------------------------------------------------- */
+/*      When there is no ambiguity, try to accept quoting errors...     */
+/* -------------------------------------------------------------------- */
+    if( bOneMoreTimeOK && !CSLTestBoolean(CPLGetConfigOption("OGR_SQL_STRICT", "FALSE")) )
+    {
+        if( table_name[0] )
+        {
+            CPLString osAggregatedName(CPLSPrintf("%s.%s", table_name, field_token));
+
+            // Check there's no table called table_name, or a field called with
+            // the aggregated name
+            for( i = 0; i < field_list->count; i++ )
+            {
+                if( tables_enabled )
+                {
+                    int t_id = field_list->table_ids[i];
+                    if( EQUAL(table_name,field_list->table_defs[t_id].table_alias) )
+                        break;
+                }
+            }
+            if( i == field_list->count )
+            {
+                int ret = swq_identify_field_internal( NULL,
+                                            osAggregatedName, 
+                                            field_list,
+                                            this_type, table_id, FALSE );
+                if( ret >= 0 )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                            "Passed field name %s.%s should have been surrounded by double quotes. "
+                            "Accepted since there is no ambiguity...",
+                            table_name, field_token);
+                }
+                return ret;
+            }
+        }
+        else
+        {
+            // If the fieldname is a.b (and there's no . in b), then 
+            // it might be an error in providing it as being quoted where it should
+            // not have been quoted.
+            const char* pszDot = strchr(field_token, '.');
+            if( pszDot && strchr(pszDot+1, '.') == NULL )
+            {
+                CPLString osTableName(field_token);
+                osTableName.resize(pszDot - field_token);
+                CPLString osFieldName(pszDot + 1);
+
+                int ret = swq_identify_field_internal( osTableName,
+                                            osFieldName, 
+                                            field_list,
+                                            this_type, table_id, FALSE );
+                if( ret >= 0 )
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                            "Passed field name %s should NOT have been surrounded by double quotes. "
+                            "Accepted since there is no ambiguity...",
+                            field_token);
+                }
+                return ret;
+            }
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      No match, return failure.                                       */
 /* -------------------------------------------------------------------- */
     if( this_type != NULL )
@@ -743,6 +763,8 @@ CPLErr swq_expr_compile( const char *where_clause,
                          int field_count,
                          char **field_names, 
                          swq_field_type *field_types, 
+                         int bCheck,
+                         swq_custom_func_registrar* poCustomFuncRegistrar,
                          swq_expr_node **expr_out )
 
 {
@@ -757,7 +779,8 @@ CPLErr swq_expr_compile( const char *where_clause,
     field_list.table_count = 0;
     field_list.table_defs = NULL;
 
-    return swq_expr_compile2( where_clause, &field_list, expr_out );
+    return swq_expr_compile2( where_clause, &field_list,
+                              bCheck, poCustomFuncRegistrar, expr_out );
 }
 
 
@@ -767,6 +790,8 @@ CPLErr swq_expr_compile( const char *where_clause,
 
 CPLErr swq_expr_compile2( const char *where_clause, 
                           swq_field_list *field_list,
+                          int bCheck,
+                          swq_custom_func_registrar* poCustomFuncRegistrar,
                           swq_expr_node **expr_out )
 
 {
@@ -776,10 +801,11 @@ CPLErr swq_expr_compile2( const char *where_clause,
     context.pszInput = where_clause;
     context.pszNext = where_clause;
     context.pszLastValid = where_clause;
-    context.nStartToken = SWQT_LOGICAL_START;
+    context.nStartToken = SWQT_VALUE_START;
+    context.bAcceptCustomFuncs = poCustomFuncRegistrar != NULL;
     
     if( swqparse( &context ) == 0 
-        && context.poRoot->Check( field_list, FALSE ) != SWQ_ERROR )
+        && bCheck && context.poRoot->Check( field_list, FALSE, FALSE, poCustomFuncRegistrar ) != SWQ_ERROR )
     {
         *expr_out = context.poRoot;
 
@@ -843,6 +869,7 @@ const char* SWQFieldTypeToString( swq_field_type field_type )
     switch(field_type)
     {
         case SWQ_INTEGER:   return "integer";
+        case SWQ_INTEGER64: return "bigint";
         case SWQ_FLOAT:     return "float";
         case SWQ_STRING:    return "string";
         case SWQ_BOOLEAN:   return "boolean";
diff --git a/ogr/swq.h b/ogr/swq.h
index c0114cb..d46a78a 100644
--- a/ogr/swq.h
+++ b/ogr/swq.h
@@ -52,18 +52,20 @@ typedef enum {
     SWQ_MODULUS,
     SWQ_CONCAT,
     SWQ_SUBSTR,
+    SWQ_HSTORE_GET_VALUE,
     SWQ_AVG,
     SWQ_MIN,
     SWQ_MAX,
     SWQ_COUNT,
     SWQ_SUM,
     SWQ_CAST,
-    SWQ_FUNC_DEFINED,
-    SWQ_UNKNOWN
+    SWQ_CUSTOM_FUNC, /* only if parsing done in bAcceptCustomFuncs mode */
+    SWQ_ARGUMENT_LIST /* temporary value only set during parsing and replaced by something else at the end */
 } swq_op;
 
 typedef enum {
     SWQ_INTEGER,
+    SWQ_INTEGER64,
     SWQ_FLOAT,
     SWQ_STRING, 
     SWQ_BOOLEAN,  // integer
@@ -76,6 +78,8 @@ typedef enum {
     SWQ_ERROR
 } swq_field_type;
 
+#define SWQ_IS_INTEGER(x) ((x) == SWQ_INTEGER || (x) == SWQ_INTEGER64)
+
 typedef enum {
     SNT_CONSTANT,
     SNT_COLUMN, 
@@ -92,15 +96,18 @@ typedef swq_expr_node *(*swq_field_fetcher)( swq_expr_node *op,
                                              void *record_handle );
 typedef swq_expr_node *(*swq_op_evaluator)(swq_expr_node *op,
                                            swq_expr_node **sub_field_values );
-typedef swq_field_type (*swq_op_checker)( swq_expr_node *op );
+typedef swq_field_type (*swq_op_checker)( swq_expr_node *op,
+                                          int bAllowMismatchTypeOnFieldComparison );
+
+class swq_custom_func_registrar;
 
 class swq_expr_node {
-    static void   Quote( CPLString &, char chQuote = '\'' );
 public:
     swq_expr_node();
 
     swq_expr_node( const char * );
     swq_expr_node( int );
+    swq_expr_node( GIntBig );
     swq_expr_node( double );
     swq_expr_node( OGRGeometry* );
     swq_expr_node( swq_op );
@@ -108,11 +115,17 @@ public:
     ~swq_expr_node();
 
     void           Initialize();
+    CPLString      UnparseOperationFromUnparsedSubExpr(char** apszSubExpr);
     char          *Unparse( swq_field_list *, char chColumnQuote );
     void           Dump( FILE *fp, int depth );
-    swq_field_type Check( swq_field_list *, int bAllowFieldsInSecondaryTables );
+    swq_field_type Check( swq_field_list *, int bAllowFieldsInSecondaryTables,
+                          int bAllowMismatchTypeOnFieldComparison,
+                          swq_custom_func_registrar* poCustomFuncRegistrar );
     swq_expr_node* Evaluate( swq_field_fetcher pfnFetcher, 
                              void *record );
+    swq_expr_node* Clone();
+
+    void           ReplaceBetweenByGEAndLERecurse();
 
     swq_node_type eNodeType;
     swq_field_type field_type;
@@ -127,13 +140,21 @@ public:
     /* only for SNT_COLUMN */
     int         field_index;
     int         table_index;
+    char        *table_name;
 
     /* only for SNT_CONSTANT */
     int         is_null;
-    char        *string_value;
-    int         int_value;
+    GIntBig     int_value;
     double      float_value;
     OGRGeometry *geometry_value;
+    
+    /* shared by SNT_COLUMN, SNT_CONSTANT and also possibly SNT_OPERATION when */
+    /* nOperation == SWQ_CUSTOM_FUNC */
+    char        *string_value; /* column name when SNT_COLUMN */
+
+
+    static CPLString   QuoteIfNecessary( const CPLString &, char chQuote = '\'' );
+    static CPLString   Quote( const CPLString &, char chQuote = '\'' );
 };
 
 typedef struct {
@@ -149,6 +170,14 @@ public:
     static const swq_operation *GetOperator( swq_op eOperation );
 };
 
+class swq_custom_func_registrar
+{
+    public:
+        virtual ~swq_custom_func_registrar() {}
+        virtual const swq_operation *GetOperator( const char * ) = 0;
+};
+
+
 typedef struct {
     char       *data_source;
     char       *table_name;
@@ -169,12 +198,15 @@ public:
 
 class swq_parse_context {
 public:
-    swq_parse_context() : nStartToken(0), poRoot(NULL), poCurSelect(NULL) {}
+    swq_parse_context() : nStartToken(0), pszInput(NULL), pszNext(NULL),
+                          pszLastValid(NULL), bAcceptCustomFuncs(FALSE),
+                          poRoot(NULL), poCurSelect(NULL) {}
 
     int        nStartToken;
     const char *pszInput;
     const char *pszNext;
     const char *pszLastValid;
+    int        bAcceptCustomFuncs;
 
     swq_expr_node *poRoot;
 
@@ -189,17 +221,22 @@ int swqparse( swq_parse_context *context );
 int swqlex( swq_expr_node **ppNode, swq_parse_context *context );
 void swqerror( swq_parse_context *context, const char *msg );
 
-int swq_identify_field( const char *token, swq_field_list *field_list,
+int swq_identify_field( const char* table_name,
+                        const char *token, swq_field_list *field_list,
                         swq_field_type *this_type, int *table_id );
 
 CPLErr swq_expr_compile( const char *where_clause, 
                          int field_count,
                          char **field_list,
                          swq_field_type *field_types,
+                         int bCheck,
+                         swq_custom_func_registrar* poCustomFuncRegistrar,
                          swq_expr_node **expr_root );
 
 CPLErr swq_expr_compile2( const char *where_clause, 
                           swq_field_list *field_list, 
+                          int bCheck,
+                          swq_custom_func_registrar* poCustomFuncRegistrar,
                           swq_expr_node **expr_root );
 
 /*
@@ -208,9 +245,9 @@ CPLErr swq_expr_compile2( const char *where_clause,
 int swq_test_like( const char *input, const char *pattern );
 
 swq_expr_node *SWQGeneralEvaluator( swq_expr_node *, swq_expr_node **);
-swq_field_type SWQGeneralChecker( swq_expr_node *node );
+swq_field_type SWQGeneralChecker( swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison );
 swq_expr_node *SWQCastEvaluator( swq_expr_node *, swq_expr_node **);
-swq_field_type SWQCastChecker( swq_expr_node *node );
+swq_field_type SWQCastChecker( swq_expr_node *node, int bAllowMismatchTypeOnFieldComparison );
 const char*    SWQFieldTypeToString( swq_field_type field_type );
 
 /****************************************************************************/
@@ -233,12 +270,14 @@ typedef enum {
 
 typedef struct {
     swq_col_func col_func;
+    char         *table_name;
     char         *field_name;
     char         *field_alias;
     int          table_index;
     int          field_index;
     swq_field_type field_type;
     swq_field_type target_type;
+    OGRFieldSubType target_subtype;
     int          field_length;
     int          field_precision;
     int          distinct_flag;
@@ -248,7 +287,7 @@ typedef struct {
 } swq_col_def;
 
 typedef struct {
-    int         count;
+    GIntBig     count;
     
     char        **distinct_list; /* items of the list can be NULL */
     double      sum;
@@ -259,6 +298,7 @@ typedef struct {
 } swq_summary;
 
 typedef struct {
+    char *table_name;
     char *field_name;
     int   table_index;
     int   field_index;
@@ -267,18 +307,31 @@ typedef struct {
 
 typedef struct {
     int        secondary_table;
-
-    char      *primary_field_name;
-    int        primary_field;
-
-    swq_op     op;
-
-    char      *secondary_field_name;
-    int        secondary_field;
+    swq_expr_node  *poExpr;
 } swq_join_def;
 
+class swq_select_parse_options
+{
+public:
+    swq_custom_func_registrar* poCustomFuncRegistrar;
+    int                        bAllowFieldsInSecondaryTablesInWhere;
+    int                        bAddSecondaryTablesGeometryFields;
+    int                        bAlwaysPrefixWithTableName;
+    int                        bAllowDistinctOnGeometryField;
+    int                        bAllowDistinctOnMultipleFields;
+
+                    swq_select_parse_options(): poCustomFuncRegistrar(NULL),
+                                                bAllowFieldsInSecondaryTablesInWhere(FALSE),
+                                                bAddSecondaryTablesGeometryFields(FALSE),
+                                                bAlwaysPrefixWithTableName(FALSE),
+                                                bAllowDistinctOnGeometryField(FALSE),
+                                                bAllowDistinctOnMultipleFields(FALSE) {}
+};
+
 class swq_select
 {
+    void        postpreparse();
+
 public:
     swq_select();
     ~swq_select();
@@ -299,26 +352,27 @@ public:
     int         table_count;
     swq_table_def *table_defs;
 
-    void        PushJoin( int iSecondaryTable,
-                          const char *pszPrimaryField,
-                          const char *pszSecondaryField );
+    void        PushJoin( int iSecondaryTable, swq_expr_node* poExpr );
     int         join_count;
     swq_join_def *join_defs;
 
     swq_expr_node *where_expr;
 
-    void        PushOrderBy( const char *pszFieldName, int bAscending );
+    void        PushOrderBy( const char* pszTableName, const char *pszFieldName, int bAscending );
     int         order_specs;
     swq_order_def *order_defs;
 
     swq_select *poOtherSelect;
     void        PushUnionAll( swq_select* poOtherSelectIn );
 
-    CPLErr      preparse( const char *select_statement );
-    void        postpreparse();
-    CPLErr      expand_wildcard( swq_field_list *field_list );
-    CPLErr      parse( swq_field_list *field_list, int parse_flags );
+    CPLErr      preparse( const char *select_statement,
+                          int bAcceptCustomFuncs = FALSE );
+    CPLErr      expand_wildcard( swq_field_list *field_list,
+                                 int bAlwaysPrefixWithTableName );
+    CPLErr      parse( swq_field_list *field_list,
+                       swq_select_parse_options* poParseOptions );
 
+    char       *Unparse();
     void        Dump( FILE * );
 };
 
@@ -333,4 +387,6 @@ const char *swq_select_summarize( swq_select *select_info,
 
 int swq_is_reserved_keyword(const char* pszStr);
 
+char* OGRHStoreGetValue(const char* pszHStore, const char* pszSearchedKey);
+
 #endif /* def _SWQ_H_INCLUDED_ */
diff --git a/ogr/swq_expr_node.cpp b/ogr/swq_expr_node.cpp
index 53a1ca7..c1fa528 100644
--- a/ogr/swq_expr_node.cpp
+++ b/ogr/swq_expr_node.cpp
@@ -57,6 +57,19 @@ swq_expr_node::swq_expr_node( int nValueIn )
 }
 
 /************************************************************************/
+/*                        swq_expr_node(GIntBig)                        */
+/************************************************************************/
+
+swq_expr_node::swq_expr_node( GIntBig nValueIn )
+
+{
+    Initialize();
+
+    field_type = SWQ_INTEGER64;
+    int_value = nValueIn;
+}
+
+/************************************************************************/
 /*                        swq_expr_node(double)                         */
 /************************************************************************/
 
@@ -125,6 +138,7 @@ void swq_expr_node::Initialize()
     int_value = 0;
 
     is_null = FALSE;
+    table_name = NULL;
     string_value = NULL;
     geometry_value = NULL;
     papoSubExpr = NULL;
@@ -138,6 +152,7 @@ void swq_expr_node::Initialize()
 swq_expr_node::~swq_expr_node()
 
 {
+    CPLFree( table_name );
     CPLFree( string_value );
 
     int i;
@@ -186,35 +201,12 @@ void swq_expr_node::ReverseSubExpressions()
 /************************************************************************/
 
 swq_field_type swq_expr_node::Check( swq_field_list *poFieldList,
-                                     int bAllowFieldsInSecondaryTables )
+                                     int bAllowFieldsInSecondaryTables,
+                                     int bAllowMismatchTypeOnFieldComparison,
+                                     swq_custom_func_registrar* poCustomFuncRegistrar )
 
 {
 /* -------------------------------------------------------------------- */
-/*      If something is a string constant, we must check if it is       */
-/*      actually a reference to a field in which case we will           */
-/*      convert it into a column type.                                  */
-/* -------------------------------------------------------------------- */
-    if( eNodeType == SNT_CONSTANT && field_type == SWQ_STRING )
-    {
-        int wrk_field_index, wrk_table_index;
-        swq_field_type wrk_field_type;
-
-        if( is_null )
-            wrk_field_index = -1;
-        else
-            wrk_field_index = 
-                swq_identify_field( string_value, poFieldList,
-                                    &wrk_field_type, &wrk_table_index );
-        
-        if( wrk_field_index >= 0 )
-        {
-            eNodeType = SNT_COLUMN;
-            field_index = -1;
-            table_index = -1;
-        }
-    }
-
-/* -------------------------------------------------------------------- */
 /*      Otherwise we take constants literally.                          */
 /* -------------------------------------------------------------------- */
     if( eNodeType == SNT_CONSTANT )
@@ -227,13 +219,18 @@ swq_field_type swq_expr_node::Check( swq_field_list *poFieldList,
     if( eNodeType == SNT_COLUMN && field_index == -1 )
     {
         field_index = 
-            swq_identify_field( string_value, poFieldList,
+            swq_identify_field( table_name, string_value, poFieldList,
                                 &field_type, &table_index );
         
         if( field_index < 0 )
         {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "'%s' not recognised as an available field.",
+            if( table_name )
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                      "\"%s\".\"%s\" not recognised as an available field.",
+                      table_name, string_value );
+            else
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                      "\"%s\" not recognised as an available field.",
                       string_value );
 
             return SWQ_ERROR;
@@ -255,13 +252,20 @@ swq_field_type swq_expr_node::Check( swq_field_list *poFieldList,
 /*      We are dealing with an operation - fetch the definition.        */
 /* -------------------------------------------------------------------- */
     const swq_operation *poOp = 
-        swq_op_registrar::GetOperator((swq_op)nOperation);
+        (nOperation == SWQ_CUSTOM_FUNC && poCustomFuncRegistrar != NULL ) ?
+            poCustomFuncRegistrar->GetOperator(string_value) :
+            swq_op_registrar::GetOperator((swq_op)nOperation);
 
     if( poOp == NULL )
     {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "Check(): Unable to find definition for operator %d.",
-                  nOperation );
+        if( nOperation == SWQ_CUSTOM_FUNC )
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Check(): Unable to find definition for operator %s.",
+                      string_value );
+        else
+            CPLError( CE_Failure, CPLE_AppDefined,
+                      "Check(): Unable to find definition for operator %d.",
+                      nOperation );
         return SWQ_ERROR;
     }
 
@@ -272,14 +276,16 @@ swq_field_type swq_expr_node::Check( swq_field_list *poFieldList,
 
     for( i = 0; i < nSubExprCount; i++ )
     {
-        if( papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables) == SWQ_ERROR )
+        if( papoSubExpr[i]->Check(poFieldList, bAllowFieldsInSecondaryTables,
+                                  bAllowMismatchTypeOnFieldComparison,
+                                  poCustomFuncRegistrar) == SWQ_ERROR )
             return SWQ_ERROR;
     }
     
 /* -------------------------------------------------------------------- */
 /*      Check this node.                                                */
 /* -------------------------------------------------------------------- */
-    field_type = poOp->pfnChecker( this );
+    field_type = poOp->pfnChecker( this, bAllowMismatchTypeOnFieldComparison );
 
     return field_type;
 }
@@ -306,8 +312,9 @@ void swq_expr_node::Dump( FILE * fp, int depth )
 
     if( eNodeType == SNT_CONSTANT )
     {
-        if( field_type == SWQ_INTEGER || field_type == SWQ_BOOLEAN )
-            fprintf( fp, "%s  %d\n", spaces, int_value );
+        if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
+            field_type == SWQ_BOOLEAN )
+            fprintf( fp, "%s  " CPL_FRMT_GIB "\n", spaces, int_value );
         else if( field_type == SWQ_FLOAT )
             fprintf( fp, "%s  %.15g\n", spaces, float_value );
         else if( field_type == SWQ_GEOMETRY )
@@ -331,20 +338,54 @@ void swq_expr_node::Dump( FILE * fp, int depth )
 
     const swq_operation *op_def = 
         swq_op_registrar::GetOperator( (swq_op) nOperation );
-
-    fprintf( fp, "%s%s\n", spaces, op_def->pszName );
+    if( op_def )
+        fprintf( fp, "%s%s\n", spaces, op_def->pszName );
+    else
+        fprintf( fp, "%s%s\n", spaces, string_value );
 
     for( i = 0; i < nSubExprCount; i++ )
         papoSubExpr[i]->Dump( fp, depth+1 );
 }
 
+        
+/************************************************************************/
+/*                       QuoteIfNecessary()                             */
+/*                                                                      */
+/*      Add quoting if necessary to unparse a string.                   */
+/************************************************************************/
+
+CPLString swq_expr_node::QuoteIfNecessary( const CPLString &osExpr, char chQuote )
+
+{
+    if( osExpr[0] == '_' )
+        return Quote(osExpr, chQuote);
+    if( osExpr == "*" )
+        return osExpr;
+
+    for( int i = 0; i < (int) osExpr.size(); i++ )
+    {
+        char ch = osExpr[i];
+        if ((!(isalnum((int)ch) || ch == '_')) || ch == '.')
+        {
+            return Quote(osExpr, chQuote);
+        }
+    }
+
+    if (swq_is_reserved_keyword(osExpr))
+    {
+        return Quote(osExpr, chQuote);
+    }
+    
+    return osExpr;
+}
+
 /************************************************************************/
 /*                               Quote()                                */
 /*                                                                      */
 /*      Add quoting necessary to unparse a string.                      */
 /************************************************************************/
 
-void swq_expr_node::Quote( CPLString &osTarget, char chQuote )
+CPLString swq_expr_node::Quote( const CPLString &osTarget, char chQuote )
 
 {
     CPLString osNew;
@@ -364,7 +405,7 @@ void swq_expr_node::Quote( CPLString &osTarget, char chQuote )
     }
     osNew += chQuote;
 
-    osTarget = osNew;
+    return osNew;
 }
 
 /************************************************************************/
@@ -384,8 +425,9 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
         if (is_null)
             return CPLStrdup("NULL");
 
-        if( field_type == SWQ_INTEGER || field_type == SWQ_BOOLEAN )
-            osExpr.Printf( "%d", int_value );
+        if( field_type == SWQ_INTEGER || field_type == SWQ_INTEGER64 ||
+            field_type == SWQ_BOOLEAN )
+            osExpr.Printf( CPL_FRMT_GIB, int_value );
         else if( field_type == SWQ_FLOAT )
         {
             osExpr.Printf( "%.15g", float_value );
@@ -397,8 +439,7 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
         }
         else 
         {
-            osExpr = string_value;
-            Quote( osExpr );
+            osExpr = Quote( string_value );
         }
         
         return CPLStrdup(osExpr);
@@ -409,7 +450,17 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
 /* -------------------------------------------------------------------- */
     if( eNodeType == SNT_COLUMN )
     {
-        if( field_index != -1 
+        if( field_list == NULL )
+        {
+            if( table_name )
+                osExpr.Printf( "%s.%s",
+                               QuoteIfNecessary(table_name, chColumnQuote).c_str(),
+                               QuoteIfNecessary(string_value, chColumnQuote).c_str() );
+            else
+                osExpr.Printf( "%s",
+                               QuoteIfNecessary(string_value, chColumnQuote).c_str() );
+        }
+        else if( field_index != -1 
             && table_index < field_list->table_count 
             && table_index > 0 )
         {
@@ -419,8 +470,8 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
                     field_list->ids[i] == field_index )
                 {
                     osExpr.Printf( "%s.%s",
-                                   field_list->table_defs[table_index].table_name,
-                                   field_list->names[i] );
+                                   QuoteIfNecessary(field_list->table_defs[table_index].table_name, chColumnQuote).c_str(),
+                                   QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
                     break;
                 }
             }
@@ -432,7 +483,7 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
                 if( field_list->table_ids[i] == table_index &&
                     field_list->ids[i] == field_index )
                 {
-                    osExpr.Printf( "%s", field_list->names[i] );
+                    osExpr.Printf( "%s", QuoteIfNecessary(field_list->names[i], chColumnQuote).c_str() );
                     break;
                 }
             }
@@ -443,22 +494,6 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
             return CPLStrdup(CPLSPrintf("%c%c", chColumnQuote, chColumnQuote));
         }
 
-        for( int i = 0; i < (int) osExpr.size(); i++ )
-        {
-            char ch = osExpr[i];
-            if (!(isalnum((int)ch) || ch == '_'))
-            {
-                Quote( osExpr, chColumnQuote );
-                return CPLStrdup(osExpr.c_str());
-            }
-        }
-
-        if (swq_is_reserved_keyword(osExpr))
-        {
-            Quote( osExpr, chColumnQuote );
-            return CPLStrdup(osExpr.c_str());
-        }
-
         /* The string is just alphanum and not a reserved SQL keyword, no needs to quote and escape */
         return CPLStrdup(osExpr.c_str());
     }
@@ -472,16 +507,36 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
     for( i = 0; i < nSubExprCount; i++ )
         apszSubExpr.push_back( papoSubExpr[i]->Unparse(field_list, chColumnQuote) );
 
+    osExpr = UnparseOperationFromUnparsedSubExpr(&apszSubExpr[0]);
+    
+/* -------------------------------------------------------------------- */
+/*      cleanup subexpressions.                                         */
+/* -------------------------------------------------------------------- */
+    for( i = 0; i < nSubExprCount; i++ )
+        CPLFree( apszSubExpr[i] );
+
+    return CPLStrdup( osExpr.c_str() );
+}
+
+/************************************************************************/
+/*                  UnparseOperationFromUnparsedSubExpr()               */
+/************************************************************************/
+
+CPLString swq_expr_node::UnparseOperationFromUnparsedSubExpr(char** apszSubExpr)
+{
+    int i;
+    CPLString osExpr;
+
 /* -------------------------------------------------------------------- */
 /*      Put things together in a fashion depending on the operator.     */
 /* -------------------------------------------------------------------- */
     const swq_operation *poOp = 
         swq_op_registrar::GetOperator( (swq_op) nOperation );
 
-    if( poOp == NULL )
+    if( poOp == NULL && nOperation != SWQ_CUSTOM_FUNC )
     {
         CPLAssert( FALSE );
-        return CPLStrdup("");
+        return osExpr;
     }
 
     switch( nOperation )
@@ -592,7 +647,10 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
         break;
 
       default: // function style.
-        osExpr.Printf( "%s(", poOp->pszName );
+        if( nOperation != SWQ_CUSTOM_FUNC )
+            osExpr.Printf( "%s(", poOp->pszName );
+        else
+            osExpr.Printf( "%s(", string_value );
         for( i = 0; i < nSubExprCount; i++ )
         {
             if( i > 0 )
@@ -604,14 +662,47 @@ char *swq_expr_node::Unparse( swq_field_list *field_list, char chColumnQuote )
         osExpr += ")";
         break;
     }
+    
+    return osExpr;
+}
 
-/* -------------------------------------------------------------------- */
-/*      cleanup subexpressions.                                         */
-/* -------------------------------------------------------------------- */
-    for( i = 0; i < nSubExprCount; i++ )
-        CPLFree( apszSubExpr[i] );
+/************************************************************************/
+/*                               Clone()                                */
+/************************************************************************/
 
-    return CPLStrdup( osExpr.c_str() );
+swq_expr_node *swq_expr_node::Clone()
+{
+    swq_expr_node* poRetNode = new swq_expr_node();
+
+    poRetNode->eNodeType = eNodeType;
+    poRetNode->field_type = field_type;
+    if( eNodeType == SNT_OPERATION )
+    {
+        poRetNode->nOperation = nOperation;
+        poRetNode->nSubExprCount = nSubExprCount;
+        poRetNode->papoSubExpr = (swq_expr_node **) 
+                CPLMalloc( sizeof(void*) * nSubExprCount );
+        for(int i=0;i<nSubExprCount;i++)
+            poRetNode->papoSubExpr[i] = papoSubExpr[i]->Clone();
+    }
+    else if( eNodeType == SNT_COLUMN )
+    {
+        poRetNode->field_index = field_index;
+        poRetNode->table_index = table_index;
+        poRetNode->table_name = table_name ? CPLStrdup(table_name) : NULL;
+    }
+    else if( eNodeType == SNT_CONSTANT )
+    {
+        poRetNode->is_null = is_null;
+        poRetNode->int_value = int_value;
+        poRetNode->float_value = float_value;
+        if( geometry_value )
+            poRetNode->geometry_value = geometry_value->clone();
+        else
+            poRetNode->geometry_value = NULL;
+    }
+    poRetNode->string_value = string_value ? CPLStrdup(string_value) : NULL;
+    return poRetNode;
 }
 
 /************************************************************************/
@@ -629,26 +720,7 @@ swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
 /* -------------------------------------------------------------------- */
     if( eNodeType == SNT_CONSTANT )
     {
-        poRetNode = new swq_expr_node();
-
-        poRetNode->eNodeType = SNT_CONSTANT;
-        poRetNode->field_type = field_type;
-        poRetNode->int_value = int_value;
-        poRetNode->float_value = float_value;
-
-        if( string_value )
-            poRetNode->string_value = CPLStrdup(string_value);
-        else
-            poRetNode->string_value = NULL;
-
-        if( geometry_value )
-            poRetNode->geometry_value = geometry_value->clone();
-        else
-            poRetNode->geometry_value = NULL;
-
-        poRetNode->is_null = is_null;
-
-        return poRetNode;
+        return Clone();
     }
 
 /* -------------------------------------------------------------------- */
@@ -677,8 +749,14 @@ swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
         }
         else
         {
-            apoValues.push_back(papoSubExpr[i]->Evaluate(pfnFetcher,pRecord));
-            anValueNeedsFree.push_back( TRUE );
+            swq_expr_node* poSubExprVal = papoSubExpr[i]->Evaluate(pfnFetcher,pRecord);
+            if( poSubExprVal == NULL )
+                bError = TRUE;
+            else
+            {
+                apoValues.push_back(poSubExprVal);
+                anValueNeedsFree.push_back( TRUE );
+            }
         }
     }
 
@@ -689,8 +767,20 @@ swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
     {
         const swq_operation *poOp = 
             swq_op_registrar::GetOperator( (swq_op) nOperation );
-        
-        poRetNode = poOp->pfnEvaluator( this, &(apoValues[0]) );
+        if( poOp == NULL )
+        {
+            if( nOperation == SWQ_CUSTOM_FUNC )
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "Evaluate(): Unable to find definition for operator %s.",
+                        string_value );
+            else
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "Evaluate(): Unable to find definition for operator %d.",
+                        nOperation );
+            poRetNode = NULL;
+        }
+        else
+            poRetNode = poOp->pfnEvaluator( this, &(apoValues[0]) );
     }
 
 /* -------------------------------------------------------------------- */
@@ -704,3 +794,36 @@ swq_expr_node *swq_expr_node::Evaluate( swq_field_fetcher pfnFetcher,
 
     return poRetNode;
 }
+
+/************************************************************************/
+/*                      ReplaceBetweenByGEAndLERecurse()                */
+/************************************************************************/
+
+void swq_expr_node::ReplaceBetweenByGEAndLERecurse()
+{
+    if( eNodeType != SNT_OPERATION )
+        return;
+
+    if( nOperation != SWQ_BETWEEN )
+    {
+        for(int i=0;i<nSubExprCount;i++)
+            papoSubExpr[i]->ReplaceBetweenByGEAndLERecurse();
+        return;
+    }
+
+    if( nSubExprCount != 3 )
+        return;
+
+    swq_expr_node* poExpr0 = papoSubExpr[0];
+    swq_expr_node* poExpr1 = papoSubExpr[1];
+    swq_expr_node* poExpr2 = papoSubExpr[2];
+    
+    nSubExprCount = 2;
+    nOperation = SWQ_AND;
+    papoSubExpr[0] = new swq_expr_node(SWQ_GE);
+    papoSubExpr[0]->PushSubExpression(poExpr0);
+    papoSubExpr[0]->PushSubExpression(poExpr1);
+    papoSubExpr[1] = new swq_expr_node(SWQ_LE);
+    papoSubExpr[1]->PushSubExpression(poExpr0->Clone());
+    papoSubExpr[1]->PushSubExpression(poExpr2);
+}
diff --git a/ogr/swq_op_general.cpp b/ogr/swq_op_general.cpp
index a9ffabd..bef9f5e 100644
--- a/ogr/swq_op_general.cpp
+++ b/ogr/swq_op_general.cpp
@@ -104,6 +104,144 @@ int swq_test_like( const char *input, const char *pattern, char chEscape )
 }
 
 /************************************************************************/
+/*                        OGRHStoreGetValue()                           */
+/************************************************************************/
+
+static char* OGRHStoreCheckEnd(char* pszIter, int bIsKey)
+{
+    pszIter ++;
+    for( ; *pszIter != '\0'; pszIter ++ )
+    {
+        if( bIsKey )
+        {
+            if( *pszIter == ' ' )
+                ;
+            else if( *pszIter == '=' && pszIter[1] == '>' )
+                return pszIter + 2;
+            else
+                return NULL;
+        }
+        else
+        {
+            if( *pszIter == ' ' )
+                ;
+            else if( *pszIter == ',' )
+                return pszIter + 1;
+            else
+                return NULL;
+        }
+    }
+    return pszIter;
+}
+
+static char* OGRHStoreGetNextString(char* pszIter,
+                                    char** ppszOut,
+                                    int bIsKey)
+{
+    char ch;
+    int bInString = FALSE;
+    char* pszOut = NULL;
+    *ppszOut = NULL;
+    for( ; (ch = *pszIter) != '\0'; pszIter ++ )
+    {
+        if( bInString )
+        {
+            if( ch == '"' )
+            {
+                *pszOut = '\0';
+                return OGRHStoreCheckEnd(pszIter, bIsKey);
+            }
+            else if( ch == '\\')
+            {
+                pszIter ++;
+                if( (ch = *pszIter) == '\0' )
+                    return NULL;
+            }
+            *pszOut = ch;
+            pszOut ++;
+        }
+        else
+        {
+            if( ch == ' ' )
+            {
+                if( pszOut != NULL )
+                {
+                    *pszIter = '\0';
+                    return OGRHStoreCheckEnd(pszIter, bIsKey);
+                }
+            }
+            else if( bIsKey && ch == '=' && pszIter[1] == '>' )
+            {
+                if( pszOut != NULL )
+                {
+                    *pszIter = '\0';
+                    return pszIter + 2;
+                }
+            }
+            else if( !bIsKey && ch == ',' )
+            {
+                if( pszOut != NULL )
+                {
+                    *pszIter = '\0';
+                    return pszIter + 1;
+                }
+            }
+            else if( ch == '"' )
+            {
+                pszOut = *ppszOut = pszIter + 1;
+                bInString = TRUE;
+            }
+            else if( pszOut == NULL )
+                pszOut = *ppszOut = pszIter;
+        }
+    }
+
+    if( !bInString && pszOut != NULL )
+    {
+        return pszIter;
+    }
+    return NULL;
+}
+
+static char* OGRHStoreGetNextKeyValue(char* pszHStore,
+                                      char** ppszKey,
+                                       char** ppszValue)
+{
+    char* pszNext = OGRHStoreGetNextString(pszHStore, ppszKey, TRUE);
+    if( pszNext == NULL || *pszNext == '\0' )
+        return NULL;
+    return OGRHStoreGetNextString(pszNext, ppszValue, FALSE);
+}
+
+char* OGRHStoreGetValue(const char* pszHStore, const char* pszSearchedKey)
+{
+    char* pszHStoreDup = CPLStrdup(pszHStore);
+    char* pszHStoreIter = pszHStoreDup;
+    char* pszRet = NULL;
+
+    while( TRUE )
+    {
+        char* pszKey, *pszValue;
+        pszHStoreIter = OGRHStoreGetNextKeyValue(pszHStoreIter, &pszKey, &pszValue);
+        if( pszHStoreIter == NULL )
+        {
+            break;
+        }
+        if( strcmp(pszKey, pszSearchedKey) == 0 )
+        {
+            pszRet = CPLStrdup(pszValue);
+            break;
+        }
+        if( *pszHStoreIter == '\0' )
+        {
+            break;
+        }
+    }
+    CPLFree(pszHStoreDup);
+    return pszRet;
+}
+
+/************************************************************************/
 /*                        SWQGeneralEvaluator()                         */
 /************************************************************************/
 
@@ -124,11 +262,11 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
         poRet = new swq_expr_node(0);
         poRet->field_type = node->field_type;
 
-        if( sub_node_values[0]->field_type == SWQ_INTEGER )
-            sub_node_values[0]->float_value = sub_node_values[0]->int_value;
+        if( SWQ_IS_INTEGER(sub_node_values[0]->field_type) )
+            sub_node_values[0]->float_value = (double) sub_node_values[0]->int_value;
         if( node->nSubExprCount > 1 &&
-            sub_node_values[1]->field_type == SWQ_INTEGER )
-            sub_node_values[1]->float_value = sub_node_values[1]->int_value;
+            SWQ_IS_INTEGER(sub_node_values[1]->field_type) )
+            sub_node_values[1]->float_value = (double)sub_node_values[1]->int_value;
 
         if( node->nOperation != SWQ_ISNULL )
         {
@@ -147,7 +285,7 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
                         poRet->is_null = 1;
                         return poRet;
                     }
-                    else if( poRet->field_type == SWQ_INTEGER ||
+                    else if( SWQ_IS_INTEGER(poRet->field_type) ||
                              node->nOperation == SWQ_MODULUS )
                     {
                         poRet->field_type = SWQ_INTEGER;
@@ -243,12 +381,12 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
             
           case SWQ_MODULUS:
           {
-            int nRight = (int) sub_node_values[1]->float_value;
+            GIntBig nRight = (GIntBig) sub_node_values[1]->float_value;
             poRet->field_type = SWQ_INTEGER;
             if (nRight == 0)
                 poRet->int_value = INT_MAX;
             else
-                poRet->int_value = ((int) sub_node_values[0]->float_value)
+                poRet->int_value = ((GIntBig) sub_node_values[0]->float_value)
                     % nRight;
             break;
           }
@@ -263,7 +401,7 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
 /* -------------------------------------------------------------------- */
 /*      integer/boolean operations.                                     */
 /* -------------------------------------------------------------------- */
-    else if( sub_node_values[0]->field_type == SWQ_INTEGER
+    else if( SWQ_IS_INTEGER(sub_node_values[0]->field_type)
         || sub_node_values[0]->field_type == SWQ_BOOLEAN )
     {
         poRet = new swq_expr_node(0);
@@ -280,7 +418,7 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
                         poRet->int_value = FALSE;
                         return poRet;
                     }
-                    else if( poRet->field_type == SWQ_INTEGER )
+                    else if( SWQ_IS_INTEGER(poRet->field_type) )
                     {
                         poRet->int_value = 0;
                         poRet->is_null = 1;
@@ -434,10 +572,45 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
         switch( (swq_op) node->nOperation )
         {
           case SWQ_EQ:
-            poRet->int_value = 
-                strcasecmp(sub_node_values[0]->string_value,
-                           sub_node_values[1]->string_value) == 0;
+          {
+            /* When comparing timestamps, the +00 at the end might be discarded */
+            /* if the other member has no explicit timezone */
+            if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
+                 sub_node_values[0]->field_type == SWQ_STRING) &&
+                (sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
+                 sub_node_values[1]->field_type == SWQ_STRING) &&
+                strlen(sub_node_values[0]->string_value) > 3 &&
+                strlen(sub_node_values[1]->string_value) > 3 &&
+                (strcmp(sub_node_values[0]->string_value + strlen(sub_node_values[0]->string_value)-3, "+00") == 0 &&
+                 sub_node_values[1]->string_value[strlen(sub_node_values[1]->string_value)-3] == ':') )
+            {
+                poRet->int_value = 
+                    EQUALN(sub_node_values[0]->string_value,
+                           sub_node_values[1]->string_value,
+                           strlen(sub_node_values[1]->string_value));
+            }
+            else if( (sub_node_values[0]->field_type == SWQ_TIMESTAMP ||
+                      sub_node_values[0]->field_type == SWQ_STRING) &&
+                     (sub_node_values[1]->field_type == SWQ_TIMESTAMP ||
+                      sub_node_values[1]->field_type == SWQ_STRING) &&
+                     strlen(sub_node_values[0]->string_value) > 3 &&
+                     strlen(sub_node_values[1]->string_value) > 3 &&
+                     (sub_node_values[0]->string_value[strlen(sub_node_values[0]->string_value)-3] == ':')  &&
+                      strcmp(sub_node_values[1]->string_value + strlen(sub_node_values[1]->string_value)-3, "+00") == 0)
+            {
+                poRet->int_value = 
+                    EQUALN(sub_node_values[0]->string_value,
+                           sub_node_values[1]->string_value,
+                           strlen(sub_node_values[0]->string_value));
+            }
+            else
+            {
+                poRet->int_value = 
+                    strcasecmp(sub_node_values[0]->string_value,
+                            sub_node_values[1]->string_value) == 0;
+            }
             break;
+          }
 
           case SWQ_NE:
             poRet->int_value = 
@@ -527,8 +700,8 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
               int nOffset, nSize;
               const char *pszSrcStr = sub_node_values[0]->string_value;
 
-              if( sub_node_values[1]->field_type == SWQ_INTEGER )
-                  nOffset = sub_node_values[1]->int_value;
+              if( SWQ_IS_INTEGER(sub_node_values[1]->field_type) )
+                  nOffset = (int)sub_node_values[1]->int_value;
               else if( sub_node_values[1]->field_type == SWQ_FLOAT )
                   nOffset = (int) sub_node_values[1]->float_value; 
               else
@@ -536,8 +709,8 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
 
               if( node->nSubExprCount < 3 )
                   nSize = 100000;
-              else if( sub_node_values[2]->field_type == SWQ_INTEGER )
-                  nSize = sub_node_values[2]->int_value;
+              else if( SWQ_IS_INTEGER(sub_node_values[2]->field_type) )
+                  nSize = (int)sub_node_values[2]->int_value;
               else if( sub_node_values[2]->field_type == SWQ_FLOAT )
                   nSize = (int) sub_node_values[2]->float_value; 
               else
@@ -577,6 +750,16 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
               break;
           }
 
+          case SWQ_HSTORE_GET_VALUE:
+          {
+              const char *pszHStore = sub_node_values[0]->string_value;
+              const char *pszSearchedKey = sub_node_values[1]->string_value;
+              char* pszRet = OGRHStoreGetValue(pszHStore, pszSearchedKey);
+              poRet->string_value = pszRet ? pszRet : CPLStrdup("");
+              poRet->is_null = (pszRet == NULL);
+              break;
+          }
+
           default:
             CPLAssert( FALSE );
             delete poRet;
@@ -589,10 +772,10 @@ swq_expr_node *SWQGeneralEvaluator( swq_expr_node *node,
 }
 
 /************************************************************************/
-/*                    SWQAutoPromoteIntegerToFloat()                    */
+/*                SWQAutoPromoteIntegerToInteger64OrFloat()             */
 /************************************************************************/
 
-static void SWQAutoPromoteIntegerToFloat( swq_expr_node *poNode )
+static void SWQAutoPromoteIntegerToInteger64OrFloat( swq_expr_node *poNode )
 
 {
     if( poNode->nSubExprCount < 2 )
@@ -601,14 +784,18 @@ static void SWQAutoPromoteIntegerToFloat( swq_expr_node *poNode )
     swq_field_type eArgType = poNode->papoSubExpr[0]->field_type;
     int i;
 
-    // We allow mixes of integer and float, and string and dates.
-    // When encountered, we promote integers to floats, and strings to
-    // dates.  We do that now.
+    // We allow mixes of integer, integer64 and float, and string and dates.
+    // When encountered, we promote integers/integer64 to floats, 
+    // integer to integer64 and strings to dates.  We do that now.
     for( i = 1; i < poNode->nSubExprCount; i++ )
     {
-        if( eArgType == SWQ_INTEGER
-            && poNode->papoSubExpr[i]->field_type == SWQ_FLOAT )
+        swq_expr_node *poSubNode = poNode->papoSubExpr[i];
+        if( SWQ_IS_INTEGER(eArgType)
+            && poSubNode->field_type == SWQ_FLOAT )
             eArgType = SWQ_FLOAT;
+        else if( eArgType == SWQ_INTEGER
+                 && poSubNode->field_type == SWQ_INTEGER64 )
+            eArgType = SWQ_INTEGER64;
     }
     
     for( i = 0; i < poNode->nSubExprCount; i++ )
@@ -616,14 +803,21 @@ static void SWQAutoPromoteIntegerToFloat( swq_expr_node *poNode )
         swq_expr_node *poSubNode = poNode->papoSubExpr[i];
 
         if( eArgType == SWQ_FLOAT
-            && poSubNode->field_type == SWQ_INTEGER )
+            && SWQ_IS_INTEGER(poSubNode->field_type) )
         {
             if( poSubNode->eNodeType == SNT_CONSTANT )
             {
-                poSubNode->float_value = poSubNode->int_value;
+                poSubNode->float_value = (double) poSubNode->int_value;
                 poSubNode->field_type = SWQ_FLOAT;
             }
         }
+        else if( eArgType == SWQ_INTEGER64 && poSubNode->field_type == SWQ_INTEGER )
+        {
+            if( poSubNode->eNodeType == SNT_CONSTANT )
+            {
+                poSubNode->field_type = SWQ_INTEGER64;
+            }
+        }
     }
 }
 
@@ -693,9 +887,9 @@ static void SWQAutoConvertStringToNumeric( swq_expr_node *poNode )
 
         /* identify the mixture of the argument type */
         if( (eArgType == SWQ_STRING
-            && (poSubNode->field_type == SWQ_INTEGER
+            && (SWQ_IS_INTEGER(poSubNode->field_type)
                || poSubNode->field_type == SWQ_FLOAT)) ||
-            (eArgType == SWQ_INTEGER
+            (SWQ_IS_INTEGER(eArgType)
             && poSubNode->field_type == SWQ_STRING) )
         {
             eArgType = SWQ_FLOAT;
@@ -724,7 +918,7 @@ static void SWQAutoConvertStringToNumeric( swq_expr_node *poNode )
                 }
 
                 /* we should also fill the integer value in this case */
-                poSubNode->int_value = (int)poSubNode->float_value;
+                poSubNode->int_value = (GIntBig)poSubNode->float_value;
                 poSubNode->field_type = SWQ_FLOAT;
             }
         }
@@ -757,7 +951,8 @@ static int SWQCheckSubExprAreNotGeometries( swq_expr_node *poNode )
 /*      circumstances.                                                  */
 /************************************************************************/
 
-swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
+swq_field_type SWQGeneralChecker( swq_expr_node *poNode,
+                                  int bAllowMismatchTypeOnFieldComparison  )
 
 {									
     swq_field_type eRetType = SWQ_ERROR;
@@ -786,7 +981,7 @@ swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
             return SWQ_ERROR;
         eRetType = SWQ_BOOLEAN;
         SWQAutoConvertStringToNumeric( poNode );
-        SWQAutoPromoteIntegerToFloat( poNode );
+        SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
         SWQAutoPromoteStringToDateTime( poNode );
         eArgType = poNode->papoSubExpr[0]->field_type;
         break;
@@ -812,11 +1007,13 @@ swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
       case SWQ_ADD:
         if( !SWQCheckSubExprAreNotGeometries(poNode) )
             return SWQ_ERROR;
-        SWQAutoPromoteIntegerToFloat( poNode );
+        SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
         if( poNode->papoSubExpr[0]->field_type == SWQ_STRING )
             eRetType = eArgType = SWQ_STRING;
         else if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT )
             eRetType = eArgType = SWQ_FLOAT;
+        else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 )
+            eRetType = eArgType = SWQ_INTEGER64;
         else
             eRetType = eArgType = SWQ_INTEGER;
         break;
@@ -826,9 +1023,11 @@ swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
       case SWQ_DIVIDE:
         if( !SWQCheckSubExprAreNotGeometries(poNode) )
             return SWQ_ERROR;
-        SWQAutoPromoteIntegerToFloat( poNode );
+        SWQAutoPromoteIntegerToInteger64OrFloat( poNode );
         if( poNode->papoSubExpr[0]->field_type == SWQ_FLOAT )
             eRetType = eArgType = SWQ_FLOAT;
+        else if( poNode->papoSubExpr[0]->field_type == SWQ_INTEGER64 )
+            eRetType = eArgType = SWQ_INTEGER64;
         else
             eRetType = eArgType = SWQ_INTEGER;
         break;
@@ -862,6 +1061,26 @@ swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
         }
         break;
 
+      case SWQ_HSTORE_GET_VALUE:
+        if( !SWQCheckSubExprAreNotGeometries(poNode) )
+            return SWQ_ERROR;
+        eRetType = SWQ_STRING;
+        if( poNode->nSubExprCount != 2 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "Expected 2 arguments to hstore_get_value(), but got %d.",
+                      poNode->nSubExprCount );
+            return SWQ_ERROR;
+        }
+        if( poNode->papoSubExpr[0]->field_type != SWQ_STRING 
+            || poNode->papoSubExpr[1]->field_type != SWQ_STRING )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                      "Wrong argument type for hstore_get_value(), expected hstore_get_value(string,string)." );
+            return SWQ_ERROR;
+        }
+        break;
+        
       default:
       {
           const swq_operation *poOp = 
@@ -880,17 +1099,48 @@ swq_field_type SWQGeneralChecker( swq_expr_node *poNode )
     {
         int i;
 
-        if( eArgType == SWQ_INTEGER )
+        if( SWQ_IS_INTEGER(eArgType) || eArgType == SWQ_BOOLEAN )
             eArgType = SWQ_FLOAT;
 
         for( i = 0; i < poNode->nSubExprCount; i++ )
         {
             swq_field_type eThisArgType = poNode->papoSubExpr[i]->field_type;
-            if( eThisArgType == SWQ_INTEGER )
+            if( SWQ_IS_INTEGER(eThisArgType) ||  eThisArgType == SWQ_BOOLEAN )
                 eThisArgType = SWQ_FLOAT;
 
             if( eArgType != eThisArgType )
             {
+                // Conveniency for join. We allow comparing numeric columns
+                // and string columns, by casting string columns to numeric
+                if( bAllowMismatchTypeOnFieldComparison &&
+                    poNode->nSubExprCount == 2 &&
+                    poNode->nOperation == SWQ_EQ &&
+                    poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+                    poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
+                    eArgType == SWQ_FLOAT && eThisArgType == SWQ_STRING )
+                {
+                    swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST);
+                    poNewNode->PushSubExpression(poNode->papoSubExpr[i]);
+                    poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
+                    SWQCastChecker(poNewNode, FALSE);
+                    poNode->papoSubExpr[i] = poNewNode;
+                    break;
+                }
+                if( bAllowMismatchTypeOnFieldComparison &&
+                    poNode->nSubExprCount == 2 &&
+                    poNode->nOperation == SWQ_EQ &&
+                    poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
+                    poNode->papoSubExpr[i]->eNodeType == SNT_COLUMN &&
+                    eThisArgType == SWQ_FLOAT && eArgType == SWQ_STRING )
+                {
+                    swq_expr_node* poNewNode = new swq_expr_node(SWQ_CAST);
+                    poNewNode->PushSubExpression(poNode->papoSubExpr[0]);
+                    poNewNode->PushSubExpression(new swq_expr_node("FLOAT"));
+                    SWQCastChecker(poNewNode, FALSE);
+                    poNode->papoSubExpr[0] = poNewNode;
+                    break;
+                }
+
                 const swq_operation *poOp = 
                     swq_op_registrar::GetOperator((swq_op)poNode->nOperation);
                 
@@ -947,6 +1197,11 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
                     poRetNode->int_value = poSrcNode->int_value;
                     break;
 
+                case SWQ_INTEGER64:
+                    // TODO: warn in case of overflow ?
+                    poRetNode->int_value = (int) poSrcNode->int_value;
+                    break;
+
                 case SWQ_FLOAT:
                     poRetNode->int_value = (int) poSrcNode->float_value;
                     break;
@@ -957,6 +1212,30 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
             }
         }
         break;
+        
+        case SWQ_INTEGER64:
+        {
+            poRetNode = new swq_expr_node( 0 );
+            poRetNode->is_null = poSrcNode->is_null;
+
+            switch( poSrcNode->field_type )
+            {
+                case SWQ_INTEGER:
+                case SWQ_INTEGER64:
+                case SWQ_BOOLEAN:
+                    poRetNode->int_value = poSrcNode->int_value;
+                    break;
+
+                case SWQ_FLOAT:
+                    poRetNode->int_value = (GIntBig) poSrcNode->float_value;
+                    break;
+
+                default:
+                    poRetNode->int_value = CPLAtoGIntBig(poSrcNode->string_value);
+                    break;
+            }
+        }
+        break;
 
         case SWQ_FLOAT:
         {
@@ -966,8 +1245,9 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
             switch( poSrcNode->field_type )
             {
                 case SWQ_INTEGER:
+                case SWQ_INTEGER64:
                 case SWQ_BOOLEAN:
-                    poRetNode->float_value = poSrcNode->int_value;
+                    poRetNode->float_value = (double) poSrcNode->int_value;
                     break;
 
                 case SWQ_FLOAT:
@@ -975,7 +1255,7 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
                     break;
 
                 default:
-                    poRetNode->float_value = atof(poSrcNode->string_value);
+                    poRetNode->float_value = CPLAtof(poSrcNode->string_value);
                     break;
             }
         }
@@ -1022,7 +1302,8 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
             {
                 case SWQ_INTEGER:
                 case SWQ_BOOLEAN:
-                    osRet.Printf( "%d", poSrcNode->int_value );
+                case SWQ_INTEGER64:
+                    osRet.Printf( CPL_FRMT_GIB, poSrcNode->int_value );
                     break;
 
                 case SWQ_FLOAT:
@@ -1052,7 +1333,7 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
             {
                 int nWidth;
 
-                nWidth = sub_node_values[2]->int_value;
+                nWidth = (int) sub_node_values[2]->int_value;
                 if( nWidth > 0 && (int) strlen(osRet) > nWidth )
                     osRet.resize(nWidth);
             }
@@ -1069,7 +1350,8 @@ swq_expr_node *SWQCastEvaluator( swq_expr_node *node,
 /*                           SWQCastChecker()                           */
 /************************************************************************/
 
-swq_field_type SWQCastChecker( swq_expr_node *poNode )
+swq_field_type SWQCastChecker( swq_expr_node *poNode,
+                               CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
 
 {									
     swq_field_type eType = SWQ_ERROR;
@@ -1083,10 +1365,16 @@ swq_field_type SWQCastChecker( swq_expr_node *poNode )
                   pszTypeName );
     }
 
+    else if( EQUAL(pszTypeName,"boolean") )
+        eType = SWQ_BOOLEAN;
     else if( EQUAL(pszTypeName,"character") )
         eType = SWQ_STRING;
     else if( EQUAL(pszTypeName,"integer") )
         eType = SWQ_INTEGER;
+    else if( EQUAL(pszTypeName,"bigint") )
+        eType = SWQ_INTEGER64;
+    else if( EQUAL(pszTypeName,"smallint") )
+        eType = SWQ_INTEGER;
     else if( EQUAL(pszTypeName,"float") )
         eType = SWQ_FLOAT;
     else if( EQUAL(pszTypeName,"numeric") )
diff --git a/ogr/swq_op_registrar.cpp b/ogr/swq_op_registrar.cpp
index d9f7a54..b5445dc 100644
--- a/ogr/swq_op_registrar.cpp
+++ b/ogr/swq_op_registrar.cpp
@@ -31,7 +31,8 @@
 #include "cpl_conv.h"
 #include "swq.h"
 
-static swq_field_type SWQColumnFuncChecker( swq_expr_node *poNode );
+static swq_field_type SWQColumnFuncChecker( swq_expr_node *poNode,
+                                            int bAllowMismatchTypeOnFieldComparison );
 
 static const swq_operation swq_apsOperations[] =
 {
@@ -55,6 +56,7 @@ static const swq_operation swq_apsOperations[] =
     { "%", SWQ_MODULUS , SWQGeneralEvaluator, SWQGeneralChecker },
     { "CONCAT", SWQ_CONCAT , SWQGeneralEvaluator, SWQGeneralChecker },
     { "SUBSTR", SWQ_SUBSTR , SWQGeneralEvaluator, SWQGeneralChecker },
+    { "HSTORE_GET_VALUE", SWQ_HSTORE_GET_VALUE , SWQGeneralEvaluator, SWQGeneralChecker },
 
     { "AVG", SWQ_AVG, SWQGeneralEvaluator, SWQColumnFuncChecker },
     { "MIN", SWQ_MIN, SWQGeneralEvaluator, SWQColumnFuncChecker },
@@ -111,7 +113,8 @@ const swq_operation *swq_op_registrar::GetOperator( swq_op eOperator )
 /*      error if they are used in any other context.                    */
 /************************************************************************/
 
-static swq_field_type SWQColumnFuncChecker( swq_expr_node *poNode )
+static swq_field_type SWQColumnFuncChecker( swq_expr_node *poNode,
+                                            CPL_UNUSED int bAllowMismatchTypeOnFieldComparison )
 {
     const swq_operation *poOp =
             swq_op_registrar::GetOperator((swq_op)poNode->nOperation);
diff --git a/ogr/swq_parser.cpp b/ogr/swq_parser.cpp
index ac107c5..4371b13 100644
--- a/ogr/swq_parser.cpp
+++ b/ogr/swq_parser.cpp
@@ -3,7 +3,6 @@
 /* Bison implementation for Yacc-like parsers in C
 
    Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
- * Copyright (c) 2010-2013, Even Rouault <even dot rouault at mines-paris dot org>
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -177,14 +176,13 @@ extern int swqdebug;
     SWQT_CAST = 280,
     SWQT_UNION = 281,
     SWQT_ALL = 282,
-    SWQT_LOGICAL_START = 283,
-    SWQT_VALUE_START = 284,
-    SWQT_SELECT_START = 285,
-    SWQT_NOT = 286,
-    SWQT_OR = 287,
-    SWQT_AND = 288,
-    SWQT_UMINUS = 289,
-    SWQT_RESERVED_KEYWORD = 290
+    SWQT_VALUE_START = 283,
+    SWQT_SELECT_START = 284,
+    SWQT_NOT = 285,
+    SWQT_OR = 286,
+    SWQT_AND = 287,
+    SWQT_UMINUS = 288,
+    SWQT_RESERVED_KEYWORD = 289
   };
 #endif
 
@@ -203,7 +201,7 @@ int swqparse (swq_parse_context *context);
 
 /* Copy the second part of user declarations.  */
 
-#line 206 "swq_parser.cpp" /* yacc.c:358  */
+#line 205 "swq_parser.cpp" /* yacc.c:358  */
 
 #ifdef short
 # undef short
@@ -424,23 +422,23 @@ union yyalloc
 #endif /* !YYCOPY_NEEDED */
 
 /* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  23
+#define YYFINAL  20
 /* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   328
+#define YYLAST   416
 
 /* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  49
+#define YYNTOKENS  48
 /* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  21
+#define YYNNTS  20
 /* YYNRULES -- Number of rules.  */
-#define YYNRULES  89
+#define YYNRULES  87
 /* YYNSTATES -- Number of states.  */
-#define YYNSTATES  191
+#define YYNSTATES  185
 
 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    by yylex, with out-of-bounds checking.  */
 #define YYUNDEFTOK  2
-#define YYMAXUTOK   290
+#define YYMAXUTOK   289
 
 #define YYTRANSLATE(YYX)                                                \
   ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -452,10 +450,10 @@ static const yytype_uint8 yytranslate[] =
        0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    46,     2,     2,     2,    38,     2,     2,
-      41,    42,    36,    34,    47,    35,    48,    37,     2,     2,
+       2,     2,     2,    36,     2,     2,     2,    41,     2,     2,
+      44,    45,    39,    37,    46,    38,    47,    40,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-      44,    43,    45,     2,     2,     2,     2,     2,     2,     2,
+      34,    33,    35,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
        2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
@@ -477,23 +475,22 @@ static const yytype_uint8 yytranslate[] =
        2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
        5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
       15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    39,
-      40
+      25,    26,    27,    28,    29,    30,    31,    32,    42,    43
 };
 
 #if YYDEBUG
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   111,   111,   116,   121,   127,   135,   143,   150,   155,
-     163,   171,   179,   187,   195,   203,   211,   219,   227,   235,
-     248,   257,   271,   280,   295,   304,   318,   325,   339,   345,
-     352,   359,   375,   380,   385,   389,   394,   399,   404,   420,
-     427,   434,   441,   448,   455,   479,   487,   493,   500,   509,
-     527,   547,   548,   551,   556,   557,   559,   567,   568,   571,
-     580,   589,   598,   610,   621,   635,   657,   687,   721,   745,
-     774,   780,   783,   784,   789,   790,   799,   809,   810,   813,
-     814,   817,   823,   829,   837,   841,   847,   857,   868,   879
+       0,   112,   112,   113,   118,   124,   129,   137,   145,   152,
+     160,   168,   176,   184,   192,   200,   208,   216,   224,   232,
+     245,   254,   268,   277,   292,   301,   315,   322,   336,   342,
+     349,   356,   368,   373,   378,   382,   387,   392,   397,   413,
+     420,   427,   434,   441,   448,   484,   492,   498,   505,   514,
+     532,   552,   553,   556,   561,   567,   568,   570,   578,   579,
+     582,   591,   602,   616,   638,   668,   702,   726,   755,   761,
+     764,   765,   770,   771,   777,   784,   785,   788,   789,   792,
+     798,   804,   812,   822,   833,   844,   857,   868
 };
 #endif
 
@@ -507,15 +504,15 @@ static const char *const yytname[] =
   "\"LIKE\"", "\"ESCAPE\"", "\"BETWEEN\"", "\"NULL\"", "\"IS\"",
   "\"SELECT\"", "\"LEFT\"", "\"JOIN\"", "\"WHERE\"", "\"ON\"", "\"ORDER\"",
   "\"BY\"", "\"FROM\"", "\"AS\"", "\"ASC\"", "\"DESC\"", "\"DISTINCT\"",
-  "\"CAST\"", "\"UNION\"", "\"ALL\"", "SWQT_LOGICAL_START",
-  "SWQT_VALUE_START", "SWQT_SELECT_START", "\"NOT\"", "\"OR\"", "\"AND\"",
-  "'+'", "'-'", "'*'", "'/'", "'%'", "SWQT_UMINUS", "\"reserved keyword\"",
-  "'('", "')'", "'='", "'<'", "'>'", "'!'", "','", "'.'", "$accept",
-  "input", "logical_expr", "value_expr_list", "field_value", "value_expr",
+  "\"CAST\"", "\"UNION\"", "\"ALL\"", "SWQT_VALUE_START",
+  "SWQT_SELECT_START", "\"NOT\"", "\"OR\"", "\"AND\"", "'='", "'<'", "'>'",
+  "'!'", "'+'", "'-'", "'*'", "'/'", "'%'", "SWQT_UMINUS",
+  "\"reserved keyword\"", "'('", "')'", "','", "'.'", "$accept", "input",
+  "value_expr", "value_expr_list", "field_value", "value_expr_non_logical",
   "type_def", "select_statement", "select_core", "opt_union_all",
   "union_all", "select_field_list", "column_spec", "as_clause",
   "opt_where", "opt_joins", "opt_order_by", "sort_spec_list", "sort_spec",
-  "string_or_identifier", "table_def", YY_NULL
+  "table_def", YY_NULL
 };
 #endif
 
@@ -527,15 +524,15 @@ static const yytype_uint16 yytoknum[] =
        0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
      265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
      275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,    43,    45,    42,    47,    37,   289,
-     290,    40,    41,    61,    60,    62,    33,    44,    46
+     285,   286,   287,    61,    60,    62,    33,    43,    45,    42,
+      47,    37,   288,   289,    40,    41,    44,    46
 };
 # endif
 
-#define YYPACT_NINF -170
+#define YYPACT_NINF -119
 
 #define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-170)))
+  (!!((Yystate) == (-119)))
 
 #define YYTABLE_NINF -1
 
@@ -546,26 +543,25 @@ static const yytype_uint16 yytoknum[] =
      STATE-NUM.  */
 static const yytype_int16 yypact[] =
 {
-      72,   243,   260,    -8,    16,  -170,  -170,  -170,   -10,  -170,
-      -1,   243,   260,   243,    56,  -170,   181,   260,   290,   217,
-      23,  -170,    18,  -170,   260,    36,   260,    56,  -170,   -25,
-     165,   243,   243,    22,   260,   260,    -5,    54,   260,   260,
-     260,   260,   260,    62,   126,   149,    31,    44,    -9,    99,
-    -170,   144,    39,    29,    43,    65,  -170,    -8,    53,   252,
-    -170,   105,  -170,  -170,    87,  -170,   260,   268,   279,  -170,
-     112,    84,   260,   260,    75,    75,  -170,  -170,  -170,   260,
-     260,   290,   260,   260,   290,   260,   290,   260,   226,    -2,
-    -170,    79,     4,  -170,  -170,   103,  -170,  -170,   111,   217,
-      18,  -170,  -170,  -170,   260,   127,   114,   260,   260,  -170,
-     260,   273,   285,   290,   290,   290,   290,   290,   290,   151,
-     116,  -170,  -170,  -170,   115,   153,   121,  -170,  -170,  -170,
-     125,   120,  -170,   290,   290,   122,   260,   260,   128,     4,
-     103,  -170,   161,   111,   152,    69,  -170,  -170,   290,   290,
-       4,  -170,   177,   111,   168,   243,   169,   -20,     1,  -170,
-    -170,   178,   151,    56,   167,  -170,  -170,   191,  -170,   194,
-     151,   155,   151,   162,   163,   170,   151,   123,  -170,   159,
-    -170,  -170,   151,   121,  -170,  -170,   151,   121,  -170,  -170,
-    -170
+      -9,   204,    -6,    10,  -119,  -119,  -119,   -30,  -119,   -32,
+     204,   240,   204,   342,  -119,   356,    54,    12,  -119,     4,
+    -119,   204,    35,   204,   380,  -119,   263,    18,   204,   240,
+      50,    87,   204,   204,    97,   112,   158,    33,   240,   240,
+     240,   240,   240,   -23,   194,  -119,   297,    36,    28,    31,
+      56,  -119,    -6,   256,    42,  -119,   335,  -119,   204,    82,
+      72,  -119,    70,    55,   204,   240,   247,   350,   204,   204,
+    -119,   204,   204,  -119,   204,  -119,   204,    80,    80,  -119,
+    -119,  -119,   148,     0,    94,  -119,   118,  -119,    47,   194,
+       4,  -119,  -119,   204,  -119,   120,    85,   204,   240,  -119,
+     204,   124,   284,  -119,  -119,  -119,  -119,  -119,  -119,   130,
+      95,  -119,    47,  -119,    96,    -5,    75,  -119,  -119,  -119,
+     100,   101,  -119,  -119,   356,   103,   204,   240,   108,   115,
+       2,    75,   151,   159,  -119,   153,    47,   150,    23,  -119,
+    -119,  -119,   356,     2,  -119,   150,     2,     2,    47,   154,
+     204,   152,    61,    83,  -119,   152,  -119,  -119,   157,   204,
+     342,   156,  -119,  -119,   173,  -119,   174,  -119,   204,   305,
+     130,   134,   135,   305,  -119,   116,  -119,   136,  -119,  -119,
+    -119,  -119,  -119,   130,  -119
 };
 
   /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
@@ -573,42 +569,39 @@ static const yytype_int16 yypact[] =
      means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
-       0,     0,     0,     0,     0,    32,    33,    34,    30,    37,
-       0,     0,     0,     0,     2,    35,     0,     0,     3,     0,
-       0,     4,    54,     1,     0,     0,     0,     7,    38,     0,
+       2,     0,     0,     0,    32,    33,    34,    30,    37,     0,
+       0,     0,     0,     3,    35,     5,     0,     0,     4,    55,
+       1,     0,     0,     0,     8,    38,     0,     0,     0,     0,
        0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,    30,     0,
-      64,    61,     0,    57,     0,     0,    51,     0,     0,    29,
-      31,     0,     8,    36,     6,     5,     0,    18,     0,    26,
-       0,     0,     0,     0,    39,    40,    41,    42,    43,     0,
-       0,     9,     0,     0,    12,     0,    13,     0,     0,     0,
-      60,    30,    59,    85,    84,     0,    63,    71,     0,     0,
-      54,    56,    55,    44,     0,     0,     0,     0,     0,    27,
+       0,     0,     0,    30,     0,    62,    60,     0,    58,     0,
+       0,    51,     0,    29,     0,    31,     0,    36,     0,    18,
+       0,    26,     0,     0,     0,     0,     7,     6,     0,     0,
+       9,     0,     0,    12,     0,    13,     0,    39,    40,    41,
+      42,    43,     0,     0,     0,    69,     0,    61,     0,     0,
+      55,    57,    56,     0,    44,     0,     0,     0,     0,    27,
        0,    19,     0,    15,    16,    14,    10,    17,    11,     0,
-       0,    65,    62,    70,    85,    86,    74,    58,    52,    28,
-      46,     0,    22,    20,    24,     0,     0,     0,     0,    66,
-       0,    87,     0,     0,    72,     0,    45,    23,    21,    25,
-      68,    67,    88,     0,     0,     0,    77,     0,     0,    69,
-      89,     0,     0,    73,     0,    53,    47,     0,    49,     0,
-       0,     0,     0,     0,     0,     0,     0,    81,    78,    80,
-      48,    50,     0,    74,    82,    83,     0,    74,    75,    79,
-      76
+       0,    63,     0,    68,     0,    82,    72,    59,    52,    28,
+      46,     0,    22,    20,    24,     0,     0,     0,    30,     0,
+      64,    72,     0,     0,    83,     0,     0,    70,     0,    45,
+      23,    21,    25,    66,    65,    70,    84,    86,     0,     0,
+       0,    75,     0,     0,    67,    75,    85,    87,     0,     0,
+      71,     0,    53,    47,     0,    49,     0,    54,     0,    72,
+       0,     0,     0,    72,    73,    79,    76,    78,    48,    50,
+      74,    80,    81,     0,    77
 };
 
   /* YYPGOTO[NTERM-NUM].  */
 static const yytype_int16 yypgoto[] =
 {
-    -170,  -170,   -11,   -63,   -48,    11,  -170,   157,   213,   134,
-    -170,   136,  -170,   -81,  -170,  -169,  -170,    50,  -170,   -83,
-    -124
+    -119,  -119,    -1,   -56,  -106,     7,  -119,   129,   167,    99,
+    -119,   -39,  -119,   -61,    40,  -118,    38,    11,  -119,  -108
 };
 
   /* YYDEFGOTO[NTERM-NUM].  */
 static const yytype_int16 yydefgoto[] =
 {
-      -1,     4,    14,    58,    15,    16,   131,    21,    22,    56,
-      57,    52,    53,    96,   156,   144,   165,   178,   179,    97,
-     126
+      -1,     3,    53,    54,    14,    15,   121,    18,    19,    51,
+      52,    47,    48,    87,   151,   137,   162,   176,   177,   116
 };
 
   /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
@@ -616,130 +609,147 @@ static const yytype_int16 yydefgoto[] =
      number is the opposite.  If YYTABLE_NINF, syntax error.  */
 static const yytype_uint8 yytable[] =
 {
-      27,    92,    29,   106,    60,    19,    69,    31,    32,    93,
-      94,   122,   123,    18,   188,   125,    23,    62,   190,   154,
-      64,    65,   166,    28,    30,    95,    70,   167,    47,   161,
-      51,    24,    88,    20,   121,    59,    19,    61,    25,    89,
-      26,   129,    60,   168,    55,    67,    68,   135,   169,    74,
-      75,    76,    77,    78,    81,    84,    86,   152,   151,    98,
-     125,    71,    72,    66,    73,     5,     6,     7,     8,   159,
-     125,   138,   157,     9,    87,   158,    99,    59,    38,    39,
-      40,    41,    42,   111,   112,   100,    63,    10,    31,    32,
-     113,   114,   101,   115,   116,   103,   117,    12,   118,    59,
-       1,     2,     3,    17,    90,    91,    79,    80,    93,    94,
-      51,    40,    41,    42,   171,    59,   124,    94,   133,   134,
-      32,    59,   175,   109,   177,   110,   105,    25,   183,     5,
-       6,     7,     8,   130,   187,   142,   143,     9,   177,    38,
-      39,    40,    41,    42,   163,   184,   185,   148,   149,    93,
-      94,    10,     5,     6,     7,     8,   132,    91,   139,   141,
-       9,    12,   146,   140,   147,    95,   145,    17,   155,    82,
-     150,    83,    33,    34,    10,    35,   153,    36,    38,    39,
-      40,    41,    42,   160,    12,   162,   172,   164,    33,    34,
-      17,    35,    85,    36,   173,   170,    37,   174,   176,    38,
-      39,    40,    41,    42,   180,   181,   186,    63,    43,    44,
-      45,    46,    37,   182,   102,    38,    39,    40,    41,    42,
-       5,     6,     7,    48,    43,    44,    45,    46,     9,     5,
-       6,     7,     8,    54,   128,   127,   189,     9,     0,     0,
-       0,    49,    10,     0,     0,     0,     5,     6,     7,     8,
-     119,    10,    12,    50,     9,     0,     0,     0,    17,     0,
-       0,    12,   120,     5,     6,     7,     8,    17,    10,     0,
-       0,     9,     0,     0,    11,     0,     0,   107,    12,     0,
-       0,     0,   136,     0,    13,    10,    38,    39,    40,    41,
-      42,     0,     0,     0,     0,    12,     0,     0,     0,   104,
-       0,    17,    38,    39,    40,    41,    42,    38,    39,    40,
-      41,    42,   108,    38,    39,    40,    41,    42,   137,    38,
-      39,    40,    41,    42,    38,    39,    40,    41,    42
+      13,    85,    96,   129,   131,    84,    55,    16,    85,    24,
+      20,    26,    23,   145,    21,    46,    86,    22,    25,     1,
+       2,    82,    56,    86,    83,    16,   152,    59,   149,   153,
+      50,    66,    67,    70,    73,    75,    60,   119,    17,   111,
+     158,    55,   133,    46,   125,    77,    78,    79,    80,    81,
+     117,   174,   114,   115,   134,   180,    88,     4,     5,     6,
+      43,    61,    58,   101,   175,     8,    76,   103,   104,   144,
+     105,   106,   102,   107,    89,   108,    90,   175,    44,     9,
+      62,    99,   154,    91,    10,   156,   157,    94,    46,   135,
+     136,    97,    11,    45,    63,    64,   123,    65,    12,   100,
+       4,     5,     6,     7,    98,   124,   163,   164,     8,    38,
+      39,    40,    41,    42,   112,     4,     5,     6,     7,    40,
+      41,    42,     9,     8,   113,   141,   120,    10,   165,   166,
+     122,    68,    69,   126,   142,    11,   128,     9,   181,   182,
+     130,    12,    10,   132,   138,    71,   139,    72,   140,   160,
+      11,     4,     5,     6,     7,    22,    12,   146,   169,     8,
+     143,     4,     5,     6,     7,   147,   150,   173,   148,     8,
+     161,   159,   109,     9,   168,   170,   171,   172,    10,   178,
+     179,    92,   183,     9,    49,   155,    11,   110,    10,   118,
+       0,    74,    12,   167,   184,     0,    11,     4,     5,     6,
+      43,     0,    12,     0,     0,     8,     0,     4,     5,     6,
+       7,     0,     0,     0,     0,     8,     0,     0,     0,     9,
+       0,     0,     0,     0,    10,     0,     0,     0,     0,     9,
+       0,     0,    11,    45,    10,     0,     0,     0,    12,     0,
+       0,     0,    11,     4,     5,     6,     7,     0,    12,     0,
+       0,     8,     0,     0,    27,    28,     0,    29,     0,    30,
+       0,     0,     0,    27,    28,     9,    29,     0,    30,     0,
+      27,    28,     0,    29,     0,    30,     0,    31,    11,    33,
+      34,    35,    36,    37,    12,     0,    31,    32,    33,    34,
+      35,    36,    37,    31,    32,    33,    34,    35,    36,    37,
+       0,     0,    93,    85,    27,    28,     0,    29,    57,    30,
+       0,     0,    27,    28,     0,    29,   127,    30,    86,   135,
+     136,    38,    39,    40,    41,    42,     0,    31,    32,    33,
+      34,    35,    36,    37,     0,    31,    32,    33,    34,    35,
+      36,    37,    27,    28,     0,    29,     0,    30,     0,    27,
+      28,     0,    29,     0,    30,     0,    95,    27,    28,     0,
+      29,     0,    30,     0,     0,    31,    32,    33,    34,    35,
+      36,    37,    31,    32,    33,    34,    35,    36,    37,     0,
+      31,     0,     0,    34,    35,    36,    37,    27,    28,     0,
+      29,     0,    30,    38,    39,    40,    41,    42,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    34,    35,    36,    37
 };
 
 static const yytype_int16 yycheck[] =
 {
-      11,    49,    13,    66,     6,    13,    11,    32,    33,     5,
-       6,    92,    95,     2,   183,    98,     0,    42,   187,   143,
-      31,    32,    42,    12,    13,    21,    31,    47,    17,   153,
-      19,    41,    41,    41,    36,    24,    13,    26,    48,    48,
-      41,   104,     6,    42,    26,    34,    35,   110,    47,    38,
-      39,    40,    41,    42,    43,    44,    45,   140,   139,    20,
-     143,     7,     8,    41,    10,     3,     4,     5,     6,   150,
-     153,   119,     3,    11,    43,     6,    47,    66,    34,    35,
-      36,    37,    38,    72,    73,    42,    42,    25,    32,    33,
-      79,    80,    27,    82,    83,    42,    85,    35,    87,    88,
-      28,    29,    30,    41,     5,     6,    44,    45,     5,     6,
-      99,    36,    37,    38,   162,   104,     5,     6,   107,   108,
-      33,   110,   170,    11,   172,    41,    21,    48,   176,     3,
-       4,     5,     6,     6,   182,    14,    15,    11,   186,    34,
-      35,    36,    37,    38,   155,    22,    23,   136,   137,     5,
-       6,    25,     3,     4,     5,     6,    42,     6,    42,     6,
-      11,    35,    42,    48,    42,    21,    41,    41,    16,    43,
-      42,    45,     7,     8,    25,    10,    15,    12,    34,    35,
-      36,    37,    38,     6,    35,    17,    19,    18,     7,     8,
-      41,    10,    43,    12,     3,    17,    31,     3,    43,    34,
-      35,    36,    37,    38,    42,    42,    47,    42,    43,    44,
-      45,    46,    31,    43,    57,    34,    35,    36,    37,    38,
-       3,     4,     5,     6,    43,    44,    45,    46,    11,     3,
-       4,     5,     6,    20,   100,    99,   186,    11,    -1,    -1,
-      -1,    24,    25,    -1,    -1,    -1,     3,     4,     5,     6,
-      24,    25,    35,    36,    11,    -1,    -1,    -1,    41,    -1,
-      -1,    35,    36,     3,     4,     5,     6,    41,    25,    -1,
-      -1,    11,    -1,    -1,    31,    -1,    -1,     9,    35,    -1,
-      -1,    -1,     9,    -1,    41,    25,    34,    35,    36,    37,
-      38,    -1,    -1,    -1,    -1,    35,    -1,    -1,    -1,    47,
-      -1,    41,    34,    35,    36,    37,    38,    34,    35,    36,
-      37,    38,    33,    34,    35,    36,    37,    38,    33,    34,
-      35,    36,    37,    38,    34,    35,    36,    37,    38
+       1,     6,    58,   109,   112,    44,     6,    13,     6,    10,
+       0,    12,    44,   131,    44,    16,    21,    47,    11,    28,
+      29,    44,    23,    21,    47,    13,     3,    28,   136,     6,
+      26,    32,    33,    34,    35,    36,    29,    93,    44,    39,
+     148,     6,    47,    44,   100,    38,    39,    40,    41,    42,
+      89,   169,     5,     6,   115,   173,    20,     3,     4,     5,
+       6,    11,    44,    64,   170,    11,    33,    68,    69,   130,
+      71,    72,    65,    74,    46,    76,    45,   183,    24,    25,
+      30,    11,   143,    27,    30,   146,   147,    45,    89,    14,
+      15,     9,    38,    39,     7,     8,    97,    10,    44,    44,
+       3,     4,     5,     6,    32,    98,    45,    46,    11,    37,
+      38,    39,    40,    41,    20,     3,     4,     5,     6,    39,
+      40,    41,    25,    11,     6,   126,     6,    30,    45,    46,
+      45,    34,    35,     9,   127,    38,     6,    25,    22,    23,
+      45,    44,    30,    47,    44,    33,    45,    35,    45,   150,
+      38,     3,     4,     5,     6,    47,    44,     6,   159,    11,
+      45,     3,     4,     5,     6,     6,    16,   168,    15,    11,
+      18,    17,    24,    25,    17,    19,     3,     3,    30,    45,
+      45,    52,    46,    25,    17,   145,    38,    39,    30,    90,
+      -1,    33,    44,   155,   183,    -1,    38,     3,     4,     5,
+       6,    -1,    44,    -1,    -1,    11,    -1,     3,     4,     5,
+       6,    -1,    -1,    -1,    -1,    11,    -1,    -1,    -1,    25,
+      -1,    -1,    -1,    -1,    30,    -1,    -1,    -1,    -1,    25,
+      -1,    -1,    38,    39,    30,    -1,    -1,    -1,    44,    -1,
+      -1,    -1,    38,     3,     4,     5,     6,    -1,    44,    -1,
+      -1,    11,    -1,    -1,     7,     8,    -1,    10,    -1,    12,
+      -1,    -1,    -1,     7,     8,    25,    10,    -1,    12,    -1,
+       7,     8,    -1,    10,    -1,    12,    -1,    30,    38,    32,
+      33,    34,    35,    36,    44,    -1,    30,    31,    32,    33,
+      34,    35,    36,    30,    31,    32,    33,    34,    35,    36,
+      -1,    -1,    46,     6,     7,     8,    -1,    10,    45,    12,
+      -1,    -1,     7,     8,    -1,    10,    32,    12,    21,    14,
+      15,    37,    38,    39,    40,    41,    -1,    30,    31,    32,
+      33,    34,    35,    36,    -1,    30,    31,    32,    33,    34,
+      35,    36,     7,     8,    -1,    10,    -1,    12,    -1,     7,
+       8,    -1,    10,    -1,    12,    -1,    21,     7,     8,    -1,
+      10,    -1,    12,    -1,    -1,    30,    31,    32,    33,    34,
+      35,    36,    30,    31,    32,    33,    34,    35,    36,    -1,
+      30,    -1,    -1,    33,    34,    35,    36,     7,     8,    -1,
+      10,    -1,    12,    37,    38,    39,    40,    41,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    33,    34,    35,    36
 };
 
   /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
      symbol of state STATE-NUM.  */
 static const yytype_uint8 yystos[] =
 {
-       0,    28,    29,    30,    50,     3,     4,     5,     6,    11,
-      25,    31,    35,    41,    51,    53,    54,    41,    54,    13,
-      41,    56,    57,     0,    41,    48,    41,    51,    54,    51,
-      54,    32,    33,     7,     8,    10,    12,    31,    34,    35,
-      36,    37,    38,    43,    44,    45,    46,    54,     6,    24,
-      36,    54,    60,    61,    57,    26,    58,    59,    52,    54,
-       6,    54,    42,    42,    51,    51,    41,    54,    54,    11,
-      31,     7,     8,    10,    54,    54,    54,    54,    54,    44,
-      45,    54,    43,    45,    54,    43,    54,    43,    41,    48,
-       5,     6,    53,     5,     6,    21,    62,    68,    20,    47,
-      42,    27,    56,    42,    47,    21,    52,     9,    33,    11,
-      41,    54,    54,    54,    54,    54,    54,    54,    54,    24,
-      36,    36,    62,    68,     5,    68,    69,    60,    58,    52,
-       6,    55,    42,    54,    54,    52,     9,    33,    53,    42,
-      48,     6,    14,    15,    64,    41,    42,    42,    54,    54,
-      42,    62,    68,    15,    69,    16,    63,     3,     6,    62,
-       6,    69,    17,    51,    18,    65,    42,    47,    42,    47,
-      17,    53,    19,     3,     3,    53,    43,    53,    66,    67,
-      42,    42,    43,    53,    22,    23,    47,    53,    64,    66,
-      64
+       0,    28,    29,    49,     3,     4,     5,     6,    11,    25,
+      30,    38,    44,    50,    52,    53,    13,    44,    55,    56,
+       0,    44,    47,    44,    50,    53,    50,     7,     8,    10,
+      12,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,     6,    24,    39,    50,    59,    60,    56,
+      26,    57,    58,    50,    51,     6,    50,    45,    44,    50,
+      53,    11,    30,     7,     8,    10,    50,    50,    34,    35,
+      50,    33,    35,    50,    33,    50,    33,    53,    53,    53,
+      53,    53,    44,    47,    59,     6,    21,    61,    20,    46,
+      45,    27,    55,    46,    45,    21,    51,     9,    32,    11,
+      44,    50,    53,    50,    50,    50,    50,    50,    50,    24,
+      39,    39,    20,     6,     5,     6,    67,    59,    57,    51,
+       6,    54,    45,    50,    53,    51,     9,    32,     6,    52,
+      45,    67,    47,    47,    61,    14,    15,    63,    44,    45,
+      45,    50,    53,    45,    61,    63,     6,     6,    15,    67,
+      16,    62,     3,     6,    61,    62,    61,    61,    67,    17,
+      50,    18,    64,    45,    46,    45,    46,    64,    17,    50,
+      19,     3,     3,    50,    63,    52,    65,    66,    45,    45,
+      63,    22,    23,    46,    65
 };
 
   /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
 static const yytype_uint8 yyr1[] =
 {
-       0,    49,    50,    50,    50,    51,    51,    51,    51,    51,
-      51,    51,    51,    51,    51,    51,    51,    51,    51,    51,
-      51,    51,    51,    51,    51,    51,    51,    51,    52,    52,
-      53,    53,    54,    54,    54,    54,    54,    54,    54,    54,
-      54,    54,    54,    54,    54,    54,    55,    55,    55,    55,
-      55,    56,    56,    57,    58,    58,    59,    60,    60,    61,
-      61,    61,    61,    61,    61,    61,    61,    61,    61,    61,
-      62,    62,    63,    63,    64,    64,    64,    65,    65,    66,
-      66,    67,    67,    67,    68,    68,    69,    69,    69,    69
+       0,    48,    49,    49,    49,    50,    50,    50,    50,    50,
+      50,    50,    50,    50,    50,    50,    50,    50,    50,    50,
+      50,    50,    50,    50,    50,    50,    50,    50,    51,    51,
+      52,    52,    53,    53,    53,    53,    53,    53,    53,    53,
+      53,    53,    53,    53,    53,    53,    54,    54,    54,    54,
+      54,    55,    55,    56,    56,    57,    57,    58,    59,    59,
+      60,    60,    60,    60,    60,    60,    60,    60,    61,    61,
+      62,    62,    63,    63,    63,    64,    64,    65,    65,    66,
+      66,    66,    67,    67,    67,    67,    67,    67
 };
 
   /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
 static const yytype_uint8 yyr2[] =
 {
-       0,     2,     2,     2,     2,     3,     3,     2,     3,     3,
+       0,     2,     0,     2,     2,     1,     3,     3,     2,     3,
        4,     4,     3,     3,     4,     4,     4,     4,     3,     4,
        5,     6,     5,     6,     5,     6,     3,     4,     3,     1,
        1,     3,     1,     1,     1,     1,     3,     1,     2,     3,
        3,     3,     3,     3,     4,     6,     1,     4,     6,     4,
-       6,     2,     4,     7,     0,     2,     2,     1,     3,     2,
-       2,     1,     3,     2,     1,     3,     4,     5,     5,     6,
-       2,     1,     0,     2,     0,     7,     8,     0,     3,     3,
-       1,     1,     2,     2,     1,     1,     1,     2,     3,     4
+       6,     2,     4,     7,     8,     0,     2,     2,     1,     3,
+       1,     2,     1,     3,     4,     5,     5,     6,     2,     1,
+       0,     2,     0,     5,     6,     0,     3,     3,     1,     1,
+       2,     2,     1,     2,     3,     4,     3,     4
 };
 
 
@@ -1165,69 +1175,63 @@ yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, swq_parse_context
   switch (yytype)
     {
           case 3: /* "integer number"  */
-#line 105 "swq_parser.y" /* yacc.c:1257  */
+#line 107 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1170 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1181 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
     case 4: /* "floating point number"  */
-#line 105 "swq_parser.y" /* yacc.c:1257  */
+#line 107 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1176 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1187 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
     case 5: /* "string"  */
-#line 105 "swq_parser.y" /* yacc.c:1257  */
+#line 107 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1182 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1193 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
     case 6: /* "identifier"  */
-#line 105 "swq_parser.y" /* yacc.c:1257  */
+#line 107 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1188 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1199 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 51: /* logical_expr  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 50: /* value_expr  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1194 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1205 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 52: /* value_expr_list  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 51: /* value_expr_list  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1200 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1211 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 53: /* field_value  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 52: /* field_value  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1206 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1217 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 54: /* value_expr  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 53: /* value_expr_non_logical  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1212 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1223 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 55: /* type_def  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 54: /* type_def  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1218 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1229 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
-    case 68: /* string_or_identifier  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
+    case 67: /* table_def  */
+#line 108 "swq_parser.y" /* yacc.c:1257  */
       { delete ((*yyvaluep)); }
-#line 1224 "swq_parser.cpp" /* yacc.c:1257  */
-        break;
-
-    case 69: /* table_def  */
-#line 106 "swq_parser.y" /* yacc.c:1257  */
-      { delete ((*yyvaluep)); }
-#line 1230 "swq_parser.cpp" /* yacc.c:1257  */
+#line 1235 "swq_parser.cpp" /* yacc.c:1257  */
         break;
 
 
@@ -1492,182 +1496,174 @@ yyreduce:
   YY_REDUCE_PRINT (yyn);
   switch (yyn)
     {
-        case 2:
-#line 112 "swq_parser.y" /* yacc.c:1646  */
+        case 3:
+#line 114 "swq_parser.y" /* yacc.c:1646  */
     {
             context->poRoot = (yyvsp[0]);
         }
-#line 1500 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1505 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 3:
-#line 117 "swq_parser.y" /* yacc.c:1646  */
+  case 4:
+#line 119 "swq_parser.y" /* yacc.c:1646  */
     {
             context->poRoot = (yyvsp[0]);
         }
-#line 1508 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1513 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 4:
-#line 122 "swq_parser.y" /* yacc.c:1646  */
+  case 5:
+#line 125 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poRoot = (yyvsp[0]);
+            (yyval) = (yyvsp[0]);
         }
-#line 1516 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1521 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 5:
-#line 128 "swq_parser.y" /* yacc.c:1646  */
+  case 6:
+#line 130 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_AND );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1527 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1532 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 6:
-#line 136 "swq_parser.y" /* yacc.c:1646  */
+  case 7:
+#line 138 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_OR );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1538 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1543 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 7:
-#line 144 "swq_parser.y" /* yacc.c:1646  */
+  case 8:
+#line 146 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_NOT );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1548 "swq_parser.cpp" /* yacc.c:1646  */
-    break;
-
-  case 8:
-#line 151 "swq_parser.y" /* yacc.c:1646  */
-    {
-            (yyval) = (yyvsp[-1]);
-        }
-#line 1556 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1553 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 9:
-#line 156 "swq_parser.y" /* yacc.c:1646  */
+#line 153 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_EQ );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1567 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1564 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 10:
-#line 164 "swq_parser.y" /* yacc.c:1646  */
+#line 161 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_NE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1578 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1575 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 11:
-#line 172 "swq_parser.y" /* yacc.c:1646  */
+#line 169 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_NE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1589 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1586 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 12:
-#line 180 "swq_parser.y" /* yacc.c:1646  */
+#line 177 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LT );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1600 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1597 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 13:
-#line 188 "swq_parser.y" /* yacc.c:1646  */
+#line 185 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_GT );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1611 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1608 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 14:
-#line 196 "swq_parser.y" /* yacc.c:1646  */
+#line 193 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1622 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1619 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 15:
-#line 204 "swq_parser.y" /* yacc.c:1646  */
+#line 201 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1633 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1630 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 16:
-#line 212 "swq_parser.y" /* yacc.c:1646  */
+#line 209 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1644 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1641 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 17:
-#line 220 "swq_parser.y" /* yacc.c:1646  */
+#line 217 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_GE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1655 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1652 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 18:
-#line 228 "swq_parser.y" /* yacc.c:1646  */
+#line 225 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LIKE );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1666 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1663 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 19:
-#line 236 "swq_parser.y" /* yacc.c:1646  */
+#line 233 "swq_parser.y" /* yacc.c:1646  */
     {
             swq_expr_node *like;
             like = new swq_expr_node( SWQ_LIKE );
@@ -1679,11 +1675,11 @@ yyreduce:
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( like );
         }
-#line 1682 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1679 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 20:
-#line 249 "swq_parser.y" /* yacc.c:1646  */
+#line 246 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_LIKE );
             (yyval)->field_type = SWQ_BOOLEAN;
@@ -1691,11 +1687,11 @@ yyreduce:
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1694 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1691 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 21:
-#line 258 "swq_parser.y" /* yacc.c:1646  */
+#line 255 "swq_parser.y" /* yacc.c:1646  */
     {
             swq_expr_node *like;
             like = new swq_expr_node( SWQ_LIKE );
@@ -1708,11 +1704,11 @@ yyreduce:
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( like );
         }
-#line 1711 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1708 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 22:
-#line 272 "swq_parser.y" /* yacc.c:1646  */
+#line 269 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[-1]);
             (yyval)->field_type = SWQ_BOOLEAN;
@@ -1720,11 +1716,11 @@ yyreduce:
             (yyval)->PushSubExpression( (yyvsp[-4]) );
             (yyval)->ReverseSubExpressions();
         }
-#line 1723 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1720 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 23:
-#line 281 "swq_parser.y" /* yacc.c:1646  */
+#line 278 "swq_parser.y" /* yacc.c:1646  */
     {
             swq_expr_node *in;
 
@@ -1738,11 +1734,11 @@ yyreduce:
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( in );
         }
-#line 1741 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1738 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 24:
-#line 296 "swq_parser.y" /* yacc.c:1646  */
+#line 293 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_BETWEEN );
             (yyval)->field_type = SWQ_BOOLEAN;
@@ -1750,11 +1746,11 @@ yyreduce:
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1753 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1750 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 25:
-#line 305 "swq_parser.y" /* yacc.c:1646  */
+#line 302 "swq_parser.y" /* yacc.c:1646  */
     {
             swq_expr_node *between;
             between = new swq_expr_node( SWQ_BETWEEN );
@@ -1767,21 +1763,21 @@ yyreduce:
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( between );
         }
-#line 1770 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1767 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 26:
-#line 319 "swq_parser.y" /* yacc.c:1646  */
+#line 316 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_ISNULL );
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( (yyvsp[-2]) );
         }
-#line 1780 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1777 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 27:
-#line 326 "swq_parser.y" /* yacc.c:1646  */
+#line 323 "swq_parser.y" /* yacc.c:1646  */
     {
         swq_expr_node *isnull;
 
@@ -1793,105 +1789,101 @@ yyreduce:
             (yyval)->field_type = SWQ_BOOLEAN;
             (yyval)->PushSubExpression( isnull );
         }
-#line 1796 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1793 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 28:
-#line 340 "swq_parser.y" /* yacc.c:1646  */
+#line 337 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);
             (yyvsp[0])->PushSubExpression( (yyvsp[-2]) );
         }
-#line 1805 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1802 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 29:
-#line 346 "swq_parser.y" /* yacc.c:1646  */
+#line 343 "swq_parser.y" /* yacc.c:1646  */
     {
-            (yyval) = new swq_expr_node( SWQ_UNKNOWN ); /* list */
+            (yyval) = new swq_expr_node( SWQ_ARGUMENT_LIST ); /* temporary value */
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1814 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1811 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 30:
-#line 353 "swq_parser.y" /* yacc.c:1646  */
+#line 350 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);  // validation deferred.
             (yyval)->eNodeType = SNT_COLUMN;
             (yyval)->field_index = (yyval)->table_index = -1;
         }
-#line 1824 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1821 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 31:
-#line 360 "swq_parser.y" /* yacc.c:1646  */
+#line 357 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[-2]);  // validation deferred.
             (yyval)->eNodeType = SNT_COLUMN;
             (yyval)->field_index = (yyval)->table_index = -1;
-            (yyval)->string_value = (char *) 
-                            CPLRealloc( (yyval)->string_value, 
-                                        strlen((yyval)->string_value) 
-                                        + strlen((yyvsp[0])->string_value) + 2 );
-            strcat( (yyval)->string_value, "." );
-            strcat( (yyval)->string_value, (yyvsp[0])->string_value );
+            (yyval)->table_name = (yyval)->string_value;
+            (yyval)->string_value = CPLStrdup((yyvsp[0])->string_value);
             delete (yyvsp[0]);
             (yyvsp[0]) = NULL;
         }
-#line 1842 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1835 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 32:
-#line 376 "swq_parser.y" /* yacc.c:1646  */
+#line 369 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);
         }
-#line 1850 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1843 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 33:
-#line 381 "swq_parser.y" /* yacc.c:1646  */
+#line 374 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);
         }
-#line 1858 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1851 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 34:
-#line 386 "swq_parser.y" /* yacc.c:1646  */
+#line 379 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);
         }
-#line 1866 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1859 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 35:
-#line 390 "swq_parser.y" /* yacc.c:1646  */
+#line 383 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[0]);
         }
-#line 1874 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1867 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 36:
-#line 395 "swq_parser.y" /* yacc.c:1646  */
+#line 388 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[-1]);
         }
-#line 1882 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1875 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 37:
-#line 400 "swq_parser.y" /* yacc.c:1646  */
+#line 393 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node((const char*)NULL);
         }
-#line 1890 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1883 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 38:
-#line 405 "swq_parser.y" /* yacc.c:1646  */
+#line 398 "swq_parser.y" /* yacc.c:1646  */
     {
             if ((yyvsp[0])->eNodeType == SNT_CONSTANT)
             {
@@ -1906,128 +1898,140 @@ yyreduce:
                 (yyval)->PushSubExpression( (yyvsp[0]) );
             }
         }
-#line 1909 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1902 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 39:
-#line 421 "swq_parser.y" /* yacc.c:1646  */
+#line 414 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_ADD );
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1919 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1912 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 40:
-#line 428 "swq_parser.y" /* yacc.c:1646  */
+#line 421 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_SUBTRACT );
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1929 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1922 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 41:
-#line 435 "swq_parser.y" /* yacc.c:1646  */
+#line 428 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_MULTIPLY );
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1939 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1932 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 42:
-#line 442 "swq_parser.y" /* yacc.c:1646  */
+#line 435 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_DIVIDE );
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1949 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1942 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 43:
-#line 449 "swq_parser.y" /* yacc.c:1646  */
+#line 442 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = new swq_expr_node( SWQ_MODULUS );
             (yyval)->PushSubExpression( (yyvsp[-2]) );
             (yyval)->PushSubExpression( (yyvsp[0]) );
         }
-#line 1959 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1952 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 44:
-#line 456 "swq_parser.y" /* yacc.c:1646  */
+#line 449 "swq_parser.y" /* yacc.c:1646  */
     {
             const swq_operation *poOp = 
                     swq_op_registrar::GetOperator( (yyvsp[-3])->string_value );
 
             if( poOp == NULL )
             {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                                "Undefined function '%s' used.",
-                                (yyvsp[-3])->string_value );
-                delete (yyvsp[-3]);
-                delete (yyvsp[-1]);
-                YYERROR;
+                if( context->bAcceptCustomFuncs )
+                {
+                    (yyval) = (yyvsp[-1]);
+                    (yyval)->eNodeType = SNT_OPERATION;
+                    (yyval)->nOperation = SWQ_CUSTOM_FUNC;
+                    (yyval)->string_value = CPLStrdup((yyvsp[-3])->string_value);
+                    (yyval)->ReverseSubExpressions();
+                    delete (yyvsp[-3]);
+                }
+                else
+                {
+                    CPLError( CE_Failure, CPLE_AppDefined, 
+                                    "Undefined function '%s' used.",
+                                    (yyvsp[-3])->string_value );
+                    delete (yyvsp[-3]);
+                    delete (yyvsp[-1]);
+                    YYERROR;
+                }
             }
             else
             {
                 (yyval) = (yyvsp[-1]);
-                            (yyval)->eNodeType = SNT_OPERATION;
-                            (yyval)->nOperation = poOp->eOperation;
+                (yyval)->eNodeType = SNT_OPERATION;
+                (yyval)->nOperation = poOp->eOperation;
                 (yyval)->ReverseSubExpressions();
                 delete (yyvsp[-3]);
             }
         }
-#line 1986 "swq_parser.cpp" /* yacc.c:1646  */
+#line 1991 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 45:
-#line 480 "swq_parser.y" /* yacc.c:1646  */
+#line 485 "swq_parser.y" /* yacc.c:1646  */
     {
             (yyval) = (yyvsp[-1]);
             (yyval)->PushSubExpression( (yyvsp[-3]) );
             (yyval)->ReverseSubExpressions();
         }
-#line 1996 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2001 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 46:
-#line 488 "swq_parser.y" /* yacc.c:1646  */
+#line 493 "swq_parser.y" /* yacc.c:1646  */
     {
         (yyval) = new swq_expr_node( SWQ_CAST );
         (yyval)->PushSubExpression( (yyvsp[0]) );
     }
-#line 2005 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2010 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 47:
-#line 494 "swq_parser.y" /* yacc.c:1646  */
+#line 499 "swq_parser.y" /* yacc.c:1646  */
     {
         (yyval) = new swq_expr_node( SWQ_CAST );
         (yyval)->PushSubExpression( (yyvsp[-1]) );
         (yyval)->PushSubExpression( (yyvsp[-3]) );
     }
-#line 2015 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2020 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 48:
-#line 501 "swq_parser.y" /* yacc.c:1646  */
+#line 506 "swq_parser.y" /* yacc.c:1646  */
     {
         (yyval) = new swq_expr_node( SWQ_CAST );
         (yyval)->PushSubExpression( (yyvsp[-1]) );
         (yyval)->PushSubExpression( (yyvsp[-3]) );
         (yyval)->PushSubExpression( (yyvsp[-5]) );
     }
-#line 2026 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2031 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 49:
-#line 510 "swq_parser.y" /* yacc.c:1646  */
+#line 515 "swq_parser.y" /* yacc.c:1646  */
     {
         OGRwkbGeometryType eType = OGRFromOGCGeomType((yyvsp[-1])->string_value);
         if( !EQUAL((yyvsp[-3])->string_value,"GEOMETRY") || 
@@ -2043,11 +2047,11 @@ yyreduce:
         (yyval)->PushSubExpression( (yyvsp[-1]) );
         (yyval)->PushSubExpression( (yyvsp[-3]) );
     }
-#line 2046 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2051 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 50:
-#line 528 "swq_parser.y" /* yacc.c:1646  */
+#line 533 "swq_parser.y" /* yacc.c:1646  */
     {
         OGRwkbGeometryType eType = OGRFromOGCGeomType((yyvsp[-3])->string_value);
         if( !EQUAL((yyvsp[-5])->string_value,"GEOMETRY") || 
@@ -2065,53 +2069,38 @@ yyreduce:
         (yyval)->PushSubExpression( (yyvsp[-3]) );
         (yyval)->PushSubExpression( (yyvsp[-5]) );
     }
-#line 2068 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2073 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 53:
-#line 552 "swq_parser.y" /* yacc.c:1646  */
+#line 557 "swq_parser.y" /* yacc.c:1646  */
     {
         delete (yyvsp[-3]);
     }
-#line 2076 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2081 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 56:
-#line 560 "swq_parser.y" /* yacc.c:1646  */
+  case 54:
+#line 562 "swq_parser.y" /* yacc.c:1646  */
     {
-        swq_select* poNewSelect = new swq_select();
-        context->poCurSelect->PushUnionAll(poNewSelect);
-        context->poCurSelect = poNewSelect;
+        context->poCurSelect->query_mode = SWQM_DISTINCT_LIST;
+        delete (yyvsp[-3]);
     }
-#line 2086 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2090 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 59:
-#line 572 "swq_parser.y" /* yacc.c:1646  */
+  case 57:
+#line 571 "swq_parser.y" /* yacc.c:1646  */
     {
-            if( !context->poCurSelect->PushField( (yyvsp[0]), NULL, TRUE ) )
-            {
-                delete (yyvsp[0]);
-                YYERROR;
-            }
-        }
-#line 2098 "swq_parser.cpp" /* yacc.c:1646  */
+        swq_select* poNewSelect = new swq_select();
+        context->poCurSelect->PushUnionAll(poNewSelect);
+        context->poCurSelect = poNewSelect;
+    }
+#line 2100 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
   case 60:
-#line 581 "swq_parser.y" /* yacc.c:1646  */
-    {
-            if( !context->poCurSelect->PushField( (yyvsp[0]), NULL, TRUE ) )
-            {
-                delete (yyvsp[0]);
-                YYERROR;
-            }
-        }
-#line 2110 "swq_parser.cpp" /* yacc.c:1646  */
-    break;
-
-  case 61:
-#line 590 "swq_parser.y" /* yacc.c:1646  */
+#line 583 "swq_parser.y" /* yacc.c:1646  */
     {
             if( !context->poCurSelect->PushField( (yyvsp[0]) ) )
             {
@@ -2119,26 +2108,11 @@ yyreduce:
                 YYERROR;
             }
         }
-#line 2122 "swq_parser.cpp" /* yacc.c:1646  */
-    break;
-
-  case 62:
-#line 599 "swq_parser.y" /* yacc.c:1646  */
-    {
-            if( !context->poCurSelect->PushField( (yyvsp[-1]), (yyvsp[0])->string_value, TRUE ))
-            {
-                delete (yyvsp[-1]);
-                delete (yyvsp[0]);
-                YYERROR;
-            }
-
-            delete (yyvsp[0]);
-        }
-#line 2137 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2112 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 63:
-#line 611 "swq_parser.y" /* yacc.c:1646  */
+  case 61:
+#line 592 "swq_parser.y" /* yacc.c:1646  */
     {
             if( !context->poCurSelect->PushField( (yyvsp[-1]), (yyvsp[0])->string_value ) )
             {
@@ -2148,11 +2122,11 @@ yyreduce:
             }
             delete (yyvsp[0]);
         }
-#line 2151 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2126 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 64:
-#line 622 "swq_parser.y" /* yacc.c:1646  */
+  case 62:
+#line 603 "swq_parser.y" /* yacc.c:1646  */
     {
             swq_expr_node *poNode = new swq_expr_node();
             poNode->eNodeType = SNT_COLUMN;
@@ -2165,23 +2139,23 @@ yyreduce:
                 YYERROR;
             }
         }
-#line 2168 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2143 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 65:
-#line 636 "swq_parser.y" /* yacc.c:1646  */
+  case 63:
+#line 617 "swq_parser.y" /* yacc.c:1646  */
     {
-            CPLString osQualifiedField;
+            CPLString osTableName;
 
-            osQualifiedField = (yyvsp[-2])->string_value;
-            osQualifiedField += ".*";
+            osTableName = (yyvsp[-2])->string_value;
 
             delete (yyvsp[-2]);
             (yyvsp[-2]) = NULL;
 
             swq_expr_node *poNode = new swq_expr_node();
             poNode->eNodeType = SNT_COLUMN;
-            poNode->string_value = CPLStrdup( osQualifiedField );
+            poNode->table_name = CPLStrdup(osTableName );
+            poNode->string_value = CPLStrdup( "*" );
             poNode->table_index = poNode->field_index = -1;
 
             if( !context->poCurSelect->PushField( poNode ) )
@@ -2190,20 +2164,20 @@ yyreduce:
                 YYERROR;
             }
         }
-#line 2193 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2168 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 66:
-#line 658 "swq_parser.y" /* yacc.c:1646  */
+  case 64:
+#line 639 "swq_parser.y" /* yacc.c:1646  */
     {
                 // special case for COUNT(*), confirm it.
             if( !EQUAL((yyvsp[-3])->string_value,"COUNT") )
             {
                 CPLError( CE_Failure, CPLE_AppDefined,
                         "Syntax Error with %s(*).", 
-                    (yyvsp[-3])->string_value );
+                        (yyvsp[-3])->string_value );
                 delete (yyvsp[-3]);
-                    YYERROR;
+                YYERROR;
             }
 
             delete (yyvsp[-3]);
@@ -2223,11 +2197,11 @@ yyreduce:
                 YYERROR;
             }
         }
-#line 2226 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2201 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 67:
-#line 688 "swq_parser.y" /* yacc.c:1646  */
+  case 65:
+#line 669 "swq_parser.y" /* yacc.c:1646  */
     {
                 // special case for COUNT(*), confirm it.
             if( !EQUAL((yyvsp[-4])->string_value,"COUNT") )
@@ -2260,11 +2234,11 @@ yyreduce:
 
             delete (yyvsp[0]);
         }
-#line 2263 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2238 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 68:
-#line 722 "swq_parser.y" /* yacc.c:1646  */
+  case 66:
+#line 703 "swq_parser.y" /* yacc.c:1646  */
     {
                 // special case for COUNT(DISTINCT x), confirm it.
             if( !EQUAL((yyvsp[-4])->string_value,"COUNT") )
@@ -2287,11 +2261,11 @@ yyreduce:
                 YYERROR;
             }
         }
-#line 2290 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2265 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 69:
-#line 746 "swq_parser.y" /* yacc.c:1646  */
+  case 67:
+#line 727 "swq_parser.y" /* yacc.c:1646  */
     {
             // special case for COUNT(DISTINCT x), confirm it.
             if( !EQUAL((yyvsp[-5])->string_value,"COUNT") )
@@ -2318,127 +2292,135 @@ yyreduce:
             delete (yyvsp[-5]);
             delete (yyvsp[0]);
         }
-#line 2321 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2296 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 70:
-#line 775 "swq_parser.y" /* yacc.c:1646  */
+  case 68:
+#line 756 "swq_parser.y" /* yacc.c:1646  */
     {
             delete (yyvsp[-1]);
             (yyval) = (yyvsp[0]);
         }
-#line 2330 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2305 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 73:
-#line 785 "swq_parser.y" /* yacc.c:1646  */
+  case 71:
+#line 766 "swq_parser.y" /* yacc.c:1646  */
     {
             context->poCurSelect->where_expr = (yyvsp[0]);
         }
-#line 2338 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2313 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 75:
-#line 791 "swq_parser.y" /* yacc.c:1646  */
+  case 73:
+#line 772 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poCurSelect->PushJoin( (yyvsp[-5])->int_value,
-                                            (yyvsp[-3])->string_value, 
-                                            (yyvsp[-1])->string_value );
-            delete (yyvsp[-5]);
+            context->poCurSelect->PushJoin( (yyvsp[-3])->int_value,
+                                            (yyvsp[-1]) );
             delete (yyvsp[-3]);
-            delete (yyvsp[-1]);
         }
-#line 2351 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2323 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 76:
-#line 800 "swq_parser.y" /* yacc.c:1646  */
+  case 74:
+#line 778 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poCurSelect->PushJoin( (yyvsp[-5])->int_value,
-                                            (yyvsp[-3])->string_value, 
-                                            (yyvsp[-1])->string_value );
-            delete (yyvsp[-5]);
+            context->poCurSelect->PushJoin( (yyvsp[-3])->int_value,
+                                            (yyvsp[-1]) );
             delete (yyvsp[-3]);
-            delete (yyvsp[-1]);
 	    }
-#line 2364 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2333 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 81:
-#line 818 "swq_parser.y" /* yacc.c:1646  */
+  case 79:
+#line 793 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poCurSelect->PushOrderBy( (yyvsp[0])->string_value, TRUE );
+            context->poCurSelect->PushOrderBy( (yyvsp[0])->table_name, (yyvsp[0])->string_value, TRUE );
             delete (yyvsp[0]);
             (yyvsp[0]) = NULL;
         }
-#line 2374 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2343 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 82:
-#line 824 "swq_parser.y" /* yacc.c:1646  */
+  case 80:
+#line 799 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poCurSelect->PushOrderBy( (yyvsp[-1])->string_value, TRUE );
+            context->poCurSelect->PushOrderBy( (yyvsp[-1])->table_name, (yyvsp[-1])->string_value, TRUE );
             delete (yyvsp[-1]);
             (yyvsp[-1]) = NULL;
         }
-#line 2384 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2353 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 83:
-#line 830 "swq_parser.y" /* yacc.c:1646  */
+  case 81:
+#line 805 "swq_parser.y" /* yacc.c:1646  */
     {
-            context->poCurSelect->PushOrderBy( (yyvsp[-1])->string_value, FALSE );
+            context->poCurSelect->PushOrderBy( (yyvsp[-1])->table_name, (yyvsp[-1])->string_value, FALSE );
             delete (yyvsp[-1]);
             (yyvsp[-1]) = NULL;
         }
-#line 2394 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2363 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 84:
-#line 838 "swq_parser.y" /* yacc.c:1646  */
+  case 82:
+#line 813 "swq_parser.y" /* yacc.c:1646  */
     {
-            (yyval) = (yyvsp[0]);
-        }
-#line 2402 "swq_parser.cpp" /* yacc.c:1646  */
+        int iTable;
+        iTable =context->poCurSelect->PushTableDef( NULL, (yyvsp[0])->string_value,
+                                                    NULL );
+        delete (yyvsp[0]);
+
+        (yyval) = new swq_expr_node( iTable );
+    }
+#line 2376 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 85:
-#line 842 "swq_parser.y" /* yacc.c:1646  */
+  case 83:
+#line 823 "swq_parser.y" /* yacc.c:1646  */
     {
-            (yyval) = (yyvsp[0]);
-        }
-#line 2410 "swq_parser.cpp" /* yacc.c:1646  */
+        int iTable;
+        iTable = context->poCurSelect->PushTableDef( NULL, (yyvsp[-1])->string_value,
+                                                     (yyvsp[0])->string_value );
+        delete (yyvsp[-1]);
+        delete (yyvsp[0]);
+
+        (yyval) = new swq_expr_node( iTable );
+    }
+#line 2390 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 86:
-#line 848 "swq_parser.y" /* yacc.c:1646  */
+  case 84:
+#line 834 "swq_parser.y" /* yacc.c:1646  */
     {
         int iTable;
-        iTable =context->poCurSelect->PushTableDef( NULL, (yyvsp[0])->string_value,
-                                                    NULL );
+        iTable = context->poCurSelect->PushTableDef( (yyvsp[-2])->string_value,
+                                                     (yyvsp[0])->string_value, NULL );
+        delete (yyvsp[-2]);
         delete (yyvsp[0]);
 
         (yyval) = new swq_expr_node( iTable );
     }
-#line 2423 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2404 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 87:
-#line 858 "swq_parser.y" /* yacc.c:1646  */
+  case 85:
+#line 845 "swq_parser.y" /* yacc.c:1646  */
     {
         int iTable;
-        iTable = context->poCurSelect->PushTableDef( NULL, (yyvsp[-1])->string_value,
+        iTable = context->poCurSelect->PushTableDef( (yyvsp[-3])->string_value,
+                                                     (yyvsp[-1])->string_value, 
                                                      (yyvsp[0])->string_value );
+        delete (yyvsp[-3]);
         delete (yyvsp[-1]);
         delete (yyvsp[0]);
 
         (yyval) = new swq_expr_node( iTable );
     }
-#line 2437 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2420 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 88:
-#line 869 "swq_parser.y" /* yacc.c:1646  */
+  case 86:
+#line 858 "swq_parser.y" /* yacc.c:1646  */
     {
         int iTable;
         iTable = context->poCurSelect->PushTableDef( (yyvsp[-2])->string_value,
@@ -2448,11 +2430,11 @@ yyreduce:
 
         (yyval) = new swq_expr_node( iTable );
     }
-#line 2451 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2434 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
-  case 89:
-#line 880 "swq_parser.y" /* yacc.c:1646  */
+  case 87:
+#line 869 "swq_parser.y" /* yacc.c:1646  */
     {
         int iTable;
         iTable = context->poCurSelect->PushTableDef( (yyvsp[-3])->string_value,
@@ -2464,11 +2446,11 @@ yyreduce:
 
         (yyval) = new swq_expr_node( iTable );
     }
-#line 2467 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2450 "swq_parser.cpp" /* yacc.c:1646  */
     break;
 
 
-#line 2471 "swq_parser.cpp" /* yacc.c:1646  */
+#line 2454 "swq_parser.cpp" /* yacc.c:1646  */
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
diff --git a/ogr/swq_parser.hpp b/ogr/swq_parser.hpp
index 894cf17..80f43c2 100644
--- a/ogr/swq_parser.hpp
+++ b/ogr/swq_parser.hpp
@@ -3,7 +3,6 @@
 /* Bison interface for Yacc-like parsers in C
 
    Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
- * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -72,14 +71,13 @@ extern int swqdebug;
     SWQT_CAST = 280,
     SWQT_UNION = 281,
     SWQT_ALL = 282,
-    SWQT_LOGICAL_START = 283,
-    SWQT_VALUE_START = 284,
-    SWQT_SELECT_START = 285,
-    SWQT_NOT = 286,
-    SWQT_OR = 287,
-    SWQT_AND = 288,
-    SWQT_UMINUS = 289,
-    SWQT_RESERVED_KEYWORD = 290
+    SWQT_VALUE_START = 283,
+    SWQT_SELECT_START = 284,
+    SWQT_NOT = 285,
+    SWQT_OR = 286,
+    SWQT_AND = 287,
+    SWQT_UMINUS = 288,
+    SWQT_RESERVED_KEYWORD = 289
   };
 #endif
 
diff --git a/ogr/swq_parser.y b/ogr/swq_parser.y
index cdc2877..28f10df 100644
--- a/ogr/swq_parser.y
+++ b/ogr/swq_parser.y
@@ -80,7 +80,6 @@
 %token SWQT_UNION               "UNION"
 %token SWQT_ALL                 "ALL"
 
-%token SWQT_LOGICAL_START
 %token SWQT_VALUE_START
 %token SWQT_SELECT_START
 
@@ -90,9 +89,12 @@
 %token SWQT_OR                  "OR"
 %token SWQT_AND                 "AND"
 
-%left SWQT_NOT
 %left SWQT_OR
 %left SWQT_AND
+%left SWQT_NOT
+
+%left '=' '<' '>' '!'  SWQT_BETWEEN SWQT_IN SWQT_LIKE SWQT_IS
+%left SWQT_ESCAPE
 
 %left '+' '-'
 %left '*' '/' '%'
@@ -103,28 +105,28 @@
 /* Any grammar rule that does $$ =  must be listed afterwards */
 /* as well as SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER that are allocated by swqlex() */
 %destructor { delete $$; } SWQT_INTEGER_NUMBER SWQT_FLOAT_NUMBER SWQT_STRING SWQT_IDENTIFIER
-%destructor { delete $$; } logical_expr value_expr_list field_value value_expr type_def string_or_identifier table_def
+%destructor { delete $$; } value_expr_list field_value value_expr value_expr_non_logical type_def table_def
 
 %%
 
 input:  
-    SWQT_LOGICAL_START logical_expr
+    | SWQT_VALUE_START value_expr
         {
             context->poRoot = $2;
         }
 
-    | SWQT_VALUE_START value_expr
+    | SWQT_SELECT_START select_statement
         {
             context->poRoot = $2;
         }
 
-    | SWQT_SELECT_START select_statement
+value_expr:
+    value_expr_non_logical 
         {
-            context->poRoot = $2;
+            $$ = $1;
         }
 
-logical_expr:
-    logical_expr SWQT_AND logical_expr 
+    | value_expr SWQT_AND value_expr 
         {
             $$ = new swq_expr_node( SWQ_AND );
             $$->field_type = SWQ_BOOLEAN;
@@ -132,7 +134,7 @@ logical_expr:
             $$->PushSubExpression( $3 );
         }
 
-    | logical_expr SWQT_OR logical_expr
+    | value_expr SWQT_OR value_expr
         {
             $$ = new swq_expr_node( SWQ_OR );
             $$->field_type = SWQ_BOOLEAN;
@@ -140,18 +142,13 @@ logical_expr:
             $$->PushSubExpression( $3 );
         }
 
-    | SWQT_NOT logical_expr
+    | SWQT_NOT value_expr
         {
             $$ = new swq_expr_node( SWQ_NOT );
             $$->field_type = SWQ_BOOLEAN;
             $$->PushSubExpression( $2 );
         }
 
-    | '(' logical_expr ')'
-        {
-            $$ = $2;
-        }
-
     | value_expr '=' value_expr
         {
             $$ = new swq_expr_node( SWQ_EQ );
@@ -292,7 +289,7 @@ logical_expr:
             $$->PushSubExpression( in );
         }
 
-    | value_expr SWQT_BETWEEN value_expr SWQT_AND value_expr
+    | value_expr SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_BETWEEN );
             $$->field_type = SWQ_BOOLEAN;
@@ -301,7 +298,7 @@ logical_expr:
             $$->PushSubExpression( $5 );
         }
 
-    | value_expr SWQT_NOT SWQT_BETWEEN value_expr SWQT_AND value_expr
+    | value_expr SWQT_NOT SWQT_BETWEEN value_expr_non_logical SWQT_AND value_expr_non_logical
         {
             swq_expr_node *between;
             between = new swq_expr_node( SWQ_BETWEEN );
@@ -344,7 +341,7 @@ value_expr_list:
 
     | value_expr
             {
-            $$ = new swq_expr_node( SWQ_UNKNOWN ); /* list */
+            $$ = new swq_expr_node( SWQ_ARGUMENT_LIST ); /* temporary value */
             $$->PushSubExpression( $1 );
         }
 
@@ -361,17 +358,13 @@ field_value:
             $$ = $1;  // validation deferred.
             $$->eNodeType = SNT_COLUMN;
             $$->field_index = $$->table_index = -1;
-            $$->string_value = (char *) 
-                            CPLRealloc( $$->string_value, 
-                                        strlen($$->string_value) 
-                                        + strlen($3->string_value) + 2 );
-            strcat( $$->string_value, "." );
-            strcat( $$->string_value, $3->string_value );
+            $$->table_name = $$->string_value;
+            $$->string_value = CPLStrdup($3->string_value);
             delete $3;
             $3 = NULL;
         }
 
-value_expr:
+value_expr_non_logical:
     SWQT_INTEGER_NUMBER 
         {
             $$ = $1;
@@ -401,7 +394,7 @@ value_expr:
             $$ = new swq_expr_node((const char*)NULL);
         }
 
-    | '-' value_expr %prec SWQT_UMINUS
+    | '-' value_expr_non_logical %prec SWQT_UMINUS
         {
             if ($2->eNodeType == SNT_CONSTANT)
             {
@@ -417,35 +410,35 @@ value_expr:
             }
         }
 
-    | value_expr '+' value_expr
+    | value_expr_non_logical '+' value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_ADD );
             $$->PushSubExpression( $1 );
             $$->PushSubExpression( $3 );
         }
 
-    | value_expr '-' value_expr
+    | value_expr_non_logical '-' value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_SUBTRACT );
             $$->PushSubExpression( $1 );
             $$->PushSubExpression( $3 );
         }
 
-    | value_expr '*' value_expr
+    | value_expr_non_logical '*' value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_MULTIPLY );
             $$->PushSubExpression( $1 );
             $$->PushSubExpression( $3 );
         }
 
-    | value_expr '/' value_expr
+    | value_expr_non_logical '/' value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_DIVIDE );
             $$->PushSubExpression( $1 );
             $$->PushSubExpression( $3 );
         }
 
-    | value_expr '%' value_expr
+    | value_expr_non_logical '%' value_expr_non_logical
         {
             $$ = new swq_expr_node( SWQ_MODULUS );
             $$->PushSubExpression( $1 );
@@ -459,18 +452,30 @@ value_expr:
 
             if( poOp == NULL )
             {
-                CPLError( CE_Failure, CPLE_AppDefined, 
-                                "Undefined function '%s' used.",
-                                $1->string_value );
-                delete $1;
-                delete $3;
-                YYERROR;
+                if( context->bAcceptCustomFuncs )
+                {
+                    $$ = $3;
+                    $$->eNodeType = SNT_OPERATION;
+                    $$->nOperation = SWQ_CUSTOM_FUNC;
+                    $$->string_value = CPLStrdup($1->string_value);
+                    $$->ReverseSubExpressions();
+                    delete $1;
+                }
+                else
+                {
+                    CPLError( CE_Failure, CPLE_AppDefined, 
+                                    "Undefined function '%s' used.",
+                                    $1->string_value );
+                    delete $1;
+                    delete $3;
+                    YYERROR;
+                }
             }
             else
             {
                 $$ = $3;
-                            $$->eNodeType = SNT_OPERATION;
-                            $$->nOperation = poOp->eOperation;
+                $$->eNodeType = SNT_OPERATION;
+                $$->nOperation = poOp->eOperation;
                 $$->ReverseSubExpressions();
                 delete $1;
             }
@@ -553,6 +558,12 @@ select_core:
         delete $4;
     }
 
+    | SWQT_SELECT SWQT_DISTINCT select_field_list SWQT_FROM table_def opt_joins opt_where opt_order_by
+    {
+        context->poCurSelect->query_mode = SWQM_DISTINCT_LIST;
+        delete $5;
+    }
+
 opt_union_all:
     | union_all select_statement
 
@@ -568,25 +579,7 @@ select_field_list:
     | column_spec ',' select_field_list
 
 column_spec: 
-    SWQT_DISTINCT field_value
-        {
-            if( !context->poCurSelect->PushField( $2, NULL, TRUE ) )
-            {
-                delete $2;
-                YYERROR;
-            }
-        }
-
-    | SWQT_DISTINCT SWQT_STRING
-        {
-            if( !context->poCurSelect->PushField( $2, NULL, TRUE ) )
-            {
-                delete $2;
-                YYERROR;
-            }
-        }
-
-    | value_expr
+    value_expr
         {
             if( !context->poCurSelect->PushField( $1 ) )
             {
@@ -595,18 +588,6 @@ column_spec:
             }
         }
 
-    | SWQT_DISTINCT field_value as_clause
-        {
-            if( !context->poCurSelect->PushField( $2, $3->string_value, TRUE ))
-            {
-                delete $2;
-                delete $3;
-                YYERROR;
-            }
-
-            delete $3;
-        }
-
     | value_expr as_clause
         {
             if( !context->poCurSelect->PushField( $1, $2->string_value ) )
@@ -634,17 +615,17 @@ column_spec:
 
     | SWQT_IDENTIFIER '.' '*'
         {
-            CPLString osQualifiedField;
+            CPLString osTableName;
 
-            osQualifiedField = $1->string_value;
-            osQualifiedField += ".*";
+            osTableName = $1->string_value;
 
             delete $1;
             $1 = NULL;
 
             swq_expr_node *poNode = new swq_expr_node();
             poNode->eNodeType = SNT_COLUMN;
-            poNode->string_value = CPLStrdup( osQualifiedField );
+            poNode->table_name = CPLStrdup(osTableName );
+            poNode->string_value = CPLStrdup( "*" );
             poNode->table_index = poNode->field_index = -1;
 
             if( !context->poCurSelect->PushField( poNode ) )
@@ -661,9 +642,9 @@ column_spec:
             {
                 CPLError( CE_Failure, CPLE_AppDefined,
                         "Syntax Error with %s(*).", 
-                    $1->string_value );
+                        $1->string_value );
                 delete $1;
-                    YYERROR;
+                YYERROR;
             }
 
             delete $1;
@@ -771,39 +752,33 @@ column_spec:
         }
 
 as_clause:
-    SWQT_AS string_or_identifier
+    SWQT_AS SWQT_IDENTIFIER
         {
             delete $1;
             $$ = $2;
         }
 
-    | string_or_identifier
+    | SWQT_IDENTIFIER
 
 
 opt_where:  
-    | SWQT_WHERE logical_expr
+    | SWQT_WHERE value_expr
         {
             context->poCurSelect->where_expr = $2;
         }
 
 opt_joins:
-    | SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
+    | SWQT_JOIN table_def SWQT_ON value_expr opt_joins
         {
             context->poCurSelect->PushJoin( $2->int_value,
-                                            $4->string_value, 
-                                            $6->string_value );
+                                            $4 );
             delete $2;
-            delete $4;
-            delete $6;
         }
-    | SWQT_LEFT SWQT_JOIN table_def SWQT_ON field_value '=' field_value opt_joins
+    | SWQT_LEFT SWQT_JOIN table_def SWQT_ON value_expr opt_joins
         {
             context->poCurSelect->PushJoin( $3->int_value,
-                                            $5->string_value, 
-                                            $7->string_value );
+                                            $5 );
             delete $3;
-            delete $5;
-            delete $7;
 	    }
 
 opt_order_by:
@@ -816,35 +791,25 @@ sort_spec_list:
 sort_spec:
     field_value
         {
-            context->poCurSelect->PushOrderBy( $1->string_value, TRUE );
+            context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
             delete $1;
             $1 = NULL;
         }
     | field_value SWQT_ASC
         {
-            context->poCurSelect->PushOrderBy( $1->string_value, TRUE );
+            context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, TRUE );
             delete $1;
             $1 = NULL;
         }
     | field_value SWQT_DESC
         {
-            context->poCurSelect->PushOrderBy( $1->string_value, FALSE );
+            context->poCurSelect->PushOrderBy( $1->table_name, $1->string_value, FALSE );
             delete $1;
             $1 = NULL;
         }
 
-string_or_identifier:
-    SWQT_IDENTIFIER
-        {
-            $$ = $1;
-        }
-    | SWQT_STRING
-        {
-            $$ = $1;
-        }
-
 table_def:
-    string_or_identifier
+    SWQT_IDENTIFIER
     {
         int iTable;
         iTable =context->poCurSelect->PushTableDef( NULL, $1->string_value,
@@ -854,7 +819,7 @@ table_def:
         $$ = new swq_expr_node( iTable );
     }
 
-    | string_or_identifier SWQT_IDENTIFIER
+    | SWQT_IDENTIFIER as_clause
     {
         int iTable;
         iTable = context->poCurSelect->PushTableDef( NULL, $1->string_value,
@@ -865,7 +830,31 @@ table_def:
         $$ = new swq_expr_node( iTable );
     }
 
-    | SWQT_STRING '.' string_or_identifier
+    | SWQT_STRING '.' SWQT_IDENTIFIER
+    {
+        int iTable;
+        iTable = context->poCurSelect->PushTableDef( $1->string_value,
+                                                     $3->string_value, NULL );
+        delete $1;
+        delete $3;
+
+        $$ = new swq_expr_node( iTable );
+    }
+
+    | SWQT_STRING '.' SWQT_IDENTIFIER as_clause
+    {
+        int iTable;
+        iTable = context->poCurSelect->PushTableDef( $1->string_value,
+                                                     $3->string_value, 
+                                                     $4->string_value );
+        delete $1;
+        delete $3;
+        delete $4;
+
+        $$ = new swq_expr_node( iTable );
+    }
+
+    | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER
     {
         int iTable;
         iTable = context->poCurSelect->PushTableDef( $1->string_value,
@@ -876,7 +865,7 @@ table_def:
         $$ = new swq_expr_node( iTable );
     }
 
-    | SWQT_STRING '.' string_or_identifier SWQT_IDENTIFIER
+    | SWQT_IDENTIFIER '.' SWQT_IDENTIFIER as_clause
     {
         int iTable;
         iTable = context->poCurSelect->PushTableDef( $1->string_value,
diff --git a/ogr/swq_select.cpp b/ogr/swq_select.cpp
index 59068e9..c731547 100644
--- a/ogr/swq_select.cpp
+++ b/ogr/swq_select.cpp
@@ -84,6 +84,7 @@ swq_select::~swq_select()
 
     for( i = 0; i < result_columns; i++ )
     {
+        CPLFree( column_defs[i].table_name );
         CPLFree( column_defs[i].field_name );
         CPLFree( column_defs[i].field_alias );
 
@@ -107,6 +108,7 @@ swq_select::~swq_select()
 
     for( i = 0; i < order_specs; i++ )
     {
+        CPLFree( order_defs[i].table_name );
         CPLFree( order_defs[i].field_name );
     }
     
@@ -114,8 +116,7 @@ swq_select::~swq_select()
 
     for( i = 0; i < join_count; i++ )
     {
-        CPLFree( join_defs[i].primary_field_name );
-        CPLFree( join_defs[i].secondary_field_name );
+        delete join_defs[i].poExpr;
     }
     CPLFree( join_defs );
 
@@ -129,7 +130,8 @@ swq_select::~swq_select()
 /*      tables and fields.                                              */
 /************************************************************************/
 
-CPLErr swq_select::preparse( const char *select_statement )
+CPLErr swq_select::preparse( const char *select_statement,
+                             int bAcceptCustomFuncs )
 
 {
 /* -------------------------------------------------------------------- */
@@ -141,6 +143,7 @@ CPLErr swq_select::preparse( const char *select_statement )
     context.pszNext = select_statement;
     context.pszLastValid = select_statement;
     context.nStartToken = SWQT_SELECT_START;
+    context.bAcceptCustomFuncs = bAcceptCustomFuncs;
     context.poCurSelect = this;
 
 /* -------------------------------------------------------------------- */
@@ -216,7 +219,7 @@ void swq_select::Dump( FILE *fp )
     {
         swq_col_def *def = column_defs + i;
 
-        
+        fprintf( fp, "  Table name: %s\n", def->table_name );
         fprintf( fp, "  Name: %s\n", def->field_name );
 
         if( def->field_alias )
@@ -247,6 +250,7 @@ void swq_select::Dump( FILE *fp )
 
         fprintf( fp, "    Field Type: %d\n", def->field_type );
         fprintf( fp, "    Target Type: %d\n", def->target_type );
+        fprintf( fp, "    Target SubType: %d\n", def->target_subtype );
         fprintf( fp, "    Length: %d, Precision: %d\n",
                  def->field_length, def->field_precision );
 
@@ -278,16 +282,7 @@ void swq_select::Dump( FILE *fp )
     for( i = 0; i < join_count; i++ )
     {
         fprintf( fp, "  %d:\n", i );
-        fprintf( fp, "    Primary Field: %s/%d\n", 
-                 join_defs[i].primary_field_name,
-                 join_defs[i].primary_field );
-
-        fprintf( fp, "    Operation: %d\n", 
-                 join_defs[i].op );
-
-        fprintf( fp, "    Secondary Field: %s/%d\n", 
-                 join_defs[i].secondary_field_name,
-                 join_defs[i].secondary_field );
+        join_defs[i].poExpr->Dump( fp, 4 );
         fprintf( fp, "    Secondary Table: %d\n", 
                  join_defs[i].secondary_table );
     }
@@ -319,6 +314,123 @@ void swq_select::Dump( FILE *fp )
 }
 
 /************************************************************************/
+/*                               Unparse()                              */
+/************************************************************************/
+
+char* swq_select::Unparse()
+{
+    int i;
+    CPLString osSelect("SELECT ");
+    if( query_mode == SWQM_DISTINCT_LIST )
+        osSelect += "DISTINCT ";
+
+    for( i = 0; i < result_columns; i++ )
+    {
+        swq_col_def *def = column_defs + i;
+
+        if( i > 0 )
+            osSelect += ", ";
+
+        if( def->expr != NULL && def->col_func == SWQCF_NONE )
+        {
+            char* pszTmp = def->expr->Unparse(NULL, '"');
+            osSelect += pszTmp;
+            CPLFree(pszTmp);
+        }
+        else
+        {
+            if( def->col_func == SWQCF_AVG )
+                osSelect += "AVG(";
+            else if( def->col_func == SWQCF_MIN )
+                osSelect += "MIN(";
+            else if( def->col_func == SWQCF_MAX )
+                osSelect += "MAX(";
+            else if( def->col_func == SWQCF_COUNT )
+                osSelect += "COUNT(";
+            else if( def->col_func == SWQCF_SUM )
+                osSelect += "SUM(";
+
+            if( def->distinct_flag && def->col_func == SWQCF_COUNT )
+                osSelect += "DISTINCT ";
+
+            if( (def->field_alias == NULL || table_count > 1) &&
+                def->table_name != NULL && def->table_name[0] != '\0' )
+            {
+                osSelect += swq_expr_node::QuoteIfNecessary(def->table_name, '"');
+                osSelect += ".";
+            }
+            osSelect += swq_expr_node::QuoteIfNecessary(def->field_name, '"');
+        }
+
+        if( def->field_alias != NULL &&
+            strcmp(def->field_name, def->field_alias) != 0 )
+        {
+            osSelect += " AS ";
+            osSelect += swq_expr_node::QuoteIfNecessary(def->field_alias, '"');
+        }
+
+        if( def->col_func != SWQCF_NONE )
+            osSelect += ")";
+    }
+    
+    osSelect += " FROM ";
+    if( table_defs[0].data_source != NULL )
+    {
+        osSelect += "'";
+        osSelect += table_defs[0].data_source;
+        osSelect += "'.";
+    }
+    osSelect += swq_expr_node::QuoteIfNecessary(table_defs[0].table_name, '"');
+    if( table_defs[0].table_alias != NULL &&
+        strcmp(table_defs[0].table_name, table_defs[0].table_alias) != 0 )
+    {
+        osSelect += " AS ";
+        osSelect += swq_expr_node::QuoteIfNecessary(table_defs[0].table_alias, '"');
+    }
+
+    for( i = 0; i < join_count; i++ )
+    {
+        int iTable = join_defs[i].secondary_table;
+        osSelect += " JOIN ";
+        if( table_defs[iTable].data_source != NULL )
+        {
+            osSelect += "'";
+            osSelect += table_defs[iTable].data_source;
+            osSelect += "'.";
+        }
+        osSelect += swq_expr_node::QuoteIfNecessary(table_defs[iTable].table_name, '"');
+        if( table_defs[iTable].table_alias != NULL &&
+            strcmp(table_defs[iTable].table_name, table_defs[iTable].table_alias) != 0 )
+        {
+            osSelect += " AS ";
+            osSelect += swq_expr_node::QuoteIfNecessary(table_defs[iTable].table_alias, '"');
+        }
+        osSelect += " ON ";
+        char* pszTmp = join_defs[i].poExpr->Unparse(NULL, '"');
+        osSelect += pszTmp;
+        CPLFree(pszTmp);
+    }
+
+    if( where_expr != NULL )
+    {
+        osSelect += " WHERE ";
+        char* pszTmp = where_expr->Unparse(NULL, '"');
+        osSelect += pszTmp;
+        CPLFree(pszTmp);
+    }
+
+    for( i = 0; i < order_specs; i++ )
+    {
+        osSelect += " ORDER BY ";
+        osSelect += swq_expr_node::QuoteIfNecessary(order_defs[i].field_name, '"');
+        if( !order_defs[i].ascending_flag )
+            osSelect += " DESC";
+    }
+
+    return CPLStrdup(osSelect);
+}
+
+/************************************************************************/
 /*                             PushField()                              */
 /*                                                                      */
 /*      Create a new field definition by name and possibly alias.       */
@@ -328,6 +440,12 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
                            int distinct_flag )
 
 {
+    if( query_mode == SWQM_DISTINCT_LIST && distinct_flag )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported, "SELECT DISTINCT and COUNT(DISTINCT...) not supported together");
+        return FALSE;
+    }
+
 /* -------------------------------------------------------------------- */
 /*      Grow the array.                                                 */
 /* -------------------------------------------------------------------- */
@@ -344,18 +462,30 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
 /*      Try to capture a field name.                                    */
 /* -------------------------------------------------------------------- */
     if( poExpr->eNodeType == SNT_COLUMN )
+    {
+        col_def->table_name = 
+            CPLStrdup(poExpr->table_name ? poExpr->table_name : "");
         col_def->field_name = 
             CPLStrdup(poExpr->string_value);
+    }
     else if( poExpr->eNodeType == SNT_OPERATION
              && (poExpr->nOperation == SWQ_CAST ||
                  (poExpr->nOperation >= SWQ_AVG &&
                   poExpr->nOperation <= SWQ_SUM))
              && poExpr->nSubExprCount >= 1
              && poExpr->papoSubExpr[0]->eNodeType == SNT_COLUMN )
+    {
+        col_def->table_name = 
+            CPLStrdup(poExpr->papoSubExpr[0]->table_name ?
+                        poExpr->papoSubExpr[0]->table_name : "");
         col_def->field_name = 
             CPLStrdup(poExpr->papoSubExpr[0]->string_value);
+    }
     else
+    {
+        col_def->table_name = CPLStrdup("");
         col_def->field_name = CPLStrdup("");
+    }
 
 /* -------------------------------------------------------------------- */
 /*      Initialize fields.                                              */
@@ -380,6 +510,7 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
     col_def->field_type = SWQ_OTHER;
     col_def->field_precision = -1;
     col_def->target_type = SWQ_OTHER;
+    col_def->target_subtype = OFSTNone;
     col_def->col_func = SWQCF_NONE;
     col_def->distinct_flag = distinct_flag;
 
@@ -397,10 +528,23 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
             col_def->target_type = SWQ_STRING;
             col_def->field_length = 1;
         }
+        else if( strcasecmp(pszTypeName,"boolean") == 0 )
+        {
+            col_def->target_type = SWQ_BOOLEAN;
+        }
         else if( strcasecmp(pszTypeName,"integer") == 0 )
         {
             col_def->target_type = SWQ_INTEGER;
         }
+        else if( strcasecmp(pszTypeName,"bigint") == 0 )
+        {
+            col_def->target_type = SWQ_INTEGER64;
+        }
+        else if( strcasecmp(pszTypeName,"smallint") == 0 )
+        {
+            col_def->target_type = SWQ_INTEGER;
+            col_def->target_subtype = OFSTInt16;
+        }
         else if( strcasecmp(pszTypeName,"float") == 0 )
         {
             col_def->target_type = SWQ_FLOAT;
@@ -431,6 +575,8 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Unrecognized typename %s in CAST operator.", 
                       pszTypeName );
+            CPLFree(col_def->table_name);
+            col_def->table_name = NULL;
             CPLFree(col_def->field_name);
             col_def->field_name = NULL;
             CPLFree(col_def->field_alias);
@@ -447,6 +593,8 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
                 {
                     CPLError( CE_Failure, CPLE_AppDefined,
                       "First argument of CAST operator should be an geometry type identifier." );
+                    CPLFree(col_def->table_name);
+                    col_def->table_name = NULL;
                     CPLFree(col_def->field_name);
                     col_def->field_name = NULL;
                     CPLFree(col_def->field_alias);
@@ -461,7 +609,7 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
                 // SRID
                 if( poExpr->nSubExprCount > 3 )
                 {
-                    col_def->nSRID = poExpr->papoSubExpr[3]->int_value;
+                    col_def->nSRID = (int)poExpr->papoSubExpr[3]->int_value;
                 }
             }
         }
@@ -474,6 +622,8 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
                 {
                     CPLError( CE_Failure, CPLE_AppDefined,
                       "First argument of CAST operator should be of integer type." );
+                    CPLFree(col_def->table_name);
+                    col_def->table_name = NULL;
                     CPLFree(col_def->field_name);
                     col_def->field_name = NULL;
                     CPLFree(col_def->field_alias);
@@ -481,13 +631,20 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
                     result_columns--;
                     return FALSE;
                 }
-                col_def->field_length = poExpr->papoSubExpr[2]->int_value;
+                col_def->field_length = (int)poExpr->papoSubExpr[2]->int_value;
             }
 
             // field width.
             if( poExpr->nSubExprCount > 3 && parse_precision )
             {
-                col_def->field_precision = poExpr->papoSubExpr[3]->int_value;
+                col_def->field_precision = (int)poExpr->papoSubExpr[3]->int_value;
+                if( col_def->field_precision == 0 )
+                {
+                    if( col_def->field_length < 10 )
+                        col_def->target_type = SWQ_INTEGER;
+                    else if( col_def->field_length < 19 )
+                        col_def->target_type = SWQ_INTEGER64;
+                }
             }
         }
     }
@@ -506,6 +663,8 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Column Summary Function '%s' has wrong number of arguments.", 
                       poOp->pszName );
+            CPLFree(col_def->table_name);
+            col_def->table_name = NULL;
             CPLFree(col_def->field_name);
             col_def->field_name = NULL;
             CPLFree(col_def->field_alias);
@@ -520,6 +679,8 @@ int swq_select::PushField( swq_expr_node *poExpr, const char *pszAlias,
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Argument of column Summary Function '%s' should be a column.", 
                       poOp->pszName );
+            CPLFree(col_def->table_name);
+            col_def->table_name = NULL;
             CPLFree(col_def->field_name);
             col_def->field_name = NULL;
             CPLFree(col_def->field_alias);
@@ -580,13 +741,14 @@ int swq_select::PushTableDef( const char *pszDataSource,
 /*                            PushOrderBy()                             */
 /************************************************************************/
 
-void swq_select::PushOrderBy( const char *pszFieldName, int bAscending )
+void swq_select::PushOrderBy( const char* pszTableName, const char *pszFieldName, int bAscending )
 
 {
     order_specs++;
     order_defs = (swq_order_def *) 
         CPLRealloc( order_defs, sizeof(swq_order_def) * order_specs );
 
+    order_defs[order_specs-1].table_name = CPLStrdup(pszTableName ? pszTableName : "");
     order_defs[order_specs-1].field_name = CPLStrdup(pszFieldName);
     order_defs[order_specs-1].table_index = -1;
     order_defs[order_specs-1].field_index = -1;
@@ -597,9 +759,7 @@ void swq_select::PushOrderBy( const char *pszFieldName, int bAscending )
 /*                              PushJoin()                              */
 /************************************************************************/
 
-void swq_select::PushJoin( int iSecondaryTable,
-                           const char *pszPrimaryField,
-                           const char *pszSecondaryField )
+void swq_select::PushJoin( int iSecondaryTable, swq_expr_node* poExpr )
 
 {
     join_count++;
@@ -607,11 +767,7 @@ void swq_select::PushJoin( int iSecondaryTable,
         CPLRealloc( join_defs, sizeof(swq_join_def) * join_count );
 
     join_defs[join_count-1].secondary_table = iSecondaryTable;
-    join_defs[join_count-1].primary_field_name = CPLStrdup(pszPrimaryField);
-    join_defs[join_count-1].primary_field = -1;
-    join_defs[join_count-1].op = SWQ_EQ;
-    join_defs[join_count-1].secondary_field_name = CPLStrdup(pszSecondaryField);
-    join_defs[join_count-1].secondary_field = -1;
+    join_defs[join_count-1].poExpr = poExpr;
 }
 
 /************************************************************************/
@@ -634,7 +790,8 @@ void swq_select::PushUnionAll( swq_select* poOtherSelectIn )
 /*      fields.                                                         */
 /************************************************************************/
 
-CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
+CPLErr swq_select::expand_wildcard( swq_field_list *field_list,
+                                    int bAlwaysPrefixWithTableName )
 
 {
     int isrc;
@@ -644,6 +801,7 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
 /* ==================================================================== */
     for( isrc = 0; isrc < result_columns; isrc++ )
     {
+        const char *src_tablename = column_defs[isrc].table_name;
         const char *src_fieldname = column_defs[isrc].field_name;
         int itable, new_fields, i, iout;
 
@@ -659,27 +817,16 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
 /*      Parse out the table name, verify it, and establish the          */
 /*      number of fields to insert from it.                             */
 /* -------------------------------------------------------------------- */
-        if( strcmp(src_fieldname,"*") == 0 )
+        if( src_tablename[0] == 0 && strcmp(src_fieldname,"*") == 0 )
         {
             itable = -1;
             new_fields = field_list->count;
         }
-        else if( strlen(src_fieldname) < 3 
-                 || src_fieldname[strlen(src_fieldname)-2] != '.' )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                      "Ill formatted field definition '%s'.",
-                     src_fieldname );
-            return CE_Failure;
-        }
         else
         {
-            char *table_name = CPLStrdup( src_fieldname );
-            table_name[strlen(src_fieldname)-2] = '\0';
-
             for( itable = 0; itable < field_list->table_count; itable++ )
             {
-                if( strcasecmp(table_name,
+                if( strcasecmp(src_tablename,
                         field_list->table_defs[itable].table_alias ) == 0 )
                     break;
             }
@@ -687,13 +834,11 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
             if( itable == field_list->table_count )
             {
                 CPLError( CE_Failure, CPLE_AppDefined,
-                         "Table %s not recognised from %s definition.", 
-                         table_name, src_fieldname );
-                CPLFree( table_name );
+                         "Table %s not recognised from %s.%s definition.", 
+                         src_tablename, src_tablename, src_fieldname );
                 return CE_Failure;
             }
-            CPLFree( table_name );
-            
+
             /* count the number of fields in this table. */
             new_fields = 0;
             for( i = 0; i < field_list->count; i++ )
@@ -708,6 +853,7 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
 /* -------------------------------------------------------------------- */
 /*      Reallocate the column list larger.                              */
 /* -------------------------------------------------------------------- */
+            CPLFree( column_defs[isrc].table_name );
             CPLFree( column_defs[isrc].field_name );
             delete column_defs[isrc].expr;
 
@@ -743,6 +889,7 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
 /* -------------------------------------------------------------------- */
 /*      The wildcard expands to nothing                                 */
 /* -------------------------------------------------------------------- */
+            CPLFree( column_defs[isrc].table_name );
             CPLFree( column_defs[isrc].field_name );
             delete column_defs[isrc].expr;
 
@@ -761,7 +908,7 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
         for( i = 0; i < field_list->count; i++ )
         {
             swq_col_def *def;
-            int compose = itable != -1;
+            int compose = (itable != -1) || bAlwaysPrefixWithTableName;
 
             /* skip this field if it isn't in the target table.  */
             if( itable != -1 && itable != field_list->table_ids[i] )
@@ -771,6 +918,7 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
             def = column_defs + iout;
             def->field_precision = -1; 
             def->target_type = SWQ_OTHER;
+            def->target_subtype = OFSTNone;
 
             /* does this field duplicate an earlier one? */
             if( field_list->table_ids[i] != 0 
@@ -790,17 +938,12 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
             }
 
             int itable = field_list->table_ids[i];
-            char *composed_name;
             const char *field_name = field_list->names[i];
             const char *table_alias = 
                 field_list->table_defs[itable].table_alias;
 
-            composed_name = (char *) 
-                CPLMalloc(strlen(field_name)+strlen(table_alias)+2);
-
-            sprintf( composed_name, "%s.%s", table_alias, field_name );
-
-            def->field_name = composed_name;
+            def->table_name = CPLStrdup(table_alias);
+            def->field_name = CPLStrdup(field_name);
             if( !compose )
                 def->field_alias = CPLStrdup( field_list->names[i] );
 
@@ -821,22 +964,74 @@ CPLErr swq_select::expand_wildcard( swq_field_list *field_list )
 }
 
 /************************************************************************/
+/*                       CheckCompatibleJoinExpr()                      */
+/************************************************************************/
+
+static int CheckCompatibleJoinExpr( swq_expr_node* poExpr,
+                                    int secondary_table,
+                                    swq_field_list* field_list )
+{
+    if( poExpr->eNodeType == SNT_CONSTANT )
+        return TRUE;
+    
+    if( poExpr->eNodeType == SNT_COLUMN )
+    {
+        CPLAssert( poExpr->field_index != -1 );
+        CPLAssert( poExpr->table_index != -1 );
+        if( poExpr->table_index != 0 && poExpr->table_index != secondary_table )
+        {
+            if( poExpr->table_name )
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                        "Field %s.%s in JOIN clause does not correspond to the primary table nor the joint (secondary) table.", 
+                        poExpr->table_name,
+                        poExpr->string_value );
+            else
+                CPLError( CE_Failure, CPLE_AppDefined, 
+                        "Field %s in JOIN clause does not correspond to the primary table nor the joint (secondary) table.", 
+                        poExpr->string_value );
+            return FALSE;
+        }
+
+        return TRUE;
+    }
+
+    if( poExpr->eNodeType == SNT_OPERATION )
+    {
+        for(int i=0;i<poExpr->nSubExprCount;i++)
+        {
+            if( !CheckCompatibleJoinExpr( poExpr->papoSubExpr[i],
+                                          secondary_table,
+                                          field_list ) )
+                return FALSE;
+        }
+        return TRUE;
+    }
+    
+    return FALSE;
+}
+
+/************************************************************************/
 /*                               parse()                                */
 /*                                                                      */
 /*      This method really does post-parse processing.                  */
 /************************************************************************/
 
 CPLErr swq_select::parse( swq_field_list *field_list,
-                          CPL_UNUSED int parse_flags )
+                          swq_select_parse_options* poParseOptions )
 {
     int  i;
     CPLErr eError;
 
-    eError = expand_wildcard( field_list );
+    int bAlwaysPrefixWithTableName = poParseOptions &&
+                                     poParseOptions->bAlwaysPrefixWithTableName;
+    eError = expand_wildcard( field_list, bAlwaysPrefixWithTableName );
     if( eError != CE_None )
         return eError;
 
-    
+    swq_custom_func_registrar* poCustomFuncRegistrar = NULL;
+    if( poParseOptions != NULL )
+        poCustomFuncRegistrar = poParseOptions->poCustomFuncRegistrar;
+
 /* -------------------------------------------------------------------- */
 /*      Identify field information.                                     */
 /* -------------------------------------------------------------------- */
@@ -849,28 +1044,18 @@ CPLErr swq_select::parse( swq_field_list *field_list,
             def->field_index = -1;
             def->table_index = -1;
 
-            if( def->expr->Check( field_list, TRUE ) == SWQ_ERROR )
+            if( def->expr->Check( field_list, TRUE, FALSE, poCustomFuncRegistrar ) == SWQ_ERROR )
                 return CE_Failure;
                 
             def->field_type = def->expr->field_type;
-
-            // If the field was changed from string constant to 
-            // column field then adopt the name. 
-            if( def->expr->eNodeType == SNT_COLUMN )
-            {
-                def->field_index = def->expr->field_index;
-                def->table_index = def->expr->table_index;
-
-                CPLFree( def->field_name );
-                def->field_name = CPLStrdup(def->expr->string_value);
-            }
         }
         else
         {
             swq_field_type  this_type;
 
             /* identify field */
-            def->field_index = swq_identify_field( def->field_name, field_list,
+            def->field_index = swq_identify_field( def->table_name,
+                                                   def->field_name, field_list,
                                                    &this_type, 
                                                    &(def->table_index) );
             
@@ -881,7 +1066,7 @@ CPLErr swq_select::parse( swq_field_list *field_list,
             {
                 CPLError( CE_Failure, CPLE_AppDefined, 
                           "Unrecognised field name %s.", 
-                          def->field_name );
+                          def->table_name[0] ? CPLSPrintf("%s.%s", def->table_name, def->field_name) : def->field_name );
                 return CE_Failure;
             }
         }
@@ -911,12 +1096,34 @@ CPLErr swq_select::parse( swq_field_list *field_list,
 /*      of records.  Generate an error if we get conflicting            */
 /*      indications.                                                    */
 /* -------------------------------------------------------------------- */
-    query_mode = -1;
+
+    int bAllowDistinctOnMultipleFields = (
+        poParseOptions && poParseOptions->bAllowDistinctOnMultipleFields );
+    if( query_mode == SWQM_DISTINCT_LIST && result_columns > 1 &&
+        !bAllowDistinctOnMultipleFields )
+    {
+            CPLError( CE_Failure, CPLE_NotSupported,
+                        "SELECT DISTINCT not supported on multiple columns." );
+            return CE_Failure;
+    }
+
     for( i = 0; i < result_columns; i++ )
     {
         swq_col_def *def = column_defs + i;
         int this_indicator = -1;
 
+        if( query_mode == SWQM_DISTINCT_LIST && def->field_type == SWQ_GEOMETRY )
+        {
+            int bAllowDistinctOnGeometryField = (
+                    poParseOptions && poParseOptions->bAllowDistinctOnGeometryField );
+            if( !bAllowDistinctOnGeometryField )
+            {
+                CPLError( CE_Failure, CPLE_NotSupported,
+                            "SELECT DISTINCT on a geometry not supported." );
+                return CE_Failure;
+            }
+        }
+
         if( def->col_func == SWQCF_MIN 
             || def->col_func == SWQCF_MAX
             || def->col_func == SWQCF_AVG
@@ -935,15 +1142,10 @@ CPLErr swq_select::parse( swq_field_list *field_list,
         }
         else if( def->col_func == SWQCF_NONE )
         {
-            if( def->distinct_flag )
+            if( query_mode == SWQM_DISTINCT_LIST )
             {
+                def->distinct_flag = TRUE;
                 this_indicator = SWQM_DISTINCT_LIST;
-                if( def->field_type == SWQ_GEOMETRY )
-                {
-                    CPLError( CE_Failure, CPLE_AppDefined,
-                              "SELECT DISTINCT on a geometry not supported." );
-                    return CE_Failure;
-                }
             }
             else
                 this_indicator = SWQM_RECORDSET;
@@ -951,7 +1153,7 @@ CPLErr swq_select::parse( swq_field_list *field_list,
 
         if( this_indicator != query_mode
              && this_indicator != -1
-            && query_mode != -1 )
+            && query_mode != 0 )
         {
             CPLError( CE_Failure, CPLE_AppDefined,
                       "Field list implies mixture of regular recordset mode, summary mode or distinct field list mode." );
@@ -962,14 +1164,7 @@ CPLErr swq_select::parse( swq_field_list *field_list,
             query_mode = this_indicator;
     }
 
-    if( result_columns > 1 
-        && query_mode == SWQM_DISTINCT_LIST )
-    {
-        CPLError( CE_Failure, CPLE_AppDefined,
-                  "SELECTing more than one DISTINCT field is a query not supported." );
-        return CE_Failure;
-    }
-    else if (result_columns == 0)
+    if (result_columns == 0)
     {
         query_mode = SWQM_RECORDSET;
     }
@@ -980,48 +1175,10 @@ CPLErr swq_select::parse( swq_field_list *field_list,
     for( i = 0; i < join_count; i++ )
     {
         swq_join_def *def = join_defs + i;
-        int          table_id;
-
-        /* identify primary field */
-        def->primary_field = swq_identify_field( def->primary_field_name,
-                                                 field_list, NULL, &table_id );
-        if( def->primary_field == -1 )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                     "Unrecognised primary field %s in JOIN clause..", 
-                     def->primary_field_name );
+        if( def->poExpr->Check( field_list, TRUE, TRUE, poCustomFuncRegistrar ) == SWQ_ERROR )
             return CE_Failure;
-        }
-        
-        if( table_id != 0 )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined,
-                     "Currently the primary key must come from the primary table in\n"
-                     "JOIN, %s is not from the primary table.",
-                     def->primary_field_name );
+        if( !CheckCompatibleJoinExpr( def->poExpr, def->secondary_table, field_list ) )
             return CE_Failure;
-        }
-        
-        /* identify secondary field */
-        def->secondary_field = swq_identify_field( def->secondary_field_name,
-                                                   field_list, NULL,&table_id);
-        if( def->secondary_field == -1 )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                     "Unrecognised secondary field %s in JOIN clause..", 
-                     def->secondary_field_name );
-            return CE_Failure;
-        }
-        
-        if( table_id != def->secondary_table )
-        {
-            CPLError( CE_Failure, CPLE_AppDefined, 
-                     "Currently the secondary key must come from the secondary table\n"
-                     "listed in the JOIN.  %s is not from table %s..",
-                     def->secondary_field_name,
-                     table_defs[def->secondary_table].table_name);
-            return CE_Failure;
-        }
     }
 
 /* -------------------------------------------------------------------- */
@@ -1033,13 +1190,14 @@ CPLErr swq_select::parse( swq_field_list *field_list,
 
         /* identify field */
         swq_field_type field_type;
-        def->field_index = swq_identify_field( def->field_name, field_list,
+        def->field_index = swq_identify_field( def->table_name,
+                                               def->field_name, field_list,
                                                &field_type, &(def->table_index) );
         if( def->field_index == -1 )
         {
             CPLError( CE_Failure, CPLE_AppDefined, 
                       "Unrecognised field name %s in ORDER BY.", 
-                     def->field_name );
+                      def->table_name[0] ? CPLSPrintf("%s.%s", def->table_name, def->field_name) : def->field_name );
             return CE_Failure;
         }
 
@@ -1064,8 +1222,11 @@ CPLErr swq_select::parse( swq_field_list *field_list,
 /*      Post process the where clause, subbing in field indexes and     */
 /*      doing final validation.                                         */
 /* -------------------------------------------------------------------- */
+    int bAllowFieldsInSecondaryTablesInWhere = FALSE;
+    if( poParseOptions != NULL )
+        bAllowFieldsInSecondaryTablesInWhere = poParseOptions->bAllowFieldsInSecondaryTablesInWhere;
     if( where_expr != NULL 
-        && where_expr->Check( field_list, FALSE ) == SWQ_ERROR )
+        && where_expr->Check( field_list, bAllowFieldsInSecondaryTablesInWhere, FALSE, poCustomFuncRegistrar ) == SWQ_ERROR )
     {
         return CE_Failure;
     }
diff --git a/ogr/wcts/GNUmakefile b/ogr/wcts/GNUmakefile
deleted file mode 100644
index 60259f6..0000000
--- a/ogr/wcts/GNUmakefile
+++ /dev/null
@@ -1,29 +0,0 @@
-
-CURL_LIB = -lcurl
-#OTHER_OPTS :=	$(OTHER_OPTS) -DHAVE_CURL
-
-OTHER_OPTS :=	$(OTHER_OPTS) -DDISABLE_USER_DEFINED_CRS
-
-include ../../GDALmake.opt
-
-CPPFLAGS	+=	-I../ogrsf_frmts -I.. $(OTHER_OPTS)
-
-WCTS_OBJ	=	ogrwcts.o
-C_WCTS_OBJ	=	wctsclient.o
-
-BIN	=	ogrwcts
-C_BIN	=	wctsclient
-
-default:	$(BIN)
-
-all:	default $(C_BIN)
-
-clean:
-	rm -f *.o $(BIN) $(C_BIN)
-
-$(BIN):	$(WCTS_OBJ)
-	$(LD) $(LNK_FLAGS) $(WCTS_OBJ) $(CONFIG_LIBS) $(CURL_LIB) -o $(BIN)
-
-$(C_BIN):	$(C_WCTS_OBJ)
-	$(LD) $(LNK_FLAGS) $(C_WCTS_OBJ) $(CONFIG_LIBS) $(CURL_LIB) \
-		-o $(C_BIN)
diff --git a/ogr/wcts/html/client.html b/ogr/wcts/html/client.html
deleted file mode 100644
index ce6b6a9..0000000
--- a/ogr/wcts/html/client.html
+++ /dev/null
@@ -1,212 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
-<head>
-<title>OGR WCTS Interactive Form</title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-<link href="popup.css" rel="stylesheet" type="text/css">
-<style type="text/css">
-<!--
-.bigTitle {
-  font-family: Arial, Helvetica, sans-serif;
-  font-size: 18px;
-  font-weight: bold;
-}
--->
-</style>
-
-<script name="javascript">
-
-function setAction(action)
-{
-  if(action == "TransformPoint")
-	{
-    document.forms[0].Request.value="Transform";
-    document.forms[0].GMLDATA.value="";
-    document.forms[0].GMLURL.value="";
-	}
-  else
-  {
-	  document.forms[0].Request.value=action;
-	}
-	document.forms[0].submit();
-}
-
-</script>
-
-</head>
-
-<body>
-<form action="http://maps.gdal.org/cgi-bin/wctsclient" method="post">
-
-<input name="Request" type="hidden" value="">
-
-<table width="600" border="0" cellpadding="1" cellspacing="10">
-  <tr>
-    <td width="140"> </td>
-    <td width="430"><p class="bigTitle">OGR WCTS - <br>
-      Web Coordinate Transformation Service</p>
-    <p class="text">The Web Coordinate Transformation Service enables the transformation<br>
-    of geometries between different coordinate reference systems (CRS).</p>
-    <p class="text"> </p></td>
-  </tr>
-  <tr>
-    <td valign="top"> </td>
-    <td class="layoutTable">
-      <table class="titleArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td><a name="top"></a><span class="title">WCTS Server</span></td>
-        </tr>
-      </table>
-      <table class="contentArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td align="center"><p class="helpArea">Provide the WCTS server.</p>
-          </td>
-        </tr>
-      </table>
-      <table class="contentArea" border="0" cellspacing="0" cellpadding="4" width="100%">
-        <tr>
-          <td width="15%" valign="top"><p class="text"><strong>Server</strong></p>
-          </td>
-          <td width="85%"><input name="WCTSServer" type="text" value="http://maps.gdal.org/cgi-bin/ogrwcts" size="45">
-            </td>
-        </tr>
-        <tr>
-          <td valign="top"> </td>
-          <td align="right"><input type="button" name="SubmitGetCapabilities" value="GetCapabilities" onClick="setAction('GetCapabilities');"></td>
-        </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td valign="top"> </td>
-    <td class="layoutTable">
-      <table class="titleArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td><a name="crs"></a><span class="title">Coordinate Reference Systems (CRS)</span></td>
-        </tr>
-      </table>
-      <table class="contentArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td align="center"><p class="helpArea">
-            Provide the original and target coordinate reference system (CRS) as EPSG PCS or GCS codes. Some examples are: <br>
-            • 4326: Lat/Long WGS84<br>
-            • 4269: Lat/Long NAD83<br>
-            • 4267: Lat/Long NAD27<br>
-            • 32611: UTM 11 WGS84<br>
-            • 26911: UTM 11 NAD83<br>
-            • 26711: UTM 11 NAD27</p>
-          </td>
-        </tr>
-      </table>
-      <table class="contentArea" border="0" cellspacing="0" cellpadding="4" width="100%">
-        <tr valign="top">
-          <td width="15%"><p class="text"><strong>Source</strong></p></td>
-          <td><span class="text">CRS / Projection</span>
-            <!-- <span class="nnInputWrap">
-            <select class="inputList" name="select">
-              <option class="inputList" selected>EPSG 4326</option>
-            </select>
-            </span>
-            <span class="text">or </span> -->
-              <input class="inputBox" name="SourceCRS" value="4326" type="text" size="15">
-          </td>
-        </tr>
-        <tr valign="top">
-          <td><p class="text"><strong>Target</strong></p>
-          </td>
-          <td><span class="text">CRS / Projection</span>
-            <!-- <span class="nnInputWrap">
-            <select class="inputList" name="select">
-              <option class="inputList" selected>EPSG 4326</option>
-            </select>
-            </span>
-            <span class="text">or </span> -->
-            <input class="inputBox" name="TargetCRS" value="32611" type="text" size="15">
-          </td>
-        </tr>
-        <tr align="right" valign="top">
-          <td colspan="2">            <input type="button" name="SubmitIsTransformable" value="IsTransformable" onClick="setAction('IsTransformable');">
-            <input type="button" name="SubmitDescribeTransformation" value="DescribeTransformation" onClick="setAction('DescribeTransformation');">
-            </td>
-          </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td valign="top"> </td>
-    <td class="layoutTable">
-      <table class="titleArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td><a name="point"></a><span class="title">Point / Location</span></td>
-        </tr>
-      </table>
-      <table class="contentArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td align="center"><p class="helpArea">
-            Provide the X and Y coordinates for the point / location in decimal degrees. An example is: -117 44</p>
-          </td>
-        </tr>
-      </table>
-      <table class="contentArea" border="0" cellspacing="0" cellpadding="4" width="100%">
-        <tr valign="top">
-          <td width="15%"><p class="text"><strong>Source</strong></p></td>
-          <td width="35%" align="right"><span class="text">X / Longitude / Easting</span></td>
-          <td width="50%"><input name="InputX" type="text" class="inputBox" value="-75" size="20"></td>
-        </tr>
-        <tr valign="top">
-          <td> </td>
-          <td align="right"><span class="text">Y / Latitude / Northing</span></td>
-          <td><input name="InputY" type="text" class="inputBox" value="49" size="20"></td>
-        </tr>
-        <tr valign="top">
-          <td> </td>
-          <td align="right"> </td>
-          <td align="right"><input type="button" name="SubmitPointTransform" value="Transform" onClick="setAction('TransformPoint');"></td>
-        </tr>
-      </table>
-    </td>
-  </tr>
-  <tr>
-    <td valign="top"> </td>
-    <td class="layoutTable">
-      <table class="titleArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td><a name="gml"></a><span class="title">GML Dataset</span></td>
-        </tr>
-      </table>
-      <table class="contentArea" width="100%" border="0" cellpadding="4" cellspacing="0">
-        <tr>
-          <td align="center">
-            <p class="helpArea">Provide a URL to the GML dataset, or paste the GML directly into the textbox.</p>
-          </td>
-        </tr>
-      </table>
-      <table class="contentArea" border="0" cellspacing="0" cellpadding="4" width="100%">
-        <tr valign="top">
-          <td width="15%"><p class="text"><strong>Source</strong></p></td>
-          <td width="85%"><span class="text">URL:</span>
-            <input class="inputBox" name="GMLURL" type="text" size="40">
-          </td>
-        </tr>
-        <!-- <tr valign="top">
-          <td> </td>
-          <td><input name="file" type="file" size="35"></td>
-        </tr> -->
-        <tr valign="top">
-          <td> </td>
-          <td><span class="text">GML:</span>
-            <textarea name="GMLDATA" cols="60" rows="10" class="inputBox"></textarea>
-          </td>
-        </tr>
-        <tr valign="top">
-          <td> </td>
-          <td align="right"><input type="button" name="SubmitPointTransform" value="Transform" onClick="setAction('Transform');">
-          </td>
-        </tr>
-      </table>
-    </td>
-  </tr>
-</table>
-</form>
-</body>
-</html>
diff --git a/ogr/wcts/html/imp_details.html b/ogr/wcts/html/imp_details.html
deleted file mode 100644
index c0b9923..0000000
--- a/ogr/wcts/html/imp_details.html
+++ /dev/null
@@ -1,249 +0,0 @@
-<html>
-<head>
-<title>OGR WCTS Implementation Details</title>
-</head>
-
-<body>
-<h1>OGR WCTS Implementation Details</h1>
-
-<h2>Methods Implemented</h2>
-
-The OGR WCTS server implements the <b>GetCapabilities</b>, 
-<b>IsTransformable</b> and <b>Transform</b> server options (REQUEST= values).
-In all operation cases only VERSION 0.1.0 is currently supported.<p>
-
-<h3>GetCapabilities</h3>
-
-The <b>GetCapabilities</b> operation is supported as an XML request 
-submitted using the HTTP POST mechanism, or as a key/value pair request
-submitted using the HTTP GET mechanism.<p>
-
-The returned capabilities
-document is taken from static document provided by the installer, it
-is not actually machine generated at all.  In particular the list of
-supported coordinate systems is not machine generated.<p>
-
-<h3>IsTransformable</h3>
-
-The <b>IsTransformable</b> operation is supported as an XML request 
-submitted using the HTTP POST mechanism, or as a key/value pair request
-submitted using the HTTP GET mechanism.<p>
-
-The geometric primite type, 
-coverage type, and coverage interpolation method parameters are currently
-ignored. <p>
-
-<h3>Transform</h3>
-
-The <b>Transform</b> operation is only supported as an XML request submitted
-using the HTTP POST mechanism.<p>
-
-It is apparently legal to submit key/value
-pair requests with remotely referred to, or url encoded GML data but there
-are no examples of how this would be done so it has not been implemented at
-this time.<p>
-
-The transformation sequence (gml:_CoordinateOperation) argument is
-unsupported and ignored.<p>
-
-The data argument may be a GML instance document, or a FileURL
-referencing a remote document which may be fetched using HTTP GET.  
-It may not be a wcts:RemoteOWS element for doing operations against
-a remote WFS instance.  How this actually works is not currently well
-defined in the WCTS document. <p>
-
-<h3>DescribeTransformation</h3>
-
-The <b>DescribeTransformation</b> operation is not supported by the
-server at all at this time.<p>
-
-<h2>Coordinate Systems Supported</h2>
-
-Currently the server supports all EPSG 6.2.2 2D geographic coordinate systems
-and projected coordinate systems based on supported projections.<p>
-
-Converting between different datums is
-only supported for some coordinate systems for which a single 3 or 7
-parameter datum transformation to WGS84 exists in the EPSG database.  Other
-datums for which multiple transformations 3 or 7 parameter transformations are
-defined, or for which no such transformations are available are not able
-to be converted to other datums.  One exception is NAD27 and NAD83.  NAD83 is
-considered equivelent to WGS84.  NAD27 is handled specially using grid
-shift files for the area of Canada and the United States (either NTv2, NTv1,
-or NADCON grid shift information is used depending on the location being 
-transformed, and the configuration of the server.<p>
-
-Coordinate systems based on datum that cannot be related to WGS84 can still
-be trasformed to other coordinate systems based on the same datum.<P>
-
-<h3>Supported EPSG projections</h3>
-
-<table border>
-<th>EPSG Code<th>Name<th>Comments<tr>
-<td>9801<td>Lambert Conic Conformal (1SP)
-<td><tr><td>9802<td>Lambert Conic Conformal (2SP)
-<td><tr><td>9803<td>Lambert Conic Conformal (2SP Belgium) <td>(treated same as 9802)
-<tr><td>9804<td>Mercator (1SP)
-<td><tr><td>9805<td>Mercator (2SP)
-<td><tr><td>9806<td>Cassini-Soldner
-<td><tr><td>9807<td>Transverse Mercator
-<td><tr><td>9809<td>Oblique Stereographic
-<td><tr><td>9810<td>Polar Stereographic
-<td><tr><td>9811<td>New Zealand Map Grid
-<td><tr><td>9812<td>Hotine Oblique Mercator
-<td><tr><td>9813<td>Laborde Oblique Mercator<td>(treated same as 9813)
-<tr><td>9815<td>Oblique Mercator
-<td><tr><td>9819<td>Krovak Oblique Conic Conformal
-<td><tr><td>9820<td>Lambert Azimuthal Equal Area
-<td><tr><td>9822<td>Albers Equal Area
-<td><tr><td>9823<td>Equidistant Cylindrical
-</table>
-
-<h3>Unsupported EPSG Projections</h3>
-
-<table border>
-<th>EPSG Code<th>Name<th>Comments<tr>
-<td>9808<td>Transverse Mercator (South Orientated)
-<td><tr><td>9814<td>Swiss Oblique Cylindrical
-<td><tr><td>9816<td>Tunisia Mining Grid
-<td><tr><td>9817<td>Lambert Conic Near-Conformal
-<td><tr><td>9818<td>American Polyconic
-<td><tr><td>9821<td>Lambert Azimuthal Equal Area (Spherical)
-<td><tr><td>9824<td>Transverse Mercator Zoned Grid System
-<td><tr><td>9825<td>Pseudo Plate Carree
-<td><tr><td>9826<td>Lambert Conic Conformal (West Orientated)
-<td><tr><td>9827<td>Bonne
-<td><tr><td>9828<td>Bonne (South Orientated)
-</table>
-
-<h2>User Defined CRSes</h2>
-
-The server has prototype support for coordinate systems described using the
-pre-approval 03-010r2 GML CRS schemas.  Details of this implementation are
-evolving.  Contact the author for sample requests that work at this time.<p>
-
-<h2>Implementation Strategy</h2>
-
-This section is intended to explain a bit about how the internals of this
-server are implemented to better understand likely strengths and weaknesses
-of the server.<p>
-
-<ol>
-<li> All XML handling is done using the <b>CPL MiniXML</b> parser.  This is
-a simple well formed XML parser but it does not treat the whole XML standard
-properly.  It is likely to fail dramatically if given files in other than 
-8bit codes spaces (ie. UTF-8), and there may well be esoteric XML 
-constructions that will not be parsed properly by it. <p>
-
-<li> In order to transform GML geometries, the server walks the <data>
-subtree searching for elements recognisable as GML geometries.  The rules
-to recognise GML geometries are basically to strip any namespace value off
-an element name, and compare to the simple feature GML elements (such as
-<b>Polygon, LineString, Point, Box, GeometryCollection, MultiPoint, 
-MultiLineString </b> or <b>MultiPolygon</b>.  Problems may be encountered
-if non-geometries (marked as being from non-gml names spaces) are incorrectly
-identified as being geometries.  Alternate names for geometries (established
-by derivation in application schemas) are not supported.<p>
-
-A good aspect of the above approach is that there is no need to understand
-the application schema of the gml features passed to the server.<p>
-
-<li> Once recognised GML geometry elements are transformed into OGRGeometry's,
-transformed, and converted back into GML to substitute "inplace" in the file.
-This process will drop any attributes of the geometries, such as srsName, and
-will produce new gml with the gml: namespace prefix regardless of what
-namespace may have been in place originally.  Resulting geometries are
-converted back to GML using a %.16g C format string preserving double 
-precision accuracy, but potentially implying far more precision that is
-meaningful depending on the precision of the original points.<p>
-
-<li> When the <FileURL> data item is found, the URL is resolved and
-the resulting document is substituted in the place of the original FileURL
-in the transformation request.  At this point a special step is done to
-try and remove any <?xml> line to avoid confusing the XML/GML parsing.
-However, other constructions, such as a DOCTYPE declaration might well foul
-things up.<p>
-
-<li> Currently SourceCRS and TargetCRS definitions are supported well supported
-by <crsID> as well as a more limited form of user defined coordinate
-system.  The user defined coordinate system support is experimental and will
-not be further discussed here for now.<p>
-
-Those defined via <crsID> will be inspected for a code, and codeSpace
-element.  The codeSpace must be EPSG, and the code will be lookuped up in the
-EPSG 6.2.2 .csv files using the OGRSpatialReference:ImportFromEPSG() method.
-<p>
-
-<li> Internally all coordinate transformations are accomplished using the
-OGRCoordinateTransformation class which in turns converts the coordinate
-system definitions into PROJ.4 format, and uses the PROJ.4 pj_transform()
-function to transform the points.  This supports reprojection, change of
-ellipsoid, change of datum (sometimes), and change of prime meridian.<P>
-
-</ol>
-
-<h2><a name="audit">OGR WCTS Security Audit</a></h2>
-
-A security audit of the OGR WCTS server was completed on 2003/03/29.  In
-addition to a careful inspection of the code in the ogrwcts.cpp module, the
-following components were also addressed:
-<P>
-
-<ol>
-<li> libcurl (not checked) - all URLs other than http, https and ftp have
-been disabled to avoid issues with less known protocols.
-<li> CPLTokenize() support for parsing QUERY_STRING.  (checked)
-<li> OGR GML Geometry reading and writing services. (checked)
-<li> OGR GML CRS reading and writing services.  (not checked)
-<li> cpl_minixml.cpp parsing and serializing services (checked)
-<li> cpl_string escaping logic, and stringlist handling (checked)
-</ol>
-
-The conclusion is that the <b>ogrwcts</b> is safe for use where
-it may potentially be given input by hostile parties as long as user defined
-CRS support is disabled.  The user defined CRS code is in flux, so any audit 
-will be rapidly outdated.  Disabling user defined CRSes may be accomplished by 
-compiling with DISABLE_USER_DEFINED_CRS defined in the GNUmakefile (the 
-default).<p>
-
-This security audit was primarily directed to discovering buffer overrun 
-issues possible with user input.  Several isses were discovered and corrected
-though it isn't clear if they could have been externally utilized to
-gain control as each of them related only to buffer overruns within the 
-heap (not on the stack).<p>
-
-A review of the overall architectural approach of the server identified only
-the issue with use of libcurl to access user supplied URLs.  With this disabled
-no vulnerability remains.<p>
-
-The initial security audit was completed by Frank Warmerdam.  An independent
-audit is underway by Andrey Kiselev.<p>
-
-<h2>Other Notes</h2>
-
-<ol>
-<li> The server does not do any schema validation, but does require input
-XML documents to be well formed. <p>
-
-<li> Input SourceCRS and TargetCRS elements must have a <b>crsID</b> 
-element with a <b>gml:code</b> that is the EPSG code of the coordinate
-system, and a <b>gml:codeSpace</b> that is <b>EPSG</b>.<p>
-
-<li> Version and Service parameters are never checked.<p>
-
-<li> The server handles bounding box (boundedBy properties in GML) specially.
-It transforms the box into a polygon, transforms that and then regenerates
-a box based on the mimimum bounding box of that polygon.  While better than
-just transforming the two corner coordinates of the bounding box, it is not
-generally going to produce a minimal bounding box for the features in question
-in the target coordinate systems.  In fact, depending on the nature of
-the transformation (bowing out of a side for instance) the resulting box
-may not even quite contain all the transformed feature.<p>
-
-<li> The current GML geometry handling in OGR does not support tuple 
-separators other than " " or ordinate separators other than ",".<p>
-
-</ol>
-
-</body>
-</html>
diff --git a/ogr/wcts/html/index.html b/ogr/wcts/html/index.html
deleted file mode 100644
index c383375..0000000
--- a/ogr/wcts/html/index.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<html>
-<head>
-<title>OGR WCTS Implementation</title>
-</head>
-<body>
-
-<h1>OGR WCTS Implementation</h1>				
-
-As a part of a project to implement a Coordinate Transformations Server for
-<a href="http://www.dmsolutions.ca/">DM Solutions Group</a> I am implementing
-a WCTS (Web Coordinate Transformation Server) attempting to conform to the
-OpenGIS internal discussion paper 02-061r2.  This paper can be found in 
-the OpenGIS internal documents are for 
-<a href="http://www.opengis.org/">OpenGIS</a> members.<p>
-
-Note that this is not yet a specification, it is a proposal that might be
-adopted as a specification at some point, likely after further changes.  Thus
-<i>WCTS</i> is a protocol in flux.<p>
-
-This implementation is based on the <a href="http://www.gdal.org/ogr/classOGRSpatialReference.html">OGRSpatialReference</a> class
-within the <a href="http://www.gdal.org/">GDAL/OGR</a> library.
-The underlying projections engine is 
-<a href="http://www.remotesensing.org/proj">PROJ.4</a>, and the GML support
-from <a href="http://www.gdal.org/ogr">OGR</a> is used.<p>
-
-The code implementing the server can be found in the GDAL/OGR CVS tree
-in the gdal/ogr/wcts directory, along with some sample request documents.
-Currently all the server specific code is in the 
-<a href="http://www.gdal.org/srctree/ogr/wcts/ogrwcts.cpp">
-ogrwcts.cpp</a> file in this directory.<p>
-
-Some <a href="imp_details.html">Implementation Details</a> on features and
-limitations of the server are available.  There is also an 
-<a href="install.html">Installation and Configuration</a> document.<P>
-
-Some sample XML input requests are available for the following requests:<p>
-<ul>
-<li> <a href="http://www.gdal.org/srctree/ogr/wcts/req_getcap.xml">GetCapabilities</a><p>
-<li> <a href="http://www.gdal.org/srctree/ogr/wcts/req_istransformable.xml">IsTransformable</a><p>
-<li> <a href="http://www.gdal.org/srctree/ogr/wcts/req_transform.xml">Transform</a><p>
-<li> <a href="http://www.gdal.org/srctree/ogr/wcts/req_remote.xml">Transform using FileURL</a><p>
-</ul>
-
-A development server is running at http://maps.gdal.org/cgi-bin/ogrwcts.  Some
-sample KVP encoded requests are:<p>
-
-<ul>
-<li> <a href="http://maps.gdal.org/cgi-bin/ogrwcts?REQUEST=GetCapabilities">
-http://maps.gdal.org/cgi-bin/ogrwcts?REQUEST=GetCapabilities</a>: Fetch
-the capabilities.<p>
-
-<li> <a href="http://maps.gdal.org/cgi-bin/ogrwcts?REQUEST=IsTransformable&SOURCECRS=EPSG:4001&TARGETCRS=EPSG:4002">http://maps.gdal.org/cgi-bin/ogrwcts?REQUEST=IsTransformable&SOURCECRS=EPSG:4001&TARGETCRS=EPSG:4002</a>: Test
-if EPSG:4001 can be transformed to EPSG:4002.<p>
-
-</ul>
-
-Note that WCTS does not support KVP (including the arguments in the URL) usage
-for the actual transformation operations, so you need something that can
-PUT the XML request data to utilize the transform operator.<p>
-
-An <a href="client.html">HTML form</a>
-based client (backed by a cgi-bin program) has been implemented
-for user interface to WCTS services and testing.<p>
-
-<h2>Other WCTS Implementations</h2>
-
-Currently there is only one other WCTS implementation in existance.  That
-is the one done by <a href="http://www.lat-lon.de">lat/lon</a>, the folks
-that write the WCTS document.  That implementation is also open source, and
-can be found within the <a href="http://www.deegree.org">deegree</a> project.
-<p>
-
-A user form for interacting with an instance of the deegree based server
-is <a href="http://www.lat-lon.de/projekte_en.html#coord">available at lat/lon
-</a>.<p>
-
-</BODY>
-</html>
diff --git a/ogr/wcts/html/install.html b/ogr/wcts/html/install.html
deleted file mode 100644
index 0f53a71..0000000
--- a/ogr/wcts/html/install.html
+++ /dev/null
@@ -1,236 +0,0 @@
-<html>
-<head>
-<title>Installing and Configuring OGR WCTS</title>
-</head>
-
-<body>
-
-<h1>Installing and Configuring OGR WCTS</h1>
-
-The OGR WCTS server is currently implemented as a C++ cgi-bin style web
-service.  It should be useable with any web server that supports passing
-on arguments via QUERY_STRING and posted input via stdin.<p>
-
-<h2>Build and Install PROJ.4</h2>
-
-The OGR WCTS server depends on PROJ.4 for doing the actual transformations.
-It is therefore necessary to build and install PROJ.4, preferrably before
-building and installing GDAL.  Download the latest source release from
-<a href="http://www.remotesensing.org/proj">http://www.remotesensing.org/proj
-</a>.  Ensure you get PROJ 4.4.7 or later if NTv2 datum shifting support
-is required.<p>
-
-If US grid based NAD27 datum shifting is required for North America, it is
-imperative to unpack the the datum shift files "on" the PROJ.4 source
-tree before configuring, building and installing.<p>
-
-<pre>
-% tar xzvf proj-4.4.7.tar.gz
-% cd proj-4.4.7/nad
-% tar xzvf ../../proj-nad27-1.1.tar.gz
-% cd ..
-% ./configure
-% make
-% su
-Password: *******
-$ make install
-$ exit
-</pre>
-
-If NTv2 support is desired, download the NTv2 data file from the
-<a href="http://www.geod.emr.ca/index_e/products_e/software_e/ntv2_e.html">
-Natural Resources Canada</a> web site, and copy it to 
-/usr/local/share/proj.  This can be safely done after PROJ.4 is installed.
-The file is platform independent (unlike the binary files built for
-the US grid shift files).  Please ensure the file is installed with the
-filename in lower case.<p>
-
-<pre>
-$ cp NTV2_0.GSB /usr/local/share/proj/ntv2_0.gsb
-</pre>
-
-<h2>Build and Install GDAL</h2>
-
-Currently a build mechanism only exists for Unix, and the WCTS server is
-not built and installed as a standard part of GDAL/OGR.  However it does
-<i>live</i> in the GDAL/OGR source tree in the ogr/wcts directory.  The
-source (such as a nightly CVS snapshot) can be downloaded from the 
-<a href="http://www.remotesensing.org/gdal">GDAL/OGR web site</a>.<P>
-
-Once unpacked, build GDAL/OGR according to the <a href=
-"http://www.remotesensing.org/gdal/gdal_building.html">provided 
-instructions</a>, and then install.<P>
-
-<pre>
-% cd gdal
-% ./configure
-...
-% make
-% su 
-Password: ********
-$ make install
-$ exit
-</pre>
-
-<h2>Build and Install OGR WCTS Server</h2>
-
-Next, build the WCTS server itself.  It is found in ogr/wcts.
-If you wish the ability to fetch remote GML files, ensure that 
-<a href="http://curl.haxx.se/libcurl/c">libcurl</a> is installed, and
-uncomment the CURL_LIB and CURL_DEF lines in the GNUmakefile.  Ensure
-that the CURL_LIB is defined appropriately to find libcurl on your system.<p>
-Then build the server.<p>
-
-<pre>
-% cd ogr/wcts
-% make 
-</pre>
-
-The server (ogrwcts) is a simple executable that depends on libgdal.1.1, and
-potentially on libcurl.  It would normally be copied directly into your
-web server cgi-bin directory.<p>
-
-<pre>
-% cp ogrwcts /u/apache/cgi-bin
-</pre>
-
-If you want the HTML form based WCTS client (demonstrated at
-<a href="http://maps.gdal.org/wcts/client.html">
-http://maps.gdal.org/wcts/client.html</a> to have a local cgi-bin 
-server, you should also build the <b>wctsclient</b> application.<p>
-
-<pre>
-% make all
-% cp wctsclient /u/apache/cgi-bin
-</pre>
-
-<h2>GetCapabilities</h2>
-
-The server needs to be able to respond to a <b>GetCapabilities</b> request. 
-The response document is actually created statically ahead of time.  There
-is a provided sample in the ogr/wcts directory called 
-wcts_capabilities.xml.0.1.0.  It should generally be updated depending on
-the nature of the service being setup.  In particular, the ContactInformation
-should be updated to refer to whoever is setting up the service.  Also, all
-the service URLs all need to be updated to reflect the url for the service
-as it is being installed.  Change each occurance of 
-"http://maps.gdal.org/cgi-bin/ogrwcts?to the appropriate value. <p>
-
-<pre>
-% vi wcts_capabilities.xml.0.1.0
-% cp wcts_capabilities.xml.0.1.0 /usr/local/share/gdal
-</pre>
-
-Next this modified document (with the name unchanged) needs to be placed some
-where it can be found by the server.  The ideal location is the 
-/usr/local/share/gdal directory since it is already in the "data file search
-path".  If it is placed elsewhere, the -data switch to ogrwcts will need to 
-be used to point to the directory.  Note, all aspects of the server other
-than the <b>GetCapabilities</b> request will work fine even without the
-capabilities document.<p>
-
-<h2>Commandline Testing of Server</h2>
-
-Before trying under the web server, it may be helpful to test the WCTS
-server as a commandline program.  Some sample requests are available in
-the wcts build directory, and can be used like this:
-
-<pre>
-% cd ogr/wcts
-% ./ogrwcts -put < req_getcap.xml
-% ./ogrwcts -put < req_istransformable.xml
-% ./ogrwcts -put < req_transform.xml
-</pre>
-
-<h2>Web Server Setup</h2>
-
-It is assumed that the web server is already setup to allow cgi-bin
-programs to be executed in the directory you installed the ogrwcts executable.
-If not, correct this.<P>
-
-It is also necessary for the ogrwcts program to be able to load the shared
-libraries it depends on.  In a default install under /usr/local, this might
-involved adding the directive "SetEnv LD_LIBRARY_PATH /usr/local/lib" in 
-an Apache configuration file, or utilizing ldconfig to ensure that 
-libgdal.1.1.so, and libproj.so will be found when ogrwcts is started.<p>
-
-It is also necessary that directories with the supporting data files
-used by ogrwcts be readable by the user that cgi-bin programs run as
-(often "nobody").  In a default install the directories in question are
-/usr/local/share/gdal and /usr/local/share/proj.   Usually these locations
-will be world readable by default.<p>
-
-<h2>Debugging</h2>
-
-If the server isn't working there are a few strategies to debugging problems.
-<P>
-
-<ol>
-<li> Most errors will result in an XML exception document being returned. 
-If so, it should contain some indication of what went wrong.<p>
-<li> Ensure that ogrwcts works standalone (see Commandline Testing of Server
-above). 
-<li> Check the error log for the web server and check for messages there.
-Common problems would be web server permissions problems for the cgi-bin or
-failure to load the shared libraries. <p>
-<li> Run the server with full debugging turned on.  This can be accomplished
-by passing the <b>-debug</b> commandline switch.  This will various debugging
-information from GDAL/OGR, and PROJ.4 to be logged in the error file, 
-including details of what grids are being used for datum shifting.<P>
-</ol>
-
-If all the above have been exausted, bugs with OGR WCTS 
-<a href="http://bugzilla.remotesensing.org/enter_bug.cgi?product=GDAL&component=OGR_SRS">may be reported</a> via the GDAL/OGR Bugzilla.<p>
-
-<h2>Installing in Non-Default Locations</h2>
-
-It is often desirable to install GDAL, and PROJ.4 in a non-default location
-in order to better control software configurations.  This can be accomplished
-by using the <i>--prefix</i> flag when configuring them. For example:<p>
-
-<pre>
-% ./configure --prefix=/opt
-</pre>
-
-This mechanism can be used while configuring both GDAL and PROJ.4 (and
-presumably libcurl).  Appropriate adjustements to the LD_LIBRARY_PATH or
-ldconfig settings would be required to find support libraries in 
-${prefix}/lib.  Default path to files supporting GDAL, and PROJ.4 are 
-established during their builds (based on the configure --prefix setting), 
-so these components should be able to find their supporting data files as
-long as everything is built and installed consistently.<p>
-
-Sometimes it is also desirable to force the <b>ogrwcts</b> cgi-bin to use
-particular versions of local files.  This is normally accomplished by
-using a shell script as the target cgi-bin, and having that script run
-ogrwcts with appropriate override commandline switches and environment 
-variables.<p>
-
-The <b>PROJ_LIB</b> environment variable can be set to point to an alternate
-location to find supporting datum shift files for PROJ.4.  They are
-normally kept in /usr/local/share/proj.<p>
-
-The <b>GDAL_DATA</b> environment variable may be used to set an alternate
-source for the .csv files used to translate EPSG CRS numbers into 
-detailed definitions.   They are normally kept in /usr/local/share/gdal.<p>
-
-The <b>-data</b> <i>directory</i> commandline switch to <b>ogrwcts</b> may
-be used to designate an alternate search directory for GDAL .csv files, and
-the capabilities document.<p>
-
-This is an example of a script that might be to override selected environment 
-variables before running the real ogrwcts binary.<p>
-
-<pre>
-#! /bin/sh
-
-LD_LIBRARY_PATH=/home/warmerda/gdal:/usr/local/lib
-export LD_LIBRARY_PATH
-PROJ_LIB=/usr2/cgi-bin/wcts-proj-lib
-export PROJ_LIB
-/home/warmerda/gdal/ogr/wcts/ogrwcts $*
-exit 0
-</pre>
-
-</body>
-</html>
diff --git a/ogr/wcts/html/popup.css b/ogr/wcts/html/popup.css
deleted file mode 100644
index ad0d14c..0000000
--- a/ogr/wcts/html/popup.css
+++ /dev/null
@@ -1,177 +0,0 @@
-.page
-/* Defines the page style.
-   - Basic usage sets the background colour. */
-{
-	background-color: #ffffff;
-}
-
-.layoutTable
-/* Defines the style of the main layout table.
-   - Basic usage sets the background colour, which acts as an outline.
-	 - Every popup must use a table with 1 column and as many rows as are 
-	   needed for the popup. Basic popups with an OK or CANCEL button would 
-	   use a layout table with 2 rows, while more advanced popups like the 
-	   SEARCH popup use 3 rows, one for the search, one for the results, 
-	   and one for the OK, CANCEL buttons */
-{
-	background-color: #666666;
-}
-
-.titleArea
-/* Defines the style for the title table.
-   - Every popup has a title table as the first table within the layout table*/
-{
-	background-color: #BBBBBB;
-}
-
-.title
-/* Defines the style for the title text.
-   - Every popup has a title this sets the font, size, colour etc.*/
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 15px;
-	font-weight: bold;
-	color: #000000;
-	vertical-align: middle;
-	text-align: left;
-}
-
-.contentArea
-/* Defines the style of content layout tables.
-   - Basic usage sets the background colour of the content areas.
-	 - Every popup must use at least 1 content layout table, but often use 2,
-	   one for the help text, and one to layout the popup's input elements.
-	 - For best results this table should have cellspacing="0" otherwise the 
-	   colour of the page or layoutTable will show through. */
-{
-	background-color: #E9E9E9;
-}
-
-.subLayoutTable
-/* Defines the style of secondary (nested) layout tables.
-   - Basic usage sets the background colour, which acts as an outline;
-	   similar in usage to layoutTable.
-	 - This allows for more advanced designs like the layer browser dialogue. */
-{
-	background-color: #666666;
-}
-
-.subContentArea1
-/* Defines the style of tables or cells in secondary layout tables.
-   - Basic usage sets the background colour of a sub content areas.
-	 - This allows for more advanced designs and is intended to be used
-	   with subLayoutTable (either styling cells, or nested-tables). */
-{
-	background-color: #ffffff;
-}
-
-.subContentArea2
-/* Defines an alternate style of tables or cells in secondary layout tables.
-   - Used in the same way as subContentArea1. */
-{
-	background-color: #e3f0f0;
-}
-
-.helpArea
-/* Defines the style of the help area.
-   - Basic useage sets the styling of the <p> that surrounds the help text. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 12px;
-	color: #666666;
-	background-color: #FFFFFF;
-	border: 1px solid #666666;
-	width: 400px;
-	text-align: left;
-}
-
-.label
-/* Defines the style of text labels.
-   - Basic useage sets the size, colour and font of any labels of input
-	   elements. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 12px;
-	color: #000000;
-}
-
-.note
-/* Defines the style of text notes.
-   - Basic useage sets the size, colour and font of any small notes
-	   Also used in the legend for small text. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 9px;
-	color: #333333;
-}
-
-.text
-/* Defines the style of text blocks.
-   - Basic useage sets the size, colour and font of <p>, <span> or 
-	   <div> tags. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 13px;
-	color: #000000;
-}
-
-.list
-/* Defines the style of ordered and unordered lists.
-   - Basic useage sets the size, colour and font of any <ul>, <ol> tag. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-}
-
-.listItem
-/* Defines the style of list items.
-   - Basic useage sets the size, colour and font of any <li> tag.
-	   Normally would be the same as list, but more advanced techniques
-		 can be used as well.*/
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-}
-
-.inputBox
-/* Defines the style of text input elements.
-   - Basic useage sets the font and size of any input elements' text.
-	 - More advanced useage sets the styling of the input area as well. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-	background-color: #FFFFFF;
-}
-
-.inputList
-/* Defines the style of list input elements.
-   - Basic useage sets the font and size of any input elements' text.
-	 - More advanced useage sets the styling of the input area as well. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-	background-color: #FFFFFF;
-}
-
-.nnInputWrap
-/* Workaround to define the style of input elements for nn4.x.
-   - Sets the font and size of input elements' text. */
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-}
-
-/* .inputBox
-{
-	font-family: Arial, Helvetica, sans-serif;
-	font-size: 11px;
-	color: #000000;
-	background-color: #FFFFFF;
-	padding: 3px;
-	border: 1px solid #666666;
-} */
diff --git a/ogr/wcts/html/user_form.html b/ogr/wcts/html/user_form.html
deleted file mode 100644
index b2ca7d4..0000000
--- a/ogr/wcts/html/user_form.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<html>
-<head>
-<title>OGR WCTS Interactive Form</title>
-</head>
-<body>
-
-<h1>OGR WCTS Interactive Form</h1>
-
-<form action="http://maps.gdal.org/cgi-bin/wctsclient" method="POST">
-
-Action: 
-<select name="Request">
-<option>Transform</option>
-<option>GetCapabilities</option>
-<option>IsTransformable</option>
-<option>DescribeTransformation</option>
-</select>
-<p>
-
-Enter the source and destination Coordinate Reference Systems (CRS) as
-EPSG PCS or GCS codes.  Some examples are:
-<ul>
-<li> 4326: Lat/Long WGS84
-<li> 4269: Lat/Long NAD83
-<li> 4267: Lat/Long NAD27
-<li> 32611: UTM 11 WGS84
-<li> 26911: UTM 11 NAD83
-<li> 26711: UTM 11 NAD27
-</ul>
-
-Source CRS: <input MAXLENGTH=80 name="SourceCRS" type="text" value="4326"><p>
-Target CRS: <input MAXLENGTH=80 name="TargetCRS" type="text" value="32611"><p>
-
-Input Location (angles in decimal degrees): <br>
-<input MAXLENGTH=20 name="InputX" type="text">Long/Northing<br>
-<input MAXLENGTH=20 name="InputY" type="text">Lat/Easting<p>
-
-or an URL to a GML dataset:<br>
-<input MAXLENGTH=120 name="GMLURL" type="text"><p>
-
-or a whole GML dataset:<br>
-<textarea rows=10 cols=60 wrap="virtual" name="GMLDATA"></textarea><p>
-
-WCTS Server: <input MAXLENGTH=120 name="WCTSServer" type="text"
-value="http://maps.gdal.org/cgi-bin/ogrwcts"><p>
-
-<input type="submit">
-
-</form>
-
-</body>
-</html>
diff --git a/ogr/wcts/makefile.vc b/ogr/wcts/makefile.vc
deleted file mode 100644
index bf65e2b..0000000
--- a/ogr/wcts/makefile.vc
+++ /dev/null
@@ -1,31 +0,0 @@
-
-GDAL_ROOT = 	..\..
-
-WINSOCK_LIB = "WSOCK32.LIB"
-
-LIBS	=	$(GDAL_ROOT)\gdal_i.lib $(CURL_LIB)
-
-XTRAFLAGS =	-I$(GDAL_ROOT)\ogr\ogrsf_frmts $(CURL_INC)
-
-!INCLUDE ..\..\nmake.opt
-
-default:	ogrwcts.exe wctsclient.exe
-
-ogrwcts.exe:	ogrwcts.cpp $(GDALLIB) $(XTRAOBJ) 
-	$(CC) $(CFLAGS) $(XTRAFLAGS) ogrwcts.cpp $(XTRAOBJ) $(LIBS) \
-		/link $(LINKER_FLAGS)
-	
-wctsclient.exe:	wctsclient.cpp $(GDALLIB) $(XTRAOBJ) 
-	$(CC) $(CFLAGS) $(XTRAFLAGS) wctsclient.cpp $(XTRAOBJ) $(LIBS) \
-		/link $(LINKER_FLAGS)
-	
-clean:
-	-del *.obj
-	-del *.exe
-	-del *.pdb
-	-del *.ilk
-	-del *.lib
-
-install:	default
-	copy *.exe $(BINDIR)
-	-copy *.exe.manifest $(BINDIR)
diff --git a/ogr/wcts/ogrwcts.cpp b/ogr/wcts/ogrwcts.cpp
deleted file mode 100644
index 6b9fe2f..0000000
--- a/ogr/wcts/ogrwcts.cpp
+++ /dev/null
@@ -1,1020 +0,0 @@
-/******************************************************************************
- * $Id: ogrwcts.cpp 10645 2007-01-18 02:22:39Z warmerdam $
- *
- * Project:  Web Coordinate Transformation Service
- * Purpose:  cgi-bin mainline for WCTS Implementation
- * Author:   Frank Warmerdam <warmerdam at pobox.com>
- *
- ******************************************************************************
- * Copyright (c) 2003, Frank Warmerdma <warmerdam at pobox.com>
- *
- * 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.
- ******************************************************************************
- *
- * Independent Security Audit 2003/04/17 Andrey Kiselev:
- *   Completed audit of this module and the same required items:
- * 
- *   - CSLTokenizeString*() and other functions from cpl_string.cpp;
- *   - XMP parsing and serializing functions from cpl_minixml.cpp;
- *   - GML Translation modules (gml2ogrgeometr.cpp, ogr2gmlgeometry.cpp);
- *
- * Security Audit 2003/03/29 warmerda:
- *   Completed security audit.  I believe that *this* module may be safely used
- *   to handle arbitrary input.  It also requires the following to be safe:
- *
- *    1) libcurl (not checked), all URLs other than http, https and ftp have
- *       been disabled to avoid issues with less known protocols.
- *    2) CPLTokenize() support for parsing QUERY_STRING.  (checked)
- *    3) OGR GML Geometry reading and writing services. (checked)
- *    4) OGR GML CRS reading and writing services.  (not checked)
- *    5) cpl_minixml.cpp parsing and serializing services (checked)
- *    6) cpl_string escaping logic, and stringlist handling (checked)
- * 
- *   For optimal overall security this server should be run user defined CRS
- *   support as this code is in flux, so any audit will be rapidly outdated.
- *   This may be accomplished by compiling with DISABLE_USER_DEFINED_CRS
- *   defined in the GNUmakefile (the default).
- *
- */
-
-#include <assert.h>
-#include "cpl_minixml.h"
-#include "ogr_api.h"
-#include "ogrsf_frmts.h"
-#include "cpl_conv.h"
-#include "cpl_string.h"
-
-#ifdef HAVE_CURL
-#include <curl/curl.h>
-#endif
-
-CPL_CVSID("$Id: ogrwcts.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-/************************************************************************/
-/*                      WCTSEmitServiceException()                      */
-/************************************************************************/
-
-static void WCTSEmitServiceException( const char *pszMessage )
-
-{
-    /* printf( "Content-type: text/xml%c%c", 10, 10 ); */
-    printf("Content-type: application/vnd.ogc.se_xml%c%c",10,10);
-
-    printf( "<?xml version='1.0' encoding=\"%s\" standalone=\"no\" ?>\n",
-            "ISO-8859-1" );
-
-    printf("<!DOCTYPE ServiceExceptionReport SYSTEM \"http://www.digitalearth.gov/wmt/xml/exception_1_1_0.dtd\">\n");
-
-    printf("<ServiceExceptionReport version=\"1.1.0\">\n");        
-    printf("<ServiceException>\n");
-    printf("%s\n", pszMessage ); /* this should likely be XML escaped */
-    printf("</ServiceException>\n");
-    printf("</ServiceExceptionReport>\n");
-
-    exit( 1 );
-}
-
-/************************************************************************/
-/*                            WCTSWriteFct()                            */
-/*                                                                      */
-/*      Append incoming text to our collection buffer, reallocating     */
-/*      it larger as needed.                                            */
-/************************************************************************/
-
-size_t WCTSWriteFct(void *buffer, size_t size, size_t nmemb, void *reqInfo)
-
-{
-    char **ppszWorkBuffer = (char **) reqInfo;
-    int  nNewSize, nOldSize;
-
-    if( *ppszWorkBuffer == NULL )
-        nOldSize = 0;
-    else
-        nOldSize = strlen(*ppszWorkBuffer);
-
-    nNewSize = nOldSize + nmemb * size + 1;
-
-    *ppszWorkBuffer = (char *) CPLRealloc(*ppszWorkBuffer, nNewSize);
-    strncpy( (*ppszWorkBuffer) + nOldSize, (char *) buffer, 
-             nmemb * size );
-    (*ppszWorkBuffer)[nNewSize-1] = '\0';
-
-    return nmemb;
-}
-
-/************************************************************************/
-/*                           WCTSHTTPFetch()                            */
-/*                                                                      */
-/*      Fetch a document from an url and return in a string.            */
-/************************************************************************/
-
-char *WCTSHTTPFetch( const char *pszURL )
-
-{
-#ifndef HAVE_CURL
-    WCTSEmitServiceException( "Server not compiled with libcurl support, remote requests not supported." );
-    return NULL;
-#else
-    CURL *http_handle;
-    char *pszData = NULL;
-    char szCurlErrBuf[CURL_ERROR_SIZE+1];
-    CURLcode error;
-
-    http_handle = curl_easy_init();
-
-    curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );
-
-    /* Enable following redirections.  Requires libcurl 7.10.1 at least */
-    curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1 );
-    curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10 );
-    
-    /* Set timeout.*/
-    curl_easy_setopt(http_handle, CURLOPT_TIMEOUT, 15 );
-
-    /* NOSIGNAL should be set to true for timeout to work in multithread
-     * environments on Unix, requires libcurl 7.10 or more recent.
-     * (this force avoiding the use of sgnal handlers)
-     */
-#ifdef CURLOPT_NOSIGNAL
-    curl_easy_setopt(http_handle, CURLOPT_NOSIGNAL, 1 );
-#endif
-
-    curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, &pszData );
-    curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, WCTSWriteFct );
-
-    szCurlErrBuf[0] = '\0';
-
-    curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, szCurlErrBuf );
-
-    error = curl_easy_perform( http_handle );
-
-    curl_easy_cleanup( http_handle );
-
-    if( strlen(szCurlErrBuf) > 0 )
-        WCTSEmitServiceException( szCurlErrBuf );
-    else if( pszData == NULL )
-        WCTSEmitServiceException( "No response from WCTS server." );
-
-    return pszData;
-#endif /* def HAVE_CURL */
-}
-
-/************************************************************************/
-/*                          WCTSAuthId2crsId()                          */
-/*                                                                      */
-/*      Convert a KVP format CRS keyword into XML format.  Returns      */
-/*      the crsID node and done.                                        */
-/************************************************************************/
-
-CPLXMLNode *WCTSAuthId2crsId( char **papszParms, const char *pszName )
-
-{
-    const char *pszAuthId = CSLFetchNameValue( papszParms, pszName );
-    CPLXMLNode *psCRSId;
-    char **papszTokens;
-
-    if( pszAuthId == NULL )
-        WCTSEmitServiceException( 
-            CPLSPrintf( "%s keyword missing", pszName ) );
-    
-    papszTokens = CSLTokenizeString2( pszAuthId, ":", 0 );
-    if( CSLCount(papszTokens) != 2 )
-        WCTSEmitServiceException( 
-            CPLSPrintf( "%.500s value corrupt, use 'authority:code'.",
-                        pszName ));
-    
-    psCRSId = CPLCreateXMLNode( NULL, CXT_Element, "crsID" );
-    
-    CPLCreateXMLElementAndValue( psCRSId, "gml:codeSpace", papszTokens[0]);
-    CPLCreateXMLElementAndValue( psCRSId, "gml:code", papszTokens[1] );
-    
-    CSLDestroy( papszTokens );
-
-    return psCRSId;
-}
-
-
-/************************************************************************/
-/*                       WCTSCollectKVPRequest()                        */
-/*                                                                      */
-/*      Build an XML tree representation of a request received in       */
-/*      KVP format via QUERY_STRING.                                    */
-/************************************************************************/
-
-CPLXMLNode *WCTSCollectKVPRequest()
-
-{
-    char **papszParmList;
-
-/* -------------------------------------------------------------------- */
-/*      Parse the query string.                                         */
-/* -------------------------------------------------------------------- */
-    if( getenv("QUERY_STRING") == NULL )
-        WCTSEmitServiceException( "QUERY_STRING not set." );
-
-    papszParmList = CSLTokenizeString2( getenv("QUERY_STRING"), "&",
-                                        CSLT_PRESERVEESCAPES );
-    
-/* -------------------------------------------------------------------- */
-/*      Un-url-encode the items.                                        */
-/* -------------------------------------------------------------------- */
-    int i;
-
-    for( i = 0; papszParmList != NULL && papszParmList[i] != NULL; i++ )
-    {
-        char *pszNewValue = CPLUnescapeString( papszParmList[i], 
-                                               NULL, CPLES_URL );
-        
-        CPLFree( papszParmList[i] );
-        papszParmList[i] = pszNewValue;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Check for REQUEST                                               */
-/* -------------------------------------------------------------------- */
-    const char *pszVersion = CSLFetchNameValue(papszParmList,"VERSION");
-    const char *pszRequest = CSLFetchNameValue(papszParmList,"REQUEST");
-
-    if( pszRequest == NULL )
-        WCTSEmitServiceException( "REQUEST not provided in KVP URL." );
-
-/* -------------------------------------------------------------------- */
-/*      Handle GetCapabilities                                          */
-/* -------------------------------------------------------------------- */
-    else if( EQUAL(pszRequest,"GetCapabilities") )
-    {
-        CPLXMLNode *psRequest = CPLCreateXMLNode( NULL, CXT_Element, 
-                                                  "GetCapabilities" );
-
-        if( pszVersion != NULL )
-        {
-            CPLCreateXMLNode( 
-                CPLCreateXMLNode( psRequest, CXT_Attribute, "version" ),
-                CXT_Text, pszVersion );
-        }
-
-        if( CSLFetchNameValue(papszParmList,"SERVICE") != NULL )
-        {
-            CPLCreateXMLNode( 
-                CPLCreateXMLNode( psRequest, CXT_Attribute, "service" ),
-                CXT_Text, CSLFetchNameValue(papszParmList,"SERVICE") );
-        }
-
-        return psRequest;
-    }
-
-/* ==================================================================== */
-/*      Handle IsTransformable                                          */
-/* ==================================================================== */
-    else if( EQUAL(pszRequest,"IsTransformable") )
-    {
-        CPLXMLNode *psRequest = CPLCreateXMLNode( NULL, CXT_Element, 
-                                                  "IsTransformable" );
-
-/* -------------------------------------------------------------------- */
-/*      Translate the source crs.                                       */
-/* -------------------------------------------------------------------- */
-        CPLAddXMLChild( 
-            CPLCreateXMLNode( psRequest, CXT_Element, "SourceCRS" ),
-            WCTSAuthId2crsId( papszParmList, "SOURCECRS" ) );
-
-/* -------------------------------------------------------------------- */
-/*      Translate the destination crs.                                  */
-/* -------------------------------------------------------------------- */
-        CPLAddXMLChild( 
-            CPLCreateXMLNode( psRequest, CXT_Element, "TargetCRS" ),
-            WCTSAuthId2crsId( papszParmList, "TARGETCRS" ) );
-
-/* -------------------------------------------------------------------- */
-/*      Handle version.                                                 */
-/* -------------------------------------------------------------------- */
-        if( pszVersion != NULL )
-        {
-            CPLCreateXMLNode( 
-                CPLCreateXMLNode( psRequest, CXT_Attribute, "version" ),
-                CXT_Text, pszVersion );
-        }
-
-/* -------------------------------------------------------------------- */
-/*      geometric primitive.                                            */
-/* -------------------------------------------------------------------- */
-        if( CSLFetchNameValue(papszParmList,"GEOMETRICPRIMITIVE") != NULL )
-        {
-            CPLCreateXMLElementAndValue( 
-                psRequest, "GeometricPrimitive", 
-                CSLFetchNameValue(papszParmList,"GEOMETRICPRIMITIVE") );
-        }
-
-        /* Add COVERAGETYPE and COVERAGEINTERPOLATIONMETHOD layer? */
-
-        return psRequest;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Unrecognised.                                                   */
-/* -------------------------------------------------------------------- */
-    else
-        WCTSEmitServiceException( 
-            CPLSPrintf( "Unrecognised REQUEST value (%.500s).", pszRequest) );
-
-    return NULL;
-}
-
-/************************************************************************/
-/*                         WCTSCollectRequest()                         */
-/*                                                                      */
-/*      This function will return an XML document in CPLXMLNode tree    */
-/*      format corresponding to the current request.  If an error       */
-/*      occurs the function does not return.  GET KVP style requests    */
-/*      are internally converted into XML format.                       */
-/************************************************************************/
-
-CPLXMLNode *WCTSCollectRequest()
-
-{
-    if( getenv("REQUEST_METHOD") == NULL )
-        WCTSEmitServiceException( "REQUEST_METHOD not set." );
-
-    if( EQUAL(getenv("REQUEST_METHOD"),"GET") )
-        return WCTSCollectKVPRequest();
-
-/* -------------------------------------------------------------------- */
-/*      Read the body of the POST message into a buffer.                */
-/* -------------------------------------------------------------------- */
-    int nContentLength = 0;
-    char *pszXML = NULL;
-
-    if( getenv("CONTENT_LENGTH") != NULL )
-    {
-        nContentLength = atoi(getenv("CONTENT_LENGTH"));
-
-        pszXML = (char *) CPLMalloc(nContentLength+1);
-        
-        if( (int) fread(pszXML, 1, nContentLength, stdin) < nContentLength )
-            WCTSEmitServiceException( "POST body is short." );
-
-        pszXML[nContentLength] = '\0';
-    }
-
-    else
-    {
-        int nXMLMax, nXMLLen=0;
-
-        nXMLMax = 100;
-        pszXML = (char *) CPLMalloc(nXMLMax);
-        
-        while( !feof(stdin) )
-        {
-            pszXML[nXMLLen++] = fgetc(stdin);
-            if( nXMLLen == nXMLMax )
-            {
-                nXMLMax = nXMLMax * 2;
-                pszXML = (char *) CPLRealloc(pszXML, nXMLMax);
-            }
-        }
-
-        pszXML[nXMLLen] = '\0';
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Convert into an XML document.                                   */
-/* -------------------------------------------------------------------- */
-    CPLErrorReset();
-
-    CPLXMLNode *psTree = CPLParseXMLString( pszXML );
-    CPLFree( pszXML );
-
-    if( CPLGetLastErrorType() == CE_Failure )
-        WCTSEmitServiceException( CPLGetLastErrorMsg() );
-
-    return psTree;
-}
-
-/************************************************************************/
-/*                        WCTSGetCapabilities()                         */
-/*                                                                      */
-/*      For now we just return a fixed capabilities document from       */
-/*      the file system.  No real need to dynamically generate          */
-/*      this except possibly to insert the coordinate system list       */
-/*      based on scanning pcs.csv and gcs.csv.                          */
-/************************************************************************/
-
-void WCTSGetCapabilities( CPLXMLNode *psOperation )
-
-{
-/* -------------------------------------------------------------------- */
-/*      Verify the service.                                             */
-/* -------------------------------------------------------------------- */
-    if( !EQUAL(CPLGetXMLValue(psOperation,"service","WCTS"),"WCTS") )
-    {
-        WCTSEmitServiceException( 
-            CPLSPrintf( "Attempt to GetCapabilities for unsupported '%.500s'\n"
-                        "service.  Only WCTS supported.",
-                        CPLGetXMLValue(psOperation,"service","WCTS") ) );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Search for our capabilities document.                           */
-/* -------------------------------------------------------------------- */
-    const char *pszCapFilename;
-    FILE *fp;
-
-    pszCapFilename = CPLFindFile( "gdal", "wcts_capabilities.xml.0.1.0" );
-
-    if( pszCapFilename == NULL 
-        || (fp = VSIFOpen( pszCapFilename, "rt")) == NULL )
-    {
-        WCTSEmitServiceException( "WCTS server misconfigured, "
-                                  "unable to find capabilities document." );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Emit the document.                                              */
-/* -------------------------------------------------------------------- */
-    int nLen;
-    char *pszDoc;
-
-    VSIFSeek( fp, 0, SEEK_END );
-    nLen = VSIFTell( fp );
-    VSIFSeek( fp, 0, SEEK_SET );
-    
-    pszDoc = (char *) CPLMalloc(nLen);
-    VSIFRead( pszDoc, 1, nLen, fp );
-    VSIFClose( fp );
-
-    printf( "Content-type: text/xml%c%c", 10, 10 );
-
-    VSIFWrite( pszDoc, 1, nLen, stdout );
-    fflush( stdout );
-
-    CPLFree( pszDoc );
-
-    exit( 0 );
-}
-
-/************************************************************************/
-/*                WCTSImportCoordinateReferenceSystem()                 */
-/*                                                                      */
-/*      This is a place holder. Eventually this will use                */
-/*      OGRSpatialReference.importFromXML() when that has been          */
-/*      updated to the GML 3.0 CRS formats.                             */
-/************************************************************************/
-
-OGRSpatialReference *
-WCTSImportCoordinateReferenceSystem( CPLXMLNode *psXMLCRS )
-
-{
-    CPLStripXMLNamespace( psXMLCRS->psChild, NULL, TRUE );
-
-/* ==================================================================== */
-/*      Try to find a direct crsID as per old specification.            */
-/* ==================================================================== */
-    const char *pszCode = CPLGetXMLValue( psXMLCRS, "crsID.code", NULL );
-    const char *pszCodeSpace = CPLGetXMLValue( psXMLCRS, "crsID.codeSpace", 
-                                               NULL );
-
-    if( pszCode != NULL && pszCodeSpace != NULL )
-    {
-/* -------------------------------------------------------------------- */
-/*      Get the EPSG code, and verify that it is in the EPSG            */
-/*      codeSpace.                                                      */
-/* -------------------------------------------------------------------- */
-        OGRSpatialReference oSRS;
-
-        if( EQUAL(pszCodeSpace,"EPSG") )
-        {
-            int nEPSGCode = atoi(pszCode);
-            
-            if( nEPSGCode == 0 )
-            {
-                WCTSEmitServiceException( "Failed to decode CoordinateReferenceSystem with missing,\n"
-                                          "or zero crsID.code" );
-            }								
-
-            CPLErrorReset();
-            if( oSRS.importFromEPSG( nEPSGCode ) != OGRERR_NONE )
-            {
-                if( strlen(CPLGetLastErrorMsg()) > 0 )
-                    WCTSEmitServiceException( CPLGetLastErrorMsg() );
-                else
-                    WCTSEmitServiceException( 
-                        CPLSPrintf( "OGRSpatialReference::importFromEPSG(%d) "
-                                    "failed.  Is this a defined EPSG code?", 
-                                    nEPSGCode ) );
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Handle AUTO case.                                               */
-/* -------------------------------------------------------------------- */
-        else if( EQUAL(pszCodeSpace,"AUTO") )
-        {
-            if( oSRS.importFromWMSAUTO( pszCode ) != OGRERR_NONE )
-            {
-                if( strlen(CPLGetLastErrorMsg()) > 0 )
-                    WCTSEmitServiceException( CPLGetLastErrorMsg() );
-                else
-                    WCTSEmitServiceException( 
-                        CPLSPrintf( "OGRSpatialReference::importFromWMSAUTO(%s) "
-                                    "failed.  Is this a defined EPSG code?", 
-                                    pszCode  ) );
-            }
-        }
-
-/* -------------------------------------------------------------------- */
-/*      Otherwise blow a gasket.                                        */
-/* -------------------------------------------------------------------- */
-        else
-        {
-            WCTSEmitServiceException( "Failed to decode CoordinateReferenceSystem with missing,\n"
-                                      "or non-EPSG crsID.codeSpace" );
-        }	
-        
-/* -------------------------------------------------------------------- */
-/*      Translate into an OGRSpatialReference from EPSG code.           */
-/* -------------------------------------------------------------------- */
-
-        return oSRS.Clone();
-    }
-
-/* ==================================================================== */
-/*      Try to import a projectedCRS or geographicCRS.                  */
-/* ==================================================================== */
-    if( CPLGetXMLNode( psXMLCRS, "ProjectedCRS" ) != NULL 
-        || CPLGetXMLNode( psXMLCRS, "GeographicCRS" ) != NULL )
-    {
-#ifdef DISABLE_USER_DEFINED_CRS
-        WCTSEmitServiceException( 
-            "User defined ProjectedCRS and GeographicCRS support\n"
-            "disabled for security reasons." );
-#else
-        char *pszSerializedForm;
-        OGRSpatialReference oSRS;
-
-        pszSerializedForm = CPLSerializeXMLTree( psXMLCRS->psChild );
-        if( oSRS.importFromXML( pszSerializedForm ) != OGRERR_NONE )
-        {
-            CPLFree( pszSerializedForm );
-            if( strlen(CPLGetLastErrorMsg()) > 0 )
-                WCTSEmitServiceException( CPLGetLastErrorMsg() );
-            else
-                WCTSEmitServiceException( "Failed to import CRS" );
-        }
-
-        CPLFree( pszSerializedForm );
-        return oSRS.Clone();
-#endif
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      We don't seem to recognise a CRS here.                          */
-/* -------------------------------------------------------------------- */
-    WCTSEmitServiceException( "Unable to identify CRS in one of SourceCRS or TargetCRS elements" );
-
-    return NULL;
-}
-
-/************************************************************************/
-/*                        WCTSIsTransformable()                         */
-/************************************************************************/
-
-void WCTSIsTransformable( CPLXMLNode *psOperation )
-
-{
-    OGRSpatialReference *poSrcCRS, *poDstCRS;
-    CPLXMLNode *psSrcXMLCRS, *psDstXMLCRS;
-
-/* -------------------------------------------------------------------- */
-/*      Translate the source CRS.                                       */
-/* -------------------------------------------------------------------- */
-    psSrcXMLCRS = CPLGetXMLNode( psOperation, "SourceCRS" );
-
-    if( psSrcXMLCRS == NULL )
-        WCTSEmitServiceException( "Unable to identify SourceCRS.CoordinateReferenceSystem" );
-
-    poSrcCRS = WCTSImportCoordinateReferenceSystem( psSrcXMLCRS );
-
-/* -------------------------------------------------------------------- */
-/*      Translate the destination CRS.                                  */
-/* -------------------------------------------------------------------- */
-    psDstXMLCRS = CPLGetXMLNode( psOperation, "TargetCRS" );
-
-    if( psDstXMLCRS == NULL )
-        WCTSEmitServiceException( "Unable to identify DestinationCRS.CoordinateReferenceSystem" );
-
-    poDstCRS = WCTSImportCoordinateReferenceSystem( psDstXMLCRS );
-
-/* -------------------------------------------------------------------- */
-/*      Create a transformation object between the coordinate           */
-/*      systems as an added step of verification that they are          */
-/*      supported.                                                      */
-/* -------------------------------------------------------------------- */
-    OGRCoordinateTransformation *poCT;
-    const char *pszResult;
-
-    poCT = OGRCreateCoordinateTransformation( poSrcCRS, poDstCRS );
-    if( poCT == NULL )
-        pszResult = "false";
-    else
-    {
-        delete poCT;
-        pszResult = "true";
-    }
-
-    delete poSrcCRS;
-    delete poDstCRS;
-
-/* -------------------------------------------------------------------- */
-/*      Return the answer.                                              */
-/* -------------------------------------------------------------------- */
-    printf( "Content-type: text/xml%c%c", 10, 10 );
-
-    printf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
-    printf( "<TransformableResponse xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://www.deegree.org/xml/schemas/wcts/transformableResponse.xsd\" transformable=\"%s\"/>\n", 
-            pszResult );
-
-    exit( 0 );
-}
-
-/************************************************************************/
-/*                       WCTSIsGeometryElement()                        */
-/************************************************************************/
-
-int WCTSIsGeometryElement( CPLXMLNode *psNode )
-
-{
-    if( psNode->eType != CXT_Element )
-        return FALSE;
-    
-    const char *pszElement = psNode->pszValue;
-    
-    if( EQUALN(pszElement,"gml:",4) )
-        pszElement += 4;
-
-    return EQUAL(pszElement,"Polygon") 
-        || EQUAL(pszElement,"MultiPolygon") 
-        || EQUAL(pszElement,"MultiPoint") 
-        || EQUAL(pszElement,"MultiLineString") 
-        || EQUAL(pszElement,"GeometryCollection") 
-        || EQUAL(pszElement,"Point") 
-        || EQUAL(pszElement,"Box")
-        || EQUAL(pszElement,"LineString");
-}
-    
-/************************************************************************/
-/*                      WCTSRecurseAndTransform()                       */
-/*                                                                      */
-/*      Recurse down a XML document tree that contains some GML         */
-/*      geometries.  Identify them, convert them into OGRGeometries,    */
-/*      transform these, convert back to GML, insert in place of old    */
-/*      geometry fragments, and continue on.                            */
-/************************************************************************/
-
-void WCTSRecurseAndTransform( CPLXMLNode *psTree, 
-                              OGRCoordinateTransformation *poCT )
-
-{
-    if( psTree == NULL )
-        return;
-
-/* -------------------------------------------------------------------- */
-/*      If this isn't a geometry mode just recurse.                     */
-/* -------------------------------------------------------------------- */
-    if( !WCTSIsGeometryElement( psTree ) )
-    {
-        WCTSRecurseAndTransform( psTree->psChild, poCT );
-        WCTSRecurseAndTransform( psTree->psNext, poCT );
-        return;
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Convert this node, and it's children (but not it's sibling)     */
-/*      into serialized XML form for feeding to the GML geometry        */
-/*      parser.                                                         */
-/* -------------------------------------------------------------------- */
-    CPLXMLNode *psNext = psTree->psNext;
-    OGRGeometry *poGeometry;
-
-    psTree->psNext = NULL;
-    poGeometry = (OGRGeometry *) OGR_G_CreateFromGMLTree( psTree );
-    psTree->psNext = psNext;
-
-    if( poGeometry == NULL )
-    {
-        /* should we raise an exception?  For now, no.*/
-        WCTSRecurseAndTransform( psTree->psNext, poCT );
-        return;
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Attempt to transform the geometry (inplace).                    */
-/* -------------------------------------------------------------------- */
-    if( poGeometry->transform( poCT ) != OGRERR_NONE )
-        WCTSEmitServiceException( "Unable to transform some geometries." );
-
-/* -------------------------------------------------------------------- */
-/*      Convert back to XML Tree format.                                */
-/* -------------------------------------------------------------------- */
-    CPLXMLNode *psAltered, sTempCopy;
-
-    if( strstr(psTree->pszValue,"Box") == NULL )
-        psAltered = OGR_G_ExportToGMLTree( (OGRGeometryH) poGeometry );
-    else
-        psAltered = OGR_G_ExportEnvelopeToGMLTree( (OGRGeometryH) poGeometry );
-
-    OGRGeometryFactory::destroyGeometry( poGeometry );
-    
-/* -------------------------------------------------------------------- */
-/*      do fancy swap to copy contents of altered tree in over the      */
-/*      node being changed.  We do this in such a funky way because     */
-/*      we can't change the nodes that point to psTree to point to      */
-/*      psAltered.                                                      */
-/* -------------------------------------------------------------------- */
-    CPLAssert( psAltered->psNext == NULL );
-
-    memcpy( &sTempCopy, psTree, sizeof(CPLXMLNode));
-    memcpy( psTree, psAltered, sizeof(CPLXMLNode));
-    memcpy( psAltered, &sTempCopy, sizeof(CPLXMLNode));
-
-    psTree->psNext = psAltered->psNext;
-    psAltered->psNext = NULL;
-
-    CPLDestroyXMLNode( psAltered );
-    
-/* -------------------------------------------------------------------- */
-/*      Continue on to sibling nodes, but do no further travelling      */
-/*      to this nodes children.                                         */
-/* -------------------------------------------------------------------- */
-    WCTSRecurseAndTransform( psTree->psNext, poCT );
-}
-
-/************************************************************************/
-/*                            WCTSGetData()                             */
-/*                                                                      */
-/*      Fetch the data component as a parsed XML tree.  In some         */
-/*      cases the data contents are local, in other cases they have     */
-/*      to be fetched from a remote tree.                               */
-/*                                                                      */
-/*      The argument passed in is the <Data> element.  If it has a      */
-/*      FileURL child that child is replaced by the actual instance.    */
-/************************************************************************/
-
-void WCTSGetData( CPLXMLNode * psData )
-
-{
-    CPLAssert( psData != NULL && psData->eType == CXT_Element
-               && EQUAL(psData->pszValue,"Data") );
-
-/* ==================================================================== */
-/*      Handle a FileURL.                                               */
-/* ==================================================================== */
-    if( psData->psChild != NULL 
-        && EQUAL(psData->psChild->pszValue,"FileURL")
-        && psData->psChild->eType == CXT_Element 
-        && psData->psChild->psChild != NULL
-        && psData->psChild->psChild->eType == CXT_Text )
-    {
-        CPLXMLNode *psNewDataTree;
-        char *pszData;
-
-        if( !EQUALN(psData->psChild->psChild->pszValue,"http:",5) 
-            && !EQUALN(psData->psChild->psChild->pszValue,"https:",6) 
-            && !EQUALN(psData->psChild->psChild->pszValue,"ftp:",4) )
-            
-        {
-            WCTSEmitServiceException( 
-                "Use of FileURL with protocol other than http, https or ftp\n"
-                "not supported for security reasons." );
-        }
-
-        pszData = WCTSHTTPFetch( psData->psChild->psChild->pszValue );
-
-        psNewDataTree = CPLParseXMLString( pszData );
-        if( psNewDataTree == NULL )
-        {
-            if( strlen(CPLGetLastErrorMsg()) > 0 )
-                WCTSEmitServiceException( CPLGetLastErrorMsg() );
-            else
-                WCTSEmitServiceException( "Failing parsing GML fetched from FileURL." );
-        }
-
-        CPLFree( pszData );
-
-        /* discard special prefix line if present */
-        if( psNewDataTree->eType == CXT_Literal 
-            || (psNewDataTree->eType == CXT_Element
-                && EQUALN(psNewDataTree->pszValue,"?",1) ) )
-        {
-            CPLXMLNode *psNext = psNewDataTree->psNext;
-            psNewDataTree->psNext = NULL;
-            CPLDestroyXMLNode( psNewDataTree );
-            psNewDataTree = psNext;
-        }
-        
-        /* substitute this tree in place of the FileURL */
-        CPLDestroyXMLNode( psData->psChild );
-        psData->psChild = psNewDataTree;
-
-        return;
-    }
-
-/* ==================================================================== */
-/*      Otherwise, no change required.                                  */
-/* ==================================================================== */
-    return;
-}
-
-/************************************************************************/
-/*                           WCTSTransform()                            */
-/************************************************************************/
-
-void WCTSTransform( CPLXMLNode *psOperation )
-
-{
-    OGRSpatialReference *poSrcCRS, *poDstCRS;
-    CPLXMLNode *psSrcXMLCRS, *psDstXMLCRS;
-
-/* -------------------------------------------------------------------- */
-/*      Translate the source CRS.                                       */
-/* -------------------------------------------------------------------- */
-    psSrcXMLCRS = CPLGetXMLNode( psOperation, "SourceCRS" );
-
-    if( psSrcXMLCRS == NULL )
-        WCTSEmitServiceException( "Unable to identify SourceCRS.CoordinateReferenceSystem" );
-
-    poSrcCRS = WCTSImportCoordinateReferenceSystem( psSrcXMLCRS );
-
-/* -------------------------------------------------------------------- */
-/*      Translate the destination CRS.                                  */
-/* -------------------------------------------------------------------- */
-    psDstXMLCRS = CPLGetXMLNode( psOperation, "TargetCRS" );
-
-    if( psDstXMLCRS == NULL )
-        WCTSEmitServiceException( "Unable to identify DestinationCRS.CoordinateReferenceSystem" );
-
-    poDstCRS = WCTSImportCoordinateReferenceSystem( psDstXMLCRS );
-
-/* -------------------------------------------------------------------- */
-/*      Create the coordinate transformation object.                    */
-/* -------------------------------------------------------------------- */
-    OGRCoordinateTransformation *poCT;
-
-    poCT = OGRCreateCoordinateTransformation( poSrcCRS, poDstCRS );
-    if( poCT == NULL )
-        WCTSEmitServiceException( "Unable to transform between source and destination CRSs." );
-
-    delete poSrcCRS;
-    delete poDstCRS;
-
-/* -------------------------------------------------------------------- */
-/*      We will recurse over the GML data tree looking for segments     */
-/*      that are recognizably geometries to be transformed in place.    */
-/* -------------------------------------------------------------------- */
-    CPLXMLNode *psData = CPLGetXMLNode(psOperation,"Data");
-
-    if( psData == NULL )
-        WCTSEmitServiceException( "Unable to find GML Data contents." );
-
-    WCTSGetData( psData );
-    WCTSRecurseAndTransform( psData, poCT );
-
-/* -------------------------------------------------------------------- */
-/*      Now translate the data back into a serialized form suitable     */
-/*      for including in the reply.                                     */
-/* -------------------------------------------------------------------- */
-    char *pszDataText = CPLSerializeXMLTree( psData );
-
-/* -------------------------------------------------------------------- */
-/*      Return result.                                                  */
-/* -------------------------------------------------------------------- */
-    printf( "Content-type: text/xml%c%c", 10, 10 );
-
-    printf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
-    printf( "<TransformResponse xmlns:gml=\"http://www.opengis.net/gml\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >\n" );
-    fwrite( pszDataText, 1, strlen(pszDataText), stdout );
-    printf( "</TransformResponse>\n" );
-
-    exit( 0 );
-}
-
-/************************************************************************/
-/*                                main()                                */
-/************************************************************************/
-
-int main( int nArgc, char ** papszArgv )
-
-{
-    RegisterOGRGML();
-
-/* -------------------------------------------------------------------- */
-/*      Process any configuration switches.                             */
-/* -------------------------------------------------------------------- */
-    int iArg;
-
-    for( iArg = 1; iArg < nArgc; iArg++ )
-    {
-        if( EQUAL(papszArgv[iArg],"-log") && iArg < nArgc-1 )
-        {
-            char *pszLogEnv = (char *) CPLMalloc(strlen(papszArgv[iArg+1])+20);
-
-            sprintf( pszLogEnv, "CPL_LOG=%s", papszArgv[iArg+1] );
-            putenv( pszLogEnv );
-
-            iArg++;
-        }
-        else if( EQUAL(papszArgv[iArg],"-debug") )
-        {
-            putenv( "CPL_DEBUG=ON" );
-            putenv( "PROJ_DEBUG=ON" );
-        }
-        else if( EQUAL(papszArgv[iArg],"-data")  && iArg < nArgc-1 )
-        {
-            CPLPushFinderLocation( papszArgv[++iArg] );
-        }
-        else if( EQUAL(papszArgv[iArg],"-put") )
-        {
-            putenv( "REQUEST_METHOD=PUT" );
-        }
-        else if( EQUAL(papszArgv[iArg],"-get")  && iArg < nArgc-1 )
-        {
-            char *pszLogEnv = (char *) CPLMalloc(strlen(papszArgv[iArg+1])+20);
-
-            sprintf( pszLogEnv, "QUERY_STRING=%s", papszArgv[iArg+1] );
-            putenv( pszLogEnv );
-            putenv( "REQUEST_METHOD=GET" );
-
-            iArg++;
-        }
-        else
-        {
-            WCTSEmitServiceException( 
-               "Server misconfigured, unknown commandline options received.\n"
-               "\n"
-               "Usage: ogrwcts [-log logfilename] [-debug] [-data directory]\n"
-               "               [-get url] [-put]\n" );
-        }
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Collect the request as a parsed XML document.                   */
-/* -------------------------------------------------------------------- */
-    CPLXMLNode *psRequest;
-
-    psRequest = WCTSCollectRequest();
-
-/* -------------------------------------------------------------------- */
-/*      Scan for known operation nodes.                                 */
-/* -------------------------------------------------------------------- */
-    CPLXMLNode *psOperation;
-
-    for( psOperation = psRequest; 
-         psOperation != NULL; 
-         psOperation = psOperation->psNext )
-    {
-        if( psOperation->eType == CXT_Element
-            && EQUAL(psOperation->pszValue,"GetCapabilities") )
-        {
-            WCTSGetCapabilities( psOperation );
-            assert( FALSE );
-        }
-        else if( psOperation->eType == CXT_Element
-            && EQUAL(psOperation->pszValue,"IsTransformable") )
-        {
-            WCTSIsTransformable( psOperation );
-            assert( FALSE );
-        }
-        else if( psOperation->eType == CXT_Element
-            && EQUAL(psOperation->pszValue,"Transform") )
-        {
-            WCTSTransform( psOperation );
-            assert( FALSE );
-        }
-        else if( psOperation->eType == CXT_Element
-            && EQUAL(psOperation->pszValue,"DescribeTransformation") )
-        {
-            WCTSEmitServiceException( "This server does not support the DescribeTransformation operation." );
-        }
-    }
-
-    CPLDestroyXMLNode( psRequest );
-
-    WCTSEmitServiceException( "No recognisable supported request found." );
-    exit( 1 );
-}
-
diff --git a/ogr/wcts/req_getcap.xml b/ogr/wcts/req_getcap.xml
deleted file mode 100644
index 57fd823..0000000
--- a/ogr/wcts/req_getcap.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<GetCapabilities service="WCTS" version="0.1.0"/>
diff --git a/ogr/wcts/req_istransformable.xml b/ogr/wcts/req_istransformable.xml
deleted file mode 100644
index fba6a6e..0000000
--- a/ogr/wcts/req_istransformable.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<IsTransformable 
-    xmlns="http://schemas.opengis.net/wcts" 
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
-    xmlns:gml="http://www.opengis.net/gml" 
-    xsi:schemaLocation="http://schemas.opengis.net/wcts/IsTransformableRequest.xsd"> 
-    <SourceCRS> 
-         <crsID> 
-              <gml:code>4326</gml:code> 
-              <gml:codeSpace>EPSG</gml:codeSpace> 
-         </crsID> 
-    </SourceCRS> 
-    <TargetCRS> 
-         <crsID> 
-              <gml:code>23032</gml:code> 
-              <gml:codeSpace>EPSG</gml:codeSpace> 
-         </crsID> 
-     </TargetCRS> 
-</IsTransformable> 
- 
diff --git a/ogr/wcts/req_nad2783tr.xml b/ogr/wcts/req_nad2783tr.xml
deleted file mode 100644
index 6c6527b..0000000
--- a/ogr/wcts/req_nad2783tr.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<Transform xmlns="http://schemas.opengis.net/wcts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" version="0.1.0">
-  <SourceCRS>
-    <crsID>
-      <gml:code>4267</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </SourceCRS>
-  <TargetCRS>
-    <crsID>
-      <gml:code>4269</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </TargetCRS>
-  <CoordinateOperationID>
-    <gml:code>1241</gml:code> 
-    <gml:codeSpace>EPSG</gml:codeSpace> 
-    <gml:version>6.2.2</gml:version> 
-  </CoordinateOperationID>
-  <Data>
-    <gml:featureCollection xmlns:gml="http://www.opengis.net/gml">
-      <gml:featureMember>
-        <StreetInt fid="0">
-          <gml:geometryProperty>
-            <gml:Point>
-              <gml:coordinates>-123.0,49.75</gml:coordinates>
-            </gml:Point>
-          </gml:geometryProperty>
-        </StreetInt>
-      </gml:featureMember>
-    </gml:featureCollection>
-  </Data>
-</Transform>
diff --git a/ogr/wcts/req_remote.xml b/ogr/wcts/req_remote.xml
deleted file mode 100644
index 3e05e6f..0000000
--- a/ogr/wcts/req_remote.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<Transform xmlns="http://schemas.opengis.net/wcts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" version="0.1.0">
-  <SourceCRS>
-    <crsID>
-      <gml:code>4267</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </SourceCRS>
-  <TargetCRS>
-    <crsID>
-      <gml:code>4269</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </TargetCRS>
-  <CoordinateOperationID>
-    <gml:code>1241</gml:code> 
-    <gml:codeSpace>EPSG</gml:codeSpace> 
-    <gml:version>6.2.2</gml:version> 
-  </CoordinateOperationID>
-  <Data>
-    <FileURL>http://gdal.velocet.ca/~warmerda/nad27.gml</FileURL>
-  </Data>
-</Transform>
diff --git a/ogr/wcts/req_transform.xml b/ogr/wcts/req_transform.xml
deleted file mode 100644
index c05d851..0000000
--- a/ogr/wcts/req_transform.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<Transform xmlns="http://schemas.opengis.net/wcts" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" version="0.1.0">
-  <SourceCRS>
-    <crsID>
-      <gml:code>4326</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </SourceCRS>
-  <TargetCRS>
-    <crsID>
-      <gml:code>32611</gml:code>
-      <gml:codeSpace>EPSG</gml:codeSpace>
-    </crsID>
-  </TargetCRS>
-  <Data>
-    <gml:featureCollection xmlns:gml="http://www.opengis.net/gml">
-      <gml:boundedBy>
-        <gml:Box>
-          <gml:coord>
-            <gml:X>-115.467123</gml:X>
-            <gml:Y>16.743654</gml:Y>
-          </gml:coord>
-          <gml:coord>
-            <gml:X>-88.291157</gml:X>
-            <gml:Y>32.654688</gml:Y>
-          </gml:coord>
-        </gml:Box>
-      </gml:boundedBy>
-      <gml:featureMember>
-        <mx_caps fid="0">
-          <Capital>Aguascalientes</Capital>
-          <State_Name>AGUASCALIENTES</State_Name>
-          <gml:geometryProperty>
-            <gml:Point>
-              <gml:coordinates>-102.28969800,21.88751600</gml:coordinates>
-            </gml:Point>
-          </gml:geometryProperty>
-        </mx_caps>
-      </gml:featureMember>
-    </gml:featureCollection>
-  </Data>
-</Transform>
diff --git a/ogr/wcts/wcts_capabilities.xml.0.1.0 b/ogr/wcts/wcts_capabilities.xml.0.1.0
deleted file mode 100644
index 3dc8dfd..0000000
--- a/ogr/wcts/wcts_capabilities.xml.0.1.0
+++ /dev/null
@@ -1,146 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<WCTS_Capabilities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gml="http://www.opengis.net/gml" xsi:noNamespaceSchemaLocation="http://www.deegree.org/xml/schemas/wcts/capabilities.xsd" version="0.1.0" updateSequence="1">
-  <Service>
-    <Name>WCTS</Name>
-    <Title>Web Coordinate Transformation Service</Title>
-    <Abstract>Service for transforming coordinates from one CRS to another
-through a network</Abstract>
-    <KeywordList>
-      <Keyword>Coordinate Reference System</Keyword>
-      <Keyword>transformation</Keyword>
-    </KeywordList>
-    <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://www.lat-lon.de"/>
-    <ContactInformation>
-      <ContactPersonPrimary>
-        <ContactPerson>Frank Warmerdam</ContactPerson>
-        <ContactOrganization>DM Solutions Group</ContactOrganization>
-      </ContactPersonPrimary>
-      <ContactPosition>Software Developer</ContactPosition>
-      <ContactAddress>
-        <AddressType>postal</AddressType>
-        <Address>15 - 85 Baif Blvd.</Address>
-        <City>Richmond Hill</City>
-        <StateOrProvince>Ontario</StateOrProvince>
-        <PostCode>L4C 5E2</PostCode>
-        <Country>Canada</Country>
-      </ContactAddress>
-      <ContactVoiceTelephone>++011 905 7800450</ContactVoiceTelephone>
-      <ContactFacsimileTelephone>++011 905 7800450</ContactFacsimileTelephone>
-      <ContactElectronicMailAddress>warmerdam at pobox.com</ContactElectronicMailAddress>
-    </ContactInformation>
-    <Fees>none</Fees>
-    <AccessConstraints>none</AccessConstraints>
-  </Service>
-  <Capability userDefinedCoordinateSystems="false" userDefinedTransformations="false">
-    <Request>
-      <GetCapabilities>
-        <Format>String</Format>
-        <DCPType>
-          <HTTP>
-            <Get>
-              <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://gdal.velocet.ca/cgi-bin/ogrwcts?"/>
-            </Get>
-            <Post>
-              <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://gdal.velocet.ca/cgi-bin/ogrwcts?"/>
-            </Post>
-          </HTTP>
-        </DCPType>
-      </GetCapabilities>
-      <Transform>
-        <Format>String</Format>
-        <DCPType>
-          <HTTP>
-            <Post>
-              <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://gdal.velocet.ca/cgi-bin/ogrwcts?"/>
-            </Post>
-          </HTTP>
-        </DCPType>
-      </Transform>
-      <IsTransformable>
-        <Format>String</Format>
-        <DCPType>
-          <HTTP>
-            <Post>
-              <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://gdal.velocet.ca/cgi-bin/ogrwcts?"/>
-            </Post>
-          </HTTP>
-        </DCPType>
-      </IsTransformable>
-      <!-- I think I should just omit this, since I don't support it, 
-           is that right? -->
-      <DescribeTransformation>
-        <Format>String</Format>
-        <DCPType>
-          <HTTP>
-            <Post>
-              <OnlineResource xmlns:xlink="http://www.w3c.org/1999/xlink" xlink:type="simple" xlink:href="http://gdal.velocet.ca/cgi-bin/ogrwcts?"/>
-            </Post>
-          </HTTP>
-        </DCPType>
-      </DescribeTransformation>
-    </Request>
-    <!-- ================================================ -->
-    <!-- list of transformation types known by the WCTS   -->
-    <!-- ================================================ -->
-    <SupportedTransformation>
-      <coordinateTransformationID>
-        <gml:code>9601</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </coordinateTransformationID>
-    </SupportedTransformation>
-    <SupportedTransformation>
-      <coordinateTransformationID>
-        <gml:code>9602</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </coordinateTransformationID>
-    </SupportedTransformation>
-    <SupportedTransformation>
-      <coordinateTransformationID>
-        <gml:code>9603</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </coordinateTransformationID>
-    </SupportedTransformation>
-    <SupportedTransformation>
-      <coordinateTransformationID>
-        <gml:code>9604</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </coordinateTransformationID>
-    </SupportedTransformation>
-    <SupportedTransformation>
-      <coordinateTransformationID>
-        <gml:code>9807</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </coordinateTransformationID>
-    </SupportedTransformation>
-    <!-- ====================================================== -->
-    <!--- list of coordinate reference systems known by the WCTS -->
-    <!-- ====================================================== -->
-    <SupportedCoordinateReferenceSystem>
-      <crsID>
-        <gml:code>4326</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </crsID>
-    </SupportedCoordinateReferenceSystem>
-    <SupportedCoordinateReferenceSystem>
-      <crsID>
-        <gml:code>23031</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </crsID>
-    </SupportedCoordinateReferenceSystem>
-    <SupportedCoordinateReferenceSystem>
-      <crsID>
-        <gml:code>23032</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </crsID>
-    </SupportedCoordinateReferenceSystem>
-    <SupportedCoordinateReferenceSystem>
-      <crsID>
-        <gml:code>31467</gml:code>
-        <gml:codeSpace>EPSG</gml:codeSpace>
-      </crsID>
-    </SupportedCoordinateReferenceSystem>
-    <SupportedGeometricPrimitiveType>PointType</SupportedGeometricPrimitiveType>
-    <SupportedGeometricPrimitiveType>LineStringType</SupportedGeometricPrimitiveType>
-    <SupportedGeometricPrimitiveType>PolygonType</SupportedGeometricPrimitiveType>
-  </Capability>
-</WCTS_Capabilities>
diff --git a/ogr/wcts/wctsclient.cpp b/ogr/wcts/wctsclient.cpp
deleted file mode 100644
index 977ee4d..0000000
--- a/ogr/wcts/wctsclient.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-/******************************************************************************
- * $Id: wctsclient.cpp 10645 2007-01-18 02:22:39Z warmerdam $
- *
- * Project:  Web Coordinate Transformation Service
- * Purpose:  cgi-bin client form processor.  Turns client form request into
- *           a WCTS request, and returns the result to the client in HTML.
- * Author:   Frank Warmerdam <warmerdam at pobox.com>
- *
- ******************************************************************************
- * Copyright (c) 2003, Frank Warmerdma <warmerdam at pobox.com>
- *
- * 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.
- ****************************************************************************/
-
-#include <assert.h>
-#include <curl/curl.h>
-#include "cpl_minixml.h"
-#include "cpl_conv.h"
-#include "cpl_string.h"
-
-CPL_CVSID("$Id: wctsclient.cpp 10645 2007-01-18 02:22:39Z warmerdam $");
-
-/************************************************************************/
-/*                   WCTSClientEmitServiceException()                   */
-/************************************************************************/
-
-static void WCTSClientEmitServiceException( const char * pszMessage )
-
-{
-    printf("Content-type: text/html%c%c",10,10);
-
-    printf("<html><title>WCTS Client Error</title><body>\n" );
-    printf("<h1>WCTS Client Error</h1>\n" );
-    printf("%s\n", pszMessage );
-    printf("</html>\n" );
-
-    exit( 1 );
-}
-
-/************************************************************************/
-/*                        WCTSClientReturnXML()                         */
-/*                                                                      */
-/*      Return an XML document literally but properly typed.            */
-/************************************************************************/
-
-static void WCTSClientReturnXML( const char *pszXML )
-
-{
-    if( EQUALN(pszXML,"<?xml",5) )
-        printf("Content-type: text/xml%c%c",10,10);
-    else if( strstr(pszXML,"<HTML") != NULL
-             || strstr(pszXML,"<html") != NULL )
-        printf("Content-type: text/html%c%c",10,10);
-    else
-        printf("Content-type: text/plain%c%c",10,10);
-
-    printf("%s", pszXML );
-    
-    exit( 0 );
-}
-
-/************************************************************************/
-/*                         WCTSClientWriteFct()                         */
-/*                                                                      */
-/*      Append incoming text to our collection buffer, reallocating     */
-/*      it larger as needed.                                            */
-/************************************************************************/
-
-static size_t 
-WCTSClientWriteFct(void *buffer, size_t size, size_t nmemb, void *reqInfo)
-
-{
-    char **ppszWorkBuffer = (char **) reqInfo;
-    int  nNewSize, nOldSize;
-
-    if( *ppszWorkBuffer == NULL )
-        nOldSize = 0;
-    else
-        nOldSize = strlen(*ppszWorkBuffer);
-
-    nNewSize = nOldSize + nmemb * size + 1;
-
-    *ppszWorkBuffer = (char *) CPLRealloc(*ppszWorkBuffer, nNewSize);
-    strncpy( (*ppszWorkBuffer) + nOldSize, (char *) buffer, 
-             nmemb * size );
-    (*ppszWorkBuffer)[nNewSize-1] = '\0';
-
-    return nmemb;
-}
-
-/************************************************************************/
-/*                        WCTSClientHTTPFetch()                         */
-/*                                                                      */
-/*      Fetch a document from an url and return in a string.            */
-/************************************************************************/
-
-static char *WCTSClientHTTPFetch( const char *pszURL, const char *pszPostDoc )
-
-{
-    CURL *http_handle;
-    char *pszData = NULL;
-    char szCurlErrBuf[CURL_ERROR_SIZE+1];
-    CURLcode error;
-
-    CPLDebug( "WCTSCLIENT", "HTTP Fetch: %s", pszURL );
-
-    http_handle = curl_easy_init();
-
-    curl_easy_setopt(http_handle, CURLOPT_URL, pszURL );
-
-    /* Enable following redirections.  Requires libcurl 7.10.1 at least */
-    curl_easy_setopt(http_handle, CURLOPT_FOLLOWLOCATION, 1 );
-    curl_easy_setopt(http_handle, CURLOPT_MAXREDIRS, 10 );
-    
-    /* Set timeout.*/
-    curl_easy_setopt(http_handle, CURLOPT_TIMEOUT, 15 );
-
-    /* NOSIGNAL should be set to true for timeout to work in multithread
-     * environments on Unix, requires libcurl 7.10 or more recent.
-     * (this force avoiding the use of sgnal handlers)
-     */
-#ifdef CURLOPT_NOSIGNAL
-    curl_easy_setopt(http_handle, CURLOPT_NOSIGNAL, 1 );
-#endif
-
-    curl_easy_setopt(http_handle, CURLOPT_WRITEDATA, &pszData );
-    curl_easy_setopt(http_handle, CURLOPT_WRITEFUNCTION, WCTSClientWriteFct );
-
-    if( pszPostDoc != NULL )
-    {
-        curl_easy_setopt(http_handle, CURLOPT_POST, 1 );
-        curl_easy_setopt(http_handle, CURLOPT_POSTFIELDS, pszPostDoc );
-    }
-
-    szCurlErrBuf[0] = '\0';
-
-    curl_easy_setopt(http_handle, CURLOPT_ERRORBUFFER, szCurlErrBuf );
-
-    error = curl_easy_perform( http_handle );
-
-    curl_easy_cleanup( http_handle );
-
-    if( strlen(szCurlErrBuf) > 0 )
-        WCTSClientEmitServiceException( szCurlErrBuf );
-    else if( pszData == NULL )
-        WCTSClientEmitServiceException( "No response from WCTS server." );
-
-
-    return pszData;
-}
-
-/************************************************************************/
-/*                                main()                                */
-/************************************************************************/
-
-int main( int nArgc, char ** papszArgv )
-
-{
-    putenv( "CPL_LOG=/tmp/wctsclient.log" );
-    putenv( "CPL_DEBUG=ON" );
-
-/* ==================================================================== */
-/*      Collect client request.                                         */
-/* ==================================================================== */
-    char **papszParmList = NULL;
-
-/* -------------------------------------------------------------------- */
-/*      Parse the query string.                                         */
-/* -------------------------------------------------------------------- */
-    if( getenv("REQUEST_METHOD") == NULL
-        || !EQUAL(getenv("REQUEST_METHOD"),"POST") )
-    {
-        if( getenv("QUERY_STRING") == NULL )
-            WCTSClientEmitServiceException( "QUERY_STRING not set." );
-        
-        papszParmList = CSLTokenizeString2( getenv("QUERY_STRING"), "&",
-                                            CSLT_PRESERVEESCAPES );
-    }
-
-/* -------------------------------------------------------------------- */
-/*      Or parse the urlencoded text in the POST body (stdin)           */
-/* -------------------------------------------------------------------- */
-    else
-    {
-        int nContentLength = 0;
-        char *pszBody = NULL;
-        
-        if( getenv("CONTENT_LENGTH") != NULL )
-        {
-            nContentLength = atoi(getenv("CONTENT_LENGTH"));
-            
-            pszBody = (char *) CPLMalloc(nContentLength+1);
-            
-            if( (int) fread(pszBody, 1, nContentLength, stdin) < nContentLength )
-                WCTSClientEmitServiceException( "POST body is short." );
-            
-            pszBody[nContentLength] = '\0';
-        }
-        
-        else
-        {
-            int nBodyMax, nBodyLen=0;
-            
-            nBodyMax = 100;
-            pszBody = (char *) CPLMalloc(nBodyMax);
-            
-            while( !feof(stdin) )
-            {
-                pszBody[nBodyLen++] = fgetc(stdin);
-                if( nBodyLen == nBodyMax )
-                {
-                    nBodyMax = nBodyMax * 2;
-                    pszBody = (char *) CPLRealloc(pszBody, nBodyMax);
-                }
-            }
-            
-            pszBody[nBodyLen] = '\0';
-        }
-
-        papszParmList = CSLTokenizeString2( pszBody, "&",
-                                            CSLT_PRESERVEESCAPES );
-    }
-    
-/* -------------------------------------------------------------------- */
-/*      Un-url-encode the items.                                        */
-/* -------------------------------------------------------------------- */
-    int i;
-
-    for( i = 0; papszParmList != NULL && papszParmList[i] != NULL; i++ )
-    {
-        char *pszNewValue = CPLUnescapeString( papszParmList[i], 
-                                               NULL, CPLES_URL );
-        
-        CPLFree( papszParmList[i] );
-        papszParmList[i] = pszNewValue;
-    }
-
-/* -------------------------------------------------------------------- */
-/*	Fetch and default arguments.					*/
-/* -------------------------------------------------------------------- */
-    const char *pszRequest = CSLFetchNameValue(papszParmList,"Request");
-    const char *pszSourceCRS = CSLFetchNameValue(papszParmList,"SourceCRS");
-    const char *pszTargetCRS = CSLFetchNameValue(papszParmList,"TargetCRS");
-    const char *pszInputX = CSLFetchNameValue(papszParmList,"InputX");
-    const char *pszInputY = CSLFetchNameValue(papszParmList,"InputY");
-    const char *pszGMLURL = CSLFetchNameValue(papszParmList,"GMLURL");
-    const char *pszGMLData = CSLFetchNameValue(papszParmList,"GMLDATA");
-    const char *pszServer = CSLFetchNameValue(papszParmList,"WCTSServer");
-
-    if( pszRequest == NULL )
-        pszRequest = "Transform";
-
-    if( pszServer == NULL )
-        WCTSClientEmitServiceException( "WCTS Server not selected." );
-
-    CPLDebug( "WCTSCLIENT", "Request=%s", pszRequest );
-    CPLDebug( "WCTSCLIENT", "Server=%s", pszServer );
-
-/* ==================================================================== */
-/*      Handle a GetCapabilities request.                               */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "GetCapabilities" ) )
-    {
-        char *pszURL;
-        char *pszCapXML;
-
-        pszURL = CPLStrdup(
-            CPLSPrintf( "%s?REQUEST=GetCapabilities&Service=WCTS", 
-                        pszServer ));
-
-        pszCapXML = WCTSClientHTTPFetch( pszURL, NULL );
-        WCTSClientReturnXML( pszCapXML );
-    }
-
-/* ==================================================================== */
-/*      Handle IsTransformable request.                                 */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "IsTransformable" ) )
-    {
-        char *pszURL;
-        char *pszResultXML;
-
-        pszURL = CPLStrdup(
-            CPLSPrintf( "%s?REQUEST=IsTransformable&Service=WCTS"
-                        "&SourceCRS=EPSG:%s&TargetCRS=EPSG:%s", 
-                        pszServer, pszSourceCRS, pszTargetCRS ));
-
-        pszResultXML = WCTSClientHTTPFetch( pszURL, NULL );
-        WCTSClientReturnXML( pszResultXML );
-    }
-
-/* ==================================================================== */
-/*      Handle DescribeTransformation request.                          */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "DescribeTransformation" ) )
-    {
-        char *pszURL;
-        char *pszResultXML;
-
-        pszURL = CPLStrdup(
-            CPLSPrintf( "%s?REQUEST=DescribeTransformation&Service=WCTS"
-                        "&SourceCRS=EPSG:%s&TargetCRS=EPSG:%s", 
-                        pszServer, pszSourceCRS, pszTargetCRS ));
-
-        pszResultXML = WCTSClientHTTPFetch( pszURL, NULL );
-        WCTSClientReturnXML( pszResultXML );
-    }
-
-/* ==================================================================== */
-/*      Handle Transform request for a single point provided in the     */
-/*      form.                                                           */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "Transform" ) && pszGMLURL != NULL
-        && strlen(pszGMLURL) != 0 )
-    {
-/* -------------------------------------------------------------------- */
-/*      Prepare request.                                                */
-/* -------------------------------------------------------------------- */
-        char szReqDoc[10000];
-
-        sprintf( szReqDoc, 
-"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
-"<Transform xmlns=\"http://schemas.opengis.net/wcts\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:gml=\"http://www.opengis.net/gml\" version=\"0.1.0\">\n"
-"  <SourceCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </SourceCRS>\n"
-"  <TargetCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </TargetCRS>\n"
-"  <Data>\n"
-"    <FileURL>%s</FileURL>\n" 
-"  </Data>\n"
-"</Transform>\n",
-                 pszSourceCRS, pszTargetCRS, pszGMLURL );
-
-/* -------------------------------------------------------------------- */
-/*      Invoke Service.                                                 */
-/* -------------------------------------------------------------------- */
-        char *pszResultXML;
-
-        pszResultXML = WCTSClientHTTPFetch( pszServer, szReqDoc );
-
-/* -------------------------------------------------------------------- */
-/*      Display result.                                                 */
-/* -------------------------------------------------------------------- */
-        WCTSClientReturnXML( pszResultXML );
-    }
-
-/* ==================================================================== */
-/*      Handle Transform request for a single point provided in the     */
-/*      form.                                                           */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "Transform" ) && pszGMLData != NULL
-        && strlen(pszGMLData) != 0 )
-    {
-        
-/* -------------------------------------------------------------------- */
-/*      Skip past any <?xml> element.                                   */
-/* -------------------------------------------------------------------- */
-        if( EQUALN(pszGMLData,"<?xml", 5) )
-        {
-            
-            while( *pszGMLData != '\0' && !EQUALN(pszGMLData,"?>",2) )
-                pszGMLData++;
-
-            if( EQUALN(pszGMLData,"?>",2) )
-                pszGMLData += 2;
-        }
-        
-/* -------------------------------------------------------------------- */
-/*      Prepare request.                                                */
-/* -------------------------------------------------------------------- */
-        char *pszReqDoc;
-
-        pszReqDoc = (char *) CPLMalloc(strlen(pszGMLData) + 10000);
-
-        sprintf( pszReqDoc, 
-"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
-"<Transform xmlns=\"http://schemas.opengis.net/wcts\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:gml=\"http://www.opengis.net/gml\" version=\"0.1.0\">\n"
-"  <SourceCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </SourceCRS>\n"
-"  <TargetCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </TargetCRS>\n"
-"  <Data>\n"
-"%s\n" 
-"  </Data>\n"
-"</Transform>\n",
-                 pszSourceCRS, pszTargetCRS, pszGMLData );
-
-/* -------------------------------------------------------------------- */
-/*      Invoke Service.                                                 */
-/* -------------------------------------------------------------------- */
-        char *pszResultXML;
-
-        pszResultXML = WCTSClientHTTPFetch( pszServer, pszReqDoc );
-        CPLFree( pszReqDoc );
-
-/* -------------------------------------------------------------------- */
-/*      Display result.                                                 */
-/* -------------------------------------------------------------------- */
-        WCTSClientReturnXML( pszResultXML );
-    }
-
-/* ==================================================================== */
-/*      Handle Transform request for a single point provided in the     */
-/*      form.                                                           */
-/* ==================================================================== */
-    if( EQUAL( pszRequest, "Transform" ) )
-    {
-        char *pszResultXML;
-
-        if( pszInputX == NULL || pszInputY == NULL
-            || strlen(pszInputX) == 0 || strlen(pszInputY) == 0 )
-            WCTSClientEmitServiceException( "InputX or InputY missing or empty" );
-
-/* -------------------------------------------------------------------- */
-/*      Prepare an XML document representing the transformation to      */
-/*      be executed.                                                    */
-/* -------------------------------------------------------------------- */
-        char szReqDoc[10000];
-
-        sprintf( szReqDoc, 
-"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
-"<Transform xmlns=\"http://schemas.opengis.net/wcts\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:gml=\"http://www.opengis.net/gml\" version=\"0.1.0\">\n"
-"  <SourceCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </SourceCRS>\n"
-"  <TargetCRS>\n"
-"    <crsID>\n"
-"      <gml:code>%s</gml:code>\n"
-"      <gml:codeSpace>EPSG</gml:codeSpace>\n"
-"    </crsID>\n"
-"  </TargetCRS>\n"
-"  <Data>\n"
-"    <TrFeature fid=\"0\">\n"
-"      <gml:geometryProperty>\n"
-"        <gml:Point>\n"
-"          <gml:coordinates>%s,%s</gml:coordinates>\n"
-"        </gml:Point>\n"
-"      </gml:geometryProperty>\n"
-"    </TrFeature>\n"
-"  </Data>\n"
-"</Transform>\n",
-                 pszSourceCRS, pszTargetCRS, pszInputX, pszInputY );
-
-/* -------------------------------------------------------------------- */
-/*      Invoke Service.                                                 */
-/* -------------------------------------------------------------------- */
-        pszResultXML = WCTSClientHTTPFetch( pszServer, szReqDoc );
-
-/* -------------------------------------------------------------------- */
-/*      Display result.                                                 */
-/* -------------------------------------------------------------------- */
-        char *pszCoord = strstr(pszResultXML,"<gml:coordinates>");
-
-        if( pszCoord != NULL )
-        {
-            pszCoord += 17;
-            char *pszEnd = pszCoord;
-            while( *pszEnd != '\0' && *pszEnd != '<' )
-                pszEnd++;
-
-            *pszEnd = '\0';
-
-            printf( "Content-type: text/html\n\n" );
-            printf( "<html><body>\n" );
-            printf( "Transformed coordinate: <b>%s</b>", pszCoord );
-            printf( "<body></html>\n" );
-            exit( 0 );
-        }
-        else
-        {
-            WCTSClientReturnXML( pszResultXML );
-        }
-    }
-
-/* ==================================================================== */
-/*      No request match.                                               */
-/* ==================================================================== */
-    WCTSClientEmitServiceException( 
-        CPLSPrintf( "REQUEST=%s not supported.", pszRequest ) );
-}
-
-/*
-REQUEST_URI="/cgi-bin/printenv?H=1"
-SERVER_NAME="gdal.velocet.ca"
-*/
diff --git a/port/GNUmakefile b/port/GNUmakefile
index 6ad69b7..e9949d2 100644
--- a/port/GNUmakefile
+++ b/port/GNUmakefile
@@ -1,7 +1,6 @@
 #
 # CPL (Common Portability Library) makefile
 #
-
 ifneq ($(wildcard ../GDALmake.op?),)
 include ../GDALmake.opt
 else
diff --git a/port/cpl_atomic_ops.cpp b/port/cpl_atomic_ops.cpp
index fee48b5..76965be 100644
--- a/port/cpl_atomic_ops.cpp
+++ b/port/cpl_atomic_ops.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_atomic_ops.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_atomic_ops.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Name:     cpl_atomic_ops.cpp
  * Project:  CPL - Common Portability Library
@@ -99,7 +99,7 @@ int CPLAtomicAdd(volatile int* ptr, int increment)
 
 #include "cpl_multiproc.h"
 
-static void *hAtomicOpMutex = NULL;
+static CPLMutex *hAtomicOpMutex = NULL;
 
 /* Slow, but safe, implemenation using a mutex */
 int CPLAtomicAdd(volatile int* ptr, int increment)
@@ -110,17 +110,3 @@ int CPLAtomicAdd(volatile int* ptr, int increment)
 }
 
 #endif
-
-#ifndef HAS_CPL_INLINE
-
-int CPLAtomicInc(volatile int* ptr)
-{
-    return CPLAtomicAdd(ptr, 1);
-}
-
-int CPLAtomicDec(volatile int* ptr)
-{
-    return CPLAtomicAdd(ptr, -1);
-}
-
-#endif
diff --git a/port/cpl_atomic_ops.h b/port/cpl_atomic_ops.h
index 29416be..efe9193 100644
--- a/port/cpl_atomic_ops.h
+++ b/port/cpl_atomic_ops.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_atomic_ops.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_atomic_ops.h 27869 2014-10-17 02:22:42Z rouault $
  *
  * Name:     cpl_atomic_ops.h
  * Project:  CPL - Common Portability Library
@@ -69,14 +69,7 @@ int CPL_DLL CPLAtomicAdd(volatile int* ptr, int increment);
   * @param ptr a pointer to an integer to increment
   * @return the pointed value AFTER the opeation: *ptr + 1
   */
-#ifdef HAS_CPL_INLINE
-CPL_INLINE int CPLAtomicInc(volatile int* ptr)
-{
-    return CPLAtomicAdd(ptr, 1);
-}
-#else
-int CPL_DLL CPLAtomicInc(volatile int* ptr);
-#endif
+#define CPLAtomicInc(ptr) CPLAtomicAdd(ptr, 1)
 
 /** Decrement of 1 the pointed integer in a thread and SMP-safe way
   * and return the resulting value of the operation.
@@ -87,14 +80,7 @@ int CPL_DLL CPLAtomicInc(volatile int* ptr);
   * @param ptr a pointer to an integer to decrement
   * @return the pointed value AFTER the opeation: *ptr - 1
   */
-#ifdef HAS_CPL_INLINE
-CPL_INLINE int CPLAtomicDec(volatile int* ptr)
-{
-    return CPLAtomicAdd(ptr, -1);
-}
-#else
-int CPL_DLL CPLAtomicDec(volatile int* ptr);
-#endif
+#define CPLAtomicDec(ptr) CPLAtomicAdd(ptr, -1)
 
 CPL_C_END
 
diff --git a/port/cpl_config.h.in b/port/cpl_config.h.in
index e9f3c80..313729f 100644
--- a/port/cpl_config.h.in
+++ b/port/cpl_config.h.in
@@ -6,6 +6,15 @@
 /* Define to 1 if you have the `PTHREAD_MUTEX_RECURSIVE' constant. */
 #undef HAVE_PTHREAD_MUTEX_RECURSIVE
 
+/* Define to 1 if you have the `PTHREAD_MUTEX_ADAPTIVE_NP' constant. */
+#undef HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
+
+/* Define to 1 if you have the `pthread_spinlock_t' type. */
+#undef HAVE_PTHREAD_SPINLOCK
+
+/* Define to 1 if you have the 5 args `mremap' function. */
+#undef HAVE_5ARGS_MREMAP
+
 /* --prefix directory for GDAL install */
 #undef GDAL_PREFIX
 
@@ -214,6 +223,9 @@
 /* Define to 1 if you have the `getaddrinfo' function. */
 #undef HAVE_GETADDRINFO
 
+/* Define to 1 if you have the _SC_PHYS_PAGES' constant. */
+#undef HAVE_SC_PHYS_PAGES
+
 /* Use this file to override settings in instances where you're doing FAT compiles
    on Apple.  It is currently off by default because it doesn't seem to work with 
    newish ( XCode >= 3/28/11) XCodes */
diff --git a/port/cpl_config.h.vc b/port/cpl_config.h.vc
index bfff8f6..8fd4641 100644
--- a/port/cpl_config.h.vc
+++ b/port/cpl_config.h.vc
@@ -17,7 +17,9 @@
 #if defined(_MSC_VER) && (_MSC_VER < 1500)
 #  define vsnprintf _vsnprintf
 #endif
-#define snprintf _snprintf
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+#  define snprintf _snprintf
+#endif
 
 #define HAVE_GETCWD 1
 /* gmt_notunix.h from GMT project also redefines getcwd. See #3138 */
diff --git a/port/cpl_conv.cpp b/port/cpl_conv.cpp
index 876434e..5fbffff 100644
--- a/port/cpl_conv.cpp
+++ b/port/cpl_conv.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_conv.cpp 27550 2014-07-25 20:43:52Z rouault $
+ * $Id: cpl_conv.cpp 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Convenience functions.
@@ -34,23 +34,24 @@
 #include "cpl_string.h"
 #include "cpl_vsi.h"
 #include "cpl_multiproc.h"
+#include <errno.h>
 
-CPL_CVSID("$Id: cpl_conv.cpp 27550 2014-07-25 20:43:52Z rouault $");
+CPL_CVSID("$Id: cpl_conv.cpp 28601 2015-03-03 11:06:40Z rouault $");
 
 #if defined(WIN32CE)
 #  include "cpl_wince.h"
 #endif
 
-static void *hConfigMutex = NULL;
+static CPLMutex *hConfigMutex = NULL;
 static volatile char **papszConfigOptions = NULL;
 
 /* Used by CPLOpenShared() and friends */
-static void *hSharedFileMutex = NULL;
+static CPLMutex *hSharedFileMutex = NULL;
 static volatile int nSharedFileCount = 0;
 static volatile CPLSharedFileInfo *pasSharedFileList = NULL;
 
 /* Used by CPLsetlocale() */
-static void *hSetLocaleMutex = NULL;
+static CPLMutex *hSetLocaleMutex = NULL;
 
 /* Note: ideally this should be added in CPLSharedFileInfo* */
 /* but CPLSharedFileInfo is exposed in the API, hence that trick */
@@ -928,6 +929,93 @@ GUIntBig CPLScanUIntBig( const char *pszString, int nMaxLength )
 }
 
 /************************************************************************/
+/*                           CPLAtoGIntBig()                            */
+/************************************************************************/
+
+/**
+ * Convert a string to a 64 bit signed integer.
+ * 
+ * @param pszString String containing 64 bit signed integer.
+ * @return 64 bit signed integer.
+ * @since GDAL 2.0
+ */
+
+GIntBig CPLAtoGIntBig( const char* pszString )
+{
+#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
+    return _atoi64( pszString );
+# elif HAVE_ATOLL
+    return atoll( pszString );
+#else
+    return atol( pszString );
+#endif
+}
+
+#if defined(__MINGW32__)
+
+// mingw atoll() doesn't return ERANGE in case of overflow
+int CPLAtoGIntBigExHasOverflow(const char* pszString, GIntBig nVal)
+{
+    if( strlen(pszString) <= 18 )
+        return FALSE;
+    while( *pszString == ' ' )
+        pszString ++;
+    if( *pszString == '+' )
+        pszString ++;
+    char szBuffer[32];
+    sprintf(szBuffer, CPL_FRMT_GIB, nVal);
+    return strcmp(szBuffer, pszString) != 0;
+}
+
+#endif
+
+/************************************************************************/
+/*                          CPLAtoGIntBigEx()                           */
+/************************************************************************/
+
+/**
+ * Convert a string to a 64 bit signed integer.
+ * 
+ * @param pszString String containing 64 bit signed integer.
+ * @param bWarn Issue a warning if an overflow occurs during conversion
+ * @param pbOverflow Pointer to an integer to store if an overflow occured, or NULL
+ * @return 64 bit signed integer.
+ * @since GDAL 2.0
+ */
+
+GIntBig CPLAtoGIntBigEx( const char* pszString, int bWarn, int *pbOverflow )
+{
+    GIntBig nVal;
+    errno = 0;
+#if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
+    nVal = _atoi64( pszString );
+# elif HAVE_ATOLL
+    nVal = atoll( pszString );
+#else
+    nVal = atol( pszString );
+#endif
+    if( errno == ERANGE
+#if defined(__MINGW32__)
+        || CPLAtoGIntBigExHasOverflow(pszString, nVal)
+#endif
+        )
+    {
+        if( pbOverflow ) *pbOverflow = TRUE;
+        if( bWarn )
+        {
+            CPLError(CE_Warning, CPLE_AppDefined,
+                     "64 bit integer overflow when converting %s",
+                     pszString);
+        }
+        while( *pszString == ' ' )
+            pszString ++;
+        return (*pszString == '-' ) ? GINTBIG_MIN : GINTBIG_MAX;
+    }
+    else if( pbOverflow ) *pbOverflow = FALSE;
+    return nVal;
+}
+
+/************************************************************************/
 /*                           CPLScanPointer()                           */
 /************************************************************************/
 
@@ -1282,54 +1370,28 @@ int CPLPrintPointer( char *pszBuffer, void *pValue, int nMaxLen )
  */
 
 int CPLPrintDouble( char *pszBuffer, const char *pszFormat,
-                    double dfValue, const char *pszLocale )
+                    double dfValue, CPL_UNUSED const char *pszLocale )
 {
-
-#define DOUBLE_BUFFER_SIZE 64
-
-    char    szTemp[DOUBLE_BUFFER_SIZE];
-    int     i;
-
     if ( !pszBuffer )
         return 0;
 
-#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
-    char        *pszCurLocale = NULL;
-
-    if ( pszLocale || EQUAL( pszLocale, "" ) )
-    {
-        // Save the current locale
-        pszCurLocale = CPLsetlocale(LC_ALL, NULL );
-        // Set locale to the specified value
-        CPLsetlocale( LC_ALL, pszLocale );
-    }
-#else
-    (void) pszLocale;
-#endif
+    const int double_buffer_size = 64;
+    char szTemp[double_buffer_size];
 
 #if defined(HAVE_SNPRINTF)
-    snprintf( szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue );
+    CPLsnprintf( szTemp, double_buffer_size, pszFormat, dfValue );
 #else
-    sprintf( szTemp, pszFormat, dfValue );
+    CPLsprintf( szTemp, pszFormat, dfValue );
 #endif
-    szTemp[DOUBLE_BUFFER_SIZE - 1] = '\0';
+    szTemp[double_buffer_size - 1] = '\0';
 
-    for( i = 0; szTemp[i] != '\0'; i++ )
+    for( int i = 0; szTemp[i] != '\0'; i++ )
     {
         if( szTemp[i] == 'E' || szTemp[i] == 'e' )
             szTemp[i] = 'D';
     }
 
-#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
-    // Restore stored locale back
-    if ( pszCurLocale )
-        CPLsetlocale( LC_ALL, pszCurLocale );
-#endif
-
     return CPLPrintString( pszBuffer, szTemp, 64 );
-
-#undef DOUBLE_BUFFER_SIZE
-
 }
 
 /************************************************************************/
@@ -1531,7 +1593,7 @@ static void CPLAccessConfigOption(const char* pszKey, int bGet)
   *     char* pszOldVal = pszOldValTmp ? CPLStrdup(pszOldValTmp) : NULL;
   *     // override with new value
   *     CPLSetConfigOption(pszKey, pszNewVal);
-  *     // do something usefull
+  *     // do something useful
   *     // restore old value
   *     CPLSetConfigOption(pszKey, pszOldVal);
   *     CPLFree(pszOldVal);
@@ -1736,7 +1798,7 @@ proj_strtod(char *nptr, char **endptr)
              * then restore it and return
              */
             *cp = '\0';
-            result = strtod(nptr, endptr);
+            result = CPLStrtod(nptr, endptr);
             *cp = c;
             return result;
         }
@@ -1745,7 +1807,7 @@ proj_strtod(char *nptr, char **endptr)
 
     /* no offending characters, just handle normally */
 
-    return strtod(nptr, endptr);
+    return CPLStrtod(nptr, endptr);
 }
 
 /************************************************************************/
@@ -1857,8 +1919,8 @@ const char *CPLDecToDMS( double dfAngle, const char * pszAxis,
     else
         pszHemisphere = "N";
 
-    sprintf( szFormat, "%%3dd%%2d\'%%%d.%df\"%s", nPrecision+3, nPrecision, pszHemisphere );
-    sprintf( szBuffer, szFormat, nDegrees, nMinutes, dfSeconds );
+    CPLsprintf( szFormat, "%%3dd%%2d\'%%%d.%df\"%s", nPrecision+3, nPrecision, pszHemisphere );
+    CPLsprintf( szBuffer, szFormat, nDegrees, nMinutes, dfSeconds );
 
     return( szBuffer );
 }
@@ -2244,7 +2306,7 @@ int CPLUnlinkTree( const char *pszPath )
 
 {
 /* -------------------------------------------------------------------- */
-/*      First, ensure there isn't any such file yet.                    */
+/*      First, ensure there is such a file.                             */
 /* -------------------------------------------------------------------- */
     VSIStatBufL sStatBuf;
 
@@ -2385,6 +2447,88 @@ int CPLCopyFile( const char *pszNewPath, const char *pszOldPath )
 }
 
 /************************************************************************/
+/*                            CPLCopyTree()                             */
+/************************************************************************/
+
+int CPLCopyTree( const char *pszNewPath, const char *pszOldPath )
+
+{
+    VSIStatBufL sStatBuf;
+
+    if( VSIStatL( pszOldPath, &sStatBuf ) != 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "It seems no file system object called '%s' exists.",
+                  pszOldPath );
+
+        return -1;
+    }
+    if( VSIStatL( pszNewPath, &sStatBuf ) == 0 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "It seems that a file system object called '%s' already exists.",
+                  pszNewPath );
+
+        return -1;
+    }
+
+    if( VSI_ISDIR( sStatBuf.st_mode ) )
+    {
+        if( VSIMkdir( pszNewPath, 0755 ) != 0 )
+        {
+            CPLError( CE_Failure, CPLE_AppDefined, 
+                    "Cannot create directory '%s'.",
+                    pszNewPath );
+
+            return -1;
+        }
+
+        char **papszItems = CPLReadDir( pszOldPath );
+        int  i;
+
+        for( i = 0; papszItems != NULL && papszItems[i] != NULL; i++ )
+        {
+            char *pszNewSubPath;
+            char *pszOldSubPath;
+            int nErr;
+
+            if( EQUAL(papszItems[i],".") || EQUAL(papszItems[i],"..") )
+                continue;
+
+            pszNewSubPath = CPLStrdup(
+                CPLFormFilename( pszNewPath, papszItems[i], NULL ) );
+            pszOldSubPath = CPLStrdup(
+                CPLFormFilename( pszOldPath, papszItems[i], NULL ) );
+
+            nErr = CPLCopyTree( pszNewSubPath, pszOldSubPath );
+
+            CPLFree( pszNewSubPath );
+            CPLFree( pszOldSubPath );
+
+            if( nErr != 0 )
+            {
+                CSLDestroy( papszItems );
+                return nErr;
+            }
+        }
+        CSLDestroy( papszItems );
+
+        return 0;
+    }
+    else if( VSI_ISREG( sStatBuf.st_mode ) )
+    {
+        return CPLCopyFile( pszNewPath, pszOldPath );
+    }
+    else
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Unrecognised filesystem object : '%s'.",
+                  pszOldPath );
+        return -1;
+    }
+}
+
+/************************************************************************/
 /*                            CPLMoveFile()                             */
 /************************************************************************/
 
@@ -2460,6 +2604,9 @@ CPLLocaleC::~CPLLocaleC()
  * potential data race. A mutex is used to provide a critical region so
  * that only one thread at a time can be executing setlocale().
  *
+ * The return should not be freed, and copied quickly as it may be invalidated
+ * by a following next call to CPLsetlocale().
+ *
  * @param category See your compiler's documentation on setlocale.
  * @param locale See your compiler's documentation on setlocale.
  *
@@ -2468,7 +2615,10 @@ CPLLocaleC::~CPLLocaleC()
 char* CPLsetlocale (int category, const char* locale)
 {
     CPLMutexHolder oHolder(&hSetLocaleMutex);
-    return setlocale(category, locale);
+    char* pszRet = setlocale(category, locale);
+    if( pszRet == NULL )
+        return pszRet;
+    return (char*)CPLSPrintf("%s", pszRet); /* to make it thread-locale storage */
 }
 
 
diff --git a/port/cpl_conv.h b/port/cpl_conv.h
index 660652a..45ca021 100644
--- a/port/cpl_conv.h
+++ b/port/cpl_conv.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_conv.h 27121 2014-04-03 22:08:55Z rouault $
+ * $Id: cpl_conv.h 28601 2015-03-03 11:06:40Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Convenience functions declarations.
@@ -102,6 +102,8 @@ double CPL_DLL CPLScanDouble( const char *, int );
 long CPL_DLL CPLScanLong( const char *, int );
 unsigned long CPL_DLL CPLScanULong( const char *, int );
 GUIntBig CPL_DLL CPLScanUIntBig( const char *, int );
+GIntBig CPL_DLL CPLAtoGIntBig( const char* pszString );
+GIntBig CPL_DLL CPLAtoGIntBigEx( const char* pszString, int bWarn, int *pbOverflow );
 void CPL_DLL *CPLScanPointer( const char *, int );
 
 /* -------------------------------------------------------------------- */
@@ -210,6 +212,7 @@ void CPL_DLL CPLStringToComplex( const char *pszString,
 /* -------------------------------------------------------------------- */
 int CPL_DLL CPLUnlinkTree( const char * );
 int CPL_DLL CPLCopyFile( const char *pszNewPath, const char *pszOldPath );
+int CPL_DLL CPLCopyTree( const char *pszNewPath, const char *pszOldPath );
 int CPL_DLL CPLMoveFile( const char *pszNewPath, const char *pszOldPath );
 
 /* -------------------------------------------------------------------- */
diff --git a/port/cpl_csv.cpp b/port/cpl_csv.cpp
index 8239f8a..12322e8 100644
--- a/port/cpl_csv.cpp
+++ b/port/cpl_csv.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_csv.cpp 27958 2014-11-13 21:58:48Z goatbar $
+ * $Id: cpl_csv.cpp 28039 2014-11-30 18:24:59Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  CSV (comma separated value) file access.
@@ -33,7 +33,7 @@
 #include "cpl_multiproc.h"
 #include "gdal_csv.h"
 
-CPL_CVSID("$Id: cpl_csv.cpp 27958 2014-11-13 21:58:48Z goatbar $");
+CPL_CVSID("$Id: cpl_csv.cpp 28039 2014-11-30 18:24:59Z rouault $");
 
 /* ==================================================================== */
 /*      The CSVTable is a persistant set of info about an open CSV      */
@@ -464,7 +464,7 @@ char CSVDetectSeperator (const char* pszLine)
             else if (chDelimiter != *pszLine)
             {
                 /* The separator is not consistant on the line. */
-                CPLDebug("CSV", "Inconsistant separator. '%c' and '%c' found. Using ',' as default",
+                CPLDebug("CSV", "Inconsistent separator. '%c' and '%c' found. Using ',' as default",
                          chDelimiter, *pszLine);
                 chDelimiter = ',';
                 break;
diff --git a/port/cpl_error.cpp b/port/cpl_error.cpp
index a379801..c55be0b 100644
--- a/port/cpl_error.cpp
+++ b/port/cpl_error.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_error.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_error.cpp 28831 2015-04-01 16:46:05Z rouault $
  *
  * Name:     cpl_error.cpp
  * Project:  CPL - Common Portability Library
@@ -30,6 +30,7 @@
  ****************************************************************************/
 
 #include "cpl_error.h"
+#include "cpl_string.h"
 #include "cpl_vsi.h"
 #include "cpl_conv.h"
 #include "cpl_multiproc.h"
@@ -42,9 +43,9 @@
 #define TIMESTAMP_DEBUG
 //#define MEMORY_DEBUG
 
-CPL_CVSID("$Id: cpl_error.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_error.cpp 28831 2015-04-01 16:46:05Z rouault $");
 
-static void *hErrorMutex = NULL;
+static CPLMutex *hErrorMutex = NULL;
 static void *pErrorHandlerUserData = NULL; 
 static CPLErrorHandler pfnErrorHandler = CPLDefaultErrorHandler;
 
@@ -139,7 +140,7 @@ void* CPL_STDCALL CPLGetErrorHandlerUserData(void)
  *
  * The default behaviour of CPLError() is to report errors to stderr,
  * and to abort() after reporting a CE_Fatal error.  It is expected that
- * some applications will want to supress error reporting, and will want to
+ * some applications will want to suppress error reporting, and will want to
  * install a C++ exception, or longjmp() approach to no local fatal error
  * recovery.
  *
@@ -214,7 +215,7 @@ void    CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
             }
         }
 
-        while( ((nPR = vsnprintf( psCtx->szLastErrMsg+nPreviousSize, 
+        while( ((nPR = CPLvsnprintf( psCtx->szLastErrMsg+nPreviousSize, 
                                  psCtx->nLastErrMsgMax-nPreviousSize, fmt, wrk_args )) == -1
                 || nPR >= psCtx->nLastErrMsgMax-nPreviousSize-1)
                && psCtx->nLastErrMsgMax < 1000000 )
@@ -234,11 +235,27 @@ void    CPLErrorV(CPLErr eErrClass, int err_no, const char *fmt, va_list args )
         va_end( wrk_args );
     }
 #else
-    vsprintf( psCtx->szLastErrMsg, fmt, args);
+    // !HAVE_VSNPRINTF
+    CPLvsnprintf( psCtx->szLastErrMsg, psCtx->nLastErrMsgMax, fmt, args);
 #endif
 
 /* -------------------------------------------------------------------- */
-/*      If the user provided his own error handling function, then      */
+/*      Obfuscate any password in error message                         */
+/* -------------------------------------------------------------------- */
+
+    char* pszPassword = strstr(psCtx->szLastErrMsg, "password=");
+    if( pszPassword != NULL )
+    {
+        char* pszIter = pszPassword + strlen("password=");
+        while( *pszIter != ' ' && *pszIter != '\0' )
+        {
+            *pszIter = 'X';
+            pszIter ++;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
+/*      If the user provided an handling function, then                 */
 /*      call it, otherwise print the error to stderr and return.        */
 /* -------------------------------------------------------------------- */
     psCtx->nLastErrNo = err_no;
@@ -439,7 +456,7 @@ void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
 /* -------------------------------------------------------------------- */
 #ifdef MEMORY_DEBUG
     char szVmSize[32];
-    sprintf( szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
+    CPLsprintf( szVmSize, "[VmSize: %d] ", CPLGetProcessMemorySize());
     strcat( pszMessage, szVmSize );
 #endif
 
@@ -455,15 +472,28 @@ void CPLDebug( const char * pszCategory, const char * pszFormat, ... )
 /*      Format the application provided portion of the debug message.   */
 /* -------------------------------------------------------------------- */
     va_start(args, pszFormat);
-#if defined(HAVE_VSNPRINTF)
-    vsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage), 
+
+    CPLvsnprintf(pszMessage+strlen(pszMessage), ERROR_MAX - strlen(pszMessage), 
               pszFormat, args);
-#else
-    vsprintf(pszMessage+strlen(pszMessage), pszFormat, args);
-#endif
+
     va_end(args);
 
 /* -------------------------------------------------------------------- */
+/*      Obfuscate any password in error message                         */
+/* -------------------------------------------------------------------- */
+
+    char* pszPassword = strstr(pszMessage, "password=");
+    if( pszPassword != NULL )
+    {
+        char* pszIter = pszPassword + strlen("password=");
+        while( *pszIter != ' ' && *pszIter != '\0' )
+        {
+            *pszIter = 'X';
+            pszIter ++;
+        }
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Invoke the current error handler.                               */
 /* -------------------------------------------------------------------- */
     if( psCtx->psHandlerStack != NULL )
@@ -500,6 +530,28 @@ void CPL_STDCALL CPLErrorReset()
     psCtx->eLastErrType = CE_None;
 }
 
+/**********************************************************************
+ *                       CPLErrorSetState()
+ **********************************************************************/
+
+/**
+ * Restore an error state, without emitting an error.
+ *
+ * Can be usefull if a routine might call CPLErrorReset() and one wants to
+ * preserve the previous error state.
+ *
+ * @since GDAL 2.0
+ */
+
+void CPL_DLL CPLErrorSetState( CPLErr eErrClass, int err_no, const char* pszMsg )
+{
+    CPLErrorContext *psCtx = CPLGetErrorContext();
+
+    psCtx->nLastErrNo = err_no;
+    strncpy(psCtx->szLastErrMsg, pszMsg, psCtx->nLastErrMsgMax);
+    psCtx->szLastErrMsg[MAX(psCtx->nLastErrMsgMax-1, (int)strlen(pszMsg))] = '\0';
+    psCtx->eLastErrType = eErrClass;
+}
 
 /**********************************************************************
  *                          CPLGetLastErrorNo()
@@ -598,7 +650,10 @@ void CPL_STDCALL CPLDefaultErrorHandler( CPLErr eErrClass, int nError,
         fpLog = stderr;
         if( CPLGetConfigOption( "CPL_LOG", NULL ) != NULL )
         {
-            fpLog = fopen( CPLGetConfigOption("CPL_LOG",""), "wt" );
+            const char* pszAccess = "wt";
+            if( CPLGetConfigOption( "CPL_LOG_APPEND", NULL ) != NULL )
+                pszAccess = "at";
+            fpLog = fopen( CPLGetConfigOption("CPL_LOG",""), pszAccess );
             if( fpLog == NULL )
                 fpLog = stderr;
         }
@@ -677,21 +732,21 @@ void CPL_STDCALL CPLLoggingErrorHandler( CPLErr eErrClass, int nError,
                 /* generate sequenced log file names, inserting # before ext.*/
                 if (strrchr(cpl_log, '.') == NULL)
                 {
-                    sprintf( pszPath, "%s_%d%s", cpl_log, i++,
+                    CPLsprintf( pszPath, "%s_%d%s", cpl_log, i++,
                              ".log" );
                 }
                 else
                 {
                     size_t pos = 0;
-                    char *cpl_log_base = strdup(cpl_log);
+                    char *cpl_log_base = CPLStrdup(cpl_log);
                     pos = strcspn(cpl_log_base, ".");
                     if (pos > 0)
                     {
                         cpl_log_base[pos] = '\0';
                     }
-                    sprintf( pszPath, "%s_%d%s", cpl_log_base,
+                    CPLsprintf( pszPath, "%s_%d%s", cpl_log_base,
                              i++, ".log" );
-                    free(cpl_log_base);
+                    CPLFree(cpl_log_base);
                 }
             }
 
@@ -781,7 +836,7 @@ CPLSetErrorHandlerEx( CPLErrorHandler pfnErrorHandlerNew,
 /**
  * Install custom error handler.
  *
- * Allow the library's user to specify his own error handler function.
+ * Allow the library's user to specify an error handler function.
  * A valid error handler is a C function with the following prototype:
  *
  * <pre>
diff --git a/port/cpl_error.h b/port/cpl_error.h
index bac9bc1..4938960 100644
--- a/port/cpl_error.h
+++ b/port/cpl_error.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_error.h 26282 2013-08-08 21:15:36Z rouault $
+ * $Id: cpl_error.h 27384 2014-05-24 12:28:12Z rouault $
  *
  * Name:     cpl_error.h
  * Project:  CPL - Common Portability Library
@@ -62,6 +62,7 @@ int CPL_DLL CPL_STDCALL CPLGetLastErrorNo( void );
 CPLErr CPL_DLL CPL_STDCALL CPLGetLastErrorType( void );
 const char CPL_DLL * CPL_STDCALL CPLGetLastErrorMsg( void );
 void CPL_DLL * CPL_STDCALL CPLGetErrorHandlerUserData(void);
+void CPL_DLL CPLErrorSetState( CPLErr eErrClass, int err_no, const char* pszMsg );
 void CPL_DLL CPLCleanupErrorMutex( void );
 
 typedef void (CPL_STDCALL *CPLErrorHandler)(CPLErr, int, const char*);
diff --git a/port/cpl_findfile.cpp b/port/cpl_findfile.cpp
index 84184fe..e7416f8 100644
--- a/port/cpl_findfile.cpp
+++ b/port/cpl_findfile.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_findfile.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_findfile.cpp 27547 2014-07-23 16:27:50Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Generic data file location finder, with application hooking.
@@ -32,7 +32,7 @@
 #include "cpl_string.h"
 #include "cpl_multiproc.h"
 
-CPL_CVSID("$Id: cpl_findfile.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_findfile.cpp 27547 2014-07-23 16:27:50Z goatbar $");
 
 typedef struct
 {
@@ -128,7 +128,7 @@ void CPLFinderClean()
 }
 
 /************************************************************************/
-/*                         CPLDefaultFileFind()                         */
+/*                         CPLDefaultFindFile()                         */
 /************************************************************************/
 
 const char *CPLDefaultFindFile( const char *pszClass, 
diff --git a/port/cpl_getexecpath.cpp b/port/cpl_getexecpath.cpp
index 5ffa9a5..cea3977 100644
--- a/port/cpl_getexecpath.cpp
+++ b/port/cpl_getexecpath.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_getexecpath.cpp 27720 2014-09-21 17:58:47Z goatbar $
+ * $Id: cpl_getexecpath.cpp 27721 2014-09-22 12:42:28Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement CPLGetExecPath().
@@ -30,7 +30,7 @@
 #include "cpl_conv.h"
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: cpl_getexecpath.cpp 27720 2014-09-21 17:58:47Z goatbar $");
+CPL_CVSID("$Id: cpl_getexecpath.cpp 27721 2014-09-22 12:42:28Z goatbar $");
 
 #if defined(WIN32) || defined(WIN32CE)
 
diff --git a/port/cpl_google_oauth2.cpp b/port/cpl_google_oauth2.cpp
index 1be6acf..32ecaf6 100644
--- a/port/cpl_google_oauth2.cpp
+++ b/port/cpl_google_oauth2.cpp
@@ -270,7 +270,7 @@ char CPL_DLL *GOA2GetRefreshToken( const char *pszAuthToken,
  * @return access token, to be freed with CPLFree(), null on failure.
  */
 
-char *GOA2GetAccessToken( const char *pszRefreshToken, 
+char *GOA2GetAccessToken( const char *pszRefreshToken,
                           CPL_UNUSED const char *pszScope )
 {
 /* -------------------------------------------------------------------- */
@@ -345,6 +345,3 @@ char *GOA2GetAccessToken( const char *pszRefreshToken,
     else 
         return CPLStrdup(osAccessToken);
 }
-
-
-
diff --git a/port/cpl_http.cpp b/port/cpl_http.cpp
index 498400e..13dadf6 100644
--- a/port/cpl_http.cpp
+++ b/port/cpl_http.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_http.cpp 27517 2014-07-11 18:12:54Z kyle $
+ * $Id: cpl_http.cpp 29152 2015-05-04 11:45:44Z rouault $
  *
  * Project:  libcurl based HTTP client
  * Purpose:  libcurl based HTTP client
@@ -44,13 +44,13 @@ void CPLHTTPSetOptions(CURL *http_handle, char** papszOptions);
 
 #endif
 
-CPL_CVSID("$Id: cpl_http.cpp 27517 2014-07-11 18:12:54Z kyle $");
+CPL_CVSID("$Id: cpl_http.cpp 29152 2015-05-04 11:45:44Z rouault $");
 
 // list of named persistent http sessions 
 
 #ifdef HAVE_CURL
-static std::map<CPLString,CURL*> oSessionMap;
-static void *hSessionMapMutex = NULL;
+static std::map<CPLString,CURL*>* poSessionMap = NULL;
+static CPLMutex *hSessionMapMutex = NULL;
 #endif
 
 /************************************************************************/
@@ -138,14 +138,17 @@ static size_t CPLHdrWriteFct(void *buffer, size_t size, size_t nmemb, void *reqI
  * <li>PROXYAUTH=[BASIC/NTLM/DIGEST/ANY] to specify an proxy authentication scheme to use.
  * <li>NETRC=[YES/NO] to enable or disable use of $HOME/.netrc, default YES.
  * <li>CUSTOMREQUEST=val, where val is GET, PUT, POST, DELETE, etc.. (GDAL >= 1.9.0)
+ * <li>COOKIE=val, where val is formatted as COOKIE1=VALUE1; COOKIE2=VALUE2; ...
+ * <li>MAX_RETRY=val, where val is the maximum number of retry attempts if a 503 or
+ *               504 HTTP error occurs. Default is 0. (GDAL >= 2.0)
+ * <li>RETRY_DELAY=val, where val is the number of seconds between retry attempts.
+ *                 Default is 30. (GDAL >= 2.0)
  * </ul>
  *
  * Alternatively, if not defined in the papszOptions arguments, the PROXY,  
- * PROXYUSERPWD, PROXYAUTH and NETRC values are searched in the configuration 
- * options named GDAL_HTTP_PROXY, GDAL_HTTP_PROXYUSERPWD, GDAL_PROXY_AUTH and 
- * GDAL_HTTP_NETRC, as proxy configuration belongs to networking setup and 
- * makes more sense at the configuration option level than at the connection 
- * level.
+ * PROXYUSERPWD, PROXYAUTH, NETRC, MAX_RETRY and RETRY_DELAY values are searched in the configuration 
+ * options named GDAL_HTTP_PROXY, GDAL_HTTP_PROXYUSERPWD, GDAL_PROXY_AUTH, 
+ * GDAL_HTTP_NETRC, GDAL_HTTP_MAX_RETRY and GDAL_HTTP_RETRY_DELAY.
  *
  * @return a CPLHTTPResult* structure that must be freed by 
  * CPLHTTPDestroyResult(), or NULL if libcurl support is disabled
@@ -153,6 +156,55 @@ static size_t CPLHdrWriteFct(void *buffer, size_t size, size_t nmemb, void *reqI
 CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
 
 {
+    if( strncmp(pszURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
+        /* Disabled by default for potential security issues */
+        CSLTestBoolean(CPLGetConfigOption("CPL_CURL_ENABLE_VSIMEM", "FALSE")) )
+    {
+        CPLString osURL(pszURL);
+        const char* pszPost = CSLFetchNameValue( papszOptions, "POSTFIELDS" );
+        if( pszPost != NULL ) /* Hack: we append post content to filename */
+        {
+            osURL += "&POSTFIELDS=";
+            osURL += pszPost;
+        }
+        vsi_l_offset nLength = 0;
+        CPLHTTPResult* psResult = (CPLHTTPResult* )CPLCalloc(1, sizeof(CPLHTTPResult));
+        GByte* pabyData = VSIGetMemFileBuffer( osURL, &nLength, FALSE );
+        if( pabyData == NULL )
+        {
+            CPLDebug("HTTP", "Cannot find %s", osURL.c_str());
+            psResult->nStatus = 1;
+            psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", 404));
+            CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
+        }
+        else if( nLength != 0 )
+        {
+            psResult->nDataLen = (size_t)nLength;
+            psResult->pabyData = (GByte*) CPLMalloc((size_t)nLength + 1);
+            memcpy(psResult->pabyData, pabyData, (size_t)nLength);
+            psResult->pabyData[(size_t)nLength] = 0;
+        }
+
+        if( psResult->pabyData != NULL &&
+            strncmp((const char*)psResult->pabyData, "Content-Type: ",
+                    strlen("Content-Type: ")) == 0 )
+        {
+            const char* pszContentType = (const char*)psResult->pabyData + strlen("Content-type: ");
+            const char* pszEOL = strchr(pszContentType, '\r');
+            if( pszEOL )
+                pszEOL = strchr(pszContentType, '\n');
+            if( pszEOL )
+            {
+                int nLength = pszEOL - pszContentType;
+                psResult->pszContentType = (char*)CPLMalloc(nLength + 1);
+                memcpy(psResult->pszContentType, pszContentType, nLength);
+                psResult->pszContentType[nLength] = 0;
+            }
+        }
+
+        return psResult;
+    }
+
 #ifndef HAVE_CURL
     (void) papszOptions;
     (void) pszURL;
@@ -161,6 +213,7 @@ CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
               "GDAL/OGR not compiled with libcurl support, remote requests not supported." );
     return NULL;
 #else
+
 /* -------------------------------------------------------------------- */
 /*      Are we using a persistent named session?  If so, search for     */
 /*      or create it.                                                   */
@@ -180,14 +233,16 @@ CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
         CPLString osSessionName = pszPersistent;
         CPLMutexHolder oHolder( &hSessionMapMutex );
 
-        if( oSessionMap.count( osSessionName ) == 0 )
+        if( poSessionMap == NULL )
+            poSessionMap = new std::map<CPLString,CURL*>;
+        if( poSessionMap->count( osSessionName ) == 0 )
         {
-            oSessionMap[osSessionName] = curl_easy_init();
+            (*poSessionMap)[osSessionName] = curl_easy_init();
             CPLDebug( "HTTP", "Establish persistent session named '%s'.",
                       osSessionName.c_str() );
         }
 
-        http_handle = oSessionMap[osSessionName];
+        http_handle = (*poSessionMap)[osSessionName];
     }
 /* -------------------------------------------------------------------- */
 /*      Are we requested to close a persistent named session?          */
@@ -197,18 +252,26 @@ CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
         CPLString osSessionName = pszClosePersistent;
         CPLMutexHolder oHolder( &hSessionMapMutex );
 
-        std::map<CPLString,CURL*>::iterator oIter = oSessionMap.find( osSessionName );
-        if( oIter != oSessionMap.end() )
-        {
-            curl_easy_cleanup(oIter->second);
-            oSessionMap.erase(oIter);
-            CPLDebug( "HTTP", "Ended persistent session named '%s'.",
-                      osSessionName.c_str() );
-        }
-        else
+        if( poSessionMap )
         {
-            CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
-                      osSessionName.c_str() );
+            std::map<CPLString,CURL*>::iterator oIter = poSessionMap->find( osSessionName );
+            if( oIter != poSessionMap->end() )
+            {
+                curl_easy_cleanup(oIter->second);
+                poSessionMap->erase(oIter);
+                if( poSessionMap->size() == 0 )
+                {
+                    delete poSessionMap;
+                    poSessionMap = NULL;
+                }
+                CPLDebug( "HTTP", "Ended persistent session named '%s'.",
+                        osSessionName.c_str() );
+            }
+            else
+            {
+                CPLDebug( "HTTP", "Could not find persistent session named '%s'.",
+                        osSessionName.c_str() );
+            }
         }
 
         return NULL;
@@ -256,6 +319,17 @@ CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
         curl_easy_setopt(http_handle, CURLOPT_HTTPHEADER, headers);
     }
 
+    // are we making a head request
+    const char* pszNoBody = NULL;
+    if ((pszNoBody = CSLFetchNameValue( papszOptions, "NO_BODY" )) != NULL)
+    {
+        if (CSLTestBoolean(pszNoBody)) 
+        {
+            CPLDebug ("HTTP", "HEAD Request: %s", pszURL);
+            curl_easy_setopt(http_handle, CURLOPT_NOBODY, 1L);           
+        }
+    }
+
     // capture response headers
     curl_easy_setopt(http_handle, CURLOPT_HEADERDATA, psResult);
     curl_easy_setopt(http_handle, CURLOPT_HEADERFUNCTION, CPLHdrWriteFct);
@@ -282,69 +356,114 @@ CPLHTTPResult *CPLHTTPFetch( const char *pszURL, char **papszOptions )
     }
 
 /* -------------------------------------------------------------------- */
+/*      If 502, 503 or 504 status code retry this HTTP call until max        */
+/*      retry has been rearched                                         */
+/* -------------------------------------------------------------------- */
+    const char *pszRetryDelay = CSLFetchNameValue( papszOptions, "RETRY_DELAY" );
+    if( pszRetryDelay == NULL )
+        pszRetryDelay = CPLGetConfigOption( "GDAL_HTTP_RETRY_DELAY", "30" );
+    const char *pszMaxRetries = CSLFetchNameValue( papszOptions, "MAX_RETRY" );
+    if( pszMaxRetries == NULL )
+        pszMaxRetries = CPLGetConfigOption( "GDAL_HTTP_MAX_RETRY", "0" );
+    int nRetryDelaySecs = atoi(pszRetryDelay);
+    int nMaxRetries = atoi(pszMaxRetries);
+    int nRetryCount = 0;
+    bool bRequestRetry;
+
+    do
+    {
+        bRequestRetry = FALSE;
+
+/* -------------------------------------------------------------------- */
 /*      Execute the request, waiting for results.                       */
 /* -------------------------------------------------------------------- */
-    psResult->nStatus = (int) curl_easy_perform( http_handle );
+        psResult->nStatus = (int) curl_easy_perform( http_handle );
 
 /* -------------------------------------------------------------------- */
 /*      Fetch content-type if possible.                                 */
 /* -------------------------------------------------------------------- */
-    psResult->pszContentType = NULL;
-    curl_easy_getinfo( http_handle, CURLINFO_CONTENT_TYPE, 
-                       &(psResult->pszContentType) );
-    if( psResult->pszContentType != NULL )
-        psResult->pszContentType = CPLStrdup(psResult->pszContentType);
+        psResult->pszContentType = NULL;
+        curl_easy_getinfo( http_handle, CURLINFO_CONTENT_TYPE,
+                           &(psResult->pszContentType) );
+        if( psResult->pszContentType != NULL )
+            psResult->pszContentType = CPLStrdup(psResult->pszContentType);
 
 /* -------------------------------------------------------------------- */
 /*      Have we encountered some sort of error?                         */
 /* -------------------------------------------------------------------- */
-    if( strlen(szCurlErrBuf) > 0 )
-    {
-        int bSkipError = FALSE;
-
-        /* Some servers such as http://115.113.193.14/cgi-bin/world/qgis_mapserv.fcgi?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities */
-        /* invalidly return Content-Length as the uncompressed size, with makes curl to wait for more data */
-        /* and time-out finally. If we got the expected data size, then we don't emit an error */
-        /* but turn off GZip requests */
-        if (bGZipRequested &&
-            strstr(szCurlErrBuf, "transfer closed with") &&
-            strstr(szCurlErrBuf, "bytes remaining to read"))
+        if( strlen(szCurlErrBuf) > 0 )
         {
-            const char* pszContentLength =
-                CSLFetchNameValue(psResult->papszHeaders, "Content-Length");
-            if (pszContentLength && psResult->nDataLen != 0 &&
-                atoi(pszContentLength) == psResult->nDataLen)
+            int bSkipError = FALSE;
+
+            /* Some servers such as http://115.113.193.14/cgi-bin/world/qgis_mapserv.fcgi?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities */
+            /* invalidly return Content-Length as the uncompressed size, with makes curl to wait for more data */
+            /* and time-out finally. If we got the expected data size, then we don't emit an error */
+            /* but turn off GZip requests */
+            if (bGZipRequested &&
+                strstr(szCurlErrBuf, "transfer closed with") &&
+                strstr(szCurlErrBuf, "bytes remaining to read"))
             {
-                const char* pszCurlGZIPOption = CPLGetConfigOption("CPL_CURL_GZIP", NULL);
-                if (pszCurlGZIPOption == NULL)
+                const char* pszContentLength =
+                    CSLFetchNameValue(psResult->papszHeaders, "Content-Length");
+                if (pszContentLength && psResult->nDataLen != 0 &&
+                    atoi(pszContentLength) == psResult->nDataLen)
                 {
-                    CPLSetConfigOption("CPL_CURL_GZIP", "NO");
-                    CPLDebug("HTTP", "Disabling CPL_CURL_GZIP, because %s doesn't support it properly",
-                             pszURL);
+                    const char* pszCurlGZIPOption = CPLGetConfigOption("CPL_CURL_GZIP", NULL);
+                    if (pszCurlGZIPOption == NULL)
+                    {
+                        CPLSetConfigOption("CPL_CURL_GZIP", "NO");
+                        CPLDebug("HTTP", "Disabling CPL_CURL_GZIP, because %s doesn't support it properly",
+                                 pszURL);
+                    }
+                    psResult->nStatus = 0;
+                    bSkipError = TRUE;
                 }
-                psResult->nStatus = 0;
-                bSkipError = TRUE;
+            }
+            if (!bSkipError)
+            {
+                psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
+                CPLError( CE_Failure, CPLE_AppDefined,
+                        "%s", szCurlErrBuf );
             }
         }
-        if (!bSkipError)
-        {
-            psResult->pszErrBuf = CPLStrdup(szCurlErrBuf);
-            CPLError( CE_Failure, CPLE_AppDefined,
-                    "%s", szCurlErrBuf );
-        }
-    }
-    else
-    {
-        /* HTTP errors do not trigger curl errors. But we need to */
-        /* propagate them to the caller though */
-        long response_code = 0;
-        curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &response_code);
-        if (response_code >= 400 && response_code < 600)
+        else
         {
-            psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", (int)response_code));
-            CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
+            /* HTTP errors do not trigger curl errors. But we need to */
+            /* propagate them to the caller though */
+            long response_code = 0;
+            curl_easy_getinfo(http_handle, CURLINFO_RESPONSE_CODE, &response_code);
+
+            if (response_code >= 400 && response_code < 600)
+            {
+                /* If HTTP 502, 503 or 504 gateway timeout error retry after a pause */
+                if ((response_code >= 502 && response_code <= 504) && nRetryCount < nMaxRetries)
+                {
+                    CPLError(CE_Warning, CPLE_AppDefined,
+                             "HTTP error code: %d - %s. Retrying again in %d secs",
+                             (int)response_code, pszURL, nRetryDelaySecs);
+                    CPLSleep(nRetryDelaySecs);
+                    nRetryCount++;
+
+                    CPLFree(psResult->pszContentType);
+                    psResult->pszContentType = NULL;
+                    CSLDestroy(psResult->papszHeaders);
+                    psResult->papszHeaders = NULL;
+                    CPLFree(psResult->pabyData);
+                    psResult->pabyData = NULL;
+                    psResult->nDataLen = 0;
+                    psResult->nDataAlloc = 0;
+
+                    bRequestRetry = TRUE;
+                }
+                else
+                {
+                    psResult->pszErrBuf = CPLStrdup(CPLSPrintf("HTTP error code : %d", (int)response_code));
+                    CPLError( CE_Failure, CPLE_AppDefined, "%s", psResult->pszErrBuf );
+                }
+            }
         }
     }
+    while (bRequestRetry);
 
     if (!pszPersistent)
         curl_easy_cleanup( http_handle );
@@ -514,6 +633,12 @@ void CPLHTTPSetOptions(CURL *http_handle, char** papszOptions)
     {
         curl_easy_setopt(http_handle, CURLOPT_CUSTOMREQUEST, pszCustomRequest );
     }
+    
+    const char* pszCookie = CSLFetchNameValue(papszOptions, "COOKIE");
+    if (pszCookie == NULL)
+        pszCookie = CPLGetConfigOption("GDAL_HTTP_COOKIE", NULL);
+    if (pszCookie != NULL)
+        curl_easy_setopt(http_handle, CURLOPT_COOKIE, pszCookie);
 }
 #endif /* def HAVE_CURL */
 
@@ -522,7 +647,7 @@ void CPLHTTPSetOptions(CURL *http_handle, char** papszOptions)
 /************************************************************************/
 
 /**
- * \brief Return if CPLHTTP services can be usefull
+ * \brief Return if CPLHTTP services can be useful
  *
  * Those services depend on GDAL being build with libcurl support.
  *
@@ -555,11 +680,13 @@ void CPLHTTPCleanup()
     {
         CPLMutexHolder oHolder( &hSessionMapMutex );
         std::map<CPLString,CURL*>::iterator oIt;
-
-        for( oIt=oSessionMap.begin(); oIt != oSessionMap.end(); oIt++ )
-            curl_easy_cleanup( oIt->second );
-
-        oSessionMap.clear();
+        if( poSessionMap )
+        {
+            for( oIt=poSessionMap->begin(); oIt != poSessionMap->end(); oIt++ )
+                curl_easy_cleanup( oIt->second );
+            delete poSessionMap;
+            poSessionMap = NULL;
+        }
     }
 
     // not quite a safe sequence. 
diff --git a/port/cpl_minixml.cpp b/port/cpl_minixml.cpp
index 721587b..63eb55a 100644
--- a/port/cpl_minixml.cpp
+++ b/port/cpl_minixml.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_minixml.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_minixml.cpp 29087 2015-05-01 09:51:50Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implementation of MiniXML Parser and handling.
@@ -45,7 +45,7 @@
 #include "cpl_string.h"
 #include <ctype.h>
 
-CPL_CVSID("$Id: cpl_minixml.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_minixml.cpp 29087 2015-05-01 09:51:50Z rouault $");
 
 typedef enum {
     TNone,
@@ -599,6 +599,21 @@ CPLXMLNode *CPLParseXMLString( const char *pszString )
     }
 
 /* -------------------------------------------------------------------- */
+/*      Check for a UTF-8 BOM and skip if found                         */
+/*                                                                      */
+/*      TODO: BOM is variable-length parameter and depends on encoding. */
+/*            Add BOM detection for other encodings.                    */
+/* -------------------------------------------------------------------- */
+
+    // Used to skip to actual beginning of XML data
+    if( ( (unsigned char)pszString[0] == 0xEF )
+        && ( (unsigned char)pszString[1] == 0xBB )
+        && ( (unsigned char)pszString[2] == 0xBF) )
+    {
+        pszString += 3;
+    }
+
+/* -------------------------------------------------------------------- */
 /*      Initialize parse context.                                       */
 /* -------------------------------------------------------------------- */
     sContext.pszInput = pszString;
@@ -1658,6 +1673,44 @@ CPLXMLNode *CPLCreateXMLElementAndValue( CPLXMLNode *psParent,
 }
 
 /************************************************************************/
+/*                    CPLCreateXMLElementAndValue()                     */
+/************************************************************************/
+
+/**
+ * \brief Create an attribute and text value.
+ *
+ * This is function is a convenient short form for:
+ *
+ * \code
+ *   CPLXMLNode *psAttributeNode;
+ *
+ *   psAttributeNode = CPLCreateXMLNode( psParent, CXT_Attribute, pszName );
+ *   CPLCreateXMLNode( psAttributeNode, CXT_Text, pszValue );
+ * \endcode
+ *
+ * It creates a CXT_Attribute node, with a CXT_Text child, and
+ * attaches the element to the passed parent.
+ *
+ * @param psParent the parent node to which the resulting node should
+ * be attached.  May be NULL to keep as freestanding. 
+ *
+ * @param pszName the attribute name to create.
+ * @param pszValue the text to attach to the attribute. Must not be NULL. 
+ *
+ * @since GDAL 2.0
+ */
+
+void CPLAddXMLAttributeAndValue( CPLXMLNode *psParent,
+                                 const char *pszName,
+                                 const char *pszValue )
+{
+    CPLXMLNode *psAttributeNode;
+
+    psAttributeNode = CPLCreateXMLNode( psParent, CXT_Attribute, pszName );
+    CPLCreateXMLNode( psAttributeNode, CXT_Text, pszValue );
+}
+
+/************************************************************************/
 /*                          CPLCloneXMLTree()                           */
 /************************************************************************/
 
diff --git a/port/cpl_minixml.h b/port/cpl_minixml.h
index ed27453..731c8d7 100644
--- a/port/cpl_minixml.h
+++ b/port/cpl_minixml.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_minixml.h 25119 2012-10-13 22:38:43Z rouault $
+ * $Id: cpl_minixml.h 28690 2015-03-08 20:06:12Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Declarations for MiniXML Handler.
@@ -140,6 +140,9 @@ void       CPL_DLL  CPLAddXMLSibling( CPLXMLNode *psOlderSibling,
 CPLXMLNode CPL_DLL *CPLCreateXMLElementAndValue( CPLXMLNode *psParent,
                                                  const char *pszName,
                                                  const char *pszValue );
+void       CPL_DLL CPLAddXMLAttributeAndValue( CPLXMLNode *psParent,
+                                                 const char *pszName,
+                                                 const char *pszValue );
 CPLXMLNode CPL_DLL *CPLCloneXMLTree( CPLXMLNode *psTree );
 int        CPL_DLL CPLSetXMLValue( CPLXMLNode *psRoot,  const char *pszPath,
                                    const char *pszValue );
diff --git a/port/cpl_minizip_ioapi.cpp b/port/cpl_minizip_ioapi.cpp
index 32a5e56..189692e 100644
--- a/port/cpl_minizip_ioapi.cpp
+++ b/port/cpl_minizip_ioapi.cpp
@@ -145,7 +145,8 @@ int ZCALLBACK fclose_file_func (CPL_UNUSED voidpf opaque, voidpf stream)
 }
 
 static
-int ZCALLBACK ferror_file_func (CPL_UNUSED voidpf opaque, CPL_UNUSED voidpf stream)
+int ZCALLBACK ferror_file_func (CPL_UNUSED voidpf opaque,
+                                CPL_UNUSED voidpf stream)
 {
     int ret;
     ret = 0; // FIXME
diff --git a/port/cpl_minizip_unzip.cpp b/port/cpl_minizip_unzip.cpp
index 371bbf3..20670ef 100644
--- a/port/cpl_minizip_unzip.cpp
+++ b/port/cpl_minizip_unzip.cpp
@@ -1952,4 +1952,3 @@ extern int ZEXPORT cpl_unzSetOffset (unzFile file, uLong64 pos)
     s->current_file_ok = (err == UNZ_OK);
     return err;
 }
-
diff --git a/port/cpl_minizip_zip.cpp b/port/cpl_minizip_zip.cpp
index fe0aadd..b5c94e7 100644
--- a/port/cpl_minizip_zip.cpp
+++ b/port/cpl_minizip_zip.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_minizip_zip.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_minizip_zip.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Author:   Frank Warmerdam, warmerdam at pobox.com
@@ -319,7 +319,8 @@ local void ziplocal_putValue_inmemory (void *dest, uLong x, int nbByte)
 /****************************************************************************/
 
 
-local uLong ziplocal_TmzDateToDosDate(const tm_zip*ptm, CPL_UNUSED uLong dosDate)
+local uLong ziplocal_TmzDateToDosDate(const tm_zip *ptm,
+                                      CPL_UNUSED uLong dosDate)
 {
     uLong year = (uLong)ptm->tm_year;
     if (year>1980)
diff --git a/port/cpl_multiproc.cpp b/port/cpl_multiproc.cpp
index 5b90159..e844b03 100644
--- a/port/cpl_multiproc.cpp
+++ b/port/cpl_multiproc.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_multiproc.cpp 27720 2014-09-21 17:58:47Z goatbar $
+ * $Id: cpl_multiproc.cpp 28471 2015-02-12 21:16:10Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  CPL Multi-Threading, and process handling portability functions.
@@ -33,6 +33,7 @@
 #endif
 
 #include "cpl_multiproc.h"
+
 #include "cpl_conv.h"
 
 #if !defined(WIN32CE)
@@ -41,19 +42,74 @@
 #  include <wce_time.h>
 #endif
 
-CPL_CVSID("$Id: cpl_multiproc.cpp 27720 2014-09-21 17:58:47Z goatbar $");
+CPL_CVSID("$Id: cpl_multiproc.cpp 28471 2015-02-12 21:16:10Z rouault $");
 
 #if defined(CPL_MULTIPROC_STUB) && !defined(DEBUG)
 #  define MUTEX_NONE
 #endif
 
+//#define DEBUG_MUTEX
+
+#if defined(DEBUG) && (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
+#define DEBUG_CONTENTION
+#endif
+
+typedef struct _CPLSpinLock CPLSpinLock;
+
+struct _CPLLock
+{
+    CPLLockType eType;
+    union 
+    {
+        CPLMutex        *hMutex;
+        CPLSpinLock     *hSpinLock;
+    } u;
+
+#ifdef DEBUG_CONTENTION
+    int      bDebugPerf;
+    GUIntBig nStartTime;
+    GIntBig  nMaxDiff;
+    double   dfAvgDiff;
+    GUIntBig nIters;
+#endif
+};
+
+#ifdef DEBUG_CONTENTION
+static GUIntBig CPLrdtsc(void)
+{
+   unsigned int a, d, x, y;
+   __asm__ volatile ("cpuid" : "=a" (x), "=d" (y) : "a"(0) : "cx", "bx" );
+   __asm__ volatile ("rdtsc" : "=a" (a), "=d" (d) );
+   return ((GUIntBig )a) | (((GUIntBig )d) << 32);
+}
+
+static GUIntBig CPLrdtscp(void)
+{
+   unsigned int a, d, x, y;
+   __asm__ volatile ("rdtscp" : "=a" (a), "=d" (d) );
+   __asm__ volatile ("cpuid"  : "=a" (x), "=d" (y) : "a"(0) : "cx", "bx" );
+   return ((GUIntBig )a) | (((GUIntBig )d) << 32);
+}
+#endif
+
+static CPLSpinLock   *CPLCreateSpinLock( void ); /* returned NON acquired */
+static int     CPLCreateOrAcquireSpinLockInternal( CPLLock** );
+static int     CPLAcquireSpinLock( CPLSpinLock* );
+static void    CPLReleaseSpinLock( CPLSpinLock* );
+static void    CPLDestroySpinLock( CPLSpinLock* );
+
+/* We don't want it to be publicly used since it solves rather tricky issues */
+/* that are better to remain hidden... */
+void CPLFinalizeTLS();
+
 /************************************************************************/
 /*                           CPLMutexHolder()                           */
 /************************************************************************/
 
-CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
+CPLMutexHolder::CPLMutexHolder( CPLMutex **phMutex, double dfWaitInSeconds,
                                 const char *pszFileIn, 
-                                int nLineIn )
+                                int nLineIn,
+                                int nOptions )
 
 {
 #ifndef MUTEX_NONE
@@ -71,7 +127,7 @@ CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
              *phMutex, (long) CPLGetPID(), nLine, pszFile );
 #endif
 
-    if( !CPLCreateOrAcquireMutex( phMutex, dfWaitInSeconds ) )
+    if( !CPLCreateOrAcquireMutexEx( phMutex, dfWaitInSeconds, nOptions ) )
     {
         fprintf( stderr, "CPLMutexHolder: Failed to acquire mutex!\n" );
         hMutex = NULL;
@@ -93,7 +149,7 @@ CPLMutexHolder::CPLMutexHolder( void **phMutex, double dfWaitInSeconds,
 /*                           CPLMutexHolder()                           */
 /************************************************************************/
 
-CPLMutexHolder::CPLMutexHolder( void *hMutexIn, double dfWaitInSeconds,
+CPLMutexHolder::CPLMutexHolder( CPLMutex *hMutexIn, double dfWaitInSeconds,
                                 const char *pszFileIn, 
                                 int nLineIn )
 
@@ -132,6 +188,10 @@ CPLMutexHolder::~CPLMutexHolder()
 #endif /* ndef MUTEX_NONE */
 }
 
+int CPLCreateOrAcquireMutex( CPLMutex **phMutex, double dfWaitInSeconds )
+{
+    return CPLCreateOrAcquireMutexEx(phMutex, dfWaitInSeconds, CPL_MUTEX_RECURSIVE);
+}
 
 /************************************************************************/
 /*                      CPLCreateOrAcquireMutex()                       */
@@ -140,10 +200,10 @@ CPLMutexHolder::~CPLMutexHolder()
 #ifndef CPL_MULTIPROC_PTHREAD
 
 #ifndef MUTEX_NONE
-static void *hCOAMutex = NULL;
+static CPLMutex *hCOAMutex = NULL;
 #endif
 
-int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
+int CPLCreateOrAcquireMutexEx( CPLMutex **phMutex, double dfWaitInSeconds, int nOptions )
 
 {
     int bSuccess = FALSE;
@@ -171,7 +231,7 @@ int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
 
     if( *phMutex == NULL )
     {
-        *phMutex = CPLCreateMutex();
+        *phMutex = CPLCreateMutexEx( nOptions );
         bSuccess = *phMutex != NULL;
         CPLReleaseMutex( hCOAMutex );
     }
@@ -185,7 +245,68 @@ int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
 
     return bSuccess;
 }
-#endif
+
+/************************************************************************/
+/*                   CPLCreateOrAcquireMutexInternal()                  */
+/************************************************************************/
+
+static
+int CPLCreateOrAcquireMutexInternal( CPLLock **phLock, double dfWaitInSeconds,
+                                     CPLLockType eType )
+
+{
+    int bSuccess = FALSE;
+
+#ifndef MUTEX_NONE
+
+    /*
+    ** ironically, creation of this initial mutex is not threadsafe
+    ** even though we use it to ensure that creation of other mutexes
+    ** is threadsafe. 
+    */
+    if( hCOAMutex == NULL )
+    {
+        hCOAMutex = CPLCreateMutex();
+        if (hCOAMutex == NULL)
+        {
+            *phLock = NULL;
+            return FALSE;
+        }
+    }
+    else
+    {
+        CPLAcquireMutex( hCOAMutex, dfWaitInSeconds );
+    }
+
+    if( *phLock == NULL )
+    {
+        *phLock = (CPLLock*) calloc(1, sizeof(CPLLock));
+        if( *phLock )
+        {
+            (*phLock)->eType = eType;
+            (*phLock)->u.hMutex = CPLCreateMutexEx(
+                (eType == LOCK_RECURSIVE_MUTEX) ? CPL_MUTEX_RECURSIVE : CPL_MUTEX_ADAPTIVE );
+            if( (*phLock)->u.hMutex == NULL )
+            {
+                free(*phLock);
+                *phLock = NULL;
+            }
+        }
+        bSuccess = *phLock != NULL;
+        CPLReleaseMutex( hCOAMutex );
+    }
+    else
+    {
+        CPLReleaseMutex( hCOAMutex );
+
+        bSuccess = CPLAcquireMutex( (*phLock)->u.hMutex, dfWaitInSeconds );
+    }
+#endif /* ndef MUTEX_NONE */
+
+    return bSuccess;
+}
+
+#endif /* CPL_MULTIPROC_PTHREAD */
 
 /************************************************************************/ 
 /*                      CPLCleanupMasterMutex()                         */ 
@@ -268,7 +389,7 @@ const char *CPLGetThreadingModel()
 /*                           CPLCreateMutex()                           */
 /************************************************************************/
 
-void *CPLCreateMutex()
+CPLMutex *CPLCreateMutex()
 
 {
 #ifndef MUTEX_NONE
@@ -279,18 +400,24 @@ void *CPLCreateMutex()
     pabyMutex[2] = 'e';
     pabyMutex[3] = 'd';
 
-    return (void *) pabyMutex;
+    return (CPLMutex *) pabyMutex;
 #else
-    return (void *) 0xdeadbeef;
+    return (CPLMutex *) 0xdeadbeef;
 #endif 
 }
 
+CPLMutex *CPLCreateMutexEx(CPL_UNUSED int nOptions)
+
+{
+    return CPLCreateMutex();
+}
+
 /************************************************************************/
 /*                          CPLAcquireMutex()                           */
 /************************************************************************/
 
-int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
-
+int CPLAcquireMutex( CPLMutex *hMutex,
+                     CPL_UNUSED double dfWaitInSeconds )
 {
 #ifndef MUTEX_NONE
     unsigned char *pabyMutex = (unsigned char *) hMutex;
@@ -310,7 +437,7 @@ int CPLAcquireMutex( void *hMutex, double dfWaitInSeconds )
 /*                          CPLReleaseMutex()                           */
 /************************************************************************/
 
-void CPLReleaseMutex( void *hMutex )
+void CPLReleaseMutex( CPLMutex *hMutex )
 
 {
 #ifndef MUTEX_NONE
@@ -332,7 +459,7 @@ void CPLReleaseMutex( void *hMutex )
 /*                          CPLDestroyMutex()                           */
 /************************************************************************/
 
-void CPLDestroyMutex( void *hMutex )
+void CPLDestroyMutex( CPLMutex *hMutex )
 
 {
 #ifndef MUTEX_NONE
@@ -349,7 +476,7 @@ void CPLDestroyMutex( void *hMutex )
 /*                            CPLCreateCond()                           */
 /************************************************************************/
 
-void  *CPLCreateCond()
+CPLCond  *CPLCreateCond()
 {
     return NULL;
 }
@@ -358,7 +485,7 @@ void  *CPLCreateCond()
 /*                            CPLCondWait()                             */
 /************************************************************************/
 
-void  CPLCondWait( void *hCond, void* hMutex )
+void  CPLCondWait( CPL_UNUSED CPLCond *hCond, CPL_UNUSED CPLMutex* hMutex )
 {
 }
 
@@ -366,7 +493,7 @@ void  CPLCondWait( void *hCond, void* hMutex )
 /*                            CPLCondSignal()                           */
 /************************************************************************/
 
-void  CPLCondSignal( void *hCond )
+void  CPLCondSignal( CPL_UNUSED CPLCond *hCond )
 {
 }
 
@@ -374,7 +501,7 @@ void  CPLCondSignal( void *hCond )
 /*                           CPLCondBroadcast()                         */
 /************************************************************************/
 
-void  CPLCondBroadcast( void *hCond )
+void  CPLCondBroadcast( CPL_UNUSED CPLCond *hCond )
 {
 }
 
@@ -382,7 +509,7 @@ void  CPLCondBroadcast( void *hCond )
 /*                            CPLDestroyCond()                          */
 /************************************************************************/
 
-void  CPLDestroyCond( void *hCond )
+void  CPLDestroyCond( CPL_UNUSED CPLCond *hCond )
 {
 }
 
@@ -477,8 +604,7 @@ GIntBig CPLGetPID()
 /*                          CPLCreateThread();                          */
 /************************************************************************/
 
-int CPLCreateThread( CPLThreadFunc pfnMain, void *pArg )
-
+int CPLCreateThread( CPL_UNUSED CPLThreadFunc pfnMain, CPL_UNUSED void *pArg )
 {
     CPLDebug( "CPLCreateThread", "Fails to dummy implementation" );
 
@@ -489,8 +615,7 @@ int CPLCreateThread( CPLThreadFunc pfnMain, void *pArg )
 /*                      CPLCreateJoinableThread()                       */
 /************************************************************************/
 
-void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
-
+CPLJoinableThread* CPLCreateJoinableThread( CPL_UNUSED CPLThreadFunc pfnMain, CPL_UNUSED void *pThreadArg )
 {
     CPLDebug( "CPLCreateJoinableThread", "Fails to dummy implementation" );
 
@@ -501,7 +626,7 @@ void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
 /*                          CPLJoinThread()                             */
 /************************************************************************/
 
-void CPLJoinThread(void* hJoinableThread)
+void CPLJoinThread(CPL_UNUSED CPLJoinableThread* hJoinableThread)
 {
 }
 
@@ -510,7 +635,6 @@ void CPLJoinThread(void* hJoinableThread)
 /************************************************************************/
 
 void CPLSleep( double dfWaitInSeconds )
-
 {
     time_t  ltime;
     time_t  ttime;
@@ -545,6 +669,15 @@ static void **CPLGetTLSList()
 }
 
 /************************************************************************/
+/*                             CPLFinalizeTLS()                         */
+/************************************************************************/
+
+void CPLFinalizeTLS()
+{
+    CPLCleanupTLS();
+}
+
+/************************************************************************/
 /*                           CPLCleanupTLS()                            */
 /************************************************************************/
 
@@ -607,7 +740,7 @@ const char *CPLGetThreadingModel()
 /*                           CPLCreateMutex()                           */
 /************************************************************************/
 
-void *CPLCreateMutex()
+CPLMutex *CPLCreateMutex()
 
 {
 #ifdef USE_WIN32_MUTEX
@@ -615,7 +748,7 @@ void *CPLCreateMutex()
 
     hMutex = CreateMutex( NULL, TRUE, NULL );
 
-    return (void *) hMutex;
+    return (CPLMutex *) hMutex;
 #else
     CRITICAL_SECTION *pcs;
 
@@ -628,15 +761,21 @@ void *CPLCreateMutex()
       EnterCriticalSection(pcs);
     }
 
-    return (void *) pcs;
+    return (CPLMutex *) pcs;
 #endif
 }
 
+CPLMutex *CPLCreateMutexEx(CPL_UNUSED int nOptions)
+
+{
+    return CPLCreateMutex();
+}
+
 /************************************************************************/
 /*                          CPLAcquireMutex()                           */
 /************************************************************************/
 
-int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
+int CPLAcquireMutex( CPLMutex *hMutexIn, double dfWaitInSeconds )
 
 {
 #ifdef USE_WIN32_MUTEX
@@ -664,7 +803,7 @@ int CPLAcquireMutex( void *hMutexIn, double dfWaitInSeconds )
 /*                          CPLReleaseMutex()                           */
 /************************************************************************/
 
-void CPLReleaseMutex( void *hMutexIn )
+void CPLReleaseMutex( CPLMutex *hMutexIn )
 
 {
 #ifdef USE_WIN32_MUTEX
@@ -682,7 +821,7 @@ void CPLReleaseMutex( void *hMutexIn )
 /*                          CPLDestroyMutex()                           */
 /************************************************************************/
 
-void CPLDestroyMutex( void *hMutexIn )
+void CPLDestroyMutex( CPLMutex *hMutexIn )
 
 {
 #ifdef USE_WIN32_MUTEX
@@ -710,11 +849,11 @@ typedef struct _WaiterItem WaiterItem;
 
 typedef struct
 {
-    void        *hInternalMutex;
+    CPLMutex    *hInternalMutex;
     WaiterItem  *psWaiterList;
 } Win32Cond;
 
-void  *CPLCreateCond()
+CPLCond  *CPLCreateCond()
 {
     Win32Cond* psCond = (Win32Cond*) malloc(sizeof(Win32Cond));
     if (psCond == NULL)
@@ -727,7 +866,7 @@ void  *CPLCreateCond()
     }
     CPLReleaseMutex(psCond->hInternalMutex);
     psCond->psWaiterList = NULL;
-    return psCond;
+    return (CPLCond*) psCond;
 }
 
 /************************************************************************/
@@ -739,7 +878,7 @@ static void CPLTLSFreeEvent(void* pData)
     CloseHandle((HANDLE)pData);
 }
 
-void  CPLCondWait( void *hCond, void* hClientMutex )
+void  CPLCondWait( CPLCond *hCond, CPLMutex* hClientMutex )
 {
     Win32Cond* psCond = (Win32Cond*) hCond;
 
@@ -783,7 +922,7 @@ void  CPLCondWait( void *hCond, void* hClientMutex )
 /*                            CPLCondSignal()                           */
 /************************************************************************/
 
-void  CPLCondSignal( void *hCond )
+void  CPLCondSignal( CPLCond *hCond )
 {
     Win32Cond* psCond = (Win32Cond*) hCond;
 
@@ -805,7 +944,7 @@ void  CPLCondSignal( void *hCond )
 /*                           CPLCondBroadcast()                         */
 /************************************************************************/
 
-void  CPLCondBroadcast( void *hCond )
+void  CPLCondBroadcast( CPLCond *hCond )
 {
     Win32Cond* psCond = (Win32Cond*) hCond;
 
@@ -829,7 +968,7 @@ void  CPLCondBroadcast( void *hCond )
 /*                            CPLDestroyCond()                          */
 /************************************************************************/
 
-void  CPLDestroyCond( void *hCond )
+void  CPLDestroyCond( CPLCond *hCond )
 {
     Win32Cond* psCond = (Win32Cond*) hCond;
     CPLDestroyMutex(psCond->hInternalMutex);
@@ -964,7 +1103,7 @@ int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
 /*                      CPLCreateJoinableThread()                       */
 /************************************************************************/
 
-void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
+CPLJoinableThread* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
 
 {
     HANDLE hThread;
@@ -982,14 +1121,14 @@ void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
         return NULL;
         
     psInfo->hThread = hThread;
-    return psInfo;
+    return (CPLJoinableThread*) psInfo;
 }
 
 /************************************************************************/
 /*                          CPLJoinThread()                             */
 /************************************************************************/
 
-void CPLJoinThread(void* hJoinableThread)
+void CPLJoinThread(CPLJoinableThread* hJoinableThread)
 {
     CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo *) hJoinableThread;
     
@@ -1046,6 +1185,15 @@ static void **CPLGetTLSList()
 }
 
 /************************************************************************/
+/*                             CPLFinalizeTLS()                         */
+/************************************************************************/
+
+void CPLFinalizeTLS()
+{
+    CPLCleanupTLS();
+}
+
+/************************************************************************/
 /*                           CPLCleanupTLS()                            */
 /************************************************************************/
 
@@ -1100,9 +1248,10 @@ int CPLGetNumCPUs()
 /************************************************************************/
 
 static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
-static void *CPLCreateMutexInternal(int bAlreadyInGlobalLock);
+static CPLMutex *CPLCreateMutexInternal(int bAlreadyInGlobalLock, int nOptions);
 
-int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
+int CPLCreateOrAcquireMutexEx( CPLMutex **phMutex, double dfWaitInSeconds,
+                               int nOptions )
 
 {
     int bSuccess = FALSE;
@@ -1110,7 +1259,7 @@ int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
     pthread_mutex_lock(&global_mutex);
     if( *phMutex == NULL )
     {
-        *phMutex = CPLCreateMutexInternal(TRUE);
+        *phMutex = CPLCreateMutexInternal(TRUE, nOptions);
         bSuccess = *phMutex != NULL;
         pthread_mutex_unlock(&global_mutex);
     }
@@ -1125,6 +1274,44 @@ int CPLCreateOrAcquireMutex( void **phMutex, double dfWaitInSeconds )
 }
 
 /************************************************************************/
+/*                   CPLCreateOrAcquireMutexInternal()                  */
+/************************************************************************/
+
+static
+int CPLCreateOrAcquireMutexInternal( CPLLock **phLock, double dfWaitInSeconds,
+                                     CPLLockType eType )
+{
+    int bSuccess = FALSE;
+
+    pthread_mutex_lock(&global_mutex);
+    if( *phLock == NULL )
+    {
+        *phLock = (CPLLock*) calloc(1, sizeof(CPLLock));
+        if( *phLock )
+        {
+            (*phLock)->eType = eType;
+            (*phLock)->u.hMutex = CPLCreateMutexInternal(TRUE,
+                (eType == LOCK_RECURSIVE_MUTEX) ? CPL_MUTEX_RECURSIVE : CPL_MUTEX_ADAPTIVE );
+            if( (*phLock)->u.hMutex == NULL )
+            {
+                free(*phLock);
+                *phLock = NULL;
+            }
+        }
+        bSuccess = *phLock != NULL;
+        pthread_mutex_unlock(&global_mutex);
+    }
+    else
+    {
+        pthread_mutex_unlock(&global_mutex);
+
+        bSuccess = CPLAcquireMutex( (*phLock)->u.hMutex, dfWaitInSeconds );
+    }
+
+    return bSuccess;
+}
+
+/************************************************************************/
 /*                        CPLGetThreadingModel()                        */
 /************************************************************************/
 
@@ -1142,6 +1329,7 @@ typedef struct _MutexLinkedElt MutexLinkedElt;
 struct _MutexLinkedElt
 {
     pthread_mutex_t   sMutex;
+    int               nOptions;
     _MutexLinkedElt  *psPrev;
     _MutexLinkedElt  *psNext;
 };
@@ -1149,6 +1337,18 @@ static MutexLinkedElt* psMutexList = NULL;
 
 static void CPLInitMutex(MutexLinkedElt* psItem)
 {
+    /* When an adaptive mutex is required, we can safely fallback to recursive */
+    /* mutex if we don't have HAVE_PTHREAD_MUTEX_ADAPTIVE_NP */
+#if defined(HAVE_PTHREAD_MUTEX_ADAPTIVE_NP)
+    if( psItem->nOptions == CPL_MUTEX_ADAPTIVE )
+    {
+        pthread_mutexattr_t  attr;
+        pthread_mutexattr_init( &attr );
+        pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ADAPTIVE_NP );
+        pthread_mutex_init( &(psItem->sMutex), &attr );
+    }
+#endif
+
 #if defined(PTHREAD_MUTEX_RECURSIVE) || defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
     {
         pthread_mutexattr_t  attr;
@@ -1173,7 +1373,7 @@ static void CPLInitMutex(MutexLinkedElt* psItem)
 #endif
 }
 
-static void *CPLCreateMutexInternal(int bAlreadyInGlobalLock)
+static CPLMutex *CPLCreateMutexInternal(int bAlreadyInGlobalLock, int nOptions)
 {
     MutexLinkedElt* psItem = (MutexLinkedElt *) malloc(sizeof(MutexLinkedElt));
     if (psItem == NULL)
@@ -1189,24 +1389,30 @@ static void *CPLCreateMutexInternal(int bAlreadyInGlobalLock)
     if( !bAlreadyInGlobalLock )
         pthread_mutex_unlock(&global_mutex);
 
+    psItem->nOptions = nOptions;
     CPLInitMutex(psItem);
 
     // mutexes are implicitly acquired when created.
-    CPLAcquireMutex( &(psItem->sMutex), 0.0 );
+    CPLAcquireMutex( (CPLMutex*)psItem, 0.0 );
 
-    return psItem;
+    return (CPLMutex*)psItem;
 }
 
-void *CPLCreateMutex()
+CPLMutex *CPLCreateMutex()
 {
-    return CPLCreateMutexInternal(FALSE);
+    return CPLCreateMutexInternal(FALSE, CPL_MUTEX_RECURSIVE);
+}
+
+CPLMutex *CPLCreateMutexEx(int nOptions)
+{
+    return CPLCreateMutexInternal(FALSE, nOptions);
 }
 
 /************************************************************************/
 /*                          CPLAcquireMutex()                           */
 /************************************************************************/
 
-int CPLAcquireMutex( void *hMutexIn, CPL_UNUSED double dfWaitInSeconds )
+int CPLAcquireMutex( CPLMutex *hMutexIn, CPL_UNUSED double dfWaitInSeconds )
 {
     int err;
 
@@ -1231,7 +1437,7 @@ int CPLAcquireMutex( void *hMutexIn, CPL_UNUSED double dfWaitInSeconds )
 /*                          CPLReleaseMutex()                           */
 /************************************************************************/
 
-void CPLReleaseMutex( void *hMutexIn )
+void CPLReleaseMutex( CPLMutex *hMutexIn )
 
 {
     MutexLinkedElt* psItem = (MutexLinkedElt *) hMutexIn;
@@ -1242,7 +1448,7 @@ void CPLReleaseMutex( void *hMutexIn )
 /*                          CPLDestroyMutex()                           */
 /************************************************************************/
 
-void CPLDestroyMutex( void *hMutexIn )
+void CPLDestroyMutex( CPLMutex *hMutexIn )
 
 {
     MutexLinkedElt* psItem = (MutexLinkedElt *) hMutexIn;
@@ -1281,22 +1487,23 @@ void CPLReinitAllMutex()
 /*                            CPLCreateCond()                           */
 /************************************************************************/
 
-void  *CPLCreateCond()
+CPLCond  *CPLCreateCond()
 {
     pthread_cond_t* pCond = (pthread_cond_t* )malloc(sizeof(pthread_cond_t));
     if (pCond)
         pthread_cond_init(pCond, NULL);
-    return pCond;
+    return (CPLCond*) pCond;
 }
 
 /************************************************************************/
 /*                            CPLCondWait()                             */
 /************************************************************************/
 
-void  CPLCondWait( void *hCond, void* hMutex )
+void  CPLCondWait( CPLCond *hCond, CPLMutex* hMutex )
 {
     pthread_cond_t* pCond = (pthread_cond_t* )hCond;
-    pthread_mutex_t * pMutex = (pthread_mutex_t *)hMutex;
+    MutexLinkedElt* psItem = (MutexLinkedElt *) hMutex;
+    pthread_mutex_t * pMutex = &(psItem->sMutex);
     pthread_cond_wait(pCond,  pMutex);
 }
 
@@ -1304,7 +1511,7 @@ void  CPLCondWait( void *hCond, void* hMutex )
 /*                            CPLCondSignal()                           */
 /************************************************************************/
 
-void  CPLCondSignal( void *hCond )
+void  CPLCondSignal( CPLCond *hCond )
 {
     pthread_cond_t* pCond = (pthread_cond_t* )hCond;
     pthread_cond_signal(pCond);
@@ -1314,7 +1521,7 @@ void  CPLCondSignal( void *hCond )
 /*                           CPLCondBroadcast()                         */
 /************************************************************************/
 
-void  CPLCondBroadcast( void *hCond )
+void  CPLCondBroadcast( CPLCond *hCond )
 {
     pthread_cond_t* pCond = (pthread_cond_t* )hCond;
     pthread_cond_broadcast(pCond);
@@ -1324,7 +1531,7 @@ void  CPLCondBroadcast( void *hCond )
 /*                            CPLDestroyCond()                          */
 /************************************************************************/
 
-void  CPLDestroyCond( void *hCond )
+void  CPLDestroyCond( CPLCond *hCond )
 {
     pthread_cond_t* pCond = (pthread_cond_t* )hCond;
     pthread_cond_destroy(pCond);
@@ -1471,7 +1678,7 @@ int CPLCreateThread( CPLThreadFunc pfnMain, void *pThreadArg )
 /*                      CPLCreateJoinableThread()                       */
 /************************************************************************/
 
-void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
+CPLJoinableThread* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
 
 {
     CPLStdCallThreadInfo *psInfo;
@@ -1491,14 +1698,14 @@ void* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pThreadArg )
         return NULL;
     }
 
-    return psInfo;
+    return (CPLJoinableThread*) psInfo;
 }
 
 /************************************************************************/
 /*                          CPLJoinThread()                             */
 /************************************************************************/
 
-void CPLJoinThread(void* hJoinableThread)
+void CPLJoinThread(CPLJoinableThread* hJoinableThread)
 {
     CPLStdCallThreadInfo *psInfo = (CPLStdCallThreadInfo*) hJoinableThread;
 
@@ -1539,6 +1746,17 @@ static void CPLMake_key()
 }
 
 /************************************************************************/
+/*                             CPLFinalizeTLS()                         */
+/************************************************************************/
+
+void CPLFinalizeTLS()
+{
+    CPLCleanupTLS();
+    /* See #5509 for the explanation why this may be needed */
+    pthread_key_delete(oTLSKey);
+}
+
+/************************************************************************/
 /*                             CPLCleanupTLS()                          */
 /************************************************************************/
 
@@ -1586,6 +1804,86 @@ static void **CPLGetTLSList()
     return papTLSList;
 }
 
+/************************************************************************/
+/*                          CPLCreateSpinLock()                         */
+/************************************************************************/
+
+#if defined(HAVE_PTHREAD_SPINLOCK)
+#define HAVE_SPINLOCK_IMPL
+
+struct _CPLSpinLock
+{
+    pthread_spinlock_t spin;
+};
+
+CPLSpinLock  *CPLCreateSpinLock( void )
+{
+    CPLSpinLock* psSpin = (CPLSpinLock*)malloc(sizeof(CPLSpinLock));
+    if( pthread_spin_init(&(psSpin->spin), PTHREAD_PROCESS_PRIVATE) == 0 )
+    {
+        return psSpin;
+    }
+    else
+    {
+        free(psSpin);
+        return NULL;
+    }
+}
+
+/************************************************************************/
+/*                        CPLAcquireSpinLock()                          */
+/************************************************************************/
+
+int   CPLAcquireSpinLock( CPLSpinLock* psSpin )
+{
+    return pthread_spin_lock( &(psSpin->spin) ) == 0;
+}
+
+/************************************************************************/
+/*                   CPLCreateOrAcquireSpinLockInternal()               */
+/************************************************************************/
+
+int  CPLCreateOrAcquireSpinLockInternal( CPLLock** ppsLock )
+{
+    pthread_mutex_lock(&global_mutex);
+    if( *ppsLock == NULL )
+    {
+        *ppsLock = (CPLLock*) calloc(1, sizeof(CPLLock));
+        if( *ppsLock != NULL )
+        {
+            (*ppsLock)->eType = LOCK_SPIN;
+            (*ppsLock)->u.hSpinLock = CPLCreateSpinLock();
+            if( (*ppsLock)->u.hSpinLock == NULL )
+            {
+                free(*ppsLock);
+                *ppsLock = NULL;
+            }
+        }
+    }
+    pthread_mutex_unlock(&global_mutex);
+    return( *ppsLock != NULL && CPLAcquireSpinLock( (*ppsLock)->u.hSpinLock ) );
+}
+
+/************************************************************************/
+/*                       CPLReleaseSpinLock()                           */
+/************************************************************************/
+
+void  CPLReleaseSpinLock( CPLSpinLock* psSpin )
+{
+    pthread_spin_unlock( &(psSpin->spin) );
+}
+
+/************************************************************************/
+/*                        CPLDestroySpinLock()                          */
+/************************************************************************/
+
+void  CPLDestroySpinLock( CPLSpinLock* psSpin )
+{
+    pthread_spin_destroy( &(psSpin->spin) );
+    free( psSpin );
+}
+#endif /* HAVE_PTHREAD_SPINLOCK */
+
 #endif /* def CPL_MULTIPROC_PTHREAD */
 
 /************************************************************************/
@@ -1628,3 +1926,311 @@ void CPLSetTLSWithFreeFunc( int nIndex, void *pData, CPLTLSFreeFunc pfnFree )
     papTLSList[nIndex] = pData;
     papTLSList[CTLS_MAX + nIndex] = (void*) pfnFree;
 }
+
+#ifndef HAVE_SPINLOCK_IMPL
+
+/* No spinlock specific API ? Fallback to mutex */
+
+/************************************************************************/
+/*                          CPLCreateSpinLock()                         */
+/************************************************************************/
+
+CPLSpinLock *CPLCreateSpinLock( void )
+{
+    CPLSpinLock* psSpin = (CPLSpinLock *)CPLCreateMutex();
+    if( psSpin )
+        CPLReleaseSpinLock(psSpin);
+    return psSpin;
+}
+
+/************************************************************************/
+/*                     CPLCreateOrAcquireSpinLock()                     */
+/************************************************************************/
+
+int   CPLCreateOrAcquireSpinLockInternal( CPLLock** ppsLock )
+{
+    return CPLCreateOrAcquireMutexInternal( ppsLock, 1000, LOCK_ADAPTIVE_MUTEX );
+}
+
+/************************************************************************/
+/*                        CPLAcquireSpinLock()                          */
+/************************************************************************/
+
+int  CPLAcquireSpinLock( CPLSpinLock* psSpin )
+{
+    return CPLAcquireMutex( (CPLMutex*)psSpin, 1000 );
+}
+
+/************************************************************************/
+/*                       CPLReleaseSpinLock()                           */
+/************************************************************************/
+
+void  CPLReleaseSpinLock( CPLSpinLock* psSpin )
+{
+    CPLReleaseMutex( (CPLMutex*)psSpin );
+}
+
+/************************************************************************/
+/*                        CPLDestroySpinLock()                          */
+/************************************************************************/
+
+void  CPLDestroySpinLock( CPLSpinLock* psSpin )
+{
+    CPLDestroyMutex( (CPLMutex*)psSpin );
+}
+
+#endif /* HAVE_SPINLOCK_IMPL */
+
+
+/************************************************************************/
+/*                            CPLCreateLock()                           */
+/************************************************************************/
+
+CPLLock *CPLCreateLock( CPLLockType eType )
+{
+    switch( eType )
+    {
+        case LOCK_RECURSIVE_MUTEX:
+        case LOCK_ADAPTIVE_MUTEX:
+        {
+            CPLMutex* hMutex = CPLCreateMutexEx(
+                (eType == LOCK_RECURSIVE_MUTEX) ? CPL_MUTEX_RECURSIVE : CPL_MUTEX_ADAPTIVE);
+            if(!hMutex)
+                return NULL;
+            CPLReleaseMutex(hMutex);
+            CPLLock* psLock = (CPLLock*)malloc(sizeof(CPLLock));
+            psLock->eType = eType;
+            psLock->u.hMutex = hMutex;
+            return psLock;
+        }
+        case LOCK_SPIN:
+        {
+            CPLSpinLock* hSpinLock = CPLCreateSpinLock();
+            if( !hSpinLock )
+                return NULL;
+            CPLLock* psLock = (CPLLock*)malloc(sizeof(CPLLock));
+            psLock->eType = eType;
+            psLock->u.hSpinLock = hSpinLock;
+            return psLock;
+        }
+        default:
+            CPLAssert(0);
+            return NULL;
+    }
+}
+
+/************************************************************************/
+/*                       CPLCreateOrAcquireLock()                       */
+/************************************************************************/
+
+int   CPLCreateOrAcquireLock( CPLLock** ppsLock, CPLLockType eType )
+{
+    int ret;
+#ifdef DEBUG_CONTENTION
+    GUIntBig nStartTime = 0;
+    if( (*ppsLock) && (*ppsLock)->bDebugPerf )
+        nStartTime = CPLrdtsc();
+#endif
+    switch( eType )
+    {
+        case LOCK_RECURSIVE_MUTEX:
+        case LOCK_ADAPTIVE_MUTEX:
+        {
+            ret = CPLCreateOrAcquireMutexInternal( ppsLock, 1000, eType);
+            break;
+        }
+        case LOCK_SPIN:
+        {
+            ret = CPLCreateOrAcquireSpinLockInternal( ppsLock );
+            break;
+        }
+        default:
+            CPLAssert(0);
+            return FALSE;
+    }
+#ifdef DEBUG_CONTENTION
+    if( ret && (*ppsLock)->bDebugPerf )
+    {
+        (*ppsLock)->nStartTime = nStartTime;
+    }
+#endif
+    return ret;
+}
+
+/************************************************************************/
+/*                          CPLAcquireLock()                            */
+/************************************************************************/
+
+int  CPLAcquireLock( CPLLock* psLock )
+{
+#ifdef DEBUG_CONTENTION
+    if( psLock->bDebugPerf )
+        psLock->nStartTime = CPLrdtsc();
+#endif
+    if( psLock->eType == LOCK_SPIN )
+        return CPLAcquireSpinLock( psLock->u.hSpinLock );
+    else
+        return CPLAcquireMutex( psLock->u.hMutex, 1000 );
+}
+
+/************************************************************************/
+/*                         CPLReleaseLock()                             */
+/************************************************************************/
+
+void  CPLReleaseLock( CPLLock* psLock )
+{
+#ifdef DEBUG_CONTENTION
+    int bHitMaxDiff = FALSE;
+    GIntBig nMaxDiff = 0;
+    double dfAvgDiff = 0;
+    GUIntBig nIters = 0;
+    if( psLock->bDebugPerf && psLock->nStartTime )
+    {
+        GUIntBig nStopTime = CPLrdtscp();
+        GIntBig nDiffTime = (GIntBig)(nStopTime - psLock->nStartTime);
+        if( nDiffTime > psLock->nMaxDiff )
+        {
+            bHitMaxDiff = TRUE;
+            psLock->nMaxDiff = nDiffTime;
+        }
+        nMaxDiff = psLock->nMaxDiff;
+        psLock->nIters ++;
+        nIters = psLock->nIters;
+        psLock->dfAvgDiff += (nDiffTime - psLock->dfAvgDiff) / nIters;
+        dfAvgDiff = psLock->dfAvgDiff;
+    }
+#endif
+    if( psLock->eType == LOCK_SPIN )
+        CPLReleaseSpinLock( psLock->u.hSpinLock );
+    else
+        CPLReleaseMutex( psLock->u.hMutex );
+#ifdef DEBUG_CONTENTION
+    if( psLock->bDebugPerf && (bHitMaxDiff || (psLock->nIters % 1000000) == (1000000-1) ))
+    {
+        CPLDebug("LOCK", "Lock contention : max = " CPL_FRMT_GIB ", avg = %.0f",
+                 nMaxDiff, dfAvgDiff);
+    }
+#endif
+}
+
+/************************************************************************/
+/*                          CPLDestroyLock()                            */
+/************************************************************************/
+
+void  CPLDestroyLock( CPLLock* psLock )
+{
+    if( psLock->eType == LOCK_SPIN )
+        CPLDestroySpinLock( psLock->u.hSpinLock );
+    else
+        CPLDestroyMutex( psLock->u.hMutex );
+    free( psLock );
+}
+
+/************************************************************************/
+/*                       CPLLockSetDebugPerf()                          */
+/************************************************************************/
+
+void CPLLockSetDebugPerf( CPLLock* psLock, int bEnableIn )
+{
+#ifdef DEBUG_CONTENTION
+    psLock->bDebugPerf = bEnableIn;
+#else
+    if( bEnableIn )
+    {
+        static int bOnce = FALSE;
+        if( !bOnce )
+        {
+            bOnce = TRUE;
+            CPLDebug("LOCK", "DEBUG_CONTENTION not available");
+        }
+    }
+#endif
+}
+
+/************************************************************************/
+/*                           CPLLockHolder()                            */
+/************************************************************************/
+
+CPLLockHolder::CPLLockHolder( CPLLock **phLock,
+                              CPLLockType eType,
+                              const char *pszFileIn, 
+                              int nLineIn )
+
+{
+#ifndef MUTEX_NONE
+    pszFile = pszFileIn;
+    nLine = nLineIn;
+
+#ifdef DEBUG_MUTEX
+    /*
+     * XXX: There is no way to use CPLDebug() here because it works with
+     * mutexes itself so we will fall in infinite recursion. Good old
+     * fprintf() will do the job right.
+     */
+    fprintf( stderr,
+             "CPLLockHolder: Request %p for pid %ld at %d/%s.\n", 
+             *phLock, (long) CPLGetPID(), nLine, pszFile );
+#endif
+
+    if( !CPLCreateOrAcquireLock( phLock, eType ) )
+    {
+        fprintf( stderr, "CPLLockHolder: Failed to acquire lock!\n" );
+        hLock = NULL;
+    }
+    else
+    {
+#ifdef DEBUG_MUTEX
+        fprintf( stderr,
+                 "CPLLockHolder: Acquired %p for pid %ld at %d/%s.\n", 
+                 *phLock, (long) CPLGetPID(), nLine, pszFile );
+#endif
+
+        hLock = *phLock;
+    }
+#endif /* ndef MUTEX_NONE */
+}
+
+/************************************************************************/
+/*                           CPLLockHolder()                            */
+/************************************************************************/
+
+CPLLockHolder::CPLLockHolder( CPLLock *hLockIn,
+                              const char *pszFileIn, 
+                              int nLineIn )
+
+{
+#ifndef MUTEX_NONE
+    pszFile = pszFileIn;
+    nLine = nLineIn;
+    hLock = hLockIn;
+
+    if( hLock != NULL )
+    {
+        if( !CPLAcquireLock( hLock ) )
+        {
+            fprintf( stderr, "CPLLockHolder: Failed to acquire lock!\n" );
+            hLock = NULL;
+        }
+    }
+#endif /* ndef MUTEX_NONE */
+}
+
+/************************************************************************/
+/*                          ~CPLLockHolder()                            */
+/************************************************************************/
+
+CPLLockHolder::~CPLLockHolder()
+
+{
+#ifndef MUTEX_NONE
+    if( hLock != NULL )
+    {
+#ifdef DEBUG_MUTEX
+        fprintf( stderr,
+                 "~CPLLockHolder: Release %p for pid %ld at %d/%s.\n", 
+                 hLock, (long) CPLGetPID(), nLine, pszFile );
+#endif
+        CPLReleaseLock( hLock );
+    }
+#endif /* ndef MUTEX_NONE */
+}
diff --git a/port/cpl_multiproc.h b/port/cpl_multiproc.h
index ac78f99..0b39b93 100644
--- a/port/cpl_multiproc.h
+++ b/port/cpl_multiproc.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_multiproc.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_multiproc.h 28470 2015-02-12 21:01:32Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  CPL Multi-Threading, and process handling portability functions.
@@ -59,62 +59,136 @@ typedef void (*CPLThreadFunc)(void *);
 void CPL_DLL *CPLLockFile( const char *pszPath, double dfWaitInSeconds );
 void  CPL_DLL CPLUnlockFile( void *hLock );
 
-void CPL_DLL *CPLCreateMutex( void );
-int   CPL_DLL CPLCreateOrAcquireMutex( void **, double dfWaitInSeconds );
-int   CPL_DLL CPLAcquireMutex( void *hMutex, double dfWaitInSeconds );
-void  CPL_DLL CPLReleaseMutex( void *hMutex );
-void  CPL_DLL CPLDestroyMutex( void *hMutex );
+#ifdef DEBUG
+typedef struct _CPLMutex  CPLMutex;
+typedef struct _CPLCond   CPLCond;
+typedef struct _CPLJoinableThread CPLJoinableThread;
+#else
+#define CPLMutex void
+#define CPLCond void
+#define CPLJoinableThread void
+#endif
+
+/* Options for CPLCreateMutexEx() and CPLCreateOrAcquireMutexEx() */
+#define CPL_MUTEX_RECURSIVE         0
+#define CPL_MUTEX_ADAPTIVE          1
+
+CPLMutex CPL_DLL *CPLCreateMutex( void ); /* returned acquired */
+CPLMutex CPL_DLL *CPLCreateMutexEx( int nOptions ); /* returned acquired */
+int   CPL_DLL CPLCreateOrAcquireMutex( CPLMutex **, double dfWaitInSeconds );
+int   CPL_DLL CPLCreateOrAcquireMutexEx( CPLMutex **, double dfWaitInSeconds, int nOptions  );
+int   CPL_DLL CPLAcquireMutex( CPLMutex *hMutex, double dfWaitInSeconds );
+void  CPL_DLL CPLReleaseMutex( CPLMutex *hMutex );
+void  CPL_DLL CPLDestroyMutex( CPLMutex *hMutex );
 void  CPL_DLL CPLCleanupMasterMutex( void );
 
-void  CPL_DLL *CPLCreateCond( void );
-void  CPL_DLL  CPLCondWait( void *hCond, void* hMutex );
-void  CPL_DLL  CPLCondSignal( void *hCond );
-void  CPL_DLL  CPLCondBroadcast( void *hCond );
-void  CPL_DLL  CPLDestroyCond( void *hCond );
+CPLCond  CPL_DLL *CPLCreateCond( void );
+void  CPL_DLL  CPLCondWait( CPLCond *hCond, CPLMutex* hMutex );
+void  CPL_DLL  CPLCondSignal( CPLCond *hCond );
+void  CPL_DLL  CPLCondBroadcast( CPLCond *hCond );
+void  CPL_DLL  CPLDestroyCond( CPLCond *hCond );
 
 GIntBig CPL_DLL CPLGetPID( void );
 int   CPL_DLL CPLCreateThread( CPLThreadFunc pfnMain, void *pArg );
-void  CPL_DLL* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pArg );
-void  CPL_DLL CPLJoinThread(void* hJoinableThread); 
+CPLJoinableThread  CPL_DLL* CPLCreateJoinableThread( CPLThreadFunc pfnMain, void *pArg );
+void  CPL_DLL CPLJoinThread(CPLJoinableThread* hJoinableThread); 
 void  CPL_DLL CPLSleep( double dfWaitInSeconds );
 
 const char CPL_DLL *CPLGetThreadingModel( void );
 
 int CPL_DLL CPLGetNumCPUs( void );
 
+
+typedef struct _CPLLock CPLLock;
+
+/* Currently LOCK_ADAPTIVE_MUTEX is Linux-only and LOCK_SPIN only available */
+/* on systems with pthread_spinlock API (so not MacOsX). If a requested type */
+/* isn't available, it fallbacks to LOCK_RECURSIVE_MUTEX */
+typedef enum
+{
+    LOCK_RECURSIVE_MUTEX,
+    LOCK_ADAPTIVE_MUTEX,
+    LOCK_SPIN
+} CPLLockType;
+
+CPLLock  CPL_DLL *CPLCreateLock( CPLLockType eType ); /* returned NON acquired */
+int   CPL_DLL  CPLCreateOrAcquireLock( CPLLock**, CPLLockType eType );
+int   CPL_DLL  CPLAcquireLock( CPLLock* );
+void  CPL_DLL  CPLReleaseLock( CPLLock* );
+void  CPL_DLL  CPLDestroyLock( CPLLock* );
+void  CPL_DLL  CPLLockSetDebugPerf( CPLLock*, int bEnableIn ); /* only available on x86/x86_64 with GCC for now */
+
+
 CPL_C_END
 
 #ifdef __cplusplus
 
-/* Instanciates the mutex if not already done */
+/* Instanciates the mutex if not already done. The parameter x should be a (void**)  */
 #define CPLMutexHolderD(x)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__);
 
+/* Instanciates the mutex with options if not already done. */
+/* The parameter x should be a (void**)  */
+#define CPLMutexHolderExD(x, nOptions)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__,nOptions);
+
 /* This variant assumes the the mutex has already been created. If not, it will */
-/* be a no-op */
+/* be a no-op. The parameter x should be a (void*) */
 #define CPLMutexHolderOptionalLockD(x)  CPLMutexHolder oHolder(x,1000.0,__FILE__,__LINE__);
 
 class CPL_DLL CPLMutexHolder
 {
   private:
-    void       *hMutex;
+    CPLMutex   *hMutex;
     const char *pszFile;
     int         nLine;
 
   public:
 
     /* Instanciates the mutex if not already done */
-    CPLMutexHolder( void **phMutex, double dfWaitInSeconds = 1000.0,
+    CPLMutexHolder( CPLMutex **phMutex, double dfWaitInSeconds = 1000.0,
                     const char *pszFile = __FILE__,
-                    int nLine = __LINE__ );
+                    int nLine = __LINE__,
+                    int nOptions = CPL_MUTEX_RECURSIVE);
 
     /* This variant assumes the the mutex has already been created. If not, it will */
     /* be a no-op */
-    CPLMutexHolder( void* hMutex, double dfWaitInSeconds = 1000.0,
+    CPLMutexHolder( CPLMutex* hMutex, double dfWaitInSeconds = 1000.0,
                     const char *pszFile = __FILE__,
                     int nLine = __LINE__ );
 
     ~CPLMutexHolder();
 };
+
+/* Instanciates the lock if not already done. The parameter x should be a (CPLLock**) */
+#define CPLLockHolderD(x, eType)  CPLLockHolder oHolder(x,eType,__FILE__,__LINE__);
+
+/* This variant assumes the the lock has already been created. If not, it will */
+/* be a no-op. The parameter should be (CPLLock*) */
+#define CPLLockHolderOptionalLockD(x)  CPLLockHolder oHolder(x,__FILE__,__LINE__);
+
+class CPL_DLL CPLLockHolder
+{
+  private:
+    CPLLock    *hLock;
+    const char *pszFile;
+    int         nLine;
+
+  public:
+
+    /* Instanciates the lock if not already done */
+    CPLLockHolder( CPLLock **phSpin, CPLLockType eType,
+                    const char *pszFile = __FILE__,
+                    int nLine = __LINE__);
+
+    /* This variant assumes the the lock has already been created. If not, it will */
+    /* be a no-op */
+    CPLLockHolder( CPLLock* hSpin,
+                    const char *pszFile = __FILE__,
+                    int nLine = __LINE__ );
+
+    ~CPLLockHolder();
+};
+
+
 #endif /* def __cplusplus */
 
 /* -------------------------------------------------------------------- */
diff --git a/port/cpl_odbc.cpp b/port/cpl_odbc.cpp
index a918980..0dbb4a8 100644
--- a/port/cpl_odbc.cpp
+++ b/port/cpl_odbc.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_odbc.cpp 27739 2014-09-25 18:49:52Z goatbar $
+ * $Id: cpl_odbc.cpp 29027 2015-04-26 18:29:41Z tamas $
  *
  * Project:  OGR ODBC Driver
  * Purpose:  Declarations for ODBC Access Cover API.
@@ -36,7 +36,7 @@
 
 #ifndef WIN32CE /* ODBC is not supported on Windows CE. */
 
-CPL_CVSID("$Id: cpl_odbc.cpp 27739 2014-09-25 18:49:52Z goatbar $");
+CPL_CVSID("$Id: cpl_odbc.cpp 29027 2015-04-26 18:29:41Z tamas $");
 
 #ifndef SQLColumns_TABLE_CAT 
 #define SQLColumns_TABLE_CAT 1
@@ -186,6 +186,8 @@ int CPLODBCSession::CloseSession()
 {
     if( m_hDBC!=NULL ) 
     {
+        if ( IsInTransaction() )
+            CPLError( CE_Warning, CPLE_AppDefined, "Closing session with active transactions." );
         CPLDebug( "ODBC", "SQLDisconnect()" );
         SQLDisconnect( m_hDBC );
         SQLFreeConnect( m_hDBC );
@@ -225,6 +227,7 @@ int CPLODBCSession::ClearTransaction()
             return FALSE;
     }
 
+    m_bInTransaction = FALSE;
     m_bAutoCommit = TRUE;
 
 #endif
@@ -294,10 +297,10 @@ int CPLODBCSession::RollbackTransaction()
     {
         m_bInTransaction = FALSE;
 
-        int nRetCode = SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_ROLLBACK );
-        
-        if( nRetCode != SQL_SUCCESS && nRetCode != SQL_SUCCESS_WITH_INFO )
+        if( Failed( SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_ROLLBACK ) ) )
+        {
             return FALSE;
+        }
     }
 
 #endif
@@ -456,6 +459,7 @@ CPLODBCStatement::CPLODBCStatement( CPLODBCSession *poSession )
     m_panColSize = NULL;
     m_panColPrecision = NULL;
     m_panColNullable = NULL;
+    m_papszColColumnDef = NULL;
 
     m_papszColValues = NULL;
     m_panColValueLengths = NULL;
@@ -557,6 +561,7 @@ int CPLODBCStatement::CollectResultsInfo()
     m_panColSize = (_SQLULEN *) CPLCalloc(sizeof(_SQLULEN),m_nColCount);
     m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
     m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
+    m_papszColColumnDef = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
 
 /* -------------------------------------------------------------------- */
 /*      Fetch column descriptions.                                      */
@@ -596,6 +601,18 @@ int CPLODBCStatement::CollectResultsInfo()
 }
 
 /************************************************************************/
+/*                            GetRowCountAffected()                     */
+/************************************************************************/
+
+int CPLODBCStatement::GetRowCountAffected()
+{
+    SQLLEN nResultCount=0;
+    SQLRowCount( m_hStmt, &nResultCount );
+    
+    return (int)nResultCount;
+}
+
+/************************************************************************/
 /*                            GetColCount()                             */
 /************************************************************************/
 
@@ -749,6 +766,30 @@ short CPLODBCStatement::GetColNullable( int iCol )
 }
 
 /************************************************************************/
+/*                             GetColColumnDef()                        */
+/************************************************************************/
+
+/**
+ * Fetch a column default value.
+ *
+ * Returns the default value of a column.
+ *
+ * @param iCol the zero based column index.
+ *
+ * @return NULL if the default value is not dpecified
+ * or the internal copy of the default value.
+ */
+
+const char *CPLODBCStatement::GetColColumnDef( int iCol )
+
+{
+    if( iCol < 0 || iCol >= m_nColCount )
+        return NULL;
+    else
+        return m_papszColColumnDef[iCol];
+}
+
+/************************************************************************/
 /*                               Fetch()                                */
 /************************************************************************/
 
@@ -1302,6 +1343,9 @@ void CPLODBCStatement::Clear()
         CPLFree( m_panColNullable );
         m_panColNullable = NULL;
 
+        CSLDestroy( m_papszColColumnDef );
+        m_papszColColumnDef = NULL;
+
         CSLDestroy( m_papszColNames );
         m_papszColNames = NULL;
 
@@ -1397,6 +1441,7 @@ int CPLODBCStatement::GetColumns( const char *pszTable,
     m_panColSize = (_SQLULEN *) CPLCalloc(sizeof(_SQLULEN),m_nColCount);
     m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
     m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount);
+    m_papszColColumnDef = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1));
 
 /* -------------------------------------------------------------------- */
 /*      Establish columns to use for key information.                   */
@@ -1439,6 +1484,12 @@ int CPLODBCStatement::GetColumns( const char *pszTable,
         SQLGetData( m_hStmt, SQLColumns_NULLABLE, SQL_C_CHAR,
                     szWrkData, sizeof(szWrkData)-1, &cbDataLen );
         m_panColNullable[iCol] = atoi(szWrkData) == SQL_NULLABLE;
+#if (ODBCVER >= 0x0300)
+        SQLGetData( m_hStmt, SQLColumns_COLUMN_DEF, SQL_C_CHAR,
+                    szWrkData, sizeof(szWrkData)-1, &cbDataLen );
+        if (cbDataLen > 0)
+            m_papszColColumnDef[iCol] = CPLStrdup(szWrkData);
+#endif
     }
 
     return TRUE;
@@ -1729,9 +1780,11 @@ SQLSMALLINT CPLODBCStatement::GetTypeMapping( SQLSMALLINT nTypeCode )
         case SQL_DOUBLE:
             return SQL_C_DOUBLE;
 
+        case SQL_BIGINT:
+            return SQL_C_SBIGINT;
+
         case SQL_BIT:
         case SQL_TINYINT:
-        case SQL_BIGINT:
 /*        case SQL_TYPE_UTCDATETIME:
         case SQL_TYPE_UTCTIME:*/
         case SQL_INTERVAL_MONTH:
diff --git a/port/cpl_odbc.h b/port/cpl_odbc.h
index 9c1ce83..6ada6ce 100644
--- a/port/cpl_odbc.h
+++ b/port/cpl_odbc.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_odbc.h 20579 2010-09-12 11:43:35Z rouault $
+ * $Id: cpl_odbc.h 29025 2015-04-26 11:50:20Z tamas $
  *
  * Project:  OGR ODBC Driver
  * Purpose:  Declarations for ODBC Access Cover API.
@@ -214,6 +214,7 @@ class CPL_DLL CPLODBCStatement {
     _SQLULEN      *m_panColSize;
     SQLSMALLINT   *m_panColPrecision;
     SQLSMALLINT   *m_panColNullable;
+    char         **m_papszColColumnDef;
 
     char         **m_papszColValues;
     _SQLLEN       *m_panColValueLengths;
@@ -253,11 +254,13 @@ class CPL_DLL CPLODBCStatement {
     short          GetColSize( int );
     short          GetColPrecision( int );
     short          GetColNullable( int );
+    const char    *GetColColumnDef( int );
 
     int            GetColId( const char * );
     const char    *GetColData( int, const char * = NULL );
     const char    *GetColData( const char *, const char * = NULL );
     int            GetColDataLength( int );
+    int            GetRowCountAffected();
 
     // Fetch special metadata.
     int            GetColumns( const char *pszTable, 
diff --git a/port/cpl_port.h b/port/cpl_port.h
index 7f0fe75..4dcf37e 100644
--- a/port/cpl_port.h
+++ b/port/cpl_port.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_port.h 27701 2014-09-20 15:07:02Z goatbar $
+ * $Id: cpl_port.h 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Author:   Frank Warmerdam, warmerdam at pobox.com
@@ -219,16 +219,30 @@ typedef int             GBool;
 typedef __int64          GIntBig;
 typedef unsigned __int64 GUIntBig;
 
+#define GINTBIG_MIN     ((GIntBig)(0x80000000) << 32)
+#define GINTBIG_MAX     (((GIntBig)(0x7FFFFFFF) << 32) | 0xFFFFFFFFU)
+
 #elif HAVE_LONG_LONG
 
 typedef long long        GIntBig;
 typedef unsigned long long GUIntBig;
 
+#define GINTBIG_MIN     ((GIntBig)(0x80000000) << 32)
+#define GINTBIG_MAX     (((GIntBig)(0x7FFFFFFF) << 32) | 0xFFFFFFFFU)
+
 #else
 
 typedef long             GIntBig;
 typedef unsigned long    GUIntBig;
 
+#define GINTBIG_MIN     INT_MIN
+#define GINTBIG_MAX     INT_MAX
+#endif
+
+#if SIZEOF_VOIDP == 8
+typedef GIntBig          GPtrDiff_t;
+#else
+typedef int              GPtrDiff_t;
 #endif
 
 #if defined(__MSVCRT__) || (defined(WIN32) && defined(_MSC_VER))
@@ -294,7 +308,7 @@ typedef unsigned long    GUIntBig;
 #endif
 
 /* TODO : support for other compilers needed */
-#if defined(__GNUC__) || defined(_MSC_VER)
+#if (defined(__GNUC__) && !defined(__NO_INLINE__)) || defined(_MSC_VER)
 #define HAS_CPL_INLINE  1
 #define CPL_INLINE __inline
 #elif defined(__SUNPRO_CC)
@@ -602,4 +616,10 @@ static char *cvsid_aw() { return( cvsid_aw() ? ((char *) NULL) : cpl_cvsid ); }
 #endif
 #endif
 
+#ifdef WARN_STANDARD_PRINTF
+int vsnprintf(char *str, size_t size, const char* fmt, va_list args) CPL_WARN_DEPRECATED("Use CPLvsnprintf() instead");
+int snprintf(char *str, size_t size, const char* fmt, ...) CPL_PRINT_FUNC_FORMAT(3,4) CPL_WARN_DEPRECATED("Use CPLsnprintf() instead");
+int sprintf(char *str, const char* fmt, ...) CPL_PRINT_FUNC_FORMAT(2, 3) CPL_WARN_DEPRECATED("Use CPLsprintf() instead");
+#endif
+
 #endif /* ndef CPL_BASE_H_INCLUDED */
diff --git a/port/cpl_progress.cpp b/port/cpl_progress.cpp
index 8b97fc5..8fe7714 100644
--- a/port/cpl_progress.cpp
+++ b/port/cpl_progress.cpp
@@ -45,7 +45,8 @@ CPL_CVSID("$Id: gdal_misc.cpp 25494 2013-01-13 12:55:17Z etourigny $");
  * to use one of the other progress functions that actually do something.
  */
 
-int CPL_STDCALL GDALDummyProgress( CPL_UNUSED double dfComplete, CPL_UNUSED const char *pszMessage,
+int CPL_STDCALL GDALDummyProgress( CPL_UNUSED double dfComplete,
+                                   CPL_UNUSED const char *pszMessage,
                                    CPL_UNUSED void *pData )
 {
     return TRUE;
@@ -73,6 +74,10 @@ int CPL_STDCALL GDALScaledProgress( double dfComplete, const char *pszMessage,
 
 {
     GDALScaledProgressInfo *psInfo = (GDALScaledProgressInfo *) pData;
+    
+    /* optimization if GDALCreateScaledProgress() provided with GDALDummyProgress */
+    if( psInfo == NULL )
+        return TRUE;
 
     return psInfo->pfnProgress( dfComplete * (psInfo->dfMax - psInfo->dfMin)
                                 + psInfo->dfMin,
@@ -133,6 +138,9 @@ void * CPL_STDCALL GDALCreateScaledProgress( double dfMin, double dfMax,
 
 {
     GDALScaledProgressInfo *psInfo;
+    
+    if( pfnProgress == NULL || pfnProgress == GDALDummyProgress )
+        return NULL;
 
     psInfo = (GDALScaledProgressInfo *)
         CPLCalloc(sizeof(GDALScaledProgressInfo),1);
@@ -199,7 +207,8 @@ void CPL_STDCALL GDALDestroyScaledProgress( void * pData )
  * @return Always returns TRUE indicating the process should continue.
  */
 
-int CPL_STDCALL GDALTermProgress( double dfComplete, CPL_UNUSED const char *pszMessage,
+int CPL_STDCALL GDALTermProgress( CPL_UNUSED double dfComplete,
+                                  CPL_UNUSED const char *pszMessage,
                                   void * pProgressArg )
 {
     static int nLastTick = -1;
diff --git a/port/cpl_recode_stub.cpp b/port/cpl_recode_stub.cpp
index 97bd705..34840a5 100644
--- a/port/cpl_recode_stub.cpp
+++ b/port/cpl_recode_stub.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_recode_stub.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_recode_stub.cpp 29121 2015-05-02 22:53:48Z rouault $
  *
  * Name:     cpl_recode_stub.cpp
  * Project:  CPL - Common Portability Library
@@ -32,7 +32,7 @@
 
 #include "cpl_string.h"
 
-CPL_CVSID("$Id: cpl_recode_stub.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_recode_stub.cpp 29121 2015-05-02 22:53:48Z rouault $");
 
 #ifdef CPL_RECODE_STUB 
 
@@ -323,7 +323,7 @@ char *CPLRecodeFromWCharStub( const wchar_t *pwszSource,
 /*      Convert, and confirm we had enough space.                       */
 /* -------------------------------------------------------------------- */
     nDstLen = utf8fromwc( pszResult, nDstBufSize, pwszSource, nSrcLen );
-    if( nDstLen >= nDstBufSize - 1 )
+    if( nDstLen >= nDstBufSize )
     {
         CPLAssert( FALSE ); // too small!
         return NULL;
diff --git a/port/cpl_spawn.cpp b/port/cpl_spawn.cpp
index 6f61aa6..6b8f54c 100644
--- a/port/cpl_spawn.cpp
+++ b/port/cpl_spawn.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_spawn.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_spawn.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement CPLSystem().
@@ -39,7 +39,7 @@
 #define IN_FOR_PARENT   0
 #define OUT_FOR_PARENT  1
 
-CPL_CVSID("$Id: cpl_spawn.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_spawn.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 static void FillFileFromPipe(CPL_FILE_HANDLE pipe_fd, VSILFILE* fout);
 
diff --git a/port/cpl_string.cpp b/port/cpl_string.cpp
index f054921..72b29bb 100644
--- a/port/cpl_string.cpp
+++ b/port/cpl_string.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_string.cpp 28321 2015-01-16 10:33:52Z rouault $
+ * $Id: cpl_string.cpp 28689 2015-03-08 20:05:50Z rouault $
  *
  * Name:     cpl_string.cpp
  * Project:  CPL - Common Portability Library
@@ -46,6 +46,8 @@
  *
  **********************************************************************/
 
+#undef WARN_STANDARD_PRINTF
+
 #include "cpl_string.h"
 #include "cpl_vsi.h"
 #include "cpl_multiproc.h"
@@ -55,7 +57,7 @@
 #  include <wce_string.h>
 #endif
 
-CPL_CVSID("$Id: cpl_string.cpp 28321 2015-01-16 10:33:52Z rouault $");
+CPL_CVSID("$Id: cpl_string.cpp 28689 2015-03-08 20:05:50Z rouault $");
 
 /*=====================================================================
                     StringList manipulation functions.
@@ -636,7 +638,7 @@ char **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
 /************************************************************************/
 
 /**
- * Find a string within a string list.
+ * Find a string within a string list (case insensitive).
  *
  * Returns the index of the entry in the string list that contains the 
  * target string.  The string in the string list must be a full match for
@@ -666,6 +668,42 @@ int CSLFindString( char ** papszList, const char * pszTarget )
 }
 
 /************************************************************************/
+/*                     CSLFindStringCaseSensitive()                     */
+/************************************************************************/
+
+/**
+ * Find a string within a string list(case sensitive)
+ *
+ * Returns the index of the entry in the string list that contains the 
+ * target string.  The string in the string list must be a full match for
+ * the target. 
+ * 
+ * @param papszList the string list to be searched.
+ * @param pszTarget the string to be searched for. 
+ * 
+ * @return the index of the string within the list or -1 on failure.
+ *
+ * @since GDAL 2.0
+ */
+
+int CSLFindStringCaseSensitive( char ** papszList, const char * pszTarget )
+
+{
+    int         i;
+
+    if( papszList == NULL )
+        return -1;
+
+    for( i = 0; papszList[i] != NULL; i++ )
+    {
+        if( strcmp(papszList[i],pszTarget) == 0 )
+            return i;
+    }
+
+    return -1;
+}
+
+/************************************************************************/
 /*                           CSLPartialFindString()                     */
 /************************************************************************/
 
@@ -971,11 +1009,13 @@ const char *CPLSPrintf(const char *fmt, ...)
 /* -------------------------------------------------------------------- */
 
     va_start(args, fmt);
-#if defined(HAVE_VSNPRINTF)
-    vsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
-#else
-    vsprintf(pachBuffer, fmt, args);
-#endif
+
+    int ret = CPLvsnprintf(pachBuffer, CPLSPrintf_BUF_SIZE-1, fmt, args);
+    if( ret < 0 || ret >= CPLSPrintf_BUF_SIZE-1 )
+    {
+        CPLError(CE_Failure, CPLE_AppDefined, "CPLSPrintf() called with too big string. Output will be truncated !");
+    }
+
     va_end(args);
     
     return pachBuffer;
@@ -1022,6 +1062,412 @@ int CPLVASPrintf( char **buf, const char *fmt, va_list ap )
 }
 
 /************************************************************************/
+/*                  CPLvsnprintf_get_end_of_formatting()                */
+/************************************************************************/
+
+static const char* CPLvsnprintf_get_end_of_formatting(const char* fmt)
+{
+    char ch;
+    /*flag */
+    for( ; (ch = *fmt) != '\0'; fmt ++ )
+    {
+        if( ch == '\'' )
+            continue; /* bad idea as this is locale specific */
+        if( ch == '-' || ch == '+' || ch == ' ' || ch == '#' || ch == '0' )
+            continue;
+        break;
+    }
+    
+    /* field width */
+    for( ; (ch = *fmt) != '\0'; fmt ++ )
+    {
+        if( ch == '$' )
+            return NULL; /* we don't want to support this */
+        if( *fmt >= '0' && *fmt <= '9' )
+            continue;
+        break;
+    }
+
+    /* precision */
+    if( ch == '.' )
+    {
+        fmt ++;
+        for( ; (ch = *fmt) != '\0'; fmt ++ )
+        {
+            if( ch == '$' )
+                return NULL; /* we don't want to support this */
+            if( *fmt >= '0' && *fmt <= '9' )
+                continue;
+            break;
+        }
+    }
+
+    /* length modifier */
+    for( ; (ch = *fmt) != '\0'; fmt ++ )
+    {
+        if( ch == 'h' || ch == 'l' || ch == 'j' || ch == 'z' ||
+            ch == 't' || ch == 'L' )
+            continue;
+        else if( ch == 'I' && fmt[1] == '6' && fmt[2] == '4' )
+            fmt += 2;
+        else
+            return fmt;
+    }
+
+    return NULL;
+}
+
+/************************************************************************/
+/*                           CPLvsnprintf()                             */
+/************************************************************************/
+
+#define call_native_snprintf(type) \
+    local_ret = snprintf(str + offset_out, size - offset_out, localfmt, va_arg(wrk_args, type))
+
+/** vsnprintf() wrapper that is not sensitive to LC_NUMERIC settings.
+  *
+  * This function has the same contract as standard vsnprintf(), except that
+  * formatting of floating-point numbers will use decimal point, whatever the
+  * current locale is set.
+  *
+  * @param str output buffer
+  * @param size size of the output buffer (including space for terminating nul)
+  * @param fmt formatting string
+  * @param args arguments
+  * @return the number of characters (excluding terminating nul) that would be written if size is big enough
+  * @since GDAL 2.0
+  */
+int CPLvsnprintf(char *str, size_t size, const char* fmt, va_list args)
+{
+    const char* fmt_ori = fmt;
+    size_t offset_out = 0;
+    va_list wrk_args;
+    char ch;
+    int bFormatUnknown = FALSE;
+
+    if( size == 0 )
+        return vsnprintf(str, size, fmt, args);
+
+#ifdef va_copy
+    va_copy( wrk_args, args );
+#else
+    wrk_args = args;
+#endif
+
+    for( ; (ch = *fmt) != '\0'; fmt ++ )
+    {
+        if( ch == '%' )
+        {
+            const char* ptrend = CPLvsnprintf_get_end_of_formatting(fmt+1);
+            if( ptrend == NULL || ptrend - fmt >= 20 )
+            {
+                bFormatUnknown = TRUE;
+                break;
+            }
+            char end = *ptrend;
+            char end_m1 = ptrend[-1];
+
+            char localfmt[22];
+            memcpy(localfmt, fmt, ptrend - fmt + 1);
+            localfmt[ptrend-fmt+1] = '\0';
+
+            int local_ret;
+            if( end == '%' )
+            {
+                if( offset_out == size-1 )
+                    break;
+                local_ret = 1;
+                str[offset_out] = '%';
+            }
+            else if( end == 'd' ||  end == 'i' ||  end == 'c' )
+            {
+                if( end_m1 == 'h' )
+                    call_native_snprintf(int);
+                else if( end_m1 == 'l' && ptrend[-2] != 'l' )
+                    call_native_snprintf(long);
+                else if( end_m1 == 'l' && ptrend[-2] == 'l' )
+                    call_native_snprintf(GIntBig);
+                else if( end_m1 == '4' && ptrend[-2] == '6' && ptrend[-3] == 'I' ) /* Microsoft I64 modifier */
+                    call_native_snprintf(GIntBig);
+                else if( end_m1 == 'z')
+                    call_native_snprintf(size_t);
+                else if( (end_m1 >= 'a' && end_m1 <= 'z') ||
+                         (end_m1 >= 'A' && end_m1 <= 'Z') )
+                {
+                    bFormatUnknown = TRUE;
+                    break;
+                }
+                else
+                    call_native_snprintf(int);
+            }
+            else  if( end == 'o' || end == 'u' || end == 'x' || end == 'X' )
+            {
+                if( end_m1 == 'h' )
+                    call_native_snprintf(unsigned int);
+                else if( end_m1 == 'l' && ptrend[-2] != 'l' )
+                    call_native_snprintf(unsigned long);
+                else if( end_m1 == 'l' && ptrend[-2] == 'l' )
+                    call_native_snprintf(GUIntBig);
+                else if( end_m1 == '4' && ptrend[-2] == '6' && ptrend[-3] == 'I' ) /* Microsoft I64 modifier */
+                    call_native_snprintf(GUIntBig);
+                else if( end_m1 == 'z')
+                    call_native_snprintf(size_t);
+                else if( (end_m1 >= 'a' && end_m1 <= 'z') ||
+                         (end_m1 >= 'A' && end_m1 <= 'Z') )
+                {
+                    bFormatUnknown = TRUE;
+                    break;
+                }
+                else
+                    call_native_snprintf(unsigned int);
+            }
+            else if( end == 'e' || end == 'E' ||
+                     end == 'f' || end == 'F' ||
+                     end == 'g' || end == 'G' ||
+                     end == 'a' || end == 'A' )
+            {
+                if( end_m1 == 'L' )
+                    call_native_snprintf(long double);
+                else
+                    call_native_snprintf(double);
+                /* MSVC vsnprintf() returns -1... */
+                if( local_ret <  0 || offset_out + local_ret >= size )
+                    break;
+                for( int j = 0; j < local_ret; j ++ )
+                {
+                    if( str[offset_out + j] == ',' )
+                    {
+                        str[offset_out + j] = '.';
+                        break;
+                    }
+                }
+            }
+            else if( end == 's' )
+            {
+                call_native_snprintf(char*);
+            }
+            else if( end == 'p' )
+            {
+                call_native_snprintf(void*);
+            }
+            else
+            {
+                bFormatUnknown = TRUE;
+                break;
+            }
+            /* MSVC vsnprintf() returns -1... */
+            if( local_ret <  0 || offset_out + local_ret >= size )
+                break;
+            offset_out += local_ret;
+            fmt = ptrend;
+        }
+        else
+        {
+            if( offset_out == size-1 )
+                break;
+            str[offset_out++] = *fmt;
+        }
+    }
+    if( ch == '\0' && offset_out < size )
+        str[offset_out] = '\0';
+    else
+    {
+        if( bFormatUnknown )
+        {
+            CPLDebug("CPL", "CPLvsnprintf() called with unsupported formatting string: %s", fmt_ori);
+        }
+#ifdef va_copy
+        va_end( wrk_args );
+        va_copy( wrk_args, args );
+#else
+        wrk_args = args;
+#endif
+#if defined(HAVE_VSNPRINTF)
+        offset_out = vsnprintf(str, size, fmt_ori, wrk_args);
+#else
+        offset_out = vsprintf(str, fmt_ori, wrk_args);
+#endif
+    }
+
+#ifdef va_copy
+    va_end( wrk_args );
+#endif
+
+    return (int)offset_out;
+}
+
+/************************************************************************/
+/*                           CPLsnprintf()                              */
+/************************************************************************/
+
+/** snprintf() wrapper that is not sensitive to LC_NUMERIC settings.
+  *
+  * This function has the same contract as standard snprintf(), except that
+  * formatting of floating-point numbers will use decimal point, whatever the
+  * current locale is set.
+  *
+  * @param str output buffer
+  * @param size size of the output buffer (including space for terminating nul)
+  * @param fmt formatting string
+  * @param ... arguments
+  * @return the number of characters (excluding terminating nul) that would be written if size is big enough
+  * @since GDAL 2.0
+  */
+int CPLsnprintf(char *str, size_t size, const char* fmt, ...)
+{
+    int ret;
+    va_list args;
+
+    va_start( args, fmt );
+    ret = CPLvsnprintf( str, size, fmt, args );
+    va_end( args );
+    return ret;
+}
+
+/************************************************************************/
+/*                           CPLsprintf()                               */
+/************************************************************************/
+
+/** sprintf() wrapper that is not sensitive to LC_NUMERIC settings.
+  *
+  * This function has the same contract as standard sprintf(), except that
+  * formatting of floating-point numbers will use decimal point, whatever the
+  * current locale is set.
+  *
+  * @param str output buffer (must be large enough to hold the result)
+  * @param fmt formatting string
+  * @param ... arguments
+  * @return the number of characters (excluding terminating nul) written in output buffer.
+  * @since GDAL 2.0
+  */
+int CPLsprintf(char *str, const char* fmt, ...)
+{
+    int ret;
+    va_list args;
+
+    va_start( args, fmt );
+    ret = CPLvsnprintf( str, INT_MAX, fmt, args );
+    va_end( args );
+    return ret;
+}
+
+/************************************************************************/
+/*                           CPLprintf()                                */
+/************************************************************************/
+
+/** printf() wrapper that is not sensitive to LC_NUMERIC settings.
+  *
+  * This function has the same contract as standard printf(), except that
+  * formatting of floating-point numbers will use decimal point, whatever the
+  * current locale is set.
+  *
+  * @param fmt formatting string
+  * @param ... arguments
+  * @return the number of characters (excluding terminating nul) written in output buffer.
+  * @since GDAL 2.0
+  */
+int CPLprintf(const char* fmt, ...)
+{
+    char szBuffer[4096];
+    int ret;
+    va_list wrk_args, args;
+
+    va_start( args, fmt );
+
+#ifdef va_copy
+    va_copy( wrk_args, args );
+#else
+    wrk_args = args;
+#endif
+
+    ret = CPLvsnprintf( szBuffer, sizeof(szBuffer), fmt, wrk_args );
+
+    if( ret < (int)sizeof(szBuffer)-1 )
+        ret = printf("%s", szBuffer);
+    else
+    {
+#ifdef va_copy
+        va_end( wrk_args );
+        va_copy( wrk_args, args );
+#else
+        wrk_args = args;
+#endif
+        ret = vfprintf(stdout, fmt, wrk_args);
+    }
+
+    va_end( wrk_args );
+
+    return ret;
+}
+
+/************************************************************************/
+/*                           CPLsscanf()                                */
+/************************************************************************/
+
+/** sscanf() wrapper that is not sensitive to LC_NUMERIC settings.
+  *
+  * This function has the same contract as standard sscanf(), except that
+  * formatting of floating-point numbers will use decimal point, whatever the
+  * current locale is set.
+  *
+  * CAUTION: only works with a very limited number of formatting strings,
+  * consisting only of "%lf" and regular characters.
+  *
+  * param str input string
+  * @param fmt formatting string
+  * @param ... arguments
+  * @return the number of matched patterns;
+  * @since GDAL 2.0
+  */
+int CPL_DLL CPLsscanf(const char* str, const char* fmt, ...)
+{
+    int error = FALSE;
+    int ret = 0;
+    const char* fmt_ori = fmt;
+    va_list args;
+
+    va_start( args, fmt );
+    for( ; *fmt != '\0' && *str != '\0'; fmt++ )
+    {
+        if( *fmt == '%' )
+        {
+            if( fmt[1] == 'l' && fmt[2] == 'f' )
+            {
+                fmt += 2;
+                char* end;
+                *(va_arg(args, double*)) = CPLStrtod(str, &end);
+                if( end > str )
+                {
+                    ret ++;
+                    str = end;
+                }
+                else
+                    break;
+            }
+            else
+            {
+                error = TRUE;
+                break;
+            }
+        }
+        else if( *str != *fmt )
+            break;
+        else
+            str ++;
+    }
+    va_end( args );
+
+    if( error )
+    {
+        CPLError(CE_Failure, CPLE_NotSupported,
+                 "Format %s not supported by CPLsscanf()",
+                 fmt_ori);
+    }
+
+    return ret;
+}
+
+/************************************************************************/
 /*                         CSLTestBoolean()                             */
 /************************************************************************/
 
@@ -1289,7 +1735,7 @@ char **CSLAddNameValue(char **papszStrList,
         return papszStrList;
 
     pszLine = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
-    sprintf( pszLine, "%s=%s", pszName, pszValue );
+    CPLsprintf( pszLine, "%s=%s", pszName, pszValue );
     papszStrList = CSLAddString(papszStrList, pszLine);
     CPLFree( pszLine );
 
@@ -1364,7 +1810,7 @@ char **CSLSetNameValue(char **papszList,
             else
             {
                 *papszPtr = (char *) CPLMalloc(strlen(pszName)+strlen(pszValue)+2);
-                sprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
+                CPLsprintf( *papszPtr, "%s%c%s", pszName, cSep, pszValue );
             }
             return papszList;
         }
@@ -1534,7 +1980,7 @@ char *CPLEscapeString( const char *pszInput, int nLength,
             }
             else
             {
-                sprintf( pszOutput+iOut, "%%%02X", ((unsigned char*)pszInput)[iIn] );
+                CPLsprintf( pszOutput+iOut, "%%%02X", ((unsigned char*)pszInput)[iIn] );
                 iOut += 3;
             }
         }
@@ -1577,6 +2023,22 @@ char *CPLEscapeString( const char *pszInput, int nLength,
                 pszOutput[iOut++] = 't';
                 pszOutput[iOut++] = ';';
             }
+            /* Python 2 doesn't like displaying the UTF-8 character corresponding */
+            /* to BOM, so escape it */
+            else if( ((GByte*)pszInput)[iIn] == 0xEF &&
+                     ((GByte*)pszInput)[iIn+1] == 0xBB &&
+                     ((GByte*)pszInput)[iIn+2] == 0xBF )
+            {
+                pszOutput[iOut++] = '&';
+                pszOutput[iOut++] = '#';
+                pszOutput[iOut++] = 'x';
+                pszOutput[iOut++] = 'F';
+                pszOutput[iOut++] = 'E';
+                pszOutput[iOut++] = 'F';
+                pszOutput[iOut++] = 'F';
+                pszOutput[iOut++] = ';';
+                iIn += 2;
+            }
             else if( ((GByte*)pszInput)[iIn] < 0x20 
                      && pszInput[iIn] != 0x9
                      && pszInput[iIn] != 0xA 
@@ -1725,7 +2187,7 @@ char *CPLUnescapeString( const char *pszInput, int *pnLength, int nScheme )
                     ch = pszInput[iIn ++];
                     if (ch >= 'a' && ch <= 'f')
                         anVal[0] = anVal[0] * 16 + ch - 'a' + 10;
-                    else if (ch >= 'A' && ch <= 'A')
+                    else if (ch >= 'A' && ch <= 'F')
                         anVal[0] = anVal[0] * 16 + ch - 'A' + 10;
                     else if (ch >= '0' && ch <= '9')
                         anVal[0] = anVal[0] * 16 + ch - '0';
@@ -1898,7 +2360,6 @@ char *CPLBinaryToHex( int nBytes, const GByte *pabyData )
     return pszHex;
 }
 
-
 /************************************************************************/
 /*                           CPLHexToBinary()                           */
 /************************************************************************/
@@ -2170,7 +2631,7 @@ size_t CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize)
  * the specified number of bytes.
  *
  * The CPLStrnlen() function returns MIN(strlen(pszStr), nMaxLen).
- * Only the first nMaxLen bytes of the string will be read. Usefull to
+ * Only the first nMaxLen bytes of the string will be read. Useful to
  * test if a string contains at least nMaxLen characters without reading
  * the full string up to the NUL terminating character.
  *
diff --git a/port/cpl_string.h b/port/cpl_string.h
index 93cb844..956352f 100644
--- a/port/cpl_string.h
+++ b/port/cpl_string.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_string.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_string.h 28025 2014-11-28 00:01:32Z rouault $
  *
  * Name:     cpl_string.h
  * Project:  CPL - Common Portability Library
@@ -94,6 +94,7 @@ char CPL_DLL **CSLInsertString(char **papszStrList, int nInsertAtLineNo,
 char CPL_DLL **CSLRemoveStrings(char **papszStrList, int nFirstLineToDelete,
                          int nNumToRemove, char ***ppapszRetStrings) CPL_WARN_UNUSED_RESULT;
 int CPL_DLL CSLFindString( char **, const char * );
+int CPL_DLL CSLFindStringCaseSensitive( char **, const char * );
 int CPL_DLL CSLPartialFindString( char **papszHaystack, 
 	const char * pszNeedle );
 int CPL_DLL CSLFindName(char **papszStrList, const char *pszName);
@@ -101,10 +102,6 @@ int CPL_DLL CSLTestBoolean( const char *pszValue );
 int CPL_DLL CSLFetchBoolean( char **papszStrList, const char *pszKey, 
                              int bDefault );
 
-const char CPL_DLL *CPLSPrintf(const char *fmt, ...) CPL_PRINT_FUNC_FORMAT(1, 2);
-char CPL_DLL **CSLAppendPrintf(char **papszStrList, const char *fmt, ...) CPL_PRINT_FUNC_FORMAT(2, 3) CPL_WARN_UNUSED_RESULT;
-int CPL_DLL CPLVASPrintf(char **buf, const char *fmt, va_list args );
-
 const char CPL_DLL *
       CPLParseNameValue(const char *pszNameValue, char **ppszKey );
 const char CPL_DLL *
@@ -155,6 +152,19 @@ size_t CPL_DLL CPLStrlcat(char* pszDest, const char* pszSrc, size_t nDestSize);
 size_t CPL_DLL CPLStrnlen (const char *pszStr, size_t nMaxLen);
 
 /* -------------------------------------------------------------------- */
+/*      Locale independant formatting functions.                        */
+/* -------------------------------------------------------------------- */
+int CPL_DLL CPLvsnprintf(char *str, size_t size, const char* fmt, va_list args);
+int CPL_DLL CPLsnprintf(char *str, size_t size, const char* fmt, ...) CPL_PRINT_FUNC_FORMAT(3,4);
+int CPL_DLL CPLsprintf(char *str, const char* fmt, ...) CPL_PRINT_FUNC_FORMAT(2, 3);
+int CPL_DLL CPLprintf(const char* fmt, ...) CPL_PRINT_FUNC_FORMAT(1, 2);
+int CPL_DLL CPLsscanf(const char* str, const char* fmt, ...); /* caution: only works with limited number of formats */
+
+const char CPL_DLL *CPLSPrintf(const char *fmt, ...) CPL_PRINT_FUNC_FORMAT(1, 2);
+char CPL_DLL **CSLAppendPrintf(char **papszStrList, const char *fmt, ...) CPL_PRINT_FUNC_FORMAT(2, 3) CPL_WARN_UNUSED_RESULT;
+int CPL_DLL CPLVASPrintf(char **buf, const char *fmt, va_list args );
+
+/* -------------------------------------------------------------------- */
 /*      RFC 23 character set conversion/recoding API (cpl_recode.cpp).  */
 /* -------------------------------------------------------------------- */
 #define CPL_ENC_LOCALE     ""
@@ -343,7 +353,7 @@ class CPL_DLL CPLStringList
     CPLStringList &AddNameValue( const char *pszKey, const char *pszValue );
     CPLStringList &SetNameValue( const char *pszKey, const char *pszValue );
 
-    CPLStringList &Assign( char **papszList, int bTakeOwnership=TRUE );
+    CPLStringList &Assign( char **papszListIn, int bTakeOwnership=TRUE );
     CPLStringList &operator=(char **papszListIn) { return Assign( papszListIn, TRUE ); }
     CPLStringList &operator=(const CPLStringList& oOther);
 
diff --git a/port/cpl_strtod.cpp b/port/cpl_strtod.cpp
index c1d296d..75c5a92 100644
--- a/port/cpl_strtod.cpp
+++ b/port/cpl_strtod.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_strtod.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_strtod.cpp 28849 2015-04-05 14:05:18Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Functions to convert ASCII string to floating point number.
@@ -34,7 +34,7 @@
 
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: cpl_strtod.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_strtod.cpp 28849 2015-04-05 14:05:18Z goatbar $");
 
 // XXX: with GCC 2.95 strtof() function is only available when in c99 mode.
 // Fix it here not touching the compiler options.
@@ -68,6 +68,14 @@ static float CPLNaN(void)
         return 1.0 / ZERO; /* MSVC doesn't like 1.0 / 0.0 */
     }
     #define INFINITY CPLInfinity()
+    static CPL_INLINE double CPLNegInfinity(void)
+    {
+        static double ZERO = 0;
+        return -1.0 / ZERO; /* MSVC doesn't like -1.0 / 0.0 */
+    }
+    #define NEG_INFINITY CPLNegInfinity()
+#else
+    #define NEG_INFINITY (-INFINITY)
 #endif
 
 /************************************************************************/
@@ -116,16 +124,16 @@ double CPLAtofDelim(const char *nptr, char point)
  * custom delimiter.
  *
  * IMPORTANT NOTE.
- * Existance of this function does not mean you should always use it.
+ * Existence of this function does not mean you should always use it.
  * Sometimes you should use standard locale aware atof(3) and its family. When
  * you need to process the user's input (for example, command line parameters)
- * use atof(3), because user works in localized environment and her input will
- * be done accordingly the locale set. In particular that means we should not
+ * use atof(3), because the user works in a localized environment and the user's input will
+ * be done according to the locale set. In particular that means we should not
  * make assumptions about character used as decimal delimiter, it can be
  * either "." or ",".
  * But when you are parsing some ASCII file in predefined format, you most
  * likely need CPLAtof(), because such files distributed across the systems
- * with different locales and floating point representation shoudl be
+ * with different locales and floating point representation should be
  * considered as a part of file format. If the format uses "." as a delimiter
  * the same character must be used when parsing number regardless of actual
  * locale setting.
@@ -204,17 +212,21 @@ static char* CPLReplacePointByLocalePoint(const char* pszNumber, char point)
     struct lconv *poLconv = localeconv();
     if ( poLconv
          && poLconv->decimal_point
-         && strlen(poLconv->decimal_point) > 0 )
+         && poLconv->decimal_point[0] != '\0' )
     {
         char    byPoint = poLconv->decimal_point[0];
 
         if (point != byPoint)
         {
+            const char* pszLocalePoint = strchr(pszNumber, byPoint);
             const char* pszPoint = strchr(pszNumber, point);
-            if (pszPoint)
+            if (pszPoint || pszLocalePoint)
             {
                 char* pszNew = CPLStrdup(pszNumber);
-                pszNew[pszPoint - pszNumber] = byPoint;
+                if( pszLocalePoint )
+                    pszNew[pszLocalePoint - pszNumber] = ' ';
+                if( pszPoint )
+                    pszNew[pszPoint - pszNumber] = byPoint;
                 return pszNew;
             }
         }
@@ -253,23 +265,41 @@ double CPLStrtodDelim(const char *nptr, char **endptr, char point)
     {
         if (strcmp(nptr, "-1.#QNAN") == 0 ||
             strcmp(nptr, "-1.#IND") == 0)
+        {
+            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
             return NAN;
+        }
 
         if (strcmp(nptr,"-inf") == 0 ||
             strcmp(nptr,"-1.#INF") == 0)
-            return -INFINITY;
+        {
+            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
+            return NEG_INFINITY;
+        }
     }
     else if (nptr[0] == '1')
     {
         if (strcmp(nptr, "1.#QNAN") == 0)
+        {
+            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
             return NAN;
+        }
         if (strcmp (nptr,"1.#INF") == 0)
+        {
+            if( endptr ) *endptr = (char*)nptr + strlen(nptr);
             return INFINITY;
+        }
     }
     else if (nptr[0] == 'i' && strcmp(nptr,"inf") == 0)
+    {
+        if( endptr ) *endptr = (char*)nptr + strlen(nptr);
         return INFINITY;
+    }
     else if (nptr[0] == 'n' && strcmp(nptr,"nan") == 0)
+    {
+        if( endptr ) *endptr = (char*)nptr + strlen(nptr);
         return NAN;
+    }
 
 /* -------------------------------------------------------------------- */
 /*  We are implementing a simple method here: copy the input string     */
diff --git a/port/cpl_virtualmem.cpp b/port/cpl_virtualmem.cpp
index 4aed6ed..529962a 100644
--- a/port/cpl_virtualmem.cpp
+++ b/port/cpl_virtualmem.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_virtualmem.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_virtualmem.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Name:     cpl_virtualmem.cpp
  * Project:  CPL - Common Portability Library
@@ -54,8 +54,6 @@
 #include <unistd.h>     /* read, write, close, pipe */
 #include <pthread.h>
 
-#define HAVE_5ARGS_MREMAP
-
 #ifndef HAVE_5ARGS_MREMAP
 #include "cpl_atomic_ops.h"
 #endif
@@ -135,7 +133,7 @@ struct CPLVirtualMem
     void                   *pCbkUserData;
     CPLVirtualMemFreeUserData     pfnFreeUserData;
 #ifndef HAVE_5ARGS_MREMAP
-    void                   *hMutexThreadArray;
+    CPLMutex               *hMutexThreadArray;
     int                     nThreads;
     pthread_t              *pahThreads;
 #endif
@@ -150,7 +148,7 @@ typedef struct
     int              pipefd_to_thread[2];
     int              pipefd_from_thread[2];
     int              pipefd_wait_thread[2];
-    void            *hHelperThread;
+    CPLJoinableThread *hHelperThread;
 
     struct sigaction oldact;
 } CPLVirtualMemManager;
@@ -163,7 +161,7 @@ typedef struct
 } CPLVirtualMemMsgToWorkerThread;
 
 static CPLVirtualMemManager* pVirtualMemManager = NULL;
-static void* hVirtualMemManagerMutex = NULL;
+static CPLMutex* hVirtualMemManagerMutex = NULL;
 
 static void CPLVirtualMemManagerInit();
 
@@ -2048,7 +2046,9 @@ void CPLVirtualMemUnDeclareThread(CPL_UNUSED CPLVirtualMem* ctxt)
 }
 
 void CPLVirtualMemPin(CPL_UNUSED CPLVirtualMem* ctxt,
-                      CPL_UNUSED void* pAddr, CPL_UNUSED size_t nSize, CPL_UNUSED int bWriteOp)
+                      CPL_UNUSED void* pAddr,
+                      CPL_UNUSED size_t nSize,
+                      CPL_UNUSED int bWriteOp)
 {
 }
 
diff --git a/port/cpl_virtualmem.h b/port/cpl_virtualmem.h
index 95f63b7..830f066 100644
--- a/port/cpl_virtualmem.h
+++ b/port/cpl_virtualmem.h
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_virtualmem.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_virtualmem.h 28543 2015-02-23 21:01:19Z rouault $
  *
  * Name:     cpl_virtualmem.h
  * Project:  CPL - Common Portability Library
@@ -115,7 +115,7 @@ typedef enum
  *
  * @return the page size.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 size_t CPL_DLL CPLGetPageSize(void);
 
@@ -160,7 +160,7 @@ size_t CPL_DLL CPLGetPageSize(void);
  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
  *         or NULL in case of failure.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 
 CPLVirtualMem CPL_DLL *CPLVirtualMemNew(size_t nSize,
@@ -177,7 +177,7 @@ CPLVirtualMem CPL_DLL *CPLVirtualMemNew(size_t nSize,
 /** Return if virtual memory mapping of a file is available.
  *
  * @return TRUE if virtual memory mapping of a file is available.
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 int CPL_DLL CPLIsVirtualMemFileMapAvailable(void);
 
@@ -204,7 +204,7 @@ int CPL_DLL CPLIsVirtualMemFileMapAvailable(void);
  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
  *         or NULL in case of failure.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 CPLVirtualMem CPL_DLL *CPLVirtualMemFileMapNew( VSILFILE* fp,
                                                 vsi_l_offset nOffset,
@@ -216,7 +216,7 @@ CPLVirtualMem CPL_DLL *CPLVirtualMemFileMapNew( VSILFILE* fp,
 /** Create a new virtual memory mapping derived from an other virtual memory
  *  mapping.
  *
- * This may be usefull in case of creating mapping for pixel interleaved data.
+ * This may be useful in case of creating mapping for pixel interleaved data.
  *
  * The new mapping takes a reference on the base mapping.
  *
@@ -230,7 +230,7 @@ CPLVirtualMem CPL_DLL *CPLVirtualMemFileMapNew( VSILFILE* fp,
  * @return a virtual memory object that must be freed by CPLVirtualMemFree(),
  *         or NULL in case of failure.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 CPLVirtualMem CPL_DLL *CPLVirtualMemDerivedNew(CPLVirtualMem* pVMemBase,
                                                vsi_l_offset nOffset,
@@ -247,7 +247,7 @@ CPLVirtualMem CPL_DLL *CPLVirtualMemDerivedNew(CPLVirtualMem* pVMemBase,
  *
  * @param ctxt context returned by CPLVirtualMemNew().
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 void CPL_DLL CPLVirtualMemFree(CPLVirtualMem* ctxt);
 
@@ -264,7 +264,7 @@ void CPL_DLL CPLVirtualMemFree(CPLVirtualMem* ctxt);
  * @param ctxt context returned by CPLVirtualMemNew().
  * @return the pointer to the start of a virtual memory mapping.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 void CPL_DLL *CPLVirtualMemGetAddr(CPLVirtualMem* ctxt);
 
@@ -273,7 +273,7 @@ void CPL_DLL *CPLVirtualMemGetAddr(CPLVirtualMem* ctxt);
  * @param ctxt context returned by CPLVirtualMemNew().
  * @return the size of the virtual memory mapping.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 size_t CPL_DLL CPLVirtualMemGetSize(CPLVirtualMem* ctxt);
 
@@ -282,7 +282,7 @@ size_t CPL_DLL CPLVirtualMemGetSize(CPLVirtualMem* ctxt);
  * @param ctxt context returned by CPLVirtualMemNew().
  * @return TRUE if the virtal memory mapping is a direct file mapping.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 int CPL_DLL CPLVirtualMemIsFileMapping(CPLVirtualMem* ctxt);
 
@@ -291,7 +291,7 @@ int CPL_DLL CPLVirtualMemIsFileMapping(CPLVirtualMem* ctxt);
  * @param ctxt context returned by CPLVirtualMemNew().
  * @return the access mode of the virtual memory mapping.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 CPLVirtualMemAccessMode CPL_DLL CPLVirtualMemGetAccessMode(CPLVirtualMem* ctxt);
 
@@ -303,7 +303,7 @@ CPLVirtualMemAccessMode CPL_DLL CPLVirtualMemGetAccessMode(CPLVirtualMem* ctxt);
  * @param ctxt context returned by CPLVirtualMemNew().
  * @return the page size
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 size_t CPL_DLL CPLVirtualMemGetPageSize(CPLVirtualMem* ctxt);
 
@@ -322,7 +322,7 @@ size_t CPL_DLL CPLVirtualMemGetPageSize(CPLVirtualMem* ctxt);
  * @return TRUE if this memory mapping can be accessed safely from concurrent
  *         threads.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 int CPL_DLL CPLVirtualMemIsAccessThreadSafe(CPLVirtualMem* ctxt);
 
@@ -336,7 +336,7 @@ int CPL_DLL CPLVirtualMemIsAccessThreadSafe(CPLVirtualMem* ctxt);
  *
  * @param ctxt context returned by CPLVirtualMemNew().
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 void CPL_DLL CPLVirtualMemDeclareThread(CPLVirtualMem* ctxt);
 
@@ -350,13 +350,13 @@ void CPL_DLL CPLVirtualMemDeclareThread(CPLVirtualMem* ctxt);
  *
  * @param ctxt context returned by CPLVirtualMemNew().
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 void CPL_DLL CPLVirtualMemUnDeclareThread(CPLVirtualMem* ctxt);
 
 /** Make sure that a region of virtual memory will be realized.
  *
- * Calling this function is not required, but might be usefull when debugging
+ * Calling this function is not required, but might be useful when debugging
  * a process with tools like gdb or valgrind that do not naturally like
  * segmentation fault signals.
  *
@@ -369,7 +369,7 @@ void CPL_DLL CPLVirtualMemUnDeclareThread(CPLVirtualMem* ctxt);
  * @param nSize the size of the memory region.
  * @param bWriteOp set to TRUE if the memory are will be accessed in write mode.
  *
- * @since GDAL 2.0
+ * @since GDAL 1.11
  */
 void CPL_DLL CPLVirtualMemPin(CPLVirtualMem* ctxt,
                               void* pAddr, size_t nSize, int bWriteOp);
diff --git a/port/cpl_vsi.h b/port/cpl_vsi.h
index 86a8006..23b3596 100644
--- a/port/cpl_vsi.h
+++ b/port/cpl_vsi.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsi.h 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_vsi.h 28476 2015-02-13 14:40:11Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Author:   Frank Warmerdam, warmerdam at pobox.com
@@ -202,6 +202,8 @@ void CPL_DLL *VSIMalloc2( size_t nSize1, size_t nSize2 ) CPL_WARN_UNUSED_RESULT;
 */
 void CPL_DLL *VSIMalloc3( size_t nSize1, size_t nSize2, size_t nSize3 ) CPL_WARN_UNUSED_RESULT;
 
+GIntBig CPL_DLL CPLGetPhysicalRAM(void);
+GIntBig CPL_DLL CPLGetUsablePhysicalRAM(void);
 
 /* ==================================================================== */
 /*      Other...                                                        */
@@ -240,6 +242,9 @@ GByte CPL_DLL *VSIGetMemFileBuffer( const char *pszFilename,
                                     vsi_l_offset *pnDataLength, 
                                     int bUnlinkAndSeize );
 
+typedef size_t (*VSIWriteFunction)(const void* ptr, size_t size, size_t nmemb, FILE* stream);
+void CPL_DLL VSIStdoutSetRedirection( VSIWriteFunction pFct, FILE* stream );
+
 /* ==================================================================== */
 /*      Time quering.                                                   */
 /* ==================================================================== */
diff --git a/port/cpl_vsi_mem.cpp b/port/cpl_vsi_mem.cpp
index f12093d..fa52736 100644
--- a/port/cpl_vsi_mem.cpp
+++ b/port/cpl_vsi_mem.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsi_mem.cpp 27157 2014-04-12 12:59:41Z rouault $
+ * $Id: cpl_vsi_mem.cpp 28976 2015-04-22 21:58:51Z rouault $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Implementation of Memory Buffer virtual IO functions.
@@ -36,6 +36,7 @@
 #include "cpl_vsi_virtual.h"
 #include "cpl_string.h"
 #include "cpl_multiproc.h"
+#include <time.h>
 #include <map>
 
 #if defined(WIN32CE)
@@ -43,7 +44,7 @@
 #endif
 
 
-CPL_CVSID("$Id: cpl_vsi_mem.cpp 27157 2014-04-12 12:59:41Z rouault $");
+CPL_CVSID("$Id: cpl_vsi_mem.cpp 28976 2015-04-22 21:58:51Z rouault $");
 
 /*
 ** Notes on Multithreading:
@@ -91,7 +92,7 @@ public:
     vsi_l_offset  nLength;
     vsi_l_offset  nAllocLength;
 
-    int           bEOF;
+    time_t        mTime;
 
                   VSIMemFile();
     virtual       ~VSIMemFile();
@@ -112,6 +113,10 @@ class VSIMemHandle : public VSIVirtualHandle
     vsi_l_offset  nOffset;
     int           bUpdate;
     int           bEOF;
+    int           bExtendFileAtNextWrite;
+    
+                      VSIMemHandle() : poFile(NULL), nOffset(0), bUpdate(0),
+                                       bEOF(0), bExtendFileAtNextWrite(0) {}
 
     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     virtual vsi_l_offset Tell();
@@ -132,7 +137,7 @@ class VSIMemFilesystemHandler : public VSIFilesystemHandler
 {
 public:
     std::map<CPLString,VSIMemFile*>   oFileList;
-    void             *hMutex;
+    CPLMutex        *hMutex;
 
                      VSIMemFilesystemHandler();
     virtual          ~VSIMemFilesystemHandler();
@@ -147,6 +152,8 @@ public:
     virtual int      Rename( const char *oldpath, const char *newpath );
 
     static  void     NormalizePath( CPLString & );
+
+    int              Unlink_unlocked( const char *pszFilename );
 };
 
 /************************************************************************/
@@ -168,7 +175,7 @@ VSIMemFile::VSIMemFile()
     pabyData = NULL;
     nLength = 0;
     nAllocLength = 0;
-    bEOF = FALSE;
+    time(&mTime);
 }
 
 /************************************************************************/
@@ -205,14 +212,16 @@ bool VSIMemFile::SetLength( vsi_l_offset nNewLength )
         if( !bOwnData )
         {
             CPLError(CE_Failure, CPLE_NotSupported,
-                     "Cannot extended in-memory file whose ownership was not transfered");
+                     "Cannot extended in-memory file whose ownership was not transferred");
             return false;
         }
         
         GByte *pabyNewData;
         vsi_l_offset nNewAlloc = (nNewLength + nNewLength / 10) + 5000;
-
-        pabyNewData = (GByte *) VSIRealloc(pabyData, (size_t)nNewAlloc);
+        if( (vsi_l_offset)(size_t)nNewAlloc != nNewAlloc )
+            pabyNewData = NULL;
+        else
+            pabyNewData = (GByte *) VSIRealloc(pabyData, (size_t)nNewAlloc);
         if( pabyNewData == NULL )
         {
             CPLError(CE_Failure, CPLE_OutOfMemory,
@@ -230,6 +239,7 @@ bool VSIMemFile::SetLength( vsi_l_offset nNewLength )
     }
 
     nLength = nNewLength;
+    time(&mTime);
 
     return true;
 }
@@ -263,6 +273,7 @@ int VSIMemHandle::Close()
 int VSIMemHandle::Seek( vsi_l_offset nOffset, int nWhence )
 
 {
+    bExtendFileAtNextWrite = FALSE;
     if( nWhence == SEEK_CUR )
         this->nOffset += nOffset;
     else if( nWhence == SEEK_SET )
@@ -292,8 +303,7 @@ int VSIMemHandle::Seek( vsi_l_offset nOffset, int nWhence )
         }
         else // Writeable files are zero-extended by seek past end.
         {
-            if( !poFile->SetLength( this->nOffset ) )
-                return -1;
+            bExtendFileAtNextWrite = TRUE;
         }
     }
 
@@ -351,9 +361,17 @@ size_t VSIMemHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
         errno = EACCES;
         return 0;
     }
+    if( bExtendFileAtNextWrite )
+    {
+        bExtendFileAtNextWrite = FALSE;
+        if( !poFile->SetLength( nOffset ) )
+            return 0;
+    }
 
     // FIXME: Integer overflow check should be placed here:
     size_t nBytesToWrite = nSize * nCount; 
+    //if( CSLTestBoolean(CPLGetConfigOption("VERBOSE_IO", "FALSE")) )
+    //    CPLDebug("MEM", "Write(%d bytes in [%d,%d[)", (int)nBytesToWrite, (int)nOffset, (int)(nOffset+nBytesToWrite));
 
     if( nBytesToWrite + nOffset > poFile->nLength )
     {
@@ -364,6 +382,8 @@ size_t VSIMemHandle::Write( const void * pBuffer, size_t nSize, size_t nCount )
     memcpy( poFile->pabyData + nOffset, pBuffer, nBytesToWrite );
     nOffset += nBytesToWrite;
 
+    time(&poFile->mTime);
+
     return nCount;
 }
 
@@ -389,6 +409,7 @@ int VSIMemHandle::Truncate( vsi_l_offset nNewSize )
         return -1;
     }
 
+    bExtendFileAtNextWrite = FALSE;
     if (poFile->SetLength( nNewSize ))
         return 0;
     else
@@ -544,6 +565,7 @@ int VSIMemFilesystemHandler::Stat( const char * pszFilename,
     {
         pStatBuf->st_size = poFile->nLength;
         pStatBuf->st_mode = S_IFREG;
+        pStatBuf->st_mtime = poFile->mTime;
     }
 
     return 0;
@@ -557,7 +579,16 @@ int VSIMemFilesystemHandler::Unlink( const char * pszFilename )
 
 {
     CPLMutexHolder oHolder( &hMutex );
+    return Unlink_unlocked(pszFilename);
+}
 
+/************************************************************************/
+/*                           Unlink_unlocked()                          */
+/************************************************************************/
+
+int VSIMemFilesystemHandler::Unlink_unlocked( const char * pszFilename )
+
+{
     CPLString osFilename = pszFilename;
     NormalizePath( osFilename );
 
@@ -620,8 +651,6 @@ int VSIMemFilesystemHandler::Mkdir( const char * pszPathname,
 int VSIMemFilesystemHandler::Rmdir( const char * pszPathname )
 
 {
-    CPLMutexHolder oHolder( &hMutex );
-
     return Unlink( pszPathname );
 }
 
@@ -705,14 +734,20 @@ int VSIMemFilesystemHandler::Rename( const char *pszOldPath,
     }
     else
     {
-        VSIMemFile* poFile = oFileList[osOldPath];
-
-        oFileList.erase( oFileList.find(osOldPath) );
-
-        Unlink(osNewPath);
-
-        oFileList[osNewPath] = poFile;
-        poFile->osFilename = osNewPath;
+        std::map<CPLString,VSIMemFile*>::iterator it = oFileList.find(osOldPath);
+        while (it != oFileList.end() && it->first.ifind(osOldPath) == 0)
+        {
+            const CPLString osRemainder = it->first.substr(osOldPath.size());
+            if (osRemainder.empty() || osRemainder[0] == '/')
+            {
+                const CPLString osNewFullPath = osNewPath + osRemainder;
+                Unlink_unlocked(osNewFullPath);
+                oFileList[osNewFullPath] = it->second;
+                it->second->osFilename = osNewFullPath;
+                oFileList.erase(it++);
+            }
+            else ++it;
+        }
 
         return 0;
     }
@@ -851,7 +886,7 @@ VSILFILE *VSIFileFromMemBuffer( const char *pszFilename,
 
     {
         CPLMutexHolder oHolder( &poHandler->hMutex );
-        poHandler->Unlink(osFilename);
+        poHandler->Unlink_unlocked(osFilename);
         poHandler->oFileList[poFile->osFilename] = poFile;
         poFile->nRefCount++;
     }
diff --git a/port/cpl_vsi_virtual.h b/port/cpl_vsi_virtual.h
index 9911906..33a8948 100644
--- a/port/cpl_vsi_virtual.h
+++ b/port/cpl_vsi_virtual.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsi_virtual.h 27720 2014-09-21 17:58:47Z goatbar $
+ * $Id: cpl_vsi_virtual.h 28493 2015-02-16 09:49:16Z rouault $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Declarations for classes related to the virtual filesystem.
@@ -36,6 +36,7 @@
 
 #include "cpl_vsi.h"
 #include "cpl_string.h"
+#include "cpl_multiproc.h"
 
 #if defined(WIN32CE)
 #  include "cpl_wince.h"
@@ -113,7 +114,8 @@ public:
     static VSIFilesystemHandler *GetHandler( const char * );
     static void InstallHandler( const std::string& osPrefix, 
                                 VSIFilesystemHandler * );
-    static void RemoveHandler( const std::string& osPrefix );
+    /* RemoveHandler is never defined. */
+    /* static void RemoveHandler( const std::string& osPrefix ); */
 };
 
 
@@ -161,7 +163,7 @@ class VSIArchiveReader
 class VSIArchiveFilesystemHandler : public VSIFilesystemHandler 
 {
 protected:
-    void* hMutex;
+    CPLMutex* hMutex;
     /* We use a cache that contains the list of files containes in a VSIArchive file as */
     /* unarchive.c is quite inefficient in listing them. This speeds up access to VSIArchive files */
     /* containing ~1000 files like a CADRG product */
@@ -188,8 +190,11 @@ public:
     virtual int FindFileInArchive(const char* archiveFilename, const char* fileInArchiveName, const VSIArchiveEntry** archiveEntry);
 };
 
-VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
+VSIVirtualHandle CPL_DLL *VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
+VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
+                                                const GByte* pabyBeginningContent,
+                                                vsi_l_offset nSheatFileSize);
 VSIVirtualHandle* VSICreateCachedFile( VSIVirtualHandle* poBaseHandle, size_t nChunkSize = 32768, size_t nCacheSize = 0 );
-VSIVirtualHandle* VSICreateGZipWritable( VSIVirtualHandle* poBaseHandle, int bRegularZLibIn, int bAutoCloseBaseHandle );
+VSIVirtualHandle CPL_DLL *VSICreateGZipWritable( VSIVirtualHandle* poBaseHandle, int bRegularZLibIn, int bAutoCloseBaseHandle );
 
 #endif /* ndef CPL_VSI_VIRTUAL_H_INCLUDED */
diff --git a/port/cpl_vsil.cpp b/port/cpl_vsil.cpp
index e6435cd..45af62b 100644
--- a/port/cpl_vsil.cpp
+++ b/port/cpl_vsil.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil.cpp 27110 2014-03-28 21:29:20Z rouault $
+ * $Id: cpl_vsil.cpp 28849 2015-04-05 14:05:18Z goatbar $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Implementation VSI*L File API and other file system access
@@ -34,7 +34,7 @@
 #include "cpl_string.h"
 #include <string>
 
-CPL_CVSID("$Id: cpl_vsil.cpp 27110 2014-03-28 21:29:20Z rouault $");
+CPL_CVSID("$Id: cpl_vsil.cpp 28849 2015-04-05 14:05:18Z goatbar $");
 
 /************************************************************************/
 /*                             VSIReadDir()                             */
@@ -130,6 +130,10 @@ char **VSIReadDirRecursive( const char *pszPathIn )
 
         for ( ; i < nCount; i++ )
         {
+            // Do not recurse up the tree.
+            if (EQUAL(".", papszFiles[i]) || EQUAL("..", papszFiles[i]))
+              continue;
+
             // build complete file name for stat
             osTemp1.clear();
             osTemp1.append( pszPath );
@@ -365,7 +369,7 @@ int VSIRmdir( const char * pszDirname )
  * 
  * Fetches status information about a filesystem object (file, directory, etc).
  * The returned information is placed in the VSIStatBufL structure.   For
- * portability only the st_size (size in bytes), and st_mode (file type). 
+ * portability, only use the st_size (size in bytes) and st_mode (file type).
  * This method is similar to VSIStat(), but will work on large files on 
  * systems where this requires special calls. 
  * 
@@ -396,7 +400,7 @@ int VSIStatL( const char * pszFilename, VSIStatBufL *psStatBuf )
  *
  * Fetches status information about a filesystem object (file, directory, etc).
  * The returned information is placed in the VSIStatBufL structure.   For
- * portability only the st_size (size in bytes), and st_mode (file type).
+ * portability, only use the st_size (size in bytes) and st_mode (file type).
  * This method is similar to VSIStat(), but will work on large files on
  * systems where this requires special calls.
  *
@@ -751,7 +755,7 @@ size_t VSIFWriteL( const void *pBuffer, size_t nSize, size_t nCount, VSILFILE *f
  * \brief Test for end of file.
  *
  * Returns TRUE (non-zero) if an end-of-file condition occured during the
- * previous read operation. The end-of-file flag is cleared by a successfull
+ * previous read operation. The end-of-file flag is cleared by a successful
  * VSIFSeekL() call.
  *
  * This method goes through the VSIFileHandler virtualization and may
@@ -922,7 +926,7 @@ int VSIIngestFile( VSILFILE* fp,
                         VSIFCloseL( fp );
                     return FALSE;
                 }
-                GByte* pabyNew = (GByte*)VSIRealloc(*ppabyRet, nDataAlloc);
+                GByte* pabyNew = (GByte*)VSIRealloc(*ppabyRet, (size_t)nDataAlloc);
                 if( pabyNew == NULL )
                 {
                     CPLError( CE_Failure, CPLE_OutOfMemory,
@@ -1083,7 +1087,7 @@ VSIFileManager::~VSIFileManager()
 /************************************************************************/
 
 static VSIFileManager *poManager = NULL;
-static void* hVSIFileManagerMutex = NULL;
+static CPLMutex* hVSIFileManagerMutex = NULL;
 
 VSIFileManager *VSIFileManager::Get()
 
diff --git a/port/cpl_vsil_abstract_archive.cpp b/port/cpl_vsil_abstract_archive.cpp
index a52dd55..840bf20 100644
--- a/port/cpl_vsil_abstract_archive.cpp
+++ b/port/cpl_vsil_abstract_archive.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_abstract_archive.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_abstract_archive.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for archive files.
@@ -35,7 +35,7 @@
 
 #define ENABLE_DEBUG 0
 
-CPL_CVSID("$Id: cpl_vsil_abstract_archive.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_abstract_archive.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /*                    ~VSIArchiveEntryFileOffset()                      */
@@ -444,7 +444,9 @@ VSIArchiveReader* VSIArchiveFilesystemHandler::OpenArchiveFile(const char* archi
 /*                                 Stat()                               */
 /************************************************************************/
 
-int VSIArchiveFilesystemHandler::Stat( const char *pszFilename, VSIStatBufL *pStatBuf, CPL_UNUSED int nFlags )
+int VSIArchiveFilesystemHandler::Stat( const char *pszFilename,
+                                       VSIStatBufL *pStatBuf,
+                                       CPL_UNUSED int nFlags )
 {
     int ret = -1;
     CPLString osFileInArchive;
@@ -530,7 +532,8 @@ int VSIArchiveFilesystemHandler::Unlink( CPL_UNUSED const char *pszFilename )
 /*                             Rename()                                 */
 /************************************************************************/
 
-int VSIArchiveFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNUSED const char *newpath )
+int VSIArchiveFilesystemHandler::Rename( CPL_UNUSED const char *oldpath,
+                                         CPL_UNUSED const char *newpath )
 {
     return -1;
 }
@@ -539,7 +542,8 @@ int VSIArchiveFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNU
 /*                             Mkdir()                                  */
 /************************************************************************/
 
-int VSIArchiveFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname, CPL_UNUSED long nMode )
+int VSIArchiveFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname,
+                                        CPL_UNUSED long nMode )
 {
     return -1;
 }
diff --git a/port/cpl_vsil_buffered_reader.cpp b/port/cpl_vsil_buffered_reader.cpp
index f722295..6124c38 100644
--- a/port/cpl_vsil_buffered_reader.cpp
+++ b/port/cpl_vsil_buffered_reader.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_buffered_reader.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_buffered_reader.cpp 28493 2015-02-16 09:49:16Z rouault $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Implementation of buffered reader IO functions.
@@ -35,23 +35,31 @@
 
 #include "cpl_vsi_virtual.h"
 
+#include "cpl_port.h"
+
 #define MAX_BUFFER_SIZE 65536
 
-CPL_CVSID("$Id: cpl_vsil_buffered_reader.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_buffered_reader.cpp 28493 2015-02-16 09:49:16Z rouault $");
 
 class VSIBufferedReaderHandle : public VSIVirtualHandle
 {
     VSIVirtualHandle* poBaseHandle;
-    char              pabyBuffer[MAX_BUFFER_SIZE];
+    GByte*            pabyBuffer;
     GUIntBig          nBufferOffset;
     int               nBufferSize;
     GUIntBig          nCurOffset;
     int               bNeedBaseHandleSeek;
     int               bEOF;
+    vsi_l_offset      nSheatFileSize;
+    
+    int               SeekBaseTo(vsi_l_offset nTargetOffset);
 
   public:
 
     VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle);
+    VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
+                            const GByte* pabyBeginningContent,
+                            vsi_l_offset nSheatFileSizeIn);
     ~VSIBufferedReaderHandle();
 
     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
@@ -72,6 +80,15 @@ VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
     return new VSIBufferedReaderHandle(poBaseHandle);
 }
 
+VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
+                                                const GByte* pabyBeginningContent,
+                                                vsi_l_offset nSheatFileSizeIn)
+{
+    return new VSIBufferedReaderHandle(poBaseHandle,
+                                       pabyBeginningContent,
+                                       nSheatFileSizeIn);
+}
+
 /************************************************************************/
 /*                        VSIBufferedReaderHandle()                     */
 /************************************************************************/
@@ -79,11 +96,28 @@ VSIVirtualHandle* VSICreateBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
 VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
 {
     this->poBaseHandle = poBaseHandle;
+    pabyBuffer = (GByte*)CPLMalloc(MAX_BUFFER_SIZE);
     nBufferOffset = 0;
     nBufferSize = 0;
     nCurOffset = 0;
     bNeedBaseHandleSeek = FALSE;
     bEOF = FALSE;
+    nSheatFileSize = 0;
+}
+
+VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle,
+                                                 const GByte* pabyBeginningContent,
+                                                 vsi_l_offset nSheatFileSizeIn)
+{
+    this->poBaseHandle = poBaseHandle;
+    nBufferOffset = 0;
+    nBufferSize = (int)poBaseHandle->Tell();
+    pabyBuffer = (GByte*)CPLMalloc(MAX(MAX_BUFFER_SIZE,nBufferSize));
+    memcpy(pabyBuffer, pabyBeginningContent, nBufferSize);
+    nCurOffset = 0;
+    bNeedBaseHandleSeek = TRUE;
+    bEOF = FALSE;
+    nSheatFileSize = nSheatFileSizeIn;
 }
 
 /************************************************************************/
@@ -93,6 +127,7 @@ VSIBufferedReaderHandle::VSIBufferedReaderHandle(VSIVirtualHandle* poBaseHandle)
 VSIBufferedReaderHandle::~VSIBufferedReaderHandle()
 {
     delete poBaseHandle;
+    CPLFree(pabyBuffer);
 }
 
 /************************************************************************/
@@ -107,12 +142,17 @@ int VSIBufferedReaderHandle::Seek( vsi_l_offset nOffset, int nWhence )
         nCurOffset += nOffset;
     else if (nWhence == SEEK_END)
     {
-        poBaseHandle->Seek(nOffset, nWhence);
-        nCurOffset = poBaseHandle->Tell();
-        bNeedBaseHandleSeek = TRUE;
+        if( nSheatFileSize )
+            nCurOffset = nSheatFileSize;
+        else
+        {
+            poBaseHandle->Seek(nOffset, nWhence);
+            nCurOffset = poBaseHandle->Tell();
+            bNeedBaseHandleSeek = TRUE;
+        }
     }
     else
-        nCurOffset = nOffset;
+        nCurOffset = nOffset;   
 
     return 0;
 }
@@ -126,6 +166,37 @@ vsi_l_offset VSIBufferedReaderHandle::Tell()
     //CPLDebug( "BUFFERED", "Tell() = %d", (int)nCurOffset);
     return nCurOffset;
 }
+
+/************************************************************************/
+/*                           SeekBaseTo()                               */
+/************************************************************************/
+
+int VSIBufferedReaderHandle::SeekBaseTo(vsi_l_offset nTargetOffset)
+{
+    if( poBaseHandle->Seek(nTargetOffset, SEEK_SET) == 0 )
+        return TRUE;
+
+    nCurOffset = poBaseHandle->Tell();
+    if( nCurOffset > nTargetOffset )
+        return FALSE;
+    char abyTemp[8192];
+    while(TRUE)
+    {
+        int nToRead = (int) MIN(8192, nTargetOffset - nCurOffset);
+        int nRead = (int)poBaseHandle->Read(abyTemp, 1, nToRead );
+        nCurOffset += nRead;
+
+        if (nRead < nToRead)
+        {
+            bEOF = TRUE;
+            return FALSE;
+        }
+        if (nToRead < 8192)
+            break;
+    }
+    return TRUE;
+}
+
 /************************************************************************/
 /*                               Read()                                 */
 /************************************************************************/
@@ -150,7 +221,13 @@ size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb
             /* The beginning of the the data to read is located in the buffer */
             /* but the end must be read from the file */
             if (bNeedBaseHandleSeek)
-                poBaseHandle->Seek(nBufferOffset + nBufferSize, SEEK_SET);
+            {
+                if( !SeekBaseTo(nBufferOffset + nBufferSize) )
+                {
+                    nCurOffset += nReadInBuffer;
+                    return nReadInBuffer / nSize;
+                }
+            }
             bNeedBaseHandleSeek = FALSE;
             //CPLAssert(poBaseHandle->Tell() == nBufferOffset + nBufferSize);
 
@@ -179,7 +256,8 @@ size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb
     else
     {
         /* We try either to read before or after the buffer, so a seek is necessary */
-        poBaseHandle->Seek(nCurOffset, SEEK_SET);
+        if( !SeekBaseTo(nCurOffset) )
+            return 0;
         bNeedBaseHandleSeek = FALSE;
         const int nReadInFile = poBaseHandle->Read(pBuffer, 1, nTotalToRead);
         nBufferSize = MIN(nReadInFile, MAX_BUFFER_SIZE);
@@ -201,7 +279,9 @@ size_t VSIBufferedReaderHandle::Read( void *pBuffer, size_t nSize, size_t nMemb
 /*                              Write()                                 */
 /************************************************************************/
 
-size_t VSIBufferedReaderHandle::Write( CPL_UNUSED const void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
+size_t VSIBufferedReaderHandle::Write( CPL_UNUSED const void *pBuffer,
+                                       CPL_UNUSED size_t nSize,
+                                       CPL_UNUSED size_t nMemb )
 {
     CPLError(CE_Failure, CPLE_NotSupported,
              "VSIFWriteL is not supported on buffer reader streams\n");
diff --git a/port/cpl_vsil_cache.cpp b/port/cpl_vsil_cache.cpp
index 2387ca1..c050e09 100644
--- a/port/cpl_vsil_cache.cpp
+++ b/port/cpl_vsil_cache.cpp
@@ -478,7 +478,9 @@ size_t VSICachedFile::Read( void * pBuffer, size_t nSize, size_t nCount )
 /*                               Write()                                */
 /************************************************************************/
 
-size_t VSICachedFile::Write( CPL_UNUSED const void * pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nCount )
+size_t VSICachedFile::Write( CPL_UNUSED const void * pBuffer,
+                             CPL_UNUSED size_t nSize,
+                             CPL_UNUSED size_t nCount )
 {
     return 0;
 }
diff --git a/port/cpl_vsil_curl.cpp b/port/cpl_vsil_curl.cpp
index f72504d..5b14bb1 100644
--- a/port/cpl_vsil_curl.cpp
+++ b/port/cpl_vsil_curl.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_curl.cpp 28190 2014-12-21 22:42:54Z rouault $
+ * $Id: cpl_vsil_curl.cpp 28798 2015-03-27 19:37:50Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for HTTP/FTP files
@@ -34,7 +34,7 @@
 #include "cpl_time.h"
 #include "cpl_vsil_curl_priv.h"
 
-CPL_CVSID("$Id: cpl_vsil_curl.cpp 28190 2014-12-21 22:42:54Z rouault $");
+CPL_CVSID("$Id: cpl_vsil_curl.cpp 28798 2015-03-27 19:37:50Z rouault $");
 
 #ifndef HAVE_CURL
 
@@ -47,10 +47,10 @@ void VSIInstallCurlFileHandler(void)
 /*                      VSICurlInstallReadCbk()                         */
 /************************************************************************/
 
-int VSICurlInstallReadCbk (VSILFILE* fp,
-                           VSICurlReadCbkFunc pfnReadCbk,
-                           void* pfnUserData,
-                           int bStopOnInterrruptUntilUninstall)
+int VSICurlInstallReadCbk (CPL_UNUSED VSILFILE* fp,
+                           CPL_UNUSED VSICurlReadCbkFunc pfnReadCbk,
+                           CPL_UNUSED void* pfnUserData,
+                           CPL_UNUSED int bStopOnInterrruptUntilUninstall)
 {
     return FALSE;
 }
@@ -60,7 +60,7 @@ int VSICurlInstallReadCbk (VSILFILE* fp,
 /*                    VSICurlUninstallReadCbk()                         */
 /************************************************************************/
 
-int VSICurlUninstallReadCbk(VSILFILE* fp)
+int VSICurlUninstallReadCbk(CPL_UNUSED VSILFILE* fp)
 {
     return FALSE;
 }
@@ -197,7 +197,7 @@ typedef struct
 
 class VSICurlFilesystemHandler : public VSIFilesystemHandler 
 {
-    void           *hMutex;
+    CPLMutex       *hMutex;
 
     CachedRegion  **papsRegions;
     int             nRegions;
@@ -586,6 +586,7 @@ vsi_l_offset VSICurlHandle::GetFileSize()
     /* listed in CPL_VSIL_CURL_ALLOWED_EXTENSIONS exist on the server */
     /* This can speeds up dramatically open experience, in case the server */
     /* cannot return a file list */
+    /* {noext} can be used as a special token to mean file with no extension */
     /* For example : */
     /* gdalinfo --config CPL_VSIL_CURL_ALLOWED_EXTENSIONS ".tif" /vsicurl/http://igskmncngs506.cr.usgs.gov/gmted/Global_tiles_GMTED/075darcsec/bln/W030/30N030W_20101117_gmted_bln075.tif */
     const char* pszAllowedExtensions =
@@ -598,7 +599,15 @@ vsi_l_offset VSICurlHandle::GetFileSize()
         for(int i=0;papszExtensions[i] != NULL;i++)
         {
             int nExtensionLen = strlen(papszExtensions[i]);
-            if (nURLLen > nExtensionLen &&
+            if( EQUAL(papszExtensions[i], "{noext}") )
+            {
+                if( nURLLen > 4 && strchr(pszURL + nURLLen - 4, '.') == NULL )
+                {
+                    bFound = TRUE;
+                    break;
+                }
+            }
+            else if (nURLLen > nExtensionLen &&
                 EQUAL(pszURL + nURLLen - nExtensionLen, papszExtensions[i]))
             {
                 bFound = TRUE;
@@ -1391,7 +1400,9 @@ end:
 /*                               Write()                                */
 /************************************************************************/
 
-size_t VSICurlHandle::Write( CPL_UNUSED const void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
+size_t VSICurlHandle::Write( CPL_UNUSED const void *pBuffer,
+                             CPL_UNUSED size_t nSize,
+                             CPL_UNUSED size_t nMemb )
 {
     return 0;
 }
@@ -2553,7 +2564,8 @@ int VSICurlFilesystemHandler::Unlink( CPL_UNUSED const char *pszFilename )
 /*                               Rename()                               */
 /************************************************************************/
 
-int VSICurlFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNUSED const char *newpath )
+int VSICurlFilesystemHandler::Rename( CPL_UNUSED const char *oldpath,
+                                      CPL_UNUSED const char *newpath )
 {
     return -1;
 }
@@ -2562,7 +2574,8 @@ int VSICurlFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNUSED
 /*                               Mkdir()                                */
 /************************************************************************/
 
-int VSICurlFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname, CPL_UNUSED long nMode )
+int VSICurlFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname,
+                                     CPL_UNUSED long nMode )
 {
     return -1;
 }
@@ -2641,9 +2654,9 @@ char** VSICurlFilesystemHandler::ReadDir( const char *pszDirname )
  * A special file handler is installed that allows reading on-the-fly of files
  * available through HTTP/FTP web protocols, without downloading the entire file.
  *
- * Recognized filenames are of the form /vsicurl/http://path/to/remote/ressource or
- * /vsicurl/ftp://path/to/remote/ressource where path/to/remote/ressource is the
- * URL of a remote ressource.
+ * Recognized filenames are of the form /vsicurl/http://path/to/remote/resource or
+ * /vsicurl/ftp://path/to/remote/resource where path/to/remote/resource is the
+ * URL of a remote resource.
  *
  * Partial downloads (requires the HTTP server to support random reading) are done
  * with a 16 KB granularity by default. If the driver detects sequential reading
diff --git a/port/cpl_vsil_curl_streaming.cpp b/port/cpl_vsil_curl_streaming.cpp
index ded5eb6..5c91c79 100644
--- a/port/cpl_vsil_curl_streaming.cpp
+++ b/port/cpl_vsil_curl_streaming.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_curl_streaming.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_curl_streaming.cpp 28459 2015-02-12 13:48:21Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for HTTP/FTP files in streaming mode
@@ -33,7 +33,7 @@
 #include "cpl_hash_set.h"
 #include "cpl_time.h"
 
-CPL_CVSID("$Id: cpl_vsil_curl_streaming.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_curl_streaming.cpp 28459 2015-02-12 13:48:21Z rouault $");
 
 #if !defined(HAVE_CURL) || defined(CPL_MULTIPROC_STUB)
 
@@ -154,7 +154,7 @@ typedef struct
 
 class VSICurlStreamingFSHandler : public VSIFilesystemHandler
 {
-    void           *hMutex;
+    CPLMutex           *hMutex;
 
     std::map<CPLString, CachedFileProp*>   cacheFileSize;
 
@@ -207,10 +207,10 @@ class VSICurlStreamingHandle : public VSIVirtualHandle
     volatile int    bDownloadStopped;
     volatile int    bAskDownloadEnd;
     vsi_l_offset    nRingBufferFileOffset;
-    void           *hThread;
-    void           *hRingBufferMutex;
-    void           *hCondProducer;
-    void           *hCondConsumer;
+    CPLJoinableThread *hThread;
+    CPLMutex       *hRingBufferMutex;
+    CPLCond        *hCondProducer;
+    CPLCond        *hCondConsumer;
     RingBuffer      oRingBuffer;
     void            StartDownload();
     void            StopDownload();
@@ -1265,7 +1265,9 @@ void  VSICurlStreamingHandle::AddRegion( vsi_l_offset    nFileOffsetStart,
 /*                               Write()                                */
 /************************************************************************/
 
-size_t VSICurlStreamingHandle::Write( CPL_UNUSED const void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
+size_t VSICurlStreamingHandle::Write( CPL_UNUSED const void *pBuffer,
+                                      CPL_UNUSED size_t nSize,
+                                      CPL_UNUSED size_t nMemb )
 {
     return 0;
 }
@@ -1440,9 +1442,9 @@ int VSICurlStreamingFSHandler::Stat( const char *pszFilename,
  * be efficient. If you need efficient random access and that the server supports range
  * dowloading, you should use the /vsicurl/ file system handler instead.
  *
- * Recognized filenames are of the form /vsicurl_streaming/http://path/to/remote/ressource or
- * /vsicurl_streaming/ftp://path/to/remote/ressource where path/to/remote/ressource is the
- * URL of a remote ressource.
+ * Recognized filenames are of the form /vsicurl_streaming/http://path/to/remote/resource or
+ * /vsicurl_streaming/ftp://path/to/remote/resource where path/to/remote/resource is the
+ * URL of a remote resource.
  *
  * The GDAL_HTTP_PROXY, GDAL_HTTP_PROXYUSERPWD and GDAL_PROXY_AUTH configuration options can be
  * used to define a proxy server. The syntax to use is the one of Curl CURLOPT_PROXY,
diff --git a/port/cpl_vsil_gzip.cpp b/port/cpl_vsil_gzip.cpp
index fe76fa7..91bfb6c 100644
--- a/port/cpl_vsil_gzip.cpp
+++ b/port/cpl_vsil_gzip.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_gzip.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_gzip.cpp 29033 2015-04-27 10:47:22Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for gz/zip files (.gz and .zip).
@@ -84,7 +84,7 @@
 #include "cpl_minizip_unzip.h"
 #include "cpl_time.h"
 
-CPL_CVSID("$Id: cpl_vsil_gzip.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_gzip.cpp 29033 2015-04-27 10:47:22Z rouault $");
 
 #define Z_BUFSIZE 65536  /* original size is 16384 */
 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
@@ -130,6 +130,7 @@ class VSIGZipHandle : public VSIVirtualHandle
     vsi_l_offset      offsetEndCompressedData;
     unsigned int      expected_crc;
     char             *pszBaseFileName; /* optional */
+    int               bCanSaveInfo;
 
     /* Fields from gz_stream structure */
     z_stream stream;
@@ -180,15 +181,16 @@ class VSIGZipHandle : public VSIVirtualHandle
 
     void              SetUncompressedSize(vsi_l_offset nUncompressedSize) { uncompressed_size = nUncompressedSize; }
     vsi_l_offset      GetUncompressedSize() { return uncompressed_size; }
+    
+    void              SaveInfo_unlocked();
 };
 
 
 class VSIGZipFilesystemHandler : public VSIFilesystemHandler 
 {
-    void* hMutex;
+    CPLMutex* hMutex;
     VSIGZipHandle* poHandleLastGZipFile;
-    int            bInSaveInfo;
-
+    
 public:
     VSIGZipFilesystemHandler();
     ~VSIGZipFilesystemHandler();
@@ -205,6 +207,7 @@ public:
     virtual char   **ReadDir( const char *pszDirname );
 
     void  SaveInfo( VSIGZipHandle* poHandle );
+    void  SaveInfo_unlocked( VSIGZipHandle* poHandle );
 };
 
 
@@ -280,6 +283,7 @@ VSIGZipHandle::VSIGZipHandle(VSIVirtualHandle* poBaseHandle,
     this->poBaseHandle = poBaseHandle;
     this->expected_crc = expected_crc;
     this->pszBaseFileName = (pszBaseFileName) ? CPLStrdup(pszBaseFileName) : NULL;
+    bCanSaveInfo = TRUE;
     this->offset = offset;
     if (compressed_size || transparent)
     {
@@ -339,13 +343,28 @@ VSIGZipHandle::VSIGZipHandle(VSIVirtualHandle* poBaseHandle,
 }
 
 /************************************************************************/
+/*                      SaveInfo_unlocked()                             */
+/************************************************************************/
+
+void VSIGZipHandle::SaveInfo_unlocked()
+{
+    if (pszBaseFileName && bCanSaveInfo)
+    {
+        VSIFilesystemHandler *poFSHandler = 
+            VSIFileManager::GetHandler( "/vsigzip/" );
+        ((VSIGZipFilesystemHandler*)poFSHandler)->SaveInfo_unlocked(this);
+        bCanSaveInfo = FALSE;
+    }
+}
+
+/************************************************************************/
 /*                      ~VSIGZipHandle()                                */
 /************************************************************************/
 
 VSIGZipHandle::~VSIGZipHandle()
 {
     
-    if (pszBaseFileName)
+    if (pszBaseFileName && bCanSaveInfo)
     {
         VSIFilesystemHandler *poFSHandler = 
             VSIFileManager::GetHandler( "/vsigzip/" );
@@ -507,9 +526,9 @@ int VSIGZipHandle::gzrewind ()
 
 int VSIGZipHandle::Seek( vsi_l_offset nOffset, int nWhence )
 {
-    /* The semantics of gzseek is different from ::Seek */
-    /* It returns the current offset, where as ::Seek shoud return 0 */
-    /* if successfull */
+    /* The semantics of gzseek are different from ::Seek */
+    /* It returns the current offset, where as ::Seek should return 0 */
+    /* if successful */
     int ret = gzseek(nOffset, nWhence);
     return (ret >= 0) ? 0 : ret;
 }
@@ -929,7 +948,9 @@ uLong VSIGZipHandle::getLong ()
 /*                              Write()                                 */
 /************************************************************************/
 
-size_t VSIGZipHandle::Write( CPL_UNUSED const void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
+size_t VSIGZipHandle::Write( CPL_UNUSED const void *pBuffer,
+                             CPL_UNUSED size_t nSize,
+                             CPL_UNUSED size_t nMemb )
 {
     CPLError(CE_Failure, CPLE_NotSupported, "VSIFWriteL is not supported on GZip streams");
     return 0;
@@ -1121,8 +1142,9 @@ int VSIGZipWriteHandle::Close()
 /*                                Read()                                */
 /************************************************************************/
 
-size_t VSIGZipWriteHandle::Read( CPL_UNUSED void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
-
+size_t VSIGZipWriteHandle::Read( CPL_UNUSED void *pBuffer,
+                                 CPL_UNUSED size_t nSize,
+                                 CPL_UNUSED size_t nMemb )
 {
     CPLError(CE_Failure, CPLE_NotSupported, "VSIFReadL is not supported on GZip write streams\n");
     return 0;
@@ -1249,7 +1271,6 @@ VSIGZipFilesystemHandler::VSIGZipFilesystemHandler()
     hMutex = NULL;
 
     poHandleLastGZipFile = NULL;
-    bInSaveInfo = FALSE;
 }
 
 /************************************************************************/
@@ -1273,11 +1294,11 @@ VSIGZipFilesystemHandler::~VSIGZipFilesystemHandler()
 void VSIGZipFilesystemHandler::SaveInfo(  VSIGZipHandle* poHandle )
 {
     CPLMutexHolder oHolder(&hMutex);
+    SaveInfo_unlocked(poHandle);
+}
 
-    if (bInSaveInfo)
-        return;
-    bInSaveInfo = TRUE;
-    
+void VSIGZipFilesystemHandler::SaveInfo_unlocked(  VSIGZipHandle* poHandle )
+{
     CPLAssert(poHandle->GetBaseFileName() != NULL);
 
     if (poHandleLastGZipFile &&
@@ -1287,21 +1308,26 @@ void VSIGZipFilesystemHandler::SaveInfo(  VSIGZipHandle* poHandle )
         {
             VSIGZipHandle* poTmp = poHandleLastGZipFile;
             poHandleLastGZipFile = NULL;
+            poTmp->SaveInfo_unlocked();
             delete poTmp;
             poHandleLastGZipFile = poHandle->Duplicate();
-            poHandleLastGZipFile->CloseBaseHandle();
+            if( poHandleLastGZipFile )
+                poHandleLastGZipFile->CloseBaseHandle();
         }
     }
     else
     {
         VSIGZipHandle* poTmp = poHandleLastGZipFile;
         poHandleLastGZipFile = NULL;
-        delete poTmp;
+        if( poTmp )
+        {
+            poTmp->SaveInfo_unlocked();
+            delete poTmp;
+        }
         poHandleLastGZipFile = poHandle->Duplicate();
-        poHandleLastGZipFile->CloseBaseHandle();
+        if( poHandleLastGZipFile )
+            poHandleLastGZipFile->CloseBaseHandle();
     }
-
-    bInSaveInfo = FALSE;
 }
 
 /************************************************************************/
@@ -1389,8 +1415,11 @@ VSIGZipHandle* VSIGZipFilesystemHandler::OpenGZipReadOnly( const char *pszFilena
     }
 
     if (poHandleLastGZipFile)
+    {
+        poHandleLastGZipFile->SaveInfo_unlocked();
         delete poHandleLastGZipFile;
-    poHandleLastGZipFile = NULL;
+        poHandleLastGZipFile = NULL;
+    }
 
     return new VSIGZipHandle(poVirtualHandle, pszFilename + strlen("/vsigzip/"));
 }
@@ -1461,7 +1490,7 @@ int VSIGZipFilesystemHandler::Stat( const char *pszFilename,
                 if (poHandle)
                 {
                     poHandle->SetUncompressedSize(nUncompressedSize);
-                    SaveInfo(poHandle);
+                    SaveInfo_unlocked(poHandle);
                     delete poHandle;
                 }
 
@@ -1506,7 +1535,8 @@ int VSIGZipFilesystemHandler::Unlink( CPL_UNUSED const char *pszFilename )
 /*                               Rename()                               */
 /************************************************************************/
 
-int VSIGZipFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNUSED const char *newpath )
+int VSIGZipFilesystemHandler::Rename( CPL_UNUSED const char *oldpath,
+                                      CPL_UNUSED const char *newpath )
 {
     return -1;
 }
@@ -1515,7 +1545,8 @@ int VSIGZipFilesystemHandler::Rename( CPL_UNUSED const char *oldpath, CPL_UNUSED
 /*                               Mkdir()                                */
 /************************************************************************/
 
-int VSIGZipFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname, CPL_UNUSED long nMode )
+int VSIGZipFilesystemHandler::Mkdir( CPL_UNUSED const char *pszDirname,
+                                     CPL_UNUSED long nMode )
 {
     return -1;
 }
@@ -1717,6 +1748,8 @@ class VSIZipWriteHandle;
 class VSIZipFilesystemHandler : public VSIArchiveFilesystemHandler 
 {
     std::map<CPLString, VSIZipWriteHandle*> oMapZipWriteHandles;
+    VSIVirtualHandle *OpenForWrite_unlocked( const char *pszFilename,
+                                            const char *pszAccess );
 
 public:
     virtual ~VSIZipFilesystemHandler();
@@ -2043,11 +2076,17 @@ void VSIZipFilesystemHandler::RemoveFromMap(VSIZipWriteHandle* poHandle)
 VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite( const char *pszFilename,
                                                          const char *pszAccess)
 {
-    char* zipFilename;
-    CPLString osZipInFileName;
-
     CPLMutexHolder oHolder( &hMutex );
+    return OpenForWrite_unlocked(pszFilename, pszAccess);
+}
 
+
+VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite_unlocked( const char *pszFilename,
+                                                         const char *pszAccess)
+{
+    char* zipFilename;
+    CPLString osZipInFileName;
+    
     zipFilename = SplitFilename(pszFilename, osZipInFileName, FALSE);
     if (zipFilename == NULL)
         return NULL;
@@ -2134,7 +2173,7 @@ VSIVirtualHandle* VSIZipFilesystemHandler::OpenForWrite( const char *pszFilename
         if (osZipInFileName.size() != 0)
         {
             VSIZipWriteHandle* poRes =
-                (VSIZipWriteHandle*)OpenForWrite(pszFilename, pszAccess);
+                (VSIZipWriteHandle*)OpenForWrite_unlocked(pszFilename, pszAccess);
             if (poRes == NULL)
             {
                 delete oMapZipWriteHandles[osZipFilename];
@@ -2205,7 +2244,9 @@ vsi_l_offset VSIZipWriteHandle::Tell()
 /*                               Read()                                 */
 /************************************************************************/
 
-size_t VSIZipWriteHandle::Read( CPL_UNUSED void *pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nMemb )
+size_t VSIZipWriteHandle::Read( CPL_UNUSED void *pBuffer,
+                                CPL_UNUSED size_t nSize,
+                                CPL_UNUSED size_t nMemb )
 {
     CPLError(CE_Failure, CPLE_NotSupported,
              "VSIFReadL() is not supported on writable Zip files");
@@ -2372,8 +2413,11 @@ void VSIInstallZipFileHandler(void)
  * @since GDAL 1.10.0
  */
 
-void* CPLZLibDeflate( const void* ptr, size_t nBytes, CPL_UNUSED int nLevel,
-                      void* outptr, size_t nOutAvailableBytes,
+void* CPLZLibDeflate( const void* ptr,
+                      size_t nBytes,
+                      CPL_UNUSED int nLevel,
+                      void* outptr,
+                      size_t nOutAvailableBytes,
                       size_t* pnOutBytes )
 {
     z_stream strm;
diff --git a/port/cpl_vsil_sparsefile.cpp b/port/cpl_vsil_sparsefile.cpp
index 9a2c07e..19bfd87 100644
--- a/port/cpl_vsil_sparsefile.cpp
+++ b/port/cpl_vsil_sparsefile.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_sparsefile.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_sparsefile.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Implementation of sparse file virtual io driver.
@@ -38,7 +38,7 @@
 #  include <wce_errno.h>
 #endif
 
-CPL_CVSID("$Id: cpl_vsil_sparsefile.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_sparsefile.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 class SFRegion { 
 public:
@@ -291,7 +291,9 @@ size_t VSISparseFileHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
 /*                               Write()                                */
 /************************************************************************/
 
-size_t VSISparseFileHandle::Write( CPL_UNUSED const void * pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nCount )
+size_t VSISparseFileHandle::Write( CPL_UNUSED const void * pBuffer,
+                                   CPL_UNUSED size_t nSize,
+                                   CPL_UNUSED size_t nCount )
 {
     errno = EBADF;
     return 0;
diff --git a/port/cpl_vsil_stdin.cpp b/port/cpl_vsil_stdin.cpp
index 10a7f7d..158607f 100644
--- a/port/cpl_vsil_stdin.cpp
+++ b/port/cpl_vsil_stdin.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_vsil_stdin.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_stdin.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for stdin
@@ -37,7 +37,7 @@
 #include <fcntl.h>
 #endif
 
-CPL_CVSID("$Id: cpl_vsil_stdin.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_stdin.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /* We buffer the first 1MB of standard input to enable drivers */
 /* to autodetect data. In the first MB, backward and forward seeking */
@@ -264,7 +264,8 @@ size_t VSIStdinHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
 /*                               Write()                                */
 /************************************************************************/
 
-size_t VSIStdinHandle::Write( CPL_UNUSED const void * pBuffer, CPL_UNUSED size_t nSize, 
+size_t VSIStdinHandle::Write( CPL_UNUSED const void * pBuffer,
+                              CPL_UNUSED size_t nSize,
                               CPL_UNUSED size_t nCount )
 {
     CPLError(CE_Failure, CPLE_NotSupported,
diff --git a/port/cpl_vsil_stdout.cpp b/port/cpl_vsil_stdout.cpp
index 16e16e8..faeb037 100644
--- a/port/cpl_vsil_stdout.cpp
+++ b/port/cpl_vsil_stdout.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_vsil_stdout.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_stdout.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for stdout
@@ -37,7 +37,29 @@
 #include <fcntl.h>
 #endif
 
-CPL_CVSID("$Id: cpl_vsil_stdout.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_stdout.cpp 27745 2014-09-27 16:38:57Z goatbar $");
+
+static VSIWriteFunction pWriteFunction = fwrite;
+static FILE* pWriteStream = stdout;
+
+/************************************************************************/
+/*                        VSIStdoutSetRedirection()                     */
+/************************************************************************/
+
+/** Set an alternative write function and output file handle instead of
+ *  fwrite() / stdout.
+ * 
+ * @param pFct Function with same signature as fwrite()
+ * @param stream File handle on which to output. Passed to pFct.
+ * 
+ * @since GDAL 2.0
+ */
+void VSIStdoutSetRedirection( VSIWriteFunction pFct, FILE* stream )
+{
+    pWriteFunction = pFct;
+    pWriteStream = stream;
+}
+
 
 /************************************************************************/
 /* ==================================================================== */
@@ -61,7 +83,10 @@ public:
 
 class VSIStdoutHandle : public VSIVirtualHandle
 {
+    vsi_l_offset      nOffset;
+
   public:
+                      VSIStdoutHandle() : nOffset(0) {}
 
     virtual int       Seek( vsi_l_offset nOffset, int nWhence );
     virtual vsi_l_offset Tell();
@@ -93,7 +118,7 @@ int VSIStdoutHandle::Seek( vsi_l_offset nOffset, int nWhence )
 
 vsi_l_offset VSIStdoutHandle::Tell()
 {
-    return ftell(stdout);
+    return nOffset;
 }
 
 /************************************************************************/
@@ -103,14 +128,19 @@ vsi_l_offset VSIStdoutHandle::Tell()
 int VSIStdoutHandle::Flush()
 
 {
-    return fflush( stdout );
+    if( pWriteStream == stdout )
+        return fflush( stdout );
+    else
+        return 0;
 }
 
 /************************************************************************/
 /*                                Read()                                */
 /************************************************************************/
 
-size_t VSIStdoutHandle::Read( CPL_UNUSED void * pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nCount )
+size_t VSIStdoutHandle::Read( CPL_UNUSED void * pBuffer,
+                              CPL_UNUSED size_t nSize,
+                              CPL_UNUSED size_t nCount )
 {
     CPLError(CE_Failure, CPLE_NotSupported, "Read() unsupported on /vsistdout");
     return 0;
@@ -124,7 +154,9 @@ size_t VSIStdoutHandle::Write( const void * pBuffer, size_t nSize,
                                   size_t nCount )
 
 {
-    return fwrite(pBuffer, nSize, nCount, stdout);
+    size_t nRet = pWriteFunction(pBuffer, nSize, nCount, pWriteStream);
+    nOffset += nSize * nRet;
+    return nRet;
 }
 
 /************************************************************************/
@@ -134,7 +166,7 @@ size_t VSIStdoutHandle::Write( const void * pBuffer, size_t nSize,
 int VSIStdoutHandle::Eof()
 
 {
-    return feof(stdout);
+    return 0;
 }
 
 /************************************************************************/
@@ -158,7 +190,7 @@ int VSIStdoutHandle::Close()
 /************************************************************************/
 
 VSIVirtualHandle *
-VSIStdoutFilesystemHandler::Open( CPL_UNUSED const char *pszFilename, 
+VSIStdoutFilesystemHandler::Open( CPL_UNUSED const char *pszFilename,
                                   const char *pszAccess )
 {
     if ( strchr(pszAccess, 'r') != NULL ||
@@ -184,6 +216,7 @@ VSIStdoutFilesystemHandler::Open( CPL_UNUSED const char *pszFilename,
 int VSIStdoutFilesystemHandler::Stat( CPL_UNUSED const char * pszFilename,
                                       VSIStatBufL * pStatBuf,
                                       CPL_UNUSED int nFlags )
+
 {
     memset( pStatBuf, 0, sizeof(VSIStatBufL) );
 
@@ -250,7 +283,8 @@ VSIStdoutRedirectHandle::~VSIStdoutRedirectHandle()
 /*                                Seek()                                */
 /************************************************************************/
 
-int VSIStdoutRedirectHandle::Seek( CPL_UNUSED vsi_l_offset nOffset, CPL_UNUSED int nWhence )
+int VSIStdoutRedirectHandle::Seek( CPL_UNUSED vsi_l_offset nOffset,
+                                   CPL_UNUSED int nWhence )
 {
     CPLError(CE_Failure, CPLE_NotSupported, "Seek() unsupported on /vsistdout_redirect");
     return -1;
@@ -279,7 +313,9 @@ int VSIStdoutRedirectHandle::Flush()
 /*                                Read()                                */
 /************************************************************************/
 
-size_t VSIStdoutRedirectHandle::Read( CPL_UNUSED void * pBuffer, CPL_UNUSED size_t nSize, CPL_UNUSED size_t nCount )
+size_t VSIStdoutRedirectHandle::Read( CPL_UNUSED void * pBuffer,
+                                      CPL_UNUSED size_t nSize,
+                                      CPL_UNUSED size_t nCount )
 {
     CPLError(CE_Failure, CPLE_NotSupported, "Read() unsupported on /vsistdout_redirect");
     return 0;
@@ -352,8 +388,8 @@ VSIStdoutRedirectFilesystemHandler::Open( const char *pszFilename,
 /************************************************************************/
 
 int VSIStdoutRedirectFilesystemHandler::Stat( CPL_UNUSED const char * pszFilename,
-                                      VSIStatBufL * pStatBuf,
-                                      CPL_UNUSED int nFlags )
+                                              VSIStatBufL * pStatBuf,
+                                              CPL_UNUSED int nFlags )
 {
     memset( pStatBuf, 0, sizeof(VSIStatBufL) );
 
diff --git a/port/cpl_vsil_subfile.cpp b/port/cpl_vsil_subfile.cpp
index dd9a3ad..6aed7a5 100644
--- a/port/cpl_vsil_subfile.cpp
+++ b/port/cpl_vsil_subfile.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_subfile.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_subfile.cpp 27745 2014-09-27 16:38:57Z goatbar $
  *
  * Project:  VSI Virtual File System
  * Purpose:  Implementation of subfile virtual IO functions.
@@ -37,7 +37,7 @@
 #  include <wce_errno.h>
 #endif
 
-CPL_CVSID("$Id: cpl_vsil_subfile.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_subfile.cpp 27745 2014-09-27 16:38:57Z goatbar $");
 
 /************************************************************************/
 /* ==================================================================== */
@@ -407,6 +407,7 @@ int VSISubFileFilesystemHandler::Mkdir( CPL_UNUSED const char * pszPathname,
 /************************************************************************/
 
 int VSISubFileFilesystemHandler::Rmdir( CPL_UNUSED const char * pszPathname )
+
 {
     errno = EACCES;
     return -1;
diff --git a/port/cpl_vsil_tar.cpp b/port/cpl_vsil_tar.cpp
index a0bb0b5..b03def9 100644
--- a/port/cpl_vsil_tar.cpp
+++ b/port/cpl_vsil_tar.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsil_tar.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_vsil_tar.cpp 28588 2015-03-01 20:44:43Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for tar files (.tar).
@@ -29,7 +29,7 @@
 
 #include "cpl_vsi_virtual.h"
 
-CPL_CVSID("$Id: cpl_vsil_tar.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_vsil_tar.cpp 28588 2015-03-01 20:44:43Z rouault $");
 
 
 /************************************************************************/
@@ -130,12 +130,12 @@ int VSITarReader::GotoNextFile()
         abyHeader[115] != '\0' ||
         abyHeader[123] != '\0' ||
         (abyHeader[135] != '\0' && abyHeader[135] != ' ') ||
-        (abyHeader[147] != '\0' && abyHeader[147] != ' ') ||
-        abyHeader[154] != '\0' ||
-        abyHeader[155] != ' ')
+        (abyHeader[147] != '\0' && abyHeader[147] != ' '))
     {
         return FALSE;
     }
+    if( abyHeader[124] < '0' || abyHeader[124] > '7' )
+        return FALSE;
 
     osNextFileName = abyHeader;
     nNextFileSize = 0;
diff --git a/port/cpl_vsil_unix_stdio_64.cpp b/port/cpl_vsil_unix_stdio_64.cpp
index 99cf0c2..932bc16 100644
--- a/port/cpl_vsil_unix_stdio_64.cpp
+++ b/port/cpl_vsil_unix_stdio_64.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_vsil_unix_stdio_64.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_vsil_unix_stdio_64.cpp 29006 2015-04-25 11:03:10Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for Unix platforms with fseek64()
@@ -52,7 +52,7 @@
 #include <dirent.h>
 #include <errno.h>
 
-CPL_CVSID("$Id: cpl_vsil_unix_stdio_64.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_vsil_unix_stdio_64.cpp 29006 2015-04-25 11:03:10Z rouault $");
 
 #if defined(UNIX_STDIO_64)
 
@@ -108,7 +108,7 @@ class VSIUnixStdioFilesystemHandler : public VSIFilesystemHandler
 {
 #ifdef VSI_COUNT_BYTES_READ
     vsi_l_offset  nTotalBytesRead;
-    void         *hMutex;
+    CPLMutex     *hMutex;
 #endif
 
 public:
@@ -203,9 +203,8 @@ int VSIUnixStdioHandle::Close()
 /************************************************************************/
 
 int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
-
 {
-    GByte abyTemp[4096];
+    bAtEOF = FALSE;
 
     // seeks that do nothing are still surprisingly expensive with MSVCRT.
     // try and short circuit if possible.
@@ -219,20 +218,20 @@ int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
         GIntBig nDiff = (GIntBig)nOffset - (GIntBig)this->nOffset;
         if( nDiff > 0 && nDiff < 4096 )
         {
+            GByte abyTemp[4096];
             int nRead = (int)fread(abyTemp, 1, (int)nDiff, fp);
             if( nRead == (int)nDiff )
             {
                 this->nOffset = nOffset;
                 bLastOpWrite = FALSE;
                 bLastOpRead = FALSE;
-                bAtEOF = FALSE;
                 return 0;
             }
         }
     }
 
-    int     nResult = VSI_FSEEK64( fp, nOffset, nWhence );
-    int     nError = errno;
+    const int nResult = VSI_FSEEK64( fp, nOffset, nWhence );
+    int nError = errno;
 
 #ifdef VSI_DEBUG
 
@@ -257,7 +256,7 @@ int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
                    fp, nOffset, nWhence, nResult );
     }
 
-#endif 
+#endif
 
     if( nResult != -1 )
     {
@@ -274,10 +273,9 @@ int VSIUnixStdioHandle::Seek( vsi_l_offset nOffset, int nWhence )
             this->nOffset += nOffset;
         }
     }
-        
+
     bLastOpWrite = FALSE;
     bLastOpRead = FALSE;
-    bAtEOF = FALSE;
 
     errno = nError;
     return nResult;
@@ -356,7 +354,12 @@ size_t VSIUnixStdioHandle::Read( void * pBuffer, size_t nSize, size_t nCount )
 
     if (nResult != nCount)
     {
-        nOffset = VSI_FTELL64( fp );
+        errno = 0;
+        vsi_l_offset nNewOffset = VSI_FTELL64( fp );
+        if( errno == 0 ) /* ftell() can fail if we are end of file with a pipe */
+            nOffset = nNewOffset;
+        else
+            CPLDebug("VSI", "%s", VSIStrerror(errno));
         bAtEOF = feof(fp);
     }
 
@@ -506,10 +509,9 @@ VSIUnixStdioFilesystemHandler::Open( const char *pszFilename,
 /*                                Stat()                                */
 /************************************************************************/
 
-int VSIUnixStdioFilesystemHandler::Stat( const char * pszFilename, 
+int VSIUnixStdioFilesystemHandler::Stat( const char * pszFilename,
                                          VSIStatBufL * pStatBuf,
                                          CPL_UNUSED int nFlags)
-
 {
     return( VSI_STAT64( pszFilename, pStatBuf ) );
 }
diff --git a/port/cpl_vsil_win32.cpp b/port/cpl_vsil_win32.cpp
index 6444ee4..1b6b5a4 100644
--- a/port/cpl_vsil_win32.cpp
+++ b/port/cpl_vsil_win32.cpp
@@ -1,5 +1,5 @@
 /**********************************************************************
- * $Id: cpl_vsil_win32.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_vsil_win32.cpp 27491 2014-07-05 11:24:48Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement VSI large file api for Win32.
@@ -30,7 +30,7 @@
 
 #include "cpl_vsi_virtual.h"
 
-CPL_CVSID("$Id: cpl_vsil_win32.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_vsil_win32.cpp 27491 2014-07-05 11:24:48Z rouault $");
 
 #if defined(WIN32)
 
@@ -273,7 +273,9 @@ vsi_l_offset VSIWin32Handle::Tell()
 int VSIWin32Handle::Flush()
 
 {
-    FlushFileBuffers( hFile );
+    /* Nothing needed to offer the same guarantee as POSIX fflush() */
+    /* FlushFileBuffers() would be closer to fsync() */
+    /* See http://trac.osgeo.org/gdal/ticket/5556 */
     return 0;
 }
 
diff --git a/port/cpl_vsisimple.cpp b/port/cpl_vsisimple.cpp
index 790073e..e012c29 100644
--- a/port/cpl_vsisimple.cpp
+++ b/port/cpl_vsisimple.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_vsisimple.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cpl_vsisimple.cpp 28971 2015-04-21 20:40:44Z rouault $
  *
  * Project:  Common Portability Library 
  * Purpose:  Simple implementation of POSIX VSI functions.
@@ -61,7 +61,7 @@
 /* DEBUG_VSIMALLOC must also be defined */
 //#define DEBUG_VSIMALLOC_VERBOSE
 
-CPL_CVSID("$Id: cpl_vsisimple.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cpl_vsisimple.cpp 28971 2015-04-21 20:40:44Z rouault $");
 
 /* for stat() */
 
@@ -325,7 +325,7 @@ int VSIFPutc( int nChar, FILE * fp )
 #ifdef DEBUG_VSIMALLOC_STATS
 #include "cpl_multiproc.h"
 
-static void* hMemStatMutex = 0;
+static CPLMutex* hMemStatMutex = 0;
 static size_t nCurrentTotalAllocs = 0;
 static size_t nMaxTotalAllocs = 0;
 static GUIntBig nVSIMallocs = 0;
@@ -512,7 +512,7 @@ void VSICheckMarkerBegin(char* ptr)
     if (memcmp(ptr, "VSIM", 4) != 0)
     {
         CPLError(CE_Fatal, CPLE_AppDefined,
-                 "Inconsistant use of VSI memory allocation primitives for %p : %c%c%c%c",
+                 "Inconsistent use of VSI memory allocation primitives for %p : %c%c%c%c",
                  ptr, ptr[0], ptr[1], ptr[2], ptr[3]);
     }
 }
@@ -681,16 +681,12 @@ void VSIFree( void * pData )
 char *VSIStrdup( const char * pszString )
 
 {
-#ifdef DEBUG_VSIMALLOC
     int nSize = strlen(pszString) + 1;
     char* ptr = (char*) VSIMalloc(nSize);
     if (ptr == NULL)
         return NULL;
     memcpy(ptr, pszString, nSize);
     return ptr;
-#else
-    return( strdup( pszString ) );
-#endif
 }
 
 /************************************************************************/
@@ -945,3 +941,93 @@ char *VSIStrerror( int nErrno )
 {
     return strerror( nErrno );
 }
+
+
+/************************************************************************/
+/*                        CPLGetPhysicalRAM()                           */
+/************************************************************************/
+
+#if HAVE_SC_PHYS_PAGES
+
+/** Return the total physical RAM in bytes.
+ *
+ * @return the total physical RAM in bytes (or 0 in case of failure).
+ * @since GDAL 2.0
+ */
+GIntBig CPLGetPhysicalRAM(void)
+{
+    return ((GIntBig)sysconf(_SC_PHYS_PAGES)) * sysconf(_SC_PAGESIZE);
+}
+
+#elif defined(__MACH__) && defined(__APPLE__)
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+GIntBig CPLGetPhysicalRAM(void)
+{
+    int mib[2];
+    GIntBig nPhysMem = 0;
+
+    mib[0] = CTL_HW;
+    mib[1] = HW_MEMSIZE;
+    size_t nLengthRes = sizeof(nPhysMem);
+    sysctl(mib, 2, &nPhysMem, &nLengthRes, NULL, 0);
+
+    return nPhysMem;
+}
+
+#elif defined(WIN32)
+
+/* GlobalMemoryStatusEx requires _WIN32_WINNT >= 0x0500 */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <windows.h>
+
+GIntBig CPLGetPhysicalRAM(void)
+{
+    MEMORYSTATUSEX statex;
+    statex.ullTotalPhys = 0;
+    statex.dwLength = sizeof (statex);
+    GlobalMemoryStatusEx (&statex);
+    return (GIntBig) statex.ullTotalPhys;
+}
+
+#else
+
+GIntBig CPLGetPhysicalRAM(void)
+{
+    static int bOnce = FALSE;
+    if( !bOnce )
+    {
+        bOnce = TRUE;
+        CPLDebug("PORT", "No implementation for CPLGetPhysicalRAM()");
+    }
+    return 0;
+}
+#endif
+
+/************************************************************************/
+/*                       CPLGetUsablePhysicalRAM()                      */
+/************************************************************************/
+
+/** Return the total physical RAM, usable by a process, in bytes.
+ *
+ * This is the same as CPLGetPhysicalRAM() except it will limit to 2 GB
+ * for 32 bit processes.
+ *
+ * Note: This memory may already be partly used by other processes.
+ *
+ * @return the total physical RAM, usable by a process, in bytes (or 0 in case of failure).
+ * @since GDAL 2.0
+ */
+GIntBig  CPLGetUsablePhysicalRAM(void)
+{
+    GIntBig nRAM = CPLGetPhysicalRAM();
+#if SIZEOF_VOIDP == 4
+    if( nRAM > INT_MAX )
+        nRAM = INT_MAX;
+#endif
+    return nRAM;
+}
diff --git a/port/cpl_xml_validate.cpp b/port/cpl_xml_validate.cpp
index 77c4bfa..6cba8a9 100644
--- a/port/cpl_xml_validate.cpp
+++ b/port/cpl_xml_validate.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl_xml_validate.cpp 27722 2014-09-22 15:37:31Z goatbar $
+ * $Id: cpl_xml_validate.cpp 27755 2014-09-28 16:51:08Z goatbar $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Implement XML validation against XSD schema
@@ -29,7 +29,7 @@
 
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: cpl_xml_validate.cpp 27722 2014-09-22 15:37:31Z goatbar $");
+CPL_CVSID("$Id: cpl_xml_validate.cpp 27755 2014-09-28 16:51:08Z goatbar $");
 
 #ifdef HAVE_LIBXML2
 #include <libxml/xmlversion.h>
@@ -1126,9 +1126,9 @@ int CPLValidateXML(const char* pszXMLFilename,
 /*                          CPLValidateXML()                            */
 /************************************************************************/
 
-int CPLValidateXML(const char* pszXMLFilename,
-                   const char* pszXSDFilename,
-                   char** papszOptions)
+int CPLValidateXML(CPL_UNUSED const char* pszXMLFilename,
+                   CPL_UNUSED const char* pszXSDFilename,
+                   CPL_UNUSED char** papszOptions)
 {
     CPLError(CE_Failure, CPLE_NotSupported,
              "%s not implemented due to missing libxml2 support",
diff --git a/port/cplgetsymbol.cpp b/port/cplgetsymbol.cpp
index 9ec2a66..bb9c749 100644
--- a/port/cplgetsymbol.cpp
+++ b/port/cplgetsymbol.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cplgetsymbol.cpp 27461 2014-06-18 12:38:34Z rouault $
+ * $Id: cplgetsymbol.cpp 27460 2014-06-18 12:36:06Z rouault $
  *
  * Project:  Common Portability Library
  * Purpose:  Fetch a function pointer from a shared library / DLL.
@@ -30,7 +30,7 @@
 
 #include "cpl_conv.h"
 
-CPL_CVSID("$Id: cplgetsymbol.cpp 27461 2014-06-18 12:38:34Z rouault $");
+CPL_CVSID("$Id: cplgetsymbol.cpp 27460 2014-06-18 12:36:06Z rouault $");
 
 
 /* ==================================================================== */
diff --git a/port/cplkeywordparser.cpp b/port/cplkeywordparser.cpp
index 2a9a8d0..6a934c8 100644
--- a/port/cplkeywordparser.cpp
+++ b/port/cplkeywordparser.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cplkeywordparser.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cplkeywordparser.cpp 29123 2015-05-03 11:05:46Z bishop $
  *
  * Project:  Common Portability Library
  * Purpose:  Implementation of CPLKeywordParser - a class for parsing
@@ -118,7 +118,7 @@ int CPLKeywordParser::ReadGroup( const char *pszPathPrefix )
         if( !ReadPair( osName, osValue ) )
             return FALSE;
 
-        if( EQUAL(osName,"BEGIN_GROUP") )
+        if( EQUAL(osName,"BEGIN_GROUP") || EQUAL(osName,"GROUP") )
         {
             if( !ReadGroup( (CPLString(pszPathPrefix) + osValue + ".").c_str() ) )
                 return FALSE;
diff --git a/port/cplstring.cpp b/port/cplstring.cpp
index de3d542..564ead8 100644
--- a/port/cplstring.cpp
+++ b/port/cplstring.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cplstring.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cplstring.cpp 28204 2014-12-24 06:00:26Z goatbar $
  *
  * Project:  GDAL 
  * Purpose:  CPLString implementation.
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include <string>
 
-CPL_CVSID("$Id: cplstring.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cplstring.cpp 28204 2014-12-24 06:00:26Z goatbar $");
 
 /*
  * The CPLString class is derived from std::string, so the vast majority 
@@ -69,9 +69,9 @@ CPLString &CPLString::vPrintf( const char *pszFormat, va_list args )
 
 #if !defined(HAVE_VSNPRINTF)
     char *pszBuffer = (char *) CPLMalloc(30000);
-    if( vsprintf( pszBuffer, pszFormat, args) > 29998 )
+    if( CPLvsnprintf( pszBuffer, 30000, pszFormat, args) > 29998 )
     {
-        CPLError( CE_Fatal, CPLE_AppDefined, 
+        CPLError( CE_Fatal, CPLE_AppDefined,
                   "CPLString::vPrintf() ... buffer overrun." );
     }
     *this = pszBuffer;
@@ -92,7 +92,7 @@ CPLString &CPLString::vPrintf( const char *pszFormat, va_list args )
     wrk_args = args;
 #endif
     
-    nPR = vsnprintf( szModestBuffer, sizeof(szModestBuffer), pszFormat, 
+    nPR = CPLvsnprintf( szModestBuffer, sizeof(szModestBuffer), pszFormat, 
                      wrk_args );
     if( nPR == -1 || nPR >= (int) sizeof(szModestBuffer)-1 )
     {
@@ -105,7 +105,7 @@ CPLString &CPLString::vPrintf( const char *pszFormat, va_list args )
 #else
         wrk_args = args;
 #endif
-        while( (nPR=vsnprintf( pszWorkBuffer, nWorkBufferSize, pszFormat,wrk_args))
+        while( (nPR=CPLvsnprintf( pszWorkBuffer, nWorkBufferSize, pszFormat,wrk_args))
                >= nWorkBufferSize-1 
                || nPR == -1 )
         {
@@ -126,9 +126,12 @@ CPLString &CPLString::vPrintf( const char *pszFormat, va_list args )
     {
         *this = szModestBuffer;
     }
+#ifdef va_copy
     va_end( wrk_args );
 #endif
 
+#endif /* !defined(HAVE_VSNPRINTF) */
+
     return *this;
 }
 
@@ -158,14 +161,8 @@ CPLString &CPLString::FormatC( double dfValue, const char *pszFormat )
 
     char szWork[512]; // presumably long enough for any number?
 
-    sprintf( szWork, pszFormat, dfValue );
+    CPLsprintf( szWork, pszFormat, dfValue );
     CPLAssert( strlen(szWork) < sizeof(szWork) );
-    
-    if( strchr( szWork, ',' ) != NULL )
-    {
-        char *pszDelim = strchr( szWork, ',' );
-        *pszDelim = '.';
-    }
 
     *this += szWork;
     
diff --git a/port/cplstringlist.cpp b/port/cplstringlist.cpp
index 08516dd..5f13d75 100644
--- a/port/cplstringlist.cpp
+++ b/port/cplstringlist.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cplstringlist.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: cplstringlist.cpp 27496 2014-07-06 11:23:58Z rouault $
  *
  * Project:  GDAL 
  * Purpose:  CPLStringList implementation.
@@ -7,7 +7,7 @@
  *
  ******************************************************************************
  * Copyright (c) 2011, Frank Warmerdam <warmerdam at pobox.com>
- * Copyright (c) 2011, Even Rouault <even dot rouault at mines-paris dot org>
+ * Copyright (c) 2011, Even Rouault <even dot rouault at mines-paris dot org>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -31,7 +31,7 @@
 #include "cpl_string.h"
 #include <string>
 
-CPL_CVSID("$Id: cplstringlist.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: cplstringlist.cpp 27496 2014-07-06 11:23:58Z rouault $");
 
 /************************************************************************/
 /*                           CPLStringList()                            */
@@ -468,6 +468,39 @@ char **CPLStringList::StealList()
     return papszRetList;
 }
 
+
+static int CPLCompareKeyValueString(const char* pszKVa, const char* pszKVb)
+{
+    const char* pszItera = pszKVa;
+    const char* pszIterb = pszKVb;
+    while( TRUE )
+    {
+        char cha = *pszItera;
+        char chb = *pszIterb;
+        if( cha == '=' || cha == '\0' )
+        {
+            if( chb == '=' || chb == '\0' )
+                return 0;
+            else
+                return -1;
+        }
+        if( chb == '=' || chb == '\0' )
+        {
+            return 1;
+        }
+        if( cha >= 'a' && cha <= 'z' )
+            cha -= ('a' - 'A');
+        if( chb >= 'a' && chb <= 'z' )
+            chb -= ('a' - 'A');
+        if( cha < chb )
+            return -1;
+        else if( cha > chb )
+            return 1;
+        pszItera ++;
+        pszIterb ++;
+    }
+}
+
 /************************************************************************/
 /*                            llCompareStr()                            */
 /*                                                                      */
@@ -476,7 +509,7 @@ char **CPLStringList::StealList()
 /************************************************************************/
 static int llCompareStr(const void *a, const void *b)
 {
-	return STRCASECMP((*(const char **)a),(*(const char **)b));
+	return CPLCompareKeyValueString((*(const char **)a),(*(const char **)b));
 }
 
 /************************************************************************/
@@ -542,7 +575,7 @@ int CPLStringList::FindName( const char *pszKey ) const
             && (pszMiddle[nKeyLen] == '=' || pszMiddle[nKeyLen] == ':') )
             return iMiddle;
 
-        if( STRCASECMP(pszKey,pszMiddle) < 0 )
+        if( CPLCompareKeyValueString(pszKey,pszMiddle) < 0 )
             iEnd = iMiddle-1;
         else
             iStart = iMiddle+1;
@@ -722,7 +755,7 @@ int CPLStringList::FindSortedInsertionPoint( const char *pszLine )
         int iMiddle = (iEnd+iStart)/2;
         const char *pszMiddle = papszList[iMiddle];
 
-        if( STRCASECMP(pszLine,pszMiddle) < 0 )
+        if( CPLCompareKeyValueString(pszLine,pszMiddle) < 0 )
             iEnd = iMiddle-1;
         else
             iStart = iMiddle+1;
@@ -731,9 +764,9 @@ int CPLStringList::FindSortedInsertionPoint( const char *pszLine )
     iEnd++;
     CPLAssert( iEnd >= 0 && iEnd <= nCount );
     CPLAssert( iEnd == 0 
-               || STRCASECMP(pszLine,papszList[iEnd-1]) >= 0 );
+               || CPLCompareKeyValueString(pszLine,papszList[iEnd-1]) >= 0 );
     CPLAssert( iEnd == nCount
-               || STRCASECMP(pszLine,papszList[iEnd]) <= 0 );
+               || CPLCompareKeyValueString(pszLine,papszList[iEnd]) <= 0 );
     
     return iEnd;
 }
diff --git a/port/vsipreload.cpp b/port/vsipreload.cpp
index d153a37..90589ad 100644
--- a/port/vsipreload.cpp
+++ b/port/vsipreload.cpp
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: vsipreload.cpp 27044 2014-03-16 23:41:27Z rouault $
+ * $Id: vsipreload.cpp 28464 2015-02-12 14:40:34Z rouault $
  *
  * Project:  CPL - Common Portability Library
  * Purpose:  Standalone shared library that can be LD_PRELOAD'ed as an overload of
@@ -68,7 +68,7 @@
 #include "cpl_string.h"
 #include "cpl_hash_set.h"
 
-CPL_CVSID("$Id: vsipreload.cpp 27044 2014-03-16 23:41:27Z rouault $");
+CPL_CVSID("$Id: vsipreload.cpp 28464 2015-02-12 14:40:34Z rouault $");
 
 static int DEBUG_VSIPRELOAD = 0;
 static int DEBUG_VSIPRELOAD_ONLY_VSIL = 1;
@@ -100,6 +100,7 @@ DECLARE_SYMBOL(fgetpos, int, (FILE *stream, fpos_t *pos));
 DECLARE_SYMBOL(fsetpos, int, (FILE *stream, fpos_t *pos));
 DECLARE_SYMBOL(fileno, int, (FILE *stream));
 DECLARE_SYMBOL(ferror, int, (FILE *stream));
+DECLARE_SYMBOL(clearerr, void, (FILE *stream));
 
 DECLARE_SYMBOL(fdopen, FILE*, (int fd, const char *mode));
 DECLARE_SYMBOL(freopen, FILE*, (const char *path, const char *mode, FILE *stream));
@@ -126,11 +127,12 @@ DECLARE_SYMBOL(ftruncate, int, (int fd, off_t length));
 
 DECLARE_SYMBOL(opendir, DIR* , (const char *name));
 DECLARE_SYMBOL(readdir, struct dirent*, (DIR *dirp));
+DECLARE_SYMBOL(readdir64, struct dirent64*, (DIR *dirp));
 DECLARE_SYMBOL(closedir, int, (DIR *dirp));
 DECLARE_SYMBOL(dirfd, int, (DIR *dirp));
 DECLARE_SYMBOL(fchdir, int, (int fd));
 
-static void* hMutex = NULL;
+static CPLLock* hLock = NULL;
 
 typedef struct
 {
@@ -138,6 +140,7 @@ typedef struct
     char** papszDir;
     int    nIter;
     struct dirent ent;
+    struct dirent64 ent64;
     int    fd;
 } VSIDIR;
 
@@ -160,7 +163,7 @@ std::string osCurDir;
 
 static void myinit(void)
 {
-    CPLMutexHolderD(&hMutex);
+    CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
 
     if( pfnfopen64 != NULL ) return;
     DEBUG_VSIPRELOAD = getenv("DEBUG_VSIPRELOAD") != NULL;
@@ -182,6 +185,7 @@ static void myinit(void)
     LOAD_SYMBOL(fsetpos);
     LOAD_SYMBOL(fileno);
     LOAD_SYMBOL(ferror);
+    LOAD_SYMBOL(clearerr);
 
     LOAD_SYMBOL(fdopen);
     LOAD_SYMBOL(freopen);
@@ -207,6 +211,7 @@ static void myinit(void)
 
     LOAD_SYMBOL(opendir);
     LOAD_SYMBOL(readdir);
+    LOAD_SYMBOL(readdir64);
     LOAD_SYMBOL(closedir);
     LOAD_SYMBOL(dirfd);
     LOAD_SYMBOL(fchdir);
@@ -219,7 +224,7 @@ static void myinit(void)
 static VSILFILE* getVSILFILE(FILE* stream)
 {
     VSILFILE* ret;
-    CPLMutexHolderD(&hMutex);
+    CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
     std::set<VSILFILE*>::iterator oIter = oSetFiles.find((VSILFILE*)stream);
     if( oIter != oSetFiles.end() )
         ret = *oIter;
@@ -235,7 +240,7 @@ static VSILFILE* getVSILFILE(FILE* stream)
 static VSILFILE* getVSILFILE(int fd)
 {
     VSILFILE* ret;
-    CPLMutexHolderD(&hMutex);
+    CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
     std::map<int, VSILFILE*>::iterator oIter = oMapfdToVSI.find(fd);
     if( oIter != oMapfdToVSI.end() )
         ret = oIter->second;
@@ -272,7 +277,7 @@ static VSILFILE* VSIFfopenHelper(const char *path, const char *mode)
     VSILFILE* fpVSIL = VSIFOpenL(path, mode);
     if( fpVSIL != NULL )
     {
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
         oSetFiles.insert(fpVSIL);
         oMapVSIToString[fpVSIL] = path;
     }
@@ -285,7 +290,7 @@ static VSILFILE* VSIFfopenHelper(const char *path, const char *mode)
 
 static int getfdFromVSILFILE(VSILFILE* fpVSIL)
 {
-    CPLMutexHolderD(&hMutex);
+    CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
 
     int fd;
     std::map<VSILFILE*, int>::iterator oIter = oMapVSITofd.find(fpVSIL);
@@ -491,7 +496,7 @@ int fclose(FILE *stream)
     if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "fclose(stream=%p)\n", stream);
     if( fpVSIL != NULL )
     {
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
 
         int ret = VSIFCloseL(fpVSIL);
         oMapVSIToString.erase(fpVSIL);
@@ -853,6 +858,24 @@ int ferror(FILE *stream)
 }
 
 /************************************************************************/
+/*                             clearerr()                               */
+/************************************************************************/
+
+void clearerr(FILE *stream)
+{
+    myinit();
+    VSILFILE* fpVSIL = getVSILFILE(stream);
+    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
+    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "clearerr(stream=%p)\n", stream);
+    if( fpVSIL != NULL )
+    {
+        fprintf(stderr, "clearerr() unimplemented for VSILFILE\n");
+    }
+    else
+        pfnclearerr(stream);
+}
+
+/************************************************************************/
 /*                             fdopen()                                 */
 /************************************************************************/
 
@@ -931,7 +954,7 @@ int open(const char *path, int flags, ...)
             S_ISDIR(sStatBufL.st_mode) )
         {
             fd = open("/dev/zero", O_RDONLY);
-            CPLMutexHolderD(&hMutex)
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
             oMapDirFdToName[fd] = newname;
         }
         else
@@ -987,7 +1010,7 @@ int open64(const char *path, int flags, ...)
             S_ISDIR(sStatBufL.st_mode) )
         {
             fd = open("/dev/zero", O_RDONLY);
-            CPLMutexHolderD(&hMutex)
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
             oMapDirFdToName[fd] = newname;
         }
         else
@@ -1021,7 +1044,7 @@ int close(int fd)
     VSILFILE* fpVSIL = getVSILFILE(fd);
     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
     {
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
         assert( oMapfdToVSIDIR.find(fd) == oMapfdToVSIDIR.end() );
 
         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
@@ -1035,7 +1058,7 @@ int close(int fd)
     if( fpVSIL != NULL )
     {
         VSIFCloseL(fpVSIL);
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
         oSetFiles.erase(fpVSIL);
         pfnclose(oMapVSITofd[fpVSIL]);
         oMapVSITofd.erase(fpVSIL);
@@ -1137,7 +1160,7 @@ int __fxstat (int ver, int fd, struct stat *buf)
     std::string name;
     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(fpVSIL);
     {
-        CPLMutexHolderD(&hMutex)
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
         {
             name = oMapDirFdToName[fd];
@@ -1165,7 +1188,7 @@ int __fxstat (int ver, int fd, struct stat *buf)
     {
         VSIStatBufL sStatBufL;
         {
-            CPLMutexHolderD(&hMutex);
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
             name = oMapVSIToString[fpVSIL];
         }
         int ret = VSIStatL(name.c_str(), &sStatBufL);
@@ -1198,7 +1221,7 @@ int __fxstat64 (int ver, int fd, struct stat64 *buf)
         VSIStatBufL sStatBufL;
         std::string name;
         {
-            CPLMutexHolderD(&hMutex);
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
             name = oMapVSIToString[fpVSIL];
         }
         int ret = VSIStatL(name.c_str(), &sStatBufL);
@@ -1384,7 +1407,7 @@ DIR *opendir(const char *name)
             mydir->nIter = 0;
             mydir->fd = -1;
             ret = (DIR*)mydir;
-            CPLMutexHolderD(&hMutex);
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
             oSetVSIDIR.insert(mydir);
         }
     }
@@ -1395,6 +1418,39 @@ DIR *opendir(const char *name)
 }
 
 /************************************************************************/
+/*                             filldir()                                */
+/************************************************************************/
+
+static int filldir(VSIDIR* mydir)
+{
+    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(mydir);
+    char* pszName = mydir->papszDir[mydir->nIter++];
+    if( pszName == NULL )
+        return FALSE;
+    mydir->ent.d_ino = 0;
+    mydir->ent.d_off = 0;
+    mydir->ent.d_reclen = sizeof(mydir->ent);
+    VSIStatBufL sStatBufL;
+    VSIStatL(CPLFormFilename(mydir->pszDirname, pszName, NULL), &sStatBufL);
+    if( DEBUG_VSIPRELOAD_COND && S_ISDIR(sStatBufL.st_mode) )
+        fprintf(stderr, "%s is dir\n", pszName);
+    mydir->ent.d_type = S_ISDIR(sStatBufL.st_mode) ? DT_DIR :
+                        S_ISREG(sStatBufL.st_mode) ? DT_REG :
+                        S_ISLNK(sStatBufL.st_mode) ? DT_LNK :
+                        DT_UNKNOWN;
+    strncpy(mydir->ent.d_name, pszName, 256);
+    mydir->ent.d_name[255] = '\0';
+
+    mydir->ent64.d_ino = 0;
+    mydir->ent64.d_off = 0;
+    mydir->ent64.d_reclen = sizeof(mydir->ent64);
+    mydir->ent64.d_type = mydir->ent.d_type;
+    strcpy(mydir->ent64.d_name, mydir->ent.d_name);
+
+    return TRUE;
+}
+
+/************************************************************************/
 /*                             readdir()                                */
 /************************************************************************/
 
@@ -1406,22 +1462,9 @@ struct dirent *readdir(DIR *dirp)
     if( oSetVSIDIR.find((VSIDIR*)dirp) != oSetVSIDIR.end() )
     {
         VSIDIR* mydir = (VSIDIR*)dirp;
-        char* pszName = mydir->papszDir[mydir->nIter++];
-        if( pszName == NULL )
-            return NULL;
-        mydir->ent.d_ino = 0;
-        mydir->ent.d_off = 0;
-        mydir->ent.d_reclen = sizeof(mydir->ent);
-        VSIStatBufL sStatBufL;
-        VSIStatL(CPLFormFilename(mydir->pszDirname, pszName, NULL), &sStatBufL);
-        if( DEBUG_VSIPRELOAD_COND && S_ISDIR(sStatBufL.st_mode) )
-            fprintf(stderr, "%s is dir\n", pszName);
-        mydir->ent.d_type = S_ISDIR(sStatBufL.st_mode) ? DT_DIR :
-                            S_ISREG(sStatBufL.st_mode) ? DT_REG :
-                            S_ISLNK(sStatBufL.st_mode) ? DT_LNK :
-                            DT_UNKNOWN;
-        strncpy(mydir->ent.d_name, pszName, 256);
-        mydir->ent.d_name[255] = '\0';
+        if( !filldir(mydir) )
+            return FALSE;
+
         return &(mydir->ent);
     }
     else
@@ -1429,6 +1472,27 @@ struct dirent *readdir(DIR *dirp)
 }
 
 /************************************************************************/
+/*                             readdir64()                              */
+/************************************************************************/
+
+struct dirent64 *readdir64(DIR *dirp)
+{
+    myinit();
+    int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND((VSIDIR*)dirp);
+    if (DEBUG_VSIPRELOAD_COND) fprintf(stderr, "readdir64(%p)\n", dirp);
+    if( oSetVSIDIR.find((VSIDIR*)dirp) != oSetVSIDIR.end() )
+    {
+        VSIDIR* mydir = (VSIDIR*)dirp;
+        if( !filldir(mydir) )
+            return FALSE;
+
+        return &(mydir->ent64);
+    }
+    else
+        return pfnreaddir64(dirp);
+}
+
+/************************************************************************/
 /*                             closedir()                               */
 /************************************************************************/
 
@@ -1442,7 +1506,7 @@ int closedir(DIR *dirp)
         VSIDIR* mydir = (VSIDIR*)dirp;
         CPLFree(mydir->pszDirname);
         CSLDestroy(mydir->papszDir);
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
         if( mydir->fd >= 0 )
         {
             oMapfdToVSIDIR.erase(mydir->fd);
@@ -1472,7 +1536,7 @@ int dirfd(DIR *dirp)
         if( mydir->fd < 0 )
         {
             mydir->fd = open("/dev/zero", O_RDONLY);
-            CPLMutexHolderD(&hMutex);
+            CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
             oMapfdToVSIDIR[mydir->fd] = mydir;
         }
         ret = mydir->fd;
@@ -1491,14 +1555,14 @@ int fchdir(int fd)
 {
     VSIDIR* mydir = NULL;
     {
-        CPLMutexHolderD(&hMutex);
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX);
         if( oMapfdToVSIDIR.find(fd) != oMapfdToVSIDIR.end() )
             mydir = oMapfdToVSIDIR[fd];
     }
     int DEBUG_VSIPRELOAD_COND = GET_DEBUG_VSIPRELOAD_COND(mydir);
     std::string name;
     {
-        CPLMutexHolderD(&hMutex)
+        CPLLockHolderD(&hLock, LOCK_RECURSIVE_MUTEX)
         if( oMapDirFdToName.find(fd) != oMapDirFdToName.end())
         {
             name = oMapDirFdToName[fd];
diff --git a/scripts/vagrant/gdal.sh b/scripts/vagrant/gdal.sh
index 406c6d3..4b5acd3 100755
--- a/scripts/vagrant/gdal.sh
+++ b/scripts/vagrant/gdal.sh
@@ -1,3 +1,9 @@
+#!/bin/sh
+
+# abort install if any errors occur and enable tracing
+set -o errexit
+set -o xtrace
+
 NUMTHREADS=2
 if [[ -f /sys/devices/system/cpu/online ]]; then
 	# Calculates 1.5 times physical threads
@@ -6,16 +12,16 @@ fi
 #NUMTHREADS=1 # disable MP
 export NUMTHREADS
 
-svn checkout https://svn.osgeo.org/gdal/trunk gdal
-cd gdal/gdal
+cd /vagrant
 #  --with-ecw=/usr/local --with-mrsid=/usr/local --with-mrsid-lidar=/usr/local --with-fgdb=/usr/local
 ./configure  --prefix=/usr --without-libtool --enable-debug --with-jpeg12 \
-            --with-perl --with-python --with-poppler \
+            --with-python --with-poppler \
             --with-podofo --with-spatialite --with-java --with-mdb \
             --with-jvm-lib-add-rpath --with-epsilon --with-gta \
             --with-mysql --with-liblzma --with-webp --with-libkml \
             --with-openjpeg=/usr/local --with-armadillo
 
+make clean >/dev/null
 make -j $NUMTHREADS
 cd apps
 make test_ogrsf
@@ -28,4 +34,21 @@ sudo ldconfig
 # not sure why we need to do that
 sudo cp -r /usr/lib/python2.7/site-packages/*  /usr/lib/python2.7/dist-packages/
 
+cd swig/perl
+make veryclean
+make
+make test
+cd ../..
+
+cd swig/java
+JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 make
+make test
+cd ../..
+
+cd swig/csharp
+# There's an issue with swig 2.0.4 from ubuntu 12.04
+PATH=$HOME/install-swig-1.3.40/bin:$PATH make generate
+make
+# For some reason, this fails on Vagrant ubuntu 12.04
+# make test
 cd ../..
diff --git a/scripts/vagrant/libkml.sh b/scripts/vagrant/libkml.sh
index a0c345f..2f8a58e 100755
--- a/scripts/vagrant/libkml.sh
+++ b/scripts/vagrant/libkml.sh
@@ -1,3 +1,9 @@
+#!/bin/sh
+
+# abort install if any errors occur and enable tracing
+set -o errexit
+set -o xtrace
+
 NUMTHREADS=2
 if [[ -f /sys/devices/system/cpu/online ]]; then
 	# Calculates 1.5 times physical threads
diff --git a/scripts/vagrant/openjpeg.sh b/scripts/vagrant/openjpeg.sh
index 7660ca1..0a539f0 100755
--- a/scripts/vagrant/openjpeg.sh
+++ b/scripts/vagrant/openjpeg.sh
@@ -1,3 +1,9 @@
+#!/bin/sh
+
+# abort install if any errors occur and enable tracing
+set -o errexit
+set -o xtrace
+
 NUMTHREADS=2
 if [[ -f /sys/devices/system/cpu/online ]]; then
 	# Calculates 1.5 times physical threads
diff --git a/scripts/vagrant/postgis.sh b/scripts/vagrant/postgis.sh
index 94fca70..237a850 100755
--- a/scripts/vagrant/postgis.sh
+++ b/scripts/vagrant/postgis.sh
@@ -1,6 +1,13 @@
+#!/bin/sh
+
+# abort install if any errors occur and enable tracing
+set -o errexit
+set -o xtrace
+
 sudo sed -i  's/md5/trust/' /etc/postgresql/9.1/main/pg_hba.conf
 sudo sed -i  's/peer/trust/' /etc/postgresql/9.1/main/pg_hba.conf
 
+sudo ln -s /usr/lib/libgdal.so.2 /usr/lib/libgdal.so.1
 sudo service postgresql restart
 psql -c "create database autotest" -U postgres
 psql -c "create extension postgis" -d autotest -U postgres
diff --git a/scripts/vagrant/swig-1.3.40.sh b/scripts/vagrant/swig-1.3.40.sh
new file mode 100755
index 0000000..eb83310
--- /dev/null
+++ b/scripts/vagrant/swig-1.3.40.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# abort install if any errors occur and enable tracing
+set -o errexit
+set -o xtrace
+
+NUMTHREADS=2
+if [[ -f /sys/devices/system/cpu/online ]]; then
+        # Calculates 1.5 times physical threads
+        NUMTHREADS=$(( ( $(cut -f 2 -d '-' /sys/devices/system/cpu/online) + 1 ) * 15 / 10  ))
+fi
+#NUMTHREADS=1 # disable MP
+export NUMTHREADS
+
+wget "http://downloads.sourceforge.net/project/swig/swig/swig-1.3.40/swig-1.3.40.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fswig%2Ffiles%2Fswig%2Fswig-1.3.40%2F&ts=1425900154&use_mirror=freefr" -O swig-1.3.40.tar.gz
+tar xvzf swig-1.3.40.tar.gz
+cd  swig-1.3.40
+./configure --prefix=$HOME/install-swig-1.3.40
+make -j $NUMTHREADS
+make install
+
diff --git a/scripts/vce2008_wine/prepare-gdal-vce2008.sh b/scripts/vce2008_wine/prepare-gdal-vce2008.sh
index cff6ebd..094aaa8 100755
--- a/scripts/vce2008_wine/prepare-gdal-vce2008.sh
+++ b/scripts/vce2008_wine/prepare-gdal-vce2008.sh
@@ -43,7 +43,7 @@ unzip /tmp/release-1500-dev.zip release-1500/* -d ~/.wine/drive_c
 svn checkout https://svn.osgeo.org/gdal/trunk $HOME/gdal_vce2008
 ln -s $HOME/gdal_vce2008 ~/.wine/drive_c/gdal
 
-# Install usefull scripts
+# Install useful scripts
 cp build_vce2008.patch /tmp
 cp build_vce2008.bat $HOME/gdal_vce2008/gdal
 cp build_vce2008.sh $HOME/gdal_vce2008/gdal
diff --git a/swig/GNUmakefile b/swig/GNUmakefile
index 7fdd74b..0c0fe23 100644
--- a/swig/GNUmakefile
+++ b/swig/GNUmakefile
@@ -6,7 +6,8 @@ include ../GDALmake.opt
 
 # The ALL_BINDINGS variable defines all the possible bindings.  It's used
 # in the dist and clean definitions.
-ALL_BINDINGS = python php csharp ruby perl java
+ALL_BINDINGS = python php csharp perl java
+# ruby
 
 default: generate
 
diff --git a/swig/csharp/apps/OGRFeatureEdit.cs b/swig/csharp/apps/OGRFeatureEdit.cs
new file mode 100644
index 0000000..991eb30
--- /dev/null
+++ b/swig/csharp/apps/OGRFeatureEdit.cs
@@ -0,0 +1,141 @@
+/******************************************************************************
+ * $Id: OGRFeatureEdit.cs 29015 2015-04-25 18:15:42Z tamas $
+ *
+ * Name:     OGRFeatureEdit.cs
+ * Project:  GDAL CSharp Interface
+ * Purpose:  Sample application to update/delete feature.
+ * Author:   Tamas Szekeres, szekerest at gmail.com
+ *
+ ******************************************************************************
+ * Copyright (c) 2015, Tamas Szekeres
+ *
+ * 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.
+ *****************************************************************************/
+
+using System;
+
+using OSGeo.OGR;
+using OSGeo.OSR;
+
+
+/// <summary>
+/// Sample application to update/delete feature.
+/// </summary> 
+
+class OGRFeatureEdit
+{
+	public static void usage() 
+	{
+        Console.WriteLine("usage:");
+        Console.WriteLine("OGRFeatureEdit {delete} {data source name} {layer name} {fid}");
+        Console.WriteLine("OGRFeatureEdit {update} {data source name} {layer name} {fid} {fieldname} {new value}");
+        Console.WriteLine("OGRFeatureEdit {copy} {data source name} {layer name} {src_fid} {dst_fid}");
+		System.Environment.Exit(-1);
+	}
+ 
+	public static void Main(string[] args) {
+
+		if (args.Length < 4) usage();
+
+        // Using early initialization of System.Console
+        Console.WriteLine("");
+
+		/* -------------------------------------------------------------------- */
+		/*      Register format(s).                                             */
+		/* -------------------------------------------------------------------- */
+		Ogr.RegisterAll();
+
+		/* -------------------------------------------------------------------- */
+		/*      Open data source.                                               */
+		/* -------------------------------------------------------------------- */
+		DataSource ds = Ogr.Open( args[1], 1 );
+		
+		if (ds == null) {
+			Console.WriteLine("Can't open " + args[0]);
+			System.Environment.Exit(-1);
+		}
+
+		/* -------------------------------------------------------------------- */
+		/*      Get driver                                                      */
+		/* -------------------------------------------------------------------- */	
+		Driver drv = ds.GetDriver();
+
+		if (drv == null) 
+		{
+			Console.WriteLine("Can't get driver.");
+			System.Environment.Exit(-1);
+		}
+        
+        Console.WriteLine("Using driver " + drv.name);
+
+		/* -------------------------------------------------------------------- */
+		/*      Iterating through the layers                                    */
+		/* -------------------------------------------------------------------- */
+        Layer layer = ds.GetLayerByName(args[2]);
+
+        if (layer == null)
+        {
+            Console.WriteLine("FAILURE: Couldn't fetch advertised layer " + args[2]);
+            System.Environment.Exit(-1);
+        }
+
+        if (args[0].Equals("update", StringComparison.InvariantCultureIgnoreCase))
+        {
+            Feature feature = layer.GetFeature(long.Parse(args[3]));
+            if (feature != null)
+            {
+                feature.SetField(args[4], args[5]);
+                if (layer.SetFeature(feature) == Ogr.OGRERR_NON_EXISTING_FEATURE)
+                    Console.WriteLine("feature not found");
+                else
+                    Console.WriteLine("feature updated successfully");
+            }
+            else
+                Console.WriteLine("feature not found");
+        }
+        else if (args[0].Equals("copy", StringComparison.InvariantCultureIgnoreCase))
+        {
+            Feature feature = layer.GetFeature(long.Parse(args[3]));
+            if (feature != null)
+            {
+                feature.SetFID(long.Parse(args[4]));
+                if (layer.SetFeature(feature) == Ogr.OGRERR_NON_EXISTING_FEATURE)
+                    Console.WriteLine("feature not found");
+                else
+                    Console.WriteLine("feature copied successfully");
+            }
+            else
+                Console.WriteLine("feature not found");
+        }
+        else if (args[0].Equals("delete", StringComparison.InvariantCultureIgnoreCase))
+        {
+            if (layer.TestCapability("DeleteFeature"))
+            {
+                if (layer.DeleteFeature(long.Parse(args[3])) == Ogr.OGRERR_NON_EXISTING_FEATURE)
+                    Console.WriteLine("feature not found");
+                else
+                    Console.WriteLine("feature removed successfully");
+            }
+            else
+                Console.WriteLine("DeleteFeature not supported");
+        }
+        else
+            Console.WriteLine("invalid command " + args[0]);
+	}
+}
diff --git a/swig/csharp/const/GdalConst.cs b/swig/csharp/const/GdalConst.cs
index b64b7e4..ac4496a 100644
--- a/swig/csharp/const/GdalConst.cs
+++ b/swig/csharp/const/GdalConst.cs
@@ -29,6 +29,14 @@ public class GdalConst {
   public static readonly int GA_Update = GdalConstPINVOKE.GA_Update_get();
   public static readonly int GF_Read = GdalConstPINVOKE.GF_Read_get();
   public static readonly int GF_Write = GdalConstPINVOKE.GF_Write_get();
+  public static readonly int GRIORA_NearestNeighbour = GdalConstPINVOKE.GRIORA_NearestNeighbour_get();
+  public static readonly int GRIORA_Bilinear = GdalConstPINVOKE.GRIORA_Bilinear_get();
+  public static readonly int GRIORA_Cubic = GdalConstPINVOKE.GRIORA_Cubic_get();
+  public static readonly int GRIORA_CubicSpline = GdalConstPINVOKE.GRIORA_CubicSpline_get();
+  public static readonly int GRIORA_Lanczos = GdalConstPINVOKE.GRIORA_Lanczos_get();
+  public static readonly int GRIORA_Average = GdalConstPINVOKE.GRIORA_Average_get();
+  public static readonly int GRIORA_Mode = GdalConstPINVOKE.GRIORA_Mode_get();
+  public static readonly int GRIORA_Gauss = GdalConstPINVOKE.GRIORA_Gauss_get();
   public static readonly int GCI_Undefined = GdalConstPINVOKE.GCI_Undefined_get();
   public static readonly int GCI_GrayIndex = GdalConstPINVOKE.GCI_GrayIndex_get();
   public static readonly int GCI_PaletteIndex = GdalConstPINVOKE.GCI_PaletteIndex_get();
@@ -77,16 +85,32 @@ public class GdalConst {
   public static readonly int CPLE_AssertionFailed = GdalConstPINVOKE.CPLE_AssertionFailed_get();
   public static readonly int CPLE_NoWriteAccess = GdalConstPINVOKE.CPLE_NoWriteAccess_get();
   public static readonly int CPLE_UserInterrupt = GdalConstPINVOKE.CPLE_UserInterrupt_get();
+  public static readonly int OF_ALL = GdalConstPINVOKE.OF_ALL_get();
+  public static readonly int OF_RASTER = GdalConstPINVOKE.OF_RASTER_get();
+  public static readonly int OF_VECTOR = GdalConstPINVOKE.OF_VECTOR_get();
+  public static readonly int OF_READONLY = GdalConstPINVOKE.OF_READONLY_get();
+  public static readonly int OF_UPDATE = GdalConstPINVOKE.OF_UPDATE_get();
+  public static readonly int OF_SHARED = GdalConstPINVOKE.OF_SHARED_get();
+  public static readonly int OF_VERBOSE_ERROR = GdalConstPINVOKE.OF_VERBOSE_ERROR_get();
   public static readonly string GDAL_DMD_LONGNAME = GdalConstPINVOKE.GDAL_DMD_LONGNAME_get();
   public static readonly string GDAL_DMD_HELPTOPIC = GdalConstPINVOKE.GDAL_DMD_HELPTOPIC_get();
   public static readonly string GDAL_DMD_MIMETYPE = GdalConstPINVOKE.GDAL_DMD_MIMETYPE_get();
   public static readonly string GDAL_DMD_EXTENSION = GdalConstPINVOKE.GDAL_DMD_EXTENSION_get();
+  public static readonly string GDAL_DMD_EXTENSIONS = GdalConstPINVOKE.GDAL_DMD_EXTENSIONS_get();
+  public static readonly string DMD_CONNECTION_PREFIX = GdalConstPINVOKE.DMD_CONNECTION_PREFIX_get();
   public static readonly string GDAL_DMD_CREATIONOPTIONLIST = GdalConstPINVOKE.GDAL_DMD_CREATIONOPTIONLIST_get();
   public static readonly string GDAL_DMD_CREATIONDATATYPES = GdalConstPINVOKE.GDAL_DMD_CREATIONDATATYPES_get();
+  public static readonly string GDAL_DMD_CREATIONFIELDDATATYPES = GdalConstPINVOKE.GDAL_DMD_CREATIONFIELDDATATYPES_get();
   public static readonly string GDAL_DMD_SUBDATASETS = GdalConstPINVOKE.GDAL_DMD_SUBDATASETS_get();
+  public static readonly string GDAL_DCAP_OPEN = GdalConstPINVOKE.GDAL_DCAP_OPEN_get();
   public static readonly string GDAL_DCAP_CREATE = GdalConstPINVOKE.GDAL_DCAP_CREATE_get();
   public static readonly string GDAL_DCAP_CREATECOPY = GdalConstPINVOKE.GDAL_DCAP_CREATECOPY_get();
   public static readonly string GDAL_DCAP_VIRTUALIO = GdalConstPINVOKE.GDAL_DCAP_VIRTUALIO_get();
+  public static readonly string DCAP_RASTER = GdalConstPINVOKE.DCAP_RASTER_get();
+  public static readonly string DCAP_VECTOR = GdalConstPINVOKE.DCAP_VECTOR_get();
+  public static readonly string DCAP_NOTNULL_FIELDS = GdalConstPINVOKE.DCAP_NOTNULL_FIELDS_get();
+  public static readonly string DCAP_DEFAULT_FIELDS = GdalConstPINVOKE.DCAP_DEFAULT_FIELDS_get();
+  public static readonly string DCAP_NOTNULL_GEOMFIELDS = GdalConstPINVOKE.DCAP_NOTNULL_GEOMFIELDS_get();
   public static readonly int CPLES_BackslashQuotable = GdalConstPINVOKE.CPLES_BackslashQuotable_get();
   public static readonly int CPLES_XML = GdalConstPINVOKE.CPLES_XML_get();
   public static readonly int CPLES_URL = GdalConstPINVOKE.CPLES_URL_get();
diff --git a/swig/csharp/const/GdalConstPINVOKE.cs b/swig/csharp/const/GdalConstPINVOKE.cs
index 58562b5..2178287 100644
--- a/swig/csharp/const/GdalConstPINVOKE.cs
+++ b/swig/csharp/const/GdalConstPINVOKE.cs
@@ -240,6 +240,30 @@ class GdalConstPINVOKE {
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GF_Write_get")]
   public static extern int GF_Write_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_NearestNeighbour_get")]
+  public static extern int GRIORA_NearestNeighbour_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Bilinear_get")]
+  public static extern int GRIORA_Bilinear_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Cubic_get")]
+  public static extern int GRIORA_Cubic_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_CubicSpline_get")]
+  public static extern int GRIORA_CubicSpline_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Lanczos_get")]
+  public static extern int GRIORA_Lanczos_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Average_get")]
+  public static extern int GRIORA_Average_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Mode_get")]
+  public static extern int GRIORA_Mode_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GRIORA_Gauss_get")]
+  public static extern int GRIORA_Gauss_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GCI_Undefined_get")]
   public static extern int GCI_Undefined_get();
 
@@ -384,6 +408,27 @@ class GdalConstPINVOKE {
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_CPLE_UserInterrupt_get")]
   public static extern int CPLE_UserInterrupt_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_ALL_get")]
+  public static extern int OF_ALL_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_RASTER_get")]
+  public static extern int OF_RASTER_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_VECTOR_get")]
+  public static extern int OF_VECTOR_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_READONLY_get")]
+  public static extern int OF_READONLY_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_UPDATE_get")]
+  public static extern int OF_UPDATE_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_SHARED_get")]
+  public static extern int OF_SHARED_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_OF_VERBOSE_ERROR_get")]
+  public static extern int OF_VERBOSE_ERROR_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_LONGNAME_get")]
   public static extern string GDAL_DMD_LONGNAME_get();
 
@@ -396,15 +441,27 @@ class GdalConstPINVOKE {
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_EXTENSION_get")]
   public static extern string GDAL_DMD_EXTENSION_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_EXTENSIONS_get")]
+  public static extern string GDAL_DMD_EXTENSIONS_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DMD_CONNECTION_PREFIX_get")]
+  public static extern string DMD_CONNECTION_PREFIX_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_CREATIONOPTIONLIST_get")]
   public static extern string GDAL_DMD_CREATIONOPTIONLIST_get();
 
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_CREATIONDATATYPES_get")]
   public static extern string GDAL_DMD_CREATIONDATATYPES_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_CREATIONFIELDDATATYPES_get")]
+  public static extern string GDAL_DMD_CREATIONFIELDDATATYPES_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DMD_SUBDATASETS_get")]
   public static extern string GDAL_DMD_SUBDATASETS_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DCAP_OPEN_get")]
+  public static extern string GDAL_DCAP_OPEN_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DCAP_CREATE_get")]
   public static extern string GDAL_DCAP_CREATE_get();
 
@@ -414,6 +471,21 @@ class GdalConstPINVOKE {
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_GDAL_DCAP_VIRTUALIO_get")]
   public static extern string GDAL_DCAP_VIRTUALIO_get();
 
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DCAP_RASTER_get")]
+  public static extern string DCAP_RASTER_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DCAP_VECTOR_get")]
+  public static extern string DCAP_VECTOR_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DCAP_NOTNULL_FIELDS_get")]
+  public static extern string DCAP_NOTNULL_FIELDS_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DCAP_DEFAULT_FIELDS_get")]
+  public static extern string DCAP_DEFAULT_FIELDS_get();
+
+  [DllImport("gdalconst_wrap", EntryPoint="CSharp_DCAP_NOTNULL_GEOMFIELDS_get")]
+  public static extern string DCAP_NOTNULL_GEOMFIELDS_get();
+
   [DllImport("gdalconst_wrap", EntryPoint="CSharp_CPLES_BackslashQuotable_get")]
   public static extern int CPLES_BackslashQuotable_get();
 
diff --git a/swig/csharp/const/gdalconst_wrap.c b/swig/csharp/const/gdalconst_wrap.c
index 5b87bab..0ad634a 100644
--- a/swig/csharp/const/gdalconst_wrap.c
+++ b/swig/csharp/const/gdalconst_wrap.c
@@ -436,6 +436,86 @@ SWIGEXPORT int SWIGSTDCALL CSharp_GF_Write_get() {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_NearestNeighbour_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_NearestNeighbour);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Bilinear_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Bilinear);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Cubic_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Cubic);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_CubicSpline_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_CubicSpline);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Lanczos_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Lanczos);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Average_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Average);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Mode_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Mode);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GRIORA_Gauss_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GRIORA_Gauss);
+  jresult = result; 
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_GCI_Undefined_get() {
   int jresult ;
   int result;
@@ -916,6 +996,76 @@ SWIGEXPORT int SWIGSTDCALL CSharp_CPLE_UserInterrupt_get() {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_ALL_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_ALL);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_RASTER_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_RASTER);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_VECTOR_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_VECTOR);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_READONLY_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_READONLY);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_UPDATE_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_UPDATE);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_SHARED_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_SHARED);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OF_VERBOSE_ERROR_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(GDAL_OF_VERBOSE_ERROR);
+  jresult = result; 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_LONGNAME_get() {
   char * jresult ;
   char *result = 0 ;
@@ -956,6 +1106,26 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_EXTENSION_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_EXTENSIONS_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("DMD_EXTENSIONS");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_DMD_CONNECTION_PREFIX_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("DMD_CONNECTION_PREFIX");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_CREATIONOPTIONLIST_get() {
   char * jresult ;
   char *result = 0 ;
@@ -976,6 +1146,16 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_CREATIONDATATYPES_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_CREATIONFIELDDATATYPES_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("DMD_CREATIONFIELDDATATYPES");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_SUBDATASETS_get() {
   char * jresult ;
   char *result = 0 ;
@@ -986,6 +1166,16 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DMD_SUBDATASETS_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DCAP_OPEN_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("DCAP_OPEN");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DCAP_CREATE_get() {
   char * jresult ;
   char *result = 0 ;
@@ -1016,6 +1206,56 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_GDAL_DCAP_VIRTUALIO_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_DCAP_RASTER_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("GDAL_DCAP_RASTER");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_DCAP_VECTOR_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("GDAL_DCAP_VECTOR");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_DCAP_NOTNULL_FIELDS_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("GDAL_DCAP_NOTNULL_FIELDS");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_DCAP_DEFAULT_FIELDS_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("GDAL_DCAP_DEFAULT_FIELDS");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_DCAP_NOTNULL_GEOMFIELDS_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("GDAL_DCAP_NOTNULL_GEOMFIELDS");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_CPLES_BackslashQuotable_get() {
   int jresult ;
   int result;
diff --git a/swig/csharp/gdal/Band.cs b/swig/csharp/gdal/Band.cs
index 1a9f508..a74e351 100644
--- a/swig/csharp/gdal/Band.cs
+++ b/swig/csharp/gdal/Band.cs
@@ -207,6 +207,13 @@ public class Band : MajorObject {
     } 
   }
 
+  public Dataset GetDataset() {
+    IntPtr cPtr = GdalPINVOKE.Band_GetDataset(swigCPtr);
+    Dataset ret = (cPtr == IntPtr.Zero) ? null : new Dataset(cPtr, false, ThisOwn_false());
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public int GetBand() {
     int ret = GdalPINVOKE.Band_GetBand(swigCPtr);
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
diff --git a/swig/csharp/gdal/Dataset.cs b/swig/csharp/gdal/Dataset.cs
index 9ef3849..5523b51 100644
--- a/swig/csharp/gdal/Dataset.cs
+++ b/swig/csharp/gdal/Dataset.cs
@@ -389,6 +389,24 @@ public CPLErr SetGCPs(GCP[] pGCPs, string pszGCPProjection) {
         return ret;
 }
 
+  public int StartTransaction(int force) {
+    int ret = GdalPINVOKE.Dataset_StartTransaction(swigCPtr, force);
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public int CommitTransaction() {
+    int ret = GdalPINVOKE.Dataset_CommitTransaction(swigCPtr);
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public int RollbackTransaction() {
+    int ret = GdalPINVOKE.Dataset_RollbackTransaction(swigCPtr);
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public CPLErr ReadRaster(int xOff, int yOff, int xSize, int ySize, IntPtr buffer, int buf_xSize, int buf_ySize, DataType buf_type, int bandCount, int[] bandMap, int pixelSpace, int lineSpace, int bandSpace) {
     CPLErr ret = (CPLErr)GdalPINVOKE.Dataset_ReadRaster(swigCPtr, xOff, yOff, xSize, ySize, buffer, buf_xSize, buf_ySize, (int)buf_type, bandCount, bandMap, pixelSpace, lineSpace, bandSpace);
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
diff --git a/swig/csharp/gdal/Driver.cs b/swig/csharp/gdal/Driver.cs
index 900db9c..5bec748 100644
--- a/swig/csharp/gdal/Driver.cs
+++ b/swig/csharp/gdal/Driver.cs
@@ -97,20 +97,20 @@ public class Driver : MajorObject {
     return ret;
   }
 
-  public int Delete(string utf8_path) {
-    int ret = GdalPINVOKE.Driver_Delete(swigCPtr, Gdal.StringToUtf8Bytes(utf8_path));
+  public CPLErr Delete(string utf8_path) {
+    CPLErr ret = (CPLErr)GdalPINVOKE.Driver_Delete(swigCPtr, Gdal.StringToUtf8Bytes(utf8_path));
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
     return ret;
   }
 
-  public int Rename(string newName, string oldName) {
-    int ret = GdalPINVOKE.Driver_Rename(swigCPtr, newName, oldName);
+  public CPLErr Rename(string newName, string oldName) {
+    CPLErr ret = (CPLErr)GdalPINVOKE.Driver_Rename(swigCPtr, newName, oldName);
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
     return ret;
   }
 
-  public int CopyFiles(string newName, string oldName) {
-    int ret = GdalPINVOKE.Driver_CopyFiles(swigCPtr, newName, oldName);
+  public CPLErr CopyFiles(string newName, string oldName) {
+    CPLErr ret = (CPLErr)GdalPINVOKE.Driver_CopyFiles(swigCPtr, newName, oldName);
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
     return ret;
   }
diff --git a/swig/csharp/gdal/Gdal.cs b/swig/csharp/gdal/Gdal.cs
index d72b11d..83e9af6 100644
--- a/swig/csharp/gdal/Gdal.cs
+++ b/swig/csharp/gdal/Gdal.cs
@@ -570,10 +570,10 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   }
 
   public static int InvGeoTransform(double[] gt_in, double[] gt_out) {
-    int ret = GdalPINVOKE.InvGeoTransform(gt_in, gt_out);
+    int res = GdalPINVOKE.InvGeoTransform(gt_in, gt_out);
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
-    return ret;
-  }
+    return res;
+}
 
   public static string VersionInfo(string request) {
     string ret = GdalPINVOKE.VersionInfo(request);
@@ -675,6 +675,12 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
     return ret;
   }
 
+  public static string GetJPEG2000StructureAsString(string pszFilename, string[] options) {
+    string ret = GdalPINVOKE.GetJPEG2000StructureAsString(pszFilename, (options != null)? new GdalPINVOKE.StringListMarshal(options)._ar : null);
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public static int GetDriverCount() {
     int ret = GdalPINVOKE.GetDriverCount();
     if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
@@ -702,6 +708,13 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
     return ret;
   }
 
+  public static Dataset OpenEx(string utf8_path, uint nOpenFlags, string[] allowed_drivers, string[] open_options, string[] sibling_files) {
+    IntPtr cPtr = GdalPINVOKE.OpenEx(Gdal.StringToUtf8Bytes(utf8_path), nOpenFlags, (allowed_drivers != null)? new GdalPINVOKE.StringListMarshal(allowed_drivers)._ar : null, (open_options != null)? new GdalPINVOKE.StringListMarshal(open_options)._ar : null, (sibling_files != null)? new GdalPINVOKE.StringListMarshal(sibling_files)._ar : null);
+    Dataset ret = (cPtr == IntPtr.Zero) ? null : new Dataset(cPtr, true, ThisOwn_true());
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public static Dataset OpenShared(string utf8_path, Access eAccess) {
     IntPtr cPtr = GdalPINVOKE.OpenShared(Gdal.StringToUtf8Bytes(utf8_path), (int)eAccess);
     Dataset ret = (cPtr == IntPtr.Zero) ? null : new Dataset(cPtr, true, ThisOwn_true());
diff --git a/swig/csharp/gdal/GdalPINVOKE.cs b/swig/csharp/gdal/GdalPINVOKE.cs
index 362b210..67882f4 100644
--- a/swig/csharp/gdal/GdalPINVOKE.cs
+++ b/swig/csharp/gdal/GdalPINVOKE.cs
@@ -673,6 +673,15 @@ class GdalPINVOKE {
   [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_GetFileList")]
   public static extern IntPtr Dataset_GetFileList(HandleRef jarg1);
 
+  [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_StartTransaction")]
+  public static extern int Dataset_StartTransaction(HandleRef jarg1, int jarg2);
+
+  [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_CommitTransaction")]
+  public static extern int Dataset_CommitTransaction(HandleRef jarg1);
+
+  [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_RollbackTransaction")]
+  public static extern int Dataset_RollbackTransaction(HandleRef jarg1);
+
   [DllImport("gdal_wrap", EntryPoint="CSharp_Dataset_ReadRaster")]
   public static extern int Dataset_ReadRaster(HandleRef jarg1, int jarg2, int jarg3, int jarg4, int jarg5, IntPtr jarg6, int jarg7, int jarg8, int jarg9, int jarg10, int[] jarg11, int jarg12, int jarg13, int jarg14);
 
@@ -706,6 +715,9 @@ class GdalPINVOKE {
   [DllImport("gdal_wrap", EntryPoint="CSharp_Band_DataType_get")]
   public static extern int Band_DataType_get(HandleRef jarg1);
 
+  [DllImport("gdal_wrap", EntryPoint="CSharp_Band_GetDataset")]
+  public static extern IntPtr Band_GetDataset(HandleRef jarg1);
+
   [DllImport("gdal_wrap", EntryPoint="CSharp_Band_GetBand")]
   public static extern int Band_GetBand(HandleRef jarg1);
 
@@ -931,6 +943,9 @@ class GdalPINVOKE {
   [DllImport("gdal_wrap", EntryPoint="CSharp_RasterAttributeTable_ChangesAreWrittenToFile")]
   public static extern int RasterAttributeTable_ChangesAreWrittenToFile(HandleRef jarg1);
 
+  [DllImport("gdal_wrap", EntryPoint="CSharp_RasterAttributeTable_DumpReadable")]
+  public static extern void RasterAttributeTable_DumpReadable(HandleRef jarg1);
+
   [DllImport("gdal_wrap", EntryPoint="CSharp_ComputeMedianCutPCT")]
   public static extern int ComputeMedianCutPCT(HandleRef jarg1, HandleRef jarg2, HandleRef jarg3, int jarg4, HandleRef jarg5, Gdal.GDALProgressFuncDelegate jarg6, string jarg7);
 
@@ -1042,6 +1057,9 @@ class GdalPINVOKE {
   [DllImport("gdal_wrap", EntryPoint="CSharp_SerializeXMLTree")]
   public static extern string SerializeXMLTree(HandleRef jarg1);
 
+  [DllImport("gdal_wrap", EntryPoint="CSharp_GetJPEG2000StructureAsString")]
+  public static extern string GetJPEG2000StructureAsString(string jarg1, IntPtr[] jarg2);
+
   [DllImport("gdal_wrap", EntryPoint="CSharp_GetDriverCount")]
   public static extern int GetDriverCount();
 
@@ -1054,6 +1072,9 @@ class GdalPINVOKE {
   [DllImport("gdal_wrap", EntryPoint="CSharp_Open")]
   public static extern IntPtr Open(byte[] jarg1, int jarg2);
 
+  [DllImport("gdal_wrap", EntryPoint="CSharp_OpenEx")]
+  public static extern IntPtr OpenEx(byte[] jarg1, uint jarg2, IntPtr[] jarg3, IntPtr[] jarg4, IntPtr[] jarg5);
+
   [DllImport("gdal_wrap", EntryPoint="CSharp_OpenShared")]
   public static extern IntPtr OpenShared(byte[] jarg1, int jarg2);
 
diff --git a/swig/csharp/gdal/RIOResampleAlg.cs b/swig/csharp/gdal/RIOResampleAlg.cs
new file mode 100644
index 0000000..5bca742
--- /dev/null
+++ b/swig/csharp/gdal/RIOResampleAlg.cs
@@ -0,0 +1,22 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.7
+ *
+ * Do not make changes to this file unless you know what you are doing--modify
+ * the SWIG interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+namespace OSGeo.GDAL {
+
+public enum RIOResampleAlg {
+  GRIORA_NearestNeighbour = 0,
+  GRIORA_Bilinear = 1,
+  GRIORA_Cubic = 2,
+  GRIORA_CubicSpline = 3,
+  GRIORA_Lanczos = 4,
+  GRIORA_Average = 5,
+  GRIORA_Mode = 6,
+  GRIORA_Gauss = 7
+}
+
+}
diff --git a/swig/csharp/gdal/RasterAttributeTable.cs b/swig/csharp/gdal/RasterAttributeTable.cs
index 42986f6..b81cda1 100644
--- a/swig/csharp/gdal/RasterAttributeTable.cs
+++ b/swig/csharp/gdal/RasterAttributeTable.cs
@@ -183,6 +183,11 @@ public class RasterAttributeTable : IDisposable {
     return ret;
   }
 
+  public void DumpReadable() {
+    GdalPINVOKE.RasterAttributeTable_DumpReadable(swigCPtr);
+    if (GdalPINVOKE.SWIGPendingException.Pending) throw GdalPINVOKE.SWIGPendingException.Retrieve();
+  }
+
 }
 
 }
diff --git a/swig/csharp/gdal/gdal_wrap.cpp b/swig/csharp/gdal/gdal_wrap.cpp
index 10d24cc..4db25fc 100644
--- a/swig/csharp/gdal/gdal_wrap.cpp
+++ b/swig/csharp/gdal/gdal_wrap.cpp
@@ -358,6 +358,7 @@ typedef void GDALRasterAttributeTableShadow;
 typedef void GDALTransformerInfoShadow;
 typedef void GDALAsyncReaderShadow;
 
+
 /* use this to not return the int returned by GDAL */
 typedef int RETURN_NONE;
 
@@ -463,6 +464,14 @@ int wrapper_HasThreadSupport()
     return strcmp(CPLGetThreadingModel(), "stub") != 0;
 }
 
+
+VSILFILE   *wrapper_VSIFOpenL( const char *utf8_path, const char *pszMode )
+{
+    if (!pszMode) /* would lead to segfault */
+        pszMode = "r";
+    return VSIFOpenL( utf8_path, pszMode );
+}
+
 SWIGINTERN CPLXMLNode *new_CPLXMLNode__SWIG_0(char const *pszString){
         return CPLParseXMLString( pszString );     
     }
@@ -560,13 +569,13 @@ SWIGINTERN GDALDatasetShadow *GDALDriverShadow_CreateCopy(GDALDriverShadow *self
                                                                     callback_data );
     return ds;
   }
-SWIGINTERN int GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
+SWIGINTERN CPLErr GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
     return GDALDeleteDataset( self, utf8_path );
   }
-SWIGINTERN int GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALRenameDataset( self, newName, oldName );
   }
-SWIGINTERN int GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALCopyDatasetFiles( self, newName, oldName );
   }
 SWIGINTERN int GDALDriverShadow_Register(GDALDriverShadow *self){
@@ -655,7 +664,6 @@ void GDAL_GCP_Id_set( GDAL_GCP *gcp, const char * pszId ) {
 }
 
 
-
 /* Duplicate, but transposed names for C# because 
 *  the C# module outputs backwards names
 */
@@ -707,12 +715,11 @@ void GDAL_GCP_set_Id( GDAL_GCP *gcp, const char * pszId ) {
 }
 
 
-
 /* Returned size is in bytes or 0 if an error occured */
 static
 GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
                                 int nBands, int* bandMap, int nBandMapArrayLength,
-                                int nPixelSpace, int nLineSpace, int nBandSpace,
+                                GIntBig nPixelSpace, GIntBig nLineSpace, GIntBig nBandSpace,
                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
@@ -720,7 +727,7 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -749,11 +756,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -764,11 +766,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nBandSpace == 0 )
     {
-        if (nLineSpace > MAX_INT32 / buf_ysize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nBandSpace");
-            return 0;
-        }
         nBandSpace = nLineSpace * buf_ysize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nBandSpace % nPixelSize) != 0 )
@@ -925,6 +922,38 @@ SWIGINTERN CPLErr GDALDatasetShadow_CreateMaskBand(GDALDatasetShadow *self,int n
 SWIGINTERN char **GDALDatasetShadow_GetFileList(GDALDatasetShadow *self){
     return GDALGetFileList( self );
   }
+SWIGINTERN OGRErr GDALDatasetShadow_StartTransaction(GDALDatasetShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+
+static char const *
+OGRErrMessages( int rc ) {
+  switch( rc ) {
+  case 0:
+    return "OGR Error %d: None";
+  case 1:
+    return "OGR Error %d: Not enough data";
+  case 2:
+    return "OGR Error %d: Unsupported geometry type";
+  case 3:
+    return "OGR Error %d: Unsupported operation";
+  case 4:
+    return "OGR Error %d: Corrupt data";
+  case 5:
+    return "OGR Error %d: General Error";
+  case 6:
+    return "OGR Error %d: Unsupported SRS";
+  default:
+    return "OGR Error %d: Unknown";
+  }
+}
+
+SWIGINTERN OGRErr GDALDatasetShadow_CommitTransaction(GDALDatasetShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_RollbackTransaction(GDALDatasetShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
 SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster(GDALDatasetShadow *self,int xOff,int yOff,int xSize,int ySize,void *buffer,int buf_xSize,int buf_ySize,GDALDataType buf_type,int bandCount,int *bandMap,int pixelSpace,int lineSpace,int bandSpace){
        return GDALDatasetRasterIO( self, GF_Read, xOff, yOff, xSize, ySize, 
 		        buffer, buf_xSize, buf_ySize, buf_type, bandCount, 
@@ -969,15 +998,15 @@ int GDALDatasetShadow_RasterCount_get( GDALDatasetShadow *h ) {
 /* Returned size is in bytes or 0 if an error occured */
 static
 GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
-                             int nPixelSpace, int nLineSpace,
-                             int bSpacingShouldBeMultipleOfPixelSize )
+                                 GIntBig nPixelSpace, GIntBig nLineSpace,
+                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
     const GIntBig MAX_INT = (((GIntBig)0x7fffffff) << 32) | 0xffffffff;
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -1006,11 +1035,6 @@ GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -1029,6 +1053,9 @@ GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
     return nRet;
 }
 
+SWIGINTERN GDALDatasetShadow *GDALRasterBandShadow_GetDataset(GDALRasterBandShadow *self){
+    return (GDALDatasetShadow*) GDALGetBandDataset(self);
+  }
 SWIGINTERN int GDALRasterBandShadow_GetBand(GDALRasterBandShadow *self){
     return GDALGetBandNumber(self);
   }
@@ -1283,6 +1310,9 @@ SWIGINTERN int GDALRasterAttributeTableShadow_GetRowOfValue(GDALRasterAttributeT
 SWIGINTERN int GDALRasterAttributeTableShadow_ChangesAreWrittenToFile(GDALRasterAttributeTableShadow *self){
         return GDALRATChangesAreWrittenToFile( self );
     }
+SWIGINTERN void GDALRasterAttributeTableShadow_DumpReadable(GDALRasterAttributeTableShadow *self){
+        GDALRATDumpReadable( self, NULL );
+    }
 
 #include "gdalgrid.h"
 
@@ -1610,6 +1640,17 @@ void wrapper_GDALSetCacheMax(int nBytes)
 }
 
 
+retStringAndCPLFree *GetJPEG2000StructureAsString( const char* pszFilename, char** options = NULL )
+{
+    CPLXMLNode* psNode = GDALGetJPEG2000Structure(pszFilename, options);
+    if( psNode == NULL )
+        return NULL;
+    char* pszXML = CPLSerializeXMLTree(psNode);
+    CPLDestroyXMLNode(psNode);
+    return pszXML;
+}
+
+
 int GetDriverCount() {
   return GDALGetDriverCount();
 }
@@ -1638,6 +1679,22 @@ GDALDatasetShadow* Open( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly
 }
 
 
+GDALDatasetShadow* OpenEx( char const* utf8_path, unsigned int nOpenFlags = 0,
+                           char** allowed_drivers = NULL, char** open_options = NULL,
+                           char** sibling_files = NULL ) {
+  CPLErrorReset();
+  GDALDatasetShadow *ds = GDALOpenEx( utf8_path, nOpenFlags, allowed_drivers,
+                                      open_options, sibling_files );
+  if( ds != NULL && CPLGetLastErrorType() == CE_Failure )
+  {
+      if ( GDALDereferenceDataset( ds ) <= 0 )
+          GDALClose(ds);
+      ds = NULL;
+  }
+  return (GDALDatasetShadow*) ds;
+}
+
+
 GDALDatasetShadow* OpenShared( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly ) {
   CPLErrorReset();
   GDALDatasetShadow *ds = GDALOpenShared( utf8_path, eAccess );
@@ -2785,7 +2842,7 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_VSIFOpenL(char * jarg1, char * jarg2) {
   }
   {
     CPLErrorReset();
-    result = (VSILFILE *)VSIFOpenL((char const *)arg1,(char const *)arg2);
+    result = (VSILFILE *)wrapper_VSIFOpenL((char const *)arg1,(char const *)arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -4112,7 +4169,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_Delete(void * jarg1, char * jarg2) {
   int jresult ;
   GDALDriverShadow *arg1 = (GDALDriverShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  int result;
+  CPLErr result;
   
   arg1 = (GDALDriverShadow *)jarg1; 
   arg2 = (char *)jarg2; 
@@ -4125,7 +4182,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_Delete(void * jarg1, char * jarg2) {
   }
   {
     CPLErrorReset();
-    result = (int)GDALDriverShadow_Delete(arg1,(char const *)arg2);
+    result = (CPLErr)GDALDriverShadow_Delete(arg1,(char const *)arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -4155,7 +4212,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_Rename(void * jarg1, char * jarg2, char
   GDALDriverShadow *arg1 = (GDALDriverShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   char *arg3 = (char *) 0 ;
-  int result;
+  CPLErr result;
   
   arg1 = (GDALDriverShadow *)jarg1; 
   arg2 = (char *)jarg2; 
@@ -4176,7 +4233,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_Rename(void * jarg1, char * jarg2, char
   }
   {
     CPLErrorReset();
-    result = (int)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
+    result = (CPLErr)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -4206,7 +4263,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_CopyFiles(void * jarg1, char * jarg2, c
   GDALDriverShadow *arg1 = (GDALDriverShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   char *arg3 = (char *) 0 ;
-  int result;
+  CPLErr result;
   
   arg1 = (GDALDriverShadow *)jarg1; 
   arg2 = (char *)jarg2; 
@@ -4227,7 +4284,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Driver_CopyFiles(void * jarg1, char * jarg2, c
   }
   {
     CPLErrorReset();
-    result = (int)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
+    result = (CPLErr)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -6873,6 +6930,128 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_Dataset_GetFileList(void * jarg1) {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_Dataset_StartTransaction(void * jarg1, int jarg2) {
+  int jresult ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 = (int) FALSE ;
+  OGRErr result;
+  
+  arg1 = (GDALDatasetShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)GDALDatasetShadow_StartTransaction(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_Dataset_CommitTransaction(void * jarg1) {
+  int jresult ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  OGRErr result;
+  
+  arg1 = (GDALDatasetShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)GDALDatasetShadow_CommitTransaction(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_Dataset_RollbackTransaction(void * jarg1) {
+  int jresult ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  OGRErr result;
+  
+  arg1 = (GDALDatasetShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)GDALDatasetShadow_RollbackTransaction(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_Dataset_ReadRaster(void * jarg1, int jarg2, int jarg3, int jarg4, int jarg5, void * jarg6, int jarg7, int jarg8, int jarg9, int jarg10, void * jarg11, int jarg12, int jarg13, int jarg14) {
   int jresult ;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
@@ -7306,6 +7485,39 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Band_DataType_get(void * jarg1) {
 }
 
 
+SWIGEXPORT void * SWIGSTDCALL CSharp_Band_GetDataset(void * jarg1) {
+  void * jresult ;
+  GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
+  GDALDatasetShadow *result = 0 ;
+  
+  arg1 = (GDALRasterBandShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (GDALDatasetShadow *)GDALRasterBandShadow_GetDataset(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_Band_GetBand(void * jarg1) {
   int jresult ;
   GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
@@ -10061,6 +10273,35 @@ SWIGEXPORT int SWIGSTDCALL CSharp_RasterAttributeTable_ChangesAreWrittenToFile(v
 }
 
 
+SWIGEXPORT void SWIGSTDCALL CSharp_RasterAttributeTable_DumpReadable(void * jarg1) {
+  GDALRasterAttributeTableShadow *arg1 = (GDALRasterAttributeTableShadow *) 0 ;
+  
+  arg1 = (GDALRasterAttributeTableShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    GDALRasterAttributeTableShadow_DumpReadable(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_ComputeMedianCutPCT(void * jarg1, void * jarg2, void * jarg3, int jarg4, void * jarg5, void * jarg6, void * jarg7) {
   int jresult ;
   GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
@@ -11127,7 +11368,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_InvGeoTransform(void * jarg1, void * jarg2) {
   int jresult ;
   double *arg1 ;
   double *arg2 ;
-  int result;
+  RETURN_NONE result;
   
   {
     /* %typemap(in) (double argin[ANY]) */
@@ -11139,7 +11380,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_InvGeoTransform(void * jarg1, void * jarg2) {
   }
   {
     CPLErrorReset();
-    result = (int)GDALInvGeoTransform(arg1,arg2);
+    result = GDALInvGeoTransform(arg1,arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -11718,6 +11959,59 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_SerializeXMLTree(void * jarg1) {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_GetJPEG2000StructureAsString(char * jarg1, void * jarg2) {
+  char * jresult ;
+  char *arg1 = (char *) 0 ;
+  char **arg2 = (char **) NULL ;
+  retStringAndCPLFree *result = 0 ;
+  
+  arg1 = (char *)jarg1; 
+  arg2 = (char **)jarg2; 
+  {
+    if (!arg1) {
+      {
+        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
+      };
+    }
+  }
+  {
+    CPLErrorReset();
+    result = (retStringAndCPLFree *)GetJPEG2000StructureAsString((char const *)arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  
+  /* %typemap(out) (retStringAndCPLFree*) */
+  if(result)
+  {
+    jresult = SWIG_csharp_string_callback((const char *)result);
+    CPLFree(result);
+  }
+  else
+  {
+    jresult = NULL;
+  }
+  
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_GetDriverCount() {
   int jresult ;
   int result;
@@ -11864,6 +12158,54 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_Open(char * jarg1, int jarg2) {
 }
 
 
+SWIGEXPORT void * SWIGSTDCALL CSharp_OpenEx(char * jarg1, unsigned int jarg2, void * jarg3, void * jarg4, void * jarg5) {
+  void * jresult ;
+  char *arg1 = (char *) 0 ;
+  unsigned int arg2 = (unsigned int) 0 ;
+  char **arg3 = (char **) NULL ;
+  char **arg4 = (char **) NULL ;
+  char **arg5 = (char **) NULL ;
+  GDALDatasetShadow *result = 0 ;
+  
+  arg1 = (char *)jarg1; 
+  arg2 = (unsigned int)jarg2; 
+  arg3 = (char **)jarg3; 
+  arg4 = (char **)jarg4; 
+  arg5 = (char **)jarg5; 
+  {
+    if (!arg1) {
+      {
+        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
+      };
+    }
+  }
+  {
+    CPLErrorReset();
+    result = (GDALDatasetShadow *)OpenEx((char const *)arg1,arg2,arg3,arg4,arg5);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
 SWIGEXPORT void * SWIGSTDCALL CSharp_OpenShared(char * jarg1, int jarg2) {
   void * jresult ;
   char *arg1 = (char *) 0 ;
diff --git a/swig/csharp/makefile.vc b/swig/csharp/makefile.vc
index c05c9c8..3a6b773 100644
--- a/swig/csharp/makefile.vc
+++ b/swig/csharp/makefile.vc
@@ -8,7 +8,7 @@
 #  - Run the VCVARS32.BAT script to initialize the VC++ environment variables
 #  - Start the build with:  nmake /f makefile.vc
 #
-# $Id: makefile.vc 26521 2013-10-11 09:13:30Z tamas $
+# $Id: makefile.vc 28983 2015-04-23 21:46:56Z tamas $
 #
 
 GDAL_ROOT	=	..\..
@@ -132,6 +132,7 @@ samples:
     $(CSC) $(CSDEBUG) /r:gdal_csharp.dll /out:VSIMem.exe apps\VSIMem.cs
     $(CSC) $(CSDEBUG) /r:gdal_csharp.dll /r:System.Drawing.dll /out:GDALMemDataset.exe apps\GDALMemDataset.cs
 	$(CSC) $(CSDEBUG) /r:ogr_csharp.dll /r:osr_csharp.dll /out:OGRLayerAlg.exe apps\OGRLayerAlg.cs
+	$(CSC) $(CSDEBUG) /r:ogr_csharp.dll /r:osr_csharp.dll /out:OGRFeatureEdit.exe apps\OGRFeatureEdit.cs
     
 test:
 !IFDEF MONO
diff --git a/swig/csharp/ogr/DataSource.cs b/swig/csharp/ogr/DataSource.cs
index 3d87fde..1fe8a26 100644
--- a/swig/csharp/ogr/DataSource.cs
+++ b/swig/csharp/ogr/DataSource.cs
@@ -119,6 +119,11 @@ public class DataSource : IDisposable {
     return ret;
   }
 
+  public void FlushCache() {
+    OgrPINVOKE.DataSource_FlushCache(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
   public Layer CreateLayer(string name, OSGeo.OSR.SpatialReference srs, wkbGeometryType geom_type, string[] options) {
     IntPtr cPtr = OgrPINVOKE.DataSource_CreateLayer(swigCPtr, name, OSGeo.OSR.SpatialReference.getCPtr(srs), (int)geom_type, (options != null)? new OgrPINVOKE.StringListMarshal(options)._ar : null);
     Layer ret = (cPtr == IntPtr.Zero) ? null : new Layer(cPtr, false, ThisOwn_false());
@@ -177,6 +182,24 @@ public class DataSource : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
+  public int StartTransaction(int force) {
+    int ret = OgrPINVOKE.DataSource_StartTransaction(swigCPtr, force);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public int CommitTransaction() {
+    int ret = OgrPINVOKE.DataSource_CommitTransaction(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public int RollbackTransaction() {
+    int ret = OgrPINVOKE.DataSource_RollbackTransaction(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
 }
 
 }
diff --git a/swig/csharp/ogr/Feature.cs b/swig/csharp/ogr/Feature.cs
index 6b7f265..49dddd6 100644
--- a/swig/csharp/ogr/Feature.cs
+++ b/swig/csharp/ogr/Feature.cs
@@ -219,6 +219,18 @@ public class Feature : IDisposable {
     return ret;
   }
 
+  public long GetFieldAsInteger64(int id) {
+    long res = OgrPINVOKE.Feature_GetFieldAsInteger64__SWIG_0(swigCPtr, id);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return res;
+}
+
+  public long GetFieldAsInteger64(string name) {
+    long res = OgrPINVOKE.Feature_GetFieldAsInteger64__SWIG_1(swigCPtr, name);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return res;
+}
+
   public double GetFieldAsDouble(int id) {
     double ret = OgrPINVOKE.Feature_GetFieldAsDouble__SWIG_0(swigCPtr, id);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -231,8 +243,8 @@ public class Feature : IDisposable {
     return ret;
   }
 
-  public void GetFieldAsDateTime(int id, out int pnYear, out int pnMonth, out int pnDay, out int pnHour, out int pnMinute, out int pnSecond, out int pnTZFlag) {
-    OgrPINVOKE.Feature_GetFieldAsDateTime(swigCPtr, id, out pnYear, out pnMonth, out pnDay, out pnHour, out pnMinute, out pnSecond, out pnTZFlag);
+  public void GetFieldAsDateTime(int id, out int pnYear, out int pnMonth, out int pnDay, out int pnHour, out int pnMinute, out float pfSecond, out int pnTZFlag) {
+    OgrPINVOKE.Feature_GetFieldAsDateTime(swigCPtr, id, out pnYear, out pnMonth, out pnDay, out pnHour, out pnMinute, out pfSecond, out pnTZFlag);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
@@ -305,13 +317,13 @@ public class Feature : IDisposable {
     return ret;
   }
 
-  public int GetFID() {
-    int ret = OgrPINVOKE.Feature_GetFID(swigCPtr);
+  public long GetFID() {
+    long res = OgrPINVOKE.Feature_GetFID(swigCPtr);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
-    return ret;
-  }
+    return res;
+}
 
-  public int SetFID(int fid) {
+  public int SetFID(long fid) {
     int ret = OgrPINVOKE.Feature_SetFID(swigCPtr, fid);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
     return ret;
@@ -342,6 +354,11 @@ public class Feature : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
+  public void SetFieldInteger64(int id, long value) {
+    OgrPINVOKE.Feature_SetFieldInteger64(swigCPtr, id, value);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
   public void SetField(int id, int value) {
     OgrPINVOKE.Feature_SetField__SWIG_2(swigCPtr, id, value);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -362,12 +379,12 @@ public class Feature : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
-  public void SetField(int id, int year, int month, int day, int hour, int minute, int second, int tzflag) {
+  public void SetField(int id, int year, int month, int day, int hour, int minute, float second, int tzflag) {
     OgrPINVOKE.Feature_SetField__SWIG_6(swigCPtr, id, year, month, day, hour, minute, second, tzflag);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
-  public void SetField(string name, int year, int month, int day, int hour, int minute, int second, int tzflag) {
+  public void SetField(string name, int year, int month, int day, int hour, int minute, float second, int tzflag) {
     OgrPINVOKE.Feature_SetField__SWIG_7(swigCPtr, name, year, month, day, hour, minute, second, tzflag);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
@@ -432,6 +449,17 @@ public class Feature : IDisposable {
     return ret;
   }
 
+  public int Validate(int flags, int bEmitError) {
+    int ret = OgrPINVOKE.Feature_Validate(swigCPtr, flags, bEmitError);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public void FillUnsetWithDefault(int bNotNullableOnly, string[] options) {
+    OgrPINVOKE.Feature_FillUnsetWithDefault(swigCPtr, bNotNullableOnly, (options != null)? new OgrPINVOKE.StringListMarshal(options)._ar : null);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
 }
 
 }
diff --git a/swig/csharp/ogr/FieldDefn.cs b/swig/csharp/ogr/FieldDefn.cs
index a2e1775..3108beb 100644
--- a/swig/csharp/ogr/FieldDefn.cs
+++ b/swig/csharp/ogr/FieldDefn.cs
@@ -100,6 +100,17 @@ public class FieldDefn : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
+  public FieldSubType GetSubType() {
+    FieldSubType ret = (FieldSubType)OgrPINVOKE.FieldDefn_GetSubType(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public void SetSubType(FieldSubType type) {
+    OgrPINVOKE.FieldDefn_SetSubType(swigCPtr, (int)type);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
   public Justification GetJustify() {
     Justification ret = (Justification)OgrPINVOKE.FieldDefn_GetJustify(swigCPtr);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -156,6 +167,34 @@ public class FieldDefn : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
+  public int IsNullable() {
+    int ret = OgrPINVOKE.FieldDefn_IsNullable(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public void SetNullable(int bNullable) {
+    OgrPINVOKE.FieldDefn_SetNullable(swigCPtr, bNullable);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
+  public string GetDefault() {
+    string ret = OgrPINVOKE.FieldDefn_GetDefault(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public void SetDefault(string pszValue) {
+    OgrPINVOKE.FieldDefn_SetDefault(swigCPtr, pszValue);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
+  public int IsDefaultDriverSpecific() {
+    int ret = OgrPINVOKE.FieldDefn_IsDefaultDriverSpecific(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
 }
 
 }
diff --git a/swig/csharp/ogr/FieldSubType.cs b/swig/csharp/ogr/FieldSubType.cs
new file mode 100644
index 0000000..94bc656
--- /dev/null
+++ b/swig/csharp/ogr/FieldSubType.cs
@@ -0,0 +1,18 @@
+/* ----------------------------------------------------------------------------
+ * This file was automatically generated by SWIG (http://www.swig.org).
+ * Version 2.0.7
+ *
+ * Do not make changes to this file unless you know what you are doing--modify
+ * the SWIG interface file instead.
+ * ----------------------------------------------------------------------------- */
+
+namespace OSGeo.OGR {
+
+public enum FieldSubType {
+  OFSTNone = 0,
+  OFSTBoolean = 1,
+  OFSTInt16 = 2,
+  OFSTFloat32 = 3
+}
+
+}
diff --git a/swig/csharp/ogr/FieldType.cs b/swig/csharp/ogr/FieldType.cs
index e7f1310..bfb20d5 100644
--- a/swig/csharp/ogr/FieldType.cs
+++ b/swig/csharp/ogr/FieldType.cs
@@ -20,7 +20,9 @@ public enum FieldType {
   OFTBinary = 8,
   OFTDate = 9,
   OFTTime = 10,
-  OFTDateTime = 11
+  OFTDateTime = 11,
+  OFTInteger64 = 12,
+  OFTInteger64List = 13
 }
 
 }
diff --git a/swig/csharp/ogr/GeomFieldDefn.cs b/swig/csharp/ogr/GeomFieldDefn.cs
index 61dcc16..abd167d 100644
--- a/swig/csharp/ogr/GeomFieldDefn.cs
+++ b/swig/csharp/ogr/GeomFieldDefn.cs
@@ -123,6 +123,17 @@ public class GeomFieldDefn : IDisposable {
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
   }
 
+  public int IsNullable() {
+    int ret = OgrPINVOKE.GeomFieldDefn_IsNullable(swigCPtr);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public void SetNullable(int bNullable) {
+    OgrPINVOKE.GeomFieldDefn_SetNullable(swigCPtr, bNullable);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
 }
 
 }
diff --git a/swig/csharp/ogr/Geometry.cs b/swig/csharp/ogr/Geometry.cs
index 3b5935d..b46b3d7 100644
--- a/swig/csharp/ogr/Geometry.cs
+++ b/swig/csharp/ogr/Geometry.cs
@@ -122,6 +122,12 @@ public int ExportToWkb( byte[] buffer, wkbByteOrder byte_order ) {
     return ret;
   }
 
+  public int ExportToIsoWkt(out string argout) {
+    int ret = OgrPINVOKE.Geometry_ExportToIsoWkt(swigCPtr, out argout);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public string ExportToGML() {
     string ret = OgrPINVOKE.Geometry_ExportToGML__SWIG_0(swigCPtr);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -527,6 +533,33 @@ public int ExportToWkb( byte[] buffer, wkbByteOrder byte_order ) {
     return ret;
   }
 
+  public int HasCurveGeometry(int bLookForCircular) {
+    int ret = OgrPINVOKE.Geometry_HasCurveGeometry(swigCPtr, bLookForCircular);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public Geometry GetLinearGeometry(double dfMaxAngleStepSizeDegrees, string[] options) {
+    IntPtr cPtr = OgrPINVOKE.Geometry_GetLinearGeometry(swigCPtr, dfMaxAngleStepSizeDegrees, (options != null)? new OgrPINVOKE.StringListMarshal(options)._ar : null);
+    Geometry ret = (cPtr == IntPtr.Zero) ? null : new Geometry(cPtr, true, ThisOwn_true());
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public Geometry GetCurveGeometry(string[] options) {
+    IntPtr cPtr = OgrPINVOKE.Geometry_GetCurveGeometry(swigCPtr, (options != null)? new OgrPINVOKE.StringListMarshal(options)._ar : null);
+    Geometry ret = (cPtr == IntPtr.Zero) ? null : new Geometry(cPtr, true, ThisOwn_true());
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public Geometry Value(double dfDistance) {
+    IntPtr cPtr = OgrPINVOKE.Geometry_Value(swigCPtr, dfDistance);
+    Geometry ret = (cPtr == IntPtr.Zero) ? null : new Geometry(cPtr, true, ThisOwn_true());
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public int ExportToWkb(int bufLen, IntPtr buffer, wkbByteOrder byte_order) {
     int ret = OgrPINVOKE.Geometry_ExportToWkb(swigCPtr, bufLen, buffer, (int)byte_order);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
diff --git a/swig/csharp/ogr/Layer.cs b/swig/csharp/ogr/Layer.cs
index 6204a8b..1beecf8 100644
--- a/swig/csharp/ogr/Layer.cs
+++ b/swig/csharp/ogr/Layer.cs
@@ -132,7 +132,7 @@ public class Layer : IDisposable {
     return ret;
   }
 
-  public Feature GetFeature(int fid) {
+  public Feature GetFeature(long fid) {
     IntPtr cPtr = OgrPINVOKE.Layer_GetFeature(swigCPtr, fid);
     Feature ret = (cPtr == IntPtr.Zero) ? null : new Feature(cPtr, true, ThisOwn_true());
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -146,7 +146,7 @@ public class Layer : IDisposable {
     return ret;
   }
 
-  public int SetNextByIndex(int new_index) {
+  public int SetNextByIndex(long new_index) {
     int ret = OgrPINVOKE.Layer_SetNextByIndex(swigCPtr, new_index);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
     return ret;
@@ -164,7 +164,7 @@ public class Layer : IDisposable {
     return ret;
   }
 
-  public int DeleteFeature(int fid) {
+  public int DeleteFeature(long fid) {
     int ret = OgrPINVOKE.Layer_DeleteFeature(swigCPtr, fid);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
     return ret;
@@ -183,11 +183,11 @@ public class Layer : IDisposable {
     return ret;
   }
 
-  public int GetFeatureCount(int force) {
-    int ret = OgrPINVOKE.Layer_GetFeatureCount(swigCPtr, force);
+  public long GetFeatureCount(int force) {
+    long res = OgrPINVOKE.Layer_GetFeatureCount(swigCPtr, force);
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
-    return ret;
-  }
+    return res;
+}
 
   public int GetExtent(Envelope extent, int force) {
     int ret = OgrPINVOKE.Layer_GetExtent(swigCPtr, Envelope.getCPtr(extent), force);
diff --git a/swig/csharp/ogr/Ogr.cs b/swig/csharp/ogr/Ogr.cs
index 8815aba..901b2df 100644
--- a/swig/csharp/ogr/Ogr.cs
+++ b/swig/csharp/ogr/Ogr.cs
@@ -137,6 +137,13 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
     return ret;
   }
 
+  public static Geometry ForceTo(Geometry geom_in, wkbGeometryType eTargetType, string[] options) {
+    IntPtr cPtr = OgrPINVOKE.ForceTo(Geometry.getCPtr(geom_in), (int)eTargetType, (options != null)? new OgrPINVOKE.StringListMarshal(options)._ar : null);
+    Geometry ret = (cPtr == IntPtr.Zero) ? null : new Geometry(cPtr, true, ThisOwn_true());
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public static int GetDriverCount() {
     int ret = OgrPINVOKE.GetDriverCount();
     if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
@@ -172,6 +179,89 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
     return ret;
   }
 
+  public static string GetFieldSubTypeName(FieldSubType type) {
+    string ret = OgrPINVOKE.GetFieldSubTypeName((int)type);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_Flatten(wkbGeometryType eType) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_Flatten((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_SetZ(wkbGeometryType eType) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_SetZ((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_SetModifier(wkbGeometryType eType, int bSetZ, int bSetM) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_SetModifier((int)eType, bSetZ, bSetM);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static int GT_HasZ(wkbGeometryType eType) {
+    int ret = OgrPINVOKE.GT_HasZ((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static int GT_IsSubClassOf(wkbGeometryType eType, wkbGeometryType eSuperType) {
+    int ret = OgrPINVOKE.GT_IsSubClassOf((int)eType, (int)eSuperType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static int GT_IsCurve(wkbGeometryType arg0) {
+    int ret = OgrPINVOKE.GT_IsCurve((int)arg0);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static int GT_IsSurface(wkbGeometryType arg0) {
+    int ret = OgrPINVOKE.GT_IsSurface((int)arg0);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static int GT_IsNonLinear(wkbGeometryType arg0) {
+    int ret = OgrPINVOKE.GT_IsNonLinear((int)arg0);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_GetCollection(wkbGeometryType eType) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_GetCollection((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_GetCurve(wkbGeometryType eType) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_GetCurve((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static wkbGeometryType GT_GetLinear(wkbGeometryType eType) {
+    wkbGeometryType ret = (wkbGeometryType)OgrPINVOKE.GT_GetLinear((int)eType);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
+  public static void SetNonLinearGeometriesEnabledFlag(int bFlag) {
+    OgrPINVOKE.SetNonLinearGeometriesEnabledFlag(bFlag);
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+  }
+
+  public static int GetNonLinearGeometriesEnabledFlag() {
+    int ret = OgrPINVOKE.GetNonLinearGeometriesEnabledFlag();
+    if (OgrPINVOKE.SWIGPendingException.Pending) throw OgrPINVOKE.SWIGPendingException.Retrieve();
+    return ret;
+  }
+
   public static DataSource GetOpenDS(int ds_number) {
     IntPtr cPtr = OgrPINVOKE.GetOpenDS(ds_number);
     DataSource ret = (cPtr == IntPtr.Zero) ? null : new DataSource(cPtr, false, ThisOwn_false());
@@ -247,11 +337,16 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public static readonly string OLCFastSetNextByIndex = OgrPINVOKE.OLCFastSetNextByIndex_get();
   public static readonly string OLCStringsAsUTF8 = OgrPINVOKE.OLCStringsAsUTF8_get();
   public static readonly string OLCCreateGeomField = OgrPINVOKE.OLCCreateGeomField_get();
+  public static readonly string OLCCurveGeometries = OgrPINVOKE.OLCCurveGeometries_get();
   public static readonly string ODsCCreateLayer = OgrPINVOKE.ODsCCreateLayer_get();
   public static readonly string ODsCDeleteLayer = OgrPINVOKE.ODsCDeleteLayer_get();
   public static readonly string ODsCCreateGeomFieldAfterCreateLayer = OgrPINVOKE.ODsCCreateGeomFieldAfterCreateLayer_get();
+  public static readonly string ODsCCurveGeometries = OgrPINVOKE.ODsCCurveGeometries_get();
+  public static readonly string ODsCTransactions = OgrPINVOKE.ODsCTransactions_get();
+  public static readonly string ODsCEmulatedTransactions = OgrPINVOKE.ODsCEmulatedTransactions_get();
   public static readonly string ODrCCreateDataSource = OgrPINVOKE.ODrCCreateDataSource_get();
   public static readonly string ODrCDeleteDataSource = OgrPINVOKE.ODrCDeleteDataSource_get();
+  public static readonly string OLMD_FID64 = OgrPINVOKE.OLMD_FID64_get();
   public static readonly int OGRERR_NONE = OgrPINVOKE.OGRERR_NONE_get();
   public static readonly int OGRERR_NOT_ENOUGH_DATA = OgrPINVOKE.OGRERR_NOT_ENOUGH_DATA_get();
   public static readonly int OGRERR_NOT_ENOUGH_MEMORY = OgrPINVOKE.OGRERR_NOT_ENOUGH_MEMORY_get();
@@ -260,6 +355,8 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public static readonly int OGRERR_CORRUPT_DATA = OgrPINVOKE.OGRERR_CORRUPT_DATA_get();
   public static readonly int OGRERR_FAILURE = OgrPINVOKE.OGRERR_FAILURE_get();
   public static readonly int OGRERR_UNSUPPORTED_SRS = OgrPINVOKE.OGRERR_UNSUPPORTED_SRS_get();
+  public static readonly int OGRERR_INVALID_HANDLE = OgrPINVOKE.OGRERR_INVALID_HANDLE_get();
+  public static readonly int OGRERR_NON_EXISTING_FEATURE = OgrPINVOKE.OGRERR_NON_EXISTING_FEATURE_get();
 }
 
 }
diff --git a/swig/csharp/ogr/OgrPINVOKE.cs b/swig/csharp/ogr/OgrPINVOKE.cs
index 37adca2..c6357c7 100644
--- a/swig/csharp/ogr/OgrPINVOKE.cs
+++ b/swig/csharp/ogr/OgrPINVOKE.cs
@@ -250,6 +250,9 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_OLCCreateGeomField_get")]
   public static extern string OLCCreateGeomField_get();
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_OLCCurveGeometries_get")]
+  public static extern string OLCCurveGeometries_get();
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_ODsCCreateLayer_get")]
   public static extern string ODsCCreateLayer_get();
 
@@ -259,12 +262,24 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_ODsCCreateGeomFieldAfterCreateLayer_get")]
   public static extern string ODsCCreateGeomFieldAfterCreateLayer_get();
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_ODsCCurveGeometries_get")]
+  public static extern string ODsCCurveGeometries_get();
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_ODsCTransactions_get")]
+  public static extern string ODsCTransactions_get();
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_ODsCEmulatedTransactions_get")]
+  public static extern string ODsCEmulatedTransactions_get();
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_ODrCCreateDataSource_get")]
   public static extern string ODrCCreateDataSource_get();
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_ODrCDeleteDataSource_get")]
   public static extern string ODrCDeleteDataSource_get();
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_OLMD_FID64_get")]
+  public static extern string OLMD_FID64_get();
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_OGRERR_NONE_get")]
   public static extern int OGRERR_NONE_get();
 
@@ -289,6 +304,12 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_OGRERR_UNSUPPORTED_SRS_get")]
   public static extern int OGRERR_UNSUPPORTED_SRS_get();
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_OGRERR_INVALID_HANDLE_get")]
+  public static extern int OGRERR_INVALID_HANDLE_get();
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_OGRERR_NON_EXISTING_FEATURE_get")]
+  public static extern int OGRERR_NON_EXISTING_FEATURE_get();
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_UseExceptions")]
   public static extern void UseExceptions();
 
@@ -469,6 +490,9 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_SyncToDisk")]
   public static extern int DataSource_SyncToDisk(HandleRef jarg1);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_FlushCache")]
+  public static extern void DataSource_FlushCache(HandleRef jarg1);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_CreateLayer")]
   public static extern IntPtr DataSource_CreateLayer(HandleRef jarg1, string jarg2, HandleRef jarg3, int jarg4, IntPtr[] jarg5);
 
@@ -496,6 +520,15 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_SetStyleTable")]
   public static extern void DataSource_SetStyleTable(HandleRef jarg1, HandleRef jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_StartTransaction")]
+  public static extern int DataSource_StartTransaction(HandleRef jarg1, int jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_CommitTransaction")]
+  public static extern int DataSource_CommitTransaction(HandleRef jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_DataSource_RollbackTransaction")]
+  public static extern int DataSource_RollbackTransaction(HandleRef jarg1);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_GetRefCount")]
   public static extern int Layer_GetRefCount(HandleRef jarg1);
 
@@ -533,13 +566,13 @@ class OgrPINVOKE {
   public static extern string Layer_GetFIDColumn(HandleRef jarg1);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_GetFeature")]
-  public static extern IntPtr Layer_GetFeature(HandleRef jarg1, int jarg2);
+  public static extern IntPtr Layer_GetFeature(HandleRef jarg1, long jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_GetNextFeature")]
   public static extern IntPtr Layer_GetNextFeature(HandleRef jarg1);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_SetNextByIndex")]
-  public static extern int Layer_SetNextByIndex(HandleRef jarg1, int jarg2);
+  public static extern int Layer_SetNextByIndex(HandleRef jarg1, long jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_SetFeature")]
   public static extern int Layer_SetFeature(HandleRef jarg1, HandleRef jarg2);
@@ -548,7 +581,7 @@ class OgrPINVOKE {
   public static extern int Layer_CreateFeature(HandleRef jarg1, HandleRef jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_DeleteFeature")]
-  public static extern int Layer_DeleteFeature(HandleRef jarg1, int jarg2);
+  public static extern int Layer_DeleteFeature(HandleRef jarg1, long jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_SyncToDisk")]
   public static extern int Layer_SyncToDisk(HandleRef jarg1);
@@ -557,7 +590,7 @@ class OgrPINVOKE {
   public static extern IntPtr Layer_GetLayerDefn(HandleRef jarg1);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_GetFeatureCount")]
-  public static extern int Layer_GetFeatureCount(HandleRef jarg1, int jarg2);
+  public static extern long Layer_GetFeatureCount(HandleRef jarg1, int jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Layer_GetExtent")]
   public static extern int Layer_GetExtent(HandleRef jarg1, HandleRef jarg2, int jarg3);
@@ -703,6 +736,12 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsInteger__SWIG_1")]
   public static extern int Feature_GetFieldAsInteger__SWIG_1(HandleRef jarg1, string jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsInteger64__SWIG_0")]
+  public static extern long Feature_GetFieldAsInteger64__SWIG_0(HandleRef jarg1, int jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsInteger64__SWIG_1")]
+  public static extern long Feature_GetFieldAsInteger64__SWIG_1(HandleRef jarg1, string jarg2);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsDouble__SWIG_0")]
   public static extern double Feature_GetFieldAsDouble__SWIG_0(HandleRef jarg1, int jarg2);
 
@@ -710,7 +749,7 @@ class OgrPINVOKE {
   public static extern double Feature_GetFieldAsDouble__SWIG_1(HandleRef jarg1, string jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsDateTime")]
-  public static extern void Feature_GetFieldAsDateTime(HandleRef jarg1, int jarg2, out int jarg3, out int jarg4, out int jarg5, out int jarg6, out int jarg7, out int jarg8, out int jarg9);
+  public static extern void Feature_GetFieldAsDateTime(HandleRef jarg1, int jarg2, out int jarg3, out int jarg4, out int jarg5, out int jarg6, out int jarg7, out float jarg8, out int jarg9);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldAsIntegerList")]
   public static extern IntPtr Feature_GetFieldAsIntegerList(HandleRef jarg1, int jarg2, out int jarg3);
@@ -734,10 +773,10 @@ class OgrPINVOKE {
   public static extern int Feature_GetGeomFieldIndex(HandleRef jarg1, string jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFID")]
-  public static extern int Feature_GetFID(HandleRef jarg1);
+  public static extern long Feature_GetFID(HandleRef jarg1);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetFID")]
-  public static extern int Feature_SetFID(HandleRef jarg1, int jarg2);
+  public static extern int Feature_SetFID(HandleRef jarg1, long jarg2);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_DumpReadable")]
   public static extern void Feature_DumpReadable(HandleRef jarg1);
@@ -754,6 +793,9 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetField__SWIG_1")]
   public static extern void Feature_SetField__SWIG_1(HandleRef jarg1, string jarg2, byte[] jarg3);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetFieldInteger64")]
+  public static extern void Feature_SetFieldInteger64(HandleRef jarg1, int jarg2, long jarg3);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetField__SWIG_2")]
   public static extern void Feature_SetField__SWIG_2(HandleRef jarg1, int jarg2, int jarg3);
 
@@ -767,10 +809,10 @@ class OgrPINVOKE {
   public static extern void Feature_SetField__SWIG_5(HandleRef jarg1, string jarg2, double jarg3);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetField__SWIG_6")]
-  public static extern void Feature_SetField__SWIG_6(HandleRef jarg1, int jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, int jarg8, int jarg9);
+  public static extern void Feature_SetField__SWIG_6(HandleRef jarg1, int jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, float jarg8, int jarg9);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetField__SWIG_7")]
-  public static extern void Feature_SetField__SWIG_7(HandleRef jarg1, string jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, int jarg8, int jarg9);
+  public static extern void Feature_SetField__SWIG_7(HandleRef jarg1, string jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, float jarg8, int jarg9);
 
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_SetFieldIntegerList")]
   public static extern void Feature_SetFieldIntegerList(HandleRef jarg1, int jarg2, int jarg3, int[] jarg4);
@@ -805,6 +847,12 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_GetFieldType__SWIG_1")]
   public static extern int Feature_GetFieldType__SWIG_1(HandleRef jarg1, string jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_Validate")]
+  public static extern int Feature_Validate(HandleRef jarg1, int jarg2, int jarg3);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Feature_FillUnsetWithDefault")]
+  public static extern void Feature_FillUnsetWithDefault(HandleRef jarg1, int jarg2, IntPtr[] jarg3);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_delete_FeatureDefn")]
   public static extern void delete_FeatureDefn(HandleRef jarg1);
 
@@ -886,6 +934,12 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_SetType")]
   public static extern void FieldDefn_SetType(HandleRef jarg1, int jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_GetSubType")]
+  public static extern int FieldDefn_GetSubType(HandleRef jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_SetSubType")]
+  public static extern void FieldDefn_SetSubType(HandleRef jarg1, int jarg2);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_GetJustify")]
   public static extern int FieldDefn_GetJustify(HandleRef jarg1);
 
@@ -916,6 +970,21 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_SetIgnored")]
   public static extern void FieldDefn_SetIgnored(HandleRef jarg1, int jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_IsNullable")]
+  public static extern int FieldDefn_IsNullable(HandleRef jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_SetNullable")]
+  public static extern void FieldDefn_SetNullable(HandleRef jarg1, int jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_GetDefault")]
+  public static extern string FieldDefn_GetDefault(HandleRef jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_SetDefault")]
+  public static extern void FieldDefn_SetDefault(HandleRef jarg1, string jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_FieldDefn_IsDefaultDriverSpecific")]
+  public static extern int FieldDefn_IsDefaultDriverSpecific(HandleRef jarg1);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_delete_GeomFieldDefn")]
   public static extern void delete_GeomFieldDefn(HandleRef jarg1);
 
@@ -949,6 +1018,12 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_GeomFieldDefn_SetIgnored")]
   public static extern void GeomFieldDefn_SetIgnored(HandleRef jarg1, int jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GeomFieldDefn_IsNullable")]
+  public static extern int GeomFieldDefn_IsNullable(HandleRef jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GeomFieldDefn_SetNullable")]
+  public static extern void GeomFieldDefn_SetNullable(HandleRef jarg1, int jarg2);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_CreateGeometryFromWkb")]
   public static extern IntPtr CreateGeometryFromWkb(int jarg1, IntPtr jarg2, HandleRef jarg3);
 
@@ -982,6 +1057,9 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_ForceToMultiLineString")]
   public static extern IntPtr ForceToMultiLineString(HandleRef jarg1);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_ForceTo")]
+  public static extern IntPtr ForceTo(HandleRef jarg1, int jarg2, IntPtr[] jarg3);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_delete_Geometry")]
   public static extern void delete_Geometry(HandleRef jarg1);
 
@@ -991,6 +1069,9 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_ExportToWkt")]
   public static extern int Geometry_ExportToWkt(HandleRef jarg1, out string jarg2);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_ExportToIsoWkt")]
+  public static extern int Geometry_ExportToIsoWkt(HandleRef jarg1, out string jarg2);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_ExportToGML__SWIG_0")]
   public static extern string Geometry_ExportToGML__SWIG_0(HandleRef jarg1);
 
@@ -1192,6 +1273,18 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_GetDimension")]
   public static extern int Geometry_GetDimension(HandleRef jarg1);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_HasCurveGeometry")]
+  public static extern int Geometry_HasCurveGeometry(HandleRef jarg1, int jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_GetLinearGeometry")]
+  public static extern IntPtr Geometry_GetLinearGeometry(HandleRef jarg1, double jarg2, IntPtr[] jarg3);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_GetCurveGeometry")]
+  public static extern IntPtr Geometry_GetCurveGeometry(HandleRef jarg1, IntPtr[] jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_Value")]
+  public static extern IntPtr Geometry_Value(HandleRef jarg1, double jarg2);
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_Geometry_ExportToWkb")]
   public static extern int Geometry_ExportToWkb(HandleRef jarg1, int jarg2, IntPtr jarg3, int jarg4);
 
@@ -1213,6 +1306,48 @@ class OgrPINVOKE {
   [DllImport("ogr_wrap", EntryPoint="CSharp_GetFieldTypeName")]
   public static extern string GetFieldTypeName(int jarg1);
 
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GetFieldSubTypeName")]
+  public static extern string GetFieldSubTypeName(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_Flatten")]
+  public static extern int GT_Flatten(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_SetZ")]
+  public static extern int GT_SetZ(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_SetModifier")]
+  public static extern int GT_SetModifier(int jarg1, int jarg2, int jarg3);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_HasZ")]
+  public static extern int GT_HasZ(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_IsSubClassOf")]
+  public static extern int GT_IsSubClassOf(int jarg1, int jarg2);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_IsCurve")]
+  public static extern int GT_IsCurve(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_IsSurface")]
+  public static extern int GT_IsSurface(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_IsNonLinear")]
+  public static extern int GT_IsNonLinear(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_GetCollection")]
+  public static extern int GT_GetCollection(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_GetCurve")]
+  public static extern int GT_GetCurve(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GT_GetLinear")]
+  public static extern int GT_GetLinear(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_SetNonLinearGeometriesEnabledFlag")]
+  public static extern void SetNonLinearGeometriesEnabledFlag(int jarg1);
+
+  [DllImport("ogr_wrap", EntryPoint="CSharp_GetNonLinearGeometriesEnabledFlag")]
+  public static extern int GetNonLinearGeometriesEnabledFlag();
+
   [DllImport("ogr_wrap", EntryPoint="CSharp_GetOpenDS")]
   public static extern IntPtr GetOpenDS(int jarg1);
 
diff --git a/swig/csharp/ogr/Osr.cs b/swig/csharp/ogr/Osr.cs
index 02a3f29..bfa2933 100644
--- a/swig/csharp/ogr/Osr.cs
+++ b/swig/csharp/ogr/Osr.cs
@@ -160,6 +160,7 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public const string SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA = "Lambert_Azimuthal_Equal_Area";
   public const string SRS_PT_MERCATOR_1SP = "Mercator_1SP";
   public const string SRS_PT_MERCATOR_2SP = "Mercator_2SP";
+  public const string SRS_PT_MERCATOR_AUXILIARY_SPHERE = "Mercator_Auxiliary_Sphere";
   public const string SRS_PT_MILLER_CYLINDRICAL = "Miller_Cylindrical";
   public const string SRS_PT_MOLLWEIDE = "Mollweide";
   public const string SRS_PT_NEW_ZEALAND_MAP_GRID = "New_Zealand_Map_Grid";
@@ -190,6 +191,14 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public const string SRS_PT_WAGNER_V = "Wagner_V";
   public const string SRS_PT_WAGNER_VI = "Wagner_VI";
   public const string SRS_PT_WAGNER_VII = "Wagner_VII";
+  public const string SRS_PT_QSC = "Quadrilateralized_Spherical_Cube";
+  public const string SRS_PT_AITOFF = "Aitoff";
+  public const string SRS_PT_WINKEL_I = "Winkel_I";
+  public const string SRS_PT_WINKEL_II = "Winkel_II";
+  public const string SRS_PT_WINKEL_TRIPEL = "Winkel_Tripel";
+  public const string SRS_PT_CRASTER_PARABOLIC = "Craster_Parabolic";
+  public const string SRS_PT_LOXIMUTHAL = "Loximuthal";
+  public const string SRS_PT_QUARTIC_AUTHALIC = "Quartic_Authalic";
   public const string SRS_PP_CENTRAL_MERIDIAN = "central_meridian";
   public const string SRS_PP_SCALE_FACTOR = "scale_factor";
   public const string SRS_PP_STANDARD_PARALLEL_1 = "standard_parallel_1";
diff --git a/swig/csharp/ogr/OsrPINVOKE.cs b/swig/csharp/ogr/OsrPINVOKE.cs
index 9e5e2e5..f5915f6 100644
--- a/swig/csharp/ogr/OsrPINVOKE.cs
+++ b/swig/csharp/ogr/OsrPINVOKE.cs
@@ -536,7 +536,7 @@ class OsrPINVOKE {
   public static extern int SpatialReference_ImportFromMICoordSys(HandleRef jarg1, string jarg2);
 
   [DllImport("osr_wrap", EntryPoint="CSharp_SpatialReference_ImportFromOzi")]
-  public static extern int SpatialReference_ImportFromOzi(HandleRef jarg1, string jarg2, string jarg3, string jarg4);
+  public static extern int SpatialReference_ImportFromOzi(HandleRef jarg1, IntPtr[] jarg2);
 
   [DllImport("osr_wrap", EntryPoint="CSharp_SpatialReference_ExportToWkt")]
   public static extern int SpatialReference_ExportToWkt(HandleRef jarg1, out string jarg2);
diff --git a/swig/csharp/ogr/SpatialReference.cs b/swig/csharp/ogr/SpatialReference.cs
index 907c0ad..185fa4a 100644
--- a/swig/csharp/ogr/SpatialReference.cs
+++ b/swig/csharp/ogr/SpatialReference.cs
@@ -660,8 +660,8 @@ public class SpatialReference : IDisposable {
     return ret;
   }
 
-  public int ImportFromOzi(string datum, string proj, string projParms) {
-    int ret = OsrPINVOKE.SpatialReference_ImportFromOzi(swigCPtr, datum, proj, projParms);
+  public int ImportFromOzi(string[] papszLines) {
+    int ret = OsrPINVOKE.SpatialReference_ImportFromOzi(swigCPtr, (papszLines != null)? new OsrPINVOKE.StringListMarshal(papszLines)._ar : null);
     if (OsrPINVOKE.SWIGPendingException.Pending) throw OsrPINVOKE.SWIGPendingException.Retrieve();
     return ret;
   }
diff --git a/swig/csharp/ogr/ogr_wrap.cpp b/swig/csharp/ogr/ogr_wrap.cpp
index bcc6136..5f699f5 100644
--- a/swig/csharp/ogr/ogr_wrap.cpp
+++ b/swig/csharp/ogr/ogr_wrap.cpp
@@ -342,6 +342,7 @@ typedef char retStringAndCPLFree;
 #include <iostream>
 using namespace std;
 
+#include "gdal.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
 #include "ogr_core.h"
@@ -349,6 +350,8 @@ using namespace std;
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
+typedef void GDALMajorObjectShadow;
+
 #ifdef DEBUG 
 typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
 typedef struct OGRDriverHS OGRDriverShadow;
@@ -511,6 +514,9 @@ OGRErrMessages( int rc ) {
 SWIGINTERN OGRErr OGRDataSourceShadow_SyncToDisk(OGRDataSourceShadow *self){
     return OGR_DS_SyncToDisk(self);
   }
+SWIGINTERN void OGRDataSourceShadow_FlushCache(OGRDataSourceShadow *self){
+    GDALFlushCache( self );
+  }
 SWIGINTERN OGRLayerShadow *OGRDataSourceShadow_CreateLayer(OGRDataSourceShadow *self,char const *name,OSRSpatialReferenceShadow *srs=NULL,OGRwkbGeometryType geom_type=wkbUnknown,char **options=0){
     OGRLayerShadow* layer = (OGRLayerShadow*) OGR_DS_CreateLayer( self,
 								  name,
@@ -555,6 +561,15 @@ SWIGINTERN void OGRDataSourceShadow_SetStyleTable(OGRDataSourceShadow *self,OGRS
     if( table != NULL )
         OGR_DS_SetStyleTable(self, (OGRStyleTableH) table);
   }
+SWIGINTERN OGRErr OGRDataSourceShadow_StartTransaction(OGRDataSourceShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_CommitTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_RollbackTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
 SWIGINTERN int OGRLayerShadow_GetRefCount(OGRLayerShadow *self){
     return OGR_L_GetRefCount(self);
   }
@@ -591,13 +606,13 @@ SWIGINTERN char const *OGRLayerShadow_GetGeometryColumn(OGRLayerShadow *self){
 SWIGINTERN char const *OGRLayerShadow_GetFIDColumn(OGRLayerShadow *self){
     return OGR_L_GetFIDColumn(self);
   }
-SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,GIntBig fid){
     return (OGRFeatureShadow*) OGR_L_GetFeature(self, fid);
   }
 SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetNextFeature(OGRLayerShadow *self){
     return (OGRFeatureShadow*) OGR_L_GetNextFeature(self);
   }
-SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,long new_index){
+SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,GIntBig new_index){
     return OGR_L_SetNextByIndex(self, new_index);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
@@ -606,7 +621,7 @@ SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShado
 SWIGINTERN OGRErr OGRLayerShadow_CreateFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
     return OGR_L_CreateFeature(self, feature);
   }
-SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,GIntBig fid){
     return OGR_L_DeleteFeature(self, fid);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
@@ -615,7 +630,7 @@ SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
 SWIGINTERN OGRFeatureDefnShadow *OGRLayerShadow_GetLayerDefn(OGRLayerShadow *self){
     return (OGRFeatureDefnShadow*) OGR_L_GetLayerDefn(self);
   }
-SWIGINTERN int OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
+SWIGINTERN GIntBig OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
     return OGR_L_GetFeatureCount(self, force);
   }
 SWIGINTERN OGRErr OGRLayerShadow_GetExtent(OGRLayerShadow *self,OGREnvelope *extent,int force=1){
@@ -814,6 +829,17 @@ SWIGINTERN int OGRFeatureShadow_GetFieldAsInteger__SWIG_1(OGRFeatureShadow *self
 	  return OGR_F_GetFieldAsInteger(self, i);
       return 0;
   }
+SWIGINTERN GIntBig OGRFeatureShadow_GetFieldAsInteger64__SWIG_0(OGRFeatureShadow *self,int id){
+    return OGR_F_GetFieldAsInteger64(self, id);
+  }
+SWIGINTERN GIntBig OGRFeatureShadow_GetFieldAsInteger64__SWIG_1(OGRFeatureShadow *self,char const *name){
+      int i = OGR_F_GetFieldIndex(self, name);
+      if (i == -1)
+      CPLError(CE_Failure, 1, "No such field: '%s'", name);
+      else
+      return OGR_F_GetFieldAsInteger64(self, i);
+      return 0;
+  }
 SWIGINTERN double OGRFeatureShadow_GetFieldAsDouble__SWIG_0(OGRFeatureShadow *self,int id){
     return OGR_F_GetFieldAsDouble(self, id);
   }
@@ -825,9 +851,9 @@ SWIGINTERN double OGRFeatureShadow_GetFieldAsDouble__SWIG_1(OGRFeatureShadow *se
 	  return OGR_F_GetFieldAsDouble(self, i);
       return 0;
   }
-SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,int *pnSecond,int *pnTZFlag){
-      OGR_F_GetFieldAsDateTime(self, id, pnYear, pnMonth, pnDay,
-			       pnHour, pnMinute, pnSecond,
+SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,float *pfSecond,int *pnTZFlag){
+      OGR_F_GetFieldAsDateTimeEx(self, id, pnYear, pnMonth, pnDay,
+			       pnHour, pnMinute, pfSecond,
 			       pnTZFlag);
   }
 SWIGINTERN int const *OGRFeatureShadow_GetFieldAsIntegerList(OGRFeatureShadow *self,int id,int *count){
@@ -856,10 +882,10 @@ SWIGINTERN int OGRFeatureShadow_GetFieldIndex(OGRFeatureShadow *self,char const
 SWIGINTERN int OGRFeatureShadow_GetGeomFieldIndex(OGRFeatureShadow *self,char const *name){
       return OGR_F_GetGeomFieldIndex(self, name);
   }
-SWIGINTERN int OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
+SWIGINTERN GIntBig OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
     return OGR_F_GetFID(self);
   }
-SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,int fid){
+SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,GIntBig fid){
     return OGR_F_SetFID(self, fid);
   }
 SWIGINTERN void OGRFeatureShadow_DumpReadable(OGRFeatureShadow *self){
@@ -885,6 +911,9 @@ SWIGINTERN void OGRFeatureShadow_SetField__SWIG_1(OGRFeatureShadow *self,char co
       else
 	  OGR_F_SetFieldString(self, i, value);
   }
+SWIGINTERN void OGRFeatureShadow_SetFieldInteger64(OGRFeatureShadow *self,int id,GIntBig value){
+    OGR_F_SetFieldInteger64(self, id, value);
+  }
 SWIGINTERN void OGRFeatureShadow_SetField__SWIG_2(OGRFeatureShadow *self,int id,int value){
     OGR_F_SetFieldInteger(self, id, value);
   }
@@ -905,17 +934,17 @@ SWIGINTERN void OGRFeatureShadow_SetField__SWIG_5(OGRFeatureShadow *self,char co
       else
 	  OGR_F_SetFieldDouble(self, i, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_6(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,int second,int tzflag){
-    OGR_F_SetFieldDateTime(self, id, year, month, day,
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_6(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,float second,int tzflag){
+    OGR_F_SetFieldDateTimeEx(self, id, year, month, day,
                              hour, minute, second, 
                              tzflag);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_7(OGRFeatureShadow *self,char const *name,int year,int month,int day,int hour,int minute,int second,int tzflag){
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_7(OGRFeatureShadow *self,char const *name,int year,int month,int day,int hour,int minute,float second,int tzflag){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1)
 	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
       else
-	  OGR_F_SetFieldDateTime(self, i, year, month, day,
+	  OGR_F_SetFieldDateTimeEx(self, i, year, month, day,
 				 hour, minute, second, 
 				 tzflag);
   }
@@ -965,17 +994,25 @@ SWIGINTERN void OGRFeatureShadow_SetStyleString(OGRFeatureShadow *self,char cons
     OGR_F_SetStyleString(self, the_string);
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_0(OGRFeatureShadow *self,int id){
-    return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, id));
+      OGRFieldDefnH fd = OGR_F_GetFieldDefnRef( self,  id );
+      if (fd)
+          return (OGRFieldType) OGR_Fld_GetType( fd );
+      else
+          return (OGRFieldType)0;
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *self,char const *name){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1) {
-	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
-	  return (OGRFieldType)0;
+          CPLError(CE_Failure, 1, "No such field: '%s'", name);
+          return (OGRFieldType)0;
       } else
-	  return (OGRFieldType) OGR_Fld_GetType( 
-	      OGR_F_GetFieldDefnRef( self,  i )
-	      );
+          return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, i ) );
+  }
+SWIGINTERN int OGRFeatureShadow_Validate(OGRFeatureShadow *self,int flags=OGR_F_VAL_ALL,int bEmitError=TRUE){
+    return OGR_F_Validate(self, flags, bEmitError);
+  }
+SWIGINTERN void OGRFeatureShadow_FillUnsetWithDefault(OGRFeatureShadow *self,int bNotNullableOnly=FALSE,char **options=NULL){
+    OGR_F_FillUnsetWithDefault(self, bNotNullableOnly, options );
   }
 
     static int ValidateOGRGeometryType(OGRwkbGeometryType field_type)
@@ -990,8 +1027,18 @@ SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *
             case wkbMultiLineString:
             case wkbMultiPolygon:
             case wkbGeometryCollection:
+            case wkbCircularString:
+            case wkbCompoundCurve:
+            case wkbCurvePolygon:
+            case wkbMultiCurve:
+            case wkbMultiSurface:
             case wkbNone:
             /*case wkbLinearRing:*/
+            case wkbCircularStringZ:
+            case wkbCompoundCurveZ:
+            case wkbCurvePolygonZ:
+            case wkbMultiCurveZ:
+            case wkbMultiSurfaceZ:
             case wkbPoint25D:
             case wkbLineString25D:
             case wkbPolygon25D:
@@ -1085,6 +1132,8 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
             case OFTDate:
             case OFTTime:
             case OFTDateTime:
+            case OFTInteger64:
+            case OFTInteger64List:
                 return TRUE;
             default:
                 CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field type value");
@@ -1092,6 +1141,22 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
         }
     }
 
+
+    static int ValidateOGRFieldSubType(OGRFieldSubType field_subtype)
+    {
+        switch(field_subtype)
+        {
+            case OFSTNone:
+            case OFSTBoolean:
+            case OFSTInt16:
+            case OFSTFloat32:
+                return TRUE;
+            default:
+                CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field subtype value");
+                return FALSE;
+        }
+    }
+
 SWIGINTERN void delete_OGRFieldDefnShadow(OGRFieldDefnShadow *self){
     OGR_Fld_Destroy(self);
   }
@@ -1117,6 +1182,13 @@ SWIGINTERN void OGRFieldDefnShadow_SetType(OGRFieldDefnShadow *self,OGRFieldType
     if (ValidateOGRFieldType(type))
         OGR_Fld_SetType(self, type);
   }
+SWIGINTERN OGRFieldSubType OGRFieldDefnShadow_GetSubType(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetSubType(self);
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetSubType(OGRFieldDefnShadow *self,OGRFieldSubType type){
+    if (ValidateOGRFieldSubType(type))
+        OGR_Fld_SetSubType(self, type);
+  }
 SWIGINTERN OGRJustification OGRFieldDefnShadow_GetJustify(OGRFieldDefnShadow *self){
     return OGR_Fld_GetJustify(self);
   }
@@ -1145,7 +1217,22 @@ SWIGINTERN int OGRFieldDefnShadow_IsIgnored(OGRFieldDefnShadow *self){
     return OGR_Fld_IsIgnored( self );
   }
 SWIGINTERN void OGRFieldDefnShadow_SetIgnored(OGRFieldDefnShadow *self,int bIgnored){
-    return OGR_Fld_SetIgnored( self, bIgnored );
+    OGR_Fld_SetIgnored( self, bIgnored );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsNullable(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsNullable( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetNullable(OGRFieldDefnShadow *self,int bNullable){
+    OGR_Fld_SetNullable( self, bNullable );
+  }
+SWIGINTERN char const *OGRFieldDefnShadow_GetDefault(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetDefault( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetDefault(OGRFieldDefnShadow *self,char const *pszValue){
+    OGR_Fld_SetDefault( self, pszValue );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsDefaultDriverSpecific(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsDefaultDriverSpecific( self );
   }
 SWIGINTERN void delete_OGRGeomFieldDefnShadow(OGRGeomFieldDefnShadow *self){
     OGR_GFld_Destroy(self);
@@ -1187,6 +1274,12 @@ SWIGINTERN int OGRGeomFieldDefnShadow_IsIgnored(OGRGeomFieldDefnShadow *self){
 SWIGINTERN void OGRGeomFieldDefnShadow_SetIgnored(OGRGeomFieldDefnShadow *self,int bIgnored){
     OGR_GFld_SetIgnored( self, bIgnored );
   }
+SWIGINTERN int OGRGeomFieldDefnShadow_IsNullable(OGRGeomFieldDefnShadow *self){
+    return OGR_GFld_IsNullable( self );
+  }
+SWIGINTERN void OGRGeomFieldDefnShadow_SetNullable(OGRGeomFieldDefnShadow *self,int bNullable){
+    return OGR_GFld_SetNullable( self, bNullable );
+  }
 
   OGRGeometryShadow* CreateGeometryFromWkb( int len, char *bin_string, 
                                             OSRSpatialReferenceShadow *reference=NULL ) {
@@ -1301,6 +1394,13 @@ OGRGeometryShadow* ForceToMultiLineString( OGRGeometryShadow *geom_in ) {
  return (OGRGeometryShadow* )OGR_G_ForceToMultiLineString( OGR_G_Clone(geom_in) );
 }
 
+
+OGRGeometryShadow* ForceTo( OGRGeometryShadow *geom_in, OGRwkbGeometryType eTargetType, char** options = NULL ) {
+ if (geom_in == NULL)
+     return NULL;
+ return (OGRGeometryShadow* )OGR_G_ForceTo( OGR_G_Clone(geom_in), eTargetType, options );
+}
+
 SWIGINTERN void delete_OGRGeometryShadow(OGRGeometryShadow *self){
     OGR_G_DestroyGeometry( self );
   }
@@ -1326,6 +1426,9 @@ SWIGINTERN OGRGeometryShadow *new_OGRGeometryShadow(OGRwkbGeometryType type=wkbU
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkt(OGRGeometryShadow *self,char **argout){
     return OGR_G_ExportToWkt(self, argout);
   }
+SWIGINTERN OGRErr OGRGeometryShadow_ExportToIsoWkt(OGRGeometryShadow *self,char **argout){
+    return OGR_G_ExportToIsoWkt(self, argout);
+  }
 SWIGINTERN retStringAndCPLFree *OGRGeometryShadow_ExportToGML__SWIG_0(OGRGeometryShadow *self){
     return (retStringAndCPLFree*) OGR_G_ExportToGMLEx(self, NULL);
   }
@@ -1534,6 +1637,18 @@ SWIGINTERN void OGRGeometryShadow_SetCoordinateDimension(OGRGeometryShadow *self
 SWIGINTERN int OGRGeometryShadow_GetDimension(OGRGeometryShadow *self){
     return OGR_G_GetDimension(self);
   }
+SWIGINTERN int OGRGeometryShadow_HasCurveGeometry(OGRGeometryShadow *self,int bLookForCircular=FALSE){
+        return OGR_G_HasCurveGeometry(self, bLookForCircular);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetLinearGeometry(OGRGeometryShadow *self,double dfMaxAngleStepSizeDegrees=0.0,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetLinearGeometry(self, dfMaxAngleStepSizeDegrees, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetCurveGeometry(OGRGeometryShadow *self,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetCurveGeometry(self, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_Value(OGRGeometryShadow *self,double dfDistance){
+    return OGR_G_Value(self, dfDistance);
+  }
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkb(OGRGeometryShadow *self,int bufLen,char *buffer,OGRwkbByteOrder byte_order){
       if (bufLen < OGR_G_WkbSize( self ))
         CPLError(CE_Failure, 1, "Array size is small (ExportToWkb).");
@@ -1557,6 +1672,12 @@ char const *OGRDataSourceShadow_name_get( OGRDataSourceShadow *h ) {
 }
 
 
+OGRwkbGeometryType GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM = FALSE)
+{
+    return OGR_GT_SetModifier(eType, bSetZ, bSetM);
+}
+
+
   OGRDataSourceShadow* GetOpenDS(int ds_number) {
     OGRDataSourceShadow* layer = (OGRDataSourceShadow*) OGRGetOpenDS(ds_number);
     return layer;
@@ -1808,6 +1929,16 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_OLCCreateGeomField_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_OLCCurveGeometries_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("CurveGeometries");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_ODsCCreateLayer_get() {
   char * jresult ;
   char *result = 0 ;
@@ -1838,6 +1969,36 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_ODsCCreateGeomFieldAfterCreateLayer_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_ODsCCurveGeometries_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("CurveGeometries");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_ODsCTransactions_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("Transactions");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_ODsCEmulatedTransactions_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("EmulatedTransactions");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT char * SWIGSTDCALL CSharp_ODrCCreateDataSource_get() {
   char * jresult ;
   char *result = 0 ;
@@ -1858,6 +2019,16 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_ODrCDeleteDataSource_get() {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_OLMD_FID64_get() {
+  char * jresult ;
+  char *result = 0 ;
+  
+  result = (char *)("OLMD_FID64");
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_OGRERR_NONE_get() {
   int jresult ;
   int result;
@@ -1938,6 +2109,26 @@ SWIGEXPORT int SWIGSTDCALL CSharp_OGRERR_UNSUPPORTED_SRS_get() {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_OGRERR_INVALID_HANDLE_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(8);
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_OGRERR_NON_EXISTING_FEATURE_get() {
+  int jresult ;
+  int result;
+  
+  result = (int)(9);
+  jresult = result; 
+  return jresult;
+}
+
+
 SWIGEXPORT void SWIGSTDCALL CSharp_UseExceptions() {
   UseExceptions();
 }
@@ -3237,6 +3428,35 @@ SWIGEXPORT int SWIGSTDCALL CSharp_DataSource_SyncToDisk(void * jarg1) {
 }
 
 
+SWIGEXPORT void SWIGSTDCALL CSharp_DataSource_FlushCache(void * jarg1) {
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  
+  arg1 = (OGRDataSourceShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    OGRDataSourceShadow_FlushCache(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT void * SWIGSTDCALL CSharp_DataSource_CreateLayer(void * jarg1, char * jarg2, void * jarg3, int jarg4, void * jarg5) {
   void * jresult ;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
@@ -3584,6 +3804,128 @@ SWIGEXPORT void SWIGSTDCALL CSharp_DataSource_SetStyleTable(void * jarg1, void *
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_DataSource_StartTransaction(void * jarg1, int jarg2) {
+  int jresult ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  int arg2 = (int) FALSE ;
+  OGRErr result;
+  
+  arg1 = (OGRDataSourceShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)OGRDataSourceShadow_StartTransaction(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_DataSource_CommitTransaction(void * jarg1) {
+  int jresult ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRErr result;
+  
+  arg1 = (OGRDataSourceShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)OGRDataSourceShadow_CommitTransaction(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_DataSource_RollbackTransaction(void * jarg1) {
+  int jresult ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRErr result;
+  
+  arg1 = (OGRDataSourceShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRErr)OGRDataSourceShadow_RollbackTransaction(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_Layer_GetRefCount(void * jarg1) {
   int jresult ;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
@@ -3993,14 +4335,14 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_Layer_GetFIDColumn(void * jarg1) {
 }
 
 
-SWIGEXPORT void * SWIGSTDCALL CSharp_Layer_GetFeature(void * jarg1, long jarg2) {
+SWIGEXPORT void * SWIGSTDCALL CSharp_Layer_GetFeature(void * jarg1, GIntBig jarg2) {
   void * jresult ;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
+  GIntBig arg2 ;
   OGRFeatureShadow *result = 0 ;
   
   arg1 = (OGRLayerShadow *)jarg1; 
-  arg2 = (long)jarg2; 
+  arg2 = jarg2; 
   {
     CPLErrorReset();
     result = (OGRFeatureShadow *)OGRLayerShadow_GetFeature(arg1,arg2);
@@ -4061,14 +4403,14 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_Layer_GetNextFeature(void * jarg1) {
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_Layer_SetNextByIndex(void * jarg1, long jarg2) {
+SWIGEXPORT int SWIGSTDCALL CSharp_Layer_SetNextByIndex(void * jarg1, GIntBig jarg2) {
   int jresult ;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
+  GIntBig arg2 ;
   OGRErr result;
   
   arg1 = (OGRLayerShadow *)jarg1; 
-  arg2 = (long)jarg2; 
+  arg2 = jarg2; 
   {
     CPLErrorReset();
     result = (OGRErr)OGRLayerShadow_SetNextByIndex(arg1,arg2);
@@ -4201,14 +4543,14 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Layer_CreateFeature(void * jarg1, void * jarg2
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_Layer_DeleteFeature(void * jarg1, long jarg2) {
+SWIGEXPORT int SWIGSTDCALL CSharp_Layer_DeleteFeature(void * jarg1, GIntBig jarg2) {
   int jresult ;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
+  GIntBig arg2 ;
   OGRErr result;
   
   arg1 = (OGRLayerShadow *)jarg1; 
-  arg2 = (long)jarg2; 
+  arg2 = jarg2; 
   {
     CPLErrorReset();
     result = (OGRErr)OGRLayerShadow_DeleteFeature(arg1,arg2);
@@ -4316,17 +4658,17 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_Layer_GetLayerDefn(void * jarg1) {
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_Layer_GetFeatureCount(void * jarg1, int jarg2) {
-  int jresult ;
+SWIGEXPORT GIntBig SWIGSTDCALL CSharp_Layer_GetFeatureCount(void * jarg1, int jarg2) {
+  GIntBig jresult ;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
   int arg2 = (int) 1 ;
-  int result;
+  GIntBig result;
   
   arg1 = (OGRLayerShadow *)jarg1; 
   arg2 = (int)jarg2; 
   {
     CPLErrorReset();
-    result = (int)OGRLayerShadow_GetFeatureCount(arg1,arg2);
+    result = OGRLayerShadow_GetFeatureCount(arg1,arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -6339,11 +6681,88 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Feature_GetFieldAsInteger__SWIG_1(void * jarg1
 }
 
 
-SWIGEXPORT double SWIGSTDCALL CSharp_Feature_GetFieldAsDouble__SWIG_0(void * jarg1, int jarg2) {
-  double jresult ;
+SWIGEXPORT GIntBig SWIGSTDCALL CSharp_Feature_GetFieldAsInteger64__SWIG_0(void * jarg1, int jarg2) {
+  GIntBig jresult ;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  double result;
+  GIntBig result;
+  
+  arg1 = (OGRFeatureShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  {
+    CPLErrorReset();
+    result = OGRFeatureShadow_GetFieldAsInteger64__SWIG_0(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT GIntBig SWIGSTDCALL CSharp_Feature_GetFieldAsInteger64__SWIG_1(void * jarg1, char * jarg2) {
+  GIntBig jresult ;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  GIntBig result;
+  
+  arg1 = (OGRFeatureShadow *)jarg1; 
+  arg2 = (char *)jarg2; 
+  {
+    if (!arg2) {
+      {
+        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
+      };
+    }
+  }
+  {
+    CPLErrorReset();
+    result = OGRFeatureShadow_GetFieldAsInteger64__SWIG_1(arg1,(char const *)arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT double SWIGSTDCALL CSharp_Feature_GetFieldAsDouble__SWIG_0(void * jarg1, int jarg2) {
+  double jresult ;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  double result;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
   arg2 = (int)jarg2; 
@@ -6416,7 +6835,7 @@ SWIGEXPORT double SWIGSTDCALL CSharp_Feature_GetFieldAsDouble__SWIG_1(void * jar
 }
 
 
-SWIGEXPORT void SWIGSTDCALL CSharp_Feature_GetFieldAsDateTime(void * jarg1, int jarg2, int * jarg3, int * jarg4, int * jarg5, int * jarg6, int * jarg7, int * jarg8, int * jarg9) {
+SWIGEXPORT void SWIGSTDCALL CSharp_Feature_GetFieldAsDateTime(void * jarg1, int jarg2, int * jarg3, int * jarg4, int * jarg5, int * jarg6, int * jarg7, float * jarg8, int * jarg9) {
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
   int *arg3 = (int *) 0 ;
@@ -6424,7 +6843,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_GetFieldAsDateTime(void * jarg1, int
   int *arg5 = (int *) 0 ;
   int *arg6 = (int *) 0 ;
   int *arg7 = (int *) 0 ;
-  int *arg8 = (int *) 0 ;
+  float *arg8 = (float *) 0 ;
   int *arg9 = (int *) 0 ;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
@@ -6434,7 +6853,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_GetFieldAsDateTime(void * jarg1, int
   arg5 = (int *)jarg5; 
   arg6 = (int *)jarg6; 
   arg7 = (int *)jarg7; 
-  arg8 = (int *)jarg8; 
+  arg8 = (float *)jarg8; 
   arg9 = (int *)jarg9; 
   {
     CPLErrorReset();
@@ -6737,15 +7156,15 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Feature_GetGeomFieldIndex(void * jarg1, char *
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_Feature_GetFID(void * jarg1) {
-  int jresult ;
+SWIGEXPORT GIntBig SWIGSTDCALL CSharp_Feature_GetFID(void * jarg1) {
+  GIntBig jresult ;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int result;
+  GIntBig result;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
   {
     CPLErrorReset();
-    result = (int)OGRFeatureShadow_GetFID(arg1);
+    result = OGRFeatureShadow_GetFID(arg1);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -6770,14 +7189,14 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Feature_GetFID(void * jarg1) {
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_Feature_SetFID(void * jarg1, int jarg2) {
+SWIGEXPORT int SWIGSTDCALL CSharp_Feature_SetFID(void * jarg1, GIntBig jarg2) {
   int jresult ;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
+  GIntBig arg2 ;
   OGRErr result;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
-  arg2 = (int)jarg2; 
+  arg2 = jarg2; 
   {
     CPLErrorReset();
     result = (OGRErr)OGRFeatureShadow_SetFID(arg1,arg2);
@@ -6983,6 +7402,39 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_1(void * jarg1, char *
 }
 
 
+SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetFieldInteger64(void * jarg1, int jarg2, GIntBig jarg3) {
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  GIntBig arg3 ;
+  
+  arg1 = (OGRFeatureShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  arg3 = jarg3; 
+  {
+    CPLErrorReset();
+    OGRFeatureShadow_SetFieldInteger64(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_2(void * jarg1, int jarg2, int jarg3) {
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
@@ -7129,7 +7581,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_5(void * jarg1, char *
 }
 
 
-SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_6(void * jarg1, int jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, int jarg8, int jarg9) {
+SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_6(void * jarg1, int jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, float jarg8, int jarg9) {
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
   int arg3 ;
@@ -7137,7 +7589,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_6(void * jarg1, int ja
   int arg5 ;
   int arg6 ;
   int arg7 ;
-  int arg8 ;
+  float arg8 ;
   int arg9 ;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
@@ -7147,7 +7599,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_6(void * jarg1, int ja
   arg5 = (int)jarg5; 
   arg6 = (int)jarg6; 
   arg7 = (int)jarg7; 
-  arg8 = (int)jarg8; 
+  arg8 = (float)jarg8; 
   arg9 = (int)jarg9; 
   {
     CPLErrorReset();
@@ -7174,7 +7626,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_6(void * jarg1, int ja
 }
 
 
-SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_7(void * jarg1, char * jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, int jarg8, int jarg9) {
+SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_7(void * jarg1, char * jarg2, int jarg3, int jarg4, int jarg5, int jarg6, int jarg7, float jarg8, int jarg9) {
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   int arg3 ;
@@ -7182,7 +7634,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_7(void * jarg1, char *
   int arg5 ;
   int arg6 ;
   int arg7 ;
-  int arg8 ;
+  float arg8 ;
   int arg9 ;
   
   arg1 = (OGRFeatureShadow *)jarg1; 
@@ -7192,7 +7644,7 @@ SWIGEXPORT void SWIGSTDCALL CSharp_Feature_SetField__SWIG_7(void * jarg1, char *
   arg5 = (int)jarg5; 
   arg6 = (int)jarg6; 
   arg7 = (int)jarg7; 
-  arg8 = (int)jarg8; 
+  arg8 = (float)jarg8; 
   arg9 = (int)jarg9; 
   {
     if (!arg2) {
@@ -7658,6 +8110,76 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Feature_GetFieldType__SWIG_1(void * jarg1, cha
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_Feature_Validate(void * jarg1, int jarg2, int jarg3) {
+  int jresult ;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 = (int) OGR_F_VAL_ALL ;
+  int arg3 = (int) TRUE ;
+  int result;
+  
+  arg1 = (OGRFeatureShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  arg3 = (int)jarg3; 
+  {
+    CPLErrorReset();
+    result = (int)OGRFeatureShadow_Validate(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_Feature_FillUnsetWithDefault(void * jarg1, int jarg2, void * jarg3) {
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 = (int) FALSE ;
+  char **arg3 = (char **) NULL ;
+  
+  arg1 = (OGRFeatureShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  arg3 = (char **)jarg3; 
+  {
+    CPLErrorReset();
+    OGRFeatureShadow_FillUnsetWithDefault(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT void SWIGSTDCALL CSharp_delete_FeatureDefn(void * jarg1) {
   OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
   
@@ -8590,6 +9112,70 @@ SWIGEXPORT void SWIGSTDCALL CSharp_FieldDefn_SetType(void * jarg1, int jarg2) {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_FieldDefn_GetSubType(void * jarg1) {
+  int jresult ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldSubType result;
+  
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRFieldSubType)OGRFieldDefnShadow_GetSubType(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_FieldDefn_SetSubType(void * jarg1, int jarg2) {
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldSubType arg2 ;
+  
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  arg2 = (OGRFieldSubType)jarg2; 
+  {
+    CPLErrorReset();
+    OGRFieldDefnShadow_SetSubType(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_FieldDefn_GetJustify(void * jarg1) {
   int jresult ;
   OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
@@ -8914,13 +9500,15 @@ SWIGEXPORT void SWIGSTDCALL CSharp_FieldDefn_SetIgnored(void * jarg1, int jarg2)
 }
 
 
-SWIGEXPORT void SWIGSTDCALL CSharp_delete_GeomFieldDefn(void * jarg1) {
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+SWIGEXPORT int SWIGSTDCALL CSharp_FieldDefn_IsNullable(void * jarg1) {
+  int jresult ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  int result;
   
-  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
   {
     CPLErrorReset();
-    delete_OGRGeomFieldDefnShadow(arg1);
+    result = (int)OGRFieldDefnShadow_IsNullable(arg1);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -8940,20 +9528,20 @@ SWIGEXPORT void SWIGSTDCALL CSharp_delete_GeomFieldDefn(void * jarg1) {
     
     
   }
+  jresult = result; 
+  return jresult;
 }
 
 
-SWIGEXPORT void * SWIGSTDCALL CSharp_new_GeomFieldDefn(char * jarg1, int jarg2) {
-  void * jresult ;
-  char *arg1 = (char *) "" ;
-  OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
-  OGRGeomFieldDefnShadow *result = 0 ;
+SWIGEXPORT void SWIGSTDCALL CSharp_FieldDefn_SetNullable(void * jarg1, int jarg2) {
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  int arg2 ;
   
-  arg1 = (char *)jarg1; 
-  arg2 = (OGRwkbGeometryType)jarg2; 
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  arg2 = (int)jarg2; 
   {
     CPLErrorReset();
-    result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
+    OGRFieldDefnShadow_SetNullable(arg1,arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
@@ -8973,17 +9561,176 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_new_GeomFieldDefn(char * jarg1, int jarg2)
     
     
   }
-  jresult = (void *)result; 
-  return jresult;
 }
 
 
-SWIGEXPORT char * SWIGSTDCALL CSharp_GeomFieldDefn_GetName(void * jarg1) {
+SWIGEXPORT char * SWIGSTDCALL CSharp_FieldDefn_GetDefault(void * jarg1) {
   char * jresult ;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   char *result = 0 ;
   
-  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (char *)OGRFieldDefnShadow_GetDefault(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_FieldDefn_SetDefault(void * jarg1, char * jarg2) {
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  arg2 = (char *)jarg2; 
+  {
+    CPLErrorReset();
+    OGRFieldDefnShadow_SetDefault(arg1,(char const *)arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_FieldDefn_IsDefaultDriverSpecific(void * jarg1) {
+  int jresult ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  int result;
+  
+  arg1 = (OGRFieldDefnShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGRFieldDefnShadow_IsDefaultDriverSpecific(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_delete_GeomFieldDefn(void * jarg1) {
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  
+  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    delete_OGRGeomFieldDefnShadow(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
+SWIGEXPORT void * SWIGSTDCALL CSharp_new_GeomFieldDefn(char * jarg1, int jarg2) {
+  void * jresult ;
+  char *arg1 = (char *) "" ;
+  OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
+  OGRGeomFieldDefnShadow *result = 0 ;
+  
+  arg1 = (char *)jarg1; 
+  arg2 = (OGRwkbGeometryType)jarg2; 
+  {
+    CPLErrorReset();
+    result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_GeomFieldDefn_GetName(void * jarg1) {
+  char * jresult ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  char *result = 0 ;
+  
+  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
   {
     CPLErrorReset();
     result = (char *)OGRGeomFieldDefnShadow_GetName(arg1);
@@ -9274,6 +10021,70 @@ SWIGEXPORT void SWIGSTDCALL CSharp_GeomFieldDefn_SetIgnored(void * jarg1, int ja
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_GeomFieldDefn_IsNullable(void * jarg1) {
+  int jresult ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  int result;
+  
+  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGRGeomFieldDefnShadow_IsNullable(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_GeomFieldDefn_SetNullable(void * jarg1, int jarg2) {
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  int arg2 ;
+  
+  arg1 = (OGRGeomFieldDefnShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  {
+    CPLErrorReset();
+    OGRGeomFieldDefnShadow_SetNullable(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
 SWIGEXPORT void * SWIGSTDCALL CSharp_CreateGeometryFromWkb(int jarg1, char * jarg2, void * jarg3) {
   void * jresult ;
   int arg1 ;
@@ -9671,6 +10482,43 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_ForceToMultiLineString(void * jarg1) {
 }
 
 
+SWIGEXPORT void * SWIGSTDCALL CSharp_ForceTo(void * jarg1, int jarg2, void * jarg3) {
+  void * jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRwkbGeometryType arg2 ;
+  char **arg3 = (char **) NULL ;
+  OGRGeometryShadow *result = 0 ;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  arg2 = (OGRwkbGeometryType)jarg2; 
+  arg3 = (char **)jarg3; 
+  {
+    CPLErrorReset();
+    result = (OGRGeometryShadow *)ForceTo(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
 SWIGEXPORT void SWIGSTDCALL CSharp_delete_Geometry(void * jarg1) {
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   
@@ -9794,11 +10642,64 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Geometry_ExportToWkt(void * jarg1, void * jarg
 }
 
 
-SWIGEXPORT char * SWIGSTDCALL CSharp_Geometry_ExportToGML__SWIG_0(void * jarg1) {
-  char * jresult ;
+SWIGEXPORT int SWIGSTDCALL CSharp_Geometry_ExportToIsoWkt(void * jarg1, void * jarg2) {
+  int jresult ;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  retStringAndCPLFree *result = 0 ;
-  
+  char **arg2 = (char **) 0 ;
+  OGRErr result;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  {
+    /* %typemap(in) (char **argout) */
+    arg2 = (char **)jarg2;
+  }
+  {
+    CPLErrorReset();
+    result = (OGRErr)OGRGeometryShadow_ExportToIsoWkt(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  {
+    /* %typemap(out,fragment="OGRErrMessages",canthrow=1) OGRErr */
+    jresult = result;
+  }
+  {
+    /* %typemap(argout) (char **argout) */
+    char* temp_string;
+    temp_string = SWIG_csharp_string_callback(*arg2);
+    if (*arg2)
+    CPLFree(*arg2);
+    *arg2 = temp_string;
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    
+  }
+  return jresult;
+}
+
+
+SWIGEXPORT char * SWIGSTDCALL CSharp_Geometry_ExportToGML__SWIG_0(void * jarg1) {
+  char * jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  retStringAndCPLFree *result = 0 ;
+  
   arg1 = (OGRGeometryShadow *)jarg1; 
   {
     CPLErrorReset();
@@ -12271,6 +13172,148 @@ SWIGEXPORT int SWIGSTDCALL CSharp_Geometry_GetDimension(void * jarg1) {
 }
 
 
+SWIGEXPORT int SWIGSTDCALL CSharp_Geometry_HasCurveGeometry(void * jarg1, int jarg2) {
+  int jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  int arg2 = (int) FALSE ;
+  int result;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  arg2 = (int)jarg2; 
+  {
+    CPLErrorReset();
+    result = (int)OGRGeometryShadow_HasCurveGeometry(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void * SWIGSTDCALL CSharp_Geometry_GetLinearGeometry(void * jarg1, double jarg2, void * jarg3) {
+  void * jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 = (double) 0.0 ;
+  char **arg3 = (char **) NULL ;
+  OGRGeometryShadow *result = 0 ;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  arg2 = (double)jarg2; 
+  arg3 = (char **)jarg3; 
+  {
+    CPLErrorReset();
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetLinearGeometry(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void * SWIGSTDCALL CSharp_Geometry_GetCurveGeometry(void * jarg1, void * jarg2) {
+  void * jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char **arg2 = (char **) NULL ;
+  OGRGeometryShadow *result = 0 ;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  arg2 = (char **)jarg2; 
+  {
+    CPLErrorReset();
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetCurveGeometry(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void * SWIGSTDCALL CSharp_Geometry_Value(void * jarg1, double jarg2) {
+  void * jresult ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
+  OGRGeometryShadow *result = 0 ;
+  
+  arg1 = (OGRGeometryShadow *)jarg1; 
+  arg2 = (double)jarg2; 
+  {
+    CPLErrorReset();
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Value(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = (void *)result; 
+  return jresult;
+}
+
+
 SWIGEXPORT int SWIGSTDCALL CSharp_Geometry_ExportToWkb(void * jarg1, int jarg2, char * jarg3, int jarg4) {
   int jresult ;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
@@ -12511,6 +13554,468 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_GetFieldTypeName(int jarg1) {
 }
 
 
+SWIGEXPORT char * SWIGSTDCALL CSharp_GetFieldSubTypeName(int jarg1) {
+  char * jresult ;
+  OGRFieldSubType arg1 ;
+  char *result = 0 ;
+  
+  arg1 = (OGRFieldSubType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (char *)OGR_GetFieldSubTypeName(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = SWIG_csharp_string_callback((const char *)result); 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_Flatten(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)OGR_GT_Flatten(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_SetZ(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)OGR_GT_SetZ(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_SetModifier(int jarg1, int jarg2, int jarg3) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  int arg2 ;
+  int arg3 = (int) FALSE ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  arg2 = (int)jarg2; 
+  arg3 = (int)jarg3; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)GT_SetModifier(arg1,arg2,arg3);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_HasZ(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  int result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGR_GT_HasZ(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_IsSubClassOf(int jarg1, int jarg2) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType arg2 ;
+  int result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  arg2 = (OGRwkbGeometryType)jarg2; 
+  {
+    CPLErrorReset();
+    result = (int)OGR_GT_IsSubClassOf(arg1,arg2);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_IsCurve(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  int result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGR_GT_IsCurve(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_IsSurface(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  int result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGR_GT_IsSurface(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_IsNonLinear(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  int result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (int)OGR_GT_IsNonLinear(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_GetCollection(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)OGR_GT_GetCollection(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_GetCurve(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)OGR_GT_GetCurve(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GT_GetLinear(int jarg1) {
+  int jresult ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType result;
+  
+  arg1 = (OGRwkbGeometryType)jarg1; 
+  {
+    CPLErrorReset();
+    result = (OGRwkbGeometryType)OGR_GT_GetLinear(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
+SWIGEXPORT void SWIGSTDCALL CSharp_SetNonLinearGeometriesEnabledFlag(int jarg1) {
+  int arg1 ;
+  
+  arg1 = (int)jarg1; 
+  {
+    CPLErrorReset();
+    OGRSetNonLinearGeometriesEnabledFlag(arg1);
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+}
+
+
+SWIGEXPORT int SWIGSTDCALL CSharp_GetNonLinearGeometriesEnabledFlag() {
+  int jresult ;
+  int result;
+  
+  {
+    CPLErrorReset();
+    result = (int)OGRGetNonLinearGeometriesEnabledFlag();
+    CPLErr eclass = CPLGetLastErrorType();
+    if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+      SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
+      
+      
+      
+    }
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  }
+  jresult = result; 
+  return jresult;
+}
+
+
 SWIGEXPORT void * SWIGSTDCALL CSharp_GetOpenDS(int jarg1) {
   void * jresult ;
   int arg1 ;
diff --git a/swig/csharp/ogr/osr_wrap.cpp b/swig/csharp/ogr/osr_wrap.cpp
index 6611f78..4f5087e 100644
--- a/swig/csharp/ogr/osr_wrap.cpp
+++ b/swig/csharp/ogr/osr_wrap.cpp
@@ -786,8 +786,8 @@ SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromERM(OSRSpatialReferenceSha
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromMICoordSys(OSRSpatialReferenceShadow *self,char const *pszCoordSys){
     return OSRImportFromMICoordSys( self, pszCoordSys );
   }
-SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *datum,char const *proj,char const *projParms){
-    return OSRImportFromOzi( self, datum, proj, projParms );
+SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *const *papszLines){
+    return OSRImportFromOzi( self, papszLines );
   }
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ExportToWkt(OSRSpatialReferenceShadow *self,char **argout){
     return OSRExportToWkt( self, argout );
@@ -5684,18 +5684,14 @@ SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromMICoordSys(void * j
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, char * jarg2, char * jarg3, char * jarg4) {
+SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, void * jarg2) {
   int jresult ;
   OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
-  char *arg4 = (char *) 0 ;
+  char **arg2 = (char **) 0 ;
   OGRErr result;
   
   arg1 = (OSRSpatialReferenceShadow *)jarg1; 
-  arg2 = (char *)jarg2; 
-  arg3 = (char *)jarg3; 
-  arg4 = (char *)jarg4; 
+  arg2 = (char **)jarg2; 
   {
     if (!arg2) {
       {
@@ -5704,22 +5700,8 @@ SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, c
     }
   }
   {
-    if (!arg3) {
-      {
-        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
-      };
-    }
-  }
-  {
-    if (!arg4) {
-      {
-        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
-      };
-    }
-  }
-  {
     CPLErrorReset();
-    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4);
+    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *const *)arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
diff --git a/swig/csharp/ogr/wkbGeometryType.cs b/swig/csharp/ogr/wkbGeometryType.cs
index 5c1d926..2b88c48 100644
--- a/swig/csharp/ogr/wkbGeometryType.cs
+++ b/swig/csharp/ogr/wkbGeometryType.cs
@@ -17,8 +17,18 @@ public enum wkbGeometryType {
   wkbMultiLineString = 5,
   wkbMultiPolygon = 6,
   wkbGeometryCollection = 7,
+  wkbCircularString = 8,
+  wkbCompoundCurve = 9,
+  wkbCurvePolygon = 10,
+  wkbMultiCurve = 11,
+  wkbMultiSurface = 12,
   wkbNone = 100,
   wkbLinearRing = 101,
+  wkbCircularStringZ = 1008,
+  wkbCompoundCurveZ = 1009,
+  wkbCurvePolygonZ = 1010,
+  wkbMultiCurveZ = 1011,
+  wkbMultiSurfaceZ = 1012,
   wkbPoint25D = -2147483647,
   wkbLineString25D = -2147483646,
   wkbPolygon25D = -2147483645,
diff --git a/swig/csharp/osr/Osr.cs b/swig/csharp/osr/Osr.cs
index 42d9b71..21ba2c5 100644
--- a/swig/csharp/osr/Osr.cs
+++ b/swig/csharp/osr/Osr.cs
@@ -160,6 +160,7 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public const string SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA = "Lambert_Azimuthal_Equal_Area";
   public const string SRS_PT_MERCATOR_1SP = "Mercator_1SP";
   public const string SRS_PT_MERCATOR_2SP = "Mercator_2SP";
+  public const string SRS_PT_MERCATOR_AUXILIARY_SPHERE = "Mercator_Auxiliary_Sphere";
   public const string SRS_PT_MILLER_CYLINDRICAL = "Miller_Cylindrical";
   public const string SRS_PT_MOLLWEIDE = "Mollweide";
   public const string SRS_PT_NEW_ZEALAND_MAP_GRID = "New_Zealand_Map_Grid";
@@ -190,6 +191,14 @@ public delegate int GDALProgressFuncDelegate(double Complete, IntPtr Message, In
   public const string SRS_PT_WAGNER_V = "Wagner_V";
   public const string SRS_PT_WAGNER_VI = "Wagner_VI";
   public const string SRS_PT_WAGNER_VII = "Wagner_VII";
+  public const string SRS_PT_QSC = "Quadrilateralized_Spherical_Cube";
+  public const string SRS_PT_AITOFF = "Aitoff";
+  public const string SRS_PT_WINKEL_I = "Winkel_I";
+  public const string SRS_PT_WINKEL_II = "Winkel_II";
+  public const string SRS_PT_WINKEL_TRIPEL = "Winkel_Tripel";
+  public const string SRS_PT_CRASTER_PARABOLIC = "Craster_Parabolic";
+  public const string SRS_PT_LOXIMUTHAL = "Loximuthal";
+  public const string SRS_PT_QUARTIC_AUTHALIC = "Quartic_Authalic";
   public const string SRS_PP_CENTRAL_MERIDIAN = "central_meridian";
   public const string SRS_PP_SCALE_FACTOR = "scale_factor";
   public const string SRS_PP_STANDARD_PARALLEL_1 = "standard_parallel_1";
diff --git a/swig/csharp/osr/OsrPINVOKE.cs b/swig/csharp/osr/OsrPINVOKE.cs
index f1a1869..9be4de7 100644
--- a/swig/csharp/osr/OsrPINVOKE.cs
+++ b/swig/csharp/osr/OsrPINVOKE.cs
@@ -536,7 +536,7 @@ class OsrPINVOKE {
   public static extern int SpatialReference_ImportFromMICoordSys(HandleRef jarg1, string jarg2);
 
   [DllImport("osr_wrap", EntryPoint="CSharp_SpatialReference_ImportFromOzi")]
-  public static extern int SpatialReference_ImportFromOzi(HandleRef jarg1, string jarg2, string jarg3, string jarg4);
+  public static extern int SpatialReference_ImportFromOzi(HandleRef jarg1, IntPtr[] jarg2);
 
   [DllImport("osr_wrap", EntryPoint="CSharp_SpatialReference_ExportToWkt")]
   public static extern int SpatialReference_ExportToWkt(HandleRef jarg1, out string jarg2);
diff --git a/swig/csharp/osr/SpatialReference.cs b/swig/csharp/osr/SpatialReference.cs
index 7d0b861..ae1b4b1 100644
--- a/swig/csharp/osr/SpatialReference.cs
+++ b/swig/csharp/osr/SpatialReference.cs
@@ -660,8 +660,8 @@ public class SpatialReference : IDisposable {
     return ret;
   }
 
-  public int ImportFromOzi(string datum, string proj, string projParms) {
-    int ret = OsrPINVOKE.SpatialReference_ImportFromOzi(swigCPtr, datum, proj, projParms);
+  public int ImportFromOzi(string[] papszLines) {
+    int ret = OsrPINVOKE.SpatialReference_ImportFromOzi(swigCPtr, (papszLines != null)? new OsrPINVOKE.StringListMarshal(papszLines)._ar : null);
     if (OsrPINVOKE.SWIGPendingException.Pending) throw OsrPINVOKE.SWIGPendingException.Retrieve();
     return ret;
   }
diff --git a/swig/csharp/osr/osr_wrap.cpp b/swig/csharp/osr/osr_wrap.cpp
index 6611f78..4f5087e 100644
--- a/swig/csharp/osr/osr_wrap.cpp
+++ b/swig/csharp/osr/osr_wrap.cpp
@@ -786,8 +786,8 @@ SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromERM(OSRSpatialReferenceSha
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromMICoordSys(OSRSpatialReferenceShadow *self,char const *pszCoordSys){
     return OSRImportFromMICoordSys( self, pszCoordSys );
   }
-SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *datum,char const *proj,char const *projParms){
-    return OSRImportFromOzi( self, datum, proj, projParms );
+SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *const *papszLines){
+    return OSRImportFromOzi( self, papszLines );
   }
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ExportToWkt(OSRSpatialReferenceShadow *self,char **argout){
     return OSRExportToWkt( self, argout );
@@ -5684,18 +5684,14 @@ SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromMICoordSys(void * j
 }
 
 
-SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, char * jarg2, char * jarg3, char * jarg4) {
+SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, void * jarg2) {
   int jresult ;
   OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
-  char *arg4 = (char *) 0 ;
+  char **arg2 = (char **) 0 ;
   OGRErr result;
   
   arg1 = (OSRSpatialReferenceShadow *)jarg1; 
-  arg2 = (char *)jarg2; 
-  arg3 = (char *)jarg3; 
-  arg4 = (char *)jarg4; 
+  arg2 = (char **)jarg2; 
   {
     if (!arg2) {
       {
@@ -5704,22 +5700,8 @@ SWIGEXPORT int SWIGSTDCALL CSharp_SpatialReference_ImportFromOzi(void * jarg1, c
     }
   }
   {
-    if (!arg3) {
-      {
-        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
-      };
-    }
-  }
-  {
-    if (!arg4) {
-      {
-        SWIG_CSharpException(SWIG_ValueError, "Received a NULL pointer."); return 0; 
-      };
-    }
-  }
-  {
     CPLErrorReset();
-    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4);
+    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *const *)arg2);
     CPLErr eclass = CPLGetLastErrorType();
     if ( eclass == CE_Failure || eclass == CE_Fatal ) {
       SWIG_CSharpException(SWIG_RuntimeError, CPLGetLastErrorMsg());
diff --git a/swig/include/Band.i b/swig/include/Band.i
index ffe30ae..b3fd717 100644
--- a/swig/include/Band.i
+++ b/swig/include/Band.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: Band.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: Band.i 28899 2015-04-14 09:27:00Z rouault $
  *
  * Name:     Band.i
  * Project:  GDAL Python Interface
@@ -39,15 +39,15 @@
 /* Returned size is in bytes or 0 if an error occured */
 static
 GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
-                             int nPixelSpace, int nLineSpace,
-                             int bSpacingShouldBeMultipleOfPixelSize )
+                                 GIntBig nPixelSpace, GIntBig nLineSpace,
+                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
     const GIntBig MAX_INT = (((GIntBig)0x7fffffff) << 32) | 0xffffffff;
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -76,11 +76,6 @@ GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -108,7 +103,8 @@ CPLErr ReadRaster_internal( GDALRasterBandShadow *obj,
                             int buf_xsize, int buf_ysize,
                             GDALDataType buf_type,
                             int *buf_size, char **buf,
-                            int pixel_space, int line_space )
+                            GIntBig pixel_space, GIntBig line_space,
+                            GDALRasterIOExtraArg* psExtraArg )
 {
   CPLErr result;
 
@@ -130,9 +126,9 @@ CPLErr ReadRaster_internal( GDALRasterBandShadow *obj,
   *buf = (char*) malloc( *buf_size );
   if ( *buf )
   {
-    result =  GDALRasterIO( obj, GF_Read, xoff, yoff, xsize, ysize,
+    result =  GDALRasterIOEx( obj, GF_Read, xoff, yoff, xsize, ysize,
                                     (void *) *buf, buf_xsize, buf_ysize,
-                                    buf_type, pixel_space, line_space );
+                                    buf_type, pixel_space, line_space, psExtraArg );
     if ( result != CE_None )
     {
         free( *buf );
@@ -195,6 +191,12 @@ public:
   GDALDataType DataType;
 %mutable;
 
+  /* Interface method added for GDAL 1.12.0 */
+  GDALDatasetShadow* GetDataset()
+  {
+    return (GDALDatasetShadow*) GDALGetBandDataset(self);
+  }
+
   /* Interface method added for GDAL 1.7.0 */
   int GetBand()
   {
@@ -357,15 +359,26 @@ public:
                      int *buf_ysize = 0,
                      int *buf_type = 0,
                      int *buf_pixel_space = 0,
-                     int *buf_line_space = 0) {
+                     int *buf_line_space = 0,
+                     GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour,
+                     GDALProgressFunc callback = NULL,
+                     void* callback_data=NULL ) {
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
     GDALDataType ntype  = (buf_type==0) ? GDALGetRasterDataType(self)
                                         : (GDALDataType)*buf_type;
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
     return ReadRaster_internal( self, xoff, yoff, xsize, ysize,
-                                nxsize, nysize, ntype, buf_len, buf, pixel_space, line_space );
+                                nxsize, nysize, ntype, buf_len, buf, pixel_space, line_space,
+                                &sExtraArg );
   }
 %clear (int *buf_len, char **buf );
 %clear (int*);
@@ -461,6 +474,23 @@ public:
       return GDALCreateMaskBand( self, nFlags );
   }
 
+#if defined(SWIGPYTHON)
+%feature( "kwargs" ) GetHistogram;
+  CPLErr GetHistogram( double min=-0.5,
+                     double max=255.5,
+                     int buckets=256,
+                     GUIntBig *panHistogram = NULL,
+                     int include_out_of_range = 0,
+                     int approx_ok = 1,
+                     GDALProgressFunc callback = NULL,
+                     void* callback_data=NULL ) {
+    CPLErrorReset(); 
+    CPLErr err = GDALGetRasterHistogramEx( self, min, max, buckets, panHistogram,
+                                         include_out_of_range, approx_ok,
+                                         callback, callback_data );
+    return err;
+  }
+#else
 #ifndef SWIGJAVA
 #if defined(SWIGCSHARP)
 %apply (int inout[ANY]) {int *panHistogram};
@@ -490,7 +520,19 @@ public:
 %clear (CPLErr);
 #endif
 #endif
+#endif
 
+#if defined(SWIGPYTHON)
+%feature ("kwargs") GetDefaultHistogram;
+CPLErr GetDefaultHistogram( double *min_ret=NULL, double *max_ret=NULL, int *buckets_ret = NULL, 
+                            GUIntBig **ppanHistogram = NULL, int force = 1, 
+                            GDALProgressFunc callback = NULL,
+                            void* callback_data=NULL ) {
+    return GDALGetDefaultHistogramEx( self, min_ret, max_ret, buckets_ret,
+                                    ppanHistogram, force, 
+                                    callback, callback_data );
+}
+#else
 #ifndef SWIGJAVA
 #if defined(SWIGPERL)
 %apply (double *OUTPUT){double *min_ret, double *max_ret}
@@ -512,8 +554,18 @@ CPLErr GetDefaultHistogram( double *min_ret=NULL, double *max_ret=NULL, int *buc
 %clear (CPLErr);
 #endif
 #endif
+#endif
 
-#if defined(SWIGPERL) || defined(SWIGPYTHON) || defined(SWIGJAVA)
+#if defined(SWIGPYTHON)
+%apply (int nList, GUIntBig* pList) {(int buckets_in, GUIntBig *panHistogram_in)}
+CPLErr SetDefaultHistogram( double min, double max, 
+                            int buckets_in, GUIntBig *panHistogram_in ) {
+    return GDALSetDefaultHistogramEx( self, min, max, 
+                                    buckets_in, panHistogram_in );
+}
+%clear (int buckets_in, int *panHistogram_in);
+#else
+#if defined(SWIGPERL) || defined(SWIGJAVA)
 %apply (int nList, int* pList) {(int buckets_in, int *panHistogram_in)}
 #endif
 CPLErr SetDefaultHistogram( double min, double max, 
@@ -521,9 +573,10 @@ CPLErr SetDefaultHistogram( double min, double max,
     return GDALSetDefaultHistogram( self, min, max, 
     	   			    buckets_in, panHistogram_in );
 }
-#if defined(SWIGPERL) || defined(SWIGPYTHON) || defined(SWIGJAVA)
+#if defined(SWIGPERL) || defined(SWIGJAVA)
 %clear (int buckets_in, int *panHistogram_in);
 #endif
+#endif
 
   /* Interface method added for GDAL 1.7.0 */
   bool HasArbitraryOverviews() {
diff --git a/swig/include/Dataset.i b/swig/include/Dataset.i
index ce458f7..d30e0cd 100644
--- a/swig/include/Dataset.i
+++ b/swig/include/Dataset.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: Dataset.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: Dataset.i 28601 2015-03-03 11:06:40Z rouault $
  *
  * Name:     Dataset.i
  * Project:  GDAL Python Interface
@@ -33,7 +33,7 @@
 static
 GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
                                 int nBands, int* bandMap, int nBandMapArrayLength,
-                                int nPixelSpace, int nLineSpace, int nBandSpace,
+                                GIntBig nPixelSpace, GIntBig nLineSpace, GIntBig nBandSpace,
                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
@@ -41,7 +41,7 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -70,11 +70,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -85,11 +80,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nBandSpace == 0 )
     {
-        if (nLineSpace > MAX_INT32 / buf_ysize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nBandSpace");
-            return 0;
-        }
         nBandSpace = nLineSpace * buf_ysize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nBandSpace % nPixelSize) != 0 )
@@ -124,7 +114,8 @@ CPLErr DSReadRaster_internal( GDALDatasetShadow *obj,
                             GDALDataType buf_type,
                             int *buf_size, char **buf,
                             int band_list, int *pband_list,
-                            int pixel_space, int line_space, int band_space)
+                            GIntBig pixel_space, GIntBig line_space, GIntBig band_space,
+                            GDALRasterIOExtraArg* psExtraArg)
 {
   CPLErr result;
 
@@ -146,9 +137,10 @@ CPLErr DSReadRaster_internal( GDALDatasetShadow *obj,
   *buf = (char*) malloc( *buf_size );
   if (*buf)
   {
-    result = GDALDatasetRasterIO(obj, GF_Read, xoff, yoff, xsize, ysize,
+    result = GDALDatasetRasterIOEx(obj, GF_Read, xoff, yoff, xsize, ysize,
                                     (void*) *buf, buf_xsize, buf_ysize, buf_type,
-                                    band_list, pband_list, pixel_space, line_space, band_space );
+                                    band_list, pband_list, pixel_space, line_space, band_space,
+                                    psExtraArg );
     if ( result != CE_None ) {
         free( *buf );
         *buf = 0;
@@ -596,7 +588,10 @@ CPLErr ReadRaster(  int xoff, int yoff, int xsize, int ysize,
                       int *buf_xsize = 0, int *buf_ysize = 0,
                       GDALDataType *buf_type = 0,
                       int band_list = 0, int *pband_list = 0,
-                      int* buf_pixel_space = 0, int* buf_line_space = 0, int* buf_band_space = 0 )
+                      int* buf_pixel_space = 0, int* buf_line_space = 0, int* buf_band_space = 0,
+                      GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour,
+                      GDALProgressFunc callback = NULL,
+                      void* callback_data=NULL )
 {
     CPLErr eErr;
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
@@ -611,15 +606,21 @@ CPLErr ReadRaster(  int xoff, int yoff, int xsize, int ysize,
       ntype = GDALGetRasterDataType( GDALGetRasterBand( self, lastband ) );
     }
 
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
-    int band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
                             
     eErr = DSReadRaster_internal( self, xoff, yoff, xsize, ysize,
                                 nxsize, nysize, ntype,
                                 buf_len, buf, 
                                 band_list, pband_list,
-                                pixel_space, line_space, band_space);
+                                pixel_space, line_space, band_space, &sExtraArg);
 
     return eErr;
 }
@@ -836,6 +837,113 @@ CPLErr ReadRaster(  int xoff, int yoff, int xsize, int ysize,
 
 #endif /* PYTHON */
 
+#if defined(SWIGPYTHON) || defined(SWIGJAVA)
+
+  /* Note that datasources own their layers */
+#ifndef SWIGJAVA
+  %feature( "kwargs" ) CreateLayer;
+#endif
+  OGRLayerShadow *CreateLayer(const char* name, 
+              OSRSpatialReferenceShadow* srs=NULL,
+              OGRwkbGeometryType geom_type=wkbUnknown,
+              char** options=0) {
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetCreateLayer( self,
+                                  name,
+                                  srs,
+                                  geom_type,
+                                  options);
+    return layer;
+  }
+
+#ifndef SWIGJAVA
+  %feature( "kwargs" ) CopyLayer;
+#endif
+%apply Pointer NONNULL {OGRLayerShadow *src_layer};
+  OGRLayerShadow *CopyLayer(OGRLayerShadow *src_layer,
+            const char* new_name,
+            char** options=0) {
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetCopyLayer( self,
+                                                      src_layer,
+                                                      new_name,
+                                                      options);
+    return layer;
+  }
+
+  OGRErr DeleteLayer(int index){
+    return GDALDatasetDeleteLayer(self, index);
+  }
+
+  int GetLayerCount() {
+    return GDALDatasetGetLayerCount(self);
+  }
+
+#ifdef SWIGJAVA
+  OGRLayerShadow *GetLayerByIndex( int index ) {
+#else
+  OGRLayerShadow *GetLayerByIndex( int index=0) {
+#endif
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetGetLayer(self, index);
+    return layer;
+  }
+
+  OGRLayerShadow *GetLayerByName( const char* layer_name) {
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetGetLayerByName(self, layer_name);
+    return layer;
+  }
+
+  bool TestCapability(const char * cap) {
+    return (GDALDatasetTestCapability(self, cap) > 0);
+  }
+
+#ifndef SWIGJAVA
+  %feature( "kwargs" ) ExecuteSQL;
+#endif
+  %apply Pointer NONNULL {const char * statement};
+  OGRLayerShadow *ExecuteSQL(const char* statement,
+                        OGRGeometryShadow* spatialFilter=NULL,
+                        const char* dialect="") {
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetExecuteSQL(self,
+                                                      statement,
+                                                      spatialFilter,
+                                                      dialect);
+    return layer;
+  }
+  
+%apply SWIGTYPE *DISOWN {OGRLayerShadow *layer};
+  void ReleaseResultSet(OGRLayerShadow *layer){
+    GDALDatasetReleaseResultSet(self, layer);
+  }
+%clear OGRLayerShadow *layer;
+  
+  OGRStyleTableShadow *GetStyleTable() {
+    return (OGRStyleTableShadow*) GDALDatasetGetStyleTable(self);
+  }
+
+  void SetStyleTable(OGRStyleTableShadow* table) {
+    if( table != NULL )
+        GDALDatasetSetStyleTable(self, (OGRStyleTableH) table);
+  }
+
+#endif /* defined(SWIGPYTHON) || defined(SWIGJAVA) */
+
+#ifndef SWIGJAVA
+  %feature( "kwargs" ) StartTransaction;
+#endif
+  OGRErr StartTransaction(int force = FALSE)
+  {
+    return GDALDatasetStartTransaction(self, force);
+  }
+
+  OGRErr CommitTransaction()
+  {
+    return GDALDatasetCommitTransaction(self);
+  }
+
+  OGRErr RollbackTransaction()
+  {
+    return GDALDatasetRollbackTransaction(self);
+  }
+
 } /* extend */
 }; /* GDALDatasetShadow */
 
diff --git a/swig/include/Driver.i b/swig/include/Driver.i
index 9039dce..f1f69bc 100644
--- a/swig/include/Driver.i
+++ b/swig/include/Driver.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: Driver.i 21479 2011-01-13 02:11:29Z warmerdam $
+ * $Id: Driver.i 28721 2015-03-12 15:28:20Z ajolma $
  *
  * Name:     Driver.i
  * Project:  GDAL Python Interface
@@ -97,15 +97,15 @@ public:
     return ds;
   }
 
-  int Delete( const char *utf8_path ) {
+  CPLErr Delete( const char *utf8_path ) {
     return GDALDeleteDataset( self, utf8_path );
   }
 
-  int Rename( const char *newName, const char *oldName ) {
+  CPLErr Rename( const char *newName, const char *oldName ) {
     return GDALRenameDataset( self, newName, oldName );
   }
 
-  int CopyFiles( const char *newName, const char *oldName ) {
+  CPLErr CopyFiles( const char *newName, const char *oldName ) {
     return GDALCopyDatasetFiles( self, newName, oldName );
   }
 
diff --git a/swig/include/MajorObject.i b/swig/include/MajorObject.i
index 5be76f8..a0f0be8 100644
--- a/swig/include/MajorObject.i
+++ b/swig/include/MajorObject.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: MajorObject.i 26569 2013-10-29 23:51:12Z rouault $
+ * $Id: MajorObject.i 28360 2015-01-27 09:27:05Z rouault $
  *
  * Project:  GDAL SWIG Interfaces.
  * Purpose:  SWIG Definitions for GDALMajorObject.
@@ -27,6 +27,21 @@
  * DEALINGS IN THE SOFTWARE.
  *****************************************************************************/
 
+/* For Python we don't import, but include MajorObject.i to avoid */
+/* cyclic dependency betwenn gdal.py and ogr.py. Python2 is fine with that */
+/* but Python3 not */
+/* We should probably define a new module for MajorObject, or merge gdal and ogr */
+/* modules */
+#ifndef FROM_PYTHON_OGR_I
+#ifdef PERL_CPAN_NAMESPACE
+%module "Geo::GDAL"
+#elif defined(SWIGCSHARP)
+%module Gdal
+#else
+%module gdal
+#endif
+#endif /* FROM_PYTHON_OGR_I */
+
 %rename (MajorObject) GDALMajorObjectShadow;
 
 class GDALMajorObjectShadow {
diff --git a/swig/include/Operations.i b/swig/include/Operations.i
index 31f00f1..b7776fa 100644
--- a/swig/include/Operations.i
+++ b/swig/include/Operations.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: Operations.i 24896 2012-09-03 00:32:04Z warmerdam $
+ * $Id: Operations.i 28730 2015-03-14 14:24:15Z ajolma $
  *
  * Name:     Operations.i
  * Project:  GDAL Python Interface
@@ -352,16 +352,15 @@ int  SieveFilter( GDALRasterBandShadow *srcBand,
 /*                        RegenerateOverviews()                         */
 /************************************************************************/
 
-#ifndef SWIGPERL
 #ifndef SWIGJAVA
 %feature( "kwargs" ) RegenerateOverviews;
-#endif
+#endif /* SWIGJAVA */
 #ifndef SWIGCSHARP
 %apply (int object_list_count, GDALRasterBandShadow **poObjects) {(int overviewBandCount, GDALRasterBandShadow **overviewBands)};
-#endif
+#endif /* SWIGCSHARP */
 #ifdef SWIGJAVA
 %apply (const char* stringWithDefaultValue) {const char *resampling};
-#endif
+#endif /* SWIGJAVA */
 %apply Pointer NONNULL { GDALRasterBandShadow* srcBand };
 %inline %{
 int  RegenerateOverviews( GDALRasterBandShadow *srcBand,
@@ -379,9 +378,8 @@ int  RegenerateOverviews( GDALRasterBandShadow *srcBand,
 %}
 #ifdef SWIGJAVA
 %clear (const char* resampling);
-#endif
+#endif /* SWIGJAVA */
 %clear GDALRasterBandShadow* srcBand;
-#endif
 
 /************************************************************************/
 /*                         RegenerateOverview()                         */
@@ -447,7 +445,7 @@ int wrapper_GridCreate( char* algorithmOptions,
     
     if ( eErr != CE_None )
     {
-        CPLError( eErr, CPLE_AppDefined, "Failed to process algoritm name and parameters.\n" );
+        CPLError( eErr, CPLE_AppDefined, "Failed to process algorithm name and parameters.\n" );
         return eErr;
     }
 
diff --git a/swig/include/RasterAttributeTable.i b/swig/include/RasterAttributeTable.i
index 104bf01..a1c5acd 100644
--- a/swig/include/RasterAttributeTable.i
+++ b/swig/include/RasterAttributeTable.i
@@ -164,7 +164,7 @@ public:
         return GDALRATSetLinearBinning(self, dfRow0Min, dfBinSize);
     }
 
-    /* TODO: omit color table translation,and dump readable */
+    /* TODO: omit color table translation */
 
     int GetRowOfValue( double dfValue ) {
         return GDALRATGetRowOfValue( self, dfValue );
@@ -173,6 +173,10 @@ public:
     int ChangesAreWrittenToFile() {
         return GDALRATChangesAreWrittenToFile( self );
     }
+
+    void DumpReadable() {
+        GDALRATDumpReadable( self, NULL );
+    }
 }
 
 };
diff --git a/swig/include/cpl.i b/swig/include/cpl.i
index d929f33..5be6918 100644
--- a/swig/include/cpl.i
+++ b/swig/include/cpl.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: cpl.i 26526 2013-10-11 11:49:24Z tamas $
+ * $Id: cpl.i 28730 2015-03-14 14:24:15Z ajolma $
  *
  * Name:     cpl.i
  * Project:  GDAL Python Interface
@@ -363,7 +363,7 @@ int VSIUnlink(const char * utf8_path );
 
 /* Added in GDAL 1.7.0 */
 /* Thread support is necessary for binding languages with threaded GC */
-/* even if the user doesn't explicitely use threads */
+/* even if the user doesn't explicitly use threads */
 %inline {
 int wrapper_HasThreadSupport()
 {
@@ -411,13 +411,11 @@ typedef struct
 
 struct StatBuf
 {
-%apply (GIntBig bigint) { GIntBig };
 %immutable;
   int         mode;
   GIntBig     size;
   GIntBig     mtime;
 %mutable;
-%clear (GIntBig bigint);
 
 %extend {
   StatBuf( StatBuf *psStatBuf ) {
@@ -457,15 +455,21 @@ int wrapper_VSIStatL( const char * utf8_path, StatBuf *psStatBufOut, int nFlags
 
 #endif
 
-VSILFILE   *VSIFOpenL( const char *utf8_path, const char *pszMode );
+%rename (VSIFOpenL) wrapper_VSIFOpenL;
+%inline %{
+VSILFILE   *wrapper_VSIFOpenL( const char *utf8_path, const char *pszMode )
+{
+    if (!pszMode) /* would lead to segfault */
+        pszMode = "r";
+    return VSIFOpenL( utf8_path, pszMode );
+}
+%}
 void    VSIFCloseL( VSILFILE * );
 
 #if defined(SWIGPYTHON)
-%apply (GIntBig bigint) { GIntBig };
 int     VSIFSeekL( VSILFILE *, GIntBig, int );
 GIntBig    VSIFTellL( VSILFILE * );
 int     VSIFTruncateL( VSILFILE *, GIntBig );
-%clear (GIntBig bigint);
 #else
 int     VSIFSeekL( VSILFILE *, long, int );
 long    VSIFTellL( VSILFILE * );
@@ -479,7 +483,7 @@ int wrapper_VSIFWriteL( int nLen, char *pBuf, int size, int memb, VSILFILE * f)
 {
     if (nLen < size * memb)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Inconsistant buffer size with 'size' and 'memb' values");
+        CPLError(CE_Failure, CPLE_AppDefined, "Inconsistent buffer size with 'size' and 'memb' values");
         return 0;
     }
     return VSIFWriteL(pBuf, size, memb, f);
diff --git a/swig/include/csharp/ogr_csharp.i b/swig/include/csharp/ogr_csharp.i
index ab48704..204b081 100644
--- a/swig/include/csharp/ogr_csharp.i
+++ b/swig/include/csharp/ogr_csharp.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_csharp.i 15475 2008-10-07 21:40:20Z tamas $
+ * $Id: ogr_csharp.i 27384 2014-05-24 12:28:12Z rouault $
  *
  * Name:     ogr_csharp.i
  * Project:  GDAL CSharp Interface
@@ -40,6 +40,7 @@
 
 DEFINE_EXTERNAL_CLASS(OSRSpatialReferenceShadow, OSGeo.OSR.SpatialReference)
 DEFINE_EXTERNAL_CLASS(OSRCoordinateTransformationShadow, OSGeo.OSR.CoordinateTransformation)
+DEFINE_EXTERNAL_CLASS(GDALMajorObjectShadow, OSGeo.GDAL.MajorObject)
 
 
 %typemap(cscode, noblock="1") OGRGeometryShadow {
diff --git a/swig/include/csharp/typemaps_csharp.i b/swig/include/csharp/typemaps_csharp.i
index f553ccf..ed1bb60 100644
--- a/swig/include/csharp/typemaps_csharp.i
+++ b/swig/include/csharp/typemaps_csharp.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: typemaps_csharp.i 26526 2013-10-11 11:49:24Z tamas $
+ * $Id: typemaps_csharp.i 28375 2015-01-30 12:06:11Z rouault $
  *
  * Name:     typemaps_csharp.i
  * Project:  GDAL CSharp Interface
@@ -127,7 +127,9 @@ OPTIONAL_POD(int, int);
 %typemap(ctype, out="GIntBig") GIntBig  %{GIntBig%}
 %typemap(imtype, out="long") GIntBig "long"
 %typemap(cstype) GIntBig %{long%}
+%typemap(in) GIntBig %{ $1 = $input; %}
 %typemap(out) GIntBig %{ $result = $1; %}
+%typemap(csin) GIntBig "$csinput"
 %typemap(csout, excode=SWIGEXCODE) GIntBig {
     long res = $imcall;$excode
     return res;
diff --git a/swig/include/gdal.i b/swig/include/gdal.i
index 0f2a6cf..f152e9d 100644
--- a/swig/include/gdal.i
+++ b/swig/include/gdal.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: gdal.i 28713 2015-03-10 20:19:21Z ajolma $
  *
  * Name:     gdal.i
  * Project:  GDAL Python Interface
@@ -72,7 +72,28 @@ typedef void GDALColorTableShadow;
 typedef void GDALRasterAttributeTableShadow;
 typedef void GDALTransformerInfoShadow;
 typedef void GDALAsyncReaderShadow;
+%}
+
+#if defined(SWIGPYTHON) || defined(SWIGJAVA)
+%{
+#ifdef DEBUG 
+typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
+typedef struct OGRLayerHS OGRLayerShadow;
+typedef struct OGRGeometryHS OGRGeometryShadow;
+#else
+typedef void OSRSpatialReferenceShadow;
+typedef void OGRLayerShadow;
+typedef void OGRGeometryShadow;
+#endif
+typedef struct OGRStyleTableHS OGRStyleTableShadow;
+%}
+#endif /* #if defined(SWIGPYTHON) || defined(SWIGJAVA) */
 
+#if defined(SWIGCSHARP)
+typedef int OGRErr;
+#endif
+
+%{
 /* use this to not return the int returned by GDAL */
 typedef int RETURN_NONE;
 
@@ -94,6 +115,7 @@ typedef int CPLErr;
 typedef int GDALResampleAlg;
 typedef int GDALAsyncStatusType;
 typedef int GDALRWFlag;
+typedef int GDALRIOResampleAlg;
 #else
 /*! Pixel data types */
 %rename (DataType) GDALDataType;
@@ -161,6 +183,20 @@ typedef enum {
     /*! Write data */  GF_Write = 1
 } GDALRWFlag;
 
+%rename (RIOResampleAlg) GDALRIOResampleAlg;
+typedef enum
+{
+    /*! Nearest neighbour */                GRIORA_NearestNeighbour = 0,
+    /*! Bilinear (2x2 kernel) */            GRIORA_Bilinear = 1,
+    /*! Cubic Convolution Approximation  */ GRIORA_Cubic = 2,
+    /*! Cubic B-Spline Approximation */     GRIORA_CubicSpline = 3,
+    /*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRIORA_Lanczos = 4,
+    /*! Average */                          GRIORA_Average = 5,
+    /*! Mode (selects the value which appears most often of all the sampled points) */
+                                            GRIORA_Mode = 6,
+    /*! Gauss bluring */                    GRIORA_Gauss = 7
+} GDALRIOResampleAlg;
+
 /*! Warp Resampling Algorithm */
 %rename (ResampleAlg) GDALResampleAlg;
 typedef enum {
@@ -245,6 +281,16 @@ $1;
 %include "Driver.i"
 
 
+
+#if defined(SWIGPYTHON) || defined(SWIGJAVA) || defined(SWIGPERL)
+/*
+ * We need to import ogr.i and osr.i for OGRLayer and OSRSpatialRefrerence
+ */
+#define FROM_GDAL_I
+%import ogr.i
+#endif /* #if defined(SWIGPYTHON) || defined(SWIGJAVA) */
+
+
 //************************************************************************
 //
 // Define renames.
@@ -290,7 +336,12 @@ $1;
 %rename (DecToPackedDMS) GDALDecToPackedDMS;
 %rename (ParseXMLString) CPLParseXMLString;
 %rename (SerializeXMLTree) CPLSerializeXMLTree;
+%rename (GetJPEG2000Structure) GDALGetJPEG2000Structure;
 #endif
+#ifdef SWIGPERL
+%include "gdal_perl_rename.i"
+#endif
+
 
 //************************************************************************
 //
@@ -411,9 +462,10 @@ void GDAL_GCP_Id_set( GDAL_GCP *gcp, const char * pszId ) {
     CPLFree( gcp->pszId );
   gcp->pszId = CPLStrdup(pszId);
 }
+%} //%inline 
 
-
-
+#if defined(SWIGCSHARP)
+%inline %{
 /* Duplicate, but transposed names for C# because 
 *  the C# module outputs backwards names
 */
@@ -463,8 +515,9 @@ void GDAL_GCP_set_Id( GDAL_GCP *gcp, const char * pszId ) {
     CPLFree( gcp->pszId );
   gcp->pszId = CPLStrdup(pszId);
 }
-
 %} //%inline 
+#endif //if defined(SWIGCSHARP)
+
 %clear GDAL_GCP *gcp;
 
 #ifdef SWIGJAVA
@@ -533,7 +586,14 @@ void GDALApplyGeoTransform( double padfGeoTransform[6],
 
 %apply (double argin[ANY]) {double gt_in[6]};
 %apply (double argout[ANY]) {double gt_out[6]};
+#ifdef SWIGJAVA
+// FIXME: we should implement correctly the IF_FALSE_RETURN_NONE typemap
 int GDALInvGeoTransform( double gt_in[6], double gt_out[6] );
+#else
+%apply (IF_FALSE_RETURN_NONE) { (RETURN_NONE) };
+RETURN_NONE GDALInvGeoTransform( double gt_in[6], double gt_out[6] );
+%clear (RETURN_NONE);
+#endif
 %clear (double *gt_in);
 %clear (double *gt_out);
 
@@ -556,7 +616,6 @@ void GDALAllRegister();
 void GDALDestroyDriverManager();
 
 #ifdef SWIGPYTHON
-%apply (GIntBig bigint) { GIntBig };
 %inline {
 GIntBig wrapper_GDALGetCacheMax()
 {
@@ -644,6 +703,24 @@ retStringAndCPLFree *CPLSerializeXMLTree( CPLXMLNode *xmlnode );
 char *CPLSerializeXMLTree( CPLXMLNode *xmlnode );
 #endif
 
+#if defined(SWIGPYTHON)
+%newobject GDALGetJPEG2000Structure;
+CPLXMLNode *GDALGetJPEG2000Structure( const char* pszFilename, char** options = NULL );
+#endif
+
+%inline {
+retStringAndCPLFree *GetJPEG2000StructureAsString( const char* pszFilename, char** options = NULL )
+{
+    CPLXMLNode* psNode = GDALGetJPEG2000Structure(pszFilename, options);
+    if( psNode == NULL )
+        return NULL;
+    char* pszXML = CPLSerializeXMLTree(psNode);
+    CPLDestroyXMLNode(psNode);
+    return pszXML;
+}
+}
+
+
 //************************************************************************
 //
 // Define the factory functions for Drivers and Datasets
@@ -694,6 +771,7 @@ GDALDatasetShadow* Open( char const* name ) {
   return Open( name, GA_ReadOnly );
 }
 %}
+
 #else
 %newobject Open;
 %inline %{
@@ -709,8 +787,36 @@ GDALDatasetShadow* Open( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly
   return (GDALDatasetShadow*) ds;
 }
 %}
+
 #endif
 
+%newobject OpenEx;
+#ifndef SWIGJAVA
+%feature( "kwargs" ) OpenEx;
+#endif
+%apply (char **options) {char** allowed_drivers};
+%apply (char **options) {char** open_options};
+%apply (char **options) {char** sibling_files};
+%inline %{
+GDALDatasetShadow* OpenEx( char const* utf8_path, unsigned int nOpenFlags = 0,
+                           char** allowed_drivers = NULL, char** open_options = NULL,
+                           char** sibling_files = NULL ) {
+  CPLErrorReset();
+  GDALDatasetShadow *ds = GDALOpenEx( utf8_path, nOpenFlags, allowed_drivers,
+                                      open_options, sibling_files );
+  if( ds != NULL && CPLGetLastErrorType() == CE_Failure )
+  {
+      if ( GDALDereferenceDataset( ds ) <= 0 )
+          GDALClose(ds);
+      ds = NULL;
+  }
+  return (GDALDatasetShadow*) ds;
+}
+%}
+%clear char** allowed_drivers;
+%clear char** open_options;
+%clear char** sibling_files;
+
 %newobject OpenShared;
 %inline %{
 GDALDatasetShadow* OpenShared( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly ) {
diff --git a/swig/include/gdal_array.i b/swig/include/gdal_array.i
index 92e290c..5e87595 100644
--- a/swig/include/gdal_array.i
+++ b/swig/include/gdal_array.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_array.i 28304 2015-01-07 11:24:37Z rouault $
+ * $Id: gdal_array.i 28497 2015-02-16 11:31:14Z rouault $
  *
  * Name:     gdal_array.i
  * Project:  GDAL Python Interface
@@ -38,6 +38,7 @@
 
 %import MajorObject.i
 %import Band.i
+%import Dataset.i
 %import RasterAttributeTable.i
 
 %include "cplvirtualmem.i"
@@ -48,9 +49,11 @@
 %}
 
 typedef int CPLErr;
+typedef int GDALRIOResampleAlg;
 
 %include "python_strings.i"
 
+
 %{
 #include "gdal_priv.h"
 #ifdef _DEBUG
@@ -64,9 +67,11 @@ typedef int CPLErr;
 
 #ifdef DEBUG 
 typedef struct GDALRasterBandHS GDALRasterBandShadow;
+typedef struct GDALDatasetHS GDALDatasetShadow;
 typedef struct RasterAttributeTableHS GDALRasterAttributeTableShadow;
 #else
 typedef void GDALRasterBandShadow;
+typedef void GDALDatasetShadow;
 typedef void GDALRasterAttributeTableShadow;
 #endif
 
@@ -118,7 +123,8 @@ static void GDALRegister_NUMPY(void)
 
 {
     GDALDriver	*poDriver;
-
+    if (! GDAL_CHECK_VERSION("NUMPY driver"))
+        return;
     if( GDALGetDriverByName( "NUMPY" ) == NULL )
     {
         poDriver = new GDALDriver();
@@ -126,6 +132,7 @@ static void GDALRegister_NUMPY(void)
         poDriver->SetDescription( "NUMPY" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Numeric Python Array" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         
         poDriver->pfnOpen = NUMPYDataset::Open;
 
@@ -293,7 +300,7 @@ GDALDataset *NUMPYDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Is this a numpy dataset name?                                   */
 /* -------------------------------------------------------------------- */
     if( !EQUALN(poOpenInfo->pszFilename,"NUMPY:::",8) 
-        || poOpenInfo->fp != NULL )
+        || poOpenInfo->fpL != NULL )
         return NULL;
 
     psArray = NULL;
@@ -445,6 +452,26 @@ GDALDataset *NUMPYDataset::Open( GDALOpenInfo * poOpenInfo )
 
 %}
 
+// So that SWIGTYPE_p_f_double_p_q_const__char_p_void__int is declared...
+/************************************************************************/
+/*                            TermProgress()                            */
+/************************************************************************/
+
+%rename (TermProgress_nocb) GDALTermProgress_nocb;
+%feature( "kwargs" ) GDALTermProgress_nocb;
+%inline %{
+int GDALTermProgress_nocb( double dfProgress, const char * pszMessage=NULL, void *pData=NULL ) {
+  return GDALTermProgress( dfProgress, pszMessage, pData);
+}
+%}
+
+%rename (TermProgress) GDALTermProgress;
+%callback("%s");
+int GDALTermProgress( double, const char *, void * );
+%nocallback;
+
+%include "callback.i"
+
 %typemap(in,numinputs=1) (PyArrayObject *psArray)
 {
   /* %typemap(in,numinputs=1) (PyArrayObject  *psArray) */
@@ -475,8 +502,11 @@ retStringAndCPLFree* GetArrayFilename(PyArrayObject *psArray)
 %feature( "kwargs" ) BandRasterIONumPy;
 %inline %{
   CPLErr BandRasterIONumPy( GDALRasterBandShadow* band, int bWrite, int xoff, int yoff, int xsize, int ysize,
-                     PyArrayObject *psArray,
-                     int buf_type) {
+                            PyArrayObject *psArray,
+                            int buf_type,
+                            GDALRIOResampleAlg resample_alg,
+                            GDALProgressFunc callback = NULL,
+                            void* callback_data = NULL) {
 
     GDALDataType ntype  = (GDALDataType)buf_type;
     if( psArray->nd < 2 || psArray->nd > 3 )
@@ -496,9 +526,66 @@ retStringAndCPLFree* GetArrayFilename(PyArrayObject *psArray)
     pixel_space = psArray->strides[xdim];
     line_space = psArray->strides[ydim];
 
-    return  GDALRasterIO( band, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    return  GDALRasterIOEx( band, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
                           psArray->data, nxsize, nysize,
-                          ntype, pixel_space, line_space );
+                          ntype, pixel_space, line_space, &sExtraArg );
+  }
+%}
+
+%feature( "kwargs" ) DatasetIONumPy;
+%inline %{
+  CPLErr DatasetIONumPy( GDALDatasetShadow* ds, int bWrite, int xoff, int yoff, int xsize, int ysize,
+                         PyArrayObject *psArray,
+                         int buf_type,
+                         GDALRIOResampleAlg resample_alg,
+                         GDALProgressFunc callback = NULL,
+                         void* callback_data = NULL )
+{
+    GDALDataType ntype  = (GDALDataType)buf_type;
+    if( psArray->nd != 3 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Illegal numpy array rank %d.", 
+                  psArray->nd );
+        return CE_Failure;
+    }
+
+    int xdim = 2;
+    int ydim = 1;
+
+    int bandsize, nxsize, nysize;
+    GIntBig pixel_space, line_space, band_space;
+    nxsize = psArray->dimensions[xdim];
+    nysize = psArray->dimensions[ydim];
+    bandsize = psArray->dimensions[0];
+    if( bandsize != GDALGetRasterCount(ds) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Illegal numpy array band dimension %d. Expected value: %d", 
+                  bandsize, GDALGetRasterCount(ds) );
+        return CE_Failure;
+    }
+    pixel_space = psArray->strides[xdim];
+    line_space = psArray->strides[ydim];
+    band_space = psArray->strides[0];
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    return  GDALDatasetRasterIOEx( ds, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
+                                   psArray->data, nxsize, nysize,
+                                   ntype,
+                                   bandsize, NULL,
+                                   pixel_space, line_space, band_space, &sExtraArg );
   }
 %}
 
@@ -919,12 +1006,18 @@ def NumericTypeCodeToGDALTypeCode(numeric_type):
 def GDALTypeCodeToNumericTypeCode(gdal_code):
     return flip_code(gdal_code)
     
-def LoadFile( filename, xoff=0, yoff=0, xsize=None, ysize=None ):
+def LoadFile( filename, xoff=0, yoff=0, xsize=None, ysize=None,
+              buf_xsize=None, buf_ysize=None, buf_type=None,
+              resample_alg = gdal.GRIORA_NearestNeighbour,
+              callback=None, callback_data=None ):
     ds = gdal.Open( filename )
     if ds is None:
         raise ValueError("Can't open "+filename+"\n\n"+gdal.GetLastErrorMsg())
 
-    return DatasetReadAsArray( ds, xoff, yoff, xsize, ysize )
+    return DatasetReadAsArray( ds, xoff, yoff, xsize, ysize,
+                               buf_xsize=buf_xsize, buf_ysize=buf_ysize, buf_type=buf_type,
+                               resample_alg=resample_alg,
+                               callback = callback, callback_data = callback_data )
 
 def SaveArray( src_array, filename, format = "GTiff", prototype = None ):
     driver = gdal.GetDriverByName( format )
@@ -933,42 +1026,79 @@ def SaveArray( src_array, filename, format = "GTiff", prototype = None ):
 
     return driver.CreateCopy( filename, OpenArray(src_array,prototype) )
 
-def DatasetReadAsArray( ds, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None ):
 
-    if xsize is None:
-        xsize = ds.RasterXSize
-    if ysize is None:
-        ysize = ds.RasterYSize
+def DatasetReadAsArray( ds, xoff=0, yoff=0, win_xsize=None, win_ysize=None, buf_obj=None,
+                        buf_xsize = None, buf_ysize = None, buf_type = None,
+                        resample_alg = gdal.GRIORA_NearestNeighbour,
+                        callback=None, callback_data=None ):
+    """Pure python implementation of reading a chunk of a GDAL file
+    into a numpy array.  Used by the gdal.Dataset.ReadAsArray method."""
+
+    if win_xsize is None:
+        win_xsize = ds.RasterXSize
+    if win_ysize is None:
+        win_ysize = ds.RasterYSize
+
+    if ds.RasterCount == 0:
+        return None
 
     if ds.RasterCount == 1:
-        return BandReadAsArray( ds.GetRasterBand(1), xoff, yoff, xsize, ysize, buf_obj = buf_obj)
+        return BandReadAsArray( ds.GetRasterBand(1), xoff, yoff, win_xsize, win_ysize,
+                                buf_xsize = buf_xsize, buf_ysize = buf_ysize, buf_type = buf_type,
+                                buf_obj = buf_obj,
+                                resample_alg = resample_alg,
+                                callback = callback,
+                                callback_data = callback_data )
 
-    datatype = ds.GetRasterBand(1).DataType
-    for band_index in range(2,ds.RasterCount+1):
-        if datatype != ds.GetRasterBand(band_index).DataType:
-            datatype = gdalconst.GDT_Float32
-    
-    typecode = GDALTypeCodeToNumericTypeCode( datatype )
-    if typecode == None:
-        datatype = gdalconst.GDT_Float32
-        typecode = numpy.float32
-
-    if buf_obj is not None:
-        for band_index in range(1,ds.RasterCount+1):
-            BandReadAsArray( ds.GetRasterBand(band_index),
-                             xoff, yoff, xsize, ysize, buf_obj = buf_obj[band_index-1])
-        return buf_obj
-    
-    array_list = []
-    for band_index in range(1,ds.RasterCount+1):
-        band_array = BandReadAsArray( ds.GetRasterBand(band_index),
-                                      xoff, yoff, xsize, ysize)
-        array_list.append( numpy.reshape( band_array, [1,ysize,xsize] ) )
+    if buf_obj is None:
+        if buf_xsize is None:
+            buf_xsize = win_xsize
+        if buf_ysize is None:
+            buf_ysize = win_ysize
+        if buf_type is None:
+            buf_type = ds.GetRasterBand(1).DataType
+            for band_index in range(2,ds.RasterCount+1):
+                if buf_type != ds.GetRasterBand(band_index).DataType:
+                    buf_type = gdalconst.GDT_Float32
+
+        typecode = GDALTypeCodeToNumericTypeCode( buf_type )
+        if typecode == None:
+            buf_type = gdalconst.GDT_Float32
+            typecode = numpy.float32
+        if buf_type == gdalconst.GDT_Byte and ds.GetRasterBand(1).GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
+            typecode = numpy.int8
+        buf_obj = numpy.empty([ds.RasterCount, buf_ysize,buf_xsize], dtype = typecode)
+
+    else:
+        if len(buf_obj.shape) != 3:
+            raise ValueError('Array should have 3 dimensions')
+
+        shape_buf_xsize = buf_obj.shape[2]
+        shape_buf_ysize = buf_obj.shape[1]
+        if buf_xsize is not None and buf_xsize != shape_buf_xsize:
+            raise ValueError('Specified buf_xsize not consistant with array shape')
+        if buf_ysize is not None and buf_ysize != shape_buf_ysize:
+            raise ValueError('Specified buf_ysize not consistant with array shape')
+        if buf_obj.shape[0] != ds.RasterCount:
+            raise ValueError('Array should have space for %d bands' % ds.RasterCount)
+
+        datatype = NumericTypeCodeToGDALTypeCode( buf_obj.dtype.type )
+        if not datatype:
+            raise ValueError("array does not have corresponding GDAL data type")
+        if buf_type is not None and buf_type != datatype:
+            raise ValueError("Specified buf_type not consistant with array type")
+        buf_type = datatype
+
+    if DatasetIONumPy( ds, 0, xoff, yoff, win_xsize, win_ysize,
+                       buf_obj, buf_type, resample_alg, callback, callback_data ) != 0:
+        return None
+
+    return buf_obj
 
-    return numpy.concatenate( array_list )
-            
 def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = None,
-                     buf_xsize=None, buf_ysize=None, buf_obj=None ):
+                     buf_xsize=None, buf_ysize=None, buf_type=None, buf_obj=None,
+                     resample_alg = gdal.GRIORA_NearestNeighbour,
+                     callback=None, callback_data=None):
     """Pure python implementation of reading a chunk of a GDAL file
     into a numpy array.  Used by the gdal.Band.ReadAsArray method."""
 
@@ -982,6 +1112,20 @@ def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = Non
             buf_xsize = win_xsize
         if buf_ysize is None:
             buf_ysize = win_ysize
+        if buf_type is None:
+            buf_type = band.DataType
+
+        typecode = GDALTypeCodeToNumericTypeCode( buf_type )
+        if typecode == None:
+            buf_type = gdalconst.GDT_Float32
+            typecode = numpy.float32
+        else:
+            buf_type = NumericTypeCodeToGDALTypeCode( typecode )
+
+        if buf_type == gdalconst.GDT_Byte and band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
+            typecode = numpy.int8
+        buf_obj = numpy.empty([buf_ysize,buf_xsize], dtype = typecode)
+
     else:
         if len(buf_obj.shape) == 2:
             shape_buf_xsize = buf_obj.shape[1]
@@ -993,38 +1137,23 @@ def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = Non
             raise ValueError('Specified buf_xsize not consistant with array shape')
         if buf_ysize is not None and buf_ysize != shape_buf_ysize:
             raise ValueError('Specified buf_ysize not consistant with array shape')
-        buf_xsize = shape_buf_xsize
-        buf_ysize = shape_buf_ysize
-
-    if buf_obj is None:
-        datatype = band.DataType
-        typecode = GDALTypeCodeToNumericTypeCode( datatype )
-        if typecode == None:
-            datatype = gdalconst.GDT_Float32
-            typecode = numpy.float32
-        else:
-            datatype = NumericTypeCodeToGDALTypeCode( typecode )
-
-        if datatype == gdalconst.GDT_Byte and band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
-            typecode = numpy.int8
-        ar = numpy.empty([buf_ysize,buf_xsize], dtype = typecode)
-        if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
-                                ar, datatype ) != 0:
-            return None
 
-        return ar
-    else:
         datatype = NumericTypeCodeToGDALTypeCode( buf_obj.dtype.type )
         if not datatype:
             raise ValueError("array does not have corresponding GDAL data type")
+        if buf_type is not None and buf_type != datatype:
+            raise ValueError("Specified buf_type not consistant with array type")
+        buf_type = datatype
 
-        if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
-                                buf_obj, datatype ) != 0:
-            return None
+    if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
+                          buf_obj, buf_type, resample_alg, callback, callback_data ) != 0:
+        return None
 
-        return buf_obj
+    return buf_obj
 
-def BandWriteArray( band, array, xoff=0, yoff=0 ):
+def BandWriteArray( band, array, xoff=0, yoff=0,
+                    resample_alg = gdal.GRIORA_NearestNeighbour,
+                    callback=None, callback_data=None ):
     """Pure python implementation of writing a chunk of a GDAL file
     from a numpy array.  Used by the gdal.Band.WriteArray method."""
 
@@ -1050,7 +1179,7 @@ def BandWriteArray( band, array, xoff=0, yoff=0 ):
         raise ValueError("array does not have corresponding GDAL data type")
 
     return BandRasterIONumPy( band, 1, xoff, yoff, xsize, ysize,
-                                array, datatype )
+                                array, datatype, resample_alg, callback, callback_data )
 
 def RATWriteArray(rat, array, field, start=0):
     """
diff --git a/swig/include/gdalconst.i b/swig/include/gdalconst.i
index cf54a24..4747239 100644
--- a/swig/include/gdalconst.i
+++ b/swig/include/gdalconst.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalconst.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: gdalconst.i 29019 2015-04-25 20:34:19Z rouault $
  *
  * Name:     gdalconst.i
  * Project:  GDAL Python Interface
@@ -70,6 +70,16 @@
 %constant GF_Read  = GF_Read;
 %constant GF_Write = GF_Write;
 
+// GDALRIOResampleAlg
+%constant GRIORA_NearestNeighbour = GRIORA_NearestNeighbour;
+%constant GRIORA_Bilinear = GRIORA_Bilinear;
+%constant GRIORA_Cubic = GRIORA_Cubic;
+%constant GRIORA_CubicSpline = GRIORA_CubicSpline;
+%constant GRIORA_Lanczos = GRIORA_Lanczos;
+%constant GRIORA_Average = GRIORA_Average;
+%constant GRIORA_Mode = GRIORA_Mode;
+%constant GRIORA_Gauss = GRIORA_Gauss;
+
 // GDALColorInterp
 %constant GCI_Undefined     = GCI_Undefined;
 %constant GCI_GrayIndex     = GCI_GrayIndex;
@@ -132,19 +142,37 @@
 %constant CPLE_NoWriteAccess              = CPLE_NoWriteAccess;
 %constant CPLE_UserInterrupt              = CPLE_UserInterrupt;
 
+// Open flags
+%constant OF_ALL     = GDAL_OF_ALL;
+%constant OF_RASTER = GDAL_OF_RASTER;
+%constant OF_VECTOR = GDAL_OF_VECTOR;
+%constant OF_READONLY = GDAL_OF_READONLY;
+%constant OF_UPDATE = GDAL_OF_UPDATE;
+%constant OF_SHARED = GDAL_OF_SHARED;
+%constant OF_VERBOSE_ERROR = GDAL_OF_VERBOSE_ERROR;
+
 #if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
 
 %constant char *DMD_LONGNAME           = GDAL_DMD_LONGNAME;
 %constant char *DMD_HELPTOPIC          = GDAL_DMD_HELPTOPIC;
 %constant char *DMD_MIMETYPE           = GDAL_DMD_MIMETYPE;
 %constant char *DMD_EXTENSION          = GDAL_DMD_EXTENSION;
+%constant char *DMD_EXTENSIONS         = GDAL_DMD_EXTENSIONS;
+%constant char *DMD_CONNECTION_PREFIX  = GDAL_DMD_CONNECTION_PREFIX;
 %constant char *DMD_CREATIONOPTIONLIST = GDAL_DMD_CREATIONOPTIONLIST;
 %constant char *DMD_CREATIONDATATYPES  = GDAL_DMD_CREATIONDATATYPES;
+%constant char *DMD_CREATIONFIELDDATATYPES  = GDAL_DMD_CREATIONFIELDDATATYPES;
 %constant char *DMD_SUBDATASETS        = GDAL_DMD_SUBDATASETS;
 
+%constant char *DCAP_OPEN       = GDAL_DCAP_OPEN;
 %constant char *DCAP_CREATE     = GDAL_DCAP_CREATE;
 %constant char *DCAP_CREATECOPY = GDAL_DCAP_CREATECOPY;
-%constant char *DCAP_VIRTUALIO = GDAL_DCAP_VIRTUALIO;
+%constant char *DCAP_VIRTUALIO  = GDAL_DCAP_VIRTUALIO;
+%constant char *DCAP_RASTER     = GDAL_DCAP_RASTER;
+%constant char *DCAP_VECTOR     = GDAL_DCAP_VECTOR;
+%constant char *DCAP_NOTNULL_FIELDS      = GDAL_DCAP_NOTNULL_FIELDS;
+%constant char *DCAP_DEFAULT_FIELDS      = GDAL_DCAP_DEFAULT_FIELDS;
+%constant char *DCAP_NOTNULL_GEOMFIELDS  = GDAL_DCAP_NOTNULL_GEOMFIELDS;
 
 #else
 
@@ -152,13 +180,22 @@
 #define GDAL_DMD_HELPTOPIC "DMD_HELPTOPIC"
 #define GDAL_DMD_MIMETYPE "DMD_MIMETYPE"
 #define GDAL_DMD_EXTENSION "DMD_EXTENSION"
+#define GDAL_DMD_EXTENSIONS "DMD_EXTENSIONS"
+#define DMD_CONNECTION_PREFIX  "DMD_CONNECTION_PREFIX"
 #define GDAL_DMD_CREATIONOPTIONLIST "DMD_CREATIONOPTIONLIST"
 #define GDAL_DMD_CREATIONDATATYPES "DMD_CREATIONDATATYPES"
+#define GDAL_DMD_CREATIONFIELDDATATYPES "DMD_CREATIONFIELDDATATYPES"
 #define GDAL_DMD_SUBDATASETS "DMD_SUBDATASETS"
 
+#define GDAL_DCAP_OPEN       "DCAP_OPEN"
 #define GDAL_DCAP_CREATE     "DCAP_CREATE"
 #define GDAL_DCAP_CREATECOPY "DCAP_CREATECOPY"
 #define GDAL_DCAP_VIRTUALIO  "DCAP_VIRTUALIO"
+#define DCAP_RASTER          "GDAL_DCAP_RASTER"
+#define DCAP_VECTOR          "GDAL_DCAP_VECTOR"
+#define DCAP_NOTNULL_FIELDS  "GDAL_DCAP_NOTNULL_FIELDS"
+#define DCAP_DEFAULT_FIELDS  "GDAL_DCAP_DEFAULT_FIELDS"
+#define DCAP_NOTNULL_GEOMFIELDS  "GDAL_DCAP_NOTNULL_GEOMFIELDS"
 
 #endif
 
diff --git a/swig/include/java/gdal_java.i b/swig/include/java/gdal_java.i
index 9ffa91a..f7b8fa5 100644
--- a/swig/include/java/gdal_java.i
+++ b/swig/include/java/gdal_java.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdal_java.i 27432 2014-06-03 18:28:26Z goatbar $
+ * $Id: gdal_java.i 28053 2014-12-04 09:31:07Z rouault $
  *
  * Name:     gdal_java.i
  * Project:  GDAL SWIG Interface
@@ -17,6 +17,8 @@
  *
 */
 
+%include java_exceptions.i
+
 %pragma(java) jniclasscode=%{
   private static boolean available = false;
 
@@ -44,8 +46,27 @@
 
 /* This hacks turns the gdalJNI class into a package private class */
 %pragma(java) jniclassimports=%{
+import org.gdal.osr.SpatialReference;
+import org.gdal.ogr.Geometry;
+import org.gdal.ogr.StyleTable;
+import org.gdal.ogr.Layer;
+%}
+
+%pragma(java) moduleimports=%{
+import org.gdal.osr.SpatialReference;
+import org.gdal.ogr.Geometry;
+import org.gdal.ogr.StyleTable;
+import org.gdal.ogr.Layer;
+%}
+
+%typemap(javaimports) GDALDatasetShadow %{
+import org.gdal.osr.SpatialReference;
+import org.gdal.ogr.Geometry;
+import org.gdal.ogr.StyleTable;
+import org.gdal.ogr.Layer;
 %}
 
+
 %pragma(java) modulecode=%{
 
     /* Uninstanciable class */
@@ -145,7 +166,6 @@ import org.gdal.gdalconst.gdalconstConstants;
 
 %}
 
-
 %typemap(javacode) GDALDatasetShadow %{
 
   // Preferred name to match C++ API
@@ -176,6 +196,16 @@ import org.gdal.gdalconst.gdalconstConstants;
       GetGeoTransform(adfGeoTransform);
       return adfGeoTransform;
   }
+
+  public Layer GetLayer(int index)
+  {
+      return GetLayerByIndex(index);
+  }
+
+  public Layer GetLayer(String layerName)
+  {
+      return GetLayerByName(layerName);
+  }
 %}
 
 %{
@@ -205,7 +235,7 @@ import org.gdal.gdalconst.gdalconstConstants;
 static
 GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
                                 int nBands, int* bandMap, int nBandMapArrayLength,
-                                int nPixelSpace, int nLineSpace, int nBandSpace,
+                                GIntBig nPixelSpace, GIntBig nLineSpace, GIntBig nBandSpace,
                                 int bSpacingShouldBeMultipleOfPixelSize );
 
 static CPLErr DatasetRasterIO( GDALDatasetH hDS, GDALRWFlag eRWFlag,
@@ -372,8 +402,8 @@ CPLErr ReadRaster( int xoff, int yoff, int xsize, int ysize,
 %{
 static
 GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
-                             int nPixelSpace, int nLineSpace,
-                             int bSpacingShouldBeMultipleOfPixelSize );
+                                 GIntBig nPixelSpace, GIntBig nLineSpace,
+                                 int bSpacingShouldBeMultipleOfPixelSize );
 
 static CPLErr BandRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag,
                             int xoff, int yoff, int xsize, int ysize,
@@ -859,6 +889,11 @@ import org.gdal.gdalconst.gdalconstConstants;
                   GDALRasterBandShadow* GetMaskBand,
                   GDALColorTableShadow* GetColorTable,
                   GDALColorTableShadow* GetRasterColorTable,
+                  OGRLayerShadow* CreateLayer,
+                  OGRLayerShadow* CopyLayer,
+                  OGRLayerShadow* GetLayerByIndex,
+                  OGRLayerShadow* GetLayerByName,
+                  OGRLayerShadow* ExecuteSQL,
                   CPLXMLNode* getChild,
                   CPLXMLNode* getNext,
                   CPLXMLNode* GetXMLNode,
@@ -912,21 +947,6 @@ import org.gdal.gdalconst.gdalconstConstants;
   }
 %}
 
-%typemap(in) (OGRLayerShadow*)
-{
-    if ($input != NULL)
-    {
-        const jclass klass = jenv->FindClass("org/gdal/ogr/Layer");
-        const jmethodID getCPtr = jenv->GetStaticMethodID(klass, "getCPtr", "(Lorg/gdal/ogr/Layer;)J");
-        $1 = (OGRLayerShadow*) jenv->CallStaticLongMethod(klass, getCPtr, $input);
-    }
-}
-
-%typemap(jni) (OGRLayerShadow*)  "jobject"
-%typemap(jtype) (OGRLayerShadow*)  "org.gdal.ogr.Layer"
-%typemap(jstype) (OGRLayerShadow*)  "org.gdal.ogr.Layer"
-%typemap(javain) (OGRLayerShadow*)  "$javainput"
-
 %include callback.i
 
 %include typemaps_java.i
diff --git a/swig/include/java/ogr_java.i b/swig/include/java/ogr_java.i
index f975412..1ccf5a0 100644
--- a/swig/include/java/ogr_java.i
+++ b/swig/include/java/ogr_java.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_java.i 26302 2013-08-11 16:24:14Z rouault $
+ * $Id: ogr_java.i 27568 2014-08-05 13:10:20Z tamas $
  *
  * Name:     ogr_java.i
  * Project:  GDAL SWIG Interface
@@ -17,7 +17,9 @@
  *
 */
 
+#ifndef FROM_GDAL_I
 %include java_exceptions.i
+#endif
 
 %pragma(java) jniclasscode=%{
   private static boolean available = false;
@@ -58,17 +60,24 @@
 %pragma(java) jniclassimports=%{
 import org.gdal.osr.SpatialReference;
 import org.gdal.osr.CoordinateTransformation;
+import org.gdal.gdal.MajorObject;
 %}
  
 %pragma(java) moduleimports=%{
 import org.gdal.osr.SpatialReference;
+import org.gdal.gdal.MajorObject;
 %}
 
 %typemap(javaimports) OGRLayerShadow %{
 import org.gdal.osr.SpatialReference;
+import org.gdal.gdal.MajorObject;
 %}
 %typemap(javaimports) OGRDataSourceShadow %{
 import org.gdal.osr.SpatialReference;
+import org.gdal.gdal.MajorObject;
+%}
+%typemap(javaimports) OGRDriverShadow %{
+import org.gdal.gdal.MajorObject;
 %}
 %typemap(javaimports) OGRGeomFieldDefnShadow %{
 import org.gdal.osr.SpatialReference;
@@ -99,10 +108,59 @@ import org.gdal.osr.SpatialReference;
 
 %}
 
+#if SWIG_VERSION < 0x020000
+
+%typemap(javabody_derived) OGRLayerShadow %{
+  private long swigCPtr;
+
+  public Layer(long cPtr, boolean cMemoryOwn) {
+    super(ogrJNI.SWIGLayerUpcast(cPtr), cMemoryOwn);
+    swigCPtr = cPtr;
+  }
+
+  public static long getCPtr(Layer obj) {
+    return (obj == null) ? 0 : obj.swigCPtr;
+  }
+%}
+
+#else
+
+%typemap(javabody_derived) OGRLayerShadow %{
+  private long swigCPtr;
+
+  public Layer(long cPtr, boolean cMemoryOwn) {
+    super(ogrJNI.Layer_SWIGUpcast(cPtr), cMemoryOwn);
+    swigCPtr = cPtr;
+  }
+
+  public static long getCPtr(Layer obj) {
+    return (obj == null) ? 0 : obj.swigCPtr;
+  }
+%}
+
+#endif
+
+%typemap(javabody) OGRStyleTableShadow %{
+  private boolean swigCMemOwn;
+  private long swigCPtr;
+
+  public $javaclassname(long cPtr, boolean cMemoryOwn) {
+    if (cPtr == 0)
+        throw new RuntimeException();
+    swigCMemOwn = cMemoryOwn;
+    swigCPtr = cPtr;
+  }
+
+  public static long getCPtr($javaclassname obj) {
+    return (obj == null) ? 0 : obj.swigCPtr;
+  }
+%}
+
 %typemap(javacode) OGRLayerShadow %{
   private Object parentReference;
 
-  protected static long getCPtrAndDisown($javaclassname obj) {
+
+  public static long getCPtrAndDisown($javaclassname obj) {
     if (obj != null)
     {
         obj.swigCMemOwn= false;
@@ -112,7 +170,7 @@ import org.gdal.osr.SpatialReference;
   }
 
   /* Ensure that the GC doesn't collect any parent instance set from Java */
-  protected void addReference(Object reference) {
+  public void addReference(Object reference) {
     parentReference = reference;
   }
 
@@ -405,7 +463,7 @@ class%}
   private long swigCPtr;
   private type ## Native nativeObject;
 
-  protected $javaclassname(long cPtr, boolean cMemoryOwn) {
+  public $javaclassname(long cPtr, boolean cMemoryOwn) {
     if (cPtr == 0)
         throw new RuntimeException();
     swigCPtr = cPtr;
@@ -413,7 +471,7 @@ class%}
         nativeObject = new type ## Native(this, cPtr);
   }
   
-  protected static long getCPtr($javaclassname obj) {
+  public static long getCPtr($javaclassname obj) {
     return (obj == null) ? 0 : obj.swigCPtr;
   }
 %}
@@ -462,6 +520,8 @@ SMART_FINALIZER(Geometry)
 /* End of smart finalizer mechanism                                  */
 /* ----------------------------------------------------------------- */
 
+#ifndef FROM_GDAL_I
 %include callback.i
+#endif
 
 %include typemaps_java.i
diff --git a/swig/include/java/osr_java.i b/swig/include/java/osr_java.i
index 8656c11..008a398 100644
--- a/swig/include/java/osr_java.i
+++ b/swig/include/java/osr_java.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: osr_java.i 25229 2012-11-16 19:06:58Z rouault $
+ * $Id: osr_java.i 27384 2014-05-24 12:28:12Z rouault $
  *
  * Name:     osr_java.i
  * Project:  GDAL SWIG Interface
@@ -19,7 +19,10 @@
 
 %include arrays_java.i
 %include typemaps_java.i
+
+#ifndef FROM_GDAL_I
 %include java_exceptions.i
+#endif
 
 %pragma(java) jniclasscode=%{
   private static boolean available = false;
diff --git a/swig/include/ogr.i b/swig/include/ogr.i
index fed89cc..edaa329 100644
--- a/swig/include/ogr.i
+++ b/swig/include/ogr.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr.i 27071 2014-03-21 21:52:46Z rouault $
+ * $Id: ogr.i 28900 2015-04-14 09:40:34Z rouault $
  *
  * Project:  OGR Core SWIG Interface declarations.
  * Purpose:  OGR declarations.
@@ -27,7 +27,9 @@
  * DEALINGS IN THE SOFTWARE.
  *****************************************************************************/
 
+#ifndef FROM_GDAL_I
 %include "exception.i"
+#endif
 
 #ifdef PERL_CPAN_NAMESPACE
 %module "Geo::OGR"
@@ -37,9 +39,11 @@
 %module ogr
 #endif
 
+#ifndef FROM_GDAL_I
 %inline %{
 typedef char retStringAndCPLFree;
 %}
+#endif
 
 #ifdef SWIGCSHARP
 %include swig_csharp_extensions.i
@@ -59,6 +63,7 @@ typedef char retStringAndCPLFree;
 typedef int OGRwkbByteOrder;
 typedef int OGRwkbGeometryType;
 typedef int OGRFieldType;
+typedef int OGRFieldSubType;
 typedef int OGRJustification;
 #else
 %rename (wkbByteOrder) OGRwkbByteOrder;
@@ -79,8 +84,25 @@ typedef enum
     wkbMultiLineString = 5,
     wkbMultiPolygon = 6,
     wkbGeometryCollection = 7,
-    wkbNone = 100,              /* non-standard, for pure attribute records */
-    wkbLinearRing = 101,        /* non-standard, just for createGeometry() */
+
+    wkbCircularString = 8,  /**< one or more circular arc segments connected end to end,
+                             *   ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCompoundCurve = 9,   /**< sequence of contiguous curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCurvePolygon = 10,   /**< planar surface, defined by 1 exterior boundary
+                             *   and zero or more interior boundaries, that are curves.
+                             *    ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiCurve = 11,     /**< GeometryCollection of Curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiSurface = 12,   /**< GeometryCollection of Surfaces, ISO SQL/MM Part 3. GDAL >= 2.0 */
+
+    wkbNone = 100,          /**< non-standard, for pure attribute records */
+    wkbLinearRing = 101,    /**< non-standard, just for createGeometry() */
+
+    wkbCircularStringZ = 1008,  /**< wkbCircularString with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCompoundCurveZ = 1009,   /**< wkbCompoundCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbCurvePolygonZ = 1010,    /**< wkbCurvePolygon with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiCurveZ = 1011,      /**< wkbMultiCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+    wkbMultiSurfaceZ = 1012,    /**< wkbMultiSurface with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
+
     wkbPoint25D = -2147483647,   /* 2.5D extensions as per 99-402 */
     wkbLineString25D = -2147483646,
     wkbPolygon25D = -2147483645,
@@ -104,9 +126,24 @@ typedef enum
   /** Raw Binary data */                        OFTBinary = 8,
   /** Date */                                   OFTDate = 9,
   /** Time */                                   OFTTime = 10,
-  /** Date and Time */                          OFTDateTime = 11
+  /** Date and Time */                          OFTDateTime = 11,
+  /** Single 64bit integer */                   OFTInteger64 = 12,
+  /** List of 64bit integers */                 OFTInteger64List = 13
 } OGRFieldType;
 
+%rename (FieldSubType) OGRFieldSubType;
+typedef enum
+{
+    /** No subtype. This is the default value */        OFSTNone = 0,
+    /** Boolean integer. Only valid for OFTInteger
+        and OFTIntegerList.*/                           OFSTBoolean = 1,
+    /** Signed 16-bit integer. Only valid for OFTInteger and OFTIntegerList. */
+                                                        OFSTInt16 = 2,
+    /** Single precision (32 bit) floatint point. Only valid for OFTReal and OFTRealList. */
+                                                        OFSTFloat32 = 3
+} OGRFieldSubType;
+
+
 %rename (Justification) OGRJustification;
 typedef enum 
 {
@@ -120,6 +157,7 @@ typedef enum
 #include <iostream>
 using namespace std;
 
+#include "gdal.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
 #include "ogr_core.h"
@@ -127,6 +165,8 @@ using namespace std;
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
+typedef void GDALMajorObjectShadow;
+
 #ifdef DEBUG 
 typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
 typedef struct OGRDriverHS OGRDriverShadow;
@@ -178,15 +218,29 @@ typedef void retGetPoints;
 %constant wkbMultiLineString = 5;
 %constant wkbMultiPolygon = 6;
 %constant wkbGeometryCollection = 7;
+
+%constant wkbCircularString = 8;
+%constant wkbCompoundCurve = 9;
+%constant wkbCurvePolygon = 10;
+%constant wkbMultiCurve = 11;
+%constant wkbMultiSurface = 12;
+
 %constant wkbNone = 100;
 %constant wkbLinearRing = 101;
-%constant wkbPoint25D =              wkbPoint              + wkb25DBit;
-%constant wkbLineString25D =         wkbLineString         + wkb25DBit;
-%constant wkbPolygon25D =            wkbPolygon            + wkb25DBit;
-%constant wkbMultiPoint25D =         wkbMultiPoint         + wkb25DBit;
-%constant wkbMultiLineString25D =    wkbMultiLineString    + wkb25DBit;
-%constant wkbMultiPolygon25D =       wkbMultiPolygon       + wkb25DBit;
-%constant wkbGeometryCollection25D = wkbGeometryCollection + wkb25DBit;
+
+%constant wkbCircularStringZ = 1008;
+%constant wkbCompoundCurveZ = 1009;
+%constant wkbCurvePolygonZ = 1010;
+%constant wkbMultiCurveZ = 1011;
+%constant wkbMultiSurfaceZ = 1012;
+
+%constant wkbPoint25D =              0x80000001;
+%constant wkbLineString25D =         0x80000002;
+%constant wkbPolygon25D =            0x80000003;
+%constant wkbMultiPoint25D =         0x80000004;
+%constant wkbMultiLineString25D =    0x80000005;
+%constant wkbMultiPolygon25D =       0x80000006;
+%constant wkbGeometryCollection25D = 0x80000007;
 
 %constant OFTInteger = 0;
 %constant OFTIntegerList= 1;
@@ -200,6 +254,13 @@ typedef void retGetPoints;
 %constant OFTDate = 9;
 %constant OFTTime = 10;
 %constant OFTDateTime = 11;
+%constant OFTInteger64 = 12;
+%constant OFTInteger64List = 13;
+
+%constant OFSTNone = 0;
+%constant OFSTBoolean = 1;
+%constant OFSTInt16 = 2;
+%constant OFSTFloat32 = 3;
 
 %constant OJUndefined = 0;
 %constant OJLeft = 1;
@@ -213,7 +274,15 @@ typedef void retGetPoints;
 %constant ALTER_NAME_FLAG = 1;
 %constant ALTER_TYPE_FLAG = 2;
 %constant ALTER_WIDTH_PRECISION_FLAG = 4;
-%constant ALTER_ALL_FLAG = 1 + 2 + 4;
+%constant ALTER_NULLABLE_FLAG = 8;
+%constant ALTER_DEFAULT_FLAG = 16;
+%constant ALTER_ALL_FLAG = 1 + 2 + 4 + 8 + 16;
+
+%constant F_VAL_NULL= 0x00000001; /**< Validate that fields respect not-null constraints */
+%constant F_VAL_GEOM_TYPE = 0x00000002; /**< Validate that geometries respect geometry column type */
+%constant F_VAL_WIDTH = 0x00000004; /**< Validate that (string) fields respect field width */
+%constant F_VAL_ALLOW_NULL_WHEN_DEFAULT = 0x00000008; /***<Allow fields that are null when there's an associated default value. */
+%constant F_VAL_ALL = 0xFFFFFFFF; /**< Enable all validation tests */
 
 %constant char *OLCRandomRead          = "RandomRead";
 %constant char *OLCSequentialWrite     = "SequentialWrite";
@@ -231,13 +300,20 @@ typedef void retGetPoints;
 %constant char *OLCStringsAsUTF8       = "StringsAsUTF8";
 %constant char *OLCIgnoreFields        = "IgnoreFields";
 %constant char *OLCCreateGeomField     = "CreateGeomField";
+%constant char *OLCCurveGeometries     = "CurveGeometries";
 
 %constant char *ODsCCreateLayer        = "CreateLayer";
 %constant char *ODsCDeleteLayer        = "DeleteLayer";
 %constant char *ODsCCreateGeomFieldAfterCreateLayer  = "CreateGeomFieldAfterCreateLayer";
+%constant char *ODsCCurveGeometries    = "CurveGeometries";
+%constant char *ODsCTransactions       = "Transactions";
+%constant char *ODsCEmulatedTransactions = "EmulatedTransactions";
 
 %constant char *ODrCCreateDataSource   = "CreateDataSource";
 %constant char *ODrCDeleteDataSource   = "DeleteDataSource";
+
+%constant char *OLMD_FID64             = "OLMD_FID64";
+
 #else
 typedef int OGRErr;
 
@@ -262,16 +338,23 @@ typedef int OGRErr;
 #define OLCFastSetNextByIndex  "FastSetNextByIndex"
 #define OLCStringsAsUTF8       "StringsAsUTF8"
 #define OLCCreateGeomField     "CreateGeomField"
+#define OLCCurveGeometries     "CurveGeometries"
 
 #define ODsCCreateLayer        "CreateLayer"
 #define ODsCDeleteLayer        "DeleteLayer"
 #define ODsCCreateGeomFieldAfterCreateLayer   "CreateGeomFieldAfterCreateLayer"
+#define ODsCCurveGeometries    "CurveGeometries"
+#define ODsCTransactions       "Transactions"
+#define ODsCEmulatedTransactions "EmulatedTransactions"
 
 #define ODrCCreateDataSource   "CreateDataSource"
 #define ODrCDeleteDataSource   "DeleteDataSource"
+
+#define OLMD_FID64             "OLMD_FID64"
+
 #endif
 
-#if defined(SWIGCSHARP) || defined(SWIGJAVA)
+#if defined(SWIGCSHARP) || defined(SWIGJAVA) || defined(SWIGPYTHON)
 
 #define OGRERR_NONE                0
 #define OGRERR_NOT_ENOUGH_DATA     1    /* not enough data to deserialize */
@@ -281,6 +364,8 @@ typedef int OGRErr;
 #define OGRERR_CORRUPT_DATA        5
 #define OGRERR_FAILURE             6
 #define OGRERR_UNSUPPORTED_SRS     7
+#define OGRERR_INVALID_HANDLE      8
+#define OGRERR_NON_EXISTING_FEATURE 9
 
 #endif
 
@@ -307,8 +392,28 @@ typedef int OGRErr;
  * This was primarily a problem in the perl bindings because
  * perl names things differently when using -proxy (default) argument
  */
+#define FROM_OGR_I
 %import osr.i
 
+#ifndef FROM_GDAL_I
+/* For Python we don't import, but include MajorObject.i to avoid */
+/* cyclic dependency betwenn gdal.py and ogr.py. Python2 is fine with that */
+/* but Python3 not */
+/* We should probably define a new module for MajorObject, or merge gdal and ogr */
+/* modules */
+#if defined(SWIGPYTHON)
+%{
+#include "gdal.h"
+%}
+typedef int CPLErr;
+#define FROM_PYTHON_OGR_I
+%include MajorObject.i
+#undef FROM_PYTHON_OGR_I
+#else /* defined(SWIGPYTHON) */
+%import MajorObject.i
+#endif /* defined(SWIGPYTHON) */
+#endif /* FROM_GDAL_I */
+
 /************************************************************************/
 /*                               OGREnvelope                            */
 /************************************************************************/
@@ -335,8 +440,6 @@ typedef struct
 } OGREnvelope3D;
 #endif
 
-#ifndef GDAL_BINDINGS
-
 /************************************************************************/
 /*                          OGRStyleTable                               */
 /************************************************************************/
@@ -396,9 +499,16 @@ public:
 /*                              OGRDriver                               */
 /************************************************************************/
 
+#ifndef FROM_GDAL_I
+
 %rename (Driver) OGRDriverShadow;
 
+#ifdef SWIGCSHARP
+/* Because of issue with CSharp to handle different inheritance from class in different namespaces  */
 class OGRDriverShadow {
+#else
+class OGRDriverShadow : public GDALMajorObjectShadow {
+#endif
   OGRDriverShadow();
   ~OGRDriverShadow();
 public:
@@ -479,8 +589,6 @@ public:
 
 } /* %extend */
 }; /* class OGRDriverShadow */
-#endif /* GDAL_BINDINGS */
-
 
 /************************************************************************/
 /*                            OGRDataSource                             */
@@ -489,7 +597,12 @@ public:
 
 %rename (DataSource) OGRDataSourceShadow;
 
+#ifdef SWIGCSHARP
+/* Because of issue with CSharp to handle different inheritance from class in different namespaces  */
 class OGRDataSourceShadow {
+#else
+class OGRDataSourceShadow : public GDALMajorObjectShadow {
+#endif
   OGRDataSourceShadow() {
   }
 public:
@@ -531,6 +644,10 @@ public:
     return OGR_DS_SyncToDisk(self);
   }
   
+  void FlushCache() {
+    GDALFlushCache( self );
+  }
+
   /* Note that datasources own their layers */
 #ifndef SWIGJAVA
   %feature( "kwargs" ) CreateLayer;
@@ -608,17 +725,41 @@ public:
         OGR_DS_SetStyleTable(self, (OGRStyleTableH) table);
   }
 
+#ifndef SWIGJAVA
+  %feature( "kwargs" ) StartTransaction;
+#endif
+  OGRErr StartTransaction(int force = FALSE)
+  {
+    return GDALDatasetStartTransaction(self, force);
+  }
+
+  OGRErr CommitTransaction()
+  {
+    return GDALDatasetCommitTransaction(self);
+  }
+
+  OGRErr RollbackTransaction()
+  {
+    return GDALDatasetRollbackTransaction(self);
+  }
 } /* %extend */
 
 
 }; /* class OGRDataSourceShadow */
 
+#endif /* FROM_GDAL_I */
+
 /************************************************************************/
 /*                               OGRLayer                               */
 /************************************************************************/
 
 %rename (Layer) OGRLayerShadow;
+#ifdef SWIGCSHARP
+/* Because of issue with CSharp to handle different inheritance from class in different namespaces  */
 class OGRLayerShadow {
+#else
+class OGRLayerShadow : public GDALMajorObjectShadow {
+#endif
   OGRLayerShadow();
   ~OGRLayerShadow();
 public:
@@ -682,7 +823,7 @@ public:
   }
 
 %newobject GetFeature;
-  OGRFeatureShadow *GetFeature(long fid) {
+  OGRFeatureShadow *GetFeature(GIntBig fid) {
     return (OGRFeatureShadow*) OGR_L_GetFeature(self, fid);
   }
   
@@ -691,7 +832,7 @@ public:
     return (OGRFeatureShadow*) OGR_L_GetNextFeature(self);
   }
   
-  OGRErr SetNextByIndex(long new_index) {
+  OGRErr SetNextByIndex(GIntBig new_index) {
     return OGR_L_SetNextByIndex(self, new_index);
   }
   
@@ -705,7 +846,7 @@ public:
   }
 %clear OGRFeatureShadow *feature;
 
-  OGRErr DeleteFeature(long fid) {
+  OGRErr DeleteFeature(GIntBig fid) {
     return OGR_L_DeleteFeature(self, fid);
   }
   
@@ -720,7 +861,7 @@ public:
 #ifndef SWIGJAVA
   %feature( "kwargs" ) GetFeatureCount;  
 #endif
-  int GetFeatureCount(int force=1) {
+  GIntBig GetFeatureCount(int force=1) {
     return OGR_L_GetFeatureCount(self, force);
   }
   
@@ -1114,6 +1255,24 @@ public:
 #endif
   /* ------------------------------------------- */  
 
+  /* ---- GetFieldAsInteger64 ------------------ */
+
+  GIntBig GetFieldAsInteger64(int id) {
+    return OGR_F_GetFieldAsInteger64(self, id);
+  }
+
+#ifndef SWIGPERL
+  GIntBig GetFieldAsInteger64(const char* name) {
+      int i = OGR_F_GetFieldIndex(self, name);
+      if (i == -1)
+      CPLError(CE_Failure, 1, "No such field: '%s'", name);
+      else
+      return OGR_F_GetFieldAsInteger64(self, i);
+      return 0;
+  }
+#endif
+  /* ------------------------------------------- */  
+
   /* ---- GetFieldAsDouble --------------------- */
 
   double GetFieldAsDouble(int id) {
@@ -1133,14 +1292,16 @@ public:
   /* ------------------------------------------- */  
 
   %apply (int *OUTPUT) {(int *)};
+  %apply (float *OUTPUT) {(float *)};
   void GetFieldAsDateTime(int id, int *pnYear, int *pnMonth, int *pnDay,
-			  int *pnHour, int *pnMinute, int *pnSecond,
+			  int *pnHour, int *pnMinute, float *pfSecond,
 			  int *pnTZFlag) {
-      OGR_F_GetFieldAsDateTime(self, id, pnYear, pnMonth, pnDay,
-			       pnHour, pnMinute, pnSecond,
+      OGR_F_GetFieldAsDateTimeEx(self, id, pnYear, pnMonth, pnDay,
+			       pnHour, pnMinute, pfSecond,
 			       pnTZFlag);
   }
   %clear (int *);
+  %clear (float *);
 
 #if defined(SWIGJAVA)
   retIntArray GetFieldAsIntegerList(int id, int *nLen, const int **pList) {
@@ -1161,6 +1322,12 @@ public:
   }
 #endif
 
+#if defined(SWIGPYTHON)
+  void GetFieldAsInteger64List(int id, int *nLen, const GIntBig **pList) {
+      *pList = OGR_F_GetFieldAsInteger64List(self, id, nLen);
+  }
+#endif
+
 #if defined(SWIGJAVA)
   retDoubleArray GetFieldAsDoubleList(int id, int *nLen, const double **pList) {
       *pList = OGR_F_GetFieldAsDoubleList(self, id, nLen);
@@ -1198,6 +1365,62 @@ public:
   }
 #endif
 
+#ifndef SWIGCSHARP
+#ifdef SWIGJAVA
+%apply (GByte* outBytes) {GByte*};
+  GByte* GetFieldAsBinary(int id, int *nLen, char **pBuf) {
+    GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+    *pBuf = (char*)malloc(*nLen);
+    memcpy(*pBuf, pabyBlob, *nLen);
+    return (GByte*)*pBuf;
+  }
+
+  GByte* GetFieldAsBinary(const char* name, int *nLen, char **pBuf) {
+      int id = OGR_F_GetFieldIndex(self, name);
+      if (id == -1)
+      {
+        CPLError(CE_Failure, 1, "No such field: '%s'", name);
+        return NULL;
+      }
+      else
+      {
+        GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+        *pBuf = (char*)malloc(*nLen);
+        memcpy(*pBuf, pabyBlob, *nLen);
+        return (GByte*)*pBuf;
+      }
+  }
+%clear GByte*;
+#else
+  OGRErr GetFieldAsBinary( int id, int *nLen, char **pBuf) {
+    GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+    *pBuf = (char*)malloc(*nLen);
+    memcpy(*pBuf, pabyBlob, *nLen);
+    return OGRERR_NONE;
+  }
+
+#ifndef SWIGPERL
+  OGRErr GetFieldAsBinary(const char* name, int *nLen, char **pBuf) {
+      int id = OGR_F_GetFieldIndex(self, name);
+      if (id == -1)
+      {
+        CPLError(CE_Failure, 1, "No such field: '%s'", name);
+        return OGRERR_FAILURE;
+      }
+      else
+      {
+        GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+        *pBuf = (char*)malloc(*nLen);
+        memcpy(*pBuf, pabyBlob, *nLen);
+        return OGRERR_NONE;
+      }
+  }
+#endif /* SWIGPERL */ 
+
+#endif /* SWIGJAVA */
+
+#endif /* SWIGCSHARP */
+
   /* ---- IsFieldSet --------------------------- */
   bool IsFieldSet(int id) {
     return (OGR_F_IsFieldSet(self, id) > 0);
@@ -1221,11 +1444,11 @@ public:
       return OGR_F_GetGeomFieldIndex(self, name);
   }
 
-  int GetFID() {
+  GIntBig GetFID() {
     return OGR_F_GetFID(self);
   }
   
-  OGRErr SetFID(int fid) {
+  OGRErr SetFID(GIntBig fid) {
     return OGR_F_SetFID(self, fid);
   }
   
@@ -1267,7 +1490,12 @@ public:
   }
 #endif
   %clear (const char* value );
-  
+
+  void SetFieldInteger64(int id, GIntBig value) {
+    OGR_F_SetFieldInteger64(self, id, value);
+  }
+
+#ifndef SWIGPYTHON
   void SetField(int id, int value) {
     OGR_F_SetFieldInteger(self, id, value);
   }
@@ -1280,7 +1508,8 @@ public:
       else
 	  OGR_F_SetFieldInteger(self, i, value);
   }
-#endif
+#endif /* SWIGPERL */
+#endif /* SWIGPYTHON */
   
   void SetField(int id, double value) {
     OGR_F_SetFieldDouble(self, id, value);
@@ -1297,22 +1526,22 @@ public:
 #endif
   
   void SetField( int id, int year, int month, int day,
-                             int hour, int minute, int second, 
+                             int hour, int minute, float second, 
                              int tzflag ) {
-    OGR_F_SetFieldDateTime(self, id, year, month, day,
+    OGR_F_SetFieldDateTimeEx(self, id, year, month, day,
                              hour, minute, second, 
                              tzflag);
   }
 
 #ifndef SWIGPERL  
   void SetField(const char* name, int year, int month, int day,
-                             int hour, int minute, int second, 
+                             int hour, int minute, float second, 
                              int tzflag ) {
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1)
 	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
       else
-	  OGR_F_SetFieldDateTime(self, i, year, month, day,
+	  OGR_F_SetFieldDateTimeEx(self, i, year, month, day,
 				 hour, minute, second, 
 				 tzflag);
   }
@@ -1322,6 +1551,12 @@ public:
       OGR_F_SetFieldIntegerList(self, id, nList, pList);
   }
 
+#if defined(SWIGPYTHON)
+  void SetFieldInteger64List(int id, int nList, GIntBig *pList) {
+      OGR_F_SetFieldInteger64List(self, id, nList, pList);
+  }
+#endif
+
   void SetFieldDoubleList(int id, int nList, double *pList) {
       OGR_F_SetFieldDoubleList(self, id, nList, pList);
   }
@@ -1387,21 +1622,31 @@ public:
 
   /* ---- GetFieldType ------------------------- */  
   OGRFieldType GetFieldType(int id) {
-    return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, id));
+      OGRFieldDefnH fd = OGR_F_GetFieldDefnRef( self,  id );
+      if (fd)
+          return (OGRFieldType) OGR_Fld_GetType( fd );
+      else
+          return (OGRFieldType)0;
   }
   
   OGRFieldType GetFieldType(const char* name) {
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1) {
-	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
-	  return (OGRFieldType)0;
+          CPLError(CE_Failure, 1, "No such field: '%s'", name);
+          return (OGRFieldType)0;
       } else
-	  return (OGRFieldType) OGR_Fld_GetType( 
-	      OGR_F_GetFieldDefnRef( self,  i )
-	      );
+          return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, i ) );
   }
   /* ------------------------------------------- */  
   
+  int Validate( int flags = OGR_F_VAL_ALL, int bEmitError = TRUE ) {
+    return OGR_F_Validate(self, flags, bEmitError);
+  }
+
+  void FillUnsetWithDefault( int bNotNullableOnly = FALSE, char** options = NULL ) {
+    OGR_F_FillUnsetWithDefault(self, bNotNullableOnly, options );
+  }
+
 } /* %extend */
 
 
@@ -1427,8 +1672,18 @@ public:
             case wkbMultiLineString:
             case wkbMultiPolygon:
             case wkbGeometryCollection:
+            case wkbCircularString:
+            case wkbCompoundCurve:
+            case wkbCurvePolygon:
+            case wkbMultiCurve:
+            case wkbMultiSurface:
             case wkbNone:
             /*case wkbLinearRing:*/
+            case wkbCircularStringZ:
+            case wkbCompoundCurveZ:
+            case wkbCurvePolygonZ:
+            case wkbMultiCurveZ:
+            case wkbMultiSurfaceZ:
             case wkbPoint25D:
             case wkbLineString25D:
             case wkbPolygon25D:
@@ -1571,6 +1826,8 @@ public:
             case OFTDate:
             case OFTTime:
             case OFTDateTime:
+            case OFTInteger64:
+            case OFTInteger64List:
                 return TRUE;
             default:
                 CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field type value");
@@ -1579,6 +1836,22 @@ public:
     }
 %}
 
+%{
+    static int ValidateOGRFieldSubType(OGRFieldSubType field_subtype)
+    {
+        switch(field_subtype)
+        {
+            case OFSTNone:
+            case OFSTBoolean:
+            case OFSTInt16:
+            case OFSTFloat32:
+                return TRUE;
+            default:
+                CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field subtype value");
+                return FALSE;
+        }
+    }
+%}
 
 class OGRFieldDefnShadow {
   OGRFieldDefnShadow();
@@ -1620,7 +1893,16 @@ public:
     if (ValidateOGRFieldType(type))
         OGR_Fld_SetType(self, type);
   }
-  
+
+  OGRFieldSubType GetSubType() {
+    return OGR_Fld_GetSubType(self);
+  }
+
+  void SetSubType(OGRFieldSubType type) {
+    if (ValidateOGRFieldSubType(type))
+        OGR_Fld_SetSubType(self, type);
+  }
+
   OGRJustification GetJustify() {
     return OGR_Fld_GetJustify(self);
   }
@@ -1661,9 +1943,28 @@ public:
   }
 
   void SetIgnored(int bIgnored ) {
-    return OGR_Fld_SetIgnored( self, bIgnored );
+    OGR_Fld_SetIgnored( self, bIgnored );
+  }
+
+  int IsNullable() {
+    return OGR_Fld_IsNullable( self );
+  }
+
+  void SetNullable(int bNullable ) {
+    OGR_Fld_SetNullable( self, bNullable );
+  }
+
+  const char* GetDefault() {
+    return OGR_Fld_GetDefault( self );
   }
 
+  void SetDefault(const char* pszValue ) {
+    OGR_Fld_SetDefault( self, pszValue );
+  }
+
+  int IsDefaultDriverSpecific() {
+    return OGR_Fld_IsDefaultDriverSpecific( self );
+  }
 } /* %extend */
 
 
@@ -1737,6 +2038,13 @@ public:
     OGR_GFld_SetIgnored( self, bIgnored );
   }
 
+  int IsNullable() {
+    return OGR_GFld_IsNullable( self );
+  }
+
+  void SetNullable(int bNullable ) {
+    return OGR_GFld_SetNullable( self, bNullable );
+  }
 } /* %extend */
 
 
@@ -1932,6 +2240,16 @@ OGRGeometryShadow* ForceToMultiLineString( OGRGeometryShadow *geom_in ) {
 }
 %}
 
+%newobject ForceTo;
+/* Contrary to the C/C++ method, the passed geometry is preserved */
+/* This avoids dirty trick for Java */
+%inline %{
+OGRGeometryShadow* ForceTo( OGRGeometryShadow *geom_in, OGRwkbGeometryType eTargetType, char** options = NULL ) {
+ if (geom_in == NULL)
+     return NULL;
+ return (OGRGeometryShadow* )OGR_G_ForceTo( OGR_G_Clone(geom_in), eTargetType, options );
+}
+%}
 
 /************************************************************************/
 /*                             OGRGeometry                              */
@@ -1984,6 +2302,10 @@ public:
     return OGR_G_ExportToWkt(self, argout);
   }
 
+  OGRErr ExportToIsoWkt( char** argout ) {
+    return OGR_G_ExportToIsoWkt(self, argout);
+  }
+
 #ifndef SWIGCSHARP
 #ifdef SWIGJAVA
 %apply (GByte* outBytes) {GByte*};
@@ -1993,6 +2315,13 @@ public:
     OGR_G_ExportToWkb(self, byte_order, (unsigned char*) *pBuf );
     return (GByte*)*pBuf;
   }
+
+  GByte* ExportToIsoWkb( int *nLen, char **pBuf, OGRwkbByteOrder byte_order=wkbXDR ) {
+    *nLen = OGR_G_WkbSize( self );
+    *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
+    OGR_G_ExportToIsoWkb(self, byte_order, (unsigned char*) *pBuf );
+    return (GByte*)*pBuf;
+  }
 %clear GByte*;
 #else
   %feature("kwargs") ExportToWkb;
@@ -2001,6 +2330,13 @@ public:
     *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
     return OGR_G_ExportToWkb(self, byte_order, (unsigned char*) *pBuf );
   }
+
+  %feature("kwargs") ExportToIsoWkb;
+  OGRErr ExportToIsoWkb( int *nLen, char **pBuf, OGRwkbByteOrder byte_order=wkbXDR ) {
+    *nLen = OGR_G_WkbSize( self );
+    *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
+    return OGR_G_ExportToIsoWkb(self, byte_order, (unsigned char*) *pBuf );
+  }
 #endif
 #endif
 
@@ -2443,6 +2779,32 @@ public:
     return OGR_G_GetDimension(self);
   }
 
+  int HasCurveGeometry(int bLookForCircular = FALSE)
+  {
+        return OGR_G_HasCurveGeometry(self, bLookForCircular);
+  }
+
+  %newobject GetLinearGeometry;
+#ifndef SWIGJAVA
+  %feature("kwargs") GetLinearGeometry;  
+#endif
+  OGRGeometryShadow* GetLinearGeometry(double dfMaxAngleStepSizeDegrees = 0.0,char** options = NULL) {
+    return (OGRGeometryShadow* )OGR_G_GetLinearGeometry(self, dfMaxAngleStepSizeDegrees, options);
+  }
+
+  %newobject GetCurveGeometry;
+#ifndef SWIGJAVA
+  %feature("kwargs") GetCurveGeometry;  
+#endif
+  OGRGeometryShadow* GetCurveGeometry(char** options = NULL) {
+    return (OGRGeometryShadow* )OGR_G_GetCurveGeometry(self, options);
+  }
+
+  %newobject Value;
+  OGRGeometryShadow* Value(double dfDistance) {
+    return OGR_G_Value(self, dfDistance);
+  }
+
 } /* %extend */
 
 }; /* class OGRGeometryShadow */
@@ -2452,6 +2814,8 @@ public:
 /*                        Other misc functions.                         */
 /************************************************************************/
 
+#ifndef FROM_GDAL_I
+
 %{
 char const *OGRDriverShadow_get_name( OGRDriverShadow *h ) {
   return OGR_Dr_GetName( h );
@@ -2470,9 +2834,9 @@ char const *OGRDataSourceShadow_name_get( OGRDataSourceShadow *h ) {
 }
 %}
 
-#ifndef GDAL_BINDINGS
 int OGRGetDriverCount();
-#endif
+
+#endif /* FROM_GDAL_I */
 
 int OGRGetOpenDSCount();
 
@@ -2486,6 +2850,53 @@ const char *OGRGeometryTypeToName( OGRwkbGeometryType eType );
 %rename (GetFieldTypeName) OGR_GetFieldTypeName;
 const char * OGR_GetFieldTypeName(OGRFieldType type);
 
+%rename (GetFieldSubTypeName) OGR_GetFieldSubTypeName;
+const char * OGR_GetFieldSubTypeName(OGRFieldSubType type);
+
+%rename (GT_Flatten) OGR_GT_Flatten;
+OGRwkbGeometryType OGR_GT_Flatten( OGRwkbGeometryType eType );
+
+%rename (GT_SetZ) OGR_GT_SetZ;
+OGRwkbGeometryType OGR_GT_SetZ( OGRwkbGeometryType eType );
+
+%inline  %{
+OGRwkbGeometryType GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM = FALSE)
+{
+    return OGR_GT_SetModifier(eType, bSetZ, bSetM);
+}
+%}
+
+%rename (GT_HasZ) OGR_GT_HasZ;
+int                OGR_GT_HasZ( OGRwkbGeometryType eType );
+
+%rename (GT_IsSubClassOf) OGR_GT_IsSubClassOf;
+int                OGR_GT_IsSubClassOf( OGRwkbGeometryType eType,
+                                                OGRwkbGeometryType eSuperType );
+
+%rename (GT_IsCurve) OGR_GT_IsCurve;
+int                OGR_GT_IsCurve( OGRwkbGeometryType );
+
+%rename (GT_IsSurface) OGR_GT_IsSurface;
+int                OGR_GT_IsSurface( OGRwkbGeometryType );
+
+%rename (GT_IsNonLinear) OGR_GT_IsNonLinear;
+int                OGR_GT_IsNonLinear( OGRwkbGeometryType );
+
+%rename (GT_GetCollection) OGR_GT_GetCollection;
+OGRwkbGeometryType OGR_GT_GetCollection( OGRwkbGeometryType eType );
+
+%rename (GT_GetCurve) OGR_GT_GetCurve;
+OGRwkbGeometryType OGR_GT_GetCurve( OGRwkbGeometryType eType );
+
+%rename (GT_GetLinear) OGR_GT_GetLinear;
+OGRwkbGeometryType OGR_GT_GetLinear( OGRwkbGeometryType eType );
+
+%rename (SetNonLinearGeometriesEnabledFlag) OGRSetNonLinearGeometriesEnabledFlag;
+void OGRSetNonLinearGeometriesEnabledFlag( int bFlag );
+
+%rename (GetNonLinearGeometriesEnabledFlag) OGRGetNonLinearGeometriesEnabledFlag;
+int OGRGetNonLinearGeometriesEnabledFlag(void);
+
 %inline %{
   OGRDataSourceShadow* GetOpenDS(int ds_number) {
     OGRDataSourceShadow* layer = (OGRDataSourceShadow*) OGRGetOpenDS(ds_number);
@@ -2493,6 +2904,8 @@ const char * OGR_GetFieldTypeName(OGRFieldType type);
   }
 %}
 
+#if !(defined(FROM_GDAL_I) && (defined(SWIGJAVA) || defined(SWIGPYTHON)))
+
 %newobject Open;
 #ifndef SWIGJAVA
 %feature( "kwargs" ) Open;
@@ -2532,7 +2945,10 @@ const char * OGR_GetFieldTypeName(OGRFieldType type);
   }
 %}
 
-#ifndef GDAL_BINDINGS
+#endif /* !(defined(FROM_GDAL_I) && (defined(SWIGJAVA) || defined(SWIGPYTHON))) */
+
+#ifndef FROM_GDAL_I
+
 %inline %{
 OGRDriverShadow* GetDriverByName( char const *name ) {
   return (OGRDriverShadow*) OGRGetDriverByName( name );
@@ -2542,7 +2958,6 @@ OGRDriverShadow* GetDriver(int driver_number) {
   return (OGRDriverShadow*) OGRGetDriver(driver_number);
 }
 %}
-#endif
 
 #if defined(SWIGPYTHON) || defined(SWIGJAVA)
 /* FIXME: other bindings should also use those typemaps to avoid memory leaks */
@@ -2599,6 +3014,7 @@ OGRDriverShadow* GetDriver(int driver_number) {
 #endif
 %clear char **;
 
+#endif /* FROM_GDAL_I */
 
 #ifdef SWIGJAVA
 class FeatureNative {
@@ -2617,6 +3033,8 @@ class GeometryNative {
 /*                            TermProgress()                            */
 /************************************************************************/
 
+#ifndef FROM_GDAL_I
+
 #if !defined(SWIGCSHARP) && !defined(SWIGJAVA)
 %rename (TermProgress_nocb) GDALTermProgress_nocb;
 %feature( "kwargs" ) GDALTermProgress_nocb;
@@ -2632,6 +3050,8 @@ int GDALTermProgress( double, const char *, void * );
 %nocallback;
 #endif
 
+#endif /* FROM_GDAL_I */
+
 //************************************************************************
 //
 // Language specific extensions
diff --git a/swig/include/ogr_error_map.i b/swig/include/ogr_error_map.i
index 63e5cba..b635d93 100644
--- a/swig/include/ogr_error_map.i
+++ b/swig/include/ogr_error_map.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogr_error_map.i 12444 2007-10-16 17:48:23Z ajolma $
+ * $Id: ogr_error_map.i 28809 2015-03-28 17:10:07Z rouault $
  *
  * Project:  GDAL SWIG Interfaces.
  * Purpose:  OGRErr handling typemap.
@@ -56,6 +56,8 @@ OGRErrMessages( int rc ) {
     return "OGR Error: Unsupported SRS";
   case OGRERR_INVALID_HANDLE:
     return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
   default:
     return "OGR Error: Unknown";
   }
diff --git a/swig/include/osr.i b/swig/include/osr.i
index 4f6e38b..a0132f5 100644
--- a/swig/include/osr.i
+++ b/swig/include/osr.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: osr.i 26938 2014-02-13 20:15:52Z rcoup $
+ * $Id: osr.i 28972 2015-04-22 10:39:11Z rouault $
  *
  * Project:  GDAL SWIG Interfaces.
  * Purpose:  OGRSpatialReference related declarations.
@@ -59,9 +59,11 @@
 %javaconst(0);
 #endif
 
+#if !defined(FROM_GDAL_I) && !defined(FROM_OGR_I)
 %inline %{
 typedef char retStringAndCPLFree;
 %}
+#endif
 
 %{
 #include <iostream>
@@ -204,12 +206,16 @@ public:
 /* FIXME : all bindings should avoid using the #else case */
 /* as the deallocator for the char* is delete[] where as */
 /* OSRExportToPrettyWkt uses CPL/VSIMalloc() */
-#if defined(SWIGCSHARP)||defined(SWIGPYTHON)||defined(SWIGJAVA)||defined(SWIGPERL)
+#if defined(SWIGCSHARP)||defined(SWIGPYTHON)||defined(SWIGJAVA)
   retStringAndCPLFree *__str__() {
     char *buf = 0;
     OSRExportToPrettyWkt( self, &buf, 0 );
     return buf;
   }
+/* Adding __str__ to Perl bindings makes Swig to use overloading,
+   which is undesirable since it is not used elsewhere in these
+   bindings, and causes side effects. */
+#elif defined(SWIGPERL)
 #else
 %newobject __str__;
   char *__str__() {
@@ -808,11 +814,10 @@ public:
     return OSRImportFromMICoordSys( self, pszCoordSys );
   }
 
-%apply Pointer NONNULL {char const *projParms};
-  OGRErr ImportFromOzi( char const *datum,
-                        char const *proj,
-                        char const *projParms ) {
-    return OSRImportFromOzi( self, datum, proj, projParms );
+%apply Pointer NONNULL {const char* const *papszLines};
+%apply (char **options) { (const char* const *papszLines) };
+  OGRErr ImportFromOzi( const char* const *papszLines ) {
+    return OSRImportFromOzi( self, papszLines );
   }
 
   OGRErr ExportToWkt( char **argout ) {
diff --git a/swig/include/perl/callback.i b/swig/include/perl/callback.i
index 1a39305..cab94ce 100644
--- a/swig/include/perl/callback.i
+++ b/swig/include/perl/callback.i
@@ -2,33 +2,33 @@
     #ifndef SWIG
     typedef struct
     {
-	SV *fct;
-	SV *data;
+        SV *fct;
+        SV *data;
     } SavedEnv;
     #endif
     int callback_d_cp_vp(double d, const char *cp, void *vp)
     {
-	int count, ret;
-	SavedEnv *env_ptr = (SavedEnv *)vp;
-	dSP;
-	ENTER;
-	SAVETMPS;
-	PUSHMARK(SP);
-	XPUSHs(sv_2mortal(newSVnv(d)));
-	XPUSHs(sv_2mortal(newSVpv(cp, 0)));
-	if (env_ptr->data)
-	    XPUSHs(env_ptr->data);
-	PUTBACK;
-	count = call_sv(env_ptr->fct, G_SCALAR);
-	SPAGAIN;
-	if (count != 1) {
-	    fprintf(stderr, "The callback must return only one value.\n");
-	    return 0; /* interrupt */
-	}
-	ret = POPi;
-	PUTBACK;
-	FREETMPS;
-	LEAVE;
-	return ret;
+        int count, ret;
+        SavedEnv *env_ptr = (SavedEnv *)vp;
+        dSP;
+        ENTER;
+        SAVETMPS;
+        PUSHMARK(SP);
+        XPUSHs(sv_2mortal(newSVnv(d)));
+        XPUSHs(sv_2mortal(newSVpv(cp, 0)));
+        if (env_ptr->data)
+            XPUSHs(env_ptr->data);
+        PUTBACK;
+        count = call_sv(env_ptr->fct, G_SCALAR);
+        SPAGAIN;
+        if (count != 1) {
+            fprintf(stderr, "The callback must return only one value.\n");
+            return 0; /* interrupt */
+        }
+        ret = POPi;
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+        return ret;
     }
 %}
diff --git a/swig/include/perl/gdal_perl.i b/swig/include/perl/gdal_perl.i
index d2db8da..aef7cf6 100644
--- a/swig/include/perl/gdal_perl.i
+++ b/swig/include/perl/gdal_perl.i
@@ -30,7 +30,7 @@
   /* gdal_perl.i %init code */
   UseExceptions();
   if ( GDALGetDriverCount() == 0 ) {
-    GDALAllRegister();
+      GDALAllRegister();
   }
 %}
 
@@ -45,7 +45,6 @@
 
 %import destroy.i
 
-/*ALTERED_DESTROY(GDALRasterBandShadow, GDALc, delete_Band) !does not work! */
 ALTERED_DESTROY(GDALColorTableShadow, GDALc, delete_ColorTable)
 ALTERED_DESTROY(GDALConstShadow, GDALc, delete_Const)
 ALTERED_DESTROY(GDALDatasetShadow, GDALc, delete_Dataset)
@@ -54,8 +53,15 @@ ALTERED_DESTROY(GDAL_GCP, GDALc, delete_GCP)
 ALTERED_DESTROY(GDALMajorObjectShadow, GDALc, delete_MajorObject)
 ALTERED_DESTROY(GDALRasterAttributeTableShadow, GDALc, delete_RasterAttributeTable)
 
-%rename (_GetDataTypeSize) GetDataTypeSize;
-%rename (_DataTypeIsComplex) DataTypeIsComplex;
+/* remove unwanted name duplication */
+
+%rename (X) GCPX;
+%rename (Y) GCPY;
+%rename (Z) GCPZ;
+%rename (Column) GCPPixel;
+%rename (Row) GCPLine;
+
+/* Make room for Perl interface */
 
 %rename (_GetDriver) GetDriver;
 
@@ -65,6 +71,14 @@ ALTERED_DESTROY(GDALRasterAttributeTableShadow, GDALc, delete_RasterAttributeTab
 %rename (_OpenShared) OpenShared;
 %newobject _OpenShared;
 
+%rename (_BuildOverviews) BuildOverviews;
+
+%rename (_ReadRaster) ReadRaster;
+%rename (_WriteRaster) WriteRaster;
+
+%rename (_GetMaskFlags) GetMaskFlags;
+%rename (_CreateMaskBand) CreateMaskBand;
+
 /* those that need callback_data check: */
 
 %rename (_ComputeMedianCutPCT) ComputeMedianCutPCT;
@@ -99,671 +113,1396 @@ ALTERED_DESTROY(GDALRasterAttributeTableShadow, GDALc, delete_RasterAttributeTab
 %rename (Stat) VSIStatL;
 
 %perlcode %{
-    use strict;
-    use Carp;
-    use Encode;
-    use Geo::GDAL::Const;
-    use Geo::OGR;
-    use Geo::OSR;
-    # $VERSION is the Perl module (CPAN) version number, which must be
-    # an increasing floating point number.  $GDAL_VERSION is the
-    # version number of the GDAL that this module is a part of. It is
-    # used in build time to check the version of GDAL against which we
-    # build.  For GDAL 1.9.2 and below $VERSION is made by dropping
-    # the second point.  Hoping that there will not be GDAL 1.9.10, we
-    # set the $VERSION of GDAL 1.10 to 1.991. Thus GDAL 1.10.1 would
-    # have $VERSION 1.9911 and GDAL 1.11 would have $VERSION 1.992
-    # etc.  GDAL 2.0 should then get VERSION 2.000 and 2.1 should get
-    # 2.001 etc.
-
-    our $VERSION = '1.9922';
-    our $GDAL_VERSION = '1.11.2';
-    use vars qw/
-	%TYPE_STRING2INT %TYPE_INT2STRING
-	%ACCESS_STRING2INT %ACCESS_INT2STRING
-	%RESAMPLING_STRING2INT %RESAMPLING_INT2STRING
-	%NODE_TYPE_STRING2INT %NODE_TYPE_INT2STRING
-	/;
-    for my $string (qw/Unknown Byte UInt16 Int16 UInt32 Int32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64/) {
-	my $int = eval "\$Geo::GDAL::Constc::GDT_$string";
-	$TYPE_STRING2INT{$string} = $int;
-	$TYPE_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/ReadOnly Update/) {
-	my $int = eval "\$Geo::GDAL::Constc::GA_$string";
-	$ACCESS_STRING2INT{$string} = $int;
-	$ACCESS_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/NearestNeighbour Bilinear Cubic CubicSpline/) {
-	my $int = eval "\$Geo::GDAL::Constc::GRA_$string";
-	$RESAMPLING_STRING2INT{$string} = $int;
-	$RESAMPLING_INT2STRING{$int} = $string;
-    }
-    {
-	my $int = 0;
-	for my $string (qw/Element Text Attribute Comment Literal/) {
-	    $NODE_TYPE_STRING2INT{$string} = $int;
-	    $NODE_TYPE_INT2STRING{$int} = $string;
-	    $int++;
-	}
-    }
-    sub RELEASE_PARENTS {
-    }
-    sub NodeType {
-	my $type = shift;
-	return $NODE_TYPE_INT2STRING{$type} if $type =~ /^\d/;
-	return $NODE_TYPE_STRING2INT{$type};
-    }
-    sub NodeData {
-	my $node = shift;
-	return (Geo::GDAL::NodeType($node->[0]), $node->[1]);
-    }
-    sub Children {
-	my $node = shift;
-	return @$node[2..$#$node];
-    }
-    sub Child {
-	my($node, $child) = @_;
-	return $node->[2+$child];
-    }
-    sub GetDataTypeSize {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	return _GetDataTypeSize($t);
-    }
-    sub DataTypeValueRange {
-    	my $t = shift;
-	# these values are from gdalrasterband.cpp
-	return (0,255) if $t =~ /^Byte$/;
-	return (0,65535) if $t =~ /^UInt16$/;
-	return (-32768,32767) if $t =~ /Int16$/; # also CInt
-	return (0,4294967295) if $t =~ /^UInt32$/;
-	return (-2147483648,2147483647) if $t =~ /Int32$/; # also CInt
-	return (-4294967295.0,4294967295.0) if $t =~ /Float32$/; # also CFloat
-	return (-4294967295.0,4294967295.0) if $t =~ /Float64$/; # also CFloat
-	croak "GDAL does not support data type '$t'";
-    }
-    sub DataTypeIsComplex {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	return _DataTypeIsComplex($t);
-    }
-    sub PackCharacter {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	my $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; # from Programming Perl
-	return 'C' if $t =~ /^Byte$/;
-	return ($is_big_endian ? 'n': 'v') if $t =~ /^UInt16$/;
-	return 's' if $t =~ /^Int16$/;
-	return ($is_big_endian ? 'N' : 'V') if $t =~ /^UInt32$/;
-	return 'l' if $t =~ /^Int32$/;
-	return 'f' if $t =~ /^Float32$/;
-	return 'd' if $t =~ /^Float64$/;
-	croak "data type '$t' is not known in Geo::GDAL::PackCharacter";
-    }
-    sub Drivers {
-	my @drivers;
-	for my $i (0..GetDriverCount()-1) {
-	    push @drivers, _GetDriver($i);
-	}
-	return @drivers;
-    }
-    sub GetDriver {
-	my $driver = shift;
-	return _GetDriver($driver) if $driver =~ /^\d/;
-	return GetDriverByName($driver);
-    }
-    *Driver = *GetDriver;
-    sub Open {
-	my @p = @_;
-	$p[1] = $ACCESS_STRING2INT{$p[1]} if $p[1] and exists $ACCESS_STRING2INT{$p[1]};
-	return _Open(@p);
-    }
-    sub OpenShared {
-	my @p = @_;
-	$p[1] = $ACCESS_STRING2INT{$p[1]} if $p[1] and exists $ACCESS_STRING2INT{$p[1]};
-	return _OpenShared(@p);
-    }
-    sub ComputeMedianCutPCT {
-    	$_[6] = 1 if $_[5] and not defined $_[6];
-	_ComputeMedianCutPCT(@_);
-    }
-    sub DitherRGB2PCT {
-    	$_[6] = 1 if $_[5] and not defined $_[6];
-	_DitherRGB2PCT(@_);
-    }
-    sub ComputeProximity {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_ComputeProximity(@_);
-    }
-    sub RasterizeLayer {
-    	$_[8] = 1 if $_[7] and not defined $_[8];
-	_RasterizeLayer(@_);
-    }
-    sub Polygonize {
-        my @params = @_;
-        $params[6] = 1 if $params[5] and not defined $params[6];
-        $params[3] = $params[2]->GetLayerDefn->GetFieldIndex($params[3]) unless $params[3] =~ /^\d/;
-	_Polygonize(@params);
-    }
-    sub SieveFilter {
-    	$_[7] = 1 if $_[6] and not defined $_[7];
-	_SieveFilter(@_);
-    }
-    sub RegenerateOverviews {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_RegenerateOverviews(@_);
-    }
-    sub RegenerateOverview {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_RegenerateOverview(@_);
-    }
-    sub ReprojectImage {
-    	$_[8] = 1 if $_[7] and not defined $_[8];
-	$_[4] = $RESAMPLING_STRING2INT{$_[4]} if $_[4] and exists $RESAMPLING_STRING2INT{$_[4]};
-	return _ReprojectImage(@_);
-    }
-    sub AutoCreateWarpedVRT {
-	$_[3] = $RESAMPLING_STRING2INT{$_[3]} if $_[3] and exists $RESAMPLING_STRING2INT{$_[3]};
-	return _AutoCreateWarpedVRT(@_);
-    }
-
-    package Geo::GDAL::MajorObject;
-    use vars qw/@DOMAINS/;
-    use strict;
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub Description {
-	my($self, $desc) = @_;
-	SetDescription($self, $desc) if defined $desc;
-	GetDescription($self) if defined wantarray;
-    }
-    sub Metadata {
-	my $self = shift;
-	my $metadata;
-	$metadata = shift if ref $_[0];
-	my $domain = shift;
-	$domain = '' unless defined $domain;
-	SetMetadata($self, $metadata, $domain) if defined $metadata;
-	GetMetadata($self, $domain) if defined wantarray;
-    }
-
-    package Geo::GDAL::Driver;
-    use vars qw/@CAPABILITIES @DOMAINS/;
-    use strict;
-    @CAPABILITIES = ('Create', 'CreateCopy');
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub Name {
-	my $self = shift;
-	return $self->{ShortName};
-    }
-    sub Capabilities {
-	my $self = shift;
-	return @CAPABILITIES unless $self;
-	my $h = $self->GetMetadata;
-	my @cap;
-	for my $cap (@CAPABILITIES) {
-	    my $test = $h->{'DCAP_'.uc($cap)};
-	    push @cap, $cap if defined($test) and $test eq 'YES';
-	}
-	return @cap;
-    }
-    sub TestCapability {
-	my($self, $cap) = @_;
-	my $h = $self->GetMetadata->{'DCAP_'.uc($cap)};
-	return (defined($h) and $h eq 'YES') ? 1 : undef;
-    }
-    sub Extension {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return $h->{DMD_EXTENSION};
-    }
-    sub MIMEType {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return $h->{DMD_MIMETYPE};
-    }
-    sub CreationOptionList {
-	my $self = shift;
-	my @options;
-	my $h = $self->GetMetadata->{DMD_CREATIONOPTIONLIST};
-	if ($h) {
-	    $h = Geo::GDAL::ParseXMLString($h);
-	    my($type, $value) = Geo::GDAL::NodeData($h);
-	    if ($value eq 'CreationOptionList') {
-		for my $o (Geo::GDAL::Children($h)) {
-		    my %option;
-		    for my $a (Geo::GDAL::Children($o)) {
-			my(undef, $key) = Geo::GDAL::NodeData($a);
-			my(undef, $value) = Geo::GDAL::NodeData(Geo::GDAL::Child($a, 0));
-			if ($key eq 'Value') {
-			    push @{$option{$key}}, $value;
-			} else {
-			    $option{$key} = $value;
-			}
-		    }
-		    push @options, \%option;
-		}
-	    }
-	}
-	return @options;
-    }
-    sub CreationDataTypes {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return split /\s+/, $h->{DMD_CREATIONDATATYPES};
-    }
-    sub CreateDataset {
-	my @p = @_;
-	$p[5] = $Geo::GDAL::TYPE_STRING2INT{$p[5]} if $p[5] and exists $Geo::GDAL::TYPE_STRING2INT{$p[5]};
-	return _Create(@p);
-    }
-    *Create = *CreateDataset;
-    *Copy = *CreateCopy;
-
-    package Geo::GDAL::Dataset;
-    use strict;
-    use vars qw/%BANDS @DOMAINS/;
-    @DOMAINS = ("IMAGE_STRUCTURE", "SUBDATASETS", "GEOLOCATION");
-    sub Domains {
-	return @DOMAINS;
-    }
-    *GetDriver = *_GetDriver;
-    sub Open {
-	return Geo::GDAL::Open(@_);
-    }
-    sub OpenShared {
-	return Geo::GDAL::OpenShared(@_);
-    }
-    sub Size {
-	my $self = shift;
-	return ($self->{RasterXSize}, $self->{RasterYSize});
-    }
-    sub Bands {
-	my $self = shift;
-	my @bands;
-	for my $i (1..$self->{RasterCount}) {
-	    push @bands, GetRasterBand($self, $i);
-	}
-	return @bands;
-    }
-    sub GetRasterBand {
-	my($self, $index) = @_;
-	$index = 1 unless defined $index;
-	my $band = _GetRasterBand($self, $index);
-	$BANDS{tied(%{$band})} = $self;
-	return $band;
-    }
-    *Band = *GetRasterBand;
-    sub AddBand {
-	my @p = @_;
-	$p[1] = $Geo::GDAL::TYPE_STRING2INT{$p[1]} if $p[1] and exists $Geo::GDAL::TYPE_STRING2INT{$p[1]};
-	return _AddBand(@p);
-    }
-    sub Projection {
-	my($self, $proj) = @_;
-	SetProjection($self, $proj) if defined $proj;
-	GetProjection($self) if defined wantarray;
-    }
-    sub GeoTransform {
-	my $self = shift;
-	SetGeoTransform($self, \@_) if @_ > 0;
-	return unless defined wantarray;
-	my $t = GetGeoTransform($self);
-	return @$t;
-    }
-    sub GCPs {
-	my $self = shift;
-	if (@_ > 0) {
-	    my $proj = pop @_;
-	    SetGCPs($self, \@_, $proj);
-	}
-	return unless defined wantarray;
-	my $proj = GetGCPProjection($self);
-	my $GCPs = GetGCPs($self);
-	return (@$GCPs, $proj);
-    }
-
-    package Geo::GDAL::Band;
-    use strict;
-    use Carp;
-    use Scalar::Util 'blessed';
-    use vars qw/
-        @COLOR_INTERPRETATIONS
-	%COLOR_INTERPRETATION_STRING2INT %COLOR_INTERPRETATION_INT2STRING @DOMAINS
-	/;
-    @COLOR_INTERPRETATIONS = qw/Undefined GrayIndex PaletteIndex RedBand GreenBand BlueBand AlphaBand 
-		    HueBand SaturationBand LightnessBand CyanBand MagentaBand YellowBand BlackBand/;
-    for my $string (@COLOR_INTERPRETATIONS) {
-	my $int = eval "\$Geo::GDAL::Constc::GCI_$string";
-	$COLOR_INTERPRETATION_STRING2INT{$string} = $int;
-	$COLOR_INTERPRETATION_INT2STRING{$int} = $string;
-    }
-    @DOMAINS = ("IMAGE_STRUCTURE", "RESAMPLING");
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub DESTROY {
-	my $self;
-	if ($_[0]->isa('SCALAR')) {
-	    $self = $_[0];
-	} else {
-	    return unless $_[0]->isa('HASH');
-	    $self = tied(%{$_[0]});
-	    return unless defined $self;
-	}
-	delete $ITERATORS{$self};
-	if (exists $OWNER{$self}) {
-	    delete $OWNER{$self};
-	}
-	$self->RELEASE_PARENTS();
-    }
-    sub RELEASE_PARENTS {
-	my $self = shift;
-	delete $Geo::GDAL::Dataset::BANDS{$self};
-    }
-    sub Size {
-	my $self = shift;
-	return ($self->{XSize}, $self->{YSize});
-    }
-    sub DataType {
-	my $self = shift;
-	return $Geo::GDAL::TYPE_INT2STRING{$self->{DataType}};
-    }
-    sub NoDataValue {
-	my $self = shift;
-	SetNoDataValue($self, $_[0]) if @_ > 0;
-	GetNoDataValue($self);
-    }
-    sub Unit {
-	my $self = shift;
-	SetUnitType($self, $_[0]) if @_ > 0;
-	GetUnitType($self);
-    }
-    sub ScaleAndOffset {
-	my $self = shift;
-	SetScale($self, $_[0]) if @_ > 0;
-	SetOffset($self, $_[1]) if @_ > 1;
-	(GetScale($self), GetOffset($self));
-    }
-    sub ReadTile {
-	my($self, $xoff, $yoff, $xsize, $ysize) = @_;
-	$xoff = 0 unless defined $xoff;
-	$yoff = 0 unless defined $yoff;
-	$xsize = $self->{XSize} - $xoff unless defined $xsize;
-	$ysize = $self->{YSize} - $yoff unless defined $ysize;
-	my $buf = $self->ReadRaster($xoff, $yoff, $xsize, $ysize);
-	my $pc = Geo::GDAL::PackCharacter($self->{DataType});
-	my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
-	my $offset = 0;
-	my @data;
-	for (0..$ysize-1) {
-	    my $sub = substr($buf, $offset, $w);
-	    my @d = unpack($pc."[$xsize]", $sub);
-	    push @data, \@d;
-	    $offset += $w;
-	}
-	return \@data;
-    }
-    sub WriteTile {
-	my($self, $data, $xoff, $yoff) = @_;
-	$xoff = 0 unless defined $xoff;
-	$yoff = 0 unless defined $yoff;
-	my $xsize = @{$data->[0]};
-	$xsize = $self->{XSize} - $xoff if $xsize > $self->{XSize} - $xoff;
-	my $ysize = @{$data};
-	$ysize = $self->{YSize} - $yoff if $ysize > $self->{YSize} - $yoff;
-	my $pc = Geo::GDAL::PackCharacter($self->{DataType});
-	my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
-	for my $i (0..$ysize-1) {
-	    my $scanline = pack($pc."[$xsize]", @{$data->[$i]});
-	    $self->WriteRaster( $xoff, $yoff+$i, $xsize, 1, $scanline );
-	}
-    }
-    sub ColorInterpretation {
-	my($self, $ci) = @_;
-	if ($ci) {
-	    $ci = $COLOR_INTERPRETATION_STRING2INT{$ci} if exists $COLOR_INTERPRETATION_STRING2INT{$ci};
-	    SetRasterColorInterpretation($self, $ci);
-	    return $ci;
-	} else {
-	    return $COLOR_INTERPRETATION_INT2STRING{GetRasterColorInterpretation($self)};
-	}
-    }
-    sub ColorTable {
-	my $self = shift;
-	SetRasterColorTable($self, $_[0]) if @_;
-	return unless defined wantarray;
-	GetRasterColorTable($self);
-    }
-    sub CategoryNames {
-	my $self = shift;
-	SetRasterCategoryNames($self, \@_) if @_;
-	return unless defined wantarray;
-	my $n = GetRasterCategoryNames($self);
-	return @$n;
-    }
-    sub AttributeTable {
-	my $self = shift;
-	SetDefaultRAT($self, $_[0]) if @_;
-	return unless defined wantarray;
-	my $r = GetDefaultRAT($self);
-	$Geo::GDAL::RasterAttributeTable::BANDS{$r} = $self;
-	return $r;
-    }
-    sub GetHistogram {
-	my $self = shift;
-	my %defaults = (Min => -0.5,
-			Max => 255.5,
-			Buckets => 256, 
-			IncludeOutOfRange => 0,
-			ApproxOK => 0,
-			Progress => undef,
-			ProgressData => undef);
-	my %params = @_;
-	for (keys %params) {
-	    carp "unknown parameter $_ in Geo::GDAL::Band::GetHistogram" unless exists $defaults{$_};
-	}
-	for (keys %defaults) {
-	    $params{$_} = $defaults{$_} unless defined $params{$_};
-	}
-	$params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
-	_GetHistogram($self, $params{Min}, $params{Max}, $params{Buckets},
-		      $params{IncludeOutOfRange}, $params{ApproxOK},
-		      $params{Progress}, $params{ProgressData});
-    }
-    sub Contours {
-	my $self = shift;
-	my %defaults = (DataSource => undef,
-			LayerConstructor => {Name => 'contours'},
-			ContourInterval => 100, 
-			ContourBase => 0,
-			FixedLevels => [], 
-			NoDataValue => undef, 
-			IDField => -1, 
-			ElevField => -1,
-			callback => undef,
-			callback_data => undef);
-	my %params;
-	if (!defined($_[0]) or (blessed($_[0]) and $_[0]->isa('Geo::OGR::DataSource'))) {
-	    ($params{DataSource}, $params{LayerConstructor},
-	     $params{ContourInterval}, $params{ContourBase},
-	     $params{FixedLevels}, $params{NoDataValue}, 
-	     $params{IDField}, $params{ElevField},
-	     $params{callback}, $params{callback_data}) = @_;
-	} else {
-	    %params = @_;
-	}
-	for (keys %params) {
-	    carp "unknown parameter $_ in Geo::GDAL::Band::Contours" unless exists $defaults{$_};
-	}
-	for (keys %defaults) {
-	    $params{$_} = $defaults{$_} unless defined $params{$_};
-	}
-	$params{DataSource} = Geo::OGR::GetDriver('Memory')->CreateDataSource('ds') 
-	    unless defined $params{DataSource};
-	$params{LayerConstructor}->{Schema} = {} unless $params{LayerConstructor}->{Schema};
-	$params{LayerConstructor}->{Schema}{Fields} = [] unless $params{LayerConstructor}->{Schema}{Fields};
-	my %fields;
-	unless ($params{IDField} =~ /^[+-]?\d+$/ or $fields{$params{IDField}}) {
-	    push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{IDField}, Type => 'Integer'};
-	}
-	unless ($params{ElevField} =~ /^[+-]?\d+$/ or $fields{$params{ElevField}}) {
-	    my $type = $self->DataType() =~ /Float/ ? 'Real' : 'Integer';
-	    push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{ElevField}, Type => $type};
-	}
-	my $layer = $params{DataSource}->CreateLayer($params{LayerConstructor});
-	my $schema = $layer->GetLayerDefn;
-	for ('IDField', 'ElevField') {
-	    $params{$_} = $schema->GetFieldIndex($params{$_}) unless $params{$_} =~ /^[+-]?\d+$/;
-	}
-	$params{callback_data} = 1 if $params{callback} and not defined $params{callback_data};
-	ContourGenerate($self, $params{ContourInterval}, $params{ContourBase}, $params{FixedLevels},
-			$params{NoDataValue}, $layer, $params{IDField}, $params{ElevField},
-			$params{callback}, $params{callback_data});
-	return $layer;
-    }
-    sub FillNodata {
-      croak 'usage: Geo::GDAL::Band->FillNodata($mask)' unless blessed($_[1]) and $_[1]->isa('Geo::GDAL::Band');
-      $_[2] = 10 unless defined $_[2];
-      $_[3] = 0 unless defined $_[3];
-      $_[4] = undef unless defined $_[4];
-      $_[5] = undef unless defined $_[5];
-      $_[6] = undef unless defined $_[6];
-      Geo::GDAL::FillNodata(@_);
-    }
-    *GetBandNumber = *GetBand;
-
-    package Geo::GDAL::ColorTable;
-    use strict;
-    use vars qw/
-	%PALETTE_INTERPRETATION_STRING2INT %PALETTE_INTERPRETATION_INT2STRING
-	/;
-    for my $string (qw/Gray RGB CMYK HLS/) {
-	my $int = eval "\$Geo::GDAL::Constc::GPI_$string";
-	$PALETTE_INTERPRETATION_STRING2INT{$string} = $int;
-	$PALETTE_INTERPRETATION_INT2STRING{$int} = $string;
-    }
-    sub create {
-	my($pkg, $pi) = @_;
-	$pi = $PALETTE_INTERPRETATION_STRING2INT{$pi} if defined $pi and exists $PALETTE_INTERPRETATION_STRING2INT{$pi};
-	my $self = Geo::GDALc::new_ColorTable($pi);
-	bless $self, $pkg if defined($self);
-    }
-    sub GetPaletteInterpretation {
-	my $self = shift;
-	return $PALETTE_INTERPRETATION_INT2STRING{GetPaletteInterpretation($self)};
-    }
-    sub SetColorEntry {
-	@_ == 3 ? _SetColorEntry(@_) : _SetColorEntry(@_[0..1], [@_[2..5]]);
-    }
-    sub ColorEntry {
-	my $self = shift;
-	my $index = shift;
-	SetColorEntry($self, $index, @_) if @_ > 0;
-	GetColorEntry($self, $index) if defined wantarray;
-    }
-    sub ColorTable {
-	my $self = shift;
-	my @table;
-	if (@_) {
-	    my $index = 0;
-	    for my $color (@_) {
-		push @table, [ColorEntry($self, $index, @$color)];
-		$index++;
-	    }
-	} else {
-	    for (my $index = 0; $index < GetCount($self); $index++) {
-		push @table, [ColorEntry($self, $index)];
-	    }
-	}
-	return @table;
-    }
-    *ColorEntries = *ColorTable;
-
-    package Geo::GDAL::RasterAttributeTable;
-    use strict;
-    use vars qw/ %BANDS
-	%FIELD_TYPE_STRING2INT %FIELD_TYPE_INT2STRING
-	%FIELD_USAGE_STRING2INT %FIELD_USAGE_INT2STRING
-	/;
-    for my $string (qw/Integer Real String/) {
-	my $int = eval "\$Geo::GDAL::Constc::GFT_$string";
-	$FIELD_TYPE_STRING2INT{$string} = $int;
-	$FIELD_TYPE_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/Generic PixelCount Name Min Max MinMax 
-		    Red Green Blue Alpha RedMin 
-		    GreenMin BlueMin AlphaMin RedMax GreenMax BlueMax AlphaMax 
-		    MaxCount/) {
-	my $int = eval "\$Geo::GDAL::Constc::GFU_$string";
-	$FIELD_USAGE_STRING2INT{$string} = $int;
-	$FIELD_USAGE_INT2STRING{$int} = $string;
-    }
-    sub FieldTypes {
-	return keys %FIELD_TYPE_STRING2INT;
-    }
-    sub FieldUsages {
-	return keys %FIELD_USAGE_STRING2INT;
-    }
-    sub RELEASE_PARENTS {
-	my $self = shift;
-	delete $BANDS{$self};
-    }
-    sub GetUsageOfCol {
-	my($self, $col) = @_;
-	$FIELD_USAGE_INT2STRING{_GetUsageOfCol($self, $col)};
-    }
-    sub GetColOfUsage {
-	my($self, $usage) = @_;
-	_GetColOfUsage($self, $FIELD_USAGE_STRING2INT{$usage});
-    }
-    sub GetTypeOfCol {
-	my($self, $col) = @_;
-	$FIELD_TYPE_INT2STRING{_GetTypeOfCol($self, $col)};
-    }
-    sub Columns {
-	my $self = shift;
-	my %columns;
-	if (@_) { # create columns
-	    %columns = @_;
-	    for my $name (keys %columns) {
-		$self->CreateColumn($name, $columns{$name}{Type}, $columns{$name}{Usage});
-	    }
-	}
-	%columns = ();
-	for my $c (0..$self->GetColumnCount-1) {
-	    my $name = $self->GetNameOfCol($c);
-	    $columns{$name}{Type} = $self->GetTypeOfCol($c);
-	    $columns{$name}{Usage} = $self->GetUsageOfCol($c);
-	}
-	return %columns;
-    }
-    sub CreateColumn {
-	my($self, $name, $type, $usage) = @_;
-	_CreateColumn($self, $name, $FIELD_TYPE_STRING2INT{$type}, $FIELD_USAGE_STRING2INT{$usage});
-    }
-    sub Value {
-	my($self, $row, $column) = @_;
-	SetValueAsString($self, $row, $column, $_[3]) if defined $_[3];
-	return unless defined wantarray;
-	GetValueAsString($self, $row, $column);
-    }
-    sub LinearBinning {
-	my $self = shift;
-	SetLinearBinning($self, @_) if @_ > 0;
-	return unless defined wantarray;
-	my @a = GetLinearBinning($self);
-	return $a[0] ? ($a[1], $a[2]) : ();
-    }
-
- %}
-
-#define GDAL_BINDINGS
-%import ogr.i
+
+package Geo::GDAL;
+use strict;
+use warnings;
+use Carp;
+use Encode;
+use Geo::GDAL::Const;
+use Geo::OGR;
+use Geo::OSR;
+# $VERSION is the Perl module (CPAN) version number, which must be
+# an increasing floating point number.  $GDAL_VERSION is the
+# version number of the GDAL that this module is a part of. It is
+# used in build time to check the version of GDAL against which we
+# build.
+# For GDAL 2.0 or above, GDAL X.Y.Z should then
+# VERSION = X + Y / 100.0 + Z / 10000.0
+
+our $VERSION = '2.0000';
+our $GDAL_VERSION = '2.0.0';
+use vars qw/
+    @DATA_TYPES @ACCESS_TYPES @RESAMPLING_TYPES @RIO_RESAMPLING_TYPES @NODE_TYPES
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    %ACCESS_STRING2INT %ACCESS_INT2STRING
+    %RESAMPLING_STRING2INT %RESAMPLING_INT2STRING
+    %RIO_RESAMPLING_STRING2INT %RIO_RESAMPLING_INT2STRING
+    %NODE_TYPE_STRING2INT %NODE_TYPE_INT2STRING
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@DATA_TYPES, $1), next if /^GDT_(\w+)/;
+    push(@ACCESS_TYPES, $1), next if /^GA_(\w+)/;
+    push(@RESAMPLING_TYPES, $1), next if /^GRA_(\w+)/;
+    push(@RIO_RESAMPLING_TYPES, $1), next if /^GRIORA_(\w+)/;
+    push(@NODE_TYPES, $1), next if /^CXT_(\w+)/;
+}
+for my $string (@DATA_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GDT_$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@ACCESS_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GA_$string";
+    $ACCESS_STRING2INT{$string} = $int;
+    $ACCESS_INT2STRING{$int} = $string;
+}
+for my $string (@RESAMPLING_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GRA_$string";
+    $RESAMPLING_STRING2INT{$string} = $int;
+    $RESAMPLING_INT2STRING{$int} = $string;
+}
+for my $string (@RIO_RESAMPLING_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GRIORA_$string";
+    $RIO_RESAMPLING_STRING2INT{$string} = $int;
+    $RIO_RESAMPLING_INT2STRING{$int} = $string;
+}
+for my $string (@NODE_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::CXT_$string";
+    $NODE_TYPE_STRING2INT{$string} = $int;
+    $NODE_TYPE_INT2STRING{$int} = $string;
+}
+
+sub RELEASE_PARENTS {
+}
+
+sub DataTypes {
+    return @DATA_TYPES;
+}
+
+sub AccessTypes {
+    return @ACCESS_TYPES;
+}
+
+sub ResamplingTypes {
+    return @RESAMPLING_TYPES;
+}
+
+sub RIOResamplingTypes {
+    return @RIO_RESAMPLING_TYPES;
+}
+
+sub NodeTypes {
+    return @NODE_TYPES;
+}
+
+sub NodeType {
+    my $type = shift;
+    return $NODE_TYPE_INT2STRING{$type} if $type =~ /^\d/;
+    return $NODE_TYPE_STRING2INT{$type};
+}
+
+sub NodeData {
+    my $node = shift;
+    return (Geo::GDAL::NodeType($node->[0]), $node->[1]);
+}
+
+sub Children {
+    my $node = shift;
+    return @$node[2..$#$node];
+}
+
+sub Child {
+    my($node, $child) = @_;
+    return $node->[2+$child];
+}
+
+sub GetDataTypeSize {
+    my $t = shift;
+    my $t2 = $t;
+    $t2 = $TYPE_STRING2INT{$t} if exists $TYPE_STRING2INT{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_INT2STRING{$t2};
+    return _GetDataTypeSize($t2);
+}
+
+sub DataTypeValueRange {
+    my $t = shift;
+    confess "Unknown data type: '$t'." unless exists $TYPE_STRING2INT{$t};
+    # these values are from gdalrasterband.cpp
+    return (0,255) if $t =~ /Byte/;
+    return (0,65535) if $t =~/UInt16/;
+    return (-32768,32767) if $t =~/Int16/;
+    return (0,4294967295) if $t =~/UInt32/;
+    return (-2147483648,2147483647) if $t =~/Int32/;
+    return (-4294967295.0,4294967295.0) if $t =~/Float32/;
+    return (-4294967295.0,4294967295.0) if $t =~/Float64/;
+}
+
+sub DataTypeIsComplex {
+    my $t = shift;
+    my $t2 = $t;
+    $t2 = $TYPE_STRING2INT{$t} if exists $TYPE_STRING2INT{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_INT2STRING{$t2};
+    return _DataTypeIsComplex($t2);
+}
+
+sub PackCharacter {
+    my $t = shift;
+    $t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_STRING2INT{$t};
+    my $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; # from Programming Perl
+    return 'C' if $t =~ /^Byte$/;
+    return ($is_big_endian ? 'n': 'v') if $t =~ /^UInt16$/;
+    return 's' if $t =~ /^Int16$/;
+    return ($is_big_endian ? 'N' : 'V') if $t =~ /^UInt32$/;
+    return 'l' if $t =~ /^Int32$/;
+    return 'f' if $t =~ /^Float32$/;
+    return 'd' if $t =~ /^Float64$/;
+}
+
+sub GetDriverNames {
+    my @names;
+    for my $i (0..GetDriverCount()-1) {
+        my $driver = _GetDriver($i);
+        my $md = $driver->GetMetadata;
+        next unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        push @names, _GetDriver($i)->Name;
+    }
+    return @names;
+}
+
+sub Drivers {
+    my @drivers;
+    for my $i (0..GetDriverCount()-1) {
+        my $driver = _GetDriver($i);
+        my $md = $driver->GetMetadata;
+        next unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        push @drivers, _GetDriver($i);
+    }
+    return @drivers;
+}
+
+sub GetDriver {
+    my($name) = @_;
+    $name = 0 unless defined $name;
+    my $driver;
+    $driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
+    $driver = GetDriverByName("$name") unless $driver;
+    if ($driver) {
+        my $md = $driver->GetMetadata;
+        confess "Driver exists but does not have raster capabilities." 
+            unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        return $driver;
+    }
+    confess "Driver not found: '$name'. Maybe support for it was not built in?";
+}
+*Driver = *GetDriver;
+
+sub Open {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown access type: '$p[1]'." unless exists $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+    }
+    return _Open(@p);
+}
+
+sub OpenShared {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown access type: '$p[1]'." unless exists $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+    }
+    return _OpenShared(@p);
+}
+
+sub ComputeMedianCutPCT {
+    my @p = @_;
+    $p[6] = 1 if $p[5] and not defined $p[6];
+    _ComputeMedianCutPCT(@p);
+}
+
+sub DitherRGB2PCT {
+    my @p = @_;
+    $p[6] = 1 if $p[5] and not defined $p[6];
+    _DitherRGB2PCT(@p);
+}
+
+sub ComputeProximity {
+    my @p = @_;
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _ComputeProximity(@p);
+}
+
+sub RasterizeLayer {
+    my @p = @_;
+    $p[8] = 1 if $p[7] and not defined $p[8];
+    _RasterizeLayer(@p);
+}
+
+sub Polygonize {
+    my @params = @_;
+    $params[6] = 1 if $params[5] and not defined $params[6];
+    $params[3] = $params[2]->GetLayerDefn->GetFieldIndex($params[3]) unless $params[3] =~ /^\d/;
+    _Polygonize(@params);
+}
+
+sub SieveFilter {
+    my @p = @_;
+    $p[7] = 1 if $p[6] and not defined $p[7];
+    _SieveFilter(@p);
+}
+
+sub RegenerateOverviews {
+    my @p = @_;
+    $p[2] = uc($p[2]) if $p[2]; # see overview.cpp:2030
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _RegenerateOverviews(@p);
+}
+
+sub RegenerateOverview {
+    my @p = @_;
+    $p[2] = uc($p[2]) if $p[2]; # see overview.cpp:2030
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _RegenerateOverview(@p);
+}
+
+sub ReprojectImage {
+    my @p = @_;
+    $p[8] = 1 if $p[7] and not defined $p[8];
+    if (defined $p[4]) {
+        confess "Unknown data type: '$p[4]'." unless exists $Geo::GDAL::RESAMPLING_STRING2INT{$p[4]};
+        $p[4] = $Geo::GDAL::RESAMPLING_STRING2INT{$p[4]};
+    }
+    return _ReprojectImage(@p);
+}
+
+sub AutoCreateWarpedVRT {
+    my @p = @_;
+    for my $i (1..2) {
+        if (defined $p[$i] and ref($p[$i])) {
+            $p[$i] = $p[$i]->ExportToWkt;
+        }
+    }
+    if (defined $p[3]) {
+        confess "Unknown data type: '$p[3]'." unless exists $Geo::GDAL::RESAMPLING_STRING2INT{$p[3]};
+        $p[3] = $Geo::GDAL::RESAMPLING_STRING2INT{$p[3]};
+    }
+    return _AutoCreateWarpedVRT(@p);
+}
+
+
+
+
+package Geo::GDAL::MajorObject;
+use strict;
+use warnings;
+use vars qw/@DOMAINS/;
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub Description {
+    my($self, $desc) = @_;
+    SetDescription($self, $desc) if defined $desc;
+    GetDescription($self) if defined wantarray;
+}
+
+sub Metadata {
+    my $self = shift;
+    my $metadata;
+    $metadata = shift if ref $_[0];
+    my $domain = shift;
+    $domain = '' unless defined $domain;
+    SetMetadata($self, $metadata, $domain) if defined $metadata;
+    GetMetadata($self, $domain) if defined wantarray;
+}
+
+
+package Geo::GDAL::Driver;
+use strict;
+use warnings;
+use Carp;
+use vars qw/@CAPABILITIES @DOMAINS/;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@CAPABILITIES, $1), next if /^DCAP_(\w+)/;
+}
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub Name {
+    my $self = shift;
+    return $self->{ShortName};
+}
+
+sub Capabilities {
+    my $self = shift;
+    return @CAPABILITIES unless $self;
+    my $h = $self->GetMetadata;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        my $test = $h->{'DCAP_'.uc($cap)};
+        push @cap, $cap if defined($test) and $test eq 'YES';
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    my $h = $self->GetMetadata->{'DCAP_'.uc($cap)};
+    return (defined($h) and $h eq 'YES') ? 1 : undef;
+}
+
+sub Extension {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return $h->{DMD_EXTENSION};
+}
+
+sub MIMEType {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return $h->{DMD_MIMETYPE};
+}
+
+sub CreationOptionList {
+    my $self = shift;
+    my @options;
+    my $h = $self->GetMetadata->{DMD_CREATIONOPTIONLIST};
+    if ($h) {
+        $h = Geo::GDAL::ParseXMLString($h);
+        my($type, $value) = Geo::GDAL::NodeData($h);
+        if ($value eq 'CreationOptionList') {
+            for my $o (Geo::GDAL::Children($h)) {
+                my %option;
+                for my $a (Geo::GDAL::Children($o)) {
+                    my(undef, $key) = Geo::GDAL::NodeData($a);
+                    my(undef, $value) = Geo::GDAL::NodeData(Geo::GDAL::Child($a, 0));
+                    if ($key eq 'Value') {
+                        push @{$option{$key}}, $value;
+                    } else {
+                        $option{$key} = $value;
+                    }
+                }
+                push @options, \%option;
+            }
+        }
+    }
+    return @options;
+}
+
+sub CreationDataTypes {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return split /\s+/, $h->{DMD_CREATIONDATATYPES} if $h->{DMD_CREATIONDATATYPES};
+}
+
+sub Create {
+    my $self = shift;
+    my %defaults = ( Name => 'unnamed',
+                     Width => 256,
+                     Height => 256,
+                     Bands => 1,
+                     Type => 'Byte',
+                     Options => {} );
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (exists $defaults{$_[0]} and @_ % 2 == 0) {
+        %params = @_;
+    } else {
+        ($params{Name}, $params{Width}, $params{Height}, $params{Bands}, $params{Type}, $params{Options}) = @_;
+    }
+    for my $k (keys %params) {
+        carp "Create: unrecognized named parameter '$k'." unless exists $defaults{$k};
+    }
+    for my $k (keys %defaults) {
+        $params{$k} = $defaults{$k} unless defined $params{$k};
+    }
+    my $type;
+    confess "Unknown data type: '$params{Type}'." unless exists $Geo::GDAL::TYPE_STRING2INT{$params{Type}};
+    $type = $Geo::GDAL::TYPE_STRING2INT{$params{Type}};
+    return $self->_Create($params{Name}, $params{Width}, $params{Height}, $params{Bands}, $type, $params{Options});
+}
+*CreateDataset = *Create;
+*Copy = *CreateCopy;
+
+
+
+
+package Geo::GDAL::Dataset;
+use strict;
+use warnings;
+use Carp;
+use vars qw/%BANDS @DOMAINS/;
+ at DOMAINS = qw/IMAGE_STRUCTURE SUBDATASETS GEOLOCATION/;
+
+sub Domains {
+    return @DOMAINS;
+}
+*GetDriver = *_GetDriver;
+
+sub Open {
+    return Geo::GDAL::Open(@_);
+}
+
+sub OpenShared {
+    return Geo::GDAL::OpenShared(@_);
+}
+
+sub Size {
+    my $self = shift;
+    return ($self->{RasterXSize}, $self->{RasterYSize});
+}
+
+sub Bands {
+    my $self = shift;
+    my @bands;
+    for my $i (1..$self->{RasterCount}) {
+        push @bands, GetRasterBand($self, $i);
+    }
+    return @bands;
+}
+
+sub GetRasterBand {
+    my($self, $index) = @_;
+    $index = 1 unless defined $index;
+    my $band = _GetRasterBand($self, $index);
+    $BANDS{tied(%{$band})} = $self;
+    return $band;
+}
+*Band = *GetRasterBand;
+
+sub AddBand {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown data type: '$p[1]'." unless exists $Geo::GDAL::TYPE_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::TYPE_STRING2INT{$p[1]};
+    }
+    return _AddBand(@p);
+}
+
+sub Projection {
+    my($self, $proj) = @_;
+    SetProjection($self, $proj) if defined $proj;
+    GetProjection($self) if defined wantarray;
+}
+
+sub SpatialReference {
+    my($self, $sr) = @_;
+    SetProjection($self, $sr->As('WKT')) if defined $sr;
+    return Geo::OSR::SpatialReference->new(GetProjection($self)) if defined wantarray;
+}
+
+sub GeoTransform {
+    my $self = shift;
+    eval {
+        if (@_ == 1) {
+            SetGeoTransform($self, $_[0]);
+        } elsif (@_ > 1) {
+            SetGeoTransform($self, \@_);
+        }
+    };
+    confess $@ if $@;
+    return unless defined wantarray;
+    my $t = GetGeoTransform($self);
+    if (wantarray) {
+        return @$t;
+    } else {
+        return Geo::GDAL::GeoTransform->new($t);
+    }
+}
+
+sub GCPs {
+    my $self = shift;
+    if (@_ > 0) {
+        my $proj = pop @_;
+        $proj = $proj->Export('WKT') if $proj and ref($proj);
+        SetGCPs($self, \@_, $proj);
+    }
+    return unless defined wantarray;
+    my $proj = Geo::OSR::SpatialReference->new(GetGCPProjection($self));
+    my $GCPs = GetGCPs($self);
+    return (@$GCPs, $proj);
+}
+
+sub ReadRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->Band->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BANDLIST => [1],
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        BUFBANDSPACE => 0,
+        RESAMPLEALG => 'NearestNeighbour',
+        PROGRESS => undef,
+        PROGRESSDATA => undef
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{band_list},$p{buf_pixel_space},$p{buf_line_space},$p{buf_band_space},$p{resample_alg},$p{progress},$p{progress_data}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    confess "Unknown resampling algorithm: '$p{RESAMPLEALG}'." 
+        unless exists $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    $p{RESAMPLEALG} = $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_ReadRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BANDLIST},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{BUFBANDSPACE},$p{RESAMPLEALG},$p{PROGRESS},$p{PROGRESSDATA});
+}
+
+sub WriteRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->Band->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUF => undef,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BANDLIST => [1],
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        BUFBANDSPACE => 0
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{band_list},$p{buf_pixel_space},$p{buf_line_space},$p{buf_band_space}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_WriteRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUF},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BANDLIST},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{BUFBANDSPACE});
+}
+
+sub BuildOverviews {
+    my $self = shift;
+    my @p = @_;
+    $p[0] = uc($p[0]) if $p[0];
+    eval {
+        $self->_BuildOverviews(@p);
+    };
+    confess $@ if $@;
+}
+
+
+
+
+package Geo::GDAL::Band;
+use strict;
+use warnings;
+use POSIX;
+use Carp;
+use Scalar::Util 'blessed';
+use vars qw/
+    @COLOR_INTERPRETATIONS
+    %COLOR_INTERPRETATION_STRING2INT %COLOR_INTERPRETATION_INT2STRING @DOMAINS
+    %MASK_FLAGS
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@COLOR_INTERPRETATIONS, $1), next if /^GCI_(\w+)/;
+}
+for my $string (@COLOR_INTERPRETATIONS) {
+    my $int = eval "\$Geo::GDAL::Constc::GCI_$string";
+    $COLOR_INTERPRETATION_STRING2INT{$string} = $int;
+    $COLOR_INTERPRETATION_INT2STRING{$int} = $string;
+}
+ at DOMAINS = qw/IMAGE_STRUCTURE RESAMPLING/;
+%MASK_FLAGS = (AllValid => 1, PerDataset => 2, Alpha => 4, NoData => 8);
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub ColorInterpretations {
+    return @COLOR_INTERPRETATIONS;
+}
+
+sub MaskFlags {
+    my @f = sort {$MASK_FLAGS{$a} <=> $MASK_FLAGS{$b}} keys %MASK_FLAGS;
+    return @f;
+}
+
+sub DESTROY {
+    my $self;
+    if ($_[0]->isa('SCALAR')) {
+        $self = $_[0];
+    } else {
+        return unless $_[0]->isa('HASH');
+        $self = tied(%{$_[0]});
+        return unless defined $self;
+    }
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        delete $OWNER{$self};
+    }
+    $self->RELEASE_PARENTS();
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::GDAL::Dataset::BANDS{$self};
+}
+
+sub Size {
+    my $self = shift;
+    return ($self->{XSize}, $self->{YSize});
+}
+
+sub DataType {
+    my $self = shift;
+    return $Geo::GDAL::TYPE_INT2STRING{$self->{DataType}};
+}
+
+sub PackCharacter {
+    my $self = shift;
+    return Geo::GDAL::PackCharacter($self->DataType);
+}
+
+sub NoDataValue {
+    my $self = shift;
+    if (@_ > 0) {
+        if (defined $_[0]) {
+            SetNoDataValue($self, $_[0]);
+        } else {
+            SetNoDataValue($self, POSIX::FLT_MAX); # hopefully an "out of range" value
+        }
+    }
+    GetNoDataValue($self);
+}
+
+sub Unit {
+    my $self = shift;
+    if (@_ > 0) {
+        my $unit = shift;
+        $unit = '' unless defined $unit;
+        SetUnitType($self, $unit);
+    }
+    return unless defined wantarray;
+    GetUnitType($self);
+}
+
+sub ScaleAndOffset {
+    my $self = shift;
+    SetScale($self, $_[0]) if @_ > 0 and defined $_[0];
+    SetOffset($self, $_[1]) if @_ > 1 and defined $_[1];
+    return unless defined wantarray;
+    my $scale = GetScale($self);
+    my $offset = GetOffset($self);
+    return ($scale, $offset);
+}
+
+sub ReadTile {
+    my($self, $xoff, $yoff, $xsize, $ysize) = @_;
+    $xoff = 0 unless defined $xoff;
+    $yoff = 0 unless defined $yoff;
+    $xsize = $self->{XSize} - $xoff unless defined $xsize;
+    $ysize = $self->{YSize} - $yoff unless defined $ysize;
+    my $buf = $self->ReadRaster($xoff, $yoff, $xsize, $ysize);
+    my $pc = Geo::GDAL::PackCharacter($self->{DataType});
+    my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
+    my $offset = 0;
+    my @data;
+    for (0..$ysize-1) {
+        my $sub = substr($buf, $offset, $w);
+        my @d = unpack($pc."[$xsize]", $sub);
+        push @data, \@d;
+        $offset += $w;
+    }
+    return \@data;
+}
+
+sub WriteTile {
+    my($self, $data, $xoff, $yoff) = @_;
+    $xoff = 0 unless defined $xoff;
+    $yoff = 0 unless defined $yoff;
+    my $xsize = @{$data->[0]};
+    $xsize = $self->{XSize} - $xoff if $xsize > $self->{XSize} - $xoff;
+    my $ysize = @{$data};
+    $ysize = $self->{YSize} - $yoff if $ysize > $self->{YSize} - $yoff;
+    my $pc = Geo::GDAL::PackCharacter($self->{DataType});
+    for my $i (0..$ysize-1) {
+        my $scanline = pack($pc."[$xsize]", @{$data->[$i]});
+        $self->WriteRaster( $xoff, $yoff+$i, $xsize, 1, $scanline );
+    }
+}
+
+sub ColorInterpretation {
+    my($self, $ci) = @_;
+    if (defined $ci) {
+        my $ci2 = $ci;
+        $ci2 = $COLOR_INTERPRETATION_STRING2INT{$ci} if exists $COLOR_INTERPRETATION_STRING2INT{$ci};
+        confess "Unknown color interpretation: '$ci'." unless exists $COLOR_INTERPRETATION_INT2STRING{$ci2};
+        SetRasterColorInterpretation($self, $ci2);
+        return $ci;
+    } else {
+        return $COLOR_INTERPRETATION_INT2STRING{GetRasterColorInterpretation($self)};
+    }
+}
+
+sub ColorTable {
+    my $self = shift;
+    SetRasterColorTable($self, $_[0]) if @_ and defined $_[0];
+    return unless defined wantarray;
+    GetRasterColorTable($self);
+}
+
+sub CategoryNames {
+    my $self = shift;
+    SetRasterCategoryNames($self, \@_) if @_;
+    return unless defined wantarray;
+    my $n = GetRasterCategoryNames($self);
+    return @$n;
+}
+
+sub AttributeTable {
+    my $self = shift;
+    SetDefaultRAT($self, $_[0]) if @_ and defined $_[0];
+    return unless defined wantarray;
+    my $r = GetDefaultRAT($self);
+    $Geo::GDAL::RasterAttributeTable::BANDS{$r} = $self if $r;
+    return $r;
+}
+
+sub GetHistogram {
+    my $self = shift;
+    my %defaults = (Min => -0.5,
+                    Max => 255.5,
+                    Buckets => 256,
+                    IncludeOutOfRange => 0,
+                    ApproxOK => 0,
+                    Progress => undef,
+                    ProgressData => undef);
+    my %params = @_;
+    for (keys %params) {
+        carp "unknown parameter $_ in Geo::GDAL::Band::GetHistogram" unless exists $defaults{$_};
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    $params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
+    _GetHistogram($self, $params{Min}, $params{Max}, $params{Buckets},
+                  $params{IncludeOutOfRange}, $params{ApproxOK},
+                  $params{Progress}, $params{ProgressData});
+}
+
+sub Contours {
+    my $self = shift;
+    my %defaults = (DataSource => undef,
+                    LayerConstructor => {Name => 'contours'},
+                    ContourInterval => 100,
+                    ContourBase => 0,
+                    FixedLevels => [],
+                    NoDataValue => undef,
+                    IDField => -1,
+                    ElevField => -1,
+                    Progress => undef,
+                    ProgressData => undef);
+    my %params;
+    if (!defined($_[0]) or (blessed($_[0]) and $_[0]->isa('Geo::OGR::DataSource'))) {
+        ($params{DataSource}, $params{LayerConstructor},
+         $params{ContourInterval}, $params{ContourBase},
+         $params{FixedLevels}, $params{NoDataValue},
+         $params{IDField}, $params{ElevField},
+         $params{Progress}, $params{ProgressData}) = @_;
+    } else {
+        %params = @_;
+        if (exists $params{progress}) {
+            $params{Progress} = $params{progress};
+            delete $params{progress};
+        }
+        if (exists $params{progress_data}) {
+            $params{ProgressData} = $params{progress_data};
+            delete $params{progress_data};
+        }
+    }
+    for (keys %params) {
+        carp "unknown parameter $_ in Geo::GDAL::Band::Contours" unless exists $defaults{$_};
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    $params{DataSource} = Geo::OGR::GetDriver('Memory')->CreateDataSource('ds')
+        unless defined $params{DataSource};
+    $params{LayerConstructor}->{Schema} = {} unless $params{LayerConstructor}->{Schema};
+    $params{LayerConstructor}->{Schema}{Fields} = [] unless $params{LayerConstructor}->{Schema}{Fields};
+    my %fields;
+    unless ($params{IDField} =~ /^[+-]?\d+$/ or $fields{$params{IDField}}) {
+        push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{IDField}, Type => 'Integer'};
+    }
+    unless ($params{ElevField} =~ /^[+-]?\d+$/ or $fields{$params{ElevField}}) {
+        my $type = $self->DataType() =~ /Float/ ? 'Real' : 'Integer';
+        push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{ElevField}, Type => $type};
+    }
+    my $layer = $params{DataSource}->CreateLayer($params{LayerConstructor});
+    my $schema = $layer->GetLayerDefn;
+    for ('IDField', 'ElevField') {
+        $params{$_} = $schema->GetFieldIndex($params{$_}) unless $params{$_} =~ /^[+-]?\d+$/;
+    }
+    $params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
+    ContourGenerate($self, $params{ContourInterval}, $params{ContourBase}, $params{FixedLevels},
+                    $params{NoDataValue}, $layer, $params{IDField}, $params{ElevField},
+                    $params{Progress}, $params{ProgressData});
+    return $layer;
+}
+
+sub FillNodata {
+    my $self = shift;
+    my $mask = shift;
+    $mask = $self->GetMaskBand unless $mask;
+    my @p = @_;
+    $p[0] = 10 unless defined $p[0];
+    $p[1] = 0 unless defined $p[1];
+    $p[2] = undef unless defined $p[2];
+    $p[3] = undef unless defined $p[3];
+    $p[4] = undef unless defined $p[1];
+    Geo::GDAL::FillNodata($self, $mask, @p);
+}
+*GetBandNumber = *GetBand;
+
+sub ReadRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        RESAMPLEALG => 'NearestNeighbour',
+        PROGRESS => undef,
+        PROGRESSDATA => undef
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{buf_pixel_space},$p{buf_line_space},$p{resample_alg},$p{progress},$p{progress_data}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    confess "Unknown resampling algorithm: '$p{RESAMPLEALG}'." 
+        unless exists $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    $p{RESAMPLEALG} = $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_ReadRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{RESAMPLEALG},$p{PROGRESS},$p{PROGRESSDATA});
+}
+
+sub WriteRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUF => undef,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{buf_pixel_space},$p{buf_line_space}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_WriteRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUF},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BUFPIXELSPACE},$p{BUFLINESPACE});
+}
+
+sub GetMaskFlags {
+    my $self = shift;
+    my $f = $self->_GetMaskFlags;
+    my @f;
+    for my $flag (keys %MASK_FLAGS) {
+        push @f, $flag if $f & $MASK_FLAGS{$flag};
+    }
+    return wantarray ? @f : $f;
+}
+
+sub CreateMaskBand {
+    my $self = shift;
+    my $f = 0;
+    if (@_ and $_[0] =~ /^\d$/) {
+        $f = shift;
+    } else {
+        for my $flag (@_) {
+            carp "Unknown mask flag: '$flag'." unless $MASK_FLAGS{$flag};
+            $f |= $MASK_FLAGS{$flag};
+        }
+    }
+    $self->_CreateMaskBand($f);
+}
+
+# GetMaskBand should be redefined and the result should be put into 
+# %Geo::GDAL::Dataset::BANDS
+
+# GetOverview should be redefined and the result should be put into 
+# %Geo::GDAL::Dataset::BANDS
+
+sub RegenerateOverview {
+    my $self = shift;
+    #Geo::GDAL::Band overview, scalar resampling, subref callback, scalar callback_data
+    my @p = @_;
+    Geo::GDAL::RegenerateOverview($self, @p);
+}
+ 
+sub RegenerateOverviews {
+    my $self = shift;
+    #arrayref overviews, scalar resampling, subref callback, scalar callback_data
+    my @p = @_;
+    Geo::GDAL::RegenerateOverviews($self, @p);
+}
+
+
+
+
+package Geo::GDAL::ColorTable;
+use strict;
+use warnings;
+use Carp;
+use vars qw/
+    %PALETTE_INTERPRETATION_STRING2INT %PALETTE_INTERPRETATION_INT2STRING
+    /;
+for my $string (qw/Gray RGB CMYK HLS/) {
+    my $int = eval "\$Geo::GDAL::Constc::GPI_$string";
+    $PALETTE_INTERPRETATION_STRING2INT{$string} = $int;
+    $PALETTE_INTERPRETATION_INT2STRING{$int} = $string;
+}
+%}
+
+%feature("shadow") GDALColorTableShadow(GDALPaletteInterp palette = GPI_RGB)
+%{
+use Carp;
+sub new {
+    my($pkg, $pi) = @_;
+    $pi = $PALETTE_INTERPRETATION_STRING2INT{$pi} if defined $pi and exists $PALETTE_INTERPRETATION_STRING2INT{$pi};
+    my $self = Geo::GDALc::new_ColorTable($pi);
+    bless $self, $pkg if defined($self);
+}
+%}
+
+%perlcode %{
+sub GetPaletteInterpretation {
+    my $self = shift;
+    return $PALETTE_INTERPRETATION_INT2STRING{GetPaletteInterpretation($self)};
+}
+
+sub SetColorEntry {
+    my $self = shift;
+    my $index = shift;
+    my $color;
+    if (ref($_[0]) eq 'ARRAY') {
+        $color = shift;
+    } else {
+        $color = [@_];
+    }
+    eval {
+        $self->_SetColorEntry($index, $color);
+    };
+    confess $@ if $@;
+}
+
+sub ColorEntry {
+    my $self = shift;
+    my $index = shift;
+    SetColorEntry($self, $index, @_) if @_ > 0;
+    GetColorEntry($self, $index) if defined wantarray;
+}
+
+sub ColorTable {
+    my $self = shift;
+    my @table;
+    if (@_) {
+        my $index = 0;
+        for my $color (@_) {
+            push @table, [ColorEntry($self, $index, @$color)];
+            $index++;
+        }
+    } else {
+        for (my $index = 0; $index < GetCount($self); $index++) {
+            push @table, [ColorEntry($self, $index)];
+        }
+    }
+    return @table;
+}
+*ColorEntries = *ColorTable;
+
+
+
+
+package Geo::GDAL::RasterAttributeTable;
+use strict;
+use warnings;
+use Carp;
+use vars qw/ %BANDS
+    @FIELD_TYPES @FIELD_USAGES
+    %FIELD_TYPE_STRING2INT %FIELD_TYPE_INT2STRING
+    %FIELD_USAGE_STRING2INT %FIELD_USAGE_INT2STRING
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@FIELD_TYPES, $1), next if /^GFT_(\w+)/;
+    push(@FIELD_USAGES, $1), next if /^GFU_(\w+)/;
+}
+for my $string (@FIELD_TYPES) {
+    my $int = eval "\$Geo::GDAL::Constc::GFT_$string";
+    $FIELD_TYPE_STRING2INT{$string} = $int;
+    $FIELD_TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@FIELD_USAGES) {
+    my $int = eval "\$Geo::GDAL::Constc::GFU_$string";
+    $FIELD_USAGE_STRING2INT{$string} = $int;
+    $FIELD_USAGE_INT2STRING{$int} = $string;
+}
+
+sub FieldTypes {
+    return @FIELD_TYPES;
+}
+
+sub FieldUsages {
+    return @FIELD_USAGES;
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $BANDS{$self};
+}
+
+sub GetUsageOfCol {
+    my($self, $col) = @_;
+    $FIELD_USAGE_INT2STRING{_GetUsageOfCol($self, $col)};
+}
+
+sub GetColOfUsage {
+    my($self, $usage) = @_;
+    _GetColOfUsage($self, $FIELD_USAGE_STRING2INT{$usage});
+}
+
+sub GetTypeOfCol {
+    my($self, $col) = @_;
+    $FIELD_TYPE_INT2STRING{_GetTypeOfCol($self, $col)};
+}
+
+sub Columns {
+    my $self = shift;
+    my %columns;
+    if (@_) { # create columns
+        %columns = @_;
+        for my $name (keys %columns) {
+            $self->CreateColumn($name, $columns{$name}{Type}, $columns{$name}{Usage});
+        }
+    }
+    %columns = ();
+    for my $c (0..$self->GetColumnCount-1) {
+        my $name = $self->GetNameOfCol($c);
+        $columns{$name}{Type} = $self->GetTypeOfCol($c);
+        $columns{$name}{Usage} = $self->GetUsageOfCol($c);
+    }
+    return %columns;
+}
+
+sub CreateColumn {
+    my($self, $name, $type, $usage) = @_;
+    confess "Unknown RAT column type: '$type'." unless exists $FIELD_TYPE_STRING2INT{$type};
+    confess "Unknown RAT column usage: '$usage'." unless exists $FIELD_USAGE_STRING2INT{$usage};
+    for my $color (qw/Red Green Blue Alpha/) {
+        carp "RAT column type will be 'Integer' for usage '$color'." if $usage eq $color and $type ne 'Integer';
+    }
+    $type = $FIELD_TYPE_STRING2INT{$type};
+    $usage = $FIELD_USAGE_STRING2INT{$usage};
+    _CreateColumn($self, $name, $type, $usage);
+}
+
+sub Value {
+    my($self, $row, $column) = @_;
+    SetValueAsString($self, $row, $column, $_[3]) if defined $_[3];
+    return unless defined wantarray;
+    GetValueAsString($self, $row, $column);
+}
+
+sub LinearBinning {
+    my $self = shift;
+    SetLinearBinning($self, @_) if @_ > 0;
+    return unless defined wantarray;
+    my @a = GetLinearBinning($self);
+    return $a[0] ? ($a[1], $a[2]) : ();
+}
+
+
+
+
+package Geo::GDAL::GCP;
+
+*swig_Pixel_get = *Geo::GDALc::GCP_Column_get;
+*swig_Pixel_set = *Geo::GDALc::GCP_Column_set;
+*swig_Line_get = *Geo::GDALc::GCP_Row_get;
+*swig_Line_set = *Geo::GDALc::GCP_Row_set;
+
+
+
+package Geo::GDAL::VSIF;
+use strict;
+use warnings;
+use Carp;
+
+sub Open {
+    my ($path, $mode) = @_;
+    my $self = Geo::GDAL::VSIFOpenL($path, $mode);
+    bless $self, 'Geo::GDAL::VSIF';
+}
+
+sub Write {
+    my ($self, $data) = @_;
+    Geo::GDAL::VSIFWriteL($data, $self);
+}
+
+sub Close {
+    my ($self, $data) = @_;
+    Geo::GDAL::VSIFCloseL($self);
+}
+
+sub Read {
+    my ($self, $count) = @_;
+    Geo::GDAL::VSIFReadL($count, $self);
+}
+
+sub Seek {
+    my ($self, $offset, $whence) = @_;
+    Geo::GDAL::VSIFSeekL($self, $offset, $whence);
+}
+
+sub Tell {
+    my ($self) = @_;
+    Geo::GDAL::VSIFTellL($self);
+}
+
+sub Truncate {
+    my ($self, $new_size) = @_;
+    Geo::GDAL::VSIFTruncateL($self, $new_size);
+}
+
+sub Mkdir {
+    my ($path, $mode) = @_;
+    Geo::GDAL::Mkdir($path, $mode);
+}
+*MkDir = *Mkdir;
+
+sub ReadDir {
+    my ($path) = @_;
+    Geo::GDAL::ReadDir($path);
+}
+
+sub ReadDirRecursive {
+    my ($path) = @_;
+    Geo::GDAL::ReadDirRecursive($path);
+}
+
+sub Rename {
+    my ($old, $new) = @_;
+    Geo::GDAL::Rename($old, $new);
+}
+
+sub Rmdir {
+    my ($dirname, $recursive) = @_;
+    if (!$recursive) {
+        Geo::GDAL::Rmdir($dirname);
+    } else {
+        for my $f (ReadDir($dirname)) {
+            next if $f eq '..' or $f eq '.';
+            my @s = Stat($dirname.'/'.$f);
+            if ($s[0] eq 'f') {
+                Unlink($dirname.'/'.$f);
+            } elsif ($s[0] eq 'd') {
+                Rmdir($dirname.'/'.$f, 1);
+                Rmdir($dirname.'/'.$f);
+            }
+        }
+        Rmdir($dirname);
+    }
+}
+*RmDir = *Rmdir;
+
+sub Stat {
+    my ($path) = @_;
+    Geo::GDAL::Stat($path);
+}
+
+sub Unlink {
+    my ($filename) = @_;
+    Geo::GDAL::Unlink($filename);
+}
+
+
+
+
+package Geo::GDAL::GeoTransform;
+use strict;
+use warnings;
+use Carp;
+
+sub new {
+    my $class = shift;
+    my $self;
+    if (@_ == 0) {
+        $self = [0,1,0,0,0,1];
+    } elsif (@_ == 1) {
+        $self = $_[0];
+    } else {
+        my @a = @_;
+        $self = \@a;
+    }
+    bless $self, $class;
+    return $self;
+}
+
+sub FromGCPs {
+    my @GCPs;
+    my $ApproxOK = 1;
+    if (ref($_[0]) eq 'ARRAY') {
+        @GCPs = @{$_[0]};
+        $ApproxOK = $_[1] if defined $_[1];
+    } else {
+        @GCPs = @_;
+        $ApproxOK = pop @GCPs if !ref($GCPs[$#GCPs]);
+    }
+    my $self = Geo::GDAL::GCPsToGeoTransform(\@GCPs, $ApproxOK);
+    bless $self, 'Geo::GDAL::GetTransform';
+    return $self;
+}
+
+sub Apply {
+    my ($self, $columns, $rows) = @_;
+    my (@x, @y);
+    for my $i (0..$#$columns) {
+        ($x[$i], $y[$i]) = 
+            Geo::GDAL::ApplyGeoTransform($self, $columns->[$i], $rows->[$i]);
+    }
+    return (\@x, \@y);
+}
+
+sub Inv {
+    my $self = shift;
+    my @inv = Geo::GDAL::InvGeoTransform($self);
+    unless (defined wantarray) {
+        @$self = @inv;
+    } else {
+        return new(@inv);
+    }
+}
+
+%}
+
 %{
 typedef void OGRLayerShadow;
 %}
@@ -771,17 +1510,17 @@ typedef void OGRLayerShadow;
     %apply (int nList, double* pList) {(int nFixedLevelCount, double *padfFixedLevels)};
     %apply (int defined, double value) {(int bUseNoData, double dfNoDataValue)};
     CPLErr ContourGenerate(double dfContourInterval, double dfContourBase,
-			   int nFixedLevelCount, double *padfFixedLevels,
-			   int bUseNoData, double dfNoDataValue, 
-			   OGRLayerShadow *hLayer, int iIDField, int iElevField,
-			   GDALProgressFunc callback = NULL,
-			   void* callback_data = NULL) {
-	return GDALContourGenerate( self, dfContourInterval, dfContourBase,
-				    nFixedLevelCount, padfFixedLevels,
-				    bUseNoData, dfNoDataValue, 
-				    hLayer, iIDField, iElevField,
-				    callback,
-				    callback_data );
+                           int nFixedLevelCount, double *padfFixedLevels,
+                           int bUseNoData, double dfNoDataValue,
+                           OGRLayerShadow *hLayer, int iIDField, int iElevField,
+                           GDALProgressFunc progress = NULL,
+                           void* progress_data = NULL) {
+        return GDALContourGenerate( self, dfContourInterval, dfContourBase,
+                                    nFixedLevelCount, padfFixedLevels,
+                                    bUseNoData, dfNoDataValue,
+                                    hLayer, iIDField, iElevField,
+                                    progress,
+                                    progress_data );
     }
     %clear (int nFixedLevelCount, double *padfFixedLevels);
     %clear (int bUseNoData, double dfNoDataValue);
diff --git a/swig/include/perl/gdal_perl_rename.i b/swig/include/perl/gdal_perl_rename.i
new file mode 100644
index 0000000..c3d6196
--- /dev/null
+++ b/swig/include/perl/gdal_perl_rename.i
@@ -0,0 +1,4 @@
+/* Make room for Perl interface */
+
+%rename (_GetDataTypeSize) GDALGetDataTypeSize;
+%rename (_DataTypeIsComplex) GDALDataTypeIsComplex;
diff --git a/swig/include/perl/ogr_perl.i b/swig/include/perl/ogr_perl.i
index 79d6fbc..4df0b12 100644
--- a/swig/include/perl/ogr_perl.i
+++ b/swig/include/perl/ogr_perl.i
@@ -32,7 +32,7 @@
   if ( OGRGetDriverCount() == 0 ) {
     OGRRegisterAll();
   }
-  
+
 %}
 
 %include callback.i
@@ -54,11 +54,13 @@ ALTERED_DESTROY(OGRFeatureDefnShadow, OGRc, delete_FeatureDefn)
 ALTERED_DESTROY(OGRFieldDefnShadow, OGRc, delete_FieldDefn)
 ALTERED_DESTROY(OGRGeometryShadow, OGRc, delete_Geometry)
 
+#ifndef FROM_GDAL_I
 %extend OGRDataSourceShadow {
 
   %rename (_ExecuteSQL) ExecuteSQL;
 
  }
+#endif
 
 %extend OGRGeometryShadow {
 
@@ -79,17 +81,17 @@ ALTERED_DESTROY(OGRGeometryShadow, OGRc, delete_Geometry)
 %extend OGRGeometryShadow {
 
     void Move(double dx, double dy, double dz = 0) {
-	int n = OGR_G_GetGeometryCount(self);
-	if (n > 0) {
-	    int i;
-	    for (i = 0; i < n; i++) {
-		OGRGeometryShadow *g = (OGRGeometryShadow*)OGR_G_GetGeometryRef(self, i);
-		OGRGeometryShadow_Move(g, dx, dy, dz);
-	    }
-	} else {
-	    int i;
-	    int d = OGR_G_GetCoordinateDimension(self);
-	    for (i = 0; i < OGR_G_GetPointCount(self); i++) {
+        int n = OGR_G_GetGeometryCount(self);
+        if (n > 0) {
+            int i;
+            for (i = 0; i < n; i++) {
+                OGRGeometryShadow *g = (OGRGeometryShadow*)OGR_G_GetGeometryRef(self, i);
+                OGRGeometryShadow_Move(g, dx, dy, dz);
+            }
+        } else {
+            int i;
+            int d = OGR_G_GetCoordinateDimension(self);
+            for (i = 0; i < OGR_G_GetPointCount(self); i++) {
                 if (d == 0) {
                 } else {
                     double x = OGR_G_GetX(self, i);
@@ -101,1201 +103,1845 @@ ALTERED_DESTROY(OGRGeometryShadow, OGRc, delete_Geometry)
                         OGR_G_SetPoint(self, i, x+dx, y+dy, z+dz);
                     }
                 }
-	    }
-	}
+            }
+        }
     }
-    
+
 }
 
-%rename (_GetLayerByIndex) GetLayerByIndex;
-%rename (_GetLayerByName) GetLayerByName;
+# wrapped data source methods:
+%rename (_GetDriver) GetDriver;
+%rename (_TestCapability) TestCapability;
+
+# wrapped layer methods:
+%rename (_ReleaseResultSet) ReleaseResultSet;
 %rename (_CreateLayer) CreateLayer;
 %rename (_DeleteLayer) DeleteLayer;
 %rename (_CreateField) CreateField;
 %rename (_DeleteField) DeleteField;
-%rename (_GetFieldType) GetFieldType;
-%rename (_SetGeometryDirectly) SetGeometryDirectly;
+%rename (_Validate) Validate;
+
+# wrapped feature methods:
+%rename (_AlterFieldDefn) AlterFieldDefn;
+%rename (_SetGeometry) SetGeometry;
+
+# wrapped geometry methods:
 %rename (_ExportToWkb) ExportToWkb;
-%rename (_GetDriver) GetDriver;
-%rename (_TestCapability) TestCapability;
 
 %perlcode %{
-    use strict;
-    use Carp;
-    {
-        package Geo::OGR;
+
+package Geo::OGR::Driver;
+use strict;
+use warnings;
+use Carp;
+use vars qw /@CAPABILITIES %CAPABILITIES/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^ODrC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::ODrC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    confess "No such capability defined for class Driver: '$cap'." unless defined $CAPABILITIES{$cap};
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+
+*Create = *CreateDataSource;
+*Copy = *CopyDataSource;
+*OpenDataSource = *Open;
+*Delete = *DeleteDataSource;
+*Name = *GetName;
+
+
+
+
+package Geo::OGR::DataSource;
+use strict;
+use warnings;
+use Carp;
+use vars qw /@CAPABILITIES %CAPABILITIES %LAYERS %RESULT_SET/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^ODsC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::ODsC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    confess "No such capability defined for class DataSource: '$cap'." unless defined $CAPABILITIES{$cap};
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+*GetDriver = *_GetDriver;
+
+sub new {
+    my $pkg = shift;
+    return Geo::OGR::Open(@_);
+}
+
+sub Open {
+    return Geo::OGR::Open(@_);
+}
+
+sub OpenShared {
+    return Geo::OGR::OpenShared(@_);
+}
+
+sub ExecuteSQL {
+    my $self = shift;
+    my $layer = $self->_ExecuteSQL(@_);
+    $LAYERS{tied(%$layer)} = $self;
+    $RESULT_SET{tied(%$layer)} = 1;
+    return $layer;
+}
+
+sub ReleaseResultSet {
+    # a no-op, _ReleaseResultSet is called from Layer::DESTROY
+}
+
+sub GetLayer {
+    my($self, $name) = @_;
+    my $layer = defined $name ? GetLayerByName($self, "$name") : GetLayerByIndex($self, 0);
+    $name = '' unless defined $name;
+    confess "No such layer: '$name'." unless $layer;
+    $LAYERS{tied(%$layer)} = $self;
+    return $layer;
+}
+*Layer = *GetLayer;
+
+sub GetLayerNames {
+    my $self = shift;
+    my @names;
+    for my $i (0..$self->GetLayerCount-1) {
+        my $layer = GetLayerByIndex($self, $i);
+        push @names, $layer->GetName;
+    }
+    return @names;
+}
+*Layers = *GetLayerNames;
+
+sub CreateLayer {
+    my $self = shift;
+    my %defaults = ( Name => 'unnamed',
+                     SRS => undef,
+                     Options => {},
+                     GeometryType => 'Unknown',
+                     Schema => undef,
+                     Fields => undef,
+                     ApproxOK => 1);
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $_[0] and exists $defaults{$_[0]})) {
+        %params = @_;
+    } else {
+        ($params{Name}, $params{SRS}, $params{GeometryType}, $params{Options}, $params{Schema}) = @_;
+    }
+    for (keys %params) {
+        carp "CreateLayer: unknown named parameter '$_'." unless exists $defaults{$_};
+    }
+    if (exists $params{Schema}) {
+        my $s = $params{Schema};
+        $params{GeometryType} = $s->{GeometryType} if exists $s->{GeometryType};
+        $params{Fields} = $s->{Fields} if exists $s->{Fields};
+        $params{Name} = $s->{Name} if exists $s->{Name};
+    }
+    $defaults{GeometryType} = 'None' if $params{Fields};
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    confess "Unknown geometry type: '$params{GeometryType}'."
+        unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
+    my $gt = $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
+    my $layer = _CreateLayer($self, $params{Name}, $params{SRS}, $gt, $params{Options});
+    $LAYERS{tied(%$layer)} = $self;
+    my $f = $params{Fields};
+    if ($f) {
+        confess "Named parameter 'Fields' must be a reference to an array." unless ref($f) eq 'ARRAY';
+        for my $field (@$f) {
+            $layer->CreateField($field);
+        }
+    }
+    return $layer;
+}
+
+sub DeleteLayer {
+    my ($self, $name) = @_;
+    my $index;
+    for my $i (0..$self->GetLayerCount-1) {
+        my $layer = GetLayerByIndex($self, $i);
+        $index = $i, last if $layer->GetName eq $name;
+    }
+    confess "No such layer: '$name'." unless defined $index;
+    _DeleteLayer($self, $index);
+}
+
+
+
+
+package Geo::OGR::Layer;
+use strict;
+use warnings;
+use Carp;
+use Scalar::Util 'blessed';
+use vars qw /@CAPABILITIES %CAPABILITIES  %DEFNS/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^OLC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::OLC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub DESTROY {
+    my $self;
+    if ($_[0]->isa('SCALAR')) {
+        $self = $_[0];
+    } else {
+        return unless $_[0]->isa('HASH');
+        $self = tied(%{$_[0]});
+        return unless defined $self;
+    }
+    if ($Geo::OGR::DataSource::RESULT_SET{$self}) {
+        $Geo::OGR::DataSource::LAYERS{$self}->_ReleaseResultSet($self);
+        delete $Geo::OGR::DataSource::RESULT_SET{$self}
+    }
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        delete $OWNER{$self};
+    }
+    $self->RELEASE_PARENTS();
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::DataSource::LAYERS{$self};
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+
+sub GetDataSource {
+    my $self = shift;
+    return $Geo::OGR::DataSource::LAYERS{$self};
+}
+*DataSource = *GetDataSource;
+
+sub GetDefn {
+    my $self = shift;
+    my $defn = $self->GetLayerDefn;
+    $DEFNS{$defn} = $self;
+    return $defn;
+}
+
+sub CreateField {
+    my $self = shift;
+    my %defaults = ( ApproxOK => 1,
+                     Type => '' );
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %params = @_;
+    } else {
+        ($params{Defn}) = @_;
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    if (blessed($params{Defn}) and $params{Defn}->isa('Geo::OGR::FieldDefn')) {
+        $self->_CreateField($params{Defn}, $params{ApproxOK});
+    } elsif (blessed($_[0]) and $params{Defn}->isa('Geo::OGR::GeomFieldDefn')) {
+        $self->CreateGeomField($params{Defn}, $params{ApproxOK});
+    } else {
+        my $a = $params{ApproxOK};
+        delete $params{ApproxOK};
+        if (exists $params{GeometryType}) {
+            $params{Type} = $params{GeometryType};
+            delete $params{GeometryType};
+        }
+        if (exists $Geo::OGR::FieldDefn::TYPE_STRING2INT{$params{Type}}) {
+            my $fd = Geo::OGR::FieldDefn->new(%params);
+            _CreateField($self, $fd, $a);
+        } else {
+            my $fd = Geo::OGR::GeomFieldDefn->new(%params);
+            CreateGeomField($self, $fd, $a);
+        }
+    }
+}
+
+sub AlterFieldDefn {
+    my $self = shift;
+    my $field = shift;
+    my $index;
+    eval {
+        $index = $self->GetFieldIndex($field);
+    };
+    confess "Only non-spatial fields can be altered.\n$@" if $@;
+    if (blessed($_[0]) and $_[0]->isa('Geo::OGR::FieldDefn')) {
+        _AlterFieldDefn($self, $index, @_);
+    } elsif (@_ % 2 == 0) {
+        my %params = @_;
+        my $definition = Geo::OGR::FieldDefn->new(%params);
+        my $flags = 0;
+        $flags |= 1 if exists $params{Name};
+        $flags |= 2 if exists $params{Type};
+        $flags |= 4 if exists $params{Width} or exists $params{Precision};
+        $flags |= 8 if exists $params{Nullable};
+        $flags |= 16 if exists $params{Default};
+        _AlterFieldDefn($self, $index, $definition, $flags);
+    } else {
+        croak "Usage: AlterFieldDefn(\$Name, \%NamedParameters)";
+    }
+}
+
+sub DeleteField {
+    my($self, $fn) = @_;
+    my $d = $self->GetDefn;
+    my $index = $d->GetFieldIndex($fn);
+    $index = $fn if $index < 0;
+    eval {
+        _DeleteField($self, $index);
+    };
+    confess "Field not found: '$fn'. Only non-spatial fields can be deleted." if $@;
+}
+
+sub GetSchema {
+    my $self = shift;
+    carp "Schema of a layer should not be set directly." if @_;
+    if (@_ and @_ % 2 == 0) {
+        my %schema = @_;
+        if ($schema{Fields}) {
+            for my $field (@{$schema{Fields}}) {
+                $self->CreateField($field);
+            }
+        }
+    }
+    return $self->GetDefn->Schema;
+}
+*Schema = *GetSchema;
+
+sub Row {
+    my $self = shift;
+    my $update = @_ > 0;
+    my %row = @_;
+    my $feature = defined $row{FID} ? $self->GetFeature($row{FID}) : $self->GetNextFeature;
+    return unless $feature;
+    my $ret;
+    if (defined wantarray) {
+        $ret = $feature->Row(@_);
+    } else {
+        $feature->Row(@_);
+    }
+    $self->SetFeature($feature) if $update;
+    return unless defined wantarray;
+    return $ret;
+}
+
+sub Tuple {
+    my $self = shift;
+    my $FID = shift;
+    my $feature = defined $FID ? $self->GetFeature($FID) : $self->GetNextFeature;
+    return unless $feature;
+    my $set = @_ > 0;
+    unshift @_, $feature->GetFID if $set;
+    my @ret;
+    if (defined wantarray) {
+        @ret = $feature->Tuple(@_);
+    } else {
+        $feature->Tuple(@_);
+    }
+    $self->SetFeature($feature) if $set;
+    return unless defined wantarray;
+    return @ret;
+}
+
+sub SpatialFilter {
+    my $self = shift;
+    $self->SetSpatialFilter($_[0]) if @_ == 1;
+    $self->SetSpatialFilterRect(@_) if @_ == 4;
+    return unless defined wantarray;
+    $self->GetSpatialFilter;
+}
+
+sub InsertFeature {
+    my $self = shift;
+    my $feature = shift;
+    confess "Usage: \$feature->InsertFeature(reference to a hash or array)." unless ref($feature);
+    my $new = Geo::OGR::Feature->new($self->GetDefn);
+    if (ref($feature) eq 'HASH') {
+        $new->Row(%$feature);
+    } elsif (ref($feature) eq 'ARRAY') {
+        $new->Tuple(@$feature);
+    } elsif (blessed($feature) and $feature->isa('Geo::OGR::Feature')) {
+        $new->Row($feature->Row);
+    }
+    $self->CreateFeature($new);
+}
+
+sub ForFeatures {
+    my $self = shift;
+    my $code = shift;
+    my $in_place = shift;
+    $self->ResetReading;
+    while (my $f = $self->GetNextFeature) {
+        $code->($f);
+        $self->SetFeature($f) if $in_place;
+    };
+}
+
+sub ForGeometries {
+    my $self = shift;
+    my $code = shift;
+    my $in_place = shift;
+    $self->ResetReading;
+    while (my $f = $self->GetNextFeature) {
+        my $g = $f->Geometry();
+        $code->($g);
+        if ($in_place) {
+            $f->Geometry($g);
+            $self->SetFeature($f);
+        }
+    }
+}
+
+sub GetFieldNames {
+    my $self = shift;
+    my $d = $self->GetDefn;
+    my @ret;
+    for (my $i = 0; $i < $d->GetFieldCount; $i++) {
+        push @ret, $d->GetFieldDefn($i)->Name();
+    }
+    for (my $i = 0; $i < $d->GetGeomFieldCount; $i++) {
+        push @ret, $d->GetGeomFieldDefn($i)->Name();
+    }
+    return @ret;
+}
+
+sub GetFieldDefn {
+    my ($self, $name) = @_;
+    my $d = $self->GetDefn;
+    for (my $i = 0; $i < $d->GetFieldCount; $i++) {
+        my $fd = $d->GetFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    for (my $i = 0; $i < $d->GetGeomFieldCount; $i++) {
+        my $fd = $d->GetGeomFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GeometryType {
+    my $self = shift;
+    my $d = $self->GetDefn;
+    my $fd = $d->GetGeomFieldDefn(0);
+    return $fd->Type if $fd;
+}
+
+sub SpatialReference {
+    my($self, $field, $sr) = @_;
+    my $d = $self->GetDefn;
+    my $i;
+    if (not defined $field or (blessed($field) and $field->isa('Geo::OSR::SpatialReference'))) {
+        $i = 0;
+    } else {
+        $i = $d->GetGeomFieldIndex($field);
+    }
+    my $d2 = $d->GetGeomFieldDefn($i);
+    $d2->SpatialReference($sr) if defined $sr;
+    return $d2->SpatialReference() if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::FeatureDefn;
+use strict;
+use warnings;
+use Encode;
+use Carp;
+use Scalar::Util 'blessed';
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::Feature::DEFNS{$self};
+    delete $Geo::OGR::Layer::DEFNS{$self};
+}
+%}
+
+%feature("shadow") OGRFeatureDefnShadow(const char* name_null_ok=NULL)
+%{
+use Carp;
+use Scalar::Util 'blessed';
+sub new {
+    my $pkg = shift;
+    my %schema;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %schema = %{$_[0]};
+    } elsif (@_ and @_ % 2 == 0) {
+        %schema = @_;
+    }
+    my $fields = $schema{Fields};
+    confess "The Fields argument is not a reference to an array." if $fields and ref($fields) ne 'ARRAY';
+    $schema{Name} = '' unless exists $schema{Name};
+    my $self = Geo::OGRc::new_FeatureDefn($schema{Name});
+    bless $self, $pkg;
+    my $gt = $schema{GeometryType};
+    if ($fields) {
+        $self->DeleteGeomFieldDefn(0); # either default behavior or argument specified
+    } else {
+        $self->GeometryType($schema{GeometryType}) if exists $schema{GeometryType};
+    }
+    $self->StyleIgnored($schema{StyleIgnored}) if exists $schema{StyleIgnored};
+    for my $fd (@{$fields}) {
+        my $d = $fd;
+        if (ref($fd) eq 'HASH') {
+            if ($fd->{GeometryType} or exists $Geo::OGR::Geometry::TYPE_STRING2INT{$fd->{Type}}) {
+                $d = Geo::OGR::GeomFieldDefn->new(%$fd);
+            } else {
+                $d = Geo::OGR::FieldDefn->new(%$fd);
+            }
+        }
+        if (blessed($d) and $d->isa('Geo::OGR::FieldDefn')) {
+            AddFieldDefn($self, $d);
+        } elsif (blessed($d) and $d->isa('Geo::OGR::GeomFieldDefn')) {
+            AddGeomFieldDefn($self, $d);
+        } else {
+            confess "Item in field list does not define a field.";
+        }
+    }
+    return $self;
+}
+%}
+
+%perlcode %{
+*Name = *GetName;
+
+sub GetSchema {
+    my $self = shift;
+    carp "Schema of a feature definition should not be set directly." if @_;
+    if (@_ and @_ % 2 == 0) {
+        my %schema = @_;
+        if ($schema{Fields}) {
+            for my $field (@{$schema{Fields}}) {
+                $self->AddField($field);
+            }
+        }
+    }
+    my %schema;
+    $schema{Name} = $self->Name();
+    $schema{StyleIgnored} = $self->StyleIgnored();
+    $schema{Fields} = [];
+    for my $i (0..$self->GetFieldCount-1) {
+        my $s = $self->GetFieldDefn($i)->Schema;
+        push @{$schema{Fields}}, $s;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        my $s = $self->GetGeomFieldDefn($i)->Schema;
+        push @{$schema{Fields}}, $s;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*Schema = *GetSchema;
+
+sub AddField {
+    my $self = shift;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %params = @_;
+    }
+    $params{Type} = '' unless defined $params{Type};
+    if (exists $Geo::OGR::FieldDefn::TYPE_STRING2INT{$params{Type}}) {
+        my $fd = Geo::OGR::FieldDefn->new(%params);
+        $self->AddFieldDefn($fd);
+    } else {
+        my $fd = Geo::OGR::GeomFieldDefn->new(%params);
+        $self->AddGeomFieldDefn($fd);
+    }
+}
+
+sub DeleteField {
+    my ($self, $name) = @_;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    for my $i (0..$self->GetFieldCount-1) {
+        confess "Non-geometry fields cannot be deleted." if $self->GetFieldDefn($i)->Name eq $name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        $self->DeleteGeomFieldDefn($i) if $self->GetGeomFieldDefn($i)->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GetFieldNames {
+    my $self = shift;
+    my @names = ();
+    for my $i (0..$self->GetFieldCount-1) {
+        push @names, $self->GetFieldDefn($i)->Name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        push @names, $self->GetGeomFieldDefn($i)->Name;
+    }
+    return @names;
+}
+
+sub GetFieldDefn {
+    my ($self, $name) = @_;
+    for my $i (0..$self->GetFieldCount-1) {
+        my $fd = $self->GetFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        my $fd = $self->GetGeomFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GeomType {
+    my ($self, $type) = @_;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    if (defined $type) {
+        confess "Unknown geometry data type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        SetGeomType($self, $type);
+    }
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)} if defined wantarray;
+}
+*GeometryType = *GeomType;
+
+sub GeometryIgnored {
+    my $self = shift;
+    SetGeometryIgnored($self, $_[0]) if @_;
+    IsGeometryIgnored($self) if defined wantarray;
+}
+
+sub StyleIgnored {
+    my $self = shift;
+    SetStyleIgnored($self, $_[0]) if @_;
+    IsStyleIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::Feature;
+use strict;
+use warnings;
+use vars qw /%GEOMETRIES %DEFNS/;
+use Carp;
+use Encode;
+use Scalar::Util 'blessed';
+%}
+
+%feature("shadow") OGRFeatureShadow()
+%{
+use Carp;
+sub new {
+    my $pkg = shift;
+    if (blessed($_[0]) and $_[0]->isa('Geo::OGR::FeatureDefn')) {
+        return $pkg->new($_[0]);
+    } else {
+        return $pkg->new(Geo::OGR::FeatureDefn->new(@_));
+    }
+}
+%}
+
+%perlcode %{
+sub FETCH {
+    my($self, $index) = @_;
+    my $i;
+    eval {$i = $self->_GetFieldIndex($index)};
+    $self->GetField($i) unless $@;
+    $i = $self->_GetGeomFieldIndex($index);
+    $self->GetGeometry($i);
+}
+
+sub STORE {
+    my $self = shift;
+    my $index = shift;
+    my $i;
+    eval {$i = $self->_GetFieldIndex($index)};
+    $self->SetField($i, @_) unless $@;
+    $i = $self->_GetGeomFieldIndex($index);
+    $self->SetGeometry($i, @_);
+}
+
+sub FID {
+    my $self = shift;
+    $self->SetFID($_[0]) if @_;
+    return unless defined wantarray;
+    $self->GetFID;
+}
+
+sub StyleString {
+    my $self = shift;
+    $self->SetStyleString($_[0]) if @_;
+    return unless defined wantarray;
+    $self->GetStyleString;
+}
+
+sub Validate {
+    my $self = shift;
+    my $flags = 0;
+    for my $flag (@_) {
+        my $f = eval '$Geo::OGR::'.uc($flag);
+        $flags |= $f;
+    }
+    _Validate($self, $flags);
+}
+
+sub GetSchema {
+    my $self = shift;
+    confess "Schema of a feature cannot be set directly." if @_;
+    return $self->GetDefnRef->Schema;
+}
+*Schema = *GetSchema;
+
+sub Row {
+    my $self = shift;
+    my $nf = $self->GetFieldCount;
+    my $ngf = $self->GetGeomFieldCount;
+    if (@_) { # update
+        my %row;
+        if (@_ == 1 and ref($_[0]) eq 'HASH') {
+            %row = %{$_[0]};
+        } elsif (@_ and @_ % 2 == 0) {
+            %row = @_;
+        } else {
+            confess 'Usage: $feature->Row(%FeatureData).';
+        }
+        $self->SetFID($row{FID}) if defined $row{FID};
+        #$self->Geometry($schema, $row{Geometry}) if $row{Geometry};
+        for my $name (keys %row) {
+            next if $name eq 'FID';
+            if ($name eq 'Geometry') {
+                $self->SetGeometry(0, $row{$name});
+                next;
+            }
+            my $f = 0;
+            for my $i (0..$nf-1) {
+                if ($self->GetFieldDefnRef($i)->Name eq $name) {
+                    $self->SetField($i, $row{$name});
+                    $f = 1;
+                    last;
+                }
+            }
+            next if $f;
+            for my $i (0..$ngf-1) {
+                if ($self->GetGeomFieldDefnRef($i)->Name eq $name) {
+                    $self->SetGeometry($i, $row{$name});
+                    $f = 1;
+                    last;
+                }
+            }
+            next if $f;
+            carp "Feature->Row: Unknown field: '$name'.";
+        }
+    }
+    return unless defined wantarray;
+    my %row = ();
+    for my $i (0..$nf-1) {
+        my $name = $self->GetFieldDefnRef($i)->Name;
+        $row{$name} = $self->GetField($i);
+    }
+    for my $i (0..$ngf-1) {
+        my $name = $self->GetGeomFieldDefnRef($i)->Name;
+        $name = 'Geometry' if $name eq '';
+        $row{$name} = $self->GetGeometry($i);
+    }
+    $row{FID} = $self->GetFID;
+    #$row{Geometry} = $self->Geometry;
+    return \%row;
+}
+
+sub Tuple {
+    my $self = shift;
+    my $nf = $self->GetFieldCount;
+    my $ngf = $self->GetGeomFieldCount;
+    if (@_) {
+        my $FID;
+        $FID = shift if @_ == $nf + $ngf + 1;
+        $self->SetFID($FID) if defined $FID;
+        my $values = \@_;
+        if (@$values != $nf + $ngf) {
+            my $n = $nf + $ngf;
+            confess "Too many or too few attribute values for a feature (need $n).";
+        }
+        my $index = 0; # index to non-geometry and geometry fields
+        for my $i (0..$nf-1) {
+            $self->SetField($i, $values->[$i]);
+        }
+        for my $i (0..$ngf-1) {
+            $self->SetGeometry($i, $values->[$nf+$i]);
+        }
+    }
+    return unless defined wantarray;
+    my @ret = ($self->GetFID);
+    for my $i (0..$nf-1) {
+        my $v = $self->GetField($i);
+        push @ret, $v;
+    }
+    for my $i (0..$ngf-1) {
+        my $v = $self->GetGeometry($i);
+        push @ret, $v;
+    }
+    return @ret;
+}
+
+sub GetDefn {
+    my $self = shift;
+    my $defn = $self->GetDefnRef;
+    $DEFNS{$defn} = $self;
+    return $defn;
+}
+
+*GetFieldNames = *Geo::OGR::Layer::GetFieldNames;
+*GetFieldDefn = *Geo::OGR::Layer::GetFieldDefn;
+
+sub _GetFieldIndex {
+    my($self, $field) = @_;
+    if ($field =~ /^\d+$/) {
+        return $field if $field >= 0 and $field < $self->GetFieldCount;
+    } else {
+        for my $i (0..$self->GetFieldCount-1) {
+            return $i if $self->GetFieldDefnRef($i)->Name eq $field;
+        }
+    }
+    confess "No such field: '$field'.";
+}
+
+sub GetField {
+    my($self, $field) = @_;
+    $field = $self->_GetFieldIndex($field);
+    return unless IsFieldSet($self, $field);
+    my $type = GetFieldType($self, $field);
+    if ($type == $Geo::OGR::OFTInteger) {
+        return GetFieldAsInteger($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTInteger64) {
+        return GetFieldAsInteger64($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTReal) {
+        return GetFieldAsDouble($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTString) {
+        return GetFieldAsString($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTIntegerList) {
+        my $ret = GetFieldAsIntegerList($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTInteger64List) {
+        my $ret = GetFieldAsInteger64List($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTRealList) {
+        my $ret = GetFieldAsDoubleList($self, $field);
+        return wantarray ? @$ret : $ret;
     }
+    if ($type == $Geo::OGR::OFTStringList) {
+        my $ret = GetFieldAsStringList($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTBinary) {
+        return GetFieldAsString($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTDate) {
+        my @ret = GetFieldAsDateTime($self, $field);
+        # year, month, day, hour, minute, second, timezone
+        return wantarray ? @ret[0..2] : [@ret[0..2]];
+    }
+    if ($type == $Geo::OGR::OFTTime) {
+        my @ret = GetFieldAsDateTime($self, $field);
+        return wantarray ? @ret[3..6] : [@ret[3..6]];
+    }
+    if ($type == $Geo::OGR::OFTDateTime) {
+        return GetFieldAsDateTime($self, $field);
+    }
+    confess "Perl bindings do not support field type '$Geo::OGR::FieldDefn::TYPE_INT2STRING{$type}'.";
+}
+
+sub UnsetField {
+    my($self, $field) = @_;
+    $field = $self->_GetFieldIndex($field);
+    _UnsetField($self, $field);
+}
+
+sub SetField {
+    my $self = shift;
+    my $field = shift;
+    $field = $self->_GetFieldIndex($field);
+    if (@_ == 0 or !defined($_[0])) {
+        _UnsetField($self, $field);
+        return;
+    }
+    my $list = ref($_[0]) ? $_[0] : [@_];
+    my $type = GetFieldType($self, $field);
+    if ($type == $Geo::OGR::OFTInteger or
+        $type == $Geo::OGR::OFTInteger64 or
+        $type == $Geo::OGR::OFTReal or
+        $type == $Geo::OGR::OFTString or
+        $type == $Geo::OGR::OFTBinary)
     {
-        package Geo::OGR::Driver;
-	use strict;
-	use vars qw /@CAPABILITIES %CAPABILITIES/;
-	@CAPABILITIES = qw/CreateDataSource DeleteDataSource/; 
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::ODrC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-        sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-	*Create = *CreateDataSource;
-	*Copy = *CopyDataSource;
-	*OpenDataSource = *Open;
-	*Delete = *DeleteDataSource;
-	*Name = *GetName;
-
-	package Geo::OGR::DataSource;
-	use Carp;
-	use strict;
-	use vars qw /@CAPABILITIES %CAPABILITIES %LAYERS/;
-	@CAPABILITIES = qw/CreateLayer DeleteLayer/;
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::ODsC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-	sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-	*GetDriver = *_GetDriver;
-	sub new {
-	    my $pkg = shift;
-	    return Geo::OGR::Open(@_);
-	}
-	sub Open {
-	    return Geo::OGR::Open(@_);
-	}
-	sub OpenShared {
-	    return Geo::OGR::OpenShared(@_);
-	}
-	sub ExecuteSQL {
-	    my $self = shift;
-	    my $layer = $self->_ExecuteSQL(@_);
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub Layer {
-	    my($self, $name) = @_;
-	    my $layer;
-	    if (defined $name) {
-		$layer = _GetLayerByName($self, "$name");
-		croak "$name is not a layer in this datasource" if (not $layer and not $name =~ /^\d+$/);
-		$layer = _GetLayerByIndex($self, $name+0) unless $layer;
-	    } else {
-		$layer = _GetLayerByIndex($self, 0);
-	    }
-	    croak "the data source does not appear to have a layer with name '$name'" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub Layers {
-	    my $self = shift;
-	    my @names;
-	    for my $i (0..$self->GetLayerCount-1) {
-		my $layer = _GetLayerByIndex($self, $i);
-		push @names, $layer->GetName;
-	    }
-	    return @names;
-	}
-	sub GetLayerByIndex {
-	    my($self, $index) = @_;
-	    $index = 0 unless defined $index;
-	    my $layer = _GetLayerByIndex($self, $index+0);
-	    croak "the data source does not appear to have a layer with index '$index'" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub GetLayerByName {
-	    my($self, $name) = @_;
-	    my $layer = _GetLayerByName($self, "$name");
-	    croak "the data source does not appear to have a layer with name $name" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub CreateLayer {
-	    my $self = shift;
-	    my %defaults = (Name => 'unnamed',
-			    SRS => undef, 
-			    GeometryType => 'Unknown', 
-			    Options => [], 
-			    Schema => undef,
-			    Fields => undef);
-	    my %params;
-	    if (ref($_[0]) eq 'HASH') {
-		%params = %{$_[0]};
-	    } else {
-		($params{Name}, $params{SRS}, $params{GeometryType}, $params{Options}, $params{Schema}) = @_;
-	    }
-	    for (keys %params) {
-		carp "unknown parameter $_ in Geo::OGR::DataSource->CreateLayer" unless exists $defaults{$_};
-	    }
-	    for (keys %defaults) {
-		$params{$_} = $defaults{$_} unless defined $params{$_};
-	    }
-	    $params{GeometryType} = $params{Schema}->{GeometryType} if 
-		($params{Schema} and exists $params{Schema}->{GeometryType});
-	    $params{GeometryType} = $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}} if 
-		exists $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
-	    my $layer = _CreateLayer($self, $params{Name}, $params{SRS}, $params{GeometryType}, $params{Options});
-	    $LAYERS{tied(%$layer)} = $self;
-	    if ($params{Fields}) {
-		$params{Schema} = {} unless $params{Schema};
-		$params{Schema}{Fields} = $params{Fields};
-	    }
-	    $layer->Schema(%{$params{Schema}}) if $params{Schema};
-	    return $layer;
-	}
-	sub DeleteLayer {
-	    my $self = shift;
-	    my $name;
-	    if (@_ == 2) {
-		my %param = @_;
-		_DeleteLayer($self, $param{index}), return if exists $param{index};
-		$name = $param{name};
-	    } else {
-		$name = shift;
-	    }
-	    my $index;
-	    for my $i (0..$self->GetLayerCount-1) {
-		my $layer = _GetLayerByIndex($self, $i);
-		$index = $i, last if $layer->GetName eq $name;
-	    }
-	    $index = $name unless defined $index;
-	    _DeleteLayer($self, $index) if defined $index;
-	}
-
-	package Geo::OGR::Layer;
-	use strict;
-	use Carp;
-	use Scalar::Util 'blessed';
-	use vars qw /@CAPABILITIES %CAPABILITIES/;
-	@CAPABILITIES = qw/RandomRead SequentialWrite RandomWrite 
-		   FastSpatialFilter FastFeatureCount FastGetExtent 
-		   CreateField DeleteField ReorderFields AlterFieldDefn
-                   Transactions DeleteFeature FastSetNextByIndex
-                   StringsAsUTF8 IgnoreFields/;
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::OLC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub DESTROY {
-	    my $self;
-	    if ($_[0]->isa('SCALAR')) {
-		$self = $_[0];
-	    } else {
-		return unless $_[0]->isa('HASH');
-		$self = tied(%{$_[0]});
-		return unless defined $self;
-	    }
-	    delete $ITERATORS{$self};
-	    if (exists $OWNER{$self}) {
-		delete $OWNER{$self};
-	    }
-	    $self->RELEASE_PARENTS();
-	}
-	sub RELEASE_PARENTS {
-	    my $self = shift;
-	    delete $Geo::OGR::DataSource::LAYERS{$self};
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-	sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-        sub DataSource {
-	    my $self = shift;
-	    return $Geo::OGR::DataSource::LAYERS{$self};
-	}
-	sub HasField {
-	    my($self, $fn) = @_;
-	    eval {
-		$fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-		$self->GetLayerDefn->GetFieldDefn($fn);
-	    };
-	    return $@ eq '';
-	}
-        sub GetField {
-	    my($self, $fn) = @_;
-	    $fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-	    return $self->GetLayerDefn->GetFieldDefn($fn)->Schema;
-	}
-	sub CreateField {
-	    my $self = shift;
-	    my $fd = shift;
-	    if (blessed($fd) and $fd->isa('Geo::OGR::FieldDefn')) {
-		my $n = $fd->Schema->{Name};
-		croak "the layer already has a field with name '$n'" if $self->HasField($n);
-		my $a = shift || 1;
-		_CreateField($self, $fd, $a);
-	    } else {
-		$fd = Geo::OGR::FieldDefn->create($fd, @_);
-		my $n = $fd->Schema->{Name};
-		croak "the layer already has a field with name '$n'" if $self->HasField($n);
-		_CreateField($self, $fd); # approximation flag cannot be set using this method
-	    }
-	}
-        sub AlterField {
-	    my $self = shift;
-	    my $fn = shift;
-	    my $index = $fn;	    
-	    $index = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-	    my $field = $self->GetLayerDefn->GetFieldDefn($index);
-	    my $definition = Geo::OGR::FieldDefn->create(@_);
-	    my $flags = 0;
-	    my %params = @_;
-	    $flags |= 1 if $params{Name};
-	    $flags |= 2 if $params{Type};
-	    $flags |= 4 if $params{Width};
-	    AlterFieldDefn($self, $index, $definition, $flags);
-	}
-	sub DeleteField {
-	    my($self, $fn) = @_;
-	    $fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /\d+/;
-	    _DeleteField($self, $fn);
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %schema = @_;
-		# the Name and GeometryType cannot be set
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    $schema{ApproxOK} = 1 unless defined $schema{ApproxOK};
-		    _CreateField($self, $fd, $schema{ApproxOK});
-		}
-	    }
-	    return unless defined wantarray;
-	    return $self->GetLayerDefn->Schema;
-	}
-	sub Row {
-	    my $self = shift;
-	    my %row;
-	    my $update;
-	    if (@_ > 0 and ref($_[0])) { # undocumented hack: the first argument may be the schema
-		$update = @_ > 1;
-		%row = @_[1..$#$_];
-	    } else {
-		$update = @_ > 0;
-		%row = @_;
-	    }
-	    my $feature = defined $row{FID} ? $self->GetFeature($row{FID}) : $self->GetNextFeature;
-	    return unless $feature;
-	    my $ret;
-	    if (defined wantarray) {
-		$ret = $feature->Row(@_);
-	    } else {
-		$feature->Row(@_);
-	    }
-	    $self->SetFeature($feature) if $update;
-	    return unless defined wantarray;
-	    return $ret;
-	}
-	sub Tuple {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    my $FID = shift;
-	    my $feature = defined $FID ? $self->GetFeature($FID) : $self->GetNextFeature;
-	    return unless $feature;
-	    my $set = @_ > 0;
-	    unshift @_, $feature->GetFID if $set;
-	    my @ret;
-	    if (defined wantarray) {
-		@ret = $feature->Tuple($schema, @_);
-	    } else {
-		$feature->Tuple($schema, @_);
-	    }
-	    $self->SetFeature($feature) if $set;
-	    return unless defined wantarray;
-	    return @ret;
-	}
-	sub SpatialFilter {
-	    my $self = shift;
-	    $self->SetSpatialFilter($_[0]) if @_ == 1;
-	    $self->SetSpatialFilterRect(@_) if @_ == 4;
-	    return unless defined wantarray;
-	    $self->GetSpatialFilter;
-	}
-	sub InsertFeature {
-	    my $self = shift;
-	    my $feature = shift;
-	    croak "InsertFeature requires the feature data in an object or in a referenced hash or array" unless ref($feature);
-	    my $schema = shift;
-	    $schema = $self->Schema unless $schema;
-	    my $new = Geo::OGR::Feature->create($schema);
-	    if (ref($feature) eq 'HASH') {
-		$new->Row($schema, %$feature);
-	    } elsif (ref($feature) eq 'ARRAY') {
-		$new->Tuple($schema, @$feature);
-	    } elsif (blessed($feature) and $feature->isa('Geo::OGR::Feature')) {
-		$new->Row($schema, $feature->Row);
-	    }
-	    $self->CreateFeature($new);
-	}
-	sub ForFeatures {
-	    my $self = shift;
-	    my $code = shift;
-	    my $in_place = shift;
-	    $self->ResetReading;
-	    while (my $f = $self->GetNextFeature) {
-		$code->($f);
-		$self->SetFeature($f) if $in_place;
-	    };
-	}
-	sub ForGeometries {
-	    my $self = shift;
-	    my $code = shift;
-	    my $in_place = shift;
-	    $self->ResetReading;
-	    while (my $f = $self->GetNextFeature) {
-		my $g = $f->Geometry();
-		$code->($g);
-		if ($in_place) {
-		    $f->Geometry($g);
-		    $self->SetFeature($f);
-		}
-	    }
-	}
-	sub GeometryType {
-	    my $self = shift;
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)};
-	}
-
-	package Geo::OGR::FeatureDefn;
-	use strict;
-	use Encode;
-	sub create {
-	    my $pkg = shift;
-	    my %schema;
-	    if (@_ == 1) {
-	        %schema = %{$_[0]};
-	    } else {
-	        %schema = @_;
-	    }
-	    my $self = Geo::OGRc::new_FeatureDefn($schema{Name});
-	    bless $self, $pkg;
-	    $self->GeometryType($schema{GeometryType});
-	    for my $fd (@{$schema{Fields}}) {
-		my $d;
-		if (ref($fd) eq 'HASH') {
-		    $d = Geo::OGR::FieldDefn->create(%$fd);
-		} else {
-		    $d = Geo::OGR::FieldDefn->create($fd->Schema);
-		}
-		AddFieldDefn($self, $d);
-	    }
-	    return $self;
-	}
-	*Name = *GetName;
-	sub Schema {
-	    my $self = shift;
-	    my %schema;
-	    if (@_) {
-		%schema = @_;
-		# the Name cannot be set
-		$self->GeomType($schema{GeometryType}) if exists $schema{GeometryType};
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    AddFieldDefn($self, $fd);
-		}
-	    }
-	    return unless defined wantarray;
-	    $schema{Name} = $self->GetName();
-	    $schema{GeometryType} = $self->GeomType();
-	    $schema{Fields} = [];
-	    for my $i (0..$self->GetFieldCount-1) {
-		my $s = $self->GetFieldDefn($i)->Schema;
-		$s->{Index} = $i;
-		push @{$schema{Fields}}, $s;
-	    }
-	    return wantarray ? %schema : \%schema;
-	}
-	sub GeomType {
-	    my($self, $type) = @_;
-	    if ($type) {
-		$type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type} if 
-		    $type and exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
-		SetGeomType($self, $type);
-	    }
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)} if defined wantarray;
-	}
-	*GeometryType = *GeomType;
-	sub GeometryIgnored {
-	    my $self = shift;
-	    SetGeometryIgnored($self, $_[0]) if @_;
-	    IsGeometryIgnored($self) if defined wantarray;
-	}
-	sub StyleIgnored {
-	    my $self = shift;
-	    SetStyleIgnored($self, $_[0]) if @_;
-	    IsStyleIgnored($self) if defined wantarray;
-	}
-
-	package Geo::OGR::Feature;
-	use strict;
-	use vars qw /%GEOMETRIES/;
-	use Carp;
-	use Encode;
-	sub create {
-	    my $pkg = shift;
-	    $pkg->new(Geo::OGR::FeatureDefn->create(@_));
-	}
-	sub FETCH {
-	    my($self, $index) = @_;
-	    $self->GetField($index);
-	}
-	sub STORE {
-	    my $self = shift;
-	    $self->SetField(@_);
-	}
-	sub FID {
-	    my $self = shift;
-	    $self->SetFID($_[0]) if @_;
-	    return unless defined wantarray;
-	    $self->GetFID;
-	}
-	sub StyleString {
-	    my $self = shift;
-	    $self->SetStyleString($_[0]) if @_;
-	    return unless defined wantarray;
-	    $self->GetStyleString;
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %schema = @_;
-		# the Name and GeometryType cannot be set
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    $schema{ApproxOK} = 1 unless defined $schema{ApproxOK};
-		    CreateField($self, $fd, $schema{ApproxOK});
-		}
-	    }
-	    return unless defined wantarray;
-	    return $self->GetDefnRef->Schema;
-	}
-	sub Row {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    if (@_) { # update
-		my %row = ref($_[0]) ? %{$_[0]} : @_;
-		$self->SetFID($row{FID}) if defined $row{FID};
-		$self->Geometry($schema, $row{Geometry}) if $row{Geometry};
-		for my $fn (keys %row) {
-		    next if $fn eq 'FID';
-		    next if $fn eq 'Geometry';
-		    my $index = GetFieldIndex($self, $fn);
-		    next if $index < 0;
-		    $self->SetField($index, $row{$fn});
-		}
-	    }
-	    return unless defined wantarray;
-	    my %row = ();
-	    for my $field (@{$schema->{Fields}}) {
-		my $n = $field->{Name};
-		if (FieldIsList($self, $n)) {
-		    $row{$n} = [$self->GetField($n)];
-		} else {
-		    $row{$n} = $self->GetField($n);
-		}
-	    }
-	    $row{FID} = $self->GetFID;
-	    $row{Geometry} = $self->Geometry;
-	    return \%row;
-	}
-	sub Tuple {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    my $FID = shift;
-	    if (defined $FID) {
-		$self->SetFID($FID);
-		my $geometry = shift;
-		$self->Geometry($schema, $geometry) if $geometry;
-		if (@_) {
-		    for my $field (@{$schema->{Fields}}) {
-			my $v = shift;
-			my $n = $field->{Name};
-			$self->SetField($n, $v);
-		    }
-		}
-	    }
-	    return unless defined wantarray;
-	    my @ret = ($self->GetFID, $self->Geometry);
-	    my $i = 0;
-	    for my $field (@{$schema->{Fields}}) {
-		if (FieldIsList($self, $i)) {
-		    push @ret, [$self->GetField($i++)];
-		} else {
-		    push @ret, $self->GetField($i++);
-		}
-	    }
-	    return @ret;
-	}
-	sub Index {
-	    my($self, $field) = @_;
-	    my $index;
-	    if ($field =~ /^\d+$/) {
-		$index = $field;
-	    } else {
-		$index = GetFieldIndex($self, "$field");
-	    }
-	    croak "the feature does not have a field with name '$field'" if $index < 0 or $index >= GetFieldCount($self);
-	    return $index;
-	}
-	sub GetFieldType {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    return $Geo::OGR::FieldDefn::TYPE_INT2STRING{_GetFieldType($self, $field)};
-	}
-	sub FieldIsList {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    my $type = _GetFieldType($self, $field);
-	    return 1 if ($type == $Geo::OGR::OFTIntegerList or
-			 $type == $Geo::OGR::OFTRealList or
-			 $type == $Geo::OGR::OFTStringList or
-			 $type == $Geo::OGR::OFTDate or
-			 $type == $Geo::OGR::OFTTime or
-			 $type == $Geo::OGR::OFTDateTime);
-	    return 0;
-	}
-	sub GetField {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    return undef unless IsFieldSet($self, $field);
-	    my $type = _GetFieldType($self, $field);
-	    if ($type == $Geo::OGR::OFTInteger) {
-		return GetFieldAsInteger($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTReal) {
-		return GetFieldAsDouble($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTString) {
-		return GetFieldAsString($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTIntegerList) {
-		my $ret = GetFieldAsIntegerList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    } 
-	    if ($type == $Geo::OGR::OFTRealList) {
-		my $ret = GetFieldAsDoubleList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    }
-	    if ($type == $Geo::OGR::OFTStringList) {
-		my $ret = GetFieldAsStringList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    }
-	    if ($type == $Geo::OGR::OFTBinary) {
-		return GetFieldAsString($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTDate) {
-		my @ret = GetFieldAsDateTime($self, $field);
-		# year, month, day, hour, minute, second, timezone
-		return wantarray ? @ret[0..2] : [@ret[0..2]];
-	    }
-	    if ($type == $Geo::OGR::OFTTime) {
-		my @ret = GetFieldAsDateTime($self, $field);
-		return wantarray ? @ret[3..6] : [@ret[3..6]];
-	    }
-	    if ($type == $Geo::OGR::OFTDateTime) {
-		return GetFieldAsDateTime($self, $field);
-	    }
-	    croak "GDAL does not have a field type whose constant is '$type'";
-	}
-	sub UnsetField {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    _UnsetField($self, $field);
-	}
-	sub SetField {
-	    my $self = shift;
-	    my $field = $_[0];
-	    $field = Index($self, $field);
-	    shift;
-	    if (@_ == 0 or !defined($_[0])) {
-		_UnsetField($self, $field);
-		return;
-	    }
-	    my $list = ref($_[0]) ? $_[0] : [@_];
-	    my $type = _GetFieldType($self, $field);
-	    if ($type == $Geo::OGR::OFTInteger or
-		$type == $Geo::OGR::OFTReal or
-		$type == $Geo::OGR::OFTString or
-		$type == $Geo::OGR::OFTBinary)
-	    {
-		_SetField($self, $field, $_[0]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTIntegerList) {
-		SetFieldIntegerList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTRealList) {
-		SetFieldDoubleList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTStringList) {
-		SetFieldStringList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTDate) {
-		# year, month, day, hour, minute, second, timezone
-		for my $i (0..6) {
-		    $list->[$i] = 0 unless defined $list->[$i];
-		}
-		_SetField($self, $field, @$list[0..6]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTTime) {
-		$list->[3] = 0 unless defined $list->[3];
-		_SetField($self, $field, 0, 0, 0, @$list[0..3]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTDateTime) {
-		$list->[6] = 0 unless defined $list->[6];
-		_SetField($self, $field, @$list[0..6]);
-	    } 
-	    else {
-		croak "GDAL does not have a field type of number '$type'";
-	    }
-	}
-	sub Field {
-	    my $self = shift;
-	    my $field = shift;
-	    $self->SetField($field, @_) if @_;
-	    $self->GetField($field);
-	}
-	sub Geometry {
-	    my $self = shift;
-	    if (@_) {
-		# undocumented hack: the first argument may be the schema
-		my $schema = @_ == 2 ? shift : $self->Schema;
-		my $geometry = shift;
-		my $type = $schema->{GeometryType};
-		if (ref($geometry) eq 'HASH') {
-		    my $geom;
-		    eval {
-			$geom = Geo::OGR::Geometry->create(%$geometry);
-		    };
-		    if ($@) {
-			$geometry->{GeometryType} = $type;
-			$geom = Geo::OGR::Geometry->create(%$geometry);
-		    }
-		    unless ($type eq 'Unknown' or !$geom->GeometryType) {
-			croak "an attempt to insert a geometry with type '",$geom->GeometryType,"' into a feature with geometry type '$type'" unless $type eq $geom->GeometryType;
-		    }
-		    $self->SetGeometryDirectly($geom);
-		} else {
-		    unless ($type eq 'Unknown') {
-			croak "an attempt to insert a geometry with type '",$geometry->GeometryType,"' into a feature with geometry type '$type'" unless $type eq $geometry->GeometryType;
-		    }
-		    $self->SetGeometry($geometry);
-		}
-	    }
-	    return unless defined wantarray;
-            my $geometry = $self->GetGeometryRef();
-	    $geometry->Clone() if $geometry;
-	}
-	sub SetGeometryDirectly {
-	    _SetGeometryDirectly(@_);
-	    $GEOMETRIES{tied(%{$_[1]})} = $_[0];
-	}
-	sub GetGeometry {
-	    my $self = shift;
-	    my $geom = GetGeometryRef($self);
-	    $GEOMETRIES{tied(%$geom)} = $self if $geom;
-	    return $geom;
-	}
-	sub ReferenceGeometry {
-	    my $self = shift;
-	    SetGeometryDirectly($self, $_[0]) if @_;
-	    if (defined wantarray) {
-		my $geometry = GetGeometry($self);
-		return $geometry->Clone() if $geometry;
-	    }
-	}
-	sub SetFrom {
-	    my($self, $other) = @_;
-	    _SetFrom($self, $other), return if @_ <= 2;
-	    my $forgiving = $_[2];
-	    _SetFrom($self, $other, $forgiving), return if @_ <= 3;	    
-	    my $map = $_[3];
-	    my @list;
-	    for my $i (1..GetFieldCount($self)) {
-		push @list, ($map->{$i} || -1);
-	    }
-	    SetFromWithMap($self, $other, 1, \@list);
-	}
-
-	package Geo::OGR::FieldDefn;
-	use strict;
-	use vars qw /
-	    @FIELD_TYPES @JUSTIFY_TYPES
-	    %TYPE_STRING2INT %TYPE_INT2STRING
-	    %JUSTIFY_STRING2INT %JUSTIFY_INT2STRING
-	    /;
-        use Carp;
-	use Encode;
-	@FIELD_TYPES = qw/Integer IntegerList Real RealList String StringList 
-			WideString WideStringList Binary Date Time DateTime/;
-	@JUSTIFY_TYPES = qw/Undefined Left Right/;
-	for my $string (@FIELD_TYPES) {
-	    my $int = eval "\$Geo::OGR::OFT$string";
-	    $TYPE_STRING2INT{$string} = $int;
-	    $TYPE_INT2STRING{$int} = $string;
-	}
-	for my $string (@JUSTIFY_TYPES) {
-	    my $int = eval "\$Geo::OGR::OJ$string";
-	    $JUSTIFY_STRING2INT{$string} = $int;
-	    $JUSTIFY_INT2STRING{$int} = $string;
-	}
-	sub create {
-	    my $pkg = shift;
-	    my %param = ( Name => 'unnamed', Type => 'String' );
-	    if (@_ == 0) {
-	    } elsif (@_ == 1) {
-		$param{Name} = shift;
-	    } else {
-		my %known = map {$_ => 1} qw/Index Name Type Justify Width Precision/;
-		unless ($known{$_[0]}) {
-		    $param{Name} = shift;
-		    $param{Type} = shift;
-		} else {
-		    my %p = @_;
-		    for my $k (keys %known) {
-			$param{$k} = $p{$k} if exists $p{$k};
-		    }
-		}
-	    }
-	    croak "usage: Geo::OGR::FieldDefn->create(%params)" if ref($param{Name});
-	    $param{Type} = $TYPE_STRING2INT{$param{Type}} 
-	    if defined $param{Type} and exists $TYPE_STRING2INT{$param{Type}};
-	    $param{Justify} = $JUSTIFY_STRING2INT{$param{Justify}} 
-	    if defined $param{Justify} and exists $JUSTIFY_STRING2INT{$param{Justify}};
-	    my $self = Geo::OGRc::new_FieldDefn($param{Name}, $param{Type});
-	    if (defined($self)) {
-		bless $self, $pkg;
-		$self->Justify($param{Justify}) if exists $param{Justify};
-		$self->Width($param{Width}) if exists $param{Width};
-		$self->Precision($param{Precision}) if exists $param{Precision};
-	    }
-	    return $self;
-	}
-	sub Name {
-	    my $self = shift;
-	    SetName($self, $_[0]) if @_;
-	    GetName($self) if defined wantarray;
-	}
-	sub Type {
-	    my($self, $type) = @_;
-	    if (defined $type) {
-		$type = $TYPE_STRING2INT{$type} if $type and exists $TYPE_STRING2INT{$type};
-		SetType($self, $type);
-	    }
-	    return $TYPE_INT2STRING{GetType($self)} if defined wantarray;
-	}
-	sub Justify {
-	    my($self, $justify) = @_;
-	    if (defined $justify) {
-		$justify = $JUSTIFY_STRING2INT{$justify} if $justify and exists $JUSTIFY_STRING2INT{$justify};
-		SetJustify($self, $justify);
-	    }
-	    return $JUSTIFY_INT2STRING{GetJustify($self)} if defined wantarray;
-	}
-	sub Width {
-	    my $self = shift;
-	    SetWidth($self, $_[0]) if @_;
-	    GetWidth($self) if defined wantarray;
-	}
-	sub Precision {
-	    my $self = shift;
-	    SetPrecision($self, $_[0]) if @_;
-	    GetPrecision($self) if defined wantarray;
-	}
-	sub Ignored {
-	    my $self = shift;
-	    SetIgnored($self, $_[0]) if @_;
-	    IsIgnored($self) if defined wantarray;
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %param = @_;
- 		$self->Name($param{Name}) if exists $param{Name};
-		$self->Type($param{Type}) if exists $param{Type};
-		$self->Justify($param{Justify}) if exists $param{Justify};
-		$self->Width($param{Width}) if exists $param{Width};
-		$self->Precision($param{Precision}) if exists $param{Precision};
-	    }
-	    return unless defined wantarray;
-	    my %schema = ( Name => $self->Name, 
-			   Type  => $self->Type,
-			   Justify  => $self->Justify,
-			   Width  => $self->Width,
-			   Precision => $self->Precision );
-	    return wantarray ? %schema : \%schema;
-	}
-
-	package Geo::OGR::Geometry;
-	use strict;
-	use Carp;
-	use vars qw /
-            @GEOMETRY_TYPES @BYTE_ORDER_TYPES
-	    %TYPE_STRING2INT %TYPE_INT2STRING
-	    %BYTE_ORDER_STRING2INT %BYTE_ORDER_INT2STRING
-	    /;
-        @GEOMETRY_TYPES = qw/Unknown 
-			Point LineString Polygon 
-			MultiPoint MultiLineString MultiPolygon GeometryCollection 
-			None LinearRing
-			Point25D LineString25D Polygon25D 
-			MultiPoint25D MultiLineString25D MultiPolygon25D GeometryCollection25D/;
-	for my $string (@GEOMETRY_TYPES) {
-	    my $int = eval "\$Geo::OGR::wkb$string";
-	    $TYPE_STRING2INT{$string} = $int;
-	    $TYPE_INT2STRING{$int} = $string;
-	}
-	@BYTE_ORDER_TYPES = qw/XDR NDR/;
-	for my $string (@BYTE_ORDER_TYPES) {
-	    my $int = eval "\$Geo::OGR::wkb$string";
-	    $BYTE_ORDER_STRING2INT{$string} = $int;
-	    $BYTE_ORDER_INT2STRING{$int} = $string;
-	}
-	sub RELEASE_PARENTS {
-	    my $self = shift;
-	    delete $Geo::OGR::Feature::GEOMETRIES{$self};
-	}
-	sub create { # alternative constructor since swig created new cannot be overridden(?)
-	    my $pkg = shift;
-	    my($type, $wkt, $wkb, $gml, $json, $srs, $points, $arc);
-	    if (@_ == 1) {
-		$type = shift;
-	    } else {
-		my %param = @_;
-		$type = ($param{type} or $param{Type} or $param{GeometryType});
-		$srs = ($param{srs} or $param{SRS});
-		$wkt = ($param{wkt} or $param{WKT});
-		$wkb = ($param{wkb} or $param{WKB});
-		my $hex = ($param{hexewkb} or $param{HEXEWKB}); # PostGIS HEX EWKB
-		substr($hex, 10, 8) = '' if $hex; # remove SRID
-		$hex = ($param{hexwkb} or $param{HEXWKB}) unless $hex;
-		if ($hex) {
-		    $wkb = '';
-		    for (my $i = 0; $i < length($hex); $i+=2) {
-			$wkb .= chr(hex(substr($hex,$i,2)));
-		    }
-		}
-		$gml = ($param{gml} or $param{GML});
-		$json = ($param{geojson} or $param{GeoJSON});
-		$points = $param{Points};
-		$arc = ($param{arc} or $param{Arc});
-	    }
-	    $type = $TYPE_STRING2INT{$type} if defined $type and exists $TYPE_STRING2INT{$type};
-	    my $self;
-	    if (defined $wkt) {
-		$self = Geo::OGRc::CreateGeometryFromWkt($wkt, $srs);
-	    } elsif (defined $wkb) {
-		$self = Geo::OGRc::CreateGeometryFromWkb($wkb, $srs);
-	    } elsif (defined $gml) {
-		$self = Geo::OGRc::CreateGeometryFromGML($gml);
-	    } elsif (defined $json) {
-		$self = Geo::OGRc::CreateGeometryFromJson($json);
-	    } elsif (defined $type) {
-		croak "unknown GeometryType '$type' when creating a Geo::OGR::Geometry object" unless 
-		    exists($TYPE_STRING2INT{$type}) or exists($TYPE_INT2STRING{$type});
-		$self = Geo::OGRc::new_Geometry($type);
-	    } elsif (defined $arc) {
-		$self = Geo::OGRc::ApproximateArcAngles(@$arc);
-	    } else {
-		croak "missing a parameter when creating a Geo::OGR::Geometry object";
-	    }
-	    bless $self, $pkg if defined $self;
-	    $self->Points($points) if $points;
-	    return $self;
-	}
-	sub AsHEXWKB {
-	    my($self) = @_;
-	    my $wkb = _ExportToWkb($self, 1);
-	    my $hex = '';
-	    for (my $i = 0; $i < length($wkb); $i++) {
-		my $x = sprintf("%x", ord(substr($wkb,$i,1)));
-		$x = '0' . $x if length($x) == 1;
-		$hex .= uc($x);
-	    }
-	    return $hex;
-	}
-	sub AsHEXEWKB {
-	    my($self, $srid) = @_;
-	    my $hex = AsHEXWKB($self);
-	    if ($srid) {
-		my $s = sprintf("%x", $srid);
-		$srid = '';
-		do {
-		    if (length($s) > 2) {
-			$srid .= substr($s,-2,2);
-			substr($s,-2,2) = '';
-		    } elsif (length($s) > 1) {
-			$srid .= $s;
-			$s = '';
-		    } else {
-			$srid .= '0'.$s;
-			$s = '';
-		    }
-		} until $s eq '';
-	    } else {
-		$srid = '00000000';
-	    }
-	    while (length($srid) < 8) {
-		$srid .= '00';
-	    }
-	    substr($hex, 10, 0) = uc($srid);
-	    return $hex;
-	}
-	sub GeometryType {
-	    my $self = shift;
-	    return $TYPE_INT2STRING{$self->GetGeometryType};
-	}
-	sub CoordinateDimension {
-	    my $self = shift;
-	    SetCoordinateDimension($self, $_[0]) if @_;
-	    GetCoordinateDimension($self) if defined wantarray;
-	}
-	sub AddPoint {
-	    @_ == 4 ? AddPoint_3D(@_) : AddPoint_2D(@_);
-	}
-	sub SetPoint {
-	    @_ == 5 ? SetPoint_3D(@_) : SetPoint_2D(@_);
-	}
-	sub GetPoint {
-	    my($self, $i) = @_;
-	    $i = 0 unless defined $i;
-	    my $point = ($self->GetGeometryType & 0x80000000) == 0 ? GetPoint_2D($self, $i) : GetPoint_3D($self, $i);
-	    return @$point;
-	}
-	sub Point {
-	    my $self = shift;
-	    my $i;
-	    if (@_) {
-		my $t = $self->GetGeometryType;
-		if ($t == $Geo::OGR::wkbPoint) {
-		    shift if @_ > 2;
-		    $i = 0;
-		} elsif ($t == $Geo::OGR::wkbPoint25D) {
-		    shift if @_ > 3;
-		    $i = 0;
-		} else {
-		    my $i = shift;
-		}
-		SetPoint($self, $i, @_);
-	    }
-	    return GetPoint($self, $i) if defined wantarray;
-	}
-	sub Points {
-	    my $self = shift;
-	    my $t = $self->GetGeometryType;
-	    my $flat = ($t & 0x80000000) == 0;
-	    $t = $TYPE_INT2STRING{$t & ~0x80000000};
-	    my $points = shift;
-	    if ($points) {
-		Empty($self);
-		if ($t eq 'Unknown' or $t eq 'None' or $t eq 'GeometryCollection') {
-		    croak("can't set points of a geometry of type '$t'");
-		} elsif ($t eq 'Point') {
-		    # support both "Point" as a list of one point and one point
-		    if (ref($points->[0])) {
-			$flat ? 
-			    AddPoint_2D($self, @{$points->[0]}[0..1]) : 
-			    AddPoint_3D($self, @{$points->[0]}[0..2]);
-		    } else {
-			$flat ? 
-			    AddPoint_2D($self, @$points[0..1]) : 
-			    AddPoint_3D($self, @$points[0..2]);
-		    }
-		} elsif ($t eq 'LineString' or $t eq 'LinearRing') {
-		    if ($flat) {
-			for my $p (@$points) {
-			    AddPoint_2D($self, @$p[0..1]);
-			}
-		    } else{
-			for my $p (@$points) {
-			    AddPoint_3D($self, @$p[0..2]);
-			}
-		    }
-		} elsif ($t eq 'Polygon') {
-		    for my $r (@$points) {
-			my $ring = Geo::OGR::Geometry->create('LinearRing');
-			$ring->SetCoordinateDimension(3) unless $flat;
-			$ring->Points($r);
-			$self->AddGeometryDirectly($ring);
-		    }
-		} elsif ($t eq 'MultiPoint') {
-		    for my $p (@$points) {
-			my $point = Geo::OGR::Geometry->create($flat ? 'Point' : 'Point25D');
-			$point->Points($p);
-			$self->AddGeometryDirectly($point);
-		    }
-		} elsif ($t eq 'MultiLineString') {
-		    for my $l (@$points) {
-			my $linestring = Geo::OGR::Geometry->create($flat ? 'LineString' : 'LineString25D');
-			$linestring->Points($l);
-			$self->AddGeometryDirectly($linestring);
-		    }
-		} elsif ($t eq 'MultiPolygon') {
-		    for my $p (@$points) {
-			my $polygon = Geo::OGR::Geometry->create($flat ? 'Polygon' : 'Polygon25D');
-			$polygon->Points($p);
-			$self->AddGeometryDirectly($polygon);
-		    }
-		}
-	    }
-	    return unless defined wantarray;
-	    $self->_GetPoints($flat);
-	}
-	sub _GetPoints {
-	    my($self, $flat) = @_;
-	    my @points;
-	    my $n = $self->GetGeometryCount;
-	    if ($n) {
-		for my $i (0..$n-1) {
-		    push @points, $self->GetGeometryRef($i)->_GetPoints($flat);
-		}
-	    } else {
-		$n = $self->GetPointCount;
-		if ($n == 1) {
-		    push @points, $flat ? GetPoint_2D($self) : GetPoint_3D($self);
-		} else {
-		    my $i;
-		    if ($flat) {
-			for my $i (0..$n-1) {
-			    push @points, scalar GetPoint_2D($self, $i);
-			}
-		    } else {
-			for my $i (0..$n-1) {
-			    push @points, scalar GetPoint_3D($self, $i);
-			}
-		    }
-		}
-	    }
-	    return \@points;
-	}
-	sub ExportToWkb {
-	    my($self, $bo) = @_;
-	    $bo = $BYTE_ORDER_STRING2INT{$bo} if defined $bo and exists $BYTE_ORDER_STRING2INT{$bo};
-	    return _ExportToWkb($self, $bo);
-	}
-	sub ForceToMultiPoint {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiPoint($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToMultiLineString {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiLineString($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToMultiPolygon {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiPolygon($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToCollection {
-	    my $self = Geo::OGR::Geometry->create(GeometryType => 'GeometryCollection');
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	*Collect = *ForceToCollection;
-	sub Dissolve {
-	    my $self = shift;
-	    my @c;
-	    my $n = $self->GetGeometryCount;
-	    if ($n > 0) {
-		for my $i (0..$n-1) {
-		    push @c, $self->GetGeometryRef($i)->Clone;
-		}
-	    } else {
-		push @c, $self;
-	    }
-	    return @c;
-	}
-	*AsText = *ExportToWkt;
-	*AsBinary = *ExportToWkb;
-	*AsGML = *ExportToGML;
-	*AsKML = *ExportToKML;
-	*AsJSON = *ExportToJson;
-	*BuildPolygonFromEdges = *Geo::OGR::BuildPolygonFromEdges;
-	*ForceToPolygon = *Geo::OGR::ForceToPolygon;
-	
-    }
-    sub GeometryType {
-	my($type_or_name) = @_;
-	if (defined $type_or_name) {
-	    return $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name} if 
-		exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name};
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name} if 
-		exists $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name};
-	    croak "unknown geometry type constant value or name '$type_or_name'";
-	} else {
-	    return keys %Geo::OGR::Geometry::TYPE_STRING2INT;
-	}
-    }
-    sub RELEASE_PARENTS {
-    }
-    sub GeometryTypes {
-	return keys %Geo::OGR::Geometry::TYPE_STRING2INT;
-    }
-    sub Drivers {
-	my @drivers;
-	for my $i (0..GetDriverCount()-1) {
-	    push @drivers, _GetDriver($i);
-	}
-	return @drivers;
-    }
-    sub GetDriver {
-	my($name) = @_;
-	my $driver;
-	$driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
-	$driver = GetDriverByName("$name") unless $driver;
-	croak "OGR driver with name '$name' not found (maybe support for it was not built in?)" unless $driver;
-	return $driver;
-    }
-    *Driver = *GetDriver;
+        _SetField($self, $field, $_[0]);
+    }
+    elsif ($type == $Geo::OGR::OFTIntegerList) {
+        SetFieldIntegerList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTInteger64List) {
+        SetFieldInteger64List($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTRealList) {
+        SetFieldDoubleList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTStringList) {
+        SetFieldStringList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTDate) {
+        # year, month, day, hour, minute, second, timezone
+        for my $i (0..6) {
+            $list->[$i] = 0 unless defined $list->[$i];
+        }
+        _SetField($self, $field, @$list[0..6]);
+    }
+    elsif ($type == $Geo::OGR::OFTTime) {
+        $list->[3] = 0 unless defined $list->[3];
+        _SetField($self, $field, 0, 0, 0, @$list[0..3]);
+    }
+    elsif ($type == $Geo::OGR::OFTDateTime) {
+        $list->[6] = 0 unless defined $list->[6];
+        _SetField($self, $field, @$list[0..6]);
+    }
+    else {
+        confess "Perl bindings do not support field type '$Geo::OGR::FieldDefn::TYPE_INT2STRING{$type}'.";
+    }
+}
+
+sub Field {
+    my $self = shift;
+    my $field = shift;
+    $self->SetField($field, @_) if @_;
+    $self->GetField($field);
+}
+
+sub _GetGeomFieldIndex {
+    my($self, $field) = @_;
+    if (not defined $field) {
+        return 0 if $self->GetGeomFieldCount > 0;
+    } if ($field =~ /^\d+$/) {
+        return $field if $field >= 0 and $field < $self->GetGeomFieldCount;
+    } else {
+        for my $i (0..$self->GetGeomFieldCount-1) {
+            return $i if $self->GetGeomFieldDefn($i)->Name eq $field;
+        }
+        return 0 if $self->GetGeomFieldCount > 0 and $field eq 'Geometry';
+    }
+    confess "No such field: '$field'.";
+}
+
+sub Geometry {
+    my $self = shift;
+    my $field = (ref($_[0]) eq '' or (@_ > 2 and @_ % 2 == 1)) ? shift : undef;
+    $field = $self->_GetGeomFieldIndex($field);
+    if (@_) {
+        my $type = $self->GetDefn->GetGeomFieldDefn($field)->Type;
+        my $geometry;
+        if (@_ == 1) {
+            $geometry = $_[0];
+        } elsif (@_ and @_ % 2 == 0) {
+            %$geometry = @_;
+        }
+        if (blessed($geometry) and $geometry->isa('Geo::OGR::Geometry')) {
+            confess "The type of the inserted geometry ('".$geometry->GeometryType."') is not the field type ('$type')."
+                if $type ne 'Unknown' and $type ne $geometry->GeometryType;
+            eval {
+                $self->SetGeomFieldDirectly($field, $geometry);
+            };
+            confess "$@" if $@;
+            $GEOMETRIES{tied(%{$geometry})} = $self;
+        } elsif (ref($geometry) eq 'HASH') {
+            $geometry->{GeometryType} = $type unless exists $geometry->{GeometryType};
+            eval {
+                $geometry = Geo::OGR::Geometry->new($geometry);
+            };
+            confess "The type of the inserted geometry ('".$geometry->GeometryType."') is not the field type ('$type')."
+                if $type ne 'Unknown' and $type ne $geometry->GeometryType;
+            eval {
+                $self->SetGeomFieldDirectly($field, $geometry);
+            };
+            confess "$@" if $@;
+        } else {
+            confess "'@_' does not define a geometry.";
+        }
+    }
+    return unless defined wantarray;
+    my $geometry = $self->GetGeomFieldRef($field);
+    return unless $geometry;
+    $GEOMETRIES{tied(%{$geometry})} = $self;
+    return $geometry;
+}
+*GetGeometry = *Geometry;
+*SetGeometry = *Geometry;
+
+sub SetFrom {
+    my($self, $other) = @_;
+    _SetFrom($self, $other), return if @_ <= 2;
+    my $forgiving = $_[2];
+    _SetFrom($self, $other, $forgiving), return if @_ <= 3;
+    my $map = $_[3];
+    my @list;
+    for my $i (1..GetFieldCount($self)) {
+        push @list, ($map->{$i} || -1);
+    }
+    SetFromWithMap($self, $other, 1, \@list);
+}
+
+
+
+
+package Geo::OGR::FieldDefn;
+use strict;
+use warnings;
+use vars qw /
+    %SCHEMA_KEYS
+    @TYPES @SUB_TYPES @JUSTIFY_VALUES
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    %SUB_TYPE_STRING2INT %SUB_TYPE_INT2STRING
+    %JUSTIFY_STRING2INT %JUSTIFY_INT2STRING
+    /;
+use Carp;
+use Encode;
+%SCHEMA_KEYS = map {$_ => 1} qw/Name Type SubType Justify Width Precision Nullable Default Ignored/;
+for (keys %Geo::OGR::) {
+    push(@TYPES, $1), next if /^OFT(\w+)/;
+    push(@SUB_TYPES, $1), next if /^OFST(\w+)/;
+    push(@JUSTIFY_VALUES, $1), next if /^OJ(\w+)/;
+}
+for my $string (@TYPES) {
+    my $int = eval "\$Geo::OGR::OFT$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@SUB_TYPES) {
+    my $int = eval "\$Geo::OGR::OFST$string";
+    $SUB_TYPE_STRING2INT{$string} = $int;
+    $SUB_TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@JUSTIFY_VALUES) {
+    my $int = eval "\$Geo::OGR::OJ$string";
+    $JUSTIFY_STRING2INT{$string} = $int;
+    $JUSTIFY_INT2STRING{$int} = $string;
+}
+
+sub Types {
+    return @TYPES;
+}
+
+sub SubTypes {
+    return @SUB_TYPES;
+}
+
+sub JustifyValues {
+    return @JUSTIFY_VALUES;
+}
+%}
+
+%feature("shadow") OGRFieldDefnShadow( const char* name_null_ok="unnamed", OGRFieldType field_type=OFTString)
+%{
+use Carp;
+sub new {
+    my $pkg = shift;
+    my ($name, $type) = ('unnamed', 'String');
+    my %args;
+    if (@_ == 0) {
+    } elsif (@_ == 1) {
+        $name = shift;
+    } elsif (@_ == 2 and not $SCHEMA_KEYS{$_[0]}) {
+        $name = shift;
+        $type = shift;
+    } else {
+        my %named = @_;
+        for my $key (keys %named) {
+            if ($SCHEMA_KEYS{$key}) {
+                $args{$key} = $named{$key};
+            } else {
+                carp "Unrecognized argument: '$key'." if $key ne 'Index';
+            }
+        }
+        $name = $args{Name} if exists $args{Name};
+        delete $args{Name};
+        $type = $args{Type} if exists $args{Type};
+        delete $args{Type};
+    }
+    confess "Unknown field type: '$type'." unless exists $TYPE_STRING2INT{$type};
+    $type = $TYPE_STRING2INT{$type};
+    my $self = Geo::OGRc::new_FieldDefn($name, $type);
+    if (defined($self)) {
+        bless $self, $pkg;
+        $self->Schema(%args);
+    }
+    return $self;
+}
+%}
+
+%perlcode %{
+sub Schema {
+    my $self = shift;
+    if (@_) {
+        my %args = @_;
+        for my $key (keys %SCHEMA_KEYS) {
+            eval '$self->'.$key.'($args{'.$key.'}) if exists $args{'.$key.'}';
+            croak $@ if $@;
+        }
+    }
+    return unless defined wantarray;
+    my %schema = ();
+    for my $key (keys %SCHEMA_KEYS) {
+        $schema{$key} = eval '$self->'.$key;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*GetSchema = *Schema;
+*SetSchema = *Schema;
+
+sub Name {
+    my $self = shift;
+    SetName($self, $_[0]) if @_;
+    GetName($self) if defined wantarray;
+}
+
+sub Type {
+    my($self, $type) = @_;
+    if (defined $type) {
+        confess "Unknown field type: '$type'." unless exists $TYPE_STRING2INT{$type};
+        $type = $TYPE_STRING2INT{$type};
+        SetType($self, $type);
+    }
+    return $TYPE_INT2STRING{GetType($self)} if defined wantarray;
+}
+
+sub SubType {
+    my($self, $sub_type) = @_;
+    if (defined $sub_type) {
+        confess "Unknown field sub type: '$sub_type'." unless exists $SUB_TYPE_STRING2INT{$sub_type};
+        $sub_type = $SUB_TYPE_STRING2INT{$sub_type};
+        SetSubType($self, $sub_type);
+    }
+    return $SUB_TYPE_INT2STRING{GetSubType($self)} if defined wantarray;
+}
+
+sub Justify {
+    my($self, $justify) = @_;
+    if (defined $justify) {
+        confess "Unknown justify value: '$justify'." unless exists $JUSTIFY_STRING2INT{$justify};
+        $justify = $JUSTIFY_STRING2INT{$justify} if exists $JUSTIFY_STRING2INT{$justify};
+        SetJustify($self, $justify);
+    }
+    return $JUSTIFY_INT2STRING{GetJustify($self)} if defined wantarray;
+}
+
+sub Width {
+    my $self = shift;
+    SetWidth($self, $_[0]) if @_;
+    GetWidth($self) if defined wantarray;
+}
+
+sub Precision {
+    my $self = shift;
+    SetPrecision($self, $_[0]) if @_;
+    GetPrecision($self) if defined wantarray;
+}
+
+sub Nullable {
+    my $self = shift;
+    SetNullable($self, $_[0]) if @_;
+    IsNullable($self) if defined wantarray;
+}
+
+sub Default {
+    my $self = shift;
+    SetDefault($self, $_[0]) if @_;
+    GetDefault($self) if defined wantarray;
+}
+
+sub Ignored {
+    my $self = shift;
+    SetIgnored($self, $_[0]) if @_;
+    IsIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::GeomFieldDefn;
+use strict;
+use warnings;
+use vars qw / %SCHEMA_KEYS /;
+use Carp;
+use Scalar::Util 'blessed';
+%SCHEMA_KEYS = map {$_ => 1} qw/Name Type SpatialReference Nullable Ignored/;
+%}
+
+%feature("shadow") OGRGeomFieldDefnShadow( const char* name_null_ok="", OGRwkbGeometryType field_type = wkbUnknown)
+%{
+use Carp;
+sub new {
+    my $pkg = shift;
+    my ($name, $type) = ('geom', 'Unknown');
+    my %args;
+    if (@_ == 0) {
+    } elsif (@_ == 1) {
+        $name = shift;
+    } elsif (@_ == 2 and not $SCHEMA_KEYS{$_[0]}) {
+        $name = shift;
+        $type = shift;
+    } else {
+        my %named = @_;
+        for my $key (keys %named) {
+            if ($SCHEMA_KEYS{$key}) {
+                $args{$key} = $named{$key};
+            } else {
+                carp "Unrecognized argument: '$key'." if $key ne 'Index';
+            }
+        }
+        $name = $args{Name} if exists $args{Name};
+        delete $args{Name};
+        $type = $args{Type} if $args{Type};
+        delete $args{Type};
+        $type = $args{GeometryType} if $args{GeometryType};
+        delete $args{GeometryType};
+    }
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    my $self = Geo::OGRc::new_GeomFieldDefn($name, $type);
+    if (defined($self)) {
+        bless $self, $pkg;
+        $self->Schema(%args);
+    }
+    return $self;
+}
+%}
+
+%perlcode %{
+sub Schema {
+    my $self = shift;
+    if (@_) {
+        my %args = @_;
+        for my $key (keys %SCHEMA_KEYS) {
+            eval '$self->'.$key.'($args{'.$key.'}) if exists $args{'.$key.'}';
+            croak $@ if $@;
+        }
+    }
+    return unless defined wantarray;
+    my %schema = ();
+    for my $key (keys %SCHEMA_KEYS) {
+        $schema{$key} = eval '$self->'.$key;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*GetSchema = *Schema;
+*SetSchema = *Schema;
+
+sub Name {
+    my $self = shift;
+    SetName($self, $_[0]) if @_;
+    GetName($self) if defined wantarray;
+}
+
+sub Type {
+    my($self, $type) = @_;
+    if (defined $type) {
+        confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        SetType($self, $type);
+    }
+    $Geo::OGR::Geometry::TYPE_INT2STRING{GetType($self)} if defined wantarray;
+}
+
+sub Types {
+  return @Geo::OGR::Geometry::GEOMETRY_TYPES;
+}
+
+sub SpatialReference {
+    my $self = shift;
+    SetSpatialRef($self, $_[0]) if @_;
+    GetSpatialRef($self) if defined wantarray;
+}
+
+sub Nullable {
+    my $self = shift;
+    SetNullable($self, $_[0]) if @_;
+    IsNullable($self) if defined wantarray;
+}
+
+sub Ignored {
+    my $self = shift;
+    SetIgnored($self, $_[0]) if @_;
+    IsIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::Geometry;
+use strict;
+use warnings;
+use Carp;
+use vars qw /
+    @BYTE_ORDER_TYPES @GEOMETRY_TYPES
+    %BYTE_ORDER_STRING2INT %BYTE_ORDER_INT2STRING
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    /;
+ at BYTE_ORDER_TYPES = qw/XDR NDR/;
+for my $string (@BYTE_ORDER_TYPES) {
+    my $int = eval "\$Geo::OGR::wkb$string";
+    $BYTE_ORDER_STRING2INT{$string} = $int;
+    $BYTE_ORDER_INT2STRING{$int} = $string;
+}
+for (keys %Geo::OGR::) {
+    next if /^wkb25/;
+    next if /^wkb.DR/;
+    push(@GEOMETRY_TYPES, $1), next if /^wkb(\w+)/;
+}
+for my $string (@GEOMETRY_TYPES) {
+    my $int = eval "\$Geo::OGR::wkb$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+
+sub ByteOrders {
+    return @BYTE_ORDER_TYPES;
+}
+
+sub GeometryTypes {
+    return @GEOMETRY_TYPES;
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::Feature::GEOMETRIES{$self};
+}
+%}
+
+%feature("shadow") OGRGeometryShadow( OGRwkbGeometryType type = wkbUnknown, char *wkt = 0, int wkb = 0, char *wkb_buf = 0, char *gml = 0 )
+%{
+use Carp;
+sub new {
+    my $pkg = shift;
+    my ($type, $wkt, $wkb, $gml, $json, $srs, $points, $arc);
+    my %param;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %param = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %param = @_;
+    } else {
+        ($param{GeometryType}) = @_;
+    }
+    $type = ($param{type} or $param{Type} or $param{GeometryType});
+    $srs = ($param{srs} or $param{SRS});
+    $wkt = ($param{wkt} or $param{WKT});
+    $wkb = ($param{wkb} or $param{WKB});
+    my $hex = ($param{hexewkb} or $param{HEXEWKB}); # PostGIS HEX EWKB
+    my $srid;
+    if ($hex) {
+        # get and remove SRID
+        $srid = substr($hex, 10, 8);
+        substr($hex, 10, 8) = '';
+    } else {
+        $hex = ($param{hexwkb} or $param{HEXWKB});
+    }
+    if ($hex) {
+        $wkb = '';
+        for (my $i = 0; $i < length($hex); $i+=2) {
+            $wkb .= chr(hex(substr($hex,$i,2)));
+        }
+    }
+    $gml = ($param{gml} or $param{GML});
+    $json = ($param{geojson} or $param{GeoJSON});
+    $points = $param{Points};
+    $arc = ($param{arc} or $param{Arc});
+    my $self;
+    if (defined $wkt) {
+        $self = Geo::OGRc::CreateGeometryFromWkt($wkt, $srs);
+    } elsif (defined $wkb) {
+        $self = Geo::OGRc::CreateGeometryFromWkb($wkb, $srs);
+    } elsif (defined $gml) {
+        $self = Geo::OGRc::CreateGeometryFromGML($gml);
+    } elsif (defined $json) {
+        $self = Geo::OGRc::CreateGeometryFromJson($json);
+    } elsif (defined $type) {
+        confess "Unknown geometry type: '$type'." unless exists $TYPE_STRING2INT{$type};
+        $type = $TYPE_STRING2INT{$type};
+        $self = Geo::OGRc::new_Geometry($type); # flattens the type
+        SetCoordinateDimension($self, 3) if Geo::OGR::GT_HasZ($type);
+    } elsif (defined $arc) {
+        $self = Geo::OGRc::ApproximateArcAngles(@$arc);
+    } else {
+        confess "Missing a parameter when creating a Geo::OGR::Geometry object.";
+    }
+    bless $self, $pkg if defined $self;
+    $self->Points($points) if $points;
+    return $self;
+}
+%}
+
+%perlcode %{
+sub ApproximateArcAngles {
+    my %p = @_;
+    my %default = ( Center => [0,0,0],
+                    PrimaryRadius => 1,
+                    SecondaryAxis => 1,
+                    Rotation => 0,
+                    StartAngle => 0,
+                    EndAngle => 360,
+                    MaxAngleStepSizeDegrees => 4 
+        );
+    for my $p (keys %p) {
+        if (exists $default{$p}) {
+            $p{$p} = $default{$p} unless defined $p{$p};
+        } else {
+            carp "Unknown named parameter: '$p'.";
+        }
+    }
+    for my $p (keys %default) {
+        $p{$p} = $default{$p} unless exists $p{$p};
+    }
+    confess "Usage: Center => [x,y,z]." unless ref($p{Center}) eq 'ARRAY';
+    for my $i (0..2) {
+        $p{Center}->[$i] = 0 unless defined $p{Center}->[$i];
+    }
+    return Geo::OGR::ApproximateArcAngles($p{Center}->[0], $p{Center}->[1], $p{Center}->[2], $p{PrimaryRadius}, $p{SecondaryAxis}, $p{Rotation}, $p{StartAngle}, $p{EndAngle}, $p{MaxAngleStepSizeDegrees});
+}
+
+sub As {
+    my $self = shift;
+    my %param;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %param = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %param = @_;
+    } else {
+        ($param{Format}, $param{x}) = @_;
+    }
+    $param{ByteOrder} = 'XDR' unless $param{ByteOrder};
+    my $f = $param{Format};
+    my $x = $param{x};
+    $x = $param{ByteOrder} unless defined $x;
+    if ($f =~ /text/i) {
+        return $self->AsText;
+    } elsif ($f =~ /wkt/i) {
+        if ($f =~ /iso/i) {
+            return $self->ExportToIsoWkt;
+        } else {
+            return $self->AsText;
+        }
+    } elsif ($f =~ /binary/i) {
+        return $self->AsBinary($x);        
+    } elsif ($f =~ /wkb/i) {
+        if ($f =~ /iso/i) {
+            return $self->ExportToIsoWkb;
+        } elsif ($f =~ /hexe/i) {
+            $param{srid} = 'XDR' unless $param{srid};
+            $x = $param{srid} unless defined $x;
+            return $self->AsHEXEWKB($x);
+        } elsif ($f =~ /hex/i) {
+            return $self->AsHEXWKB;
+        } else {
+            return $self->AsBinary($x);
+        }
+    } elsif ($f =~ /gml/i) {
+        return $self->AsGML;
+    } elsif ($f =~ /kml/i) {
+        return $self->AsKML;
+    } elsif ($f =~ /json/i) {
+        return $self->AsJSON;
+    } else {
+        confess "Unsupported format: $f.";
+    }
+}
+
+sub AsHEXWKB {
+    my ($self) = @_;
+    my $wkb = _ExportToWkb($self, 1);
+    my $hex = '';
+    for (my $i = 0; $i < length($wkb); $i++) {
+        my $x = sprintf("%x", ord(substr($wkb,$i,1)));
+        $x = '0' . $x if length($x) == 1;
+        $hex .= uc($x);
+    }
+    return $hex;
+}
+
+sub AsHEXEWKB {
+    my ($self, $srid) = @_;
+    my $hex = AsHEXWKB($self);
+    if ($srid) {
+        my $s = sprintf("%x", $srid);
+        $srid = '';
+        do {
+            if (length($s) > 2) {
+                $srid .= substr($s,-2,2);
+                substr($s,-2,2) = '';
+            } elsif (length($s) > 1) {
+                $srid .= $s;
+                $s = '';
+            } else {
+                $srid .= '0'.$s;
+                $s = '';
+            }
+        } until $s eq '';
+    } else {
+        $srid = '00000000';
+    }
+    while (length($srid) < 8) {
+        $srid .= '00';
+    }
+    substr($hex, 10, 0) = uc($srid);
+    return $hex;
+}
+
+sub GeometryType {
+    my $self = shift;
+    return $TYPE_INT2STRING{$self->GetGeometryType};
+}
+
+sub CoordinateDimension {
+    my $self = shift;
+    SetCoordinateDimension($self, $_[0]) if @_;
+    GetCoordinateDimension($self) if defined wantarray;
+}
+
+sub AddPoint {
+    @_ == 4 ? AddPoint_3D(@_) : AddPoint_2D(@_);
+}
+
+sub SetPoint {
+    @_ == 5 ? SetPoint_3D(@_) : SetPoint_2D(@_);
+}
+
+sub GetPoint {
+    my($self, $i) = @_;
+    $i = 0 unless defined $i;
+    my $point = ($self->GetGeometryType & 0x80000000) == 0 ? GetPoint_2D($self, $i) : GetPoint_3D($self, $i);
+    return @$point;
+}
+
+sub Point {
+    my $self = shift;
+    my $i;
+    if (@_) {
+        my $t = $self->GetGeometryType;
+        if ($t == $Geo::OGR::wkbPoint) {
+            shift if @_ > 2;
+            $i = 0;
+        } elsif ($t == $Geo::OGR::wkbPoint25D) {
+            shift if @_ > 3;
+            $i = 0;
+        } else {
+            my $i = shift;
+        }
+        SetPoint($self, $i, @_);
+    }
+    return GetPoint($self, $i) if defined wantarray;
+}
+
+sub Points {
+    my $self = shift;
+    my $t = $self->GetGeometryType;
+    my $flat = not Geo::OGR::GT_HasZ($t);
+    $t = Geo::OGR::GT_Flatten($t);
+    $t = $TYPE_INT2STRING{$t};
+    my $points = shift;
+    if ($points) {
+        Empty($self);
+        if ($t eq 'Unknown' or $t eq 'None' or $t eq 'GeometryCollection') {
+            confess "Can't set points of a geometry of type '$t'.";
+        } elsif ($t eq 'Point') {
+            # support both "Point" as a list of one point and one point
+            if (ref($points->[0])) {
+                $flat ?
+                    AddPoint_2D($self, @{$points->[0]}[0..1]) :
+                    AddPoint_3D($self, @{$points->[0]}[0..2]);
+            } else {
+                $flat ?
+                    AddPoint_2D($self, @$points[0..1]) :
+                    AddPoint_3D($self, @$points[0..2]);
+            }
+        } elsif ($t eq 'LineString' or $t eq 'LinearRing') {
+            if ($flat) {
+                for my $p (@$points) {
+                    AddPoint_2D($self, @$p[0..1]);
+                }
+            } else{
+                for my $p (@$points) {
+                    AddPoint_3D($self, @$p[0..2]);
+                }
+            }
+        } elsif ($t eq 'Polygon') {
+            for my $r (@$points) {
+                my $ring = Geo::OGR::Geometry->new('LinearRing');
+                $ring->SetCoordinateDimension(3) unless $flat;
+                $ring->Points($r);
+                $self->AddGeometryDirectly($ring);
+            }
+        } elsif ($t eq 'MultiPoint') {
+            for my $p (@$points) {
+                my $point = Geo::OGR::Geometry->new($flat ? 'Point' : 'Point25D');
+                $point->Points($p);
+                $self->AddGeometryDirectly($point);
+            }
+        } elsif ($t eq 'MultiLineString') {
+            for my $l (@$points) {
+                my $linestring = Geo::OGR::Geometry->new($flat ? 'LineString' : 'LineString25D');
+                $linestring->Points($l);
+                $self->AddGeometryDirectly($linestring);
+            }
+        } elsif ($t eq 'MultiPolygon') {
+            for my $p (@$points) {
+                my $polygon = Geo::OGR::Geometry->new($flat ? 'Polygon' : 'Polygon25D');
+                $polygon->Points($p);
+                $self->AddGeometryDirectly($polygon);
+            }
+        }
+    }
+    return unless defined wantarray;
+    $self->_GetPoints($flat);
+}
+
+sub _GetPoints {
+    my($self, $flat) = @_;
+    my @points;
+    my $n = $self->GetGeometryCount;
+    if ($n) {
+        for my $i (0..$n-1) {
+            push @points, $self->GetGeometryRef($i)->_GetPoints($flat);
+        }
+    } else {
+        $n = $self->GetPointCount;
+        if ($n == 1) {
+            push @points, $flat ? GetPoint_2D($self) : GetPoint_3D($self);
+        } else {
+            my $i;
+            if ($flat) {
+                for my $i (0..$n-1) {
+                    push @points, scalar GetPoint_2D($self, $i);
+                }
+            } else {
+                for my $i (0..$n-1) {
+                    push @points, scalar GetPoint_3D($self, $i);
+                }
+            }
+        }
+    }
+    return \@points;
+}
+
+sub ExportToWkb {
+    my($self, $bo) = @_;
+    if (defined $bo) {
+        confess "Unknown byte order: '$bo'." unless exists $BYTE_ORDER_STRING2INT{$bo};
+        $bo = $BYTE_ORDER_STRING2INT{$bo};
+    }
+    return _ExportToWkb($self, $bo);
+}
+
+sub ForceTo {
+    my $self = shift;
+    my $type = shift;
+    confess "Unknown geometry type: '$type'." unless exists $TYPE_STRING2INT{$type};
+    $type = $TYPE_STRING2INT{$type};
+    eval {
+        $self = Geo::OGR::ForceTo($self, $type, @_);
+    };
+    confess $@ if $@;
+    return $self;
+}
+
+sub ForceToLineString {
+    my $self = shift;
+    $self = Geo::OGR::ForceToLineString($self);
+    return $self;
+}
+
+sub ForceToMultiPoint {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiPoint($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToMultiLineString {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiLineString($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToMultiPolygon {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiPolygon($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToCollection {
+    my $self = Geo::OGR::Geometry->new(GeometryType => 'GeometryCollection');
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+*Collect = *ForceToCollection;
+
+sub Dissolve {
+    my $self = shift;
+    my @c;
+    my $n = $self->GetGeometryCount;
+    if ($n > 0) {
+        for my $i (0..$n-1) {
+            push @c, $self->GetGeometryRef($i)->Clone;
+        }
+    } else {
+        push @c, $self;
+    }
+    return @c;
+}
+*AsText = *ExportToWkt;
+*AsBinary = *ExportToWkb;
+*AsGML = *ExportToGML;
+*AsKML = *ExportToKML;
+*AsJSON = *ExportToJson;
+*BuildPolygonFromEdges = *Geo::OGR::BuildPolygonFromEdges;
+*ForceToPolygon = *Geo::OGR::ForceToPolygon;
+
+
+package Geo::OGR;
+use strict;
+use warnings;
+use Carp;
+
+sub GeometryType {
+    my($type_or_name) = @_;
+    if (defined $type_or_name) {
+        return $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name} if
+            exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name};
+        return $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name} if
+            exists $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name};
+        confess "Unknown geometry type: '$type_or_name'.";
+    } else {
+        return @Geo::OGR::Geometry::GEOMETRY_TYPES;
+    }
+}
+
+sub GeometryTypeModify {
+    my($type, $modifier) = @_;
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_Flatten($type)} if $modifier =~ /flat/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_SetZ($type)} if $modifier =~ /z/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetCollection($type)} if $modifier =~ /collection/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetCurve($type)} if $modifier =~ /curve/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetLinear($type)} if $modifier =~ /linear/i;
+    confess "Unknown geometry type modifier: '$modifier'.";
+}
+
+sub GeometryTypeTest {
+    my($type, $test, $type2) = @_;
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    if (defined $type2) {
+        confess "Unknown geometry type: '$type2'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type2};
+        $type2 = $Geo::OGR::Geometry::TYPE_STRING2INT{$type2};
+    } else {
+        confess "Usage: GeometryTypeTest(type1, 'is_subclass_of', type2)." if $test =~ /subclass/i;
+    }
+    return GT_HasZ($type) if $test =~ /z/i;
+    return GT_IsSubClassOf($type, $type2) if $test =~ /subclass/i;
+    return GT_IsCurve($type) if $test =~ /curve/i;
+    return GT_IsSurface($type) if $test =~ /surface/i;
+    return GT_IsNonLinear($type) if $test =~ /linear/i;
+    confess "Unknown geometry type test: '$test'.";
+}
+
+sub RELEASE_PARENTS {
+}
+
+*ByteOrders = *Geo::OGR::Geometry::ByteOrders;
+*GeometryTypes = *Geo::OGR::Geometry::GeometryTypes;
+
+sub GetDriverNames {
+    my @names;
+    for my $i (0..GetDriverCount()-1) {
+        push @names, _GetDriver($i)->Name;
+    }
+    return @names;
+}
+
+sub Drivers {
+    my @drivers;
+    for my $i (0..GetDriverCount()-1) {
+        push @drivers, _GetDriver($i);
+    }
+    return @drivers;
+}
+
+sub GetDriver {
+    my($name) = @_;
+    $name = 0 unless defined $name;
+    my $driver;
+    $driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
+    $driver = GetDriverByName("$name") unless $driver;
+    return $driver if $driver;
+    confess "Driver not found: '$name'. Maybe support for it was not built in?";
+}
+*Driver = *GetDriver;
 %}
diff --git a/swig/include/perl/osr_perl.i b/swig/include/perl/osr_perl.i
index aa04813..b63b328 100644
--- a/swig/include/perl/osr_perl.i
+++ b/swig/include/perl/osr_perl.i
@@ -5,337 +5,324 @@
 %rename (_GetUTMZone) GetUTMZone;
 
 %perlcode %{
-    sub RELEASE_PARENTS {
+
+package Geo::OSR;
+use strict;
+use warnings;
+
+use vars qw /%PROJECTIONS %PARAMETERS %LINEAR_UNITS %ANGULAR_UNITS %DATUMS/;
+
+for (keys %Geo::OSR::) {
+    if (/^SRS_PT_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $PROJECTIONS{$p} = 1;
     }
-    package Geo::OSR::SpatialReference;
-    use strict;
-    use Carp;
-    use vars qw /@PROJECTIONS %PROJECTIONS @PARAMETERS %PARAMETERS/;
-    @PROJECTIONS = qw/
-ALBERS_CONIC_EQUAL_AREA
-AZIMUTHAL_EQUIDISTANT
-CASSINI_SOLDNER
-CYLINDRICAL_EQUAL_AREA
-BONNE
-ECKERT_I
-ECKERT_II
-ECKERT_III
-ECKERT_IV
-ECKERT_V
-ECKERT_VI
-EQUIDISTANT_CONIC
-EQUIRECTANGULAR
-GALL_STEREOGRAPHIC
-GAUSSSCHREIBERTMERCATOR
-GEOSTATIONARY_SATELLITE
-GOODE_HOMOLOSINE
-IGH
-GNOMONIC
-HOTINE_OBLIQUE_MERCATOR
-HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN
-LABORDE_OBLIQUE_MERCATOR
-LAMBERT_CONFORMAL_CONIC_1SP
-LAMBERT_CONFORMAL_CONIC_2SP
-LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM
-LAMBERT_AZIMUTHAL_EQUAL_AREA
-MERCATOR_1SP
-MERCATOR_2SP
-MILLER_CYLINDRICAL
-MOLLWEIDE
-NEW_ZEALAND_MAP_GRID
-OBLIQUE_STEREOGRAPHIC
-ORTHOGRAPHIC
-POLAR_STEREOGRAPHIC
-POLYCONIC
-ROBINSON
-SINUSOIDAL
-STEREOGRAPHIC
-SWISS_OBLIQUE_CYLINDRICAL
-TRANSVERSE_MERCATOR
-TRANSVERSE_MERCATOR_SOUTH_ORIENTED
-TRANSVERSE_MERCATOR_MI_21
-TRANSVERSE_MERCATOR_MI_22
-TRANSVERSE_MERCATOR_MI_23
-TRANSVERSE_MERCATOR_MI_24
-TRANSVERSE_MERCATOR_MI_25
-TUNISIA_MINING_GRID
-TWO_POINT_EQUIDISTANT
-VANDERGRINTEN
-KROVAK
-IMW_POLYCONIC
-WAGNER_I
-WAGNER_II
-WAGNER_III
-WAGNER_IV
-WAGNER_V
-WAGNER_VI
-WAGNER_VII
-/;
-    for my $s (@PROJECTIONS) {
-	my $p = eval "\$Geo::OGR::SRS_PT_$s";
-	$PROJECTIONS{$s} = $p;
+    elsif (/^SRS_PP_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $PARAMETERS{$p} = 1;
     }
-    @PARAMETERS = qw/
-CENTRAL_MERIDIAN
-SCALE_FACTOR
-STANDARD_PARALLEL_1
-STANDARD_PARALLEL_2
-PSEUDO_STD_PARALLEL_1
-LONGITUDE_OF_CENTER
-LATITUDE_OF_CENTER
-LONGITUDE_OF_ORIGIN
-LATITUDE_OF_ORIGIN
-FALSE_EASTING
-FALSE_NORTHING
-AZIMUTH
-LONGITUDE_OF_POINT_1
-LATITUDE_OF_POINT_1
-LONGITUDE_OF_POINT_2
-LATITUDE_OF_POINT_2
-LONGITUDE_OF_POINT_3
-LATITUDE_OF_POINT_3
-RECTIFIED_GRID_ANGLE
-LANDSAT_NUMBER
-PATH_NUMBER
-PERSPECTIVE_POINT_HEIGHT
-SATELLITE_HEIGHT
-FIPSZONE
-ZONE
-LATITUDE_OF_1ST_POINT
-LONGITUDE_OF_1ST_POINT
-LATITUDE_OF_2ND_POINT
-LONGITUDE_OF_2ND_POINT
-/;
-    for my $s (@PARAMETERS) {
-	my $p = eval "\$Geo::OGR::SRS_PP_$s";
-	$PARAMETERS{$s} = $p;
+    elsif (/^SRS_UL_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $LINEAR_UNITS{$p} = 1;
     }
-    sub create {
-	my $pkg = shift;
-	my %param = @_;
-	my $self = Geo::OSRc::new_SpatialReference();
-	if ($param{WKT}) {
-	    ImportFromWkt($self, $param{WKT});
-	} elsif ($param{Text}) {
-	    ImportFromWkt($self, $param{Text});
-	} elsif ($param{Proj4}) {
-	    ImportFromProj4($self, $param{Proj4});
-	} elsif ($param{ESRI}) {
-	    ImportFromESRI($self, @{$param{ESRI}});
-	} elsif ($param{EPSG}) {
-	    ImportFromEPSG($self, $param{EPSG});
-	} elsif ($param{EPSGA}) {
-	    ImportFromEPSGA($self, $param{EPSGA});
-	} elsif ($param{PCI}) {
-	    ImportFromPCI($self, @{$param{PCI}});
-	} elsif ($param{USGS}) {
-	    ImportFromUSGS($self, @{$param{USGS}});
-	} elsif ($param{XML}) {
-	    ImportFromXML($self, $param{XML});
-	} elsif ($param{GML}) {
-	    ImportFromGML($self, $param{GML});
-	} elsif ($param{URL}) {
-	    ImportFromUrl($self, $param{URL});
-	} elsif ($param{ERMapper}) {
-	    ImportFromERM($self, @{$param{ERMapper}} );
-	} elsif ($param{ERM}) {
-	    ImportFromERM($self, @{$param{ERM}} );
-	} elsif ($param{MICoordSys}) {
-	    ImportFromMICoordSys($self, $param{MICoordSys} );
-	} elsif ($param{MapInfoCS}) {
-	    ImportFromMICoordSys($self, $param{MapInfoCS} );
-	} else {
-	    croak "unrecognized import format '@_' for Geo::OSR::SpatialReference";
-	}
-	bless $self, $pkg if defined $self;
+    elsif (/^SRS_UA_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $ANGULAR_UNITS{$p} = 1;
+    }
+    elsif (/^SRS_DN_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $DATUMS{$p} = 1;
+    }
+}
+
+sub Projections {
+    return keys %PROJECTIONS;
+}
+
+sub Parameters {
+    return keys %PARAMETERS;
+}
+
+sub LinearUnits {
+    return keys %LINEAR_UNITS;
+}
+
+sub AngularUnits {
+    return keys %ANGULAR_UNITS;
+}
+
+sub Datums {
+    return keys %DATUMS;
+}
+
+sub RELEASE_PARENTS {
+}
+
+
+package Geo::OSR::SpatialReference;
+use strict;
+use warnings;
+use Carp;
+%}
+
+%feature("shadow") OSRSpatialReferenceShadow( char const * wkt = "" )
+%{
+use Carp;
+sub new {
+    my $pkg = shift;
+    my %param = @_;
+    my $self = Geo::OSRc::new_SpatialReference();
+    if ($param{WKT}) {
+        ImportFromWkt($self, $param{WKT});
+    } elsif ($param{Text}) {
+        ImportFromWkt($self, $param{Text});
+    } elsif ($param{Proj4}) {
+        ImportFromProj4($self, $param{Proj4});
+    } elsif ($param{ESRI}) {
+        ImportFromESRI($self, @{$param{ESRI}});
+    } elsif ($param{EPSG}) {
+        ImportFromEPSG($self, $param{EPSG});
+    } elsif ($param{EPSGA}) {
+        ImportFromEPSGA($self, $param{EPSGA});
+    } elsif ($param{PCI}) {
+        ImportFromPCI($self, @{$param{PCI}});
+    } elsif ($param{USGS}) {
+        ImportFromUSGS($self, @{$param{USGS}});
+    } elsif ($param{XML}) {
+        ImportFromXML($self, $param{XML});
+    } elsif ($param{GML}) {
+        ImportFromGML($self, $param{GML});
+    } elsif ($param{URL}) {
+        ImportFromUrl($self, $param{URL});
+    } elsif ($param{ERMapper}) {
+        ImportFromERM($self, @{$param{ERMapper}});
+    } elsif ($param{ERM}) {
+        ImportFromERM($self, @{$param{ERM}});
+    } elsif ($param{MICoordSys}) {
+        ImportFromMICoordSys($self, $param{MICoordSys});
+    } elsif ($param{MapInfoCS}) {
+        ImportFromMICoordSys($self, $param{MapInfoCS});
+    } elsif ($param{WGS}) {
+        eval {
+            SetWellKnownGeogCS($self, 'WGS'.$param{WGS});
+        };
+        confess "$@" if $@;
+    } else {
+        confess "Unrecognized/missing parameters: @_.";
     }
-    sub Export {
-	my $self = shift;
-	my $format;
-	$format = pop if @_ == 1;
-	my %params = @_;
-	$format = $params{to} unless $format;
-	$format = $params{format} unless $format;
-	$format = $params{as} unless $format;
-	if ($format eq 'WKT' or $format eq 'Text') {
-	    return ExportToWkt($self);
-	} elsif ($format eq 'PrettyWKT') {
-	    my $simplify = exists $params{simplify} ? $params{simplify} : 0;
-	    return ExportToPrettyWkt($self, $simplify);
-	} elsif ($format eq 'Proj4') {
-	    return ExportToProj4($self);
-	} elsif ($format eq 'PCI') {	    
-	    return ExportToPCI($self);
-	} elsif ($format eq 'USGS') {
-	    return ExportToUSGS($self);
-	} elsif ($format eq 'GML' or $format eq 'XML') {
-	    my $dialect = exists $params{dialect} ? $params{dialect} : '';
-	    return ExportToXML($self, $dialect);
-	} elsif ($format eq 'MICoordSys' or $format eq 'MapInfoCS') {
-	    return ExportToMICoordSys();
-	} else {
-	    croak "unrecognized export format '$format/@_' for Geo::OSR::SpatialReference.";
-	}
+    bless $self, $pkg if defined $self;
+}
+%}
+
+%perlcode %{
+sub Export {
+    my $self = shift;
+    my $format;
+    $format = pop if @_ == 1;
+    my %params = @_;
+    $format = $params{to} unless $format;
+    $format = $params{format} unless $format;
+    $format = $params{as} unless $format;
+    if ($format eq 'WKT' or $format eq 'Text') {
+        return ExportToWkt($self);
+    } elsif ($format eq 'PrettyWKT') {
+        my $simplify = exists $params{simplify} ? $params{simplify} : 0;
+        return ExportToPrettyWkt($self, $simplify);
+    } elsif ($format eq 'Proj4') {
+        return ExportToProj4($self);
+    } elsif ($format eq 'PCI') {            
+        return ExportToPCI($self);
+    } elsif ($format eq 'USGS') {
+        return ExportToUSGS($self);
+    } elsif ($format eq 'GML' or $format eq 'XML') {
+        my $dialect = exists $params{dialect} ? $params{dialect} : '';
+        return ExportToXML($self, $dialect);
+    } elsif ($format eq 'MICoordSys' or $format eq 'MapInfoCS') {
+        return ExportToMICoordSys();
+    } else {
+        confess "Unrecognized export format.";
     }
-    *AsText = *ExportToWkt;
-    *As = *Export;
-    sub Set {
-	my($self, %params) = @_;
-	if (exists $params{Authority} and exists $params{Node} and exists $params{Code}) {
-	    SetAuthority($self, $params{TargetKey}, $params{Authority}, $params{Code});
-	} elsif (exists $params{Node} and exists $params{Value}) {
-	    SetAttrValue($self, $params{Node}, $params{Value});
-	} elsif (exists $params{AngularUnits} and exists $params{Value}) {
-	    SetAngularUnits($self, $params{AngularUnits}, $params{Value});
-	} elsif (exists $params{LinearUnits} and exists $params{Node} and exists $params{Value}) {
-	    SetTargetLinearUnits($self, $params{Node}, $params{LinearUnits}, $params{Value});
-	} elsif (exists $params{LinearUnits} and exists $params{Value}) {
-	    SetLinearUnitsAndUpdateParameters($self, $params{LinearUnits}, $params{Value});
-	} elsif ($params{CoordinateSystem} eq 'UTM' and exists $params{Zone} and exists $params{North}) {
-	    my $north = exists $params{North} ? $params{North} : 1;
-	    SetUTM($self, $params{Zone}, $north);
-	} elsif ($params{CoordinateSystem} eq 'State Plane' and exists $params{Zone}) {
-	    my $NAD83 = exists $params{NAD83} ? $params{NAD83} : 1;
-	    my $name = exists $params{UnitName} ? $params{UnitName} : undef;
-	    my $c = exists $params{UnitConversionFactor} ? $params{UnitConversionFactor} : 0.0;
-	    SetStatePlane($self, $params{Zone}, $NAD83, $name, $c);
-	} elsif ($params{Parameter} and exists $params{Value}) {
-	    croak "unknown parameter '$params{Parameter}' in Geo::OSR::SpatialReference->Set" unless exists $PARAMETERS{$params{Parameter}};
-	    $params{Normalized} ?
-		SetNormProjParm($self, $params{Parameter}, $params{Value}) :
-		SetProjParm($self, $params{Parameter}, $params{Value});
-	} elsif ($params{Projection}) {
-	    croak "unknown projection '$params{Projection}' in Geo::OSR::SpatialReference->Set" unless exists $PROJECTIONS{$params{Projection}};
-	    if (not $params{Parameters}) {
-		SetProjection($self, $PROJECTIONS{$params{Projection}});
-	    } elsif ($params{Projection} eq 'ALBERS_CONIC_EQUAL_AREA' and $params{Parameters}) {
-		SetACEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'AZIMUTHAL_EQUIDISTANT' and $params{Parameters}) {
-		SetAE($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'BONNE' and $params{Parameters}) {
-		SetBonne($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'CYLINDRICAL_EQUAL_AREA' and $params{Parameters}) {
-		SetCEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'CASSINI_SOLDNER' and $params{Parameters}) {
-		SetCS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'EQUIDISTANT_CONIC' and $params{Parameters}) {
-		SetEC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ECKERT_IV' and $params{Parameters}) {
-		SetEckertIV($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ECKERT_VI' and $params{Parameters}) {
-		SetEckertVI($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'EQUIRECTANGULAR' and $params{Parameters}) {
-		@{$params{Parameters}} == 4 ?
-		    SetEquirectangular($self, @{$params{Parameters}}) :
-		    SetEquirectangular2($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GAUSSSCHREIBERTMERCATOR' and $params{Parameters}) {
-		SetGaussSchreiberTMercator($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GALL_STEREOGRAPHIC' and $params{Parameters}) {
-		SetGS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GOODE_HOMOLOSINE' and $params{Parameters}) {
-		SetGH($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'IGH') {
-		SetIGH($self);
-	    } elsif ($params{Projection} eq 'GEOSTATIONARY_SATELLITE' and $params{Parameters}) {
-		SetGEOS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GNOMONIC' and $params{Parameters}) {
-		SetGnomonic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'HOTINE_OBLIQUE_MERCATOR' and $params{Parameters}) {
-		SetHOM($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN' and $params{Parameters}) {
-		SetHOM2PNO($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'KROVAK' and $params{Parameters}) {
-		SetKrovak($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_AZIMUTHAL_EQUAL_AREA' and $params{Parameters}) {
-		SetLAEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_2SP' and $params{Parameters}) {
-		SetLCC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_1SP' and $params{Parameters}) {
-		SetLCC1SP($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM' and $params{Parameters}) {
-		SetLCCB($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'MILLER_CYLINDRICAL' and $params{Parameters}) {
-		SetMC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} =~ /^MERCATOR/ and $params{Parameters}) {
-		SetMercator($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'MOLLWEIDE' and $params{Parameters}) {
-		SetMollweide($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'NEW_ZEALAND_MAP_GRID' and $params{Parameters}) {
-		SetNZMG($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'OBLIQUE_STEREOGRAPHIC' and $params{Parameters}) {
-		SetOS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ORTHOGRAPHIC' and $params{Parameters}) {
-		SetOrthographic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'POLYCONIC' and $params{Parameters}) {
-		SetPolyconic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'POLAR_STEREOGRAPHIC' and $params{Parameters}) {
-		SetPS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ROBINSON' and $params{Parameters}) {
-		SetRobinson($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'SINUSOIDAL' and $params{Parameters}) {
-		SetSinusoidal($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'STEREOGRAPHIC' and $params{Parameters}) {
-		SetStereographic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'SWISS_OBLIQUE_CYLINDRICAL' and $params{Parameters}) {
-		SetSOC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'TRANSVERSE_MERCATOR_SOUTH_ORIENTED' and $params{Parameters}) {
-		SetTMSO($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} =~ /^TRANSVERSE_MERCATOR/ and $params{Parameters}) {
-		my($variant) = $params{Projection} =~ /^TRANSVERSE_MERCATOR_(\w+)/;
-		$variant = $params{Name} unless $variant;
-		$variant ?
-		    SetTMVariant($self, $variant, @{$params{Parameters}}) :
-		    SetTM($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'TUNISIA_MINING_GRID' and $params{Parameters}) {
-		SetTMG($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'VANDERGRINTEN' and $params{Parameters}) {
-		SetVDG($self, @{$params{Parameters}});
-	    } elsif ($params{Name}) {
-		SetWellKnownGeogCS($self, $params{Name});
-	    } elsif ($params{GuessFrom}) {
-		SetFromUserInput($self, $params{GuessFrom});
-	    } elsif ($params{CoordinateSystem} eq 'WGS' and $params{Parameters}) {
-		SetTOWGS84($self, @{$params{Parameters}});
-	    } elsif ($params{LOCAL_CS}) {
-		SetLocalCS($self, $params{LOCAL_CS});
-	    } elsif ($params{CoordinateSystem} and $params{Datum} and $params{Spheroid} and $params{Parameters}) {
-		SetGeogCS($self, $params{CoordinateSystem}, $params{Datum}, $params{Spheroid}, @{$params{Parameters}});
-	    } elsif ($params{CoordinateSystem}) {
-		SetProjCS($self, $params{CoordinateSystem});
-	    } elsif ($params{GeocentricCS}) {
-		SetGeocCS($self, $params{GeocentricCS});
-	    } elsif ($params{VerticalCS} and $params{Datum}) {
-		my $type = $params{VertDatumType} || 2005;
-		SetVertCS($self, $params{VerticalCS}, $params{Datum}, $type);
-	    } elsif ($params{CoordinateSystem} and $params{HorizontalCS} and $params{VerticalCS}) {
-		SetCompoundCS($self, $params{CoordinateSystem}, $params{HorizontalCS}, $params{VerticalCS});
-	    } else {
-		croak "not enough information to set anything in a spatial reference object in Geo::OSR::SpatialReference->Set";
-	    }
-	}
+}
+*AsText = *ExportToWkt;
+*As = *Export;
+
+sub Set {
+    my($self, %params) = @_;
+    if (exists $params{Authority} and exists $params{TargetKey} and exists $params{Node} and exists $params{Code}) {
+        SetAuthority($self, $params{TargetKey}, $params{Authority}, $params{Code});
+    } elsif (exists $params{Node} and exists $params{Value}) {
+        SetAttrValue($self, $params{Node}, $params{Value});
+    } elsif (exists $params{AngularUnits} and exists $params{Value}) {
+        SetAngularUnits($self, $params{AngularUnits}, $params{Value});
+    } elsif (exists $params{LinearUnits} and exists $params{Node} and exists $params{Value}) {
+        SetTargetLinearUnits($self, $params{Node}, $params{LinearUnits}, $params{Value});
+    } elsif (exists $params{LinearUnits} and exists $params{Value}) {
+        SetLinearUnitsAndUpdateParameters($self, $params{LinearUnits}, $params{Value});
+    } elsif ($params{Parameter} and exists $params{Value}) {
+        croak "Unknown projection parameter '$params{Parameter}'." unless exists $Geo::OSR::PARAMETERS{$params{Parameter}};
+        $params{Normalized} ?
+            SetNormProjParm($self, $params{Parameter}, $params{Value}) :
+            SetProjParm($self, $params{Parameter}, $params{Value});
+    } elsif ($params{Name}) {
+        SetWellKnownGeogCS($self, $params{Name});
+    } elsif ($params{GuessFrom}) {
+        SetFromUserInput($self, $params{GuessFrom});
+    } elsif ($params{LOCAL_CS}) {
+        SetLocalCS($self, $params{LOCAL_CS});
+    } elsif ($params{GeocentricCS}) {
+        SetGeocCS($self, $params{GeocentricCS});
+    } elsif ($params{VerticalCS} and $params{Datum}) {
+        my $type = $params{VertDatumType} || 2005;
+        SetVertCS($self, $params{VerticalCS}, $params{Datum}, $type);
+    } elsif ($params{CoordinateSystem}) {
+        my @parameters = ();
+        @parameters = @{$params{Parameters}} if ref($params{Parameters});
+        if ($params{CoordinateSystem} eq 'State Plane' and exists $params{Zone}) {
+            my $NAD83 = exists $params{NAD83} ? $params{NAD83} : 1;
+            my $name = exists $params{UnitName} ? $params{UnitName} : undef;
+            my $c = exists $params{UnitConversionFactor} ? $params{UnitConversionFactor} : 0.0;
+            SetStatePlane($self, $params{Zone}, $NAD83, $name, $c);
+        } elsif ($params{CoordinateSystem} eq 'UTM' and exists $params{Zone} and exists $params{North}) {
+            my $north = exists $params{North} ? $params{North} : 1;
+            SetUTM($self, $params{Zone}, $north);
+        } elsif ($params{CoordinateSystem} eq 'WGS') {
+            SetTOWGS84($self, @parameters);
+        } elsif ($params{CoordinateSystem} and $params{Datum} and $params{Spheroid}) {
+            SetGeogCS($self, $params{CoordinateSystem}, $params{Datum}, $params{Spheroid}, @parameters);
+        } elsif ($params{CoordinateSystem} and $params{HorizontalCS} and $params{VerticalCS}) {
+            SetCompoundCS($self, $params{CoordinateSystem}, $params{HorizontalCS}, $params{VerticalCS});
+        } else {
+            SetProjCS($self, $params{CoordinateSystem});
+        }
+    } elsif ($params{Projection}) {
+        confess "Unknown projection." unless exists $Geo::OSR::PROJECTIONS{$params{Projection}};
+        my @parameters = ();
+        @parameters = @{$params{Parameters}} if ref($params{Parameters});
+        if ($params{Projection} eq 'Albers_Conic_Equal_Area') {
+            SetACEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Azimuthal_Equidistant') {
+            SetAE($self, @parameters);
+        } elsif ($params{Projection} eq 'Bonne') {
+            SetBonne($self, @parameters);
+        } elsif ($params{Projection} eq 'Cylindrical_Equal_Area') {
+            SetCEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Cassini_Soldner') {
+            SetCS($self, @parameters);
+        } elsif ($params{Projection} eq 'Equidistant_Conic') {
+            SetEC($self, @parameters);
+            # Eckert_I, Eckert_II, Eckert_III, Eckert_V ?
+        } elsif ($params{Projection} eq 'Eckert_IV') {
+            SetEckertIV($self, @parameters);
+        } elsif ($params{Projection} eq 'Eckert_VI') {
+            SetEckertVI($self, @parameters);
+        } elsif ($params{Projection} eq 'Equirectangular') {
+            @parameters == 4 ?
+                SetEquirectangular($self, @parameters) :
+                SetEquirectangular2($self, @parameters);
+        } elsif ($params{Projection} eq 'Gauss_Schreiber_Transverse_Mercator') {
+            SetGaussSchreiberTMercator($self, @parameters);
+        } elsif ($params{Projection} eq 'Gall_Stereographic') {
+            SetGS($self, @parameters);
+        } elsif ($params{Projection} eq 'Goode_Homolosine') {
+            SetGH($self, @parameters);
+        } elsif ($params{Projection} eq 'Interrupted_Goode_Homolosine') {
+            SetIGH($self);
+        } elsif ($params{Projection} eq 'Geostationary_Satellite') {
+            SetGEOS($self, @parameters);
+        } elsif ($params{Projection} eq 'Gnomonic') {
+            SetGnomonic($self, @parameters);
+        } elsif ($params{Projection} eq 'Hotine_Oblique_Mercator') {
+            # Hotine_Oblique_Mercator_Azimuth_Center ?
+            SetHOM($self, @parameters);
+        } elsif ($params{Projection} eq 'Hotine_Oblique_Mercator_Two_Point_Natural_Origin') {
+            SetHOM2PNO($self, @parameters);
+        } elsif ($params{Projection} eq 'Krovak') {
+            SetKrovak($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Azimuthal_Equal_Area') {
+            SetLAEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_2SP') {
+            SetLCC($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_1SP') {
+            SetLCC1SP($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_2SP_Belgium') {
+            SetLCCB($self, @parameters);
+        } elsif ($params{Projection} eq 'miller_cylindrical') {
+            SetMC($self, @parameters);
+        } elsif ($params{Projection} =~ /^Mercator/) {
+            # Mercator_1SP, Mercator_2SP, Mercator_Auxiliary_Sphere ?
+            # variant is in Variant (or Name)
+            SetMercator($self, @parameters);
+        } elsif ($params{Projection} eq 'Mollweide') {
+            SetMollweide($self, @parameters);
+        } elsif ($params{Projection} eq 'New_Zealand_Map_Grid') {
+            SetNZMG($self, @parameters);
+        } elsif ($params{Projection} eq 'Oblique_Stereographic') {
+            SetOS($self, @parameters);
+        } elsif ($params{Projection} eq 'Orthographic') {
+            SetOrthographic($self, @parameters);
+        } elsif ($params{Projection} eq 'Polyconic') {
+            SetPolyconic($self, @parameters);
+        } elsif ($params{Projection} eq 'Polar_Stereographic') {
+            SetPS($self, @parameters);
+        } elsif ($params{Projection} eq 'Robinson') {
+            SetRobinson($self, @parameters);
+        } elsif ($params{Projection} eq 'Sinusoidal') {
+            SetSinusoidal($self, @parameters);
+        } elsif ($params{Projection} eq 'Stereographic') {
+            SetStereographic($self, @parameters);
+        } elsif ($params{Projection} eq 'Swiss_Oblique_Cylindrical') {
+            SetSOC($self, @parameters);
+        } elsif ($params{Projection} eq 'Transverse_Mercator_South_Orientated') {
+            SetTMSO($self, @parameters);
+        } elsif ($params{Projection} =~ /^Transverse_Mercator/) {
+            my($variant) = $params{Projection} =~ /^Transverse_Mercator_(\w+)/;
+            $variant = $params{Variant} unless $variant;
+            $variant = $params{Name} unless $variant;
+            $variant ?
+                SetTMVariant($self, $variant, @parameters) :
+                SetTM($self, @parameters);
+        } elsif ($params{Projection} eq 'Tunisia_Mining_Grid') {
+            SetTMG($self, @parameters);
+        } elsif ($params{Projection} eq 'VanDerGrinten') {
+            SetVDG($self, @parameters);
+        } else {
+            # Aitoff, Craster_Parabolic, International_Map_of_the_World_Polyconic, Laborde_Oblique_Mercator
+            # Loximuthal, Miller_Cylindrical, Quadrilateralized_Spherical_Cube, Quartic_Authalic, Two_Point_Equidistant
+            # Wagner_I, Wagner_II, Wagner_III, Wagner_IV, Wagner_V, Wagner_VI, Wagner_VII
+            # Winkel_I, Winkel_II, Winkel_Tripel
+            # ?
+            SetProjection($self, $params{Projection});
+        }
+    } else {
+        confess "Not enough information for a spatial reference object.";
     }
-    sub GetUTMZone {
-	my $self = shift;
-	my $zone = _GetUTMZone($self);
-	if (wantarray) {	    
-	    my $north = 1;
-	    if ($zone < 0) {
-		$zone *= -1;
-		$north = 0;
-	    }
-	    return ($zone, $north);
-	} else {
-	    return $zone;
-	}
+}
+
+sub GetUTMZone {
+    my $self = shift;
+    my $zone = _GetUTMZone($self);
+    if (wantarray) {            
+        my $north = 1;
+        if ($zone < 0) {
+            $zone *= -1;
+            $north = 0;
+        }
+        return ($zone, $north);
+    } else {
+        return $zone;
     }
+}
+
+
+package Geo::OSR::CoordinateTransformation;
+use strict;
+use warnings;
 
-    package Geo::OSR::CoordinateTransformation;
-    use strict;
-    sub TransformPoints {
-	my($self, $points) = @_;
-	_TransformPoints($self, $points), return unless ref($points->[0]->[0]);
-	for my $p (@$points) {
-	    TransformPoints($self, $p);
-	}
+sub TransformPoints {
+    my($self, $points) = @_;
+    _TransformPoints($self, $points), return unless ref($points->[0]->[0]);
+    for my $p (@$points) {
+        TransformPoints($self, $p);
     }
+}
 %}
diff --git a/swig/include/perl/typemaps_perl.i b/swig/include/perl/typemaps_perl.i
index ff49ef7..c58cbfe 100644
--- a/swig/include/perl/typemaps_perl.i
+++ b/swig/include/perl/typemaps_perl.i
@@ -16,22 +16,42 @@
 
 /*
  * double *val, int*hasval, is a special contrived typemap used for
- * the RasterBand GetNoDataValue, GetMinimum, GetMaximum, GetOffset, GetScale methods.
- * the variable hasval is tested.  If it is false (is, the value
- * is not set in the raster band) then undef is returned.  If is is != 0, then
- * the value is coerced into a long and returned.
+ * the RasterBand GetNoDataValue, GetMinimum, GetMaximum, GetOffset,
+ * GetScale methods. The variable hasval is tested and if it is false
+ * (meaning, the value is not set in the raster band) then undef is
+ * returned in scalar context.  If is is != 0, then the value is
+ * coerced into a long and returned in scalar context. In list context
+ * the value and hasval are returned. If hasval is zero, the value is
+ * "generally the minimum supported value for the data type".
  */
+
 %typemap(in,numinputs=0) (double *val, int *hasval) ( double tmpval, int tmphasval ) {
   /* %typemap(in,numinputs=0) (double *val, int *hasval) */
   $1 = &tmpval;
   $2 = &tmphasval;
 }
 %typemap(argout) (double *val, int *hasval) {
-  /* %typemap(argout) (double *val, int *hasval) */
-  $result = sv_newmortal();
-  if ( *$2 )
-    sv_setnv($result, *$1);
-  argvi++;
+    /* %typemap(argout) (double *val, int *hasval) */
+    if (GIMME_V == G_ARRAY) {
+        $result = sv_newmortal();
+        sv_setnv($result, *$1);
+        argvi++;
+        $result = sv_newmortal();
+        sv_setiv($result, *$2);
+        argvi++;
+    } else {
+        if ( *$2 ) {
+            $result = sv_newmortal();
+            sv_setnv($result, *$1);
+            argvi++;
+        }
+    }
+}
+
+%typemap(in) GIntBig
+{
+  /* %typemap(in) GIntBig */
+  $1 = SvIV($input); //FIXME is that right ??
 }
 
 %typemap(out) GIntBig
@@ -53,31 +73,31 @@
 {
     /* %typemap(out) char **CSL */
     if (GIMME_V == G_ARRAY) {
-	if ($1) {
-	    int i;
-	    for (i = 0; $1[i]; i++) {
-		if (argvi > items-1) EXTEND(SP, 1);
-		SV *sv = newSVpv($1[i], 0);
-		SvUTF8_on(sv); /* expecting GDAL to give us UTF-8 */
-		ST(argvi++) = sv_2mortal(sv);
-	    }
-	    CSLDestroy($1);
-	}
+        if ($1) {
+            int i;
+            for (i = 0; $1[i]; i++) {
+                if (argvi > items-1) EXTEND(SP, 1);
+                SV *sv = newSVpv($1[i], 0);
+                SvUTF8_on(sv); /* expecting GDAL to give us UTF-8 */
+                ST(argvi++) = sv_2mortal(sv);
+            }
+            CSLDestroy($1);
+        }
     } else {
-	AV *av = (AV*)sv_2mortal((SV*)newAV());
-	if ($1) {
-	    int i;
-	    for (i = 0; $1[i]; i++) {
-	      SV *sv = newSVpv($1[i], 0);
-	      SvUTF8_on(sv); /* expecting GDAL to give us UTF-8 */
-	      if (!av_store(av, i, sv))
-		SvREFCNT_dec(sv);
-	    }
-	    CSLDestroy($1);
-	}
-	$result = newRV((SV*)av);
-	sv_2mortal($result);
-	argvi++;
+        AV *av = (AV*)sv_2mortal((SV*)newAV());
+        if ($1) {
+            int i;
+            for (i = 0; $1[i]; i++) {
+              SV *sv = newSVpv($1[i], 0);
+              SvUTF8_on(sv); /* expecting GDAL to give us UTF-8 */
+              if (!av_store(av, i, sv))
+                SvREFCNT_dec(sv);
+            }
+            CSLDestroy($1);
+        }
+        $result = newRV((SV*)av);
+        sv_2mortal($result);
+        argvi++;
     }
 }
 %typemap(out) (char **CSL_REF)
@@ -90,7 +110,7 @@
       SV *sv = newSVpv($1[i], 0);
       SvUTF8_on(sv); /* expecting GDAL to give us UTF-8 */
       if (!av_store(av, i, sv))
-	SvREFCNT_dec(sv);
+        SvREFCNT_dec(sv);
     }
     CSLDestroy($1);
   }
@@ -144,6 +164,10 @@
 {
   /* %typemap(out) IF_ERROR_RETURN_NONE */
 }
+%typemap(out) CPLErr
+{
+  /* %typemap(out) CPLErr */
+}
 /* return value is really void or prepared by typemaps, avoids unnecessary sv_newmortal */
 %typemap(out) void
 {
@@ -336,12 +360,12 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(in) (double argin[ANY]) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     $1 = argin;
     AV *av = (AV*)(SvRV($input));
     for (unsigned int i=0; i<$dim0; i++) {
-	SV **sv = av_fetch(av, i, 0);
-	$1[i] =  SvNV(*sv);
+        SV **sv = av_fetch(av, i, 0);
+        $1[i] =  SvNV(*sv);
     }
 }
 
@@ -352,60 +376,64 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(in,numinputs=1) (int nList, int* pList) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
     $1 = av_len(av)+1;
-    $2 = (int*) malloc($1*sizeof(int));
-    for( int i = 0; i<$1; i++ ) {
-	SV **sv = av_fetch(av, i, 0);
-	$2[i] =  SvIV(*sv);
-    }
+    $2 = (int*)CPLMalloc($1*sizeof(int));
+    if ($2) {
+        for( int i = 0; i<$1; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            $2[i] =  SvIV(*sv);
+        }
+    } else
+        SWIG_fail;
 }
 %typemap(freearg) (int nList, int* pList)
 {
     /* %typemap(freearg) (int nList, int* pList) */
-    if ($2)
-	free((void*) $2);
+    CPLFree((void*) $2);
 }
 
 %typemap(in,numinputs=1) (int nList, double* pList)
 {
     /* %typemap(in,numinputs=1) (int nList, double* pList) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
     $1 = av_len(av)+1;
-    $2 = (double*) malloc($1*sizeof(double));
-    for( int i = 0; i<$1; i++ ) {
-	SV **sv = av_fetch(av, i, 0);
-	$2[i] =  SvNV(*sv);
-    }
+    $2 = (double*)CPLMalloc($1*sizeof(double));
+    if ($2) {
+        for( int i = 0; i<$1; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            $2[i] =  SvNV(*sv);
+        }
+    } else
+        SWIG_fail;
 }
 %typemap(freearg) (int nList, double* pList)
 {
     /* %typemap(freearg) (int nList, double* pList) */
-    if ($2)
-	free((void*) $2);
+    CPLFree((void*) $2);
 }
 
 %typemap(in) (char **pList)
 {
     /* %typemap(in) (char **pList) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
     for (int i = 0; i < av_len(av)+1; i++) {
-	SV *sv = *(av_fetch(av, i, 0));
-	sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-	char *pszItem = SvPV_nolen(sv);
-	$1 = CSLAddString( $1, pszItem );
+        SV *sv = *(av_fetch(av, i, 0));
+        sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+        char *pszItem = SvPV_nolen(sv);
+        $1 = CSLAddString( $1, pszItem );
     }
 }
 %typemap(freearg) (char **pList)
 {
     /* %typemap(freearg) (char **pList) */
     if ($1)
-	CSLDestroy( $1 );
+        CSLDestroy( $1 );
 }
 
 %typemap(in,numinputs=1) (int defined, double value)
@@ -445,28 +473,28 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
     if (SvOK($input)) {
-	if (!SvPOK($input))
-	    SWIG_croak("expected binary data as input");
-	STRLEN len = SvCUR($input);
-	$2 = SvPV_nolen($input);
-	$1 = len;
+        if (!SvPOK($input))
+            SWIG_croak("Expected binary data.");
+        STRLEN len = SvCUR($input);
+        $2 = SvPV_nolen($input);
+        $1 = len;
     } else {
-	$2 = NULL;
-	$1 = 0;
+        $2 = NULL;
+        $1 = 0;
     }
 }
 %typemap(in,numinputs=1) (int nLen, unsigned char *pBuf )
 {
     /* %typemap(in,numinputs=1) (int nLen, unsigned char *pBuf ) */
     if (SvOK($input)) {
-	if (!SvPOK($input))
-	    SWIG_croak("expected binary data as input to a Geo::GDAL method");
-	STRLEN len = SvCUR($input);
-	$2 = (unsigned char *)SvPV_nolen($input);
-	$1 = len;
+        if (!SvPOK($input))
+            SWIG_croak("Expected binary data.");
+        STRLEN len = SvCUR($input);
+        $2 = (unsigned char *)SvPV_nolen($input);
+        $1 = len;
     } else {
-	$2 = NULL;
-	$1 = 0;
+        $2 = NULL;
+        $1 = 0;
     }
 }
 
@@ -533,30 +561,28 @@ CreateArrayFromStringArray( char **first ) {
   $result = sv_2mortal(newRV((SV*)dict));
   argvi++;
 }
-%typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) ( GDAL_GCP *tmpGCPList )
+%typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs )
 {
     /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
     $1 = av_len(av)+1;
-    tmpGCPList = (GDAL_GCP*) malloc($1*sizeof(GDAL_GCP));
-    $2 = tmpGCPList;
-    for( int i = 0; i<$1; i++ ) {
-	SV **sv = av_fetch(av, i, 0);
-	GDAL_GCP *item = 0;
-	SWIG_ConvertPtr( *sv, (void**)&item, SWIGTYPE_p_GDAL_GCP, 0 );
-	if (!item )
-	    SWIG_fail;
-	memcpy( (void*) tmpGCPList, (void*) item, sizeof( GDAL_GCP ) );
-	++tmpGCPList;
-    }
+    $2 = (GDAL_GCP *)CPLMalloc($1*sizeof(GDAL_GCP));
+    if ($2) {
+        for (int i = 0; i < $1; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            int ret = SWIG_ConvertPtr(*sv, (void**)&($2[i]), SWIGTYPE_p_GDAL_GCP, 0);
+            if (!SWIG_IsOK(ret))
+                SWIG_croak("An item in the argument array is not a GCP object.");
+        }
+    } else
+        SWIG_croak("Out of memory.");
 }
 %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs )
 {
     /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    if ($2)
-	free($2);
+    CPLFree($2);
 }
 
 /*
@@ -567,7 +593,7 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(out) GDALColorEntry* */
     if (!result)
-	SWIG_croak("GetColorEntry failed");
+        SWIG_croak("GetColorEntry failed.");
     $result = sv_newmortal();
     sv_setiv(ST(argvi++), (IV) result->c1);
     $result = sv_newmortal();
@@ -586,7 +612,7 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(argout) GDALColorEntry* */
     if (!result)
-	SWIG_croak("GetColorEntryAsRGB failed");
+        SWIG_croak("GetColorEntryAsRGB failed.");
     argvi--;
     $result = sv_newmortal();
     sv_setiv(ST(argvi++), (IV) e3.c1);
@@ -605,17 +631,23 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(in,numinputs=1) const GDALColorEntry*(GDALColorEntry e) */
     $1 = &e3;
-    if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
-    AV *av = (AV*)(SvRV($input));
-    SV **sv = av_fetch(av, 0, 0);
-    $1->c1 =  SvIV(*sv);
-    sv = av_fetch(av, 1, 0);
-    $1->c2 =  SvIV(*sv);
-    sv = av_fetch(av, 2, 0);
-    $1->c3 =  SvIV(*sv);
-    sv = av_fetch(av, 3, 0);
-    $1->c4 =  SvIV(*sv);
+    int ok = SvROK($input) && SvTYPE(SvRV($input))==SVt_PVAV;
+    AV *av;
+    if (ok) {
+      av = (AV*)(SvRV($input));
+      ok = av_len(av) == 3;
+    }
+    if (ok) {
+      SV **sv = av_fetch(av, 0, 0);
+      $1->c1 =  SvIV(*sv);
+      sv = av_fetch(av, 1, 0);
+      $1->c2 =  SvIV(*sv);
+      sv = av_fetch(av, 2, 0);
+      $1->c3 =  SvIV(*sv);
+      sv = av_fetch(av, 3, 0);
+      $1->c4 =  SvIV(*sv);
+    } else 
+      SWIG_croak("Color entry is an array of four values: red, green, blue, alpha.");
 }
 
 /*
@@ -674,29 +706,29 @@ CreateArrayFromStringArray( char **first ) {
     /* %typemap(in) char **options */
     if (SvOK($input)) {
         if (SvROK($input)) {
-	    if (SvTYPE(SvRV($input))==SVt_PVAV) {
-		AV *av = (AV*)(SvRV($input));
-		for (int i = 0; i < av_len(av)+1; i++) {
-		    SV *sv = *(av_fetch(av, i, 0));
-		    sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-		    char *pszItem = SvPV_nolen(sv);
-		    $1 = CSLAddString( $1, pszItem );
-		}
-	    } else if (SvTYPE(SvRV($input))==SVt_PVHV) {
-		HV *hv = (HV*)SvRV($input);
-		SV *sv;
-		char *key;
-		I32 klen;
-		$1 = NULL;
-		hv_iterinit(hv);
-		while(sv = hv_iternextsv(hv,&key,&klen)) {
-		    sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+            if (SvTYPE(SvRV($input))==SVt_PVAV) {
+                AV *av = (AV*)(SvRV($input));
+                for (int i = 0; i < av_len(av)+1; i++) {
+                    SV *sv = *(av_fetch(av, i, 0));
+                    sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                    char *pszItem = SvPV_nolen(sv);
+                    $1 = CSLAddString( $1, pszItem );
+                }
+            } else if (SvTYPE(SvRV($input))==SVt_PVHV) {
+                HV *hv = (HV*)SvRV($input);
+                SV *sv;
+                char *key;
+                I32 klen;
+                $1 = NULL;
+                hv_iterinit(hv);
+                while(sv = hv_iternextsv(hv,&key,&klen)) {
+                    sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
                     $1 = CSLAddNameValue( $1, key, SvPV_nolen(sv) );
-		}
-	    } else
-		SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
-	} else
-	    SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+                }
+            } else
+                SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+        } else
+            SWIG_croak("The 'options' argument is not a reference.");   
     }
 }
 %typemap(freearg) char **options
@@ -710,13 +742,13 @@ CreateArrayFromStringArray( char **first ) {
     AV* av = (AV*)sv_2mortal((SV*)newAV());
     char **stringarray = $1;
     if ( stringarray != NULL ) {
-	int n = CSLCount( stringarray );
-	for ( int i = 0; i < n; i++ ) {
-	    SV *sv = newSVpv(stringarray[i], 0);
-	    SvUTF8_on(sv); /* expecting UTF-8 from GDAL */
-	    if (!av_store(av, i, sv))
-		SvREFCNT_dec(sv);
-	}
+        int n = CSLCount( stringarray );
+        for ( int i = 0; i < n; i++ ) {
+            SV *sv = newSVpv(stringarray[i], 0);
+            SvUTF8_on(sv); /* expecting UTF-8 from GDAL */
+            if (!av_store(av, i, sv))
+                SvREFCNT_dec(sv);
+        }
     }
     $result = newRV((SV*)av);
     sv_2mortal($result);
@@ -817,9 +849,9 @@ CreateArrayFromStringArray( char **first ) {
 {
     /* %typemap(out) OGRErr */
     if ( result != 0 ) {
-	const char *err = CPLGetLastErrorMsg();
-	if (err and *err) SWIG_croak(err); /* this is usually better */
-	SWIG_croak( OGRErrMessages(result) );
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
     }
 }
 
@@ -831,16 +863,18 @@ CreateArrayFromStringArray( char **first ) {
 /************************************************************************/
 /*                          AVToXMLTree()                               */
 /************************************************************************/
-static CPLXMLNode *AVToXMLTree( AV *av )
+  static CPLXMLNode *AVToXMLTree( AV *av, int *err )
 {
     int      nChildCount = 0, iChild, nType;
     CPLXMLNode *psThisNode;
     char       *pszText = NULL;
     
     nChildCount = av_len(av) - 1; /* there are two non-childs in the array */
-    if (nChildCount < 0)
+    if (nChildCount < 0) {
         /* the input XML is empty */
-	return NULL;
+        *err = 1;
+        return NULL;
+    }
 
     nType = SvIV(*(av_fetch(av,0,0)));
     SV *sv = *(av_fetch(av,1,0));
@@ -850,19 +884,20 @@ static CPLXMLNode *AVToXMLTree( AV *av )
     
     for( iChild = 0; iChild < nChildCount; iChild++ )
     {
-	SV **s = av_fetch(av, iChild+2, 0);
-	CPLXMLNode *psChild;
-	if (!(SvROK(*s) && (SvTYPE(SvRV(*s))==SVt_PVAV)))
-	    /* expected a reference to an array */
-	    psChild = NULL;
-	else
-	    psChild = AVToXMLTree((AV*)SvRV(*s));
-	if (psChild)
-	    CPLAddXMLChild( psThisNode, psChild );
-	else {
-	    CPLDestroyXMLNode(psThisNode);
-	    return NULL;
-	}
+        SV **s = av_fetch(av, iChild+2, 0);
+        CPLXMLNode *psChild;
+        if (!(SvROK(*s) && (SvTYPE(SvRV(*s))==SVt_PVAV))) {
+            /* expected a reference to an array */
+            *err = 2;
+            psChild = NULL;
+        } else
+            psChild = AVToXMLTree((AV*)SvRV(*s), err);
+        if (psChild)
+            CPLAddXMLChild( psThisNode, psChild );
+        else {
+            CPLDestroyXMLNode(psThisNode);
+            return NULL;
+        }
     }
 
     return psThisNode;
@@ -873,10 +908,18 @@ static CPLXMLNode *AVToXMLTree( AV *av )
 {
     /* %typemap(in) (CPLXMLNode* xmlnode ) */
     if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
-    $1 = AVToXMLTree( av );
-    if ( !$1 ) SWIG_croak("conversion of a Perl array to XMLTree failed entering a Geo::GDAL method");
+    int err;
+    $1 = AVToXMLTree( av, &err );
+    if ( !$1 ) {
+        switch (err) {
+        case 1:
+            SWIG_croak("Conversion of a Perl array to XMLTree failed: the input XML is empty.");
+        case 2:
+            SWIG_croak("Conversion of a Perl array to XMLTree failed, child should be a reference to an array.");
+        }
+    }
 }
 %typemap(freearg) (CPLXMLNode *xmlnode)
 {
@@ -910,9 +953,9 @@ static AV *XMLTreeToAV( CPLXMLNode *psTree )
          psChild != NULL; 
          psChild = psChild->psNext, iChild++ )
     {
-	SV *s = newRV((SV*)XMLTreeToAV(psChild));
-	if (!av_store(av, iChild, s))
-	    SvREFCNT_dec(s);
+        SV *s = newRV((SV*)XMLTreeToAV(psChild));
+        if (!av_store(av, iChild, s))
+            SvREFCNT_dec(s);
     }
 
     return av;
@@ -939,14 +982,14 @@ static AV *XMLTreeToAV( CPLXMLNode *psTree )
 {
     /* %typemap(check) (type *param) */
     if (!$1)
-	SWIG_croak("The msg must not be undefined when it is an argument to a Geo::GDAL method");
+        SWIG_croak("The msg must not be undefined when it is an argument to a Geo::GDAL method");
 }
 %enddef
 
 %define IF_UNDEF_SET_EMPTY_STRING(type, param)
 %typemap(default) type param {
     /* %typemap(default) type param */
-    $1 = (char *)"";
+  $1 = (char *)"";
 }
 %enddef
 
@@ -980,30 +1023,32 @@ IF_UNDEF_NULL(const char *, target_key)
     /* %typemap(in) (int nCount, double *x, double *y, double *z) */
     /* $input is a ref to a list of refs to point lists */
     if (! (SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
-	SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
     AV *av = (AV*)(SvRV($input));
     $1 = av_len(av)+1;
-    $2 = (double*) malloc($1*sizeof(double));
-    $3 = (double*) malloc($1*sizeof(double));
-    $4 = (double*) malloc($1*sizeof(double));
+    $2 = (double*)CPLMalloc($1*sizeof(double));
+    if ($2)
+        $3 = (double*)CPLMalloc($1*sizeof(double));
+    if ($2 && $3)
+        $4 = (double*)CPLMalloc($1*sizeof(double));
     if (!$2 or !$3 or !$4)
-	SWIG_croak("out of memory in Geo::GDAL");
+        SWIG_fail;
     for (int i = 0; i < $1; i++) {
-	SV **sv = av_fetch(av, i, 0); /* ref to one point list */
-	if (!(SvROK(*sv) && (SvTYPE(SvRV(*sv))==SVt_PVAV)))
-	    SWIG_croak("expected a reference to a list of coordinates as an argument to a Geo::GDAL method");
-	AV *ac = (AV*)(SvRV(*sv));
-	int n = av_len(ac)+1;
-	SV **c = av_fetch(ac, 0, 0);
-	$2[i] = SvNV(*c);
-	c = av_fetch(ac, 1, 0);
-	$3[i] = SvNV(*c);
-	if (n < 3) {
-	    $4[i] = 0;
-	} else {
-	    c = av_fetch(ac, 2, 0);
-	    $4[i] = SvNV(*c);
-	}
+        SV **sv = av_fetch(av, i, 0); /* ref to one point list */
+        if (!(SvROK(*sv) && (SvTYPE(SvRV(*sv))==SVt_PVAV)))
+            SWIG_croak("An item in the list is not a reference to an array.");
+        AV *ac = (AV*)(SvRV(*sv));
+        int n = av_len(ac)+1;
+        SV **c = av_fetch(ac, 0, 0);
+        $2[i] = SvNV(*c);
+        c = av_fetch(ac, 1, 0);
+        $3[i] = SvNV(*c);
+        if (n < 3) {
+            $4[i] = 0;
+        } else {
+            c = av_fetch(ac, 2, 0);
+            $4[i] = SvNV(*c);
+        }
     }
 }
 
@@ -1012,27 +1057,27 @@ IF_UNDEF_NULL(const char *, target_key)
     /* %typemap(argout) (int nCount, double *x, double *y, double *z) */
     AV *av = (AV*)(SvRV($input));
     for (int i = 0; i < $1; i++) {
-	SV **sv = av_fetch(av, i, 0);
-	AV *ac = (AV*)(SvRV(*sv));
-	int n = av_len(ac)+1;
-	SV *c = newSVnv($2[i]);
-	if (!av_store(ac, 0, c))
-	    SvREFCNT_dec(c);
-	c = newSVnv($3[i]);
-	if (!av_store(ac, 1, c))
-	    SvREFCNT_dec(c);
-	c = newSVnv($4[i]);
-	if (!av_store(ac, 2, c))
-	    SvREFCNT_dec(c);
+        SV **sv = av_fetch(av, i, 0);
+        AV *ac = (AV*)(SvRV(*sv));
+        int n = av_len(ac)+1;
+        SV *c = newSVnv($2[i]);
+        if (!av_store(ac, 0, c))
+            SvREFCNT_dec(c);
+        c = newSVnv($3[i]);
+        if (!av_store(ac, 1, c))
+            SvREFCNT_dec(c);
+        c = newSVnv($4[i]);
+        if (!av_store(ac, 2, c))
+            SvREFCNT_dec(c);
     }
 }
 
 %typemap(freearg) (int nCount, double *x, double *y, double *z)
 {
     /* %typemap(freearg) (int nCount, double *x, double *y, double *z) */
-    if ($2) free($2);
-    if ($3) free($3);
-    if ($4) free($4);
+    CPLFree($2);
+    CPLFree($3);
+    CPLFree($4);
 }
 
 %typemap(arginit, noblock=1) ( void* callback_data = NULL)
@@ -1049,15 +1094,15 @@ IF_UNDEF_NULL(const char *, target_key)
     /* %typemap(in) (GDALProgressFunc callback = NULL) */
     if (SvOK($input)) {
         if (SvROK($input)) {
-	    if (SvTYPE(SvRV($input)) != SVt_PVCV) {
-	       SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
-	    } else {
-	       saved_env.fct = (SV *)$input;
-	       $1 = &callback_d_cp_vp;
+            if (SvTYPE(SvRV($input)) != SVt_PVCV) {
+               SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+            } else {
+               saved_env.fct = (SV *)$input;
+               $1 = &callback_d_cp_vp;
            }
         } else {
             SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
-	}
+        }
     }
 }
 
@@ -1065,7 +1110,7 @@ IF_UNDEF_NULL(const char *, target_key)
 {
     /* %typemap(in) (void* callback_data=NULL) */
     if (SvOK($input))
-	saved_env.data = (SV *)$input;
+        saved_env.data = (SV *)$input;
 }
 
 /*
@@ -1105,7 +1150,9 @@ IF_UNDEF_NULL(const char *, target_key)
 {
   /* %typemap(in,numinputs=1) (void *pBuffer, size_t nSize, size_t nCount) */
   size_t len = SvIV($input);
-  $1 = malloc(len);
+  $1 = CPLMalloc(len);
+  if (!$1)
+      SWIG_fail;
   $2 = 1;
   $3 = len;
 }
@@ -1117,6 +1164,7 @@ IF_UNDEF_NULL(const char *, target_key)
   } else {
     $result = &PL_sv_undef;
   }
+  CPLFree($1);
   argvi++;
 }
 %typemap(out) (size_t VSIFReadL)
@@ -1165,3 +1213,42 @@ IF_UNDEF_NULL(const char *, target_key)
   sv_utf8_upgrade($input);
   $1 = SvPV_nolen($input);
 }
+%typemap(in,numinputs=0) (int *pnBytes) (int bytes)
+{
+  /* %typemap(in,numinputs=0) (int *pnBytes) (int bytes) */
+  $1 = &bytes;
+}
+%typemap(out) GByte *
+{
+  /* %typemap(out) GByte * */
+  $result = sv_newmortal();
+  sv_setpvn($result, (const char*)$1, *arg2);
+  CPLFree($1);
+  argvi++;
+}
+
+%typemap(in,numinputs=1) (int object_list_count, GDALRasterBandShadow **poObjects)
+{
+    /* %typemap(in,numinputs=1) (int object_list_count, GDALRasterBandShadow **poObjects) */
+    if (!(SvROK($input) && (SvTYPE(SvRV($input))==SVt_PVAV)))
+        SWIG_croak("Expected a reference to an array of Band objects.");
+    AV *av = (AV*)(SvRV($input));
+    $1 = av_len(av)+1;
+    /* get the pointers from the array into bands */
+    $2 = (GDALRasterBandShadow **)CPLMalloc($1*sizeof(GDALRasterBandShadow *));
+    if ($2) {
+        for (int i = 0; i < $1; i++) {
+            SV **sv = av_fetch(av, i, 0);
+            int ret = SWIG_ConvertPtr(*sv, &($2[i]), SWIGTYPE_p_GDALRasterBandShadow, 0);
+            if (!SWIG_IsOK(ret))
+                SWIG_croak("An item in the argument array is not a Band object.");
+        }
+    } else
+        SWIG_croak("Out of memory.");
+        
+}
+%typemap(freearg) (int object_list_count, GDALRasterBandShadow **poObjects)
+{
+    /* %typemap(freearg) (int object_list_count, GDALRasterBandShadow **poObjects) */
+    CPLFree($2);
+}
diff --git a/swig/include/php/gdal_php.i b/swig/include/php/gdal_php.i
index f80b157..a3ca90b 100644
--- a/swig/include/php/gdal_php.i
+++ b/swig/include/php/gdal_php.i
@@ -1,5 +1,5 @@
 /*
- * $Id: gdal_php.i 8189 2005-09-02 16:19:23Z kruland $
+ * $Id: gdal_php.i 28039 2014-11-30 18:24:59Z rouault $
  *
  * php specific code for gdal bindings.
  */
@@ -7,7 +7,7 @@
 /*
  * $Log$
  * Revision 1.1  2005/09/02 16:19:23  kruland
- * Major reorganization to accomodate multiple language bindings.
+ * Major reorganization to accommodate multiple language bindings.
  * Each language binding can define renames and supplemental code without
  * having to have a lot of conditionals in the main interface definition files.
  *
diff --git a/swig/include/php/ogr_php.i b/swig/include/php/ogr_php.i
index 4e3ccef..699174d 100644
--- a/swig/include/php/ogr_php.i
+++ b/swig/include/php/ogr_php.i
@@ -1,5 +1,5 @@
 /*
- * $Id: ogr_php.i 8189 2005-09-02 16:19:23Z kruland $
+ * $Id: ogr_php.i 28039 2014-11-30 18:24:59Z rouault $
  *
  * php specific code for ogr bindings.
  */
@@ -7,7 +7,7 @@
 /*
  * $Log$
  * Revision 1.1  2005/09/02 16:19:23  kruland
- * Major reorganization to accomodate multiple language bindings.
+ * Major reorganization to accommodate multiple language bindings.
  * Each language binding can define renames and supplemental code without
  * having to have a lot of conditionals in the main interface definition files.
  *
diff --git a/swig/include/python/docs/ogr_datasource_docs.i b/swig/include/python/docs/ogr_datasource_docs.i
index 97440a5..6071242 100644
--- a/swig/include/python/docs/ogr_datasource_docs.i
+++ b/swig/include/python/docs/ogr_datasource_docs.i
@@ -171,7 +171,7 @@ filter. Can be NULL.
 
 pszDialect:  allows control of the statement dialect. If set to NULL,
 the OGR SQL engine will be used, except for RDBMS drivers that will
-use their dedicated SQL engine, unless OGRSQL is explicitely passed as
+use their dedicated SQL engine, unless OGRSQL is explicitly passed as
 the dialect.
 
 an handle to a OGRLayer containing the results of the query.
diff --git a/swig/include/python/gdal_python.i b/swig/include/python/gdal_python.i
index d038360..c3cedf2 100644
--- a/swig/include/python/gdal_python.i
+++ b/swig/include/python/gdal_python.i
@@ -1,5 +1,5 @@
 /*
- * $Id: gdal_python.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: gdal_python.i 28497 2015-02-16 11:31:14Z rouault $
  *
  * python specific code for gdal bindings.
  */
@@ -110,6 +110,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return 0;
     }
@@ -126,6 +127,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return 0;
     }
@@ -148,7 +150,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
 /* -------------------------------------------------------------------- */
 
 %extend GDAL_GCP {
-%pythoncode {
+%pythoncode %{
   def __str__(self):
     str = '%s (%.2fP,%.2fL) -> (%.7fE,%.7fN,%.2f) %s '\
           % (self.Id, self.GCPPixel, self.GCPLine,
@@ -170,26 +172,30 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     if with_Z:
         base.append([CXT_Attribute,'Z',[CXT_Text,zval]])        
     return base
-} /* pythoncode */
+%} /* pythoncode */
 }
 
 %extend GDALRasterBandShadow {
 %apply ( void **outPythonObject ) { (void **buf ) };
 %apply ( int *optional_int ) {(int*)};
+%apply ( GIntBig *optional_GIntBig ) {(GIntBig*)};
 %feature( "kwargs" ) ReadRaster1;
   CPLErr ReadRaster1( int xoff, int yoff, int xsize, int ysize,
                      void **buf,
                      int *buf_xsize = 0,
                      int *buf_ysize = 0,
                      int *buf_type = 0,
-                     int *buf_pixel_space = 0,
-                     int *buf_line_space = 0) {
+                     GIntBig *buf_pixel_space = 0,
+                     GIntBig *buf_line_space = 0,
+                     GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour,
+                     GDALProgressFunc callback = NULL,
+                     void* callback_data=NULL) {
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
     GDALDataType ntype  = (buf_type==0) ? GDALGetRasterDataType(self)
                                         : (GDALDataType)*buf_type;
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
 
     GIntBig buf_size = ComputeBandRasterIOSize( nxsize, nysize, GDALGetDataTypeSize( ntype ) / 8,
                                             pixel_space, line_space, FALSE ); 
@@ -203,6 +209,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -211,14 +218,28 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
     char *data = PyString_AsString( (PyObject *)*buf ); 
 %#endif
-    CPLErr eErr = GDALRasterIO( self, GF_Read, xoff, yoff, xsize, ysize, 
+
+    /* Should we clear the buffer in case there are hole in it ? */
+    if( line_space != 0 && pixel_space != 0 && line_space > pixel_space * nxsize )
+    {
+        memset(data, 0, buf_size);
+    }
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    CPLErr eErr = GDALRasterIOEx( self, GF_Read, xoff, yoff, xsize, ysize, 
                          (void *) data, nxsize, nysize, ntype, 
-                         pixel_space, line_space ); 
+                         pixel_space, line_space, &sExtraArg ); 
     if (eErr == CE_Failure)
     {
         Py_DECREF((PyObject*)*buf);
@@ -228,6 +249,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
   }
 %clear (void **buf );
 %clear (int*);
+%clear (GIntBig*);
 
 %apply ( void **outPythonObject ) { (void **buf ) };
 %feature( "kwargs" ) ReadBlock;
@@ -243,6 +265,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -251,6 +274,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -267,11 +291,14 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
 %clear (void **buf );
 
 
-%pythoncode {
+%pythoncode %{
 
   def ReadRaster(self, xoff = 0, yoff = 0, xsize = None, ysize = None,
                    buf_xsize = None, buf_ysize = None, buf_type = None,
-                   buf_pixel_space = None, buf_line_space = None ):
+                   buf_pixel_space = None, buf_line_space = None,
+                   resample_alg = GRIORA_NearestNeighbour,
+                   callback = None,
+                   callback_data = None):
 
       if xsize is None:
           xsize = self.XSize
@@ -280,20 +307,36 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
 
       return _gdal.Band_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                     buf_xsize, buf_ysize, buf_type,
-                                    buf_pixel_space, buf_line_space)
+                                    buf_pixel_space, buf_line_space,
+                                    resample_alg, callback, callback_data)
 
   def ReadAsArray(self, xoff=0, yoff=0, win_xsize=None, win_ysize=None,
-                  buf_xsize=None, buf_ysize=None, buf_obj=None):
+                  buf_xsize=None, buf_ysize=None, buf_type=None, buf_obj=None,
+                  resample_alg = GRIORA_NearestNeighbour,
+                  callback = None,
+                  callback_data = None):
+      """ Reading a chunk of a GDAL band into a numpy array. The optional (buf_xsize,buf_ysize,buf_type)
+      parameters should generally not be specified if buf_obj is specified. The array is returned"""
+
       import gdalnumeric
 
       return gdalnumeric.BandReadAsArray( self, xoff, yoff,
                                           win_xsize, win_ysize,
-                                          buf_xsize, buf_ysize, buf_obj )
+                                          buf_xsize, buf_ysize, buf_type, buf_obj,
+                                          resample_alg = resample_alg,
+                                          callback = callback,
+                                          callback_data = callback_data)
     
-  def WriteArray(self, array, xoff=0, yoff=0):
+  def WriteArray(self, array, xoff=0, yoff=0,
+                 resample_alg = GRIORA_NearestNeighbour,
+                 callback = None,
+                 callback_data = None):
       import gdalnumeric
 
-      return gdalnumeric.BandWriteArray( self, array, xoff, yoff )
+      return gdalnumeric.BandWriteArray( self, array, xoff, yoff,
+                                         resample_alg = resample_alg,
+                                         callback = callback,
+                                         callback_data = callback_data )
 
   def GetVirtualMemArray(self, eAccess = gdalconst.GF_Read, xoff=0, yoff=0,
                          xsize=None, ysize=None, bufxsize=None, bufysize=None,
@@ -361,7 +404,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
   def __get_array_interface__(self):
       shape = [1, self.XSize, self.YSize]
       
-}
+%}
 }
 
 %extend GDALDatasetShadow {
@@ -370,12 +413,16 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
 %apply (int nList, int *pList ) { (int band_list, int *pband_list ) };
 %apply ( void **outPythonObject ) { (void **buf ) };
 %apply ( int *optional_int ) {(int*)};
+%apply ( GIntBig *optional_GIntBig ) {(GIntBig*)};
 CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
                     void **buf,
                     int *buf_xsize = 0, int *buf_ysize = 0,
                     GDALDataType *buf_type = 0,
                     int band_list = 0, int *pband_list = 0,
-                    int* buf_pixel_space = 0, int* buf_line_space = 0, int* buf_band_space = 0 )
+                    GIntBig* buf_pixel_space = 0, GIntBig* buf_line_space = 0, GIntBig* buf_band_space = 0,
+                    GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour,
+                    GDALProgressFunc callback = NULL,
+                    void* callback_data=NULL )
 {
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
@@ -392,11 +439,12 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
       ntype = GDALGetRasterDataType( GDALGetRasterBand( self, lastband ) );
     }
 
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
-    int band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
 
-    GIntBig buf_size = ComputeDatasetRasterIOSize (nxsize, nysize, GDALGetDataTypeSize( ntype ) / 8,
+    int ntypesize = GDALGetDataTypeSize( ntype ) / 8;
+    GIntBig buf_size = ComputeDatasetRasterIOSize (nxsize, nysize, ntypesize,
                                                band_list ? band_list : GDALGetRasterCount(self), pband_list, band_list,
                                                pixel_space, line_space, band_space, FALSE);
     if (buf_size == 0)
@@ -409,6 +457,7 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
     *buf = (void *)PyBytes_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -417,15 +466,36 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
     char *data = PyString_AsString( (PyObject *)*buf ); 
 %#endif
 
-    CPLErr eErr = GDALDatasetRasterIO(self, GF_Read, xoff, yoff, xsize, ysize,
+    /* Should we clear the buffer in case there are hole in it ? */
+    if( line_space != 0 && pixel_space != 0 && line_space > pixel_space * nxsize )
+    {
+        memset(data, 0, buf_size);
+    }
+    else if( band_list > 1 && band_space != 0 )
+    {
+        if( line_space != 0 && band_space > line_space * nysize )
+            memset(data, 0, buf_size);
+        else if( pixel_space != 0 && band_space < pixel_space &&
+                 pixel_space != GDALGetRasterCount(self) * ntypesize )
+            memset(data, 0, buf_size);
+    }
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+    CPLErr eErr = GDALDatasetRasterIOEx(self, GF_Read, xoff, yoff, xsize, ysize,
                                (void*) data, nxsize, nysize, ntype,
-                               band_list, pband_list, pixel_space, line_space, band_space );
+                               band_list, pband_list, pixel_space, line_space, band_space,
+                               &sExtraArg );
     if (eErr == CE_Failure)
     {
         Py_DECREF((PyObject*)*buf);
@@ -438,11 +508,25 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
 %clear (int band_list, int *pband_list );
 %clear (void **buf );
 %clear (int*);
+%clear (GIntBig*);
+
+%pythoncode %{
+
+    def ReadAsArray(self, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None,
+                    buf_xsize = None, buf_ysize = None, buf_type = None,
+                    resample_alg = GRIORA_NearestNeighbour,
+                    callback = None,
+                    callback_data = None):
+        """ Reading a chunk of a GDAL band into a numpy array. The optional (buf_xsize,buf_ysize,buf_type)
+        parameters should generally not be specified if buf_obj is specified. The array is returned"""
 
-%pythoncode {
-    def ReadAsArray(self, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None ):
         import gdalnumeric
-        return gdalnumeric.DatasetReadAsArray( self, xoff, yoff, xsize, ysize, buf_obj )
+        return gdalnumeric.DatasetReadAsArray( self, xoff, yoff, xsize, ysize, buf_obj,
+                                               buf_xsize, buf_ysize, buf_type,
+                                               resample_alg = resample_alg,
+                                               callback = callback,
+                                               callback_data = callback_data )
+
     def WriteRaster(self, xoff, yoff, xsize, ysize,
                     buf_string,
                     buf_xsize = None, buf_ysize = None, buf_type = None,
@@ -466,7 +550,10 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
     def ReadRaster(self, xoff = 0, yoff = 0, xsize = None, ysize = None,
                    buf_xsize = None, buf_ysize = None, buf_type = None,
                    band_list = None,
-                   buf_pixel_space = None, buf_line_space = None, buf_band_space = None ):
+                   buf_pixel_space = None, buf_line_space = None, buf_band_space = None,
+                   resample_alg = GRIORA_NearestNeighbour,
+                   callback = None,
+                   callback_data = None):
 
         if xsize is None:
             xsize = self.RasterXSize
@@ -484,7 +571,8 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
 
         return _gdal.Dataset_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                             buf_xsize, buf_ysize, buf_type,
-                                            band_list, buf_pixel_space, buf_line_space, buf_band_space )
+                                            band_list, buf_pixel_space, buf_line_space, buf_band_space,
+                                          resample_alg, callback, callback_data )
 
     def GetVirtualMemArray(self, eAccess = gdalconst.GF_Read, xoff=0, yoff=0,
                            xsize=None, ysize=None, bufxsize=None, bufysize=None,
@@ -589,20 +677,42 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
             else:
                 buf_obj = ' ' * nRequiredSize
         return _gdal.Dataset_BeginAsyncReader(self, xoff, yoff, xsize, ysize, buf_obj, buf_xsize, buf_ysize, buf_type, band_list,  0, 0, 0, options)
-}
+
+    def GetLayer(self,iLayer=0):
+        """Return the layer given an index or a name"""
+        if isinstance(iLayer, str):
+            return self.GetLayerByName(str(iLayer))
+        elif isinstance(iLayer, int):
+            return self.GetLayerByIndex(iLayer)
+        else:
+            raise TypeError("Input %s is not of String or Int type" % type(iLayer))
+
+    def DeleteLayer(self, value):
+        """Deletes the layer given an index or layer name"""
+        if isinstance(value, str):
+            for i in range(self.GetLayerCount()):
+                name = self.GetLayer(i).GetName()
+                if name == value:
+                    return _gdal.Dataset_DeleteLayer(self, i)
+            raise ValueError("Layer %s not found to delete" % value)
+        elif isinstance(value, int):
+            return _gdal.Dataset_DeleteLayer(self, value)
+        else:
+            raise TypeError("Input %s is not of String or Int type" % type(value))
+%}
 }
 
 %extend GDALMajorObjectShadow {
-%pythoncode {
+%pythoncode %{
   def GetMetadata( self, domain = '' ):
     if domain[:4] == 'xml:':
       return self.GetMetadata_List( domain )
     return self.GetMetadata_Dict( domain )
-}
+%}
 }
 
 %extend GDALRasterAttributeTableShadow {
-%pythoncode {
+%pythoncode %{
   def WriteArray(self, array, field, start=0):
       import gdalnumeric
 
@@ -612,7 +722,7 @@ CPLErr ReadRaster1(  int xoff, int yoff, int xsize, int ysize,
       import gdalnumeric
 
       return gdalnumeric.RATReadArray(self, field, start, length)
-}
+%}
 }
 
 %include "callback.i"
diff --git a/swig/include/python/ogr_python.i b/swig/include/python/ogr_python.i
index 7c1876c..f52d574 100644
--- a/swig/include/python/ogr_python.i
+++ b/swig/include/python/ogr_python.i
@@ -1,5 +1,5 @@
 /*
- * $Id: ogr_python.i 28298 2015-01-06 09:03:37Z rouault $
+ * $Id: ogr_python.i 28380 2015-01-30 13:42:54Z rouault $
  *
  * python specific code for ogr bindings.
  */
@@ -7,6 +7,7 @@
 
 %feature("autodoc");
 
+#ifndef FROM_GDAL_I
 %init %{
 
   if ( OGRGetDriverCount() == 0 ) {
@@ -14,6 +15,7 @@
   }
   
 %}
+#endif
 
 /*%{
     
@@ -25,8 +27,10 @@
 */
 
 %include "ogr_layer_docs.i"
+#ifndef FROM_GDAL_I
 %include "ogr_datasource_docs.i"
 %include "ogr_driver_docs.i"
+#endif
 %include "ogr_feature_docs.i"
 %include "ogr_featuredef_docs.i"
 %include "ogr_fielddef_docs.i"
@@ -37,6 +41,7 @@
 %rename (SetGenerate_DB2_V72_BYTE_ORDER) OGRSetGenerate_DB2_V72_BYTE_ORDER;
 %rename (RegisterAll) OGRRegisterAll();
 
+#ifndef FROM_GDAL_I
 %include "python_exceptions.i"
 %include "python_strings.i"
 
@@ -110,6 +115,9 @@ ds[0:4] would return a list of the first four layers."""
   }
 }
 
+#endif
+
+
 %extend OGRLayerShadow {
   %pythoncode %{
     def Reference(self):
@@ -188,6 +196,13 @@ layer[0:4] would return a list of the first four features."""
 }
 
 %extend OGRFeatureShadow {
+
+  %apply ( const char *utf8_path ) { (const char* value) };
+  void SetFieldString(int id, const char* value) {
+    OGR_F_SetFieldString(self, id, value);
+  }
+  %clear (const char* value );
+  
   %pythoncode %{
     def Reference(self):
       pass
@@ -281,18 +296,57 @@ layer[0:4] would return a list of the first four features."""
         fld_type = self.GetFieldType(fld_index)
         if fld_type == OFTInteger:
             return self.GetFieldAsInteger(fld_index)
+        if fld_type == OFTInteger64:
+            return self.GetFieldAsInteger64(fld_index)
         if fld_type == OFTReal:
             return self.GetFieldAsDouble(fld_index)
         if fld_type == OFTStringList:
             return self.GetFieldAsStringList(fld_index)
         if fld_type == OFTIntegerList:
             return self.GetFieldAsIntegerList(fld_index)
+        if fld_type == OFTInteger64List:
+            return self.GetFieldAsInteger64List(fld_index)
         if fld_type == OFTRealList:
             return self.GetFieldAsDoubleList(fld_index)
         ## if fld_type == OFTDateTime or fld_type == OFTDate or fld_type == OFTTime:
         #     return self.GetFieldAsDate(fld_index)
         # default to returning as a string.  Should we add more types?
-        return self.GetFieldAsString(fld_index)
+        try:
+            return self.GetFieldAsString(fld_index)
+        except:
+            # For Python3 on non-UTF8 strings
+            return self.GetFieldAsBinary(fld_index)
+
+    # With several override, SWIG cannot dispatch automatically unicode strings
+    # to the right implementation, so we have to do it at hand
+    def SetField(self, *args):
+        """
+        SetField(self, int id, char value)
+        SetField(self, char name, char value)
+        SetField(self, int id, int value)
+        SetField(self, char name, int value)
+        SetField(self, int id, double value)
+        SetField(self, char name, double value)
+        SetField(self, int id, int year, int month, int day, int hour, int minute, 
+            int second, int tzflag)
+        SetField(self, char name, int year, int month, int day, int hour, 
+            int minute, int second, int tzflag)
+        """
+
+        if len(args) == 2 and (type(args[1]) == type(1) or type(args[1]) == type(12345678901234)):
+            fld_index = args[0]
+            if isinstance(fld_index, str):
+                fld_index = self.GetFieldIndex(fld_index)
+            return _ogr.Feature_SetFieldInteger64(self, fld_index, args[1])
+
+
+        if len(args) == 2 and str(type(args[1])) == "<type 'unicode'>":
+            fld_index = args[0]
+            if isinstance(fld_index, str):
+                fld_index = self.GetFieldIndex(fld_index)
+            return _ogr.Feature_SetFieldString(self, fld_index, args[1])
+
+        return _ogr.Feature_SetField(self, *args)
 
     def SetField2(self, fld_index, value):
         if isinstance(fld_index, str):
@@ -308,8 +362,8 @@ layer[0:4] would return a list of the first four features."""
             if len(value) == 0:
                 self.UnsetField( fld_index )
                 return
-            if isinstance(value[0],int):
-                self.SetFieldIntegerList(fld_index,value)
+            if isinstance(value[0],type(1)) or isinstance(value[0],type(12345678901234)):
+                self.SetFieldInteger64List(fld_index,value)
                 return
             elif isinstance(value[0],float):
                 self.SetFieldDoubleList(fld_index,value)
@@ -318,7 +372,7 @@ layer[0:4] would return a list of the first four features."""
                 self.SetFieldStringList(fld_index,value)
                 return
             else:
-                raise TypeError( 'Unsupported type of list in SetField2()' )
+                raise TypeError( 'Unsupported type of list in SetField2(). Type of element is %s' % str(type(value[0])) )
 
         try:
             self.SetField( fld_index, value )
@@ -459,4 +513,95 @@ layer[0:4] would return a list of the first four features."""
 
 %import typemaps_python.i
 
+#ifndef FROM_GDAL_I
 %include "callback.i"
+
+
+%extend GDALMajorObjectShadow {
+%pythoncode %{
+  def GetMetadata( self, domain = '' ):
+    if domain[:4] == 'xml:':
+      return self.GetMetadata_List( domain )
+    return self.GetMetadata_Dict( domain )
+%}
+}
+#endif
+
+
+%pythoncode %{
+
+# Backup original dictionnary before doing anything else
+_initial_dict = globals().copy()
+
+ at property
+def wkb25Bit(module):
+    import warnings
+    warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning)
+    return module._initial_dict['wkb25DBit']
+
+ at property
+def wkb25DBit(module):
+    import warnings
+    warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning)
+    return module._initial_dict['wkb25DBit']
+
+# Inspired from http://www.dr-josiah.com/2013/12/properties-on-python-modules.html
+class _Module(object):
+    def __init__(self):
+        self.__dict__ = globals()
+        self._initial_dict = _initial_dict
+
+        # Transfer properties from the object to the Class
+        for k, v in list(self.__dict__.items()):
+            if isinstance(v, property):
+                setattr(self.__class__, k, v)
+                #del self.__dict__[k]
+
+        # Replace original module by our object
+        import sys
+        self._original_module = sys.modules[self.__name__]
+        sys.modules[self.__name__] = self
+
+# Custom help() replacement to display the help of the original module
+# instead of the one of our instance object
+class _MyHelper(object):
+
+    def __init__(self, module):
+        self.module = module
+        self.original_help = help
+
+        # Replace builtin help by ours
+        try:
+            import __builtin__ as builtins # Python 2
+        except ImportError:
+            import builtins # Python 3
+        builtins.help = self
+
+    def __repr__(self):
+        return self.original_help.__repr__()
+
+    def __call__(self, *args, **kwds):
+
+        if args == (self.module,):
+            import sys
+
+            # Restore original module before calling help() otherwise
+            # we don't get methods or classes mentionned
+            sys.modules[self.module.__name__] = self.module._original_module
+
+            ret = self.original_help(self.module._original_module, **kwds)
+
+            # Reinstall our module
+            sys.modules[self.module.__name__] = self.module
+
+            return ret
+        elif args == (self,):
+            return self.original_help(self.original_help, **kwds)
+        else:
+            return self.original_help(*args, **kwds)
+
+_MyHelper(_Module())
+del _MyHelper
+del _Module
+
+%}
diff --git a/swig/include/python/osr_python.i b/swig/include/python/osr_python.i
index f72a505..4f14524 100644
--- a/swig/include/python/osr_python.i
+++ b/swig/include/python/osr_python.i
@@ -1,5 +1,5 @@
 /*
- * $Id: osr_python.i 18192 2009-12-06 19:41:32Z rouault $
+ * $Id: osr_python.i 27384 2014-05-24 12:28:12Z rouault $
  *
  * python specific code for ogr bindings.
  */
@@ -7,8 +7,10 @@
 
 %feature("autodoc");
 
+#ifndef FROM_GDAL_I
 %include "python_exceptions.i"
 %include "python_strings.i"
+#endif
 
 %{
 static PyObject *
diff --git a/swig/include/python/python_exceptions.i b/swig/include/python/python_exceptions.i
index 5d22cfe..ed2964f 100644
--- a/swig/include/python/python_exceptions.i
+++ b/swig/include/python/python_exceptions.i
@@ -11,7 +11,7 @@ void CPL_STDCALL
 PythonBindingErrorHandler(CPLErr eclass, int code, const char *msg ) 
 {
   /* 
-  ** Generally we want to supress error reporting if we have exceptions
+  ** Generally we want to suppress error reporting if we have exceptions
   ** enabled as the error message will be in the exception thrown in 
   ** Python.  
   */
diff --git a/swig/include/python/typemaps_python.i b/swig/include/python/typemaps_python.i
index 1f5098e..8a916d6 100644
--- a/swig/include/python/typemaps_python.i
+++ b/swig/include/python/typemaps_python.i
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: typemaps_python.i 26832 2014-01-15 12:46:08Z rouault $
+ * $Id: typemaps_python.i 28899 2015-04-14 09:27:00Z rouault $
  *
  * Name:     typemaps_python.i
  * Project:  GDAL Python Interface
@@ -24,7 +24,7 @@
 
 %apply (double *OUTPUT) { double *argout };
 
-%typemap(in) GIntBig bigint
+%typemap(in) GIntBig
 {
     PY_LONG_LONG val;
     if ( !PyArg_Parse($input,"L",&val) ) {
@@ -34,7 +34,7 @@
     $1 = (GIntBig)val;
 }
 
-%typemap(out) GIntBig bigint
+%typemap(out) GIntBig
 {
     char szTmp[32];
     sprintf(szTmp, CPL_FRMT_GIB, $1);
@@ -276,6 +276,74 @@ CreateTupleFromDoubleArray( double *first, unsigned int size ) {
 }
 
 /*
+ *  Typemap for counted arrays of GIntBig <- PySequence
+ */
+%typemap(in,numinputs=1) (int nList, GIntBig* pList)
+{
+  /* %typemap(in,numinputs=1) (int nList, GIntBig* pList)*/
+  /* check if is List */
+  if ( !PySequence_Check($input) ) {
+    PyErr_SetString(PyExc_TypeError, "not a sequence");
+    SWIG_fail;
+  }
+  $1 = PySequence_Size($input);
+  $2 = (GIntBig*) malloc($1*sizeof(GIntBig));
+  for( int i = 0; i<$1; i++ ) {
+    PyObject *o = PySequence_GetItem($input,i);
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(o,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      Py_DECREF(o);
+      SWIG_fail;
+    }
+    $2[i] = (GIntBig)val;
+    Py_DECREF(o);
+  }
+}
+
+%typemap(freearg) (int nList, GIntBig* pList)
+{
+  /* %typemap(freearg) (int nList, GIntBig* pList) */
+  if ($2) {
+    free((void*) $2);
+  }
+}
+
+/*
+ *  Typemap for counted arrays of GUIntBig <- PySequence
+ */
+%typemap(in,numinputs=1) (int nList, GUIntBig* pList)
+{
+  /* %typemap(in,numinputs=1) (int nList, GUIntBig* pList)*/
+  /* check if is List */
+  if ( !PySequence_Check($input) ) {
+    PyErr_SetString(PyExc_TypeError, "not a sequence");
+    SWIG_fail;
+  }
+  $1 = PySequence_Size($input);
+  $2 = (GUIntBig*) malloc($1*sizeof(GUIntBig));
+  for( int i = 0; i<$1; i++ ) {
+    PyObject *o = PySequence_GetItem($input,i);
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(o,"K",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      Py_DECREF(o);
+      SWIG_fail;
+    }
+    $2[i] = (GUIntBig)val;
+    Py_DECREF(o);
+  }
+}
+
+%typemap(freearg) (int nList, GUIntBig* pList)
+{
+  /* %typemap(freearg) (int nList, GUIntBig* pList) */
+  if ($2) {
+    free((void*) $2);
+  }
+}
+
+/*
  *  Typemap for counted arrays of doubles <- PySequence
  */
 %typemap(in,numinputs=1) (int nList, double* pList)
@@ -532,6 +600,64 @@ CreateTupleFromDoubleArray( int *first, unsigned int size ) {
 }
 
 /*
+ * Typemap argout used in Feature::GetFieldAsInteger64List()
+ */
+%typemap(in,numinputs=0) (int *nLen, const GIntBig **pList) (int nLen, GIntBig *pList)
+{
+  /* %typemap(in,numinputs=0) (int *nLen, const GIntBig **pList) (int nLen, GIntBig *pList) */
+  $1 = &nLen;
+  $2 = &pList;
+}
+
+%typemap(argout) (int *nLen, const GIntBig **pList )
+{
+  /* %typemap(argout) (int *nLen, const GIntBig **pList ) */
+  Py_DECREF($result);
+  PyObject *out = PyList_New( *$1 );
+  for( int i=0; i<*$1; i++ ) {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, (*$2)[i]);
+    PyObject* val;
+%#if PY_VERSION_HEX>=0x03000000
+    val = PyLong_FromString(szTmp, NULL, 10);
+%#else
+    val = PyInt_FromString(szTmp, NULL, 10);
+%#endif
+    PyList_SetItem( out, i, val );
+  }
+  $result = out;
+}
+
+/*
+ * Typemap argout used in Feature::GetFieldAsInteger64List()
+ */
+%typemap(in,numinputs=0) (int *nLen, const GIntBig **pList) (int nLen, GIntBig *pList)
+{
+  /* %typemap(in,numinputs=0) (int *nLen, const GIntBig **pList) (int nLen, GIntBig *pList) */
+  $1 = &nLen;
+  $2 = &pList;
+}
+
+%typemap(argout) (int *nLen, const GIntBig **pList )
+{
+  /* %typemap(argout) (int *nLen, const GIntBig **pList ) */
+  Py_DECREF($result);
+  PyObject *out = PyList_New( *$1 );
+  for( int i=0; i<*$1; i++ ) {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, (*$2)[i]);
+    PyObject* val;
+%#if PY_VERSION_HEX>=0x03000000
+    val = PyLong_FromString(szTmp, NULL, 10);
+%#else
+    val = PyInt_FromString(szTmp, NULL, 10);
+%#endif
+    PyList_SetItem( out, i, val );
+  }
+  $result = out;
+}
+
+/*
  * Typemap argout used in Feature::GetFieldAsDoubleList()
  */
 %typemap(in,numinputs=0) (int *nLen, const double **pList) (int nLen, double *pList)
@@ -685,7 +811,7 @@ CreateTupleFromDoubleArray( int *first, unsigned int size ) {
 %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) (char **dict)
 {
   /* %typecheck(SWIG_TYPECHECK_POINTER) (char **dict) */
-  /* Note: we exclude explicitely strings, because they can be considered as a sequence of characters, */
+  /* Note: we exclude explicitly strings, because they can be considered as a sequence of characters, */
   /* which is not desirable since it makes it impossible to define bindings such as SetMetadata(string) and SetMetadata(array_of_string) */
   /* (see #4816) */
   $1 = ((PyMapping_Check($input) || PySequence_Check($input) ) && !SWIG_CheckState(SWIG_AsCharPtrAndSize($input, 0, NULL, 0)) ) ? 1 : 0;
@@ -697,14 +823,16 @@ CreateTupleFromDoubleArray( int *first, unsigned int size ) {
   if ( PySequence_Check( $input ) ) {
     int size = PySequence_Size($input);
     for (int i = 0; i < size; i++) {
-      char *pszItem = NULL;
       PyObject* pyObj = PySequence_GetItem($input,i);
-      if ( ! PyArg_Parse( pyObj, "s", &pszItem ) ) {
+      int bFreeStr;
+      char* pszStr = GDALPythonObjectToCStr(pyObj, &bFreeStr);
+      if ( pszStr == NULL ) {
           Py_DECREF(pyObj);
           PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
           SWIG_fail;
       }
-      $1 = CSLAddString( $1, pszItem );
+      $1 = CSLAddString( $1, pszStr );
+      GDALPythonFreeCStr(pszStr, bFreeStr);
       Py_DECREF(pyObj);
     }
   }
@@ -715,14 +843,29 @@ CreateTupleFromDoubleArray( int *first, unsigned int size ) {
       PyObject *item_list = PyMapping_Items( $input );
       for( int i=0; i<size; i++ ) {
         PyObject *it = PySequence_GetItem( item_list, i );
-        char *nm;
-        char *val;
-        if ( ! PyArg_ParseTuple( it, "ss", &nm, &val ) ) {
+
+        PyObject *k, *v;
+        if ( ! PyArg_ParseTuple( it, "OO", &k, &v ) ) {
           Py_DECREF(it);
           PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
           SWIG_fail;
         }
-        $1 = CSLAddNameValue( $1, nm, val );
+
+        int bFreeK, bFreeV;
+        char* pszK = GDALPythonObjectToCStr(k, &bFreeK);
+        char* pszV = GDALPythonObjectToCStr(v, &bFreeV);
+        if( pszK == NULL || pszV == NULL )
+        {
+            GDALPythonFreeCStr(pszK, bFreeK);
+            GDALPythonFreeCStr(pszV, bFreeV);
+            Py_DECREF(it);
+            PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
+            SWIG_fail;
+        }
+         $1 = CSLAddNameValue( $1, pszK, pszV );
+
+        GDALPythonFreeCStr(pszK, bFreeK);
+        GDALPythonFreeCStr(pszV, bFreeV);
         Py_DECREF(it);
       }
       Py_DECREF(item_list);
@@ -910,6 +1053,7 @@ CreateTupleFromDoubleArray( int *first, unsigned int size ) {
 %enddef
 
 OPTIONAL_POD(int,i);
+OPTIONAL_POD(GIntBig,L);
 
 /*
  * Typedef const char * <- Any object.
@@ -1040,6 +1184,9 @@ static PyObject *XMLTreeToPyList( CPLXMLNode *psTree )
     int      nChildCount = 0, iChild;
     CPLXMLNode *psChild;
 
+    if( psTree == NULL )
+        return Py_None;
+
     for( psChild = psTree->psChild; 
          psChild != NULL; 
          psChild = psChild->psNext )
@@ -1291,26 +1438,26 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
  * a list object. 
  */
 
-%typemap(arginit) (int buckets, int* panHistogram)
+%typemap(arginit) (int buckets, GUIntBig* panHistogram)
 {
-  /* %typemap(in) int buckets, int* panHistogram -> list */
-  $2 = (int *) VSICalloc(sizeof(int),$1);
+  /* %typemap(in) int buckets, GUIntBig* panHistogram -> list */
+  $2 = (GUIntBig *) VSICalloc(sizeof(GUIntBig),$1);
 }
 
-%typemap(in, numinputs=1) (int buckets, int* panHistogram)
+%typemap(in, numinputs=1) (int buckets, GUIntBig* panHistogram)
 {
-  /* %typemap(in) int buckets, int* panHistogram -> list */
+  /* %typemap(in) int buckets, GUIntBig* panHistogram -> list */
   int requested_buckets = 0;
   SWIG_AsVal_int($input, &requested_buckets);
   if( requested_buckets != $1 )
   {
     $1 = requested_buckets;
-    if (requested_buckets <= 0 || requested_buckets > (int)(INT_MAX / sizeof(int)))
+    if (requested_buckets <= 0 || requested_buckets > (int)(INT_MAX / sizeof(GUIntBig)))
     {
         PyErr_SetString( PyExc_RuntimeError, "Bad value for buckets" );
         SWIG_fail;
     }
-    $2 = (int *) VSIRealloc($2, sizeof(int) * requested_buckets);
+    $2 = (GUIntBig *) VSIRealloc($2, sizeof(GUIntBig) * requested_buckets);
   }
   if ($2 == NULL)
   {
@@ -1319,18 +1466,18 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
   }
 }
 
-%typemap(freearg)  (int buckets, int* panHistogram)
+%typemap(freearg)  (int buckets, GUIntBig* panHistogram)
 {
-  /* %typemap(freearg) (int buckets, int* panHistogram)*/
+  /* %typemap(freearg) (int buckets, GUIntBig* panHistogram)*/
   if ( $2 ) {
     VSIFree( $2 );
   }
 }
 
-%typemap(argout) (int buckets, int* panHistogram)
+%typemap(argout) (int buckets, GUIntBig* panHistogram)
 {
-  /* %typemap(out) int buckets, int* panHistogram -> list */
-  int *integerarray = $2;
+  /* %typemap(out) int buckets, GUIntBig* panHistogram -> list */
+  GUIntBig *integerarray = $2;
   if ( integerarray == NULL ) {
     $result = Py_None;
     Py_INCREF( $result );
@@ -1338,7 +1485,13 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
   else {
     $result = PyList_New( $1 );
     for ( int i = 0; i < $1; ++i ) {
-      PyObject *o =  PyInt_FromLong( integerarray[i] );
+      char szTmp[32];
+      sprintf(szTmp, CPL_FRMT_GUIB, integerarray[i]);
+%#if PY_VERSION_HEX>=0x03000000
+      PyObject *o = PyLong_FromString(szTmp, NULL, 10);
+%#else
+      PyObject *o =  PyInt_FromString(szTmp, NULL, 10);
+%#endif
       PyList_SetItem($result, i, o );
     }
   }
@@ -1348,11 +1501,11 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
  *                       GetDefaultHistogram()
  */
 
-%typemap(arginit, noblock=1) (double *min_ret, double *max_ret, int *buckets_ret, int **ppanHistogram)
+%typemap(arginit, noblock=1) (double *min_ret, double *max_ret, int *buckets_ret, GUIntBig **ppanHistogram)
 {
    double min_val, max_val;
    int buckets_val;
-   int *panHistogram;
+   GUIntBig *panHistogram;
 
    $1 = &min_val;
    $2 = &max_val;
@@ -1360,7 +1513,7 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
    $4 = &panHistogram;
 }
 
-%typemap(argout) (double *min_ret, double *max_ret, int *buckets_ret, int** ppanHistogram)
+%typemap(argout) (double *min_ret, double *max_ret, int *buckets_ret, GUIntBig** ppanHistogram)
 {
   int i;
   PyObject *psList = NULL;
@@ -1371,7 +1524,7 @@ OBJECT_LIST_INPUT(GDALRasterBandShadow);
   {
       psList = PyList_New(buckets_val);
       for( i = 0; i < buckets_val; i++ )
-        PyList_SetItem(psList, i, Py_BuildValue("i", panHistogram[i] ));
+        PyList_SetItem(psList, i, Py_BuildValue("K", panHistogram[i] ));
 
       CPLFree( panHistogram );
 
diff --git a/swig/include/ruby/gdal_ruby.i b/swig/include/ruby/gdal_ruby.i
index e49b49e..f4fd5bf 100644
--- a/swig/include/ruby/gdal_ruby.i
+++ b/swig/include/ruby/gdal_ruby.i
@@ -1,5 +1,5 @@
 /*
- * $Id: gdal_ruby.i 21964 2011-03-17 14:00:08Z warmerdam $
+ * $Id: gdal_ruby.i 28039 2014-11-30 18:24:59Z rouault $
  *
  * ruby specific code for gdal bindings.
  */
@@ -10,7 +10,7 @@
  * Copied over code from the Python version of gdal_ruby.i.  Will have to port the code to Ruby.
  *
  * Revision 1.1  2005/09/02 16:19:23  kruland
- * Major reorganization to accomodate multiple language bindings.
+ * Major reorganization to accommodate multiple language bindings.
  * Each language binding can define renames and supplemental code without
  * having to have a lot of conditionals in the main interface definition files.
  *
diff --git a/swig/include/ruby/ogr_ruby.i b/swig/include/ruby/ogr_ruby.i
index cdbea76..3a69c23 100644
--- a/swig/include/ruby/ogr_ruby.i
+++ b/swig/include/ruby/ogr_ruby.i
@@ -1,5 +1,5 @@
 /*
- * $Id: ogr_ruby.i 9022 2006-01-17 04:42:16Z cfis $
+ * $Id: ogr_ruby.i 28039 2014-11-30 18:24:59Z rouault $
  *
  * ruby specific code for ogr bindings.
  */
@@ -16,7 +16,7 @@
  * Added support for exceptions, removed some outdated code.
  *
  * Revision 1.1  2005/09/02 16:19:23  kruland
- * Major reorganization to accomodate multiple language bindings.
+ * Major reorganization to accommodate multiple language bindings.
  * Each language binding can define renames and supplemental code without
  * having to have a lot of conditionals in the main interface definition files.
  *
diff --git a/swig/include/ruby/typemaps_ruby.i b/swig/include/ruby/typemaps_ruby.i
index ea5f84d..ec1ec33 100644
--- a/swig/include/ruby/typemaps_ruby.i
+++ b/swig/include/ruby/typemaps_ruby.i
@@ -1,6 +1,6 @@
 
 /******************************************************************************
- * $Id: typemaps_ruby.i 21964 2011-03-17 14:00:08Z warmerdam $
+ * $Id: typemaps_ruby.i 28039 2014-11-30 18:24:59Z rouault $
  *
  * Name:     typemaps_ruby.i
  * Project:  GDAL Ruby Interface
@@ -39,7 +39,7 @@
  * Significantly updated typemaps for Ruby - resynced with the Python typemaps file.
  *
  * Revision 1.5  2005/09/02 16:19:23  kruland
- * Major reorganization to accomodate multiple language bindings.
+ * Major reorganization to accommodate multiple language bindings.
  * Each language binding can define renames and supplemental code without
  * having to have a lot of conditionals in the main interface definition files.
  *
diff --git a/swig/java/apps/gdalinfo.java b/swig/java/apps/gdalinfo.java
index 85394f0..4dda025 100644
--- a/swig/java/apps/gdalinfo.java
+++ b/swig/java/apps/gdalinfo.java
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: gdalinfo.java 25229 2012-11-16 19:06:58Z rouault $
+ * $Id: gdalinfo.java 28051 2014-12-03 18:59:00Z goatbar $
  *
  * Name:     gdalinfo.java
  * Project:  GDAL SWIG Interface
@@ -74,7 +74,7 @@ public class gdalinfo {
 			double[] adfGeoTransform = new double[6];
 			Driver hDriver;
 			Vector papszMetadata;
-			boolean bComputeMinMax = false, bSample = false;
+			boolean bComputeMinMax = false /* , bSample = false */;
 			boolean bShowGCPs = true, bShowMetadata = true;
 			boolean bStats = false, bApproxStats = true;
                         boolean bShowColorTable = true, bComputeChecksum = false;
diff --git a/swig/java/apps/ogrtindex.java b/swig/java/apps/ogrtindex.java
index 31c3e89..d9a73f8 100644
--- a/swig/java/apps/ogrtindex.java
+++ b/swig/java/apps/ogrtindex.java
@@ -1,5 +1,5 @@
 /******************************************************************************
- * $Id: ogrtindex.java 23738 2012-01-09 19:40:54Z rouault $
+ * $Id: ogrtindex.java 28375 2015-01-30 12:06:11Z rouault $
  *
  * Project:  OpenGIS Simple Features Reference Implementation
  * Purpose:  Program to generate a UMN MapServer compatible tile index for a
@@ -250,7 +250,7 @@ public class ogrtindex {
       String[] existingLayersTab = null;
       SpatialReference alreadyExistingSpatialRef = null;
       boolean alreadyExistingSpatialRefValid = false;
-      nExistingLayers = poDstLayer.GetFeatureCount();
+      nExistingLayers = (int)poDstLayer.GetFeatureCount();
       if (nExistingLayers > 0)
       {
          existingLayersTab = new String[nExistingLayers];
diff --git a/swig/java/build.xml b/swig/java/build.xml
index fcc9ecb..6e0be1e 100644
--- a/swig/java/build.xml
+++ b/swig/java/build.xml
@@ -2,8 +2,20 @@
 <project name="gdal" default="all">
 
 	<description>Builds the Java SWIG bindings-proxy classes for GDAL/OGR</description>
+
 	
-	<target name="compile" description="Compile the source files.">
+	<target name="init" description="Initialize, reading version info">
+		<loadfile property="version" srcFile="${basedir}/../../VERSION">
+			<filterchain>
+				<striplinebreaks/>
+			</filterchain>
+		</loadfile>
+		<echo message="version = ${version}"/>
+		<property name="mvn.dir" value="build/maven"/>
+		<property name="mvn.base" value="gdal-${version}"/>
+	</target>
+
+	<target name="compile" depends="init" description="Compile the source files.">
 		<mkdir dir="build/classes"/>
 		<javac srcdir="org" destdir="build/classes" 
 		       debug="on" source="1.4" target="1.4"
@@ -32,6 +44,62 @@
         <target name="all" depends="compile_tests" description="Build a jar and test apps.">
         </target>
 
+        <target name="maven" depends="compile_tests" description="Build maven artifacts">
+		<mkdir dir="${mvn.dir}"/>
+
+		<!-- run the javadoc generation -->
+		<exec executable="./make_doc.sh"/>
+
+		<!-- copy over pom -->
+		<copy file="pom.xml" filtering="true"
+		      tofile="${mvn.dir}/${mvn.base}.pom">
+			<filterset>
+				<filter token="VERSION" value="${version}"/>
+			</filterset>
+		</copy>
+
+		<!-- copy over main jar, javadoc jar, and source jar -->
+		<copy file="gdal.jar" tofile="${mvn.dir}/${mvn.base}.jar"/>
+		<jar destfile="${mvn.dir}/${mvn.base}-javadoc.jar" basedir="java"/>
+		<jar destfile="${mvn.dir}/${mvn.base}-sources.jar" basedir="."
+		     includes="org/**/*.java"/>
+
+        </target>
+
+
+        <target name="maven_sign" depends="maven"
+		description="GPG signs maven artifacts">
+
+		<!-- sign all artifacts -->
+		<antcall target="sign_file">
+			<param name="file" value="${mvn.dir}/${mvn.base}.pom"/>
+		</antcall>
+		<antcall target="sign_file">
+			<param name="file" value="${mvn.dir}/${mvn.base}.jar"/>
+		</antcall>
+		<antcall target="sign_file">
+			<param name="file" value="${mvn.dir}/${mvn.base}-javadoc.jar"/>
+		</antcall>
+		<antcall target="sign_file">
+			<param name="file" value="${mvn.dir}/${mvn.base}-sources.jar"/>
+		</antcall>
+
+		<!-- bundle into single jar for deployment -->
+		<delete file="${mvn.dir}/bundle.jar"/>
+		<jar destfile="${mvn.dir}/bundle.jar" basedir="${mvn.dir}"
+		     includes="${mvn.base}*"/>
+        </target>
+
+	<target name="sign_file" description="Helper target to gpg sign a file">
+		<fail unless="gpg.key" message="system property gpg.key required"/>
+		<condition property="pass" value="--passphrase ${gpg.pass}"
+			else="">
+			<isset property="gpg.pass"/>
+		</condition>
+		<exec executable="gpg">
+			<arg line="-u ${gpg.key} ${pass} -ab ${file}"/>
+		</exec>
+	</target>
 	<target name="clean" description="Clean up old files.">
 		<delete dir="build"/>
 	</target>
diff --git a/swig/java/javadoc.java b/swig/java/javadoc.java
index f3f190d..18e3c7e 100644
--- a/swig/java/javadoc.java
+++ b/swig/java/javadoc.java
@@ -1,5 +1,5 @@
 /* ***************************************************************************
-* $Id: javadoc.java 25687 2013-02-25 17:41:30Z rouault $
+* $Id: javadoc.java 28785 2015-03-26 20:46:45Z goatbar $
 *
 * Project:  GDAL/OGR Java bindings
 * Purpose:  Documentation for the Java bindings
@@ -195,7 +195,7 @@ public class gdal:public static int SetErrorHandler()
  * <p>
  * The default behaviour of Error() is to report errors to stderr,
  * and to abort() after reporting a gdalconst.CE_Fatal error.  It is expected that
- * some applications will want to supress error reporting, and will want to
+ * some applications will want to suppress error reporting, and will want to
  * install a C++ exception, or longjmp() approach to no local fatal error
  * recovery.
  * <p>
@@ -1336,7 +1336,7 @@ public class gdal:public static Driver GetDriver(int iDriver)
  * The first successful open will result in a returned dataset.  If all
  * drivers fail then null is returned.
  * <p>
- * It is required that you explicitely close a dataset opened in update
+ * It is required that you explicitly close a dataset opened in update
  * mode with the Dataset.delete() method. Otherwise the data might not be
  * flushed to the disk. Don't rely only on Java garbage collection.
  *
@@ -2235,7 +2235,7 @@ public class Dataset:public int ReadRaster_Direct(int xoff, int yoff, int xsize,
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Byte">gdalconstConstants.GDT_Byte</a>,
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Int16">gdalconstConstants.GDT_Int16</a>, ...
  * The pixel values will automatically be translated to/from the Band
- * data type as needed. The GDAL type must be consistant with the type of the Java array.
+ * data type as needed. The GDAL type must be consistent with the type of the Java array.
  *
  * @param array The array into which the data will be written. This buffer must contain at least
  * buf_xsize * buf_ysize elements * nBandCount .  It is organized
@@ -2496,7 +2496,7 @@ public class Dataset:public int WriteRaster_Direct(int xoff, int yoff, int xsize
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Byte">gdalconstConstants.GDT_Byte</a>,
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Int16">gdalconstConstants.GDT_Int16</a>, ...
  * The pixel values will automatically be translated to/from the Band
- * data type as needed. The GDAL type must be consistant with the type of the Java array.
+ * data type as needed. The GDAL type must be consistent with the type of the Java array.
  *
  * @param array The array from which the data will be read. This buffer must contain at least
  * buf_xsize * buf_ysize elements * nBandCount .  It is organized
@@ -3357,7 +3357,7 @@ public class Band:public int GetRasterDataType()
  * but no warning will have been issued.   This is a non-standard use of
  * the CE_Warning return value to indicate "nothing done". 
  * <p>
- * Note that file formats using PAM (Persistent Auxilary Metadata) services
+ * Note that file formats using PAM (Persistent Auxiliary Metadata) services
  * will generally cache statistics in the .pam file allowing fast fetch
  * after the first request. 
  *
@@ -3639,7 +3639,7 @@ public class Band:public java.nio.ByteBuffer ReadRaster_Direct(int xoff, int yof
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Byte">gdalconstConstants.GDT_Byte</a>,
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Int16">gdalconstConstants.GDT_Int16</a>, ...
  * The pixel values will automatically be translated to/from the Band
- * data type as needed. The GDAL type must be consistant with the type of the Java array.
+ * data type as needed. The GDAL type must be consistent with the type of the Java array.
  *
  * @param array The buffer into which the data should be read.
  * This buffer must contain at least buf_xsize *
@@ -4045,7 +4045,7 @@ public class Band:public int WriteRaster_Direct(int xoff, int yoff, int xsize, i
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Byte">gdalconstConstants.GDT_Byte</a>,
  * <a href="../gdalconst/gdalconstConstants.html#GDT_Int16">gdalconstConstants.GDT_Int16</a>, ...
  * The pixel values will automatically be translated to/from the Band
- * data type as needed. The GDAL type must be consistant with the type of the Java array.
+ * data type as needed. The GDAL type must be consistent with the type of the Java array.
  *
  * @param array The buffer into which the data should be read.
  * This buffer must contain at least buf_xsize *
@@ -5062,7 +5062,7 @@ public class org.gdal.gdal.Driver:public String getHelpTopic()
   * Class used to report progression of long operations.
   * <p>
   * This class will not do anything by itself, but it can be subclassed, like <a href="TermProgressCallback.html">TermProgressCallback</a> class.
-  * to do more usefull things.
+  * to do more useful things.
   *
   * @since Java bindings 1.7.0
   */
@@ -6718,7 +6718,7 @@ public class Layer:public double[] GetExtent()
  @return 0 on success. Otherwise throws a RuntimeException (or an error code if DontUseExceptions() has been called).
 
 */
-public class Layer:public int DeleteFeature(int fid)
+public class Layer:public int DeleteFeature(long fid)
 
 /**
  Fetch a feature by its identifier.
@@ -6738,14 +6738,14 @@ public class Layer:public int DeleteFeature(int fid)
  Sequential reads are generally considered interrupted by a GetFeature() call.
  <p>
  The returned feature will be properly handled by the Java garbage collector,
- but you can help it by explicitely calling the
+ but you can help it by explicitly calling the
  Feature.<a href="Feature.html#delete()">delete()</a> method.
 
  @param fid the feature id of the feature to read. 
 
  @return a feature, or null on failure. 
 */
-public class Layer:public Feature GetFeature(int fid)
+public class Layer:public Feature GetFeature(long fid)
 
 /**
  Fetch the feature count in this layer. 
@@ -6763,7 +6763,7 @@ public class Layer:public Feature GetFeature(int fid)
 
  @return feature count, -1 if count not known. 
 */
-public class Layer:public int GetFeatureCount(int force)
+public class Layer:public long GetFeatureCount(int force)
 
 /**
   * Fetch the feature count in this layer.
@@ -6774,7 +6774,7 @@ public class Layer:public int GetFeatureCount(int force)
   *
   * @since Java bindings 1.7.0
   */
-public class Layer:public int GetFeatureCount()
+public class Layer:public long GetFeatureCount()
 
 /**
   * Return the total number of features read.
@@ -6870,7 +6870,7 @@ public class Layer:public int GetGeomType()
  ResetReading() method can be used to start at the beginning again.  
  <p>
  The returned feature will be properly handled by the Java garbage collector,
- but you can help it by explicitely calling the
+ but you can help it by explicitly calling the
  Feature.<a href="Feature.html#delete()">delete()</a> method.
 
  @return a feature, or null if no more features are available. 
@@ -6969,7 +6969,7 @@ public class Layer:public int SetFeature(Feature feature)
 
  @return 0 on success. Otherwise throws a RuntimeException (or an error code if DontUseExceptions() has been called).
 */
-public class Layer:public int SetNextByIndex(int new_index)
+public class Layer:public int SetNextByIndex(long new_index)
 
 
 /** 
@@ -7595,7 +7595,7 @@ public class Feature:public Feature Clone()
  * <p>
  * Calling this method is not required as normal garbage collection will
  * reclaim associated resources when the object goes out of scope.
- * Otherwise calling delete() explicitely will help release resources sooner.
+ * Otherwise calling delete() explicitly will help release resources sooner.
  * Don't call any method on a deleted object !
  */
 public class Feature:public void delete()
@@ -7635,7 +7635,7 @@ public class Feature:public FeatureDefn GetDefnRef()
  *
  * @return feature id or OGRNullFID if none has been assigned.
  */
-public class Feature:public int GetFID()
+public class Feature:public long GetFID()
 
 /**
  * Fetch field value as date and time.
@@ -7879,7 +7879,7 @@ public class Feature:public boolean IsFieldSet(String name)
  *
  * @return 0 on success. Otherwise throws a RuntimeException (or an error code if DontUseExceptions() has been called).
  */
-public class Feature:public int SetFID(int fid)
+public class Feature:public int SetFID(long fid)
 
 /**
  * Set field to double value. 
@@ -8475,7 +8475,7 @@ public class Geometry:public boolean Crosses(Geometry other)
  * <p>
  * Calling this method is not required as normal garbage collection will
  * reclaim associated resources when the object goes out of scope.
- * Otherwise calling delete() explicitely will help release resources sooner.
+ * Otherwise calling delete() explicitly will help release resources sooner.
  * Don't call any method on a deleted object !
  */
 public class Geometry:public void delete()
@@ -9103,7 +9103,7 @@ public class Geometry:public void SetCoordinateDimension(int dimension)
  * <p>
  * If ipoint is larger than the number of existing
  * points in the linestring, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * @param ipoint the index of the vertex to assign (zero based) or
  *  zero for a point.
@@ -9117,7 +9117,7 @@ public class Geometry:public void SetPoint_2D(int ipoint, double x, double y)
  * <p>
  * If ipoint is larger than the number of existing
  * points in the linestring, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * @param ipoint the index of the vertex to assign (zero based) or
  *  zero for a point.
@@ -9132,7 +9132,7 @@ public class Geometry:public void SetPoint(int ipoint, double x, double y, doubl
  * <p>
  * If ipoint is larger than the number of existing
  * points in the linestring, the point count will be increased to
- * accomodate the request.
+ * accommodate the request.
  *
  * @param ipoint the index of the vertex to assign (zero based) or
  *  zero for a point.
@@ -11773,7 +11773,7 @@ public class CoordinateTransformation
  * Caution: the coordinate transformation object returned can be in a non
  * working state if no coordinate transformation can be established between
  * src and dst, and calling other methods on it can result in the process
- * termination. If using GDAL 1.10 or above, it is recommanded to use the
+ * termination. If using GDAL 1.10 or above, it is recommended to use the
  * <a href="#CreateCoordinateTransformation(org.gdal.osr.SpatialReference,%20org.gdal.osr.SpatialReference)">
  * CreateCoordinateTransformation(org.gdal.osr.SpatialReference, org.gdal.osr.SpatialReference)</a> method instead.
  * <p>
diff --git a/swig/java/make_doc.sh b/swig/java/make_doc.sh
index 0b9966d..81a1e09 100755
--- a/swig/java/make_doc.sh
+++ b/swig/java/make_doc.sh
@@ -1,5 +1,8 @@
 #!/bin/sh
 
+# read version
+version=`cat ../../VERSION | xargs echo -n`
+
 # Patch the generated SIWG Java files to add the Javadoc into them
 # thanks to the small utility add_javadoc
 rm -rf org_patched
@@ -20,7 +23,7 @@ cp gdal-package-info.java org_patched/org/gdal/gdal/package-info.java
 cp gdalconst-package-info.java org_patched/org/gdal/gdalconst/package-info.java
 cp ogr-package-info.java org_patched/org/gdal/ogr/package-info.java
 cp osr-package-info.java org_patched/org/gdal/osr/package-info.java
-javadoc -overview overview.html -public -d ./java -sourcepath org_patched -subpackages org.gdal -link http://java.sun.com/javase/6/docs/api -windowtitle "GDAL/OGR 1.8.0 Java bindings API"
+javadoc -overview overview.html -public -d ./java -sourcepath org_patched -subpackages org.gdal -link http://java.sun.com/javase/6/docs/api -windowtitle "GDAL/OGR ${version} Java bindings API"
 
 # Create a zip with the Javadoc
 rm -f javadoc.zip
diff --git a/swig/java/pom.xml b/swig/java/pom.xml
new file mode 100644
index 0000000..7cce590
--- /dev/null
+++ b/swig/java/pom.xml
@@ -0,0 +1,41 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.gdal</groupId>
+  <artifactId>gdal</artifactId>
+  <version>@VERSION@</version>
+  <packaging>pom</packaging>
+
+  <name>gdal</name>
+  <description>
+    Geospatial Data Abstraction Library
+  </description>
+
+  <url>http://gdal.org</url>
+
+  <licenses>
+    <license>
+      <name>MIT License</name>
+      <url>http://opensource.org/licenses/MIT</url>
+    </license>
+  </licenses>
+
+  <developers>
+    <developer>
+      <name>Even Rouault</name>
+      <url>http://www.spatialys.com/</url>
+      <organization>Spatialys</organization>
+    </developer>
+    <developer>
+      <name>Justin Deoliveira</name>
+      <url>http://github.com/jdeolive</url>
+    </developer>
+  </developers>
+
+  <scm>
+    <connection>scm:git:git at github.com:osgeo/gdal.git</connection>
+    <url>git at github.com:osgeo/gdal.git</url>
+  </scm>
+
+</project>
diff --git a/swig/makefile.vc b/swig/makefile.vc
index d4e3566..9d565f7 100644
--- a/swig/makefile.vc
+++ b/swig/makefile.vc
@@ -52,14 +52,14 @@ java: gdalvars
         cd ..
         $(MAKE) /f makefile.vc
 
-ruby: gdalvars
-        cd ruby
-        $(SWIG) -ruby -I../include/ruby -o gdalconst_wrap.c -autorename -prefix "gdal::" ../include/gdalconst.i
-        $(SWIG) -c++ -ruby -I../include/ruby -o gdal_wrap.cpp -autorename -prefix "gdal::" ../include/gdal.i
-        $(SWIG) -c++ -ruby -I../include/ruby -o osr_wrap.cpp -autorename -prefix "gdal::" ../include/osr.i
-        $(SWIG) -c++ -ruby -I../include/ruby -o ogr_wrap.cpp -autorename -prefix "gdal::" ../include/ogr.i
-        $(MAKE) /f makefile.vc build
-        $(MAKE) /f makefile.vc install 
+#ruby: gdalvars
+#        cd ruby
+#        $(SWIG) -ruby -I../include/ruby -o gdalconst_wrap.c -autorename -prefix "gdal::" ../include/gdalconst.i
+#        $(SWIG) -c++ -ruby -I../include/ruby -o gdal_wrap.cpp -autorename -prefix "gdal::" ../include/gdal.i
+#        $(SWIG) -c++ -ruby -I../include/ruby -o osr_wrap.cpp -autorename -prefix "gdal::" ../include/osr.i
+#        $(SWIG) -c++ -ruby -I../include/ruby -o ogr_wrap.cpp -autorename -prefix "gdal::" ../include/ogr.i
+#        $(MAKE) /f makefile.vc build
+#        $(MAKE) /f makefile.vc install 
         
 test: gdalvars
 				cd $(GDAL_HOME)\..\gdalautotest
diff --git a/swig/perl/Changes-in-the-API-in-2.0 b/swig/perl/Changes-in-the-API-in-2.0
new file mode 100644
index 0000000..6513b40
--- /dev/null
+++ b/swig/perl/Changes-in-the-API-in-2.0
@@ -0,0 +1,45 @@
+This file lists the backwards incompatible changes in the Perl
+bindings API in version 2.0.
+
+There are numerous other changes but they are meant to be
+non-breaking.
+
+To be on the safe side, new code should be written according to
+what is presented in the documentation.
+
+constructors:
+
+    Geo::GDAL does not use the "create" constructors any more.  All
+    constructors are called "new" and use the new syntax.  This
+    applieds to classes Geo::GDAL::ColorTable, Geo::OGR::Feature,
+    Geo::OGR::FeatureDefn, Geo::OGR::FieldDefn,
+    Geo::OGR::GeomFieldDefn, Geo::OGR::Geometry, and
+    Geo::OSR::SpatialReference.
+
+class Geo::GDAL::GCP:
+
+    attributes GCP* are renamed as * (the prefix GCP is removed)
+
+many classes:
+
+    Class attributes (arrays or hashes with upcase names) may have
+    been (re)moved, accessor functions which return lists, like
+    GeometryTypes(), are the replacement.
+
+Geo::OSR::SpatialReference:
+
+    Overloading to "", and = have been removed. Use explicit 
+    method call As('PrettyWKT') instead.
+
+Geo::OGR::Layer
+
+    Tuple requires now the geometry fields as last.
+
+Geo::OGR::Feature
+
+    Tuple requires now the geometry fields as last.
+
+Geo::OSR
+
+    Projection and other constants (strings) are now mixed case, as
+    the values in GDAL.
diff --git a/swig/perl/Doxyfile b/swig/perl/Doxyfile
index 318463b..c56fef1 100644
--- a/swig/perl/Doxyfile
+++ b/swig/perl/Doxyfile
@@ -1,101 +1,114 @@
-# Doxyfile 1.7.3
+# Doxyfile 1.8.6
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
 #
-# All text after a hash (#) is considered a comment and will be ignored.
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
 # The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
 
 #---------------------------------------------------------------------------
 # Project related configuration options
 #---------------------------------------------------------------------------
 
 # This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
 
 DOXYFILE_ENCODING      = UTF-8
 
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
-# by quotes) that should identify the project.
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
 
 PROJECT_NAME           = Geo::GDAL
 
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
 
-PROJECT_NUMBER         = 1.11
+PROJECT_NUMBER         = 2.0
 
-# Using the PROJECT_BRIEF tag one can provide an optional one line description for a project that appears at the top of each page and should give viewer a quick idea about the purpose of the project. Keep the description short.
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
 
 PROJECT_BRIEF          =
 
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
 
 PROJECT_LOGO           =
 
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
 
-OUTPUT_DIRECTORY       = .
+OUTPUT_DIRECTORY       = doc
 
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
 
 CREATE_SUBDIRS         = NO
 
 # The OUTPUT_LANGUAGE tag is used to specify the language in which all
 # documentation generated by doxygen is written. Doxygen will use this
 # information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
 
 OUTPUT_LANGUAGE        = English
 
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
 
 BRIEF_MEMBER_DESC      = YES
 
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
 # brief descriptions will be completely suppressed.
+# The default value is: YES.
 
 REPEAT_BRIEF           = YES
 
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
 
 ABBREVIATE_BRIEF       = "The $name class" \
                          "The $name widget" \
@@ -110,8 +123,9 @@ ABBREVIATE_BRIEF       = "The $name class" \
                          the
 
 # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# doxygen will generate a detailed section even if there is only a brief
 # description.
+# The default value is: NO.
 
 ALWAYS_DETAILED_SEC    = NO
 
@@ -119,153 +133,204 @@ ALWAYS_DETAILED_SEC    = NO
 # inherited members of a class in the documentation of that class as if those
 # members were ordinary class members. Constructors, destructors and assignment
 # operators of the base classes will not be shown.
+# The default value is: NO.
 
 INLINE_INHERITED_MEMB  = NO
 
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
 
 FULL_PATH_NAMES        = YES
 
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
 
-STRIP_FROM_PATH        =
+STRIP_FROM_PATH        = .
 
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
 
 STRIP_FROM_INC_PATH    =
 
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
 
 SHORT_NAMES            = NO
 
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
 
 JAVADOC_AUTOBRIEF      = NO
 
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
 
 QT_AUTOBRIEF           = NO
 
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
 
 MULTILINE_CPP_IS_BRIEF = NO
 
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
 
 INHERIT_DOCS           = YES
 
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
 
 SEPARATE_MEMBER_PAGES  = NO
 
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
 
-TAB_SIZE               = 8
+TAB_SIZE               = 4
 
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
 
-ALIASES                =
+ALIASES                = "copy=\par Copyright:\n©"
 
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_FOR_C  = NO
 
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_JAVA   = NO
 
 # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
 
 OPTIMIZE_FOR_FORTRAN   = NO
 
 # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
 
 OPTIMIZE_OUTPUT_VHDL   = NO
 
 # Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
 # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
 
 EXTENSION_MAPPING      =
 
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
 # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
 # diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
 
 BUILTIN_STL_SUPPORT    = NO
 
 # If you use Microsoft's C++/CLI language, you should set this option to YES to
 # enable parsing support.
+# The default value is: NO.
 
 CPP_CLI_SUPPORT        = NO
 
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
 
 SIP_SUPPORT            = NO
 
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
 
 IDL_PROPERTY_SUPPORT   = YES
 
@@ -273,385 +338,472 @@ IDL_PROPERTY_SUPPORT   = YES
 # tag is set to YES, then doxygen will reuse the documentation of the first
 # member in the group (if any) for the other members of the group. By default
 # all members of a group must be documented explicitly.
+# The default value is: NO.
 
 DISTRIBUTE_GROUP_DOC   = NO
 
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
 
 SUBGROUPING            = YES
 
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
 # typedef struct TypeS {} TypeT, will appear in the documentation as a struct
 # with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
 # types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
 
 TYPEDEF_HIDES_STRUCT   = NO
 
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols
-
-SYMBOL_CACHE_SIZE      = 0
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
 
 #---------------------------------------------------------------------------
 # Build related configuration options
 #---------------------------------------------------------------------------
 
 # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
 
-EXTRACT_ALL            = YES
+EXTRACT_ALL            = NO
 
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
 
 EXTRACT_PRIVATE        = NO
 
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
 
 EXTRACT_STATIC         = NO
 
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
 
 EXTRACT_LOCAL_CLASSES  = YES
 
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
 
 EXTRACT_LOCAL_METHODS  = NO
 
 # If this flag is set to YES, the members of anonymous namespaces will be
 # extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
 
 EXTRACT_ANON_NSPACES   = NO
 
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
 
-HIDE_UNDOC_MEMBERS     = YES
+HIDE_UNDOC_MEMBERS     = NO
 
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
 
-HIDE_UNDOC_CLASSES     = YES
+HIDE_UNDOC_CLASSES     = NO
 
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
 
 HIDE_FRIEND_COMPOUNDS  = NO
 
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
 
 HIDE_IN_BODY_DOCS      = NO
 
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
 
 INTERNAL_DOCS          = NO
 
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
 # allowed. This is useful if you have classes or files whose names only differ
 # in case and if your file system supports case sensitive file names. Windows
 # and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
 
-CASE_SENSE_NAMES       = NO
+CASE_SENSE_NAMES       = YES
 
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
 
 HIDE_SCOPE_NAMES       = NO
 
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
 
 SHOW_INCLUDE_FILES     = YES
 
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
 
 FORCE_LOCAL_INCLUDES   = NO
 
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
 
 INLINE_INFO            = YES
 
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
 
 SORT_MEMBER_DOCS       = YES
 
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
 
 SORT_BRIEF_DOCS        = NO
 
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
 
 SORT_MEMBERS_CTORS_1ST = NO
 
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
 
 SORT_GROUP_NAMES       = NO
 
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
 # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
 
-SORT_BY_SCOPE_NAME     = NO
+SORT_BY_SCOPE_NAME     = YES
 
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even if there is only one candidate or it is obvious which candidate to choose by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
 
 STRICT_PROTO_MATCHING  = NO
 
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
 
 GENERATE_TODOLIST      = YES
 
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
 
 GENERATE_TESTLIST      = YES
 
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
 
 GENERATE_BUGLIST       = YES
 
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
 
 GENERATE_DEPRECATEDLIST= YES
 
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
 
 ENABLED_SECTIONS       =
 
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
 
 MAX_INITIALIZER_LINES  = 30
 
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
 
 SHOW_USED_FILES        = YES
 
-# If the sources in your project are distributed over multiple directories
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
 
 SHOW_FILES             = YES
 
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
 
 SHOW_NAMESPACES        = YES
 
 # The FILE_VERSION_FILTER tag can be used to specify a program or script that
 # doxygen should invoke to get the current version for each file (typically from
 # the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
 
 FILE_VERSION_FILTER    =
 
 # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
 # by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. The create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
 
 LAYOUT_FILE            =
 
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
 #---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
 
 QUIET                  = NO
 
 # The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
 
 WARNINGS               = YES
 
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
 
 WARN_IF_UNDOCUMENTED   = YES
 
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
 
 WARN_IF_DOC_ERROR      = YES
 
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
 
 WARN_NO_PARAMDOC       = NO
 
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
 
 WARN_FORMAT            = "$file:$line: $text"
 
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
 
 WARN_LOGFILE           =
 
 #---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
 #---------------------------------------------------------------------------
 
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
 
 INPUT                  = .
 
 # This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
 
 INPUT_ENCODING         = UTF-8
 
 # If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
 
-FILE_PATTERNS          = *.pm \
-                         *.dox
+FILE_PATTERNS          = *.dox \
+                         *.pm
 
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
 
-RECURSIVE              = YES
+RECURSIVE              = NO
 
-# The EXCLUDE tag can be used to specify files and/or directories that should
+# The EXCLUDE tag can be used to specify files and/or directories that should be
 # excluded from the INPUT source files. This way you can easily exclude a
 # subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
 
-EXCLUDE                = blib
+EXCLUDE                =
 
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
 # directories that are symbolic links (a Unix file system feature) are excluded
 # from the input.
+# The default value is: NO.
 
 EXCLUDE_SYMLINKS       = NO
 
 # If the value of the INPUT tag contains directories, you can use the
 # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
 
 EXCLUDE_PATTERNS       =
 
@@ -660,716 +812,1080 @@ EXCLUDE_PATTERNS       =
 # output. The symbol name can be a fully qualified name, a word, or if the
 # wildcard * is used, a substring. Examples: ANamespace, AClass,
 # AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
 
 EXCLUDE_SYMBOLS        =
 
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
 
 EXAMPLE_PATH           =
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
 
-EXAMPLE_PATTERNS       = *
+EXAMPLE_PATTERNS       =
 
 # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
 
-EXAMPLE_RECURSIVE      = NO
+EXAMPLE_RECURSIVE      = YES
 
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
 
 IMAGE_PATH             =
 
 # The INPUT_FILTER tag can be used to specify a program that doxygen should
 # invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
 
-INPUT_FILTER           = doxygenfilter
+INPUT_FILTER           = doxygen-filter-perl
 
 # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
 
 FILTER_PATTERNS        =
 
 # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
 
 FILTER_SOURCE_FILES    = NO
 
 # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
 
 FILTER_SOURCE_PATTERNS =
 
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
 #---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
 #---------------------------------------------------------------------------
 
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
 
-SOURCE_BROWSER         = NO
+SOURCE_BROWSER         = YES
 
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
 
 INLINE_SOURCES         = NO
 
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C and C++ comments will always remain visible.
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
 
 STRIP_CODE_COMMENTS    = YES
 
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
 
-REFERENCED_BY_RELATION = NO
+REFERENCED_BY_RELATION = YES
 
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
 
-REFERENCES_RELATION    = NO
+REFERENCES_RELATION    = YES
 
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
 
 REFERENCES_LINK_SOURCE = YES
 
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
 
 USE_HTAGS              = NO
 
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
 
 VERBATIM_HEADERS       = NO
 
 #---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
 #---------------------------------------------------------------------------
 
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
 
-ALPHABETICAL_INDEX     = NO
+ALPHABETICAL_INDEX     = YES
 
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
 COLS_IN_ALPHA_INDEX    = 5
 
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
 IGNORE_PREFIX          =
 
 #---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
 
 GENERATE_HTML          = YES
 
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_OUTPUT            = html
 
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_FILE_EXTENSION    = .html
 
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
 # standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_HEADER            =
 
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_FOOTER            =
 
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# stylesheet in the HTML output directory as well, or it will be erased!
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_STYLESHEET        =
 
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the stylesheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_HUE    = 220
 
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_SAT    = 100
 
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_COLORSTYLE_GAMMA  = 80
 
 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 HTML_TIMESTAMP         = YES
 
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
-# files or namespaces will be aligned in HTML using tables. If set to
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
 # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
 # documentation will contain sections that can be hidden and shown after the
-# page has loaded. For this to work a browser that supports
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = NO
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
 # for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_DOCSET        = NO
 
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_FEEDNAME        = "Doxygen generated docs"
 
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_BUNDLE_ID       = org.doxygen.Project
 
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
 # the documentation publisher. This should be a reverse domain-name style
 # string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
 
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
 DOCSET_PUBLISHER_NAME  = Publisher
 
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_HTMLHELP      = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
 # written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_FILE               =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 HHC_LOCATION           =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 GENERATE_CHI           = NO
 
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 CHM_INDEX_ENCODING     =
 
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 BINARY_TOC             = NO
 
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
 TOC_EXPAND             = NO
 
 # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_QHP           = NO
 
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QCH_FILE               =
 
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_NAMESPACE          = org.doxygen.Project
 
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_VIRTUAL_FOLDER     = doc
 
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_CUST_FILTER_NAME   =
 
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_CUST_FILTER_ATTRS  =
 
 # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHP_SECT_FILTER_ATTRS  =
 
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
 
 QHG_LOCATION           =
 
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-#  will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 GENERATE_ECLIPSEHELP   = NO
 
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
 
 ECLIPSE_DOC_ID         = org.doxygen.Project
 
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
-# top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it.
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 DISABLE_INDEX          = NO
 
-# This tag can be used to set the number of enum values (range [0,1..20])
-# that doxygen will group on one line in the generated HTML documentation.
-# Note that a value of 0 will completely suppress the enum values from appearing in the overview section.
-
-ENUM_VALUES_PER_LINE   = 4
-
 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW      = NO
-
-# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
-# and Class Hierarchy pages using a tree view instead of an ordered list.
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
-USE_INLINE_TREES       = NO
+ENUM_VALUES_PER_LINE   = 4
 
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 TREEVIEW_WIDTH         = 250
 
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 EXT_LINKS_IN_WINDOW    = NO
 
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 FORMULA_FONTSIZE       = 10
 
 # Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 FORMULA_TRANSPARENT    = YES
 
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 USE_MATHJAX            = NO
 
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the mathjax.org site, so you can quickly see the result without installing
-# MathJax, but it is strongly recommended to install a local copy of MathJax
-# before deployment.
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
 
 MATHJAX_RELPATH        = http://www.mathjax.org/mathjax
 
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
 
 SEARCHENGINE           = NO
 
 # When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
 
 SERVER_BASED_SEARCH    = NO
 
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
 #---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
 
-GENERATE_LATEX         = YES
+GENERATE_LATEX         = NO
 
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_OUTPUT           = latex
 
 # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_CMD_NAME         = latex
 
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 MAKEINDEX_CMD_NAME     = makeindex
 
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 COMPACT_LATEX          = NO
 
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 PAPER_TYPE             = a4wide
 
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 EXTRA_PACKAGES         =
 
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HEADER           =
 
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 PDF_HYPERLINKS         = NO
 
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
 # higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
-USE_PDFLATEX           = NO
+USE_PDFLATEX           = YES
 
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_BATCHMODE        = NO
 
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_HIDE_INDICES     = NO
 
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
 
 LATEX_SOURCE_CODE      = NO
 
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
 #---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
 
 GENERATE_RTF           = NO
 
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_OUTPUT             = rtf
 
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 COMPACT_RTF            = NO
 
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_HYPERLINKS         = NO
 
-# Load stylesheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_STYLESHEET_FILE    =
 
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
 
 RTF_EXTENSIONS_FILE    =
 
 #---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
 
 GENERATE_MAN           = NO
 
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_OUTPUT             = man
 
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_EXTENSION          = .3
 
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
 
 MAN_LINKS              = NO
 
 #---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
 
 GENERATE_XML           = NO
 
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_OUTPUT             = xml
 
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_SCHEMA             =
 
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_DTD                =
 
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
 
 XML_PROGRAMLISTING     = YES
 
 #---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options related to the DOCBOOK output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
 
 GENERATE_AUTOGEN_DEF   = NO
 
 #---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
 #---------------------------------------------------------------------------
 
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
 
 GENERATE_PERLMOD       = NO
 
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_LATEX          = NO
 
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_PRETTY         = YES
 
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
 PERLMOD_MAKEVAR_PREFIX =
 
@@ -1377,109 +1893,128 @@ PERLMOD_MAKEVAR_PREFIX =
 # Configuration options related to the preprocessor
 #---------------------------------------------------------------------------
 
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
 
-ENABLE_PREPROCESSING   = YES
+ENABLE_PREPROCESSING   = NO
 
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 MACRO_EXPANSION        = NO
 
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 EXPAND_ONLY_PREDEF     = NO
 
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
-SEARCH_INCLUDES        = YES
+SEARCH_INCLUDES        = NO
 
 # The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
 
 INCLUDE_PATH           =
 
 # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
 # patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 INCLUDE_FILE_PATTERNS  =
 
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 PREDEFINED             =
 
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that overrules the definition found in the source code.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 EXPAND_AS_DEFINED      =
 
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to function-like macros that are alone on a line, have an
+# all uppercase name, and do not end with a semicolon. Such function macros are
+# typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
 SKIP_FUNCTION_MACROS   = YES
 
 #---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
 #---------------------------------------------------------------------------
 
-# The TAGFILES option can be used to specify one or more tagfiles.
-# Optionally an initial location of the external documentation
-# can be added for each tagfile. The format of a tag file without
-# this location is as follows:
-#
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
 # TAGFILES = file1 file2 ...
 # Adding location for the tag files is done as follows:
-#
 # TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths or
-# URLs. If a location is present for each tag, the installdox tool
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen
-# is run, you must also specify the path to the tagfile here.
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
 
 TAGFILES               =
 
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
 
 GENERATE_TAGFILE       =
 
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
 
 ALLEXTERNALS           = NO
 
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
 
 EXTERNAL_GROUPS        = YES
 
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
 # The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
 
 PERL_PATH              = /usr/bin/perl
 
@@ -1487,204 +2022,293 @@ PERL_PATH              = /usr/bin/perl
 # Configuration options related to the dot tool
 #---------------------------------------------------------------------------
 
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
 
 CLASS_DIAGRAMS         = NO
 
 # You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
 # documentation. The MSCGEN_PATH tag allows you to specify the directory where
 # the mscgen tool resides. If left empty the tool is assumed to be found in the
 # default search path.
 
 MSCGEN_PATH            =
 
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
 
-HIDE_UNDOC_RELATIONS   = YES
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = NO
 
 # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
 
 HAVE_DOT               = YES
 
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_NUM_THREADS        = 0
 
-# By default doxygen will write a font called Helvetica to the output
-# directory and reference it in all dot files that doxygen generates.
-# When you want a differently looking font you can specify the font name
-# using DOT_FONTNAME. You need to make sure dot is able to find the font,
-# which can be done by putting it in a standard location or by setting the
-# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
-# containing the font.
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_FONTNAME           = Helvetica
 
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_FONTSIZE           = 10
 
-# By default doxygen will tell dot to use the output directory to look for the
-# FreeSans.ttf font (which doxygen will put there itself). If you specify a
-# different font using DOT_FONTNAME you can set the path where dot
-# can find it using this tag.
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_FONTPATH           =
 
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# the CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 CLASS_GRAPH            = YES
 
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
-COLLABORATION_GRAPH    = NO
+COLLABORATION_GRAPH    = YES
 
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GROUP_GRAPHS           = YES
 
 # If the UML_LOOK tag is set to YES doxygen will generate inheritance and
 # collaboration diagrams in a style similar to the OMG's Unified Modeling
 # Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 UML_LOOK               = NO
 
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 TEMPLATE_RELATIONS     = NO
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 INCLUDE_GRAPH          = YES
 
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 INCLUDED_BY_GRAPH      = YES
 
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 CALL_GRAPH             = NO
 
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 CALLER_GRAPH           = NO
 
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GRAPHICAL_HIERARCHY    = YES
 
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DIRECTORY_GRAPH        = YES
 
 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are png, svg, gif or svg.
-# If left blank png will be used.
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_IMAGE_FORMAT       = png
 
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
 # found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_PATH               =
 
 # The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOTFILE_DIRS           =
 
 # The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
 
 MSCFILE_DIRS           =
 
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_GRAPH_MAX_NODES    = 50
 
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
 # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 MAX_DOT_GRAPH_DEPTH    = 0
 
 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_TRANSPARENT        = NO
 
 # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
 # files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_MULTI_TARGETS      = NO
 
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 GENERATE_LEGEND        = YES
 
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
 
 DOT_CLEANUP            = YES
diff --git a/swig/perl/GNUmakefile b/swig/perl/GNUmakefile
index 9db3018..1d82b53 100644
--- a/swig/perl/GNUmakefile
+++ b/swig/perl/GNUmakefile
@@ -53,5 +53,7 @@ veryclean: clean
 	-rm -f ${WRAPPERS} 
 	-rm -f gdal.pm gdalconst.pm osr.pm ogr.pm
 
-doc:
-	doxygen
+doc: .FORCE
+
+.FORCE:
+	perl parse-for-doxygen.pl > all.pm; doxygen; rm -f all.pm
diff --git a/swig/perl/README b/swig/perl/README
index ea5f3d9..8d76ad7 100644
--- a/swig/perl/README
+++ b/swig/perl/README
@@ -30,6 +30,28 @@ make generate
 
 perl Makefile.PL
 
+NOTE-----------NOTE-----------NOTE-----------NOTE-----------NOTE
+
+NOTE: The Perl bindings use ExtUtils::MakeMaker, which accepts (from
+version 6.31) argument INSTALL_BASE to change where the module will be
+installed.
+
+http://perldoc.perl.org/ExtUtils/MakeMaker.html#INSTALL_BASE
+
+GNUmakefile in this directory calls
+
+	perl Makefile.PL INSTALL_BASE=$(INST_PREFIX)
+
+to honor the overall location where GDAL is to be installed.  It seems
+that plain "perl Makefile.PL" is different from "perl Makefile.PL
+INSTALL_BASE=/usr/local" in that the former will install into
+/usr/local/lib/perl and the latter will install into
+/usr/local/lib/perl5. This feature is in version 7.04 of
+ExtUtils::MakeMaker. It may easily lead to several versions of
+Geo::GDAL in your machine.
+
+NOTE-----------NOTE-----------NOTE-----------NOTE-----------NOTE
+
 3) making the bindings
 
 make -f Makefile_Geo__GDAL
@@ -60,18 +82,17 @@ This module requires the GDAL library.
 
 DOCUMENTATION
 
-The documentation is maintained in Doxygen files. Doxygen is available
-at www.doxygen.org. You will also need Perl Doxygen Filter from
-http://www.bigsister.ch/doxygenfilter/ and an extension to it from
-http://geoinformatics.aalto.fi/files/doxygenfilter/. To generate the
-documentation type
+The documentation is maintained in Doxygen files. You will also need
+Doxygen-Filter-Perl. To generate the documentation type
+
+make doc
 
-    doxygen
+You can find the documentation also at ajolma.net.
 
-You can find the documentation also at
-http://geoinformatics.aalto.fi/doc/Geo-GDAL/html/. However, the
-comprehensive documentation of GDAL and OGR are at
-http://www.gdal.org/.
+GDAL: http://www.gdal.org/
+Doxygen : http://www.doxygen.org
+Doxygen-Filter-Perl: http://search.cpan.org/~jordan/Doxygen-Filter-Perl/
+Geo::GDAL documentation: http://ajolma.net/Geo-GDAL/snapshot/
 
 COPYRIGHT AND LICENCE
 
diff --git a/swig/perl/cr.dox b/swig/perl/cr.dox
index 832320c..f5ed01f 100644
--- a/swig/perl/cr.dox
+++ b/swig/perl/cr.dox
@@ -6,44 +6,59 @@ what it does, what input it needs, etc. Do not blindly execute
 anything!
 
 This example will create a raster dataset with one band and with cell
-value of type Float32. The raster will be stored as a !GeoTiff and it
-will have undefined SRS. The coordinates of the upper left vertex are
-known and the size of each pixel. Pixels are squares.
+value of type Float32. The raster will be stored in GeoTiff format and
+it will have ETRS-TM35FIN as the SRS. The coordinates of the upper
+left vertex are known and the size of each pixel. Pixels are squares.
 
 \code
 use Geo::GDAL;
 
+$driver = 'GTiff';    # name of the GDAL driver
+$ext = '.tiff';       # extension for the file
 $name = "raster";     # name (without extension) for the new raster
+$bands = 1;           # it will have only one band
 $datatype = 'Float32';# datatype for the values in pixels
-$width = 100;         # number of pixels in x direction
+$epsg = 3067;         # SRS as EPSG for the dataset
+$width = 200;         # number of pixels in x direction
 $height = 100;        # number of pixels in y direction
-$minx = 12.3;         # x of the left border of leftmost pixel
-$dx = 0.1;            # width of pixels
-$maxy = 14.5;         # y of the top border of topmost pixel
-$dy = -0.1;           # height of pixels, negative means miny < maxy
+$minx = 384600;       # x of the left border of leftmost pixel
+$dx = 100;            # width of pixels
+$maxy = 6672700;      # y of the top border of topmost pixel
+$dy = 100;            # height of pixels
 $nodata = -1;         # nodata value
- at data = ();           # pixel values, stored in this example in a hash
+ at data = ();           # pixel values, stored in this example in an array
 
-# note: things that are hardcoded:
-# We create a GTiff and set the extension to '.tiff'.
-# We add only one band to the raster.
-
-$dataset = Geo::GDAL::Driver('GTiff')->Create($name.'.tiff', $width, $height, 1, $datatype);
+$dataset = Geo::GDAL::Driver($driver)->Create($name.$ext, $width, $height, $bands, $datatype);
+# Set the transformation matrix from pixels to projection, note minus in front of $dy
 $dataset->GeoTransform($minx, $dx, 0, $maxy, 0, -$dy);
+$dataset->Projection(Geo::OSR::SpatialReference->create(EPSG=>$epsg)->As('WKT'));
 $band = $dataset->Band(1);
 $band->NoDataValue($nodata);
 
-for (1..100) {
-    push @data, [1..100];
+# put something into all pixels
+# note that x and y here are pixel coordinates, not projection coordinates
+# the pixel with biggest value will be bottom right (southeasternmost in this case)
+for my $y (0..$height-1) {
+    my @row;
+    for my $x (0..$width-1) {
+        $row[$x] = $x * $y;
+    }
+    push @data, \@row;
 }
+
+# put the data into the GDAL raster
 $band->WriteTile(\@data);
+
+# make a hole into the raster
 @data = ();
-for $i (0..19) {
-    for $j (0..29) {
-	$data[$i][$j] = $nodata;
+for $y (0..19) {
+    for $x (0..29) {
+        $data[$y][$x] = $nodata;
     }
 }
 $band->WriteTile(\@data,10,20);
+
+# the data is flushed to disk when the variable $dataset is destroyed
 \endcode
 
 */
diff --git a/swig/perl/cv.dox b/swig/perl/cv.dox
index 356d988..fa67c55 100644
--- a/swig/perl/cv.dox
+++ b/swig/perl/cv.dox
@@ -5,52 +5,64 @@ before using any of this code, you look into it and try to understand
 what it does, what input it needs, etc. Do not blindly execute
 anything!
 
-This example creates a new layer to a named datasource. The layer will
-contain polygon features and each feature will contain an integer as
-an attribute value. The name of the attribute will be 'key'. Each
-polygon will have four vertices. The SRS is explicitly set to WGS84.
-
+This example creates a new layer to a data source in memory. The layer
+will contain polygon features and each feature will contain a string
+as an attribute value. The name of the attribute will be 'key'. Each
+polygon will have four vertices. The SRS is set to WGS84.
 
 \code
 use Geo::GDAL;
 
 # information that we need:
-$dsname = ".";          # name of the datasource (in this case a directory)
-$lname = "boxes";        # name of the layer
- at data;                   # array which contains the data as hashref items,
-                         # each item comprises items 'points' and 'key'
-                         # 'points' is in this case an array of four points
-                         # which are refs to arrays (x,y)
-                         # 'key' is an integer which is stored as each
-                         # feature's attribute data
-
- at data = ({key => 'rect1', points => [[0,0],[1,0],[1,1],[0,1]]},
-	 {key => 'rect2', points => [[5,5],[7,5],[7,6],[5,6]]});
-
-$datasource = Geo::OGR::Driver('ESRI Shapefile')->Create($dsname) or die;
+my $driver = 'Memory';
+my $dsname = ".";    # name of the datasource
+my $lname = "boxes"; # name of the layer
+my @data;            # array which contains the data as hashref items,
+                     # each item comprises items 'points' and 'key'
+                     # 'points' is in this case an array of four points
+                     # which are refs to arrays (x,y)
+                     # 'key' is a string
+ at data = (
+    { key => 'rect1', points => [[0,0],[1,0],[1,1],[0,1]] },
+    { key => 'rect2', points => [[5,5],[7,5],[7,6],[5,6]] }
+    );
+eval {
+    $datasource = Geo::OGR::Driver($driver)->Create($dsname);
+};
+die "Can't create data source $dsname: $@" if $@;
 
-$osr = new Geo::OSR::SpatialReference;
-$osr->SetWellKnownGeogCS('WGS84');
+$osr = Geo::OSR::SpatialReference->create(WGS => 84);
 
-$layer = $datasource->CreateLayer({ Name => $lname, SRS => $osr, GeometryType => 'Polygon'});
-$layer->Schema( Fields => 
-		[{ Name => 'key', Type => 'Integer' }] );
-
-# make sure the cells share the points
+$layer = $datasource->CreateLayer(
+    Name => $lname, 
+    SRS => $osr,
+    # add the fields as in @data
+    Fields => [
+        { Name => 'key', Type => 'String' },
+        { Name => 'geom', Type => 'Polygon' }
+    ]
+    );
 
 for $item (@data) {
+    my @ring = ( $item->{points}[0], 
+                 $item->{points}[1], 
+                 $item->{points}[2], 
+                 $item->{points}[3],
+                 $item->{points}[0] # close the ring
+        );
+    my %feature_data = (
+        key => $item->{key},
+        # a polygon is an array of rings, here we define just the outer ring
+        geom => { Points => [ \@ring ] }
+        );
+    $layer->InsertFeature(\%feature_data);
+}
 
-    @ring = ($item->{points}[0], 
-	     $item->{points}[1], 
-	     $item->{points}[2], 
-	     $item->{points}[3],
-	     $item->{points}[0]);
-
-    $layer->InsertFeature({ 
-	key => $item->{key},
-	Geometry => { Points => [ \@ring ] }
-    });
+# check that we got it ok
 
+$layer = $datasource->GetLayer($lname);
+while ($feature = $layer->GetNextFeature()) {  
+    $feature->DumpReadable;
 }
 \endcode
 
diff --git a/swig/perl/gdal_wrap.cpp b/swig/perl/gdal_wrap.cpp
index afb74a6..d77ba65 100644
--- a/swig/perl/gdal_wrap.cpp
+++ b/swig/perl/gdal_wrap.cpp
@@ -1530,13 +1530,15 @@ SWIG_Perl_SetModule(swig_module_info *module) {
 #define SWIGTYPE_p_VSIStatBufL swig_types[15]
 #define SWIGTYPE_p_char swig_types[16]
 #define SWIGTYPE_p_double swig_types[17]
-#define SWIGTYPE_p_int swig_types[18]
-#define SWIGTYPE_p_p_GDAL_GCP swig_types[19]
-#define SWIGTYPE_p_p_char swig_types[20]
-#define SWIGTYPE_p_p_int swig_types[21]
-#define SWIGTYPE_p_void swig_types[22]
-static swig_type_info *swig_types[24];
-static swig_module_info swig_module = {swig_types, 23, 0, 0, 0, 0};
+#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[18]
+#define SWIGTYPE_p_int swig_types[19]
+#define SWIGTYPE_p_p_GDALRasterBandShadow swig_types[20]
+#define SWIGTYPE_p_p_GDAL_GCP swig_types[21]
+#define SWIGTYPE_p_p_char swig_types[22]
+#define SWIGTYPE_p_p_int swig_types[23]
+#define SWIGTYPE_p_void swig_types[24]
+static swig_type_info *swig_types[26];
+static swig_module_info swig_module = {swig_types, 25, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -1594,6 +1596,7 @@ typedef void GDALRasterAttributeTableShadow;
 typedef void GDALTransformerInfoShadow;
 typedef void GDALAsyncReaderShadow;
 
+
 /* use this to not return the int returned by GDAL */
 typedef int RETURN_NONE;
 
@@ -1602,34 +1605,34 @@ typedef int RETURN_NONE;
     #ifndef SWIG
     typedef struct
     {
-	SV *fct;
-	SV *data;
+        SV *fct;
+        SV *data;
     } SavedEnv;
     #endif
     int callback_d_cp_vp(double d, const char *cp, void *vp)
     {
-	int count, ret;
-	SavedEnv *env_ptr = (SavedEnv *)vp;
-	dSP;
-	ENTER;
-	SAVETMPS;
-	PUSHMARK(SP);
-	XPUSHs(sv_2mortal(newSVnv(d)));
-	XPUSHs(sv_2mortal(newSVpv(cp, 0)));
-	if (env_ptr->data)
-	    XPUSHs(env_ptr->data);
-	PUTBACK;
-	count = call_sv(env_ptr->fct, G_SCALAR);
-	SPAGAIN;
-	if (count != 1) {
-	    fprintf(stderr, "The callback must return only one value.\n");
-	    return 0; /* interrupt */
-	}
-	ret = POPi;
-	PUTBACK;
-	FREETMPS;
-	LEAVE;
-	return ret;
+        int count, ret;
+        SavedEnv *env_ptr = (SavedEnv *)vp;
+        dSP;
+        ENTER;
+        SAVETMPS;
+        PUSHMARK(SP);
+        XPUSHs(sv_2mortal(newSVnv(d)));
+        XPUSHs(sv_2mortal(newSVpv(cp, 0)));
+        if (env_ptr->data)
+            XPUSHs(env_ptr->data);
+        PUTBACK;
+        count = call_sv(env_ptr->fct, G_SCALAR);
+        SPAGAIN;
+        if (count != 1) {
+            fprintf(stderr, "The callback must return only one value.\n");
+            return 0; /* interrupt */
+        }
+        ret = POPi;
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+        return ret;
     }
 
 
@@ -1948,6 +1951,14 @@ int wrapper_HasThreadSupport()
 }
 
 
+VSILFILE   *wrapper_VSIFOpenL( const char *utf8_path, const char *pszMode )
+{
+    if (!pszMode) /* would lead to segfault */
+        pszMode = "r";
+    return VSIFOpenL( utf8_path, pszMode );
+}
+
+
 SWIGINTERN int
 SWIG_AsVal_unsigned_SS_long SWIG_PERL_DECL_ARGS_2(SV *obj, unsigned long *val) 
 {
@@ -2073,13 +2084,13 @@ SWIGINTERN GDALDatasetShadow *GDALDriverShadow_CreateCopy(GDALDriverShadow *self
                                                                     callback_data );
     return ds;
   }
-SWIGINTERN int GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
+SWIGINTERN CPLErr GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
     return GDALDeleteDataset( self, utf8_path );
   }
-SWIGINTERN int GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALRenameDataset( self, newName, oldName );
   }
-SWIGINTERN int GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALCopyDatasetFiles( self, newName, oldName );
   }
 SWIGINTERN int GDALDriverShadow_Register(GDALDriverShadow *self){
@@ -2195,59 +2206,6 @@ void GDAL_GCP_Id_set( GDAL_GCP *gcp, const char * pszId ) {
 }
 
 
-
-/* Duplicate, but transposed names for C# because 
-*  the C# module outputs backwards names
-*/
-double GDAL_GCP_get_GCPX( GDAL_GCP *gcp ) {
-  return gcp->dfGCPX;
-}
-void GDAL_GCP_set_GCPX( GDAL_GCP *gcp, double dfGCPX ) {
-  gcp->dfGCPX = dfGCPX;
-}
-double GDAL_GCP_get_GCPY( GDAL_GCP *gcp ) {
-  return gcp->dfGCPY;
-}
-void GDAL_GCP_set_GCPY( GDAL_GCP *gcp, double dfGCPY ) {
-  gcp->dfGCPY = dfGCPY;
-}
-double GDAL_GCP_get_GCPZ( GDAL_GCP *gcp ) {
-  return gcp->dfGCPZ;
-}
-void GDAL_GCP_set_GCPZ( GDAL_GCP *gcp, double dfGCPZ ) {
-  gcp->dfGCPZ = dfGCPZ;
-}
-double GDAL_GCP_get_GCPPixel( GDAL_GCP *gcp ) {
-  return gcp->dfGCPPixel;
-}
-void GDAL_GCP_set_GCPPixel( GDAL_GCP *gcp, double dfGCPPixel ) {
-  gcp->dfGCPPixel = dfGCPPixel;
-}
-double GDAL_GCP_get_GCPLine( GDAL_GCP *gcp ) {
-  return gcp->dfGCPLine;
-}
-void GDAL_GCP_set_GCPLine( GDAL_GCP *gcp, double dfGCPLine ) {
-  gcp->dfGCPLine = dfGCPLine;
-}
-const char * GDAL_GCP_get_Info( GDAL_GCP *gcp ) {
-  return gcp->pszInfo;
-}
-void GDAL_GCP_set_Info( GDAL_GCP *gcp, const char * pszInfo ) {
-  if ( gcp->pszInfo ) 
-    CPLFree( gcp->pszInfo );
-  gcp->pszInfo = CPLStrdup(pszInfo);
-}
-const char * GDAL_GCP_get_Id( GDAL_GCP *gcp ) {
-  return gcp->pszId;
-}
-void GDAL_GCP_set_Id( GDAL_GCP *gcp, const char * pszId ) {
-  if ( gcp->pszId ) 
-    CPLFree( gcp->pszId );
-  gcp->pszId = CPLStrdup(pszId);
-}
-
-
-
 static SV *
 CreateArrayFromDoubleArray( double *first, unsigned int size ) {
   AV *av = (AV*)sv_2mortal((SV*)newAV());
@@ -2263,7 +2221,7 @@ CreateArrayFromDoubleArray( double *first, unsigned int size ) {
 static
 GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
                                 int nBands, int* bandMap, int nBandMapArrayLength,
-                                int nPixelSpace, int nLineSpace, int nBandSpace,
+                                GIntBig nPixelSpace, GIntBig nLineSpace, GIntBig nBandSpace,
                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
@@ -2271,7 +2229,7 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -2300,11 +2258,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -2315,11 +2268,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nBandSpace == 0 )
     {
-        if (nLineSpace > MAX_INT32 / buf_ysize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nBandSpace");
-            return 0;
-        }
         nBandSpace = nLineSpace * buf_ysize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nBandSpace % nPixelSize) != 0 )
@@ -2352,7 +2300,8 @@ CPLErr DSReadRaster_internal( GDALDatasetShadow *obj,
                             GDALDataType buf_type,
                             int *buf_size, char **buf,
                             int band_list, int *pband_list,
-                            int pixel_space, int line_space, int band_space)
+                            GIntBig pixel_space, GIntBig line_space, GIntBig band_space,
+                            GDALRasterIOExtraArg* psExtraArg)
 {
   CPLErr result;
 
@@ -2374,9 +2323,10 @@ CPLErr DSReadRaster_internal( GDALDatasetShadow *obj,
   *buf = (char*) malloc( *buf_size );
   if (*buf)
   {
-    result = GDALDatasetRasterIO(obj, GF_Read, xoff, yoff, xsize, ysize,
+    result = GDALDatasetRasterIOEx(obj, GF_Read, xoff, yoff, xsize, ysize,
                                     (void*) *buf, buf_xsize, buf_ysize, buf_type,
-                                    band_list, pband_list, pixel_space, line_space, band_space );
+                                    band_list, pband_list, pixel_space, line_space, band_space,
+                                    psExtraArg );
     if ( result != CE_None ) {
         free( *buf );
         *buf = 0;
@@ -2569,7 +2519,7 @@ SWIGINTERN CPLErr GDALDatasetShadow_WriteRaster(GDALDatasetShadow *self,int xoff
 
     return eErr;
   }
-SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster(GDALDatasetShadow *self,int xoff,int yoff,int xsize,int ysize,int *buf_len,char **buf,int *buf_xsize=0,int *buf_ysize=0,GDALDataType *buf_type=0,int band_list=0,int *pband_list=0,int *buf_pixel_space=0,int *buf_line_space=0,int *buf_band_space=0){
+SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster(GDALDatasetShadow *self,int xoff,int yoff,int xsize,int ysize,int *buf_len,char **buf,int *buf_xsize=0,int *buf_ysize=0,GDALDataType *buf_type=0,int band_list=0,int *pband_list=0,int *buf_pixel_space=0,int *buf_line_space=0,int *buf_band_space=0,GDALRIOResampleAlg resample_alg=GRIORA_NearestNeighbour,GDALProgressFunc callback=NULL,void *callback_data=NULL){
     CPLErr eErr;
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
@@ -2583,18 +2533,64 @@ SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster(GDALDatasetShadow *self,int xoff,
       ntype = GDALGetRasterDataType( GDALGetRasterBand( self, lastband ) );
     }
 
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
-    int band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
                             
     eErr = DSReadRaster_internal( self, xoff, yoff, xsize, ysize,
                                 nxsize, nysize, ntype,
                                 buf_len, buf, 
                                 band_list, pband_list,
-                                pixel_space, line_space, band_space);
+                                pixel_space, line_space, band_space, &sExtraArg);
 
     return eErr;
 }
+SWIGINTERN OGRErr GDALDatasetShadow_StartTransaction(GDALDatasetShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+
+
+#include "ogr_core.h"
+static char const *
+OGRErrMessages( int rc ) {
+  switch( rc ) {
+  case OGRERR_NONE:
+    return "OGR Error: None";
+  case OGRERR_NOT_ENOUGH_DATA:
+    return "OGR Error: Not enough data to deserialize";
+  case OGRERR_NOT_ENOUGH_MEMORY:
+    return "OGR Error: Not enough memory";
+  case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
+    return "OGR Error: Unsupported geometry type";
+  case OGRERR_UNSUPPORTED_OPERATION:
+    return "OGR Error: Unsupported operation";
+  case OGRERR_CORRUPT_DATA:
+    return "OGR Error: Corrupt data";
+  case OGRERR_FAILURE:
+    return "OGR Error: General Error";
+  case OGRERR_UNSUPPORTED_SRS:
+    return "OGR Error: Unsupported SRS";
+  case OGRERR_INVALID_HANDLE:
+    return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
+  default:
+    return "OGR Error: Unknown";
+  }
+}
+
+SWIGINTERN OGRErr GDALDatasetShadow_CommitTransaction(GDALDatasetShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_RollbackTransaction(GDALDatasetShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
 
 int GDALDatasetShadow_RasterXSize_get( GDALDatasetShadow *h ) {
   return GDALGetRasterXSize( h );
@@ -2610,15 +2606,15 @@ int GDALDatasetShadow_RasterCount_get( GDALDatasetShadow *h ) {
 /* Returned size is in bytes or 0 if an error occured */
 static
 GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
-                             int nPixelSpace, int nLineSpace,
-                             int bSpacingShouldBeMultipleOfPixelSize )
+                                 GIntBig nPixelSpace, GIntBig nLineSpace,
+                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
     const GIntBig MAX_INT = (((GIntBig)0x7fffffff) << 32) | 0xffffffff;
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -2647,11 +2643,6 @@ GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -2677,7 +2668,8 @@ CPLErr ReadRaster_internal( GDALRasterBandShadow *obj,
                             int buf_xsize, int buf_ysize,
                             GDALDataType buf_type,
                             int *buf_size, char **buf,
-                            int pixel_space, int line_space )
+                            GIntBig pixel_space, GIntBig line_space,
+                            GDALRasterIOExtraArg* psExtraArg )
 {
   CPLErr result;
 
@@ -2699,9 +2691,9 @@ CPLErr ReadRaster_internal( GDALRasterBandShadow *obj,
   *buf = (char*) malloc( *buf_size );
   if ( *buf )
   {
-    result =  GDALRasterIO( obj, GF_Read, xoff, yoff, xsize, ysize,
+    result =  GDALRasterIOEx( obj, GF_Read, xoff, yoff, xsize, ysize,
                                     (void *) *buf, buf_xsize, buf_ysize,
-                                    buf_type, pixel_space, line_space );
+                                    buf_type, pixel_space, line_space, psExtraArg );
     if ( result != CE_None )
     {
         free( *buf );
@@ -2743,6 +2735,9 @@ CPLErr WriteRaster_internal( GDALRasterBandShadow *obj,
 		        (void *) buffer, buf_xsize, buf_ysize, buf_type, pixel_space, line_space );
 }
 
+SWIGINTERN GDALDatasetShadow *GDALRasterBandShadow_GetDataset(GDALRasterBandShadow *self){
+    return (GDALDatasetShadow*) GDALGetBandDataset(self);
+  }
 SWIGINTERN int GDALRasterBandShadow_GetBand(GDALRasterBandShadow *self){
     return GDALGetBandNumber(self);
   }
@@ -2848,15 +2843,23 @@ SWIGINTERN void GDALRasterBandShadow_ComputeBandStats(GDALRasterBandShadow *self
 SWIGINTERN CPLErr GDALRasterBandShadow_Fill(GDALRasterBandShadow *self,double real_fill,double imag_fill=0.0){
     return GDALFillRaster( self, real_fill, imag_fill );
   }
-SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster(GDALRasterBandShadow *self,int xoff,int yoff,int xsize,int ysize,int *buf_len,char **buf,int *buf_xsize=0,int *buf_ysize=0,int *buf_type=0,int *buf_pixel_space=0,int *buf_line_space=0){
+SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster(GDALRasterBandShadow *self,int xoff,int yoff,int xsize,int ysize,int *buf_len,char **buf,int *buf_xsize=0,int *buf_ysize=0,int *buf_type=0,int *buf_pixel_space=0,int *buf_line_space=0,GDALRIOResampleAlg resample_alg=GRIORA_NearestNeighbour,GDALProgressFunc callback=NULL,void *callback_data=NULL){
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
     GDALDataType ntype  = (buf_type==0) ? GDALGetRasterDataType(self)
                                         : (GDALDataType)*buf_type;
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
     return ReadRaster_internal( self, xoff, yoff, xsize, ysize,
-                                nxsize, nysize, ntype, buf_len, buf, pixel_space, line_space );
+                                nxsize, nysize, ntype, buf_len, buf, pixel_space, line_space,
+                                &sExtraArg );
   }
 SWIGINTERN CPLErr GDALRasterBandShadow_WriteRaster(GDALRasterBandShadow *self,int xoff,int yoff,int xsize,int ysize,int buf_len,char *buf_string,int *buf_xsize=0,int *buf_ysize=0,int *buf_type=0,int *buf_pixel_space=0,int *buf_line_space=0){
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
@@ -2941,13 +2944,13 @@ SWIGINTERN char **GDALRasterBandShadow_GetCategoryNames(GDALRasterBandShadow *se
 SWIGINTERN CPLErr GDALRasterBandShadow_SetCategoryNames(GDALRasterBandShadow *self,char **papszCategoryNames){
     return GDALSetRasterCategoryNames( self, papszCategoryNames );
   }
-SWIGINTERN CPLErr GDALRasterBandShadow_ContourGenerate(GDALRasterBandShadow *self,double dfContourInterval,double dfContourBase,int nFixedLevelCount,double *padfFixedLevels,int bUseNoData,double dfNoDataValue,OGRLayerShadow *hLayer,int iIDField,int iElevField,GDALProgressFunc callback=NULL,void *callback_data=NULL){
-	return GDALContourGenerate( self, dfContourInterval, dfContourBase,
-				    nFixedLevelCount, padfFixedLevels,
-				    bUseNoData, dfNoDataValue, 
-				    hLayer, iIDField, iElevField,
-				    callback,
-				    callback_data );
+SWIGINTERN CPLErr GDALRasterBandShadow_ContourGenerate(GDALRasterBandShadow *self,double dfContourInterval,double dfContourBase,int nFixedLevelCount,double *padfFixedLevels,int bUseNoData,double dfNoDataValue,OGRLayerShadow *hLayer,int iIDField,int iElevField,GDALProgressFunc progress=NULL,void *progress_data=NULL){
+        return GDALContourGenerate( self, dfContourInterval, dfContourBase,
+                                    nFixedLevelCount, padfFixedLevels,
+                                    bUseNoData, dfNoDataValue,
+                                    hLayer, iIDField, iElevField,
+                                    progress,
+                                    progress_data );
     }
 
 GDALDataType GDALRasterBandShadow_DataType_get( GDALRasterBandShadow *h ) {
@@ -3051,6 +3054,9 @@ SWIGINTERN int GDALRasterAttributeTableShadow_GetRowOfValue(GDALRasterAttributeT
 SWIGINTERN int GDALRasterAttributeTableShadow_ChangesAreWrittenToFile(GDALRasterAttributeTableShadow *self){
         return GDALRATChangesAreWrittenToFile( self );
     }
+SWIGINTERN void GDALRasterAttributeTableShadow_DumpReadable(GDALRasterAttributeTableShadow *self){
+        GDALRATDumpReadable( self, NULL );
+    }
 
 #include "gdalgrid.h"
 
@@ -3241,6 +3247,20 @@ int  SieveFilter( GDALRasterBandShadow *srcBand,
 }
 
 
+int  RegenerateOverviews( GDALRasterBandShadow *srcBand,
+     			  int overviewBandCount,
+                          GDALRasterBandShadow **overviewBands,
+                          const char *resampling = "average",
+                          GDALProgressFunc callback=NULL,
+                          void* callback_data=NULL) {
+
+    CPLErrorReset();
+
+    return GDALRegenerateOverviews( srcBand, overviewBandCount, overviewBands,
+    	   			    resampling ? resampling : "average", callback, callback_data );
+}
+
+
 int  RegenerateOverview( GDALRasterBandShadow *srcBand,
                           GDALRasterBandShadow *overviewBand,
                           const char *resampling = "average",
@@ -3394,9 +3414,9 @@ static AV *XMLTreeToAV( CPLXMLNode *psTree )
          psChild != NULL; 
          psChild = psChild->psNext, iChild++ )
     {
-	SV *s = newRV((SV*)XMLTreeToAV(psChild));
-	if (!av_store(av, iChild, s))
-	    SvREFCNT_dec(s);
+        SV *s = newRV((SV*)XMLTreeToAV(psChild));
+        if (!av_store(av, iChild, s))
+            SvREFCNT_dec(s);
     }
 
     return av;
@@ -3406,16 +3426,18 @@ static AV *XMLTreeToAV( CPLXMLNode *psTree )
 /************************************************************************/
 /*                          AVToXMLTree()                               */
 /************************************************************************/
-static CPLXMLNode *AVToXMLTree( AV *av )
+  static CPLXMLNode *AVToXMLTree( AV *av, int *err )
 {
     int      nChildCount = 0, iChild, nType;
     CPLXMLNode *psThisNode;
     char       *pszText = NULL;
     
     nChildCount = av_len(av) - 1; /* there are two non-childs in the array */
-    if (nChildCount < 0)
+    if (nChildCount < 0) {
         /* the input XML is empty */
-	return NULL;
+        *err = 1;
+        return NULL;
+    }
 
     nType = SvIV(*(av_fetch(av,0,0)));
     SV *sv = *(av_fetch(av,1,0));
@@ -3425,25 +3447,37 @@ static CPLXMLNode *AVToXMLTree( AV *av )
     
     for( iChild = 0; iChild < nChildCount; iChild++ )
     {
-	SV **s = av_fetch(av, iChild+2, 0);
-	CPLXMLNode *psChild;
-	if (!(SvROK(*s) && (SvTYPE(SvRV(*s))==SVt_PVAV)))
-	    /* expected a reference to an array */
-	    psChild = NULL;
-	else
-	    psChild = AVToXMLTree((AV*)SvRV(*s));
-	if (psChild)
-	    CPLAddXMLChild( psThisNode, psChild );
-	else {
-	    CPLDestroyXMLNode(psThisNode);
-	    return NULL;
-	}
+        SV **s = av_fetch(av, iChild+2, 0);
+        CPLXMLNode *psChild;
+        if (!(SvROK(*s) && (SvTYPE(SvRV(*s))==SVt_PVAV))) {
+            /* expected a reference to an array */
+            *err = 2;
+            psChild = NULL;
+        } else
+            psChild = AVToXMLTree((AV*)SvRV(*s), err);
+        if (psChild)
+            CPLAddXMLChild( psThisNode, psChild );
+        else {
+            CPLDestroyXMLNode(psThisNode);
+            return NULL;
+        }
     }
 
     return psThisNode;
 }
 
 
+retStringAndCPLFree *GetJPEG2000StructureAsString( const char* pszFilename, char** options = NULL )
+{
+    CPLXMLNode* psNode = GDALGetJPEG2000Structure(pszFilename, options);
+    if( psNode == NULL )
+        return NULL;
+    char* pszXML = CPLSerializeXMLTree(psNode);
+    CPLDestroyXMLNode(psNode);
+    return pszXML;
+}
+
+
 int GetDriverCount() {
   return GDALGetDriverCount();
 }
@@ -3472,6 +3506,38 @@ GDALDatasetShadow* Open( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly
 }
 
 
+GDALDatasetShadow* OpenEx( char const* utf8_path, unsigned int nOpenFlags = 0,
+                           char** allowed_drivers = NULL, char** open_options = NULL,
+                           char** sibling_files = NULL ) {
+  CPLErrorReset();
+  GDALDatasetShadow *ds = GDALOpenEx( utf8_path, nOpenFlags, allowed_drivers,
+                                      open_options, sibling_files );
+  if( ds != NULL && CPLGetLastErrorType() == CE_Failure )
+  {
+      if ( GDALDereferenceDataset( ds ) <= 0 )
+          GDALClose(ds);
+      ds = NULL;
+  }
+  return (GDALDatasetShadow*) ds;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_unsigned_SS_int SWIG_PERL_DECL_ARGS_2(SV * obj, unsigned int *val)
+{
+  unsigned long v;
+  int res = SWIG_AsVal_unsigned_SS_long SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v > UINT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = static_cast< unsigned int >(v);
+    }
+  }  
+  return res;
+}
+
+
 GDALDatasetShadow* OpenShared( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly ) {
   CPLErrorReset();
   GDALDatasetShadow *ds = GDALOpenShared( utf8_path, eAccess );
@@ -4304,7 +4370,7 @@ XS(_wrap_EscapeString) {
       /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
       if (SvOK(ST(0))) {
         if (!SvPOK(ST(0)))
-        SWIG_croak("expected binary data as input");
+        SWIG_croak("Expected binary data.");
         STRLEN len = SvCUR(ST(0));
         arg2 = SvPV_nolen(ST(0));
         arg1 = len;
@@ -5049,7 +5115,7 @@ XS(_wrap_CPLBinaryToHex) {
       /* %typemap(in,numinputs=1) (int nLen, unsigned char *pBuf ) */
       if (SvOK(ST(0))) {
         if (!SvPOK(ST(0)))
-        SWIG_croak("expected binary data as input to a Geo::GDAL method");
+        SWIG_croak("Expected binary data.");
         STRLEN len = SvCUR(ST(0));
         arg2 = (unsigned char *)SvPV_nolen(ST(0));
         arg1 = len;
@@ -5109,25 +5175,23 @@ XS(_wrap_CPLHexToBinary) {
     int res1 ;
     char *buf1 = 0 ;
     int alloc1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    int bytes2 ;
     int argvi = 0;
     GByte *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: CPLHexToBinary(pszHex,pnBytes);");
+    {
+      /* %typemap(in,numinputs=0) (int *pnBytes) (int bytes2) */
+      arg2 = &bytes2;
+    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: CPLHexToBinary(pszHex);");
     }
     res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
     if (!SWIG_IsOK(res1)) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CPLHexToBinary" "', argument " "1"" of type '" "char const *""'");
     }
     arg1 = reinterpret_cast< char * >(buf1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_int, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CPLHexToBinary" "', argument " "2"" of type '" "int *""'"); 
-    }
-    arg2 = reinterpret_cast< int * >(argp2);
     {
       CPLErrorReset();
       result = (GByte *)CPLHexToBinary((char const *)arg1,arg2);
@@ -5152,7 +5216,13 @@ XS(_wrap_CPLHexToBinary) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GByte, 0 | 0); argvi++ ;
+    {
+      /* %typemap(out) GByte * */
+      ST(argvi) = sv_newmortal();
+      sv_setpvn(ST(argvi), (const char*)result, *arg2);
+      CPLFree(result);
+      argvi++;
+    }
     if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
     
     XSRETURN(argvi);
@@ -5670,7 +5740,7 @@ XS(_wrap_VSIFOpenL) {
     }
     {
       CPLErrorReset();
-      result = (VSILFILE *)VSIFOpenL((char const *)arg1,(char const *)arg2);
+      result = (VSILFILE *)wrapper_VSIFOpenL((char const *)arg1,(char const *)arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -6006,7 +6076,9 @@ XS(_wrap_VSIFReadL) {
     {
       /* %typemap(in,numinputs=1) (void *pBuffer, size_t nSize, size_t nCount) */
       size_t len = SvIV(ST(0));
-      arg1 = malloc(len);
+      arg1 = CPLMalloc(len);
+      if (!arg1)
+      SWIG_fail;
       arg2 = 1;
       arg3 = len;
     }
@@ -6049,6 +6121,7 @@ XS(_wrap_VSIFReadL) {
       } else {
         ST(argvi) = &PL_sv_undef;
       }
+      CPLFree(arg1);
       argvi++;
     }
     
@@ -7057,9 +7130,9 @@ XS(_wrap_Driver__Create) {
                 arg7 = CSLAddNameValue( arg7, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -7200,9 +7273,9 @@ XS(_wrap_Driver_CreateCopy) {
                 arg5 = CSLAddNameValue( arg5, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -7295,7 +7368,7 @@ XS(_wrap_Driver_Delete) {
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    int result;
+    CPLErr result;
     dXSARGS;
     
     {
@@ -7324,7 +7397,7 @@ XS(_wrap_Driver_Delete) {
     }
     {
       CPLErrorReset();
-      result = (int)GDALDriverShadow_Delete(arg1,(char const *)arg2);
+      result = (CPLErr)GDALDriverShadow_Delete(arg1,(char const *)arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -7346,7 +7419,9 @@ XS(_wrap_Driver_Delete) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) CPLErr */
+    }
     
     XSRETURN(argvi);
   fail:
@@ -7370,7 +7445,7 @@ XS(_wrap_Driver_Rename) {
     char *buf3 = 0 ;
     int alloc3 = 0 ;
     int argvi = 0;
-    int result;
+    CPLErr result;
     dXSARGS;
     
     if ((items < 3) || (items > 3)) {
@@ -7403,7 +7478,7 @@ XS(_wrap_Driver_Rename) {
     }
     {
       CPLErrorReset();
-      result = (int)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
+      result = (CPLErr)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -7425,7 +7500,9 @@ XS(_wrap_Driver_Rename) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) CPLErr */
+    }
     
     if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
@@ -7453,7 +7530,7 @@ XS(_wrap_Driver_CopyFiles) {
     char *buf3 = 0 ;
     int alloc3 = 0 ;
     int argvi = 0;
-    int result;
+    CPLErr result;
     dXSARGS;
     
     if ((items < 3) || (items > 3)) {
@@ -7486,7 +7563,7 @@ XS(_wrap_Driver_CopyFiles) {
     }
     {
       CPLErrorReset();
-      result = (int)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
+      result = (CPLErr)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -7508,7 +7585,9 @@ XS(_wrap_Driver_CopyFiles) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) CPLErr */
+    }
     
     if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
@@ -7625,7 +7704,7 @@ XS(_wrap_Driver_Deregister) {
 }
 
 
-XS(_wrap_GCP_GCPX_set) {
+XS(_wrap_GCP_X_set) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     double arg2 ;
@@ -7637,16 +7716,16 @@ XS(_wrap_GCP_GCPX_set) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GCP_GCPX_set(self,GCPX);");
+      SWIG_croak("Usage: GCP_X_set(self,GCPX);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPX_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_X_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_GCPX_set" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_X_set" "', argument " "2"" of type '" "double""'");
     } 
     arg2 = static_cast< double >(val2);
     {
@@ -7687,7 +7766,7 @@ XS(_wrap_GCP_GCPX_set) {
 }
 
 
-XS(_wrap_GCP_GCPX_get) {
+XS(_wrap_GCP_X_get) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     void *argp1 = 0 ;
@@ -7697,11 +7776,11 @@ XS(_wrap_GCP_GCPX_get) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GCP_GCPX_get(self);");
+      SWIG_croak("Usage: GCP_X_get(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPX_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_X_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
@@ -7738,7 +7817,7 @@ XS(_wrap_GCP_GCPX_get) {
 }
 
 
-XS(_wrap_GCP_GCPY_set) {
+XS(_wrap_GCP_Y_set) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     double arg2 ;
@@ -7750,16 +7829,16 @@ XS(_wrap_GCP_GCPY_set) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GCP_GCPY_set(self,GCPY);");
+      SWIG_croak("Usage: GCP_Y_set(self,GCPY);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPY_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Y_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_GCPY_set" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_Y_set" "', argument " "2"" of type '" "double""'");
     } 
     arg2 = static_cast< double >(val2);
     {
@@ -7800,7 +7879,7 @@ XS(_wrap_GCP_GCPY_set) {
 }
 
 
-XS(_wrap_GCP_GCPY_get) {
+XS(_wrap_GCP_Y_get) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     void *argp1 = 0 ;
@@ -7810,11 +7889,11 @@ XS(_wrap_GCP_GCPY_get) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GCP_GCPY_get(self);");
+      SWIG_croak("Usage: GCP_Y_get(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPY_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Y_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
@@ -7851,7 +7930,7 @@ XS(_wrap_GCP_GCPY_get) {
 }
 
 
-XS(_wrap_GCP_GCPZ_set) {
+XS(_wrap_GCP_Z_set) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     double arg2 ;
@@ -7863,16 +7942,16 @@ XS(_wrap_GCP_GCPZ_set) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GCP_GCPZ_set(self,GCPZ);");
+      SWIG_croak("Usage: GCP_Z_set(self,GCPZ);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPZ_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Z_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_GCPZ_set" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_Z_set" "', argument " "2"" of type '" "double""'");
     } 
     arg2 = static_cast< double >(val2);
     {
@@ -7913,7 +7992,7 @@ XS(_wrap_GCP_GCPZ_set) {
 }
 
 
-XS(_wrap_GCP_GCPZ_get) {
+XS(_wrap_GCP_Z_get) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     void *argp1 = 0 ;
@@ -7923,11 +8002,11 @@ XS(_wrap_GCP_GCPZ_get) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GCP_GCPZ_get(self);");
+      SWIG_croak("Usage: GCP_Z_get(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPZ_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Z_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
@@ -7964,7 +8043,7 @@ XS(_wrap_GCP_GCPZ_get) {
 }
 
 
-XS(_wrap_GCP_GCPPixel_set) {
+XS(_wrap_GCP_Column_set) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     double arg2 ;
@@ -7976,16 +8055,16 @@ XS(_wrap_GCP_GCPPixel_set) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GCP_GCPPixel_set(self,GCPPixel);");
+      SWIG_croak("Usage: GCP_Column_set(self,GCPPixel);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPPixel_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Column_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_GCPPixel_set" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_Column_set" "', argument " "2"" of type '" "double""'");
     } 
     arg2 = static_cast< double >(val2);
     {
@@ -8026,7 +8105,7 @@ XS(_wrap_GCP_GCPPixel_set) {
 }
 
 
-XS(_wrap_GCP_GCPPixel_get) {
+XS(_wrap_GCP_Column_get) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     void *argp1 = 0 ;
@@ -8036,11 +8115,11 @@ XS(_wrap_GCP_GCPPixel_get) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GCP_GCPPixel_get(self);");
+      SWIG_croak("Usage: GCP_Column_get(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPPixel_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Column_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
@@ -8077,7 +8156,7 @@ XS(_wrap_GCP_GCPPixel_get) {
 }
 
 
-XS(_wrap_GCP_GCPLine_set) {
+XS(_wrap_GCP_Row_set) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     double arg2 ;
@@ -8089,16 +8168,16 @@ XS(_wrap_GCP_GCPLine_set) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GCP_GCPLine_set(self,GCPLine);");
+      SWIG_croak("Usage: GCP_Row_set(self,GCPLine);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPLine_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Row_set" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_GCPLine_set" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GCP_Row_set" "', argument " "2"" of type '" "double""'");
     } 
     arg2 = static_cast< double >(val2);
     {
@@ -8139,7 +8218,7 @@ XS(_wrap_GCP_GCPLine_set) {
 }
 
 
-XS(_wrap_GCP_GCPLine_get) {
+XS(_wrap_GCP_Row_get) {
   {
     GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
     void *argp1 = 0 ;
@@ -8149,11 +8228,11 @@ XS(_wrap_GCP_GCPLine_get) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GCP_GCPLine_get(self);");
+      SWIG_croak("Usage: GCP_Row_get(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_GCPLine_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GCP_Row_get" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
     }
     arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
@@ -9472,31 +9551,53 @@ XS(_wrap_GDAL_GCP_Id_set) {
 }
 
 
-XS(_wrap_GDAL_GCP_get_GCPX) {
+XS(_wrap_GCPsToGeoTransform) {
   {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    int arg1 ;
+    GDAL_GCP *arg2 = (GDAL_GCP *) 0 ;
+    double *arg3 ;
+    int arg4 = (int) 1 ;
+    double argout3[6] ;
+    int val4 ;
+    int ecode4 = 0 ;
     int argvi = 0;
-    double result;
+    RETURN_NONE result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_GCPX(gcp);");
+    {
+      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+      arg3 = argout3;
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPX" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: GCPsToGeoTransform(nGCPs,pGCPs,bApproxOK);");
     }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
     {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
+      /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
+      if (!(SvROK(ST(0)) && (SvTYPE(SvRV(ST(0)))==SVt_PVAV)))
+      SWIG_croak("Expected a reference to an array.");
+      AV *av = (AV*)(SvRV(ST(0)));
+      arg1 = av_len(av)+1;
+      arg2 = (GDAL_GCP *)CPLMalloc(arg1*sizeof(GDAL_GCP));
+      if (arg2) {
+        for (int i = 0; i < arg1; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          int ret = SWIG_ConvertPtr(*sv, (void**)&(arg2[i]), SWIGTYPE_p_GDAL_GCP, 0);
+          if (!SWIG_IsOK(ret))
+          SWIG_croak("An item in the argument array is not a GCP object.");
+        }
+      } else
+      SWIG_croak("Out of memory.");
+    }
+    if (items > 1) {
+      ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GCPsToGeoTransform" "', argument " "4"" of type '" "int""'");
+      } 
+      arg4 = static_cast< int >(val4);
     }
     {
       CPLErrorReset();
-      result = (double)GDAL_GCP_get_GCPX(arg1);
+      result = GDALGCPsToGeoTransform(arg1,(GDAL_GCP const *)arg2,arg3,arg4);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -9518,48 +9619,66 @@ XS(_wrap_GDAL_GCP_get_GCPX) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    {
+      /* %typemap(out) IF_FALSE_RETURN_NONE */
+    }
+    {
+      /* %typemap(argout) (double argout[ANY]) */
+      if (GIMME_V == G_ARRAY) {
+        /* return a list */
+        int i;
+        EXTEND(SP, argvi+6-items+1);
+        for (i = 0; i < 6; i++)
+        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
+      } else {
+        ST(argvi) = CreateArrayFromDoubleArray( arg3, 6 );
+        argvi++;
+      }  
+    }
+    {
+      /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+      CPLFree(arg2);
+    }
     
+    
+    {
+      /* %typemap(ret) IF_FALSE_RETURN_NONE */
+      if (result == 0 ) {
+        SWIG_croak("unexpected error in 'GCPsToGeoTransform'");
+      }
+    }
     XSRETURN(argvi);
   fail:
+    {
+      /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+      CPLFree(arg2);
+    }
+    
     
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GDAL_GCP_set_GCPX) {
+XS(_wrap_delete_AsyncReader) {
   {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    double arg2 ;
+    GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_GCPX(gcp,dfGCPX);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_AsyncReader(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_DISOWN |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPX" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPX" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_AsyncReader" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
     }
+    arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
     {
       CPLErrorReset();
-      GDAL_GCP_set_GCPX(arg1,arg2);
+      delete_GDALAsyncReaderShadow(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -9585,941 +9704,22 @@ XS(_wrap_GDAL_GCP_set_GCPX) {
       /* %typemap(out) void */
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GDAL_GCP_get_GCPY) {
+XS(_wrap_AsyncReader_GetNextUpdatedRegion) {
   {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    double result;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_GCPY(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPY" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (double)GDAL_GCP_get_GCPY(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_GCPY) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    double arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_GCPY(gcp,dfGCPY);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPY" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPY" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_GCPY(arg1,arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    XSRETURN(argvi);
-  fail:
-    
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_get_GCPZ) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    double result;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_GCPZ(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPZ" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (double)GDAL_GCP_get_GCPZ(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_GCPZ) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    double arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_GCPZ(gcp,dfGCPZ);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPZ" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPZ" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_GCPZ(arg1,arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    XSRETURN(argvi);
-  fail:
-    
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_get_GCPPixel) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    double result;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_GCPPixel(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPPixel" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (double)GDAL_GCP_get_GCPPixel(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_GCPPixel) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    double arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_GCPPixel(gcp,dfGCPPixel);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPPixel" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPPixel" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_GCPPixel(arg1,arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    XSRETURN(argvi);
-  fail:
-    
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_get_GCPLine) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    double result;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_GCPLine(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPLine" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (double)GDAL_GCP_get_GCPLine(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_GCPLine) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    double arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_GCPLine(gcp,dfGCPLine);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPLine" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPLine" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_GCPLine(arg1,arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    XSRETURN(argvi);
-  fail:
-    
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_get_Info) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    char *result = 0 ;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_Info(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_Info" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (char *)GDAL_GCP_get_Info(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_Info) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    char *arg2 = (char *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int res2 ;
-    char *buf2 = 0 ;
-    int alloc2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_Info(gcp,pszInfo);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_Info" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GDAL_GCP_set_Info" "', argument " "2"" of type '" "char const *""'");
-    }
-    arg2 = reinterpret_cast< char * >(buf2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_Info(arg1,(char const *)arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    XSRETURN(argvi);
-  fail:
-    
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_get_Id) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    char *result = 0 ;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GDAL_GCP_get_Id(gcp);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_Id" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      result = (char *)GDAL_GCP_get_Id(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GDAL_GCP_set_Id) {
-  {
-    GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-    char *arg2 = (char *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int res2 ;
-    char *buf2 = 0 ;
-    int alloc2 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GDAL_GCP_set_Id(gcp,pszId);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_Id" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-    }
-    arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GDAL_GCP_set_Id" "', argument " "2"" of type '" "char const *""'");
-    }
-    arg2 = reinterpret_cast< char * >(buf2);
-    {
-      if (!arg1) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
-    {
-      CPLErrorReset();
-      GDAL_GCP_set_Id(arg1,(char const *)arg2);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    XSRETURN(argvi);
-  fail:
-    
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_GCPsToGeoTransform) {
-  {
-    int arg1 ;
-    GDAL_GCP *arg2 = (GDAL_GCP *) 0 ;
-    double *arg3 ;
-    int arg4 = (int) 1 ;
-    GDAL_GCP *tmpGCPList1 ;
-    double argout3[6] ;
-    int val4 ;
-    int ecode4 = 0 ;
-    int argvi = 0;
-    RETURN_NONE result;
-    dXSARGS;
-    
-    {
-      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-      arg3 = argout3;
-    }
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: GCPsToGeoTransform(nGCPs,pGCPs,bApproxOK);");
-    }
-    {
-      /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
-      if (!(SvROK(ST(0)) && (SvTYPE(SvRV(ST(0)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
-      AV *av = (AV*)(SvRV(ST(0)));
-      arg1 = av_len(av)+1;
-      tmpGCPList1 = (GDAL_GCP*) malloc(arg1*sizeof(GDAL_GCP));
-      arg2 = tmpGCPList1;
-      for( int i = 0; i<arg1; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        GDAL_GCP *item = 0;
-        SWIG_ConvertPtr( *sv, (void**)&item, SWIGTYPE_p_GDAL_GCP, 0 );
-        if (!item )
-        SWIG_fail;
-        memcpy( (void*) tmpGCPList1, (void*) item, sizeof( GDAL_GCP ) );
-        ++tmpGCPList1;
-      }
-    }
-    if (items > 1) {
-      ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val4);
-      if (!SWIG_IsOK(ecode4)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GCPsToGeoTransform" "', argument " "4"" of type '" "int""'");
-      } 
-      arg4 = static_cast< int >(val4);
-    }
-    {
-      CPLErrorReset();
-      result = GDALGCPsToGeoTransform(arg1,(GDAL_GCP const *)arg2,arg3,arg4);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) IF_FALSE_RETURN_NONE */
-    }
-    {
-      /* %typemap(argout) (double argout[ANY]) */
-      if (GIMME_V == G_ARRAY) {
-        /* return a list */
-        int i;
-        EXTEND(SP, argvi+6-items+1);
-        for (i = 0; i < 6; i++)
-        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
-      } else {
-        ST(argvi) = CreateArrayFromDoubleArray( arg3, 6 );
-        argvi++;
-      }  
-    }
-    {
-      /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-      if (arg2)
-      free(arg2);
-    }
-    
-    
-    {
-      /* %typemap(ret) IF_FALSE_RETURN_NONE */
-      if (result == 0 ) {
-        SWIG_croak("unexpected error in 'GCPsToGeoTransform'");
-      }
-    }
-    XSRETURN(argvi);
-  fail:
-    {
-      /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-      if (arg2)
-      free(arg2);
-    }
-    
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_delete_AsyncReader) {
-  {
-    GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: delete_AsyncReader(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_DISOWN |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_AsyncReader" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
-    {
-      CPLErrorReset();
-      delete_GDALAsyncReaderShadow(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    {
-      /* %typemap(out) void */
-    }
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap_AsyncReader_GetNextUpdatedRegion) {
-  {
-    GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
-    double arg2 ;
-    int *arg3 = (int *) 0 ;
-    int *arg4 = (int *) 0 ;
-    int *arg5 = (int *) 0 ;
-    int *arg6 = (int *) 0 ;
+    GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
+    double arg2 ;
+    int *arg3 = (int *) 0 ;
+    int *arg4 = (int *) 0 ;
+    int *arg5 = (int *) 0 ;
+    int *arg6 = (int *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     double val2 ;
@@ -11329,7 +10529,7 @@ XS(_wrap_Dataset_SetGeoTransform) {
     {
       /* %typemap(in) (double argin2[ANY]) */
       if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       arg2 = argin2;
       AV *av = (AV*)(SvRV(ST(1)));
       for (unsigned int i=0; i<6; i++) {
@@ -11375,7 +10575,7 @@ XS(_wrap_Dataset_SetGeoTransform) {
 }
 
 
-XS(_wrap_Dataset_BuildOverviews) {
+XS(_wrap_Dataset__BuildOverviews) {
   {
     GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
     char *arg2 = (char *) "NEAREST" ;
@@ -11398,17 +10598,17 @@ XS(_wrap_Dataset_BuildOverviews) {
     saved_env.data = &PL_sv_undef;
     arg6 = (void *)(&saved_env);
     if ((items < 1) || (items > 5)) {
-      SWIG_croak("Usage: Dataset_BuildOverviews(self,resampling,overviewlist,pOverviews,callback,callback_data);");
+      SWIG_croak("Usage: Dataset__BuildOverviews(self,resampling,overviewlist,pOverviews,callback,callback_data);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_BuildOverviews" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset__BuildOverviews" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     if (items > 1) {
       res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
       if (!SWIG_IsOK(res2)) {
-        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_BuildOverviews" "', argument " "2"" of type '" "char const *""'");
+        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset__BuildOverviews" "', argument " "2"" of type '" "char const *""'");
       }
       arg2 = reinterpret_cast< char * >(buf2);
     }
@@ -11416,14 +10616,17 @@ XS(_wrap_Dataset_BuildOverviews) {
       {
         /* %typemap(in,numinputs=1) (int nList, int* pList) */
         if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         AV *av = (AV*)(SvRV(ST(2)));
         arg3 = av_len(av)+1;
-        arg4 = (int*) malloc(arg3*sizeof(int));
-        for( int i = 0; i<arg3; i++ ) {
-          SV **sv = av_fetch(av, i, 0);
-          arg4[i] =  SvIV(*sv);
-        }
+        arg4 = (int*)CPLMalloc(arg3*sizeof(int));
+        if (arg4) {
+          for( int i = 0; i<arg3; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            arg4[i] =  SvIV(*sv);
+          }
+        } else
+        SWIG_fail;
       }
     }
     if (items > 3) {
@@ -11479,8 +10682,7 @@ XS(_wrap_Dataset_BuildOverviews) {
     if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     
     XSRETURN(argvi);
@@ -11489,8 +10691,7 @@ XS(_wrap_Dataset_BuildOverviews) {
     if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     
     SWIG_croak_null();
@@ -11693,7 +10894,6 @@ XS(_wrap_Dataset_SetGCPs) {
     char *arg4 = (char *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    GDAL_GCP *tmpGCPList2 ;
     int res4 ;
     char *buf4 = 0 ;
     int alloc4 = 0 ;
@@ -11712,20 +10912,19 @@ XS(_wrap_Dataset_SetGCPs) {
     {
       /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
       if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(1)));
       arg2 = av_len(av)+1;
-      tmpGCPList2 = (GDAL_GCP*) malloc(arg2*sizeof(GDAL_GCP));
-      arg3 = tmpGCPList2;
-      for( int i = 0; i<arg2; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        GDAL_GCP *item = 0;
-        SWIG_ConvertPtr( *sv, (void**)&item, SWIGTYPE_p_GDAL_GCP, 0 );
-        if (!item )
-        SWIG_fail;
-        memcpy( (void*) tmpGCPList2, (void*) item, sizeof( GDAL_GCP ) );
-        ++tmpGCPList2;
-      }
+      arg3 = (GDAL_GCP *)CPLMalloc(arg2*sizeof(GDAL_GCP));
+      if (arg3) {
+        for (int i = 0; i < arg2; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          int ret = SWIG_ConvertPtr(*sv, (void**)&(arg3[i]), SWIGTYPE_p_GDAL_GCP, 0);
+          if (!SWIG_IsOK(ret))
+          SWIG_croak("An item in the argument array is not a GCP object.");
+        }
+      } else
+      SWIG_croak("Out of memory.");
     }
     res4 = SWIG_AsCharPtrAndSize(ST(2), &buf4, NULL, &alloc4);
     if (!SWIG_IsOK(res4)) {
@@ -11762,8 +10961,7 @@ XS(_wrap_Dataset_SetGCPs) {
     
     {
       /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-      if (arg3)
-      free(arg3);
+      CPLFree(arg3);
     }
     if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
     XSRETURN(argvi);
@@ -11771,8 +10969,7 @@ XS(_wrap_Dataset_SetGCPs) {
     
     {
       /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-      if (arg3)
-      free(arg3);
+      CPLFree(arg3);
     }
     if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
     SWIG_croak_null();
@@ -11885,9 +11082,9 @@ XS(_wrap_Dataset__AddBand) {
                 arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -11937,7 +11134,7 @@ XS(_wrap_Dataset__AddBand) {
 }
 
 
-XS(_wrap_Dataset_CreateMaskBand) {
+XS(_wrap_Dataset__CreateMaskBand) {
   {
     GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
     int arg2 ;
@@ -11950,16 +11147,16 @@ XS(_wrap_Dataset_CreateMaskBand) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Dataset_CreateMaskBand(self,nFlags);");
+      SWIG_croak("Usage: Dataset__CreateMaskBand(self,nFlags);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CreateMaskBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset__CreateMaskBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_CreateMaskBand" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset__CreateMaskBand" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     {
@@ -12080,7 +11277,7 @@ XS(_wrap_Dataset_GetFileList) {
 }
 
 
-XS(_wrap_Dataset_WriteRaster) {
+XS(_wrap_Dataset__WriteRaster) {
   {
     GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
     int arg2 ;
@@ -12118,38 +11315,38 @@ XS(_wrap_Dataset_WriteRaster) {
     dXSARGS;
     
     if ((items < 6) || (items > 13)) {
-      SWIG_croak("Usage: Dataset_WriteRaster(self,xoff,yoff,xsize,ysize,buf_len,buf_string,buf_xsize,buf_ysize,buf_type,band_list,pband_list,buf_pixel_space,buf_line_space,buf_band_space);");
+      SWIG_croak("Usage: Dataset__WriteRaster(self,xoff,yoff,xsize,ysize,buf_len,buf_string,buf_xsize,buf_ysize,buf_type,band_list,pband_list,buf_pixel_space,buf_line_space,buf_band_space);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_WriteRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset__WriteRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_WriteRaster" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset__WriteRaster" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
     if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_WriteRaster" "', argument " "3"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset__WriteRaster" "', argument " "3"" of type '" "int""'");
     } 
     arg3 = static_cast< int >(val3);
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_WriteRaster" "', argument " "4"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset__WriteRaster" "', argument " "4"" of type '" "int""'");
     } 
     arg4 = static_cast< int >(val4);
     ecode5 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
     if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_WriteRaster" "', argument " "5"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset__WriteRaster" "', argument " "5"" of type '" "int""'");
     } 
     arg5 = static_cast< int >(val5);
     {
       /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
       if (SvOK(ST(5))) {
         if (!SvPOK(ST(5)))
-        SWIG_croak("expected binary data as input");
+        SWIG_croak("Expected binary data.");
         STRLEN len = SvCUR(ST(5));
         arg7 = SvPV_nolen(ST(5));
         arg6 = len;
@@ -12198,14 +11395,17 @@ XS(_wrap_Dataset_WriteRaster) {
       {
         /* %typemap(in,numinputs=1) (int nList, int* pList) */
         if (!(SvROK(ST(9)) && (SvTYPE(SvRV(ST(9)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         AV *av = (AV*)(SvRV(ST(9)));
         arg11 = av_len(av)+1;
-        arg12 = (int*) malloc(arg11*sizeof(int));
-        for( int i = 0; i<arg11; i++ ) {
-          SV **sv = av_fetch(av, i, 0);
-          arg12[i] =  SvIV(*sv);
-        }
+        arg12 = (int*)CPLMalloc(arg11*sizeof(int));
+        if (arg12) {
+          for( int i = 0; i<arg11; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            arg12[i] =  SvIV(*sv);
+          }
+        } else
+        SWIG_fail;
       }
     }
     if (items > 10) {
@@ -12281,8 +11481,7 @@ XS(_wrap_Dataset_WriteRaster) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg12)
-      free((void*) arg12);
+      CPLFree((void*) arg12);
     }
     
     
@@ -12299,8 +11498,7 @@ XS(_wrap_Dataset_WriteRaster) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg12)
-      free((void*) arg12);
+      CPLFree((void*) arg12);
     }
     
     
@@ -12310,7 +11508,7 @@ XS(_wrap_Dataset_WriteRaster) {
 }
 
 
-XS(_wrap_Dataset_ReadRaster) {
+XS(_wrap_Dataset__ReadRaster) {
   {
     GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
     int arg2 ;
@@ -12327,6 +11525,9 @@ XS(_wrap_Dataset_ReadRaster) {
     int *arg13 = (int *) 0 ;
     int *arg14 = (int *) 0 ;
     int *arg15 = (int *) 0 ;
+    GDALRIOResampleAlg arg16 = (GDALRIOResampleAlg) GRIORA_NearestNeighbour ;
+    GDALProgressFunc arg17 = (GDALProgressFunc) NULL ;
+    void *arg18 = (void *) NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
@@ -12345,41 +11546,48 @@ XS(_wrap_Dataset_ReadRaster) {
     int val13 ;
     int val14 ;
     int val15 ;
+    int val16 ;
+    int ecode16 = 0 ;
     int argvi = 0;
     CPLErr result;
     dXSARGS;
     
+    /* %typemap(arginit, noblock=1) ( void* callback_data = NULL) */
+    SavedEnv saved_env;
+    saved_env.fct = NULL;
+    saved_env.data = &PL_sv_undef;
+    arg18 = (void *)(&saved_env);
     {
       /* %typemap(in,numinputs=0) (int *nLen6, char **pBuf6 ) */
       arg6 = &nLen6;
       arg7 = &pBuf6;
     }
-    if ((items < 5) || (items > 12)) {
-      SWIG_croak("Usage: Dataset_ReadRaster(self,xoff,yoff,xsize,ysize,buf,buf_xsize,buf_ysize,buf_type,band_list,pband_list,buf_pixel_space,buf_line_space,buf_band_space);");
+    if ((items < 5) || (items > 15)) {
+      SWIG_croak("Usage: Dataset__ReadRaster(self,xoff,yoff,xsize,ysize,buf,buf_xsize,buf_ysize,buf_type,band_list,pband_list,buf_pixel_space,buf_line_space,buf_band_space,resample_alg,callback,callback_data);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_ReadRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset__ReadRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_ReadRaster" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset__ReadRaster" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
     if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_ReadRaster" "', argument " "3"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset__ReadRaster" "', argument " "3"" of type '" "int""'");
     } 
     arg3 = static_cast< int >(val3);
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_ReadRaster" "', argument " "4"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset__ReadRaster" "', argument " "4"" of type '" "int""'");
     } 
     arg4 = static_cast< int >(val4);
     ecode5 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
     if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_ReadRaster" "', argument " "5"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset__ReadRaster" "', argument " "5"" of type '" "int""'");
     } 
     arg5 = static_cast< int >(val5);
     if (items > 5) {
@@ -12422,14 +11630,17 @@ XS(_wrap_Dataset_ReadRaster) {
       {
         /* %typemap(in,numinputs=1) (int nList, int* pList) */
         if (!(SvROK(ST(8)) && (SvTYPE(SvRV(ST(8)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         AV *av = (AV*)(SvRV(ST(8)));
         arg11 = av_len(av)+1;
-        arg12 = (int*) malloc(arg11*sizeof(int));
-        for( int i = 0; i<arg11; i++ ) {
-          SV **sv = av_fetch(av, i, 0);
-          arg12[i] =  SvIV(*sv);
-        }
+        arg12 = (int*)CPLMalloc(arg11*sizeof(int));
+        if (arg12) {
+          for( int i = 0; i<arg11; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            arg12[i] =  SvIV(*sv);
+          }
+        } else
+        SWIG_fail;
       }
     }
     if (items > 9) {
@@ -12456,21 +11667,164 @@ XS(_wrap_Dataset_ReadRaster) {
         }
       }
     }
-    if (items > 11) {
-      {
-        /* %typemap(in) (int *optional_int) */
-        if ( !SvOK(ST(11)) ) {
-          arg15 = 0;
-        }
-        else {
-          val15 = SvIV(ST(11));
-          arg15 = (int *)&val15;
-        }
-      }
+    if (items > 11) {
+      {
+        /* %typemap(in) (int *optional_int) */
+        if ( !SvOK(ST(11)) ) {
+          arg15 = 0;
+        }
+        else {
+          val15 = SvIV(ST(11));
+          arg15 = (int *)&val15;
+        }
+      }
+    }
+    if (items > 12) {
+      ecode16 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(12), &val16);
+      if (!SWIG_IsOK(ecode16)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode16), "in method '" "Dataset__ReadRaster" "', argument " "16"" of type '" "GDALRIOResampleAlg""'");
+      } 
+      arg16 = static_cast< GDALRIOResampleAlg >(val16);
+    }
+    if (items > 13) {
+      {
+        /* %typemap(in) (GDALProgressFunc callback = NULL) */
+        if (SvOK(ST(13))) {
+          if (SvROK(ST(13))) {
+            if (SvTYPE(SvRV(ST(13))) != SVt_PVCV) {
+              SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+            } else {
+              saved_env.fct = (SV *)ST(13);
+              arg17 = &callback_d_cp_vp;
+            }
+          } else {
+            SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+          }
+        }
+      }
+    }
+    if (items > 14) {
+      {
+        /* %typemap(in) (void* callback_data=NULL) */
+        if (SvOK(ST(14)))
+        saved_env.data = (SV *)ST(14);
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (CPLErr)GDALDatasetShadow_ReadRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17,arg18);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) CPLErr */
+    }
+    {
+      /* %typemap(argout) (int *nLen, char **pBuf ) */
+      ST(argvi) = sv_2mortal(newSVpv( *arg7, *arg6 ));
+      argvi++;
+    }
+    
+    
+    
+    
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg6 ) {
+        free( *arg7 );
+      }
+    }
+    
+    
+    
+    {
+      /* %typemap(freearg) (int nList, int* pList) */
+      CPLFree((void*) arg12);
+    }
+    
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg6 ) {
+        free( *arg7 );
+      }
+    }
+    
+    
+    
+    {
+      /* %typemap(freearg) (int nList, int* pList) */
+      CPLFree((void*) arg12);
+    }
+    
+    
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Dataset_StartTransaction) {
+  {
+    GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+    int arg2 = (int) FALSE ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Dataset_StartTransaction(self,force);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_StartTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_StartTransaction" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (CPLErr)GDALDatasetShadow_ReadRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
+      result = (OGRErr)GDALDatasetShadow_StartTransaction(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -12493,58 +11847,134 @@ XS(_wrap_Dataset_ReadRaster) {
       
     }
     {
-      /* %typemap(out) CPLErr */
-    }
-    {
-      /* %typemap(argout) (int *nLen, char **pBuf ) */
-      ST(argvi) = sv_2mortal(newSVpv( *arg7, *arg6 ));
-      argvi++;
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
     
+    XSRETURN(argvi);
+  fail:
     
     
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Dataset_CommitTransaction) {
+  {
+    GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
     
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Dataset_CommitTransaction(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CommitTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     {
-      /* %typemap(freearg) (int *nLen, char **pBuf ) */
-      if( *arg6 ) {
-        free( *arg7 );
+      CPLErrorReset();
+      result = (OGRErr)GDALDatasetShadow_CommitTransaction(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
       }
+      
+      
     }
-    
-    
-    
     {
-      /* %typemap(freearg) (int nList, int* pList) */
-      if (arg12)
-      free((void*) arg12);
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
-    
-    
     XSRETURN(argvi);
   fail:
     
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Dataset_RollbackTransaction) {
+  {
+    GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
     
-    
-    
-    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Dataset_RollbackTransaction(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RollbackTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
     {
-      /* %typemap(freearg) (int *nLen, char **pBuf ) */
-      if( *arg6 ) {
-        free( *arg7 );
+      CPLErrorReset();
+      result = (OGRErr)GDALDatasetShadow_RollbackTransaction(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
       }
+      
+      
     }
-    
-    
-    
     {
-      /* %typemap(freearg) (int nList, int* pList) */
-      if (arg12)
-      free((void*) arg12);
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
-    
+    XSRETURN(argvi);
+  fail:
     
     SWIG_croak_null();
   }
@@ -12704,6 +12134,57 @@ XS(_wrap_Band_DataType_get) {
 }
 
 
+XS(_wrap_Band_GetDataset) {
+  {
+    GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    GDALDatasetShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Band_GetDataset(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_GetDataset" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (GDALDatasetShadow *)GDALRasterBandShadow_GetDataset(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDatasetShadow, 0 | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_Band_GetBand) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
@@ -13113,10 +12594,20 @@ XS(_wrap_Band_GetNoDataValue) {
     }
     {
       /* %typemap(argout) (double *val, int *hasval) */
-      ST(argvi) = sv_newmortal();
-      if ( *arg3 )
-      sv_setnv(ST(argvi), *arg2);
-      argvi++;
+      if (GIMME_V == G_ARRAY) {
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), *arg2);
+        argvi++;
+        ST(argvi) = sv_newmortal();
+        sv_setiv(ST(argvi), *arg3);
+        argvi++;
+      } else {
+        if ( *arg3 ) {
+          ST(argvi) = sv_newmortal();
+          sv_setnv(ST(argvi), *arg2);
+          argvi++;
+        }
+      }
     }
     
     XSRETURN(argvi);
@@ -13420,9 +12911,9 @@ XS(_wrap_Band_SetRasterCategoryNames) {
               arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -13523,10 +13014,20 @@ XS(_wrap_Band_GetMinimum) {
     }
     {
       /* %typemap(argout) (double *val, int *hasval) */
-      ST(argvi) = sv_newmortal();
-      if ( *arg3 )
-      sv_setnv(ST(argvi), *arg2);
-      argvi++;
+      if (GIMME_V == G_ARRAY) {
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), *arg2);
+        argvi++;
+        ST(argvi) = sv_newmortal();
+        sv_setiv(ST(argvi), *arg3);
+        argvi++;
+      } else {
+        if ( *arg3 ) {
+          ST(argvi) = sv_newmortal();
+          sv_setnv(ST(argvi), *arg2);
+          argvi++;
+        }
+      }
     }
     
     XSRETURN(argvi);
@@ -13591,10 +13092,20 @@ XS(_wrap_Band_GetMaximum) {
     }
     {
       /* %typemap(argout) (double *val, int *hasval) */
-      ST(argvi) = sv_newmortal();
-      if ( *arg3 )
-      sv_setnv(ST(argvi), *arg2);
-      argvi++;
+      if (GIMME_V == G_ARRAY) {
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), *arg2);
+        argvi++;
+        ST(argvi) = sv_newmortal();
+        sv_setiv(ST(argvi), *arg3);
+        argvi++;
+      } else {
+        if ( *arg3 ) {
+          ST(argvi) = sv_newmortal();
+          sv_setnv(ST(argvi), *arg2);
+          argvi++;
+        }
+      }
     }
     
     XSRETURN(argvi);
@@ -13659,10 +13170,20 @@ XS(_wrap_Band_GetOffset) {
     }
     {
       /* %typemap(argout) (double *val, int *hasval) */
-      ST(argvi) = sv_newmortal();
-      if ( *arg3 )
-      sv_setnv(ST(argvi), *arg2);
-      argvi++;
+      if (GIMME_V == G_ARRAY) {
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), *arg2);
+        argvi++;
+        ST(argvi) = sv_newmortal();
+        sv_setiv(ST(argvi), *arg3);
+        argvi++;
+      } else {
+        if ( *arg3 ) {
+          ST(argvi) = sv_newmortal();
+          sv_setnv(ST(argvi), *arg2);
+          argvi++;
+        }
+      }
     }
     
     XSRETURN(argvi);
@@ -13727,10 +13248,20 @@ XS(_wrap_Band_GetScale) {
     }
     {
       /* %typemap(argout) (double *val, int *hasval) */
-      ST(argvi) = sv_newmortal();
-      if ( *arg3 )
-      sv_setnv(ST(argvi), *arg2);
-      argvi++;
+      if (GIMME_V == G_ARRAY) {
+        ST(argvi) = sv_newmortal();
+        sv_setnv(ST(argvi), *arg2);
+        argvi++;
+        ST(argvi) = sv_newmortal();
+        sv_setiv(ST(argvi), *arg3);
+        argvi++;
+      } else {
+        if ( *arg3 ) {
+          ST(argvi) = sv_newmortal();
+          sv_setnv(ST(argvi), *arg2);
+          argvi++;
+        }
+      }
     }
     
     XSRETURN(argvi);
@@ -14685,7 +14216,7 @@ XS(_wrap_Band_Fill) {
 }
 
 
-XS(_wrap_Band_ReadRaster) {
+XS(_wrap_Band__ReadRaster) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
     int arg2 ;
@@ -14699,6 +14230,9 @@ XS(_wrap_Band_ReadRaster) {
     int *arg10 = (int *) 0 ;
     int *arg11 = (int *) 0 ;
     int *arg12 = (int *) 0 ;
+    GDALRIOResampleAlg arg13 = (GDALRIOResampleAlg) GRIORA_NearestNeighbour ;
+    GDALProgressFunc arg14 = (GDALProgressFunc) NULL ;
+    void *arg15 = (void *) NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
@@ -14716,41 +14250,48 @@ XS(_wrap_Band_ReadRaster) {
     int val10 ;
     int val11 ;
     int val12 ;
+    int val13 ;
+    int ecode13 = 0 ;
     int argvi = 0;
     CPLErr result;
     dXSARGS;
     
+    /* %typemap(arginit, noblock=1) ( void* callback_data = NULL) */
+    SavedEnv saved_env;
+    saved_env.fct = NULL;
+    saved_env.data = &PL_sv_undef;
+    arg15 = (void *)(&saved_env);
     {
       /* %typemap(in,numinputs=0) (int *nLen6, char **pBuf6 ) */
       arg6 = &nLen6;
       arg7 = &pBuf6;
     }
-    if ((items < 5) || (items > 10)) {
-      SWIG_croak("Usage: Band_ReadRaster(self,xoff,yoff,xsize,ysize,buf,buf_xsize,buf_ysize,buf_type,buf_pixel_space,buf_line_space);");
+    if ((items < 5) || (items > 13)) {
+      SWIG_croak("Usage: Band__ReadRaster(self,xoff,yoff,xsize,ysize,buf,buf_xsize,buf_ysize,buf_type,buf_pixel_space,buf_line_space,resample_alg,callback,callback_data);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_ReadRaster" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band__ReadRaster" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band_ReadRaster" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band__ReadRaster" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
     if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Band_ReadRaster" "', argument " "3"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Band__ReadRaster" "', argument " "3"" of type '" "int""'");
     } 
     arg3 = static_cast< int >(val3);
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Band_ReadRaster" "', argument " "4"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Band__ReadRaster" "', argument " "4"" of type '" "int""'");
     } 
     arg4 = static_cast< int >(val4);
     ecode5 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
     if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Band_ReadRaster" "', argument " "5"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Band__ReadRaster" "', argument " "5"" of type '" "int""'");
     } 
     arg5 = static_cast< int >(val5);
     if (items > 5) {
@@ -14813,9 +14354,40 @@ XS(_wrap_Band_ReadRaster) {
         }
       }
     }
+    if (items > 10) {
+      ecode13 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(10), &val13);
+      if (!SWIG_IsOK(ecode13)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode13), "in method '" "Band__ReadRaster" "', argument " "13"" of type '" "GDALRIOResampleAlg""'");
+      } 
+      arg13 = static_cast< GDALRIOResampleAlg >(val13);
+    }
+    if (items > 11) {
+      {
+        /* %typemap(in) (GDALProgressFunc callback = NULL) */
+        if (SvOK(ST(11))) {
+          if (SvROK(ST(11))) {
+            if (SvTYPE(SvRV(ST(11))) != SVt_PVCV) {
+              SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+            } else {
+              saved_env.fct = (SV *)ST(11);
+              arg14 = &callback_d_cp_vp;
+            }
+          } else {
+            SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+          }
+        }
+      }
+    }
+    if (items > 12) {
+      {
+        /* %typemap(in) (void* callback_data=NULL) */
+        if (SvOK(ST(12)))
+        saved_env.data = (SV *)ST(12);
+      }
+    }
     {
       CPLErrorReset();
-      result = (CPLErr)GDALRasterBandShadow_ReadRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12);
+      result = (CPLErr)GDALRasterBandShadow_ReadRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -14859,6 +14431,8 @@ XS(_wrap_Band_ReadRaster) {
     
     
     
+    
+    
     XSRETURN(argvi);
   fail:
     
@@ -14877,12 +14451,14 @@ XS(_wrap_Band_ReadRaster) {
     
     
     
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Band_WriteRaster) {
+XS(_wrap_Band__WriteRaster) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
     int arg2 ;
@@ -14916,38 +14492,38 @@ XS(_wrap_Band_WriteRaster) {
     dXSARGS;
     
     if ((items < 6) || (items > 11)) {
-      SWIG_croak("Usage: Band_WriteRaster(self,xoff,yoff,xsize,ysize,buf_len,buf_string,buf_xsize,buf_ysize,buf_type,buf_pixel_space,buf_line_space);");
+      SWIG_croak("Usage: Band__WriteRaster(self,xoff,yoff,xsize,ysize,buf_len,buf_string,buf_xsize,buf_ysize,buf_type,buf_pixel_space,buf_line_space);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_WriteRaster" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band__WriteRaster" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band_WriteRaster" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band__WriteRaster" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
     if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Band_WriteRaster" "', argument " "3"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Band__WriteRaster" "', argument " "3"" of type '" "int""'");
     } 
     arg3 = static_cast< int >(val3);
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Band_WriteRaster" "', argument " "4"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Band__WriteRaster" "', argument " "4"" of type '" "int""'");
     } 
     arg4 = static_cast< int >(val4);
     ecode5 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
     if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Band_WriteRaster" "', argument " "5"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Band__WriteRaster" "', argument " "5"" of type '" "int""'");
     } 
     arg5 = static_cast< int >(val5);
     {
       /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
       if (SvOK(ST(5))) {
         if (!SvPOK(ST(5)))
-        SWIG_croak("expected binary data as input");
+        SWIG_croak("Expected binary data.");
         STRLEN len = SvCUR(ST(5));
         arg7 = SvPV_nolen(ST(5));
         arg6 = len;
@@ -15507,7 +15083,7 @@ XS(_wrap_Band_GetMaskBand) {
 }
 
 
-XS(_wrap_Band_GetMaskFlags) {
+XS(_wrap_Band__GetMaskFlags) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
     void *argp1 = 0 ;
@@ -15517,11 +15093,11 @@ XS(_wrap_Band_GetMaskFlags) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Band_GetMaskFlags(self);");
+      SWIG_croak("Usage: Band__GetMaskFlags(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_GetMaskFlags" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band__GetMaskFlags" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
     {
@@ -15558,7 +15134,7 @@ XS(_wrap_Band_GetMaskFlags) {
 }
 
 
-XS(_wrap_Band_CreateMaskBand) {
+XS(_wrap_Band__CreateMaskBand) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
     int arg2 ;
@@ -15571,16 +15147,16 @@ XS(_wrap_Band_CreateMaskBand) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Band_CreateMaskBand(self,nFlags);");
+      SWIG_croak("Usage: Band__CreateMaskBand(self,nFlags);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_CreateMaskBand" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band__CreateMaskBand" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
     }
     arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band_CreateMaskBand" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Band__CreateMaskBand" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     {
@@ -15964,14 +15540,17 @@ XS(_wrap_Band_SetDefaultHistogram) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList) */
       if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(3)));
       arg4 = av_len(av)+1;
-      arg5 = (int*) malloc(arg4*sizeof(int));
-      for( int i = 0; i<arg4; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg5[i] =  SvIV(*sv);
-      }
+      arg5 = (int*)CPLMalloc(arg4*sizeof(int));
+      if (arg5) {
+        for( int i = 0; i<arg4; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg5[i] =  SvIV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       CPLErrorReset();
@@ -16003,8 +15582,7 @@ XS(_wrap_Band_SetDefaultHistogram) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     XSRETURN(argvi);
   fail:
@@ -16013,8 +15591,7 @@ XS(_wrap_Band_SetDefaultHistogram) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     SWIG_croak_null();
   }
@@ -16181,9 +15758,9 @@ XS(_wrap_Band_SetCategoryNames) {
               arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -16254,17 +15831,15 @@ XS(_wrap_Band_ContourGenerate) {
     int ecode9 = 0 ;
     int val10 ;
     int ecode10 = 0 ;
+    void *argp11 ;
+    int res11 = 0 ;
+    int res12 ;
     int argvi = 0;
     CPLErr result;
-    dXSARGS;
-    
-    /* %typemap(arginit, noblock=1) ( void* callback_data = NULL) */
-    SavedEnv saved_env;
-    saved_env.fct = NULL;
-    saved_env.data = &PL_sv_undef;
-    arg12 = (void *)(&saved_env);
+    dXSARGS;
+    
     if ((items < 8) || (items > 10)) {
-      SWIG_croak("Usage: Band_ContourGenerate(self,dfContourInterval,dfContourBase,nFixedLevelCount,padfFixedLevels,bUseNoData,dfNoDataValue,hLayer,iIDField,iElevField,callback,callback_data);");
+      SWIG_croak("Usage: Band_ContourGenerate(self,dfContourInterval,dfContourBase,nFixedLevelCount,padfFixedLevels,bUseNoData,dfNoDataValue,hLayer,iIDField,iElevField,progress,progress_data);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
@@ -16284,14 +15859,17 @@ XS(_wrap_Band_ContourGenerate) {
     {
       /* %typemap(in,numinputs=1) (int nList, double* pList) */
       if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(3)));
       arg4 = av_len(av)+1;
-      arg5 = (double*) malloc(arg4*sizeof(double));
-      for( int i = 0; i<arg4; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg5[i] =  SvNV(*sv);
-      }
+      arg5 = (double*)CPLMalloc(arg4*sizeof(double));
+      if (arg5) {
+        for( int i = 0; i<arg4; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg5[i] =  SvNV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       /* %typemap(in,numinputs=1) (int defined, double value) */
@@ -16315,26 +15893,21 @@ XS(_wrap_Band_ContourGenerate) {
     arg10 = static_cast< int >(val10);
     if (items > 8) {
       {
-        /* %typemap(in) (GDALProgressFunc callback = NULL) */
-        if (SvOK(ST(8))) {
-          if (SvROK(ST(8))) {
-            if (SvTYPE(SvRV(ST(8))) != SVt_PVCV) {
-              SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
-            } else {
-              saved_env.fct = (SV *)ST(8);
-              arg11 = &callback_d_cp_vp;
-            }
-          } else {
-            SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
-          }
+        res11 = SWIG_ConvertPtr(ST(8), &argp11, SWIGTYPE_p_GDALProgressFunc,  0 );
+        if (!SWIG_IsOK(res11)) {
+          SWIG_exception_fail(SWIG_ArgError(res11), "in method '" "Band_ContourGenerate" "', argument " "11"" of type '" "GDALProgressFunc""'"); 
+        }  
+        if (!argp11) {
+          SWIG_exception_fail(SWIG_ValueError, "invalid null reference " "in method '" "Band_ContourGenerate" "', argument " "11"" of type '" "GDALProgressFunc""'");
+        } else {
+          arg11 = *(reinterpret_cast< GDALProgressFunc * >(argp11));
         }
       }
     }
     if (items > 9) {
-      {
-        /* %typemap(in) (void* callback_data=NULL) */
-        if (SvOK(ST(9)))
-        saved_env.data = (SV *)ST(9);
+      res12 = SWIG_ConvertPtr(ST(9),SWIG_as_voidptrptr(&arg12), 0, 0);
+      if (!SWIG_IsOK(res12)) {
+        SWIG_exception_fail(SWIG_ArgError(res12), "in method '" "Band_ContourGenerate" "', argument " "12"" of type '" "void *""'"); 
       }
     }
     {
@@ -16367,8 +15940,7 @@ XS(_wrap_Band_ContourGenerate) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     
     
@@ -16381,8 +15953,7 @@ XS(_wrap_Band_ContourGenerate) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     
     
@@ -16703,7 +16274,7 @@ XS(_wrap_ColorTable_GetColorEntry) {
     {
       /* %typemap(out) GDALColorEntry* */
       if (!result)
-      SWIG_croak("GetColorEntry failed");
+      SWIG_croak("GetColorEntry failed.");
       ST(argvi) = sv_newmortal();
       sv_setiv(ST(argvi++), (IV) result->c1);
       ST(argvi) = sv_newmortal();
@@ -16783,7 +16354,7 @@ XS(_wrap_ColorTable_GetColorEntryAsRGB) {
     {
       /* %typemap(argout) GDALColorEntry* */
       if (!result)
-      SWIG_croak("GetColorEntryAsRGB failed");
+      SWIG_croak("GetColorEntryAsRGB failed.");
       argvi--;
       ST(argvi) = sv_newmortal();
       sv_setiv(ST(argvi++), (IV) e3.c1);
@@ -16837,17 +16408,23 @@ XS(_wrap_ColorTable__SetColorEntry) {
     {
       /* %typemap(in,numinputs=1) const GDALColorEntry*(GDALColorEntry e3) */
       arg3 = &e3;
-      if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
-      AV *av = (AV*)(SvRV(ST(2)));
-      SV **sv = av_fetch(av, 0, 0);
-      arg3->c1 =  SvIV(*sv);
-      sv = av_fetch(av, 1, 0);
-      arg3->c2 =  SvIV(*sv);
-      sv = av_fetch(av, 2, 0);
-      arg3->c3 =  SvIV(*sv);
-      sv = av_fetch(av, 3, 0);
-      arg3->c4 =  SvIV(*sv);
+      int ok = SvROK(ST(2)) && SvTYPE(SvRV(ST(2)))==SVt_PVAV;
+      AV *av;
+      if (ok) {
+        av = (AV*)(SvRV(ST(2)));
+        ok = av_len(av) == 3;
+      }
+      if (ok) {
+        SV **sv = av_fetch(av, 0, 0);
+        arg3->c1 =  SvIV(*sv);
+        sv = av_fetch(av, 1, 0);
+        arg3->c2 =  SvIV(*sv);
+        sv = av_fetch(av, 2, 0);
+        arg3->c3 =  SvIV(*sv);
+        sv = av_fetch(av, 3, 0);
+        arg3->c4 =  SvIV(*sv);
+      } else 
+      SWIG_croak("Color entry is an array of four values: red, green, blue, alpha.");
     }
     _saved[0] = ST(2);
     {
@@ -16928,17 +16505,23 @@ XS(_wrap_ColorTable_CreateColorRamp) {
     {
       /* %typemap(in,numinputs=1) const GDALColorEntry*(GDALColorEntry e3) */
       arg3 = &e3;
-      if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
-      AV *av = (AV*)(SvRV(ST(2)));
-      SV **sv = av_fetch(av, 0, 0);
-      arg3->c1 =  SvIV(*sv);
-      sv = av_fetch(av, 1, 0);
-      arg3->c2 =  SvIV(*sv);
-      sv = av_fetch(av, 2, 0);
-      arg3->c3 =  SvIV(*sv);
-      sv = av_fetch(av, 3, 0);
-      arg3->c4 =  SvIV(*sv);
+      int ok = SvROK(ST(2)) && SvTYPE(SvRV(ST(2)))==SVt_PVAV;
+      AV *av;
+      if (ok) {
+        av = (AV*)(SvRV(ST(2)));
+        ok = av_len(av) == 3;
+      }
+      if (ok) {
+        SV **sv = av_fetch(av, 0, 0);
+        arg3->c1 =  SvIV(*sv);
+        sv = av_fetch(av, 1, 0);
+        arg3->c2 =  SvIV(*sv);
+        sv = av_fetch(av, 2, 0);
+        arg3->c3 =  SvIV(*sv);
+        sv = av_fetch(av, 3, 0);
+        arg3->c4 =  SvIV(*sv);
+      } else 
+      SWIG_croak("Color entry is an array of four values: red, green, blue, alpha.");
     }
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
@@ -16948,17 +16531,23 @@ XS(_wrap_ColorTable_CreateColorRamp) {
     {
       /* %typemap(in,numinputs=1) const GDALColorEntry*(GDALColorEntry e5) */
       arg5 = &e3;
-      if (!(SvROK(ST(4)) && (SvTYPE(SvRV(ST(4)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
-      AV *av = (AV*)(SvRV(ST(4)));
-      SV **sv = av_fetch(av, 0, 0);
-      arg5->c1 =  SvIV(*sv);
-      sv = av_fetch(av, 1, 0);
-      arg5->c2 =  SvIV(*sv);
-      sv = av_fetch(av, 2, 0);
-      arg5->c3 =  SvIV(*sv);
-      sv = av_fetch(av, 3, 0);
-      arg5->c4 =  SvIV(*sv);
+      int ok = SvROK(ST(4)) && SvTYPE(SvRV(ST(4)))==SVt_PVAV;
+      AV *av;
+      if (ok) {
+        av = (AV*)(SvRV(ST(4)));
+        ok = av_len(av) == 3;
+      }
+      if (ok) {
+        SV **sv = av_fetch(av, 0, 0);
+        arg5->c1 =  SvIV(*sv);
+        sv = av_fetch(av, 1, 0);
+        arg5->c2 =  SvIV(*sv);
+        sv = av_fetch(av, 2, 0);
+        arg5->c3 =  SvIV(*sv);
+        sv = av_fetch(av, 3, 0);
+        arg5->c4 =  SvIV(*sv);
+      } else 
+      SWIG_croak("Color entry is an array of four values: red, green, blue, alpha.");
     }
     _saved[0] = ST(2);
     _saved[1] = ST(4);
@@ -18371,6 +17960,132 @@ XS(_wrap_RasterAttributeTable_ChangesAreWrittenToFile) {
 }
 
 
+XS(_wrap_RasterAttributeTable_DumpReadable) {
+  {
+    GDALRasterAttributeTableShadow *arg1 = (GDALRasterAttributeTableShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: RasterAttributeTable_DumpReadable(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterAttributeTableShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "RasterAttributeTable_DumpReadable" "', argument " "1"" of type '" "GDALRasterAttributeTableShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALRasterAttributeTableShadow * >(argp1);
+    {
+      CPLErrorReset();
+      GDALRasterAttributeTableShadow_DumpReadable(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_TermProgress_nocb) {
+  {
+    double arg1 ;
+    char *arg2 = (char *) NULL ;
+    void *arg3 = (void *) NULL ;
+    double val1 ;
+    int ecode1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res3 ;
+    int argvi = 0;
+    int result;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 3)) {
+      SWIG_croak("Usage: TermProgress_nocb(dfProgress,pszMessage,pData);");
+    }
+    ecode1 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "TermProgress_nocb" "', argument " "1"" of type '" "double""'");
+    } 
+    arg1 = static_cast< double >(val1);
+    if (items > 1) {
+      res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+      if (!SWIG_IsOK(res2)) {
+        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "TermProgress_nocb" "', argument " "2"" of type '" "char const *""'");
+      }
+      arg2 = reinterpret_cast< char * >(buf2);
+    }
+    if (items > 2) {
+      res3 = SWIG_ConvertPtr(ST(2),SWIG_as_voidptrptr(&arg3), 0, 0);
+      if (!SWIG_IsOK(res3)) {
+        SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "TermProgress_nocb" "', argument " "3"" of type '" "void *""'"); 
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (int)GDALTermProgress_nocb(arg1,(char const *)arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap__ComputeMedianCutPCT) {
   {
     GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
@@ -18888,9 +18603,9 @@ XS(_wrap__ComputeProximity) {
                 arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -19013,14 +18728,17 @@ XS(_wrap__RasterizeLayer) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList) */
       if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(1)));
       arg2 = av_len(av)+1;
-      arg3 = (int*) malloc(arg2*sizeof(int));
-      for( int i = 0; i<arg2; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg3[i] =  SvIV(*sv);
-      }
+      arg3 = (int*)CPLMalloc(arg2*sizeof(int));
+      if (arg3) {
+        for( int i = 0; i<arg2; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg3[i] =  SvIV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     res4 = SWIG_ConvertPtr(ST(2), &argp4,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
     if (!SWIG_IsOK(res4)) {
@@ -19043,14 +18761,17 @@ XS(_wrap__RasterizeLayer) {
       {
         /* %typemap(in,numinputs=1) (int nList, double* pList) */
         if (!(SvROK(ST(5)) && (SvTYPE(SvRV(ST(5)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         AV *av = (AV*)(SvRV(ST(5)));
         arg7 = av_len(av)+1;
-        arg8 = (double*) malloc(arg7*sizeof(double));
-        for( int i = 0; i<arg7; i++ ) {
-          SV **sv = av_fetch(av, i, 0);
-          arg8[i] =  SvNV(*sv);
-        }
+        arg8 = (double*)CPLMalloc(arg7*sizeof(double));
+        if (arg8) {
+          for( int i = 0; i<arg7; i++ ) {
+            SV **sv = av_fetch(av, i, 0);
+            arg8[i] =  SvNV(*sv);
+          }
+        } else
+        SWIG_fail;
       }
     }
     if (items > 6) {
@@ -19078,9 +18799,9 @@ XS(_wrap__RasterizeLayer) {
                 arg9 = CSLAddNameValue( arg9, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -19146,16 +18867,14 @@ XS(_wrap__RasterizeLayer) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg3)
-      free((void*) arg3);
+      CPLFree((void*) arg3);
     }
     
     
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg8)
-      free((void*) arg8);
+      CPLFree((void*) arg8);
     }
     {
       /* %typemap(freearg) char **options */
@@ -19167,16 +18886,14 @@ XS(_wrap__RasterizeLayer) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg3)
-      free((void*) arg3);
+      CPLFree((void*) arg3);
     }
     
     
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg8)
-      free((void*) arg8);
+      CPLFree((void*) arg8);
     }
     {
       /* %typemap(freearg) char **options */
@@ -19262,9 +18979,9 @@ XS(_wrap__Polygonize) {
                 arg5 = CSLAddNameValue( arg5, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -19426,9 +19143,9 @@ XS(_wrap_FillNodata) {
                 arg5 = CSLAddNameValue( arg5, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -19595,9 +19312,9 @@ XS(_wrap__SieveFilter) {
                 arg6 = CSLAddNameValue( arg6, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -19666,21 +19383,152 @@ XS(_wrap__SieveFilter) {
     
     
     {
-      /* %typemap(freearg) char **options */
-      if (arg6) CSLDestroy( arg6 );
+      /* %typemap(freearg) char **options */
+      if (arg6) CSLDestroy( arg6 );
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg6) CSLDestroy( arg6 );
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap__RegenerateOverviews) {
+  {
+    GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
+    int arg2 ;
+    GDALRasterBandShadow **arg3 = (GDALRasterBandShadow **) 0 ;
+    char *arg4 = (char *) "average" ;
+    GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+    void *arg6 = (void *) NULL ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res4 ;
+    char *buf4 = 0 ;
+    int alloc4 = 0 ;
+    int argvi = 0;
+    int result;
+    dXSARGS;
+    
+    /* %typemap(arginit, noblock=1) ( void* callback_data = NULL) */
+    SavedEnv saved_env;
+    saved_env.fct = NULL;
+    saved_env.data = &PL_sv_undef;
+    arg6 = (void *)(&saved_env);
+    if ((items < 2) || (items > 5)) {
+      SWIG_croak("Usage: _RegenerateOverviews(srcBand,overviewBandCount,overviewBands,resampling,callback,callback_data);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "_RegenerateOverviews" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
+    {
+      /* %typemap(in,numinputs=1) (int object_list_count, GDALRasterBandShadow **poObjects) */
+      if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
+      SWIG_croak("Expected a reference to an array of Band objects.");
+      AV *av = (AV*)(SvRV(ST(1)));
+      arg2 = av_len(av)+1;
+      /* get the pointers from the array into bands */
+      arg3 = (GDALRasterBandShadow **)CPLMalloc(arg2*sizeof(GDALRasterBandShadow *));
+      if (arg3) {
+        for (int i = 0; i < arg2; i++) {
+          SV **sv = av_fetch(av, i, 0);
+          int ret = SWIG_ConvertPtr(*sv, &(arg3[i]), SWIGTYPE_p_GDALRasterBandShadow, 0);
+          if (!SWIG_IsOK(ret))
+          SWIG_croak("An item in the argument array is not a Band object.");
+        }
+      } else
+      SWIG_croak("Out of memory.");
+      
+    }
+    if (items > 2) {
+      res4 = SWIG_AsCharPtrAndSize(ST(2), &buf4, NULL, &alloc4);
+      if (!SWIG_IsOK(res4)) {
+        SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "_RegenerateOverviews" "', argument " "4"" of type '" "char const *""'");
+      }
+      arg4 = reinterpret_cast< char * >(buf4);
+    }
+    if (items > 3) {
+      {
+        /* %typemap(in) (GDALProgressFunc callback = NULL) */
+        if (SvOK(ST(3))) {
+          if (SvROK(ST(3))) {
+            if (SvTYPE(SvRV(ST(3))) != SVt_PVCV) {
+              SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+            } else {
+              saved_env.fct = (SV *)ST(3);
+              arg5 = &callback_d_cp_vp;
+            }
+          } else {
+            SWIG_croak("the callback argument of a Geo::GDAL method must be a reference to a subroutine");
+          }
+        }
+      }
+    }
+    if (items > 4) {
+      {
+        /* %typemap(in) (void* callback_data=NULL) */
+        if (SvOK(ST(4)))
+        saved_env.data = (SV *)ST(4);
+      }
+    }
+    {
+      if (!arg1) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (int)RegenerateOverviews(arg1,arg2,arg3,(char const *)arg4,arg5,arg6);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    {
+      /* %typemap(freearg) (int object_list_count, GDALRasterBandShadow **poObjects) */
+      CPLFree(arg3);
     }
+    if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
     
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
-    
     {
-      /* %typemap(freearg) char **options */
-      if (arg6) CSLDestroy( arg6 );
+      /* %typemap(freearg) (int object_list_count, GDALRasterBandShadow **poObjects) */
+      CPLFree(arg3);
     }
+    if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
     
     SWIG_croak_null();
   }
@@ -19864,14 +19712,17 @@ XS(_wrap_ContourGenerate) {
     {
       /* %typemap(in,numinputs=1) (int nList, double* pList) */
       if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(3)));
       arg4 = av_len(av)+1;
-      arg5 = (double*) malloc(arg4*sizeof(double));
-      for( int i = 0; i<arg4; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg5[i] =  SvNV(*sv);
-      }
+      arg5 = (double*)CPLMalloc(arg4*sizeof(double));
+      if (arg5) {
+        for( int i = 0; i<arg4; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg5[i] =  SvNV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     ecode6 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(4), &val6);
     if (!SWIG_IsOK(ecode6)) {
@@ -19962,8 +19813,7 @@ XS(_wrap_ContourGenerate) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     
     
@@ -19978,8 +19828,7 @@ XS(_wrap_ContourGenerate) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     
     
@@ -20148,9 +19997,9 @@ XS(_wrap_new_Transformer) {
               arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -20280,7 +20129,7 @@ XS(_wrap_Transformer_TransformPoint__SWIG_0) {
     {
       /* %typemap(in) (double argin3[ANY]) */
       if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       arg3 = argin3;
       AV *av = (AV*)(SvRV(ST(2)));
       for (unsigned int i=0; i<3; i++) {
@@ -20614,18 +20463,20 @@ XS(_wrap_Transformer__TransformPoints) {
       /* %typemap(in) (int nCount, double *x, double *y, double *z) */
       /* ST(2) is a ref to a list of refs to point lists */
       if (! (SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(2)));
       arg3 = av_len(av)+1;
-      arg4 = (double*) malloc(arg3*sizeof(double));
-      arg5 = (double*) malloc(arg3*sizeof(double));
-      arg6 = (double*) malloc(arg3*sizeof(double));
+      arg4 = (double*)CPLMalloc(arg3*sizeof(double));
+      if (arg4)
+      arg5 = (double*)CPLMalloc(arg3*sizeof(double));
+      if (arg4 && arg5)
+      arg6 = (double*)CPLMalloc(arg3*sizeof(double));
       if (!arg4 or !arg5 or !arg6)
-      SWIG_croak("out of memory in Geo::GDAL");
+      SWIG_fail;
       for (int i = 0; i < arg3; i++) {
         SV **sv = av_fetch(av, i, 0); /* ref to one point list */
         if (!(SvROK(*sv) && (SvTYPE(SvRV(*sv))==SVt_PVAV)))
-        SWIG_croak("expected a reference to a list of coordinates as an argument to a Geo::GDAL method");
+        SWIG_croak("An item in the list is not a reference to an array.");
         AV *ac = (AV*)(SvRV(*sv));
         int n = av_len(ac)+1;
         SV **c = av_fetch(ac, 0, 0);
@@ -20693,9 +20544,9 @@ XS(_wrap_Transformer__TransformPoints) {
     
     {
       /* %typemap(freearg) (int nCount, double *x, double *y, double *z) */
-      if (arg4) free(arg4);
-      if (arg5) free(arg5);
-      if (arg6) free(arg6);
+      CPLFree(arg4);
+      CPLFree(arg5);
+      CPLFree(arg6);
     }
     
     XSRETURN(argvi);
@@ -20704,9 +20555,9 @@ XS(_wrap_Transformer__TransformPoints) {
     
     {
       /* %typemap(freearg) (int nCount, double *x, double *y, double *z) */
-      if (arg4) free(arg4);
-      if (arg5) free(arg5);
-      if (arg6) free(arg6);
+      CPLFree(arg4);
+      CPLFree(arg5);
+      CPLFree(arg6);
     }
     
     SWIG_croak_null();
@@ -20812,9 +20663,9 @@ XS(_wrap_Transformer_TransformGeolocations) {
                 arg7 = CSLAddNameValue( arg7, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -20910,7 +20761,7 @@ XS(_wrap_ApplyGeoTransform) {
     {
       /* %typemap(in) (double argin1[ANY]) */
       if (!(SvROK(ST(0)) && (SvTYPE(SvRV(ST(0)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       arg1 = argin1;
       AV *av = (AV*)(SvRV(ST(0)));
       for (unsigned int i=0; i<6; i++) {
@@ -20991,7 +20842,7 @@ XS(_wrap_InvGeoTransform) {
     double argin1[6] ;
     double argout2[6] ;
     int argvi = 0;
-    int result;
+    RETURN_NONE result;
     dXSARGS;
     
     {
@@ -21004,7 +20855,7 @@ XS(_wrap_InvGeoTransform) {
     {
       /* %typemap(in) (double argin1[ANY]) */
       if (!(SvROK(ST(0)) && (SvTYPE(SvRV(ST(0)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       arg1 = argin1;
       AV *av = (AV*)(SvRV(ST(0)));
       for (unsigned int i=0; i<6; i++) {
@@ -21014,7 +20865,7 @@ XS(_wrap_InvGeoTransform) {
     }
     {
       CPLErrorReset();
-      result = (int)GDALInvGeoTransform(arg1,arg2);
+      result = GDALInvGeoTransform(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21036,7 +20887,9 @@ XS(_wrap_InvGeoTransform) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) IF_FALSE_RETURN_NONE */
+    }
     {
       /* %typemap(argout) (double argout[ANY]) */
       if (GIMME_V == G_ARRAY) {
@@ -21052,6 +20905,12 @@ XS(_wrap_InvGeoTransform) {
     }
     
     
+    {
+      /* %typemap(ret) IF_FALSE_RETURN_NONE */
+      if (result == 0 ) {
+        SWIG_croak("unexpected error in 'InvGeoTransform'");
+      }
+    }
     XSRETURN(argvi);
   fail:
     
@@ -21344,7 +21203,7 @@ XS(_wrap_SetCacheMax) {
 }
 
 
-XS(_wrap_GetDataTypeSize) {
+XS(_wrap__GetDataTypeSize) {
   {
     GDALDataType arg1 ;
     int val1 ;
@@ -21354,11 +21213,11 @@ XS(_wrap_GetDataTypeSize) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GetDataTypeSize(eDataType);");
+      SWIG_croak("Usage: _GetDataTypeSize(eDataType);");
     }
     ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
     if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetDataTypeSize" "', argument " "1"" of type '" "GDALDataType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "_GetDataTypeSize" "', argument " "1"" of type '" "GDALDataType""'");
     } 
     arg1 = static_cast< GDALDataType >(val1);
     {
@@ -21395,7 +21254,7 @@ XS(_wrap_GetDataTypeSize) {
 }
 
 
-XS(_wrap_DataTypeIsComplex) {
+XS(_wrap__DataTypeIsComplex) {
   {
     GDALDataType arg1 ;
     int val1 ;
@@ -21405,11 +21264,11 @@ XS(_wrap_DataTypeIsComplex) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: DataTypeIsComplex(eDataType);");
+      SWIG_croak("Usage: _DataTypeIsComplex(eDataType);");
     }
     ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
     if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "DataTypeIsComplex" "', argument " "1"" of type '" "GDALDataType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "_DataTypeIsComplex" "', argument " "1"" of type '" "GDALDataType""'");
     } 
     arg1 = static_cast< GDALDataType >(val1);
     {
@@ -21925,10 +21784,18 @@ XS(_wrap_SerializeXMLTree) {
     {
       /* %typemap(in) (CPLXMLNode* xmlnode ) */
       if (!(SvROK(ST(0)) && (SvTYPE(SvRV(ST(0)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(0)));
-      arg1 = AVToXMLTree( av );
-      if ( !arg1 ) SWIG_croak("conversion of a Perl array to XMLTree failed entering a Geo::GDAL method");
+      int err;
+      arg1 = AVToXMLTree( av, &err );
+      if ( !arg1 ) {
+        switch (err) {
+        case 1:
+          SWIG_croak("Conversion of a Perl array to XMLTree failed: the input XML is empty.");
+        case 2:
+          SWIG_croak("Conversion of a Perl array to XMLTree failed, child should be a reference to an array.");
+        }
+      }
     }
     {
       CPLErrorReset();
@@ -21982,6 +21849,115 @@ XS(_wrap_SerializeXMLTree) {
 }
 
 
+XS(_wrap_GetJPEG2000StructureAsString) {
+  {
+    char *arg1 = (char *) 0 ;
+    char **arg2 = (char **) NULL ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    retStringAndCPLFree *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: GetJPEG2000StructureAsString(pszFilename,options);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GetJPEG2000StructureAsString" "', argument " "1"" of type '" "char const *""'");
+    }
+    arg1 = reinterpret_cast< char * >(buf1);
+    if (items > 1) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(1))) {
+          if (SvROK(ST(1))) {
+            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(1)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg2 = CSLAddString( arg2, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(1));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg2 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    {
+      if (!arg1) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (retStringAndCPLFree *)GetJPEG2000StructureAsString((char const *)arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      ST(argvi) = SWIG_FromCharPtr((const char *)result);
+      CPLFree(result);
+    }
+    else
+    {
+      ST(argvi) = &PL_sv_undef;
+    }
+    argvi++ ;
+    
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_GetDriverCount) {
   {
     int argvi = 0;
@@ -22131,11 +22107,136 @@ XS(_wrap__GetDriver) {
 }
 
 
-XS(_wrap__Open__SWIG_1) {
+XS(_wrap__Open__SWIG_1) {
+  {
+    char *arg1 = (char *) 0 ;
+    GDALAccess arg2 = (GDALAccess) GA_ReadOnly ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    GDALDatasetShadow *result = 0 ;
+    dXSARGS;
+    
+    {
+      /* %typemap(default) const char * utf8_path */
+      arg1 = (char *)"";
+    }
+    if ((items < 0) || (items > 2)) {
+      SWIG_croak("Usage: _Open(utf8_path,eAccess);");
+    }
+    if (items > 0) {
+      {
+        /* %typemap(in,numinputs=1) (const char* utf8_path) */
+        sv_utf8_upgrade(ST(0));
+        arg1 = SvPV_nolen(ST(0));
+      }
+    }
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_Open" "', argument " "2"" of type '" "GDALAccess""'");
+      } 
+      arg2 = static_cast< GDALAccess >(val2);
+    }
+    {
+      if (!arg1) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (GDALDatasetShadow *)Open((char const *)arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDatasetShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap__Open) {
+  dXSARGS;
+  
+  {
+    unsigned long _index = 0;
+    SWIG_TypeRank _rank = 0; 
+    if ((items >= 0) && (items <= 2)) {
+      SWIG_TypeRank _ranki = 0;
+      SWIG_TypeRank _rankm = 0;
+      SWIG_TypeRank _pi = 1;
+      int _v = 0;
+      if (items > 0) {
+        {
+          int res = SWIG_AsCharPtrAndSize(ST(0), 0, NULL, 0);
+          _v = SWIG_CheckState(res);
+        }
+        if (!_v) goto check_1;
+        _ranki += _v*_pi;
+        _rankm += _pi;
+        _pi *= SWIG_MAXCASTRANK;
+        if (items > 1) {
+          {
+            {
+              int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), NULL);
+              _v = SWIG_CheckState(res);
+            }
+          }
+          if (!_v) goto check_1;
+          _ranki += _v*_pi;
+          _rankm += _pi;
+          _pi *= SWIG_MAXCASTRANK;
+        }
+      }
+      if (!_index || (_ranki < _rank)) {
+        _rank = _ranki; _index = 1;
+        if (_rank == _rankm) goto dispatch;
+      }
+    }
+  check_1:
+    
+  dispatch:
+    switch(_index) {
+    case 1:
+      PUSHMARK(MARK); SWIG_CALLXS(_wrap__Open__SWIG_1); return;
+    }
+  }
+  
+  croak("No matching function for overloaded '_Open'");
+  XSRETURN(0);
+}
+
+
+XS(_wrap_OpenEx) {
   {
     char *arg1 = (char *) 0 ;
-    GDALAccess arg2 = (GDALAccess) GA_ReadOnly ;
-    int val2 ;
+    unsigned int arg2 = (unsigned int) 0 ;
+    char **arg3 = (char **) NULL ;
+    char **arg4 = (char **) NULL ;
+    char **arg5 = (char **) NULL ;
+    unsigned int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
     GDALDatasetShadow *result = 0 ;
@@ -22145,8 +22246,8 @@ XS(_wrap__Open__SWIG_1) {
       /* %typemap(default) const char * utf8_path */
       arg1 = (char *)"";
     }
-    if ((items < 0) || (items > 2)) {
-      SWIG_croak("Usage: _Open(utf8_path,eAccess);");
+    if ((items < 0) || (items > 5)) {
+      SWIG_croak("Usage: OpenEx(utf8_path,nOpenFlags,allowed_drivers,open_options,sibling_files);");
     }
     if (items > 0) {
       {
@@ -22156,11 +22257,104 @@ XS(_wrap__Open__SWIG_1) {
       }
     }
     if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      ecode2 = SWIG_AsVal_unsigned_SS_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
       if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "_Open" "', argument " "2"" of type '" "GDALAccess""'");
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "OpenEx" "', argument " "2"" of type '" "unsigned int""'");
       } 
-      arg2 = static_cast< GDALAccess >(val2);
+      arg2 = static_cast< unsigned int >(val2);
+    }
+    if (items > 2) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(2))) {
+          if (SvROK(ST(2))) {
+            if (SvTYPE(SvRV(ST(2)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(2)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg3 = CSLAddString( arg3, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(2)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(2));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg3 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    if (items > 3) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(3))) {
+          if (SvROK(ST(3))) {
+            if (SvTYPE(SvRV(ST(3)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(3)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg4 = CSLAddString( arg4, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(3)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(3));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg4 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    if (items > 4) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(4))) {
+          if (SvROK(ST(4))) {
+            if (SvTYPE(SvRV(ST(4)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(4)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg5 = CSLAddString( arg5, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(4)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(4));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg5 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg5 = CSLAddNameValue( arg5, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
     }
     {
       if (!arg1) {
@@ -22169,7 +22363,7 @@ XS(_wrap__Open__SWIG_1) {
     }
     {
       CPLErrorReset();
-      result = (GDALDatasetShadow *)Open((char const *)arg1,arg2);
+      result = (GDALDatasetShadow *)OpenEx((char const *)arg1,arg2,arg3,arg4,arg5);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22193,63 +22387,35 @@ XS(_wrap__Open__SWIG_1) {
     }
     ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDatasetShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
+    {
+      /* %typemap(freearg) char **options */
+      if (arg4) CSLDestroy( arg4 );
+    }
+    {
+      /* %typemap(freearg) char **options */
+      if (arg5) CSLDestroy( arg5 );
+    }
     XSRETURN(argvi);
   fail:
     
-    SWIG_croak_null();
-  }
-}
-
-
-XS(_wrap__Open) {
-  dXSARGS;
-  
-  {
-    unsigned long _index = 0;
-    SWIG_TypeRank _rank = 0; 
-    if ((items >= 0) && (items <= 2)) {
-      SWIG_TypeRank _ranki = 0;
-      SWIG_TypeRank _rankm = 0;
-      SWIG_TypeRank _pi = 1;
-      int _v = 0;
-      if (items > 0) {
-        {
-          int res = SWIG_AsCharPtrAndSize(ST(0), 0, NULL, 0);
-          _v = SWIG_CheckState(res);
-        }
-        if (!_v) goto check_1;
-        _ranki += _v*_pi;
-        _rankm += _pi;
-        _pi *= SWIG_MAXCASTRANK;
-        if (items > 1) {
-          {
-            {
-              int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), NULL);
-              _v = SWIG_CheckState(res);
-            }
-          }
-          if (!_v) goto check_1;
-          _ranki += _v*_pi;
-          _rankm += _pi;
-          _pi *= SWIG_MAXCASTRANK;
-        }
-      }
-      if (!_index || (_ranki < _rank)) {
-        _rank = _ranki; _index = 1;
-        if (_rank == _rankm) goto dispatch;
-      }
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
     }
-  check_1:
-    
-  dispatch:
-    switch(_index) {
-    case 1:
-      PUSHMARK(MARK); SWIG_CALLXS(_wrap__Open__SWIG_1); return;
+    {
+      /* %typemap(freearg) char **options */
+      if (arg4) CSLDestroy( arg4 );
+    }
+    {
+      /* %typemap(freearg) char **options */
+      if (arg5) CSLDestroy( arg5 );
     }
+    SWIG_croak_null();
   }
-  
-  croak("No matching function for overloaded '_Open'");
-  XSRETURN(0);
 }
 
 
@@ -22422,9 +22588,9 @@ XS(_wrap_IdentifyDriver) {
                 arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -22473,12 +22639,122 @@ XS(_wrap_IdentifyDriver) {
 }
 
 
+XS(_wrap_GeneralCmdLineProcessor) {
+  {
+    char **arg1 = (char **) 0 ;
+    int arg2 = (int) 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    char **result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: GeneralCmdLineProcessor(papszArgv,nOptions);");
+    }
+    {
+      /* %typemap(in) char **options */
+      if (SvOK(ST(0))) {
+        if (SvROK(ST(0))) {
+          if (SvTYPE(SvRV(ST(0)))==SVt_PVAV) {
+            AV *av = (AV*)(SvRV(ST(0)));
+            for (int i = 0; i < av_len(av)+1; i++) {
+              SV *sv = *(av_fetch(av, i, 0));
+              sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+              char *pszItem = SvPV_nolen(sv);
+              arg1 = CSLAddString( arg1, pszItem );
+            }
+          } else if (SvTYPE(SvRV(ST(0)))==SVt_PVHV) {
+            HV *hv = (HV*)SvRV(ST(0));
+            SV *sv;
+            char *key;
+            I32 klen;
+            arg1 = NULL;
+            hv_iterinit(hv);
+            while(sv = hv_iternextsv(hv,&key,&klen)) {
+              sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+              arg1 = CSLAddNameValue( arg1, key, SvPV_nolen(sv) );
+            }
+          } else
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+        } else
+        SWIG_croak("The 'options' argument is not a reference.");   
+      }
+    }
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeneralCmdLineProcessor" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
+    }
+    {
+      CPLErrorReset();
+      result = (char **)GeneralCmdLineProcessor(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) char **options -> ( string ) */
+      AV* av = (AV*)sv_2mortal((SV*)newAV());
+      char **stringarray = result;
+      if ( stringarray != NULL ) {
+        int n = CSLCount( stringarray );
+        for ( int i = 0; i < n; i++ ) {
+          SV *sv = newSVpv(stringarray[i], 0);
+          SvUTF8_on(sv); /* expecting UTF-8 from GDAL */
+          if (!av_store(av, i, sv))
+          SvREFCNT_dec(sv);
+        }
+      }
+      ST(argvi) = newRV((SV*)av);
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
+    {
+      /* %typemap(freearg) char **options */
+      if (arg1) CSLDestroy( arg1 );
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    {
+      /* %typemap(freearg) char **options */
+      if (arg1) CSLDestroy( arg1 );
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
 
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
 
 static void *_p_GDALDriverShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((GDALMajorObjectShadow *)  ((GDALDriverShadow *) x));
 }
+static void *_p_OGRLayerShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRLayerShadow *) x));
+}
 static void *_p_GDALDatasetShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((GDALMajorObjectShadow *)  ((GDALDatasetShadow *) x));
 }
@@ -22503,7 +22779,9 @@ static swig_type_info _swigt__p_OGRLayerShadow = {"_p_OGRLayerShadow", "OGRLayer
 static swig_type_info _swigt__p_VSIStatBufL = {"_p_VSIStatBufL", "VSIStatBufL *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_char = {"_p_char", "char *|retStringAndCPLFree *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_double = {"_p_double", "double *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "GDALRATFieldType *|OGRFieldType *|GDALAccess *|int *|OGRwkbByteOrder *|CPLErr *|GDALRWFlag *|OGRJustification *|GDALRATFieldUsage *|GDALTileOrganization *|GDALPaletteInterp *|GDALColorInterp *|GDALResampleAlg *|OGRErr *|OGRwkbGeometryType *|GDALDataType *|GDALAsyncStatusType *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_f_double_p_q_const__char_p_void__int = {"_p_f_double_p_q_const__char_p_void__int", "int (*)(double,char const *,void *)", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldSubType *|GDALRATFieldType *|OGRFieldType *|int *|GDALAccess *|OGRwkbByteOrder *|CPLErr *|GDALRWFlag *|OGRJustification *|GDALRATFieldUsage *|GDALTileOrganization *|GDALPaletteInterp *|GDALColorInterp *|GDALResampleAlg *|GDALRIOResampleAlg *|OGRErr *|OGRwkbGeometryType *|GDALDataType *|GDALAsyncStatusType *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_GDALRasterBandShadow = {"_p_p_GDALRasterBandShadow", "GDALRasterBandShadow **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_GDAL_GCP = {"_p_p_GDAL_GCP", "GDAL_GCP **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_int = {"_p_p_int", "int **", 0, 0, (void*)0, 0};
@@ -22528,7 +22806,9 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_VSIStatBufL,
   &_swigt__p_char,
   &_swigt__p_double,
+  &_swigt__p_f_double_p_q_const__char_p_void__int,
   &_swigt__p_int,
+  &_swigt__p_p_GDALRasterBandShadow,
   &_swigt__p_p_GDAL_GCP,
   &_swigt__p_p_char,
   &_swigt__p_p_int,
@@ -22543,7 +22823,7 @@ static swig_cast_info _swigc__p_GDALColorEntry[] = {  {&_swigt__p_GDALColorEntry
 static swig_cast_info _swigc__p_GDALColorTableShadow[] = {  {&_swigt__p_GDALColorTableShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALDatasetShadow[] = {  {&_swigt__p_GDALDatasetShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALDriverShadow[] = {  {&_swigt__p_GDALDriverShadow, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_GDALDriverShadow, _p_GDALDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALDatasetShadow, _p_GDALDatasetShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALRasterBandShadow, _p_GDALRasterBandShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_GDALDriverShadow, _p_GDALDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRLayerShadow, _p_OGRLayerShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALDatasetShadow, _p_GDALDatasetShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALRasterBandShadow, _p_GDALRasterBandShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALProgressFunc[] = {  {&_swigt__p_GDALProgressFunc, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterAttributeTableShadow[] = {  {&_swigt__p_GDALRasterAttributeTableShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterBandShadow[] = {  {&_swigt__p_GDALRasterBandShadow, 0, 0, 0},{0, 0, 0, 0}};
@@ -22553,7 +22833,9 @@ static swig_cast_info _swigc__p_OGRLayerShadow[] = {  {&_swigt__p_OGRLayerShadow
 static swig_cast_info _swigc__p_VSIStatBufL[] = {  {&_swigt__p_VSIStatBufL, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_f_double_p_q_const__char_p_void__int[] = {  {&_swigt__p_f_double_p_q_const__char_p_void__int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_GDALRasterBandShadow[] = {  {&_swigt__p_p_GDALRasterBandShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_GDAL_GCP[] = {  {&_swigt__p_p_GDAL_GCP, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_int[] = {  {&_swigt__p_p_int, 0, 0, 0},{0, 0, 0, 0}};
@@ -22578,7 +22860,9 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_VSIStatBufL,
   _swigc__p_char,
   _swigc__p_double,
+  _swigc__p_f_double_p_q_const__char_p_void__int,
   _swigc__p_int,
+  _swigc__p_p_GDALRasterBandShadow,
   _swigc__p_p_GDAL_GCP,
   _swigc__p_p_char,
   _swigc__p_p_int,
@@ -22655,16 +22939,16 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::Driver_CopyFiles", _wrap_Driver_CopyFiles},
 {"Geo::GDALc::Driver_Register", _wrap_Driver_Register},
 {"Geo::GDALc::Driver_Deregister", _wrap_Driver_Deregister},
-{"Geo::GDALc::GCP_GCPX_set", _wrap_GCP_GCPX_set},
-{"Geo::GDALc::GCP_GCPX_get", _wrap_GCP_GCPX_get},
-{"Geo::GDALc::GCP_GCPY_set", _wrap_GCP_GCPY_set},
-{"Geo::GDALc::GCP_GCPY_get", _wrap_GCP_GCPY_get},
-{"Geo::GDALc::GCP_GCPZ_set", _wrap_GCP_GCPZ_set},
-{"Geo::GDALc::GCP_GCPZ_get", _wrap_GCP_GCPZ_get},
-{"Geo::GDALc::GCP_GCPPixel_set", _wrap_GCP_GCPPixel_set},
-{"Geo::GDALc::GCP_GCPPixel_get", _wrap_GCP_GCPPixel_get},
-{"Geo::GDALc::GCP_GCPLine_set", _wrap_GCP_GCPLine_set},
-{"Geo::GDALc::GCP_GCPLine_get", _wrap_GCP_GCPLine_get},
+{"Geo::GDALc::GCP_X_set", _wrap_GCP_X_set},
+{"Geo::GDALc::GCP_X_get", _wrap_GCP_X_get},
+{"Geo::GDALc::GCP_Y_set", _wrap_GCP_Y_set},
+{"Geo::GDALc::GCP_Y_get", _wrap_GCP_Y_get},
+{"Geo::GDALc::GCP_Z_set", _wrap_GCP_Z_set},
+{"Geo::GDALc::GCP_Z_get", _wrap_GCP_Z_get},
+{"Geo::GDALc::GCP_Column_set", _wrap_GCP_Column_set},
+{"Geo::GDALc::GCP_Column_get", _wrap_GCP_Column_get},
+{"Geo::GDALc::GCP_Row_set", _wrap_GCP_Row_set},
+{"Geo::GDALc::GCP_Row_get", _wrap_GCP_Row_get},
 {"Geo::GDALc::GCP_Info_set", _wrap_GCP_Info_set},
 {"Geo::GDALc::GCP_Info_get", _wrap_GCP_Info_get},
 {"Geo::GDALc::GCP_Id_set", _wrap_GCP_Id_set},
@@ -22685,20 +22969,6 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::GDAL_GCP_Info_set", _wrap_GDAL_GCP_Info_set},
 {"Geo::GDALc::GDAL_GCP_Id_get", _wrap_GDAL_GCP_Id_get},
 {"Geo::GDALc::GDAL_GCP_Id_set", _wrap_GDAL_GCP_Id_set},
-{"Geo::GDALc::GDAL_GCP_get_GCPX", _wrap_GDAL_GCP_get_GCPX},
-{"Geo::GDALc::GDAL_GCP_set_GCPX", _wrap_GDAL_GCP_set_GCPX},
-{"Geo::GDALc::GDAL_GCP_get_GCPY", _wrap_GDAL_GCP_get_GCPY},
-{"Geo::GDALc::GDAL_GCP_set_GCPY", _wrap_GDAL_GCP_set_GCPY},
-{"Geo::GDALc::GDAL_GCP_get_GCPZ", _wrap_GDAL_GCP_get_GCPZ},
-{"Geo::GDALc::GDAL_GCP_set_GCPZ", _wrap_GDAL_GCP_set_GCPZ},
-{"Geo::GDALc::GDAL_GCP_get_GCPPixel", _wrap_GDAL_GCP_get_GCPPixel},
-{"Geo::GDALc::GDAL_GCP_set_GCPPixel", _wrap_GDAL_GCP_set_GCPPixel},
-{"Geo::GDALc::GDAL_GCP_get_GCPLine", _wrap_GDAL_GCP_get_GCPLine},
-{"Geo::GDALc::GDAL_GCP_set_GCPLine", _wrap_GDAL_GCP_set_GCPLine},
-{"Geo::GDALc::GDAL_GCP_get_Info", _wrap_GDAL_GCP_get_Info},
-{"Geo::GDALc::GDAL_GCP_set_Info", _wrap_GDAL_GCP_set_Info},
-{"Geo::GDALc::GDAL_GCP_get_Id", _wrap_GDAL_GCP_get_Id},
-{"Geo::GDALc::GDAL_GCP_set_Id", _wrap_GDAL_GCP_set_Id},
 {"Geo::GDALc::GCPsToGeoTransform", _wrap_GCPsToGeoTransform},
 {"Geo::GDALc::delete_AsyncReader", _wrap_delete_AsyncReader},
 {"Geo::GDALc::AsyncReader_GetNextUpdatedRegion", _wrap_AsyncReader_GetNextUpdatedRegion},
@@ -22715,20 +22985,24 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::Dataset_SetProjection", _wrap_Dataset_SetProjection},
 {"Geo::GDALc::Dataset_GetGeoTransform", _wrap_Dataset_GetGeoTransform},
 {"Geo::GDALc::Dataset_SetGeoTransform", _wrap_Dataset_SetGeoTransform},
-{"Geo::GDALc::Dataset_BuildOverviews", _wrap_Dataset_BuildOverviews},
+{"Geo::GDALc::Dataset__BuildOverviews", _wrap_Dataset__BuildOverviews},
 {"Geo::GDALc::Dataset_GetGCPCount", _wrap_Dataset_GetGCPCount},
 {"Geo::GDALc::Dataset_GetGCPProjection", _wrap_Dataset_GetGCPProjection},
 {"Geo::GDALc::Dataset_GetGCPs", _wrap_Dataset_GetGCPs},
 {"Geo::GDALc::Dataset_SetGCPs", _wrap_Dataset_SetGCPs},
 {"Geo::GDALc::Dataset_FlushCache", _wrap_Dataset_FlushCache},
 {"Geo::GDALc::Dataset__AddBand", _wrap_Dataset__AddBand},
-{"Geo::GDALc::Dataset_CreateMaskBand", _wrap_Dataset_CreateMaskBand},
+{"Geo::GDALc::Dataset__CreateMaskBand", _wrap_Dataset__CreateMaskBand},
 {"Geo::GDALc::Dataset_GetFileList", _wrap_Dataset_GetFileList},
-{"Geo::GDALc::Dataset_WriteRaster", _wrap_Dataset_WriteRaster},
-{"Geo::GDALc::Dataset_ReadRaster", _wrap_Dataset_ReadRaster},
+{"Geo::GDALc::Dataset__WriteRaster", _wrap_Dataset__WriteRaster},
+{"Geo::GDALc::Dataset__ReadRaster", _wrap_Dataset__ReadRaster},
+{"Geo::GDALc::Dataset_StartTransaction", _wrap_Dataset_StartTransaction},
+{"Geo::GDALc::Dataset_CommitTransaction", _wrap_Dataset_CommitTransaction},
+{"Geo::GDALc::Dataset_RollbackTransaction", _wrap_Dataset_RollbackTransaction},
 {"Geo::GDALc::Band_XSize_get", _wrap_Band_XSize_get},
 {"Geo::GDALc::Band_YSize_get", _wrap_Band_YSize_get},
 {"Geo::GDALc::Band_DataType_get", _wrap_Band_DataType_get},
+{"Geo::GDALc::Band_GetDataset", _wrap_Band_GetDataset},
 {"Geo::GDALc::Band_GetBand", _wrap_Band_GetBand},
 {"Geo::GDALc::Band_GetBlockSize", _wrap_Band_GetBlockSize},
 {"Geo::GDALc::Band_GetColorInterpretation", _wrap_Band_GetColorInterpretation},
@@ -22756,8 +23030,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::Band_ComputeRasterMinMax", _wrap_Band_ComputeRasterMinMax},
 {"Geo::GDALc::Band_ComputeBandStats", _wrap_Band_ComputeBandStats},
 {"Geo::GDALc::Band_Fill", _wrap_Band_Fill},
-{"Geo::GDALc::Band_ReadRaster", _wrap_Band_ReadRaster},
-{"Geo::GDALc::Band_WriteRaster", _wrap_Band_WriteRaster},
+{"Geo::GDALc::Band__ReadRaster", _wrap_Band__ReadRaster},
+{"Geo::GDALc::Band__WriteRaster", _wrap_Band__WriteRaster},
 {"Geo::GDALc::Band_FlushCache", _wrap_Band_FlushCache},
 {"Geo::GDALc::Band_GetRasterColorTable", _wrap_Band_GetRasterColorTable},
 {"Geo::GDALc::Band_GetColorTable", _wrap_Band_GetColorTable},
@@ -22766,8 +23040,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::Band_GetDefaultRAT", _wrap_Band_GetDefaultRAT},
 {"Geo::GDALc::Band_SetDefaultRAT", _wrap_Band_SetDefaultRAT},
 {"Geo::GDALc::Band_GetMaskBand", _wrap_Band_GetMaskBand},
-{"Geo::GDALc::Band_GetMaskFlags", _wrap_Band_GetMaskFlags},
-{"Geo::GDALc::Band_CreateMaskBand", _wrap_Band_CreateMaskBand},
+{"Geo::GDALc::Band__GetMaskFlags", _wrap_Band__GetMaskFlags},
+{"Geo::GDALc::Band__CreateMaskBand", _wrap_Band__CreateMaskBand},
 {"Geo::GDALc::Band__GetHistogram", _wrap_Band__GetHistogram},
 {"Geo::GDALc::Band_GetDefaultHistogram", _wrap_Band_GetDefaultHistogram},
 {"Geo::GDALc::Band_SetDefaultHistogram", _wrap_Band_SetDefaultHistogram},
@@ -22805,6 +23079,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::RasterAttributeTable_SetLinearBinning", _wrap_RasterAttributeTable_SetLinearBinning},
 {"Geo::GDALc::RasterAttributeTable_GetRowOfValue", _wrap_RasterAttributeTable_GetRowOfValue},
 {"Geo::GDALc::RasterAttributeTable_ChangesAreWrittenToFile", _wrap_RasterAttributeTable_ChangesAreWrittenToFile},
+{"Geo::GDALc::RasterAttributeTable_DumpReadable", _wrap_RasterAttributeTable_DumpReadable},
+{"Geo::GDALc::TermProgress_nocb", _wrap_TermProgress_nocb},
 {"Geo::GDALc::_ComputeMedianCutPCT", _wrap__ComputeMedianCutPCT},
 {"Geo::GDALc::_DitherRGB2PCT", _wrap__DitherRGB2PCT},
 {"Geo::GDALc::_ReprojectImage", _wrap__ReprojectImage},
@@ -22813,6 +23089,7 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::_Polygonize", _wrap__Polygonize},
 {"Geo::GDALc::FillNodata", _wrap_FillNodata},
 {"Geo::GDALc::_SieveFilter", _wrap__SieveFilter},
+{"Geo::GDALc::_RegenerateOverviews", _wrap__RegenerateOverviews},
 {"Geo::GDALc::_RegenerateOverview", _wrap__RegenerateOverview},
 {"Geo::GDALc::ContourGenerate", _wrap_ContourGenerate},
 {"Geo::GDALc::_AutoCreateWarpedVRT", _wrap__AutoCreateWarpedVRT},
@@ -22829,8 +23106,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::GetCacheMax", _wrap_GetCacheMax},
 {"Geo::GDALc::GetCacheUsed", _wrap_GetCacheUsed},
 {"Geo::GDALc::SetCacheMax", _wrap_SetCacheMax},
-{"Geo::GDALc::GetDataTypeSize", _wrap_GetDataTypeSize},
-{"Geo::GDALc::DataTypeIsComplex", _wrap_DataTypeIsComplex},
+{"Geo::GDALc::_GetDataTypeSize", _wrap__GetDataTypeSize},
+{"Geo::GDALc::_DataTypeIsComplex", _wrap__DataTypeIsComplex},
 {"Geo::GDALc::GetDataTypeName", _wrap_GetDataTypeName},
 {"Geo::GDALc::GetDataTypeByName", _wrap_GetDataTypeByName},
 {"Geo::GDALc::GetColorInterpretationName", _wrap_GetColorInterpretationName},
@@ -22840,12 +23117,15 @@ static swig_command_info swig_commands[] = {
 {"Geo::GDALc::DecToPackedDMS", _wrap_DecToPackedDMS},
 {"Geo::GDALc::ParseXMLString", _wrap_ParseXMLString},
 {"Geo::GDALc::SerializeXMLTree", _wrap_SerializeXMLTree},
+{"Geo::GDALc::GetJPEG2000StructureAsString", _wrap_GetJPEG2000StructureAsString},
 {"Geo::GDALc::GetDriverCount", _wrap_GetDriverCount},
 {"Geo::GDALc::GetDriverByName", _wrap_GetDriverByName},
 {"Geo::GDALc::_GetDriver", _wrap__GetDriver},
 {"Geo::GDALc::_Open", _wrap__Open},
+{"Geo::GDALc::OpenEx", _wrap_OpenEx},
 {"Geo::GDALc::_OpenShared", _wrap__OpenShared},
 {"Geo::GDALc::IdentifyDriver", _wrap_IdentifyDriver},
+{"Geo::GDALc::GeneralCmdLineProcessor", _wrap_GeneralCmdLineProcessor},
 {0,0}
 };
 /* -----------------------------------------------------------------------------
@@ -23160,6 +23440,11 @@ XS(SWIG_init) {
   SWIG_TypeClientData(SWIGTYPE_p_GDALRasterBandShadow, (void*) "Geo::GDAL::Band");
   SWIG_TypeClientData(SWIGTYPE_p_GDALColorTableShadow, (void*) "Geo::GDAL::ColorTable");
   SWIG_TypeClientData(SWIGTYPE_p_GDALRasterAttributeTableShadow, (void*) "Geo::GDAL::RasterAttributeTable");
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "TermProgress", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_NewFunctionPtrObj((void *)(int (*)(double,char const *,void *))(GDALTermProgress), SWIGTYPE_p_f_double_p_q_const__char_p_void__int));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
   SWIG_TypeClientData(SWIGTYPE_p_GDALTransformerInfoShadow, (void*) "Geo::GDAL::Transformer");
   ST(0) = &PL_sv_yes;
   XSRETURN(1);
diff --git a/swig/perl/gdalconst_wrap.c b/swig/perl/gdalconst_wrap.c
index a3df647..866ea0f 100644
--- a/swig/perl/gdalconst_wrap.c
+++ b/swig/perl/gdalconst_wrap.c
@@ -2006,6 +2006,46 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_NearestNeighbour", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_NearestNeighbour)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Bilinear", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Bilinear)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Cubic", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Cubic)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_CubicSpline", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_CubicSpline)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Lanczos", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Lanczos)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Average", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Average)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Mode", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Mode)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "GRIORA_Gauss", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GRIORA_Gauss)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "GCI_Undefined", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GCI_Undefined)));
     SvREADONLY_on(sv);
@@ -2246,6 +2286,41 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_ALL", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_ALL)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_RASTER", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_RASTER)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_VECTOR", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_VECTOR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_READONLY", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_READONLY)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_UPDATE", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_UPDATE)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_SHARED", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_SHARED)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OF_VERBOSE_ERROR", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(GDAL_OF_VERBOSE_ERROR)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "DMD_LONGNAME", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_LONGNAME));
     SvREADONLY_on(sv);
@@ -2266,6 +2341,16 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DMD_EXTENSIONS", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_EXTENSIONS));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DMD_CONNECTION_PREFIX", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_CONNECTION_PREFIX));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "DMD_CREATIONOPTIONLIST", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_CREATIONOPTIONLIST));
     SvREADONLY_on(sv);
@@ -2276,11 +2361,21 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DMD_CREATIONFIELDDATATYPES", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_CREATIONFIELDDATATYPES));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "DMD_SUBDATASETS", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr(GDAL_DMD_SUBDATASETS));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_OPEN", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_OPEN));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "DCAP_CREATE", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_CREATE));
     SvREADONLY_on(sv);
@@ -2296,6 +2391,31 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_RASTER", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_RASTER));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_VECTOR", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_VECTOR));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_NOTNULL_FIELDS", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_NOTNULL_FIELDS));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_DEFAULT_FIELDS", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_DEFAULT_FIELDS));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "DCAP_NOTNULL_GEOMFIELDS", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr(GDAL_DCAP_NOTNULL_GEOMFIELDS));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "CPLES_BackslashQuotable", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1((int)(CPLES_BackslashQuotable)));
     SvREADONLY_on(sv);
diff --git a/swig/perl/index.dox b/swig/perl/index.dox
index 57af49b..80fac8a 100644
--- a/swig/perl/index.dox
+++ b/swig/perl/index.dox
@@ -4,13 +4,14 @@
 
 These pages document the development version of the GDAL Perl API,
 which is extended from the released versions APIs. Old versions: 
-<a href="/doc/Geo-GDAL-1.4/html/index.html">1.4</a>
-<a href="/doc/Geo-GDAL-1.5/html/index.html">1.5</a>
-<a href="/doc/Geo-GDAL-1.6/html/index.html">1.6</a>
-<a href="/doc/Geo-GDAL-1.7/html/index.html">1.7</a>
-<a href="/doc/Geo-GDAL-1.8/html/index.html">1.8</a>
-<a href="/doc/Geo-GDAL-1.9/html/index.html">1.9</a>
-<a href="/doc/Geo-GDAL-1.10/html/index.html">1.10</a>
+<a href="../1.4/index.html">1.4</a>
+<a href="../1.5/index.html">1.5</a>
+<a href="../1.6/index.html">1.6</a>
+<a href="../1.7/index.html">1.7</a>
+<a href="../1.8/index.html">1.8</a>
+<a href="../1.9/index.html">1.9</a>
+<a href="../1.10/index.html">1.10</a>
+<a href="../1.11/index.html">1.11</a>
 
 \section index_intro Introduction
 
@@ -19,10 +20,12 @@ library. The modules allow you to use Perl to access and manipulate
 all geospatial data that the installed GDAL library is configured to
 access and manipulate.
 
-This documentation covers mainly the syntax of the bindings. For more
-in-depth documentation see the main documentation of <a
-href="http://www.gdal.org/">GDAL</a> and <a
-href="http://www.gdal.org/ogr/">OGR</a>.
+This documentation covers the Perl bindings. For more in-depth
+documentation see the main documentation of <a
+href="http://www.gdal.org/">GDAL</a>. This documentation also
+emphasizes the recommended Perl API. Some methods and aliases to
+method names are left out since they may skip some built-in usability
+or other additions.
 
 Some arguments are optional and have a default value. This is
 illustrated like this:
@@ -53,23 +56,23 @@ In some cases a method may behave differently depending on the
 parameters that it gets:
 
 \code
-$object->method($hashref); # a method called with a reference to a hash
-$object->method($arrayref); # a method called with a reference to an array
+$object->method($hashref); # method called with a reference to a hash
+$object->method($arrayref); # method called with a reference to an array
 \endcode
 
 In some cases a method may examine the context in which it is called,
 and behave differently:
 
 \code
-$object->method();
+$object->method(); # method called in void context
 $return = $object->method(); # method called in scalar context
 @return = $object->method(); # method called in list context
 \endcode
 
 Many of the methods may throw an error, which can be caught by putting
-the call into eval{}; and then examining the contents of $@.
+the call into eval{}; and then examining the contents of $\@.
 
-\section class_methods_vs_object_methods Class methods vs object methods
+\section class_methods_vs_object_methods Class methods and attributes vs object methods and attributes 
 
 Some methods are class methods and some methods are object
 methods. Object methods are always invoked for objects, i.e.
@@ -92,9 +95,32 @@ Geo::GDAL::Class::subroutine();
 
 The disctinction between class methods and subroutines is subtle but
 often important. The method invocation passes the class name as the
-first argument while the subroutine invocation does not. Thus
+first argument while the subroutine invocation does not. Especially
 constructors (new and create) must be called as class methods.
 
+Similar to methods, also attributes are either class attributes or
+object attributes. Class attributes are global variables that are
+associated with a class and object attributes are variables owned by
+each individual object. Class attributes are used for example for
+enumerated values. In some cases object attributes can be accessed
+as hash values
+
+\code
+$value = $object->{attribute};
+$object->{attribute} = $new_value;
+\endcode
+
+but this is mostly deprecated and class and object attributes should
+be accessed through methods.
+
+Class attributes are also used for maintaining, e.g., is_a_part_of
+relationships between objects. Because Band objects are a part of
+Dataset objects, there is a class attribute (a hash) in Dataset, which
+maintains these relationships and makes sure the Dataset object that
+owns a Band object is not destroyed before the Band object. Also,
+definition objects that are linked to feature and layer objects are
+read-only, and this constraint is enforced using class attributes.
+
 \section index_exceptions Exceptions
 
 Geo::GDAL uses the Perl exception mechanism. This means that
@@ -102,11 +128,10 @@ exceptions that GDAL classifies as failures or fatal errors trigger a
 Perl exception, and an exception that is classified as a warning
 triggers a Perl warning.
 
-Perl exceptions can be caught by \a eval() and Perl warnings can be
-caught by signal '__WARN__'. Examples:
+Perl exceptions can be caught by eval() and Perl warnings can be
+caught by signal \_\_WARN\_\_. Examples:
 
 \code
-use Geo::GDAL;
 eval {
     $point = Geo::OGR::Geometry->create(WKT=>"POINTXX(1 1)");
 };
@@ -118,23 +143,56 @@ Prints:
 Error: RuntimeError OGR Error: Unsupported geometry type
 \endcode
 
+and
+
 \code
-use Geo::GDAL;
-BEGIN { $SIG{'__WARN__'} = sub {  print STDERR "Warning: @_"; } }
-Geo::GDAL::Driver('GTiff')->Create('x',10,10,1,'Byte',{a=>'b'});
+BEGIN { 
+    $SIG{__WARN__} = sub {  print STDERR "Warning: @_"; } 
+}
+Geo::GDAL::GetDriver('GTiff')->Create( Name => 'my.tiff', 
+                                       Width => 100, 
+                                       Height => 100, 
+                                       Type => 'Byte', 
+                                       Options => { my_unknown_option => 'b' } );
 \endcode
 
 Prints: 
 \code
-Warning: Driver GTiff does not support a creation option at site/lib/Geo/GDAL.pm line 771.
+Warning: Driver GTiff does not support my_unknown_option creation option at site/lib/Geo/GDAL.pm line 771.
+\endcode
+
+\section index_progress Progress callback
+
+Some methods accept a callback function for reporting the
+progress. The progress subroutine is called with three arguments: a
+number, a string, and user defined data. The user defined data 
+is an argument to the method.
+
+\code
+sub progress {
+    my($progress, $message, $data) = @_;
+    my $terminate = 0;
+    ...
+    return $terminate ? 0 : 1;
+}
 \endcode
 
 \section index_footer Note
 
 This documentation is generated from files within the GDAL
-distribution (directory swig/perl) with a tweaked version of <a
-href="http://www.bigsister.ch/doxygenfilter/">Perl Doxygen Filter</a>
-with Doxygen. The modified version is available <a
-href="https://geoinformatics.aalto.fi/svn/doxygenfilter/">here</a>.
+distribution (directory swig/perl) with Doxygen using a Perl module <a
+href="http://search.cpan.org/~jordan/Doxygen-Filter-Perl/">Doxygen::Filter::Perl</a>
+(see also <a
+href="https://rt.cpan.org/Public/Dist/Display.html?Name=Doxygen-Filter-Perl">the
+Doxygen::Filter::Perl bug reports</a>). A tailor made preprocessor in
+the GDAL distribution is used to process and put all Perl code and
+documentation into a single file (all.pm) for Doxygen.
+
+Many methods are just interfaces to non-Perl code in the bindings or
+GDAL and thus their code show as blank on these pages. The bindings
+are created with Swig, which adds some methods by default.
+
+Code examples in method pages contain dots ('.') to enforce
+indentation. This is due to a doxygen bug.
 
 */
diff --git a/swig/perl/lib/Geo/GDAL.dox b/swig/perl/lib/Geo/GDAL.dox
index f3fbf1c..1060f4f 100644
--- a/swig/perl/lib/Geo/GDAL.dox
+++ b/swig/perl/lib/Geo/GDAL.dox
@@ -1,89 +1,72 @@
-## @ignore Geo::GDALc
-
 ## @class Geo::GDAL
+# @brief GDAL utility functions and a root class for raster classes.
+#
+# Geo::GDAL wraps many GDAL utility functions and acts as a root class
+# for all GDAL raster classes. A "raster" is a dataset, whose core is
+# a rectagular grid or grids of pixels, called a "band" in GDAL. Each
+# pixel contains a numeric value of a specific data type
 
-## @ignore TIEHASH
-## @ignore CLEAR
-## @ignore FIRSTKEY
-## @ignore NEXTKEY
-## @ignore FETCH
-## @ignore STORE
-## @ignore this
-## @ignore UseExceptions
-## @ignore DontUseExceptions
-## @ignore PushErrorHandler
-## @ignore PopErrorHandler
-## @ignore Debug
-## @ignore Error
-## @ignore ErrorReset
-## @ignore GetLastErrorNo
-## @ignore GetLastErrorType
-## @ignore GetLastErrorMsg
-## @ignore ApplyGeoTransform
-## @ignore ContourGenerate
-## @ignore EscapeString
 ## @ignore FileFromMemBuffer
-## @ignore FillNodata
 ## @ignore GDALDestroyDriverManager
 ## @ignore HasThreadSupport
-## @ignore InvGeoTransform
-## @ignore Mkdir
-## @ignore Rename
-## @ignore Rmdir
 ## @ignore TermProgress
 ## @ignore TermProgress_nocb
-## @ignore Unlink
-## @ignore callback_d_cp_vp 
-
-## @fn @ReadDir($dir)
-# @return Contents of the directory.
 
-## @fn @Stat($filename)
-# @return ($filemode, $filesize). filemode is f for a plain file, d
-# for a directory, l for a symbolic link, p for a named pipe (FIFO), S
-# for a socket, b for a block special file, and c for a character
-# special file.
-
-## @fn Unlink($filename)
-# @param filename The file to delete.
-# @return 0 on success and -1 on an error.
+## @ignore PopErrorHandler
+## @ignore PushErrorHandler
+## @ignore SetErrorHandler
+## @ignore Error
+## @ignore ErrorReset
+## @ignore GetLastErrorMsg
+## @ignore GetLastErrorNo
+## @ignore GetLastErrorType
 
-## @fn $VSIFOpenL($filename, $mode)
-# @param filename Name of the file to open. For example "/vsimem/x".
-# @param mode Access mode. 'r', 'r+', 'w', etc.
-# @return A file handle on success.
+## @ignore GeneralCmdLineProcessor
 
-## @fn VSIFCloseL($file)
-# @param file The file handle.
+## @ignore GetDataTypeName
+## @ignore GetDataTypeByName
+## @ignore GetColorInterpretationName
+## @ignore GetPaletteInterpretationName
 
-## @fn $VSIFWriteL($scalar, $file)
-# @param scalar The byte string to write to the file.
-# @param file The file handle.
-# @return Number of bytes written into the file.
+## @ignore VSIFOpenL
+## @ignore VSIFWriteL
+## @ignore VSIFCloseL
+## @ignore VSIFReadL
+## @ignore VSIFSeekL
+## @ignore VSIFTellL
+## @ignore VSIFTruncateL
+## @ignore Mkdir
+## @ignore ReadDir
+## @ignore ReadDirRecursive
+## @ignore Rename
+## @ignore RmDir
+## @ignore Rmdir
+## @ignore Stat
+## @ignore Unlink
 
-## @fn $VSIFReadL($count, $file)
-# @param count The number of bytes to read from the file.
-# @param file The file handle.
-# @return A byte string.
+## @ignore FillNodata
+## @ignore ContourGenerate
+## @ignore RegenerateOverviews
+## @ignore RegenerateOverview
 
-## @fn $VersionInfo($request = 'VERSION_NUM')
+## @cmethod $VersionInfo($request = 'VERSION_NUM')
 # @param request A string specifying the request. Currently either
 # "VERSION_NUM", "RELEASE_DATE", "RELEASE_NAME", or
 # "--version". Default is "VERSION_NUM".
 # @return Requested information.
 
-## @fn PushFinderLocation($path)
+## @cmethod PushFinderLocation($path)
 # Add a path to the set of paths from where GDAL support files are
 # sought.
 
-## @fn PopFinderLocation()
+## @cmethod PopFinderLocation()
 # Remove the latest addition from the set of support file search
 # paths.
 
-## @fn FinderClean()
+## @cmethod FinderClean()
 # Clear the set of support file search paths.
 
-## @fn $FindFile($class, $basename)
+## @cmethod $FindFile($class, $basename)
 # Search for GDAL support files.
 #
 # An example:
@@ -102,7 +85,7 @@
 #  'pcs.csv'.
 # @return the path to the searched file or undef.
 
-## @fn SetConfigOption($key, $value)
+## @cmethod SetConfigOption($key, $value)
 # @param key A GDAL config option. Possible values include
 # 'GDAL_FORCE_CACHING', 'USE_RRD', GDAL_DATA', 'GDAL_SKIP',
 # 'GDAL_DRIVER_PATH', 'GDAL_IGNORE_AXIS_ORIENTATION',
@@ -116,58 +99,55 @@
 # @param value A value for the option, typically 'YES', 'NO',
 # undef, a path, or a filename.
 
-## @fn $GetConfigOption($key, $default)
+## @cmethod $GetConfigOption($key, $default)
 # @param key A GDAL config option.
 # @param default A default value for the option.
 # @return the value of the GDAL config option or the value of the
 # default parameter.
 
-## @ignore CPLBinaryToHex()
-
-## @ignore CPLHexToBinary()
-
-## @fn \@GCPsToGeoTransform(\@GCPs, $ApproxOK = 1)
-# Compute transformation coefficients from a set of Geo::GDAL::GCP
-# objects
-# The geo transformation has the form
-# \code
-# x = a + column * b + row * c
-# y = d + column * e + row * f
-# \endcode
-# where<br/>
-# (column,row) is the location in pixel coordinates<br/>
-# (x,y) is the location in projection coordinates<br/>
-# @param GCPs A set of Geo::GDAL::GCP objects.
-# @param ApproxOK Minimize the error in the coefficient.
-# @return [$a, $b, $c, $d, $e, $f]
-
-## @ignore AllRegister()
+## @ignore ApplyGeoTransform
+## @ignore InvGeoTransform
+## @ignore GCPsToGeoTransform
 
-## @fn $GetCacheMax()
+## @cmethod $GetCacheMax()
 # @return maximum amount of memory (as bytes) for caching within GDAL.
 
-## @fn SetCacheMax($Bytes)
+## @cmethod SetCacheMax($Bytes)
 # @param Bytes New maximum amount of memory for caching within GDAL.
+#
 
-## @fn $GetCacheUsed()
+## @cmethod $GetCacheUsed()
 # @return the amount of memory currently used for caching within GDAL.
 
-## @fn $GetDataTypeSize($GDALDataType)
-# @param GDALDataType An integer (one of keys of
-# Geo::GDAL::TYPE_INT2STRING hash).
+## @cmethod @DataTypes()
+# @return a list of GDAL pixel data types. These are currently:
+# +list Geo::GDAL::Const GDT_ TypeCount
+
+## @cmethod $GetDataTypeSize($DataType)
+# @param DataType A GDAL pixel data type (one of those listed by Geo::GDAL::DataTypes).
 # @return the size as the number of bits.
 
-## @fn @DataTypeValueRange($DataType)
-# @param DataType Data type as string (one of Byte UInt16 Int16 UInt32
-# Int32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64).
+## @cmethod @DataTypeValueRange($DataType)
+# @param DataType Data type (one of those listed by Geo::GDAL::DataTypes).
+# @note Some returned values are inaccurate.
+#
 # @return the minimum, maximum range of the data type.
 
-## @fn $DataTypeIsComplex($GDALDataType)
-# @param GDALDataType An integer (one of keys of
-# Geo::GDAL::TYPE_INT2STRING hash).
+## @cmethod $DataTypeIsComplex($DataType)
+# @param DataType A GDAL pixel data type (one of those listed by Geo::GDAL::DataTypes).
 # @return true if the data type is a complex number.
 
-## @fn $DecToDMS($angle, $axis, $precision=2)
+## @cmethod @AccessTypes()
+# @return a list of GDAL data set open modes. These are currently:
+# +list Geo::GDAL::Const GA_
+
+## @cmethod @ResamplingTypes()
+# @return a list of GDAL resampling methods.
+
+## @cmethod @RIOResamplingTypes()
+# @return a list of GDAL raster IO resampling methods.
+
+## @cmethod $DecToDMS($angle, $axis, $precision=2)
 # Convert decimal degrees to degrees, minutes, and seconds string
 # @param angle A number
 # @param axis A string specifying latitude or longitude ('Long').
@@ -175,99 +155,116 @@
 # @return a string nndnn'nn.nn'"L where n is a number and L is either
 # N or E
 
-## @fn $PackedDMSToDec($packed)
+## @cmethod $PackedDMSToDec($packed)
 # @param packed DMS as a number DDDMMMSSS.SS
 # @return decimal degrees
 
-## @fn $DecToPackedDMS($dec)
+## @cmethod $DecToPackedDMS($dec)
 # @param dec Decimal degrees
 # @return packed DMS, i.e., a number DDDMMMSSS.SS
 
-## @fn $NodeType($type)
+## @cmethod @NodeTypes()
+# @return a list of GDAL XML parser node types. These are currently:
+# +list Geo::GDAL::Const CXT_
+
+## @cmethod $NodeType($type)
 # Convert between integer and string expressions of CPLXMLNodeTypes
-# @param type
-# @return type
+# @param type (as integer)
+# @return type (as string)
 
-## @fn \@ParseXMLString($XML)
+## @cmethod \@ParseXMLString($XML)
 # Parses a given XML into an array of arrays and returns a reference
 # to that. An array in the structure is: (CPLXMLNodeType, value,
 # child, child, ...). CPLXMLNodeType is an integer.
 # @param XML
-# @return an XMLTree
+# @return an XMLTree.
+#
+# Example:
+# \code
+open FILE, "data.xml" or die "Couldn't open file: $!"; 
+my $xml = join("", <FILE>); 
+close FILE;
+my $tree = Geo::GDAL::ParseXMLString($xml);
+traverse($tree);
+print Geo::GDAL::SerializeXMLTree($tree),"\n";
+ 
+sub traverse {
+.    my $node = shift;
+.    my $type = shift @$node;
+.    my $data = shift @$node;
+.    $type = Geo::GDAL::NodeType($type); 
+.    print "$type, $data\n";
+.    for my $child (@$node) {
+.        traverse($child);
+.    }
+}
+# \endcode
 
-## @fn @NodeData($node)
+## @cmethod @NodeData($node)
 # @param node
 # @return ($NodeType, $value)
 
-## @fn @Children($node)
+## @cmethod @Children($node)
 # @param node
 # @return
 
-## @fn @Child($node, $i)
+## @cmethod @Child($node, $i)
 # @param node
 # @param i 0 .. number of children - 1
 # @return
 
-## @fn $SerializeXMLTree(\@XMLTree)
+## @cmethod $SerializeXMLTree(arrayref XMLTree)
 # @param XMLTree
 # @return XML
 
-## @fn @Drivers()
-# An example:
-# \code
-# use Geo::GDAL;
-# for my $driver (Geo::GDAL::Drivers) {
-#    print $driver->{ShortName},"\n";
-# }
-# \endcode
-# Prints short names of all available GDAL raster drivers.
-# @return all GDAL raster driver objects in a list.
+## @ignore Drivers
+## @ignore GetDriverCount
 
-## @fn $GetDriverCount()
-# @return the number of available GDAL raster drivers.
+## @cmethod @GetDriverNames()
+# @return a list of the named of all (available and registered) GDAL
+# raster drivers.
 
-## @fn Geo::GDAL::Driver Driver($driver)
-# Create a driver object for the internal GDAL driver.
-# @note a.k.a. GetDriver
-# @param driver The name or number of the driver.
-# @return a new Geo::GDAL::Driver object
+## @ignore Driver
+## @ignore GetDriverByName
 
-## @fn Geo::GDAL::Driver GetDriverByName($ShortName)
-# @param ShortName A short name of the driver.
-# @return a new Geo::GDAL::Driver object
+## @cmethod Geo::GDAL::Driver GetDriver($name)
+# Create a driver object for the internal GDAL driver.
+# @param name the (short) name of the driver.
+# @return a Geo::GDAL::Driver object, which represents the internal driver.
 
-## @fn Geo::GDAL::Driver IdentifyDriver($name, $siblings)
-# @param name A dataset path.
-# @param siblings [optional] A list of names of files in the directory specified by \a name.
-# @return a new Geo::GDAL::Driver object
+## @cmethod Geo::GDAL::Driver IdentifyDriver($path, $siblings)
+# @param path a dataset path.
+# @param siblings [optional] A list of names of files in the directory
+# specified by the path.
+# @return a Geo::GDAL::Driver object, which represents an internal driver.
 
-## @fn ComputeMedianCutPCT($red, $green, $blue, $num_colors, $colors, $callback, $callback_data)
+## @cmethod ComputeMedianCutPCT(Geo::GDAL::Band red, Geo::GDAL::Band green, Geo::GDAL::Band blue, $num_colors, $colors, subref progress, $progress_data)
 # Compute an "optimal" color table for a three band image.
 # @param red a Geo::GDAL::Band object
 # @param green a Geo::GDAL::Band object
 # @param blue a Geo::GDAL::Band object
 # @param num_colors the desired number of colors 
 # @param colors an empty Geo::GDAL::ColorTable object
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn DitherRGB2PCT($red, $green, $blue, $target, $colors, $callback, $callback_data)
+## @cmethod DitherRGB2PCT($red, $green, $blue, $target, $colors, subref progress, $progress_data)
 # Dither a three band image into one band using a color table.
 # @param red a Geo::GDAL::Band object
 # @param green a Geo::GDAL::Band object
 # @param blue a Geo::GDAL::Band object
 # @param target a Geo::GDAL::Band object
 # @param colors a Geo::GDAL::ColorTable object
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn ReprojectImage($src_ds, $dst_ds, $src_wkt=undef, $dst_wkt=undef, $ResampleAlg='NearestNeighbour', $WarpMemoryLimit=0, $maxerror=0.0, $callback, $callback_data)
+## @cmethod ReprojectImage($src_ds, $dst_ds, $src_wkt=undef, $dst_wkt=undef, $ResampleAlg='NearestNeighbour', $WarpMemoryLimit=0, $maxerror=0.0, subref progress, $progress_data)
 # @param src_ds Source dataset.
 # @param dst_ds Destination dataset.
 # @param src_wkt Source projection as a WKT.
@@ -277,24 +274,24 @@
 # @param maxerror Maximum error measured in input pixels that is
 # allowed in approximating the transformation. Default is 0.0, i.e.,
 # exact calculations.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data).
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data).
 # Reprojection is terminated if the progress function returns 0.
-# @param callback_data [optional]
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdalwarper_8h.html">Documentation for GDAL warper</a>
 
-## @fn Geo::GDAL::Dataset AutoCreateWarpedVRT(Geo::GDAL::Dataset src, $src_wkt=undef, $dst_wkt=undef, $ResampleAlg='NearestNeighbour', $maxerror=0.0)
+## @cmethod Geo::GDAL::Dataset AutoCreateWarpedVRT(Geo::GDAL::Dataset src, Geo::OSR::SpatialReference src_srs=undef, Geo::OSR::SpatialReference dst_srs=undef, $ResampleAlg='NearestNeighbour', $maxerror=0.0)
 # @param src
-# @param src_wkt A WKT string.
-# @param dst_wkt A WKT string.
-# @param ResampleAlg one of 'NearestNeighbour', 'Bilinear', 'Cubic', or 'CubicSpline'.
+# @param src_srs source projection.
+# @param dst_srs destination projection.
+# @param ResampleAlg one of Geo::GDAL::ResamplingTypes().
 # @param maxerror
 # @return a new Geo::GDAL::Dataset object
 #
 # <a href="http://www.gdal.org/gdalwarper_8h.html">Documentation for GDAL warper</a>
 
-## @fn ComputeProximity(Geo::GDAL::Band src, Geo::GDAL::Band proximity, \%options, $callback, $callback_data)
+## @cmethod ComputeProximity(Geo::GDAL::Band src, Geo::GDAL::Band proximity, hashref options, subref progress, $progress_data)
 # @param src The raster from which the proximities are computed from.
 # @param proximity The raster to which the proximities are computed to.
 # @param options Options. Supported key, value pairs are 
@@ -315,13 +312,13 @@
 # - FIXED_BUF_VAL => n If this option is set, all pixels within the
 # MAXDIST threadhold are set to this fixed value instead of to a
 # proximity distance.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn RasterizeLayer(Geo::GDAL::Dataset ds, \@bands, Geo::OGR::Layer layer, $transformer, $arg, \@burn_values, \%options, $callback, $callback_data)
+## @cmethod RasterizeLayer(Geo::GDAL::Dataset ds, arrayref bands, Geo::OGR::Layer layer, $transformer, $arg, arrayref burn_values, hashref options, subref progress, $progress_data)
 # @param ds
 # @param bands A reference to a list of bands to be updated.
 # @param layer
@@ -329,13 +326,13 @@
 # @param arg Transformer argument, must be undef.
 # @param burn_values Values to be used for burning the geometries. One for each layer.
 # @param options Not used.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn Polygonize(Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::OGR::Layer out, $PixValField, \%options, $callback, $callback_data)
+## @cmethod Polygonize(Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::OGR::Layer out, $PixValField, hashref options, subref progress, $progress_data)
 # @param src
 # @param mask All pixels in the mask band with a value other than zero
 # will be considered suitable for collection as polygons. Must be
@@ -344,13 +341,13 @@
 # @param PixValField The index (or name) of the field in output layer
 # into which the pixel value of the polygon should be written.
 # @param options Not used.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn SieveFilter(Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::GDAL::Band dst, $threshold, $connectedness, \%options, $callback, $callback_data)
+## @cmethod SieveFilter(Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::GDAL::Band dst, $threshold, $connectedness, hashref options, subref progress, $progress_data)
 # Removes small raster polygons.
 # @param src
 # @param mask
@@ -358,94 +355,61 @@
 # @param threshold An integer.
 # @param connectedness 4 or 8
 # @param options Not used.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
-## @fn RegenerateOverviews(Geo::GDAL::Band src, \@overviews, $resampling, $callback, $callback_data)
-# @todo This is not yet available
-# @param src
-# @param overviews A list of Geo::GDAL::Band's for the overviews.
-# @param resampling 'NEAREST', 'AVERAGE', or 'GAUSS'
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
-
-## @fn RegenerateOverview(Geo::GDAL::Band src, Geo::GDAL::Band overview, $resampling, $callback, $callback_data)
-# @param src
-# @param overview
-# @param resampling 'NEAREST', 'AVERAGE', or 'GAUSS'
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
-
-## @fn \@GeneralCmdLineProcessor(\@argv, $options = 0)
+## @cmethod \@GeneralCmdLineProcessor(arrayref argv, $options = 0)
 # @param argv
 # @param options integer
 # @return arrayref
 
-## @fn $PackCharacter($DataType)
+## @cmethod $PackCharacter($DataType)
 # Get the character that is needed for Perl's pack and unpack when
 # they are used with Geo::GDAL::Band::ReadRaster and
 # Geo::GDAL::Band::WriteRaster. Note that Geo::GDAL::Band::ReadTile
 # and Geo::GDAL::Band::WriteTile have simpler interfaces that do not
 # require pack and unpack.
-# @param DataType GDAL data type value, typically from $band->{DataType}
-# @return character which can be used in Perl's pack and unpack
+# @param DataType A GDAL pixel data type (typically from $band->{DataType}).
+# @return a character which can be used in Perl's pack and unpack.
 
-## @fn Geo::GDAL::Dataset Open($name, $access='ReadOnly')
+## @cmethod Geo::GDAL::Dataset Open($name, $access = 'ReadOnly')
 # An example
 # \code
 # use Geo::GDAL;
 # $ds = Geo::GDAL::Open('existing.tiff', 'Update');
 # \endcode
 # @param name
-# @param access either 'ReadOnly' or 'Update'
-# @return a new Geo::GDAL::Dataset object
+# @param access Access type (one of those listed by Geo::GDAL::AccessTypes).
+# @return a new Geo::GDAL::Dataset object.
 
-## @fn Geo::GDAL::Dataset OpenShared($name, $access='ReadOnly')
+## @cmethod Geo::GDAL::Dataset OpenShared($name, $access = 'ReadOnly')
 # @param name
-# @param access either 'ReadOnly' or 'Update'
-# @return a new Geo::GDAL::Dataset object
-
-## @fn $GetDataTypeName($GDALDataType)
-# @deprecated use string names
-# @param GDALDataType
-# @return
+# @param access Access type (one of those listed by Geo::GDAL::AccessTypes).
+# @return a new Geo::GDAL::Dataset object.
 
-## @fn $GetDataTypeByName($GDALDataType)
-# @deprecated use string names
-# @param GDALDataType
-# @return
+## @cmethod Geo::GDAL::Dataset OpenEx($name, $open_flags = 0, array reference allowed_drivers = undef, array reference open_options = undef, array reference sibling_files = undef);
+# @return a new Geo::GDAL::Dataset object.
 
-## @fn $GetColorInterpretationName($ColorInterpretation)
-# @deprecated use string names
-# @param ColorInterpretation
-# @return
 
-## @fn $GetPaletteInterpretationName($PaletteInterpretation)
-# @deprecated use string names
-# @param PaletteInterpretation
-# @return
 
 
 ## @class Geo::GDAL::AsyncReader
+# @brief Enable asynchronous requests.
 # @isa (Geo::GDAL)
-# This class is not yet documented not tested in the GDAL Perl wrappers
+# @todo Test and document.
+#
+# This class is not yet documented nor tested in the GDAL Perl wrappers
+
 
-## @ignore GetNextUpdatedRegion
-## @ignore LockBuffer
-## @ignore UnlockBuffer
 
 
 ## @class Geo::GDAL::MajorObject
+# @brief An object, which holds meta data.
 # @isa (Geo::GDAL)
 
-## @attr DOMAINS
-# a class specific list, well known metadata domains
-
 ## @cmethod Domains
 # @return the class specific DOMAINS list
 
@@ -458,12 +422,12 @@
 
 ## @method SetDescription($NewDesc)
 # @param NewDesc
+#
 
 ## @ignore SetMetadataItem
-
 ## @ignore GetMetadataItem
 
-## @method \%Metadata(\%metadata = undef, $domain = '')
+## @method \%Metadata(hashref metadata = undef, $domain = '')
 # @param metadata
 # @param domain
 # @return the metadata in a non-void context.
@@ -473,21 +437,22 @@
 # @param domain
 # @return
 
-## @method SetMetadata(\%metadata, $domain = "")
+## @method SetMetadata(hashref metadata, $domain = "")
 # @note see Metadata
 # @param metadata
 # @param domain
+#
+
+
 
 
 ## @class Geo::GDAL::Driver
+# @brief A raster format driver.
 # @isa (Geo::GDAL::MajorObject Geo::GDAL)
 
 ## @ignore Register
-
 ## @ignore Deregister
 
-## @ignore CopyFiles
-
 ## @attr ShortName
 # $driver->{ShortName}
 
@@ -502,14 +467,23 @@
 # @param NewName String.
 # @param OldName String.
 
+## @method Copy($NewName, $OldName)
+# Copy the files of a dataset.
+# @param NewName String.
+# @param OldName String.
+
 # @method $Name
 # @return The short name of the driver.
 
-## @cmethod @Capabilities()
-# @return A list of capabilities. The class method returns a list of
-# all potential capabilities a driver may have; the object method
-# returns a list of all capabilities the driver has.
-# Currently capabilities are 'Create' and 'CreateCopy'.
+## @method @Capabilities()
+# @return A list of capabilities. When executed as a class method
+# returns a list of all potential capabilities a driver may have. When
+# executed as an object method returns a list of all capabilities the
+# driver has.
+#
+# Currently capabilities are:
+# +list Geo::GDAL::Const DCAP_
+#
 # Examples.
 # \code
 # @all_capabilities = Geo::GDAL::Driver::Capabilities;
@@ -533,29 +507,30 @@
 # name, type and description or Value. Value is a listref.
 
 ## @method @CreationDataTypes()
-# @return a list of data types (strings) that can be used for new datasets.
+# @return a list of data types that can be used for new datasets.
 
-## @method Geo::GDAL::Dataset Create($name, $xsize, $ysize, $bands =1, $type = 'Byte', \%options = undef)
+## @ignore CreateDataset
+
+## @method Geo::GDAL::Dataset Create(%params)
 # Create a GDAL dataset using this driver.
 # @note a.k.a. CreateDataset
 #
+# @note As a list the parameters are: Name, Width, Height, NumberOfBands, PixelDataType, Options
+#
 # Create a new Geo::GDAL::Dataset
-# @param name
-# @param xsize
-# @param ysize
-# @param bands
-# @param type One of the data types this driver supports.
-# @param options An anonymous hash of driver specific parameters.
+# @param params named parameters:
+# - \a Name the name of the dataset (default is 'unnamed').
+# - \a Width the width of the dataset (default is 256).
+# - \a Height the height of the dataset (default is 256).
+# - \a Bands number of bands in the dataset (default is 1).
+# - \a Type the data type of the pixels the dataset (default is 'Byte'). One of Geo::OGR::Driver::CreationDataTypes.
+# - \a Options creation options as a reference to a hash (default is {}).
 #
-# Usage:
-# \code
-# $ds = Geo::GDAL::Dataset::Create(...arguments...);
-# \endcode
-# @return a new Geo::GDAL::Dataset object
+# @return a new Geo::GDAL::Dataset object.
 
 ## @ignore CreateCopy
 
-## @method Geo::GDAL::Dataset Copy($name, $src, $strict = 1, \%options = undef)
+## @method Geo::GDAL::Dataset Copy($name, $src, $strict = 1, hashref options = undef)
 # Create a new Geo::GDAL::Dataset as a copy of an existing dataset.
 # @note a.k.a. CreateCopy 
 # @param name
@@ -568,46 +543,56 @@
 # @param name
 
 
+
+
 ## @class Geo::GDAL::GCP
+# @brief A ground control point for georeferencing images.
 # @isa (Geo::GDAL)
 
-## @cmethod $new($x = 0.0, $y = 0.0, $z = 0.0, $pixel = 0.0, $line = 0.0, $info = "", $id = "")
-# @param x
-# @param y
-# @param z
-# @param pixel
-# @param line
-# @param info
-# @param id
+## @cmethod $new($x = 0.0, $y = 0.0, $z = 0.0, $column = 0.0, $row = 0.0, $info = "", $id = "")
+# @param x projection coordinate
+# @param y projection coordinate
+# @param z projection coordinate
+# @param column pixel x coordinate
+# @param row pixel y coordinate
+# @param info informational message
+# @param id unique identifier (string)
 # @return a new Geo::GDAL::GCP object
 
-## @attr GCPX
-# scalar (access as $gcp->{GCPX})
+## @attr X
+# projection coordinate (access as $gcp->{X})
 
-## @attr GCPY
-# scalar (access as $gcp->{GCPY})
+## @attr Y
+# projection coordinate (access as $gcp->{Y})
 
-## @attr GCPZ
-# scalar (access as $gcp->{GCPZ})
+## @attr Z
+# projection coordinate (access as $gcp->{Z})
 
-## @attr GCPPixel
-# scalar (access as $gcp->{GCPPixel})
-# the pixel's j coordinate
+## @attr Column
+# pixel x coordinate (access as $gcp->{Column})
+# @note Pixel is deprecated.
+#
 
-## @attr GCPLine
-# scalar (access as $gcp->{GCPLine})
-# the pixel's i coordinate
+## @attr Row
+# pixel y coordinate (access as $gcp->{Row})
+# @note Line is deprecated.
+#
 
 ## @attr Info
-# scalar (access as $gcp->{Info})
+# informational message (access as $gcp->{Info})
 
 ## @attr Id
-# scalar (access as $gcp->{Id})
+# unique identifier (string) (access as $gcp->{Id})
+
+
 
 
 ## @class Geo::GDAL::Dataset
+# @brief A set of associated raster bands.
 # @isa (Geo::GDAL::MajorObject Geo::GDAL)
 
+## @ignore FlushCache
+
 ## @attr RasterXSize
 # scalar (access as $dataset->{RasterXSize})
 
@@ -624,12 +609,12 @@
 # $ds = Geo::GDAL::Dataset::Open('/data/dem.tiff', 'Update');
 # \endcode
 # @param name
-# @param access Either 'ReadOnly' or 'Update'.
+# @param access Access type (one of those listed by Geo::GDAL::AccessTypes).
 # @return a new Geo::GDAL::Dataset object.
 
 ## @cmethod Geo::GDAL::Dataset OpenShared($name, $access='ReadOnly')
 # @param name
-# @param access Either ReadOnly or Update.
+# @param access Access type (one of those listed by Geo::GDAL::AccessTypes).
 # @return a new Geo::GDAL::Dataset object.
 
 ## @method @GetFileList()
@@ -641,6 +626,8 @@
 ## @method Geo::GDAL::Driver GetDriver()
 # @return a new Geo::GDAL::Driver object
 
+## @ignore GetRasterBand
+
 ## @method Geo::GDAL::Band Band($index)
 # Create a band object for the band within the dataset.
 # @note a.k.a. GetRasterBand
@@ -650,110 +637,127 @@
 ## @method @Bands()
 # @return a list of new Geo::GDAL::Band objects
 
-## @method $Projection($projection)
-# Get or set the projection.
-# @param projection [optional] as WKT
-# @return the projection as WKT
-
-## @method $GetProjection()
-# @return the projection as WKT
-
 ## @ignore GetProjectionRef
-
-## @method $SetProjection($proj)
-# @param proj projection as WKT
-
-## @method @GeoTransform(@geo_transform)
-# Transformation from pixel coordinates (x,y) to projection
-# coordinates (Xp, Yp)
+## @ignore GetProjection
+## @ignore SetProjection
+## @ignore Projection
+
+## @method Geo::OSR::SpatialReference SpatialReference(Geo::OSR::SpatialReference sr)
+# Get or set the projection of this dataset.
+# @param sr [optional] a Geo::OSR::SpatialReference object,
+# which replaces the existing projection definition of this dataset.
+# @return a Geo::OSR::SpatialReference object, which represents the
+# projection of this dataset.
+# @note Methods GetProjection, SetProjection, and Projection return WKT strings.
+
+## @ignore GetGeoTransform
+## @ignore SetGeoTransform
+
+## @method Geo::GDAL::GeoTransform GeoTransform(Geo::GDAL::GeoTransform $geo_transform)
+# Transformation from pixel coordinates (column,row) to projection
+# coordinates (x,y)
 # \code
-# Xp = geo_transform[0] + x*geo_transform[1] + y*geo_transform[2]
-# Yp = geo_transform[3] + x*geo_transform[4] + y*geo_transform[5]
+# x = geo_transform[0] + column*geo_transform[1] + row*geo_transform[2]
+# y = geo_transform[3] + column*geo_transform[4] + row*geo_transform[5]
 # \endcode
 # @param geo_transform [optional]
 # @return the geo transform in a non-void context.
 
-## @method \@GetGeoTransform()
-# @return a reference to an array of six parameters.
-
-## @method SetGeoTransform(\@GeoTransform)
-# @param GeoTransform
-
-## @method BuildOverviews($resampling, \@overviews, $callback, $callback_data)
-# @param resampling Either 'NEAREST', 'AVERAGE', or 'AVERAGE_MAGPHASE'.
+## @method BuildOverviews($resampling, arrayref overviews, subref progress, $progress_data)
+# @param resampling the resampling method, one of Geo::GDAL::RIOResamplingTypes.
 # @param overviews The list of overview decimation factors to
 # build. For example [2,4,8].
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
+
+## @ignore GetGCPCount
+## @ignore GetGCPs
+## @ignore SetGCPs
 
-## @method @GCPs(@GCPs, $GCPProjection)
+## @method @GCPs(@GCPs, Geo::OSR::SpatialReference sr)
 # Get or set the GCPs and their projection.
 # @param GCPs [optional] a list of Geo::GDAL::GCP objects
-# @param GCPProjection [optional] Projection string.
-# @return a list of Geo::GDAL::GCP objects followed by a GCPProjection
-
-## @method $GetGCPCount()
-# @return the number of GCPs
+# @param sr [optional] the projection of the GCPs.
+# @return a list of Geo::GDAL::GCP objects followed by a Geo::OSR::SpatialReference object.
 
 ## @method $GetGCPProjection()
 # @return projection string.
 
-## @method \@GetGCPs()
-# @return 
-
-## @method SetGCPs(\@GCPs, $GCPProjection)
-# @param GCPs
-# @param GCPProjection
-
 ## @method FlushCache()
 # Write cached data to disk. There is usually no need to call this
 # method.
 
-## @method AddBand($datatype = 'Byte', \%options = 0)
+## @method AddBand($datatype = 'Byte', hashref options = 0)
 # Add a new band to the dataset. The driver must support the action.
-# @param datatype Data type string. The data type must be supported by
-# the driver of this dataset. GDAL raster data types are Byte UInt16
-# Int16 UInt32 Int32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64.
-# @param options A reference to a hash of format specific key=>value options.
+# @param datatype GDAL pixel data type (one of those listed by Geo::GDAL::DataTypes).
+# @param options reference to a hash of format specific key=>value options.
 
-## @method WriteRaster($xoff, $yoff, $xsize, $ysize, $buf, $buf_xsize = undef, $buf_ysize = undef, $buf_type = undef, \@band_list = undef)
-# Write a buffer into the raster. Create the buffer with \a pack function of Perl.
+## @method WriteRaster(%params)
+# Write data into the dataset. 
+#
+# @param params named parameters. These are
+# - \a XOff x offset (pixel coordinates) (default is 0)
+# - \a YOff y offset (pixel coordinates) (default is 0)
+# - \a XSize width of the area to write (default is the width of the dataset)
+# - \a YSize height of the area to write (default is the height of the dataset)
+# - \a Buf a buffer containing the data. Create the buffer with \a pack function of Perl. See Geo::GDAL::Band::PackCharacter.
+# - \a BufXSize (default is undef, i.e., the same as XSize)
+# - \a BufYSize (default is undef, i.e., the same as YSize)
+# - \a BufType data type of the buffer (default is the data type of the first band)
+# - \a BandList a reference to an array of band indeces (default is [1])
+# - \a BufPixelSpace (default is 0)
+# - \a BufLineSpace (default is 0)
+# - \a BufBandSpace (default is 0)
+#
+# If the parameters are given as a list the order is as above.
 # <a href="http://www.gdal.org/classGDALDataset.html">Entry in GDAL docs (method RasterIO)</a>
-# @param xoff
-# @param yoff
-# @param xsize
-# @param ysize
-# @param buf
-# @param buf_xsize
-# @param buf_ysize
-# @param buf_type
-# @param band_list
-
-## @method $ReadRaster($xoff, $yoff, $xsize, $ysize, $buf_xsize = undef, $buf_ysize = undef, $buf_type = undef, \@band_list = undef)
-# Read a buffer from the raster.
-# @param xoff
-# @param yoff
-# @param xsize
-# @param ysize
-# @param buf_xsize
-# @param buf_ysize
-# @param buf_type
-# @param band_list
-# @return a buffer, open the buffer with unpack.
+
+## @method $ReadRaster(%params)
+# Read data from the dataset.
+#
+# @param params named parameters. These are
+# - \a XOff x offset (pixel coordinates) (default is 0)
+# - \a YOff y offset (pixel coordinates) (default is 0)
+# - \a XSize width of the area to read (default is the width of the dataset)
+# - \a YSize height of the area to read (default is the height of the dataset)
+# - \a BufXSize (default is undef, i.e., the same as XSize)
+# - \a BufYSize (default is undef, i.e., the same as YSize)
+# - \a BufType data type of the buffer (default is the data type of the first band)
+# - \a BandList a reference to an array of band indeces (default is [1])
+# - \a BufPixelSpace (default is 0)
+# - \a BufLineSpace (default is 0)
+# - \a BufBandSpace (default is 0)
+# - \a ResampleAlg one of Geo::GDAL::RIOResamplingTypes (default is 'NearestNeighbour'),
+# - \a Progress reference to a progress function (default is undef)
+# - \a ProgressData (default is undef)
+#
+# If the parameters are given as a list the order is as above.
+# <a href="http://www.gdal.org/classGDALDataset.html">Entry in GDAL docs (method RasterIO)</a>
+# @return a buffer, open the buffer with \a unpack function of Perl. See Geo::GDAL::Band::PackCharacter.
 
 ## @method CreateMaskBand()
+# Add a mask band to the dataset.
+
+
 
 
 ## @class Geo::GDAL::Band
+# @brief A raster band.
 # @isa ( Geo::GDAL::MajorObject Geo::GDAL )
 
-## @attr list COLOR_INTERPRETATIONS
+## @ignore COLOR_INTERPRETATIONS 
+
+## @cmethods ColorInterpretations
+# @return a list of types of color interpretation for raster
+# bands.
 
 ## @attr XSize
+# Object attribute.
 # scalar (access as $band->{XSize})
 
 ## @attr YSize
+# Object attribute.
 # scalar (access as $band->{YSize})
 
 ## @ignore GetBand
@@ -763,8 +767,10 @@
 # @return the number of this band.
 
 ## @method $DataType()
-# @return a data type string (Byte, UInt16, Int16, UInt32, Int32, Float32,
-# Float64, CInt16, CInt32, CFloat32, or CFloat64).
+# @return the data type of this band (as string, one of Geo::GDAL::DataTypes).
+
+## @method $PackCharacter()
+# @return the character to use in Perl pack and unpack for the DataType of this band.
 
 ## @method @Size()
 # @return the size of the band as a list (width, height).
@@ -783,8 +789,8 @@
 # (get only and returns an integer), SetRasterColorInterpretation and
 # SetColorInterpretation (set only and requires an integer)
 # @param color_interpretation [optional] new color interpretation, one
-# of \@Geo::GDAL::Band::COLOR_INTERPRETATIONS
-# @return color interpretation, one of \@Geo::GDAL::Band::COLOR_INTERPRETATIONS
+# of Geo::GDAL::Band::ColorInterpretations.
+# @return color interpretation, one of Geo::GDAL::Band::ColorInterpretations.
 
 ## @ignore GetNoDataValue
 ## @ignore SetNoDataValue
@@ -792,16 +798,20 @@
 ## @method $NoDataValue($NoDataValue)
 # @note a.k.a. GetNoDataValue (get only), SetNoDataValue (set only)
 # @param NoDataValue [optional]
-# Get or set the no data value.
-# @note There does not exist a good way to clear the no data
-# value. $band->NoDataValue(undef) does not do what you want.
-# @return the nodata value.
+# Get or set the "no data" value.
+# @note $band->NoDataValue(undef) sets the "no data" value to the Posix
+# floating point maximum.
+# @return the "no data" value in scalar context. In list context
+# returns the no data value or an out of range value and a boolean
+# value, which indicates which is the case (true is first, false is
+# second).
 
 ## @ignore GetUnitType
 ## @ignore SetUnitType
 
 ## @method Unit($type)
 # @param type [optional] the unit (a string).
+# @note $band->Unit(undef) sets the unit value to an empty string.
 # @return the unit (a string).
 # @since version 1.9 of the bindings.
 
@@ -816,26 +826,54 @@
 # \code
 # Units value = (raw value * scale) + offset
 # \endcode
-# @return ($scale, $offset)
+# @return a list ($scale, $offset), the values are undefined if they
+# are not set.
 # @since version 1.9 of the bindings.
 
+## @method ComputeRasterMinMax($approx_ok = 0)
+# @return arrayref MinMax = [min, max]
+
+## @method ComputeBandStats($samplestep = 1)
+# @param samplestep the row increment in computing the statistics.
+# @note Returns uncorrected sample standard deviation.
+#
+# See also Geo::GDAL::Band::ComputeStatistics.
+# @return a list (mean, stddev).
+
 ## @method $GetMinimum()
+# @note Call Geo::GDAL::Band::ComputeStatistics before calling
+# GetMinimum to make sure the value is computed.
+#
 # @return statistical minimum of the band or undef if statistics are
-# not kept or computed.
+# not kept or computed in scalar context. In list context returns the
+# minimum value or a (kind of) minimum value supported by the data
+# type and a boolean value, which indicates which is the case (true is
+# first, false is second).
 
 ## @method $GetMaximum()
+# @note Call Geo::GDAL::Band::ComputeStatistics before calling
+# GetMaximum to make sure the value is computed.
+#
 # @return statistical minimum of the band or undef if statistics are
-# not kept or computed.
+# not kept or computed in scalar context. In list context returns the
+# maximum value or a (kind of) maximum value supported by the data
+# type and a boolean value, which indicates which is the case (true is
+# first, false is second).
 
-## @method @ComputeStatistics($approx_ok)
+## @method @ComputeStatistics($approx_ok, $progress = undef, $progress_data = undef)
 # @param approx_ok Whether it is allowed to compute the statistics
 # based on overviews or similar.
+# @note Returns uncorrected sample standard deviation.
+#
+# See also Geo::GDAL::Band::ComputeBandStats.
 # @return a list ($min, $max, $mean, $stddev).
 
 ## @method @GetStatistics($approx_ok, $force)
 # @param approx_ok Whether it is allowed to compute the statistics
 # based on overviews or similar.
 # @param force Whether to force scanning of the whole raster.
+# @note Uses Geo::GDAL::Band::ComputeStatistics internally.
+#
 # @return a list ($min, $max, $mean, $stddev).
 
 ## @method SetStatistics($min, $max, $mean, $stddev)
@@ -849,9 +887,10 @@
 ## @method $GetOverviewCount()
 # @return the number of overviews available of the band.
 
-## @method Geo::GDAL::Band GetOverview($band)
-# @param band 0..GetOverviewCount-1
-# @return a new Geo::GDAL::Band object.
+## @method Geo::GDAL::Band GetOverview($index)
+# @param index 0..GetOverviewCount-1
+# @return a Geo::GDAL::Band object, which represents the internal
+# overview band, or undef.  if the index is out of bounds.
 
 ## @method HasArbitraryOverviews()
 # @return true or false.
@@ -864,23 +903,18 @@
 # @param ysize
 # @return the checksum.
 
-## @method ComputeRasterMinMax($approx_ok = 0)
-# @return arrayref MinMax = [min, max]
-
-## @method ComputeBandStats($samplestep = 1)
-# @param samplestep
-# @return arrayref Stats [mean, stddev]
-
 ## @method Fill($real_part, $imag_part = 0.0)
 # Fill the band with a constant value.
 # @param real_part Real component of fill value.
 # @param imag_part Imaginary component of fill value.
+#
 
 ## @method WriteTile($data, $xoff = 0, $yoff = 0)
 # @param data A two-dimensional Perl array, organizes as data->[y][x], y =
 # 0..height-1, x = 0..width-1.
 # @param xoff
 # @param yoff
+#
 
 ## @method \@ReadTile($xoff = 0, $yoff = 0, $xsize = <width>, $ysize = <height>)
 #
@@ -893,19 +927,19 @@
 # my($W,$H) = $dataset->Band(1)->Size();
 # my($xoff,$yoff,$w,$h) = (0,0,200,200);
 # while (1) {
-#     if ($xoff >= $W) {
-#         $xoff = 0;
-#         $yoff += $h;
-#         last if $yoff >= $H;
-#     }
-#     my $data = $dataset->Band(1)->ReadTile($xoff,$yoff,min($W-$xoff,$w),min($H-$yoff,$h));
-#     # add your data processing code here
-#     $dataset->Band(1)->WriteTile($data,$xoff,$yoff);
-#     $xoff += $w;
+# .    if ($xoff >= $W) {
+# .        $xoff = 0;
+# .        $yoff += $h;
+# .        last if $yoff >= $H;
+# .    }
+# .    my $data = $dataset->Band(1)->ReadTile($xoff,$yoff,min($W-$xoff,$w),min($H-$yoff,$h));
+# .    # add your data processing code here
+# .    $dataset->Band(1)->WriteTile($data,$xoff,$yoff);
+# .    $xoff += $w;
 # }
 #
 # sub min {
-#     return $_[0] < $_[1] ? $_[0] : $_[1];
+# .    return $_[0] < $_[1] ? $_[0] : $_[1];
 # }
 # \endcode
 # @param xoff
@@ -915,27 +949,44 @@
 # @return a two-dimensional Perl array, organizes as data->[y][x], y =
 # 0..height-1, x = 0..width-1.
 
-## @method WriteRaster($xoff, $yoff, $xsize, $ysize, $buf, $buf_xsize = undef, $buf_ysize = undef, $buf_type = undef)
-# @param xoff
-# @param yoff
-# @param xsize
-# @param ysize
-# @param buf The data to be written in a binary buffer. Use the \a
-# pack function of Perl to prepare a buffer.
-# @param buf_xsize
-# @param buf_ysize
-# @param buf_type
+## @method WriteRaster(%params)
+# Write data into the band.
+#
+# @param params named parameters. These are
+# - \a XOff x offset (pixel coordinates) (default is 0)
+# - \a YOff y offset (pixel coordinates) (default is 0)
+# - \a XSize width of the area to write (default is the width of the band)
+# - \a YSize height of the area to write (default is the height of the band)
+# - \a Buf a buffer containing the data. Create the buffer with \a pack function of Perl. See Geo::GDAL::Band::PackCharacter.
+# - \a BufXSize (default is undef, i.e., the same as XSize)
+# - \a BufYSize (default is undef, i.e., the same as YSize)
+# - \a BufType data type of the buffer (default is the data type of the band)
+# - \a BufPixelSpace (default is 0)
+# - \a BufLineSpace (default is 0)
+#
+# If the parameters are given as a list the order is as above.
+# <a href="http://www.gdal.org/classGDALDataset.html">Entry in GDAL docs (method RasterIO)</a>
 
-## @method $ReadRaster($xoff, $yoff, $xsize, $ysize, $buf_xsize = undef, $buf_ysize = undef, $buf_type = undef)
-# @param xoff
-# @param yoff
-# @param xsize
-# @param ysize
-# @param buf_xsize
-# @param buf_ysize
-# @param buf_type
-# @return the data in a binary buffer. Use the \a unpack function of
-# Perl to get the data from the buffer.
+## @method $ReadRaster(%params)
+# Read data from the band.
+#
+# @param params named parameters. These are
+# - \a XOff x offset (pixel coordinates) (default is 0)
+# - \a YOff y offset (pixel coordinates) (default is 0)
+# - \a XSize width of the area to read (default is the width of the band)
+# - \a YSize height of the area to read (default is the height of the band)
+# - \a BufXSize (default is undef, i.e., the same as XSize)
+# - \a BufYSize (default is undef, i.e., the same as YSize)
+# - \a BufType data type of the buffer (default is the data type of the band)
+# - \a BufPixelSpace (default is 0)
+# - \a BufLineSpace (default is 0)
+# - \a ResampleAlg one of Geo::GDAL::RIOResamplingTypes (default is 'NearestNeighbour'),
+# - \a Progress reference to a progress function (default is undef)
+# - \a ProgressData (default is undef)
+#
+# If the parameters are given as a list the order is as above.
+# <a href="http://www.gdal.org/classGDALDataset.html">Entry in GDAL docs (method RasterIO)</a>
+# @return a buffer, open the buffer with \a unpack function of Perl. See Geo::GDAL::Band::PackCharacter.
 
 ## @method @GetHistogram(%parameters)
 # Compute histogram from the raster.
@@ -952,17 +1003,18 @@
 # - \a ProgressData data for the progress function, the default is undef
 # @return a list which contains the count of values in each bucket
 
-## @method @GetDefaultHistogram($force = 1, $callback = undef, $callback_data = undef)
+## @method @GetDefaultHistogram($force = 1, subref progress = undef, $progress_data = undef)
 # @param force true to force the computation
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 # @return a list: ($min, $max, arrayref histogram).
 
 ## @method @SetDefaultHistogram($min, $max, $histogram)
 # @param min
 # @param max
 # @param histogram reference to an array containing the histogram
+#
 
 ## @method FlushCache()
 # Write cached data to disk. There is usually no need to call this
@@ -974,56 +1026,60 @@
 # @return a new Geo::GDAL::ColorTable object in a non-void context.
 
 ## @ignore GetRasterColorTable
+## @ignore SetRasterColorTable
 
 ## @method Geo::GDAL::ColorTable GetColorTable()
 # @note a.k.a. GetRasterColorTable, see also ColorTable
 # @return a color table object.
 
-## @ignore SetRasterColorTable
-
 ## @method SetColorTable($ColorTable)
 # @note a.k.a. SetRasterColorTable, see also ColorTable
 # @param ColorTable A color table object.
+#
 
-## @method CreateMaskBand()
+## @cmethod @MaskFlags
+# @return the list of mask flags. These are
+# - \a AllValid: There are no invalid pixels, all mask values will be 255.
+# When used this will normally be the only flag set.
+# - \a PerDataset: The mask band is shared between all bands on the dataset.
+# - \a Alpha: The mask band is actually an alpha band and may have values
+# other than 0 and 255.
+# - \a NoData: Indicates the mask is actually being generated from nodata values.
+# (mutually exclusive of Alpha).
+
+## @method CreateMaskBand(@flags)
+# @note May invalidate any previous mask band obtained with Geo::GDAL::Band::GetMaskBand.
+#
+# @param flags one or more mask flags. The flags are Geo::GDAL::Band::MaskFlags.
 
 ## @method Geo::GDAL::Band GetMaskBand()
+# @return the mask band associated with this
+# band.
 
-## @method $GetMaskFlags()
+## @method @GetMaskFlags()
+# @return th mask flags of the mask band associated with this
+# band. The flags are Geo::GDAL::Band::MaskFlags.
+
+## @ignore GetRasterCategoryNames
+## @ignore SetRasterCategoryNames
+## @ignore GetCategoryNames
+## @ignore SetCategoryNames
 
 ## @method @CategoryNames(@names)
 # @param names [optional]
 # @return
 
-## @ignore GetCategoryNames
-
-## @method $GetRasterCategoryNames()
-# @note a.k.a. GetCategoryNames, see also CategoryNames
-# @return names
-
-## @ignore SetCategoryNames
-
-## @method SetRasterCategoryNames($names)
-# @note a.k.a. SetCategoryNames, see also CategoryNames
-# @param names
+## @ignore SetDefaultRAT
+## @ignore GetDefaultRAT
 
 ## @method Geo::GDAL::RasterAttributeTable AttributeTable($AttributeTable)
 # @param AttributeTable [optional] A Geo::GDAL::RasterAttributeTable object.
 # @return a new Geo::GDAL::RasterAttributeTable object, whose data is
 # contained within the band.
 
-## @method Geo::GDAL::RasterAttributeTable GetDefaultRAT()
-# @deprecated use Geo::GDAL::Band::AttributeTable, which makes sure
-# the band is not destroyed before the attribute table.
-# @return a new Geo::GDAL::RasterAttributeTable object, whose data is
-# contained within the band.
-
-## @method SetDefaultRAT($AttributeTable)
-# @param AttributeTable a Geo::GDAL::RasterAttributeTable object
-
 ## @ignore ContourGenerate
 
-## @method Geo::OGR::Layer Contours($DataSource, \%LayerConstructor, $ContourInterval, $ContourBase, \@FixedLevels, $NoDataValue, $IDField, $ElevField, $callback, $callback_data)
+## @method Geo::OGR::Layer Contours($DataSource, hashref LayerConstructor, $ContourInterval, $ContourBase, arrayref FixedLevels, $NoDataValue, $IDField, $ElevField, subref Progress, $ProgressData)
 # Generate contours for this raster band. This method can also be used with named parameters.
 # @note This method is a wrapper for ContourGenerate.
 #
@@ -1043,33 +1099,51 @@
 # @param NoDataValue default is undef
 # @param IDField default is '', i.e., no field (the field is created if this is given)
 # @param ElevField default is '', i.e., no field (the field is created if this is given)
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
 # @return
 
-## @method FillNodata($mask, $max_search_dist = 10, $smoothing_iterations = 0, $options = {}, $callback, $callback_data)
+## @method FillNodata($mask, $max_search_dist, $smoothing_iterations, $options, subref progress, $progress_data)
+# Interpolate values for pixels in this raster. The pixels to fill
+# should be marked in the mask band with zero.
 # @note This is a wrapper for Geo::GDAL::FillNodata.
-# @param mask a mask band indicating pixels to be interpolated (zero valued)
+#
+# @param mask [optional] a mask band indicating pixels to be interpolated (zero valued) (default is to get it with Geo::GDAL::Band::GetMaskBand).
 # @param max_search_dist [optional] the maximum number of pixels to
-# search in all directions to find values to interpolate from.
-# @param smoothing_iterations [optional] the number of 3x3 smoothing filter passes to run (0 or more).
-# @param options [optional] A reference to a hash. No options have been defined so far for this algorithm.
-# @param callback [optional] a reference to a subroutine, which will
-# be called with parameters (number progress, string msg, callback_data)
-# @param callback_data [optional]
+# search in all directions to find values to interpolate from (default is 10).
+# @param smoothing_iterations [optional] the number of 3x3 smoothing filter passes to run (0 or more) (default is 0).
+# @param options [optional] A reference to a hash. No options have been defined so far for this algorithm (default is {}).
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data) (default is undef).
+# @param progress_data [optional] (default is undef).
 #
 # <a href="http://www.gdal.org/gdal__alg_8h.html">Documentation for GDAL algorithms</a>
 
+## @method RegenerateOverviews(arrayref overviews, $resampling, subref progress, $progress_data)
+# @todo This is not yet available
+#
+# @param overviews a list of Geo::GDAL::Band objects for the overviews.
+# @param resampling [optional] the resampling method (one of Geo::GDAL::RIOResamplingTypes) (default is Average).
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
+
+## @method RegenerateOverview(Geo::GDAL::Band overview, $resampling, subref progress, $progress_data)
+# @param overview a Geo::GDAL::Band object for the overview.
+# @param resampling [optional] the resampling method (one of Geo::GDAL::RIOResamplingTypes) (default is Average).
+# @param progress [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, progress_data)
+# @param progress_data [optional]
+
+
+
 
 ## @class Geo::GDAL::ColorTable
+# @brief A color table in a raster band.
 # @isa ( Geo::GDAL::MajorObject Geo::GDAL )
 
-## @cmethod Geo::GDAL::ColorTable new($GDALPaletteInterp = $Geo::GDAL::Const::GPI_RGB)
-# @deprecated use Geo::GDAL::ColorTable::create, which uses string constants
-# @return a new Geo::GDAL::ColorTable object
-
-## @cmethod Geo::GDAL::ColorTable create($GDALPaletteInterp = 'RGB')
+## @cmethod Geo::GDAL::ColorTable new($GDALPaletteInterp = 'RGB')
 #
 # Usage:
 # \code
@@ -1094,6 +1168,7 @@
 ## @method @ColorEntries(@color_entries)
 # Get or set the table of color entries.
 # @deprecated use Geo::GDAL::ColorTable::ColorTable
+#
 # @param color_entries [optional]
 # @return a table of color entries (a list of lists) in a non void context
 
@@ -1114,15 +1189,20 @@
 ## @method SetColorEntry($index, @ColorEntry)
 # @param index
 # @param ColorEntry a list or a reference to an array
+#
 
-## @method CreateColorRamp($start_index, \@start_color, $end_index, \@end_color)
+## @method CreateColorRamp($start_index, arrayref start_color, $end_index, arrayref end_color)
 # @param start_index
 # @param start_color
 # @param end_index
 # @param end_color
+#
+
+
 
 
 ## @class Geo::GDAL::RasterAttributeTable
+# @brief An attribute table in a raster band.
 # @isa = ( Geo::GDAL::MajorObject Geo::GDAL )
 
 ## @cmethod Geo::GDAL::RasterAttributeTable new()
@@ -1139,6 +1219,7 @@
 
 ## @method SetRowCount($count)
 # @param count
+#
 
 ## @method $GetRowCount()
 
@@ -1201,16 +1282,19 @@
 # @param row
 # @param column
 # @param value
+#
 
 ## @method SetValueAsInt($row, $column, $value)
 # @param row
 # @param column
 # @param value
+#
 
 ## @method SetValueAsDouble($row, $column, $value)
 # @param row
 # @param column
 # @param value
+#
 
 ## @ignore GetLinearBinning
 ## @ignore SetLinearBinning
@@ -1221,5 +1305,107 @@
 # @return ($Row0MinIn, $BinSizeIn) or an empty list if LinearBinning is not set.
 
 
+
+
 ## @class Geo::GDAL::Transformer
+# @brief
+#
 # This class is not yet documented for the GDAL Perl bindings.
+# @todo Test and document.
+
+
+
+
+## @class Geo::GDAL::VSIF
+# @brief A GDAL virtual file system.
+# @isa = ( Geo::GDAL )
+
+## @cmethod Geo::GDAL::VSIF Open($filename, $mode)
+# @param filename Name of the file to open. For example "/vsimem/x".
+# @param mode Access mode. 'r', 'r+', 'w', etc.
+# @return A file handle on success.
+
+## @method Close()
+
+## @method $Read($count)
+# @param count The number of bytes to read from the file.
+# @return A byte string.
+
+## @method Write($scalar)
+# @param scalar The byte string to write to the file.
+# @return Number of bytes written into the file.
+
+## @method Seek($offset, $whence)
+
+## @method $Tell()
+
+## @method Truncate($new_size)
+
+## @cmethod @ReadDir($dir)
+# @return Contents of a directory in an anonymous array or as a list.
+
+## @cmethod $ReadDirRecursive($dir)
+# @return Contents of a directory tree in an anonymous array.
+
+## @cmethod @Stat($filename)
+# @return ($filemode, $filesize). filemode is f for a plain file, d
+# for a directory, l for a symbolic link, p for a named pipe (FIFO), S
+# for a socket, b for a block special file, and c for a character
+# special file.
+
+## @cmethod Unlink($filename)
+# @param filename The file to delete.
+# @return 0 on success and -1 on an error.
+
+## @ignore Mkdir
+
+## @cmethod Mkdir($path, $mode)
+# Make a directory.
+# @note The name of this method is VSIMkdir in GDAL.
+#
+
+## @cmethod Rmdir($path)
+# Remove a directory.
+# @note The name of this method is VSIRmdir in GDAL.
+#
+
+## @cmethod Rename($old, $new)
+# Rename a file.
+# @note The name of this method is VSIRename in GDAL.
+#
+
+
+
+
+## @class Geo::GDAL::GeoTransform
+# @brief An array of affine transformation coefficients.
+#
+# The geo transformation has the form
+# \code
+# x = a + column * b + row * c
+# y = d + column * e + row * f
+# \endcode
+# where<br/>
+# (column,row) is the location in pixel coordinates<br/>
+# (x,y) is the location in projection coordinates<br/>
+# or vice versa.
+# A Geo::GDAL::GeoTransform object is a reference to an anonymous array.
+# @isa = ( Geo::GDAL )
+
+## @cmethod new(@coeffs)
+# @return a new Geo::GDAL::GeoTransform object.
+
+## @method FromGCPs(@GCPs, $ApproxOK)
+# Compute transformation coefficients from a list of Geo::GDAL::GCP
+# objects
+# @param GCPs A list of Geo::GDAL::GCP objects.
+# @param ApproxOK [optional] Minimize the error in the coefficient (integer, default is true).
+# @return a new Geo::GDAL::GeoTransform object.
+
+## @method Apply(array reference x, array reference y)
+# @return a list (x, y), where x and y are references to arrays of
+# transformed coordinates.
+
+## @method Inv
+# @return a new Geo::GDAL::GeoTransform object, which is the inverse
+# of this one (in void context changes this object).
diff --git a/swig/perl/lib/Geo/GDAL.pm b/swig/perl/lib/Geo/GDAL.pm
index 8814901..d47f6c9 100644
--- a/swig/perl/lib/Geo/GDAL.pm
+++ b/swig/perl/lib/Geo/GDAL.pm
@@ -105,21 +105,8 @@ package Geo::GDAL;
 *GDAL_GCP_Info_set = *Geo::GDALc::GDAL_GCP_Info_set;
 *GDAL_GCP_Id_get = *Geo::GDALc::GDAL_GCP_Id_get;
 *GDAL_GCP_Id_set = *Geo::GDALc::GDAL_GCP_Id_set;
-*GDAL_GCP_get_GCPX = *Geo::GDALc::GDAL_GCP_get_GCPX;
-*GDAL_GCP_set_GCPX = *Geo::GDALc::GDAL_GCP_set_GCPX;
-*GDAL_GCP_get_GCPY = *Geo::GDALc::GDAL_GCP_get_GCPY;
-*GDAL_GCP_set_GCPY = *Geo::GDALc::GDAL_GCP_set_GCPY;
-*GDAL_GCP_get_GCPZ = *Geo::GDALc::GDAL_GCP_get_GCPZ;
-*GDAL_GCP_set_GCPZ = *Geo::GDALc::GDAL_GCP_set_GCPZ;
-*GDAL_GCP_get_GCPPixel = *Geo::GDALc::GDAL_GCP_get_GCPPixel;
-*GDAL_GCP_set_GCPPixel = *Geo::GDALc::GDAL_GCP_set_GCPPixel;
-*GDAL_GCP_get_GCPLine = *Geo::GDALc::GDAL_GCP_get_GCPLine;
-*GDAL_GCP_set_GCPLine = *Geo::GDALc::GDAL_GCP_set_GCPLine;
-*GDAL_GCP_get_Info = *Geo::GDALc::GDAL_GCP_get_Info;
-*GDAL_GCP_set_Info = *Geo::GDALc::GDAL_GCP_set_Info;
-*GDAL_GCP_get_Id = *Geo::GDALc::GDAL_GCP_get_Id;
-*GDAL_GCP_set_Id = *Geo::GDALc::GDAL_GCP_set_Id;
 *GCPsToGeoTransform = *Geo::GDALc::GCPsToGeoTransform;
+*TermProgress_nocb = *Geo::GDALc::TermProgress_nocb;
 *_ComputeMedianCutPCT = *Geo::GDALc::_ComputeMedianCutPCT;
 *_DitherRGB2PCT = *Geo::GDALc::_DitherRGB2PCT;
 *_ReprojectImage = *Geo::GDALc::_ReprojectImage;
@@ -128,6 +115,7 @@ package Geo::GDAL;
 *_Polygonize = *Geo::GDALc::_Polygonize;
 *FillNodata = *Geo::GDALc::FillNodata;
 *_SieveFilter = *Geo::GDALc::_SieveFilter;
+*_RegenerateOverviews = *Geo::GDALc::_RegenerateOverviews;
 *_RegenerateOverview = *Geo::GDALc::_RegenerateOverview;
 *ContourGenerate = *Geo::GDALc::ContourGenerate;
 *_AutoCreateWarpedVRT = *Geo::GDALc::_AutoCreateWarpedVRT;
@@ -139,8 +127,8 @@ package Geo::GDAL;
 *GetCacheMax = *Geo::GDALc::GetCacheMax;
 *GetCacheUsed = *Geo::GDALc::GetCacheUsed;
 *SetCacheMax = *Geo::GDALc::SetCacheMax;
-*GetDataTypeSize = *Geo::GDALc::GetDataTypeSize;
-*DataTypeIsComplex = *Geo::GDALc::DataTypeIsComplex;
+*_GetDataTypeSize = *Geo::GDALc::_GetDataTypeSize;
+*_DataTypeIsComplex = *Geo::GDALc::_DataTypeIsComplex;
 *GetDataTypeName = *Geo::GDALc::GetDataTypeName;
 *GetDataTypeByName = *Geo::GDALc::GetDataTypeByName;
 *GetColorInterpretationName = *Geo::GDALc::GetColorInterpretationName;
@@ -150,12 +138,15 @@ package Geo::GDAL;
 *DecToPackedDMS = *Geo::GDALc::DecToPackedDMS;
 *ParseXMLString = *Geo::GDALc::ParseXMLString;
 *SerializeXMLTree = *Geo::GDALc::SerializeXMLTree;
+*GetJPEG2000StructureAsString = *Geo::GDALc::GetJPEG2000StructureAsString;
 *GetDriverCount = *Geo::GDALc::GetDriverCount;
 *GetDriverByName = *Geo::GDALc::GetDriverByName;
 *_GetDriver = *Geo::GDALc::_GetDriver;
 *_Open = *Geo::GDALc::_Open;
+*OpenEx = *Geo::GDALc::OpenEx;
 *_OpenShared = *Geo::GDALc::_OpenShared;
 *IdentifyDriver = *Geo::GDALc::IdentifyDriver;
+*GeneralCmdLineProcessor = *Geo::GDALc::GeneralCmdLineProcessor;
 
 ############# Class : Geo::GDAL::MajorObject ##############
 
@@ -223,16 +214,16 @@ use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 @ISA = qw( Geo::GDAL );
 %OWNER = ();
 %ITERATORS = ();
-*swig_GCPX_get = *Geo::GDALc::GCP_GCPX_get;
-*swig_GCPX_set = *Geo::GDALc::GCP_GCPX_set;
-*swig_GCPY_get = *Geo::GDALc::GCP_GCPY_get;
-*swig_GCPY_set = *Geo::GDALc::GCP_GCPY_set;
-*swig_GCPZ_get = *Geo::GDALc::GCP_GCPZ_get;
-*swig_GCPZ_set = *Geo::GDALc::GCP_GCPZ_set;
-*swig_GCPPixel_get = *Geo::GDALc::GCP_GCPPixel_get;
-*swig_GCPPixel_set = *Geo::GDALc::GCP_GCPPixel_set;
-*swig_GCPLine_get = *Geo::GDALc::GCP_GCPLine_get;
-*swig_GCPLine_set = *Geo::GDALc::GCP_GCPLine_set;
+*swig_X_get = *Geo::GDALc::GCP_X_get;
+*swig_X_set = *Geo::GDALc::GCP_X_set;
+*swig_Y_get = *Geo::GDALc::GCP_Y_get;
+*swig_Y_set = *Geo::GDALc::GCP_Y_set;
+*swig_Z_get = *Geo::GDALc::GCP_Z_get;
+*swig_Z_set = *Geo::GDALc::GCP_Z_set;
+*swig_Column_get = *Geo::GDALc::GCP_Column_get;
+*swig_Column_set = *Geo::GDALc::GCP_Column_set;
+*swig_Row_get = *Geo::GDALc::GCP_Row_get;
+*swig_Row_set = *Geo::GDALc::GCP_Row_set;
 *swig_Info_get = *Geo::GDALc::GCP_Info_get;
 *swig_Info_set = *Geo::GDALc::GCP_Info_set;
 *swig_Id_get = *Geo::GDALc::GCP_Id_get;
@@ -344,17 +335,20 @@ sub DESTROY {
 *SetProjection = *Geo::GDALc::Dataset_SetProjection;
 *GetGeoTransform = *Geo::GDALc::Dataset_GetGeoTransform;
 *SetGeoTransform = *Geo::GDALc::Dataset_SetGeoTransform;
-*BuildOverviews = *Geo::GDALc::Dataset_BuildOverviews;
+*_BuildOverviews = *Geo::GDALc::Dataset__BuildOverviews;
 *GetGCPCount = *Geo::GDALc::Dataset_GetGCPCount;
 *GetGCPProjection = *Geo::GDALc::Dataset_GetGCPProjection;
 *GetGCPs = *Geo::GDALc::Dataset_GetGCPs;
 *SetGCPs = *Geo::GDALc::Dataset_SetGCPs;
 *FlushCache = *Geo::GDALc::Dataset_FlushCache;
 *_AddBand = *Geo::GDALc::Dataset__AddBand;
-*CreateMaskBand = *Geo::GDALc::Dataset_CreateMaskBand;
+*_CreateMaskBand = *Geo::GDALc::Dataset__CreateMaskBand;
 *GetFileList = *Geo::GDALc::Dataset_GetFileList;
-*WriteRaster = *Geo::GDALc::Dataset_WriteRaster;
-*ReadRaster = *Geo::GDALc::Dataset_ReadRaster;
+*_WriteRaster = *Geo::GDALc::Dataset__WriteRaster;
+*_ReadRaster = *Geo::GDALc::Dataset__ReadRaster;
+*StartTransaction = *Geo::GDALc::Dataset_StartTransaction;
+*CommitTransaction = *Geo::GDALc::Dataset_CommitTransaction;
+*RollbackTransaction = *Geo::GDALc::Dataset_RollbackTransaction;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -381,6 +375,7 @@ use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 *swig_YSize_set = *Geo::GDALc::Band_YSize_set;
 *swig_DataType_get = *Geo::GDALc::Band_DataType_get;
 *swig_DataType_set = *Geo::GDALc::Band_DataType_set;
+*GetDataset = *Geo::GDALc::Band_GetDataset;
 *GetBand = *Geo::GDALc::Band_GetBand;
 *GetBlockSize = *Geo::GDALc::Band_GetBlockSize;
 *GetColorInterpretation = *Geo::GDALc::Band_GetColorInterpretation;
@@ -408,8 +403,8 @@ use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 *ComputeRasterMinMax = *Geo::GDALc::Band_ComputeRasterMinMax;
 *ComputeBandStats = *Geo::GDALc::Band_ComputeBandStats;
 *Fill = *Geo::GDALc::Band_Fill;
-*ReadRaster = *Geo::GDALc::Band_ReadRaster;
-*WriteRaster = *Geo::GDALc::Band_WriteRaster;
+*_ReadRaster = *Geo::GDALc::Band__ReadRaster;
+*_WriteRaster = *Geo::GDALc::Band__WriteRaster;
 *FlushCache = *Geo::GDALc::Band_FlushCache;
 *GetRasterColorTable = *Geo::GDALc::Band_GetRasterColorTable;
 *GetColorTable = *Geo::GDALc::Band_GetColorTable;
@@ -418,8 +413,8 @@ use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 *GetDefaultRAT = *Geo::GDALc::Band_GetDefaultRAT;
 *SetDefaultRAT = *Geo::GDALc::Band_SetDefaultRAT;
 *GetMaskBand = *Geo::GDALc::Band_GetMaskBand;
-*GetMaskFlags = *Geo::GDALc::Band_GetMaskFlags;
-*CreateMaskBand = *Geo::GDALc::Band_CreateMaskBand;
+*_GetMaskFlags = *Geo::GDALc::Band__GetMaskFlags;
+*_CreateMaskBand = *Geo::GDALc::Band__CreateMaskBand;
 *_GetHistogram = *Geo::GDALc::Band__GetHistogram;
 *GetDefaultHistogram = *Geo::GDALc::Band_GetDefaultHistogram;
 *SetDefaultHistogram = *Geo::GDALc::Band_SetDefaultHistogram;
@@ -446,9 +441,11 @@ package Geo::GDAL::ColorTable;
 use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 @ISA = qw( Geo::GDAL );
 %OWNER = ();
+use Carp;
 sub new {
-    my $pkg = shift;
-    my $self = Geo::GDALc::new_ColorTable(@_);
+    my($pkg, $pi) = @_;
+    $pi = $PALETTE_INTERPRETATION_STRING2INT{$pi} if defined $pi and exists $PALETTE_INTERPRETATION_STRING2INT{$pi};
+    my $self = Geo::GDALc::new_ColorTable($pi);
     bless $self, $pkg if defined($self);
 }
 
@@ -537,6 +534,7 @@ sub DESTROY {
 *SetLinearBinning = *Geo::GDALc::RasterAttributeTable_SetLinearBinning;
 *GetRowOfValue = *Geo::GDALc::RasterAttributeTable_GetRowOfValue;
 *ChangesAreWrittenToFile = *Geo::GDALc::RasterAttributeTable_ChangesAreWrittenToFile;
+*DumpReadable = *Geo::GDALc::RasterAttributeTable_DumpReadable;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -594,666 +592,1381 @@ sub ACQUIRE {
 
 package Geo::GDAL;
 
+*TermProgress = *Geo::GDALc::TermProgress;
+
+
+package Geo::GDAL;
+use strict;
+use warnings;
+use Carp;
+use Encode;
+use Geo::GDAL::Const;
+use Geo::OGR;
+use Geo::OSR;
+# $VERSION is the Perl module (CPAN) version number, which must be
+# an increasing floating point number.  $GDAL_VERSION is the
+# version number of the GDAL that this module is a part of. It is
+# used in build time to check the version of GDAL against which we
+# build.
+# For GDAL 2.0 or above, GDAL X.Y.Z should then
+# VERSION = X + Y / 100.0 + Z / 10000.0
+
+our $VERSION = '2.0000';
+our $GDAL_VERSION = '2.0.0';
+use vars qw/
+    @DATA_TYPES @ACCESS_TYPES @RESAMPLING_TYPES @RIO_RESAMPLING_TYPES @NODE_TYPES
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    %ACCESS_STRING2INT %ACCESS_INT2STRING
+    %RESAMPLING_STRING2INT %RESAMPLING_INT2STRING
+    %RIO_RESAMPLING_STRING2INT %RIO_RESAMPLING_INT2STRING
+    %NODE_TYPE_STRING2INT %NODE_TYPE_INT2STRING
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@DATA_TYPES, $1), next if /^GDT_(\w+)/;
+    push(@ACCESS_TYPES, $1), next if /^GA_(\w+)/;
+    push(@RESAMPLING_TYPES, $1), next if /^GRA_(\w+)/;
+    push(@RIO_RESAMPLING_TYPES, $1), next if /^GRIORA_(\w+)/;
+    push(@NODE_TYPES, $1), next if /^CXT_(\w+)/;
+}
+for my $string (@DATA_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GDT_$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@ACCESS_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GA_$string";
+    $ACCESS_STRING2INT{$string} = $int;
+    $ACCESS_INT2STRING{$int} = $string;
+}
+for my $string (@RESAMPLING_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GRA_$string";
+    $RESAMPLING_STRING2INT{$string} = $int;
+    $RESAMPLING_INT2STRING{$int} = $string;
+}
+for my $string (@RIO_RESAMPLING_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::GRIORA_$string";
+    $RIO_RESAMPLING_STRING2INT{$string} = $int;
+    $RIO_RESAMPLING_INT2STRING{$int} = $string;
+}
+for my $string (@NODE_TYPES) {
+    my $int = eval "\$Geo::GDAL::Const::CXT_$string";
+    $NODE_TYPE_STRING2INT{$string} = $int;
+    $NODE_TYPE_INT2STRING{$int} = $string;
+}
+
+sub RELEASE_PARENTS {
+}
+
+sub DataTypes {
+    return @DATA_TYPES;
+}
+
+sub AccessTypes {
+    return @ACCESS_TYPES;
+}
+
+sub ResamplingTypes {
+    return @RESAMPLING_TYPES;
+}
+
+sub RIOResamplingTypes {
+    return @RIO_RESAMPLING_TYPES;
+}
+
+sub NodeTypes {
+    return @NODE_TYPES;
+}
+
+sub NodeType {
+    my $type = shift;
+    return $NODE_TYPE_INT2STRING{$type} if $type =~ /^\d/;
+    return $NODE_TYPE_STRING2INT{$type};
+}
+
+sub NodeData {
+    my $node = shift;
+    return (Geo::GDAL::NodeType($node->[0]), $node->[1]);
+}
+
+sub Children {
+    my $node = shift;
+    return @$node[2..$#$node];
+}
+
+sub Child {
+    my($node, $child) = @_;
+    return $node->[2+$child];
+}
+
+sub GetDataTypeSize {
+    my $t = shift;
+    my $t2 = $t;
+    $t2 = $TYPE_STRING2INT{$t} if exists $TYPE_STRING2INT{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_INT2STRING{$t2};
+    return _GetDataTypeSize($t2);
+}
+
+sub DataTypeValueRange {
+    my $t = shift;
+    confess "Unknown data type: '$t'." unless exists $TYPE_STRING2INT{$t};
+    # these values are from gdalrasterband.cpp
+    return (0,255) if $t =~ /Byte/;
+    return (0,65535) if $t =~/UInt16/;
+    return (-32768,32767) if $t =~/Int16/;
+    return (0,4294967295) if $t =~/UInt32/;
+    return (-2147483648,2147483647) if $t =~/Int32/;
+    return (-4294967295.0,4294967295.0) if $t =~/Float32/;
+    return (-4294967295.0,4294967295.0) if $t =~/Float64/;
+}
+
+sub DataTypeIsComplex {
+    my $t = shift;
+    my $t2 = $t;
+    $t2 = $TYPE_STRING2INT{$t} if exists $TYPE_STRING2INT{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_INT2STRING{$t2};
+    return _DataTypeIsComplex($t2);
+}
+
+sub PackCharacter {
+    my $t = shift;
+    $t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
+    confess "Unknown data type: '$t'." unless exists $TYPE_STRING2INT{$t};
+    my $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; # from Programming Perl
+    return 'C' if $t =~ /^Byte$/;
+    return ($is_big_endian ? 'n': 'v') if $t =~ /^UInt16$/;
+    return 's' if $t =~ /^Int16$/;
+    return ($is_big_endian ? 'N' : 'V') if $t =~ /^UInt32$/;
+    return 'l' if $t =~ /^Int32$/;
+    return 'f' if $t =~ /^Float32$/;
+    return 'd' if $t =~ /^Float64$/;
+}
+
+sub GetDriverNames {
+    my @names;
+    for my $i (0..GetDriverCount()-1) {
+        my $driver = _GetDriver($i);
+        my $md = $driver->GetMetadata;
+        next unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        push @names, _GetDriver($i)->Name;
+    }
+    return @names;
+}
+
+sub Drivers {
+    my @drivers;
+    for my $i (0..GetDriverCount()-1) {
+        my $driver = _GetDriver($i);
+        my $md = $driver->GetMetadata;
+        next unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        push @drivers, _GetDriver($i);
+    }
+    return @drivers;
+}
+
+sub GetDriver {
+    my($name) = @_;
+    $name = 0 unless defined $name;
+    my $driver;
+    $driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
+    $driver = GetDriverByName("$name") unless $driver;
+    if ($driver) {
+        my $md = $driver->GetMetadata;
+        confess "Driver exists but does not have raster capabilities." 
+            unless $md->{DCAP_RASTER} and $md->{DCAP_RASTER} eq 'YES';
+        return $driver;
+    }
+    confess "Driver not found: '$name'. Maybe support for it was not built in?";
+}
+*Driver = *GetDriver;
+
+sub Open {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown access type: '$p[1]'." unless exists $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+    }
+    return _Open(@p);
+}
+
+sub OpenShared {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown access type: '$p[1]'." unless exists $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::ACCESS_STRING2INT{$p[1]};
+    }
+    return _OpenShared(@p);
+}
+
+sub ComputeMedianCutPCT {
+    my @p = @_;
+    $p[6] = 1 if $p[5] and not defined $p[6];
+    _ComputeMedianCutPCT(@p);
+}
+
+sub DitherRGB2PCT {
+    my @p = @_;
+    $p[6] = 1 if $p[5] and not defined $p[6];
+    _DitherRGB2PCT(@p);
+}
+
+sub ComputeProximity {
+    my @p = @_;
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _ComputeProximity(@p);
+}
+
+sub RasterizeLayer {
+    my @p = @_;
+    $p[8] = 1 if $p[7] and not defined $p[8];
+    _RasterizeLayer(@p);
+}
+
+sub Polygonize {
+    my @params = @_;
+    $params[6] = 1 if $params[5] and not defined $params[6];
+    $params[3] = $params[2]->GetLayerDefn->GetFieldIndex($params[3]) unless $params[3] =~ /^\d/;
+    _Polygonize(@params);
+}
+
+sub SieveFilter {
+    my @p = @_;
+    $p[7] = 1 if $p[6] and not defined $p[7];
+    _SieveFilter(@p);
+}
+
+sub RegenerateOverviews {
+    my @p = @_;
+    $p[2] = uc($p[2]) if $p[2]; # see overview.cpp:2030
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _RegenerateOverviews(@p);
+}
+
+sub RegenerateOverview {
+    my @p = @_;
+    $p[2] = uc($p[2]) if $p[2]; # see overview.cpp:2030
+    $p[4] = 1 if $p[3] and not defined $p[4];
+    _RegenerateOverview(@p);
+}
+
+sub ReprojectImage {
+    my @p = @_;
+    $p[8] = 1 if $p[7] and not defined $p[8];
+    if (defined $p[4]) {
+        confess "Unknown data type: '$p[4]'." unless exists $Geo::GDAL::RESAMPLING_STRING2INT{$p[4]};
+        $p[4] = $Geo::GDAL::RESAMPLING_STRING2INT{$p[4]};
+    }
+    return _ReprojectImage(@p);
+}
+
+sub AutoCreateWarpedVRT {
+    my @p = @_;
+    for my $i (1..2) {
+        if (defined $p[$i] and ref($p[$i])) {
+            $p[$i] = $p[$i]->ExportToWkt;
+        }
+    }
+    if (defined $p[3]) {
+        confess "Unknown data type: '$p[3]'." unless exists $Geo::GDAL::RESAMPLING_STRING2INT{$p[3]};
+        $p[3] = $Geo::GDAL::RESAMPLING_STRING2INT{$p[3]};
+    }
+    return _AutoCreateWarpedVRT(@p);
+}
+
+
+
+
+package Geo::GDAL::MajorObject;
+use strict;
+use warnings;
+use vars qw/@DOMAINS/;
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub Description {
+    my($self, $desc) = @_;
+    SetDescription($self, $desc) if defined $desc;
+    GetDescription($self) if defined wantarray;
+}
+
+sub Metadata {
+    my $self = shift;
+    my $metadata;
+    $metadata = shift if ref $_[0];
+    my $domain = shift;
+    $domain = '' unless defined $domain;
+    SetMetadata($self, $metadata, $domain) if defined $metadata;
+    GetMetadata($self, $domain) if defined wantarray;
+}
+
+
+package Geo::GDAL::Driver;
+use strict;
+use warnings;
+use Carp;
+use vars qw/@CAPABILITIES @DOMAINS/;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@CAPABILITIES, $1), next if /^DCAP_(\w+)/;
+}
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub Name {
+    my $self = shift;
+    return $self->{ShortName};
+}
+
+sub Capabilities {
+    my $self = shift;
+    return @CAPABILITIES unless $self;
+    my $h = $self->GetMetadata;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        my $test = $h->{'DCAP_'.uc($cap)};
+        push @cap, $cap if defined($test) and $test eq 'YES';
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    my $h = $self->GetMetadata->{'DCAP_'.uc($cap)};
+    return (defined($h) and $h eq 'YES') ? 1 : undef;
+}
+
+sub Extension {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return $h->{DMD_EXTENSION};
+}
+
+sub MIMEType {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return $h->{DMD_MIMETYPE};
+}
+
+sub CreationOptionList {
+    my $self = shift;
+    my @options;
+    my $h = $self->GetMetadata->{DMD_CREATIONOPTIONLIST};
+    if ($h) {
+        $h = Geo::GDAL::ParseXMLString($h);
+        my($type, $value) = Geo::GDAL::NodeData($h);
+        if ($value eq 'CreationOptionList') {
+            for my $o (Geo::GDAL::Children($h)) {
+                my %option;
+                for my $a (Geo::GDAL::Children($o)) {
+                    my(undef, $key) = Geo::GDAL::NodeData($a);
+                    my(undef, $value) = Geo::GDAL::NodeData(Geo::GDAL::Child($a, 0));
+                    if ($key eq 'Value') {
+                        push @{$option{$key}}, $value;
+                    } else {
+                        $option{$key} = $value;
+                    }
+                }
+                push @options, \%option;
+            }
+        }
+    }
+    return @options;
+}
+
+sub CreationDataTypes {
+    my $self = shift;
+    my $h = $self->GetMetadata;
+    return split /\s+/, $h->{DMD_CREATIONDATATYPES} if $h->{DMD_CREATIONDATATYPES};
+}
+
+sub Create {
+    my $self = shift;
+    my %defaults = ( Name => 'unnamed',
+                     Width => 256,
+                     Height => 256,
+                     Bands => 1,
+                     Type => 'Byte',
+                     Options => {} );
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (exists $defaults{$_[0]} and @_ % 2 == 0) {
+        %params = @_;
+    } else {
+        ($params{Name}, $params{Width}, $params{Height}, $params{Bands}, $params{Type}, $params{Options}) = @_;
+    }
+    for my $k (keys %params) {
+        carp "Create: unrecognized named parameter '$k'." unless exists $defaults{$k};
+    }
+    for my $k (keys %defaults) {
+        $params{$k} = $defaults{$k} unless defined $params{$k};
+    }
+    my $type;
+    confess "Unknown data type: '$params{Type}'." unless exists $Geo::GDAL::TYPE_STRING2INT{$params{Type}};
+    $type = $Geo::GDAL::TYPE_STRING2INT{$params{Type}};
+    return $self->_Create($params{Name}, $params{Width}, $params{Height}, $params{Bands}, $type, $params{Options});
+}
+*CreateDataset = *Create;
+*Copy = *CreateCopy;
+
+
+
+
+package Geo::GDAL::Dataset;
+use strict;
+use warnings;
+use Carp;
+use vars qw/%BANDS @DOMAINS/;
+ at DOMAINS = qw/IMAGE_STRUCTURE SUBDATASETS GEOLOCATION/;
+
+sub Domains {
+    return @DOMAINS;
+}
+*GetDriver = *_GetDriver;
+
+sub Open {
+    return Geo::GDAL::Open(@_);
+}
+
+sub OpenShared {
+    return Geo::GDAL::OpenShared(@_);
+}
+
+sub Size {
+    my $self = shift;
+    return ($self->{RasterXSize}, $self->{RasterYSize});
+}
+
+sub Bands {
+    my $self = shift;
+    my @bands;
+    for my $i (1..$self->{RasterCount}) {
+        push @bands, GetRasterBand($self, $i);
+    }
+    return @bands;
+}
+
+sub GetRasterBand {
+    my($self, $index) = @_;
+    $index = 1 unless defined $index;
+    my $band = _GetRasterBand($self, $index);
+    $BANDS{tied(%{$band})} = $self;
+    return $band;
+}
+*Band = *GetRasterBand;
+
+sub AddBand {
+    my @p = @_;
+    if (defined $p[1]) {
+        confess "Unknown data type: '$p[1]'." unless exists $Geo::GDAL::TYPE_STRING2INT{$p[1]};
+        $p[1] = $Geo::GDAL::TYPE_STRING2INT{$p[1]};
+    }
+    return _AddBand(@p);
+}
+
+sub Projection {
+    my($self, $proj) = @_;
+    SetProjection($self, $proj) if defined $proj;
+    GetProjection($self) if defined wantarray;
+}
+
+sub SpatialReference {
+    my($self, $sr) = @_;
+    SetProjection($self, $sr->As('WKT')) if defined $sr;
+    return Geo::OSR::SpatialReference->new(GetProjection($self)) if defined wantarray;
+}
+
+sub GeoTransform {
+    my $self = shift;
+    eval {
+        if (@_ == 1) {
+            SetGeoTransform($self, $_[0]);
+        } elsif (@_ > 1) {
+            SetGeoTransform($self, \@_);
+        }
+    };
+    confess $@ if $@;
+    return unless defined wantarray;
+    my $t = GetGeoTransform($self);
+    if (wantarray) {
+        return @$t;
+    } else {
+        return Geo::GDAL::GeoTransform->new($t);
+    }
+}
+
+sub GCPs {
+    my $self = shift;
+    if (@_ > 0) {
+        my $proj = pop @_;
+        $proj = $proj->Export('WKT') if $proj and ref($proj);
+        SetGCPs($self, \@_, $proj);
+    }
+    return unless defined wantarray;
+    my $proj = Geo::OSR::SpatialReference->new(GetGCPProjection($self));
+    my $GCPs = GetGCPs($self);
+    return (@$GCPs, $proj);
+}
+
+sub ReadRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->Band->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BANDLIST => [1],
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        BUFBANDSPACE => 0,
+        RESAMPLEALG => 'NearestNeighbour',
+        PROGRESS => undef,
+        PROGRESSDATA => undef
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{band_list},$p{buf_pixel_space},$p{buf_line_space},$p{buf_band_space},$p{resample_alg},$p{progress},$p{progress_data}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    confess "Unknown resampling algorithm: '$p{RESAMPLEALG}'." 
+        unless exists $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    $p{RESAMPLEALG} = $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_ReadRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BANDLIST},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{BUFBANDSPACE},$p{RESAMPLEALG},$p{PROGRESS},$p{PROGRESSDATA});
+}
+
+sub WriteRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->Band->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUF => undef,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BANDLIST => [1],
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        BUFBANDSPACE => 0
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{band_list},$p{buf_pixel_space},$p{buf_line_space},$p{buf_band_space}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_WriteRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUF},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BANDLIST},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{BUFBANDSPACE});
+}
+
+sub BuildOverviews {
+    my $self = shift;
+    my @p = @_;
+    $p[0] = uc($p[0]) if $p[0];
+    eval {
+        $self->_BuildOverviews(@p);
+    };
+    confess $@ if $@;
+}
+
+
+
+
+package Geo::GDAL::Band;
+use strict;
+use warnings;
+use POSIX;
+use Carp;
+use Scalar::Util 'blessed';
+use vars qw/
+    @COLOR_INTERPRETATIONS
+    %COLOR_INTERPRETATION_STRING2INT %COLOR_INTERPRETATION_INT2STRING @DOMAINS
+    %MASK_FLAGS
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@COLOR_INTERPRETATIONS, $1), next if /^GCI_(\w+)/;
+}
+for my $string (@COLOR_INTERPRETATIONS) {
+    my $int = eval "\$Geo::GDAL::Constc::GCI_$string";
+    $COLOR_INTERPRETATION_STRING2INT{$string} = $int;
+    $COLOR_INTERPRETATION_INT2STRING{$int} = $string;
+}
+ at DOMAINS = qw/IMAGE_STRUCTURE RESAMPLING/;
+%MASK_FLAGS = (AllValid => 1, PerDataset => 2, Alpha => 4, NoData => 8);
+
+sub Domains {
+    return @DOMAINS;
+}
+
+sub ColorInterpretations {
+    return @COLOR_INTERPRETATIONS;
+}
+
+sub MaskFlags {
+    my @f = sort {$MASK_FLAGS{$a} <=> $MASK_FLAGS{$b}} keys %MASK_FLAGS;
+    return @f;
+}
+
+sub DESTROY {
+    my $self;
+    if ($_[0]->isa('SCALAR')) {
+        $self = $_[0];
+    } else {
+        return unless $_[0]->isa('HASH');
+        $self = tied(%{$_[0]});
+        return unless defined $self;
+    }
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        delete $OWNER{$self};
+    }
+    $self->RELEASE_PARENTS();
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::GDAL::Dataset::BANDS{$self};
+}
+
+sub Size {
+    my $self = shift;
+    return ($self->{XSize}, $self->{YSize});
+}
+
+sub DataType {
+    my $self = shift;
+    return $Geo::GDAL::TYPE_INT2STRING{$self->{DataType}};
+}
+
+sub PackCharacter {
+    my $self = shift;
+    return Geo::GDAL::PackCharacter($self->DataType);
+}
+
+sub NoDataValue {
+    my $self = shift;
+    if (@_ > 0) {
+        if (defined $_[0]) {
+            SetNoDataValue($self, $_[0]);
+        } else {
+            SetNoDataValue($self, POSIX::FLT_MAX); # hopefully an "out of range" value
+        }
+    }
+    GetNoDataValue($self);
+}
+
+sub Unit {
+    my $self = shift;
+    if (@_ > 0) {
+        my $unit = shift;
+        $unit = '' unless defined $unit;
+        SetUnitType($self, $unit);
+    }
+    return unless defined wantarray;
+    GetUnitType($self);
+}
+
+sub ScaleAndOffset {
+    my $self = shift;
+    SetScale($self, $_[0]) if @_ > 0 and defined $_[0];
+    SetOffset($self, $_[1]) if @_ > 1 and defined $_[1];
+    return unless defined wantarray;
+    my $scale = GetScale($self);
+    my $offset = GetOffset($self);
+    return ($scale, $offset);
+}
+
+sub ReadTile {
+    my($self, $xoff, $yoff, $xsize, $ysize) = @_;
+    $xoff = 0 unless defined $xoff;
+    $yoff = 0 unless defined $yoff;
+    $xsize = $self->{XSize} - $xoff unless defined $xsize;
+    $ysize = $self->{YSize} - $yoff unless defined $ysize;
+    my $buf = $self->ReadRaster($xoff, $yoff, $xsize, $ysize);
+    my $pc = Geo::GDAL::PackCharacter($self->{DataType});
+    my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
+    my $offset = 0;
+    my @data;
+    for (0..$ysize-1) {
+        my $sub = substr($buf, $offset, $w);
+        my @d = unpack($pc."[$xsize]", $sub);
+        push @data, \@d;
+        $offset += $w;
+    }
+    return \@data;
+}
+
+sub WriteTile {
+    my($self, $data, $xoff, $yoff) = @_;
+    $xoff = 0 unless defined $xoff;
+    $yoff = 0 unless defined $yoff;
+    my $xsize = @{$data->[0]};
+    $xsize = $self->{XSize} - $xoff if $xsize > $self->{XSize} - $xoff;
+    my $ysize = @{$data};
+    $ysize = $self->{YSize} - $yoff if $ysize > $self->{YSize} - $yoff;
+    my $pc = Geo::GDAL::PackCharacter($self->{DataType});
+    for my $i (0..$ysize-1) {
+        my $scanline = pack($pc."[$xsize]", @{$data->[$i]});
+        $self->WriteRaster( $xoff, $yoff+$i, $xsize, 1, $scanline );
+    }
+}
+
+sub ColorInterpretation {
+    my($self, $ci) = @_;
+    if (defined $ci) {
+        my $ci2 = $ci;
+        $ci2 = $COLOR_INTERPRETATION_STRING2INT{$ci} if exists $COLOR_INTERPRETATION_STRING2INT{$ci};
+        confess "Unknown color interpretation: '$ci'." unless exists $COLOR_INTERPRETATION_INT2STRING{$ci2};
+        SetRasterColorInterpretation($self, $ci2);
+        return $ci;
+    } else {
+        return $COLOR_INTERPRETATION_INT2STRING{GetRasterColorInterpretation($self)};
+    }
+}
+
+sub ColorTable {
+    my $self = shift;
+    SetRasterColorTable($self, $_[0]) if @_ and defined $_[0];
+    return unless defined wantarray;
+    GetRasterColorTable($self);
+}
+
+sub CategoryNames {
+    my $self = shift;
+    SetRasterCategoryNames($self, \@_) if @_;
+    return unless defined wantarray;
+    my $n = GetRasterCategoryNames($self);
+    return @$n;
+}
+
+sub AttributeTable {
+    my $self = shift;
+    SetDefaultRAT($self, $_[0]) if @_ and defined $_[0];
+    return unless defined wantarray;
+    my $r = GetDefaultRAT($self);
+    $Geo::GDAL::RasterAttributeTable::BANDS{$r} = $self if $r;
+    return $r;
+}
+
+sub GetHistogram {
+    my $self = shift;
+    my %defaults = (Min => -0.5,
+                    Max => 255.5,
+                    Buckets => 256,
+                    IncludeOutOfRange => 0,
+                    ApproxOK => 0,
+                    Progress => undef,
+                    ProgressData => undef);
+    my %params = @_;
+    for (keys %params) {
+        carp "unknown parameter $_ in Geo::GDAL::Band::GetHistogram" unless exists $defaults{$_};
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    $params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
+    _GetHistogram($self, $params{Min}, $params{Max}, $params{Buckets},
+                  $params{IncludeOutOfRange}, $params{ApproxOK},
+                  $params{Progress}, $params{ProgressData});
+}
+
+sub Contours {
+    my $self = shift;
+    my %defaults = (DataSource => undef,
+                    LayerConstructor => {Name => 'contours'},
+                    ContourInterval => 100,
+                    ContourBase => 0,
+                    FixedLevels => [],
+                    NoDataValue => undef,
+                    IDField => -1,
+                    ElevField => -1,
+                    Progress => undef,
+                    ProgressData => undef);
+    my %params;
+    if (!defined($_[0]) or (blessed($_[0]) and $_[0]->isa('Geo::OGR::DataSource'))) {
+        ($params{DataSource}, $params{LayerConstructor},
+         $params{ContourInterval}, $params{ContourBase},
+         $params{FixedLevels}, $params{NoDataValue},
+         $params{IDField}, $params{ElevField},
+         $params{Progress}, $params{ProgressData}) = @_;
+    } else {
+        %params = @_;
+        if (exists $params{progress}) {
+            $params{Progress} = $params{progress};
+            delete $params{progress};
+        }
+        if (exists $params{progress_data}) {
+            $params{ProgressData} = $params{progress_data};
+            delete $params{progress_data};
+        }
+    }
+    for (keys %params) {
+        carp "unknown parameter $_ in Geo::GDAL::Band::Contours" unless exists $defaults{$_};
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    $params{DataSource} = Geo::OGR::GetDriver('Memory')->CreateDataSource('ds')
+        unless defined $params{DataSource};
+    $params{LayerConstructor}->{Schema} = {} unless $params{LayerConstructor}->{Schema};
+    $params{LayerConstructor}->{Schema}{Fields} = [] unless $params{LayerConstructor}->{Schema}{Fields};
+    my %fields;
+    unless ($params{IDField} =~ /^[+-]?\d+$/ or $fields{$params{IDField}}) {
+        push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{IDField}, Type => 'Integer'};
+    }
+    unless ($params{ElevField} =~ /^[+-]?\d+$/ or $fields{$params{ElevField}}) {
+        my $type = $self->DataType() =~ /Float/ ? 'Real' : 'Integer';
+        push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{ElevField}, Type => $type};
+    }
+    my $layer = $params{DataSource}->CreateLayer($params{LayerConstructor});
+    my $schema = $layer->GetLayerDefn;
+    for ('IDField', 'ElevField') {
+        $params{$_} = $schema->GetFieldIndex($params{$_}) unless $params{$_} =~ /^[+-]?\d+$/;
+    }
+    $params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
+    ContourGenerate($self, $params{ContourInterval}, $params{ContourBase}, $params{FixedLevels},
+                    $params{NoDataValue}, $layer, $params{IDField}, $params{ElevField},
+                    $params{Progress}, $params{ProgressData});
+    return $layer;
+}
+
+sub FillNodata {
+    my $self = shift;
+    my $mask = shift;
+    $mask = $self->GetMaskBand unless $mask;
+    my @p = @_;
+    $p[0] = 10 unless defined $p[0];
+    $p[1] = 0 unless defined $p[1];
+    $p[2] = undef unless defined $p[2];
+    $p[3] = undef unless defined $p[3];
+    $p[4] = undef unless defined $p[1];
+    Geo::GDAL::FillNodata($self, $mask, @p);
+}
+*GetBandNumber = *GetBand;
+
+sub ReadRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0,
+        RESAMPLEALG => 'NearestNeighbour',
+        PROGRESS => undef,
+        PROGRESSDATA => undef
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{buf_pixel_space},$p{buf_line_space},$p{resample_alg},$p{progress},$p{progress_data}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    confess "Unknown resampling algorithm: '$p{RESAMPLEALG}'." 
+        unless exists $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    $p{RESAMPLEALG} = $Geo::GDAL::RIO_RESAMPLING_STRING2INT{$p{RESAMPLEALG}};
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_ReadRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BUFPIXELSPACE},$p{BUFLINESPACE},$p{RESAMPLEALG},$p{PROGRESS},$p{PROGRESSDATA});
+}
+
+sub WriteRaster {
+    my $self = shift;
+    my ($width, $height) = $self->Size;
+    my ($type) = $self->DataType;
+    my %d = (
+        XOFF => 0,
+        YOFF => 0,
+        XSIZE => $width,
+        YSIZE => $height,
+        BUF => undef,
+        BUFXSIZE => undef,
+        BUFYSIZE => undef,
+        BUFTYPE => $type,
+        BUFPIXELSPACE => 0,
+        BUFLINESPACE => 0
+        );
+    my %p;
+    my $t;
+    if (defined $_[0]) {
+        $t = uc($_[0]); 
+        $t =~ s/_//g;
+    }
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %p = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $t and exists $d{$t})) {
+        %p = @_;
+    } else {
+        ($p{xoff},$p{yoff},$p{xsize},$p{ysize},$p{buf},$p{buf_xsize},$p{buf_ysize},$p{buf_type},$p{buf_pixel_space},$p{buf_line_space}) = @_;
+    }
+    for (keys %p) {
+        my $u = uc($_);
+        $u =~ s/_//g;
+        carp "Unknown named parameter '$_'." unless exists $d{$u};
+        $p{$u} = $p{$_};
+    }
+    for (keys %d) {
+        $p{$_} = $d{$_} unless defined $p{$_};
+    }
+    unless ($Geo::GDAL::TYPE_INT2STRING{$p{BUFTYPE}}) {
+        confess "Unknown data type: '$p{BUFTYPE}'." 
+            unless exists $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+        $p{BUFTYPE} = $Geo::GDAL::TYPE_STRING2INT{$p{BUFTYPE}};
+    }
+    $self->_WriteRaster($p{XOFF},$p{YOFF},$p{XSIZE},$p{YSIZE},$p{BUF},$p{BUFXSIZE},$p{BUFYSIZE},$p{BUFTYPE},$p{BUFPIXELSPACE},$p{BUFLINESPACE});
+}
+
+sub GetMaskFlags {
+    my $self = shift;
+    my $f = $self->_GetMaskFlags;
+    my @f;
+    for my $flag (keys %MASK_FLAGS) {
+        push @f, $flag if $f & $MASK_FLAGS{$flag};
+    }
+    return wantarray ? @f : $f;
+}
+
+sub CreateMaskBand {
+    my $self = shift;
+    my $f = 0;
+    if (@_ and $_[0] =~ /^\d$/) {
+        $f = shift;
+    } else {
+        for my $flag (@_) {
+            carp "Unknown mask flag: '$flag'." unless $MASK_FLAGS{$flag};
+            $f |= $MASK_FLAGS{$flag};
+        }
+    }
+    $self->_CreateMaskBand($f);
+}
+
+# GetMaskBand should be redefined and the result should be put into 
+# %Geo::GDAL::Dataset::BANDS
+
+# GetOverview should be redefined and the result should be put into 
+# %Geo::GDAL::Dataset::BANDS
+
+sub RegenerateOverview {
+    my $self = shift;
+    #Geo::GDAL::Band overview, scalar resampling, subref callback, scalar callback_data
+    my @p = @_;
+    Geo::GDAL::RegenerateOverview($self, @p);
+}
+ 
+sub RegenerateOverviews {
+    my $self = shift;
+    #arrayref overviews, scalar resampling, subref callback, scalar callback_data
+    my @p = @_;
+    Geo::GDAL::RegenerateOverviews($self, @p);
+}
+
+
+
+
+package Geo::GDAL::ColorTable;
+use strict;
+use warnings;
+use Carp;
+use vars qw/
+    %PALETTE_INTERPRETATION_STRING2INT %PALETTE_INTERPRETATION_INT2STRING
+    /;
+for my $string (qw/Gray RGB CMYK HLS/) {
+    my $int = eval "\$Geo::GDAL::Constc::GPI_$string";
+    $PALETTE_INTERPRETATION_STRING2INT{$string} = $int;
+    $PALETTE_INTERPRETATION_INT2STRING{$int} = $string;
+}
+
+sub GetPaletteInterpretation {
+    my $self = shift;
+    return $PALETTE_INTERPRETATION_INT2STRING{GetPaletteInterpretation($self)};
+}
+
+sub SetColorEntry {
+    my $self = shift;
+    my $index = shift;
+    my $color;
+    if (ref($_[0]) eq 'ARRAY') {
+        $color = shift;
+    } else {
+        $color = [@_];
+    }
+    eval {
+        $self->_SetColorEntry($index, $color);
+    };
+    confess $@ if $@;
+}
+
+sub ColorEntry {
+    my $self = shift;
+    my $index = shift;
+    SetColorEntry($self, $index, @_) if @_ > 0;
+    GetColorEntry($self, $index) if defined wantarray;
+}
+
+sub ColorTable {
+    my $self = shift;
+    my @table;
+    if (@_) {
+        my $index = 0;
+        for my $color (@_) {
+            push @table, [ColorEntry($self, $index, @$color)];
+            $index++;
+        }
+    } else {
+        for (my $index = 0; $index < GetCount($self); $index++) {
+            push @table, [ColorEntry($self, $index)];
+        }
+    }
+    return @table;
+}
+*ColorEntries = *ColorTable;
+
+
+
+
+package Geo::GDAL::RasterAttributeTable;
+use strict;
+use warnings;
+use Carp;
+use vars qw/ %BANDS
+    @FIELD_TYPES @FIELD_USAGES
+    %FIELD_TYPE_STRING2INT %FIELD_TYPE_INT2STRING
+    %FIELD_USAGE_STRING2INT %FIELD_USAGE_INT2STRING
+    /;
+for (keys %Geo::GDAL::Const::) {
+    next if /TypeCount/;
+    push(@FIELD_TYPES, $1), next if /^GFT_(\w+)/;
+    push(@FIELD_USAGES, $1), next if /^GFU_(\w+)/;
+}
+for my $string (@FIELD_TYPES) {
+    my $int = eval "\$Geo::GDAL::Constc::GFT_$string";
+    $FIELD_TYPE_STRING2INT{$string} = $int;
+    $FIELD_TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@FIELD_USAGES) {
+    my $int = eval "\$Geo::GDAL::Constc::GFU_$string";
+    $FIELD_USAGE_STRING2INT{$string} = $int;
+    $FIELD_USAGE_INT2STRING{$int} = $string;
+}
+
+sub FieldTypes {
+    return @FIELD_TYPES;
+}
+
+sub FieldUsages {
+    return @FIELD_USAGES;
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $BANDS{$self};
+}
+
+sub GetUsageOfCol {
+    my($self, $col) = @_;
+    $FIELD_USAGE_INT2STRING{_GetUsageOfCol($self, $col)};
+}
+
+sub GetColOfUsage {
+    my($self, $usage) = @_;
+    _GetColOfUsage($self, $FIELD_USAGE_STRING2INT{$usage});
+}
+
+sub GetTypeOfCol {
+    my($self, $col) = @_;
+    $FIELD_TYPE_INT2STRING{_GetTypeOfCol($self, $col)};
+}
+
+sub Columns {
+    my $self = shift;
+    my %columns;
+    if (@_) { # create columns
+        %columns = @_;
+        for my $name (keys %columns) {
+            $self->CreateColumn($name, $columns{$name}{Type}, $columns{$name}{Usage});
+        }
+    }
+    %columns = ();
+    for my $c (0..$self->GetColumnCount-1) {
+        my $name = $self->GetNameOfCol($c);
+        $columns{$name}{Type} = $self->GetTypeOfCol($c);
+        $columns{$name}{Usage} = $self->GetUsageOfCol($c);
+    }
+    return %columns;
+}
+
+sub CreateColumn {
+    my($self, $name, $type, $usage) = @_;
+    confess "Unknown RAT column type: '$type'." unless exists $FIELD_TYPE_STRING2INT{$type};
+    confess "Unknown RAT column usage: '$usage'." unless exists $FIELD_USAGE_STRING2INT{$usage};
+    for my $color (qw/Red Green Blue Alpha/) {
+        carp "RAT column type will be 'Integer' for usage '$color'." if $usage eq $color and $type ne 'Integer';
+    }
+    $type = $FIELD_TYPE_STRING2INT{$type};
+    $usage = $FIELD_USAGE_STRING2INT{$usage};
+    _CreateColumn($self, $name, $type, $usage);
+}
+
+sub Value {
+    my($self, $row, $column) = @_;
+    SetValueAsString($self, $row, $column, $_[3]) if defined $_[3];
+    return unless defined wantarray;
+    GetValueAsString($self, $row, $column);
+}
+
+sub LinearBinning {
+    my $self = shift;
+    SetLinearBinning($self, @_) if @_ > 0;
+    return unless defined wantarray;
+    my @a = GetLinearBinning($self);
+    return $a[0] ? ($a[1], $a[2]) : ();
+}
+
+
+
+
+package Geo::GDAL::GCP;
+
+*swig_Pixel_get = *Geo::GDALc::GCP_Column_get;
+*swig_Pixel_set = *Geo::GDALc::GCP_Column_set;
+*swig_Line_get = *Geo::GDALc::GCP_Row_get;
+*swig_Line_set = *Geo::GDALc::GCP_Row_set;
+
+
+
+package Geo::GDAL::VSIF;
+use strict;
+use warnings;
+use Carp;
+
+sub Open {
+    my ($path, $mode) = @_;
+    my $self = Geo::GDAL::VSIFOpenL($path, $mode);
+    bless $self, 'Geo::GDAL::VSIF';
+}
+
+sub Write {
+    my ($self, $data) = @_;
+    Geo::GDAL::VSIFWriteL($data, $self);
+}
+
+sub Close {
+    my ($self, $data) = @_;
+    Geo::GDAL::VSIFCloseL($self);
+}
+
+sub Read {
+    my ($self, $count) = @_;
+    Geo::GDAL::VSIFReadL($count, $self);
+}
+
+sub Seek {
+    my ($self, $offset, $whence) = @_;
+    Geo::GDAL::VSIFSeekL($self, $offset, $whence);
+}
+
+sub Tell {
+    my ($self) = @_;
+    Geo::GDAL::VSIFTellL($self);
+}
+
+sub Truncate {
+    my ($self, $new_size) = @_;
+    Geo::GDAL::VSIFTruncateL($self, $new_size);
+}
+
+sub Mkdir {
+    my ($path, $mode) = @_;
+    Geo::GDAL::Mkdir($path, $mode);
+}
+*MkDir = *Mkdir;
+
+sub ReadDir {
+    my ($path) = @_;
+    Geo::GDAL::ReadDir($path);
+}
+
+sub ReadDirRecursive {
+    my ($path) = @_;
+    Geo::GDAL::ReadDirRecursive($path);
+}
+
+sub Rename {
+    my ($old, $new) = @_;
+    Geo::GDAL::Rename($old, $new);
+}
+
+sub Rmdir {
+    my ($dirname, $recursive) = @_;
+    if (!$recursive) {
+        Geo::GDAL::Rmdir($dirname);
+    } else {
+        for my $f (ReadDir($dirname)) {
+            next if $f eq '..' or $f eq '.';
+            my @s = Stat($dirname.'/'.$f);
+            if ($s[0] eq 'f') {
+                Unlink($dirname.'/'.$f);
+            } elsif ($s[0] eq 'd') {
+                Rmdir($dirname.'/'.$f, 1);
+                Rmdir($dirname.'/'.$f);
+            }
+        }
+        Rmdir($dirname);
+    }
+}
+*RmDir = *Rmdir;
+
+sub Stat {
+    my ($path) = @_;
+    Geo::GDAL::Stat($path);
+}
+
+sub Unlink {
+    my ($filename) = @_;
+    Geo::GDAL::Unlink($filename);
+}
+
+
+
+
+package Geo::GDAL::GeoTransform;
+use strict;
+use warnings;
+use Carp;
+
+sub new {
+    my $class = shift;
+    my $self;
+    if (@_ == 0) {
+        $self = [0,1,0,0,0,1];
+    } elsif (@_ == 1) {
+        $self = $_[0];
+    } else {
+        my @a = @_;
+        $self = \@a;
+    }
+    bless $self, $class;
+    return $self;
+}
+
+sub FromGCPs {
+    my @GCPs;
+    my $ApproxOK = 1;
+    if (ref($_[0]) eq 'ARRAY') {
+        @GCPs = @{$_[0]};
+        $ApproxOK = $_[1] if defined $_[1];
+    } else {
+        @GCPs = @_;
+        $ApproxOK = pop @GCPs if !ref($GCPs[$#GCPs]);
+    }
+    my $self = Geo::GDAL::GCPsToGeoTransform(\@GCPs, $ApproxOK);
+    bless $self, 'Geo::GDAL::GetTransform';
+    return $self;
+}
+
+sub Apply {
+    my ($self, $columns, $rows) = @_;
+    my (@x, @y);
+    for my $i (0..$#$columns) {
+        ($x[$i], $y[$i]) = 
+            Geo::GDAL::ApplyGeoTransform($self, $columns->[$i], $rows->[$i]);
+    }
+    return (\@x, \@y);
+}
+
+sub Inv {
+    my $self = shift;
+    my @inv = Geo::GDAL::InvGeoTransform($self);
+    unless (defined wantarray) {
+        @$self = @inv;
+    } else {
+        return new(@inv);
+    }
+}
 
-    use strict;
-    use Carp;
-    use Encode;
-    use Geo::GDAL::Const;
-    use Geo::OGR;
-    use Geo::OSR;
-    # $VERSION is the Perl module (CPAN) version number, which must be
-    # an increasing floating point number.  $GDAL_VERSION is the
-    # version number of the GDAL that this module is a part of. It is
-    # used in build time to check the version of GDAL against which we
-    # build.  For GDAL 1.9.2 and below $VERSION is made by dropping
-    # the second point.  Hoping that there will not be GDAL 1.9.10, we
-    # set the $VERSION of GDAL 1.10 to 1.991. Thus GDAL 1.10.1 would
-    # have $VERSION 1.9911 and GDAL 1.11 would have $VERSION 1.992
-    # etc.  GDAL 2.0 should then get VERSION 2.000 and 2.1 should get
-    # 2.001 etc.
-
-    our $VERSION = '1.9922';
-    our $GDAL_VERSION = '1.11.2';
-    use vars qw/
-	%TYPE_STRING2INT %TYPE_INT2STRING
-	%ACCESS_STRING2INT %ACCESS_INT2STRING
-	%RESAMPLING_STRING2INT %RESAMPLING_INT2STRING
-	%NODE_TYPE_STRING2INT %NODE_TYPE_INT2STRING
-	/;
-    for my $string (qw/Unknown Byte UInt16 Int16 UInt32 Int32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64/) {
-	my $int = eval "\$Geo::GDAL::Constc::GDT_$string";
-	$TYPE_STRING2INT{$string} = $int;
-	$TYPE_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/ReadOnly Update/) {
-	my $int = eval "\$Geo::GDAL::Constc::GA_$string";
-	$ACCESS_STRING2INT{$string} = $int;
-	$ACCESS_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/NearestNeighbour Bilinear Cubic CubicSpline/) {
-	my $int = eval "\$Geo::GDAL::Constc::GRA_$string";
-	$RESAMPLING_STRING2INT{$string} = $int;
-	$RESAMPLING_INT2STRING{$int} = $string;
-    }
-    {
-	my $int = 0;
-	for my $string (qw/Element Text Attribute Comment Literal/) {
-	    $NODE_TYPE_STRING2INT{$string} = $int;
-	    $NODE_TYPE_INT2STRING{$int} = $string;
-	    $int++;
-	}
-    }
-    sub RELEASE_PARENTS {
-    }
-    sub NodeType {
-	my $type = shift;
-	return $NODE_TYPE_INT2STRING{$type} if $type =~ /^\d/;
-	return $NODE_TYPE_STRING2INT{$type};
-    }
-    sub NodeData {
-	my $node = shift;
-	return (Geo::GDAL::NodeType($node->[0]), $node->[1]);
-    }
-    sub Children {
-	my $node = shift;
-	return @$node[2..$#$node];
-    }
-    sub Child {
-	my($node, $child) = @_;
-	return $node->[2+$child];
-    }
-    sub GetDataTypeSize {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	return _GetDataTypeSize($t);
-    }
-    sub DataTypeValueRange {
-    	my $t = shift;
-	# these values are from gdalrasterband.cpp
-	return (0,255) if $t =~ /^Byte$/;
-	return (0,65535) if $t =~ /^UInt16$/;
-	return (-32768,32767) if $t =~ /Int16$/; # also CInt
-	return (0,4294967295) if $t =~ /^UInt32$/;
-	return (-2147483648,2147483647) if $t =~ /Int32$/; # also CInt
-	return (-4294967295.0,4294967295.0) if $t =~ /Float32$/; # also CFloat
-	return (-4294967295.0,4294967295.0) if $t =~ /Float64$/; # also CFloat
-	croak "GDAL does not support data type '$t'";
-    }
-    sub DataTypeIsComplex {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	return _DataTypeIsComplex($t);
-    }
-    sub PackCharacter {
-	my $t = shift;
-	$t = $TYPE_INT2STRING{$t} if exists $TYPE_INT2STRING{$t};
-	my $is_big_endian = unpack("h*", pack("s", 1)) =~ /01/; # from Programming Perl
-	return 'C' if $t =~ /^Byte$/;
-	return ($is_big_endian ? 'n': 'v') if $t =~ /^UInt16$/;
-	return 's' if $t =~ /^Int16$/;
-	return ($is_big_endian ? 'N' : 'V') if $t =~ /^UInt32$/;
-	return 'l' if $t =~ /^Int32$/;
-	return 'f' if $t =~ /^Float32$/;
-	return 'd' if $t =~ /^Float64$/;
-	croak "data type '$t' is not known in Geo::GDAL::PackCharacter";
-    }
-    sub Drivers {
-	my @drivers;
-	for my $i (0..GetDriverCount()-1) {
-	    push @drivers, _GetDriver($i);
-	}
-	return @drivers;
-    }
-    sub GetDriver {
-	my $driver = shift;
-	return _GetDriver($driver) if $driver =~ /^\d/;
-	return GetDriverByName($driver);
-    }
-    *Driver = *GetDriver;
-    sub Open {
-	my @p = @_;
-	$p[1] = $ACCESS_STRING2INT{$p[1]} if $p[1] and exists $ACCESS_STRING2INT{$p[1]};
-	return _Open(@p);
-    }
-    sub OpenShared {
-	my @p = @_;
-	$p[1] = $ACCESS_STRING2INT{$p[1]} if $p[1] and exists $ACCESS_STRING2INT{$p[1]};
-	return _OpenShared(@p);
-    }
-    sub ComputeMedianCutPCT {
-    	$_[6] = 1 if $_[5] and not defined $_[6];
-	_ComputeMedianCutPCT(@_);
-    }
-    sub DitherRGB2PCT {
-    	$_[6] = 1 if $_[5] and not defined $_[6];
-	_DitherRGB2PCT(@_);
-    }
-    sub ComputeProximity {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_ComputeProximity(@_);
-    }
-    sub RasterizeLayer {
-    	$_[8] = 1 if $_[7] and not defined $_[8];
-	_RasterizeLayer(@_);
-    }
-    sub Polygonize {
-        my @params = @_;
-        $params[6] = 1 if $params[5] and not defined $params[6];
-        $params[3] = $params[2]->GetLayerDefn->GetFieldIndex($params[3]) unless $params[3] =~ /^\d/;
-	_Polygonize(@params);
-    }
-    sub SieveFilter {
-    	$_[7] = 1 if $_[6] and not defined $_[7];
-	_SieveFilter(@_);
-    }
-    sub RegenerateOverviews {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_RegenerateOverviews(@_);
-    }
-    sub RegenerateOverview {
-    	$_[4] = 1 if $_[3] and not defined $_[4];
-	_RegenerateOverview(@_);
-    }
-    sub ReprojectImage {
-    	$_[8] = 1 if $_[7] and not defined $_[8];
-	$_[4] = $RESAMPLING_STRING2INT{$_[4]} if $_[4] and exists $RESAMPLING_STRING2INT{$_[4]};
-	return _ReprojectImage(@_);
-    }
-    sub AutoCreateWarpedVRT {
-	$_[3] = $RESAMPLING_STRING2INT{$_[3]} if $_[3] and exists $RESAMPLING_STRING2INT{$_[3]};
-	return _AutoCreateWarpedVRT(@_);
-    }
-
-    package Geo::GDAL::MajorObject;
-    use vars qw/@DOMAINS/;
-    use strict;
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub Description {
-	my($self, $desc) = @_;
-	SetDescription($self, $desc) if defined $desc;
-	GetDescription($self) if defined wantarray;
-    }
-    sub Metadata {
-	my $self = shift;
-	my $metadata;
-	$metadata = shift if ref $_[0];
-	my $domain = shift;
-	$domain = '' unless defined $domain;
-	SetMetadata($self, $metadata, $domain) if defined $metadata;
-	GetMetadata($self, $domain) if defined wantarray;
-    }
-
-    package Geo::GDAL::Driver;
-    use vars qw/@CAPABILITIES @DOMAINS/;
-    use strict;
-    @CAPABILITIES = ('Create', 'CreateCopy');
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub Name {
-	my $self = shift;
-	return $self->{ShortName};
-    }
-    sub Capabilities {
-	my $self = shift;
-	return @CAPABILITIES unless $self;
-	my $h = $self->GetMetadata;
-	my @cap;
-	for my $cap (@CAPABILITIES) {
-	    my $test = $h->{'DCAP_'.uc($cap)};
-	    push @cap, $cap if defined($test) and $test eq 'YES';
-	}
-	return @cap;
-    }
-    sub TestCapability {
-	my($self, $cap) = @_;
-	my $h = $self->GetMetadata->{'DCAP_'.uc($cap)};
-	return (defined($h) and $h eq 'YES') ? 1 : undef;
-    }
-    sub Extension {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return $h->{DMD_EXTENSION};
-    }
-    sub MIMEType {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return $h->{DMD_MIMETYPE};
-    }
-    sub CreationOptionList {
-	my $self = shift;
-	my @options;
-	my $h = $self->GetMetadata->{DMD_CREATIONOPTIONLIST};
-	if ($h) {
-	    $h = Geo::GDAL::ParseXMLString($h);
-	    my($type, $value) = Geo::GDAL::NodeData($h);
-	    if ($value eq 'CreationOptionList') {
-		for my $o (Geo::GDAL::Children($h)) {
-		    my %option;
-		    for my $a (Geo::GDAL::Children($o)) {
-			my(undef, $key) = Geo::GDAL::NodeData($a);
-			my(undef, $value) = Geo::GDAL::NodeData(Geo::GDAL::Child($a, 0));
-			if ($key eq 'Value') {
-			    push @{$option{$key}}, $value;
-			} else {
-			    $option{$key} = $value;
-			}
-		    }
-		    push @options, \%option;
-		}
-	    }
-	}
-	return @options;
-    }
-    sub CreationDataTypes {
-	my $self = shift;
-	my $h = $self->GetMetadata;
-	return split /\s+/, $h->{DMD_CREATIONDATATYPES};
-    }
-    sub CreateDataset {
-	my @p = @_;
-	$p[5] = $Geo::GDAL::TYPE_STRING2INT{$p[5]} if $p[5] and exists $Geo::GDAL::TYPE_STRING2INT{$p[5]};
-	return _Create(@p);
-    }
-    *Create = *CreateDataset;
-    *Copy = *CreateCopy;
-
-    package Geo::GDAL::Dataset;
-    use strict;
-    use vars qw/%BANDS @DOMAINS/;
-    @DOMAINS = ("IMAGE_STRUCTURE", "SUBDATASETS", "GEOLOCATION");
-    sub Domains {
-	return @DOMAINS;
-    }
-    *GetDriver = *_GetDriver;
-    sub Open {
-	return Geo::GDAL::Open(@_);
-    }
-    sub OpenShared {
-	return Geo::GDAL::OpenShared(@_);
-    }
-    sub Size {
-	my $self = shift;
-	return ($self->{RasterXSize}, $self->{RasterYSize});
-    }
-    sub Bands {
-	my $self = shift;
-	my @bands;
-	for my $i (1..$self->{RasterCount}) {
-	    push @bands, GetRasterBand($self, $i);
-	}
-	return @bands;
-    }
-    sub GetRasterBand {
-	my($self, $index) = @_;
-	$index = 1 unless defined $index;
-	my $band = _GetRasterBand($self, $index);
-	$BANDS{tied(%{$band})} = $self;
-	return $band;
-    }
-    *Band = *GetRasterBand;
-    sub AddBand {
-	my @p = @_;
-	$p[1] = $Geo::GDAL::TYPE_STRING2INT{$p[1]} if $p[1] and exists $Geo::GDAL::TYPE_STRING2INT{$p[1]};
-	return _AddBand(@p);
-    }
-    sub Projection {
-	my($self, $proj) = @_;
-	SetProjection($self, $proj) if defined $proj;
-	GetProjection($self) if defined wantarray;
-    }
-    sub GeoTransform {
-	my $self = shift;
-	SetGeoTransform($self, \@_) if @_ > 0;
-	return unless defined wantarray;
-	my $t = GetGeoTransform($self);
-	return @$t;
-    }
-    sub GCPs {
-	my $self = shift;
-	if (@_ > 0) {
-	    my $proj = pop @_;
-	    SetGCPs($self, \@_, $proj);
-	}
-	return unless defined wantarray;
-	my $proj = GetGCPProjection($self);
-	my $GCPs = GetGCPs($self);
-	return (@$GCPs, $proj);
-    }
-
-    package Geo::GDAL::Band;
-    use strict;
-    use Carp;
-    use Scalar::Util 'blessed';
-    use vars qw/
-        @COLOR_INTERPRETATIONS
-	%COLOR_INTERPRETATION_STRING2INT %COLOR_INTERPRETATION_INT2STRING @DOMAINS
-	/;
-    @COLOR_INTERPRETATIONS = qw/Undefined GrayIndex PaletteIndex RedBand GreenBand BlueBand AlphaBand 
-		    HueBand SaturationBand LightnessBand CyanBand MagentaBand YellowBand BlackBand/;
-    for my $string (@COLOR_INTERPRETATIONS) {
-	my $int = eval "\$Geo::GDAL::Constc::GCI_$string";
-	$COLOR_INTERPRETATION_STRING2INT{$string} = $int;
-	$COLOR_INTERPRETATION_INT2STRING{$int} = $string;
-    }
-    @DOMAINS = ("IMAGE_STRUCTURE", "RESAMPLING");
-    sub Domains {
-	return @DOMAINS;
-    }
-    sub DESTROY {
-	my $self;
-	if ($_[0]->isa('SCALAR')) {
-	    $self = $_[0];
-	} else {
-	    return unless $_[0]->isa('HASH');
-	    $self = tied(%{$_[0]});
-	    return unless defined $self;
-	}
-	delete $ITERATORS{$self};
-	if (exists $OWNER{$self}) {
-	    delete $OWNER{$self};
-	}
-	$self->RELEASE_PARENTS();
-    }
-    sub RELEASE_PARENTS {
-	my $self = shift;
-	delete $Geo::GDAL::Dataset::BANDS{$self};
-    }
-    sub Size {
-	my $self = shift;
-	return ($self->{XSize}, $self->{YSize});
-    }
-    sub DataType {
-	my $self = shift;
-	return $Geo::GDAL::TYPE_INT2STRING{$self->{DataType}};
-    }
-    sub NoDataValue {
-	my $self = shift;
-	SetNoDataValue($self, $_[0]) if @_ > 0;
-	GetNoDataValue($self);
-    }
-    sub Unit {
-	my $self = shift;
-	SetUnitType($self, $_[0]) if @_ > 0;
-	GetUnitType($self);
-    }
-    sub ScaleAndOffset {
-	my $self = shift;
-	SetScale($self, $_[0]) if @_ > 0;
-	SetOffset($self, $_[1]) if @_ > 1;
-	(GetScale($self), GetOffset($self));
-    }
-    sub ReadTile {
-	my($self, $xoff, $yoff, $xsize, $ysize) = @_;
-	$xoff = 0 unless defined $xoff;
-	$yoff = 0 unless defined $yoff;
-	$xsize = $self->{XSize} - $xoff unless defined $xsize;
-	$ysize = $self->{YSize} - $yoff unless defined $ysize;
-	my $buf = $self->ReadRaster($xoff, $yoff, $xsize, $ysize);
-	my $pc = Geo::GDAL::PackCharacter($self->{DataType});
-	my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
-	my $offset = 0;
-	my @data;
-	for (0..$ysize-1) {
-	    my $sub = substr($buf, $offset, $w);
-	    my @d = unpack($pc."[$xsize]", $sub);
-	    push @data, \@d;
-	    $offset += $w;
-	}
-	return \@data;
-    }
-    sub WriteTile {
-	my($self, $data, $xoff, $yoff) = @_;
-	$xoff = 0 unless defined $xoff;
-	$yoff = 0 unless defined $yoff;
-	my $xsize = @{$data->[0]};
-	$xsize = $self->{XSize} - $xoff if $xsize > $self->{XSize} - $xoff;
-	my $ysize = @{$data};
-	$ysize = $self->{YSize} - $yoff if $ysize > $self->{YSize} - $yoff;
-	my $pc = Geo::GDAL::PackCharacter($self->{DataType});
-	my $w = $xsize * Geo::GDAL::GetDataTypeSize($self->{DataType})/8;
-	for my $i (0..$ysize-1) {
-	    my $scanline = pack($pc."[$xsize]", @{$data->[$i]});
-	    $self->WriteRaster( $xoff, $yoff+$i, $xsize, 1, $scanline );
-	}
-    }
-    sub ColorInterpretation {
-	my($self, $ci) = @_;
-	if ($ci) {
-	    $ci = $COLOR_INTERPRETATION_STRING2INT{$ci} if exists $COLOR_INTERPRETATION_STRING2INT{$ci};
-	    SetRasterColorInterpretation($self, $ci);
-	    return $ci;
-	} else {
-	    return $COLOR_INTERPRETATION_INT2STRING{GetRasterColorInterpretation($self)};
-	}
-    }
-    sub ColorTable {
-	my $self = shift;
-	SetRasterColorTable($self, $_[0]) if @_;
-	return unless defined wantarray;
-	GetRasterColorTable($self);
-    }
-    sub CategoryNames {
-	my $self = shift;
-	SetRasterCategoryNames($self, \@_) if @_;
-	return unless defined wantarray;
-	my $n = GetRasterCategoryNames($self);
-	return @$n;
-    }
-    sub AttributeTable {
-	my $self = shift;
-	SetDefaultRAT($self, $_[0]) if @_;
-	return unless defined wantarray;
-	my $r = GetDefaultRAT($self);
-	$Geo::GDAL::RasterAttributeTable::BANDS{$r} = $self;
-	return $r;
-    }
-    sub GetHistogram {
-	my $self = shift;
-	my %defaults = (Min => -0.5,
-			Max => 255.5,
-			Buckets => 256, 
-			IncludeOutOfRange => 0,
-			ApproxOK => 0,
-			Progress => undef,
-			ProgressData => undef);
-	my %params = @_;
-	for (keys %params) {
-	    carp "unknown parameter $_ in Geo::GDAL::Band::GetHistogram" unless exists $defaults{$_};
-	}
-	for (keys %defaults) {
-	    $params{$_} = $defaults{$_} unless defined $params{$_};
-	}
-	$params{ProgressData} = 1 if $params{Progress} and not defined $params{ProgressData};
-	_GetHistogram($self, $params{Min}, $params{Max}, $params{Buckets},
-		      $params{IncludeOutOfRange}, $params{ApproxOK},
-		      $params{Progress}, $params{ProgressData});
-    }
-    sub Contours {
-	my $self = shift;
-	my %defaults = (DataSource => undef,
-			LayerConstructor => {Name => 'contours'},
-			ContourInterval => 100, 
-			ContourBase => 0,
-			FixedLevels => [], 
-			NoDataValue => undef, 
-			IDField => -1, 
-			ElevField => -1,
-			callback => undef,
-			callback_data => undef);
-	my %params;
-	if (!defined($_[0]) or (blessed($_[0]) and $_[0]->isa('Geo::OGR::DataSource'))) {
-	    ($params{DataSource}, $params{LayerConstructor},
-	     $params{ContourInterval}, $params{ContourBase},
-	     $params{FixedLevels}, $params{NoDataValue}, 
-	     $params{IDField}, $params{ElevField},
-	     $params{callback}, $params{callback_data}) = @_;
-	} else {
-	    %params = @_;
-	}
-	for (keys %params) {
-	    carp "unknown parameter $_ in Geo::GDAL::Band::Contours" unless exists $defaults{$_};
-	}
-	for (keys %defaults) {
-	    $params{$_} = $defaults{$_} unless defined $params{$_};
-	}
-	$params{DataSource} = Geo::OGR::GetDriver('Memory')->CreateDataSource('ds') 
-	    unless defined $params{DataSource};
-	$params{LayerConstructor}->{Schema} = {} unless $params{LayerConstructor}->{Schema};
-	$params{LayerConstructor}->{Schema}{Fields} = [] unless $params{LayerConstructor}->{Schema}{Fields};
-	my %fields;
-	unless ($params{IDField} =~ /^[+-]?\d+$/ or $fields{$params{IDField}}) {
-	    push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{IDField}, Type => 'Integer'};
-	}
-	unless ($params{ElevField} =~ /^[+-]?\d+$/ or $fields{$params{ElevField}}) {
-	    my $type = $self->DataType() =~ /Float/ ? 'Real' : 'Integer';
-	    push @{$params{LayerConstructor}->{Schema}{Fields}}, {Name => $params{ElevField}, Type => $type};
-	}
-	my $layer = $params{DataSource}->CreateLayer($params{LayerConstructor});
-	my $schema = $layer->GetLayerDefn;
-	for ('IDField', 'ElevField') {
-	    $params{$_} = $schema->GetFieldIndex($params{$_}) unless $params{$_} =~ /^[+-]?\d+$/;
-	}
-	$params{callback_data} = 1 if $params{callback} and not defined $params{callback_data};
-	ContourGenerate($self, $params{ContourInterval}, $params{ContourBase}, $params{FixedLevels},
-			$params{NoDataValue}, $layer, $params{IDField}, $params{ElevField},
-			$params{callback}, $params{callback_data});
-	return $layer;
-    }
-    sub FillNodata {
-      croak 'usage: Geo::GDAL::Band->FillNodata($mask)' unless blessed($_[1]) and $_[1]->isa('Geo::GDAL::Band');
-      $_[2] = 10 unless defined $_[2];
-      $_[3] = 0 unless defined $_[3];
-      $_[4] = undef unless defined $_[4];
-      $_[5] = undef unless defined $_[5];
-      $_[6] = undef unless defined $_[6];
-      Geo::GDAL::FillNodata(@_);
-    }
-    *GetBandNumber = *GetBand;
-
-    package Geo::GDAL::ColorTable;
-    use strict;
-    use vars qw/
-	%PALETTE_INTERPRETATION_STRING2INT %PALETTE_INTERPRETATION_INT2STRING
-	/;
-    for my $string (qw/Gray RGB CMYK HLS/) {
-	my $int = eval "\$Geo::GDAL::Constc::GPI_$string";
-	$PALETTE_INTERPRETATION_STRING2INT{$string} = $int;
-	$PALETTE_INTERPRETATION_INT2STRING{$int} = $string;
-    }
-    sub create {
-	my($pkg, $pi) = @_;
-	$pi = $PALETTE_INTERPRETATION_STRING2INT{$pi} if defined $pi and exists $PALETTE_INTERPRETATION_STRING2INT{$pi};
-	my $self = Geo::GDALc::new_ColorTable($pi);
-	bless $self, $pkg if defined($self);
-    }
-    sub GetPaletteInterpretation {
-	my $self = shift;
-	return $PALETTE_INTERPRETATION_INT2STRING{GetPaletteInterpretation($self)};
-    }
-    sub SetColorEntry {
-	@_ == 3 ? _SetColorEntry(@_) : _SetColorEntry(@_[0..1], [@_[2..5]]);
-    }
-    sub ColorEntry {
-	my $self = shift;
-	my $index = shift;
-	SetColorEntry($self, $index, @_) if @_ > 0;
-	GetColorEntry($self, $index) if defined wantarray;
-    }
-    sub ColorTable {
-	my $self = shift;
-	my @table;
-	if (@_) {
-	    my $index = 0;
-	    for my $color (@_) {
-		push @table, [ColorEntry($self, $index, @$color)];
-		$index++;
-	    }
-	} else {
-	    for (my $index = 0; $index < GetCount($self); $index++) {
-		push @table, [ColorEntry($self, $index)];
-	    }
-	}
-	return @table;
-    }
-    *ColorEntries = *ColorTable;
-
-    package Geo::GDAL::RasterAttributeTable;
-    use strict;
-    use vars qw/ %BANDS
-	%FIELD_TYPE_STRING2INT %FIELD_TYPE_INT2STRING
-	%FIELD_USAGE_STRING2INT %FIELD_USAGE_INT2STRING
-	/;
-    for my $string (qw/Integer Real String/) {
-	my $int = eval "\$Geo::GDAL::Constc::GFT_$string";
-	$FIELD_TYPE_STRING2INT{$string} = $int;
-	$FIELD_TYPE_INT2STRING{$int} = $string;
-    }
-    for my $string (qw/Generic PixelCount Name Min Max MinMax 
-		    Red Green Blue Alpha RedMin 
-		    GreenMin BlueMin AlphaMin RedMax GreenMax BlueMax AlphaMax 
-		    MaxCount/) {
-	my $int = eval "\$Geo::GDAL::Constc::GFU_$string";
-	$FIELD_USAGE_STRING2INT{$string} = $int;
-	$FIELD_USAGE_INT2STRING{$int} = $string;
-    }
-    sub FieldTypes {
-	return keys %FIELD_TYPE_STRING2INT;
-    }
-    sub FieldUsages {
-	return keys %FIELD_USAGE_STRING2INT;
-    }
-    sub RELEASE_PARENTS {
-	my $self = shift;
-	delete $BANDS{$self};
-    }
-    sub GetUsageOfCol {
-	my($self, $col) = @_;
-	$FIELD_USAGE_INT2STRING{_GetUsageOfCol($self, $col)};
-    }
-    sub GetColOfUsage {
-	my($self, $usage) = @_;
-	_GetColOfUsage($self, $FIELD_USAGE_STRING2INT{$usage});
-    }
-    sub GetTypeOfCol {
-	my($self, $col) = @_;
-	$FIELD_TYPE_INT2STRING{_GetTypeOfCol($self, $col)};
-    }
-    sub Columns {
-	my $self = shift;
-	my %columns;
-	if (@_) { # create columns
-	    %columns = @_;
-	    for my $name (keys %columns) {
-		$self->CreateColumn($name, $columns{$name}{Type}, $columns{$name}{Usage});
-	    }
-	}
-	%columns = ();
-	for my $c (0..$self->GetColumnCount-1) {
-	    my $name = $self->GetNameOfCol($c);
-	    $columns{$name}{Type} = $self->GetTypeOfCol($c);
-	    $columns{$name}{Usage} = $self->GetUsageOfCol($c);
-	}
-	return %columns;
-    }
-    sub CreateColumn {
-	my($self, $name, $type, $usage) = @_;
-	_CreateColumn($self, $name, $FIELD_TYPE_STRING2INT{$type}, $FIELD_USAGE_STRING2INT{$usage});
-    }
-    sub Value {
-	my($self, $row, $column) = @_;
-	SetValueAsString($self, $row, $column, $_[3]) if defined $_[3];
-	return unless defined wantarray;
-	GetValueAsString($self, $row, $column);
-    }
-    sub LinearBinning {
-	my $self = shift;
-	SetLinearBinning($self, @_) if @_ > 0;
-	return unless defined wantarray;
-	my @a = GetLinearBinning($self);
-	return $a[0] ? ($a[1], $a[2]) : ();
-    }
-
- 1;
+1;
diff --git a/swig/perl/lib/Geo/GDAL/Const.dox b/swig/perl/lib/Geo/GDAL/Const.dox
deleted file mode 100644
index 089de8e..0000000
--- a/swig/perl/lib/Geo/GDAL/Const.dox
+++ /dev/null
@@ -1,274 +0,0 @@
-## @ignore Geo::GDAL::Constc
-
-## @class Geo::GDAL::Const
-
-## @ignore TIEHASH
-## @ignore CLEAR
-## @ignore FIRSTKEY
-## @ignore NEXTKEY
-## @ignore FETCH
-## @ignore STORE
-## @ignore this
-
-## @attr GDT_Unknown
-# @deprecated use string 'Unknown' instead for data type
-
-## @attr GDT_Byte
-# @deprecated use string 'Byte' instead for data type
-
-## @attr GDT_UInt16
-# @deprecated use string 'UInt16' instead for data type
-
-## @attr GDT_Int16
-# @deprecated use string 'Int16' instead for data type
-
-## @attr GDT_UInt32
-# @deprecated use string 'UInt32' instead for data type
-
-## @attr GDT_Int32
-# @deprecated use string 'Int32' instead for data type
-
-## @attr GDT_Float32
-# @deprecated use string 'Float32' instead for data type
-
-## @attr GDT_Float64
-# @deprecated use string 'Float64' instead for data type
-
-## @attr GDT_CInt16
-# @deprecated use string 'CInt16' instead for data type
-
-## @attr GDT_CInt32
-# @deprecated use string 'CInt32' instead for data type
-
-## @attr GDT_CFloat32
-# @deprecated use string 'CFloat32' instead for data type
-
-## @attr GDT_CFloat64
-# @deprecated use string 'CFloat64' instead for data type
-
-## @ignore GDT_TypeCount
-
-## @attr GA_ReadOnly
-# @deprecated use string 'ReadOnly' instead for access
-
-## @attr GA_Update
-# @deprecated use string 'Update' instead for access
-
-## @ignore GF_Read
-
-## @ignore GF_Write
-
-## @attr GCI_Undefined
-# @deprecated use string 'Undefined' for color interpretation
-
-## @attr GCI_GrayIndex
-# @deprecated use string 'GrayIndex' for color interpretation
-
-## @attr GCI_PaletteIndex
-# @deprecated use string 'PaletteIndex' for color interpretation
-
-## @attr GCI_RedBand
-# @deprecated use string 'RedBand' for color interpretation
-
-## @attr GCI_GreenBand
-# @deprecated use string 'GreenBand' for color interpretation
-
-## @attr GCI_BlueBand
-# @deprecated use string 'BlueBand' for color interpretation
-
-## @attr GCI_AlphaBand
-# @deprecated use string 'AlphaBand' for color interpretation
-
-## @attr GCI_HueBand
-# @deprecated use string 'HueBand' for color interpretation
-
-## @attr GCI_SaturationBand
-# @deprecated use string 'SaturationBand' for color interpretation
-
-## @attr GCI_LightnessBand
-# @deprecated use string 'LightnessBand' for color interpretation
-
-## @attr GCI_CyanBand
-# @deprecated use string 'CyanBand' for color interpretation
-
-## @attr GCI_MagentaBand
-# @deprecated use string 'MagentaBand' for color interpretation
-
-## @attr GCI_YellowBand
-# @deprecated use string 'YellowBand' for color interpretation
-
-## @attr GCI_BlackBand
-# @deprecated use string 'BlackBand' for color interpretation
-
-## @attr GRA_NearestNeighbour
-# @deprecated use string 'NearestNeighbour' for resampling method
-
-## @attr GRA_Bilinear
-# @deprecated use string 'Bilinear' for resampling method
-
-## @attr GRA_Cubic
-# @deprecated use string 'CubicSpline' for resampling method
-
-## @attr GRA_CubicSpline
-# @deprecated use string 'CubicSpline' for resampling method
-
-## @attr GPI_Gray
-# @deprecated use string 'Gray' for palette interpretation
-
-## @attr GPI_RGB
-# @deprecated use string 'RGB' for palette interpretation
-
-## @attr GPI_CMYK
-# @deprecated use string 'CMYK' for palette interpretation
-
-## @attr GPI_HLS
-# @deprecated use string 'HLS' for palette interpretation
-
-## @attr CXT_Element
-# @deprecated use string 'Element' for XML node type
-
-## @attr CXT_Text
-# @deprecated use string 'Text' for XML node type
-
-## @attr CXT_Attribute
-# @deprecated use string 'Attribute' for XML node type
-
-## @attr CXT_Comment
-# @deprecated use string 'Comment' for XML node type
-
-## @attr CXT_Literal
-# @deprecated use string 'Literal' for XML node type
-
-## @ignore CE_None
-
-## @ignore CE_Debug
-
-## @ignore CE_Warning
-
-## @ignore CE_Failure
-
-## @ignore CE_Fatal
-
-## @ignore CPLE_None
-
-## @ignore CPLE_AppDefined
-
-## @ignore CPLE_OutOfMemory
-
-## @ignore CPLE_FileIO
-
-## @ignore CPLE_OpenFailed
-
-## @ignore CPLE_IllegalArg
-
-## @ignore CPLE_NotSupported
-
-## @ignore CPLE_AssertionFailed
-
-## @ignore CPLE_NoWriteAccess
-
-## @ignore CPLE_UserInterrupt
-
-## @ignore DMD_LONGNAME
-
-## @ignore DMD_HELPTOPIC
-
-## @ignore DMD_MIMETYPE
-
-## @ignore DMD_EXTENSION
-
-## @ignore DMD_CREATIONOPTIONLIST
-
-## @ignore DMD_CREATIONDATATYPES
-
-## @ignore DCAP_CREATE
-
-## @ignore DCAP_CREATECOPY
-
-## @ignore CPLES_BackslashQuotable
-
-## @ignore CPLES_XML
-
-## @ignore CPLES_URL
-
-## @ignore CPLES_SQL
-
-## @ignore CPLES_CSV
-
-## @attr GFT_Integer
-# @deprecated use 'Integer' for raster attribute table field type
-
-## @attr GFT_Real
-# @deprecated use 'Real' for raster attribute table field type
-
-## @attr GFT_String
-# @deprecated use 'String' for raster attribute table field type
-
-## @attr GFU_Generic
-# @deprecated use 'Generic' for raster attribute table field usage
-
-## @attr GFU_Alpha
-# @deprecated use 'Alpha' for raster attribute table field usage
-
-## @attr GFU_AlphaMax
-# @deprecated use 'AlphaMax' for raster attribute table field usage
-
-## @attr GFU_AlphaMin
-# @deprecated use 'AlphaMin' for raster attribute table field usage
-
-## @attr GFU_Blue
-# @deprecated use 'Blue' for raster attribute table field usage
-
-## @attr GFU_BlueMax
-# @deprecated use 'BlueMax' for raster attribute table field usage
-
-## @attr GFU_BlueMin
-# @deprecated use 'BlueMin' for raster attribute table field usage
-
-## @attr GFU_Green
-# @deprecated use 'Green' for raster attribute table field usage
-
-## @attr GFU_GreenMax
-# @deprecated use 'GreenMax' for raster attribute table field usage
-
-## @attr GFU_GreenMin
-# @deprecated use 'GreenMin' for raster attribute table field usage
-
-## @attr GFU_Max
-# @deprecated use 'Max' for raster attribute table field usage
-
-## @attr GFU_Min
-# @deprecated use 'Min' for raster attribute table field usage
-
-## @attr GFU_MinMax
-# @deprecated use 'MinMax' for raster attribute table field usage
-
-## @attr GFU_MaxCount
-# @deprecated use 'MaxCount' for raster attribute table field usage
-
-## @attr GFU_Name
-# @deprecated use 'Name' for raster attribute table field usage
-
-## @attr GFU_PixelCount
-# @deprecated use 'PixelCount' for raster attribute table field usage
-
-## @attr GFU_Red
-# @deprecated use 'Red' for raster attribute table field usage
-
-## @attr GFU_RedMax
-# @deprecated use 'RedMax' for raster attribute table field usage
-
-## @attr GFU_RedMin
-# @deprecated use 'RedMin' for raster attribute table field usage
-
-## @attr GMF_ALL_VALID
-# a mask band flag
-
-## @attr GMF_ALPHA
-# a mask band flag
-
-## @attr GMF_NODATA
-# a mask band flag
-
-## @attr GMF_PER_DATASET
-# a mask band flag
diff --git a/swig/perl/lib/Geo/GDAL/Const.pm b/swig/perl/lib/Geo/GDAL/Const.pm
index 1fa2f7b..e050e7a 100644
--- a/swig/perl/lib/Geo/GDAL/Const.pm
+++ b/swig/perl/lib/Geo/GDAL/Const.pm
@@ -71,6 +71,14 @@ package Geo::GDAL::Const;
 *GA_Update = *Geo::GDAL::Constc::GA_Update;
 *GF_Read = *Geo::GDAL::Constc::GF_Read;
 *GF_Write = *Geo::GDAL::Constc::GF_Write;
+*GRIORA_NearestNeighbour = *Geo::GDAL::Constc::GRIORA_NearestNeighbour;
+*GRIORA_Bilinear = *Geo::GDAL::Constc::GRIORA_Bilinear;
+*GRIORA_Cubic = *Geo::GDAL::Constc::GRIORA_Cubic;
+*GRIORA_CubicSpline = *Geo::GDAL::Constc::GRIORA_CubicSpline;
+*GRIORA_Lanczos = *Geo::GDAL::Constc::GRIORA_Lanczos;
+*GRIORA_Average = *Geo::GDAL::Constc::GRIORA_Average;
+*GRIORA_Mode = *Geo::GDAL::Constc::GRIORA_Mode;
+*GRIORA_Gauss = *Geo::GDAL::Constc::GRIORA_Gauss;
 *GCI_Undefined = *Geo::GDAL::Constc::GCI_Undefined;
 *GCI_GrayIndex = *Geo::GDAL::Constc::GCI_GrayIndex;
 *GCI_PaletteIndex = *Geo::GDAL::Constc::GCI_PaletteIndex;
@@ -119,16 +127,32 @@ package Geo::GDAL::Const;
 *CPLE_AssertionFailed = *Geo::GDAL::Constc::CPLE_AssertionFailed;
 *CPLE_NoWriteAccess = *Geo::GDAL::Constc::CPLE_NoWriteAccess;
 *CPLE_UserInterrupt = *Geo::GDAL::Constc::CPLE_UserInterrupt;
+*OF_ALL = *Geo::GDAL::Constc::OF_ALL;
+*OF_RASTER = *Geo::GDAL::Constc::OF_RASTER;
+*OF_VECTOR = *Geo::GDAL::Constc::OF_VECTOR;
+*OF_READONLY = *Geo::GDAL::Constc::OF_READONLY;
+*OF_UPDATE = *Geo::GDAL::Constc::OF_UPDATE;
+*OF_SHARED = *Geo::GDAL::Constc::OF_SHARED;
+*OF_VERBOSE_ERROR = *Geo::GDAL::Constc::OF_VERBOSE_ERROR;
 *DMD_LONGNAME = *Geo::GDAL::Constc::DMD_LONGNAME;
 *DMD_HELPTOPIC = *Geo::GDAL::Constc::DMD_HELPTOPIC;
 *DMD_MIMETYPE = *Geo::GDAL::Constc::DMD_MIMETYPE;
 *DMD_EXTENSION = *Geo::GDAL::Constc::DMD_EXTENSION;
+*DMD_EXTENSIONS = *Geo::GDAL::Constc::DMD_EXTENSIONS;
+*DMD_CONNECTION_PREFIX = *Geo::GDAL::Constc::DMD_CONNECTION_PREFIX;
 *DMD_CREATIONOPTIONLIST = *Geo::GDAL::Constc::DMD_CREATIONOPTIONLIST;
 *DMD_CREATIONDATATYPES = *Geo::GDAL::Constc::DMD_CREATIONDATATYPES;
+*DMD_CREATIONFIELDDATATYPES = *Geo::GDAL::Constc::DMD_CREATIONFIELDDATATYPES;
 *DMD_SUBDATASETS = *Geo::GDAL::Constc::DMD_SUBDATASETS;
+*DCAP_OPEN = *Geo::GDAL::Constc::DCAP_OPEN;
 *DCAP_CREATE = *Geo::GDAL::Constc::DCAP_CREATE;
 *DCAP_CREATECOPY = *Geo::GDAL::Constc::DCAP_CREATECOPY;
 *DCAP_VIRTUALIO = *Geo::GDAL::Constc::DCAP_VIRTUALIO;
+*DCAP_RASTER = *Geo::GDAL::Constc::DCAP_RASTER;
+*DCAP_VECTOR = *Geo::GDAL::Constc::DCAP_VECTOR;
+*DCAP_NOTNULL_FIELDS = *Geo::GDAL::Constc::DCAP_NOTNULL_FIELDS;
+*DCAP_DEFAULT_FIELDS = *Geo::GDAL::Constc::DCAP_DEFAULT_FIELDS;
+*DCAP_NOTNULL_GEOMFIELDS = *Geo::GDAL::Constc::DCAP_NOTNULL_GEOMFIELDS;
 *CPLES_BackslashQuotable = *Geo::GDAL::Constc::CPLES_BackslashQuotable;
 *CPLES_XML = *Geo::GDAL::Constc::CPLES_XML;
 *CPLES_URL = *Geo::GDAL::Constc::CPLES_URL;
diff --git a/swig/perl/lib/Geo/OGR.dox b/swig/perl/lib/Geo/OGR.dox
index 29cf3ab..a4bd5d9 100644
--- a/swig/perl/lib/Geo/OGR.dox
+++ b/swig/perl/lib/Geo/OGR.dox
@@ -1,16 +1,18 @@
-## @ignore Geo::OGRc
-
 ## @class Geo::OGR
+# @brief OGR utility functions.
+#
+# A wrapper for many OGR utility functions and a root class for all
+# OGR classes.
 
-## @ignore TIEHASH
-## @ignore CLEAR
-## @ignore FIRSTKEY
-## @ignore NEXTKEY
-## @ignore FETCH
-## @ignore STORE
-## @ignore this
+## @ignore TermProgress
+## @ignore TermProgress_nocb
 
 ## @ignore BuildPolygonFromEdges
+
+## @ignore ApproximateArcAngles
+
+## @ignore ForceTo
+## @ignore ForceToLineString
 ## @ignore ForceToMultiLineString
 ## @ignore ForceToMultiPoint
 ## @ignore ForceToMultiPolygon
@@ -20,131 +22,88 @@
 ## @ignore GeometryTypeToName
 ## @ignore GetFieldTypeName
 
-## @ignore UseExceptions()
-## @ignore DontUseExceptions()
+## @ignore GeometryType
+## @ignore GetFieldSubTypeName
+
+## @cmethod @GeometryTypes()
+# @return a list of all geometry types, currently:
+# +list Geo::OGR wkb 25DBit,25Bit,NDR,XDR
+
+## @cmethod list ByteOrders
+# @return a list of byte order types, XDR and NDR. XDR denotes
+# big-endian and NDR denotes little-endian.
 
-## @fn @GeometryTypes()
-# @return a list of all geometry types.
+## @method $GeometryTypeModify($type, $modifier)
+# @param type a geometry type (one of Geo::OGR::GeometryTypes).
+# @param modifier one of 'flatten', 'set_Z', 'make_collection', 'make_curve', or 'make_linear'.
+# @return modified geometry type.
+
+## @method $GeometryTypeTest($type, $test, $type2)
+# @param type a geometry type (one of Geo::OGR::GeometryTypes).
+# @param test one of 'has_z', 'is_subclass_of', 'is_curve', 'is_surface', or 'is_non_linear'.
+# @param type2 a geometry type (one of Geo::OGR::GeometryTypes). Required for 'is_subclass_of' test.
+# @return result of the test.
 
 ## @ignore CreateGeometryFromWkb
 ## @ignore CreateGeometryFromWkt
 ## @ignore CreateGeometryFromGML
 ## @ignore CreateGeometryFromJson
-## @ignore ApproximateArcAngles
 
-## @fn @Drivers()
-# @return a list of Geo::OGR::Driver objects, one for each OGR format.
+## @ignore Drivers
+## @ignore GetDriverCount
+## @ignore GetDriverByName
+## @ignore Driver
+
+## @method @GetDriverNames()
+# @return a list of the names of available Geo::OGR::Drivers.
 
-## @fn $GetDriverCount()
-# @return the number of all available drivers.
+## @method Geo::OGR::Driver GetDriver($name)
+# @param name a driver name. One of Geo::OGR::GetDriverNames.
+# @return a Geo::OGR::Driver object that represents the internal driver.
 
-## @fn $GetOpenDSCount()
+## @method $GetOpenDSCount()
 # @return the number of all open data sources.
 
-## @fn SetGenerate_DB2_V72_BYTE_ORDER($Generate_DB2_V72_BYTE_ORDER)
+## @method SetGenerate_DB2_V72_BYTE_ORDER($Generate_DB2_V72_BYTE_ORDER)
 # Needed only on IBM DB2.
 
-## @ignore RegisterAll()
-# Called in initialization.
-
-## @fn Geo::OGR::DataSource GetOpenDS($number)
+## @method Geo::OGR::DataSource GetOpenDS($number)
 # @param number The number of the requested data source.
 # @return a new Geo::OGR::DataSource object.
 
-## @fn Geo::OGR::DataSource Open($name, $update = 0)
+## @method Geo::OGR::DataSource Open($name, $update = 0)
 # @param name The data source string (directory, filename, etc.).
 # @param update Whether to open the data source in update mode.
 # @return a new Geo::OGR::DataSource object.
 
-## @fn Geo::OGR::DataSource OpenShared($name, $update = 0)
+## @method Geo::OGR::DataSource OpenShared($name, $update = 0)
 # @param name The data source string (directory, filename, etc.).
 # @param update Whether to open the data source in update mode.
 # @return a new Geo::OGR::DataSource object.
 
-## @fn Geo::OGR::Driver GetDriverByName($name)
-# @param name
-# @return a new Geo::OGR::Driver object.
+## @ignore NullFID
+
 
-## @fn Geo::OGR::Driver Driver($driver) 
-# Create a driver object for the internal OGR driver.
-# @note a.k.a. GetDriver
-# @param driver the index or the name of the driver
-# @return a new Geo::OGR::Driver object
 
-## @ignore NullFID
-## @ignore wkb25Bit
-## @ignore wkb25DBit
-## @ignore wkbUnknown
-## @ignore wkbPoint
-## @ignore wkbLineString
-## @ignore wkbPolygon
-## @ignore wkbMultiPoint
-## @ignore wkbMultiLineString
-## @ignore wkbMultiPolygon
-## @ignore wkbGeometryCollection
-## @ignore wkbNone
-## @ignore wkbLinearRing
-## @ignore wkbPoint25D
-## @ignore wkbLineString25D
-## @ignore wkbPolygon25D
-## @ignore wkbMultiPoint25D
-## @ignore wkbMultiLineString25D
-## @ignore wkbMultiPolygon25D
-## @ignore wkbGeometryCollection25D
-## @ignore OFTInteger
-## @ignore OFTIntegerList
-## @ignore OFTReal
-## @ignore OFTRealList
-## @ignore OFTString
-## @ignore OFTStringList
-## @ignore OFTWideString
-## @ignore OFTWideStringList
-## @ignore OFTBinary
-## @ignore OFTDate
-## @ignore OFTTime
-## @ignore OFTDateTime
-## @ignore OJUndefined
-## @ignore OJLeft
-## @ignore OJRight
-## @ignore wkbXDR
-## @ignore wkbNDR
-## @ignore OLCRandomRead
-## @ignore OLCSequentialWrite
-## @ignore OLCRandomWrite
-## @ignore OLCFastSpatialFilter
-## @ignore OLCFastFeatureCount
-## @ignore OLCFastGetExtent
-## @ignore OLCCreateField
-## @ignore OLCTransactions
-## @ignore OLCDeleteFeature
-## @ignore OLCFastSetNextByIndex
-## @ignore OLCAlterFieldDefn
-## @ignore OLCDeleteField
-## @ignore OLCIgnoreFields
-## @ignore OLCReorderFields
-## @ignore OLCStringsAsUTF8
-## @ignore ODsCCreateLayer
-## @ignore ODsCDeleteLayer
-## @ignore ODrCCreateDataSource
-## @ignore ODrCDeleteDataSource
 
 ## @class Geo::OGR::Driver
+# @brief A vector format driver.
+#
+# A driver may, depending on its capabilities, create, open, copy, and
+# delete data sources.
 # @isa (Geo::OGR)
 
-## @attr list CAPABILITIES
-# Driver capabilities known to GDAL
-
 ## @ignore Register
 ## @ignore Deregister
 
-## @attr name
-# scalar (access as $driver->{name})
-
-## @cmethod @Capabilities()
-# @return a list of capabilities. The class method returns a list of
-# all potential capabilities a driver may have; the object method
-# returns a list of all capabilities the driver has.
-# Examples.
+## @method @Capabilities()
+# Both a class and an object method.
+# @return a list of capabilities. The object method returns a list of
+# the capabilities the driver has. The class method returns a list of
+# all potential capabilities a driver may have. These are currently:
+# +list Geo::OGR ODrC
+#
+# Examples:
 # \code
 # @all_capabilities = Geo::OGR::Driver::Capabilities;
 # @capabilities_of_a_driver = Geo::OGR::Driver('KML')->Capabilities;
@@ -156,7 +115,7 @@
 
 ## @ignore CreateDataSource
 
-## @method Geo::OGR::DataSource Create($name, \%options = undef )
+## @method Geo::OGR::DataSource Create($name, hashref options = undef )
 # Create an OGR data source object.
 # @note a.k.a. CreateDataSource
 # @param name The data source name.
@@ -170,18 +129,21 @@
 
 ## @ignore CopyDataSource
 
-## @method Geo::OGR::DataSource Copy($ds, $name, \@options = undef)
+## @method Geo::OGR::DataSource Copy(Geo::OGR::DataSource source, $name, arrayref options = undef)
 # Copy an OGR data source object.
 # @note a.k.a. CopyDataSource
-# @param ds The Geo::OGR::DataSource object to be copied.
-# @param name The name for the new data source.
-# @param options Driver specific options.
+# @param source the Geo::OGR::DataSource object to be copied.
+# @param name the name for the new data source.
+# @param options driver specific options.
 # @return a new Geo::OGR::DataSource object.
 
+## @ignore OpenDataSource
+
 ## @method Geo::OGR::DataSource Open($name, $update = 0)
 # Open an OGR data source object. Alternative name: OpenDataSource.
-# @param name The name of data source.
-# @param update Whether to open the data source in update mode.
+# @note a.k.a. GetDataSource
+# @param name the name of data source.
+# @param update whether to open the data source in update mode.
 # @return a new Geo::OGR::DataSource object
 
 ## @ignore DeleteDataSource
@@ -191,26 +153,31 @@
 # @note a.k.a. DeleteDataSource
 # @param name The name of data source.
 
+## @ignore GetName
+
 ## @method $Name()
 # @note a.k.a. GetName
 # @return the name of the driver.
 
 
+
+
 ## @class Geo::OGR::DataSource
+# @brief A source and/or storage of vector data layers.
+#
+# A data source object may, depending on its capabilities, create,
+# open (as such or using GDAL SQL), copy, and delete layers.
 # @isa (Geo::OGR)
 
-## @attr list CAPABILITIES
-# Data source capabilities known to GDAL
-
 ## @ignore SyncToDisk
 
-## @attr name
-# string (access as $datasource->{name})
-
-## @cmethod @Capabilities()
-# @return a list of capabilities. The class method returns a list of
-# all potential capabilities a data source may have; the object method
-# returns a list of all capabilities the data source has.
+## @method @Capabilities()
+# Both a class and an object method.
+# @return a list of capabilities. The object method returns a list of
+# all capabilities the data source has. The class method returns a
+# list of all potential capabilities a data source may have. These are
+# currently:
+# +list Geo::OGR ODsC
 
 ## @method $TestCapability($cap)
 # @param cap A capability string.
@@ -232,16 +199,22 @@
 # @param update Whether to open the data source in update mode.
 # @return a new Geo::OGR::DataSource object.
 
-## @method Geo::OGR::Layer Layer($layer = 0)
-# @param layer a name (primary) or index (secondary) of the requested
-# layer. If not given, then returns the first layer.
-# @return a new Geo::OGR::Layer object
+## @ignore GetLayerByIndex
+## @ignore GetLayerByName
+## @ignore Layer
+
+## @method Geo::OGR::Layer GetLayer($name)
+# @param name the name of the requested layer. If not given, then
+# returns the first layer in the data source.
+# @return a new Geo::OGR::Layer object that represents the layer
+# in the data source.
 
-## @method @Layers()
-# @return a list of layers this data source provides.
+## @ignore GetLayerCount
+## @ignore Layers
 
-## @method $GetLayerCount()
-# @return the number of layers this data source provides.
+## @method @GetLayerNames()
+# @note Delivers the functionality of undocumented method GetLayerCount.
+# @return a list of the names of the layers this data source provides.
 
 ## @method Geo::OGR::Driver GetDriver()
 # @return a Geo::OGR::Driver object for this data source.
@@ -249,135 +222,242 @@
 ## @method $GetName()
 # @return the name of this data source.
 
-## @method Geo::OGR::Layer CreateLayer($Name, $SRS = undef, $GeometryType = 'Unknown', \%Options = undef, \%Schema = undef)
-# @note This method can also be used with named parameters: $ds->CreateLayer({parameter=>value, ...}).
+## @method Geo::OGR::Layer CreateLayer(%params)
+# @brief Create a new layer into this data source.
+#
+# @param %params A list of named parameters:
+# - \a Name (scalar) name for the new layer.
+# - \a Fields (array reference) a list of field definitions as in 
+# Geo::OGR::Layer::CreateField.
+# - \a ApproxOK (boolean value, default is true) a flag, which is forwarded to Geo::OGR::Layer::CreateField.
+# - \a Options (hash reference) driver specific hash of layer creation options.
+# - \a Schema (hash reference, deprecated) may contain keys Name, Fields, GeomFields, GeometryType.
+# - \a SRS (scalar, deprecated) the spatial reference for the default geometry field.
+# - \a GeometryType (scalar) the type of the default geometry field (if only one geometry field).
+#
+# @note If Fields or Schema|Fields is not given, a default geometry
+# field (Name => '', GeometryType => 'Unknown') is created. The type
+# can be also set with the named parameter.
 #
 # Example:
 # \code
 # my $roads = Geo::OGR::Driver('Memory')->Create('road')->
-#     CreateLayer({GeometryType=>'LineString25D', Fields=>[{Name=>'class',Type=>'Integer'}]});
+# .   CreateLayer(
+# .       Fields => [ { Name => 'class', 
+# .                     Type => 'Integer' },
+# .                   { Name => 'geom', 
+# .                     Type => 'LineString25D' } ] );
 # \endcode
-#
-# @param Name name for the new layer.
-# @param SRS a Geo::OSR::SpatialReference object.
-# @param GeometryType one of \@Geo::OGR::Geometry::GEOMETRY_TYPES
-# @param Options a ref to a hash of format specific options.
-# @param Schema forwarded to Layer::Schema, which is called if this
-# parameter exists. Additionally, if $Schema->{GeometryType} exists,
-# it overrides $GeometryType argument and default.
-# @param Fields the fields for the schema of the layer [can be used only as a named parameter].
-# @return a new Geo::OGR::Layer object
-
-## @method Geo::OGR::Layer CopyLayer($layer, $name, \%options = undef)
+# @return a new Geo::OGR::Layer object.
+
+## @method Geo::OGR::Layer CopyLayer($layer, $name, hashref options = undef)
 # @param layer A Geo::OGR::Layer object to be copied.
 # @param name A name for the new layer.
 # @param options A ref to a hash of format specific options.
 # @return a new Geo::OGR::Layer object.
 
-## @method DeleteLayer($layer)
+## @method DeleteLayer($name)
 # Deletes a layer from the data source. Note that if there is a layer
 # object for the deleted layer, it becomes unusable.
-# @param layer name (primary) or index (secondary) of the layer to be
-# deleted, if ambiguous use named parameter syntax (name or index).
-
-## @method DeleteLayer(%param)
-# Deletes a layer from the data source. Note that if there are layers
-# objects for the deleted layer, they become unusable.
-# @param param Named parameter (name or index) for the layer to be
-# deleted.
+# @param name name of the layer to delete.
 
 ## @method Geo::OGR::Layer ExecuteSQL($statement, $geom = undef, $dialect = "")
 # @param statement A SQL statement.
 # @param geom A Geo::OGR::Geometry object.
 # @param dialect
-# @return a new Geo::OGR::Layer object.
+# @return a new Geo::OGR::Layer object. The data source object will
+# exist as long as the layer object exists.
 
 ## @method ReleaseResultSet($layer)
 # @param layer A layer the has been created with ExecuteSQL.
-
-## @method Geo::OGR::Layer GetLayerByIndex($index = 0)
-# @param index A number.
-# @return a new Geo::OGR::Layer object.
-
-## @method Geo::OGR::Layer GetLayerByName($name)
-# @param name A string.
-# @return a new Geo::OGR::Layer object.
+# @note There is no need to call this method. The result set layer is
+# released in the destructor of the layer that was created with SQL.
 
 ## @ignore GetRefCount
-
 ## @ignore GetSummaryRefCount
 
 
+
+
 ## @class Geo::OGR::Layer
+# @brief A collection of similar features.
+#
+# A layer object is typically obtained with a data source object. A
+# layer has a data model (a schema), which is maintained in a
+# definition object, and a set of features, which contain data
+# according to the data model. The schema is typically set when the
+# layer is created or opened, but it may be altered somewhat with
+# methods Geo::OGR::Layer::CreateField,
+# Geo::OGR::Layer::AlterFieldDefn, and
+# Geo::OGR::Layer::DeleteField. Features and/or their data can be
+# read, inserted and deleted. Reading can be filtered. Layers can be
+# compared to each other with methods Clip, Erase, Identity,
+# Intersection, SymDifference, Union, and Update.
 # @isa (Geo::OGR)
 
-## @attr list CAPABILITIES
-# Layer capabilities known to GDAL
-
-## @cmethod @Capabilities()
+## @method @Capabilities()
+# Both a class and an object method.
+# @return a list of capabilities. The object method returns a list of
+# the capabilities the layer has. The class method returns a list of
+# all potential capabilities a layer may have. These are currently:
+# +list Geo::OGR OLC
+#
 # Examples:
 # \code
 # @cap = Geo::OGR::Layer::Capabilities(); # the class method
 # @cap = $layer->Capabilities(); # the object method
 # \endcode
-# @return a list of capabilities. The class method returns a list of
-# all potential capabilities a layer may have. The object method
-# returns a list of all capabilities the layer has.
+
+## @method Clip(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# Clip off areas that are not covered by the method layer. The schema
+# of the result layer can be set before calling this method, or is
+# initialized to to contain all fields from
+# this and method layer.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method Intersection(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are common between features in the input layer and in the
+# method layer. The schema of the result layer can be set before
+# calling this method, or is initialized to contain all fields from
+# this and method layer.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method Union(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are in either in the input layer or in the method layer. The
+# schema of the result layer can be set before calling this method, or
+# is initialized to contain all fields from this and method layer.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method SymDifference(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are in either in the input layer or in the method layer but not
+# in both. The features in the result layer have attributes from both
+# input and method layers. For features which represent areas that are
+# only in the input or in the method layer the respective attributes
+# have undefined values. The schema of the result layer can be set by
+# the user or, if it is empty, is initialized to contain all fields in
+# the input and method layers.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method Identity(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are in the input layer. The features in the result layer have
+# attributes from both input and method layers. The schema of the
+# result layer can be set by the user or, if it is empty, is
+# initialized to contain all fields in input and method layers.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method Update(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are either in the input layer or in the method layer. The
+# features in the result layer have areas of the features of the
+# method layer or those ares of the features of the input layer that
+# are not covered by the method layer. The features of the result
+# layer get their attributes from the input layer. The schema of the
+# result layer can be set by the user or, if it is empty, is
+# initialized to contain all fields in the input layer.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
+
+## @method Erase(Geo::OGR::Layer method, Geo::OGR::Layer result, hashref options, subref callback, $callback_data)
+# The result layer contains features whose geometries represent areas
+# that are in the input layer but not in the method layer. The
+# features in the result layer have attributes from the input
+# layer. The schema of the result layer can be set by the user or, if
+# it is empty, is initialized to contain all fields in the input
+# layer.
+# @param method method layer.
+# @param result result layer.
+# @param options a reference to an options hash.
+# @param callback [optional] a reference to a subroutine, which will
+# be called with parameters (number progress, string msg, callback_data)
+# @param callback_data [optional]
 
 ## @method $TestCapability($cap)
 # @param cap A capability string.
 # @return a boolean value indicating whether the layer has the
 # specified capability.
 
-## @method Geo::OGR::DataSource DataSource()
+## @method Geo::OSR::SpatialReference SpatialReference($name, Geo::OSR::SpatialReference sr)
+# @note A.k.a GetSpatialRef.
+# Get or set the projection of a spatial field of this layer. Gets or
+# sets the projection of the first field if no field name is given.
+# @param name [optional] a name of a spatial field in this layer.
+# @param sr [optional] a Geo::OSR::SpatialReference object,
+# which replaces the existing projection.
+# @return a Geo::OSR::SpatialReference object, which represents the
+# projection in the given spatial field.
+
+## @method Geo::OGR::DataSource GetDataSource()
 # @return the data source object to which this layer object belongs to.
 
-## @method %GetField($field_name)
-# @param field_name the name (or index) of the field
-# @return the schema of the field in a hash (in list context) or in an
-# anonymous hash
-
-## @method CreateField(%parameters)
-# @param parameters named parameters: Name, Type, Justify, Width,
-# Precision
-
-## @method CreateField($field_definition, $approximation_ok)
-# @deprecated use CreateField(hash parameters)
-# @param field_definition a Geo::OGR::FieldDefn object
-# @param approximation_ok may the field be created in a slightly
-# different form depending on the limitations of the format driver.
-
-## @method AlterField($field_name, %new_definition)
-# @param field_name the name (or index) of the field to be altered
-# @param new_definition one or more of Name, Type, and Width
-
-## @method AlterFieldDefn($field, $definition, $flags)
-# @deprecated use AlterField(scalar name, hash parameters)
-# Alter the definition of an existing field on a layer.
-# @param field index of the field whose definition is altered
-# @param definition a Geo::OGR::FieldDefn object
-# @param flags 1 to alter the name, 2 to alter the type, 4 to alter
-# the width, use combinations 3, 5, 6 or 7 to alter two or more
-# properties
+## @ignore FindFieldIndex
+
+## @method %GetFieldDefn($name)
+# Get the definition of a field.
+# @param name the name of the field.
+# @return the field definition object, either Geo::OGR::FieldDefn or
+# Geo::OGR::GeomFieldDefn.
+
+## @ignore CreateGeomField
+
+## @method CreateField(%params)
+# Create a field.
+# @param params as in Geo::OGR::FieldDefn::create or
+# Geo::OGR::GeomFieldDefn::create, plus ApproxOK (whose default is true).
+
+## @method AlterFieldDefn($name, %params)
+# @param field the name of the field to be altered.
+# @param params as in Geo::OGR::FieldDefn::create. Width and
+# Precision should be both or neither.
+# @note Only non-spatial fields can be altered.
+# @note Also the deprecated form AlterFieldDefn($field,
+# Geo::OGR::FieldDefn $Defn, $Flags) works.
 
 ## @method DeleteField($field)
 # Delete an existing field from a layer.
 # @param field name (or index) of the field which is deleted
+# @note Only non-spatial fields can be deleted.
+
+## @ignore Schema
 
-## @method \%Schema(%schema)
-# Get and/or set the schema of the layer.
-# @param schema The schema hash may contain the keys:
-# - \a Fields A reference to a list of field definitions (either
-# Geo::OGR::FieldDefn objects or hashrefs from which they can be
-# created).
-# - \a ApproxOK (optional) A flag specifying whether it is ok to
-# change the requested field definition to accommodate limitations of
-# the layer.
-# @return a reference to a schema hash, which has keys:
-# - \a Name The name of this layer.
-# - \a GeometryType The type of the geometries in this layer (a
-# string).
-# - \a Fields An array of references to hashes of field definitions.
+## @method \%GetSchema()
+# @brief Get the schema of this layer.
+# @note The schema of a layer cannot be set with this method.  If you
+# have a Geo::OGR::FeatureDefn object before creating the layer, use
+# its schema in the Geo::OGR::CreateLayer method.
+# @return the schema of this layer, as in Geo::OGR::FeatureDefn::Schema.
 
 ## @method \%Row(%row)
 # Get and/or set the data of a feature that has the supplied feature
@@ -389,8 +469,8 @@
 ## @method @Tuple(@tuple)
 # Get and/set the data of a feature that has the supplied feature id
 # (the next feature obtained with GetNextFeature is used if feature id
-# is not given). The order of the data in the tuple is: feature id,
-# Geometry, fields in their order. Calls Geo::OGR::Feature::Tuple.
+# is not given). The expected data in the tuple is: ([feature id,]
+# non-spatial fields, spatial fields). Calls Geo::OGR::Feature::Tuple.
 # @param tuple [optional] feature data
 # @note The schema of the tuple needs to be the same as that of the
 # layer.
@@ -471,11 +551,11 @@
 # layer
 
 ## @method $GetName()
-# @return
+# @return the name of the layer.
 
 ## @method Geo::OGR::Feature GetFeature($fid)
 # @param fid feature id
-# @return a new Geo::OGR::Feature object
+# @return a new Geo::OGR::Feature object that represents the feature in the layer.
 
 ## @method SetFeature($feature)
 # @note The feature should have the same schema as the layer.
@@ -507,9 +587,11 @@
 
 ## @method SyncToDisk()
 
-## @method Geo::OGR::FeatureDefn GetLayerDefn()
-# @deprecated use Geo::OGR::Layer::Schema, which returns a Perl structure
-# @return a new Geo::OGR::FeatureDefn object
+## @ignore GetLayerDefn
+
+## @method Geo::OGR::FeatureDefn GetDefn()
+# A.k.a GetLayerDefn.
+# @return a Geo::OGR::FeatureDefn object.
 
 ## @method $GetFeatureCount($force = 1)
 # @param force
@@ -532,49 +614,62 @@
 
 ## @method RollbackTransaction()
 
-## @method Geo::OSR::SpatialReference GetSpatialRef()
-# @return a new Geo::OSR::SpatialReference object
+## @ignore GetSpatialRef
 
 ## @ignore GetRefCount
 
 ## @method $GetFIDColumn()
-# @return the name of the underlying database column being used as the FID column, or "" if not supported.
-
-## @method $GetGeometryColumn()
-# @return the name of the underlying database column being used as the geometry column, or "" if not supported
+# @return the name of the underlying database column being used as the
+# FID column, or "" if not supported.
 
+## @ignore GetGeometryColumn
 ## @ignore GetGeomType
 
-## @method $GeometryType()
-# @return the geometry type of the layer, one of \@Geo::OGR::Geometry::GEOMETRY_TYPES
+## @method @GetFieldNames()
+# @return a list of the names of the fields in this layer. The
+# non-geometry field names are first in the list and then the geometry
+# fields.
 
-## @ignore ReorderField
-## @ignore ReorderFields
+## @method $GetFieldDef($name)
+# @param name name of the field.
+# @return the definition object of the given field. Either
+# Geo::OGR::FieldDefn or Geo::OGR::GeomFieldDefn.
 
 ## @method SetIgnoredFields(@fields)
 # @param fields a list of field names
 
 
+
+
 ## @class Geo::OGR::Feature
+# @brief A collection of non-spatial and spatial attributes.
+#
+# A feature is a collection of non-spatial and spatial attributes and
+# an id, which is a special attribute, and data records according to
+# this data model. Attributes are called fields and some fields are
+# spatial, i.e., their value is a geometry. Fields have at least a
+# name and a type. Features may exist within a layer or
+# separetely. The data model of a feature is a definition object.
 # @isa (Geo::OGR)
 
-## @cmethod Geo::OGR::Feature new($feature_def)
-# @param feature_def a Geo::OGR::FeatureDefn object
-# @return a new Geo::OGR::Feature object
-
-## @cmethod Geo::OGR::Feature create(%schema)
+## @cmethod Geo::OGR::Feature new(%schema)
 # @param schema as in Schema
 # @return a new Geo::OGR::Feature object
 
-## @method \%Schema(%schema)
-# Get or set the schema. The schema is a hash (Name => name,
-# GeometryType => geometry_type, Fields => [list of
-# Geo::OGR::FieldDefn objects or hashrefs from which such can be
-# created]. The Name and GeometryType cannot be set and the Fields are
-# added to the schema. Fields is an array of hashrefs that
-# contain schemas of FieldDefns
-# @param schema [optional]
-# @return
+## @method $DumpReadable()
+# Write the contents of this feature to stdout.
+
+## @method $Validate(list flags)
+# @param flags one of more of null, geom_type, width,
+# allow_null_when_default, or all.
+# @exception croaks with an error message if the feature is not valid.
+# @return integer denoting the validity of the feature object.
+
+## @ignore Schema
+
+## @method \%GetSchema()
+# @brief Get the schema of this feature. 
+# @return the schema of this layer, as in Geo::OGR::FeatureDefn::Schema.
 
 ## @method \%Row(%row)
 # @note This method discards the data the destination feature (or
@@ -587,62 +682,41 @@
 # geometry is set and get using the Geo::OGR::Feature::Geometry
 # method. Field values are set using the Geo::OGR::Feature::SetField
 # method.
-# @param row [optional] feature data in a hash
-# @return a reference to feature data in a hash
+# @param row [optional] feature data in a hash.
+# @return a reference to feature data in a hash. Spatial fields are
+# returned as Geo::OGR::Geometry objects.
 
 ## @method @Tuple(@tuple)
 # @note This method discards the data the destination feature (or
 # layer) does not support. Changes in data due to differences between
 # field types may also occur.
+#
 # @note The schema of the tuple needs to be the same as that of the
 # feature.
 #
-# Get and/set the data of the feature. The order of the data in the
-# tuple is: field_id, geometry, fields in their order. The geometry is
-# set and get using the Geo::OGR::Feature::Geometry method. Field
-# values are set using the Geo::OGR::Feature::SetField method.
+# Get and/set the data of the feature. The expected data in the tuple
+# is ([feature_id,] non-spatial fields, spatial fields). The fields in
+# the order they are in the schema. Field values are set using the
+# Geo::OGR::Feature::Field method. Geometries are set and get using
+# the Geo::OGR::Feature::Geometry method.
 # @param tuple [optional] feature data in an array
 # @return feature data in an array
 
-## @method Geo::OGR::FeatureDefn GetDefnRef()
-# @return a new Geo::OGR::FeatureDefn object
+## @ignore GetDefnRef
 
-## @method Geo::OGR::FieldDefn GetFieldDefnRef($field)
-# @param field the name (or index) of the field
-# @return a new Geo::OGR::FieldDefn object
+## @method Geo::OGR::FeatureDefn GetDefn()
+# @note A.k.a GetDefnRef.
+# @return a Geo::OGR::FeatureDefn object, which represents the definition of this feature.
 
-## @method $GetFieldType($field)
-# @param field the name (or index) of the field
-# @return one of field types
-
-## @method SetGeometry($geometry)
-# @deprecated use Geometry, which accepts Perl data and checks the geometry type
-# Copy geometry into this feature.
-# @param geometry a Geo::OGR::Geometry object
-
-## @method $Geometry($geometry)
-# Set or get the geometry in the feature. When setting, does a check
-# against the schema (GeometryType) of the feature.
-# @param geometry [optional] a Geo::OGR::Geometry object or data from
-# which such can be created (using Geo::OGR::Geometry::create)
-# @return a copy of the geometry in the feature as a
-# Geo::OGR::Geometry object (in a non-void context)
-
-## @ignore SetGeometryDirectly
-## @ignore GetGeometry
-## @ignore GetGeometryRef
+## @ignore GetFieldDefnRef
+## @ignore GetFieldType
+## @ignore GetGeomFieldDefnRef
 
-## @method $ReferenceGeometry($geometry)
-# Create a new Geo::OGR::Geometry object, which references the
-# geometry within the feature and/or create a reference to the
-# argument geometry within the feature. This method maintains a link
-# between the two objects and will not let the feature object be
-# destroyed while the geometry object exists. Use with caution.
-# @note a.k.a. SetGeometryDirectly (only reference in), GetGeometry
-# (only create with a reference), GetGeometryRef (only create with a
-# reference and do not create the link between the objects).
-# @param geometry [optional] a Geo::OGR::Geometry object
-# @return a new Geo::OGR::Geometry object in a non-void context
+## @method Geo::OGR::FieldDefn GetFieldDefn($name)
+# @note A.k.a GetFieldDefnRef
+# @param name the name of the field.
+# @return a new Geo::OGR::FieldDefn object that represents the field
+# in question.
 
 ## @method Geo::OGR::Feature Clone()
 # @return a new Geo::OGR::Feature object
@@ -651,12 +725,13 @@
 # @param feature a Geo::OGR::Feature object for comparison
 # @return boolean
 
-## @method $GetFieldIndex($name)
-# @param name the name of the field
-# @return integer the index of the field (0..Count-1)
+## @ignore GetFieldIndex
+## @ignore GetGeomFieldIndex
+## @ignore GetFieldCount
+## @ignore GetGeomFieldCount
 
-## @method $GetFieldCount()
-# @return an integer
+## @method @GetFieldNames()
+# Get the names of the fields in this feature.
 
 ## @ignore GetFieldAsString
 ## @ignore GetFieldAsInteger
@@ -666,11 +741,11 @@
 ## @ignore GetFieldAsIntegerList
 ## @ignore GetFieldAsStringList
 
-## @method @GetField($field)
+## @method @GetField($name)
 # @note A number of GetFieldAs* methods exist but they are not
 # documented. Syntax $feature->{field} can be used to access the
 # field (v1.9.0)
-# @param field the name (or index) of the field
+# @param name the name of the field
 # @return the value of the field, which may be a scalar or a list,
 # depending on the field type.
 
@@ -678,19 +753,54 @@
 ## @ignore SetFieldIntegerList
 ## @ignore SetFieldStringList
 
-## @method SetField($field, @value)
+## @method SetField($name, @Value)
 # @note Syntax $feature->{field} can be used to access the
 # field (v1.9.0)
-# @param field the name (or index) of the field
-# @param value is a string, integer, double, a list (year, month,
+# @param name the name of the field.
+# @param Value a string, integer, double, a list (year, month,
 # day), a list (hour, minute, second, tzflag), a list (year, month,
 # day, hour, minute, second, tzflag), or a list of integers, doubles,
 # or strings.
 # @note If value is not given or is undefined this method unsets the field.
 
+## @method Field($name, @Value)
+# @brief Get or set the field.
+# @param name the name of the field.
+# @param Value a scalar or list depending on the field type.
+# @return the value of the field, which may be a scalar or a list,
+# depending on the field type.
+
+## @ignore SetGeometry
+## @ignore SetGeometryDirectly
+## @ignore GetGeometry
+## @ignore GetGeometryRef
+## @ignore GetGeomFieldRef
+## @ignore SetGeomField
+## @ignore SetGeomFieldDirectly
+
+## @method $Geometry($name, $geometry)
+# @brief Get or set the value of a geometry field.
+# @note This method delivers the functionality of undocumented methods
+# SetGeometry($geometry), SetGeometryDirectly, SetGeomField,
+# SetGeomFieldDirectly, GetGeometry, GetGeometryRef.
+#
+# Set or get the geometry in the feature. When setting, does a check
+# against the schema (GeometryType) of the feature. The ownership of
+# the geometry is given (if the parameter is an object) or kept to the
+# feature and thus the geometry will keep the feature alive as long as
+# the geometry is alive.
+# @param name [optional] the name of the spatial field,
+# whose geometry is to be set. If not given, sets or gets the geometry
+# of the first spatial field.
+# @param geometry [optional] a Geo::OGR::Geometry object or a hash
+# array from which such can be created (using
+# Geo::OGR::Geometry::create)
+# @return in a non-void context the geometry in the feature
+# as a Geo::OGR::Geometry object.
+
 ## @ignore SetFromWithMap
 
-## @method SetFrom($other, $forgiving = 1, \%map)
+## @method SetFrom($other, $forgiving = 1, hashref map)
 # @param other a Geo::OGR::Feature object
 # @param forgiving [optional] set to false if the operation should not
 # continue if output fields do not match some of the source fields
@@ -707,21 +817,20 @@
 # parameters or with an undefined argument.
 # @param field the name (or index) of the field
 
-## @method $FID($fid)
-# @param fid [optional] the id to set for this feature
-# @return integer the id of this feature
+## @method $FID($id)
+# @brief Get or set the id of this feature.
+# @param id [optional] the id to set for this feature.
+# @return integer the id of this feature.
 
 ## @method $GetFID()
-# @return integer the feature id
+# @return the feature id (an integer).
 
-## @method SetFID($fid)
-# @param fid the feature id
+## @method SetFID($id)
+# @param id the feature id.
 
 ## @method DumpReadable()
 
-## @method $StyleString($string)
-# @param string [optional]
-# @return
+## @ignore StyleString
 
 ## @method $GetStyleString()
 # @return a string
@@ -730,65 +839,95 @@
 # @param string
 
 
+
+
 ## @class Geo::OGR::FeatureDefn
+# @brief A definition of the attributes of a feature class or a layer.
+#
+# A definition object is a collection of field definition objects. A
+# read-only definition object is obtained from a layer or a feature.
 # @isa (Geo::OGR)
 
-## @cmethod Geo::OGR::FeatureDefn new($name = undef)
-# @param name
+## @cmethod Geo::OGR::FeatureDefn new(%schema)
+# Creates a new layer or feature definition. The new definition is
+# either initialized to the given schema or it will contain no
+# non-spatial fields and one spatial field, whose Name is '' and
+# GeometryType is 'Unknown' or the value of the named parameter
+# GeometryType.
+# @param schema [optional] The schema for the new feature definition,
+# as in Geo::OGR::FeatureDefn::Schema.
 # @return a Geo::OGR::FeatureDefn object
-
-## @cmethod Geo::OGR::FeatureDefn create(%schema)
+#
 # Example usage:
 # \code
 # $fd = Geo::OGR::FeatureDefn->create( 
-#     Name => "name", 
-#     GeometryType => "Polygon",
-#     Fields => [{ Name => 'field1', Type => 'String' }] );
+#     Name => "name",
+#     Fields => [{ Name => 'field1', Type => 'String' },
+#                { Name => 'geom', GeometryType => 'Point' }] );
 # \endcode
-# @param schema The schema for the new feature definition, as in
-# Geo::OGR::FeatureDefn::Schema.
-# @return a Geo::OGR::FeatureDefn object
 
-## @method \%Schema(%schema)
-# Get or set the schema. The schema is a hash (Name => name,
-# GeometryType => geometry_type, Fields => [list of
-# Geo::OGR::FieldDefn objects or hashrefs from which such can be
-# created (see Geo::OGR::FieldDefn::create)]. The Name cannot be set
-# and the Fields are added to the schema. Fields is an array of
-# hashrefs that contain schemas of FieldDefns. In addition, in the
-# 'get' form of the function, each field hash contains key 'Index',
-# whose value is the index of the field.
-# @param schema [optional]
-# @return
+## @ignore Schema
+
+## @method \%GetSchema()
+# @brief Get the schema of this feature or layer definition. 
+#
+# The schema is a hash whose keywords are Name, StyleIgnored and
+# Fields. Fields is an anonymous array of first non-spatial and then
+# spatial field schemas as in Geo::OGR::FieldDefn::Schema and
+# Geo::OGR::GeomFieldDefn::Schema.
+# @return the schema of this feature or layer definition.
+
+## @ignore Name
 
 ## @method $GetName()
-# @note a.k.a. Name
-# @return a string
+# @return the name of this layer or feature definition.
 
-## @method $GetFieldCount()
-# @return an integer
+## @ignore GetFieldIndex
+## @ignore GetFieldCount
+## @ignore GetGeomFieldCount
+## @ignore GetGeomFieldIndex
 
-## @method Geo::OGR::FieldDefn GetFieldDefn($index)
-# @deprecated use Geo::OGR::FeatureDefn::Schema
-# @param index the index (0..field_count-1) of the field
-# @return a new Geo::OGR::FieldDefn object
+## @method @GetFieldNames()
+# The names of the fields in this layer or feature definition.
+# @return the list of field names.
+
+## @ignore GeometryIgnored
+## @ignore GeometryType
+## @ignore GetGeomFieldDefn
 
-## @method $GetFieldIndex($name)
-# @param name
-# @return integer (0..field_count-1, -1 if no such field)
+## @method object GetFieldDefn($name)
+# @param name the name of the field.
+# @return either a Geo::OGR::FieldDefn or Geo::OGR::GeomFieldDefn
+# object that represents the field in question.
 
-## @method AddFieldDefn($defn)
-# @param defn a Geo::OGR::FieldDefn object
+## @ignore AddFieldDefn
+## @ignore AddGeomFieldDefn
 
+## @method AddField(%params)
+# @param params named parameters to create a new Geo::OGR::FieldDefn
+# or Geo::OGR::GeomFieldDefn object.
+
+## @ignore DeleteGeomFieldDefn
+
+## @method DeleteField($name)
+# @note Currently only geometry fields can be deleted.
+# @param index the index of the geometry field to be deleted.
+
+## @ignore GeomType
 ## @ignore GetGeomType
 ## @ignore SetGeomType
 
 ## @method $GeometryType($geometry_type)
-# Get or set the geometry type.
+# Get or set the geometry type of this feature definition.
+# @deprecated returns the type of the first spatial field. Use
+# Geo::OGR::Layer::GeometryType($index),
+# Geo::OGR::Feature::GeometryType($index),
+# Geo::OGR::GeomFieldDefn::GeometryType, or the schema.
+#
 # @note a.k.a. GeomType, GetGeomType (deprecated, returns an integer),
 # SetGeomType (deprecated, requires an integer)
-# @param geometry_type [optional] one of \@Geo::OGR::Geometry::GEOMETRY_TYPES
-# @return the geometry type, one of \@Geo::OGR::Geometry::GEOMETRY_TYPES
+# @param geometry_type [optional] one of \@Geo::OGR::GeometryTypes
+# @return the geometry type, one of \@Geo::OGR::GeometryTypes
 
 ## @ignore GetReferenceCount
 
@@ -796,66 +935,73 @@
 ## @ignore SetGeometryIgnored
 
 ## @method $GeometryIgnored($IgnoreState)
+# @deprecated gets or sets the ignore status of the first spatial
+# field. Use Geo::OGR::GeomFieldDefn::Ignored or set the keyword in
+# schema in creation.
+#
 # @note a.k.a. GetGeometryIgnored (only get), SetGeometryIgnored (only set)
 #
 # Get or set the ignore status of geometry when fetching features.
 # @return the ignore status of geometry
 # @since 1.9.0
 
-## @ignore IsStyleIgnored
-## @ignore SetStyleIgnored
+## @ignore StyleIgnored
 
-## @method $StyleIgnored($IgnoreState)
-# @note a.k.a. GetStyleIgnored (only get), SetStyleIgnored (only set)
-#
-# Get or set the ignore status of style information when fetching features.
+## @method $IsStyleIgnored()
+# Get the ignore status of style information when fetching features.
 # @return the ignore status of style information
 # @since 1.9.0
 
+## @method SetStyleIgnored($IgnoreState)
+# Set the ignore status of style information when fetching features.
+# @since 1.9.0
+
+## @method IsSame(Geo::OGR::FeatureDefn defn)
+# @return true if this definition is similar to the other definition,
+# false otherwise.
+
+
+
 
 ## @class Geo::OGR::FieldDefn
+# @brief A definition of a non-spatial attribute.
 # @isa (Geo::OGR)
 
-## @attr list FIELD_TYPES
-# Field types supported by GDAL, one of: Integer IntegerList Real
-# RealList String StringList WideString WideStringList Binary Date
-# Time DateTime
-
-## @attr list JUSTIFY_TYPES
-# Justify types supported by GDAL, one of: Undefined Left Right
+## @cmethod list Types
+# Field types supported by GDAL. Current list is
+# +list Geo::OGR OFT
 
-## @cmethod Geo::OGR::FieldDefn new($name = "unnamed", $field_type = $Geo::OGR::OFTString)
-# @deprecated use Geo::OGR::FieldDefn::create, which accepts type as a string
-# @param name
-# @param field_type as integer
-# @return a new Geo::OGR::FieldDefn object
+## @cmethod list JustifyValues
+# Justify values supported by GDAL. Current list is
+# +list Geo::OGR OJ
 
-## @cmethod Geo::OGR::FieldDefn create($name = "unnamed", $field_type = 'String')
-# @param name
-# @param field_type one of field types. Optional. Default is String.
+## @cmethod Geo::OGR::FieldDefn new(%params)
+# @brief Create a new field definition.
 #
-# Usage:
-# \code
-# $fd = Geo::OGR::FieldDefn->create(...arguments...);
-# \endcode
-# @return a new Geo::OGR::FieldDefn object
-
-## @cmethod Geo::OGR::FieldDefn create(%parameters)
-# @param parameters named parameters: Name, Type, Justify, Width,
-# Precision
+# This method supports both an argument list and named arguments.
 #
-# Usage:
-# \code
-# $fd = Geo::OGR::FieldDefn->create( Name => "name", Type => "FieldType", ...);
-# \endcode
+# @param name Field name.
+# @param type One of supported field types
+# (see Geo::OGR::FieldDefn::Types). Optional. Default is String.
+#
+# or
+#
+# @param params one or more of:
+# - \a Name Field name (default is 'unnamed').
+# - \a Type Field type, one of Geo::OGR::FieldDefn::Types (default is 'String').
+# - \a SubType Field sub type, one of Geo::OGR::FieldDefn::SubTypes.
+# - \a Justify Justify value, one of Geo::OGR::FieldDefn::JustifyValues
+# - \a Width
+# - \a Precision
+# - \a Nullable (default is true)
+# - \a Default 
+# - \a Ignored (default is false)
 # @return a new Geo::OGR::FieldDefn object
 
-## @method \%Schema(%parameters)
+## @method \%Schema(%params)
 # Get the schema or set parts of the schema
-# @param parameters [optional] named parameters: Name, Type, Justify,
-# Width, Precision
-# @return a reference to a hash whose keys are Name, Type, Justify,
-# Width, and Precision
+# @param params [optional] as those in Geo::OGR::FieldDefn::create.
+# @return a reference to a hash whose keys are as those in Geo::OGR::FieldDefn::create.
 
 ## @ignore GetName
 ## @ignore GetNameRef
@@ -874,10 +1020,16 @@
 
 ## @method $Type($type)
 # @note a.k.a. GetFieldTypeName, GetTypeName, GetType, SetType
-# @param type [optional] one of field types: Integer, IntegerList, Real,
-# RealList, String, StringList, WideString, WideStringList, Binary, Date,
-# Time, or DateTime (wide strings are not really supported yet?)
-# @return one of field types in non-void context
+# @param type [optional] One of field types (Geo::OGR::FieldDefn::Types).
+# @return one of field types in non-void context.
+
+## @ignore GetSubType
+## @ignore SetSubType
+
+## @method $SubType($SubType)
+# @note a.k.a. GetSubType, SetSubType
+# @param SubType [optional] One of field sub types (Geo::OGR::FieldDefn::SubTypes).
+# @return the sub type of this field in non-void context.
 
 ## @ignore GetJustify
 ## @ignore SetJustify
@@ -885,8 +1037,8 @@
 ## @method $Justify($justify)
 # Get and/or set the justification of this field.
 # @note a.k.a. GetJustify, SetJustify
-# @param justify [optional] as string: Undefined, Left, or Right
-# @return one of Undefined Left Right in non-void context
+# @param justify [optional] One of field justify types (Geo::OGR::FieldDefn::JustifyValues).
+# @return the justify value of this field in non-void context.
 
 ## @ignore GetWidth
 ## @ignore SetWidth
@@ -895,7 +1047,7 @@
 # Get and/or set the field width.
 # @note a.k.a. GetWidth, SetWidth
 # @param width [optional]
-# @return integer in non-void context
+# @return the width of this field in non-void context.
 
 ## @ignore GetPrecision
 ## @ignore SetPrecision
@@ -904,7 +1056,25 @@
 # Get and/or set the precision of this field.
 # @note a.k.a. GetPrecision, SetPrecision
 # @param precision [optional]
-# @return integer in non-void context
+# @return the precision of this field in non-void context.
+
+## @ignore IsNullable
+## @ignore SetNullable
+
+## @method $Nullable($nullable)
+# Get or set the nullable constraint for this field.
+# @note a.k.a. IsNullable and SetNullable
+# @param nullable [optional]
+# @return the nullable value of this field in non-void context.
+
+## @ignore GetDefault
+## @ignore SetDefault
+
+## @method $Default($value)
+# Get or set the default value for this field.
+# @note a.k.a. GetDefault and SetDefault
+# @param value [optional]
+# @return the default value of this field in non-void context.
 
 ## @ignore IsIgnored
 ## @ignore SetIgnored
@@ -914,58 +1084,134 @@
 # omitted when fetching features) of this field.
 # @note a.k.a. IsIgnored, SetIgnored
 # @param ignore [optional]
-# @return the ignore status in non-void context
+# @return the ignore status of this field in non-void context.
 # @since 1.9.0
 
-## @class Geo::OGR::Geometry
+
+
+
+## @class Geo::OGR::GeomFieldDefn
+# @brief A definition of a spatial attribute.
 # @isa (Geo::OGR)
-# @note Most spatial analysis methods require <a
-# href="http://geos.osgeo.org/doxygen/">GEOS</a> to work rigorously.
 
-## @attr list GEOMETRY_TYPES
-# Geometry types supported by GDAL, one of: Unknown Point LineString
-# Polygon MultiPoint MultiLineString MultiPolygon GeometryCollection
-# None LinearRingPoint25D LineString25D Polygon25D MultiPoint25D
-# MultiLineString25D MultiPolygon25D GeometryCollection25D
-
-## @attr list BYTE_ORDER_TYPES
-# Byte order strings, one of: XDR NDR
-
-## @cmethod Geo::OGR::Geometry new($type = $Geo::OGR::wkbUnknown, $WKT = undef, $WKB = undef, $GML = undef)
-# @deprecated use Geo::OGR::Geometry::create, which accepts type as a string
-# @param type one of Geo::OGR::wkb*
-# @param WKT
-# @param WKB
-# @param GML
-# @return a new Geo::OGR::Geometry object
+## @cmethod Geo::OGR::GeomFieldDefn new(%params)
+# @brief Create a new spatial field definition.
+#
+# @param params one or more of:
+# - \a Name name for the field (default is 'geom').
+# - \a GeometryType type for the field type, one of Geo::OGR::GeomFieldDefn::Types (default is 'Unknown').
+# - \a SpatialReference a Geo::OSR::SpatialReference object.
+# - \a Nullable (default is true)
+# - \a Ignored (default is false)
+# @return a new Geo::OGR::GeomFieldDefn object
+
+## @method \%Schema(%params)
+# Get the schema or set parts of the schema.
+# @param params [optional] as those in Geo::OGR::GeomFieldDefn::create
+# @return a reference to a hash whose keys are as those in Geo::OGR::GeomFieldDefn::create
+
+## @method Type
+# @return the type of this geometry field. One of Geo::OGR::GeomFieldDefn::Types
+
+## @cmethod Types
+# @return a list of all geometry types, currently:
+# +list Geo::OGR wkb 25DBit,25Bit,NDR,XDR
 
-## @cmethod Geo::OGR::Geometry create($type)
-# @param type One of geometry type strings: 'Point', 'LineString', etc.
+## @ignore GetName
+## @ignore GetNameRef
+## @ignore SetName
+
+## @method $Name($name)
+# @note a.k.a. GetName, GetNameRef, SetName
+# @return the name of the field.
+
+## @ignore GetType
+## @ignore SetType
+
+## @method $GeometryType($type)
+# @note a.k.a. GetType, SetType
+# @return the geometry type of the field.
+
+## @ignore GetSpatialRef
+## @ignore SetSpatialRef
+
+## @method $SpatialReference($sr)
+# @note a.k.a. GetSpatialRef, SetSpatialRef
+# @return the spatial reference of the field as a Geo::OSR::SpatialReference object.
+
+## @ignore IsNullable
+## @ignore SetNullable
+
+## @method $Nullable($nullable)
+# @note a.k.a. IsNullable, SetNullable
+# @return the nullable status of the field.
+
+## @ignore IsIgnored
+## @ignore SetIgnored
+
+## @method $Ignored($ignore)
+# @note a.k.a. IsIgnored, SetIgnored
+# @return the ignore status of the field.
+
+
+
+
+## @class Geo::OGR::Geometry
+# @isa (Geo::OGR)
+# @brief Spatial data.
 #
-# Usage:
-# \code
-# $g = Geo::OGR::Geometry->create(...arguments...);
-# \endcode
-# @return a new Geo::OGR::Geometry object
+# A geometry is spatial data (coordinate values, and a reference to a
+# spatial reference system) organized into one of the geometry
+# types. Geometries can be created from several type of data including
+# a Perl data structure. There are several methods, which modify,
+# compare, test, or compute values from geometries.
+# @note Most spatial analysis methods require <a
+# href="http://geos.osgeo.org/doxygen/">GEOS</a> to work rigorously.
 
-## @cmethod Geo::OGR::Geometry create(%params)
-# @param %params A named parameter, one of: GeometryType, WKT,
-# WKB, HEXWKB, HEXEWKB (PostGIS extended WKB), GML, GeoJSON, arc, and/or
-# Points.
+## @cmethod @GeometryTypes()
+# Same as Geo::OGR::GeometryTypes
+
+## @cmethod list ByteOrders
+# Same as Geo::OGR::ByteOrders
+
+## @cmethod Geo::OGR::Geometry new(%params)
+# @param %params A named parameter, one of: WKT, WKB, HEXWKB,
+# HEXEWKB, GML, GeoJSON, arc, or GeometryType and optionally Points.
+# - \a GeometryType one the supported geometry types, see Geo::OGR::GeometryTypes.
+# - \a WKT a well known text string, which defines a geometry.
+# - \a WKB a well known binary string, which defines a geometry.
+# - \a HEXWKB WKB in hexadecimal.
+# - \a HEXEWKB PostGIS extended WKB.
+# - \a GML geometry written in Geographic Markup Language.
+# - \a GeoJSON geometry written in GeoJSON (JavaScript Object Notation for Geographic data).
+# - \a arc a reference to a list of values defining an arc: [CenterX,
+#    CenterY, CenterZ, PrimaryRadius, SecondaryRadius, Rotation,
+#    StartAngle, EndAngle, MaxAngleStepSizeDegrees] (see also Geo::OGR::Geometry::ApproximateArcAngles)
 # - \a Points An anonymous array as in method
-# Geo::OGR::Geometry::Points; Note: requires also GeometryType
-# parameter
-# - \a arc An anonymous list of [CenterX, CenterY, CenterZ,
-#    PrimaryRadius, SecondaryRadius, Rotation, StartAngle, EndAngle,
-#    MaxAngleStepSizeDegrees]
+#      Geo::OGR::Geometry::Points; Note: requires also GeometryType
+#      parameter
 #
 # @note uses CreateGeometryFrom* functions from Geo::OGR
 #
+# @return a new Geo::OGR::Geometry object.
 # Usage:
 # \code
 # $g = Geo::OGR::Geometry->create(...arguments...);
 # \endcode
-# @return a new Geo::OGR::Geometry object
+
+## @cmethod Geo::OGR::Geometry ApproximateArcAngles(%params)
+# Create a line string, which approximates an arc. 
+# @note All angles are in degrees.
+#
+# @param %params named parameters, these are:
+# - \a Center center point (default is [0, 0, 0])
+# - \a PrimaryRadius default is 1,
+# - \a SecondaryAxis default is 1,
+# - \a Rotation default is 0,
+# - \a StartAngle default is 0,
+# - \a EndAngle default is 360,
+# - \a MaxAngleStepSizeDegrees default is 4 
+# @return a new Geo::OGR::Geometry object.
 
 ## @method FlattenTo2D()
 
@@ -982,39 +1228,31 @@
 ## @method $GetDimension()
 # @return 0, 1, or 2
 
+## @ignore AsText
 ## @ignore ExportToWkt
-
-## @method $AsText()
-# This geometric object in Well Known Text.
-# @note a.k.a. ExportToWkt
-# @return a WKT string
-
-## @method $AsBinary($byte_order = 'XDR')
-# This geometric object as a Well-known binary string.
-# @note a.k.a. ExportToWkb
-# @param byte_order XDR or NDR
-# @return a WKB binary string
-
+## @ignore ExportToIsoWkt
+## @ignore AsBinary
+## @ignore AsHEXWKB
+## @ignore AsHEXEWKB
+## @ignore ExportToWkb
+## @ignore ExportToIsoWkb
+## @ignore AsGML
 ## @ignore ExportToGML
-
-## @method $AsGML()
-# This geometric object as a GML string.
-# @note a.k.a. ExportToGML
-# @return a GML string
-
+## @ignore AsKML
 ## @ignore ExportToKML
+## @ignore AsJSON
+## @ignore ExportToJson
 
-## @method $AsKML()
-# This geometric object as a KML string.
-# @note a.k.a. ExportToKML
-# @return KML string
+## @method $As(%params)
+# Export the geometry into a known format.
 
-## @ignore ExportToJson
+# @param params named parameters, either: Text (a.k.a WKT), WKB
+# (a.k.a. Binary) (ByteOrder can also be defined, default is 'XDR'),
+# ISO WKT and WKB, HEXWKB, HEXEWKB (srid can also be given), GML,
+# GeoJSON, Binary.
 
-## @method $AsJSON()
-# This geometric object as a JSON string.
-# @note a.k.a. ExportToJson
-# @return JSON string
+# @note Uses As\<format\>/ExportTo\<format\> methods.
+# @return the geometry in a given format.
 
 ## @method AddPoint($x, $y, $z)
 # Set the data of a point or add a point to a line string. Consider
@@ -1096,7 +1334,7 @@
 # @param z [optional]
 # @return
 
-## @method \@Points(\@points)
+## @method \@Points(arrayref points)
 # Get or set the points of the geometry. The points (vertices) are
 # stored in obvious lists of lists. When setting, the geometry is
 # first emptied. The method uses internally either AddPoint_2D or
@@ -1149,7 +1387,7 @@
 # @return a new Geo::OGR::Geometry object
 
 ## @method $GeometryType()
-# @return the geometry type
+# @return the geometry type of this geometry (one of Geo::OGR::GeometryTypes).
 
 ## @method $Length()
 # @return the length of the linestring
@@ -1164,7 +1402,7 @@
 # @return an integer
 
 ## @method $GetGeometryRef($index)
-# @param index
+# @param index index to the geometry, which is a part of this geometry
 # @return a new Geo::OGR::Geometry object whose data is a part of the
 # parent geometry
 
@@ -1188,10 +1426,20 @@
 # Dissolve a geometrycollection into separate geometries.
 # @return a list of new Geo::OGR::Geometry objects cloned from the collection.
 
+## @method Geo::OGR::Geometry ForceTo($type, ref options)
+# Attempt to make a geometry of type 'type' out of this geometry.
+# @param type target geometry type. One of Geo::OGR::GeometryTypes.
+# @param options not used currently.
+# @return a new Geo::OGR::Geometry object.
+
+## @method Geo::OGR::Geometry ForceToLineString()
+# Attempt to create a line string from this geometry.
+# @return a new Geo::OGR::Geometry object.
+
 ## @method Geo::OGR::Geometry ForceToPolygon()
-# Attempt to create a polygon from the geometry.
+# Attempt to create a polygon from this geometry.
 # @exception None reported. If this method fails, just a copy is returned.
-# @return a new Geo::OGR::Geometry object
+# @return a new Geo::OGR::Geometry object.
 
 ## @method Geo::OGR::Geometry ForceToMultiPoint(@points)
 # Attempt to create a multipoint from the geometry, which must be a point.
@@ -1337,9 +1585,12 @@
 # @return an integer
 
 ## @method $GetGeometryType()
-# @deprecated use Geo::OGR::Geometry::GeometryType, which returns the type as a string
+# @deprecated use Geo::OGR::Geometry::GeometryType, which returns the
+# type as a string.
+#
 # @return type as an integer
 
 ## @method $GetGeometryName()
-# @deprecated use string names
+# @deprecated use Geo::OGR::Geometry::GeometryType.
+#
 # @return a string
diff --git a/swig/perl/lib/Geo/OGR.pm b/swig/perl/lib/Geo/OGR.pm
index 1f01802..bfaab95 100644
--- a/swig/perl/lib/Geo/OGR.pm
+++ b/swig/perl/lib/Geo/OGR.pm
@@ -8,6 +8,7 @@ package Geo::OGR;
 use base qw(Exporter);
 use base qw(DynaLoader);
 require Geo::OSR;
+require Geo::GDAL;
 package Geo::OGRc;
 bootstrap Geo::OGR;
 package Geo::OGR;
@@ -64,12 +65,27 @@ package Geo::OGR;
 *ForceToMultiPolygon = *Geo::OGRc::ForceToMultiPolygon;
 *ForceToMultiPoint = *Geo::OGRc::ForceToMultiPoint;
 *ForceToMultiLineString = *Geo::OGRc::ForceToMultiLineString;
+*ForceTo = *Geo::OGRc::ForceTo;
 *GetDriverCount = *Geo::OGRc::GetDriverCount;
 *GetOpenDSCount = *Geo::OGRc::GetOpenDSCount;
 *SetGenerate_DB2_V72_BYTE_ORDER = *Geo::OGRc::SetGenerate_DB2_V72_BYTE_ORDER;
 *RegisterAll = *Geo::OGRc::RegisterAll;
 *GeometryTypeToName = *Geo::OGRc::GeometryTypeToName;
 *GetFieldTypeName = *Geo::OGRc::GetFieldTypeName;
+*GetFieldSubTypeName = *Geo::OGRc::GetFieldSubTypeName;
+*GT_Flatten = *Geo::OGRc::GT_Flatten;
+*GT_SetZ = *Geo::OGRc::GT_SetZ;
+*GT_SetModifier = *Geo::OGRc::GT_SetModifier;
+*GT_HasZ = *Geo::OGRc::GT_HasZ;
+*GT_IsSubClassOf = *Geo::OGRc::GT_IsSubClassOf;
+*GT_IsCurve = *Geo::OGRc::GT_IsCurve;
+*GT_IsSurface = *Geo::OGRc::GT_IsSurface;
+*GT_IsNonLinear = *Geo::OGRc::GT_IsNonLinear;
+*GT_GetCollection = *Geo::OGRc::GT_GetCollection;
+*GT_GetCurve = *Geo::OGRc::GT_GetCurve;
+*GT_GetLinear = *Geo::OGRc::GT_GetLinear;
+*SetNonLinearGeometriesEnabledFlag = *Geo::OGRc::SetNonLinearGeometriesEnabledFlag;
+*GetNonLinearGeometriesEnabledFlag = *Geo::OGRc::GetNonLinearGeometriesEnabledFlag;
 *GetOpenDS = *Geo::OGRc::GetOpenDS;
 *Open = *Geo::OGRc::Open;
 *OpenShared = *Geo::OGRc::OpenShared;
@@ -126,7 +142,7 @@ sub ACQUIRE {
 
 package Geo::OGR::Driver;
 use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
- at ISA = qw( Geo::OGR );
+ at ISA = qw( Geo::GDAL::MajorObject Geo::OGR );
 %OWNER = ();
 %ITERATORS = ();
 *swig_name_get = *Geo::OGRc::Driver_name_get;
@@ -156,7 +172,7 @@ sub ACQUIRE {
 
 package Geo::OGR::DataSource;
 use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
- at ISA = qw( Geo::OGR );
+ at ISA = qw( Geo::GDAL::MajorObject Geo::OGR );
 %OWNER = ();
 %ITERATORS = ();
 *swig_name_get = *Geo::OGRc::DataSource_name_get;
@@ -185,15 +201,19 @@ sub DESTROY {
 *GetName = *Geo::OGRc::DataSource_GetName;
 *_DeleteLayer = *Geo::OGRc::DataSource__DeleteLayer;
 *SyncToDisk = *Geo::OGRc::DataSource_SyncToDisk;
+*FlushCache = *Geo::OGRc::DataSource_FlushCache;
 *_CreateLayer = *Geo::OGRc::DataSource__CreateLayer;
 *CopyLayer = *Geo::OGRc::DataSource_CopyLayer;
-*_GetLayerByIndex = *Geo::OGRc::DataSource__GetLayerByIndex;
-*_GetLayerByName = *Geo::OGRc::DataSource__GetLayerByName;
+*GetLayerByIndex = *Geo::OGRc::DataSource_GetLayerByIndex;
+*GetLayerByName = *Geo::OGRc::DataSource_GetLayerByName;
 *_TestCapability = *Geo::OGRc::DataSource__TestCapability;
 *_ExecuteSQL = *Geo::OGRc::DataSource__ExecuteSQL;
-*ReleaseResultSet = *Geo::OGRc::DataSource_ReleaseResultSet;
+*_ReleaseResultSet = *Geo::OGRc::DataSource__ReleaseResultSet;
 *GetStyleTable = *Geo::OGRc::DataSource_GetStyleTable;
 *SetStyleTable = *Geo::OGRc::DataSource_SetStyleTable;
+*StartTransaction = *Geo::OGRc::DataSource_StartTransaction;
+*CommitTransaction = *Geo::OGRc::DataSource_CommitTransaction;
+*RollbackTransaction = *Geo::OGRc::DataSource_RollbackTransaction;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -211,7 +231,7 @@ sub ACQUIRE {
 
 package Geo::OGR::Layer;
 use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
- at ISA = qw( Geo::OGR );
+ at ISA = qw( Geo::GDAL::MajorObject Geo::OGR );
 %OWNER = ();
 *GetRefCount = *Geo::OGRc::Layer_GetRefCount;
 *SetSpatialFilter = *Geo::OGRc::Layer_SetSpatialFilter;
@@ -238,7 +258,7 @@ use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 *_DeleteField = *Geo::OGRc::Layer__DeleteField;
 *ReorderField = *Geo::OGRc::Layer_ReorderField;
 *ReorderFields = *Geo::OGRc::Layer_ReorderFields;
-*AlterFieldDefn = *Geo::OGRc::Layer_AlterFieldDefn;
+*_AlterFieldDefn = *Geo::OGRc::Layer__AlterFieldDefn;
 *CreateGeomField = *Geo::OGRc::Layer_CreateGeomField;
 *StartTransaction = *Geo::OGRc::Layer_StartTransaction;
 *CommitTransaction = *Geo::OGRc::Layer_CommitTransaction;
@@ -299,8 +319,8 @@ sub new {
 }
 
 *GetDefnRef = *Geo::OGRc::Feature_GetDefnRef;
-*SetGeometry = *Geo::OGRc::Feature_SetGeometry;
-*_SetGeometryDirectly = *Geo::OGRc::Feature__SetGeometryDirectly;
+*_SetGeometry = *Geo::OGRc::Feature__SetGeometry;
+*SetGeometryDirectly = *Geo::OGRc::Feature_SetGeometryDirectly;
 *GetGeometryRef = *Geo::OGRc::Feature_GetGeometryRef;
 *SetGeomField = *Geo::OGRc::Feature_SetGeomField;
 *SetGeomFieldDirectly = *Geo::OGRc::Feature_SetGeomFieldDirectly;
@@ -313,11 +333,13 @@ sub new {
 *GetGeomFieldDefnRef = *Geo::OGRc::Feature_GetGeomFieldDefnRef;
 *GetFieldAsString = *Geo::OGRc::Feature_GetFieldAsString;
 *GetFieldAsInteger = *Geo::OGRc::Feature_GetFieldAsInteger;
+*GetFieldAsInteger64 = *Geo::OGRc::Feature_GetFieldAsInteger64;
 *GetFieldAsDouble = *Geo::OGRc::Feature_GetFieldAsDouble;
 *GetFieldAsDateTime = *Geo::OGRc::Feature_GetFieldAsDateTime;
 *GetFieldAsIntegerList = *Geo::OGRc::Feature_GetFieldAsIntegerList;
 *GetFieldAsDoubleList = *Geo::OGRc::Feature_GetFieldAsDoubleList;
 *GetFieldAsStringList = *Geo::OGRc::Feature_GetFieldAsStringList;
+*GetFieldAsBinary = *Geo::OGRc::Feature_GetFieldAsBinary;
 *IsFieldSet = *Geo::OGRc::Feature_IsFieldSet;
 *GetFieldIndex = *Geo::OGRc::Feature_GetFieldIndex;
 *GetGeomFieldIndex = *Geo::OGRc::Feature_GetGeomFieldIndex;
@@ -325,6 +347,7 @@ sub new {
 *SetFID = *Geo::OGRc::Feature_SetFID;
 *DumpReadable = *Geo::OGRc::Feature_DumpReadable;
 *_UnsetField = *Geo::OGRc::Feature__UnsetField;
+*SetFieldInteger64 = *Geo::OGRc::Feature_SetFieldInteger64;
 *_SetField = *Geo::OGRc::Feature__SetField;
 *SetFieldIntegerList = *Geo::OGRc::Feature_SetFieldIntegerList;
 *SetFieldDoubleList = *Geo::OGRc::Feature_SetFieldDoubleList;
@@ -334,7 +357,9 @@ sub new {
 *SetFromWithMap = *Geo::OGRc::Feature_SetFromWithMap;
 *GetStyleString = *Geo::OGRc::Feature_GetStyleString;
 *SetStyleString = *Geo::OGRc::Feature_SetStyleString;
-*_GetFieldType = *Geo::OGRc::Feature__GetFieldType;
+*GetFieldType = *Geo::OGRc::Feature_GetFieldType;
+*_Validate = *Geo::OGRc::Feature__Validate;
+*FillUnsetWithDefault = *Geo::OGRc::Feature_FillUnsetWithDefault;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -371,10 +396,46 @@ sub DESTROY {
     $self->RELEASE_PARENTS();
 }
 
+use Carp;
+use Scalar::Util 'blessed';
 sub new {
     my $pkg = shift;
-    my $self = Geo::OGRc::new_FeatureDefn(@_);
-    bless $self, $pkg if defined($self);
+    my %schema;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %schema = %{$_[0]};
+    } elsif (@_ and @_ % 2 == 0) {
+        %schema = @_;
+    }
+    my $fields = $schema{Fields};
+    confess "The Fields argument is not a reference to an array." if $fields and ref($fields) ne 'ARRAY';
+    $schema{Name} = '' unless exists $schema{Name};
+    my $self = Geo::OGRc::new_FeatureDefn($schema{Name});
+    bless $self, $pkg;
+    my $gt = $schema{GeometryType};
+    if ($fields) {
+        $self->DeleteGeomFieldDefn(0); # either default behavior or argument specified
+    } else {
+        $self->GeometryType($schema{GeometryType}) if exists $schema{GeometryType};
+    }
+    $self->StyleIgnored($schema{StyleIgnored}) if exists $schema{StyleIgnored};
+    for my $fd (@{$fields}) {
+        my $d = $fd;
+        if (ref($fd) eq 'HASH') {
+            if ($fd->{GeometryType} or exists $Geo::OGR::Geometry::TYPE_STRING2INT{$fd->{Type}}) {
+                $d = Geo::OGR::GeomFieldDefn->new(%$fd);
+            } else {
+                $d = Geo::OGR::FieldDefn->new(%$fd);
+            }
+        }
+        if (blessed($d) and $d->isa('Geo::OGR::FieldDefn')) {
+            AddFieldDefn($self, $d);
+        } elsif (blessed($d) and $d->isa('Geo::OGR::GeomFieldDefn')) {
+            AddGeomFieldDefn($self, $d);
+        } else {
+            confess "Item in field list does not define a field.";
+        }
+    }
+    return $self;
 }
 
 *GetName = *Geo::OGRc::FeatureDefn_GetName;
@@ -431,10 +492,39 @@ sub DESTROY {
     $self->RELEASE_PARENTS();
 }
 
+use Carp;
 sub new {
     my $pkg = shift;
-    my $self = Geo::OGRc::new_FieldDefn(@_);
-    bless $self, $pkg if defined($self);
+    my ($name, $type) = ('unnamed', 'String');
+    my %args;
+    if (@_ == 0) {
+    } elsif (@_ == 1) {
+        $name = shift;
+    } elsif (@_ == 2 and not $SCHEMA_KEYS{$_[0]}) {
+        $name = shift;
+        $type = shift;
+    } else {
+        my %named = @_;
+        for my $key (keys %named) {
+            if ($SCHEMA_KEYS{$key}) {
+                $args{$key} = $named{$key};
+            } else {
+                carp "Unrecognized argument: '$key'." if $key ne 'Index';
+            }
+        }
+        $name = $args{Name} if exists $args{Name};
+        delete $args{Name};
+        $type = $args{Type} if exists $args{Type};
+        delete $args{Type};
+    }
+    confess "Unknown field type: '$type'." unless exists $TYPE_STRING2INT{$type};
+    $type = $TYPE_STRING2INT{$type};
+    my $self = Geo::OGRc::new_FieldDefn($name, $type);
+    if (defined($self)) {
+        bless $self, $pkg;
+        $self->Schema(%args);
+    }
+    return $self;
 }
 
 *GetName = *Geo::OGRc::FieldDefn_GetName;
@@ -442,6 +532,8 @@ sub new {
 *SetName = *Geo::OGRc::FieldDefn_SetName;
 *GetType = *Geo::OGRc::FieldDefn_GetType;
 *SetType = *Geo::OGRc::FieldDefn_SetType;
+*GetSubType = *Geo::OGRc::FieldDefn_GetSubType;
+*SetSubType = *Geo::OGRc::FieldDefn_SetSubType;
 *GetJustify = *Geo::OGRc::FieldDefn_GetJustify;
 *SetJustify = *Geo::OGRc::FieldDefn_SetJustify;
 *GetWidth = *Geo::OGRc::FieldDefn_GetWidth;
@@ -452,6 +544,11 @@ sub new {
 *GetFieldTypeName = *Geo::OGRc::FieldDefn_GetFieldTypeName;
 *IsIgnored = *Geo::OGRc::FieldDefn_IsIgnored;
 *SetIgnored = *Geo::OGRc::FieldDefn_SetIgnored;
+*IsNullable = *Geo::OGRc::FieldDefn_IsNullable;
+*SetNullable = *Geo::OGRc::FieldDefn_SetNullable;
+*GetDefault = *Geo::OGRc::FieldDefn_GetDefault;
+*SetDefault = *Geo::OGRc::FieldDefn_SetDefault;
+*IsDefaultDriverSpecific = *Geo::OGRc::FieldDefn_IsDefaultDriverSpecific;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -483,10 +580,41 @@ sub DESTROY {
     }
 }
 
+use Carp;
 sub new {
     my $pkg = shift;
-    my $self = Geo::OGRc::new_GeomFieldDefn(@_);
-    bless $self, $pkg if defined($self);
+    my ($name, $type) = ('geom', 'Unknown');
+    my %args;
+    if (@_ == 0) {
+    } elsif (@_ == 1) {
+        $name = shift;
+    } elsif (@_ == 2 and not $SCHEMA_KEYS{$_[0]}) {
+        $name = shift;
+        $type = shift;
+    } else {
+        my %named = @_;
+        for my $key (keys %named) {
+            if ($SCHEMA_KEYS{$key}) {
+                $args{$key} = $named{$key};
+            } else {
+                carp "Unrecognized argument: '$key'." if $key ne 'Index';
+            }
+        }
+        $name = $args{Name} if exists $args{Name};
+        delete $args{Name};
+        $type = $args{Type} if $args{Type};
+        delete $args{Type};
+        $type = $args{GeometryType} if $args{GeometryType};
+        delete $args{GeometryType};
+    }
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    my $self = Geo::OGRc::new_GeomFieldDefn($name, $type);
+    if (defined($self)) {
+        bless $self, $pkg;
+        $self->Schema(%args);
+    }
+    return $self;
 }
 
 *GetName = *Geo::OGRc::GeomFieldDefn_GetName;
@@ -498,6 +626,8 @@ sub new {
 *SetSpatialRef = *Geo::OGRc::GeomFieldDefn_SetSpatialRef;
 *IsIgnored = *Geo::OGRc::GeomFieldDefn_IsIgnored;
 *SetIgnored = *Geo::OGRc::GeomFieldDefn_SetIgnored;
+*IsNullable = *Geo::OGRc::GeomFieldDefn_IsNullable;
+*SetNullable = *Geo::OGRc::GeomFieldDefn_SetNullable;
 sub DISOWN {
     my $self = shift;
     my $ptr = tied(%$self);
@@ -534,14 +664,69 @@ sub DESTROY {
     $self->RELEASE_PARENTS();
 }
 
+use Carp;
 sub new {
     my $pkg = shift;
-    my $self = Geo::OGRc::new_Geometry(@_);
-    bless $self, $pkg if defined($self);
+    my ($type, $wkt, $wkb, $gml, $json, $srs, $points, $arc);
+    my %param;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %param = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %param = @_;
+    } else {
+        ($param{GeometryType}) = @_;
+    }
+    $type = ($param{type} or $param{Type} or $param{GeometryType});
+    $srs = ($param{srs} or $param{SRS});
+    $wkt = ($param{wkt} or $param{WKT});
+    $wkb = ($param{wkb} or $param{WKB});
+    my $hex = ($param{hexewkb} or $param{HEXEWKB}); # PostGIS HEX EWKB
+    my $srid;
+    if ($hex) {
+        # get and remove SRID
+        $srid = substr($hex, 10, 8);
+        substr($hex, 10, 8) = '';
+    } else {
+        $hex = ($param{hexwkb} or $param{HEXWKB});
+    }
+    if ($hex) {
+        $wkb = '';
+        for (my $i = 0; $i < length($hex); $i+=2) {
+            $wkb .= chr(hex(substr($hex,$i,2)));
+        }
+    }
+    $gml = ($param{gml} or $param{GML});
+    $json = ($param{geojson} or $param{GeoJSON});
+    $points = $param{Points};
+    $arc = ($param{arc} or $param{Arc});
+    my $self;
+    if (defined $wkt) {
+        $self = Geo::OGRc::CreateGeometryFromWkt($wkt, $srs);
+    } elsif (defined $wkb) {
+        $self = Geo::OGRc::CreateGeometryFromWkb($wkb, $srs);
+    } elsif (defined $gml) {
+        $self = Geo::OGRc::CreateGeometryFromGML($gml);
+    } elsif (defined $json) {
+        $self = Geo::OGRc::CreateGeometryFromJson($json);
+    } elsif (defined $type) {
+        confess "Unknown geometry type: '$type'." unless exists $TYPE_STRING2INT{$type};
+        $type = $TYPE_STRING2INT{$type};
+        $self = Geo::OGRc::new_Geometry($type); # flattens the type
+        SetCoordinateDimension($self, 3) if Geo::OGR::GT_HasZ($type);
+    } elsif (defined $arc) {
+        $self = Geo::OGRc::ApproximateArcAngles(@$arc);
+    } else {
+        confess "Missing a parameter when creating a Geo::OGR::Geometry object.";
+    }
+    bless $self, $pkg if defined $self;
+    $self->Points($points) if $points;
+    return $self;
 }
 
 *ExportToWkt = *Geo::OGRc::Geometry_ExportToWkt;
+*ExportToIsoWkt = *Geo::OGRc::Geometry_ExportToIsoWkt;
 *_ExportToWkb = *Geo::OGRc::Geometry__ExportToWkb;
+*ExportToIsoWkb = *Geo::OGRc::Geometry_ExportToIsoWkb;
 *ExportToGML = *Geo::OGRc::Geometry_ExportToGML;
 *ExportToKML = *Geo::OGRc::Geometry_ExportToKML;
 *ExportToJson = *Geo::OGRc::Geometry_ExportToJson;
@@ -608,6 +793,10 @@ sub new {
 *GetCoordinateDimension = *Geo::OGRc::Geometry_GetCoordinateDimension;
 *SetCoordinateDimension = *Geo::OGRc::Geometry_SetCoordinateDimension;
 *GetDimension = *Geo::OGRc::Geometry_GetDimension;
+*HasCurveGeometry = *Geo::OGRc::Geometry_HasCurveGeometry;
+*GetLinearGeometry = *Geo::OGRc::Geometry_GetLinearGeometry;
+*GetCurveGeometry = *Geo::OGRc::Geometry_GetCurveGeometry;
+*Value = *Geo::OGRc::Geometry_Value;
 *Move = *Geo::OGRc::Geometry_Move;
 sub DISOWN {
     my $self = shift;
@@ -636,8 +825,18 @@ package Geo::OGR;
 *wkbMultiLineString = *Geo::OGRc::wkbMultiLineString;
 *wkbMultiPolygon = *Geo::OGRc::wkbMultiPolygon;
 *wkbGeometryCollection = *Geo::OGRc::wkbGeometryCollection;
+*wkbCircularString = *Geo::OGRc::wkbCircularString;
+*wkbCompoundCurve = *Geo::OGRc::wkbCompoundCurve;
+*wkbCurvePolygon = *Geo::OGRc::wkbCurvePolygon;
+*wkbMultiCurve = *Geo::OGRc::wkbMultiCurve;
+*wkbMultiSurface = *Geo::OGRc::wkbMultiSurface;
 *wkbNone = *Geo::OGRc::wkbNone;
 *wkbLinearRing = *Geo::OGRc::wkbLinearRing;
+*wkbCircularStringZ = *Geo::OGRc::wkbCircularStringZ;
+*wkbCompoundCurveZ = *Geo::OGRc::wkbCompoundCurveZ;
+*wkbCurvePolygonZ = *Geo::OGRc::wkbCurvePolygonZ;
+*wkbMultiCurveZ = *Geo::OGRc::wkbMultiCurveZ;
+*wkbMultiSurfaceZ = *Geo::OGRc::wkbMultiSurfaceZ;
 *wkbPoint25D = *Geo::OGRc::wkbPoint25D;
 *wkbLineString25D = *Geo::OGRc::wkbLineString25D;
 *wkbPolygon25D = *Geo::OGRc::wkbPolygon25D;
@@ -657,6 +856,12 @@ package Geo::OGR;
 *OFTDate = *Geo::OGRc::OFTDate;
 *OFTTime = *Geo::OGRc::OFTTime;
 *OFTDateTime = *Geo::OGRc::OFTDateTime;
+*OFTInteger64 = *Geo::OGRc::OFTInteger64;
+*OFTInteger64List = *Geo::OGRc::OFTInteger64List;
+*OFSTNone = *Geo::OGRc::OFSTNone;
+*OFSTBoolean = *Geo::OGRc::OFSTBoolean;
+*OFSTInt16 = *Geo::OGRc::OFSTInt16;
+*OFSTFloat32 = *Geo::OGRc::OFSTFloat32;
 *OJUndefined = *Geo::OGRc::OJUndefined;
 *OJLeft = *Geo::OGRc::OJLeft;
 *OJRight = *Geo::OGRc::OJRight;
@@ -666,7 +871,14 @@ package Geo::OGR;
 *ALTER_NAME_FLAG = *Geo::OGRc::ALTER_NAME_FLAG;
 *ALTER_TYPE_FLAG = *Geo::OGRc::ALTER_TYPE_FLAG;
 *ALTER_WIDTH_PRECISION_FLAG = *Geo::OGRc::ALTER_WIDTH_PRECISION_FLAG;
+*ALTER_NULLABLE_FLAG = *Geo::OGRc::ALTER_NULLABLE_FLAG;
+*ALTER_DEFAULT_FLAG = *Geo::OGRc::ALTER_DEFAULT_FLAG;
 *ALTER_ALL_FLAG = *Geo::OGRc::ALTER_ALL_FLAG;
+*F_VAL_NULL = *Geo::OGRc::F_VAL_NULL;
+*F_VAL_GEOM_TYPE = *Geo::OGRc::F_VAL_GEOM_TYPE;
+*F_VAL_WIDTH = *Geo::OGRc::F_VAL_WIDTH;
+*F_VAL_ALLOW_NULL_WHEN_DEFAULT = *Geo::OGRc::F_VAL_ALLOW_NULL_WHEN_DEFAULT;
+*F_VAL_ALL = *Geo::OGRc::F_VAL_ALL;
 *OLCRandomRead = *Geo::OGRc::OLCRandomRead;
 *OLCSequentialWrite = *Geo::OGRc::OLCSequentialWrite;
 *OLCRandomWrite = *Geo::OGRc::OLCRandomWrite;
@@ -683,1189 +895,1623 @@ package Geo::OGR;
 *OLCStringsAsUTF8 = *Geo::OGRc::OLCStringsAsUTF8;
 *OLCIgnoreFields = *Geo::OGRc::OLCIgnoreFields;
 *OLCCreateGeomField = *Geo::OGRc::OLCCreateGeomField;
+*OLCCurveGeometries = *Geo::OGRc::OLCCurveGeometries;
 *ODsCCreateLayer = *Geo::OGRc::ODsCCreateLayer;
 *ODsCDeleteLayer = *Geo::OGRc::ODsCDeleteLayer;
 *ODsCCreateGeomFieldAfterCreateLayer = *Geo::OGRc::ODsCCreateGeomFieldAfterCreateLayer;
+*ODsCCurveGeometries = *Geo::OGRc::ODsCCurveGeometries;
+*ODsCTransactions = *Geo::OGRc::ODsCTransactions;
+*ODsCEmulatedTransactions = *Geo::OGRc::ODsCEmulatedTransactions;
 *ODrCCreateDataSource = *Geo::OGRc::ODrCCreateDataSource;
 *ODrCDeleteDataSource = *Geo::OGRc::ODrCDeleteDataSource;
+*OLMD_FID64 = *Geo::OGRc::OLMD_FID64;
 *TermProgress = *Geo::OGRc::TermProgress;
 
-    use strict;
-    use Carp;
-    {
-        package Geo::OGR;
+
+package Geo::OGR::Driver;
+use strict;
+use warnings;
+use Carp;
+use vars qw /@CAPABILITIES %CAPABILITIES/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^ODrC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::ODrC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    confess "No such capability defined for class Driver: '$cap'." unless defined $CAPABILITIES{$cap};
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+
+*Create = *CreateDataSource;
+*Copy = *CopyDataSource;
+*OpenDataSource = *Open;
+*Delete = *DeleteDataSource;
+*Name = *GetName;
+
+
+
+
+package Geo::OGR::DataSource;
+use strict;
+use warnings;
+use Carp;
+use vars qw /@CAPABILITIES %CAPABILITIES %LAYERS %RESULT_SET/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^ODsC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::ODsC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    confess "No such capability defined for class DataSource: '$cap'." unless defined $CAPABILITIES{$cap};
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+*GetDriver = *_GetDriver;
+
+sub new {
+    my $pkg = shift;
+    return Geo::OGR::Open(@_);
+}
+
+sub Open {
+    return Geo::OGR::Open(@_);
+}
+
+sub OpenShared {
+    return Geo::OGR::OpenShared(@_);
+}
+
+sub ExecuteSQL {
+    my $self = shift;
+    my $layer = $self->_ExecuteSQL(@_);
+    $LAYERS{tied(%$layer)} = $self;
+    $RESULT_SET{tied(%$layer)} = 1;
+    return $layer;
+}
+
+sub ReleaseResultSet {
+    # a no-op, _ReleaseResultSet is called from Layer::DESTROY
+}
+
+sub GetLayer {
+    my($self, $name) = @_;
+    my $layer = defined $name ? GetLayerByName($self, "$name") : GetLayerByIndex($self, 0);
+    $name = '' unless defined $name;
+    confess "No such layer: '$name'." unless $layer;
+    $LAYERS{tied(%$layer)} = $self;
+    return $layer;
+}
+*Layer = *GetLayer;
+
+sub GetLayerNames {
+    my $self = shift;
+    my @names;
+    for my $i (0..$self->GetLayerCount-1) {
+        my $layer = GetLayerByIndex($self, $i);
+        push @names, $layer->GetName;
+    }
+    return @names;
+}
+*Layers = *GetLayerNames;
+
+sub CreateLayer {
+    my $self = shift;
+    my %defaults = ( Name => 'unnamed',
+                     SRS => undef,
+                     Options => {},
+                     GeometryType => 'Unknown',
+                     Schema => undef,
+                     Fields => undef,
+                     ApproxOK => 1);
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0 and (defined $_[0] and exists $defaults{$_[0]})) {
+        %params = @_;
+    } else {
+        ($params{Name}, $params{SRS}, $params{GeometryType}, $params{Options}, $params{Schema}) = @_;
+    }
+    for (keys %params) {
+        carp "CreateLayer: unknown named parameter '$_'." unless exists $defaults{$_};
+    }
+    if (exists $params{Schema}) {
+        my $s = $params{Schema};
+        $params{GeometryType} = $s->{GeometryType} if exists $s->{GeometryType};
+        $params{Fields} = $s->{Fields} if exists $s->{Fields};
+        $params{Name} = $s->{Name} if exists $s->{Name};
+    }
+    $defaults{GeometryType} = 'None' if $params{Fields};
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    confess "Unknown geometry type: '$params{GeometryType}'."
+        unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
+    my $gt = $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
+    my $layer = _CreateLayer($self, $params{Name}, $params{SRS}, $gt, $params{Options});
+    $LAYERS{tied(%$layer)} = $self;
+    my $f = $params{Fields};
+    if ($f) {
+        confess "Named parameter 'Fields' must be a reference to an array." unless ref($f) eq 'ARRAY';
+        for my $field (@$f) {
+            $layer->CreateField($field);
+        }
+    }
+    return $layer;
+}
+
+sub DeleteLayer {
+    my ($self, $name) = @_;
+    my $index;
+    for my $i (0..$self->GetLayerCount-1) {
+        my $layer = GetLayerByIndex($self, $i);
+        $index = $i, last if $layer->GetName eq $name;
+    }
+    confess "No such layer: '$name'." unless defined $index;
+    _DeleteLayer($self, $index);
+}
+
+
+
+
+package Geo::OGR::Layer;
+use strict;
+use warnings;
+use Carp;
+use Scalar::Util 'blessed';
+use vars qw /@CAPABILITIES %CAPABILITIES  %DEFNS/;
+for (keys %Geo::OGR::) {
+    push(@CAPABILITIES, $1), next if /^OLC(\w+)/;
+}
+for my $s (@CAPABILITIES) {
+    my $cap = eval "\$Geo::OGR::OLC$s";
+    $CAPABILITIES{$s} = $cap;
+}
+
+sub DESTROY {
+    my $self;
+    if ($_[0]->isa('SCALAR')) {
+        $self = $_[0];
+    } else {
+        return unless $_[0]->isa('HASH');
+        $self = tied(%{$_[0]});
+        return unless defined $self;
+    }
+    if ($Geo::OGR::DataSource::RESULT_SET{$self}) {
+        $Geo::OGR::DataSource::LAYERS{$self}->_ReleaseResultSet($self);
+        delete $Geo::OGR::DataSource::RESULT_SET{$self}
+    }
+    delete $ITERATORS{$self};
+    if (exists $OWNER{$self}) {
+        delete $OWNER{$self};
+    }
+    $self->RELEASE_PARENTS();
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::DataSource::LAYERS{$self};
+}
+
+sub Capabilities {
+    return @CAPABILITIES if @_ == 0;
+    my $self = shift;
+    my @cap;
+    for my $cap (@CAPABILITIES) {
+        push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
+    }
+    return @cap;
+}
+
+sub TestCapability {
+    my($self, $cap) = @_;
+    return _TestCapability($self, $CAPABILITIES{$cap});
+}
+
+sub GetDataSource {
+    my $self = shift;
+    return $Geo::OGR::DataSource::LAYERS{$self};
+}
+*DataSource = *GetDataSource;
+
+sub GetDefn {
+    my $self = shift;
+    my $defn = $self->GetLayerDefn;
+    $DEFNS{$defn} = $self;
+    return $defn;
+}
+
+sub CreateField {
+    my $self = shift;
+    my %defaults = ( ApproxOK => 1,
+                     Type => '' );
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %params = @_;
+    } else {
+        ($params{Defn}) = @_;
+    }
+    for (keys %defaults) {
+        $params{$_} = $defaults{$_} unless defined $params{$_};
+    }
+    if (blessed($params{Defn}) and $params{Defn}->isa('Geo::OGR::FieldDefn')) {
+        $self->_CreateField($params{Defn}, $params{ApproxOK});
+    } elsif (blessed($_[0]) and $params{Defn}->isa('Geo::OGR::GeomFieldDefn')) {
+        $self->CreateGeomField($params{Defn}, $params{ApproxOK});
+    } else {
+        my $a = $params{ApproxOK};
+        delete $params{ApproxOK};
+        if (exists $params{GeometryType}) {
+            $params{Type} = $params{GeometryType};
+            delete $params{GeometryType};
+        }
+        if (exists $Geo::OGR::FieldDefn::TYPE_STRING2INT{$params{Type}}) {
+            my $fd = Geo::OGR::FieldDefn->new(%params);
+            _CreateField($self, $fd, $a);
+        } else {
+            my $fd = Geo::OGR::GeomFieldDefn->new(%params);
+            CreateGeomField($self, $fd, $a);
+        }
+    }
+}
+
+sub AlterFieldDefn {
+    my $self = shift;
+    my $field = shift;
+    my $index;
+    eval {
+        $index = $self->GetFieldIndex($field);
+    };
+    confess "Only non-spatial fields can be altered.\n$@" if $@;
+    if (blessed($_[0]) and $_[0]->isa('Geo::OGR::FieldDefn')) {
+        _AlterFieldDefn($self, $index, @_);
+    } elsif (@_ % 2 == 0) {
+        my %params = @_;
+        my $definition = Geo::OGR::FieldDefn->new(%params);
+        my $flags = 0;
+        $flags |= 1 if exists $params{Name};
+        $flags |= 2 if exists $params{Type};
+        $flags |= 4 if exists $params{Width} or exists $params{Precision};
+        $flags |= 8 if exists $params{Nullable};
+        $flags |= 16 if exists $params{Default};
+        _AlterFieldDefn($self, $index, $definition, $flags);
+    } else {
+        croak "Usage: AlterFieldDefn(\$Name, \%NamedParameters)";
+    }
+}
+
+sub DeleteField {
+    my($self, $fn) = @_;
+    my $d = $self->GetDefn;
+    my $index = $d->GetFieldIndex($fn);
+    $index = $fn if $index < 0;
+    eval {
+        _DeleteField($self, $index);
+    };
+    confess "Field not found: '$fn'. Only non-spatial fields can be deleted." if $@;
+}
+
+sub GetSchema {
+    my $self = shift;
+    carp "Schema of a layer should not be set directly." if @_;
+    if (@_ and @_ % 2 == 0) {
+        my %schema = @_;
+        if ($schema{Fields}) {
+            for my $field (@{$schema{Fields}}) {
+                $self->CreateField($field);
+            }
+        }
+    }
+    return $self->GetDefn->Schema;
+}
+*Schema = *GetSchema;
+
+sub Row {
+    my $self = shift;
+    my $update = @_ > 0;
+    my %row = @_;
+    my $feature = defined $row{FID} ? $self->GetFeature($row{FID}) : $self->GetNextFeature;
+    return unless $feature;
+    my $ret;
+    if (defined wantarray) {
+        $ret = $feature->Row(@_);
+    } else {
+        $feature->Row(@_);
+    }
+    $self->SetFeature($feature) if $update;
+    return unless defined wantarray;
+    return $ret;
+}
+
+sub Tuple {
+    my $self = shift;
+    my $FID = shift;
+    my $feature = defined $FID ? $self->GetFeature($FID) : $self->GetNextFeature;
+    return unless $feature;
+    my $set = @_ > 0;
+    unshift @_, $feature->GetFID if $set;
+    my @ret;
+    if (defined wantarray) {
+        @ret = $feature->Tuple(@_);
+    } else {
+        $feature->Tuple(@_);
+    }
+    $self->SetFeature($feature) if $set;
+    return unless defined wantarray;
+    return @ret;
+}
+
+sub SpatialFilter {
+    my $self = shift;
+    $self->SetSpatialFilter($_[0]) if @_ == 1;
+    $self->SetSpatialFilterRect(@_) if @_ == 4;
+    return unless defined wantarray;
+    $self->GetSpatialFilter;
+}
+
+sub InsertFeature {
+    my $self = shift;
+    my $feature = shift;
+    confess "Usage: \$feature->InsertFeature(reference to a hash or array)." unless ref($feature);
+    my $new = Geo::OGR::Feature->new($self->GetDefn);
+    if (ref($feature) eq 'HASH') {
+        $new->Row(%$feature);
+    } elsif (ref($feature) eq 'ARRAY') {
+        $new->Tuple(@$feature);
+    } elsif (blessed($feature) and $feature->isa('Geo::OGR::Feature')) {
+        $new->Row($feature->Row);
+    }
+    $self->CreateFeature($new);
+}
+
+sub ForFeatures {
+    my $self = shift;
+    my $code = shift;
+    my $in_place = shift;
+    $self->ResetReading;
+    while (my $f = $self->GetNextFeature) {
+        $code->($f);
+        $self->SetFeature($f) if $in_place;
+    };
+}
+
+sub ForGeometries {
+    my $self = shift;
+    my $code = shift;
+    my $in_place = shift;
+    $self->ResetReading;
+    while (my $f = $self->GetNextFeature) {
+        my $g = $f->Geometry();
+        $code->($g);
+        if ($in_place) {
+            $f->Geometry($g);
+            $self->SetFeature($f);
+        }
+    }
+}
+
+sub GetFieldNames {
+    my $self = shift;
+    my $d = $self->GetDefn;
+    my @ret;
+    for (my $i = 0; $i < $d->GetFieldCount; $i++) {
+        push @ret, $d->GetFieldDefn($i)->Name();
+    }
+    for (my $i = 0; $i < $d->GetGeomFieldCount; $i++) {
+        push @ret, $d->GetGeomFieldDefn($i)->Name();
+    }
+    return @ret;
+}
+
+sub GetFieldDefn {
+    my ($self, $name) = @_;
+    my $d = $self->GetDefn;
+    for (my $i = 0; $i < $d->GetFieldCount; $i++) {
+        my $fd = $d->GetFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    for (my $i = 0; $i < $d->GetGeomFieldCount; $i++) {
+        my $fd = $d->GetGeomFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GeometryType {
+    my $self = shift;
+    my $d = $self->GetDefn;
+    my $fd = $d->GetGeomFieldDefn(0);
+    return $fd->Type if $fd;
+}
+
+sub SpatialReference {
+    my($self, $field, $sr) = @_;
+    my $d = $self->GetDefn;
+    my $i;
+    if (not defined $field or (blessed($field) and $field->isa('Geo::OSR::SpatialReference'))) {
+        $i = 0;
+    } else {
+        $i = $d->GetGeomFieldIndex($field);
+    }
+    my $d2 = $d->GetGeomFieldDefn($i);
+    $d2->SpatialReference($sr) if defined $sr;
+    return $d2->SpatialReference() if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::FeatureDefn;
+use strict;
+use warnings;
+use Encode;
+use Carp;
+use Scalar::Util 'blessed';
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::Feature::DEFNS{$self};
+    delete $Geo::OGR::Layer::DEFNS{$self};
+}
+
+*Name = *GetName;
+
+sub GetSchema {
+    my $self = shift;
+    carp "Schema of a feature definition should not be set directly." if @_;
+    if (@_ and @_ % 2 == 0) {
+        my %schema = @_;
+        if ($schema{Fields}) {
+            for my $field (@{$schema{Fields}}) {
+                $self->AddField($field);
+            }
+        }
+    }
+    my %schema;
+    $schema{Name} = $self->Name();
+    $schema{StyleIgnored} = $self->StyleIgnored();
+    $schema{Fields} = [];
+    for my $i (0..$self->GetFieldCount-1) {
+        my $s = $self->GetFieldDefn($i)->Schema;
+        push @{$schema{Fields}}, $s;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        my $s = $self->GetGeomFieldDefn($i)->Schema;
+        push @{$schema{Fields}}, $s;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*Schema = *GetSchema;
+
+sub AddField {
+    my $self = shift;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    my %params;
+    if (@_ == 0) {
+    } elsif (ref($_[0]) eq 'HASH') {
+        %params = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %params = @_;
+    }
+    $params{Type} = '' unless defined $params{Type};
+    if (exists $Geo::OGR::FieldDefn::TYPE_STRING2INT{$params{Type}}) {
+        my $fd = Geo::OGR::FieldDefn->new(%params);
+        $self->AddFieldDefn($fd);
+    } else {
+        my $fd = Geo::OGR::GeomFieldDefn->new(%params);
+        $self->AddGeomFieldDefn($fd);
+    }
+}
+
+sub DeleteField {
+    my ($self, $name) = @_;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    for my $i (0..$self->GetFieldCount-1) {
+        confess "Non-geometry fields cannot be deleted." if $self->GetFieldDefn($i)->Name eq $name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        $self->DeleteGeomFieldDefn($i) if $self->GetGeomFieldDefn($i)->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GetFieldNames {
+    my $self = shift;
+    my @names = ();
+    for my $i (0..$self->GetFieldCount-1) {
+        push @names, $self->GetFieldDefn($i)->Name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        push @names, $self->GetGeomFieldDefn($i)->Name;
+    }
+    return @names;
+}
+
+sub GetFieldDefn {
+    my ($self, $name) = @_;
+    for my $i (0..$self->GetFieldCount-1) {
+        my $fd = $self->GetFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    for my $i (0..$self->GetGeomFieldCount-1) {
+        my $fd = $self->GetGeomFieldDefn($i);
+        return $fd if $fd->Name eq $name;
+    }
+    confess "No such field: '$name'.";
+}
+
+sub GeomType {
+    my ($self, $type) = @_;
+    confess "Read-only definition." if $Geo::OGR::Feature::DEFNS{$self} or $Geo::OGR::Layer::DEFNS{$self};
+    if (defined $type) {
+        confess "Unknown geometry data type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        SetGeomType($self, $type);
+    }
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)} if defined wantarray;
+}
+*GeometryType = *GeomType;
+
+sub GeometryIgnored {
+    my $self = shift;
+    SetGeometryIgnored($self, $_[0]) if @_;
+    IsGeometryIgnored($self) if defined wantarray;
+}
+
+sub StyleIgnored {
+    my $self = shift;
+    SetStyleIgnored($self, $_[0]) if @_;
+    IsStyleIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::Feature;
+use strict;
+use warnings;
+use vars qw /%GEOMETRIES %DEFNS/;
+use Carp;
+use Encode;
+use Scalar::Util 'blessed';
+
+sub FETCH {
+    my($self, $index) = @_;
+    my $i;
+    eval {$i = $self->_GetFieldIndex($index)};
+    $self->GetField($i) unless $@;
+    $i = $self->_GetGeomFieldIndex($index);
+    $self->GetGeometry($i);
+}
+
+sub STORE {
+    my $self = shift;
+    my $index = shift;
+    my $i;
+    eval {$i = $self->_GetFieldIndex($index)};
+    $self->SetField($i, @_) unless $@;
+    $i = $self->_GetGeomFieldIndex($index);
+    $self->SetGeometry($i, @_);
+}
+
+sub FID {
+    my $self = shift;
+    $self->SetFID($_[0]) if @_;
+    return unless defined wantarray;
+    $self->GetFID;
+}
+
+sub StyleString {
+    my $self = shift;
+    $self->SetStyleString($_[0]) if @_;
+    return unless defined wantarray;
+    $self->GetStyleString;
+}
+
+sub Validate {
+    my $self = shift;
+    my $flags = 0;
+    for my $flag (@_) {
+        my $f = eval '$Geo::OGR::'.uc($flag);
+        $flags |= $f;
+    }
+    _Validate($self, $flags);
+}
+
+sub GetSchema {
+    my $self = shift;
+    confess "Schema of a feature cannot be set directly." if @_;
+    return $self->GetDefnRef->Schema;
+}
+*Schema = *GetSchema;
+
+sub Row {
+    my $self = shift;
+    my $nf = $self->GetFieldCount;
+    my $ngf = $self->GetGeomFieldCount;
+    if (@_) { # update
+        my %row;
+        if (@_ == 1 and ref($_[0]) eq 'HASH') {
+            %row = %{$_[0]};
+        } elsif (@_ and @_ % 2 == 0) {
+            %row = @_;
+        } else {
+            confess 'Usage: $feature->Row(%FeatureData).';
+        }
+        $self->SetFID($row{FID}) if defined $row{FID};
+        #$self->Geometry($schema, $row{Geometry}) if $row{Geometry};
+        for my $name (keys %row) {
+            next if $name eq 'FID';
+            if ($name eq 'Geometry') {
+                $self->SetGeometry(0, $row{$name});
+                next;
+            }
+            my $f = 0;
+            for my $i (0..$nf-1) {
+                if ($self->GetFieldDefnRef($i)->Name eq $name) {
+                    $self->SetField($i, $row{$name});
+                    $f = 1;
+                    last;
+                }
+            }
+            next if $f;
+            for my $i (0..$ngf-1) {
+                if ($self->GetGeomFieldDefnRef($i)->Name eq $name) {
+                    $self->SetGeometry($i, $row{$name});
+                    $f = 1;
+                    last;
+                }
+            }
+            next if $f;
+            carp "Feature->Row: Unknown field: '$name'.";
+        }
+    }
+    return unless defined wantarray;
+    my %row = ();
+    for my $i (0..$nf-1) {
+        my $name = $self->GetFieldDefnRef($i)->Name;
+        $row{$name} = $self->GetField($i);
+    }
+    for my $i (0..$ngf-1) {
+        my $name = $self->GetGeomFieldDefnRef($i)->Name;
+        $name = 'Geometry' if $name eq '';
+        $row{$name} = $self->GetGeometry($i);
+    }
+    $row{FID} = $self->GetFID;
+    #$row{Geometry} = $self->Geometry;
+    return \%row;
+}
+
+sub Tuple {
+    my $self = shift;
+    my $nf = $self->GetFieldCount;
+    my $ngf = $self->GetGeomFieldCount;
+    if (@_) {
+        my $FID;
+        $FID = shift if @_ == $nf + $ngf + 1;
+        $self->SetFID($FID) if defined $FID;
+        my $values = \@_;
+        if (@$values != $nf + $ngf) {
+            my $n = $nf + $ngf;
+            confess "Too many or too few attribute values for a feature (need $n).";
+        }
+        my $index = 0; # index to non-geometry and geometry fields
+        for my $i (0..$nf-1) {
+            $self->SetField($i, $values->[$i]);
+        }
+        for my $i (0..$ngf-1) {
+            $self->SetGeometry($i, $values->[$nf+$i]);
+        }
+    }
+    return unless defined wantarray;
+    my @ret = ($self->GetFID);
+    for my $i (0..$nf-1) {
+        my $v = $self->GetField($i);
+        push @ret, $v;
+    }
+    for my $i (0..$ngf-1) {
+        my $v = $self->GetGeometry($i);
+        push @ret, $v;
+    }
+    return @ret;
+}
+
+sub GetDefn {
+    my $self = shift;
+    my $defn = $self->GetDefnRef;
+    $DEFNS{$defn} = $self;
+    return $defn;
+}
+
+*GetFieldNames = *Geo::OGR::Layer::GetFieldNames;
+*GetFieldDefn = *Geo::OGR::Layer::GetFieldDefn;
+
+sub _GetFieldIndex {
+    my($self, $field) = @_;
+    if ($field =~ /^\d+$/) {
+        return $field if $field >= 0 and $field < $self->GetFieldCount;
+    } else {
+        for my $i (0..$self->GetFieldCount-1) {
+            return $i if $self->GetFieldDefnRef($i)->Name eq $field;
+        }
+    }
+    confess "No such field: '$field'.";
+}
+
+sub GetField {
+    my($self, $field) = @_;
+    $field = $self->_GetFieldIndex($field);
+    return unless IsFieldSet($self, $field);
+    my $type = GetFieldType($self, $field);
+    if ($type == $Geo::OGR::OFTInteger) {
+        return GetFieldAsInteger($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTInteger64) {
+        return GetFieldAsInteger64($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTReal) {
+        return GetFieldAsDouble($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTString) {
+        return GetFieldAsString($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTIntegerList) {
+        my $ret = GetFieldAsIntegerList($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTInteger64List) {
+        my $ret = GetFieldAsInteger64List($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTRealList) {
+        my $ret = GetFieldAsDoubleList($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTStringList) {
+        my $ret = GetFieldAsStringList($self, $field);
+        return wantarray ? @$ret : $ret;
+    }
+    if ($type == $Geo::OGR::OFTBinary) {
+        return GetFieldAsString($self, $field);
+    }
+    if ($type == $Geo::OGR::OFTDate) {
+        my @ret = GetFieldAsDateTime($self, $field);
+        # year, month, day, hour, minute, second, timezone
+        return wantarray ? @ret[0..2] : [@ret[0..2]];
     }
+    if ($type == $Geo::OGR::OFTTime) {
+        my @ret = GetFieldAsDateTime($self, $field);
+        return wantarray ? @ret[3..6] : [@ret[3..6]];
+    }
+    if ($type == $Geo::OGR::OFTDateTime) {
+        return GetFieldAsDateTime($self, $field);
+    }
+    confess "Perl bindings do not support field type '$Geo::OGR::FieldDefn::TYPE_INT2STRING{$type}'.";
+}
+
+sub UnsetField {
+    my($self, $field) = @_;
+    $field = $self->_GetFieldIndex($field);
+    _UnsetField($self, $field);
+}
+
+sub SetField {
+    my $self = shift;
+    my $field = shift;
+    $field = $self->_GetFieldIndex($field);
+    if (@_ == 0 or !defined($_[0])) {
+        _UnsetField($self, $field);
+        return;
+    }
+    my $list = ref($_[0]) ? $_[0] : [@_];
+    my $type = GetFieldType($self, $field);
+    if ($type == $Geo::OGR::OFTInteger or
+        $type == $Geo::OGR::OFTInteger64 or
+        $type == $Geo::OGR::OFTReal or
+        $type == $Geo::OGR::OFTString or
+        $type == $Geo::OGR::OFTBinary)
     {
-        package Geo::OGR::Driver;
-	use strict;
-	use vars qw /@CAPABILITIES %CAPABILITIES/;
-	@CAPABILITIES = qw/CreateDataSource DeleteDataSource/; 
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::ODrC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-        sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-	*Create = *CreateDataSource;
-	*Copy = *CopyDataSource;
-	*OpenDataSource = *Open;
-	*Delete = *DeleteDataSource;
-	*Name = *GetName;
-
-	package Geo::OGR::DataSource;
-	use Carp;
-	use strict;
-	use vars qw /@CAPABILITIES %CAPABILITIES %LAYERS/;
-	@CAPABILITIES = qw/CreateLayer DeleteLayer/;
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::ODsC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-	sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-	*GetDriver = *_GetDriver;
-	sub new {
-	    my $pkg = shift;
-	    return Geo::OGR::Open(@_);
-	}
-	sub Open {
-	    return Geo::OGR::Open(@_);
-	}
-	sub OpenShared {
-	    return Geo::OGR::OpenShared(@_);
-	}
-	sub ExecuteSQL {
-	    my $self = shift;
-	    my $layer = $self->_ExecuteSQL(@_);
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub Layer {
-	    my($self, $name) = @_;
-	    my $layer;
-	    if (defined $name) {
-		$layer = _GetLayerByName($self, "$name");
-		croak "$name is not a layer in this datasource" if (not $layer and not $name =~ /^\d+$/);
-		$layer = _GetLayerByIndex($self, $name+0) unless $layer;
-	    } else {
-		$layer = _GetLayerByIndex($self, 0);
-	    }
-	    croak "the data source does not appear to have a layer with name '$name'" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub Layers {
-	    my $self = shift;
-	    my @names;
-	    for my $i (0..$self->GetLayerCount-1) {
-		my $layer = _GetLayerByIndex($self, $i);
-		push @names, $layer->GetName;
-	    }
-	    return @names;
-	}
-	sub GetLayerByIndex {
-	    my($self, $index) = @_;
-	    $index = 0 unless defined $index;
-	    my $layer = _GetLayerByIndex($self, $index+0);
-	    croak "the data source does not appear to have a layer with index '$index'" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub GetLayerByName {
-	    my($self, $name) = @_;
-	    my $layer = _GetLayerByName($self, "$name");
-	    croak "the data source does not appear to have a layer with name $name" unless $layer;
-	    $LAYERS{tied(%$layer)} = $self;
-	    return $layer;
-	}
-	sub CreateLayer {
-	    my $self = shift;
-	    my %defaults = (Name => 'unnamed',
-			    SRS => undef, 
-			    GeometryType => 'Unknown', 
-			    Options => [], 
-			    Schema => undef,
-			    Fields => undef);
-	    my %params;
-	    if (ref($_[0]) eq 'HASH') {
-		%params = %{$_[0]};
-	    } else {
-		($params{Name}, $params{SRS}, $params{GeometryType}, $params{Options}, $params{Schema}) = @_;
-	    }
-	    for (keys %params) {
-		carp "unknown parameter $_ in Geo::OGR::DataSource->CreateLayer" unless exists $defaults{$_};
-	    }
-	    for (keys %defaults) {
-		$params{$_} = $defaults{$_} unless defined $params{$_};
-	    }
-	    $params{GeometryType} = $params{Schema}->{GeometryType} if 
-		($params{Schema} and exists $params{Schema}->{GeometryType});
-	    $params{GeometryType} = $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}} if 
-		exists $Geo::OGR::Geometry::TYPE_STRING2INT{$params{GeometryType}};
-	    my $layer = _CreateLayer($self, $params{Name}, $params{SRS}, $params{GeometryType}, $params{Options});
-	    $LAYERS{tied(%$layer)} = $self;
-	    if ($params{Fields}) {
-		$params{Schema} = {} unless $params{Schema};
-		$params{Schema}{Fields} = $params{Fields};
-	    }
-	    $layer->Schema(%{$params{Schema}}) if $params{Schema};
-	    return $layer;
-	}
-	sub DeleteLayer {
-	    my $self = shift;
-	    my $name;
-	    if (@_ == 2) {
-		my %param = @_;
-		_DeleteLayer($self, $param{index}), return if exists $param{index};
-		$name = $param{name};
-	    } else {
-		$name = shift;
-	    }
-	    my $index;
-	    for my $i (0..$self->GetLayerCount-1) {
-		my $layer = _GetLayerByIndex($self, $i);
-		$index = $i, last if $layer->GetName eq $name;
-	    }
-	    $index = $name unless defined $index;
-	    _DeleteLayer($self, $index) if defined $index;
-	}
-
-	package Geo::OGR::Layer;
-	use strict;
-	use Carp;
-	use Scalar::Util 'blessed';
-	use vars qw /@CAPABILITIES %CAPABILITIES/;
-	@CAPABILITIES = qw/RandomRead SequentialWrite RandomWrite 
-		   FastSpatialFilter FastFeatureCount FastGetExtent 
-		   CreateField DeleteField ReorderFields AlterFieldDefn
-                   Transactions DeleteFeature FastSetNextByIndex
-                   StringsAsUTF8 IgnoreFields/;
-	for my $s (@CAPABILITIES) {
-	    my $cap = eval "\$Geo::OGR::OLC$s";
-	    $CAPABILITIES{$s} = $cap;
-	}
-	sub DESTROY {
-	    my $self;
-	    if ($_[0]->isa('SCALAR')) {
-		$self = $_[0];
-	    } else {
-		return unless $_[0]->isa('HASH');
-		$self = tied(%{$_[0]});
-		return unless defined $self;
-	    }
-	    delete $ITERATORS{$self};
-	    if (exists $OWNER{$self}) {
-		delete $OWNER{$self};
-	    }
-	    $self->RELEASE_PARENTS();
-	}
-	sub RELEASE_PARENTS {
-	    my $self = shift;
-	    delete $Geo::OGR::DataSource::LAYERS{$self};
-	}
-	sub Capabilities {
-	    return @CAPABILITIES if @_ == 0;
-	    my $self = shift;
-	    my @cap;
-	    for my $cap (@CAPABILITIES) {
-		push @cap, $cap if _TestCapability($self, $CAPABILITIES{$cap});
-	    }
-	    return @cap;
-	}
-	sub TestCapability {
-	    my($self, $cap) = @_;
-	    return _TestCapability($self, $CAPABILITIES{$cap});
-	}
-        sub DataSource {
-	    my $self = shift;
-	    return $Geo::OGR::DataSource::LAYERS{$self};
-	}
-	sub HasField {
-	    my($self, $fn) = @_;
-	    eval {
-		$fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-		$self->GetLayerDefn->GetFieldDefn($fn);
-	    };
-	    return $@ eq '';
-	}
-        sub GetField {
-	    my($self, $fn) = @_;
-	    $fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-	    return $self->GetLayerDefn->GetFieldDefn($fn)->Schema;
-	}
-	sub CreateField {
-	    my $self = shift;
-	    my $fd = shift;
-	    if (blessed($fd) and $fd->isa('Geo::OGR::FieldDefn')) {
-		my $n = $fd->Schema->{Name};
-		croak "the layer already has a field with name '$n'" if $self->HasField($n);
-		my $a = shift || 1;
-		_CreateField($self, $fd, $a);
-	    } else {
-		$fd = Geo::OGR::FieldDefn->create($fd, @_);
-		my $n = $fd->Schema->{Name};
-		croak "the layer already has a field with name '$n'" if $self->HasField($n);
-		_CreateField($self, $fd); # approximation flag cannot be set using this method
-	    }
-	}
-        sub AlterField {
-	    my $self = shift;
-	    my $fn = shift;
-	    my $index = $fn;	    
-	    $index = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /^\d+$/;
-	    my $field = $self->GetLayerDefn->GetFieldDefn($index);
-	    my $definition = Geo::OGR::FieldDefn->create(@_);
-	    my $flags = 0;
-	    my %params = @_;
-	    $flags |= 1 if $params{Name};
-	    $flags |= 2 if $params{Type};
-	    $flags |= 4 if $params{Width};
-	    AlterFieldDefn($self, $index, $definition, $flags);
-	}
-	sub DeleteField {
-	    my($self, $fn) = @_;
-	    $fn = $self->GetLayerDefn->GetFieldIndex($fn) unless $fn =~ /\d+/;
-	    _DeleteField($self, $fn);
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %schema = @_;
-		# the Name and GeometryType cannot be set
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    $schema{ApproxOK} = 1 unless defined $schema{ApproxOK};
-		    _CreateField($self, $fd, $schema{ApproxOK});
-		}
-	    }
-	    return unless defined wantarray;
-	    return $self->GetLayerDefn->Schema;
-	}
-	sub Row {
-	    my $self = shift;
-	    my %row;
-	    my $update;
-	    if (@_ > 0 and ref($_[0])) { # undocumented hack: the first argument may be the schema
-		$update = @_ > 1;
-		%row = @_[1..$#$_];
-	    } else {
-		$update = @_ > 0;
-		%row = @_;
-	    }
-	    my $feature = defined $row{FID} ? $self->GetFeature($row{FID}) : $self->GetNextFeature;
-	    return unless $feature;
-	    my $ret;
-	    if (defined wantarray) {
-		$ret = $feature->Row(@_);
-	    } else {
-		$feature->Row(@_);
-	    }
-	    $self->SetFeature($feature) if $update;
-	    return unless defined wantarray;
-	    return $ret;
-	}
-	sub Tuple {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    my $FID = shift;
-	    my $feature = defined $FID ? $self->GetFeature($FID) : $self->GetNextFeature;
-	    return unless $feature;
-	    my $set = @_ > 0;
-	    unshift @_, $feature->GetFID if $set;
-	    my @ret;
-	    if (defined wantarray) {
-		@ret = $feature->Tuple($schema, @_);
-	    } else {
-		$feature->Tuple($schema, @_);
-	    }
-	    $self->SetFeature($feature) if $set;
-	    return unless defined wantarray;
-	    return @ret;
-	}
-	sub SpatialFilter {
-	    my $self = shift;
-	    $self->SetSpatialFilter($_[0]) if @_ == 1;
-	    $self->SetSpatialFilterRect(@_) if @_ == 4;
-	    return unless defined wantarray;
-	    $self->GetSpatialFilter;
-	}
-	sub InsertFeature {
-	    my $self = shift;
-	    my $feature = shift;
-	    croak "InsertFeature requires the feature data in an object or in a referenced hash or array" unless ref($feature);
-	    my $schema = shift;
-	    $schema = $self->Schema unless $schema;
-	    my $new = Geo::OGR::Feature->create($schema);
-	    if (ref($feature) eq 'HASH') {
-		$new->Row($schema, %$feature);
-	    } elsif (ref($feature) eq 'ARRAY') {
-		$new->Tuple($schema, @$feature);
-	    } elsif (blessed($feature) and $feature->isa('Geo::OGR::Feature')) {
-		$new->Row($schema, $feature->Row);
-	    }
-	    $self->CreateFeature($new);
-	}
-	sub ForFeatures {
-	    my $self = shift;
-	    my $code = shift;
-	    my $in_place = shift;
-	    $self->ResetReading;
-	    while (my $f = $self->GetNextFeature) {
-		$code->($f);
-		$self->SetFeature($f) if $in_place;
-	    };
-	}
-	sub ForGeometries {
-	    my $self = shift;
-	    my $code = shift;
-	    my $in_place = shift;
-	    $self->ResetReading;
-	    while (my $f = $self->GetNextFeature) {
-		my $g = $f->Geometry();
-		$code->($g);
-		if ($in_place) {
-		    $f->Geometry($g);
-		    $self->SetFeature($f);
-		}
-	    }
-	}
-	sub GeometryType {
-	    my $self = shift;
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)};
-	}
-
-	package Geo::OGR::FeatureDefn;
-	use strict;
-	use Encode;
-	sub create {
-	    my $pkg = shift;
-	    my %schema;
-	    if (@_ == 1) {
-	        %schema = %{$_[0]};
-	    } else {
-	        %schema = @_;
-	    }
-	    my $self = Geo::OGRc::new_FeatureDefn($schema{Name});
-	    bless $self, $pkg;
-	    $self->GeometryType($schema{GeometryType});
-	    for my $fd (@{$schema{Fields}}) {
-		my $d;
-		if (ref($fd) eq 'HASH') {
-		    $d = Geo::OGR::FieldDefn->create(%$fd);
-		} else {
-		    $d = Geo::OGR::FieldDefn->create($fd->Schema);
-		}
-		AddFieldDefn($self, $d);
-	    }
-	    return $self;
-	}
-	*Name = *GetName;
-	sub Schema {
-	    my $self = shift;
-	    my %schema;
-	    if (@_) {
-		%schema = @_;
-		# the Name cannot be set
-		$self->GeomType($schema{GeometryType}) if exists $schema{GeometryType};
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    AddFieldDefn($self, $fd);
-		}
-	    }
-	    return unless defined wantarray;
-	    $schema{Name} = $self->GetName();
-	    $schema{GeometryType} = $self->GeomType();
-	    $schema{Fields} = [];
-	    for my $i (0..$self->GetFieldCount-1) {
-		my $s = $self->GetFieldDefn($i)->Schema;
-		$s->{Index} = $i;
-		push @{$schema{Fields}}, $s;
-	    }
-	    return wantarray ? %schema : \%schema;
-	}
-	sub GeomType {
-	    my($self, $type) = @_;
-	    if ($type) {
-		$type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type} if 
-		    $type and exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
-		SetGeomType($self, $type);
-	    }
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{GetGeomType($self)} if defined wantarray;
-	}
-	*GeometryType = *GeomType;
-	sub GeometryIgnored {
-	    my $self = shift;
-	    SetGeometryIgnored($self, $_[0]) if @_;
-	    IsGeometryIgnored($self) if defined wantarray;
-	}
-	sub StyleIgnored {
-	    my $self = shift;
-	    SetStyleIgnored($self, $_[0]) if @_;
-	    IsStyleIgnored($self) if defined wantarray;
-	}
-
-	package Geo::OGR::Feature;
-	use strict;
-	use vars qw /%GEOMETRIES/;
-	use Carp;
-	use Encode;
-	sub create {
-	    my $pkg = shift;
-	    $pkg->new(Geo::OGR::FeatureDefn->create(@_));
-	}
-	sub FETCH {
-	    my($self, $index) = @_;
-	    $self->GetField($index);
-	}
-	sub STORE {
-	    my $self = shift;
-	    $self->SetField(@_);
-	}
-	sub FID {
-	    my $self = shift;
-	    $self->SetFID($_[0]) if @_;
-	    return unless defined wantarray;
-	    $self->GetFID;
-	}
-	sub StyleString {
-	    my $self = shift;
-	    $self->SetStyleString($_[0]) if @_;
-	    return unless defined wantarray;
-	    $self->GetStyleString;
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %schema = @_;
-		# the Name and GeometryType cannot be set
-		for my $fd (@{$schema{Fields}}) {
-		    if (ref($fd) eq 'HASH') {
-			$fd = Geo::OGR::FieldDefn->create(%$fd);
-		    }
-		    $schema{ApproxOK} = 1 unless defined $schema{ApproxOK};
-		    CreateField($self, $fd, $schema{ApproxOK});
-		}
-	    }
-	    return unless defined wantarray;
-	    return $self->GetDefnRef->Schema;
-	}
-	sub Row {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    if (@_) { # update
-		my %row = ref($_[0]) ? %{$_[0]} : @_;
-		$self->SetFID($row{FID}) if defined $row{FID};
-		$self->Geometry($schema, $row{Geometry}) if $row{Geometry};
-		for my $fn (keys %row) {
-		    next if $fn eq 'FID';
-		    next if $fn eq 'Geometry';
-		    my $index = GetFieldIndex($self, $fn);
-		    next if $index < 0;
-		    $self->SetField($index, $row{$fn});
-		}
-	    }
-	    return unless defined wantarray;
-	    my %row = ();
-	    for my $field (@{$schema->{Fields}}) {
-		my $n = $field->{Name};
-		if (FieldIsList($self, $n)) {
-		    $row{$n} = [$self->GetField($n)];
-		} else {
-		    $row{$n} = $self->GetField($n);
-		}
-	    }
-	    $row{FID} = $self->GetFID;
-	    $row{Geometry} = $self->Geometry;
-	    return \%row;
-	}
-	sub Tuple {
-	    my $self = shift;
-	    # undocumented hack: the first argument may be the schema
-	    my $schema = ref($_[0]) ? shift : $self->Schema;
-	    my $FID = shift;
-	    if (defined $FID) {
-		$self->SetFID($FID);
-		my $geometry = shift;
-		$self->Geometry($schema, $geometry) if $geometry;
-		if (@_) {
-		    for my $field (@{$schema->{Fields}}) {
-			my $v = shift;
-			my $n = $field->{Name};
-			$self->SetField($n, $v);
-		    }
-		}
-	    }
-	    return unless defined wantarray;
-	    my @ret = ($self->GetFID, $self->Geometry);
-	    my $i = 0;
-	    for my $field (@{$schema->{Fields}}) {
-		if (FieldIsList($self, $i)) {
-		    push @ret, [$self->GetField($i++)];
-		} else {
-		    push @ret, $self->GetField($i++);
-		}
-	    }
-	    return @ret;
-	}
-	sub Index {
-	    my($self, $field) = @_;
-	    my $index;
-	    if ($field =~ /^\d+$/) {
-		$index = $field;
-	    } else {
-		$index = GetFieldIndex($self, "$field");
-	    }
-	    croak "the feature does not have a field with name '$field'" if $index < 0 or $index >= GetFieldCount($self);
-	    return $index;
-	}
-	sub GetFieldType {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    return $Geo::OGR::FieldDefn::TYPE_INT2STRING{_GetFieldType($self, $field)};
-	}
-	sub FieldIsList {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    my $type = _GetFieldType($self, $field);
-	    return 1 if ($type == $Geo::OGR::OFTIntegerList or
-			 $type == $Geo::OGR::OFTRealList or
-			 $type == $Geo::OGR::OFTStringList or
-			 $type == $Geo::OGR::OFTDate or
-			 $type == $Geo::OGR::OFTTime or
-			 $type == $Geo::OGR::OFTDateTime);
-	    return 0;
-	}
-	sub GetField {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    return undef unless IsFieldSet($self, $field);
-	    my $type = _GetFieldType($self, $field);
-	    if ($type == $Geo::OGR::OFTInteger) {
-		return GetFieldAsInteger($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTReal) {
-		return GetFieldAsDouble($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTString) {
-		return GetFieldAsString($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTIntegerList) {
-		my $ret = GetFieldAsIntegerList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    } 
-	    if ($type == $Geo::OGR::OFTRealList) {
-		my $ret = GetFieldAsDoubleList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    }
-	    if ($type == $Geo::OGR::OFTStringList) {
-		my $ret = GetFieldAsStringList($self, $field);
-		return wantarray ? @$ret : $ret;
-	    }
-	    if ($type == $Geo::OGR::OFTBinary) {
-		return GetFieldAsString($self, $field);
-	    }
-	    if ($type == $Geo::OGR::OFTDate) {
-		my @ret = GetFieldAsDateTime($self, $field);
-		# year, month, day, hour, minute, second, timezone
-		return wantarray ? @ret[0..2] : [@ret[0..2]];
-	    }
-	    if ($type == $Geo::OGR::OFTTime) {
-		my @ret = GetFieldAsDateTime($self, $field);
-		return wantarray ? @ret[3..6] : [@ret[3..6]];
-	    }
-	    if ($type == $Geo::OGR::OFTDateTime) {
-		return GetFieldAsDateTime($self, $field);
-	    }
-	    croak "GDAL does not have a field type whose constant is '$type'";
-	}
-	sub UnsetField {
-	    my($self, $field) = @_;
-	    $field = Index($self, $field);
-	    _UnsetField($self, $field);
-	}
-	sub SetField {
-	    my $self = shift;
-	    my $field = $_[0];
-	    $field = Index($self, $field);
-	    shift;
-	    if (@_ == 0 or !defined($_[0])) {
-		_UnsetField($self, $field);
-		return;
-	    }
-	    my $list = ref($_[0]) ? $_[0] : [@_];
-	    my $type = _GetFieldType($self, $field);
-	    if ($type == $Geo::OGR::OFTInteger or
-		$type == $Geo::OGR::OFTReal or
-		$type == $Geo::OGR::OFTString or
-		$type == $Geo::OGR::OFTBinary)
-	    {
-		_SetField($self, $field, $_[0]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTIntegerList) {
-		SetFieldIntegerList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTRealList) {
-		SetFieldDoubleList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTStringList) {
-		SetFieldStringList($self, $field, $list);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTDate) {
-		# year, month, day, hour, minute, second, timezone
-		for my $i (0..6) {
-		    $list->[$i] = 0 unless defined $list->[$i];
-		}
-		_SetField($self, $field, @$list[0..6]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTTime) {
-		$list->[3] = 0 unless defined $list->[3];
-		_SetField($self, $field, 0, 0, 0, @$list[0..3]);
-	    } 
-	    elsif ($type == $Geo::OGR::OFTDateTime) {
-		$list->[6] = 0 unless defined $list->[6];
-		_SetField($self, $field, @$list[0..6]);
-	    } 
-	    else {
-		croak "GDAL does not have a field type of number '$type'";
-	    }
-	}
-	sub Field {
-	    my $self = shift;
-	    my $field = shift;
-	    $self->SetField($field, @_) if @_;
-	    $self->GetField($field);
-	}
-	sub Geometry {
-	    my $self = shift;
-	    if (@_) {
-		# undocumented hack: the first argument may be the schema
-		my $schema = @_ == 2 ? shift : $self->Schema;
-		my $geometry = shift;
-		my $type = $schema->{GeometryType};
-		if (ref($geometry) eq 'HASH') {
-		    my $geom;
-		    eval {
-			$geom = Geo::OGR::Geometry->create(%$geometry);
-		    };
-		    if ($@) {
-			$geometry->{GeometryType} = $type;
-			$geom = Geo::OGR::Geometry->create(%$geometry);
-		    }
-		    unless ($type eq 'Unknown' or !$geom->GeometryType) {
-			croak "an attempt to insert a geometry with type '",$geom->GeometryType,"' into a feature with geometry type '$type'" unless $type eq $geom->GeometryType;
-		    }
-		    $self->SetGeometryDirectly($geom);
-		} else {
-		    unless ($type eq 'Unknown') {
-			croak "an attempt to insert a geometry with type '",$geometry->GeometryType,"' into a feature with geometry type '$type'" unless $type eq $geometry->GeometryType;
-		    }
-		    $self->SetGeometry($geometry);
-		}
-	    }
-	    return unless defined wantarray;
-            my $geometry = $self->GetGeometryRef();
-	    $geometry->Clone() if $geometry;
-	}
-	sub SetGeometryDirectly {
-	    _SetGeometryDirectly(@_);
-	    $GEOMETRIES{tied(%{$_[1]})} = $_[0];
-	}
-	sub GetGeometry {
-	    my $self = shift;
-	    my $geom = GetGeometryRef($self);
-	    $GEOMETRIES{tied(%$geom)} = $self if $geom;
-	    return $geom;
-	}
-	sub ReferenceGeometry {
-	    my $self = shift;
-	    SetGeometryDirectly($self, $_[0]) if @_;
-	    if (defined wantarray) {
-		my $geometry = GetGeometry($self);
-		return $geometry->Clone() if $geometry;
-	    }
-	}
-	sub SetFrom {
-	    my($self, $other) = @_;
-	    _SetFrom($self, $other), return if @_ <= 2;
-	    my $forgiving = $_[2];
-	    _SetFrom($self, $other, $forgiving), return if @_ <= 3;	    
-	    my $map = $_[3];
-	    my @list;
-	    for my $i (1..GetFieldCount($self)) {
-		push @list, ($map->{$i} || -1);
-	    }
-	    SetFromWithMap($self, $other, 1, \@list);
-	}
-
-	package Geo::OGR::FieldDefn;
-	use strict;
-	use vars qw /
-	    @FIELD_TYPES @JUSTIFY_TYPES
-	    %TYPE_STRING2INT %TYPE_INT2STRING
-	    %JUSTIFY_STRING2INT %JUSTIFY_INT2STRING
-	    /;
-        use Carp;
-	use Encode;
-	@FIELD_TYPES = qw/Integer IntegerList Real RealList String StringList 
-			WideString WideStringList Binary Date Time DateTime/;
-	@JUSTIFY_TYPES = qw/Undefined Left Right/;
-	for my $string (@FIELD_TYPES) {
-	    my $int = eval "\$Geo::OGR::OFT$string";
-	    $TYPE_STRING2INT{$string} = $int;
-	    $TYPE_INT2STRING{$int} = $string;
-	}
-	for my $string (@JUSTIFY_TYPES) {
-	    my $int = eval "\$Geo::OGR::OJ$string";
-	    $JUSTIFY_STRING2INT{$string} = $int;
-	    $JUSTIFY_INT2STRING{$int} = $string;
-	}
-	sub create {
-	    my $pkg = shift;
-	    my %param = ( Name => 'unnamed', Type => 'String' );
-	    if (@_ == 0) {
-	    } elsif (@_ == 1) {
-		$param{Name} = shift;
-	    } else {
-		my %known = map {$_ => 1} qw/Index Name Type Justify Width Precision/;
-		unless ($known{$_[0]}) {
-		    $param{Name} = shift;
-		    $param{Type} = shift;
-		} else {
-		    my %p = @_;
-		    for my $k (keys %known) {
-			$param{$k} = $p{$k} if exists $p{$k};
-		    }
-		}
-	    }
-	    croak "usage: Geo::OGR::FieldDefn->create(%params)" if ref($param{Name});
-	    $param{Type} = $TYPE_STRING2INT{$param{Type}} 
-	    if defined $param{Type} and exists $TYPE_STRING2INT{$param{Type}};
-	    $param{Justify} = $JUSTIFY_STRING2INT{$param{Justify}} 
-	    if defined $param{Justify} and exists $JUSTIFY_STRING2INT{$param{Justify}};
-	    my $self = Geo::OGRc::new_FieldDefn($param{Name}, $param{Type});
-	    if (defined($self)) {
-		bless $self, $pkg;
-		$self->Justify($param{Justify}) if exists $param{Justify};
-		$self->Width($param{Width}) if exists $param{Width};
-		$self->Precision($param{Precision}) if exists $param{Precision};
-	    }
-	    return $self;
-	}
-	sub Name {
-	    my $self = shift;
-	    SetName($self, $_[0]) if @_;
-	    GetName($self) if defined wantarray;
-	}
-	sub Type {
-	    my($self, $type) = @_;
-	    if (defined $type) {
-		$type = $TYPE_STRING2INT{$type} if $type and exists $TYPE_STRING2INT{$type};
-		SetType($self, $type);
-	    }
-	    return $TYPE_INT2STRING{GetType($self)} if defined wantarray;
-	}
-	sub Justify {
-	    my($self, $justify) = @_;
-	    if (defined $justify) {
-		$justify = $JUSTIFY_STRING2INT{$justify} if $justify and exists $JUSTIFY_STRING2INT{$justify};
-		SetJustify($self, $justify);
-	    }
-	    return $JUSTIFY_INT2STRING{GetJustify($self)} if defined wantarray;
-	}
-	sub Width {
-	    my $self = shift;
-	    SetWidth($self, $_[0]) if @_;
-	    GetWidth($self) if defined wantarray;
-	}
-	sub Precision {
-	    my $self = shift;
-	    SetPrecision($self, $_[0]) if @_;
-	    GetPrecision($self) if defined wantarray;
-	}
-	sub Ignored {
-	    my $self = shift;
-	    SetIgnored($self, $_[0]) if @_;
-	    IsIgnored($self) if defined wantarray;
-	}
-	sub Schema {
-	    my $self = shift;
-	    if (@_) {
-		my %param = @_;
- 		$self->Name($param{Name}) if exists $param{Name};
-		$self->Type($param{Type}) if exists $param{Type};
-		$self->Justify($param{Justify}) if exists $param{Justify};
-		$self->Width($param{Width}) if exists $param{Width};
-		$self->Precision($param{Precision}) if exists $param{Precision};
-	    }
-	    return unless defined wantarray;
-	    my %schema = ( Name => $self->Name, 
-			   Type  => $self->Type,
-			   Justify  => $self->Justify,
-			   Width  => $self->Width,
-			   Precision => $self->Precision );
-	    return wantarray ? %schema : \%schema;
-	}
-
-	package Geo::OGR::Geometry;
-	use strict;
-	use Carp;
-	use vars qw /
-            @GEOMETRY_TYPES @BYTE_ORDER_TYPES
-	    %TYPE_STRING2INT %TYPE_INT2STRING
-	    %BYTE_ORDER_STRING2INT %BYTE_ORDER_INT2STRING
-	    /;
-        @GEOMETRY_TYPES = qw/Unknown 
-			Point LineString Polygon 
-			MultiPoint MultiLineString MultiPolygon GeometryCollection 
-			None LinearRing
-			Point25D LineString25D Polygon25D 
-			MultiPoint25D MultiLineString25D MultiPolygon25D GeometryCollection25D/;
-	for my $string (@GEOMETRY_TYPES) {
-	    my $int = eval "\$Geo::OGR::wkb$string";
-	    $TYPE_STRING2INT{$string} = $int;
-	    $TYPE_INT2STRING{$int} = $string;
-	}
-	@BYTE_ORDER_TYPES = qw/XDR NDR/;
-	for my $string (@BYTE_ORDER_TYPES) {
-	    my $int = eval "\$Geo::OGR::wkb$string";
-	    $BYTE_ORDER_STRING2INT{$string} = $int;
-	    $BYTE_ORDER_INT2STRING{$int} = $string;
-	}
-	sub RELEASE_PARENTS {
-	    my $self = shift;
-	    delete $Geo::OGR::Feature::GEOMETRIES{$self};
-	}
-	sub create { # alternative constructor since swig created new cannot be overridden(?)
-	    my $pkg = shift;
-	    my($type, $wkt, $wkb, $gml, $json, $srs, $points, $arc);
-	    if (@_ == 1) {
-		$type = shift;
-	    } else {
-		my %param = @_;
-		$type = ($param{type} or $param{Type} or $param{GeometryType});
-		$srs = ($param{srs} or $param{SRS});
-		$wkt = ($param{wkt} or $param{WKT});
-		$wkb = ($param{wkb} or $param{WKB});
-		my $hex = ($param{hexewkb} or $param{HEXEWKB}); # PostGIS HEX EWKB
-		substr($hex, 10, 8) = '' if $hex; # remove SRID
-		$hex = ($param{hexwkb} or $param{HEXWKB}) unless $hex;
-		if ($hex) {
-		    $wkb = '';
-		    for (my $i = 0; $i < length($hex); $i+=2) {
-			$wkb .= chr(hex(substr($hex,$i,2)));
-		    }
-		}
-		$gml = ($param{gml} or $param{GML});
-		$json = ($param{geojson} or $param{GeoJSON});
-		$points = $param{Points};
-		$arc = ($param{arc} or $param{Arc});
-	    }
-	    $type = $TYPE_STRING2INT{$type} if defined $type and exists $TYPE_STRING2INT{$type};
-	    my $self;
-	    if (defined $wkt) {
-		$self = Geo::OGRc::CreateGeometryFromWkt($wkt, $srs);
-	    } elsif (defined $wkb) {
-		$self = Geo::OGRc::CreateGeometryFromWkb($wkb, $srs);
-	    } elsif (defined $gml) {
-		$self = Geo::OGRc::CreateGeometryFromGML($gml);
-	    } elsif (defined $json) {
-		$self = Geo::OGRc::CreateGeometryFromJson($json);
-	    } elsif (defined $type) {
-		croak "unknown GeometryType '$type' when creating a Geo::OGR::Geometry object" unless 
-		    exists($TYPE_STRING2INT{$type}) or exists($TYPE_INT2STRING{$type});
-		$self = Geo::OGRc::new_Geometry($type);
-	    } elsif (defined $arc) {
-		$self = Geo::OGRc::ApproximateArcAngles(@$arc);
-	    } else {
-		croak "missing a parameter when creating a Geo::OGR::Geometry object";
-	    }
-	    bless $self, $pkg if defined $self;
-	    $self->Points($points) if $points;
-	    return $self;
-	}
-	sub AsHEXWKB {
-	    my($self) = @_;
-	    my $wkb = _ExportToWkb($self, 1);
-	    my $hex = '';
-	    for (my $i = 0; $i < length($wkb); $i++) {
-		my $x = sprintf("%x", ord(substr($wkb,$i,1)));
-		$x = '0' . $x if length($x) == 1;
-		$hex .= uc($x);
-	    }
-	    return $hex;
-	}
-	sub AsHEXEWKB {
-	    my($self, $srid) = @_;
-	    my $hex = AsHEXWKB($self);
-	    if ($srid) {
-		my $s = sprintf("%x", $srid);
-		$srid = '';
-		do {
-		    if (length($s) > 2) {
-			$srid .= substr($s,-2,2);
-			substr($s,-2,2) = '';
-		    } elsif (length($s) > 1) {
-			$srid .= $s;
-			$s = '';
-		    } else {
-			$srid .= '0'.$s;
-			$s = '';
-		    }
-		} until $s eq '';
-	    } else {
-		$srid = '00000000';
-	    }
-	    while (length($srid) < 8) {
-		$srid .= '00';
-	    }
-	    substr($hex, 10, 0) = uc($srid);
-	    return $hex;
-	}
-	sub GeometryType {
-	    my $self = shift;
-	    return $TYPE_INT2STRING{$self->GetGeometryType};
-	}
-	sub CoordinateDimension {
-	    my $self = shift;
-	    SetCoordinateDimension($self, $_[0]) if @_;
-	    GetCoordinateDimension($self) if defined wantarray;
-	}
-	sub AddPoint {
-	    @_ == 4 ? AddPoint_3D(@_) : AddPoint_2D(@_);
-	}
-	sub SetPoint {
-	    @_ == 5 ? SetPoint_3D(@_) : SetPoint_2D(@_);
-	}
-	sub GetPoint {
-	    my($self, $i) = @_;
-	    $i = 0 unless defined $i;
-	    my $point = ($self->GetGeometryType & 0x80000000) == 0 ? GetPoint_2D($self, $i) : GetPoint_3D($self, $i);
-	    return @$point;
-	}
-	sub Point {
-	    my $self = shift;
-	    my $i;
-	    if (@_) {
-		my $t = $self->GetGeometryType;
-		if ($t == $Geo::OGR::wkbPoint) {
-		    shift if @_ > 2;
-		    $i = 0;
-		} elsif ($t == $Geo::OGR::wkbPoint25D) {
-		    shift if @_ > 3;
-		    $i = 0;
-		} else {
-		    my $i = shift;
-		}
-		SetPoint($self, $i, @_);
-	    }
-	    return GetPoint($self, $i) if defined wantarray;
-	}
-	sub Points {
-	    my $self = shift;
-	    my $t = $self->GetGeometryType;
-	    my $flat = ($t & 0x80000000) == 0;
-	    $t = $TYPE_INT2STRING{$t & ~0x80000000};
-	    my $points = shift;
-	    if ($points) {
-		Empty($self);
-		if ($t eq 'Unknown' or $t eq 'None' or $t eq 'GeometryCollection') {
-		    croak("can't set points of a geometry of type '$t'");
-		} elsif ($t eq 'Point') {
-		    # support both "Point" as a list of one point and one point
-		    if (ref($points->[0])) {
-			$flat ? 
-			    AddPoint_2D($self, @{$points->[0]}[0..1]) : 
-			    AddPoint_3D($self, @{$points->[0]}[0..2]);
-		    } else {
-			$flat ? 
-			    AddPoint_2D($self, @$points[0..1]) : 
-			    AddPoint_3D($self, @$points[0..2]);
-		    }
-		} elsif ($t eq 'LineString' or $t eq 'LinearRing') {
-		    if ($flat) {
-			for my $p (@$points) {
-			    AddPoint_2D($self, @$p[0..1]);
-			}
-		    } else{
-			for my $p (@$points) {
-			    AddPoint_3D($self, @$p[0..2]);
-			}
-		    }
-		} elsif ($t eq 'Polygon') {
-		    for my $r (@$points) {
-			my $ring = Geo::OGR::Geometry->create('LinearRing');
-			$ring->SetCoordinateDimension(3) unless $flat;
-			$ring->Points($r);
-			$self->AddGeometryDirectly($ring);
-		    }
-		} elsif ($t eq 'MultiPoint') {
-		    for my $p (@$points) {
-			my $point = Geo::OGR::Geometry->create($flat ? 'Point' : 'Point25D');
-			$point->Points($p);
-			$self->AddGeometryDirectly($point);
-		    }
-		} elsif ($t eq 'MultiLineString') {
-		    for my $l (@$points) {
-			my $linestring = Geo::OGR::Geometry->create($flat ? 'LineString' : 'LineString25D');
-			$linestring->Points($l);
-			$self->AddGeometryDirectly($linestring);
-		    }
-		} elsif ($t eq 'MultiPolygon') {
-		    for my $p (@$points) {
-			my $polygon = Geo::OGR::Geometry->create($flat ? 'Polygon' : 'Polygon25D');
-			$polygon->Points($p);
-			$self->AddGeometryDirectly($polygon);
-		    }
-		}
-	    }
-	    return unless defined wantarray;
-	    $self->_GetPoints($flat);
-	}
-	sub _GetPoints {
-	    my($self, $flat) = @_;
-	    my @points;
-	    my $n = $self->GetGeometryCount;
-	    if ($n) {
-		for my $i (0..$n-1) {
-		    push @points, $self->GetGeometryRef($i)->_GetPoints($flat);
-		}
-	    } else {
-		$n = $self->GetPointCount;
-		if ($n == 1) {
-		    push @points, $flat ? GetPoint_2D($self) : GetPoint_3D($self);
-		} else {
-		    my $i;
-		    if ($flat) {
-			for my $i (0..$n-1) {
-			    push @points, scalar GetPoint_2D($self, $i);
-			}
-		    } else {
-			for my $i (0..$n-1) {
-			    push @points, scalar GetPoint_3D($self, $i);
-			}
-		    }
-		}
-	    }
-	    return \@points;
-	}
-	sub ExportToWkb {
-	    my($self, $bo) = @_;
-	    $bo = $BYTE_ORDER_STRING2INT{$bo} if defined $bo and exists $BYTE_ORDER_STRING2INT{$bo};
-	    return _ExportToWkb($self, $bo);
-	}
-	sub ForceToMultiPoint {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiPoint($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToMultiLineString {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiLineString($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToMultiPolygon {
-	    my $self = shift;
-	    $self = Geo::OGR::ForceToMultiPolygon($self);
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	sub ForceToCollection {
-	    my $self = Geo::OGR::Geometry->create(GeometryType => 'GeometryCollection');
-	    for my $g (@_) {
-		$self->AddGeometry($g);
-	    }
-	    return $self;
-	}
-	*Collect = *ForceToCollection;
-	sub Dissolve {
-	    my $self = shift;
-	    my @c;
-	    my $n = $self->GetGeometryCount;
-	    if ($n > 0) {
-		for my $i (0..$n-1) {
-		    push @c, $self->GetGeometryRef($i)->Clone;
-		}
-	    } else {
-		push @c, $self;
-	    }
-	    return @c;
-	}
-	*AsText = *ExportToWkt;
-	*AsBinary = *ExportToWkb;
-	*AsGML = *ExportToGML;
-	*AsKML = *ExportToKML;
-	*AsJSON = *ExportToJson;
-	*BuildPolygonFromEdges = *Geo::OGR::BuildPolygonFromEdges;
-	*ForceToPolygon = *Geo::OGR::ForceToPolygon;
-	
-    }
-    sub GeometryType {
-	my($type_or_name) = @_;
-	if (defined $type_or_name) {
-	    return $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name} if 
-		exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name};
-	    return $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name} if 
-		exists $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name};
-	    croak "unknown geometry type constant value or name '$type_or_name'";
-	} else {
-	    return keys %Geo::OGR::Geometry::TYPE_STRING2INT;
-	}
-    }
-    sub RELEASE_PARENTS {
-    }
-    sub GeometryTypes {
-	return keys %Geo::OGR::Geometry::TYPE_STRING2INT;
-    }
-    sub Drivers {
-	my @drivers;
-	for my $i (0..GetDriverCount()-1) {
-	    push @drivers, _GetDriver($i);
-	}
-	return @drivers;
-    }
-    sub GetDriver {
-	my($name) = @_;
-	my $driver;
-	$driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
-	$driver = GetDriverByName("$name") unless $driver;
-	croak "OGR driver with name '$name' not found (maybe support for it was not built in?)" unless $driver;
-	return $driver;
-    }
-    *Driver = *GetDriver;
+        _SetField($self, $field, $_[0]);
+    }
+    elsif ($type == $Geo::OGR::OFTIntegerList) {
+        SetFieldIntegerList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTInteger64List) {
+        SetFieldInteger64List($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTRealList) {
+        SetFieldDoubleList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTStringList) {
+        SetFieldStringList($self, $field, $list);
+    }
+    elsif ($type == $Geo::OGR::OFTDate) {
+        # year, month, day, hour, minute, second, timezone
+        for my $i (0..6) {
+            $list->[$i] = 0 unless defined $list->[$i];
+        }
+        _SetField($self, $field, @$list[0..6]);
+    }
+    elsif ($type == $Geo::OGR::OFTTime) {
+        $list->[3] = 0 unless defined $list->[3];
+        _SetField($self, $field, 0, 0, 0, @$list[0..3]);
+    }
+    elsif ($type == $Geo::OGR::OFTDateTime) {
+        $list->[6] = 0 unless defined $list->[6];
+        _SetField($self, $field, @$list[0..6]);
+    }
+    else {
+        confess "Perl bindings do not support field type '$Geo::OGR::FieldDefn::TYPE_INT2STRING{$type}'.";
+    }
+}
+
+sub Field {
+    my $self = shift;
+    my $field = shift;
+    $self->SetField($field, @_) if @_;
+    $self->GetField($field);
+}
+
+sub _GetGeomFieldIndex {
+    my($self, $field) = @_;
+    if (not defined $field) {
+        return 0 if $self->GetGeomFieldCount > 0;
+    } if ($field =~ /^\d+$/) {
+        return $field if $field >= 0 and $field < $self->GetGeomFieldCount;
+    } else {
+        for my $i (0..$self->GetGeomFieldCount-1) {
+            return $i if $self->GetGeomFieldDefn($i)->Name eq $field;
+        }
+        return 0 if $self->GetGeomFieldCount > 0 and $field eq 'Geometry';
+    }
+    confess "No such field: '$field'.";
+}
+
+sub Geometry {
+    my $self = shift;
+    my $field = (ref($_[0]) eq '' or (@_ > 2 and @_ % 2 == 1)) ? shift : undef;
+    $field = $self->_GetGeomFieldIndex($field);
+    if (@_) {
+        my $type = $self->GetDefn->GetGeomFieldDefn($field)->Type;
+        my $geometry;
+        if (@_ == 1) {
+            $geometry = $_[0];
+        } elsif (@_ and @_ % 2 == 0) {
+            %$geometry = @_;
+        }
+        if (blessed($geometry) and $geometry->isa('Geo::OGR::Geometry')) {
+            confess "The type of the inserted geometry ('".$geometry->GeometryType."') is not the field type ('$type')."
+                if $type ne 'Unknown' and $type ne $geometry->GeometryType;
+            eval {
+                $self->SetGeomFieldDirectly($field, $geometry);
+            };
+            confess "$@" if $@;
+            $GEOMETRIES{tied(%{$geometry})} = $self;
+        } elsif (ref($geometry) eq 'HASH') {
+            $geometry->{GeometryType} = $type unless exists $geometry->{GeometryType};
+            eval {
+                $geometry = Geo::OGR::Geometry->new($geometry);
+            };
+            confess "The type of the inserted geometry ('".$geometry->GeometryType."') is not the field type ('$type')."
+                if $type ne 'Unknown' and $type ne $geometry->GeometryType;
+            eval {
+                $self->SetGeomFieldDirectly($field, $geometry);
+            };
+            confess "$@" if $@;
+        } else {
+            confess "'@_' does not define a geometry.";
+        }
+    }
+    return unless defined wantarray;
+    my $geometry = $self->GetGeomFieldRef($field);
+    return unless $geometry;
+    $GEOMETRIES{tied(%{$geometry})} = $self;
+    return $geometry;
+}
+*GetGeometry = *Geometry;
+*SetGeometry = *Geometry;
+
+sub SetFrom {
+    my($self, $other) = @_;
+    _SetFrom($self, $other), return if @_ <= 2;
+    my $forgiving = $_[2];
+    _SetFrom($self, $other, $forgiving), return if @_ <= 3;
+    my $map = $_[3];
+    my @list;
+    for my $i (1..GetFieldCount($self)) {
+        push @list, ($map->{$i} || -1);
+    }
+    SetFromWithMap($self, $other, 1, \@list);
+}
+
+
+
+
+package Geo::OGR::FieldDefn;
+use strict;
+use warnings;
+use vars qw /
+    %SCHEMA_KEYS
+    @TYPES @SUB_TYPES @JUSTIFY_VALUES
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    %SUB_TYPE_STRING2INT %SUB_TYPE_INT2STRING
+    %JUSTIFY_STRING2INT %JUSTIFY_INT2STRING
+    /;
+use Carp;
+use Encode;
+%SCHEMA_KEYS = map {$_ => 1} qw/Name Type SubType Justify Width Precision Nullable Default Ignored/;
+for (keys %Geo::OGR::) {
+    push(@TYPES, $1), next if /^OFT(\w+)/;
+    push(@SUB_TYPES, $1), next if /^OFST(\w+)/;
+    push(@JUSTIFY_VALUES, $1), next if /^OJ(\w+)/;
+}
+for my $string (@TYPES) {
+    my $int = eval "\$Geo::OGR::OFT$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@SUB_TYPES) {
+    my $int = eval "\$Geo::OGR::OFST$string";
+    $SUB_TYPE_STRING2INT{$string} = $int;
+    $SUB_TYPE_INT2STRING{$int} = $string;
+}
+for my $string (@JUSTIFY_VALUES) {
+    my $int = eval "\$Geo::OGR::OJ$string";
+    $JUSTIFY_STRING2INT{$string} = $int;
+    $JUSTIFY_INT2STRING{$int} = $string;
+}
+
+sub Types {
+    return @TYPES;
+}
+
+sub SubTypes {
+    return @SUB_TYPES;
+}
+
+sub JustifyValues {
+    return @JUSTIFY_VALUES;
+}
+
+sub Schema {
+    my $self = shift;
+    if (@_) {
+        my %args = @_;
+        for my $key (keys %SCHEMA_KEYS) {
+            eval '$self->'.$key.'($args{'.$key.'}) if exists $args{'.$key.'}';
+            croak $@ if $@;
+        }
+    }
+    return unless defined wantarray;
+    my %schema = ();
+    for my $key (keys %SCHEMA_KEYS) {
+        $schema{$key} = eval '$self->'.$key;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*GetSchema = *Schema;
+*SetSchema = *Schema;
+
+sub Name {
+    my $self = shift;
+    SetName($self, $_[0]) if @_;
+    GetName($self) if defined wantarray;
+}
+
+sub Type {
+    my($self, $type) = @_;
+    if (defined $type) {
+        confess "Unknown field type: '$type'." unless exists $TYPE_STRING2INT{$type};
+        $type = $TYPE_STRING2INT{$type};
+        SetType($self, $type);
+    }
+    return $TYPE_INT2STRING{GetType($self)} if defined wantarray;
+}
+
+sub SubType {
+    my($self, $sub_type) = @_;
+    if (defined $sub_type) {
+        confess "Unknown field sub type: '$sub_type'." unless exists $SUB_TYPE_STRING2INT{$sub_type};
+        $sub_type = $SUB_TYPE_STRING2INT{$sub_type};
+        SetSubType($self, $sub_type);
+    }
+    return $SUB_TYPE_INT2STRING{GetSubType($self)} if defined wantarray;
+}
+
+sub Justify {
+    my($self, $justify) = @_;
+    if (defined $justify) {
+        confess "Unknown justify value: '$justify'." unless exists $JUSTIFY_STRING2INT{$justify};
+        $justify = $JUSTIFY_STRING2INT{$justify} if exists $JUSTIFY_STRING2INT{$justify};
+        SetJustify($self, $justify);
+    }
+    return $JUSTIFY_INT2STRING{GetJustify($self)} if defined wantarray;
+}
+
+sub Width {
+    my $self = shift;
+    SetWidth($self, $_[0]) if @_;
+    GetWidth($self) if defined wantarray;
+}
+
+sub Precision {
+    my $self = shift;
+    SetPrecision($self, $_[0]) if @_;
+    GetPrecision($self) if defined wantarray;
+}
+
+sub Nullable {
+    my $self = shift;
+    SetNullable($self, $_[0]) if @_;
+    IsNullable($self) if defined wantarray;
+}
+
+sub Default {
+    my $self = shift;
+    SetDefault($self, $_[0]) if @_;
+    GetDefault($self) if defined wantarray;
+}
+
+sub Ignored {
+    my $self = shift;
+    SetIgnored($self, $_[0]) if @_;
+    IsIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::GeomFieldDefn;
+use strict;
+use warnings;
+use vars qw / %SCHEMA_KEYS /;
+use Carp;
+use Scalar::Util 'blessed';
+%SCHEMA_KEYS = map {$_ => 1} qw/Name Type SpatialReference Nullable Ignored/;
+
+sub Schema {
+    my $self = shift;
+    if (@_) {
+        my %args = @_;
+        for my $key (keys %SCHEMA_KEYS) {
+            eval '$self->'.$key.'($args{'.$key.'}) if exists $args{'.$key.'}';
+            croak $@ if $@;
+        }
+    }
+    return unless defined wantarray;
+    my %schema = ();
+    for my $key (keys %SCHEMA_KEYS) {
+        $schema{$key} = eval '$self->'.$key;
+    }
+    return wantarray ? %schema : \%schema;
+}
+*GetSchema = *Schema;
+*SetSchema = *Schema;
+
+sub Name {
+    my $self = shift;
+    SetName($self, $_[0]) if @_;
+    GetName($self) if defined wantarray;
+}
+
+sub Type {
+    my($self, $type) = @_;
+    if (defined $type) {
+        confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+        SetType($self, $type);
+    }
+    $Geo::OGR::Geometry::TYPE_INT2STRING{GetType($self)} if defined wantarray;
+}
+
+sub Types {
+  return @Geo::OGR::Geometry::GEOMETRY_TYPES;
+}
+
+sub SpatialReference {
+    my $self = shift;
+    SetSpatialRef($self, $_[0]) if @_;
+    GetSpatialRef($self) if defined wantarray;
+}
+
+sub Nullable {
+    my $self = shift;
+    SetNullable($self, $_[0]) if @_;
+    IsNullable($self) if defined wantarray;
+}
+
+sub Ignored {
+    my $self = shift;
+    SetIgnored($self, $_[0]) if @_;
+    IsIgnored($self) if defined wantarray;
+}
+
+
+
+
+package Geo::OGR::Geometry;
+use strict;
+use warnings;
+use Carp;
+use vars qw /
+    @BYTE_ORDER_TYPES @GEOMETRY_TYPES
+    %BYTE_ORDER_STRING2INT %BYTE_ORDER_INT2STRING
+    %TYPE_STRING2INT %TYPE_INT2STRING
+    /;
+ at BYTE_ORDER_TYPES = qw/XDR NDR/;
+for my $string (@BYTE_ORDER_TYPES) {
+    my $int = eval "\$Geo::OGR::wkb$string";
+    $BYTE_ORDER_STRING2INT{$string} = $int;
+    $BYTE_ORDER_INT2STRING{$int} = $string;
+}
+for (keys %Geo::OGR::) {
+    next if /^wkb25/;
+    next if /^wkb.DR/;
+    push(@GEOMETRY_TYPES, $1), next if /^wkb(\w+)/;
+}
+for my $string (@GEOMETRY_TYPES) {
+    my $int = eval "\$Geo::OGR::wkb$string";
+    $TYPE_STRING2INT{$string} = $int;
+    $TYPE_INT2STRING{$int} = $string;
+}
+
+sub ByteOrders {
+    return @BYTE_ORDER_TYPES;
+}
+
+sub GeometryTypes {
+    return @GEOMETRY_TYPES;
+}
+
+sub RELEASE_PARENTS {
+    my $self = shift;
+    delete $Geo::OGR::Feature::GEOMETRIES{$self};
+}
+
+sub ApproximateArcAngles {
+    my %p = @_;
+    my %default = ( Center => [0,0,0],
+                    PrimaryRadius => 1,
+                    SecondaryAxis => 1,
+                    Rotation => 0,
+                    StartAngle => 0,
+                    EndAngle => 360,
+                    MaxAngleStepSizeDegrees => 4 
+        );
+    for my $p (keys %p) {
+        if (exists $default{$p}) {
+            $p{$p} = $default{$p} unless defined $p{$p};
+        } else {
+            carp "Unknown named parameter: '$p'.";
+        }
+    }
+    for my $p (keys %default) {
+        $p{$p} = $default{$p} unless exists $p{$p};
+    }
+    confess "Usage: Center => [x,y,z]." unless ref($p{Center}) eq 'ARRAY';
+    for my $i (0..2) {
+        $p{Center}->[$i] = 0 unless defined $p{Center}->[$i];
+    }
+    return Geo::OGR::ApproximateArcAngles($p{Center}->[0], $p{Center}->[1], $p{Center}->[2], $p{PrimaryRadius}, $p{SecondaryAxis}, $p{Rotation}, $p{StartAngle}, $p{EndAngle}, $p{MaxAngleStepSizeDegrees});
+}
+
+sub As {
+    my $self = shift;
+    my %param;
+    if (@_ == 1 and ref($_[0]) eq 'HASH') {
+        %param = %{$_[0]};
+    } elsif (@_ % 2 == 0) {
+        %param = @_;
+    } else {
+        ($param{Format}, $param{x}) = @_;
+    }
+    $param{ByteOrder} = 'XDR' unless $param{ByteOrder};
+    my $f = $param{Format};
+    my $x = $param{x};
+    $x = $param{ByteOrder} unless defined $x;
+    if ($f =~ /text/i) {
+        return $self->AsText;
+    } elsif ($f =~ /wkt/i) {
+        if ($f =~ /iso/i) {
+            return $self->ExportToIsoWkt;
+        } else {
+            return $self->AsText;
+        }
+    } elsif ($f =~ /binary/i) {
+        return $self->AsBinary($x);        
+    } elsif ($f =~ /wkb/i) {
+        if ($f =~ /iso/i) {
+            return $self->ExportToIsoWkb;
+        } elsif ($f =~ /hexe/i) {
+            $param{srid} = 'XDR' unless $param{srid};
+            $x = $param{srid} unless defined $x;
+            return $self->AsHEXEWKB($x);
+        } elsif ($f =~ /hex/i) {
+            return $self->AsHEXWKB;
+        } else {
+            return $self->AsBinary($x);
+        }
+    } elsif ($f =~ /gml/i) {
+        return $self->AsGML;
+    } elsif ($f =~ /kml/i) {
+        return $self->AsKML;
+    } elsif ($f =~ /json/i) {
+        return $self->AsJSON;
+    } else {
+        confess "Unsupported format: $f.";
+    }
+}
+
+sub AsHEXWKB {
+    my ($self) = @_;
+    my $wkb = _ExportToWkb($self, 1);
+    my $hex = '';
+    for (my $i = 0; $i < length($wkb); $i++) {
+        my $x = sprintf("%x", ord(substr($wkb,$i,1)));
+        $x = '0' . $x if length($x) == 1;
+        $hex .= uc($x);
+    }
+    return $hex;
+}
+
+sub AsHEXEWKB {
+    my ($self, $srid) = @_;
+    my $hex = AsHEXWKB($self);
+    if ($srid) {
+        my $s = sprintf("%x", $srid);
+        $srid = '';
+        do {
+            if (length($s) > 2) {
+                $srid .= substr($s,-2,2);
+                substr($s,-2,2) = '';
+            } elsif (length($s) > 1) {
+                $srid .= $s;
+                $s = '';
+            } else {
+                $srid .= '0'.$s;
+                $s = '';
+            }
+        } until $s eq '';
+    } else {
+        $srid = '00000000';
+    }
+    while (length($srid) < 8) {
+        $srid .= '00';
+    }
+    substr($hex, 10, 0) = uc($srid);
+    return $hex;
+}
+
+sub GeometryType {
+    my $self = shift;
+    return $TYPE_INT2STRING{$self->GetGeometryType};
+}
+
+sub CoordinateDimension {
+    my $self = shift;
+    SetCoordinateDimension($self, $_[0]) if @_;
+    GetCoordinateDimension($self) if defined wantarray;
+}
+
+sub AddPoint {
+    @_ == 4 ? AddPoint_3D(@_) : AddPoint_2D(@_);
+}
+
+sub SetPoint {
+    @_ == 5 ? SetPoint_3D(@_) : SetPoint_2D(@_);
+}
+
+sub GetPoint {
+    my($self, $i) = @_;
+    $i = 0 unless defined $i;
+    my $point = ($self->GetGeometryType & 0x80000000) == 0 ? GetPoint_2D($self, $i) : GetPoint_3D($self, $i);
+    return @$point;
+}
+
+sub Point {
+    my $self = shift;
+    my $i;
+    if (@_) {
+        my $t = $self->GetGeometryType;
+        if ($t == $Geo::OGR::wkbPoint) {
+            shift if @_ > 2;
+            $i = 0;
+        } elsif ($t == $Geo::OGR::wkbPoint25D) {
+            shift if @_ > 3;
+            $i = 0;
+        } else {
+            my $i = shift;
+        }
+        SetPoint($self, $i, @_);
+    }
+    return GetPoint($self, $i) if defined wantarray;
+}
+
+sub Points {
+    my $self = shift;
+    my $t = $self->GetGeometryType;
+    my $flat = not Geo::OGR::GT_HasZ($t);
+    $t = Geo::OGR::GT_Flatten($t);
+    $t = $TYPE_INT2STRING{$t};
+    my $points = shift;
+    if ($points) {
+        Empty($self);
+        if ($t eq 'Unknown' or $t eq 'None' or $t eq 'GeometryCollection') {
+            confess "Can't set points of a geometry of type '$t'.";
+        } elsif ($t eq 'Point') {
+            # support both "Point" as a list of one point and one point
+            if (ref($points->[0])) {
+                $flat ?
+                    AddPoint_2D($self, @{$points->[0]}[0..1]) :
+                    AddPoint_3D($self, @{$points->[0]}[0..2]);
+            } else {
+                $flat ?
+                    AddPoint_2D($self, @$points[0..1]) :
+                    AddPoint_3D($self, @$points[0..2]);
+            }
+        } elsif ($t eq 'LineString' or $t eq 'LinearRing') {
+            if ($flat) {
+                for my $p (@$points) {
+                    AddPoint_2D($self, @$p[0..1]);
+                }
+            } else{
+                for my $p (@$points) {
+                    AddPoint_3D($self, @$p[0..2]);
+                }
+            }
+        } elsif ($t eq 'Polygon') {
+            for my $r (@$points) {
+                my $ring = Geo::OGR::Geometry->new('LinearRing');
+                $ring->SetCoordinateDimension(3) unless $flat;
+                $ring->Points($r);
+                $self->AddGeometryDirectly($ring);
+            }
+        } elsif ($t eq 'MultiPoint') {
+            for my $p (@$points) {
+                my $point = Geo::OGR::Geometry->new($flat ? 'Point' : 'Point25D');
+                $point->Points($p);
+                $self->AddGeometryDirectly($point);
+            }
+        } elsif ($t eq 'MultiLineString') {
+            for my $l (@$points) {
+                my $linestring = Geo::OGR::Geometry->new($flat ? 'LineString' : 'LineString25D');
+                $linestring->Points($l);
+                $self->AddGeometryDirectly($linestring);
+            }
+        } elsif ($t eq 'MultiPolygon') {
+            for my $p (@$points) {
+                my $polygon = Geo::OGR::Geometry->new($flat ? 'Polygon' : 'Polygon25D');
+                $polygon->Points($p);
+                $self->AddGeometryDirectly($polygon);
+            }
+        }
+    }
+    return unless defined wantarray;
+    $self->_GetPoints($flat);
+}
+
+sub _GetPoints {
+    my($self, $flat) = @_;
+    my @points;
+    my $n = $self->GetGeometryCount;
+    if ($n) {
+        for my $i (0..$n-1) {
+            push @points, $self->GetGeometryRef($i)->_GetPoints($flat);
+        }
+    } else {
+        $n = $self->GetPointCount;
+        if ($n == 1) {
+            push @points, $flat ? GetPoint_2D($self) : GetPoint_3D($self);
+        } else {
+            my $i;
+            if ($flat) {
+                for my $i (0..$n-1) {
+                    push @points, scalar GetPoint_2D($self, $i);
+                }
+            } else {
+                for my $i (0..$n-1) {
+                    push @points, scalar GetPoint_3D($self, $i);
+                }
+            }
+        }
+    }
+    return \@points;
+}
+
+sub ExportToWkb {
+    my($self, $bo) = @_;
+    if (defined $bo) {
+        confess "Unknown byte order: '$bo'." unless exists $BYTE_ORDER_STRING2INT{$bo};
+        $bo = $BYTE_ORDER_STRING2INT{$bo};
+    }
+    return _ExportToWkb($self, $bo);
+}
+
+sub ForceTo {
+    my $self = shift;
+    my $type = shift;
+    confess "Unknown geometry type: '$type'." unless exists $TYPE_STRING2INT{$type};
+    $type = $TYPE_STRING2INT{$type};
+    eval {
+        $self = Geo::OGR::ForceTo($self, $type, @_);
+    };
+    confess $@ if $@;
+    return $self;
+}
+
+sub ForceToLineString {
+    my $self = shift;
+    $self = Geo::OGR::ForceToLineString($self);
+    return $self;
+}
+
+sub ForceToMultiPoint {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiPoint($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToMultiLineString {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiLineString($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToMultiPolygon {
+    my $self = shift;
+    $self = Geo::OGR::ForceToMultiPolygon($self);
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+
+sub ForceToCollection {
+    my $self = Geo::OGR::Geometry->new(GeometryType => 'GeometryCollection');
+    for my $g (@_) {
+        $self->AddGeometry($g);
+    }
+    return $self;
+}
+*Collect = *ForceToCollection;
+
+sub Dissolve {
+    my $self = shift;
+    my @c;
+    my $n = $self->GetGeometryCount;
+    if ($n > 0) {
+        for my $i (0..$n-1) {
+            push @c, $self->GetGeometryRef($i)->Clone;
+        }
+    } else {
+        push @c, $self;
+    }
+    return @c;
+}
+*AsText = *ExportToWkt;
+*AsBinary = *ExportToWkb;
+*AsGML = *ExportToGML;
+*AsKML = *ExportToKML;
+*AsJSON = *ExportToJson;
+*BuildPolygonFromEdges = *Geo::OGR::BuildPolygonFromEdges;
+*ForceToPolygon = *Geo::OGR::ForceToPolygon;
+
+
+package Geo::OGR;
+use strict;
+use warnings;
+use Carp;
+
+sub GeometryType {
+    my($type_or_name) = @_;
+    if (defined $type_or_name) {
+        return $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name} if
+            exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type_or_name};
+        return $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name} if
+            exists $Geo::OGR::Geometry::TYPE_INT2STRING{$type_or_name};
+        confess "Unknown geometry type: '$type_or_name'.";
+    } else {
+        return @Geo::OGR::Geometry::GEOMETRY_TYPES;
+    }
+}
+
+sub GeometryTypeModify {
+    my($type, $modifier) = @_;
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_Flatten($type)} if $modifier =~ /flat/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_SetZ($type)} if $modifier =~ /z/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetCollection($type)} if $modifier =~ /collection/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetCurve($type)} if $modifier =~ /curve/i;
+    return $Geo::OGR::Geometry::TYPE_INT2STRING{GT_GetLinear($type)} if $modifier =~ /linear/i;
+    confess "Unknown geometry type modifier: '$modifier'.";
+}
+
+sub GeometryTypeTest {
+    my($type, $test, $type2) = @_;
+    confess "Unknown geometry type: '$type'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    $type = $Geo::OGR::Geometry::TYPE_STRING2INT{$type};
+    if (defined $type2) {
+        confess "Unknown geometry type: '$type2'." unless exists $Geo::OGR::Geometry::TYPE_STRING2INT{$type2};
+        $type2 = $Geo::OGR::Geometry::TYPE_STRING2INT{$type2};
+    } else {
+        confess "Usage: GeometryTypeTest(type1, 'is_subclass_of', type2)." if $test =~ /subclass/i;
+    }
+    return GT_HasZ($type) if $test =~ /z/i;
+    return GT_IsSubClassOf($type, $type2) if $test =~ /subclass/i;
+    return GT_IsCurve($type) if $test =~ /curve/i;
+    return GT_IsSurface($type) if $test =~ /surface/i;
+    return GT_IsNonLinear($type) if $test =~ /linear/i;
+    confess "Unknown geometry type test: '$test'.";
+}
+
+sub RELEASE_PARENTS {
+}
+
+*ByteOrders = *Geo::OGR::Geometry::ByteOrders;
+*GeometryTypes = *Geo::OGR::Geometry::GeometryTypes;
+
+sub GetDriverNames {
+    my @names;
+    for my $i (0..GetDriverCount()-1) {
+        push @names, _GetDriver($i)->Name;
+    }
+    return @names;
+}
+
+sub Drivers {
+    my @drivers;
+    for my $i (0..GetDriverCount()-1) {
+        push @drivers, _GetDriver($i);
+    }
+    return @drivers;
+}
+
+sub GetDriver {
+    my($name) = @_;
+    $name = 0 unless defined $name;
+    my $driver;
+    $driver = _GetDriver($name) if $name =~ /^\d+$/; # is the name an index to driver list?
+    $driver = GetDriverByName("$name") unless $driver;
+    return $driver if $driver;
+    confess "Driver not found: '$name'. Maybe support for it was not built in?";
+}
+*Driver = *GetDriver;
 1;
diff --git a/swig/perl/lib/Geo/OSR.dox b/swig/perl/lib/Geo/OSR.dox
index 89fc7d2..95c15bb 100644
--- a/swig/perl/lib/Geo/OSR.dox
+++ b/swig/perl/lib/Geo/OSR.dox
@@ -1,51 +1,51 @@
-## @ignore Geo::OSRc
-
 ## @class Geo::OSR
+# @brief Base class for projection related classes.
+
+## @cmethod @Projections()
+# @return list of known projections.
+
+## @cmethod @Parameters()
+# @return list of known projection parameters.
+
+## @cmethod @LinearUnits()
+# @return list of known linear units.
 
-## @ignore UseExceptions
-## @ignore DontUseExceptions
+## @cmethod @AngularUnits()
+# @return list of known angular units.
 
-## @ignore TIEHASH
-## @ignore CLEAR
-## @ignore FIRSTKEY
-## @ignore NEXTKEY
-## @ignore FETCH
-## @ignore STORE
-## @ignore this
+## @cmethod @Datums()
+# @return list of known datums.
 
-## @fn $GetWellKnownGeogCSAsWKT($name)
+## @cmethod $GetWellKnownGeogCSAsWKT($name)
+# @brief Get well known geographic coordinate system as WKT
 # @param name a well known name
 # @return a WKT string
 
-## @fn $GetUserInputAsWKT($name)
+## @cmethod $GetUserInputAsWKT($name)
 # @param name the user input
 # @return a WKT string
 
-## @fn \@GetProjectionMethods()
+## @cmethod \@GetProjectionMethods()
+# @deprecated Use Geo::OSR::Projections.
+#
 # @return reference to an array of possible projection methods
 
-## @fn @GetProjectionMethodParameterList($method)
-# @param method projection method name
+## @cmethod @GetProjectionMethodParameterList($projection)
+# @param projection one of Geo::OSR::Projections
 # @return (arrayref parameters, $projection_name)
 
-## @fn @GetProjectionMethodParamInfo($method, $parameter)
-# @return ($user_friendly_name, $type, $defaultval)
+## @cmethod @GetProjectionMethodParamInfo($projection, $parameter)
+# @param projection one of Geo::OSR::Projections
+# @param parameter one of Geo::OSR::Parameters
+# @return ($user_friendly_name, $type, $default_value)
 
 
 ## @class Geo::OSR::SpatialReference
-# @brief <a href="http://www.gdal.org/ogr/classOGRSpatialReference.html">Documentation
+# @brief A spatial reference system.
+#
+# <a href="http://www.gdal.org/ogr/classOGRSpatialReference.html">Documentation
 # of the underlying C++ class at www.gdal.org</a>
 
-## @attr list PROJECTIONS
-# Projections known to GDAL
-
-## @attr list PARAMETERS
-# Some projection parameters known to GDAL
-
-## @cmethod Geo::OSR::SpatialReference new($wkt = undef)
-# @param wkt well known text
-# @return a new Geo::OSR::SpatialReference object
-
 ## @ignore ImportFromEPSGA
 ## @ignore ImportFromERM
 ## @ignore ImportFromMICoordSys
@@ -58,7 +58,7 @@
 ## @ignore ImportFromXML
 ## @ignore ImportFromUrl
 
-## @cmethod Geo::OSR::SpatialReference create(%params)
+## @cmethod Geo::OSR::SpatialReference new(%params)
 # Create a new spatial reference object using a named parameter. This
 # constructor recognizes the following key words (alternative in
 # parenthesis): WKT (Text), Proj4, ESRI, EPSG, EPSGA, PCI, USGS, GML
@@ -106,6 +106,7 @@
 ## @method Export($format)
 # Export the spatial reference to a selected format.
 # @note a.k.a. As
+#
 # @param format One of the following. The return value is explained
 # after the format. Other arguments are explained in parenthesis.
 # - WKT (Text): Well Known Text string
@@ -189,30 +190,31 @@
 # Set a parameter or parameters in the spatial reference object.
 # @param params Named parameters. Recognized keys and respective
 # values are the following.
-# - Authority: authority name
-# - Node: partial or complete path to the target node
-# - AngularUnits: angular units for the geographic coordinate system
-# - LinearUnits: linear units for the target node or the object
-# - CoordinateSystem: 'UTM', 'State Plane', 'WGS' or a user visible name 
-# - Zone: zone for setting up UTM or State Plane coordinate systems (State Plane zone in USGS numbering scheme)
-# - Projection: one from \@Geo::OSR::PROJECTIONS
-# - Parameter: one from \@Geo::OSR::PARAMETERS
+# - Authority: authority name (give also TargetKey, Node and Code)
+# - TargetKey:
+# - Node: partial or complete path to the target node (Node and Value together sets an attribute value)
 # - Code: code for value with an authority
-# - Value: value to be assigned to a node, the projection or the object
+# - Value: value to be assigned to a node, a projection parameter or an object
+# - AngularUnits: angular units for the geographic coordinate system (give also Value) (one of Geo::OSR::LinearUnits)
+# - LinearUnits: linear units for the target node or the object (give also Value and optionally Node) (one of Geo::OSR::LinearUnits)
+# - Parameter: projection parameter to set (give also Value and Normalized) (one of Geo::OSR::Parameters)
 # - Normalized: set to true to indicate that the Value argument is in "normalized" form
-# - Parameters: a reference to a list containing the projection parameters
-# - Name: Transverse Mercator variant name or a well known name (e.g. WGS84)
-# - GuessFrom: tries to guess from given text
+# - Name: a well known name of a geographic coordinate system (e.g. WGS84)
+# - GuessFrom: arbitrary text that specifies a projection ("user input")
+# - LOCAL_CS: name of a local coordinate system
+# - GeocentricCS: name of a geocentric coordinate system
+# - VerticalCS: name of a vertical coordinate system (give also Datum and optionally VertDatumType [default is 2005])
+# - Datum: a known (OGC or EPSG) name (or(?) one of Geo::OSR::Datums)
+# - CoordinateSystem: 'WGS', 'UTM', 'State Plane', or a user visible name (give optionally also Parameters, Zone, North, NAD83, UnitName, UnitConversionFactor, Datum, Spheroid, HorizontalCS, and/or VerticalCS
+# - Parameters: a reference to a list containing the coordinate system or projection parameters
+# - Zone: zone for setting up UTM or State Plane coordinate systems (State Plane zone in USGS numbering scheme)
 # - North: set false for southern hemisphere
 # - NAD83: set false if the NAD27 zone definition should be used instead of NAD83
 # - UnitName: to override the legal definition for a zone
 # - UnitConversionFactor: to override the legal definition for a zone
-# - LOCAL_CS: local cs name
-# - Datum: a known (OGC or EPSG) name
 # - Spheroid: user visible name
-# - GeocentricCS: Geocentric coorinate system name
 # - HorizontalCS: Horizontal coordinate system name
-# - VerticalCS: Vertical coordinate system name (setting requires Datum)
+# - Projection: name of a projection, one of Geo::OSR::Projections (give also optionally Parameters and Variant)
 #
 # @note Numerous Set* methods also exist but are not documented here.
 
@@ -317,6 +319,7 @@
 
 
 ## @class Geo::OSR::CoordinateTransformation
+# @brief An object for transforming from one projection to another.
 
 ## @cmethod Geo::OSR::CoordinateTransformation new($src, $dst)
 # @param src a Geo::OSR::SpatialReference object
@@ -329,7 +332,7 @@
 # @param z [optional]
 # @return arrayref = [$x, $y, $z]
 
-## @method TransformPoints(\@points)
+## @method TransformPoints(arrayref points)
 # @param points [in/out] a reference to a list of points (line string
 # or ring) that is modified in-place. A list of points is: ([x, y, z],
 # [x, y, z], ...), where z is optional. Supports also lists of line
diff --git a/swig/perl/lib/Geo/OSR.pm b/swig/perl/lib/Geo/OSR.pm
index f8cb864..bc2a2e5 100644
--- a/swig/perl/lib/Geo/OSR.pm
+++ b/swig/perl/lib/Geo/OSR.pm
@@ -61,18 +61,54 @@ package Geo::OSR;
 ############# Class : Geo::OSR::SpatialReference ##############
 
 package Geo::OSR::SpatialReference;
-use overload
-    '""' => sub { $_[0]->__str__()},
-    "=" => sub { my $class = ref($_[0]); $class->new($_[0]) },
-    "fallback" => 1;
 use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS);
 @ISA = qw( Geo::OSR );
 %OWNER = ();
 %ITERATORS = ();
+use Carp;
 sub new {
     my $pkg = shift;
-    my $self = Geo::OSRc::new_SpatialReference(@_);
-    bless $self, $pkg if defined($self);
+    my %param = @_;
+    my $self = Geo::OSRc::new_SpatialReference();
+    if ($param{WKT}) {
+        ImportFromWkt($self, $param{WKT});
+    } elsif ($param{Text}) {
+        ImportFromWkt($self, $param{Text});
+    } elsif ($param{Proj4}) {
+        ImportFromProj4($self, $param{Proj4});
+    } elsif ($param{ESRI}) {
+        ImportFromESRI($self, @{$param{ESRI}});
+    } elsif ($param{EPSG}) {
+        ImportFromEPSG($self, $param{EPSG});
+    } elsif ($param{EPSGA}) {
+        ImportFromEPSGA($self, $param{EPSGA});
+    } elsif ($param{PCI}) {
+        ImportFromPCI($self, @{$param{PCI}});
+    } elsif ($param{USGS}) {
+        ImportFromUSGS($self, @{$param{USGS}});
+    } elsif ($param{XML}) {
+        ImportFromXML($self, $param{XML});
+    } elsif ($param{GML}) {
+        ImportFromGML($self, $param{GML});
+    } elsif ($param{URL}) {
+        ImportFromUrl($self, $param{URL});
+    } elsif ($param{ERMapper}) {
+        ImportFromERM($self, @{$param{ERMapper}});
+    } elsif ($param{ERM}) {
+        ImportFromERM($self, @{$param{ERM}});
+    } elsif ($param{MICoordSys}) {
+        ImportFromMICoordSys($self, $param{MICoordSys});
+    } elsif ($param{MapInfoCS}) {
+        ImportFromMICoordSys($self, $param{MapInfoCS});
+    } elsif ($param{WGS}) {
+        eval {
+            SetWellKnownGeogCS($self, 'WGS'.$param{WGS});
+        };
+        confess "$@" if $@;
+    } else {
+        confess "Unrecognized/missing parameters: @_.";
+    }
+    bless $self, $pkg if defined $self;
 }
 
 sub DESTROY {
@@ -86,7 +122,6 @@ sub DESTROY {
     }
 }
 
-*__str__ = *Geo::OSRc::SpatialReference___str__;
 *IsSame = *Geo::OSRc::SpatialReference_IsSame;
 *IsSameGeogCS = *Geo::OSRc::SpatialReference_IsSameGeogCS;
 *IsSameVertCS = *Geo::OSRc::SpatialReference_IsSameVertCS;
@@ -286,6 +321,7 @@ package Geo::OSR;
 *SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA = *Geo::OSRc::SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA;
 *SRS_PT_MERCATOR_1SP = *Geo::OSRc::SRS_PT_MERCATOR_1SP;
 *SRS_PT_MERCATOR_2SP = *Geo::OSRc::SRS_PT_MERCATOR_2SP;
+*SRS_PT_MERCATOR_AUXILIARY_SPHERE = *Geo::OSRc::SRS_PT_MERCATOR_AUXILIARY_SPHERE;
 *SRS_PT_MILLER_CYLINDRICAL = *Geo::OSRc::SRS_PT_MILLER_CYLINDRICAL;
 *SRS_PT_MOLLWEIDE = *Geo::OSRc::SRS_PT_MOLLWEIDE;
 *SRS_PT_NEW_ZEALAND_MAP_GRID = *Geo::OSRc::SRS_PT_NEW_ZEALAND_MAP_GRID;
@@ -316,6 +352,14 @@ package Geo::OSR;
 *SRS_PT_WAGNER_V = *Geo::OSRc::SRS_PT_WAGNER_V;
 *SRS_PT_WAGNER_VI = *Geo::OSRc::SRS_PT_WAGNER_VI;
 *SRS_PT_WAGNER_VII = *Geo::OSRc::SRS_PT_WAGNER_VII;
+*SRS_PT_QSC = *Geo::OSRc::SRS_PT_QSC;
+*SRS_PT_AITOFF = *Geo::OSRc::SRS_PT_AITOFF;
+*SRS_PT_WINKEL_I = *Geo::OSRc::SRS_PT_WINKEL_I;
+*SRS_PT_WINKEL_II = *Geo::OSRc::SRS_PT_WINKEL_II;
+*SRS_PT_WINKEL_TRIPEL = *Geo::OSRc::SRS_PT_WINKEL_TRIPEL;
+*SRS_PT_CRASTER_PARABOLIC = *Geo::OSRc::SRS_PT_CRASTER_PARABOLIC;
+*SRS_PT_LOXIMUTHAL = *Geo::OSRc::SRS_PT_LOXIMUTHAL;
+*SRS_PT_QUARTIC_AUTHALIC = *Geo::OSRc::SRS_PT_QUARTIC_AUTHALIC;
 *SRS_PP_CENTRAL_MERIDIAN = *Geo::OSRc::SRS_PP_CENTRAL_MERIDIAN;
 *SRS_PP_SCALE_FACTOR = *Geo::OSRc::SRS_PP_SCALE_FACTOR;
 *SRS_PP_STANDARD_PARALLEL_1 = *Geo::OSRc::SRS_PP_STANDARD_PARALLEL_1;
@@ -409,337 +453,273 @@ package Geo::OSR;
 *SRS_WGS84_SEMIMAJOR = *Geo::OSRc::SRS_WGS84_SEMIMAJOR;
 *SRS_WGS84_INVFLATTENING = *Geo::OSRc::SRS_WGS84_INVFLATTENING;
 
-    sub RELEASE_PARENTS {
+
+package Geo::OSR;
+use strict;
+use warnings;
+
+use vars qw /%PROJECTIONS %PARAMETERS %LINEAR_UNITS %ANGULAR_UNITS %DATUMS/;
+
+for (keys %Geo::OSR::) {
+    if (/^SRS_PT_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $PROJECTIONS{$p} = 1;
     }
-    package Geo::OSR::SpatialReference;
-    use strict;
-    use Carp;
-    use vars qw /@PROJECTIONS %PROJECTIONS @PARAMETERS %PARAMETERS/;
-    @PROJECTIONS = qw/
-ALBERS_CONIC_EQUAL_AREA
-AZIMUTHAL_EQUIDISTANT
-CASSINI_SOLDNER
-CYLINDRICAL_EQUAL_AREA
-BONNE
-ECKERT_I
-ECKERT_II
-ECKERT_III
-ECKERT_IV
-ECKERT_V
-ECKERT_VI
-EQUIDISTANT_CONIC
-EQUIRECTANGULAR
-GALL_STEREOGRAPHIC
-GAUSSSCHREIBERTMERCATOR
-GEOSTATIONARY_SATELLITE
-GOODE_HOMOLOSINE
-IGH
-GNOMONIC
-HOTINE_OBLIQUE_MERCATOR
-HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN
-LABORDE_OBLIQUE_MERCATOR
-LAMBERT_CONFORMAL_CONIC_1SP
-LAMBERT_CONFORMAL_CONIC_2SP
-LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM
-LAMBERT_AZIMUTHAL_EQUAL_AREA
-MERCATOR_1SP
-MERCATOR_2SP
-MILLER_CYLINDRICAL
-MOLLWEIDE
-NEW_ZEALAND_MAP_GRID
-OBLIQUE_STEREOGRAPHIC
-ORTHOGRAPHIC
-POLAR_STEREOGRAPHIC
-POLYCONIC
-ROBINSON
-SINUSOIDAL
-STEREOGRAPHIC
-SWISS_OBLIQUE_CYLINDRICAL
-TRANSVERSE_MERCATOR
-TRANSVERSE_MERCATOR_SOUTH_ORIENTED
-TRANSVERSE_MERCATOR_MI_21
-TRANSVERSE_MERCATOR_MI_22
-TRANSVERSE_MERCATOR_MI_23
-TRANSVERSE_MERCATOR_MI_24
-TRANSVERSE_MERCATOR_MI_25
-TUNISIA_MINING_GRID
-TWO_POINT_EQUIDISTANT
-VANDERGRINTEN
-KROVAK
-IMW_POLYCONIC
-WAGNER_I
-WAGNER_II
-WAGNER_III
-WAGNER_IV
-WAGNER_V
-WAGNER_VI
-WAGNER_VII
-/;
-    for my $s (@PROJECTIONS) {
-	my $p = eval "\$Geo::OGR::SRS_PT_$s";
-	$PROJECTIONS{$s} = $p;
+    elsif (/^SRS_PP_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $PARAMETERS{$p} = 1;
     }
-    @PARAMETERS = qw/
-CENTRAL_MERIDIAN
-SCALE_FACTOR
-STANDARD_PARALLEL_1
-STANDARD_PARALLEL_2
-PSEUDO_STD_PARALLEL_1
-LONGITUDE_OF_CENTER
-LATITUDE_OF_CENTER
-LONGITUDE_OF_ORIGIN
-LATITUDE_OF_ORIGIN
-FALSE_EASTING
-FALSE_NORTHING
-AZIMUTH
-LONGITUDE_OF_POINT_1
-LATITUDE_OF_POINT_1
-LONGITUDE_OF_POINT_2
-LATITUDE_OF_POINT_2
-LONGITUDE_OF_POINT_3
-LATITUDE_OF_POINT_3
-RECTIFIED_GRID_ANGLE
-LANDSAT_NUMBER
-PATH_NUMBER
-PERSPECTIVE_POINT_HEIGHT
-SATELLITE_HEIGHT
-FIPSZONE
-ZONE
-LATITUDE_OF_1ST_POINT
-LONGITUDE_OF_1ST_POINT
-LATITUDE_OF_2ND_POINT
-LONGITUDE_OF_2ND_POINT
-/;
-    for my $s (@PARAMETERS) {
-	my $p = eval "\$Geo::OGR::SRS_PP_$s";
-	$PARAMETERS{$s} = $p;
+    elsif (/^SRS_UL_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $LINEAR_UNITS{$p} = 1;
     }
-    sub create {
-	my $pkg = shift;
-	my %param = @_;
-	my $self = Geo::OSRc::new_SpatialReference();
-	if ($param{WKT}) {
-	    ImportFromWkt($self, $param{WKT});
-	} elsif ($param{Text}) {
-	    ImportFromWkt($self, $param{Text});
-	} elsif ($param{Proj4}) {
-	    ImportFromProj4($self, $param{Proj4});
-	} elsif ($param{ESRI}) {
-	    ImportFromESRI($self, @{$param{ESRI}});
-	} elsif ($param{EPSG}) {
-	    ImportFromEPSG($self, $param{EPSG});
-	} elsif ($param{EPSGA}) {
-	    ImportFromEPSGA($self, $param{EPSGA});
-	} elsif ($param{PCI}) {
-	    ImportFromPCI($self, @{$param{PCI}});
-	} elsif ($param{USGS}) {
-	    ImportFromUSGS($self, @{$param{USGS}});
-	} elsif ($param{XML}) {
-	    ImportFromXML($self, $param{XML});
-	} elsif ($param{GML}) {
-	    ImportFromGML($self, $param{GML});
-	} elsif ($param{URL}) {
-	    ImportFromUrl($self, $param{URL});
-	} elsif ($param{ERMapper}) {
-	    ImportFromERM($self, @{$param{ERMapper}} );
-	} elsif ($param{ERM}) {
-	    ImportFromERM($self, @{$param{ERM}} );
-	} elsif ($param{MICoordSys}) {
-	    ImportFromMICoordSys($self, $param{MICoordSys} );
-	} elsif ($param{MapInfoCS}) {
-	    ImportFromMICoordSys($self, $param{MapInfoCS} );
-	} else {
-	    croak "unrecognized import format '@_' for Geo::OSR::SpatialReference";
-	}
-	bless $self, $pkg if defined $self;
+    elsif (/^SRS_UA_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $ANGULAR_UNITS{$p} = 1;
     }
-    sub Export {
-	my $self = shift;
-	my $format;
-	$format = pop if @_ == 1;
-	my %params = @_;
-	$format = $params{to} unless $format;
-	$format = $params{format} unless $format;
-	$format = $params{as} unless $format;
-	if ($format eq 'WKT' or $format eq 'Text') {
-	    return ExportToWkt($self);
-	} elsif ($format eq 'PrettyWKT') {
-	    my $simplify = exists $params{simplify} ? $params{simplify} : 0;
-	    return ExportToPrettyWkt($self, $simplify);
-	} elsif ($format eq 'Proj4') {
-	    return ExportToProj4($self);
-	} elsif ($format eq 'PCI') {	    
-	    return ExportToPCI($self);
-	} elsif ($format eq 'USGS') {
-	    return ExportToUSGS($self);
-	} elsif ($format eq 'GML' or $format eq 'XML') {
-	    my $dialect = exists $params{dialect} ? $params{dialect} : '';
-	    return ExportToXML($self, $dialect);
-	} elsif ($format eq 'MICoordSys' or $format eq 'MapInfoCS') {
-	    return ExportToMICoordSys();
-	} else {
-	    croak "unrecognized export format '$format/@_' for Geo::OSR::SpatialReference.";
-	}
+    elsif (/^SRS_DN_(\w+)/) {
+        my $p = eval '$Geo::OSR::'.$_;
+        $DATUMS{$p} = 1;
     }
-    *AsText = *ExportToWkt;
-    *As = *Export;
-    sub Set {
-	my($self, %params) = @_;
-	if (exists $params{Authority} and exists $params{Node} and exists $params{Code}) {
-	    SetAuthority($self, $params{TargetKey}, $params{Authority}, $params{Code});
-	} elsif (exists $params{Node} and exists $params{Value}) {
-	    SetAttrValue($self, $params{Node}, $params{Value});
-	} elsif (exists $params{AngularUnits} and exists $params{Value}) {
-	    SetAngularUnits($self, $params{AngularUnits}, $params{Value});
-	} elsif (exists $params{LinearUnits} and exists $params{Node} and exists $params{Value}) {
-	    SetTargetLinearUnits($self, $params{Node}, $params{LinearUnits}, $params{Value});
-	} elsif (exists $params{LinearUnits} and exists $params{Value}) {
-	    SetLinearUnitsAndUpdateParameters($self, $params{LinearUnits}, $params{Value});
-	} elsif ($params{CoordinateSystem} eq 'UTM' and exists $params{Zone} and exists $params{North}) {
-	    my $north = exists $params{North} ? $params{North} : 1;
-	    SetUTM($self, $params{Zone}, $north);
-	} elsif ($params{CoordinateSystem} eq 'State Plane' and exists $params{Zone}) {
-	    my $NAD83 = exists $params{NAD83} ? $params{NAD83} : 1;
-	    my $name = exists $params{UnitName} ? $params{UnitName} : undef;
-	    my $c = exists $params{UnitConversionFactor} ? $params{UnitConversionFactor} : 0.0;
-	    SetStatePlane($self, $params{Zone}, $NAD83, $name, $c);
-	} elsif ($params{Parameter} and exists $params{Value}) {
-	    croak "unknown parameter '$params{Parameter}' in Geo::OSR::SpatialReference->Set" unless exists $PARAMETERS{$params{Parameter}};
-	    $params{Normalized} ?
-		SetNormProjParm($self, $params{Parameter}, $params{Value}) :
-		SetProjParm($self, $params{Parameter}, $params{Value});
-	} elsif ($params{Projection}) {
-	    croak "unknown projection '$params{Projection}' in Geo::OSR::SpatialReference->Set" unless exists $PROJECTIONS{$params{Projection}};
-	    if (not $params{Parameters}) {
-		SetProjection($self, $PROJECTIONS{$params{Projection}});
-	    } elsif ($params{Projection} eq 'ALBERS_CONIC_EQUAL_AREA' and $params{Parameters}) {
-		SetACEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'AZIMUTHAL_EQUIDISTANT' and $params{Parameters}) {
-		SetAE($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'BONNE' and $params{Parameters}) {
-		SetBonne($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'CYLINDRICAL_EQUAL_AREA' and $params{Parameters}) {
-		SetCEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'CASSINI_SOLDNER' and $params{Parameters}) {
-		SetCS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'EQUIDISTANT_CONIC' and $params{Parameters}) {
-		SetEC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ECKERT_IV' and $params{Parameters}) {
-		SetEckertIV($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ECKERT_VI' and $params{Parameters}) {
-		SetEckertVI($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'EQUIRECTANGULAR' and $params{Parameters}) {
-		@{$params{Parameters}} == 4 ?
-		    SetEquirectangular($self, @{$params{Parameters}}) :
-		    SetEquirectangular2($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GAUSSSCHREIBERTMERCATOR' and $params{Parameters}) {
-		SetGaussSchreiberTMercator($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GALL_STEREOGRAPHIC' and $params{Parameters}) {
-		SetGS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GOODE_HOMOLOSINE' and $params{Parameters}) {
-		SetGH($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'IGH') {
-		SetIGH($self);
-	    } elsif ($params{Projection} eq 'GEOSTATIONARY_SATELLITE' and $params{Parameters}) {
-		SetGEOS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'GNOMONIC' and $params{Parameters}) {
-		SetGnomonic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'HOTINE_OBLIQUE_MERCATOR' and $params{Parameters}) {
-		SetHOM($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN' and $params{Parameters}) {
-		SetHOM2PNO($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'KROVAK' and $params{Parameters}) {
-		SetKrovak($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_AZIMUTHAL_EQUAL_AREA' and $params{Parameters}) {
-		SetLAEA($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_2SP' and $params{Parameters}) {
-		SetLCC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_1SP' and $params{Parameters}) {
-		SetLCC1SP($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM' and $params{Parameters}) {
-		SetLCCB($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'MILLER_CYLINDRICAL' and $params{Parameters}) {
-		SetMC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} =~ /^MERCATOR/ and $params{Parameters}) {
-		SetMercator($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'MOLLWEIDE' and $params{Parameters}) {
-		SetMollweide($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'NEW_ZEALAND_MAP_GRID' and $params{Parameters}) {
-		SetNZMG($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'OBLIQUE_STEREOGRAPHIC' and $params{Parameters}) {
-		SetOS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ORTHOGRAPHIC' and $params{Parameters}) {
-		SetOrthographic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'POLYCONIC' and $params{Parameters}) {
-		SetPolyconic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'POLAR_STEREOGRAPHIC' and $params{Parameters}) {
-		SetPS($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'ROBINSON' and $params{Parameters}) {
-		SetRobinson($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'SINUSOIDAL' and $params{Parameters}) {
-		SetSinusoidal($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'STEREOGRAPHIC' and $params{Parameters}) {
-		SetStereographic($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'SWISS_OBLIQUE_CYLINDRICAL' and $params{Parameters}) {
-		SetSOC($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'TRANSVERSE_MERCATOR_SOUTH_ORIENTED' and $params{Parameters}) {
-		SetTMSO($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} =~ /^TRANSVERSE_MERCATOR/ and $params{Parameters}) {
-		my($variant) = $params{Projection} =~ /^TRANSVERSE_MERCATOR_(\w+)/;
-		$variant = $params{Name} unless $variant;
-		$variant ?
-		    SetTMVariant($self, $variant, @{$params{Parameters}}) :
-		    SetTM($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'TUNISIA_MINING_GRID' and $params{Parameters}) {
-		SetTMG($self, @{$params{Parameters}});
-	    } elsif ($params{Projection} eq 'VANDERGRINTEN' and $params{Parameters}) {
-		SetVDG($self, @{$params{Parameters}});
-	    } elsif ($params{Name}) {
-		SetWellKnownGeogCS($self, $params{Name});
-	    } elsif ($params{GuessFrom}) {
-		SetFromUserInput($self, $params{GuessFrom});
-	    } elsif ($params{CoordinateSystem} eq 'WGS' and $params{Parameters}) {
-		SetTOWGS84($self, @{$params{Parameters}});
-	    } elsif ($params{LOCAL_CS}) {
-		SetLocalCS($self, $params{LOCAL_CS});
-	    } elsif ($params{CoordinateSystem} and $params{Datum} and $params{Spheroid} and $params{Parameters}) {
-		SetGeogCS($self, $params{CoordinateSystem}, $params{Datum}, $params{Spheroid}, @{$params{Parameters}});
-	    } elsif ($params{CoordinateSystem}) {
-		SetProjCS($self, $params{CoordinateSystem});
-	    } elsif ($params{GeocentricCS}) {
-		SetGeocCS($self, $params{GeocentricCS});
-	    } elsif ($params{VerticalCS} and $params{Datum}) {
-		my $type = $params{VertDatumType} || 2005;
-		SetVertCS($self, $params{VerticalCS}, $params{Datum}, $type);
-	    } elsif ($params{CoordinateSystem} and $params{HorizontalCS} and $params{VerticalCS}) {
-		SetCompoundCS($self, $params{CoordinateSystem}, $params{HorizontalCS}, $params{VerticalCS});
-	    } else {
-		croak "not enough information to set anything in a spatial reference object in Geo::OSR::SpatialReference->Set";
-	    }
-	}
+}
+
+sub Projections {
+    return keys %PROJECTIONS;
+}
+
+sub Parameters {
+    return keys %PARAMETERS;
+}
+
+sub LinearUnits {
+    return keys %LINEAR_UNITS;
+}
+
+sub AngularUnits {
+    return keys %ANGULAR_UNITS;
+}
+
+sub Datums {
+    return keys %DATUMS;
+}
+
+sub RELEASE_PARENTS {
+}
+
+
+package Geo::OSR::SpatialReference;
+use strict;
+use warnings;
+use Carp;
+
+sub Export {
+    my $self = shift;
+    my $format;
+    $format = pop if @_ == 1;
+    my %params = @_;
+    $format = $params{to} unless $format;
+    $format = $params{format} unless $format;
+    $format = $params{as} unless $format;
+    if ($format eq 'WKT' or $format eq 'Text') {
+        return ExportToWkt($self);
+    } elsif ($format eq 'PrettyWKT') {
+        my $simplify = exists $params{simplify} ? $params{simplify} : 0;
+        return ExportToPrettyWkt($self, $simplify);
+    } elsif ($format eq 'Proj4') {
+        return ExportToProj4($self);
+    } elsif ($format eq 'PCI') {            
+        return ExportToPCI($self);
+    } elsif ($format eq 'USGS') {
+        return ExportToUSGS($self);
+    } elsif ($format eq 'GML' or $format eq 'XML') {
+        my $dialect = exists $params{dialect} ? $params{dialect} : '';
+        return ExportToXML($self, $dialect);
+    } elsif ($format eq 'MICoordSys' or $format eq 'MapInfoCS') {
+        return ExportToMICoordSys();
+    } else {
+        confess "Unrecognized export format.";
     }
-    sub GetUTMZone {
-	my $self = shift;
-	my $zone = _GetUTMZone($self);
-	if (wantarray) {	    
-	    my $north = 1;
-	    if ($zone < 0) {
-		$zone *= -1;
-		$north = 0;
-	    }
-	    return ($zone, $north);
-	} else {
-	    return $zone;
-	}
+}
+*AsText = *ExportToWkt;
+*As = *Export;
+
+sub Set {
+    my($self, %params) = @_;
+    if (exists $params{Authority} and exists $params{TargetKey} and exists $params{Node} and exists $params{Code}) {
+        SetAuthority($self, $params{TargetKey}, $params{Authority}, $params{Code});
+    } elsif (exists $params{Node} and exists $params{Value}) {
+        SetAttrValue($self, $params{Node}, $params{Value});
+    } elsif (exists $params{AngularUnits} and exists $params{Value}) {
+        SetAngularUnits($self, $params{AngularUnits}, $params{Value});
+    } elsif (exists $params{LinearUnits} and exists $params{Node} and exists $params{Value}) {
+        SetTargetLinearUnits($self, $params{Node}, $params{LinearUnits}, $params{Value});
+    } elsif (exists $params{LinearUnits} and exists $params{Value}) {
+        SetLinearUnitsAndUpdateParameters($self, $params{LinearUnits}, $params{Value});
+    } elsif ($params{Parameter} and exists $params{Value}) {
+        croak "Unknown projection parameter '$params{Parameter}'." unless exists $Geo::OSR::PARAMETERS{$params{Parameter}};
+        $params{Normalized} ?
+            SetNormProjParm($self, $params{Parameter}, $params{Value}) :
+            SetProjParm($self, $params{Parameter}, $params{Value});
+    } elsif ($params{Name}) {
+        SetWellKnownGeogCS($self, $params{Name});
+    } elsif ($params{GuessFrom}) {
+        SetFromUserInput($self, $params{GuessFrom});
+    } elsif ($params{LOCAL_CS}) {
+        SetLocalCS($self, $params{LOCAL_CS});
+    } elsif ($params{GeocentricCS}) {
+        SetGeocCS($self, $params{GeocentricCS});
+    } elsif ($params{VerticalCS} and $params{Datum}) {
+        my $type = $params{VertDatumType} || 2005;
+        SetVertCS($self, $params{VerticalCS}, $params{Datum}, $type);
+    } elsif ($params{CoordinateSystem}) {
+        my @parameters = ();
+        @parameters = @{$params{Parameters}} if ref($params{Parameters});
+        if ($params{CoordinateSystem} eq 'State Plane' and exists $params{Zone}) {
+            my $NAD83 = exists $params{NAD83} ? $params{NAD83} : 1;
+            my $name = exists $params{UnitName} ? $params{UnitName} : undef;
+            my $c = exists $params{UnitConversionFactor} ? $params{UnitConversionFactor} : 0.0;
+            SetStatePlane($self, $params{Zone}, $NAD83, $name, $c);
+        } elsif ($params{CoordinateSystem} eq 'UTM' and exists $params{Zone} and exists $params{North}) {
+            my $north = exists $params{North} ? $params{North} : 1;
+            SetUTM($self, $params{Zone}, $north);
+        } elsif ($params{CoordinateSystem} eq 'WGS') {
+            SetTOWGS84($self, @parameters);
+        } elsif ($params{CoordinateSystem} and $params{Datum} and $params{Spheroid}) {
+            SetGeogCS($self, $params{CoordinateSystem}, $params{Datum}, $params{Spheroid}, @parameters);
+        } elsif ($params{CoordinateSystem} and $params{HorizontalCS} and $params{VerticalCS}) {
+            SetCompoundCS($self, $params{CoordinateSystem}, $params{HorizontalCS}, $params{VerticalCS});
+        } else {
+            SetProjCS($self, $params{CoordinateSystem});
+        }
+    } elsif ($params{Projection}) {
+        confess "Unknown projection." unless exists $Geo::OSR::PROJECTIONS{$params{Projection}};
+        my @parameters = ();
+        @parameters = @{$params{Parameters}} if ref($params{Parameters});
+        if ($params{Projection} eq 'Albers_Conic_Equal_Area') {
+            SetACEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Azimuthal_Equidistant') {
+            SetAE($self, @parameters);
+        } elsif ($params{Projection} eq 'Bonne') {
+            SetBonne($self, @parameters);
+        } elsif ($params{Projection} eq 'Cylindrical_Equal_Area') {
+            SetCEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Cassini_Soldner') {
+            SetCS($self, @parameters);
+        } elsif ($params{Projection} eq 'Equidistant_Conic') {
+            SetEC($self, @parameters);
+            # Eckert_I, Eckert_II, Eckert_III, Eckert_V ?
+        } elsif ($params{Projection} eq 'Eckert_IV') {
+            SetEckertIV($self, @parameters);
+        } elsif ($params{Projection} eq 'Eckert_VI') {
+            SetEckertVI($self, @parameters);
+        } elsif ($params{Projection} eq 'Equirectangular') {
+            @parameters == 4 ?
+                SetEquirectangular($self, @parameters) :
+                SetEquirectangular2($self, @parameters);
+        } elsif ($params{Projection} eq 'Gauss_Schreiber_Transverse_Mercator') {
+            SetGaussSchreiberTMercator($self, @parameters);
+        } elsif ($params{Projection} eq 'Gall_Stereographic') {
+            SetGS($self, @parameters);
+        } elsif ($params{Projection} eq 'Goode_Homolosine') {
+            SetGH($self, @parameters);
+        } elsif ($params{Projection} eq 'Interrupted_Goode_Homolosine') {
+            SetIGH($self);
+        } elsif ($params{Projection} eq 'Geostationary_Satellite') {
+            SetGEOS($self, @parameters);
+        } elsif ($params{Projection} eq 'Gnomonic') {
+            SetGnomonic($self, @parameters);
+        } elsif ($params{Projection} eq 'Hotine_Oblique_Mercator') {
+            # Hotine_Oblique_Mercator_Azimuth_Center ?
+            SetHOM($self, @parameters);
+        } elsif ($params{Projection} eq 'Hotine_Oblique_Mercator_Two_Point_Natural_Origin') {
+            SetHOM2PNO($self, @parameters);
+        } elsif ($params{Projection} eq 'Krovak') {
+            SetKrovak($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Azimuthal_Equal_Area') {
+            SetLAEA($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_2SP') {
+            SetLCC($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_1SP') {
+            SetLCC1SP($self, @parameters);
+        } elsif ($params{Projection} eq 'Lambert_Conformal_Conic_2SP_Belgium') {
+            SetLCCB($self, @parameters);
+        } elsif ($params{Projection} eq 'miller_cylindrical') {
+            SetMC($self, @parameters);
+        } elsif ($params{Projection} =~ /^Mercator/) {
+            # Mercator_1SP, Mercator_2SP, Mercator_Auxiliary_Sphere ?
+            # variant is in Variant (or Name)
+            SetMercator($self, @parameters);
+        } elsif ($params{Projection} eq 'Mollweide') {
+            SetMollweide($self, @parameters);
+        } elsif ($params{Projection} eq 'New_Zealand_Map_Grid') {
+            SetNZMG($self, @parameters);
+        } elsif ($params{Projection} eq 'Oblique_Stereographic') {
+            SetOS($self, @parameters);
+        } elsif ($params{Projection} eq 'Orthographic') {
+            SetOrthographic($self, @parameters);
+        } elsif ($params{Projection} eq 'Polyconic') {
+            SetPolyconic($self, @parameters);
+        } elsif ($params{Projection} eq 'Polar_Stereographic') {
+            SetPS($self, @parameters);
+        } elsif ($params{Projection} eq 'Robinson') {
+            SetRobinson($self, @parameters);
+        } elsif ($params{Projection} eq 'Sinusoidal') {
+            SetSinusoidal($self, @parameters);
+        } elsif ($params{Projection} eq 'Stereographic') {
+            SetStereographic($self, @parameters);
+        } elsif ($params{Projection} eq 'Swiss_Oblique_Cylindrical') {
+            SetSOC($self, @parameters);
+        } elsif ($params{Projection} eq 'Transverse_Mercator_South_Orientated') {
+            SetTMSO($self, @parameters);
+        } elsif ($params{Projection} =~ /^Transverse_Mercator/) {
+            my($variant) = $params{Projection} =~ /^Transverse_Mercator_(\w+)/;
+            $variant = $params{Variant} unless $variant;
+            $variant = $params{Name} unless $variant;
+            $variant ?
+                SetTMVariant($self, $variant, @parameters) :
+                SetTM($self, @parameters);
+        } elsif ($params{Projection} eq 'Tunisia_Mining_Grid') {
+            SetTMG($self, @parameters);
+        } elsif ($params{Projection} eq 'VanDerGrinten') {
+            SetVDG($self, @parameters);
+        } else {
+            # Aitoff, Craster_Parabolic, International_Map_of_the_World_Polyconic, Laborde_Oblique_Mercator
+            # Loximuthal, Miller_Cylindrical, Quadrilateralized_Spherical_Cube, Quartic_Authalic, Two_Point_Equidistant
+            # Wagner_I, Wagner_II, Wagner_III, Wagner_IV, Wagner_V, Wagner_VI, Wagner_VII
+            # Winkel_I, Winkel_II, Winkel_Tripel
+            # ?
+            SetProjection($self, $params{Projection});
+        }
+    } else {
+        confess "Not enough information for a spatial reference object.";
     }
+}
 
-    package Geo::OSR::CoordinateTransformation;
-    use strict;
-    sub TransformPoints {
-	my($self, $points) = @_;
-	_TransformPoints($self, $points), return unless ref($points->[0]->[0]);
-	for my $p (@$points) {
-	    TransformPoints($self, $p);
-	}
+sub GetUTMZone {
+    my $self = shift;
+    my $zone = _GetUTMZone($self);
+    if (wantarray) {            
+        my $north = 1;
+        if ($zone < 0) {
+            $zone *= -1;
+            $north = 0;
+        }
+        return ($zone, $north);
+    } else {
+        return $zone;
+    }
+}
+
+
+package Geo::OSR::CoordinateTransformation;
+use strict;
+use warnings;
+
+sub TransformPoints {
+    my($self, $points) = @_;
+    _TransformPoints($self, $points), return unless ref($points->[0]->[0]);
+    for my $p (@$points) {
+        TransformPoints($self, $p);
     }
+}
 1;
diff --git a/swig/perl/ogr_wrap.cpp b/swig/perl/ogr_wrap.cpp
index 7365979..1e9144a 100644
--- a/swig/perl/ogr_wrap.cpp
+++ b/swig/perl/ogr_wrap.cpp
@@ -1512,28 +1512,31 @@ SWIG_Perl_SetModule(swig_module_info *module) {
 
 /* -------- TYPES TABLE (BEGIN) -------- */
 
-#define SWIGTYPE_p_GDALProgressFunc swig_types[0]
-#define SWIGTYPE_p_OGRDataSourceShadow swig_types[1]
-#define SWIGTYPE_p_OGRDriverShadow swig_types[2]
-#define SWIGTYPE_p_OGRFeatureDefnShadow swig_types[3]
-#define SWIGTYPE_p_OGRFeatureShadow swig_types[4]
-#define SWIGTYPE_p_OGRFieldDefnShadow swig_types[5]
-#define SWIGTYPE_p_OGRGeomFieldDefnShadow swig_types[6]
-#define SWIGTYPE_p_OGRGeometryShadow swig_types[7]
-#define SWIGTYPE_p_OGRLayerShadow swig_types[8]
-#define SWIGTYPE_p_OGRStyleTableShadow swig_types[9]
-#define SWIGTYPE_p_OSRCoordinateTransformationShadow swig_types[10]
-#define SWIGTYPE_p_OSRSpatialReferenceShadow swig_types[11]
-#define SWIGTYPE_p_char swig_types[12]
-#define SWIGTYPE_p_double swig_types[13]
-#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[14]
-#define SWIGTYPE_p_int swig_types[15]
-#define SWIGTYPE_p_p_char swig_types[16]
-#define SWIGTYPE_p_p_double swig_types[17]
-#define SWIGTYPE_p_p_int swig_types[18]
-#define SWIGTYPE_p_p_p_char swig_types[19]
-static swig_type_info *swig_types[21];
-static swig_module_info swig_module = {swig_types, 20, 0, 0, 0, 0};
+#define SWIGTYPE_p_GDALMajorObjectShadow swig_types[0]
+#define SWIGTYPE_p_GDALProgressFunc swig_types[1]
+#define SWIGTYPE_p_GIntBig swig_types[2]
+#define SWIGTYPE_p_OGRDataSourceShadow swig_types[3]
+#define SWIGTYPE_p_OGRDriverShadow swig_types[4]
+#define SWIGTYPE_p_OGRFeatureDefnShadow swig_types[5]
+#define SWIGTYPE_p_OGRFeatureShadow swig_types[6]
+#define SWIGTYPE_p_OGRFieldDefnShadow swig_types[7]
+#define SWIGTYPE_p_OGRGeomFieldDefnShadow swig_types[8]
+#define SWIGTYPE_p_OGRGeometryShadow swig_types[9]
+#define SWIGTYPE_p_OGRLayerShadow swig_types[10]
+#define SWIGTYPE_p_OGRStyleTableShadow swig_types[11]
+#define SWIGTYPE_p_OSRCoordinateTransformationShadow swig_types[12]
+#define SWIGTYPE_p_OSRSpatialReferenceShadow swig_types[13]
+#define SWIGTYPE_p_char swig_types[14]
+#define SWIGTYPE_p_double swig_types[15]
+#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[16]
+#define SWIGTYPE_p_float swig_types[17]
+#define SWIGTYPE_p_int swig_types[18]
+#define SWIGTYPE_p_p_char swig_types[19]
+#define SWIGTYPE_p_p_double swig_types[20]
+#define SWIGTYPE_p_p_int swig_types[21]
+#define SWIGTYPE_p_p_p_char swig_types[22]
+static swig_type_info *swig_types[24];
+static swig_module_info swig_module = {swig_types, 23, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -1575,6 +1578,7 @@ typedef char retStringAndCPLFree;
 #include <iostream>
 using namespace std;
 
+#include "gdal.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
 #include "ogr_core.h"
@@ -1582,6 +1586,8 @@ using namespace std;
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
+typedef void GDALMajorObjectShadow;
+
 #ifdef DEBUG 
 typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
 typedef struct OGRDriverHS OGRDriverShadow;
@@ -1650,34 +1656,34 @@ SWIG_FromCharPtr(const char *cptr)
     #ifndef SWIG
     typedef struct
     {
-	SV *fct;
-	SV *data;
+        SV *fct;
+        SV *data;
     } SavedEnv;
     #endif
     int callback_d_cp_vp(double d, const char *cp, void *vp)
     {
-	int count, ret;
-	SavedEnv *env_ptr = (SavedEnv *)vp;
-	dSP;
-	ENTER;
-	SAVETMPS;
-	PUSHMARK(SP);
-	XPUSHs(sv_2mortal(newSVnv(d)));
-	XPUSHs(sv_2mortal(newSVpv(cp, 0)));
-	if (env_ptr->data)
-	    XPUSHs(env_ptr->data);
-	PUTBACK;
-	count = call_sv(env_ptr->fct, G_SCALAR);
-	SPAGAIN;
-	if (count != 1) {
-	    fprintf(stderr, "The callback must return only one value.\n");
-	    return 0; /* interrupt */
-	}
-	ret = POPi;
-	PUTBACK;
-	FREETMPS;
-	LEAVE;
-	return ret;
+        int count, ret;
+        SavedEnv *env_ptr = (SavedEnv *)vp;
+        dSP;
+        ENTER;
+        SAVETMPS;
+        PUSHMARK(SP);
+        XPUSHs(sv_2mortal(newSVnv(d)));
+        XPUSHs(sv_2mortal(newSVpv(cp, 0)));
+        if (env_ptr->data)
+            XPUSHs(env_ptr->data);
+        PUTBACK;
+        count = call_sv(env_ptr->fct, G_SCALAR);
+        SPAGAIN;
+        if (count != 1) {
+            fprintf(stderr, "The callback must return only one value.\n");
+            return 0; /* interrupt */
+        }
+        ret = POPi;
+        PUTBACK;
+        FREETMPS;
+        LEAVE;
+        return ret;
     }
 
 
@@ -2014,6 +2020,8 @@ OGRErrMessages( int rc ) {
     return "OGR Error: Unsupported SRS";
   case OGRERR_INVALID_HANDLE:
     return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
   default:
     return "OGR Error: Unknown";
   }
@@ -2022,6 +2030,9 @@ OGRErrMessages( int rc ) {
 SWIGINTERN OGRErr OGRDataSourceShadow_SyncToDisk(OGRDataSourceShadow *self){
     return OGR_DS_SyncToDisk(self);
   }
+SWIGINTERN void OGRDataSourceShadow_FlushCache(OGRDataSourceShadow *self){
+    GDALFlushCache( self );
+  }
 SWIGINTERN OGRLayerShadow *OGRDataSourceShadow_CreateLayer(OGRDataSourceShadow *self,char const *name,OSRSpatialReferenceShadow *srs=NULL,OGRwkbGeometryType geom_type=wkbUnknown,char **options=0){
     OGRLayerShadow* layer = (OGRLayerShadow*) OGR_DS_CreateLayer( self,
 								  name,
@@ -2066,6 +2077,15 @@ SWIGINTERN void OGRDataSourceShadow_SetStyleTable(OGRDataSourceShadow *self,OGRS
     if( table != NULL )
         OGR_DS_SetStyleTable(self, (OGRStyleTableH) table);
   }
+SWIGINTERN OGRErr OGRDataSourceShadow_StartTransaction(OGRDataSourceShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_CommitTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_RollbackTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
 SWIGINTERN int OGRLayerShadow_GetRefCount(OGRLayerShadow *self){
     return OGR_L_GetRefCount(self);
   }
@@ -2102,13 +2122,13 @@ SWIGINTERN char const *OGRLayerShadow_GetGeometryColumn(OGRLayerShadow *self){
 SWIGINTERN char const *OGRLayerShadow_GetFIDColumn(OGRLayerShadow *self){
     return OGR_L_GetFIDColumn(self);
   }
-SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,GIntBig fid){
     return (OGRFeatureShadow*) OGR_L_GetFeature(self, fid);
   }
 SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetNextFeature(OGRLayerShadow *self){
     return (OGRFeatureShadow*) OGR_L_GetNextFeature(self);
   }
-SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,long new_index){
+SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,GIntBig new_index){
     return OGR_L_SetNextByIndex(self, new_index);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
@@ -2117,7 +2137,7 @@ SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShado
 SWIGINTERN OGRErr OGRLayerShadow_CreateFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
     return OGR_L_CreateFeature(self, feature);
   }
-SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,GIntBig fid){
     return OGR_L_DeleteFeature(self, fid);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
@@ -2126,7 +2146,7 @@ SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
 SWIGINTERN OGRFeatureDefnShadow *OGRLayerShadow_GetLayerDefn(OGRLayerShadow *self){
     return (OGRFeatureDefnShadow*) OGR_L_GetLayerDefn(self);
   }
-SWIGINTERN int OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
+SWIGINTERN GIntBig OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
     return OGR_L_GetFeatureCount(self, force);
   }
 
@@ -2323,6 +2343,9 @@ SWIGINTERN char const *OGRFeatureShadow_GetFieldAsString(OGRFeatureShadow *self,
 SWIGINTERN int OGRFeatureShadow_GetFieldAsInteger(OGRFeatureShadow *self,int id){
     return OGR_F_GetFieldAsInteger(self, id);
   }
+SWIGINTERN GIntBig OGRFeatureShadow_GetFieldAsInteger64(OGRFeatureShadow *self,int id){
+    return OGR_F_GetFieldAsInteger64(self, id);
+  }
 SWIGINTERN double OGRFeatureShadow_GetFieldAsDouble(OGRFeatureShadow *self,int id){
     return OGR_F_GetFieldAsDouble(self, id);
   }
@@ -2333,9 +2356,16 @@ SWIG_From_double  SWIG_PERL_DECL_ARGS_1(double value)
   return sv_2mortal(newSVnv(value));
 }
 
-SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,int *pnSecond,int *pnTZFlag){
-      OGR_F_GetFieldAsDateTime(self, id, pnYear, pnMonth, pnDay,
-			       pnHour, pnMinute, pnSecond,
+
+SWIGINTERNINLINE SV *
+SWIG_From_float  SWIG_PERL_DECL_ARGS_1(float value)
+{    
+  return SWIG_From_double  SWIG_PERL_CALL_ARGS_1(value);
+}
+
+SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,float *pfSecond,int *pnTZFlag){
+      OGR_F_GetFieldAsDateTimeEx(self, id, pnYear, pnMonth, pnDay,
+			       pnHour, pnMinute, pfSecond,
 			       pnTZFlag);
   }
 
@@ -2371,6 +2401,12 @@ CreateArrayFromStringArray( char **first ) {
 SWIGINTERN void OGRFeatureShadow_GetFieldAsStringList(OGRFeatureShadow *self,int id,char ***pList){
       *pList = OGR_F_GetFieldAsStringList(self, id);
   }
+SWIGINTERN OGRErr OGRFeatureShadow_GetFieldAsBinary(OGRFeatureShadow *self,int id,int *nLen,char **pBuf){
+    GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+    *pBuf = (char*)malloc(*nLen);
+    memcpy(*pBuf, pabyBlob, *nLen);
+    return OGRERR_NONE;
+  }
 SWIGINTERN bool OGRFeatureShadow_IsFieldSet__SWIG_0(OGRFeatureShadow *self,int id){
     return (OGR_F_IsFieldSet(self, id) > 0);
   }
@@ -2388,10 +2424,10 @@ SWIGINTERN int OGRFeatureShadow_GetFieldIndex(OGRFeatureShadow *self,char const
 SWIGINTERN int OGRFeatureShadow_GetGeomFieldIndex(OGRFeatureShadow *self,char const *name){
       return OGR_F_GetGeomFieldIndex(self, name);
   }
-SWIGINTERN int OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
+SWIGINTERN GIntBig OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
     return OGR_F_GetFID(self);
   }
-SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,int fid){
+SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,GIntBig fid){
     return OGR_F_SetFID(self, fid);
   }
 SWIGINTERN void OGRFeatureShadow_DumpReadable(OGRFeatureShadow *self){
@@ -2403,14 +2439,33 @@ SWIGINTERN void OGRFeatureShadow_UnsetField(OGRFeatureShadow *self,int id){
 SWIGINTERN void OGRFeatureShadow_SetField__SWIG_0(OGRFeatureShadow *self,int id,char const *value){
     OGR_F_SetFieldString(self, id, value);
   }
+SWIGINTERN void OGRFeatureShadow_SetFieldInteger64(OGRFeatureShadow *self,int id,GIntBig value){
+    OGR_F_SetFieldInteger64(self, id, value);
+  }
 SWIGINTERN void OGRFeatureShadow_SetField__SWIG_1(OGRFeatureShadow *self,int id,int value){
     OGR_F_SetFieldInteger(self, id, value);
   }
 SWIGINTERN void OGRFeatureShadow_SetField__SWIG_2(OGRFeatureShadow *self,int id,double value){
     OGR_F_SetFieldDouble(self, id, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_3(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,int second,int tzflag){
-    OGR_F_SetFieldDateTime(self, id, year, month, day,
+
+SWIGINTERN int
+SWIG_AsVal_float SWIG_PERL_DECL_ARGS_2(SV * obj, float *val)
+{
+  double v;
+  int res = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < -FLT_MAX || v > FLT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = static_cast< float >(v);
+    }
+  }  
+  return res;
+}
+
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_3(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,float second,int tzflag){
+    OGR_F_SetFieldDateTimeEx(self, id, year, month, day,
                              hour, minute, second, 
                              tzflag);
   }
@@ -2460,17 +2515,25 @@ SWIGINTERN void OGRFeatureShadow_SetStyleString(OGRFeatureShadow *self,char cons
     OGR_F_SetStyleString(self, the_string);
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_0(OGRFeatureShadow *self,int id){
-    return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, id));
+      OGRFieldDefnH fd = OGR_F_GetFieldDefnRef( self,  id );
+      if (fd)
+          return (OGRFieldType) OGR_Fld_GetType( fd );
+      else
+          return (OGRFieldType)0;
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *self,char const *name){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1) {
-	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
-	  return (OGRFieldType)0;
+          CPLError(CE_Failure, 1, "No such field: '%s'", name);
+          return (OGRFieldType)0;
       } else
-	  return (OGRFieldType) OGR_Fld_GetType( 
-	      OGR_F_GetFieldDefnRef( self,  i )
-	      );
+          return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, i ) );
+  }
+SWIGINTERN int OGRFeatureShadow_Validate(OGRFeatureShadow *self,int flags=OGR_F_VAL_ALL,int bEmitError=TRUE){
+    return OGR_F_Validate(self, flags, bEmitError);
+  }
+SWIGINTERN void OGRFeatureShadow_FillUnsetWithDefault(OGRFeatureShadow *self,int bNotNullableOnly=FALSE,char **options=NULL){
+    OGR_F_FillUnsetWithDefault(self, bNotNullableOnly, options );
   }
 
     static int ValidateOGRGeometryType(OGRwkbGeometryType field_type)
@@ -2485,8 +2548,18 @@ SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *
             case wkbMultiLineString:
             case wkbMultiPolygon:
             case wkbGeometryCollection:
+            case wkbCircularString:
+            case wkbCompoundCurve:
+            case wkbCurvePolygon:
+            case wkbMultiCurve:
+            case wkbMultiSurface:
             case wkbNone:
             /*case wkbLinearRing:*/
+            case wkbCircularStringZ:
+            case wkbCompoundCurveZ:
+            case wkbCurvePolygonZ:
+            case wkbMultiCurveZ:
+            case wkbMultiSurfaceZ:
             case wkbPoint25D:
             case wkbLineString25D:
             case wkbPolygon25D:
@@ -2580,6 +2653,8 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
             case OFTDate:
             case OFTTime:
             case OFTDateTime:
+            case OFTInteger64:
+            case OFTInteger64List:
                 return TRUE;
             default:
                 CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field type value");
@@ -2587,6 +2662,22 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
         }
     }
 
+
+    static int ValidateOGRFieldSubType(OGRFieldSubType field_subtype)
+    {
+        switch(field_subtype)
+        {
+            case OFSTNone:
+            case OFSTBoolean:
+            case OFSTInt16:
+            case OFSTFloat32:
+                return TRUE;
+            default:
+                CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field subtype value");
+                return FALSE;
+        }
+    }
+
 SWIGINTERN void delete_OGRFieldDefnShadow(OGRFieldDefnShadow *self){
     OGR_Fld_Destroy(self);
   }
@@ -2612,6 +2703,13 @@ SWIGINTERN void OGRFieldDefnShadow_SetType(OGRFieldDefnShadow *self,OGRFieldType
     if (ValidateOGRFieldType(type))
         OGR_Fld_SetType(self, type);
   }
+SWIGINTERN OGRFieldSubType OGRFieldDefnShadow_GetSubType(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetSubType(self);
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetSubType(OGRFieldDefnShadow *self,OGRFieldSubType type){
+    if (ValidateOGRFieldSubType(type))
+        OGR_Fld_SetSubType(self, type);
+  }
 SWIGINTERN OGRJustification OGRFieldDefnShadow_GetJustify(OGRFieldDefnShadow *self){
     return OGR_Fld_GetJustify(self);
   }
@@ -2640,7 +2738,22 @@ SWIGINTERN int OGRFieldDefnShadow_IsIgnored(OGRFieldDefnShadow *self){
     return OGR_Fld_IsIgnored( self );
   }
 SWIGINTERN void OGRFieldDefnShadow_SetIgnored(OGRFieldDefnShadow *self,int bIgnored){
-    return OGR_Fld_SetIgnored( self, bIgnored );
+    OGR_Fld_SetIgnored( self, bIgnored );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsNullable(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsNullable( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetNullable(OGRFieldDefnShadow *self,int bNullable){
+    OGR_Fld_SetNullable( self, bNullable );
+  }
+SWIGINTERN char const *OGRFieldDefnShadow_GetDefault(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetDefault( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetDefault(OGRFieldDefnShadow *self,char const *pszValue){
+    OGR_Fld_SetDefault( self, pszValue );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsDefaultDriverSpecific(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsDefaultDriverSpecific( self );
   }
 SWIGINTERN void delete_OGRGeomFieldDefnShadow(OGRGeomFieldDefnShadow *self){
     OGR_GFld_Destroy(self);
@@ -2682,6 +2795,12 @@ SWIGINTERN int OGRGeomFieldDefnShadow_IsIgnored(OGRGeomFieldDefnShadow *self){
 SWIGINTERN void OGRGeomFieldDefnShadow_SetIgnored(OGRGeomFieldDefnShadow *self,int bIgnored){
     OGR_GFld_SetIgnored( self, bIgnored );
   }
+SWIGINTERN int OGRGeomFieldDefnShadow_IsNullable(OGRGeomFieldDefnShadow *self){
+    return OGR_GFld_IsNullable( self );
+  }
+SWIGINTERN void OGRGeomFieldDefnShadow_SetNullable(OGRGeomFieldDefnShadow *self,int bNullable){
+    return OGR_GFld_SetNullable( self, bNullable );
+  }
 
   OGRGeometryShadow* CreateGeometryFromWkb( int len, char *bin_string, 
                                             OSRSpatialReferenceShadow *reference=NULL ) {
@@ -2796,6 +2915,13 @@ OGRGeometryShadow* ForceToMultiLineString( OGRGeometryShadow *geom_in ) {
  return (OGRGeometryShadow* )OGR_G_ForceToMultiLineString( OGR_G_Clone(geom_in) );
 }
 
+
+OGRGeometryShadow* ForceTo( OGRGeometryShadow *geom_in, OGRwkbGeometryType eTargetType, char** options = NULL ) {
+ if (geom_in == NULL)
+     return NULL;
+ return (OGRGeometryShadow* )OGR_G_ForceTo( OGR_G_Clone(geom_in), eTargetType, options );
+}
+
 SWIGINTERN void delete_OGRGeometryShadow(OGRGeometryShadow *self){
     OGR_G_DestroyGeometry( self );
   }
@@ -2821,11 +2947,19 @@ SWIGINTERN OGRGeometryShadow *new_OGRGeometryShadow(OGRwkbGeometryType type=wkbU
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkt(OGRGeometryShadow *self,char **argout){
     return OGR_G_ExportToWkt(self, argout);
   }
+SWIGINTERN OGRErr OGRGeometryShadow_ExportToIsoWkt(OGRGeometryShadow *self,char **argout){
+    return OGR_G_ExportToIsoWkt(self, argout);
+  }
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkb(OGRGeometryShadow *self,int *nLen,char **pBuf,OGRwkbByteOrder byte_order=wkbXDR){
     *nLen = OGR_G_WkbSize( self );
     *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
     return OGR_G_ExportToWkb(self, byte_order, (unsigned char*) *pBuf );
   }
+SWIGINTERN OGRErr OGRGeometryShadow_ExportToIsoWkb(OGRGeometryShadow *self,int *nLen,char **pBuf,OGRwkbByteOrder byte_order=wkbXDR){
+    *nLen = OGR_G_WkbSize( self );
+    *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
+    return OGR_G_ExportToIsoWkb(self, byte_order, (unsigned char*) *pBuf );
+  }
 SWIGINTERN retStringAndCPLFree *OGRGeometryShadow_ExportToGML(OGRGeometryShadow *self,char **options=0){
     return (retStringAndCPLFree*) OGR_G_ExportToGMLEx(self, options);
   }
@@ -3031,18 +3165,30 @@ SWIGINTERN void OGRGeometryShadow_SetCoordinateDimension(OGRGeometryShadow *self
 SWIGINTERN int OGRGeometryShadow_GetDimension(OGRGeometryShadow *self){
     return OGR_G_GetDimension(self);
   }
+SWIGINTERN int OGRGeometryShadow_HasCurveGeometry(OGRGeometryShadow *self,int bLookForCircular=FALSE){
+        return OGR_G_HasCurveGeometry(self, bLookForCircular);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetLinearGeometry(OGRGeometryShadow *self,double dfMaxAngleStepSizeDegrees=0.0,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetLinearGeometry(self, dfMaxAngleStepSizeDegrees, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetCurveGeometry(OGRGeometryShadow *self,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetCurveGeometry(self, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_Value(OGRGeometryShadow *self,double dfDistance){
+    return OGR_G_Value(self, dfDistance);
+  }
 SWIGINTERN void OGRGeometryShadow_Move(OGRGeometryShadow *self,double dx,double dy,double dz=0){
-	int n = OGR_G_GetGeometryCount(self);
-	if (n > 0) {
-	    int i;
-	    for (i = 0; i < n; i++) {
-		OGRGeometryShadow *g = (OGRGeometryShadow*)OGR_G_GetGeometryRef(self, i);
-		OGRGeometryShadow_Move(g, dx, dy, dz);
-	    }
-	} else {
-	    int i;
-	    int d = OGR_G_GetCoordinateDimension(self);
-	    for (i = 0; i < OGR_G_GetPointCount(self); i++) {
+        int n = OGR_G_GetGeometryCount(self);
+        if (n > 0) {
+            int i;
+            for (i = 0; i < n; i++) {
+                OGRGeometryShadow *g = (OGRGeometryShadow*)OGR_G_GetGeometryRef(self, i);
+                OGRGeometryShadow_Move(g, dx, dy, dz);
+            }
+        } else {
+            int i;
+            int d = OGR_G_GetCoordinateDimension(self);
+            for (i = 0; i < OGR_G_GetPointCount(self); i++) {
                 if (d == 0) {
                 } else {
                     double x = OGR_G_GetX(self, i);
@@ -3054,8 +3200,8 @@ SWIGINTERN void OGRGeometryShadow_Move(OGRGeometryShadow *self,double dx,double
                         OGR_G_SetPoint(self, i, x+dx, y+dy, z+dz);
                     }
                 }
-	    }
-	}
+            }
+        }
     }
 
 char const *OGRDriverShadow_get_name( OGRDriverShadow *h ) {
@@ -3075,6 +3221,12 @@ char const *OGRDataSourceShadow_name_get( OGRDataSourceShadow *h ) {
 }
 
 
+OGRwkbGeometryType GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM = FALSE)
+{
+    return OGR_GT_SetModifier(eType, bSetZ, bSetM);
+}
+
+
   OGRDataSourceShadow* GetOpenDS(int ds_number) {
     OGRDataSourceShadow* layer = (OGRDataSourceShadow*) OGRGetOpenDS(ds_number);
     return layer;
@@ -3884,9 +4036,9 @@ XS(_wrap_Driver_CreateDataSource) {
                 arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -3995,9 +4147,9 @@ XS(_wrap_Driver_CopyDataSource) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -4907,6 +5059,58 @@ XS(_wrap_DataSource_SyncToDisk) {
 }
 
 
+XS(_wrap_DataSource_FlushCache) {
+  {
+    OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: DataSource_FlushCache(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_FlushCache" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+    {
+      CPLErrorReset();
+      OGRDataSourceShadow_FlushCache(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_DataSource__CreateLayer) {
   {
     OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
@@ -4976,9 +5180,9 @@ XS(_wrap_DataSource__CreateLayer) {
                 arg5 = CSLAddNameValue( arg5, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -5093,9 +5297,9 @@ XS(_wrap_DataSource_CopyLayer) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -5150,7 +5354,7 @@ XS(_wrap_DataSource_CopyLayer) {
 }
 
 
-XS(_wrap_DataSource__GetLayerByIndex) {
+XS(_wrap_DataSource_GetLayerByIndex) {
   {
     OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
     int arg2 = (int) 0 ;
@@ -5163,17 +5367,17 @@ XS(_wrap_DataSource__GetLayerByIndex) {
     dXSARGS;
     
     if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: DataSource__GetLayerByIndex(self,index);");
+      SWIG_croak("Usage: DataSource_GetLayerByIndex(self,index);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource__GetLayerByIndex" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByIndex" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
     if (items > 1) {
       ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
       if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource__GetLayerByIndex" "', argument " "2"" of type '" "int""'");
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_GetLayerByIndex" "', argument " "2"" of type '" "int""'");
       } 
       arg2 = static_cast< int >(val2);
     }
@@ -5213,7 +5417,7 @@ XS(_wrap_DataSource__GetLayerByIndex) {
 }
 
 
-XS(_wrap_DataSource__GetLayerByName) {
+XS(_wrap_DataSource_GetLayerByName) {
   {
     OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
     char *arg2 = (char *) 0 ;
@@ -5224,11 +5428,11 @@ XS(_wrap_DataSource__GetLayerByName) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: DataSource__GetLayerByName(self,layer_name);");
+      SWIG_croak("Usage: DataSource_GetLayerByName(self,layer_name);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource__GetLayerByName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
     {
@@ -5429,7 +5633,7 @@ XS(_wrap_DataSource__ExecuteSQL) {
 }
 
 
-XS(_wrap_DataSource_ReleaseResultSet) {
+XS(_wrap_DataSource__ReleaseResultSet) {
   {
     OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
     OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
@@ -5440,16 +5644,16 @@ XS(_wrap_DataSource_ReleaseResultSet) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: DataSource_ReleaseResultSet(self,layer);");
+      SWIG_croak("Usage: DataSource__ReleaseResultSet(self,layer);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_ReleaseResultSet" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource__ReleaseResultSet" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRLayerShadow, SWIG_POINTER_DISOWN |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_ReleaseResultSet" "', argument " "2"" of type '" "OGRLayerShadow *""'");
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource__ReleaseResultSet" "', argument " "2"" of type '" "OGRLayerShadow *""'");
     }
     {
       CPLErrorReset();
@@ -5602,26 +5806,36 @@ XS(_wrap_DataSource_SetStyleTable) {
 }
 
 
-XS(_wrap_Layer_GetRefCount) {
+XS(_wrap_DataSource_StartTransaction) {
   {
-    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+    OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+    int arg2 = (int) FALSE ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    int result;
+    OGRErr result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Layer_GetRefCount(self);");
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: DataSource_StartTransaction(self,force);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetRefCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_StartTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_StartTransaction" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
-    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRLayerShadow_GetRefCount(arg1);
+      result = (OGRErr)OGRDataSourceShadow_StartTransaction(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -5643,43 +5857,45 @@ XS(_wrap_Layer_GetRefCount) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Layer_SetSpatialFilter__SWIG_0) {
+XS(_wrap_DataSource_CommitTransaction) {
   {
-    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
+    OGRErr result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Layer_SetSpatialFilter(self,filter);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: DataSource_CommitTransaction(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CommitTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
     }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRLayerShadow_SetSpatialFilter__SWIG_0(arg1,arg2);
+      result = (OGRErr)OGRDataSourceShadow_CommitTransaction(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -5702,70 +5918,42 @@ XS(_wrap_Layer_SetSpatialFilter__SWIG_0) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Layer_SetSpatialFilterRect__SWIG_0) {
+XS(_wrap_DataSource_RollbackTransaction) {
   {
-    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    double arg2 ;
-    double arg3 ;
-    double arg4 ;
-    double arg5 ;
+    OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
-    double val5 ;
-    int ecode5 = 0 ;
     int argvi = 0;
+    OGRErr result;
     dXSARGS;
     
-    if ((items < 5) || (items > 5)) {
-      SWIG_croak("Usage: Layer_SetSpatialFilterRect(self,minx,miny,maxx,maxy);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: DataSource_RollbackTransaction(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_RollbackTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
-    } 
-    arg3 = static_cast< double >(val3);
-    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
-    } 
-    arg4 = static_cast< double >(val4);
-    ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
-    if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
-    } 
-    arg5 = static_cast< double >(val5);
+    arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRLayerShadow_SetSpatialFilterRect__SWIG_0(arg1,arg2,arg3,arg4,arg5);
+      result = (OGRErr)OGRDataSourceShadow_RollbackTransaction(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -5788,42 +5976,244 @@ XS(_wrap_Layer_SetSpatialFilterRect__SWIG_0) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
-    
-    
-    
-    
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Layer_SetSpatialFilter__SWIG_1) {
+XS(_wrap_Layer_GetRefCount) {
   {
     OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    int arg2 ;
-    OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    void *argp3 = 0 ;
-    int res3 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 3) || (items > 3)) {
-      SWIG_croak("Usage: Layer_SetSpatialFilter(self,iGeomField,filter);");
-    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Layer_GetRefCount(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetRefCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (int)OGRLayerShadow_GetRefCount(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Layer_SetSpatialFilter__SWIG_0) {
+  {
+    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Layer_SetSpatialFilter(self,filter);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      CPLErrorReset();
+      OGRLayerShadow_SetSpatialFilter__SWIG_0(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Layer_SetSpatialFilterRect__SWIG_0) {
+  {
+    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+    double arg2 ;
+    double arg3 ;
+    double arg4 ;
+    double arg5 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
+    double val5 ;
+    int ecode5 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 5) || (items > 5)) {
+      SWIG_croak("Usage: Layer_SetSpatialFilterRect(self,minx,miny,maxx,maxy);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
+    } 
+    arg4 = static_cast< double >(val4);
+    ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
+    if (!SWIG_IsOK(ecode5)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
+    } 
+    arg5 = static_cast< double >(val5);
+    {
+      CPLErrorReset();
+      OGRLayerShadow_SetSpatialFilterRect__SWIG_0(arg1,arg2,arg3,arg4,arg5);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Layer_SetSpatialFilter__SWIG_1) {
+  {
+    OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+    int arg2 ;
+    OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    void *argp3 = 0 ;
+    int res3 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: Layer_SetSpatialFilter(self,iGeomField,filter);");
+    }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
@@ -6620,11 +7010,9 @@ XS(_wrap_Layer_GetFIDColumn) {
 XS(_wrap_Layer_GetFeature) {
   {
     OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    long arg2 ;
+    GIntBig arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    long val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
     OGRFeatureShadow *result = 0 ;
     dXSARGS;
@@ -6637,11 +7025,10 @@ XS(_wrap_Layer_GetFeature) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-    ecode2 = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_GetFeature" "', argument " "2"" of type '" "long""'");
-    } 
-    arg2 = static_cast< long >(val2);
+    {
+      /* %typemap(in) GIntBig */
+      arg2 = SvIV(ST(1)); //FIXME is that right ??
+    }
     {
       CPLErrorReset();
       result = (OGRFeatureShadow *)OGRLayerShadow_GetFeature(arg1,arg2);
@@ -6668,11 +7055,9 @@ XS(_wrap_Layer_GetFeature) {
     }
     ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
@@ -6732,11 +7117,9 @@ XS(_wrap_Layer_GetNextFeature) {
 XS(_wrap_Layer_SetNextByIndex) {
   {
     OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    long arg2 ;
+    GIntBig arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    long val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
     OGRErr result;
     dXSARGS;
@@ -6749,11 +7132,10 @@ XS(_wrap_Layer_SetNextByIndex) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetNextByIndex" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-    ecode2 = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetNextByIndex" "', argument " "2"" of type '" "long""'");
-    } 
-    arg2 = static_cast< long >(val2);
+    {
+      /* %typemap(in) GIntBig */
+      arg2 = SvIV(ST(1)); //FIXME is that right ??
+    }
     {
       CPLErrorReset();
       result = (OGRErr)OGRLayerShadow_SetNextByIndex(arg1,arg2);
@@ -6787,11 +7169,9 @@ XS(_wrap_Layer_SetNextByIndex) {
       }
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
@@ -6946,11 +7326,9 @@ XS(_wrap_Layer_CreateFeature) {
 XS(_wrap_Layer_DeleteFeature) {
   {
     OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-    long arg2 ;
+    GIntBig arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    long val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
     OGRErr result;
     dXSARGS;
@@ -6963,11 +7341,10 @@ XS(_wrap_Layer_DeleteFeature) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_DeleteFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-    ecode2 = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_DeleteFeature" "', argument " "2"" of type '" "long""'");
-    } 
-    arg2 = static_cast< long >(val2);
+    {
+      /* %typemap(in) GIntBig */
+      arg2 = SvIV(ST(1)); //FIXME is that right ??
+    }
     {
       CPLErrorReset();
       result = (OGRErr)OGRLayerShadow_DeleteFeature(arg1,arg2);
@@ -7001,11 +7378,9 @@ XS(_wrap_Layer_DeleteFeature) {
       }
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
@@ -7129,7 +7504,7 @@ XS(_wrap_Layer_GetFeatureCount) {
     int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
-    int result;
+    GIntBig result;
     dXSARGS;
     
     if ((items < 1) || (items > 2)) {
@@ -7149,7 +7524,7 @@ XS(_wrap_Layer_GetFeatureCount) {
     }
     {
       CPLErrorReset();
-      result = (int)OGRLayerShadow_GetFeatureCount(arg1,arg2);
+      result = OGRLayerShadow_GetFeatureCount(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -7171,7 +7546,12 @@ XS(_wrap_Layer_GetFeatureCount) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) GIntBig */
+      ST(argvi) = sv_newmortal();
+      sv_setiv(ST(argvi), (IV) result);
+      argvi++;
+    }
     
     
     XSRETURN(argvi);
@@ -7594,14 +7974,17 @@ XS(_wrap_Layer_ReorderFields) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList) */
       if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(1)));
       arg2 = av_len(av)+1;
-      arg3 = (int*) malloc(arg2*sizeof(int));
-      for( int i = 0; i<arg2; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg3[i] =  SvIV(*sv);
-      }
+      arg3 = (int*)CPLMalloc(arg2*sizeof(int));
+      if (arg3) {
+        for( int i = 0; i<arg2; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg3[i] =  SvIV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       CPLErrorReset();
@@ -7638,23 +8021,21 @@ XS(_wrap_Layer_ReorderFields) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg3)
-      free((void*) arg3);
+      CPLFree((void*) arg3);
     }
     XSRETURN(argvi);
   fail:
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg3)
-      free((void*) arg3);
+      CPLFree((void*) arg3);
     }
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Layer_AlterFieldDefn) {
+XS(_wrap_Layer__AlterFieldDefn) {
   {
     OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
     int arg2 ;
@@ -7673,26 +8054,26 @@ XS(_wrap_Layer_AlterFieldDefn) {
     dXSARGS;
     
     if ((items < 4) || (items > 4)) {
-      SWIG_croak("Usage: Layer_AlterFieldDefn(self,iField,field_def,nFlags);");
+      SWIG_croak("Usage: Layer__AlterFieldDefn(self,iField,field_def,nFlags);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_AlterFieldDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer__AlterFieldDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_AlterFieldDefn" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer__AlterFieldDefn" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     res3 = SWIG_ConvertPtr(ST(2), &argp3,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_AlterFieldDefn" "', argument " "3"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer__AlterFieldDefn" "', argument " "3"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg3 = reinterpret_cast< OGRFieldDefnShadow * >(argp3);
     ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_AlterFieldDefn" "', argument " "4"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer__AlterFieldDefn" "', argument " "4"" of type '" "int""'");
     } 
     arg4 = static_cast< int >(val4);
     {
@@ -8227,9 +8608,9 @@ XS(_wrap_Layer_SetIgnoredFields) {
               arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -8347,9 +8728,9 @@ XS(_wrap_Layer_Intersection) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -8498,9 +8879,9 @@ XS(_wrap_Layer_Union) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -8649,9 +9030,9 @@ XS(_wrap_Layer_SymDifference) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -8800,9 +9181,9 @@ XS(_wrap_Layer_Identity) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -8951,9 +9332,9 @@ XS(_wrap_Layer_Update) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -9102,9 +9483,9 @@ XS(_wrap_Layer_Clip) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -9253,9 +9634,9 @@ XS(_wrap_Layer_Erase) {
                 arg4 = CSLAddNameValue( arg4, key, SvPV_nolen(sv) );
               }
             } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+          SWIG_croak("The 'options' argument is not a reference.");   
         }
       }
     }
@@ -9610,7 +9991,7 @@ XS(_wrap_Feature_GetDefnRef) {
 }
 
 
-XS(_wrap_Feature_SetGeometry) {
+XS(_wrap_Feature__SetGeometry) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -9623,16 +10004,16 @@ XS(_wrap_Feature_SetGeometry) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Feature_SetGeometry(self,geom);");
+      SWIG_croak("Usage: Feature__SetGeometry(self,geom);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometry" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature__SetGeometry" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature__SetGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -9683,7 +10064,7 @@ XS(_wrap_Feature_SetGeometry) {
 }
 
 
-XS(_wrap_Feature__SetGeometryDirectly) {
+XS(_wrap_Feature_SetGeometryDirectly) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -9695,16 +10076,16 @@ XS(_wrap_Feature__SetGeometryDirectly) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Feature__SetGeometryDirectly(self,geom);");
+      SWIG_croak("Usage: Feature_SetGeometryDirectly(self,geom);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature__SetGeometryDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometryDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature__SetGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
     }
     {
       /* %typemap(check) (OGRGeometryShadow *geom) */
@@ -11267,7 +11648,7 @@ XS(_wrap_Feature_GetFieldAsInteger) {
 }
 
 
-XS(_wrap_Feature_GetFieldAsDouble) {
+XS(_wrap_Feature_GetFieldAsInteger64) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
     int arg2 ;
@@ -11276,25 +11657,25 @@ XS(_wrap_Feature_GetFieldAsDouble) {
     int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
-    double result;
+    GIntBig result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Feature_GetFieldAsDouble(self,id);");
+      SWIG_croak("Usage: Feature_GetFieldAsInteger64(self,id);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger64" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsInteger64" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (double)OGRFeatureShadow_GetFieldAsDouble(arg1,arg2);
+      result = OGRFeatureShadow_GetFieldAsInteger64(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -11316,9 +11697,75 @@ XS(_wrap_Feature_GetFieldAsDouble) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
-    
+    {
+      /* %typemap(out) GIntBig */
+      ST(argvi) = sv_newmortal();
+      sv_setiv(ST(argvi), (IV) result);
+      argvi++;
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Feature_GetFieldAsDouble) {
+  {
+    OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    double result;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Feature_GetFieldAsDouble(self,id);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+    {
+      CPLErrorReset();
+      result = (double)OGRFeatureShadow_GetFieldAsDouble(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    
+    
     XSRETURN(argvi);
   fail:
     
@@ -11337,7 +11784,7 @@ XS(_wrap_Feature_GetFieldAsDateTime) {
     int *arg5 = (int *) 0 ;
     int *arg6 = (int *) 0 ;
     int *arg7 = (int *) 0 ;
-    int *arg8 = (int *) 0 ;
+    float *arg8 = (float *) 0 ;
     int *arg9 = (int *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
@@ -11353,7 +11800,7 @@ XS(_wrap_Feature_GetFieldAsDateTime) {
     int res6 = SWIG_TMPOBJ ;
     int temp7 ;
     int res7 = SWIG_TMPOBJ ;
-    int temp8 ;
+    float temp8 ;
     int res8 = SWIG_TMPOBJ ;
     int temp9 ;
     int res9 = SWIG_TMPOBJ ;
@@ -11438,10 +11885,10 @@ XS(_wrap_Feature_GetFieldAsDateTime) {
       if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_NewPointerObj((void*)(arg7), SWIGTYPE_p_int, new_flags); argvi++  ;
     }
     if (SWIG_IsTmpObj(res8)) {
-      if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1((*arg8)); argvi++  ;
+      if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_From_float  SWIG_PERL_CALL_ARGS_1((*arg8)); argvi++  ;
     } else {
       int new_flags = SWIG_IsNewObj(res8) ? (SWIG_POINTER_OWN | 0) : 0;
-      if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_NewPointerObj((void*)(arg8), SWIGTYPE_p_int, new_flags); argvi++  ;
+      if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_NewPointerObj((void*)(arg8), SWIGTYPE_p_float, new_flags); argvi++  ;
     }
     if (SWIG_IsTmpObj(res9)) {
       if (argvi >= items) EXTEND(sp,1);  ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1((*arg9)); argvi++  ;
@@ -11701,6 +12148,100 @@ XS(_wrap_Feature_GetFieldAsStringList) {
 }
 
 
+XS(_wrap_Feature_GetFieldAsBinary) {
+  {
+    OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+    int arg2 ;
+    int *arg3 = (int *) 0 ;
+    char **arg4 = (char **) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int nLen3 = 0 ;
+    char *pBuf3 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    {
+      /* %typemap(in,numinputs=0) (int *nLen3, char **pBuf3 ) */
+      arg3 = &nLen3;
+      arg4 = &pBuf3;
+    }
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Feature_GetFieldAsBinary(self,id,pBuf);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsBinary" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsBinary" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRFeatureShadow_GetFieldAsBinary(arg1,arg2,arg3,arg4);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    {
+      /* %typemap(argout) (int *nLen, char **pBuf ) */
+      ST(argvi) = sv_2mortal(newSVpv( *arg4, *arg3 ));
+      argvi++;
+    }
+    
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg3 ) {
+        free( *arg4 );
+      }
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg3 ) {
+        free( *arg4 );
+      }
+    }
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_Feature_IsFieldSet__SWIG_0) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
@@ -12034,7 +12575,7 @@ XS(_wrap_Feature_GetFID) {
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    int result;
+    GIntBig result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
@@ -12047,7 +12588,7 @@ XS(_wrap_Feature_GetFID) {
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRFeatureShadow_GetFID(arg1);
+      result = OGRFeatureShadow_GetFID(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -12069,7 +12610,12 @@ XS(_wrap_Feature_GetFID) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) GIntBig */
+      ST(argvi) = sv_newmortal();
+      sv_setiv(ST(argvi), (IV) result);
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -12082,11 +12628,9 @@ XS(_wrap_Feature_GetFID) {
 XS(_wrap_Feature_SetFID) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-    int arg2 ;
+    GIntBig arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
     OGRErr result;
     dXSARGS;
@@ -12099,11 +12643,10 @@ XS(_wrap_Feature_SetFID) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFID" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFID" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+    {
+      /* %typemap(in) GIntBig */
+      arg2 = SvIV(ST(1)); //FIXME is that right ??
+    }
     {
       CPLErrorReset();
       result = (OGRErr)OGRFeatureShadow_SetFID(arg1,arg2);
@@ -12137,11 +12680,9 @@ XS(_wrap_Feature_SetFID) {
       }
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
@@ -12329,6 +12870,73 @@ XS(_wrap_Feature__SetField__SWIG_0) {
 }
 
 
+XS(_wrap_Feature_SetFieldInteger64) {
+  {
+    OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+    int arg2 ;
+    GIntBig arg3 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: Feature_SetFieldInteger64(self,id,value);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldInteger64" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldInteger64" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+    {
+      /* %typemap(in) GIntBig */
+      arg3 = SvIV(ST(2)); //FIXME is that right ??
+    }
+    {
+      CPLErrorReset();
+      OGRFeatureShadow_SetFieldInteger64(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_Feature__SetField__SWIG_1) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
@@ -12482,7 +13090,7 @@ XS(_wrap_Feature__SetField__SWIG_3) {
     int arg5 ;
     int arg6 ;
     int arg7 ;
-    int arg8 ;
+    float arg8 ;
     int arg9 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
@@ -12498,7 +13106,7 @@ XS(_wrap_Feature__SetField__SWIG_3) {
     int ecode6 = 0 ;
     int val7 ;
     int ecode7 = 0 ;
-    int val8 ;
+    float val8 ;
     int ecode8 = 0 ;
     int val9 ;
     int ecode9 = 0 ;
@@ -12543,11 +13151,11 @@ XS(_wrap_Feature__SetField__SWIG_3) {
       SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Feature__SetField" "', argument " "7"" of type '" "int""'");
     } 
     arg7 = static_cast< int >(val7);
-    ecode8 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(7), &val8);
+    ecode8 = SWIG_AsVal_float SWIG_PERL_CALL_ARGS_2(ST(7), &val8);
     if (!SWIG_IsOK(ecode8)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature__SetField" "', argument " "8"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature__SetField" "', argument " "8"" of type '" "float""'");
     } 
-    arg8 = static_cast< int >(val8);
+    arg8 = static_cast< float >(val8);
     ecode9 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(8), &val9);
     if (!SWIG_IsOK(ecode9)) {
       SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Feature__SetField" "', argument " "9"" of type '" "int""'");
@@ -12810,7 +13418,7 @@ XS(_wrap_Feature__SetField) {
       _pi *= SWIG_MAXCASTRANK;
       {
         {
-          int res = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(7), NULL);
+          int res = SWIG_AsVal_float SWIG_PERL_CALL_ARGS_2(ST(7), NULL);
           _v = SWIG_CheckState(res);
         }
       }
@@ -12882,14 +13490,17 @@ XS(_wrap_Feature_SetFieldIntegerList) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList) */
       if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(2)));
       arg3 = av_len(av)+1;
-      arg4 = (int*) malloc(arg3*sizeof(int));
-      for( int i = 0; i<arg3; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg4[i] =  SvIV(*sv);
-      }
+      arg4 = (int*)CPLMalloc(arg3*sizeof(int));
+      if (arg4) {
+        for( int i = 0; i<arg3; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg4[i] =  SvIV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       CPLErrorReset();
@@ -12922,8 +13533,7 @@ XS(_wrap_Feature_SetFieldIntegerList) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     XSRETURN(argvi);
   fail:
@@ -12931,8 +13541,7 @@ XS(_wrap_Feature_SetFieldIntegerList) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     SWIG_croak_null();
   }
@@ -12968,14 +13577,17 @@ XS(_wrap_Feature_SetFieldDoubleList) {
     {
       /* %typemap(in,numinputs=1) (int nList, double* pList) */
       if (!(SvROK(ST(2)) && (SvTYPE(SvRV(ST(2)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(2)));
       arg3 = av_len(av)+1;
-      arg4 = (double*) malloc(arg3*sizeof(double));
-      for( int i = 0; i<arg3; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg4[i] =  SvNV(*sv);
-      }
+      arg4 = (double*)CPLMalloc(arg3*sizeof(double));
+      if (arg4) {
+        for( int i = 0; i<arg3; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg4[i] =  SvNV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       CPLErrorReset();
@@ -13008,8 +13620,7 @@ XS(_wrap_Feature_SetFieldDoubleList) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     XSRETURN(argvi);
   fail:
@@ -13017,8 +13628,7 @@ XS(_wrap_Feature_SetFieldDoubleList) {
     
     {
       /* %typemap(freearg) (int nList, double* pList) */
-      if (arg4)
-      free((void*) arg4);
+      CPLFree((void*) arg4);
     }
     SWIG_croak_null();
   }
@@ -13074,9 +13684,9 @@ XS(_wrap_Feature_SetFieldStringList) {
               arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -13491,14 +14101,17 @@ XS(_wrap_Feature_SetFromWithMap) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList) */
       if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(3)));
       arg4 = av_len(av)+1;
-      arg5 = (int*) malloc(arg4*sizeof(int));
-      for( int i = 0; i<arg4; i++ ) {
-        SV **sv = av_fetch(av, i, 0);
-        arg5[i] =  SvIV(*sv);
-      }
+      arg5 = (int*)CPLMalloc(arg4*sizeof(int));
+      if (arg5) {
+        for( int i = 0; i<arg4; i++ ) {
+          SV **sv = av_fetch(av, i, 0);
+          arg5[i] =  SvIV(*sv);
+        }
+      } else
+      SWIG_fail;
     }
     {
       if (!arg2) {
@@ -13542,8 +14155,7 @@ XS(_wrap_Feature_SetFromWithMap) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     XSRETURN(argvi);
   fail:
@@ -13552,8 +14164,7 @@ XS(_wrap_Feature_SetFromWithMap) {
     
     {
       /* %typemap(freearg) (int nList, int* pList) */
-      if (arg5)
-      free((void*) arg5);
+      CPLFree((void*) arg5);
     }
     SWIG_croak_null();
   }
@@ -13680,7 +14291,7 @@ XS(_wrap_Feature_SetStyleString) {
 }
 
 
-XS(_wrap_Feature__GetFieldType__SWIG_0) {
+XS(_wrap_Feature_GetFieldType__SWIG_0) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
     int arg2 ;
@@ -13693,16 +14304,16 @@ XS(_wrap_Feature__GetFieldType__SWIG_0) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Feature__GetFieldType(self,id);");
+      SWIG_croak("Usage: Feature_GetFieldType(self,id);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature__GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature__GetFieldType" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldType" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     {
@@ -13741,7 +14352,7 @@ XS(_wrap_Feature__GetFieldType__SWIG_0) {
 }
 
 
-XS(_wrap_Feature__GetFieldType__SWIG_1) {
+XS(_wrap_Feature_GetFieldType__SWIG_1) {
   {
     OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
     char *arg2 = (char *) 0 ;
@@ -13752,11 +14363,11 @@ XS(_wrap_Feature__GetFieldType__SWIG_1) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Feature__GetFieldType(self,name);");
+      SWIG_croak("Usage: Feature_GetFieldType(self,name);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature__GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
     {
@@ -13803,7 +14414,7 @@ XS(_wrap_Feature__GetFieldType__SWIG_1) {
 }
 
 
-XS(_wrap_Feature__GetFieldType) {
+XS(_wrap_Feature_GetFieldType) {
   dXSARGS;
   
   {
@@ -13872,37 +14483,216 @@ XS(_wrap_Feature__GetFieldType) {
   dispatch:
     switch(_index) {
     case 1:
-      PUSHMARK(MARK); SWIG_CALLXS(_wrap_Feature__GetFieldType__SWIG_0); return;
+      PUSHMARK(MARK); SWIG_CALLXS(_wrap_Feature_GetFieldType__SWIG_0); return;
     case 2:
-      PUSHMARK(MARK); SWIG_CALLXS(_wrap_Feature__GetFieldType__SWIG_1); return;
+      PUSHMARK(MARK); SWIG_CALLXS(_wrap_Feature_GetFieldType__SWIG_1); return;
     }
   }
   
-  croak("No matching function for overloaded 'Feature__GetFieldType'");
+  croak("No matching function for overloaded 'Feature_GetFieldType'");
   XSRETURN(0);
 }
 
 
-XS(_wrap_delete_FeatureDefn) {
+XS(_wrap_Feature__Validate) {
   {
-    OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+    OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+    int arg2 = (int) OGR_F_VAL_ALL ;
+    int arg3 = (int) TRUE ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int val3 ;
+    int ecode3 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: delete_FeatureDefn(self);");
+    if ((items < 1) || (items > 3)) {
+      SWIG_croak("Usage: Feature__Validate(self,flags,bEmitError);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_DISOWN |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FeatureDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature__Validate" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-    {
-      CPLErrorReset();
-      delete_OGRFeatureDefnShadow(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
+    arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature__Validate" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
+    }
+    if (items > 2) {
+      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+      if (!SWIG_IsOK(ecode3)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature__Validate" "', argument " "3"" of type '" "int""'");
+      } 
+      arg3 = static_cast< int >(val3);
+    }
+    {
+      CPLErrorReset();
+      result = (int)OGRFeatureShadow_Validate(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Feature_FillUnsetWithDefault) {
+  {
+    OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+    int arg2 = (int) FALSE ;
+    char **arg3 = (char **) NULL ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 3)) {
+      SWIG_croak("Usage: Feature_FillUnsetWithDefault(self,bNotNullableOnly,options);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_FillUnsetWithDefault" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_FillUnsetWithDefault" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
+    }
+    if (items > 2) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(2))) {
+          if (SvROK(ST(2))) {
+            if (SvTYPE(SvRV(ST(2)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(2)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg3 = CSLAddString( arg3, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(2)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(2));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg3 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    {
+      CPLErrorReset();
+      OGRFeatureShadow_FillUnsetWithDefault(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_FeatureDefn) {
+  {
+    OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_FeatureDefn(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FeatureDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+    {
+      CPLErrorReset();
+      delete_OGRFeatureDefnShadow(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
         
@@ -15460,26 +16250,26 @@ XS(_wrap_FieldDefn_SetType) {
 }
 
 
-XS(_wrap_FieldDefn_GetJustify) {
+XS(_wrap_FieldDefn_GetSubType) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    OGRJustification result;
+    OGRFieldSubType result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: FieldDefn_GetJustify(self);");
+      SWIG_croak("Usage: FieldDefn_GetSubType(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetSubType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRJustification)OGRFieldDefnShadow_GetJustify(arg1);
+      result = (OGRFieldSubType)OGRFieldDefnShadow_GetSubType(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15511,10 +16301,10 @@ XS(_wrap_FieldDefn_GetJustify) {
 }
 
 
-XS(_wrap_FieldDefn_SetJustify) {
+XS(_wrap_FieldDefn_SetSubType) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-    OGRJustification arg2 ;
+    OGRFieldSubType arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
@@ -15523,21 +16313,21 @@ XS(_wrap_FieldDefn_SetJustify) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: FieldDefn_SetJustify(self,justify);");
+      SWIG_croak("Usage: FieldDefn_SetSubType(self,type);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetSubType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetJustify" "', argument " "2"" of type '" "OGRJustification""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetSubType" "', argument " "2"" of type '" "OGRFieldSubType""'");
     } 
-    arg2 = static_cast< OGRJustification >(val2);
+    arg2 = static_cast< OGRFieldSubType >(val2);
     {
       CPLErrorReset();
-      OGRFieldDefnShadow_SetJustify(arg1,arg2);
+      OGRFieldDefnShadow_SetSubType(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15573,26 +16363,26 @@ XS(_wrap_FieldDefn_SetJustify) {
 }
 
 
-XS(_wrap_FieldDefn_GetWidth) {
+XS(_wrap_FieldDefn_GetJustify) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    int result;
+    OGRJustification result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: FieldDefn_GetWidth(self);");
+      SWIG_croak("Usage: FieldDefn_GetJustify(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRFieldDefnShadow_GetWidth(arg1);
+      result = (OGRJustification)OGRFieldDefnShadow_GetJustify(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15624,10 +16414,10 @@ XS(_wrap_FieldDefn_GetWidth) {
 }
 
 
-XS(_wrap_FieldDefn_SetWidth) {
+XS(_wrap_FieldDefn_SetJustify) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-    int arg2 ;
+    OGRJustification arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
@@ -15636,21 +16426,21 @@ XS(_wrap_FieldDefn_SetWidth) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: FieldDefn_SetWidth(self,width);");
+      SWIG_croak("Usage: FieldDefn_SetJustify(self,justify);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetWidth" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetJustify" "', argument " "2"" of type '" "OGRJustification""'");
     } 
-    arg2 = static_cast< int >(val2);
+    arg2 = static_cast< OGRJustification >(val2);
     {
       CPLErrorReset();
-      OGRFieldDefnShadow_SetWidth(arg1,arg2);
+      OGRFieldDefnShadow_SetJustify(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15686,7 +16476,7 @@ XS(_wrap_FieldDefn_SetWidth) {
 }
 
 
-XS(_wrap_FieldDefn_GetPrecision) {
+XS(_wrap_FieldDefn_GetWidth) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
@@ -15696,16 +16486,16 @@ XS(_wrap_FieldDefn_GetPrecision) {
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: FieldDefn_GetPrecision(self);");
+      SWIG_croak("Usage: FieldDefn_GetWidth(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRFieldDefnShadow_GetPrecision(arg1);
+      result = (int)OGRFieldDefnShadow_GetWidth(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15737,7 +16527,7 @@ XS(_wrap_FieldDefn_GetPrecision) {
 }
 
 
-XS(_wrap_FieldDefn_SetPrecision) {
+XS(_wrap_FieldDefn_SetWidth) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     int arg2 ;
@@ -15749,21 +16539,21 @@ XS(_wrap_FieldDefn_SetPrecision) {
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: FieldDefn_SetPrecision(self,precision);");
+      SWIG_croak("Usage: FieldDefn_SetWidth(self,width);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetPrecision" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetWidth" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      OGRFieldDefnShadow_SetPrecision(arg1,arg2);
+      OGRFieldDefnShadow_SetWidth(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15799,26 +16589,26 @@ XS(_wrap_FieldDefn_SetPrecision) {
 }
 
 
-XS(_wrap_FieldDefn_GetTypeName) {
+XS(_wrap_FieldDefn_GetPrecision) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
+    int result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: FieldDefn_GetTypeName(self);");
+      SWIG_croak("Usage: FieldDefn_GetPrecision(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (char *)OGRFieldDefnShadow_GetTypeName(arg1);
+      result = (int)OGRFieldDefnShadow_GetPrecision(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15840,13 +16630,7 @@ XS(_wrap_FieldDefn_GetTypeName) {
       
       
     }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -15856,34 +16640,33 @@ XS(_wrap_FieldDefn_GetTypeName) {
 }
 
 
-XS(_wrap_FieldDefn_GetFieldTypeName) {
+XS(_wrap_FieldDefn_SetPrecision) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-    OGRFieldType arg2 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: FieldDefn_GetFieldTypeName(self,type);");
+      SWIG_croak("Usage: FieldDefn_SetPrecision(self,precision);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "2"" of type '" "OGRFieldType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetPrecision" "', argument " "2"" of type '" "int""'");
     } 
-    arg2 = static_cast< OGRFieldType >(val2);
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (char *)OGRFieldDefnShadow_GetFieldTypeName(arg1,arg2);
+      OGRFieldDefnShadow_SetPrecision(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15906,11 +16689,7 @@ XS(_wrap_FieldDefn_GetFieldTypeName) {
       
     }
     {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
+      /* %typemap(out) void */
     }
     
     
@@ -15923,26 +16702,26 @@ XS(_wrap_FieldDefn_GetFieldTypeName) {
 }
 
 
-XS(_wrap_FieldDefn_IsIgnored) {
+XS(_wrap_FieldDefn_GetTypeName) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    int result;
+    char *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: FieldDefn_IsIgnored(self);");
+      SWIG_croak("Usage: FieldDefn_GetTypeName(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRFieldDefnShadow_IsIgnored(arg1);
+      result = (char *)OGRFieldDefnShadow_GetTypeName(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -15964,7 +16743,13 @@ XS(_wrap_FieldDefn_IsIgnored) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -15974,33 +16759,34 @@ XS(_wrap_FieldDefn_IsIgnored) {
 }
 
 
-XS(_wrap_FieldDefn_SetIgnored) {
+XS(_wrap_FieldDefn_GetFieldTypeName) {
   {
     OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-    int arg2 ;
+    OGRFieldType arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
+    char *result = 0 ;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: FieldDefn_SetIgnored(self,bIgnored);");
+      SWIG_croak("Usage: FieldDefn_GetFieldTypeName(self,type);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "2"" of type '" "OGRFieldType""'");
     } 
-    arg2 = static_cast< int >(val2);
+    arg2 = static_cast< OGRFieldType >(val2);
     {
       CPLErrorReset();
-      OGRFieldDefnShadow_SetIgnored(arg1,arg2);
+      result = (char *)OGRFieldDefnShadow_GetFieldTypeName(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16023,7 +16809,11 @@ XS(_wrap_FieldDefn_SetIgnored) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
     }
     
     
@@ -16036,25 +16826,26 @@ XS(_wrap_FieldDefn_SetIgnored) {
 }
 
 
-XS(_wrap_delete_GeomFieldDefn) {
+XS(_wrap_FieldDefn_IsIgnored) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: delete_GeomFieldDefn(self);");
+      SWIG_croak("Usage: FieldDefn_IsIgnored(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_GeomFieldDefn" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      delete_OGRGeomFieldDefnShadow(arg1);
+      result = (int)OGRFieldDefnShadow_IsIgnored(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16076,9 +16867,7 @@ XS(_wrap_delete_GeomFieldDefn) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -16088,39 +16877,33 @@ XS(_wrap_delete_GeomFieldDefn) {
 }
 
 
-XS(_wrap_new_GeomFieldDefn) {
+XS(_wrap_FieldDefn_SetIgnored) {
   {
-    char *arg1 = (char *) "" ;
-    OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
-    int res1 ;
-    char *buf1 = 0 ;
-    int alloc1 = 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+    int arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int val2 ;
     int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeomFieldDefnShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 0) || (items > 2)) {
-      SWIG_croak("Usage: new_GeomFieldDefn(name_null_ok,field_type);");
-    }
-    if (items > 0) {
-      res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
-      if (!SWIG_IsOK(res1)) {
-        SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_GeomFieldDefn" "', argument " "1"" of type '" "char const *""'");
-      }
-      arg1 = reinterpret_cast< char * >(buf1);
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: FieldDefn_SetIgnored(self,bIgnored);");
     }
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_GeomFieldDefn" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
-      } 
-      arg2 = static_cast< OGRwkbGeometryType >(val2);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
+      OGRFieldDefnShadow_SetIgnored(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16142,38 +16925,40 @@ XS(_wrap_new_GeomFieldDefn) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    {
+      /* %typemap(out) void */
+    }
+    
     
     XSRETURN(argvi);
   fail:
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    
     
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeomFieldDefn_GetName) {
+XS(_wrap_FieldDefn_IsNullable) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
+    int result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeomFieldDefn_GetName(self);");
+      SWIG_croak("Usage: FieldDefn_IsNullable(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsNullable" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (char *)OGRGeomFieldDefnShadow_GetName(arg1);
+      result = (int)OGRFieldDefnShadow_IsNullable(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16195,13 +16980,7 @@ XS(_wrap_GeomFieldDefn_GetName) {
       
       
     }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -16211,26 +16990,33 @@ XS(_wrap_GeomFieldDefn_GetName) {
 }
 
 
-XS(_wrap_GeomFieldDefn_GetNameRef) {
+XS(_wrap_FieldDefn_SetNullable) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeomFieldDefn_GetNameRef(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: FieldDefn_SetNullable(self,bNullable);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetNullable" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetNullable" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (char *)OGRGeomFieldDefnShadow_GetNameRef(arg1);
+      OGRFieldDefnShadow_SetNullable(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16253,51 +17039,39 @@ XS(_wrap_GeomFieldDefn_GetNameRef) {
       
     }
     {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
+      /* %typemap(out) void */
     }
     
+    
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeomFieldDefn_SetName) {
+XS(_wrap_FieldDefn_GetDefault) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-    char *arg2 = (char *) 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
+    char *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GeomFieldDefn_SetName(self,name);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: FieldDefn_GetDefault(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-    {
-      /* %typemap(in,numinputs=1) (const char* name) */
-      sv_utf8_upgrade(ST(1));
-      arg2 = SvPV_nolen(ST(1));
-    }
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetDefault" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeomFieldDefnShadow_SetName(arg1,(char const *)arg2);
+      result = (char *)OGRFieldDefnShadow_GetDefault(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16320,7 +17094,11 @@ XS(_wrap_GeomFieldDefn_SetName) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
     }
     
     XSRETURN(argvi);
@@ -16331,26 +17109,34 @@ XS(_wrap_GeomFieldDefn_SetName) {
 }
 
 
-XS(_wrap_GeomFieldDefn_GetType) {
+XS(_wrap_FieldDefn_SetDefault) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+    char *arg2 = (char *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
     int argvi = 0;
-    OGRwkbGeometryType result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeomFieldDefn_GetType(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: FieldDefn_SetDefault(self,pszValue);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetDefault" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FieldDefn_SetDefault" "', argument " "2"" of type '" "char const *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
     {
       CPLErrorReset();
-      result = (OGRwkbGeometryType)OGRGeomFieldDefnShadow_GetType(arg1);
+      OGRFieldDefnShadow_SetDefault(arg1,(char const *)arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16372,43 +17158,40 @@ XS(_wrap_GeomFieldDefn_GetType) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     XSRETURN(argvi);
   fail:
     
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeomFieldDefn_SetType) {
+XS(_wrap_FieldDefn_IsDefaultDriverSpecific) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-    OGRwkbGeometryType arg2 ;
+    OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GeomFieldDefn_SetType(self,type);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: FieldDefn_IsDefaultDriverSpecific(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsDefaultDriverSpecific" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
-    } 
-    arg2 = static_cast< OGRwkbGeometryType >(val2);
+    arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeomFieldDefnShadow_SetType(arg1,arg2);
+      result = (int)OGRFieldDefnShadow_IsDefaultDriverSpecific(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16430,40 +17213,35 @@ XS(_wrap_GeomFieldDefn_SetType) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeomFieldDefn_GetSpatialRef) {
+XS(_wrap_delete_GeomFieldDefn) {
   {
     OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    OSRSpatialReferenceShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeomFieldDefn_GetSpatialRef(self);");
+      SWIG_croak("Usage: delete_GeomFieldDefn(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_GeomFieldDefn" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OSRSpatialReferenceShadow *)OGRGeomFieldDefnShadow_GetSpatialRef(arg1);
+      delete_OGRGeomFieldDefnShadow(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16485,7 +17263,9 @@ XS(_wrap_GeomFieldDefn_GetSpatialRef) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     XSRETURN(argvi);
   fail:
@@ -16495,33 +17275,39 @@ XS(_wrap_GeomFieldDefn_GetSpatialRef) {
 }
 
 
-XS(_wrap_GeomFieldDefn_SetSpatialRef) {
+XS(_wrap_new_GeomFieldDefn) {
   {
-    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    char *arg1 = (char *) "" ;
+    OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
+    OGRGeomFieldDefnShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GeomFieldDefn_SetSpatialRef(self,srs);");
+    if ((items < 0) || (items > 2)) {
+      SWIG_croak("Usage: new_GeomFieldDefn(name_null_ok,field_type);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    if (items > 0) {
+      res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+      if (!SWIG_IsOK(res1)) {
+        SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_GeomFieldDefn" "', argument " "1"" of type '" "char const *""'");
+      }
+      arg1 = reinterpret_cast< char * >(buf1);
     }
-    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_GeomFieldDefn" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
+      } 
+      arg2 = static_cast< OGRwkbGeometryType >(val2);
     }
-    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
     {
       CPLErrorReset();
-      OGRGeomFieldDefnShadow_SetSpatialRef(arg1,arg2);
+      result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16543,40 +17329,38 @@ XS(_wrap_GeomFieldDefn_SetSpatialRef) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
     
     XSRETURN(argvi);
   fail:
-    
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
     
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeomFieldDefn_IsIgnored) {
+XS(_wrap_GeomFieldDefn_GetName) {
   {
     OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    int result;
+    char *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeomFieldDefn_IsIgnored(self);");
+      SWIG_croak("Usage: GeomFieldDefn_GetName(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (int)OGRGeomFieldDefnShadow_IsIgnored(arg1);
+      result = (char *)OGRGeomFieldDefnShadow_GetName(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16598,7 +17382,13 @@ XS(_wrap_GeomFieldDefn_IsIgnored) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    {
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -16608,33 +17398,26 @@ XS(_wrap_GeomFieldDefn_IsIgnored) {
 }
 
 
-XS(_wrap_GeomFieldDefn_SetIgnored) {
+XS(_wrap_GeomFieldDefn_GetNameRef) {
   {
     OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
+    char *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: GeomFieldDefn_SetIgnored(self,bIgnored);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GeomFieldDefn_GetNameRef(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      OGRGeomFieldDefnShadow_SetIgnored(arg1,arg2);
+      result = (char *)OGRGeomFieldDefnShadow_GetNameRef(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16657,56 +17440,51 @@ XS(_wrap_GeomFieldDefn_SetIgnored) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_CreateGeometryFromWkb) {
+XS(_wrap_GeomFieldDefn_SetName) {
   {
-    int arg1 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
     char *arg2 = (char *) 0 ;
-    OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
-    void *argp3 = 0 ;
-    int res3 = 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: CreateGeometryFromWkb(len,bin_string,reference);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GeomFieldDefn_SetName(self,name);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
-      /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
-      if (SvOK(ST(0))) {
-        if (!SvPOK(ST(0)))
-        SWIG_croak("expected binary data as input");
-        STRLEN len = SvCUR(ST(0));
-        arg2 = SvPV_nolen(ST(0));
-        arg1 = len;
-      } else {
-        arg2 = NULL;
-        arg1 = 0;
-      }
+      /* %typemap(in,numinputs=1) (const char* name) */
+      sv_utf8_upgrade(ST(1));
+      arg2 = SvPV_nolen(ST(1));
     }
-    if (items > 1) {
-      res3 = SWIG_ConvertPtr(ST(1), &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-      if (!SWIG_IsOK(res3)) {
-        SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CreateGeometryFromWkb" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
       }
-      arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)CreateGeometryFromWkb(arg1,arg2,arg3);
+      OGRGeomFieldDefnShadow_SetName(arg1,(char const *)arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16728,7 +17506,9 @@ XS(_wrap_CreateGeometryFromWkb) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     XSRETURN(argvi);
   fail:
@@ -16738,36 +17518,26 @@ XS(_wrap_CreateGeometryFromWkb) {
 }
 
 
-XS(_wrap_CreateGeometryFromWkt) {
+XS(_wrap_GeomFieldDefn_GetType) {
   {
-    char **arg1 = (char **) 0 ;
-    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) NULL ;
-    char *val1 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    OGRwkbGeometryType result;
     dXSARGS;
     
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: CreateGeometryFromWkt(val,reference);");
-    }
-    {
-      /* %typemap(in) (char **ignorechange) */
-      sv_utf8_upgrade(ST(0)); /* GDAL expects UTF-8 */
-      val1 = SvPV_nolen(ST(0));
-      arg1 = &val1;
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GeomFieldDefn_GetType(self);");
     }
-    if (items > 1) {
-      res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-      if (!SWIG_IsOK(res2)) {
-        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CreateGeometryFromWkt" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
-      }
-      arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)CreateGeometryFromWkt(arg1,arg2);
+      result = (OGRwkbGeometryType)OGRGeomFieldDefnShadow_GetType(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16789,39 +17559,43 @@ XS(_wrap_CreateGeometryFromWkt) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_CreateGeometryFromGML) {
+XS(_wrap_GeomFieldDefn_SetType) {
   {
-    char *arg1 = (char *) 0 ;
-    int res1 ;
-    char *buf1 = 0 ;
-    int alloc1 = 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OGRwkbGeometryType arg2 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: CreateGeometryFromGML(input_string);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GeomFieldDefn_SetType(self,type);");
     }
-    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromGML" "', argument " "1"" of type '" "char const *""'");
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< char * >(buf1);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg2 = static_cast< OGRwkbGeometryType >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)CreateGeometryFromGML((char const *)arg1);
+      OGRGeomFieldDefnShadow_SetType(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16843,37 +17617,40 @@ XS(_wrap_CreateGeometryFromGML) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    {
+      /* %typemap(out) void */
+    }
+    
+    
     XSRETURN(argvi);
   fail:
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_CreateGeometryFromJson) {
+XS(_wrap_GeomFieldDefn_GetSpatialRef) {
   {
-    char *arg1 = (char *) 0 ;
-    int res1 ;
-    char *buf1 = 0 ;
-    int alloc1 = 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    OSRSpatialReferenceShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: CreateGeometryFromJson(input_string);");
+      SWIG_croak("Usage: GeomFieldDefn_GetSpatialRef(self);");
     }
-    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromJson" "', argument " "1"" of type '" "char const *""'");
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< char * >(buf1);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)CreateGeometryFromJson((char const *)arg1);
+      result = (OSRSpatialReferenceShadow *)OGRGeomFieldDefnShadow_GetSpatialRef(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16895,66 +17672,43 @@ XS(_wrap_CreateGeometryFromJson) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
     XSRETURN(argvi);
   fail:
-    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_BuildPolygonFromEdges) {
+XS(_wrap_GeomFieldDefn_SetSpatialRef) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
-    int arg3 = (int) 0 ;
-    double arg4 = (double) 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    int val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 4)) {
-      SWIG_croak("Usage: BuildPolygonFromEdges(hLineCollection,bBestEffort,bAutoClose,dfTolerance);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GeomFieldDefn_SetSpatialRef(self,srs);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BuildPolygonFromEdges" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "BuildPolygonFromEdges" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
-    }
-    if (items > 2) {
-      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-      if (!SWIG_IsOK(ecode3)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "BuildPolygonFromEdges" "', argument " "3"" of type '" "int""'");
-      } 
-      arg3 = static_cast< int >(val3);
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    if (items > 3) {
-      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-      if (!SWIG_IsOK(ecode4)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "BuildPolygonFromEdges" "', argument " "4"" of type '" "double""'");
-      } 
-      arg4 = static_cast< double >(val4);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
     }
+    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)BuildPolygonFromEdges(arg1,arg2,arg3,arg4);
+      OGRGeomFieldDefnShadow_SetSpatialRef(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -16976,106 +17730,40 @@ XS(_wrap_BuildPolygonFromEdges) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
-    
+    {
+      /* %typemap(out) void */
+    }
     
     
     XSRETURN(argvi);
   fail:
     
     
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_ApproximateArcAngles) {
+XS(_wrap_GeomFieldDefn_IsIgnored) {
   {
-    double arg1 ;
-    double arg2 ;
-    double arg3 ;
-    double arg4 ;
-    double arg5 ;
-    double arg6 ;
-    double arg7 ;
-    double arg8 ;
-    double arg9 ;
-    double val1 ;
-    int ecode1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
-    double val5 ;
-    int ecode5 = 0 ;
-    double val6 ;
-    int ecode6 = 0 ;
-    double val7 ;
-    int ecode7 = 0 ;
-    double val8 ;
-    int ecode8 = 0 ;
-    double val9 ;
-    int ecode9 = 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    int result;
     dXSARGS;
     
-    if ((items < 9) || (items > 9)) {
-      SWIG_croak("Usage: ApproximateArcAngles(dfCenterX,dfCenterY,dfZ,dfPrimaryRadius,dfSecondaryAxis,dfRotation,dfStartAngle,dfEndAngle,dfMaxAngleStepSizeDegrees);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GeomFieldDefn_IsIgnored(self);");
     }
-    ecode1 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
-    if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ApproximateArcAngles" "', argument " "1"" of type '" "double""'");
-    } 
-    arg1 = static_cast< double >(val1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ApproximateArcAngles" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ApproximateArcAngles" "', argument " "3"" of type '" "double""'");
-    } 
-    arg3 = static_cast< double >(val3);
-    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "ApproximateArcAngles" "', argument " "4"" of type '" "double""'");
-    } 
-    arg4 = static_cast< double >(val4);
-    ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
-    if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "ApproximateArcAngles" "', argument " "5"" of type '" "double""'");
-    } 
-    arg5 = static_cast< double >(val5);
-    ecode6 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(5), &val6);
-    if (!SWIG_IsOK(ecode6)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "ApproximateArcAngles" "', argument " "6"" of type '" "double""'");
-    } 
-    arg6 = static_cast< double >(val6);
-    ecode7 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(6), &val7);
-    if (!SWIG_IsOK(ecode7)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "ApproximateArcAngles" "', argument " "7"" of type '" "double""'");
-    } 
-    arg7 = static_cast< double >(val7);
-    ecode8 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(7), &val8);
-    if (!SWIG_IsOK(ecode8)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "ApproximateArcAngles" "', argument " "8"" of type '" "double""'");
-    } 
-    arg8 = static_cast< double >(val8);
-    ecode9 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(8), &val9);
-    if (!SWIG_IsOK(ecode9)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "ApproximateArcAngles" "', argument " "9"" of type '" "double""'");
-    } 
-    arg9 = static_cast< double >(val9);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)ApproximateArcAngles(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+      result = (int)OGRGeomFieldDefnShadow_IsIgnored(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17097,52 +17785,43 @@ XS(_wrap_ApproximateArcAngles) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
-    
-    
-    
-    
-    
-    
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
-    
-    
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_ForceToPolygon) {
+XS(_wrap_GeomFieldDefn_SetIgnored) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: ForceToPolygon(geom_in);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GeomFieldDefn_SetIgnored(self,bIgnored);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)ForceToPolygon(arg1);
+      OGRGeomFieldDefnShadow_SetIgnored(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17164,36 +17843,40 @@ XS(_wrap_ForceToPolygon) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_ForceToLineString) {
+XS(_wrap_GeomFieldDefn_IsNullable) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    int result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: ForceToLineString(geom_in);");
+      SWIG_croak("Usage: GeomFieldDefn_IsNullable(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsNullable" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)ForceToLineString(arg1);
+      result = (int)OGRGeomFieldDefnShadow_IsNullable(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17215,7 +17898,7 @@ XS(_wrap_ForceToLineString) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -17225,26 +17908,33 @@ XS(_wrap_ForceToLineString) {
 }
 
 
-XS(_wrap_ForceToMultiPolygon) {
+XS(_wrap_GeomFieldDefn_SetNullable) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: ForceToMultiPolygon(geom_in);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GeomFieldDefn_SetNullable(self,bNullable);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetNullable" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetNullable" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)ForceToMultiPolygon(arg1);
+      OGRGeomFieldDefnShadow_SetNullable(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17266,42 +17956,2045 @@ XS(_wrap_ForceToMultiPolygon) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_ForceToMultiPoint) {
+XS(_wrap_CreateGeometryFromWkb) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    int arg1 ;
+    char *arg2 = (char *) 0 ;
+    OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
+    void *argp3 = 0 ;
+    int res3 = 0 ;
     int argvi = 0;
     OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: ForceToMultiPoint(geom_in);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: CreateGeometryFromWkb(len,bin_string,reference);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
-      CPLErrorReset();
-      result = (OGRGeometryShadow *)ForceToMultiPoint(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
+      /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
+      if (SvOK(ST(0))) {
+        if (!SvPOK(ST(0)))
+        SWIG_croak("Expected binary data.");
+        STRLEN len = SvCUR(ST(0));
+        arg2 = SvPV_nolen(ST(0));
+        arg1 = len;
+      } else {
+        arg2 = NULL;
+        arg1 = 0;
+      }
+    }
+    if (items > 1) {
+      res3 = SWIG_ConvertPtr(ST(1), &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+      if (!SWIG_IsOK(res3)) {
+        SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CreateGeometryFromWkb" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
+      }
+      arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)CreateGeometryFromWkb(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_CreateGeometryFromWkt) {
+  {
+    char **arg1 = (char **) 0 ;
+    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) NULL ;
+    char *val1 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: CreateGeometryFromWkt(val,reference);");
+    }
+    {
+      /* %typemap(in) (char **ignorechange) */
+      sv_utf8_upgrade(ST(0)); /* GDAL expects UTF-8 */
+      val1 = SvPV_nolen(ST(0));
+      arg1 = &val1;
+    }
+    if (items > 1) {
+      res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+      if (!SWIG_IsOK(res2)) {
+        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CreateGeometryFromWkt" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+      }
+      arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)CreateGeometryFromWkt(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_CreateGeometryFromGML) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: CreateGeometryFromGML(input_string);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromGML" "', argument " "1"" of type '" "char const *""'");
+    }
+    arg1 = reinterpret_cast< char * >(buf1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)CreateGeometryFromGML((char const *)arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_CreateGeometryFromJson) {
+  {
+    char *arg1 = (char *) 0 ;
+    int res1 ;
+    char *buf1 = 0 ;
+    int alloc1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: CreateGeometryFromJson(input_string);");
+    }
+    res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromJson" "', argument " "1"" of type '" "char const *""'");
+    }
+    arg1 = reinterpret_cast< char * >(buf1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)CreateGeometryFromJson((char const *)arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    XSRETURN(argvi);
+  fail:
+    if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_BuildPolygonFromEdges) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    int arg2 = (int) 0 ;
+    int arg3 = (int) 0 ;
+    double arg4 = (double) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 4)) {
+      SWIG_croak("Usage: BuildPolygonFromEdges(hLineCollection,bBestEffort,bAutoClose,dfTolerance);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BuildPolygonFromEdges" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "BuildPolygonFromEdges" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
+    }
+    if (items > 2) {
+      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+      if (!SWIG_IsOK(ecode3)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "BuildPolygonFromEdges" "', argument " "3"" of type '" "int""'");
+      } 
+      arg3 = static_cast< int >(val3);
+    }
+    if (items > 3) {
+      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "BuildPolygonFromEdges" "', argument " "4"" of type '" "double""'");
+      } 
+      arg4 = static_cast< double >(val4);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)BuildPolygonFromEdges(arg1,arg2,arg3,arg4);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ApproximateArcAngles) {
+  {
+    double arg1 ;
+    double arg2 ;
+    double arg3 ;
+    double arg4 ;
+    double arg5 ;
+    double arg6 ;
+    double arg7 ;
+    double arg8 ;
+    double arg9 ;
+    double val1 ;
+    int ecode1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
+    double val5 ;
+    int ecode5 = 0 ;
+    double val6 ;
+    int ecode6 = 0 ;
+    double val7 ;
+    int ecode7 = 0 ;
+    double val8 ;
+    int ecode8 = 0 ;
+    double val9 ;
+    int ecode9 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 9) || (items > 9)) {
+      SWIG_croak("Usage: ApproximateArcAngles(dfCenterX,dfCenterY,dfZ,dfPrimaryRadius,dfSecondaryAxis,dfRotation,dfStartAngle,dfEndAngle,dfMaxAngleStepSizeDegrees);");
+    }
+    ecode1 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ApproximateArcAngles" "', argument " "1"" of type '" "double""'");
+    } 
+    arg1 = static_cast< double >(val1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ApproximateArcAngles" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ApproximateArcAngles" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "ApproximateArcAngles" "', argument " "4"" of type '" "double""'");
+    } 
+    arg4 = static_cast< double >(val4);
+    ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
+    if (!SWIG_IsOK(ecode5)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "ApproximateArcAngles" "', argument " "5"" of type '" "double""'");
+    } 
+    arg5 = static_cast< double >(val5);
+    ecode6 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(5), &val6);
+    if (!SWIG_IsOK(ecode6)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "ApproximateArcAngles" "', argument " "6"" of type '" "double""'");
+    } 
+    arg6 = static_cast< double >(val6);
+    ecode7 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(6), &val7);
+    if (!SWIG_IsOK(ecode7)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "ApproximateArcAngles" "', argument " "7"" of type '" "double""'");
+    } 
+    arg7 = static_cast< double >(val7);
+    ecode8 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(7), &val8);
+    if (!SWIG_IsOK(ecode8)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "ApproximateArcAngles" "', argument " "8"" of type '" "double""'");
+    } 
+    arg8 = static_cast< double >(val8);
+    ecode9 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(8), &val9);
+    if (!SWIG_IsOK(ecode9)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "ApproximateArcAngles" "', argument " "9"" of type '" "double""'");
+    } 
+    arg9 = static_cast< double >(val9);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ApproximateArcAngles(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceToPolygon) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: ForceToPolygon(geom_in);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceToPolygon(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceToLineString) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: ForceToLineString(geom_in);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceToLineString(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceToMultiPolygon) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: ForceToMultiPolygon(geom_in);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceToMultiPolygon(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceToMultiPoint) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: ForceToMultiPoint(geom_in);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceToMultiPoint(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceToMultiLineString) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: ForceToMultiLineString(geom_in);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceToMultiLineString(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_ForceTo) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRwkbGeometryType arg2 ;
+    char **arg3 = (char **) NULL ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 3)) {
+      SWIG_croak("Usage: ForceTo(geom_in,eTargetType,options);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ForceTo" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg2 = static_cast< OGRwkbGeometryType >(val2);
+    if (items > 2) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(2))) {
+          if (SvROK(ST(2))) {
+            if (SvTYPE(SvRV(ST(2)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(2)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg3 = CSLAddString( arg3, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(2)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(2));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg3 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)ForceTo(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_delete_Geometry) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: delete_Geometry(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Geometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      delete_OGRGeometryShadow(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_new_Geometry) {
+  {
+    OGRwkbGeometryType arg1 = (OGRwkbGeometryType) wkbUnknown ;
+    char *arg2 = (char *) 0 ;
+    int arg3 = (int) 0 ;
+    char *arg4 = (char *) 0 ;
+    char *arg5 = (char *) 0 ;
+    int val1 ;
+    int ecode1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int res5 ;
+    char *buf5 = 0 ;
+    int alloc5 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 4)) {
+      SWIG_croak("Usage: new_Geometry(type,wkt,wkb,wkb_buf,gml);");
+    }
+    if (items > 0) {
+      ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+      if (!SWIG_IsOK(ecode1)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_Geometry" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+      } 
+      arg1 = static_cast< OGRwkbGeometryType >(val1);
+    }
+    if (items > 1) {
+      res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+      if (!SWIG_IsOK(res2)) {
+        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Geometry" "', argument " "2"" of type '" "char *""'");
+      }
+      arg2 = reinterpret_cast< char * >(buf2);
+    }
+    if (items > 2) {
+      {
+        /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
+        if (SvOK(ST(2))) {
+          if (!SvPOK(ST(2)))
+          SWIG_croak("Expected binary data.");
+          STRLEN len = SvCUR(ST(2));
+          arg4 = SvPV_nolen(ST(2));
+          arg3 = len;
+        } else {
+          arg4 = NULL;
+          arg3 = 0;
+        }
+      }
+    }
+    if (items > 3) {
+      res5 = SWIG_AsCharPtrAndSize(ST(3), &buf5, NULL, &alloc5);
+      if (!SWIG_IsOK(res5)) {
+        SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "new_Geometry" "', argument " "5"" of type '" "char *""'");
+      }
+      arg5 = reinterpret_cast< char * >(buf5);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)new_OGRGeometryShadow(arg1,arg2,arg3,arg4,arg5);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToWkt) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    char **arg2 = (char **) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char *argout2 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    {
+      /* %typemap(in,numinputs=0) (char **argout2) */
+      arg2 = &argout2;
+    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_ExportToWkt(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_ExportToWkt(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    {
+      /* %typemap(argout) (char **argout) */
+      ST(argvi) = sv_newmortal();
+      if ( arg2 ) {
+        sv_setpv(ST(argvi), *arg2);
+        SvUTF8_on(ST(argvi)); /* expecting UTF-8 from GDAL */
+      }
+      argvi++;
+    }
+    
+    {
+      /* %typemap(freearg) (char **argout) */
+      if ( *arg2 )
+      CPLFree( *arg2 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) (char **argout) */
+      if ( *arg2 )
+      CPLFree( *arg2 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToIsoWkt) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    char **arg2 = (char **) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    char *argout2 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    {
+      /* %typemap(in,numinputs=0) (char **argout2) */
+      arg2 = &argout2;
+    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_ExportToIsoWkt(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToIsoWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_ExportToIsoWkt(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    {
+      /* %typemap(argout) (char **argout) */
+      ST(argvi) = sv_newmortal();
+      if ( arg2 ) {
+        sv_setpv(ST(argvi), *arg2);
+        SvUTF8_on(ST(argvi)); /* expecting UTF-8 from GDAL */
+      }
+      argvi++;
+    }
+    
+    {
+      /* %typemap(freearg) (char **argout) */
+      if ( *arg2 )
+      CPLFree( *arg2 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) (char **argout) */
+      if ( *arg2 )
+      CPLFree( *arg2 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry__ExportToWkb) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    int *arg2 = (int *) 0 ;
+    char **arg3 = (char **) 0 ;
+    OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int nLen2 = 0 ;
+    char *pBuf2 = 0 ;
+    int val4 ;
+    int ecode4 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    {
+      /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
+      arg2 = &nLen2;
+      arg3 = &pBuf2;
+    }
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry__ExportToWkb(self,pBuf,byte_order);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry__ExportToWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry__ExportToWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+      } 
+      arg4 = static_cast< OGRwkbByteOrder >(val4);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_ExportToWkb(arg1,arg2,arg3,arg4);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    {
+      /* %typemap(argout) (int *nLen, char **pBuf ) */
+      ST(argvi) = sv_2mortal(newSVpv( *arg3, *arg2 ));
+      argvi++;
+    }
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg2 ) {
+        free( *arg3 );
+      }
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg2 ) {
+        free( *arg3 );
+      }
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToIsoWkb) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    int *arg2 = (int *) 0 ;
+    char **arg3 = (char **) 0 ;
+    OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int nLen2 = 0 ;
+    char *pBuf2 = 0 ;
+    int val4 ;
+    int ecode4 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    {
+      /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
+      arg2 = &nLen2;
+      arg3 = &pBuf2;
+    }
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_ExportToIsoWkb(self,pBuf,byte_order);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToIsoWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_ExportToIsoWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+      } 
+      arg4 = static_cast< OGRwkbByteOrder >(val4);
+    }
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_ExportToIsoWkb(arg1,arg2,arg3,arg4);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    {
+      /* %typemap(argout) (int *nLen, char **pBuf ) */
+      ST(argvi) = sv_2mortal(newSVpv( *arg3, *arg2 ));
+      argvi++;
+    }
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg2 ) {
+        free( *arg3 );
+      }
+    }
+    
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) (int *nLen, char **pBuf ) */
+      if( *arg2 ) {
+        free( *arg3 );
+      }
+    }
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToGML) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    char **arg2 = (char **) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    retStringAndCPLFree *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_ExportToGML(self,options);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToGML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(1))) {
+          if (SvROK(ST(1))) {
+            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(1)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg2 = CSLAddString( arg2, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(1));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg2 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToGML(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      ST(argvi) = SWIG_FromCharPtr((const char *)result);
+      CPLFree(result);
+    }
+    else
+    {
+      ST(argvi) = &PL_sv_undef;
+    }
+    argvi++ ;
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToKML) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    char *arg2 = (char *) NULL ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res2 ;
+    char *buf2 = 0 ;
+    int alloc2 = 0 ;
+    int argvi = 0;
+    retStringAndCPLFree *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_ExportToKML(self,altitude_mode);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToKML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
+      if (!SWIG_IsOK(res2)) {
+        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_ExportToKML" "', argument " "2"" of type '" "char const *""'");
+      }
+      arg2 = reinterpret_cast< char * >(buf2);
+    }
+    {
+      CPLErrorReset();
+      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToKML(arg1,(char const *)arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      ST(argvi) = SWIG_FromCharPtr((const char *)result);
+      CPLFree(result);
+    }
+    else
+    {
+      ST(argvi) = &PL_sv_undef;
+    }
+    argvi++ ;
+    
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    XSRETURN(argvi);
+  fail:
+    
+    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_ExportToJson) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    char **arg2 = (char **) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    retStringAndCPLFree *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_ExportToJson(self,options);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToJson" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(1))) {
+          if (SvROK(ST(1))) {
+            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(1)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg2 = CSLAddString( arg2, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(1));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg2 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToJson(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      ST(argvi) = SWIG_FromCharPtr((const char *)result);
+      CPLFree(result);
+    }
+    else
+    {
+      ST(argvi) = &PL_sv_undef;
+    }
+    argvi++ ;
+    
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    XSRETURN(argvi);
+  fail:
+    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_AddPoint_3D) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
+    double arg3 ;
+    double arg4 = (double) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 4)) {
+      SWIG_croak("Usage: Geometry_AddPoint_3D(self,x,y,z);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_3D" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_3D" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    if (items > 3) {
+      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_AddPoint_3D" "', argument " "4"" of type '" "double""'");
+      } 
+      arg4 = static_cast< double >(val4);
+    }
+    {
+      CPLErrorReset();
+      OGRGeometryShadow_AddPoint(arg1,arg2,arg3,arg4);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_AddPoint_2D) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
+    double arg3 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    int argvi = 0;
+    dXSARGS;
+    
+    if ((items < 3) || (items > 3)) {
+      SWIG_croak("Usage: Geometry_AddPoint_2D(self,x,y);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_2D" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_2D" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    {
+      CPLErrorReset();
+      OGRGeometryShadow_AddPoint_2D(arg1,arg2,arg3);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) void */
+    }
+    
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_AddGeometryDirectly) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int res2 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_AddGeometryDirectly(self,other_disown);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometryDirectly" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
+    }
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_AddGeometryDirectly(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_AddGeometry) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
+    int argvi = 0;
+    OGRErr result;
+    dXSARGS;
+    
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_AddGeometry(self,other);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
+    {
+      CPLErrorReset();
+      result = (OGRErr)OGRGeometryShadow_AddGeometry(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_Clone) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_Clone(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Clone" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Clone(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_GetGeometryType) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    OGRwkbGeometryType result;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetGeometryType(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryType" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (OGRwkbGeometryType)OGRGeometryShadow_GetGeometryType(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_GetGeometryName) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int argvi = 0;
+    char *result = 0 ;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetGeometryName(self);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryName" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    {
+      CPLErrorReset();
+      result = (char *)OGRGeometryShadow_GetGeometryName(arg1);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
         
         
       }
@@ -17317,7 +20010,13 @@ XS(_wrap_ForceToMultiPoint) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -17327,26 +20026,26 @@ XS(_wrap_ForceToMultiPoint) {
 }
 
 
-XS(_wrap_ForceToMultiLineString) {
+XS(_wrap_Geometry_Length) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    double result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: ForceToMultiLineString(geom_in);");
+      SWIG_croak("Usage: Geometry_Length(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Length" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)ForceToMultiLineString(arg1);
+      result = (double)OGRGeometryShadow_Length(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17368,7 +20067,7 @@ XS(_wrap_ForceToMultiLineString) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -17378,25 +20077,26 @@ XS(_wrap_ForceToMultiLineString) {
 }
 
 
-XS(_wrap_delete_Geometry) {
+XS(_wrap_Geometry_Area) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
+    double result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: delete_Geometry(self);");
+      SWIG_croak("Usage: Geometry_Area(self);");
     }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Geometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Area" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      delete_OGRGeometryShadow(arg1);
+      result = (double)OGRGeometryShadow_Area(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17418,9 +20118,7 @@ XS(_wrap_delete_Geometry) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -17430,67 +20128,26 @@ XS(_wrap_delete_Geometry) {
 }
 
 
-XS(_wrap_new_Geometry) {
+XS(_wrap_Geometry_GetArea) {
   {
-    OGRwkbGeometryType arg1 = (OGRwkbGeometryType) wkbUnknown ;
-    char *arg2 = (char *) 0 ;
-    int arg3 = (int) 0 ;
-    char *arg4 = (char *) 0 ;
-    char *arg5 = (char *) 0 ;
-    int val1 ;
-    int ecode1 = 0 ;
-    int res2 ;
-    char *buf2 = 0 ;
-    int alloc2 = 0 ;
-    int res5 ;
-    char *buf5 = 0 ;
-    int alloc5 = 0 ;
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    double result;
     dXSARGS;
     
-    if ((items < 0) || (items > 4)) {
-      SWIG_croak("Usage: new_Geometry(type,wkt,wkb,wkb_buf,gml);");
-    }
-    if (items > 0) {
-      ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
-      if (!SWIG_IsOK(ecode1)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_Geometry" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
-      } 
-      arg1 = static_cast< OGRwkbGeometryType >(val1);
-    }
-    if (items > 1) {
-      res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
-      if (!SWIG_IsOK(res2)) {
-        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Geometry" "', argument " "2"" of type '" "char *""'");
-      }
-      arg2 = reinterpret_cast< char * >(buf2);
-    }
-    if (items > 2) {
-      {
-        /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
-        if (SvOK(ST(2))) {
-          if (!SvPOK(ST(2)))
-          SWIG_croak("expected binary data as input");
-          STRLEN len = SvCUR(ST(2));
-          arg4 = SvPV_nolen(ST(2));
-          arg3 = len;
-        } else {
-          arg4 = NULL;
-          arg3 = 0;
-        }
-      }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetArea(self);");
     }
-    if (items > 3) {
-      res5 = SWIG_AsCharPtrAndSize(ST(3), &buf5, NULL, &alloc5);
-      if (!SWIG_IsOK(res5)) {
-        SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "new_Geometry" "', argument " "5"" of type '" "char *""'");
-      }
-      arg5 = reinterpret_cast< char * >(buf5);
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetArea" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)new_OGRGeometryShadow(arg1,arg2,arg3,arg4,arg5);
+      result = (double)OGRGeometryShadow_GetArea(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17512,46 +20169,36 @@ XS(_wrap_new_Geometry) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
     XSRETURN(argvi);
   fail:
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_ExportToWkt) {
+XS(_wrap_Geometry_GetPointCount) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    char **arg2 = (char **) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    char *argout2 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    int result;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (char **argout2) */
-      arg2 = &argout2;
-    }
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_ExportToWkt(self);");
+      SWIG_croak("Usage: Geometry_GetPointCount(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPointCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_ExportToWkt(arg1,arg2);
+      result = (int)OGRGeometryShadow_GetPointCount(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17573,81 +20220,109 @@ XS(_wrap_Geometry_ExportToWkt) {
       
       
     }
-    {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    XSRETURN(argvi);
+  fail:
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_Geometry_GetX) {
+  {
+    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    int arg2 = (int) 0 ;
+    void *argp1 = 0 ;
+    int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    int argvi = 0;
+    double result;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_GetX(self,point);");
+    }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetX" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetX" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
-      /* %typemap(argout) (char **argout) */
-      ST(argvi) = sv_newmortal();
-      if ( arg2 ) {
-        sv_setpv(ST(argvi), *arg2);
-        SvUTF8_on(ST(argvi)); /* expecting UTF-8 from GDAL */
+      CPLErrorReset();
+      result = (double)OGRGeometryShadow_GetX(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
       }
-      argvi++;
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
     }
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    
     
-    {
-      /* %typemap(freearg) (char **argout) */
-      if ( *arg2 )
-      CPLFree( *arg2 );
-    }
     XSRETURN(argvi);
   fail:
     
-    {
-      /* %typemap(freearg) (char **argout) */
-      if ( *arg2 )
-      CPLFree( *arg2 );
-    }
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry__ExportToWkb) {
+XS(_wrap_Geometry_GetY) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int *arg2 = (int *) 0 ;
-    char **arg3 = (char **) 0 ;
-    OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
+    int arg2 = (int) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int nLen2 = 0 ;
-    char *pBuf2 = 0 ;
-    int val4 ;
-    int ecode4 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    double result;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
-      arg2 = &nLen2;
-      arg3 = &pBuf2;
-    }
     if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry__ExportToWkb(self,pBuf,byte_order);");
+      SWIG_croak("Usage: Geometry_GetY(self,point);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry__ExportToWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetY" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     if (items > 1) {
-      ecode4 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val4);
-      if (!SWIG_IsOK(ecode4)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry__ExportToWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetY" "', argument " "2"" of type '" "int""'");
       } 
-      arg4 = static_cast< OGRwkbByteOrder >(val4);
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_ExportToWkb(arg1,arg2,arg3,arg4);
+      result = (double)OGRGeometryShadow_GetY(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17669,94 +20344,48 @@ XS(_wrap_Geometry__ExportToWkb) {
       
       
     }
-    {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
-    }
-    {
-      /* %typemap(argout) (int *nLen, char **pBuf ) */
-      ST(argvi) = sv_2mortal(newSVpv( *arg3, *arg2 ));
-      argvi++;
-    }
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
     
-    {
-      /* %typemap(freearg) (int *nLen, char **pBuf ) */
-      if( *arg2 ) {
-        free( *arg3 );
-      }
-    }
     
     XSRETURN(argvi);
   fail:
     
-    {
-      /* %typemap(freearg) (int *nLen, char **pBuf ) */
-      if( *arg2 ) {
-        free( *arg3 );
-      }
-    }
     
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_ExportToGML) {
+XS(_wrap_Geometry_GetZ) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    char **arg2 = (char **) 0 ;
+    int arg2 = (int) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    retStringAndCPLFree *result = 0 ;
+    double result;
     dXSARGS;
     
     if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_ExportToGML(self,options);");
+      SWIG_croak("Usage: Geometry_GetZ(self,point);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToGML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetZ" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     if (items > 1) {
-      {
-        /* %typemap(in) char **options */
-        if (SvOK(ST(1))) {
-          if (SvROK(ST(1))) {
-            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
-              AV *av = (AV*)(SvRV(ST(1)));
-              for (int i = 0; i < av_len(av)+1; i++) {
-                SV *sv = *(av_fetch(av, i, 0));
-                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-                char *pszItem = SvPV_nolen(sv);
-                arg2 = CSLAddString( arg2, pszItem );
-              }
-            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
-              HV *hv = (HV*)SvRV(ST(1));
-              SV *sv;
-              char *key;
-              I32 klen;
-              arg2 = NULL;
-              hv_iterinit(hv);
-              while(sv = hv_iternextsv(hv,&key,&klen)) {
-                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
-              }
-            } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
-          } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
-        }
-      }
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetZ" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToGML(arg1,arg2);
+      result = (double)OGRGeometryShadow_GetZ(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17778,67 +20407,53 @@ XS(_wrap_Geometry_ExportToGML) {
       
       
     }
-    
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
-    {
-      ST(argvi) = SWIG_FromCharPtr((const char *)result);
-      CPLFree(result);
-    }
-    else
-    {
-      ST(argvi) = &PL_sv_undef;
-    }
-    argvi++ ;
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
     
     
-    {
-      /* %typemap(freearg) char **options */
-      if (arg2) CSLDestroy( arg2 );
-    }
     XSRETURN(argvi);
   fail:
     
-    {
-      /* %typemap(freearg) char **options */
-      if (arg2) CSLDestroy( arg2 );
-    }
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_ExportToKML) {
+XS(_wrap_Geometry_GetPoint_3D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    char *arg2 = (char *) NULL ;
+    int arg2 = (int) 0 ;
+    double *arg3 = (double *) (double *)NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int res2 ;
-    char *buf2 = 0 ;
-    int alloc2 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    double argout3[3] ;
     int argvi = 0;
-    retStringAndCPLFree *result = 0 ;
     dXSARGS;
     
+    {
+      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+      arg3 = argout3;
+    }
     if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_ExportToKML(self,altitude_mode);");
+      SWIG_croak("Usage: Geometry_GetPoint_3D(self,iPoint);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToKML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     if (items > 1) {
-      res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
-      if (!SWIG_IsOK(res2)) {
-        SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_ExportToKML" "', argument " "2"" of type '" "char const *""'");
-      }
-      arg2 = reinterpret_cast< char * >(buf2);
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_3D" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToKML(arg1,(char const *)arg2);
+      OGRGeometryShadow_GetPoint(arg1,arg2,arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17860,82 +20475,70 @@ XS(_wrap_Geometry_ExportToKML) {
       
       
     }
-    
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
     {
-      ST(argvi) = SWIG_FromCharPtr((const char *)result);
-      CPLFree(result);
+      /* %typemap(out) void */
     }
-    else
     {
-      ST(argvi) = &PL_sv_undef;
+      /* %typemap(argout) (double argout[ANY]) */
+      if (GIMME_V == G_ARRAY) {
+        /* return a list */
+        int i;
+        EXTEND(SP, argvi+3-items+1);
+        for (i = 0; i < 3; i++)
+        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
+      } else {
+        ST(argvi) = CreateArrayFromDoubleArray( arg3, 3 );
+        argvi++;
+      }  
     }
-    argvi++ ;
     
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    
     XSRETURN(argvi);
   fail:
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_ExportToJson) {
+XS(_wrap_Geometry_GetPoint_2D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    char **arg2 = (char **) 0 ;
+    int arg2 = (int) 0 ;
+    double *arg3 = (double *) (double *)NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    double argout3[2] ;
     int argvi = 0;
-    retStringAndCPLFree *result = 0 ;
     dXSARGS;
     
+    {
+      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+      arg3 = argout3;
+    }
     if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_ExportToJson(self,options);");
+      SWIG_croak("Usage: Geometry_GetPoint_2D(self,iPoint);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToJson" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     if (items > 1) {
-      {
-        /* %typemap(in) char **options */
-        if (SvOK(ST(1))) {
-          if (SvROK(ST(1))) {
-            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
-              AV *av = (AV*)(SvRV(ST(1)));
-              for (int i = 0; i < av_len(av)+1; i++) {
-                SV *sv = *(av_fetch(av, i, 0));
-                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-                char *pszItem = SvPV_nolen(sv);
-                arg2 = CSLAddString( arg2, pszItem );
-              }
-            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
-              HV *hv = (HV*)SvRV(ST(1));
-              SV *sv;
-              char *key;
-              I32 klen;
-              arg2 = NULL;
-              hv_iterinit(hv);
-              while(sv = hv_iternextsv(hv,&key,&klen)) {
-                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
-                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
-              }
-            } else
-            SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
-          } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
-        }
-      }
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_2D" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToJson(arg1,arg2);
+      OGRGeometryShadow_GetPoint_2D(arg1,arg2,arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -17957,81 +20560,55 @@ XS(_wrap_Geometry_ExportToJson) {
       
       
     }
-    
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
     {
-      ST(argvi) = SWIG_FromCharPtr((const char *)result);
-      CPLFree(result);
+      /* %typemap(out) void */
     }
-    else
     {
-      ST(argvi) = &PL_sv_undef;
+      /* %typemap(argout) (double argout[ANY]) */
+      if (GIMME_V == G_ARRAY) {
+        /* return a list */
+        int i;
+        EXTEND(SP, argvi+2-items+1);
+        for (i = 0; i < 2; i++)
+        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
+      } else {
+        ST(argvi) = CreateArrayFromDoubleArray( arg3, 2 );
+        argvi++;
+      }  
     }
-    argvi++ ;
     
     
-    {
-      /* %typemap(freearg) char **options */
-      if (arg2) CSLDestroy( arg2 );
-    }
+    
     XSRETURN(argvi);
   fail:
     
-    {
-      /* %typemap(freearg) char **options */
-      if (arg2) CSLDestroy( arg2 );
-    }
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_AddPoint_3D) {
+XS(_wrap_Geometry_GetGeometryCount) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
-    double arg3 ;
-    double arg4 = (double) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 3) || (items > 4)) {
-      SWIG_croak("Usage: Geometry_AddPoint_3D(self,x,y,z);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetGeometryCount(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_3D" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_3D" "', argument " "3"" of type '" "double""'");
-    } 
-    arg3 = static_cast< double >(val3);
-    if (items > 3) {
-      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-      if (!SWIG_IsOK(ecode4)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_AddPoint_3D" "', argument " "4"" of type '" "double""'");
-      } 
-      arg4 = static_cast< double >(val4);
-    }
     {
       CPLErrorReset();
-      OGRGeometryShadow_AddPoint(arg1,arg2,arg3,arg4);
+      result = (int)OGRGeometryShadow_GetGeometryCount(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18053,59 +20630,69 @@ XS(_wrap_Geometry_AddPoint_3D) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_AddPoint_2D) {
+XS(_wrap_Geometry_SetPoint_3D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
+    int arg2 ;
     double arg3 ;
+    double arg4 ;
+    double arg5 = (double) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
+    int val2 ;
     int ecode2 = 0 ;
     double val3 ;
     int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
+    double val5 ;
+    int ecode5 = 0 ;
     int argvi = 0;
     dXSARGS;
     
-    if ((items < 3) || (items > 3)) {
-      SWIG_croak("Usage: Geometry_AddPoint_2D(self,x,y);");
+    if ((items < 4) || (items > 5)) {
+      SWIG_croak("Usage: Geometry_SetPoint_3D(self,point,x,y,z);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_2D" "', argument " "2"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_3D" "', argument " "2"" of type '" "int""'");
     } 
-    arg2 = static_cast< double >(val2);
+    arg2 = static_cast< int >(val2);
     ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
     if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_2D" "', argument " "3"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_3D" "', argument " "3"" of type '" "double""'");
     } 
     arg3 = static_cast< double >(val3);
+    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_3D" "', argument " "4"" of type '" "double""'");
+    } 
+    arg4 = static_cast< double >(val4);
+    if (items > 4) {
+      ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
+      if (!SWIG_IsOK(ecode5)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_SetPoint_3D" "', argument " "5"" of type '" "double""'");
+      } 
+      arg5 = static_cast< double >(val5);
+    }
     {
       CPLErrorReset();
-      OGRGeometryShadow_AddPoint_2D(arg1,arg2,arg3);
+      OGRGeometryShadow_SetPoint(arg1,arg2,arg3,arg4,arg5);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18133,47 +20720,63 @@ XS(_wrap_Geometry_AddPoint_2D) {
     
     
     
+    
+    
     XSRETURN(argvi);
   fail:
     
     
     
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_AddGeometryDirectly) {
+XS(_wrap_Geometry_SetPoint_2D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    int arg2 ;
+    double arg3 ;
+    double arg4 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int res2 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
     int argvi = 0;
-    OGRErr result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_AddGeometryDirectly(self,other_disown);");
+    if ((items < 4) || (items > 4)) {
+      SWIG_croak("Usage: Geometry_SetPoint_2D(self,point,x,y);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometryDirectly" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
-    }
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_2D" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_2D" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_2D" "', argument " "4"" of type '" "double""'");
+    } 
+    arg4 = static_cast< double >(val4);
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_AddGeometryDirectly(arg1,arg2);
+      OGRGeometryShadow_SetPoint_2D(arg1,arg2,arg3,arg4);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18196,57 +20799,51 @@ XS(_wrap_Geometry_AddGeometryDirectly) {
       
     }
     {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
+      /* %typemap(out) void */
     }
     
     
+    
+    
     XSRETURN(argvi);
   fail:
     
     
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_AddGeometry) {
+XS(_wrap_Geometry_GetGeometryRef) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_AddGeometry(self,other);");
+      SWIG_croak("Usage: Geometry_GetGeometryRef(self,geom);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryRef" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetGeometryRef" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_AddGeometry(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_GetGeometryRef(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18268,14 +20865,7 @@ XS(_wrap_Geometry_AddGeometry) {
       
       
     }
-    {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
-    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 | SWIG_SHADOW); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -18287,26 +20877,34 @@ XS(_wrap_Geometry_AddGeometry) {
 }
 
 
-XS(_wrap_Geometry_Clone) {
+XS(_wrap_Geometry_Simplify) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
     OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Clone(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Simplify(self,tolerance);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Clone" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Simplify" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Simplify" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Clone(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Simplify(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18330,34 +20928,44 @@ XS(_wrap_Geometry_Clone) {
     }
     ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
+    
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetGeometryType) {
+XS(_wrap_Geometry_SimplifyPreserveTopology) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRwkbGeometryType result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetGeometryType(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_SimplifyPreserveTopology(self,tolerance);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryType" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (OGRwkbGeometryType)OGRGeometryShadow_GetGeometryType(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_SimplifyPreserveTopology(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18379,36 +20987,38 @@ XS(_wrap_Geometry_GetGeometryType) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetGeometryName) {
+XS(_wrap_Geometry_Boundary) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetGeometryName(self);");
+      SWIG_croak("Usage: Geometry_Boundary(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryName" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Boundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (char *)OGRGeometryShadow_GetGeometryName(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Boundary(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18430,13 +21040,7 @@ XS(_wrap_Geometry_GetGeometryName) {
       
       
     }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -18446,26 +21050,26 @@ XS(_wrap_Geometry_GetGeometryName) {
 }
 
 
-XS(_wrap_Geometry_Length) {
+XS(_wrap_Geometry_GetBoundary) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Length(self);");
+      SWIG_croak("Usage: Geometry_GetBoundary(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Length" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetBoundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_Length(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_GetBoundary(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18487,7 +21091,7 @@ XS(_wrap_Geometry_Length) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -18497,26 +21101,26 @@ XS(_wrap_Geometry_Length) {
 }
 
 
-XS(_wrap_Geometry_Area) {
+XS(_wrap_Geometry_ConvexHull) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Area(self);");
+      SWIG_croak("Usage: Geometry_ConvexHull(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Area" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ConvexHull" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_Area(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_ConvexHull(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18538,7 +21142,7 @@ XS(_wrap_Geometry_Area) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -18548,26 +21152,44 @@ XS(_wrap_Geometry_Area) {
 }
 
 
-XS(_wrap_Geometry_GetArea) {
+XS(_wrap_Geometry_Buffer) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
+    int arg3 = (int) 30 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    int val3 ;
+    int ecode3 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetArea(self);");
+    if ((items < 2) || (items > 3)) {
+      SWIG_croak("Usage: Geometry_Buffer(self,distance,quadsecs);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetArea" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Buffer" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Buffer" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    if (items > 2) {
+      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+      if (!SWIG_IsOK(ecode3)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Buffer" "', argument " "3"" of type '" "int""'");
+      } 
+      arg3 = static_cast< int >(val3);
+    }
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_GetArea(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Buffer(arg1,arg2,arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18589,36 +21211,53 @@ XS(_wrap_Geometry_GetArea) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
+    
     
     XSRETURN(argvi);
   fail:
     
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetPointCount) {
+XS(_wrap_Geometry_Intersection) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    int result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetPointCount(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Intersection(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPointCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersection" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersection" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
     {
       CPLErrorReset();
-      result = (int)OGRGeometryShadow_GetPointCount(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Intersection(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18640,46 +21279,51 @@ XS(_wrap_Geometry_GetPointCount) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetX) {
+XS(_wrap_Geometry_Union) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetX(self,point);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Union(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetX" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Union" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetX" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Union" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_GetX(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Union(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18701,7 +21345,7 @@ XS(_wrap_Geometry_GetX) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -18713,36 +21357,26 @@ XS(_wrap_Geometry_GetX) {
 }
 
 
-XS(_wrap_Geometry_GetY) {
+XS(_wrap_Geometry_UnionCascaded) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetY(self,point);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_UnionCascaded(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetY" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_UnionCascaded" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetY" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
-    }
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_GetY(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_UnionCascaded(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18764,48 +21398,49 @@ XS(_wrap_Geometry_GetY) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetZ) {
+XS(_wrap_Geometry_Difference) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    double result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetZ(self,point);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Difference(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetZ" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Difference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetZ" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Difference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_GetZ(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Difference(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18827,7 +21462,7 @@ XS(_wrap_Geometry_GetZ) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -18839,41 +21474,39 @@ XS(_wrap_Geometry_GetZ) {
 }
 
 
-XS(_wrap_Geometry_GetPoint_3D) {
+XS(_wrap_Geometry_SymDifference) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
-    double *arg3 = (double *) (double *)NULL ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    double argout3[3] ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-      arg3 = argout3;
-    }
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetPoint_3D(self,iPoint);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_SymDifference(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_3D" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
     {
       CPLErrorReset();
-      OGRGeometryShadow_GetPoint(arg1,arg2,arg3);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_SymDifference(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18895,70 +21528,51 @@ XS(_wrap_Geometry_GetPoint_3D) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    {
-      /* %typemap(argout) (double argout[ANY]) */
-      if (GIMME_V == G_ARRAY) {
-        /* return a list */
-        int i;
-        EXTEND(SP, argvi+3-items+1);
-        for (i = 0; i < 3; i++)
-        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
-      } else {
-        ST(argvi) = CreateArrayFromDoubleArray( arg3, 3 );
-        argvi++;
-      }  
-    }
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     
     XSRETURN(argvi);
   fail:
     
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetPoint_2D) {
+XS(_wrap_Geometry_SymmetricDifference) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 = (int) 0 ;
-    double *arg3 = (double *) (double *)NULL ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    double argout3[2] ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-      arg3 = argout3;
-    }
-    if ((items < 1) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetPoint_2D(self,iPoint);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_SymmetricDifference(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymmetricDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    if (items > 1) {
-      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-      if (!SWIG_IsOK(ecode2)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_2D" "', argument " "2"" of type '" "int""'");
-      } 
-      arg2 = static_cast< int >(val2);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymmetricDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
     {
       CPLErrorReset();
-      OGRGeometryShadow_GetPoint_2D(arg1,arg2,arg3);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_SymmetricDifference(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -18980,55 +21594,51 @@ XS(_wrap_Geometry_GetPoint_2D) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    {
-      /* %typemap(argout) (double argout[ANY]) */
-      if (GIMME_V == G_ARRAY) {
-        /* return a list */
-        int i;
-        EXTEND(SP, argvi+2-items+1);
-        for (i = 0; i < 2; i++)
-        ST(argvi++) = sv_2mortal(newSVnv(arg3[i]));
-      } else {
-        ST(argvi) = CreateArrayFromDoubleArray( arg3, 2 );
-        argvi++;
-      }  
-    }
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     
     XSRETURN(argvi);
   fail:
     
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetGeometryCount) {
+XS(_wrap_Geometry_Distance) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    int result;
+    double result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetGeometryCount(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Distance(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Distance" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Distance" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
     {
       CPLErrorReset();
-      result = (int)OGRGeometryShadow_GetGeometryCount(arg1);
+      result = (double)OGRGeometryShadow_Distance(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19050,69 +21660,37 @@ XS(_wrap_Geometry_GetGeometryCount) {
       
       
     }
-    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_SetPoint_3D) {
+XS(_wrap_Geometry_Empty) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 ;
-    double arg3 ;
-    double arg4 ;
-    double arg5 = (double) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
-    double val5 ;
-    int ecode5 = 0 ;
     int argvi = 0;
     dXSARGS;
     
-    if ((items < 4) || (items > 5)) {
-      SWIG_croak("Usage: Geometry_SetPoint_3D(self,point,x,y,z);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_Empty(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Empty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_3D" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_3D" "', argument " "3"" of type '" "double""'");
-    } 
-    arg3 = static_cast< double >(val3);
-    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_3D" "', argument " "4"" of type '" "double""'");
-    } 
-    arg4 = static_cast< double >(val4);
-    if (items > 4) {
-      ecode5 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(4), &val5);
-      if (!SWIG_IsOK(ecode5)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_SetPoint_3D" "', argument " "5"" of type '" "double""'");
-      } 
-      arg5 = static_cast< double >(val5);
-    }
     {
       CPLErrorReset();
-      OGRGeometryShadow_SetPoint(arg1,arg2,arg3,arg4,arg5);
+      OGRGeometryShadow_Empty(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19138,65 +21716,34 @@ XS(_wrap_Geometry_SetPoint_3D) {
       /* %typemap(out) void */
     }
     
-    
-    
-    
-    
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_SetPoint_2D) {
+XS(_wrap_Geometry_IsEmpty) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 ;
-    double arg3 ;
-    double arg4 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
     int argvi = 0;
+    bool result;
     dXSARGS;
     
-    if ((items < 4) || (items > 4)) {
-      SWIG_croak("Usage: Geometry_SetPoint_2D(self,point,x,y);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_IsEmpty(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsEmpty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_2D" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_2D" "', argument " "3"" of type '" "double""'");
-    } 
-    arg3 = static_cast< double >(val3);
-    ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_2D" "', argument " "4"" of type '" "double""'");
-    } 
-    arg4 = static_cast< double >(val4);
     {
       CPLErrorReset();
-      OGRGeometryShadow_SetPoint_2D(arg1,arg2,arg3,arg4);
+      result = (bool)OGRGeometryShadow_IsEmpty(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19218,52 +21765,36 @@ XS(_wrap_Geometry_SetPoint_2D) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetGeometryRef) {
+XS(_wrap_Geometry_IsValid) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_GetGeometryRef(self,geom);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_IsValid(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryRef" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsValid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetGeometryRef" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_GetGeometryRef(arg1,arg2);
+      result = (bool)OGRGeometryShadow_IsValid(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19285,46 +21816,36 @@ XS(_wrap_Geometry_GetGeometryRef) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 | SWIG_SHADOW); argvi++ ;
-    
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Simplify) {
+XS(_wrap_Geometry_IsSimple) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Simplify(self,tolerance);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_IsSimple(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Simplify" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsSimple" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Simplify" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Simplify(arg1,arg2);
+      result = (bool)OGRGeometryShadow_IsSimple(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19346,46 +21867,36 @@ XS(_wrap_Geometry_Simplify) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_SimplifyPreserveTopology) {
+XS(_wrap_Geometry_IsRing) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_SimplifyPreserveTopology(self,tolerance);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_IsRing(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsRing" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_SimplifyPreserveTopology(arg1,arg2);
+      result = (bool)OGRGeometryShadow_IsRing(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19407,38 +21918,49 @@ XS(_wrap_Geometry_SimplifyPreserveTopology) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Boundary) {
+XS(_wrap_Geometry_Intersects) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Boundary(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Intersects(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Boundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersects" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersects" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Boundary(arg1);
+      result = (bool)OGRGeometryShadow_Intersects(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19460,36 +21982,51 @@ XS(_wrap_Geometry_Boundary) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetBoundary) {
+XS(_wrap_Geometry_Intersect) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetBoundary(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Intersect(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetBoundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersect" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersect" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_GetBoundary(arg1);
+      result = (bool)OGRGeometryShadow_Intersect(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19511,36 +22048,51 @@ XS(_wrap_Geometry_GetBoundary) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_ConvexHull) {
+XS(_wrap_Geometry_Equals) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_ConvexHull(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Equals(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ConvexHull" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equals" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equals" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_ConvexHull(arg1);
+      result = (bool)OGRGeometryShadow_Equals(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19562,54 +22114,51 @@ XS(_wrap_Geometry_ConvexHull) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Buffer) {
+XS(_wrap_Geometry_Equal) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
-    int arg3 = (int) 30 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
-    int val3 ;
-    int ecode3 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 3)) {
-      SWIG_croak("Usage: Geometry_Buffer(self,distance,quadsecs);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Equal(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Buffer" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equal" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Buffer" "', argument " "2"" of type '" "double""'");
-    } 
-    arg2 = static_cast< double >(val2);
-    if (items > 2) {
-      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-      if (!SWIG_IsOK(ecode3)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Buffer" "', argument " "3"" of type '" "int""'");
-      } 
-      arg3 = static_cast< int >(val3);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equal" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Buffer(arg1,arg2,arg3);
+      result = (bool)OGRGeometryShadow_Equal(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19631,21 +22180,19 @@ XS(_wrap_Geometry_Buffer) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
-    
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
   fail:
     
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Intersection) {
+XS(_wrap_Geometry_Disjoint) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -19654,20 +22201,20 @@ XS(_wrap_Geometry_Intersection) {
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Intersection(self,other);");
+      SWIG_croak("Usage: Geometry_Disjoint(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersection" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Disjoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersection" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Disjoint" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -19677,7 +22224,7 @@ XS(_wrap_Geometry_Intersection) {
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Intersection(arg1,arg2);
+      result = (bool)OGRGeometryShadow_Disjoint(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19699,7 +22246,7 @@ XS(_wrap_Geometry_Intersection) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -19711,7 +22258,7 @@ XS(_wrap_Geometry_Intersection) {
 }
 
 
-XS(_wrap_Geometry_Union) {
+XS(_wrap_Geometry_Touches) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -19720,20 +22267,20 @@ XS(_wrap_Geometry_Union) {
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Union(self,other);");
+      SWIG_croak("Usage: Geometry_Touches(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Union" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Touches" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Union" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Touches" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -19743,7 +22290,7 @@ XS(_wrap_Geometry_Union) {
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Union(arg1,arg2);
+      result = (bool)OGRGeometryShadow_Touches(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19765,7 +22312,7 @@ XS(_wrap_Geometry_Union) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -19777,26 +22324,39 @@ XS(_wrap_Geometry_Union) {
 }
 
 
-XS(_wrap_Geometry_UnionCascaded) {
+XS(_wrap_Geometry_Crosses) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_UnionCascaded(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Crosses(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_UnionCascaded" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Crosses" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Crosses" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
+    }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_UnionCascaded(arg1);
+      result = (bool)OGRGeometryShadow_Crosses(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19818,17 +22378,19 @@ XS(_wrap_Geometry_UnionCascaded) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Difference) {
+XS(_wrap_Geometry_Within) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -19837,20 +22399,20 @@ XS(_wrap_Geometry_Difference) {
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Difference(self,other);");
+      SWIG_croak("Usage: Geometry_Within(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Difference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Within" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Difference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Within" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -19860,7 +22422,7 @@ XS(_wrap_Geometry_Difference) {
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Difference(arg1,arg2);
+      result = (bool)OGRGeometryShadow_Within(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19882,7 +22444,7 @@ XS(_wrap_Geometry_Difference) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -19894,7 +22456,7 @@ XS(_wrap_Geometry_Difference) {
 }
 
 
-XS(_wrap_Geometry_SymDifference) {
+XS(_wrap_Geometry_Contains) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -19903,20 +22465,20 @@ XS(_wrap_Geometry_SymDifference) {
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_SymDifference(self,other);");
+      SWIG_croak("Usage: Geometry_Contains(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Contains" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Contains" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -19926,7 +22488,7 @@ XS(_wrap_Geometry_SymDifference) {
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_SymDifference(arg1,arg2);
+      result = (bool)OGRGeometryShadow_Contains(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -19948,7 +22510,7 @@ XS(_wrap_Geometry_SymDifference) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -19960,7 +22522,7 @@ XS(_wrap_Geometry_SymDifference) {
 }
 
 
-XS(_wrap_Geometry_SymmetricDifference) {
+XS(_wrap_Geometry_Overlaps) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -19969,20 +22531,20 @@ XS(_wrap_Geometry_SymmetricDifference) {
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_SymmetricDifference(self,other);");
+      SWIG_croak("Usage: Geometry_Overlaps(self,other);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymmetricDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Overlaps" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymmetricDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Overlaps" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
     {
@@ -19992,7 +22554,7 @@ XS(_wrap_Geometry_SymmetricDifference) {
     }
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_SymmetricDifference(arg1,arg2);
+      result = (bool)OGRGeometryShadow_Overlaps(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20014,7 +22576,7 @@ XS(_wrap_Geometry_SymmetricDifference) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -20026,31 +22588,31 @@ XS(_wrap_Geometry_SymmetricDifference) {
 }
 
 
-XS(_wrap_Geometry_Distance) {
+XS(_wrap_Geometry_TransformTo) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     void *argp2 = 0 ;
     int res2 = 0 ;
     int argvi = 0;
-    double result;
+    OGRErr result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Distance(self,other);");
+      SWIG_croak("Usage: Geometry_TransformTo(self,reference);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Distance" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_TransformTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
     if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Distance" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_TransformTo" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
     }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
     {
       if (!arg2) {
         SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -20058,7 +22620,7 @@ XS(_wrap_Geometry_Distance) {
     }
     {
       CPLErrorReset();
-      result = (double)OGRGeometryShadow_Distance(arg1,arg2);
+      result = (OGRErr)OGRGeometryShadow_TransformTo(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20080,7 +22642,14 @@ XS(_wrap_Geometry_Distance) {
       
       
     }
-    ST(argvi) = SWIG_From_double  SWIG_PERL_CALL_ARGS_1(static_cast< double >(result)); argvi++ ;
+    {
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
+    }
     
     
     XSRETURN(argvi);
@@ -20092,25 +22661,39 @@ XS(_wrap_Geometry_Distance) {
 }
 
 
-XS(_wrap_Geometry_Empty) {
+XS(_wrap_Geometry_Transform) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OSRCoordinateTransformationShadow *arg2 = (OSRCoordinateTransformationShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
+    OGRErr result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Empty(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Transform(self,trans);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Empty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Transform" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRCoordinateTransformationShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Transform" "', argument " "2"" of type '" "OSRCoordinateTransformationShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OSRCoordinateTransformationShadow * >(argp2);
+    {
+      if (!arg2) {
+        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      }
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_Empty(arg1);
+      result = (OGRErr)OGRGeometryShadow_Transform(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20133,37 +22716,44 @@ XS(_wrap_Geometry_Empty) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
+    
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_IsEmpty) {
+XS(_wrap_Geometry_GetSpatialReference) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    bool result;
+    OSRSpatialReferenceShadow *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_IsEmpty(self);");
+      SWIG_croak("Usage: Geometry_GetSpatialReference(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsEmpty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_IsEmpty(arg1);
+      result = (OSRSpatialReferenceShadow *)OGRGeometryShadow_GetSpatialReference(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20185,7 +22775,7 @@ XS(_wrap_Geometry_IsEmpty) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -20195,26 +22785,33 @@ XS(_wrap_Geometry_IsEmpty) {
 }
 
 
-XS(_wrap_Geometry_IsValid) {
+XS(_wrap_Geometry_AssignSpatialReference) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    void *argp2 = 0 ;
+    int res2 = 0 ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_IsValid(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_AssignSpatialReference(self,reference);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsValid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AssignSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AssignSpatialReference" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_IsValid(arg1);
+      OGRGeometryShadow_AssignSpatialReference(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20236,36 +22833,39 @@ XS(_wrap_Geometry_IsValid) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_IsSimple) {
+XS(_wrap_Geometry_CloseRings) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_IsSimple(self);");
+      SWIG_croak("Usage: Geometry_CloseRings(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsSimple" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_CloseRings" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_IsSimple(arg1);
+      OGRGeometryShadow_CloseRings(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20287,7 +22887,9 @@ XS(_wrap_Geometry_IsSimple) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     XSRETURN(argvi);
   fail:
@@ -20297,26 +22899,25 @@ XS(_wrap_Geometry_IsSimple) {
 }
 
 
-XS(_wrap_Geometry_IsRing) {
+XS(_wrap_Geometry_FlattenTo2D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_IsRing(self);");
+      SWIG_croak("Usage: Geometry_FlattenTo2D(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsRing" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_FlattenTo2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_IsRing(arg1);
+      OGRGeometryShadow_FlattenTo2D(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20338,7 +22939,9 @@ XS(_wrap_Geometry_IsRing) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     XSRETURN(argvi);
   fail:
@@ -20348,39 +22951,33 @@ XS(_wrap_Geometry_IsRing) {
 }
 
 
-XS(_wrap_Geometry_Intersects) {
+XS(_wrap_Geometry_Segmentize) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Intersects(self,other);");
+      SWIG_croak("Usage: Geometry_Segmentize(self,dfMaxLength);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersects" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Segmentize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersects" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Segmentize" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Intersects(arg1,arg2);
+      OGRGeometryShadow_Segmentize(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20402,7 +22999,9 @@ XS(_wrap_Geometry_Intersects) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     
     XSRETURN(argvi);
@@ -20414,39 +23013,31 @@ XS(_wrap_Geometry_Intersects) {
 }
 
 
-XS(_wrap_Geometry_Intersect) {
+XS(_wrap_Geometry_GetEnvelope) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    double *arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    double argout2[4] ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Intersect(self,other);");
+    {
+      /* %typemap(in,numinputs=0) (double argout2[ANY]) */
+      arg2 = argout2;
+    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetEnvelope(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersect" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersect" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Intersect(arg1,arg2);
+      OGRGeometryShadow_GetEnvelope(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20468,7 +23059,22 @@ XS(_wrap_Geometry_Intersect) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
+    {
+      /* %typemap(argout) (double argout[ANY]) */
+      if (GIMME_V == G_ARRAY) {
+        /* return a list */
+        int i;
+        EXTEND(SP, argvi+4-items+1);
+        for (i = 0; i < 4; i++)
+        ST(argvi++) = sv_2mortal(newSVnv(arg2[i]));
+      } else {
+        ST(argvi) = CreateArrayFromDoubleArray( arg2, 4 );
+        argvi++;
+      }  
+    }
     
     
     XSRETURN(argvi);
@@ -20480,39 +23086,31 @@ XS(_wrap_Geometry_Intersect) {
 }
 
 
-XS(_wrap_Geometry_Equals) {
+XS(_wrap_Geometry_GetEnvelope3D) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    double *arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    double argout2[6] ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Equals(self,other);");
+    {
+      /* %typemap(in,numinputs=0) (double argout2[ANY]) */
+      arg2 = argout2;
+    }
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetEnvelope3D(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equals" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equals" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Equals(arg1,arg2);
+      OGRGeometryShadow_GetEnvelope3D(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20534,7 +23132,22 @@ XS(_wrap_Geometry_Equals) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
+    {
+      /* %typemap(argout) (double argout[ANY]) */
+      if (GIMME_V == G_ARRAY) {
+        /* return a list */
+        int i;
+        EXTEND(SP, argvi+6-items+1);
+        for (i = 0; i < 6; i++)
+        ST(argvi++) = sv_2mortal(newSVnv(arg2[i]));
+      } else {
+        ST(argvi) = CreateArrayFromDoubleArray( arg2, 6 );
+        argvi++;
+      }  
+    }
     
     
     XSRETURN(argvi);
@@ -20546,39 +23159,26 @@ XS(_wrap_Geometry_Equals) {
 }
 
 
-XS(_wrap_Geometry_Equal) {
+XS(_wrap_Geometry_Centroid) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    bool result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Equal(self,other);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_Centroid(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equal" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Centroid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equal" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Equal(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Centroid(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20600,51 +23200,36 @@ XS(_wrap_Geometry_Equal) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Disjoint) {
+XS(_wrap_Geometry_PointOnSurface) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    bool result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Disjoint(self,other);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Disjoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Disjoint" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_PointOnSurface(self);");
     }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
+    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_PointOnSurface" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
+    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Disjoint(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_PointOnSurface(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20666,51 +23251,36 @@ XS(_wrap_Geometry_Disjoint) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Touches) {
+XS(_wrap_Geometry_WkbSize) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    bool result;
+    int result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Touches(self,other);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_WkbSize(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Touches" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_WkbSize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Touches" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Touches(arg1,arg2);
+      result = (int)OGRGeometryShadow_WkbSize(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20732,51 +23302,36 @@ XS(_wrap_Geometry_Touches) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Crosses) {
+XS(_wrap_Geometry_GetCoordinateDimension) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    bool result;
+    int result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Crosses(self,other);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetCoordinateDimension(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Crosses" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Crosses" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Crosses(arg1,arg2);
+      result = (int)OGRGeometryShadow_GetCoordinateDimension(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20798,51 +23353,43 @@ XS(_wrap_Geometry_Crosses) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Within) {
+XS(_wrap_Geometry_SetCoordinateDimension) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    int arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    bool result;
     dXSARGS;
     
     if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Within(self,other);");
+      SWIG_croak("Usage: Geometry_SetCoordinateDimension(self,dimension);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Within" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Within" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetCoordinateDimension" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Within(arg1,arg2);
+      OGRGeometryShadow_SetCoordinateDimension(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20864,7 +23411,9 @@ XS(_wrap_Geometry_Within) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    {
+      /* %typemap(out) void */
+    }
     
     
     XSRETURN(argvi);
@@ -20876,39 +23425,26 @@ XS(_wrap_Geometry_Within) {
 }
 
 
-XS(_wrap_Geometry_Contains) {
+XS(_wrap_Geometry_GetDimension) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    bool result;
+    int result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Contains(self,other);");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: Geometry_GetDimension(self);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Contains" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Contains" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Contains(arg1,arg2);
+      result = (int)OGRGeometryShadow_GetDimension(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20930,51 +23466,46 @@ XS(_wrap_Geometry_Contains) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Overlaps) {
+XS(_wrap_Geometry_HasCurveGeometry) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+    int arg2 = (int) FALSE ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    int val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    bool result;
+    int result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Overlaps(self,other);");
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_HasCurveGeometry(self,bLookForCircular);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Overlaps" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_HasCurveGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Overlaps" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_HasCurveGeometry" "', argument " "2"" of type '" "int""'");
+      } 
+      arg2 = static_cast< int >(val2);
     }
     {
       CPLErrorReset();
-      result = (bool)OGRGeometryShadow_Overlaps(arg1,arg2);
+      result = (int)OGRGeometryShadow_HasCurveGeometry(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -20996,7 +23527,7 @@ XS(_wrap_Geometry_Overlaps) {
       
       
     }
-    ST(argvi) = SWIG_From_bool  SWIG_PERL_CALL_ARGS_1(static_cast< bool >(result)); argvi++ ;
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     
     XSRETURN(argvi);
@@ -21008,39 +23539,68 @@ XS(_wrap_Geometry_Overlaps) {
 }
 
 
-XS(_wrap_Geometry_TransformTo) {
+XS(_wrap_Geometry_GetLinearGeometry) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
+    double arg2 = (double) 0.0 ;
+    char **arg3 = (char **) NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_TransformTo(self,reference);");
+    if ((items < 1) || (items > 3)) {
+      SWIG_croak("Usage: Geometry_GetLinearGeometry(self,dfMaxAngleStepSizeDegrees,options);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_TransformTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetLinearGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_TransformTo" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    if (items > 1) {
+      ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+      if (!SWIG_IsOK(ecode2)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetLinearGeometry" "', argument " "2"" of type '" "double""'");
+      } 
+      arg2 = static_cast< double >(val2);
     }
-    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    if (items > 2) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(2))) {
+          if (SvROK(ST(2))) {
+            if (SvTYPE(SvRV(ST(2)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(2)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg3 = CSLAddString( arg3, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(2)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(2));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg3 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg3 = CSLAddNameValue( arg3, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
       }
     }
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_TransformTo(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_GetLinearGeometry(arg1,arg2,arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21062,58 +23622,78 @@ XS(_wrap_Geometry_TransformTo) {
       
       
     }
-    {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
-    }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
     
     
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
     XSRETURN(argvi);
   fail:
     
     
+    {
+      /* %typemap(freearg) char **options */
+      if (arg3) CSLDestroy( arg3 );
+    }
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Transform) {
+XS(_wrap_Geometry_GetCurveGeometry) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OSRCoordinateTransformationShadow *arg2 = (OSRCoordinateTransformationShadow *) 0 ;
+    char **arg2 = (char **) NULL ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Transform(self,trans);");
+    if ((items < 1) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_GetCurveGeometry(self,options);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Transform" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCurveGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRCoordinateTransformationShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Transform" "', argument " "2"" of type '" "OSRCoordinateTransformationShadow *""'"); 
-    }
-    arg2 = reinterpret_cast< OSRCoordinateTransformationShadow * >(argp2);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    if (items > 1) {
+      {
+        /* %typemap(in) char **options */
+        if (SvOK(ST(1))) {
+          if (SvROK(ST(1))) {
+            if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
+              AV *av = (AV*)(SvRV(ST(1)));
+              for (int i = 0; i < av_len(av)+1; i++) {
+                SV *sv = *(av_fetch(av, i, 0));
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                char *pszItem = SvPV_nolen(sv);
+                arg2 = CSLAddString( arg2, pszItem );
+              }
+            } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
+              HV *hv = (HV*)SvRV(ST(1));
+              SV *sv;
+              char *key;
+              I32 klen;
+              arg2 = NULL;
+              hv_iterinit(hv);
+              while(sv = hv_iternextsv(hv,&key,&klen)) {
+                sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+                arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
+              }
+            } else
+            SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+          } else
+          SWIG_croak("The 'options' argument is not a reference.");   
+        }
       }
     }
     {
       CPLErrorReset();
-      result = (OGRErr)OGRGeometryShadow_Transform(arg1,arg2);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_GetCurveGeometry(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21135,45 +23715,52 @@ XS(_wrap_Geometry_Transform) {
       
       
     }
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
     {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
     }
-    
-    
     XSRETURN(argvi);
   fail:
     
-    
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetSpatialReference) {
+XS(_wrap_Geometry_Value) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    double arg2 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
     int argvi = 0;
-    OSRSpatialReferenceShadow *result = 0 ;
+    OGRGeometryShadow *result = 0 ;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetSpatialReference(self);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: Geometry_Value(self,dfDistance);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Value" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Value" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
     {
       CPLErrorReset();
-      result = (OSRSpatialReferenceShadow *)OGRGeometryShadow_GetSpatialReference(arg1);
+      result = (OGRGeometryShadow *)OGRGeometryShadow_Value(arg1,arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21195,43 +23782,63 @@ XS(_wrap_Geometry_GetSpatialReference) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    
     
     XSRETURN(argvi);
   fail:
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_AssignSpatialReference) {
+XS(_wrap_Geometry_Move) {
   {
     OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
+    double arg2 ;
+    double arg3 ;
+    double arg4 = (double) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    void *argp2 = 0 ;
-    int res2 = 0 ;
+    double val2 ;
+    int ecode2 = 0 ;
+    double val3 ;
+    int ecode3 = 0 ;
+    double val4 ;
+    int ecode4 = 0 ;
     int argvi = 0;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_AssignSpatialReference(self,reference);");
+    if ((items < 3) || (items > 4)) {
+      SWIG_croak("Usage: Geometry_Move(self,dx,dy,dz);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AssignSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Move" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
     }
     arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    res2 = SWIG_ConvertPtr(ST(1), &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AssignSpatialReference" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Move" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
+    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Move" "', argument " "3"" of type '" "double""'");
+    } 
+    arg3 = static_cast< double >(val3);
+    if (items > 3) {
+      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
+      if (!SWIG_IsOK(ecode4)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_Move" "', argument " "4"" of type '" "double""'");
+      } 
+      arg4 = static_cast< double >(val4);
     }
-    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
     {
       CPLErrorReset();
-      OGRGeometryShadow_AssignSpatialReference(arg1,arg2);
+      OGRGeometryShadow_Move(arg1,arg2,arg3,arg4);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21258,34 +23865,31 @@ XS(_wrap_Geometry_AssignSpatialReference) {
     }
     
     
+    
+    
     XSRETURN(argvi);
   fail:
     
     
+    
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_CloseRings) {
+XS(_wrap_GetDriverCount) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_CloseRings(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_CloseRings" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: GetDriverCount();");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_CloseRings(arg1);
+      result = (int)OGRGetDriverCount();
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21307,37 +23911,26 @@ XS(_wrap_Geometry_CloseRings) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     XSRETURN(argvi);
   fail:
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_FlattenTo2D) {
+XS(_wrap_GetOpenDSCount) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_FlattenTo2D(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_FlattenTo2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: GetOpenDSCount();");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_FlattenTo2D(arg1);
+      result = (int)OGRGetOpenDSCount();
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21359,45 +23952,34 @@ XS(_wrap_Geometry_FlattenTo2D) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     XSRETURN(argvi);
   fail:
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Segmentize) {
+XS(_wrap_SetGenerate_DB2_V72_BYTE_ORDER) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
-    int ecode2 = 0 ;
+    int arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
+    OGRErr result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_Segmentize(self,dfMaxLength);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Segmentize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: SetGenerate_DB2_V72_BYTE_ORDER(bGenerate_DB2_V72_BYTE_ORDER);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Segmentize" "', argument " "2"" of type '" "double""'");
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetGenerate_DB2_V72_BYTE_ORDER" "', argument " "1"" of type '" "int""'");
     } 
-    arg2 = static_cast< double >(val2);
+    arg1 = static_cast< int >(val1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_Segmentize(arg1,arg2);
+      result = (OGRErr)OGRSetGenerate_DB2_V72_BYTE_ORDER(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21420,44 +24002,33 @@ XS(_wrap_Geometry_Segmentize) {
       
     }
     {
-      /* %typemap(out) void */
+      /* %typemap(out) OGRErr */
+      if ( result != 0 ) {
+        const char *err = CPLGetLastErrorMsg();
+        if (err and *err) SWIG_croak(err); /* this is usually better */
+        SWIG_croak( OGRErrMessages(result) );
+      }
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetEnvelope) {
+XS(_wrap_RegisterAll) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double *arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double argout2[4] ;
     int argvi = 0;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (double argout2[ANY]) */
-      arg2 = argout2;
-    }
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetEnvelope(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: RegisterAll();");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_GetEnvelope(arg1,arg2);
+      OGRRegisterAll();
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21482,55 +24053,33 @@ XS(_wrap_Geometry_GetEnvelope) {
     {
       /* %typemap(out) void */
     }
-    {
-      /* %typemap(argout) (double argout[ANY]) */
-      if (GIMME_V == G_ARRAY) {
-        /* return a list */
-        int i;
-        EXTEND(SP, argvi+4-items+1);
-        for (i = 0; i < 4; i++)
-        ST(argvi++) = sv_2mortal(newSVnv(arg2[i]));
-      } else {
-        ST(argvi) = CreateArrayFromDoubleArray( arg2, 4 );
-        argvi++;
-      }  
-    }
-    
-    
     XSRETURN(argvi);
   fail:
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetEnvelope3D) {
+XS(_wrap_GeometryTypeToName) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double *arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double argout2[6] ;
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
+    char *result = 0 ;
     dXSARGS;
     
-    {
-      /* %typemap(in,numinputs=0) (double argout2[ANY]) */
-      arg2 = argout2;
-    }
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetEnvelope3D(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GeometryTypeToName(eType);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GeometryTypeToName" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_GetEnvelope3D(arg1,arg2);
+      result = (char *)OGRGeometryTypeToName(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21553,52 +24102,41 @@ XS(_wrap_Geometry_GetEnvelope3D) {
       
     }
     {
-      /* %typemap(out) void */
-    }
-    {
-      /* %typemap(argout) (double argout[ANY]) */
-      if (GIMME_V == G_ARRAY) {
-        /* return a list */
-        int i;
-        EXTEND(SP, argvi+6-items+1);
-        for (i = 0; i < 6; i++)
-        ST(argvi++) = sv_2mortal(newSVnv(arg2[i]));
-      } else {
-        ST(argvi) = CreateArrayFromDoubleArray( arg2, 6 );
-        argvi++;
-      }  
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
     }
     
-    
     XSRETURN(argvi);
   fail:
     
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_Centroid) {
+XS(_wrap_GetFieldTypeName) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    OGRFieldType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    char *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_Centroid(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Centroid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GetFieldTypeName(type);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldType""'");
+    } 
+    arg1 = static_cast< OGRFieldType >(val1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_Centroid(arg1);
+      result = (char *)OGR_GetFieldTypeName(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21620,7 +24158,13 @@ XS(_wrap_Geometry_Centroid) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -21630,26 +24174,26 @@ XS(_wrap_Geometry_Centroid) {
 }
 
 
-XS(_wrap_Geometry_PointOnSurface) {
+XS(_wrap_GetFieldSubTypeName) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    OGRFieldSubType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
-    OGRGeometryShadow *result = 0 ;
+    char *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_PointOnSurface(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_PointOnSurface" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GetFieldSubTypeName(type);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldSubTypeName" "', argument " "1"" of type '" "OGRFieldSubType""'");
+    } 
+    arg1 = static_cast< OGRFieldSubType >(val1);
     {
       CPLErrorReset();
-      result = (OGRGeometryShadow *)OGRGeometryShadow_PointOnSurface(arg1);
+      result = (char *)OGR_GetFieldSubTypeName(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21671,7 +24215,13 @@ XS(_wrap_Geometry_PointOnSurface) {
       
       
     }
-    ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_OWNER | SWIG_SHADOW); argvi++ ;
+    {
+      /* %typemap(out) const char * */
+      ST(argvi) = newSVpv(result, 0);
+      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
+      sv_2mortal(ST(argvi));
+      argvi++;
+    }
     
     XSRETURN(argvi);
   fail:
@@ -21681,26 +24231,26 @@ XS(_wrap_Geometry_PointOnSurface) {
 }
 
 
-XS(_wrap_Geometry_WkbSize) {
+XS(_wrap_GT_Flatten) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
-    int result;
+    OGRwkbGeometryType result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_WkbSize(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_WkbSize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GT_Flatten(eType);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_Flatten" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (int)OGRGeometryShadow_WkbSize(arg1);
+      result = (OGRwkbGeometryType)OGR_GT_Flatten(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21732,26 +24282,26 @@ XS(_wrap_Geometry_WkbSize) {
 }
 
 
-XS(_wrap_Geometry_GetCoordinateDimension) {
+XS(_wrap_GT_SetZ) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
-    int result;
+    OGRwkbGeometryType result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetCoordinateDimension(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GT_SetZ(eType);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_SetZ" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (int)OGRGeometryShadow_GetCoordinateDimension(arg1);
+      result = (OGRwkbGeometryType)OGR_GT_SetZ(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21783,33 +24333,44 @@ XS(_wrap_Geometry_GetCoordinateDimension) {
 }
 
 
-XS(_wrap_Geometry_SetCoordinateDimension) {
+XS(_wrap_GT_SetModifier) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+    OGRwkbGeometryType arg1 ;
     int arg2 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    int arg3 = (int) FALSE ;
+    int val1 ;
+    int ecode1 = 0 ;
     int val2 ;
     int ecode2 = 0 ;
+    int val3 ;
+    int ecode3 = 0 ;
     int argvi = 0;
+    OGRwkbGeometryType result;
     dXSARGS;
     
-    if ((items < 2) || (items > 2)) {
-      SWIG_croak("Usage: Geometry_SetCoordinateDimension(self,dimension);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 2) || (items > 3)) {
+      SWIG_croak("Usage: GT_SetModifier(eType,bSetZ,bSetM);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_SetModifier" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetCoordinateDimension" "', argument " "2"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GT_SetModifier" "', argument " "2"" of type '" "int""'");
     } 
     arg2 = static_cast< int >(val2);
+    if (items > 2) {
+      ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
+      if (!SWIG_IsOK(ecode3)) {
+        SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "GT_SetModifier" "', argument " "3"" of type '" "int""'");
+      } 
+      arg3 = static_cast< int >(val3);
+    }
     {
       CPLErrorReset();
-      OGRGeometryShadow_SetCoordinateDimension(arg1,arg2);
+      result = (OGRwkbGeometryType)GT_SetModifier(arg1,arg2,arg3);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21831,40 +24392,40 @@ XS(_wrap_Geometry_SetCoordinateDimension) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
     
     
     XSRETURN(argvi);
   fail:
     
     
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_Geometry_GetDimension) {
+XS(_wrap_GT_HasZ) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
     int result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: Geometry_GetDimension(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+      SWIG_croak("Usage: GT_HasZ(eType);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_HasZ" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (int)OGRGeometryShadow_GetDimension(arg1);
+      result = (int)OGR_GT_HasZ(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21896,51 +24457,87 @@ XS(_wrap_Geometry_GetDimension) {
 }
 
 
-XS(_wrap_Geometry_Move) {
+XS(_wrap_GT_IsSubClassOf) {
   {
-    OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-    double arg2 ;
-    double arg3 ;
-    double arg4 = (double) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    double val2 ;
+    OGRwkbGeometryType arg1 ;
+    OGRwkbGeometryType arg2 ;
+    int val1 ;
+    int ecode1 = 0 ;
+    int val2 ;
     int ecode2 = 0 ;
-    double val3 ;
-    int ecode3 = 0 ;
-    double val4 ;
-    int ecode4 = 0 ;
     int argvi = 0;
+    int result;
     dXSARGS;
     
-    if ((items < 3) || (items > 4)) {
-      SWIG_croak("Usage: Geometry_Move(self,dx,dy,dz);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Move" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: GT_IsSubClassOf(eType,eSuperType);");
     }
-    arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-    ecode2 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Move" "', argument " "2"" of type '" "double""'");
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsSubClassOf" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
     } 
-    arg2 = static_cast< double >(val2);
-    ecode3 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(2), &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Move" "', argument " "3"" of type '" "double""'");
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
+    ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GT_IsSubClassOf" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
     } 
-    arg3 = static_cast< double >(val3);
-    if (items > 3) {
-      ecode4 = SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(ST(3), &val4);
-      if (!SWIG_IsOK(ecode4)) {
-        SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_Move" "', argument " "4"" of type '" "double""'");
-      } 
-      arg4 = static_cast< double >(val4);
+    arg2 = static_cast< OGRwkbGeometryType >(val2);
+    {
+      CPLErrorReset();
+      result = (int)OGR_GT_IsSubClassOf(arg1,arg2);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
+    
+    XSRETURN(argvi);
+  fail:
+    
+    
+    SWIG_croak_null();
+  }
+}
+
+
+XS(_wrap_GT_IsCurve) {
+  {
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
+    int argvi = 0;
+    int result;
+    dXSARGS;
+    
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GT_IsCurve(OGRwkbGeometryType);");
     }
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsCurve" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      OGRGeometryShadow_Move(arg1,arg2,arg3,arg4);
+      result = (int)OGR_GT_IsCurve(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -21962,36 +24559,36 @@ XS(_wrap_Geometry_Move) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
-    
-    
-    
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
     
-    
-    
-    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GetDriverCount) {
+XS(_wrap_GT_IsSurface) {
   {
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
     int result;
     dXSARGS;
     
-    if ((items < 0) || (items > 0)) {
-      SWIG_croak("Usage: GetDriverCount();");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GT_IsSurface(OGRwkbGeometryType);");
     }
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsSurface" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (int)OGRGetDriverCount();
+      result = (int)OGR_GT_IsSurface(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22014,25 +24611,35 @@ XS(_wrap_GetDriverCount) {
       
     }
     ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
     XSRETURN(argvi);
   fail:
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GetOpenDSCount) {
+XS(_wrap_GT_IsNonLinear) {
   {
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
     int result;
     dXSARGS;
     
-    if ((items < 0) || (items > 0)) {
-      SWIG_croak("Usage: GetOpenDSCount();");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GT_IsNonLinear(OGRwkbGeometryType);");
     }
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsNonLinear" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (int)OGRGetOpenDSCount();
+      result = (int)OGR_GT_IsNonLinear(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22055,33 +24662,35 @@ XS(_wrap_GetOpenDSCount) {
       
     }
     ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
     XSRETURN(argvi);
   fail:
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_SetGenerate_DB2_V72_BYTE_ORDER) {
+XS(_wrap_GT_GetCollection) {
   {
-    int arg1 ;
+    OGRwkbGeometryType arg1 ;
     int val1 ;
     int ecode1 = 0 ;
     int argvi = 0;
-    OGRErr result;
+    OGRwkbGeometryType result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: SetGenerate_DB2_V72_BYTE_ORDER(bGenerate_DB2_V72_BYTE_ORDER);");
+      SWIG_croak("Usage: GT_GetCollection(eType);");
     }
     ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
     if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetGenerate_DB2_V72_BYTE_ORDER" "', argument " "1"" of type '" "int""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetCollection" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
     } 
-    arg1 = static_cast< int >(val1);
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (OGRErr)OGRSetGenerate_DB2_V72_BYTE_ORDER(arg1);
+      result = (OGRwkbGeometryType)OGR_GT_GetCollection(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22103,14 +24712,7 @@ XS(_wrap_SetGenerate_DB2_V72_BYTE_ORDER) {
       
       
     }
-    {
-      /* %typemap(out) OGRErr */
-      if ( result != 0 ) {
-        const char *err = CPLGetLastErrorMsg();
-        if (err and *err) SWIG_croak(err); /* this is usually better */
-        SWIG_croak( OGRErrMessages(result) );
-      }
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -22120,17 +24722,26 @@ XS(_wrap_SetGenerate_DB2_V72_BYTE_ORDER) {
 }
 
 
-XS(_wrap_RegisterAll) {
+XS(_wrap_GT_GetCurve) {
   {
+    OGRwkbGeometryType arg1 ;
+    int val1 ;
+    int ecode1 = 0 ;
     int argvi = 0;
+    OGRwkbGeometryType result;
     dXSARGS;
     
-    if ((items < 0) || (items > 0)) {
-      SWIG_croak("Usage: RegisterAll();");
+    if ((items < 1) || (items > 1)) {
+      SWIG_croak("Usage: GT_GetCurve(eType);");
     }
+    ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetCurve" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      OGRRegisterAll();
+      result = (OGRwkbGeometryType)OGR_GT_GetCurve(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22152,36 +24763,36 @@ XS(_wrap_RegisterAll) {
       
       
     }
-    {
-      /* %typemap(out) void */
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    
     XSRETURN(argvi);
   fail:
+    
     SWIG_croak_null();
   }
 }
 
 
-XS(_wrap_GeometryTypeToName) {
+XS(_wrap_GT_GetLinear) {
   {
     OGRwkbGeometryType arg1 ;
     int val1 ;
     int ecode1 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
+    OGRwkbGeometryType result;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GeometryTypeToName(eType);");
+      SWIG_croak("Usage: GT_GetLinear(eType);");
     }
     ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
     if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GeometryTypeToName" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetLinear" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
     } 
     arg1 = static_cast< OGRwkbGeometryType >(val1);
     {
       CPLErrorReset();
-      result = (char *)OGRGeometryTypeToName(arg1);
+      result = (OGRwkbGeometryType)OGR_GT_GetLinear(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22203,13 +24814,7 @@ XS(_wrap_GeometryTypeToName) {
       
       
     }
-    {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
-    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
     
     XSRETURN(argvi);
   fail:
@@ -22219,26 +24824,25 @@ XS(_wrap_GeometryTypeToName) {
 }
 
 
-XS(_wrap_GetFieldTypeName) {
+XS(_wrap_SetNonLinearGeometriesEnabledFlag) {
   {
-    OGRFieldType arg1 ;
+    int arg1 ;
     int val1 ;
     int ecode1 = 0 ;
     int argvi = 0;
-    char *result = 0 ;
     dXSARGS;
     
     if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: GetFieldTypeName(type);");
+      SWIG_croak("Usage: SetNonLinearGeometriesEnabledFlag(bFlag);");
     }
     ecode1 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(0), &val1);
     if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetNonLinearGeometriesEnabledFlag" "', argument " "1"" of type '" "int""'");
     } 
-    arg1 = static_cast< OGRFieldType >(val1);
+    arg1 = static_cast< int >(val1);
     {
       CPLErrorReset();
-      result = (char *)OGR_GetFieldTypeName(arg1);
+      OGRSetNonLinearGeometriesEnabledFlag(arg1);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -22261,11 +24865,7 @@ XS(_wrap_GetFieldTypeName) {
       
     }
     {
-      /* %typemap(out) const char * */
-      ST(argvi) = newSVpv(result, 0);
-      SvUTF8_on(ST(argvi)); /* expecting GDAL to give us UTF-8 */
-      sv_2mortal(ST(argvi));
-      argvi++;
+      /* %typemap(out) void */
     }
     
     XSRETURN(argvi);
@@ -22276,6 +24876,47 @@ XS(_wrap_GetFieldTypeName) {
 }
 
 
+XS(_wrap_GetNonLinearGeometriesEnabledFlag) {
+  {
+    int argvi = 0;
+    int result;
+    dXSARGS;
+    
+    if ((items < 0) || (items > 0)) {
+      SWIG_croak("Usage: GetNonLinearGeometriesEnabledFlag();");
+    }
+    {
+      CPLErrorReset();
+      result = (int)OGRGetNonLinearGeometriesEnabledFlag();
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+        
+        
+        
+        
+        
+      }
+      
+      
+      /* 
+          Make warnings regular Perl warnings. This duplicates the warning
+          message if DontUseExceptions() is in effect (it is not by default).
+          */
+      if ( eclass == CE_Warning ) {
+        warn( CPLGetLastErrorMsg(), "%s" );
+      }
+      
+      
+    }
+    ST(argvi) = SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ;
+    XSRETURN(argvi);
+  fail:
+    SWIG_croak_null();
+  }
+}
+
+
 XS(_wrap_GetOpenDS) {
   {
     int arg1 ;
@@ -22597,9 +25238,9 @@ XS(_wrap_GeneralCmdLineProcessor) {
               arg1 = CSLAddNameValue( arg1, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     if (items > 1) {
@@ -22744,7 +25385,18 @@ XS(_wrap_TermProgress_nocb) {
 
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
 
+static void *_p_OGRDriverShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRDriverShadow *) x));
+}
+static void *_p_OGRLayerShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRLayerShadow *) x));
+}
+static void *_p_OGRDataSourceShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRDataSourceShadow *) x));
+}
+static swig_type_info _swigt__p_GDALMajorObjectShadow = {"_p_GDALMajorObjectShadow", "GDALMajorObjectShadow *", 0, 0, (void*)"Geo::GDAL::MajorObject", 0};
 static swig_type_info _swigt__p_GDALProgressFunc = {"_p_GDALProgressFunc", "GDALProgressFunc *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GIntBig = {"_p_GIntBig", "GIntBig *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_OGRDataSourceShadow = {"_p_OGRDataSourceShadow", "OGRDataSourceShadow *", 0, 0, (void*)"Geo::OGR::DataSource", 0};
 static swig_type_info _swigt__p_OGRDriverShadow = {"_p_OGRDriverShadow", "OGRDriverShadow *", 0, 0, (void*)"Geo::OGR::Driver", 0};
 static swig_type_info _swigt__p_OGRFeatureDefnShadow = {"_p_OGRFeatureDefnShadow", "OGRFeatureDefnShadow *", 0, 0, (void*)"Geo::OGR::FeatureDefn", 0};
@@ -22759,14 +25411,17 @@ static swig_type_info _swigt__p_OSRSpatialReferenceShadow = {"_p_OSRSpatialRefer
 static swig_type_info _swigt__p_char = {"_p_char", "char *|retStringAndCPLFree *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_double = {"_p_double", "double *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_f_double_p_q_const__char_p_void__int = {"_p_f_double_p_q_const__char_p_void__int", "int (*)(double,char const *,void *)", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldType *|int *|OGRwkbGeometryType *|OGRJustification *|OGRwkbByteOrder *|OGRErr *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldSubType *|OGRFieldType *|int *|OGRwkbGeometryType *|OGRJustification *|OGRwkbByteOrder *|OGRErr *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_double = {"_p_p_double", "double **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_int = {"_p_p_int", "int **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_p_char = {"_p_p_p_char", "char ***", 0, 0, (void*)0, 0};
 
 static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_GDALMajorObjectShadow,
   &_swigt__p_GDALProgressFunc,
+  &_swigt__p_GIntBig,
   &_swigt__p_OGRDataSourceShadow,
   &_swigt__p_OGRDriverShadow,
   &_swigt__p_OGRFeatureDefnShadow,
@@ -22781,6 +25436,7 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_char,
   &_swigt__p_double,
   &_swigt__p_f_double_p_q_const__char_p_void__int,
+  &_swigt__p_float,
   &_swigt__p_int,
   &_swigt__p_p_char,
   &_swigt__p_p_double,
@@ -22788,7 +25444,9 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_p_p_char,
 };
 
+static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_OGRDriverShadow, _p_OGRDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRLayerShadow, _p_OGRLayerShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRDataSourceShadow, _p_OGRDataSourceShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALProgressFunc[] = {  {&_swigt__p_GDALProgressFunc, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GIntBig[] = {  {&_swigt__p_GIntBig, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_OGRDataSourceShadow[] = {  {&_swigt__p_OGRDataSourceShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_OGRDriverShadow[] = {  {&_swigt__p_OGRDriverShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_OGRFeatureDefnShadow[] = {  {&_swigt__p_OGRFeatureDefnShadow, 0, 0, 0},{0, 0, 0, 0}};
@@ -22803,6 +25461,7 @@ static swig_cast_info _swigc__p_OSRSpatialReferenceShadow[] = {  {&_swigt__p_OSR
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_f_double_p_q_const__char_p_void__int[] = {  {&_swigt__p_f_double_p_q_const__char_p_void__int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_double[] = {  {&_swigt__p_p_double, 0, 0, 0},{0, 0, 0, 0}};
@@ -22810,7 +25469,9 @@ static swig_cast_info _swigc__p_p_int[] = {  {&_swigt__p_p_int, 0, 0, 0},{0, 0,
 static swig_cast_info _swigc__p_p_p_char[] = {  {&_swigt__p_p_p_char, 0, 0, 0},{0, 0, 0, 0}};
 
 static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_GDALMajorObjectShadow,
   _swigc__p_GDALProgressFunc,
+  _swigc__p_GIntBig,
   _swigc__p_OGRDataSourceShadow,
   _swigc__p_OGRDriverShadow,
   _swigc__p_OGRFeatureDefnShadow,
@@ -22825,6 +25486,7 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_char,
   _swigc__p_double,
   _swigc__p_f_double_p_q_const__char_p_void__int,
+  _swigc__p_float,
   _swigc__p_int,
   _swigc__p_p_char,
   _swigc__p_p_double,
@@ -22875,15 +25537,19 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::DataSource_GetName", _wrap_DataSource_GetName},
 {"Geo::OGRc::DataSource__DeleteLayer", _wrap_DataSource__DeleteLayer},
 {"Geo::OGRc::DataSource_SyncToDisk", _wrap_DataSource_SyncToDisk},
+{"Geo::OGRc::DataSource_FlushCache", _wrap_DataSource_FlushCache},
 {"Geo::OGRc::DataSource__CreateLayer", _wrap_DataSource__CreateLayer},
 {"Geo::OGRc::DataSource_CopyLayer", _wrap_DataSource_CopyLayer},
-{"Geo::OGRc::DataSource__GetLayerByIndex", _wrap_DataSource__GetLayerByIndex},
-{"Geo::OGRc::DataSource__GetLayerByName", _wrap_DataSource__GetLayerByName},
+{"Geo::OGRc::DataSource_GetLayerByIndex", _wrap_DataSource_GetLayerByIndex},
+{"Geo::OGRc::DataSource_GetLayerByName", _wrap_DataSource_GetLayerByName},
 {"Geo::OGRc::DataSource__TestCapability", _wrap_DataSource__TestCapability},
 {"Geo::OGRc::DataSource__ExecuteSQL", _wrap_DataSource__ExecuteSQL},
-{"Geo::OGRc::DataSource_ReleaseResultSet", _wrap_DataSource_ReleaseResultSet},
+{"Geo::OGRc::DataSource__ReleaseResultSet", _wrap_DataSource__ReleaseResultSet},
 {"Geo::OGRc::DataSource_GetStyleTable", _wrap_DataSource_GetStyleTable},
 {"Geo::OGRc::DataSource_SetStyleTable", _wrap_DataSource_SetStyleTable},
+{"Geo::OGRc::DataSource_StartTransaction", _wrap_DataSource_StartTransaction},
+{"Geo::OGRc::DataSource_CommitTransaction", _wrap_DataSource_CommitTransaction},
+{"Geo::OGRc::DataSource_RollbackTransaction", _wrap_DataSource_RollbackTransaction},
 {"Geo::OGRc::Layer_GetRefCount", _wrap_Layer_GetRefCount},
 {"Geo::OGRc::Layer_SetSpatialFilter", _wrap_Layer_SetSpatialFilter},
 {"Geo::OGRc::Layer_SetSpatialFilterRect", _wrap_Layer_SetSpatialFilterRect},
@@ -22909,7 +25575,7 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::Layer__DeleteField", _wrap_Layer__DeleteField},
 {"Geo::OGRc::Layer_ReorderField", _wrap_Layer_ReorderField},
 {"Geo::OGRc::Layer_ReorderFields", _wrap_Layer_ReorderFields},
-{"Geo::OGRc::Layer_AlterFieldDefn", _wrap_Layer_AlterFieldDefn},
+{"Geo::OGRc::Layer__AlterFieldDefn", _wrap_Layer__AlterFieldDefn},
 {"Geo::OGRc::Layer_CreateGeomField", _wrap_Layer_CreateGeomField},
 {"Geo::OGRc::Layer_StartTransaction", _wrap_Layer_StartTransaction},
 {"Geo::OGRc::Layer_CommitTransaction", _wrap_Layer_CommitTransaction},
@@ -22930,8 +25596,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::delete_Feature", _wrap_delete_Feature},
 {"Geo::OGRc::new_Feature", _wrap_new_Feature},
 {"Geo::OGRc::Feature_GetDefnRef", _wrap_Feature_GetDefnRef},
-{"Geo::OGRc::Feature_SetGeometry", _wrap_Feature_SetGeometry},
-{"Geo::OGRc::Feature__SetGeometryDirectly", _wrap_Feature__SetGeometryDirectly},
+{"Geo::OGRc::Feature__SetGeometry", _wrap_Feature__SetGeometry},
+{"Geo::OGRc::Feature_SetGeometryDirectly", _wrap_Feature_SetGeometryDirectly},
 {"Geo::OGRc::Feature_GetGeometryRef", _wrap_Feature_GetGeometryRef},
 {"Geo::OGRc::Feature_SetGeomField", _wrap_Feature_SetGeomField},
 {"Geo::OGRc::Feature_SetGeomFieldDirectly", _wrap_Feature_SetGeomFieldDirectly},
@@ -22944,11 +25610,13 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::Feature_GetGeomFieldDefnRef", _wrap_Feature_GetGeomFieldDefnRef},
 {"Geo::OGRc::Feature_GetFieldAsString", _wrap_Feature_GetFieldAsString},
 {"Geo::OGRc::Feature_GetFieldAsInteger", _wrap_Feature_GetFieldAsInteger},
+{"Geo::OGRc::Feature_GetFieldAsInteger64", _wrap_Feature_GetFieldAsInteger64},
 {"Geo::OGRc::Feature_GetFieldAsDouble", _wrap_Feature_GetFieldAsDouble},
 {"Geo::OGRc::Feature_GetFieldAsDateTime", _wrap_Feature_GetFieldAsDateTime},
 {"Geo::OGRc::Feature_GetFieldAsIntegerList", _wrap_Feature_GetFieldAsIntegerList},
 {"Geo::OGRc::Feature_GetFieldAsDoubleList", _wrap_Feature_GetFieldAsDoubleList},
 {"Geo::OGRc::Feature_GetFieldAsStringList", _wrap_Feature_GetFieldAsStringList},
+{"Geo::OGRc::Feature_GetFieldAsBinary", _wrap_Feature_GetFieldAsBinary},
 {"Geo::OGRc::Feature_IsFieldSet", _wrap_Feature_IsFieldSet},
 {"Geo::OGRc::Feature_GetFieldIndex", _wrap_Feature_GetFieldIndex},
 {"Geo::OGRc::Feature_GetGeomFieldIndex", _wrap_Feature_GetGeomFieldIndex},
@@ -22956,6 +25624,7 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::Feature_SetFID", _wrap_Feature_SetFID},
 {"Geo::OGRc::Feature_DumpReadable", _wrap_Feature_DumpReadable},
 {"Geo::OGRc::Feature__UnsetField", _wrap_Feature__UnsetField},
+{"Geo::OGRc::Feature_SetFieldInteger64", _wrap_Feature_SetFieldInteger64},
 {"Geo::OGRc::Feature__SetField", _wrap_Feature__SetField},
 {"Geo::OGRc::Feature_SetFieldIntegerList", _wrap_Feature_SetFieldIntegerList},
 {"Geo::OGRc::Feature_SetFieldDoubleList", _wrap_Feature_SetFieldDoubleList},
@@ -22965,7 +25634,9 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::Feature_SetFromWithMap", _wrap_Feature_SetFromWithMap},
 {"Geo::OGRc::Feature_GetStyleString", _wrap_Feature_GetStyleString},
 {"Geo::OGRc::Feature_SetStyleString", _wrap_Feature_SetStyleString},
-{"Geo::OGRc::Feature__GetFieldType", _wrap_Feature__GetFieldType},
+{"Geo::OGRc::Feature_GetFieldType", _wrap_Feature_GetFieldType},
+{"Geo::OGRc::Feature__Validate", _wrap_Feature__Validate},
+{"Geo::OGRc::Feature_FillUnsetWithDefault", _wrap_Feature_FillUnsetWithDefault},
 {"Geo::OGRc::delete_FeatureDefn", _wrap_delete_FeatureDefn},
 {"Geo::OGRc::new_FeatureDefn", _wrap_new_FeatureDefn},
 {"Geo::OGRc::FeatureDefn_GetName", _wrap_FeatureDefn_GetName},
@@ -22993,6 +25664,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::FieldDefn_SetName", _wrap_FieldDefn_SetName},
 {"Geo::OGRc::FieldDefn_GetType", _wrap_FieldDefn_GetType},
 {"Geo::OGRc::FieldDefn_SetType", _wrap_FieldDefn_SetType},
+{"Geo::OGRc::FieldDefn_GetSubType", _wrap_FieldDefn_GetSubType},
+{"Geo::OGRc::FieldDefn_SetSubType", _wrap_FieldDefn_SetSubType},
 {"Geo::OGRc::FieldDefn_GetJustify", _wrap_FieldDefn_GetJustify},
 {"Geo::OGRc::FieldDefn_SetJustify", _wrap_FieldDefn_SetJustify},
 {"Geo::OGRc::FieldDefn_GetWidth", _wrap_FieldDefn_GetWidth},
@@ -23003,6 +25676,11 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::FieldDefn_GetFieldTypeName", _wrap_FieldDefn_GetFieldTypeName},
 {"Geo::OGRc::FieldDefn_IsIgnored", _wrap_FieldDefn_IsIgnored},
 {"Geo::OGRc::FieldDefn_SetIgnored", _wrap_FieldDefn_SetIgnored},
+{"Geo::OGRc::FieldDefn_IsNullable", _wrap_FieldDefn_IsNullable},
+{"Geo::OGRc::FieldDefn_SetNullable", _wrap_FieldDefn_SetNullable},
+{"Geo::OGRc::FieldDefn_GetDefault", _wrap_FieldDefn_GetDefault},
+{"Geo::OGRc::FieldDefn_SetDefault", _wrap_FieldDefn_SetDefault},
+{"Geo::OGRc::FieldDefn_IsDefaultDriverSpecific", _wrap_FieldDefn_IsDefaultDriverSpecific},
 {"Geo::OGRc::delete_GeomFieldDefn", _wrap_delete_GeomFieldDefn},
 {"Geo::OGRc::new_GeomFieldDefn", _wrap_new_GeomFieldDefn},
 {"Geo::OGRc::GeomFieldDefn_GetName", _wrap_GeomFieldDefn_GetName},
@@ -23014,6 +25692,8 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::GeomFieldDefn_SetSpatialRef", _wrap_GeomFieldDefn_SetSpatialRef},
 {"Geo::OGRc::GeomFieldDefn_IsIgnored", _wrap_GeomFieldDefn_IsIgnored},
 {"Geo::OGRc::GeomFieldDefn_SetIgnored", _wrap_GeomFieldDefn_SetIgnored},
+{"Geo::OGRc::GeomFieldDefn_IsNullable", _wrap_GeomFieldDefn_IsNullable},
+{"Geo::OGRc::GeomFieldDefn_SetNullable", _wrap_GeomFieldDefn_SetNullable},
 {"Geo::OGRc::CreateGeometryFromWkb", _wrap_CreateGeometryFromWkb},
 {"Geo::OGRc::CreateGeometryFromWkt", _wrap_CreateGeometryFromWkt},
 {"Geo::OGRc::CreateGeometryFromGML", _wrap_CreateGeometryFromGML},
@@ -23025,10 +25705,13 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::ForceToMultiPolygon", _wrap_ForceToMultiPolygon},
 {"Geo::OGRc::ForceToMultiPoint", _wrap_ForceToMultiPoint},
 {"Geo::OGRc::ForceToMultiLineString", _wrap_ForceToMultiLineString},
+{"Geo::OGRc::ForceTo", _wrap_ForceTo},
 {"Geo::OGRc::delete_Geometry", _wrap_delete_Geometry},
 {"Geo::OGRc::new_Geometry", _wrap_new_Geometry},
 {"Geo::OGRc::Geometry_ExportToWkt", _wrap_Geometry_ExportToWkt},
+{"Geo::OGRc::Geometry_ExportToIsoWkt", _wrap_Geometry_ExportToIsoWkt},
 {"Geo::OGRc::Geometry__ExportToWkb", _wrap_Geometry__ExportToWkb},
+{"Geo::OGRc::Geometry_ExportToIsoWkb", _wrap_Geometry_ExportToIsoWkb},
 {"Geo::OGRc::Geometry_ExportToGML", _wrap_Geometry_ExportToGML},
 {"Geo::OGRc::Geometry_ExportToKML", _wrap_Geometry_ExportToKML},
 {"Geo::OGRc::Geometry_ExportToJson", _wrap_Geometry_ExportToJson},
@@ -23095,6 +25778,10 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::Geometry_GetCoordinateDimension", _wrap_Geometry_GetCoordinateDimension},
 {"Geo::OGRc::Geometry_SetCoordinateDimension", _wrap_Geometry_SetCoordinateDimension},
 {"Geo::OGRc::Geometry_GetDimension", _wrap_Geometry_GetDimension},
+{"Geo::OGRc::Geometry_HasCurveGeometry", _wrap_Geometry_HasCurveGeometry},
+{"Geo::OGRc::Geometry_GetLinearGeometry", _wrap_Geometry_GetLinearGeometry},
+{"Geo::OGRc::Geometry_GetCurveGeometry", _wrap_Geometry_GetCurveGeometry},
+{"Geo::OGRc::Geometry_Value", _wrap_Geometry_Value},
 {"Geo::OGRc::Geometry_Move", _wrap_Geometry_Move},
 {"Geo::OGRc::GetDriverCount", _wrap_GetDriverCount},
 {"Geo::OGRc::GetOpenDSCount", _wrap_GetOpenDSCount},
@@ -23102,6 +25789,20 @@ static swig_command_info swig_commands[] = {
 {"Geo::OGRc::RegisterAll", _wrap_RegisterAll},
 {"Geo::OGRc::GeometryTypeToName", _wrap_GeometryTypeToName},
 {"Geo::OGRc::GetFieldTypeName", _wrap_GetFieldTypeName},
+{"Geo::OGRc::GetFieldSubTypeName", _wrap_GetFieldSubTypeName},
+{"Geo::OGRc::GT_Flatten", _wrap_GT_Flatten},
+{"Geo::OGRc::GT_SetZ", _wrap_GT_SetZ},
+{"Geo::OGRc::GT_SetModifier", _wrap_GT_SetModifier},
+{"Geo::OGRc::GT_HasZ", _wrap_GT_HasZ},
+{"Geo::OGRc::GT_IsSubClassOf", _wrap_GT_IsSubClassOf},
+{"Geo::OGRc::GT_IsCurve", _wrap_GT_IsCurve},
+{"Geo::OGRc::GT_IsSurface", _wrap_GT_IsSurface},
+{"Geo::OGRc::GT_IsNonLinear", _wrap_GT_IsNonLinear},
+{"Geo::OGRc::GT_GetCollection", _wrap_GT_GetCollection},
+{"Geo::OGRc::GT_GetCurve", _wrap_GT_GetCurve},
+{"Geo::OGRc::GT_GetLinear", _wrap_GT_GetLinear},
+{"Geo::OGRc::SetNonLinearGeometriesEnabledFlag", _wrap_SetNonLinearGeometriesEnabledFlag},
+{"Geo::OGRc::GetNonLinearGeometriesEnabledFlag", _wrap_GetNonLinearGeometriesEnabledFlag},
 {"Geo::OGRc::GetOpenDS", _wrap_GetOpenDS},
 {"Geo::OGRc::Open", _wrap_Open},
 {"Geo::OGRc::OpenShared", _wrap_OpenShared},
@@ -23459,6 +26160,31 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCircularString", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(8)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCompoundCurve", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(9)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCurvePolygon", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(10)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbMultiCurve", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(11)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbMultiSurface", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(12)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbNone", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(100)));
     SvREADONLY_on(sv);
@@ -23469,38 +26195,63 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCircularStringZ", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1008)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCompoundCurveZ", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1009)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbCurvePolygonZ", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1010)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbMultiCurveZ", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1011)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "wkbMultiSurfaceZ", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1012)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbPoint25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbPoint+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000001)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbLineString25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbLineString+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000002)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbPolygon25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbPolygon+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000003)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbMultiPoint25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbMultiPoint+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000004)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbMultiLineString25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbMultiLineString+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000005)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbMultiPolygon25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbMultiPolygon+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000006)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "wkbGeometryCollection25D", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(wkbGeometryCollection+wkb25DBit)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x80000007)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
@@ -23564,6 +26315,36 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFTInteger64", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(12)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFTInteger64List", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(13)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFSTNone", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFSTBoolean", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFSTInt16", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(2)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OFSTFloat32", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(3)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "OJUndefined", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0)));
     SvREADONLY_on(sv);
@@ -23609,8 +26390,43 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALTER_NULLABLE_FLAG", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(8)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ALTER_DEFAULT_FLAG", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(16)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "ALTER_ALL_FLAG", TRUE | 0x2 | GV_ADDMULTI);
-    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1+2+4)));
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(1+2+4+8+16)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_VAL_NULL", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x00000001)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_VAL_GEOM_TYPE", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x00000002)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_VAL_WIDTH", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x00000004)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_VAL_ALLOW_NULL_WHEN_DEFAULT", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0x00000008)));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "F_VAL_ALL", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_From_int  SWIG_PERL_CALL_ARGS_1(static_cast< int >(0xFFFFFFFF)));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
@@ -23694,6 +26510,11 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OLCCurveGeometries", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("CurveGeometries"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "ODsCCreateLayer", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr("CreateLayer"));
     SvREADONLY_on(sv);
@@ -23709,6 +26530,21 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ODsCCurveGeometries", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("CurveGeometries"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ODsCTransactions", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Transactions"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "ODsCEmulatedTransactions", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("EmulatedTransactions"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "ODrCCreateDataSource", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr("CreateDataSource"));
     SvREADONLY_on(sv);
@@ -23718,6 +26554,11 @@ XS(SWIG_init) {
     sv_setsv(sv, SWIG_FromCharPtr("DeleteDataSource"));
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "OLMD_FID64", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("OLMD_FID64"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
   
   
   /*UseExceptions(); is set by GDAL module */
diff --git a/swig/perl/osr_wrap.cpp b/swig/perl/osr_wrap.cpp
index a845a27..81ca7a1 100644
--- a/swig/perl/osr_wrap.cpp
+++ b/swig/perl/osr_wrap.cpp
@@ -1713,6 +1713,8 @@ OGRErrMessages( int rc ) {
     return "OGR Error: Unsupported SRS";
   case OGRERR_INVALID_HANDLE:
     return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
   default:
     return "OGR Error: Unknown";
   }
@@ -1736,11 +1738,6 @@ SWIGINTERN void delete_OSRSpatialReferenceShadow(OSRSpatialReferenceShadow *self
       OSRDestroySpatialReference( self );
     }
   }
-SWIGINTERN retStringAndCPLFree *OSRSpatialReferenceShadow___str__(OSRSpatialReferenceShadow *self){
-    char *buf = 0;
-    OSRExportToPrettyWkt( self, &buf, 0 );
-    return buf;
-  }
 SWIGINTERN int OSRSpatialReferenceShadow_IsSame(OSRSpatialReferenceShadow *self,OSRSpatialReferenceShadow *rhs){
     return OSRIsSame( self, rhs );
   }
@@ -2262,8 +2259,8 @@ SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromERM(OSRSpatialReferenceSha
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromMICoordSys(OSRSpatialReferenceShadow *self,char const *pszCoordSys){
     return OSRImportFromMICoordSys( self, pszCoordSys );
   }
-SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *datum,char const *proj,char const *projParms){
-    return OSRImportFromOzi( self, datum, proj, projParms );
+SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *const *papszLines){
+    return OSRImportFromOzi( self, papszLines );
   }
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ExportToWkt(OSRSpatialReferenceShadow *self,char **argout){
     return OSRExportToWkt( self, argout );
@@ -2953,69 +2950,6 @@ XS(_wrap_delete_SpatialReference) {
 }
 
 
-XS(_wrap_SpatialReference___str__) {
-  {
-    OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
-    void *argp1 = 0 ;
-    int res1 = 0 ;
-    int argvi = 0;
-    retStringAndCPLFree *result = 0 ;
-    dXSARGS;
-    
-    if ((items < 1) || (items > 1)) {
-      SWIG_croak("Usage: SpatialReference___str__(self);");
-    }
-    res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SpatialReference___str__" "', argument " "1"" of type '" "OSRSpatialReferenceShadow *""'"); 
-    }
-    arg1 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp1);
-    {
-      CPLErrorReset();
-      result = (retStringAndCPLFree *)OSRSpatialReferenceShadow___str__(arg1);
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-        
-        
-        
-        
-        
-      }
-      
-      
-      /* 
-          Make warnings regular Perl warnings. This duplicates the warning
-          message if DontUseExceptions() is in effect (it is not by default).
-          */
-      if ( eclass == CE_Warning ) {
-        warn( CPLGetLastErrorMsg(), "%s" );
-      }
-      
-      
-    }
-    
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
-    {
-      ST(argvi) = SWIG_FromCharPtr((const char *)result);
-      CPLFree(result);
-    }
-    else
-    {
-      ST(argvi) = &PL_sv_undef;
-    }
-    argvi++ ;
-    
-    
-    XSRETURN(argvi);
-  fail:
-    
-    SWIG_croak_null();
-  }
-}
-
-
 XS(_wrap_SpatialReference_IsSame) {
   {
     OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
@@ -10665,9 +10599,9 @@ XS(_wrap_SpatialReference_ImportFromESRI) {
               arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
             }
           } else
-          SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference to an array or hash");
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
         } else
-        SWIG_croak("the 'options' argument to a Geo::GDAL method is not a reference");   
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
@@ -10898,7 +10832,7 @@ XS(_wrap_SpatialReference_ImportFromPCI) {
       {
         /* %typemap(in) (double argin4[ANY]) */
         if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         arg4 = argin4;
         AV *av = (AV*)(SvRV(ST(3)));
         for (unsigned int i=0; i<17; i++) {
@@ -10998,7 +10932,7 @@ XS(_wrap_SpatialReference_ImportFromUSGS) {
       {
         /* %typemap(in) (double argin4[ANY]) */
         if (!(SvROK(ST(3)) && (SvTYPE(SvRV(ST(3)))==SVt_PVAV)))
-        SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+        SWIG_croak("Expected a reference to an array.");
         arg4 = argin4;
         AV *av = (AV*)(SvRV(ST(3)));
         for (unsigned int i=0; i<15; i++) {
@@ -11305,65 +11239,58 @@ XS(_wrap_SpatialReference_ImportFromMICoordSys) {
 XS(_wrap_SpatialReference_ImportFromOzi) {
   {
     OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
-    char *arg2 = (char *) 0 ;
-    char *arg3 = (char *) 0 ;
-    char *arg4 = (char *) 0 ;
+    char **arg2 = (char **) 0 ;
     void *argp1 = 0 ;
     int res1 = 0 ;
-    int res2 ;
-    char *buf2 = 0 ;
-    int alloc2 = 0 ;
-    int res3 ;
-    char *buf3 = 0 ;
-    int alloc3 = 0 ;
-    int res4 ;
-    char *buf4 = 0 ;
-    int alloc4 = 0 ;
     int argvi = 0;
     OGRErr result;
     dXSARGS;
     
-    if ((items < 4) || (items > 4)) {
-      SWIG_croak("Usage: SpatialReference_ImportFromOzi(self,datum,proj,projParms);");
+    if ((items < 2) || (items > 2)) {
+      SWIG_croak("Usage: SpatialReference_ImportFromOzi(self,papszLines);");
     }
     res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
     if (!SWIG_IsOK(res1)) {
       SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SpatialReference_ImportFromOzi" "', argument " "1"" of type '" "OSRSpatialReferenceShadow *""'"); 
     }
     arg1 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp1);
-    res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "SpatialReference_ImportFromOzi" "', argument " "2"" of type '" "char const *""'");
-    }
-    arg2 = reinterpret_cast< char * >(buf2);
-    res3 = SWIG_AsCharPtrAndSize(ST(2), &buf3, NULL, &alloc3);
-    if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "SpatialReference_ImportFromOzi" "', argument " "3"" of type '" "char const *""'");
-    }
-    arg3 = reinterpret_cast< char * >(buf3);
-    res4 = SWIG_AsCharPtrAndSize(ST(3), &buf4, NULL, &alloc4);
-    if (!SWIG_IsOK(res4)) {
-      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "SpatialReference_ImportFromOzi" "', argument " "4"" of type '" "char const *""'");
-    }
-    arg4 = reinterpret_cast< char * >(buf4);
-    {
-      if (!arg2) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-      }
-    }
     {
-      if (!arg3) {
-        SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+      /* %typemap(in) char **options */
+      if (SvOK(ST(1))) {
+        if (SvROK(ST(1))) {
+          if (SvTYPE(SvRV(ST(1)))==SVt_PVAV) {
+            AV *av = (AV*)(SvRV(ST(1)));
+            for (int i = 0; i < av_len(av)+1; i++) {
+              SV *sv = *(av_fetch(av, i, 0));
+              sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+              char *pszItem = SvPV_nolen(sv);
+              arg2 = CSLAddString( arg2, pszItem );
+            }
+          } else if (SvTYPE(SvRV(ST(1)))==SVt_PVHV) {
+            HV *hv = (HV*)SvRV(ST(1));
+            SV *sv;
+            char *key;
+            I32 klen;
+            arg2 = NULL;
+            hv_iterinit(hv);
+            while(sv = hv_iternextsv(hv,&key,&klen)) {
+              sv_utf8_upgrade(sv); /* GDAL expects UTF-8 */
+              arg2 = CSLAddNameValue( arg2, key, SvPV_nolen(sv) );
+            }
+          } else
+          SWIG_croak("The 'options' argument is not a reference to an array or a hash.");
+        } else
+        SWIG_croak("The 'options' argument is not a reference.");   
       }
     }
     {
-      if (!arg4) {
+      if (!arg2) {
         SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
       }
     }
     {
       CPLErrorReset();
-      result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4);
+      result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *const *)arg2);
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception_fail( SWIG_RuntimeError, CPLGetLastErrorMsg() );
@@ -11394,15 +11321,17 @@ XS(_wrap_SpatialReference_ImportFromOzi) {
       }
     }
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-    if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
     XSRETURN(argvi);
   fail:
     
-    if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-    if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-    if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+    {
+      /* %typemap(freearg) char **options */
+      if (arg2) CSLDestroy( arg2 );
+    }
     SWIG_croak_null();
   }
 }
@@ -12678,7 +12607,7 @@ XS(_wrap_CoordinateTransformation_TransformPoint__SWIG_0) {
     {
       /* %typemap(in) (double argin2[ANY]) */
       if (!(SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       arg2 = argin2;
       AV *av = (AV*)(SvRV(ST(1)));
       for (unsigned int i=0; i<3; i++) {
@@ -12981,18 +12910,20 @@ XS(_wrap_CoordinateTransformation__TransformPoints) {
       /* %typemap(in) (int nCount, double *x, double *y, double *z) */
       /* ST(1) is a ref to a list of refs to point lists */
       if (! (SvROK(ST(1)) && (SvTYPE(SvRV(ST(1)))==SVt_PVAV)))
-      SWIG_croak("expected a reference to an array as an argument to a Geo::GDAL method");
+      SWIG_croak("Expected a reference to an array.");
       AV *av = (AV*)(SvRV(ST(1)));
       arg2 = av_len(av)+1;
-      arg3 = (double*) malloc(arg2*sizeof(double));
-      arg4 = (double*) malloc(arg2*sizeof(double));
-      arg5 = (double*) malloc(arg2*sizeof(double));
+      arg3 = (double*)CPLMalloc(arg2*sizeof(double));
+      if (arg3)
+      arg4 = (double*)CPLMalloc(arg2*sizeof(double));
+      if (arg3 && arg4)
+      arg5 = (double*)CPLMalloc(arg2*sizeof(double));
       if (!arg3 or !arg4 or !arg5)
-      SWIG_croak("out of memory in Geo::GDAL");
+      SWIG_fail;
       for (int i = 0; i < arg2; i++) {
         SV **sv = av_fetch(av, i, 0); /* ref to one point list */
         if (!(SvROK(*sv) && (SvTYPE(SvRV(*sv))==SVt_PVAV)))
-        SWIG_croak("expected a reference to a list of coordinates as an argument to a Geo::GDAL method");
+        SWIG_croak("An item in the list is not a reference to an array.");
         AV *ac = (AV*)(SvRV(*sv));
         int n = av_len(ac)+1;
         SV **c = av_fetch(ac, 0, 0);
@@ -13061,18 +12992,18 @@ XS(_wrap_CoordinateTransformation__TransformPoints) {
     
     {
       /* %typemap(freearg) (int nCount, double *x, double *y, double *z) */
-      if (arg3) free(arg3);
-      if (arg4) free(arg4);
-      if (arg5) free(arg5);
+      CPLFree(arg3);
+      CPLFree(arg4);
+      CPLFree(arg5);
     }
     XSRETURN(argvi);
   fail:
     
     {
       /* %typemap(freearg) (int nCount, double *x, double *y, double *z) */
-      if (arg3) free(arg3);
-      if (arg4) free(arg4);
-      if (arg5) free(arg5);
+      CPLFree(arg3);
+      CPLFree(arg4);
+      CPLFree(arg5);
     }
     SWIG_croak_null();
   }
@@ -13205,7 +13136,6 @@ static swig_command_info swig_commands[] = {
 {"Geo::OSRc::GetProjectionMethodParamInfo", _wrap_GetProjectionMethodParamInfo},
 {"Geo::OSRc::new_SpatialReference", _wrap_new_SpatialReference},
 {"Geo::OSRc::delete_SpatialReference", _wrap_delete_SpatialReference},
-{"Geo::OSRc::SpatialReference___str__", _wrap_SpatialReference___str__},
 {"Geo::OSRc::SpatialReference_IsSame", _wrap_SpatialReference_IsSame},
 {"Geo::OSRc::SpatialReference_IsSameGeogCS", _wrap_SpatialReference_IsSameGeogCS},
 {"Geo::OSRc::SpatialReference_IsSameVertCS", _wrap_SpatialReference_IsSameVertCS},
@@ -13774,6 +13704,11 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_MERCATOR_AUXILIARY_SPHERE", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Mercator_Auxiliary_Sphere"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_MILLER_CYLINDRICAL", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr("Miller_Cylindrical"));
     SvREADONLY_on(sv);
@@ -13924,6 +13859,46 @@ XS(SWIG_init) {
     SvREADONLY_on(sv);
   } while(0) /*@SWIG@*/;
   /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_QSC", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Quadrilateralized_Spherical_Cube"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_AITOFF", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Aitoff"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_WINKEL_I", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Winkel_I"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_WINKEL_II", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Winkel_II"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_WINKEL_TRIPEL", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Winkel_Tripel"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_CRASTER_PARABOLIC", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Craster_Parabolic"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_LOXIMUTHAL", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Loximuthal"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
+    SV *sv = get_sv((char*) SWIG_prefix "SRS_PT_QUARTIC_AUTHALIC", TRUE | 0x2 | GV_ADDMULTI);
+    sv_setsv(sv, SWIG_FromCharPtr("Quartic_Authalic"));
+    SvREADONLY_on(sv);
+  } while(0) /*@SWIG@*/;
+  /*@SWIG:/usr/share/swig2.0/perl5/perltypemaps.swg,65,%set_constant@*/ do {
     SV *sv = get_sv((char*) SWIG_prefix "SRS_PP_CENTRAL_MERIDIAN", TRUE | 0x2 | GV_ADDMULTI);
     sv_setsv(sv, SWIG_FromCharPtr("central_meridian"));
     SvREADONLY_on(sv);
diff --git a/swig/perl/parse-for-doxygen.pl b/swig/perl/parse-for-doxygen.pl
new file mode 100644
index 0000000..dc57517
--- /dev/null
+++ b/swig/perl/parse-for-doxygen.pl
@@ -0,0 +1,297 @@
+my @pm = qw(lib/Geo/GDAL.pm lib/Geo/OGR.pm lib/Geo/OSR.pm lib/Geo/GDAL/Const.pm);
+
+my %internal_methods = map {$_=>1} qw/TIEHASH CLEAR FIRSTKEY NEXTKEY FETCH STORE 
+                                      DESTROY DISOWN ACQUIRE RELEASE_PARENTS
+                                      UseExceptions DontUseExceptions this AllRegister RegisterAll
+                                      callback_d_cp_vp/;
+my %private_methods = map {$_=>1} qw/PushErrorHandler PopErrorHandler Error ErrorReset 
+                                     GetLastErrorNo GetLastErrorType GetLastErrorMsg/;
+my %constant_prefixes = map {$_=>1} qw/DCAP_/;
+
+my %package;
+my $package;
+my $sub;
+my $attr;
+for my $pm (@pm) {
+    open(my $fh, "<", $pm) or die "cannot open < $pm: $!";
+    while (<$fh>) {
+        chomp;
+        my $code = $_;
+        s/^\s+//;
+        next if $_ eq '';
+        next if $_ =~ /^#####/; # skip swig comments
+        my($w) = /^(\S+)\s/;
+        if ($w eq 'package') {
+            $package = $_;
+            $package =~ s/^(\S+)\s+//;
+            $package =~ s/;.*//;
+            $sub = '';
+            $attr = '';
+            next;
+        }
+        if ($w eq 'sub') {
+            $sub = $_;
+            $sub =~ s/^(\S+)\s+//;
+            $sub =~ s/\W.*//;
+            $package{$package}{subs}{$sub} = 1;
+            $attr = '';
+            next;
+        }
+        if ($w =~ /^\*/) {
+            $sub = $w;
+            $sub =~ s/^\*//;
+            $sub =~ s/\W.*//;
+            $package{$package}{subs}{$sub} = 1;
+            $attr = '';
+            next;
+        }
+        if (!$sub and $w =~ /^[\$@\%]/ and /=/) {
+            $attr = $w;
+            $attr =~ s/^[\$@\%]//;
+            $attr =~ s/\W.*//;
+            #print "attr: $attr\n";
+            $package{$package}{attr}{$attr} = 1;
+            $sub = '';
+        }
+        if (/use base/) {
+            #print "$_\n";
+        }
+        if (/\@ISA/ and /=/) {
+            my $isa = $_;
+            $isa =~ s/\@ISA//;
+            $isa =~ s/=//;
+            $isa =~ s/qw//;
+            $isa =~ s/\(//;
+            $isa =~ s/\)//;
+            $isa =~ s/;//;
+            @isa = split /\s+/, $isa;
+            for my $isa (@isa) {
+                next if $isa eq '';
+                push @{$package{$package}{isas}}, $isa;
+            }
+        }
+        #print "sub=$sub, $_\n";
+        if ($sub) {
+            push @{$package{$package}{code}{$sub}}, $code;
+            next;
+        }
+        if ($attr) {
+            push @{$package{$package}{code}{$attr}}, $code;
+            $attr = '' if /;/;
+            next;
+        }
+    }
+    close $fh;
+}
+
+my @dox = qw(lib/Geo/GDAL.dox lib/Geo/OGR.dox lib/Geo/OSR.dox);
+
+my $package;
+my $sub;
+my $attr;
+for my $dox (@dox) {
+    open(my $fh, "<", $dox) or die "cannot open < $dox: $!";
+    while (<$fh>) {
+        chomp;
+        next if $_ eq '';
+        s/^[\s#]+//;
+        #next if $_ eq '';
+        ($w) = /^(\S+)\s/;
+        if ($w eq '@class') {
+            $package = $_;
+            $package =~ s/^(\S+)\s+//;
+            $attr = '';
+            $sub = '';
+            next;
+        }
+        if ($w eq '@isa') {
+            next;
+        }
+        if ($w eq '@ignore') {
+            $sub = $_;
+            $sub =~ s/^(\S+)\s+//;
+            #delete $package{$package}{subs}{$sub};
+            $package{$package}{dox}{$sub}{d} = $sub;
+            $package{$package}{dox}{$sub}{at} = $w;
+            $package{$package}{dox}{$sub}{ignore} = 1;
+            next;
+        }
+        if ($w eq '@cmethod' or $w eq '@method') {
+            $sub = $_;
+            $sub =~ s/^(\S+)\s+//;
+            $d = $sub;
+            if (/(\w+)\(/) {
+                $sub = $1;
+            } elsif (/(\w+)$/) {
+                $sub = $1;
+            } else {
+                print STDERR "sub?: $_\n";
+            }
+            $package{$package}{dox}{$sub}{d} = $d;
+            $package{$package}{dox}{$sub}{at} = $w;
+            $attr = '';
+            next;
+        }
+        if ($w eq '@attr') {
+            $attr = $_;
+            $attr =~ s/^(\S+)\s+//;
+            $attr =~ s/\s*list\s+/@/;
+            $attr = '$'.$attr unless $attr =~ /^@/;;
+            $d = $attr;
+            $attr =~ s/@//;
+            #print "attr: '$d'\n";
+            $package{$package}{attrs}{$attr} = 1;
+            $package{$package}{dox}{$attr}{d} = $d;
+            $sub = '';
+            next;
+        }
+        if ($sub) {
+            push @{$package{$package}{dox}{$sub}{c}}, $_;
+            next;
+        }
+        if ($attr) {
+            push @{$package{$package}{dox}{$attr}{c}}, $_;
+            next;
+        }
+        if ($package) {
+            push @{$package{$package}{package_dox}}, $_;
+            next;
+        }
+    }
+    close $fh;
+}
+
+#use Data::Dumper;
+#print Dumper(%package);
+#exit;
+
+for my $package (sort keys %package) {
+    next if $package eq '';
+    next if $package eq 'Geo::GDAL::Const';
+    print "#** \@class $package\n";
+    for my $l (@{$package{$package}{package_dox}}) {
+        print "# $l\n";
+    }
+    print "#*\n";
+    print "package $package;\n\n";
+
+    print "use base qw(",join(' ', @{$package{$package}{isas}}),")\n\n";
+
+    for my $attr (sort keys %{$package{$package}{attrs}}) {
+        next if $package{$package}{dox}{$attr}{ignore};
+        my $d = $package{$package}{dox}{$attr}{d};
+        $d = $attr unless $d;
+        print "#** \@attr $d \n";
+        for my $c (@{$package{$package}{dox}{$attr}{c}}) {
+            print "# $c\n";
+        }
+        print "#*\n";
+        for my $l (@{$package{$package}{code}{$attr}}) {
+            print "$l\n";
+        }
+        print "\n";
+    }
+
+    for my $sub (sort keys %{$package{$package}{subs}}) {
+        next if $package{$package}{dox}{$sub}{ignore};
+        next if $sub =~ /^_/; # no use showing these
+        next if $sub =~ /swig_/; # skip attribute setters and getters
+        next if $sub =~ /GDAL_GCP_/; # skip GDAL::GCP class methods from class GDAL
+
+        next if $sub =~ /GT_/; # done in methods geometry type test and modify
+
+        # processed constants (Const.pm is not given to Doxygen at all)
+        # to do: GF_, GRIORA_, GPI_, OF_, DMD_, CPLES_, GMF_, GARIO_, GTO_
+        # OLMD_
+        # SRS_PM_, SRS_WGS84_
+        next if $sub =~ /^wkb/;
+        next if $sub =~ /^OFT/;
+        next if $sub =~ /^OFST/;
+        next if $sub =~ /^OJ/;
+        next if $sub =~ /^ALTER_/;
+        next if $sub =~ /^F_/;
+        next if $sub =~ /^OLC/;
+        next if $sub =~ /^ODsC/;
+        next if $sub =~ /^ODrC/;
+        next if $sub =~ /^SRS_PT_/;
+        next if $sub =~ /^SRS_PP_/;
+        next if $sub =~ /^SRS_UL_/;
+        next if $sub =~ /^SRS_UA_/;
+        next if $sub =~ /^SRS_DN_/;
+        
+        next if $internal_methods{$sub}; # skip internal methods
+
+        my $d = $package{$package}{dox}{$sub}{d};
+        my $nxt = 0;
+        for my $prefix (keys %constant_prefixes) {
+            $nxt = 1 if $sub =~ /^$prefix/;
+        }
+        next if $nxt;
+        $d = $sub unless $d;
+        $d =~ s/^\$/scalar /;
+        $d =~ s/^\\\$/scalar reference /;
+        $d =~ s/^\@/list /;
+        $d =~ s/^\\\@/array reference /;
+        $d =~ s/^\%/hash /;
+        $d =~ s/^\\\%/hash reference /;
+        $dp = $d;
+        $dp .= '()' unless $dp =~ /\(/;
+        print "#** \@method $dp\n";
+        if ($private_methods{$d} or $package{$package}{dox}{$sub}{at} eq '@ignore') {
+            print "# Undocumented method, do not call unless you know what you're doing.\n";
+            print "# \@todo Test and document this method.\n";
+        }
+        if ($package{$package}{dox}{$sub}{at} eq '@cmethod') {
+            print "# Class method.\n";
+        }
+        for my $c (@{$package{$package}{dox}{$sub}{c}}) {
+            if ($c =~ /^\+list/) {
+                $c =~ s/\+list //;
+                my($pkg, $prefix, $exclude) = split / /, $c;
+                #print STDERR "$pkg, $prefix, $exclude\n";
+                my %exclude = map {$_=>1} split /,/, $exclude;
+                print "# ";
+                my @list;
+                for my $l (sort keys %{$package{$pkg}{subs}}) {
+                    next unless $l =~ /^$prefix/;
+                    $l =~ s/^$prefix//;
+                    next if $exclude{$l};
+                    #print STDERR "  $l\n";
+                    push @list, $l;
+                }
+                my $last = pop @list;
+                print join(', ', @list),", and $last.\n";
+            } else {
+                print "# $c\n";
+            }
+        }
+        print "#*\n";
+        print "sub $sub {\n";
+        my $code = $package{$package}{code}{$sub};
+        fix_indentation($code);
+        pop @$code if $code->[$#$code] =~ /^\s*}\s*$/; # remove duplicate ending } of the sub
+        for my $l (@$code) {
+            print "$l\n";
+        }
+        print "}\n\n";
+    }
+}
+
+sub fix_indentation {
+    my $code = shift;
+    my($space) = $code->[0] =~ /^(\s*)/;
+    my $l = length($space);
+    if ($l < 4) {
+        for (@$code) {
+            for my $i ($l..4) {
+                $_ = ' '.$_;
+            }
+        }
+    } elsif ($l > 4) {
+        for (@$code) {
+            for my $i (4..$l) {
+                $_ =~ s/^ //;
+            }
+        }
+    } 
+}
diff --git a/swig/perl/t/00.t b/swig/perl/t/00.t
new file mode 100644
index 0000000..81539fa
--- /dev/null
+++ b/swig/perl/t/00.t
@@ -0,0 +1,200 @@
+use strict;
+use Test::More qw(no_plan);
+BEGIN { use_ok('Geo::GDAL') };
+
+# Documented subs in Geo::GDAL 
+
+my $binary = Geo::GDAL::CPLHexToBinary('ab10');
+my $hex = Geo::GDAL::CPLBinaryToHex($binary);
+ok($hex eq 'AB10', "CPLHexToBinary and CPLBinaryToHex, got $hex");
+
+my $dms = Geo::GDAL::DecToDMS(62, 'Long');
+ok($dms eq " 62d 0' 0.00\"E", "DecToDMS, got '$dms'"),
+$dms = Geo::GDAL::DecToPackedDMS(62.15);
+my $dec = Geo::GDAL::PackedDMSToDec($dms);
+ok($dec == 62.15, "DecToPackedDMS and PackedDMSToDec, got $dec");
+
+my $s = Geo::GDAL::EscapeString("abc");
+ok($s eq 'abc', "EscapeString, got $s");
+
+Geo::GDAL::SetConfigOption('foo', 'bar');
+$s = Geo::GDAL::GetConfigOption('foo');
+ok($s eq 'bar', "SetConfigOption and GetConfigOption, got $s");
+
+Geo::GDAL::SetCacheMax(1000000);
+$s = Geo::GDAL::GetCacheMax();
+ok($s == 1000000, "SetCacheMax and GetCacheMax, got $s");
+$s = Geo::GDAL::GetCacheUsed();
+ok($s == 0, "GetCacheUsed, got $s");
+
+eval {
+    Geo::GDAL::PushFinderLocation('abc');
+    Geo::GDAL::PopFinderLocation();
+    Geo::GDAL::FinderClean();
+};
+ok($@ eq '', "FinderClean, PushFinderLocation and PopFinderLocation, got $@");
+
+$s = Geo::GDAL::FindFile('', 'gcs.csv');
+ok($s, "FindFile, got $s");
+
+my @list;
+
+eval {
+    @list = Geo::GDAL::AccessTypes();
+};
+ok((@list > 0 and $@ eq ''), "AccessTypes, got $@");
+
+eval {
+    @list = Geo::GDAL::DataTypes();
+};
+ok((@list > 0 and $@ eq ''), "DataTypes, got $@");
+
+eval {
+    @list = Geo::GDAL::GetDriverNames();
+};
+ok((@list > 0 and $@ eq ''), "GetDriverNames, got $@");
+
+eval {
+    @list = Geo::GDAL::NodeTypes();
+};
+ok((@list > 0 and $@ eq ''), "NodeTypes, got $@");
+
+eval {
+    @list = Geo::GDAL::RIOResamplingTypes();
+};
+ok((@list > 0 and $@ eq ''), "RIOResamplingTypes, got $@");
+
+eval {
+    @list = Geo::GDAL::ResamplingTypes();
+};
+ok((@list > 0 and $@ eq ''), "ResamplingTypes, got $@");
+
+for my $type (Geo::GDAL::DataTypes()) {
+    my $nr = $Geo::GDAL::TYPE_STRING2INT{$type};
+    my $c = Geo::GDAL::GetDataTypeName($nr);
+    ok($type eq $c, "Data type $type");
+    eval {
+        my $scalar = Geo::GDAL::DataTypeIsComplex($type);
+        @list = Geo::GDAL::DataTypeValueRange($type);
+        $scalar = Geo::GDAL::GetDataTypeSize($type);
+        $scalar = Geo::GDAL::PackCharacter($type);
+    };
+    ok(($@ eq '' and ($type eq 'Unknown' or @list == 2)), 
+       "$type: DataTypeIsComplex, DataTypeValueRange, GetDataTypeSize, PackCharacter, got $@ and ".scalar(@list));
+}
+
+for my $name (Geo::GDAL::GetDriverNames()) {
+    my $driver;
+    eval {
+        $driver = Geo::GDAL::GetDriver($name);
+    };
+    ok($driver, "$name: GetDriver");
+}
+
+
+my $xml = '<PAMDataset><Metadata><MDI key="PyramidResamplingType">NEAREST</MDI></Metadata></PAMDataset>';
+
+my $a = Geo::GDAL::ParseXMLString($xml);
+my @elements;
+traverse($a);
+ok((@elements == 6 and $elements[5][0] eq 'Text' and $elements[5][1] eq 'NEAREST'), 
+   "XML parsing and traversing");
+
+sub traverse {
+    my $node = shift;
+    my $type = $node->[0];
+    my $data = $node->[1];
+    $type = Geo::GDAL::NodeType($type);
+    push @elements, [$type, $data];
+    for my $child (@$node[2..$#$node]) {
+        traverse($child);
+    }
+}
+
+my $xml2 = Geo::GDAL::SerializeXMLTree($a);
+$xml2 =~ s/\s//g;
+$xml2 =~ s/key/ key/g;
+ok($xml2 eq $xml, "SerializeXMLTree, got $xml2");
+
+my $VersionInfo = Geo::GDAL::VersionInfo('VERSION_NUM');
+ok($VersionInfo, "VersionInfo, got $VersionInfo");
+
+my $dataset = Geo::GDAL::Driver('MEM')->Create();
+my $transform = Geo::GDAL::GeoTransform->new;
+$dataset->GeoTransform($transform);
+$transform = $dataset->GeoTransform();
+
+$dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff');
+my @list = $dataset->GetFileList();
+undef $dataset;
+
+ at list = Geo::GDAL::VSIF::ReadDir('/vsimem/');
+print "@list\n";
+my $driver = Geo::GDAL::IdentifyDriver('/vsimem/test.gtiff');
+print $driver->Name,"\n";
+
+
+$dataset = Geo::GDAL::Open('/vsimem/test.gtiff', 'ReadOnly');
+print "$dataset\n";
+undef $dataset;
+
+$dataset = Geo::GDAL::OpenShared('/vsimem/test.gtiff', 'ReadOnly');
+print "$dataset\n";
+$dataset = Geo::GDAL::OpenEx('/vsimem/test.gtiff');
+print "$dataset\n";
+
+
+__END__
+
+# Classes
+
+AsyncReader
+Band
+ColorTable
+Dataset
+Driver
+GCP
+GeoTransform
+MajorObject
+RasterAttributeTable
+Transformer
+VSIF
+
+__END__
+ 
+public method 	Debug ()
+ 
+public method 	GOA2GetAccessToken ()
+public method 	GOA2GetAuthorizationURL ()
+public method 	GOA2GetRefreshToken ()
+
+public method 	GetJPEG2000StructureAsString ()
+
+Algorithms:
+
+my $src_srs = Geo::OSR::SpatialReference->new(EPSG => 2392);
+my $dst_srs = Geo::OSR::SpatialReference->new(EPSG => 2393);
+my $ResampleAlg = 'NearestNeighbour';
+my $maxerror = 0.0;
+my $dataset = Geo::GDAL::AutoCreateWarpedVRT($src, $src_srs, $dst_srs, $ResampleAlg, $maxerror);
+
+public method 	DitherRGB2PCT (scalar red, scalar green, scalar blue, scalar target, scalar colors, subref callback, scalar callback_data)
+ 
+public method 	ComputeMedianCutPCT (Geo::GDAL::Band red, Geo::GDAL::Band green, Geo::GDAL::Band blue, scalar num_colors, scalar colors, subref callback, scalar callback_data)
+ 
+public method 	ComputeProximity (Geo::GDAL::Band src, Geo::GDAL::Band proximity, hashref options, subref callback, scalar callback_data)
+
+public method 	Polygonize (Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::OGR::Layer out, scalar PixValField, hashref options, subref callback, scalar callback_data)
+ 
+public method 	RasterizeLayer (Geo::GDAL::Dataset ds, arrayref bands, Geo::OGR::Layer layer, scalar transformer, scalar arg, arrayref burn_values, hashref options, subref callback, scalar callback_data)
+ 
+public method 	RegenerateOverview (Geo::GDAL::Band src, Geo::GDAL::Band overview, scalar resampling, subref callback, scalar callback_data)
+ 
+public method 	RegenerateOverviews (Geo::GDAL::Band src, arrayref overviews, scalar resampling, subref callback, scalar callback_data)
+ 
+public method 	ReprojectImage (scalar src_ds, scalar dst_ds, scalar src_wkt=undef, scalar dst_wkt=undef, scalar ResampleAlg='NearestNeighbour', scalar WarpMemoryLimit=0, scalar maxerror=0.0, subref callback, scalar callback_data)
+ 
+public method 	SieveFilter (Geo::GDAL::Band src, Geo::GDAL::Band mask, Geo::GDAL::Band dst, scalar threshold, scalar connectedness, hashref options, subref callback, scalar callback_data)
+ 
+
+ 
diff --git a/swig/perl/t/01.t b/swig/perl/t/01.t
new file mode 100644
index 0000000..cdd8550
--- /dev/null
+++ b/swig/perl/t/01.t
@@ -0,0 +1,77 @@
+use strict;
+use Test::More qw(no_plan);
+BEGIN { use_ok('Geo::GDAL') };
+
+# Create and open dataset
+
+my $dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff', Width => 123, Height => 45);
+ok($dataset, "Create a geotiff into vsimem");
+my @list = $dataset->GetFileList();
+ok($list[0] eq '/vsimem/test.gtiff', "GetFileList");
+undef $dataset;
+
+ at list = Geo::GDAL::VSIF::ReadDir('/vsimem/');
+ok($list[0] eq 'test.gtiff', "ReadDir");
+
+my $driver = Geo::GDAL::IdentifyDriver('/vsimem/test.gtiff');
+ok($driver->Name eq Geo::GDAL::Driver('GTiff')->Name, "IdentifyDriver");
+
+$dataset = Geo::GDAL::Open('/vsimem/test.gtiff', 'ReadOnly');
+ok($dataset, "Open");
+
+$dataset = Geo::GDAL::OpenShared('/vsimem/test.gtiff', 'ReadOnly');
+ok($dataset, "OpenShared");
+
+$dataset = Geo::GDAL::OpenEx('/vsimem/test.gtiff');
+ok($dataset, "OpenEx");
+
+# Geo::GDAL::Driver 
+
+my %cap = map {$_=>1} Geo::GDAL::Driver::Capabilities;
+my @cap = Geo::GDAL::Driver('GTiff')->Capabilities;
+for my $cap (@cap) {
+    ok($cap{$cap}, "Capability $cap");
+    my $t = Geo::GDAL::Driver('GTiff')->TestCapability($cap);
+    ok($t, "Test capability $cap");
+}
+
+my $dataset2 = Geo::GDAL::Driver('MEM')->Copy('', $dataset);
+my @size1 = $dataset->Size;
+my @size2 = $dataset2->Size;
+is_deeply(\@size1, \@size2, "Size, Copy, got @size1 and @size2");
+
+$dataset->GetDriver->CopyFiles('/vsimem/new.gtiff', '/vsimem/test.gtiff');
+my %files = map {$_=>1} Geo::GDAL::VSIF::ReadDir('/vsimem/');
+ok(($files{'new.gtiff'} and $files{'test.gtiff'}), "CopyFiles");
+
+my %dt = map {$_=>1} Geo::GDAL::DataTypes();
+for my $dt (Geo::GDAL::Driver('GTiff')->CreationDataTypes()) {
+    ok($dt{$dt}, "CreationDataTypes: $dt");
+}
+
+for my $co (Geo::GDAL::Driver('GTiff')->CreationOptionList()) {
+    ok(ref($co) eq 'HASH', "Creation option");
+    ok(ref($co->{Value}) eq 'ARRAY', "Value in creation option") if $co->{Value};
+    #use Data::Dumper;
+    #print Dumper $co;
+}
+
+$dataset->GetDriver->Delete('/vsimem/new.gtiff');
+ at list = Geo::GDAL::VSIF::ReadDir('/vsimem/');
+ok((@list == 1 and $list[0] eq 'test.gtiff'), "Delete");
+
+%dt = map {$_=>1} Geo::GDAL::Driver::Domains();
+for my $dt (Geo::GDAL::Driver('GTiff')->Domains()) {
+    ok($dt{$dt}, "Driver domain: $dt");
+}
+
+my $ext = Geo::GDAL::Driver('GTiff')->Extension;
+ok($ext eq 'tif', "Extension, got $ext");
+
+$ext = Geo::GDAL::Driver('GTiff')->MIMEType;
+ok($ext eq 'image/tiff', "MIMEType, got $ext");
+
+$dataset->GetDriver->CopyFiles('/vsimem/new.gtiff', '/vsimem/test.gtiff');
+$dataset->GetDriver->Rename('/vsimem/new2.gtiff', '/vsimem/new.gtiff');
+my %files = map {$_=>1} Geo::GDAL::VSIF::ReadDir('/vsimem/');
+ok(($files{'new2.gtiff'} and $files{'test.gtiff'}), "Rename");
diff --git a/swig/perl/t/02.t b/swig/perl/t/02.t
new file mode 100644
index 0000000..953c5b6
--- /dev/null
+++ b/swig/perl/t/02.t
@@ -0,0 +1,71 @@
+use strict;
+use Test::More qw(no_plan);
+BEGIN { use_ok('Geo::GDAL') };
+
+# Geo::GDAL::Dataset
+
+my %dt = map {$_=>1} Geo::GDAL::Dataset::Domains();
+for my $dt (Geo::GDAL::Driver('MEM')->Create->Domains()) {
+    ok($dt{$dt}, "Dataset domain: $dt");
+}
+
+my $dataset = Geo::GDAL::Driver('MEM')->Create(Width => 8, Height => 10);
+my $band = $dataset->Band;
+my $band2 = $dataset->Band(1);
+my @bands = $dataset->Bands;
+ok(@bands == 1, "Bands");
+
+my @list = Geo::GDAL::DataTypes();
+#print "@list\n";
+$dataset->AddBand('Int32', {a => 1});
+ at bands = $dataset->Bands;
+ok(@bands == 2, "AddBand");
+my $dt = $dataset->Band(2)->DataType;
+ok($dt eq 'Int32', "DataType");
+
+my $transform = Geo::GDAL::GeoTransform->new(1,2,3,4,5,6);
+$dataset->GeoTransform($transform);
+$transform = $dataset->GeoTransform();
+is_deeply($transform, [1,2,3,4,5,6], "GeoTransform");
+
+$transform = Geo::GDAL::GeoTransform->new;
+$dataset->GeoTransform($transform);
+
+ at list = Geo::GDAL::RIOResamplingTypes();
+#print "@list\n";
+
+my $buf = $dataset->ReadRaster(0, 0, 8, 10, 8, 10, undef, [1,2]);
+my $pc = Geo::GDAL::PackCharacter('Byte');
+my @data = unpack("$pc*", $buf);
+my $n = @data;
+ok($n == 160, "ReadRaster");
+
+$data[80] = 1;
+$data[159] = 2;
+$buf = pack("$pc*", @data[80..159]);
+$dataset->WriteRaster(XOff => 0, yoff => 0, buf => $buf, BandList => [1]);
+my $data = $dataset->Band(1)->ReadTile;
+ok(($data->[0][0] == 1 and $data->[9][7] == 2), "WriteRaster ReadTile");
+
+$data->[5][5] = 3;
+$dataset->Band(1)->WriteTile($data);
+$data = $dataset->Band(1)->ReadTile;
+ok($data->[5][5] == 3, "WriteTile");
+#for my $row (@$data) {
+#    print "@$row\n";
+#}
+
+__END__
+
+tests to do
+
+CreateMaskBand
+
+GCPs
+GetGCPProjection
+
+SpatialReference
+
+StartTransaction
+CommitTransaction
+RollbackTransaction
diff --git a/swig/perl/t/03.t b/swig/perl/t/03.t
new file mode 100644
index 0000000..edede79
--- /dev/null
+++ b/swig/perl/t/03.t
@@ -0,0 +1,247 @@
+use strict;
+use Scalar::Util 'blessed';
+use Test::More qw(no_plan);
+BEGIN { use_ok('Geo::GDAL') };
+
+# Geo::GDAL::Band
+
+my $dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff', Width => 4, Height => 6);
+my $band = $dataset->Band;
+
+$band->CategoryNames('a','b');
+my @list = $band->CategoryNames;
+ok(($list[0] eq 'a' and $list[1] eq 'b'), "CategoryNames");
+
+ at list = $band->GetBlockSize;
+ok(($list[0] == 4 and $list[1] == 6), "GetBlockSize");
+
+ at list = $band->Size;
+ok(($list[0] == 4 and $list[1] == 6), "Size");
+
+my $ds = $band->GetDataset;
+ok((defined($ds) and blessed($ds) and $ds->isa('Geo::GDAL::Dataset')), "GetDataset");
+
+$band->Unit('metri');
+$ds = $band->Unit();
+ok($ds eq 'metri', "Unit");
+
+$band->ScaleAndOffset(0.1, 5);
+ at list = $band->ScaleAndOffset();
+ok(($list[0] == 0.1 and $list[1] == 5), "ScaleAndOffset");
+
+my $nr = $band->GetBandNumber;
+ok($nr == 1, "GetBandNumber");
+
+my $rat = Geo::GDAL::RasterAttributeTable->new;
+$band->AttributeTable($rat);
+$rat = $band->AttributeTable();
+ok((defined($rat) and blessed($rat) and $rat->isa('Geo::GDAL::RasterAttributeTable')), "RasterAttributeTable");
+
+my $c = $band->ColorInterpretation;
+my %c = map {$_=>1} Geo::GDAL::Band::ColorInterpretations;
+ok($c{$c}, "Get ColorInterpretation");
+$c = (keys %c)[0];
+$band->ColorInterpretation($c);
+ok($band->ColorInterpretation eq $c, "Set ColorInterpretation");
+
+ at list = $band->Domains;
+ok(@list > 1, "Domains");
+
+$c = Geo::GDAL::ColorTable->new;
+$c->ColorEntry(0, 100, 50, 150, 300);
+ at list = $c->ColorTable;
+ok($list[0][0] == 100, "Colortable");
+$band->SetColorTable($c);
+$c = $band->GetColorTable();
+ok((defined($c) and blessed($c) and $c->isa('Geo::GDAL::ColorTable')), "Get ColorTable");
+ at list = $c->ColorTable;
+ok($list[0][0] == 100, "Set and Get Colortable");
+
+$dataset = Geo::GDAL::Driver('MEM')->Create(Width => 4, Height => 4);
+$dataset->AddBand('Int32');
+$band = $dataset->Band(2);
+$band->	Fill(123);
+my $data = $band->ReadTile;
+ok($data->[0][0] == 123, "Fill with integer");
+for my $row (@$data) {
+#    print "@$row\n";
+}
+$dataset->AddBand('Float64');
+$band = $dataset->Band(3);
+$band->	Fill(123.45);
+$data = $band->ReadTile;
+ok($data->[0][0] == 123.45, "Fill with real");
+for my $row (@$data) {
+#    print "@$row\n";
+}
+#$dataset->AddBand('CFloat64');
+#$band = $dataset->Band(4);
+#$band->Fill(123.45, 10);
+#$data = $band->ReadTile;
+#for my $row (@$data) {
+#    print "@$row\n";
+#}
+
+#use Statistics::Descriptive;
+#my $stat = Statistics::Descriptive::Full->new();      
+$band = $dataset->Band(3);
+for my $y (0..3) {
+    for my $x (0..3) {
+        $data->[$y][$x] = rand 10;
+        #$stat->add_data($data->[$y][$x]);
+    }
+}
+$band->WriteTile($data);
+for my $row (@$data) {
+    #print "@$row\n";
+}
+
+my $x;
+my ($min, $max, $mean, $stddev);
+
+#print $stat->mean()," ",$stat->standard_deviation(),"\n";
+
+ at list = $band->ComputeRasterMinMax;
+ok(@list == 2, "ComputeRasterMinMax");
+
+$x = $band->GetMinimum;
+ok(!defined($x), "GetMinimum");
+ at list = $band->GetMinimum;
+ok(@list == 2, "GetMinimum");
+
+$x = $band->GetMaximum;
+ok(!defined($x), "GetMaximum");
+ at list = $band->GetMaximum;
+ok(@list == 2, "GetMaximum");
+
+ at list = $band->ComputeBandStats;
+ok(@list == 2, "ComputeBandStats");
+
+$band->ComputeStatistics(1);
+$x = $band->GetMaximum;
+ok(defined($x), "GetMaximum");
+
+ at list = $band->GetStatistics(1,0);
+ok(@list == 4, "GetStatistics");
+
+$band->SetStatistics(0, 1, 2, 3);
+ at list = $band->GetStatistics(0,0);
+ok($list[3] == 3, "SetStatistics");
+
+ at list = $band->ComputeBandStats;
+ok(@list == 2, "ComputeBandStats");
+
+my $foo;
+my $n = 0;
+ at list = $band->ComputeStatistics(0, sub {$foo = $_[2] unless $foo; $n++; 1}, 'foo'); 
+ok(@list == 4, "ComputeStatistics");
+ok(($n > 0 and $foo eq 'foo'), "ComputeStatistics callback");
+
+Geo::GDAL::VSIF::Unlink('/vsimem/test.gtiff');
+$dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff', Width => 4, Height => 6);
+$band = $dataset->Band;
+$c = $band->Checksum;
+ok($c == 0, "Checksum");
+
+$c = $band->NoDataValue;
+ok(!defined($c), "Get NoDataValue");
+$band->NoDataValue(10);
+$c = $band->NoDataValue;
+ok($c == 10, "Set NoDataValue");
+
+# set one pixel no data
+$data = $band->ReadTile;
+$data->[2][2] = 10;
+$band->WriteTile($data);
+
+my @f = $band->MaskFlags;
+ok(@f > 0, "MaskFlags");
+
+ at f = $band->GetMaskFlags;
+ok($f[0] eq 'NoData', "GetMaskFlags");
+
+# fill the one pixel
+$band->FillNodata();
+$data = $band->ReadTile;
+ok($data->[2][2] == 0, "FillNodata, got $data->[2][2]");
+
+$band->CreateMaskBand('PerDataset');
+ at f = $band->GetMaskFlags;
+ok($f[0] eq 'PerDataset', "CreateMaskBand");
+
+#@list = Geo::GDAL::VSIF::ReadDir('/vsimem/');
+#print "files @list\n"; # includes .msk
+
+# $m is not valid here any more, how to test?
+
+Geo::GDAL::VSIF::Unlink('/vsimem/test.gtiff');
+$dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff', Bands => 2);
+$dataset->BuildOverviews('average', [2,4]);
+
+my $band1 = $dataset->Band(1);
+my $band2 = $dataset->Band(2);
+
+$band1->RegenerateOverviews([$band2]); #scalar resampling, subref callback, scalar callback_data
+$band1->RegenerateOverview($band2); #scalar resampling, subref callback, scalar callback_data
+
+my $c = $band1->GetOverviewCount;
+ok($c == 2, "GetOverviewCount, got $c");
+my $o = $band1->GetOverview(1);
+ok(defined($o), "GetOverview");
+my $b = $band1->HasArbitraryOverviews;
+ok(!$b, "HasArbitraryOverviews");
+
+Geo::GDAL::VSIF::Unlink('/vsimem/test.gtiff');
+$dataset = Geo::GDAL::Driver('GTiff')->Create(Name => '/vsimem/test.gtiff', Type => 'Float64');
+$band = $dataset->Band;
+
+my $data = $band->ReadTile;
+my ($min, $max);
+for my $y (0..@$data-1) {
+    for my $x (0..@{$data->[$y]}-1) {
+        $data->[$y][$x] = rand 10;
+        if (defined $min) {
+            $min = $data->[$y][$x] if $data->[$y][$x] < $min;
+        } else {
+            $min = $data->[$y][$x];
+        }
+        if (defined $max) {
+            $max = $data->[$y][$x] if $data->[$y][$x] > $max;
+        } else {
+            $max = $data->[$y][$x];
+        }
+    }
+}
+$band->WriteTile($data);
+
+my $h = $band->GetHistogram(Max => 10.0, Buckets => 11);
+my $sum = 0;
+for (@$h) {
+    $sum += $_;
+}
+ok($sum == 256*256, "GetHistogram");
+ok(@$h == 11, "GetHistogram");
+my ($min, $max, $histogram) = $band->GetDefaultHistogram;
+ok(ref($histogram) eq 'ARRAY', "GetDefaultHistogram");
+eval {
+    $band->SetDefaultHistogram($min, $max, $histogram);
+};
+ok(!$@, "SetDefaultHistogram");
+
+my $buf = $band->ReadRaster();
+my $pc = $band->PackCharacter;
+my @data = unpack("$pc*", $buf);
+my $n = @data;
+ok($n == 256*256, "ReadRaster");
+
+$buf = pack("$pc*", @data);
+eval {
+    $band->WriteRaster(XOff => 0, yoff => 0, buf => $buf);
+};
+ok(!$@, "WriteRaster");
+
+__END__
+
+ 
+public Geo::OGR::Layer 	Contours (scalar DataSource, hashref LayerConstructor, scalar ContourInterval, scalar ContourBase, arrayref FixedLevels, scalar NoDataValue, scalar IDField, scalar ElevField, subref callback, scalar callback_data)
+ 
diff --git a/swig/perl/t/gdal.t b/swig/perl/t/gdal.t
index 0322c49..6148084 100644
--- a/swig/perl/t/gdal.t
+++ b/swig/perl/t/gdal.t
@@ -193,40 +193,52 @@ if (0) {
 }
 
 {
+    BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } }
     my $r = Geo::GDAL::RasterAttributeTable->new;
     my @t = $r->FieldTypes;
     my @u = $r->FieldUsages;
+    my %colors = (Red=>1, Green=>1, Blue=>1, Alpha=>1);
+    my @types;
+    my @usages;
     for my $u (@u) {
 	for my $t (@t) {
 	    $r->CreateColumn("$t $u", $t, $u);
+            push @types, $t;
+            push @usages, $u;
 	}
     }
     my $n = $r->GetColumnCount;
     my $n2 = @t * @u;
     ok($n == $n2, "create rat column");
-    $r->SetRowCount(scalar(@t));
+    $r->SetRowCount(1);
     my $i = 0;
-    my $c = 0;
-    for (@t) {
-	if (/Integer/) {
-	    my $v = $r->Value($i, $c, 12);
-	    ok($v == 12, "rat int");
-	} elsif (/Real/) {
-	    my $v = $r->Value($i, $c, 1.23);
-	    ok($v == 1.23, "rat int");
-	} elsif (/String/) {
-	    my $v = $r->Value($i, $c, "abc");
-	    ok($v eq 'abc', "rat str");
-	}
-	$i++;
-	$c++;
+    for my $c (0..$n-1) {
+        my $usage = $r->GetUsageOfCol($c);
+        ok($usage eq $usages[$c], "usage $usage eq $usages[$c]");
+        my $type = $r->GetTypeOfCol($c);
+        if ($colors{$usage}) {
+            ok($type eq 'Integer', "type $type eq 'Integer'");
+        } else {
+            ok($type eq $types[$c], "type $type eq $types[$c]");
+        }
+        for ($type) {
+            if (/Integer/) {
+                my $v = $r->Value($i, $c, 12);
+                ok($v == 12, "rat int ($i,$c): $v vs 12");
+            } elsif (/Real/) {
+                my $v = $r->Value($i, $c, 1.23);
+                ok($v == 1.23, "rat real ($i,$c): $v vs 1.23");
+            } elsif (/String/) {
+                my $v = $r->Value($i, $c, "abc");
+                ok($v eq 'abc', "rat str ($i,$c): $v vs 'abc'");
+            }
+        }
     }
 }
 
 gdal_tests();
 
-$src = Geo::OSR::SpatialReference->new();
-$src->ImportFromEPSG(2392);
+$src = Geo::OSR::SpatialReference->new(EPSG => 2392);
 
 $xml = $src->ExportToXML();
 $a = Geo::GDAL::ParseXMLString($xml);
@@ -236,10 +248,10 @@ ok(is_deeply($a, $b), "xml parsing");
 
 my @tmp = sort keys %available_driver;
 
-print STDERR "\nGDAL version: ",Geo::GDAL::VersionInfo,"\n";
-print STDERR "Unexpected failures:\n", at fails,"\n" if @fails;
-print STDERR "Available drivers were ",join(', ', at tmp),"\n";
-print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
+#print STDERR "\nGDAL version: ",Geo::GDAL::VersionInfo,"\n";
+#print STDERR "Unexpected failures:\n", at fails,"\n" if @fails;
+#print STDERR "Available drivers were ",join(', ', at tmp),"\n";
+#print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
 
 system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 
@@ -291,6 +303,8 @@ sub gdal_tests {
 	    next;
 	}
 
+        next unless $driver->{ShortName} eq 'MEM';
+
 	push @tested_drivers,$name;
 	
 	my $ext = $metadata->{DMD_EXTENSION} ? '.'.$metadata->{DMD_EXTENSION} : '';
@@ -362,8 +376,7 @@ sub gdal_tests {
 		
 	    } else 
 	    {
-		#my $colortable = Geo::GDAL::ColorTable->create('RGB');
-		my $colortable = Geo::GDAL::ColorTable->new($Geo::GDAL::Constc::GPI_Gray);
+		my $colortable = Geo::GDAL::ColorTable->new('Gray');
 		my @rgba = (255,0,0,255);
 		$colortable->SetColorEntry(0, \@rgba);
 		$band->ColorTable($colortable);
@@ -414,10 +427,10 @@ sub gdal_tests {
 		my $c = $dataset->GetGCPCount();
 		my $p = $dataset->GetGCPProjection();
 		my $gcps = $dataset->GetGCPs();
-		my $y1 = $gcps->[0]->{GCPY};
-		my $y2 = $gcps->[1]->{GCPY};
-		my $y1o = $gcps[0]->{GCPY};
-		my $y2o = $gcps[1]->{GCPY};
+		my $y1 = $gcps->[0]->{Y};
+		my $y2 = $gcps->[1]->{Y};
+		my $y1o = $gcps[0]->{Y};
+		my $y2o = $gcps[1]->{Y};
 		mytest(($c == 2 and $p eq $po and $y1 == $y1o and $y2 == $y2o),
 		       "$c != 2 or $p ne $po or $y1 != $y1o or $y2 != $y2o",$name,$type,'Set/GetGCPs');
 	    }
diff --git a/swig/perl/t/ogr.t b/swig/perl/t/ogr.t
index f2e6a7d..513d078 100644
--- a/swig/perl/t/ogr.t
+++ b/swig/perl/t/ogr.t
@@ -44,19 +44,22 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
     my $l = Geo::OGR::Driver('Memory')->Create()->CreateLayer({GeometryType=>'Polygon'});
     eval {
 	# this is an error because the layer is polygon and this is a point
-	$l->InsertFeature([0,{wkt=>'POINT(1 1)'},12.2,3]);
+	$l->InsertFeature([0,12.2,{wkt=>'POINT(1 1)'}]);
     };
     ok($@, 'an error because geometry type mismatch');
 }
 
 {
-    my $l = Geo::OGR::Driver('Memory')->Create()->CreateLayer();
+    our $warning;
+    BEGIN { $SIG{'__WARN__'} = sub { $warning = $_[0] } }
+    my $l = Geo::OGR::Driver('Memory')->Create()->CreateLayer(GeometryType => 'None');
     $l->CreateField(Name => 'value', Type => 'Integer');
-    $l->InsertFeature([0,{wkt=>'POINT(1 1)'},12.2,3]);
+    $l->CreateField(Name => 'geom', GeometryType => 'Point');
+    $l->InsertFeature([0,12.2,{wkt=>'POINT(1 1)'}]);
     my $f = $l->GetFeature(0);
     my $r = $f->Row;
-    ok($r->{Geometry}->AsText eq 'POINT (1 1)', 'The geometry of the inserted feature is ok');
-    ok($r->{value} == 12, "The float is changed to integer because that's the type in the layer");
+    ok($r->{geom}->AsText eq 'POINT (1 1)', 'The geometry of the inserted feature is ok');
+    ok($r->{value} == 12, "The float is changed to integer because that's the type in the layer ($warning)");
     my $n = $f->Tuple;
     ok($n == 3, 'The extra field is scrapped because layer does not have a field for it');
 }
@@ -68,20 +71,20 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 
 {
     # test conversion methods
-    my $g = Geo::OGR::Geometry->create(WKT=>'POINT (1 1)');
-    my $x = Geo::OGR::Geometry->create(WKT=>'POINT (2 2)');
+    my $g = Geo::OGR::Geometry->new(WKT=>'POINT (1 1)');
+    my $x = Geo::OGR::Geometry->new(WKT=>'POINT (2 2)');
     my $g2 = $g->ForceToMultiPoint($x);
     ok($g2->AsText eq 'MULTIPOINT (1 1,2 2)', 'ForceToMultiPoint');
-    $g = Geo::OGR::Geometry->create(WKT=>'LINESTRING (1 1,2 2)');
-    $x = Geo::OGR::Geometry->create(WKT=>'LINESTRING (2 2,3 3)');
+    $g = Geo::OGR::Geometry->new(WKT=>'LINESTRING (1 1,2 2)');
+    $x = Geo::OGR::Geometry->new(WKT=>'LINESTRING (2 2,3 3)');
     $g2 = $g->ForceToMultiLineString($x);
     ok($g2->AsText eq 'MULTILINESTRING ((1 1,2 2),(2 2,3 3))', 'ForceToMultiLineString');
-    $g = Geo::OGR::Geometry->create(WKT=>'POLYGON ((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5))');
-    $x = Geo::OGR::Geometry->create(WKT=>'POLYGON ((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5))');
+    $g = Geo::OGR::Geometry->new(WKT=>'POLYGON ((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5))');
+    $x = Geo::OGR::Geometry->new(WKT=>'POLYGON ((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5))');
     $g2 = $g->ForceToMultiPolygon($x);
     ok($g2->AsText eq 'MULTIPOLYGON (((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5)),((0.49 0.5,0.83 0.5,0.83 0.77,0.49 0.77,0.49 0.5)))', 'ForceToMultiPolygon');
-    $g = Geo::OGR::Geometry->create(WKT=>'POINT (1 1)');
-    $x = Geo::OGR::Geometry->create(WKT=>'LINESTRING (2 2,3 3)');
+    $g = Geo::OGR::Geometry->new(WKT=>'POINT (1 1)');
+    $x = Geo::OGR::Geometry->new(WKT=>'LINESTRING (2 2,3 3)');
     $g2 = $g->ForceToCollection($x);
     ok($g2->AsText eq 'GEOMETRYCOLLECTION (POINT (1 1),LINESTRING (2 2,3 3))', 'ForceToCollection');
     my @g = $g2->Dissolve;
@@ -90,7 +93,7 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 }
 
 {
-    my $g = Geo::OGR::Geometry->create(wkt => "point(1 2)");
+    my $g = Geo::OGR::Geometry->new(wkt => "point(1 2)");
     $g->Point(2,3);
     my @p = $g->Point;
     ok($p[0] == 2, "Point");
@@ -98,29 +101,29 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 	my $wkb = "0102000000050000005555555524F3484100000000A0F05941555555552".
 	    "4F34841000000E09CF05941000000C02EF34841ABAAAAAA97F05941ABAAAA2A39F3".
 	    "4841000000E09CF05941ABAAAA2A39F3484100000000A0F05941";
-	$g = Geo::OGR::Geometry->create(hexwkb => $wkb);
+	$g = Geo::OGR::Geometry->new(hexwkb => $wkb);
     };
-    ok ($@ eq '', "create from WKb: $@");
+    ok ($@ eq '', "new from WKb: $@");
     eval {
 	my $gml = "<gml:Point><gml:coordinates>1,1</gml:coordinates></gml:Point>";
-	$g = Geo::OGR::Geometry->create(gml => $gml);
+	$g = Geo::OGR::Geometry->new(gml => $gml);
     };
-    ok ($@ eq '', "create from GML: $@");
+    ok ($@ eq '', "new from GML: $@");
     eval {
-	$g = Geo::OGR::Geometry->create(GeoJSON => "abc");
+	$g = Geo::OGR::Geometry->new(GeoJSON => "abc");
     };
-    ok ($@ =~ /GeoJSON parsing error/, "create from GeoJSON: $@");
+    ok ($@ =~ /GeoJSON parsing error/, "new from GeoJSON: $@");
 }
 
 {
     # test the Points method
-    my $g = Geo::OGR::Geometry->create( WKT => 'POINT(1.1 2.2)');
+    my $g = Geo::OGR::Geometry->new( WKT => 'POINT(1.1 2.2)');
     my $p = $g->Points;
     ok ($p->[0] == 1.1 && $p->[1] == 2.2, "Points from a point is a simple anonymous array");
     $g->Points($p);
     my $q = $g->Points;
     is_deeply($p, $q, "Points with a point");
-    $g = Geo::OGR::Geometry->create(wkt => "linestring(1 1, 1 2, 2 2)");
+    $g = Geo::OGR::Geometry->new(wkt => "linestring(1 1, 1 2, 2 2)");
     $p = $g->Points;
     ok ($p->[0]->[0] == 1 && $p->[1]->[1] == 2, "Points from a linestring is an anonymous array of points");
     $g->Points($p);
@@ -129,36 +132,38 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 }
 
 {
-    my $g = Geo::OGR::Geometry->create(wkt => "linestring(1 1, 1 2, 2 2)");
+    my $g = Geo::OGR::Geometry->new(wkt => "linestring(1 1, 1 2, 2 2)");
     ok ($g->Length == 2, "Length 1");
 }
 
 {
     # test list valued fields
-    my $d = Geo::OGR::FeatureDefn->new;
-    $d->Schema(Fields=>[
-			{ Name => 'ilist',
-			  Type => 'IntegerList',
-		      },
-			{ Name => 'rlist',
-			  Type => 'RealList',
-		      },
-			{ Name => 'slist',
-			  Type => 'StringList',
-		      },
-			{ Name => 'date',
-			  Type => 'Date',
-		      },
-			{ Name => 'time',
-			  Type => 'Time',
-		      },
-			{ Name => 'datetime',
-			  Type => 'DateTime',
-		      },
-			]
-	       );
+    my $d = Geo::OGR::FeatureDefn->new(
+        Fields=>[
+            { Name => 'ilist',
+              Type => 'IntegerList',
+            },
+            { Name => 'rlist',
+              Type => 'RealList',
+            },
+            { Name => 'slist',
+              Type => 'StringList',
+            },
+            { Name => 'date',
+              Type => 'Date',
+            },
+            { Name => 'time',
+              Type => 'Time',
+            },
+            { Name => 'datetime',
+              Type => 'DateTime',
+            },
+        ]
+        );
     my $f = Geo::OGR::Feature->new($d);
-    ok($f->Schema->{Fields}->[1]->{Index} == 1, "Index in field in schema");
+    #use Data::Dumper;
+    #print Dumper {$f->Schema};
+    ok($f->Schema->{Fields}->[5]->{Name} eq 'datetime', "Name in field in schema");
     $f->Row( ilist => [1,2,3],
 	     rlist => [1.1,2.2,3.3],
 	     slist => ['a','b','c'],
@@ -184,15 +189,15 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 {
     my $g2;
     {
-	my $d = Geo::OGR::FeatureDefn->new;
-	$d->Schema(Fields=>[Geo::OGR::FieldDefn->create(Name=>'Foo')]);
+	my $d = Geo::OGR::FeatureDefn->new(Fields=>[Geo::OGR::FieldDefn->new(Name=>'Foo')]);
+        $d->AddField(Type => 'Point');
 	my $f = Geo::OGR::Feature->new($d);
-	my $g = Geo::OGR::Geometry->create('Point');
+	my $g = Geo::OGR::Geometry->new('Point');
 	$f->SetGeometry($g);
 	my $fd = $f->GetDefnRef;
 	my $s = $fd->Schema;
 	my $s2 = $s->{Fields}[0];
-	ok($s->{GeometryType} eq 'Unknown', 'Feature defn schema 0');
+	ok($s->{Fields}[1]{Type} eq 'Point', 'Feature defn schema 0');
 	ok($s2->{Name} eq 'Foo', 'Feature defn schema 1');
 	ok($s2->{Type} eq 'String', 'Feature defn schema 2');
 	$g2 = $f->GetGeometry;
@@ -200,18 +205,18 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
     $g2->GetDimension; # does not cause a kaboom
 }
 {
-    my $f = Geo::OGR::FieldDefn->create();
+    my $f = Geo::OGR::FieldDefn->new();
     my $s = $f->Schema(Width => 10);
     ok($s->{Width} == 10, 'fieldefn schema 1');
     ok($s->{Type} eq 'String', 'fieldefn schema 2');
 }
 {
     my $driver = Geo::OGR::Driver('Memory');
-    my @cap = $driver->Capabilities;
-    ok(is_deeply(\@cap, ['CreateDataSource']), "driver capabilities");
+    my %cap = map {$_=>1} $driver->Capabilities;
+    ok($cap{CreateDataSource}, "driver capabilities");
     my $datasource = $driver->CreateDataSource('test');
-    @cap = $datasource->Capabilities;
-    ok(is_deeply(\@cap, ['CreateLayer','DeleteLayer']), "data source capabilities");
+    %cap = map {$_=>1} $datasource->Capabilities;
+    ok($cap{CreateLayer} and $cap{DeleteLayer}, "data source capabilities");
     
     my $layer = $datasource->CreateLayer('a', undef, 'Point');
     my %cap = map { $_ => 1 } $layer->Capabilities;
@@ -229,12 +234,13 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
 	ok(is_deeply(\@layers, ['a','c'], "delete layer"));
     }
     
-    $layer = $datasource->CreateLayer('test', undef, 'Point');
-    $layer->Schema(Fields => 
-		   [{Name => 'test1', Type => 'Integer'},
-		    {Name => 'test2', Type => 'String'},
-		    {Name => 'test3', Type => 'Real'}
-		    ], ApproxOK => 1);
+    $layer = $datasource->CreateLayer
+        ( Name => 'test', 
+          GeometryType => 'Point',
+          Fields => [ {Name => 'test1', Type => 'Integer'},
+                      {Name => 'test2', Type => 'String'},
+                      {Name => 'test3', Type => 'Real'} ], 
+          ApproxOK => 1 );
     $layer->InsertFeature({ test1 => 13, 
 			    Geometry => { Points => [1,2,3] } });
     $layer->InsertFeature({ test2 => '31a', 
@@ -243,11 +249,11 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
     my $i = 0;
     while (my $f = $layer->GetNextFeature) {
 	my @a = $f->Tuple;
-	$a[1] = $a[1]->AsText;
+	$a[4] = $a[4]->AsText;
 	my $h = $f->Row;
 	$h->{Geometry} = $h->{Geometry}->AsText;
 	if ($i == 0) {
-	    my @t = (0,'POINT (1 2)',13,undef,undef);
+	    my @t = (0,13,undef,undef,'POINT (1 2)');
 	    ok(is_deeply(\@a, \@t), "layer create test 1");
 	} else {
 	    my %t = (FID => 1, Geometry => 'POINT (3 2)', test1 => undef, test2 => '31a', test3 => undef);
@@ -257,17 +263,14 @@ system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
     }
     $layer->Row(FID=>0, Geometry=>{ Points => [5,6] }, test3 => 6.5);
     my @t = $layer->Tuple(0);
-    ok($t[4] == 6.5, "layer row and tuple");
-    ok($t[1]->ExportToWkt eq 'POINT (5 6)', "layer row and tuple");
+    ok($t[3] == 6.5, "layer row and tuple");
+    ok($t[4]->ExportToWkt eq 'POINT (5 6)', "layer row and tuple");
 }
 
-my $osr = new Geo::OSR::SpatialReference;
-$osr->SetWellKnownGeogCS('WGS84');
+my $osr = Geo::OSR::SpatialReference->new(WGS => 84);
 
 @types = Geo::OGR::GeometryType();
 
-ok(@types == 17, "number of geometry types is 17");
-
 my @tmp = @types;
 @types = ();
 for (@tmp) {
@@ -301,11 +304,11 @@ for my $method (@$methods) {
 
 if (@fails) {
     print STDERR "\nUnexpected failures:\n", at fails;
-    print STDERR "\nAvailable drivers were ",join(', ', at tmp),"\n";
-    print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
+    #print STDERR "\nAvailable drivers were ",join(', ', at tmp),"\n";
+    #print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
 } else {
-    print STDERR "\nAvailable drivers were ",join(', ', at tmp),"\n";
-    print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
+    #print STDERR "\nAvailable drivers were ",join(', ', at tmp),"\n";
+    #print STDERR "Drivers used in tests were: ",join(', ', at tested_drivers),"\n";
 }
 
 system "rm -rf tmp_ds_*" unless $^O eq 'MSWin32';
@@ -355,6 +358,10 @@ sub ogr_tests {
 	    mytest("skipped: can't create layers afterwards.",undef,$name,'datasource create');
 	    next;
 	}
+        if ($name eq 'ESRI Shapefile' or $name eq 'MapInfo File') {
+	    mytest("skipped",undef,$name,'datasource create');
+	    next;
+	}
 
 	push @tested_drivers,$name;
 
@@ -382,20 +389,11 @@ sub ogr_tests {
 	
 	for my $type (@types) {
 	    
-	    if ($name eq 'ESRI Shapefile' and $type eq 'GeometryCollection') {
-		mytest("skipped, will fail",undef,$name,$type,'layer create');
-		next;
-	    }
-	    
-	    if ($type eq 'MultiPolygon') {
+            print "$type\n";
+	    if ($type eq 'MultiPolygon' or $type =~ /Z/) {
 		mytest("skipped, no test yet",undef,$name,$type,'layer create');
 		next;
 	    }
-
-	    if ($name eq 'MapInfo File' and $type eq 'MultiLineString') {
-		mytest("skipped, no test",undef,$name,$type,'layer create');
-		next;
-	    }
 	    
 	    my $layer;
 	    eval {
@@ -409,7 +407,7 @@ sub ogr_tests {
 	    
 	    for my $ft (@field_types) {
 		
-		my $column = Geo::OGR::FieldDefn->create($ft, $ft);
+		my $column = Geo::OGR::FieldDefn->new($ft, $ft);
 		$column->SetWidth(5) if $ft eq 'Integer';
 		$layer->CreateField($column);
 		
@@ -429,14 +427,15 @@ sub ogr_tests {
 		
 		my $feature = new Geo::OGR::Feature($schema);
 		
-		my $t = $type eq 'Unknown' ? 'Polygon' : $type;
+		my $t = $schema->GeometryType;
+                $t = 'Polygon' if $t eq 'Unknown';
 
-		my $geom = Geo::OGR::Geometry->create($t);
+		my $geom = Geo::OGR::Geometry->new($t);
 		
 		if ($type eq 'MultiPoint') {
 
 		    for (0..1) {
-			my $g = Geo::OGR::Geometry->create('Point');
+			my $g = Geo::OGR::Geometry->new('Point');
 			test_geom($g,$name,'Point','create');
 			$geom->AddGeometry($g);
 		    }
@@ -444,7 +443,7 @@ sub ogr_tests {
 		} elsif ($type eq 'MultiLineString') {
 
 		    for (0..1) {
-			my $g = Geo::OGR::Geometry->create('LineString');
+			my $g = Geo::OGR::Geometry->new('LineString');
 			test_geom($g,$name,'LineString','create');
 			$geom->AddGeometry($g);
 		    }
@@ -483,13 +482,8 @@ sub ogr_tests {
 		
 		if ($name ne 'Memory') {
 		    eval {
-			if ($name eq 'MapInfo File') {
-			    $datasource = Geo::OGR::Open("$dir/$type.tab");
-			    $layer = $datasource->GetLayerByIndex;
-			} else {
-			    $datasource = $driver->CreateDataSource($dir);
+			    $datasource = Geo::OGR::Open($dir, 1);
 			    $layer = $datasource->GetLayerByName($type);
-			}
 		    };
 		    
 		    mytest($layer,'no message',$name,$type,"layer $type open");
@@ -520,11 +514,13 @@ sub ogr_tests {
 			
 			my $geom = $feature->GetGeometryRef();
 			
-			if ($type eq 'Pointxx') {
+                        if (!$geom) {
+                        } elsif ($type eq 'Pointxx') {
 			    mytest('skipped',undef,$name,$type,'geom open');
 			} else {
 			    my $t = $type eq 'Unknown' ? 'Polygon' : $type;
 			    my $t2 = $geom->GeometryType;
+                       
 			    mytest($t eq $t2,"$t ne $t2",$name,$type,'geom open');
 
 			    if ($type eq 'MultiPoint') {
@@ -583,7 +579,7 @@ sub ogr_tests {
 
     # specific tests:
 
-    my $geom = Geo::OGR::Geometry->create('Point');
+    my $geom = Geo::OGR::Geometry->new('Point');
     $geom->AddPoint(1,1);
     ok($geom->GeometryType eq 'Point', "Add 2D Point");
     $geom->AddPoint(1,1,1);
@@ -631,7 +627,7 @@ sub test_geom {
 	my @pts = ([1.1,1],[1.11,0],[0,0.2],[0,2.1],[1,1.23],[1.1,1]);
 
 	if ($mode eq 'create') {
-	    my $r = Geo::OGR::Geometry->create('LinearRing');
+	    my $r = Geo::OGR::Geometry->new('LinearRing');
 	    pop @pts;
 	    my $n = @pts;
 	    for my $pt (@pts) {
@@ -639,15 +635,15 @@ sub test_geom {
 	    }
 	    $pc = $r->GetPointCount;
 	    mytest($pc == $n,"$pc != $n",$name,$type,'point count pre');
-	    $geom->AddGeometry($r);
-	    $geom->CloseRings; # this adds the point we popped out
-	    $n++;
-	    $r = $geom->GetGeometryRef(0);
-	    $pc = $r->GetPointCount;
-	    for (0..$pc-1) {
-		my @p = $r->GetPoint($_);
-	    }
-	    mytest($pc == $n,"$pc != $n",$name,$type,'point count post 1');
+            $geom->AddGeometry($r);
+            $geom->CloseRings; # this adds the point we popped out
+            $n++;
+            $r = $geom->GetGeometryRef(0);
+            $pc = $r->GetPointCount;
+            for (0..$pc-1) {
+                my @p = $r->GetPoint($_);
+            }
+            mytest($pc == $n,"$pc != $n",$name,$type,'point count post 1');
 	} else {	       
 	    mytest($gn == 1,"$gn != 1",$name,$type,'geom count');
 	    my $r = $geom->GetGeometryRef(0);
@@ -661,7 +657,7 @@ sub test_geom {
 	}
 
     } else {
-	mytest('skipped',undef,$name,$type,'geom create/open');
+	mytest('skipped',undef,$name,$type,'geom new/open');
     }
 }
 
diff --git a/swig/perl/t/osr.t b/swig/perl/t/osr.t
index c05cccd..709fa06 100644
--- a/swig/perl/t/osr.t
+++ b/swig/perl/t/osr.t
@@ -1,17 +1,14 @@
 use Test::More qw(no_plan);
 BEGIN { use_ok('Geo::GDAL') };
 
-$srs1 = Geo::OSR::SpatialReference->create(EPSG=>2936);
-$srs2 = Geo::OSR::SpatialReference->create(Text=>$srs1->AsText);
+$srs1 = Geo::OSR::SpatialReference->new(EPSG=>2936);
+$srs2 = Geo::OSR::SpatialReference->new(Text=>$srs1->AsText);
 
-ok($srs1->ExportToProj4 eq $srs2->ExportToProj4, "create EPSG, Text, Proj4");
+ok($srs1->ExportToProj4 eq $srs2->ExportToProj4, "new EPSG, Text, Proj4");
 
-my $src = Geo::OSR::SpatialReference->new();
-$src->ImportFromEPSG(2392);
-
-my $dst = Geo::OSR::SpatialReference->new();
-$dst->ImportFromEPSG(2393);
-ok(($src and $dst), "create Geo::OSR::SpatialReference");
+my $src = Geo::OSR::SpatialReference->new(EPSG => 2392);
+my $dst = Geo::OSR::SpatialReference->new(EPSG => 2393);
+ok(($src and $dst), "new Geo::OSR::SpatialReference");
 
 SKIP: {
     skip "PROJSO not set", 1 if (!$ENV{PROJSO} and $^O eq 'MSWin32');
@@ -20,9 +17,9 @@ SKIP: {
 	$t1 = Geo::OSR::CoordinateTransformation->new($src, $dst);
 	$t2 = Geo::OSR::CoordinateTransformation->new($dst, $src);
     };
-    ok($t1, "create Geo::OSR::CoordinateTransformation $@");
+    ok($t1, "new Geo::OSR::CoordinateTransformation $@");
 
-    skip "create Geo::OSR::CoordinateTransformation failed",1 unless ($t1 and $t2);
+    skip "new Geo::OSR::CoordinateTransformation failed",1 unless ($t1 and $t2);
 
     my @points = ([2492055.205, 6830493.772],
 		  [2492065.205, 6830483.772],
diff --git a/swig/php/osr.php b/swig/php/osr.php
index 3bee39c..c0e6f52 100644
--- a/swig/php/osr.php
+++ b/swig/php/osr.php
@@ -83,6 +83,8 @@ abstract class osr {
 
 	const SRS_PT_MERCATOR_2SP = SRS_PT_MERCATOR_2SP;
 
+	const SRS_PT_MERCATOR_AUXILIARY_SPHERE = SRS_PT_MERCATOR_AUXILIARY_SPHERE;
+
 	const SRS_PT_MILLER_CYLINDRICAL = SRS_PT_MILLER_CYLINDRICAL;
 
 	const SRS_PT_MOLLWEIDE = SRS_PT_MOLLWEIDE;
diff --git a/swig/php/osr_wrap.cpp b/swig/php/osr_wrap.cpp
index 2084a5c..3e6b015 100644
--- a/swig/php/osr_wrap.cpp
+++ b/swig/php/osr_wrap.cpp
@@ -8280,6 +8280,7 @@ SWIG_STRING_CONSTANT(SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM, "Lambert_Confor
 SWIG_STRING_CONSTANT(SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA, "Lambert_Azimuthal_Equal_Area");
 SWIG_STRING_CONSTANT(SRS_PT_MERCATOR_1SP, "Mercator_1SP");
 SWIG_STRING_CONSTANT(SRS_PT_MERCATOR_2SP, "Mercator_2SP");
+SWIG_STRING_CONSTANT(SRS_PT_MERCATOR_AUXILIARY_SPHERE, "Mercator_Auxiliary_Sphere");
 SWIG_STRING_CONSTANT(SRS_PT_MILLER_CYLINDRICAL, "Miller_Cylindrical");
 SWIG_STRING_CONSTANT(SRS_PT_MOLLWEIDE, "Mollweide");
 SWIG_STRING_CONSTANT(SRS_PT_NEW_ZEALAND_MAP_GRID, "New_Zealand_Map_Grid");
diff --git a/swig/python/extensions/gdal_array_wrap.cpp b/swig/python/extensions/gdal_array_wrap.cpp
index d3e9989..a0d3b30 100644
--- a/swig/python/extensions/gdal_array_wrap.cpp
+++ b/swig/python/extensions/gdal_array_wrap.cpp
@@ -2724,16 +2724,19 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 
 #define SWIGTYPE_p_CPLVirtualMemShadow swig_types[0]
 #define SWIGTYPE_p_GDALDataType swig_types[1]
-#define SWIGTYPE_p_GDALRasterAttributeTableShadow swig_types[2]
-#define SWIGTYPE_p_GDALRasterBandShadow swig_types[3]
-#define SWIGTYPE_p_PyArrayObject swig_types[4]
-#define SWIGTYPE_p_char swig_types[5]
-#define SWIGTYPE_p_int swig_types[6]
-#define SWIGTYPE_p_p_CPLVirtualMemShadow swig_types[7]
-#define SWIGTYPE_p_p_void swig_types[8]
-#define SWIGTYPE_p_size_t swig_types[9]
-static swig_type_info *swig_types[11];
-static swig_module_info swig_module = {swig_types, 10, 0, 0, 0, 0};
+#define SWIGTYPE_p_GDALDatasetShadow swig_types[2]
+#define SWIGTYPE_p_GDALProgressFunc swig_types[3]
+#define SWIGTYPE_p_GDALRasterAttributeTableShadow swig_types[4]
+#define SWIGTYPE_p_GDALRasterBandShadow swig_types[5]
+#define SWIGTYPE_p_PyArrayObject swig_types[6]
+#define SWIGTYPE_p_char swig_types[7]
+#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[8]
+#define SWIGTYPE_p_int swig_types[9]
+#define SWIGTYPE_p_p_CPLVirtualMemShadow swig_types[10]
+#define SWIGTYPE_p_p_void swig_types[11]
+#define SWIGTYPE_p_size_t swig_types[12]
+static swig_type_info *swig_types[14];
+static swig_module_info swig_module = {swig_types, 13, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -3145,9 +3148,11 @@ static void GDALPythonFreeCStr(void* ptr, int bToFree)
 
 #ifdef DEBUG 
 typedef struct GDALRasterBandHS GDALRasterBandShadow;
+typedef struct GDALDatasetHS GDALDatasetShadow;
 typedef struct RasterAttributeTableHS GDALRasterAttributeTableShadow;
 #else
 typedef void GDALRasterBandShadow;
+typedef void GDALDatasetShadow;
 typedef void GDALRasterAttributeTableShadow;
 #endif
 
@@ -3199,7 +3204,8 @@ static void GDALRegister_NUMPY(void)
 
 {
     GDALDriver	*poDriver;
-
+    if (! GDAL_CHECK_VERSION("NUMPY driver"))
+        return;
     if( GDALGetDriverByName( "NUMPY" ) == NULL )
     {
         poDriver = new GDALDriver();
@@ -3207,6 +3213,7 @@ static void GDALRegister_NUMPY(void)
         poDriver->SetDescription( "NUMPY" );
         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
                                    "Numeric Python Array" );
+        poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
         
         poDriver->pfnOpen = NUMPYDataset::Open;
 
@@ -3374,7 +3381,7 @@ GDALDataset *NUMPYDataset::Open( GDALOpenInfo * poOpenInfo )
 /*      Is this a numpy dataset name?                                   */
 /* -------------------------------------------------------------------- */
     if( !EQUALN(poOpenInfo->pszFilename,"NUMPY:::",8) 
-        || poOpenInfo->fp != NULL )
+        || poOpenInfo->fpL != NULL )
         return NULL;
 
     psArray = NULL;
@@ -3526,6 +3533,175 @@ GDALDataset *NUMPYDataset::Open( GDALOpenInfo * poOpenInfo )
 
 
 
+int GDALTermProgress_nocb( double dfProgress, const char * pszMessage=NULL, void *pData=NULL ) {
+  return GDALTermProgress( dfProgress, pszMessage, pData);
+}
+
+
+SWIGINTERN swig_type_info*
+SWIG_pchar_descriptor(void)
+{
+  static int init = 0;
+  static swig_type_info* info = 0;
+  if (!init) {
+    info = SWIG_TypeQuery("_p_char");
+    init = 1;
+  }
+  return info;
+}
+
+
+SWIGINTERN int
+SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
+{
+#if PY_VERSION_HEX>=0x03000000
+  if (PyUnicode_Check(obj))
+#else  
+  if (PyString_Check(obj))
+#endif
+  {
+    char *cstr; Py_ssize_t len;
+#if PY_VERSION_HEX>=0x03000000
+    if (!alloc && cptr) {
+        /* We can't allow converting without allocation, since the internal
+           representation of string in Python 3 is UCS-2/UCS-4 but we require
+           a UTF-8 representation.
+           TODO(bhy) More detailed explanation */
+        return SWIG_RuntimeError;
+    }
+    obj = PyUnicode_AsUTF8String(obj);
+    PyBytes_AsStringAndSize(obj, &cstr, &len);
+    if(alloc) *alloc = SWIG_NEWOBJ;
+#else
+    PyString_AsStringAndSize(obj, &cstr, &len);
+#endif
+    if (cptr) {
+      if (alloc) {
+	/* 
+	   In python the user should not be able to modify the inner
+	   string representation. To warranty that, if you define
+	   SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string
+	   buffer is always returned.
+
+	   The default behavior is just to return the pointer value,
+	   so, be careful.
+	*/ 
+#if defined(SWIG_PYTHON_SAFE_CSTRINGS)
+	if (*alloc != SWIG_OLDOBJ) 
+#else
+	if (*alloc == SWIG_NEWOBJ) 
+#endif
+	  {
+	    *cptr = reinterpret_cast< char* >(memcpy((new char[len + 1]), cstr, sizeof(char)*(len + 1)));
+	    *alloc = SWIG_NEWOBJ;
+	  }
+	else {
+	  *cptr = cstr;
+	  *alloc = SWIG_OLDOBJ;
+	}
+      } else {
+        #if PY_VERSION_HEX>=0x03000000
+        assert(0); /* Should never reach here in Python 3 */
+        #endif
+	*cptr = SWIG_Python_str_AsChar(obj);
+      }
+    }
+    if (psize) *psize = len + 1;
+#if PY_VERSION_HEX>=0x03000000
+    Py_XDECREF(obj);
+#endif
+    return SWIG_OK;
+  } else {
+    swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
+    if (pchar_descriptor) {
+      void* vptr = 0;
+      if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) {
+	if (cptr) *cptr = (char *) vptr;
+	if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0;
+	if (alloc) *alloc = SWIG_OLDOBJ;
+	return SWIG_OK;
+      }
+    }
+  }
+  return SWIG_TypeError;
+}
+
+
+
+
+
+  #define SWIG_From_long   PyInt_FromLong 
+
+
+SWIGINTERNINLINE PyObject *
+SWIG_From_int  (int value)
+{    
+  return SWIG_From_long  (value);
+}
+
+
+
+typedef struct {
+    PyObject *psPyCallback;
+    PyObject *psPyCallbackData;
+    int nLastReported;
+} PyProgressData;
+
+/************************************************************************/
+/*                          PyProgressProxy()                           */
+/************************************************************************/
+
+int CPL_STDCALL
+PyProgressProxy( double dfComplete, const char *pszMessage, void *pData )
+
+{
+    PyProgressData *psInfo = (PyProgressData *) pData;
+    PyObject *psArgs, *psResult;
+    int      bContinue = TRUE;
+
+    if( psInfo->nLastReported == (int) (100.0 * dfComplete) )
+        return TRUE;
+
+    if( psInfo->psPyCallback == NULL || psInfo->psPyCallback == Py_None )
+        return TRUE;
+
+    psInfo->nLastReported = (int) (100.0 * dfComplete);
+    
+    if( pszMessage == NULL )
+        pszMessage = "";
+
+    if( psInfo->psPyCallbackData == NULL )
+        psArgs = Py_BuildValue("(dsO)", dfComplete, pszMessage, Py_None );
+    else
+        psArgs = Py_BuildValue("(dsO)", dfComplete, pszMessage, 
+	                       psInfo->psPyCallbackData );
+
+    psResult = PyEval_CallObject( psInfo->psPyCallback, psArgs);
+    Py_XDECREF(psArgs);
+
+    if( psResult == NULL )
+    {
+        return TRUE;
+    }
+
+    if( psResult == Py_None )
+    {
+	Py_XDECREF(Py_None);
+        return TRUE;
+    }
+
+    if( !PyArg_Parse( psResult, "i", &bContinue ) )
+    {
+        PyErr_SetString(PyExc_ValueError, "bad progress return value");
+	return FALSE;
+    }
+
+    Py_XDECREF(psResult);
+
+    return bContinue;    
+}
+
+
 retStringAndCPLFree* GetArrayFilename(PyArrayObject *psArray)
 {
     char      szString[128];
@@ -3539,8 +3715,11 @@ retStringAndCPLFree* GetArrayFilename(PyArrayObject *psArray)
 
 
   CPLErr BandRasterIONumPy( GDALRasterBandShadow* band, int bWrite, int xoff, int yoff, int xsize, int ysize,
-                     PyArrayObject *psArray,
-                     int buf_type) {
+                            PyArrayObject *psArray,
+                            int buf_type,
+                            GDALRIOResampleAlg resample_alg,
+                            GDALProgressFunc callback = NULL,
+                            void* callback_data = NULL) {
 
     GDALDataType ntype  = (GDALDataType)buf_type;
     if( psArray->nd < 2 || psArray->nd > 3 )
@@ -3560,20 +3739,65 @@ retStringAndCPLFree* GetArrayFilename(PyArrayObject *psArray)
     pixel_space = psArray->strides[xdim];
     line_space = psArray->strides[ydim];
 
-    return  GDALRasterIO( band, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    return  GDALRasterIOEx( band, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
                           psArray->data, nxsize, nysize,
-                          ntype, pixel_space, line_space );
+                          ntype, pixel_space, line_space, &sExtraArg );
   }
 
 
-  #define SWIG_From_long   PyInt_FromLong 
+  CPLErr DatasetIONumPy( GDALDatasetShadow* ds, int bWrite, int xoff, int yoff, int xsize, int ysize,
+                         PyArrayObject *psArray,
+                         int buf_type,
+                         GDALRIOResampleAlg resample_alg,
+                         GDALProgressFunc callback = NULL,
+                         void* callback_data = NULL )
+{
+    GDALDataType ntype  = (GDALDataType)buf_type;
+    if( psArray->nd != 3 )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Illegal numpy array rank %d.", 
+                  psArray->nd );
+        return CE_Failure;
+    }
 
+    int xdim = 2;
+    int ydim = 1;
 
-SWIGINTERNINLINE PyObject *
-SWIG_From_int  (int value)
-{    
-  return SWIG_From_long  (value);
-}
+    int bandsize, nxsize, nysize;
+    GIntBig pixel_space, line_space, band_space;
+    nxsize = psArray->dimensions[xdim];
+    nysize = psArray->dimensions[ydim];
+    bandsize = psArray->dimensions[0];
+    if( bandsize != GDALGetRasterCount(ds) )
+    {
+        CPLError( CE_Failure, CPLE_AppDefined, 
+                  "Illegal numpy array band dimension %d. Expected value: %d", 
+                  bandsize, GDALGetRasterCount(ds) );
+        return CE_Failure;
+    }
+    pixel_space = psArray->strides[xdim];
+    line_space = psArray->strides[ydim];
+    band_space = psArray->strides[0];
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    return  GDALDatasetRasterIOEx( ds, (bWrite) ? GF_Write : GF_Read, xoff, yoff, xsize, ysize,
+                                   psArray->data, nxsize, nysize,
+                                   ntype,
+                                   bandsize, NULL,
+                                   pixel_space, line_space, band_space, &sExtraArg );
+  }
 
 
     void VirtualMemGetArray(CPLVirtualMemShadow* virtualmem, CPLVirtualMemShadow** pvirtualmem, int numpytypemap)
@@ -4101,6 +4325,54 @@ SWIGINTERN PyObject *VirtualMem_swigregister(PyObject *SWIGUNUSEDPARM(self), PyO
   return SWIG_Py_Void();
 }
 
+SWIGINTERN PyObject *_wrap_TermProgress_nocb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  double arg1 ;
+  char *arg2 = (char *) NULL ;
+  void *arg3 = (void *) NULL ;
+  double val1 ;
+  int ecode1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "dfProgress",(char *) "pszMessage",(char *) "pData", NULL 
+  };
+  int result;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:TermProgress_nocb",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  ecode1 = SWIG_AsVal_double(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "TermProgress_nocb" "', argument " "1"" of type '" "double""'");
+  } 
+  arg1 = static_cast< double >(val1);
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "TermProgress_nocb" "', argument " "2"" of type '" "char const *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
+  }
+  if (obj2) {
+    res3 = SWIG_ConvertPtr(obj2,SWIG_as_voidptrptr(&arg3), 0, 0);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "TermProgress_nocb" "', argument " "3"" of type '" "void *""'"); 
+    }
+  }
+  result = (int)GDALTermProgress_nocb(arg1,(char const *)arg2,arg3);
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_GetArrayFilename(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   PyArrayObject *arg1 = (PyArrayObject *) 0 ;
@@ -4145,6 +4417,9 @@ SWIGINTERN PyObject *_wrap_BandRasterIONumPy(PyObject *SWIGUNUSEDPARM(self), PyO
   int arg6 ;
   PyArrayObject *arg7 = (PyArrayObject *) 0 ;
   int arg8 ;
+  GDALRIOResampleAlg arg9 ;
+  GDALProgressFunc arg10 = (GDALProgressFunc) NULL ;
+  void *arg11 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -4159,6 +4434,8 @@ SWIGINTERN PyObject *_wrap_BandRasterIONumPy(PyObject *SWIGUNUSEDPARM(self), PyO
   int ecode6 = 0 ;
   int val8 ;
   int ecode8 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
@@ -4167,12 +4444,22 @@ SWIGINTERN PyObject *_wrap_BandRasterIONumPy(PyObject *SWIGUNUSEDPARM(self), PyO
   PyObject * obj5 = 0 ;
   PyObject * obj6 = 0 ;
   PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
   char *  kwnames[] = {
-    (char *) "band",(char *) "bWrite",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "psArray",(char *) "buf_type", NULL 
+    (char *) "band",(char *) "bWrite",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "psArray",(char *) "buf_type",(char *) "resample_alg",(char *) "callback",(char *) "callback_data", NULL 
   };
   CPLErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOO:BandRasterIONumPy",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7)) SWIG_fail;
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg11 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOO|OO:BandRasterIONumPy",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BandRasterIONumPy" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
@@ -4220,10 +4507,218 @@ SWIGINTERN PyObject *_wrap_BandRasterIONumPy(PyObject *SWIGUNUSEDPARM(self), PyO
     SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "BandRasterIONumPy" "', argument " "8"" of type '" "int""'");
   } 
   arg8 = static_cast< int >(val8);
-  result = (CPLErr)BandRasterIONumPy(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "BandRasterIONumPy" "', argument " "9"" of type '" "GDALRIOResampleAlg""'");
+  } 
+  arg9 = static_cast< GDALRIOResampleAlg >(val9);
+  if (obj9) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj9 && obj9 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj9, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg10 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj9)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj9;
+          arg10 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj10) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj10 ;
+    }
+  }
+  result = (CPLErr)BandRasterIONumPy(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11);
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_DatasetIONumPy(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  int arg6 ;
+  PyArrayObject *arg7 = (PyArrayObject *) 0 ;
+  int arg8 ;
+  GDALRIOResampleAlg arg9 ;
+  GDALProgressFunc arg10 = (GDALProgressFunc) NULL ;
+  void *arg11 = (void *) NULL ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
+  int val8 ;
+  int ecode8 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
+  char *  kwnames[] = {
+    (char *) "ds",(char *) "bWrite",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "psArray",(char *) "buf_type",(char *) "resample_alg",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  CPLErr result;
+  
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg11 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOO|OO:DatasetIONumPy",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DatasetIONumPy" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DatasetIONumPy" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "DatasetIONumPy" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "DatasetIONumPy" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "DatasetIONumPy" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
+  ecode6 = SWIG_AsVal_int(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "DatasetIONumPy" "', argument " "6"" of type '" "int""'");
+  } 
+  arg6 = static_cast< int >(val6);
+  {
+    /* %typemap(in,numinputs=1) (PyArrayObject  *psArray) */
+    if (obj6 != NULL && PyArray_Check(obj6))
+    {
+      arg7 = (PyArrayObject*)(obj6);
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a numpy array");
+      SWIG_fail;
+    }
+  }
+  ecode8 = SWIG_AsVal_int(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "DatasetIONumPy" "', argument " "8"" of type '" "int""'");
+  } 
+  arg8 = static_cast< int >(val8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "DatasetIONumPy" "', argument " "9"" of type '" "GDALRIOResampleAlg""'");
+  } 
+  arg9 = static_cast< GDALRIOResampleAlg >(val9);
+  if (obj9) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj9 && obj9 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj9, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg10 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj9)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj9;
+          arg10 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj10) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj10 ;
+    }
+  }
+  result = (CPLErr)DatasetIONumPy(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11);
   resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
@@ -4548,10 +5043,19 @@ static PyMethodDef SwigMethods[] = {
 		"VirtualMem_Pin(VirtualMem self)\n"
 		""},
 	 { (char *)"VirtualMem_swigregister", VirtualMem_swigregister, METH_VARARGS, NULL},
+	 { (char *)"TermProgress_nocb", (PyCFunction) _wrap_TermProgress_nocb, METH_VARARGS | METH_KEYWORDS, (char *)"TermProgress_nocb(double dfProgress, char pszMessage = None, void pData = None) -> int"},
 	 { (char *)"GetArrayFilename", _wrap_GetArrayFilename, METH_VARARGS, (char *)"GetArrayFilename(PyArrayObject psArray) -> retStringAndCPLFree"},
 	 { (char *)"BandRasterIONumPy", (PyCFunction) _wrap_BandRasterIONumPy, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"BandRasterIONumPy(Band band, int bWrite, int xoff, int yoff, int xsize, \n"
-		"    int ysize, PyArrayObject psArray, int buf_type) -> CPLErr\n"
+		"    int ysize, PyArrayObject psArray, int buf_type, \n"
+		"    GDALRIOResampleAlg resample_alg, GDALProgressFunc callback = None, \n"
+		"    void callback_data = None) -> CPLErr\n"
+		""},
+	 { (char *)"DatasetIONumPy", (PyCFunction) _wrap_DatasetIONumPy, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+		"DatasetIONumPy(Dataset ds, int bWrite, int xoff, int yoff, int xsize, \n"
+		"    int ysize, PyArrayObject psArray, int buf_type, \n"
+		"    GDALRIOResampleAlg resample_alg, GDALProgressFunc callback = None, \n"
+		"    void callback_data = None) -> CPLErr\n"
 		""},
 	 { (char *)"VirtualMemGetArray", _wrap_VirtualMemGetArray, METH_VARARGS, (char *)"VirtualMemGetArray(VirtualMem virtualmem)"},
 	 { (char *)"RATValuesIONumPyWrite", (PyCFunction) _wrap_RATValuesIONumPyWrite, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
@@ -4570,11 +5074,14 @@ static PyMethodDef SwigMethods[] = {
 
 static swig_type_info _swigt__p_CPLVirtualMemShadow = {"_p_CPLVirtualMemShadow", "CPLVirtualMemShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GDALDataType = {"_p_GDALDataType", "GDALDataType *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GDALDatasetShadow = {"_p_GDALDatasetShadow", "GDALDatasetShadow *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GDALProgressFunc = {"_p_GDALProgressFunc", "GDALProgressFunc *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GDALRasterAttributeTableShadow = {"_p_GDALRasterAttributeTableShadow", "GDALRasterAttributeTableShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GDALRasterBandShadow = {"_p_GDALRasterBandShadow", "GDALRasterBandShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_PyArrayObject = {"_p_PyArrayObject", "PyArrayObject *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "GDALRATFieldType *|CPLErr *|int *|GDALRATFieldUsage *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_f_double_p_q_const__char_p_void__int = {"_p_f_double_p_q_const__char_p_void__int", "int (*)(double,char const *,void *)", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "GDALRATFieldType *|CPLErr *|int *|GDALRATFieldUsage *|GDALRIOResampleAlg *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_CPLVirtualMemShadow = {"_p_p_CPLVirtualMemShadow", "CPLVirtualMemShadow **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_void = {"_p_p_void", "void **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_size_t = {"_p_size_t", "size_t *", 0, 0, (void*)0, 0};
@@ -4582,10 +5089,13 @@ static swig_type_info _swigt__p_size_t = {"_p_size_t", "size_t *", 0, 0, (void*)
 static swig_type_info *swig_type_initial[] = {
   &_swigt__p_CPLVirtualMemShadow,
   &_swigt__p_GDALDataType,
+  &_swigt__p_GDALDatasetShadow,
+  &_swigt__p_GDALProgressFunc,
   &_swigt__p_GDALRasterAttributeTableShadow,
   &_swigt__p_GDALRasterBandShadow,
   &_swigt__p_PyArrayObject,
   &_swigt__p_char,
+  &_swigt__p_f_double_p_q_const__char_p_void__int,
   &_swigt__p_int,
   &_swigt__p_p_CPLVirtualMemShadow,
   &_swigt__p_p_void,
@@ -4594,10 +5104,13 @@ static swig_type_info *swig_type_initial[] = {
 
 static swig_cast_info _swigc__p_CPLVirtualMemShadow[] = {  {&_swigt__p_CPLVirtualMemShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALDataType[] = {  {&_swigt__p_GDALDataType, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GDALDatasetShadow[] = {  {&_swigt__p_GDALDatasetShadow, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GDALProgressFunc[] = {  {&_swigt__p_GDALProgressFunc, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterAttributeTableShadow[] = {  {&_swigt__p_GDALRasterAttributeTableShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterBandShadow[] = {  {&_swigt__p_GDALRasterBandShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_PyArrayObject[] = {  {&_swigt__p_PyArrayObject, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_f_double_p_q_const__char_p_void__int[] = {  {&_swigt__p_f_double_p_q_const__char_p_void__int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_CPLVirtualMemShadow[] = {  {&_swigt__p_p_CPLVirtualMemShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_void[] = {  {&_swigt__p_p_void, 0, 0, 0},{0, 0, 0, 0}};
@@ -4606,10 +5119,13 @@ static swig_cast_info _swigc__p_size_t[] = {  {&_swigt__p_size_t, 0, 0, 0},{0, 0
 static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_CPLVirtualMemShadow,
   _swigc__p_GDALDataType,
+  _swigc__p_GDALDatasetShadow,
+  _swigc__p_GDALProgressFunc,
   _swigc__p_GDALRasterAttributeTableShadow,
   _swigc__p_GDALRasterBandShadow,
   _swigc__p_PyArrayObject,
   _swigc__p_char,
+  _swigc__p_f_double_p_q_const__char_p_void__int,
   _swigc__p_int,
   _swigc__p_p_CPLVirtualMemShadow,
   _swigc__p_p_void,
@@ -4620,6 +5136,7 @@ static swig_cast_info *swig_cast_initial[] = {
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */
 
 static swig_const_info swig_const_table[] = {
+{ SWIG_PY_POINTER, (char*)"TermProgress", 0, 0, (void *)((int (*)(double,char const *,void *))(GDALTermProgress)), &SWIGTYPE_p_f_double_p_q_const__char_p_void__int },
 {0, 0, 0, 0.0, 0, 0}};
 
 #ifdef __cplusplus
@@ -5211,6 +5728,7 @@ SWIG_init(void) {
   import_array();
   GDALRegister_NUMPY();
   
+  
 #if PY_VERSION_HEX >= 0x03000000
   return m;
 #else
diff --git a/swig/python/extensions/gdal_wrap.cpp b/swig/python/extensions/gdal_wrap.cpp
index 6745815..9cb29a9 100644
--- a/swig/python/extensions/gdal_wrap.cpp
+++ b/swig/python/extensions/gdal_wrap.cpp
@@ -2738,21 +2738,25 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 #define SWIGTYPE_p_GDALTransformerInfoShadow swig_types[13]
 #define SWIGTYPE_p_GDAL_GCP swig_types[14]
 #define SWIGTYPE_p_GIntBig swig_types[15]
-#define SWIGTYPE_p_OGRLayerShadow swig_types[16]
-#define SWIGTYPE_p_StatBuf swig_types[17]
-#define SWIGTYPE_p_char swig_types[18]
-#define SWIGTYPE_p_double swig_types[19]
-#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[20]
-#define SWIGTYPE_p_int swig_types[21]
-#define SWIGTYPE_p_p_GDALRasterBandShadow swig_types[22]
-#define SWIGTYPE_p_p_GDAL_GCP swig_types[23]
-#define SWIGTYPE_p_p_char swig_types[24]
-#define SWIGTYPE_p_p_int swig_types[25]
-#define SWIGTYPE_p_p_void swig_types[26]
-#define SWIGTYPE_p_size_t swig_types[27]
-#define SWIGTYPE_p_void swig_types[28]
-static swig_type_info *swig_types[30];
-static swig_module_info swig_module = {swig_types, 29, 0, 0, 0, 0};
+#define SWIGTYPE_p_GUIntBig swig_types[16]
+#define SWIGTYPE_p_OGRGeometryShadow swig_types[17]
+#define SWIGTYPE_p_OGRLayerShadow swig_types[18]
+#define SWIGTYPE_p_OGRStyleTableShadow swig_types[19]
+#define SWIGTYPE_p_OSRSpatialReferenceShadow swig_types[20]
+#define SWIGTYPE_p_StatBuf swig_types[21]
+#define SWIGTYPE_p_char swig_types[22]
+#define SWIGTYPE_p_double swig_types[23]
+#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[24]
+#define SWIGTYPE_p_int swig_types[25]
+#define SWIGTYPE_p_p_GDALRasterBandShadow swig_types[26]
+#define SWIGTYPE_p_p_GDAL_GCP swig_types[27]
+#define SWIGTYPE_p_p_GUIntBig swig_types[28]
+#define SWIGTYPE_p_p_char swig_types[29]
+#define SWIGTYPE_p_p_void swig_types[30]
+#define SWIGTYPE_p_size_t swig_types[31]
+#define SWIGTYPE_p_void swig_types[32]
+static swig_type_info *swig_types[34];
+static swig_module_info swig_module = {swig_types, 33, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -2871,6 +2875,19 @@ typedef void GDALRasterAttributeTableShadow;
 typedef void GDALTransformerInfoShadow;
 typedef void GDALAsyncReaderShadow;
 
+
+#ifdef DEBUG 
+typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
+typedef struct OGRLayerHS OGRLayerShadow;
+typedef struct OGRGeometryHS OGRGeometryShadow;
+#else
+typedef void OSRSpatialReferenceShadow;
+typedef void OGRLayerShadow;
+typedef void OGRGeometryShadow;
+#endif
+typedef struct OGRStyleTableHS OGRStyleTableShadow;
+
+
 /* use this to not return the int returned by GDAL */
 typedef int RETURN_NONE;
 
@@ -2883,7 +2900,7 @@ void CPL_STDCALL
 PythonBindingErrorHandler(CPLErr eclass, int code, const char *msg ) 
 {
   /* 
-  ** Generally we want to supress error reporting if we have exceptions
+  ** Generally we want to suppress error reporting if we have exceptions
   ** enabled as the error message will be in the exception thrown in 
   ** Python.  
   */
@@ -3019,6 +3036,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return 0;
     }
@@ -3035,6 +3053,7 @@ int wrapper_VSIFReadL( void **buf, int nMembSize, int nMembCount, VSILFILE *fp)
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return 0;
     }
@@ -3501,11 +3520,19 @@ int wrapper_VSIStatL( const char * utf8_path, StatBuf *psStatBufOut, int nFlags
 }
 
 
+VSILFILE   *wrapper_VSIFOpenL( const char *utf8_path, const char *pszMode )
+{
+    if (!pszMode) /* would lead to segfault */
+        pszMode = "r";
+    return VSIFOpenL( utf8_path, pszMode );
+}
+
+
 int wrapper_VSIFWriteL( int nLen, char *pBuf, int size, int memb, VSILFILE * f)
 {
     if (nLen < size * memb)
     {
-        CPLError(CE_Failure, CPLE_AppDefined, "Inconsistant buffer size with 'size' and 'memb' values");
+        CPLError(CE_Failure, CPLE_AppDefined, "Inconsistent buffer size with 'size' and 'memb' values");
         return 0;
     }
     return VSIFWriteL(pBuf, size, memb, f);
@@ -3563,13 +3590,13 @@ SWIGINTERN GDALDatasetShadow *GDALDriverShadow_CreateCopy(GDALDriverShadow *self
                                                                     callback_data );
     return ds;
   }
-SWIGINTERN int GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
+SWIGINTERN CPLErr GDALDriverShadow_Delete(GDALDriverShadow *self,char const *utf8_path){
     return GDALDeleteDataset( self, utf8_path );
   }
-SWIGINTERN int GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_Rename(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALRenameDataset( self, newName, oldName );
   }
-SWIGINTERN int GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
+SWIGINTERN CPLErr GDALDriverShadow_CopyFiles(GDALDriverShadow *self,char const *newName,char const *oldName){
     return GDALCopyDatasetFiles( self, newName, oldName );
   }
 SWIGINTERN int GDALDriverShadow_Register(GDALDriverShadow *self){
@@ -3684,59 +3711,6 @@ void GDAL_GCP_Id_set( GDAL_GCP *gcp, const char * pszId ) {
 }
 
 
-
-/* Duplicate, but transposed names for C# because 
-*  the C# module outputs backwards names
-*/
-double GDAL_GCP_get_GCPX( GDAL_GCP *gcp ) {
-  return gcp->dfGCPX;
-}
-void GDAL_GCP_set_GCPX( GDAL_GCP *gcp, double dfGCPX ) {
-  gcp->dfGCPX = dfGCPX;
-}
-double GDAL_GCP_get_GCPY( GDAL_GCP *gcp ) {
-  return gcp->dfGCPY;
-}
-void GDAL_GCP_set_GCPY( GDAL_GCP *gcp, double dfGCPY ) {
-  gcp->dfGCPY = dfGCPY;
-}
-double GDAL_GCP_get_GCPZ( GDAL_GCP *gcp ) {
-  return gcp->dfGCPZ;
-}
-void GDAL_GCP_set_GCPZ( GDAL_GCP *gcp, double dfGCPZ ) {
-  gcp->dfGCPZ = dfGCPZ;
-}
-double GDAL_GCP_get_GCPPixel( GDAL_GCP *gcp ) {
-  return gcp->dfGCPPixel;
-}
-void GDAL_GCP_set_GCPPixel( GDAL_GCP *gcp, double dfGCPPixel ) {
-  gcp->dfGCPPixel = dfGCPPixel;
-}
-double GDAL_GCP_get_GCPLine( GDAL_GCP *gcp ) {
-  return gcp->dfGCPLine;
-}
-void GDAL_GCP_set_GCPLine( GDAL_GCP *gcp, double dfGCPLine ) {
-  gcp->dfGCPLine = dfGCPLine;
-}
-const char * GDAL_GCP_get_Info( GDAL_GCP *gcp ) {
-  return gcp->pszInfo;
-}
-void GDAL_GCP_set_Info( GDAL_GCP *gcp, const char * pszInfo ) {
-  if ( gcp->pszInfo ) 
-    CPLFree( gcp->pszInfo );
-  gcp->pszInfo = CPLStrdup(pszInfo);
-}
-const char * GDAL_GCP_get_Id( GDAL_GCP *gcp ) {
-  return gcp->pszId;
-}
-void GDAL_GCP_set_Id( GDAL_GCP *gcp, const char * pszId ) {
-  if ( gcp->pszId ) 
-    CPLFree( gcp->pszId );
-  gcp->pszId = CPLStrdup(pszId);
-}
-
-
-
 #define t_output_helper SWIG_Python_AppendOutput
 
 
@@ -3847,7 +3821,7 @@ SWIGINTERN void CPLVirtualMemShadow_Pin(CPLVirtualMemShadow *self,size_t start_o
 static
 GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
                                 int nBands, int* bandMap, int nBandMapArrayLength,
-                                int nPixelSpace, int nLineSpace, int nBandSpace,
+                                GIntBig nPixelSpace, GIntBig nLineSpace, GIntBig nBandSpace,
                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
@@ -3855,7 +3829,7 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -3884,11 +3858,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -3899,11 +3868,6 @@ GIntBig ComputeDatasetRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize
 
     if( nBandSpace == 0 )
     {
-        if (nLineSpace > MAX_INT32 / buf_ysize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nBandSpace");
-            return 0;
-        }
         nBandSpace = nLineSpace * buf_ysize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nBandSpace % nPixelSize) != 0 )
@@ -4295,7 +4259,104 @@ SWIGINTERN CPLVirtualMemShadow *GDALDatasetShadow_GetTiledVirtualMem(GDALDataset
         vmemshadow->nBandCount = band_list;
         return vmemshadow;
     }
-SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster1(GDALDatasetShadow *self,int xoff,int yoff,int xsize,int ysize,void **buf,int *buf_xsize=0,int *buf_ysize=0,GDALDataType *buf_type=0,int band_list=0,int *pband_list=0,int *buf_pixel_space=0,int *buf_line_space=0,int *buf_band_space=0){
+SWIGINTERN OGRLayerShadow *GDALDatasetShadow_CreateLayer(GDALDatasetShadow *self,char const *name,OSRSpatialReferenceShadow *srs=NULL,OGRwkbGeometryType geom_type=wkbUnknown,char **options=0){
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetCreateLayer( self,
+                                  name,
+                                  srs,
+                                  geom_type,
+                                  options);
+    return layer;
+  }
+SWIGINTERN OGRLayerShadow *GDALDatasetShadow_CopyLayer(GDALDatasetShadow *self,OGRLayerShadow *src_layer,char const *new_name,char **options=0){
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetCopyLayer( self,
+                                                      src_layer,
+                                                      new_name,
+                                                      options);
+    return layer;
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_DeleteLayer(GDALDatasetShadow *self,int index){
+    return GDALDatasetDeleteLayer(self, index);
+  }
+
+
+#include "ogr_core.h"
+static char const *
+OGRErrMessages( int rc ) {
+  switch( rc ) {
+  case OGRERR_NONE:
+    return "OGR Error: None";
+  case OGRERR_NOT_ENOUGH_DATA:
+    return "OGR Error: Not enough data to deserialize";
+  case OGRERR_NOT_ENOUGH_MEMORY:
+    return "OGR Error: Not enough memory";
+  case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
+    return "OGR Error: Unsupported geometry type";
+  case OGRERR_UNSUPPORTED_OPERATION:
+    return "OGR Error: Unsupported operation";
+  case OGRERR_CORRUPT_DATA:
+    return "OGR Error: Corrupt data";
+  case OGRERR_FAILURE:
+    return "OGR Error: General Error";
+  case OGRERR_UNSUPPORTED_SRS:
+    return "OGR Error: Unsupported SRS";
+  case OGRERR_INVALID_HANDLE:
+    return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
+  default:
+    return "OGR Error: Unknown";
+  }
+}
+
+SWIGINTERN int GDALDatasetShadow_GetLayerCount(GDALDatasetShadow *self){
+    return GDALDatasetGetLayerCount(self);
+  }
+SWIGINTERN OGRLayerShadow *GDALDatasetShadow_GetLayerByIndex(GDALDatasetShadow *self,int index=0){
+
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetGetLayer(self, index);
+    return layer;
+  }
+SWIGINTERN OGRLayerShadow *GDALDatasetShadow_GetLayerByName(GDALDatasetShadow *self,char const *layer_name){
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetGetLayerByName(self, layer_name);
+    return layer;
+  }
+SWIGINTERN bool GDALDatasetShadow_TestCapability(GDALDatasetShadow *self,char const *cap){
+    return (GDALDatasetTestCapability(self, cap) > 0);
+  }
+
+SWIGINTERNINLINE PyObject*
+  SWIG_From_bool  (bool value)
+{
+  return PyBool_FromLong(value ? 1 : 0);
+}
+
+SWIGINTERN OGRLayerShadow *GDALDatasetShadow_ExecuteSQL(GDALDatasetShadow *self,char const *statement,OGRGeometryShadow *spatialFilter=NULL,char const *dialect=""){
+    OGRLayerShadow* layer = (OGRLayerShadow*) GDALDatasetExecuteSQL(self,
+                                                      statement,
+                                                      spatialFilter,
+                                                      dialect);
+    return layer;
+  }
+SWIGINTERN void GDALDatasetShadow_ReleaseResultSet(GDALDatasetShadow *self,OGRLayerShadow *layer){
+    GDALDatasetReleaseResultSet(self, layer);
+  }
+SWIGINTERN OGRStyleTableShadow *GDALDatasetShadow_GetStyleTable(GDALDatasetShadow *self){
+    return (OGRStyleTableShadow*) GDALDatasetGetStyleTable(self);
+  }
+SWIGINTERN void GDALDatasetShadow_SetStyleTable(GDALDatasetShadow *self,OGRStyleTableShadow *table){
+    if( table != NULL )
+        GDALDatasetSetStyleTable(self, (OGRStyleTableH) table);
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_StartTransaction(GDALDatasetShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_CommitTransaction(GDALDatasetShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr GDALDatasetShadow_RollbackTransaction(GDALDatasetShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
+SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster1(GDALDatasetShadow *self,int xoff,int yoff,int xsize,int ysize,void **buf,int *buf_xsize=0,int *buf_ysize=0,GDALDataType *buf_type=0,int band_list=0,int *pband_list=0,GIntBig *buf_pixel_space=0,GIntBig *buf_line_space=0,GIntBig *buf_band_space=0,GDALRIOResampleAlg resample_alg=GRIORA_NearestNeighbour,GDALProgressFunc callback=NULL,void *callback_data=NULL){
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
     GDALDataType ntype;
@@ -4311,11 +4372,12 @@ SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster1(GDALDatasetShadow *self,int xoff
       ntype = GDALGetRasterDataType( GDALGetRasterBand( self, lastband ) );
     }
 
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
-    int band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig band_space = (buf_band_space == 0) ? 0 : *buf_band_space;
 
-    GIntBig buf_size = ComputeDatasetRasterIOSize (nxsize, nysize, GDALGetDataTypeSize( ntype ) / 8,
+    int ntypesize = GDALGetDataTypeSize( ntype ) / 8;
+    GIntBig buf_size = ComputeDatasetRasterIOSize (nxsize, nysize, ntypesize,
                                                band_list ? band_list : GDALGetRasterCount(self), pband_list, band_list,
                                                pixel_space, line_space, band_space, FALSE);
     if (buf_size == 0)
@@ -4328,6 +4390,7 @@ SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster1(GDALDatasetShadow *self,int xoff
     *buf = (void *)PyBytes_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -4336,15 +4399,36 @@ SWIGINTERN CPLErr GDALDatasetShadow_ReadRaster1(GDALDatasetShadow *self,int xoff
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
     char *data = PyString_AsString( (PyObject *)*buf ); 
 #endif
 
-    CPLErr eErr = GDALDatasetRasterIO(self, GF_Read, xoff, yoff, xsize, ysize,
+    /* Should we clear the buffer in case there are hole in it ? */
+    if( line_space != 0 && pixel_space != 0 && line_space > pixel_space * nxsize )
+    {
+        memset(data, 0, buf_size);
+    }
+    else if( band_list > 1 && band_space != 0 )
+    {
+        if( line_space != 0 && band_space > line_space * nysize )
+            memset(data, 0, buf_size);
+        else if( pixel_space != 0 && band_space < pixel_space &&
+                 pixel_space != GDALGetRasterCount(self) * ntypesize )
+            memset(data, 0, buf_size);
+    }
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+    CPLErr eErr = GDALDatasetRasterIOEx(self, GF_Read, xoff, yoff, xsize, ysize,
                                (void*) data, nxsize, nysize, ntype,
-                               band_list, pband_list, pixel_space, line_space, band_space );
+                               band_list, pband_list, pixel_space, line_space, band_space,
+                               &sExtraArg );
     if (eErr == CE_Failure)
     {
         Py_DECREF((PyObject*)*buf);
@@ -4367,15 +4451,15 @@ int GDALDatasetShadow_RasterCount_get( GDALDatasetShadow *h ) {
 /* Returned size is in bytes or 0 if an error occured */
 static
 GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
-                             int nPixelSpace, int nLineSpace,
-                             int bSpacingShouldBeMultipleOfPixelSize )
+                                 GIntBig nPixelSpace, GIntBig nLineSpace,
+                                 int bSpacingShouldBeMultipleOfPixelSize )
 {
 #if SIZEOF_VOIDP == 8
     const GIntBig MAX_INT = (((GIntBig)0x7fffffff) << 32) | 0xffffffff;
 #else
     const GIntBig MAX_INT = 0x7fffffff;
 #endif
-    const GIntBig MAX_INT32 = 0x7fffffff;
+
     if (buf_xsize <= 0 || buf_ysize <= 0)
     {
         CPLError(CE_Failure, CPLE_IllegalArg, "Illegal values for buffer size");
@@ -4404,11 +4488,6 @@ GIntBig ComputeBandRasterIOSize (int buf_xsize, int buf_ysize, int nPixelSize,
 
     if( nLineSpace == 0 )
     {
-        if (nPixelSpace > MAX_INT32 / buf_xsize)
-        {
-            CPLError(CE_Failure, CPLE_IllegalArg, "Integer overflow for nLineSpace");
-            return 0;
-        }
         nLineSpace = nPixelSpace * buf_xsize;
     }
     else if ( bSpacingShouldBeMultipleOfPixelSize && (nLineSpace % nPixelSize) != 0 )
@@ -4450,6 +4529,9 @@ CPLErr WriteRaster_internal( GDALRasterBandShadow *obj,
 		        (void *) buffer, buf_xsize, buf_ysize, buf_type, pixel_space, line_space );
 }
 
+SWIGINTERN GDALDatasetShadow *GDALRasterBandShadow_GetDataset(GDALRasterBandShadow *self){
+    return (GDALDatasetShadow*) GDALGetBandDataset(self);
+  }
 SWIGINTERN int GDALRasterBandShadow_GetBand(GDALRasterBandShadow *self){
     return GDALGetBandNumber(self);
   }
@@ -4590,32 +4672,25 @@ SWIGINTERN int GDALRasterBandShadow_GetMaskFlags(GDALRasterBandShadow *self){
 SWIGINTERN CPLErr GDALRasterBandShadow_CreateMaskBand(GDALRasterBandShadow *self,int nFlags){
       return GDALCreateMaskBand( self, nFlags );
   }
-SWIGINTERN CPLErr GDALRasterBandShadow_GetHistogram(GDALRasterBandShadow *self,double min=-0.5,double max=255.5,int buckets=256,int *panHistogram=NULL,int include_out_of_range=0,int approx_ok=1,GDALProgressFunc callback=NULL,void *callback_data=NULL){
+SWIGINTERN CPLErr GDALRasterBandShadow_GetHistogram(GDALRasterBandShadow *self,double min=-0.5,double max=255.5,int buckets=256,GUIntBig *panHistogram=NULL,int include_out_of_range=0,int approx_ok=1,GDALProgressFunc callback=NULL,void *callback_data=NULL){
     CPLErrorReset(); 
-    CPLErr err = GDALGetRasterHistogram( self, min, max, buckets, panHistogram,
+    CPLErr err = GDALGetRasterHistogramEx( self, min, max, buckets, panHistogram,
                                          include_out_of_range, approx_ok,
                                          callback, callback_data );
     return err;
   }
-SWIGINTERN CPLErr GDALRasterBandShadow_GetDefaultHistogram(GDALRasterBandShadow *self,double *min_ret=NULL,double *max_ret=NULL,int *buckets_ret=NULL,int **ppanHistogram=NULL,int force=1,GDALProgressFunc callback=NULL,void *callback_data=NULL){
-    return GDALGetDefaultHistogram( self, min_ret, max_ret, buckets_ret,
+SWIGINTERN CPLErr GDALRasterBandShadow_GetDefaultHistogram(GDALRasterBandShadow *self,double *min_ret=NULL,double *max_ret=NULL,int *buckets_ret=NULL,GUIntBig **ppanHistogram=NULL,int force=1,GDALProgressFunc callback=NULL,void *callback_data=NULL){
+    return GDALGetDefaultHistogramEx( self, min_ret, max_ret, buckets_ret,
                                     ppanHistogram, force, 
                                     callback, callback_data );
 }
-SWIGINTERN CPLErr GDALRasterBandShadow_SetDefaultHistogram(GDALRasterBandShadow *self,double min,double max,int buckets_in,int *panHistogram_in){
-    return GDALSetDefaultHistogram( self, min, max, 
-    	   			    buckets_in, panHistogram_in );
+SWIGINTERN CPLErr GDALRasterBandShadow_SetDefaultHistogram(GDALRasterBandShadow *self,double min,double max,int buckets_in,GUIntBig *panHistogram_in){
+    return GDALSetDefaultHistogramEx( self, min, max, 
+                                    buckets_in, panHistogram_in );
 }
 SWIGINTERN bool GDALRasterBandShadow_HasArbitraryOverviews(GDALRasterBandShadow *self){
       return (GDALHasArbitraryOverviews( self ) != 0) ? true : false;
   }
-
-SWIGINTERNINLINE PyObject*
-  SWIG_From_bool  (bool value)
-{
-  return PyBool_FromLong(value ? 1 : 0);
-}
-
 SWIGINTERN char **GDALRasterBandShadow_GetCategoryNames(GDALRasterBandShadow *self){
     return GDALGetRasterCategoryNames( self );
   }
@@ -4694,13 +4769,13 @@ SWIGINTERN CPLVirtualMemShadow *GDALRasterBandShadow_GetTiledVirtualMem(GDALRast
         vmemshadow->nBandCount = 1;
         return vmemshadow;
     }
-SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster1(GDALRasterBandShadow *self,int xoff,int yoff,int xsize,int ysize,void **buf,int *buf_xsize=0,int *buf_ysize=0,int *buf_type=0,int *buf_pixel_space=0,int *buf_line_space=0){
+SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster1(GDALRasterBandShadow *self,int xoff,int yoff,int xsize,int ysize,void **buf,int *buf_xsize=0,int *buf_ysize=0,int *buf_type=0,GIntBig *buf_pixel_space=0,GIntBig *buf_line_space=0,GDALRIOResampleAlg resample_alg=GRIORA_NearestNeighbour,GDALProgressFunc callback=NULL,void *callback_data=NULL){
     int nxsize = (buf_xsize==0) ? xsize : *buf_xsize;
     int nysize = (buf_ysize==0) ? ysize : *buf_ysize;
     GDALDataType ntype  = (buf_type==0) ? GDALGetRasterDataType(self)
                                         : (GDALDataType)*buf_type;
-    int pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
-    int line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
+    GIntBig pixel_space = (buf_pixel_space == 0) ? 0 : *buf_pixel_space;
+    GIntBig line_space = (buf_line_space == 0) ? 0 : *buf_line_space;
 
     GIntBig buf_size = ComputeBandRasterIOSize( nxsize, nysize, GDALGetDataTypeSize( ntype ) / 8,
                                             pixel_space, line_space, FALSE ); 
@@ -4714,6 +4789,7 @@ SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster1(GDALRasterBandShadow *self,in
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -4722,14 +4798,28 @@ SWIGINTERN CPLErr GDALRasterBandShadow_ReadRaster1(GDALRasterBandShadow *self,in
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
     char *data = PyString_AsString( (PyObject *)*buf ); 
 #endif
-    CPLErr eErr = GDALRasterIO( self, GF_Read, xoff, yoff, xsize, ysize, 
+
+    /* Should we clear the buffer in case there are hole in it ? */
+    if( line_space != 0 && pixel_space != 0 && line_space > pixel_space * nxsize )
+    {
+        memset(data, 0, buf_size);
+    }
+
+    GDALRasterIOExtraArg sExtraArg;
+    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
+    sExtraArg.eResampleAlg = resample_alg;
+    sExtraArg.pfnProgress = callback;
+    sExtraArg.pProgressData = callback_data;
+
+    CPLErr eErr = GDALRasterIOEx( self, GF_Read, xoff, yoff, xsize, ysize, 
                          (void *) data, nxsize, nysize, ntype, 
-                         pixel_space, line_space ); 
+                         pixel_space, line_space, &sExtraArg ); 
     if (eErr == CE_Failure)
     {
         Py_DECREF((PyObject*)*buf);
@@ -4749,6 +4839,7 @@ SWIGINTERN CPLErr GDALRasterBandShadow_ReadBlock(GDALRasterBandShadow *self,int
     if (*buf == NULL)
     {
         *buf = Py_None;
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -4757,6 +4848,7 @@ SWIGINTERN CPLErr GDALRasterBandShadow_ReadBlock(GDALRasterBandShadow *self,int
     *buf = (void *)PyString_FromStringAndSize( NULL, buf_size ); 
     if (*buf == NULL)
     {
+        if( !bUseExceptions ) PyErr_Clear();
         CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot allocate result buffer");
         return CE_Failure;
     }
@@ -4872,6 +4964,9 @@ SWIGINTERN int GDALRasterAttributeTableShadow_GetRowOfValue(GDALRasterAttributeT
 SWIGINTERN int GDALRasterAttributeTableShadow_ChangesAreWrittenToFile(GDALRasterAttributeTableShadow *self){
         return GDALRATChangesAreWrittenToFile( self );
     }
+SWIGINTERN void GDALRasterAttributeTableShadow_DumpReadable(GDALRasterAttributeTableShadow *self){
+        GDALRATDumpReadable( self, NULL );
+    }
 
 #include "gdalgrid.h"
 
@@ -5288,6 +5383,9 @@ static PyObject *XMLTreeToPyList( CPLXMLNode *psTree )
     int      nChildCount = 0, iChild;
     CPLXMLNode *psChild;
 
+    if( psTree == NULL )
+        return Py_None;
+
     for( psChild = psTree->psChild; 
          psChild != NULL; 
          psChild = psChild->psNext )
@@ -5363,6 +5461,17 @@ static CPLXMLNode *PyListToXMLTree( PyObject *pyList )
 }
 
 
+retStringAndCPLFree *GetJPEG2000StructureAsString( const char* pszFilename, char** options = NULL )
+{
+    CPLXMLNode* psNode = GDALGetJPEG2000Structure(pszFilename, options);
+    if( psNode == NULL )
+        return NULL;
+    char* pszXML = CPLSerializeXMLTree(psNode);
+    CPLDestroyXMLNode(psNode);
+    return pszXML;
+}
+
+
 int GetDriverCount() {
   return GDALGetDriverCount();
 }
@@ -5391,6 +5500,38 @@ GDALDatasetShadow* Open( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly
 }
 
 
+GDALDatasetShadow* OpenEx( char const* utf8_path, unsigned int nOpenFlags = 0,
+                           char** allowed_drivers = NULL, char** open_options = NULL,
+                           char** sibling_files = NULL ) {
+  CPLErrorReset();
+  GDALDatasetShadow *ds = GDALOpenEx( utf8_path, nOpenFlags, allowed_drivers,
+                                      open_options, sibling_files );
+  if( ds != NULL && CPLGetLastErrorType() == CE_Failure )
+  {
+      if ( GDALDereferenceDataset( ds ) <= 0 )
+          GDALClose(ds);
+      ds = NULL;
+  }
+  return (GDALDatasetShadow*) ds;
+}
+
+
+SWIGINTERN int
+SWIG_AsVal_unsigned_SS_int (PyObject * obj, unsigned int *val)
+{
+  unsigned long v;
+  int res = SWIG_AsVal_unsigned_SS_long (obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v > UINT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = static_cast< unsigned int >(v);
+    }
+  }  
+  return res;
+}
+
+
 GDALDatasetShadow* OpenShared( char const* utf8_path, GDALAccess eAccess = GA_ReadOnly ) {
   CPLErrorReset();
   GDALDatasetShadow *ds = GDALOpenShared( utf8_path, eAccess );
@@ -7254,7 +7395,7 @@ SWIGINTERN PyObject *_wrap_VSIFOpenL(PyObject *SWIGUNUSEDPARM(self), PyObject *a
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (VSILFILE *)VSIFOpenL((char const *)arg1,(char const *)arg2);
+    result = (VSILFILE *)wrapper_VSIFOpenL((char const *)arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7833,14 +7974,16 @@ SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata__SWIG_0(PyObject *SWIGUNUSEDP
     if ( PySequence_Check( obj1 ) ) {
       int size = PySequence_Size(obj1);
       for (int i = 0; i < size; i++) {
-        char *pszItem = NULL;
         PyObject* pyObj = PySequence_GetItem(obj1,i);
-        if ( ! PyArg_Parse( pyObj, "s", &pszItem ) ) {
+        int bFreeStr;
+        char* pszStr = GDALPythonObjectToCStr(pyObj, &bFreeStr);
+        if ( pszStr == NULL ) {
           Py_DECREF(pyObj);
           PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
           SWIG_fail;
         }
-        arg2 = CSLAddString( arg2, pszItem );
+        arg2 = CSLAddString( arg2, pszStr );
+        GDALPythonFreeCStr(pszStr, bFreeStr);
         Py_DECREF(pyObj);
       }
     }
@@ -7851,14 +7994,29 @@ SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata__SWIG_0(PyObject *SWIGUNUSEDP
         PyObject *item_list = PyMapping_Items( obj1 );
         for( int i=0; i<size; i++ ) {
           PyObject *it = PySequence_GetItem( item_list, i );
-          char *nm;
-          char *val;
-          if ( ! PyArg_ParseTuple( it, "ss", &nm, &val ) ) {
+          
+          PyObject *k, *v;
+          if ( ! PyArg_ParseTuple( it, "OO", &k, &v ) ) {
+            Py_DECREF(it);
+            PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
+            SWIG_fail;
+          }
+          
+          int bFreeK, bFreeV;
+          char* pszK = GDALPythonObjectToCStr(k, &bFreeK);
+          char* pszV = GDALPythonObjectToCStr(v, &bFreeV);
+          if( pszK == NULL || pszV == NULL )
+          {
+            GDALPythonFreeCStr(pszK, bFreeK);
+            GDALPythonFreeCStr(pszV, bFreeV);
             Py_DECREF(it);
             PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
             SWIG_fail;
           }
-          arg2 = CSLAddNameValue( arg2, nm, val );
+          arg2 = CSLAddNameValue( arg2, pszK, pszV );
+          
+          GDALPythonFreeCStr(pszK, bFreeK);
+          GDALPythonFreeCStr(pszV, bFreeV);
           Py_DECREF(it);
         }
         Py_DECREF(item_list);
@@ -8002,7 +8160,7 @@ SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata(PyObject *self, PyObject *arg
     if (_v) {
       {
         /* %typecheck(SWIG_TYPECHECK_POINTER) (char **dict) */
-        /* Note: we exclude explicitely strings, because they can be considered as a sequence of characters, */
+        /* Note: we exclude explicitly strings, because they can be considered as a sequence of characters, */
         /* which is not desirable since it makes it impossible to define bindings such as SetMetadata(string) and SetMetadata(array_of_string) */
         /* (see #4816) */
         _v = ((PyMapping_Check(argv[1]) || PySequence_Check(argv[1]) ) && !SWIG_CheckState(SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0)) ) ? 1 : 0;
@@ -8669,7 +8827,7 @@ SWIGINTERN PyObject *_wrap_Driver_Delete(PyObject *SWIGUNUSEDPARM(self), PyObjec
   int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  int result;
+  CPLErr result;
   
   if (!PyArg_ParseTuple(args,(char *)"OO:Driver_Delete",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDriverShadow, 0 |  0 );
@@ -8695,7 +8853,7 @@ SWIGINTERN PyObject *_wrap_Driver_Delete(PyObject *SWIGUNUSEDPARM(self), PyObjec
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALDriverShadow_Delete(arg1,(char const *)arg2);
+    result = (CPLErr)GDALDriverShadow_Delete(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8708,6 +8866,16 @@ SWIGINTERN PyObject *_wrap_Driver_Delete(PyObject *SWIGUNUSEDPARM(self), PyObjec
     /* %typemap(freearg) (const char *utf8_path) */
     GDALPythonFreeCStr(arg2, bToFree2);
   }
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
   {
@@ -8734,7 +8902,7 @@ SWIGINTERN PyObject *_wrap_Driver_Rename(PyObject *SWIGUNUSEDPARM(self), PyObjec
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  int result;
+  CPLErr result;
   
   if (!PyArg_ParseTuple(args,(char *)"OOO:Driver_Rename",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDriverShadow, 0 |  0 );
@@ -8766,7 +8934,7 @@ SWIGINTERN PyObject *_wrap_Driver_Rename(PyObject *SWIGUNUSEDPARM(self), PyObjec
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
+    result = (CPLErr)GDALDriverShadow_Rename(arg1,(char const *)arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8777,6 +8945,16 @@ SWIGINTERN PyObject *_wrap_Driver_Rename(PyObject *SWIGUNUSEDPARM(self), PyObjec
   resultobj = SWIG_From_int(static_cast< int >(result));
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
@@ -8801,7 +8979,7 @@ SWIGINTERN PyObject *_wrap_Driver_CopyFiles(PyObject *SWIGUNUSEDPARM(self), PyOb
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  int result;
+  CPLErr result;
   
   if (!PyArg_ParseTuple(args,(char *)"OOO:Driver_CopyFiles",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDriverShadow, 0 |  0 );
@@ -8833,7 +9011,7 @@ SWIGINTERN PyObject *_wrap_Driver_CopyFiles(PyObject *SWIGUNUSEDPARM(self), PyOb
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
+    result = (CPLErr)GDALDriverShadow_CopyFiles(arg1,(char const *)arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8844,6 +9022,16 @@ SWIGINTERN PyObject *_wrap_Driver_CopyFiles(PyObject *SWIGUNUSEDPARM(self), PyOb
   resultobj = SWIG_From_int(static_cast< int >(result));
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
@@ -10615,30 +10803,60 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPX(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GCPsToGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  int arg1 ;
+  GDAL_GCP *arg2 = (GDAL_GCP *) 0 ;
+  double *arg3 ;
+  int arg4 = (int) 1 ;
+  GDAL_GCP *tmpGCPList1 ;
+  double argout3[6] ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
+  PyObject * obj1 = 0 ;
+  RETURN_NONE result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_GCPX",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPX" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+  {
+    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+    arg3 = argout3;
   }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O|O:GCPsToGeoTransform",&obj0,&obj1)) SWIG_fail;
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    /* check if is List */
+    if ( !PySequence_Check(obj0) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg1 = PySequence_Size(obj0);
+    tmpGCPList1 = (GDAL_GCP*) malloc(arg1*sizeof(GDAL_GCP));
+    arg2 = tmpGCPList1;
+    for( int i = 0; i<arg1; i++ ) {
+      PyObject *o = PySequence_GetItem(obj0,i);
+      GDAL_GCP *item = 0;
+      SWIG_ConvertPtr( o, (void**)&item, SWIGTYPE_p_GDAL_GCP, SWIG_POINTER_EXCEPTION | 0 );
+      if ( ! item ) {
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      memcpy( (void*) tmpGCPList1, (void*) item, sizeof( GDAL_GCP ) );
+      ++tmpGCPList1;
+      Py_DECREF(o);
     }
   }
+  if (obj1) {
+    ecode4 = SWIG_AsVal_int(obj1, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GCPsToGeoTransform" "', argument " "4"" of type '" "int""'");
+    } 
+    arg4 = static_cast< int >(val4);
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)GDAL_GCP_get_GCPX(arg1);
+    result = GDALGCPsToGeoTransform(arg1,(GDAL_GCP const *)arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10646,45 +10864,60 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPX(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  /*%typemap(out) IF_FALSE_RETURN_NONE */
+  {
+    /* %typemap(argout) (double argout[ANY]) */
+    PyObject *out = CreateTupleFromDoubleArray( arg3, 6 );
+    resultobj = t_output_helper(resultobj,out);
+  }
+  {
+    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    if (arg2) {
+      free( (void*) arg2 );
+    }
+  }
+  {
+    /* %typemap(ret) IF_FALSE_RETURN_NONE */
+    if (result == 0 ) {
+      Py_XDECREF( resultobj );
+      resultobj = Py_None;
+      Py_INCREF(resultobj);
+    }
+    if (resultobj == 0) {
+      resultobj = Py_None;
+      Py_INCREF(resultobj);
+    }
+  }
   return resultobj;
 fail:
-  return NULL;
+  {
+    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    if (arg2) {
+      free( (void*) arg2 );
+    }
+  }
+  return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPX(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_VirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  double arg2 ;
+  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_GCPX",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_VirtualMem",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPX" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPX" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_VirtualMem" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
   }
+  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_GCPX(arg1,arg2);
+    delete_CPLVirtualMemShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10699,30 +10932,39 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPY(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_VirtualMem_GetAddr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
+  void **arg2 = (void **) 0 ;
+  size_t *arg3 = (size_t *) 0 ;
+  GDALDataType *arg4 = (GDALDataType *) 0 ;
+  int *arg5 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *ptr2 ;
+  size_t nsize2 ;
+  GDALDataType datatype2 ;
+  int readonly2 ;
   PyObject * obj0 = 0 ;
-  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_GCPY",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPY" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    /* %typemap(in,numinputs=0) (void** pptr, size_t* pnsize, GDALDataType* pdatatype, int* preadonly) */
+    arg2 = &ptr2;
+    arg3 = &nsize2;
+    arg4 = &datatype2;
+    arg5 = &readonly2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:VirtualMem_GetAddr",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "VirtualMem_GetAddr" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
   }
+  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)GDAL_GCP_get_GCPY(arg1);
+    CPLVirtualMemShadow_GetAddr(arg1,arg2,arg3,arg4,arg5);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10730,45 +10972,117 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPY(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_Py_Void();
+  {
+#if PY_VERSION_HEX >= 0x02070000 
+    /* %typemap(argout) (void** pptr, size_t* pnsize, GDALDataType* pdatatype, int* preadonly)*/
+    Py_buffer *buf=(Py_buffer*)malloc(sizeof(Py_buffer));
+    if (PyBuffer_FillInfo(buf,  obj0,  *(arg2), *(arg3), *(arg5), PyBUF_ND)) {
+      // error, handle
+    }
+    if( *(arg4) == GDT_Byte )
+    {
+      buf->format = "B";
+      buf->itemsize = 1;
+    }
+    else if( *(arg4) == GDT_Int16 )
+    {
+      buf->format = "h";
+      buf->itemsize = 2;
+    }
+    else if( *(arg4) == GDT_UInt16 )
+    {
+      buf->format = "H";
+      buf->itemsize = 2;
+    }
+    else if( *(arg4) == GDT_Int32 )
+    {
+      buf->format = "i";
+      buf->itemsize = 4;
+    }
+    else if( *(arg4) == GDT_UInt32 )
+    {
+      buf->format = "I";
+      buf->itemsize = 4;
+    }
+    else if( *(arg4) == GDT_Float32 )
+    {
+      buf->format = "f";
+      buf->itemsize = 4;
+    }
+    else if( *(arg4) == GDT_Float64 )
+    {
+      buf->format = "F";
+      buf->itemsize = 8;
+    }
+    else
+    {
+      buf->format = "B";
+      buf->itemsize = 1;
+    }
+    resultobj = PyMemoryView_FromBuffer(buf);
+#else
+    PyErr_SetString( PyExc_RuntimeError, "needs Python 2.7 or later" );
+    SWIG_fail;
+#endif
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPY(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_VirtualMem_Pin(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  double arg2 ;
+  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
+  size_t arg2 = (size_t) 0 ;
+  size_t arg3 = (size_t) 0 ;
+  int arg4 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
+  size_t val2 ;
   int ecode2 = 0 ;
+  size_t val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_GCPY",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O|OOO:VirtualMem_Pin",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPY" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "VirtualMem_Pin" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
   }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPY" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_size_t(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "VirtualMem_Pin" "', argument " "2"" of type '" "size_t""'");
+    } 
+    arg2 = static_cast< size_t >(val2);
+  }
+  if (obj2) {
+    ecode3 = SWIG_AsVal_size_t(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "VirtualMem_Pin" "', argument " "3"" of type '" "size_t""'");
+    } 
+    arg3 = static_cast< size_t >(val3);
+  }
+  if (obj3) {
+    ecode4 = SWIG_AsVal_int(obj3, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "VirtualMem_Pin" "', argument " "4"" of type '" "int""'");
+    } 
+    arg4 = static_cast< int >(val4);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_GCPY(arg1,arg2);
+    CPLVirtualMemShadow_Pin(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10783,30 +11097,31 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *VirtualMem_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_CPLVirtualMemShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_delete_AsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_GCPZ",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_AsyncReader",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPZ" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_AsyncReader" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)GDAL_GCP_get_GCPZ(arg1);
+    delete_GDALAsyncReaderShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10814,45 +11129,57 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPZ(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_AsyncReader_GetNextUpdatedRegion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
   double arg2 ;
+  int *arg3 = (int *) 0 ;
+  int *arg4 = (int *) 0 ;
+  int *arg5 = (int *) 0 ;
+  int *arg6 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
+  int temp3 ;
+  int res3 = SWIG_TMPOBJ ;
+  int temp4 ;
+  int res4 = SWIG_TMPOBJ ;
+  int temp5 ;
+  int res5 = SWIG_TMPOBJ ;
+  int temp6 ;
+  int res6 = SWIG_TMPOBJ ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  GDALAsyncStatusType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_GCPZ",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  arg3 = &temp3;
+  arg4 = &temp4;
+  arg5 = &temp5;
+  arg6 = &temp6;
+  if (!PyArg_ParseTuple(args,(char *)"OO:AsyncReader_GetNextUpdatedRegion",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPZ" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_GetNextUpdatedRegion" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
   }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
+  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   ecode2 = SWIG_AsVal_double(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPZ" "', argument " "2"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "AsyncReader_GetNextUpdatedRegion" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
-  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_GCPZ(arg1,arg2);
+    result = (GDALAsyncStatusType)GDALAsyncReaderShadow_GetNextUpdatedRegion(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10860,37 +11187,61 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPZ(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (SWIG_IsTmpObj(res3)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res4)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res5)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg5)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res5) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg5), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res6)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg6)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res6) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg6), SWIGTYPE_p_int, new_flags));
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPPixel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_AsyncReader_GetBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
+  void **arg2 = (void **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *pyObject2 = NULL ;
   PyObject * obj0 = 0 ;
-  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_GCPPixel",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPPixel" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    /* %typemap(in,numinputs=0) ( void **outPythonObject ) ( void *pyObject2 = NULL ) */
+    arg2 = &pyObject2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:AsyncReader_GetBuffer",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_GetBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)GDAL_GCP_get_GCPPixel(arg1);
+    GDALAsyncReaderShadow_GetBuffer(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10898,16 +11249,29 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPPixel(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) ( void **outPythonObject ) */
+    Py_XDECREF(resultobj);
+    if (*arg2)
+    {
+      resultobj = (PyObject*)*arg2;
+    }
+    else
+    {
+      resultobj = Py_None;
+      Py_INCREF(resultobj);
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPPixel(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_AsyncReader_LockBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
   double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -10915,28 +11279,56 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPPixel(PyObject *SWIGUNUSEDPARM(self),
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_GCPPixel",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:AsyncReader_LockBuffer",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPPixel" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_LockBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
   }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
+  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   ecode2 = SWIG_AsVal_double(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPPixel" "', argument " "2"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "AsyncReader_LockBuffer" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)GDALAsyncReaderShadow_LockBuffer(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_AsyncReader_UnlockBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:AsyncReader_UnlockBuffer",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_UnlockBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_GCPPixel(arg1,arg2);
+    GDALAsyncReaderShadow_UnlockBuffer(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10951,30 +11343,32 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPLine(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *AsyncReader_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_Dataset_RasterXSize_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_GCPLine",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterXSize_get",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_GCPLine" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterXSize_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)GDAL_GCP_get_GCPLine(arg1);
+    result = (int)GDALDatasetShadow_RasterXSize_get(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10982,45 +11376,32 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_GCPLine(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPLine(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_RasterYSize_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  double arg2 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_GCPLine",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterYSize_get",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_GCPLine" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GDAL_GCP_set_GCPLine" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterYSize_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_GCPLine(arg1,arg2);
+    result = (int)GDALDatasetShadow_RasterYSize_get(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11028,37 +11409,32 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_set_GCPLine(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_Info(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_RasterCount_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_Info",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterCount_get",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_Info" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterCount_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)GDAL_GCP_get_Info(arg1);
+    result = (int)GDALDatasetShadow_RasterCount_get(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11066,46 +11442,31 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_Info(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_Info(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_Dataset(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  char *arg2 = (char *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_Info",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_Dataset",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_Info" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GDAL_GCP_set_Info" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Dataset" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_Info(arg1,(char const *)arg2);
+    delete_GDALDatasetShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11114,38 +11475,31 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_set_Info(PyObject *SWIGUNUSEDPARM(self), PyO
     }
   }
   resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_get_Id(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetDriver(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  GDALDriverShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GDAL_GCP_get_Id",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetDriver",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_get_Id" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetDriver" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)GDAL_GCP_get_Id(arg1);
+    result = (GDALDriverShadow *)GDALDatasetShadow_GetDriver(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11153,46 +11507,41 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_get_Id(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDriverShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GDAL_GCP_set_Id(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetRasterBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDAL_GCP *arg1 = (GDAL_GCP *) 0 ;
-  char *arg2 = (char *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  GDALRasterBandShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GDAL_GCP_set_Id",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDAL_GCP, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_GetRasterBand",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GDAL_GCP_set_Id" "', argument " "1"" of type '" "GDAL_GCP *""'"); 
-  }
-  arg1 = reinterpret_cast< GDAL_GCP * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GDAL_GCP_set_Id" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetRasterBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetRasterBand" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDAL_GCP_set_Id(arg1,(char const *)arg2);
+    result = (GDALRasterBandShadow *)GDALDatasetShadow_GetRasterBand(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11200,69 +11549,32 @@ SWIGINTERN PyObject *_wrap_GDAL_GCP_set_Id(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GCPsToGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  int arg1 ;
-  GDAL_GCP *arg2 = (GDAL_GCP *) 0 ;
-  double *arg3 ;
-  int arg4 = (int) 1 ;
-  GDAL_GCP *tmpGCPList1 ;
-  double argout3[6] ;
-  int val4 ;
-  int ecode4 = 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  RETURN_NONE result;
+  char *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-    arg3 = argout3;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O|O:GCPsToGeoTransform",&obj0,&obj1)) SWIG_fail;
-  {
-    /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    /* check if is List */
-    if ( !PySequence_Check(obj0) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
-    }
-    arg1 = PySequence_Size(obj0);
-    tmpGCPList1 = (GDAL_GCP*) malloc(arg1*sizeof(GDAL_GCP));
-    arg2 = tmpGCPList1;
-    for( int i = 0; i<arg1; i++ ) {
-      PyObject *o = PySequence_GetItem(obj0,i);
-      GDAL_GCP *item = 0;
-      SWIG_ConvertPtr( o, (void**)&item, SWIGTYPE_p_GDAL_GCP, SWIG_POINTER_EXCEPTION | 0 );
-      if ( ! item ) {
-        Py_DECREF(o);
-        SWIG_fail;
-      }
-      memcpy( (void*) tmpGCPList1, (void*) item, sizeof( GDAL_GCP ) );
-      ++tmpGCPList1;
-      Py_DECREF(o);
-    }
-  }
-  if (obj1) {
-    ecode4 = SWIG_AsVal_int(obj1, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "GCPsToGeoTransform" "', argument " "4"" of type '" "int""'");
-    } 
-    arg4 = static_cast< int >(val4);
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetProjection",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = GDALGCPsToGeoTransform(arg1,(GDAL_GCP const *)arg2,arg3,arg4);
+    result = (char *)GDALDatasetShadow_GetProjection(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11270,60 +11582,32 @@ SWIGINTERN PyObject *_wrap_GCPsToGeoTransform(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  /*%typemap(out) IF_FALSE_RETURN_NONE */
-  {
-    /* %typemap(argout) (double argout[ANY]) */
-    PyObject *out = CreateTupleFromDoubleArray( arg3, 6 );
-    resultobj = t_output_helper(resultobj,out);
-  }
-  {
-    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    if (arg2) {
-      free( (void*) arg2 );
-    }
-  }
-  {
-    /* %typemap(ret) IF_FALSE_RETURN_NONE */
-    if (result == 0 ) {
-      Py_XDECREF( resultobj );
-      resultobj = Py_None;
-      Py_INCREF(resultobj);
-    }
-    if (resultobj == 0) {
-      resultobj = Py_None;
-      Py_INCREF(resultobj);
-    }
-  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    if (arg2) {
-      free( (void*) arg2 );
-    }
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_delete_VirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetProjectionRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_VirtualMem",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetProjectionRef",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_VirtualMem" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetProjectionRef" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
-  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_CPLVirtualMemShadow(arg1);
+    result = (char *)GDALDatasetShadow_GetProjectionRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11331,46 +11615,47 @@ SWIGINTERN PyObject *_wrap_delete_VirtualMem(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_VirtualMem_GetAddr(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_SetProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
-  void **arg2 = (void **) 0 ;
-  size_t *arg3 = (size_t *) 0 ;
-  GDALDataType *arg4 = (GDALDataType *) 0 ;
-  int *arg5 = (int *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *ptr2 ;
-  size_t nsize2 ;
-  GDALDataType datatype2 ;
-  int readonly2 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  CPLErr result;
   
-  {
-    /* %typemap(in,numinputs=0) (void** pptr, size_t* pnsize, GDALDataType* pdatatype, int* preadonly) */
-    arg2 = &ptr2;
-    arg3 = &nsize2;
-    arg4 = &datatype2;
-    arg5 = &readonly2;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O:VirtualMem_GetAddr",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_SetProjection",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "VirtualMem_GetAddr" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_SetProjection" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    CPLVirtualMemShadow_GetAddr(arg1,arg2,arg3,arg4,arg5);
+    result = (CPLErr)GDALDatasetShadow_SetProjection(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11378,117 +11663,73 @@ SWIGINTERN PyObject *_wrap_VirtualMem_GetAddr(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   {
-#if PY_VERSION_HEX >= 0x02070000 
-    /* %typemap(argout) (void** pptr, size_t* pnsize, GDALDataType* pdatatype, int* preadonly)*/
-    Py_buffer *buf=(Py_buffer*)malloc(sizeof(Py_buffer));
-    if (PyBuffer_FillInfo(buf,  obj0,  *(arg2), *(arg3), *(arg5), PyBUF_ND)) {
-      // error, handle
-    }
-    if( *(arg4) == GDT_Byte )
-    {
-      buf->format = "B";
-      buf->itemsize = 1;
-    }
-    else if( *(arg4) == GDT_Int16 )
-    {
-      buf->format = "h";
-      buf->itemsize = 2;
-    }
-    else if( *(arg4) == GDT_UInt16 )
-    {
-      buf->format = "H";
-      buf->itemsize = 2;
-    }
-    else if( *(arg4) == GDT_Int32 )
-    {
-      buf->format = "i";
-      buf->itemsize = 4;
-    }
-    else if( *(arg4) == GDT_UInt32 )
-    {
-      buf->format = "I";
-      buf->itemsize = 4;
-    }
-    else if( *(arg4) == GDT_Float32 )
-    {
-      buf->format = "f";
-      buf->itemsize = 4;
-    }
-    else if( *(arg4) == GDT_Float64 )
-    {
-      buf->format = "F";
-      buf->itemsize = 8;
-    }
-    else
-    {
-      buf->format = "B";
-      buf->itemsize = 1;
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
     }
-    resultobj = PyMemoryView_FromBuffer(buf);
-#else
-    PyErr_SetString( PyExc_RuntimeError, "needs Python 2.7 or later" );
-    SWIG_fail;
-#endif
   }
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_VirtualMem_Pin(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  CPLVirtualMemShadow *arg1 = (CPLVirtualMemShadow *) 0 ;
-  size_t arg2 = (size_t) 0 ;
-  size_t arg3 = (size_t) 0 ;
-  int arg4 = (int) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  double *arg2 ;
+  int *arg3 = (int *) 0 ;
+  int *arg4 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  size_t val2 ;
-  int ecode2 = 0 ;
-  size_t val3 ;
-  int ecode3 = 0 ;
+  double argout2[6] ;
+  int isvalid2 ;
   int val4 ;
-  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "can_return_null", NULL 
+  };
   
-  if (!PyArg_ParseTuple(args,(char *)"O|OOO:VirtualMem_Pin",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_CPLVirtualMemShadow, 0 |  0 );
+  {
+    /* %typemap(in,numinputs=0) (double argout2[6], int* isvalid2) */
+    arg2 = argout2;
+    arg3 = &isvalid2;
+  }
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Dataset_GetGeoTransform",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "VirtualMem_Pin" "', argument " "1"" of type '" "CPLVirtualMemShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGeoTransform" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
-  arg1 = reinterpret_cast< CPLVirtualMemShadow * >(argp1);
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   if (obj1) {
-    ecode2 = SWIG_AsVal_size_t(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "VirtualMem_Pin" "', argument " "2"" of type '" "size_t""'");
-    } 
-    arg2 = static_cast< size_t >(val2);
-  }
-  if (obj2) {
-    ecode3 = SWIG_AsVal_size_t(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "VirtualMem_Pin" "', argument " "3"" of type '" "size_t""'");
-    } 
-    arg3 = static_cast< size_t >(val3);
-  }
-  if (obj3) {
-    ecode4 = SWIG_AsVal_int(obj3, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "VirtualMem_Pin" "', argument " "4"" of type '" "int""'");
-    } 
-    arg4 = static_cast< int >(val4);
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj1 == Py_None ) {
+        arg4 = 0;
+      }
+      else if ( PyArg_Parse( obj1,"i" ,&val4 ) ) {
+        arg4 = (int *) &val4;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+        SWIG_fail;
+      }
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    CPLVirtualMemShadow_Pin(arg1,arg2,arg3,arg4);
+    GDALDatasetShadow_GetGeoTransform(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11497,37 +11738,70 @@ SWIGINTERN PyObject *_wrap_VirtualMem_Pin(PyObject *SWIGUNUSEDPARM(self), PyObje
     }
   }
   resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *VirtualMem_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_CPLVirtualMemShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
+  {
+    /* %typemap(argout) (double argout[6], int* isvalid)  */
+    PyObject *r;
+    if ( !*arg3 ) {
+      Py_INCREF(Py_None);
+      r = Py_None;
+    }
+    else {
+      r = CreateTupleFromDoubleArray(arg2, 6);
+    }
+    resultobj = t_output_helper(resultobj,r);
+  }
+  return resultobj;
+fail:
+  return NULL;
 }
 
-SWIGINTERN PyObject *_wrap_delete_AsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+
+SWIGINTERN PyObject *_wrap_Dataset_SetGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  double *arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double argin2[6] ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_AsyncReader",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_SetGeoTransform",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_AsyncReader" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetGeoTransform" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  {
+    /* %typemap(in) (double argin2[ANY]) */
+    arg2 = argin2;
+    if (! PySequence_Check(obj1) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    int seq_size = PySequence_Size(obj1);
+    if ( seq_size != 6 ) {
+      PyErr_SetString(PyExc_TypeError, "sequence must have length ##size");
+      SWIG_fail;
+    }
+    for (unsigned int i=0; i<6; i++) {
+      PyObject *o = PySequence_GetItem(obj1,i);
+      double val;
+      if ( !PyArg_Parse(o, "d", &val ) ) {
+        PyErr_SetString(PyExc_TypeError, "not a number");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      arg2[i] =  val;
+      Py_DECREF(o);
+    }
   }
-  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_GDALAsyncReaderShadow(arg1);
+    result = (CPLErr)GDALDatasetShadow_SetGeoTransform(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11535,57 +11809,125 @@ SWIGINTERN PyObject *_wrap_delete_AsyncReader(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_AsyncReader_GetNextUpdatedRegion(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_BuildOverviews(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
-  double arg2 ;
-  int *arg3 = (int *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  char *arg2 = (char *) "NEAREST" ;
+  int arg3 = (int) 0 ;
   int *arg4 = (int *) 0 ;
-  int *arg5 = (int *) 0 ;
-  int *arg6 = (int *) 0 ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  int temp3 ;
-  int res3 = SWIG_TMPOBJ ;
-  int temp4 ;
-  int res4 = SWIG_TMPOBJ ;
-  int temp5 ;
-  int res5 = SWIG_TMPOBJ ;
-  int temp6 ;
-  int res6 = SWIG_TMPOBJ ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  GDALAsyncStatusType result;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "resampling",(char *) "overviewlist",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  int result;
   
-  arg3 = &temp3;
-  arg4 = &temp4;
-  arg5 = &temp5;
-  arg6 = &temp6;
-  if (!PyArg_ParseTuple(args,(char *)"OO:AsyncReader_GetNextUpdatedRegion",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:Dataset_BuildOverviews",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_GetNextUpdatedRegion" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_BuildOverviews" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_BuildOverviews" "', argument " "2"" of type '" "char const *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
+  }
+  if (obj2) {
+    {
+      /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+      /* check if is List */
+      if ( !PySequence_Check(obj2) ) {
+        PyErr_SetString(PyExc_TypeError, "not a sequence");
+        SWIG_fail;
+      }
+      arg3 = PySequence_Size(obj2);
+      arg4 = (int*) malloc(arg3*sizeof(int));
+      for( int i = 0; i<arg3; i++ ) {
+        PyObject *o = PySequence_GetItem(obj2,i);
+        if ( !PyArg_Parse(o,"i",&arg4[i]) ) {
+          PyErr_SetString(PyExc_TypeError, "not an integer");
+          Py_DECREF(o);
+          SWIG_fail;
+        }
+        Py_DECREF(o);
+      }
+    }
+  }
+  if (obj3) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj3 && obj3 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj3, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj3)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj3;
+          arg5 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj4) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj4 ;
+    }
   }
-  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "AsyncReader_GetNextUpdatedRegion" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (GDALAsyncStatusType)GDALAsyncReaderShadow_GetNextUpdatedRegion(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (int)GDALDatasetShadow_BuildOverviews(arg1,(char const *)arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11594,115 +11936,57 @@ SWIGINTERN PyObject *_wrap_AsyncReader_GetNextUpdatedRegion(PyObject *SWIGUNUSED
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  if (SWIG_IsTmpObj(res3)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res4)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res5)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg5)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res5) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg5), SWIGTYPE_p_int, new_flags));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
   }
-  if (SWIG_IsTmpObj(res6)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg6)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res6) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg6), SWIGTYPE_p_int, new_flags));
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
   }
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_AsyncReader_GetBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetGCPCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
-  void **arg2 = (void **) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *pyObject2 = NULL ;
   PyObject * obj0 = 0 ;
+  int result;
   
-  {
-    /* %typemap(in,numinputs=0) ( void **outPythonObject ) ( void *pyObject2 = NULL ) */
-    arg2 = &pyObject2;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O:AsyncReader_GetBuffer",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_GetBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    GDALAsyncReaderShadow_GetBuffer(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) ( void **outPythonObject ) */
-    Py_XDECREF(resultobj);
-    if (*arg2)
-    {
-      resultobj = (PyObject*)*arg2;
-    }
-    else
-    {
-      resultobj = Py_None;
-      Py_INCREF(resultobj);
-    }
-  }
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_AsyncReader_LockBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:AsyncReader_LockBuffer",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_LockBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPCount" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
-  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "AsyncReader_LockBuffer" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALAsyncReaderShadow_LockBuffer(arg1,arg2);
+    result = (int)GDALDatasetShadow_GetGCPCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11717,24 +12001,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_AsyncReader_UnlockBuffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetGCPProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  GDALAsyncReaderShadow *arg1 = (GDALAsyncReaderShadow *) 0 ;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:AsyncReader_UnlockBuffer",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPProjection",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "AsyncReader_UnlockBuffer" "', argument " "1"" of type '" "GDALAsyncReaderShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
-  arg1 = reinterpret_cast< GDALAsyncReaderShadow * >(argp1);
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDALAsyncReaderShadow_UnlockBuffer(arg1);
+    result = (char *)GDALDatasetShadow_GetGCPProjection(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11742,39 +12027,40 @@ SWIGINTERN PyObject *_wrap_AsyncReader_UnlockBuffer(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *AsyncReader_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_Dataset_RasterXSize_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int *arg2 = (int *) 0 ;
+  GDAL_GCP **arg3 = (GDAL_GCP **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int nGCPs2 = 0 ;
+  GDAL_GCP *pGCPs2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterXSize_get",&obj0)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=0) (int *nGCPs2, GDAL_GCP const **pGCPs2 ) */
+    arg2 = &nGCPs2;
+    arg3 = &pGCPs2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPs",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterXSize_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPs" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALDatasetShadow_RasterXSize_get(arg1);
+    GDALDatasetShadow_GetGCPs(arg1,arg2,(GDAL_GCP const **)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11782,65 +12068,87 @@ SWIGINTERN PyObject *_wrap_Dataset_RasterXSize_get(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (int *nGCPs, GDAL_GCP const **pGCPs ) */
+    PyObject *dict = PyTuple_New( *arg2 );
+    for( int i = 0; i < *arg2; i++ ) {
+      GDAL_GCP *o = new_GDAL_GCP( (*arg3)[i].dfGCPX,
+        (*arg3)[i].dfGCPY,
+        (*arg3)[i].dfGCPZ,
+        (*arg3)[i].dfGCPPixel,
+        (*arg3)[i].dfGCPLine,
+        (*arg3)[i].pszInfo,
+        (*arg3)[i].pszId );
+      
+      PyTuple_SetItem(dict, i, 
+        SWIG_NewPointerObj((void*)o,SWIGTYPE_p_GDAL_GCP,1) );
+    }
+    Py_DECREF(resultobj);
+    resultobj = dict;
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_RasterYSize_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_SetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 ;
+  GDAL_GCP *arg3 = (GDAL_GCP *) 0 ;
+  char *arg4 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  GDAL_GCP *tmpGCPList2 ;
+  int res4 ;
+  char *buf4 = 0 ;
+  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterYSize_get",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Dataset_SetGCPs",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterYSize_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetGCPs" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
+    /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    /* check if is List */
+    if ( !PySequence_Check(obj1) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
     }
-    result = (int)GDALDatasetShadow_RasterYSize_get(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+    arg2 = PySequence_Size(obj1);
+    tmpGCPList2 = (GDAL_GCP*) malloc(arg2*sizeof(GDAL_GCP));
+    arg3 = tmpGCPList2;
+    for( int i = 0; i<arg2; i++ ) {
+      PyObject *o = PySequence_GetItem(obj1,i);
+      GDAL_GCP *item = 0;
+      SWIG_ConvertPtr( o, (void**)&item, SWIGTYPE_p_GDAL_GCP, SWIG_POINTER_EXCEPTION | 0 );
+      if ( ! item ) {
+        Py_DECREF(o);
+        SWIG_fail;
       }
+      memcpy( (void*) tmpGCPList2, (void*) item, sizeof( GDAL_GCP ) );
+      ++tmpGCPList2;
+      Py_DECREF(o);
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_RasterCount_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RasterCount_get",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RasterCount_get" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  res4 = SWIG_AsCharPtrAndSize(obj2, &buf4, NULL, &alloc4);
+  if (!SWIG_IsOK(res4)) {
+    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Dataset_SetGCPs" "', argument " "4"" of type '" "char const *""'");
   }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  arg4 = reinterpret_cast< char * >(buf4);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALDatasetShadow_RasterCount_get(arg1);
+    result = (CPLErr)GDALDatasetShadow_SetGCPs(arg1,arg2,(GDAL_GCP const *)arg3,(char const *)arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11849,63 +12157,54 @@ SWIGINTERN PyObject *_wrap_Dataset_RasterCount_get(PyObject *SWIGUNUSEDPARM(self
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_delete_Dataset(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_Dataset",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Dataset" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
+    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    if (arg3) {
+      free( (void*) arg3 );
     }
-    delete_GDALDatasetShadow(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  }
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
       }
     }
   }
-  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
+    if (arg3) {
+      free( (void*) arg3 );
+    }
+  }
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetDriver(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_FlushCache(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  GDALDriverShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetDriver",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_FlushCache",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetDriver" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_FlushCache" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (GDALDriverShadow *)GDALDatasetShadow_GetDriver(arg1);
+    GDALDatasetShadow_FlushCache(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11913,74 +12212,94 @@ SWIGINTERN PyObject *_wrap_Dataset_GetDriver(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDriverShadow, 0 |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetRasterBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_AddBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int arg2 ;
+  GDALDataType arg2 = (GDALDataType) GDT_Byte ;
+  char **arg3 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  GDALRasterBandShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_GetRasterBand",&obj0,&obj1)) SWIG_fail;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "datatype",(char *) "options", NULL 
+  };
+  CPLErr result;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:Dataset_AddBand",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetRasterBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_AddBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetRasterBand" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (GDALRasterBandShadow *)GDALDatasetShadow_GetRasterBand(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_AddBand" "', argument " "2"" of type '" "GDALDataType""'");
+    } 
+    arg2 = static_cast< GDALDataType >(val2);
+  }
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_GetProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetProjection",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)GDALDatasetShadow_GetProjection(arg1);
+    result = (CPLErr)GDALDatasetShadow_AddBand(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11988,80 +12307,59 @@ SWIGINTERN PyObject *_wrap_Dataset_GetProjection(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_GetProjectionRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetProjectionRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetProjectionRef" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
   }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (char *)GDALDatasetShadow_GetProjectionRef(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_SetProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_CreateMaskBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_SetProjection",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_CreateMaskBand",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CreateMaskBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_SetProjection" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_CreateMaskBand" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_SetProjection(arg1,(char const *)arg2);
+    result = (CPLErr)GDALDatasetShadow_CreateMaskBand(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12070,7 +12368,6 @@ SWIGINTERN PyObject *_wrap_Dataset_SetProjection(PyObject *SWIGUNUSEDPARM(self),
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   {
     /* %typemap(ret) CPLErr */
     if ( bUseExceptions == 0 ) {
@@ -12083,59 +12380,29 @@ SWIGINTERN PyObject *_wrap_Dataset_SetProjection(PyObject *SWIGUNUSEDPARM(self),
   }
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_GetFileList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  double *arg2 ;
-  int *arg3 = (int *) 0 ;
-  int *arg4 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double argout2[6] ;
-  int isvalid2 ;
-  int val4 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "can_return_null", NULL 
-  };
+  char **result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout2[6], int* isvalid2) */
-    arg2 = argout2;
-    arg3 = &isvalid2;
-  }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Dataset_GetGeoTransform",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetFileList",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGeoTransform" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetFileList" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  if (obj1) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj1 == Py_None ) {
-        arg4 = 0;
-      }
-      else if ( PyArg_Parse( obj1,"i" ,&val4 ) ) {
-        arg4 = (int *) &val4;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
-        SWIG_fail;
-      }
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDALDatasetShadow_GetGeoTransform(arg1,arg2,arg3,arg4);
+    result = (char **)GDALDatasetShadow_GetFileList(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12143,18 +12410,22 @@ SWIGINTERN PyObject *_wrap_Dataset_GetGeoTransform(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_Py_Void();
   {
-    /* %typemap(argout) (double argout[6], int* isvalid)  */
-    PyObject *r;
-    if ( !*arg3 ) {
-      Py_INCREF(Py_None);
-      r = Py_None;
+    /* %typemap(out) char **CSL -> ( string ) */
+    char **stringarray = result;
+    if ( stringarray == NULL ) {
+      resultobj = Py_None;
+      Py_INCREF( resultobj );
     }
     else {
-      r = CreateTupleFromDoubleArray(arg2, 6);
+      int len = CSLCount( stringarray );
+      resultobj = PyList_New( len );
+      for ( int i = 0; i < len; ++i ) {
+        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
+        PyList_SetItem(resultobj, i, o );
+      }
     }
-    resultobj = t_output_helper(resultobj,r);
+    CSLDestroy(result);
   }
   return resultobj;
 fail:
@@ -12162,132 +12433,181 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_SetGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_WriteRaster(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  double *arg2 ;
+  int arg2 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  GIntBig arg6 ;
+  char *arg7 = (char *) 0 ;
+  int *arg8 = (int *) 0 ;
+  int *arg9 = (int *) 0 ;
+  GDALDataType *arg10 = (GDALDataType *) 0 ;
+  int arg11 = (int) 0 ;
+  int *arg12 = (int *) 0 ;
+  int *arg13 = (int *) 0 ;
+  int *arg14 = (int *) 0 ;
+  int *arg15 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double argin2[6] ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  CPLErr result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_SetGeoTransform",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetGeoTransform" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int alloc6 = 0 ;
+  int val8 ;
+  int val9 ;
+  int val10 ;
+  int val13 ;
+  int val14 ;
+  int val15 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
+  PyObject * obj11 = 0 ;
+  PyObject * obj12 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_len",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "band_list",(char *) "buf_pixel_space",(char *) "buf_line_space",(char *) "buf_band_space", NULL 
+  };
+  CPLErr result;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOO|OOOOOOO:Dataset_WriteRaster",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_WriteRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_WriteRaster" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_WriteRaster" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_WriteRaster" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_WriteRaster" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
   {
-    /* %typemap(in) (double argin2[ANY]) */
-    arg2 = argin2;
-    if (! PySequence_Check(obj1) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
+    /* %typemap(in,numinputs=1) (GIntBig nLen, char *pBuf ) */
+#if PY_VERSION_HEX>=0x03000000
+    if (PyUnicode_Check(obj5))
+    {
+      size_t safeLen = 0;
+      int ret = SWIG_AsCharPtrAndSize(obj5, (char**) &arg7, &safeLen, &alloc6);
+      if (!SWIG_IsOK(ret)) {
+        SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
+      }
+      
+      if (safeLen) safeLen--;
+      arg6 = (GIntBig) safeLen;
+    }
+    else if (PyBytes_Check(obj5))
+    {
+      Py_ssize_t safeLen = 0;
+      PyBytes_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
+      arg6 = (GIntBig) safeLen;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
       SWIG_fail;
     }
-    int seq_size = PySequence_Size(obj1);
-    if ( seq_size != 6 ) {
-      PyErr_SetString(PyExc_TypeError, "sequence must have length ##size");
+#else
+    if (PyString_Check(obj5))
+    {
+      Py_ssize_t safeLen = 0;
+      PyString_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
+      arg6 = (GIntBig) safeLen;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a string");
       SWIG_fail;
     }
-    for (unsigned int i=0; i<6; i++) {
-      PyObject *o = PySequence_GetItem(obj1,i);
-      double val;
-      if ( !PyArg_Parse(o, "d", &val ) ) {
-        PyErr_SetString(PyExc_TypeError, "not a number");
-        Py_DECREF(o);
+#endif
+  }
+  if (obj6) {
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj6 == Py_None ) {
+        arg8 = 0;
+      }
+      else if ( PyArg_Parse( obj6,"i" ,&val8 ) ) {
+        arg8 = (int *) &val8;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
         SWIG_fail;
       }
-      arg2[i] =  val;
-      Py_DECREF(o);
     }
   }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (CPLErr)GDALDatasetShadow_SetGeoTransform(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  if (obj7) {
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj7 == Py_None ) {
+        arg9 = 0;
       }
-    }
-  }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  {
-    /* %typemap(ret) CPLErr */
-    if ( bUseExceptions == 0 ) {
-      /* We're not using exceptions.  And no error has occurred */
-      if ( resultobj == 0 ) {
-        /* No other return values set so return ErrorCode */
-        resultobj = PyInt_FromLong(result);
+      else if ( PyArg_Parse( obj7,"i" ,&val9 ) ) {
+        arg9 = (int *) &val9;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+        SWIG_fail;
       }
     }
   }
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_BuildOverviews(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  char *arg2 = (char *) "NEAREST" ;
-  int arg3 = (int) 0 ;
-  int *arg4 = (int *) 0 ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "resampling",(char *) "overviewlist",(char *) "callback",(char *) "callback_data", NULL 
-  };
-  int result;
-  
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:Dataset_BuildOverviews",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_BuildOverviews" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  if (obj1) {
-    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_BuildOverviews" "', argument " "2"" of type '" "char const *""'");
+  if (obj8) {
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj8 == Py_None ) {
+        arg10 = 0;
+      }
+      else if ( PyArg_Parse( obj8,"i" ,&val10 ) ) {
+        arg10 = (GDALDataType *) &val10;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+        SWIG_fail;
+      }
     }
-    arg2 = reinterpret_cast< char * >(buf2);
   }
-  if (obj2) {
+  if (obj9) {
     {
       /* %typemap(in,numinputs=1) (int nList, int* pList)*/
       /* check if is List */
-      if ( !PySequence_Check(obj2) ) {
+      if ( !PySequence_Check(obj9) ) {
         PyErr_SetString(PyExc_TypeError, "not a sequence");
         SWIG_fail;
       }
-      arg3 = PySequence_Size(obj2);
-      arg4 = (int*) malloc(arg3*sizeof(int));
-      for( int i = 0; i<arg3; i++ ) {
-        PyObject *o = PySequence_GetItem(obj2,i);
-        if ( !PyArg_Parse(o,"i",&arg4[i]) ) {
+      arg11 = PySequence_Size(obj9);
+      arg12 = (int*) malloc(arg11*sizeof(int));
+      for( int i = 0; i<arg11; i++ ) {
+        PyObject *o = PySequence_GetItem(obj9,i);
+        if ( !PyArg_Parse(o,"i",&arg12[i]) ) {
           PyErr_SetString(PyExc_TypeError, "not an integer");
           Py_DECREF(o);
           SWIG_fail;
@@ -12296,265 +12616,56 @@ SWIGINTERN PyObject *_wrap_Dataset_BuildOverviews(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  if (obj3) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj3 && obj3 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj3, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj3)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj3;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
-  }
-  if (obj4) {
+  if (obj10) {
     {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj4 ;
-    }
-  }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (int)GDALDatasetShadow_BuildOverviews(arg1,(char const *)arg2,arg3,arg4,arg5,arg6);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg4) {
-      free((void*) arg4);
-    }
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg4) {
-      free((void*) arg4);
-    }
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_GetGCPCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPCount" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (int)GDALDatasetShadow_GetGCPCount(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj10 == Py_None ) {
+        arg13 = 0;
       }
-    }
-  }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_GetGCPProjection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPProjection",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPProjection" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (char *)GDALDatasetShadow_GetGCPProjection(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      else if ( PyArg_Parse( obj10,"i" ,&val13 ) ) {
+        arg13 = (int *) &val13;
       }
-    }
-  }
-  resultobj = SWIG_FromCharPtr((const char *)result);
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_GetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int *arg2 = (int *) 0 ;
-  GDAL_GCP **arg3 = (GDAL_GCP **) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int nGCPs2 = 0 ;
-  GDAL_GCP *pGCPs2 = 0 ;
-  PyObject * obj0 = 0 ;
-  
-  {
-    /* %typemap(in,numinputs=0) (int *nGCPs2, GDAL_GCP const **pGCPs2 ) */
-    arg2 = &nGCPs2;
-    arg3 = &pGCPs2;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetGCPs",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetGCPs" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    GDALDatasetShadow_GetGCPs(arg1,arg2,(GDAL_GCP const **)arg3);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+        SWIG_fail;
       }
-    }
-  }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (int *nGCPs, GDAL_GCP const **pGCPs ) */
-    PyObject *dict = PyTuple_New( *arg2 );
-    for( int i = 0; i < *arg2; i++ ) {
-      GDAL_GCP *o = new_GDAL_GCP( (*arg3)[i].dfGCPX,
-        (*arg3)[i].dfGCPY,
-        (*arg3)[i].dfGCPZ,
-        (*arg3)[i].dfGCPPixel,
-        (*arg3)[i].dfGCPLine,
-        (*arg3)[i].pszInfo,
-        (*arg3)[i].pszId );
-      
-      PyTuple_SetItem(dict, i, 
-        SWIG_NewPointerObj((void*)o,SWIGTYPE_p_GDAL_GCP,1) );
-    }
-    Py_DECREF(resultobj);
-    resultobj = dict;
-  }
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_SetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int arg2 ;
-  GDAL_GCP *arg3 = (GDAL_GCP *) 0 ;
-  char *arg4 = (char *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  GDAL_GCP *tmpGCPList2 ;
-  int res4 ;
-  char *buf4 = 0 ;
-  int alloc4 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  CPLErr result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Dataset_SetGCPs",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetGCPs" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  {
-    /* %typemap(in,numinputs=1) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    /* check if is List */
-    if ( !PySequence_Check(obj1) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
-    }
-    arg2 = PySequence_Size(obj1);
-    tmpGCPList2 = (GDAL_GCP*) malloc(arg2*sizeof(GDAL_GCP));
-    arg3 = tmpGCPList2;
-    for( int i = 0; i<arg2; i++ ) {
-      PyObject *o = PySequence_GetItem(obj1,i);
-      GDAL_GCP *item = 0;
-      SWIG_ConvertPtr( o, (void**)&item, SWIGTYPE_p_GDAL_GCP, SWIG_POINTER_EXCEPTION | 0 );
-      if ( ! item ) {
-        Py_DECREF(o);
+    }
+  }
+  if (obj11) {
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj11 == Py_None ) {
+        arg14 = 0;
+      }
+      else if ( PyArg_Parse( obj11,"i" ,&val14 ) ) {
+        arg14 = (int *) &val14;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
         SWIG_fail;
       }
-      memcpy( (void*) tmpGCPList2, (void*) item, sizeof( GDAL_GCP ) );
-      ++tmpGCPList2;
-      Py_DECREF(o);
     }
   }
-  res4 = SWIG_AsCharPtrAndSize(obj2, &buf4, NULL, &alloc4);
-  if (!SWIG_IsOK(res4)) {
-    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Dataset_SetGCPs" "', argument " "4"" of type '" "char const *""'");
+  if (obj12) {
+    {
+      /* %typemap(in) (int *optional_##int) */
+      if ( obj12 == Py_None ) {
+        arg15 = 0;
+      }
+      else if ( PyArg_Parse( obj12,"i" ,&val15 ) ) {
+        arg15 = (int *) &val15;
+      }
+      else {
+        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+        SWIG_fail;
+      }
+    }
   }
-  arg4 = reinterpret_cast< char * >(buf4);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_SetGCPs(arg1,arg2,(GDAL_GCP const *)arg3,(char const *)arg4);
+    result = (CPLErr)GDALDatasetShadow_WriteRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12564,12 +12675,17 @@ SWIGINTERN PyObject *_wrap_Dataset_SetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObj
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    if (arg3) {
-      free( (void*) arg3 );
+    /* %typemap(freearg) (GIntBig *nLen, char *pBuf ) */
+    if( alloc6 == SWIG_NEWOBJ ) {
+      delete[] arg7;
+    }
+  }
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg12) {
+      free((void*) arg12);
     }
   }
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   {
     /* %typemap(ret) CPLErr */
     if ( bUseExceptions == 0 ) {
@@ -12583,94 +12699,212 @@ SWIGINTERN PyObject *_wrap_Dataset_SetGCPs(PyObject *SWIGUNUSEDPARM(self), PyObj
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (int nGCPs, GDAL_GCP const *pGCPs ) */
-    if (arg3) {
-      free( (void*) arg3 );
+    /* %typemap(freearg) (GIntBig *nLen, char *pBuf ) */
+    if( alloc6 == SWIG_NEWOBJ ) {
+      delete[] arg7;
     }
   }
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Dataset_FlushCache(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_FlushCache",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_FlushCache" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    GDALDatasetShadow_FlushCache(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg12) {
+      free((void*) arg12);
     }
   }
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_AddBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_BeginAsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  GDALDataType arg2 = (GDALDataType) GDT_Byte ;
-  char **arg3 = (char **) 0 ;
+  int arg2 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  int arg6 ;
+  char *arg7 = (char *) 0 ;
+  void *arg8 = (void *) 0 ;
+  int arg9 ;
+  int arg10 ;
+  GDALDataType arg11 = (GDALDataType) (GDALDataType) 0 ;
+  int arg12 = (int) 0 ;
+  int *arg13 = (int *) 0 ;
+  int arg14 = (int) 0 ;
+  int arg15 = (int) 0 ;
+  int arg16 = (int) 0 ;
+  char **arg17 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
+  int val10 ;
+  int ecode10 = 0 ;
+  int val11 ;
+  int ecode11 = 0 ;
+  int val14 ;
+  int ecode14 = 0 ;
+  int val15 ;
+  int ecode15 = 0 ;
+  int val16 ;
+  int ecode16 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
+  PyObject * obj11 = 0 ;
+  PyObject * obj12 = 0 ;
+  PyObject * obj13 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "datatype",(char *) "options", NULL 
+    (char *) "self",(char *) "xOff",(char *) "yOff",(char *) "xSize",(char *) "ySize",(char *) "buf_len",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "bufType",(char *) "band_list",(char *) "nPixelSpace",(char *) "nLineSpace",(char *) "nBandSpace",(char *) "options", NULL 
   };
-  CPLErr result;
+  GDALAsyncReaderShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:Dataset_AddBand",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOO|OOOOOO:Dataset_BeginAsyncReader",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12,&obj13)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_AddBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_BeginAsyncReader" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_AddBand" "', argument " "2"" of type '" "GDALDataType""'");
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_BeginAsyncReader" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_BeginAsyncReader" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_BeginAsyncReader" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_BeginAsyncReader" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
+  {
+    /* %typemap(in,numinputs=1) (int nLenKeepObject, char *pBufKeepObject, void* pyObject) */
+#if PY_VERSION_HEX>=0x03000000
+    if (PyBytes_Check(obj5))
+    {
+      Py_ssize_t safeLen = 0;
+      PyBytes_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
+      arg6 = (int) safeLen;
+      arg8 = obj5;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a bytes");
+      SWIG_fail;
+    }
+#else
+    if (PyString_Check(obj5))
+    {
+      Py_ssize_t safeLen = 0;
+      PyString_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
+      arg6 = (int) safeLen;
+      arg8 = obj5;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a string");
+      SWIG_fail;
+    }
+#endif
+  }
+  ecode9 = SWIG_AsVal_int(obj6, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_BeginAsyncReader" "', argument " "9"" of type '" "int""'");
+  } 
+  arg9 = static_cast< int >(val9);
+  ecode10 = SWIG_AsVal_int(obj7, &val10);
+  if (!SWIG_IsOK(ecode10)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode10), "in method '" "Dataset_BeginAsyncReader" "', argument " "10"" of type '" "int""'");
+  } 
+  arg10 = static_cast< int >(val10);
+  if (obj8) {
+    ecode11 = SWIG_AsVal_int(obj8, &val11);
+    if (!SWIG_IsOK(ecode11)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode11), "in method '" "Dataset_BeginAsyncReader" "', argument " "11"" of type '" "GDALDataType""'");
     } 
-    arg2 = static_cast< GDALDataType >(val2);
+    arg11 = static_cast< GDALDataType >(val11);
+  }
+  if (obj9) {
+    {
+      /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+      /* check if is List */
+      if ( !PySequence_Check(obj9) ) {
+        PyErr_SetString(PyExc_TypeError, "not a sequence");
+        SWIG_fail;
+      }
+      arg12 = PySequence_Size(obj9);
+      arg13 = (int*) malloc(arg12*sizeof(int));
+      for( int i = 0; i<arg12; i++ ) {
+        PyObject *o = PySequence_GetItem(obj9,i);
+        if ( !PyArg_Parse(o,"i",&arg13[i]) ) {
+          PyErr_SetString(PyExc_TypeError, "not an integer");
+          Py_DECREF(o);
+          SWIG_fail;
+        }
+        Py_DECREF(o);
+      }
+    }
+  }
+  if (obj10) {
+    ecode14 = SWIG_AsVal_int(obj10, &val14);
+    if (!SWIG_IsOK(ecode14)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode14), "in method '" "Dataset_BeginAsyncReader" "', argument " "14"" of type '" "int""'");
+    } 
+    arg14 = static_cast< int >(val14);
+  }
+  if (obj11) {
+    ecode15 = SWIG_AsVal_int(obj11, &val15);
+    if (!SWIG_IsOK(ecode15)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode15), "in method '" "Dataset_BeginAsyncReader" "', argument " "15"" of type '" "int""'");
+    } 
+    arg15 = static_cast< int >(val15);
+  }
+  if (obj12) {
+    ecode16 = SWIG_AsVal_int(obj12, &val16);
+    if (!SWIG_IsOK(ecode16)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode16), "in method '" "Dataset_BeginAsyncReader" "', argument " "16"" of type '" "int""'");
+    } 
+    arg16 = static_cast< int >(val16);
   }
-  if (obj2) {
+  if (obj13) {
     {
       /* %typemap(in) char **options */
       /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+      if ( ! PySequence_Check(obj13) || PyUnicode_Check(obj13)
   #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj2)
+        || PyString_Check(obj13)
   #endif
         ) {
         PyErr_SetString(PyExc_TypeError,"not a sequence");
         SWIG_fail;
       }
       
-      int size = PySequence_Size(obj2);
+      int size = PySequence_Size(obj13);
       for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        PyObject* pyObj = PySequence_GetItem(obj13,i);
         if (PyUnicode_Check(pyObj))
         {
           char *pszStr;
@@ -12681,15 +12915,15 @@ SWIGINTERN PyObject *_wrap_Dataset_AddBand(PyObject *SWIGUNUSEDPARM(self), PyObj
 #else
           PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
 #endif
-          arg3 = CSLAddString( arg3, pszStr );
+          arg17 = CSLAddString( arg17, pszStr );
           Py_XDECREF(pyUTF8Str);
         }
 #if PY_VERSION_HEX >= 0x03000000
         else if (PyBytes_Check(pyObj))
-        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+        arg17 = CSLAddString( arg17, PyBytes_AsString(pyObj) );
 #else
         else if (PyString_Check(pyObj))
-        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+        arg17 = CSLAddString( arg17, PyString_AsString(pyObj) );
 #endif
         else
         {
@@ -12705,7 +12939,7 @@ SWIGINTERN PyObject *_wrap_Dataset_AddBand(PyObject *SWIGUNUSEDPARM(self), PyObj
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_AddBand(arg1,arg2,arg3);
+    result = (GDALAsyncReaderShadow *)GDALDatasetShadow_BeginAsyncReader(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12713,59 +12947,60 @@ SWIGINTERN PyObject *_wrap_Dataset_AddBand(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg13) {
+      free((void*) arg13);
+    }
   }
   {
-    /* %typemap(ret) CPLErr */
-    if ( bUseExceptions == 0 ) {
-      /* We're not using exceptions.  And no error has occurred */
-      if ( resultobj == 0 ) {
-        /* No other return values set so return ErrorCode */
-        resultobj = PyInt_FromLong(result);
-      }
-    }
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg17 );
   }
   return resultobj;
 fail:
   {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg13) {
+      free((void*) arg13);
+    }
+  }
+  {
     /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
+    CSLDestroy( arg17 );
   }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_CreateMaskBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_EndAsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int arg2 ;
+  GDALAsyncReaderShadow *arg2 = (GDALAsyncReaderShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_CreateMaskBand",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_EndAsyncReader",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CreateMaskBand" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_EndAsyncReader" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_CreateMaskBand" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_EndAsyncReader" "', argument " "2"" of type '" "GDALAsyncReaderShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< GDALAsyncReaderShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_CreateMaskBand(arg1,arg2);
+    GDALDatasetShadow_EndAsyncReader(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12773,42 +13008,204 @@ SWIGINTERN PyObject *_wrap_Dataset_CreateMaskBand(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  {
-    /* %typemap(ret) CPLErr */
-    if ( bUseExceptions == 0 ) {
-      /* We're not using exceptions.  And no error has occurred */
-      if ( resultobj == 0 ) {
-        /* No other return values set so return ErrorCode */
-        resultobj = PyInt_FromLong(result);
-      }
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetFileList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_GetVirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  GDALRWFlag arg2 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  int arg6 ;
+  int arg7 ;
+  int arg8 ;
+  GDALDataType arg9 ;
+  int arg10 ;
+  int *arg11 = (int *) 0 ;
+  int arg12 ;
+  size_t arg13 ;
+  size_t arg14 ;
+  char **arg15 = (char **) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
+  int val7 ;
+  int ecode7 = 0 ;
+  int val8 ;
+  int ecode8 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
+  int val12 ;
+  int ecode12 = 0 ;
+  size_t val13 ;
+  int ecode13 = 0 ;
+  size_t val14 ;
+  int ecode14 = 0 ;
   PyObject * obj0 = 0 ;
-  char **result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
+  PyObject * obj11 = 0 ;
+  PyObject * obj12 = 0 ;
+  PyObject * obj13 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "eRWFlag",(char *) "nXOff",(char *) "nYOff",(char *) "nXSize",(char *) "nYSize",(char *) "nBufXSize",(char *) "nBufYSize",(char *) "eBufType",(char *) "band_list",(char *) "bIsBandSequential",(char *) "nCacheSize",(char *) "nPageSizeHint",(char *) "options", NULL 
+  };
+  CPLVirtualMemShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetFileList",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOOOOOO|O:Dataset_GetVirtualMem",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12,&obj13)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetFileList" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetVirtualMem" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetVirtualMem" "', argument " "2"" of type '" "GDALRWFlag""'");
+  } 
+  arg2 = static_cast< GDALRWFlag >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_GetVirtualMem" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_GetVirtualMem" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_GetVirtualMem" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
+  ecode6 = SWIG_AsVal_int(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Dataset_GetVirtualMem" "', argument " "6"" of type '" "int""'");
+  } 
+  arg6 = static_cast< int >(val6);
+  ecode7 = SWIG_AsVal_int(obj6, &val7);
+  if (!SWIG_IsOK(ecode7)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Dataset_GetVirtualMem" "', argument " "7"" of type '" "int""'");
+  } 
+  arg7 = static_cast< int >(val7);
+  ecode8 = SWIG_AsVal_int(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Dataset_GetVirtualMem" "', argument " "8"" of type '" "int""'");
+  } 
+  arg8 = static_cast< int >(val8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_GetVirtualMem" "', argument " "9"" of type '" "GDALDataType""'");
+  } 
+  arg9 = static_cast< GDALDataType >(val9);
+  {
+    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj9) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg10 = PySequence_Size(obj9);
+    arg11 = (int*) malloc(arg10*sizeof(int));
+    for( int i = 0; i<arg10; i++ ) {
+      PyObject *o = PySequence_GetItem(obj9,i);
+      if ( !PyArg_Parse(o,"i",&arg11[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      Py_DECREF(o);
+    }
+  }
+  ecode12 = SWIG_AsVal_int(obj10, &val12);
+  if (!SWIG_IsOK(ecode12)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode12), "in method '" "Dataset_GetVirtualMem" "', argument " "12"" of type '" "int""'");
+  } 
+  arg12 = static_cast< int >(val12);
+  ecode13 = SWIG_AsVal_size_t(obj11, &val13);
+  if (!SWIG_IsOK(ecode13)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode13), "in method '" "Dataset_GetVirtualMem" "', argument " "13"" of type '" "size_t""'");
+  } 
+  arg13 = static_cast< size_t >(val13);
+  ecode14 = SWIG_AsVal_size_t(obj12, &val14);
+  if (!SWIG_IsOK(ecode14)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode14), "in method '" "Dataset_GetVirtualMem" "', argument " "14"" of type '" "size_t""'");
+  } 
+  arg14 = static_cast< size_t >(val14);
+  if (obj13) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj13) || PyUnicode_Check(obj13)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj13)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj13);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj13,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg15 = CSLAddString( arg15, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg15 = CSLAddString( arg15, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg15 = CSLAddString( arg15, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
   }
-  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char **)GDALDatasetShadow_GetFileList(arg1);
+    result = (CPLVirtualMemShadow *)GDALDatasetShadow_GetVirtualMem(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12816,46 +13213,49 @@ SWIGINTERN PyObject *_wrap_Dataset_GetFileList(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(out) char **CSL -> ( string ) */
-    char **stringarray = result;
-    if ( stringarray == NULL ) {
-      resultobj = Py_None;
-      Py_INCREF( resultobj );
-    }
-    else {
-      int len = CSLCount( stringarray );
-      resultobj = PyList_New( len );
-      for ( int i = 0; i < len; ++i ) {
-        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
-        PyList_SetItem(resultobj, i, o );
-      }
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg11) {
+      free((void*) arg11);
     }
-    CSLDestroy(result);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg15 );
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg11) {
+      free((void*) arg11);
+    }
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg15 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_WriteRaster(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_GetTiledVirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int arg2 ;
+  GDALRWFlag arg2 ;
   int arg3 ;
   int arg4 ;
   int arg5 ;
-  GIntBig arg6 ;
-  char *arg7 = (char *) 0 ;
-  int *arg8 = (int *) 0 ;
-  int *arg9 = (int *) 0 ;
-  GDALDataType *arg10 = (GDALDataType *) 0 ;
-  int arg11 = (int) 0 ;
-  int *arg12 = (int *) 0 ;
-  int *arg13 = (int *) 0 ;
-  int *arg14 = (int *) 0 ;
-  int *arg15 = (int *) 0 ;
+  int arg6 ;
+  int arg7 ;
+  int arg8 ;
+  GDALDataType arg9 ;
+  int arg10 ;
+  int *arg11 = (int *) 0 ;
+  GDALTileOrganization arg12 ;
+  size_t arg13 ;
+  char **arg14 = (char **) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -12866,13 +13266,18 @@ SWIGINTERN PyObject *_wrap_Dataset_WriteRaster(PyObject *SWIGUNUSEDPARM(self), P
   int ecode4 = 0 ;
   int val5 ;
   int ecode5 = 0 ;
-  int alloc6 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
+  int val7 ;
+  int ecode7 = 0 ;
   int val8 ;
+  int ecode8 = 0 ;
   int val9 ;
-  int val10 ;
-  int val13 ;
-  int val14 ;
-  int val15 ;
+  int ecode9 = 0 ;
+  int val12 ;
+  int ecode12 = 0 ;
+  size_t val13 ;
+  int ecode13 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
@@ -12887,191 +13292,136 @@ SWIGINTERN PyObject *_wrap_Dataset_WriteRaster(PyObject *SWIGUNUSEDPARM(self), P
   PyObject * obj11 = 0 ;
   PyObject * obj12 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_len",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "band_list",(char *) "buf_pixel_space",(char *) "buf_line_space",(char *) "buf_band_space", NULL 
+    (char *) "self",(char *) "eRWFlag",(char *) "nXOff",(char *) "nYOff",(char *) "nXSize",(char *) "nYSize",(char *) "nTileXSize",(char *) "nTileYSize",(char *) "eBufType",(char *) "band_list",(char *) "eTileOrganization",(char *) "nCacheSize",(char *) "options", NULL 
   };
-  CPLErr result;
+  CPLVirtualMemShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOO|OOOOOOO:Dataset_WriteRaster",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOOOOO|O:Dataset_GetTiledVirtualMem",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_WriteRaster" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_WriteRaster" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "2"" of type '" "GDALRWFlag""'");
   } 
-  arg2 = static_cast< int >(val2);
+  arg2 = static_cast< GDALRWFlag >(val2);
   ecode3 = SWIG_AsVal_int(obj2, &val3);
   if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_WriteRaster" "', argument " "3"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "3"" of type '" "int""'");
   } 
   arg3 = static_cast< int >(val3);
   ecode4 = SWIG_AsVal_int(obj3, &val4);
   if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_WriteRaster" "', argument " "4"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "4"" of type '" "int""'");
   } 
   arg4 = static_cast< int >(val4);
   ecode5 = SWIG_AsVal_int(obj4, &val5);
   if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_WriteRaster" "', argument " "5"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "5"" of type '" "int""'");
   } 
   arg5 = static_cast< int >(val5);
+  ecode6 = SWIG_AsVal_int(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "6"" of type '" "int""'");
+  } 
+  arg6 = static_cast< int >(val6);
+  ecode7 = SWIG_AsVal_int(obj6, &val7);
+  if (!SWIG_IsOK(ecode7)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "7"" of type '" "int""'");
+  } 
+  arg7 = static_cast< int >(val7);
+  ecode8 = SWIG_AsVal_int(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "8"" of type '" "int""'");
+  } 
+  arg8 = static_cast< int >(val8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "9"" of type '" "GDALDataType""'");
+  } 
+  arg9 = static_cast< GDALDataType >(val9);
   {
-    /* %typemap(in,numinputs=1) (GIntBig nLen, char *pBuf ) */
-#if PY_VERSION_HEX>=0x03000000
-    if (PyUnicode_Check(obj5))
-    {
-      size_t safeLen = 0;
-      int ret = SWIG_AsCharPtrAndSize(obj5, (char**) &arg7, &safeLen, &alloc6);
-      if (!SWIG_IsOK(ret)) {
-        SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
-      }
-      
-      if (safeLen) safeLen--;
-      arg6 = (GIntBig) safeLen;
-    }
-    else if (PyBytes_Check(obj5))
-    {
-      Py_ssize_t safeLen = 0;
-      PyBytes_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
-      arg6 = (GIntBig) safeLen;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
-      SWIG_fail;
-    }
-#else
-    if (PyString_Check(obj5))
-    {
-      Py_ssize_t safeLen = 0;
-      PyString_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
-      arg6 = (GIntBig) safeLen;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a string");
+    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj9) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
       SWIG_fail;
     }
-#endif
-  }
-  if (obj6) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj6 == Py_None ) {
-        arg8 = 0;
-      }
-      else if ( PyArg_Parse( obj6,"i" ,&val8 ) ) {
-        arg8 = (int *) &val8;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
-        SWIG_fail;
-      }
-    }
-  }
-  if (obj7) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj7 == Py_None ) {
-        arg9 = 0;
-      }
-      else if ( PyArg_Parse( obj7,"i" ,&val9 ) ) {
-        arg9 = (int *) &val9;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
-        SWIG_fail;
-      }
-    }
-  }
-  if (obj8) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj8 == Py_None ) {
-        arg10 = 0;
-      }
-      else if ( PyArg_Parse( obj8,"i" ,&val10 ) ) {
-        arg10 = (GDALDataType *) &val10;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
-        SWIG_fail;
-      }
-    }
-  }
-  if (obj9) {
-    {
-      /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-      /* check if is List */
-      if ( !PySequence_Check(obj9) ) {
-        PyErr_SetString(PyExc_TypeError, "not a sequence");
-        SWIG_fail;
-      }
-      arg11 = PySequence_Size(obj9);
-      arg12 = (int*) malloc(arg11*sizeof(int));
-      for( int i = 0; i<arg11; i++ ) {
-        PyObject *o = PySequence_GetItem(obj9,i);
-        if ( !PyArg_Parse(o,"i",&arg12[i]) ) {
-          PyErr_SetString(PyExc_TypeError, "not an integer");
-          Py_DECREF(o);
-          SWIG_fail;
-        }
+    arg10 = PySequence_Size(obj9);
+    arg11 = (int*) malloc(arg10*sizeof(int));
+    for( int i = 0; i<arg10; i++ ) {
+      PyObject *o = PySequence_GetItem(obj9,i);
+      if ( !PyArg_Parse(o,"i",&arg11[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
         Py_DECREF(o);
-      }
-    }
-  }
-  if (obj10) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj10 == Py_None ) {
-        arg13 = 0;
-      }
-      else if ( PyArg_Parse( obj10,"i" ,&val13 ) ) {
-        arg13 = (int *) &val13;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
-        SWIG_fail;
-      }
-    }
-  }
-  if (obj11) {
-    {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj11 == Py_None ) {
-        arg14 = 0;
-      }
-      else if ( PyArg_Parse( obj11,"i" ,&val14 ) ) {
-        arg14 = (int *) &val14;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
         SWIG_fail;
       }
+      Py_DECREF(o);
     }
   }
+  ecode12 = SWIG_AsVal_int(obj10, &val12);
+  if (!SWIG_IsOK(ecode12)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode12), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "12"" of type '" "GDALTileOrganization""'");
+  } 
+  arg12 = static_cast< GDALTileOrganization >(val12);
+  ecode13 = SWIG_AsVal_size_t(obj11, &val13);
+  if (!SWIG_IsOK(ecode13)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode13), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "13"" of type '" "size_t""'");
+  } 
+  arg13 = static_cast< size_t >(val13);
   if (obj12) {
     {
-      /* %typemap(in) (int *optional_##int) */
-      if ( obj12 == Py_None ) {
-        arg15 = 0;
-      }
-      else if ( PyArg_Parse( obj12,"i" ,&val15 ) ) {
-        arg15 = (int *) &val15;
-      }
-      else {
-        PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj12) || PyUnicode_Check(obj12)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj12)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
         SWIG_fail;
       }
+      
+      int size = PySequence_Size(obj12);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj12,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg14 = CSLAddString( arg14, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg14 = CSLAddString( arg14, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg14 = CSLAddString( arg14, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_WriteRaster(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
+    result = (CPLVirtualMemShadow *)GDALDatasetShadow_GetTiledVirtualMem(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13079,238 +13429,218 @@ SWIGINTERN PyObject *_wrap_Dataset_WriteRaster(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  {
-    /* %typemap(freearg) (GIntBig *nLen, char *pBuf ) */
-    if( alloc6 == SWIG_NEWOBJ ) {
-      delete[] arg7;
-    }
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_OWN |  0 );
   {
     /* %typemap(freearg) (int nList, int* pList) */
-    if (arg12) {
-      free((void*) arg12);
+    if (arg11) {
+      free((void*) arg11);
     }
   }
   {
-    /* %typemap(ret) CPLErr */
-    if ( bUseExceptions == 0 ) {
-      /* We're not using exceptions.  And no error has occurred */
-      if ( resultobj == 0 ) {
-        /* No other return values set so return ErrorCode */
-        resultobj = PyInt_FromLong(result);
-      }
-    }
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg14 );
   }
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (GIntBig *nLen, char *pBuf ) */
-    if( alloc6 == SWIG_NEWOBJ ) {
-      delete[] arg7;
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg11) {
+      free((void*) arg11);
     }
   }
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg12) {
-      free((void*) arg12);
-    }
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg14 );
   }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_BeginAsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_CreateLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  int arg2 ;
-  int arg3 ;
-  int arg4 ;
-  int arg5 ;
-  int arg6 ;
-  char *arg7 = (char *) 0 ;
-  void *arg8 = (void *) 0 ;
-  int arg9 ;
-  int arg10 ;
-  GDALDataType arg11 = (GDALDataType) (GDALDataType) 0 ;
-  int arg12 = (int) 0 ;
-  int *arg13 = (int *) 0 ;
-  int arg14 = (int) 0 ;
-  int arg15 = (int) 0 ;
-  int arg16 = (int) 0 ;
-  char **arg17 = (char **) 0 ;
+  char *arg2 = (char *) 0 ;
+  OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
+  OGRwkbGeometryType arg4 = (OGRwkbGeometryType) wkbUnknown ;
+  char **arg5 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   int val4 ;
   int ecode4 = 0 ;
-  int val5 ;
-  int ecode5 = 0 ;
-  int val9 ;
-  int ecode9 = 0 ;
-  int val10 ;
-  int ecode10 = 0 ;
-  int val11 ;
-  int ecode11 = 0 ;
-  int val14 ;
-  int ecode14 = 0 ;
-  int val15 ;
-  int ecode15 = 0 ;
-  int val16 ;
-  int ecode16 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
   PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
-  PyObject * obj9 = 0 ;
-  PyObject * obj10 = 0 ;
-  PyObject * obj11 = 0 ;
-  PyObject * obj12 = 0 ;
-  PyObject * obj13 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "xOff",(char *) "yOff",(char *) "xSize",(char *) "ySize",(char *) "buf_len",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "bufType",(char *) "band_list",(char *) "nPixelSpace",(char *) "nLineSpace",(char *) "nBandSpace",(char *) "options", NULL 
+    (char *) "self",(char *) "name",(char *) "srs",(char *) "geom_type",(char *) "options", NULL 
   };
-  GDALAsyncReaderShadow *result = 0 ;
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOO|OOOOOO:Dataset_BeginAsyncReader",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12,&obj13)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OOO:Dataset_CreateLayer",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_BeginAsyncReader" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CreateLayer" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_BeginAsyncReader" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_BeginAsyncReader" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_BeginAsyncReader" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
-  ecode5 = SWIG_AsVal_int(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_BeginAsyncReader" "', argument " "5"" of type '" "int""'");
-  } 
-  arg5 = static_cast< int >(val5);
-  {
-    /* %typemap(in,numinputs=1) (int nLenKeepObject, char *pBufKeepObject, void* pyObject) */
-#if PY_VERSION_HEX>=0x03000000
-    if (PyBytes_Check(obj5))
-    {
-      Py_ssize_t safeLen = 0;
-      PyBytes_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
-      arg6 = (int) safeLen;
-      arg8 = obj5;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a bytes");
-      SWIG_fail;
-    }
-#else
-    if (PyString_Check(obj5))
-    {
-      Py_ssize_t safeLen = 0;
-      PyString_AsStringAndSize(obj5, (char**) &arg7, &safeLen);
-      arg6 = (int) safeLen;
-      arg8 = obj5;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a string");
-      SWIG_fail;
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_CreateLayer" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Dataset_CreateLayer" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
     }
-#endif
+    arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
   }
-  ecode9 = SWIG_AsVal_int(obj6, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_BeginAsyncReader" "', argument " "9"" of type '" "int""'");
-  } 
-  arg9 = static_cast< int >(val9);
-  ecode10 = SWIG_AsVal_int(obj7, &val10);
-  if (!SWIG_IsOK(ecode10)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode10), "in method '" "Dataset_BeginAsyncReader" "', argument " "10"" of type '" "int""'");
-  } 
-  arg10 = static_cast< int >(val10);
-  if (obj8) {
-    ecode11 = SWIG_AsVal_int(obj8, &val11);
-    if (!SWIG_IsOK(ecode11)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode11), "in method '" "Dataset_BeginAsyncReader" "', argument " "11"" of type '" "GDALDataType""'");
+  if (obj3) {
+    ecode4 = SWIG_AsVal_int(obj3, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_CreateLayer" "', argument " "4"" of type '" "OGRwkbGeometryType""'");
     } 
-    arg11 = static_cast< GDALDataType >(val11);
+    arg4 = static_cast< OGRwkbGeometryType >(val4);
   }
-  if (obj9) {
+  if (obj4) {
     {
-      /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-      /* check if is List */
-      if ( !PySequence_Check(obj9) ) {
-        PyErr_SetString(PyExc_TypeError, "not a sequence");
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj4) || PyUnicode_Check(obj4)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj4)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
         SWIG_fail;
       }
-      arg12 = PySequence_Size(obj9);
-      arg13 = (int*) malloc(arg12*sizeof(int));
-      for( int i = 0; i<arg12; i++ ) {
-        PyObject *o = PySequence_GetItem(obj9,i);
-        if ( !PyArg_Parse(o,"i",&arg13[i]) ) {
-          PyErr_SetString(PyExc_TypeError, "not an integer");
-          Py_DECREF(o);
+      
+      int size = PySequence_Size(obj4);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj4,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg5 = CSLAddString( arg5, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
           SWIG_fail;
         }
-        Py_DECREF(o);
+        Py_DECREF(pyObj);
       }
     }
   }
-  if (obj10) {
-    ecode14 = SWIG_AsVal_int(obj10, &val14);
-    if (!SWIG_IsOK(ecode14)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode14), "in method '" "Dataset_BeginAsyncReader" "', argument " "14"" of type '" "int""'");
-    } 
-    arg14 = static_cast< int >(val14);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  if (obj11) {
-    ecode15 = SWIG_AsVal_int(obj11, &val15);
-    if (!SWIG_IsOK(ecode15)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode15), "in method '" "Dataset_BeginAsyncReader" "', argument " "15"" of type '" "int""'");
-    } 
-    arg15 = static_cast< int >(val15);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)GDALDatasetShadow_CreateLayer(arg1,(char const *)arg2,arg3,arg4,arg5);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
   }
-  if (obj12) {
-    ecode16 = SWIG_AsVal_int(obj12, &val16);
-    if (!SWIG_IsOK(ecode16)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode16), "in method '" "Dataset_BeginAsyncReader" "', argument " "16"" of type '" "int""'");
-    } 
-    arg16 = static_cast< int >(val16);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
   }
-  if (obj13) {
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_CopyLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  char *arg3 = (char *) 0 ;
+  char **arg4 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "src_layer",(char *) "new_name",(char *) "options", NULL 
+  };
+  OGRLayerShadow *result = 0 ;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Dataset_CopyLayer",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CopyLayer" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_CopyLayer" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Dataset_CopyLayer" "', argument " "3"" of type '" "char const *""'");
+  }
+  arg3 = reinterpret_cast< char * >(buf3);
+  if (obj3) {
     {
       /* %typemap(in) char **options */
       /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj13) || PyUnicode_Check(obj13)
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
   #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj13)
+        || PyString_Check(obj3)
   #endif
         ) {
         PyErr_SetString(PyExc_TypeError,"not a sequence");
         SWIG_fail;
       }
       
-      int size = PySequence_Size(obj13);
+      int size = PySequence_Size(obj3);
       for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj13,i);
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
         if (PyUnicode_Check(pyObj))
         {
           char *pszStr;
@@ -13321,15 +13651,15 @@ SWIGINTERN PyObject *_wrap_Dataset_BeginAsyncReader(PyObject *SWIGUNUSEDPARM(sel
 #else
           PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
 #endif
-          arg17 = CSLAddString( arg17, pszStr );
+          arg4 = CSLAddString( arg4, pszStr );
           Py_XDECREF(pyUTF8Str);
         }
 #if PY_VERSION_HEX >= 0x03000000
         else if (PyBytes_Check(pyObj))
-        arg17 = CSLAddString( arg17, PyBytes_AsString(pyObj) );
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
 #else
         else if (PyString_Check(pyObj))
-        arg17 = CSLAddString( arg17, PyString_AsString(pyObj) );
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
 #endif
         else
         {
@@ -13342,10 +13672,15 @@ SWIGINTERN PyObject *_wrap_Dataset_BeginAsyncReader(PyObject *SWIGUNUSEDPARM(sel
     }
   }
   {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (GDALAsyncReaderShadow *)GDALDatasetShadow_BeginAsyncReader(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17);
+    result = (OGRLayerShadow *)GDALDatasetShadow_CopyLayer(arg1,arg2,(char const *)arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13353,60 +13688,232 @@ SWIGINTERN PyObject *_wrap_Dataset_BeginAsyncReader(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALAsyncReaderShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg13) {
-      free((void*) arg13);
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  return resultobj;
+fail:
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_DeleteLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_DeleteLayer",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_DeleteLayer" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_DeleteLayer" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)GDALDatasetShadow_DeleteLayer(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_GetLayerCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetLayerCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetLayerCount" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)GDALDatasetShadow_GetLayerCount(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_GetLayerByIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  int arg2 = (int) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRLayerShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O|O:Dataset_GetLayerByIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetLayerByIndex" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetLayerByIndex" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)GDALDatasetShadow_GetLayerByIndex(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_GetLayerByName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRLayerShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_GetLayerByName",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetLayerByName" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_GetLayerByName" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)GDALDatasetShadow_GetLayerByName(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg17 );
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg13) {
-      free((void*) arg13);
-    }
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg17 );
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_EndAsyncReader(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Dataset_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  GDALAsyncReaderShadow *arg2 = (GDALAsyncReaderShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_EndAsyncReader",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_TestCapability",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_EndAsyncReader" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_TestCapability" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_GDALAsyncReaderShadow, 0 |  0 );
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_EndAsyncReader" "', argument " "2"" of type '" "GDALAsyncReaderShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_TestCapability" "', argument " "2"" of type '" "char const *""'");
   }
-  arg2 = reinterpret_cast< GDALAsyncReaderShadow * >(argp2);
+  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    GDALDatasetShadow_EndAsyncReader(arg1,arg2);
+    result = (bool)GDALDatasetShadow_TestCapability(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13414,204 +13921,118 @@ SWIGINTERN PyObject *_wrap_Dataset_EndAsyncReader(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetVirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_ExecuteSQL(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  GDALRWFlag arg2 ;
-  int arg3 ;
-  int arg4 ;
-  int arg5 ;
-  int arg6 ;
-  int arg7 ;
-  int arg8 ;
-  GDALDataType arg9 ;
-  int arg10 ;
-  int *arg11 = (int *) 0 ;
-  int arg12 ;
-  size_t arg13 ;
-  size_t arg14 ;
-  char **arg15 = (char **) NULL ;
+  char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) NULL ;
+  char *arg4 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
-  int val5 ;
-  int ecode5 = 0 ;
-  int val6 ;
-  int ecode6 = 0 ;
-  int val7 ;
-  int ecode7 = 0 ;
-  int val8 ;
-  int ecode8 = 0 ;
-  int val9 ;
-  int ecode9 = 0 ;
-  int val12 ;
-  int ecode12 = 0 ;
-  size_t val13 ;
-  int ecode13 = 0 ;
-  size_t val14 ;
-  int ecode14 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
+  int res4 ;
+  char *buf4 = 0 ;
+  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
-  PyObject * obj9 = 0 ;
-  PyObject * obj10 = 0 ;
-  PyObject * obj11 = 0 ;
-  PyObject * obj12 = 0 ;
-  PyObject * obj13 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "eRWFlag",(char *) "nXOff",(char *) "nYOff",(char *) "nXSize",(char *) "nYSize",(char *) "nBufXSize",(char *) "nBufYSize",(char *) "eBufType",(char *) "band_list",(char *) "bIsBandSequential",(char *) "nCacheSize",(char *) "nPageSizeHint",(char *) "options", NULL 
+    (char *) "self",(char *) "statement",(char *) "spatialFilter",(char *) "dialect", NULL 
   };
-  CPLVirtualMemShadow *result = 0 ;
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOOOOOO|O:Dataset_GetVirtualMem",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12,&obj13)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OO:Dataset_ExecuteSQL",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetVirtualMem" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_ExecuteSQL" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetVirtualMem" "', argument " "2"" of type '" "GDALRWFlag""'");
-  } 
-  arg2 = static_cast< GDALRWFlag >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_GetVirtualMem" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_GetVirtualMem" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
-  ecode5 = SWIG_AsVal_int(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_GetVirtualMem" "', argument " "5"" of type '" "int""'");
-  } 
-  arg5 = static_cast< int >(val5);
-  ecode6 = SWIG_AsVal_int(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Dataset_GetVirtualMem" "', argument " "6"" of type '" "int""'");
-  } 
-  arg6 = static_cast< int >(val6);
-  ecode7 = SWIG_AsVal_int(obj6, &val7);
-  if (!SWIG_IsOK(ecode7)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Dataset_GetVirtualMem" "', argument " "7"" of type '" "int""'");
-  } 
-  arg7 = static_cast< int >(val7);
-  ecode8 = SWIG_AsVal_int(obj7, &val8);
-  if (!SWIG_IsOK(ecode8)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Dataset_GetVirtualMem" "', argument " "8"" of type '" "int""'");
-  } 
-  arg8 = static_cast< int >(val8);
-  ecode9 = SWIG_AsVal_int(obj8, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_GetVirtualMem" "', argument " "9"" of type '" "GDALDataType""'");
-  } 
-  arg9 = static_cast< GDALDataType >(val9);
-  {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj9) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_ExecuteSQL" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Dataset_ExecuteSQL" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
     }
-    arg10 = PySequence_Size(obj9);
-    arg11 = (int*) malloc(arg10*sizeof(int));
-    for( int i = 0; i<arg10; i++ ) {
-      PyObject *o = PySequence_GetItem(obj9,i);
-      if ( !PyArg_Parse(o,"i",&arg11[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not an integer");
-        Py_DECREF(o);
-        SWIG_fail;
-      }
-      Py_DECREF(o);
+    arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
+  }
+  if (obj3) {
+    res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "Dataset_ExecuteSQL" "', argument " "4"" of type '" "char const *""'");
     }
+    arg4 = reinterpret_cast< char * >(buf4);
   }
-  ecode12 = SWIG_AsVal_int(obj10, &val12);
-  if (!SWIG_IsOK(ecode12)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode12), "in method '" "Dataset_GetVirtualMem" "', argument " "12"" of type '" "int""'");
-  } 
-  arg12 = static_cast< int >(val12);
-  ecode13 = SWIG_AsVal_size_t(obj11, &val13);
-  if (!SWIG_IsOK(ecode13)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode13), "in method '" "Dataset_GetVirtualMem" "', argument " "13"" of type '" "size_t""'");
-  } 
-  arg13 = static_cast< size_t >(val13);
-  ecode14 = SWIG_AsVal_size_t(obj12, &val14);
-  if (!SWIG_IsOK(ecode14)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode14), "in method '" "Dataset_GetVirtualMem" "', argument " "14"" of type '" "size_t""'");
-  } 
-  arg14 = static_cast< size_t >(val14);
-  if (obj13) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj13) || PyUnicode_Check(obj13)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj13)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj13);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj13,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg15 = CSLAddString( arg15, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg15 = CSLAddString( arg15, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg15 = CSLAddString( arg15, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)GDALDatasetShadow_ExecuteSQL(arg1,(char const *)arg2,arg3,(char const *)arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_ReleaseResultSet(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_ReleaseResultSet",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_ReleaseResultSet" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRLayerShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_ReleaseResultSet" "', argument " "2"" of type '" "OGRLayerShadow *""'");
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLVirtualMemShadow *)GDALDatasetShadow_GetVirtualMem(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15);
+    GDALDatasetShadow_ReleaseResultSet(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13619,215 +14040,169 @@ SWIGINTERN PyObject *_wrap_Dataset_GetVirtualMem(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_OWN |  0 );
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg11) {
-      free((void*) arg11);
-    }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRStyleTableShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_GetStyleTable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetStyleTable" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg15 );
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRStyleTableShadow *)GDALDatasetShadow_GetStyleTable(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg11) {
-      free((void*) arg11);
-    }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  OGRStyleTableShadow *arg2 = (OGRStyleTableShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Dataset_SetStyleTable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_SetStyleTable" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Dataset_SetStyleTable" "', argument " "2"" of type '" "OGRStyleTableShadow *""'"); 
   }
+  arg2 = reinterpret_cast< OGRStyleTableShadow * >(argp2);
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg15 );
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    GDALDatasetShadow_SetStyleTable(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
   }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Dataset_GetTiledVirtualMem(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Dataset_StartTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
-  GDALRWFlag arg2 ;
-  int arg3 ;
-  int arg4 ;
-  int arg5 ;
-  int arg6 ;
-  int arg7 ;
-  int arg8 ;
-  GDALDataType arg9 ;
-  int arg10 ;
-  int *arg11 = (int *) 0 ;
-  GDALTileOrganization arg12 ;
-  size_t arg13 ;
-  char **arg14 = (char **) NULL ;
+  int arg2 = (int) FALSE ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
-  int val5 ;
-  int ecode5 = 0 ;
-  int val6 ;
-  int ecode6 = 0 ;
-  int val7 ;
-  int ecode7 = 0 ;
-  int val8 ;
-  int ecode8 = 0 ;
-  int val9 ;
-  int ecode9 = 0 ;
-  int val12 ;
-  int ecode12 = 0 ;
-  size_t val13 ;
-  int ecode13 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
-  PyObject * obj9 = 0 ;
-  PyObject * obj10 = 0 ;
-  PyObject * obj11 = 0 ;
-  PyObject * obj12 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "eRWFlag",(char *) "nXOff",(char *) "nYOff",(char *) "nXSize",(char *) "nYSize",(char *) "nTileXSize",(char *) "nTileYSize",(char *) "eBufType",(char *) "band_list",(char *) "eTileOrganization",(char *) "nCacheSize",(char *) "options", NULL 
+    (char *) "self",(char *) "force", NULL 
   };
-  CPLVirtualMemShadow *result = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOOOOO|O:Dataset_GetTiledVirtualMem",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Dataset_StartTransaction",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_StartTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "2"" of type '" "GDALRWFlag""'");
-  } 
-  arg2 = static_cast< GDALRWFlag >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
-  ecode5 = SWIG_AsVal_int(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "5"" of type '" "int""'");
-  } 
-  arg5 = static_cast< int >(val5);
-  ecode6 = SWIG_AsVal_int(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "6"" of type '" "int""'");
-  } 
-  arg6 = static_cast< int >(val6);
-  ecode7 = SWIG_AsVal_int(obj6, &val7);
-  if (!SWIG_IsOK(ecode7)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "7"" of type '" "int""'");
-  } 
-  arg7 = static_cast< int >(val7);
-  ecode8 = SWIG_AsVal_int(obj7, &val8);
-  if (!SWIG_IsOK(ecode8)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "8"" of type '" "int""'");
-  } 
-  arg8 = static_cast< int >(val8);
-  ecode9 = SWIG_AsVal_int(obj8, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "9"" of type '" "GDALDataType""'");
-  } 
-  arg9 = static_cast< GDALDataType >(val9);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Dataset_StartTransaction" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
   {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj9) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg10 = PySequence_Size(obj9);
-    arg11 = (int*) malloc(arg10*sizeof(int));
-    for( int i = 0; i<arg10; i++ ) {
-      PyObject *o = PySequence_GetItem(obj9,i);
-      if ( !PyArg_Parse(o,"i",&arg11[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not an integer");
-        Py_DECREF(o);
-        SWIG_fail;
+    result = (OGRErr)GDALDatasetShadow_StartTransaction(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-      Py_DECREF(o);
     }
   }
-  ecode12 = SWIG_AsVal_int(obj10, &val12);
-  if (!SWIG_IsOK(ecode12)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode12), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "12"" of type '" "GDALTileOrganization""'");
-  } 
-  arg12 = static_cast< GDALTileOrganization >(val12);
-  ecode13 = SWIG_AsVal_size_t(obj11, &val13);
-  if (!SWIG_IsOK(ecode13)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode13), "in method '" "Dataset_GetTiledVirtualMem" "', argument " "13"" of type '" "size_t""'");
-  } 
-  arg13 = static_cast< size_t >(val13);
-  if (obj12) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj12) || PyUnicode_Check(obj12)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj12)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj12);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj12,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg14 = CSLAddString( arg14, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg14 = CSLAddString( arg14, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg14 = CSLAddString( arg14, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
     }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_CommitTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_CommitTransaction",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_CommitTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLVirtualMemShadow *)GDALDatasetShadow_GetTiledVirtualMem(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14);
+    result = (OGRErr)GDALDatasetShadow_CommitTransaction(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13835,29 +14210,74 @@ SWIGINTERN PyObject *_wrap_Dataset_GetTiledVirtualMem(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_CPLVirtualMemShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg11) {
-      free((void*) arg11);
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg14 );
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
   }
   return resultobj;
 fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Dataset_RollbackTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALDatasetShadow *arg1 = (GDALDatasetShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Dataset_RollbackTransaction",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_RollbackTransaction" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALDatasetShadow * >(argp1);
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg11) {
-      free((void*) arg11);
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)GDALDatasetShadow_RollbackTransaction(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg14 );
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
   }
+  return resultobj;
+fail:
   return NULL;
 }
 
@@ -13875,9 +14295,12 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   GDALDataType *arg9 = (GDALDataType *) 0 ;
   int arg10 = (int) 0 ;
   int *arg11 = (int *) 0 ;
-  int *arg12 = (int *) 0 ;
-  int *arg13 = (int *) 0 ;
-  int *arg14 = (int *) 0 ;
+  GIntBig *arg12 = (GIntBig *) 0 ;
+  GIntBig *arg13 = (GIntBig *) 0 ;
+  GIntBig *arg14 = (GIntBig *) 0 ;
+  GDALRIOResampleAlg arg15 = (GDALRIOResampleAlg) GRIORA_NearestNeighbour ;
+  GDALProgressFunc arg16 = (GDALProgressFunc) NULL ;
+  void *arg17 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -13892,9 +14315,11 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   int val7 ;
   int val8 ;
   int val9 ;
-  int val12 ;
-  int val13 ;
-  int val14 ;
+  GIntBig val12 ;
+  GIntBig val13 ;
+  GIntBig val14 ;
+  int val15 ;
+  int ecode15 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
@@ -13907,16 +14332,26 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   PyObject * obj9 = 0 ;
   PyObject * obj10 = 0 ;
   PyObject * obj11 = 0 ;
+  PyObject * obj12 = 0 ;
+  PyObject * obj13 = 0 ;
+  PyObject * obj14 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "band_list",(char *) "buf_pixel_space",(char *) "buf_line_space",(char *) "buf_band_space", NULL 
+    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "band_list",(char *) "buf_pixel_space",(char *) "buf_line_space",(char *) "buf_band_space",(char *) "resample_alg",(char *) "callback",(char *) "callback_data", NULL 
   };
   CPLErr result;
   
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg17 = psProgressInfo;
   {
     /* %typemap(in,numinputs=0) ( void **outPythonObject ) ( void *pyObject6 = NULL ) */
     arg6 = &pyObject6;
   }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOO|OOOOOOO:Dataset_ReadRaster1",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOO|OOOOOOOOOO:Dataset_ReadRaster1",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12,&obj13,&obj14)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Dataset_ReadRaster1" "', argument " "1"" of type '" "GDALDatasetShadow *""'"); 
@@ -14010,12 +14445,12 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   }
   if (obj9) {
     {
-      /* %typemap(in) (int *optional_##int) */
+      /* %typemap(in) (GIntBig *optional_##GIntBig) */
       if ( obj9 == Py_None ) {
         arg12 = 0;
       }
-      else if ( PyArg_Parse( obj9,"i" ,&val12 ) ) {
-        arg12 = (int *) &val12;
+      else if ( PyArg_Parse( obj9,"L" ,&val12 ) ) {
+        arg12 = (GIntBig *) &val12;
       }
       else {
         PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
@@ -14025,12 +14460,12 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   }
   if (obj10) {
     {
-      /* %typemap(in) (int *optional_##int) */
+      /* %typemap(in) (GIntBig *optional_##GIntBig) */
       if ( obj10 == Py_None ) {
         arg13 = 0;
       }
-      else if ( PyArg_Parse( obj10,"i" ,&val13 ) ) {
-        arg13 = (int *) &val13;
+      else if ( PyArg_Parse( obj10,"L" ,&val13 ) ) {
+        arg13 = (GIntBig *) &val13;
       }
       else {
         PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
@@ -14040,12 +14475,12 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
   }
   if (obj11) {
     {
-      /* %typemap(in) (int *optional_##int) */
+      /* %typemap(in) (GIntBig *optional_##GIntBig) */
       if ( obj11 == Py_None ) {
         arg14 = 0;
       }
-      else if ( PyArg_Parse( obj11,"i" ,&val14 ) ) {
-        arg14 = (int *) &val14;
+      else if ( PyArg_Parse( obj11,"L" ,&val14 ) ) {
+        arg14 = (GIntBig *) &val14;
       }
       else {
         PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
@@ -14053,11 +14488,51 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
+  if (obj12) {
+    ecode15 = SWIG_AsVal_int(obj12, &val15);
+    if (!SWIG_IsOK(ecode15)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode15), "in method '" "Dataset_ReadRaster1" "', argument " "15"" of type '" "GDALRIOResampleAlg""'");
+    } 
+    arg15 = static_cast< GDALRIOResampleAlg >(val15);
+  }
+  if (obj13) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj13 && obj13 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj13, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg16 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj13)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj13;
+          arg16 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj14) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj14 ;
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALDatasetShadow_ReadRaster1(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14);
+    result = (CPLErr)GDALDatasetShadow_ReadRaster1(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15,arg16,arg17);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14086,6 +14561,12 @@ SWIGINTERN PyObject *_wrap_Dataset_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), P
     }
   }
   {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
     /* %typemap(ret) CPLErr */
     if ( bUseExceptions == 0 ) {
       /* We're not using exceptions.  And no error has occurred */
@@ -14103,6 +14584,12 @@ fail:
       free((void*) arg11);
     }
   }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
@@ -14213,6 +14700,39 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Band_GetDataset(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  GDALDatasetShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Band_GetDataset",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_GetDataset" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALRasterBandShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (GDALDatasetShadow *)GDALRasterBandShadow_GetDataset(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDatasetShadow, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Band_GetBand(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALRasterBandShadow *arg1 = (GDALRasterBandShadow *) 0 ;
@@ -16357,7 +16877,7 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
   double arg2 = (double) -0.5 ;
   double arg3 = (double) 255.5 ;
   int arg4 = (int) 256 ;
-  int *arg5 = (int *) NULL ;
+  GUIntBig *arg5 = (GUIntBig *) NULL ;
   int arg6 = (int) 0 ;
   int arg7 = (int) 1 ;
   GDALProgressFunc arg8 = (GDALProgressFunc) NULL ;
@@ -16386,8 +16906,8 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
   CPLErr result;
   
   {
-    /* %typemap(in) int buckets, int* panHistogram -> list */
-    arg5 = (int *) VSICalloc(sizeof(int),arg4);
+    /* %typemap(in) int buckets, GUIntBig* panHistogram -> list */
+    arg5 = (GUIntBig *) VSICalloc(sizeof(GUIntBig),arg4);
   }
   /* %typemap(arginit) ( const char* callback_data=NULL)  */
   PyProgressData *psProgressInfo;
@@ -16418,18 +16938,18 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
   }
   if (obj3) {
     {
-      /* %typemap(in) int buckets, int* panHistogram -> list */
+      /* %typemap(in) int buckets, GUIntBig* panHistogram -> list */
       int requested_buckets = 0;
       SWIG_AsVal_int(obj3, &requested_buckets);
       if( requested_buckets != arg4 )
       {
         arg4 = requested_buckets;
-        if (requested_buckets <= 0 || requested_buckets > (int)(INT_MAX / sizeof(int)))
+        if (requested_buckets <= 0 || requested_buckets > (int)(INT_MAX / sizeof(GUIntBig)))
         {
           PyErr_SetString( PyExc_RuntimeError, "Bad value for buckets" );
           SWIG_fail;
         }
-        arg5 = (int *) VSIRealloc(arg5, sizeof(int) * requested_buckets);
+        arg5 = (GUIntBig *) VSIRealloc(arg5, sizeof(GUIntBig) * requested_buckets);
       }
       if (arg5 == NULL)
       {
@@ -16499,8 +17019,8 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(out) int buckets, int* panHistogram -> list */
-    int *integerarray = arg5;
+    /* %typemap(out) int buckets, GUIntBig* panHistogram -> list */
+    GUIntBig *integerarray = arg5;
     if ( integerarray == NULL ) {
       resultobj = Py_None;
       Py_INCREF( resultobj );
@@ -16508,13 +17028,19 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
     else {
       resultobj = PyList_New( arg4 );
       for ( int i = 0; i < arg4; ++i ) {
-        PyObject *o =  PyInt_FromLong( integerarray[i] );
+        char szTmp[32];
+        sprintf(szTmp, CPL_FRMT_GUIB, integerarray[i]);
+#if PY_VERSION_HEX>=0x03000000
+        PyObject *o = PyLong_FromString(szTmp, NULL, 10);
+#else
+        PyObject *o =  PyInt_FromString(szTmp, NULL, 10);
+#endif
         PyList_SetItem(resultobj, i, o );
       }
     }
   }
   {
-    /* %typemap(freearg) (int buckets, int* panHistogram)*/
+    /* %typemap(freearg) (int buckets, GUIntBig* panHistogram)*/
     if ( arg5 ) {
       VSIFree( arg5 );
     }
@@ -16528,7 +17054,7 @@ SWIGINTERN PyObject *_wrap_Band_GetHistogram(PyObject *SWIGUNUSEDPARM(self), PyO
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (int buckets, int* panHistogram)*/
+    /* %typemap(freearg) (int buckets, GUIntBig* panHistogram)*/
     if ( arg5 ) {
       VSIFree( arg5 );
     }
@@ -16549,7 +17075,7 @@ SWIGINTERN PyObject *_wrap_Band_GetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   double *arg2 = (double *) NULL ;
   double *arg3 = (double *) NULL ;
   int *arg4 = (int *) NULL ;
-  int **arg5 = (int **) NULL ;
+  GUIntBig **arg5 = (GUIntBig **) NULL ;
   int arg6 = (int) 1 ;
   GDALProgressFunc arg7 = (GDALProgressFunc) NULL ;
   void *arg8 = (void *) NULL ;
@@ -16580,7 +17106,7 @@ SWIGINTERN PyObject *_wrap_Band_GetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   
   double min_val, max_val;
   int buckets_val;
-  int *panHistogram;
+  GUIntBig *panHistogram;
   
   arg2 = &min_val;
   arg3 = &max_val;
@@ -16621,11 +17147,11 @@ SWIGINTERN PyObject *_wrap_Band_GetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
     arg4 = reinterpret_cast< int * >(argp4);
   }
   if (obj4) {
-    res5 = SWIG_ConvertPtr(obj4, &argp5,SWIGTYPE_p_p_int, 0 |  0 );
+    res5 = SWIG_ConvertPtr(obj4, &argp5,SWIGTYPE_p_p_GUIntBig, 0 |  0 );
     if (!SWIG_IsOK(res5)) {
-      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "Band_GetDefaultHistogram" "', argument " "5"" of type '" "int **""'"); 
+      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "Band_GetDefaultHistogram" "', argument " "5"" of type '" "GUIntBig **""'"); 
     }
-    arg5 = reinterpret_cast< int ** >(argp5);
+    arg5 = reinterpret_cast< GUIntBig ** >(argp5);
   }
   if (obj5) {
     ecode6 = SWIG_AsVal_int(obj5, &val6);
@@ -16690,7 +17216,7 @@ SWIGINTERN PyObject *_wrap_Band_GetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
     {
       psList = PyList_New(buckets_val);
       for( i = 0; i < buckets_val; i++ )
-      PyList_SetItem(psList, i, Py_BuildValue("i", panHistogram[i] ));
+      PyList_SetItem(psList, i, Py_BuildValue("K", panHistogram[i] ));
       
       CPLFree( panHistogram );
       
@@ -16727,7 +17253,7 @@ SWIGINTERN PyObject *_wrap_Band_SetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   double arg2 ;
   double arg3 ;
   int arg4 ;
-  int *arg5 = (int *) 0 ;
+  GUIntBig *arg5 = (GUIntBig *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   double val2 ;
@@ -16757,21 +17283,23 @@ SWIGINTERN PyObject *_wrap_Band_SetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   } 
   arg3 = static_cast< double >(val3);
   {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* %typemap(in,numinputs=1) (int nList, GUIntBig* pList)*/
     /* check if is List */
     if ( !PySequence_Check(obj3) ) {
       PyErr_SetString(PyExc_TypeError, "not a sequence");
       SWIG_fail;
     }
     arg4 = PySequence_Size(obj3);
-    arg5 = (int*) malloc(arg4*sizeof(int));
+    arg5 = (GUIntBig*) malloc(arg4*sizeof(GUIntBig));
     for( int i = 0; i<arg4; i++ ) {
       PyObject *o = PySequence_GetItem(obj3,i);
-      if ( !PyArg_Parse(o,"i",&arg5[i]) ) {
+      PY_LONG_LONG val;
+      if ( !PyArg_Parse(o,"K",&val) ) {
         PyErr_SetString(PyExc_TypeError, "not an integer");
         Py_DECREF(o);
         SWIG_fail;
       }
+      arg5[i] = (GUIntBig)val;
       Py_DECREF(o);
     }
   }
@@ -16789,7 +17317,7 @@ SWIGINTERN PyObject *_wrap_Band_SetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(freearg) (int nList, int* pList) */
+    /* %typemap(freearg) (int nList, GUIntBig* pList) */
     if (arg5) {
       free((void*) arg5);
     }
@@ -16797,7 +17325,7 @@ SWIGINTERN PyObject *_wrap_Band_SetDefaultHistogram(PyObject *SWIGUNUSEDPARM(sel
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (int nList, int* pList) */
+    /* %typemap(freearg) (int nList, GUIntBig* pList) */
     if (arg5) {
       free((void*) arg5);
     }
@@ -17441,8 +17969,11 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
   int *arg7 = (int *) 0 ;
   int *arg8 = (int *) 0 ;
   int *arg9 = (int *) 0 ;
-  int *arg10 = (int *) 0 ;
-  int *arg11 = (int *) 0 ;
+  GIntBig *arg10 = (GIntBig *) 0 ;
+  GIntBig *arg11 = (GIntBig *) 0 ;
+  GDALRIOResampleAlg arg12 = (GDALRIOResampleAlg) GRIORA_NearestNeighbour ;
+  GDALProgressFunc arg13 = (GDALProgressFunc) NULL ;
+  void *arg14 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -17457,8 +17988,10 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
   int val7 ;
   int val8 ;
   int val9 ;
-  int val10 ;
-  int val11 ;
+  GIntBig val10 ;
+  GIntBig val11 ;
+  int val12 ;
+  int ecode12 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
@@ -17469,16 +18002,26 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
   PyObject * obj7 = 0 ;
   PyObject * obj8 = 0 ;
   PyObject * obj9 = 0 ;
+  PyObject * obj10 = 0 ;
+  PyObject * obj11 = 0 ;
+  PyObject * obj12 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "buf_pixel_space",(char *) "buf_line_space", NULL 
+    (char *) "self",(char *) "xoff",(char *) "yoff",(char *) "xsize",(char *) "ysize",(char *) "buf_xsize",(char *) "buf_ysize",(char *) "buf_type",(char *) "buf_pixel_space",(char *) "buf_line_space",(char *) "resample_alg",(char *) "callback",(char *) "callback_data", NULL 
   };
   CPLErr result;
   
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg14 = psProgressInfo;
   {
     /* %typemap(in,numinputs=0) ( void **outPythonObject ) ( void *pyObject6 = NULL ) */
     arg6 = &pyObject6;
   }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOO|OOOOO:Band_ReadRaster1",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOO|OOOOOOOO:Band_ReadRaster1",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8,&obj9,&obj10,&obj11,&obj12)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALRasterBandShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Band_ReadRaster1" "', argument " "1"" of type '" "GDALRasterBandShadow *""'"); 
@@ -17551,12 +18094,12 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
   }
   if (obj8) {
     {
-      /* %typemap(in) (int *optional_##int) */
+      /* %typemap(in) (GIntBig *optional_##GIntBig) */
       if ( obj8 == Py_None ) {
         arg10 = 0;
       }
-      else if ( PyArg_Parse( obj8,"i" ,&val10 ) ) {
-        arg10 = (int *) &val10;
+      else if ( PyArg_Parse( obj8,"L" ,&val10 ) ) {
+        arg10 = (GIntBig *) &val10;
       }
       else {
         PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
@@ -17566,12 +18109,12 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
   }
   if (obj9) {
     {
-      /* %typemap(in) (int *optional_##int) */
+      /* %typemap(in) (GIntBig *optional_##GIntBig) */
       if ( obj9 == Py_None ) {
         arg11 = 0;
       }
-      else if ( PyArg_Parse( obj9,"i" ,&val11 ) ) {
-        arg11 = (int *) &val11;
+      else if ( PyArg_Parse( obj9,"L" ,&val11 ) ) {
+        arg11 = (GIntBig *) &val11;
       }
       else {
         PyErr_SetString( PyExc_TypeError, "Invalid Parameter" );
@@ -17579,11 +18122,51 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
+  if (obj10) {
+    ecode12 = SWIG_AsVal_int(obj10, &val12);
+    if (!SWIG_IsOK(ecode12)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode12), "in method '" "Band_ReadRaster1" "', argument " "12"" of type '" "GDALRIOResampleAlg""'");
+    } 
+    arg12 = static_cast< GDALRIOResampleAlg >(val12);
+  }
+  if (obj11) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj11 && obj11 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj11, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg13 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj11)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj11;
+          arg13 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj12) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj12 ;
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (CPLErr)GDALRasterBandShadow_ReadRaster1(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11);
+    result = (CPLErr)GDALRasterBandShadow_ReadRaster1(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17605,8 +18188,20 @@ SWIGINTERN PyObject *_wrap_Band_ReadRaster1(PyObject *SWIGUNUSEDPARM(self), PyOb
       Py_INCREF(resultobj);
     }
   }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
@@ -19072,25 +19667,57 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_RasterAttributeTable_ChangesAreWrittenToFile(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_RasterAttributeTable_ChangesAreWrittenToFile(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  GDALRasterAttributeTableShadow *arg1 = (GDALRasterAttributeTableShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:RasterAttributeTable_ChangesAreWrittenToFile",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALRasterAttributeTableShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "RasterAttributeTable_ChangesAreWrittenToFile" "', argument " "1"" of type '" "GDALRasterAttributeTableShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALRasterAttributeTableShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)GDALRasterAttributeTableShadow_ChangesAreWrittenToFile(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_RasterAttributeTable_DumpReadable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   GDALRasterAttributeTableShadow *arg1 = (GDALRasterAttributeTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:RasterAttributeTable_ChangesAreWrittenToFile",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:RasterAttributeTable_DumpReadable",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALRasterAttributeTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "RasterAttributeTable_ChangesAreWrittenToFile" "', argument " "1"" of type '" "GDALRasterAttributeTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "RasterAttributeTable_DumpReadable" "', argument " "1"" of type '" "GDALRasterAttributeTableShadow *""'"); 
   }
   arg1 = reinterpret_cast< GDALRasterAttributeTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALRasterAttributeTableShadow_ChangesAreWrittenToFile(arg1);
+    GDALRasterAttributeTableShadow_DumpReadable(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19098,7 +19725,7 @@ SWIGINTERN PyObject *_wrap_RasterAttributeTable_ChangesAreWrittenToFile(PyObject
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
@@ -21939,7 +22566,7 @@ SWIGINTERN PyObject *_wrap_InvGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObj
   double argin1[6] ;
   double argout2[6] ;
   PyObject * obj0 = 0 ;
-  int result;
+  RETURN_NONE result;
   
   {
     /* %typemap(in,numinputs=0) (double argout2[ANY]) */
@@ -21974,7 +22601,7 @@ SWIGINTERN PyObject *_wrap_InvGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObj
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)GDALInvGeoTransform(arg1,arg2);
+    result = GDALInvGeoTransform(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -21982,12 +22609,24 @@ SWIGINTERN PyObject *_wrap_InvGeoTransform(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  /*%typemap(out) IF_FALSE_RETURN_NONE */
   {
     /* %typemap(argout) (double argout[ANY]) */
     PyObject *out = CreateTupleFromDoubleArray( arg2, 6 );
     resultobj = t_output_helper(resultobj,out);
   }
+  {
+    /* %typemap(ret) IF_FALSE_RETURN_NONE */
+    if (result == 0 ) {
+      Py_XDECREF( resultobj );
+      resultobj = Py_None;
+      Py_INCREF(resultobj);
+    }
+    if (resultobj == 0) {
+      resultobj = Py_None;
+      Py_INCREF(resultobj);
+    }
+  }
   return resultobj;
 fail:
   return NULL;
@@ -22554,30 +23193,256 @@ SWIGINTERN PyObject *_wrap_ParseXMLString(PyObject *SWIGUNUSEDPARM(self), PyObje
     /* %typemap(ret) (CPLXMLNode*) */
     if ( result ) CPLDestroyXMLNode( result );
   }
-  return resultobj;
-fail:
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_SerializeXMLTree(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  CPLXMLNode *arg1 = (CPLXMLNode *) 0 ;
-  PyObject * obj0 = 0 ;
-  retStringAndCPLFree *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:SerializeXMLTree",&obj0)) SWIG_fail;
+  return resultobj;
+fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_SerializeXMLTree(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  CPLXMLNode *arg1 = (CPLXMLNode *) 0 ;
+  PyObject * obj0 = 0 ;
+  retStringAndCPLFree *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:SerializeXMLTree",&obj0)) SWIG_fail;
+  {
+    /* %typemap(python,in) (CPLXMLNode* xmlnode ) */
+    arg1 = PyListToXMLTree( obj0 );
+    if ( !arg1 ) SWIG_fail;
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (retStringAndCPLFree *)CPLSerializeXMLTree(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      resultobj = GDALPythonObjectFromCStr( (const char *)result);
+      CPLFree(result);
+    }
+  }
+  {
+    /* %typemap(freearg) (CPLXMLNode *xmlnode) */
+    if ( arg1 ) CPLDestroyXMLNode( arg1 );
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (CPLXMLNode *xmlnode) */
+    if ( arg1 ) CPLDestroyXMLNode( arg1 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_GetJPEG2000Structure(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  char *arg1 = (char *) 0 ;
+  char **arg2 = (char **) NULL ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  CPLXMLNode *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O|O:GetJPEG2000Structure",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GetJPEG2000Structure" "', argument " "1"" of type '" "char const *""'");
+  }
+  arg1 = reinterpret_cast< char * >(buf1);
+  if (obj1) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj1)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg2 = CSLAddString( arg2, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  {
+    if (!arg1) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (CPLXMLNode *)GDALGetJPEG2000Structure((char const *)arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) (CPLXMLNode*) */
+    
+    CPLXMLNode *psXMLTree = result;
+    int         bFakeRoot = FALSE;
+    
+    if( psXMLTree != NULL && psXMLTree->psNext != NULL )
+    {
+      CPLXMLNode *psFirst = psXMLTree;
+      
+      /* create a "pseudo" root if we have multiple elements */
+      psXMLTree = CPLCreateXMLNode( NULL, CXT_Element, "" );
+      psXMLTree->psChild = psFirst;
+      bFakeRoot = TRUE;
+    }
+    
+    resultobj = XMLTreeToPyList( psXMLTree );
+    
+    if( bFakeRoot )
+    {
+      psXMLTree->psChild = NULL;
+      CPLDestroyXMLNode( psXMLTree );
+    }
+  }
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
+  {
+    /* %typemap(ret) (CPLXMLNode*) */
+    if ( result ) CPLDestroyXMLNode( result );
+  }
+  return resultobj;
+fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_GetJPEG2000StructureAsString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  char *arg1 = (char *) 0 ;
+  char **arg2 = (char **) NULL ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  retStringAndCPLFree *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O|O:GetJPEG2000StructureAsString",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GetJPEG2000StructureAsString" "', argument " "1"" of type '" "char const *""'");
+  }
+  arg1 = reinterpret_cast< char * >(buf1);
+  if (obj1) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj1)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg2 = CSLAddString( arg2, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
   {
-    /* %typemap(python,in) (CPLXMLNode* xmlnode ) */
-    arg1 = PyListToXMLTree( obj0 );
-    if ( !arg1 ) SWIG_fail;
+    if (!arg1) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (retStringAndCPLFree *)CPLSerializeXMLTree(arg1);
+    result = (retStringAndCPLFree *)GetJPEG2000StructureAsString((char const *)arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -22593,15 +23458,17 @@ SWIGINTERN PyObject *_wrap_SerializeXMLTree(PyObject *SWIGUNUSEDPARM(self), PyOb
       CPLFree(result);
     }
   }
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   {
-    /* %typemap(freearg) (CPLXMLNode *xmlnode) */
-    if ( arg1 ) CPLDestroyXMLNode( arg1 );
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
   }
   return resultobj;
 fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   {
-    /* %typemap(freearg) (CPLXMLNode *xmlnode) */
-    if ( arg1 ) CPLDestroyXMLNode( arg1 );
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
   }
   return NULL;
 }
@@ -22765,6 +23632,237 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_OpenEx(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  char *arg1 = (char *) 0 ;
+  unsigned int arg2 = (unsigned int) 0 ;
+  char **arg3 = (char **) NULL ;
+  char **arg4 = (char **) NULL ;
+  char **arg5 = (char **) NULL ;
+  int bToFree1 = 0 ;
+  unsigned int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  char *  kwnames[] = {
+    (char *) "utf8_path",(char *) "nOpenFlags",(char *) "allowed_drivers",(char *) "open_options",(char *) "sibling_files", NULL 
+  };
+  GDALDatasetShadow *result = 0 ;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOOO:OpenEx",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg1 = GDALPythonObjectToCStr( obj0, &bToFree1 );
+    if (arg1 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
+  }
+  if (obj1) {
+    ecode2 = SWIG_AsVal_unsigned_SS_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "OpenEx" "', argument " "2"" of type '" "unsigned int""'");
+    } 
+    arg2 = static_cast< unsigned int >(val2);
+  }
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  if (obj4) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj4) || PyUnicode_Check(obj4)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj4)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj4);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj4,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg5 = CSLAddString( arg5, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  {
+    if (!arg1) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (GDALDatasetShadow *)OpenEx((char const *)arg1,arg2,arg3,arg4,arg5);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_GDALDatasetShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg1, bToFree1);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg1, bToFree1);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
+  }
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_OpenShared(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   char *arg1 = (char *) 0 ;
@@ -23109,9 +24207,9 @@ static PyMethodDef SwigMethods[] = {
 		"    char options = None, GDALProgressFunc callback = None, \n"
 		"    void callback_data = None) -> Dataset\n"
 		""},
-	 { (char *)"Driver_Delete", _wrap_Driver_Delete, METH_VARARGS, (char *)"Driver_Delete(Driver self, char utf8_path) -> int"},
-	 { (char *)"Driver_Rename", _wrap_Driver_Rename, METH_VARARGS, (char *)"Driver_Rename(Driver self, char newName, char oldName) -> int"},
-	 { (char *)"Driver_CopyFiles", _wrap_Driver_CopyFiles, METH_VARARGS, (char *)"Driver_CopyFiles(Driver self, char newName, char oldName) -> int"},
+	 { (char *)"Driver_Delete", _wrap_Driver_Delete, METH_VARARGS, (char *)"Driver_Delete(Driver self, char utf8_path) -> CPLErr"},
+	 { (char *)"Driver_Rename", _wrap_Driver_Rename, METH_VARARGS, (char *)"Driver_Rename(Driver self, char newName, char oldName) -> CPLErr"},
+	 { (char *)"Driver_CopyFiles", _wrap_Driver_CopyFiles, METH_VARARGS, (char *)"Driver_CopyFiles(Driver self, char newName, char oldName) -> CPLErr"},
 	 { (char *)"Driver_Register", _wrap_Driver_Register, METH_VARARGS, (char *)"Driver_Register(Driver self) -> int"},
 	 { (char *)"Driver_Deregister", _wrap_Driver_Deregister, METH_VARARGS, (char *)"Driver_Deregister(Driver self)"},
 	 { (char *)"Driver_swigregister", Driver_swigregister, METH_VARARGS, NULL},
@@ -23161,20 +24259,6 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"GDAL_GCP_Info_set", _wrap_GDAL_GCP_Info_set, METH_VARARGS, (char *)"GDAL_GCP_Info_set(GCP gcp, char pszInfo)"},
 	 { (char *)"GDAL_GCP_Id_get", _wrap_GDAL_GCP_Id_get, METH_VARARGS, (char *)"GDAL_GCP_Id_get(GCP gcp) -> char"},
 	 { (char *)"GDAL_GCP_Id_set", _wrap_GDAL_GCP_Id_set, METH_VARARGS, (char *)"GDAL_GCP_Id_set(GCP gcp, char pszId)"},
-	 { (char *)"GDAL_GCP_get_GCPX", _wrap_GDAL_GCP_get_GCPX, METH_VARARGS, (char *)"GDAL_GCP_get_GCPX(GCP gcp) -> double"},
-	 { (char *)"GDAL_GCP_set_GCPX", _wrap_GDAL_GCP_set_GCPX, METH_VARARGS, (char *)"GDAL_GCP_set_GCPX(GCP gcp, double dfGCPX)"},
-	 { (char *)"GDAL_GCP_get_GCPY", _wrap_GDAL_GCP_get_GCPY, METH_VARARGS, (char *)"GDAL_GCP_get_GCPY(GCP gcp) -> double"},
-	 { (char *)"GDAL_GCP_set_GCPY", _wrap_GDAL_GCP_set_GCPY, METH_VARARGS, (char *)"GDAL_GCP_set_GCPY(GCP gcp, double dfGCPY)"},
-	 { (char *)"GDAL_GCP_get_GCPZ", _wrap_GDAL_GCP_get_GCPZ, METH_VARARGS, (char *)"GDAL_GCP_get_GCPZ(GCP gcp) -> double"},
-	 { (char *)"GDAL_GCP_set_GCPZ", _wrap_GDAL_GCP_set_GCPZ, METH_VARARGS, (char *)"GDAL_GCP_set_GCPZ(GCP gcp, double dfGCPZ)"},
-	 { (char *)"GDAL_GCP_get_GCPPixel", _wrap_GDAL_GCP_get_GCPPixel, METH_VARARGS, (char *)"GDAL_GCP_get_GCPPixel(GCP gcp) -> double"},
-	 { (char *)"GDAL_GCP_set_GCPPixel", _wrap_GDAL_GCP_set_GCPPixel, METH_VARARGS, (char *)"GDAL_GCP_set_GCPPixel(GCP gcp, double dfGCPPixel)"},
-	 { (char *)"GDAL_GCP_get_GCPLine", _wrap_GDAL_GCP_get_GCPLine, METH_VARARGS, (char *)"GDAL_GCP_get_GCPLine(GCP gcp) -> double"},
-	 { (char *)"GDAL_GCP_set_GCPLine", _wrap_GDAL_GCP_set_GCPLine, METH_VARARGS, (char *)"GDAL_GCP_set_GCPLine(GCP gcp, double dfGCPLine)"},
-	 { (char *)"GDAL_GCP_get_Info", _wrap_GDAL_GCP_get_Info, METH_VARARGS, (char *)"GDAL_GCP_get_Info(GCP gcp) -> char"},
-	 { (char *)"GDAL_GCP_set_Info", _wrap_GDAL_GCP_set_Info, METH_VARARGS, (char *)"GDAL_GCP_set_Info(GCP gcp, char pszInfo)"},
-	 { (char *)"GDAL_GCP_get_Id", _wrap_GDAL_GCP_get_Id, METH_VARARGS, (char *)"GDAL_GCP_get_Id(GCP gcp) -> char"},
-	 { (char *)"GDAL_GCP_set_Id", _wrap_GDAL_GCP_set_Id, METH_VARARGS, (char *)"GDAL_GCP_set_Id(GCP gcp, char pszId)"},
 	 { (char *)"GCPsToGeoTransform", _wrap_GCPsToGeoTransform, METH_VARARGS, (char *)"GCPsToGeoTransform(int nGCPs, int bApproxOK = 1) -> RETURN_NONE"},
 	 { (char *)"delete_VirtualMem", _wrap_delete_VirtualMem, METH_VARARGS, (char *)"delete_VirtualMem(VirtualMem self)"},
 	 { (char *)"VirtualMem_GetAddr", _wrap_VirtualMem_GetAddr, METH_VARARGS, (char *)"VirtualMem_GetAddr(VirtualMem self)"},
@@ -23242,17 +24326,42 @@ static PyMethodDef SwigMethods[] = {
 		"    GDALTileOrganization eTileOrganization, \n"
 		"    size_t nCacheSize, char options = None) -> VirtualMem\n"
 		""},
+	 { (char *)"Dataset_CreateLayer", (PyCFunction) _wrap_Dataset_CreateLayer, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+		"Dataset_CreateLayer(Dataset self, char name, SpatialReference srs = None, \n"
+		"    OGRwkbGeometryType geom_type = wkbUnknown, \n"
+		"    char options = None) -> Layer\n"
+		""},
+	 { (char *)"Dataset_CopyLayer", (PyCFunction) _wrap_Dataset_CopyLayer, METH_VARARGS | METH_KEYWORDS, (char *)"Dataset_CopyLayer(Dataset self, Layer src_layer, char new_name, char options = None) -> Layer"},
+	 { (char *)"Dataset_DeleteLayer", _wrap_Dataset_DeleteLayer, METH_VARARGS, (char *)"Dataset_DeleteLayer(Dataset self, int index) -> OGRErr"},
+	 { (char *)"Dataset_GetLayerCount", _wrap_Dataset_GetLayerCount, METH_VARARGS, (char *)"Dataset_GetLayerCount(Dataset self) -> int"},
+	 { (char *)"Dataset_GetLayerByIndex", _wrap_Dataset_GetLayerByIndex, METH_VARARGS, (char *)"Dataset_GetLayerByIndex(Dataset self, int index = 0) -> Layer"},
+	 { (char *)"Dataset_GetLayerByName", _wrap_Dataset_GetLayerByName, METH_VARARGS, (char *)"Dataset_GetLayerByName(Dataset self, char layer_name) -> Layer"},
+	 { (char *)"Dataset_TestCapability", _wrap_Dataset_TestCapability, METH_VARARGS, (char *)"Dataset_TestCapability(Dataset self, char cap) -> bool"},
+	 { (char *)"Dataset_ExecuteSQL", (PyCFunction) _wrap_Dataset_ExecuteSQL, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+		"Dataset_ExecuteSQL(Dataset self, char statement, Geometry spatialFilter = None, \n"
+		"    char dialect = \"\") -> Layer\n"
+		""},
+	 { (char *)"Dataset_ReleaseResultSet", _wrap_Dataset_ReleaseResultSet, METH_VARARGS, (char *)"Dataset_ReleaseResultSet(Dataset self, Layer layer)"},
+	 { (char *)"Dataset_GetStyleTable", _wrap_Dataset_GetStyleTable, METH_VARARGS, (char *)"Dataset_GetStyleTable(Dataset self) -> StyleTable"},
+	 { (char *)"Dataset_SetStyleTable", _wrap_Dataset_SetStyleTable, METH_VARARGS, (char *)"Dataset_SetStyleTable(Dataset self, StyleTable table)"},
+	 { (char *)"Dataset_StartTransaction", (PyCFunction) _wrap_Dataset_StartTransaction, METH_VARARGS | METH_KEYWORDS, (char *)"Dataset_StartTransaction(Dataset self, int force = True) -> OGRErr"},
+	 { (char *)"Dataset_CommitTransaction", _wrap_Dataset_CommitTransaction, METH_VARARGS, (char *)"Dataset_CommitTransaction(Dataset self) -> OGRErr"},
+	 { (char *)"Dataset_RollbackTransaction", _wrap_Dataset_RollbackTransaction, METH_VARARGS, (char *)"Dataset_RollbackTransaction(Dataset self) -> OGRErr"},
 	 { (char *)"Dataset_ReadRaster1", (PyCFunction) _wrap_Dataset_ReadRaster1, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"Dataset_ReadRaster1(Dataset self, int xoff, int yoff, int xsize, int ysize, \n"
 		"    int buf_xsize = None, int buf_ysize = None, \n"
 		"    GDALDataType buf_type = None, int band_list = 0, \n"
-		"    int buf_pixel_space = None, int buf_line_space = None, \n"
-		"    int buf_band_space = None) -> CPLErr\n"
+		"    GIntBig buf_pixel_space = None, GIntBig buf_line_space = None, \n"
+		"    GIntBig buf_band_space = None, \n"
+		"    GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour, \n"
+		"    GDALProgressFunc callback = None, \n"
+		"    void callback_data = None) -> CPLErr\n"
 		""},
 	 { (char *)"Dataset_swigregister", Dataset_swigregister, METH_VARARGS, NULL},
 	 { (char *)"Band_XSize_get", _wrap_Band_XSize_get, METH_VARARGS, (char *)"Band_XSize_get(Band self) -> int"},
 	 { (char *)"Band_YSize_get", _wrap_Band_YSize_get, METH_VARARGS, (char *)"Band_YSize_get(Band self) -> int"},
 	 { (char *)"Band_DataType_get", _wrap_Band_DataType_get, METH_VARARGS, (char *)"Band_DataType_get(Band self) -> GDALDataType"},
+	 { (char *)"Band_GetDataset", _wrap_Band_GetDataset, METH_VARARGS, (char *)"Band_GetDataset(Band self) -> Dataset"},
 	 { (char *)"Band_GetBand", _wrap_Band_GetBand, METH_VARARGS, (char *)"Band_GetBand(Band self) -> int"},
 	 { (char *)"Band_GetBlockSize", _wrap_Band_GetBlockSize, METH_VARARGS, (char *)"Band_GetBlockSize(Band self)"},
 	 { (char *)"Band_GetColorInterpretation", _wrap_Band_GetColorInterpretation, METH_VARARGS, (char *)"Band_GetColorInterpretation(Band self) -> GDALColorInterp"},
@@ -23310,7 +24419,7 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { (char *)"Band_GetDefaultHistogram", (PyCFunction) _wrap_Band_GetDefaultHistogram, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"Band_GetDefaultHistogram(Band self, double min_ret = None, double max_ret = None, \n"
-		"    int buckets_ret = None, int ppanHistogram = None, \n"
+		"    int buckets_ret = None, GUIntBig ppanHistogram = None, \n"
 		"    int force = 1, GDALProgressFunc callback = None, \n"
 		"    void callback_data = None) -> CPLErr\n"
 		""},
@@ -23334,8 +24443,10 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"Band_ReadRaster1", (PyCFunction) _wrap_Band_ReadRaster1, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"Band_ReadRaster1(Band self, int xoff, int yoff, int xsize, int ysize, \n"
 		"    int buf_xsize = None, int buf_ysize = None, \n"
-		"    int buf_type = None, int buf_pixel_space = None, \n"
-		"    int buf_line_space = None) -> CPLErr\n"
+		"    int buf_type = None, GIntBig buf_pixel_space = None, \n"
+		"    GIntBig buf_line_space = None, GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour, \n"
+		"    GDALProgressFunc callback = None, \n"
+		"    void callback_data = None) -> CPLErr\n"
 		""},
 	 { (char *)"Band_ReadBlock", (PyCFunction) _wrap_Band_ReadBlock, METH_VARARGS | METH_KEYWORDS, (char *)"Band_ReadBlock(Band self, int xoff, int yoff) -> CPLErr"},
 	 { (char *)"Band_swigregister", Band_swigregister, METH_VARARGS, NULL},
@@ -23376,6 +24487,7 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"RasterAttributeTable_SetLinearBinning", _wrap_RasterAttributeTable_SetLinearBinning, METH_VARARGS, (char *)"RasterAttributeTable_SetLinearBinning(RasterAttributeTable self, double dfRow0Min, double dfBinSize) -> int"},
 	 { (char *)"RasterAttributeTable_GetRowOfValue", _wrap_RasterAttributeTable_GetRowOfValue, METH_VARARGS, (char *)"RasterAttributeTable_GetRowOfValue(RasterAttributeTable self, double dfValue) -> int"},
 	 { (char *)"RasterAttributeTable_ChangesAreWrittenToFile", _wrap_RasterAttributeTable_ChangesAreWrittenToFile, METH_VARARGS, (char *)"RasterAttributeTable_ChangesAreWrittenToFile(RasterAttributeTable self) -> int"},
+	 { (char *)"RasterAttributeTable_DumpReadable", _wrap_RasterAttributeTable_DumpReadable, METH_VARARGS, (char *)"RasterAttributeTable_DumpReadable(RasterAttributeTable self)"},
 	 { (char *)"RasterAttributeTable_swigregister", RasterAttributeTable_swigregister, METH_VARARGS, NULL},
 	 { (char *)"TermProgress_nocb", (PyCFunction) _wrap_TermProgress_nocb, METH_VARARGS | METH_KEYWORDS, (char *)"TermProgress_nocb(double dfProgress, char pszMessage = None, void pData = None) -> int"},
 	 { (char *)"ComputeMedianCutPCT", (PyCFunction) _wrap_ComputeMedianCutPCT, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
@@ -23400,14 +24512,14 @@ static PyMethodDef SwigMethods[] = {
 		"    GDALProgressFunc callback = None, void callback_data = None) -> int\n"
 		""},
 	 { (char *)"RasterizeLayer", (PyCFunction) _wrap_RasterizeLayer, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
-		"RasterizeLayer(Dataset dataset, int bands, OGRLayerShadow layer, void pfnTransformer = None, \n"
+		"RasterizeLayer(Dataset dataset, int bands, Layer layer, void pfnTransformer = None, \n"
 		"    void pTransformArg = None, \n"
-		"    int burn_values = 0, char options = None, \n"
-		"    GDALProgressFunc callback = None, void callback_data = None) -> int\n"
+		"    int burn_values = 0, char options = None, GDALProgressFunc callback = None, \n"
+		"    void callback_data = None) -> int\n"
 		""},
 	 { (char *)"Polygonize", (PyCFunction) _wrap_Polygonize, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
-		"Polygonize(Band srcBand, Band maskBand, OGRLayerShadow outLayer, \n"
-		"    int iPixValField, char options = None, GDALProgressFunc callback = None, \n"
+		"Polygonize(Band srcBand, Band maskBand, Layer outLayer, int iPixValField, \n"
+		"    char options = None, GDALProgressFunc callback = None, \n"
 		"    void callback_data = None) -> int\n"
 		""},
 	 { (char *)"FillNodata", (PyCFunction) _wrap_FillNodata, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
@@ -23433,7 +24545,7 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"ContourGenerate", (PyCFunction) _wrap_ContourGenerate, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"ContourGenerate(Band srcBand, double contourInterval, double contourBase, \n"
 		"    int fixedLevelCount, int useNoData, double noDataValue, \n"
-		"    OGRLayerShadow dstLayer, int idField, \n"
+		"    Layer dstLayer, int idField, \n"
 		"    int elevField, GDALProgressFunc callback = None, \n"
 		"    void callback_data = None) -> int\n"
 		""},
@@ -23457,7 +24569,7 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { (char *)"Transformer_swigregister", Transformer_swigregister, METH_VARARGS, NULL},
 	 { (char *)"ApplyGeoTransform", _wrap_ApplyGeoTransform, METH_VARARGS, (char *)"ApplyGeoTransform(double padfGeoTransform, double dfPixel, double dfLine)"},
-	 { (char *)"InvGeoTransform", _wrap_InvGeoTransform, METH_VARARGS, (char *)"InvGeoTransform(double gt_in) -> int"},
+	 { (char *)"InvGeoTransform", _wrap_InvGeoTransform, METH_VARARGS, (char *)"InvGeoTransform(double gt_in) -> RETURN_NONE"},
 	 { (char *)"VersionInfo", _wrap_VersionInfo, METH_VARARGS, (char *)"VersionInfo(char request = \"VERSION_NUM\") -> char"},
 	 { (char *)"AllRegister", _wrap_AllRegister, METH_VARARGS, (char *)"AllRegister()"},
 	 { (char *)"GDALDestroyDriverManager", _wrap_GDALDestroyDriverManager, METH_VARARGS, (char *)"GDALDestroyDriverManager()"},
@@ -23475,10 +24587,17 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"DecToPackedDMS", _wrap_DecToPackedDMS, METH_VARARGS, (char *)"DecToPackedDMS(double dfDec) -> double"},
 	 { (char *)"ParseXMLString", _wrap_ParseXMLString, METH_VARARGS, (char *)"ParseXMLString(char pszXMLString) -> CPLXMLNode"},
 	 { (char *)"SerializeXMLTree", _wrap_SerializeXMLTree, METH_VARARGS, (char *)"SerializeXMLTree(CPLXMLNode xmlnode) -> retStringAndCPLFree"},
+	 { (char *)"GetJPEG2000Structure", _wrap_GetJPEG2000Structure, METH_VARARGS, (char *)"GetJPEG2000Structure(char pszFilename, char options = None) -> CPLXMLNode"},
+	 { (char *)"GetJPEG2000StructureAsString", _wrap_GetJPEG2000StructureAsString, METH_VARARGS, (char *)"GetJPEG2000StructureAsString(char pszFilename, char options = None) -> retStringAndCPLFree"},
 	 { (char *)"GetDriverCount", _wrap_GetDriverCount, METH_VARARGS, (char *)"GetDriverCount() -> int"},
 	 { (char *)"GetDriverByName", _wrap_GetDriverByName, METH_VARARGS, (char *)"GetDriverByName(char name) -> Driver"},
 	 { (char *)"GetDriver", _wrap_GetDriver, METH_VARARGS, (char *)"GetDriver(int i) -> Driver"},
 	 { (char *)"Open", _wrap_Open, METH_VARARGS, (char *)"Open(char utf8_path, GDALAccess eAccess = GA_ReadOnly) -> Dataset"},
+	 { (char *)"OpenEx", (PyCFunction) _wrap_OpenEx, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+		"OpenEx(char utf8_path, unsigned int nOpenFlags = 0, char allowed_drivers = None, \n"
+		"    char open_options = None, \n"
+		"    char sibling_files = None) -> Dataset\n"
+		""},
 	 { (char *)"OpenShared", _wrap_OpenShared, METH_VARARGS, (char *)"OpenShared(char utf8_path, GDALAccess eAccess = GA_ReadOnly) -> Dataset"},
 	 { (char *)"IdentifyDriver", _wrap_IdentifyDriver, METH_VARARGS, (char *)"IdentifyDriver(char utf8_path, char papszSiblings = None) -> Driver"},
 	 { (char *)"GeneralCmdLineProcessor", _wrap_GeneralCmdLineProcessor, METH_VARARGS, (char *)"GeneralCmdLineProcessor(char papszArgv, int nOptions = 0) -> char"},
@@ -23491,6 +24610,9 @@ static PyMethodDef SwigMethods[] = {
 static void *_p_GDALDriverShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((GDALMajorObjectShadow *)  ((GDALDriverShadow *) x));
 }
+static void *_p_OGRLayerShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRLayerShadow *) x));
+}
 static void *_p_GDALDatasetShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((GDALMajorObjectShadow *)  ((GDALDatasetShadow *) x));
 }
@@ -23513,16 +24635,20 @@ static swig_type_info _swigt__p_GDALRasterBandShadow = {"_p_GDALRasterBandShadow
 static swig_type_info _swigt__p_GDALTransformerInfoShadow = {"_p_GDALTransformerInfoShadow", "GDALTransformerInfoShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GDAL_GCP = {"_p_GDAL_GCP", "GDAL_GCP *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GIntBig = {"_p_GIntBig", "GIntBig *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_GUIntBig = {"_p_GUIntBig", "GUIntBig *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_OGRGeometryShadow = {"_p_OGRGeometryShadow", "OGRGeometryShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_OGRLayerShadow = {"_p_OGRLayerShadow", "OGRLayerShadow *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_OGRStyleTableShadow = {"_p_OGRStyleTableShadow", "OGRStyleTableShadow *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_OSRSpatialReferenceShadow = {"_p_OSRSpatialReferenceShadow", "OSRSpatialReferenceShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_StatBuf = {"_p_StatBuf", "StatBuf *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_char = {"_p_char", "char *|retStringAndCPLFree *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_double = {"_p_double", "double *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_f_double_p_q_const__char_p_void__int = {"_p_f_double_p_q_const__char_p_void__int", "int (*)(double,char const *,void *)", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "CPLErr *|GDALRATFieldType *|int *|GDALColorInterp *|GDALAccess *|GDALPaletteInterp *|GDALDataType *|GDALAsyncStatusType *|GDALRWFlag *|GDALTileOrganization *|GDALRATFieldUsage *|GDALResampleAlg *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldSubType *|GDALRATFieldType *|OGRFieldType *|int *|GDALAccess *|OGRwkbByteOrder *|CPLErr *|GDALRWFlag *|OGRJustification *|GDALRATFieldUsage *|GDALTileOrganization *|GDALPaletteInterp *|GDALColorInterp *|GDALResampleAlg *|GDALRIOResampleAlg *|OGRErr *|OGRwkbGeometryType *|GDALDataType *|GDALAsyncStatusType *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_GDALRasterBandShadow = {"_p_p_GDALRasterBandShadow", "GDALRasterBandShadow **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_GDAL_GCP = {"_p_p_GDAL_GCP", "GDAL_GCP **", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_GUIntBig = {"_p_p_GUIntBig", "GUIntBig **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_p_int = {"_p_p_int", "int **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_void = {"_p_p_void", "void **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_size_t = {"_p_size_t", "size_t *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_void = {"_p_void", "VSILFILE *|void *", 0, 0, (void*)0, 0};
@@ -23544,7 +24670,11 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_GDALTransformerInfoShadow,
   &_swigt__p_GDAL_GCP,
   &_swigt__p_GIntBig,
+  &_swigt__p_GUIntBig,
+  &_swigt__p_OGRGeometryShadow,
   &_swigt__p_OGRLayerShadow,
+  &_swigt__p_OGRStyleTableShadow,
+  &_swigt__p_OSRSpatialReferenceShadow,
   &_swigt__p_StatBuf,
   &_swigt__p_char,
   &_swigt__p_double,
@@ -23552,8 +24682,8 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_int,
   &_swigt__p_p_GDALRasterBandShadow,
   &_swigt__p_p_GDAL_GCP,
+  &_swigt__p_p_GUIntBig,
   &_swigt__p_p_char,
-  &_swigt__p_p_int,
   &_swigt__p_p_void,
   &_swigt__p_size_t,
   &_swigt__p_void,
@@ -23568,14 +24698,18 @@ static swig_cast_info _swigc__p_GDALColorEntry[] = {  {&_swigt__p_GDALColorEntry
 static swig_cast_info _swigc__p_GDALColorTableShadow[] = {  {&_swigt__p_GDALColorTableShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALDatasetShadow[] = {  {&_swigt__p_GDALDatasetShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALDriverShadow[] = {  {&_swigt__p_GDALDriverShadow, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_GDALDriverShadow, _p_GDALDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALDatasetShadow, _p_GDALDatasetShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALRasterBandShadow, _p_GDALRasterBandShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_GDALDriverShadow, _p_GDALDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRLayerShadow, _p_OGRLayerShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALDatasetShadow, _p_GDALDatasetShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_GDALRasterBandShadow, _p_GDALRasterBandShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALProgressFunc[] = {  {&_swigt__p_GDALProgressFunc, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterAttributeTableShadow[] = {  {&_swigt__p_GDALRasterAttributeTableShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALRasterBandShadow[] = {  {&_swigt__p_GDALRasterBandShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALTransformerInfoShadow[] = {  {&_swigt__p_GDALTransformerInfoShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDAL_GCP[] = {  {&_swigt__p_GDAL_GCP, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GIntBig[] = {  {&_swigt__p_GIntBig, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_GUIntBig[] = {  {&_swigt__p_GUIntBig, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_OGRGeometryShadow[] = {  {&_swigt__p_OGRGeometryShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_OGRLayerShadow[] = {  {&_swigt__p_OGRLayerShadow, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_OGRStyleTableShadow[] = {  {&_swigt__p_OGRStyleTableShadow, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_OSRSpatialReferenceShadow[] = {  {&_swigt__p_OSRSpatialReferenceShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_StatBuf[] = {  {&_swigt__p_StatBuf, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
@@ -23583,8 +24717,8 @@ static swig_cast_info _swigc__p_f_double_p_q_const__char_p_void__int[] = {  {&_s
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_GDALRasterBandShadow[] = {  {&_swigt__p_p_GDALRasterBandShadow, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_GDAL_GCP[] = {  {&_swigt__p_p_GDAL_GCP, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_GUIntBig[] = {  {&_swigt__p_p_GUIntBig, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_p_int[] = {  {&_swigt__p_p_int, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_void[] = {  {&_swigt__p_p_void, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_size_t[] = {  {&_swigt__p_size_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_void[] = {  {&_swigt__p_void, 0, 0, 0},{0, 0, 0, 0}};
@@ -23606,7 +24740,11 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_GDALTransformerInfoShadow,
   _swigc__p_GDAL_GCP,
   _swigc__p_GIntBig,
+  _swigc__p_GUIntBig,
+  _swigc__p_OGRGeometryShadow,
   _swigc__p_OGRLayerShadow,
+  _swigc__p_OGRStyleTableShadow,
+  _swigc__p_OSRSpatialReferenceShadow,
   _swigc__p_StatBuf,
   _swigc__p_char,
   _swigc__p_double,
@@ -23614,8 +24752,8 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_int,
   _swigc__p_p_GDALRasterBandShadow,
   _swigc__p_p_GDAL_GCP,
+  _swigc__p_p_GUIntBig,
   _swigc__p_p_char,
-  _swigc__p_p_int,
   _swigc__p_p_void,
   _swigc__p_size_t,
   _swigc__p_void,
diff --git a/swig/python/extensions/gdalconst_wrap.c b/swig/python/extensions/gdalconst_wrap.c
index f3b89c9..02bd730 100644
--- a/swig/python/extensions/gdalconst_wrap.c
+++ b/swig/python/extensions/gdalconst_wrap.c
@@ -3416,6 +3416,14 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "GA_Update",SWIG_From_int((int)(GA_Update)));
   SWIG_Python_SetConstant(d, "GF_Read",SWIG_From_int((int)(GF_Read)));
   SWIG_Python_SetConstant(d, "GF_Write",SWIG_From_int((int)(GF_Write)));
+  SWIG_Python_SetConstant(d, "GRIORA_NearestNeighbour",SWIG_From_int((int)(GRIORA_NearestNeighbour)));
+  SWIG_Python_SetConstant(d, "GRIORA_Bilinear",SWIG_From_int((int)(GRIORA_Bilinear)));
+  SWIG_Python_SetConstant(d, "GRIORA_Cubic",SWIG_From_int((int)(GRIORA_Cubic)));
+  SWIG_Python_SetConstant(d, "GRIORA_CubicSpline",SWIG_From_int((int)(GRIORA_CubicSpline)));
+  SWIG_Python_SetConstant(d, "GRIORA_Lanczos",SWIG_From_int((int)(GRIORA_Lanczos)));
+  SWIG_Python_SetConstant(d, "GRIORA_Average",SWIG_From_int((int)(GRIORA_Average)));
+  SWIG_Python_SetConstant(d, "GRIORA_Mode",SWIG_From_int((int)(GRIORA_Mode)));
+  SWIG_Python_SetConstant(d, "GRIORA_Gauss",SWIG_From_int((int)(GRIORA_Gauss)));
   SWIG_Python_SetConstant(d, "GCI_Undefined",SWIG_From_int((int)(GCI_Undefined)));
   SWIG_Python_SetConstant(d, "GCI_GrayIndex",SWIG_From_int((int)(GCI_GrayIndex)));
   SWIG_Python_SetConstant(d, "GCI_PaletteIndex",SWIG_From_int((int)(GCI_PaletteIndex)));
@@ -3464,16 +3472,32 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "CPLE_AssertionFailed",SWIG_From_int((int)(CPLE_AssertionFailed)));
   SWIG_Python_SetConstant(d, "CPLE_NoWriteAccess",SWIG_From_int((int)(CPLE_NoWriteAccess)));
   SWIG_Python_SetConstant(d, "CPLE_UserInterrupt",SWIG_From_int((int)(CPLE_UserInterrupt)));
+  SWIG_Python_SetConstant(d, "OF_ALL",SWIG_From_int((int)(GDAL_OF_ALL)));
+  SWIG_Python_SetConstant(d, "OF_RASTER",SWIG_From_int((int)(GDAL_OF_RASTER)));
+  SWIG_Python_SetConstant(d, "OF_VECTOR",SWIG_From_int((int)(GDAL_OF_VECTOR)));
+  SWIG_Python_SetConstant(d, "OF_READONLY",SWIG_From_int((int)(GDAL_OF_READONLY)));
+  SWIG_Python_SetConstant(d, "OF_UPDATE",SWIG_From_int((int)(GDAL_OF_UPDATE)));
+  SWIG_Python_SetConstant(d, "OF_SHARED",SWIG_From_int((int)(GDAL_OF_SHARED)));
+  SWIG_Python_SetConstant(d, "OF_VERBOSE_ERROR",SWIG_From_int((int)(GDAL_OF_VERBOSE_ERROR)));
   SWIG_Python_SetConstant(d, "DMD_LONGNAME",SWIG_FromCharPtr(GDAL_DMD_LONGNAME));
   SWIG_Python_SetConstant(d, "DMD_HELPTOPIC",SWIG_FromCharPtr(GDAL_DMD_HELPTOPIC));
   SWIG_Python_SetConstant(d, "DMD_MIMETYPE",SWIG_FromCharPtr(GDAL_DMD_MIMETYPE));
   SWIG_Python_SetConstant(d, "DMD_EXTENSION",SWIG_FromCharPtr(GDAL_DMD_EXTENSION));
+  SWIG_Python_SetConstant(d, "DMD_EXTENSIONS",SWIG_FromCharPtr(GDAL_DMD_EXTENSIONS));
+  SWIG_Python_SetConstant(d, "DMD_CONNECTION_PREFIX",SWIG_FromCharPtr(GDAL_DMD_CONNECTION_PREFIX));
   SWIG_Python_SetConstant(d, "DMD_CREATIONOPTIONLIST",SWIG_FromCharPtr(GDAL_DMD_CREATIONOPTIONLIST));
   SWIG_Python_SetConstant(d, "DMD_CREATIONDATATYPES",SWIG_FromCharPtr(GDAL_DMD_CREATIONDATATYPES));
+  SWIG_Python_SetConstant(d, "DMD_CREATIONFIELDDATATYPES",SWIG_FromCharPtr(GDAL_DMD_CREATIONFIELDDATATYPES));
   SWIG_Python_SetConstant(d, "DMD_SUBDATASETS",SWIG_FromCharPtr(GDAL_DMD_SUBDATASETS));
+  SWIG_Python_SetConstant(d, "DCAP_OPEN",SWIG_FromCharPtr(GDAL_DCAP_OPEN));
   SWIG_Python_SetConstant(d, "DCAP_CREATE",SWIG_FromCharPtr(GDAL_DCAP_CREATE));
   SWIG_Python_SetConstant(d, "DCAP_CREATECOPY",SWIG_FromCharPtr(GDAL_DCAP_CREATECOPY));
   SWIG_Python_SetConstant(d, "DCAP_VIRTUALIO",SWIG_FromCharPtr(GDAL_DCAP_VIRTUALIO));
+  SWIG_Python_SetConstant(d, "DCAP_RASTER",SWIG_FromCharPtr(GDAL_DCAP_RASTER));
+  SWIG_Python_SetConstant(d, "DCAP_VECTOR",SWIG_FromCharPtr(GDAL_DCAP_VECTOR));
+  SWIG_Python_SetConstant(d, "DCAP_NOTNULL_FIELDS",SWIG_FromCharPtr(GDAL_DCAP_NOTNULL_FIELDS));
+  SWIG_Python_SetConstant(d, "DCAP_DEFAULT_FIELDS",SWIG_FromCharPtr(GDAL_DCAP_DEFAULT_FIELDS));
+  SWIG_Python_SetConstant(d, "DCAP_NOTNULL_GEOMFIELDS",SWIG_FromCharPtr(GDAL_DCAP_NOTNULL_GEOMFIELDS));
   SWIG_Python_SetConstant(d, "CPLES_BackslashQuotable",SWIG_From_int((int)(CPLES_BackslashQuotable)));
   SWIG_Python_SetConstant(d, "CPLES_XML",SWIG_From_int((int)(CPLES_XML)));
   SWIG_Python_SetConstant(d, "CPLES_URL",SWIG_From_int((int)(CPLES_URL)));
diff --git a/swig/python/extensions/ogr_wrap.cpp b/swig/python/extensions/ogr_wrap.cpp
index 186b1cf..7d5c5cf 100644
--- a/swig/python/extensions/ogr_wrap.cpp
+++ b/swig/python/extensions/ogr_wrap.cpp
@@ -2722,28 +2722,31 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)
 
 /* -------- TYPES TABLE (BEGIN) -------- */
 
-#define SWIGTYPE_p_GDALProgressFunc swig_types[0]
-#define SWIGTYPE_p_GIntBig swig_types[1]
-#define SWIGTYPE_p_OGRDataSourceShadow swig_types[2]
-#define SWIGTYPE_p_OGRDriverShadow swig_types[3]
-#define SWIGTYPE_p_OGRFeatureDefnShadow swig_types[4]
-#define SWIGTYPE_p_OGRFeatureShadow swig_types[5]
-#define SWIGTYPE_p_OGRFieldDefnShadow swig_types[6]
-#define SWIGTYPE_p_OGRGeomFieldDefnShadow swig_types[7]
-#define SWIGTYPE_p_OGRGeometryShadow swig_types[8]
-#define SWIGTYPE_p_OGRLayerShadow swig_types[9]
-#define SWIGTYPE_p_OGRStyleTableShadow swig_types[10]
-#define SWIGTYPE_p_OSRCoordinateTransformationShadow swig_types[11]
-#define SWIGTYPE_p_OSRSpatialReferenceShadow swig_types[12]
-#define SWIGTYPE_p_char swig_types[13]
-#define SWIGTYPE_p_double swig_types[14]
-#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[15]
-#define SWIGTYPE_p_int swig_types[16]
-#define SWIGTYPE_p_p_char swig_types[17]
-#define SWIGTYPE_p_p_double swig_types[18]
-#define SWIGTYPE_p_p_int swig_types[19]
-static swig_type_info *swig_types[21];
-static swig_module_info swig_module = {swig_types, 20, 0, 0, 0, 0};
+#define SWIGTYPE_p_GDALMajorObjectShadow swig_types[0]
+#define SWIGTYPE_p_GDALProgressFunc swig_types[1]
+#define SWIGTYPE_p_GIntBig swig_types[2]
+#define SWIGTYPE_p_OGRDataSourceShadow swig_types[3]
+#define SWIGTYPE_p_OGRDriverShadow swig_types[4]
+#define SWIGTYPE_p_OGRFeatureDefnShadow swig_types[5]
+#define SWIGTYPE_p_OGRFeatureShadow swig_types[6]
+#define SWIGTYPE_p_OGRFieldDefnShadow swig_types[7]
+#define SWIGTYPE_p_OGRGeomFieldDefnShadow swig_types[8]
+#define SWIGTYPE_p_OGRGeometryShadow swig_types[9]
+#define SWIGTYPE_p_OGRLayerShadow swig_types[10]
+#define SWIGTYPE_p_OGRStyleTableShadow swig_types[11]
+#define SWIGTYPE_p_OSRCoordinateTransformationShadow swig_types[12]
+#define SWIGTYPE_p_OSRSpatialReferenceShadow swig_types[13]
+#define SWIGTYPE_p_char swig_types[14]
+#define SWIGTYPE_p_double swig_types[15]
+#define SWIGTYPE_p_f_double_p_q_const__char_p_void__int swig_types[16]
+#define SWIGTYPE_p_float swig_types[17]
+#define SWIGTYPE_p_int swig_types[18]
+#define SWIGTYPE_p_p_GIntBig swig_types[19]
+#define SWIGTYPE_p_p_char swig_types[20]
+#define SWIGTYPE_p_p_double swig_types[21]
+#define SWIGTYPE_p_p_int swig_types[22]
+static swig_type_info *swig_types[24];
+static swig_module_info swig_module = {swig_types, 23, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -2846,6 +2849,7 @@ typedef char retStringAndCPLFree;
 #include <iostream>
 using namespace std;
 
+#include "gdal.h"
 #include "ogr_api.h"
 #include "ogr_p.h"
 #include "ogr_core.h"
@@ -2853,6 +2857,8 @@ using namespace std;
 #include "cpl_string.h"
 #include "ogr_srs_api.h"
 
+typedef void GDALMajorObjectShadow;
+
 #ifdef DEBUG 
 typedef struct OGRSpatialReferenceHS OSRSpatialReferenceShadow;
 typedef struct OGRDriverHS OGRDriverShadow;
@@ -2937,7 +2943,7 @@ void CPL_STDCALL
 PythonBindingErrorHandler(CPLErr eclass, int code, const char *msg ) 
 {
   /* 
-  ** Generally we want to supress error reporting if we have exceptions
+  ** Generally we want to suppress error reporting if we have exceptions
   ** enabled as the error message will be in the exception thrown in 
   ** Python.  
   */
@@ -3110,12 +3116,12 @@ PyProgressProxy( double dfComplete, const char *pszMessage, void *pData )
     return bContinue;    
 }
 
-SWIGINTERN OGRStyleTableShadow *new_OGRStyleTableShadow(){
-        return (OGRStyleTableShadow*) OGR_STBL_Create();
-   }
-SWIGINTERN void delete_OGRStyleTableShadow(OGRStyleTableShadow *self){
-        OGR_STBL_Destroy( (OGRStyleTableH) self );
-   }
+
+#include "gdal.h"
+
+SWIGINTERN char const *GDALMajorObjectShadow_GetDescription(GDALMajorObjectShadow *self){
+    return GDALGetDescription( self );
+  }
 
 SWIGINTERN int
 SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
@@ -3195,6 +3201,39 @@ SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc)
 
 
 
+SWIGINTERN void GDALMajorObjectShadow_SetDescription(GDALMajorObjectShadow *self,char const *pszNewDesc){
+    GDALSetDescription( self, pszNewDesc );
+  }
+SWIGINTERN char **GDALMajorObjectShadow_GetMetadataDomainList(GDALMajorObjectShadow *self){
+    return GDALGetMetadataDomainList( self );
+  }
+SWIGINTERN char **GDALMajorObjectShadow_GetMetadata_Dict(GDALMajorObjectShadow *self,char const *pszDomain=""){
+    return GDALGetMetadata( self, pszDomain );
+  }
+SWIGINTERN char **GDALMajorObjectShadow_GetMetadata_List(GDALMajorObjectShadow *self,char const *pszDomain=""){
+    return GDALGetMetadata( self, pszDomain );
+  }
+SWIGINTERN CPLErr GDALMajorObjectShadow_SetMetadata__SWIG_0(GDALMajorObjectShadow *self,char **papszMetadata,char const *pszDomain=""){
+    return GDALSetMetadata( self, papszMetadata, pszDomain );
+  }
+SWIGINTERN CPLErr GDALMajorObjectShadow_SetMetadata__SWIG_1(GDALMajorObjectShadow *self,char *pszMetadataString,char const *pszDomain=""){
+    char *tmpList[2];
+    tmpList[0] = pszMetadataString;
+    tmpList[1] = 0;
+    return GDALSetMetadata( self, tmpList, pszDomain );
+  }
+SWIGINTERN char const *GDALMajorObjectShadow_GetMetadataItem(GDALMajorObjectShadow *self,char const *pszName,char const *pszDomain=""){
+    return GDALGetMetadataItem( self, pszName, pszDomain);
+  }
+SWIGINTERN CPLErr GDALMajorObjectShadow_SetMetadataItem(GDALMajorObjectShadow *self,char const *pszName,char const *pszValue,char const *pszDomain=""){
+    return GDALSetMetadataItem( self, pszName, pszValue, pszDomain);
+  }
+SWIGINTERN OGRStyleTableShadow *new_OGRStyleTableShadow(){
+        return (OGRStyleTableShadow*) OGR_STBL_Create();
+   }
+SWIGINTERN void delete_OGRStyleTableShadow(OGRStyleTableShadow *self){
+        OGR_STBL_Destroy( (OGRStyleTableH) self );
+   }
 SWIGINTERN int OGRStyleTableShadow_AddStyle(OGRStyleTableShadow *self,char const *pszName,char const *pszStyleString){
         return OGR_STBL_AddStyle( (OGRStyleTableH) self, pszName, pszStyleString);
    }
@@ -3452,6 +3491,8 @@ OGRErrMessages( int rc ) {
     return "OGR Error: Unsupported SRS";
   case OGRERR_INVALID_HANDLE:
     return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
   default:
     return "OGR Error: Unknown";
   }
@@ -3460,6 +3501,9 @@ OGRErrMessages( int rc ) {
 SWIGINTERN OGRErr OGRDataSourceShadow_SyncToDisk(OGRDataSourceShadow *self){
     return OGR_DS_SyncToDisk(self);
   }
+SWIGINTERN void OGRDataSourceShadow_FlushCache(OGRDataSourceShadow *self){
+    GDALFlushCache( self );
+  }
 SWIGINTERN OGRLayerShadow *OGRDataSourceShadow_CreateLayer(OGRDataSourceShadow *self,char const *name,OSRSpatialReferenceShadow *srs=NULL,OGRwkbGeometryType geom_type=wkbUnknown,char **options=0){
     OGRLayerShadow* layer = (OGRLayerShadow*) OGR_DS_CreateLayer( self,
 								  name,
@@ -3504,6 +3548,15 @@ SWIGINTERN void OGRDataSourceShadow_SetStyleTable(OGRDataSourceShadow *self,OGRS
     if( table != NULL )
         OGR_DS_SetStyleTable(self, (OGRStyleTableH) table);
   }
+SWIGINTERN OGRErr OGRDataSourceShadow_StartTransaction(OGRDataSourceShadow *self,int force=FALSE){
+    return GDALDatasetStartTransaction(self, force);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_CommitTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetCommitTransaction(self);
+  }
+SWIGINTERN OGRErr OGRDataSourceShadow_RollbackTransaction(OGRDataSourceShadow *self){
+    return GDALDatasetRollbackTransaction(self);
+  }
 SWIGINTERN int OGRLayerShadow_GetRefCount(OGRLayerShadow *self){
     return OGR_L_GetRefCount(self);
   }
@@ -3540,13 +3593,13 @@ SWIGINTERN char const *OGRLayerShadow_GetGeometryColumn(OGRLayerShadow *self){
 SWIGINTERN char const *OGRLayerShadow_GetFIDColumn(OGRLayerShadow *self){
     return OGR_L_GetFIDColumn(self);
   }
-SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetFeature(OGRLayerShadow *self,GIntBig fid){
     return (OGRFeatureShadow*) OGR_L_GetFeature(self, fid);
   }
 SWIGINTERN OGRFeatureShadow *OGRLayerShadow_GetNextFeature(OGRLayerShadow *self){
     return (OGRFeatureShadow*) OGR_L_GetNextFeature(self);
   }
-SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,long new_index){
+SWIGINTERN OGRErr OGRLayerShadow_SetNextByIndex(OGRLayerShadow *self,GIntBig new_index){
     return OGR_L_SetNextByIndex(self, new_index);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
@@ -3555,7 +3608,7 @@ SWIGINTERN OGRErr OGRLayerShadow_SetFeature(OGRLayerShadow *self,OGRFeatureShado
 SWIGINTERN OGRErr OGRLayerShadow_CreateFeature(OGRLayerShadow *self,OGRFeatureShadow *feature){
     return OGR_L_CreateFeature(self, feature);
   }
-SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,long fid){
+SWIGINTERN OGRErr OGRLayerShadow_DeleteFeature(OGRLayerShadow *self,GIntBig fid){
     return OGR_L_DeleteFeature(self, fid);
   }
 SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
@@ -3564,13 +3617,13 @@ SWIGINTERN OGRErr OGRLayerShadow_SyncToDisk(OGRLayerShadow *self){
 SWIGINTERN OGRFeatureDefnShadow *OGRLayerShadow_GetLayerDefn(OGRLayerShadow *self){
     return (OGRFeatureDefnShadow*) OGR_L_GetLayerDefn(self);
   }
-SWIGINTERN int OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
+SWIGINTERN GIntBig OGRLayerShadow_GetFeatureCount(OGRLayerShadow *self,int force=1){
     return OGR_L_GetFeatureCount(self, force);
   }
 SWIGINTERN void OGRLayerShadow_GetExtent(OGRLayerShadow *self,double argout[4],int *isvalid=NULL,int force=1,int can_return_null=0,int geom_field=0){
     OGRErr eErr = OGR_L_GetExtentEx(self, geom_field, (OGREnvelope*)argout, force);
     if (can_return_null)
-        *isvalid = (eErr == OGRERR_NONE);
+        *isvalid = (eErr == 0);
     else
         *isvalid = TRUE;
     return;
@@ -3593,7 +3646,7 @@ SWIGINTERN OGRErr OGRLayerShadow_ReorderFields(OGRLayerShadow *self,int nList,in
       CPLError(CE_Failure, CPLE_IllegalArg,
                "List should have %d elements",
                OGR_FD_GetFieldCount(OGR_L_GetLayerDefn(self)));
-      return OGRERR_FAILURE;
+      return 6;
     }
     return OGR_L_ReorderFields(self, pList);
   }
@@ -3681,7 +3734,7 @@ SWIGINTERN OGRErr OGRFeatureShadow_SetGeomField__SWIG_1(OGRFeatureShadow *self,c
       if (iField == -1)
       {
         CPLError(CE_Failure, 1, "No such field: '%s'", name);
-        return OGRERR_FAILURE;
+        return 6;
       }
       else
         return OGR_F_SetGeomField(self, iField, geom);
@@ -3694,7 +3747,7 @@ SWIGINTERN OGRErr OGRFeatureShadow_SetGeomFieldDirectly__SWIG_1(OGRFeatureShadow
       if (iField == -1)
       {
         CPLError(CE_Failure, 1, "No such field: '%s'", name);
-        return OGRERR_FAILURE;
+        return 6;
       }
       else
         return OGR_F_SetGeomFieldDirectly(self, iField, geom);
@@ -3768,6 +3821,17 @@ SWIGINTERN int OGRFeatureShadow_GetFieldAsInteger__SWIG_1(OGRFeatureShadow *self
 	  return OGR_F_GetFieldAsInteger(self, i);
       return 0;
   }
+SWIGINTERN GIntBig OGRFeatureShadow_GetFieldAsInteger64__SWIG_0(OGRFeatureShadow *self,int id){
+    return OGR_F_GetFieldAsInteger64(self, id);
+  }
+SWIGINTERN GIntBig OGRFeatureShadow_GetFieldAsInteger64__SWIG_1(OGRFeatureShadow *self,char const *name){
+      int i = OGR_F_GetFieldIndex(self, name);
+      if (i == -1)
+      CPLError(CE_Failure, 1, "No such field: '%s'", name);
+      else
+      return OGR_F_GetFieldAsInteger64(self, i);
+      return 0;
+  }
 SWIGINTERN double OGRFeatureShadow_GetFieldAsDouble__SWIG_0(OGRFeatureShadow *self,int id){
     return OGR_F_GetFieldAsDouble(self, id);
   }
@@ -3782,20 +3846,51 @@ SWIGINTERN double OGRFeatureShadow_GetFieldAsDouble__SWIG_1(OGRFeatureShadow *se
 	  return OGR_F_GetFieldAsDouble(self, i);
       return 0;
   }
-SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,int *pnSecond,int *pnTZFlag){
-      OGR_F_GetFieldAsDateTime(self, id, pnYear, pnMonth, pnDay,
-			       pnHour, pnMinute, pnSecond,
+
+SWIGINTERNINLINE PyObject *
+SWIG_From_float  (float value)
+{    
+  return SWIG_From_double  (value);
+}
+
+SWIGINTERN void OGRFeatureShadow_GetFieldAsDateTime(OGRFeatureShadow *self,int id,int *pnYear,int *pnMonth,int *pnDay,int *pnHour,int *pnMinute,float *pfSecond,int *pnTZFlag){
+      OGR_F_GetFieldAsDateTimeEx(self, id, pnYear, pnMonth, pnDay,
+			       pnHour, pnMinute, pfSecond,
 			       pnTZFlag);
   }
 SWIGINTERN void OGRFeatureShadow_GetFieldAsIntegerList(OGRFeatureShadow *self,int id,int *nLen,int const **pList){
       *pList = OGR_F_GetFieldAsIntegerList(self, id, nLen);
   }
+SWIGINTERN void OGRFeatureShadow_GetFieldAsInteger64List(OGRFeatureShadow *self,int id,int *nLen,GIntBig const **pList){
+      *pList = OGR_F_GetFieldAsInteger64List(self, id, nLen);
+  }
 SWIGINTERN void OGRFeatureShadow_GetFieldAsDoubleList(OGRFeatureShadow *self,int id,int *nLen,double const **pList){
       *pList = OGR_F_GetFieldAsDoubleList(self, id, nLen);
   }
 SWIGINTERN char **OGRFeatureShadow_GetFieldAsStringList(OGRFeatureShadow *self,int id){
       return OGR_F_GetFieldAsStringList(self, id);
   }
+SWIGINTERN OGRErr OGRFeatureShadow_GetFieldAsBinary__SWIG_0(OGRFeatureShadow *self,int id,int *nLen,char **pBuf){
+    GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+    *pBuf = (char*)malloc(*nLen);
+    memcpy(*pBuf, pabyBlob, *nLen);
+    return 0;
+  }
+SWIGINTERN OGRErr OGRFeatureShadow_GetFieldAsBinary__SWIG_1(OGRFeatureShadow *self,char const *name,int *nLen,char **pBuf){
+      int id = OGR_F_GetFieldIndex(self, name);
+      if (id == -1)
+      {
+        CPLError(CE_Failure, 1, "No such field: '%s'", name);
+        return 6;
+      }
+      else
+      {
+        GByte* pabyBlob = OGR_F_GetFieldAsBinary(self, id, nLen);
+        *pBuf = (char*)malloc(*nLen);
+        memcpy(*pBuf, pabyBlob, *nLen);
+        return 0;
+      }
+  }
 SWIGINTERN bool OGRFeatureShadow_IsFieldSet__SWIG_0(OGRFeatureShadow *self,int id){
     return (OGR_F_IsFieldSet(self, id) > 0);
   }
@@ -3813,10 +3908,10 @@ SWIGINTERN int OGRFeatureShadow_GetFieldIndex(OGRFeatureShadow *self,char const
 SWIGINTERN int OGRFeatureShadow_GetGeomFieldIndex(OGRFeatureShadow *self,char const *name){
       return OGR_F_GetGeomFieldIndex(self, name);
   }
-SWIGINTERN int OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
+SWIGINTERN GIntBig OGRFeatureShadow_GetFID(OGRFeatureShadow *self){
     return OGR_F_GetFID(self);
   }
-SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,int fid){
+SWIGINTERN OGRErr OGRFeatureShadow_SetFID(OGRFeatureShadow *self,GIntBig fid){
     return OGR_F_SetFID(self, fid);
   }
 SWIGINTERN void OGRFeatureShadow_DumpReadable(OGRFeatureShadow *self){
@@ -3842,43 +3937,55 @@ SWIGINTERN void OGRFeatureShadow_SetField__SWIG_1(OGRFeatureShadow *self,char co
       else
 	  OGR_F_SetFieldString(self, i, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_2(OGRFeatureShadow *self,int id,int value){
-    OGR_F_SetFieldInteger(self, id, value);
-  }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_3(OGRFeatureShadow *self,char const *name,int value){
-      int i = OGR_F_GetFieldIndex(self, name);
-      if (i == -1)
-	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
-      else
-	  OGR_F_SetFieldInteger(self, i, value);
+SWIGINTERN void OGRFeatureShadow_SetFieldInteger64(OGRFeatureShadow *self,int id,GIntBig value){
+    OGR_F_SetFieldInteger64(self, id, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_4(OGRFeatureShadow *self,int id,double value){
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_2(OGRFeatureShadow *self,int id,double value){
     OGR_F_SetFieldDouble(self, id, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_5(OGRFeatureShadow *self,char const *name,double value){
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_3(OGRFeatureShadow *self,char const *name,double value){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1)
 	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
       else
 	  OGR_F_SetFieldDouble(self, i, value);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_6(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,int second,int tzflag){
-    OGR_F_SetFieldDateTime(self, id, year, month, day,
+
+SWIGINTERN int
+SWIG_AsVal_float (PyObject * obj, float *val)
+{
+  double v;
+  int res = SWIG_AsVal_double (obj, &v);
+  if (SWIG_IsOK(res)) {
+    if ((v < -FLT_MAX || v > FLT_MAX)) {
+      return SWIG_OverflowError;
+    } else {
+      if (val) *val = static_cast< float >(v);
+    }
+  }  
+  return res;
+}
+
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_4(OGRFeatureShadow *self,int id,int year,int month,int day,int hour,int minute,float second,int tzflag){
+    OGR_F_SetFieldDateTimeEx(self, id, year, month, day,
                              hour, minute, second, 
                              tzflag);
   }
-SWIGINTERN void OGRFeatureShadow_SetField__SWIG_7(OGRFeatureShadow *self,char const *name,int year,int month,int day,int hour,int minute,int second,int tzflag){
+SWIGINTERN void OGRFeatureShadow_SetField__SWIG_5(OGRFeatureShadow *self,char const *name,int year,int month,int day,int hour,int minute,float second,int tzflag){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1)
 	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
       else
-	  OGR_F_SetFieldDateTime(self, i, year, month, day,
+	  OGR_F_SetFieldDateTimeEx(self, i, year, month, day,
 				 hour, minute, second, 
 				 tzflag);
   }
 SWIGINTERN void OGRFeatureShadow_SetFieldIntegerList(OGRFeatureShadow *self,int id,int nList,int *pList){
       OGR_F_SetFieldIntegerList(self, id, nList, pList);
   }
+SWIGINTERN void OGRFeatureShadow_SetFieldInteger64List(OGRFeatureShadow *self,int id,int nList,GIntBig *pList){
+      OGR_F_SetFieldInteger64List(self, id, nList, pList);
+  }
 SWIGINTERN void OGRFeatureShadow_SetFieldDoubleList(OGRFeatureShadow *self,int id,int nList,double *pList){
       OGR_F_SetFieldDoubleList(self, id, nList, pList);
   }
@@ -3911,7 +4018,7 @@ SWIGINTERN OGRErr OGRFeatureShadow_SetFromWithMap(OGRFeatureShadow *self,OGRFeat
     {
         CPLError(CE_Failure, CPLE_AppDefined,
                  "The size of map doesn't match with the field count of the source feature");
-        return OGRERR_FAILURE;
+        return 6;
     }
     return OGR_F_SetFromWithMap(self, other, forgiving, pList);
   }
@@ -3922,17 +4029,28 @@ SWIGINTERN void OGRFeatureShadow_SetStyleString(OGRFeatureShadow *self,char cons
     OGR_F_SetStyleString(self, the_string);
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_0(OGRFeatureShadow *self,int id){
-    return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, id));
+      OGRFieldDefnH fd = OGR_F_GetFieldDefnRef( self,  id );
+      if (fd)
+          return (OGRFieldType) OGR_Fld_GetType( fd );
+      else
+          return (OGRFieldType)0;
   }
 SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *self,char const *name){
       int i = OGR_F_GetFieldIndex(self, name);
       if (i == -1) {
-	  CPLError(CE_Failure, 1, "No such field: '%s'", name);
-	  return (OGRFieldType)0;
+          CPLError(CE_Failure, 1, "No such field: '%s'", name);
+          return (OGRFieldType)0;
       } else
-	  return (OGRFieldType) OGR_Fld_GetType( 
-	      OGR_F_GetFieldDefnRef( self,  i )
-	      );
+          return (OGRFieldType) OGR_Fld_GetType( OGR_F_GetFieldDefnRef( self, i ) );
+  }
+SWIGINTERN int OGRFeatureShadow_Validate(OGRFeatureShadow *self,int flags=OGR_F_VAL_ALL,int bEmitError=TRUE){
+    return OGR_F_Validate(self, flags, bEmitError);
+  }
+SWIGINTERN void OGRFeatureShadow_FillUnsetWithDefault(OGRFeatureShadow *self,int bNotNullableOnly=FALSE,char **options=NULL){
+    OGR_F_FillUnsetWithDefault(self, bNotNullableOnly, options );
+  }
+SWIGINTERN void OGRFeatureShadow_SetFieldString(OGRFeatureShadow *self,int id,char const *value){
+    OGR_F_SetFieldString(self, id, value);
   }
 
     static int ValidateOGRGeometryType(OGRwkbGeometryType field_type)
@@ -3947,8 +4065,18 @@ SWIGINTERN OGRFieldType OGRFeatureShadow_GetFieldType__SWIG_1(OGRFeatureShadow *
             case wkbMultiLineString:
             case wkbMultiPolygon:
             case wkbGeometryCollection:
+            case wkbCircularString:
+            case wkbCompoundCurve:
+            case wkbCurvePolygon:
+            case wkbMultiCurve:
+            case wkbMultiSurface:
             case wkbNone:
             /*case wkbLinearRing:*/
+            case wkbCircularStringZ:
+            case wkbCompoundCurveZ:
+            case wkbCurvePolygonZ:
+            case wkbMultiCurveZ:
+            case wkbMultiSurfaceZ:
             case wkbPoint25D:
             case wkbLineString25D:
             case wkbPolygon25D:
@@ -4042,6 +4170,8 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
             case OFTDate:
             case OFTTime:
             case OFTDateTime:
+            case OFTInteger64:
+            case OFTInteger64List:
                 return TRUE;
             default:
                 CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field type value");
@@ -4049,6 +4179,22 @@ SWIGINTERN int OGRFeatureDefnShadow_IsSame(OGRFeatureDefnShadow *self,OGRFeature
         }
     }
 
+
+    static int ValidateOGRFieldSubType(OGRFieldSubType field_subtype)
+    {
+        switch(field_subtype)
+        {
+            case OFSTNone:
+            case OFSTBoolean:
+            case OFSTInt16:
+            case OFSTFloat32:
+                return TRUE;
+            default:
+                CPLError(CE_Failure, CPLE_IllegalArg, "Illegal field subtype value");
+                return FALSE;
+        }
+    }
+
 SWIGINTERN void delete_OGRFieldDefnShadow(OGRFieldDefnShadow *self){
     OGR_Fld_Destroy(self);
   }
@@ -4074,6 +4220,13 @@ SWIGINTERN void OGRFieldDefnShadow_SetType(OGRFieldDefnShadow *self,OGRFieldType
     if (ValidateOGRFieldType(type))
         OGR_Fld_SetType(self, type);
   }
+SWIGINTERN OGRFieldSubType OGRFieldDefnShadow_GetSubType(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetSubType(self);
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetSubType(OGRFieldDefnShadow *self,OGRFieldSubType type){
+    if (ValidateOGRFieldSubType(type))
+        OGR_Fld_SetSubType(self, type);
+  }
 SWIGINTERN OGRJustification OGRFieldDefnShadow_GetJustify(OGRFieldDefnShadow *self){
     return OGR_Fld_GetJustify(self);
   }
@@ -4102,7 +4255,22 @@ SWIGINTERN int OGRFieldDefnShadow_IsIgnored(OGRFieldDefnShadow *self){
     return OGR_Fld_IsIgnored( self );
   }
 SWIGINTERN void OGRFieldDefnShadow_SetIgnored(OGRFieldDefnShadow *self,int bIgnored){
-    return OGR_Fld_SetIgnored( self, bIgnored );
+    OGR_Fld_SetIgnored( self, bIgnored );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsNullable(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsNullable( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetNullable(OGRFieldDefnShadow *self,int bNullable){
+    OGR_Fld_SetNullable( self, bNullable );
+  }
+SWIGINTERN char const *OGRFieldDefnShadow_GetDefault(OGRFieldDefnShadow *self){
+    return OGR_Fld_GetDefault( self );
+  }
+SWIGINTERN void OGRFieldDefnShadow_SetDefault(OGRFieldDefnShadow *self,char const *pszValue){
+    OGR_Fld_SetDefault( self, pszValue );
+  }
+SWIGINTERN int OGRFieldDefnShadow_IsDefaultDriverSpecific(OGRFieldDefnShadow *self){
+    return OGR_Fld_IsDefaultDriverSpecific( self );
   }
 SWIGINTERN void delete_OGRGeomFieldDefnShadow(OGRGeomFieldDefnShadow *self){
     OGR_GFld_Destroy(self);
@@ -4144,6 +4312,12 @@ SWIGINTERN int OGRGeomFieldDefnShadow_IsIgnored(OGRGeomFieldDefnShadow *self){
 SWIGINTERN void OGRGeomFieldDefnShadow_SetIgnored(OGRGeomFieldDefnShadow *self,int bIgnored){
     OGR_GFld_SetIgnored( self, bIgnored );
   }
+SWIGINTERN int OGRGeomFieldDefnShadow_IsNullable(OGRGeomFieldDefnShadow *self){
+    return OGR_GFld_IsNullable( self );
+  }
+SWIGINTERN void OGRGeomFieldDefnShadow_SetNullable(OGRGeomFieldDefnShadow *self,int bNullable){
+    return OGR_GFld_SetNullable( self, bNullable );
+  }
 
   OGRGeometryShadow* CreateGeometryFromWkb( int len, char *bin_string, 
                                             OSRSpatialReferenceShadow *reference=NULL ) {
@@ -4258,6 +4432,13 @@ OGRGeometryShadow* ForceToMultiLineString( OGRGeometryShadow *geom_in ) {
  return (OGRGeometryShadow* )OGR_G_ForceToMultiLineString( OGR_G_Clone(geom_in) );
 }
 
+
+OGRGeometryShadow* ForceTo( OGRGeometryShadow *geom_in, OGRwkbGeometryType eTargetType, char** options = NULL ) {
+ if (geom_in == NULL)
+     return NULL;
+ return (OGRGeometryShadow* )OGR_G_ForceTo( OGR_G_Clone(geom_in), eTargetType, options );
+}
+
 SWIGINTERN void delete_OGRGeometryShadow(OGRGeometryShadow *self){
     OGR_G_DestroyGeometry( self );
   }
@@ -4286,11 +4467,19 @@ SWIGINTERN OGRGeometryShadow *new_OGRGeometryShadow(OGRwkbGeometryType type=wkbU
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkt(OGRGeometryShadow *self,char **argout){
     return OGR_G_ExportToWkt(self, argout);
   }
+SWIGINTERN OGRErr OGRGeometryShadow_ExportToIsoWkt(OGRGeometryShadow *self,char **argout){
+    return OGR_G_ExportToIsoWkt(self, argout);
+  }
 SWIGINTERN OGRErr OGRGeometryShadow_ExportToWkb(OGRGeometryShadow *self,int *nLen,char **pBuf,OGRwkbByteOrder byte_order=wkbXDR){
     *nLen = OGR_G_WkbSize( self );
     *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
     return OGR_G_ExportToWkb(self, byte_order, (unsigned char*) *pBuf );
   }
+SWIGINTERN OGRErr OGRGeometryShadow_ExportToIsoWkb(OGRGeometryShadow *self,int *nLen,char **pBuf,OGRwkbByteOrder byte_order=wkbXDR){
+    *nLen = OGR_G_WkbSize( self );
+    *pBuf = (char *) malloc( *nLen * sizeof(unsigned char) );
+    return OGR_G_ExportToIsoWkb(self, byte_order, (unsigned char*) *pBuf );
+  }
 SWIGINTERN retStringAndCPLFree *OGRGeometryShadow_ExportToGML(OGRGeometryShadow *self,char **options=0){
     return (retStringAndCPLFree*) OGR_G_ExportToGMLEx(self, options);
   }
@@ -4531,6 +4720,18 @@ SWIGINTERN void OGRGeometryShadow_SetCoordinateDimension(OGRGeometryShadow *self
 SWIGINTERN int OGRGeometryShadow_GetDimension(OGRGeometryShadow *self){
     return OGR_G_GetDimension(self);
   }
+SWIGINTERN int OGRGeometryShadow_HasCurveGeometry(OGRGeometryShadow *self,int bLookForCircular=FALSE){
+        return OGR_G_HasCurveGeometry(self, bLookForCircular);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetLinearGeometry(OGRGeometryShadow *self,double dfMaxAngleStepSizeDegrees=0.0,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetLinearGeometry(self, dfMaxAngleStepSizeDegrees, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_GetCurveGeometry(OGRGeometryShadow *self,char **options=NULL){
+    return (OGRGeometryShadow* )OGR_G_GetCurveGeometry(self, options);
+  }
+SWIGINTERN OGRGeometryShadow *OGRGeometryShadow_Value(OGRGeometryShadow *self,double dfDistance){
+    return OGR_G_Value(self, dfDistance);
+  }
 
 char const *OGRDriverShadow_get_name( OGRDriverShadow *h ) {
   return OGR_Dr_GetName( h );
@@ -4549,6 +4750,12 @@ char const *OGRDataSourceShadow_name_get( OGRDataSourceShadow *h ) {
 }
 
 
+OGRwkbGeometryType GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM = FALSE)
+{
+    return OGR_GT_SetModifier(eType, bSetZ, bSetM);
+}
+
+
   OGRDataSourceShadow* GetOpenDS(int ds_number) {
     OGRDataSourceShadow* layer = (OGRDataSourceShadow*) OGRGetOpenDS(ds_number);
     return layer;
@@ -4650,48 +4857,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_new_StyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRStyleTableShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)":new_StyleTable")) SWIG_fail;
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRStyleTableShadow *)new_OGRStyleTableShadow();
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, SWIG_POINTER_NEW |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_delete_StyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_GetDescription(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_StyleTable",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:MajorObject_GetDescription",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_StyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_GetDescription" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRStyleTableShadow(arg1);
+    result = (char *)GDALMajorObjectShadow_GetDescription(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4699,52 +4883,46 @@ SWIGINTERN PyObject *_wrap_delete_StyleTable(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_AddStyle(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_SetDescription(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
-  int res3 ;
-  char *buf3 = 0 ;
-  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:StyleTable_AddStyle",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:MajorObject_SetDescription",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_AddStyle" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_SetDescription" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "StyleTable_AddStyle" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_SetDescription" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
-  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "StyleTable_AddStyle" "', argument " "3"" of type '" "char const *""'");
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg3 = reinterpret_cast< char * >(buf3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRStyleTableShadow_AddStyle(arg1,(char const *)arg2,(char const *)arg3);
+    GDALMajorObjectShadow_SetDescription(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4752,48 +4930,34 @@ SWIGINTERN PyObject *_wrap_StyleTable_AddStyle(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_LoadStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_GetMetadataDomainList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  int result;
+  char **result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_LoadStyleTable",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:MajorObject_GetMetadataDomainList",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_LoadStyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
-    if (arg2 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_GetMetadataDomainList" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRStyleTableShadow_LoadStyleTable(arg1,(char const *)arg2);
+    result = (char **)GDALMajorObjectShadow_GetMetadataDomainList(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4801,52 +4965,60 @@ SWIGINTERN PyObject *_wrap_StyleTable_LoadStyleTable(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
+    /* %typemap(out) char **CSL -> ( string ) */
+    char **stringarray = result;
+    if ( stringarray == NULL ) {
+      resultobj = Py_None;
+      Py_INCREF( resultobj );
+    }
+    else {
+      int len = CSLCount( stringarray );
+      resultobj = PyList_New( len );
+      for ( int i = 0; i < len; ++i ) {
+        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
+        PyList_SetItem(resultobj, i, o );
+      }
+    }
+    CSLDestroy(result);
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_SaveStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_GetMetadata_Dict(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
+  char *arg2 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int bToFree2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  int result;
+  char **result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_SaveStyleTable",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O|O:MajorObject_GetMetadata_Dict",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_SaveStyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_GetMetadata_Dict" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
-    if (arg2 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_GetMetadata_Dict" "', argument " "2"" of type '" "char const *""'");
     }
+    arg2 = reinterpret_cast< char * >(buf2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRStyleTableShadow_SaveStyleTable(arg1,(char const *)arg2);
+    result = (char **)GDALMajorObjectShadow_GetMetadata_Dict(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4854,25 +5026,42 @@ SWIGINTERN PyObject *_wrap_StyleTable_SaveStyleTable(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
+    /* %typemap(out) char **dict */
+    char **stringarray = result;
+    resultobj = PyDict_New();
+    if ( stringarray != NULL ) {
+      while (*stringarray != NULL ) {
+        char const *valptr;
+        char *keyptr;
+        const char* pszSep = strchr( *stringarray, '=' );
+        if ( pszSep != NULL) {
+          keyptr = CPLStrdup(*stringarray);
+          keyptr[pszSep - *stringarray] = '\0';
+          valptr = pszSep + 1;
+          PyObject *nm = GDALPythonObjectFromCStr( keyptr );
+          PyObject *val = GDALPythonObjectFromCStr( valptr );
+          PyDict_SetItem(resultobj, nm, val );
+          Py_DECREF(nm);
+          Py_DECREF(val);
+          CPLFree( keyptr );
+        }
+        stringarray++;
+      }
+    }
   }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_Find(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_GetMetadata_List(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
+  char *arg2 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
@@ -4880,24 +5069,26 @@ SWIGINTERN PyObject *_wrap_StyleTable_Find(PyObject *SWIGUNUSEDPARM(self), PyObj
   int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *result = 0 ;
+  char **result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_Find",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O|O:MajorObject_GetMetadata_List",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_Find" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_GetMetadata_List" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "StyleTable_Find" "', argument " "2"" of type '" "char const *""'");
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_GetMetadata_List" "', argument " "2"" of type '" "char const *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
   }
-  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRStyleTableShadow_Find(arg1,(char const *)arg2);
+    result = (char **)GDALMajorObjectShadow_GetMetadata_List(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4905,7 +5096,22 @@ SWIGINTERN PyObject *_wrap_StyleTable_Find(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  {
+    /* %typemap(out) char **options -> ( string ) */
+    char **stringarray = result;
+    if ( stringarray == NULL ) {
+      resultobj = Py_None;
+      Py_INCREF( resultobj );
+    }
+    else {
+      int len = CSLCount( stringarray );
+      resultobj = PyList_New( len );
+      for ( int i = 0; i < len; ++i ) {
+        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
+        PyList_SetItem(resultobj, i, o );
+      }
+    }
+  }
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
@@ -4914,24 +5120,98 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_ResetStyleStringReading(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
+  char *arg3 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_ResetStyleStringReading",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO|O:MajorObject_SetMetadata",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_ResetStyleStringReading" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_SetMetadata" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  {
+    /* %typemap(in) char **dict */
+    arg2 = NULL;
+    if ( PySequence_Check( obj1 ) ) {
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        int bFreeStr;
+        char* pszStr = GDALPythonObjectToCStr(pyObj, &bFreeStr);
+        if ( pszStr == NULL ) {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        arg2 = CSLAddString( arg2, pszStr );
+        GDALPythonFreeCStr(pszStr, bFreeStr);
+        Py_DECREF(pyObj);
+      }
+    }
+    else if ( PyMapping_Check( obj1 ) ) {
+      /* We need to use the dictionary form. */
+      int size = PyMapping_Length( obj1 );
+      if ( size > 0 ) {
+        PyObject *item_list = PyMapping_Items( obj1 );
+        for( int i=0; i<size; i++ ) {
+          PyObject *it = PySequence_GetItem( item_list, i );
+          
+          PyObject *k, *v;
+          if ( ! PyArg_ParseTuple( it, "OO", &k, &v ) ) {
+            Py_DECREF(it);
+            PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
+            SWIG_fail;
+          }
+          
+          int bFreeK, bFreeV;
+          char* pszK = GDALPythonObjectToCStr(k, &bFreeK);
+          char* pszV = GDALPythonObjectToCStr(v, &bFreeV);
+          if( pszK == NULL || pszV == NULL )
+          {
+            GDALPythonFreeCStr(pszK, bFreeK);
+            GDALPythonFreeCStr(pszV, bFreeV);
+            Py_DECREF(it);
+            PyErr_SetString(PyExc_TypeError,"dictionnaire must contain tuples of strings");
+            SWIG_fail;
+          }
+          arg2 = CSLAddNameValue( arg2, pszK, pszV );
+          
+          GDALPythonFreeCStr(pszK, bFreeK);
+          GDALPythonFreeCStr(pszV, bFreeV);
+          Py_DECREF(it);
+        }
+        Py_DECREF(item_list);
+      }
+    }
+    else {
+      PyErr_SetString(PyExc_TypeError,"Argument must be dictionary or sequence of strings");
+      SWIG_fail;
+    }
+  }
+  if (obj2) {
+    res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "MajorObject_SetMetadata" "', argument " "3"" of type '" "char const *""'");
+    }
+    arg3 = reinterpret_cast< char * >(buf3);
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRStyleTableShadow_ResetStyleStringReading(arg1);
+    result = (CPLErr)GDALMajorObjectShadow_SetMetadata__SWIG_0(arg1,arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4939,32 +5219,74 @@ SWIGINTERN PyObject *_wrap_StyleTable_ResetStyleStringReading(PyObject *SWIGUNUS
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) char **dict */
+    CSLDestroy( arg2 );
+  }
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **dict */
+    CSLDestroy( arg2 );
+  }
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_GetNextStyle(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  char *arg3 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  CPLErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_GetNextStyle",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO|O:MajorObject_SetMetadata",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_GetNextStyle" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_SetMetadata" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_SetMetadata" "', argument " "2"" of type '" "char *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "MajorObject_SetMetadata" "', argument " "3"" of type '" "char const *""'");
+    }
+    arg3 = reinterpret_cast< char * >(buf3);
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRStyleTableShadow_GetNextStyle(arg1);
+    result = (CPLErr)GDALMajorObjectShadow_SetMetadata__SWIG_1(arg1,arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -4972,72 +5294,138 @@ SWIGINTERN PyObject *_wrap_StyleTable_GetNextStyle(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
+  }
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_StyleTable_GetLastStyleName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
+SWIGINTERN PyObject *_wrap_MajorObject_SetMetadata(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[4];
+  int ii;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_GetLastStyleName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_GetLastStyleName" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
   }
-  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
+  if ((argc >= 2) && (argc <= 3)) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_GDALMajorObjectShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        /* %typecheck(SWIG_TYPECHECK_POINTER) (char **dict) */
+        /* Note: we exclude explicitly strings, because they can be considered as a sequence of characters, */
+        /* which is not desirable since it makes it impossible to define bindings such as SetMetadata(string) and SetMetadata(array_of_string) */
+        /* (see #4816) */
+        _v = ((PyMapping_Check(argv[1]) || PySequence_Check(argv[1]) ) && !SWIG_CheckState(SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0)) ) ? 1 : 0;
+      }
+      if (_v) {
+        if (argc <= 2) {
+          return _wrap_MajorObject_SetMetadata__SWIG_0(self, args);
+        }
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_MajorObject_SetMetadata__SWIG_0(self, args);
+        }
+      }
     }
-    result = (char *)OGRStyleTableShadow_GetLastStyleName(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  }
+  if ((argc >= 2) && (argc <= 3)) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_GDALMajorObjectShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        if (argc <= 2) {
+          return _wrap_MajorObject_SetMetadata__SWIG_1(self, args);
+        }
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_MajorObject_SetMetadata__SWIG_1(self, args);
+        }
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
-  return resultobj;
+  
 fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'MajorObject_SetMetadata'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetMetadata(GDALMajorObjectShadow *,char **,char const *)\n"
+    "    SetMetadata(GDALMajorObjectShadow *,char *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *StyleTable_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRStyleTableShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_Driver_name_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_MajorObject_GetMetadataItem(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  char *arg3 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
   char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Driver_name_get",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO|O:MajorObject_GetMetadataItem",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_name_get" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_GetMetadataItem" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_GetMetadataItem" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "MajorObject_GetMetadataItem" "', argument " "3"" of type '" "char const *""'");
+    }
+    arg3 = reinterpret_cast< char * >(buf3);
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRDriverShadow_name_get(arg1);
+    result = (char *)GDALMajorObjectShadow_GetMetadataItem(arg1,(char const *)arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5046,94 +5434,72 @@ SWIGINTERN PyObject *_wrap_Driver_name_get(PyObject *SWIGUNUSEDPARM(self), PyObj
     }
   }
   resultobj = SWIG_FromCharPtr((const char *)result);
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_CreateDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_MajorObject_SetMetadataItem(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  GDALMajorObjectShadow *arg1 = (GDALMajorObjectShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  char **arg3 = (char **) 0 ;
+  char *arg3 = (char *) 0 ;
+  char *arg4 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int bToFree2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
+  int res4 ;
+  char *buf4 = 0 ;
+  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "utf8_path",(char *) "options", NULL 
-  };
-  OGRDataSourceShadow *result = 0 ;
+  PyObject * obj3 = 0 ;
+  CPLErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Driver_CreateDataSource",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OOO|O:MajorObject_SetMetadataItem",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_GDALMajorObjectShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_CreateDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "MajorObject_SetMetadataItem" "', argument " "1"" of type '" "GDALMajorObjectShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
-    if (arg2 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
-    }
+  arg1 = reinterpret_cast< GDALMajorObjectShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "MajorObject_SetMetadataItem" "', argument " "2"" of type '" "char const *""'");
   }
-  if (obj2) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj2)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj2);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj2,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg3 = CSLAddString( arg3, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
+  arg2 = reinterpret_cast< char * >(buf2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "MajorObject_SetMetadataItem" "', argument " "3"" of type '" "char const *""'");
+  }
+  arg3 = reinterpret_cast< char * >(buf3);
+  if (obj3) {
+    res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "MajorObject_SetMetadataItem" "', argument " "4"" of type '" "char const *""'");
+    }
+    arg4 = reinterpret_cast< char * >(buf4);
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRDataSourceShadow *)OGRDriverShadow_CreateDataSource(arg1,(char const *)arg2,arg3);
+    result = (CPLErr)GDALMajorObjectShadow_SetMetadataItem(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5141,120 +5507,46 @@ SWIGINTERN PyObject *_wrap_Driver_CreateDataSource(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
+    /* %typemap(ret) CPLErr */
+    if ( bUseExceptions == 0 ) {
+      /* We're not using exceptions.  And no error has occurred */
+      if ( resultobj == 0 ) {
+        /* No other return values set so return ErrorCode */
+        resultobj = PyInt_FromLong(result);
+      }
+    }
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_CopyDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *MajorObject_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_GDALMajorObjectShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_new_StyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
-  OGRDataSourceShadow *arg2 = (OGRDataSourceShadow *) 0 ;
-  char *arg3 = (char *) 0 ;
-  char **arg4 = (char **) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  int bToFree3 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "copy_ds",(char *) "utf8_path",(char *) "options", NULL 
-  };
-  OGRDataSourceShadow *result = 0 ;
+  OGRStyleTableShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Driver_CopyDataSource",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_CopyDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Driver_CopyDataSource" "', argument " "2"" of type '" "OGRDataSourceShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRDataSourceShadow * >(argp2);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg3 = GDALPythonObjectToCStr( obj2, &bToFree3 );
-    if (arg3 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
-    }
-  }
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
-  }
+  if (!PyArg_ParseTuple(args,(char *)":new_StyleTable")) SWIG_fail;
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRDataSourceShadow *)OGRDriverShadow_CopyDataSource(arg1,arg2,(char const *)arg3,arg4);
+    result = (OGRStyleTableShadow *)new_OGRStyleTableShadow();
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5262,74 +5554,31 @@ SWIGINTERN PyObject *_wrap_Driver_CopyDataSource(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg3, bToFree3);
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg3, bToFree3);
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_Open(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_delete_StyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  int arg3 = (int) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int bToFree2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "utf8_path",(char *) "update", NULL 
-  };
-  OGRDataSourceShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Driver_Open",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_StyleTable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Open" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
-    if (arg2 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
-    }
-  }
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Driver_Open" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_StyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRDataSourceShadow *)OGRDriverShadow_Open(arg1,(char const *)arg2,arg3);
+    delete_OGRStyleTableShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5337,52 +5586,52 @@ SWIGINTERN PyObject *_wrap_Driver_Open(PyObject *SWIGUNUSEDPARM(self), PyObject
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_DeleteDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_AddStyle(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   char *arg2 = (char *) 0 ;
+  char *arg3 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int bToFree2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Driver_DeleteDataSource",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_DeleteDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+  if (!PyArg_ParseTuple(args,(char *)"OOO:StyleTable_AddStyle",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_AddStyle" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
-  {
-    /* %typemap(in) (const char *utf8_path) */
-    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
-    if (arg2 == NULL)
-    {
-      PyErr_SetString( PyExc_RuntimeError, "not a string" );
-      SWIG_fail;
-    }
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "StyleTable_AddStyle" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "StyleTable_AddStyle" "', argument " "3"" of type '" "char const *""'");
   }
+  arg3 = reinterpret_cast< char * >(buf3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRDriverShadow_DeleteDataSource(arg1,(char const *)arg2);
+    result = (int)OGRStyleTableShadow_AddStyle(arg1,(char const *)arg2,(char const *)arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5391,54 +5640,47 @@ SWIGINTERN PyObject *_wrap_Driver_DeleteDataSource(PyObject *SWIGUNUSEDPARM(self
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (const char *utf8_path) */
-    GDALPythonFreeCStr(arg2, bToFree2);
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_LoadStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Driver_TestCapability",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_LoadStyleTable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_TestCapability" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Driver_TestCapability" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_LoadStyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    /* %typemap(in) (const char *utf8_path) */
+    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
+    if (arg2 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRDriverShadow_TestCapability(arg1,(char const *)arg2);
+    result = (int)OGRStyleTableShadow_LoadStyleTable(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5446,34 +5688,52 @@ SWIGINTERN PyObject *_wrap_Driver_TestCapability(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_SaveStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Driver_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_SaveStyleTable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_GetName" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_SaveStyleTable" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
+    if (arg2 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRDriverShadow_GetName(arg1);
+    result = (int)OGRStyleTableShadow_SaveStyleTable(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5481,31 +5741,50 @@ SWIGINTERN PyObject *_wrap_Driver_GetName(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_Register(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_Find(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Driver_Register",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:StyleTable_Find",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Register" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_Find" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "StyleTable_Find" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRDriverShadow_Register(arg1);
+    result = (char *)OGRStyleTableShadow_Find(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5513,31 +5792,33 @@ SWIGINTERN PyObject *_wrap_Driver_Register(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Driver_Deregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_ResetStyleStringReading(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Driver_Deregister",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_ResetStyleStringReading",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Deregister" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_ResetStyleStringReading" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRDriverShadow_Deregister(arg1);
+    OGRStyleTableShadow_ResetStyleStringReading(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5552,32 +5833,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *Driver_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRDriverShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_DataSource_name_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_GetNextStyle(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_name_get",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_GetNextStyle",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_name_get" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_GetNextStyle" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRDataSourceShadow_name_get(arg1);
+    result = (char *)OGRStyleTableShadow_GetNextStyle(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5592,24 +5866,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_delete_DataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_StyleTable_GetLastStyleName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRStyleTableShadow *arg1 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_DataSource",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:StyleTable_GetLastStyleName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_DataSource" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "StyleTable_GetLastStyleName" "', argument " "1"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRStyleTableShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRDataSourceShadow(arg1);
+    result = (char *)OGRStyleTableShadow_GetLastStyleName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5617,32 +5892,39 @@ SWIGINTERN PyObject *_wrap_delete_DataSource(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *StyleTable_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRStyleTableShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_Driver_name_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetRefCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Driver_name_get",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetRefCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_name_get" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRDataSourceShadow_GetRefCount(arg1);
+    result = (char *)OGRDriverShadow_name_get(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5650,65 +5932,95 @@ SWIGINTERN PyObject *_wrap_DataSource_GetRefCount(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetSummaryRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Driver_CreateDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  char **arg3 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "utf8_path",(char *) "options", NULL 
+  };
+  OGRDataSourceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetSummaryRefCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Driver_CreateDataSource",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetSummaryRefCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_CreateDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (int)OGRDataSourceShadow_GetSummaryRefCount(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+    /* %typemap(in) (const char *utf8_path) */
+    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
+    if (arg2 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_DataSource_GetLayerCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetLayerCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRDataSourceShadow_GetLayerCount(arg1);
+    result = (OGRDataSourceShadow *)OGRDriverShadow_CreateDataSource(arg1,(char const *)arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5716,32 +6028,120 @@ SWIGINTERN PyObject *_wrap_DataSource_GetLayerCount(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetDriver(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Driver_CopyDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  OGRDataSourceShadow *arg2 = (OGRDataSourceShadow *) 0 ;
+  char *arg3 = (char *) 0 ;
+  char **arg4 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  int bToFree3 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRDriverShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "copy_ds",(char *) "utf8_path",(char *) "options", NULL 
+  };
+  OGRDataSourceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetDriver",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Driver_CopyDataSource",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetDriver" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_CopyDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Driver_CopyDataSource" "', argument " "2"" of type '" "OGRDataSourceShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRDataSourceShadow * >(argp2);
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg3 = GDALPythonObjectToCStr( obj2, &bToFree3 );
+    if (arg3 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
+  }
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRDriverShadow *)OGRDataSourceShadow_GetDriver(arg1);
+    result = (OGRDataSourceShadow *)OGRDriverShadow_CopyDataSource(arg1,arg2,(char const *)arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5749,32 +6149,74 @@ SWIGINTERN PyObject *_wrap_DataSource_GetDriver(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Driver_Open(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  int arg3 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int bToFree2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "utf8_path",(char *) "update", NULL 
+  };
+  OGRDataSourceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Driver_Open",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Open" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
+    if (arg2 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
+  }
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Driver_Open" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRDataSourceShadow_GetName(arg1);
+    result = (OGRDataSourceShadow *)OGRDriverShadow_Open(arg1,(char const *)arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5782,41 +6224,52 @@ SWIGINTERN PyObject *_wrap_DataSource_GetName(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_DeleteLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Driver_DeleteDataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int bToFree2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_DeleteLayer",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Driver_DeleteDataSource",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_DeleteLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_DeleteDataSource" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg2 = GDALPythonObjectToCStr( obj1, &bToFree2 );
+    if (arg2 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_DeleteLayer" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRDataSourceShadow_DeleteLayer(arg1,arg2);
+    result = (int)OGRDriverShadow_DeleteDataSource(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5824,48 +6277,55 @@ SWIGINTERN PyObject *_wrap_DataSource_DeleteLayer(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg2, bToFree2);
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_SyncToDisk(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Driver_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRErr result;
+  PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_SyncToDisk",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Driver_TestCapability",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_SyncToDisk" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_TestCapability" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Driver_TestCapability" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRDataSourceShadow_SyncToDisk(arg1);
+    result = (bool)OGRDriverShadow_TestCapability(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -5873,136 +6333,66 @@ SWIGINTERN PyObject *_wrap_DataSource_SyncToDisk(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_CreateLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Driver_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
-  OGRwkbGeometryType arg4 = (OGRwkbGeometryType) wkbUnknown ;
-  char **arg5 = (char **) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "name",(char *) "srs",(char *) "geom_type",(char *) "options", NULL 
-  };
-  OGRLayerShadow *result = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OOO:DataSource_CreateLayer",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Driver_GetName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CreateLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_CreateLayer" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_GetName" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
-  if (obj2) {
-    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_CreateLayer" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
-  }
-  if (obj3) {
-    ecode4 = SWIG_AsVal_int(obj3, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "DataSource_CreateLayer" "', argument " "4"" of type '" "OGRwkbGeometryType""'");
-    } 
-    arg4 = static_cast< OGRwkbGeometryType >(val4);
-  }
-  if (obj4) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj4) || PyUnicode_Check(obj4)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj4)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj4);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj4,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg5 = CSLAddString( arg5, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg5 = CSLAddString( arg5, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg5 = CSLAddString( arg5, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
+    result = (char *)OGRDriverShadow_GetName(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Driver_Register(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Driver_Register",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Register" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRLayerShadow *)OGRDataSourceShadow_CreateLayer(arg1,(char const *)arg2,arg3,arg4,arg5);
+    OGRDriverShadow_Register(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6010,117 +6400,31 @@ SWIGINTERN PyObject *_wrap_DataSource_CreateLayer(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg5 );
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg5 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_CopyLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Driver_Deregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  char *arg3 = (char *) 0 ;
-  char **arg4 = (char **) 0 ;
+  OGRDriverShadow *arg1 = (OGRDriverShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  int res3 ;
-  char *buf3 = 0 ;
-  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "src_layer",(char *) "new_name",(char *) "options", NULL 
-  };
-  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:DataSource_CopyLayer",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Driver_Deregister",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CopyLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_CopyLayer" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_CopyLayer" "', argument " "3"" of type '" "char const *""'");
-  }
-  arg3 = reinterpret_cast< char * >(buf3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Driver_Deregister" "', argument " "1"" of type '" "OGRDriverShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRDriverShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRLayerShadow *)OGRDataSourceShadow_CopyLayer(arg1,arg2,(char const *)arg3,arg4);
+    OGRDriverShadow_Deregister(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6128,53 +6432,39 @@ SWIGINTERN PyObject *_wrap_DataSource_CopyLayer(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetLayerByIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *Driver_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRDriverShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_DataSource_name_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  int arg2 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRLayerShadow *result = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O|O:DataSource_GetLayerByIndex",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_name_get",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByIndex" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_name_get" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_GetLayerByIndex" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRLayerShadow *)OGRDataSourceShadow_GetLayerByIndex(arg1,arg2);
+    result = (char *)OGRDataSourceShadow_name_get(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6182,42 +6472,31 @@ SWIGINTERN PyObject *_wrap_DataSource_GetLayerByIndex(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetLayerByName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_DataSource(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_GetLayerByName",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_DataSource",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_DataSource" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_GetLayerByName" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRLayerShadow *)OGRDataSourceShadow_GetLayerByName(arg1,(char const *)arg2);
+    delete_OGRDataSourceShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6225,49 +6504,32 @@ SWIGINTERN PyObject *_wrap_DataSource_GetLayerByName(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_TestCapability",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetRefCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_TestCapability" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetRefCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_TestCapability" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRDataSourceShadow_TestCapability(arg1,(char const *)arg2);
+    result = (int)OGRDataSourceShadow_GetRefCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6275,75 +6537,32 @@ SWIGINTERN PyObject *_wrap_DataSource_TestCapability(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_ExecuteSQL(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_DataSource_GetSummaryRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) NULL ;
-  char *arg4 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  int res4 ;
-  char *buf4 = 0 ;
-  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "statement",(char *) "spatialFilter",(char *) "dialect", NULL 
-  };
-  OGRLayerShadow *result = 0 ;
+  int result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OO:DataSource_ExecuteSQL",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetSummaryRefCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_ExecuteSQL" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetSummaryRefCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_ExecuteSQL" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  if (obj2) {
-    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-    if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_ExecuteSQL" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
-    }
-    arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
-  }
-  if (obj3) {
-    res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
-    if (!SWIG_IsOK(res4)) {
-      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "DataSource_ExecuteSQL" "', argument " "4"" of type '" "char const *""'");
-    }
-    arg4 = reinterpret_cast< char * >(buf4);
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRLayerShadow *)OGRDataSourceShadow_ExecuteSQL(arg1,(char const *)arg2,arg3,(char const *)arg4);
+    result = (int)OGRDataSourceShadow_GetSummaryRefCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6351,42 +6570,32 @@ SWIGINTERN PyObject *_wrap_DataSource_ExecuteSQL(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_ReleaseResultSet(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetLayerCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_ReleaseResultSet",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetLayerCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_ReleaseResultSet" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerCount" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRLayerShadow, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_ReleaseResultSet" "', argument " "2"" of type '" "OGRLayerShadow *""'");
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRDataSourceShadow_ReleaseResultSet(arg1,arg2);
+    result = (int)OGRDataSourceShadow_GetLayerCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6394,32 +6603,32 @@ SWIGINTERN PyObject *_wrap_DataSource_ReleaseResultSet(PyObject *SWIGUNUSEDPARM(
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetDriver(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRStyleTableShadow *result = 0 ;
+  OGRDriverShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetStyleTable",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetDriver",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetStyleTable" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetDriver" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRStyleTableShadow *)OGRDataSourceShadow_GetStyleTable(arg1);
+    result = (OGRDriverShadow *)OGRDataSourceShadow_GetDriver(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6427,40 +6636,32 @@ SWIGINTERN PyObject *_wrap_DataSource_GetStyleTable(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRDriverShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_DataSource_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
-  OGRStyleTableShadow *arg2 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_SetStyleTable",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetName",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_SetStyleTable" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_SetStyleTable" "', argument " "2"" of type '" "OGRStyleTableShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRStyleTableShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRDataSourceShadow_SetStyleTable(arg1,arg2);
+    result = (char *)OGRDataSourceShadow_GetName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6468,39 +6669,41 @@ SWIGINTERN PyObject *_wrap_DataSource_SetStyleTable(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *DataSource_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRDataSourceShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_Layer_GetRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_DeleteLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetRefCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_DeleteLayer",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetRefCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_DeleteLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_DeleteLayer" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRLayerShadow_GetRefCount(arg1);
+    result = (OGRErr)OGRDataSourceShadow_DeleteLayer(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6508,40 +6711,48 @@ SWIGINTERN PyObject *_wrap_Layer_GetRefCount(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_SyncToDisk(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetSpatialFilter",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_SyncToDisk",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_SyncToDisk" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_SetSpatialFilter__SWIG_0(arg1,arg2);
+    result = (OGRErr)OGRDataSourceShadow_SyncToDisk(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6549,67 +6760,47 @@ SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter__SWIG_0(PyObject *SWIGUNUSEDPA
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_FlushCache(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  double arg2 ;
-  double arg3 ;
-  double arg4 ;
-  double arg5 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  double val5 ;
-  int ecode5 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOOO:Layer_SetSpatialFilterRect",&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_FlushCache",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_FlushCache" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  ecode5 = SWIG_AsVal_double(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
-  } 
-  arg5 = static_cast< double >(val5);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_SetSpatialFilterRect__SWIG_0(arg1,arg2,arg3,arg4,arg5);
+    OGRDataSourceShadow_FlushCache(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6624,173 +6815,231 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_CreateLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
+  OGRwkbGeometryType arg4 = (OGRwkbGeometryType) wkbUnknown ;
+  char **arg5 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   void *argp3 = 0 ;
   int res3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "name",(char *) "srs",(char *) "geom_type",(char *) "options", NULL 
+  };
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_SetSpatialFilter",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OOO:DataSource_CreateLayer",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CreateLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_SetSpatialFilter" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_CreateLayer" "', argument " "2"" of type '" "char const *""'");
   }
-  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    OGRLayerShadow_SetSpatialFilter__SWIG_1(arg1,arg2,arg3);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_CreateLayer" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
     }
+    arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
   }
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[4];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  if (obj3) {
+    ecode4 = SWIG_AsVal_int(obj3, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "DataSource_CreateLayer" "', argument " "4"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg4 = static_cast< OGRwkbGeometryType >(val4);
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      void *vptr = 0;
-      int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Layer_SetSpatialFilter__SWIG_0(self, args);
-      }
-    }
-  }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
+  if (obj4) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj4) || PyUnicode_Check(obj4)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj4)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
       }
-      if (_v) {
-        void *vptr = 0;
-        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Layer_SetSpatialFilter__SWIG_1(self, args);
+      
+      int size = PySequence_Size(obj4);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj4,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg5 = CSLAddString( arg5, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg5 = CSLAddString( arg5, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
         }
+        Py_DECREF(pyObj);
       }
     }
   }
-  
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)OGRDataSourceShadow_CreateLayer(arg1,(char const *)arg2,arg3,arg4,arg5);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
+  }
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Layer_SetSpatialFilter'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetSpatialFilter(OGRLayerShadow *,OGRGeometryShadow *)\n"
-    "    SetSpatialFilter(OGRLayerShadow *,int,OGRGeometryShadow *)\n");
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg5 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_CopyLayer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
-  double arg3 ;
-  double arg4 ;
-  double arg5 ;
-  double arg6 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  char *arg3 = (char *) 0 ;
+  char **arg4 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  double val5 ;
-  int ecode5 = 0 ;
-  double val6 ;
-  int ecode6 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "src_layer",(char *) "new_name",(char *) "options", NULL 
+  };
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOOOO:Layer_SetSpatialFilterRect",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:DataSource_CopyLayer",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CopyLayer" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_CopyLayer" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_CopyLayer" "', argument " "3"" of type '" "char const *""'");
+  }
+  arg3 = reinterpret_cast< char * >(buf3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  ecode5 = SWIG_AsVal_double(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
-  } 
-  arg5 = static_cast< double >(val5);
-  ecode6 = SWIG_AsVal_double(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Layer_SetSpatialFilterRect" "', argument " "6"" of type '" "double""'");
-  } 
-  arg6 = static_cast< double >(val6);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_SetSpatialFilterRect__SWIG_1(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRLayerShadow *)OGRDataSourceShadow_CopyLayer(arg1,arg2,(char const *)arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6798,124 +7047,96 @@ SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect__SWIG_1(PyObject *SWIGUNUS
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
   return resultobj;
 fail:
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[7];
-  int ii;
+SWIGINTERN PyObject *_wrap_DataSource_GetLayerByIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  int arg2 = (int) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 6); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  if (!PyArg_ParseTuple(args,(char *)"O|O:DataSource_GetLayerByIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByIndex" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  if (argc == 5) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_double(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        {
-          int res = SWIG_AsVal_double(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          {
-            int res = SWIG_AsVal_double(argv[3], NULL);
-            _v = SWIG_CheckState(res);
-          }
-          if (_v) {
-            {
-              int res = SWIG_AsVal_double(argv[4], NULL);
-              _v = SWIG_CheckState(res);
-            }
-            if (_v) {
-              return _wrap_Layer_SetSpatialFilterRect__SWIG_0(self, args);
-            }
-          }
-        }
-      }
-    }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_GetLayerByIndex" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
-  if (argc == 6) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        {
-          int res = SWIG_AsVal_double(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          {
-            int res = SWIG_AsVal_double(argv[3], NULL);
-            _v = SWIG_CheckState(res);
-          }
-          if (_v) {
-            {
-              int res = SWIG_AsVal_double(argv[4], NULL);
-              _v = SWIG_CheckState(res);
-            }
-            if (_v) {
-              {
-                int res = SWIG_AsVal_double(argv[5], NULL);
-                _v = SWIG_CheckState(res);
-              }
-              if (_v) {
-                return _wrap_Layer_SetSpatialFilterRect__SWIG_1(self, args);
-              }
-            }
-          }
-        }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRLayerShadow *)OGRDataSourceShadow_GetLayerByIndex(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Layer_SetSpatialFilterRect'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetSpatialFilterRect(OGRLayerShadow *,double,double,double,double)\n"
-    "    SetSpatialFilterRect(OGRLayerShadow *,int,double,double,double,double)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetSpatialFilter(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetLayerByName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetSpatialFilter",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_GetLayerByName",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetLayerByName" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_GetLayerByName" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRLayerShadow_GetSpatialFilter(arg1);
+    result = (OGRLayerShadow *)OGRDataSourceShadow_GetLayerByName(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6923,16 +7144,18 @@ SWIGINTERN PyObject *_wrap_Layer_GetSpatialFilter(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetAttributeFilter(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -6941,24 +7164,29 @@ SWIGINTERN PyObject *_wrap_Layer_SetAttributeFilter(PyObject *SWIGUNUSEDPARM(sel
   int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetAttributeFilter",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_TestCapability",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetAttributeFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_TestCapability" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetAttributeFilter" "', argument " "2"" of type '" "char *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_TestCapability" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
   {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SetAttributeFilter(arg1,arg2);
+    result = (bool)OGRDataSourceShadow_TestCapability(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -6966,24 +7194,8 @@ SWIGINTERN PyObject *_wrap_Layer_SetAttributeFilter(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
@@ -6991,24 +7203,66 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_ResetReading(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_ExecuteSQL(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) NULL ;
+  char *arg4 = (char *) "" ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
+  int res4 ;
+  char *buf4 = 0 ;
+  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "statement",(char *) "spatialFilter",(char *) "dialect", NULL 
+  };
+  OGRLayerShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_ResetReading",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|OO:DataSource_ExecuteSQL",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ResetReading" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_ExecuteSQL" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_ExecuteSQL" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  if (obj2) {
+    res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "DataSource_ExecuteSQL" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
+    }
+    arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
+  }
+  if (obj3) {
+    res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
+    if (!SWIG_IsOK(res4)) {
+      SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "DataSource_ExecuteSQL" "', argument " "4"" of type '" "char const *""'");
+    }
+    arg4 = reinterpret_cast< char * >(buf4);
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_ResetReading(arg1);
+    result = (OGRLayerShadow *)OGRDataSourceShadow_ExecuteSQL(arg1,(char const *)arg2,arg3,(char const *)arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7016,32 +7270,42 @@ SWIGINTERN PyObject *_wrap_Layer_ResetReading(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_ReleaseResultSet(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_ReleaseResultSet",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetName" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_ReleaseResultSet" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRLayerShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_ReleaseResultSet" "', argument " "2"" of type '" "OGRLayerShadow *""'");
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRLayerShadow_GetName(arg1);
+    OGRDataSourceShadow_ReleaseResultSet(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7049,98 +7313,32 @@ SWIGINTERN PyObject *_wrap_Layer_GetName(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRwkbGeometryType result;
+  OGRStyleTableShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetGeomType",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetGeomType" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRwkbGeometryType)OGRLayerShadow_GetGeomType(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Layer_GetGeometryColumn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetGeometryColumn",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetGeometryColumn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (char *)OGRLayerShadow_GetGeometryColumn(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_FromCharPtr((const char *)result);
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Layer_GetFIDColumn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetFIDColumn",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_GetStyleTable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFIDColumn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_GetStyleTable" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRLayerShadow_GetFIDColumn(arg1);
+    result = (OGRStyleTableShadow *)OGRDataSourceShadow_GetStyleTable(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7148,74 +7346,40 @@ SWIGINTERN PyObject *_wrap_Layer_GetFIDColumn(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  OGRStyleTableShadow *arg2 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  long val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRFeatureShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_GetFeature",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:DataSource_SetStyleTable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_long(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_GetFeature" "', argument " "2"" of type '" "long""'");
-  } 
-  arg2 = static_cast< long >(val2);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRFeatureShadow *)OGRLayerShadow_GetFeature(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_SetStyleTable" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Layer_GetNextFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  OGRFeatureShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetNextFeature",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetNextFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "DataSource_SetStyleTable" "', argument " "2"" of type '" "OGRStyleTableShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  arg2 = reinterpret_cast< OGRStyleTableShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFeatureShadow *)OGRLayerShadow_GetNextFeature(arg1);
+    OGRDataSourceShadow_SetStyleTable(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7223,41 +7387,46 @@ SWIGINTERN PyObject *_wrap_Layer_GetNextFeature(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetNextByIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_StartTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
+  int arg2 = (int) FALSE ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  long val2 ;
+  int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "force", NULL 
+  };
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetNextByIndex",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:DataSource_StartTransaction",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetNextByIndex" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_StartTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "DataSource_StartTransaction" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_long(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetNextByIndex" "', argument " "2"" of type '" "long""'");
-  } 
-  arg2 = static_cast< long >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SetNextByIndex(arg1,arg2);
+    result = (OGRErr)OGRDataSourceShadow_StartTransaction(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7288,39 +7457,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_CommitTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetFeature",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_CommitTransaction",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetFeature" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_CommitTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SetFeature(arg1,arg2);
+    result = (OGRErr)OGRDataSourceShadow_CommitTransaction(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7351,39 +7506,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_CreateFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_DataSource_RollbackTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
+  OGRDataSourceShadow *arg1 = (OGRDataSourceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_CreateFeature",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:DataSource_RollbackTransaction",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRDataSourceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateFeature" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "DataSource_RollbackTransaction" "', argument " "1"" of type '" "OGRDataSourceShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRDataSourceShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_CreateFeature(arg1,arg2);
+    result = (OGRErr)OGRDataSourceShadow_RollbackTransaction(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7414,34 +7555,32 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_DeleteFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *DataSource_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRDataSourceShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_Layer_GetRefCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  long arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  long val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRErr result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_DeleteFeature",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetRefCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_DeleteFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetRefCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_long(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_DeleteFeature" "', argument " "2"" of type '" "long""'");
-  } 
-  arg2 = static_cast< long >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_DeleteFeature(arg1,arg2);
+    result = (int)OGRLayerShadow_GetRefCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7449,48 +7588,40 @@ SWIGINTERN PyObject *_wrap_Layer_DeleteFeature(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SyncToDisk(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRErr result;
+  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_SyncToDisk",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetSpatialFilter",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SyncToDisk" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SyncToDisk(arg1);
+    OGRLayerShadow_SetSpatialFilter__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7498,48 +7629,67 @@ SWIGINTERN PyObject *_wrap_Layer_SyncToDisk(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetLayerDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  double arg2 ;
+  double arg3 ;
+  double arg4 ;
+  double arg5 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
+  int ecode4 = 0 ;
+  double val5 ;
+  int ecode5 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRFeatureDefnShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetLayerDefn",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOOOO:Layer_SetSpatialFilterRect",&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetLayerDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  ecode4 = SWIG_AsVal_double(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
+  } 
+  arg4 = static_cast< double >(val4);
+  ecode5 = SWIG_AsVal_double(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
+  } 
+  arg5 = static_cast< double >(val5);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFeatureDefnShadow *)OGRLayerShadow_GetLayerDefn(arg1);
+    OGRLayerShadow_SetSpatialFilterRect__SWIG_0(arg1,arg2,arg3,arg4,arg5);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7547,46 +7697,49 @@ SWIGINTERN PyObject *_wrap_Layer_GetLayerDefn(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetFeatureCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 = (int) 1 ;
+  int arg2 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "force", NULL 
-  };
-  int result;
+  PyObject * obj2 = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Layer_GetFeatureCount",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_SetSpatialFilter",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeatureCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_GetFeatureCount" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilter" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_SetSpatialFilter" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRLayerShadow_GetFeatureCount(arg1,arg2);
+    OGRLayerShadow_SetSpatialFilter__SWIG_1(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7594,76 +7747,130 @@ SWIGINTERN PyObject *_wrap_Layer_GetFeatureCount(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetExtent(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilter(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[4];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      void *vptr = 0;
+      int res = SWIG_ConvertPtr(argv[1], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Layer_SetSpatialFilter__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Layer_SetSpatialFilter__SWIG_1(self, args);
+        }
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Layer_SetSpatialFilter'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetSpatialFilter(OGRLayerShadow *,OGRGeometryShadow *)\n"
+    "    SetSpatialFilter(OGRLayerShadow *,int,OGRGeometryShadow *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  double *arg2 ;
-  int *arg3 = (int *) NULL ;
-  int arg4 = (int) 1 ;
-  int arg5 = (int) 0 ;
-  int arg6 = (int) 0 ;
+  int arg2 ;
+  double arg3 ;
+  double arg4 ;
+  double arg5 ;
+  double arg6 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double argout2[6] ;
-  int isvalid2 ;
-  int val4 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
   int ecode4 = 0 ;
-  int val5 ;
+  double val5 ;
   int ecode5 = 0 ;
-  int val6 ;
+  double val6 ;
   int ecode6 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "force",(char *) "can_return_null",(char *) "geom_field", NULL 
-  };
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
   
-  {
-    /* %typemap(in) (double argout2[4], int* isvalid2) */
-    arg2 = argout2;
-    arg3 = &isvalid2;
-  }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOO:Layer_GetExtent",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOOOOO:Layer_SetSpatialFilterRect",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetExtent" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetSpatialFilterRect" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  if (obj1) {
-    ecode4 = SWIG_AsVal_int(obj1, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_GetExtent" "', argument " "4"" of type '" "int""'");
-    } 
-    arg4 = static_cast< int >(val4);
-  }
-  if (obj2) {
-    ecode5 = SWIG_AsVal_int(obj2, &val5);
-    if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_GetExtent" "', argument " "5"" of type '" "int""'");
-    } 
-    arg5 = static_cast< int >(val5);
-  }
-  if (obj3) {
-    ecode6 = SWIG_AsVal_int(obj3, &val6);
-    if (!SWIG_IsOK(ecode6)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Layer_GetExtent" "', argument " "6"" of type '" "int""'");
-    } 
-    arg6 = static_cast< int >(val6);
-  }
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_SetSpatialFilterRect" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_SetSpatialFilterRect" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  ecode4 = SWIG_AsVal_double(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_SetSpatialFilterRect" "', argument " "4"" of type '" "double""'");
+  } 
+  arg4 = static_cast< double >(val4);
+  ecode5 = SWIG_AsVal_double(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_SetSpatialFilterRect" "', argument " "5"" of type '" "double""'");
+  } 
+  arg5 = static_cast< double >(val5);
+  ecode6 = SWIG_AsVal_double(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Layer_SetSpatialFilterRect" "', argument " "6"" of type '" "double""'");
+  } 
+  arg6 = static_cast< double >(val6);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_GetExtent(arg1,arg2,arg3,arg4,arg5,arg6);
+    OGRLayerShadow_SetSpatialFilterRect__SWIG_1(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7672,58 +7879,123 @@ SWIGINTERN PyObject *_wrap_Layer_GetExtent(PyObject *SWIGUNUSEDPARM(self), PyObj
     }
   }
   resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (double argout[4], int* isvalid)  */
-    PyObject *r;
-    if ( !*arg3 ) {
-      Py_INCREF(Py_None);
-      r = Py_None;
-    }
-    else {
-      r = CreateTupleFromDoubleArray(arg2, 4);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_SetSpatialFilterRect(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[7];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 6); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 5) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_double(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        {
+          int res = SWIG_AsVal_double(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          {
+            int res = SWIG_AsVal_double(argv[3], NULL);
+            _v = SWIG_CheckState(res);
+          }
+          if (_v) {
+            {
+              int res = SWIG_AsVal_double(argv[4], NULL);
+              _v = SWIG_CheckState(res);
+            }
+            if (_v) {
+              return _wrap_Layer_SetSpatialFilterRect__SWIG_0(self, args);
+            }
+          }
+        }
+      }
     }
-    resultobj = t_output_helper(resultobj,r);
   }
-  return resultobj;
+  if (argc == 6) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRLayerShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        {
+          int res = SWIG_AsVal_double(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          {
+            int res = SWIG_AsVal_double(argv[3], NULL);
+            _v = SWIG_CheckState(res);
+          }
+          if (_v) {
+            {
+              int res = SWIG_AsVal_double(argv[4], NULL);
+              _v = SWIG_CheckState(res);
+            }
+            if (_v) {
+              {
+                int res = SWIG_AsVal_double(argv[5], NULL);
+                _v = SWIG_CheckState(res);
+              }
+              if (_v) {
+                return _wrap_Layer_SetSpatialFilterRect__SWIG_1(self, args);
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  
 fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Layer_SetSpatialFilterRect'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetSpatialFilterRect(OGRLayerShadow *,double,double,double,double)\n"
+    "    SetSpatialFilterRect(OGRLayerShadow *,int,double,double,double,double)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetSpatialFilter(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_TestCapability",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetSpatialFilter",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_TestCapability" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetSpatialFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_TestCapability" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRLayerShadow_TestCapability(arg1,(char const *)arg2);
+    result = (OGRGeometryShadow *)OGRLayerShadow_GetSpatialFilter(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7731,62 +8003,42 @@ SWIGINTERN PyObject *_wrap_Layer_TestCapability(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_CreateField(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_SetAttributeFilter(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRFieldDefnShadow *arg2 = (OGRFieldDefnShadow *) 0 ;
-  int arg3 = (int) 1 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "field_def",(char *) "approx_ok", NULL 
-  };
   OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Layer_CreateField",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetAttributeFilter",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetAttributeFilter" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateField" "', argument " "2"" of type '" "OGRFieldDefnShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFieldDefnShadow * >(argp2);
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_CreateField" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetAttributeFilter" "', argument " "2"" of type '" "char *""'");
   }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_CreateField(arg1,arg2,arg3);
+    result = (OGRErr)OGRLayerShadow_SetAttributeFilter(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7801,6 +8053,7 @@ SWIGINTERN PyObject *_wrap_Layer_CreateField(PyObject *SWIGUNUSEDPARM(self), PyO
       SWIG_fail;
     }
   }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
@@ -7813,38 +8066,29 @@ SWIGINTERN PyObject *_wrap_Layer_CreateField(PyObject *SWIGUNUSEDPARM(self), PyO
   }
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_DeleteField(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_ResetReading(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_DeleteField",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_ResetReading",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_DeleteField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ResetReading" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_DeleteField" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_DeleteField(arg1,arg2);
+    OGRLayerShadow_ResetReading(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7852,66 +8096,32 @@ SWIGINTERN PyObject *_wrap_Layer_DeleteField(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_ReorderField(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
-  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  OGRErr result;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_ReorderField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetName",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ReorderField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetName" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_ReorderField" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_ReorderField" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_ReorderField(arg1,arg2,arg3);
+    result = (char *)OGRLayerShadow_GetName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7919,70 +8129,65 @@ SWIGINTERN PyObject *_wrap_Layer_ReorderField(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_ReorderFields(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
-  int *arg3 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRErr result;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_ReorderFields",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetGeomType",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ReorderFields" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetGeomType" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj1) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg2 = PySequence_Size(obj1);
-    arg3 = (int*) malloc(arg2*sizeof(int));
-    for( int i = 0; i<arg2; i++ ) {
-      PyObject *o = PySequence_GetItem(obj1,i);
-      if ( !PyArg_Parse(o,"i",&arg3[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not an integer");
-        Py_DECREF(o);
-        SWIG_fail;
+    result = (OGRwkbGeometryType)OGRLayerShadow_GetGeomType(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-      Py_DECREF(o);
     }
   }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_GetGeometryColumn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  char *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetGeometryColumn",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetGeometryColumn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_ReorderFields(arg1,arg2,arg3);
+    result = (char *)OGRLayerShadow_GetGeometryColumn(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -7990,92 +8195,151 @@ SWIGINTERN PyObject *_wrap_Layer_ReorderFields(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_GetFIDColumn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  char *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetFIDColumn",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFIDColumn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (char *)OGRLayerShadow_GetFIDColumn(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_GetFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  GIntBig arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRFeatureShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_GetFeature",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg3) {
-      free((void*) arg3);
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(obj1,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      SWIG_fail;
     }
+    arg2 = (GIntBig)val;
   }
   {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
+    result = (OGRFeatureShadow *)OGRLayerShadow_GetFeature(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_GetNextFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRFeatureShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetNextFeature",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetNextFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg3) {
-      free((void*) arg3);
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRFeatureShadow *)OGRLayerShadow_GetNextFeature(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
+  return resultobj;
+fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_AlterFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_SetNextByIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  int arg2 ;
-  OGRFieldDefnShadow *arg3 = (OGRFieldDefnShadow *) 0 ;
-  int arg4 ;
+  GIntBig arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOO:Layer_AlterFieldDefn",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetNextByIndex",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_AlterFieldDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetNextByIndex" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_AlterFieldDefn" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_AlterFieldDefn" "', argument " "3"" of type '" "OGRFieldDefnShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRFieldDefnShadow * >(argp3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_AlterFieldDefn" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
   {
-    if (!arg3) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(obj1,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      SWIG_fail;
     }
+    arg2 = (GIntBig)val;
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_AlterFieldDefn(arg1,arg2,arg3,arg4);
+    result = (OGRErr)OGRLayerShadow_SetNextByIndex(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8106,43 +8370,29 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_CreateGeomField(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_SetFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRGeomFieldDefnShadow *arg2 = (OGRGeomFieldDefnShadow *) 0 ;
-  int arg3 = (int) 1 ;
+  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "field_def",(char *) "approx_ok", NULL 
-  };
   OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Layer_CreateGeomField",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetFeature",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateGeomField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateGeomField" "', argument " "2"" of type '" "OGRGeomFieldDefnShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp2);
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_CreateGeomField" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetFeature" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
   }
+  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -8152,7 +8402,7 @@ SWIGINTERN PyObject *_wrap_Layer_CreateGeomField(PyObject *SWIGUNUSEDPARM(self),
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_CreateGeomField(arg1,arg2,arg3);
+    result = (OGRErr)OGRLayerShadow_SetFeature(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8183,25 +8433,39 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_StartTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_CreateFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_StartTransaction",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_CreateFeature",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_StartTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateFeature" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_StartTransaction(arg1);
+    result = (OGRErr)OGRLayerShadow_CreateFeature(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8232,25 +8496,35 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_CommitTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_DeleteFeature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  GIntBig arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_CommitTransaction",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_DeleteFeature",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CommitTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_DeleteFeature" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(obj1,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      SWIG_fail;
+    }
+    arg2 = (GIntBig)val;
+  }
+  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_CommitTransaction(arg1);
+    result = (OGRErr)OGRLayerShadow_DeleteFeature(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8281,7 +8555,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_RollbackTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_SyncToDisk(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
   void *argp1 = 0 ;
@@ -8289,17 +8563,17 @@ SWIGINTERN PyObject *_wrap_Layer_RollbackTransaction(PyObject *SWIGUNUSEDPARM(se
   PyObject * obj0 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_RollbackTransaction",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_SyncToDisk",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_RollbackTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SyncToDisk" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_RollbackTransaction(arg1);
+    result = (OGRErr)OGRLayerShadow_SyncToDisk(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8330,44 +8604,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_FindFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetLayerDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  int result;
+  OGRFeatureDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_FindFieldIndex",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetLayerDefn",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_FindFieldIndex" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetLayerDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_FindFieldIndex" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_FindFieldIndex" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRLayerShadow_FindFieldIndex(arg1,(char const *)arg2,arg3);
+    result = (OGRFeatureDefnShadow *)OGRLayerShadow_GetLayerDefn(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8375,34 +8630,46 @@ SWIGINTERN PyObject *_wrap_Layer_FindFieldIndex(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetFeatureCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  int arg2 = (int) 1 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  OSRSpatialReferenceShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "force", NULL 
+  };
+  GIntBig result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetSpatialRef",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Layer_GetFeatureCount",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetSpatialRef" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeatureCount" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_GetFeatureCount" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OSRSpatialReferenceShadow *)OGRLayerShadow_GetSpatialRef(arg1);
+    result = OGRLayerShadow_GetFeatureCount(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8410,32 +8677,84 @@ SWIGINTERN PyObject *_wrap_Layer_GetSpatialRef(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
+  {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, result);
+#if PY_VERSION_HEX>=0x03000000
+    resultobj = PyLong_FromString(szTmp, NULL, 10);
+#else
+    resultobj = PyInt_FromString(szTmp, NULL, 10);
+#endif
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetFeaturesRead(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetExtent(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  double *arg2 ;
+  int *arg3 = (int *) NULL ;
+  int arg4 = (int) 1 ;
+  int arg5 = (int) 0 ;
+  int arg6 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double argout2[6] ;
+  int isvalid2 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
   PyObject * obj0 = 0 ;
-  GIntBig result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "force",(char *) "can_return_null",(char *) "geom_field", NULL 
+  };
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetFeaturesRead",&obj0)) SWIG_fail;
+  {
+    /* %typemap(in) (double argout2[4], int* isvalid2) */
+    arg2 = argout2;
+    arg3 = &isvalid2;
+  }
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOO:Layer_GetExtent",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeaturesRead" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetExtent" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  if (obj1) {
+    ecode4 = SWIG_AsVal_int(obj1, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_GetExtent" "', argument " "4"" of type '" "int""'");
+    } 
+    arg4 = static_cast< int >(val4);
+  }
+  if (obj2) {
+    ecode5 = SWIG_AsVal_int(obj2, &val5);
+    if (!SWIG_IsOK(ecode5)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Layer_GetExtent" "', argument " "5"" of type '" "int""'");
+    } 
+    arg5 = static_cast< int >(val5);
+  }
+  if (obj3) {
+    ecode6 = SWIG_AsVal_int(obj3, &val6);
+    if (!SWIG_IsOK(ecode6)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Layer_GetExtent" "', argument " "6"" of type '" "int""'");
+    } 
+    arg6 = static_cast< int >(val6);
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = OGRLayerShadow_GetFeaturesRead(arg1);
+    OGRLayerShadow_GetExtent(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8443,78 +8762,59 @@ SWIGINTERN PyObject *_wrap_Layer_GetFeaturesRead(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj((new GIntBig(static_cast< const GIntBig& >(result))), SWIGTYPE_p_GIntBig, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (double argout[4], int* isvalid)  */
+    PyObject *r;
+    if ( !*arg3 ) {
+      Py_INCREF(Py_None);
+      r = Py_None;
+    }
+    else {
+      r = CreateTupleFromDoubleArray(arg2, 4);
+    }
+    resultobj = t_output_helper(resultobj,r);
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetIgnoredFields(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_TestCapability(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  char **arg2 = (char **) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetIgnoredFields",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_TestCapability",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetIgnoredFields" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_TestCapability" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_TestCapability" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
-    /* %typemap(in) char **options */
-    /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-    if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
-  #if PY_VERSION_HEX < 0x03000000
-      || PyString_Check(obj1)
-  #endif
-      ) {
-      PyErr_SetString(PyExc_TypeError,"not a sequence");
-      SWIG_fail;
-    }
-    
-    int size = PySequence_Size(obj1);
-    for (int i = 0; i < size; i++) {
-      PyObject* pyObj = PySequence_GetItem(obj1,i);
-      if (PyUnicode_Check(pyObj))
-      {
-        char *pszStr;
-        Py_ssize_t nLen;
-        PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-        PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-        PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-        arg2 = CSLAddString( arg2, pszStr );
-        Py_XDECREF(pyUTF8Str);
-      }
-#if PY_VERSION_HEX >= 0x03000000
-      else if (PyBytes_Check(pyObj))
-      arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
-#else
-      else if (PyString_Check(pyObj))
-      arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
-#endif
-      else
-      {
-        Py_DECREF(pyObj);
-        PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-        SWIG_fail;
-      }
-      Py_DECREF(pyObj);
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SetIgnoredFields(arg1,(char const **)arg2);
+    result = (bool)OGRLayerShadow_TestCapability(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8522,169 +8822,62 @@ SWIGINTERN PyObject *_wrap_Layer_SetIgnoredFields(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
-  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Intersection(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_CreateField(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
+  OGRFieldDefnShadow *arg2 = (OGRFieldDefnShadow *) 0 ;
+  int arg3 = (int) 1 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+    (char *) "self",(char *) "field_def",(char *) "approx_ok", NULL 
   };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Intersection",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Layer_CreateField",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Intersection" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Intersection" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Intersection" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateField" "', argument " "2"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
+  arg2 = reinterpret_cast< OGRFieldDefnShadow * >(argp2);
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_CreateField" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
   }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_Intersection(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_CreateField(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8700,16 +8893,6 @@ SWIGINTERN PyObject *_wrap_Layer_Intersection(PyObject *SWIGUNUSEDPARM(self), Py
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -8721,152 +8904,38 @@ SWIGINTERN PyObject *_wrap_Layer_Intersection(PyObject *SWIGUNUSEDPARM(self), Py
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Union(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_DeleteField(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
-  };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Union",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_DeleteField",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Union" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_DeleteField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Union" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Union" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
-  }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
-  }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
-    }
-  }
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_DeleteField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_Union(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_DeleteField(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -8882,16 +8951,6 @@ SWIGINTERN PyObject *_wrap_Layer_Union(PyObject *SWIGUNUSEDPARM(self), PyObject
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -8903,152 +8962,118 @@ SWIGINTERN PyObject *_wrap_Layer_Union(PyObject *SWIGUNUSEDPARM(self), PyObject
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SymDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_ReorderField(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
+  int arg2 ;
+  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
-  };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_SymDifference",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_ReorderField",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SymDifference" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ReorderField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SymDifference" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_SymDifference" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_ReorderField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_ReorderField" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRLayerShadow_ReorderField(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
     }
   }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_ReorderFields(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_ReorderFields",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_ReorderFields" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  {
+    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj1) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg2 = PySequence_Size(obj1);
+    arg3 = (int*) malloc(arg2*sizeof(int));
+    for( int i = 0; i<arg2; i++ ) {
+      PyObject *o = PySequence_GetItem(obj1,i);
+      if ( !PyArg_Parse(o,"i",&arg3[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      Py_DECREF(o);
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_SymDifference(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_ReorderFields(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9064,14 +9089,10 @@ SWIGINTERN PyObject *_wrap_Layer_SymDifference(PyObject *SWIGUNUSEDPARM(self), P
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg3) {
+      free((void*) arg3);
+    }
   }
   {
     /* %typemap(ret) OGRErr */
@@ -9086,151 +9107,66 @@ SWIGINTERN PyObject *_wrap_Layer_SymDifference(PyObject *SWIGUNUSEDPARM(self), P
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg3) {
+      free((void*) arg3);
+    }
   }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Identity(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_AlterFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
+  int arg2 ;
+  OGRFieldDefnShadow *arg3 = (OGRFieldDefnShadow *) 0 ;
+  int arg4 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   void *argp3 = 0 ;
   int res3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
-  };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Identity",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOOO:Layer_AlterFieldDefn",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Identity" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_AlterFieldDefn" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Identity" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Layer_AlterFieldDefn" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Identity" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
-  }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_AlterFieldDefn" "', argument " "3"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
+  arg3 = reinterpret_cast< OGRFieldDefnShadow * >(argp3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Layer_AlterFieldDefn" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  {
+    if (!arg3) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_Identity(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_AlterFieldDefn(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9246,16 +9182,6 @@ SWIGINTERN PyObject *_wrap_Layer_Identity(PyObject *SWIGUNUSEDPARM(self), PyObje
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -9267,152 +9193,57 @@ SWIGINTERN PyObject *_wrap_Layer_Identity(PyObject *SWIGUNUSEDPARM(self), PyObje
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Update(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_CreateGeomField(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
+  OGRGeomFieldDefnShadow *arg2 = (OGRGeomFieldDefnShadow *) 0 ;
+  int arg3 = (int) 1 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+    (char *) "self",(char *) "field_def",(char *) "approx_ok", NULL 
   };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Update",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Layer_CreateGeomField",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Update" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CreateGeomField" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Update" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Update" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_CreateGeomField" "', argument " "2"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
+  arg2 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp2);
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_CreateGeomField" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
   }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_Update(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_CreateGeomField(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9428,16 +9259,6 @@ SWIGINTERN PyObject *_wrap_Layer_Update(PyObject *SWIGUNUSEDPARM(self), PyObject
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -9449,152 +9270,78 @@ SWIGINTERN PyObject *_wrap_Layer_Update(PyObject *SWIGUNUSEDPARM(self), PyObject
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Clip(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_StartTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
-  };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Clip",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_StartTransaction",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Clip" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_StartTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Clip" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Clip" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRLayerShadow_StartTransaction(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
     }
   }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
     }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Layer_CommitTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_CommitTransaction",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_CommitTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRLayerShadow_Clip(arg1,arg2,arg3,arg4,arg5,arg6);
+    result = (OGRErr)OGRLayerShadow_CommitTransaction(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9610,16 +9357,6 @@ SWIGINTERN PyObject *_wrap_Layer_Clip(PyObject *SWIGUNUSEDPARM(self), PyObject *
     }
   }
   {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
-  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -9631,175 +9368,42 @@ SWIGINTERN PyObject *_wrap_Layer_Clip(PyObject *SWIGUNUSEDPARM(self), PyObject *
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_Erase(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_RollbackTransaction(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
-  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
-  char **arg4 = (char **) NULL ;
-  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
-  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
-  };
   OGRErr result;
   
-  /* %typemap(arginit) ( const char* callback_data=NULL)  */
-  PyProgressData *psProgressInfo;
-  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
-  psProgressInfo->nLastReported = -1;
-  psProgressInfo->psPyCallback = NULL;
-  psProgressInfo->psPyCallbackData = NULL;
-  arg6 = psProgressInfo;
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Erase",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_RollbackTransaction",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Erase" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_RollbackTransaction" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Erase" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRLayerShadow_RollbackTransaction(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
   }
-  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Erase" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
-  if (obj3) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj3)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj3);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj3,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg4 = CSLAddString( arg4, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
-  }
-  if (obj4) {
-    {
-      /* %typemap(in) (GDALProgressFunc callback = NULL) */
-      /* callback_func typemap */
-      if (obj4 && obj4 != Py_None ) {
-        void* cbfunction = NULL;
-        SWIG_ConvertPtr( obj4, 
-          (void**)&cbfunction,
-          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
-          SWIG_POINTER_EXCEPTION | 0 );
-        
-        if ( cbfunction == GDALTermProgress ) {
-          arg5 = GDALTermProgress;
-        } else {
-          if (!PyCallable_Check(obj4)) {
-            PyErr_SetString( PyExc_RuntimeError, 
-              "Object given is not a Python function" );
-            SWIG_fail;
-          }
-          psProgressInfo->psPyCallback = obj4;
-          arg5 = PyProgressProxy;
-        }
-        
-      }
-      
-    }
-  }
-  if (obj5) {
-    {
-      /* %typemap(in) ( void* callback_data=NULL)  */
-      psProgressInfo->psPyCallbackData = obj5 ;
-    }
-  }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRErr)OGRLayerShadow_Erase(arg1,arg2,arg3,arg4,arg5,arg6);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
   }
   {
     /* %typemap(ret) OGRErr */
@@ -9813,39 +9417,48 @@ SWIGINTERN PyObject *_wrap_Layer_Erase(PyObject *SWIGUNUSEDPARM(self), PyObject
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg4 );
-  }
-  {
-    /* %typemap(freearg) ( void* callback_data=NULL)  */
-    
-    CPLFree(psProgressInfo);
-    
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_FindFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRStyleTableShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetStyleTable",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Layer_FindFieldIndex",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetStyleTable" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_FindFieldIndex" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_FindFieldIndex" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Layer_FindFieldIndex" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRStyleTableShadow *)OGRLayerShadow_GetStyleTable(arg1);
+    result = (int)OGRLayerShadow_FindFieldIndex(arg1,(char const *)arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9853,40 +9466,34 @@ SWIGINTERN PyObject *_wrap_Layer_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Layer_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
-  OGRStyleTableShadow *arg2 = (OGRStyleTableShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  OSRSpatialReferenceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetStyleTable",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetSpatialRef",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetStyleTable" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetSpatialRef" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetStyleTable" "', argument " "2"" of type '" "OGRStyleTableShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRStyleTableShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRLayerShadow_SetStyleTable(arg1,arg2);
+    result = (OSRSpatialReferenceShadow *)OGRLayerShadow_GetSpatialRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9894,38 +9501,32 @@ SWIGINTERN PyObject *_wrap_Layer_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *Layer_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRLayerShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_delete_Feature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetFeaturesRead(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  GIntBig result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_Feature",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetFeaturesRead",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Feature" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetFeaturesRead" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRFeatureShadow(arg1);
+    result = OGRLayerShadow_GetFeaturesRead(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -9933,115 +9534,86 @@ SWIGINTERN PyObject *_wrap_delete_Feature(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, result);
+#if PY_VERSION_HEX>=0x03000000
+    resultobj = PyLong_FromString(szTmp, NULL, 10);
+#else
+    resultobj = PyInt_FromString(szTmp, NULL, 10);
+#endif
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_new_Feature(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Layer_SetIgnoredFields(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *  kwnames[] = {
-    (char *) "feature_def", NULL 
-  };
-  OGRFeatureShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:new_Feature",kwnames,&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetIgnoredFields",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Feature" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetIgnoredFields" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
-    if (!arg1) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    /* %typemap(in) char **options */
+    /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+    if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+      || PyString_Check(obj1)
+  #endif
+      ) {
+      PyErr_SetString(PyExc_TypeError,"not a sequence");
+      SWIG_fail;
+    }
+    
+    int size = PySequence_Size(obj1);
+    for (int i = 0; i < size; i++) {
+      PyObject* pyObj = PySequence_GetItem(obj1,i);
+      if (PyUnicode_Check(pyObj))
+      {
+        char *pszStr;
+        Py_ssize_t nLen;
+        PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+        PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+        PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+        arg2 = CSLAddString( arg2, pszStr );
+        Py_XDECREF(pyUTF8Str);
+      }
+#if PY_VERSION_HEX >= 0x03000000
+      else if (PyBytes_Check(pyObj))
+      arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+      else if (PyString_Check(pyObj))
+      arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+      else
+      {
+        Py_DECREF(pyObj);
+        PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+        SWIG_fail;
+      }
+      Py_DECREF(pyObj);
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFeatureShadow *)new_OGRFeatureShadow(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_NEW |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetDefnRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  OGRFeatureDefnShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetDefnRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRFeatureDefnShadow *)OGRFeatureShadow_GetDefnRef(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_SetGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRErr result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetGeometry",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometry" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRErr)OGRFeatureShadow_SetGeometry(arg1,arg2);
+    result = (OGRErr)OGRLayerShadow_SetIgnoredFields(arg1,(char const **)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10057,6 +9629,10 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeometry(PyObject *SWIGUNUSEDPARM(self), P
     }
   }
   {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
+  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -10068,36 +9644,146 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeometry(PyObject *SWIGUNUSEDPARM(self), P
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetGeometryDirectly(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Intersection(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
   int res2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetGeometryDirectly",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Intersection",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometryDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Intersection" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Intersection" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Intersection" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetGeometryDirectly(arg1,arg2);
+    result = (OGRErr)OGRLayerShadow_Intersection(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10113,6 +9799,16 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeometryDirectly(PyObject *SWIGUNUSEDPARM(
     }
   }
   {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -10124,80 +9820,152 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeometryDirectly(PyObject *SWIGUNUSEDPARM(
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeometryRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Union(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetGeometryRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeometryRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeometryRef(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Union",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Union" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Union" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Union" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  OGRErr result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomField",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetGeomField" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomField" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
-  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetGeomField__SWIG_0(arg1,arg2,arg3);
+    result = (OGRErr)OGRLayerShadow_Union(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10213,6 +9981,16 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_0(PyObject *SWIGUNUSEDPARM
     }
   }
   {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -10224,178 +10002,152 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_0(PyObject *SWIGUNUSEDPARM
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_SymDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   void *argp3 = 0 ;
   int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomField",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_SymDifference",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SymDifference" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeomField" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SymDifference" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
-  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomField" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_SymDifference" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
   }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRErr)OGRFeatureShadow_SetGeomField__SWIG_1(arg1,(char const *)arg2,arg3);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
       }
-    }
-  }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_SetGeomField(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[4];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        void *vptr = 0;
-        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetGeomField__SWIG_0(self, args);
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
         }
+        Py_DECREF(pyObj);
       }
     }
   }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        void *vptr = 0;
-        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetGeomField__SWIG_1(self, args);
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
         }
+        
       }
+      
     }
   }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetGeomField'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetGeomField(OGRFeatureShadow *,int,OGRGeometryShadow *)\n"
-    "    SetGeomField(OGRFeatureShadow *,char const *,OGRGeometryShadow *)\n");
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int res3 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  OGRErr result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomFieldDirectly",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  res3 = SWIG_ConvertPtr(obj2, SWIG_as_voidptrptr(&arg3), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "3"" of type '" "OGRGeometryShadow *""'");
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetGeomFieldDirectly__SWIG_0(arg1,arg2,arg3);
+    result = (OGRErr)OGRLayerShadow_SymDifference(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10411,6 +10163,16 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_0(PyObject *SWIGUN
     }
   }
   {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
       Py_DECREF(resultobj);
@@ -10422,169 +10184,152 @@ SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_0(PyObject *SWIGUN
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Identity(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  void *argp3 = 0 ;
   int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomFieldDirectly",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Identity",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Identity" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Identity" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
-  res3 = SWIG_ConvertPtr(obj2, SWIG_as_voidptrptr(&arg3), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "3"" of type '" "OGRGeometryShadow *""'");
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Identity" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
   }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRErr)OGRFeatureShadow_SetGeomFieldDirectly__SWIG_1(arg1,(char const *)arg2,arg3);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
       }
-    }
-  }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[4];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        void *vptr = 0;
-        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetGeomFieldDirectly__SWIG_0(self, args);
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
         }
+        Py_DECREF(pyObj);
       }
     }
   }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        void *vptr = 0;
-        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetGeomFieldDirectly__SWIG_1(self, args);
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
         }
+        
       }
+      
     }
   }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetGeomFieldDirectly'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetGeomFieldDirectly(OGRFeatureShadow *,int,OGRGeometryShadow *)\n"
-    "    SetGeomFieldDirectly(OGRFeatureShadow *,char const *,OGRGeometryShadow *)\n");
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetGeomFieldRef" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeomFieldRef__SWIG_0(arg1,arg2);
+    result = (OGRErr)OGRLayerShadow_Identity(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10592,130 +10337,181 @@ SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef__SWIG_0(PyObject *SWIGUNUSEDP
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Update(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Update",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Update" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldRef" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Update" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
   }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeomFieldRef__SWIG_1(arg1,(char const *)arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Update" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
       }
-      if (_v) {
-        return _wrap_Feature_GetGeomFieldRef__SWIG_0(self, args);
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
       }
     }
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetGeomFieldRef__SWIG_1(self, args);
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
+        }
+        
       }
+      
     }
   }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetGeomFieldRef'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetGeomFieldRef(OGRFeatureShadow *,int)\n"
-    "    GetGeomFieldRef(OGRFeatureShadow *,char const *)\n");
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_Clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  OGRFeatureShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_Clone",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_Clone" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFeatureShadow *)OGRFeatureShadow_Clone(arg1);
+    result = (OGRErr)OGRLayerShadow_Update(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10723,169 +10519,181 @@ SWIGINTERN PyObject *_wrap_Feature_Clone(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_Equal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_Equal",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_Equal" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_Equal" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
   }
-  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
   {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
   }
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
     }
-    result = (bool)OGRFeatureShadow_Equal(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetFieldCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldCount" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (int)OGRFeatureShadow_GetFieldCount(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  return resultobj;
-fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Clip(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRFieldDefnShadow *result = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldDefnRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Clip",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Clip" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldDefnRef" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (OGRFieldDefnShadow *)OGRFeatureShadow_GetFieldDefnRef__SWIG_0(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Clip" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Clip" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRFieldDefnShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldDefnRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldDefnRef" "', argument " "2"" of type '" "char const *""'");
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
   }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldDefnShadow *)OGRFeatureShadow_GetFieldDefnRef__SWIG_1(arg1,(char const *)arg2);
+    result = (OGRErr)OGRLayerShadow_Clip(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -10893,124 +10701,181 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef__SWIG_1(PyObject *SWIGUNUSEDP
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_Feature_GetFieldDefnRef__SWIG_0(self, args);
-      }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
     }
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetFieldDefnRef__SWIG_1(self, args);
-      }
-    }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
   }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldDefnRef'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetFieldDefnRef(OGRFeatureShadow *,int)\n"
-    "    GetFieldDefnRef(OGRFeatureShadow *,char const *)\n");
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  int result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetGeomFieldCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldCount" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
     }
-    result = (int)OGRFeatureShadow_GetGeomFieldCount(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_Erase(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg2 = (OGRLayerShadow *) 0 ;
+  OGRLayerShadow *arg3 = (OGRLayerShadow *) 0 ;
+  char **arg4 = (char **) NULL ;
+  GDALProgressFunc arg5 = (GDALProgressFunc) NULL ;
+  void *arg6 = (void *) NULL ;
+  void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeomFieldDefnShadow *result = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "method_layer",(char *) "result_layer",(char *) "options",(char *) "callback",(char *) "callback_data", NULL 
+  };
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldDefnRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  /* %typemap(arginit) ( const char* callback_data=NULL)  */
+  PyProgressData *psProgressInfo;
+  psProgressInfo = (PyProgressData *) CPLCalloc(1,sizeof(PyProgressData));
+  psProgressInfo->nLastReported = -1;
+  psProgressInfo->psPyCallback = NULL;
+  psProgressInfo->psPyCallbackData = NULL;
+  arg6 = psProgressInfo;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|OOO:Layer_Erase",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_Erase" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_Erase" "', argument " "2"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRLayerShadow * >(argp2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Layer_Erase" "', argument " "3"" of type '" "OGRLayerShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRLayerShadow * >(argp3);
+  if (obj3) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj3) || PyUnicode_Check(obj3)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj3)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj3);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj3,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg4 = CSLAddString( arg4, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg4 = CSLAddString( arg4, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  if (obj4) {
+    {
+      /* %typemap(in) (GDALProgressFunc callback = NULL) */
+      /* callback_func typemap */
+      if (obj4 && obj4 != Py_None ) {
+        void* cbfunction = NULL;
+        SWIG_ConvertPtr( obj4, 
+          (void**)&cbfunction,
+          SWIGTYPE_p_f_double_p_q_const__char_p_void__int,
+          SWIG_POINTER_EXCEPTION | 0 );
+        
+        if ( cbfunction == GDALTermProgress ) {
+          arg5 = GDALTermProgress;
+        } else {
+          if (!PyCallable_Check(obj4)) {
+            PyErr_SetString( PyExc_RuntimeError, 
+              "Object given is not a Python function" );
+            SWIG_fail;
+          }
+          psProgressInfo->psPyCallback = obj4;
+          arg5 = PyProgressProxy;
+        }
+        
+      }
+      
+    }
+  }
+  if (obj5) {
+    {
+      /* %typemap(in) ( void* callback_data=NULL)  */
+      psProgressInfo->psPyCallbackData = obj5 ;
+    }
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeomFieldDefnShadow *)OGRFeatureShadow_GetGeomFieldDefnRef__SWIG_0(arg1,arg2);
+    result = (OGRErr)OGRLayerShadow_Erase(arg1,arg2,arg3,arg4,arg5,arg6);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11018,47 +10883,68 @@ SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_0(PyObject *SWIGUNU
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg4 );
+  }
+  {
+    /* %typemap(freearg) ( void* callback_data=NULL)  */
+    
+    CPLFree(psProgressInfo);
+    
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Layer_GetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRGeomFieldDefnShadow *result = 0 ;
+  OGRStyleTableShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldDefnRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Layer_GetStyleTable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_GetStyleTable" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeomFieldDefnShadow *)OGRFeatureShadow_GetGeomFieldDefnRef__SWIG_1(arg1,(char const *)arg2);
+    result = (OGRStyleTableShadow *)OGRLayerShadow_GetStyleTable(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11066,91 +10952,79 @@ SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_1(PyObject *SWIGUNU
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
+SWIGINTERN PyObject *_wrap_Layer_SetStyleTable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRLayerShadow *arg1 = (OGRLayerShadow *) 0 ;
+  OGRStyleTableShadow *arg2 = (OGRStyleTableShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
   
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  if (!PyArg_ParseTuple(args,(char *)"OO:Layer_SetStyleTable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRLayerShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Layer_SetStyleTable" "', argument " "1"" of type '" "OGRLayerShadow *""'"); 
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_Feature_GetGeomFieldDefnRef__SWIG_0(self, args);
+  arg1 = reinterpret_cast< OGRLayerShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRStyleTableShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Layer_SetStyleTable" "', argument " "2"" of type '" "OGRStyleTableShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRStyleTableShadow * >(argp2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRLayerShadow_SetStyleTable(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetGeomFieldDefnRef__SWIG_1(self, args);
-      }
-    }
-  }
-  
+  resultobj = SWIG_Py_Void();
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetGeomFieldDefnRef'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetGeomFieldDefnRef(OGRFeatureShadow *,int)\n"
-    "    GetGeomFieldDefnRef(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *Layer_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRLayerShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_delete_Feature(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsString",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_Feature",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Feature" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsString" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFeatureShadow_GetFieldAsString__SWIG_0(arg1,arg2);
+    delete_OGRFeatureShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11158,39 +11032,32 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_0(PyObject *SWIGUNUSED
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_Feature(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *result = 0 ;
+  char *  kwnames[] = {
+    (char *) "feature_def", NULL 
+  };
+  OGRFeatureShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsString",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:new_Feature",kwnames,&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsString" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_Feature" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   {
-    if (!arg2) {
+    if (!arg1) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
@@ -11198,7 +11065,7 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_1(PyObject *SWIGUNUSED
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFeatureShadow_GetFieldAsString__SWIG_1(arg1,(char const *)arg2);
+    result = (OGRFeatureShadow *)new_OGRFeatureShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11206,91 +11073,32 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_1(PyObject *SWIGUNUSED
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_NEW |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_Feature_GetFieldAsString__SWIG_0(self, args);
-      }
-    }
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetFieldAsString__SWIG_1(self, args);
-      }
-    }
-  }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsString'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetFieldAsString(OGRFeatureShadow *,int)\n"
-    "    GetFieldAsString(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetDefnRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  int result;
+  OGRFeatureDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetDefnRef",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsInteger" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureShadow_GetFieldAsInteger__SWIG_0(arg1,arg2);
+    result = (OGRFeatureDefnShadow *)OGRFeatureShadow_GetDefnRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11298,47 +11106,41 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_0(PyObject *SWIGUNUSE
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  int result;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetGeometry",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometry" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsInteger" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureShadow_GetFieldAsInteger__SWIG_1(arg1,(char const *)arg2);
+    result = (OGRErr)OGRFeatureShadow_SetGeometry(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11346,91 +11148,155 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_1(PyObject *SWIGUNUSE
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_Feature_GetFieldAsInteger__SWIG_0(self, args);
-      }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
     }
   }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetFieldAsInteger__SWIG_1(self, args);
-      }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
     }
   }
-  
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsInteger'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetFieldAsInteger(OGRFeatureShadow *,int)\n"
-    "    GetFieldAsInteger(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeometryDirectly(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  double result;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDouble",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetGeometryDirectly",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeometryDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_SetGeometryDirectly(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetGeometryRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRGeometryShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetGeometryRef",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeometryRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeometryRef(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomField",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetGeomField" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomField" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRFeatureShadow_GetFieldAsDouble__SWIG_0(arg1,arg2);
+    result = (OGRErr)OGRFeatureShadow_SetGeomField__SWIG_0(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11438,37 +11304,62 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_0(PyObject *SWIGUNUSED
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeomField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  double result;
+  PyObject * obj2 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDouble",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomField",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeomField" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
+  res3 = SWIG_ConvertPtr(obj2, &argp3,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomField" "', argument " "3"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg3 = reinterpret_cast< OGRGeometryShadow * >(argp3);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -11478,7 +11369,7 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_1(PyObject *SWIGUNUSED
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRFeatureShadow_GetFieldAsDouble__SWIG_1(arg1,(char const *)arg2);
+    result = (OGRErr)OGRFeatureShadow_SetGeomField__SWIG_1(arg1,(char const *)arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11486,8 +11377,24 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_1(PyObject *SWIGUNUSED
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
@@ -11495,17 +11402,17 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeomField(PyObject *self, PyObject *args) {
   int argc;
-  PyObject *argv[3];
+  PyObject *argv[4];
   int ii;
   
   if (!PyTuple_Check(args)) SWIG_fail;
   argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
     argv[ii] = PyTuple_GET_ITEM(args,ii);
   }
-  if (argc == 2) {
+  if (argc == 3) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
@@ -11516,11 +11423,16 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble(PyObject *self, PyObject *ar
         _v = SWIG_CheckState(res);
       }
       if (_v) {
-        return _wrap_Feature_GetFieldAsDouble__SWIG_0(self, args);
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetGeomField__SWIG_0(self, args);
+        }
       }
     }
   }
-  if (argc == 2) {
+  if (argc == 3) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
@@ -11529,75 +11441,60 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble(PyObject *self, PyObject *ar
       int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_Feature_GetFieldAsDouble__SWIG_1(self, args);
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetGeomField__SWIG_1(self, args);
+        }
       }
     }
   }
   
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsDouble'.\n"
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetGeomField'.\n"
     "  Possible C/C++ prototypes are:\n"
-    "    GetFieldAsDouble(OGRFeatureShadow *,int)\n"
-    "    GetFieldAsDouble(OGRFeatureShadow *,char const *)\n");
+    "    SetGeomField(OGRFeatureShadow *,int,OGRGeometryShadow *)\n"
+    "    SetGeomField(OGRFeatureShadow *,char const *,OGRGeometryShadow *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDateTime(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  int *arg3 = (int *) 0 ;
-  int *arg4 = (int *) 0 ;
-  int *arg5 = (int *) 0 ;
-  int *arg6 = (int *) 0 ;
-  int *arg7 = (int *) 0 ;
-  int *arg8 = (int *) 0 ;
-  int *arg9 = (int *) 0 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  int temp3 ;
-  int res3 = SWIG_TMPOBJ ;
-  int temp4 ;
-  int res4 = SWIG_TMPOBJ ;
-  int temp5 ;
-  int res5 = SWIG_TMPOBJ ;
-  int temp6 ;
-  int res6 = SWIG_TMPOBJ ;
-  int temp7 ;
-  int res7 = SWIG_TMPOBJ ;
-  int temp8 ;
-  int res8 = SWIG_TMPOBJ ;
-  int temp9 ;
-  int res9 = SWIG_TMPOBJ ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  OGRErr result;
   
-  arg3 = &temp3;
-  arg4 = &temp4;
-  arg5 = &temp5;
-  arg6 = &temp6;
-  arg7 = &temp7;
-  arg8 = &temp8;
-  arg9 = &temp9;
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDateTime",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomFieldDirectly",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDateTime" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDateTime" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
+  res3 = SWIG_ConvertPtr(obj2, SWIG_as_voidptrptr(&arg3), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "3"" of type '" "OGRGeometryShadow *""'");
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_GetFieldAsDateTime(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    result = (OGRErr)OGRFeatureShadow_SetGeomFieldDirectly__SWIG_0(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11605,48 +11502,22 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDateTime(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  if (SWIG_IsTmpObj(res3)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res4)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
   }
-  if (SWIG_IsTmpObj(res5)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg5)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res5) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg5), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res6)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg6)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res6) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg6), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res7)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg7)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res7) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg7), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res8)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg8)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res8) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg8), SWIGTYPE_p_int, new_flags));
-  }
-  if (SWIG_IsTmpObj(res9)) {
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg9)));
-  } else {
-    int new_flags = SWIG_IsNewObj(res9) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
-    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg9), SWIGTYPE_p_int, new_flags));
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
   }
   return resultobj;
 fail:
@@ -11654,42 +11525,47 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsIntegerList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  int *arg3 = (int *) 0 ;
-  int **arg4 = (int **) 0 ;
+  char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg3 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int nLen3 ;
-  int *pList3 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  OGRErr result;
   
-  {
-    /* %typemap(in,numinputs=0) (int *nLen3, const int **pList3) (int nLen3, int *pList3) */
-    arg3 = &nLen3;
-    arg4 = &pList3;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsIntegerList",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetGeomFieldDirectly",&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsIntegerList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsIntegerList" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  res3 = SWIG_ConvertPtr(obj2, SWIG_as_voidptrptr(&arg3), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetGeomFieldDirectly" "', argument " "3"" of type '" "OGRGeometryShadow *""'");
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_GetFieldAsIntegerList(arg1,arg2,arg3,(int const **)arg4);
+    result = (OGRErr)OGRFeatureShadow_SetGeomFieldDirectly__SWIG_1(arg1,(char const *)arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11697,59 +11573,117 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsIntegerList(PyObject *SWIGUNUSEDPAR
       }
     }
   }
-  resultobj = SWIG_Py_Void();
   {
-    /* %typemap(argout) (int *nLen, const int **pList ) */
-    Py_DECREF(resultobj);
-    PyObject *out = PyList_New( *arg3 );
-    for( int i=0; i<*arg3; i++ ) {
-      PyObject *val = PyInt_FromLong( (*arg4)[i] );
-      PyList_SetItem( out, i, val );
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
     }
-    resultobj = out;
   }
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDoubleList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_SetGeomFieldDirectly(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[4];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetGeomFieldDirectly__SWIG_0(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        void *vptr = 0;
+        int res = SWIG_ConvertPtr(argv[2], &vptr, SWIGTYPE_p_OGRGeometryShadow, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetGeomFieldDirectly__SWIG_1(self, args);
+        }
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetGeomFieldDirectly'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetGeomFieldDirectly(OGRFeatureShadow *,int,OGRGeometryShadow *)\n"
+    "    SetGeomFieldDirectly(OGRFeatureShadow *,char const *,OGRGeometryShadow *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  int *arg3 = (int *) 0 ;
-  double **arg4 = (double **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  int nLen3 ;
-  double *pList3 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (int *nLen3, const double **pList3) (int nLen3, double *pList3) */
-    arg3 = &nLen3;
-    arg4 = &pList3;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDoubleList",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDoubleList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDoubleList" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetGeomFieldRef" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_GetFieldAsDoubleList(arg1,arg2,arg3,(double const **)arg4);
+    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeomFieldRef__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11757,51 +11691,47 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDoubleList(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (int *nLen, const double **pList ) */
-    Py_DECREF(resultobj);
-    PyObject *out = PyList_New( *arg3 );
-    for( int i=0; i<*arg3; i++ ) {
-      PyObject *val = PyFloat_FromDouble( (*arg4)[i] );
-      PyList_SetItem( out, i, val );
-    }
-    resultobj = out;
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldAsStringList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char **result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsStringList",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsStringList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsStringList" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldRef" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char **)OGRFeatureShadow_GetFieldAsStringList(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRFeatureShadow_GetGeomFieldRef__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11809,121 +11739,16 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldAsStringList(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  {
-    /* %typemap(out) char **options -> ( string ) */
-    char **stringarray = result;
-    if ( stringarray == NULL ) {
-      resultobj = Py_None;
-      Py_INCREF( resultobj );
-    }
-    else {
-      int len = CSLCount( stringarray );
-      resultobj = PyList_New( len );
-      for ( int i = 0; i < len; ++i ) {
-        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
-        PyList_SetItem(resultobj, i, o );
-      }
-    }
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_IsFieldSet__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_IsFieldSet",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_IsFieldSet" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_IsFieldSet" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (bool)OGRFeatureShadow_IsFieldSet__SWIG_0(arg1,arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_IsFieldSet__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_IsFieldSet",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_IsFieldSet" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_IsFieldSet" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    result = (bool)OGRFeatureShadow_IsFieldSet__SWIG_1(arg1,(char const *)arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_IsFieldSet(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldRef(PyObject *self, PyObject *args) {
   int argc;
   PyObject *argv[3];
   int ii;
@@ -11944,7 +11769,7 @@ SWIGINTERN PyObject *_wrap_Feature_IsFieldSet(PyObject *self, PyObject *args) {
         _v = SWIG_CheckState(res);
       }
       if (_v) {
-        return _wrap_Feature_IsFieldSet__SWIG_0(self, args);
+        return _wrap_Feature_GetGeomFieldRef__SWIG_0(self, args);
       }
     }
   }
@@ -11957,54 +11782,39 @@ SWIGINTERN PyObject *_wrap_Feature_IsFieldSet(PyObject *self, PyObject *args) {
       int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_Feature_IsFieldSet__SWIG_1(self, args);
+        return _wrap_Feature_GetGeomFieldRef__SWIG_1(self, args);
       }
     }
   }
   
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_IsFieldSet'.\n"
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetGeomFieldRef'.\n"
     "  Possible C/C++ prototypes are:\n"
-    "    IsFieldSet(OGRFeatureShadow *,int)\n"
-    "    IsFieldSet(OGRFeatureShadow *,char const *)\n");
+    "    GetGeomFieldRef(OGRFeatureShadow *,int)\n"
+    "    GetGeomFieldRef(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_Clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  int result;
+  OGRFeatureShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldIndex",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_Clone",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldIndex" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_Clone" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldIndex" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureShadow_GetFieldIndex(arg1,(char const *)arg2);
+    result = (OGRFeatureShadow *)OGRFeatureShadow_Clone(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12012,39 +11822,36 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldIndex(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_Equal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  int result;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldIndex",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_Equal",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldIndex" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_Equal" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldIndex" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_Equal" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
+  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -12054,7 +11861,7 @@ SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(se
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureShadow_GetGeomFieldIndex(arg1,(char const *)arg2);
+    result = (bool)OGRFeatureShadow_Equal(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12062,16 +11869,14 @@ SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFID(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   void *argp1 = 0 ;
@@ -12079,17 +11884,17 @@ SWIGINTERN PyObject *_wrap_Feature_GetFID(PyObject *SWIGUNUSEDPARM(self), PyObje
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetFID",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetFieldCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFID" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldCount" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureShadow_GetFID(arg1);
+    result = (int)OGRFeatureShadow_GetFieldCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12104,7 +11909,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFID(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
@@ -12114,24 +11919,24 @@ SWIGINTERN PyObject *_wrap_Feature_SetFID(PyObject *SWIGUNUSEDPARM(self), PyObje
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  OGRFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetFID",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldDefnRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFID" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFID" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldDefnRef" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetFID(arg1,arg2);
+    result = (OGRFieldDefnShadow *)OGRFeatureShadow_GetFieldDefnRef__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12139,88 +11944,47 @@ SWIGINTERN PyObject *_wrap_Feature_SetFID(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_DumpReadable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_DumpReadable",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldDefnRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_DumpReadable" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldDefnRef" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    OGRFeatureShadow_DumpReadable(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_UnsetField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_UnsetField",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_UnsetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_UnsetField" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_UnsetField__SWIG_0(arg1,arg2);
+    result = (OGRFieldDefnShadow *)OGRFeatureShadow_GetFieldDefnRef__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12228,63 +11992,16 @@ SWIGINTERN PyObject *_wrap_Feature_UnsetField__SWIG_0(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_UnsetField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_UnsetField",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_UnsetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_UnsetField" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    OGRFeatureShadow_UnsetField__SWIG_1(arg1,(char const *)arg2);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return resultobj;
-fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_Feature_UnsetField(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldDefnRef(PyObject *self, PyObject *args) {
   int argc;
   PyObject *argv[3];
   int ii;
@@ -12305,7 +12022,7 @@ SWIGINTERN PyObject *_wrap_Feature_UnsetField(PyObject *self, PyObject *args) {
         _v = SWIG_CheckState(res);
       }
       if (_v) {
-        return _wrap_Feature_UnsetField__SWIG_0(self, args);
+        return _wrap_Feature_GetFieldDefnRef__SWIG_0(self, args);
       }
     }
   }
@@ -12318,61 +12035,81 @@ SWIGINTERN PyObject *_wrap_Feature_UnsetField(PyObject *self, PyObject *args) {
       int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        return _wrap_Feature_UnsetField__SWIG_1(self, args);
+        return _wrap_Feature_GetFieldDefnRef__SWIG_1(self, args);
       }
     }
   }
   
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_UnsetField'.\n"
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldDefnRef'.\n"
     "  Possible C/C++ prototypes are:\n"
-    "    UnsetField(OGRFeatureShadow *,int)\n"
-    "    UnsetField(OGRFeatureShadow *,char const *)\n");
+    "    GetFieldDefnRef(OGRFeatureShadow *,int)\n"
+    "    GetFieldDefnRef(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetGeomFieldCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldCount" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureShadow_GetGeomFieldCount(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  char *arg3 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  PyObject *str3 = 0 ;
-  int bToFree3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  OGRGeomFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldDefnRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
-    /* %typemap(in) (tostring argin) */
-    str3 = PyObject_Str( obj2 );
-    if ( str3 == 0 ) {
-      PyErr_SetString( PyExc_RuntimeError, "Unable to format argument as string");
-      SWIG_fail;
-    }
-    
-    arg3 = GDALPythonObjectToCStr(str3, &bToFree3); 
-  }
-  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_0(arg1,arg2,(char const *)arg3);
+    result = (OGRGeomFieldDefnShadow *)OGRFeatureShadow_GetGeomFieldDefnRef__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12380,67 +12117,38 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_0(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(freearg) (tostring argin) */
-    if ( str3 != NULL)
-    {
-      Py_DECREF(str3);
-    }
-    GDALPythonFreeCStr(arg3, bToFree3);
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (tostring argin) */
-    if ( str3 != NULL)
-    {
-      Py_DECREF(str3);
-    }
-    GDALPythonFreeCStr(arg3, bToFree3);
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
-  PyObject *str3 = 0 ;
-  int bToFree3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  OGRGeomFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldDefnRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldDefnRef" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
   {
-    /* %typemap(in) (tostring argin) */
-    str3 = PyObject_Str( obj2 );
-    if ( str3 == 0 ) {
-      PyErr_SetString( PyExc_RuntimeError, "Unable to format argument as string");
-      SWIG_fail;
-    }
-    
-    arg3 = GDALPythonObjectToCStr(str3, &bToFree3); 
-  }
-  {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
@@ -12449,7 +12157,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_1(PyObject *SWIGUNUSEDPARM(sel
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_1(arg1,(char const *)arg2,(char const *)arg3);
+    result = (OGRGeomFieldDefnShadow *)OGRFeatureShadow_GetGeomFieldDefnRef__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12457,67 +12165,91 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_1(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (tostring argin) */
-    if ( str3 != NULL)
-    {
-      Py_DECREF(str3);
-    }
-    GDALPythonFreeCStr(arg3, bToFree3);
-  }
   return resultobj;
 fail:
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (tostring argin) */
-    if ( str3 != NULL)
-    {
-      Py_DECREF(str3);
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldDefnRef(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_GetGeomFieldDefnRef__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_GetGeomFieldDefnRef__SWIG_1(self, args);
+      }
     }
-    GDALPythonFreeCStr(arg3, bToFree3);
   }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetGeomFieldDefnRef'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetGeomFieldDefnRef(OGRFeatureShadow *,int)\n"
+    "    GetGeomFieldDefnRef(OGRFeatureShadow *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsString",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsString" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_2(arg1,arg2,arg3);
+    result = (char *)OGRFeatureShadow_GetFieldAsString__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12525,45 +12257,37 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_2(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_3(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  int arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsString",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsString" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -12573,7 +12297,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_3(PyObject *SWIGUNUSEDPARM(sel
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_3(arg1,(char const *)arg2,arg3);
+    result = (char *)OGRFeatureShadow_GetFieldAsString__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12581,7 +12305,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_3(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
@@ -12590,42 +12314,82 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_4(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsString(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_GetFieldAsString__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_GetFieldAsString__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsString'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldAsString(OGRFeatureShadow *,int)\n"
+    "    GetFieldAsString(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  double arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsInteger" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_4(arg1,arg2,arg3);
+    result = (int)OGRFeatureShadow_GetFieldAsInteger__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12633,45 +12397,37 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_4(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_5(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  double arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsInteger" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -12681,7 +12437,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_5(PyObject *SWIGUNUSEDPARM(sel
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_5(arg1,(char const *)arg2,arg3);
+    result = (int)OGRFeatureShadow_GetFieldAsInteger__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12689,7 +12445,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_5(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
@@ -12698,96 +12454,82 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_6(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_GetFieldAsInteger__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_GetFieldAsInteger__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsInteger'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldAsInteger(OGRFeatureShadow *,int)\n"
+    "    GetFieldAsInteger(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger64__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   int arg2 ;
-  int arg3 ;
-  int arg4 ;
-  int arg5 ;
-  int arg6 ;
-  int arg7 ;
-  int arg8 ;
-  int arg9 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
-  int val5 ;
-  int ecode5 = 0 ;
-  int val6 ;
-  int ecode6 = 0 ;
-  int val7 ;
-  int ecode7 = 0 ;
-  int val8 ;
-  int ecode8 = 0 ;
-  int val9 ;
-  int ecode9 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
+  GIntBig result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOOOOOOO:Feature_SetField",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger64",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger64" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsInteger64" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Feature_SetField" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
-  ecode5 = SWIG_AsVal_int(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Feature_SetField" "', argument " "5"" of type '" "int""'");
-  } 
-  arg5 = static_cast< int >(val5);
-  ecode6 = SWIG_AsVal_int(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Feature_SetField" "', argument " "6"" of type '" "int""'");
-  } 
-  arg6 = static_cast< int >(val6);
-  ecode7 = SWIG_AsVal_int(obj6, &val7);
-  if (!SWIG_IsOK(ecode7)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Feature_SetField" "', argument " "7"" of type '" "int""'");
-  } 
-  arg7 = static_cast< int >(val7);
-  ecode8 = SWIG_AsVal_int(obj7, &val8);
-  if (!SWIG_IsOK(ecode8)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature_SetField" "', argument " "8"" of type '" "int""'");
-  } 
-  arg8 = static_cast< int >(val8);
-  ecode9 = SWIG_AsVal_int(obj8, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Feature_SetField" "', argument " "9"" of type '" "int""'");
-  } 
-  arg9 = static_cast< int >(val9);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_6(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    result = OGRFeatureShadow_GetFieldAsInteger64__SWIG_0(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12795,99 +12537,45 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_6(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, result);
+#if PY_VERSION_HEX>=0x03000000
+    resultobj = PyLong_FromString(szTmp, NULL, 10);
+#else
+    resultobj = PyInt_FromString(szTmp, NULL, 10);
+#endif
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_7(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger64__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
   char *arg2 = (char *) 0 ;
-  int arg3 ;
-  int arg4 ;
-  int arg5 ;
-  int arg6 ;
-  int arg7 ;
-  int arg8 ;
-  int arg9 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int res2 ;
   char *buf2 = 0 ;
   int alloc2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
-  int val5 ;
-  int ecode5 = 0 ;
-  int val6 ;
-  int ecode6 = 0 ;
-  int val7 ;
-  int ecode7 = 0 ;
-  int val8 ;
-  int ecode8 = 0 ;
-  int val9 ;
-  int ecode9 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
+  GIntBig result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOOOOOOO:Feature_SetField",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger64",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger64" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsInteger64" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  ecode4 = SWIG_AsVal_int(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Feature_SetField" "', argument " "4"" of type '" "int""'");
-  } 
-  arg4 = static_cast< int >(val4);
-  ecode5 = SWIG_AsVal_int(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Feature_SetField" "', argument " "5"" of type '" "int""'");
-  } 
-  arg5 = static_cast< int >(val5);
-  ecode6 = SWIG_AsVal_int(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Feature_SetField" "', argument " "6"" of type '" "int""'");
-  } 
-  arg6 = static_cast< int >(val6);
-  ecode7 = SWIG_AsVal_int(obj6, &val7);
-  if (!SWIG_IsOK(ecode7)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Feature_SetField" "', argument " "7"" of type '" "int""'");
-  } 
-  arg7 = static_cast< int >(val7);
-  ecode8 = SWIG_AsVal_int(obj7, &val8);
-  if (!SWIG_IsOK(ecode8)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature_SetField" "', argument " "8"" of type '" "int""'");
-  } 
-  arg8 = static_cast< int >(val8);
-  ecode9 = SWIG_AsVal_int(obj8, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Feature_SetField" "', argument " "9"" of type '" "int""'");
-  } 
-  arg9 = static_cast< int >(val9);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -12897,7 +12585,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_7(PyObject *SWIGUNUSEDPARM(sel
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetField__SWIG_7(arg1,(char const *)arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    result = OGRFeatureShadow_GetFieldAsInteger64__SWIG_1(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -12905,7 +12593,15 @@ SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_7(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, result);
+#if PY_VERSION_HEX>=0x03000000
+    resultobj = PyLong_FromString(szTmp, NULL, 10);
+#else
+    resultobj = PyInt_FromString(szTmp, NULL, 10);
+#endif
+  }
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
@@ -12914,17 +12610,17 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetField(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger64(PyObject *self, PyObject *args) {
   int argc;
-  PyObject *argv[10];
+  PyObject *argv[3];
   int ii;
   
   if (!PyTuple_Check(args)) SWIG_fail;
   argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 9); ii++) {
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
     argv[ii] = PyTuple_GET_ITEM(args,ii);
   }
-  if (argc == 3) {
+  if (argc == 2) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
@@ -12935,95 +12631,151 @@ SWIGINTERN PyObject *_wrap_Feature_SetField(PyObject *self, PyObject *args) {
         _v = SWIG_CheckState(res);
       }
       if (_v) {
-        {
-          int res = SWIG_AsVal_int(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_2(self, args);
-        }
+        return _wrap_Feature_GetFieldAsInteger64__SWIG_0(self, args);
       }
     }
   }
-  if (argc == 3) {
+  if (argc == 2) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
     _v = SWIG_CheckState(res);
     if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
       if (_v) {
-        {
-          int res = SWIG_AsVal_double(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_4(self, args);
-        }
+        return _wrap_Feature_GetFieldAsInteger64__SWIG_1(self, args);
       }
     }
   }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_0(self, args);
-        }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsInteger64'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldAsInteger64(OGRFeatureShadow *,int)\n"
+    "    GetFieldAsInteger64(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  double result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDouble",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (double)OGRFeatureShadow_GetFieldAsDouble__SWIG_0(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        {
-          int res = SWIG_AsVal_int(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_3(self, args);
-        }
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  double result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDouble",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDouble" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsDouble" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (double)OGRFeatureShadow_GetFieldAsDouble__SWIG_1(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  if (argc == 3) {
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDouble(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
     _v = SWIG_CheckState(res);
     if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
       if (_v) {
-        {
-          int res = SWIG_AsVal_double(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_5(self, args);
-        }
+        return _wrap_Feature_GetFieldAsDouble__SWIG_0(self, args);
       }
     }
   }
-  if (argc == 3) {
+  if (argc == 2) {
     int _v;
     void *vptr = 0;
     int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
@@ -13032,64 +12784,1833 @@ SWIGINTERN PyObject *_wrap_Feature_SetField(PyObject *self, PyObject *args) {
       int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
       _v = SWIG_CheckState(res);
       if (_v) {
-        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetField__SWIG_1(self, args);
-        }
+        return _wrap_Feature_GetFieldAsDouble__SWIG_1(self, args);
       }
     }
   }
-  if (argc == 9) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        {
-          int res = SWIG_AsVal_int(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          {
-            int res = SWIG_AsVal_int(argv[3], NULL);
-            _v = SWIG_CheckState(res);
-          }
-          if (_v) {
-            {
-              int res = SWIG_AsVal_int(argv[4], NULL);
-              _v = SWIG_CheckState(res);
-            }
-            if (_v) {
-              {
-                int res = SWIG_AsVal_int(argv[5], NULL);
-                _v = SWIG_CheckState(res);
-              }
-              if (_v) {
-                {
-                  int res = SWIG_AsVal_int(argv[6], NULL);
-                  _v = SWIG_CheckState(res);
-                }
-                if (_v) {
-                  {
-                    int res = SWIG_AsVal_int(argv[7], NULL);
-                    _v = SWIG_CheckState(res);
-                  }
-                  if (_v) {
-                    {
-                      int res = SWIG_AsVal_int(argv[8], NULL);
-                      _v = SWIG_CheckState(res);
-                    }
-                    if (_v) {
-                      return _wrap_Feature_SetField__SWIG_6(self, args);
-                    }
-                  }
-                }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsDouble'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldAsDouble(OGRFeatureShadow *,int)\n"
+    "    GetFieldAsDouble(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDateTime(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  int *arg4 = (int *) 0 ;
+  int *arg5 = (int *) 0 ;
+  int *arg6 = (int *) 0 ;
+  int *arg7 = (int *) 0 ;
+  float *arg8 = (float *) 0 ;
+  int *arg9 = (int *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int temp3 ;
+  int res3 = SWIG_TMPOBJ ;
+  int temp4 ;
+  int res4 = SWIG_TMPOBJ ;
+  int temp5 ;
+  int res5 = SWIG_TMPOBJ ;
+  int temp6 ;
+  int res6 = SWIG_TMPOBJ ;
+  int temp7 ;
+  int res7 = SWIG_TMPOBJ ;
+  float temp8 ;
+  int res8 = SWIG_TMPOBJ ;
+  int temp9 ;
+  int res9 = SWIG_TMPOBJ ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  arg3 = &temp3;
+  arg4 = &temp4;
+  arg5 = &temp5;
+  arg6 = &temp6;
+  arg7 = &temp7;
+  arg8 = &temp8;
+  arg9 = &temp9;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDateTime",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDateTime" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDateTime" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_GetFieldAsDateTime(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (SWIG_IsTmpObj(res3)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg3)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res3) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg3), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res4)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg4)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res4) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg4), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res5)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg5)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res5) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg5), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res6)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg6)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res6) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg6), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res7)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg7)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res7) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg7), SWIGTYPE_p_int, new_flags));
+  }
+  if (SWIG_IsTmpObj(res8)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_float((*arg8)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res8) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg8), SWIGTYPE_p_float, new_flags));
+  }
+  if (SWIG_IsTmpObj(res9)) {
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_From_int((*arg9)));
+  } else {
+    int new_flags = SWIG_IsNewObj(res9) ? (SWIG_POINTER_OWN |  0 ) :  0 ;
+    resultobj = SWIG_Python_AppendOutput(resultobj, SWIG_NewPointerObj((void*)(arg9), SWIGTYPE_p_int, new_flags));
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsIntegerList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  int **arg4 = (int **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int nLen3 ;
+  int *pList3 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  {
+    /* %typemap(in,numinputs=0) (int *nLen3, const int **pList3) (int nLen3, int *pList3) */
+    arg3 = &nLen3;
+    arg4 = &pList3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsIntegerList",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsIntegerList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsIntegerList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_GetFieldAsIntegerList(arg1,arg2,arg3,(int const **)arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (int *nLen, const int **pList ) */
+    Py_DECREF(resultobj);
+    PyObject *out = PyList_New( *arg3 );
+    for( int i=0; i<*arg3; i++ ) {
+      PyObject *val = PyInt_FromLong( (*arg4)[i] );
+      PyList_SetItem( out, i, val );
+    }
+    resultobj = out;
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsInteger64List(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  GIntBig **arg4 = (GIntBig **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int nLen3 ;
+  GIntBig *pList3 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  {
+    /* %typemap(in,numinputs=0) (int *nLen3, const GIntBig **pList3) (int nLen3, GIntBig *pList3) */
+    arg3 = &nLen3;
+    arg4 = &pList3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsInteger64List",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsInteger64List" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsInteger64List" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_GetFieldAsInteger64List(arg1,arg2,arg3,(GIntBig const **)arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (int *nLen, const GIntBig **pList ) */
+    Py_DECREF(resultobj);
+    PyObject *out = PyList_New( *arg3 );
+    for( int i=0; i<*arg3; i++ ) {
+      char szTmp[32];
+      sprintf(szTmp, CPL_FRMT_GIB, (*arg4)[i]);
+      PyObject* val;
+#if PY_VERSION_HEX>=0x03000000
+      val = PyLong_FromString(szTmp, NULL, 10);
+#else
+      val = PyInt_FromString(szTmp, NULL, 10);
+#endif
+      PyList_SetItem( out, i, val );
+    }
+    resultobj = out;
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsDoubleList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  double **arg4 = (double **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int nLen3 ;
+  double *pList3 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  {
+    /* %typemap(in,numinputs=0) (int *nLen3, const double **pList3) (int nLen3, double *pList3) */
+    arg3 = &nLen3;
+    arg4 = &pList3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsDoubleList",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsDoubleList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsDoubleList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_GetFieldAsDoubleList(arg1,arg2,arg3,(double const **)arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (int *nLen, const double **pList ) */
+    Py_DECREF(resultobj);
+    PyObject *out = PyList_New( *arg3 );
+    for( int i=0; i<*arg3; i++ ) {
+      PyObject *val = PyFloat_FromDouble( (*arg4)[i] );
+      PyList_SetItem( out, i, val );
+    }
+    resultobj = out;
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsStringList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  char **result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsStringList",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsStringList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsStringList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (char **)OGRFeatureShadow_GetFieldAsStringList(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) char **options -> ( string ) */
+    char **stringarray = result;
+    if ( stringarray == NULL ) {
+      resultobj = Py_None;
+      Py_INCREF( resultobj );
+    }
+    else {
+      int len = CSLCount( stringarray );
+      resultobj = PyList_New( len );
+      for ( int i = 0; i < len; ++i ) {
+        PyObject *o = GDALPythonObjectFromCStr( stringarray[i] );
+        PyList_SetItem(resultobj, i, o );
+      }
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsBinary__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int *arg3 = (int *) 0 ;
+  char **arg4 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int nLen3 = 0 ;
+  char *pBuf3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  {
+    /* %typemap(in,numinputs=0) (int *nLen3, char **pBuf3 ) */
+    arg3 = &nLen3;
+    arg4 = &pBuf3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsBinary",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsBinary" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldAsBinary" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_GetFieldAsBinary__SWIG_0(arg1,arg2,arg3,arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (int *nLen, char **pBuf ) */
+    Py_XDECREF(resultobj);
+#if PY_VERSION_HEX >= 0x03000000
+    resultobj = PyBytes_FromStringAndSize( *arg4, *arg3 );
+#else
+    resultobj = PyString_FromStringAndSize( *arg4, *arg3 );
+#endif
+  }
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg3 ) {
+      free( *arg4 );
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg3 ) {
+      free( *arg4 );
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsBinary__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  int *arg3 = (int *) 0 ;
+  char **arg4 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int nLen3 = 0 ;
+  char *pBuf3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  {
+    /* %typemap(in,numinputs=0) (int *nLen3, char **pBuf3 ) */
+    arg3 = &nLen3;
+    arg4 = &pBuf3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldAsBinary",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldAsBinary" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldAsBinary" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_GetFieldAsBinary__SWIG_1(arg1,(char const *)arg2,arg3,arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (int *nLen, char **pBuf ) */
+    Py_XDECREF(resultobj);
+#if PY_VERSION_HEX >= 0x03000000
+    resultobj = PyBytes_FromStringAndSize( *arg4, *arg3 );
+#else
+    resultobj = PyString_FromStringAndSize( *arg4, *arg3 );
+#endif
+  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg3 ) {
+      free( *arg4 );
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg3 ) {
+      free( *arg4 );
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldAsBinary(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_GetFieldAsBinary__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_GetFieldAsBinary__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldAsBinary'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldAsBinary(OGRFeatureShadow *,int,int *,char **)\n"
+    "    GetFieldAsBinary(OGRFeatureShadow *,char const *,int *,char **)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_IsFieldSet__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_IsFieldSet",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_IsFieldSet" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_IsFieldSet" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (bool)OGRFeatureShadow_IsFieldSet__SWIG_0(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_IsFieldSet__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_IsFieldSet",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_IsFieldSet" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_IsFieldSet" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (bool)OGRFeatureShadow_IsFieldSet__SWIG_1(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_IsFieldSet(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_IsFieldSet__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_IsFieldSet__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_IsFieldSet'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    IsFieldSet(OGRFeatureShadow *,int)\n"
+    "    IsFieldSet(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldIndex" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldIndex" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureShadow_GetFieldIndex(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetGeomFieldIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetGeomFieldIndex" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetGeomFieldIndex" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureShadow_GetGeomFieldIndex(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFID(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  GIntBig result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetFID",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFID" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = OGRFeatureShadow_GetFID(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    char szTmp[32];
+    sprintf(szTmp, CPL_FRMT_GIB, result);
+#if PY_VERSION_HEX>=0x03000000
+    resultobj = PyLong_FromString(szTmp, NULL, 10);
+#else
+    resultobj = PyInt_FromString(szTmp, NULL, 10);
+#endif
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFID(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  GIntBig arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetFID",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFID" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(obj1,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      SWIG_fail;
+    }
+    arg2 = (GIntBig)val;
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_SetFID(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_DumpReadable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_DumpReadable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_DumpReadable" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_DumpReadable(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_UnsetField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_UnsetField",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_UnsetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_UnsetField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_UnsetField__SWIG_0(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_UnsetField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_UnsetField",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_UnsetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_UnsetField" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_UnsetField__SWIG_1(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_UnsetField(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_UnsetField__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_UnsetField__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_UnsetField'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    UnsetField(OGRFeatureShadow *,int)\n"
+    "    UnsetField(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  char *arg3 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject *str3 = 0 ;
+  int bToFree3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in) (tostring argin) */
+    str3 = PyObject_Str( obj2 );
+    if ( str3 == 0 ) {
+      PyErr_SetString( PyExc_RuntimeError, "Unable to format argument as string");
+      SWIG_fail;
+    }
+    
+    arg3 = GDALPythonObjectToCStr(str3, &bToFree3); 
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_0(arg1,arg2,(char const *)arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (tostring argin) */
+    if ( str3 != NULL)
+    {
+      Py_DECREF(str3);
+    }
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (tostring argin) */
+    if ( str3 != NULL)
+    {
+      Py_DECREF(str3);
+    }
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  char *arg3 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject *str3 = 0 ;
+  int bToFree3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    /* %typemap(in) (tostring argin) */
+    str3 = PyObject_Str( obj2 );
+    if ( str3 == 0 ) {
+      PyErr_SetString( PyExc_RuntimeError, "Unable to format argument as string");
+      SWIG_fail;
+    }
+    
+    arg3 = GDALPythonObjectToCStr(str3, &bToFree3); 
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_1(arg1,(char const *)arg2,(char const *)arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (tostring argin) */
+    if ( str3 != NULL)
+    {
+      Py_DECREF(str3);
+    }
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (tostring argin) */
+    if ( str3 != NULL)
+    {
+      Py_DECREF(str3);
+    }
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldInteger64(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  GIntBig arg3 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldInteger64",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldInteger64" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldInteger64" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    PY_LONG_LONG val;
+    if ( !PyArg_Parse(obj2,"L",&val) ) {
+      PyErr_SetString(PyExc_TypeError, "not an integer");
+      SWIG_fail;
+    }
+    arg3 = (GIntBig)val;
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldInteger64(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_2(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  double arg3 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_2(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_3(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  double arg3 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetField",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_3(arg1,(char const *)arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_4(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  int arg6 ;
+  int arg7 ;
+  float arg8 ;
+  int arg9 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
+  int val7 ;
+  int ecode7 = 0 ;
+  float val8 ;
+  int ecode8 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOOOOOOOO:Feature_SetField",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Feature_SetField" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Feature_SetField" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
+  ecode6 = SWIG_AsVal_int(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Feature_SetField" "', argument " "6"" of type '" "int""'");
+  } 
+  arg6 = static_cast< int >(val6);
+  ecode7 = SWIG_AsVal_int(obj6, &val7);
+  if (!SWIG_IsOK(ecode7)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Feature_SetField" "', argument " "7"" of type '" "int""'");
+  } 
+  arg7 = static_cast< int >(val7);
+  ecode8 = SWIG_AsVal_float(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature_SetField" "', argument " "8"" of type '" "float""'");
+  } 
+  arg8 = static_cast< float >(val8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Feature_SetField" "', argument " "9"" of type '" "int""'");
+  } 
+  arg9 = static_cast< int >(val9);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_4(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField__SWIG_5(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  int arg3 ;
+  int arg4 ;
+  int arg5 ;
+  int arg6 ;
+  int arg7 ;
+  float arg8 ;
+  int arg9 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
+  int val5 ;
+  int ecode5 = 0 ;
+  int val6 ;
+  int ecode6 = 0 ;
+  int val7 ;
+  int ecode7 = 0 ;
+  float val8 ;
+  int ecode8 = 0 ;
+  int val9 ;
+  int ecode9 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOOOOOOOO:Feature_SetField",&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetField" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetField" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetField" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  ecode4 = SWIG_AsVal_int(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Feature_SetField" "', argument " "4"" of type '" "int""'");
+  } 
+  arg4 = static_cast< int >(val4);
+  ecode5 = SWIG_AsVal_int(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Feature_SetField" "', argument " "5"" of type '" "int""'");
+  } 
+  arg5 = static_cast< int >(val5);
+  ecode6 = SWIG_AsVal_int(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "Feature_SetField" "', argument " "6"" of type '" "int""'");
+  } 
+  arg6 = static_cast< int >(val6);
+  ecode7 = SWIG_AsVal_int(obj6, &val7);
+  if (!SWIG_IsOK(ecode7)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "Feature_SetField" "', argument " "7"" of type '" "int""'");
+  } 
+  arg7 = static_cast< int >(val7);
+  ecode8 = SWIG_AsVal_float(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "Feature_SetField" "', argument " "8"" of type '" "float""'");
+  } 
+  arg8 = static_cast< float >(val8);
+  ecode9 = SWIG_AsVal_int(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "Feature_SetField" "', argument " "9"" of type '" "int""'");
+  } 
+  arg9 = static_cast< int >(val9);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetField__SWIG_5(arg1,(char const *)arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetField(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[10];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 9); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        {
+          int res = SWIG_AsVal_double(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          return _wrap_Feature_SetField__SWIG_2(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetField__SWIG_0(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        {
+          int res = SWIG_AsVal_double(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          return _wrap_Feature_SetField__SWIG_3(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetField__SWIG_1(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 9) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        {
+          int res = SWIG_AsVal_int(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          {
+            int res = SWIG_AsVal_int(argv[3], NULL);
+            _v = SWIG_CheckState(res);
+          }
+          if (_v) {
+            {
+              int res = SWIG_AsVal_int(argv[4], NULL);
+              _v = SWIG_CheckState(res);
+            }
+            if (_v) {
+              {
+                int res = SWIG_AsVal_int(argv[5], NULL);
+                _v = SWIG_CheckState(res);
+              }
+              if (_v) {
+                {
+                  int res = SWIG_AsVal_int(argv[6], NULL);
+                  _v = SWIG_CheckState(res);
+                }
+                if (_v) {
+                  {
+                    int res = SWIG_AsVal_float(argv[7], NULL);
+                    _v = SWIG_CheckState(res);
+                  }
+                  if (_v) {
+                    {
+                      int res = SWIG_AsVal_int(argv[8], NULL);
+                      _v = SWIG_CheckState(res);
+                    }
+                    if (_v) {
+                      return _wrap_Feature_SetField__SWIG_4(self, args);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  if (argc == 9) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        {
+          int res = SWIG_AsVal_int(argv[2], NULL);
+          _v = SWIG_CheckState(res);
+        }
+        if (_v) {
+          {
+            int res = SWIG_AsVal_int(argv[3], NULL);
+            _v = SWIG_CheckState(res);
+          }
+          if (_v) {
+            {
+              int res = SWIG_AsVal_int(argv[4], NULL);
+              _v = SWIG_CheckState(res);
+            }
+            if (_v) {
+              {
+                int res = SWIG_AsVal_int(argv[5], NULL);
+                _v = SWIG_CheckState(res);
+              }
+              if (_v) {
+                {
+                  int res = SWIG_AsVal_int(argv[6], NULL);
+                  _v = SWIG_CheckState(res);
+                }
+                if (_v) {
+                  {
+                    int res = SWIG_AsVal_float(argv[7], NULL);
+                    _v = SWIG_CheckState(res);
+                  }
+                  if (_v) {
+                    {
+                      int res = SWIG_AsVal_int(argv[8], NULL);
+                      _v = SWIG_CheckState(res);
+                    }
+                    if (_v) {
+                      return _wrap_Feature_SetField__SWIG_5(self, args);
+                    }
+                  }
+                }
               }
             }
           }
@@ -13097,126 +14618,1520 @@ SWIGINTERN PyObject *_wrap_Feature_SetField(PyObject *self, PyObject *args) {
       }
     }
   }
-  if (argc == 9) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        {
-          int res = SWIG_AsVal_int(argv[2], NULL);
-          _v = SWIG_CheckState(res);
-        }
-        if (_v) {
-          {
-            int res = SWIG_AsVal_int(argv[3], NULL);
-            _v = SWIG_CheckState(res);
-          }
-          if (_v) {
-            {
-              int res = SWIG_AsVal_int(argv[4], NULL);
-              _v = SWIG_CheckState(res);
-            }
-            if (_v) {
-              {
-                int res = SWIG_AsVal_int(argv[5], NULL);
-                _v = SWIG_CheckState(res);
-              }
-              if (_v) {
-                {
-                  int res = SWIG_AsVal_int(argv[6], NULL);
-                  _v = SWIG_CheckState(res);
-                }
-                if (_v) {
-                  {
-                    int res = SWIG_AsVal_int(argv[7], NULL);
-                    _v = SWIG_CheckState(res);
-                  }
-                  if (_v) {
-                    {
-                      int res = SWIG_AsVal_int(argv[8], NULL);
-                      _v = SWIG_CheckState(res);
-                    }
-                    if (_v) {
-                      return _wrap_Feature_SetField__SWIG_7(self, args);
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetField'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetField(OGRFeatureShadow *,int,char const *)\n"
+    "    SetField(OGRFeatureShadow *,char const *,char const *)\n"
+    "    SetField(OGRFeatureShadow *,int,double)\n"
+    "    SetField(OGRFeatureShadow *,char const *,double)\n"
+    "    SetField(OGRFeatureShadow *,int,int,int,int,int,int,float,int)\n"
+    "    SetField(OGRFeatureShadow *,char const *,int,int,int,int,int,float,int)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldIntegerList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int arg3 ;
+  int *arg4 = (int *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldIntegerList",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldIntegerList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldIntegerList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj2) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg3 = PySequence_Size(obj2);
+    arg4 = (int*) malloc(arg3*sizeof(int));
+    for( int i = 0; i<arg3; i++ ) {
+      PyObject *o = PySequence_GetItem(obj2,i);
+      if ( !PyArg_Parse(o,"i",&arg4[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      Py_DECREF(o);
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldIntegerList(arg1,arg2,arg3,arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldInteger64List(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int arg3 ;
+  GIntBig *arg4 = (GIntBig *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldInteger64List",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldInteger64List" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldInteger64List" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in,numinputs=1) (int nList, GIntBig* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj2) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg3 = PySequence_Size(obj2);
+    arg4 = (GIntBig*) malloc(arg3*sizeof(GIntBig));
+    for( int i = 0; i<arg3; i++ ) {
+      PyObject *o = PySequence_GetItem(obj2,i);
+      PY_LONG_LONG val;
+      if ( !PyArg_Parse(o,"L",&val) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      arg4[i] = (GIntBig)val;
+      Py_DECREF(o);
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldInteger64List(arg1,arg2,arg3,arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (int nList, GIntBig* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (int nList, GIntBig* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldDoubleList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  int arg3 ;
+  double *arg4 = (double *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldDoubleList",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldDoubleList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldDoubleList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in,numinputs=1) (int nList, double* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj2) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg3 = PySequence_Size(obj2);
+    arg4 = (double*) malloc(arg3*sizeof(double));
+    for( int i = 0; i<arg3; i++ ) {
+      PyObject *o = PySequence_GetItem(obj2,i);
+      if ( !PyArg_Parse(o,"d",&arg4[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not a number");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      Py_DECREF(o);
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldDoubleList(arg1,arg2,arg3,arg4);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (int nList, double* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (int nList, double* pList) */
+    if (arg4) {
+      free((void*) arg4);
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldStringList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  char **arg3 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldStringList",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldStringList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldStringList" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in) char **options */
+    /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+    if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+      || PyString_Check(obj2)
+  #endif
+      ) {
+      PyErr_SetString(PyExc_TypeError,"not a sequence");
+      SWIG_fail;
+    }
+    
+    int size = PySequence_Size(obj2);
+    for (int i = 0; i < size; i++) {
+      PyObject* pyObj = PySequence_GetItem(obj2,i);
+      if (PyUnicode_Check(pyObj))
+      {
+        char *pszStr;
+        Py_ssize_t nLen;
+        PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+        PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+        PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+        arg3 = CSLAddString( arg3, pszStr );
+        Py_XDECREF(pyUTF8Str);
+      }
+#if PY_VERSION_HEX >= 0x03000000
+      else if (PyBytes_Check(pyObj))
+      arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+      else if (PyString_Check(pyObj))
+      arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+      else
+      {
+        Py_DECREF(pyObj);
+        PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+        SWIG_fail;
+      }
+      Py_DECREF(pyObj);
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldStringList(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  char *arg3 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldBinaryFromHexString",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "3"" of type '" "char const *""'");
+  }
+  arg3 = reinterpret_cast< char * >(buf3);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldBinaryFromHexString__SWIG_0(arg1,arg2,(char const *)arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  return resultobj;
+fail:
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  char *arg3 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int res3 ;
+  char *buf3 = 0 ;
+  int alloc3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldBinaryFromHexString",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
+  if (!SWIG_IsOK(res3)) {
+    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "3"" of type '" "char const *""'");
+  }
+  arg3 = reinterpret_cast< char * >(buf3);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldBinaryFromHexString__SWIG_1(arg1,(char const *)arg2,(char const *)arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[4];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetFieldBinaryFromHexString__SWIG_0(self, args);
+        }
+      }
+    }
+  }
+  if (argc == 3) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
+        _v = SWIG_CheckState(res);
+        if (_v) {
+          return _wrap_Feature_SetFieldBinaryFromHexString__SWIG_1(self, args);
+        }
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetFieldBinaryFromHexString'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    SetFieldBinaryFromHexString(OGRFeatureShadow *,int,char const *)\n"
+    "    SetFieldBinaryFromHexString(OGRFeatureShadow *,char const *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFrom(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
+  int arg3 = (int) 1 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "other",(char *) "forgiving", NULL 
+  };
+  OGRErr result;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Feature_SetFrom",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFrom" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFrom" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetFrom" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_SetFrom(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFromWithMap(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
+  int arg3 ;
+  int arg4 ;
+  int *arg5 = (int *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOOO:Feature_SetFromWithMap",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFromWithMap" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFromWithMap" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
+  ecode3 = SWIG_AsVal_int(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetFromWithMap" "', argument " "3"" of type '" "int""'");
+  } 
+  arg3 = static_cast< int >(val3);
+  {
+    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
+    /* check if is List */
+    if ( !PySequence_Check(obj3) ) {
+      PyErr_SetString(PyExc_TypeError, "not a sequence");
+      SWIG_fail;
+    }
+    arg4 = PySequence_Size(obj3);
+    arg5 = (int*) malloc(arg4*sizeof(int));
+    for( int i = 0; i<arg4; i++ ) {
+      PyObject *o = PySequence_GetItem(obj3,i);
+      if ( !PyArg_Parse(o,"i",&arg5[i]) ) {
+        PyErr_SetString(PyExc_TypeError, "not an integer");
+        Py_DECREF(o);
+        SWIG_fail;
+      }
+      Py_DECREF(o);
+    }
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRFeatureShadow_SetFromWithMap(arg1,arg2,arg3,arg4,arg5);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg5) {
+      free((void*) arg5);
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (int nList, int* pList) */
+    if (arg5) {
+      free((void*) arg5);
+    }
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetStyleString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  char *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetStyleString",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetStyleString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (char *)OGRFeatureShadow_GetStyleString(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetStyleString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetStyleString",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetStyleString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetStyleString" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetStyleString(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRFieldType result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldType" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRFieldType)OGRFeatureShadow_GetFieldType__SWIG_0(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRFieldType result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldType" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRFieldType)OGRFeatureShadow_GetFieldType__SWIG_1(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_GetFieldType(PyObject *self, PyObject *args) {
+  int argc;
+  PyObject *argv[3];
+  int ii;
+  
+  if (!PyTuple_Check(args)) SWIG_fail;
+  argc = (int)PyObject_Length(args);
+  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
+    argv[ii] = PyTuple_GET_ITEM(args,ii);
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      {
+        int res = SWIG_AsVal_int(argv[1], NULL);
+        _v = SWIG_CheckState(res);
+      }
+      if (_v) {
+        return _wrap_Feature_GetFieldType__SWIG_0(self, args);
+      }
+    }
+  }
+  if (argc == 2) {
+    int _v;
+    void *vptr = 0;
+    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
+    _v = SWIG_CheckState(res);
+    if (_v) {
+      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
+      _v = SWIG_CheckState(res);
+      if (_v) {
+        return _wrap_Feature_GetFieldType__SWIG_1(self, args);
+      }
+    }
+  }
+  
+fail:
+  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldType'.\n"
+    "  Possible C/C++ prototypes are:\n"
+    "    GetFieldType(OGRFeatureShadow *,int)\n"
+    "    GetFieldType(OGRFeatureShadow *,char const *)\n");
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_Validate(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 = (int) OGR_F_VAL_ALL ;
+  int arg3 = (int) TRUE ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O|OO:Feature_Validate",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_Validate" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_Validate" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_Validate" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureShadow_Validate(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_FillUnsetWithDefault(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 = (int) FALSE ;
+  char **arg3 = (char **) NULL ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O|OO:Feature_FillUnsetWithDefault",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_FillUnsetWithDefault" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_FillUnsetWithDefault" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_FillUnsetWithDefault(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Feature_SetFieldString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  int arg2 ;
+  char *arg3 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int bToFree3 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldString",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldString" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    /* %typemap(in) (const char *utf8_path) */
+    arg3 = GDALPythonObjectToCStr( obj2, &bToFree3 );
+    if (arg3 == NULL)
+    {
+      PyErr_SetString( PyExc_RuntimeError, "not a string" );
+      SWIG_fail;
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureShadow_SetFieldString(arg1,arg2,(char const *)arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return resultobj;
+fail:
+  {
+    /* %typemap(freearg) (const char *utf8_path) */
+    GDALPythonFreeCStr(arg3, bToFree3);
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *Feature_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFeatureShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_delete_FeatureDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_FeatureDefn",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FeatureDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    delete_OGRFeatureDefnShadow(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_new_FeatureDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+  PyObject *resultobj = 0;
+  char *arg1 = (char *) NULL ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
+  PyObject * obj0 = 0 ;
+  char *  kwnames[] = {
+    (char *) "name_null_ok", NULL 
+  };
+  OGRFeatureDefnShadow *result = 0 ;
+  
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|O:new_FeatureDefn",kwnames,&obj0)) SWIG_fail;
+  if (obj0) {
+    res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FeatureDefn" "', argument " "1"" of type '" "char const *""'");
+    }
+    arg1 = reinterpret_cast< char * >(buf1);
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRFeatureDefnShadow *)new_OGRFeatureDefnShadow((char const *)arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_NEW |  0 );
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  return resultobj;
+fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  char *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetName" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (char *)OGRFeatureDefnShadow_GetName(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetFieldCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureDefnShadow_GetFieldCount(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  int arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRFieldDefnShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetFieldDefn",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_GetFieldDefn" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRFieldDefnShadow *)OGRFeatureDefnShadow_GetFieldDefn(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetFieldIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldIndex" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_GetFieldIndex" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureDefnShadow_GetFieldIndex(arg1,(char const *)arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_AddFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg2 = (OGRFieldDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_AddFieldDefn",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_AddFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_AddFieldDefn" "', argument " "2"" of type '" "OGRFieldDefnShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRFieldDefnShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureDefnShadow_AddFieldDefn(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
   
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetGeomFieldCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureDefnShadow_GetGeomFieldCount(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetField'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetField(OGRFeatureShadow *,int,char const *)\n"
-    "    SetField(OGRFeatureShadow *,char const *,char const *)\n"
-    "    SetField(OGRFeatureShadow *,int,int)\n"
-    "    SetField(OGRFeatureShadow *,char const *,int)\n"
-    "    SetField(OGRFeatureShadow *,int,double)\n"
-    "    SetField(OGRFeatureShadow *,char const *,double)\n"
-    "    SetField(OGRFeatureShadow *,int,int,int,int,int,int,int,int)\n"
-    "    SetField(OGRFeatureShadow *,char const *,int,int,int,int,int,int,int)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldIntegerList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
   int arg2 ;
-  int arg3 ;
-  int *arg4 = (int *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  OGRGeomFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldIntegerList",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldIntegerList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldIntegerList" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_GetGeomFieldDefn" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj2) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg3 = PySequence_Size(obj2);
-    arg4 = (int*) malloc(arg3*sizeof(int));
-    for( int i = 0; i<arg3; i++ ) {
-      PyObject *o = PySequence_GetItem(obj2,i);
-      if ( !PyArg_Parse(o,"i",&arg4[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not an integer");
-        Py_DECREF(o);
-        SWIG_fail;
+    result = (OGRGeomFieldDefnShadow *)OGRFeatureDefnShadow_GetGeomFieldDefn(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-      Py_DECREF(o);
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetGeomFieldIndex",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldIndex" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_GetGeomFieldIndex" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetFieldIntegerList(arg1,arg2,arg3,arg4);
+    result = (int)OGRFeatureDefnShadow_GetGeomFieldIndex(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13224,74 +16139,138 @@ SWIGINTERN PyObject *_wrap_Feature_SetFieldIntegerList(PyObject *SWIGUNUSEDPARM(
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return resultobj;
+fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_AddGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg2 = (OGRGeomFieldDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_AddGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_AddGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_AddGeomFieldDefn" "', argument " "2"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp2);
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg4) {
-      free((void*) arg4);
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
-  return resultobj;
-fail:
   {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg4) {
-      free((void*) arg4);
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRFeatureDefnShadow_AddGeomFieldDefn(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldDoubleList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_DeleteGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
   int arg2 ;
-  int arg3 ;
-  double *arg4 = (double *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldDoubleList",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_DeleteGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldDoubleList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_DeleteGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldDoubleList" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_DeleteGeomFieldDefn" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
-    /* %typemap(in,numinputs=1) (int nList, double* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj2) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg3 = PySequence_Size(obj2);
-    arg4 = (double*) malloc(arg3*sizeof(double));
-    for( int i = 0; i<arg3; i++ ) {
-      PyObject *o = PySequence_GetItem(obj2,i);
-      if ( !PyArg_Parse(o,"d",&arg4[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not a number");
-        Py_DECREF(o);
-        SWIG_fail;
+    result = (OGRErr)OGRFeatureDefnShadow_DeleteGeomFieldDefn(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-      Py_DECREF(o);
     }
   }
   {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRwkbGeometryType result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetGeomType",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomType" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetFieldDoubleList(arg1,arg2,arg3,arg4);
+    result = (OGRwkbGeometryType)OGRFeatureDefnShadow_GetGeomType(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13299,98 +16278,73 @@ SWIGINTERN PyObject *_wrap_Feature_SetFieldDoubleList(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(freearg) (int nList, double* pList) */
-    if (arg4) {
-      free((void*) arg4);
-    }
-  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int nList, double* pList) */
-    if (arg4) {
-      free((void*) arg4);
-    }
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldStringList(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  char **arg3 = (char **) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRwkbGeometryType arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldStringList",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetGeomType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldStringList" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetGeomType" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldStringList" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetGeomType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
   } 
-  arg2 = static_cast< int >(val2);
+  arg2 = static_cast< OGRwkbGeometryType >(val2);
   {
-    /* %typemap(in) char **options */
-    /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-    if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
-  #if PY_VERSION_HEX < 0x03000000
-      || PyString_Check(obj2)
-  #endif
-      ) {
-      PyErr_SetString(PyExc_TypeError,"not a sequence");
-      SWIG_fail;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    
-    int size = PySequence_Size(obj2);
-    for (int i = 0; i < size; i++) {
-      PyObject* pyObj = PySequence_GetItem(obj2,i);
-      if (PyUnicode_Check(pyObj))
-      {
-        char *pszStr;
-        Py_ssize_t nLen;
-        PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-        PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-        PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-        arg3 = CSLAddString( arg3, pszStr );
-        Py_XDECREF(pyUTF8Str);
-      }
-#if PY_VERSION_HEX >= 0x03000000
-      else if (PyBytes_Check(pyObj))
-      arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
-#else
-      else if (PyString_Check(pyObj))
-      arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
-#endif
-      else
-      {
-        Py_DECREF(pyObj);
-        PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-        SWIG_fail;
+    OGRFeatureDefnShadow_SetGeomType(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-      Py_DECREF(pyObj);
     }
   }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_FeatureDefn_GetReferenceCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetReferenceCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetReferenceCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetFieldStringList(arg1,arg2,arg3);
+    result = (int)OGRFeatureDefnShadow_GetReferenceCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13398,58 +16352,32 @@ SWIGINTERN PyObject *_wrap_Feature_SetFieldStringList(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
-  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg3 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_IsGeometryIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
-  char *arg3 = (char *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  int res3 ;
-  char *buf3 = 0 ;
-  int alloc3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldBinaryFromHexString",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_IsGeometryIgnored",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "3"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsGeometryIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg3 = reinterpret_cast< char * >(buf3);
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetFieldBinaryFromHexString__SWIG_0(arg1,arg2,(char const *)arg3);
+    result = (int)OGRFeatureDefnShadow_IsGeometryIgnored(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13457,58 +16385,40 @@ SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_0(PyObject
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeometryIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  int res3 ;
-  char *buf3 = 0 ;
-  int alloc3 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Feature_SetFieldBinaryFromHexString",&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetGeometryIgnored",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "Feature_SetFieldBinaryFromHexString" "', argument " "3"" of type '" "char const *""'");
-  }
-  arg3 = reinterpret_cast< char * >(buf3);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetGeometryIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetGeometryIgnored" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetFieldBinaryFromHexString__SWIG_1(arg1,(char const *)arg2,(char const *)arg3);
+    OGRFeatureDefnShadow_SetGeometryIgnored(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13517,119 +16427,72 @@ SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString__SWIG_1(PyObject
     }
   }
   resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFieldBinaryFromHexString(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[4];
-  int ii;
+SWIGINTERN PyObject *_wrap_FeatureDefn_IsStyleIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
   
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 3); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetFieldBinaryFromHexString__SWIG_0(self, args);
-        }
-      }
-    }
-  }
-  if (argc == 3) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        int res = SWIG_AsCharPtrAndSize(argv[2], 0, NULL, 0);
-        _v = SWIG_CheckState(res);
-        if (_v) {
-          return _wrap_Feature_SetFieldBinaryFromHexString__SWIG_1(self, args);
-        }
+  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_IsStyleIgnored",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsStyleIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRFeatureDefnShadow_IsStyleIgnored(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
     }
   }
-  
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
 fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_SetFieldBinaryFromHexString'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    SetFieldBinaryFromHexString(OGRFeatureShadow *,int,char const *)\n"
-    "    SetFieldBinaryFromHexString(OGRFeatureShadow *,char const *,char const *)\n");
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFrom(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_SetStyleIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
-  int arg3 = (int) 1 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "other",(char *) "forgiving", NULL 
-  };
-  OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Feature_SetFrom",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetStyleIgnored",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFrom" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFrom" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetFrom" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetStyleIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetStyleIgnored" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetFrom(arg1,arg2,arg3);
+    OGRFeatureDefnShadow_SetStyleIgnored(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13637,83 +16500,36 @@ SWIGINTERN PyObject *_wrap_Feature_SetFrom(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetFromWithMap(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FeatureDefn_IsSame(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  OGRFeatureShadow *arg2 = (OGRFeatureShadow *) 0 ;
-  int arg3 ;
-  int arg4 ;
-  int *arg5 = (int *) 0 ;
+  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFeatureDefnShadow *arg2 = (OGRFeatureDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  OGRErr result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOO:Feature_SetFromWithMap",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_IsSame",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetFromWithMap" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsSame" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetFromWithMap" "', argument " "2"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFeatureShadow * >(argp2);
-  ecode3 = SWIG_AsVal_int(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Feature_SetFromWithMap" "', argument " "3"" of type '" "int""'");
-  } 
-  arg3 = static_cast< int >(val3);
-  {
-    /* %typemap(in,numinputs=1) (int nList, int* pList)*/
-    /* check if is List */
-    if ( !PySequence_Check(obj3) ) {
-      PyErr_SetString(PyExc_TypeError, "not a sequence");
-      SWIG_fail;
-    }
-    arg4 = PySequence_Size(obj3);
-    arg5 = (int*) malloc(arg4*sizeof(int));
-    for( int i = 0; i<arg4; i++ ) {
-      PyObject *o = PySequence_GetItem(obj3,i);
-      if ( !PyArg_Parse(o,"i",&arg5[i]) ) {
-        PyErr_SetString(PyExc_TypeError, "not an integer");
-        Py_DECREF(o);
-        SWIG_fail;
-      }
-      Py_DECREF(o);
-    }
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_IsSame" "', argument " "2"" of type '" "OGRFeatureDefnShadow *""'"); 
   }
+  arg2 = reinterpret_cast< OGRFeatureDefnShadow * >(argp2);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -13723,7 +16539,7 @@ SWIGINTERN PyObject *_wrap_Feature_SetFromWithMap(PyObject *SWIGUNUSEDPARM(self)
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureShadow_SetFromWithMap(arg1,arg2,arg3,arg4,arg5);
+    result = (int)OGRFeatureDefnShadow_IsSame(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13731,60 +16547,88 @@ SWIGINTERN PyObject *_wrap_Feature_SetFromWithMap(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg5) {
-      free((void*) arg5);
-    }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *FeatureDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_delete_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_FieldDefn",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FieldDefn" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
+    delete_OGRFieldDefnShadow(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int nList, int* pList) */
-    if (arg5) {
-      free((void*) arg5);
-    }
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetStyleString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  char *arg1 = (char *) "unnamed" ;
+  OGRFieldType arg2 = (OGRFieldType) OFTString ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "name_null_ok",(char *) "field_type", NULL 
+  };
+  OGRFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Feature_GetStyleString",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetStyleString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OO:new_FieldDefn",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (obj0) {
+    res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+    if (!SWIG_IsOK(res1)) {
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FieldDefn" "', argument " "1"" of type '" "char const *""'");
+    }
+    arg1 = reinterpret_cast< char * >(buf1);
+  }
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_FieldDefn" "', argument " "2"" of type '" "OGRFieldType""'");
+    } 
+    arg2 = static_cast< OGRFieldType >(val2);
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFeatureShadow_GetStyleString(arg1);
+    result = (OGRFieldDefnShadow *)new_OGRFieldDefnShadow((char const *)arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13792,41 +16636,34 @@ SWIGINTERN PyObject *_wrap_Feature_GetStyleString(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, SWIG_POINTER_NEW |  0 );
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return resultobj;
 fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_SetStyleString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_SetStyleString",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  char *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_SetStyleString" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_SetStyleString" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg2 = reinterpret_cast< char * >(buf2);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureShadow_SetStyleString(arg1,(char const *)arg2);
+    result = (char *)OGRFieldDefnShadow_GetName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13834,43 +16671,32 @@ SWIGINTERN PyObject *_wrap_Feature_SetStyleString(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_0(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetNameRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
-  int arg2 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRFieldType result;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldType",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetNameRef",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Feature_GetFieldType" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldType)OGRFeatureShadow_GetFieldType__SWIG_0(arg1,arg2);
+    result = (char *)OGRFieldDefnShadow_GetNameRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13878,16 +16704,16 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_0(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_1(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureShadow *arg1 = (OGRFeatureShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -13896,17 +16722,16 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_1(PyObject *SWIGUNUSEDPARM
   int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRFieldType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Feature_GetFieldType",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetName",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Feature_GetFieldType" "', argument " "1"" of type '" "OGRFeatureShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Feature_GetFieldType" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FieldDefn_SetName" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
   {
@@ -13918,7 +16743,7 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_1(PyObject *SWIGUNUSEDPARM
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldType)OGRFeatureShadow_GetFieldType__SWIG_1(arg1,(char const *)arg2);
+    OGRFieldDefnShadow_SetName(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -13926,7 +16751,7 @@ SWIGINTERN PyObject *_wrap_Feature_GetFieldType__SWIG_1(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
   if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
@@ -13935,118 +16760,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Feature_GetFieldType(PyObject *self, PyObject *args) {
-  int argc;
-  PyObject *argv[3];
-  int ii;
-  
-  if (!PyTuple_Check(args)) SWIG_fail;
-  argc = (int)PyObject_Length(args);
-  for (ii = 0; (ii < argc) && (ii < 2); ii++) {
-    argv[ii] = PyTuple_GET_ITEM(args,ii);
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_int(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_Feature_GetFieldType__SWIG_0(self, args);
-      }
-    }
-  }
-  if (argc == 2) {
-    int _v;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_OGRFeatureShadow, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      int res = SWIG_AsCharPtrAndSize(argv[1], 0, NULL, 0);
-      _v = SWIG_CheckState(res);
-      if (_v) {
-        return _wrap_Feature_GetFieldType__SWIG_1(self, args);
-      }
-    }
-  }
-  
-fail:
-  SWIG_SetErrorMsg(PyExc_NotImplementedError,"Wrong number of arguments for overloaded function 'Feature_GetFieldType'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    GetFieldType(OGRFeatureShadow *,int)\n"
-    "    GetFieldType(OGRFeatureShadow *,char const *)\n");
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *Feature_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFeatureShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_delete_FeatureDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  OGRFieldType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_FeatureDefn",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetType",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FeatureDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  {
-    if ( bUseExceptions ) {
-      CPLErrorReset();
-    }
-    delete_OGRFeatureDefnShadow(arg1);
-    if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_Py_Void();
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_new_FeatureDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
-  PyObject *resultobj = 0;
-  char *arg1 = (char *) NULL ;
-  int res1 ;
-  char *buf1 = 0 ;
-  int alloc1 = 0 ;
-  PyObject * obj0 = 0 ;
-  char *  kwnames[] = {
-    (char *) "name_null_ok", NULL 
-  };
-  OGRFeatureDefnShadow *result = 0 ;
-  
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|O:new_FeatureDefn",kwnames,&obj0)) SWIG_fail;
-  if (obj0) {
-    res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FeatureDefn" "', argument " "1"" of type '" "char const *""'");
-    }
-    arg1 = reinterpret_cast< char * >(buf1);
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFeatureDefnShadow *)new_OGRFeatureDefnShadow((char const *)arg1);
+    result = (OGRFieldType)OGRFieldDefnShadow_GetType(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14054,34 +16786,40 @@ SWIGINTERN PyObject *_wrap_new_FeatureDefn(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_POINTER_NEW |  0 );
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldType arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetName" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetType" "', argument " "2"" of type '" "OGRFieldType""'");
+  } 
+  arg2 = static_cast< OGRFieldType >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFeatureDefnShadow_GetName(arg1);
+    OGRFieldDefnShadow_SetType(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14089,32 +16827,32 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetName(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetSubType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  OGRFieldSubType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetFieldCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetSubType",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetSubType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_GetFieldCount(arg1);
+    result = (OGRFieldSubType)OGRFieldDefnShadow_GetSubType(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14129,34 +16867,33 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetSubType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  int arg2 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldSubType arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetFieldDefn",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetSubType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetSubType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_GetFieldDefn" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetSubType" "', argument " "2"" of type '" "OGRFieldSubType""'");
   } 
-  arg2 = static_cast< int >(val2);
+  arg2 = static_cast< OGRFieldSubType >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldDefnShadow *)OGRFeatureDefnShadow_GetFieldDefn(arg1,arg2);
+    OGRFieldDefnShadow_SetSubType(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14164,47 +16901,32 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldDefn(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetJustify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  int result;
+  OGRJustification result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetFieldIndex",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetFieldIndex" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_GetFieldIndex" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetJustify",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_GetFieldIndex(arg1,(char const *)arg2);
+    result = (OGRJustification)OGRFieldDefnShadow_GetJustify(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14213,46 +16935,39 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetFieldIndex(PyObject *SWIGUNUSEDPARM(se
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_AddFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetJustify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  OGRFieldDefnShadow *arg2 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRJustification arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_AddFieldDefn",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetJustify",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_AddFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_AddFieldDefn" "', argument " "2"" of type '" "OGRFieldDefnShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFieldDefnShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetJustify" "', argument " "2"" of type '" "OGRJustification""'");
+  } 
+  arg2 = static_cast< OGRJustification >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureDefnShadow_AddFieldDefn(arg1,arg2);
+    OGRFieldDefnShadow_SetJustify(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14267,25 +16982,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetWidth(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetGeomFieldCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetWidth",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_GetGeomFieldCount(arg1);
+    result = (int)OGRFieldDefnShadow_GetWidth(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14300,9 +17015,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetWidth(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -14310,24 +17025,23 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldDefn(PyObject *SWIGUNUSEDPARM
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeomFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetWidth",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_GetGeomFieldDefn" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetWidth" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeomFieldDefnShadow *)OGRFeatureDefnShadow_GetGeomFieldDefn(arg1,arg2);
+    OGRFieldDefnShadow_SetWidth(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14335,47 +17049,32 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldDefn(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldIndex(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetPrecision(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_GetGeomFieldIndex",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetPrecision",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomFieldIndex" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_GetGeomFieldIndex" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_GetGeomFieldIndex(arg1,(char const *)arg2);
+    result = (int)OGRFieldDefnShadow_GetPrecision(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14384,46 +17083,39 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomFieldIndex(PyObject *SWIGUNUSEDPAR
     }
   }
   resultobj = SWIG_From_int(static_cast< int >(result));
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_AddGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetPrecision(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  OGRGeomFieldDefnShadow *arg2 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_AddGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetPrecision",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_AddGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_AddGeomFieldDefn" "', argument " "2"" of type '" "OGRGeomFieldDefnShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetPrecision" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureDefnShadow_AddGeomFieldDefn(arg1,arg2);
+    OGRFieldDefnShadow_SetPrecision(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14438,34 +17130,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_DeleteGeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  int arg2 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRErr result;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_DeleteGeomFieldDefn",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetTypeName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_DeleteGeomFieldDefn" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_DeleteGeomFieldDefn" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRFeatureDefnShadow_DeleteGeomFieldDefn(arg1,arg2);
+    result = (char *)OGRFieldDefnShadow_GetTypeName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14473,48 +17156,41 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_DeleteGeomFieldDefn(PyObject *SWIGUNUSEDP
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRFieldType arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRwkbGeometryType result;
+  PyObject * obj1 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetGeomType",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_GetFieldTypeName",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetGeomType" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "2"" of type '" "OGRFieldType""'");
+  } 
+  arg2 = static_cast< OGRFieldType >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRwkbGeometryType)OGRFeatureDefnShadow_GetGeomType(arg1);
+    result = (char *)OGRFieldDefnShadow_GetFieldTypeName(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14522,40 +17198,32 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetGeomType(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeomType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  OGRwkbGeometryType arg2 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetGeomType",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_IsIgnored",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetGeomType" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetGeomType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
-  } 
-  arg2 = static_cast< OGRwkbGeometryType >(val2);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureDefnShadow_SetGeomType(arg1,arg2);
+    result = (int)OGRFieldDefnShadow_IsIgnored(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14563,32 +17231,40 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeomType(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_GetReferenceCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_GetReferenceCount",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetIgnored",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_GetReferenceCount" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_GetReferenceCount(arg1);
+    OGRFieldDefnShadow_SetIgnored(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14596,32 +17272,32 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_GetReferenceCount(PyObject *SWIGUNUSEDPAR
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_IsGeometryIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_IsNullable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_IsGeometryIgnored",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_IsNullable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsGeometryIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsNullable" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_IsGeometryIgnored(arg1);
+    result = (int)OGRFieldDefnShadow_IsNullable(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14636,9 +17312,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeometryIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetNullable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -14647,22 +17323,22 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_SetGeometryIgnored(PyObject *SWIGUNUSEDPA
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetGeometryIgnored",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetNullable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetGeometryIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetNullable" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetGeometryIgnored" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetNullable" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureDefnShadow_SetGeometryIgnored(arg1,arg2);
+    OGRFieldDefnShadow_SetNullable(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14677,25 +17353,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_IsStyleIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_GetDefault(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FeatureDefn_IsStyleIgnored",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetDefault",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsStyleIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetDefault" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_IsStyleIgnored(arg1);
+    result = (char *)OGRFieldDefnShadow_GetDefault(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14703,40 +17379,41 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_IsStyleIgnored(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_SetStyleIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_SetDefault(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  int arg2 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_SetStyleIgnored",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetDefault",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_SetStyleIgnored" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetDefault" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FeatureDefn_SetStyleIgnored" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FieldDefn_SetDefault" "', argument " "2"" of type '" "char const *""'");
+  }
+  arg2 = reinterpret_cast< char * >(buf2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFeatureDefnShadow_SetStyleIgnored(arg1,arg2);
+    OGRFieldDefnShadow_SetDefault(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14745,45 +17422,33 @@ SWIGINTERN PyObject *_wrap_FeatureDefn_SetStyleIgnored(PyObject *SWIGUNUSEDPARM(
     }
   }
   resultobj = SWIG_Py_Void();
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FeatureDefn_IsSame(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_FieldDefn_IsDefaultDriverSpecific(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFeatureDefnShadow *arg1 = (OGRFeatureDefnShadow *) 0 ;
-  OGRFeatureDefnShadow *arg2 = (OGRFeatureDefnShadow *) 0 ;
+  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FeatureDefn_IsSame",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_IsDefaultDriverSpecific",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FeatureDefn_IsSame" "', argument " "1"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFeatureDefnShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRFeatureDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FeatureDefn_IsSame" "', argument " "2"" of type '" "OGRFeatureDefnShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRFeatureDefnShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsDefaultDriverSpecific" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFeatureDefnShadow_IsSame(arg1,arg2);
+    result = (int)OGRFieldDefnShadow_IsDefaultDriverSpecific(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14798,31 +17463,31 @@ fail:
 }
 
 
-SWIGINTERN PyObject *FeatureDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *FieldDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *obj;
   if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFeatureDefnShadow, SWIG_NewClientData(obj));
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFieldDefnShadow, SWIG_NewClientData(obj));
   return SWIG_Py_Void();
 }
 
-SWIGINTERN PyObject *_wrap_delete_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_FieldDefn",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_GeomFieldDefn",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_FieldDefn" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_GeomFieldDefn" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRFieldDefnShadow(arg1);
+    delete_OGRGeomFieldDefnShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14837,10 +17502,10 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_new_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_new_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  char *arg1 = (char *) "unnamed" ;
-  OGRFieldType arg2 = (OGRFieldType) OFTString ;
+  char *arg1 = (char *) "" ;
+  OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
   int res1 ;
   char *buf1 = 0 ;
   int alloc1 = 0 ;
@@ -14851,28 +17516,28 @@ SWIGINTERN PyObject *_wrap_new_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObjec
   char *  kwnames[] = {
     (char *) "name_null_ok",(char *) "field_type", NULL 
   };
-  OGRFieldDefnShadow *result = 0 ;
+  OGRGeomFieldDefnShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OO:new_FieldDefn",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OO:new_GeomFieldDefn",kwnames,&obj0,&obj1)) SWIG_fail;
   if (obj0) {
     res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
     if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_FieldDefn" "', argument " "1"" of type '" "char const *""'");
+      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_GeomFieldDefn" "', argument " "1"" of type '" "char const *""'");
     }
     arg1 = reinterpret_cast< char * >(buf1);
   }
   if (obj1) {
     ecode2 = SWIG_AsVal_int(obj1, &val2);
     if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_FieldDefn" "', argument " "2"" of type '" "OGRFieldType""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_GeomFieldDefn" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
     } 
-    arg2 = static_cast< OGRFieldType >(val2);
+    arg2 = static_cast< OGRwkbGeometryType >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldDefnShadow *)new_OGRFieldDefnShadow((char const *)arg1,arg2);
+    result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14880,7 +17545,7 @@ SWIGINTERN PyObject *_wrap_new_FieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRFieldDefnShadow, SWIG_POINTER_NEW |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_NEW |  0 );
   if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return resultobj;
 fail:
@@ -14889,25 +17554,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetName",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFieldDefnShadow_GetName(arg1);
+    result = (char *)OGRGeomFieldDefnShadow_GetName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14922,25 +17587,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetNameRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetNameRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetNameRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetNameRef",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFieldDefnShadow_GetNameRef(arg1);
+    result = (char *)OGRGeomFieldDefnShadow_GetNameRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -14955,9 +17620,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   char *arg2 = (char *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -14967,15 +17632,15 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyO
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetName",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetName",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "FieldDefn_SetName" "', argument " "2"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetName" "', argument " "2"" of type '" "char const *""'");
   }
   arg2 = reinterpret_cast< char * >(buf2);
   {
@@ -14987,7 +17652,7 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyO
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetName(arg1,(char const *)arg2);
+    OGRGeomFieldDefnShadow_SetName(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15004,25 +17669,99 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRwkbGeometryType result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetType",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRwkbGeometryType)OGRGeomFieldDefnShadow_GetType(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRwkbGeometryType arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetType",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg2 = static_cast< OGRwkbGeometryType >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    OGRGeomFieldDefnShadow_SetType(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRFieldType result;
+  OSRSpatialReferenceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetType",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetSpatialRef",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRFieldType)OGRFieldDefnShadow_GetType(arg1);
+    result = (OSRSpatialReferenceShadow *)OGRGeomFieldDefnShadow_GetSpatialRef(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15030,40 +17769,40 @@ SWIGINTERN PyObject *_wrap_FieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  OGRFieldType arg2 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetType",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetSpatialRef",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetType" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetType" "', argument " "2"" of type '" "OGRFieldType""'");
-  } 
-  arg2 = static_cast< OGRFieldType >(val2);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetType(arg1,arg2);
+    OGRGeomFieldDefnShadow_SetSpatialRef(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15078,25 +17817,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetJustify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRJustification result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetJustify",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_IsIgnored",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRJustification)OGRFieldDefnShadow_GetJustify(arg1);
+    result = (int)OGRGeomFieldDefnShadow_IsIgnored(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15111,10 +17850,10 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetJustify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  OGRJustification arg2 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   int val2 ;
@@ -15122,22 +17861,22 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetJustify(PyObject *SWIGUNUSEDPARM(self),
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetJustify",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetIgnored",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetJustify" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetJustify" "', argument " "2"" of type '" "OGRJustification""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
   } 
-  arg2 = static_cast< OGRJustification >(val2);
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetJustify(arg1,arg2);
+    OGRGeomFieldDefnShadow_SetIgnored(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15152,25 +17891,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetWidth(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_IsNullable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetWidth",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_IsNullable",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsNullable" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFieldDefnShadow_GetWidth(arg1);
+    result = (int)OGRGeomFieldDefnShadow_IsNullable(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15185,9 +17924,9 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetWidth(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetNullable(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
   int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
@@ -15196,22 +17935,22 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetWidth(PyObject *SWIGUNUSEDPARM(self), Py
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetWidth",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetNullable",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetWidth" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetNullable" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetWidth" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetNullable" "', argument " "2"" of type '" "int""'");
   } 
   arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetWidth(arg1,arg2);
+    OGRGeomFieldDefnShadow_SetNullable(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15226,25 +17965,80 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetPrecision(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *GeomFieldDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_CreateGeometryFromWkb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  int arg1 ;
+  char *arg2 = (char *) 0 ;
+  OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
+  int alloc1 = 0 ;
+  void *argp3 = 0 ;
+  int res3 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "len",(char *) "reference", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetPrecision",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:CreateGeometryFromWkb",kwnames,&obj0,&obj1)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
+#if PY_VERSION_HEX>=0x03000000
+    if (PyUnicode_Check(obj0))
+    {
+      size_t safeLen = 0;
+      int ret = SWIG_AsCharPtrAndSize(obj0, (char**) &arg2, &safeLen, &alloc1);
+      if (!SWIG_IsOK(ret)) {
+        SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
+      }
+      
+      if (safeLen) safeLen--;
+      arg1 = (int) safeLen;
+    }
+    else if (PyBytes_Check(obj0))
+    {
+      Py_ssize_t safeLen = 0;
+      PyBytes_AsStringAndSize(obj0, (char**) &arg2, &safeLen);
+      arg1 = (int) safeLen;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
+      SWIG_fail;
+    }
+#else
+    if (PyString_Check(obj0))
+    {
+      Py_ssize_t safeLen = 0;
+      PyString_AsStringAndSize(obj0, (char**) &arg2, &safeLen);
+      arg1 = (int) safeLen;
+    }
+    else
+    {
+      PyErr_SetString(PyExc_TypeError, "not a string");
+      SWIG_fail;
+    }
+#endif
+  }
+  if (obj1) {
+    res3 = SWIG_ConvertPtr(obj1, &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res3)) {
+      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CreateGeometryFromWkb" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    }
+    arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFieldDefnShadow_GetPrecision(arg1);
+    result = (OGRGeometryShadow *)CreateGeometryFromWkb(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15252,40 +18046,60 @@ SWIGINTERN PyObject *_wrap_FieldDefn_GetPrecision(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) (int *nLen, char *pBuf ) */
+    if( alloc1 == SWIG_NEWOBJ ) {
+      delete[] arg2;
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (int *nLen, char *pBuf ) */
+    if( alloc1 == SWIG_NEWOBJ ) {
+      delete[] arg2;
+    }
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetPrecision(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_CreateGeometryFromWkt(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  char **arg1 = (char **) 0 ;
+  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) NULL ;
+  char *val1 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "val",(char *) "reference", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetPrecision",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetPrecision" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:CreateGeometryFromWkt",kwnames,&obj0,&obj1)) SWIG_fail;
+  {
+    /* %typemap(in) (char **ignorechange) */
+    if( !PyArg_Parse( obj0, "s", &val1 ) ) {
+      PyErr_SetString( PyExc_TypeError, "not a string" );
+      SWIG_fail;
+    }
+    arg1 = &val1;
+  }
+  if (obj1) {
+    res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CreateGeometryFromWkt" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    }
+    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetPrecision" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetPrecision(arg1,arg2);
+    result = (OGRGeometryShadow *)CreateGeometryFromWkt(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15293,32 +18107,33 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetPrecision(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_CreateGeometryFromGML(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  char *arg1 = (char *) 0 ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_GetTypeName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:CreateGeometryFromGML",&obj0)) SWIG_fail;
+  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromGML" "', argument " "1"" of type '" "char const *""'");
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< char * >(buf1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFieldDefnShadow_GetTypeName(arg1);
+    result = (OGRGeometryShadow *)CreateGeometryFromGML((char const *)arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15326,41 +18141,35 @@ SWIGINTERN PyObject *_wrap_FieldDefn_GetTypeName(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return resultobj;
 fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_CreateGeometryFromJson(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  OGRFieldType arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  char *arg1 = (char *) 0 ;
+  int res1 ;
+  char *buf1 = 0 ;
+  int alloc1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_GetFieldTypeName",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:CreateGeometryFromJson",&obj0)) SWIG_fail;
+  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromJson" "', argument " "1"" of type '" "char const *""'");
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_GetFieldTypeName" "', argument " "2"" of type '" "OGRFieldType""'");
-  } 
-  arg2 = static_cast< OGRFieldType >(val2);
+  arg1 = reinterpret_cast< char * >(buf1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRFieldDefnShadow_GetFieldTypeName(arg1,arg2);
+    result = (OGRGeometryShadow *)CreateGeometryFromJson((char const *)arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15368,32 +18177,70 @@ SWIGINTERN PyObject *_wrap_FieldDefn_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(s
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return resultobj;
 fail:
+  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_BuildPolygonFromEdges(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  int arg2 = (int) 0 ;
+  int arg3 = (int) 0 ;
+  double arg4 = (double) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "hLineCollection",(char *) "bBestEffort",(char *) "bAutoClose",(char *) "dfTolerance", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:FieldDefn_IsIgnored",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOO:BuildPolygonFromEdges",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BuildPolygonFromEdges" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "BuildPolygonFromEdges" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
+  }
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "BuildPolygonFromEdges" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
+  }
+  if (obj3) {
+    ecode4 = SWIG_AsVal_double(obj3, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "BuildPolygonFromEdges" "', argument " "4"" of type '" "double""'");
+    } 
+    arg4 = static_cast< double >(val4);
   }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRFieldDefnShadow_IsIgnored(arg1);
+    result = (OGRGeometryShadow *)BuildPolygonFromEdges(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15401,40 +18248,107 @@ SWIGINTERN PyObject *_wrap_FieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_FieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ApproximateArcAngles(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRFieldDefnShadow *arg1 = (OGRFieldDefnShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  int val2 ;
+  double arg1 ;
+  double arg2 ;
+  double arg3 ;
+  double arg4 ;
+  double arg5 ;
+  double arg6 ;
+  double arg7 ;
+  double arg8 ;
+  double arg9 ;
+  double val1 ;
+  int ecode1 = 0 ;
+  double val2 ;
   int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
+  int ecode4 = 0 ;
+  double val5 ;
+  int ecode5 = 0 ;
+  double val6 ;
+  int ecode6 = 0 ;
+  double val7 ;
+  int ecode7 = 0 ;
+  double val8 ;
+  int ecode8 = 0 ;
+  double val9 ;
+  int ecode9 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  PyObject * obj5 = 0 ;
+  PyObject * obj6 = 0 ;
+  PyObject * obj7 = 0 ;
+  PyObject * obj8 = 0 ;
+  char *  kwnames[] = {
+    (char *) "dfCenterX",(char *) "dfCenterY",(char *) "dfZ",(char *) "dfPrimaryRadius",(char *) "dfSecondaryAxis",(char *) "dfRotation",(char *) "dfStartAngle",(char *) "dfEndAngle",(char *) "dfMaxAngleStepSizeDegrees", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:FieldDefn_SetIgnored",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRFieldDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOO:ApproximateArcAngles",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
+  ecode1 = SWIG_AsVal_double(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ApproximateArcAngles" "', argument " "1"" of type '" "double""'");
+  } 
+  arg1 = static_cast< double >(val1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ApproximateArcAngles" "', argument " "2"" of type '" "double""'");
   } 
-  arg2 = static_cast< int >(val2);
+  arg2 = static_cast< double >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ApproximateArcAngles" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  ecode4 = SWIG_AsVal_double(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "ApproximateArcAngles" "', argument " "4"" of type '" "double""'");
+  } 
+  arg4 = static_cast< double >(val4);
+  ecode5 = SWIG_AsVal_double(obj4, &val5);
+  if (!SWIG_IsOK(ecode5)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "ApproximateArcAngles" "', argument " "5"" of type '" "double""'");
+  } 
+  arg5 = static_cast< double >(val5);
+  ecode6 = SWIG_AsVal_double(obj5, &val6);
+  if (!SWIG_IsOK(ecode6)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "ApproximateArcAngles" "', argument " "6"" of type '" "double""'");
+  } 
+  arg6 = static_cast< double >(val6);
+  ecode7 = SWIG_AsVal_double(obj6, &val7);
+  if (!SWIG_IsOK(ecode7)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "ApproximateArcAngles" "', argument " "7"" of type '" "double""'");
+  } 
+  arg7 = static_cast< double >(val7);
+  ecode8 = SWIG_AsVal_double(obj7, &val8);
+  if (!SWIG_IsOK(ecode8)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "ApproximateArcAngles" "', argument " "8"" of type '" "double""'");
+  } 
+  arg8 = static_cast< double >(val8);
+  ecode9 = SWIG_AsVal_double(obj8, &val9);
+  if (!SWIG_IsOK(ecode9)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "ApproximateArcAngles" "', argument " "9"" of type '" "double""'");
+  } 
+  arg9 = static_cast< double >(val9);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRFieldDefnShadow_SetIgnored(arg1,arg2);
+    result = (OGRGeometryShadow *)ApproximateArcAngles(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15442,38 +18356,32 @@ SWIGINTERN PyObject *_wrap_FieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *FieldDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRFieldDefnShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_delete_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ForceToPolygon(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_GeomFieldDefn",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:ForceToPolygon",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_GeomFieldDefn" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRGeomFieldDefnShadow(arg1);
+    result = (OGRGeometryShadow *)ForceToPolygon(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15481,49 +18389,32 @@ SWIGINTERN PyObject *_wrap_delete_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_new_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_ForceToLineString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  char *arg1 = (char *) "" ;
-  OGRwkbGeometryType arg2 = (OGRwkbGeometryType) wkbUnknown ;
-  int res1 ;
-  char *buf1 = 0 ;
-  int alloc1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "name_null_ok",(char *) "field_type", NULL 
-  };
-  OGRGeomFieldDefnShadow *result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OO:new_GeomFieldDefn",kwnames,&obj0,&obj1)) SWIG_fail;
-  if (obj0) {
-    res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
-    if (!SWIG_IsOK(res1)) {
-      SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_GeomFieldDefn" "', argument " "1"" of type '" "char const *""'");
-    }
-    arg1 = reinterpret_cast< char * >(buf1);
-  }
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_GeomFieldDefn" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
-    } 
-    arg2 = static_cast< OGRwkbGeometryType >(val2);
+  if (!PyArg_ParseTuple(args,(char *)"O:ForceToLineString",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeomFieldDefnShadow *)new_OGRGeomFieldDefnShadow((char const *)arg1,arg2);
+    result = (OGRGeometryShadow *)ForceToLineString(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15531,34 +18422,32 @@ SWIGINTERN PyObject *_wrap_new_GeomFieldDefn(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_POINTER_NEW |  0 );
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ForceToMultiPolygon(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetName",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiPolygon",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRGeomFieldDefnShadow_GetName(arg1);
+    result = (OGRGeometryShadow *)ForceToMultiPolygon(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15566,32 +18455,32 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetName(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetNameRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ForceToMultiPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetNameRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiPoint",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetNameRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRGeomFieldDefnShadow_GetNameRef(arg1);
+    result = (OGRGeometryShadow *)ForceToMultiPoint(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15599,46 +18488,32 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetNameRef(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ForceToMultiLineString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetName",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiLineString",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetName" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetName" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeomFieldDefnShadow_SetName(arg1,(char const *)arg2);
+    result = (OGRGeometryShadow *)ForceToMultiLineString(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15646,34 +18521,89 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetName(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_ForceTo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRwkbGeometryType arg2 ;
+  char **arg3 = (char **) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRwkbGeometryType result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetType",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"OO|O:ForceTo",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ForceTo" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg2 = static_cast< OGRwkbGeometryType >(val2);
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRwkbGeometryType)OGRGeomFieldDefnShadow_GetType(arg1);
+    result = (OGRGeometryShadow *)ForceTo(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15681,40 +18611,39 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetType(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_delete_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-  OGRwkbGeometryType arg2 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetType",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:delete_Geometry",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetType" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Geometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetType" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
-  } 
-  arg2 = static_cast< OGRwkbGeometryType >(val2);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeomFieldDefnShadow_SetType(arg1,arg2);
+    delete_OGRGeometryShadow(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15729,25 +18658,99 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_new_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 = (OGRwkbGeometryType) wkbUnknown ;
+  char *arg2 = (char *) 0 ;
+  int arg3 = (int) 0 ;
+  char *arg4 = (char *) 0 ;
+  char *arg5 = (char *) 0 ;
+  int val1 ;
+  int ecode1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
+  int alloc3 = 0 ;
+  int res5 ;
+  char *buf5 = 0 ;
+  int alloc5 = 0 ;
   PyObject * obj0 = 0 ;
-  OSRSpatialReferenceShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "type",(char *) "wkt",(char *) "wkb",(char *) "gml", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_GetSpatialRef",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_GetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OOOO:new_Geometry",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (obj0) {
+    ecode1 = SWIG_AsVal_int(obj0, &val1);
+    if (!SWIG_IsOK(ecode1)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_Geometry" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    } 
+    arg1 = static_cast< OGRwkbGeometryType >(val1);
+  }
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Geometry" "', argument " "2"" of type '" "char *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
+  }
+  if (obj2) {
+    {
+      /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
+#if PY_VERSION_HEX>=0x03000000
+      if (PyUnicode_Check(obj2))
+      {
+        size_t safeLen = 0;
+        int ret = SWIG_AsCharPtrAndSize(obj2, (char**) &arg4, &safeLen, &alloc3);
+        if (!SWIG_IsOK(ret)) {
+          SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
+        }
+        
+        if (safeLen) safeLen--;
+        arg3 = (int) safeLen;
+      }
+      else if (PyBytes_Check(obj2))
+      {
+        Py_ssize_t safeLen = 0;
+        PyBytes_AsStringAndSize(obj2, (char**) &arg4, &safeLen);
+        arg3 = (int) safeLen;
+      }
+      else
+      {
+        PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
+        SWIG_fail;
+      }
+#else
+      if (PyString_Check(obj2))
+      {
+        Py_ssize_t safeLen = 0;
+        PyString_AsStringAndSize(obj2, (char**) &arg4, &safeLen);
+        arg3 = (int) safeLen;
+      }
+      else
+      {
+        PyErr_SetString(PyExc_TypeError, "not a string");
+        SWIG_fail;
+      }
+#endif
+    }
+  }
+  if (obj3) {
+    res5 = SWIG_AsCharPtrAndSize(obj3, &buf5, NULL, &alloc5);
+    if (!SWIG_IsOK(res5)) {
+      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "new_Geometry" "', argument " "5"" of type '" "char *""'");
+    }
+    arg5 = reinterpret_cast< char * >(buf5);
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OSRSpatialReferenceShadow *)OGRGeomFieldDefnShadow_GetSpatialRef(arg1);
+    result = (OGRGeometryShadow *)new_OGRGeometryShadow(arg1,arg2,arg3,arg4,arg5);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15755,40 +18758,54 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_GetSpatialRef(PyObject *SWIGUNUSEDPARM(
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_NEW |  0 );
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int *nLen, char *pBuf ) */
+    if( alloc3 == SWIG_NEWOBJ ) {
+      delete[] arg4;
+    }
+  }
+  if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
   return resultobj;
 fail:
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  {
+    /* %typemap(freearg) (int *nLen, char *pBuf ) */
+    if( alloc3 == SWIG_NEWOBJ ) {
+      delete[] arg4;
+    }
+  }
+  if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetSpatialRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToWkt(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  char *argout2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetSpatialRef",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+  {
+    /* %typemap(in,numinputs=0) (char **argout2) */
+    arg2 = &argout2;
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "GeomFieldDefn_SetSpatialRef" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_ExportToWkt",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeomFieldDefnShadow_SetSpatialRef(arg1,arg2);
+    result = (OGRErr)OGRGeometryShadow_ExportToWkt(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15796,32 +18813,76 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetSpatialRef(PyObject *SWIGUNUSEDPARM(
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (char **argout) */
+    PyObject *o;
+    if ( arg2 != NULL && *arg2 != NULL) {
+      o = GDALPythonObjectFromCStr( *arg2 );
+    }
+    else {
+      o = Py_None;
+      Py_INCREF( o );
+    }
+    resultobj = t_output_helper(resultobj, o);
+  }
+  {
+    /* %typemap(freearg) (char **argout) */
+    if ( *arg2 )
+    CPLFree( *arg2 );
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (char **argout) */
+    if ( *arg2 )
+    CPLFree( *arg2 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToIsoWkt(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  char *argout2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeomFieldDefn_IsIgnored",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  {
+    /* %typemap(in,numinputs=0) (char **argout2) */
+    arg2 = &argout2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_ExportToIsoWkt",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_IsIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToIsoWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeomFieldDefnShadow_IsIgnored(arg1);
+    result = (OGRErr)OGRGeometryShadow_ExportToIsoWkt(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15829,40 +18890,93 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_IsIgnored(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (char **argout) */
+    PyObject *o;
+    if ( arg2 != NULL && *arg2 != NULL) {
+      o = GDALPythonObjectFromCStr( *arg2 );
+    }
+    else {
+      o = Py_None;
+      Py_INCREF( o );
+    }
+    resultobj = t_output_helper(resultobj, o);
+  }
+  {
+    /* %typemap(freearg) (char **argout) */
+    if ( *arg2 )
+    CPLFree( *arg2 );
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) (char **argout) */
+    if ( *arg2 )
+    CPLFree( *arg2 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToWkb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  OGRGeomFieldDefnShadow *arg1 = (OGRGeomFieldDefnShadow *) 0 ;
-  int arg2 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  int *arg2 = (int *) 0 ;
+  char **arg3 = (char **) 0 ;
+  OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  int nLen2 = 0 ;
+  char *pBuf2 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "byte_order", NULL 
+  };
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:GeomFieldDefn_SetIgnored",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeomFieldDefnShadow, 0 |  0 );
+  {
+    /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
+    arg2 = &nLen2;
+    arg3 = &pBuf2;
+  }
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToWkb",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "1"" of type '" "OGRGeomFieldDefnShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (obj1) {
+    ecode4 = SWIG_AsVal_int(obj1, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_ExportToWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+    } 
+    arg4 = static_cast< OGRwkbByteOrder >(val4);
   }
-  arg1 = reinterpret_cast< OGRGeomFieldDefnShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GeomFieldDefn_SetIgnored" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeomFieldDefnShadow_SetIgnored(arg1,arg2);
+    result = (OGRErr)OGRGeometryShadow_ExportToWkb(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15870,87 +18984,92 @@ SWIGINTERN PyObject *_wrap_GeomFieldDefn_SetIgnored(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (int *nLen, char **pBuf ) */
+    Py_XDECREF(resultobj);
+#if PY_VERSION_HEX >= 0x03000000
+    resultobj = PyBytes_FromStringAndSize( *arg3, *arg2 );
+#else
+    resultobj = PyString_FromStringAndSize( *arg3, *arg2 );
+#endif
+  }
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg2 ) {
+      free( *arg3 );
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *GeomFieldDefn_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRGeomFieldDefnShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg2 ) {
+      free( *arg3 );
+    }
+  }
+  return NULL;
 }
 
-SWIGINTERN PyObject *_wrap_CreateGeometryFromWkb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+
+SWIGINTERN PyObject *_wrap_Geometry_ExportToIsoWkb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  int arg1 ;
-  char *arg2 = (char *) 0 ;
-  OSRSpatialReferenceShadow *arg3 = (OSRSpatialReferenceShadow *) NULL ;
-  int alloc1 = 0 ;
-  void *argp3 = 0 ;
-  int res3 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  int *arg2 = (int *) 0 ;
+  char **arg3 = (char **) 0 ;
+  OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int nLen2 = 0 ;
+  char *pBuf2 = 0 ;
+  int val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   char *  kwnames[] = {
-    (char *) "len",(char *) "reference", NULL 
+    (char *) "self",(char *) "byte_order", NULL 
   };
-  OGRGeometryShadow *result = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:CreateGeometryFromWkb",kwnames,&obj0,&obj1)) SWIG_fail;
   {
-    /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
-#if PY_VERSION_HEX>=0x03000000
-    if (PyUnicode_Check(obj0))
-    {
-      size_t safeLen = 0;
-      int ret = SWIG_AsCharPtrAndSize(obj0, (char**) &arg2, &safeLen, &alloc1);
-      if (!SWIG_IsOK(ret)) {
-        SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
-      }
-      
-      if (safeLen) safeLen--;
-      arg1 = (int) safeLen;
-    }
-    else if (PyBytes_Check(obj0))
-    {
-      Py_ssize_t safeLen = 0;
-      PyBytes_AsStringAndSize(obj0, (char**) &arg2, &safeLen);
-      arg1 = (int) safeLen;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
-      SWIG_fail;
-    }
-#else
-    if (PyString_Check(obj0))
-    {
-      Py_ssize_t safeLen = 0;
-      PyString_AsStringAndSize(obj0, (char**) &arg2, &safeLen);
-      arg1 = (int) safeLen;
-    }
-    else
-    {
-      PyErr_SetString(PyExc_TypeError, "not a string");
-      SWIG_fail;
-    }
-#endif
+    /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
+    arg2 = &nLen2;
+    arg3 = &pBuf2;
   }
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToIsoWkb",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToIsoWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    res3 = SWIG_ConvertPtr(obj1, &argp3,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res3)) {
-      SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "CreateGeometryFromWkb" "', argument " "3"" of type '" "OSRSpatialReferenceShadow *""'"); 
-    }
-    arg3 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp3);
+    ecode4 = SWIG_AsVal_int(obj1, &val4);
+    if (!SWIG_IsOK(ecode4)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_ExportToIsoWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+    } 
+    arg4 = static_cast< OGRwkbByteOrder >(val4);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)CreateGeometryFromWkb(arg1,arg2,arg3);
+    result = (OGRErr)OGRGeometryShadow_ExportToIsoWkb(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -15958,60 +19077,120 @@ SWIGINTERN PyObject *_wrap_CreateGeometryFromWkb(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(freearg) (int *nLen, char *pBuf ) */
-    if( alloc1 == SWIG_NEWOBJ ) {
-      delete[] arg2;
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(argout) (int *nLen, char **pBuf ) */
+    Py_XDECREF(resultobj);
+#if PY_VERSION_HEX >= 0x03000000
+    resultobj = PyBytes_FromStringAndSize( *arg3, *arg2 );
+#else
+    resultobj = PyString_FromStringAndSize( *arg3, *arg2 );
+#endif
+  }
+  {
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg2 ) {
+      free( *arg3 );
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
     }
   }
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (int *nLen, char *pBuf ) */
-    if( alloc1 == SWIG_NEWOBJ ) {
-      delete[] arg2;
+    /* %typemap(freearg) (int *nLen, char **pBuf ) */
+    if( *arg2 ) {
+      free( *arg3 );
     }
   }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_CreateGeometryFromWkt(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToGML(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  char **arg1 = (char **) 0 ;
-  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) NULL ;
-  char *val1 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   char *  kwnames[] = {
-    (char *) "val",(char *) "reference", NULL 
+    (char *) "self",(char *) "options", NULL 
   };
-  OGRGeometryShadow *result = 0 ;
+  retStringAndCPLFree *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:CreateGeometryFromWkt",kwnames,&obj0,&obj1)) SWIG_fail;
-  {
-    /* %typemap(in) (char **ignorechange) */
-    if( !PyArg_Parse( obj0, "s", &val1 ) ) {
-      PyErr_SetString( PyExc_TypeError, "not a string" );
-      SWIG_fail;
-    }
-    arg1 = &val1;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToGML",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToGML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "CreateGeometryFromWkt" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj1)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg2 = CSLAddString( arg2, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
     }
-    arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)CreateGeometryFromWkt(arg1,arg2);
+    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToGML(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16019,33 +19198,59 @@ SWIGINTERN PyObject *_wrap_CreateGeometryFromWkt(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      resultobj = GDALPythonObjectFromCStr( (const char *)result);
+      CPLFree(result);
+    }
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_CreateGeometryFromGML(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToKML(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  char *arg1 = (char *) 0 ;
-  int res1 ;
-  char *buf1 = 0 ;
-  int alloc1 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char *arg2 = (char *) NULL ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 ;
+  char *buf2 = 0 ;
+  int alloc2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  retStringAndCPLFree *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:CreateGeometryFromGML",&obj0)) SWIG_fail;
-  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_ExportToKML",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromGML" "', argument " "1"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToKML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (obj1) {
+    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
+    if (!SWIG_IsOK(res2)) {
+      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_ExportToKML" "', argument " "2"" of type '" "char const *""'");
+    }
+    arg2 = reinterpret_cast< char * >(buf2);
   }
-  arg1 = reinterpret_cast< char * >(buf1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)CreateGeometryFromGML((char const *)arg1);
+    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToKML(arg1,(char const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16053,35 +19258,92 @@ SWIGINTERN PyObject *_wrap_CreateGeometryFromGML(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  {
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      resultobj = GDALPythonObjectFromCStr( (const char *)result);
+      CPLFree(result);
+    }
+  }
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return resultobj;
 fail:
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_CreateGeometryFromJson(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ExportToJson(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
-  char *arg1 = (char *) 0 ;
-  int res1 ;
-  char *buf1 = 0 ;
-  int alloc1 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  char **arg2 = (char **) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "options", NULL 
+  };
+  retStringAndCPLFree *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:CreateGeometryFromJson",&obj0)) SWIG_fail;
-  res1 = SWIG_AsCharPtrAndSize(obj0, &buf1, NULL, &alloc1);
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToJson",kwnames,&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "CreateGeometryFromJson" "', argument " "1"" of type '" "char const *""'");
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToJson" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (obj1) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj1)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg2 = CSLAddString( arg2, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
+    }
   }
-  arg1 = reinterpret_cast< char * >(buf1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)CreateGeometryFromJson((char const *)arg1);
+    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToJson(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16089,26 +19351,39 @@ SWIGINTERN PyObject *_wrap_CreateGeometryFromJson(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  {
+    /* %typemap(out) (retStringAndCPLFree*) */
+    if(result)
+    {
+      resultobj = GDALPythonObjectFromCStr( (const char *)result);
+      CPLFree(result);
+    }
+  }
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return resultobj;
 fail:
-  if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_BuildPolygonFromEdges(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_AddPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
-  int arg3 = (int) 0 ;
+  double arg2 ;
+  double arg3 ;
   double arg4 = (double) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
+  double val2 ;
   int ecode2 = 0 ;
-  int val3 ;
+  double val3 ;
   int ecode3 = 0 ;
   double val4 ;
   int ecode4 = 0 ;
@@ -16117,34 +19392,29 @@ SWIGINTERN PyObject *_wrap_BuildPolygonFromEdges(PyObject *SWIGUNUSEDPARM(self),
   PyObject * obj2 = 0 ;
   PyObject * obj3 = 0 ;
   char *  kwnames[] = {
-    (char *) "hLineCollection",(char *) "bBestEffort",(char *) "bAutoClose",(char *) "dfTolerance", NULL 
+    (char *) "self",(char *) "x",(char *) "y",(char *) "z", NULL 
   };
-  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OOO:BuildPolygonFromEdges",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Geometry_AddPoint",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "BuildPolygonFromEdges" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "BuildPolygonFromEdges" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
-  }
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "BuildPolygonFromEdges" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
-  }
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
   if (obj3) {
     ecode4 = SWIG_AsVal_double(obj3, &val4);
     if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "BuildPolygonFromEdges" "', argument " "4"" of type '" "double""'");
+      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_AddPoint" "', argument " "4"" of type '" "double""'");
     } 
     arg4 = static_cast< double >(val4);
   }
@@ -16152,7 +19422,7 @@ SWIGINTERN PyObject *_wrap_BuildPolygonFromEdges(PyObject *SWIGUNUSEDPARM(self),
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)BuildPolygonFromEdges(arg1,arg2,arg3,arg4);
+    OGRGeometryShadow_AddPoint(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16160,107 +19430,94 @@ SWIGINTERN PyObject *_wrap_BuildPolygonFromEdges(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_ApproximateArcAngles(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_AddPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  double arg1 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   double arg2 ;
   double arg3 ;
-  double arg4 ;
-  double arg5 ;
-  double arg6 ;
-  double arg7 ;
-  double arg8 ;
-  double arg9 ;
-  double val1 ;
-  int ecode1 = 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
   double val3 ;
   int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  double val5 ;
-  int ecode5 = 0 ;
-  double val6 ;
-  int ecode6 = 0 ;
-  double val7 ;
-  int ecode7 = 0 ;
-  double val8 ;
-  int ecode8 = 0 ;
-  double val9 ;
-  int ecode9 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  PyObject * obj5 = 0 ;
-  PyObject * obj6 = 0 ;
-  PyObject * obj7 = 0 ;
-  PyObject * obj8 = 0 ;
-  char *  kwnames[] = {
-    (char *) "dfCenterX",(char *) "dfCenterY",(char *) "dfZ",(char *) "dfPrimaryRadius",(char *) "dfSecondaryAxis",(char *) "dfRotation",(char *) "dfStartAngle",(char *) "dfEndAngle",(char *) "dfMaxAngleStepSizeDegrees", NULL 
-  };
-  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOOOOOOO:ApproximateArcAngles",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4,&obj5,&obj6,&obj7,&obj8)) SWIG_fail;
-  ecode1 = SWIG_AsVal_double(obj0, &val1);
-  if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "ApproximateArcAngles" "', argument " "1"" of type '" "double""'");
-  } 
-  arg1 = static_cast< double >(val1);
+  if (!PyArg_ParseTuple(args,(char *)"OOO:Geometry_AddPoint_2D",&obj0,&obj1,&obj2)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   ecode2 = SWIG_AsVal_double(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "ApproximateArcAngles" "', argument " "2"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_2D" "', argument " "2"" of type '" "double""'");
   } 
   arg2 = static_cast< double >(val2);
   ecode3 = SWIG_AsVal_double(obj2, &val3);
   if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ApproximateArcAngles" "', argument " "3"" of type '" "double""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_2D" "', argument " "3"" of type '" "double""'");
   } 
   arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "ApproximateArcAngles" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  ecode5 = SWIG_AsVal_double(obj4, &val5);
-  if (!SWIG_IsOK(ecode5)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "ApproximateArcAngles" "', argument " "5"" of type '" "double""'");
-  } 
-  arg5 = static_cast< double >(val5);
-  ecode6 = SWIG_AsVal_double(obj5, &val6);
-  if (!SWIG_IsOK(ecode6)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "ApproximateArcAngles" "', argument " "6"" of type '" "double""'");
-  } 
-  arg6 = static_cast< double >(val6);
-  ecode7 = SWIG_AsVal_double(obj6, &val7);
-  if (!SWIG_IsOK(ecode7)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode7), "in method '" "ApproximateArcAngles" "', argument " "7"" of type '" "double""'");
-  } 
-  arg7 = static_cast< double >(val7);
-  ecode8 = SWIG_AsVal_double(obj7, &val8);
-  if (!SWIG_IsOK(ecode8)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode8), "in method '" "ApproximateArcAngles" "', argument " "8"" of type '" "double""'");
-  } 
-  arg8 = static_cast< double >(val8);
-  ecode9 = SWIG_AsVal_double(obj8, &val9);
-  if (!SWIG_IsOK(ecode9)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode9), "in method '" "ApproximateArcAngles" "', argument " "9"" of type '" "double""'");
-  } 
-  arg9 = static_cast< double >(val9);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ApproximateArcAngles(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
+    OGRGeometryShadow_AddPoint_2D(arg1,arg2,arg3);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Geometry_AddGeometryDirectly(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  int res2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AddGeometryDirectly",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometryDirectly" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
+  }
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (OGRErr)OGRGeometryShadow_AddGeometryDirectly(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16268,32 +19525,62 @@ SWIGINTERN PyObject *_wrap_ApproximateArcAngles(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_ForceToPolygon(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_AddGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:ForceToPolygon",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AddGeometry",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ForceToPolygon(arg1);
+    result = (OGRErr)OGRGeometryShadow_AddGeometry(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16301,14 +19588,30 @@ SWIGINTERN PyObject *_wrap_ForceToPolygon(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_ForceToLineString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
@@ -16316,17 +19619,17 @@ SWIGINTERN PyObject *_wrap_ForceToLineString(PyObject *SWIGUNUSEDPARM(self), PyO
   PyObject * obj0 = 0 ;
   OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:ForceToLineString",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Clone",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Clone" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ForceToLineString(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Clone(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16341,25 +19644,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_ForceToMultiPolygon(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetGeometryType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiPolygon",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryType",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPolygon" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryType" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ForceToMultiPolygon(arg1);
+    result = (OGRwkbGeometryType)OGRGeometryShadow_GetGeometryType(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16367,32 +19670,32 @@ SWIGINTERN PyObject *_wrap_ForceToMultiPolygon(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_ForceToMultiPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetGeometryName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiPoint",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryName",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryName" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ForceToMultiPoint(arg1);
+    result = (char *)OGRGeometryShadow_GetGeometryName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16400,32 +19703,32 @@ SWIGINTERN PyObject *_wrap_ForceToMultiPoint(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_ForceToMultiLineString(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Length(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:ForceToMultiLineString",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Length",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ForceToMultiLineString" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Length" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)ForceToMultiLineString(arg1);
+    result = (double)OGRGeometryShadow_Length(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16433,31 +19736,32 @@ SWIGINTERN PyObject *_wrap_ForceToMultiLineString(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_delete_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Area(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
+  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:delete_Geometry",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Area",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_Geometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Area" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    delete_OGRGeometryShadow(arg1);
+    result = (double)OGRGeometryShadow_Area(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16465,106 +19769,65 @@ SWIGINTERN PyObject *_wrap_delete_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_new_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_GetArea(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRwkbGeometryType arg1 = (OGRwkbGeometryType) wkbUnknown ;
-  char *arg2 = (char *) 0 ;
-  int arg3 = (int) 0 ;
-  char *arg4 = (char *) 0 ;
-  char *arg5 = (char *) 0 ;
-  int val1 ;
-  int ecode1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  int alloc3 = 0 ;
-  int res5 ;
-  char *buf5 = 0 ;
-  int alloc5 = 0 ;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "type",(char *) "wkt",(char *) "wkb",(char *) "gml", NULL 
-  };
-  OGRGeometryShadow *result = 0 ;
+  double result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"|OOOO:new_Geometry",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
-  if (obj0) {
-    ecode1 = SWIG_AsVal_int(obj0, &val1);
-    if (!SWIG_IsOK(ecode1)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "new_Geometry" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
-    } 
-    arg1 = static_cast< OGRwkbGeometryType >(val1);
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetArea",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetArea" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
-  if (obj1) {
-    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "new_Geometry" "', argument " "2"" of type '" "char *""'");
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    arg2 = reinterpret_cast< char * >(buf2);
-  }
-  if (obj2) {
-    {
-      /* %typemap(in,numinputs=1) (int nLen, char *pBuf ) */
-#if PY_VERSION_HEX>=0x03000000
-      if (PyUnicode_Check(obj2))
-      {
-        size_t safeLen = 0;
-        int ret = SWIG_AsCharPtrAndSize(obj2, (char**) &arg4, &safeLen, &alloc3);
-        if (!SWIG_IsOK(ret)) {
-          SWIG_exception( SWIG_RuntimeError, "invalid Unicode string" );
-        }
-        
-        if (safeLen) safeLen--;
-        arg3 = (int) safeLen;
-      }
-      else if (PyBytes_Check(obj2))
-      {
-        Py_ssize_t safeLen = 0;
-        PyBytes_AsStringAndSize(obj2, (char**) &arg4, &safeLen);
-        arg3 = (int) safeLen;
-      }
-      else
-      {
-        PyErr_SetString(PyExc_TypeError, "not a unicode string or a bytes");
-        SWIG_fail;
-      }
-#else
-      if (PyString_Check(obj2))
-      {
-        Py_ssize_t safeLen = 0;
-        PyString_AsStringAndSize(obj2, (char**) &arg4, &safeLen);
-        arg3 = (int) safeLen;
-      }
-      else
-      {
-        PyErr_SetString(PyExc_TypeError, "not a string");
-        SWIG_fail;
+    result = (double)OGRGeometryShadow_GetArea(arg1);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-#endif
     }
   }
-  if (obj3) {
-    res5 = SWIG_AsCharPtrAndSize(obj3, &buf5, NULL, &alloc5);
-    if (!SWIG_IsOK(res5)) {
-      SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "new_Geometry" "', argument " "5"" of type '" "char *""'");
-    }
-    arg5 = reinterpret_cast< char * >(buf5);
+  resultobj = SWIG_From_double(static_cast< double >(result));
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Geometry_GetPointCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject * obj0 = 0 ;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetPointCount",&obj0)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPointCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)new_OGRGeometryShadow(arg1,arg2,arg3,arg4,arg5);
+    result = (int)OGRGeometryShadow_GetPointCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16572,54 +19835,57 @@ SWIGINTERN PyObject *_wrap_new_Geometry(PyObject *SWIGUNUSEDPARM(self), PyObject
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_NEW |  0 );
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (int *nLen, char *pBuf ) */
-    if( alloc3 == SWIG_NEWOBJ ) {
-      delete[] arg4;
-    }
-  }
-  if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  {
-    /* %typemap(freearg) (int *nLen, char *pBuf ) */
-    if( alloc3 == SWIG_NEWOBJ ) {
-      delete[] arg4;
-    }
-  }
-  if (alloc5 == SWIG_NEWOBJ) delete[] buf5;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ExportToWkt(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetPoints(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  char **arg2 = (char **) 0 ;
+  int *arg2 = (int *) 0 ;
+  double **arg3 = (double **) 0 ;
+  double **arg4 = (double **) 0 ;
+  int arg5 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  char *argout2 = 0 ;
+  int nPoints2 = 0 ;
+  double *padfXY2 = NULL ;
+  double *padfZ2 = NULL ;
+  int val5 ;
+  int ecode5 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRErr result;
+  PyObject * obj1 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "nCoordDimension", NULL 
+  };
   
   {
-    /* %typemap(in,numinputs=0) (char **argout2) */
-    arg2 = &argout2;
+    /* %typemap(in,numinputs=0) (int* pnCount, double** ppadfXY, double** ppadfZ) */
+    arg2 = &nPoints2;
+    arg3 = &padfXY2;
+    arg4 = &padfZ2;
   }
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_ExportToWkt",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetPoints",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkt" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoints" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (obj1) {
+    ecode5 = SWIG_AsVal_int(obj1, &val5);
+    if (!SWIG_IsOK(ecode5)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_GetPoints" "', argument " "5"" of type '" "int""'");
+    } 
+    arg5 = static_cast< int >(val5);
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_ExportToWkt(arg1,arg2);
+    OGRGeometryShadow_GetPoints(arg1,arg2,arg3,arg4,arg5);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16627,93 +19893,79 @@ SWIGINTERN PyObject *_wrap_Geometry_ExportToWkt(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
+  resultobj = SWIG_Py_Void();
   {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(argout) (char **argout) */
-    PyObject *o;
-    if ( arg2 != NULL && *arg2 != NULL) {
-      o = GDALPythonObjectFromCStr( *arg2 );
+    /* %typemap(argout)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
+    Py_DECREF(resultobj);
+    int nPointCount = *(arg2);
+    if (nPointCount == 0)
+    {
+      resultobj = Py_None;
     }
-    else {
-      o = Py_None;
-      Py_INCREF( o );
+    else
+    {
+      PyObject *xyz = PyList_New( nPointCount );
+      int nDimensions = (*arg4 != NULL) ? 3 : 2;
+      for( int i=0; i< nPointCount; i++ ) {
+        PyObject *tuple = PyTuple_New( nDimensions );
+        PyTuple_SetItem( tuple, 0, PyFloat_FromDouble( (*arg3)[2*i] ) );
+        PyTuple_SetItem( tuple, 1, PyFloat_FromDouble( (*arg3)[2*i+1] ) );
+        if (nDimensions == 3)
+        PyTuple_SetItem( tuple, 2, PyFloat_FromDouble( (*arg4)[i] ) );
+        PyList_SetItem( xyz, i, tuple );
+      }
+      resultobj = xyz;
     }
-    resultobj = t_output_helper(resultobj, o);
-  }
-  {
-    /* %typemap(freearg) (char **argout) */
-    if ( *arg2 )
-    CPLFree( *arg2 );
   }
   {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
+    /* %typemap(freearg)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
+    VSIFree(*arg3);
+    VSIFree(*arg4);
   }
   return resultobj;
 fail:
   {
-    /* %typemap(freearg) (char **argout) */
-    if ( *arg2 )
-    CPLFree( *arg2 );
+    /* %typemap(freearg)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
+    VSIFree(*arg3);
+    VSIFree(*arg4);
   }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ExportToWkb(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_GetX(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int *arg2 = (int *) 0 ;
-  char **arg3 = (char **) 0 ;
-  OGRwkbByteOrder arg4 = (OGRwkbByteOrder) wkbXDR ;
+  int arg2 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int nLen2 = 0 ;
-  char *pBuf2 = 0 ;
-  int val4 ;
-  int ecode4 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "byte_order", NULL 
+    (char *) "self",(char *) "point", NULL 
   };
-  OGRErr result;
+  double result;
   
-  {
-    /* %typemap(in,numinputs=0) (int *nLen2, char **pBuf2 ) */
-    arg2 = &nLen2;
-    arg3 = &pBuf2;
-  }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToWkb",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetX",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToWkb" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetX" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    ecode4 = SWIG_AsVal_int(obj1, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_ExportToWkb" "', argument " "4"" of type '" "OGRwkbByteOrder""'");
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetX" "', argument " "2"" of type '" "int""'");
     } 
-    arg4 = static_cast< OGRwkbByteOrder >(val4);
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_ExportToWkb(arg1,arg2,arg3,arg4);
+    result = (double)OGRGeometryShadow_GetX(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16721,180 +19973,93 @@ SWIGINTERN PyObject *_wrap_Geometry_ExportToWkb(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(argout) (int *nLen, char **pBuf ) */
-    Py_XDECREF(resultobj);
-#if PY_VERSION_HEX >= 0x03000000
-    resultobj = PyBytes_FromStringAndSize( *arg3, *arg2 );
-#else
-    resultobj = PyString_FromStringAndSize( *arg3, *arg2 );
-#endif
-  }
-  {
-    /* %typemap(freearg) (int *nLen, char **pBuf ) */
-    if( *arg2 ) {
-      free( *arg3 );
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) (int *nLen, char **pBuf ) */
-    if( *arg2 ) {
-      free( *arg3 );
-    }
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ExportToGML(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_GetY(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  char **arg2 = (char **) 0 ;
+  int arg2 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
   char *  kwnames[] = {
-    (char *) "self",(char *) "options", NULL 
+    (char *) "self",(char *) "point", NULL 
   };
-  retStringAndCPLFree *result = 0 ;
+  double result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToGML",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetY",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToGML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetY" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj1)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj1);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj1,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg2 = CSLAddString( arg2, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetY" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToGML(arg1,arg2);
+    result = (double)OGRGeometryShadow_GetY(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
         SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
       }
-    }
-  }
-  {
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
-    {
-      resultobj = GDALPythonObjectFromCStr( (const char *)result);
-      CPLFree(result);
-    }
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
+    }
   }
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ExportToKML(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  char *arg2 = (char *) NULL ;
+  int arg2 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  retStringAndCPLFree *result = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "point", NULL 
+  };
+  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_ExportToKML",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetZ",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToKML" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetZ" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-    if (!SWIG_IsOK(res2)) {
-      SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_ExportToKML" "', argument " "2"" of type '" "char const *""'");
-    }
-    arg2 = reinterpret_cast< char * >(buf2);
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetZ" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToKML(arg1,(char const *)arg2);
+    result = (double)OGRGeometryShadow_GetZ(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16902,92 +20067,48 @@ SWIGINTERN PyObject *_wrap_Geometry_ExportToKML(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  {
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
-    {
-      resultobj = GDALPythonObjectFromCStr( (const char *)result);
-      CPLFree(result);
-    }
-  }
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ExportToJson(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_GetPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  char **arg2 = (char **) 0 ;
+  int arg2 = (int) 0 ;
+  double *arg3 = (double *) (double *)NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  double argout3[3] ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "options", NULL 
-  };
-  retStringAndCPLFree *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_ExportToJson",kwnames,&obj0,&obj1)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+    arg3 = argout3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_GetPoint",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ExportToJson" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   if (obj1) {
-    {
-      /* %typemap(in) char **options */
-      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
-      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
-  #if PY_VERSION_HEX < 0x03000000
-        || PyString_Check(obj1)
-  #endif
-        ) {
-        PyErr_SetString(PyExc_TypeError,"not a sequence");
-        SWIG_fail;
-      }
-      
-      int size = PySequence_Size(obj1);
-      for (int i = 0; i < size; i++) {
-        PyObject* pyObj = PySequence_GetItem(obj1,i);
-        if (PyUnicode_Check(pyObj))
-        {
-          char *pszStr;
-          Py_ssize_t nLen;
-          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
-#if PY_VERSION_HEX >= 0x03000000
-          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#else
-          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
-#endif
-          arg2 = CSLAddString( arg2, pszStr );
-          Py_XDECREF(pyUTF8Str);
-        }
-#if PY_VERSION_HEX >= 0x03000000
-        else if (PyBytes_Check(pyObj))
-        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
-#else
-        else if (PyString_Check(pyObj))
-        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
-#endif
-        else
-        {
-          Py_DECREF(pyObj);
-          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
-          SWIG_fail;
-        }
-        Py_DECREF(pyObj);
-      }
-    }
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (retStringAndCPLFree *)OGRGeometryShadow_ExportToJson(arg1,arg2);
+    OGRGeometryShadow_GetPoint(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -16995,78 +20116,53 @@ SWIGINTERN PyObject *_wrap_Geometry_ExportToJson(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
+  resultobj = SWIG_Py_Void();
   {
-    /* %typemap(out) (retStringAndCPLFree*) */
-    if(result)
-    {
-      resultobj = GDALPythonObjectFromCStr( (const char *)result);
-      CPLFree(result);
-    }
-  }
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
+    /* %typemap(argout) (double argout[ANY]) */
+    PyObject *out = CreateTupleFromDoubleArray( arg3, 3 );
+    resultobj = t_output_helper(resultobj,out);
   }
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg) char **options */
-    CSLDestroy( arg2 );
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_AddPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_GetPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
-  double arg3 ;
-  double arg4 = (double) 0 ;
+  int arg2 = (int) 0 ;
+  double *arg3 = (double *) (double *)NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
+  int val2 ;
   int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
+  double argout3[2] ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "x",(char *) "y",(char *) "z", NULL 
-  };
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO|O:Geometry_AddPoint",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
+    arg3 = argout3;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_GetPoint_2D",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  if (obj3) {
-    ecode4 = SWIG_AsVal_double(obj3, &val4);
-    if (!SWIG_IsOK(ecode4)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_AddPoint" "', argument " "4"" of type '" "double""'");
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_2D" "', argument " "2"" of type '" "int""'");
     } 
-    arg4 = static_cast< double >(val4);
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_AddPoint(arg1,arg2,arg3,arg4);
+    OGRGeometryShadow_GetPoint_2D(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17075,48 +20171,36 @@ SWIGINTERN PyObject *_wrap_Geometry_AddPoint(PyObject *SWIGUNUSEDPARM(self), PyO
     }
   }
   resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (double argout[ANY]) */
+    PyObject *out = CreateTupleFromDoubleArray( arg3, 2 );
+    resultobj = t_output_helper(resultobj,out);
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_AddPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetGeometryCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
-  double arg3 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOO:Geometry_AddPoint_2D",&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryCount",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_AddPoint_2D" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_AddPoint_2D" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_AddPoint_2D(arg1,arg2,arg3);
+    result = (int)OGRGeometryShadow_GetGeometryCount(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17124,44 +20208,72 @@ SWIGINTERN PyObject *_wrap_Geometry_AddPoint_2D(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_AddGeometryDirectly(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SetPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  int arg2 ;
+  double arg3 ;
+  double arg4 ;
+  double arg5 = (double) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
+  int ecode4 = 0 ;
+  double val5 ;
+  int ecode5 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  PyObject * obj4 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "point",(char *) "x",(char *) "y",(char *) "z", NULL 
+  };
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AddGeometryDirectly",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO|O:Geometry_SetPoint",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometryDirectly" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, SWIG_as_voidptrptr(&arg2), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_DISOWN |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometryDirectly" "', argument " "2"" of type '" "OGRGeometryShadow *""'");
-  }
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  ecode4 = SWIG_AsVal_double(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint" "', argument " "4"" of type '" "double""'");
+  } 
+  arg4 = static_cast< double >(val4);
+  if (obj4) {
+    ecode5 = SWIG_AsVal_double(obj4, &val5);
+    if (!SWIG_IsOK(ecode5)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_SetPoint" "', argument " "5"" of type '" "double""'");
+    } 
+    arg5 = static_cast< double >(val5);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_AddGeometryDirectly(arg1,arg2);
+    OGRGeometryShadow_SetPoint(arg1,arg2,arg3,arg4,arg5);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17169,62 +20281,61 @@ SWIGINTERN PyObject *_wrap_Geometry_AddGeometryDirectly(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_AddGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SetPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  int arg2 ;
+  double arg3 ;
+  double arg4 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  double val3 ;
+  int ecode3 = 0 ;
+  double val4 ;
+  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  PyObject * obj2 = 0 ;
+  PyObject * obj3 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "point",(char *) "x",(char *) "y", NULL 
+  };
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AddGeometry",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:Geometry_SetPoint_2D",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AddGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AddGeometry" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_2D" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  ecode3 = SWIG_AsVal_double(obj2, &val3);
+  if (!SWIG_IsOK(ecode3)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_2D" "', argument " "3"" of type '" "double""'");
+  } 
+  arg3 = static_cast< double >(val3);
+  ecode4 = SWIG_AsVal_double(obj3, &val4);
+  if (!SWIG_IsOK(ecode4)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_2D" "', argument " "4"" of type '" "double""'");
+  } 
+  arg4 = static_cast< double >(val4);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_AddGeometry(arg1,arg2);
+    OGRGeometryShadow_SetPoint_2D(arg1,arg2,arg3,arg4);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17232,48 +20343,41 @@ SWIGINTERN PyObject *_wrap_Geometry_AddGeometry(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Clone(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetGeometryRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
   OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Clone",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_GetGeometryRef",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Clone" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryRef" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetGeometryRef" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Clone(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetGeometryRef(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17281,32 +20385,41 @@ SWIGINTERN PyObject *_wrap_Geometry_Clone(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetGeometryType(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Simplify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRwkbGeometryType result;
+  PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryType",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Simplify",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryType" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Simplify" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Simplify" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRwkbGeometryType)OGRGeometryShadow_GetGeometryType(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Simplify(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17314,32 +20427,41 @@ SWIGINTERN PyObject *_wrap_Geometry_GetGeometryType(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetGeometryName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SimplifyPreserveTopology(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryName",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SimplifyPreserveTopology",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryName" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRGeometryShadow_GetGeometryName(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_SimplifyPreserveTopology(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17347,32 +20469,32 @@ SWIGINTERN PyObject *_wrap_Geometry_GetGeometryName(PyObject *SWIGUNUSEDPARM(sel
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Length(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Boundary(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Length",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Boundary",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Length" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Boundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_Length(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Boundary(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17380,32 +20502,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Length(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Area(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetBoundary(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Area",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetBoundary",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Area" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetBoundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_Area(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetBoundary(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17413,32 +20535,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Area(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetArea(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_ConvexHull(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetArea",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_ConvexHull",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetArea" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ConvexHull" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_GetArea(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_ConvexHull(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17446,32 +20568,55 @@ SWIGINTERN PyObject *_wrap_Geometry_GetArea(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetPointCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Buffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
+  int arg3 = (int) 30 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "distance",(char *) "quadsecs", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetPointCount",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Geometry_Buffer",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPointCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Buffer" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Buffer" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Buffer" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeometryShadow_GetPointCount(arg1);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Buffer(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17479,57 +20624,46 @@ SWIGINTERN PyObject *_wrap_Geometry_GetPointCount(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetPoints(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_Intersection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int *arg2 = (int *) 0 ;
-  double **arg3 = (double **) 0 ;
-  double **arg4 = (double **) 0 ;
-  int arg5 = (int) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int nPoints2 = 0 ;
-  double *padfXY2 = NULL ;
-  double *padfZ2 = NULL ;
-  int val5 ;
-  int ecode5 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "nCoordDimension", NULL 
-  };
+  OGRGeometryShadow *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (int* pnCount, double** ppadfXY, double** ppadfZ) */
-    arg2 = &nPoints2;
-    arg3 = &padfXY2;
-    arg4 = &padfZ2;
-  }
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetPoints",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersection",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoints" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersection" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode5 = SWIG_AsVal_int(obj1, &val5);
-    if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_GetPoints" "', argument " "5"" of type '" "int""'");
-    } 
-    arg5 = static_cast< int >(val5);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersection" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_GetPoints(arg1,arg2,arg3,arg4,arg5);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Intersection(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17537,79 +20671,46 @@ SWIGINTERN PyObject *_wrap_Geometry_GetPoints(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
-    Py_DECREF(resultobj);
-    int nPointCount = *(arg2);
-    if (nPointCount == 0)
-    {
-      resultobj = Py_None;
-    }
-    else
-    {
-      PyObject *xyz = PyList_New( nPointCount );
-      int nDimensions = (*arg4 != NULL) ? 3 : 2;
-      for( int i=0; i< nPointCount; i++ ) {
-        PyObject *tuple = PyTuple_New( nDimensions );
-        PyTuple_SetItem( tuple, 0, PyFloat_FromDouble( (*arg3)[2*i] ) );
-        PyTuple_SetItem( tuple, 1, PyFloat_FromDouble( (*arg3)[2*i+1] ) );
-        if (nDimensions == 3)
-        PyTuple_SetItem( tuple, 2, PyFloat_FromDouble( (*arg4)[i] ) );
-        PyList_SetItem( xyz, i, tuple );
-      }
-      resultobj = xyz;
-    }
-  }
-  {
-    /* %typemap(freearg)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
-    VSIFree(*arg3);
-    VSIFree(*arg4);
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
-  {
-    /* %typemap(freearg)  (int* pnCount, double** ppadfXY, double** ppadfZ) */
-    VSIFree(*arg3);
-    VSIFree(*arg4);
-  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetX(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_Union(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "point", NULL 
-  };
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetX",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Union",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetX" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Union" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetX" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Union" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_GetX(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Union(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17617,46 +20718,32 @@ SWIGINTERN PyObject *_wrap_Geometry_GetX(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetY(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_UnionCascaded(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "point", NULL 
-  };
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetY",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_UnionCascaded",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetY" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_UnionCascaded" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetY" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_GetY(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_UnionCascaded(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17664,46 +20751,46 @@ SWIGINTERN PyObject *_wrap_Geometry_GetY(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_Difference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "point", NULL 
-  };
-  double result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetZ",kwnames,&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Difference",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetZ" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Difference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetZ" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Difference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_GetZ(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Difference(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17711,48 +20798,46 @@ SWIGINTERN PyObject *_wrap_Geometry_GetZ(PyObject *SWIGUNUSEDPARM(self), PyObjec
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SymDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
-  double *arg3 = (double *) (double *)NULL ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  double argout3[3] ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-    arg3 = argout3;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_GetPoint",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SymDifference",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_GetPoint(arg1,arg2,arg3);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_SymDifference(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17760,91 +20845,93 @@ SWIGINTERN PyObject *_wrap_Geometry_GetPoint(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (double argout[ANY]) */
-    PyObject *out = CreateTupleFromDoubleArray( arg3, 3 );
-    resultobj = t_output_helper(resultobj,out);
-  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SymmetricDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 = (int) 0 ;
-  double *arg3 = (double *) (double *)NULL ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  double argout3[2] ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout3[ANY]) */
-    arg3 = argout3;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_GetPoint_2D",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SymmetricDifference",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymmetricDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  if (obj1) {
-    ecode2 = SWIG_AsVal_int(obj1, &val2);
-    if (!SWIG_IsOK(ecode2)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetPoint_2D" "', argument " "2"" of type '" "int""'");
-    } 
-    arg2 = static_cast< int >(val2);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymmetricDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_GetPoint_2D(arg1,arg2,arg3);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_SymmetricDifference(arg1,arg2);
     if ( bUseExceptions ) {
-      CPLErr eclass = CPLGetLastErrorType();
-      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
-        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
-      }
-    }
-  }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (double argout[ANY]) */
-    PyObject *out = CreateTupleFromDoubleArray( arg3, 2 );
-    resultobj = t_output_helper(resultobj,out);
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetGeometryCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Distance(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  double result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetGeometryCount",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Distance",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryCount" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Distance" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Distance" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeometryShadow_GetGeometryCount(arg1);
+    result = (double)OGRGeometryShadow_Distance(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17852,72 +20939,31 @@ SWIGINTERN PyObject *_wrap_Geometry_GetGeometryCount(PyObject *SWIGUNUSEDPARM(se
       }
     }
   }
-  resultobj = SWIG_From_int(static_cast< int >(result));
+  resultobj = SWIG_From_double(static_cast< double >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SetPoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_Empty(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 ;
-  double arg3 ;
-  double arg4 ;
-  double arg5 = (double) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  double val5 ;
-  int ecode5 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  PyObject * obj4 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "point",(char *) "x",(char *) "y",(char *) "z", NULL 
-  };
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO|O:Geometry_SetPoint",kwnames,&obj0,&obj1,&obj2,&obj3,&obj4)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Empty",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Empty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
-  if (obj4) {
-    ecode5 = SWIG_AsVal_double(obj4, &val5);
-    if (!SWIG_IsOK(ecode5)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode5), "in method '" "Geometry_SetPoint" "', argument " "5"" of type '" "double""'");
-    } 
-    arg5 = static_cast< double >(val5);
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_SetPoint(arg1,arg2,arg3,arg4,arg5);
+    OGRGeometryShadow_Empty(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17932,54 +20978,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SetPoint_2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_IsEmpty(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 ;
-  double arg3 ;
-  double arg4 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
-  double val3 ;
-  int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "point",(char *) "x",(char *) "y", NULL 
-  };
+  bool result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOOO:Geometry_SetPoint_2D",kwnames,&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsEmpty",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetPoint_2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsEmpty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetPoint_2D" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
-  ecode3 = SWIG_AsVal_double(obj2, &val3);
-  if (!SWIG_IsOK(ecode3)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_SetPoint_2D" "', argument " "3"" of type '" "double""'");
-  } 
-  arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(obj3, &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "Geometry_SetPoint_2D" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_SetPoint_2D(arg1,arg2,arg3,arg4);
+    result = (bool)OGRGeometryShadow_IsEmpty(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -17987,41 +21004,32 @@ SWIGINTERN PyObject *_wrap_Geometry_SetPoint_2D(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetGeometryRef(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_IsValid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_GetGeometryRef",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsValid",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetGeometryRef" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsValid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_int(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetGeometryRef" "', argument " "2"" of type '" "int""'");
-  } 
-  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_GetGeometryRef(arg1,arg2);
+    result = (bool)OGRGeometryShadow_IsValid(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18029,41 +21037,32 @@ SWIGINTERN PyObject *_wrap_Geometry_GetGeometryRef(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Simplify(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_IsSimple(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Simplify",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsSimple",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Simplify" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsSimple" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Simplify" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Simplify(arg1,arg2);
+    result = (bool)OGRGeometryShadow_IsSimple(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18071,41 +21070,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Simplify(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SimplifyPreserveTopology(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_IsRing(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SimplifyPreserveTopology",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsRing",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsRing" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SimplifyPreserveTopology" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_SimplifyPreserveTopology(arg1,arg2);
+    result = (bool)OGRGeometryShadow_IsRing(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18113,32 +21103,46 @@ SWIGINTERN PyObject *_wrap_Geometry_SimplifyPreserveTopology(PyObject *SWIGUNUSE
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Boundary(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Intersects(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Boundary",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersects",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Boundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersects" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersects" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Boundary(arg1);
+    result = (bool)OGRGeometryShadow_Intersects(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18146,32 +21150,46 @@ SWIGINTERN PyObject *_wrap_Geometry_Boundary(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetBoundary(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Intersect(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetBoundary",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersect",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetBoundary" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersect" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersect" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_GetBoundary(arg1);
+    result = (bool)OGRGeometryShadow_Intersect(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18179,32 +21197,46 @@ SWIGINTERN PyObject *_wrap_Geometry_GetBoundary(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_ConvexHull(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Equals(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_ConvexHull",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Equals",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_ConvexHull" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equals" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equals" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_ConvexHull(arg1);
+    result = (bool)OGRGeometryShadow_Equals(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18212,55 +21244,46 @@ SWIGINTERN PyObject *_wrap_Geometry_ConvexHull(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Buffer(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
+SWIGINTERN PyObject *_wrap_Geometry_Equal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
-  int arg3 = (int) 30 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
-  int val3 ;
-  int ecode3 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  char *  kwnames[] = {
-    (char *) "self",(char *) "distance",(char *) "quadsecs", NULL 
-  };
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO|O:Geometry_Buffer",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Equal",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Buffer" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equal" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Buffer" "', argument " "2"" of type '" "double""'");
-  } 
-  arg2 = static_cast< double >(val2);
-  if (obj2) {
-    ecode3 = SWIG_AsVal_int(obj2, &val3);
-    if (!SWIG_IsOK(ecode3)) {
-      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "Geometry_Buffer" "', argument " "3"" of type '" "int""'");
-    } 
-    arg3 = static_cast< int >(val3);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equal" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Buffer(arg1,arg2,arg3);
+    result = (bool)OGRGeometryShadow_Equal(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18268,14 +21291,14 @@ SWIGINTERN PyObject *_wrap_Geometry_Buffer(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Intersection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Disjoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -18285,17 +21308,17 @@ SWIGINTERN PyObject *_wrap_Geometry_Intersection(PyObject *SWIGUNUSEDPARM(self),
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersection",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Disjoint",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersection" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Disjoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersection" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Disjoint" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
@@ -18307,7 +21330,7 @@ SWIGINTERN PyObject *_wrap_Geometry_Intersection(PyObject *SWIGUNUSEDPARM(self),
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Intersection(arg1,arg2);
+    result = (bool)OGRGeometryShadow_Disjoint(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18315,14 +21338,14 @@ SWIGINTERN PyObject *_wrap_Geometry_Intersection(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Union(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Touches(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -18332,17 +21355,17 @@ SWIGINTERN PyObject *_wrap_Geometry_Union(PyObject *SWIGUNUSEDPARM(self), PyObje
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Union",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Touches",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Union" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Touches" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Union" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Touches" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
@@ -18354,7 +21377,7 @@ SWIGINTERN PyObject *_wrap_Geometry_Union(PyObject *SWIGUNUSEDPARM(self), PyObje
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Union(arg1,arg2);
+    result = (bool)OGRGeometryShadow_Touches(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18362,32 +21385,46 @@ SWIGINTERN PyObject *_wrap_Geometry_Union(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_UnionCascaded(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Crosses(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  PyObject * obj1 = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_UnionCascaded",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Crosses",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_UnionCascaded" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Crosses" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Crosses" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_UnionCascaded(arg1);
+    result = (bool)OGRGeometryShadow_Crosses(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18395,14 +21432,14 @@ SWIGINTERN PyObject *_wrap_Geometry_UnionCascaded(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Difference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Within(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -18412,17 +21449,17 @@ SWIGINTERN PyObject *_wrap_Geometry_Difference(PyObject *SWIGUNUSEDPARM(self), P
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Difference",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Within",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Difference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Within" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Difference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Within" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
@@ -18434,7 +21471,7 @@ SWIGINTERN PyObject *_wrap_Geometry_Difference(PyObject *SWIGUNUSEDPARM(self), P
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Difference(arg1,arg2);
+    result = (bool)OGRGeometryShadow_Within(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18442,14 +21479,14 @@ SWIGINTERN PyObject *_wrap_Geometry_Difference(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SymDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Contains(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -18459,17 +21496,17 @@ SWIGINTERN PyObject *_wrap_Geometry_SymDifference(PyObject *SWIGUNUSEDPARM(self)
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SymDifference",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Contains",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Contains" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Contains" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
@@ -18481,7 +21518,7 @@ SWIGINTERN PyObject *_wrap_Geometry_SymDifference(PyObject *SWIGUNUSEDPARM(self)
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_SymDifference(arg1,arg2);
+    result = (bool)OGRGeometryShadow_Contains(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18489,14 +21526,14 @@ SWIGINTERN PyObject *_wrap_Geometry_SymDifference(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SymmetricDifference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Overlaps(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
@@ -18506,17 +21543,17 @@ SWIGINTERN PyObject *_wrap_Geometry_SymmetricDifference(PyObject *SWIGUNUSEDPARM
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SymmetricDifference",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Overlaps",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SymmetricDifference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Overlaps" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_SymmetricDifference" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Overlaps" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
   {
@@ -18528,7 +21565,7 @@ SWIGINTERN PyObject *_wrap_Geometry_SymmetricDifference(PyObject *SWIGUNUSEDPARM
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_SymmetricDifference(arg1,arg2);
+    result = (bool)OGRGeometryShadow_Overlaps(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18536,36 +21573,36 @@ SWIGINTERN PyObject *_wrap_Geometry_SymmetricDifference(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_bool(static_cast< bool >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Distance(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_TransformTo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   void *argp2 = 0 ;
   int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  double result;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Distance",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_TransformTo",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Distance" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_TransformTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
   if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Distance" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_TransformTo" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
   }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
+  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
   {
     if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
@@ -18575,7 +21612,7 @@ SWIGINTERN PyObject *_wrap_Geometry_Distance(PyObject *SWIGUNUSEDPARM(self), PyO
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (double)OGRGeometryShadow_Distance(arg1,arg2);
+    result = (OGRErr)OGRGeometryShadow_TransformTo(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18583,31 +21620,62 @@ SWIGINTERN PyObject *_wrap_Geometry_Distance(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_double(static_cast< double >(result));
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Empty(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Transform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OSRCoordinateTransformationShadow *arg2 = (OSRCoordinateTransformationShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Empty",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Transform",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Empty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Transform" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRCoordinateTransformationShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Transform" "', argument " "2"" of type '" "OSRCoordinateTransformationShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OSRCoordinateTransformationShadow * >(argp2);
+  {
+    if (!arg2) {
+      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    }
+  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_Empty(arg1);
+    result = (OGRErr)OGRGeometryShadow_Transform(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18615,32 +21683,48 @@ SWIGINTERN PyObject *_wrap_Geometry_Empty(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_IsEmpty(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetSpatialReference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  bool result;
+  OSRSpatialReferenceShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsEmpty",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetSpatialReference",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsEmpty" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_IsEmpty(arg1);
+    result = (OSRSpatialReferenceShadow *)OGRGeometryShadow_GetSpatialReference(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18648,32 +21732,40 @@ SWIGINTERN PyObject *_wrap_Geometry_IsEmpty(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_IsValid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_AssignSpatialReference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
+  void *argp2 = 0 ;
+  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  bool result;
+  PyObject * obj1 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsValid",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AssignSpatialReference",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsValid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AssignSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
+  if (!SWIG_IsOK(res2)) {
+    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AssignSpatialReference" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+  }
+  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_IsValid(arg1);
+    OGRGeometryShadow_AssignSpatialReference(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18681,32 +21773,31 @@ SWIGINTERN PyObject *_wrap_Geometry_IsValid(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_IsSimple(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_CloseRings(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsSimple",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_CloseRings",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsSimple" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_CloseRings" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_IsSimple(arg1);
+    OGRGeometryShadow_CloseRings(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18714,32 +21805,31 @@ SWIGINTERN PyObject *_wrap_Geometry_IsSimple(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_IsRing(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_FlattenTo2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   PyObject * obj0 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_IsRing",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_FlattenTo2D",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_IsRing" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_FlattenTo2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_IsRing(arg1);
+    OGRGeometryShadow_FlattenTo2D(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18747,46 +21837,40 @@ SWIGINTERN PyObject *_wrap_Geometry_IsRing(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Intersects(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Segmentize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersects",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Segmentize",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersects" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Segmentize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersects" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Segmentize" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Intersects(arg1,arg2);
+    OGRGeometryShadow_Segmentize(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18794,46 +21878,37 @@ SWIGINTERN PyObject *_wrap_Geometry_Intersects(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Intersect(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  double *arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  double argout2[4] ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Intersect",&obj0,&obj1)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=0) (double argout2[ANY]) */
+    arg2 = argout2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetEnvelope",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Intersect" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Intersect" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Intersect(arg1,arg2);
+    OGRGeometryShadow_GetEnvelope(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18841,46 +21916,42 @@ SWIGINTERN PyObject *_wrap_Geometry_Intersect(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (double argout[ANY]) */
+    PyObject *out = CreateTupleFromDoubleArray( arg2, 4 );
+    resultobj = t_output_helper(resultobj,out);
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Equals(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope3D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  double *arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  double argout2[6] ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Equals",&obj0,&obj1)) SWIG_fail;
+  {
+    /* %typemap(in,numinputs=0) (double argout2[ANY]) */
+    arg2 = argout2;
+  }
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetEnvelope3D",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equals" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equals" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Equals(arg1,arg2);
+    OGRGeometryShadow_GetEnvelope3D(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18888,46 +21959,37 @@ SWIGINTERN PyObject *_wrap_Geometry_Equals(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(argout) (double argout[ANY]) */
+    PyObject *out = CreateTupleFromDoubleArray( arg2, 6 );
+    resultobj = t_output_helper(resultobj,out);
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Equal(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_Centroid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Equal",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Centroid",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Equal" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Centroid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Equal" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Equal(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Centroid(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18935,46 +21997,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Equal(PyObject *SWIGUNUSEDPARM(self), PyObje
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Disjoint(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_PointOnSurface(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Disjoint",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_PointOnSurface",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Disjoint" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_PointOnSurface" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Disjoint" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Disjoint(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_PointOnSurface(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -18982,46 +22030,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Disjoint(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Touches(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_WkbSize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Touches",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_WkbSize",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Touches" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_WkbSize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Touches" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Touches(arg1,arg2);
+    result = (int)OGRGeometryShadow_WkbSize(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19029,46 +22063,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Touches(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Crosses(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetCoordinateDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Crosses",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetCoordinateDimension",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Crosses" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Crosses" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Crosses(arg1,arg2);
+    result = (int)OGRGeometryShadow_GetCoordinateDimension(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19076,46 +22096,40 @@ SWIGINTERN PyObject *_wrap_Geometry_Crosses(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Within(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_SetCoordinateDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  int arg2 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  bool result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Within",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SetCoordinateDimension",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Within" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Within" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetCoordinateDimension" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Within(arg1,arg2);
+    OGRGeometryShadow_SetCoordinateDimension(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19123,46 +22137,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Within(PyObject *SWIGUNUSEDPARM(self), PyObj
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_Py_Void();
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Contains(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Contains",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetDimension",&obj0)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Contains" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Contains" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
-  }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Contains(arg1,arg2);
+    result = (int)OGRGeometryShadow_GetDimension(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19170,46 +22170,43 @@ SWIGINTERN PyObject *_wrap_Geometry_Contains(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Overlaps(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_HasCurveGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OGRGeometryShadow *arg2 = (OGRGeometryShadow *) 0 ;
+  int arg2 = (int) FALSE ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  bool result;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Overlaps",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O|O:Geometry_HasCurveGeometry",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Overlaps" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_HasCurveGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Overlaps" "', argument " "2"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OGRGeometryShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
-    }
+  if (obj1) {
+    ecode2 = SWIG_AsVal_int(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_HasCurveGeometry" "', argument " "2"" of type '" "int""'");
+    } 
+    arg2 = static_cast< int >(val2);
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (bool)OGRGeometryShadow_Overlaps(arg1,arg2);
+    result = (int)OGRGeometryShadow_HasCurveGeometry(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19217,46 +22214,94 @@ SWIGINTERN PyObject *_wrap_Geometry_Overlaps(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_From_bool(static_cast< bool >(result));
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_TransformTo(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetLinearGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
+  double arg2 = (double) 0.0 ;
+  char **arg3 = (char **) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  PyObject * obj2 = 0 ;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "dfMaxAngleStepSizeDegrees",(char *) "options", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_TransformTo",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|OO:Geometry_GetLinearGeometry",kwnames,&obj0,&obj1,&obj2)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_TransformTo" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetLinearGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_TransformTo" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
+  if (obj1) {
+    ecode2 = SWIG_AsVal_double(obj1, &val2);
+    if (!SWIG_IsOK(ecode2)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_GetLinearGeometry" "', argument " "2"" of type '" "double""'");
+    } 
+    arg2 = static_cast< double >(val2);
   }
-  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+  if (obj2) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj2) || PyUnicode_Check(obj2)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj2)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj2);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj2,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg3 = CSLAddString( arg3, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg3 = CSLAddString( arg3, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_TransformTo(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetLinearGeometry(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19264,62 +22309,91 @@ SWIGINTERN PyObject *_wrap_Geometry_TransformTo(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
   }
   return resultobj;
 fail:
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg3 );
+  }
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Transform(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_Geometry_GetCurveGeometry(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) {
   PyObject *resultobj = 0;
   OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OSRCoordinateTransformationShadow *arg2 = (OSRCoordinateTransformationShadow *) 0 ;
+  char **arg2 = (char **) NULL ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  OGRErr result;
+  char *  kwnames[] = {
+    (char *) "self",(char *) "options", NULL 
+  };
+  OGRGeometryShadow *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Transform",&obj0,&obj1)) SWIG_fail;
+  if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:Geometry_GetCurveGeometry",kwnames,&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Transform" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCurveGeometry" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
   }
   arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRCoordinateTransformationShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_Transform" "', argument " "2"" of type '" "OSRCoordinateTransformationShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OSRCoordinateTransformationShadow * >(argp2);
-  {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+  if (obj1) {
+    {
+      /* %typemap(in) char **options */
+      /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+      if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+        || PyString_Check(obj1)
+  #endif
+        ) {
+        PyErr_SetString(PyExc_TypeError,"not a sequence");
+        SWIG_fail;
+      }
+      
+      int size = PySequence_Size(obj1);
+      for (int i = 0; i < size; i++) {
+        PyObject* pyObj = PySequence_GetItem(obj1,i);
+        if (PyUnicode_Check(pyObj))
+        {
+          char *pszStr;
+          Py_ssize_t nLen;
+          PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+          PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+          PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+          arg2 = CSLAddString( arg2, pszStr );
+          Py_XDECREF(pyUTF8Str);
+        }
+#if PY_VERSION_HEX >= 0x03000000
+        else if (PyBytes_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+        else if (PyString_Check(pyObj))
+        arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+        else
+        {
+          Py_DECREF(pyObj);
+          PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+          SWIG_fail;
+        }
+        Py_DECREF(pyObj);
+      }
     }
   }
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRGeometryShadow_Transform(arg1,arg2);
+    result = (OGRGeometryShadow *)OGRGeometryShadow_GetCurveGeometry(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19327,48 +22401,80 @@ SWIGINTERN PyObject *_wrap_Geometry_Transform(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
   }
+  return resultobj;
+fail:
   {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_Geometry_Value(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
+  double arg2 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  double val2 ;
+  int ecode2 = 0 ;
+  PyObject * obj0 = 0 ;
+  PyObject * obj1 = 0 ;
+  OGRGeometryShadow *result = 0 ;
+  
+  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Value",&obj0,&obj1)) SWIG_fail;
+  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Value" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  }
+  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  ecode2 = SWIG_AsVal_double(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Value" "', argument " "2"" of type '" "double""'");
+  } 
+  arg2 = static_cast< double >(val2);
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
     }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
+    result = (OGRGeometryShadow *)OGRGeometryShadow_Value(arg1,arg2);
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
     }
   }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetSpatialReference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *Geometry_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_OGRGeometryShadow, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *_wrap_GetDriverCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  OSRSpatialReferenceShadow *result = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetSpatialReference",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)":GetDriverCount")) SWIG_fail;
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OSRSpatialReferenceShadow *)OGRGeometryShadow_GetSpatialReference(arg1);
+    result = (int)OGRGetDriverCount();
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19376,40 +22482,23 @@ SWIGINTERN PyObject *_wrap_Geometry_GetSpatialReference(PyObject *SWIGUNUSEDPARM
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OSRSpatialReferenceShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_AssignSpatialReference(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GetOpenDSCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  OSRSpatialReferenceShadow *arg2 = (OSRSpatialReferenceShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  void *argp2 = 0 ;
-  int res2 = 0 ;
-  PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_AssignSpatialReference",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_AssignSpatialReference" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Geometry_AssignSpatialReference" "', argument " "2"" of type '" "OSRSpatialReferenceShadow *""'"); 
-  }
-  arg2 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp2);
+  if (!PyArg_ParseTuple(args,(char *)":GetOpenDSCount")) SWIG_fail;
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_AssignSpatialReference(arg1,arg2);
+    result = (int)OGRGetOpenDSCount();
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19417,31 +22506,32 @@ SWIGINTERN PyObject *_wrap_Geometry_AssignSpatialReference(PyObject *SWIGUNUSEDP
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_CloseRings(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_SetGenerate_DB2_V72_BYTE_ORDER(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  int arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
+  OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_CloseRings",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_CloseRings" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:SetGenerate_DB2_V72_BYTE_ORDER",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetGenerate_DB2_V72_BYTE_ORDER" "', argument " "1"" of type '" "int""'");
+  } 
+  arg1 = static_cast< int >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_CloseRings(arg1);
+    result = (OGRErr)OGRSetGenerate_DB2_V72_BYTE_ORDER(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19449,31 +22539,38 @@ SWIGINTERN PyObject *_wrap_Geometry_CloseRings(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  {
+    /* %typemap(out) OGRErr */
+    if ( result != 0 && bUseExceptions) {
+      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
+      SWIG_fail;
+    }
+  }
+  {
+    /* %typemap(ret) OGRErr */
+    if (resultobj == Py_None ) {
+      Py_DECREF(resultobj);
+      resultobj = 0;
+    }
+    if (resultobj == 0) {
+      resultobj = PyInt_FromLong( result );
+    }
+  }
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_FlattenTo2D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_RegisterAll(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_FlattenTo2D",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_FlattenTo2D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)":RegisterAll")) SWIG_fail;
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_FlattenTo2D(arg1);
+    OGRRegisterAll();
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19488,33 +22585,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Segmentize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GeometryTypeToName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double val2 ;
-  int ecode2 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
-  PyObject * obj1 = 0 ;
+  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_Segmentize",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Segmentize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
-  ecode2 = SWIG_AsVal_double(obj1, &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_Segmentize" "', argument " "2"" of type '" "double""'");
+  if (!PyArg_ParseTuple(args,(char *)"O:GeometryTypeToName",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GeometryTypeToName" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
   } 
-  arg2 = static_cast< double >(val2);
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_Segmentize(arg1,arg2);
+    result = (char *)OGRGeometryTypeToName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19522,37 +22611,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Segmentize(PyObject *SWIGUNUSEDPARM(self), P
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double *arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double argout2[4] ;
+  OGRFieldType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout2[ANY]) */
-    arg2 = argout2;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetEnvelope",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:GetFieldTypeName",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldType""'");
+  } 
+  arg1 = static_cast< OGRFieldType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_GetEnvelope(arg1,arg2);
+    result = (char *)OGR_GetFieldTypeName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19560,42 +22644,32 @@ SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope(PyObject *SWIGUNUSEDPARM(self),
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (double argout[ANY]) */
-    PyObject *out = CreateTupleFromDoubleArray( arg2, 4 );
-    resultobj = t_output_helper(resultobj,out);
-  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope3D(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GetFieldSubTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  double *arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  double argout2[6] ;
+  OGRFieldSubType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
+  char *result = 0 ;
   
-  {
-    /* %typemap(in,numinputs=0) (double argout2[ANY]) */
-    arg2 = argout2;
-  }
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetEnvelope3D",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetEnvelope3D" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:GetFieldSubTypeName",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldSubTypeName" "', argument " "1"" of type '" "OGRFieldSubType""'");
+  } 
+  arg1 = static_cast< OGRFieldSubType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_GetEnvelope3D(arg1,arg2);
+    result = (char *)OGR_GetFieldSubTypeName(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19603,37 +22677,32 @@ SWIGINTERN PyObject *_wrap_Geometry_GetEnvelope3D(PyObject *SWIGUNUSEDPARM(self)
       }
     }
   }
-  resultobj = SWIG_Py_Void();
-  {
-    /* %typemap(argout) (double argout[ANY]) */
-    PyObject *out = CreateTupleFromDoubleArray( arg2, 6 );
-    resultobj = t_output_helper(resultobj,out);
-  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_Centroid(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_Flatten(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_Centroid",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_Centroid" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_Flatten",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_Flatten" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_Centroid(arg1);
+    result = (OGRwkbGeometryType)OGR_GT_Flatten(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19641,32 +22710,32 @@ SWIGINTERN PyObject *_wrap_Geometry_Centroid(PyObject *SWIGUNUSEDPARM(self), PyO
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_PointOnSurface(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_SetZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject * obj0 = 0 ;
-  OGRGeometryShadow *result = 0 ;
-  
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_PointOnSurface",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_PointOnSurface" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRwkbGeometryType result;
+  
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_SetZ",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_SetZ" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRGeometryShadow *)OGRGeometryShadow_PointOnSurface(arg1);
+    result = (OGRwkbGeometryType)OGR_GT_SetZ(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19674,32 +22743,52 @@ SWIGINTERN PyObject *_wrap_Geometry_PointOnSurface(PyObject *SWIGUNUSEDPARM(self
       }
     }
   }
-  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_OGRGeometryShadow, SWIG_POINTER_OWN |  0 );
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_WkbSize(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_SetModifier(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  int arg2 ;
+  int arg3 = (int) FALSE ;
+  int val1 ;
+  int ecode1 = 0 ;
+  int val2 ;
+  int ecode2 = 0 ;
+  int val3 ;
+  int ecode3 = 0 ;
   PyObject * obj0 = 0 ;
-  int result;
+  PyObject * obj1 = 0 ;
+  PyObject * obj2 = 0 ;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_WkbSize",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_WkbSize" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
+  if (!PyArg_ParseTuple(args,(char *)"OO|O:GT_SetModifier",&obj0,&obj1,&obj2)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_SetModifier" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
+  ecode2 = SWIG_AsVal_int(obj1, &val2);
+  if (!SWIG_IsOK(ecode2)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GT_SetModifier" "', argument " "2"" of type '" "int""'");
+  } 
+  arg2 = static_cast< int >(val2);
+  if (obj2) {
+    ecode3 = SWIG_AsVal_int(obj2, &val3);
+    if (!SWIG_IsOK(ecode3)) {
+      SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "GT_SetModifier" "', argument " "3"" of type '" "int""'");
+    } 
+    arg3 = static_cast< int >(val3);
   }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeometryShadow_WkbSize(arg1);
+    result = (OGRwkbGeometryType)GT_SetModifier(arg1,arg2,arg3);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19714,25 +22803,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetCoordinateDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_HasZ(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetCoordinateDimension",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_HasZ",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_HasZ" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeometryShadow_GetCoordinateDimension(arg1);
+    result = (int)OGR_GT_HasZ(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19747,33 +22836,34 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_SetCoordinateDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_IsSubClassOf(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  int arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  OGRwkbGeometryType arg2 ;
+  int val1 ;
+  int ecode1 = 0 ;
   int val2 ;
   int ecode2 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
+  int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OO:Geometry_SetCoordinateDimension",&obj0,&obj1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_SetCoordinateDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"OO:GT_IsSubClassOf",&obj0,&obj1)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsSubClassOf" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   ecode2 = SWIG_AsVal_int(obj1, &val2);
   if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "Geometry_SetCoordinateDimension" "', argument " "2"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "GT_IsSubClassOf" "', argument " "2"" of type '" "OGRwkbGeometryType""'");
   } 
-  arg2 = static_cast< int >(val2);
+  arg2 = static_cast< OGRwkbGeometryType >(val2);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRGeometryShadow_SetCoordinateDimension(arg1,arg2);
+    result = (int)OGR_GT_IsSubClassOf(arg1,arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19781,32 +22871,32 @@ SWIGINTERN PyObject *_wrap_Geometry_SetCoordinateDimension(PyObject *SWIGUNUSEDP
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_Geometry_GetDimension(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_IsCurve(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRGeometryShadow *arg1 = (OGRGeometryShadow *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:Geometry_GetDimension",&obj0)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OGRGeometryShadow, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Geometry_GetDimension" "', argument " "1"" of type '" "OGRGeometryShadow *""'"); 
-  }
-  arg1 = reinterpret_cast< OGRGeometryShadow * >(argp1);
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_IsCurve",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsCurve" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGeometryShadow_GetDimension(arg1);
+    result = (int)OGR_GT_IsCurve(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19821,23 +22911,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *Geometry_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
-  PyObject *obj;
-  if (!PyArg_ParseTuple(args,(char*)"O:swigregister", &obj)) return NULL;
-  SWIG_TypeNewClientData(SWIGTYPE_p_OGRGeometryShadow, SWIG_NewClientData(obj));
-  return SWIG_Py_Void();
-}
-
-SWIGINTERN PyObject *_wrap_GetDriverCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_IsSurface(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
+  PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)":GetDriverCount")) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_IsSurface",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsSurface" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGetDriverCount();
+    result = (int)OGR_GT_IsSurface(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19852,16 +22944,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_GetOpenDSCount(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_IsNonLinear(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
+  PyObject * obj0 = 0 ;
   int result;
   
-  if (!PyArg_ParseTuple(args,(char *)":GetOpenDSCount")) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_IsNonLinear",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_IsNonLinear" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (int)OGRGetOpenDSCount();
+    result = (int)OGR_GT_IsNonLinear(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19876,25 +22977,25 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_SetGenerate_DB2_V72_BYTE_ORDER(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_GetCollection(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  int arg1 ;
+  OGRwkbGeometryType arg1 ;
   int val1 ;
   int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
-  OGRErr result;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:SetGenerate_DB2_V72_BYTE_ORDER",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_GetCollection",&obj0)) SWIG_fail;
   ecode1 = SWIG_AsVal_int(obj0, &val1);
   if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetGenerate_DB2_V72_BYTE_ORDER" "', argument " "1"" of type '" "int""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetCollection" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
   } 
-  arg1 = static_cast< int >(val1);
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OGRSetGenerate_DB2_V72_BYTE_ORDER(arg1);
+    result = (OGRwkbGeometryType)OGR_GT_GetCollection(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19902,38 +23003,32 @@ SWIGINTERN PyObject *_wrap_SetGenerate_DB2_V72_BYTE_ORDER(PyObject *SWIGUNUSEDPA
       }
     }
   }
-  {
-    /* %typemap(out) OGRErr */
-    if ( result != 0 && bUseExceptions) {
-      PyErr_SetString( PyExc_RuntimeError, OGRErrMessages(result) );
-      SWIG_fail;
-    }
-  }
-  {
-    /* %typemap(ret) OGRErr */
-    if (resultobj == Py_None ) {
-      Py_DECREF(resultobj);
-      resultobj = 0;
-    }
-    if (resultobj == 0) {
-      resultobj = PyInt_FromLong( result );
-    }
-  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_RegisterAll(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_GetCurve(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
+  OGRwkbGeometryType arg1 ;
+  int val1 ;
+  int ecode1 = 0 ;
+  PyObject * obj0 = 0 ;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)":RegisterAll")) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_GetCurve",&obj0)) SWIG_fail;
+  ecode1 = SWIG_AsVal_int(obj0, &val1);
+  if (!SWIG_IsOK(ecode1)) {
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetCurve" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+  } 
+  arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    OGRRegisterAll();
+    result = (OGRwkbGeometryType)OGR_GT_GetCurve(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19941,32 +23036,32 @@ SWIGINTERN PyObject *_wrap_RegisterAll(PyObject *SWIGUNUSEDPARM(self), PyObject
       }
     }
   }
-  resultobj = SWIG_Py_Void();
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GeometryTypeToName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_GT_GetLinear(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OGRwkbGeometryType arg1 ;
   int val1 ;
   int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
+  OGRwkbGeometryType result;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GeometryTypeToName",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:GT_GetLinear",&obj0)) SWIG_fail;
   ecode1 = SWIG_AsVal_int(obj0, &val1);
   if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GeometryTypeToName" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GT_GetLinear" "', argument " "1"" of type '" "OGRwkbGeometryType""'");
   } 
   arg1 = static_cast< OGRwkbGeometryType >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGRGeometryTypeToName(arg1);
+    result = (OGRwkbGeometryType)OGR_GT_GetLinear(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -19974,32 +23069,31 @@ SWIGINTERN PyObject *_wrap_GeometryTypeToName(PyObject *SWIGUNUSEDPARM(self), Py
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
 }
 
 
-SWIGINTERN PyObject *_wrap_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+SWIGINTERN PyObject *_wrap_SetNonLinearGeometriesEnabledFlag(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
-  OGRFieldType arg1 ;
+  int arg1 ;
   int val1 ;
   int ecode1 = 0 ;
   PyObject * obj0 = 0 ;
-  char *result = 0 ;
   
-  if (!PyArg_ParseTuple(args,(char *)"O:GetFieldTypeName",&obj0)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"O:SetNonLinearGeometriesEnabledFlag",&obj0)) SWIG_fail;
   ecode1 = SWIG_AsVal_int(obj0, &val1);
   if (!SWIG_IsOK(ecode1)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "GetFieldTypeName" "', argument " "1"" of type '" "OGRFieldType""'");
+    SWIG_exception_fail(SWIG_ArgError(ecode1), "in method '" "SetNonLinearGeometriesEnabledFlag" "', argument " "1"" of type '" "int""'");
   } 
-  arg1 = static_cast< OGRFieldType >(val1);
+  arg1 = static_cast< int >(val1);
   {
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (char *)OGR_GetFieldTypeName(arg1);
+    OGRSetNonLinearGeometriesEnabledFlag(arg1);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -20007,7 +23101,31 @@ SWIGINTERN PyObject *_wrap_GetFieldTypeName(PyObject *SWIGUNUSEDPARM(self), PyOb
       }
     }
   }
-  resultobj = SWIG_FromCharPtr((const char *)result);
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_GetNonLinearGeometriesEnabledFlag(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  int result;
+  
+  if (!PyArg_ParseTuple(args,(char *)":GetNonLinearGeometriesEnabledFlag")) SWIG_fail;
+  {
+    if ( bUseExceptions ) {
+      CPLErrorReset();
+    }
+    result = (int)OGRGetNonLinearGeometriesEnabledFlag();
+    if ( bUseExceptions ) {
+      CPLErr eclass = CPLGetLastErrorType();
+      if ( eclass == CE_Failure || eclass == CE_Fatal ) {
+        SWIG_exception( SWIG_RuntimeError, CPLGetLastErrorMsg() );
+      }
+    }
+  }
+  resultobj = SWIG_From_int(static_cast< int >(result));
   return resultobj;
 fail:
   return NULL;
@@ -20406,6 +23524,18 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"GetUseExceptions", _wrap_GetUseExceptions, METH_VARARGS, (char *)"GetUseExceptions() -> int"},
 	 { (char *)"UseExceptions", _wrap_UseExceptions, METH_VARARGS, (char *)"UseExceptions()"},
 	 { (char *)"DontUseExceptions", _wrap_DontUseExceptions, METH_VARARGS, (char *)"DontUseExceptions()"},
+	 { (char *)"MajorObject_GetDescription", _wrap_MajorObject_GetDescription, METH_VARARGS, (char *)"MajorObject_GetDescription(MajorObject self) -> char"},
+	 { (char *)"MajorObject_SetDescription", _wrap_MajorObject_SetDescription, METH_VARARGS, (char *)"MajorObject_SetDescription(MajorObject self, char pszNewDesc)"},
+	 { (char *)"MajorObject_GetMetadataDomainList", _wrap_MajorObject_GetMetadataDomainList, METH_VARARGS, (char *)"MajorObject_GetMetadataDomainList(MajorObject self) -> char"},
+	 { (char *)"MajorObject_GetMetadata_Dict", _wrap_MajorObject_GetMetadata_Dict, METH_VARARGS, (char *)"MajorObject_GetMetadata_Dict(MajorObject self, char pszDomain = \"\") -> char"},
+	 { (char *)"MajorObject_GetMetadata_List", _wrap_MajorObject_GetMetadata_List, METH_VARARGS, (char *)"MajorObject_GetMetadata_List(MajorObject self, char pszDomain = \"\") -> char"},
+	 { (char *)"MajorObject_SetMetadata", _wrap_MajorObject_SetMetadata, METH_VARARGS, (char *)"\n"
+		"SetMetadata(char papszMetadata, char pszDomain = \"\") -> CPLErr\n"
+		"MajorObject_SetMetadata(MajorObject self, char pszMetadataString, char pszDomain = \"\") -> CPLErr\n"
+		""},
+	 { (char *)"MajorObject_GetMetadataItem", _wrap_MajorObject_GetMetadataItem, METH_VARARGS, (char *)"MajorObject_GetMetadataItem(MajorObject self, char pszName, char pszDomain = \"\") -> char"},
+	 { (char *)"MajorObject_SetMetadataItem", _wrap_MajorObject_SetMetadataItem, METH_VARARGS, (char *)"MajorObject_SetMetadataItem(MajorObject self, char pszName, char pszValue, char pszDomain = \"\") -> CPLErr"},
+	 { (char *)"MajorObject_swigregister", MajorObject_swigregister, METH_VARARGS, NULL},
 	 { (char *)"new_StyleTable", _wrap_new_StyleTable, METH_VARARGS, (char *)"new_StyleTable() -> StyleTable"},
 	 { (char *)"delete_StyleTable", _wrap_delete_StyleTable, METH_VARARGS, (char *)"delete_StyleTable(StyleTable self)"},
 	 { (char *)"StyleTable_AddStyle", _wrap_StyleTable_AddStyle, METH_VARARGS, (char *)"StyleTable_AddStyle(StyleTable self, char pszName, char pszStyleString) -> int"},
@@ -20724,6 +23854,7 @@ static PyMethodDef SwigMethods[] = {
 		"OGRERR_NONE if no error occurs (even if nothing is done) or an error\n"
 		"code. \n"
 		""},
+	 { (char *)"DataSource_FlushCache", _wrap_DataSource_FlushCache, METH_VARARGS, (char *)"DataSource_FlushCache(DataSource self)"},
 	 { (char *)"DataSource_CreateLayer", (PyCFunction) _wrap_DataSource_CreateLayer, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"DataSource_CreateLayer(DataSource self, char name, SpatialReference srs = None, \n"
 		"    OGRwkbGeometryType geom_type = wkbUnknown, \n"
@@ -20887,7 +24018,7 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"pszDialect:  allows control of the statement dialect. If set to NULL,\n"
 		"the OGR SQL engine will be used, except for RDBMS drivers that will\n"
-		"use their dedicated SQL engine, unless OGRSQL is explicitely passed as\n"
+		"use their dedicated SQL engine, unless OGRSQL is explicitly passed as\n"
 		"the dialect.\n"
 		"\n"
 		"an handle to a OGRLayer containing the results of the query.\n"
@@ -20930,6 +24061,9 @@ static PyMethodDef SwigMethods[] = {
 		"OGR_DS_SetStyleTable(OGRDataSourceH hDS, OGRStyleTableH hStyleTable)\n"
 		"\n"
 		""},
+	 { (char *)"DataSource_StartTransaction", (PyCFunction) _wrap_DataSource_StartTransaction, METH_VARARGS | METH_KEYWORDS, (char *)"DataSource_StartTransaction(DataSource self, int force = True) -> OGRErr"},
+	 { (char *)"DataSource_CommitTransaction", _wrap_DataSource_CommitTransaction, METH_VARARGS, (char *)"DataSource_CommitTransaction(DataSource self) -> OGRErr"},
+	 { (char *)"DataSource_RollbackTransaction", _wrap_DataSource_RollbackTransaction, METH_VARARGS, (char *)"DataSource_RollbackTransaction(DataSource self) -> OGRErr"},
 	 { (char *)"DataSource_swigregister", DataSource_swigregister, METH_VARARGS, NULL},
 	 { (char *)"Layer_GetRefCount", _wrap_Layer_GetRefCount, METH_VARARGS, (char *)"\n"
 		"Layer_GetRefCount(Layer self) -> int\n"
@@ -21179,7 +24313,7 @@ static PyMethodDef SwigMethods[] = {
 		"fid column name. \n"
 		""},
 	 { (char *)"Layer_GetFeature", _wrap_Layer_GetFeature, METH_VARARGS, (char *)"\n"
-		"Layer_GetFeature(Layer self, long fid) -> Feature\n"
+		"Layer_GetFeature(Layer self, GIntBig fid) -> Feature\n"
 		"\n"
 		"OGRFeatureH\n"
 		"OGR_L_GetFeature(OGRLayerH hLayer, long nFeatureId)\n"
@@ -21246,7 +24380,7 @@ static PyMethodDef SwigMethods[] = {
 		"an handle to a feature, or NULL if no more features are available. \n"
 		""},
 	 { (char *)"Layer_SetNextByIndex", _wrap_Layer_SetNextByIndex, METH_VARARGS, (char *)"\n"
-		"Layer_SetNextByIndex(Layer self, long new_index) -> OGRErr\n"
+		"Layer_SetNextByIndex(Layer self, GIntBig new_index) -> OGRErr\n"
 		"\n"
 		"OGRErr\n"
 		"OGR_L_SetNextByIndex(OGRLayerH hLayer, long nIndex)\n"
@@ -21332,7 +24466,7 @@ static PyMethodDef SwigMethods[] = {
 		"OGRERR_NONE on success. \n"
 		""},
 	 { (char *)"Layer_DeleteFeature", _wrap_Layer_DeleteFeature, METH_VARARGS, (char *)"\n"
-		"Layer_DeleteFeature(Layer self, long fid) -> OGRErr\n"
+		"Layer_DeleteFeature(Layer self, GIntBig fid) -> OGRErr\n"
 		"\n"
 		"OGRErr\n"
 		"OGR_L_DeleteFeature(OGRLayerH hDS, long nFID)\n"
@@ -21408,7 +24542,7 @@ static PyMethodDef SwigMethods[] = {
 		"an handle to the feature definition. \n"
 		""},
 	 { (char *)"Layer_GetFeatureCount", (PyCFunction) _wrap_Layer_GetFeatureCount, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
-		"Layer_GetFeatureCount(Layer self, int force = 1) -> int\n"
+		"Layer_GetFeatureCount(Layer self, int force = 1) -> GIntBig\n"
 		"\n"
 		"int\n"
 		"OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)\n"
@@ -22198,6 +25332,10 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"the field value. \n"
 		""},
+	 { (char *)"Feature_GetFieldAsInteger64", _wrap_Feature_GetFieldAsInteger64, METH_VARARGS, (char *)"\n"
+		"GetFieldAsInteger64(int id) -> GIntBig\n"
+		"Feature_GetFieldAsInteger64(Feature self, char name) -> GIntBig\n"
+		""},
 	 { (char *)"Feature_GetFieldAsDouble", _wrap_Feature_GetFieldAsDouble, METH_VARARGS, (char *)"\n"
 		"GetFieldAsDouble(int id) -> double\n"
 		"Feature_GetFieldAsDouble(Feature self, char name) -> double\n"
@@ -22290,6 +25428,7 @@ static PyMethodDef SwigMethods[] = {
 		"freed. Its lifetime may be very brief. If *pnCount is zero on return\n"
 		"the returned pointer may be NULL or non-NULL. \n"
 		""},
+	 { (char *)"Feature_GetFieldAsInteger64List", _wrap_Feature_GetFieldAsInteger64List, METH_VARARGS, (char *)"Feature_GetFieldAsInteger64List(Feature self, int id)"},
 	 { (char *)"Feature_GetFieldAsDoubleList", _wrap_Feature_GetFieldAsDoubleList, METH_VARARGS, (char *)"\n"
 		"Feature_GetFieldAsDoubleList(Feature self, int id)\n"
 		"\n"
@@ -22343,6 +25482,32 @@ static PyMethodDef SwigMethods[] = {
 		"the field value. This list is internal, and should not be modified, or\n"
 		"freed. Its lifetime may be very brief. \n"
 		""},
+	 { (char *)"Feature_GetFieldAsBinary", _wrap_Feature_GetFieldAsBinary, METH_VARARGS, (char *)"\n"
+		"GetFieldAsBinary(int id) -> OGRErr\n"
+		"Feature_GetFieldAsBinary(Feature self, char name) -> OGRErr\n"
+		"\n"
+		"GByte*\n"
+		"OGR_F_GetFieldAsBinary(OGRFeatureH hFeat, int iField, int *pnBytes)\n"
+		"\n"
+		"Fetch field value as binary.\n"
+		"\n"
+		"Currently this method only works for OFTBinary fields.\n"
+		"\n"
+		"This function is the same as the C++ method\n"
+		"OGRFeature::GetFieldAsBinary().\n"
+		"\n"
+		"Parameters:\n"
+		"-----------\n"
+		"\n"
+		"hFeat:  handle to the feature that owned the field.\n"
+		"\n"
+		"iField:  the field to fetch, from 0 to GetFieldCount()-1.\n"
+		"\n"
+		"pnBytes:  location to place count of bytes returned.\n"
+		"\n"
+		"the field value. This list is internal, and should not be modified, or\n"
+		"freed. Its lifetime may be very brief. \n"
+		""},
 	 { (char *)"Feature_IsFieldSet", _wrap_Feature_IsFieldSet, METH_VARARGS, (char *)"\n"
 		"IsFieldSet(int id) -> bool\n"
 		"Feature_IsFieldSet(Feature self, char name) -> bool\n"
@@ -22387,7 +25552,7 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { (char *)"Feature_GetGeomFieldIndex", _wrap_Feature_GetGeomFieldIndex, METH_VARARGS, (char *)"Feature_GetGeomFieldIndex(Feature self, char name) -> int"},
 	 { (char *)"Feature_GetFID", _wrap_Feature_GetFID, METH_VARARGS, (char *)"\n"
-		"Feature_GetFID(Feature self) -> int\n"
+		"Feature_GetFID(Feature self) -> GIntBig\n"
 		"\n"
 		"long OGR_F_GetFID(OGRFeatureH hFeat)\n"
 		"\n"
@@ -22404,7 +25569,7 @@ static PyMethodDef SwigMethods[] = {
 		"feature id or OGRNullFID if none has been assigned. \n"
 		""},
 	 { (char *)"Feature_SetFID", _wrap_Feature_SetFID, METH_VARARGS, (char *)"\n"
-		"Feature_SetFID(Feature self, int fid) -> OGRErr\n"
+		"Feature_SetFID(Feature self, GIntBig fid) -> OGRErr\n"
 		"\n"
 		"OGRErr OGR_F_SetFID(OGRFeatureH hFeat,\n"
 		"long nFID)\n"
@@ -22467,17 +25632,16 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"iField:  the field to unset. \n"
 		""},
+	 { (char *)"Feature_SetFieldInteger64", _wrap_Feature_SetFieldInteger64, METH_VARARGS, (char *)"Feature_SetFieldInteger64(Feature self, int id, GIntBig value)"},
 	 { (char *)"Feature_SetField", _wrap_Feature_SetField, METH_VARARGS, (char *)"\n"
 		"SetField(int id, char value)\n"
 		"SetField(char name, char value)\n"
-		"SetField(int id, int value)\n"
-		"SetField(char name, int value)\n"
 		"SetField(int id, double value)\n"
 		"SetField(char name, double value)\n"
 		"SetField(int id, int year, int month, int day, int hour, int minute, \n"
-		"    int second, int tzflag)\n"
+		"    float second, int tzflag)\n"
 		"Feature_SetField(Feature self, char name, int year, int month, int day, \n"
-		"    int hour, int minute, int second, int tzflag)\n"
+		"    int hour, int minute, float second, int tzflag)\n"
 		""},
 	 { (char *)"Feature_SetFieldIntegerList", _wrap_Feature_SetFieldIntegerList, METH_VARARGS, (char *)"\n"
 		"Feature_SetFieldIntegerList(Feature self, int id, int nList)\n"
@@ -22503,6 +25667,7 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"panValues:  the values to assign. \n"
 		""},
+	 { (char *)"Feature_SetFieldInteger64List", _wrap_Feature_SetFieldInteger64List, METH_VARARGS, (char *)"Feature_SetFieldInteger64List(Feature self, int id, int nList)"},
 	 { (char *)"Feature_SetFieldDoubleList", _wrap_Feature_SetFieldDoubleList, METH_VARARGS, (char *)"\n"
 		"Feature_SetFieldDoubleList(Feature self, int id, int nList)\n"
 		"\n"
@@ -22671,6 +25836,32 @@ static PyMethodDef SwigMethods[] = {
 		"GetFieldType(int id) -> OGRFieldType\n"
 		"Feature_GetFieldType(Feature self, char name) -> OGRFieldType\n"
 		""},
+	 { (char *)"Feature_Validate", _wrap_Feature_Validate, METH_VARARGS, (char *)"Feature_Validate(Feature self, int flags = OGR_F_VAL_ALL, int bEmitError = TRUE) -> int"},
+	 { (char *)"Feature_FillUnsetWithDefault", _wrap_Feature_FillUnsetWithDefault, METH_VARARGS, (char *)"Feature_FillUnsetWithDefault(Feature self, int bNotNullableOnly = True, char options = None)"},
+	 { (char *)"Feature_SetFieldString", _wrap_Feature_SetFieldString, METH_VARARGS, (char *)"\n"
+		"Feature_SetFieldString(Feature self, int id, char value)\n"
+		"\n"
+		"void\n"
+		"OGR_F_SetFieldString(OGRFeatureH hFeat, int iField, const char\n"
+		"*pszValue)\n"
+		"\n"
+		"Set field to string value.\n"
+		"\n"
+		"OFTInteger fields will be set based on an atoi() conversion of the\n"
+		"string. OFTReal fields will be set based on an atof() conversion of\n"
+		"the string. Other field types may be unaffected.\n"
+		"\n"
+		"This function is the same as the C++ method OGRFeature::SetField().\n"
+		"\n"
+		"Parameters:\n"
+		"-----------\n"
+		"\n"
+		"hFeat:  handle to the feature that owned the field.\n"
+		"\n"
+		"iField:  the field to fetch, from 0 to GetFieldCount()-1.\n"
+		"\n"
+		"pszValue:  the value to assign. \n"
+		""},
 	 { (char *)"Feature_swigregister", Feature_swigregister, METH_VARARGS, NULL},
 	 { (char *)"delete_FeatureDefn", _wrap_delete_FeatureDefn, METH_VARARGS, (char *)"delete_FeatureDefn(FeatureDefn self)"},
 	 { (char *)"new_FeatureDefn", (PyCFunction) _wrap_new_FeatureDefn, METH_VARARGS | METH_KEYWORDS, (char *)"new_FeatureDefn(char name_null_ok = None) -> FeatureDefn"},
@@ -23003,6 +26194,8 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"eType:  the new field type. \n"
 		""},
+	 { (char *)"FieldDefn_GetSubType", _wrap_FieldDefn_GetSubType, METH_VARARGS, (char *)"FieldDefn_GetSubType(FieldDefn self) -> OGRFieldSubType"},
+	 { (char *)"FieldDefn_SetSubType", _wrap_FieldDefn_SetSubType, METH_VARARGS, (char *)"FieldDefn_SetSubType(FieldDefn self, OGRFieldSubType type)"},
 	 { (char *)"FieldDefn_GetJustify", _wrap_FieldDefn_GetJustify, METH_VARARGS, (char *)"\n"
 		"FieldDefn_GetJustify(FieldDefn self) -> OGRJustification\n"
 		"\n"
@@ -23148,6 +26341,11 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"ignore:  ignore state \n"
 		""},
+	 { (char *)"FieldDefn_IsNullable", _wrap_FieldDefn_IsNullable, METH_VARARGS, (char *)"FieldDefn_IsNullable(FieldDefn self) -> int"},
+	 { (char *)"FieldDefn_SetNullable", _wrap_FieldDefn_SetNullable, METH_VARARGS, (char *)"FieldDefn_SetNullable(FieldDefn self, int bNullable)"},
+	 { (char *)"FieldDefn_GetDefault", _wrap_FieldDefn_GetDefault, METH_VARARGS, (char *)"FieldDefn_GetDefault(FieldDefn self) -> char"},
+	 { (char *)"FieldDefn_SetDefault", _wrap_FieldDefn_SetDefault, METH_VARARGS, (char *)"FieldDefn_SetDefault(FieldDefn self, char pszValue)"},
+	 { (char *)"FieldDefn_IsDefaultDriverSpecific", _wrap_FieldDefn_IsDefaultDriverSpecific, METH_VARARGS, (char *)"FieldDefn_IsDefaultDriverSpecific(FieldDefn self) -> int"},
 	 { (char *)"FieldDefn_swigregister", FieldDefn_swigregister, METH_VARARGS, NULL},
 	 { (char *)"delete_GeomFieldDefn", _wrap_delete_GeomFieldDefn, METH_VARARGS, (char *)"delete_GeomFieldDefn(GeomFieldDefn self)"},
 	 { (char *)"new_GeomFieldDefn", (PyCFunction) _wrap_new_GeomFieldDefn, METH_VARARGS | METH_KEYWORDS, (char *)"new_GeomFieldDefn(char name_null_ok = \"\", OGRwkbGeometryType field_type = wkbUnknown) -> GeomFieldDefn"},
@@ -23160,6 +26358,8 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"GeomFieldDefn_SetSpatialRef", _wrap_GeomFieldDefn_SetSpatialRef, METH_VARARGS, (char *)"GeomFieldDefn_SetSpatialRef(GeomFieldDefn self, SpatialReference srs)"},
 	 { (char *)"GeomFieldDefn_IsIgnored", _wrap_GeomFieldDefn_IsIgnored, METH_VARARGS, (char *)"GeomFieldDefn_IsIgnored(GeomFieldDefn self) -> int"},
 	 { (char *)"GeomFieldDefn_SetIgnored", _wrap_GeomFieldDefn_SetIgnored, METH_VARARGS, (char *)"GeomFieldDefn_SetIgnored(GeomFieldDefn self, int bIgnored)"},
+	 { (char *)"GeomFieldDefn_IsNullable", _wrap_GeomFieldDefn_IsNullable, METH_VARARGS, (char *)"GeomFieldDefn_IsNullable(GeomFieldDefn self) -> int"},
+	 { (char *)"GeomFieldDefn_SetNullable", _wrap_GeomFieldDefn_SetNullable, METH_VARARGS, (char *)"GeomFieldDefn_SetNullable(GeomFieldDefn self, int bNullable)"},
 	 { (char *)"GeomFieldDefn_swigregister", GeomFieldDefn_swigregister, METH_VARARGS, NULL},
 	 { (char *)"CreateGeometryFromWkb", (PyCFunction) _wrap_CreateGeometryFromWkb, METH_VARARGS | METH_KEYWORDS, (char *)"CreateGeometryFromWkb(int len, SpatialReference reference = None) -> Geometry"},
 	 { (char *)"CreateGeometryFromWkt", (PyCFunction) _wrap_CreateGeometryFromWkt, METH_VARARGS | METH_KEYWORDS, (char *)"CreateGeometryFromWkt(char val, SpatialReference reference = None) -> Geometry"},
@@ -23180,6 +26380,7 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"ForceToMultiPolygon", _wrap_ForceToMultiPolygon, METH_VARARGS, (char *)"ForceToMultiPolygon(Geometry geom_in) -> Geometry"},
 	 { (char *)"ForceToMultiPoint", _wrap_ForceToMultiPoint, METH_VARARGS, (char *)"ForceToMultiPoint(Geometry geom_in) -> Geometry"},
 	 { (char *)"ForceToMultiLineString", _wrap_ForceToMultiLineString, METH_VARARGS, (char *)"ForceToMultiLineString(Geometry geom_in) -> Geometry"},
+	 { (char *)"ForceTo", _wrap_ForceTo, METH_VARARGS, (char *)"ForceTo(Geometry geom_in, OGRwkbGeometryType eTargetType, char options = None) -> Geometry"},
 	 { (char *)"delete_Geometry", _wrap_delete_Geometry, METH_VARARGS, (char *)"delete_Geometry(Geometry self)"},
 	 { (char *)"new_Geometry", (PyCFunction) _wrap_new_Geometry, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"new_Geometry(OGRwkbGeometryType type = wkbUnknown, char wkt = None, \n"
@@ -23208,6 +26409,7 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"Currently OGRERR_NONE is always returned. \n"
 		""},
+	 { (char *)"Geometry_ExportToIsoWkt", _wrap_Geometry_ExportToIsoWkt, METH_VARARGS, (char *)"Geometry_ExportToIsoWkt(Geometry self) -> OGRErr"},
 	 { (char *)"Geometry_ExportToWkb", (PyCFunction) _wrap_Geometry_ExportToWkb, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
 		"Geometry_ExportToWkb(Geometry self, OGRwkbByteOrder byte_order = wkbXDR) -> OGRErr\n"
 		"\n"
@@ -23236,6 +26438,7 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"Currently OGRERR_NONE is always returned. \n"
 		""},
+	 { (char *)"Geometry_ExportToIsoWkb", (PyCFunction) _wrap_Geometry_ExportToIsoWkb, METH_VARARGS | METH_KEYWORDS, (char *)"Geometry_ExportToIsoWkb(Geometry self, OGRwkbByteOrder byte_order = wkbXDR) -> OGRErr"},
 	 { (char *)"Geometry_ExportToGML", (PyCFunction) _wrap_Geometry_ExportToGML, METH_VARARGS | METH_KEYWORDS, (char *)"Geometry_ExportToGML(Geometry self, char options = None) -> retStringAndCPLFree"},
 	 { (char *)"Geometry_ExportToKML", _wrap_Geometry_ExportToKML, METH_VARARGS, (char *)"Geometry_ExportToKML(Geometry self, char altitude_mode = None) -> retStringAndCPLFree"},
 	 { (char *)"Geometry_ExportToJson", (PyCFunction) _wrap_Geometry_ExportToJson, METH_VARARGS | METH_KEYWORDS, (char *)"Geometry_ExportToJson(Geometry self, char options = None) -> retStringAndCPLFree"},
@@ -24289,6 +27492,13 @@ static PyMethodDef SwigMethods[] = {
 		"\n"
 		"0 for points, 1 for lines and 2 for surfaces. \n"
 		""},
+	 { (char *)"Geometry_HasCurveGeometry", _wrap_Geometry_HasCurveGeometry, METH_VARARGS, (char *)"Geometry_HasCurveGeometry(Geometry self, int bLookForCircular = True) -> int"},
+	 { (char *)"Geometry_GetLinearGeometry", (PyCFunction) _wrap_Geometry_GetLinearGeometry, METH_VARARGS | METH_KEYWORDS, (char *)"\n"
+		"Geometry_GetLinearGeometry(Geometry self, double dfMaxAngleStepSizeDegrees = 0.0, \n"
+		"    char options = None) -> Geometry\n"
+		""},
+	 { (char *)"Geometry_GetCurveGeometry", (PyCFunction) _wrap_Geometry_GetCurveGeometry, METH_VARARGS | METH_KEYWORDS, (char *)"Geometry_GetCurveGeometry(Geometry self, char options = None) -> Geometry"},
+	 { (char *)"Geometry_Value", _wrap_Geometry_Value, METH_VARARGS, (char *)"Geometry_Value(Geometry self, double dfDistance) -> Geometry"},
 	 { (char *)"Geometry_swigregister", Geometry_swigregister, METH_VARARGS, NULL},
 	 { (char *)"GetDriverCount", _wrap_GetDriverCount, METH_VARARGS, (char *)"GetDriverCount() -> int"},
 	 { (char *)"GetOpenDSCount", _wrap_GetOpenDSCount, METH_VARARGS, (char *)"GetOpenDSCount() -> int"},
@@ -24296,6 +27506,20 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"RegisterAll", _wrap_RegisterAll, METH_VARARGS, (char *)"RegisterAll()"},
 	 { (char *)"GeometryTypeToName", _wrap_GeometryTypeToName, METH_VARARGS, (char *)"GeometryTypeToName(OGRwkbGeometryType eType) -> char"},
 	 { (char *)"GetFieldTypeName", _wrap_GetFieldTypeName, METH_VARARGS, (char *)"GetFieldTypeName(OGRFieldType type) -> char"},
+	 { (char *)"GetFieldSubTypeName", _wrap_GetFieldSubTypeName, METH_VARARGS, (char *)"GetFieldSubTypeName(OGRFieldSubType type) -> char"},
+	 { (char *)"GT_Flatten", _wrap_GT_Flatten, METH_VARARGS, (char *)"GT_Flatten(OGRwkbGeometryType eType) -> OGRwkbGeometryType"},
+	 { (char *)"GT_SetZ", _wrap_GT_SetZ, METH_VARARGS, (char *)"GT_SetZ(OGRwkbGeometryType eType) -> OGRwkbGeometryType"},
+	 { (char *)"GT_SetModifier", _wrap_GT_SetModifier, METH_VARARGS, (char *)"GT_SetModifier(OGRwkbGeometryType eType, int bSetZ, int bSetM = True) -> OGRwkbGeometryType"},
+	 { (char *)"GT_HasZ", _wrap_GT_HasZ, METH_VARARGS, (char *)"GT_HasZ(OGRwkbGeometryType eType) -> int"},
+	 { (char *)"GT_IsSubClassOf", _wrap_GT_IsSubClassOf, METH_VARARGS, (char *)"GT_IsSubClassOf(OGRwkbGeometryType eType, OGRwkbGeometryType eSuperType) -> int"},
+	 { (char *)"GT_IsCurve", _wrap_GT_IsCurve, METH_VARARGS, (char *)"GT_IsCurve(OGRwkbGeometryType arg0) -> int"},
+	 { (char *)"GT_IsSurface", _wrap_GT_IsSurface, METH_VARARGS, (char *)"GT_IsSurface(OGRwkbGeometryType arg0) -> int"},
+	 { (char *)"GT_IsNonLinear", _wrap_GT_IsNonLinear, METH_VARARGS, (char *)"GT_IsNonLinear(OGRwkbGeometryType arg0) -> int"},
+	 { (char *)"GT_GetCollection", _wrap_GT_GetCollection, METH_VARARGS, (char *)"GT_GetCollection(OGRwkbGeometryType eType) -> OGRwkbGeometryType"},
+	 { (char *)"GT_GetCurve", _wrap_GT_GetCurve, METH_VARARGS, (char *)"GT_GetCurve(OGRwkbGeometryType eType) -> OGRwkbGeometryType"},
+	 { (char *)"GT_GetLinear", _wrap_GT_GetLinear, METH_VARARGS, (char *)"GT_GetLinear(OGRwkbGeometryType eType) -> OGRwkbGeometryType"},
+	 { (char *)"SetNonLinearGeometriesEnabledFlag", _wrap_SetNonLinearGeometriesEnabledFlag, METH_VARARGS, (char *)"SetNonLinearGeometriesEnabledFlag(int bFlag)"},
+	 { (char *)"GetNonLinearGeometriesEnabledFlag", _wrap_GetNonLinearGeometriesEnabledFlag, METH_VARARGS, (char *)"GetNonLinearGeometriesEnabledFlag() -> int"},
 	 { (char *)"GetOpenDS", _wrap_GetOpenDS, METH_VARARGS, (char *)"GetOpenDS(int ds_number) -> DataSource"},
 	 { (char *)"Open", (PyCFunction) _wrap_Open, METH_VARARGS | METH_KEYWORDS, (char *)"Open(char utf8_path, int update = 0) -> DataSource"},
 	 { (char *)"OpenShared", (PyCFunction) _wrap_OpenShared, METH_VARARGS | METH_KEYWORDS, (char *)"OpenShared(char utf8_path, int update = 0) -> DataSource"},
@@ -24309,6 +27533,16 @@ static PyMethodDef SwigMethods[] = {
 
 /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */
 
+static void *_p_OGRDriverShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRDriverShadow *) x));
+}
+static void *_p_OGRLayerShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRLayerShadow *) x));
+}
+static void *_p_OGRDataSourceShadowTo_p_GDALMajorObjectShadow(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((GDALMajorObjectShadow *)  ((OGRDataSourceShadow *) x));
+}
+static swig_type_info _swigt__p_GDALMajorObjectShadow = {"_p_GDALMajorObjectShadow", "GDALMajorObjectShadow *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GDALProgressFunc = {"_p_GDALProgressFunc", "GDALProgressFunc *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_GIntBig = {"_p_GIntBig", "GIntBig *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_OGRDataSourceShadow = {"_p_OGRDataSourceShadow", "OGRDataSourceShadow *", 0, 0, (void*)0, 0};
@@ -24325,12 +27559,15 @@ static swig_type_info _swigt__p_OSRSpatialReferenceShadow = {"_p_OSRSpatialRefer
 static swig_type_info _swigt__p_char = {"_p_char", "char *|retStringAndCPLFree *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_double = {"_p_double", "double *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_f_double_p_q_const__char_p_void__int = {"_p_f_double_p_q_const__char_p_void__int", "int (*)(double,char const *,void *)", 0, 0, (void*)0, 0};
-static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldType *|int *|OGRwkbGeometryType *|OGRJustification *|OGRwkbByteOrder *|OGRErr *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_float = {"_p_float", "float *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_int = {"_p_int", "OGRFieldSubType *|OGRFieldType *|CPLErr *|int *|OGRwkbGeometryType *|OGRJustification *|OGRwkbByteOrder *|OGRErr *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_p_GIntBig = {"_p_p_GIntBig", "GIntBig **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_char = {"_p_p_char", "char **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_double = {"_p_p_double", "double **", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_p_int = {"_p_p_int", "int **", 0, 0, (void*)0, 0};
 
 static swig_type_info *swig_type_initial[] = {
+  &_swigt__p_GDALMajorObjectShadow,
   &_swigt__p_GDALProgressFunc,
   &_swigt__p_GIntBig,
   &_swigt__p_OGRDataSourceShadow,
@@ -24347,12 +27584,15 @@ static swig_type_info *swig_type_initial[] = {
   &_swigt__p_char,
   &_swigt__p_double,
   &_swigt__p_f_double_p_q_const__char_p_void__int,
+  &_swigt__p_float,
   &_swigt__p_int,
+  &_swigt__p_p_GIntBig,
   &_swigt__p_p_char,
   &_swigt__p_p_double,
   &_swigt__p_p_int,
 };
 
+static swig_cast_info _swigc__p_GDALMajorObjectShadow[] = {  {&_swigt__p_GDALMajorObjectShadow, 0, 0, 0},  {&_swigt__p_OGRDriverShadow, _p_OGRDriverShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRLayerShadow, _p_OGRLayerShadowTo_p_GDALMajorObjectShadow, 0, 0},  {&_swigt__p_OGRDataSourceShadow, _p_OGRDataSourceShadowTo_p_GDALMajorObjectShadow, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GDALProgressFunc[] = {  {&_swigt__p_GDALProgressFunc, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_GIntBig[] = {  {&_swigt__p_GIntBig, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_OGRDataSourceShadow[] = {  {&_swigt__p_OGRDataSourceShadow, 0, 0, 0},{0, 0, 0, 0}};
@@ -24369,12 +27609,15 @@ static swig_cast_info _swigc__p_OSRSpatialReferenceShadow[] = {  {&_swigt__p_OSR
 static swig_cast_info _swigc__p_char[] = {  {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_double[] = {  {&_swigt__p_double, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_f_double_p_q_const__char_p_void__int[] = {  {&_swigt__p_f_double_p_q_const__char_p_void__int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_float[] = {  {&_swigt__p_float, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_p_GIntBig[] = {  {&_swigt__p_p_GIntBig, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_char[] = {  {&_swigt__p_p_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_double[] = {  {&_swigt__p_p_double, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_p_int[] = {  {&_swigt__p_p_int, 0, 0, 0},{0, 0, 0, 0}};
 
 static swig_cast_info *swig_cast_initial[] = {
+  _swigc__p_GDALMajorObjectShadow,
   _swigc__p_GDALProgressFunc,
   _swigc__p_GIntBig,
   _swigc__p_OGRDataSourceShadow,
@@ -24391,7 +27634,9 @@ static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_char,
   _swigc__p_double,
   _swigc__p_f_double_p_q_const__char_p_void__int,
+  _swigc__p_float,
   _swigc__p_int,
+  _swigc__p_p_GIntBig,
   _swigc__p_p_char,
   _swigc__p_p_double,
   _swigc__p_p_int,
@@ -24999,15 +28244,25 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "wkbMultiLineString",SWIG_From_int(static_cast< int >(5)));
   SWIG_Python_SetConstant(d, "wkbMultiPolygon",SWIG_From_int(static_cast< int >(6)));
   SWIG_Python_SetConstant(d, "wkbGeometryCollection",SWIG_From_int(static_cast< int >(7)));
+  SWIG_Python_SetConstant(d, "wkbCircularString",SWIG_From_int(static_cast< int >(8)));
+  SWIG_Python_SetConstant(d, "wkbCompoundCurve",SWIG_From_int(static_cast< int >(9)));
+  SWIG_Python_SetConstant(d, "wkbCurvePolygon",SWIG_From_int(static_cast< int >(10)));
+  SWIG_Python_SetConstant(d, "wkbMultiCurve",SWIG_From_int(static_cast< int >(11)));
+  SWIG_Python_SetConstant(d, "wkbMultiSurface",SWIG_From_int(static_cast< int >(12)));
   SWIG_Python_SetConstant(d, "wkbNone",SWIG_From_int(static_cast< int >(100)));
   SWIG_Python_SetConstant(d, "wkbLinearRing",SWIG_From_int(static_cast< int >(101)));
-  SWIG_Python_SetConstant(d, "wkbPoint25D",SWIG_From_int(static_cast< int >(wkbPoint+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbLineString25D",SWIG_From_int(static_cast< int >(wkbLineString+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbPolygon25D",SWIG_From_int(static_cast< int >(wkbPolygon+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbMultiPoint25D",SWIG_From_int(static_cast< int >(wkbMultiPoint+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbMultiLineString25D",SWIG_From_int(static_cast< int >(wkbMultiLineString+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbMultiPolygon25D",SWIG_From_int(static_cast< int >(wkbMultiPolygon+wkb25DBit)));
-  SWIG_Python_SetConstant(d, "wkbGeometryCollection25D",SWIG_From_int(static_cast< int >(wkbGeometryCollection+wkb25DBit)));
+  SWIG_Python_SetConstant(d, "wkbCircularStringZ",SWIG_From_int(static_cast< int >(1008)));
+  SWIG_Python_SetConstant(d, "wkbCompoundCurveZ",SWIG_From_int(static_cast< int >(1009)));
+  SWIG_Python_SetConstant(d, "wkbCurvePolygonZ",SWIG_From_int(static_cast< int >(1010)));
+  SWIG_Python_SetConstant(d, "wkbMultiCurveZ",SWIG_From_int(static_cast< int >(1011)));
+  SWIG_Python_SetConstant(d, "wkbMultiSurfaceZ",SWIG_From_int(static_cast< int >(1012)));
+  SWIG_Python_SetConstant(d, "wkbPoint25D",SWIG_From_int(static_cast< int >(0x80000001)));
+  SWIG_Python_SetConstant(d, "wkbLineString25D",SWIG_From_int(static_cast< int >(0x80000002)));
+  SWIG_Python_SetConstant(d, "wkbPolygon25D",SWIG_From_int(static_cast< int >(0x80000003)));
+  SWIG_Python_SetConstant(d, "wkbMultiPoint25D",SWIG_From_int(static_cast< int >(0x80000004)));
+  SWIG_Python_SetConstant(d, "wkbMultiLineString25D",SWIG_From_int(static_cast< int >(0x80000005)));
+  SWIG_Python_SetConstant(d, "wkbMultiPolygon25D",SWIG_From_int(static_cast< int >(0x80000006)));
+  SWIG_Python_SetConstant(d, "wkbGeometryCollection25D",SWIG_From_int(static_cast< int >(0x80000007)));
   SWIG_Python_SetConstant(d, "OFTInteger",SWIG_From_int(static_cast< int >(0)));
   SWIG_Python_SetConstant(d, "OFTIntegerList",SWIG_From_int(static_cast< int >(1)));
   SWIG_Python_SetConstant(d, "OFTReal",SWIG_From_int(static_cast< int >(2)));
@@ -25020,6 +28275,12 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "OFTDate",SWIG_From_int(static_cast< int >(9)));
   SWIG_Python_SetConstant(d, "OFTTime",SWIG_From_int(static_cast< int >(10)));
   SWIG_Python_SetConstant(d, "OFTDateTime",SWIG_From_int(static_cast< int >(11)));
+  SWIG_Python_SetConstant(d, "OFTInteger64",SWIG_From_int(static_cast< int >(12)));
+  SWIG_Python_SetConstant(d, "OFTInteger64List",SWIG_From_int(static_cast< int >(13)));
+  SWIG_Python_SetConstant(d, "OFSTNone",SWIG_From_int(static_cast< int >(0)));
+  SWIG_Python_SetConstant(d, "OFSTBoolean",SWIG_From_int(static_cast< int >(1)));
+  SWIG_Python_SetConstant(d, "OFSTInt16",SWIG_From_int(static_cast< int >(2)));
+  SWIG_Python_SetConstant(d, "OFSTFloat32",SWIG_From_int(static_cast< int >(3)));
   SWIG_Python_SetConstant(d, "OJUndefined",SWIG_From_int(static_cast< int >(0)));
   SWIG_Python_SetConstant(d, "OJLeft",SWIG_From_int(static_cast< int >(1)));
   SWIG_Python_SetConstant(d, "OJRight",SWIG_From_int(static_cast< int >(2)));
@@ -25029,7 +28290,14 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "ALTER_NAME_FLAG",SWIG_From_int(static_cast< int >(1)));
   SWIG_Python_SetConstant(d, "ALTER_TYPE_FLAG",SWIG_From_int(static_cast< int >(2)));
   SWIG_Python_SetConstant(d, "ALTER_WIDTH_PRECISION_FLAG",SWIG_From_int(static_cast< int >(4)));
-  SWIG_Python_SetConstant(d, "ALTER_ALL_FLAG",SWIG_From_int(static_cast< int >(1+2+4)));
+  SWIG_Python_SetConstant(d, "ALTER_NULLABLE_FLAG",SWIG_From_int(static_cast< int >(8)));
+  SWIG_Python_SetConstant(d, "ALTER_DEFAULT_FLAG",SWIG_From_int(static_cast< int >(16)));
+  SWIG_Python_SetConstant(d, "ALTER_ALL_FLAG",SWIG_From_int(static_cast< int >(1+2+4+8+16)));
+  SWIG_Python_SetConstant(d, "F_VAL_NULL",SWIG_From_int(static_cast< int >(0x00000001)));
+  SWIG_Python_SetConstant(d, "F_VAL_GEOM_TYPE",SWIG_From_int(static_cast< int >(0x00000002)));
+  SWIG_Python_SetConstant(d, "F_VAL_WIDTH",SWIG_From_int(static_cast< int >(0x00000004)));
+  SWIG_Python_SetConstant(d, "F_VAL_ALLOW_NULL_WHEN_DEFAULT",SWIG_From_int(static_cast< int >(0x00000008)));
+  SWIG_Python_SetConstant(d, "F_VAL_ALL",SWIG_From_int(static_cast< int >(0xFFFFFFFF)));
   SWIG_Python_SetConstant(d, "OLCRandomRead",SWIG_FromCharPtr("RandomRead"));
   SWIG_Python_SetConstant(d, "OLCSequentialWrite",SWIG_FromCharPtr("SequentialWrite"));
   SWIG_Python_SetConstant(d, "OLCRandomWrite",SWIG_FromCharPtr("RandomWrite"));
@@ -25046,11 +28314,26 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "OLCStringsAsUTF8",SWIG_FromCharPtr("StringsAsUTF8"));
   SWIG_Python_SetConstant(d, "OLCIgnoreFields",SWIG_FromCharPtr("IgnoreFields"));
   SWIG_Python_SetConstant(d, "OLCCreateGeomField",SWIG_FromCharPtr("CreateGeomField"));
+  SWIG_Python_SetConstant(d, "OLCCurveGeometries",SWIG_FromCharPtr("CurveGeometries"));
   SWIG_Python_SetConstant(d, "ODsCCreateLayer",SWIG_FromCharPtr("CreateLayer"));
   SWIG_Python_SetConstant(d, "ODsCDeleteLayer",SWIG_FromCharPtr("DeleteLayer"));
   SWIG_Python_SetConstant(d, "ODsCCreateGeomFieldAfterCreateLayer",SWIG_FromCharPtr("CreateGeomFieldAfterCreateLayer"));
+  SWIG_Python_SetConstant(d, "ODsCCurveGeometries",SWIG_FromCharPtr("CurveGeometries"));
+  SWIG_Python_SetConstant(d, "ODsCTransactions",SWIG_FromCharPtr("Transactions"));
+  SWIG_Python_SetConstant(d, "ODsCEmulatedTransactions",SWIG_FromCharPtr("EmulatedTransactions"));
   SWIG_Python_SetConstant(d, "ODrCCreateDataSource",SWIG_FromCharPtr("CreateDataSource"));
   SWIG_Python_SetConstant(d, "ODrCDeleteDataSource",SWIG_FromCharPtr("DeleteDataSource"));
+  SWIG_Python_SetConstant(d, "OLMD_FID64",SWIG_FromCharPtr("OLMD_FID64"));
+  SWIG_Python_SetConstant(d, "OGRERR_NONE",SWIG_From_int(static_cast< int >(0)));
+  SWIG_Python_SetConstant(d, "OGRERR_NOT_ENOUGH_DATA",SWIG_From_int(static_cast< int >(1)));
+  SWIG_Python_SetConstant(d, "OGRERR_NOT_ENOUGH_MEMORY",SWIG_From_int(static_cast< int >(2)));
+  SWIG_Python_SetConstant(d, "OGRERR_UNSUPPORTED_GEOMETRY_TYPE",SWIG_From_int(static_cast< int >(3)));
+  SWIG_Python_SetConstant(d, "OGRERR_UNSUPPORTED_OPERATION",SWIG_From_int(static_cast< int >(4)));
+  SWIG_Python_SetConstant(d, "OGRERR_CORRUPT_DATA",SWIG_From_int(static_cast< int >(5)));
+  SWIG_Python_SetConstant(d, "OGRERR_FAILURE",SWIG_From_int(static_cast< int >(6)));
+  SWIG_Python_SetConstant(d, "OGRERR_UNSUPPORTED_SRS",SWIG_From_int(static_cast< int >(7)));
+  SWIG_Python_SetConstant(d, "OGRERR_INVALID_HANDLE",SWIG_From_int(static_cast< int >(8)));
+  SWIG_Python_SetConstant(d, "OGRERR_NON_EXISTING_FEATURE",SWIG_From_int(static_cast< int >(9)));
   
   
   if ( OGRGetDriverCount() == 0 ) {
diff --git a/swig/python/extensions/osr_wrap.cpp b/swig/python/extensions/osr_wrap.cpp
index 4eece55..a19501e 100644
--- a/swig/python/extensions/osr_wrap.cpp
+++ b/swig/python/extensions/osr_wrap.cpp
@@ -2900,7 +2900,7 @@ void CPL_STDCALL
 PythonBindingErrorHandler(CPLErr eclass, int code, const char *msg ) 
 {
   /* 
-  ** Generally we want to supress error reporting if we have exceptions
+  ** Generally we want to suppress error reporting if we have exceptions
   ** enabled as the error message will be in the exception thrown in 
   ** Python.  
   */
@@ -3197,6 +3197,8 @@ OGRErrMessages( int rc ) {
     return "OGR Error: Unsupported SRS";
   case OGRERR_INVALID_HANDLE:
     return "OGR Error: Invalid handle";
+  case OGRERR_NON_EXISTING_FEATURE:
+    return "OGR Error: Non existing feature";
   default:
     return "OGR Error: Unknown";
   }
@@ -3732,8 +3734,8 @@ SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromERM(OSRSpatialReferenceSha
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromMICoordSys(OSRSpatialReferenceShadow *self,char const *pszCoordSys){
     return OSRImportFromMICoordSys( self, pszCoordSys );
   }
-SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *datum,char const *proj,char const *projParms){
-    return OSRImportFromOzi( self, datum, proj, projParms );
+SWIGINTERN OGRErr OSRSpatialReferenceShadow_ImportFromOzi(OSRSpatialReferenceShadow *self,char const *const *papszLines){
+    return OSRImportFromOzi( self, papszLines );
   }
 SWIGINTERN OGRErr OSRSpatialReferenceShadow_ExportToWkt(OSRSpatialReferenceShadow *self,char **argout){
     return OSRExportToWkt( self, argout );
@@ -11432,59 +11434,65 @@ fail:
 SWIGINTERN PyObject *_wrap_SpatialReference_ImportFromOzi(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   OSRSpatialReferenceShadow *arg1 = (OSRSpatialReferenceShadow *) 0 ;
-  char *arg2 = (char *) 0 ;
-  char *arg3 = (char *) 0 ;
-  char *arg4 = (char *) 0 ;
+  char **arg2 = (char **) 0 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
-  int res2 ;
-  char *buf2 = 0 ;
-  int alloc2 = 0 ;
-  int res3 ;
-  char *buf3 = 0 ;
-  int alloc3 = 0 ;
-  int res4 ;
-  char *buf4 = 0 ;
-  int alloc4 = 0 ;
   PyObject * obj0 = 0 ;
   PyObject * obj1 = 0 ;
-  PyObject * obj2 = 0 ;
-  PyObject * obj3 = 0 ;
   OGRErr result;
   
-  if (!PyArg_ParseTuple(args,(char *)"OOOO:SpatialReference_ImportFromOzi",&obj0,&obj1,&obj2,&obj3)) SWIG_fail;
+  if (!PyArg_ParseTuple(args,(char *)"OO:SpatialReference_ImportFromOzi",&obj0,&obj1)) SWIG_fail;
   res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_OSRSpatialReferenceShadow, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "SpatialReference_ImportFromOzi" "', argument " "1"" of type '" "OSRSpatialReferenceShadow *""'"); 
   }
   arg1 = reinterpret_cast< OSRSpatialReferenceShadow * >(argp1);
-  res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2);
-  if (!SWIG_IsOK(res2)) {
-    SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "SpatialReference_ImportFromOzi" "', argument " "2"" of type '" "char const *""'");
-  }
-  arg2 = reinterpret_cast< char * >(buf2);
-  res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3);
-  if (!SWIG_IsOK(res3)) {
-    SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "SpatialReference_ImportFromOzi" "', argument " "3"" of type '" "char const *""'");
-  }
-  arg3 = reinterpret_cast< char * >(buf3);
-  res4 = SWIG_AsCharPtrAndSize(obj3, &buf4, NULL, &alloc4);
-  if (!SWIG_IsOK(res4)) {
-    SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "SpatialReference_ImportFromOzi" "', argument " "4"" of type '" "char const *""'");
-  }
-  arg4 = reinterpret_cast< char * >(buf4);
   {
-    if (!arg2) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    /* %typemap(in) char **options */
+    /* Check if is a list (and reject strings, that are seen as sequence of characters)  */
+    if ( ! PySequence_Check(obj1) || PyUnicode_Check(obj1)
+  #if PY_VERSION_HEX < 0x03000000
+      || PyString_Check(obj1)
+  #endif
+      ) {
+      PyErr_SetString(PyExc_TypeError,"not a sequence");
+      SWIG_fail;
     }
-  }
-  {
-    if (!arg3) {
-      SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
+    
+    int size = PySequence_Size(obj1);
+    for (int i = 0; i < size; i++) {
+      PyObject* pyObj = PySequence_GetItem(obj1,i);
+      if (PyUnicode_Check(pyObj))
+      {
+        char *pszStr;
+        Py_ssize_t nLen;
+        PyObject* pyUTF8Str = PyUnicode_AsUTF8String(pyObj);
+#if PY_VERSION_HEX >= 0x03000000
+        PyBytes_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#else
+        PyString_AsStringAndSize(pyUTF8Str, &pszStr, &nLen);
+#endif
+        arg2 = CSLAddString( arg2, pszStr );
+        Py_XDECREF(pyUTF8Str);
+      }
+#if PY_VERSION_HEX >= 0x03000000
+      else if (PyBytes_Check(pyObj))
+      arg2 = CSLAddString( arg2, PyBytes_AsString(pyObj) );
+#else
+      else if (PyString_Check(pyObj))
+      arg2 = CSLAddString( arg2, PyString_AsString(pyObj) );
+#endif
+      else
+      {
+        Py_DECREF(pyObj);
+        PyErr_SetString(PyExc_TypeError,"sequence must contain strings");
+        SWIG_fail;
+      }
+      Py_DECREF(pyObj);
     }
   }
   {
-    if (!arg4) {
+    if (!arg2) {
       SWIG_exception(SWIG_ValueError,"Received a NULL pointer.");
     }
   }
@@ -11492,7 +11500,7 @@ SWIGINTERN PyObject *_wrap_SpatialReference_ImportFromOzi(PyObject *SWIGUNUSEDPA
     if ( bUseExceptions ) {
       CPLErrorReset();
     }
-    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4);
+    result = (OGRErr)OSRSpatialReferenceShadow_ImportFromOzi(arg1,(char const *const *)arg2);
     if ( bUseExceptions ) {
       CPLErr eclass = CPLGetLastErrorType();
       if ( eclass == CE_Failure || eclass == CE_Fatal ) {
@@ -11507,9 +11515,10 @@ SWIGINTERN PyObject *_wrap_SpatialReference_ImportFromOzi(PyObject *SWIGUNUSEDPA
       SWIG_fail;
     }
   }
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   {
     /* %typemap(ret) OGRErr */
     if (resultobj == Py_None ) {
@@ -11522,9 +11531,10 @@ SWIGINTERN PyObject *_wrap_SpatialReference_ImportFromOzi(PyObject *SWIGUNUSEDPA
   }
   return resultobj;
 fail:
-  if (alloc2 == SWIG_NEWOBJ) delete[] buf2;
-  if (alloc3 == SWIG_NEWOBJ) delete[] buf3;
-  if (alloc4 == SWIG_NEWOBJ) delete[] buf4;
+  {
+    /* %typemap(freearg) char **options */
+    CSLDestroy( arg2 );
+  }
   return NULL;
 }
 
@@ -13167,7 +13177,7 @@ static PyMethodDef SwigMethods[] = {
 	 { (char *)"SpatialReference_ImportFromXML", _wrap_SpatialReference_ImportFromXML, METH_VARARGS, (char *)"SpatialReference_ImportFromXML(SpatialReference self, char xmlString) -> OGRErr"},
 	 { (char *)"SpatialReference_ImportFromERM", _wrap_SpatialReference_ImportFromERM, METH_VARARGS, (char *)"SpatialReference_ImportFromERM(SpatialReference self, char proj, char datum, char units) -> OGRErr"},
 	 { (char *)"SpatialReference_ImportFromMICoordSys", _wrap_SpatialReference_ImportFromMICoordSys, METH_VARARGS, (char *)"SpatialReference_ImportFromMICoordSys(SpatialReference self, char pszCoordSys) -> OGRErr"},
-	 { (char *)"SpatialReference_ImportFromOzi", _wrap_SpatialReference_ImportFromOzi, METH_VARARGS, (char *)"SpatialReference_ImportFromOzi(SpatialReference self, char datum, char proj, char projParms) -> OGRErr"},
+	 { (char *)"SpatialReference_ImportFromOzi", _wrap_SpatialReference_ImportFromOzi, METH_VARARGS, (char *)"SpatialReference_ImportFromOzi(SpatialReference self, char papszLines) -> OGRErr"},
 	 { (char *)"SpatialReference_ExportToWkt", _wrap_SpatialReference_ExportToWkt, METH_VARARGS, (char *)"SpatialReference_ExportToWkt(SpatialReference self) -> OGRErr"},
 	 { (char *)"SpatialReference_ExportToPrettyWkt", _wrap_SpatialReference_ExportToPrettyWkt, METH_VARARGS, (char *)"SpatialReference_ExportToPrettyWkt(SpatialReference self, int simplify = 0) -> OGRErr"},
 	 { (char *)"SpatialReference_ExportToProj4", _wrap_SpatialReference_ExportToProj4, METH_VARARGS, (char *)"SpatialReference_ExportToProj4(SpatialReference self) -> OGRErr"},
@@ -13861,6 +13871,7 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA",SWIG_FromCharPtr("Lambert_Azimuthal_Equal_Area"));
   SWIG_Python_SetConstant(d, "SRS_PT_MERCATOR_1SP",SWIG_FromCharPtr("Mercator_1SP"));
   SWIG_Python_SetConstant(d, "SRS_PT_MERCATOR_2SP",SWIG_FromCharPtr("Mercator_2SP"));
+  SWIG_Python_SetConstant(d, "SRS_PT_MERCATOR_AUXILIARY_SPHERE",SWIG_FromCharPtr("Mercator_Auxiliary_Sphere"));
   SWIG_Python_SetConstant(d, "SRS_PT_MILLER_CYLINDRICAL",SWIG_FromCharPtr("Miller_Cylindrical"));
   SWIG_Python_SetConstant(d, "SRS_PT_MOLLWEIDE",SWIG_FromCharPtr("Mollweide"));
   SWIG_Python_SetConstant(d, "SRS_PT_NEW_ZEALAND_MAP_GRID",SWIG_FromCharPtr("New_Zealand_Map_Grid"));
@@ -13891,6 +13902,14 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "SRS_PT_WAGNER_V",SWIG_FromCharPtr("Wagner_V"));
   SWIG_Python_SetConstant(d, "SRS_PT_WAGNER_VI",SWIG_FromCharPtr("Wagner_VI"));
   SWIG_Python_SetConstant(d, "SRS_PT_WAGNER_VII",SWIG_FromCharPtr("Wagner_VII"));
+  SWIG_Python_SetConstant(d, "SRS_PT_QSC",SWIG_FromCharPtr("Quadrilateralized_Spherical_Cube"));
+  SWIG_Python_SetConstant(d, "SRS_PT_AITOFF",SWIG_FromCharPtr("Aitoff"));
+  SWIG_Python_SetConstant(d, "SRS_PT_WINKEL_I",SWIG_FromCharPtr("Winkel_I"));
+  SWIG_Python_SetConstant(d, "SRS_PT_WINKEL_II",SWIG_FromCharPtr("Winkel_II"));
+  SWIG_Python_SetConstant(d, "SRS_PT_WINKEL_TRIPEL",SWIG_FromCharPtr("Winkel_Tripel"));
+  SWIG_Python_SetConstant(d, "SRS_PT_CRASTER_PARABOLIC",SWIG_FromCharPtr("Craster_Parabolic"));
+  SWIG_Python_SetConstant(d, "SRS_PT_LOXIMUTHAL",SWIG_FromCharPtr("Loximuthal"));
+  SWIG_Python_SetConstant(d, "SRS_PT_QUARTIC_AUTHALIC",SWIG_FromCharPtr("Quartic_Authalic"));
   SWIG_Python_SetConstant(d, "SRS_PP_CENTRAL_MERIDIAN",SWIG_FromCharPtr("central_meridian"));
   SWIG_Python_SetConstant(d, "SRS_PP_SCALE_FACTOR",SWIG_FromCharPtr("scale_factor"));
   SWIG_Python_SetConstant(d, "SRS_PP_STANDARD_PARALLEL_1",SWIG_FromCharPtr("standard_parallel_1"));
diff --git a/swig/python/osgeo/gdal.py b/swig/python/osgeo/gdal.py
index 457b0c1..b913927 100644
--- a/swig/python/osgeo/gdal.py
+++ b/swig/python/osgeo/gdal.py
@@ -402,15 +402,15 @@ class Driver(MajorObject):
         return _gdal.Driver_CreateCopy(self, *args, **kwargs)
 
     def Delete(self, *args):
-        """Delete(self, char utf8_path) -> int"""
+        """Delete(self, char utf8_path) -> CPLErr"""
         return _gdal.Driver_Delete(self, *args)
 
     def Rename(self, *args):
-        """Rename(self, char newName, char oldName) -> int"""
+        """Rename(self, char newName, char oldName) -> CPLErr"""
         return _gdal.Driver_Rename(self, *args)
 
     def CopyFiles(self, *args):
-        """CopyFiles(self, char newName, char oldName) -> int"""
+        """CopyFiles(self, char newName, char oldName) -> CPLErr"""
         return _gdal.Driver_CopyFiles(self, *args)
 
     def Register(self, *args):
@@ -424,6 +424,8 @@ class Driver(MajorObject):
 Driver_swigregister = _gdal.Driver_swigregister
 Driver_swigregister(Driver)
 
+import ogr
+import osr
 class ColorEntry(_object):
     """Proxy of C++ GDALColorEntry class"""
     __swig_setmethods__ = {}
@@ -574,62 +576,6 @@ def GDAL_GCP_Id_set(*args):
   """GDAL_GCP_Id_set(GCP gcp, char pszId)"""
   return _gdal.GDAL_GCP_Id_set(*args)
 
-def GDAL_GCP_get_GCPX(*args):
-  """GDAL_GCP_get_GCPX(GCP gcp) -> double"""
-  return _gdal.GDAL_GCP_get_GCPX(*args)
-
-def GDAL_GCP_set_GCPX(*args):
-  """GDAL_GCP_set_GCPX(GCP gcp, double dfGCPX)"""
-  return _gdal.GDAL_GCP_set_GCPX(*args)
-
-def GDAL_GCP_get_GCPY(*args):
-  """GDAL_GCP_get_GCPY(GCP gcp) -> double"""
-  return _gdal.GDAL_GCP_get_GCPY(*args)
-
-def GDAL_GCP_set_GCPY(*args):
-  """GDAL_GCP_set_GCPY(GCP gcp, double dfGCPY)"""
-  return _gdal.GDAL_GCP_set_GCPY(*args)
-
-def GDAL_GCP_get_GCPZ(*args):
-  """GDAL_GCP_get_GCPZ(GCP gcp) -> double"""
-  return _gdal.GDAL_GCP_get_GCPZ(*args)
-
-def GDAL_GCP_set_GCPZ(*args):
-  """GDAL_GCP_set_GCPZ(GCP gcp, double dfGCPZ)"""
-  return _gdal.GDAL_GCP_set_GCPZ(*args)
-
-def GDAL_GCP_get_GCPPixel(*args):
-  """GDAL_GCP_get_GCPPixel(GCP gcp) -> double"""
-  return _gdal.GDAL_GCP_get_GCPPixel(*args)
-
-def GDAL_GCP_set_GCPPixel(*args):
-  """GDAL_GCP_set_GCPPixel(GCP gcp, double dfGCPPixel)"""
-  return _gdal.GDAL_GCP_set_GCPPixel(*args)
-
-def GDAL_GCP_get_GCPLine(*args):
-  """GDAL_GCP_get_GCPLine(GCP gcp) -> double"""
-  return _gdal.GDAL_GCP_get_GCPLine(*args)
-
-def GDAL_GCP_set_GCPLine(*args):
-  """GDAL_GCP_set_GCPLine(GCP gcp, double dfGCPLine)"""
-  return _gdal.GDAL_GCP_set_GCPLine(*args)
-
-def GDAL_GCP_get_Info(*args):
-  """GDAL_GCP_get_Info(GCP gcp) -> char"""
-  return _gdal.GDAL_GCP_get_Info(*args)
-
-def GDAL_GCP_set_Info(*args):
-  """GDAL_GCP_set_Info(GCP gcp, char pszInfo)"""
-  return _gdal.GDAL_GCP_set_Info(*args)
-
-def GDAL_GCP_get_Id(*args):
-  """GDAL_GCP_get_Id(GCP gcp) -> char"""
-  return _gdal.GDAL_GCP_get_Id(*args)
-
-def GDAL_GCP_set_Id(*args):
-  """GDAL_GCP_set_Id(GCP gcp, char pszId)"""
-  return _gdal.GDAL_GCP_set_Id(*args)
-
 def GCPsToGeoTransform(*args):
   """GCPsToGeoTransform(int nGCPs, int bApproxOK = 1) -> RETURN_NONE"""
   return _gdal.GCPsToGeoTransform(*args)
@@ -812,19 +758,92 @@ class Dataset(MajorObject):
         """
         return _gdal.Dataset_GetTiledVirtualMem(self, *args, **kwargs)
 
+    def CreateLayer(self, *args, **kwargs):
+        """
+        CreateLayer(self, char name, SpatialReference srs = None, OGRwkbGeometryType geom_type = wkbUnknown, 
+            char options = None) -> Layer
+        """
+        return _gdal.Dataset_CreateLayer(self, *args, **kwargs)
+
+    def CopyLayer(self, *args, **kwargs):
+        """CopyLayer(self, Layer src_layer, char new_name, char options = None) -> Layer"""
+        return _gdal.Dataset_CopyLayer(self, *args, **kwargs)
+
+    def DeleteLayer(self, *args):
+        """DeleteLayer(self, int index) -> OGRErr"""
+        return _gdal.Dataset_DeleteLayer(self, *args)
+
+    def GetLayerCount(self, *args):
+        """GetLayerCount(self) -> int"""
+        return _gdal.Dataset_GetLayerCount(self, *args)
+
+    def GetLayerByIndex(self, *args):
+        """GetLayerByIndex(self, int index = 0) -> Layer"""
+        return _gdal.Dataset_GetLayerByIndex(self, *args)
+
+    def GetLayerByName(self, *args):
+        """GetLayerByName(self, char layer_name) -> Layer"""
+        return _gdal.Dataset_GetLayerByName(self, *args)
+
+    def TestCapability(self, *args):
+        """TestCapability(self, char cap) -> bool"""
+        return _gdal.Dataset_TestCapability(self, *args)
+
+    def ExecuteSQL(self, *args, **kwargs):
+        """ExecuteSQL(self, char statement, Geometry spatialFilter = None, char dialect = "") -> Layer"""
+        return _gdal.Dataset_ExecuteSQL(self, *args, **kwargs)
+
+    def ReleaseResultSet(self, *args):
+        """ReleaseResultSet(self, Layer layer)"""
+        return _gdal.Dataset_ReleaseResultSet(self, *args)
+
+    def GetStyleTable(self, *args):
+        """GetStyleTable(self) -> StyleTable"""
+        return _gdal.Dataset_GetStyleTable(self, *args)
+
+    def SetStyleTable(self, *args):
+        """SetStyleTable(self, StyleTable table)"""
+        return _gdal.Dataset_SetStyleTable(self, *args)
+
+    def StartTransaction(self, *args, **kwargs):
+        """StartTransaction(self, int force = True) -> OGRErr"""
+        return _gdal.Dataset_StartTransaction(self, *args, **kwargs)
+
+    def CommitTransaction(self, *args):
+        """CommitTransaction(self) -> OGRErr"""
+        return _gdal.Dataset_CommitTransaction(self, *args)
+
+    def RollbackTransaction(self, *args):
+        """RollbackTransaction(self) -> OGRErr"""
+        return _gdal.Dataset_RollbackTransaction(self, *args)
+
     def ReadRaster1(self, *args, **kwargs):
         """
         ReadRaster1(self, int xoff, int yoff, int xsize, int ysize, int buf_xsize = None, 
             int buf_ysize = None, GDALDataType buf_type = None, 
-            int band_list = 0, int buf_pixel_space = None, 
-            int buf_line_space = None, 
-            int buf_band_space = None) -> CPLErr
+            int band_list = 0, GIntBig buf_pixel_space = None, 
+            GIntBig buf_line_space = None, 
+            GIntBig buf_band_space = None, GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour, 
+            GDALProgressFunc callback = None, 
+            void callback_data = None) -> CPLErr
         """
         return _gdal.Dataset_ReadRaster1(self, *args, **kwargs)
 
-    def ReadAsArray(self, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None ):
+    def ReadAsArray(self, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None,
+                    buf_xsize = None, buf_ysize = None, buf_type = None,
+                    resample_alg = GRIORA_NearestNeighbour,
+                    callback = None,
+                    callback_data = None):
+        """ Reading a chunk of a GDAL band into a numpy array. The optional (buf_xsize,buf_ysize,buf_type)
+        parameters should generally not be specified if buf_obj is specified. The array is returned"""
+
         import gdalnumeric
-        return gdalnumeric.DatasetReadAsArray( self, xoff, yoff, xsize, ysize, buf_obj )
+        return gdalnumeric.DatasetReadAsArray( self, xoff, yoff, xsize, ysize, buf_obj,
+                                               buf_xsize, buf_ysize, buf_type,
+                                               resample_alg = resample_alg,
+                                               callback = callback,
+                                               callback_data = callback_data )
+
     def WriteRaster(self, xoff, yoff, xsize, ysize,
                     buf_string,
                     buf_xsize = None, buf_ysize = None, buf_type = None,
@@ -848,7 +867,10 @@ class Dataset(MajorObject):
     def ReadRaster(self, xoff = 0, yoff = 0, xsize = None, ysize = None,
                    buf_xsize = None, buf_ysize = None, buf_type = None,
                    band_list = None,
-                   buf_pixel_space = None, buf_line_space = None, buf_band_space = None ):
+                   buf_pixel_space = None, buf_line_space = None, buf_band_space = None,
+                   resample_alg = GRIORA_NearestNeighbour,
+                   callback = None,
+                   callback_data = None):
 
         if xsize is None:
             xsize = self.RasterXSize
@@ -866,7 +888,8 @@ class Dataset(MajorObject):
 
         return _gdal.Dataset_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                             buf_xsize, buf_ysize, buf_type,
-                                            band_list, buf_pixel_space, buf_line_space, buf_band_space )
+                                            band_list, buf_pixel_space, buf_line_space, buf_band_space,
+                                          resample_alg, callback, callback_data )
 
     def GetVirtualMemArray(self, eAccess = gdalconst.GF_Read, xoff=0, yoff=0,
                            xsize=None, ysize=None, bufxsize=None, bufysize=None,
@@ -972,6 +995,28 @@ class Dataset(MajorObject):
                 buf_obj = ' ' * nRequiredSize
         return _gdal.Dataset_BeginAsyncReader(self, xoff, yoff, xsize, ysize, buf_obj, buf_xsize, buf_ysize, buf_type, band_list,  0, 0, 0, options)
 
+    def GetLayer(self,iLayer=0):
+        """Return the layer given an index or a name"""
+        if isinstance(iLayer, str):
+            return self.GetLayerByName(str(iLayer))
+        elif isinstance(iLayer, int):
+            return self.GetLayerByIndex(iLayer)
+        else:
+            raise TypeError("Input %s is not of String or Int type" % type(iLayer))
+
+    def DeleteLayer(self, value):
+        """Deletes the layer given an index or layer name"""
+        if isinstance(value, str):
+            for i in range(self.GetLayerCount()):
+                name = self.GetLayer(i).GetName()
+                if name == value:
+                    return _gdal.Dataset_DeleteLayer(self, i)
+            raise ValueError("Layer %s not found to delete" % value)
+        elif isinstance(value, int):
+            return _gdal.Dataset_DeleteLayer(self, value)
+        else:
+            raise TypeError("Input %s is not of String or Int type" % type(value))
+
 Dataset_swigregister = _gdal.Dataset_swigregister
 Dataset_swigregister(Dataset)
 
@@ -991,6 +1036,10 @@ class Band(MajorObject):
     if _newclass:YSize = _swig_property(_gdal.Band_YSize_get)
     __swig_getmethods__["DataType"] = _gdal.Band_DataType_get
     if _newclass:DataType = _swig_property(_gdal.Band_DataType_get)
+    def GetDataset(self, *args):
+        """GetDataset(self) -> Dataset"""
+        return _gdal.Band_GetDataset(self, *args)
+
     def GetBand(self, *args):
         """GetBand(self) -> int"""
         return _gdal.Band_GetBand(self, *args)
@@ -1160,7 +1209,7 @@ class Band(MajorObject):
     def GetDefaultHistogram(self, *args, **kwargs):
         """
         GetDefaultHistogram(self, double min_ret = None, double max_ret = None, int buckets_ret = None, 
-            int ppanHistogram = None, 
+            GUIntBig ppanHistogram = None, 
             int force = 1, GDALProgressFunc callback = None, 
             void callback_data = None) -> CPLErr
         """
@@ -1207,7 +1256,10 @@ class Band(MajorObject):
         """
         ReadRaster1(self, int xoff, int yoff, int xsize, int ysize, int buf_xsize = None, 
             int buf_ysize = None, int buf_type = None, 
-            int buf_pixel_space = None, int buf_line_space = None) -> CPLErr
+            GIntBig buf_pixel_space = None, GIntBig buf_line_space = None, 
+            GDALRIOResampleAlg resample_alg = GRIORA_NearestNeighbour, 
+            GDALProgressFunc callback = None, 
+            void callback_data = None) -> CPLErr
         """
         return _gdal.Band_ReadRaster1(self, *args, **kwargs)
 
@@ -1217,7 +1269,10 @@ class Band(MajorObject):
 
     def ReadRaster(self, xoff = 0, yoff = 0, xsize = None, ysize = None,
                      buf_xsize = None, buf_ysize = None, buf_type = None,
-                     buf_pixel_space = None, buf_line_space = None ):
+                     buf_pixel_space = None, buf_line_space = None,
+                     resample_alg = GRIORA_NearestNeighbour,
+                     callback = None,
+                     callback_data = None):
 
         if xsize is None:
             xsize = self.XSize
@@ -1226,20 +1281,36 @@ class Band(MajorObject):
 
         return _gdal.Band_ReadRaster1(self, xoff, yoff, xsize, ysize,
                                       buf_xsize, buf_ysize, buf_type,
-                                      buf_pixel_space, buf_line_space)
+                                      buf_pixel_space, buf_line_space,
+                                      resample_alg, callback, callback_data)
 
     def ReadAsArray(self, xoff=0, yoff=0, win_xsize=None, win_ysize=None,
-                    buf_xsize=None, buf_ysize=None, buf_obj=None):
+                    buf_xsize=None, buf_ysize=None, buf_type=None, buf_obj=None,
+                    resample_alg = GRIORA_NearestNeighbour,
+                    callback = None,
+                    callback_data = None):
+        """ Reading a chunk of a GDAL band into a numpy array. The optional (buf_xsize,buf_ysize,buf_type)
+        parameters should generally not be specified if buf_obj is specified. The array is returned"""
+
         import gdalnumeric
 
         return gdalnumeric.BandReadAsArray( self, xoff, yoff,
                                             win_xsize, win_ysize,
-                                            buf_xsize, buf_ysize, buf_obj )
+                                            buf_xsize, buf_ysize, buf_type, buf_obj,
+                                            resample_alg = resample_alg,
+                                            callback = callback,
+                                            callback_data = callback_data)
       
-    def WriteArray(self, array, xoff=0, yoff=0):
+    def WriteArray(self, array, xoff=0, yoff=0,
+                   resample_alg = GRIORA_NearestNeighbour,
+                   callback = None,
+                   callback_data = None):
         import gdalnumeric
 
-        return gdalnumeric.BandWriteArray( self, array, xoff, yoff )
+        return gdalnumeric.BandWriteArray( self, array, xoff, yoff,
+                                           resample_alg = resample_alg,
+                                           callback = callback,
+                                           callback_data = callback_data )
 
     def GetVirtualMemArray(self, eAccess = gdalconst.GF_Read, xoff=0, yoff=0,
                            xsize=None, ysize=None, bufxsize=None, bufysize=None,
@@ -1449,6 +1520,10 @@ class RasterAttributeTable(_object):
         """ChangesAreWrittenToFile(self) -> int"""
         return _gdal.RasterAttributeTable_ChangesAreWrittenToFile(self, *args)
 
+    def DumpReadable(self, *args):
+        """DumpReadable(self)"""
+        return _gdal.RasterAttributeTable_DumpReadable(self, *args)
+
     def WriteArray(self, array, field, start=0):
         import gdalnumeric
 
@@ -1507,18 +1582,18 @@ ComputeProximity = _gdal.ComputeProximity
 
 def RasterizeLayer(*args, **kwargs):
   """
-    RasterizeLayer(Dataset dataset, int bands, OGRLayerShadow layer, void pfnTransformer = None, 
+    RasterizeLayer(Dataset dataset, int bands, Layer layer, void pfnTransformer = None, 
         void pTransformArg = None, 
-        int burn_values = 0, char options = None, 
-        GDALProgressFunc callback = None, void callback_data = None) -> int
+        int burn_values = 0, char options = None, GDALProgressFunc callback = None, 
+        void callback_data = None) -> int
     """
   return _gdal.RasterizeLayer(*args, **kwargs)
 RasterizeLayer = _gdal.RasterizeLayer
 
 def Polygonize(*args, **kwargs):
   """
-    Polygonize(Band srcBand, Band maskBand, OGRLayerShadow outLayer, 
-        int iPixValField, char options = None, GDALProgressFunc callback = None, 
+    Polygonize(Band srcBand, Band maskBand, Layer outLayer, int iPixValField, 
+        char options = None, GDALProgressFunc callback = None, 
         void callback_data = None) -> int
     """
   return _gdal.Polygonize(*args, **kwargs)
@@ -1564,7 +1639,7 @@ def ContourGenerate(*args, **kwargs):
   """
     ContourGenerate(Band srcBand, double contourInterval, double contourBase, 
         int fixedLevelCount, int useNoData, double noDataValue, 
-        OGRLayerShadow dstLayer, int idField, 
+        Layer dstLayer, int idField, 
         int elevField, GDALProgressFunc callback = None, 
         void callback_data = None) -> int
     """
@@ -1622,7 +1697,7 @@ def ApplyGeoTransform(*args):
 ApplyGeoTransform = _gdal.ApplyGeoTransform
 
 def InvGeoTransform(*args):
-  """InvGeoTransform(double gt_in) -> int"""
+  """InvGeoTransform(double gt_in) -> RETURN_NONE"""
   return _gdal.InvGeoTransform(*args)
 InvGeoTransform = _gdal.InvGeoTransform
 
@@ -1711,6 +1786,16 @@ def SerializeXMLTree(*args):
   return _gdal.SerializeXMLTree(*args)
 SerializeXMLTree = _gdal.SerializeXMLTree
 
+def GetJPEG2000Structure(*args):
+  """GetJPEG2000Structure(char pszFilename, char options = None) -> CPLXMLNode"""
+  return _gdal.GetJPEG2000Structure(*args)
+GetJPEG2000Structure = _gdal.GetJPEG2000Structure
+
+def GetJPEG2000StructureAsString(*args):
+  """GetJPEG2000StructureAsString(char pszFilename, char options = None) -> retStringAndCPLFree"""
+  return _gdal.GetJPEG2000StructureAsString(*args)
+GetJPEG2000StructureAsString = _gdal.GetJPEG2000StructureAsString
+
 def GetDriverCount(*args):
   """GetDriverCount() -> int"""
   return _gdal.GetDriverCount(*args)
@@ -1731,6 +1816,15 @@ def Open(*args):
   return _gdal.Open(*args)
 Open = _gdal.Open
 
+def OpenEx(*args, **kwargs):
+  """
+    OpenEx(char utf8_path, unsigned int nOpenFlags = 0, char allowed_drivers = None, 
+        char open_options = None, 
+        char sibling_files = None) -> Dataset
+    """
+  return _gdal.OpenEx(*args, **kwargs)
+OpenEx = _gdal.OpenEx
+
 def OpenShared(*args):
   """OpenShared(char utf8_path, GDALAccess eAccess = GA_ReadOnly) -> Dataset"""
   return _gdal.OpenShared(*args)
diff --git a/swig/python/osgeo/gdal_array.py b/swig/python/osgeo/gdal_array.py
index b4e7d9e..93ccc3c 100644
--- a/swig/python/osgeo/gdal_array.py
+++ b/swig/python/osgeo/gdal_array.py
@@ -66,6 +66,7 @@ except AttributeError:
     _newclass = 0
 
 
+import gdal
 class VirtualMem(_object):
     """Proxy of C++ CPLVirtualMemShadow class"""
     __swig_setmethods__ = {}
@@ -93,20 +94,40 @@ VirtualMem_swigregister = _gdal_array.VirtualMem_swigregister
 VirtualMem_swigregister(VirtualMem)
 
 
+def TermProgress_nocb(*args, **kwargs):
+  """TermProgress_nocb(double dfProgress, char pszMessage = None, void pData = None) -> int"""
+  return _gdal_array.TermProgress_nocb(*args, **kwargs)
+TermProgress = _gdal_array.TermProgress
+
 def GetArrayFilename(*args):
   """GetArrayFilename(PyArrayObject psArray) -> retStringAndCPLFree"""
   return _gdal_array.GetArrayFilename(*args)
+GetArrayFilename = _gdal_array.GetArrayFilename
 
 def BandRasterIONumPy(*args, **kwargs):
   """
     BandRasterIONumPy(Band band, int bWrite, int xoff, int yoff, int xsize, 
-        int ysize, PyArrayObject psArray, int buf_type) -> CPLErr
+        int ysize, PyArrayObject psArray, int buf_type, 
+        GDALRIOResampleAlg resample_alg, GDALProgressFunc callback = None, 
+        void callback_data = None) -> CPLErr
     """
   return _gdal_array.BandRasterIONumPy(*args, **kwargs)
+BandRasterIONumPy = _gdal_array.BandRasterIONumPy
+
+def DatasetIONumPy(*args, **kwargs):
+  """
+    DatasetIONumPy(Dataset ds, int bWrite, int xoff, int yoff, int xsize, 
+        int ysize, PyArrayObject psArray, int buf_type, 
+        GDALRIOResampleAlg resample_alg, GDALProgressFunc callback = None, 
+        void callback_data = None) -> CPLErr
+    """
+  return _gdal_array.DatasetIONumPy(*args, **kwargs)
+DatasetIONumPy = _gdal_array.DatasetIONumPy
 
 def VirtualMemGetArray(*args):
   """VirtualMemGetArray(VirtualMem virtualmem)"""
   return _gdal_array.VirtualMemGetArray(*args)
+VirtualMemGetArray = _gdal_array.VirtualMemGetArray
 
 def RATValuesIONumPyWrite(*args, **kwargs):
   """
@@ -114,6 +135,7 @@ def RATValuesIONumPyWrite(*args, **kwargs):
         PyArrayObject psArray) -> CPLErr
     """
   return _gdal_array.RATValuesIONumPyWrite(*args, **kwargs)
+RATValuesIONumPyWrite = _gdal_array.RATValuesIONumPyWrite
 
 def RATValuesIONumPyRead(*args, **kwargs):
   """
@@ -121,6 +143,7 @@ def RATValuesIONumPyRead(*args, **kwargs):
         int nLength) -> PyObject
     """
   return _gdal_array.RATValuesIONumPyRead(*args, **kwargs)
+RATValuesIONumPyRead = _gdal_array.RATValuesIONumPyRead
 import numpy
 import _gdal_array
 
@@ -181,12 +204,18 @@ def NumericTypeCodeToGDALTypeCode(numeric_type):
 def GDALTypeCodeToNumericTypeCode(gdal_code):
     return flip_code(gdal_code)
     
-def LoadFile( filename, xoff=0, yoff=0, xsize=None, ysize=None ):
+def LoadFile( filename, xoff=0, yoff=0, xsize=None, ysize=None,
+              buf_xsize=None, buf_ysize=None, buf_type=None,
+              resample_alg = gdal.GRIORA_NearestNeighbour,
+              callback=None, callback_data=None ):
     ds = gdal.Open( filename )
     if ds is None:
         raise ValueError("Can't open "+filename+"\n\n"+gdal.GetLastErrorMsg())
 
-    return DatasetReadAsArray( ds, xoff, yoff, xsize, ysize )
+    return DatasetReadAsArray( ds, xoff, yoff, xsize, ysize,
+                               buf_xsize=buf_xsize, buf_ysize=buf_ysize, buf_type=buf_type,
+                               resample_alg=resample_alg,
+                               callback = callback, callback_data = callback_data )
 
 def SaveArray( src_array, filename, format = "GTiff", prototype = None ):
     driver = gdal.GetDriverByName( format )
@@ -195,42 +224,79 @@ def SaveArray( src_array, filename, format = "GTiff", prototype = None ):
 
     return driver.CreateCopy( filename, OpenArray(src_array,prototype) )
 
-def DatasetReadAsArray( ds, xoff=0, yoff=0, xsize=None, ysize=None, buf_obj=None ):
 
-    if xsize is None:
-        xsize = ds.RasterXSize
-    if ysize is None:
-        ysize = ds.RasterYSize
+def DatasetReadAsArray( ds, xoff=0, yoff=0, win_xsize=None, win_ysize=None, buf_obj=None,
+                        buf_xsize = None, buf_ysize = None, buf_type = None,
+                        resample_alg = gdal.GRIORA_NearestNeighbour,
+                        callback=None, callback_data=None ):
+    """Pure python implementation of reading a chunk of a GDAL file
+    into a numpy array.  Used by the gdal.Dataset.ReadAsArray method."""
+
+    if win_xsize is None:
+        win_xsize = ds.RasterXSize
+    if win_ysize is None:
+        win_ysize = ds.RasterYSize
+
+    if ds.RasterCount == 0:
+        return None
 
     if ds.RasterCount == 1:
-        return BandReadAsArray( ds.GetRasterBand(1), xoff, yoff, xsize, ysize, buf_obj = buf_obj)
+        return BandReadAsArray( ds.GetRasterBand(1), xoff, yoff, win_xsize, win_ysize,
+                                buf_xsize = buf_xsize, buf_ysize = buf_ysize, buf_type = buf_type,
+                                buf_obj = buf_obj,
+                                resample_alg = resample_alg,
+                                callback = callback,
+                                callback_data = callback_data )
 
-    datatype = ds.GetRasterBand(1).DataType
-    for band_index in range(2,ds.RasterCount+1):
-        if datatype != ds.GetRasterBand(band_index).DataType:
-            datatype = gdalconst.GDT_Float32
-    
-    typecode = GDALTypeCodeToNumericTypeCode( datatype )
-    if typecode == None:
-        datatype = gdalconst.GDT_Float32
-        typecode = numpy.float32
-
-    if buf_obj is not None:
-        for band_index in range(1,ds.RasterCount+1):
-            BandReadAsArray( ds.GetRasterBand(band_index),
-                             xoff, yoff, xsize, ysize, buf_obj = buf_obj[band_index-1])
-        return buf_obj
-    
-    array_list = []
-    for band_index in range(1,ds.RasterCount+1):
-        band_array = BandReadAsArray( ds.GetRasterBand(band_index),
-                                      xoff, yoff, xsize, ysize)
-        array_list.append( numpy.reshape( band_array, [1,ysize,xsize] ) )
+    if buf_obj is None:
+        if buf_xsize is None:
+            buf_xsize = win_xsize
+        if buf_ysize is None:
+            buf_ysize = win_ysize
+        if buf_type is None:
+            buf_type = ds.GetRasterBand(1).DataType
+            for band_index in range(2,ds.RasterCount+1):
+                if buf_type != ds.GetRasterBand(band_index).DataType:
+                    buf_type = gdalconst.GDT_Float32
+
+        typecode = GDALTypeCodeToNumericTypeCode( buf_type )
+        if typecode == None:
+            buf_type = gdalconst.GDT_Float32
+            typecode = numpy.float32
+        if buf_type == gdalconst.GDT_Byte and ds.GetRasterBand(1).GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
+            typecode = numpy.int8
+        buf_obj = numpy.empty([ds.RasterCount, buf_ysize,buf_xsize], dtype = typecode)
+
+    else:
+        if len(buf_obj.shape) != 3:
+            raise ValueError('Array should have 3 dimensions')
+
+        shape_buf_xsize = buf_obj.shape[2]
+        shape_buf_ysize = buf_obj.shape[1]
+        if buf_xsize is not None and buf_xsize != shape_buf_xsize:
+            raise ValueError('Specified buf_xsize not consistant with array shape')
+        if buf_ysize is not None and buf_ysize != shape_buf_ysize:
+            raise ValueError('Specified buf_ysize not consistant with array shape')
+        if buf_obj.shape[0] != ds.RasterCount:
+            raise ValueError('Array should have space for %d bands' % ds.RasterCount)
+
+        datatype = NumericTypeCodeToGDALTypeCode( buf_obj.dtype.type )
+        if not datatype:
+            raise ValueError("array does not have corresponding GDAL data type")
+        if buf_type is not None and buf_type != datatype:
+            raise ValueError("Specified buf_type not consistant with array type")
+        buf_type = datatype
+
+    if DatasetIONumPy( ds, 0, xoff, yoff, win_xsize, win_ysize,
+                       buf_obj, buf_type, resample_alg, callback, callback_data ) != 0:
+        return None
+
+    return buf_obj
 
-    return numpy.concatenate( array_list )
-            
 def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = None,
-                     buf_xsize=None, buf_ysize=None, buf_obj=None ):
+                     buf_xsize=None, buf_ysize=None, buf_type=None, buf_obj=None,
+                     resample_alg = gdal.GRIORA_NearestNeighbour,
+                     callback=None, callback_data=None):
     """Pure python implementation of reading a chunk of a GDAL file
     into a numpy array.  Used by the gdal.Band.ReadAsArray method."""
 
@@ -244,6 +310,20 @@ def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = Non
             buf_xsize = win_xsize
         if buf_ysize is None:
             buf_ysize = win_ysize
+        if buf_type is None:
+            buf_type = band.DataType
+
+        typecode = GDALTypeCodeToNumericTypeCode( buf_type )
+        if typecode == None:
+            buf_type = gdalconst.GDT_Float32
+            typecode = numpy.float32
+        else:
+            buf_type = NumericTypeCodeToGDALTypeCode( typecode )
+
+        if buf_type == gdalconst.GDT_Byte and band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
+            typecode = numpy.int8
+        buf_obj = numpy.empty([buf_ysize,buf_xsize], dtype = typecode)
+
     else:
         if len(buf_obj.shape) == 2:
             shape_buf_xsize = buf_obj.shape[1]
@@ -255,38 +335,23 @@ def BandReadAsArray( band, xoff = 0, yoff = 0, win_xsize = None, win_ysize = Non
             raise ValueError('Specified buf_xsize not consistant with array shape')
         if buf_ysize is not None and buf_ysize != shape_buf_ysize:
             raise ValueError('Specified buf_ysize not consistant with array shape')
-        buf_xsize = shape_buf_xsize
-        buf_ysize = shape_buf_ysize
-
-    if buf_obj is None:
-        datatype = band.DataType
-        typecode = GDALTypeCodeToNumericTypeCode( datatype )
-        if typecode == None:
-            datatype = gdalconst.GDT_Float32
-            typecode = numpy.float32
-        else:
-            datatype = NumericTypeCodeToGDALTypeCode( typecode )
 
-        if datatype == gdalconst.GDT_Byte and band.GetMetadataItem('PIXELTYPE', 'IMAGE_STRUCTURE') == 'SIGNEDBYTE':
-            typecode = numpy.int8
-        ar = numpy.empty([buf_ysize,buf_xsize], dtype = typecode)
-        if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
-                                ar, datatype ) != 0:
-            return None
-
-        return ar
-    else:
         datatype = NumericTypeCodeToGDALTypeCode( buf_obj.dtype.type )
         if not datatype:
             raise ValueError("array does not have corresponding GDAL data type")
+        if buf_type is not None and buf_type != datatype:
+            raise ValueError("Specified buf_type not consistant with array type")
+        buf_type = datatype
 
-        if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
-                                buf_obj, datatype ) != 0:
-            return None
+    if BandRasterIONumPy( band, 0, xoff, yoff, win_xsize, win_ysize,
+                          buf_obj, buf_type, resample_alg, callback, callback_data ) != 0:
+        return None
 
-        return buf_obj
+    return buf_obj
 
-def BandWriteArray( band, array, xoff=0, yoff=0 ):
+def BandWriteArray( band, array, xoff=0, yoff=0,
+                    resample_alg = gdal.GRIORA_NearestNeighbour,
+                    callback=None, callback_data=None ):
     """Pure python implementation of writing a chunk of a GDAL file
     from a numpy array.  Used by the gdal.Band.WriteArray method."""
 
@@ -312,7 +377,7 @@ def BandWriteArray( band, array, xoff=0, yoff=0 ):
         raise ValueError("array does not have corresponding GDAL data type")
 
     return BandRasterIONumPy( band, 1, xoff, yoff, xsize, ysize,
-                                array, datatype )
+                                array, datatype, resample_alg, callback, callback_data )
 
 def RATWriteArray(rat, array, field, start=0):
     """
diff --git a/swig/python/osgeo/gdalconst.py b/swig/python/osgeo/gdalconst.py
index 22b0a6e..425cdf3 100644
--- a/swig/python/osgeo/gdalconst.py
+++ b/swig/python/osgeo/gdalconst.py
@@ -83,6 +83,14 @@ GA_ReadOnly = _gdalconst.GA_ReadOnly
 GA_Update = _gdalconst.GA_Update
 GF_Read = _gdalconst.GF_Read
 GF_Write = _gdalconst.GF_Write
+GRIORA_NearestNeighbour = _gdalconst.GRIORA_NearestNeighbour
+GRIORA_Bilinear = _gdalconst.GRIORA_Bilinear
+GRIORA_Cubic = _gdalconst.GRIORA_Cubic
+GRIORA_CubicSpline = _gdalconst.GRIORA_CubicSpline
+GRIORA_Lanczos = _gdalconst.GRIORA_Lanczos
+GRIORA_Average = _gdalconst.GRIORA_Average
+GRIORA_Mode = _gdalconst.GRIORA_Mode
+GRIORA_Gauss = _gdalconst.GRIORA_Gauss
 GCI_Undefined = _gdalconst.GCI_Undefined
 GCI_GrayIndex = _gdalconst.GCI_GrayIndex
 GCI_PaletteIndex = _gdalconst.GCI_PaletteIndex
@@ -131,16 +139,32 @@ CPLE_NotSupported = _gdalconst.CPLE_NotSupported
 CPLE_AssertionFailed = _gdalconst.CPLE_AssertionFailed
 CPLE_NoWriteAccess = _gdalconst.CPLE_NoWriteAccess
 CPLE_UserInterrupt = _gdalconst.CPLE_UserInterrupt
+OF_ALL = _gdalconst.OF_ALL
+OF_RASTER = _gdalconst.OF_RASTER
+OF_VECTOR = _gdalconst.OF_VECTOR
+OF_READONLY = _gdalconst.OF_READONLY
+OF_UPDATE = _gdalconst.OF_UPDATE
+OF_SHARED = _gdalconst.OF_SHARED
+OF_VERBOSE_ERROR = _gdalconst.OF_VERBOSE_ERROR
 DMD_LONGNAME = _gdalconst.DMD_LONGNAME
 DMD_HELPTOPIC = _gdalconst.DMD_HELPTOPIC
 DMD_MIMETYPE = _gdalconst.DMD_MIMETYPE
 DMD_EXTENSION = _gdalconst.DMD_EXTENSION
+DMD_EXTENSIONS = _gdalconst.DMD_EXTENSIONS
+DMD_CONNECTION_PREFIX = _gdalconst.DMD_CONNECTION_PREFIX
 DMD_CREATIONOPTIONLIST = _gdalconst.DMD_CREATIONOPTIONLIST
 DMD_CREATIONDATATYPES = _gdalconst.DMD_CREATIONDATATYPES
+DMD_CREATIONFIELDDATATYPES = _gdalconst.DMD_CREATIONFIELDDATATYPES
 DMD_SUBDATASETS = _gdalconst.DMD_SUBDATASETS
+DCAP_OPEN = _gdalconst.DCAP_OPEN
 DCAP_CREATE = _gdalconst.DCAP_CREATE
 DCAP_CREATECOPY = _gdalconst.DCAP_CREATECOPY
 DCAP_VIRTUALIO = _gdalconst.DCAP_VIRTUALIO
+DCAP_RASTER = _gdalconst.DCAP_RASTER
+DCAP_VECTOR = _gdalconst.DCAP_VECTOR
+DCAP_NOTNULL_FIELDS = _gdalconst.DCAP_NOTNULL_FIELDS
+DCAP_DEFAULT_FIELDS = _gdalconst.DCAP_DEFAULT_FIELDS
+DCAP_NOTNULL_GEOMFIELDS = _gdalconst.DCAP_NOTNULL_GEOMFIELDS
 CPLES_BackslashQuotable = _gdalconst.CPLES_BackslashQuotable
 CPLES_XML = _gdalconst.CPLES_XML
 CPLES_URL = _gdalconst.CPLES_URL
diff --git a/swig/python/osgeo/gdalnumeric.py b/swig/python/osgeo/gdalnumeric.py
index 4cd25bb..dce3eca 100644
--- a/swig/python/osgeo/gdalnumeric.py
+++ b/swig/python/osgeo/gdalnumeric.py
@@ -1,2 +1,2 @@
-from gdal_array import *
+from osgeo.gdal_array import *
 from numpy import *
diff --git a/swig/python/osgeo/ogr.py b/swig/python/osgeo/ogr.py
index 28e6f78..ce73e3d 100644
--- a/swig/python/osgeo/ogr.py
+++ b/swig/python/osgeo/ogr.py
@@ -76,8 +76,18 @@ wkbMultiPoint = _ogr.wkbMultiPoint
 wkbMultiLineString = _ogr.wkbMultiLineString
 wkbMultiPolygon = _ogr.wkbMultiPolygon
 wkbGeometryCollection = _ogr.wkbGeometryCollection
+wkbCircularString = _ogr.wkbCircularString
+wkbCompoundCurve = _ogr.wkbCompoundCurve
+wkbCurvePolygon = _ogr.wkbCurvePolygon
+wkbMultiCurve = _ogr.wkbMultiCurve
+wkbMultiSurface = _ogr.wkbMultiSurface
 wkbNone = _ogr.wkbNone
 wkbLinearRing = _ogr.wkbLinearRing
+wkbCircularStringZ = _ogr.wkbCircularStringZ
+wkbCompoundCurveZ = _ogr.wkbCompoundCurveZ
+wkbCurvePolygonZ = _ogr.wkbCurvePolygonZ
+wkbMultiCurveZ = _ogr.wkbMultiCurveZ
+wkbMultiSurfaceZ = _ogr.wkbMultiSurfaceZ
 wkbPoint25D = _ogr.wkbPoint25D
 wkbLineString25D = _ogr.wkbLineString25D
 wkbPolygon25D = _ogr.wkbPolygon25D
@@ -97,6 +107,12 @@ OFTBinary = _ogr.OFTBinary
 OFTDate = _ogr.OFTDate
 OFTTime = _ogr.OFTTime
 OFTDateTime = _ogr.OFTDateTime
+OFTInteger64 = _ogr.OFTInteger64
+OFTInteger64List = _ogr.OFTInteger64List
+OFSTNone = _ogr.OFSTNone
+OFSTBoolean = _ogr.OFSTBoolean
+OFSTInt16 = _ogr.OFSTInt16
+OFSTFloat32 = _ogr.OFSTFloat32
 OJUndefined = _ogr.OJUndefined
 OJLeft = _ogr.OJLeft
 OJRight = _ogr.OJRight
@@ -106,7 +122,14 @@ NullFID = _ogr.NullFID
 ALTER_NAME_FLAG = _ogr.ALTER_NAME_FLAG
 ALTER_TYPE_FLAG = _ogr.ALTER_TYPE_FLAG
 ALTER_WIDTH_PRECISION_FLAG = _ogr.ALTER_WIDTH_PRECISION_FLAG
+ALTER_NULLABLE_FLAG = _ogr.ALTER_NULLABLE_FLAG
+ALTER_DEFAULT_FLAG = _ogr.ALTER_DEFAULT_FLAG
 ALTER_ALL_FLAG = _ogr.ALTER_ALL_FLAG
+F_VAL_NULL = _ogr.F_VAL_NULL
+F_VAL_GEOM_TYPE = _ogr.F_VAL_GEOM_TYPE
+F_VAL_WIDTH = _ogr.F_VAL_WIDTH
+F_VAL_ALLOW_NULL_WHEN_DEFAULT = _ogr.F_VAL_ALLOW_NULL_WHEN_DEFAULT
+F_VAL_ALL = _ogr.F_VAL_ALL
 OLCRandomRead = _ogr.OLCRandomRead
 OLCSequentialWrite = _ogr.OLCSequentialWrite
 OLCRandomWrite = _ogr.OLCRandomWrite
@@ -123,11 +146,26 @@ OLCFastSetNextByIndex = _ogr.OLCFastSetNextByIndex
 OLCStringsAsUTF8 = _ogr.OLCStringsAsUTF8
 OLCIgnoreFields = _ogr.OLCIgnoreFields
 OLCCreateGeomField = _ogr.OLCCreateGeomField
+OLCCurveGeometries = _ogr.OLCCurveGeometries
 ODsCCreateLayer = _ogr.ODsCCreateLayer
 ODsCDeleteLayer = _ogr.ODsCDeleteLayer
 ODsCCreateGeomFieldAfterCreateLayer = _ogr.ODsCCreateGeomFieldAfterCreateLayer
+ODsCCurveGeometries = _ogr.ODsCCurveGeometries
+ODsCTransactions = _ogr.ODsCTransactions
+ODsCEmulatedTransactions = _ogr.ODsCEmulatedTransactions
 ODrCCreateDataSource = _ogr.ODrCCreateDataSource
 ODrCDeleteDataSource = _ogr.ODrCDeleteDataSource
+OLMD_FID64 = _ogr.OLMD_FID64
+OGRERR_NONE = _ogr.OGRERR_NONE
+OGRERR_NOT_ENOUGH_DATA = _ogr.OGRERR_NOT_ENOUGH_DATA
+OGRERR_NOT_ENOUGH_MEMORY = _ogr.OGRERR_NOT_ENOUGH_MEMORY
+OGRERR_UNSUPPORTED_GEOMETRY_TYPE = _ogr.OGRERR_UNSUPPORTED_GEOMETRY_TYPE
+OGRERR_UNSUPPORTED_OPERATION = _ogr.OGRERR_UNSUPPORTED_OPERATION
+OGRERR_CORRUPT_DATA = _ogr.OGRERR_CORRUPT_DATA
+OGRERR_FAILURE = _ogr.OGRERR_FAILURE
+OGRERR_UNSUPPORTED_SRS = _ogr.OGRERR_UNSUPPORTED_SRS
+OGRERR_INVALID_HANDLE = _ogr.OGRERR_INVALID_HANDLE
+OGRERR_NON_EXISTING_FEATURE = _ogr.OGRERR_NON_EXISTING_FEATURE
 
 def GetUseExceptions(*args):
   """GetUseExceptions() -> int"""
@@ -140,7 +178,133 @@ def UseExceptions(*args):
 def DontUseExceptions(*args):
   """DontUseExceptions()"""
   return _ogr.DontUseExceptions(*args)
+# Backup original dictionnary before doing anything else
+_initial_dict = globals().copy()
+
+ at property
+def wkb25Bit(module):
+    import warnings
+    warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning)
+    return module._initial_dict['wkb25DBit']
+
+ at property
+def wkb25DBit(module):
+    import warnings
+    warnings.warn("ogr.wkb25DBit deprecated: use ogr.GT_Flatten(), ogr.GT_HasZ() or ogr.GT_SetZ() instead", DeprecationWarning)
+    return module._initial_dict['wkb25DBit']
+
+# Inspired from http://www.dr-josiah.com/2013/12/properties-on-python-modules.html
+class _Module(object):
+    def __init__(self):
+        self.__dict__ = globals()
+        self._initial_dict = _initial_dict
+
+        # Transfer properties from the object to the Class
+        for k, v in list(self.__dict__.items()):
+            if isinstance(v, property):
+                setattr(self.__class__, k, v)
+                #del self.__dict__[k]
+
+        # Replace original module by our object
+        import sys
+        self._original_module = sys.modules[self.__name__]
+        sys.modules[self.__name__] = self
+
+# Custom help() replacement to display the help of the original module
+# instead of the one of our instance object
+class _MyHelper(object):
+
+    def __init__(self, module):
+        self.module = module
+        self.original_help = help
+
+        # Replace builtin help by ours
+        try:
+            import __builtin__ as builtins # Python 2
+        except ImportError:
+            import builtins # Python 3
+        builtins.help = self
+
+    def __repr__(self):
+        return self.original_help.__repr__()
+
+    def __call__(self, *args, **kwds):
+
+        if args == (self.module,):
+            import sys
+
+            # Restore original module before calling help() otherwise
+            # we don't get methods or classes mentionned
+            sys.modules[self.module.__name__] = self.module._original_module
+
+            ret = self.original_help(self.module._original_module, **kwds)
+
+            # Reinstall our module
+            sys.modules[self.module.__name__] = self.module
+
+            return ret
+        elif args == (self,):
+            return self.original_help(self.original_help, **kwds)
+        else:
+            return self.original_help(*args, **kwds)
+
+_MyHelper(_Module())
+del _MyHelper
+del _Module
+
+
 import osr
+class MajorObject(_object):
+    """Proxy of C++ GDALMajorObjectShadow class"""
+    __swig_setmethods__ = {}
+    __setattr__ = lambda self, name, value: _swig_setattr(self, MajorObject, name, value)
+    __swig_getmethods__ = {}
+    __getattr__ = lambda self, name: _swig_getattr(self, MajorObject, name)
+    def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined")
+    __repr__ = _swig_repr
+    def GetDescription(self, *args):
+        """GetDescription(self) -> char"""
+        return _ogr.MajorObject_GetDescription(self, *args)
+
+    def SetDescription(self, *args):
+        """SetDescription(self, char pszNewDesc)"""
+        return _ogr.MajorObject_SetDescription(self, *args)
+
+    def GetMetadataDomainList(self, *args):
+        """GetMetadataDomainList(self) -> char"""
+        return _ogr.MajorObject_GetMetadataDomainList(self, *args)
+
+    def GetMetadata_Dict(self, *args):
+        """GetMetadata_Dict(self, char pszDomain = "") -> char"""
+        return _ogr.MajorObject_GetMetadata_Dict(self, *args)
+
+    def GetMetadata_List(self, *args):
+        """GetMetadata_List(self, char pszDomain = "") -> char"""
+        return _ogr.MajorObject_GetMetadata_List(self, *args)
+
+    def SetMetadata(self, *args):
+        """
+        SetMetadata(self, char papszMetadata, char pszDomain = "") -> CPLErr
+        SetMetadata(self, char pszMetadataString, char pszDomain = "") -> CPLErr
+        """
+        return _ogr.MajorObject_SetMetadata(self, *args)
+
+    def GetMetadataItem(self, *args):
+        """GetMetadataItem(self, char pszName, char pszDomain = "") -> char"""
+        return _ogr.MajorObject_GetMetadataItem(self, *args)
+
+    def SetMetadataItem(self, *args):
+        """SetMetadataItem(self, char pszName, char pszValue, char pszDomain = "") -> CPLErr"""
+        return _ogr.MajorObject_SetMetadataItem(self, *args)
+
+    def GetMetadata( self, domain = '' ):
+      if domain[:4] == 'xml:':
+        return self.GetMetadata_List( domain )
+      return self.GetMetadata_Dict( domain )
+
+MajorObject_swigregister = _ogr.MajorObject_swigregister
+MajorObject_swigregister(MajorObject)
+
 class StyleTable(_object):
     """Proxy of C++ OGRStyleTableShadow class"""
     __swig_setmethods__ = {}
@@ -186,11 +350,13 @@ class StyleTable(_object):
 StyleTable_swigregister = _ogr.StyleTable_swigregister
 StyleTable_swigregister(StyleTable)
 
-class Driver(_object):
+class Driver(MajorObject):
     """Proxy of C++ OGRDriverShadow class"""
     __swig_setmethods__ = {}
+    for _s in [MajorObject]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))
     __setattr__ = lambda self, name, value: _swig_setattr(self, Driver, name, value)
     __swig_getmethods__ = {}
+    for _s in [MajorObject]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))
     __getattr__ = lambda self, name: _swig_getattr(self, Driver, name)
     def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined")
     __repr__ = _swig_repr
@@ -397,11 +563,13 @@ class Driver(_object):
 Driver_swigregister = _ogr.Driver_swigregister
 Driver_swigregister(Driver)
 
-class DataSource(_object):
+class DataSource(MajorObject):
     """Proxy of C++ OGRDataSourceShadow class"""
     __swig_setmethods__ = {}
+    for _s in [MajorObject]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))
     __setattr__ = lambda self, name, value: _swig_setattr(self, DataSource, name, value)
     __swig_getmethods__ = {}
+    for _s in [MajorObject]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))
     __getattr__ = lambda self, name: _swig_getattr(self, DataSource, name)
     def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined")
     __repr__ = _swig_repr
@@ -560,6 +728,10 @@ class DataSource(_object):
         """
         return _ogr.DataSource_SyncToDisk(self, *args)
 
+    def FlushCache(self, *args):
+        """FlushCache(self)"""
+        return _ogr.DataSource_FlushCache(self, *args)
+
     def CreateLayer(self, *args, **kwargs):
         """
         CreateLayer(self, char name, SpatialReference srs = None, OGRwkbGeometryType geom_type = wkbUnknown, 
@@ -737,7 +909,7 @@ class DataSource(_object):
 
         pszDialect:  allows control of the statement dialect. If set to NULL,
         the OGR SQL engine will be used, except for RDBMS drivers that will
-        use their dedicated SQL engine, unless OGRSQL is explicitely passed as
+        use their dedicated SQL engine, unless OGRSQL is explicitly passed as
         the dialect.
 
         an handle to a OGRLayer containing the results of the query.
@@ -791,6 +963,18 @@ class DataSource(_object):
         """
         return _ogr.DataSource_SetStyleTable(self, *args)
 
+    def StartTransaction(self, *args, **kwargs):
+        """StartTransaction(self, int force = True) -> OGRErr"""
+        return _ogr.DataSource_StartTransaction(self, *args, **kwargs)
+
+    def CommitTransaction(self, *args):
+        """CommitTransaction(self) -> OGRErr"""
+        return _ogr.DataSource_CommitTransaction(self, *args)
+
+    def RollbackTransaction(self, *args):
+        """RollbackTransaction(self) -> OGRErr"""
+        return _ogr.DataSource_RollbackTransaction(self, *args)
+
     def Destroy(self):
       "Once called, self has effectively been destroyed.  Do not access. For backwards compatiblity only"
       _ogr.delete_DataSource( self )
@@ -860,11 +1044,13 @@ class DataSource(_object):
 DataSource_swigregister = _ogr.DataSource_swigregister
 DataSource_swigregister(DataSource)
 
-class Layer(_object):
+class Layer(MajorObject):
     """Proxy of C++ OGRLayerShadow class"""
     __swig_setmethods__ = {}
+    for _s in [MajorObject]: __swig_setmethods__.update(getattr(_s,'__swig_setmethods__',{}))
     __setattr__ = lambda self, name, value: _swig_setattr(self, Layer, name, value)
     __swig_getmethods__ = {}
+    for _s in [MajorObject]: __swig_getmethods__.update(getattr(_s,'__swig_getmethods__',{}))
     __getattr__ = lambda self, name: _swig_getattr(self, Layer, name)
     def __init__(self, *args, **kwargs): raise AttributeError("No constructor defined")
     __repr__ = _swig_repr
@@ -1147,7 +1333,7 @@ class Layer(_object):
 
     def GetFeature(self, *args):
         """
-        GetFeature(self, long fid) -> Feature
+        GetFeature(self, GIntBig fid) -> Feature
 
         OGRFeatureH
         OGR_L_GetFeature(OGRLayerH hLayer, long nFeatureId)
@@ -1220,7 +1406,7 @@ class Layer(_object):
 
     def SetNextByIndex(self, *args):
         """
-        SetNextByIndex(self, long new_index) -> OGRErr
+        SetNextByIndex(self, GIntBig new_index) -> OGRErr
 
         OGRErr
         OGR_L_SetNextByIndex(OGRLayerH hLayer, long nIndex)
@@ -1315,7 +1501,7 @@ class Layer(_object):
 
     def DeleteFeature(self, *args):
         """
-        DeleteFeature(self, long fid) -> OGRErr
+        DeleteFeature(self, GIntBig fid) -> OGRErr
 
         OGRErr
         OGR_L_DeleteFeature(OGRLayerH hDS, long nFID)
@@ -1400,7 +1586,7 @@ class Layer(_object):
 
     def GetFeatureCount(self, *args, **kwargs):
         """
-        GetFeatureCount(self, int force = 1) -> int
+        GetFeatureCount(self, int force = 1) -> GIntBig
 
         int
         OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
@@ -2387,6 +2573,13 @@ class Feature(_object):
         """
         return _ogr.Feature_GetFieldAsInteger(self, *args)
 
+    def GetFieldAsInteger64(self, *args):
+        """
+        GetFieldAsInteger64(self, int id) -> GIntBig
+        GetFieldAsInteger64(self, char name) -> GIntBig
+        """
+        return _ogr.Feature_GetFieldAsInteger64(self, *args)
+
     def GetFieldAsDouble(self, *args):
         """
         GetFieldAsDouble(self, int id) -> double
@@ -2488,6 +2681,10 @@ class Feature(_object):
         """
         return _ogr.Feature_GetFieldAsIntegerList(self, *args)
 
+    def GetFieldAsInteger64List(self, *args):
+        """GetFieldAsInteger64List(self, int id)"""
+        return _ogr.Feature_GetFieldAsInteger64List(self, *args)
+
     def GetFieldAsDoubleList(self, *args):
         """
         GetFieldAsDoubleList(self, int id)
@@ -2547,6 +2744,35 @@ class Feature(_object):
         """
         return _ogr.Feature_GetFieldAsStringList(self, *args)
 
+    def GetFieldAsBinary(self, *args):
+        """
+        GetFieldAsBinary(self, int id) -> OGRErr
+        GetFieldAsBinary(self, char name) -> OGRErr
+
+        GByte*
+        OGR_F_GetFieldAsBinary(OGRFeatureH hFeat, int iField, int *pnBytes)
+
+        Fetch field value as binary.
+
+        Currently this method only works for OFTBinary fields.
+
+        This function is the same as the C++ method
+        OGRFeature::GetFieldAsBinary().
+
+        Parameters:
+        -----------
+
+        hFeat:  handle to the feature that owned the field.
+
+        iField:  the field to fetch, from 0 to GetFieldCount()-1.
+
+        pnBytes:  location to place count of bytes returned.
+
+        the field value. This list is internal, and should not be modified, or
+        freed. Its lifetime may be very brief. 
+        """
+        return _ogr.Feature_GetFieldAsBinary(self, *args)
+
     def IsFieldSet(self, *args):
         """
         IsFieldSet(self, int id) -> bool
@@ -2601,7 +2827,7 @@ class Feature(_object):
 
     def GetFID(self, *args):
         """
-        GetFID(self) -> int
+        GetFID(self) -> GIntBig
 
         long OGR_F_GetFID(OGRFeatureH hFeat)
 
@@ -2621,7 +2847,7 @@ class Feature(_object):
 
     def SetFID(self, *args):
         """
-        SetFID(self, int fid) -> OGRErr
+        SetFID(self, GIntBig fid) -> OGRErr
 
         OGRErr OGR_F_SetFID(OGRFeatureH hFeat,
         long nFID)
@@ -2692,18 +2918,20 @@ class Feature(_object):
         """
         return _ogr.Feature_UnsetField(self, *args)
 
+    def SetFieldInteger64(self, *args):
+        """SetFieldInteger64(self, int id, GIntBig value)"""
+        return _ogr.Feature_SetFieldInteger64(self, *args)
+
     def SetField(self, *args):
         """
         SetField(self, int id, char value)
         SetField(self, char name, char value)
-        SetField(self, int id, int value)
-        SetField(self, char name, int value)
         SetField(self, int id, double value)
         SetField(self, char name, double value)
         SetField(self, int id, int year, int month, int day, int hour, int minute, 
-            int second, int tzflag)
+            float second, int tzflag)
         SetField(self, char name, int year, int month, int day, int hour, 
-            int minute, int second, int tzflag)
+            int minute, float second, int tzflag)
         """
         return _ogr.Feature_SetField(self, *args)
 
@@ -2734,6 +2962,10 @@ class Feature(_object):
         """
         return _ogr.Feature_SetFieldIntegerList(self, *args)
 
+    def SetFieldInteger64List(self, *args):
+        """SetFieldInteger64List(self, int id, int nList)"""
+        return _ogr.Feature_SetFieldInteger64List(self, *args)
+
     def SetFieldDoubleList(self, *args):
         """
         SetFieldDoubleList(self, int id, int nList)
@@ -2926,6 +3158,41 @@ class Feature(_object):
         """
         return _ogr.Feature_GetFieldType(self, *args)
 
+    def Validate(self, *args):
+        """Validate(self, int flags = OGR_F_VAL_ALL, int bEmitError = TRUE) -> int"""
+        return _ogr.Feature_Validate(self, *args)
+
+    def FillUnsetWithDefault(self, *args):
+        """FillUnsetWithDefault(self, int bNotNullableOnly = True, char options = None)"""
+        return _ogr.Feature_FillUnsetWithDefault(self, *args)
+
+    def SetFieldString(self, *args):
+        """
+        SetFieldString(self, int id, char value)
+
+        void
+        OGR_F_SetFieldString(OGRFeatureH hFeat, int iField, const char
+        *pszValue)
+
+        Set field to string value.
+
+        OFTInteger fields will be set based on an atoi() conversion of the
+        string. OFTReal fields will be set based on an atof() conversion of
+        the string. Other field types may be unaffected.
+
+        This function is the same as the C++ method OGRFeature::SetField().
+
+        Parameters:
+        -----------
+
+        hFeat:  handle to the feature that owned the field.
+
+        iField:  the field to fetch, from 0 to GetFieldCount()-1.
+
+        pszValue:  the value to assign. 
+        """
+        return _ogr.Feature_SetFieldString(self, *args)
+
     def Reference(self):
       pass
 
@@ -3018,18 +3285,57 @@ class Feature(_object):
         fld_type = self.GetFieldType(fld_index)
         if fld_type == OFTInteger:
             return self.GetFieldAsInteger(fld_index)
+        if fld_type == OFTInteger64:
+            return self.GetFieldAsInteger64(fld_index)
         if fld_type == OFTReal:
             return self.GetFieldAsDouble(fld_index)
         if fld_type == OFTStringList:
             return self.GetFieldAsStringList(fld_index)
         if fld_type == OFTIntegerList:
             return self.GetFieldAsIntegerList(fld_index)
+        if fld_type == OFTInteger64List:
+            return self.GetFieldAsInteger64List(fld_index)
         if fld_type == OFTRealList:
             return self.GetFieldAsDoubleList(fld_index)
         ## if fld_type == OFTDateTime or fld_type == OFTDate or fld_type == OFTTime:
         #     return self.GetFieldAsDate(fld_index)
         # default to returning as a string.  Should we add more types?
-        return self.GetFieldAsString(fld_index)
+        try:
+            return self.GetFieldAsString(fld_index)
+        except:
+            # For Python3 on non-UTF8 strings
+            return self.GetFieldAsBinary(fld_index)
+
+    # With several override, SWIG cannot dispatch automatically unicode strings
+    # to the right implementation, so we have to do it at hand
+    def SetField(self, *args):
+        """
+        SetField(self, int id, char value)
+        SetField(self, char name, char value)
+        SetField(self, int id, int value)
+        SetField(self, char name, int value)
+        SetField(self, int id, double value)
+        SetField(self, char name, double value)
+        SetField(self, int id, int year, int month, int day, int hour, int minute, 
+            int second, int tzflag)
+        SetField(self, char name, int year, int month, int day, int hour, 
+            int minute, int second, int tzflag)
+        """
+
+        if len(args) == 2 and (type(args[1]) == type(1) or type(args[1]) == type(12345678901234)):
+            fld_index = args[0]
+            if isinstance(fld_index, str):
+                fld_index = self.GetFieldIndex(fld_index)
+            return _ogr.Feature_SetFieldInteger64(self, fld_index, args[1])
+
+
+        if len(args) == 2 and str(type(args[1])) == "<type 'unicode'>":
+            fld_index = args[0]
+            if isinstance(fld_index, str):
+                fld_index = self.GetFieldIndex(fld_index)
+            return _ogr.Feature_SetFieldString(self, fld_index, args[1])
+
+        return _ogr.Feature_SetField(self, *args)
 
     def SetField2(self, fld_index, value):
         if isinstance(fld_index, str):
@@ -3045,8 +3351,8 @@ class Feature(_object):
             if len(value) == 0:
                 self.UnsetField( fld_index )
                 return
-            if isinstance(value[0],int):
-                self.SetFieldIntegerList(fld_index,value)
+            if isinstance(value[0],type(1)) or isinstance(value[0],type(12345678901234)):
+                self.SetFieldInteger64List(fld_index,value)
                 return
             elif isinstance(value[0],float):
                 self.SetFieldDoubleList(fld_index,value)
@@ -3055,7 +3361,7 @@ class Feature(_object):
                 self.SetFieldStringList(fld_index,value)
                 return
             else:
-                raise TypeError( 'Unsupported type of list in SetField2()' )
+                raise TypeError( 'Unsupported type of list in SetField2(). Type of element is %s' % str(type(value[0])) )
 
         try:
             self.SetField( fld_index, value )
@@ -3556,6 +3862,14 @@ class FieldDefn(_object):
         """
         return _ogr.FieldDefn_SetType(self, *args)
 
+    def GetSubType(self, *args):
+        """GetSubType(self) -> OGRFieldSubType"""
+        return _ogr.FieldDefn_GetSubType(self, *args)
+
+    def SetSubType(self, *args):
+        """SetSubType(self, OGRFieldSubType type)"""
+        return _ogr.FieldDefn_SetSubType(self, *args)
+
     def GetJustify(self, *args):
         """
         GetJustify(self) -> OGRJustification
@@ -3731,6 +4045,26 @@ class FieldDefn(_object):
         """
         return _ogr.FieldDefn_SetIgnored(self, *args)
 
+    def IsNullable(self, *args):
+        """IsNullable(self) -> int"""
+        return _ogr.FieldDefn_IsNullable(self, *args)
+
+    def SetNullable(self, *args):
+        """SetNullable(self, int bNullable)"""
+        return _ogr.FieldDefn_SetNullable(self, *args)
+
+    def GetDefault(self, *args):
+        """GetDefault(self) -> char"""
+        return _ogr.FieldDefn_GetDefault(self, *args)
+
+    def SetDefault(self, *args):
+        """SetDefault(self, char pszValue)"""
+        return _ogr.FieldDefn_SetDefault(self, *args)
+
+    def IsDefaultDriverSpecific(self, *args):
+        """IsDefaultDriverSpecific(self) -> int"""
+        return _ogr.FieldDefn_IsDefaultDriverSpecific(self, *args)
+
     width = property(GetWidth, SetWidth)
     type = property(GetType, SetType)
     precision = property(GetPrecision, SetPrecision)
@@ -3795,6 +4129,14 @@ class GeomFieldDefn(_object):
         """SetIgnored(self, int bIgnored)"""
         return _ogr.GeomFieldDefn_SetIgnored(self, *args)
 
+    def IsNullable(self, *args):
+        """IsNullable(self) -> int"""
+        return _ogr.GeomFieldDefn_IsNullable(self, *args)
+
+    def SetNullable(self, *args):
+        """SetNullable(self, int bNullable)"""
+        return _ogr.GeomFieldDefn_SetNullable(self, *args)
+
     type = property(GetType, SetType)
     name = property(GetName, SetName)
     srs = property(GetSpatialRef, SetSpatialRef)
@@ -3854,6 +4196,10 @@ def ForceToMultiPoint(*args):
 def ForceToMultiLineString(*args):
   """ForceToMultiLineString(Geometry geom_in) -> Geometry"""
   return _ogr.ForceToMultiLineString(*args)
+
+def ForceTo(*args):
+  """ForceTo(Geometry geom_in, OGRwkbGeometryType eTargetType, char options = None) -> Geometry"""
+  return _ogr.ForceTo(*args)
 class Geometry(_object):
     """Proxy of C++ OGRGeometryShadow class"""
     __swig_setmethods__ = {}
@@ -3897,6 +4243,10 @@ class Geometry(_object):
         """
         return _ogr.Geometry_ExportToWkt(self, *args)
 
+    def ExportToIsoWkt(self, *args):
+        """ExportToIsoWkt(self) -> OGRErr"""
+        return _ogr.Geometry_ExportToIsoWkt(self, *args)
+
     def ExportToWkb(self, *args, **kwargs):
         """
         ExportToWkb(self, OGRwkbByteOrder byte_order = wkbXDR) -> OGRErr
@@ -3928,6 +4278,10 @@ class Geometry(_object):
         """
         return _ogr.Geometry_ExportToWkb(self, *args, **kwargs)
 
+    def ExportToIsoWkb(self, *args, **kwargs):
+        """ExportToIsoWkb(self, OGRwkbByteOrder byte_order = wkbXDR) -> OGRErr"""
+        return _ogr.Geometry_ExportToIsoWkb(self, *args, **kwargs)
+
     def ExportToGML(self, *args, **kwargs):
         """ExportToGML(self, char options = None) -> retStringAndCPLFree"""
         return _ogr.Geometry_ExportToGML(self, *args, **kwargs)
@@ -5182,6 +5536,22 @@ class Geometry(_object):
         """
         return _ogr.Geometry_GetDimension(self, *args)
 
+    def HasCurveGeometry(self, *args):
+        """HasCurveGeometry(self, int bLookForCircular = True) -> int"""
+        return _ogr.Geometry_HasCurveGeometry(self, *args)
+
+    def GetLinearGeometry(self, *args, **kwargs):
+        """GetLinearGeometry(self, double dfMaxAngleStepSizeDegrees = 0.0, char options = None) -> Geometry"""
+        return _ogr.Geometry_GetLinearGeometry(self, *args, **kwargs)
+
+    def GetCurveGeometry(self, *args, **kwargs):
+        """GetCurveGeometry(self, char options = None) -> Geometry"""
+        return _ogr.Geometry_GetCurveGeometry(self, *args, **kwargs)
+
+    def Value(self, *args):
+        """Value(self, double dfDistance) -> Geometry"""
+        return _ogr.Geometry_Value(self, *args)
+
     def Destroy(self):
       self.__swig_destroy__(self) 
       self.__del__()
@@ -5238,6 +5608,62 @@ def GetFieldTypeName(*args):
   """GetFieldTypeName(OGRFieldType type) -> char"""
   return _ogr.GetFieldTypeName(*args)
 
+def GetFieldSubTypeName(*args):
+  """GetFieldSubTypeName(OGRFieldSubType type) -> char"""
+  return _ogr.GetFieldSubTypeName(*args)
+
+def GT_Flatten(*args):
+  """GT_Flatten(OGRwkbGeometryType eType) -> OGRwkbGeometryType"""
+  return _ogr.GT_Flatten(*args)
+
+def GT_SetZ(*args):
+  """GT_SetZ(OGRwkbGeometryType eType) -> OGRwkbGeometryType"""
+  return _ogr.GT_SetZ(*args)
+
+def GT_SetModifier(*args):
+  """GT_SetModifier(OGRwkbGeometryType eType, int bSetZ, int bSetM = True) -> OGRwkbGeometryType"""
+  return _ogr.GT_SetModifier(*args)
+
+def GT_HasZ(*args):
+  """GT_HasZ(OGRwkbGeometryType eType) -> int"""
+  return _ogr.GT_HasZ(*args)
+
+def GT_IsSubClassOf(*args):
+  """GT_IsSubClassOf(OGRwkbGeometryType eType, OGRwkbGeometryType eSuperType) -> int"""
+  return _ogr.GT_IsSubClassOf(*args)
+
+def GT_IsCurve(*args):
+  """GT_IsCurve(OGRwkbGeometryType arg0) -> int"""
+  return _ogr.GT_IsCurve(*args)
+
+def GT_IsSurface(*args):
+  """GT_IsSurface(OGRwkbGeometryType arg0) -> int"""
+  return _ogr.GT_IsSurface(*args)
+
+def GT_IsNonLinear(*args):
+  """GT_IsNonLinear(OGRwkbGeometryType arg0) -> int"""
+  return _ogr.GT_IsNonLinear(*args)
+
+def GT_GetCollection(*args):
+  """GT_GetCollection(OGRwkbGeometryType eType) -> OGRwkbGeometryType"""
+  return _ogr.GT_GetCollection(*args)
+
+def GT_GetCurve(*args):
+  """GT_GetCurve(OGRwkbGeometryType eType) -> OGRwkbGeometryType"""
+  return _ogr.GT_GetCurve(*args)
+
+def GT_GetLinear(*args):
+  """GT_GetLinear(OGRwkbGeometryType eType) -> OGRwkbGeometryType"""
+  return _ogr.GT_GetLinear(*args)
+
+def SetNonLinearGeometriesEnabledFlag(*args):
+  """SetNonLinearGeometriesEnabledFlag(int bFlag)"""
+  return _ogr.SetNonLinearGeometriesEnabledFlag(*args)
+
+def GetNonLinearGeometriesEnabledFlag(*args):
+  """GetNonLinearGeometriesEnabledFlag() -> int"""
+  return _ogr.GetNonLinearGeometriesEnabledFlag(*args)
+
 def GetOpenDS(*args):
   """GetOpenDS(int ds_number) -> DataSource"""
   return _ogr.GetOpenDS(*args)
diff --git a/swig/python/osgeo/osr.py b/swig/python/osgeo/osr.py
index 58ad949..d495c79 100644
--- a/swig/python/osgeo/osr.py
+++ b/swig/python/osgeo/osr.py
@@ -96,6 +96,7 @@ SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM = _osr.SRS_PT_LAMBERT_CONFORMAL_CONIC
 SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA = _osr.SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA
 SRS_PT_MERCATOR_1SP = _osr.SRS_PT_MERCATOR_1SP
 SRS_PT_MERCATOR_2SP = _osr.SRS_PT_MERCATOR_2SP
+SRS_PT_MERCATOR_AUXILIARY_SPHERE = _osr.SRS_PT_MERCATOR_AUXILIARY_SPHERE
 SRS_PT_MILLER_CYLINDRICAL = _osr.SRS_PT_MILLER_CYLINDRICAL
 SRS_PT_MOLLWEIDE = _osr.SRS_PT_MOLLWEIDE
 SRS_PT_NEW_ZEALAND_MAP_GRID = _osr.SRS_PT_NEW_ZEALAND_MAP_GRID
@@ -126,6 +127,14 @@ SRS_PT_WAGNER_IV = _osr.SRS_PT_WAGNER_IV
 SRS_PT_WAGNER_V = _osr.SRS_PT_WAGNER_V
 SRS_PT_WAGNER_VI = _osr.SRS_PT_WAGNER_VI
 SRS_PT_WAGNER_VII = _osr.SRS_PT_WAGNER_VII
+SRS_PT_QSC = _osr.SRS_PT_QSC
+SRS_PT_AITOFF = _osr.SRS_PT_AITOFF
+SRS_PT_WINKEL_I = _osr.SRS_PT_WINKEL_I
+SRS_PT_WINKEL_II = _osr.SRS_PT_WINKEL_II
+SRS_PT_WINKEL_TRIPEL = _osr.SRS_PT_WINKEL_TRIPEL
+SRS_PT_CRASTER_PARABOLIC = _osr.SRS_PT_CRASTER_PARABOLIC
+SRS_PT_LOXIMUTHAL = _osr.SRS_PT_LOXIMUTHAL
+SRS_PT_QUARTIC_AUTHALIC = _osr.SRS_PT_QUARTIC_AUTHALIC
 SRS_PP_CENTRAL_MERIDIAN = _osr.SRS_PP_CENTRAL_MERIDIAN
 SRS_PP_SCALE_FACTOR = _osr.SRS_PP_SCALE_FACTOR
 SRS_PP_STANDARD_PARALLEL_1 = _osr.SRS_PP_STANDARD_PARALLEL_1
@@ -706,7 +715,7 @@ class SpatialReference(_object):
         return _osr.SpatialReference_ImportFromMICoordSys(self, *args)
 
     def ImportFromOzi(self, *args):
-        """ImportFromOzi(self, char datum, char proj, char projParms) -> OGRErr"""
+        """ImportFromOzi(self, char papszLines) -> OGRErr"""
         return _osr.SpatialReference_ImportFromOzi(self, *args)
 
     def ExportToWkt(self, *args):
diff --git a/swig/python/samples/README b/swig/python/samples/README
index e76bef3..5bc2c82 100644
--- a/swig/python/samples/README
+++ b/swig/python/samples/README
@@ -28,7 +28,7 @@ gdalfilter.py		Example script for applying kernel based filters to
 			files as an intermediate representation.
 
 gdal_retile.py          Script for restructuring data in a tree of regular tiles.
-                        (transfered in swig/python/scripts)
+                        (transferred in swig/python/scripts)
 
 get_soundg.py		Script to copy the SOUNDG layer from an S-57 file to
 			a Shapefile, splitting up features with MULTIPOINT
diff --git a/swig/python/samples/assemblepoly.py b/swig/python/samples/assemblepoly.py
index 7731a38..f6b89c7 100755
--- a/swig/python/samples/assemblepoly.py
+++ b/swig/python/samples/assemblepoly.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: assemblepoly.py 22986 2011-08-27 14:20:16Z rouault $
+# $Id: assemblepoly.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Assemble polygon geometries from arcs fulled from an arc layer.
@@ -31,14 +31,10 @@
 ###############################################################################
 
 try:
-    from osgeo import osr
     from osgeo import ogr
 except ImportError:
-    import osr
     import ogr
 
-import string
-
 #############################################################################-
 # Open the datasource to operate on.
 
diff --git a/swig/python/samples/attachpct.py b/swig/python/samples/attachpct.py
index e049995..3d5026d 100755
--- a/swig/python/samples/attachpct.py
+++ b/swig/python/samples/attachpct.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #******************************************************************************
-#  $Id: attachpct.py 25345 2012-12-25 21:19:27Z rouault $
+#  $Id: attachpct.py 28391 2015-01-30 19:57:31Z rouault $
 # 
 #  Project:  GDAL
 #  Purpose:  Simple command line program for copying the color table of a
@@ -36,7 +36,6 @@ except ImportError:
     import gdal
 
 import sys
-import string
 
 if len(sys.argv) < 3:
     print('Usage: attachpct.py <pctfile> <infile> <outfile>')
diff --git a/swig/python/samples/build_jp2_from_xml.py b/swig/python/samples/build_jp2_from_xml.py
new file mode 100644
index 0000000..acf949c
--- /dev/null
+++ b/swig/python/samples/build_jp2_from_xml.py
@@ -0,0 +1,449 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#******************************************************************************
+#  $Id: build_jp2_from_xml.py 28891 2015-04-13 09:42:46Z rouault $
+# 
+#  Project:  GDAL
+#  Purpose:  Build a JPEG2000 file from the XML structure dumped by dump_jp2.py
+#            Mostly useful to build non-conformant files
+#  Author:   Even Rouault, <even dot rouault at spatialys dot com>
+# 
+#******************************************************************************
+#  Copyright (c) 2015, European Union (European Environment Agency)
+# 
+#  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.
+#******************************************************************************
+
+import os
+import sys
+import struct
+from osgeo import gdal
+
+XML_TYPE_IDX = 0
+XML_VALUE_IDX = 1
+XML_FIRST_CHILD_IDX = 2
+
+def Usage():
+    print('Usage: build_jp2_from_xml in.xml out.jp2')
+    return 1
+
+def find_xml_node(ar, element_name, immediate_child = False, only_attributes = False):
+    #type = ar[XML_TYPE_IDX]
+    value = ar[XML_VALUE_IDX]
+    if not immediate_child and value == element_name:
+        return ar
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        if only_attributes and child[XML_TYPE_IDX] != gdal.CXT_Attribute:
+            continue
+        if immediate_child:
+            if child[XML_VALUE_IDX] == element_name:
+                return child
+        else:
+            found = find_xml_node(child, element_name)
+            if found is not None:
+                return found
+    return None
+
+def get_attribute_val(ar, attr_name):
+    node = find_xml_node(ar, attr_name, True)
+    if node is None or node[XML_TYPE_IDX] != gdal.CXT_Attribute:
+        return None
+    if len(ar) > XML_FIRST_CHILD_IDX and \
+        node[XML_FIRST_CHILD_IDX][XML_TYPE_IDX] == gdal.CXT_Text:
+        return node[XML_FIRST_CHILD_IDX][XML_VALUE_IDX]
+    return None
+
+def get_node_content(node):
+    if node is None:
+        return None
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(node)):
+        child = node[child_idx]
+        if child[XML_TYPE_IDX] == gdal.CXT_Text:
+            return child[XML_VALUE_IDX]
+    return None
+
+def hex_letter_to_number(ch):
+    val = 0
+    if ch >= '0' and ch <= '9':
+        val = (ord(ch) - ord('0'))
+    elif ch >= 'a' and ch <= 'f':
+        val = (ord(ch) - ord('a')) + 10
+    elif ch >= 'A' and ch <= 'F':
+        val = (ord(ch) - ord('A')) + 10
+    return val
+
+def write_hexstring_as_binary(hex_binary_content, out_f):
+    for i in range(int(len(hex_binary_content)/2)):
+        val = hex_letter_to_number(hex_binary_content[2*i]) * 16 + \
+              hex_letter_to_number(hex_binary_content[2*i+1])
+        if sys.version_info >= (3,0,0):
+            out_f.write(chr(val).encode('latin1'))
+        else:
+            out_f.write(chr(val))
+
+def parse_field(xml_tree, out_f, src_jp2file):
+    if not(xml_tree[XML_TYPE_IDX] == gdal.CXT_Element and xml_tree[XML_VALUE_IDX] == 'Field'):
+        print('Not a Field element')
+        return False
+    field_name = get_attribute_val(xml_tree, 'name')
+    if field_name is None:
+        print('Cannot find Field.name attribute')
+        #return False
+    field_type = get_attribute_val(xml_tree, 'type')
+    if field_type is None:
+        print('Cannot find Field.type attribute')
+        return False
+    val = get_node_content(xml_tree)
+    if val is None:
+        print('Cannot find Field content')
+        return False
+    if field_type == 'uint8':
+        out_f.write(struct.pack('>B' * 1, int(val)))
+    elif field_type == 'uint16':
+        out_f.write(struct.pack('>H' * 1, int(val)))
+    elif field_type == 'uint32':
+        out_f.write(struct.pack('>I' * 1, int(val)))
+    elif field_type == 'string':
+        field_size = get_attribute_val(xml_tree, 'size')
+        if field_size is not None:
+            assert(len(val) == int(field_size))
+        out_f.write(val.encode('latin1'))
+    elif field_type == 'hexint':
+        field_size = get_attribute_val(xml_tree, 'size')
+        if field_size is not None:
+            assert(len(val) == 2 + 2 * int(field_size))
+        write_hexstring_as_binary(val[2:], out_f)
+    else:
+        print('Unhandled type %s' % field_type)
+        return False
+    return True
+
+marker_map = {
+    "SOC": 0xFF4F,
+    "EOC": 0xFFD9,
+    "SOT": 0xFF90,
+    "SIZ": 0xFF51,
+    "COD": 0xFF52,
+    "COC": 0xFF53,
+    "TLM": 0xFF55,
+    "PLM": 0xFF57,
+    "PLT": 0xFF58,
+    "QCD": 0xFF5C,
+    "QCC": 0xFF5D,
+    "RGN": 0xFF5E,
+    "POC": 0xFF5F,
+    "PPM": 0xFF60,
+    "PPT": 0xFF61,
+    "CRG": 0xFF63,
+    "COM": 0xFF64,
+}
+
+def parse_jpc_marker(xml_tree, out_f, src_jp2file):
+    if not(xml_tree[XML_TYPE_IDX] == gdal.CXT_Element and xml_tree[XML_VALUE_IDX] == 'Marker'):
+        print('Not a Marker element')
+        return False
+    marker_name = get_attribute_val(xml_tree, 'name')
+    if marker_name is None:
+        print('Cannot find Marker.name attribute')
+        return False
+    if find_xml_node(xml_tree, 'Field', immediate_child = True):
+        if marker_name not in marker_map:
+            print('Cannot find marker signature for %s' % marker_name)
+            return False
+        marker_signature = marker_map[marker_name]
+        out_f.write(struct.pack('>H' * 1, marker_signature))
+        pos = out_f.tell()
+        out_f.write(struct.pack('>H' * 1, 0))
+
+        for child_idx in range(XML_FIRST_CHILD_IDX, len(xml_tree)):
+            child = xml_tree[child_idx]
+            if child[XML_TYPE_IDX] != gdal.CXT_Element:
+                continue
+            if not parse_field(child, out_f, src_jp2file):
+                return False
+
+        new_pos = out_f.tell()
+        out_f.seek(pos, 0)
+        out_f.write(struct.pack('>H' * 1, new_pos - pos))
+        out_f.seek(new_pos, 0)
+    else:
+        offset = get_attribute_val(xml_tree, 'offset')
+        if offset is None:
+            if marker_name == 'SOC' or marker_name == 'EOC':
+                marker_signature = marker_map[marker_name]
+                out_f.write(struct.pack('>H' * 1, marker_signature))
+                return True
+
+            print('Cannot find Marker.offset attribute')
+            return False
+        offset = int(offset)
+
+        length = get_attribute_val(xml_tree, 'length')
+        if length is None:
+            print('Cannot find Marker.length attribute')
+            return False
+        length = int(length)
+
+        src_jp2file.seek(offset, 0)
+        data = src_jp2file.read(length)
+
+        out_f.write(data)
+
+
+    return True
+
+def parse_jp2codestream(inpath, xml_tree, out_f, src_jp2file = None):
+
+    if src_jp2file is None:
+        src_jp2filename = get_attribute_val(xml_tree, 'filename')
+        if src_jp2filename is None:
+            print('Cannot find JP2KCodeStream.filename attribute')
+            return False
+        if os.path.exists(src_jp2filename):
+            src_jp2file = open(src_jp2filename, 'rb')
+        else:
+            src_jp2file = open(os.path.join(inpath, src_jp2filename), 'rb')
+
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(xml_tree)):
+        child = xml_tree[child_idx]
+        if child[XML_TYPE_IDX] != gdal.CXT_Element:
+            continue
+        if not parse_jpc_marker(child, out_f, src_jp2file):
+            return False
+    return True
+
+def parse_jp2_box(xml_tree, out_f, src_jp2file):
+    if not(xml_tree[XML_TYPE_IDX] == gdal.CXT_Element and xml_tree[XML_VALUE_IDX] == 'JP2Box'):
+        print('Not a JP2Box element')
+        return False
+    jp2box_name = get_attribute_val(xml_tree, 'name')
+    if jp2box_name is None:
+        print('Cannot find JP2Box.name attribute')
+        return False
+    if len(jp2box_name) != 4:
+        print('Invalid JP2Box.name : %s' % jp2box_name)
+        return False
+    hex_binary_content = get_node_content(find_xml_node(xml_tree, 'BinaryContent', immediate_child = True))
+    decoded_content = find_xml_node(xml_tree, 'DecodedContent', immediate_child = True)
+    decoded_geotiff = find_xml_node(xml_tree, 'DecodedGeoTIFF', immediate_child = True)
+    text_content = get_node_content(find_xml_node(xml_tree, 'TextContent', immediate_child = True))
+    xml_content = find_xml_node(xml_tree, 'XMLContent', immediate_child = True)
+    jp2box = find_xml_node(xml_tree, 'JP2Box', immediate_child = True)
+    jp2codestream = find_xml_node(xml_tree, 'JP2KCodeStream', immediate_child = True)
+
+    if hex_binary_content:
+        if decoded_content or decoded_geotiff or text_content or xml_content or jp2box:
+            print('BinaryContent found, and one of DecodedContent/DecodedGeoTIFF/TextContent/XMLContent/JP2Box. The latter will be ignored')
+        if jp2box_name == 'uuid':
+            uuid = get_node_content(find_xml_node(xml_tree, 'UUID', immediate_child = True))
+            if uuid is None:
+                print('Cannot find JP2Box.UUID element')
+                return False
+        else:
+            uuid = ''
+        out_f.write(struct.pack('>I' * 1, 8 + int(len(hex_binary_content)/2) + int(len(uuid)/2)))
+        out_f.write(jp2box_name.encode('ascii'))
+        write_hexstring_as_binary(uuid, out_f)
+        write_hexstring_as_binary(hex_binary_content, out_f)
+
+    elif decoded_content:
+        if decoded_geotiff or text_content or xml_content or jp2box:
+            print('DecodedContent found, and one of DecodedGeoTIFF/TextContent/XMLContent/JP2Box. The latter will be ignored')
+        pos = out_f.tell()
+        out_f.write(struct.pack('>I' * 1, 0))
+        out_f.write(jp2box_name.encode('ascii'))
+        for child_idx in range(XML_FIRST_CHILD_IDX, len(decoded_content)):
+            child = decoded_content[child_idx]
+            if child[XML_TYPE_IDX] == gdal.CXT_Element and child[XML_VALUE_IDX] == 'Field':
+                if not parse_field(child, out_f, src_jp2file):
+                    return False
+        new_pos = out_f.tell()
+        out_f.seek(pos, 0)
+        out_f.write(struct.pack('>I' * 1, new_pos - pos))
+        out_f.seek(new_pos, 0)
+
+    elif text_content:
+        if decoded_geotiff or xml_content or jp2box:
+            print('TextContent found, and one of DecodedGeoTIFF/XMLContent/JP2Box. The latter will be ignored')
+        out_f.write(struct.pack('>I' * 1, 8 + len(text_content)))
+        out_f.write(jp2box_name.encode('ascii'))
+        out_f.write(text_content.encode('latin1'))
+
+    elif xml_content:
+        if decoded_geotiff or jp2box:
+            print('XMLContent found, and one of DecodedGeoTIFF/JP2Box. The latter will be ignored')
+        serialized_xml_content = gdal.SerializeXMLTree(xml_content[XML_FIRST_CHILD_IDX])
+        out_f.write(struct.pack('>I' * 1, 8 + len(serialized_xml_content)))
+        out_f.write(jp2box_name.encode('ascii'))
+        out_f.write(serialized_xml_content.encode('latin1'))
+
+    elif jp2box:
+        if decoded_geotiff:
+            print('JP2Box found, and one of DecodedGeoTIFF. The latter will be ignored')
+        pos = out_f.tell()
+        out_f.write(struct.pack('>I' * 1, 0))
+        out_f.write(jp2box_name.encode('ascii'))
+        for child_idx in range(XML_FIRST_CHILD_IDX, len(xml_tree)):
+            child = xml_tree[child_idx]
+            if child[XML_TYPE_IDX] == gdal.CXT_Element and child[XML_VALUE_IDX] == 'JP2Box':
+                if not parse_jp2_box(child, out_f, src_jp2file):
+                    return False
+        new_pos = out_f.tell()
+        out_f.seek(pos, 0)
+        out_f.write(struct.pack('>I' * 1, new_pos - pos))
+        out_f.seek(new_pos, 0)
+
+    elif decoded_geotiff:
+        serialized_xml_content = gdal.SerializeXMLTree(decoded_geotiff[XML_FIRST_CHILD_IDX])
+
+        vrt_ds = gdal.Open(serialized_xml_content)
+        if vrt_ds is None:
+            print('Cannot decode VRTDataset. Outputing empty content')
+            binary_content = ''
+        else:
+            out_ds = gdal.GetDriverByName('GTiff').CreateCopy('/vsimem/out.tif', vrt_ds)
+            del out_ds
+            tif_f = gdal.VSIFOpenL('/vsimem/out.tif', 'rb')
+            binary_content = gdal.VSIFReadL(1, 10000, tif_f)
+            gdal.VSIFCloseL(tif_f)
+
+        uuid = get_node_content(find_xml_node(xml_tree, 'UUID', immediate_child = True))
+        if uuid is None:
+            uuid = 'B14BF8BD083D4B43A5AE8CD7D5A6CE03'
+
+        out_f.write(struct.pack('>I' * 1, 8 + len(binary_content) + int(len(uuid)/2)))
+        out_f.write(jp2box_name.encode('ascii'))
+        write_hexstring_as_binary(uuid, out_f)
+        out_f.write(binary_content)
+
+    elif jp2codestream:
+        pos = out_f.tell()
+        out_f.write(struct.pack('>I' * 1, 0))
+        out_f.write(jp2box_name.encode('ascii'))
+        if not parse_jp2codestream(None, jp2codestream, out_f, src_jp2file):
+            return False
+        new_pos = out_f.tell()
+        out_f.seek(pos, 0)
+        out_f.write(struct.pack('>I' * 1, new_pos - pos))
+        out_f.seek(new_pos, 0)
+
+    else:
+        data_offset = get_attribute_val(xml_tree, 'data_offset')
+        if data_offset is None:
+            print('Cannot find JP2Box.data_offset attribute')
+            return False
+        data_offset = int(data_offset)
+
+        data_length = get_attribute_val(xml_tree, 'data_length')
+        if data_length is None:
+            print('Cannot find JP2Box.data_length attribute')
+            return False
+        data_length = int(data_length)
+
+        src_jp2file.seek(data_offset, 0)
+        data = src_jp2file.read(data_length)
+
+        out_f.write(struct.pack('>I' * 1, 8 + data_length))
+        out_f.write(jp2box_name.encode('ascii'))
+        out_f.write(data)
+
+    return True
+
+def parse_jp2file(inpath, xml_tree, out_f):
+    src_jp2filename = get_attribute_val(xml_tree, 'filename')
+    if src_jp2filename is None:
+        print('Cannot find JP2File.filename attribute')
+        return False
+    if os.path.exists(src_jp2filename):
+        src_jp2file = open(src_jp2filename, 'rb')
+    else:
+        src_jp2file = open(os.path.join(inpath, src_jp2filename), 'rb')
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(xml_tree)):
+        child = xml_tree[child_idx]
+        if child[XML_TYPE_IDX] != gdal.CXT_Element:
+            continue
+        if not parse_jp2_box(child, out_f, src_jp2file):
+            return False
+    return True
+
+# Wrapper class for GDAL VSI*L API with class Python file interface
+class VSILFile:
+    def __init__(self, filename, access):
+        self.f = gdal.VSIFOpenL(filename, access)
+
+    def write(self, data):
+        gdal.VSIFWriteL(data, 1, len(data), self.f)
+
+    def tell(self):
+        return gdal.VSIFTellL(self.f)
+
+    def seek(self, pos, ref):
+        gdal.VSIFSeekL(self.f, pos, ref)
+
+    def close(self):
+        gdal.VSIFCloseL(self.f)
+        self.f = None
+
+def build_file(inname, outname):
+
+    inpath = os.path.dirname(inname)
+    xml_tree = gdal.ParseXMLString(open(inname).read())
+    if xml_tree is None:
+        print('Cannot parse %s' % inname)
+        return False
+
+    #out_f = open(outname, 'wb+')
+    out_f = VSILFile(outname, 'wb+')
+    if xml_tree[XML_TYPE_IDX] == gdal.CXT_Element and xml_tree[XML_VALUE_IDX] == 'JP2File':
+        ret = parse_jp2file(inpath, xml_tree, out_f)
+    elif xml_tree[XML_TYPE_IDX] == gdal.CXT_Element and xml_tree[XML_VALUE_IDX] == 'JP2KCodeStream':
+        ret = parse_jp2codestream(inpath, xml_tree, out_f)
+    else:
+        print('Unexpected node: %s' % xml_tree[XML_VALUE_IDX])
+        ret = False
+    out_f.close()
+
+    return ret
+
+def main():
+    i = 1
+    inname = None
+    outname = None
+    while i < len(sys.argv):
+        if sys.argv[i][0] == '-':
+            return Usage()
+        elif inname is None:
+            inname = sys.argv[i]
+        elif outname is None:
+            outname = sys.argv[i]
+        else:
+            return Usage()
+
+        i = i + 1
+
+    if inname is None or outname is None:
+        return Usage()
+
+    if build_file(inname, outname):
+        return 0
+    return 1
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/swig/python/samples/crs2crs2grid.py b/swig/python/samples/crs2crs2grid.py
index f14a6a3..98e0078 100755
--- a/swig/python/samples/crs2crs2grid.py
+++ b/swig/python/samples/crs2crs2grid.py
@@ -34,7 +34,7 @@ import os
 import numpy
 import sys
 
-from osgeo import gdal, gdal_array, osr
+from osgeo import gdal, gdal_array
 
 # Input looks like this:
 """
diff --git a/swig/python/samples/densify.py b/swig/python/samples/densify.py
index c10c461..e41a2f2 100755
--- a/swig/python/samples/densify.py
+++ b/swig/python/samples/densify.py
@@ -292,8 +292,8 @@ class Densify(Translator):
                     segcount = int(math.floor(d/threshold))
                     xa = None
                     ya = None
-                    xb = x0
-                    yb = y0
+                    #xb = x0
+                    #yb = y0
                     remainder = d % threshold
                     for p in range(segcount):
                         if not xa:
diff --git a/swig/python/samples/dump_jp2.py b/swig/python/samples/dump_jp2.py
new file mode 100644
index 0000000..eb0fed5
--- /dev/null
+++ b/swig/python/samples/dump_jp2.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#******************************************************************************
+#  $Id: dump_jp2.py 29068 2015-04-30 09:49:21Z rouault $
+# 
+#  Project:  GDAL
+#  Purpose:  Dump JPEG2000 file structure
+#  Author:   Even Rouault, <even dot rouault at spatialys dot com>
+# 
+#******************************************************************************
+#  Copyright (c) 2015, European Union (European Environment Agency)
+#  Copyright (c) 2015, European Union Satellite Centre
+# 
+#  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.
+#******************************************************************************
+
+import sys
+from osgeo import gdal
+
+def Usage():
+    print('Usage:  dump_jp2 [-dump_gmljp2 out.xml|-] [-dump_crsdictionary out.xml|-]')
+    print('                 [-extract_all_xml_boxes filename_prefix]')
+    print('                 test.jp2')
+    print('')
+    print('Options (all are exclusive of the regular dump):')
+    print('')
+    print('-dump_gmljp2: Writes the content of the GMLJP2 box in the specified')
+    print('              file, or on the console if "-" syntax is used.')
+    print('-dump_crsdictionary: Writes the content of the GML CRS dictionary box in the specified')
+    print('                     file, or on the console if "-" syntax is used.')
+    print('-extract_all_xml_boxes: Extract all XML boxes in separate files, and prefix each filename')
+    print('                        with the supplied prefix. gmljp2://xml/ link will be replaced by')
+    print('                        links to on-disk files.')
+
+    return 1
+
+def dump_gmljp2(filename, out_gmljp2):
+    ds = gdal.Open(filename)
+    if ds is None:
+        print('Cannot open %s' % filename)
+        return 1
+    mdd = ds.GetMetadata('xml:gml.root-instance')
+    if mdd is None:
+        print('No GMLJP2 content found in %s' % filename)
+        return 1
+    if out_gmljp2 == '-':
+        print(mdd[0])
+    else:
+        f = open(out_gmljp2, 'wt')
+        f.write(mdd[0])
+        f.close()
+        print('INFO: %s written with content of GMLJP2 box' % out_gmljp2)
+    return 0
+
+def dump_crsdictionary(filename, out_crsdictionary):
+    ds = gdal.Open(filename)
+    if ds is None:
+        print('Cannot open %s' % filename)
+        return 1
+    mdd_list = ds.GetMetadataDomainList()
+    if mdd_list is None:
+        mdd_list = []
+    for domain in mdd_list:
+        if domain.startswith('xml:'):
+            mdd_item = ds.GetMetadata(domain)[0]
+            if mdd_item.find('<Dictionary') >= 0 or mdd_item.find('<gml:Dictionary') >= 0:
+                if out_crsdictionary == '-':
+                    print(mdd_item)
+                else:
+                    f = open(out_crsdictionary, 'wt')
+                    f.write(mdd_item)
+                    f.close()
+                    print('INFO: %s written with content of CRS dictionary box (%s)' % (out_crsdictionary, domain[4:]))
+                return 0
+
+    print('No CRS dictionary content found in %s' % filename)
+    return 1
+
+def extract_all_xml_boxes(filename, prefix):
+    ds = gdal.Open(filename)
+    if ds is None:
+        print('Cannot open %s' % filename)
+        return 1
+    mdd_list = ds.GetMetadataDomainList()
+    if mdd_list is None:
+        mdd_list = []
+    for domain in mdd_list:
+        if domain.startswith('xml:'):
+            mdd_item = ds.GetMetadata(domain)[0]
+            boxname = domain[4:]
+            if boxname == 'gml.root-instance':
+                boxname = 'gml_root_instance.gml'
+            out_filename = prefix + boxname
+
+            # Correct references to gmljp2://xml/foo to prefix_foo
+            out_content = ''
+            pos = 0
+            while True:
+                new_pos = mdd_item.find('gmljp2://xml/', pos)
+                if new_pos < 0:
+                    out_content += mdd_item[pos:]
+                    break
+
+                # Check that the referenced box really exists
+                end_gmljp2_link_space = mdd_item.find(' ', new_pos)
+                end_gmljp2_link_double_quote = mdd_item.find('"', new_pos)
+                end_gmljp2_link = -1
+                if end_gmljp2_link_space >= 0 and end_gmljp2_link_double_quote >= 0:
+                    if end_gmljp2_link_space < end_gmljp2_link_double_quote:
+                        end_gmljp2_link = end_gmljp2_link_space
+                    else:
+                        end_gmljp2_link = end_gmljp2_link_double_quote
+                elif end_gmljp2_link_space >= 0:
+                     end_gmljp2_link = end_gmljp2_link_space
+                elif end_gmljp2_link_double_quote >= 0:
+                     end_gmljp2_link = end_gmljp2_link_double_quote
+                if end_gmljp2_link >= 0:
+                    referenced_box = mdd_item[new_pos + len('gmljp2://xml/'):end_gmljp2_link]
+                    if not (('xml:' + referenced_box) in mdd_list):
+                        print('Warning: box %s reference box %s, but the latter is not found' % (boxname, referenced_box))
+
+                out_content += mdd_item[pos:new_pos]
+                out_content += prefix
+                pos = new_pos + len('gmljp2://xml/')
+
+            f = open(out_filename, 'wt')
+            f.write(out_content)
+            f.close()
+            print('INFO: %s written' % out_filename)
+
+    if len(mdd_list) == 0:
+        print('No XML box found')
+        return 1
+    return 0
+
+def main():
+    i = 1
+    out_gmljp2 = None
+    out_crsdictionary = None
+    extract_all_xml_boxes_prefix = None
+    filename = None
+    while i < len(sys.argv):
+        if sys.argv[i] == "-dump_gmljp2":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            out_gmljp2 = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i] == "-dump_crsdictionary":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            out_crsdictionary = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i] == "-extract_all_xml_boxes":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            extract_all_xml_boxes_prefix = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i][0] == '-':
+            return Usage()
+        elif filename is None:
+            filename = sys.argv[i]
+        else:
+            return Usage()
+
+        i = i + 1
+
+    if filename is None:
+        return Usage()
+
+    if out_gmljp2 or out_crsdictionary or extract_all_xml_boxes_prefix:
+        if out_gmljp2:
+            if dump_gmljp2(filename, out_gmljp2) != 0:
+                return 1
+        if out_crsdictionary:
+            if dump_crsdictionary(filename, out_crsdictionary) != 0:
+                return 1
+        if extract_all_xml_boxes_prefix:
+            if extract_all_xml_boxes(filename, extract_all_xml_boxes_prefix) != 0:
+                return 1
+    else:
+        s = gdal.GetJPEG2000StructureAsString(filename, ['ALL=YES'])
+        print(s)
+
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/swig/python/samples/fft.py b/swig/python/samples/fft.py
index 6528d74..7d5b1b2 100755
--- a/swig/python/samples/fft.py
+++ b/swig/python/samples/fft.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: fft.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: fft.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  GDAL Python samples
 # Purpose:  Script to perform forward and inverse two-dimensional fast
@@ -32,12 +32,8 @@
 
 try:
     from osgeo import gdal
-    from osgeo.gdalconst import *
-    import numpy as Numeric
 except ImportError:
     import gdal
-    from gdalconst import *
-    import Numeric
     
 import FFT
 import sys
@@ -53,29 +49,29 @@ def Usage():
 # =============================================================================
 def ParseType(type):
     if type == 'Byte':
-        return GDT_Byte
+        return gdal.GDT_Byte
     elif type == 'Int16':
-        return GDT_Int16
+        return gdal.GDT_Int16
     elif type == 'UInt16':
-        return GDT_UInt16
+        return gdal.GDT_UInt16
     elif type == 'Int32':
-        return GDT_Int32
+        return gdal.GDT_Int32
     elif type == 'UInt32':
-        return GDT_UInt32
+        return gdal.GDT_UInt32
     elif type == 'Float32':
-        return GDT_Float32
+        return gdal.GDT_Float32
     elif type == 'Float64':
-        return GDT_Float64
+        return gdal.GDT_Float64
     elif type == 'CInt16':
-        return GDT_CInt16
+        return gdal.GDT_CInt16
     elif type == 'CInt32':
-        return GDT_CInt32
+        return gdal.GDT_CInt32
     elif type == 'CFloat32':
-        return GDT_CFloat32
+        return gdal.GDT_CFloat32
     elif type == 'CFloat64':
-        return GDT_CFloat64
+        return gdal.GDT_CFloat64
     else:
-        return GDT_Byte
+        return gdal.GDT_Byte
 # =============================================================================
 
 infile = None
@@ -92,7 +88,7 @@ while i < len(sys.argv):
     if arg == '-inv':
         transformation = 'inverse'
         if type == None:
-            type = GDT_Float32
+            type = gdal.GDT_Float32
         
     elif arg == '-of':
         i = i + 1
@@ -120,9 +116,9 @@ if  outfile is None:
     Usage()
 
 if type == None:
-    type = GDT_CFloat32
+    type = gdal.GDT_CFloat32
 
-indataset = gdal.Open( infile, GA_ReadOnly )
+indataset = gdal.Open( infile, gdal.GA_ReadOnly )
 
 out_driver = gdal.GetDriverByName(format)
 outdataset = out_driver.Create(outfile, indataset.RasterXSize, indataset.RasterYSize, indataset.RasterCount, type)
diff --git a/swig/python/samples/gdal2grd.py b/swig/python/samples/gdal2grd.py
index 2fa776c..7f4f552 100755
--- a/swig/python/samples/gdal2grd.py
+++ b/swig/python/samples/gdal2grd.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: gdal2grd.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: gdal2grd.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  GDAL Python samples
 # Purpose:  Script to write out ASCII GRD rasters (used in Golden Software
@@ -33,18 +33,9 @@
 
 try:
     from osgeo import gdal
-    from osgeo.gdalconst import *
     gdal.TermProgress = gdal.TermProgress_nocb
 except ImportError:
     import gdal
-    from gdalconst import *
-
-try:
-    import numpy as Numeric
-    Numeric.arrayrange = Numeric.arange
-except ImportError:
-    import Numeric
-
 
 import sys
 
@@ -95,7 +86,7 @@ if infile is None:
 if  outfile is None:
     Usage()
 
-indataset = gdal.Open(infile, GA_ReadOnly)
+indataset = gdal.Open(infile, gdal.GA_ReadOnly)
 if infile == None:
     print('Cannot open', infile)
     sys.exit(2)
diff --git a/swig/python/samples/gdal_lut.py b/swig/python/samples/gdal_lut.py
index 86dfdae..693dda7 100755
--- a/swig/python/samples/gdal_lut.py
+++ b/swig/python/samples/gdal_lut.py
@@ -43,8 +43,6 @@ except:
 
 
 import sys
-import string
-import os.path
 
 # =============================================================================
 #		read_lut()
diff --git a/swig/python/samples/gdalcopyproj.py b/swig/python/samples/gdalcopyproj.py
index 1bb2f37..7ee99d5 100755
--- a/swig/python/samples/gdalcopyproj.py
+++ b/swig/python/samples/gdalcopyproj.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gdalcopyproj.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdalcopyproj.py 28391 2015-01-30 19:57:31Z rouault $
 # 
 #  Name:     gdalcopyproj.py
 #  Project:  GDAL Python Interface
@@ -39,7 +39,6 @@ except ImportError:
     import gdal
 
 import sys
-import os.path
 
 if len(sys.argv) < 3:
     print("Usage: gdalcopyproj.py source_file dest_file")
diff --git a/swig/python/samples/gdalinfo.py b/swig/python/samples/gdalinfo.py
index ca680a4..f165e6c 100755
--- a/swig/python/samples/gdalinfo.py
+++ b/swig/python/samples/gdalinfo.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #/******************************************************************************
-# * $Id: gdalinfo.py 27044 2014-03-16 23:41:27Z rouault $
+# * $Id: gdalinfo.py 28391 2015-01-30 19:57:31Z rouault $
 # *
 # * Project:  GDAL Utilities
 # * Purpose:  Python port of Commandline application to list info about a file.
@@ -59,7 +59,6 @@ def EQUAL(a, b):
 def main( argv = None ):
 
     bComputeMinMax = False
-    bSample = False
     bShowGCPs = True
     bShowMetadata = True
     bShowRAT=True
@@ -118,8 +117,6 @@ def main( argv = None ):
         elif EQUAL(argv[i], "-approx_stats"):
             bStats = True
             bApproxStats = True
-        elif EQUAL(argv[i], "-sample"):
-            bSample = True
         elif EQUAL(argv[i], "-checksum"):
             bComputeChecksum = True
         elif EQUAL(argv[i], "-nogcp"):
@@ -552,7 +549,8 @@ def main( argv = None ):
                             sEntry[3] ))
 
         if bShowRAT:
-            hRAT = hBand.GetDefaultRAT()
+            pass
+            #hRAT = hBand.GetDefaultRAT()
 
             #GDALRATDumpReadable( hRAT, None );
 
diff --git a/swig/python/samples/gdalpythonserver.py b/swig/python/samples/gdalpythonserver.py
index a862e39..5fd8e76 100755
--- a/swig/python/samples/gdalpythonserver.py
+++ b/swig/python/samples/gdalpythonserver.py
@@ -33,9 +33,9 @@
 
 import sys
 import os
-from struct import *
+import struct
 
-from osgeo import gdalconst, gdal
+from osgeo import gdal
 
 class GDALPythonServerRasterBand:
 
@@ -346,15 +346,21 @@ VERBOSE = 0
 
 def read_int():
     if sys.version_info >= (3,0,0):
-        return unpack('i', sys.stdin.read(4).encode('latin1'))[0]
+        return struct.unpack('i', sys.stdin.read(4).encode('latin1'))[0]
     else:
-        return unpack('i', sys.stdin.read(4))[0]
+        return struct.unpack('i', sys.stdin.read(4))[0]
+
+def read_bigint():
+    if sys.version_info >= (3,0,0):
+        return struct.unpack('q', sys.stdin.read(8).encode('latin1'))[0]
+    else:
+        return struct.unpack('q', sys.stdin.read(8))[0]
 
 def read_double():
     if sys.version_info >= (3,0,0):
-        return unpack('d', sys.stdin.read(8).encode('latin1'))[0]
+        return struct.unpack('d', sys.stdin.read(8).encode('latin1'))[0]
     else:
-        return unpack('d', sys.stdin.read(8))[0]
+        return struct.unpack('d', sys.stdin.read(8))[0]
 
 def read_str():
     length = read_int()
@@ -374,11 +380,18 @@ def read_strlist():
 
 def write_int(i):
     if i is True:
-        v = pack('i', 1)
+        v = struct.pack('i', 1)
     elif i is False or i is None:
-        v = pack('i', 0)
+        v = struct.pack('i', 0)
+    else:
+        v = struct.pack('i', i)
+    if sys.version_info >= (3,0,0):
+        sys.stdout.write(v.decode('latin1'))
     else:
-        v = pack('i', i)
+        sys.stdout.write(v)
+
+def write_uint64(i):
+    v = struct.pack('Q', i)
     if sys.version_info >= (3,0,0):
         sys.stdout.write(v.decode('latin1'))
     else:
@@ -386,9 +399,9 @@ def write_int(i):
 
 def write_double(d):
     if sys.version_info >= (3,0,0):
-        sys.stdout.write(pack('d', d).decode('latin1'))
+        sys.stdout.write(struct.pack('d', d).decode('latin1'))
     else:
-        sys.stdout.write(pack('d', d))
+        sys.stdout.write(struct.pack('d', d))
 
 def write_str(s):
     if s is None:
@@ -453,9 +466,9 @@ def main_loop():
 
         if instr == INSTR_GetGDALVersion:
             if sys.version_info >= (3,0,0):
-                lsb = unpack('B', sys.stdin.read(1).encode('latin1'))[0]
+                lsb = struct.unpack('B', sys.stdin.read(1).encode('latin1'))[0]
             else:
-                lsb = unpack('B', sys.stdin.read(1))[0]
+                lsb = struct.unpack('B', sys.stdin.read(1))[0]
             ver = read_str()
             vmajor = read_int()
             vminor = read_int()
@@ -471,10 +484,10 @@ def main_loop():
                 sys.stderr.write('protovminor=%d\n' % protovminor)
                 sys.stderr.write('extra_bytes=%d\n' % extra_bytes)
 
-            write_str('1.10')
-            write_int(1) # vmajor
-            write_int(10) # vminor
-            write_int(1) # protovmajor
+            write_str('2.0')
+            write_int(2) # vmajor
+            write_int(0) # vminor
+            write_int(2) # protovmajor
             write_int(0) # protovminor
             write_int(0) # extra bytes
             continue
@@ -531,7 +544,7 @@ def main_loop():
                 for cap in caps_list:
                     caps[int(cap / 8)] = caps[int(cap / 8)] | (1 << (cap % 8))
                 for i in range(16):
-                    sys.stdout.write(pack('B', caps[i])) # caps
+                    sys.stdout.write(struct.pack('B', caps[i])) # caps
                 write_str(server_ds.GetDescription())
                 drv = server_ds.GetDriver()
                 if drv is not None:
@@ -560,20 +573,20 @@ def main_loop():
         elif instr == INSTR_Create:
             filename = read_str()
             cwd = read_str()
-            xsize = read_int()
-            ysize = read_int()
-            bands = read_int()
-            datatype = read_int()
-            options = read_strlist()
+            read_int() # xsize = 
+            read_int() # ysize = 
+            read_int() # bands = 
+            read_int() # datatype = 
+            read_strlist() #options = 
             write_marker()
             # FIXME
             write_int(0)
         elif instr == INSTR_CreateCopy:
             filename = read_str()
-            src_description = read_str()
+            read_str() # src_description = 
             cwd = read_str()
-            strict = read_int()
-            options = read_strlist()
+            read_int() # strict = 
+            read_strlist() # options = 
             # FIXME
             write_int(0)
         elif instr == INSTR_QuietDelete:
@@ -633,12 +646,12 @@ def main_loop():
             nBufType = read_int()
             nBandCount = read_int()
             panBandMap = []
-            size = read_int()
+            read_int() # size = 
             for i in range(nBandCount):
                 panBandMap.append(read_int())
-            nPixelSpace = read_int()
-            nLineSpace = read_int()
-            nBandSpace = read_int()
+            nPixelSpace = read_bigint()
+            nLineSpace = read_bigint()
+            nBandSpace = read_bigint()
             val = server_ds.IRasterIO_Read(nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, nBufType, panBandMap, nPixelSpace, nLineSpace, nBandSpace)
             write_marker()
             if val is None:
@@ -788,9 +801,9 @@ def main_loop():
                 write_int(CE_Failure)
             else:
                 write_int(CE_None)
-                write_int(len(val) * 4)
+                write_int(len(val) * 8)
                 for i in range(len(val)):
-                    write_int(val[i])
+                    write_uint64(val[i])
         #elif instr == INSTR_Band_GetDefaultHistogram:
         #    bForce = read_int()
         #    write_marker()
diff --git a/swig/python/samples/get_soundg.py b/swig/python/samples/get_soundg.py
index d1fbffc..077fa3b 100755
--- a/swig/python/samples/get_soundg.py
+++ b/swig/python/samples/get_soundg.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: get_soundg.py 18195 2009-12-06 20:24:39Z rouault $
+# $Id: get_soundg.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Extract SOUNDGings from an S-57 dataset, and write them to
@@ -31,13 +31,10 @@
 ###############################################################################
 
 try:
-    from osgeo import osr
     from osgeo import ogr
 except ImportError:
-    import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/samples/hsv_merge.py b/swig/python/samples/hsv_merge.py
index a9114b6..aa0b87a 100755
--- a/swig/python/samples/hsv_merge.py
+++ b/swig/python/samples/hsv_merge.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: hsv_merge.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: hsv_merge.py 28391 2015-01-30 19:57:31Z rouault $
 # 
 #  Project:  GDAL Python Interface
 #  Purpose:  Script to merge greyscale as intensity into an RGB(A) image, for
@@ -31,8 +31,7 @@
 #  DEALINGS IN THE SOFTWARE.
 #******************************************************************************
 
-from osgeo import gdal, gdal_array
-from osgeo.gdalconst import *
+from osgeo import gdal
 import numpy
 import sys
 
@@ -158,10 +157,10 @@ while i < len(argv):
 if dst_color_filename is None:
     Usage()
 
-datatype = GDT_Byte
+datatype = gdal.GDT_Byte
 
-hilldataset = gdal.Open( src_greyscale_filename, GA_ReadOnly )
-colordataset = gdal.Open( src_color_filename, GA_ReadOnly )
+hilldataset = gdal.Open( src_greyscale_filename, gdal.GA_ReadOnly )
+colordataset = gdal.Open( src_color_filename, gdal.GA_ReadOnly )
 
 #check for 3 or 4 bands in the color file
 if (colordataset.RasterCount != 3 and colordataset.RasterCount != 4):
diff --git a/swig/python/samples/jpeg_in_tiff_extract.py b/swig/python/samples/jpeg_in_tiff_extract.py
new file mode 100755
index 0000000..9c9cc0a
--- /dev/null
+++ b/swig/python/samples/jpeg_in_tiff_extract.py
@@ -0,0 +1,251 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+###############################################################################
+# $Id: jpeg_in_tiff_extract.py 28391 2015-01-30 19:57:31Z rouault $
+#
+# Project:  GDAL/OGR samples
+# Purpose:  Extract a JPEG file from a JPEG-in-TIFF tile/strip
+# Author:   Even Rouault <even dot rouault at mines dash paris dot org>
+#
+###############################################################################
+# Copyright (c) 2014, Even Rouault <even dot rouault at mines-paris dot org>
+#
+# 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.
+###############################################################################
+
+from osgeo import gdal
+import sys
+
+###############################################################
+# Usage()
+
+def Usage():
+    print('Usage: jpeg_in_tiff_extract.py in.tif out.jpg [tile_x tile_y [band_nbr]]')
+    print('')
+    print('Extract a JPEG file from a JPEG-in-TIFF tile/strip.')
+    print('If tile_x tile_y are not specified, then all tiles/strips are extracted')
+    print('in filenames out_[bandnbr_]tx_ty.jpg')
+    print('')
+
+    return 1
+
+###############################################################
+def extract_tile(ds, src_band_nbr, tile_x, tile_y, jpg_filename):
+
+    block_offset = ds.GetRasterBand(src_band_nbr).GetMetadataItem('BLOCK_OFFSET_%d_%d' % (tile_x, tile_y), 'TIFF')
+    block_size = ds.GetRasterBand(src_band_nbr).GetMetadataItem('BLOCK_SIZE_%d_%d' % (tile_x, tile_y), 'TIFF')
+    if block_offset is None or block_size is None:
+        print('ERROR: Cannot find block (%d,%d)' % (tile_x, tile_y))
+        return 1
+
+    jpegtables = ds.GetRasterBand(src_band_nbr).GetMetadataItem('JPEGTABLES', 'TIFF')
+    if jpegtables is not None:
+        if (len(jpegtables) % 2) != 0 or jpegtables[0:4] != 'FFD8' or jpegtables[-2:] != 'D9':
+            print('ERROR: Invalid JPEG tables')
+            print(jpegtables)
+            return 1
+
+        # Remove final D9
+        jpegtables = jpegtables[0:-2]
+
+    tiff_f = gdal.VSIFOpenL(ds.GetDescription(), 'rb')
+    if tiff_f is None:
+        print('ERROR: Cannot reopen %s' % ds.GetDescription())
+        return 1
+
+    out_f = gdal.VSIFOpenL(jpg_filename, 'wb')
+    if out_f is None:
+        print('ERROR: Cannot create %s' % jpg_filename)
+        gdal.VSIFCloseL(tiff_f)
+        return 1
+
+    # Write JPEG tables
+    if jpegtables is not None:
+        for i in range(int(len(jpegtables)/2)):
+            c1 = ord(jpegtables[2*i])
+            c2 = ord(jpegtables[2*i+1])
+            if c1 >= ord('0') and c1 <= ord('9'):
+                val = c1 - ord('0')
+            else:
+                val = (c1 - ord('A')) + 10
+            val = val * 16
+            if c2 >= ord('0') and c2 <= ord('9'):
+                val = val + (c2 - ord('0'))
+            else:
+                val = val + (c2 - ord('A')) + 10
+            gdal.VSIFWriteL(chr(val), 1, 1, out_f)
+    else:
+        gdal.VSIFWriteL(chr(0xFF), 1, 1, out_f)
+        gdal.VSIFWriteL(chr(0xD8), 1, 1, out_f)
+
+    # Write Adobe APP14 marker if necessary
+    interleave = ds.GetMetadataItem('INTERLEAVE', 'IMAGE_STRUCTURE')
+    photometric = ds.GetMetadataItem('COMPRESSION', 'IMAGE_STRUCTURE')
+    if interleave == 'PIXEL' and photometric == 'JPEG' and ds.RasterCount == 3:
+        adobe_app14 = [ 0xFF, 0xEE, 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00 ]
+        for c in adobe_app14:
+            gdal.VSIFWriteL(chr(c), 1, 1, out_f)
+
+    # Write JPEG codestream
+    # skip leading 0xFF 0xD8
+    gdal.VSIFSeekL(tiff_f, int(block_offset) + 2, 0)
+    data = gdal.VSIFReadL(1, int(block_size) - 2, tiff_f)
+    gdal.VSIFCloseL(tiff_f)
+    gdal.VSIFWriteL(data, 1, len(data), out_f)
+
+    gdal.VSIFCloseL(out_f)
+
+    aux_xml_filename = '%s.aux.xml' % jpg_filename
+    gt = ds.GetGeoTransform()
+    srs = ds.GetProjectionRef()
+    if srs is not None and srs != '':
+        sub_gt = [ gt[i] for i in range(6) ]
+        (blockxsize, blockysize) = ds.GetRasterBand(1).GetBlockSize()
+        sub_gt[0] = gt[0] + tile_x * blockxsize * gt[1]
+        sub_gt[3] = gt[3] + tile_y * blockysize * gt[5]
+
+        out_f = gdal.VSIFOpenL(aux_xml_filename, 'wb')
+        if out_f is None:
+            print('ERROR: Cannot create %s' % aux_xml_filename)
+            return 1
+        content = """<PAMDataset>
+    <SRS>%s</SRS>
+    <GeoTransform>%.18g,%.18g,%.18g,%.18g,%.18g,%.18g</GeoTransform>
+    </PAMDataset>
+    """ % (srs, sub_gt[0], sub_gt[1], sub_gt[2], sub_gt[3], sub_gt[4], sub_gt[5])
+        gdal.VSIFWriteL(content, 1, len(content), out_f)
+        gdal.VSIFCloseL(out_f)
+    else:
+        gdal.Unlink('%s.aux.xml' % jpg_filename)
+
+    return 0
+
+###############################################################
+def jpeg_in_tiff_extract(argv):
+
+    if len(argv) < 2:
+        print('ERROR: Not enough arguments')
+        return Usage()
+
+    tiff_filename = argv[0]
+    jpg_filename = argv[1]
+    if len(argv) >= 3:
+        tile_x = int(argv[2])
+        tile_y = int(argv[3])
+        if len(argv) == 5:
+            band_nbr = int(argv[4])
+        else:
+            band_nbr = None
+    else:
+        tile_x = None
+        tile_y = None
+
+    radix_jpg_filename = jpg_filename
+    extensions = [ '.jpg', '.jpeg', '.JPG', '.JPEG' ]
+    extension = None
+    for i in range(len(extensions)):
+        pos = radix_jpg_filename.find(extensions[i])
+        if pos >= 0:
+            extension = extensions[i]
+            radix_jpg_filename = radix_jpg_filename[0:pos]
+            break
+    if pos < 0:
+        print('ERROR: %s should end with .jpg/.jpeg' % jpg_filename)
+        return 1
+
+    ds = gdal.Open(tiff_filename)
+    if ds is None:
+        print('ERROR: Cannot open %s' % tiff_filename)
+        return 1
+
+    if ds.GetDriver() is None or \
+       ds.GetDriver().GetDescription() != 'GTiff':
+        print('ERROR: %s is not a TIFF dataset.' % tiff_filename)
+        return 1
+
+    photometric = ds.GetMetadataItem('COMPRESSION', 'IMAGE_STRUCTURE')
+    interleave = ds.GetMetadataItem('INTERLEAVE', 'IMAGE_STRUCTURE')
+
+    if photometric != 'JPEG' and photometric != 'YCbCr JPEG':
+        print('ERROR: %s is not a JPEG-compressed TIFF dataset.' % tiff_filename)
+        return 1
+
+    (blockxsize, blockysize) = ds.GetRasterBand(1).GetBlockSize()
+    if blockysize == 1:
+        blockysize = ds.RasterYSize
+    block_in_row = (ds.RasterXSize + blockxsize - 1) / blockxsize
+    block_in_col = (ds.RasterYSize + blockysize - 1) / blockysize
+
+    # Extract single tile ?
+    if tile_x is not None:
+
+        if tile_x < 0 or tile_x >= block_in_row:
+            print('ERROR: Invalid tile_x : %d. Should be >= 0 and < %d' % (tile_x, block_in_row))
+            return 1
+        if tile_y < 0 or tile_y >= block_in_col:
+            print('ERROR: Invalid tile_y : %d. Should be >= 0 and < %d' % (tile_y, block_in_col))
+            return 1
+
+        if ds.RasterCount > 1:
+            if interleave == 'PIXEL':
+                if band_nbr is not None:
+                    print('ERROR: For a INTERLEAVE=PIXEL dataset, band_nbr should NOT be specified')
+                    return 1
+            else:
+                if band_nbr is None:
+                    print('ERROR: For a INTERLEAVE=BAND dataset, band_nbr should be specified')
+                    return 1
+
+        if band_nbr is not None:
+            if band_nbr < 1 or band_nbr >= ds.RasterCount:
+                print('ERROR: Invalid band_nbr : %d. Should be >= 1 and <= %d' % (tile_y, ds.RasterCount))
+                return 1
+
+        if band_nbr is not None:
+            src_band_nbr = band_nbr
+        else:
+            src_band_nbr = 1
+
+        return extract_tile(ds, src_band_nbr, tile_x, tile_y, jpg_filename)
+
+    # Extract all tiles
+    else:
+        if ds.RasterCount == 1 or interleave == 'PIXEL':
+            for tile_y in range(block_in_col):
+                for tile_x in range(block_in_row):
+                    filename = '%s_%d_%d%s' % (radix_jpg_filename, tile_x, tile_y, extension)
+                    ret = extract_tile(ds, 1, tile_x, tile_y, filename)
+                    if ret != 0:
+                        return ret
+        else:
+            for src_band_nbr in range(ds.RasterCount):
+                for tile_y in range(block_in_col):
+                    for tile_x in range(block_in_row):
+                        filename = '%s_%d_%d_%d%s' % (radix_jpg_filename, src_band_nbr+1, tile_x, tile_y, extension)
+                        ret = extract_tile(ds, src_band_nbr+1, tile_x, tile_y, filename)
+                        if ret != 0:
+                            return ret
+        return 0
+
+###############################################################
+# Entry point
+
+if __name__ == '__main__':
+    argv = gdal.GeneralCmdLineProcessor( sys.argv )
+    sys.exit(jpeg_in_tiff_extract(argv[1:]))
diff --git a/swig/python/samples/load2odbc.py b/swig/python/samples/load2odbc.py
index 418c5e7..6baf244 100755
--- a/swig/python/samples/load2odbc.py
+++ b/swig/python/samples/load2odbc.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: load2odbc.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: load2odbc.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Load ODBC table to an ODBC datastore.  Uses direct SQL 
@@ -31,13 +31,10 @@
 ###############################################################################
 
 try:
-    from osgeo import osr
     from osgeo import ogr
 except ImportError:
-    import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/samples/loslas2ntv2.py b/swig/python/samples/loslas2ntv2.py
index b0f1352..02bc335 100755
--- a/swig/python/samples/loslas2ntv2.py
+++ b/swig/python/samples/loslas2ntv2.py
@@ -30,10 +30,8 @@
 #  DEALINGS IN THE SOFTWARE.
 #******************************************************************************
 
-from osgeo import osr
 from osgeo import gdal
 import sys
-import string
 
 # dummy object to hold options
 class Options:
@@ -109,7 +107,7 @@ def auto_noaa( options, loslas_list ):
     original_metadata = options.metadata
     
     have_nad27 = 0
-    have_hpgn = 0
+    #have_hpgn = 0
 
     for los in loslas_list:
 
@@ -142,7 +140,7 @@ def auto_noaa( options, loslas_list ):
                 options.append = 1
             have_nad27 = 1
 
-        print 'Integrate %s into %s.' % (los, ntv2_filename)
+        print('Integrate %s into %s.' % (los, ntv2_filename))
         
         TranslateLOSLAS( los, ntv2_filename, options )
         
diff --git a/swig/python/samples/ogr2ogr.py b/swig/python/samples/ogr2ogr.py
index 0fd9bf8..6bbae6d 100755
--- a/swig/python/samples/ogr2ogr.py
+++ b/swig/python/samples/ogr2ogr.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #/******************************************************************************
-# * $Id: ogr2ogr.py 27044 2014-03-16 23:41:27Z rouault $
+# * $Id: ogr2ogr.py 28392 2015-01-30 21:01:09Z rouault $
 # *
 # * Project:  OpenGIS Simple Features Reference Implementation
 # * Purpose:  Python port of a simple client for translating between formats.
@@ -184,8 +184,8 @@ def main(args = None, progress_func = TermProgress, progress_data = None):
     pszClipDstSQL = None
     pszClipDstLayer = None
     pszClipDstWhere = None
-    pszSrcEncoding = None
-    pszDstEncoding = None
+    #pszSrcEncoding = None
+    #pszDstEncoding = None
     bWrapDateline = False
     bExplodeCollections = False
     pszZField = None
@@ -337,7 +337,7 @@ def main(args = None, progress_func = TermProgress, progress_data = None):
 
         elif EQUAL(args[iArg],"-where") and iArg < nArgc-1:
             iArg = iArg + 1
-            pszWHERE = args[++iArg]
+            pszWHERE = args[iArg]
 
         elif EQUAL(args[iArg],"-select") and iArg < nArgc-1:
             iArg = iArg + 1
diff --git a/swig/python/samples/ogr2vrt.py b/swig/python/samples/ogr2vrt.py
index b283040..c152859 100755
--- a/swig/python/samples/ogr2vrt.py
+++ b/swig/python/samples/ogr2vrt.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 ###############################################################################
-# $Id: ogr2vrt.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: ogr2vrt.py 29016 2015-04-25 19:04:46Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Create OGR VRT from source datasource
@@ -31,38 +31,35 @@
 ###############################################################################
 
 try:
-    from osgeo import osr, ogr, gdal
+    from osgeo import ogr, gdal
 except ImportError:
-    import osr, ogr, gdal
+    import  ogr, gdal
 
-import string
 import sys
 
 #############################################################################
 
 def GeomType2Name( type ):
-    if type == ogr.wkbUnknown:
-        return 'wkbUnknown'
-    elif type == ogr.wkbPoint:
-        return 'wkbPoint'
-    elif type == ogr.wkbLineString:
-        return 'wkbLineString'
-    elif type == ogr.wkbPolygon:
-        return 'wkbPolygon'
-    elif type == ogr.wkbMultiPoint:
-        return 'wkbMultiPoint'
-    elif type == ogr.wkbMultiLineString:
-        return 'wkbMultiLineString'
-    elif type == ogr.wkbMultiPolygon:
-        return 'wkbMultiPolygon'
-    elif type == ogr.wkbGeometryCollection:
-        return 'wkbGeometryCollection'
-    elif type == ogr.wkbNone:
-        return 'wkbNone'
-    elif type == ogr.wkbLinearRing:
-        return 'wkbLinearRing'
-    else:
-        return 'wkbUnknown'
+    flat_type = ogr.GT_Flatten(type)
+    dic = { ogr.wkbUnknown : ('wkbUnknown', '25D'),
+            ogr.wkbPoint : ('wkbPoint', '25D'),
+            ogr.wkbLineString : ('wkbLineString', '25D'),
+            ogr.wkbPolygon : ('wkbPolygon', '25D'),
+            ogr.wkbMultiPoint : ('wkbMultiPoint', '25D'),
+            ogr.wkbMultiLineString : ('wkbMultiLineString', '25D'),
+            ogr.wkbMultiPolygon : ('wkbMultiPolygon', '25D'),
+            ogr.wkbGeometryCollection : ('wkbGeometryCollection', '25D'),
+            ogr.wkbNone : ('wkbNone', ''),
+            ogr.wkbLinearRing : ('wkbLinearRing', ''),
+            ogr.wkbCircularString : ('wkbCircularString', 'Z'),
+            ogr.wkbCompoundCurve : ('wkbCompoundCurve', 'Z'),
+            ogr.wkbCurvePolygon : ('wkbCurvePolygon', 'Z'),
+            ogr.wkbMultiCurve : ('wkbMultiCurve', 'Z'),
+            ogr.wkbMultiSurface : ('wkbMultiSurface', 'Z') }
+    ret = dic[flat_type][0]
+    if flat_type != type:
+        ret += dic[flat_type][1]
+    return ret
 
 #############################################################################
 def Esc(x):
@@ -85,6 +82,7 @@ relative = "0"
 schema=0
 feature_count=0
 extent=0
+openoptions = []
 
 argv = gdal.GeneralCmdLineProcessor( sys.argv )
 if argv is None:
@@ -106,6 +104,10 @@ while i < len(argv):
     elif arg == '-extent':
         extent = 1
 
+    elif arg == '-oo':
+        i += 1
+        openoptions.append(argv[i])
+
     elif arg[0] == '-':
         Usage()
 
@@ -134,20 +136,42 @@ if schema and extent:
 #############################################################################
 # Open the datasource to read.
 
-src_ds = ogr.Open( infile, update = 0 )
+src_ds = gdal.OpenEx( infile, gdal.OF_VECTOR, open_options = openoptions )
 
 if schema:
     infile = '@dummy@'
 
 if len(layer_list) == 0:
-    for layer in src_ds:
-        layer_list.append( layer.GetLayerDefn().GetName() )
+    for lyr_idx in range(src_ds.GetLayerCount()):
+        layer_list.append( src_ds.GetLayer(lyr_idx).GetLayerDefn().GetName() )
 
 #############################################################################
 # Start the VRT file.
 
 vrt = '<OGRVRTDataSource>\n'
 
+
+#############################################################################
+# Metadata
+
+mdd_list = src_ds.GetMetadataDomainList()
+if mdd_list is not None:
+    for domain in mdd_list:
+        if domain == '':
+            vrt += '  <Metadata>\n'
+        elif len(domain) > 4 and domain[0:4] == 'xml:':
+            vrt += '  <Metadata domain="%s" format="xml">\n' % Esc(domain)
+        else:
+            vrt += '  <Metadata domain="%s">\n' % Esc(domain)
+        if len(domain) > 4 and domain[0:4] == 'xml:':
+            vrt += src_ds.GetMetadata_List(domain)[0]
+        else:
+            md = src_ds.GetMetadata(domain)
+            for key in md:
+                vrt += '    <MDI key="%s">%s</MDI>\n' % (Esc(key), Esc(md[key]))
+        vrt += '  </Metadata>\n'
+
+
 #############################################################################
 #	Process each source layer.
 
@@ -156,8 +180,35 @@ for name in layer_list:
     layerdef = layer.GetLayerDefn()
 
     vrt += '  <OGRVRTLayer name="%s">\n' % Esc(name)
+
+    mdd_list = layer.GetMetadataDomainList()
+    if mdd_list is not None:
+        for domain in mdd_list:
+            if domain == '':
+                vrt += '    <Metadata>\n'
+            elif len(domain) > 4 and domain[0:4] == 'xml:':
+                vrt += '    <Metadata domain="%s" format="xml">\n' % Esc(domain)
+            else:
+                vrt += '    <Metadata domain="%s">\n' % Esc(domain)
+            if len(domain) > 4 and domain[0:4] == 'xml:':
+                vrt += layer.GetMetadata_List(domain)[0]
+            else:
+                md = layer.GetMetadata(domain)
+                for key in md:
+                    vrt += '      <MDI key="%s">%s</MDI>\n' % (Esc(key), Esc(md[key]))
+            vrt += '    </Metadata>\n'
+
+
     vrt += '    <SrcDataSource relativeToVRT="%s" shared="%d">%s</SrcDataSource>\n' \
            % (relative,not schema,Esc(infile))
+
+    if len(openoptions) > 0:
+        vrt += '    <OpenOptions>\n' 
+        for option in openoptions:
+            (key, value) = option.split('=')
+            vrt += '        <OOI key="%s">%s</OOI>\n'  % (Esc(key), Esc(value))
+        vrt += '    </OpenOptions>\n' 
+
     if schema:
         vrt += '    <SrcLayer>@dummy@</SrcLayer>\n' 
     else:
@@ -166,7 +217,8 @@ for name in layer_list:
     # Historic format for mono-geometry layers
     if layerdef.GetGeomFieldCount() == 0:
         vrt += '    <GeometryType>wkbNone</GeometryType>\n'
-    elif layerdef.GetGeomFieldCount() == 1:
+    elif layerdef.GetGeomFieldCount() == 1 and \
+         layerdef.GetGeomFieldDefn(0).IsNullable():
         vrt += '    <GeometryType>%s</GeometryType>\n' \
             % GeomType2Name(layerdef.GetGeomType())
         srs = layer.GetSpatialRef()
@@ -184,7 +236,10 @@ for name in layer_list:
     else:
         for fld_index in range(layerdef.GetGeomFieldCount()):
             src_fd = layerdef.GetGeomFieldDefn( fld_index )
-            vrt += '    <GeometryField name="%s">\n' % src_fd.GetName()
+            vrt += '    <GeometryField name="%s"' % src_fd.GetName()
+            if src_fd.IsNullable() == 0:
+                vrt += ' nullable="false"'
+            vrt += '>\n'
             vrt += '      <GeometryType>%s</GeometryType>\n' \
                     % GeomType2Name(src_fd.GetType())
             srs = src_fd.GetSpatialRef()
@@ -204,6 +259,8 @@ for name in layer_list:
         src_fd = layerdef.GetFieldDefn( fld_index )
         if src_fd.GetType() == ogr.OFTInteger:
             type = 'Integer'
+        elif src_fd.GetType() == ogr.OFTInteger64:
+            type = 'Integer64'
         elif src_fd.GetType() == ogr.OFTString:
             type = 'String'
         elif src_fd.GetType() == ogr.OFTReal:
@@ -212,6 +269,8 @@ for name in layer_list:
             type = 'StringList'
         elif src_fd.GetType() == ogr.OFTIntegerList:
             type = 'IntegerList'
+        elif src_fd.GetType() == ogr.OFTInteger64List:
+            type = 'Integer64List'
         elif src_fd.GetType() == ogr.OFTRealList:
             type = 'RealList'
         elif src_fd.GetType() == ogr.OFTBinary:
@@ -227,12 +286,16 @@ for name in layer_list:
 
         vrt += '    <Field name="%s" type="%s"' \
                % (Esc(src_fd.GetName()), type)
+        if src_fd.GetSubType() != ogr.OFSTNone:
+            vrt += ' subtype="%s"' % ogr.GetFieldSubTypeName(src_fd.GetSubType())
         if not schema:
             vrt += ' src="%s"' % Esc(src_fd.GetName())
         if src_fd.GetWidth() > 0:
             vrt += ' width="%d"' % src_fd.GetWidth()
         if src_fd.GetPrecision() > 0:
             vrt += ' precision="%d"' % src_fd.GetPrecision()
+        if src_fd.IsNullable() == 0:
+            vrt += ' nullable="false"'
         vrt += '/>\n'
 
     if feature_count:
diff --git a/swig/python/samples/ogr_build_junction_table.py b/swig/python/samples/ogr_build_junction_table.py
index d9463a2..25f3963 100644
--- a/swig/python/samples/ogr_build_junction_table.py
+++ b/swig/python/samples/ogr_build_junction_table.py
@@ -33,7 +33,6 @@
 
 from osgeo import gdal
 from osgeo import ogr
-import os
 import sys
 
 
diff --git a/swig/python/samples/ogr_dispatch.py b/swig/python/samples/ogr_dispatch.py
index 83546c2..9b09576 100644
--- a/swig/python/samples/ogr_dispatch.py
+++ b/swig/python/samples/ogr_dispatch.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 ###############################################################################
-# $Id: ogr_dispatch.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: ogr_dispatch.py 28392 2015-01-30 21:01:09Z rouault $
 #
 # Project:  GDAL/OGR samples
 # Purpose:  Dispatch features into layers according to the value of some fields
@@ -288,6 +288,7 @@ def ogr_dispatch(argv, progress = None, progress_arg = None):
     dst_filename = None
     format = "ESRI Shapefile"
     options = Options()
+    lco = []
     dsco = []
     pszWHERE = None
 
@@ -370,7 +371,7 @@ def ogr_dispatch(argv, progress = None, progress_arg = None):
 
     dst_ds = ogr.Open(dst_filename, update = 1)
     if dst_ds is not None:
-        if len(options.dsco) != 0:
+        if len(dsco) != 0:
             print('-dsco should not be specified for an existing datasource')
             return 1
     else:
diff --git a/swig/python/samples/ogr_layer_algebra.py b/swig/python/samples/ogr_layer_algebra.py
index 59d6f1f..c357bd6 100644
--- a/swig/python/samples/ogr_layer_algebra.py
+++ b/swig/python/samples/ogr_layer_algebra.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #******************************************************************************
-#  $Id: ogr_layer_algebra.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: ogr_layer_algebra.py 28391 2015-01-30 19:57:31Z rouault $
 # 
 #  Project:  GDAL Python Interface
 #  Purpose:  Application for executing OGR layer algebra operations
@@ -29,7 +29,7 @@
 #  DEALINGS IN THE SOFTWARE.
 #******************************************************************************
 
-from osgeo import gdal, ogr
+from osgeo import gdal, ogr, osr
 import os
 import sys
 
diff --git a/swig/python/samples/ogrinfo.py b/swig/python/samples/ogrinfo.py
index 274ccb0..5f2bc2d 100755
--- a/swig/python/samples/ogrinfo.py
+++ b/swig/python/samples/ogrinfo.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #/******************************************************************************
-# * $Id: ogrinfo.py 27044 2014-03-16 23:41:27Z rouault $
+# * $Id: ogrinfo.py 28395 2015-01-31 10:21:04Z rouault $
 # *
 # * Project:  OpenGIS Simple Features Reference Implementation
 # * Purpose:  Python port of a simple client for viewing OGR driver data.
@@ -200,7 +200,7 @@ def main(argv = None):
 
     poDS_Name = poDS.GetName()
     if str(type(pszDataSource)) == "<type 'unicode'>" and str(type(poDS_Name)) == "<type 'str'>":
-        poDS_Name = unicode(poDS_Name, "utf8")
+        poDS_Name = poDS_Name.decode("utf8")
     if bVerbose and pszDataSource != poDS_Name:
         print( "INFO: Internal data source name `%s'\n"
                 "      different from user name `%s'." % (poDS_Name, pszDataSource ))
@@ -436,7 +436,11 @@ def DumpReadableFeature( poFeature, options = None ):
                     ogr.GetFieldTypeName(poFDefn.GetType()) )
 
             if poFeature.IsFieldSet( iField ):
-                line = line + "%s" % (poFeature.GetFieldAsString( iField ) )
+                try:
+                    line = line + "%s" % (poFeature.GetFieldAsString( iField ) )
+                except:
+                    # For Python3 on non-UTF8 strings
+                    line = line + "%s" % (poFeature.GetFieldAsBinary( iField ) )
             else:
                 line = line + "(null)"
 
@@ -446,7 +450,7 @@ def DumpReadableFeature( poFeature, options = None ):
     if poFeature.GetStyleString() is not None:
 
         if 'DISPLAY_STYLE' not in options or EQUAL(options['DISPLAY_STYLE'], 'yes'):
-            print("  Style = %s" % GetStyleString() )
+            print("  Style = %s" % poFeature.GetStyleString() )
 
     nGeomFieldCount = poFeature.GetGeomFieldCount()
     if nGeomFieldCount > 0:
diff --git a/swig/python/samples/ogrupdate.py b/swig/python/samples/ogrupdate.py
index 8ac696c..010500e 100644
--- a/swig/python/samples/ogrupdate.py
+++ b/swig/python/samples/ogrupdate.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 ###############################################################################
-# $Id: ogrupdate.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: ogrupdate.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  GDAL/OGR samples
 # Purpose:  Update an existing datasource with features from another one
@@ -79,10 +79,6 @@ def ogrupdate_analyse_args(argv, progress = None, progress_arg = None):
     matchfieldname = None
 
     # in case there's no existing matching feature in the target datasource
-    # should we try to create a new feature ? 
-    update_only = False
-
-    # in case there's no existing matching feature in the target datasource
     # should we preserve the FID of the source feature that will be inserted ?
     preserve_fid = False
     
@@ -343,7 +339,7 @@ def ogrupdate_process(src_layer, dst_layer, matchfieldname = None, update_mode =
                 if ret == 0:
                     inserted_count = inserted_count + 1
                 else:
-                    insert_failed = insert_failed + 1
+                    inserted_failed = inserted_failed + 1
 
             elif update_mode == APPEND_ONLY:
                 continue
@@ -403,7 +399,7 @@ def ogrupdate_process(src_layer, dst_layer, matchfieldname = None, update_mode =
                 if ret == 0:
                     inserted_count = inserted_count + 1
                 else:
-                    insert_failed = insert_failed + 1
+                    inserted_failed = inserted_failed + 1
 
             elif update_mode == APPEND_ONLY:
                 continue
diff --git a/swig/python/samples/rel.py b/swig/python/samples/rel.py
index f634cc9..f737e24 100755
--- a/swig/python/samples/rel.py
+++ b/swig/python/samples/rel.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: rel.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: rel.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  GDAL Python samples
 # Purpose:  Script to produce a shaded relief image from elevation data
@@ -31,11 +31,9 @@
 
 try:
     from osgeo import gdal
-    from osgeo.gdalconst import *
     gdal.TermProgress = gdal.TermProgress_nocb
 except ImportError:
     import gdal
-    from gdalconst import *
 
 try:
     import numpy as Numeric
@@ -49,7 +47,7 @@ except ImportError:
     import gdalnumeric
 
 import sys
-from math import *
+import math
 
 # =============================================================================
 def Usage():
@@ -78,36 +76,36 @@ def Usage():
 # =============================================================================
 def ParseType(type):
     if type == 'Byte':
-        return GDT_Byte
+        return gdal.GDT_Byte
     elif type == 'Int16':
-        return GDT_Int16
+        return gdal.GDT_Int16
     elif type == 'UInt16':
-        return GDT_UInt16
+        return gdal.GDT_UInt16
     elif type == 'Int32':
-        return GDT_Int32
+        return gdal.GDT_Int32
     elif type == 'UInt32':
-        return GDT_UInt32
+        return gdal.GDT_UInt32
     elif type == 'Float32':
-        return GDT_Float32
+        return gdal.GDT_Float32
     elif type == 'Float64':
-        return GDT_Float64
+        return gdal.GDT_Float64
     elif type == 'CInt16':
-        return GDT_CInt16
+        return gdal.GDT_CInt16
     elif type == 'CInt32':
-        return GDT_CInt32
+        return gdal.GDT_CInt32
     elif type == 'CFloat32':
-        return GDT_CFloat32
+        return gdal.GDT_CFloat32
     elif type == 'CFloat64':
-        return GDT_CFloat64
+        return gdal.GDT_CFloat64
     else:
-        return GDT_Byte
+        return gdal.GDT_Byte
 # =============================================================================
 
 infile = None
 outfile = None
 iBand = 1	    # The first band will be converted by default
 format = 'GTiff'
-type = GDT_Byte
+type = gdal.GDT_Byte
 
 lsrcaz = None
 lsrcel = None
@@ -174,15 +172,15 @@ if lsrcel is None:
     Usage()
 
 # translate angles from degrees to radians
-lsrcaz = lsrcaz / 180.0 * pi
-lsrcel = lsrcel / 180.0 * pi
+lsrcaz = lsrcaz / 180.0 * math.pi
+lsrcel = lsrcel / 180.0 * math.pi
 
-lx = -sin(lsrcaz) * cos(lsrcel)
-ly =  cos(lsrcaz) * cos(lsrcel)
-lz =  sin(lsrcel)
-lxyz = sqrt(lx**2 + ly**2 + lz**2)
+lx = -math.sin(lsrcaz) * math.cos(lsrcel)
+ly =  math.cos(lsrcaz) * math.cos(lsrcel)
+lz =  math.sin(lsrcel)
+lxyz = math.sqrt(lx**2 + ly**2 + lz**2)
 
-indataset = gdal.Open(infile, GA_ReadOnly)
+indataset = gdal.Open(infile, gdal.GA_ReadOnly)
 if indataset == None:
     print('Cannot open', infile)
     sys.exit(2)
diff --git a/swig/python/samples/tigerpoly.py b/swig/python/samples/tigerpoly.py
index 2db8817..66d6e51 100755
--- a/swig/python/samples/tigerpoly.py
+++ b/swig/python/samples/tigerpoly.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: tigerpoly.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: tigerpoly.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Assemble TIGER Polygons.
@@ -36,7 +36,6 @@ except ImportError:
     import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/samples/tolatlong.py b/swig/python/samples/tolatlong.py
index 7f01d4b..e7d1c80 100755
--- a/swig/python/samples/tolatlong.py
+++ b/swig/python/samples/tolatlong.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: tolatlong.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: tolatlong.py 28450 2015-02-11 13:09:05Z rouault $
 #
 # Project:  GDAL Python samples
 # Purpose:  Script to read coordinate system and geotransformation matrix
@@ -32,12 +32,10 @@
 ###############################################################################
 
 try:
-    from osgeo import gdal
-    from osgeo import osr
-    from osgeo.gdalconst import *
+    from osgeo import gdal, osr
 except ImportError:
     import gdal
-    from gdalconst import *
+    import osr
 
 import sys
 
@@ -87,7 +85,7 @@ if line is None:
     Usage()
 
 # Open input dataset
-indataset = gdal.Open( infile, GA_ReadOnly )
+indataset = gdal.Open( infile, gdal.GA_ReadOnly )
 
 # Read geotransform matrix and calculate ground coordinates
 geomatrix = indataset.GetGeoTransform()
@@ -101,7 +99,9 @@ Y += geomatrix[5] / 2.0
 # Build Spatial Reference object based on coordinate system, fetched from the
 # opened dataset
 srs = osr.SpatialReference()
-srs.ImportFromWkt(indataset.GetProjection())
+if srs.ImportFromWkt(indataset.GetProjection()) != 0:
+    print("ERROR: Cannot import projection '%s'" % indataset.GetProjection())
+    sys.exit(1)
 
 srsLatLong = srs.CloneGeogCS()
 ct = osr.CoordinateTransformation(srs, srsLatLong)
diff --git a/swig/python/samples/val_at_coord.py b/swig/python/samples/val_at_coord.py
index 87c4cef..a0a3bb3 100755
--- a/swig/python/samples/val_at_coord.py
+++ b/swig/python/samples/val_at_coord.py
@@ -1,130 +1,130 @@
-#!/usr/bin/env python
-###############################################################################
-# $Id: val_at_coord.py 27044 2014-03-16 23:41:27Z rouault $
-#
-# Project:  GDAL Python samples
-# Purpose:  Outputs the value of the raster bands at a given
-#           (longitude, latitude) or (X, Y) location.
-# Author:   Even Rouault
-#
-###############################################################################
+#!/usr/bin/env python
+###############################################################################
+# $Id: val_at_coord.py 28391 2015-01-30 19:57:31Z rouault $
+#
+# Project:  GDAL Python samples
+# Purpose:  Outputs the value of the raster bands at a given
+#           (longitude, latitude) or (X, Y) location.
+# Author:   Even Rouault
+#
+###############################################################################
 # Copyright (c) 2010, Even Rouault <even dot rouault at mines-paris dot org>
-# 
-# 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.
-###############################################################################
-
-try:
-    from osgeo import gdal
-    from osgeo import osr
-except ImportError:
-    import gdal
-
-import sys
-
-# =============================================================================
-def Usage():
-    print('Usage: val_at_coord.py [-display_xy] [longitude latitude | -coordtype=georef X Y] filename')
-    print('')
-    print('By default, the 2 first arguments are supposed to be the location')
-    print('in longitude, latitude order. If -coordtype=georef is specified before')
-    print('the next 2 values will be interpretated as the X and Y coordinates')
-    print('in the dataset spatial reference system.')
-    sys.exit( 1 )
-
-# =============================================================================
-
-display_xy = False
-coordtype_georef = False
-longitude = None
-latitude = None
-filename = None
-
-# =============================================================================
-# Parse command line arguments.
-# =============================================================================
-i = 1
-while i < len(sys.argv):
-    arg = sys.argv[i]
-
-    if arg == '-coordtype=georef':
-        coordtype_georef = True
-
-    elif arg == '-display_xy':
-        display_xy = True
-
-    elif longitude is None:
-        longitude = float(arg)
-
-    elif latitude is None:
-        latitude = float(arg)
-
-    elif filename is None:
-        filename = arg
-
-    else:
-        Usage()
-
-    i = i + 1
-
-if longitude is None:
-    Usage()
-if latitude is None:
-    Usage()
-if filename is None:
-    filename()
-
-# Open input dataset
-ds = gdal.Open( filename, gdal.GA_ReadOnly )
-if ds is None:
-    print('Cannot open %s' % filename)
-    sys.exit(1)
-
-# Build Spatial Reference object based on coordinate system, fetched from the
-# opened dataset
-if coordtype_georef:
-    X = longitude
-    Y = latitude
-else:
-    srs = osr.SpatialReference()
-    srs.ImportFromWkt(ds.GetProjection())
-
-    srsLatLong = srs.CloneGeogCS()
-    # Convert from (longitude,latitude) to projected coordinates
-    ct = osr.CoordinateTransformation(srsLatLong, srs)
-    (X, Y, height) = ct.TransformPoint(longitude, latitude)
-
-# Read geotransform matrix and calculate corresponding pixel coordinates
-geomatrix = ds.GetGeoTransform()
-(success, inv_geometrix) = gdal.InvGeoTransform(geomatrix)
-x = int(inv_geometrix[0] + inv_geometrix[1] * X + inv_geometrix[2] * Y)
-y = int(inv_geometrix[3] + inv_geometrix[4] * X + inv_geometrix[5] * Y)
-
-if display_xy:
-    print('x=%d, y=%d' % (x, y))
-
-if x < 0 or x >= ds.RasterXSize or y < 0 or y >= ds.RasterYSize:
-    print('Passed coordinates are not in dataset extent')
-    sys.exit(1)
-
-res = ds.ReadAsArray(x,y,1,1)
-if len(res.shape) == 2:
-    print(res[0][0])
-else:
-    for val in res:
-        print(val[0][0])
+# 
+# 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.
+###############################################################################
+
+try:
+    from osgeo import gdal
+    from osgeo import osr
+except ImportError:
+    import gdal
+
+import sys
+
+# =============================================================================
+def Usage():
+    print('Usage: val_at_coord.py [-display_xy] [longitude latitude | -coordtype=georef X Y] filename')
+    print('')
+    print('By default, the 2 first arguments are supposed to be the location')
+    print('in longitude, latitude order. If -coordtype=georef is specified before')
+    print('the next 2 values will be interpretated as the X and Y coordinates')
+    print('in the dataset spatial reference system.')
+    sys.exit( 1 )
+
+# =============================================================================
+
+display_xy = False
+coordtype_georef = False
+longitude = None
+latitude = None
+filename = None
+
+# =============================================================================
+# Parse command line arguments.
+# =============================================================================
+i = 1
+while i < len(sys.argv):
+    arg = sys.argv[i]
+
+    if arg == '-coordtype=georef':
+        coordtype_georef = True
+
+    elif arg == '-display_xy':
+        display_xy = True
+
+    elif longitude is None:
+        longitude = float(arg)
+
+    elif latitude is None:
+        latitude = float(arg)
+
+    elif filename is None:
+        filename = arg
+
+    else:
+        Usage()
+
+    i = i + 1
+
+if longitude is None:
+    Usage()
+if latitude is None:
+    Usage()
+if filename is None:
+    filename()
+
+# Open input dataset
+ds = gdal.Open( filename, gdal.GA_ReadOnly )
+if ds is None:
+    print('Cannot open %s' % filename)
+    sys.exit(1)
+
+# Build Spatial Reference object based on coordinate system, fetched from the
+# opened dataset
+if coordtype_georef:
+    X = longitude
+    Y = latitude
+else:
+    srs = osr.SpatialReference()
+    srs.ImportFromWkt(ds.GetProjection())
+
+    srsLatLong = srs.CloneGeogCS()
+    # Convert from (longitude,latitude) to projected coordinates
+    ct = osr.CoordinateTransformation(srsLatLong, srs)
+    (X, Y, height) = ct.TransformPoint(longitude, latitude)
+
+# Read geotransform matrix and calculate corresponding pixel coordinates
+geomatrix = ds.GetGeoTransform()
+(success, inv_geometrix) = gdal.InvGeoTransform(geomatrix)
+x = int(inv_geometrix[0] + inv_geometrix[1] * X + inv_geometrix[2] * Y)
+y = int(inv_geometrix[3] + inv_geometrix[4] * X + inv_geometrix[5] * Y)
+
+if display_xy:
+    print('x=%d, y=%d' % (x, y))
+
+if x < 0 or x >= ds.RasterXSize or y < 0 or y >= ds.RasterYSize:
+    print('Passed coordinates are not in dataset extent')
+    sys.exit(1)
+
+res = ds.ReadAsArray(x,y,1,1)
+if len(res.shape) == 2:
+    print(res[0][0])
+else:
+    for val in res:
+        print(val[0][0])
diff --git a/swig/python/samples/val_repl.py b/swig/python/samples/val_repl.py
index 4e73472..b5c0702 100755
--- a/swig/python/samples/val_repl.py
+++ b/swig/python/samples/val_repl.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: val_repl.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: val_repl.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  GDAL Python samples
 # Purpose:  Script to replace specified values from the input raster file
@@ -35,11 +35,9 @@
 
 try:
     from osgeo import gdal
-    from osgeo.gdalconst import *
     gdal.TermProgress = gdal.TermProgress_nocb
 except ImportError:
     import gdal
-    from gdalconst import *
 
 try:
     import numpy
@@ -61,8 +59,8 @@ def Usage():
 # =============================================================================
 def ParseType(type):
     gdal_dt = gdal.GetDataTypeByName(type)
-    if gdal_dt is GDT_Unknown:
-        gdal_dt = GDT_Byte
+    if gdal_dt is gdal.GDT_Unknown:
+        gdal_dt = gdal.GDT_Byte
     return gdal_dt
 
 # =============================================================================
@@ -72,7 +70,7 @@ outNoData = None
 infile = None
 outfile = None
 format = 'GTiff'
-type = GDT_Byte
+type = gdal.GDT_Byte
 
 # Parse command line arguments.
 i = 1
@@ -115,7 +113,7 @@ if inNoData is None:
 if outNoData is None:
     Usage()
 
-indataset = gdal.Open( infile, GA_ReadOnly )
+indataset = gdal.Open( infile, gdal.GA_ReadOnly )
 
 out_driver = gdal.GetDriverByName(format)
 outdataset = out_driver.Create(outfile, indataset.RasterXSize, indataset.RasterYSize, indataset.RasterCount, type)
diff --git a/swig/python/samples/validate_jp2.py b/swig/python/samples/validate_jp2.py
new file mode 100644
index 0000000..5f3ca4b
--- /dev/null
+++ b/swig/python/samples/validate_jp2.py
@@ -0,0 +1,1228 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#******************************************************************************
+#  $Id: validate_jp2.py 29042 2015-04-28 14:07:13Z rouault $
+# 
+#  Project:  GDAL
+#  Purpose:  Validate JPEG2000 file structure
+#  Author:   Even Rouault, <even dot rouault at spatialys dot com>
+# 
+#******************************************************************************
+#  Copyright (c) 2015, European Union (European Environment Agency)
+# 
+#  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.
+#******************************************************************************
+
+import os
+import sys
+from osgeo import gdal
+from osgeo import osr
+
+def Usage():
+    print('Usage: validate_jp2 [-expected_gmljp2] [-inspire_tg] [-datatype imagery|non_imagery]')
+    print('                    [-oidoc in.xml] [-ogc_schemas_location path|disabled] test.jp2')
+    print('')
+    print('Options:')
+    print('-expected_gmljp2: hint to indicate that a GMLJP2 box should be present.')
+    print('-inspire_tg: Validate using Inspire Orthoimagery technical guidelines.')
+    print('-datatype imagery|non_imagery: To specify the nature of the data. Defaults is imagery.')
+    print('                               Only used by -inspire_tg')
+    print('-oidoc: XML document conforming with Inspire Orthoimagery GML application schema.')
+    print('-ogc_schemas_location: Path to directory with OGC schemas. Needed for GMLJP2 validation.')
+    return 1
+
+XML_TYPE_IDX = 0
+XML_VALUE_IDX = 1
+XML_FIRST_CHILD_IDX = 2
+
+def find_xml_node(ar, element_name, only_attributes = False):
+    #type = ar[XML_TYPE_IDX]
+    value = ar[XML_VALUE_IDX]
+    if value == element_name:
+        return ar
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        if only_attributes and child[XML_TYPE_IDX] != gdal.CXT_Attribute:
+            continue
+        found = find_xml_node(child, element_name)
+        if found is not None:
+            return found
+    return None
+
+def get_attribute_val(ar, attr_name):
+    node = find_xml_node(ar, attr_name, True)
+    if node is None or node[XML_TYPE_IDX] != gdal.CXT_Attribute:
+        return None
+    if len(ar) > XML_FIRST_CHILD_IDX and \
+        node[XML_FIRST_CHILD_IDX][XML_TYPE_IDX] == gdal.CXT_Text:
+        return node[XML_FIRST_CHILD_IDX][XML_VALUE_IDX]
+    return None
+
+def find_message(ar):
+    msg = get_attribute_val(ar, "message")
+    if msg is None:
+        return 'unknown'
+    return msg
+
+def find_element_with_name(ar, element_name, name, attribute_name = 'name'):
+    type = ar[XML_TYPE_IDX]
+    value = ar[XML_VALUE_IDX]
+    if type == gdal.CXT_Element and value == element_name and get_attribute_val(ar, attribute_name) == name:
+        return ar
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        found = find_element_with_name(child, element_name, name, attribute_name)
+        if found:
+            return found
+    return None
+
+def find_jp2box(ar, jp2box_name):
+    return find_element_with_name(ar, 'JP2Box', jp2box_name)
+
+def find_marker(ar, marker_name):
+    return find_element_with_name(ar, 'Marker', marker_name)
+
+def get_count_and_indices_of_jp2boxes(ar):
+    the_dic = {}
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        if child[XML_TYPE_IDX] == gdal.CXT_Element and child[XML_VALUE_IDX] == 'JP2Box':
+            jp2box_name = get_attribute_val(child, 'name')
+            if jp2box_name in the_dic:
+                the_dic[jp2box_name] = (the_dic[jp2box_name][0]+1, the_dic[jp2box_name][1])
+            else:
+                the_dic[jp2box_name] = (1, child_idx)
+
+    return the_dic
+
+def get_count_of_uuidboxes(ar):
+    the_dic = {}
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        if child[XML_TYPE_IDX] == gdal.CXT_Element and child[XML_VALUE_IDX] == 'JP2Box':
+            jp2box_name = get_attribute_val(child, 'name')
+            if jp2box_name == 'uuid':
+                uuid = get_element_val(find_xml_node(child, 'UUID'))
+                if uuid in the_dic:
+                    the_dic[uuid] += 1
+                else:
+                    the_dic[uuid] = 1
+
+    return the_dic
+
+def find_field(ar, field_name):
+    return find_element_with_name(ar, 'Field', field_name)
+
+def get_element_val(node):
+    if node is None:
+        return None
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(node)):
+        child = node[child_idx]
+        if child[XML_TYPE_IDX] == gdal.CXT_Text:
+            return child[XML_VALUE_IDX]
+    return None
+
+def get_field_val(ar, field_name):
+    return get_element_val(find_field(ar, field_name))
+
+def gdalOpenWithOpenJPEGDriverPreferably(filename):
+    drivers = []
+    jp2openjpeg_drv = gdal.GetDriverByName('JP2OpenJPEG')
+    if jp2openjpeg_drv:
+        # Deregister all drivers except JP2OpenJPEG if it exists
+        for drvname in ['JP2KAK', 'JP2ECW', 'JP2OpenJPEG', 'JP2MrSID', 'JPEG2000']:
+            drv = gdal.GetDriverByName(drvname)
+            if drvname != 'JP2OpenJPEG' and drv is not None:
+                drv.Deregister()
+            drivers.append(drv)
+
+    ds = gdal.Open(filename)
+
+    # Re-register drivers
+    if jp2openjpeg_drv:
+        jp2openjpeg_drv.Deregister()
+        for i in range(len(drivers)):
+            drv = drivers[i]
+            if drv is not None:
+                drv.Register()
+
+    return ds
+
+def get_gmljp2(filename):
+    ds = gdalOpenWithOpenJPEGDriverPreferably(filename)
+    if ds is None:
+        return None
+    mdd = ds.GetMetadata('xml:gml.root-instance')
+    if mdd is None:
+        return None
+    return mdd[0]
+
+class ErrorReport:
+    def __init__(self, collect_internally = False):
+        self.error_count = 0
+        self.warning_count = 0
+        self.collect_internally = collect_internally
+        self.error_array = []
+        self.warning_array = []
+
+    def EmitError(self, category, msg, requirement = None, conformance_class = None):
+        self.error_count += 1
+
+        if category == 'PROFILE_1' and conformance_class is None:
+            conformance_class = 'A.8.14'
+
+        if requirement is not None and conformance_class is not None:
+            full_msg = 'ERROR[%s, Requirement %d, Conformance class %s]: %s' % (category, requirement, conformance_class, msg)
+        elif requirement is not None:
+            full_msg = 'ERROR[%s, Requirement %d]: %s' % (category, requirement, msg)
+        elif conformance_class is not None:
+            full_msg = 'ERROR[%s, Conformance class %s]: %s' % (category, conformance_class, msg)
+        else:
+            full_msg = 'ERROR[%s]: %s' % (category, msg)
+        if self.collect_internally:
+            self.error_array.append(full_msg)
+        else:
+            print(full_msg)
+
+    def EmitWarning(self, category, msg, recommendation = None):
+        self.warning_count += 1
+        if recommendation is not None:
+            full_msg = 'WARNING[%s, Recommendation %d]: %s' % (category, recommendation, msg)
+        else:
+            full_msg = 'WARNING[%s]: %s' % (category, msg)
+        if self.collect_internally:
+            self.warning_array.append(full_msg)
+        else:
+            print(full_msg)
+
+# Report JP2 boxes errors
+def find_remaining_bytes(error_report, ar, parent_node_name = None):
+    type = ar[XML_TYPE_IDX]
+    value = ar[XML_VALUE_IDX]
+    if type == gdal.CXT_Element and value == 'JP2Box':
+        parent_node_name = get_attribute_val(ar, 'name')
+    if type == gdal.CXT_Element and value == 'RemainingBytes':
+        error_report.EmitError('GENERAL', 'Remaining bytes in JP2 box %s: %s' % (parent_node_name, get_element_val(ar)))
+
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        find_remaining_bytes(error_report, child, parent_node_name)
+
+
+# Report codestream errors
+def find_errors(error_report, ar, parent_node = None):
+    type = ar[XML_TYPE_IDX]
+    value = ar[XML_VALUE_IDX]
+    if type == gdal.CXT_Element and value == 'Error':
+        parent_node_name = ''
+        if parent_node is not None:
+            parent_node_name = get_attribute_val(parent_node, 'name')
+            if parent_node_name is None:
+                parent_node_name = parent_node[XML_VALUE_IDX]
+        error_report.EmitError('GENERAL', 'Codestream error found on element %s: %s' % (parent_node_name, find_message(ar)))
+
+    for child_idx in range(XML_FIRST_CHILD_IDX, len(ar)):
+        child = ar[child_idx]
+        find_errors(error_report, child, ar)
+
+def validate_bitsize(error_report, inspire_tg, val_ori, field_name, datatype):
+    val = val_ori
+    signedness = "unsigned"
+    nbits = 0
+    if val is not None:
+        if val >= 128:
+            signedness = "signed"
+            val -= 128
+        val += 1
+        nbits = val
+    if inspire_tg and val != 1 and val != 8 and val != 16 and val != 32:
+        error_report.EmitError('INSPIRE_TG', '%s=%s (%s %d bits), which is not allowed' % (field_name, str(val_ori), signedness, nbits), requirement = 24, conformance_class = 'A.8.9')
+    elif inspire_tg and datatype == 'imagery' and ((val != 1 and val != 8 and val != 16) or val_ori >= 128):
+        error_report.EmitError('INSPIRE_TG', '%s=%s (%s %d bits), which is not allowed for Orthoimagery (but OK for other data)' % (field_name, str(val_ori), signedness, nbits), requirement = 27, conformance_class = 'A.8.9')
+    elif val is None or val > 37:
+        error_report.EmitError('GENERAL', '%s=%s (%s %d bits), which is not allowed' % (field_name, str(val_ori), signedness, nbits))
+
+def int_or_none(val):
+    if val is None:
+        return None
+    return int(val)
+
+def check_geojp2_gmljp2_consistency(filename, error_report):
+    gdal.SetConfigOption('GDAL_USE_GEOJP2', 'YES')
+    gdal.SetConfigOption('GDAL_USE_GMLJP2', 'NO')
+    ds = gdalOpenWithOpenJPEGDriverPreferably(filename)
+    if ds is None:
+        error_report.EmitError('GENERAL', 'Cannot open %s with a JPEG2000 compatible driver' % filename)
+        return
+    geojp2_gt = ds.GetGeoTransform()
+    geojp2_wkt = ds.GetProjectionRef()
+    geojp2_gcps = ds.GetGCPCount()
+    ds = None
+
+    gdal.SetConfigOption('GDAL_USE_GEOJP2', 'NO')
+    gdal.SetConfigOption('GDAL_USE_GMLJP2', 'YES')
+    ds = gdalOpenWithOpenJPEGDriverPreferably(filename)
+    gmljp2_gt = ds.GetGeoTransform()
+    gmljp2_wkt = ds.GetProjectionRef()
+    ds = None
+
+    gdal.SetConfigOption('GDAL_USE_GEOJP2', None)
+    gdal.SetConfigOption('GDAL_USE_GMLJP2', None)
+
+    if geojp2_gcps == 0:
+        diff = False
+        for i in range(6):
+            if abs(geojp2_gt[i] - gmljp2_gt[i] > 1e-8):
+                diff = True
+        if diff:
+            error_report.EmitError('GENERAL', 'Inconsistant geotransform between GeoJP2 (%s) and GMLJP2 (%s)' % (str(geojp2_gt), str(gmljp2_gt)))
+
+    geojp2_sr = osr.SpatialReference()
+    geojp2_sr.ImportFromWkt(geojp2_wkt)
+    geojp2_epsg_code = geojp2_sr.GetAuthorityCode(None)
+    gmljp2_sr = osr.SpatialReference()
+    gmljp2_sr.ImportFromWkt(gmljp2_wkt)
+    gmljp2_epsg_code = gmljp2_sr.GetAuthorityCode(None)
+    if geojp2_sr.IsSame(gmljp2_sr) == 0 and geojp2_epsg_code != gmljp2_epsg_code:
+        geojp2_proj4 = geojp2_sr.ExportToProj4()
+        gmljp2_proj4 = gmljp2_sr.ExportToProj4()
+        if geojp2_proj4 != gmljp2_proj4:
+            error_report.EmitError('GENERAL', 'Inconsistant SRS between GeoJP2 (wkt=%s, proj4=%s) and GMLJP2 (wkt=%s, proj4=%s)' % (geojp2_wkt, geojp2_proj4, gmljp2_wkt, gmljp2_proj4))
+
+
+# Check consistency of georeferencing of OrthoimageCoverage with the one embedded in the JPEG2000 file
+def check_oi_rg_consistency(filename, serialized_oi_rg, error_report):
+    if gdal.GetDriverByName('JP2OpenJPEG') is None:
+        return
+
+    ds = gdalOpenWithOpenJPEGDriverPreferably(filename)
+    if ds is None:
+        error_report.EmitError('GENERAL', 'Cannot open %s with a JPEG2000 compatible driver' % filename)
+        return 'fail'
+    gt = ds.GetGeoTransform()
+    wkt = ds.GetProjectionRef()
+    gcps = ds.GetGCPCount()
+    ds = None
+
+    gmljp2_from_oi = """<gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlJP2Profile/1.0.0/gmlJP2Profile.xsd">
+        <gml:boundedBy>
+        <gml:Null>withheld</gml:Null>
+        </gml:boundedBy>
+        <gml:featureMember>
+        <gml:FeatureCollection>
+            <gml:featureMember>
+            <gml:RectifiedGridCoverage dimension="2" gml:id="RGC0001">
+                <gml:rectifiedGridDomain>
+                    %s
+                </gml:rectifiedGridDomain>
+                <gml:rangeSet>
+                <gml:File>
+                    <gml:rangeParameters />
+                    <gml:fileName>gmljp2://codestream/0</gml:fileName>
+                    <gml:fileStructure>Record Interleaved</gml:fileStructure>
+                </gml:File>
+                </gml:rangeSet>
+            </gml:RectifiedGridCoverage>
+            </gml:featureMember>
+        </gml:FeatureCollection>
+        </gml:featureMember>
+    </gml:FeatureCollection>""" % serialized_oi_rg
+    gdal.SetConfigOption('GMLJP2OVERRIDE', '/vsimem/override.gml')
+    gdal.FileFromMemBuffer('/vsimem/override.gml', gmljp2_from_oi)
+    fake_in_ds = gdal.GetDriverByName('MEM').Create('', 10, 10, 1)
+    fake_in_ds.SetGeoTransform([0,60,0,0,0,-60])
+    gdal.GetDriverByName('JP2OpenJPEG').CreateCopy('/vsimem/temp.jp2', fake_in_ds, options = ['GeoJP2=NO'])
+    gdal.SetConfigOption('GMLJP2OVERRIDE', None)
+    gdal.Unlink('/vsimem/override.gml')
+
+    ds = gdalOpenWithOpenJPEGDriverPreferably('/vsimem/temp.jp2')
+    oi_gt = ds.GetGeoTransform()
+    oi_wkt = ds.GetProjectionRef()
+    ds = None
+    gdal.Unlink('/vsimem/temp.jp2')
+
+    if gcps == 0:
+        diff = False
+        for i in range(6):
+            if abs(oi_gt[i] - gt[i] > 1e-8):
+                diff = True
+        if diff:
+            error_report.EmitError('INSPIRE_TG', 'Inconsistant geotransform between OrthoImagery (%s) and GMLJP2/GeoJP2 (%s)' % (str(oi_gt), str(gt)), conformance_class = 'A.8.8')
+
+    sr = osr.SpatialReference()
+    sr.ImportFromWkt(wkt)
+    epsg_code = sr.GetAuthorityCode(None)
+    oi_sr = osr.SpatialReference()
+    oi_sr.ImportFromWkt(oi_wkt)
+    oi_epsg_code = oi_sr.GetAuthorityCode(None)
+    if sr.IsSame(oi_sr) == 0 and epsg_code != oi_epsg_code:
+        proj4 = sr.ExportToProj4()
+        oi_proj4 = oi_sr.ExportToProj4()
+        if proj4 != oi_proj4:
+            error_report.EmitError('INSPIRE_TG', 'Inconsistant SRS between OrthoImagery (wkt=%s, proj4=%s) and GMLJP2/GeoJP2 (wkt=%s, proj4=%s)' % (wkt, proj4, oi_wkt, oi_proj4), conformance_class = 'A.8.8')
+
+def validate(filename, oidoc, inspire_tg, expected_gmljp2, ogc_schemas_location, datatype = 'imagery', error_report = None):
+
+    if error_report is None:
+        error_report = ErrorReport()
+
+    ar = gdal.GetJPEG2000Structure(filename, ['ALL=YES'])
+    if ar is None:
+        error_report.error_count = 1
+        return error_report
+
+    find_remaining_bytes(error_report, ar)
+    find_errors(error_report, ar)
+
+    if inspire_tg and ar[XML_VALUE_IDX] != 'JP2File':
+        error_report.EmitError('INSPIRE_TG', 'The file contains only a JPEG2000 codestream, instead of being a JP2 file')
+        return error_report
+
+    ihdr = None
+    ihdr_nc = 0
+    pclr = None
+    bpc_vals = []
+
+    if ar[XML_VALUE_IDX] == 'JP2File':
+
+        # Check "jP " box
+        if not find_jp2box(ar, 'jP  '):
+            error_report.EmitError('GENERAL', '"jp  " box not found')
+
+        # Detect GMLJP2 and validate it if possible
+        gmljp2 = get_gmljp2(filename)
+        gmljp2_found = gmljp2 is not None
+        if expected_gmljp2 and not gmljp2_found:
+            error_report.EmitError('GMLJP2', 'No GMLJP2 box found whereas it was expected')
+        if gmljp2_found and inspire_tg and gmljp2.find('gmljp2:GMLJP2CoverageCollection') >= 0:
+            error_report.EmitError('INSPIRE_TG', 'GMLJP2 v2 box found, but Inspire TG require GMLJP2 v1', conformance_class = 'A.8.6')
+        if gmljp2_found and ogc_schemas_location != 'disabled':
+            if ogc_schemas_location is not None:
+                import os
+                sys.path.append(os.path.dirname(os.path.realpath(__file__))+'/../../../../autotest/pymod')
+                try:
+                    import xmlvalidate
+                    xml_validate_found = True
+                except:
+                    error_report.EmitWarning('GMLJP2', 'xmlvalidate not found or not runnable')
+                    xml_validate_found = False
+                if xml_validate_found:
+                    if not xmlvalidate.validate(gmljp2, ogc_schemas_location = ogc_schemas_location):
+                        error_report.EmitError('GMLJP2', 'Validation of GMLJP2 document failed', conformance_class = 'A.8.6')
+            else:
+                error_report.EmitWarning('GMLJP2', '-ogc_schemas_location not specified')
+
+        # Check that there's only one GeoTIFF box
+        count_uuidboxes = get_count_of_uuidboxes(ar)
+        if 'B14BF8BD083D4B43A5AE8CD7D5A6CE03' in count_uuidboxes:
+            count_geotiff_boxes = count_uuidboxes['B14BF8BD083D4B43A5AE8CD7D5A6CE03']
+            if count_geotiff_boxes > 1:
+                error_report.EmitError('GeoJP2', '%d GeoTIFF UUID box found' % count_geotiff_boxes)
+
+        # Check the content of a GeoTIFF UUID box
+        geotiff_found = find_element_with_name(ar, "UUID", "GeoTIFF", attribute_name = "description") is not None
+        decoded_geotiff = find_xml_node(ar, "DecodedGeoTIFF")
+        if geotiff_found:
+            if not decoded_geotiff:
+                error_report.EmitError('GeoJP2', 'GeoTIFF UUID box found, but content is not valid GeoTIFF')
+            else:
+                vrtdataset = find_xml_node(ar, "VRTDataset")
+                w = get_attribute_val(vrtdataset, "rasterXSize")
+                if w != '1':
+                    error_report.EmitError('GeoJP2', 'GeoTIFF should have width of 1 pixel, not %s' % str(w))
+                h = get_attribute_val(vrtdataset, "rasterXSize")
+                if h != '1':
+                    error_report.EmitError('GeoJP2', 'GeoTIFF should have height of 1 pixel, not %s' % str(h))
+
+        # Check that information of GeoJP2 and GMLJP2 are consistant
+        if geotiff_found and gmljp2_found:
+            check_geojp2_gmljp2_consistency(filename, error_report)
+
+        # Check "ftyp" box
+        ftyp = find_jp2box(ar, 'ftyp')
+        if ftyp:
+            JP2CLFound = False
+            JPXCLFound = False
+            if get_field_val(ftyp, 'BR') != 'jp2 ':
+                error_report.EmitError('GENERAL', 'ftyp.BR = "%s" instead of "jp2 "' % get_field_val(ftyp, 'BR'))
+
+            if get_field_val(ftyp, 'MinV') != '0':
+                error_report.EmitError('GENERAL', 'ftyp.MinV = "%s" instead of 0' % get_field_val(ftyp, 'MinV'))
+
+            for i in range(10):
+                val = get_field_val(ftyp, 'CL%d' % i)
+                if val is None:
+                    break
+                if val == 'jp2 ':
+                    JP2CLFound = True
+                if val == 'jpx ':
+                    JPXCLFound = True
+            if not JP2CLFound:
+                error_report.EmitError('GENERAL', '"jp2 " not found in compatibility list of ftyp')
+            if gmljp2_found and not JPXCLFound:
+                if inspire_tg:
+                    error_report.EmitError('INSPIRE_TG', '"jpx " not found in compatibility list of ftyp, but GMLJP2 box present')
+                else:
+                    error_report.EmitWarning('GENERAL', '"jpx " not found in compatibility list of ftyp, but GMLJP2 box present')
+        else:
+            error_report.EmitError('GENERAL', '"ftyp" box not found')
+
+        # Check "rreq" box
+        rreq = find_jp2box(ar, 'rreq')
+        if inspire_tg and gmljp2_found and not rreq:
+            error_report.EmitError('INSPIRE_TG', '"rreq" box not found, but GMLJP2 box present')
+        elif rreq:
+            NSF = get_field_val(rreq, 'NSF')
+            if NSF is None:
+                error_report.EmitError('GENERAL', 'rreq.NSF not found')
+                NSF = 0
+            NSF = int(NSF)
+            SF67Found = False
+            NSF_found = 0
+            for i in range(1000):
+                val = get_field_val(rreq, 'SF%d' % i)
+                if val is None:
+                    break
+                if val == '67':
+                    SF67Found = True
+                val = get_field_val(rreq, 'SM%d' % i)
+                if val is None:
+                    error_report.EmitError('GENERAL', 'rreq.SM[%d] not found' % i)
+                    break
+                NSF_found += 1
+            if NSF != NSF_found:
+                error_report.EmitError('GENERAL', 'rreq.NSF (=%d) != NSF_found (=%d)' % (NSF, NSF_found))
+            if gmljp2_found and not SF67Found:
+                if inspire_tg:
+                    error_report.EmitError('INSPIRE_TG', '"rreq" box does not advertize standard flag 67 whereas GMLJP2 box is present')
+                else:
+                    error_report.EmitWarning('GENERAL', '"rreq" box does not advertize standard flag 67 whereas GMLJP2 box is present')
+
+            NVF = get_field_val(rreq, 'NVF')
+            if NVF is None:
+                error_report.EmitError('GENERAL', 'rreq.NVF not found')
+                NVF = 0
+            NVF = int(NVF)
+            NVF_found = 0
+            for i in range(1000):
+                val = get_field_val(rreq, 'VF%d' % i)
+                if val is None:
+                    break
+                val = get_field_val(rreq, 'VM%d' % i)
+                if val is None:
+                    error_report.EmitError('GENERAL', 'rreq.VM[%d] not found' % i)
+                    break
+                NVF_found += 1
+            if NVF != NVF_found:
+                error_report.EmitError('GENERAL', 'rreq.NVF (=%d) != NVF_found (=%d)' % (NVF, NVF_found))
+
+        # Check "jp2h" box
+        jp2h = find_jp2box(ar, 'jp2h')
+        if not jp2h:
+            error_report.EmitError('GENERAL', '"jp2h" box not found')
+        else:
+            # Check "ihdr" subbox
+            ihdr = find_jp2box(jp2h, 'ihdr')
+            if not ihdr:
+                error_report.EmitError('GENERAL', '"ihdr" box not found')
+            else:
+                ihdr_height = int_or_none(get_field_val(ihdr, 'HEIGHT'))
+                if ihdr_height is None:
+                    error_report.EmitError('GENERAL', 'invalid value ihdr.HEIGHT = %s' % str(ihdr_height))
+                    ihdr_height = 0
+                elif inspire_tg and ihdr_height > 2**31:
+                    error_report.EmitError('INSPIRE_TG', 'ihdr.height = %d, whereas only 31 bits are allowed for Profile 1' % ihdr_height)
+
+                ihdr_width = int_or_none(get_field_val(ihdr, 'WIDTH'))
+                if ihdr_width is None:
+                    error_report.EmitError('GENERAL', 'invalid value ihdr.WIDTH = %s' % str(ihdr_width))
+                    ihdr_width = 0
+                elif inspire_tg and ihdr_width > 2**31:
+                    error_report.EmitError('INSPIRE_TG', 'ihdr.width = %d, whereas only 31 bits are allowed for Profile 1' % ihdr_width)
+
+                ihdr_nc = int_or_none(get_field_val(ihdr, 'NC'))
+                if ihdr_nc is None or ihdr_nc > 16384:
+                    error_report.EmitError('GENERAL', 'invalid value ihdr.NC = %s' % str(ihdr_nc))
+                    ihdr_nc = 0
+
+                ihdr_bpcc = int_or_none(get_field_val(ihdr, 'BPC'))
+                if ihdr_bpcc != 255:
+                    validate_bitsize(error_report, inspire_tg, ihdr_bpcc, 'ihdr.bpcc', datatype)
+
+                ihdr_c = int_or_none(get_field_val(ihdr, 'C'))
+                if ihdr_c != 7:
+                    error_report.EmitError('GENERAL', 'ihdr.C = %s instead of 7' % str(ihdr_c))
+
+                ihdr_unkc = int_or_none(get_field_val(ihdr, 'UnkC'))
+                if ihdr_unkc is None or ihdr_unkc > 1:
+                    error_report.EmitError('GENERAL', 'ihdr.UnkC = %s instead of 0 or 1' % str(ihdr_unkc))
+
+                ihdr_ipr = int_or_none(get_field_val(ihdr, 'IPR'))
+                if ihdr_ipr is None or ihdr_ipr > 1:
+                    error_report.EmitError('GENERAL', 'ihdr.IPR = %s instead of 0 or 1' % str(ihdr_ipr))
+
+            # Check optional "bpcc" subbox
+            bpcc = find_jp2box(jp2h, 'bpcc')
+            if ihdr and ihdr_bpcc == 255:
+                if not bpcc:
+                    error_report.EmitError('GENERAL', '"bpcc" box not found whereas ihdr.bpcc requires it')
+            elif ihdr and bpcc and ihdr_bpcc != 255:
+                error_report.EmitWarning('GENERAL', '"bpcc" box found whereas ihdr.bpcc does not require it')
+            if ihdr and bpcc:
+                for i in range(16384):
+                    val = get_field_val(bpcc, 'BPC%d' % i)
+                    if val is None:
+                        break
+                    val = int(val)
+                    bpc_vals.append(val)
+
+                    validate_bitsize(error_report, inspire_tg, val, 'bpcc.BPC[%d]' % i, datatype)
+
+                if len(bpc_vals) != ihdr_nc:
+                    error_report.EmitWarning('GENERAL', '"bpcc" box has %d elements whereas ihdr.nc = %d' % (len(bpc_vals), ihdr_nc))
+
+            if ihdr and not bpcc:
+                bpc_vals = [ ihdr_bpcc for i in range(ihdr_nc) ]
+
+            # Check "colr" subbox
+            colr = find_jp2box(jp2h, 'colr')
+            if not colr:
+                error_report.EmitError('GENERAL', '"colr" box not found')
+            else:
+                meth = int_or_none(get_field_val(colr, 'METH'))
+                if meth != 1 and meth != 2:
+                    error_report.EmitWarning('GENERAL', 'Unknown value %s for colr.METH' % str(meth))
+
+                prec = int_or_none(get_field_val(colr, 'PREC'))
+                if prec is None or (inspire_tg and prec != 0):
+                    error_report.EmitWarning('GENERAL', 'Unknown value %s for colr.PREC' % str(prec))
+
+                approx = int_or_none(get_field_val(colr, 'APPROX'))
+                if approx or (inspire_tg and approx != 0):
+                    error_report.EmitWarning('GENERAL', 'Unknown value %s for colr.APPROX' % str(approx))
+
+                if meth == 1:
+                    enum_cs = int_or_none(get_field_val(colr, 'EnumCS'))
+                    if enum_cs is None or (inspire_tg and enum_cs != 16 and enum_cs != 17 and enum_cs != 18):
+                        error_report.EmitWarning('GENERAL', 'Unknown value %s for colr.EnumCS' % str(enum_cs))
+                else:
+                    enum_cs = None
+
+            # Check optional "pclr" subbox
+            pclr = find_jp2box(jp2h, 'pclr')
+            if ihdr and pclr:
+                if inspire_tg and ihdr_nc != 1:
+                    error_report.EmitError('INSPIRE_TG', 'pclr box found but ihdr.nc = %d' % (ihdr_nc))
+                pclr_NE = int_or_none(get_field_val(pclr, 'NE'))
+                if pclr_NE is None:
+                    error_report.EmitWarning('GENERAL', 'Invalid value %s for pclr.NE' % str(pclr_NE))
+                    pclr_NE = 0
+
+                pclr_NPC = int_or_none(get_field_val(pclr, 'NPC'))
+                if pclr_NPC is None:
+                    error_report.EmitWarning('GENERAL', 'Invalid value %s for pclr.NPC' % str(pclr_NPC))
+                    pclr_NPC = 0
+                if inspire_tg and pclr_NPC != 3:
+                    error_report.EmitError('INSPIRE_TG', 'pclr.NPC(=%d) != 3 (for color table)' % (pclr_NPC), conformance_class = 'A.8.6')
+
+                if ihdr_bpcc == 7 and pclr_NE > 256:
+                    error_report.EmitError('GENERAL', '%d entries in pclr box, but 8 bit depth' % (pclr_NE))
+                for i in range(pclr_NPC):
+                    val = get_field_val(pclr, 'B%d' % i)
+                    if val is None:
+                        error_report.EmitError('GENERAL', 'pclr.B%d not found' % (i))
+                        break
+                    val = int(val)
+                    validate_bitsize(error_report, inspire_tg, val, 'pclr.B[%d]' % i, datatype)
+                if pclr_NE > 0 and pclr_NPC > 0:
+                    val = get_field_val(pclr, 'C_%d_%d' % (pclr_NE-1, pclr_NPC-1))
+                    if val is None:
+                        error_report.EmitError('GENERAL', 'pclr.C_%d_%d not found' % (pclr_NE-1, pclr_NPC-1))
+
+            # Check optional "cmap" subbox
+            cmap = find_jp2box(jp2h, 'cmap')
+            if cmap:
+                if pclr is None:
+                    error_report.EmitError('GENERAL', 'cmap box found but no pclr box')
+                else:
+                    cmap_count = 0
+                    PCOL_mapping = {}
+                    for i in range(16384):
+                        CMP = get_field_val(cmap, 'CMP%d' % i)
+                        if CMP is None:
+                            break
+                        CMP = int(CMP)
+                        if CMP >= ihdr_nc:
+                            error_report.EmitError('GENERAL', 'cmap.CMP[%d] = %d is invalid' % (i, CMP))
+
+                        MTYP = get_field_val(cmap, 'MTYP%d' % i)
+                        if MTYP is None:
+                            error_report.EmitError('GENERAL', 'cmap.MTYP[%d] missing' % i)
+                            break
+                        MTYP = int(MTYP)
+                        if inspire_tg and MTYP != 1:
+                            error_report.EmitError('INSPIRE_TG', 'cmap.MTYP[%d] = %d is invalid' % (i, MTYP))
+
+                        PCOL = get_field_val(cmap, 'PCOL%d' % i)
+                        if PCOL is None:
+                            error_report.EmitError('GENERAL', 'cmap.PCOL[%d] missing' % i)
+                            break
+                        PCOL = int(PCOL)
+                        if ihdr_nc == 1 and PCOL >= pclr_NPC:
+                            error_report.EmitError('GENERAL', 'cmap.PCOL[%d] = %d is invalid' % (i, PCOL))
+                        if MTYP == 1:
+                            if PCOL in PCOL_mapping:
+                                error_report.EmitError('GENERAL', 'cmap.PCOL[%d] = %d is invalid since already used' % (i, PCOL))
+                            PCOL_mapping[PCOL] = True
+
+                        cmap_count += 1
+
+                    if ihdr_nc == 1 and cmap_count != pclr_NPC:
+                        error_report.EmitError('GENERAL', 'cmap box contains %d channel definitions but pclr.NPC = %d' % (cmap_count, pclr_NPC))
+
+            else:
+                if pclr:
+                    error_report.EmitError('GENERAL', 'cmap box not found but pclr exists')
+
+            # Check optional "cdef" subbox
+            cdef = find_jp2box(jp2h, 'cdef')
+            transparent_index = -1
+            if cdef and pclr:
+                error_report.EmitWarning('GENERAL', 'cdef found and pclr also. Ignoring cdef as it is unusual')
+            elif ihdr and cdef:
+                cdef_N = int(get_field_val(cdef, 'N'))
+                if cdef_N != ihdr_nc:
+                    error_report.EmitError('GENERAL', 'cdef.N = %d whereas ihdr.nc = %d' % (cdef_N, ihdr_nc))
+                cdef_count = 0
+                cn_mapping = {}
+                typ_alpha_used = False
+                asoc_mapping = {}
+                asoc_whole_used  = False
+                for i in range(16384):
+                    cn = get_field_val(cdef, 'Cn%d' % i)
+                    if cn is None:
+                        break
+                    cn = int(cn)
+                    if cn < 0 or cn >= ihdr_nc:
+                        error_report.EmitError('GENERAL', 'cdef.cn[%d] = %d is invalid' % (i, cn))
+                    elif cn in cn_mapping:
+                        error_report.EmitError('GENERAL', 'cdef.cn[%d] = %d is invalid since already used' % (i, cn))
+                    cn_mapping[cn] = True
+
+                    typ = get_field_val(cdef, 'Typ%d' % i)
+                    if typ is None:
+                        error_report.EmitError('GENERAL', 'cdef.typ[%d] missing' % i)
+                        break
+                    typ = int(typ)
+                    if typ != 0 and typ != 1 and typ != 2 and typ != 65535:
+                        error_report.EmitError('GENERAL', 'cdef.typ[%d] = %d is invalid' % (i, typ))
+                    if typ == 1 or typ == 2:
+                        if inspire_tg and cn < len(bpc_vals) and bpc_vals[cn] != 0:
+                            error_report.EmitWarning('INSPIRE_TG', 'Bit depth of alpha channel should be 1 (BPCC 0), but its BPCC is %d' % bpc_vals[cn], recommendation = 38)
+                        if typ_alpha_used and inspire_tg:
+                            error_report.EmitError('GENERAL', 'cdef.typ[%d] = %d is invalid since another alpha channel has already been defined' % (i, typ))
+                        transparent_index = cn
+                        typ_alpha_used = True
+
+                    asoc = get_field_val(cdef, 'Asoc%d' % i)
+                    if asoc is None:
+                        error_report.EmitError('GENERAL', 'cdef.asoc[%d] missing' % i)
+                        break
+                    asoc = int(asoc)
+                    if inspire_tg and asoc == 0:
+                        if not(typ == 1 or typ == 2):
+                            error_report.EmitError('GENERAL', 'cdef.asoc[%d] = %d whereas cdef.typ[%d] = %d' % (i, asoc, i, typ))
+                        if asoc_whole_used:
+                            error_report.EmitError('GENERAL', 'cdef.asoc[%d] = %d is invalid since another band has already been associated to whole image' % (i, asoc))
+                        asoc_whole_used = True
+                    elif colr and asoc > 0 and asoc < 65535:
+                        if asoc > ihdr_nc:
+                            error_report.EmitError('GENERAL', 'cdef.asoc[%d] = %d is invalid' % (i, asoc))
+                        elif asoc in asoc_mapping:
+                            error_report.EmitError('GENERAL', 'cdef.asoc[%d] = %d is invalid since already used' % asoc)
+                        asoc_mapping[asoc] = True
+
+                    cdef_count += 1
+
+                if cdef_count != cdef_N:
+                    error_report.EmitError('GENERAL', 'cdef.N = %d whereas there are %d channel definitions' % (cdef_N, cdef_count))
+
+            # Check that all bands have the same bit-depth, except the alpha band than can (should) be 1-bit
+            if inspire_tg:
+                for i in range(len(bpc_vals)):
+                    if i == transparent_index:
+                        if bpc_vals[i] != bpc_vals[0] and bpc_vals[i] != 0:
+                            error_report.EmitError('INSPIRE_TG', 'Band %d has bpc=%d, which is different from first band whose value is %d' % (i, bpc_vals[i], bpc_vals[0]), requirement = 25)
+                    elif bpc_vals[i] != bpc_vals[0]:
+                        error_report.EmitError('INSPIRE_TG', 'Band %d has bpc=%d, which is different from first band whose value is %d' % (i, bpc_vals[i], bpc_vals[0]), requirement = 25)
+
+            # Check optional "res " subbox
+            res = find_jp2box(jp2h, 'res ')
+            if res:
+                count_boxes = get_count_and_indices_of_jp2boxes(res)
+                for key in count_boxes:
+                    (val, _) = count_boxes[key]
+                    if val > 1:
+                        error_report.EmitError('GENERAL', '"%s" box expected to be found zero or one time, but present %d times' % (key, val))
+                    if key not in ('resd', 'resc'):
+                        error_report.EmitWarning('GENERAL', '"%s" box not expected' % key)
+
+            # Check number of sub-boxes
+            count_boxes = get_count_and_indices_of_jp2boxes(jp2h)
+            for key in count_boxes:
+                (val, _) = count_boxes[key]
+                if val > 1:
+                    error_report.EmitError('GENERAL', '"%s" box expected to be found zero or one time, but present %d times' % (key, val))
+                if key not in ('ihdr', 'bpcc', 'colr', 'pclr', 'cmap', 'cdef', 'res '):
+                    error_report.EmitWarning('GENERAL', '"%s" box not expected' % key)
+
+            # Check order of boxes
+            last_idx = -1
+            for box_name in ['ihdr', 'bpcc', 'colr', 'pclr', 'cmap', 'cdef', 'res ']:
+                if box_name in count_boxes:
+                    (_, idx) = count_boxes[box_name]
+                    if idx < last_idx:
+                        error_report.EmitWarning('GENERAL', '"%s" box not at expected index' % box_name)
+                    last_idx = idx
+
+        # Check "jp2c" box
+        jp2c = find_jp2box(ar, 'jp2c')
+        if not jp2c:
+            error_report.EmitError('GENERAL', '"jp2c" box not found')
+
+        if ihdr and ihdr_ipr == 1 and not find_jp2box(ar, 'jp2i'):
+            error_report.EmitWarning('GENERAL', 'ihdr.ipr = 1 but no jp2i box found')
+        elif ihdr and ihdr_ipr == 0 and find_jp2box(ar, 'jp2i'):
+            error_report.EmitWarning('GENERAL', 'ihdr.ipr = 0 but jp2i box found')
+
+        # Check number of boxes
+        count_boxes = get_count_and_indices_of_jp2boxes(ar)
+        for key in count_boxes:
+            (val, _) = count_boxes[key]
+            if key in ( 'jP  ', 'ftyp', 'rreq', 'jp2h', 'jp2c' ):
+                if key == 'jp2c':
+                    if inspire_tg and val > 1:
+                        error_report.EmitError('INSPIRE_TG', '"%s" box expected to be found one time, but present %d times' % (key, val), requirement = 23, conformance_class = 'A.8.15')
+                elif val > 1:
+                    error_report.EmitError('GENERAL', '"%s" box expected to be found zero or one time, but present %d times' % (key, val))
+            elif key not in ('jp2i', 'asoc', 'xml ', 'uuid', 'uinf'):
+                error_report.EmitWarning('GENERAL', '"%s" box not expected' % key)
+
+        # Check order of boxes
+        last_idx = -1
+        for box_name in [ 'jP  ', 'ftyp', 'rreq', 'jp2h', 'jp2c', 'jp2i']:
+            if box_name in count_boxes:
+                (_, idx) = count_boxes[box_name]
+                if idx < last_idx:
+                    error_report.EmitWarning('GENERAL', '"%s" box not at expected index' % box_name)
+                last_idx = idx
+        if inspire_tg:
+            for box_name in ['asoc', 'xml ', 'uuid', 'uinf']:
+                if box_name in count_boxes:
+                    (_, idx) = count_boxes[box_name]
+                    if idx < last_idx:
+                        error_report.EmitWarning('INSPIRE_TG', '"%s" box not at expected index' % box_name)
+                    last_idx = idx
+
+    cs = find_xml_node(ar, 'JP2KCodeStream')
+    if cs is None:
+        return error_report
+
+    soc = find_marker(cs, 'SOC')
+    if not soc:
+        error_report.EmitError('GENERAL', 'No SOC marker found')
+
+    # Validate content of SIZ marker
+    siz = find_marker(cs, 'SIZ')
+    Csiz = 0
+    Xsiz = 0
+    Ysiz = 0
+    XOsiz = 0
+    YOsiz = 0
+    Rsiz = 0
+    tab_Ssiz = []
+    if not siz:
+        error_report.EmitError('GENERAL', 'No SIZ marker found')
+    else:
+        while True:
+            Csiz = get_field_val(siz, 'Csiz')
+            if Csiz is None:
+                error_report.EmitError('GENERAL', 'SIZ.Csiz not found')
+                break
+            Csiz = int(Csiz)
+
+            Rsiz = int(get_field_val(siz, 'Rsiz'))
+            if inspire_tg and Rsiz != 2:
+                error_report.EmitError('INSPIRE_TG', 'SIZ.Rsiz=%d found but 2 (Profile 1) expected' % Rsiz, requirement = 21)
+
+            Xsiz = int(get_field_val(siz, 'Xsiz'))
+            Ysiz = int(get_field_val(siz, 'Ysiz'))
+            XOsiz = int(get_field_val(siz, 'XOsiz'))
+            YOsiz = int(get_field_val(siz, 'YOsiz'))
+            XTsiz = int(get_field_val(siz, 'XTsiz'))
+            YTsiz = int(get_field_val(siz, 'YTsiz'))
+            XTOSiz = int(get_field_val(siz, 'XTOSiz'))
+            YTOSiz = int(get_field_val(siz, 'YTOSiz'))
+
+            if (inspire_tg or Rsiz == 2) and Xsiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'Xsiz = %d, whereas only 31 bits are allowed for Profile 1' % Xsiz)
+            if (inspire_tg or Rsiz == 2) and Ysiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'Ysiz = %d, whereas only 31 bits are allowed for Profile 1' % Ysiz)
+            if (inspire_tg or Rsiz == 2) and XOsiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'XOsiz = %d, whereas only 31 bits are allowed for Profile 1' % XOsiz)
+            if (inspire_tg or Rsiz == 2) and YOsiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'YOsiz = %d, whereas only 31 bits are allowed for Profile 1' % YOsiz)
+            if (inspire_tg or Rsiz == 2) and XTOSiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'XTOSiz = %d, whereas only 31 bits are allowed for Profile 1' % XTOSiz)
+            if (inspire_tg or Rsiz == 2) and YTOSiz >= 2**31:
+                error_report.EmitError('PROFILE_1', 'YTOSiz = %d, whereas only 31 bits are allowed for Profile 1' % YTOSiz)
+            if ihdr and ihdr_width != Xsiz - XOsiz:
+                error_report.EmitError('GENERAL', 'ihdr_width(=%d) != Xsiz (=%d)- XOsiz(=%d)' % (ihdr_width, Xsiz, XOsiz))
+            if ihdr and ihdr_height != Ysiz - YOsiz:
+                error_report.EmitError('GENERAL', 'ihdr_height(=%d) != Ysiz(=%d) - YOsiz(=%d)'% (ihdr_height, Ysiz, YOsiz))
+            if ihdr and ihdr_nc != Csiz:
+                error_report.EmitError('GENERAL', 'ihdr_nc(=%d) != Csiz (=%d)' % (ihdr_nc, Csiz))
+
+            min_XYRSiz = 255
+            for i in range(Csiz):
+                Ssiz = get_field_val(siz, 'Ssiz%d' % i)
+                if Ssiz is None:
+                    error_report.EmitError('GENERAL', 'SIZ.Ssiz[%d] not found' % i)
+                    break
+                Ssiz = int(Ssiz)
+                validate_bitsize(error_report, inspire_tg, Ssiz, 'SIZ.Ssiz[%d]' % i, datatype)
+                tab_Ssiz.append(Ssiz)
+
+                if bpc_vals and i < len(bpc_vals) and bpc_vals[i] != Ssiz:
+                    error_report.EmitError('GENERAL', 'SIZ.Ssiz[%d]=%s, whereas bpcc[%d]=%s' % (i, str(Ssiz), i, str(bpc_vals[i])))
+
+                XRsiz = get_field_val(siz, 'XRsiz%d' % i)
+                if XRsiz is None:
+                    error_report.EmitError('GENERAL', 'SIZ.XRsiz[%d] not found' % i)
+                    break
+                XRsiz = int(XRsiz)
+                if XRsiz == 0:
+                    error_report.EmitError('GENERAL', 'XRsiz[%d] = %d is invalid' % (i, XRsiz))
+                elif XRsiz < min_XYRSiz:
+                    min_XYRSiz = XRsiz
+
+                YRsiz = get_field_val(siz, 'YRsiz%d' % i)
+                if YRsiz is None:
+                    error_report.EmitError('GENERAL', 'SIZ.YRsiz[%d] not found' % i)
+                    break
+                YRsiz = int(YRsiz)
+                if YRsiz == 0:
+                    error_report.EmitError('GENERAL', 'YRsiz[%d] = %d is invalid' % (i, YRsiz))
+                elif YRsiz < min_XYRSiz:
+                    min_XYRSiz = YRsiz
+
+            tiled = not (XTsiz + XTOSiz >= Xsiz and YTsiz + YTOSiz >= Ysiz )
+            if (inspire_tg or Rsiz == 2) and XTsiz / min_XYRSiz > 1024 and tiled:
+                error_report.EmitError('PROFILE_1', 'XTsiz / min_XYRSiz = %f > 1024' % (1.0 * XTsiz / min_XYRSiz))
+            if (inspire_tg or Rsiz == 2) and XTsiz != YTsiz and tiled:
+                error_report.EmitError('PROFILE_1', 'XTsiz (=%d) != YTsiz (=%d)' % (XTsiz, YTsiz))
+
+            break
+
+    # Check GMLJP2 RectifiedGrid envelope against codestream dimensions
+    if gmljp2_found:
+        gmljp2_node = gdal.ParseXMLString(gmljp2)
+        rg = find_xml_node(gmljp2_node, 'gml:RectifiedGrid')
+        if rg is None:
+            rg = find_xml_node(gmljp2_node, 'RectifiedGrid')
+        if rg is None:
+            error_report.EmitError('GMLJP2', 'Cannot find RectifiedGrid in GMLJP2')
+        else:
+            low = find_xml_node(rg, 'low')
+            if low is None:
+                low = find_xml_node(rg, 'gml:low')
+            high = find_xml_node(rg, 'high')
+            if high is None:
+                high = find_xml_node(rg, 'gml:high')
+            if low and high:
+                low = get_element_val(low)
+                (low_x, low_y) = low.split(' ')[0:2]
+                low_x = int(low_x)
+                low_y = int(low_y)
+
+                if low_x != XOsiz:
+                    error_report.EmitError('GMLJP2', 'RectifiedGrid.limits.GridEnvelope.low[x] != XOsiz')
+                if low_y != YOsiz:
+                    error_report.EmitError('GMLJP2', 'RectifiedGrid.limits.GridEnvelope.low[y] != YOsiz')
+
+                high = get_element_val(high)
+                (high_x, high_y) = high.split(' ')[0:2]
+                high_x = int(high_x)
+                high_y = int(high_y)
+
+                if high_x != Xsiz - 1:
+                    error_report.EmitError('GMLJP2', 'RectifiedGrid.limits.GridEnvelope.high[x] != Xsiz - 1')
+                if high_y != Ysiz - 1:
+                    error_report.EmitError('GMLJP2', 'RectifiedGrid.limits.GridEnvelope.high[y] != Ysiz - 1')
+            else:
+                error_report.EmitError('GMLJP2', 'Cannot find low/high node in RectifiedGrid')
+
+    # Check against Orthoimagery document
+    if oidoc:
+        oidoc_content = open(oidoc).read()
+        oidoc_node = gdal.ParseXMLString(oidoc_content)
+        if oidoc_node is None:
+            error_report.EmitError('GENERAL', 'Cannot parse %s' % oidoc)
+        else:
+            oic = find_xml_node(oidoc_node, 'OrthoimageCoverage')
+            if oic is None:
+                oic = find_xml_node(oidoc_node, 'oi:OrthoimageCoverage')
+            if oic is None:
+                error_report.EmitError('GENERAL', 'Cannot find OrthoimageCoverage in %s' % oidoc)
+            else:
+                # Check RectifiedGrid envelope against codestream dimensions
+                rg = find_xml_node(oic, 'gml:RectifiedGrid')
+                if rg is None:
+                    rg = find_xml_node(oic, 'RectifiedGrid')
+                if rg is None:
+                    if expected_gmljp2:
+                        error_report.EmitError('INSPIRE_TG', 'Cannot find RectifiedGrid in OrthoImageryCoverage')
+                else:
+                    low = find_xml_node(rg, 'low')
+                    if low is None:
+                        low = find_xml_node(rg, 'gml:low')
+                    high = find_xml_node(rg, 'high')
+                    if high is None:
+                        high = find_xml_node(rg, 'gml:high')
+                    if low and high:
+                        low = get_element_val(low)
+                        (low_x, low_y) = low.split(' ')[0:2]
+                        low_x = int(low_x)
+                        low_y = int(low_y)
+
+                        if low_x != XOsiz:
+                            error_report.EmitError('INSPIRE_TG', 'RectifiedGrid.limits.GridEnvelope.low[x](=%d) != XOsiz(=%d)' % (low_x, XOsiz), conformance_class = 'A.8.6')
+                        if low_y != YOsiz:
+                            error_report.EmitError('INSPIRE_TG', 'RectifiedGrid.limits.GridEnvelope.low[y](=%d) != YOsiz(=%d)' % (low_y, YOsiz), conformance_class = 'A.8.6')
+
+                        high = get_element_val(high)
+                        (high_x, high_y) = high.split(' ')[0:2]
+                        high_x = int(high_x)
+                        high_y = int(high_y)
+
+                        if high_x != Xsiz - 1:
+                            error_report.EmitError('INSPIRE_TG', 'RectifiedGrid.limits.GridEnvelope.high[x](=%d) != Xsiz(=%d) - 1' % (high_x, Xsiz), conformance_class = 'A.8.6')
+                        if high_y != Ysiz - 1:
+                            error_report.EmitError('INSPIRE_TG', 'RectifiedGrid.limits.GridEnvelope.high[y](=%d) != Ysiz(=%d) - 1' % (high_y, Ysiz), conformance_class = 'A.8.6')
+                    else:
+                        error_report.EmitError('INSPIRE_TG', 'Cannot find low/high node in RectifiedGrid')
+
+                    check_oi_rg_consistency(filename, gdal.SerializeXMLTree(rg), error_report)
+
+                rangetype = find_xml_node(oic, 'gmlcov:rangeType')
+                if rangetype is None:
+                    rangetype = find_xml_node(oic, 'rangeType')
+                if rangetype is None:
+                    error_report.EmitError('INSPIRE_TG', 'Cannot find gmlcov:rangeType in OrthoImageryCoverage')
+                else:
+                    datarecord = find_xml_node(rangetype, 'swe:DataRecord')
+                    if datarecord is None:
+                        datarecord = find_xml_node(rangetype, 'DataRecord')
+                    if datarecord is None:
+                        error_report.EmitError('INSPIRE_TG', 'Cannot find swe:DataRecord in OrthoImageryCoverage.rangeType')
+                    else:
+                        count_fields = 0
+                        min_vals = []
+                        max_vals = []
+                        for child_idx in range(XML_FIRST_CHILD_IDX, len(datarecord)):
+                            child = datarecord[child_idx]
+                            if child[XML_TYPE_IDX] == gdal.CXT_Element and (child[XML_VALUE_IDX] == 'swe:field' or child[XML_VALUE_IDX] == 'field'):
+                                count_fields += 1
+
+                                interval = None
+                                constraint = find_xml_node(child, 'swe:constraint')
+                                if constraint is None:
+                                    constraint = find_xml_node(child, 'constraint')
+                                if constraint is not None:
+                                    AllowedValues = find_xml_node(constraint, 'swe:AllowedValues')
+                                    if AllowedValues is None:
+                                        AllowedValues = find_xml_node(constraint, 'AllowedValues')
+                                    if AllowedValues is not None:
+                                        interval = find_xml_node(AllowedValues, 'swe:interval')
+                                        if interval is None:
+                                            interval = find_xml_node(AllowedValues, 'interval')
+                                        if interval is not None:
+                                            interval = get_element_val(interval)
+                                if interval is None:
+                                    error_report.EmitError('INSPIRE_TG', 'Cannot find constraint.AllowedValues.interval for field %d' % count_fields)
+                                    min_vals.append(None)
+                                    max_vals.append(None)
+                                else:
+                                    (min_val, max_val) = interval.split(' ')
+                                    min_val = int(min_val)
+                                    max_val = int(max_val)
+                                    min_vals.append(min_val)
+                                    max_vals.append(max_val)
+
+                        # Check number of fields regarding number of components
+                        if pclr is None:
+                            if count_fields != Csiz:
+                                error_report.EmitError('INSPIRE_TG', 'count(OrthoImageryCoverage.rangeType.field)(=%d) != Csiz(=%d) ' % (count_fields, Csiz), conformance_class = 'A.8.6')
+                            else:
+                                # Check consistency of each channel bit-deph with the corresponding rangeType.field
+                                for i in range(Csiz):
+                                    if tab_Ssiz[i] >= 128:
+                                        tab_Ssiz[i] -= 128
+                                        minSsiz = - 2** tab_Ssiz[i]
+                                        maxSsiz = 2** tab_Ssiz[i] - 1
+                                    else:
+                                        minSsiz = 0
+                                        maxSsiz = 2** (tab_Ssiz[i]+1) - 1
+                                    if min_vals[i] is not None and max_vals[i] is not None:
+                                        if min_vals[i] != minSsiz:
+                                            error_report.EmitError('INSPIRE_TG', 'rangeType.field[%d].min(=%d) != min(Ssiz[%d])(=%d)' % (i, min_vals[i], i, minSsiz), conformance_class = 'A.8.6')
+                                        if max_vals[i] != maxSsiz:
+                                            error_report.EmitError('INSPIRE_TG', 'rangeType.field[%d].max(=%d) != max(Ssiz[%d])(=%d)' % (i, max_vals[i], i, maxSsiz), conformance_class = 'A.8.6')
+                        else:
+                            if count_fields != 3:
+                                error_report.EmitError('INSPIRE_TG', 'count(OrthoImageryCoverage.rangeType.field)(=%d) != 3 (for color table)' % (count_fields), conformance_class = 'A.8.6')
+
+
+    # Validate content of COD marker
+    cod = find_marker(cs, 'COD')
+    if not cod:
+        error_report.EmitError('GENERAL', 'No COD marker found')
+    else:
+        while True:
+            SPcod_transformation = get_field_val(cod, 'SPcod_transformation')
+            if SPcod_transformation is None:
+                error_report.EmitError('GENERAL', 'cod.SPcod_transformation not found (and perhaps other fields)')
+                break
+
+            Scod = int_or_none(get_field_val(cod, 'Scod'))
+
+            SPcod_NumDecompositions = int(get_field_val(cod, 'SPcod_NumDecompositions'))
+            if (inspire_tg or Rsiz == 2) and siz:
+                if XTsiz <= Xsiz - XOsiz and YTsiz <= Ysiz - YOsiz:
+                    max_dim = max(XTsiz, YTsiz)
+                else:
+                    max_dim = max(Xsiz - XOsiz, Ysiz - YOsiz)
+                if max_dim > 128 * 2**SPcod_NumDecompositions:
+                    error_report.EmitError('PROFILE_1', 'Not enough decomposition levels = %d (max_dim=%d, 128 * 2**SPcod_NumDecompositions=%d)' % (SPcod_NumDecompositions, max_dim, 128 * 2**SPcod_NumDecompositions))
+
+            SPcod_xcb_minus_2 = int(get_field_val(cod, 'SPcod_xcb_minus_2'))
+            SPcod_ycb_minus_2 = int(get_field_val(cod, 'SPcod_ycb_minus_2'))
+            if (inspire_tg or Rsiz == 2) and SPcod_xcb_minus_2 > 6 - 2:
+                error_report.EmitError('PROFILE_1', 'SPcod_xcb_minus_2 = %d, whereas max allowed for Profile 1 is 4' % SPcod_xcb_minus_2)
+            if (inspire_tg or Rsiz == 2) and SPcod_ycb_minus_2 > 6 - 2:
+                error_report.EmitError('PROFILE_1', 'SPcod_ycb_minus_2 = %d, whereas max allowed for Profile 1 is 4' % SPcod_ycb_minus_2)
+            if SPcod_xcb_minus_2 + SPcod_ycb_minus_2 > 8:
+                error_report.EmitError('GENERAL', 'SPcod_xcb_minus_2 + SPcod_ycb_minus_2 = %d, whereas max allowed is 8' % (SPcod_xcb_minus_2 + SPcod_ycb_minus_2))
+
+            for i in range(SPcod_NumDecompositions+1):
+                SPcod_Precincts = get_field_val(cod, 'SPcod_Precincts%d' % i)
+                if SPcod_Precincts is not None and (Scod & 1) == 0:
+                    error_report.EmitWarning('GENERAL', 'User-defined precincts %d found but SPcod_transformation dit not advertize it' % i)
+                elif SPcod_Precincts is None and (Scod & 1) != 0:
+                    error_report.EmitWarning('GENERAL', 'No user-defined precincts %d defined but SPcod_transformation advertized it' % i)
+                elif SPcod_Precincts is None and inspire_tg:
+                    error_report.EmitWarning('INSPIRE_TG', 'No user-defined precincts %d defined' % i, recommendation = 39)
+
+            break
+
+    # Check QCD marker
+    qcd = find_marker(cs, 'QCD')
+    if not qcd:
+        error_report.EmitError('GENERAL', 'No QCD marker found')
+
+    # Check SOT marker
+    sot = find_marker(cs, 'SOT')
+    if not sot:
+        error_report.EmitError('GENERAL', 'No SOT marker found')
+
+    # Check RGN marker presence
+    rgn = find_marker(cs, 'RGN')
+    if inspire_tg and rgn:
+        error_report.EmitError('INSPIRE_TG', 'RGN marker found, which is not allowed', requirement = 26, conformance_class = 'A.8.16')
+
+    # Check EOC marker
+    eoc = find_marker(cs, 'EOC')
+    if not eoc:
+        error_report.EmitError('GENERAL', 'No EOC marker found')
+
+    return error_report
+
+
+def main():
+    i = 1
+    filename = None
+    oidoc = None
+    ogc_schemas_location = None
+    inspire_tg = False
+    expected_gmljp2 = False
+    datatype = 'imagery'
+    while i < len(sys.argv):
+        if sys.argv[i] == "-oidoc":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            oidoc = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i] == "-ogc_schemas_location":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            ogc_schemas_location = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i] == "-datatype":
+            if i >= len(sys.argv) - 1:
+                return Usage()
+            datatype = sys.argv[i+1]
+            i = i + 1
+        elif sys.argv[i] == "-inspire_tg":
+            inspire_tg = True
+        elif sys.argv[i] == "-expected_gmljp2":
+            expected_gmljp2 = True
+        elif sys.argv[i][0] == '-':
+            return Usage()
+        elif filename is None:
+            filename = sys.argv[i]
+        else:
+            return Usage()
+
+        i = i + 1
+
+    if filename is None:
+        return Usage()
+
+    if ogc_schemas_location is None:
+        try:
+            os.stat('SCHEMAS_OPENGIS_NET')
+            ogc_schemas_location = 'SCHEMAS_OPENGIS_NET'
+        except:
+            pass
+
+    if ogc_schemas_location is not None:
+        try:
+            os.stat('%s/xml.xsd' % ogc_schemas_location)
+        except:
+            try:
+                os.stat('%s/SCHEMAS_OPENGIS_NET/xml.xsd' % ogc_schemas_location)
+                ogc_schemas_location = '%s/SCHEMAS_OPENGIS_NET' % ogc_schemas_location
+            except:
+                print('Cannot find %s/xml.xsd. -ogc_schemas_location value is probably wrong' % ogc_schemas_location)
+                return 1
+
+    return validate(filename, oidoc, inspire_tg, expected_gmljp2, ogc_schemas_location, datatype).error_count
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/swig/python/samples/vec_tr.py b/swig/python/samples/vec_tr.py
index 3122896..ec62269 100755
--- a/swig/python/samples/vec_tr.py
+++ b/swig/python/samples/vec_tr.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: vec_tr.py 18195 2009-12-06 20:24:39Z rouault $
+# $Id: vec_tr.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Apply a transformation to all OGR geometries.
@@ -29,13 +29,10 @@
 ###############################################################################
 
 try:
-    from osgeo import osr
     from osgeo import ogr
 except ImportError:
-    import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/samples/vec_tr_spat.py b/swig/python/samples/vec_tr_spat.py
index b93a6e6..54b1f4d 100755
--- a/swig/python/samples/vec_tr_spat.py
+++ b/swig/python/samples/vec_tr_spat.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: vec_tr_spat.py 18195 2009-12-06 20:24:39Z rouault $
+# $Id: vec_tr_spat.py 28391 2015-01-30 19:57:31Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Apply a transformation to all OGR geometries.
@@ -29,13 +29,10 @@
 ###############################################################################
 
 try:
-    from osgeo import osr
     from osgeo import ogr
 except ImportError:
-    import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/scripts/epsg_tr.py b/swig/python/scripts/epsg_tr.py
index 3549fd2..1d0044e 100755
--- a/swig/python/scripts/epsg_tr.py
+++ b/swig/python/scripts/epsg_tr.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python
+# -*- coding: utf-8 -*-
 #******************************************************************************
-#  $Id: epsg_tr.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: epsg_tr.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Project:  CFS OGC MapServer
 #  Purpose:  Script to create WKT and PROJ.4 dictionaries for EPSG GCS/PCS
@@ -50,8 +51,6 @@ def Usage():
 # =============================================================================
 def trHandleCode(code, gen_dict_line, report_error, output_format):
 
-    import time
-
     try:
         err = prj_srs.ImportFromEPSG( code )
     except:
@@ -80,9 +79,13 @@ def trHandleCode(code, gen_dict_line, report_error, output_format):
         if output_format == '-proj4':
             out_string = prj_srs.ExportToProj4()
 
-            name = prj_srs.GetAttrValue('PROJCS')
+            name = prj_srs.GetAttrValue('COMPD_CS')
+            if name is None:
+                name = prj_srs.GetAttrValue('PROJCS')
             if name is None:
                 name = prj_srs.GetAttrValue('GEOGCS')
+            if name is None:
+                name = prj_srs.GetAttrValue('GEOCCS')
 
             if name is None:
                 name = 'Unknown'
@@ -95,9 +98,14 @@ def trHandleCode(code, gen_dict_line, report_error, output_format):
                 print('#')
 
         if output_format == '-postgis':
-            name = prj_srs.GetAttrValue('PROJCS')
+
+            name = prj_srs.GetAttrValue('COMPD_CS')
+            if name is None:
+                name = prj_srs.GetAttrValue('PROJCS')
             if name is None:
                 name = prj_srs.GetAttrValue('GEOGCS')
+            if name is None:
+                name = prj_srs.GetAttrValue('GEOCCS')
 
             try:
                 proj4text = prj_srs.ExportToProj4()
diff --git a/swig/python/scripts/gcps2vec.py b/swig/python/scripts/gcps2vec.py
index 3787c22..cdb8230 100755
--- a/swig/python/scripts/gcps2vec.py
+++ b/swig/python/scripts/gcps2vec.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gcps2vec.py 21739 2011-02-18 14:59:15Z dron $
+#  $Id: gcps2vec.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Project:  GDAL
 #  Purpose:  Convert GCPs to a point layer.
@@ -88,7 +88,7 @@ if out_file is None:
 # ----------------------------------------------------------------------------
 ds = gdal.Open( in_file )
 if ds is None:
-    print('Unable to open %s' % filename)
+    print('Unable to open %s' % in_file)
     sys.exit(1)
 
 gcp_srs = ds.GetGCPProjection()
diff --git a/swig/python/scripts/gcps2wld.py b/swig/python/scripts/gcps2wld.py
index 2f337ad..d5c0d15 100755
--- a/swig/python/scripts/gcps2wld.py
+++ b/swig/python/scripts/gcps2wld.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gcps2wld.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gcps2wld.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Name:     gcps2wld
 #  Project:  GDAL Python Interface
@@ -37,7 +37,6 @@ except ImportError:
     import gdal
 
 import sys
-import os.path
 
 if len(sys.argv) < 2:
     print("Usage: gcps2wld.py source_file")
diff --git a/swig/python/scripts/gdal2tiles.py b/swig/python/scripts/gdal2tiles.py
index f49872e..deb2d46 100755
--- a/swig/python/scripts/gdal2tiles.py
+++ b/swig/python/scripts/gdal2tiles.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #******************************************************************************
-#  $Id: gdal2tiles.py 27349 2014-05-16 18:58:51Z rouault $
+#  $Id: gdal2tiles.py 28392 2015-01-30 21:01:09Z rouault $
 # 
 # Project:  Google Summer of Code 2007, 2008 (http://code.google.com/soc/)
 # Support:  BRGM (http://www.brgm.fr)
@@ -58,7 +58,7 @@ except:
     # 'antialias' resampling is not available
     pass
 
-__version__ = "$Id: gdal2tiles.py 27349 2014-05-16 18:58:51Z rouault $"
+__version__ = "$Id: gdal2tiles.py 28392 2015-01-30 21:01:09Z rouault $"
 
 resampling_list = ('average','near','bilinear','cubic','cubicspline','lanczos','antialias')
 profile_list = ('mercator','geodetic','raster') #,'zoomify')
@@ -93,15 +93,13 @@ Created by Klokan Petr Pridal on 2008-07-03.
 Google Summer of Code 2008, project GDAL2Tiles for OSGEO.
 
 In case you use this class in your product, translate it to another language
-or find it usefull for your project please let me know.
+or find it useful for your project please let me know.
 My email: klokan at klokan dot cz.
 I would like to know where it was used.
 
 Class is available under the open-source GDAL license (www.gdal.org).
 """
 
-import math
-
 MAXZOOMLEVEL = 32
 
 class GlobalMercator(object):
@@ -435,13 +433,13 @@ class Zoomify(object):
 
         # Size (in tiles) for each tier of pyramid.
         self.tierSizeInTiles = []
-        self.tierSizeInTiles.push( tiles )
+        self.tierSizeInTiles.append( tiles )
 
         # Image size in pixels for each pyramid tierself
         self.tierImageSize = []
         self.tierImageSize.append( imagesize );
 
-        while (imagesize[0] > tilesize or imageSize[1] > tilesize ):
+        while (imagesize[0] > tilesize or imagesize[1] > tilesize ):
             imagesize = (math.floor( imagesize[0] / 2 ), math.floor( imagesize[1] / 2) )
             tiles = ( math.ceil( imagesize[0] / tilesize ), math.ceil( imagesize[1] / tilesize ) )
             self.tierSizeInTiles.append( tiles )
@@ -1055,7 +1053,8 @@ gdal2tiles temp.vrt""" % self.input )
 
                 def rastertileswne(x,y,z):
                     pixelsizex = (2**(self.tmaxz-z) * self.out_gt[1]) # X-pixel size in level
-                    pixelsizey = (2**(self.tmaxz-z) * self.out_gt[1]) # Y-pixel size in level (usually -1*pixelsizex)
+                    #Comment pixelsizey as unused...
+                    #pixelsizey = (2**(self.tmaxz-z) * self.out_gt[1]) # Y-pixel size in level (usually -1*pixelsizex)
                     west = self.out_gt[0] + x*self.tilesize*pixelsizex
                     east = west + self.tilesize*pixelsizex
                     south = self.ominy + y*self.tilesize*pixelsizex
diff --git a/swig/python/scripts/gdal_auth.py b/swig/python/scripts/gdal_auth.py
index 96f60d2..7cbba43 100755
--- a/swig/python/scripts/gdal_auth.py
+++ b/swig/python/scripts/gdal_auth.py
@@ -33,8 +33,6 @@
 from osgeo import gdal
 
 import sys
-import stat
-import os
 import time
 import webbrowser
 
diff --git a/swig/python/scripts/gdal_calc.dox b/swig/python/scripts/gdal_calc.dox
index 8f3ebbd..7bac888 100644
--- a/swig/python/scripts/gdal_calc.dox
+++ b/swig/python/scripts/gdal_calc.dox
@@ -14,7 +14,7 @@ Options:
                         numpy array functions (i.e. logical_and())
   -A A                  input gdal raster file, note you can use any letter
                         A-Z
-  --A_band=A_BAND       number of raster band for file A (default 0)
+  --A_band=A_BAND       number of raster band for file A (default 1)
   --outfile=OUTF        output file to generate or fill
   --NoDataValue=NODATAVALUE
                         set output nodata value (Defaults to datatype specific
diff --git a/swig/python/scripts/gdal_calc.py b/swig/python/scripts/gdal_calc.py
index 82021c8..e928b7e 100755
--- a/swig/python/scripts/gdal_calc.py
+++ b/swig/python/scripts/gdal_calc.py
@@ -42,12 +42,9 @@
 # gdal_calc.py -A input.tif --outfile=result.tif --calc="A*(A>0)" --NoDataValue=0
 ################################################################
 
-try:
-    from osgeo import gdal
-    from osgeo.gdalnumeric import *
-except ImportError:
-    import gdal
-    from gdalnumeric import *
+from osgeo import gdal
+from osgeo import gdalnumeric
+import numpy
 
 from optparse import OptionParser
 import sys
@@ -177,7 +174,7 @@ def doit(opts, args):
             myOutB=None
 
     if opts.debug:
-        print("output file: %s, dimensions: %s, %s, type: %s" %(opts.outF,myOut.RasterXSize,myOut.RasterYSize,gdal.GetDataTypeName(myOutB.DataType)))
+        print("output file: %s, dimensions: %s, %s, type: %s" %(opts.outF,myOut.RasterXSize,myOut.RasterYSize,myOutType))
 
     ################################################################
     # find block size to chop grids into bite-sized chunks 
@@ -258,7 +255,7 @@ def doit(opts, args):
                         myBandNo=bandNo
                     else:
                         myBandNo=myBands[i]
-                    myval=BandReadAsArray(myFiles[i].GetRasterBand(myBandNo),
+                    myval=gdalnumeric.BandReadAsArray(myFiles[i].GetRasterBand(myBandNo),
                                           xoff=myX, yoff=myY,
                                           win_xsize=nXValid, win_ysize=nYValid)
 
@@ -283,7 +280,7 @@ def doit(opts, args):
 
                 # write data block to the output file
                 myOutB=myOut.GetRasterBand(bandNo)
-                BandWriteArray(myOutB, myResult, xoff=myX, yoff=myY)
+                gdalnumeric.BandWriteArray(myOutB, myResult, xoff=myX, yoff=myY)
 
     print("100 - Done")
     #print("Finished - Results written to %s" %opts.outF)
@@ -300,7 +297,7 @@ def main():
     # hack to limit the number of input file options close to required number
     for myAlpha in AlphaList[0:len(sys.argv)-1]:
         eval('parser.add_option("-%s", dest="%s", help="input gdal raster file, note you can use any letter A-Z")' %(myAlpha, myAlpha))
-        eval('parser.add_option("--%s_band", dest="%s_band", default=0, type=int, help="number of raster band for file %s (default 0)")' %(myAlpha, myAlpha, myAlpha))
+        eval('parser.add_option("--%s_band", dest="%s_band", default=1, type=int, help="number of raster band for file %s (default 1)")' %(myAlpha, myAlpha, myAlpha))
 
     parser.add_option("--outfile", dest="outF", default='gdal_calc.tif', help="output file to generate or fill")
     parser.add_option("--NoDataValue", dest="NoDataValue", type=float, help="set output nodata value (Defaults to datatype specific value)")
diff --git a/swig/python/scripts/gdal_edit.dox b/swig/python/scripts/gdal_edit.dox
index 129670a..4e7b19f 100644
--- a/swig/python/scripts/gdal_edit.dox
+++ b/swig/python/scripts/gdal_edit.dox
@@ -8,13 +8,14 @@ Edit in place various information of an existing GDAL dataset
 \verbatim
 gdal_edit [--help-general] [-ro] [-a_srs srs_def] [-a_ullr ulx uly lrx lry]
           [-tr xres yres] [-unsetgt] [-a_nodata value]
+          [-unsetstats] [-stats] [-approx_stats]
           [-gcp pixel line easting northing [elevation]]*
-          [-mo "META-TAG=VALUE"]*  datasetname
+          [-unsetmd] [-oo NAME=VALUE]* [-mo "META-TAG=VALUE"]*  datasetname
 \endverbatim
 
 \section gdal_edit_description DESCRIPTION
 
-The gdal_edit.py script can be used to allows to edit in place various information
+The gdal_edit.py script can be used to edit in place various information
 of an existing GDAL dataset (projection, geotransform, nodata, metadata).
 
 It works only with raster formats that support update access to
@@ -27,7 +28,7 @@ and exit.
 </dd>
 
 <dt> <b>-ro</b></dt>:<dd> (GDAL >= 1.11)
-Open the dataset in read-only. Might be usefull for drivers refusing to
+Open the dataset in read-only. Might be useful for drivers refusing to
 use the dataset in update-mode. In which case, updated information will go
 into PAM .aux.xml files.</dd>
 
@@ -46,6 +47,15 @@ Both must be positive values.</dd>
 <dt> <b>-unsetgt</b></dt>:<dd>
 Remove the georeference information.</dd>
 
+<dt> <b>-unsetstats</b></dt>:<dd> (GDAL >= 2.0)
+Remove band statistics information.</dd>
+
+<dt> <b>-stats</b></dt>:<dd> (GDAL >= 2.0)
+Calculate and store band statistics.</dd>
+
+<dt> <b>-approx_stats</b></dt>:<dd> (GDAL >= 2.0)
+Calculate and store approximate band statistics.</dd>
+
 <dt> <b>-a_nodata</b> <i>value</i>:</dt><dd>
 Assign a specified nodata value to output bands.</dd>
 
@@ -54,13 +64,23 @@ Add the indicated ground control point to the dataset.  This option
 may be provided multiple times to provide a set of GCPs. 
 </dd>
 
+<dt> <b>-unsetmd</b></dt>:<dd> (GDAL >= 2.0)
+Remove existing metadata (in the default metadata domain). Can be combined
+with -mo.</dd>
+
 <dt> <b>-mo</b> <i>"META-TAG=VALUE"</i>:</dt><dd> Passes a metadata key and
-value to set on the output dataset if possible.</dd>
+value to set on the output dataset if possible. This metadata is added to
+the existing metadata items, unless -unsetmd is also specified.</dd>
+
+<dt> <b>-oo</b> <i>"NAME=VALUE"</i>:</dt><dd> 
+(GDAL >= 2.0) Open option (format specific).</dd>
 
 </dl>
 
 -a_ullr, -tr and -unsetgt options are exclusive.
 
+-unsetstats and either -stats or -approx_stats options are exclusive.
+
 \section gdal_edit_example EXAMPLE
 
 \verbatim
diff --git a/swig/python/scripts/gdal_edit.py b/swig/python/scripts/gdal_edit.py
index 9e829ef..1ff1e58 100755
--- a/swig/python/scripts/gdal_edit.py
+++ b/swig/python/scripts/gdal_edit.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 ###############################################################################
-# $Id: gdal_edit.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: gdal_edit.py 28676 2015-03-08 09:03:15Z rouault $
 #
 #  Project:  GDAL samples
 #  Purpose:  Edit in place various information of an existing GDAL dataset
@@ -35,9 +35,10 @@ from osgeo import osr
 
 def Usage():
     print('Usage: gdal_edit [--help-general] [-ro] [-a_srs srs_def] [-a_ullr ulx uly lrx lry]')
-    print('                 [-tr xres yres] [-unsetgt] [-a_nodata value] ')
+    print('                 [-tr xres yres] [-unsetgt] [-a_nodata value]')
+    print('                 [-unsetstats] [-stats] [-approx_stats]')
     print('                 [-gcp pixel line easting northing [elevation]]*')
-    print('                 [-mo "META-TAG=VALUE"]*  datasetname')
+    print('                 [-unsetmd] [-oo NAME=VALUE]* [-mo "META-TAG=VALUE"]*  datasetname')
     print('')
     print('Edit in place various information of an existing GDAL dataset.')
     return -1
@@ -69,9 +70,14 @@ def gdal_edit(argv):
     xres = None
     yres = None
     unsetgt = False
+    unsetstats = False
+    stats = False
+    approx_stats = False
+    unsetmd = False
     ro = False
     molist = []
     gcp_list = []
+    open_options = []
 
     i = 1
     argc = len(argv)
@@ -119,6 +125,18 @@ def gdal_edit(argv):
             gcp_list.append(gcp)
         elif argv[i] == '-unsetgt' :
             unsetgt = True
+        elif argv[i] == '-unsetstats':
+            unsetstats = True
+        elif argv[i] == '-approx_stats':
+            stats = True
+            approx_stats = True
+        elif argv[i] == '-stats':
+            stats = True
+        elif argv[i] == '-unsetmd':
+            unsetmd = True
+        elif argv[i] == '-oo' and i < len(argv)-1:
+            open_options.append(argv[i+1])
+            i = i + 1
         elif argv[i][0] == '-':
             sys.stderr.write('Unrecognized option : %s\n' % argv[i])
             return Usage()
@@ -133,7 +151,9 @@ def gdal_edit(argv):
     if datasetname is None:
         return Usage()
 
-    if srs is None and lry is None and yres is None and not unsetgt and nodata is None and len(molist) == 0:
+    if (srs is None and lry is None and yres is None and not unsetgt
+            and not unsetstats and not stats and nodata is None
+            and len(molist) == 0 and not unsetmd):
         print('No option specified')
         print('')
         return Usage()
@@ -150,7 +170,18 @@ def gdal_edit(argv):
         print('')
         return Usage()
 
-    if ro:
+    if unsetstats and stats:
+        print('-unsetstats and either -stats or -approx_stats options are exclusive.')
+        print('')
+        return Usage()
+
+    if open_options is not None:
+        if ro:
+            ds = gdal.OpenEx(datasetname, gdal.OF_RASTER, open_options = open_options)
+        else:
+            ds = gdal.OpenEx(datasetname, gdal.OF_RASTER | gdal.OF_UPDATE, open_options = open_options)
+    # GDAL 1.X compat
+    elif ro:
         ds = gdal.Open(datasetname)
     else:
         ds = gdal.Open(datasetname, gdal.GA_Update)
@@ -177,7 +208,7 @@ def gdal_edit(argv):
     if yres is not None:
         gt = ds.GetGeoTransform()
         # Doh ! why is gt a tuple and not an array...
-        gt = [ gt[i] for i in range(6) ]
+        gt = [ gt[j] for j in range(6) ]
         gt[1] = xres
         gt[5] = yres
         ds.SetGeoTransform(gt)
@@ -194,12 +225,33 @@ def gdal_edit(argv):
 
     if nodata is not None:
         for i in range(ds.RasterCount):
-            ds.GetRasterBand(1).SetNoDataValue(nodata)
+            ds.GetRasterBand(i+1).SetNoDataValue(nodata)
+
+    if unsetstats:
+        for i in range(ds.RasterCount):
+            band = ds.GetRasterBand(i+1)
+            for key in band.GetMetadata().keys():
+                if key.startswith('STATISTICS_'):
+                    band.SetMetadataItem(key, None)
+
+    if stats:
+        for i in range(ds.RasterCount):
+            ds.GetRasterBand(i+1).ComputeStatistics(approx_stats)
 
     if len(molist) != 0:
-        ds.SetMetadata(molist)
+        if unsetmd:
+            md = {}
+        else:
+            md = ds.GetMetadata()
+        for moitem in molist:
+            equal_pos = moitem.find('=')
+            if equal_pos > 0:
+                md[moitem[0:equal_pos]] = moitem[equal_pos+1:]
+        ds.SetMetadata(md)
+    elif unsetmd:
+        ds.SetMetadata({})
 
-    ds = None
+    ds = band = None
 
     return 0
 
diff --git a/swig/python/scripts/gdal_fillnodata.dox b/swig/python/scripts/gdal_fillnodata.dox
index b348a43..4f3cf6c 100644
--- a/swig/python/scripts/gdal_fillnodata.dox
+++ b/swig/python/scripts/gdal_fillnodata.dox
@@ -22,7 +22,7 @@ docs.
 <dl>
 
 <dt> <b>-q</b>:</dt><dd>
-The script runs in quiet mode.  The progress monitor is supressed and routine
+The script runs in quiet mode.  The progress monitor is suppressed and routine
 messages are not displayed.
 
 <dt> <b>-md</b> <i>max_distance</i>:</dt><dd>
diff --git a/swig/python/scripts/gdal_fillnodata.py b/swig/python/scripts/gdal_fillnodata.py
index a86fd0a..4f53ab3 100755
--- a/swig/python/scripts/gdal_fillnodata.py
+++ b/swig/python/scripts/gdal_fillnodata.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gdal_fillnodata.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdal_fillnodata.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Project:  GDAL Python Interface
 #  Purpose:  Application for filling nodata areas in a raster by interpolation
@@ -30,13 +30,11 @@
 #******************************************************************************
 
 try:
-    from osgeo import gdal, ogr
+    from osgeo import gdal
 except ImportError:
     import gdal
-    import ogr
 
 import sys
-import os.path
 
 def CopyBand( srcband, dstband ):
     for line in range(srcband.YSize):
@@ -181,7 +179,10 @@ if dst_filename is not None:
     
     dstband = dst_ds.GetRasterBand(1)
     CopyBand( srcband, dstband )
-    
+    ndv = srcband.GetNoDataValue()
+    if ndv is not None:
+        dstband.SetNoDataValue(ndv)
+
 else:
     dstband = srcband
 
diff --git a/swig/python/scripts/gdal_merge.py b/swig/python/scripts/gdal_merge.py
index 3844886..c8a1100 100755
--- a/swig/python/scripts/gdal_merge.py
+++ b/swig/python/scripts/gdal_merge.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: gdal_merge.py 27044 2014-03-16 23:41:27Z rouault $
+# $Id: gdal_merge.py 28137 2014-12-14 10:33:22Z rouault $
 #
 # Project:  InSAR Peppers
 # Purpose:  Module to extract data from many rasters into one output.
@@ -44,6 +44,7 @@ except:
 
 import sys
 import math
+import time
 
 __version__ = '$id$'[5:-1]
 verbose = 0
@@ -277,6 +278,7 @@ def main( argv=None ):
     band_type = None
     createonly = 0
     bTargetAlignedPixels = False
+    start_time = time.time()
     
     gdal.AllRegister()
     if argv is None:
@@ -486,9 +488,10 @@ def main( argv=None ):
         
         if verbose != 0:
             print("")
-            print("Processing file %5d of %5d, %6.3f%% completed." \
+            print("Processing file %5d of %5d, %6.3f%% completed in %d minutes." \
                   % (fi_processed+1,len(file_infos),
-                     fi_processed * 100.0 / len(file_infos)) )
+                     fi_processed * 100.0 / len(file_infos),
+                     int(round((time.time() - start_time)/60.0)) ))
             fi.report()
 
         if separate == 0 :
diff --git a/swig/python/scripts/gdal_polygonize.dox b/swig/python/scripts/gdal_polygonize.dox
index c979e6d..8457d1f 100644
--- a/swig/python/scripts/gdal_polygonize.dox
+++ b/swig/python/scripts/gdal_polygonize.dox
@@ -60,7 +60,7 @@ file to be created.  Default is GML.
 </dd>
 
 <dt> <b>-q</b>:</dt><dd>
-The script runs in quiet mode.  The progress monitor is supressed and routine
+The script runs in quiet mode.  The progress monitor is suppressed and routine
 messages are not displayed.
 </dd>
 
diff --git a/swig/python/scripts/gdal_polygonize.py b/swig/python/scripts/gdal_polygonize.py
index c38afd8..efe24c6 100755
--- a/swig/python/scripts/gdal_polygonize.py
+++ b/swig/python/scripts/gdal_polygonize.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
 #******************************************************************************
-#  $Id: gdal_polygonize.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdal_polygonize.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Project:  GDAL Python Interface
 #  Purpose:  Application for converting raster data to a vector polygon layer.
@@ -36,7 +36,6 @@ except ImportError:
     import gdal, ogr, osr
 
 import sys
-import os.path
 
 def Usage():
     print("""
diff --git a/swig/python/scripts/gdal_proximity.dox b/swig/python/scripts/gdal_proximity.dox
index 54fa534..090b0a9 100644
--- a/swig/python/scripts/gdal_proximity.dox
+++ b/swig/python/scripts/gdal_proximity.dox
@@ -10,7 +10,8 @@ gdal_proximity.py srcfile dstfile [-srcband n] [-dstband n]
                   [-of format] [-co name=value]*
                   [-ot Byte/Int16/Int32/Float32/etc]
                   [-values n,n,n] [-distunits PIXEL/GEO]
-                  [-maxdist n] [-nodata n] [-fixed-buf-val n]
+                  [-maxdist n] [-nodata n] [-use_input_nodata YES/NO]
+                  [-fixed-buf-val n] 
 \endverbatim
 
 \section gdal_proximity_description DESCRIPTION
@@ -51,14 +52,21 @@ coordinates (default PIXEL).
 </dd>
 
 <dt> <b>-maxdist</b> <i>n</i>:</dt><dd>
-The maximum distance to be generated.  All pixels beyond this distance will
-be assigned either the nodata value, or 65535.   Distance is interpreted in pixels unless -distunits GEO is specified.
+The maximum distance to be generated. The nodata value will be used for pixels
+beyond this distance. If a nodata value is not provided, the output band will be
+queried for its nodata value. If the output band does not have a nodata value,
+then the value 65535 will be used. Distance is interpreted in pixels unless
+-distunits GEO is specified.
 </dd>
 
 <dt> <b>-nodata</b> <i>n</i>:</dt><dd>
 Specify a nodata value to use for the destination proximity raster.
 </dd>
 
+<dt> <b>-use_input_nodata</b> <i>YES/NO</i>:</dt><dd> (GDAL >= 2.0)
+Indicate whether nodata pixels in the input raster should be nodata in the output raster (default NO).
+</dd>
+
 <dt> <b>-fixed-buf-val</b> <i>n</i>:</dt><dd>
 Specify a value to be applied to all pixels that are within the -maxdist of target pixels (including the target pixels) instead of a distance value.
 </dd>
diff --git a/swig/python/scripts/gdal_proximity.py b/swig/python/scripts/gdal_proximity.py
index 36230c2..b93399f 100755
--- a/swig/python/scripts/gdal_proximity.py
+++ b/swig/python/scripts/gdal_proximity.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gdal_proximity.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdal_proximity.py 28882 2015-04-09 15:59:38Z rouault $
 # 
 #  Name:     gdalproximity
 #  Project:  GDAL Python Interface
@@ -36,7 +36,6 @@ except ImportError:
     import gdal
 
 import sys
-import os.path
 
 def Usage():
     print("""
@@ -44,7 +43,8 @@ gdal_proximity.py srcfile dstfile [-srcband n] [-dstband n]
                   [-of format] [-co name=value]*
                   [-ot Byte/Int16/Int32/Float32/etc]
                   [-values n,n,n] [-distunits PIXEL/GEO]
-                  [-maxdist n] [-nodata n] [-fixed-buf-val n] [-q] """)
+                  [-maxdist n] [-nodata n] [-use_input_nodata YES/NO]
+                  [-fixed-buf-val n] [-q] """)
     sys.exit(1)
 
 # =============================================================================
@@ -99,6 +99,10 @@ while i < len(argv):
         i = i + 1
         options.append( 'NODATA=' + argv[i] )
 
+    elif arg == '-use_input_nodata':
+        i = i + 1
+        options.append( 'USE_INPUT_NODATA=' + argv[i] )
+
     elif arg == '-fixed-buf-val':
         i = i + 1
         options.append( 'FIXED_BUF_VAL=' + argv[i] )
diff --git a/swig/python/scripts/gdal_retile.py b/swig/python/scripts/gdal_retile.py
index c3685f1..876e922 100755
--- a/swig/python/scripts/gdal_retile.py
+++ b/swig/python/scripts/gdal_retile.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-#  $Id: gdal_retile.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdal_retile.py 28389 2015-01-30 19:26:09Z rouault $
 #
 # Purpose:  Module for retiling (merging) tiles and building tiled pyramids
 # Author:   Christian Meuller, christian.mueller at nvoe.at
@@ -34,19 +34,22 @@ try:
     from osgeo import gdal
     from osgeo import ogr
     from osgeo import osr
-    from osgeo.gdalconst import *
 except:
     import gdal
     import ogr
     import osr
-    from gdalconst import *
 
 import sys
 import os
 import math
 
+try:
+    progress = gdal.TermProgress_nocb
+except:
+    progress = gdal.TermProgress
+
 class AffineTransformDecorator:
-    """ A class providing some usefull methods for affine Transformations """
+    """ A class providing some useful methods for affine Transformations """
     def __init__(self, transform ):
         self.geotransform=transform
         self.scaleX=self.geotransform[1]
@@ -85,7 +88,7 @@ class DataSetCache:
             return self.dict[name]
         result = gdal.Open(name)
         if result is None:
-            print("Error openenig:%s" % NameError)
+            print("Error opening: %s" % NameError)
             sys.exit(1)
         if len(self.queue)==self.cacheSize:
             toRemove = self.queue.pop(0)
@@ -206,7 +209,7 @@ class mosaic_info:
         if envelope is None:
             return None
 
-        #enlarge to query rect if necessairy
+        #enlarge to query rect if necessary
         envelope= ( min(minx,envelope[0]),max(maxx,envelope[1]),
                     min(miny,envelope[2]),max(maxy,envelope[3]))
 
@@ -227,35 +230,53 @@ class mosaic_info:
             featureName =  feature.GetField(0)
             sourceDS=self.cache.get(featureName)
             dec = AffineTransformDecorator(sourceDS.GetGeoTransform())
-            #calculate read and write offsets
-            readOffsetX =int(round((minx-dec.ulx) / self.scaleX))
-            readOffsetY =int(round((maxy-dec.uly) / self.scaleY))
-            writeOffsetX=0
-            if readOffsetX<0:
-                writeOffsetX=readOffsetX*-1;
-                readOffsetX=0
-            writeOffsetY=0
-            if readOffsetY<0:
-                writeOffsetY=readOffsetY*-1;
-                readOffsetY=0
-            #calculate read and write dimensions
-            readX=min(resultSizeX,sourceDS.RasterXSize-readOffsetX,resultSizeX-writeOffsetX)
-            if readX<=0:
-                continue
-            readY=min(resultSizeY,sourceDS.RasterYSize-readOffsetY,resultSizeY-writeOffsetY)
-            if readY<=0:
+
+            dec.lrx = dec.ulx + sourceDS.RasterXSize * dec.scaleX
+            dec.lry = dec.uly + sourceDS.RasterYSize * dec.scaleY
+
+            # Find the intersection region
+            tgw_ulx = max(dec.ulx, minx)
+            tgw_lrx = min(dec.lrx, maxx)
+            if self.scaleY < 0:
+                tgw_uly = min(dec.uly, maxy)
+                tgw_lry = max(dec.lry, miny)
+            else:
+                tgw_uly = max(dec.uly, maxy)
+                tgw_lry = min(dec.lry, miny)
+
+            # Compute source window in pixel coordinates.
+            sw_xoff = int((tgw_ulx - dec.ulx) / dec.scaleX)
+            sw_yoff = int((tgw_uly - dec.uly) / dec.scaleY)
+            sw_xsize = int((tgw_lrx - dec.ulx) / dec.scaleX + 0.5) - sw_xoff
+            sw_ysize = int((tgw_lry - dec.uly) / dec.scaleY + 0.5) - sw_yoff
+            if sw_xsize <= 0 or sw_ysize <= 0:
                 continue
 
-#            print "READ",readOffsetX,readOffsetY,readX,readY
+            # Compute target window in pixel coordinates
+            tw_xoff = int((tgw_ulx - minx) / self.scaleX)
+            tw_yoff = int((tgw_uly - maxy) / self.scaleY)
+            tw_xsize = int((tgw_lrx - minx) / self.scaleX + 0.5) - tw_xoff
+            tw_ysize = int((tgw_lry - maxy) / self.scaleY + 0.5) - tw_yoff
+            if tw_xsize <= 0 or tw_ysize <= 0:
+                continue
 
-            for bandNr in range(1,self.bands+1):
+            assert tw_xoff >= 0
+            assert tw_yoff >= 0
+            assert sw_xoff >= 0
+            assert sw_yoff >= 0
+            
+            for bandNr in range(1, self.bands + 1):
                 s_band = sourceDS.GetRasterBand( bandNr )
                 t_band = resultDS.GetRasterBand( bandNr )
                 if self.ct is not None:
                     t_band.SetRasterColorTable(self.ct)
                 t_band.SetRasterColorInterpretation(self.ci[bandNr-1])
-                data = s_band.ReadRaster( readOffsetX,readOffsetY,readX,readY, readX,readY, self.band_type )
-                t_band.WriteRaster(writeOffsetX,writeOffsetY,readX,readY,data )
+                
+                data = s_band.ReadRaster( sw_xoff, sw_yoff, sw_xsize, sw_ysize, tw_xsize, tw_ysize, self.band_type )
+                if data is None:                    
+                    print(gdal.GetLastErrorMsg())
+
+                t_band.WriteRaster(tw_xoff, tw_yoff, tw_xsize, tw_ysize, data )
 
         return resultDS
 
@@ -330,6 +351,11 @@ def tileImage(minfo, ti ):
     yRange = list(range(1,ti.countTilesY+1))
     xRange = list(range(1,ti.countTilesX+1))
 
+    if not Quiet and not Verbose:
+        progress(0.0)
+        processed = 0
+        total = len(xRange) * len(yRange)
+
     for yIndex in yRange:
         for xIndex in xRange:
             offsetY=(yIndex-1)* ti.tileHeight
@@ -349,6 +375,9 @@ def tileImage(minfo, ti ):
                 tilename=getTileName(minfo,ti, xIndex, yIndex)
             createTile(minfo, offsetX, offsetY, width, height,tilename,OGRDS)
 
+            if not Quiet and not Verbose:
+                processed += 1
+                progress(processed / float(total))
 
     if TileIndexName is not None:
         if UseDirForEachRow and PyramidOnly == False:
@@ -466,6 +495,7 @@ def createPyramidTile(levelMosaicInfo, offsetX, offsetY, width, height,tileName,
 
     if MemDriver is not None:
         tt_fh = Driver.CreateCopy( tileName, t_fh, 0, CreateOptions )
+        tt_fh.FlushCache()
 
     if Verbose:
         print(tileName + " : " + str(offsetX)+"|"+str(offsetY)+"-->"+str(width)+"-"+str(height))
@@ -538,6 +568,7 @@ def createTile( minfo, offsetX,offsetY,width,height, tilename,OGRDS):
 
     if MemDriver is not None:
         tt_fh = Driver.CreateCopy( tilename, t_fh, 0, CreateOptions )
+        tt_fh.FlushCache()
 
     if Verbose:
         print(tilename + " : " + str(offsetX)+"|"+str(offsetY)+"-->"+str(width)+"-"+str(height))
@@ -690,7 +721,7 @@ def UsageFormat():
 # =============================================================================
 def Usage():
      print('Usage: gdal_retile.py ')
-     print('        [-v] [-co NAME=VALUE]* [-of out_format]')
+     print('        [-v] [-q] [-co NAME=VALUE]* [-of out_format]')
      print('        [-ps pixelWidth pixelHeight]')
      print('        [-ot  {Byte/Int16/UInt16/UInt32/Int32/Float32/Float64/')
      print('               CInt16/CInt32/CFloat32/CFloat64}]')
@@ -712,6 +743,7 @@ def Usage():
 def main(args = None):
 
     global Verbose
+    global Quiet
     global CreateOptions
     global Names
     global TileWidth
@@ -763,6 +795,8 @@ def main(args = None):
 
         elif arg == '-v':
             Verbose = True
+        elif arg == '-q':
+            Quiet = True
 
         elif arg == '-targetDir':
             i+=1
@@ -784,15 +818,15 @@ def main(args = None):
             i+=1
             ResamplingMethodString=argv[i]
             if ResamplingMethodString=="near":
-                ResamplingMethod=GRA_NearestNeighbour
+                ResamplingMethod=gdal.GRA_NearestNeighbour
             elif ResamplingMethodString=="bilinear":
-                 ResamplingMethod=GRA_Bilinear
+                 ResamplingMethod=gdal.GRA_Bilinear
             elif ResamplingMethodString=="cubic":
-                 ResamplingMethod=GRA_Cubic
+                 ResamplingMethod=gdal.GRA_Cubic
             elif ResamplingMethodString=="cubicspline":
-                 ResamplingMethod=GRA_CubicSpline
+                 ResamplingMethod=gdal.GRA_CubicSpline
             elif ResamplingMethodString=="lanczos":
-                ResamplingMethod=GRA_Lanczos
+                ResamplingMethod=gdal.GRA_Lanczos
             else:
                 print("Unknown resampling method: %s" % ResamplingMethodString)
                 return 1
@@ -885,7 +919,7 @@ def main(args = None):
 
 
     DriverMD = Driver.GetMetadata()
-    Extension=DriverMD.get(DMD_EXTENSION);
+    Extension=DriverMD.get(gdal.DMD_EXTENSION);
     if 'DCAP_CREATE' not in DriverMD:
         MemDriver=gdal.GetDriverByName("MEM")
 
@@ -965,7 +999,7 @@ def initGlobals():
 
     Source_SRS=None
     TargetDir=None
-    ResamplingMethod=GRA_NearestNeighbour
+    ResamplingMethod=gdal.GRA_NearestNeighbour
     Levels=0
     PyramidOnly=False
     LastRowIndx=-1
@@ -975,6 +1009,7 @@ def initGlobals():
 
 #global vars
 Verbose=False
+Quiet=False
 CreateOptions = []
 Names=[]
 TileWidth=256
@@ -991,7 +1026,7 @@ CsvDelimiter=";"
 CsvFileName=None
 Source_SRS=None
 TargetDir=None
-ResamplingMethod=GRA_NearestNeighbour
+ResamplingMethod=gdal.GRA_NearestNeighbour
 Levels=0
 PyramidOnly=False
 LastRowIndx=-1
diff --git a/swig/python/scripts/gdal_sieve.dox b/swig/python/scripts/gdal_sieve.dox
index 962434e..8ede34f 100644
--- a/swig/python/scripts/gdal_sieve.dox
+++ b/swig/python/scripts/gdal_sieve.dox
@@ -23,7 +23,7 @@ docs.
 <dl>
 
 <dt> <b>-q</b>:</dt><dd>
-The script runs in quiet mode.  The progress monitor is supressed and routine
+The script runs in quiet mode.  The progress monitor is suppressed and routine
 messages are not displayed.
 
 <dt> <b>-st</b> <i>threshold</i>:</dt><dd>
diff --git a/swig/python/scripts/gdal_sieve.py b/swig/python/scripts/gdal_sieve.py
index a19bfd1..7f0cbfb 100755
--- a/swig/python/scripts/gdal_sieve.py
+++ b/swig/python/scripts/gdal_sieve.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: gdal_sieve.py 27044 2014-03-16 23:41:27Z rouault $
+#  $Id: gdal_sieve.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Project:  GDAL Python Interface
 #  Purpose:  Application for applying sieve filter to raster data.
@@ -30,13 +30,11 @@
 #******************************************************************************
 
 try:
-    from osgeo import gdal, ogr
+    from osgeo import gdal
 except ImportError:
     import gdal
-    import ogr
 
 import sys
-import os.path
 
 def Usage():
     print("""
diff --git a/swig/python/scripts/gdalcompare.py b/swig/python/scripts/gdalcompare.py
index d0a63fa..1edb73c 100755
--- a/swig/python/scripts/gdalcompare.py
+++ b/swig/python/scripts/gdalcompare.py
@@ -35,7 +35,7 @@ import filecmp
 from osgeo import gdal, osr
 
 #######################################################
-def compare_metadata(golden_md, new_md, id):
+def compare_metadata(golden_md, new_md, id, options=[]):
   if golden_md is None and new_md is None:
     return 0
 
@@ -62,14 +62,14 @@ def compare_metadata(golden_md, new_md, id):
 
 #######################################################
 # Review and report on the actual image pixels that differ.
-def compare_image_pixels(golden_band, new_band, id):
+def compare_image_pixels(golden_band, new_band, id, options=[]):
   diff_count = 0
   max_diff = 0
 
   for line in range(golden_band.YSize):
     golden_line = golden_band.ReadAsArray(0, line, golden_band.XSize, 1)[0]
     new_line = new_band.ReadAsArray(0, line, golden_band.XSize, 1)[0]
-    diff_line = golden_line - new_line
+    diff_line = golden_line.astype(float) - new_line.astype(float)
     max_diff = max(max_diff,abs(diff_line).max())
     diff_count += len(diff_line.nonzero()[0])
 
@@ -77,7 +77,7 @@ def compare_image_pixels(golden_band, new_band, id):
   print('  Maximum Pixel Difference: ' + str(max_diff))
 
 #######################################################
-def compare_band(golden_band, new_band, id):
+def compare_band(golden_band, new_band, id, options=[]):
   found_diff = 0
 
   if golden_band.DataType != new_band.DataType:
@@ -103,7 +103,7 @@ def compare_band(golden_band, new_band, id):
     print('  Golden: ' + str(golden_band.Checksum()))
     print('  New:    ' + str(new_band.Checksum()))
     found_diff += 1
-    compare_image_pixels(golden_band,new_band, id)
+    compare_image_pixels(golden_band,new_band, id, options)
 
   # Check overviews
   if golden_band.GetOverviewCount() != new_band.GetOverviewCount():
@@ -113,14 +113,16 @@ def compare_band(golden_band, new_band, id):
     found_diff += 1
   else:
     for i in range(golden_band.GetOverviewCount()):
-      compare_band(golden_band.GetOverview(i),
+      found_diff += compare_band(golden_band.GetOverview(i),
                    new_band.GetOverview(i),
-                   id + ' overview ' + str(i))
+                   id + ' overview ' + str(i), 
+                   options)
 
   # Metadata
-  found_diff += compare_metadata(golden_band.GetMetadata(),
-                                 new_band.GetMetadata(),
-                                 'Band ' + id)
+  if 'SKIP_METADATA' not in options:
+      found_diff += compare_metadata(golden_band.GetMetadata(),
+                                     new_band.GetMetadata(),
+                                     'Band ' + id, options)
 
   # TODO: Color Table, gain/bias, units, blocksize, mask, min/max
 
@@ -149,49 +151,60 @@ def compare_srs(golden_wkt, new_wkt):
   return 1
 
 #######################################################
-def compare_db(golden_db, new_db):
+def compare_db(golden_db, new_db, options=[]):
   found_diff = 0
 
   # SRS
-  found_diff += compare_srs(golden_db.GetProjection(),
-                            new_db.GetProjection())
+  if 'SKIP_SRS' not in options:
+      found_diff += compare_srs(golden_db.GetProjection(),
+                                new_db.GetProjection())
 
   # GeoTransform
-  golden_gt = golden_db.GetGeoTransform()
-  new_gt = new_db.GetGeoTransform()
-  if golden_gt != new_gt:
-    print('GeoTransforms Differ:')
-    print('  Golden: ' + str(golden_gt))
-    print('  New:    ' + str(new_gt))
-    found_diff += 1
+  if 'SKIP_GEOTRANSFORM' not in options:
+      golden_gt = golden_db.GetGeoTransform()
+      new_gt = new_db.GetGeoTransform()
+      if golden_gt != new_gt:
+          print('GeoTransforms Differ:')
+          print('  Golden: ' + str(golden_gt))
+          print('  New:    ' + str(new_gt))
+          found_diff += 1
 
   # Metadata
-  found_diff += compare_metadata(golden_db.GetMetadata(),
-                                 new_db.GetMetadata(),
-                                 'Dataset')
+  if 'SKIP_METADATA' not in options:
+      found_diff += compare_metadata(golden_db.GetMetadata(),
+                                     new_db.GetMetadata(),
+                                     'Dataset', options)
 
   # Bands
   if golden_db.RasterCount != new_db.RasterCount:
     print('Band count mismatch (golden=%d, new=%d)' \
         % (golden_db.RasterCount, new_db.RasterCount))
     found_diff += 1
-
-  elif golden_db.RasterXSize != new_db.RasterXSize or \
-       golden_db.RasterYSize != new_db.RasterYSize:
-    print('Image dimension mismatch (golden=%dx%d, new=%dx%d)' \
-          % (golden_db.RasterXSize, golden_db.RasterYSize,
-             new_db.RasterXSize, new_db.RasterYSize))
-    found_diff += 1
-  else:
+  
+  # Dimensions
+  for i in range(golden_db.RasterCount):
+      gSzX = golden_db.GetRasterBand(i+1).XSize
+      nSzX = new_db.GetRasterBand(i+1).XSize
+      gSzY = golden_db.GetRasterBand(i+1).YSize
+      nSzY = new_db.GetRasterBand(i+1).YSize
+      
+      if gSzX != nSzX or gSzY != nSzY:
+          print('Band size mismatch (band=%d golden=[%d,%d], new=[%d,%d])' %
+                (i, gSzX, gSzY, nSzX, nSzY))
+          found_diff += 1
+
+  # If so-far-so-good, then compare pixels
+  if found_diff == 0:
     for i in range(golden_db.RasterCount):
       found_diff += compare_band(golden_db.GetRasterBand(i+1),
                                  new_db.GetRasterBand(i+1),
-                                 str(i+1))
+                                 str(i+1),
+                                 options)
 
   return found_diff
 
 #######################################################
-def compare_sds(golden_db, new_db):
+def compare_sds(golden_db, new_db, options=[]):
   found_diff = 0
   
   golden_sds = golden_db.GetMetadata('SUBDATASETS')
@@ -204,7 +217,7 @@ def compare_sds(golden_db, new_db):
     sub_golden_db = gdal.Open(golden_sds[key])
     sub_new_db = gdal.Open(new_sds[key])
 
-    sds_diff = compare_db(sub_golden_db, sub_new_db)
+    sds_diff = compare_db(sub_golden_db, sub_new_db, options)
     found_diff += sds_diff
     if sds_diff > 0:
       print('%d differences found between:\n  %s\n  %s' \
diff --git a/swig/python/scripts/mkgraticule.py b/swig/python/scripts/mkgraticule.py
index 1610c39..7d67231 100755
--- a/swig/python/scripts/mkgraticule.py
+++ b/swig/python/scripts/mkgraticule.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 ###############################################################################
-# $Id: mkgraticule.py 24538 2012-06-04 18:30:34Z antonio $
+# $Id: mkgraticule.py 28389 2015-01-30 19:26:09Z rouault $
 #
 # Project:  OGR Python samples
 # Purpose:  Produce a graticule (grid) dataset.
@@ -35,7 +35,6 @@ except ImportError:
     import osr
     import ogr
 
-import string
 import sys
 
 #############################################################################
diff --git a/swig/python/scripts/pct2rgb.py b/swig/python/scripts/pct2rgb.py
index 6395321..8b758ba 100755
--- a/swig/python/scripts/pct2rgb.py
+++ b/swig/python/scripts/pct2rgb.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #******************************************************************************
-#  $Id: pct2rgb.py 27490 2014-07-02 17:43:54Z rouault $
+#  $Id: pct2rgb.py 28389 2015-01-30 19:26:09Z rouault $
 # 
 #  Name:     pct2rgb
 #  Project:  GDAL Python Interface
@@ -48,7 +48,6 @@ except ImportError:
 
 
 import sys
-import os.path
 
 def Usage():
     print('Usage: pct2rgb.py [-of format] [-b <band>] [-rgba] source_file dest_file')
diff --git a/swig/python/setup.py b/swig/python/setup.py
index bb97c7e..4c7b3db 100644
--- a/swig/python/setup.py
+++ b/swig/python/setup.py
@@ -7,7 +7,7 @@
 # Howard Butler hobu.inc at gmail.com
 
 
-gdal_version = '1.11.2'
+gdal_version = '2.0.0'
 
 import sys
 import os
@@ -201,6 +201,11 @@ class gdal_ext(build_ext):
 extra_link_args = []
 extra_compile_args = []
 
+if sys.platform == 'darwin' and [int(x) for x in os.uname()[2].split('.')] >= [11, 0, 0]:
+    # since MacOS X 10.9, clang no longer accepts -mno-fused-madd
+    #extra_compile_args.append('-Qunused-arguments')
+    os.environ['ARCHFLAGS'] = '-Wno-error=unused-command-line-argument-hard-error-in-future'
+
 gdal_module = Extension('osgeo._gdal',
                         sources=['extensions/gdal_wrap.cpp'],
                         extra_compile_args = extra_compile_args,

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/gdal.git



More information about the Pkg-grass-devel mailing list